You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

18718 lines
1.4MB

  1. (self["webpackChunk"] = self["webpackChunk"] || []).push([["vendors-node_modules_jquery-ui-dist_jquery-ui_js"],{
  2. /***/ "./node_modules/jquery-ui-dist/jquery-ui.js":
  3. /*!**************************************************!*\
  4. !*** ./node_modules/jquery-ui-dist/jquery-ui.js ***!
  5. \**************************************************/
  6. /***/ ((module, exports, __webpack_require__) => {
  7. var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! jQuery UI - v1.12.1 - 2016-09-14
  8. * http://jqueryui.com
  9. * 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
  10. * Copyright jQuery Foundation and other contributors; Licensed MIT */
  11. (function( factory ) {
  12. if ( true ) {
  13. // AMD. Register as an anonymous module.
  14. !(__WEBPACK_AMD_DEFINE_ARRAY__ = [ __webpack_require__(/*! jquery */ "./node_modules/jquery/src/jquery.js") ], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory),
  15. __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ?
  16. (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__),
  17. __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__));
  18. } else {}
  19. }(function( $ ) {
  20. $.ui = $.ui || {};
  21. var version = $.ui.version = "1.12.1";
  22. /*!
  23. * jQuery UI Widget 1.12.1
  24. * http://jqueryui.com
  25. *
  26. * Copyright jQuery Foundation and other contributors
  27. * Released under the MIT license.
  28. * http://jquery.org/license
  29. */
  30. //>>label: Widget
  31. //>>group: Core
  32. //>>description: Provides a factory for creating stateful widgets with a common API.
  33. //>>docs: http://api.jqueryui.com/jQuery.widget/
  34. //>>demos: http://jqueryui.com/widget/
  35. var widgetUuid = 0;
  36. var widgetSlice = Array.prototype.slice;
  37. $.cleanData = ( function( orig ) {
  38. return function( elems ) {
  39. var events, elem, i;
  40. for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
  41. try {
  42. // Only trigger remove when necessary to save time
  43. events = $._data( elem, "events" );
  44. if ( events && events.remove ) {
  45. $( elem ).triggerHandler( "remove" );
  46. }
  47. // Http://bugs.jquery.com/ticket/8235
  48. } catch ( e ) {}
  49. }
  50. orig( elems );
  51. };
  52. } )( $.cleanData );
  53. $.widget = function( name, base, prototype ) {
  54. var existingConstructor, constructor, basePrototype;
  55. // ProxiedPrototype allows the provided prototype to remain unmodified
  56. // so that it can be used as a mixin for multiple widgets (#8876)
  57. var proxiedPrototype = {};
  58. var namespace = name.split( "." )[ 0 ];
  59. name = name.split( "." )[ 1 ];
  60. var fullName = namespace + "-" + name;
  61. if ( !prototype ) {
  62. prototype = base;
  63. base = $.Widget;
  64. }
  65. if ( $.isArray( prototype ) ) {
  66. prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
  67. }
  68. // Create selector for plugin
  69. $.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
  70. return !!$.data( elem, fullName );
  71. };
  72. $[ namespace ] = $[ namespace ] || {};
  73. existingConstructor = $[ namespace ][ name ];
  74. constructor = $[ namespace ][ name ] = function( options, element ) {
  75. // Allow instantiation without "new" keyword
  76. if ( !this._createWidget ) {
  77. return new constructor( options, element );
  78. }
  79. // Allow instantiation without initializing for simple inheritance
  80. // must use "new" keyword (the code above always passes args)
  81. if ( arguments.length ) {
  82. this._createWidget( options, element );
  83. }
  84. };
  85. // Extend with the existing constructor to carry over any static properties
  86. $.extend( constructor, existingConstructor, {
  87. version: prototype.version,
  88. // Copy the object used to create the prototype in case we need to
  89. // redefine the widget later
  90. _proto: $.extend( {}, prototype ),
  91. // Track widgets that inherit from this widget in case this widget is
  92. // redefined after a widget inherits from it
  93. _childConstructors: []
  94. } );
  95. basePrototype = new base();
  96. // We need to make the options hash a property directly on the new instance
  97. // otherwise we'll modify the options hash on the prototype that we're
  98. // inheriting from
  99. basePrototype.options = $.widget.extend( {}, basePrototype.options );
  100. $.each( prototype, function( prop, value ) {
  101. if ( !$.isFunction( value ) ) {
  102. proxiedPrototype[ prop ] = value;
  103. return;
  104. }
  105. proxiedPrototype[ prop ] = ( function() {
  106. function _super() {
  107. return base.prototype[ prop ].apply( this, arguments );
  108. }
  109. function _superApply( args ) {
  110. return base.prototype[ prop ].apply( this, args );
  111. }
  112. return function() {
  113. var __super = this._super;
  114. var __superApply = this._superApply;
  115. var returnValue;
  116. this._super = _super;
  117. this._superApply = _superApply;
  118. returnValue = value.apply( this, arguments );
  119. this._super = __super;
  120. this._superApply = __superApply;
  121. return returnValue;
  122. };
  123. } )();
  124. } );
  125. constructor.prototype = $.widget.extend( basePrototype, {
  126. // TODO: remove support for widgetEventPrefix
  127. // always use the name + a colon as the prefix, e.g., draggable:start
  128. // don't prefix for widgets that aren't DOM-based
  129. widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
  130. }, proxiedPrototype, {
  131. constructor: constructor,
  132. namespace: namespace,
  133. widgetName: name,
  134. widgetFullName: fullName
  135. } );
  136. // If this widget is being redefined then we need to find all widgets that
  137. // are inheriting from it and redefine all of them so that they inherit from
  138. // the new version of this widget. We're essentially trying to replace one
  139. // level in the prototype chain.
  140. if ( existingConstructor ) {
  141. $.each( existingConstructor._childConstructors, function( i, child ) {
  142. var childPrototype = child.prototype;
  143. // Redefine the child widget using the same prototype that was
  144. // originally used, but inherit from the new version of the base
  145. $.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
  146. child._proto );
  147. } );
  148. // Remove the list of existing child constructors from the old constructor
  149. // so the old child constructors can be garbage collected
  150. delete existingConstructor._childConstructors;
  151. } else {
  152. base._childConstructors.push( constructor );
  153. }
  154. $.widget.bridge( name, constructor );
  155. return constructor;
  156. };
  157. $.widget.extend = function( target ) {
  158. var input = widgetSlice.call( arguments, 1 );
  159. var inputIndex = 0;
  160. var inputLength = input.length;
  161. var key;
  162. var value;
  163. for ( ; inputIndex < inputLength; inputIndex++ ) {
  164. for ( key in input[ inputIndex ] ) {
  165. value = input[ inputIndex ][ key ];
  166. if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
  167. // Clone objects
  168. if ( $.isPlainObject( value ) ) {
  169. target[ key ] = $.isPlainObject( target[ key ] ) ?
  170. $.widget.extend( {}, target[ key ], value ) :
  171. // Don't extend strings, arrays, etc. with objects
  172. $.widget.extend( {}, value );
  173. // Copy everything else by reference
  174. } else {
  175. target[ key ] = value;
  176. }
  177. }
  178. }
  179. }
  180. return target;
  181. };
  182. $.widget.bridge = function( name, object ) {
  183. var fullName = object.prototype.widgetFullName || name;
  184. $.fn[ name ] = function( options ) {
  185. var isMethodCall = typeof options === "string";
  186. var args = widgetSlice.call( arguments, 1 );
  187. var returnValue = this;
  188. if ( isMethodCall ) {
  189. // If this is an empty collection, we need to have the instance method
  190. // return undefined instead of the jQuery instance
  191. if ( !this.length && options === "instance" ) {
  192. returnValue = undefined;
  193. } else {
  194. this.each( function() {
  195. var methodValue;
  196. var instance = $.data( this, fullName );
  197. if ( options === "instance" ) {
  198. returnValue = instance;
  199. return false;
  200. }
  201. if ( !instance ) {
  202. return $.error( "cannot call methods on " + name +
  203. " prior to initialization; " +
  204. "attempted to call method '" + options + "'" );
  205. }
  206. if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
  207. return $.error( "no such method '" + options + "' for " + name +
  208. " widget instance" );
  209. }
  210. methodValue = instance[ options ].apply( instance, args );
  211. if ( methodValue !== instance && methodValue !== undefined ) {
  212. returnValue = methodValue && methodValue.jquery ?
  213. returnValue.pushStack( methodValue.get() ) :
  214. methodValue;
  215. return false;
  216. }
  217. } );
  218. }
  219. } else {
  220. // Allow multiple hashes to be passed on init
  221. if ( args.length ) {
  222. options = $.widget.extend.apply( null, [ options ].concat( args ) );
  223. }
  224. this.each( function() {
  225. var instance = $.data( this, fullName );
  226. if ( instance ) {
  227. instance.option( options || {} );
  228. if ( instance._init ) {
  229. instance._init();
  230. }
  231. } else {
  232. $.data( this, fullName, new object( options, this ) );
  233. }
  234. } );
  235. }
  236. return returnValue;
  237. };
  238. };
  239. $.Widget = function( /* options, element */ ) {};
  240. $.Widget._childConstructors = [];
  241. $.Widget.prototype = {
  242. widgetName: "widget",
  243. widgetEventPrefix: "",
  244. defaultElement: "<div>",
  245. options: {
  246. classes: {},
  247. disabled: false,
  248. // Callbacks
  249. create: null
  250. },
  251. _createWidget: function( options, element ) {
  252. element = $( element || this.defaultElement || this )[ 0 ];
  253. this.element = $( element );
  254. this.uuid = widgetUuid++;
  255. this.eventNamespace = "." + this.widgetName + this.uuid;
  256. this.bindings = $();
  257. this.hoverable = $();
  258. this.focusable = $();
  259. this.classesElementLookup = {};
  260. if ( element !== this ) {
  261. $.data( element, this.widgetFullName, this );
  262. this._on( true, this.element, {
  263. remove: function( event ) {
  264. if ( event.target === element ) {
  265. this.destroy();
  266. }
  267. }
  268. } );
  269. this.document = $( element.style ?
  270. // Element within the document
  271. element.ownerDocument :
  272. // Element is window or document
  273. element.document || element );
  274. this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
  275. }
  276. this.options = $.widget.extend( {},
  277. this.options,
  278. this._getCreateOptions(),
  279. options );
  280. this._create();
  281. if ( this.options.disabled ) {
  282. this._setOptionDisabled( this.options.disabled );
  283. }
  284. this._trigger( "create", null, this._getCreateEventData() );
  285. this._init();
  286. },
  287. _getCreateOptions: function() {
  288. return {};
  289. },
  290. _getCreateEventData: $.noop,
  291. _create: $.noop,
  292. _init: $.noop,
  293. destroy: function() {
  294. var that = this;
  295. this._destroy();
  296. $.each( this.classesElementLookup, function( key, value ) {
  297. that._removeClass( value, key );
  298. } );
  299. // We can probably remove the unbind calls in 2.0
  300. // all event bindings should go through this._on()
  301. this.element
  302. .off( this.eventNamespace )
  303. .removeData( this.widgetFullName );
  304. this.widget()
  305. .off( this.eventNamespace )
  306. .removeAttr( "aria-disabled" );
  307. // Clean up events and states
  308. this.bindings.off( this.eventNamespace );
  309. },
  310. _destroy: $.noop,
  311. widget: function() {
  312. return this.element;
  313. },
  314. option: function( key, value ) {
  315. var options = key;
  316. var parts;
  317. var curOption;
  318. var i;
  319. if ( arguments.length === 0 ) {
  320. // Don't return a reference to the internal hash
  321. return $.widget.extend( {}, this.options );
  322. }
  323. if ( typeof key === "string" ) {
  324. // Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
  325. options = {};
  326. parts = key.split( "." );
  327. key = parts.shift();
  328. if ( parts.length ) {
  329. curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
  330. for ( i = 0; i < parts.length - 1; i++ ) {
  331. curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
  332. curOption = curOption[ parts[ i ] ];
  333. }
  334. key = parts.pop();
  335. if ( arguments.length === 1 ) {
  336. return curOption[ key ] === undefined ? null : curOption[ key ];
  337. }
  338. curOption[ key ] = value;
  339. } else {
  340. if ( arguments.length === 1 ) {
  341. return this.options[ key ] === undefined ? null : this.options[ key ];
  342. }
  343. options[ key ] = value;
  344. }
  345. }
  346. this._setOptions( options );
  347. return this;
  348. },
  349. _setOptions: function( options ) {
  350. var key;
  351. for ( key in options ) {
  352. this._setOption( key, options[ key ] );
  353. }
  354. return this;
  355. },
  356. _setOption: function( key, value ) {
  357. if ( key === "classes" ) {
  358. this._setOptionClasses( value );
  359. }
  360. this.options[ key ] = value;
  361. if ( key === "disabled" ) {
  362. this._setOptionDisabled( value );
  363. }
  364. return this;
  365. },
  366. _setOptionClasses: function( value ) {
  367. var classKey, elements, currentElements;
  368. for ( classKey in value ) {
  369. currentElements = this.classesElementLookup[ classKey ];
  370. if ( value[ classKey ] === this.options.classes[ classKey ] ||
  371. !currentElements ||
  372. !currentElements.length ) {
  373. continue;
  374. }
  375. // We are doing this to create a new jQuery object because the _removeClass() call
  376. // on the next line is going to destroy the reference to the current elements being
  377. // tracked. We need to save a copy of this collection so that we can add the new classes
  378. // below.
  379. elements = $( currentElements.get() );
  380. this._removeClass( currentElements, classKey );
  381. // We don't use _addClass() here, because that uses this.options.classes
  382. // for generating the string of classes. We want to use the value passed in from
  383. // _setOption(), this is the new value of the classes option which was passed to
  384. // _setOption(). We pass this value directly to _classes().
  385. elements.addClass( this._classes( {
  386. element: elements,
  387. keys: classKey,
  388. classes: value,
  389. add: true
  390. } ) );
  391. }
  392. },
  393. _setOptionDisabled: function( value ) {
  394. this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
  395. // If the widget is becoming disabled, then nothing is interactive
  396. if ( value ) {
  397. this._removeClass( this.hoverable, null, "ui-state-hover" );
  398. this._removeClass( this.focusable, null, "ui-state-focus" );
  399. }
  400. },
  401. enable: function() {
  402. return this._setOptions( { disabled: false } );
  403. },
  404. disable: function() {
  405. return this._setOptions( { disabled: true } );
  406. },
  407. _classes: function( options ) {
  408. var full = [];
  409. var that = this;
  410. options = $.extend( {
  411. element: this.element,
  412. classes: this.options.classes || {}
  413. }, options );
  414. function processClassString( classes, checkOption ) {
  415. var current, i;
  416. for ( i = 0; i < classes.length; i++ ) {
  417. current = that.classesElementLookup[ classes[ i ] ] || $();
  418. if ( options.add ) {
  419. current = $( $.unique( current.get().concat( options.element.get() ) ) );
  420. } else {
  421. current = $( current.not( options.element ).get() );
  422. }
  423. that.classesElementLookup[ classes[ i ] ] = current;
  424. full.push( classes[ i ] );
  425. if ( checkOption && options.classes[ classes[ i ] ] ) {
  426. full.push( options.classes[ classes[ i ] ] );
  427. }
  428. }
  429. }
  430. this._on( options.element, {
  431. "remove": "_untrackClassesElement"
  432. } );
  433. if ( options.keys ) {
  434. processClassString( options.keys.match( /\S+/g ) || [], true );
  435. }
  436. if ( options.extra ) {
  437. processClassString( options.extra.match( /\S+/g ) || [] );
  438. }
  439. return full.join( " " );
  440. },
  441. _untrackClassesElement: function( event ) {
  442. var that = this;
  443. $.each( that.classesElementLookup, function( key, value ) {
  444. if ( $.inArray( event.target, value ) !== -1 ) {
  445. that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
  446. }
  447. } );
  448. },
  449. _removeClass: function( element, keys, extra ) {
  450. return this._toggleClass( element, keys, extra, false );
  451. },
  452. _addClass: function( element, keys, extra ) {
  453. return this._toggleClass( element, keys, extra, true );
  454. },
  455. _toggleClass: function( element, keys, extra, add ) {
  456. add = ( typeof add === "boolean" ) ? add : extra;
  457. var shift = ( typeof element === "string" || element === null ),
  458. options = {
  459. extra: shift ? keys : extra,
  460. keys: shift ? element : keys,
  461. element: shift ? this.element : element,
  462. add: add
  463. };
  464. options.element.toggleClass( this._classes( options ), add );
  465. return this;
  466. },
  467. _on: function( suppressDisabledCheck, element, handlers ) {
  468. var delegateElement;
  469. var instance = this;
  470. // No suppressDisabledCheck flag, shuffle arguments
  471. if ( typeof suppressDisabledCheck !== "boolean" ) {
  472. handlers = element;
  473. element = suppressDisabledCheck;
  474. suppressDisabledCheck = false;
  475. }
  476. // No element argument, shuffle and use this.element
  477. if ( !handlers ) {
  478. handlers = element;
  479. element = this.element;
  480. delegateElement = this.widget();
  481. } else {
  482. element = delegateElement = $( element );
  483. this.bindings = this.bindings.add( element );
  484. }
  485. $.each( handlers, function( event, handler ) {
  486. function handlerProxy() {
  487. // Allow widgets to customize the disabled handling
  488. // - disabled as an array instead of boolean
  489. // - disabled class as method for disabling individual parts
  490. if ( !suppressDisabledCheck &&
  491. ( instance.options.disabled === true ||
  492. $( this ).hasClass( "ui-state-disabled" ) ) ) {
  493. return;
  494. }
  495. return ( typeof handler === "string" ? instance[ handler ] : handler )
  496. .apply( instance, arguments );
  497. }
  498. // Copy the guid so direct unbinding works
  499. if ( typeof handler !== "string" ) {
  500. handlerProxy.guid = handler.guid =
  501. handler.guid || handlerProxy.guid || $.guid++;
  502. }
  503. var match = event.match( /^([\w:-]*)\s*(.*)$/ );
  504. var eventName = match[ 1 ] + instance.eventNamespace;
  505. var selector = match[ 2 ];
  506. if ( selector ) {
  507. delegateElement.on( eventName, selector, handlerProxy );
  508. } else {
  509. element.on( eventName, handlerProxy );
  510. }
  511. } );
  512. },
  513. _off: function( element, eventName ) {
  514. eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
  515. this.eventNamespace;
  516. element.off( eventName ).off( eventName );
  517. // Clear the stack to avoid memory leaks (#10056)
  518. this.bindings = $( this.bindings.not( element ).get() );
  519. this.focusable = $( this.focusable.not( element ).get() );
  520. this.hoverable = $( this.hoverable.not( element ).get() );
  521. },
  522. _delay: function( handler, delay ) {
  523. function handlerProxy() {
  524. return ( typeof handler === "string" ? instance[ handler ] : handler )
  525. .apply( instance, arguments );
  526. }
  527. var instance = this;
  528. return setTimeout( handlerProxy, delay || 0 );
  529. },
  530. _hoverable: function( element ) {
  531. this.hoverable = this.hoverable.add( element );
  532. this._on( element, {
  533. mouseenter: function( event ) {
  534. this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
  535. },
  536. mouseleave: function( event ) {
  537. this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
  538. }
  539. } );
  540. },
  541. _focusable: function( element ) {
  542. this.focusable = this.focusable.add( element );
  543. this._on( element, {
  544. focusin: function( event ) {
  545. this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
  546. },
  547. focusout: function( event ) {
  548. this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
  549. }
  550. } );
  551. },
  552. _trigger: function( type, event, data ) {
  553. var prop, orig;
  554. var callback = this.options[ type ];
  555. data = data || {};
  556. event = $.Event( event );
  557. event.type = ( type === this.widgetEventPrefix ?
  558. type :
  559. this.widgetEventPrefix + type ).toLowerCase();
  560. // The original event may come from any element
  561. // so we need to reset the target on the new event
  562. event.target = this.element[ 0 ];
  563. // Copy original event properties over to the new event
  564. orig = event.originalEvent;
  565. if ( orig ) {
  566. for ( prop in orig ) {
  567. if ( !( prop in event ) ) {
  568. event[ prop ] = orig[ prop ];
  569. }
  570. }
  571. }
  572. this.element.trigger( event, data );
  573. return !( $.isFunction( callback ) &&
  574. callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
  575. event.isDefaultPrevented() );
  576. }
  577. };
  578. $.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
  579. $.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
  580. if ( typeof options === "string" ) {
  581. options = { effect: options };
  582. }
  583. var hasOptions;
  584. var effectName = !options ?
  585. method :
  586. options === true || typeof options === "number" ?
  587. defaultEffect :
  588. options.effect || defaultEffect;
  589. options = options || {};
  590. if ( typeof options === "number" ) {
  591. options = { duration: options };
  592. }
  593. hasOptions = !$.isEmptyObject( options );
  594. options.complete = callback;
  595. if ( options.delay ) {
  596. element.delay( options.delay );
  597. }
  598. if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
  599. element[ method ]( options );
  600. } else if ( effectName !== method && element[ effectName ] ) {
  601. element[ effectName ]( options.duration, options.easing, callback );
  602. } else {
  603. element.queue( function( next ) {
  604. $( this )[ method ]();
  605. if ( callback ) {
  606. callback.call( element[ 0 ] );
  607. }
  608. next();
  609. } );
  610. }
  611. };
  612. } );
  613. var widget = $.widget;
  614. /*!
  615. * jQuery UI Position 1.12.1
  616. * http://jqueryui.com
  617. *
  618. * Copyright jQuery Foundation and other contributors
  619. * Released under the MIT license.
  620. * http://jquery.org/license
  621. *
  622. * http://api.jqueryui.com/position/
  623. */
  624. //>>label: Position
  625. //>>group: Core
  626. //>>description: Positions elements relative to other elements.
  627. //>>docs: http://api.jqueryui.com/position/
  628. //>>demos: http://jqueryui.com/position/
  629. ( function() {
  630. var cachedScrollbarWidth,
  631. max = Math.max,
  632. abs = Math.abs,
  633. rhorizontal = /left|center|right/,
  634. rvertical = /top|center|bottom/,
  635. roffset = /[\+\-]\d+(\.[\d]+)?%?/,
  636. rposition = /^\w+/,
  637. rpercent = /%$/,
  638. _position = $.fn.position;
  639. function getOffsets( offsets, width, height ) {
  640. return [
  641. parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
  642. parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
  643. ];
  644. }
  645. function parseCss( element, property ) {
  646. return parseInt( $.css( element, property ), 10 ) || 0;
  647. }
  648. function getDimensions( elem ) {
  649. var raw = elem[ 0 ];
  650. if ( raw.nodeType === 9 ) {
  651. return {
  652. width: elem.width(),
  653. height: elem.height(),
  654. offset: { top: 0, left: 0 }
  655. };
  656. }
  657. if ( $.isWindow( raw ) ) {
  658. return {
  659. width: elem.width(),
  660. height: elem.height(),
  661. offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
  662. };
  663. }
  664. if ( raw.preventDefault ) {
  665. return {
  666. width: 0,
  667. height: 0,
  668. offset: { top: raw.pageY, left: raw.pageX }
  669. };
  670. }
  671. return {
  672. width: elem.outerWidth(),
  673. height: elem.outerHeight(),
  674. offset: elem.offset()
  675. };
  676. }
  677. $.position = {
  678. scrollbarWidth: function() {
  679. if ( cachedScrollbarWidth !== undefined ) {
  680. return cachedScrollbarWidth;
  681. }
  682. var w1, w2,
  683. div = $( "<div " +
  684. "style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
  685. "<div style='height:100px;width:auto;'></div></div>" ),
  686. innerDiv = div.children()[ 0 ];
  687. $( "body" ).append( div );
  688. w1 = innerDiv.offsetWidth;
  689. div.css( "overflow", "scroll" );
  690. w2 = innerDiv.offsetWidth;
  691. if ( w1 === w2 ) {
  692. w2 = div[ 0 ].clientWidth;
  693. }
  694. div.remove();
  695. return ( cachedScrollbarWidth = w1 - w2 );
  696. },
  697. getScrollInfo: function( within ) {
  698. var overflowX = within.isWindow || within.isDocument ? "" :
  699. within.element.css( "overflow-x" ),
  700. overflowY = within.isWindow || within.isDocument ? "" :
  701. within.element.css( "overflow-y" ),
  702. hasOverflowX = overflowX === "scroll" ||
  703. ( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
  704. hasOverflowY = overflowY === "scroll" ||
  705. ( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
  706. return {
  707. width: hasOverflowY ? $.position.scrollbarWidth() : 0,
  708. height: hasOverflowX ? $.position.scrollbarWidth() : 0
  709. };
  710. },
  711. getWithinInfo: function( element ) {
  712. var withinElement = $( element || window ),
  713. isWindow = $.isWindow( withinElement[ 0 ] ),
  714. isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
  715. hasOffset = !isWindow && !isDocument;
  716. return {
  717. element: withinElement,
  718. isWindow: isWindow,
  719. isDocument: isDocument,
  720. offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
  721. scrollLeft: withinElement.scrollLeft(),
  722. scrollTop: withinElement.scrollTop(),
  723. width: withinElement.outerWidth(),
  724. height: withinElement.outerHeight()
  725. };
  726. }
  727. };
  728. $.fn.position = function( options ) {
  729. if ( !options || !options.of ) {
  730. return _position.apply( this, arguments );
  731. }
  732. // Make a copy, we don't want to modify arguments
  733. options = $.extend( {}, options );
  734. var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
  735. target = $( options.of ),
  736. within = $.position.getWithinInfo( options.within ),
  737. scrollInfo = $.position.getScrollInfo( within ),
  738. collision = ( options.collision || "flip" ).split( " " ),
  739. offsets = {};
  740. dimensions = getDimensions( target );
  741. if ( target[ 0 ].preventDefault ) {
  742. // Force left top to allow flipping
  743. options.at = "left top";
  744. }
  745. targetWidth = dimensions.width;
  746. targetHeight = dimensions.height;
  747. targetOffset = dimensions.offset;
  748. // Clone to reuse original targetOffset later
  749. basePosition = $.extend( {}, targetOffset );
  750. // Force my and at to have valid horizontal and vertical positions
  751. // if a value is missing or invalid, it will be converted to center
  752. $.each( [ "my", "at" ], function() {
  753. var pos = ( options[ this ] || "" ).split( " " ),
  754. horizontalOffset,
  755. verticalOffset;
  756. if ( pos.length === 1 ) {
  757. pos = rhorizontal.test( pos[ 0 ] ) ?
  758. pos.concat( [ "center" ] ) :
  759. rvertical.test( pos[ 0 ] ) ?
  760. [ "center" ].concat( pos ) :
  761. [ "center", "center" ];
  762. }
  763. pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
  764. pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
  765. // Calculate offsets
  766. horizontalOffset = roffset.exec( pos[ 0 ] );
  767. verticalOffset = roffset.exec( pos[ 1 ] );
  768. offsets[ this ] = [
  769. horizontalOffset ? horizontalOffset[ 0 ] : 0,
  770. verticalOffset ? verticalOffset[ 0 ] : 0
  771. ];
  772. // Reduce to just the positions without the offsets
  773. options[ this ] = [
  774. rposition.exec( pos[ 0 ] )[ 0 ],
  775. rposition.exec( pos[ 1 ] )[ 0 ]
  776. ];
  777. } );
  778. // Normalize collision option
  779. if ( collision.length === 1 ) {
  780. collision[ 1 ] = collision[ 0 ];
  781. }
  782. if ( options.at[ 0 ] === "right" ) {
  783. basePosition.left += targetWidth;
  784. } else if ( options.at[ 0 ] === "center" ) {
  785. basePosition.left += targetWidth / 2;
  786. }
  787. if ( options.at[ 1 ] === "bottom" ) {
  788. basePosition.top += targetHeight;
  789. } else if ( options.at[ 1 ] === "center" ) {
  790. basePosition.top += targetHeight / 2;
  791. }
  792. atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
  793. basePosition.left += atOffset[ 0 ];
  794. basePosition.top += atOffset[ 1 ];
  795. return this.each( function() {
  796. var collisionPosition, using,
  797. elem = $( this ),
  798. elemWidth = elem.outerWidth(),
  799. elemHeight = elem.outerHeight(),
  800. marginLeft = parseCss( this, "marginLeft" ),
  801. marginTop = parseCss( this, "marginTop" ),
  802. collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
  803. scrollInfo.width,
  804. collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
  805. scrollInfo.height,
  806. position = $.extend( {}, basePosition ),
  807. myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
  808. if ( options.my[ 0 ] === "right" ) {
  809. position.left -= elemWidth;
  810. } else if ( options.my[ 0 ] === "center" ) {
  811. position.left -= elemWidth / 2;
  812. }
  813. if ( options.my[ 1 ] === "bottom" ) {
  814. position.top -= elemHeight;
  815. } else if ( options.my[ 1 ] === "center" ) {
  816. position.top -= elemHeight / 2;
  817. }
  818. position.left += myOffset[ 0 ];
  819. position.top += myOffset[ 1 ];
  820. collisionPosition = {
  821. marginLeft: marginLeft,
  822. marginTop: marginTop
  823. };
  824. $.each( [ "left", "top" ], function( i, dir ) {
  825. if ( $.ui.position[ collision[ i ] ] ) {
  826. $.ui.position[ collision[ i ] ][ dir ]( position, {
  827. targetWidth: targetWidth,
  828. targetHeight: targetHeight,
  829. elemWidth: elemWidth,
  830. elemHeight: elemHeight,
  831. collisionPosition: collisionPosition,
  832. collisionWidth: collisionWidth,
  833. collisionHeight: collisionHeight,
  834. offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
  835. my: options.my,
  836. at: options.at,
  837. within: within,
  838. elem: elem
  839. } );
  840. }
  841. } );
  842. if ( options.using ) {
  843. // Adds feedback as second argument to using callback, if present
  844. using = function( props ) {
  845. var left = targetOffset.left - position.left,
  846. right = left + targetWidth - elemWidth,
  847. top = targetOffset.top - position.top,
  848. bottom = top + targetHeight - elemHeight,
  849. feedback = {
  850. target: {
  851. element: target,
  852. left: targetOffset.left,
  853. top: targetOffset.top,
  854. width: targetWidth,
  855. height: targetHeight
  856. },
  857. element: {
  858. element: elem,
  859. left: position.left,
  860. top: position.top,
  861. width: elemWidth,
  862. height: elemHeight
  863. },
  864. horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
  865. vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
  866. };
  867. if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
  868. feedback.horizontal = "center";
  869. }
  870. if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
  871. feedback.vertical = "middle";
  872. }
  873. if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
  874. feedback.important = "horizontal";
  875. } else {
  876. feedback.important = "vertical";
  877. }
  878. options.using.call( this, props, feedback );
  879. };
  880. }
  881. elem.offset( $.extend( position, { using: using } ) );
  882. } );
  883. };
  884. $.ui.position = {
  885. fit: {
  886. left: function( position, data ) {
  887. var within = data.within,
  888. withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
  889. outerWidth = within.width,
  890. collisionPosLeft = position.left - data.collisionPosition.marginLeft,
  891. overLeft = withinOffset - collisionPosLeft,
  892. overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
  893. newOverRight;
  894. // Element is wider than within
  895. if ( data.collisionWidth > outerWidth ) {
  896. // Element is initially over the left side of within
  897. if ( overLeft > 0 && overRight <= 0 ) {
  898. newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
  899. withinOffset;
  900. position.left += overLeft - newOverRight;
  901. // Element is initially over right side of within
  902. } else if ( overRight > 0 && overLeft <= 0 ) {
  903. position.left = withinOffset;
  904. // Element is initially over both left and right sides of within
  905. } else {
  906. if ( overLeft > overRight ) {
  907. position.left = withinOffset + outerWidth - data.collisionWidth;
  908. } else {
  909. position.left = withinOffset;
  910. }
  911. }
  912. // Too far left -> align with left edge
  913. } else if ( overLeft > 0 ) {
  914. position.left += overLeft;
  915. // Too far right -> align with right edge
  916. } else if ( overRight > 0 ) {
  917. position.left -= overRight;
  918. // Adjust based on position and margin
  919. } else {
  920. position.left = max( position.left - collisionPosLeft, position.left );
  921. }
  922. },
  923. top: function( position, data ) {
  924. var within = data.within,
  925. withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
  926. outerHeight = data.within.height,
  927. collisionPosTop = position.top - data.collisionPosition.marginTop,
  928. overTop = withinOffset - collisionPosTop,
  929. overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
  930. newOverBottom;
  931. // Element is taller than within
  932. if ( data.collisionHeight > outerHeight ) {
  933. // Element is initially over the top of within
  934. if ( overTop > 0 && overBottom <= 0 ) {
  935. newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
  936. withinOffset;
  937. position.top += overTop - newOverBottom;
  938. // Element is initially over bottom of within
  939. } else if ( overBottom > 0 && overTop <= 0 ) {
  940. position.top = withinOffset;
  941. // Element is initially over both top and bottom of within
  942. } else {
  943. if ( overTop > overBottom ) {
  944. position.top = withinOffset + outerHeight - data.collisionHeight;
  945. } else {
  946. position.top = withinOffset;
  947. }
  948. }
  949. // Too far up -> align with top
  950. } else if ( overTop > 0 ) {
  951. position.top += overTop;
  952. // Too far down -> align with bottom edge
  953. } else if ( overBottom > 0 ) {
  954. position.top -= overBottom;
  955. // Adjust based on position and margin
  956. } else {
  957. position.top = max( position.top - collisionPosTop, position.top );
  958. }
  959. }
  960. },
  961. flip: {
  962. left: function( position, data ) {
  963. var within = data.within,
  964. withinOffset = within.offset.left + within.scrollLeft,
  965. outerWidth = within.width,
  966. offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
  967. collisionPosLeft = position.left - data.collisionPosition.marginLeft,
  968. overLeft = collisionPosLeft - offsetLeft,
  969. overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
  970. myOffset = data.my[ 0 ] === "left" ?
  971. -data.elemWidth :
  972. data.my[ 0 ] === "right" ?
  973. data.elemWidth :
  974. 0,
  975. atOffset = data.at[ 0 ] === "left" ?
  976. data.targetWidth :
  977. data.at[ 0 ] === "right" ?
  978. -data.targetWidth :
  979. 0,
  980. offset = -2 * data.offset[ 0 ],
  981. newOverRight,
  982. newOverLeft;
  983. if ( overLeft < 0 ) {
  984. newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
  985. outerWidth - withinOffset;
  986. if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
  987. position.left += myOffset + atOffset + offset;
  988. }
  989. } else if ( overRight > 0 ) {
  990. newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
  991. atOffset + offset - offsetLeft;
  992. if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
  993. position.left += myOffset + atOffset + offset;
  994. }
  995. }
  996. },
  997. top: function( position, data ) {
  998. var within = data.within,
  999. withinOffset = within.offset.top + within.scrollTop,
  1000. outerHeight = within.height,
  1001. offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
  1002. collisionPosTop = position.top - data.collisionPosition.marginTop,
  1003. overTop = collisionPosTop - offsetTop,
  1004. overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
  1005. top = data.my[ 1 ] === "top",
  1006. myOffset = top ?
  1007. -data.elemHeight :
  1008. data.my[ 1 ] === "bottom" ?
  1009. data.elemHeight :
  1010. 0,
  1011. atOffset = data.at[ 1 ] === "top" ?
  1012. data.targetHeight :
  1013. data.at[ 1 ] === "bottom" ?
  1014. -data.targetHeight :
  1015. 0,
  1016. offset = -2 * data.offset[ 1 ],
  1017. newOverTop,
  1018. newOverBottom;
  1019. if ( overTop < 0 ) {
  1020. newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
  1021. outerHeight - withinOffset;
  1022. if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
  1023. position.top += myOffset + atOffset + offset;
  1024. }
  1025. } else if ( overBottom > 0 ) {
  1026. newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
  1027. offset - offsetTop;
  1028. if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
  1029. position.top += myOffset + atOffset + offset;
  1030. }
  1031. }
  1032. }
  1033. },
  1034. flipfit: {
  1035. left: function() {
  1036. $.ui.position.flip.left.apply( this, arguments );
  1037. $.ui.position.fit.left.apply( this, arguments );
  1038. },
  1039. top: function() {
  1040. $.ui.position.flip.top.apply( this, arguments );
  1041. $.ui.position.fit.top.apply( this, arguments );
  1042. }
  1043. }
  1044. };
  1045. } )();
  1046. var position = $.ui.position;
  1047. /*!
  1048. * jQuery UI :data 1.12.1
  1049. * http://jqueryui.com
  1050. *
  1051. * Copyright jQuery Foundation and other contributors
  1052. * Released under the MIT license.
  1053. * http://jquery.org/license
  1054. */
  1055. //>>label: :data Selector
  1056. //>>group: Core
  1057. //>>description: Selects elements which have data stored under the specified key.
  1058. //>>docs: http://api.jqueryui.com/data-selector/
  1059. var data = $.extend( $.expr[ ":" ], {
  1060. data: $.expr.createPseudo ?
  1061. $.expr.createPseudo( function( dataName ) {
  1062. return function( elem ) {
  1063. return !!$.data( elem, dataName );
  1064. };
  1065. } ) :
  1066. // Support: jQuery <1.8
  1067. function( elem, i, match ) {
  1068. return !!$.data( elem, match[ 3 ] );
  1069. }
  1070. } );
  1071. /*!
  1072. * jQuery UI Disable Selection 1.12.1
  1073. * http://jqueryui.com
  1074. *
  1075. * Copyright jQuery Foundation and other contributors
  1076. * Released under the MIT license.
  1077. * http://jquery.org/license
  1078. */
  1079. //>>label: disableSelection
  1080. //>>group: Core
  1081. //>>description: Disable selection of text content within the set of matched elements.
  1082. //>>docs: http://api.jqueryui.com/disableSelection/
  1083. // This file is deprecated
  1084. var disableSelection = $.fn.extend( {
  1085. disableSelection: ( function() {
  1086. var eventType = "onselectstart" in document.createElement( "div" ) ?
  1087. "selectstart" :
  1088. "mousedown";
  1089. return function() {
  1090. return this.on( eventType + ".ui-disableSelection", function( event ) {
  1091. event.preventDefault();
  1092. } );
  1093. };
  1094. } )(),
  1095. enableSelection: function() {
  1096. return this.off( ".ui-disableSelection" );
  1097. }
  1098. } );
  1099. /*!
  1100. * jQuery UI Effects 1.12.1
  1101. * http://jqueryui.com
  1102. *
  1103. * Copyright jQuery Foundation and other contributors
  1104. * Released under the MIT license.
  1105. * http://jquery.org/license
  1106. */
  1107. //>>label: Effects Core
  1108. //>>group: Effects
  1109. // jscs:disable maximumLineLength
  1110. //>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
  1111. // jscs:enable maximumLineLength
  1112. //>>docs: http://api.jqueryui.com/category/effects-core/
  1113. //>>demos: http://jqueryui.com/effect/
  1114. var dataSpace = "ui-effects-",
  1115. dataSpaceStyle = "ui-effects-style",
  1116. dataSpaceAnimated = "ui-effects-animated",
  1117. // Create a local jQuery because jQuery Color relies on it and the
  1118. // global may not exist with AMD and a custom build (#10199)
  1119. jQuery = $;
  1120. $.effects = {
  1121. effect: {}
  1122. };
  1123. /*!
  1124. * jQuery Color Animations v2.1.2
  1125. * https://github.com/jquery/jquery-color
  1126. *
  1127. * Copyright 2014 jQuery Foundation and other contributors
  1128. * Released under the MIT license.
  1129. * http://jquery.org/license
  1130. *
  1131. * Date: Wed Jan 16 08:47:09 2013 -0600
  1132. */
  1133. ( function( jQuery, undefined ) {
  1134. var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
  1135. "borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
  1136. // Plusequals test for += 100 -= 100
  1137. rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
  1138. // A set of RE's that can match strings and generate color tuples.
  1139. stringParsers = [ {
  1140. re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
  1141. parse: function( execResult ) {
  1142. return [
  1143. execResult[ 1 ],
  1144. execResult[ 2 ],
  1145. execResult[ 3 ],
  1146. execResult[ 4 ]
  1147. ];
  1148. }
  1149. }, {
  1150. re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
  1151. parse: function( execResult ) {
  1152. return [
  1153. execResult[ 1 ] * 2.55,
  1154. execResult[ 2 ] * 2.55,
  1155. execResult[ 3 ] * 2.55,
  1156. execResult[ 4 ]
  1157. ];
  1158. }
  1159. }, {
  1160. // This regex ignores A-F because it's compared against an already lowercased string
  1161. re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
  1162. parse: function( execResult ) {
  1163. return [
  1164. parseInt( execResult[ 1 ], 16 ),
  1165. parseInt( execResult[ 2 ], 16 ),
  1166. parseInt( execResult[ 3 ], 16 )
  1167. ];
  1168. }
  1169. }, {
  1170. // This regex ignores A-F because it's compared against an already lowercased string
  1171. re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
  1172. parse: function( execResult ) {
  1173. return [
  1174. parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
  1175. parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
  1176. parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
  1177. ];
  1178. }
  1179. }, {
  1180. re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
  1181. space: "hsla",
  1182. parse: function( execResult ) {
  1183. return [
  1184. execResult[ 1 ],
  1185. execResult[ 2 ] / 100,
  1186. execResult[ 3 ] / 100,
  1187. execResult[ 4 ]
  1188. ];
  1189. }
  1190. } ],
  1191. // JQuery.Color( )
  1192. color = jQuery.Color = function( color, green, blue, alpha ) {
  1193. return new jQuery.Color.fn.parse( color, green, blue, alpha );
  1194. },
  1195. spaces = {
  1196. rgba: {
  1197. props: {
  1198. red: {
  1199. idx: 0,
  1200. type: "byte"
  1201. },
  1202. green: {
  1203. idx: 1,
  1204. type: "byte"
  1205. },
  1206. blue: {
  1207. idx: 2,
  1208. type: "byte"
  1209. }
  1210. }
  1211. },
  1212. hsla: {
  1213. props: {
  1214. hue: {
  1215. idx: 0,
  1216. type: "degrees"
  1217. },
  1218. saturation: {
  1219. idx: 1,
  1220. type: "percent"
  1221. },
  1222. lightness: {
  1223. idx: 2,
  1224. type: "percent"
  1225. }
  1226. }
  1227. }
  1228. },
  1229. propTypes = {
  1230. "byte": {
  1231. floor: true,
  1232. max: 255
  1233. },
  1234. "percent": {
  1235. max: 1
  1236. },
  1237. "degrees": {
  1238. mod: 360,
  1239. floor: true
  1240. }
  1241. },
  1242. support = color.support = {},
  1243. // Element for support tests
  1244. supportElem = jQuery( "<p>" )[ 0 ],
  1245. // Colors = jQuery.Color.names
  1246. colors,
  1247. // Local aliases of functions called often
  1248. each = jQuery.each;
  1249. // Determine rgba support immediately
  1250. supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
  1251. support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
  1252. // Define cache name and alpha properties
  1253. // for rgba and hsla spaces
  1254. each( spaces, function( spaceName, space ) {
  1255. space.cache = "_" + spaceName;
  1256. space.props.alpha = {
  1257. idx: 3,
  1258. type: "percent",
  1259. def: 1
  1260. };
  1261. } );
  1262. function clamp( value, prop, allowEmpty ) {
  1263. var type = propTypes[ prop.type ] || {};
  1264. if ( value == null ) {
  1265. return ( allowEmpty || !prop.def ) ? null : prop.def;
  1266. }
  1267. // ~~ is an short way of doing floor for positive numbers
  1268. value = type.floor ? ~~value : parseFloat( value );
  1269. // IE will pass in empty strings as value for alpha,
  1270. // which will hit this case
  1271. if ( isNaN( value ) ) {
  1272. return prop.def;
  1273. }
  1274. if ( type.mod ) {
  1275. // We add mod before modding to make sure that negatives values
  1276. // get converted properly: -10 -> 350
  1277. return ( value + type.mod ) % type.mod;
  1278. }
  1279. // For now all property types without mod have min and max
  1280. return 0 > value ? 0 : type.max < value ? type.max : value;
  1281. }
  1282. function stringParse( string ) {
  1283. var inst = color(),
  1284. rgba = inst._rgba = [];
  1285. string = string.toLowerCase();
  1286. each( stringParsers, function( i, parser ) {
  1287. var parsed,
  1288. match = parser.re.exec( string ),
  1289. values = match && parser.parse( match ),
  1290. spaceName = parser.space || "rgba";
  1291. if ( values ) {
  1292. parsed = inst[ spaceName ]( values );
  1293. // If this was an rgba parse the assignment might happen twice
  1294. // oh well....
  1295. inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
  1296. rgba = inst._rgba = parsed._rgba;
  1297. // Exit each( stringParsers ) here because we matched
  1298. return false;
  1299. }
  1300. } );
  1301. // Found a stringParser that handled it
  1302. if ( rgba.length ) {
  1303. // If this came from a parsed string, force "transparent" when alpha is 0
  1304. // chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
  1305. if ( rgba.join() === "0,0,0,0" ) {
  1306. jQuery.extend( rgba, colors.transparent );
  1307. }
  1308. return inst;
  1309. }
  1310. // Named colors
  1311. return colors[ string ];
  1312. }
  1313. color.fn = jQuery.extend( color.prototype, {
  1314. parse: function( red, green, blue, alpha ) {
  1315. if ( red === undefined ) {
  1316. this._rgba = [ null, null, null, null ];
  1317. return this;
  1318. }
  1319. if ( red.jquery || red.nodeType ) {
  1320. red = jQuery( red ).css( green );
  1321. green = undefined;
  1322. }
  1323. var inst = this,
  1324. type = jQuery.type( red ),
  1325. rgba = this._rgba = [];
  1326. // More than 1 argument specified - assume ( red, green, blue, alpha )
  1327. if ( green !== undefined ) {
  1328. red = [ red, green, blue, alpha ];
  1329. type = "array";
  1330. }
  1331. if ( type === "string" ) {
  1332. return this.parse( stringParse( red ) || colors._default );
  1333. }
  1334. if ( type === "array" ) {
  1335. each( spaces.rgba.props, function( key, prop ) {
  1336. rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
  1337. } );
  1338. return this;
  1339. }
  1340. if ( type === "object" ) {
  1341. if ( red instanceof color ) {
  1342. each( spaces, function( spaceName, space ) {
  1343. if ( red[ space.cache ] ) {
  1344. inst[ space.cache ] = red[ space.cache ].slice();
  1345. }
  1346. } );
  1347. } else {
  1348. each( spaces, function( spaceName, space ) {
  1349. var cache = space.cache;
  1350. each( space.props, function( key, prop ) {
  1351. // If the cache doesn't exist, and we know how to convert
  1352. if ( !inst[ cache ] && space.to ) {
  1353. // If the value was null, we don't need to copy it
  1354. // if the key was alpha, we don't need to copy it either
  1355. if ( key === "alpha" || red[ key ] == null ) {
  1356. return;
  1357. }
  1358. inst[ cache ] = space.to( inst._rgba );
  1359. }
  1360. // This is the only case where we allow nulls for ALL properties.
  1361. // call clamp with alwaysAllowEmpty
  1362. inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
  1363. } );
  1364. // Everything defined but alpha?
  1365. if ( inst[ cache ] &&
  1366. jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
  1367. // Use the default of 1
  1368. inst[ cache ][ 3 ] = 1;
  1369. if ( space.from ) {
  1370. inst._rgba = space.from( inst[ cache ] );
  1371. }
  1372. }
  1373. } );
  1374. }
  1375. return this;
  1376. }
  1377. },
  1378. is: function( compare ) {
  1379. var is = color( compare ),
  1380. same = true,
  1381. inst = this;
  1382. each( spaces, function( _, space ) {
  1383. var localCache,
  1384. isCache = is[ space.cache ];
  1385. if ( isCache ) {
  1386. localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
  1387. each( space.props, function( _, prop ) {
  1388. if ( isCache[ prop.idx ] != null ) {
  1389. same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
  1390. return same;
  1391. }
  1392. } );
  1393. }
  1394. return same;
  1395. } );
  1396. return same;
  1397. },
  1398. _space: function() {
  1399. var used = [],
  1400. inst = this;
  1401. each( spaces, function( spaceName, space ) {
  1402. if ( inst[ space.cache ] ) {
  1403. used.push( spaceName );
  1404. }
  1405. } );
  1406. return used.pop();
  1407. },
  1408. transition: function( other, distance ) {
  1409. var end = color( other ),
  1410. spaceName = end._space(),
  1411. space = spaces[ spaceName ],
  1412. startColor = this.alpha() === 0 ? color( "transparent" ) : this,
  1413. start = startColor[ space.cache ] || space.to( startColor._rgba ),
  1414. result = start.slice();
  1415. end = end[ space.cache ];
  1416. each( space.props, function( key, prop ) {
  1417. var index = prop.idx,
  1418. startValue = start[ index ],
  1419. endValue = end[ index ],
  1420. type = propTypes[ prop.type ] || {};
  1421. // If null, don't override start value
  1422. if ( endValue === null ) {
  1423. return;
  1424. }
  1425. // If null - use end
  1426. if ( startValue === null ) {
  1427. result[ index ] = endValue;
  1428. } else {
  1429. if ( type.mod ) {
  1430. if ( endValue - startValue > type.mod / 2 ) {
  1431. startValue += type.mod;
  1432. } else if ( startValue - endValue > type.mod / 2 ) {
  1433. startValue -= type.mod;
  1434. }
  1435. }
  1436. result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
  1437. }
  1438. } );
  1439. return this[ spaceName ]( result );
  1440. },
  1441. blend: function( opaque ) {
  1442. // If we are already opaque - return ourself
  1443. if ( this._rgba[ 3 ] === 1 ) {
  1444. return this;
  1445. }
  1446. var rgb = this._rgba.slice(),
  1447. a = rgb.pop(),
  1448. blend = color( opaque )._rgba;
  1449. return color( jQuery.map( rgb, function( v, i ) {
  1450. return ( 1 - a ) * blend[ i ] + a * v;
  1451. } ) );
  1452. },
  1453. toRgbaString: function() {
  1454. var prefix = "rgba(",
  1455. rgba = jQuery.map( this._rgba, function( v, i ) {
  1456. return v == null ? ( i > 2 ? 1 : 0 ) : v;
  1457. } );
  1458. if ( rgba[ 3 ] === 1 ) {
  1459. rgba.pop();
  1460. prefix = "rgb(";
  1461. }
  1462. return prefix + rgba.join() + ")";
  1463. },
  1464. toHslaString: function() {
  1465. var prefix = "hsla(",
  1466. hsla = jQuery.map( this.hsla(), function( v, i ) {
  1467. if ( v == null ) {
  1468. v = i > 2 ? 1 : 0;
  1469. }
  1470. // Catch 1 and 2
  1471. if ( i && i < 3 ) {
  1472. v = Math.round( v * 100 ) + "%";
  1473. }
  1474. return v;
  1475. } );
  1476. if ( hsla[ 3 ] === 1 ) {
  1477. hsla.pop();
  1478. prefix = "hsl(";
  1479. }
  1480. return prefix + hsla.join() + ")";
  1481. },
  1482. toHexString: function( includeAlpha ) {
  1483. var rgba = this._rgba.slice(),
  1484. alpha = rgba.pop();
  1485. if ( includeAlpha ) {
  1486. rgba.push( ~~( alpha * 255 ) );
  1487. }
  1488. return "#" + jQuery.map( rgba, function( v ) {
  1489. // Default to 0 when nulls exist
  1490. v = ( v || 0 ).toString( 16 );
  1491. return v.length === 1 ? "0" + v : v;
  1492. } ).join( "" );
  1493. },
  1494. toString: function() {
  1495. return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
  1496. }
  1497. } );
  1498. color.fn.parse.prototype = color.fn;
  1499. // Hsla conversions adapted from:
  1500. // https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
  1501. function hue2rgb( p, q, h ) {
  1502. h = ( h + 1 ) % 1;
  1503. if ( h * 6 < 1 ) {
  1504. return p + ( q - p ) * h * 6;
  1505. }
  1506. if ( h * 2 < 1 ) {
  1507. return q;
  1508. }
  1509. if ( h * 3 < 2 ) {
  1510. return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
  1511. }
  1512. return p;
  1513. }
  1514. spaces.hsla.to = function( rgba ) {
  1515. if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
  1516. return [ null, null, null, rgba[ 3 ] ];
  1517. }
  1518. var r = rgba[ 0 ] / 255,
  1519. g = rgba[ 1 ] / 255,
  1520. b = rgba[ 2 ] / 255,
  1521. a = rgba[ 3 ],
  1522. max = Math.max( r, g, b ),
  1523. min = Math.min( r, g, b ),
  1524. diff = max - min,
  1525. add = max + min,
  1526. l = add * 0.5,
  1527. h, s;
  1528. if ( min === max ) {
  1529. h = 0;
  1530. } else if ( r === max ) {
  1531. h = ( 60 * ( g - b ) / diff ) + 360;
  1532. } else if ( g === max ) {
  1533. h = ( 60 * ( b - r ) / diff ) + 120;
  1534. } else {
  1535. h = ( 60 * ( r - g ) / diff ) + 240;
  1536. }
  1537. // Chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
  1538. // otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
  1539. if ( diff === 0 ) {
  1540. s = 0;
  1541. } else if ( l <= 0.5 ) {
  1542. s = diff / add;
  1543. } else {
  1544. s = diff / ( 2 - add );
  1545. }
  1546. return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
  1547. };
  1548. spaces.hsla.from = function( hsla ) {
  1549. if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
  1550. return [ null, null, null, hsla[ 3 ] ];
  1551. }
  1552. var h = hsla[ 0 ] / 360,
  1553. s = hsla[ 1 ],
  1554. l = hsla[ 2 ],
  1555. a = hsla[ 3 ],
  1556. q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
  1557. p = 2 * l - q;
  1558. return [
  1559. Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
  1560. Math.round( hue2rgb( p, q, h ) * 255 ),
  1561. Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
  1562. a
  1563. ];
  1564. };
  1565. each( spaces, function( spaceName, space ) {
  1566. var props = space.props,
  1567. cache = space.cache,
  1568. to = space.to,
  1569. from = space.from;
  1570. // Makes rgba() and hsla()
  1571. color.fn[ spaceName ] = function( value ) {
  1572. // Generate a cache for this space if it doesn't exist
  1573. if ( to && !this[ cache ] ) {
  1574. this[ cache ] = to( this._rgba );
  1575. }
  1576. if ( value === undefined ) {
  1577. return this[ cache ].slice();
  1578. }
  1579. var ret,
  1580. type = jQuery.type( value ),
  1581. arr = ( type === "array" || type === "object" ) ? value : arguments,
  1582. local = this[ cache ].slice();
  1583. each( props, function( key, prop ) {
  1584. var val = arr[ type === "object" ? key : prop.idx ];
  1585. if ( val == null ) {
  1586. val = local[ prop.idx ];
  1587. }
  1588. local[ prop.idx ] = clamp( val, prop );
  1589. } );
  1590. if ( from ) {
  1591. ret = color( from( local ) );
  1592. ret[ cache ] = local;
  1593. return ret;
  1594. } else {
  1595. return color( local );
  1596. }
  1597. };
  1598. // Makes red() green() blue() alpha() hue() saturation() lightness()
  1599. each( props, function( key, prop ) {
  1600. // Alpha is included in more than one space
  1601. if ( color.fn[ key ] ) {
  1602. return;
  1603. }
  1604. color.fn[ key ] = function( value ) {
  1605. var vtype = jQuery.type( value ),
  1606. fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
  1607. local = this[ fn ](),
  1608. cur = local[ prop.idx ],
  1609. match;
  1610. if ( vtype === "undefined" ) {
  1611. return cur;
  1612. }
  1613. if ( vtype === "function" ) {
  1614. value = value.call( this, cur );
  1615. vtype = jQuery.type( value );
  1616. }
  1617. if ( value == null && prop.empty ) {
  1618. return this;
  1619. }
  1620. if ( vtype === "string" ) {
  1621. match = rplusequals.exec( value );
  1622. if ( match ) {
  1623. value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
  1624. }
  1625. }
  1626. local[ prop.idx ] = value;
  1627. return this[ fn ]( local );
  1628. };
  1629. } );
  1630. } );
  1631. // Add cssHook and .fx.step function for each named hook.
  1632. // accept a space separated string of properties
  1633. color.hook = function( hook ) {
  1634. var hooks = hook.split( " " );
  1635. each( hooks, function( i, hook ) {
  1636. jQuery.cssHooks[ hook ] = {
  1637. set: function( elem, value ) {
  1638. var parsed, curElem,
  1639. backgroundColor = "";
  1640. if ( value !== "transparent" && ( jQuery.type( value ) !== "string" ||
  1641. ( parsed = stringParse( value ) ) ) ) {
  1642. value = color( parsed || value );
  1643. if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
  1644. curElem = hook === "backgroundColor" ? elem.parentNode : elem;
  1645. while (
  1646. ( backgroundColor === "" || backgroundColor === "transparent" ) &&
  1647. curElem && curElem.style
  1648. ) {
  1649. try {
  1650. backgroundColor = jQuery.css( curElem, "backgroundColor" );
  1651. curElem = curElem.parentNode;
  1652. } catch ( e ) {
  1653. }
  1654. }
  1655. value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
  1656. backgroundColor :
  1657. "_default" );
  1658. }
  1659. value = value.toRgbaString();
  1660. }
  1661. try {
  1662. elem.style[ hook ] = value;
  1663. } catch ( e ) {
  1664. // Wrapped to prevent IE from throwing errors on "invalid" values like
  1665. // 'auto' or 'inherit'
  1666. }
  1667. }
  1668. };
  1669. jQuery.fx.step[ hook ] = function( fx ) {
  1670. if ( !fx.colorInit ) {
  1671. fx.start = color( fx.elem, hook );
  1672. fx.end = color( fx.end );
  1673. fx.colorInit = true;
  1674. }
  1675. jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
  1676. };
  1677. } );
  1678. };
  1679. color.hook( stepHooks );
  1680. jQuery.cssHooks.borderColor = {
  1681. expand: function( value ) {
  1682. var expanded = {};
  1683. each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
  1684. expanded[ "border" + part + "Color" ] = value;
  1685. } );
  1686. return expanded;
  1687. }
  1688. };
  1689. // Basic color names only.
  1690. // Usage of any of the other color names requires adding yourself or including
  1691. // jquery.color.svg-names.js.
  1692. colors = jQuery.Color.names = {
  1693. // 4.1. Basic color keywords
  1694. aqua: "#00ffff",
  1695. black: "#000000",
  1696. blue: "#0000ff",
  1697. fuchsia: "#ff00ff",
  1698. gray: "#808080",
  1699. green: "#008000",
  1700. lime: "#00ff00",
  1701. maroon: "#800000",
  1702. navy: "#000080",
  1703. olive: "#808000",
  1704. purple: "#800080",
  1705. red: "#ff0000",
  1706. silver: "#c0c0c0",
  1707. teal: "#008080",
  1708. white: "#ffffff",
  1709. yellow: "#ffff00",
  1710. // 4.2.3. "transparent" color keyword
  1711. transparent: [ null, null, null, 0 ],
  1712. _default: "#ffffff"
  1713. };
  1714. } )( jQuery );
  1715. /******************************************************************************/
  1716. /****************************** CLASS ANIMATIONS ******************************/
  1717. /******************************************************************************/
  1718. ( function() {
  1719. var classAnimationActions = [ "add", "remove", "toggle" ],
  1720. shorthandStyles = {
  1721. border: 1,
  1722. borderBottom: 1,
  1723. borderColor: 1,
  1724. borderLeft: 1,
  1725. borderRight: 1,
  1726. borderTop: 1,
  1727. borderWidth: 1,
  1728. margin: 1,
  1729. padding: 1
  1730. };
  1731. $.each(
  1732. [ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
  1733. function( _, prop ) {
  1734. $.fx.step[ prop ] = function( fx ) {
  1735. if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
  1736. jQuery.style( fx.elem, prop, fx.end );
  1737. fx.setAttr = true;
  1738. }
  1739. };
  1740. }
  1741. );
  1742. function getElementStyles( elem ) {
  1743. var key, len,
  1744. style = elem.ownerDocument.defaultView ?
  1745. elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
  1746. elem.currentStyle,
  1747. styles = {};
  1748. if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
  1749. len = style.length;
  1750. while ( len-- ) {
  1751. key = style[ len ];
  1752. if ( typeof style[ key ] === "string" ) {
  1753. styles[ $.camelCase( key ) ] = style[ key ];
  1754. }
  1755. }
  1756. // Support: Opera, IE <9
  1757. } else {
  1758. for ( key in style ) {
  1759. if ( typeof style[ key ] === "string" ) {
  1760. styles[ key ] = style[ key ];
  1761. }
  1762. }
  1763. }
  1764. return styles;
  1765. }
  1766. function styleDifference( oldStyle, newStyle ) {
  1767. var diff = {},
  1768. name, value;
  1769. for ( name in newStyle ) {
  1770. value = newStyle[ name ];
  1771. if ( oldStyle[ name ] !== value ) {
  1772. if ( !shorthandStyles[ name ] ) {
  1773. if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
  1774. diff[ name ] = value;
  1775. }
  1776. }
  1777. }
  1778. }
  1779. return diff;
  1780. }
  1781. // Support: jQuery <1.8
  1782. if ( !$.fn.addBack ) {
  1783. $.fn.addBack = function( selector ) {
  1784. return this.add( selector == null ?
  1785. this.prevObject : this.prevObject.filter( selector )
  1786. );
  1787. };
  1788. }
  1789. $.effects.animateClass = function( value, duration, easing, callback ) {
  1790. var o = $.speed( duration, easing, callback );
  1791. return this.queue( function() {
  1792. var animated = $( this ),
  1793. baseClass = animated.attr( "class" ) || "",
  1794. applyClassChange,
  1795. allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
  1796. // Map the animated objects to store the original styles.
  1797. allAnimations = allAnimations.map( function() {
  1798. var el = $( this );
  1799. return {
  1800. el: el,
  1801. start: getElementStyles( this )
  1802. };
  1803. } );
  1804. // Apply class change
  1805. applyClassChange = function() {
  1806. $.each( classAnimationActions, function( i, action ) {
  1807. if ( value[ action ] ) {
  1808. animated[ action + "Class" ]( value[ action ] );
  1809. }
  1810. } );
  1811. };
  1812. applyClassChange();
  1813. // Map all animated objects again - calculate new styles and diff
  1814. allAnimations = allAnimations.map( function() {
  1815. this.end = getElementStyles( this.el[ 0 ] );
  1816. this.diff = styleDifference( this.start, this.end );
  1817. return this;
  1818. } );
  1819. // Apply original class
  1820. animated.attr( "class", baseClass );
  1821. // Map all animated objects again - this time collecting a promise
  1822. allAnimations = allAnimations.map( function() {
  1823. var styleInfo = this,
  1824. dfd = $.Deferred(),
  1825. opts = $.extend( {}, o, {
  1826. queue: false,
  1827. complete: function() {
  1828. dfd.resolve( styleInfo );
  1829. }
  1830. } );
  1831. this.el.animate( this.diff, opts );
  1832. return dfd.promise();
  1833. } );
  1834. // Once all animations have completed:
  1835. $.when.apply( $, allAnimations.get() ).done( function() {
  1836. // Set the final class
  1837. applyClassChange();
  1838. // For each animated element,
  1839. // clear all css properties that were animated
  1840. $.each( arguments, function() {
  1841. var el = this.el;
  1842. $.each( this.diff, function( key ) {
  1843. el.css( key, "" );
  1844. } );
  1845. } );
  1846. // This is guarnteed to be there if you use jQuery.speed()
  1847. // it also handles dequeuing the next anim...
  1848. o.complete.call( animated[ 0 ] );
  1849. } );
  1850. } );
  1851. };
  1852. $.fn.extend( {
  1853. addClass: ( function( orig ) {
  1854. return function( classNames, speed, easing, callback ) {
  1855. return speed ?
  1856. $.effects.animateClass.call( this,
  1857. { add: classNames }, speed, easing, callback ) :
  1858. orig.apply( this, arguments );
  1859. };
  1860. } )( $.fn.addClass ),
  1861. removeClass: ( function( orig ) {
  1862. return function( classNames, speed, easing, callback ) {
  1863. return arguments.length > 1 ?
  1864. $.effects.animateClass.call( this,
  1865. { remove: classNames }, speed, easing, callback ) :
  1866. orig.apply( this, arguments );
  1867. };
  1868. } )( $.fn.removeClass ),
  1869. toggleClass: ( function( orig ) {
  1870. return function( classNames, force, speed, easing, callback ) {
  1871. if ( typeof force === "boolean" || force === undefined ) {
  1872. if ( !speed ) {
  1873. // Without speed parameter
  1874. return orig.apply( this, arguments );
  1875. } else {
  1876. return $.effects.animateClass.call( this,
  1877. ( force ? { add: classNames } : { remove: classNames } ),
  1878. speed, easing, callback );
  1879. }
  1880. } else {
  1881. // Without force parameter
  1882. return $.effects.animateClass.call( this,
  1883. { toggle: classNames }, force, speed, easing );
  1884. }
  1885. };
  1886. } )( $.fn.toggleClass ),
  1887. switchClass: function( remove, add, speed, easing, callback ) {
  1888. return $.effects.animateClass.call( this, {
  1889. add: add,
  1890. remove: remove
  1891. }, speed, easing, callback );
  1892. }
  1893. } );
  1894. } )();
  1895. /******************************************************************************/
  1896. /*********************************** EFFECTS **********************************/
  1897. /******************************************************************************/
  1898. ( function() {
  1899. if ( $.expr && $.expr.filters && $.expr.filters.animated ) {
  1900. $.expr.filters.animated = ( function( orig ) {
  1901. return function( elem ) {
  1902. return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
  1903. };
  1904. } )( $.expr.filters.animated );
  1905. }
  1906. if ( $.uiBackCompat !== false ) {
  1907. $.extend( $.effects, {
  1908. // Saves a set of properties in a data storage
  1909. save: function( element, set ) {
  1910. var i = 0, length = set.length;
  1911. for ( ; i < length; i++ ) {
  1912. if ( set[ i ] !== null ) {
  1913. element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
  1914. }
  1915. }
  1916. },
  1917. // Restores a set of previously saved properties from a data storage
  1918. restore: function( element, set ) {
  1919. var val, i = 0, length = set.length;
  1920. for ( ; i < length; i++ ) {
  1921. if ( set[ i ] !== null ) {
  1922. val = element.data( dataSpace + set[ i ] );
  1923. element.css( set[ i ], val );
  1924. }
  1925. }
  1926. },
  1927. setMode: function( el, mode ) {
  1928. if ( mode === "toggle" ) {
  1929. mode = el.is( ":hidden" ) ? "show" : "hide";
  1930. }
  1931. return mode;
  1932. },
  1933. // Wraps the element around a wrapper that copies position properties
  1934. createWrapper: function( element ) {
  1935. // If the element is already wrapped, return it
  1936. if ( element.parent().is( ".ui-effects-wrapper" ) ) {
  1937. return element.parent();
  1938. }
  1939. // Wrap the element
  1940. var props = {
  1941. width: element.outerWidth( true ),
  1942. height: element.outerHeight( true ),
  1943. "float": element.css( "float" )
  1944. },
  1945. wrapper = $( "<div></div>" )
  1946. .addClass( "ui-effects-wrapper" )
  1947. .css( {
  1948. fontSize: "100%",
  1949. background: "transparent",
  1950. border: "none",
  1951. margin: 0,
  1952. padding: 0
  1953. } ),
  1954. // Store the size in case width/height are defined in % - Fixes #5245
  1955. size = {
  1956. width: element.width(),
  1957. height: element.height()
  1958. },
  1959. active = document.activeElement;
  1960. // Support: Firefox
  1961. // Firefox incorrectly exposes anonymous content
  1962. // https://bugzilla.mozilla.org/show_bug.cgi?id=561664
  1963. try {
  1964. active.id;
  1965. } catch ( e ) {
  1966. active = document.body;
  1967. }
  1968. element.wrap( wrapper );
  1969. // Fixes #7595 - Elements lose focus when wrapped.
  1970. if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
  1971. $( active ).trigger( "focus" );
  1972. }
  1973. // Hotfix for jQuery 1.4 since some change in wrap() seems to actually
  1974. // lose the reference to the wrapped element
  1975. wrapper = element.parent();
  1976. // Transfer positioning properties to the wrapper
  1977. if ( element.css( "position" ) === "static" ) {
  1978. wrapper.css( { position: "relative" } );
  1979. element.css( { position: "relative" } );
  1980. } else {
  1981. $.extend( props, {
  1982. position: element.css( "position" ),
  1983. zIndex: element.css( "z-index" )
  1984. } );
  1985. $.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
  1986. props[ pos ] = element.css( pos );
  1987. if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
  1988. props[ pos ] = "auto";
  1989. }
  1990. } );
  1991. element.css( {
  1992. position: "relative",
  1993. top: 0,
  1994. left: 0,
  1995. right: "auto",
  1996. bottom: "auto"
  1997. } );
  1998. }
  1999. element.css( size );
  2000. return wrapper.css( props ).show();
  2001. },
  2002. removeWrapper: function( element ) {
  2003. var active = document.activeElement;
  2004. if ( element.parent().is( ".ui-effects-wrapper" ) ) {
  2005. element.parent().replaceWith( element );
  2006. // Fixes #7595 - Elements lose focus when wrapped.
  2007. if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
  2008. $( active ).trigger( "focus" );
  2009. }
  2010. }
  2011. return element;
  2012. }
  2013. } );
  2014. }
  2015. $.extend( $.effects, {
  2016. version: "1.12.1",
  2017. define: function( name, mode, effect ) {
  2018. if ( !effect ) {
  2019. effect = mode;
  2020. mode = "effect";
  2021. }
  2022. $.effects.effect[ name ] = effect;
  2023. $.effects.effect[ name ].mode = mode;
  2024. return effect;
  2025. },
  2026. scaledDimensions: function( element, percent, direction ) {
  2027. if ( percent === 0 ) {
  2028. return {
  2029. height: 0,
  2030. width: 0,
  2031. outerHeight: 0,
  2032. outerWidth: 0
  2033. };
  2034. }
  2035. var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
  2036. y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
  2037. return {
  2038. height: element.height() * y,
  2039. width: element.width() * x,
  2040. outerHeight: element.outerHeight() * y,
  2041. outerWidth: element.outerWidth() * x
  2042. };
  2043. },
  2044. clipToBox: function( animation ) {
  2045. return {
  2046. width: animation.clip.right - animation.clip.left,
  2047. height: animation.clip.bottom - animation.clip.top,
  2048. left: animation.clip.left,
  2049. top: animation.clip.top
  2050. };
  2051. },
  2052. // Injects recently queued functions to be first in line (after "inprogress")
  2053. unshift: function( element, queueLength, count ) {
  2054. var queue = element.queue();
  2055. if ( queueLength > 1 ) {
  2056. queue.splice.apply( queue,
  2057. [ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
  2058. }
  2059. element.dequeue();
  2060. },
  2061. saveStyle: function( element ) {
  2062. element.data( dataSpaceStyle, element[ 0 ].style.cssText );
  2063. },
  2064. restoreStyle: function( element ) {
  2065. element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
  2066. element.removeData( dataSpaceStyle );
  2067. },
  2068. mode: function( element, mode ) {
  2069. var hidden = element.is( ":hidden" );
  2070. if ( mode === "toggle" ) {
  2071. mode = hidden ? "show" : "hide";
  2072. }
  2073. if ( hidden ? mode === "hide" : mode === "show" ) {
  2074. mode = "none";
  2075. }
  2076. return mode;
  2077. },
  2078. // Translates a [top,left] array into a baseline value
  2079. getBaseline: function( origin, original ) {
  2080. var y, x;
  2081. switch ( origin[ 0 ] ) {
  2082. case "top":
  2083. y = 0;
  2084. break;
  2085. case "middle":
  2086. y = 0.5;
  2087. break;
  2088. case "bottom":
  2089. y = 1;
  2090. break;
  2091. default:
  2092. y = origin[ 0 ] / original.height;
  2093. }
  2094. switch ( origin[ 1 ] ) {
  2095. case "left":
  2096. x = 0;
  2097. break;
  2098. case "center":
  2099. x = 0.5;
  2100. break;
  2101. case "right":
  2102. x = 1;
  2103. break;
  2104. default:
  2105. x = origin[ 1 ] / original.width;
  2106. }
  2107. return {
  2108. x: x,
  2109. y: y
  2110. };
  2111. },
  2112. // Creates a placeholder element so that the original element can be made absolute
  2113. createPlaceholder: function( element ) {
  2114. var placeholder,
  2115. cssPosition = element.css( "position" ),
  2116. position = element.position();
  2117. // Lock in margins first to account for form elements, which
  2118. // will change margin if you explicitly set height
  2119. // see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
  2120. // Support: Safari
  2121. element.css( {
  2122. marginTop: element.css( "marginTop" ),
  2123. marginBottom: element.css( "marginBottom" ),
  2124. marginLeft: element.css( "marginLeft" ),
  2125. marginRight: element.css( "marginRight" )
  2126. } )
  2127. .outerWidth( element.outerWidth() )
  2128. .outerHeight( element.outerHeight() );
  2129. if ( /^(static|relative)/.test( cssPosition ) ) {
  2130. cssPosition = "absolute";
  2131. placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {
  2132. // Convert inline to inline block to account for inline elements
  2133. // that turn to inline block based on content (like img)
  2134. display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
  2135. "inline-block" :
  2136. "block",
  2137. visibility: "hidden",
  2138. // Margins need to be set to account for margin collapse
  2139. marginTop: element.css( "marginTop" ),
  2140. marginBottom: element.css( "marginBottom" ),
  2141. marginLeft: element.css( "marginLeft" ),
  2142. marginRight: element.css( "marginRight" ),
  2143. "float": element.css( "float" )
  2144. } )
  2145. .outerWidth( element.outerWidth() )
  2146. .outerHeight( element.outerHeight() )
  2147. .addClass( "ui-effects-placeholder" );
  2148. element.data( dataSpace + "placeholder", placeholder );
  2149. }
  2150. element.css( {
  2151. position: cssPosition,
  2152. left: position.left,
  2153. top: position.top
  2154. } );
  2155. return placeholder;
  2156. },
  2157. removePlaceholder: function( element ) {
  2158. var dataKey = dataSpace + "placeholder",
  2159. placeholder = element.data( dataKey );
  2160. if ( placeholder ) {
  2161. placeholder.remove();
  2162. element.removeData( dataKey );
  2163. }
  2164. },
  2165. // Removes a placeholder if it exists and restores
  2166. // properties that were modified during placeholder creation
  2167. cleanUp: function( element ) {
  2168. $.effects.restoreStyle( element );
  2169. $.effects.removePlaceholder( element );
  2170. },
  2171. setTransition: function( element, list, factor, value ) {
  2172. value = value || {};
  2173. $.each( list, function( i, x ) {
  2174. var unit = element.cssUnit( x );
  2175. if ( unit[ 0 ] > 0 ) {
  2176. value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
  2177. }
  2178. } );
  2179. return value;
  2180. }
  2181. } );
  2182. // Return an effect options object for the given parameters:
  2183. function _normalizeArguments( effect, options, speed, callback ) {
  2184. // Allow passing all options as the first parameter
  2185. if ( $.isPlainObject( effect ) ) {
  2186. options = effect;
  2187. effect = effect.effect;
  2188. }
  2189. // Convert to an object
  2190. effect = { effect: effect };
  2191. // Catch (effect, null, ...)
  2192. if ( options == null ) {
  2193. options = {};
  2194. }
  2195. // Catch (effect, callback)
  2196. if ( $.isFunction( options ) ) {
  2197. callback = options;
  2198. speed = null;
  2199. options = {};
  2200. }
  2201. // Catch (effect, speed, ?)
  2202. if ( typeof options === "number" || $.fx.speeds[ options ] ) {
  2203. callback = speed;
  2204. speed = options;
  2205. options = {};
  2206. }
  2207. // Catch (effect, options, callback)
  2208. if ( $.isFunction( speed ) ) {
  2209. callback = speed;
  2210. speed = null;
  2211. }
  2212. // Add options to effect
  2213. if ( options ) {
  2214. $.extend( effect, options );
  2215. }
  2216. speed = speed || options.duration;
  2217. effect.duration = $.fx.off ? 0 :
  2218. typeof speed === "number" ? speed :
  2219. speed in $.fx.speeds ? $.fx.speeds[ speed ] :
  2220. $.fx.speeds._default;
  2221. effect.complete = callback || options.complete;
  2222. return effect;
  2223. }
  2224. function standardAnimationOption( option ) {
  2225. // Valid standard speeds (nothing, number, named speed)
  2226. if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
  2227. return true;
  2228. }
  2229. // Invalid strings - treat as "normal" speed
  2230. if ( typeof option === "string" && !$.effects.effect[ option ] ) {
  2231. return true;
  2232. }
  2233. // Complete callback
  2234. if ( $.isFunction( option ) ) {
  2235. return true;
  2236. }
  2237. // Options hash (but not naming an effect)
  2238. if ( typeof option === "object" && !option.effect ) {
  2239. return true;
  2240. }
  2241. // Didn't match any standard API
  2242. return false;
  2243. }
  2244. $.fn.extend( {
  2245. effect: function( /* effect, options, speed, callback */ ) {
  2246. var args = _normalizeArguments.apply( this, arguments ),
  2247. effectMethod = $.effects.effect[ args.effect ],
  2248. defaultMode = effectMethod.mode,
  2249. queue = args.queue,
  2250. queueName = queue || "fx",
  2251. complete = args.complete,
  2252. mode = args.mode,
  2253. modes = [],
  2254. prefilter = function( next ) {
  2255. var el = $( this ),
  2256. normalizedMode = $.effects.mode( el, mode ) || defaultMode;
  2257. // Sentinel for duck-punching the :animated psuedo-selector
  2258. el.data( dataSpaceAnimated, true );
  2259. // Save effect mode for later use,
  2260. // we can't just call $.effects.mode again later,
  2261. // as the .show() below destroys the initial state
  2262. modes.push( normalizedMode );
  2263. // See $.uiBackCompat inside of run() for removal of defaultMode in 1.13
  2264. if ( defaultMode && ( normalizedMode === "show" ||
  2265. ( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
  2266. el.show();
  2267. }
  2268. if ( !defaultMode || normalizedMode !== "none" ) {
  2269. $.effects.saveStyle( el );
  2270. }
  2271. if ( $.isFunction( next ) ) {
  2272. next();
  2273. }
  2274. };
  2275. if ( $.fx.off || !effectMethod ) {
  2276. // Delegate to the original method (e.g., .show()) if possible
  2277. if ( mode ) {
  2278. return this[ mode ]( args.duration, complete );
  2279. } else {
  2280. return this.each( function() {
  2281. if ( complete ) {
  2282. complete.call( this );
  2283. }
  2284. } );
  2285. }
  2286. }
  2287. function run( next ) {
  2288. var elem = $( this );
  2289. function cleanup() {
  2290. elem.removeData( dataSpaceAnimated );
  2291. $.effects.cleanUp( elem );
  2292. if ( args.mode === "hide" ) {
  2293. elem.hide();
  2294. }
  2295. done();
  2296. }
  2297. function done() {
  2298. if ( $.isFunction( complete ) ) {
  2299. complete.call( elem[ 0 ] );
  2300. }
  2301. if ( $.isFunction( next ) ) {
  2302. next();
  2303. }
  2304. }
  2305. // Override mode option on a per element basis,
  2306. // as toggle can be either show or hide depending on element state
  2307. args.mode = modes.shift();
  2308. if ( $.uiBackCompat !== false && !defaultMode ) {
  2309. if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
  2310. // Call the core method to track "olddisplay" properly
  2311. elem[ mode ]();
  2312. done();
  2313. } else {
  2314. effectMethod.call( elem[ 0 ], args, done );
  2315. }
  2316. } else {
  2317. if ( args.mode === "none" ) {
  2318. // Call the core method to track "olddisplay" properly
  2319. elem[ mode ]();
  2320. done();
  2321. } else {
  2322. effectMethod.call( elem[ 0 ], args, cleanup );
  2323. }
  2324. }
  2325. }
  2326. // Run prefilter on all elements first to ensure that
  2327. // any showing or hiding happens before placeholder creation,
  2328. // which ensures that any layout changes are correctly captured.
  2329. return queue === false ?
  2330. this.each( prefilter ).each( run ) :
  2331. this.queue( queueName, prefilter ).queue( queueName, run );
  2332. },
  2333. show: ( function( orig ) {
  2334. return function( option ) {
  2335. if ( standardAnimationOption( option ) ) {
  2336. return orig.apply( this, arguments );
  2337. } else {
  2338. var args = _normalizeArguments.apply( this, arguments );
  2339. args.mode = "show";
  2340. return this.effect.call( this, args );
  2341. }
  2342. };
  2343. } )( $.fn.show ),
  2344. hide: ( function( orig ) {
  2345. return function( option ) {
  2346. if ( standardAnimationOption( option ) ) {
  2347. return orig.apply( this, arguments );
  2348. } else {
  2349. var args = _normalizeArguments.apply( this, arguments );
  2350. args.mode = "hide";
  2351. return this.effect.call( this, args );
  2352. }
  2353. };
  2354. } )( $.fn.hide ),
  2355. toggle: ( function( orig ) {
  2356. return function( option ) {
  2357. if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
  2358. return orig.apply( this, arguments );
  2359. } else {
  2360. var args = _normalizeArguments.apply( this, arguments );
  2361. args.mode = "toggle";
  2362. return this.effect.call( this, args );
  2363. }
  2364. };
  2365. } )( $.fn.toggle ),
  2366. cssUnit: function( key ) {
  2367. var style = this.css( key ),
  2368. val = [];
  2369. $.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
  2370. if ( style.indexOf( unit ) > 0 ) {
  2371. val = [ parseFloat( style ), unit ];
  2372. }
  2373. } );
  2374. return val;
  2375. },
  2376. cssClip: function( clipObj ) {
  2377. if ( clipObj ) {
  2378. return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
  2379. clipObj.bottom + "px " + clipObj.left + "px)" );
  2380. }
  2381. return parseClip( this.css( "clip" ), this );
  2382. },
  2383. transfer: function( options, done ) {
  2384. var element = $( this ),
  2385. target = $( options.to ),
  2386. targetFixed = target.css( "position" ) === "fixed",
  2387. body = $( "body" ),
  2388. fixTop = targetFixed ? body.scrollTop() : 0,
  2389. fixLeft = targetFixed ? body.scrollLeft() : 0,
  2390. endPosition = target.offset(),
  2391. animation = {
  2392. top: endPosition.top - fixTop,
  2393. left: endPosition.left - fixLeft,
  2394. height: target.innerHeight(),
  2395. width: target.innerWidth()
  2396. },
  2397. startPosition = element.offset(),
  2398. transfer = $( "<div class='ui-effects-transfer'></div>" )
  2399. .appendTo( "body" )
  2400. .addClass( options.className )
  2401. .css( {
  2402. top: startPosition.top - fixTop,
  2403. left: startPosition.left - fixLeft,
  2404. height: element.innerHeight(),
  2405. width: element.innerWidth(),
  2406. position: targetFixed ? "fixed" : "absolute"
  2407. } )
  2408. .animate( animation, options.duration, options.easing, function() {
  2409. transfer.remove();
  2410. if ( $.isFunction( done ) ) {
  2411. done();
  2412. }
  2413. } );
  2414. }
  2415. } );
  2416. function parseClip( str, element ) {
  2417. var outerWidth = element.outerWidth(),
  2418. outerHeight = element.outerHeight(),
  2419. 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)\)$/,
  2420. values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
  2421. return {
  2422. top: parseFloat( values[ 1 ] ) || 0,
  2423. right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
  2424. bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
  2425. left: parseFloat( values[ 4 ] ) || 0
  2426. };
  2427. }
  2428. $.fx.step.clip = function( fx ) {
  2429. if ( !fx.clipInit ) {
  2430. fx.start = $( fx.elem ).cssClip();
  2431. if ( typeof fx.end === "string" ) {
  2432. fx.end = parseClip( fx.end, fx.elem );
  2433. }
  2434. fx.clipInit = true;
  2435. }
  2436. $( fx.elem ).cssClip( {
  2437. top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
  2438. right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
  2439. bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
  2440. left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
  2441. } );
  2442. };
  2443. } )();
  2444. /******************************************************************************/
  2445. /*********************************** EASING ***********************************/
  2446. /******************************************************************************/
  2447. ( function() {
  2448. // Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
  2449. var baseEasings = {};
  2450. $.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
  2451. baseEasings[ name ] = function( p ) {
  2452. return Math.pow( p, i + 2 );
  2453. };
  2454. } );
  2455. $.extend( baseEasings, {
  2456. Sine: function( p ) {
  2457. return 1 - Math.cos( p * Math.PI / 2 );
  2458. },
  2459. Circ: function( p ) {
  2460. return 1 - Math.sqrt( 1 - p * p );
  2461. },
  2462. Elastic: function( p ) {
  2463. return p === 0 || p === 1 ? p :
  2464. -Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
  2465. },
  2466. Back: function( p ) {
  2467. return p * p * ( 3 * p - 2 );
  2468. },
  2469. Bounce: function( p ) {
  2470. var pow2,
  2471. bounce = 4;
  2472. while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
  2473. return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
  2474. }
  2475. } );
  2476. $.each( baseEasings, function( name, easeIn ) {
  2477. $.easing[ "easeIn" + name ] = easeIn;
  2478. $.easing[ "easeOut" + name ] = function( p ) {
  2479. return 1 - easeIn( 1 - p );
  2480. };
  2481. $.easing[ "easeInOut" + name ] = function( p ) {
  2482. return p < 0.5 ?
  2483. easeIn( p * 2 ) / 2 :
  2484. 1 - easeIn( p * -2 + 2 ) / 2;
  2485. };
  2486. } );
  2487. } )();
  2488. var effect = $.effects;
  2489. /*!
  2490. * jQuery UI Effects Blind 1.12.1
  2491. * http://jqueryui.com
  2492. *
  2493. * Copyright jQuery Foundation and other contributors
  2494. * Released under the MIT license.
  2495. * http://jquery.org/license
  2496. */
  2497. //>>label: Blind Effect
  2498. //>>group: Effects
  2499. //>>description: Blinds the element.
  2500. //>>docs: http://api.jqueryui.com/blind-effect/
  2501. //>>demos: http://jqueryui.com/effect/
  2502. var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
  2503. var map = {
  2504. up: [ "bottom", "top" ],
  2505. vertical: [ "bottom", "top" ],
  2506. down: [ "top", "bottom" ],
  2507. left: [ "right", "left" ],
  2508. horizontal: [ "right", "left" ],
  2509. right: [ "left", "right" ]
  2510. },
  2511. element = $( this ),
  2512. direction = options.direction || "up",
  2513. start = element.cssClip(),
  2514. animate = { clip: $.extend( {}, start ) },
  2515. placeholder = $.effects.createPlaceholder( element );
  2516. animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
  2517. if ( options.mode === "show" ) {
  2518. element.cssClip( animate.clip );
  2519. if ( placeholder ) {
  2520. placeholder.css( $.effects.clipToBox( animate ) );
  2521. }
  2522. animate.clip = start;
  2523. }
  2524. if ( placeholder ) {
  2525. placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
  2526. }
  2527. element.animate( animate, {
  2528. queue: false,
  2529. duration: options.duration,
  2530. easing: options.easing,
  2531. complete: done
  2532. } );
  2533. } );
  2534. /*!
  2535. * jQuery UI Effects Bounce 1.12.1
  2536. * http://jqueryui.com
  2537. *
  2538. * Copyright jQuery Foundation and other contributors
  2539. * Released under the MIT license.
  2540. * http://jquery.org/license
  2541. */
  2542. //>>label: Bounce Effect
  2543. //>>group: Effects
  2544. //>>description: Bounces an element horizontally or vertically n times.
  2545. //>>docs: http://api.jqueryui.com/bounce-effect/
  2546. //>>demos: http://jqueryui.com/effect/
  2547. var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
  2548. var upAnim, downAnim, refValue,
  2549. element = $( this ),
  2550. // Defaults:
  2551. mode = options.mode,
  2552. hide = mode === "hide",
  2553. show = mode === "show",
  2554. direction = options.direction || "up",
  2555. distance = options.distance,
  2556. times = options.times || 5,
  2557. // Number of internal animations
  2558. anims = times * 2 + ( show || hide ? 1 : 0 ),
  2559. speed = options.duration / anims,
  2560. easing = options.easing,
  2561. // Utility:
  2562. ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
  2563. motion = ( direction === "up" || direction === "left" ),
  2564. i = 0,
  2565. queuelen = element.queue().length;
  2566. $.effects.createPlaceholder( element );
  2567. refValue = element.css( ref );
  2568. // Default distance for the BIGGEST bounce is the outer Distance / 3
  2569. if ( !distance ) {
  2570. distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
  2571. }
  2572. if ( show ) {
  2573. downAnim = { opacity: 1 };
  2574. downAnim[ ref ] = refValue;
  2575. // If we are showing, force opacity 0 and set the initial position
  2576. // then do the "first" animation
  2577. element
  2578. .css( "opacity", 0 )
  2579. .css( ref, motion ? -distance * 2 : distance * 2 )
  2580. .animate( downAnim, speed, easing );
  2581. }
  2582. // Start at the smallest distance if we are hiding
  2583. if ( hide ) {
  2584. distance = distance / Math.pow( 2, times - 1 );
  2585. }
  2586. downAnim = {};
  2587. downAnim[ ref ] = refValue;
  2588. // Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
  2589. for ( ; i < times; i++ ) {
  2590. upAnim = {};
  2591. upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
  2592. element
  2593. .animate( upAnim, speed, easing )
  2594. .animate( downAnim, speed, easing );
  2595. distance = hide ? distance * 2 : distance / 2;
  2596. }
  2597. // Last Bounce when Hiding
  2598. if ( hide ) {
  2599. upAnim = { opacity: 0 };
  2600. upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
  2601. element.animate( upAnim, speed, easing );
  2602. }
  2603. element.queue( done );
  2604. $.effects.unshift( element, queuelen, anims + 1 );
  2605. } );
  2606. /*!
  2607. * jQuery UI Effects Clip 1.12.1
  2608. * http://jqueryui.com
  2609. *
  2610. * Copyright jQuery Foundation and other contributors
  2611. * Released under the MIT license.
  2612. * http://jquery.org/license
  2613. */
  2614. //>>label: Clip Effect
  2615. //>>group: Effects
  2616. //>>description: Clips the element on and off like an old TV.
  2617. //>>docs: http://api.jqueryui.com/clip-effect/
  2618. //>>demos: http://jqueryui.com/effect/
  2619. var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
  2620. var start,
  2621. animate = {},
  2622. element = $( this ),
  2623. direction = options.direction || "vertical",
  2624. both = direction === "both",
  2625. horizontal = both || direction === "horizontal",
  2626. vertical = both || direction === "vertical";
  2627. start = element.cssClip();
  2628. animate.clip = {
  2629. top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
  2630. right: horizontal ? ( start.right - start.left ) / 2 : start.right,
  2631. bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
  2632. left: horizontal ? ( start.right - start.left ) / 2 : start.left
  2633. };
  2634. $.effects.createPlaceholder( element );
  2635. if ( options.mode === "show" ) {
  2636. element.cssClip( animate.clip );
  2637. animate.clip = start;
  2638. }
  2639. element.animate( animate, {
  2640. queue: false,
  2641. duration: options.duration,
  2642. easing: options.easing,
  2643. complete: done
  2644. } );
  2645. } );
  2646. /*!
  2647. * jQuery UI Effects Drop 1.12.1
  2648. * http://jqueryui.com
  2649. *
  2650. * Copyright jQuery Foundation and other contributors
  2651. * Released under the MIT license.
  2652. * http://jquery.org/license
  2653. */
  2654. //>>label: Drop Effect
  2655. //>>group: Effects
  2656. //>>description: Moves an element in one direction and hides it at the same time.
  2657. //>>docs: http://api.jqueryui.com/drop-effect/
  2658. //>>demos: http://jqueryui.com/effect/
  2659. var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {
  2660. var distance,
  2661. element = $( this ),
  2662. mode = options.mode,
  2663. show = mode === "show",
  2664. direction = options.direction || "left",
  2665. ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
  2666. motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
  2667. oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
  2668. animation = {
  2669. opacity: 0
  2670. };
  2671. $.effects.createPlaceholder( element );
  2672. distance = options.distance ||
  2673. element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
  2674. animation[ ref ] = motion + distance;
  2675. if ( show ) {
  2676. element.css( animation );
  2677. animation[ ref ] = oppositeMotion + distance;
  2678. animation.opacity = 1;
  2679. }
  2680. // Animate
  2681. element.animate( animation, {
  2682. queue: false,
  2683. duration: options.duration,
  2684. easing: options.easing,
  2685. complete: done
  2686. } );
  2687. } );
  2688. /*!
  2689. * jQuery UI Effects Explode 1.12.1
  2690. * http://jqueryui.com
  2691. *
  2692. * Copyright jQuery Foundation and other contributors
  2693. * Released under the MIT license.
  2694. * http://jquery.org/license
  2695. */
  2696. //>>label: Explode Effect
  2697. //>>group: Effects
  2698. // jscs:disable maximumLineLength
  2699. //>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
  2700. // jscs:enable maximumLineLength
  2701. //>>docs: http://api.jqueryui.com/explode-effect/
  2702. //>>demos: http://jqueryui.com/effect/
  2703. var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {
  2704. var i, j, left, top, mx, my,
  2705. rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
  2706. cells = rows,
  2707. element = $( this ),
  2708. mode = options.mode,
  2709. show = mode === "show",
  2710. // Show and then visibility:hidden the element before calculating offset
  2711. offset = element.show().css( "visibility", "hidden" ).offset(),
  2712. // Width and height of a piece
  2713. width = Math.ceil( element.outerWidth() / cells ),
  2714. height = Math.ceil( element.outerHeight() / rows ),
  2715. pieces = [];
  2716. // Children animate complete:
  2717. function childComplete() {
  2718. pieces.push( this );
  2719. if ( pieces.length === rows * cells ) {
  2720. animComplete();
  2721. }
  2722. }
  2723. // Clone the element for each row and cell.
  2724. for ( i = 0; i < rows; i++ ) { // ===>
  2725. top = offset.top + i * height;
  2726. my = i - ( rows - 1 ) / 2;
  2727. for ( j = 0; j < cells; j++ ) { // |||
  2728. left = offset.left + j * width;
  2729. mx = j - ( cells - 1 ) / 2;
  2730. // Create a clone of the now hidden main element that will be absolute positioned
  2731. // within a wrapper div off the -left and -top equal to size of our pieces
  2732. element
  2733. .clone()
  2734. .appendTo( "body" )
  2735. .wrap( "<div></div>" )
  2736. .css( {
  2737. position: "absolute",
  2738. visibility: "visible",
  2739. left: -j * width,
  2740. top: -i * height
  2741. } )
  2742. // Select the wrapper - make it overflow: hidden and absolute positioned based on
  2743. // where the original was located +left and +top equal to the size of pieces
  2744. .parent()
  2745. .addClass( "ui-effects-explode" )
  2746. .css( {
  2747. position: "absolute",
  2748. overflow: "hidden",
  2749. width: width,
  2750. height: height,
  2751. left: left + ( show ? mx * width : 0 ),
  2752. top: top + ( show ? my * height : 0 ),
  2753. opacity: show ? 0 : 1
  2754. } )
  2755. .animate( {
  2756. left: left + ( show ? 0 : mx * width ),
  2757. top: top + ( show ? 0 : my * height ),
  2758. opacity: show ? 1 : 0
  2759. }, options.duration || 500, options.easing, childComplete );
  2760. }
  2761. }
  2762. function animComplete() {
  2763. element.css( {
  2764. visibility: "visible"
  2765. } );
  2766. $( pieces ).remove();
  2767. done();
  2768. }
  2769. } );
  2770. /*!
  2771. * jQuery UI Effects Fade 1.12.1
  2772. * http://jqueryui.com
  2773. *
  2774. * Copyright jQuery Foundation and other contributors
  2775. * Released under the MIT license.
  2776. * http://jquery.org/license
  2777. */
  2778. //>>label: Fade Effect
  2779. //>>group: Effects
  2780. //>>description: Fades the element.
  2781. //>>docs: http://api.jqueryui.com/fade-effect/
  2782. //>>demos: http://jqueryui.com/effect/
  2783. var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
  2784. var show = options.mode === "show";
  2785. $( this )
  2786. .css( "opacity", show ? 0 : 1 )
  2787. .animate( {
  2788. opacity: show ? 1 : 0
  2789. }, {
  2790. queue: false,
  2791. duration: options.duration,
  2792. easing: options.easing,
  2793. complete: done
  2794. } );
  2795. } );
  2796. /*!
  2797. * jQuery UI Effects Fold 1.12.1
  2798. * http://jqueryui.com
  2799. *
  2800. * Copyright jQuery Foundation and other contributors
  2801. * Released under the MIT license.
  2802. * http://jquery.org/license
  2803. */
  2804. //>>label: Fold Effect
  2805. //>>group: Effects
  2806. //>>description: Folds an element first horizontally and then vertically.
  2807. //>>docs: http://api.jqueryui.com/fold-effect/
  2808. //>>demos: http://jqueryui.com/effect/
  2809. var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {
  2810. // Create element
  2811. var element = $( this ),
  2812. mode = options.mode,
  2813. show = mode === "show",
  2814. hide = mode === "hide",
  2815. size = options.size || 15,
  2816. percent = /([0-9]+)%/.exec( size ),
  2817. horizFirst = !!options.horizFirst,
  2818. ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
  2819. duration = options.duration / 2,
  2820. placeholder = $.effects.createPlaceholder( element ),
  2821. start = element.cssClip(),
  2822. animation1 = { clip: $.extend( {}, start ) },
  2823. animation2 = { clip: $.extend( {}, start ) },
  2824. distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
  2825. queuelen = element.queue().length;
  2826. if ( percent ) {
  2827. size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
  2828. }
  2829. animation1.clip[ ref[ 0 ] ] = size;
  2830. animation2.clip[ ref[ 0 ] ] = size;
  2831. animation2.clip[ ref[ 1 ] ] = 0;
  2832. if ( show ) {
  2833. element.cssClip( animation2.clip );
  2834. if ( placeholder ) {
  2835. placeholder.css( $.effects.clipToBox( animation2 ) );
  2836. }
  2837. animation2.clip = start;
  2838. }
  2839. // Animate
  2840. element
  2841. .queue( function( next ) {
  2842. if ( placeholder ) {
  2843. placeholder
  2844. .animate( $.effects.clipToBox( animation1 ), duration, options.easing )
  2845. .animate( $.effects.clipToBox( animation2 ), duration, options.easing );
  2846. }
  2847. next();
  2848. } )
  2849. .animate( animation1, duration, options.easing )
  2850. .animate( animation2, duration, options.easing )
  2851. .queue( done );
  2852. $.effects.unshift( element, queuelen, 4 );
  2853. } );
  2854. /*!
  2855. * jQuery UI Effects Highlight 1.12.1
  2856. * http://jqueryui.com
  2857. *
  2858. * Copyright jQuery Foundation and other contributors
  2859. * Released under the MIT license.
  2860. * http://jquery.org/license
  2861. */
  2862. //>>label: Highlight Effect
  2863. //>>group: Effects
  2864. //>>description: Highlights the background of an element in a defined color for a custom duration.
  2865. //>>docs: http://api.jqueryui.com/highlight-effect/
  2866. //>>demos: http://jqueryui.com/effect/
  2867. var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
  2868. var element = $( this ),
  2869. animation = {
  2870. backgroundColor: element.css( "backgroundColor" )
  2871. };
  2872. if ( options.mode === "hide" ) {
  2873. animation.opacity = 0;
  2874. }
  2875. $.effects.saveStyle( element );
  2876. element
  2877. .css( {
  2878. backgroundImage: "none",
  2879. backgroundColor: options.color || "#ffff99"
  2880. } )
  2881. .animate( animation, {
  2882. queue: false,
  2883. duration: options.duration,
  2884. easing: options.easing,
  2885. complete: done
  2886. } );
  2887. } );
  2888. /*!
  2889. * jQuery UI Effects Size 1.12.1
  2890. * http://jqueryui.com
  2891. *
  2892. * Copyright jQuery Foundation and other contributors
  2893. * Released under the MIT license.
  2894. * http://jquery.org/license
  2895. */
  2896. //>>label: Size Effect
  2897. //>>group: Effects
  2898. //>>description: Resize an element to a specified width and height.
  2899. //>>docs: http://api.jqueryui.com/size-effect/
  2900. //>>demos: http://jqueryui.com/effect/
  2901. var effectsEffectSize = $.effects.define( "size", function( options, done ) {
  2902. // Create element
  2903. var baseline, factor, temp,
  2904. element = $( this ),
  2905. // Copy for children
  2906. cProps = [ "fontSize" ],
  2907. vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
  2908. hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
  2909. // Set options
  2910. mode = options.mode,
  2911. restore = mode !== "effect",
  2912. scale = options.scale || "both",
  2913. origin = options.origin || [ "middle", "center" ],
  2914. position = element.css( "position" ),
  2915. pos = element.position(),
  2916. original = $.effects.scaledDimensions( element ),
  2917. from = options.from || original,
  2918. to = options.to || $.effects.scaledDimensions( element, 0 );
  2919. $.effects.createPlaceholder( element );
  2920. if ( mode === "show" ) {
  2921. temp = from;
  2922. from = to;
  2923. to = temp;
  2924. }
  2925. // Set scaling factor
  2926. factor = {
  2927. from: {
  2928. y: from.height / original.height,
  2929. x: from.width / original.width
  2930. },
  2931. to: {
  2932. y: to.height / original.height,
  2933. x: to.width / original.width
  2934. }
  2935. };
  2936. // Scale the css box
  2937. if ( scale === "box" || scale === "both" ) {
  2938. // Vertical props scaling
  2939. if ( factor.from.y !== factor.to.y ) {
  2940. from = $.effects.setTransition( element, vProps, factor.from.y, from );
  2941. to = $.effects.setTransition( element, vProps, factor.to.y, to );
  2942. }
  2943. // Horizontal props scaling
  2944. if ( factor.from.x !== factor.to.x ) {
  2945. from = $.effects.setTransition( element, hProps, factor.from.x, from );
  2946. to = $.effects.setTransition( element, hProps, factor.to.x, to );
  2947. }
  2948. }
  2949. // Scale the content
  2950. if ( scale === "content" || scale === "both" ) {
  2951. // Vertical props scaling
  2952. if ( factor.from.y !== factor.to.y ) {
  2953. from = $.effects.setTransition( element, cProps, factor.from.y, from );
  2954. to = $.effects.setTransition( element, cProps, factor.to.y, to );
  2955. }
  2956. }
  2957. // Adjust the position properties based on the provided origin points
  2958. if ( origin ) {
  2959. baseline = $.effects.getBaseline( origin, original );
  2960. from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
  2961. from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
  2962. to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
  2963. to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
  2964. }
  2965. element.css( from );
  2966. // Animate the children if desired
  2967. if ( scale === "content" || scale === "both" ) {
  2968. vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
  2969. hProps = hProps.concat( [ "marginLeft", "marginRight" ] );
  2970. // Only animate children with width attributes specified
  2971. // TODO: is this right? should we include anything with css width specified as well
  2972. element.find( "*[width]" ).each( function() {
  2973. var child = $( this ),
  2974. childOriginal = $.effects.scaledDimensions( child ),
  2975. childFrom = {
  2976. height: childOriginal.height * factor.from.y,
  2977. width: childOriginal.width * factor.from.x,
  2978. outerHeight: childOriginal.outerHeight * factor.from.y,
  2979. outerWidth: childOriginal.outerWidth * factor.from.x
  2980. },
  2981. childTo = {
  2982. height: childOriginal.height * factor.to.y,
  2983. width: childOriginal.width * factor.to.x,
  2984. outerHeight: childOriginal.height * factor.to.y,
  2985. outerWidth: childOriginal.width * factor.to.x
  2986. };
  2987. // Vertical props scaling
  2988. if ( factor.from.y !== factor.to.y ) {
  2989. childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
  2990. childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
  2991. }
  2992. // Horizontal props scaling
  2993. if ( factor.from.x !== factor.to.x ) {
  2994. childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
  2995. childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
  2996. }
  2997. if ( restore ) {
  2998. $.effects.saveStyle( child );
  2999. }
  3000. // Animate children
  3001. child.css( childFrom );
  3002. child.animate( childTo, options.duration, options.easing, function() {
  3003. // Restore children
  3004. if ( restore ) {
  3005. $.effects.restoreStyle( child );
  3006. }
  3007. } );
  3008. } );
  3009. }
  3010. // Animate
  3011. element.animate( to, {
  3012. queue: false,
  3013. duration: options.duration,
  3014. easing: options.easing,
  3015. complete: function() {
  3016. var offset = element.offset();
  3017. if ( to.opacity === 0 ) {
  3018. element.css( "opacity", from.opacity );
  3019. }
  3020. if ( !restore ) {
  3021. element
  3022. .css( "position", position === "static" ? "relative" : position )
  3023. .offset( offset );
  3024. // Need to save style here so that automatic style restoration
  3025. // doesn't restore to the original styles from before the animation.
  3026. $.effects.saveStyle( element );
  3027. }
  3028. done();
  3029. }
  3030. } );
  3031. } );
  3032. /*!
  3033. * jQuery UI Effects Scale 1.12.1
  3034. * http://jqueryui.com
  3035. *
  3036. * Copyright jQuery Foundation and other contributors
  3037. * Released under the MIT license.
  3038. * http://jquery.org/license
  3039. */
  3040. //>>label: Scale Effect
  3041. //>>group: Effects
  3042. //>>description: Grows or shrinks an element and its content.
  3043. //>>docs: http://api.jqueryui.com/scale-effect/
  3044. //>>demos: http://jqueryui.com/effect/
  3045. var effectsEffectScale = $.effects.define( "scale", function( options, done ) {
  3046. // Create element
  3047. var el = $( this ),
  3048. mode = options.mode,
  3049. percent = parseInt( options.percent, 10 ) ||
  3050. ( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
  3051. newOptions = $.extend( true, {
  3052. from: $.effects.scaledDimensions( el ),
  3053. to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
  3054. origin: options.origin || [ "middle", "center" ]
  3055. }, options );
  3056. // Fade option to support puff
  3057. if ( options.fade ) {
  3058. newOptions.from.opacity = 1;
  3059. newOptions.to.opacity = 0;
  3060. }
  3061. $.effects.effect.size.call( this, newOptions, done );
  3062. } );
  3063. /*!
  3064. * jQuery UI Effects Puff 1.12.1
  3065. * http://jqueryui.com
  3066. *
  3067. * Copyright jQuery Foundation and other contributors
  3068. * Released under the MIT license.
  3069. * http://jquery.org/license
  3070. */
  3071. //>>label: Puff Effect
  3072. //>>group: Effects
  3073. //>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
  3074. //>>docs: http://api.jqueryui.com/puff-effect/
  3075. //>>demos: http://jqueryui.com/effect/
  3076. var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
  3077. var newOptions = $.extend( true, {}, options, {
  3078. fade: true,
  3079. percent: parseInt( options.percent, 10 ) || 150
  3080. } );
  3081. $.effects.effect.scale.call( this, newOptions, done );
  3082. } );
  3083. /*!
  3084. * jQuery UI Effects Pulsate 1.12.1
  3085. * http://jqueryui.com
  3086. *
  3087. * Copyright jQuery Foundation and other contributors
  3088. * Released under the MIT license.
  3089. * http://jquery.org/license
  3090. */
  3091. //>>label: Pulsate Effect
  3092. //>>group: Effects
  3093. //>>description: Pulsates an element n times by changing the opacity to zero and back.
  3094. //>>docs: http://api.jqueryui.com/pulsate-effect/
  3095. //>>demos: http://jqueryui.com/effect/
  3096. var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
  3097. var element = $( this ),
  3098. mode = options.mode,
  3099. show = mode === "show",
  3100. hide = mode === "hide",
  3101. showhide = show || hide,
  3102. // Showing or hiding leaves off the "last" animation
  3103. anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
  3104. duration = options.duration / anims,
  3105. animateTo = 0,
  3106. i = 1,
  3107. queuelen = element.queue().length;
  3108. if ( show || !element.is( ":visible" ) ) {
  3109. element.css( "opacity", 0 ).show();
  3110. animateTo = 1;
  3111. }
  3112. // Anims - 1 opacity "toggles"
  3113. for ( ; i < anims; i++ ) {
  3114. element.animate( { opacity: animateTo }, duration, options.easing );
  3115. animateTo = 1 - animateTo;
  3116. }
  3117. element.animate( { opacity: animateTo }, duration, options.easing );
  3118. element.queue( done );
  3119. $.effects.unshift( element, queuelen, anims + 1 );
  3120. } );
  3121. /*!
  3122. * jQuery UI Effects Shake 1.12.1
  3123. * http://jqueryui.com
  3124. *
  3125. * Copyright jQuery Foundation and other contributors
  3126. * Released under the MIT license.
  3127. * http://jquery.org/license
  3128. */
  3129. //>>label: Shake Effect
  3130. //>>group: Effects
  3131. //>>description: Shakes an element horizontally or vertically n times.
  3132. //>>docs: http://api.jqueryui.com/shake-effect/
  3133. //>>demos: http://jqueryui.com/effect/
  3134. var effectsEffectShake = $.effects.define( "shake", function( options, done ) {
  3135. var i = 1,
  3136. element = $( this ),
  3137. direction = options.direction || "left",
  3138. distance = options.distance || 20,
  3139. times = options.times || 3,
  3140. anims = times * 2 + 1,
  3141. speed = Math.round( options.duration / anims ),
  3142. ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
  3143. positiveMotion = ( direction === "up" || direction === "left" ),
  3144. animation = {},
  3145. animation1 = {},
  3146. animation2 = {},
  3147. queuelen = element.queue().length;
  3148. $.effects.createPlaceholder( element );
  3149. // Animation
  3150. animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
  3151. animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
  3152. animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
  3153. // Animate
  3154. element.animate( animation, speed, options.easing );
  3155. // Shakes
  3156. for ( ; i < times; i++ ) {
  3157. element
  3158. .animate( animation1, speed, options.easing )
  3159. .animate( animation2, speed, options.easing );
  3160. }
  3161. element
  3162. .animate( animation1, speed, options.easing )
  3163. .animate( animation, speed / 2, options.easing )
  3164. .queue( done );
  3165. $.effects.unshift( element, queuelen, anims + 1 );
  3166. } );
  3167. /*!
  3168. * jQuery UI Effects Slide 1.12.1
  3169. * http://jqueryui.com
  3170. *
  3171. * Copyright jQuery Foundation and other contributors
  3172. * Released under the MIT license.
  3173. * http://jquery.org/license
  3174. */
  3175. //>>label: Slide Effect
  3176. //>>group: Effects
  3177. //>>description: Slides an element in and out of the viewport.
  3178. //>>docs: http://api.jqueryui.com/slide-effect/
  3179. //>>demos: http://jqueryui.com/effect/
  3180. var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
  3181. var startClip, startRef,
  3182. element = $( this ),
  3183. map = {
  3184. up: [ "bottom", "top" ],
  3185. down: [ "top", "bottom" ],
  3186. left: [ "right", "left" ],
  3187. right: [ "left", "right" ]
  3188. },
  3189. mode = options.mode,
  3190. direction = options.direction || "left",
  3191. ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
  3192. positiveMotion = ( direction === "up" || direction === "left" ),
  3193. distance = options.distance ||
  3194. element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
  3195. animation = {};
  3196. $.effects.createPlaceholder( element );
  3197. startClip = element.cssClip();
  3198. startRef = element.position()[ ref ];
  3199. // Define hide animation
  3200. animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
  3201. animation.clip = element.cssClip();
  3202. animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
  3203. // Reverse the animation if we're showing
  3204. if ( mode === "show" ) {
  3205. element.cssClip( animation.clip );
  3206. element.css( ref, animation[ ref ] );
  3207. animation.clip = startClip;
  3208. animation[ ref ] = startRef;
  3209. }
  3210. // Actually animate
  3211. element.animate( animation, {
  3212. queue: false,
  3213. duration: options.duration,
  3214. easing: options.easing,
  3215. complete: done
  3216. } );
  3217. } );
  3218. /*!
  3219. * jQuery UI Effects Transfer 1.12.1
  3220. * http://jqueryui.com
  3221. *
  3222. * Copyright jQuery Foundation and other contributors
  3223. * Released under the MIT license.
  3224. * http://jquery.org/license
  3225. */
  3226. //>>label: Transfer Effect
  3227. //>>group: Effects
  3228. //>>description: Displays a transfer effect from one element to another.
  3229. //>>docs: http://api.jqueryui.com/transfer-effect/
  3230. //>>demos: http://jqueryui.com/effect/
  3231. var effect;
  3232. if ( $.uiBackCompat !== false ) {
  3233. effect = $.effects.define( "transfer", function( options, done ) {
  3234. $( this ).transfer( options, done );
  3235. } );
  3236. }
  3237. var effectsEffectTransfer = effect;
  3238. /*!
  3239. * jQuery UI Focusable 1.12.1
  3240. * http://jqueryui.com
  3241. *
  3242. * Copyright jQuery Foundation and other contributors
  3243. * Released under the MIT license.
  3244. * http://jquery.org/license
  3245. */
  3246. //>>label: :focusable Selector
  3247. //>>group: Core
  3248. //>>description: Selects elements which can be focused.
  3249. //>>docs: http://api.jqueryui.com/focusable-selector/
  3250. // Selectors
  3251. $.ui.focusable = function( element, hasTabindex ) {
  3252. var map, mapName, img, focusableIfVisible, fieldset,
  3253. nodeName = element.nodeName.toLowerCase();
  3254. if ( "area" === nodeName ) {
  3255. map = element.parentNode;
  3256. mapName = map.name;
  3257. if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
  3258. return false;
  3259. }
  3260. img = $( "img[usemap='#" + mapName + "']" );
  3261. return img.length > 0 && img.is( ":visible" );
  3262. }
  3263. if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
  3264. focusableIfVisible = !element.disabled;
  3265. if ( focusableIfVisible ) {
  3266. // Form controls within a disabled fieldset are disabled.
  3267. // However, controls within the fieldset's legend do not get disabled.
  3268. // Since controls generally aren't placed inside legends, we skip
  3269. // this portion of the check.
  3270. fieldset = $( element ).closest( "fieldset" )[ 0 ];
  3271. if ( fieldset ) {
  3272. focusableIfVisible = !fieldset.disabled;
  3273. }
  3274. }
  3275. } else if ( "a" === nodeName ) {
  3276. focusableIfVisible = element.href || hasTabindex;
  3277. } else {
  3278. focusableIfVisible = hasTabindex;
  3279. }
  3280. return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
  3281. };
  3282. // Support: IE 8 only
  3283. // IE 8 doesn't resolve inherit to visible/hidden for computed values
  3284. function visible( element ) {
  3285. var visibility = element.css( "visibility" );
  3286. while ( visibility === "inherit" ) {
  3287. element = element.parent();
  3288. visibility = element.css( "visibility" );
  3289. }
  3290. return visibility !== "hidden";
  3291. }
  3292. $.extend( $.expr[ ":" ], {
  3293. focusable: function( element ) {
  3294. return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
  3295. }
  3296. } );
  3297. var focusable = $.ui.focusable;
  3298. // Support: IE8 Only
  3299. // IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
  3300. // with a string, so we need to find the proper form.
  3301. var form = $.fn.form = function() {
  3302. return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
  3303. };
  3304. /*!
  3305. * jQuery UI Form Reset Mixin 1.12.1
  3306. * http://jqueryui.com
  3307. *
  3308. * Copyright jQuery Foundation and other contributors
  3309. * Released under the MIT license.
  3310. * http://jquery.org/license
  3311. */
  3312. //>>label: Form Reset Mixin
  3313. //>>group: Core
  3314. //>>description: Refresh input widgets when their form is reset
  3315. //>>docs: http://api.jqueryui.com/form-reset-mixin/
  3316. var formResetMixin = $.ui.formResetMixin = {
  3317. _formResetHandler: function() {
  3318. var form = $( this );
  3319. // Wait for the form reset to actually happen before refreshing
  3320. setTimeout( function() {
  3321. var instances = form.data( "ui-form-reset-instances" );
  3322. $.each( instances, function() {
  3323. this.refresh();
  3324. } );
  3325. } );
  3326. },
  3327. _bindFormResetHandler: function() {
  3328. this.form = this.element.form();
  3329. if ( !this.form.length ) {
  3330. return;
  3331. }
  3332. var instances = this.form.data( "ui-form-reset-instances" ) || [];
  3333. if ( !instances.length ) {
  3334. // We don't use _on() here because we use a single event handler per form
  3335. this.form.on( "reset.ui-form-reset", this._formResetHandler );
  3336. }
  3337. instances.push( this );
  3338. this.form.data( "ui-form-reset-instances", instances );
  3339. },
  3340. _unbindFormResetHandler: function() {
  3341. if ( !this.form.length ) {
  3342. return;
  3343. }
  3344. var instances = this.form.data( "ui-form-reset-instances" );
  3345. instances.splice( $.inArray( this, instances ), 1 );
  3346. if ( instances.length ) {
  3347. this.form.data( "ui-form-reset-instances", instances );
  3348. } else {
  3349. this.form
  3350. .removeData( "ui-form-reset-instances" )
  3351. .off( "reset.ui-form-reset" );
  3352. }
  3353. }
  3354. };
  3355. /*!
  3356. * jQuery UI Support for jQuery core 1.7.x 1.12.1
  3357. * http://jqueryui.com
  3358. *
  3359. * Copyright jQuery Foundation and other contributors
  3360. * Released under the MIT license.
  3361. * http://jquery.org/license
  3362. *
  3363. */
  3364. //>>label: jQuery 1.7 Support
  3365. //>>group: Core
  3366. //>>description: Support version 1.7.x of jQuery core
  3367. // Support: jQuery 1.7 only
  3368. // Not a great way to check versions, but since we only support 1.7+ and only
  3369. // need to detect <1.8, this is a simple check that should suffice. Checking
  3370. // for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0
  3371. // and we'll never reach 1.70.0 (if we do, we certainly won't be supporting
  3372. // 1.7 anymore). See #11197 for why we're not using feature detection.
  3373. if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) {
  3374. // Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight()
  3375. // Unlike jQuery Core 1.8+, these only support numeric values to set the
  3376. // dimensions in pixels
  3377. $.each( [ "Width", "Height" ], function( i, name ) {
  3378. var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
  3379. type = name.toLowerCase(),
  3380. orig = {
  3381. innerWidth: $.fn.innerWidth,
  3382. innerHeight: $.fn.innerHeight,
  3383. outerWidth: $.fn.outerWidth,
  3384. outerHeight: $.fn.outerHeight
  3385. };
  3386. function reduce( elem, size, border, margin ) {
  3387. $.each( side, function() {
  3388. size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
  3389. if ( border ) {
  3390. size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
  3391. }
  3392. if ( margin ) {
  3393. size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
  3394. }
  3395. } );
  3396. return size;
  3397. }
  3398. $.fn[ "inner" + name ] = function( size ) {
  3399. if ( size === undefined ) {
  3400. return orig[ "inner" + name ].call( this );
  3401. }
  3402. return this.each( function() {
  3403. $( this ).css( type, reduce( this, size ) + "px" );
  3404. } );
  3405. };
  3406. $.fn[ "outer" + name ] = function( size, margin ) {
  3407. if ( typeof size !== "number" ) {
  3408. return orig[ "outer" + name ].call( this, size );
  3409. }
  3410. return this.each( function() {
  3411. $( this ).css( type, reduce( this, size, true, margin ) + "px" );
  3412. } );
  3413. };
  3414. } );
  3415. $.fn.addBack = function( selector ) {
  3416. return this.add( selector == null ?
  3417. this.prevObject : this.prevObject.filter( selector )
  3418. );
  3419. };
  3420. }
  3421. ;
  3422. /*!
  3423. * jQuery UI Keycode 1.12.1
  3424. * http://jqueryui.com
  3425. *
  3426. * Copyright jQuery Foundation and other contributors
  3427. * Released under the MIT license.
  3428. * http://jquery.org/license
  3429. */
  3430. //>>label: Keycode
  3431. //>>group: Core
  3432. //>>description: Provide keycodes as keynames
  3433. //>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
  3434. var keycode = $.ui.keyCode = {
  3435. BACKSPACE: 8,
  3436. COMMA: 188,
  3437. DELETE: 46,
  3438. DOWN: 40,
  3439. END: 35,
  3440. ENTER: 13,
  3441. ESCAPE: 27,
  3442. HOME: 36,
  3443. LEFT: 37,
  3444. PAGE_DOWN: 34,
  3445. PAGE_UP: 33,
  3446. PERIOD: 190,
  3447. RIGHT: 39,
  3448. SPACE: 32,
  3449. TAB: 9,
  3450. UP: 38
  3451. };
  3452. // Internal use only
  3453. var escapeSelector = $.ui.escapeSelector = ( function() {
  3454. var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
  3455. return function( selector ) {
  3456. return selector.replace( selectorEscape, "\\$1" );
  3457. };
  3458. } )();
  3459. /*!
  3460. * jQuery UI Labels 1.12.1
  3461. * http://jqueryui.com
  3462. *
  3463. * Copyright jQuery Foundation and other contributors
  3464. * Released under the MIT license.
  3465. * http://jquery.org/license
  3466. */
  3467. //>>label: labels
  3468. //>>group: Core
  3469. //>>description: Find all the labels associated with a given input
  3470. //>>docs: http://api.jqueryui.com/labels/
  3471. var labels = $.fn.labels = function() {
  3472. var ancestor, selector, id, labels, ancestors;
  3473. // Check control.labels first
  3474. if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
  3475. return this.pushStack( this[ 0 ].labels );
  3476. }
  3477. // Support: IE <= 11, FF <= 37, Android <= 2.3 only
  3478. // Above browsers do not support control.labels. Everything below is to support them
  3479. // as well as document fragments. control.labels does not work on document fragments
  3480. labels = this.eq( 0 ).parents( "label" );
  3481. // Look for the label based on the id
  3482. id = this.attr( "id" );
  3483. if ( id ) {
  3484. // We don't search against the document in case the element
  3485. // is disconnected from the DOM
  3486. ancestor = this.eq( 0 ).parents().last();
  3487. // Get a full set of top level ancestors
  3488. ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
  3489. // Create a selector for the label based on the id
  3490. selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
  3491. labels = labels.add( ancestors.find( selector ).addBack( selector ) );
  3492. }
  3493. // Return whatever we have found for labels
  3494. return this.pushStack( labels );
  3495. };
  3496. /*!
  3497. * jQuery UI Scroll Parent 1.12.1
  3498. * http://jqueryui.com
  3499. *
  3500. * Copyright jQuery Foundation and other contributors
  3501. * Released under the MIT license.
  3502. * http://jquery.org/license
  3503. */
  3504. //>>label: scrollParent
  3505. //>>group: Core
  3506. //>>description: Get the closest ancestor element that is scrollable.
  3507. //>>docs: http://api.jqueryui.com/scrollParent/
  3508. var scrollParent = $.fn.scrollParent = function( includeHidden ) {
  3509. var position = this.css( "position" ),
  3510. excludeStaticParent = position === "absolute",
  3511. overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
  3512. scrollParent = this.parents().filter( function() {
  3513. var parent = $( this );
  3514. if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
  3515. return false;
  3516. }
  3517. return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
  3518. parent.css( "overflow-x" ) );
  3519. } ).eq( 0 );
  3520. return position === "fixed" || !scrollParent.length ?
  3521. $( this[ 0 ].ownerDocument || document ) :
  3522. scrollParent;
  3523. };
  3524. /*!
  3525. * jQuery UI Tabbable 1.12.1
  3526. * http://jqueryui.com
  3527. *
  3528. * Copyright jQuery Foundation and other contributors
  3529. * Released under the MIT license.
  3530. * http://jquery.org/license
  3531. */
  3532. //>>label: :tabbable Selector
  3533. //>>group: Core
  3534. //>>description: Selects elements which can be tabbed to.
  3535. //>>docs: http://api.jqueryui.com/tabbable-selector/
  3536. var tabbable = $.extend( $.expr[ ":" ], {
  3537. tabbable: function( element ) {
  3538. var tabIndex = $.attr( element, "tabindex" ),
  3539. hasTabindex = tabIndex != null;
  3540. return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
  3541. }
  3542. } );
  3543. /*!
  3544. * jQuery UI Unique ID 1.12.1
  3545. * http://jqueryui.com
  3546. *
  3547. * Copyright jQuery Foundation and other contributors
  3548. * Released under the MIT license.
  3549. * http://jquery.org/license
  3550. */
  3551. //>>label: uniqueId
  3552. //>>group: Core
  3553. //>>description: Functions to generate and remove uniqueId's
  3554. //>>docs: http://api.jqueryui.com/uniqueId/
  3555. var uniqueId = $.fn.extend( {
  3556. uniqueId: ( function() {
  3557. var uuid = 0;
  3558. return function() {
  3559. return this.each( function() {
  3560. if ( !this.id ) {
  3561. this.id = "ui-id-" + ( ++uuid );
  3562. }
  3563. } );
  3564. };
  3565. } )(),
  3566. removeUniqueId: function() {
  3567. return this.each( function() {
  3568. if ( /^ui-id-\d+$/.test( this.id ) ) {
  3569. $( this ).removeAttr( "id" );
  3570. }
  3571. } );
  3572. }
  3573. } );
  3574. /*!
  3575. * jQuery UI Accordion 1.12.1
  3576. * http://jqueryui.com
  3577. *
  3578. * Copyright jQuery Foundation and other contributors
  3579. * Released under the MIT license.
  3580. * http://jquery.org/license
  3581. */
  3582. //>>label: Accordion
  3583. //>>group: Widgets
  3584. // jscs:disable maximumLineLength
  3585. //>>description: Displays collapsible content panels for presenting information in a limited amount of space.
  3586. // jscs:enable maximumLineLength
  3587. //>>docs: http://api.jqueryui.com/accordion/
  3588. //>>demos: http://jqueryui.com/accordion/
  3589. //>>css.structure: ../../themes/base/core.css
  3590. //>>css.structure: ../../themes/base/accordion.css
  3591. //>>css.theme: ../../themes/base/theme.css
  3592. var widgetsAccordion = $.widget( "ui.accordion", {
  3593. version: "1.12.1",
  3594. options: {
  3595. active: 0,
  3596. animate: {},
  3597. classes: {
  3598. "ui-accordion-header": "ui-corner-top",
  3599. "ui-accordion-header-collapsed": "ui-corner-all",
  3600. "ui-accordion-content": "ui-corner-bottom"
  3601. },
  3602. collapsible: false,
  3603. event: "click",
  3604. header: "> li > :first-child, > :not(li):even",
  3605. heightStyle: "auto",
  3606. icons: {
  3607. activeHeader: "ui-icon-triangle-1-s",
  3608. header: "ui-icon-triangle-1-e"
  3609. },
  3610. // Callbacks
  3611. activate: null,
  3612. beforeActivate: null
  3613. },
  3614. hideProps: {
  3615. borderTopWidth: "hide",
  3616. borderBottomWidth: "hide",
  3617. paddingTop: "hide",
  3618. paddingBottom: "hide",
  3619. height: "hide"
  3620. },
  3621. showProps: {
  3622. borderTopWidth: "show",
  3623. borderBottomWidth: "show",
  3624. paddingTop: "show",
  3625. paddingBottom: "show",
  3626. height: "show"
  3627. },
  3628. _create: function() {
  3629. var options = this.options;
  3630. this.prevShow = this.prevHide = $();
  3631. this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
  3632. this.element.attr( "role", "tablist" );
  3633. // Don't allow collapsible: false and active: false / null
  3634. if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
  3635. options.active = 0;
  3636. }
  3637. this._processPanels();
  3638. // handle negative values
  3639. if ( options.active < 0 ) {
  3640. options.active += this.headers.length;
  3641. }
  3642. this._refresh();
  3643. },
  3644. _getCreateEventData: function() {
  3645. return {
  3646. header: this.active,
  3647. panel: !this.active.length ? $() : this.active.next()
  3648. };
  3649. },
  3650. _createIcons: function() {
  3651. var icon, children,
  3652. icons = this.options.icons;
  3653. if ( icons ) {
  3654. icon = $( "<span>" );
  3655. this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
  3656. icon.prependTo( this.headers );
  3657. children = this.active.children( ".ui-accordion-header-icon" );
  3658. this._removeClass( children, icons.header )
  3659. ._addClass( children, null, icons.activeHeader )
  3660. ._addClass( this.headers, "ui-accordion-icons" );
  3661. }
  3662. },
  3663. _destroyIcons: function() {
  3664. this._removeClass( this.headers, "ui-accordion-icons" );
  3665. this.headers.children( ".ui-accordion-header-icon" ).remove();
  3666. },
  3667. _destroy: function() {
  3668. var contents;
  3669. // Clean up main element
  3670. this.element.removeAttr( "role" );
  3671. // Clean up headers
  3672. this.headers
  3673. .removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
  3674. .removeUniqueId();
  3675. this._destroyIcons();
  3676. // Clean up content panels
  3677. contents = this.headers.next()
  3678. .css( "display", "" )
  3679. .removeAttr( "role aria-hidden aria-labelledby" )
  3680. .removeUniqueId();
  3681. if ( this.options.heightStyle !== "content" ) {
  3682. contents.css( "height", "" );
  3683. }
  3684. },
  3685. _setOption: function( key, value ) {
  3686. if ( key === "active" ) {
  3687. // _activate() will handle invalid values and update this.options
  3688. this._activate( value );
  3689. return;
  3690. }
  3691. if ( key === "event" ) {
  3692. if ( this.options.event ) {
  3693. this._off( this.headers, this.options.event );
  3694. }
  3695. this._setupEvents( value );
  3696. }
  3697. this._super( key, value );
  3698. // Setting collapsible: false while collapsed; open first panel
  3699. if ( key === "collapsible" && !value && this.options.active === false ) {
  3700. this._activate( 0 );
  3701. }
  3702. if ( key === "icons" ) {
  3703. this._destroyIcons();
  3704. if ( value ) {
  3705. this._createIcons();
  3706. }
  3707. }
  3708. },
  3709. _setOptionDisabled: function( value ) {
  3710. this._super( value );
  3711. this.element.attr( "aria-disabled", value );
  3712. // Support: IE8 Only
  3713. // #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
  3714. // so we need to add the disabled class to the headers and panels
  3715. this._toggleClass( null, "ui-state-disabled", !!value );
  3716. this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
  3717. !!value );
  3718. },
  3719. _keydown: function( event ) {
  3720. if ( event.altKey || event.ctrlKey ) {
  3721. return;
  3722. }
  3723. var keyCode = $.ui.keyCode,
  3724. length = this.headers.length,
  3725. currentIndex = this.headers.index( event.target ),
  3726. toFocus = false;
  3727. switch ( event.keyCode ) {
  3728. case keyCode.RIGHT:
  3729. case keyCode.DOWN:
  3730. toFocus = this.headers[ ( currentIndex + 1 ) % length ];
  3731. break;
  3732. case keyCode.LEFT:
  3733. case keyCode.UP:
  3734. toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
  3735. break;
  3736. case keyCode.SPACE:
  3737. case keyCode.ENTER:
  3738. this._eventHandler( event );
  3739. break;
  3740. case keyCode.HOME:
  3741. toFocus = this.headers[ 0 ];
  3742. break;
  3743. case keyCode.END:
  3744. toFocus = this.headers[ length - 1 ];
  3745. break;
  3746. }
  3747. if ( toFocus ) {
  3748. $( event.target ).attr( "tabIndex", -1 );
  3749. $( toFocus ).attr( "tabIndex", 0 );
  3750. $( toFocus ).trigger( "focus" );
  3751. event.preventDefault();
  3752. }
  3753. },
  3754. _panelKeyDown: function( event ) {
  3755. if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
  3756. $( event.currentTarget ).prev().trigger( "focus" );
  3757. }
  3758. },
  3759. refresh: function() {
  3760. var options = this.options;
  3761. this._processPanels();
  3762. // Was collapsed or no panel
  3763. if ( ( options.active === false && options.collapsible === true ) ||
  3764. !this.headers.length ) {
  3765. options.active = false;
  3766. this.active = $();
  3767. // active false only when collapsible is true
  3768. } else if ( options.active === false ) {
  3769. this._activate( 0 );
  3770. // was active, but active panel is gone
  3771. } else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
  3772. // all remaining panel are disabled
  3773. if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
  3774. options.active = false;
  3775. this.active = $();
  3776. // activate previous panel
  3777. } else {
  3778. this._activate( Math.max( 0, options.active - 1 ) );
  3779. }
  3780. // was active, active panel still exists
  3781. } else {
  3782. // make sure active index is correct
  3783. options.active = this.headers.index( this.active );
  3784. }
  3785. this._destroyIcons();
  3786. this._refresh();
  3787. },
  3788. _processPanels: function() {
  3789. var prevHeaders = this.headers,
  3790. prevPanels = this.panels;
  3791. this.headers = this.element.find( this.options.header );
  3792. this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
  3793. "ui-state-default" );
  3794. this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
  3795. this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
  3796. // Avoid memory leaks (#10056)
  3797. if ( prevPanels ) {
  3798. this._off( prevHeaders.not( this.headers ) );
  3799. this._off( prevPanels.not( this.panels ) );
  3800. }
  3801. },
  3802. _refresh: function() {
  3803. var maxHeight,
  3804. options = this.options,
  3805. heightStyle = options.heightStyle,
  3806. parent = this.element.parent();
  3807. this.active = this._findActive( options.active );
  3808. this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
  3809. ._removeClass( this.active, "ui-accordion-header-collapsed" );
  3810. this._addClass( this.active.next(), "ui-accordion-content-active" );
  3811. this.active.next().show();
  3812. this.headers
  3813. .attr( "role", "tab" )
  3814. .each( function() {
  3815. var header = $( this ),
  3816. headerId = header.uniqueId().attr( "id" ),
  3817. panel = header.next(),
  3818. panelId = panel.uniqueId().attr( "id" );
  3819. header.attr( "aria-controls", panelId );
  3820. panel.attr( "aria-labelledby", headerId );
  3821. } )
  3822. .next()
  3823. .attr( "role", "tabpanel" );
  3824. this.headers
  3825. .not( this.active )
  3826. .attr( {
  3827. "aria-selected": "false",
  3828. "aria-expanded": "false",
  3829. tabIndex: -1
  3830. } )
  3831. .next()
  3832. .attr( {
  3833. "aria-hidden": "true"
  3834. } )
  3835. .hide();
  3836. // Make sure at least one header is in the tab order
  3837. if ( !this.active.length ) {
  3838. this.headers.eq( 0 ).attr( "tabIndex", 0 );
  3839. } else {
  3840. this.active.attr( {
  3841. "aria-selected": "true",
  3842. "aria-expanded": "true",
  3843. tabIndex: 0
  3844. } )
  3845. .next()
  3846. .attr( {
  3847. "aria-hidden": "false"
  3848. } );
  3849. }
  3850. this._createIcons();
  3851. this._setupEvents( options.event );
  3852. if ( heightStyle === "fill" ) {
  3853. maxHeight = parent.height();
  3854. this.element.siblings( ":visible" ).each( function() {
  3855. var elem = $( this ),
  3856. position = elem.css( "position" );
  3857. if ( position === "absolute" || position === "fixed" ) {
  3858. return;
  3859. }
  3860. maxHeight -= elem.outerHeight( true );
  3861. } );
  3862. this.headers.each( function() {
  3863. maxHeight -= $( this ).outerHeight( true );
  3864. } );
  3865. this.headers.next()
  3866. .each( function() {
  3867. $( this ).height( Math.max( 0, maxHeight -
  3868. $( this ).innerHeight() + $( this ).height() ) );
  3869. } )
  3870. .css( "overflow", "auto" );
  3871. } else if ( heightStyle === "auto" ) {
  3872. maxHeight = 0;
  3873. this.headers.next()
  3874. .each( function() {
  3875. var isVisible = $( this ).is( ":visible" );
  3876. if ( !isVisible ) {
  3877. $( this ).show();
  3878. }
  3879. maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
  3880. if ( !isVisible ) {
  3881. $( this ).hide();
  3882. }
  3883. } )
  3884. .height( maxHeight );
  3885. }
  3886. },
  3887. _activate: function( index ) {
  3888. var active = this._findActive( index )[ 0 ];
  3889. // Trying to activate the already active panel
  3890. if ( active === this.active[ 0 ] ) {
  3891. return;
  3892. }
  3893. // Trying to collapse, simulate a click on the currently active header
  3894. active = active || this.active[ 0 ];
  3895. this._eventHandler( {
  3896. target: active,
  3897. currentTarget: active,
  3898. preventDefault: $.noop
  3899. } );
  3900. },
  3901. _findActive: function( selector ) {
  3902. return typeof selector === "number" ? this.headers.eq( selector ) : $();
  3903. },
  3904. _setupEvents: function( event ) {
  3905. var events = {
  3906. keydown: "_keydown"
  3907. };
  3908. if ( event ) {
  3909. $.each( event.split( " " ), function( index, eventName ) {
  3910. events[ eventName ] = "_eventHandler";
  3911. } );
  3912. }
  3913. this._off( this.headers.add( this.headers.next() ) );
  3914. this._on( this.headers, events );
  3915. this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
  3916. this._hoverable( this.headers );
  3917. this._focusable( this.headers );
  3918. },
  3919. _eventHandler: function( event ) {
  3920. var activeChildren, clickedChildren,
  3921. options = this.options,
  3922. active = this.active,
  3923. clicked = $( event.currentTarget ),
  3924. clickedIsActive = clicked[ 0 ] === active[ 0 ],
  3925. collapsing = clickedIsActive && options.collapsible,
  3926. toShow = collapsing ? $() : clicked.next(),
  3927. toHide = active.next(),
  3928. eventData = {
  3929. oldHeader: active,
  3930. oldPanel: toHide,
  3931. newHeader: collapsing ? $() : clicked,
  3932. newPanel: toShow
  3933. };
  3934. event.preventDefault();
  3935. if (
  3936. // click on active header, but not collapsible
  3937. ( clickedIsActive && !options.collapsible ) ||
  3938. // allow canceling activation
  3939. ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
  3940. return;
  3941. }
  3942. options.active = collapsing ? false : this.headers.index( clicked );
  3943. // When the call to ._toggle() comes after the class changes
  3944. // it causes a very odd bug in IE 8 (see #6720)
  3945. this.active = clickedIsActive ? $() : clicked;
  3946. this._toggle( eventData );
  3947. // Switch classes
  3948. // corner classes on the previously active header stay after the animation
  3949. this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
  3950. if ( options.icons ) {
  3951. activeChildren = active.children( ".ui-accordion-header-icon" );
  3952. this._removeClass( activeChildren, null, options.icons.activeHeader )
  3953. ._addClass( activeChildren, null, options.icons.header );
  3954. }
  3955. if ( !clickedIsActive ) {
  3956. this._removeClass( clicked, "ui-accordion-header-collapsed" )
  3957. ._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
  3958. if ( options.icons ) {
  3959. clickedChildren = clicked.children( ".ui-accordion-header-icon" );
  3960. this._removeClass( clickedChildren, null, options.icons.header )
  3961. ._addClass( clickedChildren, null, options.icons.activeHeader );
  3962. }
  3963. this._addClass( clicked.next(), "ui-accordion-content-active" );
  3964. }
  3965. },
  3966. _toggle: function( data ) {
  3967. var toShow = data.newPanel,
  3968. toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
  3969. // Handle activating a panel during the animation for another activation
  3970. this.prevShow.add( this.prevHide ).stop( true, true );
  3971. this.prevShow = toShow;
  3972. this.prevHide = toHide;
  3973. if ( this.options.animate ) {
  3974. this._animate( toShow, toHide, data );
  3975. } else {
  3976. toHide.hide();
  3977. toShow.show();
  3978. this._toggleComplete( data );
  3979. }
  3980. toHide.attr( {
  3981. "aria-hidden": "true"
  3982. } );
  3983. toHide.prev().attr( {
  3984. "aria-selected": "false",
  3985. "aria-expanded": "false"
  3986. } );
  3987. // if we're switching panels, remove the old header from the tab order
  3988. // if we're opening from collapsed state, remove the previous header from the tab order
  3989. // if we're collapsing, then keep the collapsing header in the tab order
  3990. if ( toShow.length && toHide.length ) {
  3991. toHide.prev().attr( {
  3992. "tabIndex": -1,
  3993. "aria-expanded": "false"
  3994. } );
  3995. } else if ( toShow.length ) {
  3996. this.headers.filter( function() {
  3997. return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
  3998. } )
  3999. .attr( "tabIndex", -1 );
  4000. }
  4001. toShow
  4002. .attr( "aria-hidden", "false" )
  4003. .prev()
  4004. .attr( {
  4005. "aria-selected": "true",
  4006. "aria-expanded": "true",
  4007. tabIndex: 0
  4008. } );
  4009. },
  4010. _animate: function( toShow, toHide, data ) {
  4011. var total, easing, duration,
  4012. that = this,
  4013. adjust = 0,
  4014. boxSizing = toShow.css( "box-sizing" ),
  4015. down = toShow.length &&
  4016. ( !toHide.length || ( toShow.index() < toHide.index() ) ),
  4017. animate = this.options.animate || {},
  4018. options = down && animate.down || animate,
  4019. complete = function() {
  4020. that._toggleComplete( data );
  4021. };
  4022. if ( typeof options === "number" ) {
  4023. duration = options;
  4024. }
  4025. if ( typeof options === "string" ) {
  4026. easing = options;
  4027. }
  4028. // fall back from options to animation in case of partial down settings
  4029. easing = easing || options.easing || animate.easing;
  4030. duration = duration || options.duration || animate.duration;
  4031. if ( !toHide.length ) {
  4032. return toShow.animate( this.showProps, duration, easing, complete );
  4033. }
  4034. if ( !toShow.length ) {
  4035. return toHide.animate( this.hideProps, duration, easing, complete );
  4036. }
  4037. total = toShow.show().outerHeight();
  4038. toHide.animate( this.hideProps, {
  4039. duration: duration,
  4040. easing: easing,
  4041. step: function( now, fx ) {
  4042. fx.now = Math.round( now );
  4043. }
  4044. } );
  4045. toShow
  4046. .hide()
  4047. .animate( this.showProps, {
  4048. duration: duration,
  4049. easing: easing,
  4050. complete: complete,
  4051. step: function( now, fx ) {
  4052. fx.now = Math.round( now );
  4053. if ( fx.prop !== "height" ) {
  4054. if ( boxSizing === "content-box" ) {
  4055. adjust += fx.now;
  4056. }
  4057. } else if ( that.options.heightStyle !== "content" ) {
  4058. fx.now = Math.round( total - toHide.outerHeight() - adjust );
  4059. adjust = 0;
  4060. }
  4061. }
  4062. } );
  4063. },
  4064. _toggleComplete: function( data ) {
  4065. var toHide = data.oldPanel,
  4066. prev = toHide.prev();
  4067. this._removeClass( toHide, "ui-accordion-content-active" );
  4068. this._removeClass( prev, "ui-accordion-header-active" )
  4069. ._addClass( prev, "ui-accordion-header-collapsed" );
  4070. // Work around for rendering bug in IE (#5421)
  4071. if ( toHide.length ) {
  4072. toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
  4073. }
  4074. this._trigger( "activate", null, data );
  4075. }
  4076. } );
  4077. var safeActiveElement = $.ui.safeActiveElement = function( document ) {
  4078. var activeElement;
  4079. // Support: IE 9 only
  4080. // IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
  4081. try {
  4082. activeElement = document.activeElement;
  4083. } catch ( error ) {
  4084. activeElement = document.body;
  4085. }
  4086. // Support: IE 9 - 11 only
  4087. // IE may return null instead of an element
  4088. // Interestingly, this only seems to occur when NOT in an iframe
  4089. if ( !activeElement ) {
  4090. activeElement = document.body;
  4091. }
  4092. // Support: IE 11 only
  4093. // IE11 returns a seemingly empty object in some cases when accessing
  4094. // document.activeElement from an <iframe>
  4095. if ( !activeElement.nodeName ) {
  4096. activeElement = document.body;
  4097. }
  4098. return activeElement;
  4099. };
  4100. /*!
  4101. * jQuery UI Menu 1.12.1
  4102. * http://jqueryui.com
  4103. *
  4104. * Copyright jQuery Foundation and other contributors
  4105. * Released under the MIT license.
  4106. * http://jquery.org/license
  4107. */
  4108. //>>label: Menu
  4109. //>>group: Widgets
  4110. //>>description: Creates nestable menus.
  4111. //>>docs: http://api.jqueryui.com/menu/
  4112. //>>demos: http://jqueryui.com/menu/
  4113. //>>css.structure: ../../themes/base/core.css
  4114. //>>css.structure: ../../themes/base/menu.css
  4115. //>>css.theme: ../../themes/base/theme.css
  4116. var widgetsMenu = $.widget( "ui.menu", {
  4117. version: "1.12.1",
  4118. defaultElement: "<ul>",
  4119. delay: 300,
  4120. options: {
  4121. icons: {
  4122. submenu: "ui-icon-caret-1-e"
  4123. },
  4124. items: "> *",
  4125. menus: "ul",
  4126. position: {
  4127. my: "left top",
  4128. at: "right top"
  4129. },
  4130. role: "menu",
  4131. // Callbacks
  4132. blur: null,
  4133. focus: null,
  4134. select: null
  4135. },
  4136. _create: function() {
  4137. this.activeMenu = this.element;
  4138. // Flag used to prevent firing of the click handler
  4139. // as the event bubbles up through nested menus
  4140. this.mouseHandled = false;
  4141. this.element
  4142. .uniqueId()
  4143. .attr( {
  4144. role: this.options.role,
  4145. tabIndex: 0
  4146. } );
  4147. this._addClass( "ui-menu", "ui-widget ui-widget-content" );
  4148. this._on( {
  4149. // Prevent focus from sticking to links inside menu after clicking
  4150. // them (focus should always stay on UL during navigation).
  4151. "mousedown .ui-menu-item": function( event ) {
  4152. event.preventDefault();
  4153. },
  4154. "click .ui-menu-item": function( event ) {
  4155. var target = $( event.target );
  4156. var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
  4157. if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
  4158. this.select( event );
  4159. // Only set the mouseHandled flag if the event will bubble, see #9469.
  4160. if ( !event.isPropagationStopped() ) {
  4161. this.mouseHandled = true;
  4162. }
  4163. // Open submenu on click
  4164. if ( target.has( ".ui-menu" ).length ) {
  4165. this.expand( event );
  4166. } else if ( !this.element.is( ":focus" ) &&
  4167. active.closest( ".ui-menu" ).length ) {
  4168. // Redirect focus to the menu
  4169. this.element.trigger( "focus", [ true ] );
  4170. // If the active item is on the top level, let it stay active.
  4171. // Otherwise, blur the active item since it is no longer visible.
  4172. if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
  4173. clearTimeout( this.timer );
  4174. }
  4175. }
  4176. }
  4177. },
  4178. "mouseenter .ui-menu-item": function( event ) {
  4179. // Ignore mouse events while typeahead is active, see #10458.
  4180. // Prevents focusing the wrong item when typeahead causes a scroll while the mouse
  4181. // is over an item in the menu
  4182. if ( this.previousFilter ) {
  4183. return;
  4184. }
  4185. var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
  4186. target = $( event.currentTarget );
  4187. // Ignore bubbled events on parent items, see #11641
  4188. if ( actualTarget[ 0 ] !== target[ 0 ] ) {
  4189. return;
  4190. }
  4191. // Remove ui-state-active class from siblings of the newly focused menu item
  4192. // to avoid a jump caused by adjacent elements both having a class with a border
  4193. this._removeClass( target.siblings().children( ".ui-state-active" ),
  4194. null, "ui-state-active" );
  4195. this.focus( event, target );
  4196. },
  4197. mouseleave: "collapseAll",
  4198. "mouseleave .ui-menu": "collapseAll",
  4199. focus: function( event, keepActiveItem ) {
  4200. // If there's already an active item, keep it active
  4201. // If not, activate the first item
  4202. var item = this.active || this.element.find( this.options.items ).eq( 0 );
  4203. if ( !keepActiveItem ) {
  4204. this.focus( event, item );
  4205. }
  4206. },
  4207. blur: function( event ) {
  4208. this._delay( function() {
  4209. var notContained = !$.contains(
  4210. this.element[ 0 ],
  4211. $.ui.safeActiveElement( this.document[ 0 ] )
  4212. );
  4213. if ( notContained ) {
  4214. this.collapseAll( event );
  4215. }
  4216. } );
  4217. },
  4218. keydown: "_keydown"
  4219. } );
  4220. this.refresh();
  4221. // Clicks outside of a menu collapse any open menus
  4222. this._on( this.document, {
  4223. click: function( event ) {
  4224. if ( this._closeOnDocumentClick( event ) ) {
  4225. this.collapseAll( event );
  4226. }
  4227. // Reset the mouseHandled flag
  4228. this.mouseHandled = false;
  4229. }
  4230. } );
  4231. },
  4232. _destroy: function() {
  4233. var items = this.element.find( ".ui-menu-item" )
  4234. .removeAttr( "role aria-disabled" ),
  4235. submenus = items.children( ".ui-menu-item-wrapper" )
  4236. .removeUniqueId()
  4237. .removeAttr( "tabIndex role aria-haspopup" );
  4238. // Destroy (sub)menus
  4239. this.element
  4240. .removeAttr( "aria-activedescendant" )
  4241. .find( ".ui-menu" ).addBack()
  4242. .removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
  4243. "tabIndex" )
  4244. .removeUniqueId()
  4245. .show();
  4246. submenus.children().each( function() {
  4247. var elem = $( this );
  4248. if ( elem.data( "ui-menu-submenu-caret" ) ) {
  4249. elem.remove();
  4250. }
  4251. } );
  4252. },
  4253. _keydown: function( event ) {
  4254. var match, prev, character, skip,
  4255. preventDefault = true;
  4256. switch ( event.keyCode ) {
  4257. case $.ui.keyCode.PAGE_UP:
  4258. this.previousPage( event );
  4259. break;
  4260. case $.ui.keyCode.PAGE_DOWN:
  4261. this.nextPage( event );
  4262. break;
  4263. case $.ui.keyCode.HOME:
  4264. this._move( "first", "first", event );
  4265. break;
  4266. case $.ui.keyCode.END:
  4267. this._move( "last", "last", event );
  4268. break;
  4269. case $.ui.keyCode.UP:
  4270. this.previous( event );
  4271. break;
  4272. case $.ui.keyCode.DOWN:
  4273. this.next( event );
  4274. break;
  4275. case $.ui.keyCode.LEFT:
  4276. this.collapse( event );
  4277. break;
  4278. case $.ui.keyCode.RIGHT:
  4279. if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
  4280. this.expand( event );
  4281. }
  4282. break;
  4283. case $.ui.keyCode.ENTER:
  4284. case $.ui.keyCode.SPACE:
  4285. this._activate( event );
  4286. break;
  4287. case $.ui.keyCode.ESCAPE:
  4288. this.collapse( event );
  4289. break;
  4290. default:
  4291. preventDefault = false;
  4292. prev = this.previousFilter || "";
  4293. skip = false;
  4294. // Support number pad values
  4295. character = event.keyCode >= 96 && event.keyCode <= 105 ?
  4296. ( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
  4297. clearTimeout( this.filterTimer );
  4298. if ( character === prev ) {
  4299. skip = true;
  4300. } else {
  4301. character = prev + character;
  4302. }
  4303. match = this._filterMenuItems( character );
  4304. match = skip && match.index( this.active.next() ) !== -1 ?
  4305. this.active.nextAll( ".ui-menu-item" ) :
  4306. match;
  4307. // If no matches on the current filter, reset to the last character pressed
  4308. // to move down the menu to the first item that starts with that character
  4309. if ( !match.length ) {
  4310. character = String.fromCharCode( event.keyCode );
  4311. match = this._filterMenuItems( character );
  4312. }
  4313. if ( match.length ) {
  4314. this.focus( event, match );
  4315. this.previousFilter = character;
  4316. this.filterTimer = this._delay( function() {
  4317. delete this.previousFilter;
  4318. }, 1000 );
  4319. } else {
  4320. delete this.previousFilter;
  4321. }
  4322. }
  4323. if ( preventDefault ) {
  4324. event.preventDefault();
  4325. }
  4326. },
  4327. _activate: function( event ) {
  4328. if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
  4329. if ( this.active.children( "[aria-haspopup='true']" ).length ) {
  4330. this.expand( event );
  4331. } else {
  4332. this.select( event );
  4333. }
  4334. }
  4335. },
  4336. refresh: function() {
  4337. var menus, items, newSubmenus, newItems, newWrappers,
  4338. that = this,
  4339. icon = this.options.icons.submenu,
  4340. submenus = this.element.find( this.options.menus );
  4341. this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
  4342. // Initialize nested menus
  4343. newSubmenus = submenus.filter( ":not(.ui-menu)" )
  4344. .hide()
  4345. .attr( {
  4346. role: this.options.role,
  4347. "aria-hidden": "true",
  4348. "aria-expanded": "false"
  4349. } )
  4350. .each( function() {
  4351. var menu = $( this ),
  4352. item = menu.prev(),
  4353. submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
  4354. that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
  4355. item
  4356. .attr( "aria-haspopup", "true" )
  4357. .prepend( submenuCaret );
  4358. menu.attr( "aria-labelledby", item.attr( "id" ) );
  4359. } );
  4360. this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
  4361. menus = submenus.add( this.element );
  4362. items = menus.find( this.options.items );
  4363. // Initialize menu-items containing spaces and/or dashes only as dividers
  4364. items.not( ".ui-menu-item" ).each( function() {
  4365. var item = $( this );
  4366. if ( that._isDivider( item ) ) {
  4367. that._addClass( item, "ui-menu-divider", "ui-widget-content" );
  4368. }
  4369. } );
  4370. // Don't refresh list items that are already adapted
  4371. newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
  4372. newWrappers = newItems.children()
  4373. .not( ".ui-menu" )
  4374. .uniqueId()
  4375. .attr( {
  4376. tabIndex: -1,
  4377. role: this._itemRole()
  4378. } );
  4379. this._addClass( newItems, "ui-menu-item" )
  4380. ._addClass( newWrappers, "ui-menu-item-wrapper" );
  4381. // Add aria-disabled attribute to any disabled menu item
  4382. items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
  4383. // If the active item has been removed, blur the menu
  4384. if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
  4385. this.blur();
  4386. }
  4387. },
  4388. _itemRole: function() {
  4389. return {
  4390. menu: "menuitem",
  4391. listbox: "option"
  4392. }[ this.options.role ];
  4393. },
  4394. _setOption: function( key, value ) {
  4395. if ( key === "icons" ) {
  4396. var icons = this.element.find( ".ui-menu-icon" );
  4397. this._removeClass( icons, null, this.options.icons.submenu )
  4398. ._addClass( icons, null, value.submenu );
  4399. }
  4400. this._super( key, value );
  4401. },
  4402. _setOptionDisabled: function( value ) {
  4403. this._super( value );
  4404. this.element.attr( "aria-disabled", String( value ) );
  4405. this._toggleClass( null, "ui-state-disabled", !!value );
  4406. },
  4407. focus: function( event, item ) {
  4408. var nested, focused, activeParent;
  4409. this.blur( event, event && event.type === "focus" );
  4410. this._scrollIntoView( item );
  4411. this.active = item.first();
  4412. focused = this.active.children( ".ui-menu-item-wrapper" );
  4413. this._addClass( focused, null, "ui-state-active" );
  4414. // Only update aria-activedescendant if there's a role
  4415. // otherwise we assume focus is managed elsewhere
  4416. if ( this.options.role ) {
  4417. this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
  4418. }
  4419. // Highlight active parent menu item, if any
  4420. activeParent = this.active
  4421. .parent()
  4422. .closest( ".ui-menu-item" )
  4423. .children( ".ui-menu-item-wrapper" );
  4424. this._addClass( activeParent, null, "ui-state-active" );
  4425. if ( event && event.type === "keydown" ) {
  4426. this._close();
  4427. } else {
  4428. this.timer = this._delay( function() {
  4429. this._close();
  4430. }, this.delay );
  4431. }
  4432. nested = item.children( ".ui-menu" );
  4433. if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
  4434. this._startOpening( nested );
  4435. }
  4436. this.activeMenu = item.parent();
  4437. this._trigger( "focus", event, { item: item } );
  4438. },
  4439. _scrollIntoView: function( item ) {
  4440. var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
  4441. if ( this._hasScroll() ) {
  4442. borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
  4443. paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
  4444. offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
  4445. scroll = this.activeMenu.scrollTop();
  4446. elementHeight = this.activeMenu.height();
  4447. itemHeight = item.outerHeight();
  4448. if ( offset < 0 ) {
  4449. this.activeMenu.scrollTop( scroll + offset );
  4450. } else if ( offset + itemHeight > elementHeight ) {
  4451. this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
  4452. }
  4453. }
  4454. },
  4455. blur: function( event, fromFocus ) {
  4456. if ( !fromFocus ) {
  4457. clearTimeout( this.timer );
  4458. }
  4459. if ( !this.active ) {
  4460. return;
  4461. }
  4462. this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
  4463. null, "ui-state-active" );
  4464. this._trigger( "blur", event, { item: this.active } );
  4465. this.active = null;
  4466. },
  4467. _startOpening: function( submenu ) {
  4468. clearTimeout( this.timer );
  4469. // Don't open if already open fixes a Firefox bug that caused a .5 pixel
  4470. // shift in the submenu position when mousing over the caret icon
  4471. if ( submenu.attr( "aria-hidden" ) !== "true" ) {
  4472. return;
  4473. }
  4474. this.timer = this._delay( function() {
  4475. this._close();
  4476. this._open( submenu );
  4477. }, this.delay );
  4478. },
  4479. _open: function( submenu ) {
  4480. var position = $.extend( {
  4481. of: this.active
  4482. }, this.options.position );
  4483. clearTimeout( this.timer );
  4484. this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
  4485. .hide()
  4486. .attr( "aria-hidden", "true" );
  4487. submenu
  4488. .show()
  4489. .removeAttr( "aria-hidden" )
  4490. .attr( "aria-expanded", "true" )
  4491. .position( position );
  4492. },
  4493. collapseAll: function( event, all ) {
  4494. clearTimeout( this.timer );
  4495. this.timer = this._delay( function() {
  4496. // If we were passed an event, look for the submenu that contains the event
  4497. var currentMenu = all ? this.element :
  4498. $( event && event.target ).closest( this.element.find( ".ui-menu" ) );
  4499. // If we found no valid submenu ancestor, use the main menu to close all
  4500. // sub menus anyway
  4501. if ( !currentMenu.length ) {
  4502. currentMenu = this.element;
  4503. }
  4504. this._close( currentMenu );
  4505. this.blur( event );
  4506. // Work around active item staying active after menu is blurred
  4507. this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
  4508. this.activeMenu = currentMenu;
  4509. }, this.delay );
  4510. },
  4511. // With no arguments, closes the currently active menu - if nothing is active
  4512. // it closes all menus. If passed an argument, it will search for menus BELOW
  4513. _close: function( startMenu ) {
  4514. if ( !startMenu ) {
  4515. startMenu = this.active ? this.active.parent() : this.element;
  4516. }
  4517. startMenu.find( ".ui-menu" )
  4518. .hide()
  4519. .attr( "aria-hidden", "true" )
  4520. .attr( "aria-expanded", "false" );
  4521. },
  4522. _closeOnDocumentClick: function( event ) {
  4523. return !$( event.target ).closest( ".ui-menu" ).length;
  4524. },
  4525. _isDivider: function( item ) {
  4526. // Match hyphen, em dash, en dash
  4527. return !/[^\-\u2014\u2013\s]/.test( item.text() );
  4528. },
  4529. collapse: function( event ) {
  4530. var newItem = this.active &&
  4531. this.active.parent().closest( ".ui-menu-item", this.element );
  4532. if ( newItem && newItem.length ) {
  4533. this._close();
  4534. this.focus( event, newItem );
  4535. }
  4536. },
  4537. expand: function( event ) {
  4538. var newItem = this.active &&
  4539. this.active
  4540. .children( ".ui-menu " )
  4541. .find( this.options.items )
  4542. .first();
  4543. if ( newItem && newItem.length ) {
  4544. this._open( newItem.parent() );
  4545. // Delay so Firefox will not hide activedescendant change in expanding submenu from AT
  4546. this._delay( function() {
  4547. this.focus( event, newItem );
  4548. } );
  4549. }
  4550. },
  4551. next: function( event ) {
  4552. this._move( "next", "first", event );
  4553. },
  4554. previous: function( event ) {
  4555. this._move( "prev", "last", event );
  4556. },
  4557. isFirstItem: function() {
  4558. return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
  4559. },
  4560. isLastItem: function() {
  4561. return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
  4562. },
  4563. _move: function( direction, filter, event ) {
  4564. var next;
  4565. if ( this.active ) {
  4566. if ( direction === "first" || direction === "last" ) {
  4567. next = this.active
  4568. [ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
  4569. .eq( -1 );
  4570. } else {
  4571. next = this.active
  4572. [ direction + "All" ]( ".ui-menu-item" )
  4573. .eq( 0 );
  4574. }
  4575. }
  4576. if ( !next || !next.length || !this.active ) {
  4577. next = this.activeMenu.find( this.options.items )[ filter ]();
  4578. }
  4579. this.focus( event, next );
  4580. },
  4581. nextPage: function( event ) {
  4582. var item, base, height;
  4583. if ( !this.active ) {
  4584. this.next( event );
  4585. return;
  4586. }
  4587. if ( this.isLastItem() ) {
  4588. return;
  4589. }
  4590. if ( this._hasScroll() ) {
  4591. base = this.active.offset().top;
  4592. height = this.element.height();
  4593. this.active.nextAll( ".ui-menu-item" ).each( function() {
  4594. item = $( this );
  4595. return item.offset().top - base - height < 0;
  4596. } );
  4597. this.focus( event, item );
  4598. } else {
  4599. this.focus( event, this.activeMenu.find( this.options.items )
  4600. [ !this.active ? "first" : "last" ]() );
  4601. }
  4602. },
  4603. previousPage: function( event ) {
  4604. var item, base, height;
  4605. if ( !this.active ) {
  4606. this.next( event );
  4607. return;
  4608. }
  4609. if ( this.isFirstItem() ) {
  4610. return;
  4611. }
  4612. if ( this._hasScroll() ) {
  4613. base = this.active.offset().top;
  4614. height = this.element.height();
  4615. this.active.prevAll( ".ui-menu-item" ).each( function() {
  4616. item = $( this );
  4617. return item.offset().top - base + height > 0;
  4618. } );
  4619. this.focus( event, item );
  4620. } else {
  4621. this.focus( event, this.activeMenu.find( this.options.items ).first() );
  4622. }
  4623. },
  4624. _hasScroll: function() {
  4625. return this.element.outerHeight() < this.element.prop( "scrollHeight" );
  4626. },
  4627. select: function( event ) {
  4628. // TODO: It should never be possible to not have an active item at this
  4629. // point, but the tests don't trigger mouseenter before click.
  4630. this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
  4631. var ui = { item: this.active };
  4632. if ( !this.active.has( ".ui-menu" ).length ) {
  4633. this.collapseAll( event, true );
  4634. }
  4635. this._trigger( "select", event, ui );
  4636. },
  4637. _filterMenuItems: function( character ) {
  4638. var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
  4639. regex = new RegExp( "^" + escapedCharacter, "i" );
  4640. return this.activeMenu
  4641. .find( this.options.items )
  4642. // Only match on items, not dividers or other content (#10571)
  4643. .filter( ".ui-menu-item" )
  4644. .filter( function() {
  4645. return regex.test(
  4646. $.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
  4647. } );
  4648. }
  4649. } );
  4650. /*!
  4651. * jQuery UI Autocomplete 1.12.1
  4652. * http://jqueryui.com
  4653. *
  4654. * Copyright jQuery Foundation and other contributors
  4655. * Released under the MIT license.
  4656. * http://jquery.org/license
  4657. */
  4658. //>>label: Autocomplete
  4659. //>>group: Widgets
  4660. //>>description: Lists suggested words as the user is typing.
  4661. //>>docs: http://api.jqueryui.com/autocomplete/
  4662. //>>demos: http://jqueryui.com/autocomplete/
  4663. //>>css.structure: ../../themes/base/core.css
  4664. //>>css.structure: ../../themes/base/autocomplete.css
  4665. //>>css.theme: ../../themes/base/theme.css
  4666. $.widget( "ui.autocomplete", {
  4667. version: "1.12.1",
  4668. defaultElement: "<input>",
  4669. options: {
  4670. appendTo: null,
  4671. autoFocus: false,
  4672. delay: 300,
  4673. minLength: 1,
  4674. position: {
  4675. my: "left top",
  4676. at: "left bottom",
  4677. collision: "none"
  4678. },
  4679. source: null,
  4680. // Callbacks
  4681. change: null,
  4682. close: null,
  4683. focus: null,
  4684. open: null,
  4685. response: null,
  4686. search: null,
  4687. select: null
  4688. },
  4689. requestIndex: 0,
  4690. pending: 0,
  4691. _create: function() {
  4692. // Some browsers only repeat keydown events, not keypress events,
  4693. // so we use the suppressKeyPress flag to determine if we've already
  4694. // handled the keydown event. #7269
  4695. // Unfortunately the code for & in keypress is the same as the up arrow,
  4696. // so we use the suppressKeyPressRepeat flag to avoid handling keypress
  4697. // events when we know the keydown event was used to modify the
  4698. // search term. #7799
  4699. var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
  4700. nodeName = this.element[ 0 ].nodeName.toLowerCase(),
  4701. isTextarea = nodeName === "textarea",
  4702. isInput = nodeName === "input";
  4703. // Textareas are always multi-line
  4704. // Inputs are always single-line, even if inside a contentEditable element
  4705. // IE also treats inputs as contentEditable
  4706. // All other element types are determined by whether or not they're contentEditable
  4707. this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
  4708. this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
  4709. this.isNewMenu = true;
  4710. this._addClass( "ui-autocomplete-input" );
  4711. this.element.attr( "autocomplete", "off" );
  4712. this._on( this.element, {
  4713. keydown: function( event ) {
  4714. if ( this.element.prop( "readOnly" ) ) {
  4715. suppressKeyPress = true;
  4716. suppressInput = true;
  4717. suppressKeyPressRepeat = true;
  4718. return;
  4719. }
  4720. suppressKeyPress = false;
  4721. suppressInput = false;
  4722. suppressKeyPressRepeat = false;
  4723. var keyCode = $.ui.keyCode;
  4724. switch ( event.keyCode ) {
  4725. case keyCode.PAGE_UP:
  4726. suppressKeyPress = true;
  4727. this._move( "previousPage", event );
  4728. break;
  4729. case keyCode.PAGE_DOWN:
  4730. suppressKeyPress = true;
  4731. this._move( "nextPage", event );
  4732. break;
  4733. case keyCode.UP:
  4734. suppressKeyPress = true;
  4735. this._keyEvent( "previous", event );
  4736. break;
  4737. case keyCode.DOWN:
  4738. suppressKeyPress = true;
  4739. this._keyEvent( "next", event );
  4740. break;
  4741. case keyCode.ENTER:
  4742. // when menu is open and has focus
  4743. if ( this.menu.active ) {
  4744. // #6055 - Opera still allows the keypress to occur
  4745. // which causes forms to submit
  4746. suppressKeyPress = true;
  4747. event.preventDefault();
  4748. this.menu.select( event );
  4749. }
  4750. break;
  4751. case keyCode.TAB:
  4752. if ( this.menu.active ) {
  4753. this.menu.select( event );
  4754. }
  4755. break;
  4756. case keyCode.ESCAPE:
  4757. if ( this.menu.element.is( ":visible" ) ) {
  4758. if ( !this.isMultiLine ) {
  4759. this._value( this.term );
  4760. }
  4761. this.close( event );
  4762. // Different browsers have different default behavior for escape
  4763. // Single press can mean undo or clear
  4764. // Double press in IE means clear the whole form
  4765. event.preventDefault();
  4766. }
  4767. break;
  4768. default:
  4769. suppressKeyPressRepeat = true;
  4770. // search timeout should be triggered before the input value is changed
  4771. this._searchTimeout( event );
  4772. break;
  4773. }
  4774. },
  4775. keypress: function( event ) {
  4776. if ( suppressKeyPress ) {
  4777. suppressKeyPress = false;
  4778. if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
  4779. event.preventDefault();
  4780. }
  4781. return;
  4782. }
  4783. if ( suppressKeyPressRepeat ) {
  4784. return;
  4785. }
  4786. // Replicate some key handlers to allow them to repeat in Firefox and Opera
  4787. var keyCode = $.ui.keyCode;
  4788. switch ( event.keyCode ) {
  4789. case keyCode.PAGE_UP:
  4790. this._move( "previousPage", event );
  4791. break;
  4792. case keyCode.PAGE_DOWN:
  4793. this._move( "nextPage", event );
  4794. break;
  4795. case keyCode.UP:
  4796. this._keyEvent( "previous", event );
  4797. break;
  4798. case keyCode.DOWN:
  4799. this._keyEvent( "next", event );
  4800. break;
  4801. }
  4802. },
  4803. input: function( event ) {
  4804. if ( suppressInput ) {
  4805. suppressInput = false;
  4806. event.preventDefault();
  4807. return;
  4808. }
  4809. this._searchTimeout( event );
  4810. },
  4811. focus: function() {
  4812. this.selectedItem = null;
  4813. this.previous = this._value();
  4814. },
  4815. blur: function( event ) {
  4816. if ( this.cancelBlur ) {
  4817. delete this.cancelBlur;
  4818. return;
  4819. }
  4820. clearTimeout( this.searching );
  4821. this.close( event );
  4822. this._change( event );
  4823. }
  4824. } );
  4825. this._initSource();
  4826. this.menu = $( "<ul>" )
  4827. .appendTo( this._appendTo() )
  4828. .menu( {
  4829. // disable ARIA support, the live region takes care of that
  4830. role: null
  4831. } )
  4832. .hide()
  4833. .menu( "instance" );
  4834. this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
  4835. this._on( this.menu.element, {
  4836. mousedown: function( event ) {
  4837. // prevent moving focus out of the text field
  4838. event.preventDefault();
  4839. // IE doesn't prevent moving focus even with event.preventDefault()
  4840. // so we set a flag to know when we should ignore the blur event
  4841. this.cancelBlur = true;
  4842. this._delay( function() {
  4843. delete this.cancelBlur;
  4844. // Support: IE 8 only
  4845. // Right clicking a menu item or selecting text from the menu items will
  4846. // result in focus moving out of the input. However, we've already received
  4847. // and ignored the blur event because of the cancelBlur flag set above. So
  4848. // we restore focus to ensure that the menu closes properly based on the user's
  4849. // next actions.
  4850. if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
  4851. this.element.trigger( "focus" );
  4852. }
  4853. } );
  4854. },
  4855. menufocus: function( event, ui ) {
  4856. var label, item;
  4857. // support: Firefox
  4858. // Prevent accidental activation of menu items in Firefox (#7024 #9118)
  4859. if ( this.isNewMenu ) {
  4860. this.isNewMenu = false;
  4861. if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
  4862. this.menu.blur();
  4863. this.document.one( "mousemove", function() {
  4864. $( event.target ).trigger( event.originalEvent );
  4865. } );
  4866. return;
  4867. }
  4868. }
  4869. item = ui.item.data( "ui-autocomplete-item" );
  4870. if ( false !== this._trigger( "focus", event, { item: item } ) ) {
  4871. // use value to match what will end up in the input, if it was a key event
  4872. if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
  4873. this._value( item.value );
  4874. }
  4875. }
  4876. // Announce the value in the liveRegion
  4877. label = ui.item.attr( "aria-label" ) || item.value;
  4878. if ( label && $.trim( label ).length ) {
  4879. this.liveRegion.children().hide();
  4880. $( "<div>" ).text( label ).appendTo( this.liveRegion );
  4881. }
  4882. },
  4883. menuselect: function( event, ui ) {
  4884. var item = ui.item.data( "ui-autocomplete-item" ),
  4885. previous = this.previous;
  4886. // Only trigger when focus was lost (click on menu)
  4887. if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
  4888. this.element.trigger( "focus" );
  4889. this.previous = previous;
  4890. // #6109 - IE triggers two focus events and the second
  4891. // is asynchronous, so we need to reset the previous
  4892. // term synchronously and asynchronously :-(
  4893. this._delay( function() {
  4894. this.previous = previous;
  4895. this.selectedItem = item;
  4896. } );
  4897. }
  4898. if ( false !== this._trigger( "select", event, { item: item } ) ) {
  4899. this._value( item.value );
  4900. }
  4901. // reset the term after the select event
  4902. // this allows custom select handling to work properly
  4903. this.term = this._value();
  4904. this.close( event );
  4905. this.selectedItem = item;
  4906. }
  4907. } );
  4908. this.liveRegion = $( "<div>", {
  4909. role: "status",
  4910. "aria-live": "assertive",
  4911. "aria-relevant": "additions"
  4912. } )
  4913. .appendTo( this.document[ 0 ].body );
  4914. this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
  4915. // Turning off autocomplete prevents the browser from remembering the
  4916. // value when navigating through history, so we re-enable autocomplete
  4917. // if the page is unloaded before the widget is destroyed. #7790
  4918. this._on( this.window, {
  4919. beforeunload: function() {
  4920. this.element.removeAttr( "autocomplete" );
  4921. }
  4922. } );
  4923. },
  4924. _destroy: function() {
  4925. clearTimeout( this.searching );
  4926. this.element.removeAttr( "autocomplete" );
  4927. this.menu.element.remove();
  4928. this.liveRegion.remove();
  4929. },
  4930. _setOption: function( key, value ) {
  4931. this._super( key, value );
  4932. if ( key === "source" ) {
  4933. this._initSource();
  4934. }
  4935. if ( key === "appendTo" ) {
  4936. this.menu.element.appendTo( this._appendTo() );
  4937. }
  4938. if ( key === "disabled" && value && this.xhr ) {
  4939. this.xhr.abort();
  4940. }
  4941. },
  4942. _isEventTargetInWidget: function( event ) {
  4943. var menuElement = this.menu.element[ 0 ];
  4944. return event.target === this.element[ 0 ] ||
  4945. event.target === menuElement ||
  4946. $.contains( menuElement, event.target );
  4947. },
  4948. _closeOnClickOutside: function( event ) {
  4949. if ( !this._isEventTargetInWidget( event ) ) {
  4950. this.close();
  4951. }
  4952. },
  4953. _appendTo: function() {
  4954. var element = this.options.appendTo;
  4955. if ( element ) {
  4956. element = element.jquery || element.nodeType ?
  4957. $( element ) :
  4958. this.document.find( element ).eq( 0 );
  4959. }
  4960. if ( !element || !element[ 0 ] ) {
  4961. element = this.element.closest( ".ui-front, dialog" );
  4962. }
  4963. if ( !element.length ) {
  4964. element = this.document[ 0 ].body;
  4965. }
  4966. return element;
  4967. },
  4968. _initSource: function() {
  4969. var array, url,
  4970. that = this;
  4971. if ( $.isArray( this.options.source ) ) {
  4972. array = this.options.source;
  4973. this.source = function( request, response ) {
  4974. response( $.ui.autocomplete.filter( array, request.term ) );
  4975. };
  4976. } else if ( typeof this.options.source === "string" ) {
  4977. url = this.options.source;
  4978. this.source = function( request, response ) {
  4979. if ( that.xhr ) {
  4980. that.xhr.abort();
  4981. }
  4982. that.xhr = $.ajax( {
  4983. url: url,
  4984. data: request,
  4985. dataType: "json",
  4986. success: function( data ) {
  4987. response( data );
  4988. },
  4989. error: function() {
  4990. response( [] );
  4991. }
  4992. } );
  4993. };
  4994. } else {
  4995. this.source = this.options.source;
  4996. }
  4997. },
  4998. _searchTimeout: function( event ) {
  4999. clearTimeout( this.searching );
  5000. this.searching = this._delay( function() {
  5001. // Search if the value has changed, or if the user retypes the same value (see #7434)
  5002. var equalValues = this.term === this._value(),
  5003. menuVisible = this.menu.element.is( ":visible" ),
  5004. modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
  5005. if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
  5006. this.selectedItem = null;
  5007. this.search( null, event );
  5008. }
  5009. }, this.options.delay );
  5010. },
  5011. search: function( value, event ) {
  5012. value = value != null ? value : this._value();
  5013. // Always save the actual value, not the one passed as an argument
  5014. this.term = this._value();
  5015. if ( value.length < this.options.minLength ) {
  5016. return this.close( event );
  5017. }
  5018. if ( this._trigger( "search", event ) === false ) {
  5019. return;
  5020. }
  5021. return this._search( value );
  5022. },
  5023. _search: function( value ) {
  5024. this.pending++;
  5025. this._addClass( "ui-autocomplete-loading" );
  5026. this.cancelSearch = false;
  5027. this.source( { term: value }, this._response() );
  5028. },
  5029. _response: function() {
  5030. var index = ++this.requestIndex;
  5031. return $.proxy( function( content ) {
  5032. if ( index === this.requestIndex ) {
  5033. this.__response( content );
  5034. }
  5035. this.pending--;
  5036. if ( !this.pending ) {
  5037. this._removeClass( "ui-autocomplete-loading" );
  5038. }
  5039. }, this );
  5040. },
  5041. __response: function( content ) {
  5042. if ( content ) {
  5043. content = this._normalize( content );
  5044. }
  5045. this._trigger( "response", null, { content: content } );
  5046. if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
  5047. this._suggest( content );
  5048. this._trigger( "open" );
  5049. } else {
  5050. // use ._close() instead of .close() so we don't cancel future searches
  5051. this._close();
  5052. }
  5053. },
  5054. close: function( event ) {
  5055. this.cancelSearch = true;
  5056. this._close( event );
  5057. },
  5058. _close: function( event ) {
  5059. // Remove the handler that closes the menu on outside clicks
  5060. this._off( this.document, "mousedown" );
  5061. if ( this.menu.element.is( ":visible" ) ) {
  5062. this.menu.element.hide();
  5063. this.menu.blur();
  5064. this.isNewMenu = true;
  5065. this._trigger( "close", event );
  5066. }
  5067. },
  5068. _change: function( event ) {
  5069. if ( this.previous !== this._value() ) {
  5070. this._trigger( "change", event, { item: this.selectedItem } );
  5071. }
  5072. },
  5073. _normalize: function( items ) {
  5074. // assume all items have the right format when the first item is complete
  5075. if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
  5076. return items;
  5077. }
  5078. return $.map( items, function( item ) {
  5079. if ( typeof item === "string" ) {
  5080. return {
  5081. label: item,
  5082. value: item
  5083. };
  5084. }
  5085. return $.extend( {}, item, {
  5086. label: item.label || item.value,
  5087. value: item.value || item.label
  5088. } );
  5089. } );
  5090. },
  5091. _suggest: function( items ) {
  5092. var ul = this.menu.element.empty();
  5093. this._renderMenu( ul, items );
  5094. this.isNewMenu = true;
  5095. this.menu.refresh();
  5096. // Size and position menu
  5097. ul.show();
  5098. this._resizeMenu();
  5099. ul.position( $.extend( {
  5100. of: this.element
  5101. }, this.options.position ) );
  5102. if ( this.options.autoFocus ) {
  5103. this.menu.next();
  5104. }
  5105. // Listen for interactions outside of the widget (#6642)
  5106. this._on( this.document, {
  5107. mousedown: "_closeOnClickOutside"
  5108. } );
  5109. },
  5110. _resizeMenu: function() {
  5111. var ul = this.menu.element;
  5112. ul.outerWidth( Math.max(
  5113. // Firefox wraps long text (possibly a rounding bug)
  5114. // so we add 1px to avoid the wrapping (#7513)
  5115. ul.width( "" ).outerWidth() + 1,
  5116. this.element.outerWidth()
  5117. ) );
  5118. },
  5119. _renderMenu: function( ul, items ) {
  5120. var that = this;
  5121. $.each( items, function( index, item ) {
  5122. that._renderItemData( ul, item );
  5123. } );
  5124. },
  5125. _renderItemData: function( ul, item ) {
  5126. return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
  5127. },
  5128. _renderItem: function( ul, item ) {
  5129. return $( "<li>" )
  5130. .append( $( "<div>" ).text( item.label ) )
  5131. .appendTo( ul );
  5132. },
  5133. _move: function( direction, event ) {
  5134. if ( !this.menu.element.is( ":visible" ) ) {
  5135. this.search( null, event );
  5136. return;
  5137. }
  5138. if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
  5139. this.menu.isLastItem() && /^next/.test( direction ) ) {
  5140. if ( !this.isMultiLine ) {
  5141. this._value( this.term );
  5142. }
  5143. this.menu.blur();
  5144. return;
  5145. }
  5146. this.menu[ direction ]( event );
  5147. },
  5148. widget: function() {
  5149. return this.menu.element;
  5150. },
  5151. _value: function() {
  5152. return this.valueMethod.apply( this.element, arguments );
  5153. },
  5154. _keyEvent: function( keyEvent, event ) {
  5155. if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
  5156. this._move( keyEvent, event );
  5157. // Prevents moving cursor to beginning/end of the text field in some browsers
  5158. event.preventDefault();
  5159. }
  5160. },
  5161. // Support: Chrome <=50
  5162. // We should be able to just use this.element.prop( "isContentEditable" )
  5163. // but hidden elements always report false in Chrome.
  5164. // https://code.google.com/p/chromium/issues/detail?id=313082
  5165. _isContentEditable: function( element ) {
  5166. if ( !element.length ) {
  5167. return false;
  5168. }
  5169. var editable = element.prop( "contentEditable" );
  5170. if ( editable === "inherit" ) {
  5171. return this._isContentEditable( element.parent() );
  5172. }
  5173. return editable === "true";
  5174. }
  5175. } );
  5176. $.extend( $.ui.autocomplete, {
  5177. escapeRegex: function( value ) {
  5178. return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
  5179. },
  5180. filter: function( array, term ) {
  5181. var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
  5182. return $.grep( array, function( value ) {
  5183. return matcher.test( value.label || value.value || value );
  5184. } );
  5185. }
  5186. } );
  5187. // Live region extension, adding a `messages` option
  5188. // NOTE: This is an experimental API. We are still investigating
  5189. // a full solution for string manipulation and internationalization.
  5190. $.widget( "ui.autocomplete", $.ui.autocomplete, {
  5191. options: {
  5192. messages: {
  5193. noResults: "No search results.",
  5194. results: function( amount ) {
  5195. return amount + ( amount > 1 ? " results are" : " result is" ) +
  5196. " available, use up and down arrow keys to navigate.";
  5197. }
  5198. }
  5199. },
  5200. __response: function( content ) {
  5201. var message;
  5202. this._superApply( arguments );
  5203. if ( this.options.disabled || this.cancelSearch ) {
  5204. return;
  5205. }
  5206. if ( content && content.length ) {
  5207. message = this.options.messages.results( content.length );
  5208. } else {
  5209. message = this.options.messages.noResults;
  5210. }
  5211. this.liveRegion.children().hide();
  5212. $( "<div>" ).text( message ).appendTo( this.liveRegion );
  5213. }
  5214. } );
  5215. var widgetsAutocomplete = $.ui.autocomplete;
  5216. /*!
  5217. * jQuery UI Controlgroup 1.12.1
  5218. * http://jqueryui.com
  5219. *
  5220. * Copyright jQuery Foundation and other contributors
  5221. * Released under the MIT license.
  5222. * http://jquery.org/license
  5223. */
  5224. //>>label: Controlgroup
  5225. //>>group: Widgets
  5226. //>>description: Visually groups form control widgets
  5227. //>>docs: http://api.jqueryui.com/controlgroup/
  5228. //>>demos: http://jqueryui.com/controlgroup/
  5229. //>>css.structure: ../../themes/base/core.css
  5230. //>>css.structure: ../../themes/base/controlgroup.css
  5231. //>>css.theme: ../../themes/base/theme.css
  5232. var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
  5233. var widgetsControlgroup = $.widget( "ui.controlgroup", {
  5234. version: "1.12.1",
  5235. defaultElement: "<div>",
  5236. options: {
  5237. direction: "horizontal",
  5238. disabled: null,
  5239. onlyVisible: true,
  5240. items: {
  5241. "button": "input[type=button], input[type=submit], input[type=reset], button, a",
  5242. "controlgroupLabel": ".ui-controlgroup-label",
  5243. "checkboxradio": "input[type='checkbox'], input[type='radio']",
  5244. "selectmenu": "select",
  5245. "spinner": ".ui-spinner-input"
  5246. }
  5247. },
  5248. _create: function() {
  5249. this._enhance();
  5250. },
  5251. // To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
  5252. _enhance: function() {
  5253. this.element.attr( "role", "toolbar" );
  5254. this.refresh();
  5255. },
  5256. _destroy: function() {
  5257. this._callChildMethod( "destroy" );
  5258. this.childWidgets.removeData( "ui-controlgroup-data" );
  5259. this.element.removeAttr( "role" );
  5260. if ( this.options.items.controlgroupLabel ) {
  5261. this.element
  5262. .find( this.options.items.controlgroupLabel )
  5263. .find( ".ui-controlgroup-label-contents" )
  5264. .contents().unwrap();
  5265. }
  5266. },
  5267. _initWidgets: function() {
  5268. var that = this,
  5269. childWidgets = [];
  5270. // First we iterate over each of the items options
  5271. $.each( this.options.items, function( widget, selector ) {
  5272. var labels;
  5273. var options = {};
  5274. // Make sure the widget has a selector set
  5275. if ( !selector ) {
  5276. return;
  5277. }
  5278. if ( widget === "controlgroupLabel" ) {
  5279. labels = that.element.find( selector );
  5280. labels.each( function() {
  5281. var element = $( this );
  5282. if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
  5283. return;
  5284. }
  5285. element.contents()
  5286. .wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
  5287. } );
  5288. that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
  5289. childWidgets = childWidgets.concat( labels.get() );
  5290. return;
  5291. }
  5292. // Make sure the widget actually exists
  5293. if ( !$.fn[ widget ] ) {
  5294. return;
  5295. }
  5296. // We assume everything is in the middle to start because we can't determine
  5297. // first / last elements until all enhancments are done.
  5298. if ( that[ "_" + widget + "Options" ] ) {
  5299. options = that[ "_" + widget + "Options" ]( "middle" );
  5300. } else {
  5301. options = { classes: {} };
  5302. }
  5303. // Find instances of this widget inside controlgroup and init them
  5304. that.element
  5305. .find( selector )
  5306. .each( function() {
  5307. var element = $( this );
  5308. var instance = element[ widget ]( "instance" );
  5309. // We need to clone the default options for this type of widget to avoid
  5310. // polluting the variable options which has a wider scope than a single widget.
  5311. var instanceOptions = $.widget.extend( {}, options );
  5312. // If the button is the child of a spinner ignore it
  5313. // TODO: Find a more generic solution
  5314. if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
  5315. return;
  5316. }
  5317. // Create the widget if it doesn't exist
  5318. if ( !instance ) {
  5319. instance = element[ widget ]()[ widget ]( "instance" );
  5320. }
  5321. if ( instance ) {
  5322. instanceOptions.classes =
  5323. that._resolveClassesValues( instanceOptions.classes, instance );
  5324. }
  5325. element[ widget ]( instanceOptions );
  5326. // Store an instance of the controlgroup to be able to reference
  5327. // from the outermost element for changing options and refresh
  5328. var widgetElement = element[ widget ]( "widget" );
  5329. $.data( widgetElement[ 0 ], "ui-controlgroup-data",
  5330. instance ? instance : element[ widget ]( "instance" ) );
  5331. childWidgets.push( widgetElement[ 0 ] );
  5332. } );
  5333. } );
  5334. this.childWidgets = $( $.unique( childWidgets ) );
  5335. this._addClass( this.childWidgets, "ui-controlgroup-item" );
  5336. },
  5337. _callChildMethod: function( method ) {
  5338. this.childWidgets.each( function() {
  5339. var element = $( this ),
  5340. data = element.data( "ui-controlgroup-data" );
  5341. if ( data && data[ method ] ) {
  5342. data[ method ]();
  5343. }
  5344. } );
  5345. },
  5346. _updateCornerClass: function( element, position ) {
  5347. var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
  5348. var add = this._buildSimpleOptions( position, "label" ).classes.label;
  5349. this._removeClass( element, null, remove );
  5350. this._addClass( element, null, add );
  5351. },
  5352. _buildSimpleOptions: function( position, key ) {
  5353. var direction = this.options.direction === "vertical";
  5354. var result = {
  5355. classes: {}
  5356. };
  5357. result.classes[ key ] = {
  5358. "middle": "",
  5359. "first": "ui-corner-" + ( direction ? "top" : "left" ),
  5360. "last": "ui-corner-" + ( direction ? "bottom" : "right" ),
  5361. "only": "ui-corner-all"
  5362. }[ position ];
  5363. return result;
  5364. },
  5365. _spinnerOptions: function( position ) {
  5366. var options = this._buildSimpleOptions( position, "ui-spinner" );
  5367. options.classes[ "ui-spinner-up" ] = "";
  5368. options.classes[ "ui-spinner-down" ] = "";
  5369. return options;
  5370. },
  5371. _buttonOptions: function( position ) {
  5372. return this._buildSimpleOptions( position, "ui-button" );
  5373. },
  5374. _checkboxradioOptions: function( position ) {
  5375. return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
  5376. },
  5377. _selectmenuOptions: function( position ) {
  5378. var direction = this.options.direction === "vertical";
  5379. return {
  5380. width: direction ? "auto" : false,
  5381. classes: {
  5382. middle: {
  5383. "ui-selectmenu-button-open": "",
  5384. "ui-selectmenu-button-closed": ""
  5385. },
  5386. first: {
  5387. "ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
  5388. "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
  5389. },
  5390. last: {
  5391. "ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
  5392. "ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
  5393. },
  5394. only: {
  5395. "ui-selectmenu-button-open": "ui-corner-top",
  5396. "ui-selectmenu-button-closed": "ui-corner-all"
  5397. }
  5398. }[ position ]
  5399. };
  5400. },
  5401. _resolveClassesValues: function( classes, instance ) {
  5402. var result = {};
  5403. $.each( classes, function( key ) {
  5404. var current = instance.options.classes[ key ] || "";
  5405. current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
  5406. result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
  5407. } );
  5408. return result;
  5409. },
  5410. _setOption: function( key, value ) {
  5411. if ( key === "direction" ) {
  5412. this._removeClass( "ui-controlgroup-" + this.options.direction );
  5413. }
  5414. this._super( key, value );
  5415. if ( key === "disabled" ) {
  5416. this._callChildMethod( value ? "disable" : "enable" );
  5417. return;
  5418. }
  5419. this.refresh();
  5420. },
  5421. refresh: function() {
  5422. var children,
  5423. that = this;
  5424. this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
  5425. if ( this.options.direction === "horizontal" ) {
  5426. this._addClass( null, "ui-helper-clearfix" );
  5427. }
  5428. this._initWidgets();
  5429. children = this.childWidgets;
  5430. // We filter here because we need to track all childWidgets not just the visible ones
  5431. if ( this.options.onlyVisible ) {
  5432. children = children.filter( ":visible" );
  5433. }
  5434. if ( children.length ) {
  5435. // We do this last because we need to make sure all enhancment is done
  5436. // before determining first and last
  5437. $.each( [ "first", "last" ], function( index, value ) {
  5438. var instance = children[ value ]().data( "ui-controlgroup-data" );
  5439. if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
  5440. var options = that[ "_" + instance.widgetName + "Options" ](
  5441. children.length === 1 ? "only" : value
  5442. );
  5443. options.classes = that._resolveClassesValues( options.classes, instance );
  5444. instance.element[ instance.widgetName ]( options );
  5445. } else {
  5446. that._updateCornerClass( children[ value ](), value );
  5447. }
  5448. } );
  5449. // Finally call the refresh method on each of the child widgets.
  5450. this._callChildMethod( "refresh" );
  5451. }
  5452. }
  5453. } );
  5454. /*!
  5455. * jQuery UI Checkboxradio 1.12.1
  5456. * http://jqueryui.com
  5457. *
  5458. * Copyright jQuery Foundation and other contributors
  5459. * Released under the MIT license.
  5460. * http://jquery.org/license
  5461. */
  5462. //>>label: Checkboxradio
  5463. //>>group: Widgets
  5464. //>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
  5465. //>>docs: http://api.jqueryui.com/checkboxradio/
  5466. //>>demos: http://jqueryui.com/checkboxradio/
  5467. //>>css.structure: ../../themes/base/core.css
  5468. //>>css.structure: ../../themes/base/button.css
  5469. //>>css.structure: ../../themes/base/checkboxradio.css
  5470. //>>css.theme: ../../themes/base/theme.css
  5471. $.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
  5472. version: "1.12.1",
  5473. options: {
  5474. disabled: null,
  5475. label: null,
  5476. icon: true,
  5477. classes: {
  5478. "ui-checkboxradio-label": "ui-corner-all",
  5479. "ui-checkboxradio-icon": "ui-corner-all"
  5480. }
  5481. },
  5482. _getCreateOptions: function() {
  5483. var disabled, labels;
  5484. var that = this;
  5485. var options = this._super() || {};
  5486. // We read the type here, because it makes more sense to throw a element type error first,
  5487. // rather then the error for lack of a label. Often if its the wrong type, it
  5488. // won't have a label (e.g. calling on a div, btn, etc)
  5489. this._readType();
  5490. labels = this.element.labels();
  5491. // If there are multiple labels, use the last one
  5492. this.label = $( labels[ labels.length - 1 ] );
  5493. if ( !this.label.length ) {
  5494. $.error( "No label found for checkboxradio widget" );
  5495. }
  5496. this.originalLabel = "";
  5497. // We need to get the label text but this may also need to make sure it does not contain the
  5498. // input itself.
  5499. this.label.contents().not( this.element[ 0 ] ).each( function() {
  5500. // The label contents could be text, html, or a mix. We concat each element to get a
  5501. // string representation of the label, without the input as part of it.
  5502. that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
  5503. } );
  5504. // Set the label option if we found label text
  5505. if ( this.originalLabel ) {
  5506. options.label = this.originalLabel;
  5507. }
  5508. disabled = this.element[ 0 ].disabled;
  5509. if ( disabled != null ) {
  5510. options.disabled = disabled;
  5511. }
  5512. return options;
  5513. },
  5514. _create: function() {
  5515. var checked = this.element[ 0 ].checked;
  5516. this._bindFormResetHandler();
  5517. if ( this.options.disabled == null ) {
  5518. this.options.disabled = this.element[ 0 ].disabled;
  5519. }
  5520. this._setOption( "disabled", this.options.disabled );
  5521. this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
  5522. this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
  5523. if ( this.type === "radio" ) {
  5524. this._addClass( this.label, "ui-checkboxradio-radio-label" );
  5525. }
  5526. if ( this.options.label && this.options.label !== this.originalLabel ) {
  5527. this._updateLabel();
  5528. } else if ( this.originalLabel ) {
  5529. this.options.label = this.originalLabel;
  5530. }
  5531. this._enhance();
  5532. if ( checked ) {
  5533. this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
  5534. if ( this.icon ) {
  5535. this._addClass( this.icon, null, "ui-state-hover" );
  5536. }
  5537. }
  5538. this._on( {
  5539. change: "_toggleClasses",
  5540. focus: function() {
  5541. this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
  5542. },
  5543. blur: function() {
  5544. this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
  5545. }
  5546. } );
  5547. },
  5548. _readType: function() {
  5549. var nodeName = this.element[ 0 ].nodeName.toLowerCase();
  5550. this.type = this.element[ 0 ].type;
  5551. if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
  5552. $.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
  5553. " and element.type=" + this.type );
  5554. }
  5555. },
  5556. // Support jQuery Mobile enhanced option
  5557. _enhance: function() {
  5558. this._updateIcon( this.element[ 0 ].checked );
  5559. },
  5560. widget: function() {
  5561. return this.label;
  5562. },
  5563. _getRadioGroup: function() {
  5564. var group;
  5565. var name = this.element[ 0 ].name;
  5566. var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";
  5567. if ( !name ) {
  5568. return $( [] );
  5569. }
  5570. if ( this.form.length ) {
  5571. group = $( this.form[ 0 ].elements ).filter( nameSelector );
  5572. } else {
  5573. // Not inside a form, check all inputs that also are not inside a form
  5574. group = $( nameSelector ).filter( function() {
  5575. return $( this ).form().length === 0;
  5576. } );
  5577. }
  5578. return group.not( this.element );
  5579. },
  5580. _toggleClasses: function() {
  5581. var checked = this.element[ 0 ].checked;
  5582. this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
  5583. if ( this.options.icon && this.type === "checkbox" ) {
  5584. this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
  5585. ._toggleClass( this.icon, null, "ui-icon-blank", !checked );
  5586. }
  5587. if ( this.type === "radio" ) {
  5588. this._getRadioGroup()
  5589. .each( function() {
  5590. var instance = $( this ).checkboxradio( "instance" );
  5591. if ( instance ) {
  5592. instance._removeClass( instance.label,
  5593. "ui-checkboxradio-checked", "ui-state-active" );
  5594. }
  5595. } );
  5596. }
  5597. },
  5598. _destroy: function() {
  5599. this._unbindFormResetHandler();
  5600. if ( this.icon ) {
  5601. this.icon.remove();
  5602. this.iconSpace.remove();
  5603. }
  5604. },
  5605. _setOption: function( key, value ) {
  5606. // We don't allow the value to be set to nothing
  5607. if ( key === "label" && !value ) {
  5608. return;
  5609. }
  5610. this._super( key, value );
  5611. if ( key === "disabled" ) {
  5612. this._toggleClass( this.label, null, "ui-state-disabled", value );
  5613. this.element[ 0 ].disabled = value;
  5614. // Don't refresh when setting disabled
  5615. return;
  5616. }
  5617. this.refresh();
  5618. },
  5619. _updateIcon: function( checked ) {
  5620. var toAdd = "ui-icon ui-icon-background ";
  5621. if ( this.options.icon ) {
  5622. if ( !this.icon ) {
  5623. this.icon = $( "<span>" );
  5624. this.iconSpace = $( "<span> </span>" );
  5625. this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
  5626. }
  5627. if ( this.type === "checkbox" ) {
  5628. toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
  5629. this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
  5630. } else {
  5631. toAdd += "ui-icon-blank";
  5632. }
  5633. this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
  5634. if ( !checked ) {
  5635. this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
  5636. }
  5637. this.icon.prependTo( this.label ).after( this.iconSpace );
  5638. } else if ( this.icon !== undefined ) {
  5639. this.icon.remove();
  5640. this.iconSpace.remove();
  5641. delete this.icon;
  5642. }
  5643. },
  5644. _updateLabel: function() {
  5645. // Remove the contents of the label ( minus the icon, icon space, and input )
  5646. var contents = this.label.contents().not( this.element[ 0 ] );
  5647. if ( this.icon ) {
  5648. contents = contents.not( this.icon[ 0 ] );
  5649. }
  5650. if ( this.iconSpace ) {
  5651. contents = contents.not( this.iconSpace[ 0 ] );
  5652. }
  5653. contents.remove();
  5654. this.label.append( this.options.label );
  5655. },
  5656. refresh: function() {
  5657. var checked = this.element[ 0 ].checked,
  5658. isDisabled = this.element[ 0 ].disabled;
  5659. this._updateIcon( checked );
  5660. this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
  5661. if ( this.options.label !== null ) {
  5662. this._updateLabel();
  5663. }
  5664. if ( isDisabled !== this.options.disabled ) {
  5665. this._setOptions( { "disabled": isDisabled } );
  5666. }
  5667. }
  5668. } ] );
  5669. var widgetsCheckboxradio = $.ui.checkboxradio;
  5670. /*!
  5671. * jQuery UI Button 1.12.1
  5672. * http://jqueryui.com
  5673. *
  5674. * Copyright jQuery Foundation and other contributors
  5675. * Released under the MIT license.
  5676. * http://jquery.org/license
  5677. */
  5678. //>>label: Button
  5679. //>>group: Widgets
  5680. //>>description: Enhances a form with themeable buttons.
  5681. //>>docs: http://api.jqueryui.com/button/
  5682. //>>demos: http://jqueryui.com/button/
  5683. //>>css.structure: ../../themes/base/core.css
  5684. //>>css.structure: ../../themes/base/button.css
  5685. //>>css.theme: ../../themes/base/theme.css
  5686. $.widget( "ui.button", {
  5687. version: "1.12.1",
  5688. defaultElement: "<button>",
  5689. options: {
  5690. classes: {
  5691. "ui-button": "ui-corner-all"
  5692. },
  5693. disabled: null,
  5694. icon: null,
  5695. iconPosition: "beginning",
  5696. label: null,
  5697. showLabel: true
  5698. },
  5699. _getCreateOptions: function() {
  5700. var disabled,
  5701. // This is to support cases like in jQuery Mobile where the base widget does have
  5702. // an implementation of _getCreateOptions
  5703. options = this._super() || {};
  5704. this.isInput = this.element.is( "input" );
  5705. disabled = this.element[ 0 ].disabled;
  5706. if ( disabled != null ) {
  5707. options.disabled = disabled;
  5708. }
  5709. this.originalLabel = this.isInput ? this.element.val() : this.element.html();
  5710. if ( this.originalLabel ) {
  5711. options.label = this.originalLabel;
  5712. }
  5713. return options;
  5714. },
  5715. _create: function() {
  5716. if ( !this.option.showLabel & !this.options.icon ) {
  5717. this.options.showLabel = true;
  5718. }
  5719. // We have to check the option again here even though we did in _getCreateOptions,
  5720. // because null may have been passed on init which would override what was set in
  5721. // _getCreateOptions
  5722. if ( this.options.disabled == null ) {
  5723. this.options.disabled = this.element[ 0 ].disabled || false;
  5724. }
  5725. this.hasTitle = !!this.element.attr( "title" );
  5726. // Check to see if the label needs to be set or if its already correct
  5727. if ( this.options.label && this.options.label !== this.originalLabel ) {
  5728. if ( this.isInput ) {
  5729. this.element.val( this.options.label );
  5730. } else {
  5731. this.element.html( this.options.label );
  5732. }
  5733. }
  5734. this._addClass( "ui-button", "ui-widget" );
  5735. this._setOption( "disabled", this.options.disabled );
  5736. this._enhance();
  5737. if ( this.element.is( "a" ) ) {
  5738. this._on( {
  5739. "keyup": function( event ) {
  5740. if ( event.keyCode === $.ui.keyCode.SPACE ) {
  5741. event.preventDefault();
  5742. // Support: PhantomJS <= 1.9, IE 8 Only
  5743. // If a native click is available use it so we actually cause navigation
  5744. // otherwise just trigger a click event
  5745. if ( this.element[ 0 ].click ) {
  5746. this.element[ 0 ].click();
  5747. } else {
  5748. this.element.trigger( "click" );
  5749. }
  5750. }
  5751. }
  5752. } );
  5753. }
  5754. },
  5755. _enhance: function() {
  5756. if ( !this.element.is( "button" ) ) {
  5757. this.element.attr( "role", "button" );
  5758. }
  5759. if ( this.options.icon ) {
  5760. this._updateIcon( "icon", this.options.icon );
  5761. this._updateTooltip();
  5762. }
  5763. },
  5764. _updateTooltip: function() {
  5765. this.title = this.element.attr( "title" );
  5766. if ( !this.options.showLabel && !this.title ) {
  5767. this.element.attr( "title", this.options.label );
  5768. }
  5769. },
  5770. _updateIcon: function( option, value ) {
  5771. var icon = option !== "iconPosition",
  5772. position = icon ? this.options.iconPosition : value,
  5773. displayBlock = position === "top" || position === "bottom";
  5774. // Create icon
  5775. if ( !this.icon ) {
  5776. this.icon = $( "<span>" );
  5777. this._addClass( this.icon, "ui-button-icon", "ui-icon" );
  5778. if ( !this.options.showLabel ) {
  5779. this._addClass( "ui-button-icon-only" );
  5780. }
  5781. } else if ( icon ) {
  5782. // If we are updating the icon remove the old icon class
  5783. this._removeClass( this.icon, null, this.options.icon );
  5784. }
  5785. // If we are updating the icon add the new icon class
  5786. if ( icon ) {
  5787. this._addClass( this.icon, null, value );
  5788. }
  5789. this._attachIcon( position );
  5790. // If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
  5791. // the iconSpace if there is one.
  5792. if ( displayBlock ) {
  5793. this._addClass( this.icon, null, "ui-widget-icon-block" );
  5794. if ( this.iconSpace ) {
  5795. this.iconSpace.remove();
  5796. }
  5797. } else {
  5798. // Position is beginning or end so remove the ui-widget-icon-block class and add the
  5799. // space if it does not exist
  5800. if ( !this.iconSpace ) {
  5801. this.iconSpace = $( "<span> </span>" );
  5802. this._addClass( this.iconSpace, "ui-button-icon-space" );
  5803. }
  5804. this._removeClass( this.icon, null, "ui-wiget-icon-block" );
  5805. this._attachIconSpace( position );
  5806. }
  5807. },
  5808. _destroy: function() {
  5809. this.element.removeAttr( "role" );
  5810. if ( this.icon ) {
  5811. this.icon.remove();
  5812. }
  5813. if ( this.iconSpace ) {
  5814. this.iconSpace.remove();
  5815. }
  5816. if ( !this.hasTitle ) {
  5817. this.element.removeAttr( "title" );
  5818. }
  5819. },
  5820. _attachIconSpace: function( iconPosition ) {
  5821. this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
  5822. },
  5823. _attachIcon: function( iconPosition ) {
  5824. this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
  5825. },
  5826. _setOptions: function( options ) {
  5827. var newShowLabel = options.showLabel === undefined ?
  5828. this.options.showLabel :
  5829. options.showLabel,
  5830. newIcon = options.icon === undefined ? this.options.icon : options.icon;
  5831. if ( !newShowLabel && !newIcon ) {
  5832. options.showLabel = true;
  5833. }
  5834. this._super( options );
  5835. },
  5836. _setOption: function( key, value ) {
  5837. if ( key === "icon" ) {
  5838. if ( value ) {
  5839. this._updateIcon( key, value );
  5840. } else if ( this.icon ) {
  5841. this.icon.remove();
  5842. if ( this.iconSpace ) {
  5843. this.iconSpace.remove();
  5844. }
  5845. }
  5846. }
  5847. if ( key === "iconPosition" ) {
  5848. this._updateIcon( key, value );
  5849. }
  5850. // Make sure we can't end up with a button that has neither text nor icon
  5851. if ( key === "showLabel" ) {
  5852. this._toggleClass( "ui-button-icon-only", null, !value );
  5853. this._updateTooltip();
  5854. }
  5855. if ( key === "label" ) {
  5856. if ( this.isInput ) {
  5857. this.element.val( value );
  5858. } else {
  5859. // If there is an icon, append it, else nothing then append the value
  5860. // this avoids removal of the icon when setting label text
  5861. this.element.html( value );
  5862. if ( this.icon ) {
  5863. this._attachIcon( this.options.iconPosition );
  5864. this._attachIconSpace( this.options.iconPosition );
  5865. }
  5866. }
  5867. }
  5868. this._super( key, value );
  5869. if ( key === "disabled" ) {
  5870. this._toggleClass( null, "ui-state-disabled", value );
  5871. this.element[ 0 ].disabled = value;
  5872. if ( value ) {
  5873. this.element.blur();
  5874. }
  5875. }
  5876. },
  5877. refresh: function() {
  5878. // Make sure to only check disabled if its an element that supports this otherwise
  5879. // check for the disabled class to determine state
  5880. var isDisabled = this.element.is( "input, button" ) ?
  5881. this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
  5882. if ( isDisabled !== this.options.disabled ) {
  5883. this._setOptions( { disabled: isDisabled } );
  5884. }
  5885. this._updateTooltip();
  5886. }
  5887. } );
  5888. // DEPRECATED
  5889. if ( $.uiBackCompat !== false ) {
  5890. // Text and Icons options
  5891. $.widget( "ui.button", $.ui.button, {
  5892. options: {
  5893. text: true,
  5894. icons: {
  5895. primary: null,
  5896. secondary: null
  5897. }
  5898. },
  5899. _create: function() {
  5900. if ( this.options.showLabel && !this.options.text ) {
  5901. this.options.showLabel = this.options.text;
  5902. }
  5903. if ( !this.options.showLabel && this.options.text ) {
  5904. this.options.text = this.options.showLabel;
  5905. }
  5906. if ( !this.options.icon && ( this.options.icons.primary ||
  5907. this.options.icons.secondary ) ) {
  5908. if ( this.options.icons.primary ) {
  5909. this.options.icon = this.options.icons.primary;
  5910. } else {
  5911. this.options.icon = this.options.icons.secondary;
  5912. this.options.iconPosition = "end";
  5913. }
  5914. } else if ( this.options.icon ) {
  5915. this.options.icons.primary = this.options.icon;
  5916. }
  5917. this._super();
  5918. },
  5919. _setOption: function( key, value ) {
  5920. if ( key === "text" ) {
  5921. this._super( "showLabel", value );
  5922. return;
  5923. }
  5924. if ( key === "showLabel" ) {
  5925. this.options.text = value;
  5926. }
  5927. if ( key === "icon" ) {
  5928. this.options.icons.primary = value;
  5929. }
  5930. if ( key === "icons" ) {
  5931. if ( value.primary ) {
  5932. this._super( "icon", value.primary );
  5933. this._super( "iconPosition", "beginning" );
  5934. } else if ( value.secondary ) {
  5935. this._super( "icon", value.secondary );
  5936. this._super( "iconPosition", "end" );
  5937. }
  5938. }
  5939. this._superApply( arguments );
  5940. }
  5941. } );
  5942. $.fn.button = ( function( orig ) {
  5943. return function() {
  5944. if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
  5945. ( this.length && this[ 0 ].tagName === "INPUT" && (
  5946. this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
  5947. ) ) ) {
  5948. return orig.apply( this, arguments );
  5949. }
  5950. if ( !$.ui.checkboxradio ) {
  5951. $.error( "Checkboxradio widget missing" );
  5952. }
  5953. if ( arguments.length === 0 ) {
  5954. return this.checkboxradio( {
  5955. "icon": false
  5956. } );
  5957. }
  5958. return this.checkboxradio.apply( this, arguments );
  5959. };
  5960. } )( $.fn.button );
  5961. $.fn.buttonset = function() {
  5962. if ( !$.ui.controlgroup ) {
  5963. $.error( "Controlgroup widget missing" );
  5964. }
  5965. if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
  5966. return this.controlgroup.apply( this,
  5967. [ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
  5968. }
  5969. if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
  5970. return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
  5971. }
  5972. if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
  5973. arguments[ 0 ].items = {
  5974. button: arguments[ 0 ].items
  5975. };
  5976. }
  5977. return this.controlgroup.apply( this, arguments );
  5978. };
  5979. }
  5980. var widgetsButton = $.ui.button;
  5981. // jscs:disable maximumLineLength
  5982. /* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
  5983. /*!
  5984. * jQuery UI Datepicker 1.12.1
  5985. * http://jqueryui.com
  5986. *
  5987. * Copyright jQuery Foundation and other contributors
  5988. * Released under the MIT license.
  5989. * http://jquery.org/license
  5990. */
  5991. //>>label: Datepicker
  5992. //>>group: Widgets
  5993. //>>description: Displays a calendar from an input or inline for selecting dates.
  5994. //>>docs: http://api.jqueryui.com/datepicker/
  5995. //>>demos: http://jqueryui.com/datepicker/
  5996. //>>css.structure: ../../themes/base/core.css
  5997. //>>css.structure: ../../themes/base/datepicker.css
  5998. //>>css.theme: ../../themes/base/theme.css
  5999. $.extend( $.ui, { datepicker: { version: "1.12.1" } } );
  6000. var datepicker_instActive;
  6001. function datepicker_getZindex( elem ) {
  6002. var position, value;
  6003. while ( elem.length && elem[ 0 ] !== document ) {
  6004. // Ignore z-index if position is set to a value where z-index is ignored by the browser
  6005. // This makes behavior of this function consistent across browsers
  6006. // WebKit always returns auto if the element is positioned
  6007. position = elem.css( "position" );
  6008. if ( position === "absolute" || position === "relative" || position === "fixed" ) {
  6009. // IE returns 0 when zIndex is not specified
  6010. // other browsers return a string
  6011. // we ignore the case of nested elements with an explicit value of 0
  6012. // <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
  6013. value = parseInt( elem.css( "zIndex" ), 10 );
  6014. if ( !isNaN( value ) && value !== 0 ) {
  6015. return value;
  6016. }
  6017. }
  6018. elem = elem.parent();
  6019. }
  6020. return 0;
  6021. }
  6022. /* Date picker manager.
  6023. Use the singleton instance of this class, $.datepicker, to interact with the date picker.
  6024. Settings for (groups of) date pickers are maintained in an instance object,
  6025. allowing multiple different settings on the same page. */
  6026. function Datepicker() {
  6027. this._curInst = null; // The current instance in use
  6028. this._keyEvent = false; // If the last event was a key event
  6029. this._disabledInputs = []; // List of date picker inputs that have been disabled
  6030. this._datepickerShowing = false; // True if the popup picker is showing , false if not
  6031. this._inDialog = false; // True if showing within a "dialog", false if not
  6032. this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
  6033. this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
  6034. this._appendClass = "ui-datepicker-append"; // The name of the append marker class
  6035. this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
  6036. this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
  6037. this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
  6038. this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
  6039. this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
  6040. this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
  6041. this.regional = []; // Available regional settings, indexed by language code
  6042. this.regional[ "" ] = { // Default regional settings
  6043. closeText: "Done", // Display text for close link
  6044. prevText: "Prev", // Display text for previous month link
  6045. nextText: "Next", // Display text for next month link
  6046. currentText: "Today", // Display text for current month link
  6047. monthNames: [ "January","February","March","April","May","June",
  6048. "July","August","September","October","November","December" ], // Names of months for drop-down and formatting
  6049. monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
  6050. dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
  6051. dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
  6052. dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
  6053. weekHeader: "Wk", // Column header for week of the year
  6054. dateFormat: "mm/dd/yy", // See format options on parseDate
  6055. firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
  6056. isRTL: false, // True if right-to-left language, false if left-to-right
  6057. showMonthAfterYear: false, // True if the year select precedes month, false for month then year
  6058. yearSuffix: "" // Additional text to append to the year in the month headers
  6059. };
  6060. this._defaults = { // Global defaults for all the date picker instances
  6061. showOn: "focus", // "focus" for popup on focus,
  6062. // "button" for trigger button, or "both" for either
  6063. showAnim: "fadeIn", // Name of jQuery animation for popup
  6064. showOptions: {}, // Options for enhanced animations
  6065. defaultDate: null, // Used when field is blank: actual date,
  6066. // +/-number for offset from today, null for today
  6067. appendText: "", // Display text following the input box, e.g. showing the format
  6068. buttonText: "...", // Text for trigger button
  6069. buttonImage: "", // URL for trigger button image
  6070. buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
  6071. hideIfNoPrevNext: false, // True to hide next/previous month links
  6072. // if not applicable, false to just disable them
  6073. navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
  6074. gotoCurrent: false, // True if today link goes back to current selection instead
  6075. changeMonth: false, // True if month can be selected directly, false if only prev/next
  6076. changeYear: false, // True if year can be selected directly, false if only prev/next
  6077. yearRange: "c-10:c+10", // Range of years to display in drop-down,
  6078. // either relative to today's year (-nn:+nn), relative to currently displayed year
  6079. // (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
  6080. showOtherMonths: false, // True to show dates in other months, false to leave blank
  6081. selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
  6082. showWeek: false, // True to show week of the year, false to not show it
  6083. calculateWeek: this.iso8601Week, // How to calculate the week of the year,
  6084. // takes a Date and returns the number of the week for it
  6085. shortYearCutoff: "+10", // Short year values < this are in the current century,
  6086. // > this are in the previous century,
  6087. // string value starting with "+" for current year + value
  6088. minDate: null, // The earliest selectable date, or null for no limit
  6089. maxDate: null, // The latest selectable date, or null for no limit
  6090. duration: "fast", // Duration of display/closure
  6091. beforeShowDay: null, // Function that takes a date and returns an array with
  6092. // [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
  6093. // [2] = cell title (optional), e.g. $.datepicker.noWeekends
  6094. beforeShow: null, // Function that takes an input field and
  6095. // returns a set of custom settings for the date picker
  6096. onSelect: null, // Define a callback function when a date is selected
  6097. onChangeMonthYear: null, // Define a callback function when the month or year is changed
  6098. onClose: null, // Define a callback function when the datepicker is closed
  6099. numberOfMonths: 1, // Number of months to show at a time
  6100. showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
  6101. stepMonths: 1, // Number of months to step back/forward
  6102. stepBigMonths: 12, // Number of months to step back/forward for the big links
  6103. altField: "", // Selector for an alternate field to store selected dates into
  6104. altFormat: "", // The date format to use for the alternate field
  6105. constrainInput: true, // The input is constrained by the current date format
  6106. showButtonPanel: false, // True to show button panel, false to not show it
  6107. autoSize: false, // True to size the input for the date format, false to leave as is
  6108. disabled: false // The initial disabled state
  6109. };
  6110. $.extend( this._defaults, this.regional[ "" ] );
  6111. this.regional.en = $.extend( true, {}, this.regional[ "" ] );
  6112. this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
  6113. this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
  6114. }
  6115. $.extend( Datepicker.prototype, {
  6116. /* Class name added to elements to indicate already configured with a date picker. */
  6117. markerClassName: "hasDatepicker",
  6118. //Keep track of the maximum number of rows displayed (see #7043)
  6119. maxRows: 4,
  6120. // TODO rename to "widget" when switching to widget factory
  6121. _widgetDatepicker: function() {
  6122. return this.dpDiv;
  6123. },
  6124. /* Override the default settings for all instances of the date picker.
  6125. * @param settings object - the new settings to use as defaults (anonymous object)
  6126. * @return the manager object
  6127. */
  6128. setDefaults: function( settings ) {
  6129. datepicker_extendRemove( this._defaults, settings || {} );
  6130. return this;
  6131. },
  6132. /* Attach the date picker to a jQuery selection.
  6133. * @param target element - the target input field or division or span
  6134. * @param settings object - the new settings to use for this date picker instance (anonymous)
  6135. */
  6136. _attachDatepicker: function( target, settings ) {
  6137. var nodeName, inline, inst;
  6138. nodeName = target.nodeName.toLowerCase();
  6139. inline = ( nodeName === "div" || nodeName === "span" );
  6140. if ( !target.id ) {
  6141. this.uuid += 1;
  6142. target.id = "dp" + this.uuid;
  6143. }
  6144. inst = this._newInst( $( target ), inline );
  6145. inst.settings = $.extend( {}, settings || {} );
  6146. if ( nodeName === "input" ) {
  6147. this._connectDatepicker( target, inst );
  6148. } else if ( inline ) {
  6149. this._inlineDatepicker( target, inst );
  6150. }
  6151. },
  6152. /* Create a new instance object. */
  6153. _newInst: function( target, inline ) {
  6154. var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
  6155. return { id: id, input: target, // associated target
  6156. selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
  6157. drawMonth: 0, drawYear: 0, // month being drawn
  6158. inline: inline, // is datepicker inline or not
  6159. dpDiv: ( !inline ? this.dpDiv : // presentation div
  6160. datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
  6161. },
  6162. /* Attach the date picker to an input field. */
  6163. _connectDatepicker: function( target, inst ) {
  6164. var input = $( target );
  6165. inst.append = $( [] );
  6166. inst.trigger = $( [] );
  6167. if ( input.hasClass( this.markerClassName ) ) {
  6168. return;
  6169. }
  6170. this._attachments( input, inst );
  6171. input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
  6172. on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
  6173. this._autoSize( inst );
  6174. $.data( target, "datepicker", inst );
  6175. //If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
  6176. if ( inst.settings.disabled ) {
  6177. this._disableDatepicker( target );
  6178. }
  6179. },
  6180. /* Make attachments based on settings. */
  6181. _attachments: function( input, inst ) {
  6182. var showOn, buttonText, buttonImage,
  6183. appendText = this._get( inst, "appendText" ),
  6184. isRTL = this._get( inst, "isRTL" );
  6185. if ( inst.append ) {
  6186. inst.append.remove();
  6187. }
  6188. if ( appendText ) {
  6189. inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
  6190. input[ isRTL ? "before" : "after" ]( inst.append );
  6191. }
  6192. input.off( "focus", this._showDatepicker );
  6193. if ( inst.trigger ) {
  6194. inst.trigger.remove();
  6195. }
  6196. showOn = this._get( inst, "showOn" );
  6197. if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
  6198. input.on( "focus", this._showDatepicker );
  6199. }
  6200. if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
  6201. buttonText = this._get( inst, "buttonText" );
  6202. buttonImage = this._get( inst, "buttonImage" );
  6203. inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
  6204. $( "<img/>" ).addClass( this._triggerClass ).
  6205. attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
  6206. $( "<button type='button'></button>" ).addClass( this._triggerClass ).
  6207. html( !buttonImage ? buttonText : $( "<img/>" ).attr(
  6208. { src:buttonImage, alt:buttonText, title:buttonText } ) ) );
  6209. input[ isRTL ? "before" : "after" ]( inst.trigger );
  6210. inst.trigger.on( "click", function() {
  6211. if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
  6212. $.datepicker._hideDatepicker();
  6213. } else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
  6214. $.datepicker._hideDatepicker();
  6215. $.datepicker._showDatepicker( input[ 0 ] );
  6216. } else {
  6217. $.datepicker._showDatepicker( input[ 0 ] );
  6218. }
  6219. return false;
  6220. } );
  6221. }
  6222. },
  6223. /* Apply the maximum length for the date format. */
  6224. _autoSize: function( inst ) {
  6225. if ( this._get( inst, "autoSize" ) && !inst.inline ) {
  6226. var findMax, max, maxI, i,
  6227. date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
  6228. dateFormat = this._get( inst, "dateFormat" );
  6229. if ( dateFormat.match( /[DM]/ ) ) {
  6230. findMax = function( names ) {
  6231. max = 0;
  6232. maxI = 0;
  6233. for ( i = 0; i < names.length; i++ ) {
  6234. if ( names[ i ].length > max ) {
  6235. max = names[ i ].length;
  6236. maxI = i;
  6237. }
  6238. }
  6239. return maxI;
  6240. };
  6241. date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
  6242. "monthNames" : "monthNamesShort" ) ) ) );
  6243. date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
  6244. "dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
  6245. }
  6246. inst.input.attr( "size", this._formatDate( inst, date ).length );
  6247. }
  6248. },
  6249. /* Attach an inline date picker to a div. */
  6250. _inlineDatepicker: function( target, inst ) {
  6251. var divSpan = $( target );
  6252. if ( divSpan.hasClass( this.markerClassName ) ) {
  6253. return;
  6254. }
  6255. divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
  6256. $.data( target, "datepicker", inst );
  6257. this._setDate( inst, this._getDefaultDate( inst ), true );
  6258. this._updateDatepicker( inst );
  6259. this._updateAlternate( inst );
  6260. //If disabled option is true, disable the datepicker before showing it (see ticket #5665)
  6261. if ( inst.settings.disabled ) {
  6262. this._disableDatepicker( target );
  6263. }
  6264. // Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
  6265. // http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
  6266. inst.dpDiv.css( "display", "block" );
  6267. },
  6268. /* Pop-up the date picker in a "dialog" box.
  6269. * @param input element - ignored
  6270. * @param date string or Date - the initial date to display
  6271. * @param onSelect function - the function to call when a date is selected
  6272. * @param settings object - update the dialog date picker instance's settings (anonymous object)
  6273. * @param pos int[2] - coordinates for the dialog's position within the screen or
  6274. * event - with x/y coordinates or
  6275. * leave empty for default (screen centre)
  6276. * @return the manager object
  6277. */
  6278. _dialogDatepicker: function( input, date, onSelect, settings, pos ) {
  6279. var id, browserWidth, browserHeight, scrollX, scrollY,
  6280. inst = this._dialogInst; // internal instance
  6281. if ( !inst ) {
  6282. this.uuid += 1;
  6283. id = "dp" + this.uuid;
  6284. this._dialogInput = $( "<input type='text' id='" + id +
  6285. "' style='position: absolute; top: -100px; width: 0px;'/>" );
  6286. this._dialogInput.on( "keydown", this._doKeyDown );
  6287. $( "body" ).append( this._dialogInput );
  6288. inst = this._dialogInst = this._newInst( this._dialogInput, false );
  6289. inst.settings = {};
  6290. $.data( this._dialogInput[ 0 ], "datepicker", inst );
  6291. }
  6292. datepicker_extendRemove( inst.settings, settings || {} );
  6293. date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
  6294. this._dialogInput.val( date );
  6295. this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
  6296. if ( !this._pos ) {
  6297. browserWidth = document.documentElement.clientWidth;
  6298. browserHeight = document.documentElement.clientHeight;
  6299. scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
  6300. scrollY = document.documentElement.scrollTop || document.body.scrollTop;
  6301. this._pos = // should use actual width/height below
  6302. [ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
  6303. }
  6304. // Move input on screen for focus, but hidden behind dialog
  6305. this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
  6306. inst.settings.onSelect = onSelect;
  6307. this._inDialog = true;
  6308. this.dpDiv.addClass( this._dialogClass );
  6309. this._showDatepicker( this._dialogInput[ 0 ] );
  6310. if ( $.blockUI ) {
  6311. $.blockUI( this.dpDiv );
  6312. }
  6313. $.data( this._dialogInput[ 0 ], "datepicker", inst );
  6314. return this;
  6315. },
  6316. /* Detach a datepicker from its control.
  6317. * @param target element - the target input field or division or span
  6318. */
  6319. _destroyDatepicker: function( target ) {
  6320. var nodeName,
  6321. $target = $( target ),
  6322. inst = $.data( target, "datepicker" );
  6323. if ( !$target.hasClass( this.markerClassName ) ) {
  6324. return;
  6325. }
  6326. nodeName = target.nodeName.toLowerCase();
  6327. $.removeData( target, "datepicker" );
  6328. if ( nodeName === "input" ) {
  6329. inst.append.remove();
  6330. inst.trigger.remove();
  6331. $target.removeClass( this.markerClassName ).
  6332. off( "focus", this._showDatepicker ).
  6333. off( "keydown", this._doKeyDown ).
  6334. off( "keypress", this._doKeyPress ).
  6335. off( "keyup", this._doKeyUp );
  6336. } else if ( nodeName === "div" || nodeName === "span" ) {
  6337. $target.removeClass( this.markerClassName ).empty();
  6338. }
  6339. if ( datepicker_instActive === inst ) {
  6340. datepicker_instActive = null;
  6341. }
  6342. },
  6343. /* Enable the date picker to a jQuery selection.
  6344. * @param target element - the target input field or division or span
  6345. */
  6346. _enableDatepicker: function( target ) {
  6347. var nodeName, inline,
  6348. $target = $( target ),
  6349. inst = $.data( target, "datepicker" );
  6350. if ( !$target.hasClass( this.markerClassName ) ) {
  6351. return;
  6352. }
  6353. nodeName = target.nodeName.toLowerCase();
  6354. if ( nodeName === "input" ) {
  6355. target.disabled = false;
  6356. inst.trigger.filter( "button" ).
  6357. each( function() { this.disabled = false; } ).end().
  6358. filter( "img" ).css( { opacity: "1.0", cursor: "" } );
  6359. } else if ( nodeName === "div" || nodeName === "span" ) {
  6360. inline = $target.children( "." + this._inlineClass );
  6361. inline.children().removeClass( "ui-state-disabled" );
  6362. inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
  6363. prop( "disabled", false );
  6364. }
  6365. this._disabledInputs = $.map( this._disabledInputs,
  6366. function( value ) { return ( value === target ? null : value ); } ); // delete entry
  6367. },
  6368. /* Disable the date picker to a jQuery selection.
  6369. * @param target element - the target input field or division or span
  6370. */
  6371. _disableDatepicker: function( target ) {
  6372. var nodeName, inline,
  6373. $target = $( target ),
  6374. inst = $.data( target, "datepicker" );
  6375. if ( !$target.hasClass( this.markerClassName ) ) {
  6376. return;
  6377. }
  6378. nodeName = target.nodeName.toLowerCase();
  6379. if ( nodeName === "input" ) {
  6380. target.disabled = true;
  6381. inst.trigger.filter( "button" ).
  6382. each( function() { this.disabled = true; } ).end().
  6383. filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
  6384. } else if ( nodeName === "div" || nodeName === "span" ) {
  6385. inline = $target.children( "." + this._inlineClass );
  6386. inline.children().addClass( "ui-state-disabled" );
  6387. inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
  6388. prop( "disabled", true );
  6389. }
  6390. this._disabledInputs = $.map( this._disabledInputs,
  6391. function( value ) { return ( value === target ? null : value ); } ); // delete entry
  6392. this._disabledInputs[ this._disabledInputs.length ] = target;
  6393. },
  6394. /* Is the first field in a jQuery collection disabled as a datepicker?
  6395. * @param target element - the target input field or division or span
  6396. * @return boolean - true if disabled, false if enabled
  6397. */
  6398. _isDisabledDatepicker: function( target ) {
  6399. if ( !target ) {
  6400. return false;
  6401. }
  6402. for ( var i = 0; i < this._disabledInputs.length; i++ ) {
  6403. if ( this._disabledInputs[ i ] === target ) {
  6404. return true;
  6405. }
  6406. }
  6407. return false;
  6408. },
  6409. /* Retrieve the instance data for the target control.
  6410. * @param target element - the target input field or division or span
  6411. * @return object - the associated instance data
  6412. * @throws error if a jQuery problem getting data
  6413. */
  6414. _getInst: function( target ) {
  6415. try {
  6416. return $.data( target, "datepicker" );
  6417. }
  6418. catch ( err ) {
  6419. throw "Missing instance data for this datepicker";
  6420. }
  6421. },
  6422. /* Update or retrieve the settings for a date picker attached to an input field or division.
  6423. * @param target element - the target input field or division or span
  6424. * @param name object - the new settings to update or
  6425. * string - the name of the setting to change or retrieve,
  6426. * when retrieving also "all" for all instance settings or
  6427. * "defaults" for all global defaults
  6428. * @param value any - the new value for the setting
  6429. * (omit if above is an object or to retrieve a value)
  6430. */
  6431. _optionDatepicker: function( target, name, value ) {
  6432. var settings, date, minDate, maxDate,
  6433. inst = this._getInst( target );
  6434. if ( arguments.length === 2 && typeof name === "string" ) {
  6435. return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
  6436. ( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
  6437. this._get( inst, name ) ) : null ) );
  6438. }
  6439. settings = name || {};
  6440. if ( typeof name === "string" ) {
  6441. settings = {};
  6442. settings[ name ] = value;
  6443. }
  6444. if ( inst ) {
  6445. if ( this._curInst === inst ) {
  6446. this._hideDatepicker();
  6447. }
  6448. date = this._getDateDatepicker( target, true );
  6449. minDate = this._getMinMaxDate( inst, "min" );
  6450. maxDate = this._getMinMaxDate( inst, "max" );
  6451. datepicker_extendRemove( inst.settings, settings );
  6452. // reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
  6453. if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
  6454. inst.settings.minDate = this._formatDate( inst, minDate );
  6455. }
  6456. if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
  6457. inst.settings.maxDate = this._formatDate( inst, maxDate );
  6458. }
  6459. if ( "disabled" in settings ) {
  6460. if ( settings.disabled ) {
  6461. this._disableDatepicker( target );
  6462. } else {
  6463. this._enableDatepicker( target );
  6464. }
  6465. }
  6466. this._attachments( $( target ), inst );
  6467. this._autoSize( inst );
  6468. this._setDate( inst, date );
  6469. this._updateAlternate( inst );
  6470. this._updateDatepicker( inst );
  6471. }
  6472. },
  6473. // Change method deprecated
  6474. _changeDatepicker: function( target, name, value ) {
  6475. this._optionDatepicker( target, name, value );
  6476. },
  6477. /* Redraw the date picker attached to an input field or division.
  6478. * @param target element - the target input field or division or span
  6479. */
  6480. _refreshDatepicker: function( target ) {
  6481. var inst = this._getInst( target );
  6482. if ( inst ) {
  6483. this._updateDatepicker( inst );
  6484. }
  6485. },
  6486. /* Set the dates for a jQuery selection.
  6487. * @param target element - the target input field or division or span
  6488. * @param date Date - the new date
  6489. */
  6490. _setDateDatepicker: function( target, date ) {
  6491. var inst = this._getInst( target );
  6492. if ( inst ) {
  6493. this._setDate( inst, date );
  6494. this._updateDatepicker( inst );
  6495. this._updateAlternate( inst );
  6496. }
  6497. },
  6498. /* Get the date(s) for the first entry in a jQuery selection.
  6499. * @param target element - the target input field or division or span
  6500. * @param noDefault boolean - true if no default date is to be used
  6501. * @return Date - the current date
  6502. */
  6503. _getDateDatepicker: function( target, noDefault ) {
  6504. var inst = this._getInst( target );
  6505. if ( inst && !inst.inline ) {
  6506. this._setDateFromField( inst, noDefault );
  6507. }
  6508. return ( inst ? this._getDate( inst ) : null );
  6509. },
  6510. /* Handle keystrokes. */
  6511. _doKeyDown: function( event ) {
  6512. var onSelect, dateStr, sel,
  6513. inst = $.datepicker._getInst( event.target ),
  6514. handled = true,
  6515. isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
  6516. inst._keyEvent = true;
  6517. if ( $.datepicker._datepickerShowing ) {
  6518. switch ( event.keyCode ) {
  6519. case 9: $.datepicker._hideDatepicker();
  6520. handled = false;
  6521. break; // hide on tab out
  6522. case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
  6523. $.datepicker._currentClass + ")", inst.dpDiv );
  6524. if ( sel[ 0 ] ) {
  6525. $.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
  6526. }
  6527. onSelect = $.datepicker._get( inst, "onSelect" );
  6528. if ( onSelect ) {
  6529. dateStr = $.datepicker._formatDate( inst );
  6530. // Trigger custom callback
  6531. onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
  6532. } else {
  6533. $.datepicker._hideDatepicker();
  6534. }
  6535. return false; // don't submit the form
  6536. case 27: $.datepicker._hideDatepicker();
  6537. break; // hide on escape
  6538. case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  6539. -$.datepicker._get( inst, "stepBigMonths" ) :
  6540. -$.datepicker._get( inst, "stepMonths" ) ), "M" );
  6541. break; // previous month/year on page up/+ ctrl
  6542. case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  6543. +$.datepicker._get( inst, "stepBigMonths" ) :
  6544. +$.datepicker._get( inst, "stepMonths" ) ), "M" );
  6545. break; // next month/year on page down/+ ctrl
  6546. case 35: if ( event.ctrlKey || event.metaKey ) {
  6547. $.datepicker._clearDate( event.target );
  6548. }
  6549. handled = event.ctrlKey || event.metaKey;
  6550. break; // clear on ctrl or command +end
  6551. case 36: if ( event.ctrlKey || event.metaKey ) {
  6552. $.datepicker._gotoToday( event.target );
  6553. }
  6554. handled = event.ctrlKey || event.metaKey;
  6555. break; // current on ctrl or command +home
  6556. case 37: if ( event.ctrlKey || event.metaKey ) {
  6557. $.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
  6558. }
  6559. handled = event.ctrlKey || event.metaKey;
  6560. // -1 day on ctrl or command +left
  6561. if ( event.originalEvent.altKey ) {
  6562. $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  6563. -$.datepicker._get( inst, "stepBigMonths" ) :
  6564. -$.datepicker._get( inst, "stepMonths" ) ), "M" );
  6565. }
  6566. // next month/year on alt +left on Mac
  6567. break;
  6568. case 38: if ( event.ctrlKey || event.metaKey ) {
  6569. $.datepicker._adjustDate( event.target, -7, "D" );
  6570. }
  6571. handled = event.ctrlKey || event.metaKey;
  6572. break; // -1 week on ctrl or command +up
  6573. case 39: if ( event.ctrlKey || event.metaKey ) {
  6574. $.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
  6575. }
  6576. handled = event.ctrlKey || event.metaKey;
  6577. // +1 day on ctrl or command +right
  6578. if ( event.originalEvent.altKey ) {
  6579. $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
  6580. +$.datepicker._get( inst, "stepBigMonths" ) :
  6581. +$.datepicker._get( inst, "stepMonths" ) ), "M" );
  6582. }
  6583. // next month/year on alt +right
  6584. break;
  6585. case 40: if ( event.ctrlKey || event.metaKey ) {
  6586. $.datepicker._adjustDate( event.target, +7, "D" );
  6587. }
  6588. handled = event.ctrlKey || event.metaKey;
  6589. break; // +1 week on ctrl or command +down
  6590. default: handled = false;
  6591. }
  6592. } else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
  6593. $.datepicker._showDatepicker( this );
  6594. } else {
  6595. handled = false;
  6596. }
  6597. if ( handled ) {
  6598. event.preventDefault();
  6599. event.stopPropagation();
  6600. }
  6601. },
  6602. /* Filter entered characters - based on date format. */
  6603. _doKeyPress: function( event ) {
  6604. var chars, chr,
  6605. inst = $.datepicker._getInst( event.target );
  6606. if ( $.datepicker._get( inst, "constrainInput" ) ) {
  6607. chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
  6608. chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
  6609. return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
  6610. }
  6611. },
  6612. /* Synchronise manual entry and field/alternate field. */
  6613. _doKeyUp: function( event ) {
  6614. var date,
  6615. inst = $.datepicker._getInst( event.target );
  6616. if ( inst.input.val() !== inst.lastVal ) {
  6617. try {
  6618. date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
  6619. ( inst.input ? inst.input.val() : null ),
  6620. $.datepicker._getFormatConfig( inst ) );
  6621. if ( date ) { // only if valid
  6622. $.datepicker._setDateFromField( inst );
  6623. $.datepicker._updateAlternate( inst );
  6624. $.datepicker._updateDatepicker( inst );
  6625. }
  6626. }
  6627. catch ( err ) {
  6628. }
  6629. }
  6630. return true;
  6631. },
  6632. /* Pop-up the date picker for a given input field.
  6633. * If false returned from beforeShow event handler do not show.
  6634. * @param input element - the input field attached to the date picker or
  6635. * event - if triggered by focus
  6636. */
  6637. _showDatepicker: function( input ) {
  6638. input = input.target || input;
  6639. if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
  6640. input = $( "input", input.parentNode )[ 0 ];
  6641. }
  6642. if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
  6643. return;
  6644. }
  6645. var inst, beforeShow, beforeShowSettings, isFixed,
  6646. offset, showAnim, duration;
  6647. inst = $.datepicker._getInst( input );
  6648. if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
  6649. $.datepicker._curInst.dpDiv.stop( true, true );
  6650. if ( inst && $.datepicker._datepickerShowing ) {
  6651. $.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
  6652. }
  6653. }
  6654. beforeShow = $.datepicker._get( inst, "beforeShow" );
  6655. beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
  6656. if ( beforeShowSettings === false ) {
  6657. return;
  6658. }
  6659. datepicker_extendRemove( inst.settings, beforeShowSettings );
  6660. inst.lastVal = null;
  6661. $.datepicker._lastInput = input;
  6662. $.datepicker._setDateFromField( inst );
  6663. if ( $.datepicker._inDialog ) { // hide cursor
  6664. input.value = "";
  6665. }
  6666. if ( !$.datepicker._pos ) { // position below input
  6667. $.datepicker._pos = $.datepicker._findPos( input );
  6668. $.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
  6669. }
  6670. isFixed = false;
  6671. $( input ).parents().each( function() {
  6672. isFixed |= $( this ).css( "position" ) === "fixed";
  6673. return !isFixed;
  6674. } );
  6675. offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
  6676. $.datepicker._pos = null;
  6677. //to avoid flashes on Firefox
  6678. inst.dpDiv.empty();
  6679. // determine sizing offscreen
  6680. inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
  6681. $.datepicker._updateDatepicker( inst );
  6682. // fix width for dynamic number of date pickers
  6683. // and adjust position before showing
  6684. offset = $.datepicker._checkOffset( inst, offset, isFixed );
  6685. inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
  6686. "static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
  6687. left: offset.left + "px", top: offset.top + "px" } );
  6688. if ( !inst.inline ) {
  6689. showAnim = $.datepicker._get( inst, "showAnim" );
  6690. duration = $.datepicker._get( inst, "duration" );
  6691. inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
  6692. $.datepicker._datepickerShowing = true;
  6693. if ( $.effects && $.effects.effect[ showAnim ] ) {
  6694. inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
  6695. } else {
  6696. inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
  6697. }
  6698. if ( $.datepicker._shouldFocusInput( inst ) ) {
  6699. inst.input.trigger( "focus" );
  6700. }
  6701. $.datepicker._curInst = inst;
  6702. }
  6703. },
  6704. /* Generate the date picker content. */
  6705. _updateDatepicker: function( inst ) {
  6706. this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
  6707. datepicker_instActive = inst; // for delegate hover events
  6708. inst.dpDiv.empty().append( this._generateHTML( inst ) );
  6709. this._attachHandlers( inst );
  6710. var origyearshtml,
  6711. numMonths = this._getNumberOfMonths( inst ),
  6712. cols = numMonths[ 1 ],
  6713. width = 17,
  6714. activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
  6715. if ( activeCell.length > 0 ) {
  6716. datepicker_handleMouseover.apply( activeCell.get( 0 ) );
  6717. }
  6718. inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
  6719. if ( cols > 1 ) {
  6720. inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
  6721. }
  6722. inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
  6723. "Class" ]( "ui-datepicker-multi" );
  6724. inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
  6725. "Class" ]( "ui-datepicker-rtl" );
  6726. if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
  6727. inst.input.trigger( "focus" );
  6728. }
  6729. // Deffered render of the years select (to avoid flashes on Firefox)
  6730. if ( inst.yearshtml ) {
  6731. origyearshtml = inst.yearshtml;
  6732. setTimeout( function() {
  6733. //assure that inst.yearshtml didn't change.
  6734. if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
  6735. inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
  6736. }
  6737. origyearshtml = inst.yearshtml = null;
  6738. }, 0 );
  6739. }
  6740. },
  6741. // #6694 - don't focus the input if it's already focused
  6742. // this breaks the change event in IE
  6743. // Support: IE and jQuery <1.9
  6744. _shouldFocusInput: function( inst ) {
  6745. return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
  6746. },
  6747. /* Check positioning to remain on screen. */
  6748. _checkOffset: function( inst, offset, isFixed ) {
  6749. var dpWidth = inst.dpDiv.outerWidth(),
  6750. dpHeight = inst.dpDiv.outerHeight(),
  6751. inputWidth = inst.input ? inst.input.outerWidth() : 0,
  6752. inputHeight = inst.input ? inst.input.outerHeight() : 0,
  6753. viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
  6754. viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
  6755. offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
  6756. offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
  6757. offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
  6758. // Now check if datepicker is showing outside window viewport - move to a better place if so.
  6759. offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
  6760. Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
  6761. offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
  6762. Math.abs( dpHeight + inputHeight ) : 0 );
  6763. return offset;
  6764. },
  6765. /* Find an object's position on the screen. */
  6766. _findPos: function( obj ) {
  6767. var position,
  6768. inst = this._getInst( obj ),
  6769. isRTL = this._get( inst, "isRTL" );
  6770. while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
  6771. obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
  6772. }
  6773. position = $( obj ).offset();
  6774. return [ position.left, position.top ];
  6775. },
  6776. /* Hide the date picker from view.
  6777. * @param input element - the input field attached to the date picker
  6778. */
  6779. _hideDatepicker: function( input ) {
  6780. var showAnim, duration, postProcess, onClose,
  6781. inst = this._curInst;
  6782. if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
  6783. return;
  6784. }
  6785. if ( this._datepickerShowing ) {
  6786. showAnim = this._get( inst, "showAnim" );
  6787. duration = this._get( inst, "duration" );
  6788. postProcess = function() {
  6789. $.datepicker._tidyDialog( inst );
  6790. };
  6791. // DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
  6792. if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
  6793. inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
  6794. } else {
  6795. inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
  6796. ( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
  6797. }
  6798. if ( !showAnim ) {
  6799. postProcess();
  6800. }
  6801. this._datepickerShowing = false;
  6802. onClose = this._get( inst, "onClose" );
  6803. if ( onClose ) {
  6804. onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
  6805. }
  6806. this._lastInput = null;
  6807. if ( this._inDialog ) {
  6808. this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
  6809. if ( $.blockUI ) {
  6810. $.unblockUI();
  6811. $( "body" ).append( this.dpDiv );
  6812. }
  6813. }
  6814. this._inDialog = false;
  6815. }
  6816. },
  6817. /* Tidy up after a dialog display. */
  6818. _tidyDialog: function( inst ) {
  6819. inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
  6820. },
  6821. /* Close date picker if clicked elsewhere. */
  6822. _checkExternalClick: function( event ) {
  6823. if ( !$.datepicker._curInst ) {
  6824. return;
  6825. }
  6826. var $target = $( event.target ),
  6827. inst = $.datepicker._getInst( $target[ 0 ] );
  6828. if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
  6829. $target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
  6830. !$target.hasClass( $.datepicker.markerClassName ) &&
  6831. !$target.closest( "." + $.datepicker._triggerClass ).length &&
  6832. $.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
  6833. ( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
  6834. $.datepicker._hideDatepicker();
  6835. }
  6836. },
  6837. /* Adjust one of the date sub-fields. */
  6838. _adjustDate: function( id, offset, period ) {
  6839. var target = $( id ),
  6840. inst = this._getInst( target[ 0 ] );
  6841. if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
  6842. return;
  6843. }
  6844. this._adjustInstDate( inst, offset +
  6845. ( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
  6846. period );
  6847. this._updateDatepicker( inst );
  6848. },
  6849. /* Action for current link. */
  6850. _gotoToday: function( id ) {
  6851. var date,
  6852. target = $( id ),
  6853. inst = this._getInst( target[ 0 ] );
  6854. if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
  6855. inst.selectedDay = inst.currentDay;
  6856. inst.drawMonth = inst.selectedMonth = inst.currentMonth;
  6857. inst.drawYear = inst.selectedYear = inst.currentYear;
  6858. } else {
  6859. date = new Date();
  6860. inst.selectedDay = date.getDate();
  6861. inst.drawMonth = inst.selectedMonth = date.getMonth();
  6862. inst.drawYear = inst.selectedYear = date.getFullYear();
  6863. }
  6864. this._notifyChange( inst );
  6865. this._adjustDate( target );
  6866. },
  6867. /* Action for selecting a new month/year. */
  6868. _selectMonthYear: function( id, select, period ) {
  6869. var target = $( id ),
  6870. inst = this._getInst( target[ 0 ] );
  6871. inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
  6872. inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
  6873. parseInt( select.options[ select.selectedIndex ].value, 10 );
  6874. this._notifyChange( inst );
  6875. this._adjustDate( target );
  6876. },
  6877. /* Action for selecting a day. */
  6878. _selectDay: function( id, month, year, td ) {
  6879. var inst,
  6880. target = $( id );
  6881. if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
  6882. return;
  6883. }
  6884. inst = this._getInst( target[ 0 ] );
  6885. inst.selectedDay = inst.currentDay = $( "a", td ).html();
  6886. inst.selectedMonth = inst.currentMonth = month;
  6887. inst.selectedYear = inst.currentYear = year;
  6888. this._selectDate( id, this._formatDate( inst,
  6889. inst.currentDay, inst.currentMonth, inst.currentYear ) );
  6890. },
  6891. /* Erase the input field and hide the date picker. */
  6892. _clearDate: function( id ) {
  6893. var target = $( id );
  6894. this._selectDate( target, "" );
  6895. },
  6896. /* Update the input field with the selected date. */
  6897. _selectDate: function( id, dateStr ) {
  6898. var onSelect,
  6899. target = $( id ),
  6900. inst = this._getInst( target[ 0 ] );
  6901. dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
  6902. if ( inst.input ) {
  6903. inst.input.val( dateStr );
  6904. }
  6905. this._updateAlternate( inst );
  6906. onSelect = this._get( inst, "onSelect" );
  6907. if ( onSelect ) {
  6908. onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
  6909. } else if ( inst.input ) {
  6910. inst.input.trigger( "change" ); // fire the change event
  6911. }
  6912. if ( inst.inline ) {
  6913. this._updateDatepicker( inst );
  6914. } else {
  6915. this._hideDatepicker();
  6916. this._lastInput = inst.input[ 0 ];
  6917. if ( typeof( inst.input[ 0 ] ) !== "object" ) {
  6918. inst.input.trigger( "focus" ); // restore focus
  6919. }
  6920. this._lastInput = null;
  6921. }
  6922. },
  6923. /* Update any alternate field to synchronise with the main field. */
  6924. _updateAlternate: function( inst ) {
  6925. var altFormat, date, dateStr,
  6926. altField = this._get( inst, "altField" );
  6927. if ( altField ) { // update alternate field too
  6928. altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
  6929. date = this._getDate( inst );
  6930. dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
  6931. $( altField ).val( dateStr );
  6932. }
  6933. },
  6934. /* Set as beforeShowDay function to prevent selection of weekends.
  6935. * @param date Date - the date to customise
  6936. * @return [boolean, string] - is this date selectable?, what is its CSS class?
  6937. */
  6938. noWeekends: function( date ) {
  6939. var day = date.getDay();
  6940. return [ ( day > 0 && day < 6 ), "" ];
  6941. },
  6942. /* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
  6943. * @param date Date - the date to get the week for
  6944. * @return number - the number of the week within the year that contains this date
  6945. */
  6946. iso8601Week: function( date ) {
  6947. var time,
  6948. checkDate = new Date( date.getTime() );
  6949. // Find Thursday of this week starting on Monday
  6950. checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
  6951. time = checkDate.getTime();
  6952. checkDate.setMonth( 0 ); // Compare with Jan 1
  6953. checkDate.setDate( 1 );
  6954. return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
  6955. },
  6956. /* Parse a string value into a date object.
  6957. * See formatDate below for the possible formats.
  6958. *
  6959. * @param format string - the expected format of the date
  6960. * @param value string - the date in the above format
  6961. * @param settings Object - attributes include:
  6962. * shortYearCutoff number - the cutoff year for determining the century (optional)
  6963. * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
  6964. * dayNames string[7] - names of the days from Sunday (optional)
  6965. * monthNamesShort string[12] - abbreviated names of the months (optional)
  6966. * monthNames string[12] - names of the months (optional)
  6967. * @return Date - the extracted date value or null if value is blank
  6968. */
  6969. parseDate: function( format, value, settings ) {
  6970. if ( format == null || value == null ) {
  6971. throw "Invalid arguments";
  6972. }
  6973. value = ( typeof value === "object" ? value.toString() : value + "" );
  6974. if ( value === "" ) {
  6975. return null;
  6976. }
  6977. var iFormat, dim, extra,
  6978. iValue = 0,
  6979. shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
  6980. shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
  6981. new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
  6982. dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
  6983. dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
  6984. monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
  6985. monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
  6986. year = -1,
  6987. month = -1,
  6988. day = -1,
  6989. doy = -1,
  6990. literal = false,
  6991. date,
  6992. // Check whether a format character is doubled
  6993. lookAhead = function( match ) {
  6994. var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
  6995. if ( matches ) {
  6996. iFormat++;
  6997. }
  6998. return matches;
  6999. },
  7000. // Extract a number from the string value
  7001. getNumber = function( match ) {
  7002. var isDoubled = lookAhead( match ),
  7003. size = ( match === "@" ? 14 : ( match === "!" ? 20 :
  7004. ( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
  7005. minSize = ( match === "y" ? size : 1 ),
  7006. digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
  7007. num = value.substring( iValue ).match( digits );
  7008. if ( !num ) {
  7009. throw "Missing number at position " + iValue;
  7010. }
  7011. iValue += num[ 0 ].length;
  7012. return parseInt( num[ 0 ], 10 );
  7013. },
  7014. // Extract a name from the string value and convert to an index
  7015. getName = function( match, shortNames, longNames ) {
  7016. var index = -1,
  7017. names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
  7018. return [ [ k, v ] ];
  7019. } ).sort( function( a, b ) {
  7020. return -( a[ 1 ].length - b[ 1 ].length );
  7021. } );
  7022. $.each( names, function( i, pair ) {
  7023. var name = pair[ 1 ];
  7024. if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
  7025. index = pair[ 0 ];
  7026. iValue += name.length;
  7027. return false;
  7028. }
  7029. } );
  7030. if ( index !== -1 ) {
  7031. return index + 1;
  7032. } else {
  7033. throw "Unknown name at position " + iValue;
  7034. }
  7035. },
  7036. // Confirm that a literal character matches the string value
  7037. checkLiteral = function() {
  7038. if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
  7039. throw "Unexpected literal at position " + iValue;
  7040. }
  7041. iValue++;
  7042. };
  7043. for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
  7044. if ( literal ) {
  7045. if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
  7046. literal = false;
  7047. } else {
  7048. checkLiteral();
  7049. }
  7050. } else {
  7051. switch ( format.charAt( iFormat ) ) {
  7052. case "d":
  7053. day = getNumber( "d" );
  7054. break;
  7055. case "D":
  7056. getName( "D", dayNamesShort, dayNames );
  7057. break;
  7058. case "o":
  7059. doy = getNumber( "o" );
  7060. break;
  7061. case "m":
  7062. month = getNumber( "m" );
  7063. break;
  7064. case "M":
  7065. month = getName( "M", monthNamesShort, monthNames );
  7066. break;
  7067. case "y":
  7068. year = getNumber( "y" );
  7069. break;
  7070. case "@":
  7071. date = new Date( getNumber( "@" ) );
  7072. year = date.getFullYear();
  7073. month = date.getMonth() + 1;
  7074. day = date.getDate();
  7075. break;
  7076. case "!":
  7077. date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
  7078. year = date.getFullYear();
  7079. month = date.getMonth() + 1;
  7080. day = date.getDate();
  7081. break;
  7082. case "'":
  7083. if ( lookAhead( "'" ) ) {
  7084. checkLiteral();
  7085. } else {
  7086. literal = true;
  7087. }
  7088. break;
  7089. default:
  7090. checkLiteral();
  7091. }
  7092. }
  7093. }
  7094. if ( iValue < value.length ) {
  7095. extra = value.substr( iValue );
  7096. if ( !/^\s+/.test( extra ) ) {
  7097. throw "Extra/unparsed characters found in date: " + extra;
  7098. }
  7099. }
  7100. if ( year === -1 ) {
  7101. year = new Date().getFullYear();
  7102. } else if ( year < 100 ) {
  7103. year += new Date().getFullYear() - new Date().getFullYear() % 100 +
  7104. ( year <= shortYearCutoff ? 0 : -100 );
  7105. }
  7106. if ( doy > -1 ) {
  7107. month = 1;
  7108. day = doy;
  7109. do {
  7110. dim = this._getDaysInMonth( year, month - 1 );
  7111. if ( day <= dim ) {
  7112. break;
  7113. }
  7114. month++;
  7115. day -= dim;
  7116. } while ( true );
  7117. }
  7118. date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
  7119. if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
  7120. throw "Invalid date"; // E.g. 31/02/00
  7121. }
  7122. return date;
  7123. },
  7124. /* Standard date formats. */
  7125. ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
  7126. COOKIE: "D, dd M yy",
  7127. ISO_8601: "yy-mm-dd",
  7128. RFC_822: "D, d M y",
  7129. RFC_850: "DD, dd-M-y",
  7130. RFC_1036: "D, d M y",
  7131. RFC_1123: "D, d M yy",
  7132. RFC_2822: "D, d M yy",
  7133. RSS: "D, d M y", // RFC 822
  7134. TICKS: "!",
  7135. TIMESTAMP: "@",
  7136. W3C: "yy-mm-dd", // ISO 8601
  7137. _ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
  7138. Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
  7139. /* Format a date object into a string value.
  7140. * The format can be combinations of the following:
  7141. * d - day of month (no leading zero)
  7142. * dd - day of month (two digit)
  7143. * o - day of year (no leading zeros)
  7144. * oo - day of year (three digit)
  7145. * D - day name short
  7146. * DD - day name long
  7147. * m - month of year (no leading zero)
  7148. * mm - month of year (two digit)
  7149. * M - month name short
  7150. * MM - month name long
  7151. * y - year (two digit)
  7152. * yy - year (four digit)
  7153. * @ - Unix timestamp (ms since 01/01/1970)
  7154. * ! - Windows ticks (100ns since 01/01/0001)
  7155. * "..." - literal text
  7156. * '' - single quote
  7157. *
  7158. * @param format string - the desired format of the date
  7159. * @param date Date - the date value to format
  7160. * @param settings Object - attributes include:
  7161. * dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
  7162. * dayNames string[7] - names of the days from Sunday (optional)
  7163. * monthNamesShort string[12] - abbreviated names of the months (optional)
  7164. * monthNames string[12] - names of the months (optional)
  7165. * @return string - the date in the above format
  7166. */
  7167. formatDate: function( format, date, settings ) {
  7168. if ( !date ) {
  7169. return "";
  7170. }
  7171. var iFormat,
  7172. dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
  7173. dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
  7174. monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
  7175. monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
  7176. // Check whether a format character is doubled
  7177. lookAhead = function( match ) {
  7178. var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
  7179. if ( matches ) {
  7180. iFormat++;
  7181. }
  7182. return matches;
  7183. },
  7184. // Format a number, with leading zero if necessary
  7185. formatNumber = function( match, value, len ) {
  7186. var num = "" + value;
  7187. if ( lookAhead( match ) ) {
  7188. while ( num.length < len ) {
  7189. num = "0" + num;
  7190. }
  7191. }
  7192. return num;
  7193. },
  7194. // Format a name, short or long as requested
  7195. formatName = function( match, value, shortNames, longNames ) {
  7196. return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
  7197. },
  7198. output = "",
  7199. literal = false;
  7200. if ( date ) {
  7201. for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
  7202. if ( literal ) {
  7203. if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
  7204. literal = false;
  7205. } else {
  7206. output += format.charAt( iFormat );
  7207. }
  7208. } else {
  7209. switch ( format.charAt( iFormat ) ) {
  7210. case "d":
  7211. output += formatNumber( "d", date.getDate(), 2 );
  7212. break;
  7213. case "D":
  7214. output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
  7215. break;
  7216. case "o":
  7217. output += formatNumber( "o",
  7218. Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
  7219. break;
  7220. case "m":
  7221. output += formatNumber( "m", date.getMonth() + 1, 2 );
  7222. break;
  7223. case "M":
  7224. output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
  7225. break;
  7226. case "y":
  7227. output += ( lookAhead( "y" ) ? date.getFullYear() :
  7228. ( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
  7229. break;
  7230. case "@":
  7231. output += date.getTime();
  7232. break;
  7233. case "!":
  7234. output += date.getTime() * 10000 + this._ticksTo1970;
  7235. break;
  7236. case "'":
  7237. if ( lookAhead( "'" ) ) {
  7238. output += "'";
  7239. } else {
  7240. literal = true;
  7241. }
  7242. break;
  7243. default:
  7244. output += format.charAt( iFormat );
  7245. }
  7246. }
  7247. }
  7248. }
  7249. return output;
  7250. },
  7251. /* Extract all possible characters from the date format. */
  7252. _possibleChars: function( format ) {
  7253. var iFormat,
  7254. chars = "",
  7255. literal = false,
  7256. // Check whether a format character is doubled
  7257. lookAhead = function( match ) {
  7258. var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
  7259. if ( matches ) {
  7260. iFormat++;
  7261. }
  7262. return matches;
  7263. };
  7264. for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
  7265. if ( literal ) {
  7266. if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
  7267. literal = false;
  7268. } else {
  7269. chars += format.charAt( iFormat );
  7270. }
  7271. } else {
  7272. switch ( format.charAt( iFormat ) ) {
  7273. case "d": case "m": case "y": case "@":
  7274. chars += "0123456789";
  7275. break;
  7276. case "D": case "M":
  7277. return null; // Accept anything
  7278. case "'":
  7279. if ( lookAhead( "'" ) ) {
  7280. chars += "'";
  7281. } else {
  7282. literal = true;
  7283. }
  7284. break;
  7285. default:
  7286. chars += format.charAt( iFormat );
  7287. }
  7288. }
  7289. }
  7290. return chars;
  7291. },
  7292. /* Get a setting value, defaulting if necessary. */
  7293. _get: function( inst, name ) {
  7294. return inst.settings[ name ] !== undefined ?
  7295. inst.settings[ name ] : this._defaults[ name ];
  7296. },
  7297. /* Parse existing date and initialise date picker. */
  7298. _setDateFromField: function( inst, noDefault ) {
  7299. if ( inst.input.val() === inst.lastVal ) {
  7300. return;
  7301. }
  7302. var dateFormat = this._get( inst, "dateFormat" ),
  7303. dates = inst.lastVal = inst.input ? inst.input.val() : null,
  7304. defaultDate = this._getDefaultDate( inst ),
  7305. date = defaultDate,
  7306. settings = this._getFormatConfig( inst );
  7307. try {
  7308. date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
  7309. } catch ( event ) {
  7310. dates = ( noDefault ? "" : dates );
  7311. }
  7312. inst.selectedDay = date.getDate();
  7313. inst.drawMonth = inst.selectedMonth = date.getMonth();
  7314. inst.drawYear = inst.selectedYear = date.getFullYear();
  7315. inst.currentDay = ( dates ? date.getDate() : 0 );
  7316. inst.currentMonth = ( dates ? date.getMonth() : 0 );
  7317. inst.currentYear = ( dates ? date.getFullYear() : 0 );
  7318. this._adjustInstDate( inst );
  7319. },
  7320. /* Retrieve the default date shown on opening. */
  7321. _getDefaultDate: function( inst ) {
  7322. return this._restrictMinMax( inst,
  7323. this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
  7324. },
  7325. /* A date may be specified as an exact value or a relative one. */
  7326. _determineDate: function( inst, date, defaultDate ) {
  7327. var offsetNumeric = function( offset ) {
  7328. var date = new Date();
  7329. date.setDate( date.getDate() + offset );
  7330. return date;
  7331. },
  7332. offsetString = function( offset ) {
  7333. try {
  7334. return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
  7335. offset, $.datepicker._getFormatConfig( inst ) );
  7336. }
  7337. catch ( e ) {
  7338. // Ignore
  7339. }
  7340. var date = ( offset.toLowerCase().match( /^c/ ) ?
  7341. $.datepicker._getDate( inst ) : null ) || new Date(),
  7342. year = date.getFullYear(),
  7343. month = date.getMonth(),
  7344. day = date.getDate(),
  7345. pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
  7346. matches = pattern.exec( offset );
  7347. while ( matches ) {
  7348. switch ( matches[ 2 ] || "d" ) {
  7349. case "d" : case "D" :
  7350. day += parseInt( matches[ 1 ], 10 ); break;
  7351. case "w" : case "W" :
  7352. day += parseInt( matches[ 1 ], 10 ) * 7; break;
  7353. case "m" : case "M" :
  7354. month += parseInt( matches[ 1 ], 10 );
  7355. day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
  7356. break;
  7357. case "y": case "Y" :
  7358. year += parseInt( matches[ 1 ], 10 );
  7359. day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
  7360. break;
  7361. }
  7362. matches = pattern.exec( offset );
  7363. }
  7364. return new Date( year, month, day );
  7365. },
  7366. newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
  7367. ( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
  7368. newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
  7369. if ( newDate ) {
  7370. newDate.setHours( 0 );
  7371. newDate.setMinutes( 0 );
  7372. newDate.setSeconds( 0 );
  7373. newDate.setMilliseconds( 0 );
  7374. }
  7375. return this._daylightSavingAdjust( newDate );
  7376. },
  7377. /* Handle switch to/from daylight saving.
  7378. * Hours may be non-zero on daylight saving cut-over:
  7379. * > 12 when midnight changeover, but then cannot generate
  7380. * midnight datetime, so jump to 1AM, otherwise reset.
  7381. * @param date (Date) the date to check
  7382. * @return (Date) the corrected date
  7383. */
  7384. _daylightSavingAdjust: function( date ) {
  7385. if ( !date ) {
  7386. return null;
  7387. }
  7388. date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
  7389. return date;
  7390. },
  7391. /* Set the date(s) directly. */
  7392. _setDate: function( inst, date, noChange ) {
  7393. var clear = !date,
  7394. origMonth = inst.selectedMonth,
  7395. origYear = inst.selectedYear,
  7396. newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
  7397. inst.selectedDay = inst.currentDay = newDate.getDate();
  7398. inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
  7399. inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
  7400. if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
  7401. this._notifyChange( inst );
  7402. }
  7403. this._adjustInstDate( inst );
  7404. if ( inst.input ) {
  7405. inst.input.val( clear ? "" : this._formatDate( inst ) );
  7406. }
  7407. },
  7408. /* Retrieve the date(s) directly. */
  7409. _getDate: function( inst ) {
  7410. var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
  7411. this._daylightSavingAdjust( new Date(
  7412. inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
  7413. return startDate;
  7414. },
  7415. /* Attach the onxxx handlers. These are declared statically so
  7416. * they work with static code transformers like Caja.
  7417. */
  7418. _attachHandlers: function( inst ) {
  7419. var stepMonths = this._get( inst, "stepMonths" ),
  7420. id = "#" + inst.id.replace( /\\\\/g, "\\" );
  7421. inst.dpDiv.find( "[data-handler]" ).map( function() {
  7422. var handler = {
  7423. prev: function() {
  7424. $.datepicker._adjustDate( id, -stepMonths, "M" );
  7425. },
  7426. next: function() {
  7427. $.datepicker._adjustDate( id, +stepMonths, "M" );
  7428. },
  7429. hide: function() {
  7430. $.datepicker._hideDatepicker();
  7431. },
  7432. today: function() {
  7433. $.datepicker._gotoToday( id );
  7434. },
  7435. selectDay: function() {
  7436. $.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
  7437. return false;
  7438. },
  7439. selectMonth: function() {
  7440. $.datepicker._selectMonthYear( id, this, "M" );
  7441. return false;
  7442. },
  7443. selectYear: function() {
  7444. $.datepicker._selectMonthYear( id, this, "Y" );
  7445. return false;
  7446. }
  7447. };
  7448. $( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
  7449. } );
  7450. },
  7451. /* Generate the HTML for the current state of the date picker. */
  7452. _generateHTML: function( inst ) {
  7453. var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
  7454. controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
  7455. monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
  7456. selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
  7457. cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
  7458. printDate, dRow, tbody, daySettings, otherMonth, unselectable,
  7459. tempDate = new Date(),
  7460. today = this._daylightSavingAdjust(
  7461. new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
  7462. isRTL = this._get( inst, "isRTL" ),
  7463. showButtonPanel = this._get( inst, "showButtonPanel" ),
  7464. hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
  7465. navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
  7466. numMonths = this._getNumberOfMonths( inst ),
  7467. showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
  7468. stepMonths = this._get( inst, "stepMonths" ),
  7469. isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
  7470. currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
  7471. new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
  7472. minDate = this._getMinMaxDate( inst, "min" ),
  7473. maxDate = this._getMinMaxDate( inst, "max" ),
  7474. drawMonth = inst.drawMonth - showCurrentAtPos,
  7475. drawYear = inst.drawYear;
  7476. if ( drawMonth < 0 ) {
  7477. drawMonth += 12;
  7478. drawYear--;
  7479. }
  7480. if ( maxDate ) {
  7481. maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
  7482. maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
  7483. maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
  7484. while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
  7485. drawMonth--;
  7486. if ( drawMonth < 0 ) {
  7487. drawMonth = 11;
  7488. drawYear--;
  7489. }
  7490. }
  7491. }
  7492. inst.drawMonth = drawMonth;
  7493. inst.drawYear = drawYear;
  7494. prevText = this._get( inst, "prevText" );
  7495. prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
  7496. this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
  7497. this._getFormatConfig( inst ) ) );
  7498. prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
  7499. "<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
  7500. " title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
  7501. ( 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>" ) );
  7502. nextText = this._get( inst, "nextText" );
  7503. nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
  7504. this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
  7505. this._getFormatConfig( inst ) ) );
  7506. next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
  7507. "<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
  7508. " title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
  7509. ( 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>" ) );
  7510. currentText = this._get( inst, "currentText" );
  7511. gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
  7512. currentText = ( !navigationAsDateFormat ? currentText :
  7513. this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
  7514. 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'>" +
  7515. this._get( inst, "closeText" ) + "</button>" : "" );
  7516. buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
  7517. ( 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'" +
  7518. ">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
  7519. firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
  7520. firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
  7521. showWeek = this._get( inst, "showWeek" );
  7522. dayNames = this._get( inst, "dayNames" );
  7523. dayNamesMin = this._get( inst, "dayNamesMin" );
  7524. monthNames = this._get( inst, "monthNames" );
  7525. monthNamesShort = this._get( inst, "monthNamesShort" );
  7526. beforeShowDay = this._get( inst, "beforeShowDay" );
  7527. showOtherMonths = this._get( inst, "showOtherMonths" );
  7528. selectOtherMonths = this._get( inst, "selectOtherMonths" );
  7529. defaultDate = this._getDefaultDate( inst );
  7530. html = "";
  7531. for ( row = 0; row < numMonths[ 0 ]; row++ ) {
  7532. group = "";
  7533. this.maxRows = 4;
  7534. for ( col = 0; col < numMonths[ 1 ]; col++ ) {
  7535. selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
  7536. cornerClass = " ui-corner-all";
  7537. calender = "";
  7538. if ( isMultiMonth ) {
  7539. calender += "<div class='ui-datepicker-group";
  7540. if ( numMonths[ 1 ] > 1 ) {
  7541. switch ( col ) {
  7542. case 0: calender += " ui-datepicker-group-first";
  7543. cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
  7544. case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
  7545. cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
  7546. default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
  7547. }
  7548. }
  7549. calender += "'>";
  7550. }
  7551. calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
  7552. ( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
  7553. ( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
  7554. this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
  7555. row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
  7556. "</div><table class='ui-datepicker-calendar'><thead>" +
  7557. "<tr>";
  7558. thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
  7559. for ( dow = 0; dow < 7; dow++ ) { // days of the week
  7560. day = ( dow + firstDay ) % 7;
  7561. thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
  7562. "<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
  7563. }
  7564. calender += thead + "</tr></thead><tbody>";
  7565. daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
  7566. if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
  7567. inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
  7568. }
  7569. leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
  7570. curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
  7571. numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
  7572. this.maxRows = numRows;
  7573. printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
  7574. for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
  7575. calender += "<tr>";
  7576. tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
  7577. this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
  7578. for ( dow = 0; dow < 7; dow++ ) { // create date picker days
  7579. daySettings = ( beforeShowDay ?
  7580. beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
  7581. otherMonth = ( printDate.getMonth() !== drawMonth );
  7582. unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
  7583. ( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
  7584. tbody += "<td class='" +
  7585. ( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
  7586. ( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
  7587. ( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
  7588. ( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
  7589. // or defaultDate is current printedDate and defaultDate is selectedDate
  7590. " " + this._dayOverClass : "" ) + // highlight selected day
  7591. ( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
  7592. ( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
  7593. ( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
  7594. ( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
  7595. ( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "&#39;" ) + "'" : "" ) + // cell title
  7596. ( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
  7597. ( otherMonth && !showOtherMonths ? "&#xa0;" : // display for other months
  7598. ( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
  7599. ( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
  7600. ( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
  7601. ( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
  7602. "' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
  7603. printDate.setDate( printDate.getDate() + 1 );
  7604. printDate = this._daylightSavingAdjust( printDate );
  7605. }
  7606. calender += tbody + "</tr>";
  7607. }
  7608. drawMonth++;
  7609. if ( drawMonth > 11 ) {
  7610. drawMonth = 0;
  7611. drawYear++;
  7612. }
  7613. calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
  7614. ( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
  7615. group += calender;
  7616. }
  7617. html += group;
  7618. }
  7619. html += buttonPanel;
  7620. inst._keyEvent = false;
  7621. return html;
  7622. },
  7623. /* Generate the month and year header. */
  7624. _generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
  7625. secondary, monthNames, monthNamesShort ) {
  7626. var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
  7627. changeMonth = this._get( inst, "changeMonth" ),
  7628. changeYear = this._get( inst, "changeYear" ),
  7629. showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
  7630. html = "<div class='ui-datepicker-title'>",
  7631. monthHtml = "";
  7632. // Month selection
  7633. if ( secondary || !changeMonth ) {
  7634. monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
  7635. } else {
  7636. inMinYear = ( minDate && minDate.getFullYear() === drawYear );
  7637. inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
  7638. monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
  7639. for ( month = 0; month < 12; month++ ) {
  7640. if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
  7641. monthHtml += "<option value='" + month + "'" +
  7642. ( month === drawMonth ? " selected='selected'" : "" ) +
  7643. ">" + monthNamesShort[ month ] + "</option>";
  7644. }
  7645. }
  7646. monthHtml += "</select>";
  7647. }
  7648. if ( !showMonthAfterYear ) {
  7649. html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" );
  7650. }
  7651. // Year selection
  7652. if ( !inst.yearshtml ) {
  7653. inst.yearshtml = "";
  7654. if ( secondary || !changeYear ) {
  7655. html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
  7656. } else {
  7657. // determine range of years to display
  7658. years = this._get( inst, "yearRange" ).split( ":" );
  7659. thisYear = new Date().getFullYear();
  7660. determineYear = function( value ) {
  7661. var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
  7662. ( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
  7663. parseInt( value, 10 ) ) );
  7664. return ( isNaN( year ) ? thisYear : year );
  7665. };
  7666. year = determineYear( years[ 0 ] );
  7667. endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
  7668. year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
  7669. endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
  7670. inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
  7671. for ( ; year <= endYear; year++ ) {
  7672. inst.yearshtml += "<option value='" + year + "'" +
  7673. ( year === drawYear ? " selected='selected'" : "" ) +
  7674. ">" + year + "</option>";
  7675. }
  7676. inst.yearshtml += "</select>";
  7677. html += inst.yearshtml;
  7678. inst.yearshtml = null;
  7679. }
  7680. }
  7681. html += this._get( inst, "yearSuffix" );
  7682. if ( showMonthAfterYear ) {
  7683. html += ( secondary || !( changeMonth && changeYear ) ? "&#xa0;" : "" ) + monthHtml;
  7684. }
  7685. html += "</div>"; // Close datepicker_header
  7686. return html;
  7687. },
  7688. /* Adjust one of the date sub-fields. */
  7689. _adjustInstDate: function( inst, offset, period ) {
  7690. var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
  7691. month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
  7692. day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
  7693. date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
  7694. inst.selectedDay = date.getDate();
  7695. inst.drawMonth = inst.selectedMonth = date.getMonth();
  7696. inst.drawYear = inst.selectedYear = date.getFullYear();
  7697. if ( period === "M" || period === "Y" ) {
  7698. this._notifyChange( inst );
  7699. }
  7700. },
  7701. /* Ensure a date is within any min/max bounds. */
  7702. _restrictMinMax: function( inst, date ) {
  7703. var minDate = this._getMinMaxDate( inst, "min" ),
  7704. maxDate = this._getMinMaxDate( inst, "max" ),
  7705. newDate = ( minDate && date < minDate ? minDate : date );
  7706. return ( maxDate && newDate > maxDate ? maxDate : newDate );
  7707. },
  7708. /* Notify change of month/year. */
  7709. _notifyChange: function( inst ) {
  7710. var onChange = this._get( inst, "onChangeMonthYear" );
  7711. if ( onChange ) {
  7712. onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
  7713. [ inst.selectedYear, inst.selectedMonth + 1, inst ] );
  7714. }
  7715. },
  7716. /* Determine the number of months to show. */
  7717. _getNumberOfMonths: function( inst ) {
  7718. var numMonths = this._get( inst, "numberOfMonths" );
  7719. return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
  7720. },
  7721. /* Determine the current maximum date - ensure no time components are set. */
  7722. _getMinMaxDate: function( inst, minMax ) {
  7723. return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
  7724. },
  7725. /* Find the number of days in a given month. */
  7726. _getDaysInMonth: function( year, month ) {
  7727. return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
  7728. },
  7729. /* Find the day of the week of the first of a month. */
  7730. _getFirstDayOfMonth: function( year, month ) {
  7731. return new Date( year, month, 1 ).getDay();
  7732. },
  7733. /* Determines if we should allow a "next/prev" month display change. */
  7734. _canAdjustMonth: function( inst, offset, curYear, curMonth ) {
  7735. var numMonths = this._getNumberOfMonths( inst ),
  7736. date = this._daylightSavingAdjust( new Date( curYear,
  7737. curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
  7738. if ( offset < 0 ) {
  7739. date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
  7740. }
  7741. return this._isInRange( inst, date );
  7742. },
  7743. /* Is the given date in the accepted range? */
  7744. _isInRange: function( inst, date ) {
  7745. var yearSplit, currentYear,
  7746. minDate = this._getMinMaxDate( inst, "min" ),
  7747. maxDate = this._getMinMaxDate( inst, "max" ),
  7748. minYear = null,
  7749. maxYear = null,
  7750. years = this._get( inst, "yearRange" );
  7751. if ( years ) {
  7752. yearSplit = years.split( ":" );
  7753. currentYear = new Date().getFullYear();
  7754. minYear = parseInt( yearSplit[ 0 ], 10 );
  7755. maxYear = parseInt( yearSplit[ 1 ], 10 );
  7756. if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
  7757. minYear += currentYear;
  7758. }
  7759. if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
  7760. maxYear += currentYear;
  7761. }
  7762. }
  7763. return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
  7764. ( !maxDate || date.getTime() <= maxDate.getTime() ) &&
  7765. ( !minYear || date.getFullYear() >= minYear ) &&
  7766. ( !maxYear || date.getFullYear() <= maxYear ) );
  7767. },
  7768. /* Provide the configuration settings for formatting/parsing. */
  7769. _getFormatConfig: function( inst ) {
  7770. var shortYearCutoff = this._get( inst, "shortYearCutoff" );
  7771. shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
  7772. new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
  7773. return { shortYearCutoff: shortYearCutoff,
  7774. dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
  7775. monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
  7776. },
  7777. /* Format the given date for display. */
  7778. _formatDate: function( inst, day, month, year ) {
  7779. if ( !day ) {
  7780. inst.currentDay = inst.selectedDay;
  7781. inst.currentMonth = inst.selectedMonth;
  7782. inst.currentYear = inst.selectedYear;
  7783. }
  7784. var date = ( day ? ( typeof day === "object" ? day :
  7785. this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
  7786. this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
  7787. return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
  7788. }
  7789. } );
  7790. /*
  7791. * Bind hover events for datepicker elements.
  7792. * Done via delegate so the binding only occurs once in the lifetime of the parent div.
  7793. * Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
  7794. */
  7795. function datepicker_bindHover( dpDiv ) {
  7796. var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
  7797. return dpDiv.on( "mouseout", selector, function() {
  7798. $( this ).removeClass( "ui-state-hover" );
  7799. if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
  7800. $( this ).removeClass( "ui-datepicker-prev-hover" );
  7801. }
  7802. if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
  7803. $( this ).removeClass( "ui-datepicker-next-hover" );
  7804. }
  7805. } )
  7806. .on( "mouseover", selector, datepicker_handleMouseover );
  7807. }
  7808. function datepicker_handleMouseover() {
  7809. if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
  7810. $( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
  7811. $( this ).addClass( "ui-state-hover" );
  7812. if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
  7813. $( this ).addClass( "ui-datepicker-prev-hover" );
  7814. }
  7815. if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
  7816. $( this ).addClass( "ui-datepicker-next-hover" );
  7817. }
  7818. }
  7819. }
  7820. /* jQuery extend now ignores nulls! */
  7821. function datepicker_extendRemove( target, props ) {
  7822. $.extend( target, props );
  7823. for ( var name in props ) {
  7824. if ( props[ name ] == null ) {
  7825. target[ name ] = props[ name ];
  7826. }
  7827. }
  7828. return target;
  7829. }
  7830. /* Invoke the datepicker functionality.
  7831. @param options string - a command, optionally followed by additional parameters or
  7832. Object - settings for attaching new datepicker functionality
  7833. @return jQuery object */
  7834. $.fn.datepicker = function( options ) {
  7835. /* Verify an empty collection wasn't passed - Fixes #6976 */
  7836. if ( !this.length ) {
  7837. return this;
  7838. }
  7839. /* Initialise the date picker. */
  7840. if ( !$.datepicker.initialized ) {
  7841. $( document ).on( "mousedown", $.datepicker._checkExternalClick );
  7842. $.datepicker.initialized = true;
  7843. }
  7844. /* Append datepicker main container to body if not exist. */
  7845. if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
  7846. $( "body" ).append( $.datepicker.dpDiv );
  7847. }
  7848. var otherArgs = Array.prototype.slice.call( arguments, 1 );
  7849. if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
  7850. return $.datepicker[ "_" + options + "Datepicker" ].
  7851. apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
  7852. }
  7853. if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
  7854. return $.datepicker[ "_" + options + "Datepicker" ].
  7855. apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
  7856. }
  7857. return this.each( function() {
  7858. typeof options === "string" ?
  7859. $.datepicker[ "_" + options + "Datepicker" ].
  7860. apply( $.datepicker, [ this ].concat( otherArgs ) ) :
  7861. $.datepicker._attachDatepicker( this, options );
  7862. } );
  7863. };
  7864. $.datepicker = new Datepicker(); // singleton instance
  7865. $.datepicker.initialized = false;
  7866. $.datepicker.uuid = new Date().getTime();
  7867. $.datepicker.version = "1.12.1";
  7868. var widgetsDatepicker = $.datepicker;
  7869. // This file is deprecated
  7870. var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
  7871. /*!
  7872. * jQuery UI Mouse 1.12.1
  7873. * http://jqueryui.com
  7874. *
  7875. * Copyright jQuery Foundation and other contributors
  7876. * Released under the MIT license.
  7877. * http://jquery.org/license
  7878. */
  7879. //>>label: Mouse
  7880. //>>group: Widgets
  7881. //>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
  7882. //>>docs: http://api.jqueryui.com/mouse/
  7883. var mouseHandled = false;
  7884. $( document ).on( "mouseup", function() {
  7885. mouseHandled = false;
  7886. } );
  7887. var widgetsMouse = $.widget( "ui.mouse", {
  7888. version: "1.12.1",
  7889. options: {
  7890. cancel: "input, textarea, button, select, option",
  7891. distance: 1,
  7892. delay: 0
  7893. },
  7894. _mouseInit: function() {
  7895. var that = this;
  7896. this.element
  7897. .on( "mousedown." + this.widgetName, function( event ) {
  7898. return that._mouseDown( event );
  7899. } )
  7900. .on( "click." + this.widgetName, function( event ) {
  7901. if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
  7902. $.removeData( event.target, that.widgetName + ".preventClickEvent" );
  7903. event.stopImmediatePropagation();
  7904. return false;
  7905. }
  7906. } );
  7907. this.started = false;
  7908. },
  7909. // TODO: make sure destroying one instance of mouse doesn't mess with
  7910. // other instances of mouse
  7911. _mouseDestroy: function() {
  7912. this.element.off( "." + this.widgetName );
  7913. if ( this._mouseMoveDelegate ) {
  7914. this.document
  7915. .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
  7916. .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
  7917. }
  7918. },
  7919. _mouseDown: function( event ) {
  7920. // don't let more than one widget handle mouseStart
  7921. if ( mouseHandled ) {
  7922. return;
  7923. }
  7924. this._mouseMoved = false;
  7925. // We may have missed mouseup (out of window)
  7926. ( this._mouseStarted && this._mouseUp( event ) );
  7927. this._mouseDownEvent = event;
  7928. var that = this,
  7929. btnIsLeft = ( event.which === 1 ),
  7930. // event.target.nodeName works around a bug in IE 8 with
  7931. // disabled inputs (#7620)
  7932. elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
  7933. $( event.target ).closest( this.options.cancel ).length : false );
  7934. if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
  7935. return true;
  7936. }
  7937. this.mouseDelayMet = !this.options.delay;
  7938. if ( !this.mouseDelayMet ) {
  7939. this._mouseDelayTimer = setTimeout( function() {
  7940. that.mouseDelayMet = true;
  7941. }, this.options.delay );
  7942. }
  7943. if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
  7944. this._mouseStarted = ( this._mouseStart( event ) !== false );
  7945. if ( !this._mouseStarted ) {
  7946. event.preventDefault();
  7947. return true;
  7948. }
  7949. }
  7950. // Click event may never have fired (Gecko & Opera)
  7951. if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
  7952. $.removeData( event.target, this.widgetName + ".preventClickEvent" );
  7953. }
  7954. // These delegates are required to keep context
  7955. this._mouseMoveDelegate = function( event ) {
  7956. return that._mouseMove( event );
  7957. };
  7958. this._mouseUpDelegate = function( event ) {
  7959. return that._mouseUp( event );
  7960. };
  7961. this.document
  7962. .on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
  7963. .on( "mouseup." + this.widgetName, this._mouseUpDelegate );
  7964. event.preventDefault();
  7965. mouseHandled = true;
  7966. return true;
  7967. },
  7968. _mouseMove: function( event ) {
  7969. // Only check for mouseups outside the document if you've moved inside the document
  7970. // at least once. This prevents the firing of mouseup in the case of IE<9, which will
  7971. // fire a mousemove event if content is placed under the cursor. See #7778
  7972. // Support: IE <9
  7973. if ( this._mouseMoved ) {
  7974. // IE mouseup check - mouseup happened when mouse was out of window
  7975. if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
  7976. !event.button ) {
  7977. return this._mouseUp( event );
  7978. // Iframe mouseup check - mouseup occurred in another document
  7979. } else if ( !event.which ) {
  7980. // Support: Safari <=8 - 9
  7981. // Safari sets which to 0 if you press any of the following keys
  7982. // during a drag (#14461)
  7983. if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
  7984. event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
  7985. this.ignoreMissingWhich = true;
  7986. } else if ( !this.ignoreMissingWhich ) {
  7987. return this._mouseUp( event );
  7988. }
  7989. }
  7990. }
  7991. if ( event.which || event.button ) {
  7992. this._mouseMoved = true;
  7993. }
  7994. if ( this._mouseStarted ) {
  7995. this._mouseDrag( event );
  7996. return event.preventDefault();
  7997. }
  7998. if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
  7999. this._mouseStarted =
  8000. ( this._mouseStart( this._mouseDownEvent, event ) !== false );
  8001. ( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
  8002. }
  8003. return !this._mouseStarted;
  8004. },
  8005. _mouseUp: function( event ) {
  8006. this.document
  8007. .off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
  8008. .off( "mouseup." + this.widgetName, this._mouseUpDelegate );
  8009. if ( this._mouseStarted ) {
  8010. this._mouseStarted = false;
  8011. if ( event.target === this._mouseDownEvent.target ) {
  8012. $.data( event.target, this.widgetName + ".preventClickEvent", true );
  8013. }
  8014. this._mouseStop( event );
  8015. }
  8016. if ( this._mouseDelayTimer ) {
  8017. clearTimeout( this._mouseDelayTimer );
  8018. delete this._mouseDelayTimer;
  8019. }
  8020. this.ignoreMissingWhich = false;
  8021. mouseHandled = false;
  8022. event.preventDefault();
  8023. },
  8024. _mouseDistanceMet: function( event ) {
  8025. return ( Math.max(
  8026. Math.abs( this._mouseDownEvent.pageX - event.pageX ),
  8027. Math.abs( this._mouseDownEvent.pageY - event.pageY )
  8028. ) >= this.options.distance
  8029. );
  8030. },
  8031. _mouseDelayMet: function( /* event */ ) {
  8032. return this.mouseDelayMet;
  8033. },
  8034. // These are placeholder methods, to be overriden by extending plugin
  8035. _mouseStart: function( /* event */ ) {},
  8036. _mouseDrag: function( /* event */ ) {},
  8037. _mouseStop: function( /* event */ ) {},
  8038. _mouseCapture: function( /* event */ ) { return true; }
  8039. } );
  8040. // $.ui.plugin is deprecated. Use $.widget() extensions instead.
  8041. var plugin = $.ui.plugin = {
  8042. add: function( module, option, set ) {
  8043. var i,
  8044. proto = $.ui[ module ].prototype;
  8045. for ( i in set ) {
  8046. proto.plugins[ i ] = proto.plugins[ i ] || [];
  8047. proto.plugins[ i ].push( [ option, set[ i ] ] );
  8048. }
  8049. },
  8050. call: function( instance, name, args, allowDisconnected ) {
  8051. var i,
  8052. set = instance.plugins[ name ];
  8053. if ( !set ) {
  8054. return;
  8055. }
  8056. if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
  8057. instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
  8058. return;
  8059. }
  8060. for ( i = 0; i < set.length; i++ ) {
  8061. if ( instance.options[ set[ i ][ 0 ] ] ) {
  8062. set[ i ][ 1 ].apply( instance.element, args );
  8063. }
  8064. }
  8065. }
  8066. };
  8067. var safeBlur = $.ui.safeBlur = function( element ) {
  8068. // Support: IE9 - 10 only
  8069. // If the <body> is blurred, IE will switch windows, see #9420
  8070. if ( element && element.nodeName.toLowerCase() !== "body" ) {
  8071. $( element ).trigger( "blur" );
  8072. }
  8073. };
  8074. /*!
  8075. * jQuery UI Draggable 1.12.1
  8076. * http://jqueryui.com
  8077. *
  8078. * Copyright jQuery Foundation and other contributors
  8079. * Released under the MIT license.
  8080. * http://jquery.org/license
  8081. */
  8082. //>>label: Draggable
  8083. //>>group: Interactions
  8084. //>>description: Enables dragging functionality for any element.
  8085. //>>docs: http://api.jqueryui.com/draggable/
  8086. //>>demos: http://jqueryui.com/draggable/
  8087. //>>css.structure: ../../themes/base/draggable.css
  8088. $.widget( "ui.draggable", $.ui.mouse, {
  8089. version: "1.12.1",
  8090. widgetEventPrefix: "drag",
  8091. options: {
  8092. addClasses: true,
  8093. appendTo: "parent",
  8094. axis: false,
  8095. connectToSortable: false,
  8096. containment: false,
  8097. cursor: "auto",
  8098. cursorAt: false,
  8099. grid: false,
  8100. handle: false,
  8101. helper: "original",
  8102. iframeFix: false,
  8103. opacity: false,
  8104. refreshPositions: false,
  8105. revert: false,
  8106. revertDuration: 500,
  8107. scope: "default",
  8108. scroll: true,
  8109. scrollSensitivity: 20,
  8110. scrollSpeed: 20,
  8111. snap: false,
  8112. snapMode: "both",
  8113. snapTolerance: 20,
  8114. stack: false,
  8115. zIndex: false,
  8116. // Callbacks
  8117. drag: null,
  8118. start: null,
  8119. stop: null
  8120. },
  8121. _create: function() {
  8122. if ( this.options.helper === "original" ) {
  8123. this._setPositionRelative();
  8124. }
  8125. if ( this.options.addClasses ) {
  8126. this._addClass( "ui-draggable" );
  8127. }
  8128. this._setHandleClassName();
  8129. this._mouseInit();
  8130. },
  8131. _setOption: function( key, value ) {
  8132. this._super( key, value );
  8133. if ( key === "handle" ) {
  8134. this._removeHandleClassName();
  8135. this._setHandleClassName();
  8136. }
  8137. },
  8138. _destroy: function() {
  8139. if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
  8140. this.destroyOnClear = true;
  8141. return;
  8142. }
  8143. this._removeHandleClassName();
  8144. this._mouseDestroy();
  8145. },
  8146. _mouseCapture: function( event ) {
  8147. var o = this.options;
  8148. // Among others, prevent a drag on a resizable-handle
  8149. if ( this.helper || o.disabled ||
  8150. $( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
  8151. return false;
  8152. }
  8153. //Quit if we're not on a valid handle
  8154. this.handle = this._getHandle( event );
  8155. if ( !this.handle ) {
  8156. return false;
  8157. }
  8158. this._blurActiveElement( event );
  8159. this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
  8160. return true;
  8161. },
  8162. _blockFrames: function( selector ) {
  8163. this.iframeBlocks = this.document.find( selector ).map( function() {
  8164. var iframe = $( this );
  8165. return $( "<div>" )
  8166. .css( "position", "absolute" )
  8167. .appendTo( iframe.parent() )
  8168. .outerWidth( iframe.outerWidth() )
  8169. .outerHeight( iframe.outerHeight() )
  8170. .offset( iframe.offset() )[ 0 ];
  8171. } );
  8172. },
  8173. _unblockFrames: function() {
  8174. if ( this.iframeBlocks ) {
  8175. this.iframeBlocks.remove();
  8176. delete this.iframeBlocks;
  8177. }
  8178. },
  8179. _blurActiveElement: function( event ) {
  8180. var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
  8181. target = $( event.target );
  8182. // Don't blur if the event occurred on an element that is within
  8183. // the currently focused element
  8184. // See #10527, #12472
  8185. if ( target.closest( activeElement ).length ) {
  8186. return;
  8187. }
  8188. // Blur any element that currently has focus, see #4261
  8189. $.ui.safeBlur( activeElement );
  8190. },
  8191. _mouseStart: function( event ) {
  8192. var o = this.options;
  8193. //Create and append the visible helper
  8194. this.helper = this._createHelper( event );
  8195. this._addClass( this.helper, "ui-draggable-dragging" );
  8196. //Cache the helper size
  8197. this._cacheHelperProportions();
  8198. //If ddmanager is used for droppables, set the global draggable
  8199. if ( $.ui.ddmanager ) {
  8200. $.ui.ddmanager.current = this;
  8201. }
  8202. /*
  8203. * - Position generation -
  8204. * This block generates everything position related - it's the core of draggables.
  8205. */
  8206. //Cache the margins of the original element
  8207. this._cacheMargins();
  8208. //Store the helper's css position
  8209. this.cssPosition = this.helper.css( "position" );
  8210. this.scrollParent = this.helper.scrollParent( true );
  8211. this.offsetParent = this.helper.offsetParent();
  8212. this.hasFixedAncestor = this.helper.parents().filter( function() {
  8213. return $( this ).css( "position" ) === "fixed";
  8214. } ).length > 0;
  8215. //The element's absolute position on the page minus margins
  8216. this.positionAbs = this.element.offset();
  8217. this._refreshOffsets( event );
  8218. //Generate the original position
  8219. this.originalPosition = this.position = this._generatePosition( event, false );
  8220. this.originalPageX = event.pageX;
  8221. this.originalPageY = event.pageY;
  8222. //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
  8223. ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
  8224. //Set a containment if given in the options
  8225. this._setContainment();
  8226. //Trigger event + callbacks
  8227. if ( this._trigger( "start", event ) === false ) {
  8228. this._clear();
  8229. return false;
  8230. }
  8231. //Recache the helper size
  8232. this._cacheHelperProportions();
  8233. //Prepare the droppable offsets
  8234. if ( $.ui.ddmanager && !o.dropBehaviour ) {
  8235. $.ui.ddmanager.prepareOffsets( this, event );
  8236. }
  8237. // Execute the drag once - this causes the helper not to be visible before getting its
  8238. // correct position
  8239. this._mouseDrag( event, true );
  8240. // If the ddmanager is used for droppables, inform the manager that dragging has started
  8241. // (see #5003)
  8242. if ( $.ui.ddmanager ) {
  8243. $.ui.ddmanager.dragStart( this, event );
  8244. }
  8245. return true;
  8246. },
  8247. _refreshOffsets: function( event ) {
  8248. this.offset = {
  8249. top: this.positionAbs.top - this.margins.top,
  8250. left: this.positionAbs.left - this.margins.left,
  8251. scroll: false,
  8252. parent: this._getParentOffset(),
  8253. relative: this._getRelativeOffset()
  8254. };
  8255. this.offset.click = {
  8256. left: event.pageX - this.offset.left,
  8257. top: event.pageY - this.offset.top
  8258. };
  8259. },
  8260. _mouseDrag: function( event, noPropagation ) {
  8261. // reset any necessary cached properties (see #5009)
  8262. if ( this.hasFixedAncestor ) {
  8263. this.offset.parent = this._getParentOffset();
  8264. }
  8265. //Compute the helpers position
  8266. this.position = this._generatePosition( event, true );
  8267. this.positionAbs = this._convertPositionTo( "absolute" );
  8268. //Call plugins and callbacks and use the resulting position if something is returned
  8269. if ( !noPropagation ) {
  8270. var ui = this._uiHash();
  8271. if ( this._trigger( "drag", event, ui ) === false ) {
  8272. this._mouseUp( new $.Event( "mouseup", event ) );
  8273. return false;
  8274. }
  8275. this.position = ui.position;
  8276. }
  8277. this.helper[ 0 ].style.left = this.position.left + "px";
  8278. this.helper[ 0 ].style.top = this.position.top + "px";
  8279. if ( $.ui.ddmanager ) {
  8280. $.ui.ddmanager.drag( this, event );
  8281. }
  8282. return false;
  8283. },
  8284. _mouseStop: function( event ) {
  8285. //If we are using droppables, inform the manager about the drop
  8286. var that = this,
  8287. dropped = false;
  8288. if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
  8289. dropped = $.ui.ddmanager.drop( this, event );
  8290. }
  8291. //if a drop comes from outside (a sortable)
  8292. if ( this.dropped ) {
  8293. dropped = this.dropped;
  8294. this.dropped = false;
  8295. }
  8296. if ( ( this.options.revert === "invalid" && !dropped ) ||
  8297. ( this.options.revert === "valid" && dropped ) ||
  8298. this.options.revert === true || ( $.isFunction( this.options.revert ) &&
  8299. this.options.revert.call( this.element, dropped ) )
  8300. ) {
  8301. $( this.helper ).animate(
  8302. this.originalPosition,
  8303. parseInt( this.options.revertDuration, 10 ),
  8304. function() {
  8305. if ( that._trigger( "stop", event ) !== false ) {
  8306. that._clear();
  8307. }
  8308. }
  8309. );
  8310. } else {
  8311. if ( this._trigger( "stop", event ) !== false ) {
  8312. this._clear();
  8313. }
  8314. }
  8315. return false;
  8316. },
  8317. _mouseUp: function( event ) {
  8318. this._unblockFrames();
  8319. // If the ddmanager is used for droppables, inform the manager that dragging has stopped
  8320. // (see #5003)
  8321. if ( $.ui.ddmanager ) {
  8322. $.ui.ddmanager.dragStop( this, event );
  8323. }
  8324. // Only need to focus if the event occurred on the draggable itself, see #10527
  8325. if ( this.handleElement.is( event.target ) ) {
  8326. // The interaction is over; whether or not the click resulted in a drag,
  8327. // focus the element
  8328. this.element.trigger( "focus" );
  8329. }
  8330. return $.ui.mouse.prototype._mouseUp.call( this, event );
  8331. },
  8332. cancel: function() {
  8333. if ( this.helper.is( ".ui-draggable-dragging" ) ) {
  8334. this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
  8335. } else {
  8336. this._clear();
  8337. }
  8338. return this;
  8339. },
  8340. _getHandle: function( event ) {
  8341. return this.options.handle ?
  8342. !!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
  8343. true;
  8344. },
  8345. _setHandleClassName: function() {
  8346. this.handleElement = this.options.handle ?
  8347. this.element.find( this.options.handle ) : this.element;
  8348. this._addClass( this.handleElement, "ui-draggable-handle" );
  8349. },
  8350. _removeHandleClassName: function() {
  8351. this._removeClass( this.handleElement, "ui-draggable-handle" );
  8352. },
  8353. _createHelper: function( event ) {
  8354. var o = this.options,
  8355. helperIsFunction = $.isFunction( o.helper ),
  8356. helper = helperIsFunction ?
  8357. $( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
  8358. ( o.helper === "clone" ?
  8359. this.element.clone().removeAttr( "id" ) :
  8360. this.element );
  8361. if ( !helper.parents( "body" ).length ) {
  8362. helper.appendTo( ( o.appendTo === "parent" ?
  8363. this.element[ 0 ].parentNode :
  8364. o.appendTo ) );
  8365. }
  8366. // Http://bugs.jqueryui.com/ticket/9446
  8367. // a helper function can return the original element
  8368. // which wouldn't have been set to relative in _create
  8369. if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
  8370. this._setPositionRelative();
  8371. }
  8372. if ( helper[ 0 ] !== this.element[ 0 ] &&
  8373. !( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
  8374. helper.css( "position", "absolute" );
  8375. }
  8376. return helper;
  8377. },
  8378. _setPositionRelative: function() {
  8379. if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
  8380. this.element[ 0 ].style.position = "relative";
  8381. }
  8382. },
  8383. _adjustOffsetFromHelper: function( obj ) {
  8384. if ( typeof obj === "string" ) {
  8385. obj = obj.split( " " );
  8386. }
  8387. if ( $.isArray( obj ) ) {
  8388. obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
  8389. }
  8390. if ( "left" in obj ) {
  8391. this.offset.click.left = obj.left + this.margins.left;
  8392. }
  8393. if ( "right" in obj ) {
  8394. this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
  8395. }
  8396. if ( "top" in obj ) {
  8397. this.offset.click.top = obj.top + this.margins.top;
  8398. }
  8399. if ( "bottom" in obj ) {
  8400. this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
  8401. }
  8402. },
  8403. _isRootNode: function( element ) {
  8404. return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
  8405. },
  8406. _getParentOffset: function() {
  8407. //Get the offsetParent and cache its position
  8408. var po = this.offsetParent.offset(),
  8409. document = this.document[ 0 ];
  8410. // This is a special case where we need to modify a offset calculated on start, since the
  8411. // following happened:
  8412. // 1. The position of the helper is absolute, so it's position is calculated based on the
  8413. // next positioned parent
  8414. // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
  8415. // the document, which means that the scroll is included in the initial calculation of the
  8416. // offset of the parent, and never recalculated upon drag
  8417. if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
  8418. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
  8419. po.left += this.scrollParent.scrollLeft();
  8420. po.top += this.scrollParent.scrollTop();
  8421. }
  8422. if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
  8423. po = { top: 0, left: 0 };
  8424. }
  8425. return {
  8426. top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
  8427. left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
  8428. };
  8429. },
  8430. _getRelativeOffset: function() {
  8431. if ( this.cssPosition !== "relative" ) {
  8432. return { top: 0, left: 0 };
  8433. }
  8434. var p = this.element.position(),
  8435. scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
  8436. return {
  8437. top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
  8438. ( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
  8439. left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
  8440. ( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
  8441. };
  8442. },
  8443. _cacheMargins: function() {
  8444. this.margins = {
  8445. left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
  8446. top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
  8447. right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
  8448. bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
  8449. };
  8450. },
  8451. _cacheHelperProportions: function() {
  8452. this.helperProportions = {
  8453. width: this.helper.outerWidth(),
  8454. height: this.helper.outerHeight()
  8455. };
  8456. },
  8457. _setContainment: function() {
  8458. var isUserScrollable, c, ce,
  8459. o = this.options,
  8460. document = this.document[ 0 ];
  8461. this.relativeContainer = null;
  8462. if ( !o.containment ) {
  8463. this.containment = null;
  8464. return;
  8465. }
  8466. if ( o.containment === "window" ) {
  8467. this.containment = [
  8468. $( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
  8469. $( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
  8470. $( window ).scrollLeft() + $( window ).width() -
  8471. this.helperProportions.width - this.margins.left,
  8472. $( window ).scrollTop() +
  8473. ( $( window ).height() || document.body.parentNode.scrollHeight ) -
  8474. this.helperProportions.height - this.margins.top
  8475. ];
  8476. return;
  8477. }
  8478. if ( o.containment === "document" ) {
  8479. this.containment = [
  8480. 0,
  8481. 0,
  8482. $( document ).width() - this.helperProportions.width - this.margins.left,
  8483. ( $( document ).height() || document.body.parentNode.scrollHeight ) -
  8484. this.helperProportions.height - this.margins.top
  8485. ];
  8486. return;
  8487. }
  8488. if ( o.containment.constructor === Array ) {
  8489. this.containment = o.containment;
  8490. return;
  8491. }
  8492. if ( o.containment === "parent" ) {
  8493. o.containment = this.helper[ 0 ].parentNode;
  8494. }
  8495. c = $( o.containment );
  8496. ce = c[ 0 ];
  8497. if ( !ce ) {
  8498. return;
  8499. }
  8500. isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
  8501. this.containment = [
  8502. ( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
  8503. ( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
  8504. ( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
  8505. ( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
  8506. ( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
  8507. ( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
  8508. ( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
  8509. this.helperProportions.width -
  8510. this.margins.left -
  8511. this.margins.right,
  8512. ( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
  8513. ( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
  8514. ( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
  8515. this.helperProportions.height -
  8516. this.margins.top -
  8517. this.margins.bottom
  8518. ];
  8519. this.relativeContainer = c;
  8520. },
  8521. _convertPositionTo: function( d, pos ) {
  8522. if ( !pos ) {
  8523. pos = this.position;
  8524. }
  8525. var mod = d === "absolute" ? 1 : -1,
  8526. scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
  8527. return {
  8528. top: (
  8529. // The absolute mouse position
  8530. pos.top +
  8531. // Only for relative positioned nodes: Relative offset from element to offset parent
  8532. this.offset.relative.top * mod +
  8533. // The offsetParent's offset without borders (offset + border)
  8534. this.offset.parent.top * mod -
  8535. ( ( this.cssPosition === "fixed" ?
  8536. -this.offset.scroll.top :
  8537. ( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
  8538. ),
  8539. left: (
  8540. // The absolute mouse position
  8541. pos.left +
  8542. // Only for relative positioned nodes: Relative offset from element to offset parent
  8543. this.offset.relative.left * mod +
  8544. // The offsetParent's offset without borders (offset + border)
  8545. this.offset.parent.left * mod -
  8546. ( ( this.cssPosition === "fixed" ?
  8547. -this.offset.scroll.left :
  8548. ( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
  8549. )
  8550. };
  8551. },
  8552. _generatePosition: function( event, constrainPosition ) {
  8553. var containment, co, top, left,
  8554. o = this.options,
  8555. scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
  8556. pageX = event.pageX,
  8557. pageY = event.pageY;
  8558. // Cache the scroll
  8559. if ( !scrollIsRootNode || !this.offset.scroll ) {
  8560. this.offset.scroll = {
  8561. top: this.scrollParent.scrollTop(),
  8562. left: this.scrollParent.scrollLeft()
  8563. };
  8564. }
  8565. /*
  8566. * - Position constraining -
  8567. * Constrain the position to a mix of grid, containment.
  8568. */
  8569. // If we are not dragging yet, we won't check for options
  8570. if ( constrainPosition ) {
  8571. if ( this.containment ) {
  8572. if ( this.relativeContainer ) {
  8573. co = this.relativeContainer.offset();
  8574. containment = [
  8575. this.containment[ 0 ] + co.left,
  8576. this.containment[ 1 ] + co.top,
  8577. this.containment[ 2 ] + co.left,
  8578. this.containment[ 3 ] + co.top
  8579. ];
  8580. } else {
  8581. containment = this.containment;
  8582. }
  8583. if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
  8584. pageX = containment[ 0 ] + this.offset.click.left;
  8585. }
  8586. if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
  8587. pageY = containment[ 1 ] + this.offset.click.top;
  8588. }
  8589. if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
  8590. pageX = containment[ 2 ] + this.offset.click.left;
  8591. }
  8592. if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
  8593. pageY = containment[ 3 ] + this.offset.click.top;
  8594. }
  8595. }
  8596. if ( o.grid ) {
  8597. //Check for grid elements set to 0 to prevent divide by 0 error causing invalid
  8598. // argument errors in IE (see ticket #6950)
  8599. top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
  8600. this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
  8601. pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
  8602. top - this.offset.click.top > containment[ 3 ] ) ?
  8603. top :
  8604. ( ( top - this.offset.click.top >= containment[ 1 ] ) ?
  8605. top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
  8606. left = o.grid[ 0 ] ? this.originalPageX +
  8607. Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
  8608. this.originalPageX;
  8609. pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
  8610. left - this.offset.click.left > containment[ 2 ] ) ?
  8611. left :
  8612. ( ( left - this.offset.click.left >= containment[ 0 ] ) ?
  8613. left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
  8614. }
  8615. if ( o.axis === "y" ) {
  8616. pageX = this.originalPageX;
  8617. }
  8618. if ( o.axis === "x" ) {
  8619. pageY = this.originalPageY;
  8620. }
  8621. }
  8622. return {
  8623. top: (
  8624. // The absolute mouse position
  8625. pageY -
  8626. // Click offset (relative to the element)
  8627. this.offset.click.top -
  8628. // Only for relative positioned nodes: Relative offset from element to offset parent
  8629. this.offset.relative.top -
  8630. // The offsetParent's offset without borders (offset + border)
  8631. this.offset.parent.top +
  8632. ( this.cssPosition === "fixed" ?
  8633. -this.offset.scroll.top :
  8634. ( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
  8635. ),
  8636. left: (
  8637. // The absolute mouse position
  8638. pageX -
  8639. // Click offset (relative to the element)
  8640. this.offset.click.left -
  8641. // Only for relative positioned nodes: Relative offset from element to offset parent
  8642. this.offset.relative.left -
  8643. // The offsetParent's offset without borders (offset + border)
  8644. this.offset.parent.left +
  8645. ( this.cssPosition === "fixed" ?
  8646. -this.offset.scroll.left :
  8647. ( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
  8648. )
  8649. };
  8650. },
  8651. _clear: function() {
  8652. this._removeClass( this.helper, "ui-draggable-dragging" );
  8653. if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
  8654. this.helper.remove();
  8655. }
  8656. this.helper = null;
  8657. this.cancelHelperRemoval = false;
  8658. if ( this.destroyOnClear ) {
  8659. this.destroy();
  8660. }
  8661. },
  8662. // From now on bulk stuff - mainly helpers
  8663. _trigger: function( type, event, ui ) {
  8664. ui = ui || this._uiHash();
  8665. $.ui.plugin.call( this, type, [ event, ui, this ], true );
  8666. // Absolute position and offset (see #6884 ) have to be recalculated after plugins
  8667. if ( /^(drag|start|stop)/.test( type ) ) {
  8668. this.positionAbs = this._convertPositionTo( "absolute" );
  8669. ui.offset = this.positionAbs;
  8670. }
  8671. return $.Widget.prototype._trigger.call( this, type, event, ui );
  8672. },
  8673. plugins: {},
  8674. _uiHash: function() {
  8675. return {
  8676. helper: this.helper,
  8677. position: this.position,
  8678. originalPosition: this.originalPosition,
  8679. offset: this.positionAbs
  8680. };
  8681. }
  8682. } );
  8683. $.ui.plugin.add( "draggable", "connectToSortable", {
  8684. start: function( event, ui, draggable ) {
  8685. var uiSortable = $.extend( {}, ui, {
  8686. item: draggable.element
  8687. } );
  8688. draggable.sortables = [];
  8689. $( draggable.options.connectToSortable ).each( function() {
  8690. var sortable = $( this ).sortable( "instance" );
  8691. if ( sortable && !sortable.options.disabled ) {
  8692. draggable.sortables.push( sortable );
  8693. // RefreshPositions is called at drag start to refresh the containerCache
  8694. // which is used in drag. This ensures it's initialized and synchronized
  8695. // with any changes that might have happened on the page since initialization.
  8696. sortable.refreshPositions();
  8697. sortable._trigger( "activate", event, uiSortable );
  8698. }
  8699. } );
  8700. },
  8701. stop: function( event, ui, draggable ) {
  8702. var uiSortable = $.extend( {}, ui, {
  8703. item: draggable.element
  8704. } );
  8705. draggable.cancelHelperRemoval = false;
  8706. $.each( draggable.sortables, function() {
  8707. var sortable = this;
  8708. if ( sortable.isOver ) {
  8709. sortable.isOver = 0;
  8710. // Allow this sortable to handle removing the helper
  8711. draggable.cancelHelperRemoval = true;
  8712. sortable.cancelHelperRemoval = false;
  8713. // Use _storedCSS To restore properties in the sortable,
  8714. // as this also handles revert (#9675) since the draggable
  8715. // may have modified them in unexpected ways (#8809)
  8716. sortable._storedCSS = {
  8717. position: sortable.placeholder.css( "position" ),
  8718. top: sortable.placeholder.css( "top" ),
  8719. left: sortable.placeholder.css( "left" )
  8720. };
  8721. sortable._mouseStop( event );
  8722. // Once drag has ended, the sortable should return to using
  8723. // its original helper, not the shared helper from draggable
  8724. sortable.options.helper = sortable.options._helper;
  8725. } else {
  8726. // Prevent this Sortable from removing the helper.
  8727. // However, don't set the draggable to remove the helper
  8728. // either as another connected Sortable may yet handle the removal.
  8729. sortable.cancelHelperRemoval = true;
  8730. sortable._trigger( "deactivate", event, uiSortable );
  8731. }
  8732. } );
  8733. },
  8734. drag: function( event, ui, draggable ) {
  8735. $.each( draggable.sortables, function() {
  8736. var innermostIntersecting = false,
  8737. sortable = this;
  8738. // Copy over variables that sortable's _intersectsWith uses
  8739. sortable.positionAbs = draggable.positionAbs;
  8740. sortable.helperProportions = draggable.helperProportions;
  8741. sortable.offset.click = draggable.offset.click;
  8742. if ( sortable._intersectsWith( sortable.containerCache ) ) {
  8743. innermostIntersecting = true;
  8744. $.each( draggable.sortables, function() {
  8745. // Copy over variables that sortable's _intersectsWith uses
  8746. this.positionAbs = draggable.positionAbs;
  8747. this.helperProportions = draggable.helperProportions;
  8748. this.offset.click = draggable.offset.click;
  8749. if ( this !== sortable &&
  8750. this._intersectsWith( this.containerCache ) &&
  8751. $.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
  8752. innermostIntersecting = false;
  8753. }
  8754. return innermostIntersecting;
  8755. } );
  8756. }
  8757. if ( innermostIntersecting ) {
  8758. // If it intersects, we use a little isOver variable and set it once,
  8759. // so that the move-in stuff gets fired only once.
  8760. if ( !sortable.isOver ) {
  8761. sortable.isOver = 1;
  8762. // Store draggable's parent in case we need to reappend to it later.
  8763. draggable._parent = ui.helper.parent();
  8764. sortable.currentItem = ui.helper
  8765. .appendTo( sortable.element )
  8766. .data( "ui-sortable-item", true );
  8767. // Store helper option to later restore it
  8768. sortable.options._helper = sortable.options.helper;
  8769. sortable.options.helper = function() {
  8770. return ui.helper[ 0 ];
  8771. };
  8772. // Fire the start events of the sortable with our passed browser event,
  8773. // and our own helper (so it doesn't create a new one)
  8774. event.target = sortable.currentItem[ 0 ];
  8775. sortable._mouseCapture( event, true );
  8776. sortable._mouseStart( event, true, true );
  8777. // Because the browser event is way off the new appended portlet,
  8778. // modify necessary variables to reflect the changes
  8779. sortable.offset.click.top = draggable.offset.click.top;
  8780. sortable.offset.click.left = draggable.offset.click.left;
  8781. sortable.offset.parent.left -= draggable.offset.parent.left -
  8782. sortable.offset.parent.left;
  8783. sortable.offset.parent.top -= draggable.offset.parent.top -
  8784. sortable.offset.parent.top;
  8785. draggable._trigger( "toSortable", event );
  8786. // Inform draggable that the helper is in a valid drop zone,
  8787. // used solely in the revert option to handle "valid/invalid".
  8788. draggable.dropped = sortable.element;
  8789. // Need to refreshPositions of all sortables in the case that
  8790. // adding to one sortable changes the location of the other sortables (#9675)
  8791. $.each( draggable.sortables, function() {
  8792. this.refreshPositions();
  8793. } );
  8794. // Hack so receive/update callbacks work (mostly)
  8795. draggable.currentItem = draggable.element;
  8796. sortable.fromOutside = draggable;
  8797. }
  8798. if ( sortable.currentItem ) {
  8799. sortable._mouseDrag( event );
  8800. // Copy the sortable's position because the draggable's can potentially reflect
  8801. // a relative position, while sortable is always absolute, which the dragged
  8802. // element has now become. (#8809)
  8803. ui.position = sortable.position;
  8804. }
  8805. } else {
  8806. // If it doesn't intersect with the sortable, and it intersected before,
  8807. // we fake the drag stop of the sortable, but make sure it doesn't remove
  8808. // the helper by using cancelHelperRemoval.
  8809. if ( sortable.isOver ) {
  8810. sortable.isOver = 0;
  8811. sortable.cancelHelperRemoval = true;
  8812. // Calling sortable's mouseStop would trigger a revert,
  8813. // so revert must be temporarily false until after mouseStop is called.
  8814. sortable.options._revert = sortable.options.revert;
  8815. sortable.options.revert = false;
  8816. sortable._trigger( "out", event, sortable._uiHash( sortable ) );
  8817. sortable._mouseStop( event, true );
  8818. // Restore sortable behaviors that were modfied
  8819. // when the draggable entered the sortable area (#9481)
  8820. sortable.options.revert = sortable.options._revert;
  8821. sortable.options.helper = sortable.options._helper;
  8822. if ( sortable.placeholder ) {
  8823. sortable.placeholder.remove();
  8824. }
  8825. // Restore and recalculate the draggable's offset considering the sortable
  8826. // may have modified them in unexpected ways. (#8809, #10669)
  8827. ui.helper.appendTo( draggable._parent );
  8828. draggable._refreshOffsets( event );
  8829. ui.position = draggable._generatePosition( event, true );
  8830. draggable._trigger( "fromSortable", event );
  8831. // Inform draggable that the helper is no longer in a valid drop zone
  8832. draggable.dropped = false;
  8833. // Need to refreshPositions of all sortables just in case removing
  8834. // from one sortable changes the location of other sortables (#9675)
  8835. $.each( draggable.sortables, function() {
  8836. this.refreshPositions();
  8837. } );
  8838. }
  8839. }
  8840. } );
  8841. }
  8842. } );
  8843. $.ui.plugin.add( "draggable", "cursor", {
  8844. start: function( event, ui, instance ) {
  8845. var t = $( "body" ),
  8846. o = instance.options;
  8847. if ( t.css( "cursor" ) ) {
  8848. o._cursor = t.css( "cursor" );
  8849. }
  8850. t.css( "cursor", o.cursor );
  8851. },
  8852. stop: function( event, ui, instance ) {
  8853. var o = instance.options;
  8854. if ( o._cursor ) {
  8855. $( "body" ).css( "cursor", o._cursor );
  8856. }
  8857. }
  8858. } );
  8859. $.ui.plugin.add( "draggable", "opacity", {
  8860. start: function( event, ui, instance ) {
  8861. var t = $( ui.helper ),
  8862. o = instance.options;
  8863. if ( t.css( "opacity" ) ) {
  8864. o._opacity = t.css( "opacity" );
  8865. }
  8866. t.css( "opacity", o.opacity );
  8867. },
  8868. stop: function( event, ui, instance ) {
  8869. var o = instance.options;
  8870. if ( o._opacity ) {
  8871. $( ui.helper ).css( "opacity", o._opacity );
  8872. }
  8873. }
  8874. } );
  8875. $.ui.plugin.add( "draggable", "scroll", {
  8876. start: function( event, ui, i ) {
  8877. if ( !i.scrollParentNotHidden ) {
  8878. i.scrollParentNotHidden = i.helper.scrollParent( false );
  8879. }
  8880. if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
  8881. i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
  8882. i.overflowOffset = i.scrollParentNotHidden.offset();
  8883. }
  8884. },
  8885. drag: function( event, ui, i ) {
  8886. var o = i.options,
  8887. scrolled = false,
  8888. scrollParent = i.scrollParentNotHidden[ 0 ],
  8889. document = i.document[ 0 ];
  8890. if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
  8891. if ( !o.axis || o.axis !== "x" ) {
  8892. if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
  8893. o.scrollSensitivity ) {
  8894. scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
  8895. } else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
  8896. scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
  8897. }
  8898. }
  8899. if ( !o.axis || o.axis !== "y" ) {
  8900. if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
  8901. o.scrollSensitivity ) {
  8902. scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
  8903. } else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
  8904. scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
  8905. }
  8906. }
  8907. } else {
  8908. if ( !o.axis || o.axis !== "x" ) {
  8909. if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
  8910. scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
  8911. } else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
  8912. o.scrollSensitivity ) {
  8913. scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
  8914. }
  8915. }
  8916. if ( !o.axis || o.axis !== "y" ) {
  8917. if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
  8918. scrolled = $( document ).scrollLeft(
  8919. $( document ).scrollLeft() - o.scrollSpeed
  8920. );
  8921. } else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
  8922. o.scrollSensitivity ) {
  8923. scrolled = $( document ).scrollLeft(
  8924. $( document ).scrollLeft() + o.scrollSpeed
  8925. );
  8926. }
  8927. }
  8928. }
  8929. if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
  8930. $.ui.ddmanager.prepareOffsets( i, event );
  8931. }
  8932. }
  8933. } );
  8934. $.ui.plugin.add( "draggable", "snap", {
  8935. start: function( event, ui, i ) {
  8936. var o = i.options;
  8937. i.snapElements = [];
  8938. $( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
  8939. .each( function() {
  8940. var $t = $( this ),
  8941. $o = $t.offset();
  8942. if ( this !== i.element[ 0 ] ) {
  8943. i.snapElements.push( {
  8944. item: this,
  8945. width: $t.outerWidth(), height: $t.outerHeight(),
  8946. top: $o.top, left: $o.left
  8947. } );
  8948. }
  8949. } );
  8950. },
  8951. drag: function( event, ui, inst ) {
  8952. var ts, bs, ls, rs, l, r, t, b, i, first,
  8953. o = inst.options,
  8954. d = o.snapTolerance,
  8955. x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
  8956. y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
  8957. for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
  8958. l = inst.snapElements[ i ].left - inst.margins.left;
  8959. r = l + inst.snapElements[ i ].width;
  8960. t = inst.snapElements[ i ].top - inst.margins.top;
  8961. b = t + inst.snapElements[ i ].height;
  8962. if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
  8963. !$.contains( inst.snapElements[ i ].item.ownerDocument,
  8964. inst.snapElements[ i ].item ) ) {
  8965. if ( inst.snapElements[ i ].snapping ) {
  8966. ( inst.options.snap.release &&
  8967. inst.options.snap.release.call(
  8968. inst.element,
  8969. event,
  8970. $.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
  8971. ) );
  8972. }
  8973. inst.snapElements[ i ].snapping = false;
  8974. continue;
  8975. }
  8976. if ( o.snapMode !== "inner" ) {
  8977. ts = Math.abs( t - y2 ) <= d;
  8978. bs = Math.abs( b - y1 ) <= d;
  8979. ls = Math.abs( l - x2 ) <= d;
  8980. rs = Math.abs( r - x1 ) <= d;
  8981. if ( ts ) {
  8982. ui.position.top = inst._convertPositionTo( "relative", {
  8983. top: t - inst.helperProportions.height,
  8984. left: 0
  8985. } ).top;
  8986. }
  8987. if ( bs ) {
  8988. ui.position.top = inst._convertPositionTo( "relative", {
  8989. top: b,
  8990. left: 0
  8991. } ).top;
  8992. }
  8993. if ( ls ) {
  8994. ui.position.left = inst._convertPositionTo( "relative", {
  8995. top: 0,
  8996. left: l - inst.helperProportions.width
  8997. } ).left;
  8998. }
  8999. if ( rs ) {
  9000. ui.position.left = inst._convertPositionTo( "relative", {
  9001. top: 0,
  9002. left: r
  9003. } ).left;
  9004. }
  9005. }
  9006. first = ( ts || bs || ls || rs );
  9007. if ( o.snapMode !== "outer" ) {
  9008. ts = Math.abs( t - y1 ) <= d;
  9009. bs = Math.abs( b - y2 ) <= d;
  9010. ls = Math.abs( l - x1 ) <= d;
  9011. rs = Math.abs( r - x2 ) <= d;
  9012. if ( ts ) {
  9013. ui.position.top = inst._convertPositionTo( "relative", {
  9014. top: t,
  9015. left: 0
  9016. } ).top;
  9017. }
  9018. if ( bs ) {
  9019. ui.position.top = inst._convertPositionTo( "relative", {
  9020. top: b - inst.helperProportions.height,
  9021. left: 0
  9022. } ).top;
  9023. }
  9024. if ( ls ) {
  9025. ui.position.left = inst._convertPositionTo( "relative", {
  9026. top: 0,
  9027. left: l
  9028. } ).left;
  9029. }
  9030. if ( rs ) {
  9031. ui.position.left = inst._convertPositionTo( "relative", {
  9032. top: 0,
  9033. left: r - inst.helperProportions.width
  9034. } ).left;
  9035. }
  9036. }
  9037. if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
  9038. ( inst.options.snap.snap &&
  9039. inst.options.snap.snap.call(
  9040. inst.element,
  9041. event,
  9042. $.extend( inst._uiHash(), {
  9043. snapItem: inst.snapElements[ i ].item
  9044. } ) ) );
  9045. }
  9046. inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
  9047. }
  9048. }
  9049. } );
  9050. $.ui.plugin.add( "draggable", "stack", {
  9051. start: function( event, ui, instance ) {
  9052. var min,
  9053. o = instance.options,
  9054. group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
  9055. return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
  9056. ( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
  9057. } );
  9058. if ( !group.length ) { return; }
  9059. min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
  9060. $( group ).each( function( i ) {
  9061. $( this ).css( "zIndex", min + i );
  9062. } );
  9063. this.css( "zIndex", ( min + group.length ) );
  9064. }
  9065. } );
  9066. $.ui.plugin.add( "draggable", "zIndex", {
  9067. start: function( event, ui, instance ) {
  9068. var t = $( ui.helper ),
  9069. o = instance.options;
  9070. if ( t.css( "zIndex" ) ) {
  9071. o._zIndex = t.css( "zIndex" );
  9072. }
  9073. t.css( "zIndex", o.zIndex );
  9074. },
  9075. stop: function( event, ui, instance ) {
  9076. var o = instance.options;
  9077. if ( o._zIndex ) {
  9078. $( ui.helper ).css( "zIndex", o._zIndex );
  9079. }
  9080. }
  9081. } );
  9082. var widgetsDraggable = $.ui.draggable;
  9083. /*!
  9084. * jQuery UI Resizable 1.12.1
  9085. * http://jqueryui.com
  9086. *
  9087. * Copyright jQuery Foundation and other contributors
  9088. * Released under the MIT license.
  9089. * http://jquery.org/license
  9090. */
  9091. //>>label: Resizable
  9092. //>>group: Interactions
  9093. //>>description: Enables resize functionality for any element.
  9094. //>>docs: http://api.jqueryui.com/resizable/
  9095. //>>demos: http://jqueryui.com/resizable/
  9096. //>>css.structure: ../../themes/base/core.css
  9097. //>>css.structure: ../../themes/base/resizable.css
  9098. //>>css.theme: ../../themes/base/theme.css
  9099. $.widget( "ui.resizable", $.ui.mouse, {
  9100. version: "1.12.1",
  9101. widgetEventPrefix: "resize",
  9102. options: {
  9103. alsoResize: false,
  9104. animate: false,
  9105. animateDuration: "slow",
  9106. animateEasing: "swing",
  9107. aspectRatio: false,
  9108. autoHide: false,
  9109. classes: {
  9110. "ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
  9111. },
  9112. containment: false,
  9113. ghost: false,
  9114. grid: false,
  9115. handles: "e,s,se",
  9116. helper: false,
  9117. maxHeight: null,
  9118. maxWidth: null,
  9119. minHeight: 10,
  9120. minWidth: 10,
  9121. // See #7960
  9122. zIndex: 90,
  9123. // Callbacks
  9124. resize: null,
  9125. start: null,
  9126. stop: null
  9127. },
  9128. _num: function( value ) {
  9129. return parseFloat( value ) || 0;
  9130. },
  9131. _isNumber: function( value ) {
  9132. return !isNaN( parseFloat( value ) );
  9133. },
  9134. _hasScroll: function( el, a ) {
  9135. if ( $( el ).css( "overflow" ) === "hidden" ) {
  9136. return false;
  9137. }
  9138. var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
  9139. has = false;
  9140. if ( el[ scroll ] > 0 ) {
  9141. return true;
  9142. }
  9143. // TODO: determine which cases actually cause this to happen
  9144. // if the element doesn't have the scroll set, see if it's possible to
  9145. // set the scroll
  9146. el[ scroll ] = 1;
  9147. has = ( el[ scroll ] > 0 );
  9148. el[ scroll ] = 0;
  9149. return has;
  9150. },
  9151. _create: function() {
  9152. var margins,
  9153. o = this.options,
  9154. that = this;
  9155. this._addClass( "ui-resizable" );
  9156. $.extend( this, {
  9157. _aspectRatio: !!( o.aspectRatio ),
  9158. aspectRatio: o.aspectRatio,
  9159. originalElement: this.element,
  9160. _proportionallyResizeElements: [],
  9161. _helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
  9162. } );
  9163. // Wrap the element if it cannot hold child nodes
  9164. if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
  9165. this.element.wrap(
  9166. $( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
  9167. position: this.element.css( "position" ),
  9168. width: this.element.outerWidth(),
  9169. height: this.element.outerHeight(),
  9170. top: this.element.css( "top" ),
  9171. left: this.element.css( "left" )
  9172. } )
  9173. );
  9174. this.element = this.element.parent().data(
  9175. "ui-resizable", this.element.resizable( "instance" )
  9176. );
  9177. this.elementIsWrapper = true;
  9178. margins = {
  9179. marginTop: this.originalElement.css( "marginTop" ),
  9180. marginRight: this.originalElement.css( "marginRight" ),
  9181. marginBottom: this.originalElement.css( "marginBottom" ),
  9182. marginLeft: this.originalElement.css( "marginLeft" )
  9183. };
  9184. this.element.css( margins );
  9185. this.originalElement.css( "margin", 0 );
  9186. // support: Safari
  9187. // Prevent Safari textarea resize
  9188. this.originalResizeStyle = this.originalElement.css( "resize" );
  9189. this.originalElement.css( "resize", "none" );
  9190. this._proportionallyResizeElements.push( this.originalElement.css( {
  9191. position: "static",
  9192. zoom: 1,
  9193. display: "block"
  9194. } ) );
  9195. // Support: IE9
  9196. // avoid IE jump (hard set the margin)
  9197. this.originalElement.css( margins );
  9198. this._proportionallyResize();
  9199. }
  9200. this._setupHandles();
  9201. if ( o.autoHide ) {
  9202. $( this.element )
  9203. .on( "mouseenter", function() {
  9204. if ( o.disabled ) {
  9205. return;
  9206. }
  9207. that._removeClass( "ui-resizable-autohide" );
  9208. that._handles.show();
  9209. } )
  9210. .on( "mouseleave", function() {
  9211. if ( o.disabled ) {
  9212. return;
  9213. }
  9214. if ( !that.resizing ) {
  9215. that._addClass( "ui-resizable-autohide" );
  9216. that._handles.hide();
  9217. }
  9218. } );
  9219. }
  9220. this._mouseInit();
  9221. },
  9222. _destroy: function() {
  9223. this._mouseDestroy();
  9224. var wrapper,
  9225. _destroy = function( exp ) {
  9226. $( exp )
  9227. .removeData( "resizable" )
  9228. .removeData( "ui-resizable" )
  9229. .off( ".resizable" )
  9230. .find( ".ui-resizable-handle" )
  9231. .remove();
  9232. };
  9233. // TODO: Unwrap at same DOM position
  9234. if ( this.elementIsWrapper ) {
  9235. _destroy( this.element );
  9236. wrapper = this.element;
  9237. this.originalElement.css( {
  9238. position: wrapper.css( "position" ),
  9239. width: wrapper.outerWidth(),
  9240. height: wrapper.outerHeight(),
  9241. top: wrapper.css( "top" ),
  9242. left: wrapper.css( "left" )
  9243. } ).insertAfter( wrapper );
  9244. wrapper.remove();
  9245. }
  9246. this.originalElement.css( "resize", this.originalResizeStyle );
  9247. _destroy( this.originalElement );
  9248. return this;
  9249. },
  9250. _setOption: function( key, value ) {
  9251. this._super( key, value );
  9252. switch ( key ) {
  9253. case "handles":
  9254. this._removeHandles();
  9255. this._setupHandles();
  9256. break;
  9257. default:
  9258. break;
  9259. }
  9260. },
  9261. _setupHandles: function() {
  9262. var o = this.options, handle, i, n, hname, axis, that = this;
  9263. this.handles = o.handles ||
  9264. ( !$( ".ui-resizable-handle", this.element ).length ?
  9265. "e,s,se" : {
  9266. n: ".ui-resizable-n",
  9267. e: ".ui-resizable-e",
  9268. s: ".ui-resizable-s",
  9269. w: ".ui-resizable-w",
  9270. se: ".ui-resizable-se",
  9271. sw: ".ui-resizable-sw",
  9272. ne: ".ui-resizable-ne",
  9273. nw: ".ui-resizable-nw"
  9274. } );
  9275. this._handles = $();
  9276. if ( this.handles.constructor === String ) {
  9277. if ( this.handles === "all" ) {
  9278. this.handles = "n,e,s,w,se,sw,ne,nw";
  9279. }
  9280. n = this.handles.split( "," );
  9281. this.handles = {};
  9282. for ( i = 0; i < n.length; i++ ) {
  9283. handle = $.trim( n[ i ] );
  9284. hname = "ui-resizable-" + handle;
  9285. axis = $( "<div>" );
  9286. this._addClass( axis, "ui-resizable-handle " + hname );
  9287. axis.css( { zIndex: o.zIndex } );
  9288. this.handles[ handle ] = ".ui-resizable-" + handle;
  9289. this.element.append( axis );
  9290. }
  9291. }
  9292. this._renderAxis = function( target ) {
  9293. var i, axis, padPos, padWrapper;
  9294. target = target || this.element;
  9295. for ( i in this.handles ) {
  9296. if ( this.handles[ i ].constructor === String ) {
  9297. this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
  9298. } else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
  9299. this.handles[ i ] = $( this.handles[ i ] );
  9300. this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
  9301. }
  9302. if ( this.elementIsWrapper &&
  9303. this.originalElement[ 0 ]
  9304. .nodeName
  9305. .match( /^(textarea|input|select|button)$/i ) ) {
  9306. axis = $( this.handles[ i ], this.element );
  9307. padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
  9308. axis.outerHeight() :
  9309. axis.outerWidth();
  9310. padPos = [ "padding",
  9311. /ne|nw|n/.test( i ) ? "Top" :
  9312. /se|sw|s/.test( i ) ? "Bottom" :
  9313. /^e$/.test( i ) ? "Right" : "Left" ].join( "" );
  9314. target.css( padPos, padWrapper );
  9315. this._proportionallyResize();
  9316. }
  9317. this._handles = this._handles.add( this.handles[ i ] );
  9318. }
  9319. };
  9320. // TODO: make renderAxis a prototype function
  9321. this._renderAxis( this.element );
  9322. this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
  9323. this._handles.disableSelection();
  9324. this._handles.on( "mouseover", function() {
  9325. if ( !that.resizing ) {
  9326. if ( this.className ) {
  9327. axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
  9328. }
  9329. that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
  9330. }
  9331. } );
  9332. if ( o.autoHide ) {
  9333. this._handles.hide();
  9334. this._addClass( "ui-resizable-autohide" );
  9335. }
  9336. },
  9337. _removeHandles: function() {
  9338. this._handles.remove();
  9339. },
  9340. _mouseCapture: function( event ) {
  9341. var i, handle,
  9342. capture = false;
  9343. for ( i in this.handles ) {
  9344. handle = $( this.handles[ i ] )[ 0 ];
  9345. if ( handle === event.target || $.contains( handle, event.target ) ) {
  9346. capture = true;
  9347. }
  9348. }
  9349. return !this.options.disabled && capture;
  9350. },
  9351. _mouseStart: function( event ) {
  9352. var curleft, curtop, cursor,
  9353. o = this.options,
  9354. el = this.element;
  9355. this.resizing = true;
  9356. this._renderProxy();
  9357. curleft = this._num( this.helper.css( "left" ) );
  9358. curtop = this._num( this.helper.css( "top" ) );
  9359. if ( o.containment ) {
  9360. curleft += $( o.containment ).scrollLeft() || 0;
  9361. curtop += $( o.containment ).scrollTop() || 0;
  9362. }
  9363. this.offset = this.helper.offset();
  9364. this.position = { left: curleft, top: curtop };
  9365. this.size = this._helper ? {
  9366. width: this.helper.width(),
  9367. height: this.helper.height()
  9368. } : {
  9369. width: el.width(),
  9370. height: el.height()
  9371. };
  9372. this.originalSize = this._helper ? {
  9373. width: el.outerWidth(),
  9374. height: el.outerHeight()
  9375. } : {
  9376. width: el.width(),
  9377. height: el.height()
  9378. };
  9379. this.sizeDiff = {
  9380. width: el.outerWidth() - el.width(),
  9381. height: el.outerHeight() - el.height()
  9382. };
  9383. this.originalPosition = { left: curleft, top: curtop };
  9384. this.originalMousePosition = { left: event.pageX, top: event.pageY };
  9385. this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
  9386. o.aspectRatio :
  9387. ( ( this.originalSize.width / this.originalSize.height ) || 1 );
  9388. cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
  9389. $( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
  9390. this._addClass( "ui-resizable-resizing" );
  9391. this._propagate( "start", event );
  9392. return true;
  9393. },
  9394. _mouseDrag: function( event ) {
  9395. var data, props,
  9396. smp = this.originalMousePosition,
  9397. a = this.axis,
  9398. dx = ( event.pageX - smp.left ) || 0,
  9399. dy = ( event.pageY - smp.top ) || 0,
  9400. trigger = this._change[ a ];
  9401. this._updatePrevProperties();
  9402. if ( !trigger ) {
  9403. return false;
  9404. }
  9405. data = trigger.apply( this, [ event, dx, dy ] );
  9406. this._updateVirtualBoundaries( event.shiftKey );
  9407. if ( this._aspectRatio || event.shiftKey ) {
  9408. data = this._updateRatio( data, event );
  9409. }
  9410. data = this._respectSize( data, event );
  9411. this._updateCache( data );
  9412. this._propagate( "resize", event );
  9413. props = this._applyChanges();
  9414. if ( !this._helper && this._proportionallyResizeElements.length ) {
  9415. this._proportionallyResize();
  9416. }
  9417. if ( !$.isEmptyObject( props ) ) {
  9418. this._updatePrevProperties();
  9419. this._trigger( "resize", event, this.ui() );
  9420. this._applyChanges();
  9421. }
  9422. return false;
  9423. },
  9424. _mouseStop: function( event ) {
  9425. this.resizing = false;
  9426. var pr, ista, soffseth, soffsetw, s, left, top,
  9427. o = this.options, that = this;
  9428. if ( this._helper ) {
  9429. pr = this._proportionallyResizeElements;
  9430. ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
  9431. soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
  9432. soffsetw = ista ? 0 : that.sizeDiff.width;
  9433. s = {
  9434. width: ( that.helper.width() - soffsetw ),
  9435. height: ( that.helper.height() - soffseth )
  9436. };
  9437. left = ( parseFloat( that.element.css( "left" ) ) +
  9438. ( that.position.left - that.originalPosition.left ) ) || null;
  9439. top = ( parseFloat( that.element.css( "top" ) ) +
  9440. ( that.position.top - that.originalPosition.top ) ) || null;
  9441. if ( !o.animate ) {
  9442. this.element.css( $.extend( s, { top: top, left: left } ) );
  9443. }
  9444. that.helper.height( that.size.height );
  9445. that.helper.width( that.size.width );
  9446. if ( this._helper && !o.animate ) {
  9447. this._proportionallyResize();
  9448. }
  9449. }
  9450. $( "body" ).css( "cursor", "auto" );
  9451. this._removeClass( "ui-resizable-resizing" );
  9452. this._propagate( "stop", event );
  9453. if ( this._helper ) {
  9454. this.helper.remove();
  9455. }
  9456. return false;
  9457. },
  9458. _updatePrevProperties: function() {
  9459. this.prevPosition = {
  9460. top: this.position.top,
  9461. left: this.position.left
  9462. };
  9463. this.prevSize = {
  9464. width: this.size.width,
  9465. height: this.size.height
  9466. };
  9467. },
  9468. _applyChanges: function() {
  9469. var props = {};
  9470. if ( this.position.top !== this.prevPosition.top ) {
  9471. props.top = this.position.top + "px";
  9472. }
  9473. if ( this.position.left !== this.prevPosition.left ) {
  9474. props.left = this.position.left + "px";
  9475. }
  9476. if ( this.size.width !== this.prevSize.width ) {
  9477. props.width = this.size.width + "px";
  9478. }
  9479. if ( this.size.height !== this.prevSize.height ) {
  9480. props.height = this.size.height + "px";
  9481. }
  9482. this.helper.css( props );
  9483. return props;
  9484. },
  9485. _updateVirtualBoundaries: function( forceAspectRatio ) {
  9486. var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
  9487. o = this.options;
  9488. b = {
  9489. minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
  9490. maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
  9491. minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
  9492. maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
  9493. };
  9494. if ( this._aspectRatio || forceAspectRatio ) {
  9495. pMinWidth = b.minHeight * this.aspectRatio;
  9496. pMinHeight = b.minWidth / this.aspectRatio;
  9497. pMaxWidth = b.maxHeight * this.aspectRatio;
  9498. pMaxHeight = b.maxWidth / this.aspectRatio;
  9499. if ( pMinWidth > b.minWidth ) {
  9500. b.minWidth = pMinWidth;
  9501. }
  9502. if ( pMinHeight > b.minHeight ) {
  9503. b.minHeight = pMinHeight;
  9504. }
  9505. if ( pMaxWidth < b.maxWidth ) {
  9506. b.maxWidth = pMaxWidth;
  9507. }
  9508. if ( pMaxHeight < b.maxHeight ) {
  9509. b.maxHeight = pMaxHeight;
  9510. }
  9511. }
  9512. this._vBoundaries = b;
  9513. },
  9514. _updateCache: function( data ) {
  9515. this.offset = this.helper.offset();
  9516. if ( this._isNumber( data.left ) ) {
  9517. this.position.left = data.left;
  9518. }
  9519. if ( this._isNumber( data.top ) ) {
  9520. this.position.top = data.top;
  9521. }
  9522. if ( this._isNumber( data.height ) ) {
  9523. this.size.height = data.height;
  9524. }
  9525. if ( this._isNumber( data.width ) ) {
  9526. this.size.width = data.width;
  9527. }
  9528. },
  9529. _updateRatio: function( data ) {
  9530. var cpos = this.position,
  9531. csize = this.size,
  9532. a = this.axis;
  9533. if ( this._isNumber( data.height ) ) {
  9534. data.width = ( data.height * this.aspectRatio );
  9535. } else if ( this._isNumber( data.width ) ) {
  9536. data.height = ( data.width / this.aspectRatio );
  9537. }
  9538. if ( a === "sw" ) {
  9539. data.left = cpos.left + ( csize.width - data.width );
  9540. data.top = null;
  9541. }
  9542. if ( a === "nw" ) {
  9543. data.top = cpos.top + ( csize.height - data.height );
  9544. data.left = cpos.left + ( csize.width - data.width );
  9545. }
  9546. return data;
  9547. },
  9548. _respectSize: function( data ) {
  9549. var o = this._vBoundaries,
  9550. a = this.axis,
  9551. ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
  9552. ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
  9553. isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
  9554. isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
  9555. dw = this.originalPosition.left + this.originalSize.width,
  9556. dh = this.originalPosition.top + this.originalSize.height,
  9557. cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
  9558. if ( isminw ) {
  9559. data.width = o.minWidth;
  9560. }
  9561. if ( isminh ) {
  9562. data.height = o.minHeight;
  9563. }
  9564. if ( ismaxw ) {
  9565. data.width = o.maxWidth;
  9566. }
  9567. if ( ismaxh ) {
  9568. data.height = o.maxHeight;
  9569. }
  9570. if ( isminw && cw ) {
  9571. data.left = dw - o.minWidth;
  9572. }
  9573. if ( ismaxw && cw ) {
  9574. data.left = dw - o.maxWidth;
  9575. }
  9576. if ( isminh && ch ) {
  9577. data.top = dh - o.minHeight;
  9578. }
  9579. if ( ismaxh && ch ) {
  9580. data.top = dh - o.maxHeight;
  9581. }
  9582. // Fixing jump error on top/left - bug #2330
  9583. if ( !data.width && !data.height && !data.left && data.top ) {
  9584. data.top = null;
  9585. } else if ( !data.width && !data.height && !data.top && data.left ) {
  9586. data.left = null;
  9587. }
  9588. return data;
  9589. },
  9590. _getPaddingPlusBorderDimensions: function( element ) {
  9591. var i = 0,
  9592. widths = [],
  9593. borders = [
  9594. element.css( "borderTopWidth" ),
  9595. element.css( "borderRightWidth" ),
  9596. element.css( "borderBottomWidth" ),
  9597. element.css( "borderLeftWidth" )
  9598. ],
  9599. paddings = [
  9600. element.css( "paddingTop" ),
  9601. element.css( "paddingRight" ),
  9602. element.css( "paddingBottom" ),
  9603. element.css( "paddingLeft" )
  9604. ];
  9605. for ( ; i < 4; i++ ) {
  9606. widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
  9607. widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
  9608. }
  9609. return {
  9610. height: widths[ 0 ] + widths[ 2 ],
  9611. width: widths[ 1 ] + widths[ 3 ]
  9612. };
  9613. },
  9614. _proportionallyResize: function() {
  9615. if ( !this._proportionallyResizeElements.length ) {
  9616. return;
  9617. }
  9618. var prel,
  9619. i = 0,
  9620. element = this.helper || this.element;
  9621. for ( ; i < this._proportionallyResizeElements.length; i++ ) {
  9622. prel = this._proportionallyResizeElements[ i ];
  9623. // TODO: Seems like a bug to cache this.outerDimensions
  9624. // considering that we are in a loop.
  9625. if ( !this.outerDimensions ) {
  9626. this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
  9627. }
  9628. prel.css( {
  9629. height: ( element.height() - this.outerDimensions.height ) || 0,
  9630. width: ( element.width() - this.outerDimensions.width ) || 0
  9631. } );
  9632. }
  9633. },
  9634. _renderProxy: function() {
  9635. var el = this.element, o = this.options;
  9636. this.elementOffset = el.offset();
  9637. if ( this._helper ) {
  9638. this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" );
  9639. this._addClass( this.helper, this._helper );
  9640. this.helper.css( {
  9641. width: this.element.outerWidth(),
  9642. height: this.element.outerHeight(),
  9643. position: "absolute",
  9644. left: this.elementOffset.left + "px",
  9645. top: this.elementOffset.top + "px",
  9646. zIndex: ++o.zIndex //TODO: Don't modify option
  9647. } );
  9648. this.helper
  9649. .appendTo( "body" )
  9650. .disableSelection();
  9651. } else {
  9652. this.helper = this.element;
  9653. }
  9654. },
  9655. _change: {
  9656. e: function( event, dx ) {
  9657. return { width: this.originalSize.width + dx };
  9658. },
  9659. w: function( event, dx ) {
  9660. var cs = this.originalSize, sp = this.originalPosition;
  9661. return { left: sp.left + dx, width: cs.width - dx };
  9662. },
  9663. n: function( event, dx, dy ) {
  9664. var cs = this.originalSize, sp = this.originalPosition;
  9665. return { top: sp.top + dy, height: cs.height - dy };
  9666. },
  9667. s: function( event, dx, dy ) {
  9668. return { height: this.originalSize.height + dy };
  9669. },
  9670. se: function( event, dx, dy ) {
  9671. return $.extend( this._change.s.apply( this, arguments ),
  9672. this._change.e.apply( this, [ event, dx, dy ] ) );
  9673. },
  9674. sw: function( event, dx, dy ) {
  9675. return $.extend( this._change.s.apply( this, arguments ),
  9676. this._change.w.apply( this, [ event, dx, dy ] ) );
  9677. },
  9678. ne: function( event, dx, dy ) {
  9679. return $.extend( this._change.n.apply( this, arguments ),
  9680. this._change.e.apply( this, [ event, dx, dy ] ) );
  9681. },
  9682. nw: function( event, dx, dy ) {
  9683. return $.extend( this._change.n.apply( this, arguments ),
  9684. this._change.w.apply( this, [ event, dx, dy ] ) );
  9685. }
  9686. },
  9687. _propagate: function( n, event ) {
  9688. $.ui.plugin.call( this, n, [ event, this.ui() ] );
  9689. ( n !== "resize" && this._trigger( n, event, this.ui() ) );
  9690. },
  9691. plugins: {},
  9692. ui: function() {
  9693. return {
  9694. originalElement: this.originalElement,
  9695. element: this.element,
  9696. helper: this.helper,
  9697. position: this.position,
  9698. size: this.size,
  9699. originalSize: this.originalSize,
  9700. originalPosition: this.originalPosition
  9701. };
  9702. }
  9703. } );
  9704. /*
  9705. * Resizable Extensions
  9706. */
  9707. $.ui.plugin.add( "resizable", "animate", {
  9708. stop: function( event ) {
  9709. var that = $( this ).resizable( "instance" ),
  9710. o = that.options,
  9711. pr = that._proportionallyResizeElements,
  9712. ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
  9713. soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
  9714. soffsetw = ista ? 0 : that.sizeDiff.width,
  9715. style = {
  9716. width: ( that.size.width - soffsetw ),
  9717. height: ( that.size.height - soffseth )
  9718. },
  9719. left = ( parseFloat( that.element.css( "left" ) ) +
  9720. ( that.position.left - that.originalPosition.left ) ) || null,
  9721. top = ( parseFloat( that.element.css( "top" ) ) +
  9722. ( that.position.top - that.originalPosition.top ) ) || null;
  9723. that.element.animate(
  9724. $.extend( style, top && left ? { top: top, left: left } : {} ), {
  9725. duration: o.animateDuration,
  9726. easing: o.animateEasing,
  9727. step: function() {
  9728. var data = {
  9729. width: parseFloat( that.element.css( "width" ) ),
  9730. height: parseFloat( that.element.css( "height" ) ),
  9731. top: parseFloat( that.element.css( "top" ) ),
  9732. left: parseFloat( that.element.css( "left" ) )
  9733. };
  9734. if ( pr && pr.length ) {
  9735. $( pr[ 0 ] ).css( { width: data.width, height: data.height } );
  9736. }
  9737. // Propagating resize, and updating values for each animation step
  9738. that._updateCache( data );
  9739. that._propagate( "resize", event );
  9740. }
  9741. }
  9742. );
  9743. }
  9744. } );
  9745. $.ui.plugin.add( "resizable", "containment", {
  9746. start: function() {
  9747. var element, p, co, ch, cw, width, height,
  9748. that = $( this ).resizable( "instance" ),
  9749. o = that.options,
  9750. el = that.element,
  9751. oc = o.containment,
  9752. ce = ( oc instanceof $ ) ?
  9753. oc.get( 0 ) :
  9754. ( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
  9755. if ( !ce ) {
  9756. return;
  9757. }
  9758. that.containerElement = $( ce );
  9759. if ( /document/.test( oc ) || oc === document ) {
  9760. that.containerOffset = {
  9761. left: 0,
  9762. top: 0
  9763. };
  9764. that.containerPosition = {
  9765. left: 0,
  9766. top: 0
  9767. };
  9768. that.parentData = {
  9769. element: $( document ),
  9770. left: 0,
  9771. top: 0,
  9772. width: $( document ).width(),
  9773. height: $( document ).height() || document.body.parentNode.scrollHeight
  9774. };
  9775. } else {
  9776. element = $( ce );
  9777. p = [];
  9778. $( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
  9779. p[ i ] = that._num( element.css( "padding" + name ) );
  9780. } );
  9781. that.containerOffset = element.offset();
  9782. that.containerPosition = element.position();
  9783. that.containerSize = {
  9784. height: ( element.innerHeight() - p[ 3 ] ),
  9785. width: ( element.innerWidth() - p[ 1 ] )
  9786. };
  9787. co = that.containerOffset;
  9788. ch = that.containerSize.height;
  9789. cw = that.containerSize.width;
  9790. width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
  9791. height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
  9792. that.parentData = {
  9793. element: ce,
  9794. left: co.left,
  9795. top: co.top,
  9796. width: width,
  9797. height: height
  9798. };
  9799. }
  9800. },
  9801. resize: function( event ) {
  9802. var woset, hoset, isParent, isOffsetRelative,
  9803. that = $( this ).resizable( "instance" ),
  9804. o = that.options,
  9805. co = that.containerOffset,
  9806. cp = that.position,
  9807. pRatio = that._aspectRatio || event.shiftKey,
  9808. cop = {
  9809. top: 0,
  9810. left: 0
  9811. },
  9812. ce = that.containerElement,
  9813. continueResize = true;
  9814. if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
  9815. cop = co;
  9816. }
  9817. if ( cp.left < ( that._helper ? co.left : 0 ) ) {
  9818. that.size.width = that.size.width +
  9819. ( that._helper ?
  9820. ( that.position.left - co.left ) :
  9821. ( that.position.left - cop.left ) );
  9822. if ( pRatio ) {
  9823. that.size.height = that.size.width / that.aspectRatio;
  9824. continueResize = false;
  9825. }
  9826. that.position.left = o.helper ? co.left : 0;
  9827. }
  9828. if ( cp.top < ( that._helper ? co.top : 0 ) ) {
  9829. that.size.height = that.size.height +
  9830. ( that._helper ?
  9831. ( that.position.top - co.top ) :
  9832. that.position.top );
  9833. if ( pRatio ) {
  9834. that.size.width = that.size.height * that.aspectRatio;
  9835. continueResize = false;
  9836. }
  9837. that.position.top = that._helper ? co.top : 0;
  9838. }
  9839. isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
  9840. isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
  9841. if ( isParent && isOffsetRelative ) {
  9842. that.offset.left = that.parentData.left + that.position.left;
  9843. that.offset.top = that.parentData.top + that.position.top;
  9844. } else {
  9845. that.offset.left = that.element.offset().left;
  9846. that.offset.top = that.element.offset().top;
  9847. }
  9848. woset = Math.abs( that.sizeDiff.width +
  9849. ( that._helper ?
  9850. that.offset.left - cop.left :
  9851. ( that.offset.left - co.left ) ) );
  9852. hoset = Math.abs( that.sizeDiff.height +
  9853. ( that._helper ?
  9854. that.offset.top - cop.top :
  9855. ( that.offset.top - co.top ) ) );
  9856. if ( woset + that.size.width >= that.parentData.width ) {
  9857. that.size.width = that.parentData.width - woset;
  9858. if ( pRatio ) {
  9859. that.size.height = that.size.width / that.aspectRatio;
  9860. continueResize = false;
  9861. }
  9862. }
  9863. if ( hoset + that.size.height >= that.parentData.height ) {
  9864. that.size.height = that.parentData.height - hoset;
  9865. if ( pRatio ) {
  9866. that.size.width = that.size.height * that.aspectRatio;
  9867. continueResize = false;
  9868. }
  9869. }
  9870. if ( !continueResize ) {
  9871. that.position.left = that.prevPosition.left;
  9872. that.position.top = that.prevPosition.top;
  9873. that.size.width = that.prevSize.width;
  9874. that.size.height = that.prevSize.height;
  9875. }
  9876. },
  9877. stop: function() {
  9878. var that = $( this ).resizable( "instance" ),
  9879. o = that.options,
  9880. co = that.containerOffset,
  9881. cop = that.containerPosition,
  9882. ce = that.containerElement,
  9883. helper = $( that.helper ),
  9884. ho = helper.offset(),
  9885. w = helper.outerWidth() - that.sizeDiff.width,
  9886. h = helper.outerHeight() - that.sizeDiff.height;
  9887. if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
  9888. $( this ).css( {
  9889. left: ho.left - cop.left - co.left,
  9890. width: w,
  9891. height: h
  9892. } );
  9893. }
  9894. if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
  9895. $( this ).css( {
  9896. left: ho.left - cop.left - co.left,
  9897. width: w,
  9898. height: h
  9899. } );
  9900. }
  9901. }
  9902. } );
  9903. $.ui.plugin.add( "resizable", "alsoResize", {
  9904. start: function() {
  9905. var that = $( this ).resizable( "instance" ),
  9906. o = that.options;
  9907. $( o.alsoResize ).each( function() {
  9908. var el = $( this );
  9909. el.data( "ui-resizable-alsoresize", {
  9910. width: parseFloat( el.width() ), height: parseFloat( el.height() ),
  9911. left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
  9912. } );
  9913. } );
  9914. },
  9915. resize: function( event, ui ) {
  9916. var that = $( this ).resizable( "instance" ),
  9917. o = that.options,
  9918. os = that.originalSize,
  9919. op = that.originalPosition,
  9920. delta = {
  9921. height: ( that.size.height - os.height ) || 0,
  9922. width: ( that.size.width - os.width ) || 0,
  9923. top: ( that.position.top - op.top ) || 0,
  9924. left: ( that.position.left - op.left ) || 0
  9925. };
  9926. $( o.alsoResize ).each( function() {
  9927. var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
  9928. css = el.parents( ui.originalElement[ 0 ] ).length ?
  9929. [ "width", "height" ] :
  9930. [ "width", "height", "top", "left" ];
  9931. $.each( css, function( i, prop ) {
  9932. var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
  9933. if ( sum && sum >= 0 ) {
  9934. style[ prop ] = sum || null;
  9935. }
  9936. } );
  9937. el.css( style );
  9938. } );
  9939. },
  9940. stop: function() {
  9941. $( this ).removeData( "ui-resizable-alsoresize" );
  9942. }
  9943. } );
  9944. $.ui.plugin.add( "resizable", "ghost", {
  9945. start: function() {
  9946. var that = $( this ).resizable( "instance" ), cs = that.size;
  9947. that.ghost = that.originalElement.clone();
  9948. that.ghost.css( {
  9949. opacity: 0.25,
  9950. display: "block",
  9951. position: "relative",
  9952. height: cs.height,
  9953. width: cs.width,
  9954. margin: 0,
  9955. left: 0,
  9956. top: 0
  9957. } );
  9958. that._addClass( that.ghost, "ui-resizable-ghost" );
  9959. // DEPRECATED
  9960. // TODO: remove after 1.12
  9961. if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {
  9962. // Ghost option
  9963. that.ghost.addClass( this.options.ghost );
  9964. }
  9965. that.ghost.appendTo( that.helper );
  9966. },
  9967. resize: function() {
  9968. var that = $( this ).resizable( "instance" );
  9969. if ( that.ghost ) {
  9970. that.ghost.css( {
  9971. position: "relative",
  9972. height: that.size.height,
  9973. width: that.size.width
  9974. } );
  9975. }
  9976. },
  9977. stop: function() {
  9978. var that = $( this ).resizable( "instance" );
  9979. if ( that.ghost && that.helper ) {
  9980. that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
  9981. }
  9982. }
  9983. } );
  9984. $.ui.plugin.add( "resizable", "grid", {
  9985. resize: function() {
  9986. var outerDimensions,
  9987. that = $( this ).resizable( "instance" ),
  9988. o = that.options,
  9989. cs = that.size,
  9990. os = that.originalSize,
  9991. op = that.originalPosition,
  9992. a = that.axis,
  9993. grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
  9994. gridX = ( grid[ 0 ] || 1 ),
  9995. gridY = ( grid[ 1 ] || 1 ),
  9996. ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
  9997. oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
  9998. newWidth = os.width + ox,
  9999. newHeight = os.height + oy,
  10000. isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
  10001. isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
  10002. isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
  10003. isMinHeight = o.minHeight && ( o.minHeight > newHeight );
  10004. o.grid = grid;
  10005. if ( isMinWidth ) {
  10006. newWidth += gridX;
  10007. }
  10008. if ( isMinHeight ) {
  10009. newHeight += gridY;
  10010. }
  10011. if ( isMaxWidth ) {
  10012. newWidth -= gridX;
  10013. }
  10014. if ( isMaxHeight ) {
  10015. newHeight -= gridY;
  10016. }
  10017. if ( /^(se|s|e)$/.test( a ) ) {
  10018. that.size.width = newWidth;
  10019. that.size.height = newHeight;
  10020. } else if ( /^(ne)$/.test( a ) ) {
  10021. that.size.width = newWidth;
  10022. that.size.height = newHeight;
  10023. that.position.top = op.top - oy;
  10024. } else if ( /^(sw)$/.test( a ) ) {
  10025. that.size.width = newWidth;
  10026. that.size.height = newHeight;
  10027. that.position.left = op.left - ox;
  10028. } else {
  10029. if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
  10030. outerDimensions = that._getPaddingPlusBorderDimensions( this );
  10031. }
  10032. if ( newHeight - gridY > 0 ) {
  10033. that.size.height = newHeight;
  10034. that.position.top = op.top - oy;
  10035. } else {
  10036. newHeight = gridY - outerDimensions.height;
  10037. that.size.height = newHeight;
  10038. that.position.top = op.top + os.height - newHeight;
  10039. }
  10040. if ( newWidth - gridX > 0 ) {
  10041. that.size.width = newWidth;
  10042. that.position.left = op.left - ox;
  10043. } else {
  10044. newWidth = gridX - outerDimensions.width;
  10045. that.size.width = newWidth;
  10046. that.position.left = op.left + os.width - newWidth;
  10047. }
  10048. }
  10049. }
  10050. } );
  10051. var widgetsResizable = $.ui.resizable;
  10052. /*!
  10053. * jQuery UI Dialog 1.12.1
  10054. * http://jqueryui.com
  10055. *
  10056. * Copyright jQuery Foundation and other contributors
  10057. * Released under the MIT license.
  10058. * http://jquery.org/license
  10059. */
  10060. //>>label: Dialog
  10061. //>>group: Widgets
  10062. //>>description: Displays customizable dialog windows.
  10063. //>>docs: http://api.jqueryui.com/dialog/
  10064. //>>demos: http://jqueryui.com/dialog/
  10065. //>>css.structure: ../../themes/base/core.css
  10066. //>>css.structure: ../../themes/base/dialog.css
  10067. //>>css.theme: ../../themes/base/theme.css
  10068. $.widget( "ui.dialog", {
  10069. version: "1.12.1",
  10070. options: {
  10071. appendTo: "body",
  10072. autoOpen: true,
  10073. buttons: [],
  10074. classes: {
  10075. "ui-dialog": "ui-corner-all",
  10076. "ui-dialog-titlebar": "ui-corner-all"
  10077. },
  10078. closeOnEscape: true,
  10079. closeText: "Close",
  10080. draggable: true,
  10081. hide: null,
  10082. height: "auto",
  10083. maxHeight: null,
  10084. maxWidth: null,
  10085. minHeight: 150,
  10086. minWidth: 150,
  10087. modal: false,
  10088. position: {
  10089. my: "center",
  10090. at: "center",
  10091. of: window,
  10092. collision: "fit",
  10093. // Ensure the titlebar is always visible
  10094. using: function( pos ) {
  10095. var topOffset = $( this ).css( pos ).offset().top;
  10096. if ( topOffset < 0 ) {
  10097. $( this ).css( "top", pos.top - topOffset );
  10098. }
  10099. }
  10100. },
  10101. resizable: true,
  10102. show: null,
  10103. title: null,
  10104. width: 300,
  10105. // Callbacks
  10106. beforeClose: null,
  10107. close: null,
  10108. drag: null,
  10109. dragStart: null,
  10110. dragStop: null,
  10111. focus: null,
  10112. open: null,
  10113. resize: null,
  10114. resizeStart: null,
  10115. resizeStop: null
  10116. },
  10117. sizeRelatedOptions: {
  10118. buttons: true,
  10119. height: true,
  10120. maxHeight: true,
  10121. maxWidth: true,
  10122. minHeight: true,
  10123. minWidth: true,
  10124. width: true
  10125. },
  10126. resizableRelatedOptions: {
  10127. maxHeight: true,
  10128. maxWidth: true,
  10129. minHeight: true,
  10130. minWidth: true
  10131. },
  10132. _create: function() {
  10133. this.originalCss = {
  10134. display: this.element[ 0 ].style.display,
  10135. width: this.element[ 0 ].style.width,
  10136. minHeight: this.element[ 0 ].style.minHeight,
  10137. maxHeight: this.element[ 0 ].style.maxHeight,
  10138. height: this.element[ 0 ].style.height
  10139. };
  10140. this.originalPosition = {
  10141. parent: this.element.parent(),
  10142. index: this.element.parent().children().index( this.element )
  10143. };
  10144. this.originalTitle = this.element.attr( "title" );
  10145. if ( this.options.title == null && this.originalTitle != null ) {
  10146. this.options.title = this.originalTitle;
  10147. }
  10148. // Dialogs can't be disabled
  10149. if ( this.options.disabled ) {
  10150. this.options.disabled = false;
  10151. }
  10152. this._createWrapper();
  10153. this.element
  10154. .show()
  10155. .removeAttr( "title" )
  10156. .appendTo( this.uiDialog );
  10157. this._addClass( "ui-dialog-content", "ui-widget-content" );
  10158. this._createTitlebar();
  10159. this._createButtonPane();
  10160. if ( this.options.draggable && $.fn.draggable ) {
  10161. this._makeDraggable();
  10162. }
  10163. if ( this.options.resizable && $.fn.resizable ) {
  10164. this._makeResizable();
  10165. }
  10166. this._isOpen = false;
  10167. this._trackFocus();
  10168. },
  10169. _init: function() {
  10170. if ( this.options.autoOpen ) {
  10171. this.open();
  10172. }
  10173. },
  10174. _appendTo: function() {
  10175. var element = this.options.appendTo;
  10176. if ( element && ( element.jquery || element.nodeType ) ) {
  10177. return $( element );
  10178. }
  10179. return this.document.find( element || "body" ).eq( 0 );
  10180. },
  10181. _destroy: function() {
  10182. var next,
  10183. originalPosition = this.originalPosition;
  10184. this._untrackInstance();
  10185. this._destroyOverlay();
  10186. this.element
  10187. .removeUniqueId()
  10188. .css( this.originalCss )
  10189. // Without detaching first, the following becomes really slow
  10190. .detach();
  10191. this.uiDialog.remove();
  10192. if ( this.originalTitle ) {
  10193. this.element.attr( "title", this.originalTitle );
  10194. }
  10195. next = originalPosition.parent.children().eq( originalPosition.index );
  10196. // Don't try to place the dialog next to itself (#8613)
  10197. if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
  10198. next.before( this.element );
  10199. } else {
  10200. originalPosition.parent.append( this.element );
  10201. }
  10202. },
  10203. widget: function() {
  10204. return this.uiDialog;
  10205. },
  10206. disable: $.noop,
  10207. enable: $.noop,
  10208. close: function( event ) {
  10209. var that = this;
  10210. if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
  10211. return;
  10212. }
  10213. this._isOpen = false;
  10214. this._focusedElement = null;
  10215. this._destroyOverlay();
  10216. this._untrackInstance();
  10217. if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {
  10218. // Hiding a focused element doesn't trigger blur in WebKit
  10219. // so in case we have nothing to focus on, explicitly blur the active element
  10220. // https://bugs.webkit.org/show_bug.cgi?id=47182
  10221. $.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
  10222. }
  10223. this._hide( this.uiDialog, this.options.hide, function() {
  10224. that._trigger( "close", event );
  10225. } );
  10226. },
  10227. isOpen: function() {
  10228. return this._isOpen;
  10229. },
  10230. moveToTop: function() {
  10231. this._moveToTop();
  10232. },
  10233. _moveToTop: function( event, silent ) {
  10234. var moved = false,
  10235. zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
  10236. return +$( this ).css( "z-index" );
  10237. } ).get(),
  10238. zIndexMax = Math.max.apply( null, zIndices );
  10239. if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
  10240. this.uiDialog.css( "z-index", zIndexMax + 1 );
  10241. moved = true;
  10242. }
  10243. if ( moved && !silent ) {
  10244. this._trigger( "focus", event );
  10245. }
  10246. return moved;
  10247. },
  10248. open: function() {
  10249. var that = this;
  10250. if ( this._isOpen ) {
  10251. if ( this._moveToTop() ) {
  10252. this._focusTabbable();
  10253. }
  10254. return;
  10255. }
  10256. this._isOpen = true;
  10257. this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
  10258. this._size();
  10259. this._position();
  10260. this._createOverlay();
  10261. this._moveToTop( null, true );
  10262. // Ensure the overlay is moved to the top with the dialog, but only when
  10263. // opening. The overlay shouldn't move after the dialog is open so that
  10264. // modeless dialogs opened after the modal dialog stack properly.
  10265. if ( this.overlay ) {
  10266. this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
  10267. }
  10268. this._show( this.uiDialog, this.options.show, function() {
  10269. that._focusTabbable();
  10270. that._trigger( "focus" );
  10271. } );
  10272. // Track the dialog immediately upon openening in case a focus event
  10273. // somehow occurs outside of the dialog before an element inside the
  10274. // dialog is focused (#10152)
  10275. this._makeFocusTarget();
  10276. this._trigger( "open" );
  10277. },
  10278. _focusTabbable: function() {
  10279. // Set focus to the first match:
  10280. // 1. An element that was focused previously
  10281. // 2. First element inside the dialog matching [autofocus]
  10282. // 3. Tabbable element inside the content element
  10283. // 4. Tabbable element inside the buttonpane
  10284. // 5. The close button
  10285. // 6. The dialog itself
  10286. var hasFocus = this._focusedElement;
  10287. if ( !hasFocus ) {
  10288. hasFocus = this.element.find( "[autofocus]" );
  10289. }
  10290. if ( !hasFocus.length ) {
  10291. hasFocus = this.element.find( ":tabbable" );
  10292. }
  10293. if ( !hasFocus.length ) {
  10294. hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
  10295. }
  10296. if ( !hasFocus.length ) {
  10297. hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
  10298. }
  10299. if ( !hasFocus.length ) {
  10300. hasFocus = this.uiDialog;
  10301. }
  10302. hasFocus.eq( 0 ).trigger( "focus" );
  10303. },
  10304. _keepFocus: function( event ) {
  10305. function checkFocus() {
  10306. var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
  10307. isActive = this.uiDialog[ 0 ] === activeElement ||
  10308. $.contains( this.uiDialog[ 0 ], activeElement );
  10309. if ( !isActive ) {
  10310. this._focusTabbable();
  10311. }
  10312. }
  10313. event.preventDefault();
  10314. checkFocus.call( this );
  10315. // support: IE
  10316. // IE <= 8 doesn't prevent moving focus even with event.preventDefault()
  10317. // so we check again later
  10318. this._delay( checkFocus );
  10319. },
  10320. _createWrapper: function() {
  10321. this.uiDialog = $( "<div>" )
  10322. .hide()
  10323. .attr( {
  10324. // Setting tabIndex makes the div focusable
  10325. tabIndex: -1,
  10326. role: "dialog"
  10327. } )
  10328. .appendTo( this._appendTo() );
  10329. this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
  10330. this._on( this.uiDialog, {
  10331. keydown: function( event ) {
  10332. if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
  10333. event.keyCode === $.ui.keyCode.ESCAPE ) {
  10334. event.preventDefault();
  10335. this.close( event );
  10336. return;
  10337. }
  10338. // Prevent tabbing out of dialogs
  10339. if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
  10340. return;
  10341. }
  10342. var tabbables = this.uiDialog.find( ":tabbable" ),
  10343. first = tabbables.filter( ":first" ),
  10344. last = tabbables.filter( ":last" );
  10345. if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
  10346. !event.shiftKey ) {
  10347. this._delay( function() {
  10348. first.trigger( "focus" );
  10349. } );
  10350. event.preventDefault();
  10351. } else if ( ( event.target === first[ 0 ] ||
  10352. event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
  10353. this._delay( function() {
  10354. last.trigger( "focus" );
  10355. } );
  10356. event.preventDefault();
  10357. }
  10358. },
  10359. mousedown: function( event ) {
  10360. if ( this._moveToTop( event ) ) {
  10361. this._focusTabbable();
  10362. }
  10363. }
  10364. } );
  10365. // We assume that any existing aria-describedby attribute means
  10366. // that the dialog content is marked up properly
  10367. // otherwise we brute force the content as the description
  10368. if ( !this.element.find( "[aria-describedby]" ).length ) {
  10369. this.uiDialog.attr( {
  10370. "aria-describedby": this.element.uniqueId().attr( "id" )
  10371. } );
  10372. }
  10373. },
  10374. _createTitlebar: function() {
  10375. var uiDialogTitle;
  10376. this.uiDialogTitlebar = $( "<div>" );
  10377. this._addClass( this.uiDialogTitlebar,
  10378. "ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
  10379. this._on( this.uiDialogTitlebar, {
  10380. mousedown: function( event ) {
  10381. // Don't prevent click on close button (#8838)
  10382. // Focusing a dialog that is partially scrolled out of view
  10383. // causes the browser to scroll it into view, preventing the click event
  10384. if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
  10385. // Dialog isn't getting focus when dragging (#8063)
  10386. this.uiDialog.trigger( "focus" );
  10387. }
  10388. }
  10389. } );
  10390. // Support: IE
  10391. // Use type="button" to prevent enter keypresses in textboxes from closing the
  10392. // dialog in IE (#9312)
  10393. this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
  10394. .button( {
  10395. label: $( "<a>" ).text( this.options.closeText ).html(),
  10396. icon: "ui-icon-closethick",
  10397. showLabel: false
  10398. } )
  10399. .appendTo( this.uiDialogTitlebar );
  10400. this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
  10401. this._on( this.uiDialogTitlebarClose, {
  10402. click: function( event ) {
  10403. event.preventDefault();
  10404. this.close( event );
  10405. }
  10406. } );
  10407. uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
  10408. this._addClass( uiDialogTitle, "ui-dialog-title" );
  10409. this._title( uiDialogTitle );
  10410. this.uiDialogTitlebar.prependTo( this.uiDialog );
  10411. this.uiDialog.attr( {
  10412. "aria-labelledby": uiDialogTitle.attr( "id" )
  10413. } );
  10414. },
  10415. _title: function( title ) {
  10416. if ( this.options.title ) {
  10417. title.text( this.options.title );
  10418. } else {
  10419. title.html( "&#160;" );
  10420. }
  10421. },
  10422. _createButtonPane: function() {
  10423. this.uiDialogButtonPane = $( "<div>" );
  10424. this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
  10425. "ui-widget-content ui-helper-clearfix" );
  10426. this.uiButtonSet = $( "<div>" )
  10427. .appendTo( this.uiDialogButtonPane );
  10428. this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );
  10429. this._createButtons();
  10430. },
  10431. _createButtons: function() {
  10432. var that = this,
  10433. buttons = this.options.buttons;
  10434. // If we already have a button pane, remove it
  10435. this.uiDialogButtonPane.remove();
  10436. this.uiButtonSet.empty();
  10437. if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
  10438. this._removeClass( this.uiDialog, "ui-dialog-buttons" );
  10439. return;
  10440. }
  10441. $.each( buttons, function( name, props ) {
  10442. var click, buttonOptions;
  10443. props = $.isFunction( props ) ?
  10444. { click: props, text: name } :
  10445. props;
  10446. // Default to a non-submitting button
  10447. props = $.extend( { type: "button" }, props );
  10448. // Change the context for the click callback to be the main element
  10449. click = props.click;
  10450. buttonOptions = {
  10451. icon: props.icon,
  10452. iconPosition: props.iconPosition,
  10453. showLabel: props.showLabel,
  10454. // Deprecated options
  10455. icons: props.icons,
  10456. text: props.text
  10457. };
  10458. delete props.click;
  10459. delete props.icon;
  10460. delete props.iconPosition;
  10461. delete props.showLabel;
  10462. // Deprecated options
  10463. delete props.icons;
  10464. if ( typeof props.text === "boolean" ) {
  10465. delete props.text;
  10466. }
  10467. $( "<button></button>", props )
  10468. .button( buttonOptions )
  10469. .appendTo( that.uiButtonSet )
  10470. .on( "click", function() {
  10471. click.apply( that.element[ 0 ], arguments );
  10472. } );
  10473. } );
  10474. this._addClass( this.uiDialog, "ui-dialog-buttons" );
  10475. this.uiDialogButtonPane.appendTo( this.uiDialog );
  10476. },
  10477. _makeDraggable: function() {
  10478. var that = this,
  10479. options = this.options;
  10480. function filteredUi( ui ) {
  10481. return {
  10482. position: ui.position,
  10483. offset: ui.offset
  10484. };
  10485. }
  10486. this.uiDialog.draggable( {
  10487. cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
  10488. handle: ".ui-dialog-titlebar",
  10489. containment: "document",
  10490. start: function( event, ui ) {
  10491. that._addClass( $( this ), "ui-dialog-dragging" );
  10492. that._blockFrames();
  10493. that._trigger( "dragStart", event, filteredUi( ui ) );
  10494. },
  10495. drag: function( event, ui ) {
  10496. that._trigger( "drag", event, filteredUi( ui ) );
  10497. },
  10498. stop: function( event, ui ) {
  10499. var left = ui.offset.left - that.document.scrollLeft(),
  10500. top = ui.offset.top - that.document.scrollTop();
  10501. options.position = {
  10502. my: "left top",
  10503. at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
  10504. "top" + ( top >= 0 ? "+" : "" ) + top,
  10505. of: that.window
  10506. };
  10507. that._removeClass( $( this ), "ui-dialog-dragging" );
  10508. that._unblockFrames();
  10509. that._trigger( "dragStop", event, filteredUi( ui ) );
  10510. }
  10511. } );
  10512. },
  10513. _makeResizable: function() {
  10514. var that = this,
  10515. options = this.options,
  10516. handles = options.resizable,
  10517. // .ui-resizable has position: relative defined in the stylesheet
  10518. // but dialogs have to use absolute or fixed positioning
  10519. position = this.uiDialog.css( "position" ),
  10520. resizeHandles = typeof handles === "string" ?
  10521. handles :
  10522. "n,e,s,w,se,sw,ne,nw";
  10523. function filteredUi( ui ) {
  10524. return {
  10525. originalPosition: ui.originalPosition,
  10526. originalSize: ui.originalSize,
  10527. position: ui.position,
  10528. size: ui.size
  10529. };
  10530. }
  10531. this.uiDialog.resizable( {
  10532. cancel: ".ui-dialog-content",
  10533. containment: "document",
  10534. alsoResize: this.element,
  10535. maxWidth: options.maxWidth,
  10536. maxHeight: options.maxHeight,
  10537. minWidth: options.minWidth,
  10538. minHeight: this._minHeight(),
  10539. handles: resizeHandles,
  10540. start: function( event, ui ) {
  10541. that._addClass( $( this ), "ui-dialog-resizing" );
  10542. that._blockFrames();
  10543. that._trigger( "resizeStart", event, filteredUi( ui ) );
  10544. },
  10545. resize: function( event, ui ) {
  10546. that._trigger( "resize", event, filteredUi( ui ) );
  10547. },
  10548. stop: function( event, ui ) {
  10549. var offset = that.uiDialog.offset(),
  10550. left = offset.left - that.document.scrollLeft(),
  10551. top = offset.top - that.document.scrollTop();
  10552. options.height = that.uiDialog.height();
  10553. options.width = that.uiDialog.width();
  10554. options.position = {
  10555. my: "left top",
  10556. at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
  10557. "top" + ( top >= 0 ? "+" : "" ) + top,
  10558. of: that.window
  10559. };
  10560. that._removeClass( $( this ), "ui-dialog-resizing" );
  10561. that._unblockFrames();
  10562. that._trigger( "resizeStop", event, filteredUi( ui ) );
  10563. }
  10564. } )
  10565. .css( "position", position );
  10566. },
  10567. _trackFocus: function() {
  10568. this._on( this.widget(), {
  10569. focusin: function( event ) {
  10570. this._makeFocusTarget();
  10571. this._focusedElement = $( event.target );
  10572. }
  10573. } );
  10574. },
  10575. _makeFocusTarget: function() {
  10576. this._untrackInstance();
  10577. this._trackingInstances().unshift( this );
  10578. },
  10579. _untrackInstance: function() {
  10580. var instances = this._trackingInstances(),
  10581. exists = $.inArray( this, instances );
  10582. if ( exists !== -1 ) {
  10583. instances.splice( exists, 1 );
  10584. }
  10585. },
  10586. _trackingInstances: function() {
  10587. var instances = this.document.data( "ui-dialog-instances" );
  10588. if ( !instances ) {
  10589. instances = [];
  10590. this.document.data( "ui-dialog-instances", instances );
  10591. }
  10592. return instances;
  10593. },
  10594. _minHeight: function() {
  10595. var options = this.options;
  10596. return options.height === "auto" ?
  10597. options.minHeight :
  10598. Math.min( options.minHeight, options.height );
  10599. },
  10600. _position: function() {
  10601. // Need to show the dialog to get the actual offset in the position plugin
  10602. var isVisible = this.uiDialog.is( ":visible" );
  10603. if ( !isVisible ) {
  10604. this.uiDialog.show();
  10605. }
  10606. this.uiDialog.position( this.options.position );
  10607. if ( !isVisible ) {
  10608. this.uiDialog.hide();
  10609. }
  10610. },
  10611. _setOptions: function( options ) {
  10612. var that = this,
  10613. resize = false,
  10614. resizableOptions = {};
  10615. $.each( options, function( key, value ) {
  10616. that._setOption( key, value );
  10617. if ( key in that.sizeRelatedOptions ) {
  10618. resize = true;
  10619. }
  10620. if ( key in that.resizableRelatedOptions ) {
  10621. resizableOptions[ key ] = value;
  10622. }
  10623. } );
  10624. if ( resize ) {
  10625. this._size();
  10626. this._position();
  10627. }
  10628. if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
  10629. this.uiDialog.resizable( "option", resizableOptions );
  10630. }
  10631. },
  10632. _setOption: function( key, value ) {
  10633. var isDraggable, isResizable,
  10634. uiDialog = this.uiDialog;
  10635. if ( key === "disabled" ) {
  10636. return;
  10637. }
  10638. this._super( key, value );
  10639. if ( key === "appendTo" ) {
  10640. this.uiDialog.appendTo( this._appendTo() );
  10641. }
  10642. if ( key === "buttons" ) {
  10643. this._createButtons();
  10644. }
  10645. if ( key === "closeText" ) {
  10646. this.uiDialogTitlebarClose.button( {
  10647. // Ensure that we always pass a string
  10648. label: $( "<a>" ).text( "" + this.options.closeText ).html()
  10649. } );
  10650. }
  10651. if ( key === "draggable" ) {
  10652. isDraggable = uiDialog.is( ":data(ui-draggable)" );
  10653. if ( isDraggable && !value ) {
  10654. uiDialog.draggable( "destroy" );
  10655. }
  10656. if ( !isDraggable && value ) {
  10657. this._makeDraggable();
  10658. }
  10659. }
  10660. if ( key === "position" ) {
  10661. this._position();
  10662. }
  10663. if ( key === "resizable" ) {
  10664. // currently resizable, becoming non-resizable
  10665. isResizable = uiDialog.is( ":data(ui-resizable)" );
  10666. if ( isResizable && !value ) {
  10667. uiDialog.resizable( "destroy" );
  10668. }
  10669. // Currently resizable, changing handles
  10670. if ( isResizable && typeof value === "string" ) {
  10671. uiDialog.resizable( "option", "handles", value );
  10672. }
  10673. // Currently non-resizable, becoming resizable
  10674. if ( !isResizable && value !== false ) {
  10675. this._makeResizable();
  10676. }
  10677. }
  10678. if ( key === "title" ) {
  10679. this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
  10680. }
  10681. },
  10682. _size: function() {
  10683. // If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
  10684. // divs will both have width and height set, so we need to reset them
  10685. var nonContentHeight, minContentHeight, maxContentHeight,
  10686. options = this.options;
  10687. // Reset content sizing
  10688. this.element.show().css( {
  10689. width: "auto",
  10690. minHeight: 0,
  10691. maxHeight: "none",
  10692. height: 0
  10693. } );
  10694. if ( options.minWidth > options.width ) {
  10695. options.width = options.minWidth;
  10696. }
  10697. // Reset wrapper sizing
  10698. // determine the height of all the non-content elements
  10699. nonContentHeight = this.uiDialog.css( {
  10700. height: "auto",
  10701. width: options.width
  10702. } )
  10703. .outerHeight();
  10704. minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
  10705. maxContentHeight = typeof options.maxHeight === "number" ?
  10706. Math.max( 0, options.maxHeight - nonContentHeight ) :
  10707. "none";
  10708. if ( options.height === "auto" ) {
  10709. this.element.css( {
  10710. minHeight: minContentHeight,
  10711. maxHeight: maxContentHeight,
  10712. height: "auto"
  10713. } );
  10714. } else {
  10715. this.element.height( Math.max( 0, options.height - nonContentHeight ) );
  10716. }
  10717. if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
  10718. this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
  10719. }
  10720. },
  10721. _blockFrames: function() {
  10722. this.iframeBlocks = this.document.find( "iframe" ).map( function() {
  10723. var iframe = $( this );
  10724. return $( "<div>" )
  10725. .css( {
  10726. position: "absolute",
  10727. width: iframe.outerWidth(),
  10728. height: iframe.outerHeight()
  10729. } )
  10730. .appendTo( iframe.parent() )
  10731. .offset( iframe.offset() )[ 0 ];
  10732. } );
  10733. },
  10734. _unblockFrames: function() {
  10735. if ( this.iframeBlocks ) {
  10736. this.iframeBlocks.remove();
  10737. delete this.iframeBlocks;
  10738. }
  10739. },
  10740. _allowInteraction: function( event ) {
  10741. if ( $( event.target ).closest( ".ui-dialog" ).length ) {
  10742. return true;
  10743. }
  10744. // TODO: Remove hack when datepicker implements
  10745. // the .ui-front logic (#8989)
  10746. return !!$( event.target ).closest( ".ui-datepicker" ).length;
  10747. },
  10748. _createOverlay: function() {
  10749. if ( !this.options.modal ) {
  10750. return;
  10751. }
  10752. // We use a delay in case the overlay is created from an
  10753. // event that we're going to be cancelling (#2804)
  10754. var isOpening = true;
  10755. this._delay( function() {
  10756. isOpening = false;
  10757. } );
  10758. if ( !this.document.data( "ui-dialog-overlays" ) ) {
  10759. // Prevent use of anchors and inputs
  10760. // Using _on() for an event handler shared across many instances is
  10761. // safe because the dialogs stack and must be closed in reverse order
  10762. this._on( this.document, {
  10763. focusin: function( event ) {
  10764. if ( isOpening ) {
  10765. return;
  10766. }
  10767. if ( !this._allowInteraction( event ) ) {
  10768. event.preventDefault();
  10769. this._trackingInstances()[ 0 ]._focusTabbable();
  10770. }
  10771. }
  10772. } );
  10773. }
  10774. this.overlay = $( "<div>" )
  10775. .appendTo( this._appendTo() );
  10776. this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
  10777. this._on( this.overlay, {
  10778. mousedown: "_keepFocus"
  10779. } );
  10780. this.document.data( "ui-dialog-overlays",
  10781. ( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
  10782. },
  10783. _destroyOverlay: function() {
  10784. if ( !this.options.modal ) {
  10785. return;
  10786. }
  10787. if ( this.overlay ) {
  10788. var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
  10789. if ( !overlays ) {
  10790. this._off( this.document, "focusin" );
  10791. this.document.removeData( "ui-dialog-overlays" );
  10792. } else {
  10793. this.document.data( "ui-dialog-overlays", overlays );
  10794. }
  10795. this.overlay.remove();
  10796. this.overlay = null;
  10797. }
  10798. }
  10799. } );
  10800. // DEPRECATED
  10801. // TODO: switch return back to widget declaration at top of file when this is removed
  10802. if ( $.uiBackCompat !== false ) {
  10803. // Backcompat for dialogClass option
  10804. $.widget( "ui.dialog", $.ui.dialog, {
  10805. options: {
  10806. dialogClass: ""
  10807. },
  10808. _createWrapper: function() {
  10809. this._super();
  10810. this.uiDialog.addClass( this.options.dialogClass );
  10811. },
  10812. _setOption: function( key, value ) {
  10813. if ( key === "dialogClass" ) {
  10814. this.uiDialog
  10815. .removeClass( this.options.dialogClass )
  10816. .addClass( value );
  10817. }
  10818. this._superApply( arguments );
  10819. }
  10820. } );
  10821. }
  10822. var widgetsDialog = $.ui.dialog;
  10823. /*!
  10824. * jQuery UI Droppable 1.12.1
  10825. * http://jqueryui.com
  10826. *
  10827. * Copyright jQuery Foundation and other contributors
  10828. * Released under the MIT license.
  10829. * http://jquery.org/license
  10830. */
  10831. //>>label: Droppable
  10832. //>>group: Interactions
  10833. //>>description: Enables drop targets for draggable elements.
  10834. //>>docs: http://api.jqueryui.com/droppable/
  10835. //>>demos: http://jqueryui.com/droppable/
  10836. $.widget( "ui.droppable", {
  10837. version: "1.12.1",
  10838. widgetEventPrefix: "drop",
  10839. options: {
  10840. accept: "*",
  10841. addClasses: true,
  10842. greedy: false,
  10843. scope: "default",
  10844. tolerance: "intersect",
  10845. // Callbacks
  10846. activate: null,
  10847. deactivate: null,
  10848. drop: null,
  10849. out: null,
  10850. over: null
  10851. },
  10852. _create: function() {
  10853. var proportions,
  10854. o = this.options,
  10855. accept = o.accept;
  10856. this.isover = false;
  10857. this.isout = true;
  10858. this.accept = $.isFunction( accept ) ? accept : function( d ) {
  10859. return d.is( accept );
  10860. };
  10861. this.proportions = function( /* valueToWrite */ ) {
  10862. if ( arguments.length ) {
  10863. // Store the droppable's proportions
  10864. proportions = arguments[ 0 ];
  10865. } else {
  10866. // Retrieve or derive the droppable's proportions
  10867. return proportions ?
  10868. proportions :
  10869. proportions = {
  10870. width: this.element[ 0 ].offsetWidth,
  10871. height: this.element[ 0 ].offsetHeight
  10872. };
  10873. }
  10874. };
  10875. this._addToManager( o.scope );
  10876. o.addClasses && this._addClass( "ui-droppable" );
  10877. },
  10878. _addToManager: function( scope ) {
  10879. // Add the reference and positions to the manager
  10880. $.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
  10881. $.ui.ddmanager.droppables[ scope ].push( this );
  10882. },
  10883. _splice: function( drop ) {
  10884. var i = 0;
  10885. for ( ; i < drop.length; i++ ) {
  10886. if ( drop[ i ] === this ) {
  10887. drop.splice( i, 1 );
  10888. }
  10889. }
  10890. },
  10891. _destroy: function() {
  10892. var drop = $.ui.ddmanager.droppables[ this.options.scope ];
  10893. this._splice( drop );
  10894. },
  10895. _setOption: function( key, value ) {
  10896. if ( key === "accept" ) {
  10897. this.accept = $.isFunction( value ) ? value : function( d ) {
  10898. return d.is( value );
  10899. };
  10900. } else if ( key === "scope" ) {
  10901. var drop = $.ui.ddmanager.droppables[ this.options.scope ];
  10902. this._splice( drop );
  10903. this._addToManager( value );
  10904. }
  10905. this._super( key, value );
  10906. },
  10907. _activate: function( event ) {
  10908. var draggable = $.ui.ddmanager.current;
  10909. this._addActiveClass();
  10910. if ( draggable ) {
  10911. this._trigger( "activate", event, this.ui( draggable ) );
  10912. }
  10913. },
  10914. _deactivate: function( event ) {
  10915. var draggable = $.ui.ddmanager.current;
  10916. this._removeActiveClass();
  10917. if ( draggable ) {
  10918. this._trigger( "deactivate", event, this.ui( draggable ) );
  10919. }
  10920. },
  10921. _over: function( event ) {
  10922. var draggable = $.ui.ddmanager.current;
  10923. // Bail if draggable and droppable are same element
  10924. if ( !draggable || ( draggable.currentItem ||
  10925. draggable.element )[ 0 ] === this.element[ 0 ] ) {
  10926. return;
  10927. }
  10928. if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
  10929. draggable.element ) ) ) {
  10930. this._addHoverClass();
  10931. this._trigger( "over", event, this.ui( draggable ) );
  10932. }
  10933. },
  10934. _out: function( event ) {
  10935. var draggable = $.ui.ddmanager.current;
  10936. // Bail if draggable and droppable are same element
  10937. if ( !draggable || ( draggable.currentItem ||
  10938. draggable.element )[ 0 ] === this.element[ 0 ] ) {
  10939. return;
  10940. }
  10941. if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
  10942. draggable.element ) ) ) {
  10943. this._removeHoverClass();
  10944. this._trigger( "out", event, this.ui( draggable ) );
  10945. }
  10946. },
  10947. _drop: function( event, custom ) {
  10948. var draggable = custom || $.ui.ddmanager.current,
  10949. childrenIntersection = false;
  10950. // Bail if draggable and droppable are same element
  10951. if ( !draggable || ( draggable.currentItem ||
  10952. draggable.element )[ 0 ] === this.element[ 0 ] ) {
  10953. return false;
  10954. }
  10955. this.element
  10956. .find( ":data(ui-droppable)" )
  10957. .not( ".ui-draggable-dragging" )
  10958. .each( function() {
  10959. var inst = $( this ).droppable( "instance" );
  10960. if (
  10961. inst.options.greedy &&
  10962. !inst.options.disabled &&
  10963. inst.options.scope === draggable.options.scope &&
  10964. inst.accept.call(
  10965. inst.element[ 0 ], ( draggable.currentItem || draggable.element )
  10966. ) &&
  10967. intersect(
  10968. draggable,
  10969. $.extend( inst, { offset: inst.element.offset() } ),
  10970. inst.options.tolerance, event
  10971. )
  10972. ) {
  10973. childrenIntersection = true;
  10974. return false; }
  10975. } );
  10976. if ( childrenIntersection ) {
  10977. return false;
  10978. }
  10979. if ( this.accept.call( this.element[ 0 ],
  10980. ( draggable.currentItem || draggable.element ) ) ) {
  10981. this._removeActiveClass();
  10982. this._removeHoverClass();
  10983. this._trigger( "drop", event, this.ui( draggable ) );
  10984. return this.element;
  10985. }
  10986. return false;
  10987. },
  10988. ui: function( c ) {
  10989. return {
  10990. draggable: ( c.currentItem || c.element ),
  10991. helper: c.helper,
  10992. position: c.position,
  10993. offset: c.positionAbs
  10994. };
  10995. },
  10996. // Extension points just to make backcompat sane and avoid duplicating logic
  10997. // TODO: Remove in 1.13 along with call to it below
  10998. _addHoverClass: function() {
  10999. this._addClass( "ui-droppable-hover" );
  11000. },
  11001. _removeHoverClass: function() {
  11002. this._removeClass( "ui-droppable-hover" );
  11003. },
  11004. _addActiveClass: function() {
  11005. this._addClass( "ui-droppable-active" );
  11006. },
  11007. _removeActiveClass: function() {
  11008. this._removeClass( "ui-droppable-active" );
  11009. }
  11010. } );
  11011. var intersect = $.ui.intersect = ( function() {
  11012. function isOverAxis( x, reference, size ) {
  11013. return ( x >= reference ) && ( x < ( reference + size ) );
  11014. }
  11015. return function( draggable, droppable, toleranceMode, event ) {
  11016. if ( !droppable.offset ) {
  11017. return false;
  11018. }
  11019. var x1 = ( draggable.positionAbs ||
  11020. draggable.position.absolute ).left + draggable.margins.left,
  11021. y1 = ( draggable.positionAbs ||
  11022. draggable.position.absolute ).top + draggable.margins.top,
  11023. x2 = x1 + draggable.helperProportions.width,
  11024. y2 = y1 + draggable.helperProportions.height,
  11025. l = droppable.offset.left,
  11026. t = droppable.offset.top,
  11027. r = l + droppable.proportions().width,
  11028. b = t + droppable.proportions().height;
  11029. switch ( toleranceMode ) {
  11030. case "fit":
  11031. return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
  11032. case "intersect":
  11033. return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
  11034. x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
  11035. t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
  11036. y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
  11037. case "pointer":
  11038. return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
  11039. isOverAxis( event.pageX, l, droppable.proportions().width );
  11040. case "touch":
  11041. return (
  11042. ( y1 >= t && y1 <= b ) || // Top edge touching
  11043. ( y2 >= t && y2 <= b ) || // Bottom edge touching
  11044. ( y1 < t && y2 > b ) // Surrounded vertically
  11045. ) && (
  11046. ( x1 >= l && x1 <= r ) || // Left edge touching
  11047. ( x2 >= l && x2 <= r ) || // Right edge touching
  11048. ( x1 < l && x2 > r ) // Surrounded horizontally
  11049. );
  11050. default:
  11051. return false;
  11052. }
  11053. };
  11054. } )();
  11055. /*
  11056. This manager tracks offsets of draggables and droppables
  11057. */
  11058. $.ui.ddmanager = {
  11059. current: null,
  11060. droppables: { "default": [] },
  11061. prepareOffsets: function( t, event ) {
  11062. var i, j,
  11063. m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
  11064. type = event ? event.type : null, // workaround for #2317
  11065. list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
  11066. droppablesLoop: for ( i = 0; i < m.length; i++ ) {
  11067. // No disabled and non-accepted
  11068. if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
  11069. ( t.currentItem || t.element ) ) ) ) {
  11070. continue;
  11071. }
  11072. // Filter out elements in the current dragged item
  11073. for ( j = 0; j < list.length; j++ ) {
  11074. if ( list[ j ] === m[ i ].element[ 0 ] ) {
  11075. m[ i ].proportions().height = 0;
  11076. continue droppablesLoop;
  11077. }
  11078. }
  11079. m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
  11080. if ( !m[ i ].visible ) {
  11081. continue;
  11082. }
  11083. // Activate the droppable if used directly from draggables
  11084. if ( type === "mousedown" ) {
  11085. m[ i ]._activate.call( m[ i ], event );
  11086. }
  11087. m[ i ].offset = m[ i ].element.offset();
  11088. m[ i ].proportions( {
  11089. width: m[ i ].element[ 0 ].offsetWidth,
  11090. height: m[ i ].element[ 0 ].offsetHeight
  11091. } );
  11092. }
  11093. },
  11094. drop: function( draggable, event ) {
  11095. var dropped = false;
  11096. // Create a copy of the droppables in case the list changes during the drop (#9116)
  11097. $.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
  11098. if ( !this.options ) {
  11099. return;
  11100. }
  11101. if ( !this.options.disabled && this.visible &&
  11102. intersect( draggable, this, this.options.tolerance, event ) ) {
  11103. dropped = this._drop.call( this, event ) || dropped;
  11104. }
  11105. if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
  11106. ( draggable.currentItem || draggable.element ) ) ) {
  11107. this.isout = true;
  11108. this.isover = false;
  11109. this._deactivate.call( this, event );
  11110. }
  11111. } );
  11112. return dropped;
  11113. },
  11114. dragStart: function( draggable, event ) {
  11115. // Listen for scrolling so that if the dragging causes scrolling the position of the
  11116. // droppables can be recalculated (see #5003)
  11117. draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
  11118. if ( !draggable.options.refreshPositions ) {
  11119. $.ui.ddmanager.prepareOffsets( draggable, event );
  11120. }
  11121. } );
  11122. },
  11123. drag: function( draggable, event ) {
  11124. // If you have a highly dynamic page, you might try this option. It renders positions
  11125. // every time you move the mouse.
  11126. if ( draggable.options.refreshPositions ) {
  11127. $.ui.ddmanager.prepareOffsets( draggable, event );
  11128. }
  11129. // Run through all droppables and check their positions based on specific tolerance options
  11130. $.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
  11131. if ( this.options.disabled || this.greedyChild || !this.visible ) {
  11132. return;
  11133. }
  11134. var parentInstance, scope, parent,
  11135. intersects = intersect( draggable, this, this.options.tolerance, event ),
  11136. c = !intersects && this.isover ?
  11137. "isout" :
  11138. ( intersects && !this.isover ? "isover" : null );
  11139. if ( !c ) {
  11140. return;
  11141. }
  11142. if ( this.options.greedy ) {
  11143. // find droppable parents with same scope
  11144. scope = this.options.scope;
  11145. parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
  11146. return $( this ).droppable( "instance" ).options.scope === scope;
  11147. } );
  11148. if ( parent.length ) {
  11149. parentInstance = $( parent[ 0 ] ).droppable( "instance" );
  11150. parentInstance.greedyChild = ( c === "isover" );
  11151. }
  11152. }
  11153. // We just moved into a greedy child
  11154. if ( parentInstance && c === "isover" ) {
  11155. parentInstance.isover = false;
  11156. parentInstance.isout = true;
  11157. parentInstance._out.call( parentInstance, event );
  11158. }
  11159. this[ c ] = true;
  11160. this[ c === "isout" ? "isover" : "isout" ] = false;
  11161. this[ c === "isover" ? "_over" : "_out" ].call( this, event );
  11162. // We just moved out of a greedy child
  11163. if ( parentInstance && c === "isout" ) {
  11164. parentInstance.isout = false;
  11165. parentInstance.isover = true;
  11166. parentInstance._over.call( parentInstance, event );
  11167. }
  11168. } );
  11169. },
  11170. dragStop: function( draggable, event ) {
  11171. draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
  11172. // Call prepareOffsets one final time since IE does not fire return scroll events when
  11173. // overflow was caused by drag (see #5003)
  11174. if ( !draggable.options.refreshPositions ) {
  11175. $.ui.ddmanager.prepareOffsets( draggable, event );
  11176. }
  11177. }
  11178. };
  11179. // DEPRECATED
  11180. // TODO: switch return back to widget declaration at top of file when this is removed
  11181. if ( $.uiBackCompat !== false ) {
  11182. // Backcompat for activeClass and hoverClass options
  11183. $.widget( "ui.droppable", $.ui.droppable, {
  11184. options: {
  11185. hoverClass: false,
  11186. activeClass: false
  11187. },
  11188. _addActiveClass: function() {
  11189. this._super();
  11190. if ( this.options.activeClass ) {
  11191. this.element.addClass( this.options.activeClass );
  11192. }
  11193. },
  11194. _removeActiveClass: function() {
  11195. this._super();
  11196. if ( this.options.activeClass ) {
  11197. this.element.removeClass( this.options.activeClass );
  11198. }
  11199. },
  11200. _addHoverClass: function() {
  11201. this._super();
  11202. if ( this.options.hoverClass ) {
  11203. this.element.addClass( this.options.hoverClass );
  11204. }
  11205. },
  11206. _removeHoverClass: function() {
  11207. this._super();
  11208. if ( this.options.hoverClass ) {
  11209. this.element.removeClass( this.options.hoverClass );
  11210. }
  11211. }
  11212. } );
  11213. }
  11214. var widgetsDroppable = $.ui.droppable;
  11215. /*!
  11216. * jQuery UI Progressbar 1.12.1
  11217. * http://jqueryui.com
  11218. *
  11219. * Copyright jQuery Foundation and other contributors
  11220. * Released under the MIT license.
  11221. * http://jquery.org/license
  11222. */
  11223. //>>label: Progressbar
  11224. //>>group: Widgets
  11225. // jscs:disable maximumLineLength
  11226. //>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
  11227. // jscs:enable maximumLineLength
  11228. //>>docs: http://api.jqueryui.com/progressbar/
  11229. //>>demos: http://jqueryui.com/progressbar/
  11230. //>>css.structure: ../../themes/base/core.css
  11231. //>>css.structure: ../../themes/base/progressbar.css
  11232. //>>css.theme: ../../themes/base/theme.css
  11233. var widgetsProgressbar = $.widget( "ui.progressbar", {
  11234. version: "1.12.1",
  11235. options: {
  11236. classes: {
  11237. "ui-progressbar": "ui-corner-all",
  11238. "ui-progressbar-value": "ui-corner-left",
  11239. "ui-progressbar-complete": "ui-corner-right"
  11240. },
  11241. max: 100,
  11242. value: 0,
  11243. change: null,
  11244. complete: null
  11245. },
  11246. min: 0,
  11247. _create: function() {
  11248. // Constrain initial value
  11249. this.oldValue = this.options.value = this._constrainedValue();
  11250. this.element.attr( {
  11251. // Only set static values; aria-valuenow and aria-valuemax are
  11252. // set inside _refreshValue()
  11253. role: "progressbar",
  11254. "aria-valuemin": this.min
  11255. } );
  11256. this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );
  11257. this.valueDiv = $( "<div>" ).appendTo( this.element );
  11258. this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
  11259. this._refreshValue();
  11260. },
  11261. _destroy: function() {
  11262. this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );
  11263. this.valueDiv.remove();
  11264. },
  11265. value: function( newValue ) {
  11266. if ( newValue === undefined ) {
  11267. return this.options.value;
  11268. }
  11269. this.options.value = this._constrainedValue( newValue );
  11270. this._refreshValue();
  11271. },
  11272. _constrainedValue: function( newValue ) {
  11273. if ( newValue === undefined ) {
  11274. newValue = this.options.value;
  11275. }
  11276. this.indeterminate = newValue === false;
  11277. // Sanitize value
  11278. if ( typeof newValue !== "number" ) {
  11279. newValue = 0;
  11280. }
  11281. return this.indeterminate ? false :
  11282. Math.min( this.options.max, Math.max( this.min, newValue ) );
  11283. },
  11284. _setOptions: function( options ) {
  11285. // Ensure "value" option is set after other values (like max)
  11286. var value = options.value;
  11287. delete options.value;
  11288. this._super( options );
  11289. this.options.value = this._constrainedValue( value );
  11290. this._refreshValue();
  11291. },
  11292. _setOption: function( key, value ) {
  11293. if ( key === "max" ) {
  11294. // Don't allow a max less than min
  11295. value = Math.max( this.min, value );
  11296. }
  11297. this._super( key, value );
  11298. },
  11299. _setOptionDisabled: function( value ) {
  11300. this._super( value );
  11301. this.element.attr( "aria-disabled", value );
  11302. this._toggleClass( null, "ui-state-disabled", !!value );
  11303. },
  11304. _percentage: function() {
  11305. return this.indeterminate ?
  11306. 100 :
  11307. 100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
  11308. },
  11309. _refreshValue: function() {
  11310. var value = this.options.value,
  11311. percentage = this._percentage();
  11312. this.valueDiv
  11313. .toggle( this.indeterminate || value > this.min )
  11314. .width( percentage.toFixed( 0 ) + "%" );
  11315. this
  11316. ._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
  11317. value === this.options.max )
  11318. ._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );
  11319. if ( this.indeterminate ) {
  11320. this.element.removeAttr( "aria-valuenow" );
  11321. if ( !this.overlayDiv ) {
  11322. this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
  11323. this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
  11324. }
  11325. } else {
  11326. this.element.attr( {
  11327. "aria-valuemax": this.options.max,
  11328. "aria-valuenow": value
  11329. } );
  11330. if ( this.overlayDiv ) {
  11331. this.overlayDiv.remove();
  11332. this.overlayDiv = null;
  11333. }
  11334. }
  11335. if ( this.oldValue !== value ) {
  11336. this.oldValue = value;
  11337. this._trigger( "change" );
  11338. }
  11339. if ( value === this.options.max ) {
  11340. this._trigger( "complete" );
  11341. }
  11342. }
  11343. } );
  11344. /*!
  11345. * jQuery UI Selectable 1.12.1
  11346. * http://jqueryui.com
  11347. *
  11348. * Copyright jQuery Foundation and other contributors
  11349. * Released under the MIT license.
  11350. * http://jquery.org/license
  11351. */
  11352. //>>label: Selectable
  11353. //>>group: Interactions
  11354. //>>description: Allows groups of elements to be selected with the mouse.
  11355. //>>docs: http://api.jqueryui.com/selectable/
  11356. //>>demos: http://jqueryui.com/selectable/
  11357. //>>css.structure: ../../themes/base/selectable.css
  11358. var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
  11359. version: "1.12.1",
  11360. options: {
  11361. appendTo: "body",
  11362. autoRefresh: true,
  11363. distance: 0,
  11364. filter: "*",
  11365. tolerance: "touch",
  11366. // Callbacks
  11367. selected: null,
  11368. selecting: null,
  11369. start: null,
  11370. stop: null,
  11371. unselected: null,
  11372. unselecting: null
  11373. },
  11374. _create: function() {
  11375. var that = this;
  11376. this._addClass( "ui-selectable" );
  11377. this.dragged = false;
  11378. // Cache selectee children based on filter
  11379. this.refresh = function() {
  11380. that.elementPos = $( that.element[ 0 ] ).offset();
  11381. that.selectees = $( that.options.filter, that.element[ 0 ] );
  11382. that._addClass( that.selectees, "ui-selectee" );
  11383. that.selectees.each( function() {
  11384. var $this = $( this ),
  11385. selecteeOffset = $this.offset(),
  11386. pos = {
  11387. left: selecteeOffset.left - that.elementPos.left,
  11388. top: selecteeOffset.top - that.elementPos.top
  11389. };
  11390. $.data( this, "selectable-item", {
  11391. element: this,
  11392. $element: $this,
  11393. left: pos.left,
  11394. top: pos.top,
  11395. right: pos.left + $this.outerWidth(),
  11396. bottom: pos.top + $this.outerHeight(),
  11397. startselected: false,
  11398. selected: $this.hasClass( "ui-selected" ),
  11399. selecting: $this.hasClass( "ui-selecting" ),
  11400. unselecting: $this.hasClass( "ui-unselecting" )
  11401. } );
  11402. } );
  11403. };
  11404. this.refresh();
  11405. this._mouseInit();
  11406. this.helper = $( "<div>" );
  11407. this._addClass( this.helper, "ui-selectable-helper" );
  11408. },
  11409. _destroy: function() {
  11410. this.selectees.removeData( "selectable-item" );
  11411. this._mouseDestroy();
  11412. },
  11413. _mouseStart: function( event ) {
  11414. var that = this,
  11415. options = this.options;
  11416. this.opos = [ event.pageX, event.pageY ];
  11417. this.elementPos = $( this.element[ 0 ] ).offset();
  11418. if ( this.options.disabled ) {
  11419. return;
  11420. }
  11421. this.selectees = $( options.filter, this.element[ 0 ] );
  11422. this._trigger( "start", event );
  11423. $( options.appendTo ).append( this.helper );
  11424. // position helper (lasso)
  11425. this.helper.css( {
  11426. "left": event.pageX,
  11427. "top": event.pageY,
  11428. "width": 0,
  11429. "height": 0
  11430. } );
  11431. if ( options.autoRefresh ) {
  11432. this.refresh();
  11433. }
  11434. this.selectees.filter( ".ui-selected" ).each( function() {
  11435. var selectee = $.data( this, "selectable-item" );
  11436. selectee.startselected = true;
  11437. if ( !event.metaKey && !event.ctrlKey ) {
  11438. that._removeClass( selectee.$element, "ui-selected" );
  11439. selectee.selected = false;
  11440. that._addClass( selectee.$element, "ui-unselecting" );
  11441. selectee.unselecting = true;
  11442. // selectable UNSELECTING callback
  11443. that._trigger( "unselecting", event, {
  11444. unselecting: selectee.element
  11445. } );
  11446. }
  11447. } );
  11448. $( event.target ).parents().addBack().each( function() {
  11449. var doSelect,
  11450. selectee = $.data( this, "selectable-item" );
  11451. if ( selectee ) {
  11452. doSelect = ( !event.metaKey && !event.ctrlKey ) ||
  11453. !selectee.$element.hasClass( "ui-selected" );
  11454. that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
  11455. ._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
  11456. selectee.unselecting = !doSelect;
  11457. selectee.selecting = doSelect;
  11458. selectee.selected = doSelect;
  11459. // selectable (UN)SELECTING callback
  11460. if ( doSelect ) {
  11461. that._trigger( "selecting", event, {
  11462. selecting: selectee.element
  11463. } );
  11464. } else {
  11465. that._trigger( "unselecting", event, {
  11466. unselecting: selectee.element
  11467. } );
  11468. }
  11469. return false;
  11470. }
  11471. } );
  11472. },
  11473. _mouseDrag: function( event ) {
  11474. this.dragged = true;
  11475. if ( this.options.disabled ) {
  11476. return;
  11477. }
  11478. var tmp,
  11479. that = this,
  11480. options = this.options,
  11481. x1 = this.opos[ 0 ],
  11482. y1 = this.opos[ 1 ],
  11483. x2 = event.pageX,
  11484. y2 = event.pageY;
  11485. if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; }
  11486. if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; }
  11487. this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
  11488. this.selectees.each( function() {
  11489. var selectee = $.data( this, "selectable-item" ),
  11490. hit = false,
  11491. offset = {};
  11492. //prevent helper from being selected if appendTo: selectable
  11493. if ( !selectee || selectee.element === that.element[ 0 ] ) {
  11494. return;
  11495. }
  11496. offset.left = selectee.left + that.elementPos.left;
  11497. offset.right = selectee.right + that.elementPos.left;
  11498. offset.top = selectee.top + that.elementPos.top;
  11499. offset.bottom = selectee.bottom + that.elementPos.top;
  11500. if ( options.tolerance === "touch" ) {
  11501. hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
  11502. offset.bottom < y1 ) );
  11503. } else if ( options.tolerance === "fit" ) {
  11504. hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
  11505. offset.bottom < y2 );
  11506. }
  11507. if ( hit ) {
  11508. // SELECT
  11509. if ( selectee.selected ) {
  11510. that._removeClass( selectee.$element, "ui-selected" );
  11511. selectee.selected = false;
  11512. }
  11513. if ( selectee.unselecting ) {
  11514. that._removeClass( selectee.$element, "ui-unselecting" );
  11515. selectee.unselecting = false;
  11516. }
  11517. if ( !selectee.selecting ) {
  11518. that._addClass( selectee.$element, "ui-selecting" );
  11519. selectee.selecting = true;
  11520. // selectable SELECTING callback
  11521. that._trigger( "selecting", event, {
  11522. selecting: selectee.element
  11523. } );
  11524. }
  11525. } else {
  11526. // UNSELECT
  11527. if ( selectee.selecting ) {
  11528. if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
  11529. that._removeClass( selectee.$element, "ui-selecting" );
  11530. selectee.selecting = false;
  11531. that._addClass( selectee.$element, "ui-selected" );
  11532. selectee.selected = true;
  11533. } else {
  11534. that._removeClass( selectee.$element, "ui-selecting" );
  11535. selectee.selecting = false;
  11536. if ( selectee.startselected ) {
  11537. that._addClass( selectee.$element, "ui-unselecting" );
  11538. selectee.unselecting = true;
  11539. }
  11540. // selectable UNSELECTING callback
  11541. that._trigger( "unselecting", event, {
  11542. unselecting: selectee.element
  11543. } );
  11544. }
  11545. }
  11546. if ( selectee.selected ) {
  11547. if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
  11548. that._removeClass( selectee.$element, "ui-selected" );
  11549. selectee.selected = false;
  11550. that._addClass( selectee.$element, "ui-unselecting" );
  11551. selectee.unselecting = true;
  11552. // selectable UNSELECTING callback
  11553. that._trigger( "unselecting", event, {
  11554. unselecting: selectee.element
  11555. } );
  11556. }
  11557. }
  11558. }
  11559. } );
  11560. return false;
  11561. },
  11562. _mouseStop: function( event ) {
  11563. var that = this;
  11564. this.dragged = false;
  11565. $( ".ui-unselecting", this.element[ 0 ] ).each( function() {
  11566. var selectee = $.data( this, "selectable-item" );
  11567. that._removeClass( selectee.$element, "ui-unselecting" );
  11568. selectee.unselecting = false;
  11569. selectee.startselected = false;
  11570. that._trigger( "unselected", event, {
  11571. unselected: selectee.element
  11572. } );
  11573. } );
  11574. $( ".ui-selecting", this.element[ 0 ] ).each( function() {
  11575. var selectee = $.data( this, "selectable-item" );
  11576. that._removeClass( selectee.$element, "ui-selecting" )
  11577. ._addClass( selectee.$element, "ui-selected" );
  11578. selectee.selecting = false;
  11579. selectee.selected = true;
  11580. selectee.startselected = true;
  11581. that._trigger( "selected", event, {
  11582. selected: selectee.element
  11583. } );
  11584. } );
  11585. this._trigger( "stop", event );
  11586. this.helper.remove();
  11587. return false;
  11588. }
  11589. } );
  11590. /*!
  11591. * jQuery UI Selectmenu 1.12.1
  11592. * http://jqueryui.com
  11593. *
  11594. * Copyright jQuery Foundation and other contributors
  11595. * Released under the MIT license.
  11596. * http://jquery.org/license
  11597. */
  11598. //>>label: Selectmenu
  11599. //>>group: Widgets
  11600. // jscs:disable maximumLineLength
  11601. //>>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.
  11602. // jscs:enable maximumLineLength
  11603. //>>docs: http://api.jqueryui.com/selectmenu/
  11604. //>>demos: http://jqueryui.com/selectmenu/
  11605. //>>css.structure: ../../themes/base/core.css
  11606. //>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
  11607. //>>css.theme: ../../themes/base/theme.css
  11608. var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
  11609. version: "1.12.1",
  11610. defaultElement: "<select>",
  11611. options: {
  11612. appendTo: null,
  11613. classes: {
  11614. "ui-selectmenu-button-open": "ui-corner-top",
  11615. "ui-selectmenu-button-closed": "ui-corner-all"
  11616. },
  11617. disabled: null,
  11618. icons: {
  11619. button: "ui-icon-triangle-1-s"
  11620. },
  11621. position: {
  11622. my: "left top",
  11623. at: "left bottom",
  11624. collision: "none"
  11625. },
  11626. width: false,
  11627. // Callbacks
  11628. change: null,
  11629. close: null,
  11630. focus: null,
  11631. open: null,
  11632. select: null
  11633. },
  11634. _create: function() {
  11635. var selectmenuId = this.element.uniqueId().attr( "id" );
  11636. this.ids = {
  11637. element: selectmenuId,
  11638. button: selectmenuId + "-button",
  11639. menu: selectmenuId + "-menu"
  11640. };
  11641. this._drawButton();
  11642. this._drawMenu();
  11643. this._bindFormResetHandler();
  11644. this._rendered = false;
  11645. this.menuItems = $();
  11646. },
  11647. _drawButton: function() {
  11648. var icon,
  11649. that = this,
  11650. item = this._parseOption(
  11651. this.element.find( "option:selected" ),
  11652. this.element[ 0 ].selectedIndex
  11653. );
  11654. // Associate existing label with the new button
  11655. this.labels = this.element.labels().attr( "for", this.ids.button );
  11656. this._on( this.labels, {
  11657. click: function( event ) {
  11658. this.button.focus();
  11659. event.preventDefault();
  11660. }
  11661. } );
  11662. // Hide original select element
  11663. this.element.hide();
  11664. // Create button
  11665. this.button = $( "<span>", {
  11666. tabindex: this.options.disabled ? -1 : 0,
  11667. id: this.ids.button,
  11668. role: "combobox",
  11669. "aria-expanded": "false",
  11670. "aria-autocomplete": "list",
  11671. "aria-owns": this.ids.menu,
  11672. "aria-haspopup": "true",
  11673. title: this.element.attr( "title" )
  11674. } )
  11675. .insertAfter( this.element );
  11676. this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
  11677. "ui-button ui-widget" );
  11678. icon = $( "<span>" ).appendTo( this.button );
  11679. this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
  11680. this.buttonItem = this._renderButtonItem( item )
  11681. .appendTo( this.button );
  11682. if ( this.options.width !== false ) {
  11683. this._resizeButton();
  11684. }
  11685. this._on( this.button, this._buttonEvents );
  11686. this.button.one( "focusin", function() {
  11687. // Delay rendering the menu items until the button receives focus.
  11688. // The menu may have already been rendered via a programmatic open.
  11689. if ( !that._rendered ) {
  11690. that._refreshMenu();
  11691. }
  11692. } );
  11693. },
  11694. _drawMenu: function() {
  11695. var that = this;
  11696. // Create menu
  11697. this.menu = $( "<ul>", {
  11698. "aria-hidden": "true",
  11699. "aria-labelledby": this.ids.button,
  11700. id: this.ids.menu
  11701. } );
  11702. // Wrap menu
  11703. this.menuWrap = $( "<div>" ).append( this.menu );
  11704. this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
  11705. this.menuWrap.appendTo( this._appendTo() );
  11706. // Initialize menu widget
  11707. this.menuInstance = this.menu
  11708. .menu( {
  11709. classes: {
  11710. "ui-menu": "ui-corner-bottom"
  11711. },
  11712. role: "listbox",
  11713. select: function( event, ui ) {
  11714. event.preventDefault();
  11715. // Support: IE8
  11716. // If the item was selected via a click, the text selection
  11717. // will be destroyed in IE
  11718. that._setSelection();
  11719. that._select( ui.item.data( "ui-selectmenu-item" ), event );
  11720. },
  11721. focus: function( event, ui ) {
  11722. var item = ui.item.data( "ui-selectmenu-item" );
  11723. // Prevent inital focus from firing and check if its a newly focused item
  11724. if ( that.focusIndex != null && item.index !== that.focusIndex ) {
  11725. that._trigger( "focus", event, { item: item } );
  11726. if ( !that.isOpen ) {
  11727. that._select( item, event );
  11728. }
  11729. }
  11730. that.focusIndex = item.index;
  11731. that.button.attr( "aria-activedescendant",
  11732. that.menuItems.eq( item.index ).attr( "id" ) );
  11733. }
  11734. } )
  11735. .menu( "instance" );
  11736. // Don't close the menu on mouseleave
  11737. this.menuInstance._off( this.menu, "mouseleave" );
  11738. // Cancel the menu's collapseAll on document click
  11739. this.menuInstance._closeOnDocumentClick = function() {
  11740. return false;
  11741. };
  11742. // Selects often contain empty items, but never contain dividers
  11743. this.menuInstance._isDivider = function() {
  11744. return false;
  11745. };
  11746. },
  11747. refresh: function() {
  11748. this._refreshMenu();
  11749. this.buttonItem.replaceWith(
  11750. this.buttonItem = this._renderButtonItem(
  11751. // Fall back to an empty object in case there are no options
  11752. this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
  11753. )
  11754. );
  11755. if ( this.options.width === null ) {
  11756. this._resizeButton();
  11757. }
  11758. },
  11759. _refreshMenu: function() {
  11760. var item,
  11761. options = this.element.find( "option" );
  11762. this.menu.empty();
  11763. this._parseOptions( options );
  11764. this._renderMenu( this.menu, this.items );
  11765. this.menuInstance.refresh();
  11766. this.menuItems = this.menu.find( "li" )
  11767. .not( ".ui-selectmenu-optgroup" )
  11768. .find( ".ui-menu-item-wrapper" );
  11769. this._rendered = true;
  11770. if ( !options.length ) {
  11771. return;
  11772. }
  11773. item = this._getSelectedItem();
  11774. // Update the menu to have the correct item focused
  11775. this.menuInstance.focus( null, item );
  11776. this._setAria( item.data( "ui-selectmenu-item" ) );
  11777. // Set disabled state
  11778. this._setOption( "disabled", this.element.prop( "disabled" ) );
  11779. },
  11780. open: function( event ) {
  11781. if ( this.options.disabled ) {
  11782. return;
  11783. }
  11784. // If this is the first time the menu is being opened, render the items
  11785. if ( !this._rendered ) {
  11786. this._refreshMenu();
  11787. } else {
  11788. // Menu clears focus on close, reset focus to selected item
  11789. this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
  11790. this.menuInstance.focus( null, this._getSelectedItem() );
  11791. }
  11792. // If there are no options, don't open the menu
  11793. if ( !this.menuItems.length ) {
  11794. return;
  11795. }
  11796. this.isOpen = true;
  11797. this._toggleAttr();
  11798. this._resizeMenu();
  11799. this._position();
  11800. this._on( this.document, this._documentClick );
  11801. this._trigger( "open", event );
  11802. },
  11803. _position: function() {
  11804. this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
  11805. },
  11806. close: function( event ) {
  11807. if ( !this.isOpen ) {
  11808. return;
  11809. }
  11810. this.isOpen = false;
  11811. this._toggleAttr();
  11812. this.range = null;
  11813. this._off( this.document );
  11814. this._trigger( "close", event );
  11815. },
  11816. widget: function() {
  11817. return this.button;
  11818. },
  11819. menuWidget: function() {
  11820. return this.menu;
  11821. },
  11822. _renderButtonItem: function( item ) {
  11823. var buttonItem = $( "<span>" );
  11824. this._setText( buttonItem, item.label );
  11825. this._addClass( buttonItem, "ui-selectmenu-text" );
  11826. return buttonItem;
  11827. },
  11828. _renderMenu: function( ul, items ) {
  11829. var that = this,
  11830. currentOptgroup = "";
  11831. $.each( items, function( index, item ) {
  11832. var li;
  11833. if ( item.optgroup !== currentOptgroup ) {
  11834. li = $( "<li>", {
  11835. text: item.optgroup
  11836. } );
  11837. that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
  11838. ( item.element.parent( "optgroup" ).prop( "disabled" ) ?
  11839. " ui-state-disabled" :
  11840. "" ) );
  11841. li.appendTo( ul );
  11842. currentOptgroup = item.optgroup;
  11843. }
  11844. that._renderItemData( ul, item );
  11845. } );
  11846. },
  11847. _renderItemData: function( ul, item ) {
  11848. return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
  11849. },
  11850. _renderItem: function( ul, item ) {
  11851. var li = $( "<li>" ),
  11852. wrapper = $( "<div>", {
  11853. title: item.element.attr( "title" )
  11854. } );
  11855. if ( item.disabled ) {
  11856. this._addClass( li, null, "ui-state-disabled" );
  11857. }
  11858. this._setText( wrapper, item.label );
  11859. return li.append( wrapper ).appendTo( ul );
  11860. },
  11861. _setText: function( element, value ) {
  11862. if ( value ) {
  11863. element.text( value );
  11864. } else {
  11865. element.html( "&#160;" );
  11866. }
  11867. },
  11868. _move: function( direction, event ) {
  11869. var item, next,
  11870. filter = ".ui-menu-item";
  11871. if ( this.isOpen ) {
  11872. item = this.menuItems.eq( this.focusIndex ).parent( "li" );
  11873. } else {
  11874. item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
  11875. filter += ":not(.ui-state-disabled)";
  11876. }
  11877. if ( direction === "first" || direction === "last" ) {
  11878. next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
  11879. } else {
  11880. next = item[ direction + "All" ]( filter ).eq( 0 );
  11881. }
  11882. if ( next.length ) {
  11883. this.menuInstance.focus( event, next );
  11884. }
  11885. },
  11886. _getSelectedItem: function() {
  11887. return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
  11888. },
  11889. _toggle: function( event ) {
  11890. this[ this.isOpen ? "close" : "open" ]( event );
  11891. },
  11892. _setSelection: function() {
  11893. var selection;
  11894. if ( !this.range ) {
  11895. return;
  11896. }
  11897. if ( window.getSelection ) {
  11898. selection = window.getSelection();
  11899. selection.removeAllRanges();
  11900. selection.addRange( this.range );
  11901. // Support: IE8
  11902. } else {
  11903. this.range.select();
  11904. }
  11905. // Support: IE
  11906. // Setting the text selection kills the button focus in IE, but
  11907. // restoring the focus doesn't kill the selection.
  11908. this.button.focus();
  11909. },
  11910. _documentClick: {
  11911. mousedown: function( event ) {
  11912. if ( !this.isOpen ) {
  11913. return;
  11914. }
  11915. if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
  11916. $.ui.escapeSelector( this.ids.button ) ).length ) {
  11917. this.close( event );
  11918. }
  11919. }
  11920. },
  11921. _buttonEvents: {
  11922. // Prevent text selection from being reset when interacting with the selectmenu (#10144)
  11923. mousedown: function() {
  11924. var selection;
  11925. if ( window.getSelection ) {
  11926. selection = window.getSelection();
  11927. if ( selection.rangeCount ) {
  11928. this.range = selection.getRangeAt( 0 );
  11929. }
  11930. // Support: IE8
  11931. } else {
  11932. this.range = document.selection.createRange();
  11933. }
  11934. },
  11935. click: function( event ) {
  11936. this._setSelection();
  11937. this._toggle( event );
  11938. },
  11939. keydown: function( event ) {
  11940. var preventDefault = true;
  11941. switch ( event.keyCode ) {
  11942. case $.ui.keyCode.TAB:
  11943. case $.ui.keyCode.ESCAPE:
  11944. this.close( event );
  11945. preventDefault = false;
  11946. break;
  11947. case $.ui.keyCode.ENTER:
  11948. if ( this.isOpen ) {
  11949. this._selectFocusedItem( event );
  11950. }
  11951. break;
  11952. case $.ui.keyCode.UP:
  11953. if ( event.altKey ) {
  11954. this._toggle( event );
  11955. } else {
  11956. this._move( "prev", event );
  11957. }
  11958. break;
  11959. case $.ui.keyCode.DOWN:
  11960. if ( event.altKey ) {
  11961. this._toggle( event );
  11962. } else {
  11963. this._move( "next", event );
  11964. }
  11965. break;
  11966. case $.ui.keyCode.SPACE:
  11967. if ( this.isOpen ) {
  11968. this._selectFocusedItem( event );
  11969. } else {
  11970. this._toggle( event );
  11971. }
  11972. break;
  11973. case $.ui.keyCode.LEFT:
  11974. this._move( "prev", event );
  11975. break;
  11976. case $.ui.keyCode.RIGHT:
  11977. this._move( "next", event );
  11978. break;
  11979. case $.ui.keyCode.HOME:
  11980. case $.ui.keyCode.PAGE_UP:
  11981. this._move( "first", event );
  11982. break;
  11983. case $.ui.keyCode.END:
  11984. case $.ui.keyCode.PAGE_DOWN:
  11985. this._move( "last", event );
  11986. break;
  11987. default:
  11988. this.menu.trigger( event );
  11989. preventDefault = false;
  11990. }
  11991. if ( preventDefault ) {
  11992. event.preventDefault();
  11993. }
  11994. }
  11995. },
  11996. _selectFocusedItem: function( event ) {
  11997. var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
  11998. if ( !item.hasClass( "ui-state-disabled" ) ) {
  11999. this._select( item.data( "ui-selectmenu-item" ), event );
  12000. }
  12001. },
  12002. _select: function( item, event ) {
  12003. var oldIndex = this.element[ 0 ].selectedIndex;
  12004. // Change native select element
  12005. this.element[ 0 ].selectedIndex = item.index;
  12006. this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
  12007. this._setAria( item );
  12008. this._trigger( "select", event, { item: item } );
  12009. if ( item.index !== oldIndex ) {
  12010. this._trigger( "change", event, { item: item } );
  12011. }
  12012. this.close( event );
  12013. },
  12014. _setAria: function( item ) {
  12015. var id = this.menuItems.eq( item.index ).attr( "id" );
  12016. this.button.attr( {
  12017. "aria-labelledby": id,
  12018. "aria-activedescendant": id
  12019. } );
  12020. this.menu.attr( "aria-activedescendant", id );
  12021. },
  12022. _setOption: function( key, value ) {
  12023. if ( key === "icons" ) {
  12024. var icon = this.button.find( "span.ui-icon" );
  12025. this._removeClass( icon, null, this.options.icons.button )
  12026. ._addClass( icon, null, value.button );
  12027. }
  12028. this._super( key, value );
  12029. if ( key === "appendTo" ) {
  12030. this.menuWrap.appendTo( this._appendTo() );
  12031. }
  12032. if ( key === "width" ) {
  12033. this._resizeButton();
  12034. }
  12035. },
  12036. _setOptionDisabled: function( value ) {
  12037. this._super( value );
  12038. this.menuInstance.option( "disabled", value );
  12039. this.button.attr( "aria-disabled", value );
  12040. this._toggleClass( this.button, null, "ui-state-disabled", value );
  12041. this.element.prop( "disabled", value );
  12042. if ( value ) {
  12043. this.button.attr( "tabindex", -1 );
  12044. this.close();
  12045. } else {
  12046. this.button.attr( "tabindex", 0 );
  12047. }
  12048. },
  12049. _appendTo: function() {
  12050. var element = this.options.appendTo;
  12051. if ( element ) {
  12052. element = element.jquery || element.nodeType ?
  12053. $( element ) :
  12054. this.document.find( element ).eq( 0 );
  12055. }
  12056. if ( !element || !element[ 0 ] ) {
  12057. element = this.element.closest( ".ui-front, dialog" );
  12058. }
  12059. if ( !element.length ) {
  12060. element = this.document[ 0 ].body;
  12061. }
  12062. return element;
  12063. },
  12064. _toggleAttr: function() {
  12065. this.button.attr( "aria-expanded", this.isOpen );
  12066. // We can't use two _toggleClass() calls here, because we need to make sure
  12067. // we always remove classes first and add them second, otherwise if both classes have the
  12068. // same theme class, it will be removed after we add it.
  12069. this._removeClass( this.button, "ui-selectmenu-button-" +
  12070. ( this.isOpen ? "closed" : "open" ) )
  12071. ._addClass( this.button, "ui-selectmenu-button-" +
  12072. ( this.isOpen ? "open" : "closed" ) )
  12073. ._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
  12074. this.menu.attr( "aria-hidden", !this.isOpen );
  12075. },
  12076. _resizeButton: function() {
  12077. var width = this.options.width;
  12078. // For `width: false`, just remove inline style and stop
  12079. if ( width === false ) {
  12080. this.button.css( "width", "" );
  12081. return;
  12082. }
  12083. // For `width: null`, match the width of the original element
  12084. if ( width === null ) {
  12085. width = this.element.show().outerWidth();
  12086. this.element.hide();
  12087. }
  12088. this.button.outerWidth( width );
  12089. },
  12090. _resizeMenu: function() {
  12091. this.menu.outerWidth( Math.max(
  12092. this.button.outerWidth(),
  12093. // Support: IE10
  12094. // IE10 wraps long text (possibly a rounding bug)
  12095. // so we add 1px to avoid the wrapping
  12096. this.menu.width( "" ).outerWidth() + 1
  12097. ) );
  12098. },
  12099. _getCreateOptions: function() {
  12100. var options = this._super();
  12101. options.disabled = this.element.prop( "disabled" );
  12102. return options;
  12103. },
  12104. _parseOptions: function( options ) {
  12105. var that = this,
  12106. data = [];
  12107. options.each( function( index, item ) {
  12108. data.push( that._parseOption( $( item ), index ) );
  12109. } );
  12110. this.items = data;
  12111. },
  12112. _parseOption: function( option, index ) {
  12113. var optgroup = option.parent( "optgroup" );
  12114. return {
  12115. element: option,
  12116. index: index,
  12117. value: option.val(),
  12118. label: option.text(),
  12119. optgroup: optgroup.attr( "label" ) || "",
  12120. disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
  12121. };
  12122. },
  12123. _destroy: function() {
  12124. this._unbindFormResetHandler();
  12125. this.menuWrap.remove();
  12126. this.button.remove();
  12127. this.element.show();
  12128. this.element.removeUniqueId();
  12129. this.labels.attr( "for", this.ids.element );
  12130. }
  12131. } ] );
  12132. /*!
  12133. * jQuery UI Slider 1.12.1
  12134. * http://jqueryui.com
  12135. *
  12136. * Copyright jQuery Foundation and other contributors
  12137. * Released under the MIT license.
  12138. * http://jquery.org/license
  12139. */
  12140. //>>label: Slider
  12141. //>>group: Widgets
  12142. //>>description: Displays a flexible slider with ranges and accessibility via keyboard.
  12143. //>>docs: http://api.jqueryui.com/slider/
  12144. //>>demos: http://jqueryui.com/slider/
  12145. //>>css.structure: ../../themes/base/core.css
  12146. //>>css.structure: ../../themes/base/slider.css
  12147. //>>css.theme: ../../themes/base/theme.css
  12148. var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
  12149. version: "1.12.1",
  12150. widgetEventPrefix: "slide",
  12151. options: {
  12152. animate: false,
  12153. classes: {
  12154. "ui-slider": "ui-corner-all",
  12155. "ui-slider-handle": "ui-corner-all",
  12156. // Note: ui-widget-header isn't the most fittingly semantic framework class for this
  12157. // element, but worked best visually with a variety of themes
  12158. "ui-slider-range": "ui-corner-all ui-widget-header"
  12159. },
  12160. distance: 0,
  12161. max: 100,
  12162. min: 0,
  12163. orientation: "horizontal",
  12164. range: false,
  12165. step: 1,
  12166. value: 0,
  12167. values: null,
  12168. // Callbacks
  12169. change: null,
  12170. slide: null,
  12171. start: null,
  12172. stop: null
  12173. },
  12174. // Number of pages in a slider
  12175. // (how many times can you page up/down to go through the whole range)
  12176. numPages: 5,
  12177. _create: function() {
  12178. this._keySliding = false;
  12179. this._mouseSliding = false;
  12180. this._animateOff = true;
  12181. this._handleIndex = null;
  12182. this._detectOrientation();
  12183. this._mouseInit();
  12184. this._calculateNewMax();
  12185. this._addClass( "ui-slider ui-slider-" + this.orientation,
  12186. "ui-widget ui-widget-content" );
  12187. this._refresh();
  12188. this._animateOff = false;
  12189. },
  12190. _refresh: function() {
  12191. this._createRange();
  12192. this._createHandles();
  12193. this._setupEvents();
  12194. this._refreshValue();
  12195. },
  12196. _createHandles: function() {
  12197. var i, handleCount,
  12198. options = this.options,
  12199. existingHandles = this.element.find( ".ui-slider-handle" ),
  12200. handle = "<span tabindex='0'></span>",
  12201. handles = [];
  12202. handleCount = ( options.values && options.values.length ) || 1;
  12203. if ( existingHandles.length > handleCount ) {
  12204. existingHandles.slice( handleCount ).remove();
  12205. existingHandles = existingHandles.slice( 0, handleCount );
  12206. }
  12207. for ( i = existingHandles.length; i < handleCount; i++ ) {
  12208. handles.push( handle );
  12209. }
  12210. this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
  12211. this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
  12212. this.handle = this.handles.eq( 0 );
  12213. this.handles.each( function( i ) {
  12214. $( this )
  12215. .data( "ui-slider-handle-index", i )
  12216. .attr( "tabIndex", 0 );
  12217. } );
  12218. },
  12219. _createRange: function() {
  12220. var options = this.options;
  12221. if ( options.range ) {
  12222. if ( options.range === true ) {
  12223. if ( !options.values ) {
  12224. options.values = [ this._valueMin(), this._valueMin() ];
  12225. } else if ( options.values.length && options.values.length !== 2 ) {
  12226. options.values = [ options.values[ 0 ], options.values[ 0 ] ];
  12227. } else if ( $.isArray( options.values ) ) {
  12228. options.values = options.values.slice( 0 );
  12229. }
  12230. }
  12231. if ( !this.range || !this.range.length ) {
  12232. this.range = $( "<div>" )
  12233. .appendTo( this.element );
  12234. this._addClass( this.range, "ui-slider-range" );
  12235. } else {
  12236. this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
  12237. // Handle range switching from true to min/max
  12238. this.range.css( {
  12239. "left": "",
  12240. "bottom": ""
  12241. } );
  12242. }
  12243. if ( options.range === "min" || options.range === "max" ) {
  12244. this._addClass( this.range, "ui-slider-range-" + options.range );
  12245. }
  12246. } else {
  12247. if ( this.range ) {
  12248. this.range.remove();
  12249. }
  12250. this.range = null;
  12251. }
  12252. },
  12253. _setupEvents: function() {
  12254. this._off( this.handles );
  12255. this._on( this.handles, this._handleEvents );
  12256. this._hoverable( this.handles );
  12257. this._focusable( this.handles );
  12258. },
  12259. _destroy: function() {
  12260. this.handles.remove();
  12261. if ( this.range ) {
  12262. this.range.remove();
  12263. }
  12264. this._mouseDestroy();
  12265. },
  12266. _mouseCapture: function( event ) {
  12267. var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
  12268. that = this,
  12269. o = this.options;
  12270. if ( o.disabled ) {
  12271. return false;
  12272. }
  12273. this.elementSize = {
  12274. width: this.element.outerWidth(),
  12275. height: this.element.outerHeight()
  12276. };
  12277. this.elementOffset = this.element.offset();
  12278. position = { x: event.pageX, y: event.pageY };
  12279. normValue = this._normValueFromMouse( position );
  12280. distance = this._valueMax() - this._valueMin() + 1;
  12281. this.handles.each( function( i ) {
  12282. var thisDistance = Math.abs( normValue - that.values( i ) );
  12283. if ( ( distance > thisDistance ) ||
  12284. ( distance === thisDistance &&
  12285. ( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
  12286. distance = thisDistance;
  12287. closestHandle = $( this );
  12288. index = i;
  12289. }
  12290. } );
  12291. allowed = this._start( event, index );
  12292. if ( allowed === false ) {
  12293. return false;
  12294. }
  12295. this._mouseSliding = true;
  12296. this._handleIndex = index;
  12297. this._addClass( closestHandle, null, "ui-state-active" );
  12298. closestHandle.trigger( "focus" );
  12299. offset = closestHandle.offset();
  12300. mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
  12301. this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
  12302. left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
  12303. top: event.pageY - offset.top -
  12304. ( closestHandle.height() / 2 ) -
  12305. ( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
  12306. ( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
  12307. ( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
  12308. };
  12309. if ( !this.handles.hasClass( "ui-state-hover" ) ) {
  12310. this._slide( event, index, normValue );
  12311. }
  12312. this._animateOff = true;
  12313. return true;
  12314. },
  12315. _mouseStart: function() {
  12316. return true;
  12317. },
  12318. _mouseDrag: function( event ) {
  12319. var position = { x: event.pageX, y: event.pageY },
  12320. normValue = this._normValueFromMouse( position );
  12321. this._slide( event, this._handleIndex, normValue );
  12322. return false;
  12323. },
  12324. _mouseStop: function( event ) {
  12325. this._removeClass( this.handles, null, "ui-state-active" );
  12326. this._mouseSliding = false;
  12327. this._stop( event, this._handleIndex );
  12328. this._change( event, this._handleIndex );
  12329. this._handleIndex = null;
  12330. this._clickOffset = null;
  12331. this._animateOff = false;
  12332. return false;
  12333. },
  12334. _detectOrientation: function() {
  12335. this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
  12336. },
  12337. _normValueFromMouse: function( position ) {
  12338. var pixelTotal,
  12339. pixelMouse,
  12340. percentMouse,
  12341. valueTotal,
  12342. valueMouse;
  12343. if ( this.orientation === "horizontal" ) {
  12344. pixelTotal = this.elementSize.width;
  12345. pixelMouse = position.x - this.elementOffset.left -
  12346. ( this._clickOffset ? this._clickOffset.left : 0 );
  12347. } else {
  12348. pixelTotal = this.elementSize.height;
  12349. pixelMouse = position.y - this.elementOffset.top -
  12350. ( this._clickOffset ? this._clickOffset.top : 0 );
  12351. }
  12352. percentMouse = ( pixelMouse / pixelTotal );
  12353. if ( percentMouse > 1 ) {
  12354. percentMouse = 1;
  12355. }
  12356. if ( percentMouse < 0 ) {
  12357. percentMouse = 0;
  12358. }
  12359. if ( this.orientation === "vertical" ) {
  12360. percentMouse = 1 - percentMouse;
  12361. }
  12362. valueTotal = this._valueMax() - this._valueMin();
  12363. valueMouse = this._valueMin() + percentMouse * valueTotal;
  12364. return this._trimAlignValue( valueMouse );
  12365. },
  12366. _uiHash: function( index, value, values ) {
  12367. var uiHash = {
  12368. handle: this.handles[ index ],
  12369. handleIndex: index,
  12370. value: value !== undefined ? value : this.value()
  12371. };
  12372. if ( this._hasMultipleValues() ) {
  12373. uiHash.value = value !== undefined ? value : this.values( index );
  12374. uiHash.values = values || this.values();
  12375. }
  12376. return uiHash;
  12377. },
  12378. _hasMultipleValues: function() {
  12379. return this.options.values && this.options.values.length;
  12380. },
  12381. _start: function( event, index ) {
  12382. return this._trigger( "start", event, this._uiHash( index ) );
  12383. },
  12384. _slide: function( event, index, newVal ) {
  12385. var allowed, otherVal,
  12386. currentValue = this.value(),
  12387. newValues = this.values();
  12388. if ( this._hasMultipleValues() ) {
  12389. otherVal = this.values( index ? 0 : 1 );
  12390. currentValue = this.values( index );
  12391. if ( this.options.values.length === 2 && this.options.range === true ) {
  12392. newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
  12393. }
  12394. newValues[ index ] = newVal;
  12395. }
  12396. if ( newVal === currentValue ) {
  12397. return;
  12398. }
  12399. allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
  12400. // A slide can be canceled by returning false from the slide callback
  12401. if ( allowed === false ) {
  12402. return;
  12403. }
  12404. if ( this._hasMultipleValues() ) {
  12405. this.values( index, newVal );
  12406. } else {
  12407. this.value( newVal );
  12408. }
  12409. },
  12410. _stop: function( event, index ) {
  12411. this._trigger( "stop", event, this._uiHash( index ) );
  12412. },
  12413. _change: function( event, index ) {
  12414. if ( !this._keySliding && !this._mouseSliding ) {
  12415. //store the last changed value index for reference when handles overlap
  12416. this._lastChangedValue = index;
  12417. this._trigger( "change", event, this._uiHash( index ) );
  12418. }
  12419. },
  12420. value: function( newValue ) {
  12421. if ( arguments.length ) {
  12422. this.options.value = this._trimAlignValue( newValue );
  12423. this._refreshValue();
  12424. this._change( null, 0 );
  12425. return;
  12426. }
  12427. return this._value();
  12428. },
  12429. values: function( index, newValue ) {
  12430. var vals,
  12431. newValues,
  12432. i;
  12433. if ( arguments.length > 1 ) {
  12434. this.options.values[ index ] = this._trimAlignValue( newValue );
  12435. this._refreshValue();
  12436. this._change( null, index );
  12437. return;
  12438. }
  12439. if ( arguments.length ) {
  12440. if ( $.isArray( arguments[ 0 ] ) ) {
  12441. vals = this.options.values;
  12442. newValues = arguments[ 0 ];
  12443. for ( i = 0; i < vals.length; i += 1 ) {
  12444. vals[ i ] = this._trimAlignValue( newValues[ i ] );
  12445. this._change( null, i );
  12446. }
  12447. this._refreshValue();
  12448. } else {
  12449. if ( this._hasMultipleValues() ) {
  12450. return this._values( index );
  12451. } else {
  12452. return this.value();
  12453. }
  12454. }
  12455. } else {
  12456. return this._values();
  12457. }
  12458. },
  12459. _setOption: function( key, value ) {
  12460. var i,
  12461. valsLength = 0;
  12462. if ( key === "range" && this.options.range === true ) {
  12463. if ( value === "min" ) {
  12464. this.options.value = this._values( 0 );
  12465. this.options.values = null;
  12466. } else if ( value === "max" ) {
  12467. this.options.value = this._values( this.options.values.length - 1 );
  12468. this.options.values = null;
  12469. }
  12470. }
  12471. if ( $.isArray( this.options.values ) ) {
  12472. valsLength = this.options.values.length;
  12473. }
  12474. this._super( key, value );
  12475. switch ( key ) {
  12476. case "orientation":
  12477. this._detectOrientation();
  12478. this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
  12479. ._addClass( "ui-slider-" + this.orientation );
  12480. this._refreshValue();
  12481. if ( this.options.range ) {
  12482. this._refreshRange( value );
  12483. }
  12484. // Reset positioning from previous orientation
  12485. this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
  12486. break;
  12487. case "value":
  12488. this._animateOff = true;
  12489. this._refreshValue();
  12490. this._change( null, 0 );
  12491. this._animateOff = false;
  12492. break;
  12493. case "values":
  12494. this._animateOff = true;
  12495. this._refreshValue();
  12496. // Start from the last handle to prevent unreachable handles (#9046)
  12497. for ( i = valsLength - 1; i >= 0; i-- ) {
  12498. this._change( null, i );
  12499. }
  12500. this._animateOff = false;
  12501. break;
  12502. case "step":
  12503. case "min":
  12504. case "max":
  12505. this._animateOff = true;
  12506. this._calculateNewMax();
  12507. this._refreshValue();
  12508. this._animateOff = false;
  12509. break;
  12510. case "range":
  12511. this._animateOff = true;
  12512. this._refresh();
  12513. this._animateOff = false;
  12514. break;
  12515. }
  12516. },
  12517. _setOptionDisabled: function( value ) {
  12518. this._super( value );
  12519. this._toggleClass( null, "ui-state-disabled", !!value );
  12520. },
  12521. //internal value getter
  12522. // _value() returns value trimmed by min and max, aligned by step
  12523. _value: function() {
  12524. var val = this.options.value;
  12525. val = this._trimAlignValue( val );
  12526. return val;
  12527. },
  12528. //internal values getter
  12529. // _values() returns array of values trimmed by min and max, aligned by step
  12530. // _values( index ) returns single value trimmed by min and max, aligned by step
  12531. _values: function( index ) {
  12532. var val,
  12533. vals,
  12534. i;
  12535. if ( arguments.length ) {
  12536. val = this.options.values[ index ];
  12537. val = this._trimAlignValue( val );
  12538. return val;
  12539. } else if ( this._hasMultipleValues() ) {
  12540. // .slice() creates a copy of the array
  12541. // this copy gets trimmed by min and max and then returned
  12542. vals = this.options.values.slice();
  12543. for ( i = 0; i < vals.length; i += 1 ) {
  12544. vals[ i ] = this._trimAlignValue( vals[ i ] );
  12545. }
  12546. return vals;
  12547. } else {
  12548. return [];
  12549. }
  12550. },
  12551. // Returns the step-aligned value that val is closest to, between (inclusive) min and max
  12552. _trimAlignValue: function( val ) {
  12553. if ( val <= this._valueMin() ) {
  12554. return this._valueMin();
  12555. }
  12556. if ( val >= this._valueMax() ) {
  12557. return this._valueMax();
  12558. }
  12559. var step = ( this.options.step > 0 ) ? this.options.step : 1,
  12560. valModStep = ( val - this._valueMin() ) % step,
  12561. alignValue = val - valModStep;
  12562. if ( Math.abs( valModStep ) * 2 >= step ) {
  12563. alignValue += ( valModStep > 0 ) ? step : ( -step );
  12564. }
  12565. // Since JavaScript has problems with large floats, round
  12566. // the final value to 5 digits after the decimal point (see #4124)
  12567. return parseFloat( alignValue.toFixed( 5 ) );
  12568. },
  12569. _calculateNewMax: function() {
  12570. var max = this.options.max,
  12571. min = this._valueMin(),
  12572. step = this.options.step,
  12573. aboveMin = Math.round( ( max - min ) / step ) * step;
  12574. max = aboveMin + min;
  12575. if ( max > this.options.max ) {
  12576. //If max is not divisible by step, rounding off may increase its value
  12577. max -= step;
  12578. }
  12579. this.max = parseFloat( max.toFixed( this._precision() ) );
  12580. },
  12581. _precision: function() {
  12582. var precision = this._precisionOf( this.options.step );
  12583. if ( this.options.min !== null ) {
  12584. precision = Math.max( precision, this._precisionOf( this.options.min ) );
  12585. }
  12586. return precision;
  12587. },
  12588. _precisionOf: function( num ) {
  12589. var str = num.toString(),
  12590. decimal = str.indexOf( "." );
  12591. return decimal === -1 ? 0 : str.length - decimal - 1;
  12592. },
  12593. _valueMin: function() {
  12594. return this.options.min;
  12595. },
  12596. _valueMax: function() {
  12597. return this.max;
  12598. },
  12599. _refreshRange: function( orientation ) {
  12600. if ( orientation === "vertical" ) {
  12601. this.range.css( { "width": "", "left": "" } );
  12602. }
  12603. if ( orientation === "horizontal" ) {
  12604. this.range.css( { "height": "", "bottom": "" } );
  12605. }
  12606. },
  12607. _refreshValue: function() {
  12608. var lastValPercent, valPercent, value, valueMin, valueMax,
  12609. oRange = this.options.range,
  12610. o = this.options,
  12611. that = this,
  12612. animate = ( !this._animateOff ) ? o.animate : false,
  12613. _set = {};
  12614. if ( this._hasMultipleValues() ) {
  12615. this.handles.each( function( i ) {
  12616. valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
  12617. that._valueMin() ) * 100;
  12618. _set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
  12619. $( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
  12620. if ( that.options.range === true ) {
  12621. if ( that.orientation === "horizontal" ) {
  12622. if ( i === 0 ) {
  12623. that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
  12624. left: valPercent + "%"
  12625. }, o.animate );
  12626. }
  12627. if ( i === 1 ) {
  12628. that.range[ animate ? "animate" : "css" ]( {
  12629. width: ( valPercent - lastValPercent ) + "%"
  12630. }, {
  12631. queue: false,
  12632. duration: o.animate
  12633. } );
  12634. }
  12635. } else {
  12636. if ( i === 0 ) {
  12637. that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
  12638. bottom: ( valPercent ) + "%"
  12639. }, o.animate );
  12640. }
  12641. if ( i === 1 ) {
  12642. that.range[ animate ? "animate" : "css" ]( {
  12643. height: ( valPercent - lastValPercent ) + "%"
  12644. }, {
  12645. queue: false,
  12646. duration: o.animate
  12647. } );
  12648. }
  12649. }
  12650. }
  12651. lastValPercent = valPercent;
  12652. } );
  12653. } else {
  12654. value = this.value();
  12655. valueMin = this._valueMin();
  12656. valueMax = this._valueMax();
  12657. valPercent = ( valueMax !== valueMin ) ?
  12658. ( value - valueMin ) / ( valueMax - valueMin ) * 100 :
  12659. 0;
  12660. _set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
  12661. this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
  12662. if ( oRange === "min" && this.orientation === "horizontal" ) {
  12663. this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
  12664. width: valPercent + "%"
  12665. }, o.animate );
  12666. }
  12667. if ( oRange === "max" && this.orientation === "horizontal" ) {
  12668. this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
  12669. width: ( 100 - valPercent ) + "%"
  12670. }, o.animate );
  12671. }
  12672. if ( oRange === "min" && this.orientation === "vertical" ) {
  12673. this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
  12674. height: valPercent + "%"
  12675. }, o.animate );
  12676. }
  12677. if ( oRange === "max" && this.orientation === "vertical" ) {
  12678. this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
  12679. height: ( 100 - valPercent ) + "%"
  12680. }, o.animate );
  12681. }
  12682. }
  12683. },
  12684. _handleEvents: {
  12685. keydown: function( event ) {
  12686. var allowed, curVal, newVal, step,
  12687. index = $( event.target ).data( "ui-slider-handle-index" );
  12688. switch ( event.keyCode ) {
  12689. case $.ui.keyCode.HOME:
  12690. case $.ui.keyCode.END:
  12691. case $.ui.keyCode.PAGE_UP:
  12692. case $.ui.keyCode.PAGE_DOWN:
  12693. case $.ui.keyCode.UP:
  12694. case $.ui.keyCode.RIGHT:
  12695. case $.ui.keyCode.DOWN:
  12696. case $.ui.keyCode.LEFT:
  12697. event.preventDefault();
  12698. if ( !this._keySliding ) {
  12699. this._keySliding = true;
  12700. this._addClass( $( event.target ), null, "ui-state-active" );
  12701. allowed = this._start( event, index );
  12702. if ( allowed === false ) {
  12703. return;
  12704. }
  12705. }
  12706. break;
  12707. }
  12708. step = this.options.step;
  12709. if ( this._hasMultipleValues() ) {
  12710. curVal = newVal = this.values( index );
  12711. } else {
  12712. curVal = newVal = this.value();
  12713. }
  12714. switch ( event.keyCode ) {
  12715. case $.ui.keyCode.HOME:
  12716. newVal = this._valueMin();
  12717. break;
  12718. case $.ui.keyCode.END:
  12719. newVal = this._valueMax();
  12720. break;
  12721. case $.ui.keyCode.PAGE_UP:
  12722. newVal = this._trimAlignValue(
  12723. curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
  12724. );
  12725. break;
  12726. case $.ui.keyCode.PAGE_DOWN:
  12727. newVal = this._trimAlignValue(
  12728. curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
  12729. break;
  12730. case $.ui.keyCode.UP:
  12731. case $.ui.keyCode.RIGHT:
  12732. if ( curVal === this._valueMax() ) {
  12733. return;
  12734. }
  12735. newVal = this._trimAlignValue( curVal + step );
  12736. break;
  12737. case $.ui.keyCode.DOWN:
  12738. case $.ui.keyCode.LEFT:
  12739. if ( curVal === this._valueMin() ) {
  12740. return;
  12741. }
  12742. newVal = this._trimAlignValue( curVal - step );
  12743. break;
  12744. }
  12745. this._slide( event, index, newVal );
  12746. },
  12747. keyup: function( event ) {
  12748. var index = $( event.target ).data( "ui-slider-handle-index" );
  12749. if ( this._keySliding ) {
  12750. this._keySliding = false;
  12751. this._stop( event, index );
  12752. this._change( event, index );
  12753. this._removeClass( $( event.target ), null, "ui-state-active" );
  12754. }
  12755. }
  12756. }
  12757. } );
  12758. /*!
  12759. * jQuery UI Sortable 1.12.1
  12760. * http://jqueryui.com
  12761. *
  12762. * Copyright jQuery Foundation and other contributors
  12763. * Released under the MIT license.
  12764. * http://jquery.org/license
  12765. */
  12766. //>>label: Sortable
  12767. //>>group: Interactions
  12768. //>>description: Enables items in a list to be sorted using the mouse.
  12769. //>>docs: http://api.jqueryui.com/sortable/
  12770. //>>demos: http://jqueryui.com/sortable/
  12771. //>>css.structure: ../../themes/base/sortable.css
  12772. var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
  12773. version: "1.12.1",
  12774. widgetEventPrefix: "sort",
  12775. ready: false,
  12776. options: {
  12777. appendTo: "parent",
  12778. axis: false,
  12779. connectWith: false,
  12780. containment: false,
  12781. cursor: "auto",
  12782. cursorAt: false,
  12783. dropOnEmpty: true,
  12784. forcePlaceholderSize: false,
  12785. forceHelperSize: false,
  12786. grid: false,
  12787. handle: false,
  12788. helper: "original",
  12789. items: "> *",
  12790. opacity: false,
  12791. placeholder: false,
  12792. revert: false,
  12793. scroll: true,
  12794. scrollSensitivity: 20,
  12795. scrollSpeed: 20,
  12796. scope: "default",
  12797. tolerance: "intersect",
  12798. zIndex: 1000,
  12799. // Callbacks
  12800. activate: null,
  12801. beforeStop: null,
  12802. change: null,
  12803. deactivate: null,
  12804. out: null,
  12805. over: null,
  12806. receive: null,
  12807. remove: null,
  12808. sort: null,
  12809. start: null,
  12810. stop: null,
  12811. update: null
  12812. },
  12813. _isOverAxis: function( x, reference, size ) {
  12814. return ( x >= reference ) && ( x < ( reference + size ) );
  12815. },
  12816. _isFloating: function( item ) {
  12817. return ( /left|right/ ).test( item.css( "float" ) ) ||
  12818. ( /inline|table-cell/ ).test( item.css( "display" ) );
  12819. },
  12820. _create: function() {
  12821. this.containerCache = {};
  12822. this._addClass( "ui-sortable" );
  12823. //Get the items
  12824. this.refresh();
  12825. //Let's determine the parent's offset
  12826. this.offset = this.element.offset();
  12827. //Initialize mouse events for interaction
  12828. this._mouseInit();
  12829. this._setHandleClassName();
  12830. //We're ready to go
  12831. this.ready = true;
  12832. },
  12833. _setOption: function( key, value ) {
  12834. this._super( key, value );
  12835. if ( key === "handle" ) {
  12836. this._setHandleClassName();
  12837. }
  12838. },
  12839. _setHandleClassName: function() {
  12840. var that = this;
  12841. this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
  12842. $.each( this.items, function() {
  12843. that._addClass(
  12844. this.instance.options.handle ?
  12845. this.item.find( this.instance.options.handle ) :
  12846. this.item,
  12847. "ui-sortable-handle"
  12848. );
  12849. } );
  12850. },
  12851. _destroy: function() {
  12852. this._mouseDestroy();
  12853. for ( var i = this.items.length - 1; i >= 0; i-- ) {
  12854. this.items[ i ].item.removeData( this.widgetName + "-item" );
  12855. }
  12856. return this;
  12857. },
  12858. _mouseCapture: function( event, overrideHandle ) {
  12859. var currentItem = null,
  12860. validHandle = false,
  12861. that = this;
  12862. if ( this.reverting ) {
  12863. return false;
  12864. }
  12865. if ( this.options.disabled || this.options.type === "static" ) {
  12866. return false;
  12867. }
  12868. //We have to refresh the items data once first
  12869. this._refreshItems( event );
  12870. //Find out if the clicked node (or one of its parents) is a actual item in this.items
  12871. $( event.target ).parents().each( function() {
  12872. if ( $.data( this, that.widgetName + "-item" ) === that ) {
  12873. currentItem = $( this );
  12874. return false;
  12875. }
  12876. } );
  12877. if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
  12878. currentItem = $( event.target );
  12879. }
  12880. if ( !currentItem ) {
  12881. return false;
  12882. }
  12883. if ( this.options.handle && !overrideHandle ) {
  12884. $( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
  12885. if ( this === event.target ) {
  12886. validHandle = true;
  12887. }
  12888. } );
  12889. if ( !validHandle ) {
  12890. return false;
  12891. }
  12892. }
  12893. this.currentItem = currentItem;
  12894. this._removeCurrentsFromItems();
  12895. return true;
  12896. },
  12897. _mouseStart: function( event, overrideHandle, noActivation ) {
  12898. var i, body,
  12899. o = this.options;
  12900. this.currentContainer = this;
  12901. //We only need to call refreshPositions, because the refreshItems call has been moved to
  12902. // mouseCapture
  12903. this.refreshPositions();
  12904. //Create and append the visible helper
  12905. this.helper = this._createHelper( event );
  12906. //Cache the helper size
  12907. this._cacheHelperProportions();
  12908. /*
  12909. * - Position generation -
  12910. * This block generates everything position related - it's the core of draggables.
  12911. */
  12912. //Cache the margins of the original element
  12913. this._cacheMargins();
  12914. //Get the next scrolling parent
  12915. this.scrollParent = this.helper.scrollParent();
  12916. //The element's absolute position on the page minus margins
  12917. this.offset = this.currentItem.offset();
  12918. this.offset = {
  12919. top: this.offset.top - this.margins.top,
  12920. left: this.offset.left - this.margins.left
  12921. };
  12922. $.extend( this.offset, {
  12923. click: { //Where the click happened, relative to the element
  12924. left: event.pageX - this.offset.left,
  12925. top: event.pageY - this.offset.top
  12926. },
  12927. parent: this._getParentOffset(),
  12928. // This is a relative to absolute position minus the actual position calculation -
  12929. // only used for relative positioned helper
  12930. relative: this._getRelativeOffset()
  12931. } );
  12932. // Only after we got the offset, we can change the helper's position to absolute
  12933. // TODO: Still need to figure out a way to make relative sorting possible
  12934. this.helper.css( "position", "absolute" );
  12935. this.cssPosition = this.helper.css( "position" );
  12936. //Generate the original position
  12937. this.originalPosition = this._generatePosition( event );
  12938. this.originalPageX = event.pageX;
  12939. this.originalPageY = event.pageY;
  12940. //Adjust the mouse offset relative to the helper if "cursorAt" is supplied
  12941. ( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
  12942. //Cache the former DOM position
  12943. this.domPosition = {
  12944. prev: this.currentItem.prev()[ 0 ],
  12945. parent: this.currentItem.parent()[ 0 ]
  12946. };
  12947. // If the helper is not the original, hide the original so it's not playing any role during
  12948. // the drag, won't cause anything bad this way
  12949. if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
  12950. this.currentItem.hide();
  12951. }
  12952. //Create the placeholder
  12953. this._createPlaceholder();
  12954. //Set a containment if given in the options
  12955. if ( o.containment ) {
  12956. this._setContainment();
  12957. }
  12958. if ( o.cursor && o.cursor !== "auto" ) { // cursor option
  12959. body = this.document.find( "body" );
  12960. // Support: IE
  12961. this.storedCursor = body.css( "cursor" );
  12962. body.css( "cursor", o.cursor );
  12963. this.storedStylesheet =
  12964. $( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
  12965. }
  12966. if ( o.opacity ) { // opacity option
  12967. if ( this.helper.css( "opacity" ) ) {
  12968. this._storedOpacity = this.helper.css( "opacity" );
  12969. }
  12970. this.helper.css( "opacity", o.opacity );
  12971. }
  12972. if ( o.zIndex ) { // zIndex option
  12973. if ( this.helper.css( "zIndex" ) ) {
  12974. this._storedZIndex = this.helper.css( "zIndex" );
  12975. }
  12976. this.helper.css( "zIndex", o.zIndex );
  12977. }
  12978. //Prepare scrolling
  12979. if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  12980. this.scrollParent[ 0 ].tagName !== "HTML" ) {
  12981. this.overflowOffset = this.scrollParent.offset();
  12982. }
  12983. //Call callbacks
  12984. this._trigger( "start", event, this._uiHash() );
  12985. //Recache the helper size
  12986. if ( !this._preserveHelperProportions ) {
  12987. this._cacheHelperProportions();
  12988. }
  12989. //Post "activate" events to possible containers
  12990. if ( !noActivation ) {
  12991. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  12992. this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
  12993. }
  12994. }
  12995. //Prepare possible droppables
  12996. if ( $.ui.ddmanager ) {
  12997. $.ui.ddmanager.current = this;
  12998. }
  12999. if ( $.ui.ddmanager && !o.dropBehaviour ) {
  13000. $.ui.ddmanager.prepareOffsets( this, event );
  13001. }
  13002. this.dragging = true;
  13003. this._addClass( this.helper, "ui-sortable-helper" );
  13004. // Execute the drag once - this causes the helper not to be visiblebefore getting its
  13005. // correct position
  13006. this._mouseDrag( event );
  13007. return true;
  13008. },
  13009. _mouseDrag: function( event ) {
  13010. var i, item, itemElement, intersection,
  13011. o = this.options,
  13012. scrolled = false;
  13013. //Compute the helpers position
  13014. this.position = this._generatePosition( event );
  13015. this.positionAbs = this._convertPositionTo( "absolute" );
  13016. if ( !this.lastPositionAbs ) {
  13017. this.lastPositionAbs = this.positionAbs;
  13018. }
  13019. //Do scrolling
  13020. if ( this.options.scroll ) {
  13021. if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  13022. this.scrollParent[ 0 ].tagName !== "HTML" ) {
  13023. if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
  13024. event.pageY < o.scrollSensitivity ) {
  13025. this.scrollParent[ 0 ].scrollTop =
  13026. scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
  13027. } else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
  13028. this.scrollParent[ 0 ].scrollTop =
  13029. scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
  13030. }
  13031. if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
  13032. event.pageX < o.scrollSensitivity ) {
  13033. this.scrollParent[ 0 ].scrollLeft = scrolled =
  13034. this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
  13035. } else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
  13036. this.scrollParent[ 0 ].scrollLeft = scrolled =
  13037. this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
  13038. }
  13039. } else {
  13040. if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
  13041. scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
  13042. } else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
  13043. o.scrollSensitivity ) {
  13044. scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
  13045. }
  13046. if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
  13047. scrolled = this.document.scrollLeft(
  13048. this.document.scrollLeft() - o.scrollSpeed
  13049. );
  13050. } else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
  13051. o.scrollSensitivity ) {
  13052. scrolled = this.document.scrollLeft(
  13053. this.document.scrollLeft() + o.scrollSpeed
  13054. );
  13055. }
  13056. }
  13057. if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
  13058. $.ui.ddmanager.prepareOffsets( this, event );
  13059. }
  13060. }
  13061. //Regenerate the absolute position used for position checks
  13062. this.positionAbs = this._convertPositionTo( "absolute" );
  13063. //Set the helper position
  13064. if ( !this.options.axis || this.options.axis !== "y" ) {
  13065. this.helper[ 0 ].style.left = this.position.left + "px";
  13066. }
  13067. if ( !this.options.axis || this.options.axis !== "x" ) {
  13068. this.helper[ 0 ].style.top = this.position.top + "px";
  13069. }
  13070. //Rearrange
  13071. for ( i = this.items.length - 1; i >= 0; i-- ) {
  13072. //Cache variables and intersection, continue if no intersection
  13073. item = this.items[ i ];
  13074. itemElement = item.item[ 0 ];
  13075. intersection = this._intersectsWithPointer( item );
  13076. if ( !intersection ) {
  13077. continue;
  13078. }
  13079. // Only put the placeholder inside the current Container, skip all
  13080. // items from other containers. This works because when moving
  13081. // an item from one container to another the
  13082. // currentContainer is switched before the placeholder is moved.
  13083. //
  13084. // Without this, moving items in "sub-sortables" can cause
  13085. // the placeholder to jitter between the outer and inner container.
  13086. if ( item.instance !== this.currentContainer ) {
  13087. continue;
  13088. }
  13089. // Cannot intersect with itself
  13090. // no useless actions that have been done before
  13091. // no action if the item moved is the parent of the item checked
  13092. if ( itemElement !== this.currentItem[ 0 ] &&
  13093. this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
  13094. !$.contains( this.placeholder[ 0 ], itemElement ) &&
  13095. ( this.options.type === "semi-dynamic" ?
  13096. !$.contains( this.element[ 0 ], itemElement ) :
  13097. true
  13098. )
  13099. ) {
  13100. this.direction = intersection === 1 ? "down" : "up";
  13101. if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
  13102. this._rearrange( event, item );
  13103. } else {
  13104. break;
  13105. }
  13106. this._trigger( "change", event, this._uiHash() );
  13107. break;
  13108. }
  13109. }
  13110. //Post events to containers
  13111. this._contactContainers( event );
  13112. //Interconnect with droppables
  13113. if ( $.ui.ddmanager ) {
  13114. $.ui.ddmanager.drag( this, event );
  13115. }
  13116. //Call callbacks
  13117. this._trigger( "sort", event, this._uiHash() );
  13118. this.lastPositionAbs = this.positionAbs;
  13119. return false;
  13120. },
  13121. _mouseStop: function( event, noPropagation ) {
  13122. if ( !event ) {
  13123. return;
  13124. }
  13125. //If we are using droppables, inform the manager about the drop
  13126. if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
  13127. $.ui.ddmanager.drop( this, event );
  13128. }
  13129. if ( this.options.revert ) {
  13130. var that = this,
  13131. cur = this.placeholder.offset(),
  13132. axis = this.options.axis,
  13133. animation = {};
  13134. if ( !axis || axis === "x" ) {
  13135. animation.left = cur.left - this.offset.parent.left - this.margins.left +
  13136. ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
  13137. 0 :
  13138. this.offsetParent[ 0 ].scrollLeft
  13139. );
  13140. }
  13141. if ( !axis || axis === "y" ) {
  13142. animation.top = cur.top - this.offset.parent.top - this.margins.top +
  13143. ( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
  13144. 0 :
  13145. this.offsetParent[ 0 ].scrollTop
  13146. );
  13147. }
  13148. this.reverting = true;
  13149. $( this.helper ).animate(
  13150. animation,
  13151. parseInt( this.options.revert, 10 ) || 500,
  13152. function() {
  13153. that._clear( event );
  13154. }
  13155. );
  13156. } else {
  13157. this._clear( event, noPropagation );
  13158. }
  13159. return false;
  13160. },
  13161. cancel: function() {
  13162. if ( this.dragging ) {
  13163. this._mouseUp( new $.Event( "mouseup", { target: null } ) );
  13164. if ( this.options.helper === "original" ) {
  13165. this.currentItem.css( this._storedCSS );
  13166. this._removeClass( this.currentItem, "ui-sortable-helper" );
  13167. } else {
  13168. this.currentItem.show();
  13169. }
  13170. //Post deactivating events to containers
  13171. for ( var i = this.containers.length - 1; i >= 0; i-- ) {
  13172. this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
  13173. if ( this.containers[ i ].containerCache.over ) {
  13174. this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
  13175. this.containers[ i ].containerCache.over = 0;
  13176. }
  13177. }
  13178. }
  13179. if ( this.placeholder ) {
  13180. //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
  13181. // it unbinds ALL events from the original node!
  13182. if ( this.placeholder[ 0 ].parentNode ) {
  13183. this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
  13184. }
  13185. if ( this.options.helper !== "original" && this.helper &&
  13186. this.helper[ 0 ].parentNode ) {
  13187. this.helper.remove();
  13188. }
  13189. $.extend( this, {
  13190. helper: null,
  13191. dragging: false,
  13192. reverting: false,
  13193. _noFinalSort: null
  13194. } );
  13195. if ( this.domPosition.prev ) {
  13196. $( this.domPosition.prev ).after( this.currentItem );
  13197. } else {
  13198. $( this.domPosition.parent ).prepend( this.currentItem );
  13199. }
  13200. }
  13201. return this;
  13202. },
  13203. serialize: function( o ) {
  13204. var items = this._getItemsAsjQuery( o && o.connected ),
  13205. str = [];
  13206. o = o || {};
  13207. $( items ).each( function() {
  13208. var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
  13209. .match( o.expression || ( /(.+)[\-=_](.+)/ ) );
  13210. if ( res ) {
  13211. str.push(
  13212. ( o.key || res[ 1 ] + "[]" ) +
  13213. "=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
  13214. }
  13215. } );
  13216. if ( !str.length && o.key ) {
  13217. str.push( o.key + "=" );
  13218. }
  13219. return str.join( "&" );
  13220. },
  13221. toArray: function( o ) {
  13222. var items = this._getItemsAsjQuery( o && o.connected ),
  13223. ret = [];
  13224. o = o || {};
  13225. items.each( function() {
  13226. ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
  13227. } );
  13228. return ret;
  13229. },
  13230. /* Be careful with the following core functions */
  13231. _intersectsWith: function( item ) {
  13232. var x1 = this.positionAbs.left,
  13233. x2 = x1 + this.helperProportions.width,
  13234. y1 = this.positionAbs.top,
  13235. y2 = y1 + this.helperProportions.height,
  13236. l = item.left,
  13237. r = l + item.width,
  13238. t = item.top,
  13239. b = t + item.height,
  13240. dyClick = this.offset.click.top,
  13241. dxClick = this.offset.click.left,
  13242. isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
  13243. ( y1 + dyClick ) < b ),
  13244. isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
  13245. ( x1 + dxClick ) < r ),
  13246. isOverElement = isOverElementHeight && isOverElementWidth;
  13247. if ( this.options.tolerance === "pointer" ||
  13248. this.options.forcePointerForContainers ||
  13249. ( this.options.tolerance !== "pointer" &&
  13250. this.helperProportions[ this.floating ? "width" : "height" ] >
  13251. item[ this.floating ? "width" : "height" ] )
  13252. ) {
  13253. return isOverElement;
  13254. } else {
  13255. return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
  13256. x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
  13257. t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
  13258. y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
  13259. }
  13260. },
  13261. _intersectsWithPointer: function( item ) {
  13262. var verticalDirection, horizontalDirection,
  13263. isOverElementHeight = ( this.options.axis === "x" ) ||
  13264. this._isOverAxis(
  13265. this.positionAbs.top + this.offset.click.top, item.top, item.height ),
  13266. isOverElementWidth = ( this.options.axis === "y" ) ||
  13267. this._isOverAxis(
  13268. this.positionAbs.left + this.offset.click.left, item.left, item.width ),
  13269. isOverElement = isOverElementHeight && isOverElementWidth;
  13270. if ( !isOverElement ) {
  13271. return false;
  13272. }
  13273. verticalDirection = this._getDragVerticalDirection();
  13274. horizontalDirection = this._getDragHorizontalDirection();
  13275. return this.floating ?
  13276. ( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
  13277. : ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
  13278. },
  13279. _intersectsWithSides: function( item ) {
  13280. var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
  13281. this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
  13282. isOverRightHalf = this._isOverAxis( this.positionAbs.left +
  13283. this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
  13284. verticalDirection = this._getDragVerticalDirection(),
  13285. horizontalDirection = this._getDragHorizontalDirection();
  13286. if ( this.floating && horizontalDirection ) {
  13287. return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
  13288. ( horizontalDirection === "left" && !isOverRightHalf ) );
  13289. } else {
  13290. return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
  13291. ( verticalDirection === "up" && !isOverBottomHalf ) );
  13292. }
  13293. },
  13294. _getDragVerticalDirection: function() {
  13295. var delta = this.positionAbs.top - this.lastPositionAbs.top;
  13296. return delta !== 0 && ( delta > 0 ? "down" : "up" );
  13297. },
  13298. _getDragHorizontalDirection: function() {
  13299. var delta = this.positionAbs.left - this.lastPositionAbs.left;
  13300. return delta !== 0 && ( delta > 0 ? "right" : "left" );
  13301. },
  13302. refresh: function( event ) {
  13303. this._refreshItems( event );
  13304. this._setHandleClassName();
  13305. this.refreshPositions();
  13306. return this;
  13307. },
  13308. _connectWith: function() {
  13309. var options = this.options;
  13310. return options.connectWith.constructor === String ?
  13311. [ options.connectWith ] :
  13312. options.connectWith;
  13313. },
  13314. _getItemsAsjQuery: function( connected ) {
  13315. var i, j, cur, inst,
  13316. items = [],
  13317. queries = [],
  13318. connectWith = this._connectWith();
  13319. if ( connectWith && connected ) {
  13320. for ( i = connectWith.length - 1; i >= 0; i-- ) {
  13321. cur = $( connectWith[ i ], this.document[ 0 ] );
  13322. for ( j = cur.length - 1; j >= 0; j-- ) {
  13323. inst = $.data( cur[ j ], this.widgetFullName );
  13324. if ( inst && inst !== this && !inst.options.disabled ) {
  13325. queries.push( [ $.isFunction( inst.options.items ) ?
  13326. inst.options.items.call( inst.element ) :
  13327. $( inst.options.items, inst.element )
  13328. .not( ".ui-sortable-helper" )
  13329. .not( ".ui-sortable-placeholder" ), inst ] );
  13330. }
  13331. }
  13332. }
  13333. }
  13334. queries.push( [ $.isFunction( this.options.items ) ?
  13335. this.options.items
  13336. .call( this.element, null, { options: this.options, item: this.currentItem } ) :
  13337. $( this.options.items, this.element )
  13338. .not( ".ui-sortable-helper" )
  13339. .not( ".ui-sortable-placeholder" ), this ] );
  13340. function addItems() {
  13341. items.push( this );
  13342. }
  13343. for ( i = queries.length - 1; i >= 0; i-- ) {
  13344. queries[ i ][ 0 ].each( addItems );
  13345. }
  13346. return $( items );
  13347. },
  13348. _removeCurrentsFromItems: function() {
  13349. var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
  13350. this.items = $.grep( this.items, function( item ) {
  13351. for ( var j = 0; j < list.length; j++ ) {
  13352. if ( list[ j ] === item.item[ 0 ] ) {
  13353. return false;
  13354. }
  13355. }
  13356. return true;
  13357. } );
  13358. },
  13359. _refreshItems: function( event ) {
  13360. this.items = [];
  13361. this.containers = [ this ];
  13362. var i, j, cur, inst, targetData, _queries, item, queriesLength,
  13363. items = this.items,
  13364. queries = [ [ $.isFunction( this.options.items ) ?
  13365. this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
  13366. $( this.options.items, this.element ), this ] ],
  13367. connectWith = this._connectWith();
  13368. //Shouldn't be run the first time through due to massive slow-down
  13369. if ( connectWith && this.ready ) {
  13370. for ( i = connectWith.length - 1; i >= 0; i-- ) {
  13371. cur = $( connectWith[ i ], this.document[ 0 ] );
  13372. for ( j = cur.length - 1; j >= 0; j-- ) {
  13373. inst = $.data( cur[ j ], this.widgetFullName );
  13374. if ( inst && inst !== this && !inst.options.disabled ) {
  13375. queries.push( [ $.isFunction( inst.options.items ) ?
  13376. inst.options.items
  13377. .call( inst.element[ 0 ], event, { item: this.currentItem } ) :
  13378. $( inst.options.items, inst.element ), inst ] );
  13379. this.containers.push( inst );
  13380. }
  13381. }
  13382. }
  13383. }
  13384. for ( i = queries.length - 1; i >= 0; i-- ) {
  13385. targetData = queries[ i ][ 1 ];
  13386. _queries = queries[ i ][ 0 ];
  13387. for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
  13388. item = $( _queries[ j ] );
  13389. // Data for target checking (mouse manager)
  13390. item.data( this.widgetName + "-item", targetData );
  13391. items.push( {
  13392. item: item,
  13393. instance: targetData,
  13394. width: 0, height: 0,
  13395. left: 0, top: 0
  13396. } );
  13397. }
  13398. }
  13399. },
  13400. refreshPositions: function( fast ) {
  13401. // Determine whether items are being displayed horizontally
  13402. this.floating = this.items.length ?
  13403. this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
  13404. false;
  13405. //This has to be redone because due to the item being moved out/into the offsetParent,
  13406. // the offsetParent's position will change
  13407. if ( this.offsetParent && this.helper ) {
  13408. this.offset.parent = this._getParentOffset();
  13409. }
  13410. var i, item, t, p;
  13411. for ( i = this.items.length - 1; i >= 0; i-- ) {
  13412. item = this.items[ i ];
  13413. //We ignore calculating positions of all connected containers when we're not over them
  13414. if ( item.instance !== this.currentContainer && this.currentContainer &&
  13415. item.item[ 0 ] !== this.currentItem[ 0 ] ) {
  13416. continue;
  13417. }
  13418. t = this.options.toleranceElement ?
  13419. $( this.options.toleranceElement, item.item ) :
  13420. item.item;
  13421. if ( !fast ) {
  13422. item.width = t.outerWidth();
  13423. item.height = t.outerHeight();
  13424. }
  13425. p = t.offset();
  13426. item.left = p.left;
  13427. item.top = p.top;
  13428. }
  13429. if ( this.options.custom && this.options.custom.refreshContainers ) {
  13430. this.options.custom.refreshContainers.call( this );
  13431. } else {
  13432. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  13433. p = this.containers[ i ].element.offset();
  13434. this.containers[ i ].containerCache.left = p.left;
  13435. this.containers[ i ].containerCache.top = p.top;
  13436. this.containers[ i ].containerCache.width =
  13437. this.containers[ i ].element.outerWidth();
  13438. this.containers[ i ].containerCache.height =
  13439. this.containers[ i ].element.outerHeight();
  13440. }
  13441. }
  13442. return this;
  13443. },
  13444. _createPlaceholder: function( that ) {
  13445. that = that || this;
  13446. var className,
  13447. o = that.options;
  13448. if ( !o.placeholder || o.placeholder.constructor === String ) {
  13449. className = o.placeholder;
  13450. o.placeholder = {
  13451. element: function() {
  13452. var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
  13453. element = $( "<" + nodeName + ">", that.document[ 0 ] );
  13454. that._addClass( element, "ui-sortable-placeholder",
  13455. className || that.currentItem[ 0 ].className )
  13456. ._removeClass( element, "ui-sortable-helper" );
  13457. if ( nodeName === "tbody" ) {
  13458. that._createTrPlaceholder(
  13459. that.currentItem.find( "tr" ).eq( 0 ),
  13460. $( "<tr>", that.document[ 0 ] ).appendTo( element )
  13461. );
  13462. } else if ( nodeName === "tr" ) {
  13463. that._createTrPlaceholder( that.currentItem, element );
  13464. } else if ( nodeName === "img" ) {
  13465. element.attr( "src", that.currentItem.attr( "src" ) );
  13466. }
  13467. if ( !className ) {
  13468. element.css( "visibility", "hidden" );
  13469. }
  13470. return element;
  13471. },
  13472. update: function( container, p ) {
  13473. // 1. If a className is set as 'placeholder option, we don't force sizes -
  13474. // the class is responsible for that
  13475. // 2. The option 'forcePlaceholderSize can be enabled to force it even if a
  13476. // class name is specified
  13477. if ( className && !o.forcePlaceholderSize ) {
  13478. return;
  13479. }
  13480. //If the element doesn't have a actual height by itself (without styles coming
  13481. // from a stylesheet), it receives the inline height from the dragged item
  13482. if ( !p.height() ) {
  13483. p.height(
  13484. that.currentItem.innerHeight() -
  13485. parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
  13486. parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
  13487. }
  13488. if ( !p.width() ) {
  13489. p.width(
  13490. that.currentItem.innerWidth() -
  13491. parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
  13492. parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
  13493. }
  13494. }
  13495. };
  13496. }
  13497. //Create the placeholder
  13498. that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
  13499. //Append it after the actual current item
  13500. that.currentItem.after( that.placeholder );
  13501. //Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
  13502. o.placeholder.update( that, that.placeholder );
  13503. },
  13504. _createTrPlaceholder: function( sourceTr, targetTr ) {
  13505. var that = this;
  13506. sourceTr.children().each( function() {
  13507. $( "<td>&#160;</td>", that.document[ 0 ] )
  13508. .attr( "colspan", $( this ).attr( "colspan" ) || 1 )
  13509. .appendTo( targetTr );
  13510. } );
  13511. },
  13512. _contactContainers: function( event ) {
  13513. var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
  13514. floating, axis,
  13515. innermostContainer = null,
  13516. innermostIndex = null;
  13517. // Get innermost container that intersects with item
  13518. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  13519. // Never consider a container that's located within the item itself
  13520. if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
  13521. continue;
  13522. }
  13523. if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
  13524. // If we've already found a container and it's more "inner" than this, then continue
  13525. if ( innermostContainer &&
  13526. $.contains(
  13527. this.containers[ i ].element[ 0 ],
  13528. innermostContainer.element[ 0 ] ) ) {
  13529. continue;
  13530. }
  13531. innermostContainer = this.containers[ i ];
  13532. innermostIndex = i;
  13533. } else {
  13534. // container doesn't intersect. trigger "out" event if necessary
  13535. if ( this.containers[ i ].containerCache.over ) {
  13536. this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
  13537. this.containers[ i ].containerCache.over = 0;
  13538. }
  13539. }
  13540. }
  13541. // If no intersecting containers found, return
  13542. if ( !innermostContainer ) {
  13543. return;
  13544. }
  13545. // Move the item into the container if it's not there already
  13546. if ( this.containers.length === 1 ) {
  13547. if ( !this.containers[ innermostIndex ].containerCache.over ) {
  13548. this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
  13549. this.containers[ innermostIndex ].containerCache.over = 1;
  13550. }
  13551. } else {
  13552. // When entering a new container, we will find the item with the least distance and
  13553. // append our item near it
  13554. dist = 10000;
  13555. itemWithLeastDistance = null;
  13556. floating = innermostContainer.floating || this._isFloating( this.currentItem );
  13557. posProperty = floating ? "left" : "top";
  13558. sizeProperty = floating ? "width" : "height";
  13559. axis = floating ? "pageX" : "pageY";
  13560. for ( j = this.items.length - 1; j >= 0; j-- ) {
  13561. if ( !$.contains(
  13562. this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
  13563. ) {
  13564. continue;
  13565. }
  13566. if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
  13567. continue;
  13568. }
  13569. cur = this.items[ j ].item.offset()[ posProperty ];
  13570. nearBottom = false;
  13571. if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
  13572. nearBottom = true;
  13573. }
  13574. if ( Math.abs( event[ axis ] - cur ) < dist ) {
  13575. dist = Math.abs( event[ axis ] - cur );
  13576. itemWithLeastDistance = this.items[ j ];
  13577. this.direction = nearBottom ? "up" : "down";
  13578. }
  13579. }
  13580. //Check if dropOnEmpty is enabled
  13581. if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
  13582. return;
  13583. }
  13584. if ( this.currentContainer === this.containers[ innermostIndex ] ) {
  13585. if ( !this.currentContainer.containerCache.over ) {
  13586. this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
  13587. this.currentContainer.containerCache.over = 1;
  13588. }
  13589. return;
  13590. }
  13591. itemWithLeastDistance ?
  13592. this._rearrange( event, itemWithLeastDistance, null, true ) :
  13593. this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
  13594. this._trigger( "change", event, this._uiHash() );
  13595. this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
  13596. this.currentContainer = this.containers[ innermostIndex ];
  13597. //Update the placeholder
  13598. this.options.placeholder.update( this.currentContainer, this.placeholder );
  13599. this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
  13600. this.containers[ innermostIndex ].containerCache.over = 1;
  13601. }
  13602. },
  13603. _createHelper: function( event ) {
  13604. var o = this.options,
  13605. helper = $.isFunction( o.helper ) ?
  13606. $( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
  13607. ( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
  13608. //Add the helper to the DOM if that didn't happen already
  13609. if ( !helper.parents( "body" ).length ) {
  13610. $( o.appendTo !== "parent" ?
  13611. o.appendTo :
  13612. this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
  13613. }
  13614. if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
  13615. this._storedCSS = {
  13616. width: this.currentItem[ 0 ].style.width,
  13617. height: this.currentItem[ 0 ].style.height,
  13618. position: this.currentItem.css( "position" ),
  13619. top: this.currentItem.css( "top" ),
  13620. left: this.currentItem.css( "left" )
  13621. };
  13622. }
  13623. if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
  13624. helper.width( this.currentItem.width() );
  13625. }
  13626. if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
  13627. helper.height( this.currentItem.height() );
  13628. }
  13629. return helper;
  13630. },
  13631. _adjustOffsetFromHelper: function( obj ) {
  13632. if ( typeof obj === "string" ) {
  13633. obj = obj.split( " " );
  13634. }
  13635. if ( $.isArray( obj ) ) {
  13636. obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
  13637. }
  13638. if ( "left" in obj ) {
  13639. this.offset.click.left = obj.left + this.margins.left;
  13640. }
  13641. if ( "right" in obj ) {
  13642. this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
  13643. }
  13644. if ( "top" in obj ) {
  13645. this.offset.click.top = obj.top + this.margins.top;
  13646. }
  13647. if ( "bottom" in obj ) {
  13648. this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
  13649. }
  13650. },
  13651. _getParentOffset: function() {
  13652. //Get the offsetParent and cache its position
  13653. this.offsetParent = this.helper.offsetParent();
  13654. var po = this.offsetParent.offset();
  13655. // This is a special case where we need to modify a offset calculated on start, since the
  13656. // following happened:
  13657. // 1. The position of the helper is absolute, so it's position is calculated based on the
  13658. // next positioned parent
  13659. // 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
  13660. // the document, which means that the scroll is included in the initial calculation of the
  13661. // offset of the parent, and never recalculated upon drag
  13662. if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  13663. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
  13664. po.left += this.scrollParent.scrollLeft();
  13665. po.top += this.scrollParent.scrollTop();
  13666. }
  13667. // This needs to be actually done for all browsers, since pageX/pageY includes this
  13668. // information with an ugly IE fix
  13669. if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
  13670. ( this.offsetParent[ 0 ].tagName &&
  13671. this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
  13672. po = { top: 0, left: 0 };
  13673. }
  13674. return {
  13675. top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
  13676. left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
  13677. };
  13678. },
  13679. _getRelativeOffset: function() {
  13680. if ( this.cssPosition === "relative" ) {
  13681. var p = this.currentItem.position();
  13682. return {
  13683. top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
  13684. this.scrollParent.scrollTop(),
  13685. left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
  13686. this.scrollParent.scrollLeft()
  13687. };
  13688. } else {
  13689. return { top: 0, left: 0 };
  13690. }
  13691. },
  13692. _cacheMargins: function() {
  13693. this.margins = {
  13694. left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
  13695. top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
  13696. };
  13697. },
  13698. _cacheHelperProportions: function() {
  13699. this.helperProportions = {
  13700. width: this.helper.outerWidth(),
  13701. height: this.helper.outerHeight()
  13702. };
  13703. },
  13704. _setContainment: function() {
  13705. var ce, co, over,
  13706. o = this.options;
  13707. if ( o.containment === "parent" ) {
  13708. o.containment = this.helper[ 0 ].parentNode;
  13709. }
  13710. if ( o.containment === "document" || o.containment === "window" ) {
  13711. this.containment = [
  13712. 0 - this.offset.relative.left - this.offset.parent.left,
  13713. 0 - this.offset.relative.top - this.offset.parent.top,
  13714. o.containment === "document" ?
  13715. this.document.width() :
  13716. this.window.width() - this.helperProportions.width - this.margins.left,
  13717. ( o.containment === "document" ?
  13718. ( this.document.height() || document.body.parentNode.scrollHeight ) :
  13719. this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
  13720. ) - this.helperProportions.height - this.margins.top
  13721. ];
  13722. }
  13723. if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
  13724. ce = $( o.containment )[ 0 ];
  13725. co = $( o.containment ).offset();
  13726. over = ( $( ce ).css( "overflow" ) !== "hidden" );
  13727. this.containment = [
  13728. co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
  13729. ( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
  13730. co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
  13731. ( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
  13732. co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
  13733. ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
  13734. ( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
  13735. this.helperProportions.width - this.margins.left,
  13736. co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
  13737. ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
  13738. ( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
  13739. this.helperProportions.height - this.margins.top
  13740. ];
  13741. }
  13742. },
  13743. _convertPositionTo: function( d, pos ) {
  13744. if ( !pos ) {
  13745. pos = this.position;
  13746. }
  13747. var mod = d === "absolute" ? 1 : -1,
  13748. scroll = this.cssPosition === "absolute" &&
  13749. !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  13750. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
  13751. this.offsetParent :
  13752. this.scrollParent,
  13753. scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
  13754. return {
  13755. top: (
  13756. // The absolute mouse position
  13757. pos.top +
  13758. // Only for relative positioned nodes: Relative offset from element to offset parent
  13759. this.offset.relative.top * mod +
  13760. // The offsetParent's offset without borders (offset + border)
  13761. this.offset.parent.top * mod -
  13762. ( ( this.cssPosition === "fixed" ?
  13763. -this.scrollParent.scrollTop() :
  13764. ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
  13765. ),
  13766. left: (
  13767. // The absolute mouse position
  13768. pos.left +
  13769. // Only for relative positioned nodes: Relative offset from element to offset parent
  13770. this.offset.relative.left * mod +
  13771. // The offsetParent's offset without borders (offset + border)
  13772. this.offset.parent.left * mod -
  13773. ( ( this.cssPosition === "fixed" ?
  13774. -this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
  13775. scroll.scrollLeft() ) * mod )
  13776. )
  13777. };
  13778. },
  13779. _generatePosition: function( event ) {
  13780. var top, left,
  13781. o = this.options,
  13782. pageX = event.pageX,
  13783. pageY = event.pageY,
  13784. scroll = this.cssPosition === "absolute" &&
  13785. !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  13786. $.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
  13787. this.offsetParent :
  13788. this.scrollParent,
  13789. scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
  13790. // This is another very weird special case that only happens for relative elements:
  13791. // 1. If the css position is relative
  13792. // 2. and the scroll parent is the document or similar to the offset parent
  13793. // we have to refresh the relative offset during the scroll so there are no jumps
  13794. if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
  13795. this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
  13796. this.offset.relative = this._getRelativeOffset();
  13797. }
  13798. /*
  13799. * - Position constraining -
  13800. * Constrain the position to a mix of grid, containment.
  13801. */
  13802. if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
  13803. if ( this.containment ) {
  13804. if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
  13805. pageX = this.containment[ 0 ] + this.offset.click.left;
  13806. }
  13807. if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
  13808. pageY = this.containment[ 1 ] + this.offset.click.top;
  13809. }
  13810. if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
  13811. pageX = this.containment[ 2 ] + this.offset.click.left;
  13812. }
  13813. if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
  13814. pageY = this.containment[ 3 ] + this.offset.click.top;
  13815. }
  13816. }
  13817. if ( o.grid ) {
  13818. top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
  13819. o.grid[ 1 ] ) * o.grid[ 1 ];
  13820. pageY = this.containment ?
  13821. ( ( top - this.offset.click.top >= this.containment[ 1 ] &&
  13822. top - this.offset.click.top <= this.containment[ 3 ] ) ?
  13823. top :
  13824. ( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
  13825. top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
  13826. top;
  13827. left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
  13828. o.grid[ 0 ] ) * o.grid[ 0 ];
  13829. pageX = this.containment ?
  13830. ( ( left - this.offset.click.left >= this.containment[ 0 ] &&
  13831. left - this.offset.click.left <= this.containment[ 2 ] ) ?
  13832. left :
  13833. ( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
  13834. left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
  13835. left;
  13836. }
  13837. }
  13838. return {
  13839. top: (
  13840. // The absolute mouse position
  13841. pageY -
  13842. // Click offset (relative to the element)
  13843. this.offset.click.top -
  13844. // Only for relative positioned nodes: Relative offset from element to offset parent
  13845. this.offset.relative.top -
  13846. // The offsetParent's offset without borders (offset + border)
  13847. this.offset.parent.top +
  13848. ( ( this.cssPosition === "fixed" ?
  13849. -this.scrollParent.scrollTop() :
  13850. ( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
  13851. ),
  13852. left: (
  13853. // The absolute mouse position
  13854. pageX -
  13855. // Click offset (relative to the element)
  13856. this.offset.click.left -
  13857. // Only for relative positioned nodes: Relative offset from element to offset parent
  13858. this.offset.relative.left -
  13859. // The offsetParent's offset without borders (offset + border)
  13860. this.offset.parent.left +
  13861. ( ( this.cssPosition === "fixed" ?
  13862. -this.scrollParent.scrollLeft() :
  13863. scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
  13864. )
  13865. };
  13866. },
  13867. _rearrange: function( event, i, a, hardRefresh ) {
  13868. a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
  13869. i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
  13870. ( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
  13871. //Various things done here to improve the performance:
  13872. // 1. we create a setTimeout, that calls refreshPositions
  13873. // 2. on the instance, we have a counter variable, that get's higher after every append
  13874. // 3. on the local scope, we copy the counter variable, and check in the timeout,
  13875. // if it's still the same
  13876. // 4. this lets only the last addition to the timeout stack through
  13877. this.counter = this.counter ? ++this.counter : 1;
  13878. var counter = this.counter;
  13879. this._delay( function() {
  13880. if ( counter === this.counter ) {
  13881. //Precompute after each DOM insertion, NOT on mousemove
  13882. this.refreshPositions( !hardRefresh );
  13883. }
  13884. } );
  13885. },
  13886. _clear: function( event, noPropagation ) {
  13887. this.reverting = false;
  13888. // We delay all events that have to be triggered to after the point where the placeholder
  13889. // has been removed and everything else normalized again
  13890. var i,
  13891. delayedTriggers = [];
  13892. // We first have to update the dom position of the actual currentItem
  13893. // Note: don't do it if the current item is already removed (by a user), or it gets
  13894. // reappended (see #4088)
  13895. if ( !this._noFinalSort && this.currentItem.parent().length ) {
  13896. this.placeholder.before( this.currentItem );
  13897. }
  13898. this._noFinalSort = null;
  13899. if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
  13900. for ( i in this._storedCSS ) {
  13901. if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
  13902. this._storedCSS[ i ] = "";
  13903. }
  13904. }
  13905. this.currentItem.css( this._storedCSS );
  13906. this._removeClass( this.currentItem, "ui-sortable-helper" );
  13907. } else {
  13908. this.currentItem.show();
  13909. }
  13910. if ( this.fromOutside && !noPropagation ) {
  13911. delayedTriggers.push( function( event ) {
  13912. this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
  13913. } );
  13914. }
  13915. if ( ( this.fromOutside ||
  13916. this.domPosition.prev !==
  13917. this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
  13918. this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
  13919. // Trigger update callback if the DOM position has changed
  13920. delayedTriggers.push( function( event ) {
  13921. this._trigger( "update", event, this._uiHash() );
  13922. } );
  13923. }
  13924. // Check if the items Container has Changed and trigger appropriate
  13925. // events.
  13926. if ( this !== this.currentContainer ) {
  13927. if ( !noPropagation ) {
  13928. delayedTriggers.push( function( event ) {
  13929. this._trigger( "remove", event, this._uiHash() );
  13930. } );
  13931. delayedTriggers.push( ( function( c ) {
  13932. return function( event ) {
  13933. c._trigger( "receive", event, this._uiHash( this ) );
  13934. };
  13935. } ).call( this, this.currentContainer ) );
  13936. delayedTriggers.push( ( function( c ) {
  13937. return function( event ) {
  13938. c._trigger( "update", event, this._uiHash( this ) );
  13939. };
  13940. } ).call( this, this.currentContainer ) );
  13941. }
  13942. }
  13943. //Post events to containers
  13944. function delayEvent( type, instance, container ) {
  13945. return function( event ) {
  13946. container._trigger( type, event, instance._uiHash( instance ) );
  13947. };
  13948. }
  13949. for ( i = this.containers.length - 1; i >= 0; i-- ) {
  13950. if ( !noPropagation ) {
  13951. delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
  13952. }
  13953. if ( this.containers[ i ].containerCache.over ) {
  13954. delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
  13955. this.containers[ i ].containerCache.over = 0;
  13956. }
  13957. }
  13958. //Do what was originally in plugins
  13959. if ( this.storedCursor ) {
  13960. this.document.find( "body" ).css( "cursor", this.storedCursor );
  13961. this.storedStylesheet.remove();
  13962. }
  13963. if ( this._storedOpacity ) {
  13964. this.helper.css( "opacity", this._storedOpacity );
  13965. }
  13966. if ( this._storedZIndex ) {
  13967. this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
  13968. }
  13969. this.dragging = false;
  13970. if ( !noPropagation ) {
  13971. this._trigger( "beforeStop", event, this._uiHash() );
  13972. }
  13973. //$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
  13974. // it unbinds ALL events from the original node!
  13975. this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
  13976. if ( !this.cancelHelperRemoval ) {
  13977. if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
  13978. this.helper.remove();
  13979. }
  13980. this.helper = null;
  13981. }
  13982. if ( !noPropagation ) {
  13983. for ( i = 0; i < delayedTriggers.length; i++ ) {
  13984. // Trigger all delayed events
  13985. delayedTriggers[ i ].call( this, event );
  13986. }
  13987. this._trigger( "stop", event, this._uiHash() );
  13988. }
  13989. this.fromOutside = false;
  13990. return !this.cancelHelperRemoval;
  13991. },
  13992. _trigger: function() {
  13993. if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
  13994. this.cancel();
  13995. }
  13996. },
  13997. _uiHash: function( _inst ) {
  13998. var inst = _inst || this;
  13999. return {
  14000. helper: inst.helper,
  14001. placeholder: inst.placeholder || $( [] ),
  14002. position: inst.position,
  14003. originalPosition: inst.originalPosition,
  14004. offset: inst.positionAbs,
  14005. item: inst.currentItem,
  14006. sender: _inst ? _inst.element : null
  14007. };
  14008. }
  14009. } );
  14010. /*!
  14011. * jQuery UI Spinner 1.12.1
  14012. * http://jqueryui.com
  14013. *
  14014. * Copyright jQuery Foundation and other contributors
  14015. * Released under the MIT license.
  14016. * http://jquery.org/license
  14017. */
  14018. //>>label: Spinner
  14019. //>>group: Widgets
  14020. //>>description: Displays buttons to easily input numbers via the keyboard or mouse.
  14021. //>>docs: http://api.jqueryui.com/spinner/
  14022. //>>demos: http://jqueryui.com/spinner/
  14023. //>>css.structure: ../../themes/base/core.css
  14024. //>>css.structure: ../../themes/base/spinner.css
  14025. //>>css.theme: ../../themes/base/theme.css
  14026. function spinnerModifer( fn ) {
  14027. return function() {
  14028. var previous = this.element.val();
  14029. fn.apply( this, arguments );
  14030. this._refresh();
  14031. if ( previous !== this.element.val() ) {
  14032. this._trigger( "change" );
  14033. }
  14034. };
  14035. }
  14036. $.widget( "ui.spinner", {
  14037. version: "1.12.1",
  14038. defaultElement: "<input>",
  14039. widgetEventPrefix: "spin",
  14040. options: {
  14041. classes: {
  14042. "ui-spinner": "ui-corner-all",
  14043. "ui-spinner-down": "ui-corner-br",
  14044. "ui-spinner-up": "ui-corner-tr"
  14045. },
  14046. culture: null,
  14047. icons: {
  14048. down: "ui-icon-triangle-1-s",
  14049. up: "ui-icon-triangle-1-n"
  14050. },
  14051. incremental: true,
  14052. max: null,
  14053. min: null,
  14054. numberFormat: null,
  14055. page: 10,
  14056. step: 1,
  14057. change: null,
  14058. spin: null,
  14059. start: null,
  14060. stop: null
  14061. },
  14062. _create: function() {
  14063. // handle string values that need to be parsed
  14064. this._setOption( "max", this.options.max );
  14065. this._setOption( "min", this.options.min );
  14066. this._setOption( "step", this.options.step );
  14067. // Only format if there is a value, prevents the field from being marked
  14068. // as invalid in Firefox, see #9573.
  14069. if ( this.value() !== "" ) {
  14070. // Format the value, but don't constrain.
  14071. this._value( this.element.val(), true );
  14072. }
  14073. this._draw();
  14074. this._on( this._events );
  14075. this._refresh();
  14076. // Turning off autocomplete prevents the browser from remembering the
  14077. // value when navigating through history, so we re-enable autocomplete
  14078. // if the page is unloaded before the widget is destroyed. #7790
  14079. this._on( this.window, {
  14080. beforeunload: function() {
  14081. this.element.removeAttr( "autocomplete" );
  14082. }
  14083. } );
  14084. },
  14085. _getCreateOptions: function() {
  14086. var options = this._super();
  14087. var element = this.element;
  14088. $.each( [ "min", "max", "step" ], function( i, option ) {
  14089. var value = element.attr( option );
  14090. if ( value != null && value.length ) {
  14091. options[ option ] = value;
  14092. }
  14093. } );
  14094. return options;
  14095. },
  14096. _events: {
  14097. keydown: function( event ) {
  14098. if ( this._start( event ) && this._keydown( event ) ) {
  14099. event.preventDefault();
  14100. }
  14101. },
  14102. keyup: "_stop",
  14103. focus: function() {
  14104. this.previous = this.element.val();
  14105. },
  14106. blur: function( event ) {
  14107. if ( this.cancelBlur ) {
  14108. delete this.cancelBlur;
  14109. return;
  14110. }
  14111. this._stop();
  14112. this._refresh();
  14113. if ( this.previous !== this.element.val() ) {
  14114. this._trigger( "change", event );
  14115. }
  14116. },
  14117. mousewheel: function( event, delta ) {
  14118. if ( !delta ) {
  14119. return;
  14120. }
  14121. if ( !this.spinning && !this._start( event ) ) {
  14122. return false;
  14123. }
  14124. this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
  14125. clearTimeout( this.mousewheelTimer );
  14126. this.mousewheelTimer = this._delay( function() {
  14127. if ( this.spinning ) {
  14128. this._stop( event );
  14129. }
  14130. }, 100 );
  14131. event.preventDefault();
  14132. },
  14133. "mousedown .ui-spinner-button": function( event ) {
  14134. var previous;
  14135. // We never want the buttons to have focus; whenever the user is
  14136. // interacting with the spinner, the focus should be on the input.
  14137. // If the input is focused then this.previous is properly set from
  14138. // when the input first received focus. If the input is not focused
  14139. // then we need to set this.previous based on the value before spinning.
  14140. previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
  14141. this.previous : this.element.val();
  14142. function checkFocus() {
  14143. var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
  14144. if ( !isActive ) {
  14145. this.element.trigger( "focus" );
  14146. this.previous = previous;
  14147. // support: IE
  14148. // IE sets focus asynchronously, so we need to check if focus
  14149. // moved off of the input because the user clicked on the button.
  14150. this._delay( function() {
  14151. this.previous = previous;
  14152. } );
  14153. }
  14154. }
  14155. // Ensure focus is on (or stays on) the text field
  14156. event.preventDefault();
  14157. checkFocus.call( this );
  14158. // Support: IE
  14159. // IE doesn't prevent moving focus even with event.preventDefault()
  14160. // so we set a flag to know when we should ignore the blur event
  14161. // and check (again) if focus moved off of the input.
  14162. this.cancelBlur = true;
  14163. this._delay( function() {
  14164. delete this.cancelBlur;
  14165. checkFocus.call( this );
  14166. } );
  14167. if ( this._start( event ) === false ) {
  14168. return;
  14169. }
  14170. this._repeat( null, $( event.currentTarget )
  14171. .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
  14172. },
  14173. "mouseup .ui-spinner-button": "_stop",
  14174. "mouseenter .ui-spinner-button": function( event ) {
  14175. // button will add ui-state-active if mouse was down while mouseleave and kept down
  14176. if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
  14177. return;
  14178. }
  14179. if ( this._start( event ) === false ) {
  14180. return false;
  14181. }
  14182. this._repeat( null, $( event.currentTarget )
  14183. .hasClass( "ui-spinner-up" ) ? 1 : -1, event );
  14184. },
  14185. // TODO: do we really want to consider this a stop?
  14186. // shouldn't we just stop the repeater and wait until mouseup before
  14187. // we trigger the stop event?
  14188. "mouseleave .ui-spinner-button": "_stop"
  14189. },
  14190. // Support mobile enhanced option and make backcompat more sane
  14191. _enhance: function() {
  14192. this.uiSpinner = this.element
  14193. .attr( "autocomplete", "off" )
  14194. .wrap( "<span>" )
  14195. .parent()
  14196. // Add buttons
  14197. .append(
  14198. "<a></a><a></a>"
  14199. );
  14200. },
  14201. _draw: function() {
  14202. this._enhance();
  14203. this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
  14204. this._addClass( "ui-spinner-input" );
  14205. this.element.attr( "role", "spinbutton" );
  14206. // Button bindings
  14207. this.buttons = this.uiSpinner.children( "a" )
  14208. .attr( "tabIndex", -1 )
  14209. .attr( "aria-hidden", true )
  14210. .button( {
  14211. classes: {
  14212. "ui-button": ""
  14213. }
  14214. } );
  14215. // TODO: Right now button does not support classes this is already updated in button PR
  14216. this._removeClass( this.buttons, "ui-corner-all" );
  14217. this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
  14218. this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
  14219. this.buttons.first().button( {
  14220. "icon": this.options.icons.up,
  14221. "showLabel": false
  14222. } );
  14223. this.buttons.last().button( {
  14224. "icon": this.options.icons.down,
  14225. "showLabel": false
  14226. } );
  14227. // IE 6 doesn't understand height: 50% for the buttons
  14228. // unless the wrapper has an explicit height
  14229. if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
  14230. this.uiSpinner.height() > 0 ) {
  14231. this.uiSpinner.height( this.uiSpinner.height() );
  14232. }
  14233. },
  14234. _keydown: function( event ) {
  14235. var options = this.options,
  14236. keyCode = $.ui.keyCode;
  14237. switch ( event.keyCode ) {
  14238. case keyCode.UP:
  14239. this._repeat( null, 1, event );
  14240. return true;
  14241. case keyCode.DOWN:
  14242. this._repeat( null, -1, event );
  14243. return true;
  14244. case keyCode.PAGE_UP:
  14245. this._repeat( null, options.page, event );
  14246. return true;
  14247. case keyCode.PAGE_DOWN:
  14248. this._repeat( null, -options.page, event );
  14249. return true;
  14250. }
  14251. return false;
  14252. },
  14253. _start: function( event ) {
  14254. if ( !this.spinning && this._trigger( "start", event ) === false ) {
  14255. return false;
  14256. }
  14257. if ( !this.counter ) {
  14258. this.counter = 1;
  14259. }
  14260. this.spinning = true;
  14261. return true;
  14262. },
  14263. _repeat: function( i, steps, event ) {
  14264. i = i || 500;
  14265. clearTimeout( this.timer );
  14266. this.timer = this._delay( function() {
  14267. this._repeat( 40, steps, event );
  14268. }, i );
  14269. this._spin( steps * this.options.step, event );
  14270. },
  14271. _spin: function( step, event ) {
  14272. var value = this.value() || 0;
  14273. if ( !this.counter ) {
  14274. this.counter = 1;
  14275. }
  14276. value = this._adjustValue( value + step * this._increment( this.counter ) );
  14277. if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
  14278. this._value( value );
  14279. this.counter++;
  14280. }
  14281. },
  14282. _increment: function( i ) {
  14283. var incremental = this.options.incremental;
  14284. if ( incremental ) {
  14285. return $.isFunction( incremental ) ?
  14286. incremental( i ) :
  14287. Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
  14288. }
  14289. return 1;
  14290. },
  14291. _precision: function() {
  14292. var precision = this._precisionOf( this.options.step );
  14293. if ( this.options.min !== null ) {
  14294. precision = Math.max( precision, this._precisionOf( this.options.min ) );
  14295. }
  14296. return precision;
  14297. },
  14298. _precisionOf: function( num ) {
  14299. var str = num.toString(),
  14300. decimal = str.indexOf( "." );
  14301. return decimal === -1 ? 0 : str.length - decimal - 1;
  14302. },
  14303. _adjustValue: function( value ) {
  14304. var base, aboveMin,
  14305. options = this.options;
  14306. // Make sure we're at a valid step
  14307. // - find out where we are relative to the base (min or 0)
  14308. base = options.min !== null ? options.min : 0;
  14309. aboveMin = value - base;
  14310. // - round to the nearest step
  14311. aboveMin = Math.round( aboveMin / options.step ) * options.step;
  14312. // - rounding is based on 0, so adjust back to our base
  14313. value = base + aboveMin;
  14314. // Fix precision from bad JS floating point math
  14315. value = parseFloat( value.toFixed( this._precision() ) );
  14316. // Clamp the value
  14317. if ( options.max !== null && value > options.max ) {
  14318. return options.max;
  14319. }
  14320. if ( options.min !== null && value < options.min ) {
  14321. return options.min;
  14322. }
  14323. return value;
  14324. },
  14325. _stop: function( event ) {
  14326. if ( !this.spinning ) {
  14327. return;
  14328. }
  14329. clearTimeout( this.timer );
  14330. clearTimeout( this.mousewheelTimer );
  14331. this.counter = 0;
  14332. this.spinning = false;
  14333. this._trigger( "stop", event );
  14334. },
  14335. _setOption: function( key, value ) {
  14336. var prevValue, first, last;
  14337. if ( key === "culture" || key === "numberFormat" ) {
  14338. prevValue = this._parse( this.element.val() );
  14339. this.options[ key ] = value;
  14340. this.element.val( this._format( prevValue ) );
  14341. return;
  14342. }
  14343. if ( key === "max" || key === "min" || key === "step" ) {
  14344. if ( typeof value === "string" ) {
  14345. value = this._parse( value );
  14346. }
  14347. }
  14348. if ( key === "icons" ) {
  14349. first = this.buttons.first().find( ".ui-icon" );
  14350. this._removeClass( first, null, this.options.icons.up );
  14351. this._addClass( first, null, value.up );
  14352. last = this.buttons.last().find( ".ui-icon" );
  14353. this._removeClass( last, null, this.options.icons.down );
  14354. this._addClass( last, null, value.down );
  14355. }
  14356. this._super( key, value );
  14357. },
  14358. _setOptionDisabled: function( value ) {
  14359. this._super( value );
  14360. this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
  14361. this.element.prop( "disabled", !!value );
  14362. this.buttons.button( value ? "disable" : "enable" );
  14363. },
  14364. _setOptions: spinnerModifer( function( options ) {
  14365. this._super( options );
  14366. } ),
  14367. _parse: function( val ) {
  14368. if ( typeof val === "string" && val !== "" ) {
  14369. val = window.Globalize && this.options.numberFormat ?
  14370. Globalize.parseFloat( val, 10, this.options.culture ) : +val;
  14371. }
  14372. return val === "" || isNaN( val ) ? null : val;
  14373. },
  14374. _format: function( value ) {
  14375. if ( value === "" ) {
  14376. return "";
  14377. }
  14378. return window.Globalize && this.options.numberFormat ?
  14379. Globalize.format( value, this.options.numberFormat, this.options.culture ) :
  14380. value;
  14381. },
  14382. _refresh: function() {
  14383. this.element.attr( {
  14384. "aria-valuemin": this.options.min,
  14385. "aria-valuemax": this.options.max,
  14386. // TODO: what should we do with values that can't be parsed?
  14387. "aria-valuenow": this._parse( this.element.val() )
  14388. } );
  14389. },
  14390. isValid: function() {
  14391. var value = this.value();
  14392. // Null is invalid
  14393. if ( value === null ) {
  14394. return false;
  14395. }
  14396. // If value gets adjusted, it's invalid
  14397. return value === this._adjustValue( value );
  14398. },
  14399. // Update the value without triggering change
  14400. _value: function( value, allowAny ) {
  14401. var parsed;
  14402. if ( value !== "" ) {
  14403. parsed = this._parse( value );
  14404. if ( parsed !== null ) {
  14405. if ( !allowAny ) {
  14406. parsed = this._adjustValue( parsed );
  14407. }
  14408. value = this._format( parsed );
  14409. }
  14410. }
  14411. this.element.val( value );
  14412. this._refresh();
  14413. },
  14414. _destroy: function() {
  14415. this.element
  14416. .prop( "disabled", false )
  14417. .removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );
  14418. this.uiSpinner.replaceWith( this.element );
  14419. },
  14420. stepUp: spinnerModifer( function( steps ) {
  14421. this._stepUp( steps );
  14422. } ),
  14423. _stepUp: function( steps ) {
  14424. if ( this._start() ) {
  14425. this._spin( ( steps || 1 ) * this.options.step );
  14426. this._stop();
  14427. }
  14428. },
  14429. stepDown: spinnerModifer( function( steps ) {
  14430. this._stepDown( steps );
  14431. } ),
  14432. _stepDown: function( steps ) {
  14433. if ( this._start() ) {
  14434. this._spin( ( steps || 1 ) * -this.options.step );
  14435. this._stop();
  14436. }
  14437. },
  14438. pageUp: spinnerModifer( function( pages ) {
  14439. this._stepUp( ( pages || 1 ) * this.options.page );
  14440. } ),
  14441. pageDown: spinnerModifer( function( pages ) {
  14442. this._stepDown( ( pages || 1 ) * this.options.page );
  14443. } ),
  14444. value: function( newVal ) {
  14445. if ( !arguments.length ) {
  14446. return this._parse( this.element.val() );
  14447. }
  14448. spinnerModifer( this._value ).call( this, newVal );
  14449. },
  14450. widget: function() {
  14451. return this.uiSpinner;
  14452. }
  14453. } );
  14454. // DEPRECATED
  14455. // TODO: switch return back to widget declaration at top of file when this is removed
  14456. if ( $.uiBackCompat !== false ) {
  14457. // Backcompat for spinner html extension points
  14458. $.widget( "ui.spinner", $.ui.spinner, {
  14459. _enhance: function() {
  14460. this.uiSpinner = this.element
  14461. .attr( "autocomplete", "off" )
  14462. .wrap( this._uiSpinnerHtml() )
  14463. .parent()
  14464. // Add buttons
  14465. .append( this._buttonHtml() );
  14466. },
  14467. _uiSpinnerHtml: function() {
  14468. return "<span>";
  14469. },
  14470. _buttonHtml: function() {
  14471. return "<a></a><a></a>";
  14472. }
  14473. } );
  14474. }
  14475. var widgetsSpinner = $.ui.spinner;
  14476. /*!
  14477. * jQuery UI Tabs 1.12.1
  14478. * http://jqueryui.com
  14479. *
  14480. * Copyright jQuery Foundation and other contributors
  14481. * Released under the MIT license.
  14482. * http://jquery.org/license
  14483. */
  14484. //>>label: Tabs
  14485. //>>group: Widgets
  14486. //>>description: Transforms a set of container elements into a tab structure.
  14487. //>>docs: http://api.jqueryui.com/tabs/
  14488. //>>demos: http://jqueryui.com/tabs/
  14489. //>>css.structure: ../../themes/base/core.css
  14490. //>>css.structure: ../../themes/base/tabs.css
  14491. //>>css.theme: ../../themes/base/theme.css
  14492. $.widget( "ui.tabs", {
  14493. version: "1.12.1",
  14494. delay: 300,
  14495. options: {
  14496. active: null,
  14497. classes: {
  14498. "ui-tabs": "ui-corner-all",
  14499. "ui-tabs-nav": "ui-corner-all",
  14500. "ui-tabs-panel": "ui-corner-bottom",
  14501. "ui-tabs-tab": "ui-corner-top"
  14502. },
  14503. collapsible: false,
  14504. event: "click",
  14505. heightStyle: "content",
  14506. hide: null,
  14507. show: null,
  14508. // Callbacks
  14509. activate: null,
  14510. beforeActivate: null,
  14511. beforeLoad: null,
  14512. load: null
  14513. },
  14514. _isLocal: ( function() {
  14515. var rhash = /#.*$/;
  14516. return function( anchor ) {
  14517. var anchorUrl, locationUrl;
  14518. anchorUrl = anchor.href.replace( rhash, "" );
  14519. locationUrl = location.href.replace( rhash, "" );
  14520. // Decoding may throw an error if the URL isn't UTF-8 (#9518)
  14521. try {
  14522. anchorUrl = decodeURIComponent( anchorUrl );
  14523. } catch ( error ) {}
  14524. try {
  14525. locationUrl = decodeURIComponent( locationUrl );
  14526. } catch ( error ) {}
  14527. return anchor.hash.length > 1 && anchorUrl === locationUrl;
  14528. };
  14529. } )(),
  14530. _create: function() {
  14531. var that = this,
  14532. options = this.options;
  14533. this.running = false;
  14534. this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
  14535. this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
  14536. this._processTabs();
  14537. options.active = this._initialActive();
  14538. // Take disabling tabs via class attribute from HTML
  14539. // into account and update option properly.
  14540. if ( $.isArray( options.disabled ) ) {
  14541. options.disabled = $.unique( options.disabled.concat(
  14542. $.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
  14543. return that.tabs.index( li );
  14544. } )
  14545. ) ).sort();
  14546. }
  14547. // Check for length avoids error when initializing empty list
  14548. if ( this.options.active !== false && this.anchors.length ) {
  14549. this.active = this._findActive( options.active );
  14550. } else {
  14551. this.active = $();
  14552. }
  14553. this._refresh();
  14554. if ( this.active.length ) {
  14555. this.load( options.active );
  14556. }
  14557. },
  14558. _initialActive: function() {
  14559. var active = this.options.active,
  14560. collapsible = this.options.collapsible,
  14561. locationHash = location.hash.substring( 1 );
  14562. if ( active === null ) {
  14563. // check the fragment identifier in the URL
  14564. if ( locationHash ) {
  14565. this.tabs.each( function( i, tab ) {
  14566. if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
  14567. active = i;
  14568. return false;
  14569. }
  14570. } );
  14571. }
  14572. // Check for a tab marked active via a class
  14573. if ( active === null ) {
  14574. active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
  14575. }
  14576. // No active tab, set to false
  14577. if ( active === null || active === -1 ) {
  14578. active = this.tabs.length ? 0 : false;
  14579. }
  14580. }
  14581. // Handle numbers: negative, out of range
  14582. if ( active !== false ) {
  14583. active = this.tabs.index( this.tabs.eq( active ) );
  14584. if ( active === -1 ) {
  14585. active = collapsible ? false : 0;
  14586. }
  14587. }
  14588. // Don't allow collapsible: false and active: false
  14589. if ( !collapsible && active === false && this.anchors.length ) {
  14590. active = 0;
  14591. }
  14592. return active;
  14593. },
  14594. _getCreateEventData: function() {
  14595. return {
  14596. tab: this.active,
  14597. panel: !this.active.length ? $() : this._getPanelForTab( this.active )
  14598. };
  14599. },
  14600. _tabKeydown: function( event ) {
  14601. var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
  14602. selectedIndex = this.tabs.index( focusedTab ),
  14603. goingForward = true;
  14604. if ( this._handlePageNav( event ) ) {
  14605. return;
  14606. }
  14607. switch ( event.keyCode ) {
  14608. case $.ui.keyCode.RIGHT:
  14609. case $.ui.keyCode.DOWN:
  14610. selectedIndex++;
  14611. break;
  14612. case $.ui.keyCode.UP:
  14613. case $.ui.keyCode.LEFT:
  14614. goingForward = false;
  14615. selectedIndex--;
  14616. break;
  14617. case $.ui.keyCode.END:
  14618. selectedIndex = this.anchors.length - 1;
  14619. break;
  14620. case $.ui.keyCode.HOME:
  14621. selectedIndex = 0;
  14622. break;
  14623. case $.ui.keyCode.SPACE:
  14624. // Activate only, no collapsing
  14625. event.preventDefault();
  14626. clearTimeout( this.activating );
  14627. this._activate( selectedIndex );
  14628. return;
  14629. case $.ui.keyCode.ENTER:
  14630. // Toggle (cancel delayed activation, allow collapsing)
  14631. event.preventDefault();
  14632. clearTimeout( this.activating );
  14633. // Determine if we should collapse or activate
  14634. this._activate( selectedIndex === this.options.active ? false : selectedIndex );
  14635. return;
  14636. default:
  14637. return;
  14638. }
  14639. // Focus the appropriate tab, based on which key was pressed
  14640. event.preventDefault();
  14641. clearTimeout( this.activating );
  14642. selectedIndex = this._focusNextTab( selectedIndex, goingForward );
  14643. // Navigating with control/command key will prevent automatic activation
  14644. if ( !event.ctrlKey && !event.metaKey ) {
  14645. // Update aria-selected immediately so that AT think the tab is already selected.
  14646. // Otherwise AT may confuse the user by stating that they need to activate the tab,
  14647. // but the tab will already be activated by the time the announcement finishes.
  14648. focusedTab.attr( "aria-selected", "false" );
  14649. this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
  14650. this.activating = this._delay( function() {
  14651. this.option( "active", selectedIndex );
  14652. }, this.delay );
  14653. }
  14654. },
  14655. _panelKeydown: function( event ) {
  14656. if ( this._handlePageNav( event ) ) {
  14657. return;
  14658. }
  14659. // Ctrl+up moves focus to the current tab
  14660. if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
  14661. event.preventDefault();
  14662. this.active.trigger( "focus" );
  14663. }
  14664. },
  14665. // Alt+page up/down moves focus to the previous/next tab (and activates)
  14666. _handlePageNav: function( event ) {
  14667. if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
  14668. this._activate( this._focusNextTab( this.options.active - 1, false ) );
  14669. return true;
  14670. }
  14671. if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
  14672. this._activate( this._focusNextTab( this.options.active + 1, true ) );
  14673. return true;
  14674. }
  14675. },
  14676. _findNextTab: function( index, goingForward ) {
  14677. var lastTabIndex = this.tabs.length - 1;
  14678. function constrain() {
  14679. if ( index > lastTabIndex ) {
  14680. index = 0;
  14681. }
  14682. if ( index < 0 ) {
  14683. index = lastTabIndex;
  14684. }
  14685. return index;
  14686. }
  14687. while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
  14688. index = goingForward ? index + 1 : index - 1;
  14689. }
  14690. return index;
  14691. },
  14692. _focusNextTab: function( index, goingForward ) {
  14693. index = this._findNextTab( index, goingForward );
  14694. this.tabs.eq( index ).trigger( "focus" );
  14695. return index;
  14696. },
  14697. _setOption: function( key, value ) {
  14698. if ( key === "active" ) {
  14699. // _activate() will handle invalid values and update this.options
  14700. this._activate( value );
  14701. return;
  14702. }
  14703. this._super( key, value );
  14704. if ( key === "collapsible" ) {
  14705. this._toggleClass( "ui-tabs-collapsible", null, value );
  14706. // Setting collapsible: false while collapsed; open first panel
  14707. if ( !value && this.options.active === false ) {
  14708. this._activate( 0 );
  14709. }
  14710. }
  14711. if ( key === "event" ) {
  14712. this._setupEvents( value );
  14713. }
  14714. if ( key === "heightStyle" ) {
  14715. this._setupHeightStyle( value );
  14716. }
  14717. },
  14718. _sanitizeSelector: function( hash ) {
  14719. return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
  14720. },
  14721. refresh: function() {
  14722. var options = this.options,
  14723. lis = this.tablist.children( ":has(a[href])" );
  14724. // Get disabled tabs from class attribute from HTML
  14725. // this will get converted to a boolean if needed in _refresh()
  14726. options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
  14727. return lis.index( tab );
  14728. } );
  14729. this._processTabs();
  14730. // Was collapsed or no tabs
  14731. if ( options.active === false || !this.anchors.length ) {
  14732. options.active = false;
  14733. this.active = $();
  14734. // was active, but active tab is gone
  14735. } else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
  14736. // all remaining tabs are disabled
  14737. if ( this.tabs.length === options.disabled.length ) {
  14738. options.active = false;
  14739. this.active = $();
  14740. // activate previous tab
  14741. } else {
  14742. this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
  14743. }
  14744. // was active, active tab still exists
  14745. } else {
  14746. // make sure active index is correct
  14747. options.active = this.tabs.index( this.active );
  14748. }
  14749. this._refresh();
  14750. },
  14751. _refresh: function() {
  14752. this._setOptionDisabled( this.options.disabled );
  14753. this._setupEvents( this.options.event );
  14754. this._setupHeightStyle( this.options.heightStyle );
  14755. this.tabs.not( this.active ).attr( {
  14756. "aria-selected": "false",
  14757. "aria-expanded": "false",
  14758. tabIndex: -1
  14759. } );
  14760. this.panels.not( this._getPanelForTab( this.active ) )
  14761. .hide()
  14762. .attr( {
  14763. "aria-hidden": "true"
  14764. } );
  14765. // Make sure one tab is in the tab order
  14766. if ( !this.active.length ) {
  14767. this.tabs.eq( 0 ).attr( "tabIndex", 0 );
  14768. } else {
  14769. this.active
  14770. .attr( {
  14771. "aria-selected": "true",
  14772. "aria-expanded": "true",
  14773. tabIndex: 0
  14774. } );
  14775. this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
  14776. this._getPanelForTab( this.active )
  14777. .show()
  14778. .attr( {
  14779. "aria-hidden": "false"
  14780. } );
  14781. }
  14782. },
  14783. _processTabs: function() {
  14784. var that = this,
  14785. prevTabs = this.tabs,
  14786. prevAnchors = this.anchors,
  14787. prevPanels = this.panels;
  14788. this.tablist = this._getList().attr( "role", "tablist" );
  14789. this._addClass( this.tablist, "ui-tabs-nav",
  14790. "ui-helper-reset ui-helper-clearfix ui-widget-header" );
  14791. // Prevent users from focusing disabled tabs via click
  14792. this.tablist
  14793. .on( "mousedown" + this.eventNamespace, "> li", function( event ) {
  14794. if ( $( this ).is( ".ui-state-disabled" ) ) {
  14795. event.preventDefault();
  14796. }
  14797. } )
  14798. // Support: IE <9
  14799. // Preventing the default action in mousedown doesn't prevent IE
  14800. // from focusing the element, so if the anchor gets focused, blur.
  14801. // We don't have to worry about focusing the previously focused
  14802. // element since clicking on a non-focusable element should focus
  14803. // the body anyway.
  14804. .on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
  14805. if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
  14806. this.blur();
  14807. }
  14808. } );
  14809. this.tabs = this.tablist.find( "> li:has(a[href])" )
  14810. .attr( {
  14811. role: "tab",
  14812. tabIndex: -1
  14813. } );
  14814. this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
  14815. this.anchors = this.tabs.map( function() {
  14816. return $( "a", this )[ 0 ];
  14817. } )
  14818. .attr( {
  14819. role: "presentation",
  14820. tabIndex: -1
  14821. } );
  14822. this._addClass( this.anchors, "ui-tabs-anchor" );
  14823. this.panels = $();
  14824. this.anchors.each( function( i, anchor ) {
  14825. var selector, panel, panelId,
  14826. anchorId = $( anchor ).uniqueId().attr( "id" ),
  14827. tab = $( anchor ).closest( "li" ),
  14828. originalAriaControls = tab.attr( "aria-controls" );
  14829. // Inline tab
  14830. if ( that._isLocal( anchor ) ) {
  14831. selector = anchor.hash;
  14832. panelId = selector.substring( 1 );
  14833. panel = that.element.find( that._sanitizeSelector( selector ) );
  14834. // remote tab
  14835. } else {
  14836. // If the tab doesn't already have aria-controls,
  14837. // generate an id by using a throw-away element
  14838. panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
  14839. selector = "#" + panelId;
  14840. panel = that.element.find( selector );
  14841. if ( !panel.length ) {
  14842. panel = that._createPanel( panelId );
  14843. panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
  14844. }
  14845. panel.attr( "aria-live", "polite" );
  14846. }
  14847. if ( panel.length ) {
  14848. that.panels = that.panels.add( panel );
  14849. }
  14850. if ( originalAriaControls ) {
  14851. tab.data( "ui-tabs-aria-controls", originalAriaControls );
  14852. }
  14853. tab.attr( {
  14854. "aria-controls": panelId,
  14855. "aria-labelledby": anchorId
  14856. } );
  14857. panel.attr( "aria-labelledby", anchorId );
  14858. } );
  14859. this.panels.attr( "role", "tabpanel" );
  14860. this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
  14861. // Avoid memory leaks (#10056)
  14862. if ( prevTabs ) {
  14863. this._off( prevTabs.not( this.tabs ) );
  14864. this._off( prevAnchors.not( this.anchors ) );
  14865. this._off( prevPanels.not( this.panels ) );
  14866. }
  14867. },
  14868. // Allow overriding how to find the list for rare usage scenarios (#7715)
  14869. _getList: function() {
  14870. return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
  14871. },
  14872. _createPanel: function( id ) {
  14873. return $( "<div>" )
  14874. .attr( "id", id )
  14875. .data( "ui-tabs-destroy", true );
  14876. },
  14877. _setOptionDisabled: function( disabled ) {
  14878. var currentItem, li, i;
  14879. if ( $.isArray( disabled ) ) {
  14880. if ( !disabled.length ) {
  14881. disabled = false;
  14882. } else if ( disabled.length === this.anchors.length ) {
  14883. disabled = true;
  14884. }
  14885. }
  14886. // Disable tabs
  14887. for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
  14888. currentItem = $( li );
  14889. if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
  14890. currentItem.attr( "aria-disabled", "true" );
  14891. this._addClass( currentItem, null, "ui-state-disabled" );
  14892. } else {
  14893. currentItem.removeAttr( "aria-disabled" );
  14894. this._removeClass( currentItem, null, "ui-state-disabled" );
  14895. }
  14896. }
  14897. this.options.disabled = disabled;
  14898. this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
  14899. disabled === true );
  14900. },
  14901. _setupEvents: function( event ) {
  14902. var events = {};
  14903. if ( event ) {
  14904. $.each( event.split( " " ), function( index, eventName ) {
  14905. events[ eventName ] = "_eventHandler";
  14906. } );
  14907. }
  14908. this._off( this.anchors.add( this.tabs ).add( this.panels ) );
  14909. // Always prevent the default action, even when disabled
  14910. this._on( true, this.anchors, {
  14911. click: function( event ) {
  14912. event.preventDefault();
  14913. }
  14914. } );
  14915. this._on( this.anchors, events );
  14916. this._on( this.tabs, { keydown: "_tabKeydown" } );
  14917. this._on( this.panels, { keydown: "_panelKeydown" } );
  14918. this._focusable( this.tabs );
  14919. this._hoverable( this.tabs );
  14920. },
  14921. _setupHeightStyle: function( heightStyle ) {
  14922. var maxHeight,
  14923. parent = this.element.parent();
  14924. if ( heightStyle === "fill" ) {
  14925. maxHeight = parent.height();
  14926. maxHeight -= this.element.outerHeight() - this.element.height();
  14927. this.element.siblings( ":visible" ).each( function() {
  14928. var elem = $( this ),
  14929. position = elem.css( "position" );
  14930. if ( position === "absolute" || position === "fixed" ) {
  14931. return;
  14932. }
  14933. maxHeight -= elem.outerHeight( true );
  14934. } );
  14935. this.element.children().not( this.panels ).each( function() {
  14936. maxHeight -= $( this ).outerHeight( true );
  14937. } );
  14938. this.panels.each( function() {
  14939. $( this ).height( Math.max( 0, maxHeight -
  14940. $( this ).innerHeight() + $( this ).height() ) );
  14941. } )
  14942. .css( "overflow", "auto" );
  14943. } else if ( heightStyle === "auto" ) {
  14944. maxHeight = 0;
  14945. this.panels.each( function() {
  14946. maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
  14947. } ).height( maxHeight );
  14948. }
  14949. },
  14950. _eventHandler: function( event ) {
  14951. var options = this.options,
  14952. active = this.active,
  14953. anchor = $( event.currentTarget ),
  14954. tab = anchor.closest( "li" ),
  14955. clickedIsActive = tab[ 0 ] === active[ 0 ],
  14956. collapsing = clickedIsActive && options.collapsible,
  14957. toShow = collapsing ? $() : this._getPanelForTab( tab ),
  14958. toHide = !active.length ? $() : this._getPanelForTab( active ),
  14959. eventData = {
  14960. oldTab: active,
  14961. oldPanel: toHide,
  14962. newTab: collapsing ? $() : tab,
  14963. newPanel: toShow
  14964. };
  14965. event.preventDefault();
  14966. if ( tab.hasClass( "ui-state-disabled" ) ||
  14967. // tab is already loading
  14968. tab.hasClass( "ui-tabs-loading" ) ||
  14969. // can't switch durning an animation
  14970. this.running ||
  14971. // click on active header, but not collapsible
  14972. ( clickedIsActive && !options.collapsible ) ||
  14973. // allow canceling activation
  14974. ( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
  14975. return;
  14976. }
  14977. options.active = collapsing ? false : this.tabs.index( tab );
  14978. this.active = clickedIsActive ? $() : tab;
  14979. if ( this.xhr ) {
  14980. this.xhr.abort();
  14981. }
  14982. if ( !toHide.length && !toShow.length ) {
  14983. $.error( "jQuery UI Tabs: Mismatching fragment identifier." );
  14984. }
  14985. if ( toShow.length ) {
  14986. this.load( this.tabs.index( tab ), event );
  14987. }
  14988. this._toggle( event, eventData );
  14989. },
  14990. // Handles show/hide for selecting tabs
  14991. _toggle: function( event, eventData ) {
  14992. var that = this,
  14993. toShow = eventData.newPanel,
  14994. toHide = eventData.oldPanel;
  14995. this.running = true;
  14996. function complete() {
  14997. that.running = false;
  14998. that._trigger( "activate", event, eventData );
  14999. }
  15000. function show() {
  15001. that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
  15002. if ( toShow.length && that.options.show ) {
  15003. that._show( toShow, that.options.show, complete );
  15004. } else {
  15005. toShow.show();
  15006. complete();
  15007. }
  15008. }
  15009. // Start out by hiding, then showing, then completing
  15010. if ( toHide.length && this.options.hide ) {
  15011. this._hide( toHide, this.options.hide, function() {
  15012. that._removeClass( eventData.oldTab.closest( "li" ),
  15013. "ui-tabs-active", "ui-state-active" );
  15014. show();
  15015. } );
  15016. } else {
  15017. this._removeClass( eventData.oldTab.closest( "li" ),
  15018. "ui-tabs-active", "ui-state-active" );
  15019. toHide.hide();
  15020. show();
  15021. }
  15022. toHide.attr( "aria-hidden", "true" );
  15023. eventData.oldTab.attr( {
  15024. "aria-selected": "false",
  15025. "aria-expanded": "false"
  15026. } );
  15027. // If we're switching tabs, remove the old tab from the tab order.
  15028. // If we're opening from collapsed state, remove the previous tab from the tab order.
  15029. // If we're collapsing, then keep the collapsing tab in the tab order.
  15030. if ( toShow.length && toHide.length ) {
  15031. eventData.oldTab.attr( "tabIndex", -1 );
  15032. } else if ( toShow.length ) {
  15033. this.tabs.filter( function() {
  15034. return $( this ).attr( "tabIndex" ) === 0;
  15035. } )
  15036. .attr( "tabIndex", -1 );
  15037. }
  15038. toShow.attr( "aria-hidden", "false" );
  15039. eventData.newTab.attr( {
  15040. "aria-selected": "true",
  15041. "aria-expanded": "true",
  15042. tabIndex: 0
  15043. } );
  15044. },
  15045. _activate: function( index ) {
  15046. var anchor,
  15047. active = this._findActive( index );
  15048. // Trying to activate the already active panel
  15049. if ( active[ 0 ] === this.active[ 0 ] ) {
  15050. return;
  15051. }
  15052. // Trying to collapse, simulate a click on the current active header
  15053. if ( !active.length ) {
  15054. active = this.active;
  15055. }
  15056. anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
  15057. this._eventHandler( {
  15058. target: anchor,
  15059. currentTarget: anchor,
  15060. preventDefault: $.noop
  15061. } );
  15062. },
  15063. _findActive: function( index ) {
  15064. return index === false ? $() : this.tabs.eq( index );
  15065. },
  15066. _getIndex: function( index ) {
  15067. // meta-function to give users option to provide a href string instead of a numerical index.
  15068. if ( typeof index === "string" ) {
  15069. index = this.anchors.index( this.anchors.filter( "[href$='" +
  15070. $.ui.escapeSelector( index ) + "']" ) );
  15071. }
  15072. return index;
  15073. },
  15074. _destroy: function() {
  15075. if ( this.xhr ) {
  15076. this.xhr.abort();
  15077. }
  15078. this.tablist
  15079. .removeAttr( "role" )
  15080. .off( this.eventNamespace );
  15081. this.anchors
  15082. .removeAttr( "role tabIndex" )
  15083. .removeUniqueId();
  15084. this.tabs.add( this.panels ).each( function() {
  15085. if ( $.data( this, "ui-tabs-destroy" ) ) {
  15086. $( this ).remove();
  15087. } else {
  15088. $( this ).removeAttr( "role tabIndex " +
  15089. "aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
  15090. }
  15091. } );
  15092. this.tabs.each( function() {
  15093. var li = $( this ),
  15094. prev = li.data( "ui-tabs-aria-controls" );
  15095. if ( prev ) {
  15096. li
  15097. .attr( "aria-controls", prev )
  15098. .removeData( "ui-tabs-aria-controls" );
  15099. } else {
  15100. li.removeAttr( "aria-controls" );
  15101. }
  15102. } );
  15103. this.panels.show();
  15104. if ( this.options.heightStyle !== "content" ) {
  15105. this.panels.css( "height", "" );
  15106. }
  15107. },
  15108. enable: function( index ) {
  15109. var disabled = this.options.disabled;
  15110. if ( disabled === false ) {
  15111. return;
  15112. }
  15113. if ( index === undefined ) {
  15114. disabled = false;
  15115. } else {
  15116. index = this._getIndex( index );
  15117. if ( $.isArray( disabled ) ) {
  15118. disabled = $.map( disabled, function( num ) {
  15119. return num !== index ? num : null;
  15120. } );
  15121. } else {
  15122. disabled = $.map( this.tabs, function( li, num ) {
  15123. return num !== index ? num : null;
  15124. } );
  15125. }
  15126. }
  15127. this._setOptionDisabled( disabled );
  15128. },
  15129. disable: function( index ) {
  15130. var disabled = this.options.disabled;
  15131. if ( disabled === true ) {
  15132. return;
  15133. }
  15134. if ( index === undefined ) {
  15135. disabled = true;
  15136. } else {
  15137. index = this._getIndex( index );
  15138. if ( $.inArray( index, disabled ) !== -1 ) {
  15139. return;
  15140. }
  15141. if ( $.isArray( disabled ) ) {
  15142. disabled = $.merge( [ index ], disabled ).sort();
  15143. } else {
  15144. disabled = [ index ];
  15145. }
  15146. }
  15147. this._setOptionDisabled( disabled );
  15148. },
  15149. load: function( index, event ) {
  15150. index = this._getIndex( index );
  15151. var that = this,
  15152. tab = this.tabs.eq( index ),
  15153. anchor = tab.find( ".ui-tabs-anchor" ),
  15154. panel = this._getPanelForTab( tab ),
  15155. eventData = {
  15156. tab: tab,
  15157. panel: panel
  15158. },
  15159. complete = function( jqXHR, status ) {
  15160. if ( status === "abort" ) {
  15161. that.panels.stop( false, true );
  15162. }
  15163. that._removeClass( tab, "ui-tabs-loading" );
  15164. panel.removeAttr( "aria-busy" );
  15165. if ( jqXHR === that.xhr ) {
  15166. delete that.xhr;
  15167. }
  15168. };
  15169. // Not remote
  15170. if ( this._isLocal( anchor[ 0 ] ) ) {
  15171. return;
  15172. }
  15173. this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
  15174. // Support: jQuery <1.8
  15175. // jQuery <1.8 returns false if the request is canceled in beforeSend,
  15176. // but as of 1.8, $.ajax() always returns a jqXHR object.
  15177. if ( this.xhr && this.xhr.statusText !== "canceled" ) {
  15178. this._addClass( tab, "ui-tabs-loading" );
  15179. panel.attr( "aria-busy", "true" );
  15180. this.xhr
  15181. .done( function( response, status, jqXHR ) {
  15182. // support: jQuery <1.8
  15183. // http://bugs.jquery.com/ticket/11778
  15184. setTimeout( function() {
  15185. panel.html( response );
  15186. that._trigger( "load", event, eventData );
  15187. complete( jqXHR, status );
  15188. }, 1 );
  15189. } )
  15190. .fail( function( jqXHR, status ) {
  15191. // support: jQuery <1.8
  15192. // http://bugs.jquery.com/ticket/11778
  15193. setTimeout( function() {
  15194. complete( jqXHR, status );
  15195. }, 1 );
  15196. } );
  15197. }
  15198. },
  15199. _ajaxSettings: function( anchor, event, eventData ) {
  15200. var that = this;
  15201. return {
  15202. // Support: IE <11 only
  15203. // Strip any hash that exists to prevent errors with the Ajax request
  15204. url: anchor.attr( "href" ).replace( /#.*$/, "" ),
  15205. beforeSend: function( jqXHR, settings ) {
  15206. return that._trigger( "beforeLoad", event,
  15207. $.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
  15208. }
  15209. };
  15210. },
  15211. _getPanelForTab: function( tab ) {
  15212. var id = $( tab ).attr( "aria-controls" );
  15213. return this.element.find( this._sanitizeSelector( "#" + id ) );
  15214. }
  15215. } );
  15216. // DEPRECATED
  15217. // TODO: Switch return back to widget declaration at top of file when this is removed
  15218. if ( $.uiBackCompat !== false ) {
  15219. // Backcompat for ui-tab class (now ui-tabs-tab)
  15220. $.widget( "ui.tabs", $.ui.tabs, {
  15221. _processTabs: function() {
  15222. this._superApply( arguments );
  15223. this._addClass( this.tabs, "ui-tab" );
  15224. }
  15225. } );
  15226. }
  15227. var widgetsTabs = $.ui.tabs;
  15228. /*!
  15229. * jQuery UI Tooltip 1.12.1
  15230. * http://jqueryui.com
  15231. *
  15232. * Copyright jQuery Foundation and other contributors
  15233. * Released under the MIT license.
  15234. * http://jquery.org/license
  15235. */
  15236. //>>label: Tooltip
  15237. //>>group: Widgets
  15238. //>>description: Shows additional information for any element on hover or focus.
  15239. //>>docs: http://api.jqueryui.com/tooltip/
  15240. //>>demos: http://jqueryui.com/tooltip/
  15241. //>>css.structure: ../../themes/base/core.css
  15242. //>>css.structure: ../../themes/base/tooltip.css
  15243. //>>css.theme: ../../themes/base/theme.css
  15244. $.widget( "ui.tooltip", {
  15245. version: "1.12.1",
  15246. options: {
  15247. classes: {
  15248. "ui-tooltip": "ui-corner-all ui-widget-shadow"
  15249. },
  15250. content: function() {
  15251. // support: IE<9, Opera in jQuery <1.7
  15252. // .text() can't accept undefined, so coerce to a string
  15253. var title = $( this ).attr( "title" ) || "";
  15254. // Escape title, since we're going from an attribute to raw HTML
  15255. return $( "<a>" ).text( title ).html();
  15256. },
  15257. hide: true,
  15258. // Disabled elements have inconsistent behavior across browsers (#8661)
  15259. items: "[title]:not([disabled])",
  15260. position: {
  15261. my: "left top+15",
  15262. at: "left bottom",
  15263. collision: "flipfit flip"
  15264. },
  15265. show: true,
  15266. track: false,
  15267. // Callbacks
  15268. close: null,
  15269. open: null
  15270. },
  15271. _addDescribedBy: function( elem, id ) {
  15272. var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
  15273. describedby.push( id );
  15274. elem
  15275. .data( "ui-tooltip-id", id )
  15276. .attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
  15277. },
  15278. _removeDescribedBy: function( elem ) {
  15279. var id = elem.data( "ui-tooltip-id" ),
  15280. describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
  15281. index = $.inArray( id, describedby );
  15282. if ( index !== -1 ) {
  15283. describedby.splice( index, 1 );
  15284. }
  15285. elem.removeData( "ui-tooltip-id" );
  15286. describedby = $.trim( describedby.join( " " ) );
  15287. if ( describedby ) {
  15288. elem.attr( "aria-describedby", describedby );
  15289. } else {
  15290. elem.removeAttr( "aria-describedby" );
  15291. }
  15292. },
  15293. _create: function() {
  15294. this._on( {
  15295. mouseover: "open",
  15296. focusin: "open"
  15297. } );
  15298. // IDs of generated tooltips, needed for destroy
  15299. this.tooltips = {};
  15300. // IDs of parent tooltips where we removed the title attribute
  15301. this.parents = {};
  15302. // Append the aria-live region so tooltips announce correctly
  15303. this.liveRegion = $( "<div>" )
  15304. .attr( {
  15305. role: "log",
  15306. "aria-live": "assertive",
  15307. "aria-relevant": "additions"
  15308. } )
  15309. .appendTo( this.document[ 0 ].body );
  15310. this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
  15311. this.disabledTitles = $( [] );
  15312. },
  15313. _setOption: function( key, value ) {
  15314. var that = this;
  15315. this._super( key, value );
  15316. if ( key === "content" ) {
  15317. $.each( this.tooltips, function( id, tooltipData ) {
  15318. that._updateContent( tooltipData.element );
  15319. } );
  15320. }
  15321. },
  15322. _setOptionDisabled: function( value ) {
  15323. this[ value ? "_disable" : "_enable" ]();
  15324. },
  15325. _disable: function() {
  15326. var that = this;
  15327. // Close open tooltips
  15328. $.each( this.tooltips, function( id, tooltipData ) {
  15329. var event = $.Event( "blur" );
  15330. event.target = event.currentTarget = tooltipData.element[ 0 ];
  15331. that.close( event, true );
  15332. } );
  15333. // Remove title attributes to prevent native tooltips
  15334. this.disabledTitles = this.disabledTitles.add(
  15335. this.element.find( this.options.items ).addBack()
  15336. .filter( function() {
  15337. var element = $( this );
  15338. if ( element.is( "[title]" ) ) {
  15339. return element
  15340. .data( "ui-tooltip-title", element.attr( "title" ) )
  15341. .removeAttr( "title" );
  15342. }
  15343. } )
  15344. );
  15345. },
  15346. _enable: function() {
  15347. // restore title attributes
  15348. this.disabledTitles.each( function() {
  15349. var element = $( this );
  15350. if ( element.data( "ui-tooltip-title" ) ) {
  15351. element.attr( "title", element.data( "ui-tooltip-title" ) );
  15352. }
  15353. } );
  15354. this.disabledTitles = $( [] );
  15355. },
  15356. open: function( event ) {
  15357. var that = this,
  15358. target = $( event ? event.target : this.element )
  15359. // we need closest here due to mouseover bubbling,
  15360. // but always pointing at the same event target
  15361. .closest( this.options.items );
  15362. // No element to show a tooltip for or the tooltip is already open
  15363. if ( !target.length || target.data( "ui-tooltip-id" ) ) {
  15364. return;
  15365. }
  15366. if ( target.attr( "title" ) ) {
  15367. target.data( "ui-tooltip-title", target.attr( "title" ) );
  15368. }
  15369. target.data( "ui-tooltip-open", true );
  15370. // Kill parent tooltips, custom or native, for hover
  15371. if ( event && event.type === "mouseover" ) {
  15372. target.parents().each( function() {
  15373. var parent = $( this ),
  15374. blurEvent;
  15375. if ( parent.data( "ui-tooltip-open" ) ) {
  15376. blurEvent = $.Event( "blur" );
  15377. blurEvent.target = blurEvent.currentTarget = this;
  15378. that.close( blurEvent, true );
  15379. }
  15380. if ( parent.attr( "title" ) ) {
  15381. parent.uniqueId();
  15382. that.parents[ this.id ] = {
  15383. element: this,
  15384. title: parent.attr( "title" )
  15385. };
  15386. parent.attr( "title", "" );
  15387. }
  15388. } );
  15389. }
  15390. this._registerCloseHandlers( event, target );
  15391. this._updateContent( target, event );
  15392. },
  15393. _updateContent: function( target, event ) {
  15394. var content,
  15395. contentOption = this.options.content,
  15396. that = this,
  15397. eventType = event ? event.type : null;
  15398. if ( typeof contentOption === "string" || contentOption.nodeType ||
  15399. contentOption.jquery ) {
  15400. return this._open( event, target, contentOption );
  15401. }
  15402. content = contentOption.call( target[ 0 ], function( response ) {
  15403. // IE may instantly serve a cached response for ajax requests
  15404. // delay this call to _open so the other call to _open runs first
  15405. that._delay( function() {
  15406. // Ignore async response if tooltip was closed already
  15407. if ( !target.data( "ui-tooltip-open" ) ) {
  15408. return;
  15409. }
  15410. // JQuery creates a special event for focusin when it doesn't
  15411. // exist natively. To improve performance, the native event
  15412. // object is reused and the type is changed. Therefore, we can't
  15413. // rely on the type being correct after the event finished
  15414. // bubbling, so we set it back to the previous value. (#8740)
  15415. if ( event ) {
  15416. event.type = eventType;
  15417. }
  15418. this._open( event, target, response );
  15419. } );
  15420. } );
  15421. if ( content ) {
  15422. this._open( event, target, content );
  15423. }
  15424. },
  15425. _open: function( event, target, content ) {
  15426. var tooltipData, tooltip, delayedShow, a11yContent,
  15427. positionOption = $.extend( {}, this.options.position );
  15428. if ( !content ) {
  15429. return;
  15430. }
  15431. // Content can be updated multiple times. If the tooltip already
  15432. // exists, then just update the content and bail.
  15433. tooltipData = this._find( target );
  15434. if ( tooltipData ) {
  15435. tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
  15436. return;
  15437. }
  15438. // If we have a title, clear it to prevent the native tooltip
  15439. // we have to check first to avoid defining a title if none exists
  15440. // (we don't want to cause an element to start matching [title])
  15441. //
  15442. // We use removeAttr only for key events, to allow IE to export the correct
  15443. // accessible attributes. For mouse events, set to empty string to avoid
  15444. // native tooltip showing up (happens only when removing inside mouseover).
  15445. if ( target.is( "[title]" ) ) {
  15446. if ( event && event.type === "mouseover" ) {
  15447. target.attr( "title", "" );
  15448. } else {
  15449. target.removeAttr( "title" );
  15450. }
  15451. }
  15452. tooltipData = this._tooltip( target );
  15453. tooltip = tooltipData.tooltip;
  15454. this._addDescribedBy( target, tooltip.attr( "id" ) );
  15455. tooltip.find( ".ui-tooltip-content" ).html( content );
  15456. // Support: Voiceover on OS X, JAWS on IE <= 9
  15457. // JAWS announces deletions even when aria-relevant="additions"
  15458. // Voiceover will sometimes re-read the entire log region's contents from the beginning
  15459. this.liveRegion.children().hide();
  15460. a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
  15461. a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
  15462. a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
  15463. a11yContent.appendTo( this.liveRegion );
  15464. function position( event ) {
  15465. positionOption.of = event;
  15466. if ( tooltip.is( ":hidden" ) ) {
  15467. return;
  15468. }
  15469. tooltip.position( positionOption );
  15470. }
  15471. if ( this.options.track && event && /^mouse/.test( event.type ) ) {
  15472. this._on( this.document, {
  15473. mousemove: position
  15474. } );
  15475. // trigger once to override element-relative positioning
  15476. position( event );
  15477. } else {
  15478. tooltip.position( $.extend( {
  15479. of: target
  15480. }, this.options.position ) );
  15481. }
  15482. tooltip.hide();
  15483. this._show( tooltip, this.options.show );
  15484. // Handle tracking tooltips that are shown with a delay (#8644). As soon
  15485. // as the tooltip is visible, position the tooltip using the most recent
  15486. // event.
  15487. // Adds the check to add the timers only when both delay and track options are set (#14682)
  15488. if ( this.options.track && this.options.show && this.options.show.delay ) {
  15489. delayedShow = this.delayedShow = setInterval( function() {
  15490. if ( tooltip.is( ":visible" ) ) {
  15491. position( positionOption.of );
  15492. clearInterval( delayedShow );
  15493. }
  15494. }, $.fx.interval );
  15495. }
  15496. this._trigger( "open", event, { tooltip: tooltip } );
  15497. },
  15498. _registerCloseHandlers: function( event, target ) {
  15499. var events = {
  15500. keyup: function( event ) {
  15501. if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
  15502. var fakeEvent = $.Event( event );
  15503. fakeEvent.currentTarget = target[ 0 ];
  15504. this.close( fakeEvent, true );
  15505. }
  15506. }
  15507. };
  15508. // Only bind remove handler for delegated targets. Non-delegated
  15509. // tooltips will handle this in destroy.
  15510. if ( target[ 0 ] !== this.element[ 0 ] ) {
  15511. events.remove = function() {
  15512. this._removeTooltip( this._find( target ).tooltip );
  15513. };
  15514. }
  15515. if ( !event || event.type === "mouseover" ) {
  15516. events.mouseleave = "close";
  15517. }
  15518. if ( !event || event.type === "focusin" ) {
  15519. events.focusout = "close";
  15520. }
  15521. this._on( true, target, events );
  15522. },
  15523. close: function( event ) {
  15524. var tooltip,
  15525. that = this,
  15526. target = $( event ? event.currentTarget : this.element ),
  15527. tooltipData = this._find( target );
  15528. // The tooltip may already be closed
  15529. if ( !tooltipData ) {
  15530. // We set ui-tooltip-open immediately upon open (in open()), but only set the
  15531. // additional data once there's actually content to show (in _open()). So even if the
  15532. // tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
  15533. // the period between open() and _open().
  15534. target.removeData( "ui-tooltip-open" );
  15535. return;
  15536. }
  15537. tooltip = tooltipData.tooltip;
  15538. // Disabling closes the tooltip, so we need to track when we're closing
  15539. // to avoid an infinite loop in case the tooltip becomes disabled on close
  15540. if ( tooltipData.closing ) {
  15541. return;
  15542. }
  15543. // Clear the interval for delayed tracking tooltips
  15544. clearInterval( this.delayedShow );
  15545. // Only set title if we had one before (see comment in _open())
  15546. // If the title attribute has changed since open(), don't restore
  15547. if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
  15548. target.attr( "title", target.data( "ui-tooltip-title" ) );
  15549. }
  15550. this._removeDescribedBy( target );
  15551. tooltipData.hiding = true;
  15552. tooltip.stop( true );
  15553. this._hide( tooltip, this.options.hide, function() {
  15554. that._removeTooltip( $( this ) );
  15555. } );
  15556. target.removeData( "ui-tooltip-open" );
  15557. this._off( target, "mouseleave focusout keyup" );
  15558. // Remove 'remove' binding only on delegated targets
  15559. if ( target[ 0 ] !== this.element[ 0 ] ) {
  15560. this._off( target, "remove" );
  15561. }
  15562. this._off( this.document, "mousemove" );
  15563. if ( event && event.type === "mouseleave" ) {
  15564. $.each( this.parents, function( id, parent ) {
  15565. $( parent.element ).attr( "title", parent.title );
  15566. delete that.parents[ id ];
  15567. } );
  15568. }
  15569. tooltipData.closing = true;
  15570. this._trigger( "close", event, { tooltip: tooltip } );
  15571. if ( !tooltipData.hiding ) {
  15572. tooltipData.closing = false;
  15573. }
  15574. },
  15575. _tooltip: function( element ) {
  15576. var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
  15577. content = $( "<div>" ).appendTo( tooltip ),
  15578. id = tooltip.uniqueId().attr( "id" );
  15579. this._addClass( content, "ui-tooltip-content" );
  15580. this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
  15581. tooltip.appendTo( this._appendTo( element ) );
  15582. return this.tooltips[ id ] = {
  15583. element: element,
  15584. tooltip: tooltip
  15585. };
  15586. },
  15587. _find: function( target ) {
  15588. var id = target.data( "ui-tooltip-id" );
  15589. return id ? this.tooltips[ id ] : null;
  15590. },
  15591. _removeTooltip: function( tooltip ) {
  15592. tooltip.remove();
  15593. delete this.tooltips[ tooltip.attr( "id" ) ];
  15594. },
  15595. _appendTo: function( target ) {
  15596. var element = target.closest( ".ui-front, dialog" );
  15597. if ( !element.length ) {
  15598. element = this.document[ 0 ].body;
  15599. }
  15600. return element;
  15601. },
  15602. _destroy: function() {
  15603. var that = this;
  15604. // Close open tooltips
  15605. $.each( this.tooltips, function( id, tooltipData ) {
  15606. // Delegate to close method to handle common cleanup
  15607. var event = $.Event( "blur" ),
  15608. element = tooltipData.element;
  15609. event.target = event.currentTarget = element[ 0 ];
  15610. that.close( event, true );
  15611. // Remove immediately; destroying an open tooltip doesn't use the
  15612. // hide animation
  15613. $( "#" + id ).remove();
  15614. // Restore the title
  15615. if ( element.data( "ui-tooltip-title" ) ) {
  15616. // If the title attribute has changed since open(), don't restore
  15617. if ( !element.attr( "title" ) ) {
  15618. element.attr( "title", element.data( "ui-tooltip-title" ) );
  15619. }
  15620. element.removeData( "ui-tooltip-title" );
  15621. }
  15622. } );
  15623. this.liveRegion.remove();
  15624. }
  15625. } );
  15626. // DEPRECATED
  15627. // TODO: Switch return back to widget declaration at top of file when this is removed
  15628. if ( $.uiBackCompat !== false ) {
  15629. // Backcompat for tooltipClass option
  15630. $.widget( "ui.tooltip", $.ui.tooltip, {
  15631. options: {
  15632. tooltipClass: null
  15633. },
  15634. _tooltip: function() {
  15635. var tooltipData = this._superApply( arguments );
  15636. if ( this.options.tooltipClass ) {
  15637. tooltipData.tooltip.addClass( this.options.tooltipClass );
  15638. }
  15639. return tooltipData;
  15640. }
  15641. } );
  15642. }
  15643. var widgetsTooltip = $.ui.tooltip;
  15644. }));
  15645. /***/ })
  15646. }]);
  15647. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvanF1ZXJ5LXVpLWRpc3QvanF1ZXJ5LXVpLmpzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7Ozs7Ozs7O0FBQUE7QUFDQTtBQUNBO0FBQ0EscURBQXFEOztBQUVyRDtBQUNBLE1BQU0sSUFBMEM7O0FBRWhEO0FBQ0EsRUFBRSxpQ0FBTyxFQUFFLHdFQUFRLEVBQUUsb0NBQUUsT0FBTztBQUFBO0FBQUE7QUFBQSxrR0FBRTtBQUNoQyxFQUFFLE1BQU0sRUFJTjtBQUNGLENBQUM7O0FBRUQ7O0FBRUE7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYywrQkFBK0I7QUFDN0M7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHdDQUF3QztBQUN4Qzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esc0JBQXNCOztBQUV0QjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDRDQUE0QztBQUM1QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7QUFDRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFFBQVEsMEJBQTBCO0FBQ2xDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSx5QkFBeUI7O0FBRXpCO0FBQ0EseUJBQXlCOztBQUV6QjtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxpQ0FBaUM7QUFDakM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1DQUFtQztBQUNuQztBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGFBQWE7QUFDYjs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxvQ0FBb0M7QUFDcEM7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsNkJBQTZCO0FBQzdCOztBQUVBOztBQUVBLDhDQUE4QyxPQUFPLFdBQVc7QUFDaEU7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvREFBb0Q7QUFDcEQsZ0JBQWdCLHNCQUFzQjtBQUN0QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0EsNEJBQTRCLGtCQUFrQjtBQUM5QyxFQUFFOztBQUVGO0FBQ0EsNEJBQTRCLGlCQUFpQjtBQUM3QyxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQSxlQUFlLG9CQUFvQjtBQUNuQztBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsU0FBUyxrQ0FBa0M7QUFDM0M7QUFDQTtBQUNBLGNBQWM7QUFDZDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMEJBQTBCLGtCQUFrQixXQUFXLFlBQVksZ0JBQWdCO0FBQ25GLDhCQUE4QixXQUFXO0FBQ3pDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZ0RBQWdELGtCQUFrQjtBQUNsRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHVCQUF1Qjs7QUFFdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsNEJBQTRCOztBQUU1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUI7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBLEdBQUc7O0FBRUg7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxvQ0FBb0MsZUFBZTtBQUNuRCxFQUFFO0FBQ0Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLENBQUM7O0FBRUQ7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHNCQUFzQixJQUFJLFlBQVksSUFBSSxZQUFZLElBQUk7QUFDMUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0EsbUJBQW1CLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRTtBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRiw2QkFBNkI7O0FBRTdCO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0EsRUFBRTtBQUNGOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBLENBQUM7QUFDRDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBLEVBQUU7QUFDRjtBQUNBLEVBQUU7QUFDRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRixDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsY0FBYztBQUNkOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1QkFBdUI7QUFDdkI7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTtBQUNGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNLGtCQUFrQjtBQUN4QjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU0scUJBQXFCO0FBQzNCO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxpQkFBaUIsa0JBQWtCLElBQUkscUJBQXFCO0FBQzVEO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQSxNQUFNLHFCQUFxQjtBQUMzQjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLENBQUM7O0FBRUQsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFVBQVUsWUFBWTtBQUN0QjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0EsVUFBVSxZQUFZO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxrQkFBa0IsdUJBQXVCO0FBQ3pDLGtCQUFrQix1QkFBdUI7QUFDekMsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsV0FBVzs7QUFFWDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7O0FBRUEsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRCxDQUFDOztBQUVEOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLGFBQWEsbUJBQW1CLFdBQVc7QUFDM0M7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGNBQWM7QUFDZDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsUUFBUSxXQUFXO0FBQ25CO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0YsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsYUFBYSxVQUFVLFFBQVE7QUFDL0I7QUFDQTs7QUFFQSxjQUFjLFdBQVcsUUFBUTtBQUNqQztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsZ0JBQWdCLG1CQUFtQixXQUFXO0FBQzlDLGdCQUFnQixtQkFBbUIsV0FBVzs7QUFFOUM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osR0FBRztBQUNIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUYsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0Esb0NBQW9DO0FBQ3BDO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0EsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLFFBQVEsV0FBVztBQUNuQixvQkFBb0IscUJBQXFCO0FBQ3pDO0FBQ0E7O0FBRUEsbUJBQW1CLHFCQUFxQjs7QUFFeEM7O0FBRUE7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEIsaUJBQWlCO0FBQ2pCLGlCQUFpQjs7QUFFakI7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLFFBQVEsV0FBVztBQUNuQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0YsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBLEVBQUU7QUFDRjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEOzs7OztBQUtBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7O0FBS0E7QUFDQTtBQUNBLHlDQUF5QyxXQUFXLEVBQUU7QUFDdEQ7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxnREFBZ0Q7QUFDaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0Esa0NBQWtDLDJCQUEyQjtBQUM3RDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLEdBQUc7QUFDSDtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0wsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QztBQUN2QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7Ozs7QUFJRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJO0FBQ0o7QUFDQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxrQ0FBa0MsYUFBYTtBQUMvQyxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsaUNBQWlDLG9CQUFvQjtBQUNyRDtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0Esc0RBQXNEO0FBQ3REOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBO0FBQ0EsbURBQW1ELGFBQWE7O0FBRWhFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047O0FBRUEsb0RBQW9ELGFBQWE7QUFDakU7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdCQUFnQixjQUFjO0FBQzlCLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0NBQW9DLG1CQUFtQjtBQUN2RDtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLG9DQUFvQywwQkFBMEI7QUFDOUQ7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQkFBc0I7QUFDdEI7QUFDQTtBQUNBLElBQUk7QUFDSixHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0Esa0NBQWtDO0FBQ2xDLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBLGlEQUFpRCxJQUFJOztBQUVyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKLGVBQWUsWUFBWTtBQUMzQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDhDQUE4Qzs7QUFFOUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTCxHQUFHOztBQUVIO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTtBQUNKO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzQkFBc0IseUJBQXlCO0FBQy9DO0FBQ0E7O0FBRUEsQ0FBQzs7QUFFRDs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzQkFBc0IsdUJBQXVCO0FBQzdDOztBQUVBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQSxpQkFBaUIsY0FBYyxvQkFBb0IsRUFBRTs7QUFFckQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsK0JBQStCLHlCQUF5QjtBQUN4RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzQkFBc0I7QUFDdEIsd0JBQXdCO0FBQ3hCLDJCQUEyQjtBQUMzQixpQ0FBaUM7QUFDakMsd0JBQXdCO0FBQ3hCLHVDQUF1QztBQUN2Qyw0Q0FBNEM7QUFDNUMsNENBQTRDO0FBQzVDLDhDQUE4QztBQUM5Qyw0Q0FBNEM7QUFDNUMsK0NBQStDO0FBQy9DLHdEQUF3RDtBQUN4RCxrREFBa0Q7QUFDbEQscURBQXFEO0FBQ3JELG9CQUFvQjtBQUNwQix3QkFBd0I7QUFDeEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxzQ0FBc0M7QUFDdEMsOENBQThDO0FBQzlDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseURBQXlEO0FBQ3pEO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDhCQUE4QixnQkFBZ0I7QUFDOUM7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0Esb0VBQW9FO0FBQ3BFLFVBQVU7QUFDVjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxrREFBa0Q7QUFDbEQ7QUFDQTtBQUNBLG1EQUFtRDtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksdURBQXVEO0FBQ25FO0FBQ0E7QUFDQSxNQUFNLG9EQUFvRDtBQUMxRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsaUJBQWlCLGtCQUFrQjtBQUNuQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsMkJBQTJCOztBQUUzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlDQUFpQyxhQUFhLFlBQVk7QUFDMUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esd0RBQXdEO0FBQ3hEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLHVCQUF1QixFQUFFO0FBQy9DLDBCQUEwQiw2QkFBNkI7QUFDdkQsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQiw0Q0FBNEMsRUFBRSxHQUFHO0FBQ3ZFLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esc0JBQXNCLHNCQUFzQixFQUFFO0FBQzlDLDBCQUEwQixvQ0FBb0M7QUFDOUQsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHNCQUFzQiw0Q0FBNEMsRUFBRSxHQUFHO0FBQ3ZFO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLGlDQUFpQztBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhDQUE4QztBQUM5Qyw0Q0FBNEM7QUFDNUM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQSxHQUFHLG9EQUFvRDtBQUN2RDtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGlCQUFpQjtBQUNqQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbURBQW1EO0FBQ25EO0FBQ0E7O0FBRUEsMkZBQTJGO0FBQzNGO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLGlDQUFpQztBQUNqQztBQUNBO0FBQ0EsNkJBQTZCO0FBQzdCO0FBQ0EsZ0RBQWdEO0FBQ2hEOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSCxZQUFZO0FBQ1o7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQix5REFBeUQ7QUFDNUU7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CO0FBQ25CO0FBQ0EscURBQXFEOztBQUVyRDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLG1CQUFtQjtBQUNuQiwrQkFBK0I7QUFDL0I7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSw0QkFBNEIsaURBQWlEO0FBQzdFO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGdGQUFnRjtBQUNoRixHQUFHO0FBQ0gsa0NBQWtDO0FBQ2xDOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDO0FBQ2xDO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsMEJBQTBCO0FBQzFCO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQ0FBZ0MsNkJBQTZCO0FBQzdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBLE1BQU07O0FBRU47QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxvQkFBb0IseUJBQXlCO0FBQzdDO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQSx3QkFBd0I7QUFDeEI7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQSxxQkFBcUIseUJBQXlCO0FBQzlDO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7QUFDUjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG9CQUFvQix5QkFBeUI7QUFDN0M7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQjtBQUNsQjtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDJDQUEyQztBQUMzQztBQUNBLCtDQUErQztBQUMvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsZ0JBQWdCLHNCQUFzQjtBQUN0QztBQUNBO0FBQ0EsaUJBQWlCLHNCQUFzQjtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsbUVBQW1FO0FBQ25FO0FBQ0EsbUVBQW1FO0FBQ25FLDBEQUEwRCxrQkFBa0I7QUFDNUU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0JBQWtCLFNBQVMsVUFBVTtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDBEQUEwRDtBQUMxRCwyRkFBMkY7QUFDM0Y7QUFDQTtBQUNBLG1CQUFtQixnQkFBZ0IsV0FBVztBQUM5QztBQUNBO0FBQ0E7QUFDQSxtQkFBbUIsU0FBUyxVQUFVO0FBQ3RDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFIQUFxSDtBQUNySDtBQUNBLGlEQUFpRDtBQUNqRDtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtFQUFrRTtBQUNsRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLFlBQVk7QUFDL0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDhFQUE4RTtBQUM5RTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esa0VBQWtFO0FBQ2xFO0FBQ0EsbUJBQW1CO0FBQ25CO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFVBQVU7QUFDVjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjs7QUFFQSxnQ0FBZ0M7QUFDaEM7QUFDQTtBQUNBOztBQUVBOzs7OztBQUtBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0Esd0NBQXdDO0FBQ3hDLHVDQUF1QztBQUN2Qyx1Q0FBdUM7QUFDdkMseUNBQXlDLGFBQWE7QUFDdEQsQ0FBQzs7Ozs7QUFLRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxjQUFjLGdCQUFnQjtBQUM5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQSwyQ0FBMkMsNEJBQTRCO0FBQ3ZFLEdBQUc7QUFDSDtBQUNBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsVUFBVTtBQUNWO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsU0FBUztBQUNUOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLFdBQVc7QUFDWDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRixZQUFZOztBQUVaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsQ0FBQzs7QUFFRDtBQUNBO0FBQ0EsK0JBQStCO0FBQy9CO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTtBQUNGO0FBQ0EsK0JBQStCO0FBQy9CO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07O0FBRU47QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxDQUFDOztBQUVEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsSUFBSTs7QUFFSixFQUFFO0FBQ0Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtDQUFrQyx3Q0FBd0M7QUFDMUU7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87QUFDUDtBQUNBOztBQUVBOztBQUVBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUosd0JBQXdCLFFBQVE7O0FBRWhDO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBLHdEQUF3RDtBQUN4RDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLGVBQWUsY0FBYzs7QUFFN0I7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsZUFBZSxtQkFBbUI7O0FBRWxDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsbUNBQW1DLCtCQUErQjtBQUNsRTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQjs7QUFFbkI7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDJCQUEyQjtBQUMzQixnQ0FBZ0M7O0FBRWhDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxvQ0FBb0MsdUJBQXVCO0FBQzNEOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFNBQVMsT0FBTztBQUNoQjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsU0FBUywrQ0FBK0M7O0FBRXhEOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsZ0VBQWdFOztBQUVoRTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7O0FBRUEsR0FBRztBQUNIO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsV0FBVztBQUNYLEdBQUc7QUFDSDtBQUNBO0FBQ0EsV0FBVztBQUNYLEdBQUc7QUFDSDtBQUNBO0FBQ0EsV0FBVztBQUNYLEdBQUc7QUFDSDtBQUNBLFdBQVc7QUFDWCxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUYsWUFBWTs7QUFFWjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsbUNBQW1DLHVCQUF1QixLQUFLO0FBQy9EO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx5QkFBeUIseUNBQXlDO0FBQ2xFOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxDQUFDOztBQUVEOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLENBQUM7O0FBRUQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHVGQUF1RjtBQUN2RjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQSxJQUFJO0FBQ0osRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxDQUFDOztBQUVEOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxDQUFDOztBQUVEOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsc0JBQXNCO0FBQ3RCO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSywyQkFBMkI7QUFDaEM7O0FBRUE7QUFDQSxzQkFBc0IsaUJBQWlCOztBQUV2QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLEdBQUc7QUFDSDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLFNBQVMsaUJBQWlCO0FBQzFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLGdDQUFnQztBQUN2RDtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtCQUFrQjtBQUNsQixJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSwwREFBMEQ7QUFDMUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGNBQWMsZ0JBQWdCO0FBQzlCOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDhCQUE4QixjQUFjOztBQUU1QztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsZUFBZSxpQkFBaUI7QUFDaEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7O0FBRUEsRUFBRTtBQUNGOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEdBQUc7QUFDSDs7QUFFQSxFQUFFO0FBQ0Y7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7QUFDRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVILEVBQUU7QUFDRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjs7QUFFQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSw2QkFBNkI7QUFDN0I7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLElBQUk7QUFDSjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOLEtBQUs7QUFDTDtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUgsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsa0JBQWtCLFVBQVUsU0FBUyxVQUFVO0FBQy9DLGtCQUFrQixVQUFVLFNBQVMsVUFBVTtBQUMvQyxvQkFBb0IscURBQXFEOztBQUV6RTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxPQUFPO0FBQ1A7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSixHQUFHO0FBQ0g7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxDQUFDOzs7QUFHRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxzQ0FBc0MsYUFBYTtBQUNuRDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLHFDQUFxQyxrQkFBa0I7QUFDdkQsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCx3QkFBd0I7QUFDeEI7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxtQ0FBbUMsYUFBYTs7QUFFaEQ7QUFDQSxvQ0FBb0MsYUFBYTtBQUNqRDs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7OztBQUdEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7OztBQUlBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxtQ0FBbUMsaUJBQWlCO0FBQ3BEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EseUNBQXlDLGtCQUFrQjtBQUMzRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBLGtCQUFrQixpQ0FBaUM7QUFDbkQ7O0FBRUE7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsaUJBQWlCO0FBQ2pDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDZCQUE2QixRQUFRO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQSxlQUFlLGlCQUFpQjtBQUNoQztBQUNBOztBQUVBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxvQkFBb0IsMEJBQTBCO0FBQzlDO0FBQ0E7QUFDQSxvQkFBb0IsNkJBQTZCO0FBQ2pEO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTtBQUNSO0FBQ0E7QUFDQSxRQUFRO0FBQ1I7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBOztBQUVBLHNDQUFzQyxRQUFRO0FBQzlDO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxXQUFXO0FBQ1g7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsMENBQTBDO0FBQzFDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGlCQUFpQixxQ0FBcUMsRUFBRTtBQUN4RDs7QUFFQSxvQkFBb0I7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxtQkFBbUI7QUFDbkI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHdDQUF3QyxRQUFRO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxrQ0FBa0MsUUFBUTs7QUFFMUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUEsMkNBQTJDLGVBQWU7O0FBRTFEO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBOztBQUVBO0FBQ0EsNENBQTRDLFFBQVE7QUFDcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQztBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDs7QUFFQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQSxxREFBcUQ7O0FBRXJEO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxvQ0FBb0MsUUFBUTtBQUM1QztBQUNBLDZCQUE2QixRQUFRO0FBQ3JDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGdDQUFnQyxnREFBZ0Q7QUFDaEY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLCtCQUErQixRQUFRO0FBQ3ZDO0FBQ0E7O0FBRUE7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTtBQUNBLG1CQUFtQixpQkFBaUI7QUFDcEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUgsRUFBRTs7QUFFRjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHdEQUF3RCx5QkFBeUI7QUFDakY7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esb0NBQW9DLFFBQVE7QUFDNUM7QUFDQSw2QkFBNkIsUUFBUTtBQUNyQztBQUNBO0FBQ0E7QUFDQTtBQUNBLDBDQUEwQyx5QkFBeUI7QUFDbkU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLCtCQUErQixRQUFRO0FBQ3ZDO0FBQ0E7O0FBRUEsZ0RBQWdELG1CQUFtQjtBQUNuRTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsa0NBQWtDLFFBQVE7QUFDMUM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSCx3Q0FBd0MsUUFBUTtBQUNoRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQSxpQkFBaUI7QUFDakI7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx1Q0FBdUMsUUFBUTs7QUFFL0M7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsbUNBQW1DLFFBQVE7QUFDM0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxVQUFVO0FBQ1Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFNBQVM7QUFDVDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsV0FBVztBQUNYOztBQUVBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsZ0NBQWdDOztBQUVoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUgsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVDQUF1QyxRQUFRO0FBQy9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsb0NBQW9DO0FBQ3BDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsZUFBZSw0QkFBNEI7O0FBRTNDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsQ0FBQzs7O0FBR0Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7O0FBSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0gsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxHQUFHO0FBQ0g7QUFDQTs7QUFFQSw4Q0FBOEM7QUFDOUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsd0RBQXdELGVBQWU7QUFDdkU7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsaURBQWlEO0FBQ2pEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0EsZ0RBQWdELGFBQWEsRUFBRTtBQUMvRCxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBLGtEQUFrRDtBQUNsRDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGNBQWMseUJBQXlCO0FBQ3ZDO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLHdCQUF3Qix5QkFBeUI7QUFDakQsMEJBQTBCLDJCQUEyQjs7QUFFckQ7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSixHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSCxFQUFFOztBQUVGO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNILEVBQUU7O0FBRUY7QUFDQTtBQUNBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJO0FBQ0o7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxNQUFNO0FBQ04sS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOLEtBQUs7QUFDTDtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsdUNBQXVDO0FBQ3ZEO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsR0FBRztBQUNIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSixHQUFHO0FBQ0g7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBO0FBQ0EsZ0NBQWdDOztBQUVoQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjs7QUFFQSxpQ0FBaUMsbUJBQW1CO0FBQ3BELEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKOztBQUVBO0FBQ0Esa0NBQWtDLG1CQUFtQjtBQUNyRDtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFOztBQUVGO0FBQ0E7QUFDQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTtBQUNBO0FBQ0EsRUFBRTs7QUFFRjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEVBQUU7O0FBRUY7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEseUJBQXlCO0FBQ3pCO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRztBQUNIO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBOzs7OztBQUtBLENBQUMsRyIsImZpbGUiOiJ2ZW5kb3JzLW5vZGVfbW9kdWxlc19qcXVlcnktdWktZGlzdF9qcXVlcnktdWlfanMuanMiLCJzb3VyY2VzQ29udGVudCI6WyIvKiEgalF1ZXJ5IFVJIC0gdjEuMTIuMSAtIDIwMTYtMDktMTRcbiogaHR0cDovL2pxdWVyeXVpLmNvbVxuKiBJbmNsdWRlczogd2lkZ2V0LmpzLCBwb3NpdGlvbi5qcywgZGF0YS5qcywgZGlzYWJsZS1zZWxlY3Rpb24uanMsIGVmZmVjdC5qcywgZWZmZWN0cy9lZmZlY3QtYmxpbmQuanMsIGVmZmVjdHMvZWZmZWN0LWJvdW5jZS5qcywgZWZmZWN0cy9lZmZlY3QtY2xpcC5qcywgZWZmZWN0cy9lZmZlY3QtZHJvcC5qcywgZWZmZWN0cy9lZmZlY3QtZXhwbG9kZS5qcywgZWZmZWN0cy9lZmZlY3QtZmFkZS5qcywgZWZmZWN0cy9lZmZlY3QtZm9sZC5qcywgZWZmZWN0cy9lZmZlY3QtaGlnaGxpZ2h0LmpzLCBlZmZlY3RzL2VmZmVjdC1wdWZmLmpzLCBlZmZlY3RzL2VmZmVjdC1wdWxzYXRlLmpzLCBlZmZlY3RzL2VmZmVjdC1zY2FsZS5qcywgZWZmZWN0cy9lZmZlY3Qtc2hha2UuanMsIGVmZmVjdHMvZWZmZWN0LXNpemUuanMsIGVmZmVjdHMvZWZmZWN0LXNsaWRlLmpzLCBlZmZlY3RzL2VmZmVjdC10cmFuc2Zlci5qcywgZm9jdXNhYmxlLmpzLCBmb3JtLXJlc2V0LW1peGluLmpzLCBqcXVlcnktMS03LmpzLCBrZXljb2RlLmpzLCBsYWJlbHMuanMsIHNjcm9sbC1wYXJlbnQuanMsIHRhYmJhYmxlLmpzLCB1bmlxdWUtaWQuanMsIHdpZGdldHMvYWNjb3JkaW9uLmpzLCB3aWRnZXRzL2F1dG9jb21wbGV0ZS5qcywgd2lkZ2V0cy9idXR0b24uanMsIHdpZGdldHMvY2hlY2tib3hyYWRpby5qcywgd2lkZ2V0cy9jb250cm9sZ3JvdXAuanMsIHdpZGdldHMvZGF0ZXBpY2tlci5qcywgd2lkZ2V0cy9kaWFsb2cuanMsIHdpZGdldHMvZHJhZ2dhYmxlLmpzLCB3aWRnZXRzL2Ryb3BwYWJsZS5qcywgd2lkZ2V0cy9tZW51LmpzLCB3aWRnZXRzL21vdXNlLmpzLCB3aWRnZXRzL3Byb2dyZXNzYmFyLmpzLCB3aWRnZXRzL3Jlc2l6YWJsZS5qcywgd2lkZ2V0cy9zZWxlY3RhYmxlLmpzLCB3aWRnZXRzL3NlbGVjdG1lbnUuanMsIHdpZGdldHMvc2xpZGVyLmpzLCB3aWRnZXRzL3NvcnRhYmxlLmpzLCB3aWRnZXRzL3NwaW5uZXIuanMsIHdpZGdldHMvdGFicy5qcywgd2lkZ2V0cy90b29sdGlwLmpzXG4qIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzOyBMaWNlbnNlZCBNSVQgKi9cblxuKGZ1bmN0aW9uKCBmYWN0b3J5ICkge1xuXHRpZiAoIHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kICkge1xuXG5cdFx0Ly8gQU1ELiBSZWdpc3RlciBhcyBhbiBhbm9ueW1vdXMgbW9kdWxlLlxuXHRcdGRlZmluZShbIFwianF1ZXJ5XCIgXSwgZmFjdG9yeSApO1xuXHR9IGVsc2Uge1xuXG5cdFx0Ly8gQnJvd3NlciBnbG9iYWxzXG5cdFx0ZmFjdG9yeSggalF1ZXJ5ICk7XG5cdH1cbn0oZnVuY3Rpb24oICQgKSB7XG5cbiQudWkgPSAkLnVpIHx8IHt9O1xuXG52YXIgdmVyc2lvbiA9ICQudWkudmVyc2lvbiA9IFwiMS4xMi4xXCI7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgV2lkZ2V0IDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBXaWRnZXRcbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBQcm92aWRlcyBhIGZhY3RvcnkgZm9yIGNyZWF0aW5nIHN0YXRlZnVsIHdpZGdldHMgd2l0aCBhIGNvbW1vbiBBUEkuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20valF1ZXJ5LndpZGdldC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS93aWRnZXQvXG5cblxuXG52YXIgd2lkZ2V0VXVpZCA9IDA7XG52YXIgd2lkZ2V0U2xpY2UgPSBBcnJheS5wcm90b3R5cGUuc2xpY2U7XG5cbiQuY2xlYW5EYXRhID0gKCBmdW5jdGlvbiggb3JpZyApIHtcblx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtcyApIHtcblx0XHR2YXIgZXZlbnRzLCBlbGVtLCBpO1xuXHRcdGZvciAoIGkgPSAwOyAoIGVsZW0gPSBlbGVtc1sgaSBdICkgIT0gbnVsbDsgaSsrICkge1xuXHRcdFx0dHJ5IHtcblxuXHRcdFx0XHQvLyBPbmx5IHRyaWdnZXIgcmVtb3ZlIHdoZW4gbmVjZXNzYXJ5IHRvIHNhdmUgdGltZVxuXHRcdFx0XHRldmVudHMgPSAkLl9kYXRhKCBlbGVtLCBcImV2ZW50c1wiICk7XG5cdFx0XHRcdGlmICggZXZlbnRzICYmIGV2ZW50cy5yZW1vdmUgKSB7XG5cdFx0XHRcdFx0JCggZWxlbSApLnRyaWdnZXJIYW5kbGVyKCBcInJlbW92ZVwiICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0Ly8gSHR0cDovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvODIzNVxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7fVxuXHRcdH1cblx0XHRvcmlnKCBlbGVtcyApO1xuXHR9O1xufSApKCAkLmNsZWFuRGF0YSApO1xuXG4kLndpZGdldCA9IGZ1bmN0aW9uKCBuYW1lLCBiYXNlLCBwcm90b3R5cGUgKSB7XG5cdHZhciBleGlzdGluZ0NvbnN0cnVjdG9yLCBjb25zdHJ1Y3RvciwgYmFzZVByb3RvdHlwZTtcblxuXHQvLyBQcm94aWVkUHJvdG90eXBlIGFsbG93cyB0aGUgcHJvdmlkZWQgcHJvdG90eXBlIHRvIHJlbWFpbiB1bm1vZGlmaWVkXG5cdC8vIHNvIHRoYXQgaXQgY2FuIGJlIHVzZWQgYXMgYSBtaXhpbiBmb3IgbXVsdGlwbGUgd2lkZ2V0cyAoIzg4NzYpXG5cdHZhciBwcm94aWVkUHJvdG90eXBlID0ge307XG5cblx0dmFyIG5hbWVzcGFjZSA9IG5hbWUuc3BsaXQoIFwiLlwiIClbIDAgXTtcblx0bmFtZSA9IG5hbWUuc3BsaXQoIFwiLlwiIClbIDEgXTtcblx0dmFyIGZ1bGxOYW1lID0gbmFtZXNwYWNlICsgXCItXCIgKyBuYW1lO1xuXG5cdGlmICggIXByb3RvdHlwZSApIHtcblx0XHRwcm90b3R5cGUgPSBiYXNlO1xuXHRcdGJhc2UgPSAkLldpZGdldDtcblx0fVxuXG5cdGlmICggJC5pc0FycmF5KCBwcm90b3R5cGUgKSApIHtcblx0XHRwcm90b3R5cGUgPSAkLmV4dGVuZC5hcHBseSggbnVsbCwgWyB7fSBdLmNvbmNhdCggcHJvdG90eXBlICkgKTtcblx0fVxuXG5cdC8vIENyZWF0ZSBzZWxlY3RvciBmb3IgcGx1Z2luXG5cdCQuZXhwclsgXCI6XCIgXVsgZnVsbE5hbWUudG9Mb3dlckNhc2UoKSBdID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuICEhJC5kYXRhKCBlbGVtLCBmdWxsTmFtZSApO1xuXHR9O1xuXG5cdCRbIG5hbWVzcGFjZSBdID0gJFsgbmFtZXNwYWNlIF0gfHwge307XG5cdGV4aXN0aW5nQ29uc3RydWN0b3IgPSAkWyBuYW1lc3BhY2UgXVsgbmFtZSBdO1xuXHRjb25zdHJ1Y3RvciA9ICRbIG5hbWVzcGFjZSBdWyBuYW1lIF0gPSBmdW5jdGlvbiggb3B0aW9ucywgZWxlbWVudCApIHtcblxuXHRcdC8vIEFsbG93IGluc3RhbnRpYXRpb24gd2l0aG91dCBcIm5ld1wiIGtleXdvcmRcblx0XHRpZiAoICF0aGlzLl9jcmVhdGVXaWRnZXQgKSB7XG5cdFx0XHRyZXR1cm4gbmV3IGNvbnN0cnVjdG9yKCBvcHRpb25zLCBlbGVtZW50ICk7XG5cdFx0fVxuXG5cdFx0Ly8gQWxsb3cgaW5zdGFudGlhdGlvbiB3aXRob3V0IGluaXRpYWxpemluZyBmb3Igc2ltcGxlIGluaGVyaXRhbmNlXG5cdFx0Ly8gbXVzdCB1c2UgXCJuZXdcIiBrZXl3b3JkICh0aGUgY29kZSBhYm92ZSBhbHdheXMgcGFzc2VzIGFyZ3MpXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5fY3JlYXRlV2lkZ2V0KCBvcHRpb25zLCBlbGVtZW50ICk7XG5cdFx0fVxuXHR9O1xuXG5cdC8vIEV4dGVuZCB3aXRoIHRoZSBleGlzdGluZyBjb25zdHJ1Y3RvciB0byBjYXJyeSBvdmVyIGFueSBzdGF0aWMgcHJvcGVydGllc1xuXHQkLmV4dGVuZCggY29uc3RydWN0b3IsIGV4aXN0aW5nQ29uc3RydWN0b3IsIHtcblx0XHR2ZXJzaW9uOiBwcm90b3R5cGUudmVyc2lvbixcblxuXHRcdC8vIENvcHkgdGhlIG9iamVjdCB1c2VkIHRvIGNyZWF0ZSB0aGUgcHJvdG90eXBlIGluIGNhc2Ugd2UgbmVlZCB0b1xuXHRcdC8vIHJlZGVmaW5lIHRoZSB3aWRnZXQgbGF0ZXJcblx0XHRfcHJvdG86ICQuZXh0ZW5kKCB7fSwgcHJvdG90eXBlICksXG5cblx0XHQvLyBUcmFjayB3aWRnZXRzIHRoYXQgaW5oZXJpdCBmcm9tIHRoaXMgd2lkZ2V0IGluIGNhc2UgdGhpcyB3aWRnZXQgaXNcblx0XHQvLyByZWRlZmluZWQgYWZ0ZXIgYSB3aWRnZXQgaW5oZXJpdHMgZnJvbSBpdFxuXHRcdF9jaGlsZENvbnN0cnVjdG9yczogW11cblx0fSApO1xuXG5cdGJhc2VQcm90b3R5cGUgPSBuZXcgYmFzZSgpO1xuXG5cdC8vIFdlIG5lZWQgdG8gbWFrZSB0aGUgb3B0aW9ucyBoYXNoIGEgcHJvcGVydHkgZGlyZWN0bHkgb24gdGhlIG5ldyBpbnN0YW5jZVxuXHQvLyBvdGhlcndpc2Ugd2UnbGwgbW9kaWZ5IHRoZSBvcHRpb25zIGhhc2ggb24gdGhlIHByb3RvdHlwZSB0aGF0IHdlJ3JlXG5cdC8vIGluaGVyaXRpbmcgZnJvbVxuXHRiYXNlUHJvdG90eXBlLm9wdGlvbnMgPSAkLndpZGdldC5leHRlbmQoIHt9LCBiYXNlUHJvdG90eXBlLm9wdGlvbnMgKTtcblx0JC5lYWNoKCBwcm90b3R5cGUsIGZ1bmN0aW9uKCBwcm9wLCB2YWx1ZSApIHtcblx0XHRpZiAoICEkLmlzRnVuY3Rpb24oIHZhbHVlICkgKSB7XG5cdFx0XHRwcm94aWVkUHJvdG90eXBlWyBwcm9wIF0gPSB2YWx1ZTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0cHJveGllZFByb3RvdHlwZVsgcHJvcCBdID0gKCBmdW5jdGlvbigpIHtcblx0XHRcdGZ1bmN0aW9uIF9zdXBlcigpIHtcblx0XHRcdFx0cmV0dXJuIGJhc2UucHJvdG90eXBlWyBwcm9wIF0uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0fVxuXG5cdFx0XHRmdW5jdGlvbiBfc3VwZXJBcHBseSggYXJncyApIHtcblx0XHRcdFx0cmV0dXJuIGJhc2UucHJvdG90eXBlWyBwcm9wIF0uYXBwbHkoIHRoaXMsIGFyZ3MgKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgX19zdXBlciA9IHRoaXMuX3N1cGVyO1xuXHRcdFx0XHR2YXIgX19zdXBlckFwcGx5ID0gdGhpcy5fc3VwZXJBcHBseTtcblx0XHRcdFx0dmFyIHJldHVyblZhbHVlO1xuXG5cdFx0XHRcdHRoaXMuX3N1cGVyID0gX3N1cGVyO1xuXHRcdFx0XHR0aGlzLl9zdXBlckFwcGx5ID0gX3N1cGVyQXBwbHk7XG5cblx0XHRcdFx0cmV0dXJuVmFsdWUgPSB2YWx1ZS5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cblx0XHRcdFx0dGhpcy5fc3VwZXIgPSBfX3N1cGVyO1xuXHRcdFx0XHR0aGlzLl9zdXBlckFwcGx5ID0gX19zdXBlckFwcGx5O1xuXG5cdFx0XHRcdHJldHVybiByZXR1cm5WYWx1ZTtcblx0XHRcdH07XG5cdFx0fSApKCk7XG5cdH0gKTtcblx0Y29uc3RydWN0b3IucHJvdG90eXBlID0gJC53aWRnZXQuZXh0ZW5kKCBiYXNlUHJvdG90eXBlLCB7XG5cblx0XHQvLyBUT0RPOiByZW1vdmUgc3VwcG9ydCBmb3Igd2lkZ2V0RXZlbnRQcmVmaXhcblx0XHQvLyBhbHdheXMgdXNlIHRoZSBuYW1lICsgYSBjb2xvbiBhcyB0aGUgcHJlZml4LCBlLmcuLCBkcmFnZ2FibGU6c3RhcnRcblx0XHQvLyBkb24ndCBwcmVmaXggZm9yIHdpZGdldHMgdGhhdCBhcmVuJ3QgRE9NLWJhc2VkXG5cdFx0d2lkZ2V0RXZlbnRQcmVmaXg6IGV4aXN0aW5nQ29uc3RydWN0b3IgPyAoIGJhc2VQcm90b3R5cGUud2lkZ2V0RXZlbnRQcmVmaXggfHwgbmFtZSApIDogbmFtZVxuXHR9LCBwcm94aWVkUHJvdG90eXBlLCB7XG5cdFx0Y29uc3RydWN0b3I6IGNvbnN0cnVjdG9yLFxuXHRcdG5hbWVzcGFjZTogbmFtZXNwYWNlLFxuXHRcdHdpZGdldE5hbWU6IG5hbWUsXG5cdFx0d2lkZ2V0RnVsbE5hbWU6IGZ1bGxOYW1lXG5cdH0gKTtcblxuXHQvLyBJZiB0aGlzIHdpZGdldCBpcyBiZWluZyByZWRlZmluZWQgdGhlbiB3ZSBuZWVkIHRvIGZpbmQgYWxsIHdpZGdldHMgdGhhdFxuXHQvLyBhcmUgaW5oZXJpdGluZyBmcm9tIGl0IGFuZCByZWRlZmluZSBhbGwgb2YgdGhlbSBzbyB0aGF0IHRoZXkgaW5oZXJpdCBmcm9tXG5cdC8vIHRoZSBuZXcgdmVyc2lvbiBvZiB0aGlzIHdpZGdldC4gV2UncmUgZXNzZW50aWFsbHkgdHJ5aW5nIHRvIHJlcGxhY2Ugb25lXG5cdC8vIGxldmVsIGluIHRoZSBwcm90b3R5cGUgY2hhaW4uXG5cdGlmICggZXhpc3RpbmdDb25zdHJ1Y3RvciApIHtcblx0XHQkLmVhY2goIGV4aXN0aW5nQ29uc3RydWN0b3IuX2NoaWxkQ29uc3RydWN0b3JzLCBmdW5jdGlvbiggaSwgY2hpbGQgKSB7XG5cdFx0XHR2YXIgY2hpbGRQcm90b3R5cGUgPSBjaGlsZC5wcm90b3R5cGU7XG5cblx0XHRcdC8vIFJlZGVmaW5lIHRoZSBjaGlsZCB3aWRnZXQgdXNpbmcgdGhlIHNhbWUgcHJvdG90eXBlIHRoYXQgd2FzXG5cdFx0XHQvLyBvcmlnaW5hbGx5IHVzZWQsIGJ1dCBpbmhlcml0IGZyb20gdGhlIG5ldyB2ZXJzaW9uIG9mIHRoZSBiYXNlXG5cdFx0XHQkLndpZGdldCggY2hpbGRQcm90b3R5cGUubmFtZXNwYWNlICsgXCIuXCIgKyBjaGlsZFByb3RvdHlwZS53aWRnZXROYW1lLCBjb25zdHJ1Y3Rvcixcblx0XHRcdFx0Y2hpbGQuX3Byb3RvICk7XG5cdFx0fSApO1xuXG5cdFx0Ly8gUmVtb3ZlIHRoZSBsaXN0IG9mIGV4aXN0aW5nIGNoaWxkIGNvbnN0cnVjdG9ycyBmcm9tIHRoZSBvbGQgY29uc3RydWN0b3Jcblx0XHQvLyBzbyB0aGUgb2xkIGNoaWxkIGNvbnN0cnVjdG9ycyBjYW4gYmUgZ2FyYmFnZSBjb2xsZWN0ZWRcblx0XHRkZWxldGUgZXhpc3RpbmdDb25zdHJ1Y3Rvci5fY2hpbGRDb25zdHJ1Y3RvcnM7XG5cdH0gZWxzZSB7XG5cdFx0YmFzZS5fY2hpbGRDb25zdHJ1Y3RvcnMucHVzaCggY29uc3RydWN0b3IgKTtcblx0fVxuXG5cdCQud2lkZ2V0LmJyaWRnZSggbmFtZSwgY29uc3RydWN0b3IgKTtcblxuXHRyZXR1cm4gY29uc3RydWN0b3I7XG59O1xuXG4kLndpZGdldC5leHRlbmQgPSBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHR2YXIgaW5wdXQgPSB3aWRnZXRTbGljZS5jYWxsKCBhcmd1bWVudHMsIDEgKTtcblx0dmFyIGlucHV0SW5kZXggPSAwO1xuXHR2YXIgaW5wdXRMZW5ndGggPSBpbnB1dC5sZW5ndGg7XG5cdHZhciBrZXk7XG5cdHZhciB2YWx1ZTtcblxuXHRmb3IgKCA7IGlucHV0SW5kZXggPCBpbnB1dExlbmd0aDsgaW5wdXRJbmRleCsrICkge1xuXHRcdGZvciAoIGtleSBpbiBpbnB1dFsgaW5wdXRJbmRleCBdICkge1xuXHRcdFx0dmFsdWUgPSBpbnB1dFsgaW5wdXRJbmRleCBdWyBrZXkgXTtcblx0XHRcdGlmICggaW5wdXRbIGlucHV0SW5kZXggXS5oYXNPd25Qcm9wZXJ0eSgga2V5ICkgJiYgdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHQvLyBDbG9uZSBvYmplY3RzXG5cdFx0XHRcdGlmICggJC5pc1BsYWluT2JqZWN0KCB2YWx1ZSApICkge1xuXHRcdFx0XHRcdHRhcmdldFsga2V5IF0gPSAkLmlzUGxhaW5PYmplY3QoIHRhcmdldFsga2V5IF0gKSA/XG5cdFx0XHRcdFx0XHQkLndpZGdldC5leHRlbmQoIHt9LCB0YXJnZXRbIGtleSBdLCB2YWx1ZSApIDpcblxuXHRcdFx0XHRcdFx0Ly8gRG9uJ3QgZXh0ZW5kIHN0cmluZ3MsIGFycmF5cywgZXRjLiB3aXRoIG9iamVjdHNcblx0XHRcdFx0XHRcdCQud2lkZ2V0LmV4dGVuZCgge30sIHZhbHVlICk7XG5cblx0XHRcdFx0Ly8gQ29weSBldmVyeXRoaW5nIGVsc2UgYnkgcmVmZXJlbmNlXG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGFyZ2V0WyBrZXkgXSA9IHZhbHVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cdHJldHVybiB0YXJnZXQ7XG59O1xuXG4kLndpZGdldC5icmlkZ2UgPSBmdW5jdGlvbiggbmFtZSwgb2JqZWN0ICkge1xuXHR2YXIgZnVsbE5hbWUgPSBvYmplY3QucHJvdG90eXBlLndpZGdldEZ1bGxOYW1lIHx8IG5hbWU7XG5cdCQuZm5bIG5hbWUgXSA9IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXHRcdHZhciBpc01ldGhvZENhbGwgPSB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJzdHJpbmdcIjtcblx0XHR2YXIgYXJncyA9IHdpZGdldFNsaWNlLmNhbGwoIGFyZ3VtZW50cywgMSApO1xuXHRcdHZhciByZXR1cm5WYWx1ZSA9IHRoaXM7XG5cblx0XHRpZiAoIGlzTWV0aG9kQ2FsbCApIHtcblxuXHRcdFx0Ly8gSWYgdGhpcyBpcyBhbiBlbXB0eSBjb2xsZWN0aW9uLCB3ZSBuZWVkIHRvIGhhdmUgdGhlIGluc3RhbmNlIG1ldGhvZFxuXHRcdFx0Ly8gcmV0dXJuIHVuZGVmaW5lZCBpbnN0ZWFkIG9mIHRoZSBqUXVlcnkgaW5zdGFuY2Vcblx0XHRcdGlmICggIXRoaXMubGVuZ3RoICYmIG9wdGlvbnMgPT09IFwiaW5zdGFuY2VcIiApIHtcblx0XHRcdFx0cmV0dXJuVmFsdWUgPSB1bmRlZmluZWQ7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHZhciBtZXRob2RWYWx1ZTtcblx0XHRcdFx0XHR2YXIgaW5zdGFuY2UgPSAkLmRhdGEoIHRoaXMsIGZ1bGxOYW1lICk7XG5cblx0XHRcdFx0XHRpZiAoIG9wdGlvbnMgPT09IFwiaW5zdGFuY2VcIiApIHtcblx0XHRcdFx0XHRcdHJldHVyblZhbHVlID0gaW5zdGFuY2U7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCAhaW5zdGFuY2UgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gJC5lcnJvciggXCJjYW5ub3QgY2FsbCBtZXRob2RzIG9uIFwiICsgbmFtZSArXG5cdFx0XHRcdFx0XHRcdFwiIHByaW9yIHRvIGluaXRpYWxpemF0aW9uOyBcIiArXG5cdFx0XHRcdFx0XHRcdFwiYXR0ZW1wdGVkIHRvIGNhbGwgbWV0aG9kICdcIiArIG9wdGlvbnMgKyBcIidcIiApO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggISQuaXNGdW5jdGlvbiggaW5zdGFuY2VbIG9wdGlvbnMgXSApIHx8IG9wdGlvbnMuY2hhckF0KCAwICkgPT09IFwiX1wiICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuICQuZXJyb3IoIFwibm8gc3VjaCBtZXRob2QgJ1wiICsgb3B0aW9ucyArIFwiJyBmb3IgXCIgKyBuYW1lICtcblx0XHRcdFx0XHRcdFx0XCIgd2lkZ2V0IGluc3RhbmNlXCIgKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRtZXRob2RWYWx1ZSA9IGluc3RhbmNlWyBvcHRpb25zIF0uYXBwbHkoIGluc3RhbmNlLCBhcmdzICk7XG5cblx0XHRcdFx0XHRpZiAoIG1ldGhvZFZhbHVlICE9PSBpbnN0YW5jZSAmJiBtZXRob2RWYWx1ZSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuVmFsdWUgPSBtZXRob2RWYWx1ZSAmJiBtZXRob2RWYWx1ZS5qcXVlcnkgP1xuXHRcdFx0XHRcdFx0XHRyZXR1cm5WYWx1ZS5wdXNoU3RhY2soIG1ldGhvZFZhbHVlLmdldCgpICkgOlxuXHRcdFx0XHRcdFx0XHRtZXRob2RWYWx1ZTtcblx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBBbGxvdyBtdWx0aXBsZSBoYXNoZXMgdG8gYmUgcGFzc2VkIG9uIGluaXRcblx0XHRcdGlmICggYXJncy5sZW5ndGggKSB7XG5cdFx0XHRcdG9wdGlvbnMgPSAkLndpZGdldC5leHRlbmQuYXBwbHkoIG51bGwsIFsgb3B0aW9ucyBdLmNvbmNhdCggYXJncyApICk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBpbnN0YW5jZSA9ICQuZGF0YSggdGhpcywgZnVsbE5hbWUgKTtcblx0XHRcdFx0aWYgKCBpbnN0YW5jZSApIHtcblx0XHRcdFx0XHRpbnN0YW5jZS5vcHRpb24oIG9wdGlvbnMgfHwge30gKTtcblx0XHRcdFx0XHRpZiAoIGluc3RhbmNlLl9pbml0ICkge1xuXHRcdFx0XHRcdFx0aW5zdGFuY2UuX2luaXQoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0JC5kYXRhKCB0aGlzLCBmdWxsTmFtZSwgbmV3IG9iamVjdCggb3B0aW9ucywgdGhpcyApICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gcmV0dXJuVmFsdWU7XG5cdH07XG59O1xuXG4kLldpZGdldCA9IGZ1bmN0aW9uKCAvKiBvcHRpb25zLCBlbGVtZW50ICovICkge307XG4kLldpZGdldC5fY2hpbGRDb25zdHJ1Y3RvcnMgPSBbXTtcblxuJC5XaWRnZXQucHJvdG90eXBlID0ge1xuXHR3aWRnZXROYW1lOiBcIndpZGdldFwiLFxuXHR3aWRnZXRFdmVudFByZWZpeDogXCJcIixcblx0ZGVmYXVsdEVsZW1lbnQ6IFwiPGRpdj5cIixcblxuXHRvcHRpb25zOiB7XG5cdFx0Y2xhc3Nlczoge30sXG5cdFx0ZGlzYWJsZWQ6IGZhbHNlLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0Y3JlYXRlOiBudWxsXG5cdH0sXG5cblx0X2NyZWF0ZVdpZGdldDogZnVuY3Rpb24oIG9wdGlvbnMsIGVsZW1lbnQgKSB7XG5cdFx0ZWxlbWVudCA9ICQoIGVsZW1lbnQgfHwgdGhpcy5kZWZhdWx0RWxlbWVudCB8fCB0aGlzIClbIDAgXTtcblx0XHR0aGlzLmVsZW1lbnQgPSAkKCBlbGVtZW50ICk7XG5cdFx0dGhpcy51dWlkID0gd2lkZ2V0VXVpZCsrO1xuXHRcdHRoaXMuZXZlbnROYW1lc3BhY2UgPSBcIi5cIiArIHRoaXMud2lkZ2V0TmFtZSArIHRoaXMudXVpZDtcblxuXHRcdHRoaXMuYmluZGluZ3MgPSAkKCk7XG5cdFx0dGhpcy5ob3ZlcmFibGUgPSAkKCk7XG5cdFx0dGhpcy5mb2N1c2FibGUgPSAkKCk7XG5cdFx0dGhpcy5jbGFzc2VzRWxlbWVudExvb2t1cCA9IHt9O1xuXG5cdFx0aWYgKCBlbGVtZW50ICE9PSB0aGlzICkge1xuXHRcdFx0JC5kYXRhKCBlbGVtZW50LCB0aGlzLndpZGdldEZ1bGxOYW1lLCB0aGlzICk7XG5cdFx0XHR0aGlzLl9vbiggdHJ1ZSwgdGhpcy5lbGVtZW50LCB7XG5cdFx0XHRcdHJlbW92ZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRcdGlmICggZXZlbnQudGFyZ2V0ID09PSBlbGVtZW50ICkge1xuXHRcdFx0XHRcdFx0dGhpcy5kZXN0cm95KCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0XHR0aGlzLmRvY3VtZW50ID0gJCggZWxlbWVudC5zdHlsZSA/XG5cblx0XHRcdFx0Ly8gRWxlbWVudCB3aXRoaW4gdGhlIGRvY3VtZW50XG5cdFx0XHRcdGVsZW1lbnQub3duZXJEb2N1bWVudCA6XG5cblx0XHRcdFx0Ly8gRWxlbWVudCBpcyB3aW5kb3cgb3IgZG9jdW1lbnRcblx0XHRcdFx0ZWxlbWVudC5kb2N1bWVudCB8fCBlbGVtZW50ICk7XG5cdFx0XHR0aGlzLndpbmRvdyA9ICQoIHRoaXMuZG9jdW1lbnRbIDAgXS5kZWZhdWx0VmlldyB8fCB0aGlzLmRvY3VtZW50WyAwIF0ucGFyZW50V2luZG93ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5vcHRpb25zID0gJC53aWRnZXQuZXh0ZW5kKCB7fSxcblx0XHRcdHRoaXMub3B0aW9ucyxcblx0XHRcdHRoaXMuX2dldENyZWF0ZU9wdGlvbnMoKSxcblx0XHRcdG9wdGlvbnMgKTtcblxuXHRcdHRoaXMuX2NyZWF0ZSgpO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHR0aGlzLl9zZXRPcHRpb25EaXNhYmxlZCggdGhpcy5vcHRpb25zLmRpc2FibGVkICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJjcmVhdGVcIiwgbnVsbCwgdGhpcy5fZ2V0Q3JlYXRlRXZlbnREYXRhKCkgKTtcblx0XHR0aGlzLl9pbml0KCk7XG5cdH0sXG5cblx0X2dldENyZWF0ZU9wdGlvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB7fTtcblx0fSxcblxuXHRfZ2V0Q3JlYXRlRXZlbnREYXRhOiAkLm5vb3AsXG5cblx0X2NyZWF0ZTogJC5ub29wLFxuXG5cdF9pbml0OiAkLm5vb3AsXG5cblx0ZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0dGhpcy5fZGVzdHJveSgpO1xuXHRcdCQuZWFjaCggdGhpcy5jbGFzc2VzRWxlbWVudExvb2t1cCwgZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggdmFsdWUsIGtleSApO1xuXHRcdH0gKTtcblxuXHRcdC8vIFdlIGNhbiBwcm9iYWJseSByZW1vdmUgdGhlIHVuYmluZCBjYWxscyBpbiAyLjBcblx0XHQvLyBhbGwgZXZlbnQgYmluZGluZ3Mgc2hvdWxkIGdvIHRocm91Z2ggdGhpcy5fb24oKVxuXHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0Lm9mZiggdGhpcy5ldmVudE5hbWVzcGFjZSApXG5cdFx0XHQucmVtb3ZlRGF0YSggdGhpcy53aWRnZXRGdWxsTmFtZSApO1xuXHRcdHRoaXMud2lkZ2V0KClcblx0XHRcdC5vZmYoIHRoaXMuZXZlbnROYW1lc3BhY2UgKVxuXHRcdFx0LnJlbW92ZUF0dHIoIFwiYXJpYS1kaXNhYmxlZFwiICk7XG5cblx0XHQvLyBDbGVhbiB1cCBldmVudHMgYW5kIHN0YXRlc1xuXHRcdHRoaXMuYmluZGluZ3Mub2ZmKCB0aGlzLmV2ZW50TmFtZXNwYWNlICk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6ICQubm9vcCxcblxuXHR3aWRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmVsZW1lbnQ7XG5cdH0sXG5cblx0b3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHR2YXIgb3B0aW9ucyA9IGtleTtcblx0XHR2YXIgcGFydHM7XG5cdFx0dmFyIGN1ck9wdGlvbjtcblx0XHR2YXIgaTtcblxuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCA9PT0gMCApIHtcblxuXHRcdFx0Ly8gRG9uJ3QgcmV0dXJuIGEgcmVmZXJlbmNlIHRvIHRoZSBpbnRlcm5hbCBoYXNoXG5cdFx0XHRyZXR1cm4gJC53aWRnZXQuZXh0ZW5kKCB7fSwgdGhpcy5vcHRpb25zICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0eXBlb2Yga2V5ID09PSBcInN0cmluZ1wiICkge1xuXG5cdFx0XHQvLyBIYW5kbGUgbmVzdGVkIGtleXMsIGUuZy4sIFwiZm9vLmJhclwiID0+IHsgZm9vOiB7IGJhcjogX19fIH0gfVxuXHRcdFx0b3B0aW9ucyA9IHt9O1xuXHRcdFx0cGFydHMgPSBrZXkuc3BsaXQoIFwiLlwiICk7XG5cdFx0XHRrZXkgPSBwYXJ0cy5zaGlmdCgpO1xuXHRcdFx0aWYgKCBwYXJ0cy5sZW5ndGggKSB7XG5cdFx0XHRcdGN1ck9wdGlvbiA9IG9wdGlvbnNbIGtleSBdID0gJC53aWRnZXQuZXh0ZW5kKCB7fSwgdGhpcy5vcHRpb25zWyBrZXkgXSApO1xuXHRcdFx0XHRmb3IgKCBpID0gMDsgaSA8IHBhcnRzLmxlbmd0aCAtIDE7IGkrKyApIHtcblx0XHRcdFx0XHRjdXJPcHRpb25bIHBhcnRzWyBpIF0gXSA9IGN1ck9wdGlvblsgcGFydHNbIGkgXSBdIHx8IHt9O1xuXHRcdFx0XHRcdGN1ck9wdGlvbiA9IGN1ck9wdGlvblsgcGFydHNbIGkgXSBdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGtleSA9IHBhcnRzLnBvcCgpO1xuXHRcdFx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggPT09IDEgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGN1ck9wdGlvblsga2V5IF0gPT09IHVuZGVmaW5lZCA/IG51bGwgOiBjdXJPcHRpb25bIGtleSBdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGN1ck9wdGlvblsga2V5IF0gPSB2YWx1ZTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCA9PT0gMSApIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5vcHRpb25zWyBrZXkgXSA9PT0gdW5kZWZpbmVkID8gbnVsbCA6IHRoaXMub3B0aW9uc1sga2V5IF07XG5cdFx0XHRcdH1cblx0XHRcdFx0b3B0aW9uc1sga2V5IF0gPSB2YWx1ZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLl9zZXRPcHRpb25zKCBvcHRpb25zICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRfc2V0T3B0aW9uczogZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdFx0dmFyIGtleTtcblxuXHRcdGZvciAoIGtleSBpbiBvcHRpb25zICkge1xuXHRcdFx0dGhpcy5fc2V0T3B0aW9uKCBrZXksIG9wdGlvbnNbIGtleSBdICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0aWYgKCBrZXkgPT09IFwiY2xhc3Nlc1wiICkge1xuXHRcdFx0dGhpcy5fc2V0T3B0aW9uQ2xhc3NlcyggdmFsdWUgKTtcblx0XHR9XG5cblx0XHR0aGlzLm9wdGlvbnNbIGtleSBdID0gdmFsdWU7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJkaXNhYmxlZFwiICkge1xuXHRcdFx0dGhpcy5fc2V0T3B0aW9uRGlzYWJsZWQoIHZhbHVlICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X3NldE9wdGlvbkNsYXNzZXM6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR2YXIgY2xhc3NLZXksIGVsZW1lbnRzLCBjdXJyZW50RWxlbWVudHM7XG5cblx0XHRmb3IgKCBjbGFzc0tleSBpbiB2YWx1ZSApIHtcblx0XHRcdGN1cnJlbnRFbGVtZW50cyA9IHRoaXMuY2xhc3Nlc0VsZW1lbnRMb29rdXBbIGNsYXNzS2V5IF07XG5cdFx0XHRpZiAoIHZhbHVlWyBjbGFzc0tleSBdID09PSB0aGlzLm9wdGlvbnMuY2xhc3Nlc1sgY2xhc3NLZXkgXSB8fFxuXHRcdFx0XHRcdCFjdXJyZW50RWxlbWVudHMgfHxcblx0XHRcdFx0XHQhY3VycmVudEVsZW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFdlIGFyZSBkb2luZyB0aGlzIHRvIGNyZWF0ZSBhIG5ldyBqUXVlcnkgb2JqZWN0IGJlY2F1c2UgdGhlIF9yZW1vdmVDbGFzcygpIGNhbGxcblx0XHRcdC8vIG9uIHRoZSBuZXh0IGxpbmUgaXMgZ29pbmcgdG8gZGVzdHJveSB0aGUgcmVmZXJlbmNlIHRvIHRoZSBjdXJyZW50IGVsZW1lbnRzIGJlaW5nXG5cdFx0XHQvLyB0cmFja2VkLiBXZSBuZWVkIHRvIHNhdmUgYSBjb3B5IG9mIHRoaXMgY29sbGVjdGlvbiBzbyB0aGF0IHdlIGNhbiBhZGQgdGhlIG5ldyBjbGFzc2VzXG5cdFx0XHQvLyBiZWxvdy5cblx0XHRcdGVsZW1lbnRzID0gJCggY3VycmVudEVsZW1lbnRzLmdldCgpICk7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggY3VycmVudEVsZW1lbnRzLCBjbGFzc0tleSApO1xuXG5cdFx0XHQvLyBXZSBkb24ndCB1c2UgX2FkZENsYXNzKCkgaGVyZSwgYmVjYXVzZSB0aGF0IHVzZXMgdGhpcy5vcHRpb25zLmNsYXNzZXNcblx0XHRcdC8vIGZvciBnZW5lcmF0aW5nIHRoZSBzdHJpbmcgb2YgY2xhc3Nlcy4gV2Ugd2FudCB0byB1c2UgdGhlIHZhbHVlIHBhc3NlZCBpbiBmcm9tXG5cdFx0XHQvLyBfc2V0T3B0aW9uKCksIHRoaXMgaXMgdGhlIG5ldyB2YWx1ZSBvZiB0aGUgY2xhc3NlcyBvcHRpb24gd2hpY2ggd2FzIHBhc3NlZCB0b1xuXHRcdFx0Ly8gX3NldE9wdGlvbigpLiBXZSBwYXNzIHRoaXMgdmFsdWUgZGlyZWN0bHkgdG8gX2NsYXNzZXMoKS5cblx0XHRcdGVsZW1lbnRzLmFkZENsYXNzKCB0aGlzLl9jbGFzc2VzKCB7XG5cdFx0XHRcdGVsZW1lbnQ6IGVsZW1lbnRzLFxuXHRcdFx0XHRrZXlzOiBjbGFzc0tleSxcblx0XHRcdFx0Y2xhc3NlczogdmFsdWUsXG5cdFx0XHRcdGFkZDogdHJ1ZVxuXHRcdFx0fSApICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb25EaXNhYmxlZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCB0aGlzLndpZGdldCgpLCB0aGlzLndpZGdldEZ1bGxOYW1lICsgXCItZGlzYWJsZWRcIiwgbnVsbCwgISF2YWx1ZSApO1xuXG5cdFx0Ly8gSWYgdGhlIHdpZGdldCBpcyBiZWNvbWluZyBkaXNhYmxlZCwgdGhlbiBub3RoaW5nIGlzIGludGVyYWN0aXZlXG5cdFx0aWYgKCB2YWx1ZSApIHtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmhvdmVyYWJsZSwgbnVsbCwgXCJ1aS1zdGF0ZS1ob3ZlclwiICk7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5mb2N1c2FibGUsIG51bGwsIFwidWktc3RhdGUtZm9jdXNcIiApO1xuXHRcdH1cblx0fSxcblxuXHRlbmFibGU6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLl9zZXRPcHRpb25zKCB7IGRpc2FibGVkOiBmYWxzZSB9ICk7XG5cdH0sXG5cblx0ZGlzYWJsZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3NldE9wdGlvbnMoIHsgZGlzYWJsZWQ6IHRydWUgfSApO1xuXHR9LFxuXG5cdF9jbGFzc2VzOiBmdW5jdGlvbiggb3B0aW9ucyApIHtcblx0XHR2YXIgZnVsbCA9IFtdO1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdG9wdGlvbnMgPSAkLmV4dGVuZCgge1xuXHRcdFx0ZWxlbWVudDogdGhpcy5lbGVtZW50LFxuXHRcdFx0Y2xhc3NlczogdGhpcy5vcHRpb25zLmNsYXNzZXMgfHwge31cblx0XHR9LCBvcHRpb25zICk7XG5cblx0XHRmdW5jdGlvbiBwcm9jZXNzQ2xhc3NTdHJpbmcoIGNsYXNzZXMsIGNoZWNrT3B0aW9uICkge1xuXHRcdFx0dmFyIGN1cnJlbnQsIGk7XG5cdFx0XHRmb3IgKCBpID0gMDsgaSA8IGNsYXNzZXMubGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRcdGN1cnJlbnQgPSB0aGF0LmNsYXNzZXNFbGVtZW50TG9va3VwWyBjbGFzc2VzWyBpIF0gXSB8fCAkKCk7XG5cdFx0XHRcdGlmICggb3B0aW9ucy5hZGQgKSB7XG5cdFx0XHRcdFx0Y3VycmVudCA9ICQoICQudW5pcXVlKCBjdXJyZW50LmdldCgpLmNvbmNhdCggb3B0aW9ucy5lbGVtZW50LmdldCgpICkgKSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGN1cnJlbnQgPSAkKCBjdXJyZW50Lm5vdCggb3B0aW9ucy5lbGVtZW50ICkuZ2V0KCkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGF0LmNsYXNzZXNFbGVtZW50TG9va3VwWyBjbGFzc2VzWyBpIF0gXSA9IGN1cnJlbnQ7XG5cdFx0XHRcdGZ1bGwucHVzaCggY2xhc3Nlc1sgaSBdICk7XG5cdFx0XHRcdGlmICggY2hlY2tPcHRpb24gJiYgb3B0aW9ucy5jbGFzc2VzWyBjbGFzc2VzWyBpIF0gXSApIHtcblx0XHRcdFx0XHRmdWxsLnB1c2goIG9wdGlvbnMuY2xhc3Nlc1sgY2xhc3Nlc1sgaSBdIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuX29uKCBvcHRpb25zLmVsZW1lbnQsIHtcblx0XHRcdFwicmVtb3ZlXCI6IFwiX3VudHJhY2tDbGFzc2VzRWxlbWVudFwiXG5cdFx0fSApO1xuXG5cdFx0aWYgKCBvcHRpb25zLmtleXMgKSB7XG5cdFx0XHRwcm9jZXNzQ2xhc3NTdHJpbmcoIG9wdGlvbnMua2V5cy5tYXRjaCggL1xcUysvZyApIHx8IFtdLCB0cnVlICk7XG5cdFx0fVxuXHRcdGlmICggb3B0aW9ucy5leHRyYSApIHtcblx0XHRcdHByb2Nlc3NDbGFzc1N0cmluZyggb3B0aW9ucy5leHRyYS5tYXRjaCggL1xcUysvZyApIHx8IFtdICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZ1bGwuam9pbiggXCIgXCIgKTtcblx0fSxcblxuXHRfdW50cmFja0NsYXNzZXNFbGVtZW50OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXHRcdCQuZWFjaCggdGhhdC5jbGFzc2VzRWxlbWVudExvb2t1cCwgZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0XHRpZiAoICQuaW5BcnJheSggZXZlbnQudGFyZ2V0LCB2YWx1ZSApICE9PSAtMSApIHtcblx0XHRcdFx0dGhhdC5jbGFzc2VzRWxlbWVudExvb2t1cFsga2V5IF0gPSAkKCB2YWx1ZS5ub3QoIGV2ZW50LnRhcmdldCApLmdldCgpICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9yZW1vdmVDbGFzczogZnVuY3Rpb24oIGVsZW1lbnQsIGtleXMsIGV4dHJhICkge1xuXHRcdHJldHVybiB0aGlzLl90b2dnbGVDbGFzcyggZWxlbWVudCwga2V5cywgZXh0cmEsIGZhbHNlICk7XG5cdH0sXG5cblx0X2FkZENsYXNzOiBmdW5jdGlvbiggZWxlbWVudCwga2V5cywgZXh0cmEgKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3RvZ2dsZUNsYXNzKCBlbGVtZW50LCBrZXlzLCBleHRyYSwgdHJ1ZSApO1xuXHR9LFxuXG5cdF90b2dnbGVDbGFzczogZnVuY3Rpb24oIGVsZW1lbnQsIGtleXMsIGV4dHJhLCBhZGQgKSB7XG5cdFx0YWRkID0gKCB0eXBlb2YgYWRkID09PSBcImJvb2xlYW5cIiApID8gYWRkIDogZXh0cmE7XG5cdFx0dmFyIHNoaWZ0ID0gKCB0eXBlb2YgZWxlbWVudCA9PT0gXCJzdHJpbmdcIiB8fCBlbGVtZW50ID09PSBudWxsICksXG5cdFx0XHRvcHRpb25zID0ge1xuXHRcdFx0XHRleHRyYTogc2hpZnQgPyBrZXlzIDogZXh0cmEsXG5cdFx0XHRcdGtleXM6IHNoaWZ0ID8gZWxlbWVudCA6IGtleXMsXG5cdFx0XHRcdGVsZW1lbnQ6IHNoaWZ0ID8gdGhpcy5lbGVtZW50IDogZWxlbWVudCxcblx0XHRcdFx0YWRkOiBhZGRcblx0XHRcdH07XG5cdFx0b3B0aW9ucy5lbGVtZW50LnRvZ2dsZUNsYXNzKCB0aGlzLl9jbGFzc2VzKCBvcHRpb25zICksIGFkZCApO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9vbjogZnVuY3Rpb24oIHN1cHByZXNzRGlzYWJsZWRDaGVjaywgZWxlbWVudCwgaGFuZGxlcnMgKSB7XG5cdFx0dmFyIGRlbGVnYXRlRWxlbWVudDtcblx0XHR2YXIgaW5zdGFuY2UgPSB0aGlzO1xuXG5cdFx0Ly8gTm8gc3VwcHJlc3NEaXNhYmxlZENoZWNrIGZsYWcsIHNodWZmbGUgYXJndW1lbnRzXG5cdFx0aWYgKCB0eXBlb2Ygc3VwcHJlc3NEaXNhYmxlZENoZWNrICE9PSBcImJvb2xlYW5cIiApIHtcblx0XHRcdGhhbmRsZXJzID0gZWxlbWVudDtcblx0XHRcdGVsZW1lbnQgPSBzdXBwcmVzc0Rpc2FibGVkQ2hlY2s7XG5cdFx0XHRzdXBwcmVzc0Rpc2FibGVkQ2hlY2sgPSBmYWxzZTtcblx0XHR9XG5cblx0XHQvLyBObyBlbGVtZW50IGFyZ3VtZW50LCBzaHVmZmxlIGFuZCB1c2UgdGhpcy5lbGVtZW50XG5cdFx0aWYgKCAhaGFuZGxlcnMgKSB7XG5cdFx0XHRoYW5kbGVycyA9IGVsZW1lbnQ7XG5cdFx0XHRlbGVtZW50ID0gdGhpcy5lbGVtZW50O1xuXHRcdFx0ZGVsZWdhdGVFbGVtZW50ID0gdGhpcy53aWRnZXQoKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZWxlbWVudCA9IGRlbGVnYXRlRWxlbWVudCA9ICQoIGVsZW1lbnQgKTtcblx0XHRcdHRoaXMuYmluZGluZ3MgPSB0aGlzLmJpbmRpbmdzLmFkZCggZWxlbWVudCApO1xuXHRcdH1cblxuXHRcdCQuZWFjaCggaGFuZGxlcnMsIGZ1bmN0aW9uKCBldmVudCwgaGFuZGxlciApIHtcblx0XHRcdGZ1bmN0aW9uIGhhbmRsZXJQcm94eSgpIHtcblxuXHRcdFx0XHQvLyBBbGxvdyB3aWRnZXRzIHRvIGN1c3RvbWl6ZSB0aGUgZGlzYWJsZWQgaGFuZGxpbmdcblx0XHRcdFx0Ly8gLSBkaXNhYmxlZCBhcyBhbiBhcnJheSBpbnN0ZWFkIG9mIGJvb2xlYW5cblx0XHRcdFx0Ly8gLSBkaXNhYmxlZCBjbGFzcyBhcyBtZXRob2QgZm9yIGRpc2FibGluZyBpbmRpdmlkdWFsIHBhcnRzXG5cdFx0XHRcdGlmICggIXN1cHByZXNzRGlzYWJsZWRDaGVjayAmJlxuXHRcdFx0XHRcdFx0KCBpbnN0YW5jZS5vcHRpb25zLmRpc2FibGVkID09PSB0cnVlIHx8XG5cdFx0XHRcdFx0XHQkKCB0aGlzICkuaGFzQ2xhc3MoIFwidWktc3RhdGUtZGlzYWJsZWRcIiApICkgKSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiAoIHR5cGVvZiBoYW5kbGVyID09PSBcInN0cmluZ1wiID8gaW5zdGFuY2VbIGhhbmRsZXIgXSA6IGhhbmRsZXIgKVxuXHRcdFx0XHRcdC5hcHBseSggaW5zdGFuY2UsIGFyZ3VtZW50cyApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDb3B5IHRoZSBndWlkIHNvIGRpcmVjdCB1bmJpbmRpbmcgd29ya3Ncblx0XHRcdGlmICggdHlwZW9mIGhhbmRsZXIgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdGhhbmRsZXJQcm94eS5ndWlkID0gaGFuZGxlci5ndWlkID1cblx0XHRcdFx0XHRoYW5kbGVyLmd1aWQgfHwgaGFuZGxlclByb3h5Lmd1aWQgfHwgJC5ndWlkKys7XG5cdFx0XHR9XG5cblx0XHRcdHZhciBtYXRjaCA9IGV2ZW50Lm1hdGNoKCAvXihbXFx3Oi1dKilcXHMqKC4qKSQvICk7XG5cdFx0XHR2YXIgZXZlbnROYW1lID0gbWF0Y2hbIDEgXSArIGluc3RhbmNlLmV2ZW50TmFtZXNwYWNlO1xuXHRcdFx0dmFyIHNlbGVjdG9yID0gbWF0Y2hbIDIgXTtcblxuXHRcdFx0aWYgKCBzZWxlY3RvciApIHtcblx0XHRcdFx0ZGVsZWdhdGVFbGVtZW50Lm9uKCBldmVudE5hbWUsIHNlbGVjdG9yLCBoYW5kbGVyUHJveHkgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGVsZW1lbnQub24oIGV2ZW50TmFtZSwgaGFuZGxlclByb3h5ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9vZmY6IGZ1bmN0aW9uKCBlbGVtZW50LCBldmVudE5hbWUgKSB7XG5cdFx0ZXZlbnROYW1lID0gKCBldmVudE5hbWUgfHwgXCJcIiApLnNwbGl0KCBcIiBcIiApLmpvaW4oIHRoaXMuZXZlbnROYW1lc3BhY2UgKyBcIiBcIiApICtcblx0XHRcdHRoaXMuZXZlbnROYW1lc3BhY2U7XG5cdFx0ZWxlbWVudC5vZmYoIGV2ZW50TmFtZSApLm9mZiggZXZlbnROYW1lICk7XG5cblx0XHQvLyBDbGVhciB0aGUgc3RhY2sgdG8gYXZvaWQgbWVtb3J5IGxlYWtzICgjMTAwNTYpXG5cdFx0dGhpcy5iaW5kaW5ncyA9ICQoIHRoaXMuYmluZGluZ3Mubm90KCBlbGVtZW50ICkuZ2V0KCkgKTtcblx0XHR0aGlzLmZvY3VzYWJsZSA9ICQoIHRoaXMuZm9jdXNhYmxlLm5vdCggZWxlbWVudCApLmdldCgpICk7XG5cdFx0dGhpcy5ob3ZlcmFibGUgPSAkKCB0aGlzLmhvdmVyYWJsZS5ub3QoIGVsZW1lbnQgKS5nZXQoKSApO1xuXHR9LFxuXG5cdF9kZWxheTogZnVuY3Rpb24oIGhhbmRsZXIsIGRlbGF5ICkge1xuXHRcdGZ1bmN0aW9uIGhhbmRsZXJQcm94eSgpIHtcblx0XHRcdHJldHVybiAoIHR5cGVvZiBoYW5kbGVyID09PSBcInN0cmluZ1wiID8gaW5zdGFuY2VbIGhhbmRsZXIgXSA6IGhhbmRsZXIgKVxuXHRcdFx0XHQuYXBwbHkoIGluc3RhbmNlLCBhcmd1bWVudHMgKTtcblx0XHR9XG5cdFx0dmFyIGluc3RhbmNlID0gdGhpcztcblx0XHRyZXR1cm4gc2V0VGltZW91dCggaGFuZGxlclByb3h5LCBkZWxheSB8fCAwICk7XG5cdH0sXG5cblx0X2hvdmVyYWJsZTogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0dGhpcy5ob3ZlcmFibGUgPSB0aGlzLmhvdmVyYWJsZS5hZGQoIGVsZW1lbnQgKTtcblx0XHR0aGlzLl9vbiggZWxlbWVudCwge1xuXHRcdFx0bW91c2VlbnRlcjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggJCggZXZlbnQuY3VycmVudFRhcmdldCApLCBudWxsLCBcInVpLXN0YXRlLWhvdmVyXCIgKTtcblx0XHRcdH0sXG5cdFx0XHRtb3VzZWxlYXZlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCAkKCBldmVudC5jdXJyZW50VGFyZ2V0ICksIG51bGwsIFwidWktc3RhdGUtaG92ZXJcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfZm9jdXNhYmxlOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHR0aGlzLmZvY3VzYWJsZSA9IHRoaXMuZm9jdXNhYmxlLmFkZCggZWxlbWVudCApO1xuXHRcdHRoaXMuX29uKCBlbGVtZW50LCB7XG5cdFx0XHRmb2N1c2luOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCAkKCBldmVudC5jdXJyZW50VGFyZ2V0ICksIG51bGwsIFwidWktc3RhdGUtZm9jdXNcIiApO1xuXHRcdFx0fSxcblx0XHRcdGZvY3Vzb3V0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCAkKCBldmVudC5jdXJyZW50VGFyZ2V0ICksIG51bGwsIFwidWktc3RhdGUtZm9jdXNcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfdHJpZ2dlcjogZnVuY3Rpb24oIHR5cGUsIGV2ZW50LCBkYXRhICkge1xuXHRcdHZhciBwcm9wLCBvcmlnO1xuXHRcdHZhciBjYWxsYmFjayA9IHRoaXMub3B0aW9uc1sgdHlwZSBdO1xuXG5cdFx0ZGF0YSA9IGRhdGEgfHwge307XG5cdFx0ZXZlbnQgPSAkLkV2ZW50KCBldmVudCApO1xuXHRcdGV2ZW50LnR5cGUgPSAoIHR5cGUgPT09IHRoaXMud2lkZ2V0RXZlbnRQcmVmaXggP1xuXHRcdFx0dHlwZSA6XG5cdFx0XHR0aGlzLndpZGdldEV2ZW50UHJlZml4ICsgdHlwZSApLnRvTG93ZXJDYXNlKCk7XG5cblx0XHQvLyBUaGUgb3JpZ2luYWwgZXZlbnQgbWF5IGNvbWUgZnJvbSBhbnkgZWxlbWVudFxuXHRcdC8vIHNvIHdlIG5lZWQgdG8gcmVzZXQgdGhlIHRhcmdldCBvbiB0aGUgbmV3IGV2ZW50XG5cdFx0ZXZlbnQudGFyZ2V0ID0gdGhpcy5lbGVtZW50WyAwIF07XG5cblx0XHQvLyBDb3B5IG9yaWdpbmFsIGV2ZW50IHByb3BlcnRpZXMgb3ZlciB0byB0aGUgbmV3IGV2ZW50XG5cdFx0b3JpZyA9IGV2ZW50Lm9yaWdpbmFsRXZlbnQ7XG5cdFx0aWYgKCBvcmlnICkge1xuXHRcdFx0Zm9yICggcHJvcCBpbiBvcmlnICkge1xuXHRcdFx0XHRpZiAoICEoIHByb3AgaW4gZXZlbnQgKSApIHtcblx0XHRcdFx0XHRldmVudFsgcHJvcCBdID0gb3JpZ1sgcHJvcCBdO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5lbGVtZW50LnRyaWdnZXIoIGV2ZW50LCBkYXRhICk7XG5cdFx0cmV0dXJuICEoICQuaXNGdW5jdGlvbiggY2FsbGJhY2sgKSAmJlxuXHRcdFx0Y2FsbGJhY2suYXBwbHkoIHRoaXMuZWxlbWVudFsgMCBdLCBbIGV2ZW50IF0uY29uY2F0KCBkYXRhICkgKSA9PT0gZmFsc2UgfHxcblx0XHRcdGV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpICk7XG5cdH1cbn07XG5cbiQuZWFjaCggeyBzaG93OiBcImZhZGVJblwiLCBoaWRlOiBcImZhZGVPdXRcIiB9LCBmdW5jdGlvbiggbWV0aG9kLCBkZWZhdWx0RWZmZWN0ICkge1xuXHQkLldpZGdldC5wcm90b3R5cGVbIFwiX1wiICsgbWV0aG9kIF0gPSBmdW5jdGlvbiggZWxlbWVudCwgb3B0aW9ucywgY2FsbGJhY2sgKSB7XG5cdFx0aWYgKCB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdG9wdGlvbnMgPSB7IGVmZmVjdDogb3B0aW9ucyB9O1xuXHRcdH1cblxuXHRcdHZhciBoYXNPcHRpb25zO1xuXHRcdHZhciBlZmZlY3ROYW1lID0gIW9wdGlvbnMgP1xuXHRcdFx0bWV0aG9kIDpcblx0XHRcdG9wdGlvbnMgPT09IHRydWUgfHwgdHlwZW9mIG9wdGlvbnMgPT09IFwibnVtYmVyXCIgP1xuXHRcdFx0XHRkZWZhdWx0RWZmZWN0IDpcblx0XHRcdFx0b3B0aW9ucy5lZmZlY3QgfHwgZGVmYXVsdEVmZmVjdDtcblxuXHRcdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXHRcdGlmICggdHlwZW9mIG9wdGlvbnMgPT09IFwibnVtYmVyXCIgKSB7XG5cdFx0XHRvcHRpb25zID0geyBkdXJhdGlvbjogb3B0aW9ucyB9O1xuXHRcdH1cblxuXHRcdGhhc09wdGlvbnMgPSAhJC5pc0VtcHR5T2JqZWN0KCBvcHRpb25zICk7XG5cdFx0b3B0aW9ucy5jb21wbGV0ZSA9IGNhbGxiYWNrO1xuXG5cdFx0aWYgKCBvcHRpb25zLmRlbGF5ICkge1xuXHRcdFx0ZWxlbWVudC5kZWxheSggb3B0aW9ucy5kZWxheSApO1xuXHRcdH1cblxuXHRcdGlmICggaGFzT3B0aW9ucyAmJiAkLmVmZmVjdHMgJiYgJC5lZmZlY3RzLmVmZmVjdFsgZWZmZWN0TmFtZSBdICkge1xuXHRcdFx0ZWxlbWVudFsgbWV0aG9kIF0oIG9wdGlvbnMgKTtcblx0XHR9IGVsc2UgaWYgKCBlZmZlY3ROYW1lICE9PSBtZXRob2QgJiYgZWxlbWVudFsgZWZmZWN0TmFtZSBdICkge1xuXHRcdFx0ZWxlbWVudFsgZWZmZWN0TmFtZSBdKCBvcHRpb25zLmR1cmF0aW9uLCBvcHRpb25zLmVhc2luZywgY2FsbGJhY2sgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZWxlbWVudC5xdWV1ZSggZnVuY3Rpb24oIG5leHQgKSB7XG5cdFx0XHRcdCQoIHRoaXMgKVsgbWV0aG9kIF0oKTtcblx0XHRcdFx0aWYgKCBjYWxsYmFjayApIHtcblx0XHRcdFx0XHRjYWxsYmFjay5jYWxsKCBlbGVtZW50WyAwIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRuZXh0KCk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9O1xufSApO1xuXG52YXIgd2lkZ2V0ID0gJC53aWRnZXQ7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgUG9zaXRpb24gMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqXG4gKiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9wb3NpdGlvbi9cbiAqL1xuXG4vLz4+bGFiZWw6IFBvc2l0aW9uXG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogUG9zaXRpb25zIGVsZW1lbnRzIHJlbGF0aXZlIHRvIG90aGVyIGVsZW1lbnRzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3Bvc2l0aW9uL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3Bvc2l0aW9uL1xuXG5cbiggZnVuY3Rpb24oKSB7XG52YXIgY2FjaGVkU2Nyb2xsYmFyV2lkdGgsXG5cdG1heCA9IE1hdGgubWF4LFxuXHRhYnMgPSBNYXRoLmFicyxcblx0cmhvcml6b250YWwgPSAvbGVmdHxjZW50ZXJ8cmlnaHQvLFxuXHRydmVydGljYWwgPSAvdG9wfGNlbnRlcnxib3R0b20vLFxuXHRyb2Zmc2V0ID0gL1tcXCtcXC1dXFxkKyhcXC5bXFxkXSspPyU/Lyxcblx0cnBvc2l0aW9uID0gL15cXHcrLyxcblx0cnBlcmNlbnQgPSAvJSQvLFxuXHRfcG9zaXRpb24gPSAkLmZuLnBvc2l0aW9uO1xuXG5mdW5jdGlvbiBnZXRPZmZzZXRzKCBvZmZzZXRzLCB3aWR0aCwgaGVpZ2h0ICkge1xuXHRyZXR1cm4gW1xuXHRcdHBhcnNlRmxvYXQoIG9mZnNldHNbIDAgXSApICogKCBycGVyY2VudC50ZXN0KCBvZmZzZXRzWyAwIF0gKSA/IHdpZHRoIC8gMTAwIDogMSApLFxuXHRcdHBhcnNlRmxvYXQoIG9mZnNldHNbIDEgXSApICogKCBycGVyY2VudC50ZXN0KCBvZmZzZXRzWyAxIF0gKSA/IGhlaWdodCAvIDEwMCA6IDEgKVxuXHRdO1xufVxuXG5mdW5jdGlvbiBwYXJzZUNzcyggZWxlbWVudCwgcHJvcGVydHkgKSB7XG5cdHJldHVybiBwYXJzZUludCggJC5jc3MoIGVsZW1lbnQsIHByb3BlcnR5ICksIDEwICkgfHwgMDtcbn1cblxuZnVuY3Rpb24gZ2V0RGltZW5zaW9ucyggZWxlbSApIHtcblx0dmFyIHJhdyA9IGVsZW1bIDAgXTtcblx0aWYgKCByYXcubm9kZVR5cGUgPT09IDkgKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHdpZHRoOiBlbGVtLndpZHRoKCksXG5cdFx0XHRoZWlnaHQ6IGVsZW0uaGVpZ2h0KCksXG5cdFx0XHRvZmZzZXQ6IHsgdG9wOiAwLCBsZWZ0OiAwIH1cblx0XHR9O1xuXHR9XG5cdGlmICggJC5pc1dpbmRvdyggcmF3ICkgKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHdpZHRoOiBlbGVtLndpZHRoKCksXG5cdFx0XHRoZWlnaHQ6IGVsZW0uaGVpZ2h0KCksXG5cdFx0XHRvZmZzZXQ6IHsgdG9wOiBlbGVtLnNjcm9sbFRvcCgpLCBsZWZ0OiBlbGVtLnNjcm9sbExlZnQoKSB9XG5cdFx0fTtcblx0fVxuXHRpZiAoIHJhdy5wcmV2ZW50RGVmYXVsdCApIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0d2lkdGg6IDAsXG5cdFx0XHRoZWlnaHQ6IDAsXG5cdFx0XHRvZmZzZXQ6IHsgdG9wOiByYXcucGFnZVksIGxlZnQ6IHJhdy5wYWdlWCB9XG5cdFx0fTtcblx0fVxuXHRyZXR1cm4ge1xuXHRcdHdpZHRoOiBlbGVtLm91dGVyV2lkdGgoKSxcblx0XHRoZWlnaHQ6IGVsZW0ub3V0ZXJIZWlnaHQoKSxcblx0XHRvZmZzZXQ6IGVsZW0ub2Zmc2V0KClcblx0fTtcbn1cblxuJC5wb3NpdGlvbiA9IHtcblx0c2Nyb2xsYmFyV2lkdGg6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggY2FjaGVkU2Nyb2xsYmFyV2lkdGggIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHJldHVybiBjYWNoZWRTY3JvbGxiYXJXaWR0aDtcblx0XHR9XG5cdFx0dmFyIHcxLCB3Mixcblx0XHRcdGRpdiA9ICQoIFwiPGRpdiBcIiArXG5cdFx0XHRcdFwic3R5bGU9J2Rpc3BsYXk6YmxvY2s7cG9zaXRpb246YWJzb2x1dGU7d2lkdGg6NTBweDtoZWlnaHQ6NTBweDtvdmVyZmxvdzpoaWRkZW47Jz5cIiArXG5cdFx0XHRcdFwiPGRpdiBzdHlsZT0naGVpZ2h0OjEwMHB4O3dpZHRoOmF1dG87Jz48L2Rpdj48L2Rpdj5cIiApLFxuXHRcdFx0aW5uZXJEaXYgPSBkaXYuY2hpbGRyZW4oKVsgMCBdO1xuXG5cdFx0JCggXCJib2R5XCIgKS5hcHBlbmQoIGRpdiApO1xuXHRcdHcxID0gaW5uZXJEaXYub2Zmc2V0V2lkdGg7XG5cdFx0ZGl2LmNzcyggXCJvdmVyZmxvd1wiLCBcInNjcm9sbFwiICk7XG5cblx0XHR3MiA9IGlubmVyRGl2Lm9mZnNldFdpZHRoO1xuXG5cdFx0aWYgKCB3MSA9PT0gdzIgKSB7XG5cdFx0XHR3MiA9IGRpdlsgMCBdLmNsaWVudFdpZHRoO1xuXHRcdH1cblxuXHRcdGRpdi5yZW1vdmUoKTtcblxuXHRcdHJldHVybiAoIGNhY2hlZFNjcm9sbGJhcldpZHRoID0gdzEgLSB3MiApO1xuXHR9LFxuXHRnZXRTY3JvbGxJbmZvOiBmdW5jdGlvbiggd2l0aGluICkge1xuXHRcdHZhciBvdmVyZmxvd1ggPSB3aXRoaW4uaXNXaW5kb3cgfHwgd2l0aGluLmlzRG9jdW1lbnQgPyBcIlwiIDpcblx0XHRcdFx0d2l0aGluLmVsZW1lbnQuY3NzKCBcIm92ZXJmbG93LXhcIiApLFxuXHRcdFx0b3ZlcmZsb3dZID0gd2l0aGluLmlzV2luZG93IHx8IHdpdGhpbi5pc0RvY3VtZW50ID8gXCJcIiA6XG5cdFx0XHRcdHdpdGhpbi5lbGVtZW50LmNzcyggXCJvdmVyZmxvdy15XCIgKSxcblx0XHRcdGhhc092ZXJmbG93WCA9IG92ZXJmbG93WCA9PT0gXCJzY3JvbGxcIiB8fFxuXHRcdFx0XHQoIG92ZXJmbG93WCA9PT0gXCJhdXRvXCIgJiYgd2l0aGluLndpZHRoIDwgd2l0aGluLmVsZW1lbnRbIDAgXS5zY3JvbGxXaWR0aCApLFxuXHRcdFx0aGFzT3ZlcmZsb3dZID0gb3ZlcmZsb3dZID09PSBcInNjcm9sbFwiIHx8XG5cdFx0XHRcdCggb3ZlcmZsb3dZID09PSBcImF1dG9cIiAmJiB3aXRoaW4uaGVpZ2h0IDwgd2l0aGluLmVsZW1lbnRbIDAgXS5zY3JvbGxIZWlnaHQgKTtcblx0XHRyZXR1cm4ge1xuXHRcdFx0d2lkdGg6IGhhc092ZXJmbG93WSA/ICQucG9zaXRpb24uc2Nyb2xsYmFyV2lkdGgoKSA6IDAsXG5cdFx0XHRoZWlnaHQ6IGhhc092ZXJmbG93WCA/ICQucG9zaXRpb24uc2Nyb2xsYmFyV2lkdGgoKSA6IDBcblx0XHR9O1xuXHR9LFxuXHRnZXRXaXRoaW5JbmZvOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHR2YXIgd2l0aGluRWxlbWVudCA9ICQoIGVsZW1lbnQgfHwgd2luZG93ICksXG5cdFx0XHRpc1dpbmRvdyA9ICQuaXNXaW5kb3coIHdpdGhpbkVsZW1lbnRbIDAgXSApLFxuXHRcdFx0aXNEb2N1bWVudCA9ICEhd2l0aGluRWxlbWVudFsgMCBdICYmIHdpdGhpbkVsZW1lbnRbIDAgXS5ub2RlVHlwZSA9PT0gOSxcblx0XHRcdGhhc09mZnNldCA9ICFpc1dpbmRvdyAmJiAhaXNEb2N1bWVudDtcblx0XHRyZXR1cm4ge1xuXHRcdFx0ZWxlbWVudDogd2l0aGluRWxlbWVudCxcblx0XHRcdGlzV2luZG93OiBpc1dpbmRvdyxcblx0XHRcdGlzRG9jdW1lbnQ6IGlzRG9jdW1lbnQsXG5cdFx0XHRvZmZzZXQ6IGhhc09mZnNldCA/ICQoIGVsZW1lbnQgKS5vZmZzZXQoKSA6IHsgbGVmdDogMCwgdG9wOiAwIH0sXG5cdFx0XHRzY3JvbGxMZWZ0OiB3aXRoaW5FbGVtZW50LnNjcm9sbExlZnQoKSxcblx0XHRcdHNjcm9sbFRvcDogd2l0aGluRWxlbWVudC5zY3JvbGxUb3AoKSxcblx0XHRcdHdpZHRoOiB3aXRoaW5FbGVtZW50Lm91dGVyV2lkdGgoKSxcblx0XHRcdGhlaWdodDogd2l0aGluRWxlbWVudC5vdXRlckhlaWdodCgpXG5cdFx0fTtcblx0fVxufTtcblxuJC5mbi5wb3NpdGlvbiA9IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXHRpZiAoICFvcHRpb25zIHx8ICFvcHRpb25zLm9mICkge1xuXHRcdHJldHVybiBfcG9zaXRpb24uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHR9XG5cblx0Ly8gTWFrZSBhIGNvcHksIHdlIGRvbid0IHdhbnQgdG8gbW9kaWZ5IGFyZ3VtZW50c1xuXHRvcHRpb25zID0gJC5leHRlbmQoIHt9LCBvcHRpb25zICk7XG5cblx0dmFyIGF0T2Zmc2V0LCB0YXJnZXRXaWR0aCwgdGFyZ2V0SGVpZ2h0LCB0YXJnZXRPZmZzZXQsIGJhc2VQb3NpdGlvbiwgZGltZW5zaW9ucyxcblx0XHR0YXJnZXQgPSAkKCBvcHRpb25zLm9mICksXG5cdFx0d2l0aGluID0gJC5wb3NpdGlvbi5nZXRXaXRoaW5JbmZvKCBvcHRpb25zLndpdGhpbiApLFxuXHRcdHNjcm9sbEluZm8gPSAkLnBvc2l0aW9uLmdldFNjcm9sbEluZm8oIHdpdGhpbiApLFxuXHRcdGNvbGxpc2lvbiA9ICggb3B0aW9ucy5jb2xsaXNpb24gfHwgXCJmbGlwXCIgKS5zcGxpdCggXCIgXCIgKSxcblx0XHRvZmZzZXRzID0ge307XG5cblx0ZGltZW5zaW9ucyA9IGdldERpbWVuc2lvbnMoIHRhcmdldCApO1xuXHRpZiAoIHRhcmdldFsgMCBdLnByZXZlbnREZWZhdWx0ICkge1xuXG5cdFx0Ly8gRm9yY2UgbGVmdCB0b3AgdG8gYWxsb3cgZmxpcHBpbmdcblx0XHRvcHRpb25zLmF0ID0gXCJsZWZ0IHRvcFwiO1xuXHR9XG5cdHRhcmdldFdpZHRoID0gZGltZW5zaW9ucy53aWR0aDtcblx0dGFyZ2V0SGVpZ2h0ID0gZGltZW5zaW9ucy5oZWlnaHQ7XG5cdHRhcmdldE9mZnNldCA9IGRpbWVuc2lvbnMub2Zmc2V0O1xuXG5cdC8vIENsb25lIHRvIHJldXNlIG9yaWdpbmFsIHRhcmdldE9mZnNldCBsYXRlclxuXHRiYXNlUG9zaXRpb24gPSAkLmV4dGVuZCgge30sIHRhcmdldE9mZnNldCApO1xuXG5cdC8vIEZvcmNlIG15IGFuZCBhdCB0byBoYXZlIHZhbGlkIGhvcml6b250YWwgYW5kIHZlcnRpY2FsIHBvc2l0aW9uc1xuXHQvLyBpZiBhIHZhbHVlIGlzIG1pc3Npbmcgb3IgaW52YWxpZCwgaXQgd2lsbCBiZSBjb252ZXJ0ZWQgdG8gY2VudGVyXG5cdCQuZWFjaCggWyBcIm15XCIsIFwiYXRcIiBdLCBmdW5jdGlvbigpIHtcblx0XHR2YXIgcG9zID0gKCBvcHRpb25zWyB0aGlzIF0gfHwgXCJcIiApLnNwbGl0KCBcIiBcIiApLFxuXHRcdFx0aG9yaXpvbnRhbE9mZnNldCxcblx0XHRcdHZlcnRpY2FsT2Zmc2V0O1xuXG5cdFx0aWYgKCBwb3MubGVuZ3RoID09PSAxICkge1xuXHRcdFx0cG9zID0gcmhvcml6b250YWwudGVzdCggcG9zWyAwIF0gKSA/XG5cdFx0XHRcdHBvcy5jb25jYXQoIFsgXCJjZW50ZXJcIiBdICkgOlxuXHRcdFx0XHRydmVydGljYWwudGVzdCggcG9zWyAwIF0gKSA/XG5cdFx0XHRcdFx0WyBcImNlbnRlclwiIF0uY29uY2F0KCBwb3MgKSA6XG5cdFx0XHRcdFx0WyBcImNlbnRlclwiLCBcImNlbnRlclwiIF07XG5cdFx0fVxuXHRcdHBvc1sgMCBdID0gcmhvcml6b250YWwudGVzdCggcG9zWyAwIF0gKSA/IHBvc1sgMCBdIDogXCJjZW50ZXJcIjtcblx0XHRwb3NbIDEgXSA9IHJ2ZXJ0aWNhbC50ZXN0KCBwb3NbIDEgXSApID8gcG9zWyAxIF0gOiBcImNlbnRlclwiO1xuXG5cdFx0Ly8gQ2FsY3VsYXRlIG9mZnNldHNcblx0XHRob3Jpem9udGFsT2Zmc2V0ID0gcm9mZnNldC5leGVjKCBwb3NbIDAgXSApO1xuXHRcdHZlcnRpY2FsT2Zmc2V0ID0gcm9mZnNldC5leGVjKCBwb3NbIDEgXSApO1xuXHRcdG9mZnNldHNbIHRoaXMgXSA9IFtcblx0XHRcdGhvcml6b250YWxPZmZzZXQgPyBob3Jpem9udGFsT2Zmc2V0WyAwIF0gOiAwLFxuXHRcdFx0dmVydGljYWxPZmZzZXQgPyB2ZXJ0aWNhbE9mZnNldFsgMCBdIDogMFxuXHRcdF07XG5cblx0XHQvLyBSZWR1Y2UgdG8ganVzdCB0aGUgcG9zaXRpb25zIHdpdGhvdXQgdGhlIG9mZnNldHNcblx0XHRvcHRpb25zWyB0aGlzIF0gPSBbXG5cdFx0XHRycG9zaXRpb24uZXhlYyggcG9zWyAwIF0gKVsgMCBdLFxuXHRcdFx0cnBvc2l0aW9uLmV4ZWMoIHBvc1sgMSBdIClbIDAgXVxuXHRcdF07XG5cdH0gKTtcblxuXHQvLyBOb3JtYWxpemUgY29sbGlzaW9uIG9wdGlvblxuXHRpZiAoIGNvbGxpc2lvbi5sZW5ndGggPT09IDEgKSB7XG5cdFx0Y29sbGlzaW9uWyAxIF0gPSBjb2xsaXNpb25bIDAgXTtcblx0fVxuXG5cdGlmICggb3B0aW9ucy5hdFsgMCBdID09PSBcInJpZ2h0XCIgKSB7XG5cdFx0YmFzZVBvc2l0aW9uLmxlZnQgKz0gdGFyZ2V0V2lkdGg7XG5cdH0gZWxzZSBpZiAoIG9wdGlvbnMuYXRbIDAgXSA9PT0gXCJjZW50ZXJcIiApIHtcblx0XHRiYXNlUG9zaXRpb24ubGVmdCArPSB0YXJnZXRXaWR0aCAvIDI7XG5cdH1cblxuXHRpZiAoIG9wdGlvbnMuYXRbIDEgXSA9PT0gXCJib3R0b21cIiApIHtcblx0XHRiYXNlUG9zaXRpb24udG9wICs9IHRhcmdldEhlaWdodDtcblx0fSBlbHNlIGlmICggb3B0aW9ucy5hdFsgMSBdID09PSBcImNlbnRlclwiICkge1xuXHRcdGJhc2VQb3NpdGlvbi50b3AgKz0gdGFyZ2V0SGVpZ2h0IC8gMjtcblx0fVxuXG5cdGF0T2Zmc2V0ID0gZ2V0T2Zmc2V0cyggb2Zmc2V0cy5hdCwgdGFyZ2V0V2lkdGgsIHRhcmdldEhlaWdodCApO1xuXHRiYXNlUG9zaXRpb24ubGVmdCArPSBhdE9mZnNldFsgMCBdO1xuXHRiYXNlUG9zaXRpb24udG9wICs9IGF0T2Zmc2V0WyAxIF07XG5cblx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGNvbGxpc2lvblBvc2l0aW9uLCB1c2luZyxcblx0XHRcdGVsZW0gPSAkKCB0aGlzICksXG5cdFx0XHRlbGVtV2lkdGggPSBlbGVtLm91dGVyV2lkdGgoKSxcblx0XHRcdGVsZW1IZWlnaHQgPSBlbGVtLm91dGVySGVpZ2h0KCksXG5cdFx0XHRtYXJnaW5MZWZ0ID0gcGFyc2VDc3MoIHRoaXMsIFwibWFyZ2luTGVmdFwiICksXG5cdFx0XHRtYXJnaW5Ub3AgPSBwYXJzZUNzcyggdGhpcywgXCJtYXJnaW5Ub3BcIiApLFxuXHRcdFx0Y29sbGlzaW9uV2lkdGggPSBlbGVtV2lkdGggKyBtYXJnaW5MZWZ0ICsgcGFyc2VDc3MoIHRoaXMsIFwibWFyZ2luUmlnaHRcIiApICtcblx0XHRcdFx0c2Nyb2xsSW5mby53aWR0aCxcblx0XHRcdGNvbGxpc2lvbkhlaWdodCA9IGVsZW1IZWlnaHQgKyBtYXJnaW5Ub3AgKyBwYXJzZUNzcyggdGhpcywgXCJtYXJnaW5Cb3R0b21cIiApICtcblx0XHRcdFx0c2Nyb2xsSW5mby5oZWlnaHQsXG5cdFx0XHRwb3NpdGlvbiA9ICQuZXh0ZW5kKCB7fSwgYmFzZVBvc2l0aW9uICksXG5cdFx0XHRteU9mZnNldCA9IGdldE9mZnNldHMoIG9mZnNldHMubXksIGVsZW0ub3V0ZXJXaWR0aCgpLCBlbGVtLm91dGVySGVpZ2h0KCkgKTtcblxuXHRcdGlmICggb3B0aW9ucy5teVsgMCBdID09PSBcInJpZ2h0XCIgKSB7XG5cdFx0XHRwb3NpdGlvbi5sZWZ0IC09IGVsZW1XaWR0aDtcblx0XHR9IGVsc2UgaWYgKCBvcHRpb25zLm15WyAwIF0gPT09IFwiY2VudGVyXCIgKSB7XG5cdFx0XHRwb3NpdGlvbi5sZWZ0IC09IGVsZW1XaWR0aCAvIDI7XG5cdFx0fVxuXG5cdFx0aWYgKCBvcHRpb25zLm15WyAxIF0gPT09IFwiYm90dG9tXCIgKSB7XG5cdFx0XHRwb3NpdGlvbi50b3AgLT0gZWxlbUhlaWdodDtcblx0XHR9IGVsc2UgaWYgKCBvcHRpb25zLm15WyAxIF0gPT09IFwiY2VudGVyXCIgKSB7XG5cdFx0XHRwb3NpdGlvbi50b3AgLT0gZWxlbUhlaWdodCAvIDI7XG5cdFx0fVxuXG5cdFx0cG9zaXRpb24ubGVmdCArPSBteU9mZnNldFsgMCBdO1xuXHRcdHBvc2l0aW9uLnRvcCArPSBteU9mZnNldFsgMSBdO1xuXG5cdFx0Y29sbGlzaW9uUG9zaXRpb24gPSB7XG5cdFx0XHRtYXJnaW5MZWZ0OiBtYXJnaW5MZWZ0LFxuXHRcdFx0bWFyZ2luVG9wOiBtYXJnaW5Ub3Bcblx0XHR9O1xuXG5cdFx0JC5lYWNoKCBbIFwibGVmdFwiLCBcInRvcFwiIF0sIGZ1bmN0aW9uKCBpLCBkaXIgKSB7XG5cdFx0XHRpZiAoICQudWkucG9zaXRpb25bIGNvbGxpc2lvblsgaSBdIF0gKSB7XG5cdFx0XHRcdCQudWkucG9zaXRpb25bIGNvbGxpc2lvblsgaSBdIF1bIGRpciBdKCBwb3NpdGlvbiwge1xuXHRcdFx0XHRcdHRhcmdldFdpZHRoOiB0YXJnZXRXaWR0aCxcblx0XHRcdFx0XHR0YXJnZXRIZWlnaHQ6IHRhcmdldEhlaWdodCxcblx0XHRcdFx0XHRlbGVtV2lkdGg6IGVsZW1XaWR0aCxcblx0XHRcdFx0XHRlbGVtSGVpZ2h0OiBlbGVtSGVpZ2h0LFxuXHRcdFx0XHRcdGNvbGxpc2lvblBvc2l0aW9uOiBjb2xsaXNpb25Qb3NpdGlvbixcblx0XHRcdFx0XHRjb2xsaXNpb25XaWR0aDogY29sbGlzaW9uV2lkdGgsXG5cdFx0XHRcdFx0Y29sbGlzaW9uSGVpZ2h0OiBjb2xsaXNpb25IZWlnaHQsXG5cdFx0XHRcdFx0b2Zmc2V0OiBbIGF0T2Zmc2V0WyAwIF0gKyBteU9mZnNldFsgMCBdLCBhdE9mZnNldCBbIDEgXSArIG15T2Zmc2V0WyAxIF0gXSxcblx0XHRcdFx0XHRteTogb3B0aW9ucy5teSxcblx0XHRcdFx0XHRhdDogb3B0aW9ucy5hdCxcblx0XHRcdFx0XHR3aXRoaW46IHdpdGhpbixcblx0XHRcdFx0XHRlbGVtOiBlbGVtXG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHRpZiAoIG9wdGlvbnMudXNpbmcgKSB7XG5cblx0XHRcdC8vIEFkZHMgZmVlZGJhY2sgYXMgc2Vjb25kIGFyZ3VtZW50IHRvIHVzaW5nIGNhbGxiYWNrLCBpZiBwcmVzZW50XG5cdFx0XHR1c2luZyA9IGZ1bmN0aW9uKCBwcm9wcyApIHtcblx0XHRcdFx0dmFyIGxlZnQgPSB0YXJnZXRPZmZzZXQubGVmdCAtIHBvc2l0aW9uLmxlZnQsXG5cdFx0XHRcdFx0cmlnaHQgPSBsZWZ0ICsgdGFyZ2V0V2lkdGggLSBlbGVtV2lkdGgsXG5cdFx0XHRcdFx0dG9wID0gdGFyZ2V0T2Zmc2V0LnRvcCAtIHBvc2l0aW9uLnRvcCxcblx0XHRcdFx0XHRib3R0b20gPSB0b3AgKyB0YXJnZXRIZWlnaHQgLSBlbGVtSGVpZ2h0LFxuXHRcdFx0XHRcdGZlZWRiYWNrID0ge1xuXHRcdFx0XHRcdFx0dGFyZ2V0OiB7XG5cdFx0XHRcdFx0XHRcdGVsZW1lbnQ6IHRhcmdldCxcblx0XHRcdFx0XHRcdFx0bGVmdDogdGFyZ2V0T2Zmc2V0LmxlZnQsXG5cdFx0XHRcdFx0XHRcdHRvcDogdGFyZ2V0T2Zmc2V0LnRvcCxcblx0XHRcdFx0XHRcdFx0d2lkdGg6IHRhcmdldFdpZHRoLFxuXHRcdFx0XHRcdFx0XHRoZWlnaHQ6IHRhcmdldEhlaWdodFxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdGVsZW1lbnQ6IHtcblx0XHRcdFx0XHRcdFx0ZWxlbWVudDogZWxlbSxcblx0XHRcdFx0XHRcdFx0bGVmdDogcG9zaXRpb24ubGVmdCxcblx0XHRcdFx0XHRcdFx0dG9wOiBwb3NpdGlvbi50b3AsXG5cdFx0XHRcdFx0XHRcdHdpZHRoOiBlbGVtV2lkdGgsXG5cdFx0XHRcdFx0XHRcdGhlaWdodDogZWxlbUhlaWdodFxuXHRcdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRcdGhvcml6b250YWw6IHJpZ2h0IDwgMCA/IFwibGVmdFwiIDogbGVmdCA+IDAgPyBcInJpZ2h0XCIgOiBcImNlbnRlclwiLFxuXHRcdFx0XHRcdFx0dmVydGljYWw6IGJvdHRvbSA8IDAgPyBcInRvcFwiIDogdG9wID4gMCA/IFwiYm90dG9tXCIgOiBcIm1pZGRsZVwiXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0aWYgKCB0YXJnZXRXaWR0aCA8IGVsZW1XaWR0aCAmJiBhYnMoIGxlZnQgKyByaWdodCApIDwgdGFyZ2V0V2lkdGggKSB7XG5cdFx0XHRcdFx0ZmVlZGJhY2suaG9yaXpvbnRhbCA9IFwiY2VudGVyXCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCB0YXJnZXRIZWlnaHQgPCBlbGVtSGVpZ2h0ICYmIGFicyggdG9wICsgYm90dG9tICkgPCB0YXJnZXRIZWlnaHQgKSB7XG5cdFx0XHRcdFx0ZmVlZGJhY2sudmVydGljYWwgPSBcIm1pZGRsZVwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggbWF4KCBhYnMoIGxlZnQgKSwgYWJzKCByaWdodCApICkgPiBtYXgoIGFicyggdG9wICksIGFicyggYm90dG9tICkgKSApIHtcblx0XHRcdFx0XHRmZWVkYmFjay5pbXBvcnRhbnQgPSBcImhvcml6b250YWxcIjtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRmZWVkYmFjay5pbXBvcnRhbnQgPSBcInZlcnRpY2FsXCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0b3B0aW9ucy51c2luZy5jYWxsKCB0aGlzLCBwcm9wcywgZmVlZGJhY2sgKTtcblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0ZWxlbS5vZmZzZXQoICQuZXh0ZW5kKCBwb3NpdGlvbiwgeyB1c2luZzogdXNpbmcgfSApICk7XG5cdH0gKTtcbn07XG5cbiQudWkucG9zaXRpb24gPSB7XG5cdGZpdDoge1xuXHRcdGxlZnQ6IGZ1bmN0aW9uKCBwb3NpdGlvbiwgZGF0YSApIHtcblx0XHRcdHZhciB3aXRoaW4gPSBkYXRhLndpdGhpbixcblx0XHRcdFx0d2l0aGluT2Zmc2V0ID0gd2l0aGluLmlzV2luZG93ID8gd2l0aGluLnNjcm9sbExlZnQgOiB3aXRoaW4ub2Zmc2V0LmxlZnQsXG5cdFx0XHRcdG91dGVyV2lkdGggPSB3aXRoaW4ud2lkdGgsXG5cdFx0XHRcdGNvbGxpc2lvblBvc0xlZnQgPSBwb3NpdGlvbi5sZWZ0IC0gZGF0YS5jb2xsaXNpb25Qb3NpdGlvbi5tYXJnaW5MZWZ0LFxuXHRcdFx0XHRvdmVyTGVmdCA9IHdpdGhpbk9mZnNldCAtIGNvbGxpc2lvblBvc0xlZnQsXG5cdFx0XHRcdG92ZXJSaWdodCA9IGNvbGxpc2lvblBvc0xlZnQgKyBkYXRhLmNvbGxpc2lvbldpZHRoIC0gb3V0ZXJXaWR0aCAtIHdpdGhpbk9mZnNldCxcblx0XHRcdFx0bmV3T3ZlclJpZ2h0O1xuXG5cdFx0XHQvLyBFbGVtZW50IGlzIHdpZGVyIHRoYW4gd2l0aGluXG5cdFx0XHRpZiAoIGRhdGEuY29sbGlzaW9uV2lkdGggPiBvdXRlcldpZHRoICkge1xuXG5cdFx0XHRcdC8vIEVsZW1lbnQgaXMgaW5pdGlhbGx5IG92ZXIgdGhlIGxlZnQgc2lkZSBvZiB3aXRoaW5cblx0XHRcdFx0aWYgKCBvdmVyTGVmdCA+IDAgJiYgb3ZlclJpZ2h0IDw9IDAgKSB7XG5cdFx0XHRcdFx0bmV3T3ZlclJpZ2h0ID0gcG9zaXRpb24ubGVmdCArIG92ZXJMZWZ0ICsgZGF0YS5jb2xsaXNpb25XaWR0aCAtIG91dGVyV2lkdGggLVxuXHRcdFx0XHRcdFx0d2l0aGluT2Zmc2V0O1xuXHRcdFx0XHRcdHBvc2l0aW9uLmxlZnQgKz0gb3ZlckxlZnQgLSBuZXdPdmVyUmlnaHQ7XG5cblx0XHRcdFx0Ly8gRWxlbWVudCBpcyBpbml0aWFsbHkgb3ZlciByaWdodCBzaWRlIG9mIHdpdGhpblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvdmVyUmlnaHQgPiAwICYmIG92ZXJMZWZ0IDw9IDAgKSB7XG5cdFx0XHRcdFx0cG9zaXRpb24ubGVmdCA9IHdpdGhpbk9mZnNldDtcblxuXHRcdFx0XHQvLyBFbGVtZW50IGlzIGluaXRpYWxseSBvdmVyIGJvdGggbGVmdCBhbmQgcmlnaHQgc2lkZXMgb2Ygd2l0aGluXG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0aWYgKCBvdmVyTGVmdCA+IG92ZXJSaWdodCApIHtcblx0XHRcdFx0XHRcdHBvc2l0aW9uLmxlZnQgPSB3aXRoaW5PZmZzZXQgKyBvdXRlcldpZHRoIC0gZGF0YS5jb2xsaXNpb25XaWR0aDtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0cG9zaXRpb24ubGVmdCA9IHdpdGhpbk9mZnNldDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0Ly8gVG9vIGZhciBsZWZ0IC0+IGFsaWduIHdpdGggbGVmdCBlZGdlXG5cdFx0XHR9IGVsc2UgaWYgKCBvdmVyTGVmdCA+IDAgKSB7XG5cdFx0XHRcdHBvc2l0aW9uLmxlZnQgKz0gb3ZlckxlZnQ7XG5cblx0XHRcdC8vIFRvbyBmYXIgcmlnaHQgLT4gYWxpZ24gd2l0aCByaWdodCBlZGdlXG5cdFx0XHR9IGVsc2UgaWYgKCBvdmVyUmlnaHQgPiAwICkge1xuXHRcdFx0XHRwb3NpdGlvbi5sZWZ0IC09IG92ZXJSaWdodDtcblxuXHRcdFx0Ly8gQWRqdXN0IGJhc2VkIG9uIHBvc2l0aW9uIGFuZCBtYXJnaW5cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHBvc2l0aW9uLmxlZnQgPSBtYXgoIHBvc2l0aW9uLmxlZnQgLSBjb2xsaXNpb25Qb3NMZWZ0LCBwb3NpdGlvbi5sZWZ0ICk7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHR0b3A6IGZ1bmN0aW9uKCBwb3NpdGlvbiwgZGF0YSApIHtcblx0XHRcdHZhciB3aXRoaW4gPSBkYXRhLndpdGhpbixcblx0XHRcdFx0d2l0aGluT2Zmc2V0ID0gd2l0aGluLmlzV2luZG93ID8gd2l0aGluLnNjcm9sbFRvcCA6IHdpdGhpbi5vZmZzZXQudG9wLFxuXHRcdFx0XHRvdXRlckhlaWdodCA9IGRhdGEud2l0aGluLmhlaWdodCxcblx0XHRcdFx0Y29sbGlzaW9uUG9zVG9wID0gcG9zaXRpb24udG9wIC0gZGF0YS5jb2xsaXNpb25Qb3NpdGlvbi5tYXJnaW5Ub3AsXG5cdFx0XHRcdG92ZXJUb3AgPSB3aXRoaW5PZmZzZXQgLSBjb2xsaXNpb25Qb3NUb3AsXG5cdFx0XHRcdG92ZXJCb3R0b20gPSBjb2xsaXNpb25Qb3NUb3AgKyBkYXRhLmNvbGxpc2lvbkhlaWdodCAtIG91dGVySGVpZ2h0IC0gd2l0aGluT2Zmc2V0LFxuXHRcdFx0XHRuZXdPdmVyQm90dG9tO1xuXG5cdFx0XHQvLyBFbGVtZW50IGlzIHRhbGxlciB0aGFuIHdpdGhpblxuXHRcdFx0aWYgKCBkYXRhLmNvbGxpc2lvbkhlaWdodCA+IG91dGVySGVpZ2h0ICkge1xuXG5cdFx0XHRcdC8vIEVsZW1lbnQgaXMgaW5pdGlhbGx5IG92ZXIgdGhlIHRvcCBvZiB3aXRoaW5cblx0XHRcdFx0aWYgKCBvdmVyVG9wID4gMCAmJiBvdmVyQm90dG9tIDw9IDAgKSB7XG5cdFx0XHRcdFx0bmV3T3ZlckJvdHRvbSA9IHBvc2l0aW9uLnRvcCArIG92ZXJUb3AgKyBkYXRhLmNvbGxpc2lvbkhlaWdodCAtIG91dGVySGVpZ2h0IC1cblx0XHRcdFx0XHRcdHdpdGhpbk9mZnNldDtcblx0XHRcdFx0XHRwb3NpdGlvbi50b3AgKz0gb3ZlclRvcCAtIG5ld092ZXJCb3R0b207XG5cblx0XHRcdFx0Ly8gRWxlbWVudCBpcyBpbml0aWFsbHkgb3ZlciBib3R0b20gb2Ygd2l0aGluXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG92ZXJCb3R0b20gPiAwICYmIG92ZXJUb3AgPD0gMCApIHtcblx0XHRcdFx0XHRwb3NpdGlvbi50b3AgPSB3aXRoaW5PZmZzZXQ7XG5cblx0XHRcdFx0Ly8gRWxlbWVudCBpcyBpbml0aWFsbHkgb3ZlciBib3RoIHRvcCBhbmQgYm90dG9tIG9mIHdpdGhpblxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGlmICggb3ZlclRvcCA+IG92ZXJCb3R0b20gKSB7XG5cdFx0XHRcdFx0XHRwb3NpdGlvbi50b3AgPSB3aXRoaW5PZmZzZXQgKyBvdXRlckhlaWdodCAtIGRhdGEuY29sbGlzaW9uSGVpZ2h0O1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRwb3NpdGlvbi50b3AgPSB3aXRoaW5PZmZzZXQ7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdC8vIFRvbyBmYXIgdXAgLT4gYWxpZ24gd2l0aCB0b3Bcblx0XHRcdH0gZWxzZSBpZiAoIG92ZXJUb3AgPiAwICkge1xuXHRcdFx0XHRwb3NpdGlvbi50b3AgKz0gb3ZlclRvcDtcblxuXHRcdFx0Ly8gVG9vIGZhciBkb3duIC0+IGFsaWduIHdpdGggYm90dG9tIGVkZ2Vcblx0XHRcdH0gZWxzZSBpZiAoIG92ZXJCb3R0b20gPiAwICkge1xuXHRcdFx0XHRwb3NpdGlvbi50b3AgLT0gb3ZlckJvdHRvbTtcblxuXHRcdFx0Ly8gQWRqdXN0IGJhc2VkIG9uIHBvc2l0aW9uIGFuZCBtYXJnaW5cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHBvc2l0aW9uLnRvcCA9IG1heCggcG9zaXRpb24udG9wIC0gY29sbGlzaW9uUG9zVG9wLCBwb3NpdGlvbi50b3AgKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cdGZsaXA6IHtcblx0XHRsZWZ0OiBmdW5jdGlvbiggcG9zaXRpb24sIGRhdGEgKSB7XG5cdFx0XHR2YXIgd2l0aGluID0gZGF0YS53aXRoaW4sXG5cdFx0XHRcdHdpdGhpbk9mZnNldCA9IHdpdGhpbi5vZmZzZXQubGVmdCArIHdpdGhpbi5zY3JvbGxMZWZ0LFxuXHRcdFx0XHRvdXRlcldpZHRoID0gd2l0aGluLndpZHRoLFxuXHRcdFx0XHRvZmZzZXRMZWZ0ID0gd2l0aGluLmlzV2luZG93ID8gd2l0aGluLnNjcm9sbExlZnQgOiB3aXRoaW4ub2Zmc2V0LmxlZnQsXG5cdFx0XHRcdGNvbGxpc2lvblBvc0xlZnQgPSBwb3NpdGlvbi5sZWZ0IC0gZGF0YS5jb2xsaXNpb25Qb3NpdGlvbi5tYXJnaW5MZWZ0LFxuXHRcdFx0XHRvdmVyTGVmdCA9IGNvbGxpc2lvblBvc0xlZnQgLSBvZmZzZXRMZWZ0LFxuXHRcdFx0XHRvdmVyUmlnaHQgPSBjb2xsaXNpb25Qb3NMZWZ0ICsgZGF0YS5jb2xsaXNpb25XaWR0aCAtIG91dGVyV2lkdGggLSBvZmZzZXRMZWZ0LFxuXHRcdFx0XHRteU9mZnNldCA9IGRhdGEubXlbIDAgXSA9PT0gXCJsZWZ0XCIgP1xuXHRcdFx0XHRcdC1kYXRhLmVsZW1XaWR0aCA6XG5cdFx0XHRcdFx0ZGF0YS5teVsgMCBdID09PSBcInJpZ2h0XCIgP1xuXHRcdFx0XHRcdFx0ZGF0YS5lbGVtV2lkdGggOlxuXHRcdFx0XHRcdFx0MCxcblx0XHRcdFx0YXRPZmZzZXQgPSBkYXRhLmF0WyAwIF0gPT09IFwibGVmdFwiID9cblx0XHRcdFx0XHRkYXRhLnRhcmdldFdpZHRoIDpcblx0XHRcdFx0XHRkYXRhLmF0WyAwIF0gPT09IFwicmlnaHRcIiA/XG5cdFx0XHRcdFx0XHQtZGF0YS50YXJnZXRXaWR0aCA6XG5cdFx0XHRcdFx0XHQwLFxuXHRcdFx0XHRvZmZzZXQgPSAtMiAqIGRhdGEub2Zmc2V0WyAwIF0sXG5cdFx0XHRcdG5ld092ZXJSaWdodCxcblx0XHRcdFx0bmV3T3ZlckxlZnQ7XG5cblx0XHRcdGlmICggb3ZlckxlZnQgPCAwICkge1xuXHRcdFx0XHRuZXdPdmVyUmlnaHQgPSBwb3NpdGlvbi5sZWZ0ICsgbXlPZmZzZXQgKyBhdE9mZnNldCArIG9mZnNldCArIGRhdGEuY29sbGlzaW9uV2lkdGggLVxuXHRcdFx0XHRcdG91dGVyV2lkdGggLSB3aXRoaW5PZmZzZXQ7XG5cdFx0XHRcdGlmICggbmV3T3ZlclJpZ2h0IDwgMCB8fCBuZXdPdmVyUmlnaHQgPCBhYnMoIG92ZXJMZWZ0ICkgKSB7XG5cdFx0XHRcdFx0cG9zaXRpb24ubGVmdCArPSBteU9mZnNldCArIGF0T2Zmc2V0ICsgb2Zmc2V0O1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2UgaWYgKCBvdmVyUmlnaHQgPiAwICkge1xuXHRcdFx0XHRuZXdPdmVyTGVmdCA9IHBvc2l0aW9uLmxlZnQgLSBkYXRhLmNvbGxpc2lvblBvc2l0aW9uLm1hcmdpbkxlZnQgKyBteU9mZnNldCArXG5cdFx0XHRcdFx0YXRPZmZzZXQgKyBvZmZzZXQgLSBvZmZzZXRMZWZ0O1xuXHRcdFx0XHRpZiAoIG5ld092ZXJMZWZ0ID4gMCB8fCBhYnMoIG5ld092ZXJMZWZ0ICkgPCBvdmVyUmlnaHQgKSB7XG5cdFx0XHRcdFx0cG9zaXRpb24ubGVmdCArPSBteU9mZnNldCArIGF0T2Zmc2V0ICsgb2Zmc2V0O1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSxcblx0XHR0b3A6IGZ1bmN0aW9uKCBwb3NpdGlvbiwgZGF0YSApIHtcblx0XHRcdHZhciB3aXRoaW4gPSBkYXRhLndpdGhpbixcblx0XHRcdFx0d2l0aGluT2Zmc2V0ID0gd2l0aGluLm9mZnNldC50b3AgKyB3aXRoaW4uc2Nyb2xsVG9wLFxuXHRcdFx0XHRvdXRlckhlaWdodCA9IHdpdGhpbi5oZWlnaHQsXG5cdFx0XHRcdG9mZnNldFRvcCA9IHdpdGhpbi5pc1dpbmRvdyA/IHdpdGhpbi5zY3JvbGxUb3AgOiB3aXRoaW4ub2Zmc2V0LnRvcCxcblx0XHRcdFx0Y29sbGlzaW9uUG9zVG9wID0gcG9zaXRpb24udG9wIC0gZGF0YS5jb2xsaXNpb25Qb3NpdGlvbi5tYXJnaW5Ub3AsXG5cdFx0XHRcdG92ZXJUb3AgPSBjb2xsaXNpb25Qb3NUb3AgLSBvZmZzZXRUb3AsXG5cdFx0XHRcdG92ZXJCb3R0b20gPSBjb2xsaXNpb25Qb3NUb3AgKyBkYXRhLmNvbGxpc2lvbkhlaWdodCAtIG91dGVySGVpZ2h0IC0gb2Zmc2V0VG9wLFxuXHRcdFx0XHR0b3AgPSBkYXRhLm15WyAxIF0gPT09IFwidG9wXCIsXG5cdFx0XHRcdG15T2Zmc2V0ID0gdG9wID9cblx0XHRcdFx0XHQtZGF0YS5lbGVtSGVpZ2h0IDpcblx0XHRcdFx0XHRkYXRhLm15WyAxIF0gPT09IFwiYm90dG9tXCIgP1xuXHRcdFx0XHRcdFx0ZGF0YS5lbGVtSGVpZ2h0IDpcblx0XHRcdFx0XHRcdDAsXG5cdFx0XHRcdGF0T2Zmc2V0ID0gZGF0YS5hdFsgMSBdID09PSBcInRvcFwiID9cblx0XHRcdFx0XHRkYXRhLnRhcmdldEhlaWdodCA6XG5cdFx0XHRcdFx0ZGF0YS5hdFsgMSBdID09PSBcImJvdHRvbVwiID9cblx0XHRcdFx0XHRcdC1kYXRhLnRhcmdldEhlaWdodCA6XG5cdFx0XHRcdFx0XHQwLFxuXHRcdFx0XHRvZmZzZXQgPSAtMiAqIGRhdGEub2Zmc2V0WyAxIF0sXG5cdFx0XHRcdG5ld092ZXJUb3AsXG5cdFx0XHRcdG5ld092ZXJCb3R0b207XG5cdFx0XHRpZiAoIG92ZXJUb3AgPCAwICkge1xuXHRcdFx0XHRuZXdPdmVyQm90dG9tID0gcG9zaXRpb24udG9wICsgbXlPZmZzZXQgKyBhdE9mZnNldCArIG9mZnNldCArIGRhdGEuY29sbGlzaW9uSGVpZ2h0IC1cblx0XHRcdFx0XHRvdXRlckhlaWdodCAtIHdpdGhpbk9mZnNldDtcblx0XHRcdFx0aWYgKCBuZXdPdmVyQm90dG9tIDwgMCB8fCBuZXdPdmVyQm90dG9tIDwgYWJzKCBvdmVyVG9wICkgKSB7XG5cdFx0XHRcdFx0cG9zaXRpb24udG9wICs9IG15T2Zmc2V0ICsgYXRPZmZzZXQgKyBvZmZzZXQ7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSBpZiAoIG92ZXJCb3R0b20gPiAwICkge1xuXHRcdFx0XHRuZXdPdmVyVG9wID0gcG9zaXRpb24udG9wIC0gZGF0YS5jb2xsaXNpb25Qb3NpdGlvbi5tYXJnaW5Ub3AgKyBteU9mZnNldCArIGF0T2Zmc2V0ICtcblx0XHRcdFx0XHRvZmZzZXQgLSBvZmZzZXRUb3A7XG5cdFx0XHRcdGlmICggbmV3T3ZlclRvcCA+IDAgfHwgYWJzKCBuZXdPdmVyVG9wICkgPCBvdmVyQm90dG9tICkge1xuXHRcdFx0XHRcdHBvc2l0aW9uLnRvcCArPSBteU9mZnNldCArIGF0T2Zmc2V0ICsgb2Zmc2V0O1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHRmbGlwZml0OiB7XG5cdFx0bGVmdDogZnVuY3Rpb24oKSB7XG5cdFx0XHQkLnVpLnBvc2l0aW9uLmZsaXAubGVmdC5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHQkLnVpLnBvc2l0aW9uLmZpdC5sZWZ0LmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHR9LFxuXHRcdHRvcDogZnVuY3Rpb24oKSB7XG5cdFx0XHQkLnVpLnBvc2l0aW9uLmZsaXAudG9wLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdCQudWkucG9zaXRpb24uZml0LnRvcC5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0fVxuXHR9XG59O1xuXG59ICkoKTtcblxudmFyIHBvc2l0aW9uID0gJC51aS5wb3NpdGlvbjtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSA6ZGF0YSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogOmRhdGEgU2VsZWN0b3Jcbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBTZWxlY3RzIGVsZW1lbnRzIHdoaWNoIGhhdmUgZGF0YSBzdG9yZWQgdW5kZXIgdGhlIHNwZWNpZmllZCBrZXkuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZGF0YS1zZWxlY3Rvci9cblxuXG52YXIgZGF0YSA9ICQuZXh0ZW5kKCAkLmV4cHJbIFwiOlwiIF0sIHtcblx0ZGF0YTogJC5leHByLmNyZWF0ZVBzZXVkbyA/XG5cdFx0JC5leHByLmNyZWF0ZVBzZXVkbyggZnVuY3Rpb24oIGRhdGFOYW1lICkge1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRyZXR1cm4gISEkLmRhdGEoIGVsZW0sIGRhdGFOYW1lICk7XG5cdFx0XHR9O1xuXHRcdH0gKSA6XG5cblx0XHQvLyBTdXBwb3J0OiBqUXVlcnkgPDEuOFxuXHRcdGZ1bmN0aW9uKCBlbGVtLCBpLCBtYXRjaCApIHtcblx0XHRcdHJldHVybiAhISQuZGF0YSggZWxlbSwgbWF0Y2hbIDMgXSApO1xuXHRcdH1cbn0gKTtcblxuLyohXG4gKiBqUXVlcnkgVUkgRGlzYWJsZSBTZWxlY3Rpb24gMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IGRpc2FibGVTZWxlY3Rpb25cbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBEaXNhYmxlIHNlbGVjdGlvbiBvZiB0ZXh0IGNvbnRlbnQgd2l0aGluIHRoZSBzZXQgb2YgbWF0Y2hlZCBlbGVtZW50cy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9kaXNhYmxlU2VsZWN0aW9uL1xuXG4vLyBUaGlzIGZpbGUgaXMgZGVwcmVjYXRlZFxuXG5cbnZhciBkaXNhYmxlU2VsZWN0aW9uID0gJC5mbi5leHRlbmQoIHtcblx0ZGlzYWJsZVNlbGVjdGlvbjogKCBmdW5jdGlvbigpIHtcblx0XHR2YXIgZXZlbnRUeXBlID0gXCJvbnNlbGVjdHN0YXJ0XCIgaW4gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJkaXZcIiApID9cblx0XHRcdFwic2VsZWN0c3RhcnRcIiA6XG5cdFx0XHRcIm1vdXNlZG93blwiO1xuXG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIHRoaXMub24oIGV2ZW50VHlwZSArIFwiLnVpLWRpc2FibGVTZWxlY3Rpb25cIiwgZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0fSApO1xuXHRcdH07XG5cdH0gKSgpLFxuXG5cdGVuYWJsZVNlbGVjdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMub2ZmKCBcIi51aS1kaXNhYmxlU2VsZWN0aW9uXCIgKTtcblx0fVxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEVmZmVjdHMgQ29yZVxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLyBqc2NzOmRpc2FibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kZXNjcmlwdGlvbjogRXh0ZW5kcyB0aGUgaW50ZXJuYWwgalF1ZXJ5IGVmZmVjdHMuIEluY2x1ZGVzIG1vcnBoaW5nIGFuZCBlYXNpbmcuIFJlcXVpcmVkIGJ5IGFsbCBvdGhlciBlZmZlY3RzLlxuLy8ganNjczplbmFibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9jYXRlZ29yeS9lZmZlY3RzLWNvcmUvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGRhdGFTcGFjZSA9IFwidWktZWZmZWN0cy1cIixcblx0ZGF0YVNwYWNlU3R5bGUgPSBcInVpLWVmZmVjdHMtc3R5bGVcIixcblx0ZGF0YVNwYWNlQW5pbWF0ZWQgPSBcInVpLWVmZmVjdHMtYW5pbWF0ZWRcIixcblxuXHQvLyBDcmVhdGUgYSBsb2NhbCBqUXVlcnkgYmVjYXVzZSBqUXVlcnkgQ29sb3IgcmVsaWVzIG9uIGl0IGFuZCB0aGVcblx0Ly8gZ2xvYmFsIG1heSBub3QgZXhpc3Qgd2l0aCBBTUQgYW5kIGEgY3VzdG9tIGJ1aWxkICgjMTAxOTkpXG5cdGpRdWVyeSA9ICQ7XG5cbiQuZWZmZWN0cyA9IHtcblx0ZWZmZWN0OiB7fVxufTtcblxuLyohXG4gKiBqUXVlcnkgQ29sb3IgQW5pbWF0aW9ucyB2Mi4xLjJcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9qcXVlcnkvanF1ZXJ5LWNvbG9yXG4gKlxuICogQ29weXJpZ2h0IDIwMTQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICpcbiAqIERhdGU6IFdlZCBKYW4gMTYgMDg6NDc6MDkgMjAxMyAtMDYwMFxuICovXG4oIGZ1bmN0aW9uKCBqUXVlcnksIHVuZGVmaW5lZCApIHtcblxuXHR2YXIgc3RlcEhvb2tzID0gXCJiYWNrZ3JvdW5kQ29sb3IgYm9yZGVyQm90dG9tQ29sb3IgYm9yZGVyTGVmdENvbG9yIGJvcmRlclJpZ2h0Q29sb3IgXCIgK1xuXHRcdFwiYm9yZGVyVG9wQ29sb3IgY29sb3IgY29sdW1uUnVsZUNvbG9yIG91dGxpbmVDb2xvciB0ZXh0RGVjb3JhdGlvbkNvbG9yIHRleHRFbXBoYXNpc0NvbG9yXCIsXG5cblx0Ly8gUGx1c2VxdWFscyB0ZXN0IGZvciArPSAxMDAgLT0gMTAwXG5cdHJwbHVzZXF1YWxzID0gL14oW1xcLStdKT1cXHMqKFxcZCtcXC4/XFxkKikvLFxuXG5cdC8vIEEgc2V0IG9mIFJFJ3MgdGhhdCBjYW4gbWF0Y2ggc3RyaW5ncyBhbmQgZ2VuZXJhdGUgY29sb3IgdHVwbGVzLlxuXHRzdHJpbmdQYXJzZXJzID0gWyB7XG5cdFx0XHRyZTogL3JnYmE/XFwoXFxzKihcXGR7MSwzfSlcXHMqLFxccyooXFxkezEsM30pXFxzKixcXHMqKFxcZHsxLDN9KVxccyooPzosXFxzKihcXGQ/KD86XFwuXFxkKyk/KVxccyopP1xcKS8sXG5cdFx0XHRwYXJzZTogZnVuY3Rpb24oIGV4ZWNSZXN1bHQgKSB7XG5cdFx0XHRcdHJldHVybiBbXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgMSBdLFxuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDIgXSxcblx0XHRcdFx0XHRleGVjUmVzdWx0WyAzIF0sXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgNCBdXG5cdFx0XHRcdF07XG5cdFx0XHR9XG5cdFx0fSwge1xuXHRcdFx0cmU6IC9yZ2JhP1xcKFxccyooXFxkKyg/OlxcLlxcZCspPylcXCVcXHMqLFxccyooXFxkKyg/OlxcLlxcZCspPylcXCVcXHMqLFxccyooXFxkKyg/OlxcLlxcZCspPylcXCVcXHMqKD86LFxccyooXFxkPyg/OlxcLlxcZCspPylcXHMqKT9cXCkvLFxuXHRcdFx0cGFyc2U6IGZ1bmN0aW9uKCBleGVjUmVzdWx0ICkge1xuXHRcdFx0XHRyZXR1cm4gW1xuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDEgXSAqIDIuNTUsXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgMiBdICogMi41NSxcblx0XHRcdFx0XHRleGVjUmVzdWx0WyAzIF0gKiAyLjU1LFxuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDQgXVxuXHRcdFx0XHRdO1xuXHRcdFx0fVxuXHRcdH0sIHtcblxuXHRcdFx0Ly8gVGhpcyByZWdleCBpZ25vcmVzIEEtRiBiZWNhdXNlIGl0J3MgY29tcGFyZWQgYWdhaW5zdCBhbiBhbHJlYWR5IGxvd2VyY2FzZWQgc3RyaW5nXG5cdFx0XHRyZTogLyMoW2EtZjAtOV17Mn0pKFthLWYwLTldezJ9KShbYS1mMC05XXsyfSkvLFxuXHRcdFx0cGFyc2U6IGZ1bmN0aW9uKCBleGVjUmVzdWx0ICkge1xuXHRcdFx0XHRyZXR1cm4gW1xuXHRcdFx0XHRcdHBhcnNlSW50KCBleGVjUmVzdWx0WyAxIF0sIDE2ICksXG5cdFx0XHRcdFx0cGFyc2VJbnQoIGV4ZWNSZXN1bHRbIDIgXSwgMTYgKSxcblx0XHRcdFx0XHRwYXJzZUludCggZXhlY1Jlc3VsdFsgMyBdLCAxNiApXG5cdFx0XHRcdF07XG5cdFx0XHR9XG5cdFx0fSwge1xuXG5cdFx0XHQvLyBUaGlzIHJlZ2V4IGlnbm9yZXMgQS1GIGJlY2F1c2UgaXQncyBjb21wYXJlZCBhZ2FpbnN0IGFuIGFscmVhZHkgbG93ZXJjYXNlZCBzdHJpbmdcblx0XHRcdHJlOiAvIyhbYS1mMC05XSkoW2EtZjAtOV0pKFthLWYwLTldKS8sXG5cdFx0XHRwYXJzZTogZnVuY3Rpb24oIGV4ZWNSZXN1bHQgKSB7XG5cdFx0XHRcdHJldHVybiBbXG5cdFx0XHRcdFx0cGFyc2VJbnQoIGV4ZWNSZXN1bHRbIDEgXSArIGV4ZWNSZXN1bHRbIDEgXSwgMTYgKSxcblx0XHRcdFx0XHRwYXJzZUludCggZXhlY1Jlc3VsdFsgMiBdICsgZXhlY1Jlc3VsdFsgMiBdLCAxNiApLFxuXHRcdFx0XHRcdHBhcnNlSW50KCBleGVjUmVzdWx0WyAzIF0gKyBleGVjUmVzdWx0WyAzIF0sIDE2IClcblx0XHRcdFx0XTtcblx0XHRcdH1cblx0XHR9LCB7XG5cdFx0XHRyZTogL2hzbGE/XFwoXFxzKihcXGQrKD86XFwuXFxkKyk/KVxccyosXFxzKihcXGQrKD86XFwuXFxkKyk/KVxcJVxccyosXFxzKihcXGQrKD86XFwuXFxkKyk/KVxcJVxccyooPzosXFxzKihcXGQ/KD86XFwuXFxkKyk/KVxccyopP1xcKS8sXG5cdFx0XHRzcGFjZTogXCJoc2xhXCIsXG5cdFx0XHRwYXJzZTogZnVuY3Rpb24oIGV4ZWNSZXN1bHQgKSB7XG5cdFx0XHRcdHJldHVybiBbXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgMSBdLFxuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDIgXSAvIDEwMCxcblx0XHRcdFx0XHRleGVjUmVzdWx0WyAzIF0gLyAxMDAsXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgNCBdXG5cdFx0XHRcdF07XG5cdFx0XHR9XG5cdFx0fSBdLFxuXG5cdC8vIEpRdWVyeS5Db2xvciggKVxuXHRjb2xvciA9IGpRdWVyeS5Db2xvciA9IGZ1bmN0aW9uKCBjb2xvciwgZ3JlZW4sIGJsdWUsIGFscGhhICkge1xuXHRcdHJldHVybiBuZXcgalF1ZXJ5LkNvbG9yLmZuLnBhcnNlKCBjb2xvciwgZ3JlZW4sIGJsdWUsIGFscGhhICk7XG5cdH0sXG5cdHNwYWNlcyA9IHtcblx0XHRyZ2JhOiB7XG5cdFx0XHRwcm9wczoge1xuXHRcdFx0XHRyZWQ6IHtcblx0XHRcdFx0XHRpZHg6IDAsXG5cdFx0XHRcdFx0dHlwZTogXCJieXRlXCJcblx0XHRcdFx0fSxcblx0XHRcdFx0Z3JlZW46IHtcblx0XHRcdFx0XHRpZHg6IDEsXG5cdFx0XHRcdFx0dHlwZTogXCJieXRlXCJcblx0XHRcdFx0fSxcblx0XHRcdFx0Ymx1ZToge1xuXHRcdFx0XHRcdGlkeDogMixcblx0XHRcdFx0XHR0eXBlOiBcImJ5dGVcIlxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSxcblxuXHRcdGhzbGE6IHtcblx0XHRcdHByb3BzOiB7XG5cdFx0XHRcdGh1ZToge1xuXHRcdFx0XHRcdGlkeDogMCxcblx0XHRcdFx0XHR0eXBlOiBcImRlZ3JlZXNcIlxuXHRcdFx0XHR9LFxuXHRcdFx0XHRzYXR1cmF0aW9uOiB7XG5cdFx0XHRcdFx0aWR4OiAxLFxuXHRcdFx0XHRcdHR5cGU6IFwicGVyY2VudFwiXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGxpZ2h0bmVzczoge1xuXHRcdFx0XHRcdGlkeDogMixcblx0XHRcdFx0XHR0eXBlOiBcInBlcmNlbnRcIlxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHRwcm9wVHlwZXMgPSB7XG5cdFx0XCJieXRlXCI6IHtcblx0XHRcdGZsb29yOiB0cnVlLFxuXHRcdFx0bWF4OiAyNTVcblx0XHR9LFxuXHRcdFwicGVyY2VudFwiOiB7XG5cdFx0XHRtYXg6IDFcblx0XHR9LFxuXHRcdFwiZGVncmVlc1wiOiB7XG5cdFx0XHRtb2Q6IDM2MCxcblx0XHRcdGZsb29yOiB0cnVlXG5cdFx0fVxuXHR9LFxuXHRzdXBwb3J0ID0gY29sb3Iuc3VwcG9ydCA9IHt9LFxuXG5cdC8vIEVsZW1lbnQgZm9yIHN1cHBvcnQgdGVzdHNcblx0c3VwcG9ydEVsZW0gPSBqUXVlcnkoIFwiPHA+XCIgKVsgMCBdLFxuXG5cdC8vIENvbG9ycyA9IGpRdWVyeS5Db2xvci5uYW1lc1xuXHRjb2xvcnMsXG5cblx0Ly8gTG9jYWwgYWxpYXNlcyBvZiBmdW5jdGlvbnMgY2FsbGVkIG9mdGVuXG5cdGVhY2ggPSBqUXVlcnkuZWFjaDtcblxuLy8gRGV0ZXJtaW5lIHJnYmEgc3VwcG9ydCBpbW1lZGlhdGVseVxuc3VwcG9ydEVsZW0uc3R5bGUuY3NzVGV4dCA9IFwiYmFja2dyb3VuZC1jb2xvcjpyZ2JhKDEsMSwxLC41KVwiO1xuc3VwcG9ydC5yZ2JhID0gc3VwcG9ydEVsZW0uc3R5bGUuYmFja2dyb3VuZENvbG9yLmluZGV4T2YoIFwicmdiYVwiICkgPiAtMTtcblxuLy8gRGVmaW5lIGNhY2hlIG5hbWUgYW5kIGFscGhhIHByb3BlcnRpZXNcbi8vIGZvciByZ2JhIGFuZCBoc2xhIHNwYWNlc1xuZWFjaCggc3BhY2VzLCBmdW5jdGlvbiggc3BhY2VOYW1lLCBzcGFjZSApIHtcblx0c3BhY2UuY2FjaGUgPSBcIl9cIiArIHNwYWNlTmFtZTtcblx0c3BhY2UucHJvcHMuYWxwaGEgPSB7XG5cdFx0aWR4OiAzLFxuXHRcdHR5cGU6IFwicGVyY2VudFwiLFxuXHRcdGRlZjogMVxuXHR9O1xufSApO1xuXG5mdW5jdGlvbiBjbGFtcCggdmFsdWUsIHByb3AsIGFsbG93RW1wdHkgKSB7XG5cdHZhciB0eXBlID0gcHJvcFR5cGVzWyBwcm9wLnR5cGUgXSB8fCB7fTtcblxuXHRpZiAoIHZhbHVlID09IG51bGwgKSB7XG5cdFx0cmV0dXJuICggYWxsb3dFbXB0eSB8fCAhcHJvcC5kZWYgKSA/IG51bGwgOiBwcm9wLmRlZjtcblx0fVxuXG5cdC8vIH5+IGlzIGFuIHNob3J0IHdheSBvZiBkb2luZyBmbG9vciBmb3IgcG9zaXRpdmUgbnVtYmVyc1xuXHR2YWx1ZSA9IHR5cGUuZmxvb3IgPyB+fnZhbHVlIDogcGFyc2VGbG9hdCggdmFsdWUgKTtcblxuXHQvLyBJRSB3aWxsIHBhc3MgaW4gZW1wdHkgc3RyaW5ncyBhcyB2YWx1ZSBmb3IgYWxwaGEsXG5cdC8vIHdoaWNoIHdpbGwgaGl0IHRoaXMgY2FzZVxuXHRpZiAoIGlzTmFOKCB2YWx1ZSApICkge1xuXHRcdHJldHVybiBwcm9wLmRlZjtcblx0fVxuXG5cdGlmICggdHlwZS5tb2QgKSB7XG5cblx0XHQvLyBXZSBhZGQgbW9kIGJlZm9yZSBtb2RkaW5nIHRvIG1ha2Ugc3VyZSB0aGF0IG5lZ2F0aXZlcyB2YWx1ZXNcblx0XHQvLyBnZXQgY29udmVydGVkIHByb3Blcmx5OiAtMTAgLT4gMzUwXG5cdFx0cmV0dXJuICggdmFsdWUgKyB0eXBlLm1vZCApICUgdHlwZS5tb2Q7XG5cdH1cblxuXHQvLyBGb3Igbm93IGFsbCBwcm9wZXJ0eSB0eXBlcyB3aXRob3V0IG1vZCBoYXZlIG1pbiBhbmQgbWF4XG5cdHJldHVybiAwID4gdmFsdWUgPyAwIDogdHlwZS5tYXggPCB2YWx1ZSA/IHR5cGUubWF4IDogdmFsdWU7XG59XG5cbmZ1bmN0aW9uIHN0cmluZ1BhcnNlKCBzdHJpbmcgKSB7XG5cdHZhciBpbnN0ID0gY29sb3IoKSxcblx0XHRyZ2JhID0gaW5zdC5fcmdiYSA9IFtdO1xuXG5cdHN0cmluZyA9IHN0cmluZy50b0xvd2VyQ2FzZSgpO1xuXG5cdGVhY2goIHN0cmluZ1BhcnNlcnMsIGZ1bmN0aW9uKCBpLCBwYXJzZXIgKSB7XG5cdFx0dmFyIHBhcnNlZCxcblx0XHRcdG1hdGNoID0gcGFyc2VyLnJlLmV4ZWMoIHN0cmluZyApLFxuXHRcdFx0dmFsdWVzID0gbWF0Y2ggJiYgcGFyc2VyLnBhcnNlKCBtYXRjaCApLFxuXHRcdFx0c3BhY2VOYW1lID0gcGFyc2VyLnNwYWNlIHx8IFwicmdiYVwiO1xuXG5cdFx0aWYgKCB2YWx1ZXMgKSB7XG5cdFx0XHRwYXJzZWQgPSBpbnN0WyBzcGFjZU5hbWUgXSggdmFsdWVzICk7XG5cblx0XHRcdC8vIElmIHRoaXMgd2FzIGFuIHJnYmEgcGFyc2UgdGhlIGFzc2lnbm1lbnQgbWlnaHQgaGFwcGVuIHR3aWNlXG5cdFx0XHQvLyBvaCB3ZWxsLi4uLlxuXHRcdFx0aW5zdFsgc3BhY2VzWyBzcGFjZU5hbWUgXS5jYWNoZSBdID0gcGFyc2VkWyBzcGFjZXNbIHNwYWNlTmFtZSBdLmNhY2hlIF07XG5cdFx0XHRyZ2JhID0gaW5zdC5fcmdiYSA9IHBhcnNlZC5fcmdiYTtcblxuXHRcdFx0Ly8gRXhpdCBlYWNoKCBzdHJpbmdQYXJzZXJzICkgaGVyZSBiZWNhdXNlIHdlIG1hdGNoZWRcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdH0gKTtcblxuXHQvLyBGb3VuZCBhIHN0cmluZ1BhcnNlciB0aGF0IGhhbmRsZWQgaXRcblx0aWYgKCByZ2JhLmxlbmd0aCApIHtcblxuXHRcdC8vIElmIHRoaXMgY2FtZSBmcm9tIGEgcGFyc2VkIHN0cmluZywgZm9yY2UgXCJ0cmFuc3BhcmVudFwiIHdoZW4gYWxwaGEgaXMgMFxuXHRcdC8vIGNocm9tZSwgKGFuZCBtYXliZSBvdGhlcnMpIHJldHVybiBcInRyYW5zcGFyZW50XCIgYXMgcmdiYSgwLDAsMCwwKVxuXHRcdGlmICggcmdiYS5qb2luKCkgPT09IFwiMCwwLDAsMFwiICkge1xuXHRcdFx0alF1ZXJ5LmV4dGVuZCggcmdiYSwgY29sb3JzLnRyYW5zcGFyZW50ICk7XG5cdFx0fVxuXHRcdHJldHVybiBpbnN0O1xuXHR9XG5cblx0Ly8gTmFtZWQgY29sb3JzXG5cdHJldHVybiBjb2xvcnNbIHN0cmluZyBdO1xufVxuXG5jb2xvci5mbiA9IGpRdWVyeS5leHRlbmQoIGNvbG9yLnByb3RvdHlwZSwge1xuXHRwYXJzZTogZnVuY3Rpb24oIHJlZCwgZ3JlZW4sIGJsdWUsIGFscGhhICkge1xuXHRcdGlmICggcmVkID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR0aGlzLl9yZ2JhID0gWyBudWxsLCBudWxsLCBudWxsLCBudWxsIF07XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9XG5cdFx0aWYgKCByZWQuanF1ZXJ5IHx8IHJlZC5ub2RlVHlwZSApIHtcblx0XHRcdHJlZCA9IGpRdWVyeSggcmVkICkuY3NzKCBncmVlbiApO1xuXHRcdFx0Z3JlZW4gPSB1bmRlZmluZWQ7XG5cdFx0fVxuXG5cdFx0dmFyIGluc3QgPSB0aGlzLFxuXHRcdFx0dHlwZSA9IGpRdWVyeS50eXBlKCByZWQgKSxcblx0XHRcdHJnYmEgPSB0aGlzLl9yZ2JhID0gW107XG5cblx0XHQvLyBNb3JlIHRoYW4gMSBhcmd1bWVudCBzcGVjaWZpZWQgLSBhc3N1bWUgKCByZWQsIGdyZWVuLCBibHVlLCBhbHBoYSApXG5cdFx0aWYgKCBncmVlbiAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmVkID0gWyByZWQsIGdyZWVuLCBibHVlLCBhbHBoYSBdO1xuXHRcdFx0dHlwZSA9IFwiYXJyYXlcIjtcblx0XHR9XG5cblx0XHRpZiAoIHR5cGUgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5wYXJzZSggc3RyaW5nUGFyc2UoIHJlZCApIHx8IGNvbG9ycy5fZGVmYXVsdCApO1xuXHRcdH1cblxuXHRcdGlmICggdHlwZSA9PT0gXCJhcnJheVwiICkge1xuXHRcdFx0ZWFjaCggc3BhY2VzLnJnYmEucHJvcHMsIGZ1bmN0aW9uKCBrZXksIHByb3AgKSB7XG5cdFx0XHRcdHJnYmFbIHByb3AuaWR4IF0gPSBjbGFtcCggcmVkWyBwcm9wLmlkeCBdLCBwcm9wICk7XG5cdFx0XHR9ICk7XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9XG5cblx0XHRpZiAoIHR5cGUgPT09IFwib2JqZWN0XCIgKSB7XG5cdFx0XHRpZiAoIHJlZCBpbnN0YW5jZW9mIGNvbG9yICkge1xuXHRcdFx0XHRlYWNoKCBzcGFjZXMsIGZ1bmN0aW9uKCBzcGFjZU5hbWUsIHNwYWNlICkge1xuXHRcdFx0XHRcdGlmICggcmVkWyBzcGFjZS5jYWNoZSBdICkge1xuXHRcdFx0XHRcdFx0aW5zdFsgc3BhY2UuY2FjaGUgXSA9IHJlZFsgc3BhY2UuY2FjaGUgXS5zbGljZSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0ZWFjaCggc3BhY2VzLCBmdW5jdGlvbiggc3BhY2VOYW1lLCBzcGFjZSApIHtcblx0XHRcdFx0XHR2YXIgY2FjaGUgPSBzcGFjZS5jYWNoZTtcblx0XHRcdFx0XHRlYWNoKCBzcGFjZS5wcm9wcywgZnVuY3Rpb24oIGtleSwgcHJvcCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gSWYgdGhlIGNhY2hlIGRvZXNuJ3QgZXhpc3QsIGFuZCB3ZSBrbm93IGhvdyB0byBjb252ZXJ0XG5cdFx0XHRcdFx0XHRpZiAoICFpbnN0WyBjYWNoZSBdICYmIHNwYWNlLnRvICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIElmIHRoZSB2YWx1ZSB3YXMgbnVsbCwgd2UgZG9uJ3QgbmVlZCB0byBjb3B5IGl0XG5cdFx0XHRcdFx0XHRcdC8vIGlmIHRoZSBrZXkgd2FzIGFscGhhLCB3ZSBkb24ndCBuZWVkIHRvIGNvcHkgaXQgZWl0aGVyXG5cdFx0XHRcdFx0XHRcdGlmICgga2V5ID09PSBcImFscGhhXCIgfHwgcmVkWyBrZXkgXSA9PSBudWxsICkge1xuXHRcdFx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRpbnN0WyBjYWNoZSBdID0gc3BhY2UudG8oIGluc3QuX3JnYmEgKTtcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Ly8gVGhpcyBpcyB0aGUgb25seSBjYXNlIHdoZXJlIHdlIGFsbG93IG51bGxzIGZvciBBTEwgcHJvcGVydGllcy5cblx0XHRcdFx0XHRcdC8vIGNhbGwgY2xhbXAgd2l0aCBhbHdheXNBbGxvd0VtcHR5XG5cdFx0XHRcdFx0XHRpbnN0WyBjYWNoZSBdWyBwcm9wLmlkeCBdID0gY2xhbXAoIHJlZFsga2V5IF0sIHByb3AsIHRydWUgKTtcblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0XHQvLyBFdmVyeXRoaW5nIGRlZmluZWQgYnV0IGFscGhhP1xuXHRcdFx0XHRcdGlmICggaW5zdFsgY2FjaGUgXSAmJlxuXHRcdFx0XHRcdFx0XHRqUXVlcnkuaW5BcnJheSggbnVsbCwgaW5zdFsgY2FjaGUgXS5zbGljZSggMCwgMyApICkgPCAwICkge1xuXG5cdFx0XHRcdFx0XHQvLyBVc2UgdGhlIGRlZmF1bHQgb2YgMVxuXHRcdFx0XHRcdFx0aW5zdFsgY2FjaGUgXVsgMyBdID0gMTtcblx0XHRcdFx0XHRcdGlmICggc3BhY2UuZnJvbSApIHtcblx0XHRcdFx0XHRcdFx0aW5zdC5fcmdiYSA9IHNwYWNlLmZyb20oIGluc3RbIGNhY2hlIF0gKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH1cblx0fSxcblx0aXM6IGZ1bmN0aW9uKCBjb21wYXJlICkge1xuXHRcdHZhciBpcyA9IGNvbG9yKCBjb21wYXJlICksXG5cdFx0XHRzYW1lID0gdHJ1ZSxcblx0XHRcdGluc3QgPSB0aGlzO1xuXG5cdFx0ZWFjaCggc3BhY2VzLCBmdW5jdGlvbiggXywgc3BhY2UgKSB7XG5cdFx0XHR2YXIgbG9jYWxDYWNoZSxcblx0XHRcdFx0aXNDYWNoZSA9IGlzWyBzcGFjZS5jYWNoZSBdO1xuXHRcdFx0aWYgKCBpc0NhY2hlICkge1xuXHRcdFx0XHRsb2NhbENhY2hlID0gaW5zdFsgc3BhY2UuY2FjaGUgXSB8fCBzcGFjZS50byAmJiBzcGFjZS50byggaW5zdC5fcmdiYSApIHx8IFtdO1xuXHRcdFx0XHRlYWNoKCBzcGFjZS5wcm9wcywgZnVuY3Rpb24oIF8sIHByb3AgKSB7XG5cdFx0XHRcdFx0aWYgKCBpc0NhY2hlWyBwcm9wLmlkeCBdICE9IG51bGwgKSB7XG5cdFx0XHRcdFx0XHRzYW1lID0gKCBpc0NhY2hlWyBwcm9wLmlkeCBdID09PSBsb2NhbENhY2hlWyBwcm9wLmlkeCBdICk7XG5cdFx0XHRcdFx0XHRyZXR1cm4gc2FtZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBzYW1lO1xuXHRcdH0gKTtcblx0XHRyZXR1cm4gc2FtZTtcblx0fSxcblx0X3NwYWNlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdXNlZCA9IFtdLFxuXHRcdFx0aW5zdCA9IHRoaXM7XG5cdFx0ZWFjaCggc3BhY2VzLCBmdW5jdGlvbiggc3BhY2VOYW1lLCBzcGFjZSApIHtcblx0XHRcdGlmICggaW5zdFsgc3BhY2UuY2FjaGUgXSApIHtcblx0XHRcdFx0dXNlZC5wdXNoKCBzcGFjZU5hbWUgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0cmV0dXJuIHVzZWQucG9wKCk7XG5cdH0sXG5cdHRyYW5zaXRpb246IGZ1bmN0aW9uKCBvdGhlciwgZGlzdGFuY2UgKSB7XG5cdFx0dmFyIGVuZCA9IGNvbG9yKCBvdGhlciApLFxuXHRcdFx0c3BhY2VOYW1lID0gZW5kLl9zcGFjZSgpLFxuXHRcdFx0c3BhY2UgPSBzcGFjZXNbIHNwYWNlTmFtZSBdLFxuXHRcdFx0c3RhcnRDb2xvciA9IHRoaXMuYWxwaGEoKSA9PT0gMCA/IGNvbG9yKCBcInRyYW5zcGFyZW50XCIgKSA6IHRoaXMsXG5cdFx0XHRzdGFydCA9IHN0YXJ0Q29sb3JbIHNwYWNlLmNhY2hlIF0gfHwgc3BhY2UudG8oIHN0YXJ0Q29sb3IuX3JnYmEgKSxcblx0XHRcdHJlc3VsdCA9IHN0YXJ0LnNsaWNlKCk7XG5cblx0XHRlbmQgPSBlbmRbIHNwYWNlLmNhY2hlIF07XG5cdFx0ZWFjaCggc3BhY2UucHJvcHMsIGZ1bmN0aW9uKCBrZXksIHByb3AgKSB7XG5cdFx0XHR2YXIgaW5kZXggPSBwcm9wLmlkeCxcblx0XHRcdFx0c3RhcnRWYWx1ZSA9IHN0YXJ0WyBpbmRleCBdLFxuXHRcdFx0XHRlbmRWYWx1ZSA9IGVuZFsgaW5kZXggXSxcblx0XHRcdFx0dHlwZSA9IHByb3BUeXBlc1sgcHJvcC50eXBlIF0gfHwge307XG5cblx0XHRcdC8vIElmIG51bGwsIGRvbid0IG92ZXJyaWRlIHN0YXJ0IHZhbHVlXG5cdFx0XHRpZiAoIGVuZFZhbHVlID09PSBudWxsICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdC8vIElmIG51bGwgLSB1c2UgZW5kXG5cdFx0XHRpZiAoIHN0YXJ0VmFsdWUgPT09IG51bGwgKSB7XG5cdFx0XHRcdHJlc3VsdFsgaW5kZXggXSA9IGVuZFZhbHVlO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aWYgKCB0eXBlLm1vZCApIHtcblx0XHRcdFx0XHRpZiAoIGVuZFZhbHVlIC0gc3RhcnRWYWx1ZSA+IHR5cGUubW9kIC8gMiApIHtcblx0XHRcdFx0XHRcdHN0YXJ0VmFsdWUgKz0gdHlwZS5tb2Q7XG5cdFx0XHRcdFx0fSBlbHNlIGlmICggc3RhcnRWYWx1ZSAtIGVuZFZhbHVlID4gdHlwZS5tb2QgLyAyICkge1xuXHRcdFx0XHRcdFx0c3RhcnRWYWx1ZSAtPSB0eXBlLm1vZDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0cmVzdWx0WyBpbmRleCBdID0gY2xhbXAoICggZW5kVmFsdWUgLSBzdGFydFZhbHVlICkgKiBkaXN0YW5jZSArIHN0YXJ0VmFsdWUsIHByb3AgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0cmV0dXJuIHRoaXNbIHNwYWNlTmFtZSBdKCByZXN1bHQgKTtcblx0fSxcblx0YmxlbmQ6IGZ1bmN0aW9uKCBvcGFxdWUgKSB7XG5cblx0XHQvLyBJZiB3ZSBhcmUgYWxyZWFkeSBvcGFxdWUgLSByZXR1cm4gb3Vyc2VsZlxuXHRcdGlmICggdGhpcy5fcmdiYVsgMyBdID09PSAxICkge1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXG5cdFx0dmFyIHJnYiA9IHRoaXMuX3JnYmEuc2xpY2UoKSxcblx0XHRcdGEgPSByZ2IucG9wKCksXG5cdFx0XHRibGVuZCA9IGNvbG9yKCBvcGFxdWUgKS5fcmdiYTtcblxuXHRcdHJldHVybiBjb2xvciggalF1ZXJ5Lm1hcCggcmdiLCBmdW5jdGlvbiggdiwgaSApIHtcblx0XHRcdHJldHVybiAoIDEgLSBhICkgKiBibGVuZFsgaSBdICsgYSAqIHY7XG5cdFx0fSApICk7XG5cdH0sXG5cdHRvUmdiYVN0cmluZzogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHByZWZpeCA9IFwicmdiYShcIixcblx0XHRcdHJnYmEgPSBqUXVlcnkubWFwKCB0aGlzLl9yZ2JhLCBmdW5jdGlvbiggdiwgaSApIHtcblx0XHRcdFx0cmV0dXJuIHYgPT0gbnVsbCA/ICggaSA+IDIgPyAxIDogMCApIDogdjtcblx0XHRcdH0gKTtcblxuXHRcdGlmICggcmdiYVsgMyBdID09PSAxICkge1xuXHRcdFx0cmdiYS5wb3AoKTtcblx0XHRcdHByZWZpeCA9IFwicmdiKFwiO1xuXHRcdH1cblxuXHRcdHJldHVybiBwcmVmaXggKyByZ2JhLmpvaW4oKSArIFwiKVwiO1xuXHR9LFxuXHR0b0hzbGFTdHJpbmc6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBwcmVmaXggPSBcImhzbGEoXCIsXG5cdFx0XHRoc2xhID0galF1ZXJ5Lm1hcCggdGhpcy5oc2xhKCksIGZ1bmN0aW9uKCB2LCBpICkge1xuXHRcdFx0XHRpZiAoIHYgPT0gbnVsbCApIHtcblx0XHRcdFx0XHR2ID0gaSA+IDIgPyAxIDogMDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIENhdGNoIDEgYW5kIDJcblx0XHRcdFx0aWYgKCBpICYmIGkgPCAzICkge1xuXHRcdFx0XHRcdHYgPSBNYXRoLnJvdW5kKCB2ICogMTAwICkgKyBcIiVcIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gdjtcblx0XHRcdH0gKTtcblxuXHRcdGlmICggaHNsYVsgMyBdID09PSAxICkge1xuXHRcdFx0aHNsYS5wb3AoKTtcblx0XHRcdHByZWZpeCA9IFwiaHNsKFwiO1xuXHRcdH1cblx0XHRyZXR1cm4gcHJlZml4ICsgaHNsYS5qb2luKCkgKyBcIilcIjtcblx0fSxcblx0dG9IZXhTdHJpbmc6IGZ1bmN0aW9uKCBpbmNsdWRlQWxwaGEgKSB7XG5cdFx0dmFyIHJnYmEgPSB0aGlzLl9yZ2JhLnNsaWNlKCksXG5cdFx0XHRhbHBoYSA9IHJnYmEucG9wKCk7XG5cblx0XHRpZiAoIGluY2x1ZGVBbHBoYSApIHtcblx0XHRcdHJnYmEucHVzaCggfn4oIGFscGhhICogMjU1ICkgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gXCIjXCIgKyBqUXVlcnkubWFwKCByZ2JhLCBmdW5jdGlvbiggdiApIHtcblxuXHRcdFx0Ly8gRGVmYXVsdCB0byAwIHdoZW4gbnVsbHMgZXhpc3Rcblx0XHRcdHYgPSAoIHYgfHwgMCApLnRvU3RyaW5nKCAxNiApO1xuXHRcdFx0cmV0dXJuIHYubGVuZ3RoID09PSAxID8gXCIwXCIgKyB2IDogdjtcblx0XHR9ICkuam9pbiggXCJcIiApO1xuXHR9LFxuXHR0b1N0cmluZzogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3JnYmFbIDMgXSA9PT0gMCA/IFwidHJhbnNwYXJlbnRcIiA6IHRoaXMudG9SZ2JhU3RyaW5nKCk7XG5cdH1cbn0gKTtcbmNvbG9yLmZuLnBhcnNlLnByb3RvdHlwZSA9IGNvbG9yLmZuO1xuXG4vLyBIc2xhIGNvbnZlcnNpb25zIGFkYXB0ZWQgZnJvbTpcbi8vIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvbWFhc2hhYWNrL3NvdXJjZS9icm93c2UvcGFja2FnZXMvZ3JhcGhpY3MvdHJ1bmsvc3JjL2dyYXBoaWNzL2NvbG9ycy9IVUUyUkdCLmFzP3I9NTAyMVxuXG5mdW5jdGlvbiBodWUycmdiKCBwLCBxLCBoICkge1xuXHRoID0gKCBoICsgMSApICUgMTtcblx0aWYgKCBoICogNiA8IDEgKSB7XG5cdFx0cmV0dXJuIHAgKyAoIHEgLSBwICkgKiBoICogNjtcblx0fVxuXHRpZiAoIGggKiAyIDwgMSApIHtcblx0XHRyZXR1cm4gcTtcblx0fVxuXHRpZiAoIGggKiAzIDwgMiApIHtcblx0XHRyZXR1cm4gcCArICggcSAtIHAgKSAqICggKCAyIC8gMyApIC0gaCApICogNjtcblx0fVxuXHRyZXR1cm4gcDtcbn1cblxuc3BhY2VzLmhzbGEudG8gPSBmdW5jdGlvbiggcmdiYSApIHtcblx0aWYgKCByZ2JhWyAwIF0gPT0gbnVsbCB8fCByZ2JhWyAxIF0gPT0gbnVsbCB8fCByZ2JhWyAyIF0gPT0gbnVsbCApIHtcblx0XHRyZXR1cm4gWyBudWxsLCBudWxsLCBudWxsLCByZ2JhWyAzIF0gXTtcblx0fVxuXHR2YXIgciA9IHJnYmFbIDAgXSAvIDI1NSxcblx0XHRnID0gcmdiYVsgMSBdIC8gMjU1LFxuXHRcdGIgPSByZ2JhWyAyIF0gLyAyNTUsXG5cdFx0YSA9IHJnYmFbIDMgXSxcblx0XHRtYXggPSBNYXRoLm1heCggciwgZywgYiApLFxuXHRcdG1pbiA9IE1hdGgubWluKCByLCBnLCBiICksXG5cdFx0ZGlmZiA9IG1heCAtIG1pbixcblx0XHRhZGQgPSBtYXggKyBtaW4sXG5cdFx0bCA9IGFkZCAqIDAuNSxcblx0XHRoLCBzO1xuXG5cdGlmICggbWluID09PSBtYXggKSB7XG5cdFx0aCA9IDA7XG5cdH0gZWxzZSBpZiAoIHIgPT09IG1heCApIHtcblx0XHRoID0gKCA2MCAqICggZyAtIGIgKSAvIGRpZmYgKSArIDM2MDtcblx0fSBlbHNlIGlmICggZyA9PT0gbWF4ICkge1xuXHRcdGggPSAoIDYwICogKCBiIC0gciApIC8gZGlmZiApICsgMTIwO1xuXHR9IGVsc2Uge1xuXHRcdGggPSAoIDYwICogKCByIC0gZyApIC8gZGlmZiApICsgMjQwO1xuXHR9XG5cblx0Ly8gQ2hyb21hIChkaWZmKSA9PSAwIG1lYW5zIGdyZXlzY2FsZSB3aGljaCwgYnkgZGVmaW5pdGlvbiwgc2F0dXJhdGlvbiA9IDAlXG5cdC8vIG90aGVyd2lzZSwgc2F0dXJhdGlvbiBpcyBiYXNlZCBvbiB0aGUgcmF0aW8gb2YgY2hyb21hIChkaWZmKSB0byBsaWdodG5lc3MgKGFkZClcblx0aWYgKCBkaWZmID09PSAwICkge1xuXHRcdHMgPSAwO1xuXHR9IGVsc2UgaWYgKCBsIDw9IDAuNSApIHtcblx0XHRzID0gZGlmZiAvIGFkZDtcblx0fSBlbHNlIHtcblx0XHRzID0gZGlmZiAvICggMiAtIGFkZCApO1xuXHR9XG5cdHJldHVybiBbIE1hdGgucm91bmQoIGggKSAlIDM2MCwgcywgbCwgYSA9PSBudWxsID8gMSA6IGEgXTtcbn07XG5cbnNwYWNlcy5oc2xhLmZyb20gPSBmdW5jdGlvbiggaHNsYSApIHtcblx0aWYgKCBoc2xhWyAwIF0gPT0gbnVsbCB8fCBoc2xhWyAxIF0gPT0gbnVsbCB8fCBoc2xhWyAyIF0gPT0gbnVsbCApIHtcblx0XHRyZXR1cm4gWyBudWxsLCBudWxsLCBudWxsLCBoc2xhWyAzIF0gXTtcblx0fVxuXHR2YXIgaCA9IGhzbGFbIDAgXSAvIDM2MCxcblx0XHRzID0gaHNsYVsgMSBdLFxuXHRcdGwgPSBoc2xhWyAyIF0sXG5cdFx0YSA9IGhzbGFbIDMgXSxcblx0XHRxID0gbCA8PSAwLjUgPyBsICogKCAxICsgcyApIDogbCArIHMgLSBsICogcyxcblx0XHRwID0gMiAqIGwgLSBxO1xuXG5cdHJldHVybiBbXG5cdFx0TWF0aC5yb3VuZCggaHVlMnJnYiggcCwgcSwgaCArICggMSAvIDMgKSApICogMjU1ICksXG5cdFx0TWF0aC5yb3VuZCggaHVlMnJnYiggcCwgcSwgaCApICogMjU1ICksXG5cdFx0TWF0aC5yb3VuZCggaHVlMnJnYiggcCwgcSwgaCAtICggMSAvIDMgKSApICogMjU1ICksXG5cdFx0YVxuXHRdO1xufTtcblxuZWFjaCggc3BhY2VzLCBmdW5jdGlvbiggc3BhY2VOYW1lLCBzcGFjZSApIHtcblx0dmFyIHByb3BzID0gc3BhY2UucHJvcHMsXG5cdFx0Y2FjaGUgPSBzcGFjZS5jYWNoZSxcblx0XHR0byA9IHNwYWNlLnRvLFxuXHRcdGZyb20gPSBzcGFjZS5mcm9tO1xuXG5cdC8vIE1ha2VzIHJnYmEoKSBhbmQgaHNsYSgpXG5cdGNvbG9yLmZuWyBzcGFjZU5hbWUgXSA9IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblxuXHRcdC8vIEdlbmVyYXRlIGEgY2FjaGUgZm9yIHRoaXMgc3BhY2UgaWYgaXQgZG9lc24ndCBleGlzdFxuXHRcdGlmICggdG8gJiYgIXRoaXNbIGNhY2hlIF0gKSB7XG5cdFx0XHR0aGlzWyBjYWNoZSBdID0gdG8oIHRoaXMuX3JnYmEgKTtcblx0XHR9XG5cdFx0aWYgKCB2YWx1ZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmV0dXJuIHRoaXNbIGNhY2hlIF0uc2xpY2UoKTtcblx0XHR9XG5cblx0XHR2YXIgcmV0LFxuXHRcdFx0dHlwZSA9IGpRdWVyeS50eXBlKCB2YWx1ZSApLFxuXHRcdFx0YXJyID0gKCB0eXBlID09PSBcImFycmF5XCIgfHwgdHlwZSA9PT0gXCJvYmplY3RcIiApID8gdmFsdWUgOiBhcmd1bWVudHMsXG5cdFx0XHRsb2NhbCA9IHRoaXNbIGNhY2hlIF0uc2xpY2UoKTtcblxuXHRcdGVhY2goIHByb3BzLCBmdW5jdGlvbigga2V5LCBwcm9wICkge1xuXHRcdFx0dmFyIHZhbCA9IGFyclsgdHlwZSA9PT0gXCJvYmplY3RcIiA/IGtleSA6IHByb3AuaWR4IF07XG5cdFx0XHRpZiAoIHZhbCA9PSBudWxsICkge1xuXHRcdFx0XHR2YWwgPSBsb2NhbFsgcHJvcC5pZHggXTtcblx0XHRcdH1cblx0XHRcdGxvY2FsWyBwcm9wLmlkeCBdID0gY2xhbXAoIHZhbCwgcHJvcCApO1xuXHRcdH0gKTtcblxuXHRcdGlmICggZnJvbSApIHtcblx0XHRcdHJldCA9IGNvbG9yKCBmcm9tKCBsb2NhbCApICk7XG5cdFx0XHRyZXRbIGNhY2hlIF0gPSBsb2NhbDtcblx0XHRcdHJldHVybiByZXQ7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJldHVybiBjb2xvciggbG9jYWwgKTtcblx0XHR9XG5cdH07XG5cblx0Ly8gTWFrZXMgcmVkKCkgZ3JlZW4oKSBibHVlKCkgYWxwaGEoKSBodWUoKSBzYXR1cmF0aW9uKCkgbGlnaHRuZXNzKClcblx0ZWFjaCggcHJvcHMsIGZ1bmN0aW9uKCBrZXksIHByb3AgKSB7XG5cblx0XHQvLyBBbHBoYSBpcyBpbmNsdWRlZCBpbiBtb3JlIHRoYW4gb25lIHNwYWNlXG5cdFx0aWYgKCBjb2xvci5mblsga2V5IF0gKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGNvbG9yLmZuWyBrZXkgXSA9IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdHZhciB2dHlwZSA9IGpRdWVyeS50eXBlKCB2YWx1ZSApLFxuXHRcdFx0XHRmbiA9ICgga2V5ID09PSBcImFscGhhXCIgPyAoIHRoaXMuX2hzbGEgPyBcImhzbGFcIiA6IFwicmdiYVwiICkgOiBzcGFjZU5hbWUgKSxcblx0XHRcdFx0bG9jYWwgPSB0aGlzWyBmbiBdKCksXG5cdFx0XHRcdGN1ciA9IGxvY2FsWyBwcm9wLmlkeCBdLFxuXHRcdFx0XHRtYXRjaDtcblxuXHRcdFx0aWYgKCB2dHlwZSA9PT0gXCJ1bmRlZmluZWRcIiApIHtcblx0XHRcdFx0cmV0dXJuIGN1cjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB2dHlwZSA9PT0gXCJmdW5jdGlvblwiICkge1xuXHRcdFx0XHR2YWx1ZSA9IHZhbHVlLmNhbGwoIHRoaXMsIGN1ciApO1xuXHRcdFx0XHR2dHlwZSA9IGpRdWVyeS50eXBlKCB2YWx1ZSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCB2YWx1ZSA9PSBudWxsICYmIHByb3AuZW1wdHkgKSB7XG5cdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCB2dHlwZSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdFx0bWF0Y2ggPSBycGx1c2VxdWFscy5leGVjKCB2YWx1ZSApO1xuXHRcdFx0XHRpZiAoIG1hdGNoICkge1xuXHRcdFx0XHRcdHZhbHVlID0gY3VyICsgcGFyc2VGbG9hdCggbWF0Y2hbIDIgXSApICogKCBtYXRjaFsgMSBdID09PSBcIitcIiA/IDEgOiAtMSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRsb2NhbFsgcHJvcC5pZHggXSA9IHZhbHVlO1xuXHRcdFx0cmV0dXJuIHRoaXNbIGZuIF0oIGxvY2FsICk7XG5cdFx0fTtcblx0fSApO1xufSApO1xuXG4vLyBBZGQgY3NzSG9vayBhbmQgLmZ4LnN0ZXAgZnVuY3Rpb24gZm9yIGVhY2ggbmFtZWQgaG9vay5cbi8vIGFjY2VwdCBhIHNwYWNlIHNlcGFyYXRlZCBzdHJpbmcgb2YgcHJvcGVydGllc1xuY29sb3IuaG9vayA9IGZ1bmN0aW9uKCBob29rICkge1xuXHR2YXIgaG9va3MgPSBob29rLnNwbGl0KCBcIiBcIiApO1xuXHRlYWNoKCBob29rcywgZnVuY3Rpb24oIGksIGhvb2sgKSB7XG5cdFx0alF1ZXJ5LmNzc0hvb2tzWyBob29rIF0gPSB7XG5cdFx0XHRzZXQ6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSApIHtcblx0XHRcdFx0dmFyIHBhcnNlZCwgY3VyRWxlbSxcblx0XHRcdFx0XHRiYWNrZ3JvdW5kQ29sb3IgPSBcIlwiO1xuXG5cdFx0XHRcdGlmICggdmFsdWUgIT09IFwidHJhbnNwYXJlbnRcIiAmJiAoIGpRdWVyeS50eXBlKCB2YWx1ZSApICE9PSBcInN0cmluZ1wiIHx8XG5cdFx0XHRcdFx0XHQoIHBhcnNlZCA9IHN0cmluZ1BhcnNlKCB2YWx1ZSApICkgKSApIHtcblx0XHRcdFx0XHR2YWx1ZSA9IGNvbG9yKCBwYXJzZWQgfHwgdmFsdWUgKTtcblx0XHRcdFx0XHRpZiAoICFzdXBwb3J0LnJnYmEgJiYgdmFsdWUuX3JnYmFbIDMgXSAhPT0gMSApIHtcblx0XHRcdFx0XHRcdGN1ckVsZW0gPSBob29rID09PSBcImJhY2tncm91bmRDb2xvclwiID8gZWxlbS5wYXJlbnROb2RlIDogZWxlbTtcblx0XHRcdFx0XHRcdHdoaWxlIChcblx0XHRcdFx0XHRcdFx0KCBiYWNrZ3JvdW5kQ29sb3IgPT09IFwiXCIgfHwgYmFja2dyb3VuZENvbG9yID09PSBcInRyYW5zcGFyZW50XCIgKSAmJlxuXHRcdFx0XHRcdFx0XHRjdXJFbGVtICYmIGN1ckVsZW0uc3R5bGVcblx0XHRcdFx0XHRcdCkge1xuXHRcdFx0XHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdFx0XHRcdGJhY2tncm91bmRDb2xvciA9IGpRdWVyeS5jc3MoIGN1ckVsZW0sIFwiYmFja2dyb3VuZENvbG9yXCIgKTtcblx0XHRcdFx0XHRcdFx0XHRjdXJFbGVtID0gY3VyRWxlbS5wYXJlbnROb2RlO1xuXHRcdFx0XHRcdFx0XHR9IGNhdGNoICggZSApIHtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR2YWx1ZSA9IHZhbHVlLmJsZW5kKCBiYWNrZ3JvdW5kQ29sb3IgJiYgYmFja2dyb3VuZENvbG9yICE9PSBcInRyYW5zcGFyZW50XCIgP1xuXHRcdFx0XHRcdFx0XHRiYWNrZ3JvdW5kQ29sb3IgOlxuXHRcdFx0XHRcdFx0XHRcIl9kZWZhdWx0XCIgKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR2YWx1ZSA9IHZhbHVlLnRvUmdiYVN0cmluZygpO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0ZWxlbS5zdHlsZVsgaG9vayBdID0gdmFsdWU7XG5cdFx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXG5cdFx0XHRcdFx0Ly8gV3JhcHBlZCB0byBwcmV2ZW50IElFIGZyb20gdGhyb3dpbmcgZXJyb3JzIG9uIFwiaW52YWxpZFwiIHZhbHVlcyBsaWtlXG5cdFx0XHRcdFx0Ly8gJ2F1dG8nIG9yICdpbmhlcml0J1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fTtcblx0XHRqUXVlcnkuZnguc3RlcFsgaG9vayBdID0gZnVuY3Rpb24oIGZ4ICkge1xuXHRcdFx0aWYgKCAhZnguY29sb3JJbml0ICkge1xuXHRcdFx0XHRmeC5zdGFydCA9IGNvbG9yKCBmeC5lbGVtLCBob29rICk7XG5cdFx0XHRcdGZ4LmVuZCA9IGNvbG9yKCBmeC5lbmQgKTtcblx0XHRcdFx0ZnguY29sb3JJbml0ID0gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdGpRdWVyeS5jc3NIb29rc1sgaG9vayBdLnNldCggZnguZWxlbSwgZnguc3RhcnQudHJhbnNpdGlvbiggZnguZW5kLCBmeC5wb3MgKSApO1xuXHRcdH07XG5cdH0gKTtcblxufTtcblxuY29sb3IuaG9vayggc3RlcEhvb2tzICk7XG5cbmpRdWVyeS5jc3NIb29rcy5ib3JkZXJDb2xvciA9IHtcblx0ZXhwYW5kOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dmFyIGV4cGFuZGVkID0ge307XG5cblx0XHRlYWNoKCBbIFwiVG9wXCIsIFwiUmlnaHRcIiwgXCJCb3R0b21cIiwgXCJMZWZ0XCIgXSwgZnVuY3Rpb24oIGksIHBhcnQgKSB7XG5cdFx0XHRleHBhbmRlZFsgXCJib3JkZXJcIiArIHBhcnQgKyBcIkNvbG9yXCIgXSA9IHZhbHVlO1xuXHRcdH0gKTtcblx0XHRyZXR1cm4gZXhwYW5kZWQ7XG5cdH1cbn07XG5cbi8vIEJhc2ljIGNvbG9yIG5hbWVzIG9ubHkuXG4vLyBVc2FnZSBvZiBhbnkgb2YgdGhlIG90aGVyIGNvbG9yIG5hbWVzIHJlcXVpcmVzIGFkZGluZyB5b3Vyc2VsZiBvciBpbmNsdWRpbmdcbi8vIGpxdWVyeS5jb2xvci5zdmctbmFtZXMuanMuXG5jb2xvcnMgPSBqUXVlcnkuQ29sb3IubmFtZXMgPSB7XG5cblx0Ly8gNC4xLiBCYXNpYyBjb2xvciBrZXl3b3Jkc1xuXHRhcXVhOiBcIiMwMGZmZmZcIixcblx0YmxhY2s6IFwiIzAwMDAwMFwiLFxuXHRibHVlOiBcIiMwMDAwZmZcIixcblx0ZnVjaHNpYTogXCIjZmYwMGZmXCIsXG5cdGdyYXk6IFwiIzgwODA4MFwiLFxuXHRncmVlbjogXCIjMDA4MDAwXCIsXG5cdGxpbWU6IFwiIzAwZmYwMFwiLFxuXHRtYXJvb246IFwiIzgwMDAwMFwiLFxuXHRuYXZ5OiBcIiMwMDAwODBcIixcblx0b2xpdmU6IFwiIzgwODAwMFwiLFxuXHRwdXJwbGU6IFwiIzgwMDA4MFwiLFxuXHRyZWQ6IFwiI2ZmMDAwMFwiLFxuXHRzaWx2ZXI6IFwiI2MwYzBjMFwiLFxuXHR0ZWFsOiBcIiMwMDgwODBcIixcblx0d2hpdGU6IFwiI2ZmZmZmZlwiLFxuXHR5ZWxsb3c6IFwiI2ZmZmYwMFwiLFxuXG5cdC8vIDQuMi4zLiBcInRyYW5zcGFyZW50XCIgY29sb3Iga2V5d29yZFxuXHR0cmFuc3BhcmVudDogWyBudWxsLCBudWxsLCBudWxsLCAwIF0sXG5cblx0X2RlZmF1bHQ6IFwiI2ZmZmZmZlwiXG59O1xuXG59ICkoIGpRdWVyeSApO1xuXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiBDTEFTUyBBTklNQVRJT05TICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG4oIGZ1bmN0aW9uKCkge1xuXG52YXIgY2xhc3NBbmltYXRpb25BY3Rpb25zID0gWyBcImFkZFwiLCBcInJlbW92ZVwiLCBcInRvZ2dsZVwiIF0sXG5cdHNob3J0aGFuZFN0eWxlcyA9IHtcblx0XHRib3JkZXI6IDEsXG5cdFx0Ym9yZGVyQm90dG9tOiAxLFxuXHRcdGJvcmRlckNvbG9yOiAxLFxuXHRcdGJvcmRlckxlZnQ6IDEsXG5cdFx0Ym9yZGVyUmlnaHQ6IDEsXG5cdFx0Ym9yZGVyVG9wOiAxLFxuXHRcdGJvcmRlcldpZHRoOiAxLFxuXHRcdG1hcmdpbjogMSxcblx0XHRwYWRkaW5nOiAxXG5cdH07XG5cbiQuZWFjaChcblx0WyBcImJvcmRlckxlZnRTdHlsZVwiLCBcImJvcmRlclJpZ2h0U3R5bGVcIiwgXCJib3JkZXJCb3R0b21TdHlsZVwiLCBcImJvcmRlclRvcFN0eWxlXCIgXSxcblx0ZnVuY3Rpb24oIF8sIHByb3AgKSB7XG5cdFx0JC5meC5zdGVwWyBwcm9wIF0gPSBmdW5jdGlvbiggZnggKSB7XG5cdFx0XHRpZiAoIGZ4LmVuZCAhPT0gXCJub25lXCIgJiYgIWZ4LnNldEF0dHIgfHwgZngucG9zID09PSAxICYmICFmeC5zZXRBdHRyICkge1xuXHRcdFx0XHRqUXVlcnkuc3R5bGUoIGZ4LmVsZW0sIHByb3AsIGZ4LmVuZCApO1xuXHRcdFx0XHRmeC5zZXRBdHRyID0gdHJ1ZTtcblx0XHRcdH1cblx0XHR9O1xuXHR9XG4pO1xuXG5mdW5jdGlvbiBnZXRFbGVtZW50U3R5bGVzKCBlbGVtICkge1xuXHR2YXIga2V5LCBsZW4sXG5cdFx0c3R5bGUgPSBlbGVtLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXcgP1xuXHRcdFx0ZWxlbS5vd25lckRvY3VtZW50LmRlZmF1bHRWaWV3LmdldENvbXB1dGVkU3R5bGUoIGVsZW0sIG51bGwgKSA6XG5cdFx0XHRlbGVtLmN1cnJlbnRTdHlsZSxcblx0XHRzdHlsZXMgPSB7fTtcblxuXHRpZiAoIHN0eWxlICYmIHN0eWxlLmxlbmd0aCAmJiBzdHlsZVsgMCBdICYmIHN0eWxlWyBzdHlsZVsgMCBdIF0gKSB7XG5cdFx0bGVuID0gc3R5bGUubGVuZ3RoO1xuXHRcdHdoaWxlICggbGVuLS0gKSB7XG5cdFx0XHRrZXkgPSBzdHlsZVsgbGVuIF07XG5cdFx0XHRpZiAoIHR5cGVvZiBzdHlsZVsga2V5IF0gPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdHN0eWxlc1sgJC5jYW1lbENhc2UoIGtleSApIF0gPSBzdHlsZVsga2V5IF07XG5cdFx0XHR9XG5cdFx0fVxuXG5cdC8vIFN1cHBvcnQ6IE9wZXJhLCBJRSA8OVxuXHR9IGVsc2Uge1xuXHRcdGZvciAoIGtleSBpbiBzdHlsZSApIHtcblx0XHRcdGlmICggdHlwZW9mIHN0eWxlWyBrZXkgXSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdFx0c3R5bGVzWyBrZXkgXSA9IHN0eWxlWyBrZXkgXTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gc3R5bGVzO1xufVxuXG5mdW5jdGlvbiBzdHlsZURpZmZlcmVuY2UoIG9sZFN0eWxlLCBuZXdTdHlsZSApIHtcblx0dmFyIGRpZmYgPSB7fSxcblx0XHRuYW1lLCB2YWx1ZTtcblxuXHRmb3IgKCBuYW1lIGluIG5ld1N0eWxlICkge1xuXHRcdHZhbHVlID0gbmV3U3R5bGVbIG5hbWUgXTtcblx0XHRpZiAoIG9sZFN0eWxlWyBuYW1lIF0gIT09IHZhbHVlICkge1xuXHRcdFx0aWYgKCAhc2hvcnRoYW5kU3R5bGVzWyBuYW1lIF0gKSB7XG5cdFx0XHRcdGlmICggJC5meC5zdGVwWyBuYW1lIF0gfHwgIWlzTmFOKCBwYXJzZUZsb2F0KCB2YWx1ZSApICkgKSB7XG5cdFx0XHRcdFx0ZGlmZlsgbmFtZSBdID0gdmFsdWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gZGlmZjtcbn1cblxuLy8gU3VwcG9ydDogalF1ZXJ5IDwxLjhcbmlmICggISQuZm4uYWRkQmFjayApIHtcblx0JC5mbi5hZGRCYWNrID0gZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiB0aGlzLmFkZCggc2VsZWN0b3IgPT0gbnVsbCA/XG5cdFx0XHR0aGlzLnByZXZPYmplY3QgOiB0aGlzLnByZXZPYmplY3QuZmlsdGVyKCBzZWxlY3RvciApXG5cdFx0KTtcblx0fTtcbn1cblxuJC5lZmZlY3RzLmFuaW1hdGVDbGFzcyA9IGZ1bmN0aW9uKCB2YWx1ZSwgZHVyYXRpb24sIGVhc2luZywgY2FsbGJhY2sgKSB7XG5cdHZhciBvID0gJC5zcGVlZCggZHVyYXRpb24sIGVhc2luZywgY2FsbGJhY2sgKTtcblxuXHRyZXR1cm4gdGhpcy5xdWV1ZSggZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGFuaW1hdGVkID0gJCggdGhpcyApLFxuXHRcdFx0YmFzZUNsYXNzID0gYW5pbWF0ZWQuYXR0ciggXCJjbGFzc1wiICkgfHwgXCJcIixcblx0XHRcdGFwcGx5Q2xhc3NDaGFuZ2UsXG5cdFx0XHRhbGxBbmltYXRpb25zID0gby5jaGlsZHJlbiA/IGFuaW1hdGVkLmZpbmQoIFwiKlwiICkuYWRkQmFjaygpIDogYW5pbWF0ZWQ7XG5cblx0XHQvLyBNYXAgdGhlIGFuaW1hdGVkIG9iamVjdHMgdG8gc3RvcmUgdGhlIG9yaWdpbmFsIHN0eWxlcy5cblx0XHRhbGxBbmltYXRpb25zID0gYWxsQW5pbWF0aW9ucy5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGVsID0gJCggdGhpcyApO1xuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0ZWw6IGVsLFxuXHRcdFx0XHRzdGFydDogZ2V0RWxlbWVudFN0eWxlcyggdGhpcyApXG5cdFx0XHR9O1xuXHRcdH0gKTtcblxuXHRcdC8vIEFwcGx5IGNsYXNzIGNoYW5nZVxuXHRcdGFwcGx5Q2xhc3NDaGFuZ2UgPSBmdW5jdGlvbigpIHtcblx0XHRcdCQuZWFjaCggY2xhc3NBbmltYXRpb25BY3Rpb25zLCBmdW5jdGlvbiggaSwgYWN0aW9uICkge1xuXHRcdFx0XHRpZiAoIHZhbHVlWyBhY3Rpb24gXSApIHtcblx0XHRcdFx0XHRhbmltYXRlZFsgYWN0aW9uICsgXCJDbGFzc1wiIF0oIHZhbHVlWyBhY3Rpb24gXSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0fTtcblx0XHRhcHBseUNsYXNzQ2hhbmdlKCk7XG5cblx0XHQvLyBNYXAgYWxsIGFuaW1hdGVkIG9iamVjdHMgYWdhaW4gLSBjYWxjdWxhdGUgbmV3IHN0eWxlcyBhbmQgZGlmZlxuXHRcdGFsbEFuaW1hdGlvbnMgPSBhbGxBbmltYXRpb25zLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLmVuZCA9IGdldEVsZW1lbnRTdHlsZXMoIHRoaXMuZWxbIDAgXSApO1xuXHRcdFx0dGhpcy5kaWZmID0gc3R5bGVEaWZmZXJlbmNlKCB0aGlzLnN0YXJ0LCB0aGlzLmVuZCApO1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fSApO1xuXG5cdFx0Ly8gQXBwbHkgb3JpZ2luYWwgY2xhc3Ncblx0XHRhbmltYXRlZC5hdHRyKCBcImNsYXNzXCIsIGJhc2VDbGFzcyApO1xuXG5cdFx0Ly8gTWFwIGFsbCBhbmltYXRlZCBvYmplY3RzIGFnYWluIC0gdGhpcyB0aW1lIGNvbGxlY3RpbmcgYSBwcm9taXNlXG5cdFx0YWxsQW5pbWF0aW9ucyA9IGFsbEFuaW1hdGlvbnMubWFwKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBzdHlsZUluZm8gPSB0aGlzLFxuXHRcdFx0XHRkZmQgPSAkLkRlZmVycmVkKCksXG5cdFx0XHRcdG9wdHMgPSAkLmV4dGVuZCgge30sIG8sIHtcblx0XHRcdFx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0XHRcdFx0Y29tcGxldGU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0ZGZkLnJlc29sdmUoIHN0eWxlSW5mbyApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXG5cdFx0XHR0aGlzLmVsLmFuaW1hdGUoIHRoaXMuZGlmZiwgb3B0cyApO1xuXHRcdFx0cmV0dXJuIGRmZC5wcm9taXNlKCk7XG5cdFx0fSApO1xuXG5cdFx0Ly8gT25jZSBhbGwgYW5pbWF0aW9ucyBoYXZlIGNvbXBsZXRlZDpcblx0XHQkLndoZW4uYXBwbHkoICQsIGFsbEFuaW1hdGlvbnMuZ2V0KCkgKS5kb25lKCBmdW5jdGlvbigpIHtcblxuXHRcdFx0Ly8gU2V0IHRoZSBmaW5hbCBjbGFzc1xuXHRcdFx0YXBwbHlDbGFzc0NoYW5nZSgpO1xuXG5cdFx0XHQvLyBGb3IgZWFjaCBhbmltYXRlZCBlbGVtZW50LFxuXHRcdFx0Ly8gY2xlYXIgYWxsIGNzcyBwcm9wZXJ0aWVzIHRoYXQgd2VyZSBhbmltYXRlZFxuXHRcdFx0JC5lYWNoKCBhcmd1bWVudHMsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgZWwgPSB0aGlzLmVsO1xuXHRcdFx0XHQkLmVhY2goIHRoaXMuZGlmZiwgZnVuY3Rpb24oIGtleSApIHtcblx0XHRcdFx0XHRlbC5jc3MoIGtleSwgXCJcIiApO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHR9ICk7XG5cblx0XHRcdC8vIFRoaXMgaXMgZ3Vhcm50ZWVkIHRvIGJlIHRoZXJlIGlmIHlvdSB1c2UgalF1ZXJ5LnNwZWVkKClcblx0XHRcdC8vIGl0IGFsc28gaGFuZGxlcyBkZXF1ZXVpbmcgdGhlIG5leHQgYW5pbS4uLlxuXHRcdFx0by5jb21wbGV0ZS5jYWxsKCBhbmltYXRlZFsgMCBdICk7XG5cdFx0fSApO1xuXHR9ICk7XG59O1xuXG4kLmZuLmV4dGVuZCgge1xuXHRhZGRDbGFzczogKCBmdW5jdGlvbiggb3JpZyApIHtcblx0XHRyZXR1cm4gZnVuY3Rpb24oIGNsYXNzTmFtZXMsIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICkge1xuXHRcdFx0cmV0dXJuIHNwZWVkID9cblx0XHRcdFx0JC5lZmZlY3RzLmFuaW1hdGVDbGFzcy5jYWxsKCB0aGlzLFxuXHRcdFx0XHRcdHsgYWRkOiBjbGFzc05hbWVzIH0sIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICkgOlxuXHRcdFx0XHRvcmlnLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHR9O1xuXHR9ICkoICQuZm4uYWRkQ2xhc3MgKSxcblxuXHRyZW1vdmVDbGFzczogKCBmdW5jdGlvbiggb3JpZyApIHtcblx0XHRyZXR1cm4gZnVuY3Rpb24oIGNsYXNzTmFtZXMsIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICkge1xuXHRcdFx0cmV0dXJuIGFyZ3VtZW50cy5sZW5ndGggPiAxID9cblx0XHRcdFx0JC5lZmZlY3RzLmFuaW1hdGVDbGFzcy5jYWxsKCB0aGlzLFxuXHRcdFx0XHRcdHsgcmVtb3ZlOiBjbGFzc05hbWVzIH0sIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICkgOlxuXHRcdFx0XHRvcmlnLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHR9O1xuXHR9ICkoICQuZm4ucmVtb3ZlQ2xhc3MgKSxcblxuXHR0b2dnbGVDbGFzczogKCBmdW5jdGlvbiggb3JpZyApIHtcblx0XHRyZXR1cm4gZnVuY3Rpb24oIGNsYXNzTmFtZXMsIGZvcmNlLCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIHtcblx0XHRcdGlmICggdHlwZW9mIGZvcmNlID09PSBcImJvb2xlYW5cIiB8fCBmb3JjZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRpZiAoICFzcGVlZCApIHtcblxuXHRcdFx0XHRcdC8vIFdpdGhvdXQgc3BlZWQgcGFyYW1ldGVyXG5cdFx0XHRcdFx0cmV0dXJuIG9yaWcuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHJldHVybiAkLmVmZmVjdHMuYW5pbWF0ZUNsYXNzLmNhbGwoIHRoaXMsXG5cdFx0XHRcdFx0XHQoIGZvcmNlID8geyBhZGQ6IGNsYXNzTmFtZXMgfSA6IHsgcmVtb3ZlOiBjbGFzc05hbWVzIH0gKSxcblx0XHRcdFx0XHRcdHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gV2l0aG91dCBmb3JjZSBwYXJhbWV0ZXJcblx0XHRcdFx0cmV0dXJuICQuZWZmZWN0cy5hbmltYXRlQ2xhc3MuY2FsbCggdGhpcyxcblx0XHRcdFx0XHR7IHRvZ2dsZTogY2xhc3NOYW1lcyB9LCBmb3JjZSwgc3BlZWQsIGVhc2luZyApO1xuXHRcdFx0fVxuXHRcdH07XG5cdH0gKSggJC5mbi50b2dnbGVDbGFzcyApLFxuXG5cdHN3aXRjaENsYXNzOiBmdW5jdGlvbiggcmVtb3ZlLCBhZGQsIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICkge1xuXHRcdHJldHVybiAkLmVmZmVjdHMuYW5pbWF0ZUNsYXNzLmNhbGwoIHRoaXMsIHtcblx0XHRcdGFkZDogYWRkLFxuXHRcdFx0cmVtb3ZlOiByZW1vdmVcblx0XHR9LCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApO1xuXHR9XG59ICk7XG5cbn0gKSgpO1xuXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqIEVGRkVDVFMgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG5cbiggZnVuY3Rpb24oKSB7XG5cbmlmICggJC5leHByICYmICQuZXhwci5maWx0ZXJzICYmICQuZXhwci5maWx0ZXJzLmFuaW1hdGVkICkge1xuXHQkLmV4cHIuZmlsdGVycy5hbmltYXRlZCA9ICggZnVuY3Rpb24oIG9yaWcgKSB7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuICEhJCggZWxlbSApLmRhdGEoIGRhdGFTcGFjZUFuaW1hdGVkICkgfHwgb3JpZyggZWxlbSApO1xuXHRcdH07XG5cdH0gKSggJC5leHByLmZpbHRlcnMuYW5pbWF0ZWQgKTtcbn1cblxuaWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgKSB7XG5cdCQuZXh0ZW5kKCAkLmVmZmVjdHMsIHtcblxuXHRcdC8vIFNhdmVzIGEgc2V0IG9mIHByb3BlcnRpZXMgaW4gYSBkYXRhIHN0b3JhZ2Vcblx0XHRzYXZlOiBmdW5jdGlvbiggZWxlbWVudCwgc2V0ICkge1xuXHRcdFx0dmFyIGkgPSAwLCBsZW5ndGggPSBzZXQubGVuZ3RoO1xuXHRcdFx0Zm9yICggOyBpIDwgbGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRcdGlmICggc2V0WyBpIF0gIT09IG51bGwgKSB7XG5cdFx0XHRcdFx0ZWxlbWVudC5kYXRhKCBkYXRhU3BhY2UgKyBzZXRbIGkgXSwgZWxlbWVudFsgMCBdLnN0eWxlWyBzZXRbIGkgXSBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9LFxuXG5cdFx0Ly8gUmVzdG9yZXMgYSBzZXQgb2YgcHJldmlvdXNseSBzYXZlZCBwcm9wZXJ0aWVzIGZyb20gYSBkYXRhIHN0b3JhZ2Vcblx0XHRyZXN0b3JlOiBmdW5jdGlvbiggZWxlbWVudCwgc2V0ICkge1xuXHRcdFx0dmFyIHZhbCwgaSA9IDAsIGxlbmd0aCA9IHNldC5sZW5ndGg7XG5cdFx0XHRmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApIHtcblx0XHRcdFx0aWYgKCBzZXRbIGkgXSAhPT0gbnVsbCApIHtcblx0XHRcdFx0XHR2YWwgPSBlbGVtZW50LmRhdGEoIGRhdGFTcGFjZSArIHNldFsgaSBdICk7XG5cdFx0XHRcdFx0ZWxlbWVudC5jc3MoIHNldFsgaSBdLCB2YWwgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHRzZXRNb2RlOiBmdW5jdGlvbiggZWwsIG1vZGUgKSB7XG5cdFx0XHRpZiAoIG1vZGUgPT09IFwidG9nZ2xlXCIgKSB7XG5cdFx0XHRcdG1vZGUgPSBlbC5pcyggXCI6aGlkZGVuXCIgKSA/IFwic2hvd1wiIDogXCJoaWRlXCI7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gbW9kZTtcblx0XHR9LFxuXG5cdFx0Ly8gV3JhcHMgdGhlIGVsZW1lbnQgYXJvdW5kIGEgd3JhcHBlciB0aGF0IGNvcGllcyBwb3NpdGlvbiBwcm9wZXJ0aWVzXG5cdFx0Y3JlYXRlV3JhcHBlcjogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cblx0XHRcdC8vIElmIHRoZSBlbGVtZW50IGlzIGFscmVhZHkgd3JhcHBlZCwgcmV0dXJuIGl0XG5cdFx0XHRpZiAoIGVsZW1lbnQucGFyZW50KCkuaXMoIFwiLnVpLWVmZmVjdHMtd3JhcHBlclwiICkgKSB7XG5cdFx0XHRcdHJldHVybiBlbGVtZW50LnBhcmVudCgpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBXcmFwIHRoZSBlbGVtZW50XG5cdFx0XHR2YXIgcHJvcHMgPSB7XG5cdFx0XHRcdFx0d2lkdGg6IGVsZW1lbnQub3V0ZXJXaWR0aCggdHJ1ZSApLFxuXHRcdFx0XHRcdGhlaWdodDogZWxlbWVudC5vdXRlckhlaWdodCggdHJ1ZSApLFxuXHRcdFx0XHRcdFwiZmxvYXRcIjogZWxlbWVudC5jc3MoIFwiZmxvYXRcIiApXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHdyYXBwZXIgPSAkKCBcIjxkaXY+PC9kaXY+XCIgKVxuXHRcdFx0XHRcdC5hZGRDbGFzcyggXCJ1aS1lZmZlY3RzLXdyYXBwZXJcIiApXG5cdFx0XHRcdFx0LmNzcygge1xuXHRcdFx0XHRcdFx0Zm9udFNpemU6IFwiMTAwJVwiLFxuXHRcdFx0XHRcdFx0YmFja2dyb3VuZDogXCJ0cmFuc3BhcmVudFwiLFxuXHRcdFx0XHRcdFx0Ym9yZGVyOiBcIm5vbmVcIixcblx0XHRcdFx0XHRcdG1hcmdpbjogMCxcblx0XHRcdFx0XHRcdHBhZGRpbmc6IDBcblx0XHRcdFx0XHR9ICksXG5cblx0XHRcdFx0Ly8gU3RvcmUgdGhlIHNpemUgaW4gY2FzZSB3aWR0aC9oZWlnaHQgYXJlIGRlZmluZWQgaW4gJSAtIEZpeGVzICM1MjQ1XG5cdFx0XHRcdHNpemUgPSB7XG5cdFx0XHRcdFx0d2lkdGg6IGVsZW1lbnQud2lkdGgoKSxcblx0XHRcdFx0XHRoZWlnaHQ6IGVsZW1lbnQuaGVpZ2h0KClcblx0XHRcdFx0fSxcblx0XHRcdFx0YWN0aXZlID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudDtcblxuXHRcdFx0Ly8gU3VwcG9ydDogRmlyZWZveFxuXHRcdFx0Ly8gRmlyZWZveCBpbmNvcnJlY3RseSBleHBvc2VzIGFub255bW91cyBjb250ZW50XG5cdFx0XHQvLyBodHRwczovL2J1Z3ppbGxhLm1vemlsbGEub3JnL3Nob3dfYnVnLmNnaT9pZD01NjE2NjRcblx0XHRcdHRyeSB7XG5cdFx0XHRcdGFjdGl2ZS5pZDtcblx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXHRcdFx0XHRhY3RpdmUgPSBkb2N1bWVudC5ib2R5O1xuXHRcdFx0fVxuXG5cdFx0XHRlbGVtZW50LndyYXAoIHdyYXBwZXIgKTtcblxuXHRcdFx0Ly8gRml4ZXMgIzc1OTUgLSBFbGVtZW50cyBsb3NlIGZvY3VzIHdoZW4gd3JhcHBlZC5cblx0XHRcdGlmICggZWxlbWVudFsgMCBdID09PSBhY3RpdmUgfHwgJC5jb250YWlucyggZWxlbWVudFsgMCBdLCBhY3RpdmUgKSApIHtcblx0XHRcdFx0JCggYWN0aXZlICkudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEhvdGZpeCBmb3IgalF1ZXJ5IDEuNCBzaW5jZSBzb21lIGNoYW5nZSBpbiB3cmFwKCkgc2VlbXMgdG8gYWN0dWFsbHlcblx0XHRcdC8vIGxvc2UgdGhlIHJlZmVyZW5jZSB0byB0aGUgd3JhcHBlZCBlbGVtZW50XG5cdFx0XHR3cmFwcGVyID0gZWxlbWVudC5wYXJlbnQoKTtcblxuXHRcdFx0Ly8gVHJhbnNmZXIgcG9zaXRpb25pbmcgcHJvcGVydGllcyB0byB0aGUgd3JhcHBlclxuXHRcdFx0aWYgKCBlbGVtZW50LmNzcyggXCJwb3NpdGlvblwiICkgPT09IFwic3RhdGljXCIgKSB7XG5cdFx0XHRcdHdyYXBwZXIuY3NzKCB7IHBvc2l0aW9uOiBcInJlbGF0aXZlXCIgfSApO1xuXHRcdFx0XHRlbGVtZW50LmNzcyggeyBwb3NpdGlvbjogXCJyZWxhdGl2ZVwiIH0gKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdCQuZXh0ZW5kKCBwcm9wcywge1xuXHRcdFx0XHRcdHBvc2l0aW9uOiBlbGVtZW50LmNzcyggXCJwb3NpdGlvblwiICksXG5cdFx0XHRcdFx0ekluZGV4OiBlbGVtZW50LmNzcyggXCJ6LWluZGV4XCIgKVxuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdCQuZWFjaCggWyBcInRvcFwiLCBcImxlZnRcIiwgXCJib3R0b21cIiwgXCJyaWdodFwiIF0sIGZ1bmN0aW9uKCBpLCBwb3MgKSB7XG5cdFx0XHRcdFx0cHJvcHNbIHBvcyBdID0gZWxlbWVudC5jc3MoIHBvcyApO1xuXHRcdFx0XHRcdGlmICggaXNOYU4oIHBhcnNlSW50KCBwcm9wc1sgcG9zIF0sIDEwICkgKSApIHtcblx0XHRcdFx0XHRcdHByb3BzWyBwb3MgXSA9IFwiYXV0b1wiO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0XHRlbGVtZW50LmNzcygge1xuXHRcdFx0XHRcdHBvc2l0aW9uOiBcInJlbGF0aXZlXCIsXG5cdFx0XHRcdFx0dG9wOiAwLFxuXHRcdFx0XHRcdGxlZnQ6IDAsXG5cdFx0XHRcdFx0cmlnaHQ6IFwiYXV0b1wiLFxuXHRcdFx0XHRcdGJvdHRvbTogXCJhdXRvXCJcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdFx0ZWxlbWVudC5jc3MoIHNpemUgKTtcblxuXHRcdFx0cmV0dXJuIHdyYXBwZXIuY3NzKCBwcm9wcyApLnNob3coKTtcblx0XHR9LFxuXG5cdFx0cmVtb3ZlV3JhcHBlcjogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0XHR2YXIgYWN0aXZlID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudDtcblxuXHRcdFx0aWYgKCBlbGVtZW50LnBhcmVudCgpLmlzKCBcIi51aS1lZmZlY3RzLXdyYXBwZXJcIiApICkge1xuXHRcdFx0XHRlbGVtZW50LnBhcmVudCgpLnJlcGxhY2VXaXRoKCBlbGVtZW50ICk7XG5cblx0XHRcdFx0Ly8gRml4ZXMgIzc1OTUgLSBFbGVtZW50cyBsb3NlIGZvY3VzIHdoZW4gd3JhcHBlZC5cblx0XHRcdFx0aWYgKCBlbGVtZW50WyAwIF0gPT09IGFjdGl2ZSB8fCAkLmNvbnRhaW5zKCBlbGVtZW50WyAwIF0sIGFjdGl2ZSApICkge1xuXHRcdFx0XHRcdCQoIGFjdGl2ZSApLnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBlbGVtZW50O1xuXHRcdH1cblx0fSApO1xufVxuXG4kLmV4dGVuZCggJC5lZmZlY3RzLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cblx0ZGVmaW5lOiBmdW5jdGlvbiggbmFtZSwgbW9kZSwgZWZmZWN0ICkge1xuXHRcdGlmICggIWVmZmVjdCApIHtcblx0XHRcdGVmZmVjdCA9IG1vZGU7XG5cdFx0XHRtb2RlID0gXCJlZmZlY3RcIjtcblx0XHR9XG5cblx0XHQkLmVmZmVjdHMuZWZmZWN0WyBuYW1lIF0gPSBlZmZlY3Q7XG5cdFx0JC5lZmZlY3RzLmVmZmVjdFsgbmFtZSBdLm1vZGUgPSBtb2RlO1xuXG5cdFx0cmV0dXJuIGVmZmVjdDtcblx0fSxcblxuXHRzY2FsZWREaW1lbnNpb25zOiBmdW5jdGlvbiggZWxlbWVudCwgcGVyY2VudCwgZGlyZWN0aW9uICkge1xuXHRcdGlmICggcGVyY2VudCA9PT0gMCApIHtcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdGhlaWdodDogMCxcblx0XHRcdFx0d2lkdGg6IDAsXG5cdFx0XHRcdG91dGVySGVpZ2h0OiAwLFxuXHRcdFx0XHRvdXRlcldpZHRoOiAwXG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdHZhciB4ID0gZGlyZWN0aW9uICE9PSBcImhvcml6b250YWxcIiA/ICggKCBwZXJjZW50IHx8IDEwMCApIC8gMTAwICkgOiAxLFxuXHRcdFx0eSA9IGRpcmVjdGlvbiAhPT0gXCJ2ZXJ0aWNhbFwiID8gKCAoIHBlcmNlbnQgfHwgMTAwICkgLyAxMDAgKSA6IDE7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0aGVpZ2h0OiBlbGVtZW50LmhlaWdodCgpICogeSxcblx0XHRcdHdpZHRoOiBlbGVtZW50LndpZHRoKCkgKiB4LFxuXHRcdFx0b3V0ZXJIZWlnaHQ6IGVsZW1lbnQub3V0ZXJIZWlnaHQoKSAqIHksXG5cdFx0XHRvdXRlcldpZHRoOiBlbGVtZW50Lm91dGVyV2lkdGgoKSAqIHhcblx0XHR9O1xuXG5cdH0sXG5cblx0Y2xpcFRvQm94OiBmdW5jdGlvbiggYW5pbWF0aW9uICkge1xuXHRcdHJldHVybiB7XG5cdFx0XHR3aWR0aDogYW5pbWF0aW9uLmNsaXAucmlnaHQgLSBhbmltYXRpb24uY2xpcC5sZWZ0LFxuXHRcdFx0aGVpZ2h0OiBhbmltYXRpb24uY2xpcC5ib3R0b20gLSBhbmltYXRpb24uY2xpcC50b3AsXG5cdFx0XHRsZWZ0OiBhbmltYXRpb24uY2xpcC5sZWZ0LFxuXHRcdFx0dG9wOiBhbmltYXRpb24uY2xpcC50b3Bcblx0XHR9O1xuXHR9LFxuXG5cdC8vIEluamVjdHMgcmVjZW50bHkgcXVldWVkIGZ1bmN0aW9ucyB0byBiZSBmaXJzdCBpbiBsaW5lIChhZnRlciBcImlucHJvZ3Jlc3NcIilcblx0dW5zaGlmdDogZnVuY3Rpb24oIGVsZW1lbnQsIHF1ZXVlTGVuZ3RoLCBjb3VudCApIHtcblx0XHR2YXIgcXVldWUgPSBlbGVtZW50LnF1ZXVlKCk7XG5cblx0XHRpZiAoIHF1ZXVlTGVuZ3RoID4gMSApIHtcblx0XHRcdHF1ZXVlLnNwbGljZS5hcHBseSggcXVldWUsXG5cdFx0XHRcdFsgMSwgMCBdLmNvbmNhdCggcXVldWUuc3BsaWNlKCBxdWV1ZUxlbmd0aCwgY291bnQgKSApICk7XG5cdFx0fVxuXHRcdGVsZW1lbnQuZGVxdWV1ZSgpO1xuXHR9LFxuXG5cdHNhdmVTdHlsZTogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0ZWxlbWVudC5kYXRhKCBkYXRhU3BhY2VTdHlsZSwgZWxlbWVudFsgMCBdLnN0eWxlLmNzc1RleHQgKTtcblx0fSxcblxuXHRyZXN0b3JlU3R5bGU6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdGVsZW1lbnRbIDAgXS5zdHlsZS5jc3NUZXh0ID0gZWxlbWVudC5kYXRhKCBkYXRhU3BhY2VTdHlsZSApIHx8IFwiXCI7XG5cdFx0ZWxlbWVudC5yZW1vdmVEYXRhKCBkYXRhU3BhY2VTdHlsZSApO1xuXHR9LFxuXG5cdG1vZGU6IGZ1bmN0aW9uKCBlbGVtZW50LCBtb2RlICkge1xuXHRcdHZhciBoaWRkZW4gPSBlbGVtZW50LmlzKCBcIjpoaWRkZW5cIiApO1xuXG5cdFx0aWYgKCBtb2RlID09PSBcInRvZ2dsZVwiICkge1xuXHRcdFx0bW9kZSA9IGhpZGRlbiA/IFwic2hvd1wiIDogXCJoaWRlXCI7XG5cdFx0fVxuXHRcdGlmICggaGlkZGVuID8gbW9kZSA9PT0gXCJoaWRlXCIgOiBtb2RlID09PSBcInNob3dcIiApIHtcblx0XHRcdG1vZGUgPSBcIm5vbmVcIjtcblx0XHR9XG5cdFx0cmV0dXJuIG1vZGU7XG5cdH0sXG5cblx0Ly8gVHJhbnNsYXRlcyBhIFt0b3AsbGVmdF0gYXJyYXkgaW50byBhIGJhc2VsaW5lIHZhbHVlXG5cdGdldEJhc2VsaW5lOiBmdW5jdGlvbiggb3JpZ2luLCBvcmlnaW5hbCApIHtcblx0XHR2YXIgeSwgeDtcblxuXHRcdHN3aXRjaCAoIG9yaWdpblsgMCBdICkge1xuXHRcdGNhc2UgXCJ0b3BcIjpcblx0XHRcdHkgPSAwO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSBcIm1pZGRsZVwiOlxuXHRcdFx0eSA9IDAuNTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgXCJib3R0b21cIjpcblx0XHRcdHkgPSAxO1xuXHRcdFx0YnJlYWs7XG5cdFx0ZGVmYXVsdDpcblx0XHRcdHkgPSBvcmlnaW5bIDAgXSAvIG9yaWdpbmFsLmhlaWdodDtcblx0XHR9XG5cblx0XHRzd2l0Y2ggKCBvcmlnaW5bIDEgXSApIHtcblx0XHRjYXNlIFwibGVmdFwiOlxuXHRcdFx0eCA9IDA7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIFwiY2VudGVyXCI6XG5cdFx0XHR4ID0gMC41O1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSBcInJpZ2h0XCI6XG5cdFx0XHR4ID0gMTtcblx0XHRcdGJyZWFrO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHR4ID0gb3JpZ2luWyAxIF0gLyBvcmlnaW5hbC53aWR0aDtcblx0XHR9XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0eDogeCxcblx0XHRcdHk6IHlcblx0XHR9O1xuXHR9LFxuXG5cdC8vIENyZWF0ZXMgYSBwbGFjZWhvbGRlciBlbGVtZW50IHNvIHRoYXQgdGhlIG9yaWdpbmFsIGVsZW1lbnQgY2FuIGJlIG1hZGUgYWJzb2x1dGVcblx0Y3JlYXRlUGxhY2Vob2xkZXI6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHZhciBwbGFjZWhvbGRlcixcblx0XHRcdGNzc1Bvc2l0aW9uID0gZWxlbWVudC5jc3MoIFwicG9zaXRpb25cIiApLFxuXHRcdFx0cG9zaXRpb24gPSBlbGVtZW50LnBvc2l0aW9uKCk7XG5cblx0XHQvLyBMb2NrIGluIG1hcmdpbnMgZmlyc3QgdG8gYWNjb3VudCBmb3IgZm9ybSBlbGVtZW50cywgd2hpY2hcblx0XHQvLyB3aWxsIGNoYW5nZSBtYXJnaW4gaWYgeW91IGV4cGxpY2l0bHkgc2V0IGhlaWdodFxuXHRcdC8vIHNlZTogaHR0cDovL2pzZmlkZGxlLm5ldC9KWlNNdC8zLyBodHRwczovL2J1Z3Mud2Via2l0Lm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTA3MzgwXG5cdFx0Ly8gU3VwcG9ydDogU2FmYXJpXG5cdFx0ZWxlbWVudC5jc3MoIHtcblx0XHRcdG1hcmdpblRvcDogZWxlbWVudC5jc3MoIFwibWFyZ2luVG9wXCIgKSxcblx0XHRcdG1hcmdpbkJvdHRvbTogZWxlbWVudC5jc3MoIFwibWFyZ2luQm90dG9tXCIgKSxcblx0XHRcdG1hcmdpbkxlZnQ6IGVsZW1lbnQuY3NzKCBcIm1hcmdpbkxlZnRcIiApLFxuXHRcdFx0bWFyZ2luUmlnaHQ6IGVsZW1lbnQuY3NzKCBcIm1hcmdpblJpZ2h0XCIgKVxuXHRcdH0gKVxuXHRcdC5vdXRlcldpZHRoKCBlbGVtZW50Lm91dGVyV2lkdGgoKSApXG5cdFx0Lm91dGVySGVpZ2h0KCBlbGVtZW50Lm91dGVySGVpZ2h0KCkgKTtcblxuXHRcdGlmICggL14oc3RhdGljfHJlbGF0aXZlKS8udGVzdCggY3NzUG9zaXRpb24gKSApIHtcblx0XHRcdGNzc1Bvc2l0aW9uID0gXCJhYnNvbHV0ZVwiO1xuXG5cdFx0XHRwbGFjZWhvbGRlciA9ICQoIFwiPFwiICsgZWxlbWVudFsgMCBdLm5vZGVOYW1lICsgXCI+XCIgKS5pbnNlcnRBZnRlciggZWxlbWVudCApLmNzcygge1xuXG5cdFx0XHRcdC8vIENvbnZlcnQgaW5saW5lIHRvIGlubGluZSBibG9jayB0byBhY2NvdW50IGZvciBpbmxpbmUgZWxlbWVudHNcblx0XHRcdFx0Ly8gdGhhdCB0dXJuIHRvIGlubGluZSBibG9jayBiYXNlZCBvbiBjb250ZW50IChsaWtlIGltZylcblx0XHRcdFx0ZGlzcGxheTogL14oaW5saW5lfHJ1YnkpLy50ZXN0KCBlbGVtZW50LmNzcyggXCJkaXNwbGF5XCIgKSApID9cblx0XHRcdFx0XHRcImlubGluZS1ibG9ja1wiIDpcblx0XHRcdFx0XHRcImJsb2NrXCIsXG5cdFx0XHRcdHZpc2liaWxpdHk6IFwiaGlkZGVuXCIsXG5cblx0XHRcdFx0Ly8gTWFyZ2lucyBuZWVkIHRvIGJlIHNldCB0byBhY2NvdW50IGZvciBtYXJnaW4gY29sbGFwc2Vcblx0XHRcdFx0bWFyZ2luVG9wOiBlbGVtZW50LmNzcyggXCJtYXJnaW5Ub3BcIiApLFxuXHRcdFx0XHRtYXJnaW5Cb3R0b206IGVsZW1lbnQuY3NzKCBcIm1hcmdpbkJvdHRvbVwiICksXG5cdFx0XHRcdG1hcmdpbkxlZnQ6IGVsZW1lbnQuY3NzKCBcIm1hcmdpbkxlZnRcIiApLFxuXHRcdFx0XHRtYXJnaW5SaWdodDogZWxlbWVudC5jc3MoIFwibWFyZ2luUmlnaHRcIiApLFxuXHRcdFx0XHRcImZsb2F0XCI6IGVsZW1lbnQuY3NzKCBcImZsb2F0XCIgKVxuXHRcdFx0fSApXG5cdFx0XHQub3V0ZXJXaWR0aCggZWxlbWVudC5vdXRlcldpZHRoKCkgKVxuXHRcdFx0Lm91dGVySGVpZ2h0KCBlbGVtZW50Lm91dGVySGVpZ2h0KCkgKVxuXHRcdFx0LmFkZENsYXNzKCBcInVpLWVmZmVjdHMtcGxhY2Vob2xkZXJcIiApO1xuXG5cdFx0XHRlbGVtZW50LmRhdGEoIGRhdGFTcGFjZSArIFwicGxhY2Vob2xkZXJcIiwgcGxhY2Vob2xkZXIgKTtcblx0XHR9XG5cblx0XHRlbGVtZW50LmNzcygge1xuXHRcdFx0cG9zaXRpb246IGNzc1Bvc2l0aW9uLFxuXHRcdFx0bGVmdDogcG9zaXRpb24ubGVmdCxcblx0XHRcdHRvcDogcG9zaXRpb24udG9wXG5cdFx0fSApO1xuXG5cdFx0cmV0dXJuIHBsYWNlaG9sZGVyO1xuXHR9LFxuXG5cdHJlbW92ZVBsYWNlaG9sZGVyOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHR2YXIgZGF0YUtleSA9IGRhdGFTcGFjZSArIFwicGxhY2Vob2xkZXJcIixcblx0XHRcdFx0cGxhY2Vob2xkZXIgPSBlbGVtZW50LmRhdGEoIGRhdGFLZXkgKTtcblxuXHRcdGlmICggcGxhY2Vob2xkZXIgKSB7XG5cdFx0XHRwbGFjZWhvbGRlci5yZW1vdmUoKTtcblx0XHRcdGVsZW1lbnQucmVtb3ZlRGF0YSggZGF0YUtleSApO1xuXHRcdH1cblx0fSxcblxuXHQvLyBSZW1vdmVzIGEgcGxhY2Vob2xkZXIgaWYgaXQgZXhpc3RzIGFuZCByZXN0b3Jlc1xuXHQvLyBwcm9wZXJ0aWVzIHRoYXQgd2VyZSBtb2RpZmllZCBkdXJpbmcgcGxhY2Vob2xkZXIgY3JlYXRpb25cblx0Y2xlYW5VcDogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0JC5lZmZlY3RzLnJlc3RvcmVTdHlsZSggZWxlbWVudCApO1xuXHRcdCQuZWZmZWN0cy5yZW1vdmVQbGFjZWhvbGRlciggZWxlbWVudCApO1xuXHR9LFxuXG5cdHNldFRyYW5zaXRpb246IGZ1bmN0aW9uKCBlbGVtZW50LCBsaXN0LCBmYWN0b3IsIHZhbHVlICkge1xuXHRcdHZhbHVlID0gdmFsdWUgfHwge307XG5cdFx0JC5lYWNoKCBsaXN0LCBmdW5jdGlvbiggaSwgeCApIHtcblx0XHRcdHZhciB1bml0ID0gZWxlbWVudC5jc3NVbml0KCB4ICk7XG5cdFx0XHRpZiAoIHVuaXRbIDAgXSA+IDAgKSB7XG5cdFx0XHRcdHZhbHVlWyB4IF0gPSB1bml0WyAwIF0gKiBmYWN0b3IgKyB1bml0WyAxIF07XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdHJldHVybiB2YWx1ZTtcblx0fVxufSApO1xuXG4vLyBSZXR1cm4gYW4gZWZmZWN0IG9wdGlvbnMgb2JqZWN0IGZvciB0aGUgZ2l2ZW4gcGFyYW1ldGVyczpcbmZ1bmN0aW9uIF9ub3JtYWxpemVBcmd1bWVudHMoIGVmZmVjdCwgb3B0aW9ucywgc3BlZWQsIGNhbGxiYWNrICkge1xuXG5cdC8vIEFsbG93IHBhc3NpbmcgYWxsIG9wdGlvbnMgYXMgdGhlIGZpcnN0IHBhcmFtZXRlclxuXHRpZiAoICQuaXNQbGFpbk9iamVjdCggZWZmZWN0ICkgKSB7XG5cdFx0b3B0aW9ucyA9IGVmZmVjdDtcblx0XHRlZmZlY3QgPSBlZmZlY3QuZWZmZWN0O1xuXHR9XG5cblx0Ly8gQ29udmVydCB0byBhbiBvYmplY3Rcblx0ZWZmZWN0ID0geyBlZmZlY3Q6IGVmZmVjdCB9O1xuXG5cdC8vIENhdGNoIChlZmZlY3QsIG51bGwsIC4uLilcblx0aWYgKCBvcHRpb25zID09IG51bGwgKSB7XG5cdFx0b3B0aW9ucyA9IHt9O1xuXHR9XG5cblx0Ly8gQ2F0Y2ggKGVmZmVjdCwgY2FsbGJhY2spXG5cdGlmICggJC5pc0Z1bmN0aW9uKCBvcHRpb25zICkgKSB7XG5cdFx0Y2FsbGJhY2sgPSBvcHRpb25zO1xuXHRcdHNwZWVkID0gbnVsbDtcblx0XHRvcHRpb25zID0ge307XG5cdH1cblxuXHQvLyBDYXRjaCAoZWZmZWN0LCBzcGVlZCwgPylcblx0aWYgKCB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJudW1iZXJcIiB8fCAkLmZ4LnNwZWVkc1sgb3B0aW9ucyBdICkge1xuXHRcdGNhbGxiYWNrID0gc3BlZWQ7XG5cdFx0c3BlZWQgPSBvcHRpb25zO1xuXHRcdG9wdGlvbnMgPSB7fTtcblx0fVxuXG5cdC8vIENhdGNoIChlZmZlY3QsIG9wdGlvbnMsIGNhbGxiYWNrKVxuXHRpZiAoICQuaXNGdW5jdGlvbiggc3BlZWQgKSApIHtcblx0XHRjYWxsYmFjayA9IHNwZWVkO1xuXHRcdHNwZWVkID0gbnVsbDtcblx0fVxuXG5cdC8vIEFkZCBvcHRpb25zIHRvIGVmZmVjdFxuXHRpZiAoIG9wdGlvbnMgKSB7XG5cdFx0JC5leHRlbmQoIGVmZmVjdCwgb3B0aW9ucyApO1xuXHR9XG5cblx0c3BlZWQgPSBzcGVlZCB8fCBvcHRpb25zLmR1cmF0aW9uO1xuXHRlZmZlY3QuZHVyYXRpb24gPSAkLmZ4Lm9mZiA/IDAgOlxuXHRcdHR5cGVvZiBzcGVlZCA9PT0gXCJudW1iZXJcIiA/IHNwZWVkIDpcblx0XHRzcGVlZCBpbiAkLmZ4LnNwZWVkcyA/ICQuZnguc3BlZWRzWyBzcGVlZCBdIDpcblx0XHQkLmZ4LnNwZWVkcy5fZGVmYXVsdDtcblxuXHRlZmZlY3QuY29tcGxldGUgPSBjYWxsYmFjayB8fCBvcHRpb25zLmNvbXBsZXRlO1xuXG5cdHJldHVybiBlZmZlY3Q7XG59XG5cbmZ1bmN0aW9uIHN0YW5kYXJkQW5pbWF0aW9uT3B0aW9uKCBvcHRpb24gKSB7XG5cblx0Ly8gVmFsaWQgc3RhbmRhcmQgc3BlZWRzIChub3RoaW5nLCBudW1iZXIsIG5hbWVkIHNwZWVkKVxuXHRpZiAoICFvcHRpb24gfHwgdHlwZW9mIG9wdGlvbiA9PT0gXCJudW1iZXJcIiB8fCAkLmZ4LnNwZWVkc1sgb3B0aW9uIF0gKSB7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cblxuXHQvLyBJbnZhbGlkIHN0cmluZ3MgLSB0cmVhdCBhcyBcIm5vcm1hbFwiIHNwZWVkXG5cdGlmICggdHlwZW9mIG9wdGlvbiA9PT0gXCJzdHJpbmdcIiAmJiAhJC5lZmZlY3RzLmVmZmVjdFsgb3B0aW9uIF0gKSB7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cblxuXHQvLyBDb21wbGV0ZSBjYWxsYmFja1xuXHRpZiAoICQuaXNGdW5jdGlvbiggb3B0aW9uICkgKSB7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cblxuXHQvLyBPcHRpb25zIGhhc2ggKGJ1dCBub3QgbmFtaW5nIGFuIGVmZmVjdClcblx0aWYgKCB0eXBlb2Ygb3B0aW9uID09PSBcIm9iamVjdFwiICYmICFvcHRpb24uZWZmZWN0ICkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cblx0Ly8gRGlkbid0IG1hdGNoIGFueSBzdGFuZGFyZCBBUElcblx0cmV0dXJuIGZhbHNlO1xufVxuXG4kLmZuLmV4dGVuZCgge1xuXHRlZmZlY3Q6IGZ1bmN0aW9uKCAvKiBlZmZlY3QsIG9wdGlvbnMsIHNwZWVkLCBjYWxsYmFjayAqLyApIHtcblx0XHR2YXIgYXJncyA9IF9ub3JtYWxpemVBcmd1bWVudHMuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApLFxuXHRcdFx0ZWZmZWN0TWV0aG9kID0gJC5lZmZlY3RzLmVmZmVjdFsgYXJncy5lZmZlY3QgXSxcblx0XHRcdGRlZmF1bHRNb2RlID0gZWZmZWN0TWV0aG9kLm1vZGUsXG5cdFx0XHRxdWV1ZSA9IGFyZ3MucXVldWUsXG5cdFx0XHRxdWV1ZU5hbWUgPSBxdWV1ZSB8fCBcImZ4XCIsXG5cdFx0XHRjb21wbGV0ZSA9IGFyZ3MuY29tcGxldGUsXG5cdFx0XHRtb2RlID0gYXJncy5tb2RlLFxuXHRcdFx0bW9kZXMgPSBbXSxcblx0XHRcdHByZWZpbHRlciA9IGZ1bmN0aW9uKCBuZXh0ICkge1xuXHRcdFx0XHR2YXIgZWwgPSAkKCB0aGlzICksXG5cdFx0XHRcdFx0bm9ybWFsaXplZE1vZGUgPSAkLmVmZmVjdHMubW9kZSggZWwsIG1vZGUgKSB8fCBkZWZhdWx0TW9kZTtcblxuXHRcdFx0XHQvLyBTZW50aW5lbCBmb3IgZHVjay1wdW5jaGluZyB0aGUgOmFuaW1hdGVkIHBzdWVkby1zZWxlY3RvclxuXHRcdFx0XHRlbC5kYXRhKCBkYXRhU3BhY2VBbmltYXRlZCwgdHJ1ZSApO1xuXG5cdFx0XHRcdC8vIFNhdmUgZWZmZWN0IG1vZGUgZm9yIGxhdGVyIHVzZSxcblx0XHRcdFx0Ly8gd2UgY2FuJ3QganVzdCBjYWxsICQuZWZmZWN0cy5tb2RlIGFnYWluIGxhdGVyLFxuXHRcdFx0XHQvLyBhcyB0aGUgLnNob3coKSBiZWxvdyBkZXN0cm95cyB0aGUgaW5pdGlhbCBzdGF0ZVxuXHRcdFx0XHRtb2Rlcy5wdXNoKCBub3JtYWxpemVkTW9kZSApO1xuXG5cdFx0XHRcdC8vIFNlZSAkLnVpQmFja0NvbXBhdCBpbnNpZGUgb2YgcnVuKCkgZm9yIHJlbW92YWwgb2YgZGVmYXVsdE1vZGUgaW4gMS4xM1xuXHRcdFx0XHRpZiAoIGRlZmF1bHRNb2RlICYmICggbm9ybWFsaXplZE1vZGUgPT09IFwic2hvd1wiIHx8XG5cdFx0XHRcdFx0XHQoIG5vcm1hbGl6ZWRNb2RlID09PSBkZWZhdWx0TW9kZSAmJiBub3JtYWxpemVkTW9kZSA9PT0gXCJoaWRlXCIgKSApICkge1xuXHRcdFx0XHRcdGVsLnNob3coKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggIWRlZmF1bHRNb2RlIHx8IG5vcm1hbGl6ZWRNb2RlICE9PSBcIm5vbmVcIiApIHtcblx0XHRcdFx0XHQkLmVmZmVjdHMuc2F2ZVN0eWxlKCBlbCApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCAkLmlzRnVuY3Rpb24oIG5leHQgKSApIHtcblx0XHRcdFx0XHRuZXh0KCk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cblx0XHRpZiAoICQuZngub2ZmIHx8ICFlZmZlY3RNZXRob2QgKSB7XG5cblx0XHRcdC8vIERlbGVnYXRlIHRvIHRoZSBvcmlnaW5hbCBtZXRob2QgKGUuZy4sIC5zaG93KCkpIGlmIHBvc3NpYmxlXG5cdFx0XHRpZiAoIG1vZGUgKSB7XG5cdFx0XHRcdHJldHVybiB0aGlzWyBtb2RlIF0oIGFyZ3MuZHVyYXRpb24sIGNvbXBsZXRlICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRpZiAoIGNvbXBsZXRlICkge1xuXHRcdFx0XHRcdFx0Y29tcGxldGUuY2FsbCggdGhpcyApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJ1biggbmV4dCApIHtcblx0XHRcdHZhciBlbGVtID0gJCggdGhpcyApO1xuXG5cdFx0XHRmdW5jdGlvbiBjbGVhbnVwKCkge1xuXHRcdFx0XHRlbGVtLnJlbW92ZURhdGEoIGRhdGFTcGFjZUFuaW1hdGVkICk7XG5cblx0XHRcdFx0JC5lZmZlY3RzLmNsZWFuVXAoIGVsZW0gKTtcblxuXHRcdFx0XHRpZiAoIGFyZ3MubW9kZSA9PT0gXCJoaWRlXCIgKSB7XG5cdFx0XHRcdFx0ZWxlbS5oaWRlKCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRkb25lKCk7XG5cdFx0XHR9XG5cblx0XHRcdGZ1bmN0aW9uIGRvbmUoKSB7XG5cdFx0XHRcdGlmICggJC5pc0Z1bmN0aW9uKCBjb21wbGV0ZSApICkge1xuXHRcdFx0XHRcdGNvbXBsZXRlLmNhbGwoIGVsZW1bIDAgXSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCAkLmlzRnVuY3Rpb24oIG5leHQgKSApIHtcblx0XHRcdFx0XHRuZXh0KCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gT3ZlcnJpZGUgbW9kZSBvcHRpb24gb24gYSBwZXIgZWxlbWVudCBiYXNpcyxcblx0XHRcdC8vIGFzIHRvZ2dsZSBjYW4gYmUgZWl0aGVyIHNob3cgb3IgaGlkZSBkZXBlbmRpbmcgb24gZWxlbWVudCBzdGF0ZVxuXHRcdFx0YXJncy5tb2RlID0gbW9kZXMuc2hpZnQoKTtcblxuXHRcdFx0aWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgJiYgIWRlZmF1bHRNb2RlICkge1xuXHRcdFx0XHRpZiAoIGVsZW0uaXMoIFwiOmhpZGRlblwiICkgPyBtb2RlID09PSBcImhpZGVcIiA6IG1vZGUgPT09IFwic2hvd1wiICkge1xuXG5cdFx0XHRcdFx0Ly8gQ2FsbCB0aGUgY29yZSBtZXRob2QgdG8gdHJhY2sgXCJvbGRkaXNwbGF5XCIgcHJvcGVybHlcblx0XHRcdFx0XHRlbGVtWyBtb2RlIF0oKTtcblx0XHRcdFx0XHRkb25lKCk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0ZWZmZWN0TWV0aG9kLmNhbGwoIGVsZW1bIDAgXSwgYXJncywgZG9uZSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpZiAoIGFyZ3MubW9kZSA9PT0gXCJub25lXCIgKSB7XG5cblx0XHRcdFx0XHQvLyBDYWxsIHRoZSBjb3JlIG1ldGhvZCB0byB0cmFjayBcIm9sZGRpc3BsYXlcIiBwcm9wZXJseVxuXHRcdFx0XHRcdGVsZW1bIG1vZGUgXSgpO1xuXHRcdFx0XHRcdGRvbmUoKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRlZmZlY3RNZXRob2QuY2FsbCggZWxlbVsgMCBdLCBhcmdzLCBjbGVhbnVwICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBSdW4gcHJlZmlsdGVyIG9uIGFsbCBlbGVtZW50cyBmaXJzdCB0byBlbnN1cmUgdGhhdFxuXHRcdC8vIGFueSBzaG93aW5nIG9yIGhpZGluZyBoYXBwZW5zIGJlZm9yZSBwbGFjZWhvbGRlciBjcmVhdGlvbixcblx0XHQvLyB3aGljaCBlbnN1cmVzIHRoYXQgYW55IGxheW91dCBjaGFuZ2VzIGFyZSBjb3JyZWN0bHkgY2FwdHVyZWQuXG5cdFx0cmV0dXJuIHF1ZXVlID09PSBmYWxzZSA/XG5cdFx0XHR0aGlzLmVhY2goIHByZWZpbHRlciApLmVhY2goIHJ1biApIDpcblx0XHRcdHRoaXMucXVldWUoIHF1ZXVlTmFtZSwgcHJlZmlsdGVyICkucXVldWUoIHF1ZXVlTmFtZSwgcnVuICk7XG5cdH0sXG5cblx0c2hvdzogKCBmdW5jdGlvbiggb3JpZyApIHtcblx0XHRyZXR1cm4gZnVuY3Rpb24oIG9wdGlvbiApIHtcblx0XHRcdGlmICggc3RhbmRhcmRBbmltYXRpb25PcHRpb24oIG9wdGlvbiApICkge1xuXHRcdFx0XHRyZXR1cm4gb3JpZy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR2YXIgYXJncyA9IF9ub3JtYWxpemVBcmd1bWVudHMuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRhcmdzLm1vZGUgPSBcInNob3dcIjtcblx0XHRcdFx0cmV0dXJuIHRoaXMuZWZmZWN0LmNhbGwoIHRoaXMsIGFyZ3MgKTtcblx0XHRcdH1cblx0XHR9O1xuXHR9ICkoICQuZm4uc2hvdyApLFxuXG5cdGhpZGU6ICggZnVuY3Rpb24oIG9yaWcgKSB7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCBvcHRpb24gKSB7XG5cdFx0XHRpZiAoIHN0YW5kYXJkQW5pbWF0aW9uT3B0aW9uKCBvcHRpb24gKSApIHtcblx0XHRcdFx0cmV0dXJuIG9yaWcuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dmFyIGFyZ3MgPSBfbm9ybWFsaXplQXJndW1lbnRzLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdFx0YXJncy5tb2RlID0gXCJoaWRlXCI7XG5cdFx0XHRcdHJldHVybiB0aGlzLmVmZmVjdC5jYWxsKCB0aGlzLCBhcmdzICk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fSApKCAkLmZuLmhpZGUgKSxcblxuXHR0b2dnbGU6ICggZnVuY3Rpb24oIG9yaWcgKSB7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCBvcHRpb24gKSB7XG5cdFx0XHRpZiAoIHN0YW5kYXJkQW5pbWF0aW9uT3B0aW9uKCBvcHRpb24gKSB8fCB0eXBlb2Ygb3B0aW9uID09PSBcImJvb2xlYW5cIiApIHtcblx0XHRcdFx0cmV0dXJuIG9yaWcuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dmFyIGFyZ3MgPSBfbm9ybWFsaXplQXJndW1lbnRzLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdFx0YXJncy5tb2RlID0gXCJ0b2dnbGVcIjtcblx0XHRcdFx0cmV0dXJuIHRoaXMuZWZmZWN0LmNhbGwoIHRoaXMsIGFyZ3MgKTtcblx0XHRcdH1cblx0XHR9O1xuXHR9ICkoICQuZm4udG9nZ2xlICksXG5cblx0Y3NzVW5pdDogZnVuY3Rpb24oIGtleSApIHtcblx0XHR2YXIgc3R5bGUgPSB0aGlzLmNzcygga2V5ICksXG5cdFx0XHR2YWwgPSBbXTtcblxuXHRcdCQuZWFjaCggWyBcImVtXCIsIFwicHhcIiwgXCIlXCIsIFwicHRcIiBdLCBmdW5jdGlvbiggaSwgdW5pdCApIHtcblx0XHRcdGlmICggc3R5bGUuaW5kZXhPZiggdW5pdCApID4gMCApIHtcblx0XHRcdFx0dmFsID0gWyBwYXJzZUZsb2F0KCBzdHlsZSApLCB1bml0IF07XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdHJldHVybiB2YWw7XG5cdH0sXG5cblx0Y3NzQ2xpcDogZnVuY3Rpb24oIGNsaXBPYmogKSB7XG5cdFx0aWYgKCBjbGlwT2JqICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuY3NzKCBcImNsaXBcIiwgXCJyZWN0KFwiICsgY2xpcE9iai50b3AgKyBcInB4IFwiICsgY2xpcE9iai5yaWdodCArIFwicHggXCIgK1xuXHRcdFx0XHRjbGlwT2JqLmJvdHRvbSArIFwicHggXCIgKyBjbGlwT2JqLmxlZnQgKyBcInB4KVwiICk7XG5cdFx0fVxuXHRcdHJldHVybiBwYXJzZUNsaXAoIHRoaXMuY3NzKCBcImNsaXBcIiApLCB0aGlzICk7XG5cdH0sXG5cblx0dHJhbnNmZXI6IGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHRcdHZhciBlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdFx0dGFyZ2V0ID0gJCggb3B0aW9ucy50byApLFxuXHRcdFx0dGFyZ2V0Rml4ZWQgPSB0YXJnZXQuY3NzKCBcInBvc2l0aW9uXCIgKSA9PT0gXCJmaXhlZFwiLFxuXHRcdFx0Ym9keSA9ICQoIFwiYm9keVwiICksXG5cdFx0XHRmaXhUb3AgPSB0YXJnZXRGaXhlZCA/IGJvZHkuc2Nyb2xsVG9wKCkgOiAwLFxuXHRcdFx0Zml4TGVmdCA9IHRhcmdldEZpeGVkID8gYm9keS5zY3JvbGxMZWZ0KCkgOiAwLFxuXHRcdFx0ZW5kUG9zaXRpb24gPSB0YXJnZXQub2Zmc2V0KCksXG5cdFx0XHRhbmltYXRpb24gPSB7XG5cdFx0XHRcdHRvcDogZW5kUG9zaXRpb24udG9wIC0gZml4VG9wLFxuXHRcdFx0XHRsZWZ0OiBlbmRQb3NpdGlvbi5sZWZ0IC0gZml4TGVmdCxcblx0XHRcdFx0aGVpZ2h0OiB0YXJnZXQuaW5uZXJIZWlnaHQoKSxcblx0XHRcdFx0d2lkdGg6IHRhcmdldC5pbm5lcldpZHRoKClcblx0XHRcdH0sXG5cdFx0XHRzdGFydFBvc2l0aW9uID0gZWxlbWVudC5vZmZzZXQoKSxcblx0XHRcdHRyYW5zZmVyID0gJCggXCI8ZGl2IGNsYXNzPSd1aS1lZmZlY3RzLXRyYW5zZmVyJz48L2Rpdj5cIiApXG5cdFx0XHRcdC5hcHBlbmRUbyggXCJib2R5XCIgKVxuXHRcdFx0XHQuYWRkQ2xhc3MoIG9wdGlvbnMuY2xhc3NOYW1lIClcblx0XHRcdFx0LmNzcygge1xuXHRcdFx0XHRcdHRvcDogc3RhcnRQb3NpdGlvbi50b3AgLSBmaXhUb3AsXG5cdFx0XHRcdFx0bGVmdDogc3RhcnRQb3NpdGlvbi5sZWZ0IC0gZml4TGVmdCxcblx0XHRcdFx0XHRoZWlnaHQ6IGVsZW1lbnQuaW5uZXJIZWlnaHQoKSxcblx0XHRcdFx0XHR3aWR0aDogZWxlbWVudC5pbm5lcldpZHRoKCksXG5cdFx0XHRcdFx0cG9zaXRpb246IHRhcmdldEZpeGVkID8gXCJmaXhlZFwiIDogXCJhYnNvbHV0ZVwiXG5cdFx0XHRcdH0gKVxuXHRcdFx0XHQuYW5pbWF0ZSggYW5pbWF0aW9uLCBvcHRpb25zLmR1cmF0aW9uLCBvcHRpb25zLmVhc2luZywgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0dHJhbnNmZXIucmVtb3ZlKCk7XG5cdFx0XHRcdFx0aWYgKCAkLmlzRnVuY3Rpb24oIGRvbmUgKSApIHtcblx0XHRcdFx0XHRcdGRvbmUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0fVxufSApO1xuXG5mdW5jdGlvbiBwYXJzZUNsaXAoIHN0ciwgZWxlbWVudCApIHtcblx0XHR2YXIgb3V0ZXJXaWR0aCA9IGVsZW1lbnQub3V0ZXJXaWR0aCgpLFxuXHRcdFx0b3V0ZXJIZWlnaHQgPSBlbGVtZW50Lm91dGVySGVpZ2h0KCksXG5cdFx0XHRjbGlwUmVnZXggPSAvXnJlY3RcXCgoLT9cXGQqXFwuP1xcZCpweHwtP1xcZCslfGF1dG8pLD9cXHMqKC0/XFxkKlxcLj9cXGQqcHh8LT9cXGQrJXxhdXRvKSw/XFxzKigtP1xcZCpcXC4/XFxkKnB4fC0/XFxkKyV8YXV0byksP1xccyooLT9cXGQqXFwuP1xcZCpweHwtP1xcZCslfGF1dG8pXFwpJC8sXG5cdFx0XHR2YWx1ZXMgPSBjbGlwUmVnZXguZXhlYyggc3RyICkgfHwgWyBcIlwiLCAwLCBvdXRlcldpZHRoLCBvdXRlckhlaWdodCwgMCBdO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogcGFyc2VGbG9hdCggdmFsdWVzWyAxIF0gKSB8fCAwLFxuXHRcdFx0cmlnaHQ6IHZhbHVlc1sgMiBdID09PSBcImF1dG9cIiA/IG91dGVyV2lkdGggOiBwYXJzZUZsb2F0KCB2YWx1ZXNbIDIgXSApLFxuXHRcdFx0Ym90dG9tOiB2YWx1ZXNbIDMgXSA9PT0gXCJhdXRvXCIgPyBvdXRlckhlaWdodCA6IHBhcnNlRmxvYXQoIHZhbHVlc1sgMyBdICksXG5cdFx0XHRsZWZ0OiBwYXJzZUZsb2F0KCB2YWx1ZXNbIDQgXSApIHx8IDBcblx0XHR9O1xufVxuXG4kLmZ4LnN0ZXAuY2xpcCA9IGZ1bmN0aW9uKCBmeCApIHtcblx0aWYgKCAhZnguY2xpcEluaXQgKSB7XG5cdFx0Znguc3RhcnQgPSAkKCBmeC5lbGVtICkuY3NzQ2xpcCgpO1xuXHRcdGlmICggdHlwZW9mIGZ4LmVuZCA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdGZ4LmVuZCA9IHBhcnNlQ2xpcCggZnguZW5kLCBmeC5lbGVtICk7XG5cdFx0fVxuXHRcdGZ4LmNsaXBJbml0ID0gdHJ1ZTtcblx0fVxuXG5cdCQoIGZ4LmVsZW0gKS5jc3NDbGlwKCB7XG5cdFx0dG9wOiBmeC5wb3MgKiAoIGZ4LmVuZC50b3AgLSBmeC5zdGFydC50b3AgKSArIGZ4LnN0YXJ0LnRvcCxcblx0XHRyaWdodDogZngucG9zICogKCBmeC5lbmQucmlnaHQgLSBmeC5zdGFydC5yaWdodCApICsgZnguc3RhcnQucmlnaHQsXG5cdFx0Ym90dG9tOiBmeC5wb3MgKiAoIGZ4LmVuZC5ib3R0b20gLSBmeC5zdGFydC5ib3R0b20gKSArIGZ4LnN0YXJ0LmJvdHRvbSxcblx0XHRsZWZ0OiBmeC5wb3MgKiAoIGZ4LmVuZC5sZWZ0IC0gZnguc3RhcnQubGVmdCApICsgZnguc3RhcnQubGVmdFxuXHR9ICk7XG59O1xuXG59ICkoKTtcblxuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiBFQVNJTkcgKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4oIGZ1bmN0aW9uKCkge1xuXG4vLyBCYXNlZCBvbiBlYXNpbmcgZXF1YXRpb25zIGZyb20gUm9iZXJ0IFBlbm5lciAoaHR0cDovL3d3dy5yb2JlcnRwZW5uZXIuY29tL2Vhc2luZylcblxudmFyIGJhc2VFYXNpbmdzID0ge307XG5cbiQuZWFjaCggWyBcIlF1YWRcIiwgXCJDdWJpY1wiLCBcIlF1YXJ0XCIsIFwiUXVpbnRcIiwgXCJFeHBvXCIgXSwgZnVuY3Rpb24oIGksIG5hbWUgKSB7XG5cdGJhc2VFYXNpbmdzWyBuYW1lIF0gPSBmdW5jdGlvbiggcCApIHtcblx0XHRyZXR1cm4gTWF0aC5wb3coIHAsIGkgKyAyICk7XG5cdH07XG59ICk7XG5cbiQuZXh0ZW5kKCBiYXNlRWFzaW5ncywge1xuXHRTaW5lOiBmdW5jdGlvbiggcCApIHtcblx0XHRyZXR1cm4gMSAtIE1hdGguY29zKCBwICogTWF0aC5QSSAvIDIgKTtcblx0fSxcblx0Q2lyYzogZnVuY3Rpb24oIHAgKSB7XG5cdFx0cmV0dXJuIDEgLSBNYXRoLnNxcnQoIDEgLSBwICogcCApO1xuXHR9LFxuXHRFbGFzdGljOiBmdW5jdGlvbiggcCApIHtcblx0XHRyZXR1cm4gcCA9PT0gMCB8fCBwID09PSAxID8gcCA6XG5cdFx0XHQtTWF0aC5wb3coIDIsIDggKiAoIHAgLSAxICkgKSAqIE1hdGguc2luKCAoICggcCAtIDEgKSAqIDgwIC0gNy41ICkgKiBNYXRoLlBJIC8gMTUgKTtcblx0fSxcblx0QmFjazogZnVuY3Rpb24oIHAgKSB7XG5cdFx0cmV0dXJuIHAgKiBwICogKCAzICogcCAtIDIgKTtcblx0fSxcblx0Qm91bmNlOiBmdW5jdGlvbiggcCApIHtcblx0XHR2YXIgcG93Mixcblx0XHRcdGJvdW5jZSA9IDQ7XG5cblx0XHR3aGlsZSAoIHAgPCAoICggcG93MiA9IE1hdGgucG93KCAyLCAtLWJvdW5jZSApICkgLSAxICkgLyAxMSApIHt9XG5cdFx0cmV0dXJuIDEgLyBNYXRoLnBvdyggNCwgMyAtIGJvdW5jZSApIC0gNy41NjI1ICogTWF0aC5wb3coICggcG93MiAqIDMgLSAyICkgLyAyMiAtIHAsIDIgKTtcblx0fVxufSApO1xuXG4kLmVhY2goIGJhc2VFYXNpbmdzLCBmdW5jdGlvbiggbmFtZSwgZWFzZUluICkge1xuXHQkLmVhc2luZ1sgXCJlYXNlSW5cIiArIG5hbWUgXSA9IGVhc2VJbjtcblx0JC5lYXNpbmdbIFwiZWFzZU91dFwiICsgbmFtZSBdID0gZnVuY3Rpb24oIHAgKSB7XG5cdFx0cmV0dXJuIDEgLSBlYXNlSW4oIDEgLSBwICk7XG5cdH07XG5cdCQuZWFzaW5nWyBcImVhc2VJbk91dFwiICsgbmFtZSBdID0gZnVuY3Rpb24oIHAgKSB7XG5cdFx0cmV0dXJuIHAgPCAwLjUgP1xuXHRcdFx0ZWFzZUluKCBwICogMiApIC8gMiA6XG5cdFx0XHQxIC0gZWFzZUluKCBwICogLTIgKyAyICkgLyAyO1xuXHR9O1xufSApO1xuXG59ICkoKTtcblxudmFyIGVmZmVjdCA9ICQuZWZmZWN0cztcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIEJsaW5kIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBCbGluZCBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBCbGluZHMgdGhlIGVsZW1lbnQuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vYmxpbmQtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0QmxpbmQgPSAkLmVmZmVjdHMuZGVmaW5lKCBcImJsaW5kXCIsIFwiaGlkZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0dmFyIG1hcCA9IHtcblx0XHRcdHVwOiBbIFwiYm90dG9tXCIsIFwidG9wXCIgXSxcblx0XHRcdHZlcnRpY2FsOiBbIFwiYm90dG9tXCIsIFwidG9wXCIgXSxcblx0XHRcdGRvd246IFsgXCJ0b3BcIiwgXCJib3R0b21cIiBdLFxuXHRcdFx0bGVmdDogWyBcInJpZ2h0XCIsIFwibGVmdFwiIF0sXG5cdFx0XHRob3Jpem9udGFsOiBbIFwicmlnaHRcIiwgXCJsZWZ0XCIgXSxcblx0XHRcdHJpZ2h0OiBbIFwibGVmdFwiLCBcInJpZ2h0XCIgXVxuXHRcdH0sXG5cdFx0ZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRkaXJlY3Rpb24gPSBvcHRpb25zLmRpcmVjdGlvbiB8fCBcInVwXCIsXG5cdFx0c3RhcnQgPSBlbGVtZW50LmNzc0NsaXAoKSxcblx0XHRhbmltYXRlID0geyBjbGlwOiAkLmV4dGVuZCgge30sIHN0YXJ0ICkgfSxcblx0XHRwbGFjZWhvbGRlciA9ICQuZWZmZWN0cy5jcmVhdGVQbGFjZWhvbGRlciggZWxlbWVudCApO1xuXG5cdGFuaW1hdGUuY2xpcFsgbWFwWyBkaXJlY3Rpb24gXVsgMCBdIF0gPSBhbmltYXRlLmNsaXBbIG1hcFsgZGlyZWN0aW9uIF1bIDEgXSBdO1xuXG5cdGlmICggb3B0aW9ucy5tb2RlID09PSBcInNob3dcIiApIHtcblx0XHRlbGVtZW50LmNzc0NsaXAoIGFuaW1hdGUuY2xpcCApO1xuXHRcdGlmICggcGxhY2Vob2xkZXIgKSB7XG5cdFx0XHRwbGFjZWhvbGRlci5jc3MoICQuZWZmZWN0cy5jbGlwVG9Cb3goIGFuaW1hdGUgKSApO1xuXHRcdH1cblxuXHRcdGFuaW1hdGUuY2xpcCA9IHN0YXJ0O1xuXHR9XG5cblx0aWYgKCBwbGFjZWhvbGRlciApIHtcblx0XHRwbGFjZWhvbGRlci5hbmltYXRlKCAkLmVmZmVjdHMuY2xpcFRvQm94KCBhbmltYXRlICksIG9wdGlvbnMuZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nICk7XG5cdH1cblxuXHRlbGVtZW50LmFuaW1hdGUoIGFuaW1hdGUsIHtcblx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0ZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sXG5cdFx0ZWFzaW5nOiBvcHRpb25zLmVhc2luZyxcblx0XHRjb21wbGV0ZTogZG9uZVxuXHR9ICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBCb3VuY2UgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEJvdW5jZSBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBCb3VuY2VzIGFuIGVsZW1lbnQgaG9yaXpvbnRhbGx5IG9yIHZlcnRpY2FsbHkgbiB0aW1lcy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9ib3VuY2UtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0Qm91bmNlID0gJC5lZmZlY3RzLmRlZmluZSggXCJib3VuY2VcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdHZhciB1cEFuaW0sIGRvd25BbmltLCByZWZWYWx1ZSxcblx0XHRlbGVtZW50ID0gJCggdGhpcyApLFxuXG5cdFx0Ly8gRGVmYXVsdHM6XG5cdFx0bW9kZSA9IG9wdGlvbnMubW9kZSxcblx0XHRoaWRlID0gbW9kZSA9PT0gXCJoaWRlXCIsXG5cdFx0c2hvdyA9IG1vZGUgPT09IFwic2hvd1wiLFxuXHRcdGRpcmVjdGlvbiA9IG9wdGlvbnMuZGlyZWN0aW9uIHx8IFwidXBcIixcblx0XHRkaXN0YW5jZSA9IG9wdGlvbnMuZGlzdGFuY2UsXG5cdFx0dGltZXMgPSBvcHRpb25zLnRpbWVzIHx8IDUsXG5cblx0XHQvLyBOdW1iZXIgb2YgaW50ZXJuYWwgYW5pbWF0aW9uc1xuXHRcdGFuaW1zID0gdGltZXMgKiAyICsgKCBzaG93IHx8IGhpZGUgPyAxIDogMCApLFxuXHRcdHNwZWVkID0gb3B0aW9ucy5kdXJhdGlvbiAvIGFuaW1zLFxuXHRcdGVhc2luZyA9IG9wdGlvbnMuZWFzaW5nLFxuXG5cdFx0Ly8gVXRpbGl0eTpcblx0XHRyZWYgPSAoIGRpcmVjdGlvbiA9PT0gXCJ1cFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJkb3duXCIgKSA/IFwidG9wXCIgOiBcImxlZnRcIixcblx0XHRtb3Rpb24gPSAoIGRpcmVjdGlvbiA9PT0gXCJ1cFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJsZWZ0XCIgKSxcblx0XHRpID0gMCxcblxuXHRcdHF1ZXVlbGVuID0gZWxlbWVudC5xdWV1ZSgpLmxlbmd0aDtcblxuXHQkLmVmZmVjdHMuY3JlYXRlUGxhY2Vob2xkZXIoIGVsZW1lbnQgKTtcblxuXHRyZWZWYWx1ZSA9IGVsZW1lbnQuY3NzKCByZWYgKTtcblxuXHQvLyBEZWZhdWx0IGRpc3RhbmNlIGZvciB0aGUgQklHR0VTVCBib3VuY2UgaXMgdGhlIG91dGVyIERpc3RhbmNlIC8gM1xuXHRpZiAoICFkaXN0YW5jZSApIHtcblx0XHRkaXN0YW5jZSA9IGVsZW1lbnRbIHJlZiA9PT0gXCJ0b3BcIiA/IFwib3V0ZXJIZWlnaHRcIiA6IFwib3V0ZXJXaWR0aFwiIF0oKSAvIDM7XG5cdH1cblxuXHRpZiAoIHNob3cgKSB7XG5cdFx0ZG93bkFuaW0gPSB7IG9wYWNpdHk6IDEgfTtcblx0XHRkb3duQW5pbVsgcmVmIF0gPSByZWZWYWx1ZTtcblxuXHRcdC8vIElmIHdlIGFyZSBzaG93aW5nLCBmb3JjZSBvcGFjaXR5IDAgYW5kIHNldCB0aGUgaW5pdGlhbCBwb3NpdGlvblxuXHRcdC8vIHRoZW4gZG8gdGhlIFwiZmlyc3RcIiBhbmltYXRpb25cblx0XHRlbGVtZW50XG5cdFx0XHQuY3NzKCBcIm9wYWNpdHlcIiwgMCApXG5cdFx0XHQuY3NzKCByZWYsIG1vdGlvbiA/IC1kaXN0YW5jZSAqIDIgOiBkaXN0YW5jZSAqIDIgKVxuXHRcdFx0LmFuaW1hdGUoIGRvd25BbmltLCBzcGVlZCwgZWFzaW5nICk7XG5cdH1cblxuXHQvLyBTdGFydCBhdCB0aGUgc21hbGxlc3QgZGlzdGFuY2UgaWYgd2UgYXJlIGhpZGluZ1xuXHRpZiAoIGhpZGUgKSB7XG5cdFx0ZGlzdGFuY2UgPSBkaXN0YW5jZSAvIE1hdGgucG93KCAyLCB0aW1lcyAtIDEgKTtcblx0fVxuXG5cdGRvd25BbmltID0ge307XG5cdGRvd25BbmltWyByZWYgXSA9IHJlZlZhbHVlO1xuXG5cdC8vIEJvdW5jZXMgdXAvZG93bi9sZWZ0L3JpZ2h0IHRoZW4gYmFjayB0byAwIC0tIHRpbWVzICogMiBhbmltYXRpb25zIGhhcHBlbiBoZXJlXG5cdGZvciAoIDsgaSA8IHRpbWVzOyBpKysgKSB7XG5cdFx0dXBBbmltID0ge307XG5cdFx0dXBBbmltWyByZWYgXSA9ICggbW90aW9uID8gXCItPVwiIDogXCIrPVwiICkgKyBkaXN0YW5jZTtcblxuXHRcdGVsZW1lbnRcblx0XHRcdC5hbmltYXRlKCB1cEFuaW0sIHNwZWVkLCBlYXNpbmcgKVxuXHRcdFx0LmFuaW1hdGUoIGRvd25BbmltLCBzcGVlZCwgZWFzaW5nICk7XG5cblx0XHRkaXN0YW5jZSA9IGhpZGUgPyBkaXN0YW5jZSAqIDIgOiBkaXN0YW5jZSAvIDI7XG5cdH1cblxuXHQvLyBMYXN0IEJvdW5jZSB3aGVuIEhpZGluZ1xuXHRpZiAoIGhpZGUgKSB7XG5cdFx0dXBBbmltID0geyBvcGFjaXR5OiAwIH07XG5cdFx0dXBBbmltWyByZWYgXSA9ICggbW90aW9uID8gXCItPVwiIDogXCIrPVwiICkgKyBkaXN0YW5jZTtcblxuXHRcdGVsZW1lbnQuYW5pbWF0ZSggdXBBbmltLCBzcGVlZCwgZWFzaW5nICk7XG5cdH1cblxuXHRlbGVtZW50LnF1ZXVlKCBkb25lICk7XG5cblx0JC5lZmZlY3RzLnVuc2hpZnQoIGVsZW1lbnQsIHF1ZXVlbGVuLCBhbmltcyArIDEgKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIENsaXAgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IENsaXAgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogQ2xpcHMgdGhlIGVsZW1lbnQgb24gYW5kIG9mZiBsaWtlIGFuIG9sZCBUVi5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9jbGlwLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdENsaXAgPSAkLmVmZmVjdHMuZGVmaW5lKCBcImNsaXBcIiwgXCJoaWRlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHR2YXIgc3RhcnQsXG5cdFx0YW5pbWF0ZSA9IHt9LFxuXHRcdGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0ZGlyZWN0aW9uID0gb3B0aW9ucy5kaXJlY3Rpb24gfHwgXCJ2ZXJ0aWNhbFwiLFxuXHRcdGJvdGggPSBkaXJlY3Rpb24gPT09IFwiYm90aFwiLFxuXHRcdGhvcml6b250YWwgPSBib3RoIHx8IGRpcmVjdGlvbiA9PT0gXCJob3Jpem9udGFsXCIsXG5cdFx0dmVydGljYWwgPSBib3RoIHx8IGRpcmVjdGlvbiA9PT0gXCJ2ZXJ0aWNhbFwiO1xuXG5cdHN0YXJ0ID0gZWxlbWVudC5jc3NDbGlwKCk7XG5cdGFuaW1hdGUuY2xpcCA9IHtcblx0XHR0b3A6IHZlcnRpY2FsID8gKCBzdGFydC5ib3R0b20gLSBzdGFydC50b3AgKSAvIDIgOiBzdGFydC50b3AsXG5cdFx0cmlnaHQ6IGhvcml6b250YWwgPyAoIHN0YXJ0LnJpZ2h0IC0gc3RhcnQubGVmdCApIC8gMiA6IHN0YXJ0LnJpZ2h0LFxuXHRcdGJvdHRvbTogdmVydGljYWwgPyAoIHN0YXJ0LmJvdHRvbSAtIHN0YXJ0LnRvcCApIC8gMiA6IHN0YXJ0LmJvdHRvbSxcblx0XHRsZWZ0OiBob3Jpem9udGFsID8gKCBzdGFydC5yaWdodCAtIHN0YXJ0LmxlZnQgKSAvIDIgOiBzdGFydC5sZWZ0XG5cdH07XG5cblx0JC5lZmZlY3RzLmNyZWF0ZVBsYWNlaG9sZGVyKCBlbGVtZW50ICk7XG5cblx0aWYgKCBvcHRpb25zLm1vZGUgPT09IFwic2hvd1wiICkge1xuXHRcdGVsZW1lbnQuY3NzQ2xpcCggYW5pbWF0ZS5jbGlwICk7XG5cdFx0YW5pbWF0ZS5jbGlwID0gc3RhcnQ7XG5cdH1cblxuXHRlbGVtZW50LmFuaW1hdGUoIGFuaW1hdGUsIHtcblx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0ZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sXG5cdFx0ZWFzaW5nOiBvcHRpb25zLmVhc2luZyxcblx0XHRjb21wbGV0ZTogZG9uZVxuXHR9ICk7XG5cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIERyb3AgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IERyb3AgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogTW92ZXMgYW4gZWxlbWVudCBpbiBvbmUgZGlyZWN0aW9uIGFuZCBoaWRlcyBpdCBhdCB0aGUgc2FtZSB0aW1lLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2Ryb3AtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0RHJvcCA9ICQuZWZmZWN0cy5kZWZpbmUoIFwiZHJvcFwiLCBcImhpZGVcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cblx0dmFyIGRpc3RhbmNlLFxuXHRcdGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0bW9kZSA9IG9wdGlvbnMubW9kZSxcblx0XHRzaG93ID0gbW9kZSA9PT0gXCJzaG93XCIsXG5cdFx0ZGlyZWN0aW9uID0gb3B0aW9ucy5kaXJlY3Rpb24gfHwgXCJsZWZ0XCIsXG5cdFx0cmVmID0gKCBkaXJlY3Rpb24gPT09IFwidXBcIiB8fCBkaXJlY3Rpb24gPT09IFwiZG93blwiICkgPyBcInRvcFwiIDogXCJsZWZ0XCIsXG5cdFx0bW90aW9uID0gKCBkaXJlY3Rpb24gPT09IFwidXBcIiB8fCBkaXJlY3Rpb24gPT09IFwibGVmdFwiICkgPyBcIi09XCIgOiBcIis9XCIsXG5cdFx0b3Bwb3NpdGVNb3Rpb24gPSAoIG1vdGlvbiA9PT0gXCIrPVwiICkgPyBcIi09XCIgOiBcIis9XCIsXG5cdFx0YW5pbWF0aW9uID0ge1xuXHRcdFx0b3BhY2l0eTogMFxuXHRcdH07XG5cblx0JC5lZmZlY3RzLmNyZWF0ZVBsYWNlaG9sZGVyKCBlbGVtZW50ICk7XG5cblx0ZGlzdGFuY2UgPSBvcHRpb25zLmRpc3RhbmNlIHx8XG5cdFx0ZWxlbWVudFsgcmVmID09PSBcInRvcFwiID8gXCJvdXRlckhlaWdodFwiIDogXCJvdXRlcldpZHRoXCIgXSggdHJ1ZSApIC8gMjtcblxuXHRhbmltYXRpb25bIHJlZiBdID0gbW90aW9uICsgZGlzdGFuY2U7XG5cblx0aWYgKCBzaG93ICkge1xuXHRcdGVsZW1lbnQuY3NzKCBhbmltYXRpb24gKTtcblxuXHRcdGFuaW1hdGlvblsgcmVmIF0gPSBvcHBvc2l0ZU1vdGlvbiArIGRpc3RhbmNlO1xuXHRcdGFuaW1hdGlvbi5vcGFjaXR5ID0gMTtcblx0fVxuXG5cdC8vIEFuaW1hdGVcblx0ZWxlbWVudC5hbmltYXRlKCBhbmltYXRpb24sIHtcblx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0ZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sXG5cdFx0ZWFzaW5nOiBvcHRpb25zLmVhc2luZyxcblx0XHRjb21wbGV0ZTogZG9uZVxuXHR9ICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBFeHBsb2RlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBFeHBsb2RlIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLyBqc2NzOmRpc2FibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kZXNjcmlwdGlvbjogRXhwbG9kZXMgYW4gZWxlbWVudCBpbiBhbGwgZGlyZWN0aW9ucyBpbnRvIG4gcGllY2VzLiBJbXBsb2RlcyBhbiBlbGVtZW50IHRvIGl0cyBvcmlnaW5hbCB3aG9sZW5lc3MuXG4vLyBqc2NzOmVuYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2V4cGxvZGUtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0RXhwbG9kZSA9ICQuZWZmZWN0cy5kZWZpbmUoIFwiZXhwbG9kZVwiLCBcImhpZGVcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cblx0dmFyIGksIGosIGxlZnQsIHRvcCwgbXgsIG15LFxuXHRcdHJvd3MgPSBvcHRpb25zLnBpZWNlcyA/IE1hdGgucm91bmQoIE1hdGguc3FydCggb3B0aW9ucy5waWVjZXMgKSApIDogMyxcblx0XHRjZWxscyA9IHJvd3MsXG5cdFx0ZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRtb2RlID0gb3B0aW9ucy5tb2RlLFxuXHRcdHNob3cgPSBtb2RlID09PSBcInNob3dcIixcblxuXHRcdC8vIFNob3cgYW5kIHRoZW4gdmlzaWJpbGl0eTpoaWRkZW4gdGhlIGVsZW1lbnQgYmVmb3JlIGNhbGN1bGF0aW5nIG9mZnNldFxuXHRcdG9mZnNldCA9IGVsZW1lbnQuc2hvdygpLmNzcyggXCJ2aXNpYmlsaXR5XCIsIFwiaGlkZGVuXCIgKS5vZmZzZXQoKSxcblxuXHRcdC8vIFdpZHRoIGFuZCBoZWlnaHQgb2YgYSBwaWVjZVxuXHRcdHdpZHRoID0gTWF0aC5jZWlsKCBlbGVtZW50Lm91dGVyV2lkdGgoKSAvIGNlbGxzICksXG5cdFx0aGVpZ2h0ID0gTWF0aC5jZWlsKCBlbGVtZW50Lm91dGVySGVpZ2h0KCkgLyByb3dzICksXG5cdFx0cGllY2VzID0gW107XG5cblx0Ly8gQ2hpbGRyZW4gYW5pbWF0ZSBjb21wbGV0ZTpcblx0ZnVuY3Rpb24gY2hpbGRDb21wbGV0ZSgpIHtcblx0XHRwaWVjZXMucHVzaCggdGhpcyApO1xuXHRcdGlmICggcGllY2VzLmxlbmd0aCA9PT0gcm93cyAqIGNlbGxzICkge1xuXHRcdFx0YW5pbUNvbXBsZXRlKCk7XG5cdFx0fVxuXHR9XG5cblx0Ly8gQ2xvbmUgdGhlIGVsZW1lbnQgZm9yIGVhY2ggcm93IGFuZCBjZWxsLlxuXHRmb3IgKCBpID0gMDsgaSA8IHJvd3M7IGkrKyApIHsgLy8gPT09PlxuXHRcdHRvcCA9IG9mZnNldC50b3AgKyBpICogaGVpZ2h0O1xuXHRcdG15ID0gaSAtICggcm93cyAtIDEgKSAvIDI7XG5cblx0XHRmb3IgKCBqID0gMDsgaiA8IGNlbGxzOyBqKysgKSB7IC8vIHx8fFxuXHRcdFx0bGVmdCA9IG9mZnNldC5sZWZ0ICsgaiAqIHdpZHRoO1xuXHRcdFx0bXggPSBqIC0gKCBjZWxscyAtIDEgKSAvIDI7XG5cblx0XHRcdC8vIENyZWF0ZSBhIGNsb25lIG9mIHRoZSBub3cgaGlkZGVuIG1haW4gZWxlbWVudCB0aGF0IHdpbGwgYmUgYWJzb2x1dGUgcG9zaXRpb25lZFxuXHRcdFx0Ly8gd2l0aGluIGEgd3JhcHBlciBkaXYgb2ZmIHRoZSAtbGVmdCBhbmQgLXRvcCBlcXVhbCB0byBzaXplIG9mIG91ciBwaWVjZXNcblx0XHRcdGVsZW1lbnRcblx0XHRcdFx0LmNsb25lKClcblx0XHRcdFx0LmFwcGVuZFRvKCBcImJvZHlcIiApXG5cdFx0XHRcdC53cmFwKCBcIjxkaXY+PC9kaXY+XCIgKVxuXHRcdFx0XHQuY3NzKCB7XG5cdFx0XHRcdFx0cG9zaXRpb246IFwiYWJzb2x1dGVcIixcblx0XHRcdFx0XHR2aXNpYmlsaXR5OiBcInZpc2libGVcIixcblx0XHRcdFx0XHRsZWZ0OiAtaiAqIHdpZHRoLFxuXHRcdFx0XHRcdHRvcDogLWkgKiBoZWlnaHRcblx0XHRcdFx0fSApXG5cblx0XHRcdFx0Ly8gU2VsZWN0IHRoZSB3cmFwcGVyIC0gbWFrZSBpdCBvdmVyZmxvdzogaGlkZGVuIGFuZCBhYnNvbHV0ZSBwb3NpdGlvbmVkIGJhc2VkIG9uXG5cdFx0XHRcdC8vIHdoZXJlIHRoZSBvcmlnaW5hbCB3YXMgbG9jYXRlZCArbGVmdCBhbmQgK3RvcCBlcXVhbCB0byB0aGUgc2l6ZSBvZiBwaWVjZXNcblx0XHRcdFx0LnBhcmVudCgpXG5cdFx0XHRcdFx0LmFkZENsYXNzKCBcInVpLWVmZmVjdHMtZXhwbG9kZVwiIClcblx0XHRcdFx0XHQuY3NzKCB7XG5cdFx0XHRcdFx0XHRwb3NpdGlvbjogXCJhYnNvbHV0ZVwiLFxuXHRcdFx0XHRcdFx0b3ZlcmZsb3c6IFwiaGlkZGVuXCIsXG5cdFx0XHRcdFx0XHR3aWR0aDogd2lkdGgsXG5cdFx0XHRcdFx0XHRoZWlnaHQ6IGhlaWdodCxcblx0XHRcdFx0XHRcdGxlZnQ6IGxlZnQgKyAoIHNob3cgPyBteCAqIHdpZHRoIDogMCApLFxuXHRcdFx0XHRcdFx0dG9wOiB0b3AgKyAoIHNob3cgPyBteSAqIGhlaWdodCA6IDAgKSxcblx0XHRcdFx0XHRcdG9wYWNpdHk6IHNob3cgPyAwIDogMVxuXHRcdFx0XHRcdH0gKVxuXHRcdFx0XHRcdC5hbmltYXRlKCB7XG5cdFx0XHRcdFx0XHRsZWZ0OiBsZWZ0ICsgKCBzaG93ID8gMCA6IG14ICogd2lkdGggKSxcblx0XHRcdFx0XHRcdHRvcDogdG9wICsgKCBzaG93ID8gMCA6IG15ICogaGVpZ2h0ICksXG5cdFx0XHRcdFx0XHRvcGFjaXR5OiBzaG93ID8gMSA6IDBcblx0XHRcdFx0XHR9LCBvcHRpb25zLmR1cmF0aW9uIHx8IDUwMCwgb3B0aW9ucy5lYXNpbmcsIGNoaWxkQ29tcGxldGUgKTtcblx0XHR9XG5cdH1cblxuXHRmdW5jdGlvbiBhbmltQ29tcGxldGUoKSB7XG5cdFx0ZWxlbWVudC5jc3MoIHtcblx0XHRcdHZpc2liaWxpdHk6IFwidmlzaWJsZVwiXG5cdFx0fSApO1xuXHRcdCQoIHBpZWNlcyApLnJlbW92ZSgpO1xuXHRcdGRvbmUoKTtcblx0fVxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgRmFkZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRmFkZSBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBGYWRlcyB0aGUgZWxlbWVudC5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9mYWRlLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdEZhZGUgPSAkLmVmZmVjdHMuZGVmaW5lKCBcImZhZGVcIiwgXCJ0b2dnbGVcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdHZhciBzaG93ID0gb3B0aW9ucy5tb2RlID09PSBcInNob3dcIjtcblxuXHQkKCB0aGlzIClcblx0XHQuY3NzKCBcIm9wYWNpdHlcIiwgc2hvdyA/IDAgOiAxIClcblx0XHQuYW5pbWF0ZSgge1xuXHRcdFx0b3BhY2l0eTogc2hvdyA/IDEgOiAwXG5cdFx0fSwge1xuXHRcdFx0cXVldWU6IGZhbHNlLFxuXHRcdFx0ZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sXG5cdFx0XHRlYXNpbmc6IG9wdGlvbnMuZWFzaW5nLFxuXHRcdFx0Y29tcGxldGU6IGRvbmVcblx0XHR9ICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBGb2xkIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBGb2xkIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IEZvbGRzIGFuIGVsZW1lbnQgZmlyc3QgaG9yaXpvbnRhbGx5IGFuZCB0aGVuIHZlcnRpY2FsbHkuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZm9sZC1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RGb2xkID0gJC5lZmZlY3RzLmRlZmluZSggXCJmb2xkXCIsIFwiaGlkZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblxuXHQvLyBDcmVhdGUgZWxlbWVudFxuXHR2YXIgZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRtb2RlID0gb3B0aW9ucy5tb2RlLFxuXHRcdHNob3cgPSBtb2RlID09PSBcInNob3dcIixcblx0XHRoaWRlID0gbW9kZSA9PT0gXCJoaWRlXCIsXG5cdFx0c2l6ZSA9IG9wdGlvbnMuc2l6ZSB8fCAxNSxcblx0XHRwZXJjZW50ID0gLyhbMC05XSspJS8uZXhlYyggc2l6ZSApLFxuXHRcdGhvcml6Rmlyc3QgPSAhIW9wdGlvbnMuaG9yaXpGaXJzdCxcblx0XHRyZWYgPSBob3JpekZpcnN0ID8gWyBcInJpZ2h0XCIsIFwiYm90dG9tXCIgXSA6IFsgXCJib3R0b21cIiwgXCJyaWdodFwiIF0sXG5cdFx0ZHVyYXRpb24gPSBvcHRpb25zLmR1cmF0aW9uIC8gMixcblxuXHRcdHBsYWNlaG9sZGVyID0gJC5lZmZlY3RzLmNyZWF0ZVBsYWNlaG9sZGVyKCBlbGVtZW50ICksXG5cblx0XHRzdGFydCA9IGVsZW1lbnQuY3NzQ2xpcCgpLFxuXHRcdGFuaW1hdGlvbjEgPSB7IGNsaXA6ICQuZXh0ZW5kKCB7fSwgc3RhcnQgKSB9LFxuXHRcdGFuaW1hdGlvbjIgPSB7IGNsaXA6ICQuZXh0ZW5kKCB7fSwgc3RhcnQgKSB9LFxuXG5cdFx0ZGlzdGFuY2UgPSBbIHN0YXJ0WyByZWZbIDAgXSBdLCBzdGFydFsgcmVmWyAxIF0gXSBdLFxuXG5cdFx0cXVldWVsZW4gPSBlbGVtZW50LnF1ZXVlKCkubGVuZ3RoO1xuXG5cdGlmICggcGVyY2VudCApIHtcblx0XHRzaXplID0gcGFyc2VJbnQoIHBlcmNlbnRbIDEgXSwgMTAgKSAvIDEwMCAqIGRpc3RhbmNlWyBoaWRlID8gMCA6IDEgXTtcblx0fVxuXHRhbmltYXRpb24xLmNsaXBbIHJlZlsgMCBdIF0gPSBzaXplO1xuXHRhbmltYXRpb24yLmNsaXBbIHJlZlsgMCBdIF0gPSBzaXplO1xuXHRhbmltYXRpb24yLmNsaXBbIHJlZlsgMSBdIF0gPSAwO1xuXG5cdGlmICggc2hvdyApIHtcblx0XHRlbGVtZW50LmNzc0NsaXAoIGFuaW1hdGlvbjIuY2xpcCApO1xuXHRcdGlmICggcGxhY2Vob2xkZXIgKSB7XG5cdFx0XHRwbGFjZWhvbGRlci5jc3MoICQuZWZmZWN0cy5jbGlwVG9Cb3goIGFuaW1hdGlvbjIgKSApO1xuXHRcdH1cblxuXHRcdGFuaW1hdGlvbjIuY2xpcCA9IHN0YXJ0O1xuXHR9XG5cblx0Ly8gQW5pbWF0ZVxuXHRlbGVtZW50XG5cdFx0LnF1ZXVlKCBmdW5jdGlvbiggbmV4dCApIHtcblx0XHRcdGlmICggcGxhY2Vob2xkZXIgKSB7XG5cdFx0XHRcdHBsYWNlaG9sZGVyXG5cdFx0XHRcdFx0LmFuaW1hdGUoICQuZWZmZWN0cy5jbGlwVG9Cb3goIGFuaW1hdGlvbjEgKSwgZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nIClcblx0XHRcdFx0XHQuYW5pbWF0ZSggJC5lZmZlY3RzLmNsaXBUb0JveCggYW5pbWF0aW9uMiApLCBkdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcgKTtcblx0XHRcdH1cblxuXHRcdFx0bmV4dCgpO1xuXHRcdH0gKVxuXHRcdC5hbmltYXRlKCBhbmltYXRpb24xLCBkdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcgKVxuXHRcdC5hbmltYXRlKCBhbmltYXRpb24yLCBkdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcgKVxuXHRcdC5xdWV1ZSggZG9uZSApO1xuXG5cdCQuZWZmZWN0cy51bnNoaWZ0KCBlbGVtZW50LCBxdWV1ZWxlbiwgNCApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgSGlnaGxpZ2h0IDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBIaWdobGlnaHQgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogSGlnaGxpZ2h0cyB0aGUgYmFja2dyb3VuZCBvZiBhbiBlbGVtZW50IGluIGEgZGVmaW5lZCBjb2xvciBmb3IgYSBjdXN0b20gZHVyYXRpb24uXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vaGlnaGxpZ2h0LWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdEhpZ2hsaWdodCA9ICQuZWZmZWN0cy5kZWZpbmUoIFwiaGlnaGxpZ2h0XCIsIFwic2hvd1wiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0dmFyIGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0YW5pbWF0aW9uID0ge1xuXHRcdFx0YmFja2dyb3VuZENvbG9yOiBlbGVtZW50LmNzcyggXCJiYWNrZ3JvdW5kQ29sb3JcIiApXG5cdFx0fTtcblxuXHRpZiAoIG9wdGlvbnMubW9kZSA9PT0gXCJoaWRlXCIgKSB7XG5cdFx0YW5pbWF0aW9uLm9wYWNpdHkgPSAwO1xuXHR9XG5cblx0JC5lZmZlY3RzLnNhdmVTdHlsZSggZWxlbWVudCApO1xuXG5cdGVsZW1lbnRcblx0XHQuY3NzKCB7XG5cdFx0XHRiYWNrZ3JvdW5kSW1hZ2U6IFwibm9uZVwiLFxuXHRcdFx0YmFja2dyb3VuZENvbG9yOiBvcHRpb25zLmNvbG9yIHx8IFwiI2ZmZmY5OVwiXG5cdFx0fSApXG5cdFx0LmFuaW1hdGUoIGFuaW1hdGlvbiwge1xuXHRcdFx0cXVldWU6IGZhbHNlLFxuXHRcdFx0ZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sXG5cdFx0XHRlYXNpbmc6IG9wdGlvbnMuZWFzaW5nLFxuXHRcdFx0Y29tcGxldGU6IGRvbmVcblx0XHR9ICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBTaXplIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBTaXplIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IFJlc2l6ZSBhbiBlbGVtZW50IHRvIGEgc3BlY2lmaWVkIHdpZHRoIGFuZCBoZWlnaHQuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc2l6ZS1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RTaXplID0gJC5lZmZlY3RzLmRlZmluZSggXCJzaXplXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXG5cdC8vIENyZWF0ZSBlbGVtZW50XG5cdHZhciBiYXNlbGluZSwgZmFjdG9yLCB0ZW1wLFxuXHRcdGVsZW1lbnQgPSAkKCB0aGlzICksXG5cblx0XHQvLyBDb3B5IGZvciBjaGlsZHJlblxuXHRcdGNQcm9wcyA9IFsgXCJmb250U2l6ZVwiIF0sXG5cdFx0dlByb3BzID0gWyBcImJvcmRlclRvcFdpZHRoXCIsIFwiYm9yZGVyQm90dG9tV2lkdGhcIiwgXCJwYWRkaW5nVG9wXCIsIFwicGFkZGluZ0JvdHRvbVwiIF0sXG5cdFx0aFByb3BzID0gWyBcImJvcmRlckxlZnRXaWR0aFwiLCBcImJvcmRlclJpZ2h0V2lkdGhcIiwgXCJwYWRkaW5nTGVmdFwiLCBcInBhZGRpbmdSaWdodFwiIF0sXG5cblx0XHQvLyBTZXQgb3B0aW9uc1xuXHRcdG1vZGUgPSBvcHRpb25zLm1vZGUsXG5cdFx0cmVzdG9yZSA9IG1vZGUgIT09IFwiZWZmZWN0XCIsXG5cdFx0c2NhbGUgPSBvcHRpb25zLnNjYWxlIHx8IFwiYm90aFwiLFxuXHRcdG9yaWdpbiA9IG9wdGlvbnMub3JpZ2luIHx8IFsgXCJtaWRkbGVcIiwgXCJjZW50ZXJcIiBdLFxuXHRcdHBvc2l0aW9uID0gZWxlbWVudC5jc3MoIFwicG9zaXRpb25cIiApLFxuXHRcdHBvcyA9IGVsZW1lbnQucG9zaXRpb24oKSxcblx0XHRvcmlnaW5hbCA9ICQuZWZmZWN0cy5zY2FsZWREaW1lbnNpb25zKCBlbGVtZW50ICksXG5cdFx0ZnJvbSA9IG9wdGlvbnMuZnJvbSB8fCBvcmlnaW5hbCxcblx0XHR0byA9IG9wdGlvbnMudG8gfHwgJC5lZmZlY3RzLnNjYWxlZERpbWVuc2lvbnMoIGVsZW1lbnQsIDAgKTtcblxuXHQkLmVmZmVjdHMuY3JlYXRlUGxhY2Vob2xkZXIoIGVsZW1lbnQgKTtcblxuXHRpZiAoIG1vZGUgPT09IFwic2hvd1wiICkge1xuXHRcdHRlbXAgPSBmcm9tO1xuXHRcdGZyb20gPSB0bztcblx0XHR0byA9IHRlbXA7XG5cdH1cblxuXHQvLyBTZXQgc2NhbGluZyBmYWN0b3Jcblx0ZmFjdG9yID0ge1xuXHRcdGZyb206IHtcblx0XHRcdHk6IGZyb20uaGVpZ2h0IC8gb3JpZ2luYWwuaGVpZ2h0LFxuXHRcdFx0eDogZnJvbS53aWR0aCAvIG9yaWdpbmFsLndpZHRoXG5cdFx0fSxcblx0XHR0bzoge1xuXHRcdFx0eTogdG8uaGVpZ2h0IC8gb3JpZ2luYWwuaGVpZ2h0LFxuXHRcdFx0eDogdG8ud2lkdGggLyBvcmlnaW5hbC53aWR0aFxuXHRcdH1cblx0fTtcblxuXHQvLyBTY2FsZSB0aGUgY3NzIGJveFxuXHRpZiAoIHNjYWxlID09PSBcImJveFwiIHx8IHNjYWxlID09PSBcImJvdGhcIiApIHtcblxuXHRcdC8vIFZlcnRpY2FsIHByb3BzIHNjYWxpbmdcblx0XHRpZiAoIGZhY3Rvci5mcm9tLnkgIT09IGZhY3Rvci50by55ICkge1xuXHRcdFx0ZnJvbSA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBlbGVtZW50LCB2UHJvcHMsIGZhY3Rvci5mcm9tLnksIGZyb20gKTtcblx0XHRcdHRvID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGVsZW1lbnQsIHZQcm9wcywgZmFjdG9yLnRvLnksIHRvICk7XG5cdFx0fVxuXG5cdFx0Ly8gSG9yaXpvbnRhbCBwcm9wcyBzY2FsaW5nXG5cdFx0aWYgKCBmYWN0b3IuZnJvbS54ICE9PSBmYWN0b3IudG8ueCApIHtcblx0XHRcdGZyb20gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggZWxlbWVudCwgaFByb3BzLCBmYWN0b3IuZnJvbS54LCBmcm9tICk7XG5cdFx0XHR0byA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBlbGVtZW50LCBoUHJvcHMsIGZhY3Rvci50by54LCB0byApO1xuXHRcdH1cblx0fVxuXG5cdC8vIFNjYWxlIHRoZSBjb250ZW50XG5cdGlmICggc2NhbGUgPT09IFwiY29udGVudFwiIHx8IHNjYWxlID09PSBcImJvdGhcIiApIHtcblxuXHRcdC8vIFZlcnRpY2FsIHByb3BzIHNjYWxpbmdcblx0XHRpZiAoIGZhY3Rvci5mcm9tLnkgIT09IGZhY3Rvci50by55ICkge1xuXHRcdFx0ZnJvbSA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBlbGVtZW50LCBjUHJvcHMsIGZhY3Rvci5mcm9tLnksIGZyb20gKTtcblx0XHRcdHRvID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGVsZW1lbnQsIGNQcm9wcywgZmFjdG9yLnRvLnksIHRvICk7XG5cdFx0fVxuXHR9XG5cblx0Ly8gQWRqdXN0IHRoZSBwb3NpdGlvbiBwcm9wZXJ0aWVzIGJhc2VkIG9uIHRoZSBwcm92aWRlZCBvcmlnaW4gcG9pbnRzXG5cdGlmICggb3JpZ2luICkge1xuXHRcdGJhc2VsaW5lID0gJC5lZmZlY3RzLmdldEJhc2VsaW5lKCBvcmlnaW4sIG9yaWdpbmFsICk7XG5cdFx0ZnJvbS50b3AgPSAoIG9yaWdpbmFsLm91dGVySGVpZ2h0IC0gZnJvbS5vdXRlckhlaWdodCApICogYmFzZWxpbmUueSArIHBvcy50b3A7XG5cdFx0ZnJvbS5sZWZ0ID0gKCBvcmlnaW5hbC5vdXRlcldpZHRoIC0gZnJvbS5vdXRlcldpZHRoICkgKiBiYXNlbGluZS54ICsgcG9zLmxlZnQ7XG5cdFx0dG8udG9wID0gKCBvcmlnaW5hbC5vdXRlckhlaWdodCAtIHRvLm91dGVySGVpZ2h0ICkgKiBiYXNlbGluZS55ICsgcG9zLnRvcDtcblx0XHR0by5sZWZ0ID0gKCBvcmlnaW5hbC5vdXRlcldpZHRoIC0gdG8ub3V0ZXJXaWR0aCApICogYmFzZWxpbmUueCArIHBvcy5sZWZ0O1xuXHR9XG5cdGVsZW1lbnQuY3NzKCBmcm9tICk7XG5cblx0Ly8gQW5pbWF0ZSB0aGUgY2hpbGRyZW4gaWYgZGVzaXJlZFxuXHRpZiAoIHNjYWxlID09PSBcImNvbnRlbnRcIiB8fCBzY2FsZSA9PT0gXCJib3RoXCIgKSB7XG5cblx0XHR2UHJvcHMgPSB2UHJvcHMuY29uY2F0KCBbIFwibWFyZ2luVG9wXCIsIFwibWFyZ2luQm90dG9tXCIgXSApLmNvbmNhdCggY1Byb3BzICk7XG5cdFx0aFByb3BzID0gaFByb3BzLmNvbmNhdCggWyBcIm1hcmdpbkxlZnRcIiwgXCJtYXJnaW5SaWdodFwiIF0gKTtcblxuXHRcdC8vIE9ubHkgYW5pbWF0ZSBjaGlsZHJlbiB3aXRoIHdpZHRoIGF0dHJpYnV0ZXMgc3BlY2lmaWVkXG5cdFx0Ly8gVE9ETzogaXMgdGhpcyByaWdodD8gc2hvdWxkIHdlIGluY2x1ZGUgYW55dGhpbmcgd2l0aCBjc3Mgd2lkdGggc3BlY2lmaWVkIGFzIHdlbGxcblx0XHRlbGVtZW50LmZpbmQoIFwiKlt3aWR0aF1cIiApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGNoaWxkID0gJCggdGhpcyApLFxuXHRcdFx0XHRjaGlsZE9yaWdpbmFsID0gJC5lZmZlY3RzLnNjYWxlZERpbWVuc2lvbnMoIGNoaWxkICksXG5cdFx0XHRcdGNoaWxkRnJvbSA9IHtcblx0XHRcdFx0XHRoZWlnaHQ6IGNoaWxkT3JpZ2luYWwuaGVpZ2h0ICogZmFjdG9yLmZyb20ueSxcblx0XHRcdFx0XHR3aWR0aDogY2hpbGRPcmlnaW5hbC53aWR0aCAqIGZhY3Rvci5mcm9tLngsXG5cdFx0XHRcdFx0b3V0ZXJIZWlnaHQ6IGNoaWxkT3JpZ2luYWwub3V0ZXJIZWlnaHQgKiBmYWN0b3IuZnJvbS55LFxuXHRcdFx0XHRcdG91dGVyV2lkdGg6IGNoaWxkT3JpZ2luYWwub3V0ZXJXaWR0aCAqIGZhY3Rvci5mcm9tLnhcblx0XHRcdFx0fSxcblx0XHRcdFx0Y2hpbGRUbyA9IHtcblx0XHRcdFx0XHRoZWlnaHQ6IGNoaWxkT3JpZ2luYWwuaGVpZ2h0ICogZmFjdG9yLnRvLnksXG5cdFx0XHRcdFx0d2lkdGg6IGNoaWxkT3JpZ2luYWwud2lkdGggKiBmYWN0b3IudG8ueCxcblx0XHRcdFx0XHRvdXRlckhlaWdodDogY2hpbGRPcmlnaW5hbC5oZWlnaHQgKiBmYWN0b3IudG8ueSxcblx0XHRcdFx0XHRvdXRlcldpZHRoOiBjaGlsZE9yaWdpbmFsLndpZHRoICogZmFjdG9yLnRvLnhcblx0XHRcdFx0fTtcblxuXHRcdFx0Ly8gVmVydGljYWwgcHJvcHMgc2NhbGluZ1xuXHRcdFx0aWYgKCBmYWN0b3IuZnJvbS55ICE9PSBmYWN0b3IudG8ueSApIHtcblx0XHRcdFx0Y2hpbGRGcm9tID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGNoaWxkLCB2UHJvcHMsIGZhY3Rvci5mcm9tLnksIGNoaWxkRnJvbSApO1xuXHRcdFx0XHRjaGlsZFRvID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGNoaWxkLCB2UHJvcHMsIGZhY3Rvci50by55LCBjaGlsZFRvICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEhvcml6b250YWwgcHJvcHMgc2NhbGluZ1xuXHRcdFx0aWYgKCBmYWN0b3IuZnJvbS54ICE9PSBmYWN0b3IudG8ueCApIHtcblx0XHRcdFx0Y2hpbGRGcm9tID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGNoaWxkLCBoUHJvcHMsIGZhY3Rvci5mcm9tLngsIGNoaWxkRnJvbSApO1xuXHRcdFx0XHRjaGlsZFRvID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGNoaWxkLCBoUHJvcHMsIGZhY3Rvci50by54LCBjaGlsZFRvICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggcmVzdG9yZSApIHtcblx0XHRcdFx0JC5lZmZlY3RzLnNhdmVTdHlsZSggY2hpbGQgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQW5pbWF0ZSBjaGlsZHJlblxuXHRcdFx0Y2hpbGQuY3NzKCBjaGlsZEZyb20gKTtcblx0XHRcdGNoaWxkLmFuaW1hdGUoIGNoaWxkVG8sIG9wdGlvbnMuZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nLCBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHQvLyBSZXN0b3JlIGNoaWxkcmVuXG5cdFx0XHRcdGlmICggcmVzdG9yZSApIHtcblx0XHRcdFx0XHQkLmVmZmVjdHMucmVzdG9yZVN0eWxlKCBjaGlsZCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0fSApO1xuXHR9XG5cblx0Ly8gQW5pbWF0ZVxuXHRlbGVtZW50LmFuaW1hdGUoIHRvLCB7XG5cdFx0cXVldWU6IGZhbHNlLFxuXHRcdGR1cmF0aW9uOiBvcHRpb25zLmR1cmF0aW9uLFxuXHRcdGVhc2luZzogb3B0aW9ucy5lYXNpbmcsXG5cdFx0Y29tcGxldGU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0XHR2YXIgb2Zmc2V0ID0gZWxlbWVudC5vZmZzZXQoKTtcblxuXHRcdFx0aWYgKCB0by5vcGFjaXR5ID09PSAwICkge1xuXHRcdFx0XHRlbGVtZW50LmNzcyggXCJvcGFjaXR5XCIsIGZyb20ub3BhY2l0eSApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICFyZXN0b3JlICkge1xuXHRcdFx0XHRlbGVtZW50XG5cdFx0XHRcdFx0LmNzcyggXCJwb3NpdGlvblwiLCBwb3NpdGlvbiA9PT0gXCJzdGF0aWNcIiA/IFwicmVsYXRpdmVcIiA6IHBvc2l0aW9uIClcblx0XHRcdFx0XHQub2Zmc2V0KCBvZmZzZXQgKTtcblxuXHRcdFx0XHQvLyBOZWVkIHRvIHNhdmUgc3R5bGUgaGVyZSBzbyB0aGF0IGF1dG9tYXRpYyBzdHlsZSByZXN0b3JhdGlvblxuXHRcdFx0XHQvLyBkb2Vzbid0IHJlc3RvcmUgdG8gdGhlIG9yaWdpbmFsIHN0eWxlcyBmcm9tIGJlZm9yZSB0aGUgYW5pbWF0aW9uLlxuXHRcdFx0XHQkLmVmZmVjdHMuc2F2ZVN0eWxlKCBlbGVtZW50ICk7XG5cdFx0XHR9XG5cblx0XHRcdGRvbmUoKTtcblx0XHR9XG5cdH0gKTtcblxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgU2NhbGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFNjYWxlIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IEdyb3dzIG9yIHNocmlua3MgYW4gZWxlbWVudCBhbmQgaXRzIGNvbnRlbnQuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc2NhbGUtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0U2NhbGUgPSAkLmVmZmVjdHMuZGVmaW5lKCBcInNjYWxlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXG5cdC8vIENyZWF0ZSBlbGVtZW50XG5cdHZhciBlbCA9ICQoIHRoaXMgKSxcblx0XHRtb2RlID0gb3B0aW9ucy5tb2RlLFxuXHRcdHBlcmNlbnQgPSBwYXJzZUludCggb3B0aW9ucy5wZXJjZW50LCAxMCApIHx8XG5cdFx0XHQoIHBhcnNlSW50KCBvcHRpb25zLnBlcmNlbnQsIDEwICkgPT09IDAgPyAwIDogKCBtb2RlICE9PSBcImVmZmVjdFwiID8gMCA6IDEwMCApICksXG5cblx0XHRuZXdPcHRpb25zID0gJC5leHRlbmQoIHRydWUsIHtcblx0XHRcdGZyb206ICQuZWZmZWN0cy5zY2FsZWREaW1lbnNpb25zKCBlbCApLFxuXHRcdFx0dG86ICQuZWZmZWN0cy5zY2FsZWREaW1lbnNpb25zKCBlbCwgcGVyY2VudCwgb3B0aW9ucy5kaXJlY3Rpb24gfHwgXCJib3RoXCIgKSxcblx0XHRcdG9yaWdpbjogb3B0aW9ucy5vcmlnaW4gfHwgWyBcIm1pZGRsZVwiLCBcImNlbnRlclwiIF1cblx0XHR9LCBvcHRpb25zICk7XG5cblx0Ly8gRmFkZSBvcHRpb24gdG8gc3VwcG9ydCBwdWZmXG5cdGlmICggb3B0aW9ucy5mYWRlICkge1xuXHRcdG5ld09wdGlvbnMuZnJvbS5vcGFjaXR5ID0gMTtcblx0XHRuZXdPcHRpb25zLnRvLm9wYWNpdHkgPSAwO1xuXHR9XG5cblx0JC5lZmZlY3RzLmVmZmVjdC5zaXplLmNhbGwoIHRoaXMsIG5ld09wdGlvbnMsIGRvbmUgKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIFB1ZmYgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFB1ZmYgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogQ3JlYXRlcyBhIHB1ZmYgZWZmZWN0IGJ5IHNjYWxpbmcgdGhlIGVsZW1lbnQgdXAgYW5kIGhpZGluZyBpdCBhdCB0aGUgc2FtZSB0aW1lLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3B1ZmYtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0UHVmZiA9ICQuZWZmZWN0cy5kZWZpbmUoIFwicHVmZlwiLCBcImhpZGVcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdHZhciBuZXdPcHRpb25zID0gJC5leHRlbmQoIHRydWUsIHt9LCBvcHRpb25zLCB7XG5cdFx0ZmFkZTogdHJ1ZSxcblx0XHRwZXJjZW50OiBwYXJzZUludCggb3B0aW9ucy5wZXJjZW50LCAxMCApIHx8IDE1MFxuXHR9ICk7XG5cblx0JC5lZmZlY3RzLmVmZmVjdC5zY2FsZS5jYWxsKCB0aGlzLCBuZXdPcHRpb25zLCBkb25lICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBQdWxzYXRlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBQdWxzYXRlIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IFB1bHNhdGVzIGFuIGVsZW1lbnQgbiB0aW1lcyBieSBjaGFuZ2luZyB0aGUgb3BhY2l0eSB0byB6ZXJvIGFuZCBiYWNrLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3B1bHNhdGUtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0UHVsc2F0ZSA9ICQuZWZmZWN0cy5kZWZpbmUoIFwicHVsc2F0ZVwiLCBcInNob3dcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdHZhciBlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdG1vZGUgPSBvcHRpb25zLm1vZGUsXG5cdFx0c2hvdyA9IG1vZGUgPT09IFwic2hvd1wiLFxuXHRcdGhpZGUgPSBtb2RlID09PSBcImhpZGVcIixcblx0XHRzaG93aGlkZSA9IHNob3cgfHwgaGlkZSxcblxuXHRcdC8vIFNob3dpbmcgb3IgaGlkaW5nIGxlYXZlcyBvZmYgdGhlIFwibGFzdFwiIGFuaW1hdGlvblxuXHRcdGFuaW1zID0gKCAoIG9wdGlvbnMudGltZXMgfHwgNSApICogMiApICsgKCBzaG93aGlkZSA/IDEgOiAwICksXG5cdFx0ZHVyYXRpb24gPSBvcHRpb25zLmR1cmF0aW9uIC8gYW5pbXMsXG5cdFx0YW5pbWF0ZVRvID0gMCxcblx0XHRpID0gMSxcblx0XHRxdWV1ZWxlbiA9IGVsZW1lbnQucXVldWUoKS5sZW5ndGg7XG5cblx0aWYgKCBzaG93IHx8ICFlbGVtZW50LmlzKCBcIjp2aXNpYmxlXCIgKSApIHtcblx0XHRlbGVtZW50LmNzcyggXCJvcGFjaXR5XCIsIDAgKS5zaG93KCk7XG5cdFx0YW5pbWF0ZVRvID0gMTtcblx0fVxuXG5cdC8vIEFuaW1zIC0gMSBvcGFjaXR5IFwidG9nZ2xlc1wiXG5cdGZvciAoIDsgaSA8IGFuaW1zOyBpKysgKSB7XG5cdFx0ZWxlbWVudC5hbmltYXRlKCB7IG9wYWNpdHk6IGFuaW1hdGVUbyB9LCBkdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcgKTtcblx0XHRhbmltYXRlVG8gPSAxIC0gYW5pbWF0ZVRvO1xuXHR9XG5cblx0ZWxlbWVudC5hbmltYXRlKCB7IG9wYWNpdHk6IGFuaW1hdGVUbyB9LCBkdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcgKTtcblxuXHRlbGVtZW50LnF1ZXVlKCBkb25lICk7XG5cblx0JC5lZmZlY3RzLnVuc2hpZnQoIGVsZW1lbnQsIHF1ZXVlbGVuLCBhbmltcyArIDEgKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIFNoYWtlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBTaGFrZSBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBTaGFrZXMgYW4gZWxlbWVudCBob3Jpem9udGFsbHkgb3IgdmVydGljYWxseSBuIHRpbWVzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3NoYWtlLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdFNoYWtlID0gJC5lZmZlY3RzLmRlZmluZSggXCJzaGFrZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblxuXHR2YXIgaSA9IDEsXG5cdFx0ZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRkaXJlY3Rpb24gPSBvcHRpb25zLmRpcmVjdGlvbiB8fCBcImxlZnRcIixcblx0XHRkaXN0YW5jZSA9IG9wdGlvbnMuZGlzdGFuY2UgfHwgMjAsXG5cdFx0dGltZXMgPSBvcHRpb25zLnRpbWVzIHx8IDMsXG5cdFx0YW5pbXMgPSB0aW1lcyAqIDIgKyAxLFxuXHRcdHNwZWVkID0gTWF0aC5yb3VuZCggb3B0aW9ucy5kdXJhdGlvbiAvIGFuaW1zICksXG5cdFx0cmVmID0gKCBkaXJlY3Rpb24gPT09IFwidXBcIiB8fCBkaXJlY3Rpb24gPT09IFwiZG93blwiICkgPyBcInRvcFwiIDogXCJsZWZ0XCIsXG5cdFx0cG9zaXRpdmVNb3Rpb24gPSAoIGRpcmVjdGlvbiA9PT0gXCJ1cFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJsZWZ0XCIgKSxcblx0XHRhbmltYXRpb24gPSB7fSxcblx0XHRhbmltYXRpb24xID0ge30sXG5cdFx0YW5pbWF0aW9uMiA9IHt9LFxuXG5cdFx0cXVldWVsZW4gPSBlbGVtZW50LnF1ZXVlKCkubGVuZ3RoO1xuXG5cdCQuZWZmZWN0cy5jcmVhdGVQbGFjZWhvbGRlciggZWxlbWVudCApO1xuXG5cdC8vIEFuaW1hdGlvblxuXHRhbmltYXRpb25bIHJlZiBdID0gKCBwb3NpdGl2ZU1vdGlvbiA/IFwiLT1cIiA6IFwiKz1cIiApICsgZGlzdGFuY2U7XG5cdGFuaW1hdGlvbjFbIHJlZiBdID0gKCBwb3NpdGl2ZU1vdGlvbiA/IFwiKz1cIiA6IFwiLT1cIiApICsgZGlzdGFuY2UgKiAyO1xuXHRhbmltYXRpb24yWyByZWYgXSA9ICggcG9zaXRpdmVNb3Rpb24gPyBcIi09XCIgOiBcIis9XCIgKSArIGRpc3RhbmNlICogMjtcblxuXHQvLyBBbmltYXRlXG5cdGVsZW1lbnQuYW5pbWF0ZSggYW5pbWF0aW9uLCBzcGVlZCwgb3B0aW9ucy5lYXNpbmcgKTtcblxuXHQvLyBTaGFrZXNcblx0Zm9yICggOyBpIDwgdGltZXM7IGkrKyApIHtcblx0XHRlbGVtZW50XG5cdFx0XHQuYW5pbWF0ZSggYW5pbWF0aW9uMSwgc3BlZWQsIG9wdGlvbnMuZWFzaW5nIClcblx0XHRcdC5hbmltYXRlKCBhbmltYXRpb24yLCBzcGVlZCwgb3B0aW9ucy5lYXNpbmcgKTtcblx0fVxuXG5cdGVsZW1lbnRcblx0XHQuYW5pbWF0ZSggYW5pbWF0aW9uMSwgc3BlZWQsIG9wdGlvbnMuZWFzaW5nIClcblx0XHQuYW5pbWF0ZSggYW5pbWF0aW9uLCBzcGVlZCAvIDIsIG9wdGlvbnMuZWFzaW5nIClcblx0XHQucXVldWUoIGRvbmUgKTtcblxuXHQkLmVmZmVjdHMudW5zaGlmdCggZWxlbWVudCwgcXVldWVsZW4sIGFuaW1zICsgMSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgU2xpZGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFNsaWRlIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IFNsaWRlcyBhbiBlbGVtZW50IGluIGFuZCBvdXQgb2YgdGhlIHZpZXdwb3J0LlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3NsaWRlLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdFNsaWRlID0gJC5lZmZlY3RzLmRlZmluZSggXCJzbGlkZVwiLCBcInNob3dcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdHZhciBzdGFydENsaXAsIHN0YXJ0UmVmLFxuXHRcdGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0bWFwID0ge1xuXHRcdFx0dXA6IFsgXCJib3R0b21cIiwgXCJ0b3BcIiBdLFxuXHRcdFx0ZG93bjogWyBcInRvcFwiLCBcImJvdHRvbVwiIF0sXG5cdFx0XHRsZWZ0OiBbIFwicmlnaHRcIiwgXCJsZWZ0XCIgXSxcblx0XHRcdHJpZ2h0OiBbIFwibGVmdFwiLCBcInJpZ2h0XCIgXVxuXHRcdH0sXG5cdFx0bW9kZSA9IG9wdGlvbnMubW9kZSxcblx0XHRkaXJlY3Rpb24gPSBvcHRpb25zLmRpcmVjdGlvbiB8fCBcImxlZnRcIixcblx0XHRyZWYgPSAoIGRpcmVjdGlvbiA9PT0gXCJ1cFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJkb3duXCIgKSA/IFwidG9wXCIgOiBcImxlZnRcIixcblx0XHRwb3NpdGl2ZU1vdGlvbiA9ICggZGlyZWN0aW9uID09PSBcInVwXCIgfHwgZGlyZWN0aW9uID09PSBcImxlZnRcIiApLFxuXHRcdGRpc3RhbmNlID0gb3B0aW9ucy5kaXN0YW5jZSB8fFxuXHRcdFx0ZWxlbWVudFsgcmVmID09PSBcInRvcFwiID8gXCJvdXRlckhlaWdodFwiIDogXCJvdXRlcldpZHRoXCIgXSggdHJ1ZSApLFxuXHRcdGFuaW1hdGlvbiA9IHt9O1xuXG5cdCQuZWZmZWN0cy5jcmVhdGVQbGFjZWhvbGRlciggZWxlbWVudCApO1xuXG5cdHN0YXJ0Q2xpcCA9IGVsZW1lbnQuY3NzQ2xpcCgpO1xuXHRzdGFydFJlZiA9IGVsZW1lbnQucG9zaXRpb24oKVsgcmVmIF07XG5cblx0Ly8gRGVmaW5lIGhpZGUgYW5pbWF0aW9uXG5cdGFuaW1hdGlvblsgcmVmIF0gPSAoIHBvc2l0aXZlTW90aW9uID8gLTEgOiAxICkgKiBkaXN0YW5jZSArIHN0YXJ0UmVmO1xuXHRhbmltYXRpb24uY2xpcCA9IGVsZW1lbnQuY3NzQ2xpcCgpO1xuXHRhbmltYXRpb24uY2xpcFsgbWFwWyBkaXJlY3Rpb24gXVsgMSBdIF0gPSBhbmltYXRpb24uY2xpcFsgbWFwWyBkaXJlY3Rpb24gXVsgMCBdIF07XG5cblx0Ly8gUmV2ZXJzZSB0aGUgYW5pbWF0aW9uIGlmIHdlJ3JlIHNob3dpbmdcblx0aWYgKCBtb2RlID09PSBcInNob3dcIiApIHtcblx0XHRlbGVtZW50LmNzc0NsaXAoIGFuaW1hdGlvbi5jbGlwICk7XG5cdFx0ZWxlbWVudC5jc3MoIHJlZiwgYW5pbWF0aW9uWyByZWYgXSApO1xuXHRcdGFuaW1hdGlvbi5jbGlwID0gc3RhcnRDbGlwO1xuXHRcdGFuaW1hdGlvblsgcmVmIF0gPSBzdGFydFJlZjtcblx0fVxuXG5cdC8vIEFjdHVhbGx5IGFuaW1hdGVcblx0ZWxlbWVudC5hbmltYXRlKCBhbmltYXRpb24sIHtcblx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0ZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sXG5cdFx0ZWFzaW5nOiBvcHRpb25zLmVhc2luZyxcblx0XHRjb21wbGV0ZTogZG9uZVxuXHR9ICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBUcmFuc2ZlciAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogVHJhbnNmZXIgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogRGlzcGxheXMgYSB0cmFuc2ZlciBlZmZlY3QgZnJvbSBvbmUgZWxlbWVudCB0byBhbm90aGVyLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3RyYW5zZmVyLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0O1xuaWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgKSB7XG5cdGVmZmVjdCA9ICQuZWZmZWN0cy5kZWZpbmUoIFwidHJhbnNmZXJcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdFx0JCggdGhpcyApLnRyYW5zZmVyKCBvcHRpb25zLCBkb25lICk7XG5cdH0gKTtcbn1cbnZhciBlZmZlY3RzRWZmZWN0VHJhbnNmZXIgPSBlZmZlY3Q7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRm9jdXNhYmxlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiA6Zm9jdXNhYmxlIFNlbGVjdG9yXG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogU2VsZWN0cyBlbGVtZW50cyB3aGljaCBjYW4gYmUgZm9jdXNlZC5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9mb2N1c2FibGUtc2VsZWN0b3IvXG5cblxuXG4vLyBTZWxlY3RvcnNcbiQudWkuZm9jdXNhYmxlID0gZnVuY3Rpb24oIGVsZW1lbnQsIGhhc1RhYmluZGV4ICkge1xuXHR2YXIgbWFwLCBtYXBOYW1lLCBpbWcsIGZvY3VzYWJsZUlmVmlzaWJsZSwgZmllbGRzZXQsXG5cdFx0bm9kZU5hbWUgPSBlbGVtZW50Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cblx0aWYgKCBcImFyZWFcIiA9PT0gbm9kZU5hbWUgKSB7XG5cdFx0bWFwID0gZWxlbWVudC5wYXJlbnROb2RlO1xuXHRcdG1hcE5hbWUgPSBtYXAubmFtZTtcblx0XHRpZiAoICFlbGVtZW50LmhyZWYgfHwgIW1hcE5hbWUgfHwgbWFwLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgIT09IFwibWFwXCIgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHRcdGltZyA9ICQoIFwiaW1nW3VzZW1hcD0nI1wiICsgbWFwTmFtZSArIFwiJ11cIiApO1xuXHRcdHJldHVybiBpbWcubGVuZ3RoID4gMCAmJiBpbWcuaXMoIFwiOnZpc2libGVcIiApO1xuXHR9XG5cblx0aWYgKCAvXihpbnB1dHxzZWxlY3R8dGV4dGFyZWF8YnV0dG9ufG9iamVjdCkkLy50ZXN0KCBub2RlTmFtZSApICkge1xuXHRcdGZvY3VzYWJsZUlmVmlzaWJsZSA9ICFlbGVtZW50LmRpc2FibGVkO1xuXG5cdFx0aWYgKCBmb2N1c2FibGVJZlZpc2libGUgKSB7XG5cblx0XHRcdC8vIEZvcm0gY29udHJvbHMgd2l0aGluIGEgZGlzYWJsZWQgZmllbGRzZXQgYXJlIGRpc2FibGVkLlxuXHRcdFx0Ly8gSG93ZXZlciwgY29udHJvbHMgd2l0aGluIHRoZSBmaWVsZHNldCdzIGxlZ2VuZCBkbyBub3QgZ2V0IGRpc2FibGVkLlxuXHRcdFx0Ly8gU2luY2UgY29udHJvbHMgZ2VuZXJhbGx5IGFyZW4ndCBwbGFjZWQgaW5zaWRlIGxlZ2VuZHMsIHdlIHNraXBcblx0XHRcdC8vIHRoaXMgcG9ydGlvbiBvZiB0aGUgY2hlY2suXG5cdFx0XHRmaWVsZHNldCA9ICQoIGVsZW1lbnQgKS5jbG9zZXN0KCBcImZpZWxkc2V0XCIgKVsgMCBdO1xuXHRcdFx0aWYgKCBmaWVsZHNldCApIHtcblx0XHRcdFx0Zm9jdXNhYmxlSWZWaXNpYmxlID0gIWZpZWxkc2V0LmRpc2FibGVkO1xuXHRcdFx0fVxuXHRcdH1cblx0fSBlbHNlIGlmICggXCJhXCIgPT09IG5vZGVOYW1lICkge1xuXHRcdGZvY3VzYWJsZUlmVmlzaWJsZSA9IGVsZW1lbnQuaHJlZiB8fCBoYXNUYWJpbmRleDtcblx0fSBlbHNlIHtcblx0XHRmb2N1c2FibGVJZlZpc2libGUgPSBoYXNUYWJpbmRleDtcblx0fVxuXG5cdHJldHVybiBmb2N1c2FibGVJZlZpc2libGUgJiYgJCggZWxlbWVudCApLmlzKCBcIjp2aXNpYmxlXCIgKSAmJiB2aXNpYmxlKCAkKCBlbGVtZW50ICkgKTtcbn07XG5cbi8vIFN1cHBvcnQ6IElFIDggb25seVxuLy8gSUUgOCBkb2Vzbid0IHJlc29sdmUgaW5oZXJpdCB0byB2aXNpYmxlL2hpZGRlbiBmb3IgY29tcHV0ZWQgdmFsdWVzXG5mdW5jdGlvbiB2aXNpYmxlKCBlbGVtZW50ICkge1xuXHR2YXIgdmlzaWJpbGl0eSA9IGVsZW1lbnQuY3NzKCBcInZpc2liaWxpdHlcIiApO1xuXHR3aGlsZSAoIHZpc2liaWxpdHkgPT09IFwiaW5oZXJpdFwiICkge1xuXHRcdGVsZW1lbnQgPSBlbGVtZW50LnBhcmVudCgpO1xuXHRcdHZpc2liaWxpdHkgPSBlbGVtZW50LmNzcyggXCJ2aXNpYmlsaXR5XCIgKTtcblx0fVxuXHRyZXR1cm4gdmlzaWJpbGl0eSAhPT0gXCJoaWRkZW5cIjtcbn1cblxuJC5leHRlbmQoICQuZXhwclsgXCI6XCIgXSwge1xuXHRmb2N1c2FibGU6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHJldHVybiAkLnVpLmZvY3VzYWJsZSggZWxlbWVudCwgJC5hdHRyKCBlbGVtZW50LCBcInRhYmluZGV4XCIgKSAhPSBudWxsICk7XG5cdH1cbn0gKTtcblxudmFyIGZvY3VzYWJsZSA9ICQudWkuZm9jdXNhYmxlO1xuXG5cblxuXG4vLyBTdXBwb3J0OiBJRTggT25seVxuLy8gSUU4IGRvZXMgbm90IHN1cHBvcnQgdGhlIGZvcm0gYXR0cmlidXRlIGFuZCB3aGVuIGl0IGlzIHN1cHBsaWVkLiBJdCBvdmVyd3JpdGVzIHRoZSBmb3JtIHByb3Bcbi8vIHdpdGggYSBzdHJpbmcsIHNvIHdlIG5lZWQgdG8gZmluZCB0aGUgcHJvcGVyIGZvcm0uXG52YXIgZm9ybSA9ICQuZm4uZm9ybSA9IGZ1bmN0aW9uKCkge1xuXHRyZXR1cm4gdHlwZW9mIHRoaXNbIDAgXS5mb3JtID09PSBcInN0cmluZ1wiID8gdGhpcy5jbG9zZXN0KCBcImZvcm1cIiApIDogJCggdGhpc1sgMCBdLmZvcm0gKTtcbn07XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRm9ybSBSZXNldCBNaXhpbiAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRm9ybSBSZXNldCBNaXhpblxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IFJlZnJlc2ggaW5wdXQgd2lkZ2V0cyB3aGVuIHRoZWlyIGZvcm0gaXMgcmVzZXRcbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9mb3JtLXJlc2V0LW1peGluL1xuXG5cblxudmFyIGZvcm1SZXNldE1peGluID0gJC51aS5mb3JtUmVzZXRNaXhpbiA9IHtcblx0X2Zvcm1SZXNldEhhbmRsZXI6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBmb3JtID0gJCggdGhpcyApO1xuXG5cdFx0Ly8gV2FpdCBmb3IgdGhlIGZvcm0gcmVzZXQgdG8gYWN0dWFsbHkgaGFwcGVuIGJlZm9yZSByZWZyZXNoaW5nXG5cdFx0c2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgaW5zdGFuY2VzID0gZm9ybS5kYXRhKCBcInVpLWZvcm0tcmVzZXQtaW5zdGFuY2VzXCIgKTtcblx0XHRcdCQuZWFjaCggaW5zdGFuY2VzLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5yZWZyZXNoKCk7XG5cdFx0XHR9ICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9iaW5kRm9ybVJlc2V0SGFuZGxlcjogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5mb3JtID0gdGhpcy5lbGVtZW50LmZvcm0oKTtcblx0XHRpZiAoICF0aGlzLmZvcm0ubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciBpbnN0YW5jZXMgPSB0aGlzLmZvcm0uZGF0YSggXCJ1aS1mb3JtLXJlc2V0LWluc3RhbmNlc1wiICkgfHwgW107XG5cdFx0aWYgKCAhaW5zdGFuY2VzLmxlbmd0aCApIHtcblxuXHRcdFx0Ly8gV2UgZG9uJ3QgdXNlIF9vbigpIGhlcmUgYmVjYXVzZSB3ZSB1c2UgYSBzaW5nbGUgZXZlbnQgaGFuZGxlciBwZXIgZm9ybVxuXHRcdFx0dGhpcy5mb3JtLm9uKCBcInJlc2V0LnVpLWZvcm0tcmVzZXRcIiwgdGhpcy5fZm9ybVJlc2V0SGFuZGxlciApO1xuXHRcdH1cblx0XHRpbnN0YW5jZXMucHVzaCggdGhpcyApO1xuXHRcdHRoaXMuZm9ybS5kYXRhKCBcInVpLWZvcm0tcmVzZXQtaW5zdGFuY2VzXCIsIGluc3RhbmNlcyApO1xuXHR9LFxuXG5cdF91bmJpbmRGb3JtUmVzZXRIYW5kbGVyOiBmdW5jdGlvbigpIHtcblx0XHRpZiAoICF0aGlzLmZvcm0ubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciBpbnN0YW5jZXMgPSB0aGlzLmZvcm0uZGF0YSggXCJ1aS1mb3JtLXJlc2V0LWluc3RhbmNlc1wiICk7XG5cdFx0aW5zdGFuY2VzLnNwbGljZSggJC5pbkFycmF5KCB0aGlzLCBpbnN0YW5jZXMgKSwgMSApO1xuXHRcdGlmICggaW5zdGFuY2VzLmxlbmd0aCApIHtcblx0XHRcdHRoaXMuZm9ybS5kYXRhKCBcInVpLWZvcm0tcmVzZXQtaW5zdGFuY2VzXCIsIGluc3RhbmNlcyApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmZvcm1cblx0XHRcdFx0LnJlbW92ZURhdGEoIFwidWktZm9ybS1yZXNldC1pbnN0YW5jZXNcIiApXG5cdFx0XHRcdC5vZmYoIFwicmVzZXQudWktZm9ybS1yZXNldFwiICk7XG5cdFx0fVxuXHR9XG59O1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFN1cHBvcnQgZm9yIGpRdWVyeSBjb3JlIDEuNy54IDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKlxuICovXG5cbi8vPj5sYWJlbDogalF1ZXJ5IDEuNyBTdXBwb3J0XG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogU3VwcG9ydCB2ZXJzaW9uIDEuNy54IG9mIGpRdWVyeSBjb3JlXG5cblxuXG4vLyBTdXBwb3J0OiBqUXVlcnkgMS43IG9ubHlcbi8vIE5vdCBhIGdyZWF0IHdheSB0byBjaGVjayB2ZXJzaW9ucywgYnV0IHNpbmNlIHdlIG9ubHkgc3VwcG9ydCAxLjcrIGFuZCBvbmx5XG4vLyBuZWVkIHRvIGRldGVjdCA8MS44LCB0aGlzIGlzIGEgc2ltcGxlIGNoZWNrIHRoYXQgc2hvdWxkIHN1ZmZpY2UuIENoZWNraW5nXG4vLyBmb3IgXCIxLjcuXCIgd291bGQgYmUgYSBiaXQgc2FmZXIsIGJ1dCB0aGUgdmVyc2lvbiBzdHJpbmcgaXMgMS43LCBub3QgMS43LjBcbi8vIGFuZCB3ZSdsbCBuZXZlciByZWFjaCAxLjcwLjAgKGlmIHdlIGRvLCB3ZSBjZXJ0YWlubHkgd29uJ3QgYmUgc3VwcG9ydGluZ1xuLy8gMS43IGFueW1vcmUpLiBTZWUgIzExMTk3IGZvciB3aHkgd2UncmUgbm90IHVzaW5nIGZlYXR1cmUgZGV0ZWN0aW9uLlxuaWYgKCAkLmZuLmpxdWVyeS5zdWJzdHJpbmcoIDAsIDMgKSA9PT0gXCIxLjdcIiApIHtcblxuXHQvLyBTZXR0ZXJzIGZvciAuaW5uZXJXaWR0aCgpLCAuaW5uZXJIZWlnaHQoKSwgLm91dGVyV2lkdGgoKSwgLm91dGVySGVpZ2h0KClcblx0Ly8gVW5saWtlIGpRdWVyeSBDb3JlIDEuOCssIHRoZXNlIG9ubHkgc3VwcG9ydCBudW1lcmljIHZhbHVlcyB0byBzZXQgdGhlXG5cdC8vIGRpbWVuc2lvbnMgaW4gcGl4ZWxzXG5cdCQuZWFjaCggWyBcIldpZHRoXCIsIFwiSGVpZ2h0XCIgXSwgZnVuY3Rpb24oIGksIG5hbWUgKSB7XG5cdFx0dmFyIHNpZGUgPSBuYW1lID09PSBcIldpZHRoXCIgPyBbIFwiTGVmdFwiLCBcIlJpZ2h0XCIgXSA6IFsgXCJUb3BcIiwgXCJCb3R0b21cIiBdLFxuXHRcdFx0dHlwZSA9IG5hbWUudG9Mb3dlckNhc2UoKSxcblx0XHRcdG9yaWcgPSB7XG5cdFx0XHRcdGlubmVyV2lkdGg6ICQuZm4uaW5uZXJXaWR0aCxcblx0XHRcdFx0aW5uZXJIZWlnaHQ6ICQuZm4uaW5uZXJIZWlnaHQsXG5cdFx0XHRcdG91dGVyV2lkdGg6ICQuZm4ub3V0ZXJXaWR0aCxcblx0XHRcdFx0b3V0ZXJIZWlnaHQ6ICQuZm4ub3V0ZXJIZWlnaHRcblx0XHRcdH07XG5cblx0XHRmdW5jdGlvbiByZWR1Y2UoIGVsZW0sIHNpemUsIGJvcmRlciwgbWFyZ2luICkge1xuXHRcdFx0JC5lYWNoKCBzaWRlLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0c2l6ZSAtPSBwYXJzZUZsb2F0KCAkLmNzcyggZWxlbSwgXCJwYWRkaW5nXCIgKyB0aGlzICkgKSB8fCAwO1xuXHRcdFx0XHRpZiAoIGJvcmRlciApIHtcblx0XHRcdFx0XHRzaXplIC09IHBhcnNlRmxvYXQoICQuY3NzKCBlbGVtLCBcImJvcmRlclwiICsgdGhpcyArIFwiV2lkdGhcIiApICkgfHwgMDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIG1hcmdpbiApIHtcblx0XHRcdFx0XHRzaXplIC09IHBhcnNlRmxvYXQoICQuY3NzKCBlbGVtLCBcIm1hcmdpblwiICsgdGhpcyApICkgfHwgMDtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdFx0cmV0dXJuIHNpemU7XG5cdFx0fVxuXG5cdFx0JC5mblsgXCJpbm5lclwiICsgbmFtZSBdID0gZnVuY3Rpb24oIHNpemUgKSB7XG5cdFx0XHRpZiAoIHNpemUgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0cmV0dXJuIG9yaWdbIFwiaW5uZXJcIiArIG5hbWUgXS5jYWxsKCB0aGlzICk7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQkKCB0aGlzICkuY3NzKCB0eXBlLCByZWR1Y2UoIHRoaXMsIHNpemUgKSArIFwicHhcIiApO1xuXHRcdFx0fSApO1xuXHRcdH07XG5cblx0XHQkLmZuWyBcIm91dGVyXCIgKyBuYW1lIF0gPSBmdW5jdGlvbiggc2l6ZSwgbWFyZ2luICkge1xuXHRcdFx0aWYgKCB0eXBlb2Ygc2l6ZSAhPT0gXCJudW1iZXJcIiApIHtcblx0XHRcdFx0cmV0dXJuIG9yaWdbIFwib3V0ZXJcIiArIG5hbWUgXS5jYWxsKCB0aGlzLCBzaXplICk7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQkKCB0aGlzICkuY3NzKCB0eXBlLCByZWR1Y2UoIHRoaXMsIHNpemUsIHRydWUsIG1hcmdpbiApICsgXCJweFwiICk7XG5cdFx0XHR9ICk7XG5cdFx0fTtcblx0fSApO1xuXG5cdCQuZm4uYWRkQmFjayA9IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gdGhpcy5hZGQoIHNlbGVjdG9yID09IG51bGwgP1xuXHRcdFx0dGhpcy5wcmV2T2JqZWN0IDogdGhpcy5wcmV2T2JqZWN0LmZpbHRlciggc2VsZWN0b3IgKVxuXHRcdCk7XG5cdH07XG59XG5cbjtcbi8qIVxuICogalF1ZXJ5IFVJIEtleWNvZGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEtleWNvZGVcbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBQcm92aWRlIGtleWNvZGVzIGFzIGtleW5hbWVzXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20valF1ZXJ5LnVpLmtleUNvZGUvXG5cblxudmFyIGtleWNvZGUgPSAkLnVpLmtleUNvZGUgPSB7XG5cdEJBQ0tTUEFDRTogOCxcblx0Q09NTUE6IDE4OCxcblx0REVMRVRFOiA0Nixcblx0RE9XTjogNDAsXG5cdEVORDogMzUsXG5cdEVOVEVSOiAxMyxcblx0RVNDQVBFOiAyNyxcblx0SE9NRTogMzYsXG5cdExFRlQ6IDM3LFxuXHRQQUdFX0RPV046IDM0LFxuXHRQQUdFX1VQOiAzMyxcblx0UEVSSU9EOiAxOTAsXG5cdFJJR0hUOiAzOSxcblx0U1BBQ0U6IDMyLFxuXHRUQUI6IDksXG5cdFVQOiAzOFxufTtcblxuXG5cblxuLy8gSW50ZXJuYWwgdXNlIG9ubHlcbnZhciBlc2NhcGVTZWxlY3RvciA9ICQudWkuZXNjYXBlU2VsZWN0b3IgPSAoIGZ1bmN0aW9uKCkge1xuXHR2YXIgc2VsZWN0b3JFc2NhcGUgPSAvKFshXCIjJCUmJygpKissLi86Ozw9Pj9AW1xcXV5ge3x9fl0pL2c7XG5cdHJldHVybiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0cmV0dXJuIHNlbGVjdG9yLnJlcGxhY2UoIHNlbGVjdG9yRXNjYXBlLCBcIlxcXFwkMVwiICk7XG5cdH07XG59ICkoKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBMYWJlbHMgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IGxhYmVsc1xuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IEZpbmQgYWxsIHRoZSBsYWJlbHMgYXNzb2NpYXRlZCB3aXRoIGEgZ2l2ZW4gaW5wdXRcbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9sYWJlbHMvXG5cblxuXG52YXIgbGFiZWxzID0gJC5mbi5sYWJlbHMgPSBmdW5jdGlvbigpIHtcblx0dmFyIGFuY2VzdG9yLCBzZWxlY3RvciwgaWQsIGxhYmVscywgYW5jZXN0b3JzO1xuXG5cdC8vIENoZWNrIGNvbnRyb2wubGFiZWxzIGZpcnN0XG5cdGlmICggdGhpc1sgMCBdLmxhYmVscyAmJiB0aGlzWyAwIF0ubGFiZWxzLmxlbmd0aCApIHtcblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIHRoaXNbIDAgXS5sYWJlbHMgKTtcblx0fVxuXG5cdC8vIFN1cHBvcnQ6IElFIDw9IDExLCBGRiA8PSAzNywgQW5kcm9pZCA8PSAyLjMgb25seVxuXHQvLyBBYm92ZSBicm93c2VycyBkbyBub3Qgc3VwcG9ydCBjb250cm9sLmxhYmVscy4gRXZlcnl0aGluZyBiZWxvdyBpcyB0byBzdXBwb3J0IHRoZW1cblx0Ly8gYXMgd2VsbCBhcyBkb2N1bWVudCBmcmFnbWVudHMuIGNvbnRyb2wubGFiZWxzIGRvZXMgbm90IHdvcmsgb24gZG9jdW1lbnQgZnJhZ21lbnRzXG5cdGxhYmVscyA9IHRoaXMuZXEoIDAgKS5wYXJlbnRzKCBcImxhYmVsXCIgKTtcblxuXHQvLyBMb29rIGZvciB0aGUgbGFiZWwgYmFzZWQgb24gdGhlIGlkXG5cdGlkID0gdGhpcy5hdHRyKCBcImlkXCIgKTtcblx0aWYgKCBpZCApIHtcblxuXHRcdC8vIFdlIGRvbid0IHNlYXJjaCBhZ2FpbnN0IHRoZSBkb2N1bWVudCBpbiBjYXNlIHRoZSBlbGVtZW50XG5cdFx0Ly8gaXMgZGlzY29ubmVjdGVkIGZyb20gdGhlIERPTVxuXHRcdGFuY2VzdG9yID0gdGhpcy5lcSggMCApLnBhcmVudHMoKS5sYXN0KCk7XG5cblx0XHQvLyBHZXQgYSBmdWxsIHNldCBvZiB0b3AgbGV2ZWwgYW5jZXN0b3JzXG5cdFx0YW5jZXN0b3JzID0gYW5jZXN0b3IuYWRkKCBhbmNlc3Rvci5sZW5ndGggPyBhbmNlc3Rvci5zaWJsaW5ncygpIDogdGhpcy5zaWJsaW5ncygpICk7XG5cblx0XHQvLyBDcmVhdGUgYSBzZWxlY3RvciBmb3IgdGhlIGxhYmVsIGJhc2VkIG9uIHRoZSBpZFxuXHRcdHNlbGVjdG9yID0gXCJsYWJlbFtmb3I9J1wiICsgJC51aS5lc2NhcGVTZWxlY3RvciggaWQgKSArIFwiJ11cIjtcblxuXHRcdGxhYmVscyA9IGxhYmVscy5hZGQoIGFuY2VzdG9ycy5maW5kKCBzZWxlY3RvciApLmFkZEJhY2soIHNlbGVjdG9yICkgKTtcblxuXHR9XG5cblx0Ly8gUmV0dXJuIHdoYXRldmVyIHdlIGhhdmUgZm91bmQgZm9yIGxhYmVsc1xuXHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIGxhYmVscyApO1xufTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBTY3JvbGwgUGFyZW50IDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBzY3JvbGxQYXJlbnRcbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBHZXQgdGhlIGNsb3Nlc3QgYW5jZXN0b3IgZWxlbWVudCB0aGF0IGlzIHNjcm9sbGFibGUuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc2Nyb2xsUGFyZW50L1xuXG5cblxudmFyIHNjcm9sbFBhcmVudCA9ICQuZm4uc2Nyb2xsUGFyZW50ID0gZnVuY3Rpb24oIGluY2x1ZGVIaWRkZW4gKSB7XG5cdHZhciBwb3NpdGlvbiA9IHRoaXMuY3NzKCBcInBvc2l0aW9uXCIgKSxcblx0XHRleGNsdWRlU3RhdGljUGFyZW50ID0gcG9zaXRpb24gPT09IFwiYWJzb2x1dGVcIixcblx0XHRvdmVyZmxvd1JlZ2V4ID0gaW5jbHVkZUhpZGRlbiA/IC8oYXV0b3xzY3JvbGx8aGlkZGVuKS8gOiAvKGF1dG98c2Nyb2xsKS8sXG5cdFx0c2Nyb2xsUGFyZW50ID0gdGhpcy5wYXJlbnRzKCkuZmlsdGVyKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBwYXJlbnQgPSAkKCB0aGlzICk7XG5cdFx0XHRpZiAoIGV4Y2x1ZGVTdGF0aWNQYXJlbnQgJiYgcGFyZW50LmNzcyggXCJwb3NpdGlvblwiICkgPT09IFwic3RhdGljXCIgKSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBvdmVyZmxvd1JlZ2V4LnRlc3QoIHBhcmVudC5jc3MoIFwib3ZlcmZsb3dcIiApICsgcGFyZW50LmNzcyggXCJvdmVyZmxvdy15XCIgKSArXG5cdFx0XHRcdHBhcmVudC5jc3MoIFwib3ZlcmZsb3cteFwiICkgKTtcblx0XHR9ICkuZXEoIDAgKTtcblxuXHRyZXR1cm4gcG9zaXRpb24gPT09IFwiZml4ZWRcIiB8fCAhc2Nyb2xsUGFyZW50Lmxlbmd0aCA/XG5cdFx0JCggdGhpc1sgMCBdLm93bmVyRG9jdW1lbnQgfHwgZG9jdW1lbnQgKSA6XG5cdFx0c2Nyb2xsUGFyZW50O1xufTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBUYWJiYWJsZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogOnRhYmJhYmxlIFNlbGVjdG9yXG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogU2VsZWN0cyBlbGVtZW50cyB3aGljaCBjYW4gYmUgdGFiYmVkIHRvLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3RhYmJhYmxlLXNlbGVjdG9yL1xuXG5cblxudmFyIHRhYmJhYmxlID0gJC5leHRlbmQoICQuZXhwclsgXCI6XCIgXSwge1xuXHR0YWJiYWJsZTogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0dmFyIHRhYkluZGV4ID0gJC5hdHRyKCBlbGVtZW50LCBcInRhYmluZGV4XCIgKSxcblx0XHRcdGhhc1RhYmluZGV4ID0gdGFiSW5kZXggIT0gbnVsbDtcblx0XHRyZXR1cm4gKCAhaGFzVGFiaW5kZXggfHwgdGFiSW5kZXggPj0gMCApICYmICQudWkuZm9jdXNhYmxlKCBlbGVtZW50LCBoYXNUYWJpbmRleCApO1xuXHR9XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgVW5pcXVlIElEIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiB1bmlxdWVJZFxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IEZ1bmN0aW9ucyB0byBnZW5lcmF0ZSBhbmQgcmVtb3ZlIHVuaXF1ZUlkJ3Ncbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS91bmlxdWVJZC9cblxuXG5cbnZhciB1bmlxdWVJZCA9ICQuZm4uZXh0ZW5kKCB7XG5cdHVuaXF1ZUlkOiAoIGZ1bmN0aW9uKCkge1xuXHRcdHZhciB1dWlkID0gMDtcblxuXHRcdHJldHVybiBmdW5jdGlvbigpIHtcblx0XHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoICF0aGlzLmlkICkge1xuXHRcdFx0XHRcdHRoaXMuaWQgPSBcInVpLWlkLVwiICsgKCArK3V1aWQgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH07XG5cdH0gKSgpLFxuXG5cdHJlbW92ZVVuaXF1ZUlkOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggL151aS1pZC1cXGQrJC8udGVzdCggdGhpcy5pZCApICkge1xuXHRcdFx0XHQkKCB0aGlzICkucmVtb3ZlQXR0ciggXCJpZFwiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgQWNjb3JkaW9uIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBBY2NvcmRpb25cbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8ganNjczpkaXNhYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZGVzY3JpcHRpb246IERpc3BsYXlzIGNvbGxhcHNpYmxlIGNvbnRlbnQgcGFuZWxzIGZvciBwcmVzZW50aW5nIGluZm9ybWF0aW9uIGluIGEgbGltaXRlZCBhbW91bnQgb2Ygc3BhY2UuXG4vLyBqc2NzOmVuYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2FjY29yZGlvbi9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9hY2NvcmRpb24vXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9hY2NvcmRpb24uY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbnZhciB3aWRnZXRzQWNjb3JkaW9uID0gJC53aWRnZXQoIFwidWkuYWNjb3JkaW9uXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0b3B0aW9uczoge1xuXHRcdGFjdGl2ZTogMCxcblx0XHRhbmltYXRlOiB7fSxcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLWFjY29yZGlvbi1oZWFkZXJcIjogXCJ1aS1jb3JuZXItdG9wXCIsXG5cdFx0XHRcInVpLWFjY29yZGlvbi1oZWFkZXItY29sbGFwc2VkXCI6IFwidWktY29ybmVyLWFsbFwiLFxuXHRcdFx0XCJ1aS1hY2NvcmRpb24tY29udGVudFwiOiBcInVpLWNvcm5lci1ib3R0b21cIlxuXHRcdH0sXG5cdFx0Y29sbGFwc2libGU6IGZhbHNlLFxuXHRcdGV2ZW50OiBcImNsaWNrXCIsXG5cdFx0aGVhZGVyOiBcIj4gbGkgPiA6Zmlyc3QtY2hpbGQsID4gOm5vdChsaSk6ZXZlblwiLFxuXHRcdGhlaWdodFN0eWxlOiBcImF1dG9cIixcblx0XHRpY29uczoge1xuXHRcdFx0YWN0aXZlSGVhZGVyOiBcInVpLWljb24tdHJpYW5nbGUtMS1zXCIsXG5cdFx0XHRoZWFkZXI6IFwidWktaWNvbi10cmlhbmdsZS0xLWVcIlxuXHRcdH0sXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRhY3RpdmF0ZTogbnVsbCxcblx0XHRiZWZvcmVBY3RpdmF0ZTogbnVsbFxuXHR9LFxuXG5cdGhpZGVQcm9wczoge1xuXHRcdGJvcmRlclRvcFdpZHRoOiBcImhpZGVcIixcblx0XHRib3JkZXJCb3R0b21XaWR0aDogXCJoaWRlXCIsXG5cdFx0cGFkZGluZ1RvcDogXCJoaWRlXCIsXG5cdFx0cGFkZGluZ0JvdHRvbTogXCJoaWRlXCIsXG5cdFx0aGVpZ2h0OiBcImhpZGVcIlxuXHR9LFxuXG5cdHNob3dQcm9wczoge1xuXHRcdGJvcmRlclRvcFdpZHRoOiBcInNob3dcIixcblx0XHRib3JkZXJCb3R0b21XaWR0aDogXCJzaG93XCIsXG5cdFx0cGFkZGluZ1RvcDogXCJzaG93XCIsXG5cdFx0cGFkZGluZ0JvdHRvbTogXCJzaG93XCIsXG5cdFx0aGVpZ2h0OiBcInNob3dcIlxuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0dGhpcy5wcmV2U2hvdyA9IHRoaXMucHJldkhpZGUgPSAkKCk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktYWNjb3JkaW9uXCIsIFwidWktd2lkZ2V0IHVpLWhlbHBlci1yZXNldFwiICk7XG5cdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwicm9sZVwiLCBcInRhYmxpc3RcIiApO1xuXG5cdFx0Ly8gRG9uJ3QgYWxsb3cgY29sbGFwc2libGU6IGZhbHNlIGFuZCBhY3RpdmU6IGZhbHNlIC8gbnVsbFxuXHRcdGlmICggIW9wdGlvbnMuY29sbGFwc2libGUgJiYgKCBvcHRpb25zLmFjdGl2ZSA9PT0gZmFsc2UgfHwgb3B0aW9ucy5hY3RpdmUgPT0gbnVsbCApICkge1xuXHRcdFx0b3B0aW9ucy5hY3RpdmUgPSAwO1xuXHRcdH1cblxuXHRcdHRoaXMuX3Byb2Nlc3NQYW5lbHMoKTtcblxuXHRcdC8vIGhhbmRsZSBuZWdhdGl2ZSB2YWx1ZXNcblx0XHRpZiAoIG9wdGlvbnMuYWN0aXZlIDwgMCApIHtcblx0XHRcdG9wdGlvbnMuYWN0aXZlICs9IHRoaXMuaGVhZGVycy5sZW5ndGg7XG5cdFx0fVxuXHRcdHRoaXMuX3JlZnJlc2goKTtcblx0fSxcblxuXHRfZ2V0Q3JlYXRlRXZlbnREYXRhOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0aGVhZGVyOiB0aGlzLmFjdGl2ZSxcblx0XHRcdHBhbmVsOiAhdGhpcy5hY3RpdmUubGVuZ3RoID8gJCgpIDogdGhpcy5hY3RpdmUubmV4dCgpXG5cdFx0fTtcblx0fSxcblxuXHRfY3JlYXRlSWNvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpY29uLCBjaGlsZHJlbixcblx0XHRcdGljb25zID0gdGhpcy5vcHRpb25zLmljb25zO1xuXG5cdFx0aWYgKCBpY29ucyApIHtcblx0XHRcdGljb24gPSAkKCBcIjxzcGFuPlwiICk7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggaWNvbiwgXCJ1aS1hY2NvcmRpb24taGVhZGVyLWljb25cIiwgXCJ1aS1pY29uIFwiICsgaWNvbnMuaGVhZGVyICk7XG5cdFx0XHRpY29uLnByZXBlbmRUbyggdGhpcy5oZWFkZXJzICk7XG5cdFx0XHRjaGlsZHJlbiA9IHRoaXMuYWN0aXZlLmNoaWxkcmVuKCBcIi51aS1hY2NvcmRpb24taGVhZGVyLWljb25cIiApO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGNoaWxkcmVuLCBpY29ucy5oZWFkZXIgKVxuXHRcdFx0XHQuX2FkZENsYXNzKCBjaGlsZHJlbiwgbnVsbCwgaWNvbnMuYWN0aXZlSGVhZGVyIClcblx0XHRcdFx0Ll9hZGRDbGFzcyggdGhpcy5oZWFkZXJzLCBcInVpLWFjY29yZGlvbi1pY29uc1wiICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9kZXN0cm95SWNvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmhlYWRlcnMsIFwidWktYWNjb3JkaW9uLWljb25zXCIgKTtcblx0XHR0aGlzLmhlYWRlcnMuY2hpbGRyZW4oIFwiLnVpLWFjY29yZGlvbi1oZWFkZXItaWNvblwiICkucmVtb3ZlKCk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBjb250ZW50cztcblxuXHRcdC8vIENsZWFuIHVwIG1haW4gZWxlbWVudFxuXHRcdHRoaXMuZWxlbWVudC5yZW1vdmVBdHRyKCBcInJvbGVcIiApO1xuXG5cdFx0Ly8gQ2xlYW4gdXAgaGVhZGVyc1xuXHRcdHRoaXMuaGVhZGVyc1xuXHRcdFx0LnJlbW92ZUF0dHIoIFwicm9sZSBhcmlhLWV4cGFuZGVkIGFyaWEtc2VsZWN0ZWQgYXJpYS1jb250cm9scyB0YWJJbmRleFwiIClcblx0XHRcdC5yZW1vdmVVbmlxdWVJZCgpO1xuXG5cdFx0dGhpcy5fZGVzdHJveUljb25zKCk7XG5cblx0XHQvLyBDbGVhbiB1cCBjb250ZW50IHBhbmVsc1xuXHRcdGNvbnRlbnRzID0gdGhpcy5oZWFkZXJzLm5leHQoKVxuXHRcdFx0LmNzcyggXCJkaXNwbGF5XCIsIFwiXCIgKVxuXHRcdFx0LnJlbW92ZUF0dHIoIFwicm9sZSBhcmlhLWhpZGRlbiBhcmlhLWxhYmVsbGVkYnlcIiApXG5cdFx0XHQucmVtb3ZlVW5pcXVlSWQoKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmhlaWdodFN0eWxlICE9PSBcImNvbnRlbnRcIiApIHtcblx0XHRcdGNvbnRlbnRzLmNzcyggXCJoZWlnaHRcIiwgXCJcIiApO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRpZiAoIGtleSA9PT0gXCJhY3RpdmVcIiApIHtcblxuXHRcdFx0Ly8gX2FjdGl2YXRlKCkgd2lsbCBoYW5kbGUgaW52YWxpZCB2YWx1ZXMgYW5kIHVwZGF0ZSB0aGlzLm9wdGlvbnNcblx0XHRcdHRoaXMuX2FjdGl2YXRlKCB2YWx1ZSApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcImV2ZW50XCIgKSB7XG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5ldmVudCApIHtcblx0XHRcdFx0dGhpcy5fb2ZmKCB0aGlzLmhlYWRlcnMsIHRoaXMub3B0aW9ucy5ldmVudCApO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fc2V0dXBFdmVudHMoIHZhbHVlICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdC8vIFNldHRpbmcgY29sbGFwc2libGU6IGZhbHNlIHdoaWxlIGNvbGxhcHNlZDsgb3BlbiBmaXJzdCBwYW5lbFxuXHRcdGlmICgga2V5ID09PSBcImNvbGxhcHNpYmxlXCIgJiYgIXZhbHVlICYmIHRoaXMub3B0aW9ucy5hY3RpdmUgPT09IGZhbHNlICkge1xuXHRcdFx0dGhpcy5fYWN0aXZhdGUoIDAgKTtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJpY29uc1wiICkge1xuXHRcdFx0dGhpcy5fZGVzdHJveUljb25zKCk7XG5cdFx0XHRpZiAoIHZhbHVlICkge1xuXHRcdFx0XHR0aGlzLl9jcmVhdGVJY29ucygpO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uRGlzYWJsZWQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlciggdmFsdWUgKTtcblxuXHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcImFyaWEtZGlzYWJsZWRcIiwgdmFsdWUgKTtcblxuXHRcdC8vIFN1cHBvcnQ6IElFOCBPbmx5XG5cdFx0Ly8gIzUzMzIgLyAjNjA1OSAtIG9wYWNpdHkgZG9lc24ndCBjYXNjYWRlIHRvIHBvc2l0aW9uZWQgZWxlbWVudHMgaW4gSUVcblx0XHQvLyBzbyB3ZSBuZWVkIHRvIGFkZCB0aGUgZGlzYWJsZWQgY2xhc3MgdG8gdGhlIGhlYWRlcnMgYW5kIHBhbmVsc1xuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIsICEhdmFsdWUgKTtcblx0XHR0aGlzLl90b2dnbGVDbGFzcyggdGhpcy5oZWFkZXJzLmFkZCggdGhpcy5oZWFkZXJzLm5leHQoKSApLCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIsXG5cdFx0XHQhIXZhbHVlICk7XG5cdH0sXG5cblx0X2tleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoIGV2ZW50LmFsdEtleSB8fCBldmVudC5jdHJsS2V5ICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciBrZXlDb2RlID0gJC51aS5rZXlDb2RlLFxuXHRcdFx0bGVuZ3RoID0gdGhpcy5oZWFkZXJzLmxlbmd0aCxcblx0XHRcdGN1cnJlbnRJbmRleCA9IHRoaXMuaGVhZGVycy5pbmRleCggZXZlbnQudGFyZ2V0ICksXG5cdFx0XHR0b0ZvY3VzID0gZmFsc2U7XG5cblx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdGNhc2Uga2V5Q29kZS5SSUdIVDpcblx0XHRjYXNlIGtleUNvZGUuRE9XTjpcblx0XHRcdHRvRm9jdXMgPSB0aGlzLmhlYWRlcnNbICggY3VycmVudEluZGV4ICsgMSApICUgbGVuZ3RoIF07XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIGtleUNvZGUuTEVGVDpcblx0XHRjYXNlIGtleUNvZGUuVVA6XG5cdFx0XHR0b0ZvY3VzID0gdGhpcy5oZWFkZXJzWyAoIGN1cnJlbnRJbmRleCAtIDEgKyBsZW5ndGggKSAlIGxlbmd0aCBdO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSBrZXlDb2RlLlNQQUNFOlxuXHRcdGNhc2Uga2V5Q29kZS5FTlRFUjpcblx0XHRcdHRoaXMuX2V2ZW50SGFuZGxlciggZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2Uga2V5Q29kZS5IT01FOlxuXHRcdFx0dG9Gb2N1cyA9IHRoaXMuaGVhZGVyc1sgMCBdO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSBrZXlDb2RlLkVORDpcblx0XHRcdHRvRm9jdXMgPSB0aGlzLmhlYWRlcnNbIGxlbmd0aCAtIDEgXTtcblx0XHRcdGJyZWFrO1xuXHRcdH1cblxuXHRcdGlmICggdG9Gb2N1cyApIHtcblx0XHRcdCQoIGV2ZW50LnRhcmdldCApLmF0dHIoIFwidGFiSW5kZXhcIiwgLTEgKTtcblx0XHRcdCQoIHRvRm9jdXMgKS5hdHRyKCBcInRhYkluZGV4XCIsIDAgKTtcblx0XHRcdCQoIHRvRm9jdXMgKS50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9wYW5lbEtleURvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoIGV2ZW50LmtleUNvZGUgPT09ICQudWkua2V5Q29kZS5VUCAmJiBldmVudC5jdHJsS2V5ICkge1xuXHRcdFx0JCggZXZlbnQuY3VycmVudFRhcmdldCApLnByZXYoKS50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0cmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cdFx0dGhpcy5fcHJvY2Vzc1BhbmVscygpO1xuXG5cdFx0Ly8gV2FzIGNvbGxhcHNlZCBvciBubyBwYW5lbFxuXHRcdGlmICggKCBvcHRpb25zLmFjdGl2ZSA9PT0gZmFsc2UgJiYgb3B0aW9ucy5jb2xsYXBzaWJsZSA9PT0gdHJ1ZSApIHx8XG5cdFx0XHRcdCF0aGlzLmhlYWRlcnMubGVuZ3RoICkge1xuXHRcdFx0b3B0aW9ucy5hY3RpdmUgPSBmYWxzZTtcblx0XHRcdHRoaXMuYWN0aXZlID0gJCgpO1xuXG5cdFx0Ly8gYWN0aXZlIGZhbHNlIG9ubHkgd2hlbiBjb2xsYXBzaWJsZSBpcyB0cnVlXG5cdFx0fSBlbHNlIGlmICggb3B0aW9ucy5hY3RpdmUgPT09IGZhbHNlICkge1xuXHRcdFx0dGhpcy5fYWN0aXZhdGUoIDAgKTtcblxuXHRcdC8vIHdhcyBhY3RpdmUsIGJ1dCBhY3RpdmUgcGFuZWwgaXMgZ29uZVxuXHRcdH0gZWxzZSBpZiAoIHRoaXMuYWN0aXZlLmxlbmd0aCAmJiAhJC5jb250YWlucyggdGhpcy5lbGVtZW50WyAwIF0sIHRoaXMuYWN0aXZlWyAwIF0gKSApIHtcblxuXHRcdFx0Ly8gYWxsIHJlbWFpbmluZyBwYW5lbCBhcmUgZGlzYWJsZWRcblx0XHRcdGlmICggdGhpcy5oZWFkZXJzLmxlbmd0aCA9PT0gdGhpcy5oZWFkZXJzLmZpbmQoIFwiLnVpLXN0YXRlLWRpc2FibGVkXCIgKS5sZW5ndGggKSB7XG5cdFx0XHRcdG9wdGlvbnMuYWN0aXZlID0gZmFsc2U7XG5cdFx0XHRcdHRoaXMuYWN0aXZlID0gJCgpO1xuXG5cdFx0XHQvLyBhY3RpdmF0ZSBwcmV2aW91cyBwYW5lbFxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5fYWN0aXZhdGUoIE1hdGgubWF4KCAwLCBvcHRpb25zLmFjdGl2ZSAtIDEgKSApO1xuXHRcdFx0fVxuXG5cdFx0Ly8gd2FzIGFjdGl2ZSwgYWN0aXZlIHBhbmVsIHN0aWxsIGV4aXN0c1xuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIG1ha2Ugc3VyZSBhY3RpdmUgaW5kZXggaXMgY29ycmVjdFxuXHRcdFx0b3B0aW9ucy5hY3RpdmUgPSB0aGlzLmhlYWRlcnMuaW5kZXgoIHRoaXMuYWN0aXZlICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fZGVzdHJveUljb25zKCk7XG5cblx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cdH0sXG5cblx0X3Byb2Nlc3NQYW5lbHM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBwcmV2SGVhZGVycyA9IHRoaXMuaGVhZGVycyxcblx0XHRcdHByZXZQYW5lbHMgPSB0aGlzLnBhbmVscztcblxuXHRcdHRoaXMuaGVhZGVycyA9IHRoaXMuZWxlbWVudC5maW5kKCB0aGlzLm9wdGlvbnMuaGVhZGVyICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaGVhZGVycywgXCJ1aS1hY2NvcmRpb24taGVhZGVyIHVpLWFjY29yZGlvbi1oZWFkZXItY29sbGFwc2VkXCIsXG5cdFx0XHRcInVpLXN0YXRlLWRlZmF1bHRcIiApO1xuXG5cdFx0dGhpcy5wYW5lbHMgPSB0aGlzLmhlYWRlcnMubmV4dCgpLmZpbHRlciggXCI6bm90KC51aS1hY2NvcmRpb24tY29udGVudC1hY3RpdmUpXCIgKS5oaWRlKCk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMucGFuZWxzLCBcInVpLWFjY29yZGlvbi1jb250ZW50XCIsIFwidWktaGVscGVyLXJlc2V0IHVpLXdpZGdldC1jb250ZW50XCIgKTtcblxuXHRcdC8vIEF2b2lkIG1lbW9yeSBsZWFrcyAoIzEwMDU2KVxuXHRcdGlmICggcHJldlBhbmVscyApIHtcblx0XHRcdHRoaXMuX29mZiggcHJldkhlYWRlcnMubm90KCB0aGlzLmhlYWRlcnMgKSApO1xuXHRcdFx0dGhpcy5fb2ZmKCBwcmV2UGFuZWxzLm5vdCggdGhpcy5wYW5lbHMgKSApO1xuXHRcdH1cblx0fSxcblxuXHRfcmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG1heEhlaWdodCxcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRoZWlnaHRTdHlsZSA9IG9wdGlvbnMuaGVpZ2h0U3R5bGUsXG5cdFx0XHRwYXJlbnQgPSB0aGlzLmVsZW1lbnQucGFyZW50KCk7XG5cblx0XHR0aGlzLmFjdGl2ZSA9IHRoaXMuX2ZpbmRBY3RpdmUoIG9wdGlvbnMuYWN0aXZlICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuYWN0aXZlLCBcInVpLWFjY29yZGlvbi1oZWFkZXItYWN0aXZlXCIsIFwidWktc3RhdGUtYWN0aXZlXCIgKVxuXHRcdFx0Ll9yZW1vdmVDbGFzcyggdGhpcy5hY3RpdmUsIFwidWktYWNjb3JkaW9uLWhlYWRlci1jb2xsYXBzZWRcIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmFjdGl2ZS5uZXh0KCksIFwidWktYWNjb3JkaW9uLWNvbnRlbnQtYWN0aXZlXCIgKTtcblx0XHR0aGlzLmFjdGl2ZS5uZXh0KCkuc2hvdygpO1xuXG5cdFx0dGhpcy5oZWFkZXJzXG5cdFx0XHQuYXR0ciggXCJyb2xlXCIsIFwidGFiXCIgKVxuXHRcdFx0LmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgaGVhZGVyID0gJCggdGhpcyApLFxuXHRcdFx0XHRcdGhlYWRlcklkID0gaGVhZGVyLnVuaXF1ZUlkKCkuYXR0ciggXCJpZFwiICksXG5cdFx0XHRcdFx0cGFuZWwgPSBoZWFkZXIubmV4dCgpLFxuXHRcdFx0XHRcdHBhbmVsSWQgPSBwYW5lbC51bmlxdWVJZCgpLmF0dHIoIFwiaWRcIiApO1xuXHRcdFx0XHRoZWFkZXIuYXR0ciggXCJhcmlhLWNvbnRyb2xzXCIsIHBhbmVsSWQgKTtcblx0XHRcdFx0cGFuZWwuYXR0ciggXCJhcmlhLWxhYmVsbGVkYnlcIiwgaGVhZGVySWQgKTtcblx0XHRcdH0gKVxuXHRcdFx0Lm5leHQoKVxuXHRcdFx0XHQuYXR0ciggXCJyb2xlXCIsIFwidGFicGFuZWxcIiApO1xuXG5cdFx0dGhpcy5oZWFkZXJzXG5cdFx0XHQubm90KCB0aGlzLmFjdGl2ZSApXG5cdFx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdFx0XCJhcmlhLXNlbGVjdGVkXCI6IFwiZmFsc2VcIixcblx0XHRcdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJmYWxzZVwiLFxuXHRcdFx0XHRcdHRhYkluZGV4OiAtMVxuXHRcdFx0XHR9IClcblx0XHRcdFx0Lm5leHQoKVxuXHRcdFx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdFx0XHRcImFyaWEtaGlkZGVuXCI6IFwidHJ1ZVwiXG5cdFx0XHRcdFx0fSApXG5cdFx0XHRcdFx0LmhpZGUoKTtcblxuXHRcdC8vIE1ha2Ugc3VyZSBhdCBsZWFzdCBvbmUgaGVhZGVyIGlzIGluIHRoZSB0YWIgb3JkZXJcblx0XHRpZiAoICF0aGlzLmFjdGl2ZS5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLmhlYWRlcnMuZXEoIDAgKS5hdHRyKCBcInRhYkluZGV4XCIsIDAgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5hY3RpdmUuYXR0cigge1xuXHRcdFx0XHRcImFyaWEtc2VsZWN0ZWRcIjogXCJ0cnVlXCIsXG5cdFx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcInRydWVcIixcblx0XHRcdFx0dGFiSW5kZXg6IDBcblx0XHRcdH0gKVxuXHRcdFx0XHQubmV4dCgpXG5cdFx0XHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0XHRcdFwiYXJpYS1oaWRkZW5cIjogXCJmYWxzZVwiXG5cdFx0XHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX2NyZWF0ZUljb25zKCk7XG5cblx0XHR0aGlzLl9zZXR1cEV2ZW50cyggb3B0aW9ucy5ldmVudCApO1xuXG5cdFx0aWYgKCBoZWlnaHRTdHlsZSA9PT0gXCJmaWxsXCIgKSB7XG5cdFx0XHRtYXhIZWlnaHQgPSBwYXJlbnQuaGVpZ2h0KCk7XG5cdFx0XHR0aGlzLmVsZW1lbnQuc2libGluZ3MoIFwiOnZpc2libGVcIiApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgZWxlbSA9ICQoIHRoaXMgKSxcblx0XHRcdFx0XHRwb3NpdGlvbiA9IGVsZW0uY3NzKCBcInBvc2l0aW9uXCIgKTtcblxuXHRcdFx0XHRpZiAoIHBvc2l0aW9uID09PSBcImFic29sdXRlXCIgfHwgcG9zaXRpb24gPT09IFwiZml4ZWRcIiApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdFx0bWF4SGVpZ2h0IC09IGVsZW0ub3V0ZXJIZWlnaHQoIHRydWUgKTtcblx0XHRcdH0gKTtcblxuXHRcdFx0dGhpcy5oZWFkZXJzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRtYXhIZWlnaHQgLT0gJCggdGhpcyApLm91dGVySGVpZ2h0KCB0cnVlICk7XG5cdFx0XHR9ICk7XG5cblx0XHRcdHRoaXMuaGVhZGVycy5uZXh0KClcblx0XHRcdFx0LmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdCQoIHRoaXMgKS5oZWlnaHQoIE1hdGgubWF4KCAwLCBtYXhIZWlnaHQgLVxuXHRcdFx0XHRcdFx0JCggdGhpcyApLmlubmVySGVpZ2h0KCkgKyAkKCB0aGlzICkuaGVpZ2h0KCkgKSApO1xuXHRcdFx0XHR9IClcblx0XHRcdFx0LmNzcyggXCJvdmVyZmxvd1wiLCBcImF1dG9cIiApO1xuXHRcdH0gZWxzZSBpZiAoIGhlaWdodFN0eWxlID09PSBcImF1dG9cIiApIHtcblx0XHRcdG1heEhlaWdodCA9IDA7XG5cdFx0XHR0aGlzLmhlYWRlcnMubmV4dCgpXG5cdFx0XHRcdC5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR2YXIgaXNWaXNpYmxlID0gJCggdGhpcyApLmlzKCBcIjp2aXNpYmxlXCIgKTtcblx0XHRcdFx0XHRpZiAoICFpc1Zpc2libGUgKSB7XG5cdFx0XHRcdFx0XHQkKCB0aGlzICkuc2hvdygpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRtYXhIZWlnaHQgPSBNYXRoLm1heCggbWF4SGVpZ2h0LCAkKCB0aGlzICkuY3NzKCBcImhlaWdodFwiLCBcIlwiICkuaGVpZ2h0KCkgKTtcblx0XHRcdFx0XHRpZiAoICFpc1Zpc2libGUgKSB7XG5cdFx0XHRcdFx0XHQkKCB0aGlzICkuaGlkZSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApXG5cdFx0XHRcdC5oZWlnaHQoIG1heEhlaWdodCApO1xuXHRcdH1cblx0fSxcblxuXHRfYWN0aXZhdGU6IGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHR2YXIgYWN0aXZlID0gdGhpcy5fZmluZEFjdGl2ZSggaW5kZXggKVsgMCBdO1xuXG5cdFx0Ly8gVHJ5aW5nIHRvIGFjdGl2YXRlIHRoZSBhbHJlYWR5IGFjdGl2ZSBwYW5lbFxuXHRcdGlmICggYWN0aXZlID09PSB0aGlzLmFjdGl2ZVsgMCBdICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIFRyeWluZyB0byBjb2xsYXBzZSwgc2ltdWxhdGUgYSBjbGljayBvbiB0aGUgY3VycmVudGx5IGFjdGl2ZSBoZWFkZXJcblx0XHRhY3RpdmUgPSBhY3RpdmUgfHwgdGhpcy5hY3RpdmVbIDAgXTtcblxuXHRcdHRoaXMuX2V2ZW50SGFuZGxlcigge1xuXHRcdFx0dGFyZ2V0OiBhY3RpdmUsXG5cdFx0XHRjdXJyZW50VGFyZ2V0OiBhY3RpdmUsXG5cdFx0XHRwcmV2ZW50RGVmYXVsdDogJC5ub29wXG5cdFx0fSApO1xuXHR9LFxuXG5cdF9maW5kQWN0aXZlOiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0cmV0dXJuIHR5cGVvZiBzZWxlY3RvciA9PT0gXCJudW1iZXJcIiA/IHRoaXMuaGVhZGVycy5lcSggc2VsZWN0b3IgKSA6ICQoKTtcblx0fSxcblxuXHRfc2V0dXBFdmVudHM6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgZXZlbnRzID0ge1xuXHRcdFx0a2V5ZG93bjogXCJfa2V5ZG93blwiXG5cdFx0fTtcblx0XHRpZiAoIGV2ZW50ICkge1xuXHRcdFx0JC5lYWNoKCBldmVudC5zcGxpdCggXCIgXCIgKSwgZnVuY3Rpb24oIGluZGV4LCBldmVudE5hbWUgKSB7XG5cdFx0XHRcdGV2ZW50c1sgZXZlbnROYW1lIF0gPSBcIl9ldmVudEhhbmRsZXJcIjtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHR0aGlzLl9vZmYoIHRoaXMuaGVhZGVycy5hZGQoIHRoaXMuaGVhZGVycy5uZXh0KCkgKSApO1xuXHRcdHRoaXMuX29uKCB0aGlzLmhlYWRlcnMsIGV2ZW50cyApO1xuXHRcdHRoaXMuX29uKCB0aGlzLmhlYWRlcnMubmV4dCgpLCB7IGtleWRvd246IFwiX3BhbmVsS2V5RG93blwiIH0gKTtcblx0XHR0aGlzLl9ob3ZlcmFibGUoIHRoaXMuaGVhZGVycyApO1xuXHRcdHRoaXMuX2ZvY3VzYWJsZSggdGhpcy5oZWFkZXJzICk7XG5cdH0sXG5cblx0X2V2ZW50SGFuZGxlcjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBhY3RpdmVDaGlsZHJlbiwgY2xpY2tlZENoaWxkcmVuLFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGFjdGl2ZSA9IHRoaXMuYWN0aXZlLFxuXHRcdFx0Y2xpY2tlZCA9ICQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKSxcblx0XHRcdGNsaWNrZWRJc0FjdGl2ZSA9IGNsaWNrZWRbIDAgXSA9PT0gYWN0aXZlWyAwIF0sXG5cdFx0XHRjb2xsYXBzaW5nID0gY2xpY2tlZElzQWN0aXZlICYmIG9wdGlvbnMuY29sbGFwc2libGUsXG5cdFx0XHR0b1Nob3cgPSBjb2xsYXBzaW5nID8gJCgpIDogY2xpY2tlZC5uZXh0KCksXG5cdFx0XHR0b0hpZGUgPSBhY3RpdmUubmV4dCgpLFxuXHRcdFx0ZXZlbnREYXRhID0ge1xuXHRcdFx0XHRvbGRIZWFkZXI6IGFjdGl2ZSxcblx0XHRcdFx0b2xkUGFuZWw6IHRvSGlkZSxcblx0XHRcdFx0bmV3SGVhZGVyOiBjb2xsYXBzaW5nID8gJCgpIDogY2xpY2tlZCxcblx0XHRcdFx0bmV3UGFuZWw6IHRvU2hvd1xuXHRcdFx0fTtcblxuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRpZiAoXG5cblx0XHRcdFx0Ly8gY2xpY2sgb24gYWN0aXZlIGhlYWRlciwgYnV0IG5vdCBjb2xsYXBzaWJsZVxuXHRcdFx0XHQoIGNsaWNrZWRJc0FjdGl2ZSAmJiAhb3B0aW9ucy5jb2xsYXBzaWJsZSApIHx8XG5cblx0XHRcdFx0Ly8gYWxsb3cgY2FuY2VsaW5nIGFjdGl2YXRpb25cblx0XHRcdFx0KCB0aGlzLl90cmlnZ2VyKCBcImJlZm9yZUFjdGl2YXRlXCIsIGV2ZW50LCBldmVudERhdGEgKSA9PT0gZmFsc2UgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRvcHRpb25zLmFjdGl2ZSA9IGNvbGxhcHNpbmcgPyBmYWxzZSA6IHRoaXMuaGVhZGVycy5pbmRleCggY2xpY2tlZCApO1xuXG5cdFx0Ly8gV2hlbiB0aGUgY2FsbCB0byAuX3RvZ2dsZSgpIGNvbWVzIGFmdGVyIHRoZSBjbGFzcyBjaGFuZ2VzXG5cdFx0Ly8gaXQgY2F1c2VzIGEgdmVyeSBvZGQgYnVnIGluIElFIDggKHNlZSAjNjcyMClcblx0XHR0aGlzLmFjdGl2ZSA9IGNsaWNrZWRJc0FjdGl2ZSA/ICQoKSA6IGNsaWNrZWQ7XG5cdFx0dGhpcy5fdG9nZ2xlKCBldmVudERhdGEgKTtcblxuXHRcdC8vIFN3aXRjaCBjbGFzc2VzXG5cdFx0Ly8gY29ybmVyIGNsYXNzZXMgb24gdGhlIHByZXZpb3VzbHkgYWN0aXZlIGhlYWRlciBzdGF5IGFmdGVyIHRoZSBhbmltYXRpb25cblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggYWN0aXZlLCBcInVpLWFjY29yZGlvbi1oZWFkZXItYWN0aXZlXCIsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRpZiAoIG9wdGlvbnMuaWNvbnMgKSB7XG5cdFx0XHRhY3RpdmVDaGlsZHJlbiA9IGFjdGl2ZS5jaGlsZHJlbiggXCIudWktYWNjb3JkaW9uLWhlYWRlci1pY29uXCIgKTtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBhY3RpdmVDaGlsZHJlbiwgbnVsbCwgb3B0aW9ucy5pY29ucy5hY3RpdmVIZWFkZXIgKVxuXHRcdFx0XHQuX2FkZENsYXNzKCBhY3RpdmVDaGlsZHJlbiwgbnVsbCwgb3B0aW9ucy5pY29ucy5oZWFkZXIgKTtcblx0XHR9XG5cblx0XHRpZiAoICFjbGlja2VkSXNBY3RpdmUgKSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggY2xpY2tlZCwgXCJ1aS1hY2NvcmRpb24taGVhZGVyLWNvbGxhcHNlZFwiIClcblx0XHRcdFx0Ll9hZGRDbGFzcyggY2xpY2tlZCwgXCJ1aS1hY2NvcmRpb24taGVhZGVyLWFjdGl2ZVwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHRpZiAoIG9wdGlvbnMuaWNvbnMgKSB7XG5cdFx0XHRcdGNsaWNrZWRDaGlsZHJlbiA9IGNsaWNrZWQuY2hpbGRyZW4oIFwiLnVpLWFjY29yZGlvbi1oZWFkZXItaWNvblwiICk7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBjbGlja2VkQ2hpbGRyZW4sIG51bGwsIG9wdGlvbnMuaWNvbnMuaGVhZGVyIClcblx0XHRcdFx0XHQuX2FkZENsYXNzKCBjbGlja2VkQ2hpbGRyZW4sIG51bGwsIG9wdGlvbnMuaWNvbnMuYWN0aXZlSGVhZGVyICk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2FkZENsYXNzKCBjbGlja2VkLm5leHQoKSwgXCJ1aS1hY2NvcmRpb24tY29udGVudC1hY3RpdmVcIiApO1xuXHRcdH1cblx0fSxcblxuXHRfdG9nZ2xlOiBmdW5jdGlvbiggZGF0YSApIHtcblx0XHR2YXIgdG9TaG93ID0gZGF0YS5uZXdQYW5lbCxcblx0XHRcdHRvSGlkZSA9IHRoaXMucHJldlNob3cubGVuZ3RoID8gdGhpcy5wcmV2U2hvdyA6IGRhdGEub2xkUGFuZWw7XG5cblx0XHQvLyBIYW5kbGUgYWN0aXZhdGluZyBhIHBhbmVsIGR1cmluZyB0aGUgYW5pbWF0aW9uIGZvciBhbm90aGVyIGFjdGl2YXRpb25cblx0XHR0aGlzLnByZXZTaG93LmFkZCggdGhpcy5wcmV2SGlkZSApLnN0b3AoIHRydWUsIHRydWUgKTtcblx0XHR0aGlzLnByZXZTaG93ID0gdG9TaG93O1xuXHRcdHRoaXMucHJldkhpZGUgPSB0b0hpZGU7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5hbmltYXRlICkge1xuXHRcdFx0dGhpcy5fYW5pbWF0ZSggdG9TaG93LCB0b0hpZGUsIGRhdGEgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dG9IaWRlLmhpZGUoKTtcblx0XHRcdHRvU2hvdy5zaG93KCk7XG5cdFx0XHR0aGlzLl90b2dnbGVDb21wbGV0ZSggZGF0YSApO1xuXHRcdH1cblxuXHRcdHRvSGlkZS5hdHRyKCB7XG5cdFx0XHRcImFyaWEtaGlkZGVuXCI6IFwidHJ1ZVwiXG5cdFx0fSApO1xuXHRcdHRvSGlkZS5wcmV2KCkuYXR0cigge1xuXHRcdFx0XCJhcmlhLXNlbGVjdGVkXCI6IFwiZmFsc2VcIixcblx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcImZhbHNlXCJcblx0XHR9ICk7XG5cblx0XHQvLyBpZiB3ZSdyZSBzd2l0Y2hpbmcgcGFuZWxzLCByZW1vdmUgdGhlIG9sZCBoZWFkZXIgZnJvbSB0aGUgdGFiIG9yZGVyXG5cdFx0Ly8gaWYgd2UncmUgb3BlbmluZyBmcm9tIGNvbGxhcHNlZCBzdGF0ZSwgcmVtb3ZlIHRoZSBwcmV2aW91cyBoZWFkZXIgZnJvbSB0aGUgdGFiIG9yZGVyXG5cdFx0Ly8gaWYgd2UncmUgY29sbGFwc2luZywgdGhlbiBrZWVwIHRoZSBjb2xsYXBzaW5nIGhlYWRlciBpbiB0aGUgdGFiIG9yZGVyXG5cdFx0aWYgKCB0b1Nob3cubGVuZ3RoICYmIHRvSGlkZS5sZW5ndGggKSB7XG5cdFx0XHR0b0hpZGUucHJldigpLmF0dHIoIHtcblx0XHRcdFx0XCJ0YWJJbmRleFwiOiAtMSxcblx0XHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwiZmFsc2VcIlxuXHRcdFx0fSApO1xuXHRcdH0gZWxzZSBpZiAoIHRvU2hvdy5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLmhlYWRlcnMuZmlsdGVyKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuIHBhcnNlSW50KCAkKCB0aGlzICkuYXR0ciggXCJ0YWJJbmRleFwiICksIDEwICkgPT09IDA7XG5cdFx0XHR9IClcblx0XHRcdFx0LmF0dHIoIFwidGFiSW5kZXhcIiwgLTEgKTtcblx0XHR9XG5cblx0XHR0b1Nob3dcblx0XHRcdC5hdHRyKCBcImFyaWEtaGlkZGVuXCIsIFwiZmFsc2VcIiApXG5cdFx0XHQucHJldigpXG5cdFx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdFx0XCJhcmlhLXNlbGVjdGVkXCI6IFwidHJ1ZVwiLFxuXHRcdFx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcInRydWVcIixcblx0XHRcdFx0XHR0YWJJbmRleDogMFxuXHRcdFx0XHR9ICk7XG5cdH0sXG5cblx0X2FuaW1hdGU6IGZ1bmN0aW9uKCB0b1Nob3csIHRvSGlkZSwgZGF0YSApIHtcblx0XHR2YXIgdG90YWwsIGVhc2luZywgZHVyYXRpb24sXG5cdFx0XHR0aGF0ID0gdGhpcyxcblx0XHRcdGFkanVzdCA9IDAsXG5cdFx0XHRib3hTaXppbmcgPSB0b1Nob3cuY3NzKCBcImJveC1zaXppbmdcIiApLFxuXHRcdFx0ZG93biA9IHRvU2hvdy5sZW5ndGggJiZcblx0XHRcdFx0KCAhdG9IaWRlLmxlbmd0aCB8fCAoIHRvU2hvdy5pbmRleCgpIDwgdG9IaWRlLmluZGV4KCkgKSApLFxuXHRcdFx0YW5pbWF0ZSA9IHRoaXMub3B0aW9ucy5hbmltYXRlIHx8IHt9LFxuXHRcdFx0b3B0aW9ucyA9IGRvd24gJiYgYW5pbWF0ZS5kb3duIHx8IGFuaW1hdGUsXG5cdFx0XHRjb21wbGV0ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGF0Ll90b2dnbGVDb21wbGV0ZSggZGF0YSApO1xuXHRcdFx0fTtcblxuXHRcdGlmICggdHlwZW9mIG9wdGlvbnMgPT09IFwibnVtYmVyXCIgKSB7XG5cdFx0XHRkdXJhdGlvbiA9IG9wdGlvbnM7XG5cdFx0fVxuXHRcdGlmICggdHlwZW9mIG9wdGlvbnMgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRlYXNpbmcgPSBvcHRpb25zO1xuXHRcdH1cblxuXHRcdC8vIGZhbGwgYmFjayBmcm9tIG9wdGlvbnMgdG8gYW5pbWF0aW9uIGluIGNhc2Ugb2YgcGFydGlhbCBkb3duIHNldHRpbmdzXG5cdFx0ZWFzaW5nID0gZWFzaW5nIHx8IG9wdGlvbnMuZWFzaW5nIHx8IGFuaW1hdGUuZWFzaW5nO1xuXHRcdGR1cmF0aW9uID0gZHVyYXRpb24gfHwgb3B0aW9ucy5kdXJhdGlvbiB8fCBhbmltYXRlLmR1cmF0aW9uO1xuXG5cdFx0aWYgKCAhdG9IaWRlLmxlbmd0aCApIHtcblx0XHRcdHJldHVybiB0b1Nob3cuYW5pbWF0ZSggdGhpcy5zaG93UHJvcHMsIGR1cmF0aW9uLCBlYXNpbmcsIGNvbXBsZXRlICk7XG5cdFx0fVxuXHRcdGlmICggIXRvU2hvdy5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4gdG9IaWRlLmFuaW1hdGUoIHRoaXMuaGlkZVByb3BzLCBkdXJhdGlvbiwgZWFzaW5nLCBjb21wbGV0ZSApO1xuXHRcdH1cblxuXHRcdHRvdGFsID0gdG9TaG93LnNob3coKS5vdXRlckhlaWdodCgpO1xuXHRcdHRvSGlkZS5hbmltYXRlKCB0aGlzLmhpZGVQcm9wcywge1xuXHRcdFx0ZHVyYXRpb246IGR1cmF0aW9uLFxuXHRcdFx0ZWFzaW5nOiBlYXNpbmcsXG5cdFx0XHRzdGVwOiBmdW5jdGlvbiggbm93LCBmeCApIHtcblx0XHRcdFx0Zngubm93ID0gTWF0aC5yb3VuZCggbm93ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdHRvU2hvd1xuXHRcdFx0LmhpZGUoKVxuXHRcdFx0LmFuaW1hdGUoIHRoaXMuc2hvd1Byb3BzLCB7XG5cdFx0XHRcdGR1cmF0aW9uOiBkdXJhdGlvbixcblx0XHRcdFx0ZWFzaW5nOiBlYXNpbmcsXG5cdFx0XHRcdGNvbXBsZXRlOiBjb21wbGV0ZSxcblx0XHRcdFx0c3RlcDogZnVuY3Rpb24oIG5vdywgZnggKSB7XG5cdFx0XHRcdFx0Zngubm93ID0gTWF0aC5yb3VuZCggbm93ICk7XG5cdFx0XHRcdFx0aWYgKCBmeC5wcm9wICE9PSBcImhlaWdodFwiICkge1xuXHRcdFx0XHRcdFx0aWYgKCBib3hTaXppbmcgPT09IFwiY29udGVudC1ib3hcIiApIHtcblx0XHRcdFx0XHRcdFx0YWRqdXN0ICs9IGZ4Lm5vdztcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9IGVsc2UgaWYgKCB0aGF0Lm9wdGlvbnMuaGVpZ2h0U3R5bGUgIT09IFwiY29udGVudFwiICkge1xuXHRcdFx0XHRcdFx0Zngubm93ID0gTWF0aC5yb3VuZCggdG90YWwgLSB0b0hpZGUub3V0ZXJIZWlnaHQoKSAtIGFkanVzdCApO1xuXHRcdFx0XHRcdFx0YWRqdXN0ID0gMDtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0fSxcblxuXHRfdG9nZ2xlQ29tcGxldGU6IGZ1bmN0aW9uKCBkYXRhICkge1xuXHRcdHZhciB0b0hpZGUgPSBkYXRhLm9sZFBhbmVsLFxuXHRcdFx0cHJldiA9IHRvSGlkZS5wcmV2KCk7XG5cblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdG9IaWRlLCBcInVpLWFjY29yZGlvbi1jb250ZW50LWFjdGl2ZVwiICk7XG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHByZXYsIFwidWktYWNjb3JkaW9uLWhlYWRlci1hY3RpdmVcIiApXG5cdFx0XHQuX2FkZENsYXNzKCBwcmV2LCBcInVpLWFjY29yZGlvbi1oZWFkZXItY29sbGFwc2VkXCIgKTtcblxuXHRcdC8vIFdvcmsgYXJvdW5kIGZvciByZW5kZXJpbmcgYnVnIGluIElFICgjNTQyMSlcblx0XHRpZiAoIHRvSGlkZS5sZW5ndGggKSB7XG5cdFx0XHR0b0hpZGUucGFyZW50KClbIDAgXS5jbGFzc05hbWUgPSB0b0hpZGUucGFyZW50KClbIDAgXS5jbGFzc05hbWU7XG5cdFx0fVxuXHRcdHRoaXMuX3RyaWdnZXIoIFwiYWN0aXZhdGVcIiwgbnVsbCwgZGF0YSApO1xuXHR9XG59ICk7XG5cblxuXG52YXIgc2FmZUFjdGl2ZUVsZW1lbnQgPSAkLnVpLnNhZmVBY3RpdmVFbGVtZW50ID0gZnVuY3Rpb24oIGRvY3VtZW50ICkge1xuXHR2YXIgYWN0aXZlRWxlbWVudDtcblxuXHQvLyBTdXBwb3J0OiBJRSA5IG9ubHlcblx0Ly8gSUU5IHRocm93cyBhbiBcIlVuc3BlY2lmaWVkIGVycm9yXCIgYWNjZXNzaW5nIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgZnJvbSBhbiA8aWZyYW1lPlxuXHR0cnkge1xuXHRcdGFjdGl2ZUVsZW1lbnQgPSBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuXHR9IGNhdGNoICggZXJyb3IgKSB7XG5cdFx0YWN0aXZlRWxlbWVudCA9IGRvY3VtZW50LmJvZHk7XG5cdH1cblxuXHQvLyBTdXBwb3J0OiBJRSA5IC0gMTEgb25seVxuXHQvLyBJRSBtYXkgcmV0dXJuIG51bGwgaW5zdGVhZCBvZiBhbiBlbGVtZW50XG5cdC8vIEludGVyZXN0aW5nbHksIHRoaXMgb25seSBzZWVtcyB0byBvY2N1ciB3aGVuIE5PVCBpbiBhbiBpZnJhbWVcblx0aWYgKCAhYWN0aXZlRWxlbWVudCApIHtcblx0XHRhY3RpdmVFbGVtZW50ID0gZG9jdW1lbnQuYm9keTtcblx0fVxuXG5cdC8vIFN1cHBvcnQ6IElFIDExIG9ubHlcblx0Ly8gSUUxMSByZXR1cm5zIGEgc2VlbWluZ2x5IGVtcHR5IG9iamVjdCBpbiBzb21lIGNhc2VzIHdoZW4gYWNjZXNzaW5nXG5cdC8vIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgZnJvbSBhbiA8aWZyYW1lPlxuXHRpZiAoICFhY3RpdmVFbGVtZW50Lm5vZGVOYW1lICkge1xuXHRcdGFjdGl2ZUVsZW1lbnQgPSBkb2N1bWVudC5ib2R5O1xuXHR9XG5cblx0cmV0dXJuIGFjdGl2ZUVsZW1lbnQ7XG59O1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIE1lbnUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IE1lbnVcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBDcmVhdGVzIG5lc3RhYmxlIG1lbnVzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL21lbnUvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vbWVudS9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL21lbnUuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbnZhciB3aWRnZXRzTWVudSA9ICQud2lkZ2V0KCBcInVpLm1lbnVcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRkZWZhdWx0RWxlbWVudDogXCI8dWw+XCIsXG5cdGRlbGF5OiAzMDAsXG5cdG9wdGlvbnM6IHtcblx0XHRpY29uczoge1xuXHRcdFx0c3VibWVudTogXCJ1aS1pY29uLWNhcmV0LTEtZVwiXG5cdFx0fSxcblx0XHRpdGVtczogXCI+ICpcIixcblx0XHRtZW51czogXCJ1bFwiLFxuXHRcdHBvc2l0aW9uOiB7XG5cdFx0XHRteTogXCJsZWZ0IHRvcFwiLFxuXHRcdFx0YXQ6IFwicmlnaHQgdG9wXCJcblx0XHR9LFxuXHRcdHJvbGU6IFwibWVudVwiLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0Ymx1cjogbnVsbCxcblx0XHRmb2N1czogbnVsbCxcblx0XHRzZWxlY3Q6IG51bGxcblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmFjdGl2ZU1lbnUgPSB0aGlzLmVsZW1lbnQ7XG5cblx0XHQvLyBGbGFnIHVzZWQgdG8gcHJldmVudCBmaXJpbmcgb2YgdGhlIGNsaWNrIGhhbmRsZXJcblx0XHQvLyBhcyB0aGUgZXZlbnQgYnViYmxlcyB1cCB0aHJvdWdoIG5lc3RlZCBtZW51c1xuXHRcdHRoaXMubW91c2VIYW5kbGVkID0gZmFsc2U7XG5cdFx0dGhpcy5lbGVtZW50XG5cdFx0XHQudW5pcXVlSWQoKVxuXHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0cm9sZTogdGhpcy5vcHRpb25zLnJvbGUsXG5cdFx0XHRcdHRhYkluZGV4OiAwXG5cdFx0XHR9ICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1tZW51XCIsIFwidWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50XCIgKTtcblx0XHR0aGlzLl9vbigge1xuXG5cdFx0XHQvLyBQcmV2ZW50IGZvY3VzIGZyb20gc3RpY2tpbmcgdG8gbGlua3MgaW5zaWRlIG1lbnUgYWZ0ZXIgY2xpY2tpbmdcblx0XHRcdC8vIHRoZW0gKGZvY3VzIHNob3VsZCBhbHdheXMgc3RheSBvbiBVTCBkdXJpbmcgbmF2aWdhdGlvbikuXG5cdFx0XHRcIm1vdXNlZG93biAudWktbWVudS1pdGVtXCI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdH0sXG5cdFx0XHRcImNsaWNrIC51aS1tZW51LWl0ZW1cIjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR2YXIgdGFyZ2V0ID0gJCggZXZlbnQudGFyZ2V0ICk7XG5cdFx0XHRcdHZhciBhY3RpdmUgPSAkKCAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKSApO1xuXHRcdFx0XHRpZiAoICF0aGlzLm1vdXNlSGFuZGxlZCAmJiB0YXJnZXQubm90KCBcIi51aS1zdGF0ZS1kaXNhYmxlZFwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRcdHRoaXMuc2VsZWN0KCBldmVudCApO1xuXG5cdFx0XHRcdFx0Ly8gT25seSBzZXQgdGhlIG1vdXNlSGFuZGxlZCBmbGFnIGlmIHRoZSBldmVudCB3aWxsIGJ1YmJsZSwgc2VlICM5NDY5LlxuXHRcdFx0XHRcdGlmICggIWV2ZW50LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkgKSB7XG5cdFx0XHRcdFx0XHR0aGlzLm1vdXNlSGFuZGxlZCA9IHRydWU7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gT3BlbiBzdWJtZW51IG9uIGNsaWNrXG5cdFx0XHRcdFx0aWYgKCB0YXJnZXQuaGFzKCBcIi51aS1tZW51XCIgKS5sZW5ndGggKSB7XG5cdFx0XHRcdFx0XHR0aGlzLmV4cGFuZCggZXZlbnQgKTtcblx0XHRcdFx0XHR9IGVsc2UgaWYgKCAhdGhpcy5lbGVtZW50LmlzKCBcIjpmb2N1c1wiICkgJiZcblx0XHRcdFx0XHRcdFx0YWN0aXZlLmNsb3Nlc3QoIFwiLnVpLW1lbnVcIiApLmxlbmd0aCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gUmVkaXJlY3QgZm9jdXMgdG8gdGhlIG1lbnVcblx0XHRcdFx0XHRcdHRoaXMuZWxlbWVudC50cmlnZ2VyKCBcImZvY3VzXCIsIFsgdHJ1ZSBdICk7XG5cblx0XHRcdFx0XHRcdC8vIElmIHRoZSBhY3RpdmUgaXRlbSBpcyBvbiB0aGUgdG9wIGxldmVsLCBsZXQgaXQgc3RheSBhY3RpdmUuXG5cdFx0XHRcdFx0XHQvLyBPdGhlcndpc2UsIGJsdXIgdGhlIGFjdGl2ZSBpdGVtIHNpbmNlIGl0IGlzIG5vIGxvbmdlciB2aXNpYmxlLlxuXHRcdFx0XHRcdFx0aWYgKCB0aGlzLmFjdGl2ZSAmJiB0aGlzLmFjdGl2ZS5wYXJlbnRzKCBcIi51aS1tZW51XCIgKS5sZW5ndGggPT09IDEgKSB7XG5cdFx0XHRcdFx0XHRcdGNsZWFyVGltZW91dCggdGhpcy50aW1lciApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdFwibW91c2VlbnRlciAudWktbWVudS1pdGVtXCI6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdFx0XHQvLyBJZ25vcmUgbW91c2UgZXZlbnRzIHdoaWxlIHR5cGVhaGVhZCBpcyBhY3RpdmUsIHNlZSAjMTA0NTguXG5cdFx0XHRcdC8vIFByZXZlbnRzIGZvY3VzaW5nIHRoZSB3cm9uZyBpdGVtIHdoZW4gdHlwZWFoZWFkIGNhdXNlcyBhIHNjcm9sbCB3aGlsZSB0aGUgbW91c2Vcblx0XHRcdFx0Ly8gaXMgb3ZlciBhbiBpdGVtIGluIHRoZSBtZW51XG5cdFx0XHRcdGlmICggdGhpcy5wcmV2aW91c0ZpbHRlciApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblxuXHRcdFx0XHR2YXIgYWN0dWFsVGFyZ2V0ID0gJCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggXCIudWktbWVudS1pdGVtXCIgKSxcblx0XHRcdFx0XHR0YXJnZXQgPSAkKCBldmVudC5jdXJyZW50VGFyZ2V0ICk7XG5cblx0XHRcdFx0Ly8gSWdub3JlIGJ1YmJsZWQgZXZlbnRzIG9uIHBhcmVudCBpdGVtcywgc2VlICMxMTY0MVxuXHRcdFx0XHRpZiAoIGFjdHVhbFRhcmdldFsgMCBdICE9PSB0YXJnZXRbIDAgXSApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBSZW1vdmUgdWktc3RhdGUtYWN0aXZlIGNsYXNzIGZyb20gc2libGluZ3Mgb2YgdGhlIG5ld2x5IGZvY3VzZWQgbWVudSBpdGVtXG5cdFx0XHRcdC8vIHRvIGF2b2lkIGEganVtcCBjYXVzZWQgYnkgYWRqYWNlbnQgZWxlbWVudHMgYm90aCBoYXZpbmcgYSBjbGFzcyB3aXRoIGEgYm9yZGVyXG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0YXJnZXQuc2libGluZ3MoKS5jaGlsZHJlbiggXCIudWktc3RhdGUtYWN0aXZlXCIgKSxcblx0XHRcdFx0XHRudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHRcdHRoaXMuZm9jdXMoIGV2ZW50LCB0YXJnZXQgKTtcblx0XHRcdH0sXG5cdFx0XHRtb3VzZWxlYXZlOiBcImNvbGxhcHNlQWxsXCIsXG5cdFx0XHRcIm1vdXNlbGVhdmUgLnVpLW1lbnVcIjogXCJjb2xsYXBzZUFsbFwiLFxuXHRcdFx0Zm9jdXM6IGZ1bmN0aW9uKCBldmVudCwga2VlcEFjdGl2ZUl0ZW0gKSB7XG5cblx0XHRcdFx0Ly8gSWYgdGhlcmUncyBhbHJlYWR5IGFuIGFjdGl2ZSBpdGVtLCBrZWVwIGl0IGFjdGl2ZVxuXHRcdFx0XHQvLyBJZiBub3QsIGFjdGl2YXRlIHRoZSBmaXJzdCBpdGVtXG5cdFx0XHRcdHZhciBpdGVtID0gdGhpcy5hY3RpdmUgfHwgdGhpcy5lbGVtZW50LmZpbmQoIHRoaXMub3B0aW9ucy5pdGVtcyApLmVxKCAwICk7XG5cblx0XHRcdFx0aWYgKCAha2VlcEFjdGl2ZUl0ZW0gKSB7XG5cdFx0XHRcdFx0dGhpcy5mb2N1cyggZXZlbnQsIGl0ZW0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdGJsdXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHZhciBub3RDb250YWluZWQgPSAhJC5jb250YWlucyhcblx0XHRcdFx0XHRcdHRoaXMuZWxlbWVudFsgMCBdLFxuXHRcdFx0XHRcdFx0JC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdIClcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdGlmICggbm90Q29udGFpbmVkICkge1xuXHRcdFx0XHRcdFx0dGhpcy5jb2xsYXBzZUFsbCggZXZlbnQgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH0sXG5cdFx0XHRrZXlkb3duOiBcIl9rZXlkb3duXCJcblx0XHR9ICk7XG5cblx0XHR0aGlzLnJlZnJlc2goKTtcblxuXHRcdC8vIENsaWNrcyBvdXRzaWRlIG9mIGEgbWVudSBjb2xsYXBzZSBhbnkgb3BlbiBtZW51c1xuXHRcdHRoaXMuX29uKCB0aGlzLmRvY3VtZW50LCB7XG5cdFx0XHRjbGljazogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoIHRoaXMuX2Nsb3NlT25Eb2N1bWVudENsaWNrKCBldmVudCApICkge1xuXHRcdFx0XHRcdHRoaXMuY29sbGFwc2VBbGwoIGV2ZW50ICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBSZXNldCB0aGUgbW91c2VIYW5kbGVkIGZsYWdcblx0XHRcdFx0dGhpcy5tb3VzZUhhbmRsZWQgPSBmYWxzZTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpdGVtcyA9IHRoaXMuZWxlbWVudC5maW5kKCBcIi51aS1tZW51LWl0ZW1cIiApXG5cdFx0XHRcdC5yZW1vdmVBdHRyKCBcInJvbGUgYXJpYS1kaXNhYmxlZFwiICksXG5cdFx0XHRzdWJtZW51cyA9IGl0ZW1zLmNoaWxkcmVuKCBcIi51aS1tZW51LWl0ZW0td3JhcHBlclwiIClcblx0XHRcdFx0LnJlbW92ZVVuaXF1ZUlkKClcblx0XHRcdFx0LnJlbW92ZUF0dHIoIFwidGFiSW5kZXggcm9sZSBhcmlhLWhhc3BvcHVwXCIgKTtcblxuXHRcdC8vIERlc3Ryb3kgKHN1YiltZW51c1xuXHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0LnJlbW92ZUF0dHIoIFwiYXJpYS1hY3RpdmVkZXNjZW5kYW50XCIgKVxuXHRcdFx0LmZpbmQoIFwiLnVpLW1lbnVcIiApLmFkZEJhY2soKVxuXHRcdFx0XHQucmVtb3ZlQXR0ciggXCJyb2xlIGFyaWEtbGFiZWxsZWRieSBhcmlhLWV4cGFuZGVkIGFyaWEtaGlkZGVuIGFyaWEtZGlzYWJsZWQgXCIgK1xuXHRcdFx0XHRcdFwidGFiSW5kZXhcIiApXG5cdFx0XHRcdC5yZW1vdmVVbmlxdWVJZCgpXG5cdFx0XHRcdC5zaG93KCk7XG5cblx0XHRzdWJtZW51cy5jaGlsZHJlbigpLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGVsZW0gPSAkKCB0aGlzICk7XG5cdFx0XHRpZiAoIGVsZW0uZGF0YSggXCJ1aS1tZW51LXN1Ym1lbnUtY2FyZXRcIiApICkge1xuXHRcdFx0XHRlbGVtLnJlbW92ZSgpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfa2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBtYXRjaCwgcHJldiwgY2hhcmFjdGVyLCBza2lwLFxuXHRcdFx0cHJldmVudERlZmF1bHQgPSB0cnVlO1xuXG5cdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRjYXNlICQudWkua2V5Q29kZS5QQUdFX1VQOlxuXHRcdFx0dGhpcy5wcmV2aW91c1BhZ2UoIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5QQUdFX0RPV046XG5cdFx0XHR0aGlzLm5leHRQYWdlKCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuSE9NRTpcblx0XHRcdHRoaXMuX21vdmUoIFwiZmlyc3RcIiwgXCJmaXJzdFwiLCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuRU5EOlxuXHRcdFx0dGhpcy5fbW92ZSggXCJsYXN0XCIsIFwibGFzdFwiLCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuVVA6XG5cdFx0XHR0aGlzLnByZXZpb3VzKCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuRE9XTjpcblx0XHRcdHRoaXMubmV4dCggZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkxFRlQ6XG5cdFx0XHR0aGlzLmNvbGxhcHNlKCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuUklHSFQ6XG5cdFx0XHRpZiAoIHRoaXMuYWN0aXZlICYmICF0aGlzLmFjdGl2ZS5pcyggXCIudWktc3RhdGUtZGlzYWJsZWRcIiApICkge1xuXHRcdFx0XHR0aGlzLmV4cGFuZCggZXZlbnQgKTtcblx0XHRcdH1cblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkVOVEVSOlxuXHRcdGNhc2UgJC51aS5rZXlDb2RlLlNQQUNFOlxuXHRcdFx0dGhpcy5fYWN0aXZhdGUoIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5FU0NBUEU6XG5cdFx0XHR0aGlzLmNvbGxhcHNlKCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0ZGVmYXVsdDpcblx0XHRcdHByZXZlbnREZWZhdWx0ID0gZmFsc2U7XG5cdFx0XHRwcmV2ID0gdGhpcy5wcmV2aW91c0ZpbHRlciB8fCBcIlwiO1xuXHRcdFx0c2tpcCA9IGZhbHNlO1xuXG5cdFx0XHQvLyBTdXBwb3J0IG51bWJlciBwYWQgdmFsdWVzXG5cdFx0XHRjaGFyYWN0ZXIgPSBldmVudC5rZXlDb2RlID49IDk2ICYmIGV2ZW50LmtleUNvZGUgPD0gMTA1ID9cblx0XHRcdFx0KCBldmVudC5rZXlDb2RlIC0gOTYgKS50b1N0cmluZygpIDogU3RyaW5nLmZyb21DaGFyQ29kZSggZXZlbnQua2V5Q29kZSApO1xuXG5cdFx0XHRjbGVhclRpbWVvdXQoIHRoaXMuZmlsdGVyVGltZXIgKTtcblxuXHRcdFx0aWYgKCBjaGFyYWN0ZXIgPT09IHByZXYgKSB7XG5cdFx0XHRcdHNraXAgPSB0cnVlO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y2hhcmFjdGVyID0gcHJldiArIGNoYXJhY3Rlcjtcblx0XHRcdH1cblxuXHRcdFx0bWF0Y2ggPSB0aGlzLl9maWx0ZXJNZW51SXRlbXMoIGNoYXJhY3RlciApO1xuXHRcdFx0bWF0Y2ggPSBza2lwICYmIG1hdGNoLmluZGV4KCB0aGlzLmFjdGl2ZS5uZXh0KCkgKSAhPT0gLTEgP1xuXHRcdFx0XHR0aGlzLmFjdGl2ZS5uZXh0QWxsKCBcIi51aS1tZW51LWl0ZW1cIiApIDpcblx0XHRcdFx0bWF0Y2g7XG5cblx0XHRcdC8vIElmIG5vIG1hdGNoZXMgb24gdGhlIGN1cnJlbnQgZmlsdGVyLCByZXNldCB0byB0aGUgbGFzdCBjaGFyYWN0ZXIgcHJlc3NlZFxuXHRcdFx0Ly8gdG8gbW92ZSBkb3duIHRoZSBtZW51IHRvIHRoZSBmaXJzdCBpdGVtIHRoYXQgc3RhcnRzIHdpdGggdGhhdCBjaGFyYWN0ZXJcblx0XHRcdGlmICggIW1hdGNoLmxlbmd0aCApIHtcblx0XHRcdFx0Y2hhcmFjdGVyID0gU3RyaW5nLmZyb21DaGFyQ29kZSggZXZlbnQua2V5Q29kZSApO1xuXHRcdFx0XHRtYXRjaCA9IHRoaXMuX2ZpbHRlck1lbnVJdGVtcyggY2hhcmFjdGVyICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggbWF0Y2gubGVuZ3RoICkge1xuXHRcdFx0XHR0aGlzLmZvY3VzKCBldmVudCwgbWF0Y2ggKTtcblx0XHRcdFx0dGhpcy5wcmV2aW91c0ZpbHRlciA9IGNoYXJhY3Rlcjtcblx0XHRcdFx0dGhpcy5maWx0ZXJUaW1lciA9IHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRkZWxldGUgdGhpcy5wcmV2aW91c0ZpbHRlcjtcblx0XHRcdFx0fSwgMTAwMCApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0ZGVsZXRlIHRoaXMucHJldmlvdXNGaWx0ZXI7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBwcmV2ZW50RGVmYXVsdCApIHtcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9hY3RpdmF0ZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggdGhpcy5hY3RpdmUgJiYgIXRoaXMuYWN0aXZlLmlzKCBcIi51aS1zdGF0ZS1kaXNhYmxlZFwiICkgKSB7XG5cdFx0XHRpZiAoIHRoaXMuYWN0aXZlLmNoaWxkcmVuKCBcIlthcmlhLWhhc3BvcHVwPSd0cnVlJ11cIiApLmxlbmd0aCApIHtcblx0XHRcdFx0dGhpcy5leHBhbmQoIGV2ZW50ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLnNlbGVjdCggZXZlbnQgKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0cmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG1lbnVzLCBpdGVtcywgbmV3U3VibWVudXMsIG5ld0l0ZW1zLCBuZXdXcmFwcGVycyxcblx0XHRcdHRoYXQgPSB0aGlzLFxuXHRcdFx0aWNvbiA9IHRoaXMub3B0aW9ucy5pY29ucy5zdWJtZW51LFxuXHRcdFx0c3VibWVudXMgPSB0aGlzLmVsZW1lbnQuZmluZCggdGhpcy5vcHRpb25zLm1lbnVzICk7XG5cblx0XHR0aGlzLl90b2dnbGVDbGFzcyggXCJ1aS1tZW51LWljb25zXCIsIG51bGwsICEhdGhpcy5lbGVtZW50LmZpbmQoIFwiLnVpLWljb25cIiApLmxlbmd0aCApO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBuZXN0ZWQgbWVudXNcblx0XHRuZXdTdWJtZW51cyA9IHN1Ym1lbnVzLmZpbHRlciggXCI6bm90KC51aS1tZW51KVwiIClcblx0XHRcdC5oaWRlKClcblx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdHJvbGU6IHRoaXMub3B0aW9ucy5yb2xlLFxuXHRcdFx0XHRcImFyaWEtaGlkZGVuXCI6IFwidHJ1ZVwiLFxuXHRcdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJmYWxzZVwiXG5cdFx0XHR9IClcblx0XHRcdC5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIG1lbnUgPSAkKCB0aGlzICksXG5cdFx0XHRcdFx0aXRlbSA9IG1lbnUucHJldigpLFxuXHRcdFx0XHRcdHN1Ym1lbnVDYXJldCA9ICQoIFwiPHNwYW4+XCIgKS5kYXRhKCBcInVpLW1lbnUtc3VibWVudS1jYXJldFwiLCB0cnVlICk7XG5cblx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIHN1Ym1lbnVDYXJldCwgXCJ1aS1tZW51LWljb25cIiwgXCJ1aS1pY29uIFwiICsgaWNvbiApO1xuXHRcdFx0XHRpdGVtXG5cdFx0XHRcdFx0LmF0dHIoIFwiYXJpYS1oYXNwb3B1cFwiLCBcInRydWVcIiApXG5cdFx0XHRcdFx0LnByZXBlbmQoIHN1Ym1lbnVDYXJldCApO1xuXHRcdFx0XHRtZW51LmF0dHIoIFwiYXJpYS1sYWJlbGxlZGJ5XCIsIGl0ZW0uYXR0ciggXCJpZFwiICkgKTtcblx0XHRcdH0gKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBuZXdTdWJtZW51cywgXCJ1aS1tZW51XCIsIFwidWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50IHVpLWZyb250XCIgKTtcblxuXHRcdG1lbnVzID0gc3VibWVudXMuYWRkKCB0aGlzLmVsZW1lbnQgKTtcblx0XHRpdGVtcyA9IG1lbnVzLmZpbmQoIHRoaXMub3B0aW9ucy5pdGVtcyApO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBtZW51LWl0ZW1zIGNvbnRhaW5pbmcgc3BhY2VzIGFuZC9vciBkYXNoZXMgb25seSBhcyBkaXZpZGVyc1xuXHRcdGl0ZW1zLm5vdCggXCIudWktbWVudS1pdGVtXCIgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBpdGVtID0gJCggdGhpcyApO1xuXHRcdFx0aWYgKCB0aGF0Ll9pc0RpdmlkZXIoIGl0ZW0gKSApIHtcblx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIGl0ZW0sIFwidWktbWVudS1kaXZpZGVyXCIsIFwidWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdC8vIERvbid0IHJlZnJlc2ggbGlzdCBpdGVtcyB0aGF0IGFyZSBhbHJlYWR5IGFkYXB0ZWRcblx0XHRuZXdJdGVtcyA9IGl0ZW1zLm5vdCggXCIudWktbWVudS1pdGVtLCAudWktbWVudS1kaXZpZGVyXCIgKTtcblx0XHRuZXdXcmFwcGVycyA9IG5ld0l0ZW1zLmNoaWxkcmVuKClcblx0XHRcdC5ub3QoIFwiLnVpLW1lbnVcIiApXG5cdFx0XHRcdC51bmlxdWVJZCgpXG5cdFx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdFx0dGFiSW5kZXg6IC0xLFxuXHRcdFx0XHRcdHJvbGU6IHRoaXMuX2l0ZW1Sb2xlKClcblx0XHRcdFx0fSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBuZXdJdGVtcywgXCJ1aS1tZW51LWl0ZW1cIiApXG5cdFx0XHQuX2FkZENsYXNzKCBuZXdXcmFwcGVycywgXCJ1aS1tZW51LWl0ZW0td3JhcHBlclwiICk7XG5cblx0XHQvLyBBZGQgYXJpYS1kaXNhYmxlZCBhdHRyaWJ1dGUgdG8gYW55IGRpc2FibGVkIG1lbnUgaXRlbVxuXHRcdGl0ZW1zLmZpbHRlciggXCIudWktc3RhdGUtZGlzYWJsZWRcIiApLmF0dHIoIFwiYXJpYS1kaXNhYmxlZFwiLCBcInRydWVcIiApO1xuXG5cdFx0Ly8gSWYgdGhlIGFjdGl2ZSBpdGVtIGhhcyBiZWVuIHJlbW92ZWQsIGJsdXIgdGhlIG1lbnVcblx0XHRpZiAoIHRoaXMuYWN0aXZlICYmICEkLmNvbnRhaW5zKCB0aGlzLmVsZW1lbnRbIDAgXSwgdGhpcy5hY3RpdmVbIDAgXSApICkge1xuXHRcdFx0dGhpcy5ibHVyKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9pdGVtUm9sZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdG1lbnU6IFwibWVudWl0ZW1cIixcblx0XHRcdGxpc3Rib3g6IFwib3B0aW9uXCJcblx0XHR9WyB0aGlzLm9wdGlvbnMucm9sZSBdO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdGlmICgga2V5ID09PSBcImljb25zXCIgKSB7XG5cdFx0XHR2YXIgaWNvbnMgPSB0aGlzLmVsZW1lbnQuZmluZCggXCIudWktbWVudS1pY29uXCIgKTtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBpY29ucywgbnVsbCwgdGhpcy5vcHRpb25zLmljb25zLnN1Ym1lbnUgKVxuXHRcdFx0XHQuX2FkZENsYXNzKCBpY29ucywgbnVsbCwgdmFsdWUuc3VibWVudSApO1xuXHRcdH1cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb25EaXNhYmxlZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCB2YWx1ZSApO1xuXG5cdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwiYXJpYS1kaXNhYmxlZFwiLCBTdHJpbmcoIHZhbHVlICkgKTtcblx0XHR0aGlzLl90b2dnbGVDbGFzcyggbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiLCAhIXZhbHVlICk7XG5cdH0sXG5cblx0Zm9jdXM6IGZ1bmN0aW9uKCBldmVudCwgaXRlbSApIHtcblx0XHR2YXIgbmVzdGVkLCBmb2N1c2VkLCBhY3RpdmVQYXJlbnQ7XG5cdFx0dGhpcy5ibHVyKCBldmVudCwgZXZlbnQgJiYgZXZlbnQudHlwZSA9PT0gXCJmb2N1c1wiICk7XG5cblx0XHR0aGlzLl9zY3JvbGxJbnRvVmlldyggaXRlbSApO1xuXG5cdFx0dGhpcy5hY3RpdmUgPSBpdGVtLmZpcnN0KCk7XG5cblx0XHRmb2N1c2VkID0gdGhpcy5hY3RpdmUuY2hpbGRyZW4oIFwiLnVpLW1lbnUtaXRlbS13cmFwcGVyXCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggZm9jdXNlZCwgbnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXG5cdFx0Ly8gT25seSB1cGRhdGUgYXJpYS1hY3RpdmVkZXNjZW5kYW50IGlmIHRoZXJlJ3MgYSByb2xlXG5cdFx0Ly8gb3RoZXJ3aXNlIHdlIGFzc3VtZSBmb2N1cyBpcyBtYW5hZ2VkIGVsc2V3aGVyZVxuXHRcdGlmICggdGhpcy5vcHRpb25zLnJvbGUgKSB7XG5cdFx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJhcmlhLWFjdGl2ZWRlc2NlbmRhbnRcIiwgZm9jdXNlZC5hdHRyKCBcImlkXCIgKSApO1xuXHRcdH1cblxuXHRcdC8vIEhpZ2hsaWdodCBhY3RpdmUgcGFyZW50IG1lbnUgaXRlbSwgaWYgYW55XG5cdFx0YWN0aXZlUGFyZW50ID0gdGhpcy5hY3RpdmVcblx0XHRcdC5wYXJlbnQoKVxuXHRcdFx0XHQuY2xvc2VzdCggXCIudWktbWVudS1pdGVtXCIgKVxuXHRcdFx0XHRcdC5jaGlsZHJlbiggXCIudWktbWVudS1pdGVtLXdyYXBwZXJcIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBhY3RpdmVQYXJlbnQsIG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblxuXHRcdGlmICggZXZlbnQgJiYgZXZlbnQudHlwZSA9PT0gXCJrZXlkb3duXCIgKSB7XG5cdFx0XHR0aGlzLl9jbG9zZSgpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLnRpbWVyID0gdGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLl9jbG9zZSgpO1xuXHRcdFx0fSwgdGhpcy5kZWxheSApO1xuXHRcdH1cblxuXHRcdG5lc3RlZCA9IGl0ZW0uY2hpbGRyZW4oIFwiLnVpLW1lbnVcIiApO1xuXHRcdGlmICggbmVzdGVkLmxlbmd0aCAmJiBldmVudCAmJiAoIC9ebW91c2UvLnRlc3QoIGV2ZW50LnR5cGUgKSApICkge1xuXHRcdFx0dGhpcy5fc3RhcnRPcGVuaW5nKCBuZXN0ZWQgKTtcblx0XHR9XG5cdFx0dGhpcy5hY3RpdmVNZW51ID0gaXRlbS5wYXJlbnQoKTtcblxuXHRcdHRoaXMuX3RyaWdnZXIoIFwiZm9jdXNcIiwgZXZlbnQsIHsgaXRlbTogaXRlbSB9ICk7XG5cdH0sXG5cblx0X3Njcm9sbEludG9WaWV3OiBmdW5jdGlvbiggaXRlbSApIHtcblx0XHR2YXIgYm9yZGVyVG9wLCBwYWRkaW5nVG9wLCBvZmZzZXQsIHNjcm9sbCwgZWxlbWVudEhlaWdodCwgaXRlbUhlaWdodDtcblx0XHRpZiAoIHRoaXMuX2hhc1Njcm9sbCgpICkge1xuXHRcdFx0Ym9yZGVyVG9wID0gcGFyc2VGbG9hdCggJC5jc3MoIHRoaXMuYWN0aXZlTWVudVsgMCBdLCBcImJvcmRlclRvcFdpZHRoXCIgKSApIHx8IDA7XG5cdFx0XHRwYWRkaW5nVG9wID0gcGFyc2VGbG9hdCggJC5jc3MoIHRoaXMuYWN0aXZlTWVudVsgMCBdLCBcInBhZGRpbmdUb3BcIiApICkgfHwgMDtcblx0XHRcdG9mZnNldCA9IGl0ZW0ub2Zmc2V0KCkudG9wIC0gdGhpcy5hY3RpdmVNZW51Lm9mZnNldCgpLnRvcCAtIGJvcmRlclRvcCAtIHBhZGRpbmdUb3A7XG5cdFx0XHRzY3JvbGwgPSB0aGlzLmFjdGl2ZU1lbnUuc2Nyb2xsVG9wKCk7XG5cdFx0XHRlbGVtZW50SGVpZ2h0ID0gdGhpcy5hY3RpdmVNZW51LmhlaWdodCgpO1xuXHRcdFx0aXRlbUhlaWdodCA9IGl0ZW0ub3V0ZXJIZWlnaHQoKTtcblxuXHRcdFx0aWYgKCBvZmZzZXQgPCAwICkge1xuXHRcdFx0XHR0aGlzLmFjdGl2ZU1lbnUuc2Nyb2xsVG9wKCBzY3JvbGwgKyBvZmZzZXQgKTtcblx0XHRcdH0gZWxzZSBpZiAoIG9mZnNldCArIGl0ZW1IZWlnaHQgPiBlbGVtZW50SGVpZ2h0ICkge1xuXHRcdFx0XHR0aGlzLmFjdGl2ZU1lbnUuc2Nyb2xsVG9wKCBzY3JvbGwgKyBvZmZzZXQgLSBlbGVtZW50SGVpZ2h0ICsgaXRlbUhlaWdodCApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRibHVyOiBmdW5jdGlvbiggZXZlbnQsIGZyb21Gb2N1cyApIHtcblx0XHRpZiAoICFmcm9tRm9jdXMgKSB7XG5cdFx0XHRjbGVhclRpbWVvdXQoIHRoaXMudGltZXIgKTtcblx0XHR9XG5cblx0XHRpZiAoICF0aGlzLmFjdGl2ZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5hY3RpdmUuY2hpbGRyZW4oIFwiLnVpLW1lbnUtaXRlbS13cmFwcGVyXCIgKSxcblx0XHRcdG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblxuXHRcdHRoaXMuX3RyaWdnZXIoIFwiYmx1clwiLCBldmVudCwgeyBpdGVtOiB0aGlzLmFjdGl2ZSB9ICk7XG5cdFx0dGhpcy5hY3RpdmUgPSBudWxsO1xuXHR9LFxuXG5cdF9zdGFydE9wZW5pbmc6IGZ1bmN0aW9uKCBzdWJtZW51ICkge1xuXHRcdGNsZWFyVGltZW91dCggdGhpcy50aW1lciApO1xuXG5cdFx0Ly8gRG9uJ3Qgb3BlbiBpZiBhbHJlYWR5IG9wZW4gZml4ZXMgYSBGaXJlZm94IGJ1ZyB0aGF0IGNhdXNlZCBhIC41IHBpeGVsXG5cdFx0Ly8gc2hpZnQgaW4gdGhlIHN1Ym1lbnUgcG9zaXRpb24gd2hlbiBtb3VzaW5nIG92ZXIgdGhlIGNhcmV0IGljb25cblx0XHRpZiAoIHN1Ym1lbnUuYXR0ciggXCJhcmlhLWhpZGRlblwiICkgIT09IFwidHJ1ZVwiICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMudGltZXIgPSB0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLl9jbG9zZSgpO1xuXHRcdFx0dGhpcy5fb3Blbiggc3VibWVudSApO1xuXHRcdH0sIHRoaXMuZGVsYXkgKTtcblx0fSxcblxuXHRfb3BlbjogZnVuY3Rpb24oIHN1Ym1lbnUgKSB7XG5cdFx0dmFyIHBvc2l0aW9uID0gJC5leHRlbmQoIHtcblx0XHRcdG9mOiB0aGlzLmFjdGl2ZVxuXHRcdH0sIHRoaXMub3B0aW9ucy5wb3NpdGlvbiApO1xuXG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnRpbWVyICk7XG5cdFx0dGhpcy5lbGVtZW50LmZpbmQoIFwiLnVpLW1lbnVcIiApLm5vdCggc3VibWVudS5wYXJlbnRzKCBcIi51aS1tZW51XCIgKSApXG5cdFx0XHQuaGlkZSgpXG5cdFx0XHQuYXR0ciggXCJhcmlhLWhpZGRlblwiLCBcInRydWVcIiApO1xuXG5cdFx0c3VibWVudVxuXHRcdFx0LnNob3coKVxuXHRcdFx0LnJlbW92ZUF0dHIoIFwiYXJpYS1oaWRkZW5cIiApXG5cdFx0XHQuYXR0ciggXCJhcmlhLWV4cGFuZGVkXCIsIFwidHJ1ZVwiIClcblx0XHRcdC5wb3NpdGlvbiggcG9zaXRpb24gKTtcblx0fSxcblxuXHRjb2xsYXBzZUFsbDogZnVuY3Rpb24oIGV2ZW50LCBhbGwgKSB7XG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnRpbWVyICk7XG5cdFx0dGhpcy50aW1lciA9IHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblxuXHRcdFx0Ly8gSWYgd2Ugd2VyZSBwYXNzZWQgYW4gZXZlbnQsIGxvb2sgZm9yIHRoZSBzdWJtZW51IHRoYXQgY29udGFpbnMgdGhlIGV2ZW50XG5cdFx0XHR2YXIgY3VycmVudE1lbnUgPSBhbGwgPyB0aGlzLmVsZW1lbnQgOlxuXHRcdFx0XHQkKCBldmVudCAmJiBldmVudC50YXJnZXQgKS5jbG9zZXN0KCB0aGlzLmVsZW1lbnQuZmluZCggXCIudWktbWVudVwiICkgKTtcblxuXHRcdFx0Ly8gSWYgd2UgZm91bmQgbm8gdmFsaWQgc3VibWVudSBhbmNlc3RvciwgdXNlIHRoZSBtYWluIG1lbnUgdG8gY2xvc2UgYWxsXG5cdFx0XHQvLyBzdWIgbWVudXMgYW55d2F5XG5cdFx0XHRpZiAoICFjdXJyZW50TWVudS5sZW5ndGggKSB7XG5cdFx0XHRcdGN1cnJlbnRNZW51ID0gdGhpcy5lbGVtZW50O1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl9jbG9zZSggY3VycmVudE1lbnUgKTtcblxuXHRcdFx0dGhpcy5ibHVyKCBldmVudCApO1xuXG5cdFx0XHQvLyBXb3JrIGFyb3VuZCBhY3RpdmUgaXRlbSBzdGF5aW5nIGFjdGl2ZSBhZnRlciBtZW51IGlzIGJsdXJyZWRcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBjdXJyZW50TWVudS5maW5kKCBcIi51aS1zdGF0ZS1hY3RpdmVcIiApLCBudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cblx0XHRcdHRoaXMuYWN0aXZlTWVudSA9IGN1cnJlbnRNZW51O1xuXHRcdH0sIHRoaXMuZGVsYXkgKTtcblx0fSxcblxuXHQvLyBXaXRoIG5vIGFyZ3VtZW50cywgY2xvc2VzIHRoZSBjdXJyZW50bHkgYWN0aXZlIG1lbnUgLSBpZiBub3RoaW5nIGlzIGFjdGl2ZVxuXHQvLyBpdCBjbG9zZXMgYWxsIG1lbnVzLiAgSWYgcGFzc2VkIGFuIGFyZ3VtZW50LCBpdCB3aWxsIHNlYXJjaCBmb3IgbWVudXMgQkVMT1dcblx0X2Nsb3NlOiBmdW5jdGlvbiggc3RhcnRNZW51ICkge1xuXHRcdGlmICggIXN0YXJ0TWVudSApIHtcblx0XHRcdHN0YXJ0TWVudSA9IHRoaXMuYWN0aXZlID8gdGhpcy5hY3RpdmUucGFyZW50KCkgOiB0aGlzLmVsZW1lbnQ7XG5cdFx0fVxuXG5cdFx0c3RhcnRNZW51LmZpbmQoIFwiLnVpLW1lbnVcIiApXG5cdFx0XHQuaGlkZSgpXG5cdFx0XHQuYXR0ciggXCJhcmlhLWhpZGRlblwiLCBcInRydWVcIiApXG5cdFx0XHQuYXR0ciggXCJhcmlhLWV4cGFuZGVkXCIsIFwiZmFsc2VcIiApO1xuXHR9LFxuXG5cdF9jbG9zZU9uRG9jdW1lbnRDbGljazogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHJldHVybiAhJCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggXCIudWktbWVudVwiICkubGVuZ3RoO1xuXHR9LFxuXG5cdF9pc0RpdmlkZXI6IGZ1bmN0aW9uKCBpdGVtICkge1xuXG5cdFx0Ly8gTWF0Y2ggaHlwaGVuLCBlbSBkYXNoLCBlbiBkYXNoXG5cdFx0cmV0dXJuICEvW15cXC1cXHUyMDE0XFx1MjAxM1xcc10vLnRlc3QoIGl0ZW0udGV4dCgpICk7XG5cdH0sXG5cblx0Y29sbGFwc2U6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgbmV3SXRlbSA9IHRoaXMuYWN0aXZlICYmXG5cdFx0XHR0aGlzLmFjdGl2ZS5wYXJlbnQoKS5jbG9zZXN0KCBcIi51aS1tZW51LWl0ZW1cIiwgdGhpcy5lbGVtZW50ICk7XG5cdFx0aWYgKCBuZXdJdGVtICYmIG5ld0l0ZW0ubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5fY2xvc2UoKTtcblx0XHRcdHRoaXMuZm9jdXMoIGV2ZW50LCBuZXdJdGVtICk7XG5cdFx0fVxuXHR9LFxuXG5cdGV4cGFuZDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBuZXdJdGVtID0gdGhpcy5hY3RpdmUgJiZcblx0XHRcdHRoaXMuYWN0aXZlXG5cdFx0XHRcdC5jaGlsZHJlbiggXCIudWktbWVudSBcIiApXG5cdFx0XHRcdFx0LmZpbmQoIHRoaXMub3B0aW9ucy5pdGVtcyApXG5cdFx0XHRcdFx0XHQuZmlyc3QoKTtcblxuXHRcdGlmICggbmV3SXRlbSAmJiBuZXdJdGVtLmxlbmd0aCApIHtcblx0XHRcdHRoaXMuX29wZW4oIG5ld0l0ZW0ucGFyZW50KCkgKTtcblxuXHRcdFx0Ly8gRGVsYXkgc28gRmlyZWZveCB3aWxsIG5vdCBoaWRlIGFjdGl2ZWRlc2NlbmRhbnQgY2hhbmdlIGluIGV4cGFuZGluZyBzdWJtZW51IGZyb20gQVRcblx0XHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5mb2N1cyggZXZlbnQsIG5ld0l0ZW0gKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cdH0sXG5cblx0bmV4dDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHRoaXMuX21vdmUoIFwibmV4dFwiLCBcImZpcnN0XCIsIGV2ZW50ICk7XG5cdH0sXG5cblx0cHJldmlvdXM6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR0aGlzLl9tb3ZlKCBcInByZXZcIiwgXCJsYXN0XCIsIGV2ZW50ICk7XG5cdH0sXG5cblx0aXNGaXJzdEl0ZW06IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmFjdGl2ZSAmJiAhdGhpcy5hY3RpdmUucHJldkFsbCggXCIudWktbWVudS1pdGVtXCIgKS5sZW5ndGg7XG5cdH0sXG5cblx0aXNMYXN0SXRlbTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuYWN0aXZlICYmICF0aGlzLmFjdGl2ZS5uZXh0QWxsKCBcIi51aS1tZW51LWl0ZW1cIiApLmxlbmd0aDtcblx0fSxcblxuXHRfbW92ZTogZnVuY3Rpb24oIGRpcmVjdGlvbiwgZmlsdGVyLCBldmVudCApIHtcblx0XHR2YXIgbmV4dDtcblx0XHRpZiAoIHRoaXMuYWN0aXZlICkge1xuXHRcdFx0aWYgKCBkaXJlY3Rpb24gPT09IFwiZmlyc3RcIiB8fCBkaXJlY3Rpb24gPT09IFwibGFzdFwiICkge1xuXHRcdFx0XHRuZXh0ID0gdGhpcy5hY3RpdmVcblx0XHRcdFx0XHRbIGRpcmVjdGlvbiA9PT0gXCJmaXJzdFwiID8gXCJwcmV2QWxsXCIgOiBcIm5leHRBbGxcIiBdKCBcIi51aS1tZW51LWl0ZW1cIiApXG5cdFx0XHRcdFx0LmVxKCAtMSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0bmV4dCA9IHRoaXMuYWN0aXZlXG5cdFx0XHRcdFx0WyBkaXJlY3Rpb24gKyBcIkFsbFwiIF0oIFwiLnVpLW1lbnUtaXRlbVwiIClcblx0XHRcdFx0XHQuZXEoIDAgKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0aWYgKCAhbmV4dCB8fCAhbmV4dC5sZW5ndGggfHwgIXRoaXMuYWN0aXZlICkge1xuXHRcdFx0bmV4dCA9IHRoaXMuYWN0aXZlTWVudS5maW5kKCB0aGlzLm9wdGlvbnMuaXRlbXMgKVsgZmlsdGVyIF0oKTtcblx0XHR9XG5cblx0XHR0aGlzLmZvY3VzKCBldmVudCwgbmV4dCApO1xuXHR9LFxuXG5cdG5leHRQYWdlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGl0ZW0sIGJhc2UsIGhlaWdodDtcblxuXHRcdGlmICggIXRoaXMuYWN0aXZlICkge1xuXHRcdFx0dGhpcy5uZXh0KCBldmVudCApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuaXNMYXN0SXRlbSgpICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuX2hhc1Njcm9sbCgpICkge1xuXHRcdFx0YmFzZSA9IHRoaXMuYWN0aXZlLm9mZnNldCgpLnRvcDtcblx0XHRcdGhlaWdodCA9IHRoaXMuZWxlbWVudC5oZWlnaHQoKTtcblx0XHRcdHRoaXMuYWN0aXZlLm5leHRBbGwoIFwiLnVpLW1lbnUtaXRlbVwiICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGl0ZW0gPSAkKCB0aGlzICk7XG5cdFx0XHRcdHJldHVybiBpdGVtLm9mZnNldCgpLnRvcCAtIGJhc2UgLSBoZWlnaHQgPCAwO1xuXHRcdFx0fSApO1xuXG5cdFx0XHR0aGlzLmZvY3VzKCBldmVudCwgaXRlbSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmZvY3VzKCBldmVudCwgdGhpcy5hY3RpdmVNZW51LmZpbmQoIHRoaXMub3B0aW9ucy5pdGVtcyApXG5cdFx0XHRcdFsgIXRoaXMuYWN0aXZlID8gXCJmaXJzdFwiIDogXCJsYXN0XCIgXSgpICk7XG5cdFx0fVxuXHR9LFxuXG5cdHByZXZpb3VzUGFnZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBpdGVtLCBiYXNlLCBoZWlnaHQ7XG5cdFx0aWYgKCAhdGhpcy5hY3RpdmUgKSB7XG5cdFx0XHR0aGlzLm5leHQoIGV2ZW50ICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmICggdGhpcy5pc0ZpcnN0SXRlbSgpICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuX2hhc1Njcm9sbCgpICkge1xuXHRcdFx0YmFzZSA9IHRoaXMuYWN0aXZlLm9mZnNldCgpLnRvcDtcblx0XHRcdGhlaWdodCA9IHRoaXMuZWxlbWVudC5oZWlnaHQoKTtcblx0XHRcdHRoaXMuYWN0aXZlLnByZXZBbGwoIFwiLnVpLW1lbnUtaXRlbVwiICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGl0ZW0gPSAkKCB0aGlzICk7XG5cdFx0XHRcdHJldHVybiBpdGVtLm9mZnNldCgpLnRvcCAtIGJhc2UgKyBoZWlnaHQgPiAwO1xuXHRcdFx0fSApO1xuXG5cdFx0XHR0aGlzLmZvY3VzKCBldmVudCwgaXRlbSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmZvY3VzKCBldmVudCwgdGhpcy5hY3RpdmVNZW51LmZpbmQoIHRoaXMub3B0aW9ucy5pdGVtcyApLmZpcnN0KCkgKTtcblx0XHR9XG5cdH0sXG5cblx0X2hhc1Njcm9sbDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZWxlbWVudC5vdXRlckhlaWdodCgpIDwgdGhpcy5lbGVtZW50LnByb3AoIFwic2Nyb2xsSGVpZ2h0XCIgKTtcblx0fSxcblxuXHRzZWxlY3Q6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdC8vIFRPRE86IEl0IHNob3VsZCBuZXZlciBiZSBwb3NzaWJsZSB0byBub3QgaGF2ZSBhbiBhY3RpdmUgaXRlbSBhdCB0aGlzXG5cdFx0Ly8gcG9pbnQsIGJ1dCB0aGUgdGVzdHMgZG9uJ3QgdHJpZ2dlciBtb3VzZWVudGVyIGJlZm9yZSBjbGljay5cblx0XHR0aGlzLmFjdGl2ZSA9IHRoaXMuYWN0aXZlIHx8ICQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIFwiLnVpLW1lbnUtaXRlbVwiICk7XG5cdFx0dmFyIHVpID0geyBpdGVtOiB0aGlzLmFjdGl2ZSB9O1xuXHRcdGlmICggIXRoaXMuYWN0aXZlLmhhcyggXCIudWktbWVudVwiICkubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5jb2xsYXBzZUFsbCggZXZlbnQsIHRydWUgKTtcblx0XHR9XG5cdFx0dGhpcy5fdHJpZ2dlciggXCJzZWxlY3RcIiwgZXZlbnQsIHVpICk7XG5cdH0sXG5cblx0X2ZpbHRlck1lbnVJdGVtczogZnVuY3Rpb24oIGNoYXJhY3RlciApIHtcblx0XHR2YXIgZXNjYXBlZENoYXJhY3RlciA9IGNoYXJhY3Rlci5yZXBsYWNlKCAvW1xcLVxcW1xcXXt9KCkqKz8uLFxcXFxcXF4kfCNcXHNdL2csIFwiXFxcXCQmXCIgKSxcblx0XHRcdHJlZ2V4ID0gbmV3IFJlZ0V4cCggXCJeXCIgKyBlc2NhcGVkQ2hhcmFjdGVyLCBcImlcIiApO1xuXG5cdFx0cmV0dXJuIHRoaXMuYWN0aXZlTWVudVxuXHRcdFx0LmZpbmQoIHRoaXMub3B0aW9ucy5pdGVtcyApXG5cblx0XHRcdFx0Ly8gT25seSBtYXRjaCBvbiBpdGVtcywgbm90IGRpdmlkZXJzIG9yIG90aGVyIGNvbnRlbnQgKCMxMDU3MSlcblx0XHRcdFx0LmZpbHRlciggXCIudWktbWVudS1pdGVtXCIgKVxuXHRcdFx0XHRcdC5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHJlZ2V4LnRlc3QoXG5cdFx0XHRcdFx0XHRcdCQudHJpbSggJCggdGhpcyApLmNoaWxkcmVuKCBcIi51aS1tZW51LWl0ZW0td3JhcHBlclwiICkudGV4dCgpICkgKTtcblx0XHRcdFx0XHR9ICk7XG5cdH1cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBBdXRvY29tcGxldGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEF1dG9jb21wbGV0ZVxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IExpc3RzIHN1Z2dlc3RlZCB3b3JkcyBhcyB0aGUgdXNlciBpcyB0eXBpbmcuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vYXV0b2NvbXBsZXRlL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2F1dG9jb21wbGV0ZS9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2F1dG9jb21wbGV0ZS5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxuJC53aWRnZXQoIFwidWkuYXV0b2NvbXBsZXRlXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0ZGVmYXVsdEVsZW1lbnQ6IFwiPGlucHV0PlwiLFxuXHRvcHRpb25zOiB7XG5cdFx0YXBwZW5kVG86IG51bGwsXG5cdFx0YXV0b0ZvY3VzOiBmYWxzZSxcblx0XHRkZWxheTogMzAwLFxuXHRcdG1pbkxlbmd0aDogMSxcblx0XHRwb3NpdGlvbjoge1xuXHRcdFx0bXk6IFwibGVmdCB0b3BcIixcblx0XHRcdGF0OiBcImxlZnQgYm90dG9tXCIsXG5cdFx0XHRjb2xsaXNpb246IFwibm9uZVwiXG5cdFx0fSxcblx0XHRzb3VyY2U6IG51bGwsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRjaGFuZ2U6IG51bGwsXG5cdFx0Y2xvc2U6IG51bGwsXG5cdFx0Zm9jdXM6IG51bGwsXG5cdFx0b3BlbjogbnVsbCxcblx0XHRyZXNwb25zZTogbnVsbCxcblx0XHRzZWFyY2g6IG51bGwsXG5cdFx0c2VsZWN0OiBudWxsXG5cdH0sXG5cblx0cmVxdWVzdEluZGV4OiAwLFxuXHRwZW5kaW5nOiAwLFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly8gU29tZSBicm93c2VycyBvbmx5IHJlcGVhdCBrZXlkb3duIGV2ZW50cywgbm90IGtleXByZXNzIGV2ZW50cyxcblx0XHQvLyBzbyB3ZSB1c2UgdGhlIHN1cHByZXNzS2V5UHJlc3MgZmxhZyB0byBkZXRlcm1pbmUgaWYgd2UndmUgYWxyZWFkeVxuXHRcdC8vIGhhbmRsZWQgdGhlIGtleWRvd24gZXZlbnQuICM3MjY5XG5cdFx0Ly8gVW5mb3J0dW5hdGVseSB0aGUgY29kZSBmb3IgJiBpbiBrZXlwcmVzcyBpcyB0aGUgc2FtZSBhcyB0aGUgdXAgYXJyb3csXG5cdFx0Ly8gc28gd2UgdXNlIHRoZSBzdXBwcmVzc0tleVByZXNzUmVwZWF0IGZsYWcgdG8gYXZvaWQgaGFuZGxpbmcga2V5cHJlc3Ncblx0XHQvLyBldmVudHMgd2hlbiB3ZSBrbm93IHRoZSBrZXlkb3duIGV2ZW50IHdhcyB1c2VkIHRvIG1vZGlmeSB0aGVcblx0XHQvLyBzZWFyY2ggdGVybS4gIzc3OTlcblx0XHR2YXIgc3VwcHJlc3NLZXlQcmVzcywgc3VwcHJlc3NLZXlQcmVzc1JlcGVhdCwgc3VwcHJlc3NJbnB1dCxcblx0XHRcdG5vZGVOYW1lID0gdGhpcy5lbGVtZW50WyAwIF0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSxcblx0XHRcdGlzVGV4dGFyZWEgPSBub2RlTmFtZSA9PT0gXCJ0ZXh0YXJlYVwiLFxuXHRcdFx0aXNJbnB1dCA9IG5vZGVOYW1lID09PSBcImlucHV0XCI7XG5cblx0XHQvLyBUZXh0YXJlYXMgYXJlIGFsd2F5cyBtdWx0aS1saW5lXG5cdFx0Ly8gSW5wdXRzIGFyZSBhbHdheXMgc2luZ2xlLWxpbmUsIGV2ZW4gaWYgaW5zaWRlIGEgY29udGVudEVkaXRhYmxlIGVsZW1lbnRcblx0XHQvLyBJRSBhbHNvIHRyZWF0cyBpbnB1dHMgYXMgY29udGVudEVkaXRhYmxlXG5cdFx0Ly8gQWxsIG90aGVyIGVsZW1lbnQgdHlwZXMgYXJlIGRldGVybWluZWQgYnkgd2hldGhlciBvciBub3QgdGhleSdyZSBjb250ZW50RWRpdGFibGVcblx0XHR0aGlzLmlzTXVsdGlMaW5lID0gaXNUZXh0YXJlYSB8fCAhaXNJbnB1dCAmJiB0aGlzLl9pc0NvbnRlbnRFZGl0YWJsZSggdGhpcy5lbGVtZW50ICk7XG5cblx0XHR0aGlzLnZhbHVlTWV0aG9kID0gdGhpcy5lbGVtZW50WyBpc1RleHRhcmVhIHx8IGlzSW5wdXQgPyBcInZhbFwiIDogXCJ0ZXh0XCIgXTtcblx0XHR0aGlzLmlzTmV3TWVudSA9IHRydWU7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1hdXRvY29tcGxldGUtaW5wdXRcIiApO1xuXHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcImF1dG9jb21wbGV0ZVwiLCBcIm9mZlwiICk7XG5cblx0XHR0aGlzLl9vbiggdGhpcy5lbGVtZW50LCB7XG5cdFx0XHRrZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5lbGVtZW50LnByb3AoIFwicmVhZE9ubHlcIiApICkge1xuXHRcdFx0XHRcdHN1cHByZXNzS2V5UHJlc3MgPSB0cnVlO1xuXHRcdFx0XHRcdHN1cHByZXNzSW5wdXQgPSB0cnVlO1xuXHRcdFx0XHRcdHN1cHByZXNzS2V5UHJlc3NSZXBlYXQgPSB0cnVlO1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHN1cHByZXNzS2V5UHJlc3MgPSBmYWxzZTtcblx0XHRcdFx0c3VwcHJlc3NJbnB1dCA9IGZhbHNlO1xuXHRcdFx0XHRzdXBwcmVzc0tleVByZXNzUmVwZWF0ID0gZmFsc2U7XG5cdFx0XHRcdHZhciBrZXlDb2RlID0gJC51aS5rZXlDb2RlO1xuXHRcdFx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuUEFHRV9VUDpcblx0XHRcdFx0XHRzdXBwcmVzc0tleVByZXNzID0gdHJ1ZTtcblx0XHRcdFx0XHR0aGlzLl9tb3ZlKCBcInByZXZpb3VzUGFnZVwiLCBldmVudCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuUEFHRV9ET1dOOlxuXHRcdFx0XHRcdHN1cHByZXNzS2V5UHJlc3MgPSB0cnVlO1xuXHRcdFx0XHRcdHRoaXMuX21vdmUoIFwibmV4dFBhZ2VcIiwgZXZlbnQgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLlVQOlxuXHRcdFx0XHRcdHN1cHByZXNzS2V5UHJlc3MgPSB0cnVlO1xuXHRcdFx0XHRcdHRoaXMuX2tleUV2ZW50KCBcInByZXZpb3VzXCIsIGV2ZW50ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5ET1dOOlxuXHRcdFx0XHRcdHN1cHByZXNzS2V5UHJlc3MgPSB0cnVlO1xuXHRcdFx0XHRcdHRoaXMuX2tleUV2ZW50KCBcIm5leHRcIiwgZXZlbnQgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLkVOVEVSOlxuXG5cdFx0XHRcdFx0Ly8gd2hlbiBtZW51IGlzIG9wZW4gYW5kIGhhcyBmb2N1c1xuXHRcdFx0XHRcdGlmICggdGhpcy5tZW51LmFjdGl2ZSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gIzYwNTUgLSBPcGVyYSBzdGlsbCBhbGxvd3MgdGhlIGtleXByZXNzIHRvIG9jY3VyXG5cdFx0XHRcdFx0XHQvLyB3aGljaCBjYXVzZXMgZm9ybXMgdG8gc3VibWl0XG5cdFx0XHRcdFx0XHRzdXBwcmVzc0tleVByZXNzID0gdHJ1ZTtcblx0XHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0XHR0aGlzLm1lbnUuc2VsZWN0KCBldmVudCApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLlRBQjpcblx0XHRcdFx0XHRpZiAoIHRoaXMubWVudS5hY3RpdmUgKSB7XG5cdFx0XHRcdFx0XHR0aGlzLm1lbnUuc2VsZWN0KCBldmVudCApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLkVTQ0FQRTpcblx0XHRcdFx0XHRpZiAoIHRoaXMubWVudS5lbGVtZW50LmlzKCBcIjp2aXNpYmxlXCIgKSApIHtcblx0XHRcdFx0XHRcdGlmICggIXRoaXMuaXNNdWx0aUxpbmUgKSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuX3ZhbHVlKCB0aGlzLnRlcm0gKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdHRoaXMuY2xvc2UoIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRcdC8vIERpZmZlcmVudCBicm93c2VycyBoYXZlIGRpZmZlcmVudCBkZWZhdWx0IGJlaGF2aW9yIGZvciBlc2NhcGVcblx0XHRcdFx0XHRcdC8vIFNpbmdsZSBwcmVzcyBjYW4gbWVhbiB1bmRvIG9yIGNsZWFyXG5cdFx0XHRcdFx0XHQvLyBEb3VibGUgcHJlc3MgaW4gSUUgbWVhbnMgY2xlYXIgdGhlIHdob2xlIGZvcm1cblx0XHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdHN1cHByZXNzS2V5UHJlc3NSZXBlYXQgPSB0cnVlO1xuXG5cdFx0XHRcdFx0Ly8gc2VhcmNoIHRpbWVvdXQgc2hvdWxkIGJlIHRyaWdnZXJlZCBiZWZvcmUgdGhlIGlucHV0IHZhbHVlIGlzIGNoYW5nZWRcblx0XHRcdFx0XHR0aGlzLl9zZWFyY2hUaW1lb3V0KCBldmVudCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0a2V5cHJlc3M6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCBzdXBwcmVzc0tleVByZXNzICkge1xuXHRcdFx0XHRcdHN1cHByZXNzS2V5UHJlc3MgPSBmYWxzZTtcblx0XHRcdFx0XHRpZiAoICF0aGlzLmlzTXVsdGlMaW5lIHx8IHRoaXMubWVudS5lbGVtZW50LmlzKCBcIjp2aXNpYmxlXCIgKSApIHtcblx0XHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIHN1cHByZXNzS2V5UHJlc3NSZXBlYXQgKSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUmVwbGljYXRlIHNvbWUga2V5IGhhbmRsZXJzIHRvIGFsbG93IHRoZW0gdG8gcmVwZWF0IGluIEZpcmVmb3ggYW5kIE9wZXJhXG5cdFx0XHRcdHZhciBrZXlDb2RlID0gJC51aS5rZXlDb2RlO1xuXHRcdFx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuUEFHRV9VUDpcblx0XHRcdFx0XHR0aGlzLl9tb3ZlKCBcInByZXZpb3VzUGFnZVwiLCBldmVudCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuUEFHRV9ET1dOOlxuXHRcdFx0XHRcdHRoaXMuX21vdmUoIFwibmV4dFBhZ2VcIiwgZXZlbnQgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLlVQOlxuXHRcdFx0XHRcdHRoaXMuX2tleUV2ZW50KCBcInByZXZpb3VzXCIsIGV2ZW50ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5ET1dOOlxuXHRcdFx0XHRcdHRoaXMuX2tleUV2ZW50KCBcIm5leHRcIiwgZXZlbnQgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdGlucHV0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggc3VwcHJlc3NJbnB1dCApIHtcblx0XHRcdFx0XHRzdXBwcmVzc0lucHV0ID0gZmFsc2U7XG5cdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhpcy5fc2VhcmNoVGltZW91dCggZXZlbnQgKTtcblx0XHRcdH0sXG5cdFx0XHRmb2N1czogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMuc2VsZWN0ZWRJdGVtID0gbnVsbDtcblx0XHRcdFx0dGhpcy5wcmV2aW91cyA9IHRoaXMuX3ZhbHVlKCk7XG5cdFx0XHR9LFxuXHRcdFx0Ymx1cjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoIHRoaXMuY2FuY2VsQmx1ciApIHtcblx0XHRcdFx0XHRkZWxldGUgdGhpcy5jYW5jZWxCbHVyO1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNsZWFyVGltZW91dCggdGhpcy5zZWFyY2hpbmcgKTtcblx0XHRcdFx0dGhpcy5jbG9zZSggZXZlbnQgKTtcblx0XHRcdFx0dGhpcy5fY2hhbmdlKCBldmVudCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHRoaXMuX2luaXRTb3VyY2UoKTtcblx0XHR0aGlzLm1lbnUgPSAkKCBcIjx1bD5cIiApXG5cdFx0XHQuYXBwZW5kVG8oIHRoaXMuX2FwcGVuZFRvKCkgKVxuXHRcdFx0Lm1lbnUoIHtcblxuXHRcdFx0XHQvLyBkaXNhYmxlIEFSSUEgc3VwcG9ydCwgdGhlIGxpdmUgcmVnaW9uIHRha2VzIGNhcmUgb2YgdGhhdFxuXHRcdFx0XHRyb2xlOiBudWxsXG5cdFx0XHR9IClcblx0XHRcdC5oaWRlKClcblx0XHRcdC5tZW51KCBcImluc3RhbmNlXCIgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLm1lbnUuZWxlbWVudCwgXCJ1aS1hdXRvY29tcGxldGVcIiwgXCJ1aS1mcm9udFwiICk7XG5cdFx0dGhpcy5fb24oIHRoaXMubWVudS5lbGVtZW50LCB7XG5cdFx0XHRtb3VzZWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdFx0XHQvLyBwcmV2ZW50IG1vdmluZyBmb2N1cyBvdXQgb2YgdGhlIHRleHQgZmllbGRcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuXHRcdFx0XHQvLyBJRSBkb2Vzbid0IHByZXZlbnQgbW92aW5nIGZvY3VzIGV2ZW4gd2l0aCBldmVudC5wcmV2ZW50RGVmYXVsdCgpXG5cdFx0XHRcdC8vIHNvIHdlIHNldCBhIGZsYWcgdG8ga25vdyB3aGVuIHdlIHNob3VsZCBpZ25vcmUgdGhlIGJsdXIgZXZlbnRcblx0XHRcdFx0dGhpcy5jYW5jZWxCbHVyID0gdHJ1ZTtcblx0XHRcdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGRlbGV0ZSB0aGlzLmNhbmNlbEJsdXI7XG5cblx0XHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA4IG9ubHlcblx0XHRcdFx0XHQvLyBSaWdodCBjbGlja2luZyBhIG1lbnUgaXRlbSBvciBzZWxlY3RpbmcgdGV4dCBmcm9tIHRoZSBtZW51IGl0ZW1zIHdpbGxcblx0XHRcdFx0XHQvLyByZXN1bHQgaW4gZm9jdXMgbW92aW5nIG91dCBvZiB0aGUgaW5wdXQuIEhvd2V2ZXIsIHdlJ3ZlIGFscmVhZHkgcmVjZWl2ZWRcblx0XHRcdFx0XHQvLyBhbmQgaWdub3JlZCB0aGUgYmx1ciBldmVudCBiZWNhdXNlIG9mIHRoZSBjYW5jZWxCbHVyIGZsYWcgc2V0IGFib3ZlLiBTb1xuXHRcdFx0XHRcdC8vIHdlIHJlc3RvcmUgZm9jdXMgdG8gZW5zdXJlIHRoYXQgdGhlIG1lbnUgY2xvc2VzIHByb3Blcmx5IGJhc2VkIG9uIHRoZSB1c2VyJ3Ncblx0XHRcdFx0XHQvLyBuZXh0IGFjdGlvbnMuXG5cdFx0XHRcdFx0aWYgKCB0aGlzLmVsZW1lbnRbIDAgXSAhPT0gJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICkgKSB7XG5cdFx0XHRcdFx0XHR0aGlzLmVsZW1lbnQudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9LFxuXHRcdFx0bWVudWZvY3VzOiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHR2YXIgbGFiZWwsIGl0ZW07XG5cblx0XHRcdFx0Ly8gc3VwcG9ydDogRmlyZWZveFxuXHRcdFx0XHQvLyBQcmV2ZW50IGFjY2lkZW50YWwgYWN0aXZhdGlvbiBvZiBtZW51IGl0ZW1zIGluIEZpcmVmb3ggKCM3MDI0ICM5MTE4KVxuXHRcdFx0XHRpZiAoIHRoaXMuaXNOZXdNZW51ICkge1xuXHRcdFx0XHRcdHRoaXMuaXNOZXdNZW51ID0gZmFsc2U7XG5cdFx0XHRcdFx0aWYgKCBldmVudC5vcmlnaW5hbEV2ZW50ICYmIC9ebW91c2UvLnRlc3QoIGV2ZW50Lm9yaWdpbmFsRXZlbnQudHlwZSApICkge1xuXHRcdFx0XHRcdFx0dGhpcy5tZW51LmJsdXIoKTtcblxuXHRcdFx0XHRcdFx0dGhpcy5kb2N1bWVudC5vbmUoIFwibW91c2Vtb3ZlXCIsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0XHQkKCBldmVudC50YXJnZXQgKS50cmlnZ2VyKCBldmVudC5vcmlnaW5hbEV2ZW50ICk7XG5cdFx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpdGVtID0gdWkuaXRlbS5kYXRhKCBcInVpLWF1dG9jb21wbGV0ZS1pdGVtXCIgKTtcblx0XHRcdFx0aWYgKCBmYWxzZSAhPT0gdGhpcy5fdHJpZ2dlciggXCJmb2N1c1wiLCBldmVudCwgeyBpdGVtOiBpdGVtIH0gKSApIHtcblxuXHRcdFx0XHRcdC8vIHVzZSB2YWx1ZSB0byBtYXRjaCB3aGF0IHdpbGwgZW5kIHVwIGluIHRoZSBpbnB1dCwgaWYgaXQgd2FzIGEga2V5IGV2ZW50XG5cdFx0XHRcdFx0aWYgKCBldmVudC5vcmlnaW5hbEV2ZW50ICYmIC9ea2V5Ly50ZXN0KCBldmVudC5vcmlnaW5hbEV2ZW50LnR5cGUgKSApIHtcblx0XHRcdFx0XHRcdHRoaXMuX3ZhbHVlKCBpdGVtLnZhbHVlICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQW5ub3VuY2UgdGhlIHZhbHVlIGluIHRoZSBsaXZlUmVnaW9uXG5cdFx0XHRcdGxhYmVsID0gdWkuaXRlbS5hdHRyKCBcImFyaWEtbGFiZWxcIiApIHx8IGl0ZW0udmFsdWU7XG5cdFx0XHRcdGlmICggbGFiZWwgJiYgJC50cmltKCBsYWJlbCApLmxlbmd0aCApIHtcblx0XHRcdFx0XHR0aGlzLmxpdmVSZWdpb24uY2hpbGRyZW4oKS5oaWRlKCk7XG5cdFx0XHRcdFx0JCggXCI8ZGl2PlwiICkudGV4dCggbGFiZWwgKS5hcHBlbmRUbyggdGhpcy5saXZlUmVnaW9uICk7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRtZW51c2VsZWN0OiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHR2YXIgaXRlbSA9IHVpLml0ZW0uZGF0YSggXCJ1aS1hdXRvY29tcGxldGUtaXRlbVwiICksXG5cdFx0XHRcdFx0cHJldmlvdXMgPSB0aGlzLnByZXZpb3VzO1xuXG5cdFx0XHRcdC8vIE9ubHkgdHJpZ2dlciB3aGVuIGZvY3VzIHdhcyBsb3N0IChjbGljayBvbiBtZW51KVxuXHRcdFx0XHRpZiAoIHRoaXMuZWxlbWVudFsgMCBdICE9PSAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKSApIHtcblx0XHRcdFx0XHR0aGlzLmVsZW1lbnQudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHRcdFx0dGhpcy5wcmV2aW91cyA9IHByZXZpb3VzO1xuXG5cdFx0XHRcdFx0Ly8gIzYxMDkgLSBJRSB0cmlnZ2VycyB0d28gZm9jdXMgZXZlbnRzIGFuZCB0aGUgc2Vjb25kXG5cdFx0XHRcdFx0Ly8gaXMgYXN5bmNocm9ub3VzLCBzbyB3ZSBuZWVkIHRvIHJlc2V0IHRoZSBwcmV2aW91c1xuXHRcdFx0XHRcdC8vIHRlcm0gc3luY2hyb25vdXNseSBhbmQgYXN5bmNocm9ub3VzbHkgOi0oXG5cdFx0XHRcdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0dGhpcy5wcmV2aW91cyA9IHByZXZpb3VzO1xuXHRcdFx0XHRcdFx0dGhpcy5zZWxlY3RlZEl0ZW0gPSBpdGVtO1xuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZmFsc2UgIT09IHRoaXMuX3RyaWdnZXIoIFwic2VsZWN0XCIsIGV2ZW50LCB7IGl0ZW06IGl0ZW0gfSApICkge1xuXHRcdFx0XHRcdHRoaXMuX3ZhbHVlKCBpdGVtLnZhbHVlICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyByZXNldCB0aGUgdGVybSBhZnRlciB0aGUgc2VsZWN0IGV2ZW50XG5cdFx0XHRcdC8vIHRoaXMgYWxsb3dzIGN1c3RvbSBzZWxlY3QgaGFuZGxpbmcgdG8gd29yayBwcm9wZXJseVxuXHRcdFx0XHR0aGlzLnRlcm0gPSB0aGlzLl92YWx1ZSgpO1xuXG5cdFx0XHRcdHRoaXMuY2xvc2UoIGV2ZW50ICk7XG5cdFx0XHRcdHRoaXMuc2VsZWN0ZWRJdGVtID0gaXRlbTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHR0aGlzLmxpdmVSZWdpb24gPSAkKCBcIjxkaXY+XCIsIHtcblx0XHRcdHJvbGU6IFwic3RhdHVzXCIsXG5cdFx0XHRcImFyaWEtbGl2ZVwiOiBcImFzc2VydGl2ZVwiLFxuXHRcdFx0XCJhcmlhLXJlbGV2YW50XCI6IFwiYWRkaXRpb25zXCJcblx0XHR9IClcblx0XHRcdC5hcHBlbmRUbyggdGhpcy5kb2N1bWVudFsgMCBdLmJvZHkgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmxpdmVSZWdpb24sIG51bGwsIFwidWktaGVscGVyLWhpZGRlbi1hY2Nlc3NpYmxlXCIgKTtcblxuXHRcdC8vIFR1cm5pbmcgb2ZmIGF1dG9jb21wbGV0ZSBwcmV2ZW50cyB0aGUgYnJvd3NlciBmcm9tIHJlbWVtYmVyaW5nIHRoZVxuXHRcdC8vIHZhbHVlIHdoZW4gbmF2aWdhdGluZyB0aHJvdWdoIGhpc3RvcnksIHNvIHdlIHJlLWVuYWJsZSBhdXRvY29tcGxldGVcblx0XHQvLyBpZiB0aGUgcGFnZSBpcyB1bmxvYWRlZCBiZWZvcmUgdGhlIHdpZGdldCBpcyBkZXN0cm95ZWQuICM3NzkwXG5cdFx0dGhpcy5fb24oIHRoaXMud2luZG93LCB7XG5cdFx0XHRiZWZvcmV1bmxvYWQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQXR0ciggXCJhdXRvY29tcGxldGVcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnNlYXJjaGluZyApO1xuXHRcdHRoaXMuZWxlbWVudC5yZW1vdmVBdHRyKCBcImF1dG9jb21wbGV0ZVwiICk7XG5cdFx0dGhpcy5tZW51LmVsZW1lbnQucmVtb3ZlKCk7XG5cdFx0dGhpcy5saXZlUmVnaW9uLnJlbW92ZSgpO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cdFx0aWYgKCBrZXkgPT09IFwic291cmNlXCIgKSB7XG5cdFx0XHR0aGlzLl9pbml0U291cmNlKCk7XG5cdFx0fVxuXHRcdGlmICgga2V5ID09PSBcImFwcGVuZFRvXCIgKSB7XG5cdFx0XHR0aGlzLm1lbnUuZWxlbWVudC5hcHBlbmRUbyggdGhpcy5fYXBwZW5kVG8oKSApO1xuXHRcdH1cblx0XHRpZiAoIGtleSA9PT0gXCJkaXNhYmxlZFwiICYmIHZhbHVlICYmIHRoaXMueGhyICkge1xuXHRcdFx0dGhpcy54aHIuYWJvcnQoKTtcblx0XHR9XG5cdH0sXG5cblx0X2lzRXZlbnRUYXJnZXRJbldpZGdldDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBtZW51RWxlbWVudCA9IHRoaXMubWVudS5lbGVtZW50WyAwIF07XG5cblx0XHRyZXR1cm4gZXZlbnQudGFyZ2V0ID09PSB0aGlzLmVsZW1lbnRbIDAgXSB8fFxuXHRcdFx0ZXZlbnQudGFyZ2V0ID09PSBtZW51RWxlbWVudCB8fFxuXHRcdFx0JC5jb250YWlucyggbWVudUVsZW1lbnQsIGV2ZW50LnRhcmdldCApO1xuXHR9LFxuXG5cdF9jbG9zZU9uQ2xpY2tPdXRzaWRlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCAhdGhpcy5faXNFdmVudFRhcmdldEluV2lkZ2V0KCBldmVudCApICkge1xuXHRcdFx0dGhpcy5jbG9zZSgpO1xuXHRcdH1cblx0fSxcblxuXHRfYXBwZW5kVG86IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBlbGVtZW50ID0gdGhpcy5vcHRpb25zLmFwcGVuZFRvO1xuXG5cdFx0aWYgKCBlbGVtZW50ICkge1xuXHRcdFx0ZWxlbWVudCA9IGVsZW1lbnQuanF1ZXJ5IHx8IGVsZW1lbnQubm9kZVR5cGUgP1xuXHRcdFx0XHQkKCBlbGVtZW50ICkgOlxuXHRcdFx0XHR0aGlzLmRvY3VtZW50LmZpbmQoIGVsZW1lbnQgKS5lcSggMCApO1xuXHRcdH1cblxuXHRcdGlmICggIWVsZW1lbnQgfHwgIWVsZW1lbnRbIDAgXSApIHtcblx0XHRcdGVsZW1lbnQgPSB0aGlzLmVsZW1lbnQuY2xvc2VzdCggXCIudWktZnJvbnQsIGRpYWxvZ1wiICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhZWxlbWVudC5sZW5ndGggKSB7XG5cdFx0XHRlbGVtZW50ID0gdGhpcy5kb2N1bWVudFsgMCBdLmJvZHk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGVsZW1lbnQ7XG5cdH0sXG5cblx0X2luaXRTb3VyY2U6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBhcnJheSwgdXJsLFxuXHRcdFx0dGhhdCA9IHRoaXM7XG5cdFx0aWYgKCAkLmlzQXJyYXkoIHRoaXMub3B0aW9ucy5zb3VyY2UgKSApIHtcblx0XHRcdGFycmF5ID0gdGhpcy5vcHRpb25zLnNvdXJjZTtcblx0XHRcdHRoaXMuc291cmNlID0gZnVuY3Rpb24oIHJlcXVlc3QsIHJlc3BvbnNlICkge1xuXHRcdFx0XHRyZXNwb25zZSggJC51aS5hdXRvY29tcGxldGUuZmlsdGVyKCBhcnJheSwgcmVxdWVzdC50ZXJtICkgKTtcblx0XHRcdH07XG5cdFx0fSBlbHNlIGlmICggdHlwZW9mIHRoaXMub3B0aW9ucy5zb3VyY2UgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHR1cmwgPSB0aGlzLm9wdGlvbnMuc291cmNlO1xuXHRcdFx0dGhpcy5zb3VyY2UgPSBmdW5jdGlvbiggcmVxdWVzdCwgcmVzcG9uc2UgKSB7XG5cdFx0XHRcdGlmICggdGhhdC54aHIgKSB7XG5cdFx0XHRcdFx0dGhhdC54aHIuYWJvcnQoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGF0LnhociA9ICQuYWpheCgge1xuXHRcdFx0XHRcdHVybDogdXJsLFxuXHRcdFx0XHRcdGRhdGE6IHJlcXVlc3QsXG5cdFx0XHRcdFx0ZGF0YVR5cGU6IFwianNvblwiLFxuXHRcdFx0XHRcdHN1Y2Nlc3M6IGZ1bmN0aW9uKCBkYXRhICkge1xuXHRcdFx0XHRcdFx0cmVzcG9uc2UoIGRhdGEgKTtcblx0XHRcdFx0XHR9LFxuXHRcdFx0XHRcdGVycm9yOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHJlc3BvbnNlKCBbXSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0fTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5zb3VyY2UgPSB0aGlzLm9wdGlvbnMuc291cmNlO1xuXHRcdH1cblx0fSxcblxuXHRfc2VhcmNoVGltZW91dDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGNsZWFyVGltZW91dCggdGhpcy5zZWFyY2hpbmcgKTtcblx0XHR0aGlzLnNlYXJjaGluZyA9IHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblxuXHRcdFx0Ly8gU2VhcmNoIGlmIHRoZSB2YWx1ZSBoYXMgY2hhbmdlZCwgb3IgaWYgdGhlIHVzZXIgcmV0eXBlcyB0aGUgc2FtZSB2YWx1ZSAoc2VlICM3NDM0KVxuXHRcdFx0dmFyIGVxdWFsVmFsdWVzID0gdGhpcy50ZXJtID09PSB0aGlzLl92YWx1ZSgpLFxuXHRcdFx0XHRtZW51VmlzaWJsZSA9IHRoaXMubWVudS5lbGVtZW50LmlzKCBcIjp2aXNpYmxlXCIgKSxcblx0XHRcdFx0bW9kaWZpZXJLZXkgPSBldmVudC5hbHRLZXkgfHwgZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5IHx8IGV2ZW50LnNoaWZ0S2V5O1xuXG5cdFx0XHRpZiAoICFlcXVhbFZhbHVlcyB8fCAoIGVxdWFsVmFsdWVzICYmICFtZW51VmlzaWJsZSAmJiAhbW9kaWZpZXJLZXkgKSApIHtcblx0XHRcdFx0dGhpcy5zZWxlY3RlZEl0ZW0gPSBudWxsO1xuXHRcdFx0XHR0aGlzLnNlYXJjaCggbnVsbCwgZXZlbnQgKTtcblx0XHRcdH1cblx0XHR9LCB0aGlzLm9wdGlvbnMuZGVsYXkgKTtcblx0fSxcblxuXHRzZWFyY2g6IGZ1bmN0aW9uKCB2YWx1ZSwgZXZlbnQgKSB7XG5cdFx0dmFsdWUgPSB2YWx1ZSAhPSBudWxsID8gdmFsdWUgOiB0aGlzLl92YWx1ZSgpO1xuXG5cdFx0Ly8gQWx3YXlzIHNhdmUgdGhlIGFjdHVhbCB2YWx1ZSwgbm90IHRoZSBvbmUgcGFzc2VkIGFzIGFuIGFyZ3VtZW50XG5cdFx0dGhpcy50ZXJtID0gdGhpcy5fdmFsdWUoKTtcblxuXHRcdGlmICggdmFsdWUubGVuZ3RoIDwgdGhpcy5vcHRpb25zLm1pbkxlbmd0aCApIHtcblx0XHRcdHJldHVybiB0aGlzLmNsb3NlKCBldmVudCApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fdHJpZ2dlciggXCJzZWFyY2hcIiwgZXZlbnQgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuX3NlYXJjaCggdmFsdWUgKTtcblx0fSxcblxuXHRfc2VhcmNoOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dGhpcy5wZW5kaW5nKys7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktYXV0b2NvbXBsZXRlLWxvYWRpbmdcIiApO1xuXHRcdHRoaXMuY2FuY2VsU2VhcmNoID0gZmFsc2U7XG5cblx0XHR0aGlzLnNvdXJjZSggeyB0ZXJtOiB2YWx1ZSB9LCB0aGlzLl9yZXNwb25zZSgpICk7XG5cdH0sXG5cblx0X3Jlc3BvbnNlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgaW5kZXggPSArK3RoaXMucmVxdWVzdEluZGV4O1xuXG5cdFx0cmV0dXJuICQucHJveHkoIGZ1bmN0aW9uKCBjb250ZW50ICkge1xuXHRcdFx0aWYgKCBpbmRleCA9PT0gdGhpcy5yZXF1ZXN0SW5kZXggKSB7XG5cdFx0XHRcdHRoaXMuX19yZXNwb25zZSggY29udGVudCApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLnBlbmRpbmctLTtcblx0XHRcdGlmICggIXRoaXMucGVuZGluZyApIHtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIFwidWktYXV0b2NvbXBsZXRlLWxvYWRpbmdcIiApO1xuXHRcdFx0fVxuXHRcdH0sIHRoaXMgKTtcblx0fSxcblxuXHRfX3Jlc3BvbnNlOiBmdW5jdGlvbiggY29udGVudCApIHtcblx0XHRpZiAoIGNvbnRlbnQgKSB7XG5cdFx0XHRjb250ZW50ID0gdGhpcy5fbm9ybWFsaXplKCBjb250ZW50ICk7XG5cdFx0fVxuXHRcdHRoaXMuX3RyaWdnZXIoIFwicmVzcG9uc2VcIiwgbnVsbCwgeyBjb250ZW50OiBjb250ZW50IH0gKTtcblx0XHRpZiAoICF0aGlzLm9wdGlvbnMuZGlzYWJsZWQgJiYgY29udGVudCAmJiBjb250ZW50Lmxlbmd0aCAmJiAhdGhpcy5jYW5jZWxTZWFyY2ggKSB7XG5cdFx0XHR0aGlzLl9zdWdnZXN0KCBjb250ZW50ICk7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcIm9wZW5cIiApO1xuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIHVzZSAuX2Nsb3NlKCkgaW5zdGVhZCBvZiAuY2xvc2UoKSBzbyB3ZSBkb24ndCBjYW5jZWwgZnV0dXJlIHNlYXJjaGVzXG5cdFx0XHR0aGlzLl9jbG9zZSgpO1xuXHRcdH1cblx0fSxcblxuXHRjbG9zZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHRoaXMuY2FuY2VsU2VhcmNoID0gdHJ1ZTtcblx0XHR0aGlzLl9jbG9zZSggZXZlbnQgKTtcblx0fSxcblxuXHRfY2xvc2U6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdC8vIFJlbW92ZSB0aGUgaGFuZGxlciB0aGF0IGNsb3NlcyB0aGUgbWVudSBvbiBvdXRzaWRlIGNsaWNrc1xuXHRcdHRoaXMuX29mZiggdGhpcy5kb2N1bWVudCwgXCJtb3VzZWRvd25cIiApO1xuXG5cdFx0aWYgKCB0aGlzLm1lbnUuZWxlbWVudC5pcyggXCI6dmlzaWJsZVwiICkgKSB7XG5cdFx0XHR0aGlzLm1lbnUuZWxlbWVudC5oaWRlKCk7XG5cdFx0XHR0aGlzLm1lbnUuYmx1cigpO1xuXHRcdFx0dGhpcy5pc05ld01lbnUgPSB0cnVlO1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjbG9zZVwiLCBldmVudCApO1xuXHRcdH1cblx0fSxcblxuXHRfY2hhbmdlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCB0aGlzLnByZXZpb3VzICE9PSB0aGlzLl92YWx1ZSgpICkge1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjaGFuZ2VcIiwgZXZlbnQsIHsgaXRlbTogdGhpcy5zZWxlY3RlZEl0ZW0gfSApO1xuXHRcdH1cblx0fSxcblxuXHRfbm9ybWFsaXplOiBmdW5jdGlvbiggaXRlbXMgKSB7XG5cblx0XHQvLyBhc3N1bWUgYWxsIGl0ZW1zIGhhdmUgdGhlIHJpZ2h0IGZvcm1hdCB3aGVuIHRoZSBmaXJzdCBpdGVtIGlzIGNvbXBsZXRlXG5cdFx0aWYgKCBpdGVtcy5sZW5ndGggJiYgaXRlbXNbIDAgXS5sYWJlbCAmJiBpdGVtc1sgMCBdLnZhbHVlICkge1xuXHRcdFx0cmV0dXJuIGl0ZW1zO1xuXHRcdH1cblx0XHRyZXR1cm4gJC5tYXAoIGl0ZW1zLCBmdW5jdGlvbiggaXRlbSApIHtcblx0XHRcdGlmICggdHlwZW9mIGl0ZW0gPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFx0bGFiZWw6IGl0ZW0sXG5cdFx0XHRcdFx0dmFsdWU6IGl0ZW1cblx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHRcdHJldHVybiAkLmV4dGVuZCgge30sIGl0ZW0sIHtcblx0XHRcdFx0bGFiZWw6IGl0ZW0ubGFiZWwgfHwgaXRlbS52YWx1ZSxcblx0XHRcdFx0dmFsdWU6IGl0ZW0udmFsdWUgfHwgaXRlbS5sYWJlbFxuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0fSxcblxuXHRfc3VnZ2VzdDogZnVuY3Rpb24oIGl0ZW1zICkge1xuXHRcdHZhciB1bCA9IHRoaXMubWVudS5lbGVtZW50LmVtcHR5KCk7XG5cdFx0dGhpcy5fcmVuZGVyTWVudSggdWwsIGl0ZW1zICk7XG5cdFx0dGhpcy5pc05ld01lbnUgPSB0cnVlO1xuXHRcdHRoaXMubWVudS5yZWZyZXNoKCk7XG5cblx0XHQvLyBTaXplIGFuZCBwb3NpdGlvbiBtZW51XG5cdFx0dWwuc2hvdygpO1xuXHRcdHRoaXMuX3Jlc2l6ZU1lbnUoKTtcblx0XHR1bC5wb3NpdGlvbiggJC5leHRlbmQoIHtcblx0XHRcdG9mOiB0aGlzLmVsZW1lbnRcblx0XHR9LCB0aGlzLm9wdGlvbnMucG9zaXRpb24gKSApO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuYXV0b0ZvY3VzICkge1xuXHRcdFx0dGhpcy5tZW51Lm5leHQoKTtcblx0XHR9XG5cblx0XHQvLyBMaXN0ZW4gZm9yIGludGVyYWN0aW9ucyBvdXRzaWRlIG9mIHRoZSB3aWRnZXQgKCM2NjQyKVxuXHRcdHRoaXMuX29uKCB0aGlzLmRvY3VtZW50LCB7XG5cdFx0XHRtb3VzZWRvd246IFwiX2Nsb3NlT25DbGlja091dHNpZGVcIlxuXHRcdH0gKTtcblx0fSxcblxuXHRfcmVzaXplTWVudTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHVsID0gdGhpcy5tZW51LmVsZW1lbnQ7XG5cdFx0dWwub3V0ZXJXaWR0aCggTWF0aC5tYXgoXG5cblx0XHRcdC8vIEZpcmVmb3ggd3JhcHMgbG9uZyB0ZXh0IChwb3NzaWJseSBhIHJvdW5kaW5nIGJ1Zylcblx0XHRcdC8vIHNvIHdlIGFkZCAxcHggdG8gYXZvaWQgdGhlIHdyYXBwaW5nICgjNzUxMylcblx0XHRcdHVsLndpZHRoKCBcIlwiICkub3V0ZXJXaWR0aCgpICsgMSxcblx0XHRcdHRoaXMuZWxlbWVudC5vdXRlcldpZHRoKClcblx0XHQpICk7XG5cdH0sXG5cblx0X3JlbmRlck1lbnU6IGZ1bmN0aW9uKCB1bCwgaXRlbXMgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXHRcdCQuZWFjaCggaXRlbXMsIGZ1bmN0aW9uKCBpbmRleCwgaXRlbSApIHtcblx0XHRcdHRoYXQuX3JlbmRlckl0ZW1EYXRhKCB1bCwgaXRlbSApO1xuXHRcdH0gKTtcblx0fSxcblxuXHRfcmVuZGVySXRlbURhdGE6IGZ1bmN0aW9uKCB1bCwgaXRlbSApIHtcblx0XHRyZXR1cm4gdGhpcy5fcmVuZGVySXRlbSggdWwsIGl0ZW0gKS5kYXRhKCBcInVpLWF1dG9jb21wbGV0ZS1pdGVtXCIsIGl0ZW0gKTtcblx0fSxcblxuXHRfcmVuZGVySXRlbTogZnVuY3Rpb24oIHVsLCBpdGVtICkge1xuXHRcdHJldHVybiAkKCBcIjxsaT5cIiApXG5cdFx0XHQuYXBwZW5kKCAkKCBcIjxkaXY+XCIgKS50ZXh0KCBpdGVtLmxhYmVsICkgKVxuXHRcdFx0LmFwcGVuZFRvKCB1bCApO1xuXHR9LFxuXG5cdF9tb3ZlOiBmdW5jdGlvbiggZGlyZWN0aW9uLCBldmVudCApIHtcblx0XHRpZiAoICF0aGlzLm1lbnUuZWxlbWVudC5pcyggXCI6dmlzaWJsZVwiICkgKSB7XG5cdFx0XHR0aGlzLnNlYXJjaCggbnVsbCwgZXZlbnQgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLm1lbnUuaXNGaXJzdEl0ZW0oKSAmJiAvXnByZXZpb3VzLy50ZXN0KCBkaXJlY3Rpb24gKSB8fFxuXHRcdFx0XHR0aGlzLm1lbnUuaXNMYXN0SXRlbSgpICYmIC9ebmV4dC8udGVzdCggZGlyZWN0aW9uICkgKSB7XG5cblx0XHRcdGlmICggIXRoaXMuaXNNdWx0aUxpbmUgKSB7XG5cdFx0XHRcdHRoaXMuX3ZhbHVlKCB0aGlzLnRlcm0gKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5tZW51LmJsdXIoKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5tZW51WyBkaXJlY3Rpb24gXSggZXZlbnQgKTtcblx0fSxcblxuXHR3aWRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLm1lbnUuZWxlbWVudDtcblx0fSxcblxuXHRfdmFsdWU6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLnZhbHVlTWV0aG9kLmFwcGx5KCB0aGlzLmVsZW1lbnQsIGFyZ3VtZW50cyApO1xuXHR9LFxuXG5cdF9rZXlFdmVudDogZnVuY3Rpb24oIGtleUV2ZW50LCBldmVudCApIHtcblx0XHRpZiAoICF0aGlzLmlzTXVsdGlMaW5lIHx8IHRoaXMubWVudS5lbGVtZW50LmlzKCBcIjp2aXNpYmxlXCIgKSApIHtcblx0XHRcdHRoaXMuX21vdmUoIGtleUV2ZW50LCBldmVudCApO1xuXG5cdFx0XHQvLyBQcmV2ZW50cyBtb3ZpbmcgY3Vyc29yIHRvIGJlZ2lubmluZy9lbmQgb2YgdGhlIHRleHQgZmllbGQgaW4gc29tZSBicm93c2Vyc1xuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gU3VwcG9ydDogQ2hyb21lIDw9NTBcblx0Ly8gV2Ugc2hvdWxkIGJlIGFibGUgdG8ganVzdCB1c2UgdGhpcy5lbGVtZW50LnByb3AoIFwiaXNDb250ZW50RWRpdGFibGVcIiApXG5cdC8vIGJ1dCBoaWRkZW4gZWxlbWVudHMgYWx3YXlzIHJlcG9ydCBmYWxzZSBpbiBDaHJvbWUuXG5cdC8vIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD0zMTMwODJcblx0X2lzQ29udGVudEVkaXRhYmxlOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHRpZiAoICFlbGVtZW50Lmxlbmd0aCApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHR2YXIgZWRpdGFibGUgPSBlbGVtZW50LnByb3AoIFwiY29udGVudEVkaXRhYmxlXCIgKTtcblxuXHRcdGlmICggZWRpdGFibGUgPT09IFwiaW5oZXJpdFwiICkge1xuXHRcdCAgcmV0dXJuIHRoaXMuX2lzQ29udGVudEVkaXRhYmxlKCBlbGVtZW50LnBhcmVudCgpICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGVkaXRhYmxlID09PSBcInRydWVcIjtcblx0fVxufSApO1xuXG4kLmV4dGVuZCggJC51aS5hdXRvY29tcGxldGUsIHtcblx0ZXNjYXBlUmVnZXg6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRyZXR1cm4gdmFsdWUucmVwbGFjZSggL1tcXC1cXFtcXF17fSgpKis/LixcXFxcXFxeJHwjXFxzXS9nLCBcIlxcXFwkJlwiICk7XG5cdH0sXG5cdGZpbHRlcjogZnVuY3Rpb24oIGFycmF5LCB0ZXJtICkge1xuXHRcdHZhciBtYXRjaGVyID0gbmV3IFJlZ0V4cCggJC51aS5hdXRvY29tcGxldGUuZXNjYXBlUmVnZXgoIHRlcm0gKSwgXCJpXCIgKTtcblx0XHRyZXR1cm4gJC5ncmVwKCBhcnJheSwgZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0cmV0dXJuIG1hdGNoZXIudGVzdCggdmFsdWUubGFiZWwgfHwgdmFsdWUudmFsdWUgfHwgdmFsdWUgKTtcblx0XHR9ICk7XG5cdH1cbn0gKTtcblxuLy8gTGl2ZSByZWdpb24gZXh0ZW5zaW9uLCBhZGRpbmcgYSBgbWVzc2FnZXNgIG9wdGlvblxuLy8gTk9URTogVGhpcyBpcyBhbiBleHBlcmltZW50YWwgQVBJLiBXZSBhcmUgc3RpbGwgaW52ZXN0aWdhdGluZ1xuLy8gYSBmdWxsIHNvbHV0aW9uIGZvciBzdHJpbmcgbWFuaXB1bGF0aW9uIGFuZCBpbnRlcm5hdGlvbmFsaXphdGlvbi5cbiQud2lkZ2V0KCBcInVpLmF1dG9jb21wbGV0ZVwiLCAkLnVpLmF1dG9jb21wbGV0ZSwge1xuXHRvcHRpb25zOiB7XG5cdFx0bWVzc2FnZXM6IHtcblx0XHRcdG5vUmVzdWx0czogXCJObyBzZWFyY2ggcmVzdWx0cy5cIixcblx0XHRcdHJlc3VsdHM6IGZ1bmN0aW9uKCBhbW91bnQgKSB7XG5cdFx0XHRcdHJldHVybiBhbW91bnQgKyAoIGFtb3VudCA+IDEgPyBcIiByZXN1bHRzIGFyZVwiIDogXCIgcmVzdWx0IGlzXCIgKSArXG5cdFx0XHRcdFx0XCIgYXZhaWxhYmxlLCB1c2UgdXAgYW5kIGRvd24gYXJyb3cga2V5cyB0byBuYXZpZ2F0ZS5cIjtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X19yZXNwb25zZTogZnVuY3Rpb24oIGNvbnRlbnQgKSB7XG5cdFx0dmFyIG1lc3NhZ2U7XG5cdFx0dGhpcy5fc3VwZXJBcHBseSggYXJndW1lbnRzICk7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgfHwgdGhpcy5jYW5jZWxTZWFyY2ggKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmICggY29udGVudCAmJiBjb250ZW50Lmxlbmd0aCApIHtcblx0XHRcdG1lc3NhZ2UgPSB0aGlzLm9wdGlvbnMubWVzc2FnZXMucmVzdWx0cyggY29udGVudC5sZW5ndGggKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0bWVzc2FnZSA9IHRoaXMub3B0aW9ucy5tZXNzYWdlcy5ub1Jlc3VsdHM7XG5cdFx0fVxuXHRcdHRoaXMubGl2ZVJlZ2lvbi5jaGlsZHJlbigpLmhpZGUoKTtcblx0XHQkKCBcIjxkaXY+XCIgKS50ZXh0KCBtZXNzYWdlICkuYXBwZW5kVG8oIHRoaXMubGl2ZVJlZ2lvbiApO1xuXHR9XG59ICk7XG5cbnZhciB3aWRnZXRzQXV0b2NvbXBsZXRlID0gJC51aS5hdXRvY29tcGxldGU7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgQ29udHJvbGdyb3VwIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBDb250cm9sZ3JvdXBcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBWaXN1YWxseSBncm91cHMgZm9ybSBjb250cm9sIHdpZGdldHNcbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9jb250cm9sZ3JvdXAvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vY29udHJvbGdyb3VwL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29udHJvbGdyb3VwLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxudmFyIGNvbnRyb2xncm91cENvcm5lclJlZ2V4ID0gL3VpLWNvcm5lci0oW2Etel0pezIsNn0vZztcblxudmFyIHdpZGdldHNDb250cm9sZ3JvdXAgPSAkLndpZGdldCggXCJ1aS5jb250cm9sZ3JvdXBcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRkZWZhdWx0RWxlbWVudDogXCI8ZGl2PlwiLFxuXHRvcHRpb25zOiB7XG5cdFx0ZGlyZWN0aW9uOiBcImhvcml6b250YWxcIixcblx0XHRkaXNhYmxlZDogbnVsbCxcblx0XHRvbmx5VmlzaWJsZTogdHJ1ZSxcblx0XHRpdGVtczoge1xuXHRcdFx0XCJidXR0b25cIjogXCJpbnB1dFt0eXBlPWJ1dHRvbl0sIGlucHV0W3R5cGU9c3VibWl0XSwgaW5wdXRbdHlwZT1yZXNldF0sIGJ1dHRvbiwgYVwiLFxuXHRcdFx0XCJjb250cm9sZ3JvdXBMYWJlbFwiOiBcIi51aS1jb250cm9sZ3JvdXAtbGFiZWxcIixcblx0XHRcdFwiY2hlY2tib3hyYWRpb1wiOiBcImlucHV0W3R5cGU9J2NoZWNrYm94J10sIGlucHV0W3R5cGU9J3JhZGlvJ11cIixcblx0XHRcdFwic2VsZWN0bWVudVwiOiBcInNlbGVjdFwiLFxuXHRcdFx0XCJzcGlubmVyXCI6IFwiLnVpLXNwaW5uZXItaW5wdXRcIlxuXHRcdH1cblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9lbmhhbmNlKCk7XG5cdH0sXG5cblx0Ly8gVG8gc3VwcG9ydCB0aGUgZW5oYW5jZWQgb3B0aW9uIGluIGpRdWVyeSBNb2JpbGUsIHdlIGlzb2xhdGUgRE9NIG1hbmlwdWxhdGlvblxuXHRfZW5oYW5jZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwicm9sZVwiLCBcInRvb2xiYXJcIiApO1xuXHRcdHRoaXMucmVmcmVzaCgpO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9jYWxsQ2hpbGRNZXRob2QoIFwiZGVzdHJveVwiICk7XG5cdFx0dGhpcy5jaGlsZFdpZGdldHMucmVtb3ZlRGF0YSggXCJ1aS1jb250cm9sZ3JvdXAtZGF0YVwiICk7XG5cdFx0dGhpcy5lbGVtZW50LnJlbW92ZUF0dHIoIFwicm9sZVwiICk7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuaXRlbXMuY29udHJvbGdyb3VwTGFiZWwgKSB7XG5cdFx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdFx0LmZpbmQoIHRoaXMub3B0aW9ucy5pdGVtcy5jb250cm9sZ3JvdXBMYWJlbCApXG5cdFx0XHRcdC5maW5kKCBcIi51aS1jb250cm9sZ3JvdXAtbGFiZWwtY29udGVudHNcIiApXG5cdFx0XHRcdC5jb250ZW50cygpLnVud3JhcCgpO1xuXHRcdH1cblx0fSxcblxuXHRfaW5pdFdpZGdldHM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdGNoaWxkV2lkZ2V0cyA9IFtdO1xuXG5cdFx0Ly8gRmlyc3Qgd2UgaXRlcmF0ZSBvdmVyIGVhY2ggb2YgdGhlIGl0ZW1zIG9wdGlvbnNcblx0XHQkLmVhY2goIHRoaXMub3B0aW9ucy5pdGVtcywgZnVuY3Rpb24oIHdpZGdldCwgc2VsZWN0b3IgKSB7XG5cdFx0XHR2YXIgbGFiZWxzO1xuXHRcdFx0dmFyIG9wdGlvbnMgPSB7fTtcblxuXHRcdFx0Ly8gTWFrZSBzdXJlIHRoZSB3aWRnZXQgaGFzIGEgc2VsZWN0b3Igc2V0XG5cdFx0XHRpZiAoICFzZWxlY3RvciApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHdpZGdldCA9PT0gXCJjb250cm9sZ3JvdXBMYWJlbFwiICkge1xuXHRcdFx0XHRsYWJlbHMgPSB0aGF0LmVsZW1lbnQuZmluZCggc2VsZWN0b3IgKTtcblx0XHRcdFx0bGFiZWxzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHZhciBlbGVtZW50ID0gJCggdGhpcyApO1xuXG5cdFx0XHRcdFx0aWYgKCBlbGVtZW50LmNoaWxkcmVuKCBcIi51aS1jb250cm9sZ3JvdXAtbGFiZWwtY29udGVudHNcIiApLmxlbmd0aCApIHtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxlbWVudC5jb250ZW50cygpXG5cdFx0XHRcdFx0XHQud3JhcEFsbCggXCI8c3BhbiBjbGFzcz0ndWktY29udHJvbGdyb3VwLWxhYmVsLWNvbnRlbnRzJz48L3NwYW4+XCIgKTtcblx0XHRcdFx0fSApO1xuXHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggbGFiZWxzLCBudWxsLCBcInVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudCB1aS1zdGF0ZS1kZWZhdWx0XCIgKTtcblx0XHRcdFx0Y2hpbGRXaWRnZXRzID0gY2hpbGRXaWRnZXRzLmNvbmNhdCggbGFiZWxzLmdldCgpICk7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTWFrZSBzdXJlIHRoZSB3aWRnZXQgYWN0dWFsbHkgZXhpc3RzXG5cdFx0XHRpZiAoICEkLmZuWyB3aWRnZXQgXSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBXZSBhc3N1bWUgZXZlcnl0aGluZyBpcyBpbiB0aGUgbWlkZGxlIHRvIHN0YXJ0IGJlY2F1c2Ugd2UgY2FuJ3QgZGV0ZXJtaW5lXG5cdFx0XHQvLyBmaXJzdCAvIGxhc3QgZWxlbWVudHMgdW50aWwgYWxsIGVuaGFuY21lbnRzIGFyZSBkb25lLlxuXHRcdFx0aWYgKCB0aGF0WyBcIl9cIiArIHdpZGdldCArIFwiT3B0aW9uc1wiIF0gKSB7XG5cdFx0XHRcdG9wdGlvbnMgPSB0aGF0WyBcIl9cIiArIHdpZGdldCArIFwiT3B0aW9uc1wiIF0oIFwibWlkZGxlXCIgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdG9wdGlvbnMgPSB7IGNsYXNzZXM6IHt9IH07XG5cdFx0XHR9XG5cblx0XHRcdC8vIEZpbmQgaW5zdGFuY2VzIG9mIHRoaXMgd2lkZ2V0IGluc2lkZSBjb250cm9sZ3JvdXAgYW5kIGluaXQgdGhlbVxuXHRcdFx0dGhhdC5lbGVtZW50XG5cdFx0XHRcdC5maW5kKCBzZWxlY3RvciApXG5cdFx0XHRcdC5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR2YXIgZWxlbWVudCA9ICQoIHRoaXMgKTtcblx0XHRcdFx0XHR2YXIgaW5zdGFuY2UgPSBlbGVtZW50WyB3aWRnZXQgXSggXCJpbnN0YW5jZVwiICk7XG5cblx0XHRcdFx0XHQvLyBXZSBuZWVkIHRvIGNsb25lIHRoZSBkZWZhdWx0IG9wdGlvbnMgZm9yIHRoaXMgdHlwZSBvZiB3aWRnZXQgdG8gYXZvaWRcblx0XHRcdFx0XHQvLyBwb2xsdXRpbmcgdGhlIHZhcmlhYmxlIG9wdGlvbnMgd2hpY2ggaGFzIGEgd2lkZXIgc2NvcGUgdGhhbiBhIHNpbmdsZSB3aWRnZXQuXG5cdFx0XHRcdFx0dmFyIGluc3RhbmNlT3B0aW9ucyA9ICQud2lkZ2V0LmV4dGVuZCgge30sIG9wdGlvbnMgKTtcblxuXHRcdFx0XHRcdC8vIElmIHRoZSBidXR0b24gaXMgdGhlIGNoaWxkIG9mIGEgc3Bpbm5lciBpZ25vcmUgaXRcblx0XHRcdFx0XHQvLyBUT0RPOiBGaW5kIGEgbW9yZSBnZW5lcmljIHNvbHV0aW9uXG5cdFx0XHRcdFx0aWYgKCB3aWRnZXQgPT09IFwiYnV0dG9uXCIgJiYgZWxlbWVudC5wYXJlbnQoIFwiLnVpLXNwaW5uZXJcIiApLmxlbmd0aCApIHtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBDcmVhdGUgdGhlIHdpZGdldCBpZiBpdCBkb2Vzbid0IGV4aXN0XG5cdFx0XHRcdFx0aWYgKCAhaW5zdGFuY2UgKSB7XG5cdFx0XHRcdFx0XHRpbnN0YW5jZSA9IGVsZW1lbnRbIHdpZGdldCBdKClbIHdpZGdldCBdKCBcImluc3RhbmNlXCIgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCBpbnN0YW5jZSApIHtcblx0XHRcdFx0XHRcdGluc3RhbmNlT3B0aW9ucy5jbGFzc2VzID1cblx0XHRcdFx0XHRcdFx0dGhhdC5fcmVzb2x2ZUNsYXNzZXNWYWx1ZXMoIGluc3RhbmNlT3B0aW9ucy5jbGFzc2VzLCBpbnN0YW5jZSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRlbGVtZW50WyB3aWRnZXQgXSggaW5zdGFuY2VPcHRpb25zICk7XG5cblx0XHRcdFx0XHQvLyBTdG9yZSBhbiBpbnN0YW5jZSBvZiB0aGUgY29udHJvbGdyb3VwIHRvIGJlIGFibGUgdG8gcmVmZXJlbmNlXG5cdFx0XHRcdFx0Ly8gZnJvbSB0aGUgb3V0ZXJtb3N0IGVsZW1lbnQgZm9yIGNoYW5naW5nIG9wdGlvbnMgYW5kIHJlZnJlc2hcblx0XHRcdFx0XHR2YXIgd2lkZ2V0RWxlbWVudCA9IGVsZW1lbnRbIHdpZGdldCBdKCBcIndpZGdldFwiICk7XG5cdFx0XHRcdFx0JC5kYXRhKCB3aWRnZXRFbGVtZW50WyAwIF0sIFwidWktY29udHJvbGdyb3VwLWRhdGFcIixcblx0XHRcdFx0XHRcdGluc3RhbmNlID8gaW5zdGFuY2UgOiBlbGVtZW50WyB3aWRnZXQgXSggXCJpbnN0YW5jZVwiICkgKTtcblxuXHRcdFx0XHRcdGNoaWxkV2lkZ2V0cy5wdXNoKCB3aWRnZXRFbGVtZW50WyAwIF0gKTtcblx0XHRcdFx0fSApO1xuXHRcdH0gKTtcblxuXHRcdHRoaXMuY2hpbGRXaWRnZXRzID0gJCggJC51bmlxdWUoIGNoaWxkV2lkZ2V0cyApICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuY2hpbGRXaWRnZXRzLCBcInVpLWNvbnRyb2xncm91cC1pdGVtXCIgKTtcblx0fSxcblxuXHRfY2FsbENoaWxkTWV0aG9kOiBmdW5jdGlvbiggbWV0aG9kICkge1xuXHRcdHRoaXMuY2hpbGRXaWRnZXRzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0XHRcdGRhdGEgPSBlbGVtZW50LmRhdGEoIFwidWktY29udHJvbGdyb3VwLWRhdGFcIiApO1xuXHRcdFx0aWYgKCBkYXRhICYmIGRhdGFbIG1ldGhvZCBdICkge1xuXHRcdFx0XHRkYXRhWyBtZXRob2QgXSgpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfdXBkYXRlQ29ybmVyQ2xhc3M6IGZ1bmN0aW9uKCBlbGVtZW50LCBwb3NpdGlvbiApIHtcblx0XHR2YXIgcmVtb3ZlID0gXCJ1aS1jb3JuZXItdG9wIHVpLWNvcm5lci1ib3R0b20gdWktY29ybmVyLWxlZnQgdWktY29ybmVyLXJpZ2h0IHVpLWNvcm5lci1hbGxcIjtcblx0XHR2YXIgYWRkID0gdGhpcy5fYnVpbGRTaW1wbGVPcHRpb25zKCBwb3NpdGlvbiwgXCJsYWJlbFwiICkuY2xhc3Nlcy5sYWJlbDtcblxuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBlbGVtZW50LCBudWxsLCByZW1vdmUgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggZWxlbWVudCwgbnVsbCwgYWRkICk7XG5cdH0sXG5cblx0X2J1aWxkU2ltcGxlT3B0aW9uczogZnVuY3Rpb24oIHBvc2l0aW9uLCBrZXkgKSB7XG5cdFx0dmFyIGRpcmVjdGlvbiA9IHRoaXMub3B0aW9ucy5kaXJlY3Rpb24gPT09IFwidmVydGljYWxcIjtcblx0XHR2YXIgcmVzdWx0ID0ge1xuXHRcdFx0Y2xhc3Nlczoge31cblx0XHR9O1xuXHRcdHJlc3VsdC5jbGFzc2VzWyBrZXkgXSA9IHtcblx0XHRcdFwibWlkZGxlXCI6IFwiXCIsXG5cdFx0XHRcImZpcnN0XCI6IFwidWktY29ybmVyLVwiICsgKCBkaXJlY3Rpb24gPyBcInRvcFwiIDogXCJsZWZ0XCIgKSxcblx0XHRcdFwibGFzdFwiOiBcInVpLWNvcm5lci1cIiArICggZGlyZWN0aW9uID8gXCJib3R0b21cIiA6IFwicmlnaHRcIiApLFxuXHRcdFx0XCJvbmx5XCI6IFwidWktY29ybmVyLWFsbFwiXG5cdFx0fVsgcG9zaXRpb24gXTtcblxuXHRcdHJldHVybiByZXN1bHQ7XG5cdH0sXG5cblx0X3NwaW5uZXJPcHRpb25zOiBmdW5jdGlvbiggcG9zaXRpb24gKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLl9idWlsZFNpbXBsZU9wdGlvbnMoIHBvc2l0aW9uLCBcInVpLXNwaW5uZXJcIiApO1xuXG5cdFx0b3B0aW9ucy5jbGFzc2VzWyBcInVpLXNwaW5uZXItdXBcIiBdID0gXCJcIjtcblx0XHRvcHRpb25zLmNsYXNzZXNbIFwidWktc3Bpbm5lci1kb3duXCIgXSA9IFwiXCI7XG5cblx0XHRyZXR1cm4gb3B0aW9ucztcblx0fSxcblxuXHRfYnV0dG9uT3B0aW9uczogZnVuY3Rpb24oIHBvc2l0aW9uICkge1xuXHRcdHJldHVybiB0aGlzLl9idWlsZFNpbXBsZU9wdGlvbnMoIHBvc2l0aW9uLCBcInVpLWJ1dHRvblwiICk7XG5cdH0sXG5cblx0X2NoZWNrYm94cmFkaW9PcHRpb25zOiBmdW5jdGlvbiggcG9zaXRpb24gKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2J1aWxkU2ltcGxlT3B0aW9ucyggcG9zaXRpb24sIFwidWktY2hlY2tib3hyYWRpby1sYWJlbFwiICk7XG5cdH0sXG5cblx0X3NlbGVjdG1lbnVPcHRpb25zOiBmdW5jdGlvbiggcG9zaXRpb24gKSB7XG5cdFx0dmFyIGRpcmVjdGlvbiA9IHRoaXMub3B0aW9ucy5kaXJlY3Rpb24gPT09IFwidmVydGljYWxcIjtcblx0XHRyZXR1cm4ge1xuXHRcdFx0d2lkdGg6IGRpcmVjdGlvbiA/IFwiYXV0b1wiIDogZmFsc2UsXG5cdFx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcdG1pZGRsZToge1xuXHRcdFx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tb3BlblwiOiBcIlwiLFxuXHRcdFx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tY2xvc2VkXCI6IFwiXCJcblx0XHRcdFx0fSxcblx0XHRcdFx0Zmlyc3Q6IHtcblx0XHRcdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLW9wZW5cIjogXCJ1aS1jb3JuZXItXCIgKyAoIGRpcmVjdGlvbiA/IFwidG9wXCIgOiBcInRsXCIgKSxcblx0XHRcdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLWNsb3NlZFwiOiBcInVpLWNvcm5lci1cIiArICggZGlyZWN0aW9uID8gXCJ0b3BcIiA6IFwibGVmdFwiIClcblx0XHRcdFx0fSxcblx0XHRcdFx0bGFzdDoge1xuXHRcdFx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tb3BlblwiOiBkaXJlY3Rpb24gPyBcIlwiIDogXCJ1aS1jb3JuZXItdHJcIixcblx0XHRcdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLWNsb3NlZFwiOiBcInVpLWNvcm5lci1cIiArICggZGlyZWN0aW9uID8gXCJib3R0b21cIiA6IFwicmlnaHRcIiApXG5cdFx0XHRcdH0sXG5cdFx0XHRcdG9ubHk6IHtcblx0XHRcdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLW9wZW5cIjogXCJ1aS1jb3JuZXItdG9wXCIsXG5cdFx0XHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1jbG9zZWRcIjogXCJ1aS1jb3JuZXItYWxsXCJcblx0XHRcdFx0fVxuXG5cdFx0XHR9WyBwb3NpdGlvbiBdXG5cdFx0fTtcblx0fSxcblxuXHRfcmVzb2x2ZUNsYXNzZXNWYWx1ZXM6IGZ1bmN0aW9uKCBjbGFzc2VzLCBpbnN0YW5jZSApIHtcblx0XHR2YXIgcmVzdWx0ID0ge307XG5cdFx0JC5lYWNoKCBjbGFzc2VzLCBmdW5jdGlvbigga2V5ICkge1xuXHRcdFx0dmFyIGN1cnJlbnQgPSBpbnN0YW5jZS5vcHRpb25zLmNsYXNzZXNbIGtleSBdIHx8IFwiXCI7XG5cdFx0XHRjdXJyZW50ID0gJC50cmltKCBjdXJyZW50LnJlcGxhY2UoIGNvbnRyb2xncm91cENvcm5lclJlZ2V4LCBcIlwiICkgKTtcblx0XHRcdHJlc3VsdFsga2V5IF0gPSAoIGN1cnJlbnQgKyBcIiBcIiArIGNsYXNzZXNbIGtleSBdICkucmVwbGFjZSggL1xccysvZywgXCIgXCIgKTtcblx0XHR9ICk7XG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRpZiAoIGtleSA9PT0gXCJkaXJlY3Rpb25cIiApIHtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBcInVpLWNvbnRyb2xncm91cC1cIiArIHRoaXMub3B0aW9ucy5kaXJlY3Rpb24gKTtcblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXHRcdGlmICgga2V5ID09PSBcImRpc2FibGVkXCIgKSB7XG5cdFx0XHR0aGlzLl9jYWxsQ2hpbGRNZXRob2QoIHZhbHVlID8gXCJkaXNhYmxlXCIgOiBcImVuYWJsZVwiICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5yZWZyZXNoKCk7XG5cdH0sXG5cblx0cmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGNoaWxkcmVuLFxuXHRcdFx0dGhhdCA9IHRoaXM7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1jb250cm9sZ3JvdXAgdWktY29udHJvbGdyb3VwLVwiICsgdGhpcy5vcHRpb25zLmRpcmVjdGlvbiApO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlyZWN0aW9uID09PSBcImhvcml6b250YWxcIiApIHtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCBudWxsLCBcInVpLWhlbHBlci1jbGVhcmZpeFwiICk7XG5cdFx0fVxuXHRcdHRoaXMuX2luaXRXaWRnZXRzKCk7XG5cblx0XHRjaGlsZHJlbiA9IHRoaXMuY2hpbGRXaWRnZXRzO1xuXG5cdFx0Ly8gV2UgZmlsdGVyIGhlcmUgYmVjYXVzZSB3ZSBuZWVkIHRvIHRyYWNrIGFsbCBjaGlsZFdpZGdldHMgbm90IGp1c3QgdGhlIHZpc2libGUgb25lc1xuXHRcdGlmICggdGhpcy5vcHRpb25zLm9ubHlWaXNpYmxlICkge1xuXHRcdFx0Y2hpbGRyZW4gPSBjaGlsZHJlbi5maWx0ZXIoIFwiOnZpc2libGVcIiApO1xuXHRcdH1cblxuXHRcdGlmICggY2hpbGRyZW4ubGVuZ3RoICkge1xuXG5cdFx0XHQvLyBXZSBkbyB0aGlzIGxhc3QgYmVjYXVzZSB3ZSBuZWVkIHRvIG1ha2Ugc3VyZSBhbGwgZW5oYW5jbWVudCBpcyBkb25lXG5cdFx0XHQvLyBiZWZvcmUgZGV0ZXJtaW5pbmcgZmlyc3QgYW5kIGxhc3Rcblx0XHRcdCQuZWFjaCggWyBcImZpcnN0XCIsIFwibGFzdFwiIF0sIGZ1bmN0aW9uKCBpbmRleCwgdmFsdWUgKSB7XG5cdFx0XHRcdHZhciBpbnN0YW5jZSA9IGNoaWxkcmVuWyB2YWx1ZSBdKCkuZGF0YSggXCJ1aS1jb250cm9sZ3JvdXAtZGF0YVwiICk7XG5cblx0XHRcdFx0aWYgKCBpbnN0YW5jZSAmJiB0aGF0WyBcIl9cIiArIGluc3RhbmNlLndpZGdldE5hbWUgKyBcIk9wdGlvbnNcIiBdICkge1xuXHRcdFx0XHRcdHZhciBvcHRpb25zID0gdGhhdFsgXCJfXCIgKyBpbnN0YW5jZS53aWRnZXROYW1lICsgXCJPcHRpb25zXCIgXShcblx0XHRcdFx0XHRcdGNoaWxkcmVuLmxlbmd0aCA9PT0gMSA/IFwib25seVwiIDogdmFsdWVcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdG9wdGlvbnMuY2xhc3NlcyA9IHRoYXQuX3Jlc29sdmVDbGFzc2VzVmFsdWVzKCBvcHRpb25zLmNsYXNzZXMsIGluc3RhbmNlICk7XG5cdFx0XHRcdFx0aW5zdGFuY2UuZWxlbWVudFsgaW5zdGFuY2Uud2lkZ2V0TmFtZSBdKCBvcHRpb25zICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhhdC5fdXBkYXRlQ29ybmVyQ2xhc3MoIGNoaWxkcmVuWyB2YWx1ZSBdKCksIHZhbHVlICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblxuXHRcdFx0Ly8gRmluYWxseSBjYWxsIHRoZSByZWZyZXNoIG1ldGhvZCBvbiBlYWNoIG9mIHRoZSBjaGlsZCB3aWRnZXRzLlxuXHRcdFx0dGhpcy5fY2FsbENoaWxkTWV0aG9kKCBcInJlZnJlc2hcIiApO1xuXHRcdH1cblx0fVxufSApO1xuXG4vKiFcbiAqIGpRdWVyeSBVSSBDaGVja2JveHJhZGlvIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBDaGVja2JveHJhZGlvXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogRW5oYW5jZXMgYSBmb3JtIHdpdGggbXVsdGlwbGUgdGhlbWVhYmxlIGNoZWNrYm94ZXMgb3IgcmFkaW8gYnV0dG9ucy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9jaGVja2JveHJhZGlvL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2NoZWNrYm94cmFkaW8vXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9idXR0b24uY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY2hlY2tib3hyYWRpby5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxuJC53aWRnZXQoIFwidWkuY2hlY2tib3hyYWRpb1wiLCBbICQudWkuZm9ybVJlc2V0TWl4aW4sIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0b3B0aW9uczoge1xuXHRcdGRpc2FibGVkOiBudWxsLFxuXHRcdGxhYmVsOiBudWxsLFxuXHRcdGljb246IHRydWUsXG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS1jaGVja2JveHJhZGlvLWxhYmVsXCI6IFwidWktY29ybmVyLWFsbFwiLFxuXHRcdFx0XCJ1aS1jaGVja2JveHJhZGlvLWljb25cIjogXCJ1aS1jb3JuZXItYWxsXCJcblx0XHR9XG5cdH0sXG5cblx0X2dldENyZWF0ZU9wdGlvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBkaXNhYmxlZCwgbGFiZWxzO1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMuX3N1cGVyKCkgfHwge307XG5cblx0XHQvLyBXZSByZWFkIHRoZSB0eXBlIGhlcmUsIGJlY2F1c2UgaXQgbWFrZXMgbW9yZSBzZW5zZSB0byB0aHJvdyBhIGVsZW1lbnQgdHlwZSBlcnJvciBmaXJzdCxcblx0XHQvLyByYXRoZXIgdGhlbiB0aGUgZXJyb3IgZm9yIGxhY2sgb2YgYSBsYWJlbC4gT2Z0ZW4gaWYgaXRzIHRoZSB3cm9uZyB0eXBlLCBpdFxuXHRcdC8vIHdvbid0IGhhdmUgYSBsYWJlbCAoZS5nLiBjYWxsaW5nIG9uIGEgZGl2LCBidG4sIGV0Yylcblx0XHR0aGlzLl9yZWFkVHlwZSgpO1xuXG5cdFx0bGFiZWxzID0gdGhpcy5lbGVtZW50LmxhYmVscygpO1xuXG5cdFx0Ly8gSWYgdGhlcmUgYXJlIG11bHRpcGxlIGxhYmVscywgdXNlIHRoZSBsYXN0IG9uZVxuXHRcdHRoaXMubGFiZWwgPSAkKCBsYWJlbHNbIGxhYmVscy5sZW5ndGggLSAxIF0gKTtcblx0XHRpZiAoICF0aGlzLmxhYmVsLmxlbmd0aCApIHtcblx0XHRcdCQuZXJyb3IoIFwiTm8gbGFiZWwgZm91bmQgZm9yIGNoZWNrYm94cmFkaW8gd2lkZ2V0XCIgKTtcblx0XHR9XG5cblx0XHR0aGlzLm9yaWdpbmFsTGFiZWwgPSBcIlwiO1xuXG5cdFx0Ly8gV2UgbmVlZCB0byBnZXQgdGhlIGxhYmVsIHRleHQgYnV0IHRoaXMgbWF5IGFsc28gbmVlZCB0byBtYWtlIHN1cmUgaXQgZG9lcyBub3QgY29udGFpbiB0aGVcblx0XHQvLyBpbnB1dCBpdHNlbGYuXG5cdFx0dGhpcy5sYWJlbC5jb250ZW50cygpLm5vdCggdGhpcy5lbGVtZW50WyAwIF0gKS5lYWNoKCBmdW5jdGlvbigpIHtcblxuXHRcdFx0Ly8gVGhlIGxhYmVsIGNvbnRlbnRzIGNvdWxkIGJlIHRleHQsIGh0bWwsIG9yIGEgbWl4LiBXZSBjb25jYXQgZWFjaCBlbGVtZW50IHRvIGdldCBhXG5cdFx0XHQvLyBzdHJpbmcgcmVwcmVzZW50YXRpb24gb2YgdGhlIGxhYmVsLCB3aXRob3V0IHRoZSBpbnB1dCBhcyBwYXJ0IG9mIGl0LlxuXHRcdFx0dGhhdC5vcmlnaW5hbExhYmVsICs9IHRoaXMubm9kZVR5cGUgPT09IDMgPyAkKCB0aGlzICkudGV4dCgpIDogdGhpcy5vdXRlckhUTUw7XG5cdFx0fSApO1xuXG5cdFx0Ly8gU2V0IHRoZSBsYWJlbCBvcHRpb24gaWYgd2UgZm91bmQgbGFiZWwgdGV4dFxuXHRcdGlmICggdGhpcy5vcmlnaW5hbExhYmVsICkge1xuXHRcdFx0b3B0aW9ucy5sYWJlbCA9IHRoaXMub3JpZ2luYWxMYWJlbDtcblx0XHR9XG5cblx0XHRkaXNhYmxlZCA9IHRoaXMuZWxlbWVudFsgMCBdLmRpc2FibGVkO1xuXHRcdGlmICggZGlzYWJsZWQgIT0gbnVsbCApIHtcblx0XHRcdG9wdGlvbnMuZGlzYWJsZWQgPSBkaXNhYmxlZDtcblx0XHR9XG5cdFx0cmV0dXJuIG9wdGlvbnM7XG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGNoZWNrZWQgPSB0aGlzLmVsZW1lbnRbIDAgXS5jaGVja2VkO1xuXG5cdFx0dGhpcy5fYmluZEZvcm1SZXNldEhhbmRsZXIoKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkID09IG51bGwgKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMuZGlzYWJsZWQgPSB0aGlzLmVsZW1lbnRbIDAgXS5kaXNhYmxlZDtcblx0XHR9XG5cblx0XHR0aGlzLl9zZXRPcHRpb24oIFwiZGlzYWJsZWRcIiwgdGhpcy5vcHRpb25zLmRpc2FibGVkICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktY2hlY2tib3hyYWRpb1wiLCBcInVpLWhlbHBlci1oaWRkZW4tYWNjZXNzaWJsZVwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMubGFiZWwsIFwidWktY2hlY2tib3hyYWRpby1sYWJlbFwiLCBcInVpLWJ1dHRvbiB1aS13aWRnZXRcIiApO1xuXG5cdFx0aWYgKCB0aGlzLnR5cGUgPT09IFwicmFkaW9cIiApIHtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmxhYmVsLCBcInVpLWNoZWNrYm94cmFkaW8tcmFkaW8tbGFiZWxcIiApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmxhYmVsICYmIHRoaXMub3B0aW9ucy5sYWJlbCAhPT0gdGhpcy5vcmlnaW5hbExhYmVsICkge1xuXHRcdFx0dGhpcy5fdXBkYXRlTGFiZWwoKTtcblx0XHR9IGVsc2UgaWYgKCB0aGlzLm9yaWdpbmFsTGFiZWwgKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMubGFiZWwgPSB0aGlzLm9yaWdpbmFsTGFiZWw7XG5cdFx0fVxuXG5cdFx0dGhpcy5fZW5oYW5jZSgpO1xuXG5cdFx0aWYgKCBjaGVja2VkICkge1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMubGFiZWwsIFwidWktY2hlY2tib3hyYWRpby1jaGVja2VkXCIsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdGlmICggdGhpcy5pY29uICkge1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5pY29uLCBudWxsLCBcInVpLXN0YXRlLWhvdmVyXCIgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLl9vbigge1xuXHRcdFx0Y2hhbmdlOiBcIl90b2dnbGVDbGFzc2VzXCIsXG5cdFx0XHRmb2N1czogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmxhYmVsLCBudWxsLCBcInVpLXN0YXRlLWZvY3VzIHVpLXZpc3VhbC1mb2N1c1wiICk7XG5cdFx0XHR9LFxuXHRcdFx0Ymx1cjogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmxhYmVsLCBudWxsLCBcInVpLXN0YXRlLWZvY3VzIHVpLXZpc3VhbC1mb2N1c1wiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9yZWFkVHlwZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG5vZGVOYW1lID0gdGhpcy5lbGVtZW50WyAwIF0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHR0aGlzLnR5cGUgPSB0aGlzLmVsZW1lbnRbIDAgXS50eXBlO1xuXHRcdGlmICggbm9kZU5hbWUgIT09IFwiaW5wdXRcIiB8fCAhL3JhZGlvfGNoZWNrYm94Ly50ZXN0KCB0aGlzLnR5cGUgKSApIHtcblx0XHRcdCQuZXJyb3IoIFwiQ2FuJ3QgY3JlYXRlIGNoZWNrYm94cmFkaW8gb24gZWxlbWVudC5ub2RlTmFtZT1cIiArIG5vZGVOYW1lICtcblx0XHRcdFx0XCIgYW5kIGVsZW1lbnQudHlwZT1cIiArIHRoaXMudHlwZSApO1xuXHRcdH1cblx0fSxcblxuXHQvLyBTdXBwb3J0IGpRdWVyeSBNb2JpbGUgZW5oYW5jZWQgb3B0aW9uXG5cdF9lbmhhbmNlOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl91cGRhdGVJY29uKCB0aGlzLmVsZW1lbnRbIDAgXS5jaGVja2VkICk7XG5cdH0sXG5cblx0d2lkZ2V0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5sYWJlbDtcblx0fSxcblxuXHRfZ2V0UmFkaW9Hcm91cDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGdyb3VwO1xuXHRcdHZhciBuYW1lID0gdGhpcy5lbGVtZW50WyAwIF0ubmFtZTtcblx0XHR2YXIgbmFtZVNlbGVjdG9yID0gXCJpbnB1dFtuYW1lPSdcIiArICQudWkuZXNjYXBlU2VsZWN0b3IoIG5hbWUgKSArIFwiJ11cIjtcblxuXHRcdGlmICggIW5hbWUgKSB7XG5cdFx0XHRyZXR1cm4gJCggW10gKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuZm9ybS5sZW5ndGggKSB7XG5cdFx0XHRncm91cCA9ICQoIHRoaXMuZm9ybVsgMCBdLmVsZW1lbnRzICkuZmlsdGVyKCBuYW1lU2VsZWN0b3IgKTtcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBOb3QgaW5zaWRlIGEgZm9ybSwgY2hlY2sgYWxsIGlucHV0cyB0aGF0IGFsc28gYXJlIG5vdCBpbnNpZGUgYSBmb3JtXG5cdFx0XHRncm91cCA9ICQoIG5hbWVTZWxlY3RvciApLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiAkKCB0aGlzICkuZm9ybSgpLmxlbmd0aCA9PT0gMDtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZ3JvdXAubm90KCB0aGlzLmVsZW1lbnQgKTtcblx0fSxcblxuXHRfdG9nZ2xlQ2xhc3NlczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGNoZWNrZWQgPSB0aGlzLmVsZW1lbnRbIDAgXS5jaGVja2VkO1xuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCB0aGlzLmxhYmVsLCBcInVpLWNoZWNrYm94cmFkaW8tY2hlY2tlZFwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiLCBjaGVja2VkICk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5pY29uICYmIHRoaXMudHlwZSA9PT0gXCJjaGVja2JveFwiICkge1xuXHRcdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIHRoaXMuaWNvbiwgbnVsbCwgXCJ1aS1pY29uLWNoZWNrIHVpLXN0YXRlLWNoZWNrZWRcIiwgY2hlY2tlZCApXG5cdFx0XHRcdC5fdG9nZ2xlQ2xhc3MoIHRoaXMuaWNvbiwgbnVsbCwgXCJ1aS1pY29uLWJsYW5rXCIsICFjaGVja2VkICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLnR5cGUgPT09IFwicmFkaW9cIiApIHtcblx0XHRcdHRoaXMuX2dldFJhZGlvR3JvdXAoKVxuXHRcdFx0XHQuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0dmFyIGluc3RhbmNlID0gJCggdGhpcyApLmNoZWNrYm94cmFkaW8oIFwiaW5zdGFuY2VcIiApO1xuXG5cdFx0XHRcdFx0aWYgKCBpbnN0YW5jZSApIHtcblx0XHRcdFx0XHRcdGluc3RhbmNlLl9yZW1vdmVDbGFzcyggaW5zdGFuY2UubGFiZWwsXG5cdFx0XHRcdFx0XHRcdFwidWktY2hlY2tib3hyYWRpby1jaGVja2VkXCIsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHR9XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3VuYmluZEZvcm1SZXNldEhhbmRsZXIoKTtcblxuXHRcdGlmICggdGhpcy5pY29uICkge1xuXHRcdFx0dGhpcy5pY29uLnJlbW92ZSgpO1xuXHRcdFx0dGhpcy5pY29uU3BhY2UucmVtb3ZlKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXG5cdFx0Ly8gV2UgZG9uJ3QgYWxsb3cgdGhlIHZhbHVlIHRvIGJlIHNldCB0byBub3RoaW5nXG5cdFx0aWYgKCBrZXkgPT09IFwibGFiZWxcIiAmJiAhdmFsdWUgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdGlmICgga2V5ID09PSBcImRpc2FibGVkXCIgKSB7XG5cdFx0XHR0aGlzLl90b2dnbGVDbGFzcyggdGhpcy5sYWJlbCwgbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiLCB2YWx1ZSApO1xuXHRcdFx0dGhpcy5lbGVtZW50WyAwIF0uZGlzYWJsZWQgPSB2YWx1ZTtcblxuXHRcdFx0Ly8gRG9uJ3QgcmVmcmVzaCB3aGVuIHNldHRpbmcgZGlzYWJsZWRcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5yZWZyZXNoKCk7XG5cdH0sXG5cblx0X3VwZGF0ZUljb246IGZ1bmN0aW9uKCBjaGVja2VkICkge1xuXHRcdHZhciB0b0FkZCA9IFwidWktaWNvbiB1aS1pY29uLWJhY2tncm91bmQgXCI7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5pY29uICkge1xuXHRcdFx0aWYgKCAhdGhpcy5pY29uICkge1xuXHRcdFx0XHR0aGlzLmljb24gPSAkKCBcIjxzcGFuPlwiICk7XG5cdFx0XHRcdHRoaXMuaWNvblNwYWNlID0gJCggXCI8c3Bhbj4gPC9zcGFuPlwiICk7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmljb25TcGFjZSwgXCJ1aS1jaGVja2JveHJhZGlvLWljb24tc3BhY2VcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRoaXMudHlwZSA9PT0gXCJjaGVja2JveFwiICkge1xuXHRcdFx0XHR0b0FkZCArPSBjaGVja2VkID8gXCJ1aS1pY29uLWNoZWNrIHVpLXN0YXRlLWNoZWNrZWRcIiA6IFwidWktaWNvbi1ibGFua1wiO1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5pY29uLCBudWxsLCBjaGVja2VkID8gXCJ1aS1pY29uLWJsYW5rXCIgOiBcInVpLWljb24tY2hlY2tcIiApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dG9BZGQgKz0gXCJ1aS1pY29uLWJsYW5rXCI7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5pY29uLCBcInVpLWNoZWNrYm94cmFkaW8taWNvblwiLCB0b0FkZCApO1xuXHRcdFx0aWYgKCAhY2hlY2tlZCApIHtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuaWNvbiwgbnVsbCwgXCJ1aS1pY29uLWNoZWNrIHVpLXN0YXRlLWNoZWNrZWRcIiApO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5pY29uLnByZXBlbmRUbyggdGhpcy5sYWJlbCApLmFmdGVyKCB0aGlzLmljb25TcGFjZSApO1xuXHRcdH0gZWxzZSBpZiAoIHRoaXMuaWNvbiAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0dGhpcy5pY29uLnJlbW92ZSgpO1xuXHRcdFx0dGhpcy5pY29uU3BhY2UucmVtb3ZlKCk7XG5cdFx0XHRkZWxldGUgdGhpcy5pY29uO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlTGFiZWw6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly8gUmVtb3ZlIHRoZSBjb250ZW50cyBvZiB0aGUgbGFiZWwgKCBtaW51cyB0aGUgaWNvbiwgaWNvbiBzcGFjZSwgYW5kIGlucHV0IClcblx0XHR2YXIgY29udGVudHMgPSB0aGlzLmxhYmVsLmNvbnRlbnRzKCkubm90KCB0aGlzLmVsZW1lbnRbIDAgXSApO1xuXHRcdGlmICggdGhpcy5pY29uICkge1xuXHRcdFx0Y29udGVudHMgPSBjb250ZW50cy5ub3QoIHRoaXMuaWNvblsgMCBdICk7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5pY29uU3BhY2UgKSB7XG5cdFx0XHRjb250ZW50cyA9IGNvbnRlbnRzLm5vdCggdGhpcy5pY29uU3BhY2VbIDAgXSApO1xuXHRcdH1cblx0XHRjb250ZW50cy5yZW1vdmUoKTtcblxuXHRcdHRoaXMubGFiZWwuYXBwZW5kKCB0aGlzLm9wdGlvbnMubGFiZWwgKTtcblx0fSxcblxuXHRyZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgY2hlY2tlZCA9IHRoaXMuZWxlbWVudFsgMCBdLmNoZWNrZWQsXG5cdFx0XHRpc0Rpc2FibGVkID0gdGhpcy5lbGVtZW50WyAwIF0uZGlzYWJsZWQ7XG5cblx0XHR0aGlzLl91cGRhdGVJY29uKCBjaGVja2VkICk7XG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIHRoaXMubGFiZWwsIFwidWktY2hlY2tib3hyYWRpby1jaGVja2VkXCIsIFwidWktc3RhdGUtYWN0aXZlXCIsIGNoZWNrZWQgKTtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5sYWJlbCAhPT0gbnVsbCApIHtcblx0XHRcdHRoaXMuX3VwZGF0ZUxhYmVsKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCBpc0Rpc2FibGVkICE9PSB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHR0aGlzLl9zZXRPcHRpb25zKCB7IFwiZGlzYWJsZWRcIjogaXNEaXNhYmxlZCB9ICk7XG5cdFx0fVxuXHR9XG5cbn0gXSApO1xuXG52YXIgd2lkZ2V0c0NoZWNrYm94cmFkaW8gPSAkLnVpLmNoZWNrYm94cmFkaW87XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgQnV0dG9uIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBCdXR0b25cbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBFbmhhbmNlcyBhIGZvcm0gd2l0aCB0aGVtZWFibGUgYnV0dG9ucy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9idXR0b24vXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vYnV0dG9uL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvYnV0dG9uLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG4kLndpZGdldCggXCJ1aS5idXR0b25cIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRkZWZhdWx0RWxlbWVudDogXCI8YnV0dG9uPlwiLFxuXHRvcHRpb25zOiB7XG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS1idXR0b25cIjogXCJ1aS1jb3JuZXItYWxsXCJcblx0XHR9LFxuXHRcdGRpc2FibGVkOiBudWxsLFxuXHRcdGljb246IG51bGwsXG5cdFx0aWNvblBvc2l0aW9uOiBcImJlZ2lubmluZ1wiLFxuXHRcdGxhYmVsOiBudWxsLFxuXHRcdHNob3dMYWJlbDogdHJ1ZVxuXHR9LFxuXG5cdF9nZXRDcmVhdGVPcHRpb25zOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZGlzYWJsZWQsXG5cblx0XHRcdC8vIFRoaXMgaXMgdG8gc3VwcG9ydCBjYXNlcyBsaWtlIGluIGpRdWVyeSBNb2JpbGUgd2hlcmUgdGhlIGJhc2Ugd2lkZ2V0IGRvZXMgaGF2ZVxuXHRcdFx0Ly8gYW4gaW1wbGVtZW50YXRpb24gb2YgX2dldENyZWF0ZU9wdGlvbnNcblx0XHRcdG9wdGlvbnMgPSB0aGlzLl9zdXBlcigpIHx8IHt9O1xuXG5cdFx0dGhpcy5pc0lucHV0ID0gdGhpcy5lbGVtZW50LmlzKCBcImlucHV0XCIgKTtcblxuXHRcdGRpc2FibGVkID0gdGhpcy5lbGVtZW50WyAwIF0uZGlzYWJsZWQ7XG5cdFx0aWYgKCBkaXNhYmxlZCAhPSBudWxsICkge1xuXHRcdFx0b3B0aW9ucy5kaXNhYmxlZCA9IGRpc2FibGVkO1xuXHRcdH1cblxuXHRcdHRoaXMub3JpZ2luYWxMYWJlbCA9IHRoaXMuaXNJbnB1dCA/IHRoaXMuZWxlbWVudC52YWwoKSA6IHRoaXMuZWxlbWVudC5odG1sKCk7XG5cdFx0aWYgKCB0aGlzLm9yaWdpbmFsTGFiZWwgKSB7XG5cdFx0XHRvcHRpb25zLmxhYmVsID0gdGhpcy5vcmlnaW5hbExhYmVsO1xuXHRcdH1cblxuXHRcdHJldHVybiBvcHRpb25zO1xuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggIXRoaXMub3B0aW9uLnNob3dMYWJlbCAmICF0aGlzLm9wdGlvbnMuaWNvbiApIHtcblx0XHRcdHRoaXMub3B0aW9ucy5zaG93TGFiZWwgPSB0cnVlO1xuXHRcdH1cblxuXHRcdC8vIFdlIGhhdmUgdG8gY2hlY2sgdGhlIG9wdGlvbiBhZ2FpbiBoZXJlIGV2ZW4gdGhvdWdoIHdlIGRpZCBpbiBfZ2V0Q3JlYXRlT3B0aW9ucyxcblx0XHQvLyBiZWNhdXNlIG51bGwgbWF5IGhhdmUgYmVlbiBwYXNzZWQgb24gaW5pdCB3aGljaCB3b3VsZCBvdmVycmlkZSB3aGF0IHdhcyBzZXQgaW5cblx0XHQvLyBfZ2V0Q3JlYXRlT3B0aW9uc1xuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkID09IG51bGwgKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMuZGlzYWJsZWQgPSB0aGlzLmVsZW1lbnRbIDAgXS5kaXNhYmxlZCB8fCBmYWxzZTtcblx0XHR9XG5cblx0XHR0aGlzLmhhc1RpdGxlID0gISF0aGlzLmVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiICk7XG5cblx0XHQvLyBDaGVjayB0byBzZWUgaWYgdGhlIGxhYmVsIG5lZWRzIHRvIGJlIHNldCBvciBpZiBpdHMgYWxyZWFkeSBjb3JyZWN0XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMubGFiZWwgJiYgdGhpcy5vcHRpb25zLmxhYmVsICE9PSB0aGlzLm9yaWdpbmFsTGFiZWwgKSB7XG5cdFx0XHRpZiAoIHRoaXMuaXNJbnB1dCApIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LnZhbCggdGhpcy5vcHRpb25zLmxhYmVsICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQuaHRtbCggdGhpcy5vcHRpb25zLmxhYmVsICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWJ1dHRvblwiLCBcInVpLXdpZGdldFwiICk7XG5cdFx0dGhpcy5fc2V0T3B0aW9uKCBcImRpc2FibGVkXCIsIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApO1xuXHRcdHRoaXMuX2VuaGFuY2UoKTtcblxuXHRcdGlmICggdGhpcy5lbGVtZW50LmlzKCBcImFcIiApICkge1xuXHRcdFx0dGhpcy5fb24oIHtcblx0XHRcdFx0XCJrZXl1cFwiOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdFx0aWYgKCBldmVudC5rZXlDb2RlID09PSAkLnVpLmtleUNvZGUuU1BBQ0UgKSB7XG5cdFx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBQaGFudG9tSlMgPD0gMS45LCBJRSA4IE9ubHlcblx0XHRcdFx0XHRcdC8vIElmIGEgbmF0aXZlIGNsaWNrIGlzIGF2YWlsYWJsZSB1c2UgaXQgc28gd2UgYWN0dWFsbHkgY2F1c2UgbmF2aWdhdGlvblxuXHRcdFx0XHRcdFx0Ly8gb3RoZXJ3aXNlIGp1c3QgdHJpZ2dlciBhIGNsaWNrIGV2ZW50XG5cdFx0XHRcdFx0XHRpZiAoIHRoaXMuZWxlbWVudFsgMCBdLmNsaWNrICkge1xuXHRcdFx0XHRcdFx0XHR0aGlzLmVsZW1lbnRbIDAgXS5jbGljaygpO1xuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50LnRyaWdnZXIoIFwiY2xpY2tcIiApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH1cblx0fSxcblxuXHRfZW5oYW5jZTogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAhdGhpcy5lbGVtZW50LmlzKCBcImJ1dHRvblwiICkgKSB7XG5cdFx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJyb2xlXCIsIFwiYnV0dG9uXCIgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5pY29uICkge1xuXHRcdFx0dGhpcy5fdXBkYXRlSWNvbiggXCJpY29uXCIsIHRoaXMub3B0aW9ucy5pY29uICk7XG5cdFx0XHR0aGlzLl91cGRhdGVUb29sdGlwKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGVUb29sdGlwOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLnRpdGxlID0gdGhpcy5lbGVtZW50LmF0dHIoIFwidGl0bGVcIiApO1xuXG5cdFx0aWYgKCAhdGhpcy5vcHRpb25zLnNob3dMYWJlbCAmJiAhdGhpcy50aXRsZSApIHtcblx0XHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcInRpdGxlXCIsIHRoaXMub3B0aW9ucy5sYWJlbCApO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlSWNvbjogZnVuY3Rpb24oIG9wdGlvbiwgdmFsdWUgKSB7XG5cdFx0dmFyIGljb24gPSBvcHRpb24gIT09IFwiaWNvblBvc2l0aW9uXCIsXG5cdFx0XHRwb3NpdGlvbiA9IGljb24gPyB0aGlzLm9wdGlvbnMuaWNvblBvc2l0aW9uIDogdmFsdWUsXG5cdFx0XHRkaXNwbGF5QmxvY2sgPSBwb3NpdGlvbiA9PT0gXCJ0b3BcIiB8fCBwb3NpdGlvbiA9PT0gXCJib3R0b21cIjtcblxuXHRcdC8vIENyZWF0ZSBpY29uXG5cdFx0aWYgKCAhdGhpcy5pY29uICkge1xuXHRcdFx0dGhpcy5pY29uID0gJCggXCI8c3Bhbj5cIiApO1xuXG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5pY29uLCBcInVpLWJ1dHRvbi1pY29uXCIsIFwidWktaWNvblwiICk7XG5cblx0XHRcdGlmICggIXRoaXMub3B0aW9ucy5zaG93TGFiZWwgKSB7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWJ1dHRvbi1pY29uLW9ubHlcIiApO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSBpZiAoIGljb24gKSB7XG5cblx0XHRcdC8vIElmIHdlIGFyZSB1cGRhdGluZyB0aGUgaWNvbiByZW1vdmUgdGhlIG9sZCBpY29uIGNsYXNzXG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5pY29uLCBudWxsLCB0aGlzLm9wdGlvbnMuaWNvbiApO1xuXHRcdH1cblxuXHRcdC8vIElmIHdlIGFyZSB1cGRhdGluZyB0aGUgaWNvbiBhZGQgdGhlIG5ldyBpY29uIGNsYXNzXG5cdFx0aWYgKCBpY29uICkge1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaWNvbiwgbnVsbCwgdmFsdWUgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9hdHRhY2hJY29uKCBwb3NpdGlvbiApO1xuXG5cdFx0Ly8gSWYgdGhlIGljb24gaXMgb24gdG9wIG9yIGJvdHRvbSB3ZSBuZWVkIHRvIGFkZCB0aGUgdWktd2lkZ2V0LWljb24tYmxvY2sgY2xhc3MgYW5kIHJlbW92ZVxuXHRcdC8vIHRoZSBpY29uU3BhY2UgaWYgdGhlcmUgaXMgb25lLlxuXHRcdGlmICggZGlzcGxheUJsb2NrICkge1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaWNvbiwgbnVsbCwgXCJ1aS13aWRnZXQtaWNvbi1ibG9ja1wiICk7XG5cdFx0XHRpZiAoIHRoaXMuaWNvblNwYWNlICkge1xuXHRcdFx0XHR0aGlzLmljb25TcGFjZS5yZW1vdmUoKTtcblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBQb3NpdGlvbiBpcyBiZWdpbm5pbmcgb3IgZW5kIHNvIHJlbW92ZSB0aGUgdWktd2lkZ2V0LWljb24tYmxvY2sgY2xhc3MgYW5kIGFkZCB0aGVcblx0XHRcdC8vIHNwYWNlIGlmIGl0IGRvZXMgbm90IGV4aXN0XG5cdFx0XHRpZiAoICF0aGlzLmljb25TcGFjZSApIHtcblx0XHRcdFx0dGhpcy5pY29uU3BhY2UgPSAkKCBcIjxzcGFuPiA8L3NwYW4+XCIgKTtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaWNvblNwYWNlLCBcInVpLWJ1dHRvbi1pY29uLXNwYWNlXCIgKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmljb24sIG51bGwsIFwidWktd2lnZXQtaWNvbi1ibG9ja1wiICk7XG5cdFx0XHR0aGlzLl9hdHRhY2hJY29uU3BhY2UoIHBvc2l0aW9uICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQXR0ciggXCJyb2xlXCIgKTtcblxuXHRcdGlmICggdGhpcy5pY29uICkge1xuXHRcdFx0dGhpcy5pY29uLnJlbW92ZSgpO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuaWNvblNwYWNlICkge1xuXHRcdFx0dGhpcy5pY29uU3BhY2UucmVtb3ZlKCk7XG5cdFx0fVxuXHRcdGlmICggIXRoaXMuaGFzVGl0bGUgKSB7XG5cdFx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQXR0ciggXCJ0aXRsZVwiICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9hdHRhY2hJY29uU3BhY2U6IGZ1bmN0aW9uKCBpY29uUG9zaXRpb24gKSB7XG5cdFx0dGhpcy5pY29uWyAvXig/OmVuZHxib3R0b20pLy50ZXN0KCBpY29uUG9zaXRpb24gKSA/IFwiYmVmb3JlXCIgOiBcImFmdGVyXCIgXSggdGhpcy5pY29uU3BhY2UgKTtcblx0fSxcblxuXHRfYXR0YWNoSWNvbjogZnVuY3Rpb24oIGljb25Qb3NpdGlvbiApIHtcblx0XHR0aGlzLmVsZW1lbnRbIC9eKD86ZW5kfGJvdHRvbSkvLnRlc3QoIGljb25Qb3NpdGlvbiApID8gXCJhcHBlbmRcIiA6IFwicHJlcGVuZFwiIF0oIHRoaXMuaWNvbiApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb25zOiBmdW5jdGlvbiggb3B0aW9ucyApIHtcblx0XHR2YXIgbmV3U2hvd0xhYmVsID0gb3B0aW9ucy5zaG93TGFiZWwgPT09IHVuZGVmaW5lZCA/XG5cdFx0XHRcdHRoaXMub3B0aW9ucy5zaG93TGFiZWwgOlxuXHRcdFx0XHRvcHRpb25zLnNob3dMYWJlbCxcblx0XHRcdG5ld0ljb24gPSBvcHRpb25zLmljb24gPT09IHVuZGVmaW5lZCA/IHRoaXMub3B0aW9ucy5pY29uIDogb3B0aW9ucy5pY29uO1xuXG5cdFx0aWYgKCAhbmV3U2hvd0xhYmVsICYmICFuZXdJY29uICkge1xuXHRcdFx0b3B0aW9ucy5zaG93TGFiZWwgPSB0cnVlO1xuXHRcdH1cblx0XHR0aGlzLl9zdXBlciggb3B0aW9ucyApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdGlmICgga2V5ID09PSBcImljb25cIiApIHtcblx0XHRcdGlmICggdmFsdWUgKSB7XG5cdFx0XHRcdHRoaXMuX3VwZGF0ZUljb24oIGtleSwgdmFsdWUgKTtcblx0XHRcdH0gZWxzZSBpZiAoIHRoaXMuaWNvbiApIHtcblx0XHRcdFx0dGhpcy5pY29uLnJlbW92ZSgpO1xuXHRcdFx0XHRpZiAoIHRoaXMuaWNvblNwYWNlICkge1xuXHRcdFx0XHRcdHRoaXMuaWNvblNwYWNlLnJlbW92ZSgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwiaWNvblBvc2l0aW9uXCIgKSB7XG5cdFx0XHR0aGlzLl91cGRhdGVJY29uKCBrZXksIHZhbHVlICk7XG5cdFx0fVxuXG5cdFx0Ly8gTWFrZSBzdXJlIHdlIGNhbid0IGVuZCB1cCB3aXRoIGEgYnV0dG9uIHRoYXQgaGFzIG5laXRoZXIgdGV4dCBub3IgaWNvblxuXHRcdGlmICgga2V5ID09PSBcInNob3dMYWJlbFwiICkge1xuXHRcdFx0XHR0aGlzLl90b2dnbGVDbGFzcyggXCJ1aS1idXR0b24taWNvbi1vbmx5XCIsIG51bGwsICF2YWx1ZSApO1xuXHRcdFx0XHR0aGlzLl91cGRhdGVUb29sdGlwKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwibGFiZWxcIiApIHtcblx0XHRcdGlmICggdGhpcy5pc0lucHV0ICkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQudmFsKCB2YWx1ZSApO1xuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBJZiB0aGVyZSBpcyBhbiBpY29uLCBhcHBlbmQgaXQsIGVsc2Ugbm90aGluZyB0aGVuIGFwcGVuZCB0aGUgdmFsdWVcblx0XHRcdFx0Ly8gdGhpcyBhdm9pZHMgcmVtb3ZhbCBvZiB0aGUgaWNvbiB3aGVuIHNldHRpbmcgbGFiZWwgdGV4dFxuXHRcdFx0XHR0aGlzLmVsZW1lbnQuaHRtbCggdmFsdWUgKTtcblx0XHRcdFx0aWYgKCB0aGlzLmljb24gKSB7XG5cdFx0XHRcdFx0dGhpcy5fYXR0YWNoSWNvbiggdGhpcy5vcHRpb25zLmljb25Qb3NpdGlvbiApO1xuXHRcdFx0XHRcdHRoaXMuX2F0dGFjaEljb25TcGFjZSggdGhpcy5vcHRpb25zLmljb25Qb3NpdGlvbiApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdGlmICgga2V5ID09PSBcImRpc2FibGVkXCIgKSB7XG5cdFx0XHR0aGlzLl90b2dnbGVDbGFzcyggbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiLCB2YWx1ZSApO1xuXHRcdFx0dGhpcy5lbGVtZW50WyAwIF0uZGlzYWJsZWQgPSB2YWx1ZTtcblx0XHRcdGlmICggdmFsdWUgKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5ibHVyKCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdHJlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly8gTWFrZSBzdXJlIHRvIG9ubHkgY2hlY2sgZGlzYWJsZWQgaWYgaXRzIGFuIGVsZW1lbnQgdGhhdCBzdXBwb3J0cyB0aGlzIG90aGVyd2lzZVxuXHRcdC8vIGNoZWNrIGZvciB0aGUgZGlzYWJsZWQgY2xhc3MgdG8gZGV0ZXJtaW5lIHN0YXRlXG5cdFx0dmFyIGlzRGlzYWJsZWQgPSB0aGlzLmVsZW1lbnQuaXMoIFwiaW5wdXQsIGJ1dHRvblwiICkgP1xuXHRcdFx0dGhpcy5lbGVtZW50WyAwIF0uZGlzYWJsZWQgOiB0aGlzLmVsZW1lbnQuaGFzQ2xhc3MoIFwidWktYnV0dG9uLWRpc2FibGVkXCIgKTtcblxuXHRcdGlmICggaXNEaXNhYmxlZCAhPT0gdGhpcy5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0dGhpcy5fc2V0T3B0aW9ucyggeyBkaXNhYmxlZDogaXNEaXNhYmxlZCB9ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fdXBkYXRlVG9vbHRpcCgpO1xuXHR9XG59ICk7XG5cbi8vIERFUFJFQ0FURURcbmlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICkge1xuXG5cdC8vIFRleHQgYW5kIEljb25zIG9wdGlvbnNcblx0JC53aWRnZXQoIFwidWkuYnV0dG9uXCIsICQudWkuYnV0dG9uLCB7XG5cdFx0b3B0aW9uczoge1xuXHRcdFx0dGV4dDogdHJ1ZSxcblx0XHRcdGljb25zOiB7XG5cdFx0XHRcdHByaW1hcnk6IG51bGwsXG5cdFx0XHRcdHNlY29uZGFyeTogbnVsbFxuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggdGhpcy5vcHRpb25zLnNob3dMYWJlbCAmJiAhdGhpcy5vcHRpb25zLnRleHQgKSB7XG5cdFx0XHRcdHRoaXMub3B0aW9ucy5zaG93TGFiZWwgPSB0aGlzLm9wdGlvbnMudGV4dDtcblx0XHRcdH1cblx0XHRcdGlmICggIXRoaXMub3B0aW9ucy5zaG93TGFiZWwgJiYgdGhpcy5vcHRpb25zLnRleHQgKSB7XG5cdFx0XHRcdHRoaXMub3B0aW9ucy50ZXh0ID0gdGhpcy5vcHRpb25zLnNob3dMYWJlbDtcblx0XHRcdH1cblx0XHRcdGlmICggIXRoaXMub3B0aW9ucy5pY29uICYmICggdGhpcy5vcHRpb25zLmljb25zLnByaW1hcnkgfHxcblx0XHRcdFx0XHR0aGlzLm9wdGlvbnMuaWNvbnMuc2Vjb25kYXJ5ICkgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5vcHRpb25zLmljb25zLnByaW1hcnkgKSB7XG5cdFx0XHRcdFx0dGhpcy5vcHRpb25zLmljb24gPSB0aGlzLm9wdGlvbnMuaWNvbnMucHJpbWFyeTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aGlzLm9wdGlvbnMuaWNvbiA9IHRoaXMub3B0aW9ucy5pY29ucy5zZWNvbmRhcnk7XG5cdFx0XHRcdFx0dGhpcy5vcHRpb25zLmljb25Qb3NpdGlvbiA9IFwiZW5kXCI7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSBpZiAoIHRoaXMub3B0aW9ucy5pY29uICkge1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMuaWNvbnMucHJpbWFyeSA9IHRoaXMub3B0aW9ucy5pY29uO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fc3VwZXIoKTtcblx0XHR9LFxuXG5cdFx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0XHRpZiAoIGtleSA9PT0gXCJ0ZXh0XCIgKSB7XG5cdFx0XHRcdHRoaXMuX3N1cGVyKCBcInNob3dMYWJlbFwiLCB2YWx1ZSApO1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHRpZiAoIGtleSA9PT0gXCJzaG93TGFiZWxcIiApIHtcblx0XHRcdFx0dGhpcy5vcHRpb25zLnRleHQgPSB2YWx1ZTtcblx0XHRcdH1cblx0XHRcdGlmICgga2V5ID09PSBcImljb25cIiApIHtcblx0XHRcdFx0dGhpcy5vcHRpb25zLmljb25zLnByaW1hcnkgPSB2YWx1ZTtcblx0XHRcdH1cblx0XHRcdGlmICgga2V5ID09PSBcImljb25zXCIgKSB7XG5cdFx0XHRcdGlmICggdmFsdWUucHJpbWFyeSApIHtcblx0XHRcdFx0XHR0aGlzLl9zdXBlciggXCJpY29uXCIsIHZhbHVlLnByaW1hcnkgKTtcblx0XHRcdFx0XHR0aGlzLl9zdXBlciggXCJpY29uUG9zaXRpb25cIiwgXCJiZWdpbm5pbmdcIiApO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZS5zZWNvbmRhcnkgKSB7XG5cdFx0XHRcdFx0dGhpcy5fc3VwZXIoIFwiaWNvblwiLCB2YWx1ZS5zZWNvbmRhcnkgKTtcblx0XHRcdFx0XHR0aGlzLl9zdXBlciggXCJpY29uUG9zaXRpb25cIiwgXCJlbmRcIiApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9zdXBlckFwcGx5KCBhcmd1bWVudHMgKTtcblx0XHR9XG5cdH0gKTtcblxuXHQkLmZuLmJ1dHRvbiA9ICggZnVuY3Rpb24oIG9yaWcgKSB7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCAhdGhpcy5sZW5ndGggfHwgKCB0aGlzLmxlbmd0aCAmJiB0aGlzWyAwIF0udGFnTmFtZSAhPT0gXCJJTlBVVFwiICkgfHxcblx0XHRcdFx0XHQoIHRoaXMubGVuZ3RoICYmIHRoaXNbIDAgXS50YWdOYW1lID09PSBcIklOUFVUXCIgJiYgKFxuXHRcdFx0XHRcdFx0dGhpcy5hdHRyKCBcInR5cGVcIiApICE9PSBcImNoZWNrYm94XCIgJiYgdGhpcy5hdHRyKCBcInR5cGVcIiApICE9PSBcInJhZGlvXCJcblx0XHRcdFx0XHQpICkgKSB7XG5cdFx0XHRcdHJldHVybiBvcmlnLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdH1cblx0XHRcdGlmICggISQudWkuY2hlY2tib3hyYWRpbyApIHtcblx0XHRcdFx0JC5lcnJvciggXCJDaGVja2JveHJhZGlvIHdpZGdldCBtaXNzaW5nXCIgKTtcblx0XHRcdH1cblx0XHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCA9PT0gMCApIHtcblx0XHRcdFx0cmV0dXJuIHRoaXMuY2hlY2tib3hyYWRpbygge1xuXHRcdFx0XHRcdFwiaWNvblwiOiBmYWxzZVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdGhpcy5jaGVja2JveHJhZGlvLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHR9O1xuXHR9ICkoICQuZm4uYnV0dG9uICk7XG5cblx0JC5mbi5idXR0b25zZXQgPSBmdW5jdGlvbigpIHtcblx0XHRpZiAoICEkLnVpLmNvbnRyb2xncm91cCApIHtcblx0XHRcdCQuZXJyb3IoIFwiQ29udHJvbGdyb3VwIHdpZGdldCBtaXNzaW5nXCIgKTtcblx0XHR9XG5cdFx0aWYgKCBhcmd1bWVudHNbIDAgXSA9PT0gXCJvcHRpb25cIiAmJiBhcmd1bWVudHNbIDEgXSA9PT0gXCJpdGVtc1wiICYmIGFyZ3VtZW50c1sgMiBdICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuY29udHJvbGdyb3VwLmFwcGx5KCB0aGlzLFxuXHRcdFx0XHRbIGFyZ3VtZW50c1sgMCBdLCBcIml0ZW1zLmJ1dHRvblwiLCBhcmd1bWVudHNbIDIgXSBdICk7XG5cdFx0fVxuXHRcdGlmICggYXJndW1lbnRzWyAwIF0gPT09IFwib3B0aW9uXCIgJiYgYXJndW1lbnRzWyAxIF0gPT09IFwiaXRlbXNcIiApIHtcblx0XHRcdHJldHVybiB0aGlzLmNvbnRyb2xncm91cC5hcHBseSggdGhpcywgWyBhcmd1bWVudHNbIDAgXSwgXCJpdGVtcy5idXR0b25cIiBdICk7XG5cdFx0fVxuXHRcdGlmICggdHlwZW9mIGFyZ3VtZW50c1sgMCBdID09PSBcIm9iamVjdFwiICYmIGFyZ3VtZW50c1sgMCBdLml0ZW1zICkge1xuXHRcdFx0YXJndW1lbnRzWyAwIF0uaXRlbXMgPSB7XG5cdFx0XHRcdGJ1dHRvbjogYXJndW1lbnRzWyAwIF0uaXRlbXNcblx0XHRcdH07XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLmNvbnRyb2xncm91cC5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdH07XG59XG5cbnZhciB3aWRnZXRzQnV0dG9uID0gJC51aS5idXR0b247XG5cblxuLy8ganNjczpkaXNhYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vKiBqc2NzOmRpc2FibGUgcmVxdWlyZUNhbWVsQ2FzZU9yVXBwZXJDYXNlSWRlbnRpZmllcnMgKi9cbi8qIVxuICogalF1ZXJ5IFVJIERhdGVwaWNrZXIgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IERhdGVwaWNrZXJcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBEaXNwbGF5cyBhIGNhbGVuZGFyIGZyb20gYW4gaW5wdXQgb3IgaW5saW5lIGZvciBzZWxlY3RpbmcgZGF0ZXMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZGF0ZXBpY2tlci9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9kYXRlcGlja2VyL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvZGF0ZXBpY2tlci5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxuJC5leHRlbmQoICQudWksIHsgZGF0ZXBpY2tlcjogeyB2ZXJzaW9uOiBcIjEuMTIuMVwiIH0gfSApO1xuXG52YXIgZGF0ZXBpY2tlcl9pbnN0QWN0aXZlO1xuXG5mdW5jdGlvbiBkYXRlcGlja2VyX2dldFppbmRleCggZWxlbSApIHtcblx0dmFyIHBvc2l0aW9uLCB2YWx1ZTtcblx0d2hpbGUgKCBlbGVtLmxlbmd0aCAmJiBlbGVtWyAwIF0gIT09IGRvY3VtZW50ICkge1xuXG5cdFx0Ly8gSWdub3JlIHotaW5kZXggaWYgcG9zaXRpb24gaXMgc2V0IHRvIGEgdmFsdWUgd2hlcmUgei1pbmRleCBpcyBpZ25vcmVkIGJ5IHRoZSBicm93c2VyXG5cdFx0Ly8gVGhpcyBtYWtlcyBiZWhhdmlvciBvZiB0aGlzIGZ1bmN0aW9uIGNvbnNpc3RlbnQgYWNyb3NzIGJyb3dzZXJzXG5cdFx0Ly8gV2ViS2l0IGFsd2F5cyByZXR1cm5zIGF1dG8gaWYgdGhlIGVsZW1lbnQgaXMgcG9zaXRpb25lZFxuXHRcdHBvc2l0aW9uID0gZWxlbS5jc3MoIFwicG9zaXRpb25cIiApO1xuXHRcdGlmICggcG9zaXRpb24gPT09IFwiYWJzb2x1dGVcIiB8fCBwb3NpdGlvbiA9PT0gXCJyZWxhdGl2ZVwiIHx8IHBvc2l0aW9uID09PSBcImZpeGVkXCIgKSB7XG5cblx0XHRcdC8vIElFIHJldHVybnMgMCB3aGVuIHpJbmRleCBpcyBub3Qgc3BlY2lmaWVkXG5cdFx0XHQvLyBvdGhlciBicm93c2VycyByZXR1cm4gYSBzdHJpbmdcblx0XHRcdC8vIHdlIGlnbm9yZSB0aGUgY2FzZSBvZiBuZXN0ZWQgZWxlbWVudHMgd2l0aCBhbiBleHBsaWNpdCB2YWx1ZSBvZiAwXG5cdFx0XHQvLyA8ZGl2IHN0eWxlPVwiei1pbmRleDogLTEwO1wiPjxkaXYgc3R5bGU9XCJ6LWluZGV4OiAwO1wiPjwvZGl2PjwvZGl2PlxuXHRcdFx0dmFsdWUgPSBwYXJzZUludCggZWxlbS5jc3MoIFwiekluZGV4XCIgKSwgMTAgKTtcblx0XHRcdGlmICggIWlzTmFOKCB2YWx1ZSApICYmIHZhbHVlICE9PSAwICkge1xuXHRcdFx0XHRyZXR1cm4gdmFsdWU7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGVsZW0gPSBlbGVtLnBhcmVudCgpO1xuXHR9XG5cblx0cmV0dXJuIDA7XG59XG4vKiBEYXRlIHBpY2tlciBtYW5hZ2VyLlxuICAgVXNlIHRoZSBzaW5nbGV0b24gaW5zdGFuY2Ugb2YgdGhpcyBjbGFzcywgJC5kYXRlcGlja2VyLCB0byBpbnRlcmFjdCB3aXRoIHRoZSBkYXRlIHBpY2tlci5cbiAgIFNldHRpbmdzIGZvciAoZ3JvdXBzIG9mKSBkYXRlIHBpY2tlcnMgYXJlIG1haW50YWluZWQgaW4gYW4gaW5zdGFuY2Ugb2JqZWN0LFxuICAgYWxsb3dpbmcgbXVsdGlwbGUgZGlmZmVyZW50IHNldHRpbmdzIG9uIHRoZSBzYW1lIHBhZ2UuICovXG5cbmZ1bmN0aW9uIERhdGVwaWNrZXIoKSB7XG5cdHRoaXMuX2N1ckluc3QgPSBudWxsOyAvLyBUaGUgY3VycmVudCBpbnN0YW5jZSBpbiB1c2Vcblx0dGhpcy5fa2V5RXZlbnQgPSBmYWxzZTsgLy8gSWYgdGhlIGxhc3QgZXZlbnQgd2FzIGEga2V5IGV2ZW50XG5cdHRoaXMuX2Rpc2FibGVkSW5wdXRzID0gW107IC8vIExpc3Qgb2YgZGF0ZSBwaWNrZXIgaW5wdXRzIHRoYXQgaGF2ZSBiZWVuIGRpc2FibGVkXG5cdHRoaXMuX2RhdGVwaWNrZXJTaG93aW5nID0gZmFsc2U7IC8vIFRydWUgaWYgdGhlIHBvcHVwIHBpY2tlciBpcyBzaG93aW5nICwgZmFsc2UgaWYgbm90XG5cdHRoaXMuX2luRGlhbG9nID0gZmFsc2U7IC8vIFRydWUgaWYgc2hvd2luZyB3aXRoaW4gYSBcImRpYWxvZ1wiLCBmYWxzZSBpZiBub3Rcblx0dGhpcy5fbWFpbkRpdklkID0gXCJ1aS1kYXRlcGlja2VyLWRpdlwiOyAvLyBUaGUgSUQgb2YgdGhlIG1haW4gZGF0ZXBpY2tlciBkaXZpc2lvblxuXHR0aGlzLl9pbmxpbmVDbGFzcyA9IFwidWktZGF0ZXBpY2tlci1pbmxpbmVcIjsgLy8gVGhlIG5hbWUgb2YgdGhlIGlubGluZSBtYXJrZXIgY2xhc3Ncblx0dGhpcy5fYXBwZW5kQ2xhc3MgPSBcInVpLWRhdGVwaWNrZXItYXBwZW5kXCI7IC8vIFRoZSBuYW1lIG9mIHRoZSBhcHBlbmQgbWFya2VyIGNsYXNzXG5cdHRoaXMuX3RyaWdnZXJDbGFzcyA9IFwidWktZGF0ZXBpY2tlci10cmlnZ2VyXCI7IC8vIFRoZSBuYW1lIG9mIHRoZSB0cmlnZ2VyIG1hcmtlciBjbGFzc1xuXHR0aGlzLl9kaWFsb2dDbGFzcyA9IFwidWktZGF0ZXBpY2tlci1kaWFsb2dcIjsgLy8gVGhlIG5hbWUgb2YgdGhlIGRpYWxvZyBtYXJrZXIgY2xhc3Ncblx0dGhpcy5fZGlzYWJsZUNsYXNzID0gXCJ1aS1kYXRlcGlja2VyLWRpc2FibGVkXCI7IC8vIFRoZSBuYW1lIG9mIHRoZSBkaXNhYmxlZCBjb3ZlcmluZyBtYXJrZXIgY2xhc3Ncblx0dGhpcy5fdW5zZWxlY3RhYmxlQ2xhc3MgPSBcInVpLWRhdGVwaWNrZXItdW5zZWxlY3RhYmxlXCI7IC8vIFRoZSBuYW1lIG9mIHRoZSB1bnNlbGVjdGFibGUgY2VsbCBtYXJrZXIgY2xhc3Ncblx0dGhpcy5fY3VycmVudENsYXNzID0gXCJ1aS1kYXRlcGlja2VyLWN1cnJlbnQtZGF5XCI7IC8vIFRoZSBuYW1lIG9mIHRoZSBjdXJyZW50IGRheSBtYXJrZXIgY2xhc3Ncblx0dGhpcy5fZGF5T3ZlckNsYXNzID0gXCJ1aS1kYXRlcGlja2VyLWRheXMtY2VsbC1vdmVyXCI7IC8vIFRoZSBuYW1lIG9mIHRoZSBkYXkgaG92ZXIgbWFya2VyIGNsYXNzXG5cdHRoaXMucmVnaW9uYWwgPSBbXTsgLy8gQXZhaWxhYmxlIHJlZ2lvbmFsIHNldHRpbmdzLCBpbmRleGVkIGJ5IGxhbmd1YWdlIGNvZGVcblx0dGhpcy5yZWdpb25hbFsgXCJcIiBdID0geyAvLyBEZWZhdWx0IHJlZ2lvbmFsIHNldHRpbmdzXG5cdFx0Y2xvc2VUZXh0OiBcIkRvbmVcIiwgLy8gRGlzcGxheSB0ZXh0IGZvciBjbG9zZSBsaW5rXG5cdFx0cHJldlRleHQ6IFwiUHJldlwiLCAvLyBEaXNwbGF5IHRleHQgZm9yIHByZXZpb3VzIG1vbnRoIGxpbmtcblx0XHRuZXh0VGV4dDogXCJOZXh0XCIsIC8vIERpc3BsYXkgdGV4dCBmb3IgbmV4dCBtb250aCBsaW5rXG5cdFx0Y3VycmVudFRleHQ6IFwiVG9kYXlcIiwgLy8gRGlzcGxheSB0ZXh0IGZvciBjdXJyZW50IG1vbnRoIGxpbmtcblx0XHRtb250aE5hbWVzOiBbIFwiSmFudWFyeVwiLFwiRmVicnVhcnlcIixcIk1hcmNoXCIsXCJBcHJpbFwiLFwiTWF5XCIsXCJKdW5lXCIsXG5cdFx0XHRcIkp1bHlcIixcIkF1Z3VzdFwiLFwiU2VwdGVtYmVyXCIsXCJPY3RvYmVyXCIsXCJOb3ZlbWJlclwiLFwiRGVjZW1iZXJcIiBdLCAvLyBOYW1lcyBvZiBtb250aHMgZm9yIGRyb3AtZG93biBhbmQgZm9ybWF0dGluZ1xuXHRcdG1vbnRoTmFtZXNTaG9ydDogWyBcIkphblwiLCBcIkZlYlwiLCBcIk1hclwiLCBcIkFwclwiLCBcIk1heVwiLCBcIkp1blwiLCBcIkp1bFwiLCBcIkF1Z1wiLCBcIlNlcFwiLCBcIk9jdFwiLCBcIk5vdlwiLCBcIkRlY1wiIF0sIC8vIEZvciBmb3JtYXR0aW5nXG5cdFx0ZGF5TmFtZXM6IFsgXCJTdW5kYXlcIiwgXCJNb25kYXlcIiwgXCJUdWVzZGF5XCIsIFwiV2VkbmVzZGF5XCIsIFwiVGh1cnNkYXlcIiwgXCJGcmlkYXlcIiwgXCJTYXR1cmRheVwiIF0sIC8vIEZvciBmb3JtYXR0aW5nXG5cdFx0ZGF5TmFtZXNTaG9ydDogWyBcIlN1blwiLCBcIk1vblwiLCBcIlR1ZVwiLCBcIldlZFwiLCBcIlRodVwiLCBcIkZyaVwiLCBcIlNhdFwiIF0sIC8vIEZvciBmb3JtYXR0aW5nXG5cdFx0ZGF5TmFtZXNNaW46IFsgXCJTdVwiLFwiTW9cIixcIlR1XCIsXCJXZVwiLFwiVGhcIixcIkZyXCIsXCJTYVwiIF0sIC8vIENvbHVtbiBoZWFkaW5ncyBmb3IgZGF5cyBzdGFydGluZyBhdCBTdW5kYXlcblx0XHR3ZWVrSGVhZGVyOiBcIldrXCIsIC8vIENvbHVtbiBoZWFkZXIgZm9yIHdlZWsgb2YgdGhlIHllYXJcblx0XHRkYXRlRm9ybWF0OiBcIm1tL2RkL3l5XCIsIC8vIFNlZSBmb3JtYXQgb3B0aW9ucyBvbiBwYXJzZURhdGVcblx0XHRmaXJzdERheTogMCwgLy8gVGhlIGZpcnN0IGRheSBvZiB0aGUgd2VlaywgU3VuID0gMCwgTW9uID0gMSwgLi4uXG5cdFx0aXNSVEw6IGZhbHNlLCAvLyBUcnVlIGlmIHJpZ2h0LXRvLWxlZnQgbGFuZ3VhZ2UsIGZhbHNlIGlmIGxlZnQtdG8tcmlnaHRcblx0XHRzaG93TW9udGhBZnRlclllYXI6IGZhbHNlLCAvLyBUcnVlIGlmIHRoZSB5ZWFyIHNlbGVjdCBwcmVjZWRlcyBtb250aCwgZmFsc2UgZm9yIG1vbnRoIHRoZW4geWVhclxuXHRcdHllYXJTdWZmaXg6IFwiXCIgLy8gQWRkaXRpb25hbCB0ZXh0IHRvIGFwcGVuZCB0byB0aGUgeWVhciBpbiB0aGUgbW9udGggaGVhZGVyc1xuXHR9O1xuXHR0aGlzLl9kZWZhdWx0cyA9IHsgLy8gR2xvYmFsIGRlZmF1bHRzIGZvciBhbGwgdGhlIGRhdGUgcGlja2VyIGluc3RhbmNlc1xuXHRcdHNob3dPbjogXCJmb2N1c1wiLCAvLyBcImZvY3VzXCIgZm9yIHBvcHVwIG9uIGZvY3VzLFxuXHRcdFx0Ly8gXCJidXR0b25cIiBmb3IgdHJpZ2dlciBidXR0b24sIG9yIFwiYm90aFwiIGZvciBlaXRoZXJcblx0XHRzaG93QW5pbTogXCJmYWRlSW5cIiwgLy8gTmFtZSBvZiBqUXVlcnkgYW5pbWF0aW9uIGZvciBwb3B1cFxuXHRcdHNob3dPcHRpb25zOiB7fSwgLy8gT3B0aW9ucyBmb3IgZW5oYW5jZWQgYW5pbWF0aW9uc1xuXHRcdGRlZmF1bHREYXRlOiBudWxsLCAvLyBVc2VkIHdoZW4gZmllbGQgaXMgYmxhbms6IGFjdHVhbCBkYXRlLFxuXHRcdFx0Ly8gKy8tbnVtYmVyIGZvciBvZmZzZXQgZnJvbSB0b2RheSwgbnVsbCBmb3IgdG9kYXlcblx0XHRhcHBlbmRUZXh0OiBcIlwiLCAvLyBEaXNwbGF5IHRleHQgZm9sbG93aW5nIHRoZSBpbnB1dCBib3gsIGUuZy4gc2hvd2luZyB0aGUgZm9ybWF0XG5cdFx0YnV0dG9uVGV4dDogXCIuLi5cIiwgLy8gVGV4dCBmb3IgdHJpZ2dlciBidXR0b25cblx0XHRidXR0b25JbWFnZTogXCJcIiwgLy8gVVJMIGZvciB0cmlnZ2VyIGJ1dHRvbiBpbWFnZVxuXHRcdGJ1dHRvbkltYWdlT25seTogZmFsc2UsIC8vIFRydWUgaWYgdGhlIGltYWdlIGFwcGVhcnMgYWxvbmUsIGZhbHNlIGlmIGl0IGFwcGVhcnMgb24gYSBidXR0b25cblx0XHRoaWRlSWZOb1ByZXZOZXh0OiBmYWxzZSwgLy8gVHJ1ZSB0byBoaWRlIG5leHQvcHJldmlvdXMgbW9udGggbGlua3Ncblx0XHRcdC8vIGlmIG5vdCBhcHBsaWNhYmxlLCBmYWxzZSB0byBqdXN0IGRpc2FibGUgdGhlbVxuXHRcdG5hdmlnYXRpb25Bc0RhdGVGb3JtYXQ6IGZhbHNlLCAvLyBUcnVlIGlmIGRhdGUgZm9ybWF0dGluZyBhcHBsaWVkIHRvIHByZXYvdG9kYXkvbmV4dCBsaW5rc1xuXHRcdGdvdG9DdXJyZW50OiBmYWxzZSwgLy8gVHJ1ZSBpZiB0b2RheSBsaW5rIGdvZXMgYmFjayB0byBjdXJyZW50IHNlbGVjdGlvbiBpbnN0ZWFkXG5cdFx0Y2hhbmdlTW9udGg6IGZhbHNlLCAvLyBUcnVlIGlmIG1vbnRoIGNhbiBiZSBzZWxlY3RlZCBkaXJlY3RseSwgZmFsc2UgaWYgb25seSBwcmV2L25leHRcblx0XHRjaGFuZ2VZZWFyOiBmYWxzZSwgLy8gVHJ1ZSBpZiB5ZWFyIGNhbiBiZSBzZWxlY3RlZCBkaXJlY3RseSwgZmFsc2UgaWYgb25seSBwcmV2L25leHRcblx0XHR5ZWFyUmFuZ2U6IFwiYy0xMDpjKzEwXCIsIC8vIFJhbmdlIG9mIHllYXJzIHRvIGRpc3BsYXkgaW4gZHJvcC1kb3duLFxuXHRcdFx0Ly8gZWl0aGVyIHJlbGF0aXZlIHRvIHRvZGF5J3MgeWVhciAoLW5uOitubiksIHJlbGF0aXZlIHRvIGN1cnJlbnRseSBkaXNwbGF5ZWQgeWVhclxuXHRcdFx0Ly8gKGMtbm46YytubiksIGFic29sdXRlIChubm5uOm5ubm4pLCBvciBhIGNvbWJpbmF0aW9uIG9mIHRoZSBhYm92ZSAobm5ubjotbilcblx0XHRzaG93T3RoZXJNb250aHM6IGZhbHNlLCAvLyBUcnVlIHRvIHNob3cgZGF0ZXMgaW4gb3RoZXIgbW9udGhzLCBmYWxzZSB0byBsZWF2ZSBibGFua1xuXHRcdHNlbGVjdE90aGVyTW9udGhzOiBmYWxzZSwgLy8gVHJ1ZSB0byBhbGxvdyBzZWxlY3Rpb24gb2YgZGF0ZXMgaW4gb3RoZXIgbW9udGhzLCBmYWxzZSBmb3IgdW5zZWxlY3RhYmxlXG5cdFx0c2hvd1dlZWs6IGZhbHNlLCAvLyBUcnVlIHRvIHNob3cgd2VlayBvZiB0aGUgeWVhciwgZmFsc2UgdG8gbm90IHNob3cgaXRcblx0XHRjYWxjdWxhdGVXZWVrOiB0aGlzLmlzbzg2MDFXZWVrLCAvLyBIb3cgdG8gY2FsY3VsYXRlIHRoZSB3ZWVrIG9mIHRoZSB5ZWFyLFxuXHRcdFx0Ly8gdGFrZXMgYSBEYXRlIGFuZCByZXR1cm5zIHRoZSBudW1iZXIgb2YgdGhlIHdlZWsgZm9yIGl0XG5cdFx0c2hvcnRZZWFyQ3V0b2ZmOiBcIisxMFwiLCAvLyBTaG9ydCB5ZWFyIHZhbHVlcyA8IHRoaXMgYXJlIGluIHRoZSBjdXJyZW50IGNlbnR1cnksXG5cdFx0XHQvLyA+IHRoaXMgYXJlIGluIHRoZSBwcmV2aW91cyBjZW50dXJ5LFxuXHRcdFx0Ly8gc3RyaW5nIHZhbHVlIHN0YXJ0aW5nIHdpdGggXCIrXCIgZm9yIGN1cnJlbnQgeWVhciArIHZhbHVlXG5cdFx0bWluRGF0ZTogbnVsbCwgLy8gVGhlIGVhcmxpZXN0IHNlbGVjdGFibGUgZGF0ZSwgb3IgbnVsbCBmb3Igbm8gbGltaXRcblx0XHRtYXhEYXRlOiBudWxsLCAvLyBUaGUgbGF0ZXN0IHNlbGVjdGFibGUgZGF0ZSwgb3IgbnVsbCBmb3Igbm8gbGltaXRcblx0XHRkdXJhdGlvbjogXCJmYXN0XCIsIC8vIER1cmF0aW9uIG9mIGRpc3BsYXkvY2xvc3VyZVxuXHRcdGJlZm9yZVNob3dEYXk6IG51bGwsIC8vIEZ1bmN0aW9uIHRoYXQgdGFrZXMgYSBkYXRlIGFuZCByZXR1cm5zIGFuIGFycmF5IHdpdGhcblx0XHRcdC8vIFswXSA9IHRydWUgaWYgc2VsZWN0YWJsZSwgZmFsc2UgaWYgbm90LCBbMV0gPSBjdXN0b20gQ1NTIGNsYXNzIG5hbWUocykgb3IgXCJcIixcblx0XHRcdC8vIFsyXSA9IGNlbGwgdGl0bGUgKG9wdGlvbmFsKSwgZS5nLiAkLmRhdGVwaWNrZXIubm9XZWVrZW5kc1xuXHRcdGJlZm9yZVNob3c6IG51bGwsIC8vIEZ1bmN0aW9uIHRoYXQgdGFrZXMgYW4gaW5wdXQgZmllbGQgYW5kXG5cdFx0XHQvLyByZXR1cm5zIGEgc2V0IG9mIGN1c3RvbSBzZXR0aW5ncyBmb3IgdGhlIGRhdGUgcGlja2VyXG5cdFx0b25TZWxlY3Q6IG51bGwsIC8vIERlZmluZSBhIGNhbGxiYWNrIGZ1bmN0aW9uIHdoZW4gYSBkYXRlIGlzIHNlbGVjdGVkXG5cdFx0b25DaGFuZ2VNb250aFllYXI6IG51bGwsIC8vIERlZmluZSBhIGNhbGxiYWNrIGZ1bmN0aW9uIHdoZW4gdGhlIG1vbnRoIG9yIHllYXIgaXMgY2hhbmdlZFxuXHRcdG9uQ2xvc2U6IG51bGwsIC8vIERlZmluZSBhIGNhbGxiYWNrIGZ1bmN0aW9uIHdoZW4gdGhlIGRhdGVwaWNrZXIgaXMgY2xvc2VkXG5cdFx0bnVtYmVyT2ZNb250aHM6IDEsIC8vIE51bWJlciBvZiBtb250aHMgdG8gc2hvdyBhdCBhIHRpbWVcblx0XHRzaG93Q3VycmVudEF0UG9zOiAwLCAvLyBUaGUgcG9zaXRpb24gaW4gbXVsdGlwZSBtb250aHMgYXQgd2hpY2ggdG8gc2hvdyB0aGUgY3VycmVudCBtb250aCAoc3RhcnRpbmcgYXQgMClcblx0XHRzdGVwTW9udGhzOiAxLCAvLyBOdW1iZXIgb2YgbW9udGhzIHRvIHN0ZXAgYmFjay9mb3J3YXJkXG5cdFx0c3RlcEJpZ01vbnRoczogMTIsIC8vIE51bWJlciBvZiBtb250aHMgdG8gc3RlcCBiYWNrL2ZvcndhcmQgZm9yIHRoZSBiaWcgbGlua3Ncblx0XHRhbHRGaWVsZDogXCJcIiwgLy8gU2VsZWN0b3IgZm9yIGFuIGFsdGVybmF0ZSBmaWVsZCB0byBzdG9yZSBzZWxlY3RlZCBkYXRlcyBpbnRvXG5cdFx0YWx0Rm9ybWF0OiBcIlwiLCAvLyBUaGUgZGF0ZSBmb3JtYXQgdG8gdXNlIGZvciB0aGUgYWx0ZXJuYXRlIGZpZWxkXG5cdFx0Y29uc3RyYWluSW5wdXQ6IHRydWUsIC8vIFRoZSBpbnB1dCBpcyBjb25zdHJhaW5lZCBieSB0aGUgY3VycmVudCBkYXRlIGZvcm1hdFxuXHRcdHNob3dCdXR0b25QYW5lbDogZmFsc2UsIC8vIFRydWUgdG8gc2hvdyBidXR0b24gcGFuZWwsIGZhbHNlIHRvIG5vdCBzaG93IGl0XG5cdFx0YXV0b1NpemU6IGZhbHNlLCAvLyBUcnVlIHRvIHNpemUgdGhlIGlucHV0IGZvciB0aGUgZGF0ZSBmb3JtYXQsIGZhbHNlIHRvIGxlYXZlIGFzIGlzXG5cdFx0ZGlzYWJsZWQ6IGZhbHNlIC8vIFRoZSBpbml0aWFsIGRpc2FibGVkIHN0YXRlXG5cdH07XG5cdCQuZXh0ZW5kKCB0aGlzLl9kZWZhdWx0cywgdGhpcy5yZWdpb25hbFsgXCJcIiBdICk7XG5cdHRoaXMucmVnaW9uYWwuZW4gPSAkLmV4dGVuZCggdHJ1ZSwge30sIHRoaXMucmVnaW9uYWxbIFwiXCIgXSApO1xuXHR0aGlzLnJlZ2lvbmFsWyBcImVuLVVTXCIgXSA9ICQuZXh0ZW5kKCB0cnVlLCB7fSwgdGhpcy5yZWdpb25hbC5lbiApO1xuXHR0aGlzLmRwRGl2ID0gZGF0ZXBpY2tlcl9iaW5kSG92ZXIoICQoIFwiPGRpdiBpZD0nXCIgKyB0aGlzLl9tYWluRGl2SWQgKyBcIicgY2xhc3M9J3VpLWRhdGVwaWNrZXIgdWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50IHVpLWhlbHBlci1jbGVhcmZpeCB1aS1jb3JuZXItYWxsJz48L2Rpdj5cIiApICk7XG59XG5cbiQuZXh0ZW5kKCBEYXRlcGlja2VyLnByb3RvdHlwZSwge1xuXHQvKiBDbGFzcyBuYW1lIGFkZGVkIHRvIGVsZW1lbnRzIHRvIGluZGljYXRlIGFscmVhZHkgY29uZmlndXJlZCB3aXRoIGEgZGF0ZSBwaWNrZXIuICovXG5cdG1hcmtlckNsYXNzTmFtZTogXCJoYXNEYXRlcGlja2VyXCIsXG5cblx0Ly9LZWVwIHRyYWNrIG9mIHRoZSBtYXhpbXVtIG51bWJlciBvZiByb3dzIGRpc3BsYXllZCAoc2VlICM3MDQzKVxuXHRtYXhSb3dzOiA0LFxuXG5cdC8vIFRPRE8gcmVuYW1lIHRvIFwid2lkZ2V0XCIgd2hlbiBzd2l0Y2hpbmcgdG8gd2lkZ2V0IGZhY3Rvcnlcblx0X3dpZGdldERhdGVwaWNrZXI6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmRwRGl2O1xuXHR9LFxuXG5cdC8qIE92ZXJyaWRlIHRoZSBkZWZhdWx0IHNldHRpbmdzIGZvciBhbGwgaW5zdGFuY2VzIG9mIHRoZSBkYXRlIHBpY2tlci5cblx0ICogQHBhcmFtICBzZXR0aW5ncyAgb2JqZWN0IC0gdGhlIG5ldyBzZXR0aW5ncyB0byB1c2UgYXMgZGVmYXVsdHMgKGFub255bW91cyBvYmplY3QpXG5cdCAqIEByZXR1cm4gdGhlIG1hbmFnZXIgb2JqZWN0XG5cdCAqL1xuXHRzZXREZWZhdWx0czogZnVuY3Rpb24oIHNldHRpbmdzICkge1xuXHRcdGRhdGVwaWNrZXJfZXh0ZW5kUmVtb3ZlKCB0aGlzLl9kZWZhdWx0cywgc2V0dGluZ3MgfHwge30gKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvKiBBdHRhY2ggdGhlIGRhdGUgcGlja2VyIHRvIGEgalF1ZXJ5IHNlbGVjdGlvbi5cblx0ICogQHBhcmFtICB0YXJnZXRcdGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICogQHBhcmFtICBzZXR0aW5ncyAgb2JqZWN0IC0gdGhlIG5ldyBzZXR0aW5ncyB0byB1c2UgZm9yIHRoaXMgZGF0ZSBwaWNrZXIgaW5zdGFuY2UgKGFub255bW91cylcblx0ICovXG5cdF9hdHRhY2hEYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0LCBzZXR0aW5ncyApIHtcblx0XHR2YXIgbm9kZU5hbWUsIGlubGluZSwgaW5zdDtcblx0XHRub2RlTmFtZSA9IHRhcmdldC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdGlubGluZSA9ICggbm9kZU5hbWUgPT09IFwiZGl2XCIgfHwgbm9kZU5hbWUgPT09IFwic3BhblwiICk7XG5cdFx0aWYgKCAhdGFyZ2V0LmlkICkge1xuXHRcdFx0dGhpcy51dWlkICs9IDE7XG5cdFx0XHR0YXJnZXQuaWQgPSBcImRwXCIgKyB0aGlzLnV1aWQ7XG5cdFx0fVxuXHRcdGluc3QgPSB0aGlzLl9uZXdJbnN0KCAkKCB0YXJnZXQgKSwgaW5saW5lICk7XG5cdFx0aW5zdC5zZXR0aW5ncyA9ICQuZXh0ZW5kKCB7fSwgc2V0dGluZ3MgfHwge30gKTtcblx0XHRpZiAoIG5vZGVOYW1lID09PSBcImlucHV0XCIgKSB7XG5cdFx0XHR0aGlzLl9jb25uZWN0RGF0ZXBpY2tlciggdGFyZ2V0LCBpbnN0ICk7XG5cdFx0fSBlbHNlIGlmICggaW5saW5lICkge1xuXHRcdFx0dGhpcy5faW5saW5lRGF0ZXBpY2tlciggdGFyZ2V0LCBpbnN0ICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIENyZWF0ZSBhIG5ldyBpbnN0YW5jZSBvYmplY3QuICovXG5cdF9uZXdJbnN0OiBmdW5jdGlvbiggdGFyZ2V0LCBpbmxpbmUgKSB7XG5cdFx0dmFyIGlkID0gdGFyZ2V0WyAwIF0uaWQucmVwbGFjZSggLyhbXkEtWmEtejAtOV9cXC1dKS9nLCBcIlxcXFxcXFxcJDFcIiApOyAvLyBlc2NhcGUgalF1ZXJ5IG1ldGEgY2hhcnNcblx0XHRyZXR1cm4geyBpZDogaWQsIGlucHV0OiB0YXJnZXQsIC8vIGFzc29jaWF0ZWQgdGFyZ2V0XG5cdFx0XHRzZWxlY3RlZERheTogMCwgc2VsZWN0ZWRNb250aDogMCwgc2VsZWN0ZWRZZWFyOiAwLCAvLyBjdXJyZW50IHNlbGVjdGlvblxuXHRcdFx0ZHJhd01vbnRoOiAwLCBkcmF3WWVhcjogMCwgLy8gbW9udGggYmVpbmcgZHJhd25cblx0XHRcdGlubGluZTogaW5saW5lLCAvLyBpcyBkYXRlcGlja2VyIGlubGluZSBvciBub3Rcblx0XHRcdGRwRGl2OiAoICFpbmxpbmUgPyB0aGlzLmRwRGl2IDogLy8gcHJlc2VudGF0aW9uIGRpdlxuXHRcdFx0ZGF0ZXBpY2tlcl9iaW5kSG92ZXIoICQoIFwiPGRpdiBjbGFzcz0nXCIgKyB0aGlzLl9pbmxpbmVDbGFzcyArIFwiIHVpLWRhdGVwaWNrZXIgdWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50IHVpLWhlbHBlci1jbGVhcmZpeCB1aS1jb3JuZXItYWxsJz48L2Rpdj5cIiApICkgKSB9O1xuXHR9LFxuXG5cdC8qIEF0dGFjaCB0aGUgZGF0ZSBwaWNrZXIgdG8gYW4gaW5wdXQgZmllbGQuICovXG5cdF9jb25uZWN0RGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCwgaW5zdCApIHtcblx0XHR2YXIgaW5wdXQgPSAkKCB0YXJnZXQgKTtcblx0XHRpbnN0LmFwcGVuZCA9ICQoIFtdICk7XG5cdFx0aW5zdC50cmlnZ2VyID0gJCggW10gKTtcblx0XHRpZiAoIGlucHV0Lmhhc0NsYXNzKCB0aGlzLm1hcmtlckNsYXNzTmFtZSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHR0aGlzLl9hdHRhY2htZW50cyggaW5wdXQsIGluc3QgKTtcblx0XHRpbnB1dC5hZGRDbGFzcyggdGhpcy5tYXJrZXJDbGFzc05hbWUgKS5vbiggXCJrZXlkb3duXCIsIHRoaXMuX2RvS2V5RG93biApLlxuXHRcdFx0b24oIFwia2V5cHJlc3NcIiwgdGhpcy5fZG9LZXlQcmVzcyApLm9uKCBcImtleXVwXCIsIHRoaXMuX2RvS2V5VXAgKTtcblx0XHR0aGlzLl9hdXRvU2l6ZSggaW5zdCApO1xuXHRcdCQuZGF0YSggdGFyZ2V0LCBcImRhdGVwaWNrZXJcIiwgaW5zdCApO1xuXG5cdFx0Ly9JZiBkaXNhYmxlZCBvcHRpb24gaXMgdHJ1ZSwgZGlzYWJsZSB0aGUgZGF0ZXBpY2tlciBvbmNlIGl0IGhhcyBiZWVuIGF0dGFjaGVkIHRvIHRoZSBpbnB1dCAoc2VlIHRpY2tldCAjNTY2NSlcblx0XHRpZiAoIGluc3Quc2V0dGluZ3MuZGlzYWJsZWQgKSB7XG5cdFx0XHR0aGlzLl9kaXNhYmxlRGF0ZXBpY2tlciggdGFyZ2V0ICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIE1ha2UgYXR0YWNobWVudHMgYmFzZWQgb24gc2V0dGluZ3MuICovXG5cdF9hdHRhY2htZW50czogZnVuY3Rpb24oIGlucHV0LCBpbnN0ICkge1xuXHRcdHZhciBzaG93T24sIGJ1dHRvblRleHQsIGJ1dHRvbkltYWdlLFxuXHRcdFx0YXBwZW5kVGV4dCA9IHRoaXMuX2dldCggaW5zdCwgXCJhcHBlbmRUZXh0XCIgKSxcblx0XHRcdGlzUlRMID0gdGhpcy5fZ2V0KCBpbnN0LCBcImlzUlRMXCIgKTtcblxuXHRcdGlmICggaW5zdC5hcHBlbmQgKSB7XG5cdFx0XHRpbnN0LmFwcGVuZC5yZW1vdmUoKTtcblx0XHR9XG5cdFx0aWYgKCBhcHBlbmRUZXh0ICkge1xuXHRcdFx0aW5zdC5hcHBlbmQgPSAkKCBcIjxzcGFuIGNsYXNzPSdcIiArIHRoaXMuX2FwcGVuZENsYXNzICsgXCInPlwiICsgYXBwZW5kVGV4dCArIFwiPC9zcGFuPlwiICk7XG5cdFx0XHRpbnB1dFsgaXNSVEwgPyBcImJlZm9yZVwiIDogXCJhZnRlclwiIF0oIGluc3QuYXBwZW5kICk7XG5cdFx0fVxuXG5cdFx0aW5wdXQub2ZmKCBcImZvY3VzXCIsIHRoaXMuX3Nob3dEYXRlcGlja2VyICk7XG5cblx0XHRpZiAoIGluc3QudHJpZ2dlciApIHtcblx0XHRcdGluc3QudHJpZ2dlci5yZW1vdmUoKTtcblx0XHR9XG5cblx0XHRzaG93T24gPSB0aGlzLl9nZXQoIGluc3QsIFwic2hvd09uXCIgKTtcblx0XHRpZiAoIHNob3dPbiA9PT0gXCJmb2N1c1wiIHx8IHNob3dPbiA9PT0gXCJib3RoXCIgKSB7IC8vIHBvcC11cCBkYXRlIHBpY2tlciB3aGVuIGluIHRoZSBtYXJrZWQgZmllbGRcblx0XHRcdGlucHV0Lm9uKCBcImZvY3VzXCIsIHRoaXMuX3Nob3dEYXRlcGlja2VyICk7XG5cdFx0fVxuXHRcdGlmICggc2hvd09uID09PSBcImJ1dHRvblwiIHx8IHNob3dPbiA9PT0gXCJib3RoXCIgKSB7IC8vIHBvcC11cCBkYXRlIHBpY2tlciB3aGVuIGJ1dHRvbiBjbGlja2VkXG5cdFx0XHRidXR0b25UZXh0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcImJ1dHRvblRleHRcIiApO1xuXHRcdFx0YnV0dG9uSW1hZ2UgPSB0aGlzLl9nZXQoIGluc3QsIFwiYnV0dG9uSW1hZ2VcIiApO1xuXHRcdFx0aW5zdC50cmlnZ2VyID0gJCggdGhpcy5fZ2V0KCBpbnN0LCBcImJ1dHRvbkltYWdlT25seVwiICkgP1xuXHRcdFx0XHQkKCBcIjxpbWcvPlwiICkuYWRkQ2xhc3MoIHRoaXMuX3RyaWdnZXJDbGFzcyApLlxuXHRcdFx0XHRcdGF0dHIoIHsgc3JjOiBidXR0b25JbWFnZSwgYWx0OiBidXR0b25UZXh0LCB0aXRsZTogYnV0dG9uVGV4dCB9ICkgOlxuXHRcdFx0XHQkKCBcIjxidXR0b24gdHlwZT0nYnV0dG9uJz48L2J1dHRvbj5cIiApLmFkZENsYXNzKCB0aGlzLl90cmlnZ2VyQ2xhc3MgKS5cblx0XHRcdFx0XHRodG1sKCAhYnV0dG9uSW1hZ2UgPyBidXR0b25UZXh0IDogJCggXCI8aW1nLz5cIiApLmF0dHIoXG5cdFx0XHRcdFx0eyBzcmM6YnV0dG9uSW1hZ2UsIGFsdDpidXR0b25UZXh0LCB0aXRsZTpidXR0b25UZXh0IH0gKSApICk7XG5cdFx0XHRpbnB1dFsgaXNSVEwgPyBcImJlZm9yZVwiIDogXCJhZnRlclwiIF0oIGluc3QudHJpZ2dlciApO1xuXHRcdFx0aW5zdC50cmlnZ2VyLm9uKCBcImNsaWNrXCIsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoICQuZGF0ZXBpY2tlci5fZGF0ZXBpY2tlclNob3dpbmcgJiYgJC5kYXRlcGlja2VyLl9sYXN0SW5wdXQgPT09IGlucHV0WyAwIF0gKSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9oaWRlRGF0ZXBpY2tlcigpO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCAkLmRhdGVwaWNrZXIuX2RhdGVwaWNrZXJTaG93aW5nICYmICQuZGF0ZXBpY2tlci5fbGFzdElucHV0ICE9PSBpbnB1dFsgMCBdICkge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5faGlkZURhdGVwaWNrZXIoKTtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX3Nob3dEYXRlcGlja2VyKCBpbnB1dFsgMCBdICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9zaG93RGF0ZXBpY2tlciggaW5wdXRbIDAgXSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH0gKTtcblx0XHR9XG5cdH0sXG5cblx0LyogQXBwbHkgdGhlIG1heGltdW0gbGVuZ3RoIGZvciB0aGUgZGF0ZSBmb3JtYXQuICovXG5cdF9hdXRvU2l6ZTogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0aWYgKCB0aGlzLl9nZXQoIGluc3QsIFwiYXV0b1NpemVcIiApICYmICFpbnN0LmlubGluZSApIHtcblx0XHRcdHZhciBmaW5kTWF4LCBtYXgsIG1heEksIGksXG5cdFx0XHRcdGRhdGUgPSBuZXcgRGF0ZSggMjAwOSwgMTIgLSAxLCAyMCApLCAvLyBFbnN1cmUgZG91YmxlIGRpZ2l0c1xuXHRcdFx0XHRkYXRlRm9ybWF0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcImRhdGVGb3JtYXRcIiApO1xuXG5cdFx0XHRpZiAoIGRhdGVGb3JtYXQubWF0Y2goIC9bRE1dLyApICkge1xuXHRcdFx0XHRmaW5kTWF4ID0gZnVuY3Rpb24oIG5hbWVzICkge1xuXHRcdFx0XHRcdG1heCA9IDA7XG5cdFx0XHRcdFx0bWF4SSA9IDA7XG5cdFx0XHRcdFx0Zm9yICggaSA9IDA7IGkgPCBuYW1lcy5sZW5ndGg7IGkrKyApIHtcblx0XHRcdFx0XHRcdGlmICggbmFtZXNbIGkgXS5sZW5ndGggPiBtYXggKSB7XG5cdFx0XHRcdFx0XHRcdG1heCA9IG5hbWVzWyBpIF0ubGVuZ3RoO1xuXHRcdFx0XHRcdFx0XHRtYXhJID0gaTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIG1heEk7XG5cdFx0XHRcdH07XG5cdFx0XHRcdGRhdGUuc2V0TW9udGgoIGZpbmRNYXgoIHRoaXMuX2dldCggaW5zdCwgKCBkYXRlRm9ybWF0Lm1hdGNoKCAvTU0vICkgP1xuXHRcdFx0XHRcdFwibW9udGhOYW1lc1wiIDogXCJtb250aE5hbWVzU2hvcnRcIiApICkgKSApO1xuXHRcdFx0XHRkYXRlLnNldERhdGUoIGZpbmRNYXgoIHRoaXMuX2dldCggaW5zdCwgKCBkYXRlRm9ybWF0Lm1hdGNoKCAvREQvICkgP1xuXHRcdFx0XHRcdFwiZGF5TmFtZXNcIiA6IFwiZGF5TmFtZXNTaG9ydFwiICkgKSApICsgMjAgLSBkYXRlLmdldERheSgpICk7XG5cdFx0XHR9XG5cdFx0XHRpbnN0LmlucHV0LmF0dHIoIFwic2l6ZVwiLCB0aGlzLl9mb3JtYXREYXRlKCBpbnN0LCBkYXRlICkubGVuZ3RoICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIEF0dGFjaCBhbiBpbmxpbmUgZGF0ZSBwaWNrZXIgdG8gYSBkaXYuICovXG5cdF9pbmxpbmVEYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0LCBpbnN0ICkge1xuXHRcdHZhciBkaXZTcGFuID0gJCggdGFyZ2V0ICk7XG5cdFx0aWYgKCBkaXZTcGFuLmhhc0NsYXNzKCB0aGlzLm1hcmtlckNsYXNzTmFtZSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRkaXZTcGFuLmFkZENsYXNzKCB0aGlzLm1hcmtlckNsYXNzTmFtZSApLmFwcGVuZCggaW5zdC5kcERpdiApO1xuXHRcdCQuZGF0YSggdGFyZ2V0LCBcImRhdGVwaWNrZXJcIiwgaW5zdCApO1xuXHRcdHRoaXMuX3NldERhdGUoIGluc3QsIHRoaXMuX2dldERlZmF1bHREYXRlKCBpbnN0ICksIHRydWUgKTtcblx0XHR0aGlzLl91cGRhdGVEYXRlcGlja2VyKCBpbnN0ICk7XG5cdFx0dGhpcy5fdXBkYXRlQWx0ZXJuYXRlKCBpbnN0ICk7XG5cblx0XHQvL0lmIGRpc2FibGVkIG9wdGlvbiBpcyB0cnVlLCBkaXNhYmxlIHRoZSBkYXRlcGlja2VyIGJlZm9yZSBzaG93aW5nIGl0IChzZWUgdGlja2V0ICM1NjY1KVxuXHRcdGlmICggaW5zdC5zZXR0aW5ncy5kaXNhYmxlZCApIHtcblx0XHRcdHRoaXMuX2Rpc2FibGVEYXRlcGlja2VyKCB0YXJnZXQgKTtcblx0XHR9XG5cblx0XHQvLyBTZXQgZGlzcGxheTpibG9jayBpbiBwbGFjZSBvZiBpbnN0LmRwRGl2LnNob3coKSB3aGljaCB3b24ndCB3b3JrIG9uIGRpc2Nvbm5lY3RlZCBlbGVtZW50c1xuXHRcdC8vIGh0dHA6Ly9idWdzLmpxdWVyeXVpLmNvbS90aWNrZXQvNzU1MiAtIEEgRGF0ZXBpY2tlciBjcmVhdGVkIG9uIGEgZGV0YWNoZWQgZGl2IGhhcyB6ZXJvIGhlaWdodFxuXHRcdGluc3QuZHBEaXYuY3NzKCBcImRpc3BsYXlcIiwgXCJibG9ja1wiICk7XG5cdH0sXG5cblx0LyogUG9wLXVwIHRoZSBkYXRlIHBpY2tlciBpbiBhIFwiZGlhbG9nXCIgYm94LlxuXHQgKiBAcGFyYW0gIGlucHV0IGVsZW1lbnQgLSBpZ25vcmVkXG5cdCAqIEBwYXJhbSAgZGF0ZVx0c3RyaW5nIG9yIERhdGUgLSB0aGUgaW5pdGlhbCBkYXRlIHRvIGRpc3BsYXlcblx0ICogQHBhcmFtICBvblNlbGVjdCAgZnVuY3Rpb24gLSB0aGUgZnVuY3Rpb24gdG8gY2FsbCB3aGVuIGEgZGF0ZSBpcyBzZWxlY3RlZFxuXHQgKiBAcGFyYW0gIHNldHRpbmdzICBvYmplY3QgLSB1cGRhdGUgdGhlIGRpYWxvZyBkYXRlIHBpY2tlciBpbnN0YW5jZSdzIHNldHRpbmdzIChhbm9ueW1vdXMgb2JqZWN0KVxuXHQgKiBAcGFyYW0gIHBvcyBpbnRbMl0gLSBjb29yZGluYXRlcyBmb3IgdGhlIGRpYWxvZydzIHBvc2l0aW9uIHdpdGhpbiB0aGUgc2NyZWVuIG9yXG5cdCAqXHRcdFx0XHRcdGV2ZW50IC0gd2l0aCB4L3kgY29vcmRpbmF0ZXMgb3Jcblx0ICpcdFx0XHRcdFx0bGVhdmUgZW1wdHkgZm9yIGRlZmF1bHQgKHNjcmVlbiBjZW50cmUpXG5cdCAqIEByZXR1cm4gdGhlIG1hbmFnZXIgb2JqZWN0XG5cdCAqL1xuXHRfZGlhbG9nRGF0ZXBpY2tlcjogZnVuY3Rpb24oIGlucHV0LCBkYXRlLCBvblNlbGVjdCwgc2V0dGluZ3MsIHBvcyApIHtcblx0XHR2YXIgaWQsIGJyb3dzZXJXaWR0aCwgYnJvd3NlckhlaWdodCwgc2Nyb2xsWCwgc2Nyb2xsWSxcblx0XHRcdGluc3QgPSB0aGlzLl9kaWFsb2dJbnN0OyAvLyBpbnRlcm5hbCBpbnN0YW5jZVxuXG5cdFx0aWYgKCAhaW5zdCApIHtcblx0XHRcdHRoaXMudXVpZCArPSAxO1xuXHRcdFx0aWQgPSBcImRwXCIgKyB0aGlzLnV1aWQ7XG5cdFx0XHR0aGlzLl9kaWFsb2dJbnB1dCA9ICQoIFwiPGlucHV0IHR5cGU9J3RleHQnIGlkPSdcIiArIGlkICtcblx0XHRcdFx0XCInIHN0eWxlPSdwb3NpdGlvbjogYWJzb2x1dGU7IHRvcDogLTEwMHB4OyB3aWR0aDogMHB4OycvPlwiICk7XG5cdFx0XHR0aGlzLl9kaWFsb2dJbnB1dC5vbiggXCJrZXlkb3duXCIsIHRoaXMuX2RvS2V5RG93biApO1xuXHRcdFx0JCggXCJib2R5XCIgKS5hcHBlbmQoIHRoaXMuX2RpYWxvZ0lucHV0ICk7XG5cdFx0XHRpbnN0ID0gdGhpcy5fZGlhbG9nSW5zdCA9IHRoaXMuX25ld0luc3QoIHRoaXMuX2RpYWxvZ0lucHV0LCBmYWxzZSApO1xuXHRcdFx0aW5zdC5zZXR0aW5ncyA9IHt9O1xuXHRcdFx0JC5kYXRhKCB0aGlzLl9kaWFsb2dJbnB1dFsgMCBdLCBcImRhdGVwaWNrZXJcIiwgaW5zdCApO1xuXHRcdH1cblx0XHRkYXRlcGlja2VyX2V4dGVuZFJlbW92ZSggaW5zdC5zZXR0aW5ncywgc2V0dGluZ3MgfHwge30gKTtcblx0XHRkYXRlID0gKCBkYXRlICYmIGRhdGUuY29uc3RydWN0b3IgPT09IERhdGUgPyB0aGlzLl9mb3JtYXREYXRlKCBpbnN0LCBkYXRlICkgOiBkYXRlICk7XG5cdFx0dGhpcy5fZGlhbG9nSW5wdXQudmFsKCBkYXRlICk7XG5cblx0XHR0aGlzLl9wb3MgPSAoIHBvcyA/ICggcG9zLmxlbmd0aCA/IHBvcyA6IFsgcG9zLnBhZ2VYLCBwb3MucGFnZVkgXSApIDogbnVsbCApO1xuXHRcdGlmICggIXRoaXMuX3BvcyApIHtcblx0XHRcdGJyb3dzZXJXaWR0aCA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRXaWR0aDtcblx0XHRcdGJyb3dzZXJIZWlnaHQgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0O1xuXHRcdFx0c2Nyb2xsWCA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxMZWZ0IHx8IGRvY3VtZW50LmJvZHkuc2Nyb2xsTGVmdDtcblx0XHRcdHNjcm9sbFkgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsVG9wIHx8IGRvY3VtZW50LmJvZHkuc2Nyb2xsVG9wO1xuXHRcdFx0dGhpcy5fcG9zID0gLy8gc2hvdWxkIHVzZSBhY3R1YWwgd2lkdGgvaGVpZ2h0IGJlbG93XG5cdFx0XHRcdFsgKCBicm93c2VyV2lkdGggLyAyICkgLSAxMDAgKyBzY3JvbGxYLCAoIGJyb3dzZXJIZWlnaHQgLyAyICkgLSAxNTAgKyBzY3JvbGxZIF07XG5cdFx0fVxuXG5cdFx0Ly8gTW92ZSBpbnB1dCBvbiBzY3JlZW4gZm9yIGZvY3VzLCBidXQgaGlkZGVuIGJlaGluZCBkaWFsb2dcblx0XHR0aGlzLl9kaWFsb2dJbnB1dC5jc3MoIFwibGVmdFwiLCAoIHRoaXMuX3Bvc1sgMCBdICsgMjAgKSArIFwicHhcIiApLmNzcyggXCJ0b3BcIiwgdGhpcy5fcG9zWyAxIF0gKyBcInB4XCIgKTtcblx0XHRpbnN0LnNldHRpbmdzLm9uU2VsZWN0ID0gb25TZWxlY3Q7XG5cdFx0dGhpcy5faW5EaWFsb2cgPSB0cnVlO1xuXHRcdHRoaXMuZHBEaXYuYWRkQ2xhc3MoIHRoaXMuX2RpYWxvZ0NsYXNzICk7XG5cdFx0dGhpcy5fc2hvd0RhdGVwaWNrZXIoIHRoaXMuX2RpYWxvZ0lucHV0WyAwIF0gKTtcblx0XHRpZiAoICQuYmxvY2tVSSApIHtcblx0XHRcdCQuYmxvY2tVSSggdGhpcy5kcERpdiApO1xuXHRcdH1cblx0XHQkLmRhdGEoIHRoaXMuX2RpYWxvZ0lucHV0WyAwIF0sIFwiZGF0ZXBpY2tlclwiLCBpbnN0ICk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0LyogRGV0YWNoIGEgZGF0ZXBpY2tlciBmcm9tIGl0cyBjb250cm9sLlxuXHQgKiBAcGFyYW0gIHRhcmdldFx0ZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKi9cblx0X2Rlc3Ryb3lEYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHZhciBub2RlTmFtZSxcblx0XHRcdCR0YXJnZXQgPSAkKCB0YXJnZXQgKSxcblx0XHRcdGluc3QgPSAkLmRhdGEoIHRhcmdldCwgXCJkYXRlcGlja2VyXCIgKTtcblxuXHRcdGlmICggISR0YXJnZXQuaGFzQ2xhc3MoIHRoaXMubWFya2VyQ2xhc3NOYW1lICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bm9kZU5hbWUgPSB0YXJnZXQubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHQkLnJlbW92ZURhdGEoIHRhcmdldCwgXCJkYXRlcGlja2VyXCIgKTtcblx0XHRpZiAoIG5vZGVOYW1lID09PSBcImlucHV0XCIgKSB7XG5cdFx0XHRpbnN0LmFwcGVuZC5yZW1vdmUoKTtcblx0XHRcdGluc3QudHJpZ2dlci5yZW1vdmUoKTtcblx0XHRcdCR0YXJnZXQucmVtb3ZlQ2xhc3MoIHRoaXMubWFya2VyQ2xhc3NOYW1lICkuXG5cdFx0XHRcdG9mZiggXCJmb2N1c1wiLCB0aGlzLl9zaG93RGF0ZXBpY2tlciApLlxuXHRcdFx0XHRvZmYoIFwia2V5ZG93blwiLCB0aGlzLl9kb0tleURvd24gKS5cblx0XHRcdFx0b2ZmKCBcImtleXByZXNzXCIsIHRoaXMuX2RvS2V5UHJlc3MgKS5cblx0XHRcdFx0b2ZmKCBcImtleXVwXCIsIHRoaXMuX2RvS2V5VXAgKTtcblx0XHR9IGVsc2UgaWYgKCBub2RlTmFtZSA9PT0gXCJkaXZcIiB8fCBub2RlTmFtZSA9PT0gXCJzcGFuXCIgKSB7XG5cdFx0XHQkdGFyZ2V0LnJlbW92ZUNsYXNzKCB0aGlzLm1hcmtlckNsYXNzTmFtZSApLmVtcHR5KCk7XG5cdFx0fVxuXG5cdFx0aWYgKCBkYXRlcGlja2VyX2luc3RBY3RpdmUgPT09IGluc3QgKSB7XG5cdFx0XHRkYXRlcGlja2VyX2luc3RBY3RpdmUgPSBudWxsO1xuXHRcdH1cblx0fSxcblxuXHQvKiBFbmFibGUgdGhlIGRhdGUgcGlja2VyIHRvIGEgalF1ZXJ5IHNlbGVjdGlvbi5cblx0ICogQHBhcmFtICB0YXJnZXRcdGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICovXG5cdF9lbmFibGVEYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHZhciBub2RlTmFtZSwgaW5saW5lLFxuXHRcdFx0JHRhcmdldCA9ICQoIHRhcmdldCApLFxuXHRcdFx0aW5zdCA9ICQuZGF0YSggdGFyZ2V0LCBcImRhdGVwaWNrZXJcIiApO1xuXG5cdFx0aWYgKCAhJHRhcmdldC5oYXNDbGFzcyggdGhpcy5tYXJrZXJDbGFzc05hbWUgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRub2RlTmFtZSA9IHRhcmdldC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdGlmICggbm9kZU5hbWUgPT09IFwiaW5wdXRcIiApIHtcblx0XHRcdHRhcmdldC5kaXNhYmxlZCA9IGZhbHNlO1xuXHRcdFx0aW5zdC50cmlnZ2VyLmZpbHRlciggXCJidXR0b25cIiApLlxuXHRcdFx0XHRlYWNoKCBmdW5jdGlvbigpIHsgdGhpcy5kaXNhYmxlZCA9IGZhbHNlOyB9ICkuZW5kKCkuXG5cdFx0XHRcdGZpbHRlciggXCJpbWdcIiApLmNzcyggeyBvcGFjaXR5OiBcIjEuMFwiLCBjdXJzb3I6IFwiXCIgfSApO1xuXHRcdH0gZWxzZSBpZiAoIG5vZGVOYW1lID09PSBcImRpdlwiIHx8IG5vZGVOYW1lID09PSBcInNwYW5cIiApIHtcblx0XHRcdGlubGluZSA9ICR0YXJnZXQuY2hpbGRyZW4oIFwiLlwiICsgdGhpcy5faW5saW5lQ2xhc3MgKTtcblx0XHRcdGlubGluZS5jaGlsZHJlbigpLnJlbW92ZUNsYXNzKCBcInVpLXN0YXRlLWRpc2FibGVkXCIgKTtcblx0XHRcdGlubGluZS5maW5kKCBcInNlbGVjdC51aS1kYXRlcGlja2VyLW1vbnRoLCBzZWxlY3QudWktZGF0ZXBpY2tlci15ZWFyXCIgKS5cblx0XHRcdFx0cHJvcCggXCJkaXNhYmxlZFwiLCBmYWxzZSApO1xuXHRcdH1cblx0XHR0aGlzLl9kaXNhYmxlZElucHV0cyA9ICQubWFwKCB0aGlzLl9kaXNhYmxlZElucHV0cyxcblx0XHRcdGZ1bmN0aW9uKCB2YWx1ZSApIHsgcmV0dXJuICggdmFsdWUgPT09IHRhcmdldCA/IG51bGwgOiB2YWx1ZSApOyB9ICk7IC8vIGRlbGV0ZSBlbnRyeVxuXHR9LFxuXG5cdC8qIERpc2FibGUgdGhlIGRhdGUgcGlja2VyIHRvIGEgalF1ZXJ5IHNlbGVjdGlvbi5cblx0ICogQHBhcmFtICB0YXJnZXRcdGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICovXG5cdF9kaXNhYmxlRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCApIHtcblx0XHR2YXIgbm9kZU5hbWUsIGlubGluZSxcblx0XHRcdCR0YXJnZXQgPSAkKCB0YXJnZXQgKSxcblx0XHRcdGluc3QgPSAkLmRhdGEoIHRhcmdldCwgXCJkYXRlcGlja2VyXCIgKTtcblxuXHRcdGlmICggISR0YXJnZXQuaGFzQ2xhc3MoIHRoaXMubWFya2VyQ2xhc3NOYW1lICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bm9kZU5hbWUgPSB0YXJnZXQubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHRpZiAoIG5vZGVOYW1lID09PSBcImlucHV0XCIgKSB7XG5cdFx0XHR0YXJnZXQuZGlzYWJsZWQgPSB0cnVlO1xuXHRcdFx0aW5zdC50cmlnZ2VyLmZpbHRlciggXCJidXR0b25cIiApLlxuXHRcdFx0XHRlYWNoKCBmdW5jdGlvbigpIHsgdGhpcy5kaXNhYmxlZCA9IHRydWU7IH0gKS5lbmQoKS5cblx0XHRcdFx0ZmlsdGVyKCBcImltZ1wiICkuY3NzKCB7IG9wYWNpdHk6IFwiMC41XCIsIGN1cnNvcjogXCJkZWZhdWx0XCIgfSApO1xuXHRcdH0gZWxzZSBpZiAoIG5vZGVOYW1lID09PSBcImRpdlwiIHx8IG5vZGVOYW1lID09PSBcInNwYW5cIiApIHtcblx0XHRcdGlubGluZSA9ICR0YXJnZXQuY2hpbGRyZW4oIFwiLlwiICsgdGhpcy5faW5saW5lQ2xhc3MgKTtcblx0XHRcdGlubGluZS5jaGlsZHJlbigpLmFkZENsYXNzKCBcInVpLXN0YXRlLWRpc2FibGVkXCIgKTtcblx0XHRcdGlubGluZS5maW5kKCBcInNlbGVjdC51aS1kYXRlcGlja2VyLW1vbnRoLCBzZWxlY3QudWktZGF0ZXBpY2tlci15ZWFyXCIgKS5cblx0XHRcdFx0cHJvcCggXCJkaXNhYmxlZFwiLCB0cnVlICk7XG5cdFx0fVxuXHRcdHRoaXMuX2Rpc2FibGVkSW5wdXRzID0gJC5tYXAoIHRoaXMuX2Rpc2FibGVkSW5wdXRzLFxuXHRcdFx0ZnVuY3Rpb24oIHZhbHVlICkgeyByZXR1cm4gKCB2YWx1ZSA9PT0gdGFyZ2V0ID8gbnVsbCA6IHZhbHVlICk7IH0gKTsgLy8gZGVsZXRlIGVudHJ5XG5cdFx0dGhpcy5fZGlzYWJsZWRJbnB1dHNbIHRoaXMuX2Rpc2FibGVkSW5wdXRzLmxlbmd0aCBdID0gdGFyZ2V0O1xuXHR9LFxuXG5cdC8qIElzIHRoZSBmaXJzdCBmaWVsZCBpbiBhIGpRdWVyeSBjb2xsZWN0aW9uIGRpc2FibGVkIGFzIGEgZGF0ZXBpY2tlcj9cblx0ICogQHBhcmFtICB0YXJnZXRcdGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICogQHJldHVybiBib29sZWFuIC0gdHJ1ZSBpZiBkaXNhYmxlZCwgZmFsc2UgaWYgZW5hYmxlZFxuXHQgKi9cblx0X2lzRGlzYWJsZWREYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdGlmICggIXRhcmdldCApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdFx0Zm9yICggdmFyIGkgPSAwOyBpIDwgdGhpcy5fZGlzYWJsZWRJbnB1dHMubGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRpZiAoIHRoaXMuX2Rpc2FibGVkSW5wdXRzWyBpIF0gPT09IHRhcmdldCApIHtcblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblxuXHQvKiBSZXRyaWV2ZSB0aGUgaW5zdGFuY2UgZGF0YSBmb3IgdGhlIHRhcmdldCBjb250cm9sLlxuXHQgKiBAcGFyYW0gIHRhcmdldCAgZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKiBAcmV0dXJuICBvYmplY3QgLSB0aGUgYXNzb2NpYXRlZCBpbnN0YW5jZSBkYXRhXG5cdCAqIEB0aHJvd3MgIGVycm9yIGlmIGEgalF1ZXJ5IHByb2JsZW0gZ2V0dGluZyBkYXRhXG5cdCAqL1xuXHRfZ2V0SW5zdDogZnVuY3Rpb24oIHRhcmdldCApIHtcblx0XHR0cnkge1xuXHRcdFx0cmV0dXJuICQuZGF0YSggdGFyZ2V0LCBcImRhdGVwaWNrZXJcIiApO1xuXHRcdH1cblx0XHRjYXRjaCAoIGVyciApIHtcblx0XHRcdHRocm93IFwiTWlzc2luZyBpbnN0YW5jZSBkYXRhIGZvciB0aGlzIGRhdGVwaWNrZXJcIjtcblx0XHR9XG5cdH0sXG5cblx0LyogVXBkYXRlIG9yIHJldHJpZXZlIHRoZSBzZXR0aW5ncyBmb3IgYSBkYXRlIHBpY2tlciBhdHRhY2hlZCB0byBhbiBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbi5cblx0ICogQHBhcmFtICB0YXJnZXQgIGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICogQHBhcmFtICBuYW1lXHRvYmplY3QgLSB0aGUgbmV3IHNldHRpbmdzIHRvIHVwZGF0ZSBvclxuXHQgKlx0XHRcdFx0c3RyaW5nIC0gdGhlIG5hbWUgb2YgdGhlIHNldHRpbmcgdG8gY2hhbmdlIG9yIHJldHJpZXZlLFxuXHQgKlx0XHRcdFx0d2hlbiByZXRyaWV2aW5nIGFsc28gXCJhbGxcIiBmb3IgYWxsIGluc3RhbmNlIHNldHRpbmdzIG9yXG5cdCAqXHRcdFx0XHRcImRlZmF1bHRzXCIgZm9yIGFsbCBnbG9iYWwgZGVmYXVsdHNcblx0ICogQHBhcmFtICB2YWx1ZSAgIGFueSAtIHRoZSBuZXcgdmFsdWUgZm9yIHRoZSBzZXR0aW5nXG5cdCAqXHRcdFx0XHQob21pdCBpZiBhYm92ZSBpcyBhbiBvYmplY3Qgb3IgdG8gcmV0cmlldmUgYSB2YWx1ZSlcblx0ICovXG5cdF9vcHRpb25EYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0LCBuYW1lLCB2YWx1ZSApIHtcblx0XHR2YXIgc2V0dGluZ3MsIGRhdGUsIG1pbkRhdGUsIG1heERhdGUsXG5cdFx0XHRpbnN0ID0gdGhpcy5fZ2V0SW5zdCggdGFyZ2V0ICk7XG5cblx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggPT09IDIgJiYgdHlwZW9mIG5hbWUgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRyZXR1cm4gKCBuYW1lID09PSBcImRlZmF1bHRzXCIgPyAkLmV4dGVuZCgge30sICQuZGF0ZXBpY2tlci5fZGVmYXVsdHMgKSA6XG5cdFx0XHRcdCggaW5zdCA/ICggbmFtZSA9PT0gXCJhbGxcIiA/ICQuZXh0ZW5kKCB7fSwgaW5zdC5zZXR0aW5ncyApIDpcblx0XHRcdFx0dGhpcy5fZ2V0KCBpbnN0LCBuYW1lICkgKSA6IG51bGwgKSApO1xuXHRcdH1cblxuXHRcdHNldHRpbmdzID0gbmFtZSB8fCB7fTtcblx0XHRpZiAoIHR5cGVvZiBuYW1lID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0c2V0dGluZ3MgPSB7fTtcblx0XHRcdHNldHRpbmdzWyBuYW1lIF0gPSB2YWx1ZTtcblx0XHR9XG5cblx0XHRpZiAoIGluc3QgKSB7XG5cdFx0XHRpZiAoIHRoaXMuX2N1ckluc3QgPT09IGluc3QgKSB7XG5cdFx0XHRcdHRoaXMuX2hpZGVEYXRlcGlja2VyKCk7XG5cdFx0XHR9XG5cblx0XHRcdGRhdGUgPSB0aGlzLl9nZXREYXRlRGF0ZXBpY2tlciggdGFyZ2V0LCB0cnVlICk7XG5cdFx0XHRtaW5EYXRlID0gdGhpcy5fZ2V0TWluTWF4RGF0ZSggaW5zdCwgXCJtaW5cIiApO1xuXHRcdFx0bWF4RGF0ZSA9IHRoaXMuX2dldE1pbk1heERhdGUoIGluc3QsIFwibWF4XCIgKTtcblx0XHRcdGRhdGVwaWNrZXJfZXh0ZW5kUmVtb3ZlKCBpbnN0LnNldHRpbmdzLCBzZXR0aW5ncyApO1xuXG5cdFx0XHQvLyByZWZvcm1hdCB0aGUgb2xkIG1pbkRhdGUvbWF4RGF0ZSB2YWx1ZXMgaWYgZGF0ZUZvcm1hdCBjaGFuZ2VzIGFuZCBhIG5ldyBtaW5EYXRlL21heERhdGUgaXNuJ3QgcHJvdmlkZWRcblx0XHRcdGlmICggbWluRGF0ZSAhPT0gbnVsbCAmJiBzZXR0aW5ncy5kYXRlRm9ybWF0ICE9PSB1bmRlZmluZWQgJiYgc2V0dGluZ3MubWluRGF0ZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRpbnN0LnNldHRpbmdzLm1pbkRhdGUgPSB0aGlzLl9mb3JtYXREYXRlKCBpbnN0LCBtaW5EYXRlICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIG1heERhdGUgIT09IG51bGwgJiYgc2V0dGluZ3MuZGF0ZUZvcm1hdCAhPT0gdW5kZWZpbmVkICYmIHNldHRpbmdzLm1heERhdGUgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0aW5zdC5zZXR0aW5ncy5tYXhEYXRlID0gdGhpcy5fZm9ybWF0RGF0ZSggaW5zdCwgbWF4RGF0ZSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBcImRpc2FibGVkXCIgaW4gc2V0dGluZ3MgKSB7XG5cdFx0XHRcdGlmICggc2V0dGluZ3MuZGlzYWJsZWQgKSB7XG5cdFx0XHRcdFx0dGhpcy5fZGlzYWJsZURhdGVwaWNrZXIoIHRhcmdldCApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRoaXMuX2VuYWJsZURhdGVwaWNrZXIoIHRhcmdldCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9hdHRhY2htZW50cyggJCggdGFyZ2V0ICksIGluc3QgKTtcblx0XHRcdHRoaXMuX2F1dG9TaXplKCBpbnN0ICk7XG5cdFx0XHR0aGlzLl9zZXREYXRlKCBpbnN0LCBkYXRlICk7XG5cdFx0XHR0aGlzLl91cGRhdGVBbHRlcm5hdGUoIGluc3QgKTtcblx0XHRcdHRoaXMuX3VwZGF0ZURhdGVwaWNrZXIoIGluc3QgKTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gQ2hhbmdlIG1ldGhvZCBkZXByZWNhdGVkXG5cdF9jaGFuZ2VEYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0LCBuYW1lLCB2YWx1ZSApIHtcblx0XHR0aGlzLl9vcHRpb25EYXRlcGlja2VyKCB0YXJnZXQsIG5hbWUsIHZhbHVlICk7XG5cdH0sXG5cblx0LyogUmVkcmF3IHRoZSBkYXRlIHBpY2tlciBhdHRhY2hlZCB0byBhbiBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbi5cblx0ICogQHBhcmFtICB0YXJnZXQgIGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICovXG5cdF9yZWZyZXNoRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCApIHtcblx0XHR2YXIgaW5zdCA9IHRoaXMuX2dldEluc3QoIHRhcmdldCApO1xuXHRcdGlmICggaW5zdCApIHtcblx0XHRcdHRoaXMuX3VwZGF0ZURhdGVwaWNrZXIoIGluc3QgKTtcblx0XHR9XG5cdH0sXG5cblx0LyogU2V0IHRoZSBkYXRlcyBmb3IgYSBqUXVlcnkgc2VsZWN0aW9uLlxuXHQgKiBAcGFyYW0gIHRhcmdldCBlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqIEBwYXJhbSAgZGF0ZVx0RGF0ZSAtIHRoZSBuZXcgZGF0ZVxuXHQgKi9cblx0X3NldERhdGVEYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0LCBkYXRlICkge1xuXHRcdHZhciBpbnN0ID0gdGhpcy5fZ2V0SW5zdCggdGFyZ2V0ICk7XG5cdFx0aWYgKCBpbnN0ICkge1xuXHRcdFx0dGhpcy5fc2V0RGF0ZSggaW5zdCwgZGF0ZSApO1xuXHRcdFx0dGhpcy5fdXBkYXRlRGF0ZXBpY2tlciggaW5zdCApO1xuXHRcdFx0dGhpcy5fdXBkYXRlQWx0ZXJuYXRlKCBpbnN0ICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIEdldCB0aGUgZGF0ZShzKSBmb3IgdGhlIGZpcnN0IGVudHJ5IGluIGEgalF1ZXJ5IHNlbGVjdGlvbi5cblx0ICogQHBhcmFtICB0YXJnZXQgZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKiBAcGFyYW0gIG5vRGVmYXVsdCBib29sZWFuIC0gdHJ1ZSBpZiBubyBkZWZhdWx0IGRhdGUgaXMgdG8gYmUgdXNlZFxuXHQgKiBAcmV0dXJuIERhdGUgLSB0aGUgY3VycmVudCBkYXRlXG5cdCAqL1xuXHRfZ2V0RGF0ZURhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQsIG5vRGVmYXVsdCApIHtcblx0XHR2YXIgaW5zdCA9IHRoaXMuX2dldEluc3QoIHRhcmdldCApO1xuXHRcdGlmICggaW5zdCAmJiAhaW5zdC5pbmxpbmUgKSB7XG5cdFx0XHR0aGlzLl9zZXREYXRlRnJvbUZpZWxkKCBpbnN0LCBub0RlZmF1bHQgKTtcblx0XHR9XG5cdFx0cmV0dXJuICggaW5zdCA/IHRoaXMuX2dldERhdGUoIGluc3QgKSA6IG51bGwgKTtcblx0fSxcblxuXHQvKiBIYW5kbGUga2V5c3Ryb2tlcy4gKi9cblx0X2RvS2V5RG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBvblNlbGVjdCwgZGF0ZVN0ciwgc2VsLFxuXHRcdFx0aW5zdCA9ICQuZGF0ZXBpY2tlci5fZ2V0SW5zdCggZXZlbnQudGFyZ2V0ICksXG5cdFx0XHRoYW5kbGVkID0gdHJ1ZSxcblx0XHRcdGlzUlRMID0gaW5zdC5kcERpdi5pcyggXCIudWktZGF0ZXBpY2tlci1ydGxcIiApO1xuXG5cdFx0aW5zdC5fa2V5RXZlbnQgPSB0cnVlO1xuXHRcdGlmICggJC5kYXRlcGlja2VyLl9kYXRlcGlja2VyU2hvd2luZyApIHtcblx0XHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0XHRcdGNhc2UgOTogJC5kYXRlcGlja2VyLl9oaWRlRGF0ZXBpY2tlcigpO1xuXHRcdFx0XHRcdFx0aGFuZGxlZCA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0YnJlYWs7IC8vIGhpZGUgb24gdGFiIG91dFxuXHRcdFx0XHRjYXNlIDEzOiBzZWwgPSAkKCBcInRkLlwiICsgJC5kYXRlcGlja2VyLl9kYXlPdmVyQ2xhc3MgKyBcIjpub3QoLlwiICtcblx0XHRcdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fY3VycmVudENsYXNzICsgXCIpXCIsIGluc3QuZHBEaXYgKTtcblx0XHRcdFx0XHRcdGlmICggc2VsWyAwIF0gKSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fc2VsZWN0RGF5KCBldmVudC50YXJnZXQsIGluc3Quc2VsZWN0ZWRNb250aCwgaW5zdC5zZWxlY3RlZFllYXIsIHNlbFsgMCBdICk7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdG9uU2VsZWN0ID0gJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwib25TZWxlY3RcIiApO1xuXHRcdFx0XHRcdFx0aWYgKCBvblNlbGVjdCApIHtcblx0XHRcdFx0XHRcdFx0ZGF0ZVN0ciA9ICQuZGF0ZXBpY2tlci5fZm9ybWF0RGF0ZSggaW5zdCApO1xuXG5cdFx0XHRcdFx0XHRcdC8vIFRyaWdnZXIgY3VzdG9tIGNhbGxiYWNrXG5cdFx0XHRcdFx0XHRcdG9uU2VsZWN0LmFwcGx5KCAoIGluc3QuaW5wdXQgPyBpbnN0LmlucHV0WyAwIF0gOiBudWxsICksIFsgZGF0ZVN0ciwgaW5zdCBdICk7XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2hpZGVEYXRlcGlja2VyKCk7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTsgLy8gZG9uJ3Qgc3VibWl0IHRoZSBmb3JtXG5cdFx0XHRcdGNhc2UgMjc6ICQuZGF0ZXBpY2tlci5faGlkZURhdGVwaWNrZXIoKTtcblx0XHRcdFx0XHRcdGJyZWFrOyAvLyBoaWRlIG9uIGVzY2FwZVxuXHRcdFx0XHRjYXNlIDMzOiAkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGV2ZW50LnRhcmdldCwgKCBldmVudC5jdHJsS2V5ID9cblx0XHRcdFx0XHRcdFx0LSQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInN0ZXBCaWdNb250aHNcIiApIDpcblx0XHRcdFx0XHRcdFx0LSQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInN0ZXBNb250aHNcIiApICksIFwiTVwiICk7XG5cdFx0XHRcdFx0XHRicmVhazsgLy8gcHJldmlvdXMgbW9udGgveWVhciBvbiBwYWdlIHVwLysgY3RybFxuXHRcdFx0XHRjYXNlIDM0OiAkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGV2ZW50LnRhcmdldCwgKCBldmVudC5jdHJsS2V5ID9cblx0XHRcdFx0XHRcdFx0KyQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInN0ZXBCaWdNb250aHNcIiApIDpcblx0XHRcdFx0XHRcdFx0KyQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInN0ZXBNb250aHNcIiApICksIFwiTVwiICk7XG5cdFx0XHRcdFx0XHRicmVhazsgLy8gbmV4dCBtb250aC95ZWFyIG9uIHBhZ2UgZG93bi8rIGN0cmxcblx0XHRcdFx0Y2FzZSAzNTogaWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgKSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fY2xlYXJEYXRlKCBldmVudC50YXJnZXQgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGhhbmRsZWQgPSBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXk7XG5cdFx0XHRcdFx0XHRicmVhazsgLy8gY2xlYXIgb24gY3RybCBvciBjb21tYW5kICtlbmRcblx0XHRcdFx0Y2FzZSAzNjogaWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgKSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fZ290b1RvZGF5KCBldmVudC50YXJnZXQgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGhhbmRsZWQgPSBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXk7XG5cdFx0XHRcdFx0XHRicmVhazsgLy8gY3VycmVudCBvbiBjdHJsIG9yIGNvbW1hbmQgK2hvbWVcblx0XHRcdFx0Y2FzZSAzNzogaWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgKSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggZXZlbnQudGFyZ2V0LCAoIGlzUlRMID8gKzEgOiAtMSApLCBcIkRcIiApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aGFuZGxlZCA9IGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleTtcblxuXHRcdFx0XHRcdFx0Ly8gLTEgZGF5IG9uIGN0cmwgb3IgY29tbWFuZCArbGVmdFxuXHRcdFx0XHRcdFx0aWYgKCBldmVudC5vcmlnaW5hbEV2ZW50LmFsdEtleSApIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBldmVudC50YXJnZXQsICggZXZlbnQuY3RybEtleSA/XG5cdFx0XHRcdFx0XHRcdFx0LSQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInN0ZXBCaWdNb250aHNcIiApIDpcblx0XHRcdFx0XHRcdFx0XHQtJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic3RlcE1vbnRoc1wiICkgKSwgXCJNXCIgKTtcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Ly8gbmV4dCBtb250aC95ZWFyIG9uIGFsdCArbGVmdCBvbiBNYWNcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIDM4OiBpZiAoIGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSApIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBldmVudC50YXJnZXQsIC03LCBcIkRcIiApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aGFuZGxlZCA9IGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleTtcblx0XHRcdFx0XHRcdGJyZWFrOyAvLyAtMSB3ZWVrIG9uIGN0cmwgb3IgY29tbWFuZCArdXBcblx0XHRcdFx0Y2FzZSAzOTogaWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgKSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggZXZlbnQudGFyZ2V0LCAoIGlzUlRMID8gLTEgOiArMSApLCBcIkRcIiApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aGFuZGxlZCA9IGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleTtcblxuXHRcdFx0XHRcdFx0Ly8gKzEgZGF5IG9uIGN0cmwgb3IgY29tbWFuZCArcmlnaHRcblx0XHRcdFx0XHRcdGlmICggZXZlbnQub3JpZ2luYWxFdmVudC5hbHRLZXkgKSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggZXZlbnQudGFyZ2V0LCAoIGV2ZW50LmN0cmxLZXkgP1xuXHRcdFx0XHRcdFx0XHRcdCskLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzdGVwQmlnTW9udGhzXCIgKSA6XG5cdFx0XHRcdFx0XHRcdFx0KyQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInN0ZXBNb250aHNcIiApICksIFwiTVwiICk7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIG5leHQgbW9udGgveWVhciBvbiBhbHQgK3JpZ2h0XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSA0MDogaWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgKSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggZXZlbnQudGFyZ2V0LCArNywgXCJEXCIgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGhhbmRsZWQgPSBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXk7XG5cdFx0XHRcdFx0XHRicmVhazsgLy8gKzEgd2VlayBvbiBjdHJsIG9yIGNvbW1hbmQgK2Rvd25cblx0XHRcdFx0ZGVmYXVsdDogaGFuZGxlZCA9IGZhbHNlO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSBpZiAoIGV2ZW50LmtleUNvZGUgPT09IDM2ICYmIGV2ZW50LmN0cmxLZXkgKSB7IC8vIGRpc3BsYXkgdGhlIGRhdGUgcGlja2VyIG9uIGN0cmwraG9tZVxuXHRcdFx0JC5kYXRlcGlja2VyLl9zaG93RGF0ZXBpY2tlciggdGhpcyApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRoYW5kbGVkID0gZmFsc2U7XG5cdFx0fVxuXG5cdFx0aWYgKCBoYW5kbGVkICkge1xuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdH1cblx0fSxcblxuXHQvKiBGaWx0ZXIgZW50ZXJlZCBjaGFyYWN0ZXJzIC0gYmFzZWQgb24gZGF0ZSBmb3JtYXQuICovXG5cdF9kb0tleVByZXNzOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGNoYXJzLCBjaHIsXG5cdFx0XHRpbnN0ID0gJC5kYXRlcGlja2VyLl9nZXRJbnN0KCBldmVudC50YXJnZXQgKTtcblxuXHRcdGlmICggJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwiY29uc3RyYWluSW5wdXRcIiApICkge1xuXHRcdFx0Y2hhcnMgPSAkLmRhdGVwaWNrZXIuX3Bvc3NpYmxlQ2hhcnMoICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcImRhdGVGb3JtYXRcIiApICk7XG5cdFx0XHRjaHIgPSBTdHJpbmcuZnJvbUNoYXJDb2RlKCBldmVudC5jaGFyQ29kZSA9PSBudWxsID8gZXZlbnQua2V5Q29kZSA6IGV2ZW50LmNoYXJDb2RlICk7XG5cdFx0XHRyZXR1cm4gZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5IHx8ICggY2hyIDwgXCIgXCIgfHwgIWNoYXJzIHx8IGNoYXJzLmluZGV4T2YoIGNociApID4gLTEgKTtcblx0XHR9XG5cdH0sXG5cblx0LyogU3luY2hyb25pc2UgbWFudWFsIGVudHJ5IGFuZCBmaWVsZC9hbHRlcm5hdGUgZmllbGQuICovXG5cdF9kb0tleVVwOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGRhdGUsXG5cdFx0XHRpbnN0ID0gJC5kYXRlcGlja2VyLl9nZXRJbnN0KCBldmVudC50YXJnZXQgKTtcblxuXHRcdGlmICggaW5zdC5pbnB1dC52YWwoKSAhPT0gaW5zdC5sYXN0VmFsICkge1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0ZGF0ZSA9ICQuZGF0ZXBpY2tlci5wYXJzZURhdGUoICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcImRhdGVGb3JtYXRcIiApLFxuXHRcdFx0XHRcdCggaW5zdC5pbnB1dCA/IGluc3QuaW5wdXQudmFsKCkgOiBudWxsICksXG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9nZXRGb3JtYXRDb25maWcoIGluc3QgKSApO1xuXG5cdFx0XHRcdGlmICggZGF0ZSApIHsgLy8gb25seSBpZiB2YWxpZFxuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fc2V0RGF0ZUZyb21GaWVsZCggaW5zdCApO1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fdXBkYXRlQWx0ZXJuYXRlKCBpbnN0ICk7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl91cGRhdGVEYXRlcGlja2VyKCBpbnN0ICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGNhdGNoICggZXJyICkge1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHQvKiBQb3AtdXAgdGhlIGRhdGUgcGlja2VyIGZvciBhIGdpdmVuIGlucHV0IGZpZWxkLlxuXHQgKiBJZiBmYWxzZSByZXR1cm5lZCBmcm9tIGJlZm9yZVNob3cgZXZlbnQgaGFuZGxlciBkbyBub3Qgc2hvdy5cblx0ICogQHBhcmFtICBpbnB1dCAgZWxlbWVudCAtIHRoZSBpbnB1dCBmaWVsZCBhdHRhY2hlZCB0byB0aGUgZGF0ZSBwaWNrZXIgb3Jcblx0ICpcdFx0XHRcdFx0ZXZlbnQgLSBpZiB0cmlnZ2VyZWQgYnkgZm9jdXNcblx0ICovXG5cdF9zaG93RGF0ZXBpY2tlcjogZnVuY3Rpb24oIGlucHV0ICkge1xuXHRcdGlucHV0ID0gaW5wdXQudGFyZ2V0IHx8IGlucHV0O1xuXHRcdGlmICggaW5wdXQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAhPT0gXCJpbnB1dFwiICkgeyAvLyBmaW5kIGZyb20gYnV0dG9uL2ltYWdlIHRyaWdnZXJcblx0XHRcdGlucHV0ID0gJCggXCJpbnB1dFwiLCBpbnB1dC5wYXJlbnROb2RlIClbIDAgXTtcblx0XHR9XG5cblx0XHRpZiAoICQuZGF0ZXBpY2tlci5faXNEaXNhYmxlZERhdGVwaWNrZXIoIGlucHV0ICkgfHwgJC5kYXRlcGlja2VyLl9sYXN0SW5wdXQgPT09IGlucHV0ICkgeyAvLyBhbHJlYWR5IGhlcmVcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgaW5zdCwgYmVmb3JlU2hvdywgYmVmb3JlU2hvd1NldHRpbmdzLCBpc0ZpeGVkLFxuXHRcdFx0b2Zmc2V0LCBzaG93QW5pbSwgZHVyYXRpb247XG5cblx0XHRpbnN0ID0gJC5kYXRlcGlja2VyLl9nZXRJbnN0KCBpbnB1dCApO1xuXHRcdGlmICggJC5kYXRlcGlja2VyLl9jdXJJbnN0ICYmICQuZGF0ZXBpY2tlci5fY3VySW5zdCAhPT0gaW5zdCApIHtcblx0XHRcdCQuZGF0ZXBpY2tlci5fY3VySW5zdC5kcERpdi5zdG9wKCB0cnVlLCB0cnVlICk7XG5cdFx0XHRpZiAoIGluc3QgJiYgJC5kYXRlcGlja2VyLl9kYXRlcGlja2VyU2hvd2luZyApIHtcblx0XHRcdFx0JC5kYXRlcGlja2VyLl9oaWRlRGF0ZXBpY2tlciggJC5kYXRlcGlja2VyLl9jdXJJbnN0LmlucHV0WyAwIF0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRiZWZvcmVTaG93ID0gJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwiYmVmb3JlU2hvd1wiICk7XG5cdFx0YmVmb3JlU2hvd1NldHRpbmdzID0gYmVmb3JlU2hvdyA/IGJlZm9yZVNob3cuYXBwbHkoIGlucHV0LCBbIGlucHV0LCBpbnN0IF0gKSA6IHt9O1xuXHRcdGlmICggYmVmb3JlU2hvd1NldHRpbmdzID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0ZGF0ZXBpY2tlcl9leHRlbmRSZW1vdmUoIGluc3Quc2V0dGluZ3MsIGJlZm9yZVNob3dTZXR0aW5ncyApO1xuXG5cdFx0aW5zdC5sYXN0VmFsID0gbnVsbDtcblx0XHQkLmRhdGVwaWNrZXIuX2xhc3RJbnB1dCA9IGlucHV0O1xuXHRcdCQuZGF0ZXBpY2tlci5fc2V0RGF0ZUZyb21GaWVsZCggaW5zdCApO1xuXG5cdFx0aWYgKCAkLmRhdGVwaWNrZXIuX2luRGlhbG9nICkgeyAvLyBoaWRlIGN1cnNvclxuXHRcdFx0aW5wdXQudmFsdWUgPSBcIlwiO1xuXHRcdH1cblx0XHRpZiAoICEkLmRhdGVwaWNrZXIuX3BvcyApIHsgLy8gcG9zaXRpb24gYmVsb3cgaW5wdXRcblx0XHRcdCQuZGF0ZXBpY2tlci5fcG9zID0gJC5kYXRlcGlja2VyLl9maW5kUG9zKCBpbnB1dCApO1xuXHRcdFx0JC5kYXRlcGlja2VyLl9wb3NbIDEgXSArPSBpbnB1dC5vZmZzZXRIZWlnaHQ7IC8vIGFkZCB0aGUgaGVpZ2h0XG5cdFx0fVxuXG5cdFx0aXNGaXhlZCA9IGZhbHNlO1xuXHRcdCQoIGlucHV0ICkucGFyZW50cygpLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0aXNGaXhlZCB8PSAkKCB0aGlzICkuY3NzKCBcInBvc2l0aW9uXCIgKSA9PT0gXCJmaXhlZFwiO1xuXHRcdFx0cmV0dXJuICFpc0ZpeGVkO1xuXHRcdH0gKTtcblxuXHRcdG9mZnNldCA9IHsgbGVmdDogJC5kYXRlcGlja2VyLl9wb3NbIDAgXSwgdG9wOiAkLmRhdGVwaWNrZXIuX3Bvc1sgMSBdIH07XG5cdFx0JC5kYXRlcGlja2VyLl9wb3MgPSBudWxsO1xuXG5cdFx0Ly90byBhdm9pZCBmbGFzaGVzIG9uIEZpcmVmb3hcblx0XHRpbnN0LmRwRGl2LmVtcHR5KCk7XG5cblx0XHQvLyBkZXRlcm1pbmUgc2l6aW5nIG9mZnNjcmVlblxuXHRcdGluc3QuZHBEaXYuY3NzKCB7IHBvc2l0aW9uOiBcImFic29sdXRlXCIsIGRpc3BsYXk6IFwiYmxvY2tcIiwgdG9wOiBcIi0xMDAwcHhcIiB9ICk7XG5cdFx0JC5kYXRlcGlja2VyLl91cGRhdGVEYXRlcGlja2VyKCBpbnN0ICk7XG5cblx0XHQvLyBmaXggd2lkdGggZm9yIGR5bmFtaWMgbnVtYmVyIG9mIGRhdGUgcGlja2Vyc1xuXHRcdC8vIGFuZCBhZGp1c3QgcG9zaXRpb24gYmVmb3JlIHNob3dpbmdcblx0XHRvZmZzZXQgPSAkLmRhdGVwaWNrZXIuX2NoZWNrT2Zmc2V0KCBpbnN0LCBvZmZzZXQsIGlzRml4ZWQgKTtcblx0XHRpbnN0LmRwRGl2LmNzcyggeyBwb3NpdGlvbjogKCAkLmRhdGVwaWNrZXIuX2luRGlhbG9nICYmICQuYmxvY2tVSSA/XG5cdFx0XHRcInN0YXRpY1wiIDogKCBpc0ZpeGVkID8gXCJmaXhlZFwiIDogXCJhYnNvbHV0ZVwiICkgKSwgZGlzcGxheTogXCJub25lXCIsXG5cdFx0XHRsZWZ0OiBvZmZzZXQubGVmdCArIFwicHhcIiwgdG9wOiBvZmZzZXQudG9wICsgXCJweFwiIH0gKTtcblxuXHRcdGlmICggIWluc3QuaW5saW5lICkge1xuXHRcdFx0c2hvd0FuaW0gPSAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzaG93QW5pbVwiICk7XG5cdFx0XHRkdXJhdGlvbiA9ICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcImR1cmF0aW9uXCIgKTtcblx0XHRcdGluc3QuZHBEaXYuY3NzKCBcInotaW5kZXhcIiwgZGF0ZXBpY2tlcl9nZXRaaW5kZXgoICQoIGlucHV0ICkgKSArIDEgKTtcblx0XHRcdCQuZGF0ZXBpY2tlci5fZGF0ZXBpY2tlclNob3dpbmcgPSB0cnVlO1xuXG5cdFx0XHRpZiAoICQuZWZmZWN0cyAmJiAkLmVmZmVjdHMuZWZmZWN0WyBzaG93QW5pbSBdICkge1xuXHRcdFx0XHRpbnN0LmRwRGl2LnNob3coIHNob3dBbmltLCAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzaG93T3B0aW9uc1wiICksIGR1cmF0aW9uICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpbnN0LmRwRGl2WyBzaG93QW5pbSB8fCBcInNob3dcIiBdKCBzaG93QW5pbSA/IGR1cmF0aW9uIDogbnVsbCApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICQuZGF0ZXBpY2tlci5fc2hvdWxkRm9jdXNJbnB1dCggaW5zdCApICkge1xuXHRcdFx0XHRpbnN0LmlucHV0LnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQkLmRhdGVwaWNrZXIuX2N1ckluc3QgPSBpbnN0O1xuXHRcdH1cblx0fSxcblxuXHQvKiBHZW5lcmF0ZSB0aGUgZGF0ZSBwaWNrZXIgY29udGVudC4gKi9cblx0X3VwZGF0ZURhdGVwaWNrZXI6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHRoaXMubWF4Um93cyA9IDQ7IC8vUmVzZXQgdGhlIG1heCBudW1iZXIgb2Ygcm93cyBiZWluZyBkaXNwbGF5ZWQgKHNlZSAjNzA0Mylcblx0XHRkYXRlcGlja2VyX2luc3RBY3RpdmUgPSBpbnN0OyAvLyBmb3IgZGVsZWdhdGUgaG92ZXIgZXZlbnRzXG5cdFx0aW5zdC5kcERpdi5lbXB0eSgpLmFwcGVuZCggdGhpcy5fZ2VuZXJhdGVIVE1MKCBpbnN0ICkgKTtcblx0XHR0aGlzLl9hdHRhY2hIYW5kbGVycyggaW5zdCApO1xuXG5cdFx0dmFyIG9yaWd5ZWFyc2h0bWwsXG5cdFx0XHRudW1Nb250aHMgPSB0aGlzLl9nZXROdW1iZXJPZk1vbnRocyggaW5zdCApLFxuXHRcdFx0Y29scyA9IG51bU1vbnRoc1sgMSBdLFxuXHRcdFx0d2lkdGggPSAxNyxcblx0XHRcdGFjdGl2ZUNlbGwgPSBpbnN0LmRwRGl2LmZpbmQoIFwiLlwiICsgdGhpcy5fZGF5T3ZlckNsYXNzICsgXCIgYVwiICk7XG5cblx0XHRpZiAoIGFjdGl2ZUNlbGwubGVuZ3RoID4gMCApIHtcblx0XHRcdGRhdGVwaWNrZXJfaGFuZGxlTW91c2VvdmVyLmFwcGx5KCBhY3RpdmVDZWxsLmdldCggMCApICk7XG5cdFx0fVxuXG5cdFx0aW5zdC5kcERpdi5yZW1vdmVDbGFzcyggXCJ1aS1kYXRlcGlja2VyLW11bHRpLTIgdWktZGF0ZXBpY2tlci1tdWx0aS0zIHVpLWRhdGVwaWNrZXItbXVsdGktNFwiICkud2lkdGgoIFwiXCIgKTtcblx0XHRpZiAoIGNvbHMgPiAxICkge1xuXHRcdFx0aW5zdC5kcERpdi5hZGRDbGFzcyggXCJ1aS1kYXRlcGlja2VyLW11bHRpLVwiICsgY29scyApLmNzcyggXCJ3aWR0aFwiLCAoIHdpZHRoICogY29scyApICsgXCJlbVwiICk7XG5cdFx0fVxuXHRcdGluc3QuZHBEaXZbICggbnVtTW9udGhzWyAwIF0gIT09IDEgfHwgbnVtTW9udGhzWyAxIF0gIT09IDEgPyBcImFkZFwiIDogXCJyZW1vdmVcIiApICtcblx0XHRcdFwiQ2xhc3NcIiBdKCBcInVpLWRhdGVwaWNrZXItbXVsdGlcIiApO1xuXHRcdGluc3QuZHBEaXZbICggdGhpcy5fZ2V0KCBpbnN0LCBcImlzUlRMXCIgKSA/IFwiYWRkXCIgOiBcInJlbW92ZVwiICkgK1xuXHRcdFx0XCJDbGFzc1wiIF0oIFwidWktZGF0ZXBpY2tlci1ydGxcIiApO1xuXG5cdFx0aWYgKCBpbnN0ID09PSAkLmRhdGVwaWNrZXIuX2N1ckluc3QgJiYgJC5kYXRlcGlja2VyLl9kYXRlcGlja2VyU2hvd2luZyAmJiAkLmRhdGVwaWNrZXIuX3Nob3VsZEZvY3VzSW5wdXQoIGluc3QgKSApIHtcblx0XHRcdGluc3QuaW5wdXQudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0fVxuXG5cdFx0Ly8gRGVmZmVyZWQgcmVuZGVyIG9mIHRoZSB5ZWFycyBzZWxlY3QgKHRvIGF2b2lkIGZsYXNoZXMgb24gRmlyZWZveClcblx0XHRpZiAoIGluc3QueWVhcnNodG1sICkge1xuXHRcdFx0b3JpZ3llYXJzaHRtbCA9IGluc3QueWVhcnNodG1sO1xuXHRcdFx0c2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0Ly9hc3N1cmUgdGhhdCBpbnN0LnllYXJzaHRtbCBkaWRuJ3QgY2hhbmdlLlxuXHRcdFx0XHRpZiAoIG9yaWd5ZWFyc2h0bWwgPT09IGluc3QueWVhcnNodG1sICYmIGluc3QueWVhcnNodG1sICkge1xuXHRcdFx0XHRcdGluc3QuZHBEaXYuZmluZCggXCJzZWxlY3QudWktZGF0ZXBpY2tlci15ZWFyOmZpcnN0XCIgKS5yZXBsYWNlV2l0aCggaW5zdC55ZWFyc2h0bWwgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRvcmlneWVhcnNodG1sID0gaW5zdC55ZWFyc2h0bWwgPSBudWxsO1xuXHRcdFx0fSwgMCApO1xuXHRcdH1cblx0fSxcblxuXHQvLyAjNjY5NCAtIGRvbid0IGZvY3VzIHRoZSBpbnB1dCBpZiBpdCdzIGFscmVhZHkgZm9jdXNlZFxuXHQvLyB0aGlzIGJyZWFrcyB0aGUgY2hhbmdlIGV2ZW50IGluIElFXG5cdC8vIFN1cHBvcnQ6IElFIGFuZCBqUXVlcnkgPDEuOVxuXHRfc2hvdWxkRm9jdXNJbnB1dDogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0cmV0dXJuIGluc3QuaW5wdXQgJiYgaW5zdC5pbnB1dC5pcyggXCI6dmlzaWJsZVwiICkgJiYgIWluc3QuaW5wdXQuaXMoIFwiOmRpc2FibGVkXCIgKSAmJiAhaW5zdC5pbnB1dC5pcyggXCI6Zm9jdXNcIiApO1xuXHR9LFxuXG5cdC8qIENoZWNrIHBvc2l0aW9uaW5nIHRvIHJlbWFpbiBvbiBzY3JlZW4uICovXG5cdF9jaGVja09mZnNldDogZnVuY3Rpb24oIGluc3QsIG9mZnNldCwgaXNGaXhlZCApIHtcblx0XHR2YXIgZHBXaWR0aCA9IGluc3QuZHBEaXYub3V0ZXJXaWR0aCgpLFxuXHRcdFx0ZHBIZWlnaHQgPSBpbnN0LmRwRGl2Lm91dGVySGVpZ2h0KCksXG5cdFx0XHRpbnB1dFdpZHRoID0gaW5zdC5pbnB1dCA/IGluc3QuaW5wdXQub3V0ZXJXaWR0aCgpIDogMCxcblx0XHRcdGlucHV0SGVpZ2h0ID0gaW5zdC5pbnB1dCA/IGluc3QuaW5wdXQub3V0ZXJIZWlnaHQoKSA6IDAsXG5cdFx0XHR2aWV3V2lkdGggPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50V2lkdGggKyAoIGlzRml4ZWQgPyAwIDogJCggZG9jdW1lbnQgKS5zY3JvbGxMZWZ0KCkgKSxcblx0XHRcdHZpZXdIZWlnaHQgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0ICsgKCBpc0ZpeGVkID8gMCA6ICQoIGRvY3VtZW50ICkuc2Nyb2xsVG9wKCkgKTtcblxuXHRcdG9mZnNldC5sZWZ0IC09ICggdGhpcy5fZ2V0KCBpbnN0LCBcImlzUlRMXCIgKSA/ICggZHBXaWR0aCAtIGlucHV0V2lkdGggKSA6IDAgKTtcblx0XHRvZmZzZXQubGVmdCAtPSAoIGlzRml4ZWQgJiYgb2Zmc2V0LmxlZnQgPT09IGluc3QuaW5wdXQub2Zmc2V0KCkubGVmdCApID8gJCggZG9jdW1lbnQgKS5zY3JvbGxMZWZ0KCkgOiAwO1xuXHRcdG9mZnNldC50b3AgLT0gKCBpc0ZpeGVkICYmIG9mZnNldC50b3AgPT09ICggaW5zdC5pbnB1dC5vZmZzZXQoKS50b3AgKyBpbnB1dEhlaWdodCApICkgPyAkKCBkb2N1bWVudCApLnNjcm9sbFRvcCgpIDogMDtcblxuXHRcdC8vIE5vdyBjaGVjayBpZiBkYXRlcGlja2VyIGlzIHNob3dpbmcgb3V0c2lkZSB3aW5kb3cgdmlld3BvcnQgLSBtb3ZlIHRvIGEgYmV0dGVyIHBsYWNlIGlmIHNvLlxuXHRcdG9mZnNldC5sZWZ0IC09IE1hdGgubWluKCBvZmZzZXQubGVmdCwgKCBvZmZzZXQubGVmdCArIGRwV2lkdGggPiB2aWV3V2lkdGggJiYgdmlld1dpZHRoID4gZHBXaWR0aCApID9cblx0XHRcdE1hdGguYWJzKCBvZmZzZXQubGVmdCArIGRwV2lkdGggLSB2aWV3V2lkdGggKSA6IDAgKTtcblx0XHRvZmZzZXQudG9wIC09IE1hdGgubWluKCBvZmZzZXQudG9wLCAoIG9mZnNldC50b3AgKyBkcEhlaWdodCA+IHZpZXdIZWlnaHQgJiYgdmlld0hlaWdodCA+IGRwSGVpZ2h0ICkgP1xuXHRcdFx0TWF0aC5hYnMoIGRwSGVpZ2h0ICsgaW5wdXRIZWlnaHQgKSA6IDAgKTtcblxuXHRcdHJldHVybiBvZmZzZXQ7XG5cdH0sXG5cblx0LyogRmluZCBhbiBvYmplY3QncyBwb3NpdGlvbiBvbiB0aGUgc2NyZWVuLiAqL1xuXHRfZmluZFBvczogZnVuY3Rpb24oIG9iaiApIHtcblx0XHR2YXIgcG9zaXRpb24sXG5cdFx0XHRpbnN0ID0gdGhpcy5fZ2V0SW5zdCggb2JqICksXG5cdFx0XHRpc1JUTCA9IHRoaXMuX2dldCggaW5zdCwgXCJpc1JUTFwiICk7XG5cblx0XHR3aGlsZSAoIG9iaiAmJiAoIG9iai50eXBlID09PSBcImhpZGRlblwiIHx8IG9iai5ub2RlVHlwZSAhPT0gMSB8fCAkLmV4cHIuZmlsdGVycy5oaWRkZW4oIG9iaiApICkgKSB7XG5cdFx0XHRvYmogPSBvYmpbIGlzUlRMID8gXCJwcmV2aW91c1NpYmxpbmdcIiA6IFwibmV4dFNpYmxpbmdcIiBdO1xuXHRcdH1cblxuXHRcdHBvc2l0aW9uID0gJCggb2JqICkub2Zmc2V0KCk7XG5cdFx0cmV0dXJuIFsgcG9zaXRpb24ubGVmdCwgcG9zaXRpb24udG9wIF07XG5cdH0sXG5cblx0LyogSGlkZSB0aGUgZGF0ZSBwaWNrZXIgZnJvbSB2aWV3LlxuXHQgKiBAcGFyYW0gIGlucHV0ICBlbGVtZW50IC0gdGhlIGlucHV0IGZpZWxkIGF0dGFjaGVkIHRvIHRoZSBkYXRlIHBpY2tlclxuXHQgKi9cblx0X2hpZGVEYXRlcGlja2VyOiBmdW5jdGlvbiggaW5wdXQgKSB7XG5cdFx0dmFyIHNob3dBbmltLCBkdXJhdGlvbiwgcG9zdFByb2Nlc3MsIG9uQ2xvc2UsXG5cdFx0XHRpbnN0ID0gdGhpcy5fY3VySW5zdDtcblxuXHRcdGlmICggIWluc3QgfHwgKCBpbnB1dCAmJiBpbnN0ICE9PSAkLmRhdGEoIGlucHV0LCBcImRhdGVwaWNrZXJcIiApICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9kYXRlcGlja2VyU2hvd2luZyApIHtcblx0XHRcdHNob3dBbmltID0gdGhpcy5fZ2V0KCBpbnN0LCBcInNob3dBbmltXCIgKTtcblx0XHRcdGR1cmF0aW9uID0gdGhpcy5fZ2V0KCBpbnN0LCBcImR1cmF0aW9uXCIgKTtcblx0XHRcdHBvc3RQcm9jZXNzID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdCQuZGF0ZXBpY2tlci5fdGlkeURpYWxvZyggaW5zdCApO1xuXHRcdFx0fTtcblxuXHRcdFx0Ly8gREVQUkVDQVRFRDogYWZ0ZXIgQkMgZm9yIDEuOC54ICQuZWZmZWN0c1sgc2hvd0FuaW0gXSBpcyBub3QgbmVlZGVkXG5cdFx0XHRpZiAoICQuZWZmZWN0cyAmJiAoICQuZWZmZWN0cy5lZmZlY3RbIHNob3dBbmltIF0gfHwgJC5lZmZlY3RzWyBzaG93QW5pbSBdICkgKSB7XG5cdFx0XHRcdGluc3QuZHBEaXYuaGlkZSggc2hvd0FuaW0sICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInNob3dPcHRpb25zXCIgKSwgZHVyYXRpb24sIHBvc3RQcm9jZXNzICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpbnN0LmRwRGl2WyAoIHNob3dBbmltID09PSBcInNsaWRlRG93blwiID8gXCJzbGlkZVVwXCIgOlxuXHRcdFx0XHRcdCggc2hvd0FuaW0gPT09IFwiZmFkZUluXCIgPyBcImZhZGVPdXRcIiA6IFwiaGlkZVwiICkgKSBdKCAoIHNob3dBbmltID8gZHVyYXRpb24gOiBudWxsICksIHBvc3RQcm9jZXNzICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggIXNob3dBbmltICkge1xuXHRcdFx0XHRwb3N0UHJvY2VzcygpO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fZGF0ZXBpY2tlclNob3dpbmcgPSBmYWxzZTtcblxuXHRcdFx0b25DbG9zZSA9IHRoaXMuX2dldCggaW5zdCwgXCJvbkNsb3NlXCIgKTtcblx0XHRcdGlmICggb25DbG9zZSApIHtcblx0XHRcdFx0b25DbG9zZS5hcHBseSggKCBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dFsgMCBdIDogbnVsbCApLCBbICggaW5zdC5pbnB1dCA/IGluc3QuaW5wdXQudmFsKCkgOiBcIlwiICksIGluc3QgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl9sYXN0SW5wdXQgPSBudWxsO1xuXHRcdFx0aWYgKCB0aGlzLl9pbkRpYWxvZyApIHtcblx0XHRcdFx0dGhpcy5fZGlhbG9nSW5wdXQuY3NzKCB7IHBvc2l0aW9uOiBcImFic29sdXRlXCIsIGxlZnQ6IFwiMFwiLCB0b3A6IFwiLTEwMHB4XCIgfSApO1xuXHRcdFx0XHRpZiAoICQuYmxvY2tVSSApIHtcblx0XHRcdFx0XHQkLnVuYmxvY2tVSSgpO1xuXHRcdFx0XHRcdCQoIFwiYm9keVwiICkuYXBwZW5kKCB0aGlzLmRwRGl2ICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHRoaXMuX2luRGlhbG9nID0gZmFsc2U7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIFRpZHkgdXAgYWZ0ZXIgYSBkaWFsb2cgZGlzcGxheS4gKi9cblx0X3RpZHlEaWFsb2c6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdGluc3QuZHBEaXYucmVtb3ZlQ2xhc3MoIHRoaXMuX2RpYWxvZ0NsYXNzICkub2ZmKCBcIi51aS1kYXRlcGlja2VyLWNhbGVuZGFyXCIgKTtcblx0fSxcblxuXHQvKiBDbG9zZSBkYXRlIHBpY2tlciBpZiBjbGlja2VkIGVsc2V3aGVyZS4gKi9cblx0X2NoZWNrRXh0ZXJuYWxDbGljazogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggISQuZGF0ZXBpY2tlci5fY3VySW5zdCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgJHRhcmdldCA9ICQoIGV2ZW50LnRhcmdldCApLFxuXHRcdFx0aW5zdCA9ICQuZGF0ZXBpY2tlci5fZ2V0SW5zdCggJHRhcmdldFsgMCBdICk7XG5cblx0XHRpZiAoICggKCAkdGFyZ2V0WyAwIF0uaWQgIT09ICQuZGF0ZXBpY2tlci5fbWFpbkRpdklkICYmXG5cdFx0XHRcdCR0YXJnZXQucGFyZW50cyggXCIjXCIgKyAkLmRhdGVwaWNrZXIuX21haW5EaXZJZCApLmxlbmd0aCA9PT0gMCAmJlxuXHRcdFx0XHQhJHRhcmdldC5oYXNDbGFzcyggJC5kYXRlcGlja2VyLm1hcmtlckNsYXNzTmFtZSApICYmXG5cdFx0XHRcdCEkdGFyZ2V0LmNsb3Nlc3QoIFwiLlwiICsgJC5kYXRlcGlja2VyLl90cmlnZ2VyQ2xhc3MgKS5sZW5ndGggJiZcblx0XHRcdFx0JC5kYXRlcGlja2VyLl9kYXRlcGlja2VyU2hvd2luZyAmJiAhKCAkLmRhdGVwaWNrZXIuX2luRGlhbG9nICYmICQuYmxvY2tVSSApICkgKSB8fFxuXHRcdFx0KCAkdGFyZ2V0Lmhhc0NsYXNzKCAkLmRhdGVwaWNrZXIubWFya2VyQ2xhc3NOYW1lICkgJiYgJC5kYXRlcGlja2VyLl9jdXJJbnN0ICE9PSBpbnN0ICkgKSB7XG5cdFx0XHRcdCQuZGF0ZXBpY2tlci5faGlkZURhdGVwaWNrZXIoKTtcblx0XHR9XG5cdH0sXG5cblx0LyogQWRqdXN0IG9uZSBvZiB0aGUgZGF0ZSBzdWItZmllbGRzLiAqL1xuXHRfYWRqdXN0RGF0ZTogZnVuY3Rpb24oIGlkLCBvZmZzZXQsIHBlcmlvZCApIHtcblx0XHR2YXIgdGFyZ2V0ID0gJCggaWQgKSxcblx0XHRcdGluc3QgPSB0aGlzLl9nZXRJbnN0KCB0YXJnZXRbIDAgXSApO1xuXG5cdFx0aWYgKCB0aGlzLl9pc0Rpc2FibGVkRGF0ZXBpY2tlciggdGFyZ2V0WyAwIF0gKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5fYWRqdXN0SW5zdERhdGUoIGluc3QsIG9mZnNldCArXG5cdFx0XHQoIHBlcmlvZCA9PT0gXCJNXCIgPyB0aGlzLl9nZXQoIGluc3QsIFwic2hvd0N1cnJlbnRBdFBvc1wiICkgOiAwICksIC8vIHVuZG8gcG9zaXRpb25pbmdcblx0XHRcdHBlcmlvZCApO1xuXHRcdHRoaXMuX3VwZGF0ZURhdGVwaWNrZXIoIGluc3QgKTtcblx0fSxcblxuXHQvKiBBY3Rpb24gZm9yIGN1cnJlbnQgbGluay4gKi9cblx0X2dvdG9Ub2RheTogZnVuY3Rpb24oIGlkICkge1xuXHRcdHZhciBkYXRlLFxuXHRcdFx0dGFyZ2V0ID0gJCggaWQgKSxcblx0XHRcdGluc3QgPSB0aGlzLl9nZXRJbnN0KCB0YXJnZXRbIDAgXSApO1xuXG5cdFx0aWYgKCB0aGlzLl9nZXQoIGluc3QsIFwiZ290b0N1cnJlbnRcIiApICYmIGluc3QuY3VycmVudERheSApIHtcblx0XHRcdGluc3Quc2VsZWN0ZWREYXkgPSBpbnN0LmN1cnJlbnREYXk7XG5cdFx0XHRpbnN0LmRyYXdNb250aCA9IGluc3Quc2VsZWN0ZWRNb250aCA9IGluc3QuY3VycmVudE1vbnRoO1xuXHRcdFx0aW5zdC5kcmF3WWVhciA9IGluc3Quc2VsZWN0ZWRZZWFyID0gaW5zdC5jdXJyZW50WWVhcjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZGF0ZSA9IG5ldyBEYXRlKCk7XG5cdFx0XHRpbnN0LnNlbGVjdGVkRGF5ID0gZGF0ZS5nZXREYXRlKCk7XG5cdFx0XHRpbnN0LmRyYXdNb250aCA9IGluc3Quc2VsZWN0ZWRNb250aCA9IGRhdGUuZ2V0TW9udGgoKTtcblx0XHRcdGluc3QuZHJhd1llYXIgPSBpbnN0LnNlbGVjdGVkWWVhciA9IGRhdGUuZ2V0RnVsbFllYXIoKTtcblx0XHR9XG5cdFx0dGhpcy5fbm90aWZ5Q2hhbmdlKCBpbnN0ICk7XG5cdFx0dGhpcy5fYWRqdXN0RGF0ZSggdGFyZ2V0ICk7XG5cdH0sXG5cblx0LyogQWN0aW9uIGZvciBzZWxlY3RpbmcgYSBuZXcgbW9udGgveWVhci4gKi9cblx0X3NlbGVjdE1vbnRoWWVhcjogZnVuY3Rpb24oIGlkLCBzZWxlY3QsIHBlcmlvZCApIHtcblx0XHR2YXIgdGFyZ2V0ID0gJCggaWQgKSxcblx0XHRcdGluc3QgPSB0aGlzLl9nZXRJbnN0KCB0YXJnZXRbIDAgXSApO1xuXG5cdFx0aW5zdFsgXCJzZWxlY3RlZFwiICsgKCBwZXJpb2QgPT09IFwiTVwiID8gXCJNb250aFwiIDogXCJZZWFyXCIgKSBdID1cblx0XHRpbnN0WyBcImRyYXdcIiArICggcGVyaW9kID09PSBcIk1cIiA/IFwiTW9udGhcIiA6IFwiWWVhclwiICkgXSA9XG5cdFx0XHRwYXJzZUludCggc2VsZWN0Lm9wdGlvbnNbIHNlbGVjdC5zZWxlY3RlZEluZGV4IF0udmFsdWUsIDEwICk7XG5cblx0XHR0aGlzLl9ub3RpZnlDaGFuZ2UoIGluc3QgKTtcblx0XHR0aGlzLl9hZGp1c3REYXRlKCB0YXJnZXQgKTtcblx0fSxcblxuXHQvKiBBY3Rpb24gZm9yIHNlbGVjdGluZyBhIGRheS4gKi9cblx0X3NlbGVjdERheTogZnVuY3Rpb24oIGlkLCBtb250aCwgeWVhciwgdGQgKSB7XG5cdFx0dmFyIGluc3QsXG5cdFx0XHR0YXJnZXQgPSAkKCBpZCApO1xuXG5cdFx0aWYgKCAkKCB0ZCApLmhhc0NsYXNzKCB0aGlzLl91bnNlbGVjdGFibGVDbGFzcyApIHx8IHRoaXMuX2lzRGlzYWJsZWREYXRlcGlja2VyKCB0YXJnZXRbIDAgXSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGluc3QgPSB0aGlzLl9nZXRJbnN0KCB0YXJnZXRbIDAgXSApO1xuXHRcdGluc3Quc2VsZWN0ZWREYXkgPSBpbnN0LmN1cnJlbnREYXkgPSAkKCBcImFcIiwgdGQgKS5odG1sKCk7XG5cdFx0aW5zdC5zZWxlY3RlZE1vbnRoID0gaW5zdC5jdXJyZW50TW9udGggPSBtb250aDtcblx0XHRpbnN0LnNlbGVjdGVkWWVhciA9IGluc3QuY3VycmVudFllYXIgPSB5ZWFyO1xuXHRcdHRoaXMuX3NlbGVjdERhdGUoIGlkLCB0aGlzLl9mb3JtYXREYXRlKCBpbnN0LFxuXHRcdFx0aW5zdC5jdXJyZW50RGF5LCBpbnN0LmN1cnJlbnRNb250aCwgaW5zdC5jdXJyZW50WWVhciApICk7XG5cdH0sXG5cblx0LyogRXJhc2UgdGhlIGlucHV0IGZpZWxkIGFuZCBoaWRlIHRoZSBkYXRlIHBpY2tlci4gKi9cblx0X2NsZWFyRGF0ZTogZnVuY3Rpb24oIGlkICkge1xuXHRcdHZhciB0YXJnZXQgPSAkKCBpZCApO1xuXHRcdHRoaXMuX3NlbGVjdERhdGUoIHRhcmdldCwgXCJcIiApO1xuXHR9LFxuXG5cdC8qIFVwZGF0ZSB0aGUgaW5wdXQgZmllbGQgd2l0aCB0aGUgc2VsZWN0ZWQgZGF0ZS4gKi9cblx0X3NlbGVjdERhdGU6IGZ1bmN0aW9uKCBpZCwgZGF0ZVN0ciApIHtcblx0XHR2YXIgb25TZWxlY3QsXG5cdFx0XHR0YXJnZXQgPSAkKCBpZCApLFxuXHRcdFx0aW5zdCA9IHRoaXMuX2dldEluc3QoIHRhcmdldFsgMCBdICk7XG5cblx0XHRkYXRlU3RyID0gKCBkYXRlU3RyICE9IG51bGwgPyBkYXRlU3RyIDogdGhpcy5fZm9ybWF0RGF0ZSggaW5zdCApICk7XG5cdFx0aWYgKCBpbnN0LmlucHV0ICkge1xuXHRcdFx0aW5zdC5pbnB1dC52YWwoIGRhdGVTdHIgKTtcblx0XHR9XG5cdFx0dGhpcy5fdXBkYXRlQWx0ZXJuYXRlKCBpbnN0ICk7XG5cblx0XHRvblNlbGVjdCA9IHRoaXMuX2dldCggaW5zdCwgXCJvblNlbGVjdFwiICk7XG5cdFx0aWYgKCBvblNlbGVjdCApIHtcblx0XHRcdG9uU2VsZWN0LmFwcGx5KCAoIGluc3QuaW5wdXQgPyBpbnN0LmlucHV0WyAwIF0gOiBudWxsICksIFsgZGF0ZVN0ciwgaW5zdCBdICk7ICAvLyB0cmlnZ2VyIGN1c3RvbSBjYWxsYmFja1xuXHRcdH0gZWxzZSBpZiAoIGluc3QuaW5wdXQgKSB7XG5cdFx0XHRpbnN0LmlucHV0LnRyaWdnZXIoIFwiY2hhbmdlXCIgKTsgLy8gZmlyZSB0aGUgY2hhbmdlIGV2ZW50XG5cdFx0fVxuXG5cdFx0aWYgKCBpbnN0LmlubGluZSApIHtcblx0XHRcdHRoaXMuX3VwZGF0ZURhdGVwaWNrZXIoIGluc3QgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5faGlkZURhdGVwaWNrZXIoKTtcblx0XHRcdHRoaXMuX2xhc3RJbnB1dCA9IGluc3QuaW5wdXRbIDAgXTtcblx0XHRcdGlmICggdHlwZW9mKCBpbnN0LmlucHV0WyAwIF0gKSAhPT0gXCJvYmplY3RcIiApIHtcblx0XHRcdFx0aW5zdC5pbnB1dC50cmlnZ2VyKCBcImZvY3VzXCIgKTsgLy8gcmVzdG9yZSBmb2N1c1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fbGFzdElucHV0ID0gbnVsbDtcblx0XHR9XG5cdH0sXG5cblx0LyogVXBkYXRlIGFueSBhbHRlcm5hdGUgZmllbGQgdG8gc3luY2hyb25pc2Ugd2l0aCB0aGUgbWFpbiBmaWVsZC4gKi9cblx0X3VwZGF0ZUFsdGVybmF0ZTogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0dmFyIGFsdEZvcm1hdCwgZGF0ZSwgZGF0ZVN0cixcblx0XHRcdGFsdEZpZWxkID0gdGhpcy5fZ2V0KCBpbnN0LCBcImFsdEZpZWxkXCIgKTtcblxuXHRcdGlmICggYWx0RmllbGQgKSB7IC8vIHVwZGF0ZSBhbHRlcm5hdGUgZmllbGQgdG9vXG5cdFx0XHRhbHRGb3JtYXQgPSB0aGlzLl9nZXQoIGluc3QsIFwiYWx0Rm9ybWF0XCIgKSB8fCB0aGlzLl9nZXQoIGluc3QsIFwiZGF0ZUZvcm1hdFwiICk7XG5cdFx0XHRkYXRlID0gdGhpcy5fZ2V0RGF0ZSggaW5zdCApO1xuXHRcdFx0ZGF0ZVN0ciA9IHRoaXMuZm9ybWF0RGF0ZSggYWx0Rm9ybWF0LCBkYXRlLCB0aGlzLl9nZXRGb3JtYXRDb25maWcoIGluc3QgKSApO1xuXHRcdFx0JCggYWx0RmllbGQgKS52YWwoIGRhdGVTdHIgKTtcblx0XHR9XG5cdH0sXG5cblx0LyogU2V0IGFzIGJlZm9yZVNob3dEYXkgZnVuY3Rpb24gdG8gcHJldmVudCBzZWxlY3Rpb24gb2Ygd2Vla2VuZHMuXG5cdCAqIEBwYXJhbSAgZGF0ZSAgRGF0ZSAtIHRoZSBkYXRlIHRvIGN1c3RvbWlzZVxuXHQgKiBAcmV0dXJuIFtib29sZWFuLCBzdHJpbmddIC0gaXMgdGhpcyBkYXRlIHNlbGVjdGFibGU/LCB3aGF0IGlzIGl0cyBDU1MgY2xhc3M/XG5cdCAqL1xuXHRub1dlZWtlbmRzOiBmdW5jdGlvbiggZGF0ZSApIHtcblx0XHR2YXIgZGF5ID0gZGF0ZS5nZXREYXkoKTtcblx0XHRyZXR1cm4gWyAoIGRheSA+IDAgJiYgZGF5IDwgNiApLCBcIlwiIF07XG5cdH0sXG5cblx0LyogU2V0IGFzIGNhbGN1bGF0ZVdlZWsgdG8gZGV0ZXJtaW5lIHRoZSB3ZWVrIG9mIHRoZSB5ZWFyIGJhc2VkIG9uIHRoZSBJU08gODYwMSBkZWZpbml0aW9uLlxuXHQgKiBAcGFyYW0gIGRhdGUgIERhdGUgLSB0aGUgZGF0ZSB0byBnZXQgdGhlIHdlZWsgZm9yXG5cdCAqIEByZXR1cm4gIG51bWJlciAtIHRoZSBudW1iZXIgb2YgdGhlIHdlZWsgd2l0aGluIHRoZSB5ZWFyIHRoYXQgY29udGFpbnMgdGhpcyBkYXRlXG5cdCAqL1xuXHRpc284NjAxV2VlazogZnVuY3Rpb24oIGRhdGUgKSB7XG5cdFx0dmFyIHRpbWUsXG5cdFx0XHRjaGVja0RhdGUgPSBuZXcgRGF0ZSggZGF0ZS5nZXRUaW1lKCkgKTtcblxuXHRcdC8vIEZpbmQgVGh1cnNkYXkgb2YgdGhpcyB3ZWVrIHN0YXJ0aW5nIG9uIE1vbmRheVxuXHRcdGNoZWNrRGF0ZS5zZXREYXRlKCBjaGVja0RhdGUuZ2V0RGF0ZSgpICsgNCAtICggY2hlY2tEYXRlLmdldERheSgpIHx8IDcgKSApO1xuXG5cdFx0dGltZSA9IGNoZWNrRGF0ZS5nZXRUaW1lKCk7XG5cdFx0Y2hlY2tEYXRlLnNldE1vbnRoKCAwICk7IC8vIENvbXBhcmUgd2l0aCBKYW4gMVxuXHRcdGNoZWNrRGF0ZS5zZXREYXRlKCAxICk7XG5cdFx0cmV0dXJuIE1hdGguZmxvb3IoIE1hdGgucm91bmQoICggdGltZSAtIGNoZWNrRGF0ZSApIC8gODY0MDAwMDAgKSAvIDcgKSArIDE7XG5cdH0sXG5cblx0LyogUGFyc2UgYSBzdHJpbmcgdmFsdWUgaW50byBhIGRhdGUgb2JqZWN0LlxuXHQgKiBTZWUgZm9ybWF0RGF0ZSBiZWxvdyBmb3IgdGhlIHBvc3NpYmxlIGZvcm1hdHMuXG5cdCAqXG5cdCAqIEBwYXJhbSAgZm9ybWF0IHN0cmluZyAtIHRoZSBleHBlY3RlZCBmb3JtYXQgb2YgdGhlIGRhdGVcblx0ICogQHBhcmFtICB2YWx1ZSBzdHJpbmcgLSB0aGUgZGF0ZSBpbiB0aGUgYWJvdmUgZm9ybWF0XG5cdCAqIEBwYXJhbSAgc2V0dGluZ3MgT2JqZWN0IC0gYXR0cmlidXRlcyBpbmNsdWRlOlxuXHQgKlx0XHRcdFx0XHRzaG9ydFllYXJDdXRvZmYgIG51bWJlciAtIHRoZSBjdXRvZmYgeWVhciBmb3IgZGV0ZXJtaW5pbmcgdGhlIGNlbnR1cnkgKG9wdGlvbmFsKVxuXHQgKlx0XHRcdFx0XHRkYXlOYW1lc1Nob3J0XHRzdHJpbmdbN10gLSBhYmJyZXZpYXRlZCBuYW1lcyBvZiB0aGUgZGF5cyBmcm9tIFN1bmRheSAob3B0aW9uYWwpXG5cdCAqXHRcdFx0XHRcdGRheU5hbWVzXHRcdHN0cmluZ1s3XSAtIG5hbWVzIG9mIHRoZSBkYXlzIGZyb20gU3VuZGF5IChvcHRpb25hbClcblx0ICpcdFx0XHRcdFx0bW9udGhOYW1lc1Nob3J0IHN0cmluZ1sxMl0gLSBhYmJyZXZpYXRlZCBuYW1lcyBvZiB0aGUgbW9udGhzIChvcHRpb25hbClcblx0ICpcdFx0XHRcdFx0bW9udGhOYW1lc1x0XHRzdHJpbmdbMTJdIC0gbmFtZXMgb2YgdGhlIG1vbnRocyAob3B0aW9uYWwpXG5cdCAqIEByZXR1cm4gIERhdGUgLSB0aGUgZXh0cmFjdGVkIGRhdGUgdmFsdWUgb3IgbnVsbCBpZiB2YWx1ZSBpcyBibGFua1xuXHQgKi9cblx0cGFyc2VEYXRlOiBmdW5jdGlvbiggZm9ybWF0LCB2YWx1ZSwgc2V0dGluZ3MgKSB7XG5cdFx0aWYgKCBmb3JtYXQgPT0gbnVsbCB8fCB2YWx1ZSA9PSBudWxsICkge1xuXHRcdFx0dGhyb3cgXCJJbnZhbGlkIGFyZ3VtZW50c1wiO1xuXHRcdH1cblxuXHRcdHZhbHVlID0gKCB0eXBlb2YgdmFsdWUgPT09IFwib2JqZWN0XCIgPyB2YWx1ZS50b1N0cmluZygpIDogdmFsdWUgKyBcIlwiICk7XG5cdFx0aWYgKCB2YWx1ZSA9PT0gXCJcIiApIHtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblxuXHRcdHZhciBpRm9ybWF0LCBkaW0sIGV4dHJhLFxuXHRcdFx0aVZhbHVlID0gMCxcblx0XHRcdHNob3J0WWVhckN1dG9mZlRlbXAgPSAoIHNldHRpbmdzID8gc2V0dGluZ3Muc2hvcnRZZWFyQ3V0b2ZmIDogbnVsbCApIHx8IHRoaXMuX2RlZmF1bHRzLnNob3J0WWVhckN1dG9mZixcblx0XHRcdHNob3J0WWVhckN1dG9mZiA9ICggdHlwZW9mIHNob3J0WWVhckN1dG9mZlRlbXAgIT09IFwic3RyaW5nXCIgPyBzaG9ydFllYXJDdXRvZmZUZW1wIDpcblx0XHRcdFx0bmV3IERhdGUoKS5nZXRGdWxsWWVhcigpICUgMTAwICsgcGFyc2VJbnQoIHNob3J0WWVhckN1dG9mZlRlbXAsIDEwICkgKSxcblx0XHRcdGRheU5hbWVzU2hvcnQgPSAoIHNldHRpbmdzID8gc2V0dGluZ3MuZGF5TmFtZXNTaG9ydCA6IG51bGwgKSB8fCB0aGlzLl9kZWZhdWx0cy5kYXlOYW1lc1Nob3J0LFxuXHRcdFx0ZGF5TmFtZXMgPSAoIHNldHRpbmdzID8gc2V0dGluZ3MuZGF5TmFtZXMgOiBudWxsICkgfHwgdGhpcy5fZGVmYXVsdHMuZGF5TmFtZXMsXG5cdFx0XHRtb250aE5hbWVzU2hvcnQgPSAoIHNldHRpbmdzID8gc2V0dGluZ3MubW9udGhOYW1lc1Nob3J0IDogbnVsbCApIHx8IHRoaXMuX2RlZmF1bHRzLm1vbnRoTmFtZXNTaG9ydCxcblx0XHRcdG1vbnRoTmFtZXMgPSAoIHNldHRpbmdzID8gc2V0dGluZ3MubW9udGhOYW1lcyA6IG51bGwgKSB8fCB0aGlzLl9kZWZhdWx0cy5tb250aE5hbWVzLFxuXHRcdFx0eWVhciA9IC0xLFxuXHRcdFx0bW9udGggPSAtMSxcblx0XHRcdGRheSA9IC0xLFxuXHRcdFx0ZG95ID0gLTEsXG5cdFx0XHRsaXRlcmFsID0gZmFsc2UsXG5cdFx0XHRkYXRlLFxuXG5cdFx0XHQvLyBDaGVjayB3aGV0aGVyIGEgZm9ybWF0IGNoYXJhY3RlciBpcyBkb3VibGVkXG5cdFx0XHRsb29rQWhlYWQgPSBmdW5jdGlvbiggbWF0Y2ggKSB7XG5cdFx0XHRcdHZhciBtYXRjaGVzID0gKCBpRm9ybWF0ICsgMSA8IGZvcm1hdC5sZW5ndGggJiYgZm9ybWF0LmNoYXJBdCggaUZvcm1hdCArIDEgKSA9PT0gbWF0Y2ggKTtcblx0XHRcdFx0aWYgKCBtYXRjaGVzICkge1xuXHRcdFx0XHRcdGlGb3JtYXQrKztcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gbWF0Y2hlcztcblx0XHRcdH0sXG5cblx0XHRcdC8vIEV4dHJhY3QgYSBudW1iZXIgZnJvbSB0aGUgc3RyaW5nIHZhbHVlXG5cdFx0XHRnZXROdW1iZXIgPSBmdW5jdGlvbiggbWF0Y2ggKSB7XG5cdFx0XHRcdHZhciBpc0RvdWJsZWQgPSBsb29rQWhlYWQoIG1hdGNoICksXG5cdFx0XHRcdFx0c2l6ZSA9ICggbWF0Y2ggPT09IFwiQFwiID8gMTQgOiAoIG1hdGNoID09PSBcIiFcIiA/IDIwIDpcblx0XHRcdFx0XHQoIG1hdGNoID09PSBcInlcIiAmJiBpc0RvdWJsZWQgPyA0IDogKCBtYXRjaCA9PT0gXCJvXCIgPyAzIDogMiApICkgKSApLFxuXHRcdFx0XHRcdG1pblNpemUgPSAoIG1hdGNoID09PSBcInlcIiA/IHNpemUgOiAxICksXG5cdFx0XHRcdFx0ZGlnaXRzID0gbmV3IFJlZ0V4cCggXCJeXFxcXGR7XCIgKyBtaW5TaXplICsgXCIsXCIgKyBzaXplICsgXCJ9XCIgKSxcblx0XHRcdFx0XHRudW0gPSB2YWx1ZS5zdWJzdHJpbmcoIGlWYWx1ZSApLm1hdGNoKCBkaWdpdHMgKTtcblx0XHRcdFx0aWYgKCAhbnVtICkge1xuXHRcdFx0XHRcdHRocm93IFwiTWlzc2luZyBudW1iZXIgYXQgcG9zaXRpb24gXCIgKyBpVmFsdWU7XG5cdFx0XHRcdH1cblx0XHRcdFx0aVZhbHVlICs9IG51bVsgMCBdLmxlbmd0aDtcblx0XHRcdFx0cmV0dXJuIHBhcnNlSW50KCBudW1bIDAgXSwgMTAgKTtcblx0XHRcdH0sXG5cblx0XHRcdC8vIEV4dHJhY3QgYSBuYW1lIGZyb20gdGhlIHN0cmluZyB2YWx1ZSBhbmQgY29udmVydCB0byBhbiBpbmRleFxuXHRcdFx0Z2V0TmFtZSA9IGZ1bmN0aW9uKCBtYXRjaCwgc2hvcnROYW1lcywgbG9uZ05hbWVzICkge1xuXHRcdFx0XHR2YXIgaW5kZXggPSAtMSxcblx0XHRcdFx0XHRuYW1lcyA9ICQubWFwKCBsb29rQWhlYWQoIG1hdGNoICkgPyBsb25nTmFtZXMgOiBzaG9ydE5hbWVzLCBmdW5jdGlvbiggdiwgayApIHtcblx0XHRcdFx0XHRcdHJldHVybiBbIFsgaywgdiBdIF07XG5cdFx0XHRcdFx0fSApLnNvcnQoIGZ1bmN0aW9uKCBhLCBiICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIC0oIGFbIDEgXS5sZW5ndGggLSBiWyAxIF0ubGVuZ3RoICk7XG5cdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdCQuZWFjaCggbmFtZXMsIGZ1bmN0aW9uKCBpLCBwYWlyICkge1xuXHRcdFx0XHRcdHZhciBuYW1lID0gcGFpclsgMSBdO1xuXHRcdFx0XHRcdGlmICggdmFsdWUuc3Vic3RyKCBpVmFsdWUsIG5hbWUubGVuZ3RoICkudG9Mb3dlckNhc2UoKSA9PT0gbmFtZS50b0xvd2VyQ2FzZSgpICkge1xuXHRcdFx0XHRcdFx0aW5kZXggPSBwYWlyWyAwIF07XG5cdFx0XHRcdFx0XHRpVmFsdWUgKz0gbmFtZS5sZW5ndGg7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdGlmICggaW5kZXggIT09IC0xICkge1xuXHRcdFx0XHRcdHJldHVybiBpbmRleCArIDE7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhyb3cgXCJVbmtub3duIG5hbWUgYXQgcG9zaXRpb24gXCIgKyBpVmFsdWU7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cblx0XHRcdC8vIENvbmZpcm0gdGhhdCBhIGxpdGVyYWwgY2hhcmFjdGVyIG1hdGNoZXMgdGhlIHN0cmluZyB2YWx1ZVxuXHRcdFx0Y2hlY2tMaXRlcmFsID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggdmFsdWUuY2hhckF0KCBpVmFsdWUgKSAhPT0gZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApICkge1xuXHRcdFx0XHRcdHRocm93IFwiVW5leHBlY3RlZCBsaXRlcmFsIGF0IHBvc2l0aW9uIFwiICsgaVZhbHVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlWYWx1ZSsrO1xuXHRcdFx0fTtcblxuXHRcdGZvciAoIGlGb3JtYXQgPSAwOyBpRm9ybWF0IDwgZm9ybWF0Lmxlbmd0aDsgaUZvcm1hdCsrICkge1xuXHRcdFx0aWYgKCBsaXRlcmFsICkge1xuXHRcdFx0XHRpZiAoIGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKSA9PT0gXCInXCIgJiYgIWxvb2tBaGVhZCggXCInXCIgKSApIHtcblx0XHRcdFx0XHRsaXRlcmFsID0gZmFsc2U7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Y2hlY2tMaXRlcmFsKCk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHN3aXRjaCAoIGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKSApIHtcblx0XHRcdFx0XHRjYXNlIFwiZFwiOlxuXHRcdFx0XHRcdFx0ZGF5ID0gZ2V0TnVtYmVyKCBcImRcIiApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0Y2FzZSBcIkRcIjpcblx0XHRcdFx0XHRcdGdldE5hbWUoIFwiRFwiLCBkYXlOYW1lc1Nob3J0LCBkYXlOYW1lcyApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0Y2FzZSBcIm9cIjpcblx0XHRcdFx0XHRcdGRveSA9IGdldE51bWJlciggXCJvXCIgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgXCJtXCI6XG5cdFx0XHRcdFx0XHRtb250aCA9IGdldE51bWJlciggXCJtXCIgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgXCJNXCI6XG5cdFx0XHRcdFx0XHRtb250aCA9IGdldE5hbWUoIFwiTVwiLCBtb250aE5hbWVzU2hvcnQsIG1vbnRoTmFtZXMgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgXCJ5XCI6XG5cdFx0XHRcdFx0XHR5ZWFyID0gZ2V0TnVtYmVyKCBcInlcIiApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0Y2FzZSBcIkBcIjpcblx0XHRcdFx0XHRcdGRhdGUgPSBuZXcgRGF0ZSggZ2V0TnVtYmVyKCBcIkBcIiApICk7XG5cdFx0XHRcdFx0XHR5ZWFyID0gZGF0ZS5nZXRGdWxsWWVhcigpO1xuXHRcdFx0XHRcdFx0bW9udGggPSBkYXRlLmdldE1vbnRoKCkgKyAxO1xuXHRcdFx0XHRcdFx0ZGF5ID0gZGF0ZS5nZXREYXRlKCk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlIFwiIVwiOlxuXHRcdFx0XHRcdFx0ZGF0ZSA9IG5ldyBEYXRlKCAoIGdldE51bWJlciggXCIhXCIgKSAtIHRoaXMuX3RpY2tzVG8xOTcwICkgLyAxMDAwMCApO1xuXHRcdFx0XHRcdFx0eWVhciA9IGRhdGUuZ2V0RnVsbFllYXIoKTtcblx0XHRcdFx0XHRcdG1vbnRoID0gZGF0ZS5nZXRNb250aCgpICsgMTtcblx0XHRcdFx0XHRcdGRheSA9IGRhdGUuZ2V0RGF0ZSgpO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0Y2FzZSBcIidcIjpcblx0XHRcdFx0XHRcdGlmICggbG9va0FoZWFkKCBcIidcIiApICkge1xuXHRcdFx0XHRcdFx0XHRjaGVja0xpdGVyYWwoKTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdGxpdGVyYWwgPSB0cnVlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRcdGNoZWNrTGl0ZXJhbCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBpVmFsdWUgPCB2YWx1ZS5sZW5ndGggKSB7XG5cdFx0XHRleHRyYSA9IHZhbHVlLnN1YnN0ciggaVZhbHVlICk7XG5cdFx0XHRpZiAoICEvXlxccysvLnRlc3QoIGV4dHJhICkgKSB7XG5cdFx0XHRcdHRocm93IFwiRXh0cmEvdW5wYXJzZWQgY2hhcmFjdGVycyBmb3VuZCBpbiBkYXRlOiBcIiArIGV4dHJhO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggeWVhciA9PT0gLTEgKSB7XG5cdFx0XHR5ZWFyID0gbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpO1xuXHRcdH0gZWxzZSBpZiAoIHllYXIgPCAxMDAgKSB7XG5cdFx0XHR5ZWFyICs9IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSAtIG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSAlIDEwMCArXG5cdFx0XHRcdCggeWVhciA8PSBzaG9ydFllYXJDdXRvZmYgPyAwIDogLTEwMCApO1xuXHRcdH1cblxuXHRcdGlmICggZG95ID4gLTEgKSB7XG5cdFx0XHRtb250aCA9IDE7XG5cdFx0XHRkYXkgPSBkb3k7XG5cdFx0XHRkbyB7XG5cdFx0XHRcdGRpbSA9IHRoaXMuX2dldERheXNJbk1vbnRoKCB5ZWFyLCBtb250aCAtIDEgKTtcblx0XHRcdFx0aWYgKCBkYXkgPD0gZGltICkge1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHRcdG1vbnRoKys7XG5cdFx0XHRcdGRheSAtPSBkaW07XG5cdFx0XHR9IHdoaWxlICggdHJ1ZSApO1xuXHRcdH1cblxuXHRcdGRhdGUgPSB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIHllYXIsIG1vbnRoIC0gMSwgZGF5ICkgKTtcblx0XHRpZiAoIGRhdGUuZ2V0RnVsbFllYXIoKSAhPT0geWVhciB8fCBkYXRlLmdldE1vbnRoKCkgKyAxICE9PSBtb250aCB8fCBkYXRlLmdldERhdGUoKSAhPT0gZGF5ICkge1xuXHRcdFx0dGhyb3cgXCJJbnZhbGlkIGRhdGVcIjsgLy8gRS5nLiAzMS8wMi8wMFxuXHRcdH1cblx0XHRyZXR1cm4gZGF0ZTtcblx0fSxcblxuXHQvKiBTdGFuZGFyZCBkYXRlIGZvcm1hdHMuICovXG5cdEFUT006IFwieXktbW0tZGRcIiwgLy8gUkZDIDMzMzkgKElTTyA4NjAxKVxuXHRDT09LSUU6IFwiRCwgZGQgTSB5eVwiLFxuXHRJU09fODYwMTogXCJ5eS1tbS1kZFwiLFxuXHRSRkNfODIyOiBcIkQsIGQgTSB5XCIsXG5cdFJGQ184NTA6IFwiREQsIGRkLU0teVwiLFxuXHRSRkNfMTAzNjogXCJELCBkIE0geVwiLFxuXHRSRkNfMTEyMzogXCJELCBkIE0geXlcIixcblx0UkZDXzI4MjI6IFwiRCwgZCBNIHl5XCIsXG5cdFJTUzogXCJELCBkIE0geVwiLCAvLyBSRkMgODIyXG5cdFRJQ0tTOiBcIiFcIixcblx0VElNRVNUQU1QOiBcIkBcIixcblx0VzNDOiBcInl5LW1tLWRkXCIsIC8vIElTTyA4NjAxXG5cblx0X3RpY2tzVG8xOTcwOiAoICggKCAxOTcwIC0gMSApICogMzY1ICsgTWF0aC5mbG9vciggMTk3MCAvIDQgKSAtIE1hdGguZmxvb3IoIDE5NzAgLyAxMDAgKSArXG5cdFx0TWF0aC5mbG9vciggMTk3MCAvIDQwMCApICkgKiAyNCAqIDYwICogNjAgKiAxMDAwMDAwMCApLFxuXG5cdC8qIEZvcm1hdCBhIGRhdGUgb2JqZWN0IGludG8gYSBzdHJpbmcgdmFsdWUuXG5cdCAqIFRoZSBmb3JtYXQgY2FuIGJlIGNvbWJpbmF0aW9ucyBvZiB0aGUgZm9sbG93aW5nOlxuXHQgKiBkICAtIGRheSBvZiBtb250aCAobm8gbGVhZGluZyB6ZXJvKVxuXHQgKiBkZCAtIGRheSBvZiBtb250aCAodHdvIGRpZ2l0KVxuXHQgKiBvICAtIGRheSBvZiB5ZWFyIChubyBsZWFkaW5nIHplcm9zKVxuXHQgKiBvbyAtIGRheSBvZiB5ZWFyICh0aHJlZSBkaWdpdClcblx0ICogRCAgLSBkYXkgbmFtZSBzaG9ydFxuXHQgKiBERCAtIGRheSBuYW1lIGxvbmdcblx0ICogbSAgLSBtb250aCBvZiB5ZWFyIChubyBsZWFkaW5nIHplcm8pXG5cdCAqIG1tIC0gbW9udGggb2YgeWVhciAodHdvIGRpZ2l0KVxuXHQgKiBNICAtIG1vbnRoIG5hbWUgc2hvcnRcblx0ICogTU0gLSBtb250aCBuYW1lIGxvbmdcblx0ICogeSAgLSB5ZWFyICh0d28gZGlnaXQpXG5cdCAqIHl5IC0geWVhciAoZm91ciBkaWdpdClcblx0ICogQCAtIFVuaXggdGltZXN0YW1wIChtcyBzaW5jZSAwMS8wMS8xOTcwKVxuXHQgKiAhIC0gV2luZG93cyB0aWNrcyAoMTAwbnMgc2luY2UgMDEvMDEvMDAwMSlcblx0ICogXCIuLi5cIiAtIGxpdGVyYWwgdGV4dFxuXHQgKiAnJyAtIHNpbmdsZSBxdW90ZVxuXHQgKlxuXHQgKiBAcGFyYW0gIGZvcm1hdCBzdHJpbmcgLSB0aGUgZGVzaXJlZCBmb3JtYXQgb2YgdGhlIGRhdGVcblx0ICogQHBhcmFtICBkYXRlIERhdGUgLSB0aGUgZGF0ZSB2YWx1ZSB0byBmb3JtYXRcblx0ICogQHBhcmFtICBzZXR0aW5ncyBPYmplY3QgLSBhdHRyaWJ1dGVzIGluY2x1ZGU6XG5cdCAqXHRcdFx0XHRcdGRheU5hbWVzU2hvcnRcdHN0cmluZ1s3XSAtIGFiYnJldmlhdGVkIG5hbWVzIG9mIHRoZSBkYXlzIGZyb20gU3VuZGF5IChvcHRpb25hbClcblx0ICpcdFx0XHRcdFx0ZGF5TmFtZXNcdFx0c3RyaW5nWzddIC0gbmFtZXMgb2YgdGhlIGRheXMgZnJvbSBTdW5kYXkgKG9wdGlvbmFsKVxuXHQgKlx0XHRcdFx0XHRtb250aE5hbWVzU2hvcnQgc3RyaW5nWzEyXSAtIGFiYnJldmlhdGVkIG5hbWVzIG9mIHRoZSBtb250aHMgKG9wdGlvbmFsKVxuXHQgKlx0XHRcdFx0XHRtb250aE5hbWVzXHRcdHN0cmluZ1sxMl0gLSBuYW1lcyBvZiB0aGUgbW9udGhzIChvcHRpb25hbClcblx0ICogQHJldHVybiAgc3RyaW5nIC0gdGhlIGRhdGUgaW4gdGhlIGFib3ZlIGZvcm1hdFxuXHQgKi9cblx0Zm9ybWF0RGF0ZTogZnVuY3Rpb24oIGZvcm1hdCwgZGF0ZSwgc2V0dGluZ3MgKSB7XG5cdFx0aWYgKCAhZGF0ZSApIHtcblx0XHRcdHJldHVybiBcIlwiO1xuXHRcdH1cblxuXHRcdHZhciBpRm9ybWF0LFxuXHRcdFx0ZGF5TmFtZXNTaG9ydCA9ICggc2V0dGluZ3MgPyBzZXR0aW5ncy5kYXlOYW1lc1Nob3J0IDogbnVsbCApIHx8IHRoaXMuX2RlZmF1bHRzLmRheU5hbWVzU2hvcnQsXG5cdFx0XHRkYXlOYW1lcyA9ICggc2V0dGluZ3MgPyBzZXR0aW5ncy5kYXlOYW1lcyA6IG51bGwgKSB8fCB0aGlzLl9kZWZhdWx0cy5kYXlOYW1lcyxcblx0XHRcdG1vbnRoTmFtZXNTaG9ydCA9ICggc2V0dGluZ3MgPyBzZXR0aW5ncy5tb250aE5hbWVzU2hvcnQgOiBudWxsICkgfHwgdGhpcy5fZGVmYXVsdHMubW9udGhOYW1lc1Nob3J0LFxuXHRcdFx0bW9udGhOYW1lcyA9ICggc2V0dGluZ3MgPyBzZXR0aW5ncy5tb250aE5hbWVzIDogbnVsbCApIHx8IHRoaXMuX2RlZmF1bHRzLm1vbnRoTmFtZXMsXG5cblx0XHRcdC8vIENoZWNrIHdoZXRoZXIgYSBmb3JtYXQgY2hhcmFjdGVyIGlzIGRvdWJsZWRcblx0XHRcdGxvb2tBaGVhZCA9IGZ1bmN0aW9uKCBtYXRjaCApIHtcblx0XHRcdFx0dmFyIG1hdGNoZXMgPSAoIGlGb3JtYXQgKyAxIDwgZm9ybWF0Lmxlbmd0aCAmJiBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICsgMSApID09PSBtYXRjaCApO1xuXHRcdFx0XHRpZiAoIG1hdGNoZXMgKSB7XG5cdFx0XHRcdFx0aUZvcm1hdCsrO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBtYXRjaGVzO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gRm9ybWF0IGEgbnVtYmVyLCB3aXRoIGxlYWRpbmcgemVybyBpZiBuZWNlc3Nhcnlcblx0XHRcdGZvcm1hdE51bWJlciA9IGZ1bmN0aW9uKCBtYXRjaCwgdmFsdWUsIGxlbiApIHtcblx0XHRcdFx0dmFyIG51bSA9IFwiXCIgKyB2YWx1ZTtcblx0XHRcdFx0aWYgKCBsb29rQWhlYWQoIG1hdGNoICkgKSB7XG5cdFx0XHRcdFx0d2hpbGUgKCBudW0ubGVuZ3RoIDwgbGVuICkge1xuXHRcdFx0XHRcdFx0bnVtID0gXCIwXCIgKyBudW07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBudW07XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBGb3JtYXQgYSBuYW1lLCBzaG9ydCBvciBsb25nIGFzIHJlcXVlc3RlZFxuXHRcdFx0Zm9ybWF0TmFtZSA9IGZ1bmN0aW9uKCBtYXRjaCwgdmFsdWUsIHNob3J0TmFtZXMsIGxvbmdOYW1lcyApIHtcblx0XHRcdFx0cmV0dXJuICggbG9va0FoZWFkKCBtYXRjaCApID8gbG9uZ05hbWVzWyB2YWx1ZSBdIDogc2hvcnROYW1lc1sgdmFsdWUgXSApO1xuXHRcdFx0fSxcblx0XHRcdG91dHB1dCA9IFwiXCIsXG5cdFx0XHRsaXRlcmFsID0gZmFsc2U7XG5cblx0XHRpZiAoIGRhdGUgKSB7XG5cdFx0XHRmb3IgKCBpRm9ybWF0ID0gMDsgaUZvcm1hdCA8IGZvcm1hdC5sZW5ndGg7IGlGb3JtYXQrKyApIHtcblx0XHRcdFx0aWYgKCBsaXRlcmFsICkge1xuXHRcdFx0XHRcdGlmICggZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApID09PSBcIidcIiAmJiAhbG9va0FoZWFkKCBcIidcIiApICkge1xuXHRcdFx0XHRcdFx0bGl0ZXJhbCA9IGZhbHNlO1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRvdXRwdXQgKz0gZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRzd2l0Y2ggKCBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICkgKSB7XG5cdFx0XHRcdFx0XHRjYXNlIFwiZFwiOlxuXHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gZm9ybWF0TnVtYmVyKCBcImRcIiwgZGF0ZS5nZXREYXRlKCksIDIgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwiRFwiOlxuXHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gZm9ybWF0TmFtZSggXCJEXCIsIGRhdGUuZ2V0RGF5KCksIGRheU5hbWVzU2hvcnQsIGRheU5hbWVzICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcIm9cIjpcblx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9IGZvcm1hdE51bWJlciggXCJvXCIsXG5cdFx0XHRcdFx0XHRcdFx0TWF0aC5yb3VuZCggKCBuZXcgRGF0ZSggZGF0ZS5nZXRGdWxsWWVhcigpLCBkYXRlLmdldE1vbnRoKCksIGRhdGUuZ2V0RGF0ZSgpICkuZ2V0VGltZSgpIC0gbmV3IERhdGUoIGRhdGUuZ2V0RnVsbFllYXIoKSwgMCwgMCApLmdldFRpbWUoKSApIC8gODY0MDAwMDAgKSwgMyApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCJtXCI6XG5cdFx0XHRcdFx0XHRcdG91dHB1dCArPSBmb3JtYXROdW1iZXIoIFwibVwiLCBkYXRlLmdldE1vbnRoKCkgKyAxLCAyICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcIk1cIjpcblx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9IGZvcm1hdE5hbWUoIFwiTVwiLCBkYXRlLmdldE1vbnRoKCksIG1vbnRoTmFtZXNTaG9ydCwgbW9udGhOYW1lcyApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCJ5XCI6XG5cdFx0XHRcdFx0XHRcdG91dHB1dCArPSAoIGxvb2tBaGVhZCggXCJ5XCIgKSA/IGRhdGUuZ2V0RnVsbFllYXIoKSA6XG5cdFx0XHRcdFx0XHRcdFx0KCBkYXRlLmdldEZ1bGxZZWFyKCkgJSAxMDAgPCAxMCA/IFwiMFwiIDogXCJcIiApICsgZGF0ZS5nZXRGdWxsWWVhcigpICUgMTAwICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcIkBcIjpcblx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9IGRhdGUuZ2V0VGltZSgpO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCIhXCI6XG5cdFx0XHRcdFx0XHRcdG91dHB1dCArPSBkYXRlLmdldFRpbWUoKSAqIDEwMDAwICsgdGhpcy5fdGlja3NUbzE5NzA7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcIidcIjpcblx0XHRcdFx0XHRcdFx0aWYgKCBsb29rQWhlYWQoIFwiJ1wiICkgKSB7XG5cdFx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9IFwiJ1wiO1xuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdGxpdGVyYWwgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9IGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIG91dHB1dDtcblx0fSxcblxuXHQvKiBFeHRyYWN0IGFsbCBwb3NzaWJsZSBjaGFyYWN0ZXJzIGZyb20gdGhlIGRhdGUgZm9ybWF0LiAqL1xuXHRfcG9zc2libGVDaGFyczogZnVuY3Rpb24oIGZvcm1hdCApIHtcblx0XHR2YXIgaUZvcm1hdCxcblx0XHRcdGNoYXJzID0gXCJcIixcblx0XHRcdGxpdGVyYWwgPSBmYWxzZSxcblxuXHRcdFx0Ly8gQ2hlY2sgd2hldGhlciBhIGZvcm1hdCBjaGFyYWN0ZXIgaXMgZG91YmxlZFxuXHRcdFx0bG9va0FoZWFkID0gZnVuY3Rpb24oIG1hdGNoICkge1xuXHRcdFx0XHR2YXIgbWF0Y2hlcyA9ICggaUZvcm1hdCArIDEgPCBmb3JtYXQubGVuZ3RoICYmIGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKyAxICkgPT09IG1hdGNoICk7XG5cdFx0XHRcdGlmICggbWF0Y2hlcyApIHtcblx0XHRcdFx0XHRpRm9ybWF0Kys7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIG1hdGNoZXM7XG5cdFx0XHR9O1xuXG5cdFx0Zm9yICggaUZvcm1hdCA9IDA7IGlGb3JtYXQgPCBmb3JtYXQubGVuZ3RoOyBpRm9ybWF0KysgKSB7XG5cdFx0XHRpZiAoIGxpdGVyYWwgKSB7XG5cdFx0XHRcdGlmICggZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApID09PSBcIidcIiAmJiAhbG9va0FoZWFkKCBcIidcIiApICkge1xuXHRcdFx0XHRcdGxpdGVyYWwgPSBmYWxzZTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRjaGFycyArPSBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHN3aXRjaCAoIGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKSApIHtcblx0XHRcdFx0XHRjYXNlIFwiZFwiOiBjYXNlIFwibVwiOiBjYXNlIFwieVwiOiBjYXNlIFwiQFwiOlxuXHRcdFx0XHRcdFx0Y2hhcnMgKz0gXCIwMTIzNDU2Nzg5XCI7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlIFwiRFwiOiBjYXNlIFwiTVwiOlxuXHRcdFx0XHRcdFx0cmV0dXJuIG51bGw7IC8vIEFjY2VwdCBhbnl0aGluZ1xuXHRcdFx0XHRcdGNhc2UgXCInXCI6XG5cdFx0XHRcdFx0XHRpZiAoIGxvb2tBaGVhZCggXCInXCIgKSApIHtcblx0XHRcdFx0XHRcdFx0Y2hhcnMgKz0gXCInXCI7XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRsaXRlcmFsID0gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0XHRjaGFycyArPSBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIGNoYXJzO1xuXHR9LFxuXG5cdC8qIEdldCBhIHNldHRpbmcgdmFsdWUsIGRlZmF1bHRpbmcgaWYgbmVjZXNzYXJ5LiAqL1xuXHRfZ2V0OiBmdW5jdGlvbiggaW5zdCwgbmFtZSApIHtcblx0XHRyZXR1cm4gaW5zdC5zZXR0aW5nc1sgbmFtZSBdICE9PSB1bmRlZmluZWQgP1xuXHRcdFx0aW5zdC5zZXR0aW5nc1sgbmFtZSBdIDogdGhpcy5fZGVmYXVsdHNbIG5hbWUgXTtcblx0fSxcblxuXHQvKiBQYXJzZSBleGlzdGluZyBkYXRlIGFuZCBpbml0aWFsaXNlIGRhdGUgcGlja2VyLiAqL1xuXHRfc2V0RGF0ZUZyb21GaWVsZDogZnVuY3Rpb24oIGluc3QsIG5vRGVmYXVsdCApIHtcblx0XHRpZiAoIGluc3QuaW5wdXQudmFsKCkgPT09IGluc3QubGFzdFZhbCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgZGF0ZUZvcm1hdCA9IHRoaXMuX2dldCggaW5zdCwgXCJkYXRlRm9ybWF0XCIgKSxcblx0XHRcdGRhdGVzID0gaW5zdC5sYXN0VmFsID0gaW5zdC5pbnB1dCA/IGluc3QuaW5wdXQudmFsKCkgOiBudWxsLFxuXHRcdFx0ZGVmYXVsdERhdGUgPSB0aGlzLl9nZXREZWZhdWx0RGF0ZSggaW5zdCApLFxuXHRcdFx0ZGF0ZSA9IGRlZmF1bHREYXRlLFxuXHRcdFx0c2V0dGluZ3MgPSB0aGlzLl9nZXRGb3JtYXRDb25maWcoIGluc3QgKTtcblxuXHRcdHRyeSB7XG5cdFx0XHRkYXRlID0gdGhpcy5wYXJzZURhdGUoIGRhdGVGb3JtYXQsIGRhdGVzLCBzZXR0aW5ncyApIHx8IGRlZmF1bHREYXRlO1xuXHRcdH0gY2F0Y2ggKCBldmVudCApIHtcblx0XHRcdGRhdGVzID0gKCBub0RlZmF1bHQgPyBcIlwiIDogZGF0ZXMgKTtcblx0XHR9XG5cdFx0aW5zdC5zZWxlY3RlZERheSA9IGRhdGUuZ2V0RGF0ZSgpO1xuXHRcdGluc3QuZHJhd01vbnRoID0gaW5zdC5zZWxlY3RlZE1vbnRoID0gZGF0ZS5nZXRNb250aCgpO1xuXHRcdGluc3QuZHJhd1llYXIgPSBpbnN0LnNlbGVjdGVkWWVhciA9IGRhdGUuZ2V0RnVsbFllYXIoKTtcblx0XHRpbnN0LmN1cnJlbnREYXkgPSAoIGRhdGVzID8gZGF0ZS5nZXREYXRlKCkgOiAwICk7XG5cdFx0aW5zdC5jdXJyZW50TW9udGggPSAoIGRhdGVzID8gZGF0ZS5nZXRNb250aCgpIDogMCApO1xuXHRcdGluc3QuY3VycmVudFllYXIgPSAoIGRhdGVzID8gZGF0ZS5nZXRGdWxsWWVhcigpIDogMCApO1xuXHRcdHRoaXMuX2FkanVzdEluc3REYXRlKCBpbnN0ICk7XG5cdH0sXG5cblx0LyogUmV0cmlldmUgdGhlIGRlZmF1bHQgZGF0ZSBzaG93biBvbiBvcGVuaW5nLiAqL1xuXHRfZ2V0RGVmYXVsdERhdGU6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHJldHVybiB0aGlzLl9yZXN0cmljdE1pbk1heCggaW5zdCxcblx0XHRcdHRoaXMuX2RldGVybWluZURhdGUoIGluc3QsIHRoaXMuX2dldCggaW5zdCwgXCJkZWZhdWx0RGF0ZVwiICksIG5ldyBEYXRlKCkgKSApO1xuXHR9LFxuXG5cdC8qIEEgZGF0ZSBtYXkgYmUgc3BlY2lmaWVkIGFzIGFuIGV4YWN0IHZhbHVlIG9yIGEgcmVsYXRpdmUgb25lLiAqL1xuXHRfZGV0ZXJtaW5lRGF0ZTogZnVuY3Rpb24oIGluc3QsIGRhdGUsIGRlZmF1bHREYXRlICkge1xuXHRcdHZhciBvZmZzZXROdW1lcmljID0gZnVuY3Rpb24oIG9mZnNldCApIHtcblx0XHRcdFx0dmFyIGRhdGUgPSBuZXcgRGF0ZSgpO1xuXHRcdFx0XHRkYXRlLnNldERhdGUoIGRhdGUuZ2V0RGF0ZSgpICsgb2Zmc2V0ICk7XG5cdFx0XHRcdHJldHVybiBkYXRlO1xuXHRcdFx0fSxcblx0XHRcdG9mZnNldFN0cmluZyA9IGZ1bmN0aW9uKCBvZmZzZXQgKSB7XG5cdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0cmV0dXJuICQuZGF0ZXBpY2tlci5wYXJzZURhdGUoICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcImRhdGVGb3JtYXRcIiApLFxuXHRcdFx0XHRcdFx0b2Zmc2V0LCAkLmRhdGVwaWNrZXIuX2dldEZvcm1hdENvbmZpZyggaW5zdCApICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y2F0Y2ggKCBlICkge1xuXG5cdFx0XHRcdFx0Ly8gSWdub3JlXG5cdFx0XHRcdH1cblxuXHRcdFx0XHR2YXIgZGF0ZSA9ICggb2Zmc2V0LnRvTG93ZXJDYXNlKCkubWF0Y2goIC9eYy8gKSA/XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9nZXREYXRlKCBpbnN0ICkgOiBudWxsICkgfHwgbmV3IERhdGUoKSxcblx0XHRcdFx0XHR5ZWFyID0gZGF0ZS5nZXRGdWxsWWVhcigpLFxuXHRcdFx0XHRcdG1vbnRoID0gZGF0ZS5nZXRNb250aCgpLFxuXHRcdFx0XHRcdGRheSA9IGRhdGUuZ2V0RGF0ZSgpLFxuXHRcdFx0XHRcdHBhdHRlcm4gPSAvKFsrXFwtXT9bMC05XSspXFxzKihkfER8d3xXfG18TXx5fFkpPy9nLFxuXHRcdFx0XHRcdG1hdGNoZXMgPSBwYXR0ZXJuLmV4ZWMoIG9mZnNldCApO1xuXG5cdFx0XHRcdHdoaWxlICggbWF0Y2hlcyApIHtcblx0XHRcdFx0XHRzd2l0Y2ggKCBtYXRjaGVzWyAyIF0gfHwgXCJkXCIgKSB7XG5cdFx0XHRcdFx0XHRjYXNlIFwiZFwiIDogY2FzZSBcIkRcIiA6XG5cdFx0XHRcdFx0XHRcdGRheSArPSBwYXJzZUludCggbWF0Y2hlc1sgMSBdLCAxMCApOyBicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCJ3XCIgOiBjYXNlIFwiV1wiIDpcblx0XHRcdFx0XHRcdFx0ZGF5ICs9IHBhcnNlSW50KCBtYXRjaGVzWyAxIF0sIDEwICkgKiA3OyBicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCJtXCIgOiBjYXNlIFwiTVwiIDpcblx0XHRcdFx0XHRcdFx0bW9udGggKz0gcGFyc2VJbnQoIG1hdGNoZXNbIDEgXSwgMTAgKTtcblx0XHRcdFx0XHRcdFx0ZGF5ID0gTWF0aC5taW4oIGRheSwgJC5kYXRlcGlja2VyLl9nZXREYXlzSW5Nb250aCggeWVhciwgbW9udGggKSApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCJ5XCI6IGNhc2UgXCJZXCIgOlxuXHRcdFx0XHRcdFx0XHR5ZWFyICs9IHBhcnNlSW50KCBtYXRjaGVzWyAxIF0sIDEwICk7XG5cdFx0XHRcdFx0XHRcdGRheSA9IE1hdGgubWluKCBkYXksICQuZGF0ZXBpY2tlci5fZ2V0RGF5c0luTW9udGgoIHllYXIsIG1vbnRoICkgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdG1hdGNoZXMgPSBwYXR0ZXJuLmV4ZWMoIG9mZnNldCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBuZXcgRGF0ZSggeWVhciwgbW9udGgsIGRheSApO1xuXHRcdFx0fSxcblx0XHRcdG5ld0RhdGUgPSAoIGRhdGUgPT0gbnVsbCB8fCBkYXRlID09PSBcIlwiID8gZGVmYXVsdERhdGUgOiAoIHR5cGVvZiBkYXRlID09PSBcInN0cmluZ1wiID8gb2Zmc2V0U3RyaW5nKCBkYXRlICkgOlxuXHRcdFx0XHQoIHR5cGVvZiBkYXRlID09PSBcIm51bWJlclwiID8gKCBpc05hTiggZGF0ZSApID8gZGVmYXVsdERhdGUgOiBvZmZzZXROdW1lcmljKCBkYXRlICkgKSA6IG5ldyBEYXRlKCBkYXRlLmdldFRpbWUoKSApICkgKSApO1xuXG5cdFx0bmV3RGF0ZSA9ICggbmV3RGF0ZSAmJiBuZXdEYXRlLnRvU3RyaW5nKCkgPT09IFwiSW52YWxpZCBEYXRlXCIgPyBkZWZhdWx0RGF0ZSA6IG5ld0RhdGUgKTtcblx0XHRpZiAoIG5ld0RhdGUgKSB7XG5cdFx0XHRuZXdEYXRlLnNldEhvdXJzKCAwICk7XG5cdFx0XHRuZXdEYXRlLnNldE1pbnV0ZXMoIDAgKTtcblx0XHRcdG5ld0RhdGUuc2V0U2Vjb25kcyggMCApO1xuXHRcdFx0bmV3RGF0ZS5zZXRNaWxsaXNlY29uZHMoIDAgKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXdEYXRlICk7XG5cdH0sXG5cblx0LyogSGFuZGxlIHN3aXRjaCB0by9mcm9tIGRheWxpZ2h0IHNhdmluZy5cblx0ICogSG91cnMgbWF5IGJlIG5vbi16ZXJvIG9uIGRheWxpZ2h0IHNhdmluZyBjdXQtb3Zlcjpcblx0ICogPiAxMiB3aGVuIG1pZG5pZ2h0IGNoYW5nZW92ZXIsIGJ1dCB0aGVuIGNhbm5vdCBnZW5lcmF0ZVxuXHQgKiBtaWRuaWdodCBkYXRldGltZSwgc28ganVtcCB0byAxQU0sIG90aGVyd2lzZSByZXNldC5cblx0ICogQHBhcmFtICBkYXRlICAoRGF0ZSkgdGhlIGRhdGUgdG8gY2hlY2tcblx0ICogQHJldHVybiAgKERhdGUpIHRoZSBjb3JyZWN0ZWQgZGF0ZVxuXHQgKi9cblx0X2RheWxpZ2h0U2F2aW5nQWRqdXN0OiBmdW5jdGlvbiggZGF0ZSApIHtcblx0XHRpZiAoICFkYXRlICkge1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0fVxuXHRcdGRhdGUuc2V0SG91cnMoIGRhdGUuZ2V0SG91cnMoKSA+IDEyID8gZGF0ZS5nZXRIb3VycygpICsgMiA6IDAgKTtcblx0XHRyZXR1cm4gZGF0ZTtcblx0fSxcblxuXHQvKiBTZXQgdGhlIGRhdGUocykgZGlyZWN0bHkuICovXG5cdF9zZXREYXRlOiBmdW5jdGlvbiggaW5zdCwgZGF0ZSwgbm9DaGFuZ2UgKSB7XG5cdFx0dmFyIGNsZWFyID0gIWRhdGUsXG5cdFx0XHRvcmlnTW9udGggPSBpbnN0LnNlbGVjdGVkTW9udGgsXG5cdFx0XHRvcmlnWWVhciA9IGluc3Quc2VsZWN0ZWRZZWFyLFxuXHRcdFx0bmV3RGF0ZSA9IHRoaXMuX3Jlc3RyaWN0TWluTWF4KCBpbnN0LCB0aGlzLl9kZXRlcm1pbmVEYXRlKCBpbnN0LCBkYXRlLCBuZXcgRGF0ZSgpICkgKTtcblxuXHRcdGluc3Quc2VsZWN0ZWREYXkgPSBpbnN0LmN1cnJlbnREYXkgPSBuZXdEYXRlLmdldERhdGUoKTtcblx0XHRpbnN0LmRyYXdNb250aCA9IGluc3Quc2VsZWN0ZWRNb250aCA9IGluc3QuY3VycmVudE1vbnRoID0gbmV3RGF0ZS5nZXRNb250aCgpO1xuXHRcdGluc3QuZHJhd1llYXIgPSBpbnN0LnNlbGVjdGVkWWVhciA9IGluc3QuY3VycmVudFllYXIgPSBuZXdEYXRlLmdldEZ1bGxZZWFyKCk7XG5cdFx0aWYgKCAoIG9yaWdNb250aCAhPT0gaW5zdC5zZWxlY3RlZE1vbnRoIHx8IG9yaWdZZWFyICE9PSBpbnN0LnNlbGVjdGVkWWVhciApICYmICFub0NoYW5nZSApIHtcblx0XHRcdHRoaXMuX25vdGlmeUNoYW5nZSggaW5zdCApO1xuXHRcdH1cblx0XHR0aGlzLl9hZGp1c3RJbnN0RGF0ZSggaW5zdCApO1xuXHRcdGlmICggaW5zdC5pbnB1dCApIHtcblx0XHRcdGluc3QuaW5wdXQudmFsKCBjbGVhciA/IFwiXCIgOiB0aGlzLl9mb3JtYXREYXRlKCBpbnN0ICkgKTtcblx0XHR9XG5cdH0sXG5cblx0LyogUmV0cmlldmUgdGhlIGRhdGUocykgZGlyZWN0bHkuICovXG5cdF9nZXREYXRlOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHR2YXIgc3RhcnREYXRlID0gKCAhaW5zdC5jdXJyZW50WWVhciB8fCAoIGluc3QuaW5wdXQgJiYgaW5zdC5pbnB1dC52YWwoKSA9PT0gXCJcIiApID8gbnVsbCA6XG5cdFx0XHR0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoXG5cdFx0XHRpbnN0LmN1cnJlbnRZZWFyLCBpbnN0LmN1cnJlbnRNb250aCwgaW5zdC5jdXJyZW50RGF5ICkgKSApO1xuXHRcdFx0cmV0dXJuIHN0YXJ0RGF0ZTtcblx0fSxcblxuXHQvKiBBdHRhY2ggdGhlIG9ueHh4IGhhbmRsZXJzLiAgVGhlc2UgYXJlIGRlY2xhcmVkIHN0YXRpY2FsbHkgc29cblx0ICogdGhleSB3b3JrIHdpdGggc3RhdGljIGNvZGUgdHJhbnNmb3JtZXJzIGxpa2UgQ2FqYS5cblx0ICovXG5cdF9hdHRhY2hIYW5kbGVyczogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0dmFyIHN0ZXBNb250aHMgPSB0aGlzLl9nZXQoIGluc3QsIFwic3RlcE1vbnRoc1wiICksXG5cdFx0XHRpZCA9IFwiI1wiICsgaW5zdC5pZC5yZXBsYWNlKCAvXFxcXFxcXFwvZywgXCJcXFxcXCIgKTtcblx0XHRpbnN0LmRwRGl2LmZpbmQoIFwiW2RhdGEtaGFuZGxlcl1cIiApLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgaGFuZGxlciA9IHtcblx0XHRcdFx0cHJldjogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBpZCwgLXN0ZXBNb250aHMsIFwiTVwiICk7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdG5leHQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggaWQsICtzdGVwTW9udGhzLCBcIk1cIiApO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRoaWRlOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2hpZGVEYXRlcGlja2VyKCk7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHRvZGF5OiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2dvdG9Ub2RheSggaWQgKTtcblx0XHRcdFx0fSxcblx0XHRcdFx0c2VsZWN0RGF5OiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX3NlbGVjdERheSggaWQsICt0aGlzLmdldEF0dHJpYnV0ZSggXCJkYXRhLW1vbnRoXCIgKSwgK3RoaXMuZ2V0QXR0cmlidXRlKCBcImRhdGEteWVhclwiICksIHRoaXMgKTtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHNlbGVjdE1vbnRoOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX3NlbGVjdE1vbnRoWWVhciggaWQsIHRoaXMsIFwiTVwiICk7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRzZWxlY3RZZWFyOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX3NlbGVjdE1vbnRoWWVhciggaWQsIHRoaXMsIFwiWVwiICk7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXHRcdFx0JCggdGhpcyApLm9uKCB0aGlzLmdldEF0dHJpYnV0ZSggXCJkYXRhLWV2ZW50XCIgKSwgaGFuZGxlclsgdGhpcy5nZXRBdHRyaWJ1dGUoIFwiZGF0YS1oYW5kbGVyXCIgKSBdICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdC8qIEdlbmVyYXRlIHRoZSBIVE1MIGZvciB0aGUgY3VycmVudCBzdGF0ZSBvZiB0aGUgZGF0ZSBwaWNrZXIuICovXG5cdF9nZW5lcmF0ZUhUTUw6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHZhciBtYXhEcmF3LCBwcmV2VGV4dCwgcHJldiwgbmV4dFRleHQsIG5leHQsIGN1cnJlbnRUZXh0LCBnb3RvRGF0ZSxcblx0XHRcdGNvbnRyb2xzLCBidXR0b25QYW5lbCwgZmlyc3REYXksIHNob3dXZWVrLCBkYXlOYW1lcywgZGF5TmFtZXNNaW4sXG5cdFx0XHRtb250aE5hbWVzLCBtb250aE5hbWVzU2hvcnQsIGJlZm9yZVNob3dEYXksIHNob3dPdGhlck1vbnRocyxcblx0XHRcdHNlbGVjdE90aGVyTW9udGhzLCBkZWZhdWx0RGF0ZSwgaHRtbCwgZG93LCByb3csIGdyb3VwLCBjb2wsIHNlbGVjdGVkRGF0ZSxcblx0XHRcdGNvcm5lckNsYXNzLCBjYWxlbmRlciwgdGhlYWQsIGRheSwgZGF5c0luTW9udGgsIGxlYWREYXlzLCBjdXJSb3dzLCBudW1Sb3dzLFxuXHRcdFx0cHJpbnREYXRlLCBkUm93LCB0Ym9keSwgZGF5U2V0dGluZ3MsIG90aGVyTW9udGgsIHVuc2VsZWN0YWJsZSxcblx0XHRcdHRlbXBEYXRlID0gbmV3IERhdGUoKSxcblx0XHRcdHRvZGF5ID0gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoXG5cdFx0XHRcdG5ldyBEYXRlKCB0ZW1wRGF0ZS5nZXRGdWxsWWVhcigpLCB0ZW1wRGF0ZS5nZXRNb250aCgpLCB0ZW1wRGF0ZS5nZXREYXRlKCkgKSApLCAvLyBjbGVhciB0aW1lXG5cdFx0XHRpc1JUTCA9IHRoaXMuX2dldCggaW5zdCwgXCJpc1JUTFwiICksXG5cdFx0XHRzaG93QnV0dG9uUGFuZWwgPSB0aGlzLl9nZXQoIGluc3QsIFwic2hvd0J1dHRvblBhbmVsXCIgKSxcblx0XHRcdGhpZGVJZk5vUHJldk5leHQgPSB0aGlzLl9nZXQoIGluc3QsIFwiaGlkZUlmTm9QcmV2TmV4dFwiICksXG5cdFx0XHRuYXZpZ2F0aW9uQXNEYXRlRm9ybWF0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcIm5hdmlnYXRpb25Bc0RhdGVGb3JtYXRcIiApLFxuXHRcdFx0bnVtTW9udGhzID0gdGhpcy5fZ2V0TnVtYmVyT2ZNb250aHMoIGluc3QgKSxcblx0XHRcdHNob3dDdXJyZW50QXRQb3MgPSB0aGlzLl9nZXQoIGluc3QsIFwic2hvd0N1cnJlbnRBdFBvc1wiICksXG5cdFx0XHRzdGVwTW9udGhzID0gdGhpcy5fZ2V0KCBpbnN0LCBcInN0ZXBNb250aHNcIiApLFxuXHRcdFx0aXNNdWx0aU1vbnRoID0gKCBudW1Nb250aHNbIDAgXSAhPT0gMSB8fCBudW1Nb250aHNbIDEgXSAhPT0gMSApLFxuXHRcdFx0Y3VycmVudERhdGUgPSB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggKCAhaW5zdC5jdXJyZW50RGF5ID8gbmV3IERhdGUoIDk5OTksIDksIDkgKSA6XG5cdFx0XHRcdG5ldyBEYXRlKCBpbnN0LmN1cnJlbnRZZWFyLCBpbnN0LmN1cnJlbnRNb250aCwgaW5zdC5jdXJyZW50RGF5ICkgKSApLFxuXHRcdFx0bWluRGF0ZSA9IHRoaXMuX2dldE1pbk1heERhdGUoIGluc3QsIFwibWluXCIgKSxcblx0XHRcdG1heERhdGUgPSB0aGlzLl9nZXRNaW5NYXhEYXRlKCBpbnN0LCBcIm1heFwiICksXG5cdFx0XHRkcmF3TW9udGggPSBpbnN0LmRyYXdNb250aCAtIHNob3dDdXJyZW50QXRQb3MsXG5cdFx0XHRkcmF3WWVhciA9IGluc3QuZHJhd1llYXI7XG5cblx0XHRpZiAoIGRyYXdNb250aCA8IDAgKSB7XG5cdFx0XHRkcmF3TW9udGggKz0gMTI7XG5cdFx0XHRkcmF3WWVhci0tO1xuXHRcdH1cblx0XHRpZiAoIG1heERhdGUgKSB7XG5cdFx0XHRtYXhEcmF3ID0gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCBtYXhEYXRlLmdldEZ1bGxZZWFyKCksXG5cdFx0XHRcdG1heERhdGUuZ2V0TW9udGgoKSAtICggbnVtTW9udGhzWyAwIF0gKiBudW1Nb250aHNbIDEgXSApICsgMSwgbWF4RGF0ZS5nZXREYXRlKCkgKSApO1xuXHRcdFx0bWF4RHJhdyA9ICggbWluRGF0ZSAmJiBtYXhEcmF3IDwgbWluRGF0ZSA/IG1pbkRhdGUgOiBtYXhEcmF3ICk7XG5cdFx0XHR3aGlsZSAoIHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggZHJhd1llYXIsIGRyYXdNb250aCwgMSApICkgPiBtYXhEcmF3ICkge1xuXHRcdFx0XHRkcmF3TW9udGgtLTtcblx0XHRcdFx0aWYgKCBkcmF3TW9udGggPCAwICkge1xuXHRcdFx0XHRcdGRyYXdNb250aCA9IDExO1xuXHRcdFx0XHRcdGRyYXdZZWFyLS07XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdFx0aW5zdC5kcmF3TW9udGggPSBkcmF3TW9udGg7XG5cdFx0aW5zdC5kcmF3WWVhciA9IGRyYXdZZWFyO1xuXG5cdFx0cHJldlRleHQgPSB0aGlzLl9nZXQoIGluc3QsIFwicHJldlRleHRcIiApO1xuXHRcdHByZXZUZXh0ID0gKCAhbmF2aWdhdGlvbkFzRGF0ZUZvcm1hdCA/IHByZXZUZXh0IDogdGhpcy5mb3JtYXREYXRlKCBwcmV2VGV4dCxcblx0XHRcdHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggZHJhd1llYXIsIGRyYXdNb250aCAtIHN0ZXBNb250aHMsIDEgKSApLFxuXHRcdFx0dGhpcy5fZ2V0Rm9ybWF0Q29uZmlnKCBpbnN0ICkgKSApO1xuXG5cdFx0cHJldiA9ICggdGhpcy5fY2FuQWRqdXN0TW9udGgoIGluc3QsIC0xLCBkcmF3WWVhciwgZHJhd01vbnRoICkgP1xuXHRcdFx0XCI8YSBjbGFzcz0ndWktZGF0ZXBpY2tlci1wcmV2IHVpLWNvcm5lci1hbGwnIGRhdGEtaGFuZGxlcj0ncHJldicgZGF0YS1ldmVudD0nY2xpY2snXCIgK1xuXHRcdFx0XCIgdGl0bGU9J1wiICsgcHJldlRleHQgKyBcIic+PHNwYW4gY2xhc3M9J3VpLWljb24gdWktaWNvbi1jaXJjbGUtdHJpYW5nbGUtXCIgKyAoIGlzUlRMID8gXCJlXCIgOiBcIndcIiApICsgXCInPlwiICsgcHJldlRleHQgKyBcIjwvc3Bhbj48L2E+XCIgOlxuXHRcdFx0KCBoaWRlSWZOb1ByZXZOZXh0ID8gXCJcIiA6IFwiPGEgY2xhc3M9J3VpLWRhdGVwaWNrZXItcHJldiB1aS1jb3JuZXItYWxsIHVpLXN0YXRlLWRpc2FibGVkJyB0aXRsZT0nXCIgKyBwcmV2VGV4dCArIFwiJz48c3BhbiBjbGFzcz0ndWktaWNvbiB1aS1pY29uLWNpcmNsZS10cmlhbmdsZS1cIiArICggaXNSVEwgPyBcImVcIiA6IFwid1wiICkgKyBcIic+XCIgKyBwcmV2VGV4dCArIFwiPC9zcGFuPjwvYT5cIiApICk7XG5cblx0XHRuZXh0VGV4dCA9IHRoaXMuX2dldCggaW5zdCwgXCJuZXh0VGV4dFwiICk7XG5cdFx0bmV4dFRleHQgPSAoICFuYXZpZ2F0aW9uQXNEYXRlRm9ybWF0ID8gbmV4dFRleHQgOiB0aGlzLmZvcm1hdERhdGUoIG5leHRUZXh0LFxuXHRcdFx0dGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCBkcmF3WWVhciwgZHJhd01vbnRoICsgc3RlcE1vbnRocywgMSApICksXG5cdFx0XHR0aGlzLl9nZXRGb3JtYXRDb25maWcoIGluc3QgKSApICk7XG5cblx0XHRuZXh0ID0gKCB0aGlzLl9jYW5BZGp1c3RNb250aCggaW5zdCwgKzEsIGRyYXdZZWFyLCBkcmF3TW9udGggKSA/XG5cdFx0XHRcIjxhIGNsYXNzPSd1aS1kYXRlcGlja2VyLW5leHQgdWktY29ybmVyLWFsbCcgZGF0YS1oYW5kbGVyPSduZXh0JyBkYXRhLWV2ZW50PSdjbGljaydcIiArXG5cdFx0XHRcIiB0aXRsZT0nXCIgKyBuZXh0VGV4dCArIFwiJz48c3BhbiBjbGFzcz0ndWktaWNvbiB1aS1pY29uLWNpcmNsZS10cmlhbmdsZS1cIiArICggaXNSVEwgPyBcIndcIiA6IFwiZVwiICkgKyBcIic+XCIgKyBuZXh0VGV4dCArIFwiPC9zcGFuPjwvYT5cIiA6XG5cdFx0XHQoIGhpZGVJZk5vUHJldk5leHQgPyBcIlwiIDogXCI8YSBjbGFzcz0ndWktZGF0ZXBpY2tlci1uZXh0IHVpLWNvcm5lci1hbGwgdWktc3RhdGUtZGlzYWJsZWQnIHRpdGxlPSdcIiArIG5leHRUZXh0ICsgXCInPjxzcGFuIGNsYXNzPSd1aS1pY29uIHVpLWljb24tY2lyY2xlLXRyaWFuZ2xlLVwiICsgKCBpc1JUTCA/IFwid1wiIDogXCJlXCIgKSArIFwiJz5cIiArIG5leHRUZXh0ICsgXCI8L3NwYW4+PC9hPlwiICkgKTtcblxuXHRcdGN1cnJlbnRUZXh0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcImN1cnJlbnRUZXh0XCIgKTtcblx0XHRnb3RvRGF0ZSA9ICggdGhpcy5fZ2V0KCBpbnN0LCBcImdvdG9DdXJyZW50XCIgKSAmJiBpbnN0LmN1cnJlbnREYXkgPyBjdXJyZW50RGF0ZSA6IHRvZGF5ICk7XG5cdFx0Y3VycmVudFRleHQgPSAoICFuYXZpZ2F0aW9uQXNEYXRlRm9ybWF0ID8gY3VycmVudFRleHQgOlxuXHRcdFx0dGhpcy5mb3JtYXREYXRlKCBjdXJyZW50VGV4dCwgZ290b0RhdGUsIHRoaXMuX2dldEZvcm1hdENvbmZpZyggaW5zdCApICkgKTtcblxuXHRcdGNvbnRyb2xzID0gKCAhaW5zdC5pbmxpbmUgPyBcIjxidXR0b24gdHlwZT0nYnV0dG9uJyBjbGFzcz0ndWktZGF0ZXBpY2tlci1jbG9zZSB1aS1zdGF0ZS1kZWZhdWx0IHVpLXByaW9yaXR5LXByaW1hcnkgdWktY29ybmVyLWFsbCcgZGF0YS1oYW5kbGVyPSdoaWRlJyBkYXRhLWV2ZW50PSdjbGljayc+XCIgK1xuXHRcdFx0dGhpcy5fZ2V0KCBpbnN0LCBcImNsb3NlVGV4dFwiICkgKyBcIjwvYnV0dG9uPlwiIDogXCJcIiApO1xuXG5cdFx0YnV0dG9uUGFuZWwgPSAoIHNob3dCdXR0b25QYW5lbCApID8gXCI8ZGl2IGNsYXNzPSd1aS1kYXRlcGlja2VyLWJ1dHRvbnBhbmUgdWktd2lkZ2V0LWNvbnRlbnQnPlwiICsgKCBpc1JUTCA/IGNvbnRyb2xzIDogXCJcIiApICtcblx0XHRcdCggdGhpcy5faXNJblJhbmdlKCBpbnN0LCBnb3RvRGF0ZSApID8gXCI8YnV0dG9uIHR5cGU9J2J1dHRvbicgY2xhc3M9J3VpLWRhdGVwaWNrZXItY3VycmVudCB1aS1zdGF0ZS1kZWZhdWx0IHVpLXByaW9yaXR5LXNlY29uZGFyeSB1aS1jb3JuZXItYWxsJyBkYXRhLWhhbmRsZXI9J3RvZGF5JyBkYXRhLWV2ZW50PSdjbGljaydcIiArXG5cdFx0XHRcIj5cIiArIGN1cnJlbnRUZXh0ICsgXCI8L2J1dHRvbj5cIiA6IFwiXCIgKSArICggaXNSVEwgPyBcIlwiIDogY29udHJvbHMgKSArIFwiPC9kaXY+XCIgOiBcIlwiO1xuXG5cdFx0Zmlyc3REYXkgPSBwYXJzZUludCggdGhpcy5fZ2V0KCBpbnN0LCBcImZpcnN0RGF5XCIgKSwgMTAgKTtcblx0XHRmaXJzdERheSA9ICggaXNOYU4oIGZpcnN0RGF5ICkgPyAwIDogZmlyc3REYXkgKTtcblxuXHRcdHNob3dXZWVrID0gdGhpcy5fZ2V0KCBpbnN0LCBcInNob3dXZWVrXCIgKTtcblx0XHRkYXlOYW1lcyA9IHRoaXMuX2dldCggaW5zdCwgXCJkYXlOYW1lc1wiICk7XG5cdFx0ZGF5TmFtZXNNaW4gPSB0aGlzLl9nZXQoIGluc3QsIFwiZGF5TmFtZXNNaW5cIiApO1xuXHRcdG1vbnRoTmFtZXMgPSB0aGlzLl9nZXQoIGluc3QsIFwibW9udGhOYW1lc1wiICk7XG5cdFx0bW9udGhOYW1lc1Nob3J0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcIm1vbnRoTmFtZXNTaG9ydFwiICk7XG5cdFx0YmVmb3JlU2hvd0RheSA9IHRoaXMuX2dldCggaW5zdCwgXCJiZWZvcmVTaG93RGF5XCIgKTtcblx0XHRzaG93T3RoZXJNb250aHMgPSB0aGlzLl9nZXQoIGluc3QsIFwic2hvd090aGVyTW9udGhzXCIgKTtcblx0XHRzZWxlY3RPdGhlck1vbnRocyA9IHRoaXMuX2dldCggaW5zdCwgXCJzZWxlY3RPdGhlck1vbnRoc1wiICk7XG5cdFx0ZGVmYXVsdERhdGUgPSB0aGlzLl9nZXREZWZhdWx0RGF0ZSggaW5zdCApO1xuXHRcdGh0bWwgPSBcIlwiO1xuXG5cdFx0Zm9yICggcm93ID0gMDsgcm93IDwgbnVtTW9udGhzWyAwIF07IHJvdysrICkge1xuXHRcdFx0Z3JvdXAgPSBcIlwiO1xuXHRcdFx0dGhpcy5tYXhSb3dzID0gNDtcblx0XHRcdGZvciAoIGNvbCA9IDA7IGNvbCA8IG51bU1vbnRoc1sgMSBdOyBjb2wrKyApIHtcblx0XHRcdFx0c2VsZWN0ZWREYXRlID0gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCBkcmF3WWVhciwgZHJhd01vbnRoLCBpbnN0LnNlbGVjdGVkRGF5ICkgKTtcblx0XHRcdFx0Y29ybmVyQ2xhc3MgPSBcIiB1aS1jb3JuZXItYWxsXCI7XG5cdFx0XHRcdGNhbGVuZGVyID0gXCJcIjtcblx0XHRcdFx0aWYgKCBpc011bHRpTW9udGggKSB7XG5cdFx0XHRcdFx0Y2FsZW5kZXIgKz0gXCI8ZGl2IGNsYXNzPSd1aS1kYXRlcGlja2VyLWdyb3VwXCI7XG5cdFx0XHRcdFx0aWYgKCBudW1Nb250aHNbIDEgXSA+IDEgKSB7XG5cdFx0XHRcdFx0XHRzd2l0Y2ggKCBjb2wgKSB7XG5cdFx0XHRcdFx0XHRcdGNhc2UgMDogY2FsZW5kZXIgKz0gXCIgdWktZGF0ZXBpY2tlci1ncm91cC1maXJzdFwiO1xuXHRcdFx0XHRcdFx0XHRcdGNvcm5lckNsYXNzID0gXCIgdWktY29ybmVyLVwiICsgKCBpc1JUTCA/IFwicmlnaHRcIiA6IFwibGVmdFwiICk7IGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRjYXNlIG51bU1vbnRoc1sgMSBdIC0gMTogY2FsZW5kZXIgKz0gXCIgdWktZGF0ZXBpY2tlci1ncm91cC1sYXN0XCI7XG5cdFx0XHRcdFx0XHRcdFx0Y29ybmVyQ2xhc3MgPSBcIiB1aS1jb3JuZXItXCIgKyAoIGlzUlRMID8gXCJsZWZ0XCIgOiBcInJpZ2h0XCIgKTsgYnJlYWs7XG5cdFx0XHRcdFx0XHRcdGRlZmF1bHQ6IGNhbGVuZGVyICs9IFwiIHVpLWRhdGVwaWNrZXItZ3JvdXAtbWlkZGxlXCI7IGNvcm5lckNsYXNzID0gXCJcIjsgYnJlYWs7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGNhbGVuZGVyICs9IFwiJz5cIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRjYWxlbmRlciArPSBcIjxkaXYgY2xhc3M9J3VpLWRhdGVwaWNrZXItaGVhZGVyIHVpLXdpZGdldC1oZWFkZXIgdWktaGVscGVyLWNsZWFyZml4XCIgKyBjb3JuZXJDbGFzcyArIFwiJz5cIiArXG5cdFx0XHRcdFx0KCAvYWxsfGxlZnQvLnRlc3QoIGNvcm5lckNsYXNzICkgJiYgcm93ID09PSAwID8gKCBpc1JUTCA/IG5leHQgOiBwcmV2ICkgOiBcIlwiICkgK1xuXHRcdFx0XHRcdCggL2FsbHxyaWdodC8udGVzdCggY29ybmVyQ2xhc3MgKSAmJiByb3cgPT09IDAgPyAoIGlzUlRMID8gcHJldiA6IG5leHQgKSA6IFwiXCIgKSArXG5cdFx0XHRcdFx0dGhpcy5fZ2VuZXJhdGVNb250aFllYXJIZWFkZXIoIGluc3QsIGRyYXdNb250aCwgZHJhd1llYXIsIG1pbkRhdGUsIG1heERhdGUsXG5cdFx0XHRcdFx0cm93ID4gMCB8fCBjb2wgPiAwLCBtb250aE5hbWVzLCBtb250aE5hbWVzU2hvcnQgKSArIC8vIGRyYXcgbW9udGggaGVhZGVyc1xuXHRcdFx0XHRcdFwiPC9kaXY+PHRhYmxlIGNsYXNzPSd1aS1kYXRlcGlja2VyLWNhbGVuZGFyJz48dGhlYWQ+XCIgK1xuXHRcdFx0XHRcdFwiPHRyPlwiO1xuXHRcdFx0XHR0aGVhZCA9ICggc2hvd1dlZWsgPyBcIjx0aCBjbGFzcz0ndWktZGF0ZXBpY2tlci13ZWVrLWNvbCc+XCIgKyB0aGlzLl9nZXQoIGluc3QsIFwid2Vla0hlYWRlclwiICkgKyBcIjwvdGg+XCIgOiBcIlwiICk7XG5cdFx0XHRcdGZvciAoIGRvdyA9IDA7IGRvdyA8IDc7IGRvdysrICkgeyAvLyBkYXlzIG9mIHRoZSB3ZWVrXG5cdFx0XHRcdFx0ZGF5ID0gKCBkb3cgKyBmaXJzdERheSApICUgNztcblx0XHRcdFx0XHR0aGVhZCArPSBcIjx0aCBzY29wZT0nY29sJ1wiICsgKCAoIGRvdyArIGZpcnN0RGF5ICsgNiApICUgNyA+PSA1ID8gXCIgY2xhc3M9J3VpLWRhdGVwaWNrZXItd2Vlay1lbmQnXCIgOiBcIlwiICkgKyBcIj5cIiArXG5cdFx0XHRcdFx0XHRcIjxzcGFuIHRpdGxlPSdcIiArIGRheU5hbWVzWyBkYXkgXSArIFwiJz5cIiArIGRheU5hbWVzTWluWyBkYXkgXSArIFwiPC9zcGFuPjwvdGg+XCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y2FsZW5kZXIgKz0gdGhlYWQgKyBcIjwvdHI+PC90aGVhZD48dGJvZHk+XCI7XG5cdFx0XHRcdGRheXNJbk1vbnRoID0gdGhpcy5fZ2V0RGF5c0luTW9udGgoIGRyYXdZZWFyLCBkcmF3TW9udGggKTtcblx0XHRcdFx0aWYgKCBkcmF3WWVhciA9PT0gaW5zdC5zZWxlY3RlZFllYXIgJiYgZHJhd01vbnRoID09PSBpbnN0LnNlbGVjdGVkTW9udGggKSB7XG5cdFx0XHRcdFx0aW5zdC5zZWxlY3RlZERheSA9IE1hdGgubWluKCBpbnN0LnNlbGVjdGVkRGF5LCBkYXlzSW5Nb250aCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGxlYWREYXlzID0gKCB0aGlzLl9nZXRGaXJzdERheU9mTW9udGgoIGRyYXdZZWFyLCBkcmF3TW9udGggKSAtIGZpcnN0RGF5ICsgNyApICUgNztcblx0XHRcdFx0Y3VyUm93cyA9IE1hdGguY2VpbCggKCBsZWFkRGF5cyArIGRheXNJbk1vbnRoICkgLyA3ICk7IC8vIGNhbGN1bGF0ZSB0aGUgbnVtYmVyIG9mIHJvd3MgdG8gZ2VuZXJhdGVcblx0XHRcdFx0bnVtUm93cyA9ICggaXNNdWx0aU1vbnRoID8gdGhpcy5tYXhSb3dzID4gY3VyUm93cyA/IHRoaXMubWF4Um93cyA6IGN1clJvd3MgOiBjdXJSb3dzICk7IC8vSWYgbXVsdGlwbGUgbW9udGhzLCB1c2UgdGhlIGhpZ2hlciBudW1iZXIgb2Ygcm93cyAoc2VlICM3MDQzKVxuXHRcdFx0XHR0aGlzLm1heFJvd3MgPSBudW1Sb3dzO1xuXHRcdFx0XHRwcmludERhdGUgPSB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIGRyYXdZZWFyLCBkcmF3TW9udGgsIDEgLSBsZWFkRGF5cyApICk7XG5cdFx0XHRcdGZvciAoIGRSb3cgPSAwOyBkUm93IDwgbnVtUm93czsgZFJvdysrICkgeyAvLyBjcmVhdGUgZGF0ZSBwaWNrZXIgcm93c1xuXHRcdFx0XHRcdGNhbGVuZGVyICs9IFwiPHRyPlwiO1xuXHRcdFx0XHRcdHRib2R5ID0gKCAhc2hvd1dlZWsgPyBcIlwiIDogXCI8dGQgY2xhc3M9J3VpLWRhdGVwaWNrZXItd2Vlay1jb2wnPlwiICtcblx0XHRcdFx0XHRcdHRoaXMuX2dldCggaW5zdCwgXCJjYWxjdWxhdGVXZWVrXCIgKSggcHJpbnREYXRlICkgKyBcIjwvdGQ+XCIgKTtcblx0XHRcdFx0XHRmb3IgKCBkb3cgPSAwOyBkb3cgPCA3OyBkb3crKyApIHsgLy8gY3JlYXRlIGRhdGUgcGlja2VyIGRheXNcblx0XHRcdFx0XHRcdGRheVNldHRpbmdzID0gKCBiZWZvcmVTaG93RGF5ID9cblx0XHRcdFx0XHRcdFx0YmVmb3JlU2hvd0RheS5hcHBseSggKCBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dFsgMCBdIDogbnVsbCApLCBbIHByaW50RGF0ZSBdICkgOiBbIHRydWUsIFwiXCIgXSApO1xuXHRcdFx0XHRcdFx0b3RoZXJNb250aCA9ICggcHJpbnREYXRlLmdldE1vbnRoKCkgIT09IGRyYXdNb250aCApO1xuXHRcdFx0XHRcdFx0dW5zZWxlY3RhYmxlID0gKCBvdGhlck1vbnRoICYmICFzZWxlY3RPdGhlck1vbnRocyApIHx8ICFkYXlTZXR0aW5nc1sgMCBdIHx8XG5cdFx0XHRcdFx0XHRcdCggbWluRGF0ZSAmJiBwcmludERhdGUgPCBtaW5EYXRlICkgfHwgKCBtYXhEYXRlICYmIHByaW50RGF0ZSA+IG1heERhdGUgKTtcblx0XHRcdFx0XHRcdHRib2R5ICs9IFwiPHRkIGNsYXNzPSdcIiArXG5cdFx0XHRcdFx0XHRcdCggKCBkb3cgKyBmaXJzdERheSArIDYgKSAlIDcgPj0gNSA/IFwiIHVpLWRhdGVwaWNrZXItd2Vlay1lbmRcIiA6IFwiXCIgKSArIC8vIGhpZ2hsaWdodCB3ZWVrZW5kc1xuXHRcdFx0XHRcdFx0XHQoIG90aGVyTW9udGggPyBcIiB1aS1kYXRlcGlja2VyLW90aGVyLW1vbnRoXCIgOiBcIlwiICkgKyAvLyBoaWdobGlnaHQgZGF5cyBmcm9tIG90aGVyIG1vbnRoc1xuXHRcdFx0XHRcdFx0XHQoICggcHJpbnREYXRlLmdldFRpbWUoKSA9PT0gc2VsZWN0ZWREYXRlLmdldFRpbWUoKSAmJiBkcmF3TW9udGggPT09IGluc3Quc2VsZWN0ZWRNb250aCAmJiBpbnN0Ll9rZXlFdmVudCApIHx8IC8vIHVzZXIgcHJlc3NlZCBrZXlcblx0XHRcdFx0XHRcdFx0KCBkZWZhdWx0RGF0ZS5nZXRUaW1lKCkgPT09IHByaW50RGF0ZS5nZXRUaW1lKCkgJiYgZGVmYXVsdERhdGUuZ2V0VGltZSgpID09PSBzZWxlY3RlZERhdGUuZ2V0VGltZSgpICkgP1xuXG5cdFx0XHRcdFx0XHRcdC8vIG9yIGRlZmF1bHREYXRlIGlzIGN1cnJlbnQgcHJpbnRlZERhdGUgYW5kIGRlZmF1bHREYXRlIGlzIHNlbGVjdGVkRGF0ZVxuXHRcdFx0XHRcdFx0XHRcIiBcIiArIHRoaXMuX2RheU92ZXJDbGFzcyA6IFwiXCIgKSArIC8vIGhpZ2hsaWdodCBzZWxlY3RlZCBkYXlcblx0XHRcdFx0XHRcdFx0KCB1bnNlbGVjdGFibGUgPyBcIiBcIiArIHRoaXMuX3Vuc2VsZWN0YWJsZUNsYXNzICsgXCIgdWktc3RhdGUtZGlzYWJsZWRcIiA6IFwiXCIgKSArICAvLyBoaWdobGlnaHQgdW5zZWxlY3RhYmxlIGRheXNcblx0XHRcdFx0XHRcdFx0KCBvdGhlck1vbnRoICYmICFzaG93T3RoZXJNb250aHMgPyBcIlwiIDogXCIgXCIgKyBkYXlTZXR0aW5nc1sgMSBdICsgLy8gaGlnaGxpZ2h0IGN1c3RvbSBkYXRlc1xuXHRcdFx0XHRcdFx0XHQoIHByaW50RGF0ZS5nZXRUaW1lKCkgPT09IGN1cnJlbnREYXRlLmdldFRpbWUoKSA/IFwiIFwiICsgdGhpcy5fY3VycmVudENsYXNzIDogXCJcIiApICsgLy8gaGlnaGxpZ2h0IHNlbGVjdGVkIGRheVxuXHRcdFx0XHRcdFx0XHQoIHByaW50RGF0ZS5nZXRUaW1lKCkgPT09IHRvZGF5LmdldFRpbWUoKSA/IFwiIHVpLWRhdGVwaWNrZXItdG9kYXlcIiA6IFwiXCIgKSApICsgXCInXCIgKyAvLyBoaWdobGlnaHQgdG9kYXkgKGlmIGRpZmZlcmVudClcblx0XHRcdFx0XHRcdFx0KCAoICFvdGhlck1vbnRoIHx8IHNob3dPdGhlck1vbnRocyApICYmIGRheVNldHRpbmdzWyAyIF0gPyBcIiB0aXRsZT0nXCIgKyBkYXlTZXR0aW5nc1sgMiBdLnJlcGxhY2UoIC8nL2csIFwiJiMzOTtcIiApICsgXCInXCIgOiBcIlwiICkgKyAvLyBjZWxsIHRpdGxlXG5cdFx0XHRcdFx0XHRcdCggdW5zZWxlY3RhYmxlID8gXCJcIiA6IFwiIGRhdGEtaGFuZGxlcj0nc2VsZWN0RGF5JyBkYXRhLWV2ZW50PSdjbGljaycgZGF0YS1tb250aD0nXCIgKyBwcmludERhdGUuZ2V0TW9udGgoKSArIFwiJyBkYXRhLXllYXI9J1wiICsgcHJpbnREYXRlLmdldEZ1bGxZZWFyKCkgKyBcIidcIiApICsgXCI+XCIgKyAvLyBhY3Rpb25zXG5cdFx0XHRcdFx0XHRcdCggb3RoZXJNb250aCAmJiAhc2hvd090aGVyTW9udGhzID8gXCImI3hhMDtcIiA6IC8vIGRpc3BsYXkgZm9yIG90aGVyIG1vbnRoc1xuXHRcdFx0XHRcdFx0XHQoIHVuc2VsZWN0YWJsZSA/IFwiPHNwYW4gY2xhc3M9J3VpLXN0YXRlLWRlZmF1bHQnPlwiICsgcHJpbnREYXRlLmdldERhdGUoKSArIFwiPC9zcGFuPlwiIDogXCI8YSBjbGFzcz0ndWktc3RhdGUtZGVmYXVsdFwiICtcblx0XHRcdFx0XHRcdFx0KCBwcmludERhdGUuZ2V0VGltZSgpID09PSB0b2RheS5nZXRUaW1lKCkgPyBcIiB1aS1zdGF0ZS1oaWdobGlnaHRcIiA6IFwiXCIgKSArXG5cdFx0XHRcdFx0XHRcdCggcHJpbnREYXRlLmdldFRpbWUoKSA9PT0gY3VycmVudERhdGUuZ2V0VGltZSgpID8gXCIgdWktc3RhdGUtYWN0aXZlXCIgOiBcIlwiICkgKyAvLyBoaWdobGlnaHQgc2VsZWN0ZWQgZGF5XG5cdFx0XHRcdFx0XHRcdCggb3RoZXJNb250aCA/IFwiIHVpLXByaW9yaXR5LXNlY29uZGFyeVwiIDogXCJcIiApICsgLy8gZGlzdGluZ3Vpc2ggZGF0ZXMgZnJvbSBvdGhlciBtb250aHNcblx0XHRcdFx0XHRcdFx0XCInIGhyZWY9JyMnPlwiICsgcHJpbnREYXRlLmdldERhdGUoKSArIFwiPC9hPlwiICkgKSArIFwiPC90ZD5cIjsgLy8gZGlzcGxheSBzZWxlY3RhYmxlIGRhdGVcblx0XHRcdFx0XHRcdHByaW50RGF0ZS5zZXREYXRlKCBwcmludERhdGUuZ2V0RGF0ZSgpICsgMSApO1xuXHRcdFx0XHRcdFx0cHJpbnREYXRlID0gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIHByaW50RGF0ZSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRjYWxlbmRlciArPSB0Ym9keSArIFwiPC90cj5cIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRkcmF3TW9udGgrKztcblx0XHRcdFx0aWYgKCBkcmF3TW9udGggPiAxMSApIHtcblx0XHRcdFx0XHRkcmF3TW9udGggPSAwO1xuXHRcdFx0XHRcdGRyYXdZZWFyKys7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y2FsZW5kZXIgKz0gXCI8L3Rib2R5PjwvdGFibGU+XCIgKyAoIGlzTXVsdGlNb250aCA/IFwiPC9kaXY+XCIgK1xuXHRcdFx0XHRcdFx0XHQoICggbnVtTW9udGhzWyAwIF0gPiAwICYmIGNvbCA9PT0gbnVtTW9udGhzWyAxIF0gLSAxICkgPyBcIjxkaXYgY2xhc3M9J3VpLWRhdGVwaWNrZXItcm93LWJyZWFrJz48L2Rpdj5cIiA6IFwiXCIgKSA6IFwiXCIgKTtcblx0XHRcdFx0Z3JvdXAgKz0gY2FsZW5kZXI7XG5cdFx0XHR9XG5cdFx0XHRodG1sICs9IGdyb3VwO1xuXHRcdH1cblx0XHRodG1sICs9IGJ1dHRvblBhbmVsO1xuXHRcdGluc3QuX2tleUV2ZW50ID0gZmFsc2U7XG5cdFx0cmV0dXJuIGh0bWw7XG5cdH0sXG5cblx0LyogR2VuZXJhdGUgdGhlIG1vbnRoIGFuZCB5ZWFyIGhlYWRlci4gKi9cblx0X2dlbmVyYXRlTW9udGhZZWFySGVhZGVyOiBmdW5jdGlvbiggaW5zdCwgZHJhd01vbnRoLCBkcmF3WWVhciwgbWluRGF0ZSwgbWF4RGF0ZSxcblx0XHRcdHNlY29uZGFyeSwgbW9udGhOYW1lcywgbW9udGhOYW1lc1Nob3J0ICkge1xuXG5cdFx0dmFyIGluTWluWWVhciwgaW5NYXhZZWFyLCBtb250aCwgeWVhcnMsIHRoaXNZZWFyLCBkZXRlcm1pbmVZZWFyLCB5ZWFyLCBlbmRZZWFyLFxuXHRcdFx0Y2hhbmdlTW9udGggPSB0aGlzLl9nZXQoIGluc3QsIFwiY2hhbmdlTW9udGhcIiApLFxuXHRcdFx0Y2hhbmdlWWVhciA9IHRoaXMuX2dldCggaW5zdCwgXCJjaGFuZ2VZZWFyXCIgKSxcblx0XHRcdHNob3dNb250aEFmdGVyWWVhciA9IHRoaXMuX2dldCggaW5zdCwgXCJzaG93TW9udGhBZnRlclllYXJcIiApLFxuXHRcdFx0aHRtbCA9IFwiPGRpdiBjbGFzcz0ndWktZGF0ZXBpY2tlci10aXRsZSc+XCIsXG5cdFx0XHRtb250aEh0bWwgPSBcIlwiO1xuXG5cdFx0Ly8gTW9udGggc2VsZWN0aW9uXG5cdFx0aWYgKCBzZWNvbmRhcnkgfHwgIWNoYW5nZU1vbnRoICkge1xuXHRcdFx0bW9udGhIdG1sICs9IFwiPHNwYW4gY2xhc3M9J3VpLWRhdGVwaWNrZXItbW9udGgnPlwiICsgbW9udGhOYW1lc1sgZHJhd01vbnRoIF0gKyBcIjwvc3Bhbj5cIjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aW5NaW5ZZWFyID0gKCBtaW5EYXRlICYmIG1pbkRhdGUuZ2V0RnVsbFllYXIoKSA9PT0gZHJhd1llYXIgKTtcblx0XHRcdGluTWF4WWVhciA9ICggbWF4RGF0ZSAmJiBtYXhEYXRlLmdldEZ1bGxZZWFyKCkgPT09IGRyYXdZZWFyICk7XG5cdFx0XHRtb250aEh0bWwgKz0gXCI8c2VsZWN0IGNsYXNzPSd1aS1kYXRlcGlja2VyLW1vbnRoJyBkYXRhLWhhbmRsZXI9J3NlbGVjdE1vbnRoJyBkYXRhLWV2ZW50PSdjaGFuZ2UnPlwiO1xuXHRcdFx0Zm9yICggbW9udGggPSAwOyBtb250aCA8IDEyOyBtb250aCsrICkge1xuXHRcdFx0XHRpZiAoICggIWluTWluWWVhciB8fCBtb250aCA+PSBtaW5EYXRlLmdldE1vbnRoKCkgKSAmJiAoICFpbk1heFllYXIgfHwgbW9udGggPD0gbWF4RGF0ZS5nZXRNb250aCgpICkgKSB7XG5cdFx0XHRcdFx0bW9udGhIdG1sICs9IFwiPG9wdGlvbiB2YWx1ZT0nXCIgKyBtb250aCArIFwiJ1wiICtcblx0XHRcdFx0XHRcdCggbW9udGggPT09IGRyYXdNb250aCA/IFwiIHNlbGVjdGVkPSdzZWxlY3RlZCdcIiA6IFwiXCIgKSArXG5cdFx0XHRcdFx0XHRcIj5cIiArIG1vbnRoTmFtZXNTaG9ydFsgbW9udGggXSArIFwiPC9vcHRpb24+XCI7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdG1vbnRoSHRtbCArPSBcIjwvc2VsZWN0PlwiO1xuXHRcdH1cblxuXHRcdGlmICggIXNob3dNb250aEFmdGVyWWVhciApIHtcblx0XHRcdGh0bWwgKz0gbW9udGhIdG1sICsgKCBzZWNvbmRhcnkgfHwgISggY2hhbmdlTW9udGggJiYgY2hhbmdlWWVhciApID8gXCImI3hhMDtcIiA6IFwiXCIgKTtcblx0XHR9XG5cblx0XHQvLyBZZWFyIHNlbGVjdGlvblxuXHRcdGlmICggIWluc3QueWVhcnNodG1sICkge1xuXHRcdFx0aW5zdC55ZWFyc2h0bWwgPSBcIlwiO1xuXHRcdFx0aWYgKCBzZWNvbmRhcnkgfHwgIWNoYW5nZVllYXIgKSB7XG5cdFx0XHRcdGh0bWwgKz0gXCI8c3BhbiBjbGFzcz0ndWktZGF0ZXBpY2tlci15ZWFyJz5cIiArIGRyYXdZZWFyICsgXCI8L3NwYW4+XCI7XG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIGRldGVybWluZSByYW5nZSBvZiB5ZWFycyB0byBkaXNwbGF5XG5cdFx0XHRcdHllYXJzID0gdGhpcy5fZ2V0KCBpbnN0LCBcInllYXJSYW5nZVwiICkuc3BsaXQoIFwiOlwiICk7XG5cdFx0XHRcdHRoaXNZZWFyID0gbmV3IERhdGUoKS5nZXRGdWxsWWVhcigpO1xuXHRcdFx0XHRkZXRlcm1pbmVZZWFyID0gZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0XHRcdHZhciB5ZWFyID0gKCB2YWx1ZS5tYXRjaCggL2NbK1xcLV0uKi8gKSA/IGRyYXdZZWFyICsgcGFyc2VJbnQoIHZhbHVlLnN1YnN0cmluZyggMSApLCAxMCApIDpcblx0XHRcdFx0XHRcdCggdmFsdWUubWF0Y2goIC9bK1xcLV0uKi8gKSA/IHRoaXNZZWFyICsgcGFyc2VJbnQoIHZhbHVlLCAxMCApIDpcblx0XHRcdFx0XHRcdHBhcnNlSW50KCB2YWx1ZSwgMTAgKSApICk7XG5cdFx0XHRcdFx0cmV0dXJuICggaXNOYU4oIHllYXIgKSA/IHRoaXNZZWFyIDogeWVhciApO1xuXHRcdFx0XHR9O1xuXHRcdFx0XHR5ZWFyID0gZGV0ZXJtaW5lWWVhciggeWVhcnNbIDAgXSApO1xuXHRcdFx0XHRlbmRZZWFyID0gTWF0aC5tYXgoIHllYXIsIGRldGVybWluZVllYXIoIHllYXJzWyAxIF0gfHwgXCJcIiApICk7XG5cdFx0XHRcdHllYXIgPSAoIG1pbkRhdGUgPyBNYXRoLm1heCggeWVhciwgbWluRGF0ZS5nZXRGdWxsWWVhcigpICkgOiB5ZWFyICk7XG5cdFx0XHRcdGVuZFllYXIgPSAoIG1heERhdGUgPyBNYXRoLm1pbiggZW5kWWVhciwgbWF4RGF0ZS5nZXRGdWxsWWVhcigpICkgOiBlbmRZZWFyICk7XG5cdFx0XHRcdGluc3QueWVhcnNodG1sICs9IFwiPHNlbGVjdCBjbGFzcz0ndWktZGF0ZXBpY2tlci15ZWFyJyBkYXRhLWhhbmRsZXI9J3NlbGVjdFllYXInIGRhdGEtZXZlbnQ9J2NoYW5nZSc+XCI7XG5cdFx0XHRcdGZvciAoIDsgeWVhciA8PSBlbmRZZWFyOyB5ZWFyKysgKSB7XG5cdFx0XHRcdFx0aW5zdC55ZWFyc2h0bWwgKz0gXCI8b3B0aW9uIHZhbHVlPSdcIiArIHllYXIgKyBcIidcIiArXG5cdFx0XHRcdFx0XHQoIHllYXIgPT09IGRyYXdZZWFyID8gXCIgc2VsZWN0ZWQ9J3NlbGVjdGVkJ1wiIDogXCJcIiApICtcblx0XHRcdFx0XHRcdFwiPlwiICsgeWVhciArIFwiPC9vcHRpb24+XCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0aW5zdC55ZWFyc2h0bWwgKz0gXCI8L3NlbGVjdD5cIjtcblxuXHRcdFx0XHRodG1sICs9IGluc3QueWVhcnNodG1sO1xuXHRcdFx0XHRpbnN0LnllYXJzaHRtbCA9IG51bGw7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aHRtbCArPSB0aGlzLl9nZXQoIGluc3QsIFwieWVhclN1ZmZpeFwiICk7XG5cdFx0aWYgKCBzaG93TW9udGhBZnRlclllYXIgKSB7XG5cdFx0XHRodG1sICs9ICggc2Vjb25kYXJ5IHx8ICEoIGNoYW5nZU1vbnRoICYmIGNoYW5nZVllYXIgKSA/IFwiJiN4YTA7XCIgOiBcIlwiICkgKyBtb250aEh0bWw7XG5cdFx0fVxuXHRcdGh0bWwgKz0gXCI8L2Rpdj5cIjsgLy8gQ2xvc2UgZGF0ZXBpY2tlcl9oZWFkZXJcblx0XHRyZXR1cm4gaHRtbDtcblx0fSxcblxuXHQvKiBBZGp1c3Qgb25lIG9mIHRoZSBkYXRlIHN1Yi1maWVsZHMuICovXG5cdF9hZGp1c3RJbnN0RGF0ZTogZnVuY3Rpb24oIGluc3QsIG9mZnNldCwgcGVyaW9kICkge1xuXHRcdHZhciB5ZWFyID0gaW5zdC5zZWxlY3RlZFllYXIgKyAoIHBlcmlvZCA9PT0gXCJZXCIgPyBvZmZzZXQgOiAwICksXG5cdFx0XHRtb250aCA9IGluc3Quc2VsZWN0ZWRNb250aCArICggcGVyaW9kID09PSBcIk1cIiA/IG9mZnNldCA6IDAgKSxcblx0XHRcdGRheSA9IE1hdGgubWluKCBpbnN0LnNlbGVjdGVkRGF5LCB0aGlzLl9nZXREYXlzSW5Nb250aCggeWVhciwgbW9udGggKSApICsgKCBwZXJpb2QgPT09IFwiRFwiID8gb2Zmc2V0IDogMCApLFxuXHRcdFx0ZGF0ZSA9IHRoaXMuX3Jlc3RyaWN0TWluTWF4KCBpbnN0LCB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIHllYXIsIG1vbnRoLCBkYXkgKSApICk7XG5cblx0XHRpbnN0LnNlbGVjdGVkRGF5ID0gZGF0ZS5nZXREYXRlKCk7XG5cdFx0aW5zdC5kcmF3TW9udGggPSBpbnN0LnNlbGVjdGVkTW9udGggPSBkYXRlLmdldE1vbnRoKCk7XG5cdFx0aW5zdC5kcmF3WWVhciA9IGluc3Quc2VsZWN0ZWRZZWFyID0gZGF0ZS5nZXRGdWxsWWVhcigpO1xuXHRcdGlmICggcGVyaW9kID09PSBcIk1cIiB8fCBwZXJpb2QgPT09IFwiWVwiICkge1xuXHRcdFx0dGhpcy5fbm90aWZ5Q2hhbmdlKCBpbnN0ICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIEVuc3VyZSBhIGRhdGUgaXMgd2l0aGluIGFueSBtaW4vbWF4IGJvdW5kcy4gKi9cblx0X3Jlc3RyaWN0TWluTWF4OiBmdW5jdGlvbiggaW5zdCwgZGF0ZSApIHtcblx0XHR2YXIgbWluRGF0ZSA9IHRoaXMuX2dldE1pbk1heERhdGUoIGluc3QsIFwibWluXCIgKSxcblx0XHRcdG1heERhdGUgPSB0aGlzLl9nZXRNaW5NYXhEYXRlKCBpbnN0LCBcIm1heFwiICksXG5cdFx0XHRuZXdEYXRlID0gKCBtaW5EYXRlICYmIGRhdGUgPCBtaW5EYXRlID8gbWluRGF0ZSA6IGRhdGUgKTtcblx0XHRyZXR1cm4gKCBtYXhEYXRlICYmIG5ld0RhdGUgPiBtYXhEYXRlID8gbWF4RGF0ZSA6IG5ld0RhdGUgKTtcblx0fSxcblxuXHQvKiBOb3RpZnkgY2hhbmdlIG9mIG1vbnRoL3llYXIuICovXG5cdF9ub3RpZnlDaGFuZ2U6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHZhciBvbkNoYW5nZSA9IHRoaXMuX2dldCggaW5zdCwgXCJvbkNoYW5nZU1vbnRoWWVhclwiICk7XG5cdFx0aWYgKCBvbkNoYW5nZSApIHtcblx0XHRcdG9uQ2hhbmdlLmFwcGx5KCAoIGluc3QuaW5wdXQgPyBpbnN0LmlucHV0WyAwIF0gOiBudWxsICksXG5cdFx0XHRcdFsgaW5zdC5zZWxlY3RlZFllYXIsIGluc3Quc2VsZWN0ZWRNb250aCArIDEsIGluc3QgXSApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBEZXRlcm1pbmUgdGhlIG51bWJlciBvZiBtb250aHMgdG8gc2hvdy4gKi9cblx0X2dldE51bWJlck9mTW9udGhzOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHR2YXIgbnVtTW9udGhzID0gdGhpcy5fZ2V0KCBpbnN0LCBcIm51bWJlck9mTW9udGhzXCIgKTtcblx0XHRyZXR1cm4gKCBudW1Nb250aHMgPT0gbnVsbCA/IFsgMSwgMSBdIDogKCB0eXBlb2YgbnVtTW9udGhzID09PSBcIm51bWJlclwiID8gWyAxLCBudW1Nb250aHMgXSA6IG51bU1vbnRocyApICk7XG5cdH0sXG5cblx0LyogRGV0ZXJtaW5lIHRoZSBjdXJyZW50IG1heGltdW0gZGF0ZSAtIGVuc3VyZSBubyB0aW1lIGNvbXBvbmVudHMgYXJlIHNldC4gKi9cblx0X2dldE1pbk1heERhdGU6IGZ1bmN0aW9uKCBpbnN0LCBtaW5NYXggKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2RldGVybWluZURhdGUoIGluc3QsIHRoaXMuX2dldCggaW5zdCwgbWluTWF4ICsgXCJEYXRlXCIgKSwgbnVsbCApO1xuXHR9LFxuXG5cdC8qIEZpbmQgdGhlIG51bWJlciBvZiBkYXlzIGluIGEgZ2l2ZW4gbW9udGguICovXG5cdF9nZXREYXlzSW5Nb250aDogZnVuY3Rpb24oIHllYXIsIG1vbnRoICkge1xuXHRcdHJldHVybiAzMiAtIHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggeWVhciwgbW9udGgsIDMyICkgKS5nZXREYXRlKCk7XG5cdH0sXG5cblx0LyogRmluZCB0aGUgZGF5IG9mIHRoZSB3ZWVrIG9mIHRoZSBmaXJzdCBvZiBhIG1vbnRoLiAqL1xuXHRfZ2V0Rmlyc3REYXlPZk1vbnRoOiBmdW5jdGlvbiggeWVhciwgbW9udGggKSB7XG5cdFx0cmV0dXJuIG5ldyBEYXRlKCB5ZWFyLCBtb250aCwgMSApLmdldERheSgpO1xuXHR9LFxuXG5cdC8qIERldGVybWluZXMgaWYgd2Ugc2hvdWxkIGFsbG93IGEgXCJuZXh0L3ByZXZcIiBtb250aCBkaXNwbGF5IGNoYW5nZS4gKi9cblx0X2NhbkFkanVzdE1vbnRoOiBmdW5jdGlvbiggaW5zdCwgb2Zmc2V0LCBjdXJZZWFyLCBjdXJNb250aCApIHtcblx0XHR2YXIgbnVtTW9udGhzID0gdGhpcy5fZ2V0TnVtYmVyT2ZNb250aHMoIGluc3QgKSxcblx0XHRcdGRhdGUgPSB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIGN1clllYXIsXG5cdFx0XHRjdXJNb250aCArICggb2Zmc2V0IDwgMCA/IG9mZnNldCA6IG51bU1vbnRoc1sgMCBdICogbnVtTW9udGhzWyAxIF0gKSwgMSApICk7XG5cblx0XHRpZiAoIG9mZnNldCA8IDAgKSB7XG5cdFx0XHRkYXRlLnNldERhdGUoIHRoaXMuX2dldERheXNJbk1vbnRoKCBkYXRlLmdldEZ1bGxZZWFyKCksIGRhdGUuZ2V0TW9udGgoKSApICk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLl9pc0luUmFuZ2UoIGluc3QsIGRhdGUgKTtcblx0fSxcblxuXHQvKiBJcyB0aGUgZ2l2ZW4gZGF0ZSBpbiB0aGUgYWNjZXB0ZWQgcmFuZ2U/ICovXG5cdF9pc0luUmFuZ2U6IGZ1bmN0aW9uKCBpbnN0LCBkYXRlICkge1xuXHRcdHZhciB5ZWFyU3BsaXQsIGN1cnJlbnRZZWFyLFxuXHRcdFx0bWluRGF0ZSA9IHRoaXMuX2dldE1pbk1heERhdGUoIGluc3QsIFwibWluXCIgKSxcblx0XHRcdG1heERhdGUgPSB0aGlzLl9nZXRNaW5NYXhEYXRlKCBpbnN0LCBcIm1heFwiICksXG5cdFx0XHRtaW5ZZWFyID0gbnVsbCxcblx0XHRcdG1heFllYXIgPSBudWxsLFxuXHRcdFx0eWVhcnMgPSB0aGlzLl9nZXQoIGluc3QsIFwieWVhclJhbmdlXCIgKTtcblx0XHRcdGlmICggeWVhcnMgKSB7XG5cdFx0XHRcdHllYXJTcGxpdCA9IHllYXJzLnNwbGl0KCBcIjpcIiApO1xuXHRcdFx0XHRjdXJyZW50WWVhciA9IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKTtcblx0XHRcdFx0bWluWWVhciA9IHBhcnNlSW50KCB5ZWFyU3BsaXRbIDAgXSwgMTAgKTtcblx0XHRcdFx0bWF4WWVhciA9IHBhcnNlSW50KCB5ZWFyU3BsaXRbIDEgXSwgMTAgKTtcblx0XHRcdFx0aWYgKCB5ZWFyU3BsaXRbIDAgXS5tYXRjaCggL1srXFwtXS4qLyApICkge1xuXHRcdFx0XHRcdG1pblllYXIgKz0gY3VycmVudFllYXI7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCB5ZWFyU3BsaXRbIDEgXS5tYXRjaCggL1srXFwtXS4qLyApICkge1xuXHRcdFx0XHRcdG1heFllYXIgKz0gY3VycmVudFllYXI7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdHJldHVybiAoICggIW1pbkRhdGUgfHwgZGF0ZS5nZXRUaW1lKCkgPj0gbWluRGF0ZS5nZXRUaW1lKCkgKSAmJlxuXHRcdFx0KCAhbWF4RGF0ZSB8fCBkYXRlLmdldFRpbWUoKSA8PSBtYXhEYXRlLmdldFRpbWUoKSApICYmXG5cdFx0XHQoICFtaW5ZZWFyIHx8IGRhdGUuZ2V0RnVsbFllYXIoKSA+PSBtaW5ZZWFyICkgJiZcblx0XHRcdCggIW1heFllYXIgfHwgZGF0ZS5nZXRGdWxsWWVhcigpIDw9IG1heFllYXIgKSApO1xuXHR9LFxuXG5cdC8qIFByb3ZpZGUgdGhlIGNvbmZpZ3VyYXRpb24gc2V0dGluZ3MgZm9yIGZvcm1hdHRpbmcvcGFyc2luZy4gKi9cblx0X2dldEZvcm1hdENvbmZpZzogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0dmFyIHNob3J0WWVhckN1dG9mZiA9IHRoaXMuX2dldCggaW5zdCwgXCJzaG9ydFllYXJDdXRvZmZcIiApO1xuXHRcdHNob3J0WWVhckN1dG9mZiA9ICggdHlwZW9mIHNob3J0WWVhckN1dG9mZiAhPT0gXCJzdHJpbmdcIiA/IHNob3J0WWVhckN1dG9mZiA6XG5cdFx0XHRuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCkgJSAxMDAgKyBwYXJzZUludCggc2hvcnRZZWFyQ3V0b2ZmLCAxMCApICk7XG5cdFx0cmV0dXJuIHsgc2hvcnRZZWFyQ3V0b2ZmOiBzaG9ydFllYXJDdXRvZmYsXG5cdFx0XHRkYXlOYW1lc1Nob3J0OiB0aGlzLl9nZXQoIGluc3QsIFwiZGF5TmFtZXNTaG9ydFwiICksIGRheU5hbWVzOiB0aGlzLl9nZXQoIGluc3QsIFwiZGF5TmFtZXNcIiApLFxuXHRcdFx0bW9udGhOYW1lc1Nob3J0OiB0aGlzLl9nZXQoIGluc3QsIFwibW9udGhOYW1lc1Nob3J0XCIgKSwgbW9udGhOYW1lczogdGhpcy5fZ2V0KCBpbnN0LCBcIm1vbnRoTmFtZXNcIiApIH07XG5cdH0sXG5cblx0LyogRm9ybWF0IHRoZSBnaXZlbiBkYXRlIGZvciBkaXNwbGF5LiAqL1xuXHRfZm9ybWF0RGF0ZTogZnVuY3Rpb24oIGluc3QsIGRheSwgbW9udGgsIHllYXIgKSB7XG5cdFx0aWYgKCAhZGF5ICkge1xuXHRcdFx0aW5zdC5jdXJyZW50RGF5ID0gaW5zdC5zZWxlY3RlZERheTtcblx0XHRcdGluc3QuY3VycmVudE1vbnRoID0gaW5zdC5zZWxlY3RlZE1vbnRoO1xuXHRcdFx0aW5zdC5jdXJyZW50WWVhciA9IGluc3Quc2VsZWN0ZWRZZWFyO1xuXHRcdH1cblx0XHR2YXIgZGF0ZSA9ICggZGF5ID8gKCB0eXBlb2YgZGF5ID09PSBcIm9iamVjdFwiID8gZGF5IDpcblx0XHRcdHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggeWVhciwgbW9udGgsIGRheSApICkgKSA6XG5cdFx0XHR0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIGluc3QuY3VycmVudFllYXIsIGluc3QuY3VycmVudE1vbnRoLCBpbnN0LmN1cnJlbnREYXkgKSApICk7XG5cdFx0cmV0dXJuIHRoaXMuZm9ybWF0RGF0ZSggdGhpcy5fZ2V0KCBpbnN0LCBcImRhdGVGb3JtYXRcIiApLCBkYXRlLCB0aGlzLl9nZXRGb3JtYXRDb25maWcoIGluc3QgKSApO1xuXHR9XG59ICk7XG5cbi8qXG4gKiBCaW5kIGhvdmVyIGV2ZW50cyBmb3IgZGF0ZXBpY2tlciBlbGVtZW50cy5cbiAqIERvbmUgdmlhIGRlbGVnYXRlIHNvIHRoZSBiaW5kaW5nIG9ubHkgb2NjdXJzIG9uY2UgaW4gdGhlIGxpZmV0aW1lIG9mIHRoZSBwYXJlbnQgZGl2LlxuICogR2xvYmFsIGRhdGVwaWNrZXJfaW5zdEFjdGl2ZSwgc2V0IGJ5IF91cGRhdGVEYXRlcGlja2VyIGFsbG93cyB0aGUgaGFuZGxlcnMgdG8gZmluZCB0aGVpciB3YXkgYmFjayB0byB0aGUgYWN0aXZlIHBpY2tlci5cbiAqL1xuZnVuY3Rpb24gZGF0ZXBpY2tlcl9iaW5kSG92ZXIoIGRwRGl2ICkge1xuXHR2YXIgc2VsZWN0b3IgPSBcImJ1dHRvbiwgLnVpLWRhdGVwaWNrZXItcHJldiwgLnVpLWRhdGVwaWNrZXItbmV4dCwgLnVpLWRhdGVwaWNrZXItY2FsZW5kYXIgdGQgYVwiO1xuXHRyZXR1cm4gZHBEaXYub24oIFwibW91c2VvdXRcIiwgc2VsZWN0b3IsIGZ1bmN0aW9uKCkge1xuXHRcdFx0JCggdGhpcyApLnJlbW92ZUNsYXNzKCBcInVpLXN0YXRlLWhvdmVyXCIgKTtcblx0XHRcdGlmICggdGhpcy5jbGFzc05hbWUuaW5kZXhPZiggXCJ1aS1kYXRlcGlja2VyLXByZXZcIiApICE9PSAtMSApIHtcblx0XHRcdFx0JCggdGhpcyApLnJlbW92ZUNsYXNzKCBcInVpLWRhdGVwaWNrZXItcHJldi1ob3ZlclwiICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIHRoaXMuY2xhc3NOYW1lLmluZGV4T2YoIFwidWktZGF0ZXBpY2tlci1uZXh0XCIgKSAhPT0gLTEgKSB7XG5cdFx0XHRcdCQoIHRoaXMgKS5yZW1vdmVDbGFzcyggXCJ1aS1kYXRlcGlja2VyLW5leHQtaG92ZXJcIiApO1xuXHRcdFx0fVxuXHRcdH0gKVxuXHRcdC5vbiggXCJtb3VzZW92ZXJcIiwgc2VsZWN0b3IsIGRhdGVwaWNrZXJfaGFuZGxlTW91c2VvdmVyICk7XG59XG5cbmZ1bmN0aW9uIGRhdGVwaWNrZXJfaGFuZGxlTW91c2VvdmVyKCkge1xuXHRpZiAoICEkLmRhdGVwaWNrZXIuX2lzRGlzYWJsZWREYXRlcGlja2VyKCBkYXRlcGlja2VyX2luc3RBY3RpdmUuaW5saW5lID8gZGF0ZXBpY2tlcl9pbnN0QWN0aXZlLmRwRGl2LnBhcmVudCgpWyAwIF0gOiBkYXRlcGlja2VyX2luc3RBY3RpdmUuaW5wdXRbIDAgXSApICkge1xuXHRcdCQoIHRoaXMgKS5wYXJlbnRzKCBcIi51aS1kYXRlcGlja2VyLWNhbGVuZGFyXCIgKS5maW5kKCBcImFcIiApLnJlbW92ZUNsYXNzKCBcInVpLXN0YXRlLWhvdmVyXCIgKTtcblx0XHQkKCB0aGlzICkuYWRkQ2xhc3MoIFwidWktc3RhdGUtaG92ZXJcIiApO1xuXHRcdGlmICggdGhpcy5jbGFzc05hbWUuaW5kZXhPZiggXCJ1aS1kYXRlcGlja2VyLXByZXZcIiApICE9PSAtMSApIHtcblx0XHRcdCQoIHRoaXMgKS5hZGRDbGFzcyggXCJ1aS1kYXRlcGlja2VyLXByZXYtaG92ZXJcIiApO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuY2xhc3NOYW1lLmluZGV4T2YoIFwidWktZGF0ZXBpY2tlci1uZXh0XCIgKSAhPT0gLTEgKSB7XG5cdFx0XHQkKCB0aGlzICkuYWRkQ2xhc3MoIFwidWktZGF0ZXBpY2tlci1uZXh0LWhvdmVyXCIgKTtcblx0XHR9XG5cdH1cbn1cblxuLyogalF1ZXJ5IGV4dGVuZCBub3cgaWdub3JlcyBudWxscyEgKi9cbmZ1bmN0aW9uIGRhdGVwaWNrZXJfZXh0ZW5kUmVtb3ZlKCB0YXJnZXQsIHByb3BzICkge1xuXHQkLmV4dGVuZCggdGFyZ2V0LCBwcm9wcyApO1xuXHRmb3IgKCB2YXIgbmFtZSBpbiBwcm9wcyApIHtcblx0XHRpZiAoIHByb3BzWyBuYW1lIF0gPT0gbnVsbCApIHtcblx0XHRcdHRhcmdldFsgbmFtZSBdID0gcHJvcHNbIG5hbWUgXTtcblx0XHR9XG5cdH1cblx0cmV0dXJuIHRhcmdldDtcbn1cblxuLyogSW52b2tlIHRoZSBkYXRlcGlja2VyIGZ1bmN0aW9uYWxpdHkuXG4gICBAcGFyYW0gIG9wdGlvbnMgIHN0cmluZyAtIGEgY29tbWFuZCwgb3B0aW9uYWxseSBmb2xsb3dlZCBieSBhZGRpdGlvbmFsIHBhcmFtZXRlcnMgb3Jcblx0XHRcdFx0XHRPYmplY3QgLSBzZXR0aW5ncyBmb3IgYXR0YWNoaW5nIG5ldyBkYXRlcGlja2VyIGZ1bmN0aW9uYWxpdHlcbiAgIEByZXR1cm4gIGpRdWVyeSBvYmplY3QgKi9cbiQuZm4uZGF0ZXBpY2tlciA9IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXG5cdC8qIFZlcmlmeSBhbiBlbXB0eSBjb2xsZWN0aW9uIHdhc24ndCBwYXNzZWQgLSBGaXhlcyAjNjk3NiAqL1xuXHRpZiAoICF0aGlzLmxlbmd0aCApIHtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qIEluaXRpYWxpc2UgdGhlIGRhdGUgcGlja2VyLiAqL1xuXHRpZiAoICEkLmRhdGVwaWNrZXIuaW5pdGlhbGl6ZWQgKSB7XG5cdFx0JCggZG9jdW1lbnQgKS5vbiggXCJtb3VzZWRvd25cIiwgJC5kYXRlcGlja2VyLl9jaGVja0V4dGVybmFsQ2xpY2sgKTtcblx0XHQkLmRhdGVwaWNrZXIuaW5pdGlhbGl6ZWQgPSB0cnVlO1xuXHR9XG5cblx0LyogQXBwZW5kIGRhdGVwaWNrZXIgbWFpbiBjb250YWluZXIgdG8gYm9keSBpZiBub3QgZXhpc3QuICovXG5cdGlmICggJCggXCIjXCIgKyAkLmRhdGVwaWNrZXIuX21haW5EaXZJZCApLmxlbmd0aCA9PT0gMCApIHtcblx0XHQkKCBcImJvZHlcIiApLmFwcGVuZCggJC5kYXRlcGlja2VyLmRwRGl2ICk7XG5cdH1cblxuXHR2YXIgb3RoZXJBcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoIGFyZ3VtZW50cywgMSApO1xuXHRpZiAoIHR5cGVvZiBvcHRpb25zID09PSBcInN0cmluZ1wiICYmICggb3B0aW9ucyA9PT0gXCJpc0Rpc2FibGVkXCIgfHwgb3B0aW9ucyA9PT0gXCJnZXREYXRlXCIgfHwgb3B0aW9ucyA9PT0gXCJ3aWRnZXRcIiApICkge1xuXHRcdHJldHVybiAkLmRhdGVwaWNrZXJbIFwiX1wiICsgb3B0aW9ucyArIFwiRGF0ZXBpY2tlclwiIF0uXG5cdFx0XHRhcHBseSggJC5kYXRlcGlja2VyLCBbIHRoaXNbIDAgXSBdLmNvbmNhdCggb3RoZXJBcmdzICkgKTtcblx0fVxuXHRpZiAoIG9wdGlvbnMgPT09IFwib3B0aW9uXCIgJiYgYXJndW1lbnRzLmxlbmd0aCA9PT0gMiAmJiB0eXBlb2YgYXJndW1lbnRzWyAxIF0gPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0cmV0dXJuICQuZGF0ZXBpY2tlclsgXCJfXCIgKyBvcHRpb25zICsgXCJEYXRlcGlja2VyXCIgXS5cblx0XHRcdGFwcGx5KCAkLmRhdGVwaWNrZXIsIFsgdGhpc1sgMCBdIF0uY29uY2F0KCBvdGhlckFyZ3MgKSApO1xuXHR9XG5cdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdHR5cGVvZiBvcHRpb25zID09PSBcInN0cmluZ1wiID9cblx0XHRcdCQuZGF0ZXBpY2tlclsgXCJfXCIgKyBvcHRpb25zICsgXCJEYXRlcGlja2VyXCIgXS5cblx0XHRcdFx0YXBwbHkoICQuZGF0ZXBpY2tlciwgWyB0aGlzIF0uY29uY2F0KCBvdGhlckFyZ3MgKSApIDpcblx0XHRcdCQuZGF0ZXBpY2tlci5fYXR0YWNoRGF0ZXBpY2tlciggdGhpcywgb3B0aW9ucyApO1xuXHR9ICk7XG59O1xuXG4kLmRhdGVwaWNrZXIgPSBuZXcgRGF0ZXBpY2tlcigpOyAvLyBzaW5nbGV0b24gaW5zdGFuY2VcbiQuZGF0ZXBpY2tlci5pbml0aWFsaXplZCA9IGZhbHNlO1xuJC5kYXRlcGlja2VyLnV1aWQgPSBuZXcgRGF0ZSgpLmdldFRpbWUoKTtcbiQuZGF0ZXBpY2tlci52ZXJzaW9uID0gXCIxLjEyLjFcIjtcblxudmFyIHdpZGdldHNEYXRlcGlja2VyID0gJC5kYXRlcGlja2VyO1xuXG5cblxuXG4vLyBUaGlzIGZpbGUgaXMgZGVwcmVjYXRlZFxudmFyIGllID0gJC51aS5pZSA9ICEhL21zaWUgW1xcdy5dKy8uZXhlYyggbmF2aWdhdG9yLnVzZXJBZ2VudC50b0xvd2VyQ2FzZSgpICk7XG5cbi8qIVxuICogalF1ZXJ5IFVJIE1vdXNlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBNb3VzZVxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IEFic3RyYWN0cyBtb3VzZS1iYXNlZCBpbnRlcmFjdGlvbnMgdG8gYXNzaXN0IGluIGNyZWF0aW5nIGNlcnRhaW4gd2lkZ2V0cy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9tb3VzZS9cblxuXG5cbnZhciBtb3VzZUhhbmRsZWQgPSBmYWxzZTtcbiQoIGRvY3VtZW50ICkub24oIFwibW91c2V1cFwiLCBmdW5jdGlvbigpIHtcblx0bW91c2VIYW5kbGVkID0gZmFsc2U7XG59ICk7XG5cbnZhciB3aWRnZXRzTW91c2UgPSAkLndpZGdldCggXCJ1aS5tb3VzZVwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRjYW5jZWw6IFwiaW5wdXQsIHRleHRhcmVhLCBidXR0b24sIHNlbGVjdCwgb3B0aW9uXCIsXG5cdFx0ZGlzdGFuY2U6IDEsXG5cdFx0ZGVsYXk6IDBcblx0fSxcblx0X21vdXNlSW5pdDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0dGhpcy5lbGVtZW50XG5cdFx0XHQub24oIFwibW91c2Vkb3duLlwiICsgdGhpcy53aWRnZXROYW1lLCBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHJldHVybiB0aGF0Ll9tb3VzZURvd24oIGV2ZW50ICk7XG5cdFx0XHR9IClcblx0XHRcdC5vbiggXCJjbGljay5cIiArIHRoaXMud2lkZ2V0TmFtZSwgZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoIHRydWUgPT09ICQuZGF0YSggZXZlbnQudGFyZ2V0LCB0aGF0LndpZGdldE5hbWUgKyBcIi5wcmV2ZW50Q2xpY2tFdmVudFwiICkgKSB7XG5cdFx0XHRcdFx0JC5yZW1vdmVEYXRhKCBldmVudC50YXJnZXQsIHRoYXQud2lkZ2V0TmFtZSArIFwiLnByZXZlbnRDbGlja0V2ZW50XCIgKTtcblx0XHRcdFx0XHRldmVudC5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblxuXHRcdHRoaXMuc3RhcnRlZCA9IGZhbHNlO1xuXHR9LFxuXG5cdC8vIFRPRE86IG1ha2Ugc3VyZSBkZXN0cm95aW5nIG9uZSBpbnN0YW5jZSBvZiBtb3VzZSBkb2Vzbid0IG1lc3Mgd2l0aFxuXHQvLyBvdGhlciBpbnN0YW5jZXMgb2YgbW91c2Vcblx0X21vdXNlRGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5lbGVtZW50Lm9mZiggXCIuXCIgKyB0aGlzLndpZGdldE5hbWUgKTtcblx0XHRpZiAoIHRoaXMuX21vdXNlTW92ZURlbGVnYXRlICkge1xuXHRcdFx0dGhpcy5kb2N1bWVudFxuXHRcdFx0XHQub2ZmKCBcIm1vdXNlbW92ZS5cIiArIHRoaXMud2lkZ2V0TmFtZSwgdGhpcy5fbW91c2VNb3ZlRGVsZWdhdGUgKVxuXHRcdFx0XHQub2ZmKCBcIm1vdXNldXAuXCIgKyB0aGlzLndpZGdldE5hbWUsIHRoaXMuX21vdXNlVXBEZWxlZ2F0ZSApO1xuXHRcdH1cblx0fSxcblxuXHRfbW91c2VEb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHQvLyBkb24ndCBsZXQgbW9yZSB0aGFuIG9uZSB3aWRnZXQgaGFuZGxlIG1vdXNlU3RhcnRcblx0XHRpZiAoIG1vdXNlSGFuZGxlZCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLl9tb3VzZU1vdmVkID0gZmFsc2U7XG5cblx0XHQvLyBXZSBtYXkgaGF2ZSBtaXNzZWQgbW91c2V1cCAob3V0IG9mIHdpbmRvdylcblx0XHQoIHRoaXMuX21vdXNlU3RhcnRlZCAmJiB0aGlzLl9tb3VzZVVwKCBldmVudCApICk7XG5cblx0XHR0aGlzLl9tb3VzZURvd25FdmVudCA9IGV2ZW50O1xuXG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0YnRuSXNMZWZ0ID0gKCBldmVudC53aGljaCA9PT0gMSApLFxuXG5cdFx0XHQvLyBldmVudC50YXJnZXQubm9kZU5hbWUgd29ya3MgYXJvdW5kIGEgYnVnIGluIElFIDggd2l0aFxuXHRcdFx0Ly8gZGlzYWJsZWQgaW5wdXRzICgjNzYyMClcblx0XHRcdGVsSXNDYW5jZWwgPSAoIHR5cGVvZiB0aGlzLm9wdGlvbnMuY2FuY2VsID09PSBcInN0cmluZ1wiICYmIGV2ZW50LnRhcmdldC5ub2RlTmFtZSA/XG5cdFx0XHRcdCQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIHRoaXMub3B0aW9ucy5jYW5jZWwgKS5sZW5ndGggOiBmYWxzZSApO1xuXHRcdGlmICggIWJ0bklzTGVmdCB8fCBlbElzQ2FuY2VsIHx8ICF0aGlzLl9tb3VzZUNhcHR1cmUoIGV2ZW50ICkgKSB7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cblx0XHR0aGlzLm1vdXNlRGVsYXlNZXQgPSAhdGhpcy5vcHRpb25zLmRlbGF5O1xuXHRcdGlmICggIXRoaXMubW91c2VEZWxheU1ldCApIHtcblx0XHRcdHRoaXMuX21vdXNlRGVsYXlUaW1lciA9IHNldFRpbWVvdXQoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGF0Lm1vdXNlRGVsYXlNZXQgPSB0cnVlO1xuXHRcdFx0fSwgdGhpcy5vcHRpb25zLmRlbGF5ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9tb3VzZURpc3RhbmNlTWV0KCBldmVudCApICYmIHRoaXMuX21vdXNlRGVsYXlNZXQoIGV2ZW50ICkgKSB7XG5cdFx0XHR0aGlzLl9tb3VzZVN0YXJ0ZWQgPSAoIHRoaXMuX21vdXNlU3RhcnQoIGV2ZW50ICkgIT09IGZhbHNlICk7XG5cdFx0XHRpZiAoICF0aGlzLl9tb3VzZVN0YXJ0ZWQgKSB7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIENsaWNrIGV2ZW50IG1heSBuZXZlciBoYXZlIGZpcmVkIChHZWNrbyAmIE9wZXJhKVxuXHRcdGlmICggdHJ1ZSA9PT0gJC5kYXRhKCBldmVudC50YXJnZXQsIHRoaXMud2lkZ2V0TmFtZSArIFwiLnByZXZlbnRDbGlja0V2ZW50XCIgKSApIHtcblx0XHRcdCQucmVtb3ZlRGF0YSggZXZlbnQudGFyZ2V0LCB0aGlzLndpZGdldE5hbWUgKyBcIi5wcmV2ZW50Q2xpY2tFdmVudFwiICk7XG5cdFx0fVxuXG5cdFx0Ly8gVGhlc2UgZGVsZWdhdGVzIGFyZSByZXF1aXJlZCB0byBrZWVwIGNvbnRleHRcblx0XHR0aGlzLl9tb3VzZU1vdmVEZWxlZ2F0ZSA9IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHJldHVybiB0aGF0Ll9tb3VzZU1vdmUoIGV2ZW50ICk7XG5cdFx0fTtcblx0XHR0aGlzLl9tb3VzZVVwRGVsZWdhdGUgPSBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRyZXR1cm4gdGhhdC5fbW91c2VVcCggZXZlbnQgKTtcblx0XHR9O1xuXG5cdFx0dGhpcy5kb2N1bWVudFxuXHRcdFx0Lm9uKCBcIm1vdXNlbW92ZS5cIiArIHRoaXMud2lkZ2V0TmFtZSwgdGhpcy5fbW91c2VNb3ZlRGVsZWdhdGUgKVxuXHRcdFx0Lm9uKCBcIm1vdXNldXAuXCIgKyB0aGlzLndpZGdldE5hbWUsIHRoaXMuX21vdXNlVXBEZWxlZ2F0ZSApO1xuXG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuXHRcdG1vdXNlSGFuZGxlZCA9IHRydWU7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0X21vdXNlTW92ZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0Ly8gT25seSBjaGVjayBmb3IgbW91c2V1cHMgb3V0c2lkZSB0aGUgZG9jdW1lbnQgaWYgeW91J3ZlIG1vdmVkIGluc2lkZSB0aGUgZG9jdW1lbnRcblx0XHQvLyBhdCBsZWFzdCBvbmNlLiBUaGlzIHByZXZlbnRzIHRoZSBmaXJpbmcgb2YgbW91c2V1cCBpbiB0aGUgY2FzZSBvZiBJRTw5LCB3aGljaCB3aWxsXG5cdFx0Ly8gZmlyZSBhIG1vdXNlbW92ZSBldmVudCBpZiBjb250ZW50IGlzIHBsYWNlZCB1bmRlciB0aGUgY3Vyc29yLiBTZWUgIzc3Nzhcblx0XHQvLyBTdXBwb3J0OiBJRSA8OVxuXHRcdGlmICggdGhpcy5fbW91c2VNb3ZlZCApIHtcblxuXHRcdFx0Ly8gSUUgbW91c2V1cCBjaGVjayAtIG1vdXNldXAgaGFwcGVuZWQgd2hlbiBtb3VzZSB3YXMgb3V0IG9mIHdpbmRvd1xuXHRcdFx0aWYgKCAkLnVpLmllICYmICggIWRvY3VtZW50LmRvY3VtZW50TW9kZSB8fCBkb2N1bWVudC5kb2N1bWVudE1vZGUgPCA5ICkgJiZcblx0XHRcdFx0XHQhZXZlbnQuYnV0dG9uICkge1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5fbW91c2VVcCggZXZlbnQgKTtcblxuXHRcdFx0Ly8gSWZyYW1lIG1vdXNldXAgY2hlY2sgLSBtb3VzZXVwIG9jY3VycmVkIGluIGFub3RoZXIgZG9jdW1lbnRcblx0XHRcdH0gZWxzZSBpZiAoICFldmVudC53aGljaCApIHtcblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBTYWZhcmkgPD04IC0gOVxuXHRcdFx0XHQvLyBTYWZhcmkgc2V0cyB3aGljaCB0byAwIGlmIHlvdSBwcmVzcyBhbnkgb2YgdGhlIGZvbGxvd2luZyBrZXlzXG5cdFx0XHRcdC8vIGR1cmluZyBhIGRyYWcgKCMxNDQ2MSlcblx0XHRcdFx0aWYgKCBldmVudC5vcmlnaW5hbEV2ZW50LmFsdEtleSB8fCBldmVudC5vcmlnaW5hbEV2ZW50LmN0cmxLZXkgfHxcblx0XHRcdFx0XHRcdGV2ZW50Lm9yaWdpbmFsRXZlbnQubWV0YUtleSB8fCBldmVudC5vcmlnaW5hbEV2ZW50LnNoaWZ0S2V5ICkge1xuXHRcdFx0XHRcdHRoaXMuaWdub3JlTWlzc2luZ1doaWNoID0gdHJ1ZTtcblx0XHRcdFx0fSBlbHNlIGlmICggIXRoaXMuaWdub3JlTWlzc2luZ1doaWNoICkge1xuXHRcdFx0XHRcdHJldHVybiB0aGlzLl9tb3VzZVVwKCBldmVudCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBldmVudC53aGljaCB8fCBldmVudC5idXR0b24gKSB7XG5cdFx0XHR0aGlzLl9tb3VzZU1vdmVkID0gdHJ1ZTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX21vdXNlU3RhcnRlZCApIHtcblx0XHRcdHRoaXMuX21vdXNlRHJhZyggZXZlbnQgKTtcblx0XHRcdHJldHVybiBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fbW91c2VEaXN0YW5jZU1ldCggZXZlbnQgKSAmJiB0aGlzLl9tb3VzZURlbGF5TWV0KCBldmVudCApICkge1xuXHRcdFx0dGhpcy5fbW91c2VTdGFydGVkID1cblx0XHRcdFx0KCB0aGlzLl9tb3VzZVN0YXJ0KCB0aGlzLl9tb3VzZURvd25FdmVudCwgZXZlbnQgKSAhPT0gZmFsc2UgKTtcblx0XHRcdCggdGhpcy5fbW91c2VTdGFydGVkID8gdGhpcy5fbW91c2VEcmFnKCBldmVudCApIDogdGhpcy5fbW91c2VVcCggZXZlbnQgKSApO1xuXHRcdH1cblxuXHRcdHJldHVybiAhdGhpcy5fbW91c2VTdGFydGVkO1xuXHR9LFxuXG5cdF9tb3VzZVVwOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dGhpcy5kb2N1bWVudFxuXHRcdFx0Lm9mZiggXCJtb3VzZW1vdmUuXCIgKyB0aGlzLndpZGdldE5hbWUsIHRoaXMuX21vdXNlTW92ZURlbGVnYXRlIClcblx0XHRcdC5vZmYoIFwibW91c2V1cC5cIiArIHRoaXMud2lkZ2V0TmFtZSwgdGhpcy5fbW91c2VVcERlbGVnYXRlICk7XG5cblx0XHRpZiAoIHRoaXMuX21vdXNlU3RhcnRlZCApIHtcblx0XHRcdHRoaXMuX21vdXNlU3RhcnRlZCA9IGZhbHNlO1xuXG5cdFx0XHRpZiAoIGV2ZW50LnRhcmdldCA9PT0gdGhpcy5fbW91c2VEb3duRXZlbnQudGFyZ2V0ICkge1xuXHRcdFx0XHQkLmRhdGEoIGV2ZW50LnRhcmdldCwgdGhpcy53aWRnZXROYW1lICsgXCIucHJldmVudENsaWNrRXZlbnRcIiwgdHJ1ZSApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl9tb3VzZVN0b3AoIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9tb3VzZURlbGF5VGltZXIgKSB7XG5cdFx0XHRjbGVhclRpbWVvdXQoIHRoaXMuX21vdXNlRGVsYXlUaW1lciApO1xuXHRcdFx0ZGVsZXRlIHRoaXMuX21vdXNlRGVsYXlUaW1lcjtcblx0XHR9XG5cblx0XHR0aGlzLmlnbm9yZU1pc3NpbmdXaGljaCA9IGZhbHNlO1xuXHRcdG1vdXNlSGFuZGxlZCA9IGZhbHNlO1xuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdH0sXG5cblx0X21vdXNlRGlzdGFuY2VNZXQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRyZXR1cm4gKCBNYXRoLm1heChcblx0XHRcdFx0TWF0aC5hYnMoIHRoaXMuX21vdXNlRG93bkV2ZW50LnBhZ2VYIC0gZXZlbnQucGFnZVggKSxcblx0XHRcdFx0TWF0aC5hYnMoIHRoaXMuX21vdXNlRG93bkV2ZW50LnBhZ2VZIC0gZXZlbnQucGFnZVkgKVxuXHRcdFx0KSA+PSB0aGlzLm9wdGlvbnMuZGlzdGFuY2Vcblx0XHQpO1xuXHR9LFxuXG5cdF9tb3VzZURlbGF5TWV0OiBmdW5jdGlvbiggLyogZXZlbnQgKi8gKSB7XG5cdFx0cmV0dXJuIHRoaXMubW91c2VEZWxheU1ldDtcblx0fSxcblxuXHQvLyBUaGVzZSBhcmUgcGxhY2Vob2xkZXIgbWV0aG9kcywgdG8gYmUgb3ZlcnJpZGVuIGJ5IGV4dGVuZGluZyBwbHVnaW5cblx0X21vdXNlU3RhcnQ6IGZ1bmN0aW9uKCAvKiBldmVudCAqLyApIHt9LFxuXHRfbW91c2VEcmFnOiBmdW5jdGlvbiggLyogZXZlbnQgKi8gKSB7fSxcblx0X21vdXNlU3RvcDogZnVuY3Rpb24oIC8qIGV2ZW50ICovICkge30sXG5cdF9tb3VzZUNhcHR1cmU6IGZ1bmN0aW9uKCAvKiBldmVudCAqLyApIHsgcmV0dXJuIHRydWU7IH1cbn0gKTtcblxuXG5cblxuLy8gJC51aS5wbHVnaW4gaXMgZGVwcmVjYXRlZC4gVXNlICQud2lkZ2V0KCkgZXh0ZW5zaW9ucyBpbnN0ZWFkLlxudmFyIHBsdWdpbiA9ICQudWkucGx1Z2luID0ge1xuXHRhZGQ6IGZ1bmN0aW9uKCBtb2R1bGUsIG9wdGlvbiwgc2V0ICkge1xuXHRcdHZhciBpLFxuXHRcdFx0cHJvdG8gPSAkLnVpWyBtb2R1bGUgXS5wcm90b3R5cGU7XG5cdFx0Zm9yICggaSBpbiBzZXQgKSB7XG5cdFx0XHRwcm90by5wbHVnaW5zWyBpIF0gPSBwcm90by5wbHVnaW5zWyBpIF0gfHwgW107XG5cdFx0XHRwcm90by5wbHVnaW5zWyBpIF0ucHVzaCggWyBvcHRpb24sIHNldFsgaSBdIF0gKTtcblx0XHR9XG5cdH0sXG5cdGNhbGw6IGZ1bmN0aW9uKCBpbnN0YW5jZSwgbmFtZSwgYXJncywgYWxsb3dEaXNjb25uZWN0ZWQgKSB7XG5cdFx0dmFyIGksXG5cdFx0XHRzZXQgPSBpbnN0YW5jZS5wbHVnaW5zWyBuYW1lIF07XG5cblx0XHRpZiAoICFzZXQgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCAhYWxsb3dEaXNjb25uZWN0ZWQgJiYgKCAhaW5zdGFuY2UuZWxlbWVudFsgMCBdLnBhcmVudE5vZGUgfHxcblx0XHRcdFx0aW5zdGFuY2UuZWxlbWVudFsgMCBdLnBhcmVudE5vZGUubm9kZVR5cGUgPT09IDExICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Zm9yICggaSA9IDA7IGkgPCBzZXQubGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRpZiAoIGluc3RhbmNlLm9wdGlvbnNbIHNldFsgaSBdWyAwIF0gXSApIHtcblx0XHRcdFx0c2V0WyBpIF1bIDEgXS5hcHBseSggaW5zdGFuY2UuZWxlbWVudCwgYXJncyApO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufTtcblxuXG5cbnZhciBzYWZlQmx1ciA9ICQudWkuc2FmZUJsdXIgPSBmdW5jdGlvbiggZWxlbWVudCApIHtcblxuXHQvLyBTdXBwb3J0OiBJRTkgLSAxMCBvbmx5XG5cdC8vIElmIHRoZSA8Ym9keT4gaXMgYmx1cnJlZCwgSUUgd2lsbCBzd2l0Y2ggd2luZG93cywgc2VlICM5NDIwXG5cdGlmICggZWxlbWVudCAmJiBlbGVtZW50Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgIT09IFwiYm9keVwiICkge1xuXHRcdCQoIGVsZW1lbnQgKS50cmlnZ2VyKCBcImJsdXJcIiApO1xuXHR9XG59O1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIERyYWdnYWJsZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRHJhZ2dhYmxlXG4vLz4+Z3JvdXA6IEludGVyYWN0aW9uc1xuLy8+PmRlc2NyaXB0aW9uOiBFbmFibGVzIGRyYWdnaW5nIGZ1bmN0aW9uYWxpdHkgZm9yIGFueSBlbGVtZW50LlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2RyYWdnYWJsZS9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9kcmFnZ2FibGUvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvZHJhZ2dhYmxlLmNzc1xuXG5cblxuJC53aWRnZXQoIFwidWkuZHJhZ2dhYmxlXCIsICQudWkubW91c2UsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0d2lkZ2V0RXZlbnRQcmVmaXg6IFwiZHJhZ1wiLFxuXHRvcHRpb25zOiB7XG5cdFx0YWRkQ2xhc3NlczogdHJ1ZSxcblx0XHRhcHBlbmRUbzogXCJwYXJlbnRcIixcblx0XHRheGlzOiBmYWxzZSxcblx0XHRjb25uZWN0VG9Tb3J0YWJsZTogZmFsc2UsXG5cdFx0Y29udGFpbm1lbnQ6IGZhbHNlLFxuXHRcdGN1cnNvcjogXCJhdXRvXCIsXG5cdFx0Y3Vyc29yQXQ6IGZhbHNlLFxuXHRcdGdyaWQ6IGZhbHNlLFxuXHRcdGhhbmRsZTogZmFsc2UsXG5cdFx0aGVscGVyOiBcIm9yaWdpbmFsXCIsXG5cdFx0aWZyYW1lRml4OiBmYWxzZSxcblx0XHRvcGFjaXR5OiBmYWxzZSxcblx0XHRyZWZyZXNoUG9zaXRpb25zOiBmYWxzZSxcblx0XHRyZXZlcnQ6IGZhbHNlLFxuXHRcdHJldmVydER1cmF0aW9uOiA1MDAsXG5cdFx0c2NvcGU6IFwiZGVmYXVsdFwiLFxuXHRcdHNjcm9sbDogdHJ1ZSxcblx0XHRzY3JvbGxTZW5zaXRpdml0eTogMjAsXG5cdFx0c2Nyb2xsU3BlZWQ6IDIwLFxuXHRcdHNuYXA6IGZhbHNlLFxuXHRcdHNuYXBNb2RlOiBcImJvdGhcIixcblx0XHRzbmFwVG9sZXJhbmNlOiAyMCxcblx0XHRzdGFjazogZmFsc2UsXG5cdFx0ekluZGV4OiBmYWxzZSxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGRyYWc6IG51bGwsXG5cdFx0c3RhcnQ6IG51bGwsXG5cdFx0c3RvcDogbnVsbFxuXHR9LFxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmhlbHBlciA9PT0gXCJvcmlnaW5hbFwiICkge1xuXHRcdFx0dGhpcy5fc2V0UG9zaXRpb25SZWxhdGl2ZSgpO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5hZGRDbGFzc2VzICkge1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktZHJhZ2dhYmxlXCIgKTtcblx0XHR9XG5cdFx0dGhpcy5fc2V0SGFuZGxlQ2xhc3NOYW1lKCk7XG5cblx0XHR0aGlzLl9tb3VzZUluaXQoKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXHRcdGlmICgga2V5ID09PSBcImhhbmRsZVwiICkge1xuXHRcdFx0dGhpcy5fcmVtb3ZlSGFuZGxlQ2xhc3NOYW1lKCk7XG5cdFx0XHR0aGlzLl9zZXRIYW5kbGVDbGFzc05hbWUoKTtcblx0XHR9XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggKCB0aGlzLmhlbHBlciB8fCB0aGlzLmVsZW1lbnQgKS5pcyggXCIudWktZHJhZ2dhYmxlLWRyYWdnaW5nXCIgKSApIHtcblx0XHRcdHRoaXMuZGVzdHJveU9uQ2xlYXIgPSB0cnVlO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHR0aGlzLl9yZW1vdmVIYW5kbGVDbGFzc05hbWUoKTtcblx0XHR0aGlzLl9tb3VzZURlc3Ryb3koKTtcblx0fSxcblxuXHRfbW91c2VDYXB0dXJlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIG8gPSB0aGlzLm9wdGlvbnM7XG5cblx0XHQvLyBBbW9uZyBvdGhlcnMsIHByZXZlbnQgYSBkcmFnIG9uIGEgcmVzaXphYmxlLWhhbmRsZVxuXHRcdGlmICggdGhpcy5oZWxwZXIgfHwgby5kaXNhYmxlZCB8fFxuXHRcdFx0XHQkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCBcIi51aS1yZXNpemFibGUtaGFuZGxlXCIgKS5sZW5ndGggPiAwICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vUXVpdCBpZiB3ZSdyZSBub3Qgb24gYSB2YWxpZCBoYW5kbGVcblx0XHR0aGlzLmhhbmRsZSA9IHRoaXMuX2dldEhhbmRsZSggZXZlbnQgKTtcblx0XHRpZiAoICF0aGlzLmhhbmRsZSApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHR0aGlzLl9ibHVyQWN0aXZlRWxlbWVudCggZXZlbnQgKTtcblxuXHRcdHRoaXMuX2Jsb2NrRnJhbWVzKCBvLmlmcmFtZUZpeCA9PT0gdHJ1ZSA/IFwiaWZyYW1lXCIgOiBvLmlmcmFtZUZpeCApO1xuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fSxcblxuXHRfYmxvY2tGcmFtZXM6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHR0aGlzLmlmcmFtZUJsb2NrcyA9IHRoaXMuZG9jdW1lbnQuZmluZCggc2VsZWN0b3IgKS5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGlmcmFtZSA9ICQoIHRoaXMgKTtcblxuXHRcdFx0cmV0dXJuICQoIFwiPGRpdj5cIiApXG5cdFx0XHRcdC5jc3MoIFwicG9zaXRpb25cIiwgXCJhYnNvbHV0ZVwiIClcblx0XHRcdFx0LmFwcGVuZFRvKCBpZnJhbWUucGFyZW50KCkgKVxuXHRcdFx0XHQub3V0ZXJXaWR0aCggaWZyYW1lLm91dGVyV2lkdGgoKSApXG5cdFx0XHRcdC5vdXRlckhlaWdodCggaWZyYW1lLm91dGVySGVpZ2h0KCkgKVxuXHRcdFx0XHQub2Zmc2V0KCBpZnJhbWUub2Zmc2V0KCkgKVsgMCBdO1xuXHRcdH0gKTtcblx0fSxcblxuXHRfdW5ibG9ja0ZyYW1lczogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCB0aGlzLmlmcmFtZUJsb2NrcyApIHtcblx0XHRcdHRoaXMuaWZyYW1lQmxvY2tzLnJlbW92ZSgpO1xuXHRcdFx0ZGVsZXRlIHRoaXMuaWZyYW1lQmxvY2tzO1xuXHRcdH1cblx0fSxcblxuXHRfYmx1ckFjdGl2ZUVsZW1lbnQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgYWN0aXZlRWxlbWVudCA9ICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApLFxuXHRcdFx0dGFyZ2V0ID0gJCggZXZlbnQudGFyZ2V0ICk7XG5cblx0XHQvLyBEb24ndCBibHVyIGlmIHRoZSBldmVudCBvY2N1cnJlZCBvbiBhbiBlbGVtZW50IHRoYXQgaXMgd2l0aGluXG5cdFx0Ly8gdGhlIGN1cnJlbnRseSBmb2N1c2VkIGVsZW1lbnRcblx0XHQvLyBTZWUgIzEwNTI3LCAjMTI0NzJcblx0XHRpZiAoIHRhcmdldC5jbG9zZXN0KCBhY3RpdmVFbGVtZW50ICkubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEJsdXIgYW55IGVsZW1lbnQgdGhhdCBjdXJyZW50bHkgaGFzIGZvY3VzLCBzZWUgIzQyNjFcblx0XHQkLnVpLnNhZmVCbHVyKCBhY3RpdmVFbGVtZW50ICk7XG5cdH0sXG5cblx0X21vdXNlU3RhcnQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHZhciBvID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0Ly9DcmVhdGUgYW5kIGFwcGVuZCB0aGUgdmlzaWJsZSBoZWxwZXJcblx0XHR0aGlzLmhlbHBlciA9IHRoaXMuX2NyZWF0ZUhlbHBlciggZXZlbnQgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmhlbHBlciwgXCJ1aS1kcmFnZ2FibGUtZHJhZ2dpbmdcIiApO1xuXG5cdFx0Ly9DYWNoZSB0aGUgaGVscGVyIHNpemVcblx0XHR0aGlzLl9jYWNoZUhlbHBlclByb3BvcnRpb25zKCk7XG5cblx0XHQvL0lmIGRkbWFuYWdlciBpcyB1c2VkIGZvciBkcm9wcGFibGVzLCBzZXQgdGhlIGdsb2JhbCBkcmFnZ2FibGVcblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIuY3VycmVudCA9IHRoaXM7XG5cdFx0fVxuXG5cdFx0Lypcblx0XHQgKiAtIFBvc2l0aW9uIGdlbmVyYXRpb24gLVxuXHRcdCAqIFRoaXMgYmxvY2sgZ2VuZXJhdGVzIGV2ZXJ5dGhpbmcgcG9zaXRpb24gcmVsYXRlZCAtIGl0J3MgdGhlIGNvcmUgb2YgZHJhZ2dhYmxlcy5cblx0XHQgKi9cblxuXHRcdC8vQ2FjaGUgdGhlIG1hcmdpbnMgb2YgdGhlIG9yaWdpbmFsIGVsZW1lbnRcblx0XHR0aGlzLl9jYWNoZU1hcmdpbnMoKTtcblxuXHRcdC8vU3RvcmUgdGhlIGhlbHBlcidzIGNzcyBwb3NpdGlvblxuXHRcdHRoaXMuY3NzUG9zaXRpb24gPSB0aGlzLmhlbHBlci5jc3MoIFwicG9zaXRpb25cIiApO1xuXHRcdHRoaXMuc2Nyb2xsUGFyZW50ID0gdGhpcy5oZWxwZXIuc2Nyb2xsUGFyZW50KCB0cnVlICk7XG5cdFx0dGhpcy5vZmZzZXRQYXJlbnQgPSB0aGlzLmhlbHBlci5vZmZzZXRQYXJlbnQoKTtcblx0XHR0aGlzLmhhc0ZpeGVkQW5jZXN0b3IgPSB0aGlzLmhlbHBlci5wYXJlbnRzKCkuZmlsdGVyKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuICQoIHRoaXMgKS5jc3MoIFwicG9zaXRpb25cIiApID09PSBcImZpeGVkXCI7XG5cdFx0XHR9ICkubGVuZ3RoID4gMDtcblxuXHRcdC8vVGhlIGVsZW1lbnQncyBhYnNvbHV0ZSBwb3NpdGlvbiBvbiB0aGUgcGFnZSBtaW51cyBtYXJnaW5zXG5cdFx0dGhpcy5wb3NpdGlvbkFicyA9IHRoaXMuZWxlbWVudC5vZmZzZXQoKTtcblx0XHR0aGlzLl9yZWZyZXNoT2Zmc2V0cyggZXZlbnQgKTtcblxuXHRcdC8vR2VuZXJhdGUgdGhlIG9yaWdpbmFsIHBvc2l0aW9uXG5cdFx0dGhpcy5vcmlnaW5hbFBvc2l0aW9uID0gdGhpcy5wb3NpdGlvbiA9IHRoaXMuX2dlbmVyYXRlUG9zaXRpb24oIGV2ZW50LCBmYWxzZSApO1xuXHRcdHRoaXMub3JpZ2luYWxQYWdlWCA9IGV2ZW50LnBhZ2VYO1xuXHRcdHRoaXMub3JpZ2luYWxQYWdlWSA9IGV2ZW50LnBhZ2VZO1xuXG5cdFx0Ly9BZGp1c3QgdGhlIG1vdXNlIG9mZnNldCByZWxhdGl2ZSB0byB0aGUgaGVscGVyIGlmIFwiY3Vyc29yQXRcIiBpcyBzdXBwbGllZFxuXHRcdCggby5jdXJzb3JBdCAmJiB0aGlzLl9hZGp1c3RPZmZzZXRGcm9tSGVscGVyKCBvLmN1cnNvckF0ICkgKTtcblxuXHRcdC8vU2V0IGEgY29udGFpbm1lbnQgaWYgZ2l2ZW4gaW4gdGhlIG9wdGlvbnNcblx0XHR0aGlzLl9zZXRDb250YWlubWVudCgpO1xuXG5cdFx0Ly9UcmlnZ2VyIGV2ZW50ICsgY2FsbGJhY2tzXG5cdFx0aWYgKCB0aGlzLl90cmlnZ2VyKCBcInN0YXJ0XCIsIGV2ZW50ICkgPT09IGZhbHNlICkge1xuXHRcdFx0dGhpcy5fY2xlYXIoKTtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHQvL1JlY2FjaGUgdGhlIGhlbHBlciBzaXplXG5cdFx0dGhpcy5fY2FjaGVIZWxwZXJQcm9wb3J0aW9ucygpO1xuXG5cdFx0Ly9QcmVwYXJlIHRoZSBkcm9wcGFibGUgb2Zmc2V0c1xuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgJiYgIW8uZHJvcEJlaGF2aW91ciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLnByZXBhcmVPZmZzZXRzKCB0aGlzLCBldmVudCApO1xuXHRcdH1cblxuXHRcdC8vIEV4ZWN1dGUgdGhlIGRyYWcgb25jZSAtIHRoaXMgY2F1c2VzIHRoZSBoZWxwZXIgbm90IHRvIGJlIHZpc2libGUgYmVmb3JlIGdldHRpbmcgaXRzXG5cdFx0Ly8gY29ycmVjdCBwb3NpdGlvblxuXHRcdHRoaXMuX21vdXNlRHJhZyggZXZlbnQsIHRydWUgKTtcblxuXHRcdC8vIElmIHRoZSBkZG1hbmFnZXIgaXMgdXNlZCBmb3IgZHJvcHBhYmxlcywgaW5mb3JtIHRoZSBtYW5hZ2VyIHRoYXQgZHJhZ2dpbmcgaGFzIHN0YXJ0ZWRcblx0XHQvLyAoc2VlICM1MDAzKVxuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5kcmFnU3RhcnQoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0X3JlZnJlc2hPZmZzZXRzOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dGhpcy5vZmZzZXQgPSB7XG5cdFx0XHR0b3A6IHRoaXMucG9zaXRpb25BYnMudG9wIC0gdGhpcy5tYXJnaW5zLnRvcCxcblx0XHRcdGxlZnQ6IHRoaXMucG9zaXRpb25BYnMubGVmdCAtIHRoaXMubWFyZ2lucy5sZWZ0LFxuXHRcdFx0c2Nyb2xsOiBmYWxzZSxcblx0XHRcdHBhcmVudDogdGhpcy5fZ2V0UGFyZW50T2Zmc2V0KCksXG5cdFx0XHRyZWxhdGl2ZTogdGhpcy5fZ2V0UmVsYXRpdmVPZmZzZXQoKVxuXHRcdH07XG5cblx0XHR0aGlzLm9mZnNldC5jbGljayA9IHtcblx0XHRcdGxlZnQ6IGV2ZW50LnBhZ2VYIC0gdGhpcy5vZmZzZXQubGVmdCxcblx0XHRcdHRvcDogZXZlbnQucGFnZVkgLSB0aGlzLm9mZnNldC50b3Bcblx0XHR9O1xuXHR9LFxuXG5cdF9tb3VzZURyYWc6IGZ1bmN0aW9uKCBldmVudCwgbm9Qcm9wYWdhdGlvbiApIHtcblxuXHRcdC8vIHJlc2V0IGFueSBuZWNlc3NhcnkgY2FjaGVkIHByb3BlcnRpZXMgKHNlZSAjNTAwOSlcblx0XHRpZiAoIHRoaXMuaGFzRml4ZWRBbmNlc3RvciApIHtcblx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudCA9IHRoaXMuX2dldFBhcmVudE9mZnNldCgpO1xuXHRcdH1cblxuXHRcdC8vQ29tcHV0ZSB0aGUgaGVscGVycyBwb3NpdGlvblxuXHRcdHRoaXMucG9zaXRpb24gPSB0aGlzLl9nZW5lcmF0ZVBvc2l0aW9uKCBldmVudCwgdHJ1ZSApO1xuXHRcdHRoaXMucG9zaXRpb25BYnMgPSB0aGlzLl9jb252ZXJ0UG9zaXRpb25UbyggXCJhYnNvbHV0ZVwiICk7XG5cblx0XHQvL0NhbGwgcGx1Z2lucyBhbmQgY2FsbGJhY2tzIGFuZCB1c2UgdGhlIHJlc3VsdGluZyBwb3NpdGlvbiBpZiBzb21ldGhpbmcgaXMgcmV0dXJuZWRcblx0XHRpZiAoICFub1Byb3BhZ2F0aW9uICkge1xuXHRcdFx0dmFyIHVpID0gdGhpcy5fdWlIYXNoKCk7XG5cdFx0XHRpZiAoIHRoaXMuX3RyaWdnZXIoIFwiZHJhZ1wiLCBldmVudCwgdWkgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdHRoaXMuX21vdXNlVXAoIG5ldyAkLkV2ZW50KCBcIm1vdXNldXBcIiwgZXZlbnQgKSApO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLnBvc2l0aW9uID0gdWkucG9zaXRpb247XG5cdFx0fVxuXG5cdFx0dGhpcy5oZWxwZXJbIDAgXS5zdHlsZS5sZWZ0ID0gdGhpcy5wb3NpdGlvbi5sZWZ0ICsgXCJweFwiO1xuXHRcdHRoaXMuaGVscGVyWyAwIF0uc3R5bGUudG9wID0gdGhpcy5wb3NpdGlvbi50b3AgKyBcInB4XCI7XG5cblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIuZHJhZyggdGhpcywgZXZlbnQgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0sXG5cblx0X21vdXNlU3RvcDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0Ly9JZiB3ZSBhcmUgdXNpbmcgZHJvcHBhYmxlcywgaW5mb3JtIHRoZSBtYW5hZ2VyIGFib3V0IHRoZSBkcm9wXG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0ZHJvcHBlZCA9IGZhbHNlO1xuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgJiYgIXRoaXMub3B0aW9ucy5kcm9wQmVoYXZpb3VyICkge1xuXHRcdFx0ZHJvcHBlZCA9ICQudWkuZGRtYW5hZ2VyLmRyb3AoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0Ly9pZiBhIGRyb3AgY29tZXMgZnJvbSBvdXRzaWRlIChhIHNvcnRhYmxlKVxuXHRcdGlmICggdGhpcy5kcm9wcGVkICkge1xuXHRcdFx0ZHJvcHBlZCA9IHRoaXMuZHJvcHBlZDtcblx0XHRcdHRoaXMuZHJvcHBlZCA9IGZhbHNlO1xuXHRcdH1cblxuXHRcdGlmICggKCB0aGlzLm9wdGlvbnMucmV2ZXJ0ID09PSBcImludmFsaWRcIiAmJiAhZHJvcHBlZCApIHx8XG5cdFx0XHRcdCggdGhpcy5vcHRpb25zLnJldmVydCA9PT0gXCJ2YWxpZFwiICYmIGRyb3BwZWQgKSB8fFxuXHRcdFx0XHR0aGlzLm9wdGlvbnMucmV2ZXJ0ID09PSB0cnVlIHx8ICggJC5pc0Z1bmN0aW9uKCB0aGlzLm9wdGlvbnMucmV2ZXJ0ICkgJiZcblx0XHRcdFx0dGhpcy5vcHRpb25zLnJldmVydC5jYWxsKCB0aGlzLmVsZW1lbnQsIGRyb3BwZWQgKSApXG5cdFx0KSB7XG5cdFx0XHQkKCB0aGlzLmhlbHBlciApLmFuaW1hdGUoXG5cdFx0XHRcdHRoaXMub3JpZ2luYWxQb3NpdGlvbixcblx0XHRcdFx0cGFyc2VJbnQoIHRoaXMub3B0aW9ucy5yZXZlcnREdXJhdGlvbiwgMTAgKSxcblx0XHRcdFx0ZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0aWYgKCB0aGF0Ll90cmlnZ2VyKCBcInN0b3BcIiwgZXZlbnQgKSAhPT0gZmFsc2UgKSB7XG5cdFx0XHRcdFx0XHR0aGF0Ll9jbGVhcigpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0KTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aWYgKCB0aGlzLl90cmlnZ2VyKCBcInN0b3BcIiwgZXZlbnQgKSAhPT0gZmFsc2UgKSB7XG5cdFx0XHRcdHRoaXMuX2NsZWFyKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXG5cdF9tb3VzZVVwOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dGhpcy5fdW5ibG9ja0ZyYW1lcygpO1xuXG5cdFx0Ly8gSWYgdGhlIGRkbWFuYWdlciBpcyB1c2VkIGZvciBkcm9wcGFibGVzLCBpbmZvcm0gdGhlIG1hbmFnZXIgdGhhdCBkcmFnZ2luZyBoYXMgc3RvcHBlZFxuXHRcdC8vIChzZWUgIzUwMDMpXG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLmRyYWdTdG9wKCB0aGlzLCBldmVudCApO1xuXHRcdH1cblxuXHRcdC8vIE9ubHkgbmVlZCB0byBmb2N1cyBpZiB0aGUgZXZlbnQgb2NjdXJyZWQgb24gdGhlIGRyYWdnYWJsZSBpdHNlbGYsIHNlZSAjMTA1Mjdcblx0XHRpZiAoIHRoaXMuaGFuZGxlRWxlbWVudC5pcyggZXZlbnQudGFyZ2V0ICkgKSB7XG5cblx0XHRcdC8vIFRoZSBpbnRlcmFjdGlvbiBpcyBvdmVyOyB3aGV0aGVyIG9yIG5vdCB0aGUgY2xpY2sgcmVzdWx0ZWQgaW4gYSBkcmFnLFxuXHRcdFx0Ly8gZm9jdXMgdGhlIGVsZW1lbnRcblx0XHRcdHRoaXMuZWxlbWVudC50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gJC51aS5tb3VzZS5wcm90b3R5cGUuX21vdXNlVXAuY2FsbCggdGhpcywgZXZlbnQgKTtcblx0fSxcblxuXHRjYW5jZWw6IGZ1bmN0aW9uKCkge1xuXG5cdFx0aWYgKCB0aGlzLmhlbHBlci5pcyggXCIudWktZHJhZ2dhYmxlLWRyYWdnaW5nXCIgKSApIHtcblx0XHRcdHRoaXMuX21vdXNlVXAoIG5ldyAkLkV2ZW50KCBcIm1vdXNldXBcIiwgeyB0YXJnZXQ6IHRoaXMuZWxlbWVudFsgMCBdIH0gKSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9jbGVhcigpO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH0sXG5cblx0X2dldEhhbmRsZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMuaGFuZGxlID9cblx0XHRcdCEhJCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggdGhpcy5lbGVtZW50LmZpbmQoIHRoaXMub3B0aW9ucy5oYW5kbGUgKSApLmxlbmd0aCA6XG5cdFx0XHR0cnVlO1xuXHR9LFxuXG5cdF9zZXRIYW5kbGVDbGFzc05hbWU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuaGFuZGxlRWxlbWVudCA9IHRoaXMub3B0aW9ucy5oYW5kbGUgP1xuXHRcdFx0dGhpcy5lbGVtZW50LmZpbmQoIHRoaXMub3B0aW9ucy5oYW5kbGUgKSA6IHRoaXMuZWxlbWVudDtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5oYW5kbGVFbGVtZW50LCBcInVpLWRyYWdnYWJsZS1oYW5kbGVcIiApO1xuXHR9LFxuXG5cdF9yZW1vdmVIYW5kbGVDbGFzc05hbWU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmhhbmRsZUVsZW1lbnQsIFwidWktZHJhZ2dhYmxlLWhhbmRsZVwiICk7XG5cdH0sXG5cblx0X2NyZWF0ZUhlbHBlcjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dmFyIG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRoZWxwZXJJc0Z1bmN0aW9uID0gJC5pc0Z1bmN0aW9uKCBvLmhlbHBlciApLFxuXHRcdFx0aGVscGVyID0gaGVscGVySXNGdW5jdGlvbiA/XG5cdFx0XHRcdCQoIG8uaGVscGVyLmFwcGx5KCB0aGlzLmVsZW1lbnRbIDAgXSwgWyBldmVudCBdICkgKSA6XG5cdFx0XHRcdCggby5oZWxwZXIgPT09IFwiY2xvbmVcIiA/XG5cdFx0XHRcdFx0dGhpcy5lbGVtZW50LmNsb25lKCkucmVtb3ZlQXR0ciggXCJpZFwiICkgOlxuXHRcdFx0XHRcdHRoaXMuZWxlbWVudCApO1xuXG5cdFx0aWYgKCAhaGVscGVyLnBhcmVudHMoIFwiYm9keVwiICkubGVuZ3RoICkge1xuXHRcdFx0aGVscGVyLmFwcGVuZFRvKCAoIG8uYXBwZW5kVG8gPT09IFwicGFyZW50XCIgP1xuXHRcdFx0XHR0aGlzLmVsZW1lbnRbIDAgXS5wYXJlbnROb2RlIDpcblx0XHRcdFx0by5hcHBlbmRUbyApICk7XG5cdFx0fVxuXG5cdFx0Ly8gSHR0cDovL2J1Z3MuanF1ZXJ5dWkuY29tL3RpY2tldC85NDQ2XG5cdFx0Ly8gYSBoZWxwZXIgZnVuY3Rpb24gY2FuIHJldHVybiB0aGUgb3JpZ2luYWwgZWxlbWVudFxuXHRcdC8vIHdoaWNoIHdvdWxkbid0IGhhdmUgYmVlbiBzZXQgdG8gcmVsYXRpdmUgaW4gX2NyZWF0ZVxuXHRcdGlmICggaGVscGVySXNGdW5jdGlvbiAmJiBoZWxwZXJbIDAgXSA9PT0gdGhpcy5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHR0aGlzLl9zZXRQb3NpdGlvblJlbGF0aXZlKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCBoZWxwZXJbIDAgXSAhPT0gdGhpcy5lbGVtZW50WyAwIF0gJiZcblx0XHRcdFx0ISggLyhmaXhlZHxhYnNvbHV0ZSkvICkudGVzdCggaGVscGVyLmNzcyggXCJwb3NpdGlvblwiICkgKSApIHtcblx0XHRcdGhlbHBlci5jc3MoIFwicG9zaXRpb25cIiwgXCJhYnNvbHV0ZVwiICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGhlbHBlcjtcblxuXHR9LFxuXG5cdF9zZXRQb3NpdGlvblJlbGF0aXZlOiBmdW5jdGlvbigpIHtcblx0XHRpZiAoICEoIC9eKD86cnxhfGYpLyApLnRlc3QoIHRoaXMuZWxlbWVudC5jc3MoIFwicG9zaXRpb25cIiApICkgKSB7XG5cdFx0XHR0aGlzLmVsZW1lbnRbIDAgXS5zdHlsZS5wb3NpdGlvbiA9IFwicmVsYXRpdmVcIjtcblx0XHR9XG5cdH0sXG5cblx0X2FkanVzdE9mZnNldEZyb21IZWxwZXI6IGZ1bmN0aW9uKCBvYmogKSB7XG5cdFx0aWYgKCB0eXBlb2Ygb2JqID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0b2JqID0gb2JqLnNwbGl0KCBcIiBcIiApO1xuXHRcdH1cblx0XHRpZiAoICQuaXNBcnJheSggb2JqICkgKSB7XG5cdFx0XHRvYmogPSB7IGxlZnQ6ICtvYmpbIDAgXSwgdG9wOiArb2JqWyAxIF0gfHwgMCB9O1xuXHRcdH1cblx0XHRpZiAoIFwibGVmdFwiIGluIG9iaiApIHtcblx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPSBvYmoubGVmdCArIHRoaXMubWFyZ2lucy5sZWZ0O1xuXHRcdH1cblx0XHRpZiAoIFwicmlnaHRcIiBpbiBvYmogKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5jbGljay5sZWZ0ID0gdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAtIG9iai5yaWdodCArIHRoaXMubWFyZ2lucy5sZWZ0O1xuXHRcdH1cblx0XHRpZiAoIFwidG9wXCIgaW4gb2JqICkge1xuXHRcdFx0dGhpcy5vZmZzZXQuY2xpY2sudG9wID0gb2JqLnRvcCArIHRoaXMubWFyZ2lucy50b3A7XG5cdFx0fVxuXHRcdGlmICggXCJib3R0b21cIiBpbiBvYmogKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5jbGljay50b3AgPSB0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAtIG9iai5ib3R0b20gKyB0aGlzLm1hcmdpbnMudG9wO1xuXHRcdH1cblx0fSxcblxuXHRfaXNSb290Tm9kZTogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0cmV0dXJuICggLyhodG1sfGJvZHkpL2kgKS50ZXN0KCBlbGVtZW50LnRhZ05hbWUgKSB8fCBlbGVtZW50ID09PSB0aGlzLmRvY3VtZW50WyAwIF07XG5cdH0sXG5cblx0X2dldFBhcmVudE9mZnNldDogZnVuY3Rpb24oKSB7XG5cblx0XHQvL0dldCB0aGUgb2Zmc2V0UGFyZW50IGFuZCBjYWNoZSBpdHMgcG9zaXRpb25cblx0XHR2YXIgcG8gPSB0aGlzLm9mZnNldFBhcmVudC5vZmZzZXQoKSxcblx0XHRcdGRvY3VtZW50ID0gdGhpcy5kb2N1bWVudFsgMCBdO1xuXG5cdFx0Ly8gVGhpcyBpcyBhIHNwZWNpYWwgY2FzZSB3aGVyZSB3ZSBuZWVkIHRvIG1vZGlmeSBhIG9mZnNldCBjYWxjdWxhdGVkIG9uIHN0YXJ0LCBzaW5jZSB0aGVcblx0XHQvLyBmb2xsb3dpbmcgaGFwcGVuZWQ6XG5cdFx0Ly8gMS4gVGhlIHBvc2l0aW9uIG9mIHRoZSBoZWxwZXIgaXMgYWJzb2x1dGUsIHNvIGl0J3MgcG9zaXRpb24gaXMgY2FsY3VsYXRlZCBiYXNlZCBvbiB0aGVcblx0XHQvLyBuZXh0IHBvc2l0aW9uZWQgcGFyZW50XG5cdFx0Ly8gMi4gVGhlIGFjdHVhbCBvZmZzZXQgcGFyZW50IGlzIGEgY2hpbGQgb2YgdGhlIHNjcm9sbCBwYXJlbnQsIGFuZCB0aGUgc2Nyb2xsIHBhcmVudCBpc24ndFxuXHRcdC8vIHRoZSBkb2N1bWVudCwgd2hpY2ggbWVhbnMgdGhhdCB0aGUgc2Nyb2xsIGlzIGluY2x1ZGVkIGluIHRoZSBpbml0aWFsIGNhbGN1bGF0aW9uIG9mIHRoZVxuXHRcdC8vIG9mZnNldCBvZiB0aGUgcGFyZW50LCBhbmQgbmV2ZXIgcmVjYWxjdWxhdGVkIHVwb24gZHJhZ1xuXHRcdGlmICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiICYmIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gIT09IGRvY3VtZW50ICYmXG5cdFx0XHRcdCQuY29udGFpbnMoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0sIHRoaXMub2Zmc2V0UGFyZW50WyAwIF0gKSApIHtcblx0XHRcdHBvLmxlZnQgKz0gdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCgpO1xuXHRcdFx0cG8udG9wICs9IHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbFRvcCgpO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5faXNSb290Tm9kZSggdGhpcy5vZmZzZXRQYXJlbnRbIDAgXSApICkge1xuXHRcdFx0cG8gPSB7IHRvcDogMCwgbGVmdDogMCB9O1xuXHRcdH1cblxuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IHBvLnRvcCArICggcGFyc2VJbnQoIHRoaXMub2Zmc2V0UGFyZW50LmNzcyggXCJib3JkZXJUb3BXaWR0aFwiICksIDEwICkgfHwgMCApLFxuXHRcdFx0bGVmdDogcG8ubGVmdCArICggcGFyc2VJbnQoIHRoaXMub2Zmc2V0UGFyZW50LmNzcyggXCJib3JkZXJMZWZ0V2lkdGhcIiApLCAxMCApIHx8IDAgKVxuXHRcdH07XG5cblx0fSxcblxuXHRfZ2V0UmVsYXRpdmVPZmZzZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggdGhpcy5jc3NQb3NpdGlvbiAhPT0gXCJyZWxhdGl2ZVwiICkge1xuXHRcdFx0cmV0dXJuIHsgdG9wOiAwLCBsZWZ0OiAwIH07XG5cdFx0fVxuXG5cdFx0dmFyIHAgPSB0aGlzLmVsZW1lbnQucG9zaXRpb24oKSxcblx0XHRcdHNjcm9sbElzUm9vdE5vZGUgPSB0aGlzLl9pc1Jvb3ROb2RlKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICk7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiBwLnRvcCAtICggcGFyc2VJbnQoIHRoaXMuaGVscGVyLmNzcyggXCJ0b3BcIiApLCAxMCApIHx8IDAgKSArXG5cdFx0XHRcdCggIXNjcm9sbElzUm9vdE5vZGUgPyB0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxUb3AoKSA6IDAgKSxcblx0XHRcdGxlZnQ6IHAubGVmdCAtICggcGFyc2VJbnQoIHRoaXMuaGVscGVyLmNzcyggXCJsZWZ0XCIgKSwgMTAgKSB8fCAwICkgK1xuXHRcdFx0XHQoICFzY3JvbGxJc1Jvb3ROb2RlID8gdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCgpIDogMCApXG5cdFx0fTtcblxuXHR9LFxuXG5cdF9jYWNoZU1hcmdpbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMubWFyZ2lucyA9IHtcblx0XHRcdGxlZnQ6ICggcGFyc2VJbnQoIHRoaXMuZWxlbWVudC5jc3MoIFwibWFyZ2luTGVmdFwiICksIDEwICkgfHwgMCApLFxuXHRcdFx0dG9wOiAoIHBhcnNlSW50KCB0aGlzLmVsZW1lbnQuY3NzKCBcIm1hcmdpblRvcFwiICksIDEwICkgfHwgMCApLFxuXHRcdFx0cmlnaHQ6ICggcGFyc2VJbnQoIHRoaXMuZWxlbWVudC5jc3MoIFwibWFyZ2luUmlnaHRcIiApLCAxMCApIHx8IDAgKSxcblx0XHRcdGJvdHRvbTogKCBwYXJzZUludCggdGhpcy5lbGVtZW50LmNzcyggXCJtYXJnaW5Cb3R0b21cIiApLCAxMCApIHx8IDAgKVxuXHRcdH07XG5cdH0sXG5cblx0X2NhY2hlSGVscGVyUHJvcG9ydGlvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMgPSB7XG5cdFx0XHR3aWR0aDogdGhpcy5oZWxwZXIub3V0ZXJXaWR0aCgpLFxuXHRcdFx0aGVpZ2h0OiB0aGlzLmhlbHBlci5vdXRlckhlaWdodCgpXG5cdFx0fTtcblx0fSxcblxuXHRfc2V0Q29udGFpbm1lbnQ6IGZ1bmN0aW9uKCkge1xuXG5cdFx0dmFyIGlzVXNlclNjcm9sbGFibGUsIGMsIGNlLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGRvY3VtZW50ID0gdGhpcy5kb2N1bWVudFsgMCBdO1xuXG5cdFx0dGhpcy5yZWxhdGl2ZUNvbnRhaW5lciA9IG51bGw7XG5cblx0XHRpZiAoICFvLmNvbnRhaW5tZW50ICkge1xuXHRcdFx0dGhpcy5jb250YWlubWVudCA9IG51bGw7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBvLmNvbnRhaW5tZW50ID09PSBcIndpbmRvd1wiICkge1xuXHRcdFx0dGhpcy5jb250YWlubWVudCA9IFtcblx0XHRcdFx0JCggd2luZG93ICkuc2Nyb2xsTGVmdCgpIC0gdGhpcy5vZmZzZXQucmVsYXRpdmUubGVmdCAtIHRoaXMub2Zmc2V0LnBhcmVudC5sZWZ0LFxuXHRcdFx0XHQkKCB3aW5kb3cgKS5zY3JvbGxUb3AoKSAtIHRoaXMub2Zmc2V0LnJlbGF0aXZlLnRvcCAtIHRoaXMub2Zmc2V0LnBhcmVudC50b3AsXG5cdFx0XHRcdCQoIHdpbmRvdyApLnNjcm9sbExlZnQoKSArICQoIHdpbmRvdyApLndpZHRoKCkgLVxuXHRcdFx0XHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLSB0aGlzLm1hcmdpbnMubGVmdCxcblx0XHRcdFx0JCggd2luZG93ICkuc2Nyb2xsVG9wKCkgK1xuXHRcdFx0XHRcdCggJCggd2luZG93ICkuaGVpZ2h0KCkgfHwgZG9jdW1lbnQuYm9keS5wYXJlbnROb2RlLnNjcm9sbEhlaWdodCApIC1cblx0XHRcdFx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAtIHRoaXMubWFyZ2lucy50b3Bcblx0XHRcdF07XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBvLmNvbnRhaW5tZW50ID09PSBcImRvY3VtZW50XCIgKSB7XG5cdFx0XHR0aGlzLmNvbnRhaW5tZW50ID0gW1xuXHRcdFx0XHQwLFxuXHRcdFx0XHQwLFxuXHRcdFx0XHQkKCBkb2N1bWVudCApLndpZHRoKCkgLSB0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC0gdGhpcy5tYXJnaW5zLmxlZnQsXG5cdFx0XHRcdCggJCggZG9jdW1lbnQgKS5oZWlnaHQoKSB8fCBkb2N1bWVudC5ib2R5LnBhcmVudE5vZGUuc2Nyb2xsSGVpZ2h0ICkgLVxuXHRcdFx0XHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC0gdGhpcy5tYXJnaW5zLnRvcFxuXHRcdFx0XTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIG8uY29udGFpbm1lbnQuY29uc3RydWN0b3IgPT09IEFycmF5ICkge1xuXHRcdFx0dGhpcy5jb250YWlubWVudCA9IG8uY29udGFpbm1lbnQ7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBvLmNvbnRhaW5tZW50ID09PSBcInBhcmVudFwiICkge1xuXHRcdFx0by5jb250YWlubWVudCA9IHRoaXMuaGVscGVyWyAwIF0ucGFyZW50Tm9kZTtcblx0XHR9XG5cblx0XHRjID0gJCggby5jb250YWlubWVudCApO1xuXHRcdGNlID0gY1sgMCBdO1xuXG5cdFx0aWYgKCAhY2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aXNVc2VyU2Nyb2xsYWJsZSA9IC8oc2Nyb2xsfGF1dG8pLy50ZXN0KCBjLmNzcyggXCJvdmVyZmxvd1wiICkgKTtcblxuXHRcdHRoaXMuY29udGFpbm1lbnQgPSBbXG5cdFx0XHQoIHBhcnNlSW50KCBjLmNzcyggXCJib3JkZXJMZWZ0V2lkdGhcIiApLCAxMCApIHx8IDAgKSArXG5cdFx0XHRcdCggcGFyc2VJbnQoIGMuY3NzKCBcInBhZGRpbmdMZWZ0XCIgKSwgMTAgKSB8fCAwICksXG5cdFx0XHQoIHBhcnNlSW50KCBjLmNzcyggXCJib3JkZXJUb3BXaWR0aFwiICksIDEwICkgfHwgMCApICtcblx0XHRcdFx0KCBwYXJzZUludCggYy5jc3MoIFwicGFkZGluZ1RvcFwiICksIDEwICkgfHwgMCApLFxuXHRcdFx0KCBpc1VzZXJTY3JvbGxhYmxlID8gTWF0aC5tYXgoIGNlLnNjcm9sbFdpZHRoLCBjZS5vZmZzZXRXaWR0aCApIDogY2Uub2Zmc2V0V2lkdGggKSAtXG5cdFx0XHRcdCggcGFyc2VJbnQoIGMuY3NzKCBcImJvcmRlclJpZ2h0V2lkdGhcIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdCggcGFyc2VJbnQoIGMuY3NzKCBcInBhZGRpbmdSaWdodFwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAtXG5cdFx0XHRcdHRoaXMubWFyZ2lucy5sZWZ0IC1cblx0XHRcdFx0dGhpcy5tYXJnaW5zLnJpZ2h0LFxuXHRcdFx0KCBpc1VzZXJTY3JvbGxhYmxlID8gTWF0aC5tYXgoIGNlLnNjcm9sbEhlaWdodCwgY2Uub2Zmc2V0SGVpZ2h0ICkgOiBjZS5vZmZzZXRIZWlnaHQgKSAtXG5cdFx0XHRcdCggcGFyc2VJbnQoIGMuY3NzKCBcImJvcmRlckJvdHRvbVdpZHRoXCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHQoIHBhcnNlSW50KCBjLmNzcyggXCJwYWRkaW5nQm90dG9tXCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAtXG5cdFx0XHRcdHRoaXMubWFyZ2lucy50b3AgLVxuXHRcdFx0XHR0aGlzLm1hcmdpbnMuYm90dG9tXG5cdFx0XTtcblx0XHR0aGlzLnJlbGF0aXZlQ29udGFpbmVyID0gYztcblx0fSxcblxuXHRfY29udmVydFBvc2l0aW9uVG86IGZ1bmN0aW9uKCBkLCBwb3MgKSB7XG5cblx0XHRpZiAoICFwb3MgKSB7XG5cdFx0XHRwb3MgPSB0aGlzLnBvc2l0aW9uO1xuXHRcdH1cblxuXHRcdHZhciBtb2QgPSBkID09PSBcImFic29sdXRlXCIgPyAxIDogLTEsXG5cdFx0XHRzY3JvbGxJc1Jvb3ROb2RlID0gdGhpcy5faXNSb290Tm9kZSggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSApO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogKFxuXG5cdFx0XHRcdC8vIFRoZSBhYnNvbHV0ZSBtb3VzZSBwb3NpdGlvblxuXHRcdFx0XHRwb3MudG9wXHQrXG5cblx0XHRcdFx0Ly8gT25seSBmb3IgcmVsYXRpdmUgcG9zaXRpb25lZCBub2RlczogUmVsYXRpdmUgb2Zmc2V0IGZyb20gZWxlbWVudCB0byBvZmZzZXQgcGFyZW50XG5cdFx0XHRcdHRoaXMub2Zmc2V0LnJlbGF0aXZlLnRvcCAqIG1vZCArXG5cblx0XHRcdFx0Ly8gVGhlIG9mZnNldFBhcmVudCdzIG9mZnNldCB3aXRob3V0IGJvcmRlcnMgKG9mZnNldCArIGJvcmRlcilcblx0XHRcdFx0dGhpcy5vZmZzZXQucGFyZW50LnRvcCAqIG1vZCAtXG5cdFx0XHRcdCggKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImZpeGVkXCIgP1xuXHRcdFx0XHRcdC10aGlzLm9mZnNldC5zY3JvbGwudG9wIDpcblx0XHRcdFx0XHQoIHNjcm9sbElzUm9vdE5vZGUgPyAwIDogdGhpcy5vZmZzZXQuc2Nyb2xsLnRvcCApICkgKiBtb2QgKVxuXHRcdFx0KSxcblx0XHRcdGxlZnQ6IChcblxuXHRcdFx0XHQvLyBUaGUgYWJzb2x1dGUgbW91c2UgcG9zaXRpb25cblx0XHRcdFx0cG9zLmxlZnQgK1xuXG5cdFx0XHRcdC8vIE9ubHkgZm9yIHJlbGF0aXZlIHBvc2l0aW9uZWQgbm9kZXM6IFJlbGF0aXZlIG9mZnNldCBmcm9tIGVsZW1lbnQgdG8gb2Zmc2V0IHBhcmVudFxuXHRcdFx0XHR0aGlzLm9mZnNldC5yZWxhdGl2ZS5sZWZ0ICogbW9kICtcblxuXHRcdFx0XHQvLyBUaGUgb2Zmc2V0UGFyZW50J3Mgb2Zmc2V0IHdpdGhvdXQgYm9yZGVycyAob2Zmc2V0ICsgYm9yZGVyKVxuXHRcdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQubGVmdCAqIG1vZFx0LVxuXHRcdFx0XHQoICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJmaXhlZFwiID9cblx0XHRcdFx0XHQtdGhpcy5vZmZzZXQuc2Nyb2xsLmxlZnQgOlxuXHRcdFx0XHRcdCggc2Nyb2xsSXNSb290Tm9kZSA/IDAgOiB0aGlzLm9mZnNldC5zY3JvbGwubGVmdCApICkgKiBtb2QgKVxuXHRcdFx0KVxuXHRcdH07XG5cblx0fSxcblxuXHRfZ2VuZXJhdGVQb3NpdGlvbjogZnVuY3Rpb24oIGV2ZW50LCBjb25zdHJhaW5Qb3NpdGlvbiApIHtcblxuXHRcdHZhciBjb250YWlubWVudCwgY28sIHRvcCwgbGVmdCxcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRzY3JvbGxJc1Jvb3ROb2RlID0gdGhpcy5faXNSb290Tm9kZSggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSApLFxuXHRcdFx0cGFnZVggPSBldmVudC5wYWdlWCxcblx0XHRcdHBhZ2VZID0gZXZlbnQucGFnZVk7XG5cblx0XHQvLyBDYWNoZSB0aGUgc2Nyb2xsXG5cdFx0aWYgKCAhc2Nyb2xsSXNSb290Tm9kZSB8fCAhdGhpcy5vZmZzZXQuc2Nyb2xsICkge1xuXHRcdFx0dGhpcy5vZmZzZXQuc2Nyb2xsID0ge1xuXHRcdFx0XHR0b3A6IHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbFRvcCgpLFxuXHRcdFx0XHRsZWZ0OiB0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0KClcblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0Lypcblx0XHQgKiAtIFBvc2l0aW9uIGNvbnN0cmFpbmluZyAtXG5cdFx0ICogQ29uc3RyYWluIHRoZSBwb3NpdGlvbiB0byBhIG1peCBvZiBncmlkLCBjb250YWlubWVudC5cblx0XHQgKi9cblxuXHRcdC8vIElmIHdlIGFyZSBub3QgZHJhZ2dpbmcgeWV0LCB3ZSB3b24ndCBjaGVjayBmb3Igb3B0aW9uc1xuXHRcdGlmICggY29uc3RyYWluUG9zaXRpb24gKSB7XG5cdFx0XHRpZiAoIHRoaXMuY29udGFpbm1lbnQgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5yZWxhdGl2ZUNvbnRhaW5lciApIHtcblx0XHRcdFx0XHRjbyA9IHRoaXMucmVsYXRpdmVDb250YWluZXIub2Zmc2V0KCk7XG5cdFx0XHRcdFx0Y29udGFpbm1lbnQgPSBbXG5cdFx0XHRcdFx0XHR0aGlzLmNvbnRhaW5tZW50WyAwIF0gKyBjby5sZWZ0LFxuXHRcdFx0XHRcdFx0dGhpcy5jb250YWlubWVudFsgMSBdICsgY28udG9wLFxuXHRcdFx0XHRcdFx0dGhpcy5jb250YWlubWVudFsgMiBdICsgY28ubGVmdCxcblx0XHRcdFx0XHRcdHRoaXMuY29udGFpbm1lbnRbIDMgXSArIGNvLnRvcFxuXHRcdFx0XHRcdF07XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Y29udGFpbm1lbnQgPSB0aGlzLmNvbnRhaW5tZW50O1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPCBjb250YWlubWVudFsgMCBdICkge1xuXHRcdFx0XHRcdHBhZ2VYID0gY29udGFpbm1lbnRbIDAgXSArIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWSAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA8IGNvbnRhaW5tZW50WyAxIF0gKSB7XG5cdFx0XHRcdFx0cGFnZVkgPSBjb250YWlubWVudFsgMSBdICsgdGhpcy5vZmZzZXQuY2xpY2sudG9wO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVggLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0ID4gY29udGFpbm1lbnRbIDIgXSApIHtcblx0XHRcdFx0XHRwYWdlWCA9IGNvbnRhaW5tZW50WyAyIF0gKyB0aGlzLm9mZnNldC5jbGljay5sZWZ0O1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVkgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPiBjb250YWlubWVudFsgMyBdICkge1xuXHRcdFx0XHRcdHBhZ2VZID0gY29udGFpbm1lbnRbIDMgXSArIHRoaXMub2Zmc2V0LmNsaWNrLnRvcDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG8uZ3JpZCApIHtcblxuXHRcdFx0XHQvL0NoZWNrIGZvciBncmlkIGVsZW1lbnRzIHNldCB0byAwIHRvIHByZXZlbnQgZGl2aWRlIGJ5IDAgZXJyb3IgY2F1c2luZyBpbnZhbGlkXG5cdFx0XHRcdC8vIGFyZ3VtZW50IGVycm9ycyBpbiBJRSAoc2VlIHRpY2tldCAjNjk1MClcblx0XHRcdFx0dG9wID0gby5ncmlkWyAxIF0gPyB0aGlzLm9yaWdpbmFsUGFnZVkgKyBNYXRoLnJvdW5kKCAoIHBhZ2VZIC1cblx0XHRcdFx0XHR0aGlzLm9yaWdpbmFsUGFnZVkgKSAvIG8uZ3JpZFsgMSBdICkgKiBvLmdyaWRbIDEgXSA6IHRoaXMub3JpZ2luYWxQYWdlWTtcblx0XHRcdFx0cGFnZVkgPSBjb250YWlubWVudCA/ICggKCB0b3AgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPj0gY29udGFpbm1lbnRbIDEgXSB8fFxuXHRcdFx0XHRcdHRvcCAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA+IGNvbnRhaW5tZW50WyAzIF0gKSA/XG5cdFx0XHRcdFx0XHR0b3AgOlxuXHRcdFx0XHRcdFx0KCAoIHRvcCAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA+PSBjb250YWlubWVudFsgMSBdICkgP1xuXHRcdFx0XHRcdFx0XHR0b3AgLSBvLmdyaWRbIDEgXSA6IHRvcCArIG8uZ3JpZFsgMSBdICkgKSA6IHRvcDtcblxuXHRcdFx0XHRsZWZ0ID0gby5ncmlkWyAwIF0gPyB0aGlzLm9yaWdpbmFsUGFnZVggK1xuXHRcdFx0XHRcdE1hdGgucm91bmQoICggcGFnZVggLSB0aGlzLm9yaWdpbmFsUGFnZVggKSAvIG8uZ3JpZFsgMCBdICkgKiBvLmdyaWRbIDAgXSA6XG5cdFx0XHRcdFx0dGhpcy5vcmlnaW5hbFBhZ2VYO1xuXHRcdFx0XHRwYWdlWCA9IGNvbnRhaW5tZW50ID8gKCAoIGxlZnQgLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0ID49IGNvbnRhaW5tZW50WyAwIF0gfHxcblx0XHRcdFx0XHRsZWZ0IC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA+IGNvbnRhaW5tZW50WyAyIF0gKSA/XG5cdFx0XHRcdFx0XHRsZWZ0IDpcblx0XHRcdFx0XHRcdCggKCBsZWZ0IC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA+PSBjb250YWlubWVudFsgMCBdICkgP1xuXHRcdFx0XHRcdFx0XHRsZWZ0IC0gby5ncmlkWyAwIF0gOiBsZWZ0ICsgby5ncmlkWyAwIF0gKSApIDogbGVmdDtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBvLmF4aXMgPT09IFwieVwiICkge1xuXHRcdFx0XHRwYWdlWCA9IHRoaXMub3JpZ2luYWxQYWdlWDtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBvLmF4aXMgPT09IFwieFwiICkge1xuXHRcdFx0XHRwYWdlWSA9IHRoaXMub3JpZ2luYWxQYWdlWTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiAoXG5cblx0XHRcdFx0Ly8gVGhlIGFic29sdXRlIG1vdXNlIHBvc2l0aW9uXG5cdFx0XHRcdHBhZ2VZIC1cblxuXHRcdFx0XHQvLyBDbGljayBvZmZzZXQgKHJlbGF0aXZlIHRvIHRoZSBlbGVtZW50KVxuXHRcdFx0XHR0aGlzLm9mZnNldC5jbGljay50b3AgLVxuXG5cdFx0XHRcdC8vIE9ubHkgZm9yIHJlbGF0aXZlIHBvc2l0aW9uZWQgbm9kZXM6IFJlbGF0aXZlIG9mZnNldCBmcm9tIGVsZW1lbnQgdG8gb2Zmc2V0IHBhcmVudFxuXHRcdFx0XHR0aGlzLm9mZnNldC5yZWxhdGl2ZS50b3AgLVxuXG5cdFx0XHRcdC8vIFRoZSBvZmZzZXRQYXJlbnQncyBvZmZzZXQgd2l0aG91dCBib3JkZXJzIChvZmZzZXQgKyBib3JkZXIpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudC50b3AgK1xuXHRcdFx0XHQoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiZml4ZWRcIiA/XG5cdFx0XHRcdFx0LXRoaXMub2Zmc2V0LnNjcm9sbC50b3AgOlxuXHRcdFx0XHRcdCggc2Nyb2xsSXNSb290Tm9kZSA/IDAgOiB0aGlzLm9mZnNldC5zY3JvbGwudG9wICkgKVxuXHRcdFx0KSxcblx0XHRcdGxlZnQ6IChcblxuXHRcdFx0XHQvLyBUaGUgYWJzb2x1dGUgbW91c2UgcG9zaXRpb25cblx0XHRcdFx0cGFnZVggLVxuXG5cdFx0XHRcdC8vIENsaWNrIG9mZnNldCAocmVsYXRpdmUgdG8gdGhlIGVsZW1lbnQpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgLVxuXG5cdFx0XHRcdC8vIE9ubHkgZm9yIHJlbGF0aXZlIHBvc2l0aW9uZWQgbm9kZXM6IFJlbGF0aXZlIG9mZnNldCBmcm9tIGVsZW1lbnQgdG8gb2Zmc2V0IHBhcmVudFxuXHRcdFx0XHR0aGlzLm9mZnNldC5yZWxhdGl2ZS5sZWZ0IC1cblxuXHRcdFx0XHQvLyBUaGUgb2Zmc2V0UGFyZW50J3Mgb2Zmc2V0IHdpdGhvdXQgYm9yZGVycyAob2Zmc2V0ICsgYm9yZGVyKVxuXHRcdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQubGVmdCArXG5cdFx0XHRcdCggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJmaXhlZFwiID9cblx0XHRcdFx0XHQtdGhpcy5vZmZzZXQuc2Nyb2xsLmxlZnQgOlxuXHRcdFx0XHRcdCggc2Nyb2xsSXNSb290Tm9kZSA/IDAgOiB0aGlzLm9mZnNldC5zY3JvbGwubGVmdCApIClcblx0XHRcdClcblx0XHR9O1xuXG5cdH0sXG5cblx0X2NsZWFyOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5oZWxwZXIsIFwidWktZHJhZ2dhYmxlLWRyYWdnaW5nXCIgKTtcblx0XHRpZiAoIHRoaXMuaGVscGVyWyAwIF0gIT09IHRoaXMuZWxlbWVudFsgMCBdICYmICF0aGlzLmNhbmNlbEhlbHBlclJlbW92YWwgKSB7XG5cdFx0XHR0aGlzLmhlbHBlci5yZW1vdmUoKTtcblx0XHR9XG5cdFx0dGhpcy5oZWxwZXIgPSBudWxsO1xuXHRcdHRoaXMuY2FuY2VsSGVscGVyUmVtb3ZhbCA9IGZhbHNlO1xuXHRcdGlmICggdGhpcy5kZXN0cm95T25DbGVhciApIHtcblx0XHRcdHRoaXMuZGVzdHJveSgpO1xuXHRcdH1cblx0fSxcblxuXHQvLyBGcm9tIG5vdyBvbiBidWxrIHN0dWZmIC0gbWFpbmx5IGhlbHBlcnNcblxuXHRfdHJpZ2dlcjogZnVuY3Rpb24oIHR5cGUsIGV2ZW50LCB1aSApIHtcblx0XHR1aSA9IHVpIHx8IHRoaXMuX3VpSGFzaCgpO1xuXHRcdCQudWkucGx1Z2luLmNhbGwoIHRoaXMsIHR5cGUsIFsgZXZlbnQsIHVpLCB0aGlzIF0sIHRydWUgKTtcblxuXHRcdC8vIEFic29sdXRlIHBvc2l0aW9uIGFuZCBvZmZzZXQgKHNlZSAjNjg4NCApIGhhdmUgdG8gYmUgcmVjYWxjdWxhdGVkIGFmdGVyIHBsdWdpbnNcblx0XHRpZiAoIC9eKGRyYWd8c3RhcnR8c3RvcCkvLnRlc3QoIHR5cGUgKSApIHtcblx0XHRcdHRoaXMucG9zaXRpb25BYnMgPSB0aGlzLl9jb252ZXJ0UG9zaXRpb25UbyggXCJhYnNvbHV0ZVwiICk7XG5cdFx0XHR1aS5vZmZzZXQgPSB0aGlzLnBvc2l0aW9uQWJzO1xuXHRcdH1cblx0XHRyZXR1cm4gJC5XaWRnZXQucHJvdG90eXBlLl90cmlnZ2VyLmNhbGwoIHRoaXMsIHR5cGUsIGV2ZW50LCB1aSApO1xuXHR9LFxuXG5cdHBsdWdpbnM6IHt9LFxuXG5cdF91aUhhc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB7XG5cdFx0XHRoZWxwZXI6IHRoaXMuaGVscGVyLFxuXHRcdFx0cG9zaXRpb246IHRoaXMucG9zaXRpb24sXG5cdFx0XHRvcmlnaW5hbFBvc2l0aW9uOiB0aGlzLm9yaWdpbmFsUG9zaXRpb24sXG5cdFx0XHRvZmZzZXQ6IHRoaXMucG9zaXRpb25BYnNcblx0XHR9O1xuXHR9XG5cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcImRyYWdnYWJsZVwiLCBcImNvbm5lY3RUb1NvcnRhYmxlXCIsIHtcblx0c3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgdWksIGRyYWdnYWJsZSApIHtcblx0XHR2YXIgdWlTb3J0YWJsZSA9ICQuZXh0ZW5kKCB7fSwgdWksIHtcblx0XHRcdGl0ZW06IGRyYWdnYWJsZS5lbGVtZW50XG5cdFx0fSApO1xuXG5cdFx0ZHJhZ2dhYmxlLnNvcnRhYmxlcyA9IFtdO1xuXHRcdCQoIGRyYWdnYWJsZS5vcHRpb25zLmNvbm5lY3RUb1NvcnRhYmxlICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc29ydGFibGUgPSAkKCB0aGlzICkuc29ydGFibGUoIFwiaW5zdGFuY2VcIiApO1xuXG5cdFx0XHRpZiAoIHNvcnRhYmxlICYmICFzb3J0YWJsZS5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0XHRkcmFnZ2FibGUuc29ydGFibGVzLnB1c2goIHNvcnRhYmxlICk7XG5cblx0XHRcdFx0Ly8gUmVmcmVzaFBvc2l0aW9ucyBpcyBjYWxsZWQgYXQgZHJhZyBzdGFydCB0byByZWZyZXNoIHRoZSBjb250YWluZXJDYWNoZVxuXHRcdFx0XHQvLyB3aGljaCBpcyB1c2VkIGluIGRyYWcuIFRoaXMgZW5zdXJlcyBpdCdzIGluaXRpYWxpemVkIGFuZCBzeW5jaHJvbml6ZWRcblx0XHRcdFx0Ly8gd2l0aCBhbnkgY2hhbmdlcyB0aGF0IG1pZ2h0IGhhdmUgaGFwcGVuZWQgb24gdGhlIHBhZ2Ugc2luY2UgaW5pdGlhbGl6YXRpb24uXG5cdFx0XHRcdHNvcnRhYmxlLnJlZnJlc2hQb3NpdGlvbnMoKTtcblx0XHRcdFx0c29ydGFibGUuX3RyaWdnZXIoIFwiYWN0aXZhdGVcIiwgZXZlbnQsIHVpU29ydGFibGUgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cdHN0b3A6IGZ1bmN0aW9uKCBldmVudCwgdWksIGRyYWdnYWJsZSApIHtcblx0XHR2YXIgdWlTb3J0YWJsZSA9ICQuZXh0ZW5kKCB7fSwgdWksIHtcblx0XHRcdGl0ZW06IGRyYWdnYWJsZS5lbGVtZW50XG5cdFx0fSApO1xuXG5cdFx0ZHJhZ2dhYmxlLmNhbmNlbEhlbHBlclJlbW92YWwgPSBmYWxzZTtcblxuXHRcdCQuZWFjaCggZHJhZ2dhYmxlLnNvcnRhYmxlcywgZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc29ydGFibGUgPSB0aGlzO1xuXG5cdFx0XHRpZiAoIHNvcnRhYmxlLmlzT3ZlciApIHtcblx0XHRcdFx0c29ydGFibGUuaXNPdmVyID0gMDtcblxuXHRcdFx0XHQvLyBBbGxvdyB0aGlzIHNvcnRhYmxlIHRvIGhhbmRsZSByZW1vdmluZyB0aGUgaGVscGVyXG5cdFx0XHRcdGRyYWdnYWJsZS5jYW5jZWxIZWxwZXJSZW1vdmFsID0gdHJ1ZTtcblx0XHRcdFx0c29ydGFibGUuY2FuY2VsSGVscGVyUmVtb3ZhbCA9IGZhbHNlO1xuXG5cdFx0XHRcdC8vIFVzZSBfc3RvcmVkQ1NTIFRvIHJlc3RvcmUgcHJvcGVydGllcyBpbiB0aGUgc29ydGFibGUsXG5cdFx0XHRcdC8vIGFzIHRoaXMgYWxzbyBoYW5kbGVzIHJldmVydCAoIzk2NzUpIHNpbmNlIHRoZSBkcmFnZ2FibGVcblx0XHRcdFx0Ly8gbWF5IGhhdmUgbW9kaWZpZWQgdGhlbSBpbiB1bmV4cGVjdGVkIHdheXMgKCM4ODA5KVxuXHRcdFx0XHRzb3J0YWJsZS5fc3RvcmVkQ1NTID0ge1xuXHRcdFx0XHRcdHBvc2l0aW9uOiBzb3J0YWJsZS5wbGFjZWhvbGRlci5jc3MoIFwicG9zaXRpb25cIiApLFxuXHRcdFx0XHRcdHRvcDogc29ydGFibGUucGxhY2Vob2xkZXIuY3NzKCBcInRvcFwiICksXG5cdFx0XHRcdFx0bGVmdDogc29ydGFibGUucGxhY2Vob2xkZXIuY3NzKCBcImxlZnRcIiApXG5cdFx0XHRcdH07XG5cblx0XHRcdFx0c29ydGFibGUuX21vdXNlU3RvcCggZXZlbnQgKTtcblxuXHRcdFx0XHQvLyBPbmNlIGRyYWcgaGFzIGVuZGVkLCB0aGUgc29ydGFibGUgc2hvdWxkIHJldHVybiB0byB1c2luZ1xuXHRcdFx0XHQvLyBpdHMgb3JpZ2luYWwgaGVscGVyLCBub3QgdGhlIHNoYXJlZCBoZWxwZXIgZnJvbSBkcmFnZ2FibGVcblx0XHRcdFx0c29ydGFibGUub3B0aW9ucy5oZWxwZXIgPSBzb3J0YWJsZS5vcHRpb25zLl9oZWxwZXI7XG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIFByZXZlbnQgdGhpcyBTb3J0YWJsZSBmcm9tIHJlbW92aW5nIHRoZSBoZWxwZXIuXG5cdFx0XHRcdC8vIEhvd2V2ZXIsIGRvbid0IHNldCB0aGUgZHJhZ2dhYmxlIHRvIHJlbW92ZSB0aGUgaGVscGVyXG5cdFx0XHRcdC8vIGVpdGhlciBhcyBhbm90aGVyIGNvbm5lY3RlZCBTb3J0YWJsZSBtYXkgeWV0IGhhbmRsZSB0aGUgcmVtb3ZhbC5cblx0XHRcdFx0c29ydGFibGUuY2FuY2VsSGVscGVyUmVtb3ZhbCA9IHRydWU7XG5cblx0XHRcdFx0c29ydGFibGUuX3RyaWdnZXIoIFwiZGVhY3RpdmF0ZVwiLCBldmVudCwgdWlTb3J0YWJsZSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblx0ZHJhZzogZnVuY3Rpb24oIGV2ZW50LCB1aSwgZHJhZ2dhYmxlICkge1xuXHRcdCQuZWFjaCggZHJhZ2dhYmxlLnNvcnRhYmxlcywgZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgaW5uZXJtb3N0SW50ZXJzZWN0aW5nID0gZmFsc2UsXG5cdFx0XHRcdHNvcnRhYmxlID0gdGhpcztcblxuXHRcdFx0Ly8gQ29weSBvdmVyIHZhcmlhYmxlcyB0aGF0IHNvcnRhYmxlJ3MgX2ludGVyc2VjdHNXaXRoIHVzZXNcblx0XHRcdHNvcnRhYmxlLnBvc2l0aW9uQWJzID0gZHJhZ2dhYmxlLnBvc2l0aW9uQWJzO1xuXHRcdFx0c29ydGFibGUuaGVscGVyUHJvcG9ydGlvbnMgPSBkcmFnZ2FibGUuaGVscGVyUHJvcG9ydGlvbnM7XG5cdFx0XHRzb3J0YWJsZS5vZmZzZXQuY2xpY2sgPSBkcmFnZ2FibGUub2Zmc2V0LmNsaWNrO1xuXG5cdFx0XHRpZiAoIHNvcnRhYmxlLl9pbnRlcnNlY3RzV2l0aCggc29ydGFibGUuY29udGFpbmVyQ2FjaGUgKSApIHtcblx0XHRcdFx0aW5uZXJtb3N0SW50ZXJzZWN0aW5nID0gdHJ1ZTtcblxuXHRcdFx0XHQkLmVhY2goIGRyYWdnYWJsZS5zb3J0YWJsZXMsIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRcdFx0Ly8gQ29weSBvdmVyIHZhcmlhYmxlcyB0aGF0IHNvcnRhYmxlJ3MgX2ludGVyc2VjdHNXaXRoIHVzZXNcblx0XHRcdFx0XHR0aGlzLnBvc2l0aW9uQWJzID0gZHJhZ2dhYmxlLnBvc2l0aW9uQWJzO1xuXHRcdFx0XHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMgPSBkcmFnZ2FibGUuaGVscGVyUHJvcG9ydGlvbnM7XG5cdFx0XHRcdFx0dGhpcy5vZmZzZXQuY2xpY2sgPSBkcmFnZ2FibGUub2Zmc2V0LmNsaWNrO1xuXG5cdFx0XHRcdFx0aWYgKCB0aGlzICE9PSBzb3J0YWJsZSAmJlxuXHRcdFx0XHRcdFx0XHR0aGlzLl9pbnRlcnNlY3RzV2l0aCggdGhpcy5jb250YWluZXJDYWNoZSApICYmXG5cdFx0XHRcdFx0XHRcdCQuY29udGFpbnMoIHNvcnRhYmxlLmVsZW1lbnRbIDAgXSwgdGhpcy5lbGVtZW50WyAwIF0gKSApIHtcblx0XHRcdFx0XHRcdGlubmVybW9zdEludGVyc2VjdGluZyA9IGZhbHNlO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHJldHVybiBpbm5lcm1vc3RJbnRlcnNlY3Rpbmc7XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBpbm5lcm1vc3RJbnRlcnNlY3RpbmcgKSB7XG5cblx0XHRcdFx0Ly8gSWYgaXQgaW50ZXJzZWN0cywgd2UgdXNlIGEgbGl0dGxlIGlzT3ZlciB2YXJpYWJsZSBhbmQgc2V0IGl0IG9uY2UsXG5cdFx0XHRcdC8vIHNvIHRoYXQgdGhlIG1vdmUtaW4gc3R1ZmYgZ2V0cyBmaXJlZCBvbmx5IG9uY2UuXG5cdFx0XHRcdGlmICggIXNvcnRhYmxlLmlzT3ZlciApIHtcblx0XHRcdFx0XHRzb3J0YWJsZS5pc092ZXIgPSAxO1xuXG5cdFx0XHRcdFx0Ly8gU3RvcmUgZHJhZ2dhYmxlJ3MgcGFyZW50IGluIGNhc2Ugd2UgbmVlZCB0byByZWFwcGVuZCB0byBpdCBsYXRlci5cblx0XHRcdFx0XHRkcmFnZ2FibGUuX3BhcmVudCA9IHVpLmhlbHBlci5wYXJlbnQoKTtcblxuXHRcdFx0XHRcdHNvcnRhYmxlLmN1cnJlbnRJdGVtID0gdWkuaGVscGVyXG5cdFx0XHRcdFx0XHQuYXBwZW5kVG8oIHNvcnRhYmxlLmVsZW1lbnQgKVxuXHRcdFx0XHRcdFx0LmRhdGEoIFwidWktc29ydGFibGUtaXRlbVwiLCB0cnVlICk7XG5cblx0XHRcdFx0XHQvLyBTdG9yZSBoZWxwZXIgb3B0aW9uIHRvIGxhdGVyIHJlc3RvcmUgaXRcblx0XHRcdFx0XHRzb3J0YWJsZS5vcHRpb25zLl9oZWxwZXIgPSBzb3J0YWJsZS5vcHRpb25zLmhlbHBlcjtcblxuXHRcdFx0XHRcdHNvcnRhYmxlLm9wdGlvbnMuaGVscGVyID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gdWkuaGVscGVyWyAwIF07XG5cdFx0XHRcdFx0fTtcblxuXHRcdFx0XHRcdC8vIEZpcmUgdGhlIHN0YXJ0IGV2ZW50cyBvZiB0aGUgc29ydGFibGUgd2l0aCBvdXIgcGFzc2VkIGJyb3dzZXIgZXZlbnQsXG5cdFx0XHRcdFx0Ly8gYW5kIG91ciBvd24gaGVscGVyIChzbyBpdCBkb2Vzbid0IGNyZWF0ZSBhIG5ldyBvbmUpXG5cdFx0XHRcdFx0ZXZlbnQudGFyZ2V0ID0gc29ydGFibGUuY3VycmVudEl0ZW1bIDAgXTtcblx0XHRcdFx0XHRzb3J0YWJsZS5fbW91c2VDYXB0dXJlKCBldmVudCwgdHJ1ZSApO1xuXHRcdFx0XHRcdHNvcnRhYmxlLl9tb3VzZVN0YXJ0KCBldmVudCwgdHJ1ZSwgdHJ1ZSApO1xuXG5cdFx0XHRcdFx0Ly8gQmVjYXVzZSB0aGUgYnJvd3NlciBldmVudCBpcyB3YXkgb2ZmIHRoZSBuZXcgYXBwZW5kZWQgcG9ydGxldCxcblx0XHRcdFx0XHQvLyBtb2RpZnkgbmVjZXNzYXJ5IHZhcmlhYmxlcyB0byByZWZsZWN0IHRoZSBjaGFuZ2VzXG5cdFx0XHRcdFx0c29ydGFibGUub2Zmc2V0LmNsaWNrLnRvcCA9IGRyYWdnYWJsZS5vZmZzZXQuY2xpY2sudG9wO1xuXHRcdFx0XHRcdHNvcnRhYmxlLm9mZnNldC5jbGljay5sZWZ0ID0gZHJhZ2dhYmxlLm9mZnNldC5jbGljay5sZWZ0O1xuXHRcdFx0XHRcdHNvcnRhYmxlLm9mZnNldC5wYXJlbnQubGVmdCAtPSBkcmFnZ2FibGUub2Zmc2V0LnBhcmVudC5sZWZ0IC1cblx0XHRcdFx0XHRcdHNvcnRhYmxlLm9mZnNldC5wYXJlbnQubGVmdDtcblx0XHRcdFx0XHRzb3J0YWJsZS5vZmZzZXQucGFyZW50LnRvcCAtPSBkcmFnZ2FibGUub2Zmc2V0LnBhcmVudC50b3AgLVxuXHRcdFx0XHRcdFx0c29ydGFibGUub2Zmc2V0LnBhcmVudC50b3A7XG5cblx0XHRcdFx0XHRkcmFnZ2FibGUuX3RyaWdnZXIoIFwidG9Tb3J0YWJsZVwiLCBldmVudCApO1xuXG5cdFx0XHRcdFx0Ly8gSW5mb3JtIGRyYWdnYWJsZSB0aGF0IHRoZSBoZWxwZXIgaXMgaW4gYSB2YWxpZCBkcm9wIHpvbmUsXG5cdFx0XHRcdFx0Ly8gdXNlZCBzb2xlbHkgaW4gdGhlIHJldmVydCBvcHRpb24gdG8gaGFuZGxlIFwidmFsaWQvaW52YWxpZFwiLlxuXHRcdFx0XHRcdGRyYWdnYWJsZS5kcm9wcGVkID0gc29ydGFibGUuZWxlbWVudDtcblxuXHRcdFx0XHRcdC8vIE5lZWQgdG8gcmVmcmVzaFBvc2l0aW9ucyBvZiBhbGwgc29ydGFibGVzIGluIHRoZSBjYXNlIHRoYXRcblx0XHRcdFx0XHQvLyBhZGRpbmcgdG8gb25lIHNvcnRhYmxlIGNoYW5nZXMgdGhlIGxvY2F0aW9uIG9mIHRoZSBvdGhlciBzb3J0YWJsZXMgKCM5Njc1KVxuXHRcdFx0XHRcdCQuZWFjaCggZHJhZ2dhYmxlLnNvcnRhYmxlcywgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnJlZnJlc2hQb3NpdGlvbnMoKTtcblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0XHQvLyBIYWNrIHNvIHJlY2VpdmUvdXBkYXRlIGNhbGxiYWNrcyB3b3JrIChtb3N0bHkpXG5cdFx0XHRcdFx0ZHJhZ2dhYmxlLmN1cnJlbnRJdGVtID0gZHJhZ2dhYmxlLmVsZW1lbnQ7XG5cdFx0XHRcdFx0c29ydGFibGUuZnJvbU91dHNpZGUgPSBkcmFnZ2FibGU7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIHNvcnRhYmxlLmN1cnJlbnRJdGVtICkge1xuXHRcdFx0XHRcdHNvcnRhYmxlLl9tb3VzZURyYWcoIGV2ZW50ICk7XG5cblx0XHRcdFx0XHQvLyBDb3B5IHRoZSBzb3J0YWJsZSdzIHBvc2l0aW9uIGJlY2F1c2UgdGhlIGRyYWdnYWJsZSdzIGNhbiBwb3RlbnRpYWxseSByZWZsZWN0XG5cdFx0XHRcdFx0Ly8gYSByZWxhdGl2ZSBwb3NpdGlvbiwgd2hpbGUgc29ydGFibGUgaXMgYWx3YXlzIGFic29sdXRlLCB3aGljaCB0aGUgZHJhZ2dlZFxuXHRcdFx0XHRcdC8vIGVsZW1lbnQgaGFzIG5vdyBiZWNvbWUuICgjODgwOSlcblx0XHRcdFx0XHR1aS5wb3NpdGlvbiA9IHNvcnRhYmxlLnBvc2l0aW9uO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIElmIGl0IGRvZXNuJ3QgaW50ZXJzZWN0IHdpdGggdGhlIHNvcnRhYmxlLCBhbmQgaXQgaW50ZXJzZWN0ZWQgYmVmb3JlLFxuXHRcdFx0XHQvLyB3ZSBmYWtlIHRoZSBkcmFnIHN0b3Agb2YgdGhlIHNvcnRhYmxlLCBidXQgbWFrZSBzdXJlIGl0IGRvZXNuJ3QgcmVtb3ZlXG5cdFx0XHRcdC8vIHRoZSBoZWxwZXIgYnkgdXNpbmcgY2FuY2VsSGVscGVyUmVtb3ZhbC5cblx0XHRcdFx0aWYgKCBzb3J0YWJsZS5pc092ZXIgKSB7XG5cblx0XHRcdFx0XHRzb3J0YWJsZS5pc092ZXIgPSAwO1xuXHRcdFx0XHRcdHNvcnRhYmxlLmNhbmNlbEhlbHBlclJlbW92YWwgPSB0cnVlO1xuXG5cdFx0XHRcdFx0Ly8gQ2FsbGluZyBzb3J0YWJsZSdzIG1vdXNlU3RvcCB3b3VsZCB0cmlnZ2VyIGEgcmV2ZXJ0LFxuXHRcdFx0XHRcdC8vIHNvIHJldmVydCBtdXN0IGJlIHRlbXBvcmFyaWx5IGZhbHNlIHVudGlsIGFmdGVyIG1vdXNlU3RvcCBpcyBjYWxsZWQuXG5cdFx0XHRcdFx0c29ydGFibGUub3B0aW9ucy5fcmV2ZXJ0ID0gc29ydGFibGUub3B0aW9ucy5yZXZlcnQ7XG5cdFx0XHRcdFx0c29ydGFibGUub3B0aW9ucy5yZXZlcnQgPSBmYWxzZTtcblxuXHRcdFx0XHRcdHNvcnRhYmxlLl90cmlnZ2VyKCBcIm91dFwiLCBldmVudCwgc29ydGFibGUuX3VpSGFzaCggc29ydGFibGUgKSApO1xuXHRcdFx0XHRcdHNvcnRhYmxlLl9tb3VzZVN0b3AoIGV2ZW50LCB0cnVlICk7XG5cblx0XHRcdFx0XHQvLyBSZXN0b3JlIHNvcnRhYmxlIGJlaGF2aW9ycyB0aGF0IHdlcmUgbW9kZmllZFxuXHRcdFx0XHRcdC8vIHdoZW4gdGhlIGRyYWdnYWJsZSBlbnRlcmVkIHRoZSBzb3J0YWJsZSBhcmVhICgjOTQ4MSlcblx0XHRcdFx0XHRzb3J0YWJsZS5vcHRpb25zLnJldmVydCA9IHNvcnRhYmxlLm9wdGlvbnMuX3JldmVydDtcblx0XHRcdFx0XHRzb3J0YWJsZS5vcHRpb25zLmhlbHBlciA9IHNvcnRhYmxlLm9wdGlvbnMuX2hlbHBlcjtcblxuXHRcdFx0XHRcdGlmICggc29ydGFibGUucGxhY2Vob2xkZXIgKSB7XG5cdFx0XHRcdFx0XHRzb3J0YWJsZS5wbGFjZWhvbGRlci5yZW1vdmUoKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBSZXN0b3JlIGFuZCByZWNhbGN1bGF0ZSB0aGUgZHJhZ2dhYmxlJ3Mgb2Zmc2V0IGNvbnNpZGVyaW5nIHRoZSBzb3J0YWJsZVxuXHRcdFx0XHRcdC8vIG1heSBoYXZlIG1vZGlmaWVkIHRoZW0gaW4gdW5leHBlY3RlZCB3YXlzLiAoIzg4MDksICMxMDY2OSlcblx0XHRcdFx0XHR1aS5oZWxwZXIuYXBwZW5kVG8oIGRyYWdnYWJsZS5fcGFyZW50ICk7XG5cdFx0XHRcdFx0ZHJhZ2dhYmxlLl9yZWZyZXNoT2Zmc2V0cyggZXZlbnQgKTtcblx0XHRcdFx0XHR1aS5wb3NpdGlvbiA9IGRyYWdnYWJsZS5fZ2VuZXJhdGVQb3NpdGlvbiggZXZlbnQsIHRydWUgKTtcblxuXHRcdFx0XHRcdGRyYWdnYWJsZS5fdHJpZ2dlciggXCJmcm9tU29ydGFibGVcIiwgZXZlbnQgKTtcblxuXHRcdFx0XHRcdC8vIEluZm9ybSBkcmFnZ2FibGUgdGhhdCB0aGUgaGVscGVyIGlzIG5vIGxvbmdlciBpbiBhIHZhbGlkIGRyb3Agem9uZVxuXHRcdFx0XHRcdGRyYWdnYWJsZS5kcm9wcGVkID0gZmFsc2U7XG5cblx0XHRcdFx0XHQvLyBOZWVkIHRvIHJlZnJlc2hQb3NpdGlvbnMgb2YgYWxsIHNvcnRhYmxlcyBqdXN0IGluIGNhc2UgcmVtb3Zpbmdcblx0XHRcdFx0XHQvLyBmcm9tIG9uZSBzb3J0YWJsZSBjaGFuZ2VzIHRoZSBsb2NhdGlvbiBvZiBvdGhlciBzb3J0YWJsZXMgKCM5Njc1KVxuXHRcdFx0XHRcdCQuZWFjaCggZHJhZ2dhYmxlLnNvcnRhYmxlcywgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnJlZnJlc2hQb3NpdGlvbnMoKTtcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9ICk7XG5cdH1cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcImRyYWdnYWJsZVwiLCBcImN1cnNvclwiLCB7XG5cdHN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpbnN0YW5jZSApIHtcblx0XHR2YXIgdCA9ICQoIFwiYm9keVwiICksXG5cdFx0XHRvID0gaW5zdGFuY2Uub3B0aW9ucztcblxuXHRcdGlmICggdC5jc3MoIFwiY3Vyc29yXCIgKSApIHtcblx0XHRcdG8uX2N1cnNvciA9IHQuY3NzKCBcImN1cnNvclwiICk7XG5cdFx0fVxuXHRcdHQuY3NzKCBcImN1cnNvclwiLCBvLmN1cnNvciApO1xuXHR9LFxuXHRzdG9wOiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpbnN0YW5jZSApIHtcblx0XHR2YXIgbyA9IGluc3RhbmNlLm9wdGlvbnM7XG5cdFx0aWYgKCBvLl9jdXJzb3IgKSB7XG5cdFx0XHQkKCBcImJvZHlcIiApLmNzcyggXCJjdXJzb3JcIiwgby5fY3Vyc29yICk7XG5cdFx0fVxuXHR9XG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJkcmFnZ2FibGVcIiwgXCJvcGFjaXR5XCIsIHtcblx0c3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgdWksIGluc3RhbmNlICkge1xuXHRcdHZhciB0ID0gJCggdWkuaGVscGVyICksXG5cdFx0XHRvID0gaW5zdGFuY2Uub3B0aW9ucztcblx0XHRpZiAoIHQuY3NzKCBcIm9wYWNpdHlcIiApICkge1xuXHRcdFx0by5fb3BhY2l0eSA9IHQuY3NzKCBcIm9wYWNpdHlcIiApO1xuXHRcdH1cblx0XHR0LmNzcyggXCJvcGFjaXR5XCIsIG8ub3BhY2l0eSApO1xuXHR9LFxuXHRzdG9wOiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpbnN0YW5jZSApIHtcblx0XHR2YXIgbyA9IGluc3RhbmNlLm9wdGlvbnM7XG5cdFx0aWYgKCBvLl9vcGFjaXR5ICkge1xuXHRcdFx0JCggdWkuaGVscGVyICkuY3NzKCBcIm9wYWNpdHlcIiwgby5fb3BhY2l0eSApO1xuXHRcdH1cblx0fVxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwiZHJhZ2dhYmxlXCIsIFwic2Nyb2xsXCIsIHtcblx0c3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgdWksIGkgKSB7XG5cdFx0aWYgKCAhaS5zY3JvbGxQYXJlbnROb3RIaWRkZW4gKSB7XG5cdFx0XHRpLnNjcm9sbFBhcmVudE5vdEhpZGRlbiA9IGkuaGVscGVyLnNjcm9sbFBhcmVudCggZmFsc2UgKTtcblx0XHR9XG5cblx0XHRpZiAoIGkuc2Nyb2xsUGFyZW50Tm90SGlkZGVuWyAwIF0gIT09IGkuZG9jdW1lbnRbIDAgXSAmJlxuXHRcdFx0XHRpLnNjcm9sbFBhcmVudE5vdEhpZGRlblsgMCBdLnRhZ05hbWUgIT09IFwiSFRNTFwiICkge1xuXHRcdFx0aS5vdmVyZmxvd09mZnNldCA9IGkuc2Nyb2xsUGFyZW50Tm90SGlkZGVuLm9mZnNldCgpO1xuXHRcdH1cblx0fSxcblx0ZHJhZzogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaSAgKSB7XG5cblx0XHR2YXIgbyA9IGkub3B0aW9ucyxcblx0XHRcdHNjcm9sbGVkID0gZmFsc2UsXG5cdFx0XHRzY3JvbGxQYXJlbnQgPSBpLnNjcm9sbFBhcmVudE5vdEhpZGRlblsgMCBdLFxuXHRcdFx0ZG9jdW1lbnQgPSBpLmRvY3VtZW50WyAwIF07XG5cblx0XHRpZiAoIHNjcm9sbFBhcmVudCAhPT0gZG9jdW1lbnQgJiYgc2Nyb2xsUGFyZW50LnRhZ05hbWUgIT09IFwiSFRNTFwiICkge1xuXHRcdFx0aWYgKCAhby5heGlzIHx8IG8uYXhpcyAhPT0gXCJ4XCIgKSB7XG5cdFx0XHRcdGlmICggKCBpLm92ZXJmbG93T2Zmc2V0LnRvcCArIHNjcm9sbFBhcmVudC5vZmZzZXRIZWlnaHQgKSAtIGV2ZW50LnBhZ2VZIDxcblx0XHRcdFx0XHRcdG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsUGFyZW50LnNjcm9sbFRvcCA9IHNjcm9sbGVkID0gc2Nyb2xsUGFyZW50LnNjcm9sbFRvcCArIG8uc2Nyb2xsU3BlZWQ7XG5cdFx0XHRcdH0gZWxzZSBpZiAoIGV2ZW50LnBhZ2VZIC0gaS5vdmVyZmxvd09mZnNldC50b3AgPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbFBhcmVudC5zY3JvbGxUb3AgPSBzY3JvbGxlZCA9IHNjcm9sbFBhcmVudC5zY3JvbGxUb3AgLSBvLnNjcm9sbFNwZWVkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGlmICggIW8uYXhpcyB8fCBvLmF4aXMgIT09IFwieVwiICkge1xuXHRcdFx0XHRpZiAoICggaS5vdmVyZmxvd09mZnNldC5sZWZ0ICsgc2Nyb2xsUGFyZW50Lm9mZnNldFdpZHRoICkgLSBldmVudC5wYWdlWCA8XG5cdFx0XHRcdFx0XHRvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0ID0gc2Nyb2xsZWQgPSBzY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCArIG8uc2Nyb2xsU3BlZWQ7XG5cdFx0XHRcdH0gZWxzZSBpZiAoIGV2ZW50LnBhZ2VYIC0gaS5vdmVyZmxvd09mZnNldC5sZWZ0IDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCA9IHNjcm9sbGVkID0gc2Nyb2xsUGFyZW50LnNjcm9sbExlZnQgLSBvLnNjcm9sbFNwZWVkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoICFvLmF4aXMgfHwgby5heGlzICE9PSBcInhcIiApIHtcblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWSAtICQoIGRvY3VtZW50ICkuc2Nyb2xsVG9wKCkgPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbGVkID0gJCggZG9jdW1lbnQgKS5zY3JvbGxUb3AoICQoIGRvY3VtZW50ICkuc2Nyb2xsVG9wKCkgLSBvLnNjcm9sbFNwZWVkICk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoICQoIHdpbmRvdyApLmhlaWdodCgpIC0gKCBldmVudC5wYWdlWSAtICQoIGRvY3VtZW50ICkuc2Nyb2xsVG9wKCkgKSA8XG5cdFx0XHRcdFx0XHRvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbGVkID0gJCggZG9jdW1lbnQgKS5zY3JvbGxUb3AoICQoIGRvY3VtZW50ICkuc2Nyb2xsVG9wKCkgKyBvLnNjcm9sbFNwZWVkICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhby5heGlzIHx8IG8uYXhpcyAhPT0gXCJ5XCIgKSB7XG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVggLSAkKCBkb2N1bWVudCApLnNjcm9sbExlZnQoKSA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsZWQgPSAkKCBkb2N1bWVudCApLnNjcm9sbExlZnQoXG5cdFx0XHRcdFx0XHQkKCBkb2N1bWVudCApLnNjcm9sbExlZnQoKSAtIG8uc2Nyb2xsU3BlZWRcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCAkKCB3aW5kb3cgKS53aWR0aCgpIC0gKCBldmVudC5wYWdlWCAtICQoIGRvY3VtZW50ICkuc2Nyb2xsTGVmdCgpICkgPFxuXHRcdFx0XHRcdFx0by5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxlZCA9ICQoIGRvY3VtZW50ICkuc2Nyb2xsTGVmdChcblx0XHRcdFx0XHRcdCQoIGRvY3VtZW50ICkuc2Nyb2xsTGVmdCgpICsgby5zY3JvbGxTcGVlZFxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggc2Nyb2xsZWQgIT09IGZhbHNlICYmICQudWkuZGRtYW5hZ2VyICYmICFvLmRyb3BCZWhhdmlvdXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5wcmVwYXJlT2Zmc2V0cyggaSwgZXZlbnQgKTtcblx0XHR9XG5cblx0fVxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwiZHJhZ2dhYmxlXCIsIFwic25hcFwiLCB7XG5cdHN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpICkge1xuXG5cdFx0dmFyIG8gPSBpLm9wdGlvbnM7XG5cblx0XHRpLnNuYXBFbGVtZW50cyA9IFtdO1xuXG5cdFx0JCggby5zbmFwLmNvbnN0cnVjdG9yICE9PSBTdHJpbmcgPyAoIG8uc25hcC5pdGVtcyB8fCBcIjpkYXRhKHVpLWRyYWdnYWJsZSlcIiApIDogby5zbmFwIClcblx0XHRcdC5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyICR0ID0gJCggdGhpcyApLFxuXHRcdFx0XHRcdCRvID0gJHQub2Zmc2V0KCk7XG5cdFx0XHRcdGlmICggdGhpcyAhPT0gaS5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRcdFx0aS5zbmFwRWxlbWVudHMucHVzaCgge1xuXHRcdFx0XHRcdFx0aXRlbTogdGhpcyxcblx0XHRcdFx0XHRcdHdpZHRoOiAkdC5vdXRlcldpZHRoKCksIGhlaWdodDogJHQub3V0ZXJIZWlnaHQoKSxcblx0XHRcdFx0XHRcdHRvcDogJG8udG9wLCBsZWZ0OiAkby5sZWZ0XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cblx0fSxcblx0ZHJhZzogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaW5zdCApIHtcblxuXHRcdHZhciB0cywgYnMsIGxzLCBycywgbCwgciwgdCwgYiwgaSwgZmlyc3QsXG5cdFx0XHRvID0gaW5zdC5vcHRpb25zLFxuXHRcdFx0ZCA9IG8uc25hcFRvbGVyYW5jZSxcblx0XHRcdHgxID0gdWkub2Zmc2V0LmxlZnQsIHgyID0geDEgKyBpbnN0LmhlbHBlclByb3BvcnRpb25zLndpZHRoLFxuXHRcdFx0eTEgPSB1aS5vZmZzZXQudG9wLCB5MiA9IHkxICsgaW5zdC5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQ7XG5cblx0XHRmb3IgKCBpID0gaW5zdC5zbmFwRWxlbWVudHMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cblx0XHRcdGwgPSBpbnN0LnNuYXBFbGVtZW50c1sgaSBdLmxlZnQgLSBpbnN0Lm1hcmdpbnMubGVmdDtcblx0XHRcdHIgPSBsICsgaW5zdC5zbmFwRWxlbWVudHNbIGkgXS53aWR0aDtcblx0XHRcdHQgPSBpbnN0LnNuYXBFbGVtZW50c1sgaSBdLnRvcCAtIGluc3QubWFyZ2lucy50b3A7XG5cdFx0XHRiID0gdCArIGluc3Quc25hcEVsZW1lbnRzWyBpIF0uaGVpZ2h0O1xuXG5cdFx0XHRpZiAoIHgyIDwgbCAtIGQgfHwgeDEgPiByICsgZCB8fCB5MiA8IHQgLSBkIHx8IHkxID4gYiArIGQgfHxcblx0XHRcdFx0XHQhJC5jb250YWlucyggaW5zdC5zbmFwRWxlbWVudHNbIGkgXS5pdGVtLm93bmVyRG9jdW1lbnQsXG5cdFx0XHRcdFx0aW5zdC5zbmFwRWxlbWVudHNbIGkgXS5pdGVtICkgKSB7XG5cdFx0XHRcdGlmICggaW5zdC5zbmFwRWxlbWVudHNbIGkgXS5zbmFwcGluZyApIHtcblx0XHRcdFx0XHQoIGluc3Qub3B0aW9ucy5zbmFwLnJlbGVhc2UgJiZcblx0XHRcdFx0XHRcdGluc3Qub3B0aW9ucy5zbmFwLnJlbGVhc2UuY2FsbChcblx0XHRcdFx0XHRcdFx0aW5zdC5lbGVtZW50LFxuXHRcdFx0XHRcdFx0XHRldmVudCxcblx0XHRcdFx0XHRcdFx0JC5leHRlbmQoIGluc3QuX3VpSGFzaCgpLCB7IHNuYXBJdGVtOiBpbnN0LnNuYXBFbGVtZW50c1sgaSBdLml0ZW0gfSApXG5cdFx0XHRcdFx0XHQpICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aW5zdC5zbmFwRWxlbWVudHNbIGkgXS5zbmFwcGluZyA9IGZhbHNlO1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBvLnNuYXBNb2RlICE9PSBcImlubmVyXCIgKSB7XG5cdFx0XHRcdHRzID0gTWF0aC5hYnMoIHQgLSB5MiApIDw9IGQ7XG5cdFx0XHRcdGJzID0gTWF0aC5hYnMoIGIgLSB5MSApIDw9IGQ7XG5cdFx0XHRcdGxzID0gTWF0aC5hYnMoIGwgLSB4MiApIDw9IGQ7XG5cdFx0XHRcdHJzID0gTWF0aC5hYnMoIHIgLSB4MSApIDw9IGQ7XG5cdFx0XHRcdGlmICggdHMgKSB7XG5cdFx0XHRcdFx0dWkucG9zaXRpb24udG9wID0gaW5zdC5fY29udmVydFBvc2l0aW9uVG8oIFwicmVsYXRpdmVcIiwge1xuXHRcdFx0XHRcdFx0dG9wOiB0IC0gaW5zdC5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQsXG5cdFx0XHRcdFx0XHRsZWZ0OiAwXG5cdFx0XHRcdFx0fSApLnRvcDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGJzICkge1xuXHRcdFx0XHRcdHVpLnBvc2l0aW9uLnRvcCA9IGluc3QuX2NvbnZlcnRQb3NpdGlvblRvKCBcInJlbGF0aXZlXCIsIHtcblx0XHRcdFx0XHRcdHRvcDogYixcblx0XHRcdFx0XHRcdGxlZnQ6IDBcblx0XHRcdFx0XHR9ICkudG9wO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggbHMgKSB7XG5cdFx0XHRcdFx0dWkucG9zaXRpb24ubGVmdCA9IGluc3QuX2NvbnZlcnRQb3NpdGlvblRvKCBcInJlbGF0aXZlXCIsIHtcblx0XHRcdFx0XHRcdHRvcDogMCxcblx0XHRcdFx0XHRcdGxlZnQ6IGwgLSBpbnN0LmhlbHBlclByb3BvcnRpb25zLndpZHRoXG5cdFx0XHRcdFx0fSApLmxlZnQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBycyApIHtcblx0XHRcdFx0XHR1aS5wb3NpdGlvbi5sZWZ0ID0gaW5zdC5fY29udmVydFBvc2l0aW9uVG8oIFwicmVsYXRpdmVcIiwge1xuXHRcdFx0XHRcdFx0dG9wOiAwLFxuXHRcdFx0XHRcdFx0bGVmdDogclxuXHRcdFx0XHRcdH0gKS5sZWZ0O1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGZpcnN0ID0gKCB0cyB8fCBicyB8fCBscyB8fCBycyApO1xuXG5cdFx0XHRpZiAoIG8uc25hcE1vZGUgIT09IFwib3V0ZXJcIiApIHtcblx0XHRcdFx0dHMgPSBNYXRoLmFicyggdCAtIHkxICkgPD0gZDtcblx0XHRcdFx0YnMgPSBNYXRoLmFicyggYiAtIHkyICkgPD0gZDtcblx0XHRcdFx0bHMgPSBNYXRoLmFicyggbCAtIHgxICkgPD0gZDtcblx0XHRcdFx0cnMgPSBNYXRoLmFicyggciAtIHgyICkgPD0gZDtcblx0XHRcdFx0aWYgKCB0cyApIHtcblx0XHRcdFx0XHR1aS5wb3NpdGlvbi50b3AgPSBpbnN0Ll9jb252ZXJ0UG9zaXRpb25UbyggXCJyZWxhdGl2ZVwiLCB7XG5cdFx0XHRcdFx0XHR0b3A6IHQsXG5cdFx0XHRcdFx0XHRsZWZ0OiAwXG5cdFx0XHRcdFx0fSApLnRvcDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGJzICkge1xuXHRcdFx0XHRcdHVpLnBvc2l0aW9uLnRvcCA9IGluc3QuX2NvbnZlcnRQb3NpdGlvblRvKCBcInJlbGF0aXZlXCIsIHtcblx0XHRcdFx0XHRcdHRvcDogYiAtIGluc3QuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0LFxuXHRcdFx0XHRcdFx0bGVmdDogMFxuXHRcdFx0XHRcdH0gKS50b3A7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBscyApIHtcblx0XHRcdFx0XHR1aS5wb3NpdGlvbi5sZWZ0ID0gaW5zdC5fY29udmVydFBvc2l0aW9uVG8oIFwicmVsYXRpdmVcIiwge1xuXHRcdFx0XHRcdFx0dG9wOiAwLFxuXHRcdFx0XHRcdFx0bGVmdDogbFxuXHRcdFx0XHRcdH0gKS5sZWZ0O1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggcnMgKSB7XG5cdFx0XHRcdFx0dWkucG9zaXRpb24ubGVmdCA9IGluc3QuX2NvbnZlcnRQb3NpdGlvblRvKCBcInJlbGF0aXZlXCIsIHtcblx0XHRcdFx0XHRcdHRvcDogMCxcblx0XHRcdFx0XHRcdGxlZnQ6IHIgLSBpbnN0LmhlbHBlclByb3BvcnRpb25zLndpZHRoXG5cdFx0XHRcdFx0fSApLmxlZnQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhaW5zdC5zbmFwRWxlbWVudHNbIGkgXS5zbmFwcGluZyAmJiAoIHRzIHx8IGJzIHx8IGxzIHx8IHJzIHx8IGZpcnN0ICkgKSB7XG5cdFx0XHRcdCggaW5zdC5vcHRpb25zLnNuYXAuc25hcCAmJlxuXHRcdFx0XHRcdGluc3Qub3B0aW9ucy5zbmFwLnNuYXAuY2FsbChcblx0XHRcdFx0XHRcdGluc3QuZWxlbWVudCxcblx0XHRcdFx0XHRcdGV2ZW50LFxuXHRcdFx0XHRcdFx0JC5leHRlbmQoIGluc3QuX3VpSGFzaCgpLCB7XG5cdFx0XHRcdFx0XHRcdHNuYXBJdGVtOiBpbnN0LnNuYXBFbGVtZW50c1sgaSBdLml0ZW1cblx0XHRcdFx0XHRcdH0gKSApICk7XG5cdFx0XHR9XG5cdFx0XHRpbnN0LnNuYXBFbGVtZW50c1sgaSBdLnNuYXBwaW5nID0gKCB0cyB8fCBicyB8fCBscyB8fCBycyB8fCBmaXJzdCApO1xuXG5cdFx0fVxuXG5cdH1cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcImRyYWdnYWJsZVwiLCBcInN0YWNrXCIsIHtcblx0c3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgdWksIGluc3RhbmNlICkge1xuXHRcdHZhciBtaW4sXG5cdFx0XHRvID0gaW5zdGFuY2Uub3B0aW9ucyxcblx0XHRcdGdyb3VwID0gJC5tYWtlQXJyYXkoICQoIG8uc3RhY2sgKSApLnNvcnQoIGZ1bmN0aW9uKCBhLCBiICkge1xuXHRcdFx0XHRyZXR1cm4gKCBwYXJzZUludCggJCggYSApLmNzcyggXCJ6SW5kZXhcIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdFx0KCBwYXJzZUludCggJCggYiApLmNzcyggXCJ6SW5kZXhcIiApLCAxMCApIHx8IDAgKTtcblx0XHRcdH0gKTtcblxuXHRcdGlmICggIWdyb3VwLmxlbmd0aCApIHsgcmV0dXJuOyB9XG5cblx0XHRtaW4gPSBwYXJzZUludCggJCggZ3JvdXBbIDAgXSApLmNzcyggXCJ6SW5kZXhcIiApLCAxMCApIHx8IDA7XG5cdFx0JCggZ3JvdXAgKS5lYWNoKCBmdW5jdGlvbiggaSApIHtcblx0XHRcdCQoIHRoaXMgKS5jc3MoIFwiekluZGV4XCIsIG1pbiArIGkgKTtcblx0XHR9ICk7XG5cdFx0dGhpcy5jc3MoIFwiekluZGV4XCIsICggbWluICsgZ3JvdXAubGVuZ3RoICkgKTtcblx0fVxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwiZHJhZ2dhYmxlXCIsIFwiekluZGV4XCIsIHtcblx0c3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgdWksIGluc3RhbmNlICkge1xuXHRcdHZhciB0ID0gJCggdWkuaGVscGVyICksXG5cdFx0XHRvID0gaW5zdGFuY2Uub3B0aW9ucztcblxuXHRcdGlmICggdC5jc3MoIFwiekluZGV4XCIgKSApIHtcblx0XHRcdG8uX3pJbmRleCA9IHQuY3NzKCBcInpJbmRleFwiICk7XG5cdFx0fVxuXHRcdHQuY3NzKCBcInpJbmRleFwiLCBvLnpJbmRleCApO1xuXHR9LFxuXHRzdG9wOiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpbnN0YW5jZSApIHtcblx0XHR2YXIgbyA9IGluc3RhbmNlLm9wdGlvbnM7XG5cblx0XHRpZiAoIG8uX3pJbmRleCApIHtcblx0XHRcdCQoIHVpLmhlbHBlciApLmNzcyggXCJ6SW5kZXhcIiwgby5fekluZGV4ICk7XG5cdFx0fVxuXHR9XG59ICk7XG5cbnZhciB3aWRnZXRzRHJhZ2dhYmxlID0gJC51aS5kcmFnZ2FibGU7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgUmVzaXphYmxlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBSZXNpemFibGVcbi8vPj5ncm91cDogSW50ZXJhY3Rpb25zXG4vLz4+ZGVzY3JpcHRpb246IEVuYWJsZXMgcmVzaXplIGZ1bmN0aW9uYWxpdHkgZm9yIGFueSBlbGVtZW50LlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3Jlc2l6YWJsZS9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9yZXNpemFibGUvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9yZXNpemFibGUuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbiQud2lkZ2V0KCBcInVpLnJlc2l6YWJsZVwiLCAkLnVpLm1vdXNlLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdHdpZGdldEV2ZW50UHJlZml4OiBcInJlc2l6ZVwiLFxuXHRvcHRpb25zOiB7XG5cdFx0YWxzb1Jlc2l6ZTogZmFsc2UsXG5cdFx0YW5pbWF0ZTogZmFsc2UsXG5cdFx0YW5pbWF0ZUR1cmF0aW9uOiBcInNsb3dcIixcblx0XHRhbmltYXRlRWFzaW5nOiBcInN3aW5nXCIsXG5cdFx0YXNwZWN0UmF0aW86IGZhbHNlLFxuXHRcdGF1dG9IaWRlOiBmYWxzZSxcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLXJlc2l6YWJsZS1zZVwiOiBcInVpLWljb24gdWktaWNvbi1ncmlwc21hbGwtZGlhZ29uYWwtc2VcIlxuXHRcdH0sXG5cdFx0Y29udGFpbm1lbnQ6IGZhbHNlLFxuXHRcdGdob3N0OiBmYWxzZSxcblx0XHRncmlkOiBmYWxzZSxcblx0XHRoYW5kbGVzOiBcImUscyxzZVwiLFxuXHRcdGhlbHBlcjogZmFsc2UsXG5cdFx0bWF4SGVpZ2h0OiBudWxsLFxuXHRcdG1heFdpZHRoOiBudWxsLFxuXHRcdG1pbkhlaWdodDogMTAsXG5cdFx0bWluV2lkdGg6IDEwLFxuXG5cdFx0Ly8gU2VlICM3OTYwXG5cdFx0ekluZGV4OiA5MCxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdHJlc2l6ZTogbnVsbCxcblx0XHRzdGFydDogbnVsbCxcblx0XHRzdG9wOiBudWxsXG5cdH0sXG5cblx0X251bTogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHJldHVybiBwYXJzZUZsb2F0KCB2YWx1ZSApIHx8IDA7XG5cdH0sXG5cblx0X2lzTnVtYmVyOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0cmV0dXJuICFpc05hTiggcGFyc2VGbG9hdCggdmFsdWUgKSApO1xuXHR9LFxuXG5cdF9oYXNTY3JvbGw6IGZ1bmN0aW9uKCBlbCwgYSApIHtcblxuXHRcdGlmICggJCggZWwgKS5jc3MoIFwib3ZlcmZsb3dcIiApID09PSBcImhpZGRlblwiICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHZhciBzY3JvbGwgPSAoIGEgJiYgYSA9PT0gXCJsZWZ0XCIgKSA/IFwic2Nyb2xsTGVmdFwiIDogXCJzY3JvbGxUb3BcIixcblx0XHRcdGhhcyA9IGZhbHNlO1xuXG5cdFx0aWYgKCBlbFsgc2Nyb2xsIF0gPiAwICkge1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXG5cdFx0Ly8gVE9ETzogZGV0ZXJtaW5lIHdoaWNoIGNhc2VzIGFjdHVhbGx5IGNhdXNlIHRoaXMgdG8gaGFwcGVuXG5cdFx0Ly8gaWYgdGhlIGVsZW1lbnQgZG9lc24ndCBoYXZlIHRoZSBzY3JvbGwgc2V0LCBzZWUgaWYgaXQncyBwb3NzaWJsZSB0b1xuXHRcdC8vIHNldCB0aGUgc2Nyb2xsXG5cdFx0ZWxbIHNjcm9sbCBdID0gMTtcblx0XHRoYXMgPSAoIGVsWyBzY3JvbGwgXSA+IDAgKTtcblx0XHRlbFsgc2Nyb2xsIF0gPSAwO1xuXHRcdHJldHVybiBoYXM7XG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cblx0XHR2YXIgbWFyZ2lucyxcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHR0aGF0ID0gdGhpcztcblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1yZXNpemFibGVcIiApO1xuXG5cdFx0JC5leHRlbmQoIHRoaXMsIHtcblx0XHRcdF9hc3BlY3RSYXRpbzogISEoIG8uYXNwZWN0UmF0aW8gKSxcblx0XHRcdGFzcGVjdFJhdGlvOiBvLmFzcGVjdFJhdGlvLFxuXHRcdFx0b3JpZ2luYWxFbGVtZW50OiB0aGlzLmVsZW1lbnQsXG5cdFx0XHRfcHJvcG9ydGlvbmFsbHlSZXNpemVFbGVtZW50czogW10sXG5cdFx0XHRfaGVscGVyOiBvLmhlbHBlciB8fCBvLmdob3N0IHx8IG8uYW5pbWF0ZSA/IG8uaGVscGVyIHx8IFwidWktcmVzaXphYmxlLWhlbHBlclwiIDogbnVsbFxuXHRcdH0gKTtcblxuXHRcdC8vIFdyYXAgdGhlIGVsZW1lbnQgaWYgaXQgY2Fubm90IGhvbGQgY2hpbGQgbm9kZXNcblx0XHRpZiAoIHRoaXMuZWxlbWVudFsgMCBdLm5vZGVOYW1lLm1hdGNoKCAvXihjYW52YXN8dGV4dGFyZWF8aW5wdXR8c2VsZWN0fGJ1dHRvbnxpbWcpJC9pICkgKSB7XG5cblx0XHRcdHRoaXMuZWxlbWVudC53cmFwKFxuXHRcdFx0XHQkKCBcIjxkaXYgY2xhc3M9J3VpLXdyYXBwZXInIHN0eWxlPSdvdmVyZmxvdzogaGlkZGVuOyc+PC9kaXY+XCIgKS5jc3MoIHtcblx0XHRcdFx0XHRwb3NpdGlvbjogdGhpcy5lbGVtZW50LmNzcyggXCJwb3NpdGlvblwiICksXG5cdFx0XHRcdFx0d2lkdGg6IHRoaXMuZWxlbWVudC5vdXRlcldpZHRoKCksXG5cdFx0XHRcdFx0aGVpZ2h0OiB0aGlzLmVsZW1lbnQub3V0ZXJIZWlnaHQoKSxcblx0XHRcdFx0XHR0b3A6IHRoaXMuZWxlbWVudC5jc3MoIFwidG9wXCIgKSxcblx0XHRcdFx0XHRsZWZ0OiB0aGlzLmVsZW1lbnQuY3NzKCBcImxlZnRcIiApXG5cdFx0XHRcdH0gKVxuXHRcdFx0KTtcblxuXHRcdFx0dGhpcy5lbGVtZW50ID0gdGhpcy5lbGVtZW50LnBhcmVudCgpLmRhdGEoXG5cdFx0XHRcdFwidWktcmVzaXphYmxlXCIsIHRoaXMuZWxlbWVudC5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApXG5cdFx0XHQpO1xuXG5cdFx0XHR0aGlzLmVsZW1lbnRJc1dyYXBwZXIgPSB0cnVlO1xuXG5cdFx0XHRtYXJnaW5zID0ge1xuXHRcdFx0XHRtYXJnaW5Ub3A6IHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcyggXCJtYXJnaW5Ub3BcIiApLFxuXHRcdFx0XHRtYXJnaW5SaWdodDogdGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCBcIm1hcmdpblJpZ2h0XCIgKSxcblx0XHRcdFx0bWFyZ2luQm90dG9tOiB0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIFwibWFyZ2luQm90dG9tXCIgKSxcblx0XHRcdFx0bWFyZ2luTGVmdDogdGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCBcIm1hcmdpbkxlZnRcIiApXG5cdFx0XHR9O1xuXG5cdFx0XHR0aGlzLmVsZW1lbnQuY3NzKCBtYXJnaW5zICk7XG5cdFx0XHR0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIFwibWFyZ2luXCIsIDAgKTtcblxuXHRcdFx0Ly8gc3VwcG9ydDogU2FmYXJpXG5cdFx0XHQvLyBQcmV2ZW50IFNhZmFyaSB0ZXh0YXJlYSByZXNpemVcblx0XHRcdHRoaXMub3JpZ2luYWxSZXNpemVTdHlsZSA9IHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcyggXCJyZXNpemVcIiApO1xuXHRcdFx0dGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCBcInJlc2l6ZVwiLCBcIm5vbmVcIiApO1xuXG5cdFx0XHR0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZUVsZW1lbnRzLnB1c2goIHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcygge1xuXHRcdFx0XHRwb3NpdGlvbjogXCJzdGF0aWNcIixcblx0XHRcdFx0em9vbTogMSxcblx0XHRcdFx0ZGlzcGxheTogXCJibG9ja1wiXG5cdFx0XHR9ICkgKTtcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUU5XG5cdFx0XHQvLyBhdm9pZCBJRSBqdW1wIChoYXJkIHNldCB0aGUgbWFyZ2luKVxuXHRcdFx0dGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCBtYXJnaW5zICk7XG5cblx0XHRcdHRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc2V0dXBIYW5kbGVzKCk7XG5cblx0XHRpZiAoIG8uYXV0b0hpZGUgKSB7XG5cdFx0XHQkKCB0aGlzLmVsZW1lbnQgKVxuXHRcdFx0XHQub24oIFwibW91c2VlbnRlclwiLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRpZiAoIG8uZGlzYWJsZWQgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBcInVpLXJlc2l6YWJsZS1hdXRvaGlkZVwiICk7XG5cdFx0XHRcdFx0dGhhdC5faGFuZGxlcy5zaG93KCk7XG5cdFx0XHRcdH0gKVxuXHRcdFx0XHQub24oIFwibW91c2VsZWF2ZVwiLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRpZiAoIG8uZGlzYWJsZWQgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmICggIXRoYXQucmVzaXppbmcgKSB7XG5cdFx0XHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggXCJ1aS1yZXNpemFibGUtYXV0b2hpZGVcIiApO1xuXHRcdFx0XHRcdFx0dGhhdC5faGFuZGxlcy5oaWRlKCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fbW91c2VJbml0KCk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXG5cdFx0dGhpcy5fbW91c2VEZXN0cm95KCk7XG5cblx0XHR2YXIgd3JhcHBlcixcblx0XHRcdF9kZXN0cm95ID0gZnVuY3Rpb24oIGV4cCApIHtcblx0XHRcdFx0JCggZXhwIClcblx0XHRcdFx0XHQucmVtb3ZlRGF0YSggXCJyZXNpemFibGVcIiApXG5cdFx0XHRcdFx0LnJlbW92ZURhdGEoIFwidWktcmVzaXphYmxlXCIgKVxuXHRcdFx0XHRcdC5vZmYoIFwiLnJlc2l6YWJsZVwiIClcblx0XHRcdFx0XHQuZmluZCggXCIudWktcmVzaXphYmxlLWhhbmRsZVwiIClcblx0XHRcdFx0XHRcdC5yZW1vdmUoKTtcblx0XHRcdH07XG5cblx0XHQvLyBUT0RPOiBVbndyYXAgYXQgc2FtZSBET00gcG9zaXRpb25cblx0XHRpZiAoIHRoaXMuZWxlbWVudElzV3JhcHBlciApIHtcblx0XHRcdF9kZXN0cm95KCB0aGlzLmVsZW1lbnQgKTtcblx0XHRcdHdyYXBwZXIgPSB0aGlzLmVsZW1lbnQ7XG5cdFx0XHR0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIHtcblx0XHRcdFx0cG9zaXRpb246IHdyYXBwZXIuY3NzKCBcInBvc2l0aW9uXCIgKSxcblx0XHRcdFx0d2lkdGg6IHdyYXBwZXIub3V0ZXJXaWR0aCgpLFxuXHRcdFx0XHRoZWlnaHQ6IHdyYXBwZXIub3V0ZXJIZWlnaHQoKSxcblx0XHRcdFx0dG9wOiB3cmFwcGVyLmNzcyggXCJ0b3BcIiApLFxuXHRcdFx0XHRsZWZ0OiB3cmFwcGVyLmNzcyggXCJsZWZ0XCIgKVxuXHRcdFx0fSApLmluc2VydEFmdGVyKCB3cmFwcGVyICk7XG5cdFx0XHR3cmFwcGVyLnJlbW92ZSgpO1xuXHRcdH1cblxuXHRcdHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcyggXCJyZXNpemVcIiwgdGhpcy5vcmlnaW5hbFJlc2l6ZVN0eWxlICk7XG5cdFx0X2Rlc3Ryb3koIHRoaXMub3JpZ2luYWxFbGVtZW50ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0c3dpdGNoICgga2V5ICkge1xuXHRcdGNhc2UgXCJoYW5kbGVzXCI6XG5cdFx0XHR0aGlzLl9yZW1vdmVIYW5kbGVzKCk7XG5cdFx0XHR0aGlzLl9zZXR1cEhhbmRsZXMoKTtcblx0XHRcdGJyZWFrO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHRicmVhaztcblx0XHR9XG5cdH0sXG5cblx0X3NldHVwSGFuZGxlczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG8gPSB0aGlzLm9wdGlvbnMsIGhhbmRsZSwgaSwgbiwgaG5hbWUsIGF4aXMsIHRoYXQgPSB0aGlzO1xuXHRcdHRoaXMuaGFuZGxlcyA9IG8uaGFuZGxlcyB8fFxuXHRcdFx0KCAhJCggXCIudWktcmVzaXphYmxlLWhhbmRsZVwiLCB0aGlzLmVsZW1lbnQgKS5sZW5ndGggP1xuXHRcdFx0XHRcImUscyxzZVwiIDoge1xuXHRcdFx0XHRcdG46IFwiLnVpLXJlc2l6YWJsZS1uXCIsXG5cdFx0XHRcdFx0ZTogXCIudWktcmVzaXphYmxlLWVcIixcblx0XHRcdFx0XHRzOiBcIi51aS1yZXNpemFibGUtc1wiLFxuXHRcdFx0XHRcdHc6IFwiLnVpLXJlc2l6YWJsZS13XCIsXG5cdFx0XHRcdFx0c2U6IFwiLnVpLXJlc2l6YWJsZS1zZVwiLFxuXHRcdFx0XHRcdHN3OiBcIi51aS1yZXNpemFibGUtc3dcIixcblx0XHRcdFx0XHRuZTogXCIudWktcmVzaXphYmxlLW5lXCIsXG5cdFx0XHRcdFx0bnc6IFwiLnVpLXJlc2l6YWJsZS1ud1wiXG5cdFx0XHRcdH0gKTtcblxuXHRcdHRoaXMuX2hhbmRsZXMgPSAkKCk7XG5cdFx0aWYgKCB0aGlzLmhhbmRsZXMuY29uc3RydWN0b3IgPT09IFN0cmluZyApIHtcblxuXHRcdFx0aWYgKCB0aGlzLmhhbmRsZXMgPT09IFwiYWxsXCIgKSB7XG5cdFx0XHRcdHRoaXMuaGFuZGxlcyA9IFwibixlLHMsdyxzZSxzdyxuZSxud1wiO1xuXHRcdFx0fVxuXG5cdFx0XHRuID0gdGhpcy5oYW5kbGVzLnNwbGl0KCBcIixcIiApO1xuXHRcdFx0dGhpcy5oYW5kbGVzID0ge307XG5cblx0XHRcdGZvciAoIGkgPSAwOyBpIDwgbi5sZW5ndGg7IGkrKyApIHtcblxuXHRcdFx0XHRoYW5kbGUgPSAkLnRyaW0oIG5bIGkgXSApO1xuXHRcdFx0XHRobmFtZSA9IFwidWktcmVzaXphYmxlLVwiICsgaGFuZGxlO1xuXHRcdFx0XHRheGlzID0gJCggXCI8ZGl2PlwiICk7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCBheGlzLCBcInVpLXJlc2l6YWJsZS1oYW5kbGUgXCIgKyBobmFtZSApO1xuXG5cdFx0XHRcdGF4aXMuY3NzKCB7IHpJbmRleDogby56SW5kZXggfSApO1xuXG5cdFx0XHRcdHRoaXMuaGFuZGxlc1sgaGFuZGxlIF0gPSBcIi51aS1yZXNpemFibGUtXCIgKyBoYW5kbGU7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5hcHBlbmQoIGF4aXMgKTtcblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHRoaXMuX3JlbmRlckF4aXMgPSBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXG5cdFx0XHR2YXIgaSwgYXhpcywgcGFkUG9zLCBwYWRXcmFwcGVyO1xuXG5cdFx0XHR0YXJnZXQgPSB0YXJnZXQgfHwgdGhpcy5lbGVtZW50O1xuXG5cdFx0XHRmb3IgKCBpIGluIHRoaXMuaGFuZGxlcyApIHtcblxuXHRcdFx0XHRpZiAoIHRoaXMuaGFuZGxlc1sgaSBdLmNvbnN0cnVjdG9yID09PSBTdHJpbmcgKSB7XG5cdFx0XHRcdFx0dGhpcy5oYW5kbGVzWyBpIF0gPSB0aGlzLmVsZW1lbnQuY2hpbGRyZW4oIHRoaXMuaGFuZGxlc1sgaSBdICkuZmlyc3QoKS5zaG93KCk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoIHRoaXMuaGFuZGxlc1sgaSBdLmpxdWVyeSB8fCB0aGlzLmhhbmRsZXNbIGkgXS5ub2RlVHlwZSApIHtcblx0XHRcdFx0XHR0aGlzLmhhbmRsZXNbIGkgXSA9ICQoIHRoaXMuaGFuZGxlc1sgaSBdICk7XG5cdFx0XHRcdFx0dGhpcy5fb24oIHRoaXMuaGFuZGxlc1sgaSBdLCB7IFwibW91c2Vkb3duXCI6IHRoYXQuX21vdXNlRG93biB9ICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIHRoaXMuZWxlbWVudElzV3JhcHBlciAmJlxuXHRcdFx0XHRcdFx0dGhpcy5vcmlnaW5hbEVsZW1lbnRbIDAgXVxuXHRcdFx0XHRcdFx0XHQubm9kZU5hbWVcblx0XHRcdFx0XHRcdFx0Lm1hdGNoKCAvXih0ZXh0YXJlYXxpbnB1dHxzZWxlY3R8YnV0dG9uKSQvaSApICkge1xuXHRcdFx0XHRcdGF4aXMgPSAkKCB0aGlzLmhhbmRsZXNbIGkgXSwgdGhpcy5lbGVtZW50ICk7XG5cblx0XHRcdFx0XHRwYWRXcmFwcGVyID0gL3N3fG5lfG53fHNlfG58cy8udGVzdCggaSApID9cblx0XHRcdFx0XHRcdGF4aXMub3V0ZXJIZWlnaHQoKSA6XG5cdFx0XHRcdFx0XHRheGlzLm91dGVyV2lkdGgoKTtcblxuXHRcdFx0XHRcdHBhZFBvcyA9IFsgXCJwYWRkaW5nXCIsXG5cdFx0XHRcdFx0XHQvbmV8bnd8bi8udGVzdCggaSApID8gXCJUb3BcIiA6XG5cdFx0XHRcdFx0XHQvc2V8c3d8cy8udGVzdCggaSApID8gXCJCb3R0b21cIiA6XG5cdFx0XHRcdFx0XHQvXmUkLy50ZXN0KCBpICkgPyBcIlJpZ2h0XCIgOiBcIkxlZnRcIiBdLmpvaW4oIFwiXCIgKTtcblxuXHRcdFx0XHRcdHRhcmdldC5jc3MoIHBhZFBvcywgcGFkV3JhcHBlciApO1xuXG5cdFx0XHRcdFx0dGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemUoKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRoaXMuX2hhbmRsZXMgPSB0aGlzLl9oYW5kbGVzLmFkZCggdGhpcy5oYW5kbGVzWyBpIF0gKTtcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0Ly8gVE9ETzogbWFrZSByZW5kZXJBeGlzIGEgcHJvdG90eXBlIGZ1bmN0aW9uXG5cdFx0dGhpcy5fcmVuZGVyQXhpcyggdGhpcy5lbGVtZW50ICk7XG5cblx0XHR0aGlzLl9oYW5kbGVzID0gdGhpcy5faGFuZGxlcy5hZGQoIHRoaXMuZWxlbWVudC5maW5kKCBcIi51aS1yZXNpemFibGUtaGFuZGxlXCIgKSApO1xuXHRcdHRoaXMuX2hhbmRsZXMuZGlzYWJsZVNlbGVjdGlvbigpO1xuXG5cdFx0dGhpcy5faGFuZGxlcy5vbiggXCJtb3VzZW92ZXJcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoICF0aGF0LnJlc2l6aW5nICkge1xuXHRcdFx0XHRpZiAoIHRoaXMuY2xhc3NOYW1lICkge1xuXHRcdFx0XHRcdGF4aXMgPSB0aGlzLmNsYXNzTmFtZS5tYXRjaCggL3VpLXJlc2l6YWJsZS0oc2V8c3d8bmV8bnd8bnxlfHN8dykvaSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRoYXQuYXhpcyA9IGF4aXMgJiYgYXhpc1sgMSBdID8gYXhpc1sgMSBdIDogXCJzZVwiO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdGlmICggby5hdXRvSGlkZSApIHtcblx0XHRcdHRoaXMuX2hhbmRsZXMuaGlkZSgpO1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktcmVzaXphYmxlLWF1dG9oaWRlXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0X3JlbW92ZUhhbmRsZXM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX2hhbmRsZXMucmVtb3ZlKCk7XG5cdH0sXG5cblx0X21vdXNlQ2FwdHVyZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBpLCBoYW5kbGUsXG5cdFx0XHRjYXB0dXJlID0gZmFsc2U7XG5cblx0XHRmb3IgKCBpIGluIHRoaXMuaGFuZGxlcyApIHtcblx0XHRcdGhhbmRsZSA9ICQoIHRoaXMuaGFuZGxlc1sgaSBdIClbIDAgXTtcblx0XHRcdGlmICggaGFuZGxlID09PSBldmVudC50YXJnZXQgfHwgJC5jb250YWlucyggaGFuZGxlLCBldmVudC50YXJnZXQgKSApIHtcblx0XHRcdFx0Y2FwdHVyZSA9IHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuICF0aGlzLm9wdGlvbnMuZGlzYWJsZWQgJiYgY2FwdHVyZTtcblx0fSxcblxuXHRfbW91c2VTdGFydDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dmFyIGN1cmxlZnQsIGN1cnRvcCwgY3Vyc29yLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGVsID0gdGhpcy5lbGVtZW50O1xuXG5cdFx0dGhpcy5yZXNpemluZyA9IHRydWU7XG5cblx0XHR0aGlzLl9yZW5kZXJQcm94eSgpO1xuXG5cdFx0Y3VybGVmdCA9IHRoaXMuX251bSggdGhpcy5oZWxwZXIuY3NzKCBcImxlZnRcIiApICk7XG5cdFx0Y3VydG9wID0gdGhpcy5fbnVtKCB0aGlzLmhlbHBlci5jc3MoIFwidG9wXCIgKSApO1xuXG5cdFx0aWYgKCBvLmNvbnRhaW5tZW50ICkge1xuXHRcdFx0Y3VybGVmdCArPSAkKCBvLmNvbnRhaW5tZW50ICkuc2Nyb2xsTGVmdCgpIHx8IDA7XG5cdFx0XHRjdXJ0b3AgKz0gJCggby5jb250YWlubWVudCApLnNjcm9sbFRvcCgpIHx8IDA7XG5cdFx0fVxuXG5cdFx0dGhpcy5vZmZzZXQgPSB0aGlzLmhlbHBlci5vZmZzZXQoKTtcblx0XHR0aGlzLnBvc2l0aW9uID0geyBsZWZ0OiBjdXJsZWZ0LCB0b3A6IGN1cnRvcCB9O1xuXG5cdFx0dGhpcy5zaXplID0gdGhpcy5faGVscGVyID8ge1xuXHRcdFx0XHR3aWR0aDogdGhpcy5oZWxwZXIud2lkdGgoKSxcblx0XHRcdFx0aGVpZ2h0OiB0aGlzLmhlbHBlci5oZWlnaHQoKVxuXHRcdFx0fSA6IHtcblx0XHRcdFx0d2lkdGg6IGVsLndpZHRoKCksXG5cdFx0XHRcdGhlaWdodDogZWwuaGVpZ2h0KClcblx0XHRcdH07XG5cblx0XHR0aGlzLm9yaWdpbmFsU2l6ZSA9IHRoaXMuX2hlbHBlciA/IHtcblx0XHRcdFx0d2lkdGg6IGVsLm91dGVyV2lkdGgoKSxcblx0XHRcdFx0aGVpZ2h0OiBlbC5vdXRlckhlaWdodCgpXG5cdFx0XHR9IDoge1xuXHRcdFx0XHR3aWR0aDogZWwud2lkdGgoKSxcblx0XHRcdFx0aGVpZ2h0OiBlbC5oZWlnaHQoKVxuXHRcdFx0fTtcblxuXHRcdHRoaXMuc2l6ZURpZmYgPSB7XG5cdFx0XHR3aWR0aDogZWwub3V0ZXJXaWR0aCgpIC0gZWwud2lkdGgoKSxcblx0XHRcdGhlaWdodDogZWwub3V0ZXJIZWlnaHQoKSAtIGVsLmhlaWdodCgpXG5cdFx0fTtcblxuXHRcdHRoaXMub3JpZ2luYWxQb3NpdGlvbiA9IHsgbGVmdDogY3VybGVmdCwgdG9wOiBjdXJ0b3AgfTtcblx0XHR0aGlzLm9yaWdpbmFsTW91c2VQb3NpdGlvbiA9IHsgbGVmdDogZXZlbnQucGFnZVgsIHRvcDogZXZlbnQucGFnZVkgfTtcblxuXHRcdHRoaXMuYXNwZWN0UmF0aW8gPSAoIHR5cGVvZiBvLmFzcGVjdFJhdGlvID09PSBcIm51bWJlclwiICkgP1xuXHRcdFx0by5hc3BlY3RSYXRpbyA6XG5cdFx0XHQoICggdGhpcy5vcmlnaW5hbFNpemUud2lkdGggLyB0aGlzLm9yaWdpbmFsU2l6ZS5oZWlnaHQgKSB8fCAxICk7XG5cblx0XHRjdXJzb3IgPSAkKCBcIi51aS1yZXNpemFibGUtXCIgKyB0aGlzLmF4aXMgKS5jc3MoIFwiY3Vyc29yXCIgKTtcblx0XHQkKCBcImJvZHlcIiApLmNzcyggXCJjdXJzb3JcIiwgY3Vyc29yID09PSBcImF1dG9cIiA/IHRoaXMuYXhpcyArIFwiLXJlc2l6ZVwiIDogY3Vyc29yICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1yZXNpemFibGUtcmVzaXppbmdcIiApO1xuXHRcdHRoaXMuX3Byb3BhZ2F0ZSggXCJzdGFydFwiLCBldmVudCApO1xuXHRcdHJldHVybiB0cnVlO1xuXHR9LFxuXG5cdF9tb3VzZURyYWc6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHZhciBkYXRhLCBwcm9wcyxcblx0XHRcdHNtcCA9IHRoaXMub3JpZ2luYWxNb3VzZVBvc2l0aW9uLFxuXHRcdFx0YSA9IHRoaXMuYXhpcyxcblx0XHRcdGR4ID0gKCBldmVudC5wYWdlWCAtIHNtcC5sZWZ0ICkgfHwgMCxcblx0XHRcdGR5ID0gKCBldmVudC5wYWdlWSAtIHNtcC50b3AgKSB8fCAwLFxuXHRcdFx0dHJpZ2dlciA9IHRoaXMuX2NoYW5nZVsgYSBdO1xuXG5cdFx0dGhpcy5fdXBkYXRlUHJldlByb3BlcnRpZXMoKTtcblxuXHRcdGlmICggIXRyaWdnZXIgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0ZGF0YSA9IHRyaWdnZXIuYXBwbHkoIHRoaXMsIFsgZXZlbnQsIGR4LCBkeSBdICk7XG5cblx0XHR0aGlzLl91cGRhdGVWaXJ0dWFsQm91bmRhcmllcyggZXZlbnQuc2hpZnRLZXkgKTtcblx0XHRpZiAoIHRoaXMuX2FzcGVjdFJhdGlvIHx8IGV2ZW50LnNoaWZ0S2V5ICkge1xuXHRcdFx0ZGF0YSA9IHRoaXMuX3VwZGF0ZVJhdGlvKCBkYXRhLCBldmVudCApO1xuXHRcdH1cblxuXHRcdGRhdGEgPSB0aGlzLl9yZXNwZWN0U2l6ZSggZGF0YSwgZXZlbnQgKTtcblxuXHRcdHRoaXMuX3VwZGF0ZUNhY2hlKCBkYXRhICk7XG5cblx0XHR0aGlzLl9wcm9wYWdhdGUoIFwicmVzaXplXCIsIGV2ZW50ICk7XG5cblx0XHRwcm9wcyA9IHRoaXMuX2FwcGx5Q2hhbmdlcygpO1xuXG5cdFx0aWYgKCAhdGhpcy5faGVscGVyICYmIHRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplRWxlbWVudHMubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemUoKTtcblx0XHR9XG5cblx0XHRpZiAoICEkLmlzRW1wdHlPYmplY3QoIHByb3BzICkgKSB7XG5cdFx0XHR0aGlzLl91cGRhdGVQcmV2UHJvcGVydGllcygpO1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJyZXNpemVcIiwgZXZlbnQsIHRoaXMudWkoKSApO1xuXHRcdFx0dGhpcy5fYXBwbHlDaGFuZ2VzKCk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXG5cdF9tb3VzZVN0b3A6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHRoaXMucmVzaXppbmcgPSBmYWxzZTtcblx0XHR2YXIgcHIsIGlzdGEsIHNvZmZzZXRoLCBzb2Zmc2V0dywgcywgbGVmdCwgdG9wLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucywgdGhhdCA9IHRoaXM7XG5cblx0XHRpZiAoIHRoaXMuX2hlbHBlciApIHtcblxuXHRcdFx0cHIgPSB0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZUVsZW1lbnRzO1xuXHRcdFx0aXN0YSA9IHByLmxlbmd0aCAmJiAoIC90ZXh0YXJlYS9pICkudGVzdCggcHJbIDAgXS5ub2RlTmFtZSApO1xuXHRcdFx0c29mZnNldGggPSBpc3RhICYmIHRoaXMuX2hhc1Njcm9sbCggcHJbIDAgXSwgXCJsZWZ0XCIgKSA/IDAgOiB0aGF0LnNpemVEaWZmLmhlaWdodDtcblx0XHRcdHNvZmZzZXR3ID0gaXN0YSA/IDAgOiB0aGF0LnNpemVEaWZmLndpZHRoO1xuXG5cdFx0XHRzID0ge1xuXHRcdFx0XHR3aWR0aDogKCB0aGF0LmhlbHBlci53aWR0aCgpICAtIHNvZmZzZXR3ICksXG5cdFx0XHRcdGhlaWdodDogKCB0aGF0LmhlbHBlci5oZWlnaHQoKSAtIHNvZmZzZXRoIClcblx0XHRcdH07XG5cdFx0XHRsZWZ0ID0gKCBwYXJzZUZsb2F0KCB0aGF0LmVsZW1lbnQuY3NzKCBcImxlZnRcIiApICkgK1xuXHRcdFx0XHQoIHRoYXQucG9zaXRpb24ubGVmdCAtIHRoYXQub3JpZ2luYWxQb3NpdGlvbi5sZWZ0ICkgKSB8fCBudWxsO1xuXHRcdFx0dG9wID0gKCBwYXJzZUZsb2F0KCB0aGF0LmVsZW1lbnQuY3NzKCBcInRvcFwiICkgKSArXG5cdFx0XHRcdCggdGhhdC5wb3NpdGlvbi50b3AgLSB0aGF0Lm9yaWdpbmFsUG9zaXRpb24udG9wICkgKSB8fCBudWxsO1xuXG5cdFx0XHRpZiAoICFvLmFuaW1hdGUgKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5jc3MoICQuZXh0ZW5kKCBzLCB7IHRvcDogdG9wLCBsZWZ0OiBsZWZ0IH0gKSApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGF0LmhlbHBlci5oZWlnaHQoIHRoYXQuc2l6ZS5oZWlnaHQgKTtcblx0XHRcdHRoYXQuaGVscGVyLndpZHRoKCB0aGF0LnNpemUud2lkdGggKTtcblxuXHRcdFx0aWYgKCB0aGlzLl9oZWxwZXIgJiYgIW8uYW5pbWF0ZSApIHtcblx0XHRcdFx0dGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemUoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQkKCBcImJvZHlcIiApLmNzcyggXCJjdXJzb3JcIiwgXCJhdXRvXCIgKTtcblxuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBcInVpLXJlc2l6YWJsZS1yZXNpemluZ1wiICk7XG5cblx0XHR0aGlzLl9wcm9wYWdhdGUoIFwic3RvcFwiLCBldmVudCApO1xuXG5cdFx0aWYgKCB0aGlzLl9oZWxwZXIgKSB7XG5cdFx0XHR0aGlzLmhlbHBlci5yZW1vdmUoKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cblx0fSxcblxuXHRfdXBkYXRlUHJldlByb3BlcnRpZXM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMucHJldlBvc2l0aW9uID0ge1xuXHRcdFx0dG9wOiB0aGlzLnBvc2l0aW9uLnRvcCxcblx0XHRcdGxlZnQ6IHRoaXMucG9zaXRpb24ubGVmdFxuXHRcdH07XG5cdFx0dGhpcy5wcmV2U2l6ZSA9IHtcblx0XHRcdHdpZHRoOiB0aGlzLnNpemUud2lkdGgsXG5cdFx0XHRoZWlnaHQ6IHRoaXMuc2l6ZS5oZWlnaHRcblx0XHR9O1xuXHR9LFxuXG5cdF9hcHBseUNoYW5nZXM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBwcm9wcyA9IHt9O1xuXG5cdFx0aWYgKCB0aGlzLnBvc2l0aW9uLnRvcCAhPT0gdGhpcy5wcmV2UG9zaXRpb24udG9wICkge1xuXHRcdFx0cHJvcHMudG9wID0gdGhpcy5wb3NpdGlvbi50b3AgKyBcInB4XCI7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5wb3NpdGlvbi5sZWZ0ICE9PSB0aGlzLnByZXZQb3NpdGlvbi5sZWZ0ICkge1xuXHRcdFx0cHJvcHMubGVmdCA9IHRoaXMucG9zaXRpb24ubGVmdCArIFwicHhcIjtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLnNpemUud2lkdGggIT09IHRoaXMucHJldlNpemUud2lkdGggKSB7XG5cdFx0XHRwcm9wcy53aWR0aCA9IHRoaXMuc2l6ZS53aWR0aCArIFwicHhcIjtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLnNpemUuaGVpZ2h0ICE9PSB0aGlzLnByZXZTaXplLmhlaWdodCApIHtcblx0XHRcdHByb3BzLmhlaWdodCA9IHRoaXMuc2l6ZS5oZWlnaHQgKyBcInB4XCI7XG5cdFx0fVxuXG5cdFx0dGhpcy5oZWxwZXIuY3NzKCBwcm9wcyApO1xuXG5cdFx0cmV0dXJuIHByb3BzO1xuXHR9LFxuXG5cdF91cGRhdGVWaXJ0dWFsQm91bmRhcmllczogZnVuY3Rpb24oIGZvcmNlQXNwZWN0UmF0aW8gKSB7XG5cdFx0dmFyIHBNaW5XaWR0aCwgcE1heFdpZHRoLCBwTWluSGVpZ2h0LCBwTWF4SGVpZ2h0LCBiLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucztcblxuXHRcdGIgPSB7XG5cdFx0XHRtaW5XaWR0aDogdGhpcy5faXNOdW1iZXIoIG8ubWluV2lkdGggKSA/IG8ubWluV2lkdGggOiAwLFxuXHRcdFx0bWF4V2lkdGg6IHRoaXMuX2lzTnVtYmVyKCBvLm1heFdpZHRoICkgPyBvLm1heFdpZHRoIDogSW5maW5pdHksXG5cdFx0XHRtaW5IZWlnaHQ6IHRoaXMuX2lzTnVtYmVyKCBvLm1pbkhlaWdodCApID8gby5taW5IZWlnaHQgOiAwLFxuXHRcdFx0bWF4SGVpZ2h0OiB0aGlzLl9pc051bWJlciggby5tYXhIZWlnaHQgKSA/IG8ubWF4SGVpZ2h0IDogSW5maW5pdHlcblx0XHR9O1xuXG5cdFx0aWYgKCB0aGlzLl9hc3BlY3RSYXRpbyB8fCBmb3JjZUFzcGVjdFJhdGlvICkge1xuXHRcdFx0cE1pbldpZHRoID0gYi5taW5IZWlnaHQgKiB0aGlzLmFzcGVjdFJhdGlvO1xuXHRcdFx0cE1pbkhlaWdodCA9IGIubWluV2lkdGggLyB0aGlzLmFzcGVjdFJhdGlvO1xuXHRcdFx0cE1heFdpZHRoID0gYi5tYXhIZWlnaHQgKiB0aGlzLmFzcGVjdFJhdGlvO1xuXHRcdFx0cE1heEhlaWdodCA9IGIubWF4V2lkdGggLyB0aGlzLmFzcGVjdFJhdGlvO1xuXG5cdFx0XHRpZiAoIHBNaW5XaWR0aCA+IGIubWluV2lkdGggKSB7XG5cdFx0XHRcdGIubWluV2lkdGggPSBwTWluV2lkdGg7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIHBNaW5IZWlnaHQgPiBiLm1pbkhlaWdodCApIHtcblx0XHRcdFx0Yi5taW5IZWlnaHQgPSBwTWluSGVpZ2h0O1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBwTWF4V2lkdGggPCBiLm1heFdpZHRoICkge1xuXHRcdFx0XHRiLm1heFdpZHRoID0gcE1heFdpZHRoO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBwTWF4SGVpZ2h0IDwgYi5tYXhIZWlnaHQgKSB7XG5cdFx0XHRcdGIubWF4SGVpZ2h0ID0gcE1heEhlaWdodDtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5fdkJvdW5kYXJpZXMgPSBiO1xuXHR9LFxuXG5cdF91cGRhdGVDYWNoZTogZnVuY3Rpb24oIGRhdGEgKSB7XG5cdFx0dGhpcy5vZmZzZXQgPSB0aGlzLmhlbHBlci5vZmZzZXQoKTtcblx0XHRpZiAoIHRoaXMuX2lzTnVtYmVyKCBkYXRhLmxlZnQgKSApIHtcblx0XHRcdHRoaXMucG9zaXRpb24ubGVmdCA9IGRhdGEubGVmdDtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLl9pc051bWJlciggZGF0YS50b3AgKSApIHtcblx0XHRcdHRoaXMucG9zaXRpb24udG9wID0gZGF0YS50b3A7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5faXNOdW1iZXIoIGRhdGEuaGVpZ2h0ICkgKSB7XG5cdFx0XHR0aGlzLnNpemUuaGVpZ2h0ID0gZGF0YS5oZWlnaHQ7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5faXNOdW1iZXIoIGRhdGEud2lkdGggKSApIHtcblx0XHRcdHRoaXMuc2l6ZS53aWR0aCA9IGRhdGEud2lkdGg7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGVSYXRpbzogZnVuY3Rpb24oIGRhdGEgKSB7XG5cblx0XHR2YXIgY3BvcyA9IHRoaXMucG9zaXRpb24sXG5cdFx0XHRjc2l6ZSA9IHRoaXMuc2l6ZSxcblx0XHRcdGEgPSB0aGlzLmF4aXM7XG5cblx0XHRpZiAoIHRoaXMuX2lzTnVtYmVyKCBkYXRhLmhlaWdodCApICkge1xuXHRcdFx0ZGF0YS53aWR0aCA9ICggZGF0YS5oZWlnaHQgKiB0aGlzLmFzcGVjdFJhdGlvICk7XG5cdFx0fSBlbHNlIGlmICggdGhpcy5faXNOdW1iZXIoIGRhdGEud2lkdGggKSApIHtcblx0XHRcdGRhdGEuaGVpZ2h0ID0gKCBkYXRhLndpZHRoIC8gdGhpcy5hc3BlY3RSYXRpbyApO1xuXHRcdH1cblxuXHRcdGlmICggYSA9PT0gXCJzd1wiICkge1xuXHRcdFx0ZGF0YS5sZWZ0ID0gY3Bvcy5sZWZ0ICsgKCBjc2l6ZS53aWR0aCAtIGRhdGEud2lkdGggKTtcblx0XHRcdGRhdGEudG9wID0gbnVsbDtcblx0XHR9XG5cdFx0aWYgKCBhID09PSBcIm53XCIgKSB7XG5cdFx0XHRkYXRhLnRvcCA9IGNwb3MudG9wICsgKCBjc2l6ZS5oZWlnaHQgLSBkYXRhLmhlaWdodCApO1xuXHRcdFx0ZGF0YS5sZWZ0ID0gY3Bvcy5sZWZ0ICsgKCBjc2l6ZS53aWR0aCAtIGRhdGEud2lkdGggKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZGF0YTtcblx0fSxcblxuXHRfcmVzcGVjdFNpemU6IGZ1bmN0aW9uKCBkYXRhICkge1xuXG5cdFx0dmFyIG8gPSB0aGlzLl92Qm91bmRhcmllcyxcblx0XHRcdGEgPSB0aGlzLmF4aXMsXG5cdFx0XHRpc21heHcgPSB0aGlzLl9pc051bWJlciggZGF0YS53aWR0aCApICYmIG8ubWF4V2lkdGggJiYgKCBvLm1heFdpZHRoIDwgZGF0YS53aWR0aCApLFxuXHRcdFx0aXNtYXhoID0gdGhpcy5faXNOdW1iZXIoIGRhdGEuaGVpZ2h0ICkgJiYgby5tYXhIZWlnaHQgJiYgKCBvLm1heEhlaWdodCA8IGRhdGEuaGVpZ2h0ICksXG5cdFx0XHRpc21pbncgPSB0aGlzLl9pc051bWJlciggZGF0YS53aWR0aCApICYmIG8ubWluV2lkdGggJiYgKCBvLm1pbldpZHRoID4gZGF0YS53aWR0aCApLFxuXHRcdFx0aXNtaW5oID0gdGhpcy5faXNOdW1iZXIoIGRhdGEuaGVpZ2h0ICkgJiYgby5taW5IZWlnaHQgJiYgKCBvLm1pbkhlaWdodCA+IGRhdGEuaGVpZ2h0ICksXG5cdFx0XHRkdyA9IHRoaXMub3JpZ2luYWxQb3NpdGlvbi5sZWZ0ICsgdGhpcy5vcmlnaW5hbFNpemUud2lkdGgsXG5cdFx0XHRkaCA9IHRoaXMub3JpZ2luYWxQb3NpdGlvbi50b3AgKyB0aGlzLm9yaWdpbmFsU2l6ZS5oZWlnaHQsXG5cdFx0XHRjdyA9IC9zd3xud3x3Ly50ZXN0KCBhICksIGNoID0gL253fG5lfG4vLnRlc3QoIGEgKTtcblx0XHRpZiAoIGlzbWludyApIHtcblx0XHRcdGRhdGEud2lkdGggPSBvLm1pbldpZHRoO1xuXHRcdH1cblx0XHRpZiAoIGlzbWluaCApIHtcblx0XHRcdGRhdGEuaGVpZ2h0ID0gby5taW5IZWlnaHQ7XG5cdFx0fVxuXHRcdGlmICggaXNtYXh3ICkge1xuXHRcdFx0ZGF0YS53aWR0aCA9IG8ubWF4V2lkdGg7XG5cdFx0fVxuXHRcdGlmICggaXNtYXhoICkge1xuXHRcdFx0ZGF0YS5oZWlnaHQgPSBvLm1heEhlaWdodDtcblx0XHR9XG5cblx0XHRpZiAoIGlzbWludyAmJiBjdyApIHtcblx0XHRcdGRhdGEubGVmdCA9IGR3IC0gby5taW5XaWR0aDtcblx0XHR9XG5cdFx0aWYgKCBpc21heHcgJiYgY3cgKSB7XG5cdFx0XHRkYXRhLmxlZnQgPSBkdyAtIG8ubWF4V2lkdGg7XG5cdFx0fVxuXHRcdGlmICggaXNtaW5oICYmIGNoICkge1xuXHRcdFx0ZGF0YS50b3AgPSBkaCAtIG8ubWluSGVpZ2h0O1xuXHRcdH1cblx0XHRpZiAoIGlzbWF4aCAmJiBjaCApIHtcblx0XHRcdGRhdGEudG9wID0gZGggLSBvLm1heEhlaWdodDtcblx0XHR9XG5cblx0XHQvLyBGaXhpbmcganVtcCBlcnJvciBvbiB0b3AvbGVmdCAtIGJ1ZyAjMjMzMFxuXHRcdGlmICggIWRhdGEud2lkdGggJiYgIWRhdGEuaGVpZ2h0ICYmICFkYXRhLmxlZnQgJiYgZGF0YS50b3AgKSB7XG5cdFx0XHRkYXRhLnRvcCA9IG51bGw7XG5cdFx0fSBlbHNlIGlmICggIWRhdGEud2lkdGggJiYgIWRhdGEuaGVpZ2h0ICYmICFkYXRhLnRvcCAmJiBkYXRhLmxlZnQgKSB7XG5cdFx0XHRkYXRhLmxlZnQgPSBudWxsO1xuXHRcdH1cblxuXHRcdHJldHVybiBkYXRhO1xuXHR9LFxuXG5cdF9nZXRQYWRkaW5nUGx1c0JvcmRlckRpbWVuc2lvbnM6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHZhciBpID0gMCxcblx0XHRcdHdpZHRocyA9IFtdLFxuXHRcdFx0Ym9yZGVycyA9IFtcblx0XHRcdFx0ZWxlbWVudC5jc3MoIFwiYm9yZGVyVG9wV2lkdGhcIiApLFxuXHRcdFx0XHRlbGVtZW50LmNzcyggXCJib3JkZXJSaWdodFdpZHRoXCIgKSxcblx0XHRcdFx0ZWxlbWVudC5jc3MoIFwiYm9yZGVyQm90dG9tV2lkdGhcIiApLFxuXHRcdFx0XHRlbGVtZW50LmNzcyggXCJib3JkZXJMZWZ0V2lkdGhcIiApXG5cdFx0XHRdLFxuXHRcdFx0cGFkZGluZ3MgPSBbXG5cdFx0XHRcdGVsZW1lbnQuY3NzKCBcInBhZGRpbmdUb3BcIiApLFxuXHRcdFx0XHRlbGVtZW50LmNzcyggXCJwYWRkaW5nUmlnaHRcIiApLFxuXHRcdFx0XHRlbGVtZW50LmNzcyggXCJwYWRkaW5nQm90dG9tXCIgKSxcblx0XHRcdFx0ZWxlbWVudC5jc3MoIFwicGFkZGluZ0xlZnRcIiApXG5cdFx0XHRdO1xuXG5cdFx0Zm9yICggOyBpIDwgNDsgaSsrICkge1xuXHRcdFx0d2lkdGhzWyBpIF0gPSAoIHBhcnNlRmxvYXQoIGJvcmRlcnNbIGkgXSApIHx8IDAgKTtcblx0XHRcdHdpZHRoc1sgaSBdICs9ICggcGFyc2VGbG9hdCggcGFkZGluZ3NbIGkgXSApIHx8IDAgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0aGVpZ2h0OiB3aWR0aHNbIDAgXSArIHdpZHRoc1sgMiBdLFxuXHRcdFx0d2lkdGg6IHdpZHRoc1sgMSBdICsgd2lkdGhzWyAzIF1cblx0XHR9O1xuXHR9LFxuXG5cdF9wcm9wb3J0aW9uYWxseVJlc2l6ZTogZnVuY3Rpb24oKSB7XG5cblx0XHRpZiAoICF0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZUVsZW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgcHJlbCxcblx0XHRcdGkgPSAwLFxuXHRcdFx0ZWxlbWVudCA9IHRoaXMuaGVscGVyIHx8IHRoaXMuZWxlbWVudDtcblxuXHRcdGZvciAoIDsgaSA8IHRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplRWxlbWVudHMubGVuZ3RoOyBpKysgKSB7XG5cblx0XHRcdHByZWwgPSB0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZUVsZW1lbnRzWyBpIF07XG5cblx0XHRcdC8vIFRPRE86IFNlZW1zIGxpa2UgYSBidWcgdG8gY2FjaGUgdGhpcy5vdXRlckRpbWVuc2lvbnNcblx0XHRcdC8vIGNvbnNpZGVyaW5nIHRoYXQgd2UgYXJlIGluIGEgbG9vcC5cblx0XHRcdGlmICggIXRoaXMub3V0ZXJEaW1lbnNpb25zICkge1xuXHRcdFx0XHR0aGlzLm91dGVyRGltZW5zaW9ucyA9IHRoaXMuX2dldFBhZGRpbmdQbHVzQm9yZGVyRGltZW5zaW9ucyggcHJlbCApO1xuXHRcdFx0fVxuXG5cdFx0XHRwcmVsLmNzcygge1xuXHRcdFx0XHRoZWlnaHQ6ICggZWxlbWVudC5oZWlnaHQoKSAtIHRoaXMub3V0ZXJEaW1lbnNpb25zLmhlaWdodCApIHx8IDAsXG5cdFx0XHRcdHdpZHRoOiAoIGVsZW1lbnQud2lkdGgoKSAtIHRoaXMub3V0ZXJEaW1lbnNpb25zLndpZHRoICkgfHwgMFxuXHRcdFx0fSApO1xuXG5cdFx0fVxuXG5cdH0sXG5cblx0X3JlbmRlclByb3h5OiBmdW5jdGlvbigpIHtcblxuXHRcdHZhciBlbCA9IHRoaXMuZWxlbWVudCwgbyA9IHRoaXMub3B0aW9ucztcblx0XHR0aGlzLmVsZW1lbnRPZmZzZXQgPSBlbC5vZmZzZXQoKTtcblxuXHRcdGlmICggdGhpcy5faGVscGVyICkge1xuXG5cdFx0XHR0aGlzLmhlbHBlciA9IHRoaXMuaGVscGVyIHx8ICQoIFwiPGRpdiBzdHlsZT0nb3ZlcmZsb3c6aGlkZGVuOyc+PC9kaXY+XCIgKTtcblxuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaGVscGVyLCB0aGlzLl9oZWxwZXIgKTtcblx0XHRcdHRoaXMuaGVscGVyLmNzcygge1xuXHRcdFx0XHR3aWR0aDogdGhpcy5lbGVtZW50Lm91dGVyV2lkdGgoKSxcblx0XHRcdFx0aGVpZ2h0OiB0aGlzLmVsZW1lbnQub3V0ZXJIZWlnaHQoKSxcblx0XHRcdFx0cG9zaXRpb246IFwiYWJzb2x1dGVcIixcblx0XHRcdFx0bGVmdDogdGhpcy5lbGVtZW50T2Zmc2V0LmxlZnQgKyBcInB4XCIsXG5cdFx0XHRcdHRvcDogdGhpcy5lbGVtZW50T2Zmc2V0LnRvcCArIFwicHhcIixcblx0XHRcdFx0ekluZGV4OiArK28uekluZGV4IC8vVE9ETzogRG9uJ3QgbW9kaWZ5IG9wdGlvblxuXHRcdFx0fSApO1xuXG5cdFx0XHR0aGlzLmhlbHBlclxuXHRcdFx0XHQuYXBwZW5kVG8oIFwiYm9keVwiIClcblx0XHRcdFx0LmRpc2FibGVTZWxlY3Rpb24oKTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmhlbHBlciA9IHRoaXMuZWxlbWVudDtcblx0XHR9XG5cblx0fSxcblxuXHRfY2hhbmdlOiB7XG5cdFx0ZTogZnVuY3Rpb24oIGV2ZW50LCBkeCApIHtcblx0XHRcdHJldHVybiB7IHdpZHRoOiB0aGlzLm9yaWdpbmFsU2l6ZS53aWR0aCArIGR4IH07XG5cdFx0fSxcblx0XHR3OiBmdW5jdGlvbiggZXZlbnQsIGR4ICkge1xuXHRcdFx0dmFyIGNzID0gdGhpcy5vcmlnaW5hbFNpemUsIHNwID0gdGhpcy5vcmlnaW5hbFBvc2l0aW9uO1xuXHRcdFx0cmV0dXJuIHsgbGVmdDogc3AubGVmdCArIGR4LCB3aWR0aDogY3Mud2lkdGggLSBkeCB9O1xuXHRcdH0sXG5cdFx0bjogZnVuY3Rpb24oIGV2ZW50LCBkeCwgZHkgKSB7XG5cdFx0XHR2YXIgY3MgPSB0aGlzLm9yaWdpbmFsU2l6ZSwgc3AgPSB0aGlzLm9yaWdpbmFsUG9zaXRpb247XG5cdFx0XHRyZXR1cm4geyB0b3A6IHNwLnRvcCArIGR5LCBoZWlnaHQ6IGNzLmhlaWdodCAtIGR5IH07XG5cdFx0fSxcblx0XHRzOiBmdW5jdGlvbiggZXZlbnQsIGR4LCBkeSApIHtcblx0XHRcdHJldHVybiB7IGhlaWdodDogdGhpcy5vcmlnaW5hbFNpemUuaGVpZ2h0ICsgZHkgfTtcblx0XHR9LFxuXHRcdHNlOiBmdW5jdGlvbiggZXZlbnQsIGR4LCBkeSApIHtcblx0XHRcdHJldHVybiAkLmV4dGVuZCggdGhpcy5fY2hhbmdlLnMuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApLFxuXHRcdFx0XHR0aGlzLl9jaGFuZ2UuZS5hcHBseSggdGhpcywgWyBldmVudCwgZHgsIGR5IF0gKSApO1xuXHRcdH0sXG5cdFx0c3c6IGZ1bmN0aW9uKCBldmVudCwgZHgsIGR5ICkge1xuXHRcdFx0cmV0dXJuICQuZXh0ZW5kKCB0aGlzLl9jaGFuZ2Uucy5hcHBseSggdGhpcywgYXJndW1lbnRzICksXG5cdFx0XHRcdHRoaXMuX2NoYW5nZS53LmFwcGx5KCB0aGlzLCBbIGV2ZW50LCBkeCwgZHkgXSApICk7XG5cdFx0fSxcblx0XHRuZTogZnVuY3Rpb24oIGV2ZW50LCBkeCwgZHkgKSB7XG5cdFx0XHRyZXR1cm4gJC5leHRlbmQoIHRoaXMuX2NoYW5nZS5uLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSxcblx0XHRcdFx0dGhpcy5fY2hhbmdlLmUuYXBwbHkoIHRoaXMsIFsgZXZlbnQsIGR4LCBkeSBdICkgKTtcblx0XHR9LFxuXHRcdG53OiBmdW5jdGlvbiggZXZlbnQsIGR4LCBkeSApIHtcblx0XHRcdHJldHVybiAkLmV4dGVuZCggdGhpcy5fY2hhbmdlLm4uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApLFxuXHRcdFx0XHR0aGlzLl9jaGFuZ2Uudy5hcHBseSggdGhpcywgWyBldmVudCwgZHgsIGR5IF0gKSApO1xuXHRcdH1cblx0fSxcblxuXHRfcHJvcGFnYXRlOiBmdW5jdGlvbiggbiwgZXZlbnQgKSB7XG5cdFx0JC51aS5wbHVnaW4uY2FsbCggdGhpcywgbiwgWyBldmVudCwgdGhpcy51aSgpIF0gKTtcblx0XHQoIG4gIT09IFwicmVzaXplXCIgJiYgdGhpcy5fdHJpZ2dlciggbiwgZXZlbnQsIHRoaXMudWkoKSApICk7XG5cdH0sXG5cblx0cGx1Z2luczoge30sXG5cblx0dWk6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB7XG5cdFx0XHRvcmlnaW5hbEVsZW1lbnQ6IHRoaXMub3JpZ2luYWxFbGVtZW50LFxuXHRcdFx0ZWxlbWVudDogdGhpcy5lbGVtZW50LFxuXHRcdFx0aGVscGVyOiB0aGlzLmhlbHBlcixcblx0XHRcdHBvc2l0aW9uOiB0aGlzLnBvc2l0aW9uLFxuXHRcdFx0c2l6ZTogdGhpcy5zaXplLFxuXHRcdFx0b3JpZ2luYWxTaXplOiB0aGlzLm9yaWdpbmFsU2l6ZSxcblx0XHRcdG9yaWdpbmFsUG9zaXRpb246IHRoaXMub3JpZ2luYWxQb3NpdGlvblxuXHRcdH07XG5cdH1cblxufSApO1xuXG4vKlxuICogUmVzaXphYmxlIEV4dGVuc2lvbnNcbiAqL1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwicmVzaXphYmxlXCIsIFwiYW5pbWF0ZVwiLCB7XG5cblx0c3RvcDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciB0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICksXG5cdFx0XHRvID0gdGhhdC5vcHRpb25zLFxuXHRcdFx0cHIgPSB0aGF0Ll9wcm9wb3J0aW9uYWxseVJlc2l6ZUVsZW1lbnRzLFxuXHRcdFx0aXN0YSA9IHByLmxlbmd0aCAmJiAoIC90ZXh0YXJlYS9pICkudGVzdCggcHJbIDAgXS5ub2RlTmFtZSApLFxuXHRcdFx0c29mZnNldGggPSBpc3RhICYmIHRoYXQuX2hhc1Njcm9sbCggcHJbIDAgXSwgXCJsZWZ0XCIgKSA/IDAgOiB0aGF0LnNpemVEaWZmLmhlaWdodCxcblx0XHRcdHNvZmZzZXR3ID0gaXN0YSA/IDAgOiB0aGF0LnNpemVEaWZmLndpZHRoLFxuXHRcdFx0c3R5bGUgPSB7XG5cdFx0XHRcdHdpZHRoOiAoIHRoYXQuc2l6ZS53aWR0aCAtIHNvZmZzZXR3ICksXG5cdFx0XHRcdGhlaWdodDogKCB0aGF0LnNpemUuaGVpZ2h0IC0gc29mZnNldGggKVxuXHRcdFx0fSxcblx0XHRcdGxlZnQgPSAoIHBhcnNlRmxvYXQoIHRoYXQuZWxlbWVudC5jc3MoIFwibGVmdFwiICkgKSArXG5cdFx0XHRcdCggdGhhdC5wb3NpdGlvbi5sZWZ0IC0gdGhhdC5vcmlnaW5hbFBvc2l0aW9uLmxlZnQgKSApIHx8IG51bGwsXG5cdFx0XHR0b3AgPSAoIHBhcnNlRmxvYXQoIHRoYXQuZWxlbWVudC5jc3MoIFwidG9wXCIgKSApICtcblx0XHRcdFx0KCB0aGF0LnBvc2l0aW9uLnRvcCAtIHRoYXQub3JpZ2luYWxQb3NpdGlvbi50b3AgKSApIHx8IG51bGw7XG5cblx0XHR0aGF0LmVsZW1lbnQuYW5pbWF0ZShcblx0XHRcdCQuZXh0ZW5kKCBzdHlsZSwgdG9wICYmIGxlZnQgPyB7IHRvcDogdG9wLCBsZWZ0OiBsZWZ0IH0gOiB7fSApLCB7XG5cdFx0XHRcdGR1cmF0aW9uOiBvLmFuaW1hdGVEdXJhdGlvbixcblx0XHRcdFx0ZWFzaW5nOiBvLmFuaW1hdGVFYXNpbmcsXG5cdFx0XHRcdHN0ZXA6IGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRcdFx0dmFyIGRhdGEgPSB7XG5cdFx0XHRcdFx0XHR3aWR0aDogcGFyc2VGbG9hdCggdGhhdC5lbGVtZW50LmNzcyggXCJ3aWR0aFwiICkgKSxcblx0XHRcdFx0XHRcdGhlaWdodDogcGFyc2VGbG9hdCggdGhhdC5lbGVtZW50LmNzcyggXCJoZWlnaHRcIiApICksXG5cdFx0XHRcdFx0XHR0b3A6IHBhcnNlRmxvYXQoIHRoYXQuZWxlbWVudC5jc3MoIFwidG9wXCIgKSApLFxuXHRcdFx0XHRcdFx0bGVmdDogcGFyc2VGbG9hdCggdGhhdC5lbGVtZW50LmNzcyggXCJsZWZ0XCIgKSApXG5cdFx0XHRcdFx0fTtcblxuXHRcdFx0XHRcdGlmICggcHIgJiYgcHIubGVuZ3RoICkge1xuXHRcdFx0XHRcdFx0JCggcHJbIDAgXSApLmNzcyggeyB3aWR0aDogZGF0YS53aWR0aCwgaGVpZ2h0OiBkYXRhLmhlaWdodCB9ICk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gUHJvcGFnYXRpbmcgcmVzaXplLCBhbmQgdXBkYXRpbmcgdmFsdWVzIGZvciBlYWNoIGFuaW1hdGlvbiBzdGVwXG5cdFx0XHRcdFx0dGhhdC5fdXBkYXRlQ2FjaGUoIGRhdGEgKTtcblx0XHRcdFx0XHR0aGF0Ll9wcm9wYWdhdGUoIFwicmVzaXplXCIsIGV2ZW50ICk7XG5cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdCk7XG5cdH1cblxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwicmVzaXphYmxlXCIsIFwiY29udGFpbm1lbnRcIiwge1xuXG5cdHN0YXJ0OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZWxlbWVudCwgcCwgY28sIGNoLCBjdywgd2lkdGgsIGhlaWdodCxcblx0XHRcdHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKSxcblx0XHRcdG8gPSB0aGF0Lm9wdGlvbnMsXG5cdFx0XHRlbCA9IHRoYXQuZWxlbWVudCxcblx0XHRcdG9jID0gby5jb250YWlubWVudCxcblx0XHRcdGNlID0gKCBvYyBpbnN0YW5jZW9mICQgKSA/XG5cdFx0XHRcdG9jLmdldCggMCApIDpcblx0XHRcdFx0KCAvcGFyZW50Ly50ZXN0KCBvYyApICkgPyBlbC5wYXJlbnQoKS5nZXQoIDAgKSA6IG9jO1xuXG5cdFx0aWYgKCAhY2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhhdC5jb250YWluZXJFbGVtZW50ID0gJCggY2UgKTtcblxuXHRcdGlmICggL2RvY3VtZW50Ly50ZXN0KCBvYyApIHx8IG9jID09PSBkb2N1bWVudCApIHtcblx0XHRcdHRoYXQuY29udGFpbmVyT2Zmc2V0ID0ge1xuXHRcdFx0XHRsZWZ0OiAwLFxuXHRcdFx0XHR0b3A6IDBcblx0XHRcdH07XG5cdFx0XHR0aGF0LmNvbnRhaW5lclBvc2l0aW9uID0ge1xuXHRcdFx0XHRsZWZ0OiAwLFxuXHRcdFx0XHR0b3A6IDBcblx0XHRcdH07XG5cblx0XHRcdHRoYXQucGFyZW50RGF0YSA9IHtcblx0XHRcdFx0ZWxlbWVudDogJCggZG9jdW1lbnQgKSxcblx0XHRcdFx0bGVmdDogMCxcblx0XHRcdFx0dG9wOiAwLFxuXHRcdFx0XHR3aWR0aDogJCggZG9jdW1lbnQgKS53aWR0aCgpLFxuXHRcdFx0XHRoZWlnaHQ6ICQoIGRvY3VtZW50ICkuaGVpZ2h0KCkgfHwgZG9jdW1lbnQuYm9keS5wYXJlbnROb2RlLnNjcm9sbEhlaWdodFxuXHRcdFx0fTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZWxlbWVudCA9ICQoIGNlICk7XG5cdFx0XHRwID0gW107XG5cdFx0XHQkKCBbIFwiVG9wXCIsIFwiUmlnaHRcIiwgXCJMZWZ0XCIsIFwiQm90dG9tXCIgXSApLmVhY2goIGZ1bmN0aW9uKCBpLCBuYW1lICkge1xuXHRcdFx0XHRwWyBpIF0gPSB0aGF0Ll9udW0oIGVsZW1lbnQuY3NzKCBcInBhZGRpbmdcIiArIG5hbWUgKSApO1xuXHRcdFx0fSApO1xuXG5cdFx0XHR0aGF0LmNvbnRhaW5lck9mZnNldCA9IGVsZW1lbnQub2Zmc2V0KCk7XG5cdFx0XHR0aGF0LmNvbnRhaW5lclBvc2l0aW9uID0gZWxlbWVudC5wb3NpdGlvbigpO1xuXHRcdFx0dGhhdC5jb250YWluZXJTaXplID0ge1xuXHRcdFx0XHRoZWlnaHQ6ICggZWxlbWVudC5pbm5lckhlaWdodCgpIC0gcFsgMyBdICksXG5cdFx0XHRcdHdpZHRoOiAoIGVsZW1lbnQuaW5uZXJXaWR0aCgpIC0gcFsgMSBdIClcblx0XHRcdH07XG5cblx0XHRcdGNvID0gdGhhdC5jb250YWluZXJPZmZzZXQ7XG5cdFx0XHRjaCA9IHRoYXQuY29udGFpbmVyU2l6ZS5oZWlnaHQ7XG5cdFx0XHRjdyA9IHRoYXQuY29udGFpbmVyU2l6ZS53aWR0aDtcblx0XHRcdHdpZHRoID0gKCB0aGF0Ll9oYXNTY3JvbGwgKCBjZSwgXCJsZWZ0XCIgKSA/IGNlLnNjcm9sbFdpZHRoIDogY3cgKTtcblx0XHRcdGhlaWdodCA9ICggdGhhdC5faGFzU2Nyb2xsICggY2UgKSA/IGNlLnNjcm9sbEhlaWdodCA6IGNoICkgO1xuXG5cdFx0XHR0aGF0LnBhcmVudERhdGEgPSB7XG5cdFx0XHRcdGVsZW1lbnQ6IGNlLFxuXHRcdFx0XHRsZWZ0OiBjby5sZWZ0LFxuXHRcdFx0XHR0b3A6IGNvLnRvcCxcblx0XHRcdFx0d2lkdGg6IHdpZHRoLFxuXHRcdFx0XHRoZWlnaHQ6IGhlaWdodFxuXHRcdFx0fTtcblx0XHR9XG5cdH0sXG5cblx0cmVzaXplOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHdvc2V0LCBob3NldCwgaXNQYXJlbnQsIGlzT2Zmc2V0UmVsYXRpdmUsXG5cdFx0XHR0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICksXG5cdFx0XHRvID0gdGhhdC5vcHRpb25zLFxuXHRcdFx0Y28gPSB0aGF0LmNvbnRhaW5lck9mZnNldCxcblx0XHRcdGNwID0gdGhhdC5wb3NpdGlvbixcblx0XHRcdHBSYXRpbyA9IHRoYXQuX2FzcGVjdFJhdGlvIHx8IGV2ZW50LnNoaWZ0S2V5LFxuXHRcdFx0Y29wID0ge1xuXHRcdFx0XHR0b3A6IDAsXG5cdFx0XHRcdGxlZnQ6IDBcblx0XHRcdH0sXG5cdFx0XHRjZSA9IHRoYXQuY29udGFpbmVyRWxlbWVudCxcblx0XHRcdGNvbnRpbnVlUmVzaXplID0gdHJ1ZTtcblxuXHRcdGlmICggY2VbIDAgXSAhPT0gZG9jdW1lbnQgJiYgKCAvc3RhdGljLyApLnRlc3QoIGNlLmNzcyggXCJwb3NpdGlvblwiICkgKSApIHtcblx0XHRcdGNvcCA9IGNvO1xuXHRcdH1cblxuXHRcdGlmICggY3AubGVmdCA8ICggdGhhdC5faGVscGVyID8gY28ubGVmdCA6IDAgKSApIHtcblx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IHRoYXQuc2l6ZS53aWR0aCArXG5cdFx0XHRcdCggdGhhdC5faGVscGVyID9cblx0XHRcdFx0XHQoIHRoYXQucG9zaXRpb24ubGVmdCAtIGNvLmxlZnQgKSA6XG5cdFx0XHRcdFx0KCB0aGF0LnBvc2l0aW9uLmxlZnQgLSBjb3AubGVmdCApICk7XG5cblx0XHRcdGlmICggcFJhdGlvICkge1xuXHRcdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gdGhhdC5zaXplLndpZHRoIC8gdGhhdC5hc3BlY3RSYXRpbztcblx0XHRcdFx0Y29udGludWVSZXNpemUgPSBmYWxzZTtcblx0XHRcdH1cblx0XHRcdHRoYXQucG9zaXRpb24ubGVmdCA9IG8uaGVscGVyID8gY28ubGVmdCA6IDA7XG5cdFx0fVxuXG5cdFx0aWYgKCBjcC50b3AgPCAoIHRoYXQuX2hlbHBlciA/IGNvLnRvcCA6IDAgKSApIHtcblx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSB0aGF0LnNpemUuaGVpZ2h0ICtcblx0XHRcdFx0KCB0aGF0Ll9oZWxwZXIgP1xuXHRcdFx0XHRcdCggdGhhdC5wb3NpdGlvbi50b3AgLSBjby50b3AgKSA6XG5cdFx0XHRcdFx0dGhhdC5wb3NpdGlvbi50b3AgKTtcblxuXHRcdFx0aWYgKCBwUmF0aW8gKSB7XG5cdFx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IHRoYXQuc2l6ZS5oZWlnaHQgKiB0aGF0LmFzcGVjdFJhdGlvO1xuXHRcdFx0XHRjb250aW51ZVJlc2l6ZSA9IGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dGhhdC5wb3NpdGlvbi50b3AgPSB0aGF0Ll9oZWxwZXIgPyBjby50b3AgOiAwO1xuXHRcdH1cblxuXHRcdGlzUGFyZW50ID0gdGhhdC5jb250YWluZXJFbGVtZW50LmdldCggMCApID09PSB0aGF0LmVsZW1lbnQucGFyZW50KCkuZ2V0KCAwICk7XG5cdFx0aXNPZmZzZXRSZWxhdGl2ZSA9IC9yZWxhdGl2ZXxhYnNvbHV0ZS8udGVzdCggdGhhdC5jb250YWluZXJFbGVtZW50LmNzcyggXCJwb3NpdGlvblwiICkgKTtcblxuXHRcdGlmICggaXNQYXJlbnQgJiYgaXNPZmZzZXRSZWxhdGl2ZSApIHtcblx0XHRcdHRoYXQub2Zmc2V0LmxlZnQgPSB0aGF0LnBhcmVudERhdGEubGVmdCArIHRoYXQucG9zaXRpb24ubGVmdDtcblx0XHRcdHRoYXQub2Zmc2V0LnRvcCA9IHRoYXQucGFyZW50RGF0YS50b3AgKyB0aGF0LnBvc2l0aW9uLnRvcDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhhdC5vZmZzZXQubGVmdCA9IHRoYXQuZWxlbWVudC5vZmZzZXQoKS5sZWZ0O1xuXHRcdFx0dGhhdC5vZmZzZXQudG9wID0gdGhhdC5lbGVtZW50Lm9mZnNldCgpLnRvcDtcblx0XHR9XG5cblx0XHR3b3NldCA9IE1hdGguYWJzKCB0aGF0LnNpemVEaWZmLndpZHRoICtcblx0XHRcdCggdGhhdC5faGVscGVyID9cblx0XHRcdFx0dGhhdC5vZmZzZXQubGVmdCAtIGNvcC5sZWZ0IDpcblx0XHRcdFx0KCB0aGF0Lm9mZnNldC5sZWZ0IC0gY28ubGVmdCApICkgKTtcblxuXHRcdGhvc2V0ID0gTWF0aC5hYnMoIHRoYXQuc2l6ZURpZmYuaGVpZ2h0ICtcblx0XHRcdCggdGhhdC5faGVscGVyID9cblx0XHRcdFx0dGhhdC5vZmZzZXQudG9wIC0gY29wLnRvcCA6XG5cdFx0XHRcdCggdGhhdC5vZmZzZXQudG9wIC0gY28udG9wICkgKSApO1xuXG5cdFx0aWYgKCB3b3NldCArIHRoYXQuc2l6ZS53aWR0aCA+PSB0aGF0LnBhcmVudERhdGEud2lkdGggKSB7XG5cdFx0XHR0aGF0LnNpemUud2lkdGggPSB0aGF0LnBhcmVudERhdGEud2lkdGggLSB3b3NldDtcblx0XHRcdGlmICggcFJhdGlvICkge1xuXHRcdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gdGhhdC5zaXplLndpZHRoIC8gdGhhdC5hc3BlY3RSYXRpbztcblx0XHRcdFx0Y29udGludWVSZXNpemUgPSBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIGhvc2V0ICsgdGhhdC5zaXplLmhlaWdodCA+PSB0aGF0LnBhcmVudERhdGEuaGVpZ2h0ICkge1xuXHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IHRoYXQucGFyZW50RGF0YS5oZWlnaHQgLSBob3NldDtcblx0XHRcdGlmICggcFJhdGlvICkge1xuXHRcdFx0XHR0aGF0LnNpemUud2lkdGggPSB0aGF0LnNpemUuaGVpZ2h0ICogdGhhdC5hc3BlY3RSYXRpbztcblx0XHRcdFx0Y29udGludWVSZXNpemUgPSBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoICFjb250aW51ZVJlc2l6ZSApIHtcblx0XHRcdHRoYXQucG9zaXRpb24ubGVmdCA9IHRoYXQucHJldlBvc2l0aW9uLmxlZnQ7XG5cdFx0XHR0aGF0LnBvc2l0aW9uLnRvcCA9IHRoYXQucHJldlBvc2l0aW9uLnRvcDtcblx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IHRoYXQucHJldlNpemUud2lkdGg7XG5cdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gdGhhdC5wcmV2U2l6ZS5oZWlnaHQ7XG5cdFx0fVxuXHR9LFxuXG5cdHN0b3A6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICksXG5cdFx0XHRvID0gdGhhdC5vcHRpb25zLFxuXHRcdFx0Y28gPSB0aGF0LmNvbnRhaW5lck9mZnNldCxcblx0XHRcdGNvcCA9IHRoYXQuY29udGFpbmVyUG9zaXRpb24sXG5cdFx0XHRjZSA9IHRoYXQuY29udGFpbmVyRWxlbWVudCxcblx0XHRcdGhlbHBlciA9ICQoIHRoYXQuaGVscGVyICksXG5cdFx0XHRobyA9IGhlbHBlci5vZmZzZXQoKSxcblx0XHRcdHcgPSBoZWxwZXIub3V0ZXJXaWR0aCgpIC0gdGhhdC5zaXplRGlmZi53aWR0aCxcblx0XHRcdGggPSBoZWxwZXIub3V0ZXJIZWlnaHQoKSAtIHRoYXQuc2l6ZURpZmYuaGVpZ2h0O1xuXG5cdFx0aWYgKCB0aGF0Ll9oZWxwZXIgJiYgIW8uYW5pbWF0ZSAmJiAoIC9yZWxhdGl2ZS8gKS50ZXN0KCBjZS5jc3MoIFwicG9zaXRpb25cIiApICkgKSB7XG5cdFx0XHQkKCB0aGlzICkuY3NzKCB7XG5cdFx0XHRcdGxlZnQ6IGhvLmxlZnQgLSBjb3AubGVmdCAtIGNvLmxlZnQsXG5cdFx0XHRcdHdpZHRoOiB3LFxuXHRcdFx0XHRoZWlnaHQ6IGhcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoYXQuX2hlbHBlciAmJiAhby5hbmltYXRlICYmICggL3N0YXRpYy8gKS50ZXN0KCBjZS5jc3MoIFwicG9zaXRpb25cIiApICkgKSB7XG5cdFx0XHQkKCB0aGlzICkuY3NzKCB7XG5cdFx0XHRcdGxlZnQ6IGhvLmxlZnQgLSBjb3AubGVmdCAtIGNvLmxlZnQsXG5cdFx0XHRcdHdpZHRoOiB3LFxuXHRcdFx0XHRoZWlnaHQ6IGhcblx0XHRcdH0gKTtcblx0XHR9XG5cdH1cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcInJlc2l6YWJsZVwiLCBcImFsc29SZXNpemVcIiwge1xuXG5cdHN0YXJ0OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApLFxuXHRcdFx0byA9IHRoYXQub3B0aW9ucztcblxuXHRcdCQoIG8uYWxzb1Jlc2l6ZSApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGVsID0gJCggdGhpcyApO1xuXHRcdFx0ZWwuZGF0YSggXCJ1aS1yZXNpemFibGUtYWxzb3Jlc2l6ZVwiLCB7XG5cdFx0XHRcdHdpZHRoOiBwYXJzZUZsb2F0KCBlbC53aWR0aCgpICksIGhlaWdodDogcGFyc2VGbG9hdCggZWwuaGVpZ2h0KCkgKSxcblx0XHRcdFx0bGVmdDogcGFyc2VGbG9hdCggZWwuY3NzKCBcImxlZnRcIiApICksIHRvcDogcGFyc2VGbG9hdCggZWwuY3NzKCBcInRvcFwiICkgKVxuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0fSxcblxuXHRyZXNpemU6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0dmFyIHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKSxcblx0XHRcdG8gPSB0aGF0Lm9wdGlvbnMsXG5cdFx0XHRvcyA9IHRoYXQub3JpZ2luYWxTaXplLFxuXHRcdFx0b3AgPSB0aGF0Lm9yaWdpbmFsUG9zaXRpb24sXG5cdFx0XHRkZWx0YSA9IHtcblx0XHRcdFx0aGVpZ2h0OiAoIHRoYXQuc2l6ZS5oZWlnaHQgLSBvcy5oZWlnaHQgKSB8fCAwLFxuXHRcdFx0XHR3aWR0aDogKCB0aGF0LnNpemUud2lkdGggLSBvcy53aWR0aCApIHx8IDAsXG5cdFx0XHRcdHRvcDogKCB0aGF0LnBvc2l0aW9uLnRvcCAtIG9wLnRvcCApIHx8IDAsXG5cdFx0XHRcdGxlZnQ6ICggdGhhdC5wb3NpdGlvbi5sZWZ0IC0gb3AubGVmdCApIHx8IDBcblx0XHRcdH07XG5cblx0XHRcdCQoIG8uYWxzb1Jlc2l6ZSApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgZWwgPSAkKCB0aGlzICksIHN0YXJ0ID0gJCggdGhpcyApLmRhdGEoIFwidWktcmVzaXphYmxlLWFsc29yZXNpemVcIiApLCBzdHlsZSA9IHt9LFxuXHRcdFx0XHRcdGNzcyA9IGVsLnBhcmVudHMoIHVpLm9yaWdpbmFsRWxlbWVudFsgMCBdICkubGVuZ3RoID9cblx0XHRcdFx0XHRcdFx0WyBcIndpZHRoXCIsIFwiaGVpZ2h0XCIgXSA6XG5cdFx0XHRcdFx0XHRcdFsgXCJ3aWR0aFwiLCBcImhlaWdodFwiLCBcInRvcFwiLCBcImxlZnRcIiBdO1xuXG5cdFx0XHRcdCQuZWFjaCggY3NzLCBmdW5jdGlvbiggaSwgcHJvcCApIHtcblx0XHRcdFx0XHR2YXIgc3VtID0gKCBzdGFydFsgcHJvcCBdIHx8IDAgKSArICggZGVsdGFbIHByb3AgXSB8fCAwICk7XG5cdFx0XHRcdFx0aWYgKCBzdW0gJiYgc3VtID49IDAgKSB7XG5cdFx0XHRcdFx0XHRzdHlsZVsgcHJvcCBdID0gc3VtIHx8IG51bGw7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0ZWwuY3NzKCBzdHlsZSApO1xuXHRcdFx0fSApO1xuXHR9LFxuXG5cdHN0b3A6IGZ1bmN0aW9uKCkge1xuXHRcdCQoIHRoaXMgKS5yZW1vdmVEYXRhKCBcInVpLXJlc2l6YWJsZS1hbHNvcmVzaXplXCIgKTtcblx0fVxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwicmVzaXphYmxlXCIsIFwiZ2hvc3RcIiwge1xuXG5cdHN0YXJ0OiBmdW5jdGlvbigpIHtcblxuXHRcdHZhciB0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICksIGNzID0gdGhhdC5zaXplO1xuXG5cdFx0dGhhdC5naG9zdCA9IHRoYXQub3JpZ2luYWxFbGVtZW50LmNsb25lKCk7XG5cdFx0dGhhdC5naG9zdC5jc3MoIHtcblx0XHRcdG9wYWNpdHk6IDAuMjUsXG5cdFx0XHRkaXNwbGF5OiBcImJsb2NrXCIsXG5cdFx0XHRwb3NpdGlvbjogXCJyZWxhdGl2ZVwiLFxuXHRcdFx0aGVpZ2h0OiBjcy5oZWlnaHQsXG5cdFx0XHR3aWR0aDogY3Mud2lkdGgsXG5cdFx0XHRtYXJnaW46IDAsXG5cdFx0XHRsZWZ0OiAwLFxuXHRcdFx0dG9wOiAwXG5cdFx0fSApO1xuXG5cdFx0dGhhdC5fYWRkQ2xhc3MoIHRoYXQuZ2hvc3QsIFwidWktcmVzaXphYmxlLWdob3N0XCIgKTtcblxuXHRcdC8vIERFUFJFQ0FURURcblx0XHQvLyBUT0RPOiByZW1vdmUgYWZ0ZXIgMS4xMlxuXHRcdGlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICYmIHR5cGVvZiB0aGF0Lm9wdGlvbnMuZ2hvc3QgPT09IFwic3RyaW5nXCIgKSB7XG5cblx0XHRcdC8vIEdob3N0IG9wdGlvblxuXHRcdFx0dGhhdC5naG9zdC5hZGRDbGFzcyggdGhpcy5vcHRpb25zLmdob3N0ICk7XG5cdFx0fVxuXG5cdFx0dGhhdC5naG9zdC5hcHBlbmRUbyggdGhhdC5oZWxwZXIgKTtcblxuXHR9LFxuXG5cdHJlc2l6ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKTtcblx0XHRpZiAoIHRoYXQuZ2hvc3QgKSB7XG5cdFx0XHR0aGF0Lmdob3N0LmNzcygge1xuXHRcdFx0XHRwb3NpdGlvbjogXCJyZWxhdGl2ZVwiLFxuXHRcdFx0XHRoZWlnaHQ6IHRoYXQuc2l6ZS5oZWlnaHQsXG5cdFx0XHRcdHdpZHRoOiB0aGF0LnNpemUud2lkdGhcblx0XHRcdH0gKTtcblx0XHR9XG5cdH0sXG5cblx0c3RvcDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKTtcblx0XHRpZiAoIHRoYXQuZ2hvc3QgJiYgdGhhdC5oZWxwZXIgKSB7XG5cdFx0XHR0aGF0LmhlbHBlci5nZXQoIDAgKS5yZW1vdmVDaGlsZCggdGhhdC5naG9zdC5nZXQoIDAgKSApO1xuXHRcdH1cblx0fVxuXG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJyZXNpemFibGVcIiwgXCJncmlkXCIsIHtcblxuXHRyZXNpemU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvdXRlckRpbWVuc2lvbnMsXG5cdFx0XHR0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICksXG5cdFx0XHRvID0gdGhhdC5vcHRpb25zLFxuXHRcdFx0Y3MgPSB0aGF0LnNpemUsXG5cdFx0XHRvcyA9IHRoYXQub3JpZ2luYWxTaXplLFxuXHRcdFx0b3AgPSB0aGF0Lm9yaWdpbmFsUG9zaXRpb24sXG5cdFx0XHRhID0gdGhhdC5heGlzLFxuXHRcdFx0Z3JpZCA9IHR5cGVvZiBvLmdyaWQgPT09IFwibnVtYmVyXCIgPyBbIG8uZ3JpZCwgby5ncmlkIF0gOiBvLmdyaWQsXG5cdFx0XHRncmlkWCA9ICggZ3JpZFsgMCBdIHx8IDEgKSxcblx0XHRcdGdyaWRZID0gKCBncmlkWyAxIF0gfHwgMSApLFxuXHRcdFx0b3ggPSBNYXRoLnJvdW5kKCAoIGNzLndpZHRoIC0gb3Mud2lkdGggKSAvIGdyaWRYICkgKiBncmlkWCxcblx0XHRcdG95ID0gTWF0aC5yb3VuZCggKCBjcy5oZWlnaHQgLSBvcy5oZWlnaHQgKSAvIGdyaWRZICkgKiBncmlkWSxcblx0XHRcdG5ld1dpZHRoID0gb3Mud2lkdGggKyBveCxcblx0XHRcdG5ld0hlaWdodCA9IG9zLmhlaWdodCArIG95LFxuXHRcdFx0aXNNYXhXaWR0aCA9IG8ubWF4V2lkdGggJiYgKCBvLm1heFdpZHRoIDwgbmV3V2lkdGggKSxcblx0XHRcdGlzTWF4SGVpZ2h0ID0gby5tYXhIZWlnaHQgJiYgKCBvLm1heEhlaWdodCA8IG5ld0hlaWdodCApLFxuXHRcdFx0aXNNaW5XaWR0aCA9IG8ubWluV2lkdGggJiYgKCBvLm1pbldpZHRoID4gbmV3V2lkdGggKSxcblx0XHRcdGlzTWluSGVpZ2h0ID0gby5taW5IZWlnaHQgJiYgKCBvLm1pbkhlaWdodCA+IG5ld0hlaWdodCApO1xuXG5cdFx0by5ncmlkID0gZ3JpZDtcblxuXHRcdGlmICggaXNNaW5XaWR0aCApIHtcblx0XHRcdG5ld1dpZHRoICs9IGdyaWRYO1xuXHRcdH1cblx0XHRpZiAoIGlzTWluSGVpZ2h0ICkge1xuXHRcdFx0bmV3SGVpZ2h0ICs9IGdyaWRZO1xuXHRcdH1cblx0XHRpZiAoIGlzTWF4V2lkdGggKSB7XG5cdFx0XHRuZXdXaWR0aCAtPSBncmlkWDtcblx0XHR9XG5cdFx0aWYgKCBpc01heEhlaWdodCApIHtcblx0XHRcdG5ld0hlaWdodCAtPSBncmlkWTtcblx0XHR9XG5cblx0XHRpZiAoIC9eKHNlfHN8ZSkkLy50ZXN0KCBhICkgKSB7XG5cdFx0XHR0aGF0LnNpemUud2lkdGggPSBuZXdXaWR0aDtcblx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSBuZXdIZWlnaHQ7XG5cdFx0fSBlbHNlIGlmICggL14obmUpJC8udGVzdCggYSApICkge1xuXHRcdFx0dGhhdC5zaXplLndpZHRoID0gbmV3V2lkdGg7XG5cdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gbmV3SGVpZ2h0O1xuXHRcdFx0dGhhdC5wb3NpdGlvbi50b3AgPSBvcC50b3AgLSBveTtcblx0XHR9IGVsc2UgaWYgKCAvXihzdykkLy50ZXN0KCBhICkgKSB7XG5cdFx0XHR0aGF0LnNpemUud2lkdGggPSBuZXdXaWR0aDtcblx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSBuZXdIZWlnaHQ7XG5cdFx0XHR0aGF0LnBvc2l0aW9uLmxlZnQgPSBvcC5sZWZ0IC0gb3g7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGlmICggbmV3SGVpZ2h0IC0gZ3JpZFkgPD0gMCB8fCBuZXdXaWR0aCAtIGdyaWRYIDw9IDAgKSB7XG5cdFx0XHRcdG91dGVyRGltZW5zaW9ucyA9IHRoYXQuX2dldFBhZGRpbmdQbHVzQm9yZGVyRGltZW5zaW9ucyggdGhpcyApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG5ld0hlaWdodCAtIGdyaWRZID4gMCApIHtcblx0XHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IG5ld0hlaWdodDtcblx0XHRcdFx0dGhhdC5wb3NpdGlvbi50b3AgPSBvcC50b3AgLSBveTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdG5ld0hlaWdodCA9IGdyaWRZIC0gb3V0ZXJEaW1lbnNpb25zLmhlaWdodDtcblx0XHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IG5ld0hlaWdodDtcblx0XHRcdFx0dGhhdC5wb3NpdGlvbi50b3AgPSBvcC50b3AgKyBvcy5oZWlnaHQgLSBuZXdIZWlnaHQ7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIG5ld1dpZHRoIC0gZ3JpZFggPiAwICkge1xuXHRcdFx0XHR0aGF0LnNpemUud2lkdGggPSBuZXdXaWR0aDtcblx0XHRcdFx0dGhhdC5wb3NpdGlvbi5sZWZ0ID0gb3AubGVmdCAtIG94O1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0bmV3V2lkdGggPSBncmlkWCAtIG91dGVyRGltZW5zaW9ucy53aWR0aDtcblx0XHRcdFx0dGhhdC5zaXplLndpZHRoID0gbmV3V2lkdGg7XG5cdFx0XHRcdHRoYXQucG9zaXRpb24ubGVmdCA9IG9wLmxlZnQgKyBvcy53aWR0aCAtIG5ld1dpZHRoO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG59ICk7XG5cbnZhciB3aWRnZXRzUmVzaXphYmxlID0gJC51aS5yZXNpemFibGU7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRGlhbG9nIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBEaWFsb2dcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBEaXNwbGF5cyBjdXN0b21pemFibGUgZGlhbG9nIHdpbmRvd3MuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZGlhbG9nL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2RpYWxvZy9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2RpYWxvZy5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxuJC53aWRnZXQoIFwidWkuZGlhbG9nXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0b3B0aW9uczoge1xuXHRcdGFwcGVuZFRvOiBcImJvZHlcIixcblx0XHRhdXRvT3BlbjogdHJ1ZSxcblx0XHRidXR0b25zOiBbXSxcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLWRpYWxvZ1wiOiBcInVpLWNvcm5lci1hbGxcIixcblx0XHRcdFwidWktZGlhbG9nLXRpdGxlYmFyXCI6IFwidWktY29ybmVyLWFsbFwiXG5cdFx0fSxcblx0XHRjbG9zZU9uRXNjYXBlOiB0cnVlLFxuXHRcdGNsb3NlVGV4dDogXCJDbG9zZVwiLFxuXHRcdGRyYWdnYWJsZTogdHJ1ZSxcblx0XHRoaWRlOiBudWxsLFxuXHRcdGhlaWdodDogXCJhdXRvXCIsXG5cdFx0bWF4SGVpZ2h0OiBudWxsLFxuXHRcdG1heFdpZHRoOiBudWxsLFxuXHRcdG1pbkhlaWdodDogMTUwLFxuXHRcdG1pbldpZHRoOiAxNTAsXG5cdFx0bW9kYWw6IGZhbHNlLFxuXHRcdHBvc2l0aW9uOiB7XG5cdFx0XHRteTogXCJjZW50ZXJcIixcblx0XHRcdGF0OiBcImNlbnRlclwiLFxuXHRcdFx0b2Y6IHdpbmRvdyxcblx0XHRcdGNvbGxpc2lvbjogXCJmaXRcIixcblxuXHRcdFx0Ly8gRW5zdXJlIHRoZSB0aXRsZWJhciBpcyBhbHdheXMgdmlzaWJsZVxuXHRcdFx0dXNpbmc6IGZ1bmN0aW9uKCBwb3MgKSB7XG5cdFx0XHRcdHZhciB0b3BPZmZzZXQgPSAkKCB0aGlzICkuY3NzKCBwb3MgKS5vZmZzZXQoKS50b3A7XG5cdFx0XHRcdGlmICggdG9wT2Zmc2V0IDwgMCApIHtcblx0XHRcdFx0XHQkKCB0aGlzICkuY3NzKCBcInRvcFwiLCBwb3MudG9wIC0gdG9wT2Zmc2V0ICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9LFxuXHRcdHJlc2l6YWJsZTogdHJ1ZSxcblx0XHRzaG93OiBudWxsLFxuXHRcdHRpdGxlOiBudWxsLFxuXHRcdHdpZHRoOiAzMDAsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRiZWZvcmVDbG9zZTogbnVsbCxcblx0XHRjbG9zZTogbnVsbCxcblx0XHRkcmFnOiBudWxsLFxuXHRcdGRyYWdTdGFydDogbnVsbCxcblx0XHRkcmFnU3RvcDogbnVsbCxcblx0XHRmb2N1czogbnVsbCxcblx0XHRvcGVuOiBudWxsLFxuXHRcdHJlc2l6ZTogbnVsbCxcblx0XHRyZXNpemVTdGFydDogbnVsbCxcblx0XHRyZXNpemVTdG9wOiBudWxsXG5cdH0sXG5cblx0c2l6ZVJlbGF0ZWRPcHRpb25zOiB7XG5cdFx0YnV0dG9uczogdHJ1ZSxcblx0XHRoZWlnaHQ6IHRydWUsXG5cdFx0bWF4SGVpZ2h0OiB0cnVlLFxuXHRcdG1heFdpZHRoOiB0cnVlLFxuXHRcdG1pbkhlaWdodDogdHJ1ZSxcblx0XHRtaW5XaWR0aDogdHJ1ZSxcblx0XHR3aWR0aDogdHJ1ZVxuXHR9LFxuXG5cdHJlc2l6YWJsZVJlbGF0ZWRPcHRpb25zOiB7XG5cdFx0bWF4SGVpZ2h0OiB0cnVlLFxuXHRcdG1heFdpZHRoOiB0cnVlLFxuXHRcdG1pbkhlaWdodDogdHJ1ZSxcblx0XHRtaW5XaWR0aDogdHJ1ZVxuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMub3JpZ2luYWxDc3MgPSB7XG5cdFx0XHRkaXNwbGF5OiB0aGlzLmVsZW1lbnRbIDAgXS5zdHlsZS5kaXNwbGF5LFxuXHRcdFx0d2lkdGg6IHRoaXMuZWxlbWVudFsgMCBdLnN0eWxlLndpZHRoLFxuXHRcdFx0bWluSGVpZ2h0OiB0aGlzLmVsZW1lbnRbIDAgXS5zdHlsZS5taW5IZWlnaHQsXG5cdFx0XHRtYXhIZWlnaHQ6IHRoaXMuZWxlbWVudFsgMCBdLnN0eWxlLm1heEhlaWdodCxcblx0XHRcdGhlaWdodDogdGhpcy5lbGVtZW50WyAwIF0uc3R5bGUuaGVpZ2h0XG5cdFx0fTtcblx0XHR0aGlzLm9yaWdpbmFsUG9zaXRpb24gPSB7XG5cdFx0XHRwYXJlbnQ6IHRoaXMuZWxlbWVudC5wYXJlbnQoKSxcblx0XHRcdGluZGV4OiB0aGlzLmVsZW1lbnQucGFyZW50KCkuY2hpbGRyZW4oKS5pbmRleCggdGhpcy5lbGVtZW50IClcblx0XHR9O1xuXHRcdHRoaXMub3JpZ2luYWxUaXRsZSA9IHRoaXMuZWxlbWVudC5hdHRyKCBcInRpdGxlXCIgKTtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy50aXRsZSA9PSBudWxsICYmIHRoaXMub3JpZ2luYWxUaXRsZSAhPSBudWxsICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLnRpdGxlID0gdGhpcy5vcmlnaW5hbFRpdGxlO1xuXHRcdH1cblxuXHRcdC8vIERpYWxvZ3MgY2FuJ3QgYmUgZGlzYWJsZWRcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdHRoaXMub3B0aW9ucy5kaXNhYmxlZCA9IGZhbHNlO1xuXHRcdH1cblxuXHRcdHRoaXMuX2NyZWF0ZVdyYXBwZXIoKTtcblxuXHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0LnNob3coKVxuXHRcdFx0LnJlbW92ZUF0dHIoIFwidGl0bGVcIiApXG5cdFx0XHQuYXBwZW5kVG8oIHRoaXMudWlEaWFsb2cgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWRpYWxvZy1jb250ZW50XCIsIFwidWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXG5cdFx0dGhpcy5fY3JlYXRlVGl0bGViYXIoKTtcblx0XHR0aGlzLl9jcmVhdGVCdXR0b25QYW5lKCk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kcmFnZ2FibGUgJiYgJC5mbi5kcmFnZ2FibGUgKSB7XG5cdFx0XHR0aGlzLl9tYWtlRHJhZ2dhYmxlKCk7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5vcHRpb25zLnJlc2l6YWJsZSAmJiAkLmZuLnJlc2l6YWJsZSApIHtcblx0XHRcdHRoaXMuX21ha2VSZXNpemFibGUoKTtcblx0XHR9XG5cblx0XHR0aGlzLl9pc09wZW4gPSBmYWxzZTtcblxuXHRcdHRoaXMuX3RyYWNrRm9jdXMoKTtcblx0fSxcblxuXHRfaW5pdDogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuYXV0b09wZW4gKSB7XG5cdFx0XHR0aGlzLm9wZW4oKTtcblx0XHR9XG5cdH0sXG5cblx0X2FwcGVuZFRvOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZWxlbWVudCA9IHRoaXMub3B0aW9ucy5hcHBlbmRUbztcblx0XHRpZiAoIGVsZW1lbnQgJiYgKCBlbGVtZW50LmpxdWVyeSB8fCBlbGVtZW50Lm5vZGVUeXBlICkgKSB7XG5cdFx0XHRyZXR1cm4gJCggZWxlbWVudCApO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5kb2N1bWVudC5maW5kKCBlbGVtZW50IHx8IFwiYm9keVwiICkuZXEoIDAgKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG5leHQsXG5cdFx0XHRvcmlnaW5hbFBvc2l0aW9uID0gdGhpcy5vcmlnaW5hbFBvc2l0aW9uO1xuXG5cdFx0dGhpcy5fdW50cmFja0luc3RhbmNlKCk7XG5cdFx0dGhpcy5fZGVzdHJveU92ZXJsYXkoKTtcblxuXHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0LnJlbW92ZVVuaXF1ZUlkKClcblx0XHRcdC5jc3MoIHRoaXMub3JpZ2luYWxDc3MgKVxuXG5cdFx0XHQvLyBXaXRob3V0IGRldGFjaGluZyBmaXJzdCwgdGhlIGZvbGxvd2luZyBiZWNvbWVzIHJlYWxseSBzbG93XG5cdFx0XHQuZGV0YWNoKCk7XG5cblx0XHR0aGlzLnVpRGlhbG9nLnJlbW92ZSgpO1xuXG5cdFx0aWYgKCB0aGlzLm9yaWdpbmFsVGl0bGUgKSB7XG5cdFx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiLCB0aGlzLm9yaWdpbmFsVGl0bGUgKTtcblx0XHR9XG5cblx0XHRuZXh0ID0gb3JpZ2luYWxQb3NpdGlvbi5wYXJlbnQuY2hpbGRyZW4oKS5lcSggb3JpZ2luYWxQb3NpdGlvbi5pbmRleCApO1xuXG5cdFx0Ly8gRG9uJ3QgdHJ5IHRvIHBsYWNlIHRoZSBkaWFsb2cgbmV4dCB0byBpdHNlbGYgKCM4NjEzKVxuXHRcdGlmICggbmV4dC5sZW5ndGggJiYgbmV4dFsgMCBdICE9PSB0aGlzLmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdG5leHQuYmVmb3JlKCB0aGlzLmVsZW1lbnQgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0b3JpZ2luYWxQb3NpdGlvbi5wYXJlbnQuYXBwZW5kKCB0aGlzLmVsZW1lbnQgKTtcblx0XHR9XG5cdH0sXG5cblx0d2lkZ2V0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy51aURpYWxvZztcblx0fSxcblxuXHRkaXNhYmxlOiAkLm5vb3AsXG5cdGVuYWJsZTogJC5ub29wLFxuXG5cdGNsb3NlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0aWYgKCAhdGhpcy5faXNPcGVuIHx8IHRoaXMuX3RyaWdnZXIoIFwiYmVmb3JlQ2xvc2VcIiwgZXZlbnQgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5faXNPcGVuID0gZmFsc2U7XG5cdFx0dGhpcy5fZm9jdXNlZEVsZW1lbnQgPSBudWxsO1xuXHRcdHRoaXMuX2Rlc3Ryb3lPdmVybGF5KCk7XG5cdFx0dGhpcy5fdW50cmFja0luc3RhbmNlKCk7XG5cblx0XHRpZiAoICF0aGlzLm9wZW5lci5maWx0ZXIoIFwiOmZvY3VzYWJsZVwiICkudHJpZ2dlciggXCJmb2N1c1wiICkubGVuZ3RoICkge1xuXG5cdFx0XHQvLyBIaWRpbmcgYSBmb2N1c2VkIGVsZW1lbnQgZG9lc24ndCB0cmlnZ2VyIGJsdXIgaW4gV2ViS2l0XG5cdFx0XHQvLyBzbyBpbiBjYXNlIHdlIGhhdmUgbm90aGluZyB0byBmb2N1cyBvbiwgZXhwbGljaXRseSBibHVyIHRoZSBhY3RpdmUgZWxlbWVudFxuXHRcdFx0Ly8gaHR0cHM6Ly9idWdzLndlYmtpdC5vcmcvc2hvd19idWcuY2dpP2lkPTQ3MTgyXG5cdFx0XHQkLnVpLnNhZmVCbHVyKCAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX2hpZGUoIHRoaXMudWlEaWFsb2csIHRoaXMub3B0aW9ucy5oaWRlLCBmdW5jdGlvbigpIHtcblx0XHRcdHRoYXQuX3RyaWdnZXIoIFwiY2xvc2VcIiwgZXZlbnQgKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0aXNPcGVuOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5faXNPcGVuO1xuXHR9LFxuXG5cdG1vdmVUb1RvcDogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fbW92ZVRvVG9wKCk7XG5cdH0sXG5cblx0X21vdmVUb1RvcDogZnVuY3Rpb24oIGV2ZW50LCBzaWxlbnQgKSB7XG5cdFx0dmFyIG1vdmVkID0gZmFsc2UsXG5cdFx0XHR6SW5kaWNlcyA9IHRoaXMudWlEaWFsb2cuc2libGluZ3MoIFwiLnVpLWZyb250OnZpc2libGVcIiApLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiArJCggdGhpcyApLmNzcyggXCJ6LWluZGV4XCIgKTtcblx0XHRcdH0gKS5nZXQoKSxcblx0XHRcdHpJbmRleE1heCA9IE1hdGgubWF4LmFwcGx5KCBudWxsLCB6SW5kaWNlcyApO1xuXG5cdFx0aWYgKCB6SW5kZXhNYXggPj0gK3RoaXMudWlEaWFsb2cuY3NzKCBcInotaW5kZXhcIiApICkge1xuXHRcdFx0dGhpcy51aURpYWxvZy5jc3MoIFwiei1pbmRleFwiLCB6SW5kZXhNYXggKyAxICk7XG5cdFx0XHRtb3ZlZCA9IHRydWU7XG5cdFx0fVxuXG5cdFx0aWYgKCBtb3ZlZCAmJiAhc2lsZW50ICkge1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJmb2N1c1wiLCBldmVudCApO1xuXHRcdH1cblx0XHRyZXR1cm4gbW92ZWQ7XG5cdH0sXG5cblx0b3BlbjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXHRcdGlmICggdGhpcy5faXNPcGVuICkge1xuXHRcdFx0aWYgKCB0aGlzLl9tb3ZlVG9Ub3AoKSApIHtcblx0XHRcdFx0dGhpcy5fZm9jdXNUYWJiYWJsZSgpO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuX2lzT3BlbiA9IHRydWU7XG5cdFx0dGhpcy5vcGVuZXIgPSAkKCAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKSApO1xuXG5cdFx0dGhpcy5fc2l6ZSgpO1xuXHRcdHRoaXMuX3Bvc2l0aW9uKCk7XG5cdFx0dGhpcy5fY3JlYXRlT3ZlcmxheSgpO1xuXHRcdHRoaXMuX21vdmVUb1RvcCggbnVsbCwgdHJ1ZSApO1xuXG5cdFx0Ly8gRW5zdXJlIHRoZSBvdmVybGF5IGlzIG1vdmVkIHRvIHRoZSB0b3Agd2l0aCB0aGUgZGlhbG9nLCBidXQgb25seSB3aGVuXG5cdFx0Ly8gb3BlbmluZy4gVGhlIG92ZXJsYXkgc2hvdWxkbid0IG1vdmUgYWZ0ZXIgdGhlIGRpYWxvZyBpcyBvcGVuIHNvIHRoYXRcblx0XHQvLyBtb2RlbGVzcyBkaWFsb2dzIG9wZW5lZCBhZnRlciB0aGUgbW9kYWwgZGlhbG9nIHN0YWNrIHByb3Blcmx5LlxuXHRcdGlmICggdGhpcy5vdmVybGF5ICkge1xuXHRcdFx0dGhpcy5vdmVybGF5LmNzcyggXCJ6LWluZGV4XCIsIHRoaXMudWlEaWFsb2cuY3NzKCBcInotaW5kZXhcIiApIC0gMSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3Nob3coIHRoaXMudWlEaWFsb2csIHRoaXMub3B0aW9ucy5zaG93LCBmdW5jdGlvbigpIHtcblx0XHRcdHRoYXQuX2ZvY3VzVGFiYmFibGUoKTtcblx0XHRcdHRoYXQuX3RyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdH0gKTtcblxuXHRcdC8vIFRyYWNrIHRoZSBkaWFsb2cgaW1tZWRpYXRlbHkgdXBvbiBvcGVuZW5pbmcgaW4gY2FzZSBhIGZvY3VzIGV2ZW50XG5cdFx0Ly8gc29tZWhvdyBvY2N1cnMgb3V0c2lkZSBvZiB0aGUgZGlhbG9nIGJlZm9yZSBhbiBlbGVtZW50IGluc2lkZSB0aGVcblx0XHQvLyBkaWFsb2cgaXMgZm9jdXNlZCAoIzEwMTUyKVxuXHRcdHRoaXMuX21ha2VGb2N1c1RhcmdldCgpO1xuXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJvcGVuXCIgKTtcblx0fSxcblxuXHRfZm9jdXNUYWJiYWJsZTogZnVuY3Rpb24oKSB7XG5cblx0XHQvLyBTZXQgZm9jdXMgdG8gdGhlIGZpcnN0IG1hdGNoOlxuXHRcdC8vIDEuIEFuIGVsZW1lbnQgdGhhdCB3YXMgZm9jdXNlZCBwcmV2aW91c2x5XG5cdFx0Ly8gMi4gRmlyc3QgZWxlbWVudCBpbnNpZGUgdGhlIGRpYWxvZyBtYXRjaGluZyBbYXV0b2ZvY3VzXVxuXHRcdC8vIDMuIFRhYmJhYmxlIGVsZW1lbnQgaW5zaWRlIHRoZSBjb250ZW50IGVsZW1lbnRcblx0XHQvLyA0LiBUYWJiYWJsZSBlbGVtZW50IGluc2lkZSB0aGUgYnV0dG9ucGFuZVxuXHRcdC8vIDUuIFRoZSBjbG9zZSBidXR0b25cblx0XHQvLyA2LiBUaGUgZGlhbG9nIGl0c2VsZlxuXHRcdHZhciBoYXNGb2N1cyA9IHRoaXMuX2ZvY3VzZWRFbGVtZW50O1xuXHRcdGlmICggIWhhc0ZvY3VzICkge1xuXHRcdFx0aGFzRm9jdXMgPSB0aGlzLmVsZW1lbnQuZmluZCggXCJbYXV0b2ZvY3VzXVwiICk7XG5cdFx0fVxuXHRcdGlmICggIWhhc0ZvY3VzLmxlbmd0aCApIHtcblx0XHRcdGhhc0ZvY3VzID0gdGhpcy5lbGVtZW50LmZpbmQoIFwiOnRhYmJhYmxlXCIgKTtcblx0XHR9XG5cdFx0aWYgKCAhaGFzRm9jdXMubGVuZ3RoICkge1xuXHRcdFx0aGFzRm9jdXMgPSB0aGlzLnVpRGlhbG9nQnV0dG9uUGFuZS5maW5kKCBcIjp0YWJiYWJsZVwiICk7XG5cdFx0fVxuXHRcdGlmICggIWhhc0ZvY3VzLmxlbmd0aCApIHtcblx0XHRcdGhhc0ZvY3VzID0gdGhpcy51aURpYWxvZ1RpdGxlYmFyQ2xvc2UuZmlsdGVyKCBcIjp0YWJiYWJsZVwiICk7XG5cdFx0fVxuXHRcdGlmICggIWhhc0ZvY3VzLmxlbmd0aCApIHtcblx0XHRcdGhhc0ZvY3VzID0gdGhpcy51aURpYWxvZztcblx0XHR9XG5cdFx0aGFzRm9jdXMuZXEoIDAgKS50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0fSxcblxuXHRfa2VlcEZvY3VzOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0ZnVuY3Rpb24gY2hlY2tGb2N1cygpIHtcblx0XHRcdHZhciBhY3RpdmVFbGVtZW50ID0gJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICksXG5cdFx0XHRcdGlzQWN0aXZlID0gdGhpcy51aURpYWxvZ1sgMCBdID09PSBhY3RpdmVFbGVtZW50IHx8XG5cdFx0XHRcdFx0JC5jb250YWlucyggdGhpcy51aURpYWxvZ1sgMCBdLCBhY3RpdmVFbGVtZW50ICk7XG5cdFx0XHRpZiAoICFpc0FjdGl2ZSApIHtcblx0XHRcdFx0dGhpcy5fZm9jdXNUYWJiYWJsZSgpO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdGNoZWNrRm9jdXMuY2FsbCggdGhpcyApO1xuXG5cdFx0Ly8gc3VwcG9ydDogSUVcblx0XHQvLyBJRSA8PSA4IGRvZXNuJ3QgcHJldmVudCBtb3ZpbmcgZm9jdXMgZXZlbiB3aXRoIGV2ZW50LnByZXZlbnREZWZhdWx0KClcblx0XHQvLyBzbyB3ZSBjaGVjayBhZ2FpbiBsYXRlclxuXHRcdHRoaXMuX2RlbGF5KCBjaGVja0ZvY3VzICk7XG5cdH0sXG5cblx0X2NyZWF0ZVdyYXBwZXI6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMudWlEaWFsb2cgPSAkKCBcIjxkaXY+XCIgKVxuXHRcdFx0LmhpZGUoKVxuXHRcdFx0LmF0dHIoIHtcblxuXHRcdFx0XHQvLyBTZXR0aW5nIHRhYkluZGV4IG1ha2VzIHRoZSBkaXYgZm9jdXNhYmxlXG5cdFx0XHRcdHRhYkluZGV4OiAtMSxcblx0XHRcdFx0cm9sZTogXCJkaWFsb2dcIlxuXHRcdFx0fSApXG5cdFx0XHQuYXBwZW5kVG8oIHRoaXMuX2FwcGVuZFRvKCkgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnVpRGlhbG9nLCBcInVpLWRpYWxvZ1wiLCBcInVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudCB1aS1mcm9udFwiICk7XG5cdFx0dGhpcy5fb24oIHRoaXMudWlEaWFsb2csIHtcblx0XHRcdGtleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuY2xvc2VPbkVzY2FwZSAmJiAhZXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkgJiYgZXZlbnQua2V5Q29kZSAmJlxuXHRcdFx0XHRcdFx0ZXZlbnQua2V5Q29kZSA9PT0gJC51aS5rZXlDb2RlLkVTQ0FQRSApIHtcblx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdHRoaXMuY2xvc2UoIGV2ZW50ICk7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUHJldmVudCB0YWJiaW5nIG91dCBvZiBkaWFsb2dzXG5cdFx0XHRcdGlmICggZXZlbnQua2V5Q29kZSAhPT0gJC51aS5rZXlDb2RlLlRBQiB8fCBldmVudC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdFx0dmFyIHRhYmJhYmxlcyA9IHRoaXMudWlEaWFsb2cuZmluZCggXCI6dGFiYmFibGVcIiApLFxuXHRcdFx0XHRcdGZpcnN0ID0gdGFiYmFibGVzLmZpbHRlciggXCI6Zmlyc3RcIiApLFxuXHRcdFx0XHRcdGxhc3QgPSB0YWJiYWJsZXMuZmlsdGVyKCBcIjpsYXN0XCIgKTtcblxuXHRcdFx0XHRpZiAoICggZXZlbnQudGFyZ2V0ID09PSBsYXN0WyAwIF0gfHwgZXZlbnQudGFyZ2V0ID09PSB0aGlzLnVpRGlhbG9nWyAwIF0gKSAmJlxuXHRcdFx0XHRcdFx0IWV2ZW50LnNoaWZ0S2V5ICkge1xuXHRcdFx0XHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdGZpcnN0LnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCAoIGV2ZW50LnRhcmdldCA9PT0gZmlyc3RbIDAgXSB8fFxuXHRcdFx0XHRcdFx0ZXZlbnQudGFyZ2V0ID09PSB0aGlzLnVpRGlhbG9nWyAwIF0gKSAmJiBldmVudC5zaGlmdEtleSApIHtcblx0XHRcdFx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRsYXN0LnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0bW91c2Vkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5fbW92ZVRvVG9wKCBldmVudCApICkge1xuXHRcdFx0XHRcdHRoaXMuX2ZvY3VzVGFiYmFibGUoKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdC8vIFdlIGFzc3VtZSB0aGF0IGFueSBleGlzdGluZyBhcmlhLWRlc2NyaWJlZGJ5IGF0dHJpYnV0ZSBtZWFuc1xuXHRcdC8vIHRoYXQgdGhlIGRpYWxvZyBjb250ZW50IGlzIG1hcmtlZCB1cCBwcm9wZXJseVxuXHRcdC8vIG90aGVyd2lzZSB3ZSBicnV0ZSBmb3JjZSB0aGUgY29udGVudCBhcyB0aGUgZGVzY3JpcHRpb25cblx0XHRpZiAoICF0aGlzLmVsZW1lbnQuZmluZCggXCJbYXJpYS1kZXNjcmliZWRieV1cIiApLmxlbmd0aCApIHtcblx0XHRcdHRoaXMudWlEaWFsb2cuYXR0cigge1xuXHRcdFx0XHRcImFyaWEtZGVzY3JpYmVkYnlcIjogdGhpcy5lbGVtZW50LnVuaXF1ZUlkKCkuYXR0ciggXCJpZFwiIClcblx0XHRcdH0gKTtcblx0XHR9XG5cdH0sXG5cblx0X2NyZWF0ZVRpdGxlYmFyOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdWlEaWFsb2dUaXRsZTtcblxuXHRcdHRoaXMudWlEaWFsb2dUaXRsZWJhciA9ICQoIFwiPGRpdj5cIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnVpRGlhbG9nVGl0bGViYXIsXG5cdFx0XHRcInVpLWRpYWxvZy10aXRsZWJhclwiLCBcInVpLXdpZGdldC1oZWFkZXIgdWktaGVscGVyLWNsZWFyZml4XCIgKTtcblx0XHR0aGlzLl9vbiggdGhpcy51aURpYWxvZ1RpdGxlYmFyLCB7XG5cdFx0XHRtb3VzZWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdFx0XHQvLyBEb24ndCBwcmV2ZW50IGNsaWNrIG9uIGNsb3NlIGJ1dHRvbiAoIzg4MzgpXG5cdFx0XHRcdC8vIEZvY3VzaW5nIGEgZGlhbG9nIHRoYXQgaXMgcGFydGlhbGx5IHNjcm9sbGVkIG91dCBvZiB2aWV3XG5cdFx0XHRcdC8vIGNhdXNlcyB0aGUgYnJvd3NlciB0byBzY3JvbGwgaXQgaW50byB2aWV3LCBwcmV2ZW50aW5nIHRoZSBjbGljayBldmVudFxuXHRcdFx0XHRpZiAoICEkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCBcIi51aS1kaWFsb2ctdGl0bGViYXItY2xvc2VcIiApICkge1xuXG5cdFx0XHRcdFx0Ly8gRGlhbG9nIGlzbid0IGdldHRpbmcgZm9jdXMgd2hlbiBkcmFnZ2luZyAoIzgwNjMpXG5cdFx0XHRcdFx0dGhpcy51aURpYWxvZy50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdC8vIFN1cHBvcnQ6IElFXG5cdFx0Ly8gVXNlIHR5cGU9XCJidXR0b25cIiB0byBwcmV2ZW50IGVudGVyIGtleXByZXNzZXMgaW4gdGV4dGJveGVzIGZyb20gY2xvc2luZyB0aGVcblx0XHQvLyBkaWFsb2cgaW4gSUUgKCM5MzEyKVxuXHRcdHRoaXMudWlEaWFsb2dUaXRsZWJhckNsb3NlID0gJCggXCI8YnV0dG9uIHR5cGU9J2J1dHRvbic+PC9idXR0b24+XCIgKVxuXHRcdFx0LmJ1dHRvbigge1xuXHRcdFx0XHRsYWJlbDogJCggXCI8YT5cIiApLnRleHQoIHRoaXMub3B0aW9ucy5jbG9zZVRleHQgKS5odG1sKCksXG5cdFx0XHRcdGljb246IFwidWktaWNvbi1jbG9zZXRoaWNrXCIsXG5cdFx0XHRcdHNob3dMYWJlbDogZmFsc2Vcblx0XHRcdH0gKVxuXHRcdFx0LmFwcGVuZFRvKCB0aGlzLnVpRGlhbG9nVGl0bGViYXIgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnVpRGlhbG9nVGl0bGViYXJDbG9zZSwgXCJ1aS1kaWFsb2ctdGl0bGViYXItY2xvc2VcIiApO1xuXHRcdHRoaXMuX29uKCB0aGlzLnVpRGlhbG9nVGl0bGViYXJDbG9zZSwge1xuXHRcdFx0Y2xpY2s6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0dGhpcy5jbG9zZSggZXZlbnQgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHR1aURpYWxvZ1RpdGxlID0gJCggXCI8c3Bhbj5cIiApLnVuaXF1ZUlkKCkucHJlcGVuZFRvKCB0aGlzLnVpRGlhbG9nVGl0bGViYXIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdWlEaWFsb2dUaXRsZSwgXCJ1aS1kaWFsb2ctdGl0bGVcIiApO1xuXHRcdHRoaXMuX3RpdGxlKCB1aURpYWxvZ1RpdGxlICk7XG5cblx0XHR0aGlzLnVpRGlhbG9nVGl0bGViYXIucHJlcGVuZFRvKCB0aGlzLnVpRGlhbG9nICk7XG5cblx0XHR0aGlzLnVpRGlhbG9nLmF0dHIoIHtcblx0XHRcdFwiYXJpYS1sYWJlbGxlZGJ5XCI6IHVpRGlhbG9nVGl0bGUuYXR0ciggXCJpZFwiIClcblx0XHR9ICk7XG5cdH0sXG5cblx0X3RpdGxlOiBmdW5jdGlvbiggdGl0bGUgKSB7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMudGl0bGUgKSB7XG5cdFx0XHR0aXRsZS50ZXh0KCB0aGlzLm9wdGlvbnMudGl0bGUgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGl0bGUuaHRtbCggXCImIzE2MDtcIiApO1xuXHRcdH1cblx0fSxcblxuXHRfY3JlYXRlQnV0dG9uUGFuZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy51aURpYWxvZ0J1dHRvblBhbmUgPSAkKCBcIjxkaXY+XCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy51aURpYWxvZ0J1dHRvblBhbmUsIFwidWktZGlhbG9nLWJ1dHRvbnBhbmVcIixcblx0XHRcdFwidWktd2lkZ2V0LWNvbnRlbnQgdWktaGVscGVyLWNsZWFyZml4XCIgKTtcblxuXHRcdHRoaXMudWlCdXR0b25TZXQgPSAkKCBcIjxkaXY+XCIgKVxuXHRcdFx0LmFwcGVuZFRvKCB0aGlzLnVpRGlhbG9nQnV0dG9uUGFuZSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnVpQnV0dG9uU2V0LCBcInVpLWRpYWxvZy1idXR0b25zZXRcIiApO1xuXG5cdFx0dGhpcy5fY3JlYXRlQnV0dG9ucygpO1xuXHR9LFxuXG5cdF9jcmVhdGVCdXR0b25zOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRidXR0b25zID0gdGhpcy5vcHRpb25zLmJ1dHRvbnM7XG5cblx0XHQvLyBJZiB3ZSBhbHJlYWR5IGhhdmUgYSBidXR0b24gcGFuZSwgcmVtb3ZlIGl0XG5cdFx0dGhpcy51aURpYWxvZ0J1dHRvblBhbmUucmVtb3ZlKCk7XG5cdFx0dGhpcy51aUJ1dHRvblNldC5lbXB0eSgpO1xuXG5cdFx0aWYgKCAkLmlzRW1wdHlPYmplY3QoIGJ1dHRvbnMgKSB8fCAoICQuaXNBcnJheSggYnV0dG9ucyApICYmICFidXR0b25zLmxlbmd0aCApICkge1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMudWlEaWFsb2csIFwidWktZGlhbG9nLWJ1dHRvbnNcIiApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdCQuZWFjaCggYnV0dG9ucywgZnVuY3Rpb24oIG5hbWUsIHByb3BzICkge1xuXHRcdFx0dmFyIGNsaWNrLCBidXR0b25PcHRpb25zO1xuXHRcdFx0cHJvcHMgPSAkLmlzRnVuY3Rpb24oIHByb3BzICkgP1xuXHRcdFx0XHR7IGNsaWNrOiBwcm9wcywgdGV4dDogbmFtZSB9IDpcblx0XHRcdFx0cHJvcHM7XG5cblx0XHRcdC8vIERlZmF1bHQgdG8gYSBub24tc3VibWl0dGluZyBidXR0b25cblx0XHRcdHByb3BzID0gJC5leHRlbmQoIHsgdHlwZTogXCJidXR0b25cIiB9LCBwcm9wcyApO1xuXG5cdFx0XHQvLyBDaGFuZ2UgdGhlIGNvbnRleHQgZm9yIHRoZSBjbGljayBjYWxsYmFjayB0byBiZSB0aGUgbWFpbiBlbGVtZW50XG5cdFx0XHRjbGljayA9IHByb3BzLmNsaWNrO1xuXHRcdFx0YnV0dG9uT3B0aW9ucyA9IHtcblx0XHRcdFx0aWNvbjogcHJvcHMuaWNvbixcblx0XHRcdFx0aWNvblBvc2l0aW9uOiBwcm9wcy5pY29uUG9zaXRpb24sXG5cdFx0XHRcdHNob3dMYWJlbDogcHJvcHMuc2hvd0xhYmVsLFxuXG5cdFx0XHRcdC8vIERlcHJlY2F0ZWQgb3B0aW9uc1xuXHRcdFx0XHRpY29uczogcHJvcHMuaWNvbnMsXG5cdFx0XHRcdHRleHQ6IHByb3BzLnRleHRcblx0XHRcdH07XG5cblx0XHRcdGRlbGV0ZSBwcm9wcy5jbGljaztcblx0XHRcdGRlbGV0ZSBwcm9wcy5pY29uO1xuXHRcdFx0ZGVsZXRlIHByb3BzLmljb25Qb3NpdGlvbjtcblx0XHRcdGRlbGV0ZSBwcm9wcy5zaG93TGFiZWw7XG5cblx0XHRcdC8vIERlcHJlY2F0ZWQgb3B0aW9uc1xuXHRcdFx0ZGVsZXRlIHByb3BzLmljb25zO1xuXHRcdFx0aWYgKCB0eXBlb2YgcHJvcHMudGV4dCA9PT0gXCJib29sZWFuXCIgKSB7XG5cdFx0XHRcdGRlbGV0ZSBwcm9wcy50ZXh0O1xuXHRcdFx0fVxuXG5cdFx0XHQkKCBcIjxidXR0b24+PC9idXR0b24+XCIsIHByb3BzIClcblx0XHRcdFx0LmJ1dHRvbiggYnV0dG9uT3B0aW9ucyApXG5cdFx0XHRcdC5hcHBlbmRUbyggdGhhdC51aUJ1dHRvblNldCApXG5cdFx0XHRcdC5vbiggXCJjbGlja1wiLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRjbGljay5hcHBseSggdGhhdC5lbGVtZW50WyAwIF0sIGFyZ3VtZW50cyApO1xuXHRcdFx0XHR9ICk7XG5cdFx0fSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnVpRGlhbG9nLCBcInVpLWRpYWxvZy1idXR0b25zXCIgKTtcblx0XHR0aGlzLnVpRGlhbG9nQnV0dG9uUGFuZS5hcHBlbmRUbyggdGhpcy51aURpYWxvZyApO1xuXHR9LFxuXG5cdF9tYWtlRHJhZ2dhYmxlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0ZnVuY3Rpb24gZmlsdGVyZWRVaSggdWkgKSB7XG5cdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRwb3NpdGlvbjogdWkucG9zaXRpb24sXG5cdFx0XHRcdG9mZnNldDogdWkub2Zmc2V0XG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdHRoaXMudWlEaWFsb2cuZHJhZ2dhYmxlKCB7XG5cdFx0XHRjYW5jZWw6IFwiLnVpLWRpYWxvZy1jb250ZW50LCAudWktZGlhbG9nLXRpdGxlYmFyLWNsb3NlXCIsXG5cdFx0XHRoYW5kbGU6IFwiLnVpLWRpYWxvZy10aXRsZWJhclwiLFxuXHRcdFx0Y29udGFpbm1lbnQ6IFwiZG9jdW1lbnRcIixcblx0XHRcdHN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggJCggdGhpcyApLCBcInVpLWRpYWxvZy1kcmFnZ2luZ1wiICk7XG5cdFx0XHRcdHRoYXQuX2Jsb2NrRnJhbWVzKCk7XG5cdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwiZHJhZ1N0YXJ0XCIsIGV2ZW50LCBmaWx0ZXJlZFVpKCB1aSApICk7XG5cdFx0XHR9LFxuXHRcdFx0ZHJhZzogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJkcmFnXCIsIGV2ZW50LCBmaWx0ZXJlZFVpKCB1aSApICk7XG5cdFx0XHR9LFxuXHRcdFx0c3RvcDogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0dmFyIGxlZnQgPSB1aS5vZmZzZXQubGVmdCAtIHRoYXQuZG9jdW1lbnQuc2Nyb2xsTGVmdCgpLFxuXHRcdFx0XHRcdHRvcCA9IHVpLm9mZnNldC50b3AgLSB0aGF0LmRvY3VtZW50LnNjcm9sbFRvcCgpO1xuXG5cdFx0XHRcdG9wdGlvbnMucG9zaXRpb24gPSB7XG5cdFx0XHRcdFx0bXk6IFwibGVmdCB0b3BcIixcblx0XHRcdFx0XHRhdDogXCJsZWZ0XCIgKyAoIGxlZnQgPj0gMCA/IFwiK1wiIDogXCJcIiApICsgbGVmdCArIFwiIFwiICtcblx0XHRcdFx0XHRcdFwidG9wXCIgKyAoIHRvcCA+PSAwID8gXCIrXCIgOiBcIlwiICkgKyB0b3AsXG5cdFx0XHRcdFx0b2Y6IHRoYXQud2luZG93XG5cdFx0XHRcdH07XG5cdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCAkKCB0aGlzICksIFwidWktZGlhbG9nLWRyYWdnaW5nXCIgKTtcblx0XHRcdFx0dGhhdC5fdW5ibG9ja0ZyYW1lcygpO1xuXHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcImRyYWdTdG9wXCIsIGV2ZW50LCBmaWx0ZXJlZFVpKCB1aSApICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9tYWtlUmVzaXphYmxlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0aGFuZGxlcyA9IG9wdGlvbnMucmVzaXphYmxlLFxuXG5cdFx0XHQvLyAudWktcmVzaXphYmxlIGhhcyBwb3NpdGlvbjogcmVsYXRpdmUgZGVmaW5lZCBpbiB0aGUgc3R5bGVzaGVldFxuXHRcdFx0Ly8gYnV0IGRpYWxvZ3MgaGF2ZSB0byB1c2UgYWJzb2x1dGUgb3IgZml4ZWQgcG9zaXRpb25pbmdcblx0XHRcdHBvc2l0aW9uID0gdGhpcy51aURpYWxvZy5jc3MoIFwicG9zaXRpb25cIiApLFxuXHRcdFx0cmVzaXplSGFuZGxlcyA9IHR5cGVvZiBoYW5kbGVzID09PSBcInN0cmluZ1wiID9cblx0XHRcdFx0aGFuZGxlcyA6XG5cdFx0XHRcdFwibixlLHMsdyxzZSxzdyxuZSxud1wiO1xuXG5cdFx0ZnVuY3Rpb24gZmlsdGVyZWRVaSggdWkgKSB7XG5cdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRvcmlnaW5hbFBvc2l0aW9uOiB1aS5vcmlnaW5hbFBvc2l0aW9uLFxuXHRcdFx0XHRvcmlnaW5hbFNpemU6IHVpLm9yaWdpbmFsU2l6ZSxcblx0XHRcdFx0cG9zaXRpb246IHVpLnBvc2l0aW9uLFxuXHRcdFx0XHRzaXplOiB1aS5zaXplXG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdHRoaXMudWlEaWFsb2cucmVzaXphYmxlKCB7XG5cdFx0XHRjYW5jZWw6IFwiLnVpLWRpYWxvZy1jb250ZW50XCIsXG5cdFx0XHRjb250YWlubWVudDogXCJkb2N1bWVudFwiLFxuXHRcdFx0YWxzb1Jlc2l6ZTogdGhpcy5lbGVtZW50LFxuXHRcdFx0bWF4V2lkdGg6IG9wdGlvbnMubWF4V2lkdGgsXG5cdFx0XHRtYXhIZWlnaHQ6IG9wdGlvbnMubWF4SGVpZ2h0LFxuXHRcdFx0bWluV2lkdGg6IG9wdGlvbnMubWluV2lkdGgsXG5cdFx0XHRtaW5IZWlnaHQ6IHRoaXMuX21pbkhlaWdodCgpLFxuXHRcdFx0aGFuZGxlczogcmVzaXplSGFuZGxlcyxcblx0XHRcdHN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggJCggdGhpcyApLCBcInVpLWRpYWxvZy1yZXNpemluZ1wiICk7XG5cdFx0XHRcdHRoYXQuX2Jsb2NrRnJhbWVzKCk7XG5cdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwicmVzaXplU3RhcnRcIiwgZXZlbnQsIGZpbHRlcmVkVWkoIHVpICkgKTtcblx0XHRcdH0sXG5cdFx0XHRyZXNpemU6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwicmVzaXplXCIsIGV2ZW50LCBmaWx0ZXJlZFVpKCB1aSApICk7XG5cdFx0XHR9LFxuXHRcdFx0c3RvcDogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0dmFyIG9mZnNldCA9IHRoYXQudWlEaWFsb2cub2Zmc2V0KCksXG5cdFx0XHRcdFx0bGVmdCA9IG9mZnNldC5sZWZ0IC0gdGhhdC5kb2N1bWVudC5zY3JvbGxMZWZ0KCksXG5cdFx0XHRcdFx0dG9wID0gb2Zmc2V0LnRvcCAtIHRoYXQuZG9jdW1lbnQuc2Nyb2xsVG9wKCk7XG5cblx0XHRcdFx0b3B0aW9ucy5oZWlnaHQgPSB0aGF0LnVpRGlhbG9nLmhlaWdodCgpO1xuXHRcdFx0XHRvcHRpb25zLndpZHRoID0gdGhhdC51aURpYWxvZy53aWR0aCgpO1xuXHRcdFx0XHRvcHRpb25zLnBvc2l0aW9uID0ge1xuXHRcdFx0XHRcdG15OiBcImxlZnQgdG9wXCIsXG5cdFx0XHRcdFx0YXQ6IFwibGVmdFwiICsgKCBsZWZ0ID49IDAgPyBcIitcIiA6IFwiXCIgKSArIGxlZnQgKyBcIiBcIiArXG5cdFx0XHRcdFx0XHRcInRvcFwiICsgKCB0b3AgPj0gMCA/IFwiK1wiIDogXCJcIiApICsgdG9wLFxuXHRcdFx0XHRcdG9mOiB0aGF0LndpbmRvd1xuXHRcdFx0XHR9O1xuXHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggJCggdGhpcyApLCBcInVpLWRpYWxvZy1yZXNpemluZ1wiICk7XG5cdFx0XHRcdHRoYXQuX3VuYmxvY2tGcmFtZXMoKTtcblx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJyZXNpemVTdG9wXCIsIGV2ZW50LCBmaWx0ZXJlZFVpKCB1aSApICk7XG5cdFx0XHR9XG5cdFx0fSApXG5cdFx0XHQuY3NzKCBcInBvc2l0aW9uXCIsIHBvc2l0aW9uICk7XG5cdH0sXG5cblx0X3RyYWNrRm9jdXM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX29uKCB0aGlzLndpZGdldCgpLCB7XG5cdFx0XHRmb2N1c2luOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuX21ha2VGb2N1c1RhcmdldCgpO1xuXHRcdFx0XHR0aGlzLl9mb2N1c2VkRWxlbWVudCA9ICQoIGV2ZW50LnRhcmdldCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfbWFrZUZvY3VzVGFyZ2V0OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl91bnRyYWNrSW5zdGFuY2UoKTtcblx0XHR0aGlzLl90cmFja2luZ0luc3RhbmNlcygpLnVuc2hpZnQoIHRoaXMgKTtcblx0fSxcblxuXHRfdW50cmFja0luc3RhbmNlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgaW5zdGFuY2VzID0gdGhpcy5fdHJhY2tpbmdJbnN0YW5jZXMoKSxcblx0XHRcdGV4aXN0cyA9ICQuaW5BcnJheSggdGhpcywgaW5zdGFuY2VzICk7XG5cdFx0aWYgKCBleGlzdHMgIT09IC0xICkge1xuXHRcdFx0aW5zdGFuY2VzLnNwbGljZSggZXhpc3RzLCAxICk7XG5cdFx0fVxuXHR9LFxuXG5cdF90cmFja2luZ0luc3RhbmNlczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGluc3RhbmNlcyA9IHRoaXMuZG9jdW1lbnQuZGF0YSggXCJ1aS1kaWFsb2ctaW5zdGFuY2VzXCIgKTtcblx0XHRpZiAoICFpbnN0YW5jZXMgKSB7XG5cdFx0XHRpbnN0YW5jZXMgPSBbXTtcblx0XHRcdHRoaXMuZG9jdW1lbnQuZGF0YSggXCJ1aS1kaWFsb2ctaW5zdGFuY2VzXCIsIGluc3RhbmNlcyApO1xuXHRcdH1cblx0XHRyZXR1cm4gaW5zdGFuY2VzO1xuXHR9LFxuXG5cdF9taW5IZWlnaHQ6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0cmV0dXJuIG9wdGlvbnMuaGVpZ2h0ID09PSBcImF1dG9cIiA/XG5cdFx0XHRvcHRpb25zLm1pbkhlaWdodCA6XG5cdFx0XHRNYXRoLm1pbiggb3B0aW9ucy5taW5IZWlnaHQsIG9wdGlvbnMuaGVpZ2h0ICk7XG5cdH0sXG5cblx0X3Bvc2l0aW9uOiBmdW5jdGlvbigpIHtcblxuXHRcdC8vIE5lZWQgdG8gc2hvdyB0aGUgZGlhbG9nIHRvIGdldCB0aGUgYWN0dWFsIG9mZnNldCBpbiB0aGUgcG9zaXRpb24gcGx1Z2luXG5cdFx0dmFyIGlzVmlzaWJsZSA9IHRoaXMudWlEaWFsb2cuaXMoIFwiOnZpc2libGVcIiApO1xuXHRcdGlmICggIWlzVmlzaWJsZSApIHtcblx0XHRcdHRoaXMudWlEaWFsb2cuc2hvdygpO1xuXHRcdH1cblx0XHR0aGlzLnVpRGlhbG9nLnBvc2l0aW9uKCB0aGlzLm9wdGlvbnMucG9zaXRpb24gKTtcblx0XHRpZiAoICFpc1Zpc2libGUgKSB7XG5cdFx0XHR0aGlzLnVpRGlhbG9nLmhpZGUoKTtcblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbnM6IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdHJlc2l6ZSA9IGZhbHNlLFxuXHRcdFx0cmVzaXphYmxlT3B0aW9ucyA9IHt9O1xuXG5cdFx0JC5lYWNoKCBvcHRpb25zLCBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRcdHRoYXQuX3NldE9wdGlvbigga2V5LCB2YWx1ZSApO1xuXG5cdFx0XHRpZiAoIGtleSBpbiB0aGF0LnNpemVSZWxhdGVkT3B0aW9ucyApIHtcblx0XHRcdFx0cmVzaXplID0gdHJ1ZTtcblx0XHRcdH1cblx0XHRcdGlmICgga2V5IGluIHRoYXQucmVzaXphYmxlUmVsYXRlZE9wdGlvbnMgKSB7XG5cdFx0XHRcdHJlc2l6YWJsZU9wdGlvbnNbIGtleSBdID0gdmFsdWU7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0aWYgKCByZXNpemUgKSB7XG5cdFx0XHR0aGlzLl9zaXplKCk7XG5cdFx0XHR0aGlzLl9wb3NpdGlvbigpO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMudWlEaWFsb2cuaXMoIFwiOmRhdGEodWktcmVzaXphYmxlKVwiICkgKSB7XG5cdFx0XHR0aGlzLnVpRGlhbG9nLnJlc2l6YWJsZSggXCJvcHRpb25cIiwgcmVzaXphYmxlT3B0aW9ucyApO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHR2YXIgaXNEcmFnZ2FibGUsIGlzUmVzaXphYmxlLFxuXHRcdFx0dWlEaWFsb2cgPSB0aGlzLnVpRGlhbG9nO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiZGlzYWJsZWRcIiApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiYXBwZW5kVG9cIiApIHtcblx0XHRcdHRoaXMudWlEaWFsb2cuYXBwZW5kVG8oIHRoaXMuX2FwcGVuZFRvKCkgKTtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJidXR0b25zXCIgKSB7XG5cdFx0XHR0aGlzLl9jcmVhdGVCdXR0b25zKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwiY2xvc2VUZXh0XCIgKSB7XG5cdFx0XHR0aGlzLnVpRGlhbG9nVGl0bGViYXJDbG9zZS5idXR0b24oIHtcblxuXHRcdFx0XHQvLyBFbnN1cmUgdGhhdCB3ZSBhbHdheXMgcGFzcyBhIHN0cmluZ1xuXHRcdFx0XHRsYWJlbDogJCggXCI8YT5cIiApLnRleHQoIFwiXCIgKyB0aGlzLm9wdGlvbnMuY2xvc2VUZXh0ICkuaHRtbCgpXG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwiZHJhZ2dhYmxlXCIgKSB7XG5cdFx0XHRpc0RyYWdnYWJsZSA9IHVpRGlhbG9nLmlzKCBcIjpkYXRhKHVpLWRyYWdnYWJsZSlcIiApO1xuXHRcdFx0aWYgKCBpc0RyYWdnYWJsZSAmJiAhdmFsdWUgKSB7XG5cdFx0XHRcdHVpRGlhbG9nLmRyYWdnYWJsZSggXCJkZXN0cm95XCIgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhaXNEcmFnZ2FibGUgJiYgdmFsdWUgKSB7XG5cdFx0XHRcdHRoaXMuX21ha2VEcmFnZ2FibGUoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJwb3NpdGlvblwiICkge1xuXHRcdFx0dGhpcy5fcG9zaXRpb24oKTtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJyZXNpemFibGVcIiApIHtcblxuXHRcdFx0Ly8gY3VycmVudGx5IHJlc2l6YWJsZSwgYmVjb21pbmcgbm9uLXJlc2l6YWJsZVxuXHRcdFx0aXNSZXNpemFibGUgPSB1aURpYWxvZy5pcyggXCI6ZGF0YSh1aS1yZXNpemFibGUpXCIgKTtcblx0XHRcdGlmICggaXNSZXNpemFibGUgJiYgIXZhbHVlICkge1xuXHRcdFx0XHR1aURpYWxvZy5yZXNpemFibGUoIFwiZGVzdHJveVwiICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEN1cnJlbnRseSByZXNpemFibGUsIGNoYW5naW5nIGhhbmRsZXNcblx0XHRcdGlmICggaXNSZXNpemFibGUgJiYgdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0XHR1aURpYWxvZy5yZXNpemFibGUoIFwib3B0aW9uXCIsIFwiaGFuZGxlc1wiLCB2YWx1ZSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDdXJyZW50bHkgbm9uLXJlc2l6YWJsZSwgYmVjb21pbmcgcmVzaXphYmxlXG5cdFx0XHRpZiAoICFpc1Jlc2l6YWJsZSAmJiB2YWx1ZSAhPT0gZmFsc2UgKSB7XG5cdFx0XHRcdHRoaXMuX21ha2VSZXNpemFibGUoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJ0aXRsZVwiICkge1xuXHRcdFx0dGhpcy5fdGl0bGUoIHRoaXMudWlEaWFsb2dUaXRsZWJhci5maW5kKCBcIi51aS1kaWFsb2ctdGl0bGVcIiApICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zaXplOiBmdW5jdGlvbigpIHtcblxuXHRcdC8vIElmIHRoZSB1c2VyIGhhcyByZXNpemVkIHRoZSBkaWFsb2csIHRoZSAudWktZGlhbG9nIGFuZCAudWktZGlhbG9nLWNvbnRlbnRcblx0XHQvLyBkaXZzIHdpbGwgYm90aCBoYXZlIHdpZHRoIGFuZCBoZWlnaHQgc2V0LCBzbyB3ZSBuZWVkIHRvIHJlc2V0IHRoZW1cblx0XHR2YXIgbm9uQ29udGVudEhlaWdodCwgbWluQ29udGVudEhlaWdodCwgbWF4Q29udGVudEhlaWdodCxcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHQvLyBSZXNldCBjb250ZW50IHNpemluZ1xuXHRcdHRoaXMuZWxlbWVudC5zaG93KCkuY3NzKCB7XG5cdFx0XHR3aWR0aDogXCJhdXRvXCIsXG5cdFx0XHRtaW5IZWlnaHQ6IDAsXG5cdFx0XHRtYXhIZWlnaHQ6IFwibm9uZVwiLFxuXHRcdFx0aGVpZ2h0OiAwXG5cdFx0fSApO1xuXG5cdFx0aWYgKCBvcHRpb25zLm1pbldpZHRoID4gb3B0aW9ucy53aWR0aCApIHtcblx0XHRcdG9wdGlvbnMud2lkdGggPSBvcHRpb25zLm1pbldpZHRoO1xuXHRcdH1cblxuXHRcdC8vIFJlc2V0IHdyYXBwZXIgc2l6aW5nXG5cdFx0Ly8gZGV0ZXJtaW5lIHRoZSBoZWlnaHQgb2YgYWxsIHRoZSBub24tY29udGVudCBlbGVtZW50c1xuXHRcdG5vbkNvbnRlbnRIZWlnaHQgPSB0aGlzLnVpRGlhbG9nLmNzcygge1xuXHRcdFx0aGVpZ2h0OiBcImF1dG9cIixcblx0XHRcdHdpZHRoOiBvcHRpb25zLndpZHRoXG5cdFx0fSApXG5cdFx0XHQub3V0ZXJIZWlnaHQoKTtcblx0XHRtaW5Db250ZW50SGVpZ2h0ID0gTWF0aC5tYXgoIDAsIG9wdGlvbnMubWluSGVpZ2h0IC0gbm9uQ29udGVudEhlaWdodCApO1xuXHRcdG1heENvbnRlbnRIZWlnaHQgPSB0eXBlb2Ygb3B0aW9ucy5tYXhIZWlnaHQgPT09IFwibnVtYmVyXCIgP1xuXHRcdFx0TWF0aC5tYXgoIDAsIG9wdGlvbnMubWF4SGVpZ2h0IC0gbm9uQ29udGVudEhlaWdodCApIDpcblx0XHRcdFwibm9uZVwiO1xuXG5cdFx0aWYgKCBvcHRpb25zLmhlaWdodCA9PT0gXCJhdXRvXCIgKSB7XG5cdFx0XHR0aGlzLmVsZW1lbnQuY3NzKCB7XG5cdFx0XHRcdG1pbkhlaWdodDogbWluQ29udGVudEhlaWdodCxcblx0XHRcdFx0bWF4SGVpZ2h0OiBtYXhDb250ZW50SGVpZ2h0LFxuXHRcdFx0XHRoZWlnaHQ6IFwiYXV0b1wiXG5cdFx0XHR9ICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuZWxlbWVudC5oZWlnaHQoIE1hdGgubWF4KCAwLCBvcHRpb25zLmhlaWdodCAtIG5vbkNvbnRlbnRIZWlnaHQgKSApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy51aURpYWxvZy5pcyggXCI6ZGF0YSh1aS1yZXNpemFibGUpXCIgKSApIHtcblx0XHRcdHRoaXMudWlEaWFsb2cucmVzaXphYmxlKCBcIm9wdGlvblwiLCBcIm1pbkhlaWdodFwiLCB0aGlzLl9taW5IZWlnaHQoKSApO1xuXHRcdH1cblx0fSxcblxuXHRfYmxvY2tGcmFtZXM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuaWZyYW1lQmxvY2tzID0gdGhpcy5kb2N1bWVudC5maW5kKCBcImlmcmFtZVwiICkubWFwKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBpZnJhbWUgPSAkKCB0aGlzICk7XG5cblx0XHRcdHJldHVybiAkKCBcIjxkaXY+XCIgKVxuXHRcdFx0XHQuY3NzKCB7XG5cdFx0XHRcdFx0cG9zaXRpb246IFwiYWJzb2x1dGVcIixcblx0XHRcdFx0XHR3aWR0aDogaWZyYW1lLm91dGVyV2lkdGgoKSxcblx0XHRcdFx0XHRoZWlnaHQ6IGlmcmFtZS5vdXRlckhlaWdodCgpXG5cdFx0XHRcdH0gKVxuXHRcdFx0XHQuYXBwZW5kVG8oIGlmcmFtZS5wYXJlbnQoKSApXG5cdFx0XHRcdC5vZmZzZXQoIGlmcmFtZS5vZmZzZXQoKSApWyAwIF07XG5cdFx0fSApO1xuXHR9LFxuXG5cdF91bmJsb2NrRnJhbWVzOiBmdW5jdGlvbigpIHtcblx0XHRpZiAoIHRoaXMuaWZyYW1lQmxvY2tzICkge1xuXHRcdFx0dGhpcy5pZnJhbWVCbG9ja3MucmVtb3ZlKCk7XG5cdFx0XHRkZWxldGUgdGhpcy5pZnJhbWVCbG9ja3M7XG5cdFx0fVxuXHR9LFxuXG5cdF9hbGxvd0ludGVyYWN0aW9uOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCAkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCBcIi51aS1kaWFsb2dcIiApLmxlbmd0aCApIHtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblxuXHRcdC8vIFRPRE86IFJlbW92ZSBoYWNrIHdoZW4gZGF0ZXBpY2tlciBpbXBsZW1lbnRzXG5cdFx0Ly8gdGhlIC51aS1mcm9udCBsb2dpYyAoIzg5ODkpXG5cdFx0cmV0dXJuICEhJCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggXCIudWktZGF0ZXBpY2tlclwiICkubGVuZ3RoO1xuXHR9LFxuXG5cdF9jcmVhdGVPdmVybGF5OiBmdW5jdGlvbigpIHtcblx0XHRpZiAoICF0aGlzLm9wdGlvbnMubW9kYWwgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gV2UgdXNlIGEgZGVsYXkgaW4gY2FzZSB0aGUgb3ZlcmxheSBpcyBjcmVhdGVkIGZyb20gYW5cblx0XHQvLyBldmVudCB0aGF0IHdlJ3JlIGdvaW5nIHRvIGJlIGNhbmNlbGxpbmcgKCMyODA0KVxuXHRcdHZhciBpc09wZW5pbmcgPSB0cnVlO1xuXHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdGlzT3BlbmluZyA9IGZhbHNlO1xuXHRcdH0gKTtcblxuXHRcdGlmICggIXRoaXMuZG9jdW1lbnQuZGF0YSggXCJ1aS1kaWFsb2ctb3ZlcmxheXNcIiApICkge1xuXG5cdFx0XHQvLyBQcmV2ZW50IHVzZSBvZiBhbmNob3JzIGFuZCBpbnB1dHNcblx0XHRcdC8vIFVzaW5nIF9vbigpIGZvciBhbiBldmVudCBoYW5kbGVyIHNoYXJlZCBhY3Jvc3MgbWFueSBpbnN0YW5jZXMgaXNcblx0XHRcdC8vIHNhZmUgYmVjYXVzZSB0aGUgZGlhbG9ncyBzdGFjayBhbmQgbXVzdCBiZSBjbG9zZWQgaW4gcmV2ZXJzZSBvcmRlclxuXHRcdFx0dGhpcy5fb24oIHRoaXMuZG9jdW1lbnQsIHtcblx0XHRcdFx0Zm9jdXNpbjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRcdGlmICggaXNPcGVuaW5nICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggIXRoaXMuX2FsbG93SW50ZXJhY3Rpb24oIGV2ZW50ICkgKSB7XG5cdFx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0dGhpcy5fdHJhY2tpbmdJbnN0YW5jZXMoKVsgMCBdLl9mb2N1c1RhYmJhYmxlKCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5vdmVybGF5ID0gJCggXCI8ZGl2PlwiIClcblx0XHRcdC5hcHBlbmRUbyggdGhpcy5fYXBwZW5kVG8oKSApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMub3ZlcmxheSwgbnVsbCwgXCJ1aS13aWRnZXQtb3ZlcmxheSB1aS1mcm9udFwiICk7XG5cdFx0dGhpcy5fb24oIHRoaXMub3ZlcmxheSwge1xuXHRcdFx0bW91c2Vkb3duOiBcIl9rZWVwRm9jdXNcIlxuXHRcdH0gKTtcblx0XHR0aGlzLmRvY3VtZW50LmRhdGEoIFwidWktZGlhbG9nLW92ZXJsYXlzXCIsXG5cdFx0XHQoIHRoaXMuZG9jdW1lbnQuZGF0YSggXCJ1aS1kaWFsb2ctb3ZlcmxheXNcIiApIHx8IDAgKSArIDEgKTtcblx0fSxcblxuXHRfZGVzdHJveU92ZXJsYXk6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggIXRoaXMub3B0aW9ucy5tb2RhbCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMub3ZlcmxheSApIHtcblx0XHRcdHZhciBvdmVybGF5cyA9IHRoaXMuZG9jdW1lbnQuZGF0YSggXCJ1aS1kaWFsb2ctb3ZlcmxheXNcIiApIC0gMTtcblxuXHRcdFx0aWYgKCAhb3ZlcmxheXMgKSB7XG5cdFx0XHRcdHRoaXMuX29mZiggdGhpcy5kb2N1bWVudCwgXCJmb2N1c2luXCIgKTtcblx0XHRcdFx0dGhpcy5kb2N1bWVudC5yZW1vdmVEYXRhKCBcInVpLWRpYWxvZy1vdmVybGF5c1wiICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLmRvY3VtZW50LmRhdGEoIFwidWktZGlhbG9nLW92ZXJsYXlzXCIsIG92ZXJsYXlzICk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMub3ZlcmxheS5yZW1vdmUoKTtcblx0XHRcdHRoaXMub3ZlcmxheSA9IG51bGw7XG5cdFx0fVxuXHR9XG59ICk7XG5cbi8vIERFUFJFQ0FURURcbi8vIFRPRE86IHN3aXRjaCByZXR1cm4gYmFjayB0byB3aWRnZXQgZGVjbGFyYXRpb24gYXQgdG9wIG9mIGZpbGUgd2hlbiB0aGlzIGlzIHJlbW92ZWRcbmlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICkge1xuXG5cdC8vIEJhY2tjb21wYXQgZm9yIGRpYWxvZ0NsYXNzIG9wdGlvblxuXHQkLndpZGdldCggXCJ1aS5kaWFsb2dcIiwgJC51aS5kaWFsb2csIHtcblx0XHRvcHRpb25zOiB7XG5cdFx0XHRkaWFsb2dDbGFzczogXCJcIlxuXHRcdH0sXG5cdFx0X2NyZWF0ZVdyYXBwZXI6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5fc3VwZXIoKTtcblx0XHRcdHRoaXMudWlEaWFsb2cuYWRkQ2xhc3MoIHRoaXMub3B0aW9ucy5kaWFsb2dDbGFzcyApO1xuXHRcdH0sXG5cdFx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0XHRpZiAoIGtleSA9PT0gXCJkaWFsb2dDbGFzc1wiICkge1xuXHRcdFx0XHR0aGlzLnVpRGlhbG9nXG5cdFx0XHRcdFx0LnJlbW92ZUNsYXNzKCB0aGlzLm9wdGlvbnMuZGlhbG9nQ2xhc3MgKVxuXHRcdFx0XHRcdC5hZGRDbGFzcyggdmFsdWUgKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuX3N1cGVyQXBwbHkoIGFyZ3VtZW50cyApO1xuXHRcdH1cblx0fSApO1xufVxuXG52YXIgd2lkZ2V0c0RpYWxvZyA9ICQudWkuZGlhbG9nO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIERyb3BwYWJsZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRHJvcHBhYmxlXG4vLz4+Z3JvdXA6IEludGVyYWN0aW9uc1xuLy8+PmRlc2NyaXB0aW9uOiBFbmFibGVzIGRyb3AgdGFyZ2V0cyBmb3IgZHJhZ2dhYmxlIGVsZW1lbnRzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2Ryb3BwYWJsZS9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9kcm9wcGFibGUvXG5cblxuXG4kLndpZGdldCggXCJ1aS5kcm9wcGFibGVcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHR3aWRnZXRFdmVudFByZWZpeDogXCJkcm9wXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRhY2NlcHQ6IFwiKlwiLFxuXHRcdGFkZENsYXNzZXM6IHRydWUsXG5cdFx0Z3JlZWR5OiBmYWxzZSxcblx0XHRzY29wZTogXCJkZWZhdWx0XCIsXG5cdFx0dG9sZXJhbmNlOiBcImludGVyc2VjdFwiLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0YWN0aXZhdGU6IG51bGwsXG5cdFx0ZGVhY3RpdmF0ZTogbnVsbCxcblx0XHRkcm9wOiBudWxsLFxuXHRcdG91dDogbnVsbCxcblx0XHRvdmVyOiBudWxsXG5cdH0sXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0dmFyIHByb3BvcnRpb25zLFxuXHRcdFx0byA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGFjY2VwdCA9IG8uYWNjZXB0O1xuXG5cdFx0dGhpcy5pc292ZXIgPSBmYWxzZTtcblx0XHR0aGlzLmlzb3V0ID0gdHJ1ZTtcblxuXHRcdHRoaXMuYWNjZXB0ID0gJC5pc0Z1bmN0aW9uKCBhY2NlcHQgKSA/IGFjY2VwdCA6IGZ1bmN0aW9uKCBkICkge1xuXHRcdFx0cmV0dXJuIGQuaXMoIGFjY2VwdCApO1xuXHRcdH07XG5cblx0XHR0aGlzLnByb3BvcnRpb25zID0gZnVuY3Rpb24oIC8qIHZhbHVlVG9Xcml0ZSAqLyApIHtcblx0XHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCApIHtcblxuXHRcdFx0XHQvLyBTdG9yZSB0aGUgZHJvcHBhYmxlJ3MgcHJvcG9ydGlvbnNcblx0XHRcdFx0cHJvcG9ydGlvbnMgPSBhcmd1bWVudHNbIDAgXTtcblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gUmV0cmlldmUgb3IgZGVyaXZlIHRoZSBkcm9wcGFibGUncyBwcm9wb3J0aW9uc1xuXHRcdFx0XHRyZXR1cm4gcHJvcG9ydGlvbnMgP1xuXHRcdFx0XHRcdHByb3BvcnRpb25zIDpcblx0XHRcdFx0XHRwcm9wb3J0aW9ucyA9IHtcblx0XHRcdFx0XHRcdHdpZHRoOiB0aGlzLmVsZW1lbnRbIDAgXS5vZmZzZXRXaWR0aCxcblx0XHRcdFx0XHRcdGhlaWdodDogdGhpcy5lbGVtZW50WyAwIF0ub2Zmc2V0SGVpZ2h0XG5cdFx0XHRcdFx0fTtcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0dGhpcy5fYWRkVG9NYW5hZ2VyKCBvLnNjb3BlICk7XG5cblx0XHRvLmFkZENsYXNzZXMgJiYgdGhpcy5fYWRkQ2xhc3MoIFwidWktZHJvcHBhYmxlXCIgKTtcblxuXHR9LFxuXG5cdF9hZGRUb01hbmFnZXI6IGZ1bmN0aW9uKCBzY29wZSApIHtcblxuXHRcdC8vIEFkZCB0aGUgcmVmZXJlbmNlIGFuZCBwb3NpdGlvbnMgdG8gdGhlIG1hbmFnZXJcblx0XHQkLnVpLmRkbWFuYWdlci5kcm9wcGFibGVzWyBzY29wZSBdID0gJC51aS5kZG1hbmFnZXIuZHJvcHBhYmxlc1sgc2NvcGUgXSB8fCBbXTtcblx0XHQkLnVpLmRkbWFuYWdlci5kcm9wcGFibGVzWyBzY29wZSBdLnB1c2goIHRoaXMgKTtcblx0fSxcblxuXHRfc3BsaWNlOiBmdW5jdGlvbiggZHJvcCApIHtcblx0XHR2YXIgaSA9IDA7XG5cdFx0Zm9yICggOyBpIDwgZHJvcC5sZW5ndGg7IGkrKyApIHtcblx0XHRcdGlmICggZHJvcFsgaSBdID09PSB0aGlzICkge1xuXHRcdFx0XHRkcm9wLnNwbGljZSggaSwgMSApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGRyb3AgPSAkLnVpLmRkbWFuYWdlci5kcm9wcGFibGVzWyB0aGlzLm9wdGlvbnMuc2NvcGUgXTtcblxuXHRcdHRoaXMuX3NwbGljZSggZHJvcCApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiYWNjZXB0XCIgKSB7XG5cdFx0XHR0aGlzLmFjY2VwdCA9ICQuaXNGdW5jdGlvbiggdmFsdWUgKSA/IHZhbHVlIDogZnVuY3Rpb24oIGQgKSB7XG5cdFx0XHRcdHJldHVybiBkLmlzKCB2YWx1ZSApO1xuXHRcdFx0fTtcblx0XHR9IGVsc2UgaWYgKCBrZXkgPT09IFwic2NvcGVcIiApIHtcblx0XHRcdHZhciBkcm9wID0gJC51aS5kZG1hbmFnZXIuZHJvcHBhYmxlc1sgdGhpcy5vcHRpb25zLnNjb3BlIF07XG5cblx0XHRcdHRoaXMuX3NwbGljZSggZHJvcCApO1xuXHRcdFx0dGhpcy5fYWRkVG9NYW5hZ2VyKCB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cdH0sXG5cblx0X2FjdGl2YXRlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGRyYWdnYWJsZSA9ICQudWkuZGRtYW5hZ2VyLmN1cnJlbnQ7XG5cblx0XHR0aGlzLl9hZGRBY3RpdmVDbGFzcygpO1xuXHRcdGlmICggZHJhZ2dhYmxlICkge1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJhY3RpdmF0ZVwiLCBldmVudCwgdGhpcy51aSggZHJhZ2dhYmxlICkgKTtcblx0XHR9XG5cdH0sXG5cblx0X2RlYWN0aXZhdGU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgZHJhZ2dhYmxlID0gJC51aS5kZG1hbmFnZXIuY3VycmVudDtcblxuXHRcdHRoaXMuX3JlbW92ZUFjdGl2ZUNsYXNzKCk7XG5cdFx0aWYgKCBkcmFnZ2FibGUgKSB7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImRlYWN0aXZhdGVcIiwgZXZlbnQsIHRoaXMudWkoIGRyYWdnYWJsZSApICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9vdmVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR2YXIgZHJhZ2dhYmxlID0gJC51aS5kZG1hbmFnZXIuY3VycmVudDtcblxuXHRcdC8vIEJhaWwgaWYgZHJhZ2dhYmxlIGFuZCBkcm9wcGFibGUgYXJlIHNhbWUgZWxlbWVudFxuXHRcdGlmICggIWRyYWdnYWJsZSB8fCAoIGRyYWdnYWJsZS5jdXJyZW50SXRlbSB8fFxuXHRcdFx0XHRkcmFnZ2FibGUuZWxlbWVudCApWyAwIF0gPT09IHRoaXMuZWxlbWVudFsgMCBdICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5hY2NlcHQuY2FsbCggdGhpcy5lbGVtZW50WyAwIF0sICggZHJhZ2dhYmxlLmN1cnJlbnRJdGVtIHx8XG5cdFx0XHRcdGRyYWdnYWJsZS5lbGVtZW50ICkgKSApIHtcblx0XHRcdHRoaXMuX2FkZEhvdmVyQ2xhc3MoKTtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwib3ZlclwiLCBldmVudCwgdGhpcy51aSggZHJhZ2dhYmxlICkgKTtcblx0XHR9XG5cblx0fSxcblxuXHRfb3V0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR2YXIgZHJhZ2dhYmxlID0gJC51aS5kZG1hbmFnZXIuY3VycmVudDtcblxuXHRcdC8vIEJhaWwgaWYgZHJhZ2dhYmxlIGFuZCBkcm9wcGFibGUgYXJlIHNhbWUgZWxlbWVudFxuXHRcdGlmICggIWRyYWdnYWJsZSB8fCAoIGRyYWdnYWJsZS5jdXJyZW50SXRlbSB8fFxuXHRcdFx0XHRkcmFnZ2FibGUuZWxlbWVudCApWyAwIF0gPT09IHRoaXMuZWxlbWVudFsgMCBdICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5hY2NlcHQuY2FsbCggdGhpcy5lbGVtZW50WyAwIF0sICggZHJhZ2dhYmxlLmN1cnJlbnRJdGVtIHx8XG5cdFx0XHRcdGRyYWdnYWJsZS5lbGVtZW50ICkgKSApIHtcblx0XHRcdHRoaXMuX3JlbW92ZUhvdmVyQ2xhc3MoKTtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwib3V0XCIsIGV2ZW50LCB0aGlzLnVpKCBkcmFnZ2FibGUgKSApO1xuXHRcdH1cblxuXHR9LFxuXG5cdF9kcm9wOiBmdW5jdGlvbiggZXZlbnQsIGN1c3RvbSApIHtcblxuXHRcdHZhciBkcmFnZ2FibGUgPSBjdXN0b20gfHwgJC51aS5kZG1hbmFnZXIuY3VycmVudCxcblx0XHRcdGNoaWxkcmVuSW50ZXJzZWN0aW9uID0gZmFsc2U7XG5cblx0XHQvLyBCYWlsIGlmIGRyYWdnYWJsZSBhbmQgZHJvcHBhYmxlIGFyZSBzYW1lIGVsZW1lbnRcblx0XHRpZiAoICFkcmFnZ2FibGUgfHwgKCBkcmFnZ2FibGUuY3VycmVudEl0ZW0gfHxcblx0XHRcdFx0ZHJhZ2dhYmxlLmVsZW1lbnQgKVsgMCBdID09PSB0aGlzLmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdC5maW5kKCBcIjpkYXRhKHVpLWRyb3BwYWJsZSlcIiApXG5cdFx0XHQubm90KCBcIi51aS1kcmFnZ2FibGUtZHJhZ2dpbmdcIiApXG5cdFx0XHQuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBpbnN0ID0gJCggdGhpcyApLmRyb3BwYWJsZSggXCJpbnN0YW5jZVwiICk7XG5cdFx0XHRcdGlmIChcblx0XHRcdFx0XHRpbnN0Lm9wdGlvbnMuZ3JlZWR5ICYmXG5cdFx0XHRcdFx0IWluc3Qub3B0aW9ucy5kaXNhYmxlZCAmJlxuXHRcdFx0XHRcdGluc3Qub3B0aW9ucy5zY29wZSA9PT0gZHJhZ2dhYmxlLm9wdGlvbnMuc2NvcGUgJiZcblx0XHRcdFx0XHRpbnN0LmFjY2VwdC5jYWxsKFxuXHRcdFx0XHRcdFx0aW5zdC5lbGVtZW50WyAwIF0sICggZHJhZ2dhYmxlLmN1cnJlbnRJdGVtIHx8IGRyYWdnYWJsZS5lbGVtZW50IClcblx0XHRcdFx0XHQpICYmXG5cdFx0XHRcdFx0aW50ZXJzZWN0KFxuXHRcdFx0XHRcdFx0ZHJhZ2dhYmxlLFxuXHRcdFx0XHRcdFx0JC5leHRlbmQoIGluc3QsIHsgb2Zmc2V0OiBpbnN0LmVsZW1lbnQub2Zmc2V0KCkgfSApLFxuXHRcdFx0XHRcdFx0aW5zdC5vcHRpb25zLnRvbGVyYW5jZSwgZXZlbnRcblx0XHRcdFx0XHQpXG5cdFx0XHRcdCkge1xuXHRcdFx0XHRcdGNoaWxkcmVuSW50ZXJzZWN0aW9uID0gdHJ1ZTtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7IH1cblx0XHRcdH0gKTtcblx0XHRpZiAoIGNoaWxkcmVuSW50ZXJzZWN0aW9uICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5hY2NlcHQuY2FsbCggdGhpcy5lbGVtZW50WyAwIF0sXG5cdFx0XHRcdCggZHJhZ2dhYmxlLmN1cnJlbnRJdGVtIHx8IGRyYWdnYWJsZS5lbGVtZW50ICkgKSApIHtcblx0XHRcdHRoaXMuX3JlbW92ZUFjdGl2ZUNsYXNzKCk7XG5cdFx0XHR0aGlzLl9yZW1vdmVIb3ZlckNsYXNzKCk7XG5cblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiZHJvcFwiLCBldmVudCwgdGhpcy51aSggZHJhZ2dhYmxlICkgKTtcblx0XHRcdHJldHVybiB0aGlzLmVsZW1lbnQ7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXG5cdH0sXG5cblx0dWk6IGZ1bmN0aW9uKCBjICkge1xuXHRcdHJldHVybiB7XG5cdFx0XHRkcmFnZ2FibGU6ICggYy5jdXJyZW50SXRlbSB8fCBjLmVsZW1lbnQgKSxcblx0XHRcdGhlbHBlcjogYy5oZWxwZXIsXG5cdFx0XHRwb3NpdGlvbjogYy5wb3NpdGlvbixcblx0XHRcdG9mZnNldDogYy5wb3NpdGlvbkFic1xuXHRcdH07XG5cdH0sXG5cblx0Ly8gRXh0ZW5zaW9uIHBvaW50cyBqdXN0IHRvIG1ha2UgYmFja2NvbXBhdCBzYW5lIGFuZCBhdm9pZCBkdXBsaWNhdGluZyBsb2dpY1xuXHQvLyBUT0RPOiBSZW1vdmUgaW4gMS4xMyBhbG9uZyB3aXRoIGNhbGwgdG8gaXQgYmVsb3dcblx0X2FkZEhvdmVyQ2xhc3M6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWRyb3BwYWJsZS1ob3ZlclwiICk7XG5cdH0sXG5cblx0X3JlbW92ZUhvdmVyQ2xhc3M6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBcInVpLWRyb3BwYWJsZS1ob3ZlclwiICk7XG5cdH0sXG5cblx0X2FkZEFjdGl2ZUNsYXNzOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1kcm9wcGFibGUtYWN0aXZlXCIgKTtcblx0fSxcblxuXHRfcmVtb3ZlQWN0aXZlQ2xhc3M6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBcInVpLWRyb3BwYWJsZS1hY3RpdmVcIiApO1xuXHR9XG59ICk7XG5cbnZhciBpbnRlcnNlY3QgPSAkLnVpLmludGVyc2VjdCA9ICggZnVuY3Rpb24oKSB7XG5cdGZ1bmN0aW9uIGlzT3ZlckF4aXMoIHgsIHJlZmVyZW5jZSwgc2l6ZSApIHtcblx0XHRyZXR1cm4gKCB4ID49IHJlZmVyZW5jZSApICYmICggeCA8ICggcmVmZXJlbmNlICsgc2l6ZSApICk7XG5cdH1cblxuXHRyZXR1cm4gZnVuY3Rpb24oIGRyYWdnYWJsZSwgZHJvcHBhYmxlLCB0b2xlcmFuY2VNb2RlLCBldmVudCApIHtcblxuXHRcdGlmICggIWRyb3BwYWJsZS5vZmZzZXQgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0dmFyIHgxID0gKCBkcmFnZ2FibGUucG9zaXRpb25BYnMgfHxcblx0XHRcdFx0ZHJhZ2dhYmxlLnBvc2l0aW9uLmFic29sdXRlICkubGVmdCArIGRyYWdnYWJsZS5tYXJnaW5zLmxlZnQsXG5cdFx0XHR5MSA9ICggZHJhZ2dhYmxlLnBvc2l0aW9uQWJzIHx8XG5cdFx0XHRcdGRyYWdnYWJsZS5wb3NpdGlvbi5hYnNvbHV0ZSApLnRvcCArIGRyYWdnYWJsZS5tYXJnaW5zLnRvcCxcblx0XHRcdHgyID0geDEgKyBkcmFnZ2FibGUuaGVscGVyUHJvcG9ydGlvbnMud2lkdGgsXG5cdFx0XHR5MiA9IHkxICsgZHJhZ2dhYmxlLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCxcblx0XHRcdGwgPSBkcm9wcGFibGUub2Zmc2V0LmxlZnQsXG5cdFx0XHR0ID0gZHJvcHBhYmxlLm9mZnNldC50b3AsXG5cdFx0XHRyID0gbCArIGRyb3BwYWJsZS5wcm9wb3J0aW9ucygpLndpZHRoLFxuXHRcdFx0YiA9IHQgKyBkcm9wcGFibGUucHJvcG9ydGlvbnMoKS5oZWlnaHQ7XG5cblx0XHRzd2l0Y2ggKCB0b2xlcmFuY2VNb2RlICkge1xuXHRcdGNhc2UgXCJmaXRcIjpcblx0XHRcdHJldHVybiAoIGwgPD0geDEgJiYgeDIgPD0gciAmJiB0IDw9IHkxICYmIHkyIDw9IGIgKTtcblx0XHRjYXNlIFwiaW50ZXJzZWN0XCI6XG5cdFx0XHRyZXR1cm4gKCBsIDwgeDEgKyAoIGRyYWdnYWJsZS5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAvIDIgKSAmJiAvLyBSaWdodCBIYWxmXG5cdFx0XHRcdHgyIC0gKCBkcmFnZ2FibGUuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLyAyICkgPCByICYmIC8vIExlZnQgSGFsZlxuXHRcdFx0XHR0IDwgeTEgKyAoIGRyYWdnYWJsZS5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLyAyICkgJiYgLy8gQm90dG9tIEhhbGZcblx0XHRcdFx0eTIgLSAoIGRyYWdnYWJsZS5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLyAyICkgPCBiICk7IC8vIFRvcCBIYWxmXG5cdFx0Y2FzZSBcInBvaW50ZXJcIjpcblx0XHRcdHJldHVybiBpc092ZXJBeGlzKCBldmVudC5wYWdlWSwgdCwgZHJvcHBhYmxlLnByb3BvcnRpb25zKCkuaGVpZ2h0ICkgJiZcblx0XHRcdFx0aXNPdmVyQXhpcyggZXZlbnQucGFnZVgsIGwsIGRyb3BwYWJsZS5wcm9wb3J0aW9ucygpLndpZHRoICk7XG5cdFx0Y2FzZSBcInRvdWNoXCI6XG5cdFx0XHRyZXR1cm4gKFxuXHRcdFx0XHQoIHkxID49IHQgJiYgeTEgPD0gYiApIHx8IC8vIFRvcCBlZGdlIHRvdWNoaW5nXG5cdFx0XHRcdCggeTIgPj0gdCAmJiB5MiA8PSBiICkgfHwgLy8gQm90dG9tIGVkZ2UgdG91Y2hpbmdcblx0XHRcdFx0KCB5MSA8IHQgJiYgeTIgPiBiICkgLy8gU3Vycm91bmRlZCB2ZXJ0aWNhbGx5XG5cdFx0XHQpICYmIChcblx0XHRcdFx0KCB4MSA+PSBsICYmIHgxIDw9IHIgKSB8fCAvLyBMZWZ0IGVkZ2UgdG91Y2hpbmdcblx0XHRcdFx0KCB4MiA+PSBsICYmIHgyIDw9IHIgKSB8fCAvLyBSaWdodCBlZGdlIHRvdWNoaW5nXG5cdFx0XHRcdCggeDEgPCBsICYmIHgyID4gciApIC8vIFN1cnJvdW5kZWQgaG9yaXpvbnRhbGx5XG5cdFx0XHQpO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHR9O1xufSApKCk7XG5cbi8qXG5cdFRoaXMgbWFuYWdlciB0cmFja3Mgb2Zmc2V0cyBvZiBkcmFnZ2FibGVzIGFuZCBkcm9wcGFibGVzXG4qL1xuJC51aS5kZG1hbmFnZXIgPSB7XG5cdGN1cnJlbnQ6IG51bGwsXG5cdGRyb3BwYWJsZXM6IHsgXCJkZWZhdWx0XCI6IFtdIH0sXG5cdHByZXBhcmVPZmZzZXRzOiBmdW5jdGlvbiggdCwgZXZlbnQgKSB7XG5cblx0XHR2YXIgaSwgaixcblx0XHRcdG0gPSAkLnVpLmRkbWFuYWdlci5kcm9wcGFibGVzWyB0Lm9wdGlvbnMuc2NvcGUgXSB8fCBbXSxcblx0XHRcdHR5cGUgPSBldmVudCA/IGV2ZW50LnR5cGUgOiBudWxsLCAvLyB3b3JrYXJvdW5kIGZvciAjMjMxN1xuXHRcdFx0bGlzdCA9ICggdC5jdXJyZW50SXRlbSB8fCB0LmVsZW1lbnQgKS5maW5kKCBcIjpkYXRhKHVpLWRyb3BwYWJsZSlcIiApLmFkZEJhY2soKTtcblxuXHRcdGRyb3BwYWJsZXNMb29wOiBmb3IgKCBpID0gMDsgaSA8IG0ubGVuZ3RoOyBpKysgKSB7XG5cblx0XHRcdC8vIE5vIGRpc2FibGVkIGFuZCBub24tYWNjZXB0ZWRcblx0XHRcdGlmICggbVsgaSBdLm9wdGlvbnMuZGlzYWJsZWQgfHwgKCB0ICYmICFtWyBpIF0uYWNjZXB0LmNhbGwoIG1bIGkgXS5lbGVtZW50WyAwIF0sXG5cdFx0XHRcdFx0KCB0LmN1cnJlbnRJdGVtIHx8IHQuZWxlbWVudCApICkgKSApIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEZpbHRlciBvdXQgZWxlbWVudHMgaW4gdGhlIGN1cnJlbnQgZHJhZ2dlZCBpdGVtXG5cdFx0XHRmb3IgKCBqID0gMDsgaiA8IGxpc3QubGVuZ3RoOyBqKysgKSB7XG5cdFx0XHRcdGlmICggbGlzdFsgaiBdID09PSBtWyBpIF0uZWxlbWVudFsgMCBdICkge1xuXHRcdFx0XHRcdG1bIGkgXS5wcm9wb3J0aW9ucygpLmhlaWdodCA9IDA7XG5cdFx0XHRcdFx0Y29udGludWUgZHJvcHBhYmxlc0xvb3A7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0bVsgaSBdLnZpc2libGUgPSBtWyBpIF0uZWxlbWVudC5jc3MoIFwiZGlzcGxheVwiICkgIT09IFwibm9uZVwiO1xuXHRcdFx0aWYgKCAhbVsgaSBdLnZpc2libGUgKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBBY3RpdmF0ZSB0aGUgZHJvcHBhYmxlIGlmIHVzZWQgZGlyZWN0bHkgZnJvbSBkcmFnZ2FibGVzXG5cdFx0XHRpZiAoIHR5cGUgPT09IFwibW91c2Vkb3duXCIgKSB7XG5cdFx0XHRcdG1bIGkgXS5fYWN0aXZhdGUuY2FsbCggbVsgaSBdLCBldmVudCApO1xuXHRcdFx0fVxuXG5cdFx0XHRtWyBpIF0ub2Zmc2V0ID0gbVsgaSBdLmVsZW1lbnQub2Zmc2V0KCk7XG5cdFx0XHRtWyBpIF0ucHJvcG9ydGlvbnMoIHtcblx0XHRcdFx0d2lkdGg6IG1bIGkgXS5lbGVtZW50WyAwIF0ub2Zmc2V0V2lkdGgsXG5cdFx0XHRcdGhlaWdodDogbVsgaSBdLmVsZW1lbnRbIDAgXS5vZmZzZXRIZWlnaHRcblx0XHRcdH0gKTtcblxuXHRcdH1cblxuXHR9LFxuXHRkcm9wOiBmdW5jdGlvbiggZHJhZ2dhYmxlLCBldmVudCApIHtcblxuXHRcdHZhciBkcm9wcGVkID0gZmFsc2U7XG5cblx0XHQvLyBDcmVhdGUgYSBjb3B5IG9mIHRoZSBkcm9wcGFibGVzIGluIGNhc2UgdGhlIGxpc3QgY2hhbmdlcyBkdXJpbmcgdGhlIGRyb3AgKCM5MTE2KVxuXHRcdCQuZWFjaCggKCAkLnVpLmRkbWFuYWdlci5kcm9wcGFibGVzWyBkcmFnZ2FibGUub3B0aW9ucy5zY29wZSBdIHx8IFtdICkuc2xpY2UoKSwgZnVuY3Rpb24oKSB7XG5cblx0XHRcdGlmICggIXRoaXMub3B0aW9ucyApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAhdGhpcy5vcHRpb25zLmRpc2FibGVkICYmIHRoaXMudmlzaWJsZSAmJlxuXHRcdFx0XHRcdGludGVyc2VjdCggZHJhZ2dhYmxlLCB0aGlzLCB0aGlzLm9wdGlvbnMudG9sZXJhbmNlLCBldmVudCApICkge1xuXHRcdFx0XHRkcm9wcGVkID0gdGhpcy5fZHJvcC5jYWxsKCB0aGlzLCBldmVudCApIHx8IGRyb3BwZWQ7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggIXRoaXMub3B0aW9ucy5kaXNhYmxlZCAmJiB0aGlzLnZpc2libGUgJiYgdGhpcy5hY2NlcHQuY2FsbCggdGhpcy5lbGVtZW50WyAwIF0sXG5cdFx0XHRcdFx0KCBkcmFnZ2FibGUuY3VycmVudEl0ZW0gfHwgZHJhZ2dhYmxlLmVsZW1lbnQgKSApICkge1xuXHRcdFx0XHR0aGlzLmlzb3V0ID0gdHJ1ZTtcblx0XHRcdFx0dGhpcy5pc292ZXIgPSBmYWxzZTtcblx0XHRcdFx0dGhpcy5fZGVhY3RpdmF0ZS5jYWxsKCB0aGlzLCBldmVudCApO1xuXHRcdFx0fVxuXG5cdFx0fSApO1xuXHRcdHJldHVybiBkcm9wcGVkO1xuXG5cdH0sXG5cdGRyYWdTdGFydDogZnVuY3Rpb24oIGRyYWdnYWJsZSwgZXZlbnQgKSB7XG5cblx0XHQvLyBMaXN0ZW4gZm9yIHNjcm9sbGluZyBzbyB0aGF0IGlmIHRoZSBkcmFnZ2luZyBjYXVzZXMgc2Nyb2xsaW5nIHRoZSBwb3NpdGlvbiBvZiB0aGVcblx0XHQvLyBkcm9wcGFibGVzIGNhbiBiZSByZWNhbGN1bGF0ZWQgKHNlZSAjNTAwMylcblx0XHRkcmFnZ2FibGUuZWxlbWVudC5wYXJlbnRzVW50aWwoIFwiYm9keVwiICkub24oIFwic2Nyb2xsLmRyb3BwYWJsZVwiLCBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggIWRyYWdnYWJsZS5vcHRpb25zLnJlZnJlc2hQb3NpdGlvbnMgKSB7XG5cdFx0XHRcdCQudWkuZGRtYW5hZ2VyLnByZXBhcmVPZmZzZXRzKCBkcmFnZ2FibGUsIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXHRkcmFnOiBmdW5jdGlvbiggZHJhZ2dhYmxlLCBldmVudCApIHtcblxuXHRcdC8vIElmIHlvdSBoYXZlIGEgaGlnaGx5IGR5bmFtaWMgcGFnZSwgeW91IG1pZ2h0IHRyeSB0aGlzIG9wdGlvbi4gSXQgcmVuZGVycyBwb3NpdGlvbnNcblx0XHQvLyBldmVyeSB0aW1lIHlvdSBtb3ZlIHRoZSBtb3VzZS5cblx0XHRpZiAoIGRyYWdnYWJsZS5vcHRpb25zLnJlZnJlc2hQb3NpdGlvbnMgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5wcmVwYXJlT2Zmc2V0cyggZHJhZ2dhYmxlLCBldmVudCApO1xuXHRcdH1cblxuXHRcdC8vIFJ1biB0aHJvdWdoIGFsbCBkcm9wcGFibGVzIGFuZCBjaGVjayB0aGVpciBwb3NpdGlvbnMgYmFzZWQgb24gc3BlY2lmaWMgdG9sZXJhbmNlIG9wdGlvbnNcblx0XHQkLmVhY2goICQudWkuZGRtYW5hZ2VyLmRyb3BwYWJsZXNbIGRyYWdnYWJsZS5vcHRpb25zLnNjb3BlIF0gfHwgW10sIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCB8fCB0aGlzLmdyZWVkeUNoaWxkIHx8ICF0aGlzLnZpc2libGUgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0dmFyIHBhcmVudEluc3RhbmNlLCBzY29wZSwgcGFyZW50LFxuXHRcdFx0XHRpbnRlcnNlY3RzID0gaW50ZXJzZWN0KCBkcmFnZ2FibGUsIHRoaXMsIHRoaXMub3B0aW9ucy50b2xlcmFuY2UsIGV2ZW50ICksXG5cdFx0XHRcdGMgPSAhaW50ZXJzZWN0cyAmJiB0aGlzLmlzb3ZlciA/XG5cdFx0XHRcdFx0XCJpc291dFwiIDpcblx0XHRcdFx0XHQoIGludGVyc2VjdHMgJiYgIXRoaXMuaXNvdmVyID8gXCJpc292ZXJcIiA6IG51bGwgKTtcblx0XHRcdGlmICggIWMgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuZ3JlZWR5ICkge1xuXG5cdFx0XHRcdC8vIGZpbmQgZHJvcHBhYmxlIHBhcmVudHMgd2l0aCBzYW1lIHNjb3BlXG5cdFx0XHRcdHNjb3BlID0gdGhpcy5vcHRpb25zLnNjb3BlO1xuXHRcdFx0XHRwYXJlbnQgPSB0aGlzLmVsZW1lbnQucGFyZW50cyggXCI6ZGF0YSh1aS1kcm9wcGFibGUpXCIgKS5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHJldHVybiAkKCB0aGlzICkuZHJvcHBhYmxlKCBcImluc3RhbmNlXCIgKS5vcHRpb25zLnNjb3BlID09PSBzY29wZTtcblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdGlmICggcGFyZW50Lmxlbmd0aCApIHtcblx0XHRcdFx0XHRwYXJlbnRJbnN0YW5jZSA9ICQoIHBhcmVudFsgMCBdICkuZHJvcHBhYmxlKCBcImluc3RhbmNlXCIgKTtcblx0XHRcdFx0XHRwYXJlbnRJbnN0YW5jZS5ncmVlZHlDaGlsZCA9ICggYyA9PT0gXCJpc292ZXJcIiApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIFdlIGp1c3QgbW92ZWQgaW50byBhIGdyZWVkeSBjaGlsZFxuXHRcdFx0aWYgKCBwYXJlbnRJbnN0YW5jZSAmJiBjID09PSBcImlzb3ZlclwiICkge1xuXHRcdFx0XHRwYXJlbnRJbnN0YW5jZS5pc292ZXIgPSBmYWxzZTtcblx0XHRcdFx0cGFyZW50SW5zdGFuY2UuaXNvdXQgPSB0cnVlO1xuXHRcdFx0XHRwYXJlbnRJbnN0YW5jZS5fb3V0LmNhbGwoIHBhcmVudEluc3RhbmNlLCBldmVudCApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzWyBjIF0gPSB0cnVlO1xuXHRcdFx0dGhpc1sgYyA9PT0gXCJpc291dFwiID8gXCJpc292ZXJcIiA6IFwiaXNvdXRcIiBdID0gZmFsc2U7XG5cdFx0XHR0aGlzWyBjID09PSBcImlzb3ZlclwiID8gXCJfb3ZlclwiIDogXCJfb3V0XCIgXS5jYWxsKCB0aGlzLCBldmVudCApO1xuXG5cdFx0XHQvLyBXZSBqdXN0IG1vdmVkIG91dCBvZiBhIGdyZWVkeSBjaGlsZFxuXHRcdFx0aWYgKCBwYXJlbnRJbnN0YW5jZSAmJiBjID09PSBcImlzb3V0XCIgKSB7XG5cdFx0XHRcdHBhcmVudEluc3RhbmNlLmlzb3V0ID0gZmFsc2U7XG5cdFx0XHRcdHBhcmVudEluc3RhbmNlLmlzb3ZlciA9IHRydWU7XG5cdFx0XHRcdHBhcmVudEluc3RhbmNlLl9vdmVyLmNhbGwoIHBhcmVudEluc3RhbmNlLCBldmVudCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHR9LFxuXHRkcmFnU3RvcDogZnVuY3Rpb24oIGRyYWdnYWJsZSwgZXZlbnQgKSB7XG5cdFx0ZHJhZ2dhYmxlLmVsZW1lbnQucGFyZW50c1VudGlsKCBcImJvZHlcIiApLm9mZiggXCJzY3JvbGwuZHJvcHBhYmxlXCIgKTtcblxuXHRcdC8vIENhbGwgcHJlcGFyZU9mZnNldHMgb25lIGZpbmFsIHRpbWUgc2luY2UgSUUgZG9lcyBub3QgZmlyZSByZXR1cm4gc2Nyb2xsIGV2ZW50cyB3aGVuXG5cdFx0Ly8gb3ZlcmZsb3cgd2FzIGNhdXNlZCBieSBkcmFnIChzZWUgIzUwMDMpXG5cdFx0aWYgKCAhZHJhZ2dhYmxlLm9wdGlvbnMucmVmcmVzaFBvc2l0aW9ucyApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLnByZXBhcmVPZmZzZXRzKCBkcmFnZ2FibGUsIGV2ZW50ICk7XG5cdFx0fVxuXHR9XG59O1xuXG4vLyBERVBSRUNBVEVEXG4vLyBUT0RPOiBzd2l0Y2ggcmV0dXJuIGJhY2sgdG8gd2lkZ2V0IGRlY2xhcmF0aW9uIGF0IHRvcCBvZiBmaWxlIHdoZW4gdGhpcyBpcyByZW1vdmVkXG5pZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSApIHtcblxuXHQvLyBCYWNrY29tcGF0IGZvciBhY3RpdmVDbGFzcyBhbmQgaG92ZXJDbGFzcyBvcHRpb25zXG5cdCQud2lkZ2V0KCBcInVpLmRyb3BwYWJsZVwiLCAkLnVpLmRyb3BwYWJsZSwge1xuXHRcdG9wdGlvbnM6IHtcblx0XHRcdGhvdmVyQ2xhc3M6IGZhbHNlLFxuXHRcdFx0YWN0aXZlQ2xhc3M6IGZhbHNlXG5cdFx0fSxcblx0XHRfYWRkQWN0aXZlQ2xhc3M6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5fc3VwZXIoKTtcblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmFjdGl2ZUNsYXNzICkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQuYWRkQ2xhc3MoIHRoaXMub3B0aW9ucy5hY3RpdmVDbGFzcyApO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0X3JlbW92ZUFjdGl2ZUNsYXNzOiBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuX3N1cGVyKCk7XG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5hY3RpdmVDbGFzcyApIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LnJlbW92ZUNsYXNzKCB0aGlzLm9wdGlvbnMuYWN0aXZlQ2xhc3MgKTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdF9hZGRIb3ZlckNsYXNzOiBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuX3N1cGVyKCk7XG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5ob3ZlckNsYXNzICkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQuYWRkQ2xhc3MoIHRoaXMub3B0aW9ucy5ob3ZlckNsYXNzICk7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHRfcmVtb3ZlSG92ZXJDbGFzczogZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLl9zdXBlcigpO1xuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuaG92ZXJDbGFzcyApIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LnJlbW92ZUNsYXNzKCB0aGlzLm9wdGlvbnMuaG92ZXJDbGFzcyApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSApO1xufVxuXG52YXIgd2lkZ2V0c0Ryb3BwYWJsZSA9ICQudWkuZHJvcHBhYmxlO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFByb2dyZXNzYmFyIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBQcm9ncmVzc2JhclxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLyBqc2NzOmRpc2FibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kZXNjcmlwdGlvbjogRGlzcGxheXMgYSBzdGF0dXMgaW5kaWNhdG9yIGZvciBsb2FkaW5nIHN0YXRlLCBzdGFuZGFyZCBwZXJjZW50YWdlLCBhbmQgb3RoZXIgcHJvZ3Jlc3MgaW5kaWNhdG9ycy5cbi8vIGpzY3M6ZW5hYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vcHJvZ3Jlc3NiYXIvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vcHJvZ3Jlc3NiYXIvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9wcm9ncmVzc2Jhci5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxudmFyIHdpZGdldHNQcm9ncmVzc2JhciA9ICQud2lkZ2V0KCBcInVpLnByb2dyZXNzYmFyXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0b3B0aW9uczoge1xuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktcHJvZ3Jlc3NiYXJcIjogXCJ1aS1jb3JuZXItYWxsXCIsXG5cdFx0XHRcInVpLXByb2dyZXNzYmFyLXZhbHVlXCI6IFwidWktY29ybmVyLWxlZnRcIixcblx0XHRcdFwidWktcHJvZ3Jlc3NiYXItY29tcGxldGVcIjogXCJ1aS1jb3JuZXItcmlnaHRcIlxuXHRcdH0sXG5cdFx0bWF4OiAxMDAsXG5cdFx0dmFsdWU6IDAsXG5cblx0XHRjaGFuZ2U6IG51bGwsXG5cdFx0Y29tcGxldGU6IG51bGxcblx0fSxcblxuXHRtaW46IDAsXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cblx0XHQvLyBDb25zdHJhaW4gaW5pdGlhbCB2YWx1ZVxuXHRcdHRoaXMub2xkVmFsdWUgPSB0aGlzLm9wdGlvbnMudmFsdWUgPSB0aGlzLl9jb25zdHJhaW5lZFZhbHVlKCk7XG5cblx0XHR0aGlzLmVsZW1lbnQuYXR0cigge1xuXG5cdFx0XHQvLyBPbmx5IHNldCBzdGF0aWMgdmFsdWVzOyBhcmlhLXZhbHVlbm93IGFuZCBhcmlhLXZhbHVlbWF4IGFyZVxuXHRcdFx0Ly8gc2V0IGluc2lkZSBfcmVmcmVzaFZhbHVlKClcblx0XHRcdHJvbGU6IFwicHJvZ3Jlc3NiYXJcIixcblx0XHRcdFwiYXJpYS12YWx1ZW1pblwiOiB0aGlzLm1pblxuXHRcdH0gKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1wcm9ncmVzc2JhclwiLCBcInVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudFwiICk7XG5cblx0XHR0aGlzLnZhbHVlRGl2ID0gJCggXCI8ZGl2PlwiICkuYXBwZW5kVG8oIHRoaXMuZWxlbWVudCApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnZhbHVlRGl2LCBcInVpLXByb2dyZXNzYmFyLXZhbHVlXCIsIFwidWktd2lkZ2V0LWhlYWRlclwiICk7XG5cdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuZWxlbWVudC5yZW1vdmVBdHRyKCBcInJvbGUgYXJpYS12YWx1ZW1pbiBhcmlhLXZhbHVlbWF4IGFyaWEtdmFsdWVub3dcIiApO1xuXG5cdFx0dGhpcy52YWx1ZURpdi5yZW1vdmUoKTtcblx0fSxcblxuXHR2YWx1ZTogZnVuY3Rpb24oIG5ld1ZhbHVlICkge1xuXHRcdGlmICggbmV3VmFsdWUgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHJldHVybiB0aGlzLm9wdGlvbnMudmFsdWU7XG5cdFx0fVxuXG5cdFx0dGhpcy5vcHRpb25zLnZhbHVlID0gdGhpcy5fY29uc3RyYWluZWRWYWx1ZSggbmV3VmFsdWUgKTtcblx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0fSxcblxuXHRfY29uc3RyYWluZWRWYWx1ZTogZnVuY3Rpb24oIG5ld1ZhbHVlICkge1xuXHRcdGlmICggbmV3VmFsdWUgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdG5ld1ZhbHVlID0gdGhpcy5vcHRpb25zLnZhbHVlO1xuXHRcdH1cblxuXHRcdHRoaXMuaW5kZXRlcm1pbmF0ZSA9IG5ld1ZhbHVlID09PSBmYWxzZTtcblxuXHRcdC8vIFNhbml0aXplIHZhbHVlXG5cdFx0aWYgKCB0eXBlb2YgbmV3VmFsdWUgIT09IFwibnVtYmVyXCIgKSB7XG5cdFx0XHRuZXdWYWx1ZSA9IDA7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuaW5kZXRlcm1pbmF0ZSA/IGZhbHNlIDpcblx0XHRcdE1hdGgubWluKCB0aGlzLm9wdGlvbnMubWF4LCBNYXRoLm1heCggdGhpcy5taW4sIG5ld1ZhbHVlICkgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uczogZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cblx0XHQvLyBFbnN1cmUgXCJ2YWx1ZVwiIG9wdGlvbiBpcyBzZXQgYWZ0ZXIgb3RoZXIgdmFsdWVzIChsaWtlIG1heClcblx0XHR2YXIgdmFsdWUgPSBvcHRpb25zLnZhbHVlO1xuXHRcdGRlbGV0ZSBvcHRpb25zLnZhbHVlO1xuXG5cdFx0dGhpcy5fc3VwZXIoIG9wdGlvbnMgKTtcblxuXHRcdHRoaXMub3B0aW9ucy52YWx1ZSA9IHRoaXMuX2NvbnN0cmFpbmVkVmFsdWUoIHZhbHVlICk7XG5cdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0aWYgKCBrZXkgPT09IFwibWF4XCIgKSB7XG5cblx0XHRcdC8vIERvbid0IGFsbG93IGEgbWF4IGxlc3MgdGhhbiBtaW5cblx0XHRcdHZhbHVlID0gTWF0aC5tYXgoIHRoaXMubWluLCB2YWx1ZSApO1xuXHRcdH1cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb25EaXNhYmxlZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCB2YWx1ZSApO1xuXG5cdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwiYXJpYS1kaXNhYmxlZFwiLCB2YWx1ZSApO1xuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIsICEhdmFsdWUgKTtcblx0fSxcblxuXHRfcGVyY2VudGFnZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuaW5kZXRlcm1pbmF0ZSA/XG5cdFx0XHQxMDAgOlxuXHRcdFx0MTAwICogKCB0aGlzLm9wdGlvbnMudmFsdWUgLSB0aGlzLm1pbiApIC8gKCB0aGlzLm9wdGlvbnMubWF4IC0gdGhpcy5taW4gKTtcblx0fSxcblxuXHRfcmVmcmVzaFZhbHVlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdmFsdWUgPSB0aGlzLm9wdGlvbnMudmFsdWUsXG5cdFx0XHRwZXJjZW50YWdlID0gdGhpcy5fcGVyY2VudGFnZSgpO1xuXG5cdFx0dGhpcy52YWx1ZURpdlxuXHRcdFx0LnRvZ2dsZSggdGhpcy5pbmRldGVybWluYXRlIHx8IHZhbHVlID4gdGhpcy5taW4gKVxuXHRcdFx0LndpZHRoKCBwZXJjZW50YWdlLnRvRml4ZWQoIDAgKSArIFwiJVwiICk7XG5cblx0XHR0aGlzXG5cdFx0XHQuX3RvZ2dsZUNsYXNzKCB0aGlzLnZhbHVlRGl2LCBcInVpLXByb2dyZXNzYmFyLWNvbXBsZXRlXCIsIG51bGwsXG5cdFx0XHRcdHZhbHVlID09PSB0aGlzLm9wdGlvbnMubWF4IClcblx0XHRcdC5fdG9nZ2xlQ2xhc3MoIFwidWktcHJvZ3Jlc3NiYXItaW5kZXRlcm1pbmF0ZVwiLCBudWxsLCB0aGlzLmluZGV0ZXJtaW5hdGUgKTtcblxuXHRcdGlmICggdGhpcy5pbmRldGVybWluYXRlICkge1xuXHRcdFx0dGhpcy5lbGVtZW50LnJlbW92ZUF0dHIoIFwiYXJpYS12YWx1ZW5vd1wiICk7XG5cdFx0XHRpZiAoICF0aGlzLm92ZXJsYXlEaXYgKSB7XG5cdFx0XHRcdHRoaXMub3ZlcmxheURpdiA9ICQoIFwiPGRpdj5cIiApLmFwcGVuZFRvKCB0aGlzLnZhbHVlRGl2ICk7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLm92ZXJsYXlEaXYsIFwidWktcHJvZ3Jlc3NiYXItb3ZlcmxheVwiICk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuZWxlbWVudC5hdHRyKCB7XG5cdFx0XHRcdFwiYXJpYS12YWx1ZW1heFwiOiB0aGlzLm9wdGlvbnMubWF4LFxuXHRcdFx0XHRcImFyaWEtdmFsdWVub3dcIjogdmFsdWVcblx0XHRcdH0gKTtcblx0XHRcdGlmICggdGhpcy5vdmVybGF5RGl2ICkge1xuXHRcdFx0XHR0aGlzLm92ZXJsYXlEaXYucmVtb3ZlKCk7XG5cdFx0XHRcdHRoaXMub3ZlcmxheURpdiA9IG51bGw7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm9sZFZhbHVlICE9PSB2YWx1ZSApIHtcblx0XHRcdHRoaXMub2xkVmFsdWUgPSB2YWx1ZTtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY2hhbmdlXCIgKTtcblx0XHR9XG5cdFx0aWYgKCB2YWx1ZSA9PT0gdGhpcy5vcHRpb25zLm1heCApIHtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY29tcGxldGVcIiApO1xuXHRcdH1cblx0fVxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFNlbGVjdGFibGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFNlbGVjdGFibGVcbi8vPj5ncm91cDogSW50ZXJhY3Rpb25zXG4vLz4+ZGVzY3JpcHRpb246IEFsbG93cyBncm91cHMgb2YgZWxlbWVudHMgdG8gYmUgc2VsZWN0ZWQgd2l0aCB0aGUgbW91c2UuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc2VsZWN0YWJsZS9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9zZWxlY3RhYmxlL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL3NlbGVjdGFibGUuY3NzXG5cblxuXG52YXIgd2lkZ2V0c1NlbGVjdGFibGUgPSAkLndpZGdldCggXCJ1aS5zZWxlY3RhYmxlXCIsICQudWkubW91c2UsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0b3B0aW9uczoge1xuXHRcdGFwcGVuZFRvOiBcImJvZHlcIixcblx0XHRhdXRvUmVmcmVzaDogdHJ1ZSxcblx0XHRkaXN0YW5jZTogMCxcblx0XHRmaWx0ZXI6IFwiKlwiLFxuXHRcdHRvbGVyYW5jZTogXCJ0b3VjaFwiLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0c2VsZWN0ZWQ6IG51bGwsXG5cdFx0c2VsZWN0aW5nOiBudWxsLFxuXHRcdHN0YXJ0OiBudWxsLFxuXHRcdHN0b3A6IG51bGwsXG5cdFx0dW5zZWxlY3RlZDogbnVsbCxcblx0XHR1bnNlbGVjdGluZzogbnVsbFxuXHR9LFxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1zZWxlY3RhYmxlXCIgKTtcblxuXHRcdHRoaXMuZHJhZ2dlZCA9IGZhbHNlO1xuXG5cdFx0Ly8gQ2FjaGUgc2VsZWN0ZWUgY2hpbGRyZW4gYmFzZWQgb24gZmlsdGVyXG5cdFx0dGhpcy5yZWZyZXNoID0gZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGF0LmVsZW1lbnRQb3MgPSAkKCB0aGF0LmVsZW1lbnRbIDAgXSApLm9mZnNldCgpO1xuXHRcdFx0dGhhdC5zZWxlY3RlZXMgPSAkKCB0aGF0Lm9wdGlvbnMuZmlsdGVyLCB0aGF0LmVsZW1lbnRbIDAgXSApO1xuXHRcdFx0dGhhdC5fYWRkQ2xhc3MoIHRoYXQuc2VsZWN0ZWVzLCBcInVpLXNlbGVjdGVlXCIgKTtcblx0XHRcdHRoYXQuc2VsZWN0ZWVzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgJHRoaXMgPSAkKCB0aGlzICksXG5cdFx0XHRcdFx0c2VsZWN0ZWVPZmZzZXQgPSAkdGhpcy5vZmZzZXQoKSxcblx0XHRcdFx0XHRwb3MgPSB7XG5cdFx0XHRcdFx0XHRsZWZ0OiBzZWxlY3RlZU9mZnNldC5sZWZ0IC0gdGhhdC5lbGVtZW50UG9zLmxlZnQsXG5cdFx0XHRcdFx0XHR0b3A6IHNlbGVjdGVlT2Zmc2V0LnRvcCAtIHRoYXQuZWxlbWVudFBvcy50b3Bcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHQkLmRhdGEoIHRoaXMsIFwic2VsZWN0YWJsZS1pdGVtXCIsIHtcblx0XHRcdFx0XHRlbGVtZW50OiB0aGlzLFxuXHRcdFx0XHRcdCRlbGVtZW50OiAkdGhpcyxcblx0XHRcdFx0XHRsZWZ0OiBwb3MubGVmdCxcblx0XHRcdFx0XHR0b3A6IHBvcy50b3AsXG5cdFx0XHRcdFx0cmlnaHQ6IHBvcy5sZWZ0ICsgJHRoaXMub3V0ZXJXaWR0aCgpLFxuXHRcdFx0XHRcdGJvdHRvbTogcG9zLnRvcCArICR0aGlzLm91dGVySGVpZ2h0KCksXG5cdFx0XHRcdFx0c3RhcnRzZWxlY3RlZDogZmFsc2UsXG5cdFx0XHRcdFx0c2VsZWN0ZWQ6ICR0aGlzLmhhc0NsYXNzKCBcInVpLXNlbGVjdGVkXCIgKSxcblx0XHRcdFx0XHRzZWxlY3Rpbmc6ICR0aGlzLmhhc0NsYXNzKCBcInVpLXNlbGVjdGluZ1wiICksXG5cdFx0XHRcdFx0dW5zZWxlY3Rpbmc6ICR0aGlzLmhhc0NsYXNzKCBcInVpLXVuc2VsZWN0aW5nXCIgKVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9ICk7XG5cdFx0fTtcblx0XHR0aGlzLnJlZnJlc2goKTtcblxuXHRcdHRoaXMuX21vdXNlSW5pdCgpO1xuXG5cdFx0dGhpcy5oZWxwZXIgPSAkKCBcIjxkaXY+XCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5oZWxwZXIsIFwidWktc2VsZWN0YWJsZS1oZWxwZXJcIiApO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLnNlbGVjdGVlcy5yZW1vdmVEYXRhKCBcInNlbGVjdGFibGUtaXRlbVwiICk7XG5cdFx0dGhpcy5fbW91c2VEZXN0cm95KCk7XG5cdH0sXG5cblx0X21vdXNlU3RhcnQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0dGhpcy5vcG9zID0gWyBldmVudC5wYWdlWCwgZXZlbnQucGFnZVkgXTtcblx0XHR0aGlzLmVsZW1lbnRQb3MgPSAkKCB0aGlzLmVsZW1lbnRbIDAgXSApLm9mZnNldCgpO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5zZWxlY3RlZXMgPSAkKCBvcHRpb25zLmZpbHRlciwgdGhpcy5lbGVtZW50WyAwIF0gKTtcblxuXHRcdHRoaXMuX3RyaWdnZXIoIFwic3RhcnRcIiwgZXZlbnQgKTtcblxuXHRcdCQoIG9wdGlvbnMuYXBwZW5kVG8gKS5hcHBlbmQoIHRoaXMuaGVscGVyICk7XG5cblx0XHQvLyBwb3NpdGlvbiBoZWxwZXIgKGxhc3NvKVxuXHRcdHRoaXMuaGVscGVyLmNzcygge1xuXHRcdFx0XCJsZWZ0XCI6IGV2ZW50LnBhZ2VYLFxuXHRcdFx0XCJ0b3BcIjogZXZlbnQucGFnZVksXG5cdFx0XHRcIndpZHRoXCI6IDAsXG5cdFx0XHRcImhlaWdodFwiOiAwXG5cdFx0fSApO1xuXG5cdFx0aWYgKCBvcHRpb25zLmF1dG9SZWZyZXNoICkge1xuXHRcdFx0dGhpcy5yZWZyZXNoKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5zZWxlY3RlZXMuZmlsdGVyKCBcIi51aS1zZWxlY3RlZFwiICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc2VsZWN0ZWUgPSAkLmRhdGEoIHRoaXMsIFwic2VsZWN0YWJsZS1pdGVtXCIgKTtcblx0XHRcdHNlbGVjdGVlLnN0YXJ0c2VsZWN0ZWQgPSB0cnVlO1xuXHRcdFx0aWYgKCAhZXZlbnQubWV0YUtleSAmJiAhZXZlbnQuY3RybEtleSApIHtcblx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXNlbGVjdGVkXCIgKTtcblx0XHRcdFx0c2VsZWN0ZWUuc2VsZWN0ZWQgPSBmYWxzZTtcblx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXVuc2VsZWN0aW5nXCIgKTtcblx0XHRcdFx0c2VsZWN0ZWUudW5zZWxlY3RpbmcgPSB0cnVlO1xuXG5cdFx0XHRcdC8vIHNlbGVjdGFibGUgVU5TRUxFQ1RJTkcgY2FsbGJhY2tcblx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJ1bnNlbGVjdGluZ1wiLCBldmVudCwge1xuXHRcdFx0XHRcdHVuc2VsZWN0aW5nOiBzZWxlY3RlZS5lbGVtZW50XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHQkKCBldmVudC50YXJnZXQgKS5wYXJlbnRzKCkuYWRkQmFjaygpLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGRvU2VsZWN0LFxuXHRcdFx0XHRzZWxlY3RlZSA9ICQuZGF0YSggdGhpcywgXCJzZWxlY3RhYmxlLWl0ZW1cIiApO1xuXHRcdFx0aWYgKCBzZWxlY3RlZSApIHtcblx0XHRcdFx0ZG9TZWxlY3QgPSAoICFldmVudC5tZXRhS2V5ICYmICFldmVudC5jdHJsS2V5ICkgfHxcblx0XHRcdFx0XHQhc2VsZWN0ZWUuJGVsZW1lbnQuaGFzQ2xhc3MoIFwidWktc2VsZWN0ZWRcIiApO1xuXHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIGRvU2VsZWN0ID8gXCJ1aS11bnNlbGVjdGluZ1wiIDogXCJ1aS1zZWxlY3RlZFwiIClcblx0XHRcdFx0XHQuX2FkZENsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgZG9TZWxlY3QgPyBcInVpLXNlbGVjdGluZ1wiIDogXCJ1aS11bnNlbGVjdGluZ1wiICk7XG5cdFx0XHRcdHNlbGVjdGVlLnVuc2VsZWN0aW5nID0gIWRvU2VsZWN0O1xuXHRcdFx0XHRzZWxlY3RlZS5zZWxlY3RpbmcgPSBkb1NlbGVjdDtcblx0XHRcdFx0c2VsZWN0ZWUuc2VsZWN0ZWQgPSBkb1NlbGVjdDtcblxuXHRcdFx0XHQvLyBzZWxlY3RhYmxlIChVTilTRUxFQ1RJTkcgY2FsbGJhY2tcblx0XHRcdFx0aWYgKCBkb1NlbGVjdCApIHtcblx0XHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInNlbGVjdGluZ1wiLCBldmVudCwge1xuXHRcdFx0XHRcdFx0c2VsZWN0aW5nOiBzZWxlY3RlZS5lbGVtZW50XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwidW5zZWxlY3RpbmdcIiwgZXZlbnQsIHtcblx0XHRcdFx0XHRcdHVuc2VsZWN0aW5nOiBzZWxlY3RlZS5lbGVtZW50XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0fSxcblxuXHRfbW91c2VEcmFnOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR0aGlzLmRyYWdnZWQgPSB0cnVlO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIHRtcCxcblx0XHRcdHRoYXQgPSB0aGlzLFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdHgxID0gdGhpcy5vcG9zWyAwIF0sXG5cdFx0XHR5MSA9IHRoaXMub3Bvc1sgMSBdLFxuXHRcdFx0eDIgPSBldmVudC5wYWdlWCxcblx0XHRcdHkyID0gZXZlbnQucGFnZVk7XG5cblx0XHRpZiAoIHgxID4geDIgKSB7IHRtcCA9IHgyOyB4MiA9IHgxOyB4MSA9IHRtcDsgfVxuXHRcdGlmICggeTEgPiB5MiApIHsgdG1wID0geTI7IHkyID0geTE7IHkxID0gdG1wOyB9XG5cdFx0dGhpcy5oZWxwZXIuY3NzKCB7IGxlZnQ6IHgxLCB0b3A6IHkxLCB3aWR0aDogeDIgLSB4MSwgaGVpZ2h0OiB5MiAtIHkxIH0gKTtcblxuXHRcdHRoaXMuc2VsZWN0ZWVzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHNlbGVjdGVlID0gJC5kYXRhKCB0aGlzLCBcInNlbGVjdGFibGUtaXRlbVwiICksXG5cdFx0XHRcdGhpdCA9IGZhbHNlLFxuXHRcdFx0XHRvZmZzZXQgPSB7fTtcblxuXHRcdFx0Ly9wcmV2ZW50IGhlbHBlciBmcm9tIGJlaW5nIHNlbGVjdGVkIGlmIGFwcGVuZFRvOiBzZWxlY3RhYmxlXG5cdFx0XHRpZiAoICFzZWxlY3RlZSB8fCBzZWxlY3RlZS5lbGVtZW50ID09PSB0aGF0LmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRvZmZzZXQubGVmdCAgID0gc2VsZWN0ZWUubGVmdCAgICsgdGhhdC5lbGVtZW50UG9zLmxlZnQ7XG5cdFx0XHRvZmZzZXQucmlnaHQgID0gc2VsZWN0ZWUucmlnaHQgICsgdGhhdC5lbGVtZW50UG9zLmxlZnQ7XG5cdFx0XHRvZmZzZXQudG9wICAgID0gc2VsZWN0ZWUudG9wICAgICsgdGhhdC5lbGVtZW50UG9zLnRvcDtcblx0XHRcdG9mZnNldC5ib3R0b20gPSBzZWxlY3RlZS5ib3R0b20gKyB0aGF0LmVsZW1lbnRQb3MudG9wO1xuXG5cdFx0XHRpZiAoIG9wdGlvbnMudG9sZXJhbmNlID09PSBcInRvdWNoXCIgKSB7XG5cdFx0XHRcdGhpdCA9ICggISggb2Zmc2V0LmxlZnQgPiB4MiB8fCBvZmZzZXQucmlnaHQgPCB4MSB8fCBvZmZzZXQudG9wID4geTIgfHxcbiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0LmJvdHRvbSA8IHkxICkgKTtcblx0XHRcdH0gZWxzZSBpZiAoIG9wdGlvbnMudG9sZXJhbmNlID09PSBcImZpdFwiICkge1xuXHRcdFx0XHRoaXQgPSAoIG9mZnNldC5sZWZ0ID4geDEgJiYgb2Zmc2V0LnJpZ2h0IDwgeDIgJiYgb2Zmc2V0LnRvcCA+IHkxICYmXG4gICAgICAgICAgICAgICAgICAgIG9mZnNldC5ib3R0b20gPCB5MiApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGhpdCApIHtcblxuXHRcdFx0XHQvLyBTRUxFQ1Rcblx0XHRcdFx0aWYgKCBzZWxlY3RlZS5zZWxlY3RlZCApIHtcblx0XHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktc2VsZWN0ZWRcIiApO1xuXHRcdFx0XHRcdHNlbGVjdGVlLnNlbGVjdGVkID0gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBzZWxlY3RlZS51bnNlbGVjdGluZyApIHtcblx0XHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktdW5zZWxlY3RpbmdcIiApO1xuXHRcdFx0XHRcdHNlbGVjdGVlLnVuc2VsZWN0aW5nID0gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCAhc2VsZWN0ZWUuc2VsZWN0aW5nICkge1xuXHRcdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS1zZWxlY3RpbmdcIiApO1xuXHRcdFx0XHRcdHNlbGVjdGVlLnNlbGVjdGluZyA9IHRydWU7XG5cblx0XHRcdFx0XHQvLyBzZWxlY3RhYmxlIFNFTEVDVElORyBjYWxsYmFja1xuXHRcdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwic2VsZWN0aW5nXCIsIGV2ZW50LCB7XG5cdFx0XHRcdFx0XHRzZWxlY3Rpbmc6IHNlbGVjdGVlLmVsZW1lbnRcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gVU5TRUxFQ1Rcblx0XHRcdFx0aWYgKCBzZWxlY3RlZS5zZWxlY3RpbmcgKSB7XG5cdFx0XHRcdFx0aWYgKCAoIGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuY3RybEtleSApICYmIHNlbGVjdGVlLnN0YXJ0c2VsZWN0ZWQgKSB7XG5cdFx0XHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktc2VsZWN0aW5nXCIgKTtcblx0XHRcdFx0XHRcdHNlbGVjdGVlLnNlbGVjdGluZyA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXNlbGVjdGVkXCIgKTtcblx0XHRcdFx0XHRcdHNlbGVjdGVlLnNlbGVjdGVkID0gdHJ1ZTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXNlbGVjdGluZ1wiICk7XG5cdFx0XHRcdFx0XHRzZWxlY3RlZS5zZWxlY3RpbmcgPSBmYWxzZTtcblx0XHRcdFx0XHRcdGlmICggc2VsZWN0ZWUuc3RhcnRzZWxlY3RlZCApIHtcblx0XHRcdFx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXVuc2VsZWN0aW5nXCIgKTtcblx0XHRcdFx0XHRcdFx0c2VsZWN0ZWUudW5zZWxlY3RpbmcgPSB0cnVlO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHQvLyBzZWxlY3RhYmxlIFVOU0VMRUNUSU5HIGNhbGxiYWNrXG5cdFx0XHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInVuc2VsZWN0aW5nXCIsIGV2ZW50LCB7XG5cdFx0XHRcdFx0XHRcdHVuc2VsZWN0aW5nOiBzZWxlY3RlZS5lbGVtZW50XG5cdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggc2VsZWN0ZWUuc2VsZWN0ZWQgKSB7XG5cdFx0XHRcdFx0aWYgKCAhZXZlbnQubWV0YUtleSAmJiAhZXZlbnQuY3RybEtleSAmJiAhc2VsZWN0ZWUuc3RhcnRzZWxlY3RlZCApIHtcblx0XHRcdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS1zZWxlY3RlZFwiICk7XG5cdFx0XHRcdFx0XHRzZWxlY3RlZS5zZWxlY3RlZCA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktdW5zZWxlY3RpbmdcIiApO1xuXHRcdFx0XHRcdFx0c2VsZWN0ZWUudW5zZWxlY3RpbmcgPSB0cnVlO1xuXG5cdFx0XHRcdFx0XHQvLyBzZWxlY3RhYmxlIFVOU0VMRUNUSU5HIGNhbGxiYWNrXG5cdFx0XHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInVuc2VsZWN0aW5nXCIsIGV2ZW50LCB7XG5cdFx0XHRcdFx0XHRcdHVuc2VsZWN0aW5nOiBzZWxlY3RlZS5lbGVtZW50XG5cdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXG5cdF9tb3VzZVN0b3A6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHR0aGlzLmRyYWdnZWQgPSBmYWxzZTtcblxuXHRcdCQoIFwiLnVpLXVuc2VsZWN0aW5nXCIsIHRoaXMuZWxlbWVudFsgMCBdICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc2VsZWN0ZWUgPSAkLmRhdGEoIHRoaXMsIFwic2VsZWN0YWJsZS1pdGVtXCIgKTtcblx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS11bnNlbGVjdGluZ1wiICk7XG5cdFx0XHRzZWxlY3RlZS51bnNlbGVjdGluZyA9IGZhbHNlO1xuXHRcdFx0c2VsZWN0ZWUuc3RhcnRzZWxlY3RlZCA9IGZhbHNlO1xuXHRcdFx0dGhhdC5fdHJpZ2dlciggXCJ1bnNlbGVjdGVkXCIsIGV2ZW50LCB7XG5cdFx0XHRcdHVuc2VsZWN0ZWQ6IHNlbGVjdGVlLmVsZW1lbnRcblx0XHRcdH0gKTtcblx0XHR9ICk7XG5cdFx0JCggXCIudWktc2VsZWN0aW5nXCIsIHRoaXMuZWxlbWVudFsgMCBdICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc2VsZWN0ZWUgPSAkLmRhdGEoIHRoaXMsIFwic2VsZWN0YWJsZS1pdGVtXCIgKTtcblx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS1zZWxlY3RpbmdcIiApXG5cdFx0XHRcdC5fYWRkQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXNlbGVjdGVkXCIgKTtcblx0XHRcdHNlbGVjdGVlLnNlbGVjdGluZyA9IGZhbHNlO1xuXHRcdFx0c2VsZWN0ZWUuc2VsZWN0ZWQgPSB0cnVlO1xuXHRcdFx0c2VsZWN0ZWUuc3RhcnRzZWxlY3RlZCA9IHRydWU7XG5cdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInNlbGVjdGVkXCIsIGV2ZW50LCB7XG5cdFx0XHRcdHNlbGVjdGVkOiBzZWxlY3RlZS5lbGVtZW50XG5cdFx0XHR9ICk7XG5cdFx0fSApO1xuXHRcdHRoaXMuX3RyaWdnZXIoIFwic3RvcFwiLCBldmVudCApO1xuXG5cdFx0dGhpcy5oZWxwZXIucmVtb3ZlKCk7XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFNlbGVjdG1lbnUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFNlbGVjdG1lbnVcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8ganNjczpkaXNhYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZGVzY3JpcHRpb246IER1cGxpY2F0ZXMgYW5kIGV4dGVuZHMgdGhlIGZ1bmN0aW9uYWxpdHkgb2YgYSBuYXRpdmUgSFRNTCBzZWxlY3QgZWxlbWVudCwgYWxsb3dpbmcgaXQgdG8gYmUgY3VzdG9taXphYmxlIGluIGJlaGF2aW9yIGFuZCBhcHBlYXJhbmNlIGZhciBiZXlvbmQgdGhlIGxpbWl0YXRpb25zIG9mIGEgbmF0aXZlIHNlbGVjdC5cbi8vIGpzY3M6ZW5hYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc2VsZWN0bWVudS9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9zZWxlY3RtZW51L1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2Uvc2VsZWN0bWVudS5jc3MsIC4uLy4uL3RoZW1lcy9iYXNlL2J1dHRvbi5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxudmFyIHdpZGdldHNTZWxlY3RtZW51ID0gJC53aWRnZXQoIFwidWkuc2VsZWN0bWVudVwiLCBbICQudWkuZm9ybVJlc2V0TWl4aW4sIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0ZGVmYXVsdEVsZW1lbnQ6IFwiPHNlbGVjdD5cIixcblx0b3B0aW9uczoge1xuXHRcdGFwcGVuZFRvOiBudWxsLFxuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tb3BlblwiOiBcInVpLWNvcm5lci10b3BcIixcblx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tY2xvc2VkXCI6IFwidWktY29ybmVyLWFsbFwiXG5cdFx0fSxcblx0XHRkaXNhYmxlZDogbnVsbCxcblx0XHRpY29uczoge1xuXHRcdFx0YnV0dG9uOiBcInVpLWljb24tdHJpYW5nbGUtMS1zXCJcblx0XHR9LFxuXHRcdHBvc2l0aW9uOiB7XG5cdFx0XHRteTogXCJsZWZ0IHRvcFwiLFxuXHRcdFx0YXQ6IFwibGVmdCBib3R0b21cIixcblx0XHRcdGNvbGxpc2lvbjogXCJub25lXCJcblx0XHR9LFxuXHRcdHdpZHRoOiBmYWxzZSxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGNoYW5nZTogbnVsbCxcblx0XHRjbG9zZTogbnVsbCxcblx0XHRmb2N1czogbnVsbCxcblx0XHRvcGVuOiBudWxsLFxuXHRcdHNlbGVjdDogbnVsbFxuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBzZWxlY3RtZW51SWQgPSB0aGlzLmVsZW1lbnQudW5pcXVlSWQoKS5hdHRyKCBcImlkXCIgKTtcblx0XHR0aGlzLmlkcyA9IHtcblx0XHRcdGVsZW1lbnQ6IHNlbGVjdG1lbnVJZCxcblx0XHRcdGJ1dHRvbjogc2VsZWN0bWVudUlkICsgXCItYnV0dG9uXCIsXG5cdFx0XHRtZW51OiBzZWxlY3RtZW51SWQgKyBcIi1tZW51XCJcblx0XHR9O1xuXG5cdFx0dGhpcy5fZHJhd0J1dHRvbigpO1xuXHRcdHRoaXMuX2RyYXdNZW51KCk7XG5cdFx0dGhpcy5fYmluZEZvcm1SZXNldEhhbmRsZXIoKTtcblxuXHRcdHRoaXMuX3JlbmRlcmVkID0gZmFsc2U7XG5cdFx0dGhpcy5tZW51SXRlbXMgPSAkKCk7XG5cdH0sXG5cblx0X2RyYXdCdXR0b246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpY29uLFxuXHRcdFx0dGhhdCA9IHRoaXMsXG5cdFx0XHRpdGVtID0gdGhpcy5fcGFyc2VPcHRpb24oXG5cdFx0XHRcdHRoaXMuZWxlbWVudC5maW5kKCBcIm9wdGlvbjpzZWxlY3RlZFwiICksXG5cdFx0XHRcdHRoaXMuZWxlbWVudFsgMCBdLnNlbGVjdGVkSW5kZXhcblx0XHRcdCk7XG5cblx0XHQvLyBBc3NvY2lhdGUgZXhpc3RpbmcgbGFiZWwgd2l0aCB0aGUgbmV3IGJ1dHRvblxuXHRcdHRoaXMubGFiZWxzID0gdGhpcy5lbGVtZW50LmxhYmVscygpLmF0dHIoIFwiZm9yXCIsIHRoaXMuaWRzLmJ1dHRvbiApO1xuXHRcdHRoaXMuX29uKCB0aGlzLmxhYmVscywge1xuXHRcdFx0Y2xpY2s6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dGhpcy5idXR0b24uZm9jdXMoKTtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHQvLyBIaWRlIG9yaWdpbmFsIHNlbGVjdCBlbGVtZW50XG5cdFx0dGhpcy5lbGVtZW50LmhpZGUoKTtcblxuXHRcdC8vIENyZWF0ZSBidXR0b25cblx0XHR0aGlzLmJ1dHRvbiA9ICQoIFwiPHNwYW4+XCIsIHtcblx0XHRcdHRhYmluZGV4OiB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgPyAtMSA6IDAsXG5cdFx0XHRpZDogdGhpcy5pZHMuYnV0dG9uLFxuXHRcdFx0cm9sZTogXCJjb21ib2JveFwiLFxuXHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwiZmFsc2VcIixcblx0XHRcdFwiYXJpYS1hdXRvY29tcGxldGVcIjogXCJsaXN0XCIsXG5cdFx0XHRcImFyaWEtb3duc1wiOiB0aGlzLmlkcy5tZW51LFxuXHRcdFx0XCJhcmlhLWhhc3BvcHVwXCI6IFwidHJ1ZVwiLFxuXHRcdFx0dGl0bGU6IHRoaXMuZWxlbWVudC5hdHRyKCBcInRpdGxlXCIgKVxuXHRcdH0gKVxuXHRcdFx0Lmluc2VydEFmdGVyKCB0aGlzLmVsZW1lbnQgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmJ1dHRvbiwgXCJ1aS1zZWxlY3RtZW51LWJ1dHRvbiB1aS1zZWxlY3RtZW51LWJ1dHRvbi1jbG9zZWRcIixcblx0XHRcdFwidWktYnV0dG9uIHVpLXdpZGdldFwiICk7XG5cblx0XHRpY29uID0gJCggXCI8c3Bhbj5cIiApLmFwcGVuZFRvKCB0aGlzLmJ1dHRvbiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBpY29uLCBcInVpLXNlbGVjdG1lbnUtaWNvblwiLCBcInVpLWljb24gXCIgKyB0aGlzLm9wdGlvbnMuaWNvbnMuYnV0dG9uICk7XG5cdFx0dGhpcy5idXR0b25JdGVtID0gdGhpcy5fcmVuZGVyQnV0dG9uSXRlbSggaXRlbSApXG5cdFx0XHQuYXBwZW5kVG8oIHRoaXMuYnV0dG9uICk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy53aWR0aCAhPT0gZmFsc2UgKSB7XG5cdFx0XHR0aGlzLl9yZXNpemVCdXR0b24oKTtcblx0XHR9XG5cblx0XHR0aGlzLl9vbiggdGhpcy5idXR0b24sIHRoaXMuX2J1dHRvbkV2ZW50cyApO1xuXHRcdHRoaXMuYnV0dG9uLm9uZSggXCJmb2N1c2luXCIsIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBEZWxheSByZW5kZXJpbmcgdGhlIG1lbnUgaXRlbXMgdW50aWwgdGhlIGJ1dHRvbiByZWNlaXZlcyBmb2N1cy5cblx0XHRcdC8vIFRoZSBtZW51IG1heSBoYXZlIGFscmVhZHkgYmVlbiByZW5kZXJlZCB2aWEgYSBwcm9ncmFtbWF0aWMgb3Blbi5cblx0XHRcdGlmICggIXRoYXQuX3JlbmRlcmVkICkge1xuXHRcdFx0XHR0aGF0Ll9yZWZyZXNoTWVudSgpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfZHJhd01lbnU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdC8vIENyZWF0ZSBtZW51XG5cdFx0dGhpcy5tZW51ID0gJCggXCI8dWw+XCIsIHtcblx0XHRcdFwiYXJpYS1oaWRkZW5cIjogXCJ0cnVlXCIsXG5cdFx0XHRcImFyaWEtbGFiZWxsZWRieVwiOiB0aGlzLmlkcy5idXR0b24sXG5cdFx0XHRpZDogdGhpcy5pZHMubWVudVxuXHRcdH0gKTtcblxuXHRcdC8vIFdyYXAgbWVudVxuXHRcdHRoaXMubWVudVdyYXAgPSAkKCBcIjxkaXY+XCIgKS5hcHBlbmQoIHRoaXMubWVudSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLm1lbnVXcmFwLCBcInVpLXNlbGVjdG1lbnUtbWVudVwiLCBcInVpLWZyb250XCIgKTtcblx0XHR0aGlzLm1lbnVXcmFwLmFwcGVuZFRvKCB0aGlzLl9hcHBlbmRUbygpICk7XG5cblx0XHQvLyBJbml0aWFsaXplIG1lbnUgd2lkZ2V0XG5cdFx0dGhpcy5tZW51SW5zdGFuY2UgPSB0aGlzLm1lbnVcblx0XHRcdC5tZW51KCB7XG5cdFx0XHRcdGNsYXNzZXM6IHtcblx0XHRcdFx0XHRcInVpLW1lbnVcIjogXCJ1aS1jb3JuZXItYm90dG9tXCJcblx0XHRcdFx0fSxcblx0XHRcdFx0cm9sZTogXCJsaXN0Ym94XCIsXG5cdFx0XHRcdHNlbGVjdDogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUU4XG5cdFx0XHRcdFx0Ly8gSWYgdGhlIGl0ZW0gd2FzIHNlbGVjdGVkIHZpYSBhIGNsaWNrLCB0aGUgdGV4dCBzZWxlY3Rpb25cblx0XHRcdFx0XHQvLyB3aWxsIGJlIGRlc3Ryb3llZCBpbiBJRVxuXHRcdFx0XHRcdHRoYXQuX3NldFNlbGVjdGlvbigpO1xuXG5cdFx0XHRcdFx0dGhhdC5fc2VsZWN0KCB1aS5pdGVtLmRhdGEoIFwidWktc2VsZWN0bWVudS1pdGVtXCIgKSwgZXZlbnQgKTtcblx0XHRcdFx0fSxcblx0XHRcdFx0Zm9jdXM6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdFx0dmFyIGl0ZW0gPSB1aS5pdGVtLmRhdGEoIFwidWktc2VsZWN0bWVudS1pdGVtXCIgKTtcblxuXHRcdFx0XHRcdC8vIFByZXZlbnQgaW5pdGFsIGZvY3VzIGZyb20gZmlyaW5nIGFuZCBjaGVjayBpZiBpdHMgYSBuZXdseSBmb2N1c2VkIGl0ZW1cblx0XHRcdFx0XHRpZiAoIHRoYXQuZm9jdXNJbmRleCAhPSBudWxsICYmIGl0ZW0uaW5kZXggIT09IHRoYXQuZm9jdXNJbmRleCApIHtcblx0XHRcdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwiZm9jdXNcIiwgZXZlbnQsIHsgaXRlbTogaXRlbSB9ICk7XG5cdFx0XHRcdFx0XHRpZiAoICF0aGF0LmlzT3BlbiApIHtcblx0XHRcdFx0XHRcdFx0dGhhdC5fc2VsZWN0KCBpdGVtLCBldmVudCApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHR0aGF0LmZvY3VzSW5kZXggPSBpdGVtLmluZGV4O1xuXG5cdFx0XHRcdFx0dGhhdC5idXR0b24uYXR0ciggXCJhcmlhLWFjdGl2ZWRlc2NlbmRhbnRcIixcblx0XHRcdFx0XHRcdHRoYXQubWVudUl0ZW1zLmVxKCBpdGVtLmluZGV4ICkuYXR0ciggXCJpZFwiICkgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApXG5cdFx0XHQubWVudSggXCJpbnN0YW5jZVwiICk7XG5cblx0XHQvLyBEb24ndCBjbG9zZSB0aGUgbWVudSBvbiBtb3VzZWxlYXZlXG5cdFx0dGhpcy5tZW51SW5zdGFuY2UuX29mZiggdGhpcy5tZW51LCBcIm1vdXNlbGVhdmVcIiApO1xuXG5cdFx0Ly8gQ2FuY2VsIHRoZSBtZW51J3MgY29sbGFwc2VBbGwgb24gZG9jdW1lbnQgY2xpY2tcblx0XHR0aGlzLm1lbnVJbnN0YW5jZS5fY2xvc2VPbkRvY3VtZW50Q2xpY2sgPSBmdW5jdGlvbigpIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9O1xuXG5cdFx0Ly8gU2VsZWN0cyBvZnRlbiBjb250YWluIGVtcHR5IGl0ZW1zLCBidXQgbmV2ZXIgY29udGFpbiBkaXZpZGVyc1xuXHRcdHRoaXMubWVudUluc3RhbmNlLl9pc0RpdmlkZXIgPSBmdW5jdGlvbigpIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9O1xuXHR9LFxuXG5cdHJlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3JlZnJlc2hNZW51KCk7XG5cdFx0dGhpcy5idXR0b25JdGVtLnJlcGxhY2VXaXRoKFxuXHRcdFx0dGhpcy5idXR0b25JdGVtID0gdGhpcy5fcmVuZGVyQnV0dG9uSXRlbShcblxuXHRcdFx0XHQvLyBGYWxsIGJhY2sgdG8gYW4gZW1wdHkgb2JqZWN0IGluIGNhc2UgdGhlcmUgYXJlIG5vIG9wdGlvbnNcblx0XHRcdFx0dGhpcy5fZ2V0U2VsZWN0ZWRJdGVtKCkuZGF0YSggXCJ1aS1zZWxlY3RtZW51LWl0ZW1cIiApIHx8IHt9XG5cdFx0XHQpXG5cdFx0KTtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy53aWR0aCA9PT0gbnVsbCApIHtcblx0XHRcdHRoaXMuX3Jlc2l6ZUJ1dHRvbigpO1xuXHRcdH1cblx0fSxcblxuXHRfcmVmcmVzaE1lbnU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpdGVtLFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMuZWxlbWVudC5maW5kKCBcIm9wdGlvblwiICk7XG5cblx0XHR0aGlzLm1lbnUuZW1wdHkoKTtcblxuXHRcdHRoaXMuX3BhcnNlT3B0aW9ucyggb3B0aW9ucyApO1xuXHRcdHRoaXMuX3JlbmRlck1lbnUoIHRoaXMubWVudSwgdGhpcy5pdGVtcyApO1xuXG5cdFx0dGhpcy5tZW51SW5zdGFuY2UucmVmcmVzaCgpO1xuXHRcdHRoaXMubWVudUl0ZW1zID0gdGhpcy5tZW51LmZpbmQoIFwibGlcIiApXG5cdFx0XHQubm90KCBcIi51aS1zZWxlY3RtZW51LW9wdGdyb3VwXCIgKVxuXHRcdFx0XHQuZmluZCggXCIudWktbWVudS1pdGVtLXdyYXBwZXJcIiApO1xuXG5cdFx0dGhpcy5fcmVuZGVyZWQgPSB0cnVlO1xuXG5cdFx0aWYgKCAhb3B0aW9ucy5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aXRlbSA9IHRoaXMuX2dldFNlbGVjdGVkSXRlbSgpO1xuXG5cdFx0Ly8gVXBkYXRlIHRoZSBtZW51IHRvIGhhdmUgdGhlIGNvcnJlY3QgaXRlbSBmb2N1c2VkXG5cdFx0dGhpcy5tZW51SW5zdGFuY2UuZm9jdXMoIG51bGwsIGl0ZW0gKTtcblx0XHR0aGlzLl9zZXRBcmlhKCBpdGVtLmRhdGEoIFwidWktc2VsZWN0bWVudS1pdGVtXCIgKSApO1xuXG5cdFx0Ly8gU2V0IGRpc2FibGVkIHN0YXRlXG5cdFx0dGhpcy5fc2V0T3B0aW9uKCBcImRpc2FibGVkXCIsIHRoaXMuZWxlbWVudC5wcm9wKCBcImRpc2FibGVkXCIgKSApO1xuXHR9LFxuXG5cdG9wZW46IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBJZiB0aGlzIGlzIHRoZSBmaXJzdCB0aW1lIHRoZSBtZW51IGlzIGJlaW5nIG9wZW5lZCwgcmVuZGVyIHRoZSBpdGVtc1xuXHRcdGlmICggIXRoaXMuX3JlbmRlcmVkICkge1xuXHRcdFx0dGhpcy5fcmVmcmVzaE1lbnUoKTtcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBNZW51IGNsZWFycyBmb2N1cyBvbiBjbG9zZSwgcmVzZXQgZm9jdXMgdG8gc2VsZWN0ZWQgaXRlbVxuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMubWVudS5maW5kKCBcIi51aS1zdGF0ZS1hY3RpdmVcIiApLCBudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHR0aGlzLm1lbnVJbnN0YW5jZS5mb2N1cyggbnVsbCwgdGhpcy5fZ2V0U2VsZWN0ZWRJdGVtKCkgKTtcblx0XHR9XG5cblx0XHQvLyBJZiB0aGVyZSBhcmUgbm8gb3B0aW9ucywgZG9uJ3Qgb3BlbiB0aGUgbWVudVxuXHRcdGlmICggIXRoaXMubWVudUl0ZW1zLmxlbmd0aCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLmlzT3BlbiA9IHRydWU7XG5cdFx0dGhpcy5fdG9nZ2xlQXR0cigpO1xuXHRcdHRoaXMuX3Jlc2l6ZU1lbnUoKTtcblx0XHR0aGlzLl9wb3NpdGlvbigpO1xuXG5cdFx0dGhpcy5fb24oIHRoaXMuZG9jdW1lbnQsIHRoaXMuX2RvY3VtZW50Q2xpY2sgKTtcblxuXHRcdHRoaXMuX3RyaWdnZXIoIFwib3BlblwiLCBldmVudCApO1xuXHR9LFxuXG5cdF9wb3NpdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5tZW51V3JhcC5wb3NpdGlvbiggJC5leHRlbmQoIHsgb2Y6IHRoaXMuYnV0dG9uIH0sIHRoaXMub3B0aW9ucy5wb3NpdGlvbiApICk7XG5cdH0sXG5cblx0Y2xvc2U6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoICF0aGlzLmlzT3BlbiApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLmlzT3BlbiA9IGZhbHNlO1xuXHRcdHRoaXMuX3RvZ2dsZUF0dHIoKTtcblxuXHRcdHRoaXMucmFuZ2UgPSBudWxsO1xuXHRcdHRoaXMuX29mZiggdGhpcy5kb2N1bWVudCApO1xuXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJjbG9zZVwiLCBldmVudCApO1xuXHR9LFxuXG5cdHdpZGdldDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuYnV0dG9uO1xuXHR9LFxuXG5cdG1lbnVXaWRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLm1lbnU7XG5cdH0sXG5cblx0X3JlbmRlckJ1dHRvbkl0ZW06IGZ1bmN0aW9uKCBpdGVtICkge1xuXHRcdHZhciBidXR0b25JdGVtID0gJCggXCI8c3Bhbj5cIiApO1xuXG5cdFx0dGhpcy5fc2V0VGV4dCggYnV0dG9uSXRlbSwgaXRlbS5sYWJlbCApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBidXR0b25JdGVtLCBcInVpLXNlbGVjdG1lbnUtdGV4dFwiICk7XG5cblx0XHRyZXR1cm4gYnV0dG9uSXRlbTtcblx0fSxcblxuXHRfcmVuZGVyTWVudTogZnVuY3Rpb24oIHVsLCBpdGVtcyApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRjdXJyZW50T3B0Z3JvdXAgPSBcIlwiO1xuXG5cdFx0JC5lYWNoKCBpdGVtcywgZnVuY3Rpb24oIGluZGV4LCBpdGVtICkge1xuXHRcdFx0dmFyIGxpO1xuXG5cdFx0XHRpZiAoIGl0ZW0ub3B0Z3JvdXAgIT09IGN1cnJlbnRPcHRncm91cCApIHtcblx0XHRcdFx0bGkgPSAkKCBcIjxsaT5cIiwge1xuXHRcdFx0XHRcdHRleHQ6IGl0ZW0ub3B0Z3JvdXBcblx0XHRcdFx0fSApO1xuXHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggbGksIFwidWktc2VsZWN0bWVudS1vcHRncm91cFwiLCBcInVpLW1lbnUtZGl2aWRlclwiICtcblx0XHRcdFx0XHQoIGl0ZW0uZWxlbWVudC5wYXJlbnQoIFwib3B0Z3JvdXBcIiApLnByb3AoIFwiZGlzYWJsZWRcIiApID9cblx0XHRcdFx0XHRcdFwiIHVpLXN0YXRlLWRpc2FibGVkXCIgOlxuXHRcdFx0XHRcdFx0XCJcIiApICk7XG5cblx0XHRcdFx0bGkuYXBwZW5kVG8oIHVsICk7XG5cblx0XHRcdFx0Y3VycmVudE9wdGdyb3VwID0gaXRlbS5vcHRncm91cDtcblx0XHRcdH1cblxuXHRcdFx0dGhhdC5fcmVuZGVySXRlbURhdGEoIHVsLCBpdGVtICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9yZW5kZXJJdGVtRGF0YTogZnVuY3Rpb24oIHVsLCBpdGVtICkge1xuXHRcdHJldHVybiB0aGlzLl9yZW5kZXJJdGVtKCB1bCwgaXRlbSApLmRhdGEoIFwidWktc2VsZWN0bWVudS1pdGVtXCIsIGl0ZW0gKTtcblx0fSxcblxuXHRfcmVuZGVySXRlbTogZnVuY3Rpb24oIHVsLCBpdGVtICkge1xuXHRcdHZhciBsaSA9ICQoIFwiPGxpPlwiICksXG5cdFx0XHR3cmFwcGVyID0gJCggXCI8ZGl2PlwiLCB7XG5cdFx0XHRcdHRpdGxlOiBpdGVtLmVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiIClcblx0XHRcdH0gKTtcblxuXHRcdGlmICggaXRlbS5kaXNhYmxlZCApIHtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCBsaSwgbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiICk7XG5cdFx0fVxuXHRcdHRoaXMuX3NldFRleHQoIHdyYXBwZXIsIGl0ZW0ubGFiZWwgKTtcblxuXHRcdHJldHVybiBsaS5hcHBlbmQoIHdyYXBwZXIgKS5hcHBlbmRUbyggdWwgKTtcblx0fSxcblxuXHRfc2V0VGV4dDogZnVuY3Rpb24oIGVsZW1lbnQsIHZhbHVlICkge1xuXHRcdGlmICggdmFsdWUgKSB7XG5cdFx0XHRlbGVtZW50LnRleHQoIHZhbHVlICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGVsZW1lbnQuaHRtbCggXCImIzE2MDtcIiApO1xuXHRcdH1cblx0fSxcblxuXHRfbW92ZTogZnVuY3Rpb24oIGRpcmVjdGlvbiwgZXZlbnQgKSB7XG5cdFx0dmFyIGl0ZW0sIG5leHQsXG5cdFx0XHRmaWx0ZXIgPSBcIi51aS1tZW51LWl0ZW1cIjtcblxuXHRcdGlmICggdGhpcy5pc09wZW4gKSB7XG5cdFx0XHRpdGVtID0gdGhpcy5tZW51SXRlbXMuZXEoIHRoaXMuZm9jdXNJbmRleCApLnBhcmVudCggXCJsaVwiICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGl0ZW0gPSB0aGlzLm1lbnVJdGVtcy5lcSggdGhpcy5lbGVtZW50WyAwIF0uc2VsZWN0ZWRJbmRleCApLnBhcmVudCggXCJsaVwiICk7XG5cdFx0XHRmaWx0ZXIgKz0gXCI6bm90KC51aS1zdGF0ZS1kaXNhYmxlZClcIjtcblx0XHR9XG5cblx0XHRpZiAoIGRpcmVjdGlvbiA9PT0gXCJmaXJzdFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJsYXN0XCIgKSB7XG5cdFx0XHRuZXh0ID0gaXRlbVsgZGlyZWN0aW9uID09PSBcImZpcnN0XCIgPyBcInByZXZBbGxcIiA6IFwibmV4dEFsbFwiIF0oIGZpbHRlciApLmVxKCAtMSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRuZXh0ID0gaXRlbVsgZGlyZWN0aW9uICsgXCJBbGxcIiBdKCBmaWx0ZXIgKS5lcSggMCApO1xuXHRcdH1cblxuXHRcdGlmICggbmV4dC5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLm1lbnVJbnN0YW5jZS5mb2N1cyggZXZlbnQsIG5leHQgKTtcblx0XHR9XG5cdH0sXG5cblx0X2dldFNlbGVjdGVkSXRlbTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMubWVudUl0ZW1zLmVxKCB0aGlzLmVsZW1lbnRbIDAgXS5zZWxlY3RlZEluZGV4ICkucGFyZW50KCBcImxpXCIgKTtcblx0fSxcblxuXHRfdG9nZ2xlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dGhpc1sgdGhpcy5pc09wZW4gPyBcImNsb3NlXCIgOiBcIm9wZW5cIiBdKCBldmVudCApO1xuXHR9LFxuXG5cdF9zZXRTZWxlY3Rpb246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBzZWxlY3Rpb247XG5cblx0XHRpZiAoICF0aGlzLnJhbmdlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggd2luZG93LmdldFNlbGVjdGlvbiApIHtcblx0XHRcdHNlbGVjdGlvbiA9IHdpbmRvdy5nZXRTZWxlY3Rpb24oKTtcblx0XHRcdHNlbGVjdGlvbi5yZW1vdmVBbGxSYW5nZXMoKTtcblx0XHRcdHNlbGVjdGlvbi5hZGRSYW5nZSggdGhpcy5yYW5nZSApO1xuXG5cdFx0Ly8gU3VwcG9ydDogSUU4XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMucmFuZ2Uuc2VsZWN0KCk7XG5cdFx0fVxuXG5cdFx0Ly8gU3VwcG9ydDogSUVcblx0XHQvLyBTZXR0aW5nIHRoZSB0ZXh0IHNlbGVjdGlvbiBraWxscyB0aGUgYnV0dG9uIGZvY3VzIGluIElFLCBidXRcblx0XHQvLyByZXN0b3JpbmcgdGhlIGZvY3VzIGRvZXNuJ3Qga2lsbCB0aGUgc2VsZWN0aW9uLlxuXHRcdHRoaXMuYnV0dG9uLmZvY3VzKCk7XG5cdH0sXG5cblx0X2RvY3VtZW50Q2xpY2s6IHtcblx0XHRtb3VzZWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdGlmICggIXRoaXMuaXNPcGVuICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGlmICggISQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIFwiLnVpLXNlbGVjdG1lbnUtbWVudSwgI1wiICtcblx0XHRcdFx0XHQkLnVpLmVzY2FwZVNlbGVjdG9yKCB0aGlzLmlkcy5idXR0b24gKSApLmxlbmd0aCApIHtcblx0XHRcdFx0dGhpcy5jbG9zZSggZXZlbnQgKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X2J1dHRvbkV2ZW50czoge1xuXG5cdFx0Ly8gUHJldmVudCB0ZXh0IHNlbGVjdGlvbiBmcm9tIGJlaW5nIHJlc2V0IHdoZW4gaW50ZXJhY3Rpbmcgd2l0aCB0aGUgc2VsZWN0bWVudSAoIzEwMTQ0KVxuXHRcdG1vdXNlZG93bjogZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc2VsZWN0aW9uO1xuXG5cdFx0XHRpZiAoIHdpbmRvdy5nZXRTZWxlY3Rpb24gKSB7XG5cdFx0XHRcdHNlbGVjdGlvbiA9IHdpbmRvdy5nZXRTZWxlY3Rpb24oKTtcblx0XHRcdFx0aWYgKCBzZWxlY3Rpb24ucmFuZ2VDb3VudCApIHtcblx0XHRcdFx0XHR0aGlzLnJhbmdlID0gc2VsZWN0aW9uLmdldFJhbmdlQXQoIDAgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRThcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMucmFuZ2UgPSBkb2N1bWVudC5zZWxlY3Rpb24uY3JlYXRlUmFuZ2UoKTtcblx0XHRcdH1cblx0XHR9LFxuXG5cdFx0Y2xpY2s6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHRoaXMuX3NldFNlbGVjdGlvbigpO1xuXHRcdFx0dGhpcy5fdG9nZ2xlKCBldmVudCApO1xuXHRcdH0sXG5cblx0XHRrZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHR2YXIgcHJldmVudERlZmF1bHQgPSB0cnVlO1xuXHRcdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlRBQjpcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkVTQ0FQRTpcblx0XHRcdFx0dGhpcy5jbG9zZSggZXZlbnQgKTtcblx0XHRcdFx0cHJldmVudERlZmF1bHQgPSBmYWxzZTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5FTlRFUjpcblx0XHRcdFx0aWYgKCB0aGlzLmlzT3BlbiApIHtcblx0XHRcdFx0XHR0aGlzLl9zZWxlY3RGb2N1c2VkSXRlbSggZXZlbnQgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlVQOlxuXHRcdFx0XHRpZiAoIGV2ZW50LmFsdEtleSApIHtcblx0XHRcdFx0XHR0aGlzLl90b2dnbGUoIGV2ZW50ICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5fbW92ZSggXCJwcmV2XCIsIGV2ZW50ICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5ET1dOOlxuXHRcdFx0XHRpZiAoIGV2ZW50LmFsdEtleSApIHtcblx0XHRcdFx0XHR0aGlzLl90b2dnbGUoIGV2ZW50ICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5fbW92ZSggXCJuZXh0XCIsIGV2ZW50ICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5TUEFDRTpcblx0XHRcdFx0aWYgKCB0aGlzLmlzT3BlbiApIHtcblx0XHRcdFx0XHR0aGlzLl9zZWxlY3RGb2N1c2VkSXRlbSggZXZlbnQgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aGlzLl90b2dnbGUoIGV2ZW50ICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5MRUZUOlxuXHRcdFx0XHR0aGlzLl9tb3ZlKCBcInByZXZcIiwgZXZlbnQgKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5SSUdIVDpcblx0XHRcdFx0dGhpcy5fbW92ZSggXCJuZXh0XCIsIGV2ZW50ICk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuSE9NRTpcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlBBR0VfVVA6XG5cdFx0XHRcdHRoaXMuX21vdmUoIFwiZmlyc3RcIiwgZXZlbnQgKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5FTkQ6XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5QQUdFX0RPV046XG5cdFx0XHRcdHRoaXMuX21vdmUoIFwibGFzdFwiLCBldmVudCApO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdHRoaXMubWVudS50cmlnZ2VyKCBldmVudCApO1xuXHRcdFx0XHRwcmV2ZW50RGVmYXVsdCA9IGZhbHNlO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHByZXZlbnREZWZhdWx0ICkge1xuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRfc2VsZWN0Rm9jdXNlZEl0ZW06IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgaXRlbSA9IHRoaXMubWVudUl0ZW1zLmVxKCB0aGlzLmZvY3VzSW5kZXggKS5wYXJlbnQoIFwibGlcIiApO1xuXHRcdGlmICggIWl0ZW0uaGFzQ2xhc3MoIFwidWktc3RhdGUtZGlzYWJsZWRcIiApICkge1xuXHRcdFx0dGhpcy5fc2VsZWN0KCBpdGVtLmRhdGEoIFwidWktc2VsZWN0bWVudS1pdGVtXCIgKSwgZXZlbnQgKTtcblx0XHR9XG5cdH0sXG5cblx0X3NlbGVjdDogZnVuY3Rpb24oIGl0ZW0sIGV2ZW50ICkge1xuXHRcdHZhciBvbGRJbmRleCA9IHRoaXMuZWxlbWVudFsgMCBdLnNlbGVjdGVkSW5kZXg7XG5cblx0XHQvLyBDaGFuZ2UgbmF0aXZlIHNlbGVjdCBlbGVtZW50XG5cdFx0dGhpcy5lbGVtZW50WyAwIF0uc2VsZWN0ZWRJbmRleCA9IGl0ZW0uaW5kZXg7XG5cdFx0dGhpcy5idXR0b25JdGVtLnJlcGxhY2VXaXRoKCB0aGlzLmJ1dHRvbkl0ZW0gPSB0aGlzLl9yZW5kZXJCdXR0b25JdGVtKCBpdGVtICkgKTtcblx0XHR0aGlzLl9zZXRBcmlhKCBpdGVtICk7XG5cdFx0dGhpcy5fdHJpZ2dlciggXCJzZWxlY3RcIiwgZXZlbnQsIHsgaXRlbTogaXRlbSB9ICk7XG5cblx0XHRpZiAoIGl0ZW0uaW5kZXggIT09IG9sZEluZGV4ICkge1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjaGFuZ2VcIiwgZXZlbnQsIHsgaXRlbTogaXRlbSB9ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5jbG9zZSggZXZlbnQgKTtcblx0fSxcblxuXHRfc2V0QXJpYTogZnVuY3Rpb24oIGl0ZW0gKSB7XG5cdFx0dmFyIGlkID0gdGhpcy5tZW51SXRlbXMuZXEoIGl0ZW0uaW5kZXggKS5hdHRyKCBcImlkXCIgKTtcblxuXHRcdHRoaXMuYnV0dG9uLmF0dHIoIHtcblx0XHRcdFwiYXJpYS1sYWJlbGxlZGJ5XCI6IGlkLFxuXHRcdFx0XCJhcmlhLWFjdGl2ZWRlc2NlbmRhbnRcIjogaWRcblx0XHR9ICk7XG5cdFx0dGhpcy5tZW51LmF0dHIoIFwiYXJpYS1hY3RpdmVkZXNjZW5kYW50XCIsIGlkICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0aWYgKCBrZXkgPT09IFwiaWNvbnNcIiApIHtcblx0XHRcdHZhciBpY29uID0gdGhpcy5idXR0b24uZmluZCggXCJzcGFuLnVpLWljb25cIiApO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGljb24sIG51bGwsIHRoaXMub3B0aW9ucy5pY29ucy5idXR0b24gKVxuXHRcdFx0XHQuX2FkZENsYXNzKCBpY29uLCBudWxsLCB2YWx1ZS5idXR0b24gKTtcblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiYXBwZW5kVG9cIiApIHtcblx0XHRcdHRoaXMubWVudVdyYXAuYXBwZW5kVG8oIHRoaXMuX2FwcGVuZFRvKCkgKTtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJ3aWR0aFwiICkge1xuXHRcdFx0dGhpcy5fcmVzaXplQnV0dG9uKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb25EaXNhYmxlZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCB2YWx1ZSApO1xuXG5cdFx0dGhpcy5tZW51SW5zdGFuY2Uub3B0aW9uKCBcImRpc2FibGVkXCIsIHZhbHVlICk7XG5cdFx0dGhpcy5idXR0b24uYXR0ciggXCJhcmlhLWRpc2FibGVkXCIsIHZhbHVlICk7XG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIHRoaXMuYnV0dG9uLCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIsIHZhbHVlICk7XG5cblx0XHR0aGlzLmVsZW1lbnQucHJvcCggXCJkaXNhYmxlZFwiLCB2YWx1ZSApO1xuXHRcdGlmICggdmFsdWUgKSB7XG5cdFx0XHR0aGlzLmJ1dHRvbi5hdHRyKCBcInRhYmluZGV4XCIsIC0xICk7XG5cdFx0XHR0aGlzLmNsb3NlKCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuYnV0dG9uLmF0dHIoIFwidGFiaW5kZXhcIiwgMCApO1xuXHRcdH1cblx0fSxcblxuXHRfYXBwZW5kVG86IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBlbGVtZW50ID0gdGhpcy5vcHRpb25zLmFwcGVuZFRvO1xuXG5cdFx0aWYgKCBlbGVtZW50ICkge1xuXHRcdFx0ZWxlbWVudCA9IGVsZW1lbnQuanF1ZXJ5IHx8IGVsZW1lbnQubm9kZVR5cGUgP1xuXHRcdFx0XHQkKCBlbGVtZW50ICkgOlxuXHRcdFx0XHR0aGlzLmRvY3VtZW50LmZpbmQoIGVsZW1lbnQgKS5lcSggMCApO1xuXHRcdH1cblxuXHRcdGlmICggIWVsZW1lbnQgfHwgIWVsZW1lbnRbIDAgXSApIHtcblx0XHRcdGVsZW1lbnQgPSB0aGlzLmVsZW1lbnQuY2xvc2VzdCggXCIudWktZnJvbnQsIGRpYWxvZ1wiICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhZWxlbWVudC5sZW5ndGggKSB7XG5cdFx0XHRlbGVtZW50ID0gdGhpcy5kb2N1bWVudFsgMCBdLmJvZHk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGVsZW1lbnQ7XG5cdH0sXG5cblx0X3RvZ2dsZUF0dHI6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuYnV0dG9uLmF0dHIoIFwiYXJpYS1leHBhbmRlZFwiLCB0aGlzLmlzT3BlbiApO1xuXG5cdFx0Ly8gV2UgY2FuJ3QgdXNlIHR3byBfdG9nZ2xlQ2xhc3MoKSBjYWxscyBoZXJlLCBiZWNhdXNlIHdlIG5lZWQgdG8gbWFrZSBzdXJlXG5cdFx0Ly8gd2UgYWx3YXlzIHJlbW92ZSBjbGFzc2VzIGZpcnN0IGFuZCBhZGQgdGhlbSBzZWNvbmQsIG90aGVyd2lzZSBpZiBib3RoIGNsYXNzZXMgaGF2ZSB0aGVcblx0XHQvLyBzYW1lIHRoZW1lIGNsYXNzLCBpdCB3aWxsIGJlIHJlbW92ZWQgYWZ0ZXIgd2UgYWRkIGl0LlxuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmJ1dHRvbiwgXCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1cIiArXG5cdFx0XHQoIHRoaXMuaXNPcGVuID8gXCJjbG9zZWRcIiA6IFwib3BlblwiICkgKVxuXHRcdFx0Ll9hZGRDbGFzcyggdGhpcy5idXR0b24sIFwidWktc2VsZWN0bWVudS1idXR0b24tXCIgK1xuXHRcdFx0XHQoIHRoaXMuaXNPcGVuID8gXCJvcGVuXCIgOiBcImNsb3NlZFwiICkgKVxuXHRcdFx0Ll90b2dnbGVDbGFzcyggdGhpcy5tZW51V3JhcCwgXCJ1aS1zZWxlY3RtZW51LW9wZW5cIiwgbnVsbCwgdGhpcy5pc09wZW4gKTtcblxuXHRcdHRoaXMubWVudS5hdHRyKCBcImFyaWEtaGlkZGVuXCIsICF0aGlzLmlzT3BlbiApO1xuXHR9LFxuXG5cdF9yZXNpemVCdXR0b246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB3aWR0aCA9IHRoaXMub3B0aW9ucy53aWR0aDtcblxuXHRcdC8vIEZvciBgd2lkdGg6IGZhbHNlYCwganVzdCByZW1vdmUgaW5saW5lIHN0eWxlIGFuZCBzdG9wXG5cdFx0aWYgKCB3aWR0aCA9PT0gZmFsc2UgKSB7XG5cdFx0XHR0aGlzLmJ1dHRvbi5jc3MoIFwid2lkdGhcIiwgXCJcIiApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEZvciBgd2lkdGg6IG51bGxgLCBtYXRjaCB0aGUgd2lkdGggb2YgdGhlIG9yaWdpbmFsIGVsZW1lbnRcblx0XHRpZiAoIHdpZHRoID09PSBudWxsICkge1xuXHRcdFx0d2lkdGggPSB0aGlzLmVsZW1lbnQuc2hvdygpLm91dGVyV2lkdGgoKTtcblx0XHRcdHRoaXMuZWxlbWVudC5oaWRlKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5idXR0b24ub3V0ZXJXaWR0aCggd2lkdGggKTtcblx0fSxcblxuXHRfcmVzaXplTWVudTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5tZW51Lm91dGVyV2lkdGgoIE1hdGgubWF4KFxuXHRcdFx0dGhpcy5idXR0b24ub3V0ZXJXaWR0aCgpLFxuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRTEwXG5cdFx0XHQvLyBJRTEwIHdyYXBzIGxvbmcgdGV4dCAocG9zc2libHkgYSByb3VuZGluZyBidWcpXG5cdFx0XHQvLyBzbyB3ZSBhZGQgMXB4IHRvIGF2b2lkIHRoZSB3cmFwcGluZ1xuXHRcdFx0dGhpcy5tZW51LndpZHRoKCBcIlwiICkub3V0ZXJXaWR0aCgpICsgMVxuXHRcdCkgKTtcblx0fSxcblxuXHRfZ2V0Q3JlYXRlT3B0aW9uczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLl9zdXBlcigpO1xuXG5cdFx0b3B0aW9ucy5kaXNhYmxlZCA9IHRoaXMuZWxlbWVudC5wcm9wKCBcImRpc2FibGVkXCIgKTtcblxuXHRcdHJldHVybiBvcHRpb25zO1xuXHR9LFxuXG5cdF9wYXJzZU9wdGlvbnM6IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdGRhdGEgPSBbXTtcblx0XHRvcHRpb25zLmVhY2goIGZ1bmN0aW9uKCBpbmRleCwgaXRlbSApIHtcblx0XHRcdGRhdGEucHVzaCggdGhhdC5fcGFyc2VPcHRpb24oICQoIGl0ZW0gKSwgaW5kZXggKSApO1xuXHRcdH0gKTtcblx0XHR0aGlzLml0ZW1zID0gZGF0YTtcblx0fSxcblxuXHRfcGFyc2VPcHRpb246IGZ1bmN0aW9uKCBvcHRpb24sIGluZGV4ICkge1xuXHRcdHZhciBvcHRncm91cCA9IG9wdGlvbi5wYXJlbnQoIFwib3B0Z3JvdXBcIiApO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdGVsZW1lbnQ6IG9wdGlvbixcblx0XHRcdGluZGV4OiBpbmRleCxcblx0XHRcdHZhbHVlOiBvcHRpb24udmFsKCksXG5cdFx0XHRsYWJlbDogb3B0aW9uLnRleHQoKSxcblx0XHRcdG9wdGdyb3VwOiBvcHRncm91cC5hdHRyKCBcImxhYmVsXCIgKSB8fCBcIlwiLFxuXHRcdFx0ZGlzYWJsZWQ6IG9wdGdyb3VwLnByb3AoIFwiZGlzYWJsZWRcIiApIHx8IG9wdGlvbi5wcm9wKCBcImRpc2FibGVkXCIgKVxuXHRcdH07XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3VuYmluZEZvcm1SZXNldEhhbmRsZXIoKTtcblx0XHR0aGlzLm1lbnVXcmFwLnJlbW92ZSgpO1xuXHRcdHRoaXMuYnV0dG9uLnJlbW92ZSgpO1xuXHRcdHRoaXMuZWxlbWVudC5zaG93KCk7XG5cdFx0dGhpcy5lbGVtZW50LnJlbW92ZVVuaXF1ZUlkKCk7XG5cdFx0dGhpcy5sYWJlbHMuYXR0ciggXCJmb3JcIiwgdGhpcy5pZHMuZWxlbWVudCApO1xuXHR9XG59IF0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBTbGlkZXIgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFNsaWRlclxuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IERpc3BsYXlzIGEgZmxleGlibGUgc2xpZGVyIHdpdGggcmFuZ2VzIGFuZCBhY2Nlc3NpYmlsaXR5IHZpYSBrZXlib2FyZC5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zbGlkZXIvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vc2xpZGVyL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2Uvc2xpZGVyLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG52YXIgd2lkZ2V0c1NsaWRlciA9ICQud2lkZ2V0KCBcInVpLnNsaWRlclwiLCAkLnVpLm1vdXNlLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdHdpZGdldEV2ZW50UHJlZml4OiBcInNsaWRlXCIsXG5cblx0b3B0aW9uczoge1xuXHRcdGFuaW1hdGU6IGZhbHNlLFxuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktc2xpZGVyXCI6IFwidWktY29ybmVyLWFsbFwiLFxuXHRcdFx0XCJ1aS1zbGlkZXItaGFuZGxlXCI6IFwidWktY29ybmVyLWFsbFwiLFxuXG5cdFx0XHQvLyBOb3RlOiB1aS13aWRnZXQtaGVhZGVyIGlzbid0IHRoZSBtb3N0IGZpdHRpbmdseSBzZW1hbnRpYyBmcmFtZXdvcmsgY2xhc3MgZm9yIHRoaXNcblx0XHRcdC8vIGVsZW1lbnQsIGJ1dCB3b3JrZWQgYmVzdCB2aXN1YWxseSB3aXRoIGEgdmFyaWV0eSBvZiB0aGVtZXNcblx0XHRcdFwidWktc2xpZGVyLXJhbmdlXCI6IFwidWktY29ybmVyLWFsbCB1aS13aWRnZXQtaGVhZGVyXCJcblx0XHR9LFxuXHRcdGRpc3RhbmNlOiAwLFxuXHRcdG1heDogMTAwLFxuXHRcdG1pbjogMCxcblx0XHRvcmllbnRhdGlvbjogXCJob3Jpem9udGFsXCIsXG5cdFx0cmFuZ2U6IGZhbHNlLFxuXHRcdHN0ZXA6IDEsXG5cdFx0dmFsdWU6IDAsXG5cdFx0dmFsdWVzOiBudWxsLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0Y2hhbmdlOiBudWxsLFxuXHRcdHNsaWRlOiBudWxsLFxuXHRcdHN0YXJ0OiBudWxsLFxuXHRcdHN0b3A6IG51bGxcblx0fSxcblxuXHQvLyBOdW1iZXIgb2YgcGFnZXMgaW4gYSBzbGlkZXJcblx0Ly8gKGhvdyBtYW55IHRpbWVzIGNhbiB5b3UgcGFnZSB1cC9kb3duIHRvIGdvIHRocm91Z2ggdGhlIHdob2xlIHJhbmdlKVxuXHRudW1QYWdlczogNSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9rZXlTbGlkaW5nID0gZmFsc2U7XG5cdFx0dGhpcy5fbW91c2VTbGlkaW5nID0gZmFsc2U7XG5cdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IHRydWU7XG5cdFx0dGhpcy5faGFuZGxlSW5kZXggPSBudWxsO1xuXHRcdHRoaXMuX2RldGVjdE9yaWVudGF0aW9uKCk7XG5cdFx0dGhpcy5fbW91c2VJbml0KCk7XG5cdFx0dGhpcy5fY2FsY3VsYXRlTmV3TWF4KCk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1zbGlkZXIgdWktc2xpZGVyLVwiICsgdGhpcy5vcmllbnRhdGlvbixcblx0XHRcdFwidWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50XCIgKTtcblxuXHRcdHRoaXMuX3JlZnJlc2goKTtcblxuXHRcdHRoaXMuX2FuaW1hdGVPZmYgPSBmYWxzZTtcblx0fSxcblxuXHRfcmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fY3JlYXRlUmFuZ2UoKTtcblx0XHR0aGlzLl9jcmVhdGVIYW5kbGVzKCk7XG5cdFx0dGhpcy5fc2V0dXBFdmVudHMoKTtcblx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0fSxcblxuXHRfY3JlYXRlSGFuZGxlczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGksIGhhbmRsZUNvdW50LFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGV4aXN0aW5nSGFuZGxlcyA9IHRoaXMuZWxlbWVudC5maW5kKCBcIi51aS1zbGlkZXItaGFuZGxlXCIgKSxcblx0XHRcdGhhbmRsZSA9IFwiPHNwYW4gdGFiaW5kZXg9JzAnPjwvc3Bhbj5cIixcblx0XHRcdGhhbmRsZXMgPSBbXTtcblxuXHRcdGhhbmRsZUNvdW50ID0gKCBvcHRpb25zLnZhbHVlcyAmJiBvcHRpb25zLnZhbHVlcy5sZW5ndGggKSB8fCAxO1xuXG5cdFx0aWYgKCBleGlzdGluZ0hhbmRsZXMubGVuZ3RoID4gaGFuZGxlQ291bnQgKSB7XG5cdFx0XHRleGlzdGluZ0hhbmRsZXMuc2xpY2UoIGhhbmRsZUNvdW50ICkucmVtb3ZlKCk7XG5cdFx0XHRleGlzdGluZ0hhbmRsZXMgPSBleGlzdGluZ0hhbmRsZXMuc2xpY2UoIDAsIGhhbmRsZUNvdW50ICk7XG5cdFx0fVxuXG5cdFx0Zm9yICggaSA9IGV4aXN0aW5nSGFuZGxlcy5sZW5ndGg7IGkgPCBoYW5kbGVDb3VudDsgaSsrICkge1xuXHRcdFx0aGFuZGxlcy5wdXNoKCBoYW5kbGUgKTtcblx0XHR9XG5cblx0XHR0aGlzLmhhbmRsZXMgPSBleGlzdGluZ0hhbmRsZXMuYWRkKCAkKCBoYW5kbGVzLmpvaW4oIFwiXCIgKSApLmFwcGVuZFRvKCB0aGlzLmVsZW1lbnQgKSApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaGFuZGxlcywgXCJ1aS1zbGlkZXItaGFuZGxlXCIsIFwidWktc3RhdGUtZGVmYXVsdFwiICk7XG5cblx0XHR0aGlzLmhhbmRsZSA9IHRoaXMuaGFuZGxlcy5lcSggMCApO1xuXG5cdFx0dGhpcy5oYW5kbGVzLmVhY2goIGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0JCggdGhpcyApXG5cdFx0XHRcdC5kYXRhKCBcInVpLXNsaWRlci1oYW5kbGUtaW5kZXhcIiwgaSApXG5cdFx0XHRcdC5hdHRyKCBcInRhYkluZGV4XCIsIDAgKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0X2NyZWF0ZVJhbmdlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblxuXHRcdGlmICggb3B0aW9ucy5yYW5nZSApIHtcblx0XHRcdGlmICggb3B0aW9ucy5yYW5nZSA9PT0gdHJ1ZSApIHtcblx0XHRcdFx0aWYgKCAhb3B0aW9ucy52YWx1ZXMgKSB7XG5cdFx0XHRcdFx0b3B0aW9ucy52YWx1ZXMgPSBbIHRoaXMuX3ZhbHVlTWluKCksIHRoaXMuX3ZhbHVlTWluKCkgXTtcblx0XHRcdFx0fSBlbHNlIGlmICggb3B0aW9ucy52YWx1ZXMubGVuZ3RoICYmIG9wdGlvbnMudmFsdWVzLmxlbmd0aCAhPT0gMiApIHtcblx0XHRcdFx0XHRvcHRpb25zLnZhbHVlcyA9IFsgb3B0aW9ucy52YWx1ZXNbIDAgXSwgb3B0aW9ucy52YWx1ZXNbIDAgXSBdO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCAkLmlzQXJyYXkoIG9wdGlvbnMudmFsdWVzICkgKSB7XG5cdFx0XHRcdFx0b3B0aW9ucy52YWx1ZXMgPSBvcHRpb25zLnZhbHVlcy5zbGljZSggMCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGlmICggIXRoaXMucmFuZ2UgfHwgIXRoaXMucmFuZ2UubGVuZ3RoICkge1xuXHRcdFx0XHR0aGlzLnJhbmdlID0gJCggXCI8ZGl2PlwiIClcblx0XHRcdFx0XHQuYXBwZW5kVG8oIHRoaXMuZWxlbWVudCApO1xuXG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnJhbmdlLCBcInVpLXNsaWRlci1yYW5nZVwiICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5yYW5nZSwgXCJ1aS1zbGlkZXItcmFuZ2UtbWluIHVpLXNsaWRlci1yYW5nZS1tYXhcIiApO1xuXG5cdFx0XHRcdC8vIEhhbmRsZSByYW5nZSBzd2l0Y2hpbmcgZnJvbSB0cnVlIHRvIG1pbi9tYXhcblx0XHRcdFx0dGhpcy5yYW5nZS5jc3MoIHtcblx0XHRcdFx0XHRcImxlZnRcIjogXCJcIixcblx0XHRcdFx0XHRcImJvdHRvbVwiOiBcIlwiXG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHRcdGlmICggb3B0aW9ucy5yYW5nZSA9PT0gXCJtaW5cIiB8fCBvcHRpb25zLnJhbmdlID09PSBcIm1heFwiICkge1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5yYW5nZSwgXCJ1aS1zbGlkZXItcmFuZ2UtXCIgKyBvcHRpb25zLnJhbmdlICk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGlmICggdGhpcy5yYW5nZSApIHtcblx0XHRcdFx0dGhpcy5yYW5nZS5yZW1vdmUoKTtcblx0XHRcdH1cblx0XHRcdHRoaXMucmFuZ2UgPSBudWxsO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0dXBFdmVudHM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX29mZiggdGhpcy5oYW5kbGVzICk7XG5cdFx0dGhpcy5fb24oIHRoaXMuaGFuZGxlcywgdGhpcy5faGFuZGxlRXZlbnRzICk7XG5cdFx0dGhpcy5faG92ZXJhYmxlKCB0aGlzLmhhbmRsZXMgKTtcblx0XHR0aGlzLl9mb2N1c2FibGUoIHRoaXMuaGFuZGxlcyApO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmhhbmRsZXMucmVtb3ZlKCk7XG5cdFx0aWYgKCB0aGlzLnJhbmdlICkge1xuXHRcdFx0dGhpcy5yYW5nZS5yZW1vdmUoKTtcblx0XHR9XG5cblx0XHR0aGlzLl9tb3VzZURlc3Ryb3koKTtcblx0fSxcblxuXHRfbW91c2VDYXB0dXJlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHBvc2l0aW9uLCBub3JtVmFsdWUsIGRpc3RhbmNlLCBjbG9zZXN0SGFuZGxlLCBpbmRleCwgYWxsb3dlZCwgb2Zmc2V0LCBtb3VzZU92ZXJIYW5kbGUsXG5cdFx0XHR0aGF0ID0gdGhpcyxcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnM7XG5cblx0XHRpZiAoIG8uZGlzYWJsZWQgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0dGhpcy5lbGVtZW50U2l6ZSA9IHtcblx0XHRcdHdpZHRoOiB0aGlzLmVsZW1lbnQub3V0ZXJXaWR0aCgpLFxuXHRcdFx0aGVpZ2h0OiB0aGlzLmVsZW1lbnQub3V0ZXJIZWlnaHQoKVxuXHRcdH07XG5cdFx0dGhpcy5lbGVtZW50T2Zmc2V0ID0gdGhpcy5lbGVtZW50Lm9mZnNldCgpO1xuXG5cdFx0cG9zaXRpb24gPSB7IHg6IGV2ZW50LnBhZ2VYLCB5OiBldmVudC5wYWdlWSB9O1xuXHRcdG5vcm1WYWx1ZSA9IHRoaXMuX25vcm1WYWx1ZUZyb21Nb3VzZSggcG9zaXRpb24gKTtcblx0XHRkaXN0YW5jZSA9IHRoaXMuX3ZhbHVlTWF4KCkgLSB0aGlzLl92YWx1ZU1pbigpICsgMTtcblx0XHR0aGlzLmhhbmRsZXMuZWFjaCggZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHR2YXIgdGhpc0Rpc3RhbmNlID0gTWF0aC5hYnMoIG5vcm1WYWx1ZSAtIHRoYXQudmFsdWVzKCBpICkgKTtcblx0XHRcdGlmICggKCBkaXN0YW5jZSA+IHRoaXNEaXN0YW5jZSApIHx8XG5cdFx0XHRcdCggZGlzdGFuY2UgPT09IHRoaXNEaXN0YW5jZSAmJlxuXHRcdFx0XHRcdCggaSA9PT0gdGhhdC5fbGFzdENoYW5nZWRWYWx1ZSB8fCB0aGF0LnZhbHVlcyggaSApID09PSBvLm1pbiApICkgKSB7XG5cdFx0XHRcdGRpc3RhbmNlID0gdGhpc0Rpc3RhbmNlO1xuXHRcdFx0XHRjbG9zZXN0SGFuZGxlID0gJCggdGhpcyApO1xuXHRcdFx0XHRpbmRleCA9IGk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0YWxsb3dlZCA9IHRoaXMuX3N0YXJ0KCBldmVudCwgaW5kZXggKTtcblx0XHRpZiAoIGFsbG93ZWQgPT09IGZhbHNlICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0XHR0aGlzLl9tb3VzZVNsaWRpbmcgPSB0cnVlO1xuXG5cdFx0dGhpcy5faGFuZGxlSW5kZXggPSBpbmRleDtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBjbG9zZXN0SGFuZGxlLCBudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0Y2xvc2VzdEhhbmRsZS50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblxuXHRcdG9mZnNldCA9IGNsb3Nlc3RIYW5kbGUub2Zmc2V0KCk7XG5cdFx0bW91c2VPdmVySGFuZGxlID0gISQoIGV2ZW50LnRhcmdldCApLnBhcmVudHMoKS5hZGRCYWNrKCkuaXMoIFwiLnVpLXNsaWRlci1oYW5kbGVcIiApO1xuXHRcdHRoaXMuX2NsaWNrT2Zmc2V0ID0gbW91c2VPdmVySGFuZGxlID8geyBsZWZ0OiAwLCB0b3A6IDAgfSA6IHtcblx0XHRcdGxlZnQ6IGV2ZW50LnBhZ2VYIC0gb2Zmc2V0LmxlZnQgLSAoIGNsb3Nlc3RIYW5kbGUud2lkdGgoKSAvIDIgKSxcblx0XHRcdHRvcDogZXZlbnQucGFnZVkgLSBvZmZzZXQudG9wIC1cblx0XHRcdFx0KCBjbG9zZXN0SGFuZGxlLmhlaWdodCgpIC8gMiApIC1cblx0XHRcdFx0KCBwYXJzZUludCggY2xvc2VzdEhhbmRsZS5jc3MoIFwiYm9yZGVyVG9wV2lkdGhcIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdCggcGFyc2VJbnQoIGNsb3Nlc3RIYW5kbGUuY3NzKCBcImJvcmRlckJvdHRvbVdpZHRoXCIgKSwgMTAgKSB8fCAwICkgK1xuXHRcdFx0XHQoIHBhcnNlSW50KCBjbG9zZXN0SGFuZGxlLmNzcyggXCJtYXJnaW5Ub3BcIiApLCAxMCApIHx8IDAgKVxuXHRcdH07XG5cblx0XHRpZiAoICF0aGlzLmhhbmRsZXMuaGFzQ2xhc3MoIFwidWktc3RhdGUtaG92ZXJcIiApICkge1xuXHRcdFx0dGhpcy5fc2xpZGUoIGV2ZW50LCBpbmRleCwgbm9ybVZhbHVlICk7XG5cdFx0fVxuXHRcdHRoaXMuX2FuaW1hdGVPZmYgPSB0cnVlO1xuXHRcdHJldHVybiB0cnVlO1xuXHR9LFxuXG5cdF9tb3VzZVN0YXJ0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHRfbW91c2VEcmFnOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHBvc2l0aW9uID0geyB4OiBldmVudC5wYWdlWCwgeTogZXZlbnQucGFnZVkgfSxcblx0XHRcdG5vcm1WYWx1ZSA9IHRoaXMuX25vcm1WYWx1ZUZyb21Nb3VzZSggcG9zaXRpb24gKTtcblxuXHRcdHRoaXMuX3NsaWRlKCBldmVudCwgdGhpcy5faGFuZGxlSW5kZXgsIG5vcm1WYWx1ZSApO1xuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXG5cdF9tb3VzZVN0b3A6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5oYW5kbGVzLCBudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0dGhpcy5fbW91c2VTbGlkaW5nID0gZmFsc2U7XG5cblx0XHR0aGlzLl9zdG9wKCBldmVudCwgdGhpcy5faGFuZGxlSW5kZXggKTtcblx0XHR0aGlzLl9jaGFuZ2UoIGV2ZW50LCB0aGlzLl9oYW5kbGVJbmRleCApO1xuXG5cdFx0dGhpcy5faGFuZGxlSW5kZXggPSBudWxsO1xuXHRcdHRoaXMuX2NsaWNrT2Zmc2V0ID0gbnVsbDtcblx0XHR0aGlzLl9hbmltYXRlT2ZmID0gZmFsc2U7XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0sXG5cblx0X2RldGVjdE9yaWVudGF0aW9uOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLm9yaWVudGF0aW9uID0gKCB0aGlzLm9wdGlvbnMub3JpZW50YXRpb24gPT09IFwidmVydGljYWxcIiApID8gXCJ2ZXJ0aWNhbFwiIDogXCJob3Jpem9udGFsXCI7XG5cdH0sXG5cblx0X25vcm1WYWx1ZUZyb21Nb3VzZTogZnVuY3Rpb24oIHBvc2l0aW9uICkge1xuXHRcdHZhciBwaXhlbFRvdGFsLFxuXHRcdFx0cGl4ZWxNb3VzZSxcblx0XHRcdHBlcmNlbnRNb3VzZSxcblx0XHRcdHZhbHVlVG90YWwsXG5cdFx0XHR2YWx1ZU1vdXNlO1xuXG5cdFx0aWYgKCB0aGlzLm9yaWVudGF0aW9uID09PSBcImhvcml6b250YWxcIiApIHtcblx0XHRcdHBpeGVsVG90YWwgPSB0aGlzLmVsZW1lbnRTaXplLndpZHRoO1xuXHRcdFx0cGl4ZWxNb3VzZSA9IHBvc2l0aW9uLnggLSB0aGlzLmVsZW1lbnRPZmZzZXQubGVmdCAtXG5cdFx0XHRcdCggdGhpcy5fY2xpY2tPZmZzZXQgPyB0aGlzLl9jbGlja09mZnNldC5sZWZ0IDogMCApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRwaXhlbFRvdGFsID0gdGhpcy5lbGVtZW50U2l6ZS5oZWlnaHQ7XG5cdFx0XHRwaXhlbE1vdXNlID0gcG9zaXRpb24ueSAtIHRoaXMuZWxlbWVudE9mZnNldC50b3AgLVxuXHRcdFx0XHQoIHRoaXMuX2NsaWNrT2Zmc2V0ID8gdGhpcy5fY2xpY2tPZmZzZXQudG9wIDogMCApO1xuXHRcdH1cblxuXHRcdHBlcmNlbnRNb3VzZSA9ICggcGl4ZWxNb3VzZSAvIHBpeGVsVG90YWwgKTtcblx0XHRpZiAoIHBlcmNlbnRNb3VzZSA+IDEgKSB7XG5cdFx0XHRwZXJjZW50TW91c2UgPSAxO1xuXHRcdH1cblx0XHRpZiAoIHBlcmNlbnRNb3VzZSA8IDAgKSB7XG5cdFx0XHRwZXJjZW50TW91c2UgPSAwO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMub3JpZW50YXRpb24gPT09IFwidmVydGljYWxcIiApIHtcblx0XHRcdHBlcmNlbnRNb3VzZSA9IDEgLSBwZXJjZW50TW91c2U7XG5cdFx0fVxuXG5cdFx0dmFsdWVUb3RhbCA9IHRoaXMuX3ZhbHVlTWF4KCkgLSB0aGlzLl92YWx1ZU1pbigpO1xuXHRcdHZhbHVlTW91c2UgPSB0aGlzLl92YWx1ZU1pbigpICsgcGVyY2VudE1vdXNlICogdmFsdWVUb3RhbDtcblxuXHRcdHJldHVybiB0aGlzLl90cmltQWxpZ25WYWx1ZSggdmFsdWVNb3VzZSApO1xuXHR9LFxuXG5cdF91aUhhc2g6IGZ1bmN0aW9uKCBpbmRleCwgdmFsdWUsIHZhbHVlcyApIHtcblx0XHR2YXIgdWlIYXNoID0ge1xuXHRcdFx0aGFuZGxlOiB0aGlzLmhhbmRsZXNbIGluZGV4IF0sXG5cdFx0XHRoYW5kbGVJbmRleDogaW5kZXgsXG5cdFx0XHR2YWx1ZTogdmFsdWUgIT09IHVuZGVmaW5lZCA/IHZhbHVlIDogdGhpcy52YWx1ZSgpXG5cdFx0fTtcblxuXHRcdGlmICggdGhpcy5faGFzTXVsdGlwbGVWYWx1ZXMoKSApIHtcblx0XHRcdHVpSGFzaC52YWx1ZSA9IHZhbHVlICE9PSB1bmRlZmluZWQgPyB2YWx1ZSA6IHRoaXMudmFsdWVzKCBpbmRleCApO1xuXHRcdFx0dWlIYXNoLnZhbHVlcyA9IHZhbHVlcyB8fCB0aGlzLnZhbHVlcygpO1xuXHRcdH1cblxuXHRcdHJldHVybiB1aUhhc2g7XG5cdH0sXG5cblx0X2hhc011bHRpcGxlVmFsdWVzOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLnZhbHVlcyAmJiB0aGlzLm9wdGlvbnMudmFsdWVzLmxlbmd0aDtcblx0fSxcblxuXHRfc3RhcnQ6IGZ1bmN0aW9uKCBldmVudCwgaW5kZXggKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3RyaWdnZXIoIFwic3RhcnRcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggaW5kZXggKSApO1xuXHR9LFxuXG5cdF9zbGlkZTogZnVuY3Rpb24oIGV2ZW50LCBpbmRleCwgbmV3VmFsICkge1xuXHRcdHZhciBhbGxvd2VkLCBvdGhlclZhbCxcblx0XHRcdGN1cnJlbnRWYWx1ZSA9IHRoaXMudmFsdWUoKSxcblx0XHRcdG5ld1ZhbHVlcyA9IHRoaXMudmFsdWVzKCk7XG5cblx0XHRpZiAoIHRoaXMuX2hhc011bHRpcGxlVmFsdWVzKCkgKSB7XG5cdFx0XHRvdGhlclZhbCA9IHRoaXMudmFsdWVzKCBpbmRleCA/IDAgOiAxICk7XG5cdFx0XHRjdXJyZW50VmFsdWUgPSB0aGlzLnZhbHVlcyggaW5kZXggKTtcblxuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMudmFsdWVzLmxlbmd0aCA9PT0gMiAmJiB0aGlzLm9wdGlvbnMucmFuZ2UgPT09IHRydWUgKSB7XG5cdFx0XHRcdG5ld1ZhbCA9ICBpbmRleCA9PT0gMCA/IE1hdGgubWluKCBvdGhlclZhbCwgbmV3VmFsICkgOiBNYXRoLm1heCggb3RoZXJWYWwsIG5ld1ZhbCApO1xuXHRcdFx0fVxuXG5cdFx0XHRuZXdWYWx1ZXNbIGluZGV4IF0gPSBuZXdWYWw7XG5cdFx0fVxuXG5cdFx0aWYgKCBuZXdWYWwgPT09IGN1cnJlbnRWYWx1ZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRhbGxvd2VkID0gdGhpcy5fdHJpZ2dlciggXCJzbGlkZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCBpbmRleCwgbmV3VmFsLCBuZXdWYWx1ZXMgKSApO1xuXG5cdFx0Ly8gQSBzbGlkZSBjYW4gYmUgY2FuY2VsZWQgYnkgcmV0dXJuaW5nIGZhbHNlIGZyb20gdGhlIHNsaWRlIGNhbGxiYWNrXG5cdFx0aWYgKCBhbGxvd2VkID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX2hhc011bHRpcGxlVmFsdWVzKCkgKSB7XG5cdFx0XHR0aGlzLnZhbHVlcyggaW5kZXgsIG5ld1ZhbCApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLnZhbHVlKCBuZXdWYWwgKTtcblx0XHR9XG5cdH0sXG5cblx0X3N0b3A6IGZ1bmN0aW9uKCBldmVudCwgaW5kZXggKSB7XG5cdFx0dGhpcy5fdHJpZ2dlciggXCJzdG9wXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIGluZGV4ICkgKTtcblx0fSxcblxuXHRfY2hhbmdlOiBmdW5jdGlvbiggZXZlbnQsIGluZGV4ICkge1xuXHRcdGlmICggIXRoaXMuX2tleVNsaWRpbmcgJiYgIXRoaXMuX21vdXNlU2xpZGluZyApIHtcblxuXHRcdFx0Ly9zdG9yZSB0aGUgbGFzdCBjaGFuZ2VkIHZhbHVlIGluZGV4IGZvciByZWZlcmVuY2Ugd2hlbiBoYW5kbGVzIG92ZXJsYXBcblx0XHRcdHRoaXMuX2xhc3RDaGFuZ2VkVmFsdWUgPSBpbmRleDtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY2hhbmdlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIGluZGV4ICkgKTtcblx0XHR9XG5cdH0sXG5cblx0dmFsdWU6IGZ1bmN0aW9uKCBuZXdWYWx1ZSApIHtcblx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMudmFsdWUgPSB0aGlzLl90cmltQWxpZ25WYWx1ZSggbmV3VmFsdWUgKTtcblx0XHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHRcdFx0dGhpcy5fY2hhbmdlKCBudWxsLCAwICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuX3ZhbHVlKCk7XG5cdH0sXG5cblx0dmFsdWVzOiBmdW5jdGlvbiggaW5kZXgsIG5ld1ZhbHVlICkge1xuXHRcdHZhciB2YWxzLFxuXHRcdFx0bmV3VmFsdWVzLFxuXHRcdFx0aTtcblxuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCA+IDEgKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMudmFsdWVzWyBpbmRleCBdID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoIG5ld1ZhbHVlICk7XG5cdFx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0XHRcdHRoaXMuX2NoYW5nZSggbnVsbCwgaW5kZXggKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggKSB7XG5cdFx0XHRpZiAoICQuaXNBcnJheSggYXJndW1lbnRzWyAwIF0gKSApIHtcblx0XHRcdFx0dmFscyA9IHRoaXMub3B0aW9ucy52YWx1ZXM7XG5cdFx0XHRcdG5ld1ZhbHVlcyA9IGFyZ3VtZW50c1sgMCBdO1xuXHRcdFx0XHRmb3IgKCBpID0gMDsgaSA8IHZhbHMubGVuZ3RoOyBpICs9IDEgKSB7XG5cdFx0XHRcdFx0dmFsc1sgaSBdID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoIG5ld1ZhbHVlc1sgaSBdICk7XG5cdFx0XHRcdFx0dGhpcy5fY2hhbmdlKCBudWxsLCBpICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpZiAoIHRoaXMuX2hhc011bHRpcGxlVmFsdWVzKCkgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuX3ZhbHVlcyggaW5kZXggKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy52YWx1ZSgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJldHVybiB0aGlzLl92YWx1ZXMoKTtcblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dmFyIGksXG5cdFx0XHR2YWxzTGVuZ3RoID0gMDtcblxuXHRcdGlmICgga2V5ID09PSBcInJhbmdlXCIgJiYgdGhpcy5vcHRpb25zLnJhbmdlID09PSB0cnVlICkge1xuXHRcdFx0aWYgKCB2YWx1ZSA9PT0gXCJtaW5cIiApIHtcblx0XHRcdFx0dGhpcy5vcHRpb25zLnZhbHVlID0gdGhpcy5fdmFsdWVzKCAwICk7XG5cdFx0XHRcdHRoaXMub3B0aW9ucy52YWx1ZXMgPSBudWxsO1xuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgPT09IFwibWF4XCIgKSB7XG5cdFx0XHRcdHRoaXMub3B0aW9ucy52YWx1ZSA9IHRoaXMuX3ZhbHVlcyggdGhpcy5vcHRpb25zLnZhbHVlcy5sZW5ndGggLSAxICk7XG5cdFx0XHRcdHRoaXMub3B0aW9ucy52YWx1ZXMgPSBudWxsO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggJC5pc0FycmF5KCB0aGlzLm9wdGlvbnMudmFsdWVzICkgKSB7XG5cdFx0XHR2YWxzTGVuZ3RoID0gdGhpcy5vcHRpb25zLnZhbHVlcy5sZW5ndGg7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdHN3aXRjaCAoIGtleSApIHtcblx0XHRcdGNhc2UgXCJvcmllbnRhdGlvblwiOlxuXHRcdFx0XHR0aGlzLl9kZXRlY3RPcmllbnRhdGlvbigpO1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggXCJ1aS1zbGlkZXItaG9yaXpvbnRhbCB1aS1zbGlkZXItdmVydGljYWxcIiApXG5cdFx0XHRcdFx0Ll9hZGRDbGFzcyggXCJ1aS1zbGlkZXItXCIgKyB0aGlzLm9yaWVudGF0aW9uICk7XG5cdFx0XHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHRcdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5yYW5nZSApIHtcblx0XHRcdFx0XHR0aGlzLl9yZWZyZXNoUmFuZ2UoIHZhbHVlICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBSZXNldCBwb3NpdGlvbmluZyBmcm9tIHByZXZpb3VzIG9yaWVudGF0aW9uXG5cdFx0XHRcdHRoaXMuaGFuZGxlcy5jc3MoIHZhbHVlID09PSBcImhvcml6b250YWxcIiA/IFwiYm90dG9tXCIgOiBcImxlZnRcIiwgXCJcIiApO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgXCJ2YWx1ZVwiOlxuXHRcdFx0XHR0aGlzLl9hbmltYXRlT2ZmID0gdHJ1ZTtcblx0XHRcdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdFx0XHRcdHRoaXMuX2NoYW5nZSggbnVsbCwgMCApO1xuXHRcdFx0XHR0aGlzLl9hbmltYXRlT2ZmID0gZmFsc2U7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSBcInZhbHVlc1wiOlxuXHRcdFx0XHR0aGlzLl9hbmltYXRlT2ZmID0gdHJ1ZTtcblx0XHRcdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cblx0XHRcdFx0Ly8gU3RhcnQgZnJvbSB0aGUgbGFzdCBoYW5kbGUgdG8gcHJldmVudCB1bnJlYWNoYWJsZSBoYW5kbGVzICgjOTA0Nilcblx0XHRcdFx0Zm9yICggaSA9IHZhbHNMZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdFx0XHR0aGlzLl9jaGFuZ2UoIG51bGwsIGkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGlzLl9hbmltYXRlT2ZmID0gZmFsc2U7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSBcInN0ZXBcIjpcblx0XHRcdGNhc2UgXCJtaW5cIjpcblx0XHRcdGNhc2UgXCJtYXhcIjpcblx0XHRcdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IHRydWU7XG5cdFx0XHRcdHRoaXMuX2NhbGN1bGF0ZU5ld01heCgpO1xuXHRcdFx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0XHRcdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IGZhbHNlO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgXCJyYW5nZVwiOlxuXHRcdFx0XHR0aGlzLl9hbmltYXRlT2ZmID0gdHJ1ZTtcblx0XHRcdFx0dGhpcy5fcmVmcmVzaCgpO1xuXHRcdFx0XHR0aGlzLl9hbmltYXRlT2ZmID0gZmFsc2U7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uRGlzYWJsZWQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlciggdmFsdWUgKTtcblxuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIsICEhdmFsdWUgKTtcblx0fSxcblxuXHQvL2ludGVybmFsIHZhbHVlIGdldHRlclxuXHQvLyBfdmFsdWUoKSByZXR1cm5zIHZhbHVlIHRyaW1tZWQgYnkgbWluIGFuZCBtYXgsIGFsaWduZWQgYnkgc3RlcFxuXHRfdmFsdWU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB2YWwgPSB0aGlzLm9wdGlvbnMudmFsdWU7XG5cdFx0dmFsID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoIHZhbCApO1xuXG5cdFx0cmV0dXJuIHZhbDtcblx0fSxcblxuXHQvL2ludGVybmFsIHZhbHVlcyBnZXR0ZXJcblx0Ly8gX3ZhbHVlcygpIHJldHVybnMgYXJyYXkgb2YgdmFsdWVzIHRyaW1tZWQgYnkgbWluIGFuZCBtYXgsIGFsaWduZWQgYnkgc3RlcFxuXHQvLyBfdmFsdWVzKCBpbmRleCApIHJldHVybnMgc2luZ2xlIHZhbHVlIHRyaW1tZWQgYnkgbWluIGFuZCBtYXgsIGFsaWduZWQgYnkgc3RlcFxuXHRfdmFsdWVzOiBmdW5jdGlvbiggaW5kZXggKSB7XG5cdFx0dmFyIHZhbCxcblx0XHRcdHZhbHMsXG5cdFx0XHRpO1xuXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoICkge1xuXHRcdFx0dmFsID0gdGhpcy5vcHRpb25zLnZhbHVlc1sgaW5kZXggXTtcblx0XHRcdHZhbCA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKCB2YWwgKTtcblxuXHRcdFx0cmV0dXJuIHZhbDtcblx0XHR9IGVsc2UgaWYgKCB0aGlzLl9oYXNNdWx0aXBsZVZhbHVlcygpICkge1xuXG5cdFx0XHQvLyAuc2xpY2UoKSBjcmVhdGVzIGEgY29weSBvZiB0aGUgYXJyYXlcblx0XHRcdC8vIHRoaXMgY29weSBnZXRzIHRyaW1tZWQgYnkgbWluIGFuZCBtYXggYW5kIHRoZW4gcmV0dXJuZWRcblx0XHRcdHZhbHMgPSB0aGlzLm9wdGlvbnMudmFsdWVzLnNsaWNlKCk7XG5cdFx0XHRmb3IgKCBpID0gMDsgaSA8IHZhbHMubGVuZ3RoOyBpICs9IDEgKSB7XG5cdFx0XHRcdHZhbHNbIGkgXSA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKCB2YWxzWyBpIF0gKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHZhbHM7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJldHVybiBbXTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gUmV0dXJucyB0aGUgc3RlcC1hbGlnbmVkIHZhbHVlIHRoYXQgdmFsIGlzIGNsb3Nlc3QgdG8sIGJldHdlZW4gKGluY2x1c2l2ZSkgbWluIGFuZCBtYXhcblx0X3RyaW1BbGlnblZhbHVlOiBmdW5jdGlvbiggdmFsICkge1xuXHRcdGlmICggdmFsIDw9IHRoaXMuX3ZhbHVlTWluKCkgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5fdmFsdWVNaW4oKTtcblx0XHR9XG5cdFx0aWYgKCB2YWwgPj0gdGhpcy5fdmFsdWVNYXgoKSApIHtcblx0XHRcdHJldHVybiB0aGlzLl92YWx1ZU1heCgpO1xuXHRcdH1cblx0XHR2YXIgc3RlcCA9ICggdGhpcy5vcHRpb25zLnN0ZXAgPiAwICkgPyB0aGlzLm9wdGlvbnMuc3RlcCA6IDEsXG5cdFx0XHR2YWxNb2RTdGVwID0gKCB2YWwgLSB0aGlzLl92YWx1ZU1pbigpICkgJSBzdGVwLFxuXHRcdFx0YWxpZ25WYWx1ZSA9IHZhbCAtIHZhbE1vZFN0ZXA7XG5cblx0XHRpZiAoIE1hdGguYWJzKCB2YWxNb2RTdGVwICkgKiAyID49IHN0ZXAgKSB7XG5cdFx0XHRhbGlnblZhbHVlICs9ICggdmFsTW9kU3RlcCA+IDAgKSA/IHN0ZXAgOiAoIC1zdGVwICk7XG5cdFx0fVxuXG5cdFx0Ly8gU2luY2UgSmF2YVNjcmlwdCBoYXMgcHJvYmxlbXMgd2l0aCBsYXJnZSBmbG9hdHMsIHJvdW5kXG5cdFx0Ly8gdGhlIGZpbmFsIHZhbHVlIHRvIDUgZGlnaXRzIGFmdGVyIHRoZSBkZWNpbWFsIHBvaW50IChzZWUgIzQxMjQpXG5cdFx0cmV0dXJuIHBhcnNlRmxvYXQoIGFsaWduVmFsdWUudG9GaXhlZCggNSApICk7XG5cdH0sXG5cblx0X2NhbGN1bGF0ZU5ld01heDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG1heCA9IHRoaXMub3B0aW9ucy5tYXgsXG5cdFx0XHRtaW4gPSB0aGlzLl92YWx1ZU1pbigpLFxuXHRcdFx0c3RlcCA9IHRoaXMub3B0aW9ucy5zdGVwLFxuXHRcdFx0YWJvdmVNaW4gPSBNYXRoLnJvdW5kKCAoIG1heCAtIG1pbiApIC8gc3RlcCApICogc3RlcDtcblx0XHRtYXggPSBhYm92ZU1pbiArIG1pbjtcblx0XHRpZiAoIG1heCA+IHRoaXMub3B0aW9ucy5tYXggKSB7XG5cblx0XHRcdC8vSWYgbWF4IGlzIG5vdCBkaXZpc2libGUgYnkgc3RlcCwgcm91bmRpbmcgb2ZmIG1heSBpbmNyZWFzZSBpdHMgdmFsdWVcblx0XHRcdG1heCAtPSBzdGVwO1xuXHRcdH1cblx0XHR0aGlzLm1heCA9IHBhcnNlRmxvYXQoIG1heC50b0ZpeGVkKCB0aGlzLl9wcmVjaXNpb24oKSApICk7XG5cdH0sXG5cblx0X3ByZWNpc2lvbjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHByZWNpc2lvbiA9IHRoaXMuX3ByZWNpc2lvbk9mKCB0aGlzLm9wdGlvbnMuc3RlcCApO1xuXHRcdGlmICggdGhpcy5vcHRpb25zLm1pbiAhPT0gbnVsbCApIHtcblx0XHRcdHByZWNpc2lvbiA9IE1hdGgubWF4KCBwcmVjaXNpb24sIHRoaXMuX3ByZWNpc2lvbk9mKCB0aGlzLm9wdGlvbnMubWluICkgKTtcblx0XHR9XG5cdFx0cmV0dXJuIHByZWNpc2lvbjtcblx0fSxcblxuXHRfcHJlY2lzaW9uT2Y6IGZ1bmN0aW9uKCBudW0gKSB7XG5cdFx0dmFyIHN0ciA9IG51bS50b1N0cmluZygpLFxuXHRcdFx0ZGVjaW1hbCA9IHN0ci5pbmRleE9mKCBcIi5cIiApO1xuXHRcdHJldHVybiBkZWNpbWFsID09PSAtMSA/IDAgOiBzdHIubGVuZ3RoIC0gZGVjaW1hbCAtIDE7XG5cdH0sXG5cblx0X3ZhbHVlTWluOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLm1pbjtcblx0fSxcblxuXHRfdmFsdWVNYXg6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLm1heDtcblx0fSxcblxuXHRfcmVmcmVzaFJhbmdlOiBmdW5jdGlvbiggb3JpZW50YXRpb24gKSB7XG5cdFx0aWYgKCBvcmllbnRhdGlvbiA9PT0gXCJ2ZXJ0aWNhbFwiICkge1xuXHRcdFx0dGhpcy5yYW5nZS5jc3MoIHsgXCJ3aWR0aFwiOiBcIlwiLCBcImxlZnRcIjogXCJcIiB9ICk7XG5cdFx0fVxuXHRcdGlmICggb3JpZW50YXRpb24gPT09IFwiaG9yaXpvbnRhbFwiICkge1xuXHRcdFx0dGhpcy5yYW5nZS5jc3MoIHsgXCJoZWlnaHRcIjogXCJcIiwgXCJib3R0b21cIjogXCJcIiB9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZWZyZXNoVmFsdWU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBsYXN0VmFsUGVyY2VudCwgdmFsUGVyY2VudCwgdmFsdWUsIHZhbHVlTWluLCB2YWx1ZU1heCxcblx0XHRcdG9SYW5nZSA9IHRoaXMub3B0aW9ucy5yYW5nZSxcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHR0aGF0ID0gdGhpcyxcblx0XHRcdGFuaW1hdGUgPSAoICF0aGlzLl9hbmltYXRlT2ZmICkgPyBvLmFuaW1hdGUgOiBmYWxzZSxcblx0XHRcdF9zZXQgPSB7fTtcblxuXHRcdGlmICggdGhpcy5faGFzTXVsdGlwbGVWYWx1ZXMoKSApIHtcblx0XHRcdHRoaXMuaGFuZGxlcy5lYWNoKCBmdW5jdGlvbiggaSApIHtcblx0XHRcdFx0dmFsUGVyY2VudCA9ICggdGhhdC52YWx1ZXMoIGkgKSAtIHRoYXQuX3ZhbHVlTWluKCkgKSAvICggdGhhdC5fdmFsdWVNYXgoKSAtXG5cdFx0XHRcdFx0dGhhdC5fdmFsdWVNaW4oKSApICogMTAwO1xuXHRcdFx0XHRfc2V0WyB0aGF0Lm9yaWVudGF0aW9uID09PSBcImhvcml6b250YWxcIiA/IFwibGVmdFwiIDogXCJib3R0b21cIiBdID0gdmFsUGVyY2VudCArIFwiJVwiO1xuXHRcdFx0XHQkKCB0aGlzICkuc3RvcCggMSwgMSApWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIF9zZXQsIG8uYW5pbWF0ZSApO1xuXHRcdFx0XHRpZiAoIHRoYXQub3B0aW9ucy5yYW5nZSA9PT0gdHJ1ZSApIHtcblx0XHRcdFx0XHRpZiAoIHRoYXQub3JpZW50YXRpb24gPT09IFwiaG9yaXpvbnRhbFwiICkge1xuXHRcdFx0XHRcdFx0aWYgKCBpID09PSAwICkge1xuXHRcdFx0XHRcdFx0XHR0aGF0LnJhbmdlLnN0b3AoIDEsIDEgKVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCB7XG5cdFx0XHRcdFx0XHRcdFx0bGVmdDogdmFsUGVyY2VudCArIFwiJVwiXG5cdFx0XHRcdFx0XHRcdH0sIG8uYW5pbWF0ZSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0aWYgKCBpID09PSAxICkge1xuXHRcdFx0XHRcdFx0XHR0aGF0LnJhbmdlWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIHtcblx0XHRcdFx0XHRcdFx0XHR3aWR0aDogKCB2YWxQZXJjZW50IC0gbGFzdFZhbFBlcmNlbnQgKSArIFwiJVwiXG5cdFx0XHRcdFx0XHRcdH0sIHtcblx0XHRcdFx0XHRcdFx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0XHRcdFx0XHRcdFx0ZHVyYXRpb246IG8uYW5pbWF0ZVxuXHRcdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdGlmICggaSA9PT0gMCApIHtcblx0XHRcdFx0XHRcdFx0dGhhdC5yYW5nZS5zdG9wKCAxLCAxIClbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSgge1xuXHRcdFx0XHRcdFx0XHRcdGJvdHRvbTogKCB2YWxQZXJjZW50ICkgKyBcIiVcIlxuXHRcdFx0XHRcdFx0XHR9LCBvLmFuaW1hdGUgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmICggaSA9PT0gMSApIHtcblx0XHRcdFx0XHRcdFx0dGhhdC5yYW5nZVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCB7XG5cdFx0XHRcdFx0XHRcdFx0aGVpZ2h0OiAoIHZhbFBlcmNlbnQgLSBsYXN0VmFsUGVyY2VudCApICsgXCIlXCJcblx0XHRcdFx0XHRcdFx0fSwge1xuXHRcdFx0XHRcdFx0XHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRcdFx0XHRcdFx0XHRkdXJhdGlvbjogby5hbmltYXRlXG5cdFx0XHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0bGFzdFZhbFBlcmNlbnQgPSB2YWxQZXJjZW50O1xuXHRcdFx0fSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR2YWx1ZSA9IHRoaXMudmFsdWUoKTtcblx0XHRcdHZhbHVlTWluID0gdGhpcy5fdmFsdWVNaW4oKTtcblx0XHRcdHZhbHVlTWF4ID0gdGhpcy5fdmFsdWVNYXgoKTtcblx0XHRcdHZhbFBlcmNlbnQgPSAoIHZhbHVlTWF4ICE9PSB2YWx1ZU1pbiApID9cblx0XHRcdFx0XHQoIHZhbHVlIC0gdmFsdWVNaW4gKSAvICggdmFsdWVNYXggLSB2YWx1ZU1pbiApICogMTAwIDpcblx0XHRcdFx0XHQwO1xuXHRcdFx0X3NldFsgdGhpcy5vcmllbnRhdGlvbiA9PT0gXCJob3Jpem9udGFsXCIgPyBcImxlZnRcIiA6IFwiYm90dG9tXCIgXSA9IHZhbFBlcmNlbnQgKyBcIiVcIjtcblx0XHRcdHRoaXMuaGFuZGxlLnN0b3AoIDEsIDEgKVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCBfc2V0LCBvLmFuaW1hdGUgKTtcblxuXHRcdFx0aWYgKCBvUmFuZ2UgPT09IFwibWluXCIgJiYgdGhpcy5vcmllbnRhdGlvbiA9PT0gXCJob3Jpem9udGFsXCIgKSB7XG5cdFx0XHRcdHRoaXMucmFuZ2Uuc3RvcCggMSwgMSApWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIHtcblx0XHRcdFx0XHR3aWR0aDogdmFsUGVyY2VudCArIFwiJVwiXG5cdFx0XHRcdH0sIG8uYW5pbWF0ZSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBvUmFuZ2UgPT09IFwibWF4XCIgJiYgdGhpcy5vcmllbnRhdGlvbiA9PT0gXCJob3Jpem9udGFsXCIgKSB7XG5cdFx0XHRcdHRoaXMucmFuZ2Uuc3RvcCggMSwgMSApWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIHtcblx0XHRcdFx0XHR3aWR0aDogKCAxMDAgLSB2YWxQZXJjZW50ICkgKyBcIiVcIlxuXHRcdFx0XHR9LCBvLmFuaW1hdGUgKTtcblx0XHRcdH1cblx0XHRcdGlmICggb1JhbmdlID09PSBcIm1pblwiICYmIHRoaXMub3JpZW50YXRpb24gPT09IFwidmVydGljYWxcIiApIHtcblx0XHRcdFx0dGhpcy5yYW5nZS5zdG9wKCAxLCAxIClbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSgge1xuXHRcdFx0XHRcdGhlaWdodDogdmFsUGVyY2VudCArIFwiJVwiXG5cdFx0XHRcdH0sIG8uYW5pbWF0ZSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBvUmFuZ2UgPT09IFwibWF4XCIgJiYgdGhpcy5vcmllbnRhdGlvbiA9PT0gXCJ2ZXJ0aWNhbFwiICkge1xuXHRcdFx0XHR0aGlzLnJhbmdlLnN0b3AoIDEsIDEgKVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCB7XG5cdFx0XHRcdFx0aGVpZ2h0OiAoIDEwMCAtIHZhbFBlcmNlbnQgKSArIFwiJVwiXG5cdFx0XHRcdH0sIG8uYW5pbWF0ZSApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRfaGFuZGxlRXZlbnRzOiB7XG5cdFx0a2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0dmFyIGFsbG93ZWQsIGN1clZhbCwgbmV3VmFsLCBzdGVwLFxuXHRcdFx0XHRpbmRleCA9ICQoIGV2ZW50LnRhcmdldCApLmRhdGEoIFwidWktc2xpZGVyLWhhbmRsZS1pbmRleFwiICk7XG5cblx0XHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkhPTUU6XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkVORDpcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuUEFHRV9VUDpcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuUEFHRV9ET1dOOlxuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5VUDpcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuUklHSFQ6XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkRPV046XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkxFRlQ6XG5cdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHRpZiAoICF0aGlzLl9rZXlTbGlkaW5nICkge1xuXHRcdFx0XHRcdFx0dGhpcy5fa2V5U2xpZGluZyA9IHRydWU7XG5cdFx0XHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggJCggZXZlbnQudGFyZ2V0ICksIG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdFx0XHRcdGFsbG93ZWQgPSB0aGlzLl9zdGFydCggZXZlbnQsIGluZGV4ICk7XG5cdFx0XHRcdFx0XHRpZiAoIGFsbG93ZWQgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXG5cdFx0XHRzdGVwID0gdGhpcy5vcHRpb25zLnN0ZXA7XG5cdFx0XHRpZiAoIHRoaXMuX2hhc011bHRpcGxlVmFsdWVzKCkgKSB7XG5cdFx0XHRcdGN1clZhbCA9IG5ld1ZhbCA9IHRoaXMudmFsdWVzKCBpbmRleCApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y3VyVmFsID0gbmV3VmFsID0gdGhpcy52YWx1ZSgpO1xuXHRcdFx0fVxuXG5cdFx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5IT01FOlxuXHRcdFx0XHRcdG5ld1ZhbCA9IHRoaXMuX3ZhbHVlTWluKCk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkVORDpcblx0XHRcdFx0XHRuZXdWYWwgPSB0aGlzLl92YWx1ZU1heCgpO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5QQUdFX1VQOlxuXHRcdFx0XHRcdG5ld1ZhbCA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKFxuXHRcdFx0XHRcdFx0Y3VyVmFsICsgKCAoIHRoaXMuX3ZhbHVlTWF4KCkgLSB0aGlzLl92YWx1ZU1pbigpICkgLyB0aGlzLm51bVBhZ2VzIClcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5QQUdFX0RPV046XG5cdFx0XHRcdFx0bmV3VmFsID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoXG5cdFx0XHRcdFx0XHRjdXJWYWwgLSAoICggdGhpcy5fdmFsdWVNYXgoKSAtIHRoaXMuX3ZhbHVlTWluKCkgKSAvIHRoaXMubnVtUGFnZXMgKSApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5VUDpcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuUklHSFQ6XG5cdFx0XHRcdFx0aWYgKCBjdXJWYWwgPT09IHRoaXMuX3ZhbHVlTWF4KCkgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdG5ld1ZhbCA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKCBjdXJWYWwgKyBzdGVwICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkRPV046XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkxFRlQ6XG5cdFx0XHRcdFx0aWYgKCBjdXJWYWwgPT09IHRoaXMuX3ZhbHVlTWluKCkgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdG5ld1ZhbCA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKCBjdXJWYWwgLSBzdGVwICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX3NsaWRlKCBldmVudCwgaW5kZXgsIG5ld1ZhbCApO1xuXHRcdH0sXG5cdFx0a2V5dXA6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHZhciBpbmRleCA9ICQoIGV2ZW50LnRhcmdldCApLmRhdGEoIFwidWktc2xpZGVyLWhhbmRsZS1pbmRleFwiICk7XG5cblx0XHRcdGlmICggdGhpcy5fa2V5U2xpZGluZyApIHtcblx0XHRcdFx0dGhpcy5fa2V5U2xpZGluZyA9IGZhbHNlO1xuXHRcdFx0XHR0aGlzLl9zdG9wKCBldmVudCwgaW5kZXggKTtcblx0XHRcdFx0dGhpcy5fY2hhbmdlKCBldmVudCwgaW5kZXggKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoICQoIGV2ZW50LnRhcmdldCApLCBudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgU29ydGFibGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFNvcnRhYmxlXG4vLz4+Z3JvdXA6IEludGVyYWN0aW9uc1xuLy8+PmRlc2NyaXB0aW9uOiBFbmFibGVzIGl0ZW1zIGluIGEgbGlzdCB0byBiZSBzb3J0ZWQgdXNpbmcgdGhlIG1vdXNlLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3NvcnRhYmxlL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3NvcnRhYmxlL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL3NvcnRhYmxlLmNzc1xuXG5cblxudmFyIHdpZGdldHNTb3J0YWJsZSA9ICQud2lkZ2V0KCBcInVpLnNvcnRhYmxlXCIsICQudWkubW91c2UsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0d2lkZ2V0RXZlbnRQcmVmaXg6IFwic29ydFwiLFxuXHRyZWFkeTogZmFsc2UsXG5cdG9wdGlvbnM6IHtcblx0XHRhcHBlbmRUbzogXCJwYXJlbnRcIixcblx0XHRheGlzOiBmYWxzZSxcblx0XHRjb25uZWN0V2l0aDogZmFsc2UsXG5cdFx0Y29udGFpbm1lbnQ6IGZhbHNlLFxuXHRcdGN1cnNvcjogXCJhdXRvXCIsXG5cdFx0Y3Vyc29yQXQ6IGZhbHNlLFxuXHRcdGRyb3BPbkVtcHR5OiB0cnVlLFxuXHRcdGZvcmNlUGxhY2Vob2xkZXJTaXplOiBmYWxzZSxcblx0XHRmb3JjZUhlbHBlclNpemU6IGZhbHNlLFxuXHRcdGdyaWQ6IGZhbHNlLFxuXHRcdGhhbmRsZTogZmFsc2UsXG5cdFx0aGVscGVyOiBcIm9yaWdpbmFsXCIsXG5cdFx0aXRlbXM6IFwiPiAqXCIsXG5cdFx0b3BhY2l0eTogZmFsc2UsXG5cdFx0cGxhY2Vob2xkZXI6IGZhbHNlLFxuXHRcdHJldmVydDogZmFsc2UsXG5cdFx0c2Nyb2xsOiB0cnVlLFxuXHRcdHNjcm9sbFNlbnNpdGl2aXR5OiAyMCxcblx0XHRzY3JvbGxTcGVlZDogMjAsXG5cdFx0c2NvcGU6IFwiZGVmYXVsdFwiLFxuXHRcdHRvbGVyYW5jZTogXCJpbnRlcnNlY3RcIixcblx0XHR6SW5kZXg6IDEwMDAsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRhY3RpdmF0ZTogbnVsbCxcblx0XHRiZWZvcmVTdG9wOiBudWxsLFxuXHRcdGNoYW5nZTogbnVsbCxcblx0XHRkZWFjdGl2YXRlOiBudWxsLFxuXHRcdG91dDogbnVsbCxcblx0XHRvdmVyOiBudWxsLFxuXHRcdHJlY2VpdmU6IG51bGwsXG5cdFx0cmVtb3ZlOiBudWxsLFxuXHRcdHNvcnQ6IG51bGwsXG5cdFx0c3RhcnQ6IG51bGwsXG5cdFx0c3RvcDogbnVsbCxcblx0XHR1cGRhdGU6IG51bGxcblx0fSxcblxuXHRfaXNPdmVyQXhpczogZnVuY3Rpb24oIHgsIHJlZmVyZW5jZSwgc2l6ZSApIHtcblx0XHRyZXR1cm4gKCB4ID49IHJlZmVyZW5jZSApICYmICggeCA8ICggcmVmZXJlbmNlICsgc2l6ZSApICk7XG5cdH0sXG5cblx0X2lzRmxvYXRpbmc6IGZ1bmN0aW9uKCBpdGVtICkge1xuXHRcdHJldHVybiAoIC9sZWZ0fHJpZ2h0LyApLnRlc3QoIGl0ZW0uY3NzKCBcImZsb2F0XCIgKSApIHx8XG5cdFx0XHQoIC9pbmxpbmV8dGFibGUtY2VsbC8gKS50ZXN0KCBpdGVtLmNzcyggXCJkaXNwbGF5XCIgKSApO1xuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuY29udGFpbmVyQ2FjaGUgPSB7fTtcblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1zb3J0YWJsZVwiICk7XG5cblx0XHQvL0dldCB0aGUgaXRlbXNcblx0XHR0aGlzLnJlZnJlc2goKTtcblxuXHRcdC8vTGV0J3MgZGV0ZXJtaW5lIHRoZSBwYXJlbnQncyBvZmZzZXRcblx0XHR0aGlzLm9mZnNldCA9IHRoaXMuZWxlbWVudC5vZmZzZXQoKTtcblxuXHRcdC8vSW5pdGlhbGl6ZSBtb3VzZSBldmVudHMgZm9yIGludGVyYWN0aW9uXG5cdFx0dGhpcy5fbW91c2VJbml0KCk7XG5cblx0XHR0aGlzLl9zZXRIYW5kbGVDbGFzc05hbWUoKTtcblxuXHRcdC8vV2UncmUgcmVhZHkgdG8gZ29cblx0XHR0aGlzLnJlYWR5ID0gdHJ1ZTtcblxuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJoYW5kbGVcIiApIHtcblx0XHRcdHRoaXMuX3NldEhhbmRsZUNsYXNzTmFtZSgpO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0SGFuZGxlQ2xhc3NOYW1lOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuZWxlbWVudC5maW5kKCBcIi51aS1zb3J0YWJsZS1oYW5kbGVcIiApLCBcInVpLXNvcnRhYmxlLWhhbmRsZVwiICk7XG5cdFx0JC5lYWNoKCB0aGlzLml0ZW1zLCBmdW5jdGlvbigpIHtcblx0XHRcdHRoYXQuX2FkZENsYXNzKFxuXHRcdFx0XHR0aGlzLmluc3RhbmNlLm9wdGlvbnMuaGFuZGxlID9cblx0XHRcdFx0XHR0aGlzLml0ZW0uZmluZCggdGhpcy5pbnN0YW5jZS5vcHRpb25zLmhhbmRsZSApIDpcblx0XHRcdFx0XHR0aGlzLml0ZW0sXG5cdFx0XHRcdFwidWktc29ydGFibGUtaGFuZGxlXCJcblx0XHRcdCk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9tb3VzZURlc3Ryb3koKTtcblxuXHRcdGZvciAoIHZhciBpID0gdGhpcy5pdGVtcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdHRoaXMuaXRlbXNbIGkgXS5pdGVtLnJlbW92ZURhdGEoIHRoaXMud2lkZ2V0TmFtZSArIFwiLWl0ZW1cIiApO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9tb3VzZUNhcHR1cmU6IGZ1bmN0aW9uKCBldmVudCwgb3ZlcnJpZGVIYW5kbGUgKSB7XG5cdFx0dmFyIGN1cnJlbnRJdGVtID0gbnVsbCxcblx0XHRcdHZhbGlkSGFuZGxlID0gZmFsc2UsXG5cdFx0XHR0aGF0ID0gdGhpcztcblxuXHRcdGlmICggdGhpcy5yZXZlcnRpbmcgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgfHwgdGhpcy5vcHRpb25zLnR5cGUgPT09IFwic3RhdGljXCIgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly9XZSBoYXZlIHRvIHJlZnJlc2ggdGhlIGl0ZW1zIGRhdGEgb25jZSBmaXJzdFxuXHRcdHRoaXMuX3JlZnJlc2hJdGVtcyggZXZlbnQgKTtcblxuXHRcdC8vRmluZCBvdXQgaWYgdGhlIGNsaWNrZWQgbm9kZSAob3Igb25lIG9mIGl0cyBwYXJlbnRzKSBpcyBhIGFjdHVhbCBpdGVtIGluIHRoaXMuaXRlbXNcblx0XHQkKCBldmVudC50YXJnZXQgKS5wYXJlbnRzKCkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoICQuZGF0YSggdGhpcywgdGhhdC53aWRnZXROYW1lICsgXCItaXRlbVwiICkgPT09IHRoYXQgKSB7XG5cdFx0XHRcdGN1cnJlbnRJdGVtID0gJCggdGhpcyApO1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdGlmICggJC5kYXRhKCBldmVudC50YXJnZXQsIHRoYXQud2lkZ2V0TmFtZSArIFwiLWl0ZW1cIiApID09PSB0aGF0ICkge1xuXHRcdFx0Y3VycmVudEl0ZW0gPSAkKCBldmVudC50YXJnZXQgKTtcblx0XHR9XG5cblx0XHRpZiAoICFjdXJyZW50SXRlbSApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuaGFuZGxlICYmICFvdmVycmlkZUhhbmRsZSApIHtcblx0XHRcdCQoIHRoaXMub3B0aW9ucy5oYW5kbGUsIGN1cnJlbnRJdGVtICkuZmluZCggXCIqXCIgKS5hZGRCYWNrKCkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggdGhpcyA9PT0gZXZlbnQudGFyZ2V0ICkge1xuXHRcdFx0XHRcdHZhbGlkSGFuZGxlID0gdHJ1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdFx0aWYgKCAhdmFsaWRIYW5kbGUgKSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLmN1cnJlbnRJdGVtID0gY3VycmVudEl0ZW07XG5cdFx0dGhpcy5fcmVtb3ZlQ3VycmVudHNGcm9tSXRlbXMoKTtcblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9LFxuXG5cdF9tb3VzZVN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIG92ZXJyaWRlSGFuZGxlLCBub0FjdGl2YXRpb24gKSB7XG5cblx0XHR2YXIgaSwgYm9keSxcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnM7XG5cblx0XHR0aGlzLmN1cnJlbnRDb250YWluZXIgPSB0aGlzO1xuXG5cdFx0Ly9XZSBvbmx5IG5lZWQgdG8gY2FsbCByZWZyZXNoUG9zaXRpb25zLCBiZWNhdXNlIHRoZSByZWZyZXNoSXRlbXMgY2FsbCBoYXMgYmVlbiBtb3ZlZCB0b1xuXHRcdC8vIG1vdXNlQ2FwdHVyZVxuXHRcdHRoaXMucmVmcmVzaFBvc2l0aW9ucygpO1xuXG5cdFx0Ly9DcmVhdGUgYW5kIGFwcGVuZCB0aGUgdmlzaWJsZSBoZWxwZXJcblx0XHR0aGlzLmhlbHBlciA9IHRoaXMuX2NyZWF0ZUhlbHBlciggZXZlbnQgKTtcblxuXHRcdC8vQ2FjaGUgdGhlIGhlbHBlciBzaXplXG5cdFx0dGhpcy5fY2FjaGVIZWxwZXJQcm9wb3J0aW9ucygpO1xuXG5cdFx0Lypcblx0XHQgKiAtIFBvc2l0aW9uIGdlbmVyYXRpb24gLVxuXHRcdCAqIFRoaXMgYmxvY2sgZ2VuZXJhdGVzIGV2ZXJ5dGhpbmcgcG9zaXRpb24gcmVsYXRlZCAtIGl0J3MgdGhlIGNvcmUgb2YgZHJhZ2dhYmxlcy5cblx0XHQgKi9cblxuXHRcdC8vQ2FjaGUgdGhlIG1hcmdpbnMgb2YgdGhlIG9yaWdpbmFsIGVsZW1lbnRcblx0XHR0aGlzLl9jYWNoZU1hcmdpbnMoKTtcblxuXHRcdC8vR2V0IHRoZSBuZXh0IHNjcm9sbGluZyBwYXJlbnRcblx0XHR0aGlzLnNjcm9sbFBhcmVudCA9IHRoaXMuaGVscGVyLnNjcm9sbFBhcmVudCgpO1xuXG5cdFx0Ly9UaGUgZWxlbWVudCdzIGFic29sdXRlIHBvc2l0aW9uIG9uIHRoZSBwYWdlIG1pbnVzIG1hcmdpbnNcblx0XHR0aGlzLm9mZnNldCA9IHRoaXMuY3VycmVudEl0ZW0ub2Zmc2V0KCk7XG5cdFx0dGhpcy5vZmZzZXQgPSB7XG5cdFx0XHR0b3A6IHRoaXMub2Zmc2V0LnRvcCAtIHRoaXMubWFyZ2lucy50b3AsXG5cdFx0XHRsZWZ0OiB0aGlzLm9mZnNldC5sZWZ0IC0gdGhpcy5tYXJnaW5zLmxlZnRcblx0XHR9O1xuXG5cdFx0JC5leHRlbmQoIHRoaXMub2Zmc2V0LCB7XG5cdFx0XHRjbGljazogeyAvL1doZXJlIHRoZSBjbGljayBoYXBwZW5lZCwgcmVsYXRpdmUgdG8gdGhlIGVsZW1lbnRcblx0XHRcdFx0bGVmdDogZXZlbnQucGFnZVggLSB0aGlzLm9mZnNldC5sZWZ0LFxuXHRcdFx0XHR0b3A6IGV2ZW50LnBhZ2VZIC0gdGhpcy5vZmZzZXQudG9wXG5cdFx0XHR9LFxuXHRcdFx0cGFyZW50OiB0aGlzLl9nZXRQYXJlbnRPZmZzZXQoKSxcblxuXHRcdFx0Ly8gVGhpcyBpcyBhIHJlbGF0aXZlIHRvIGFic29sdXRlIHBvc2l0aW9uIG1pbnVzIHRoZSBhY3R1YWwgcG9zaXRpb24gY2FsY3VsYXRpb24gLVxuXHRcdFx0Ly8gb25seSB1c2VkIGZvciByZWxhdGl2ZSBwb3NpdGlvbmVkIGhlbHBlclxuXHRcdFx0cmVsYXRpdmU6IHRoaXMuX2dldFJlbGF0aXZlT2Zmc2V0KClcblx0XHR9ICk7XG5cblx0XHQvLyBPbmx5IGFmdGVyIHdlIGdvdCB0aGUgb2Zmc2V0LCB3ZSBjYW4gY2hhbmdlIHRoZSBoZWxwZXIncyBwb3NpdGlvbiB0byBhYnNvbHV0ZVxuXHRcdC8vIFRPRE86IFN0aWxsIG5lZWQgdG8gZmlndXJlIG91dCBhIHdheSB0byBtYWtlIHJlbGF0aXZlIHNvcnRpbmcgcG9zc2libGVcblx0XHR0aGlzLmhlbHBlci5jc3MoIFwicG9zaXRpb25cIiwgXCJhYnNvbHV0ZVwiICk7XG5cdFx0dGhpcy5jc3NQb3NpdGlvbiA9IHRoaXMuaGVscGVyLmNzcyggXCJwb3NpdGlvblwiICk7XG5cblx0XHQvL0dlbmVyYXRlIHRoZSBvcmlnaW5hbCBwb3NpdGlvblxuXHRcdHRoaXMub3JpZ2luYWxQb3NpdGlvbiA9IHRoaXMuX2dlbmVyYXRlUG9zaXRpb24oIGV2ZW50ICk7XG5cdFx0dGhpcy5vcmlnaW5hbFBhZ2VYID0gZXZlbnQucGFnZVg7XG5cdFx0dGhpcy5vcmlnaW5hbFBhZ2VZID0gZXZlbnQucGFnZVk7XG5cblx0XHQvL0FkanVzdCB0aGUgbW91c2Ugb2Zmc2V0IHJlbGF0aXZlIHRvIHRoZSBoZWxwZXIgaWYgXCJjdXJzb3JBdFwiIGlzIHN1cHBsaWVkXG5cdFx0KCBvLmN1cnNvckF0ICYmIHRoaXMuX2FkanVzdE9mZnNldEZyb21IZWxwZXIoIG8uY3Vyc29yQXQgKSApO1xuXG5cdFx0Ly9DYWNoZSB0aGUgZm9ybWVyIERPTSBwb3NpdGlvblxuXHRcdHRoaXMuZG9tUG9zaXRpb24gPSB7XG5cdFx0XHRwcmV2OiB0aGlzLmN1cnJlbnRJdGVtLnByZXYoKVsgMCBdLFxuXHRcdFx0cGFyZW50OiB0aGlzLmN1cnJlbnRJdGVtLnBhcmVudCgpWyAwIF1cblx0XHR9O1xuXG5cdFx0Ly8gSWYgdGhlIGhlbHBlciBpcyBub3QgdGhlIG9yaWdpbmFsLCBoaWRlIHRoZSBvcmlnaW5hbCBzbyBpdCdzIG5vdCBwbGF5aW5nIGFueSByb2xlIGR1cmluZ1xuXHRcdC8vIHRoZSBkcmFnLCB3b24ndCBjYXVzZSBhbnl0aGluZyBiYWQgdGhpcyB3YXlcblx0XHRpZiAoIHRoaXMuaGVscGVyWyAwIF0gIT09IHRoaXMuY3VycmVudEl0ZW1bIDAgXSApIHtcblx0XHRcdHRoaXMuY3VycmVudEl0ZW0uaGlkZSgpO1xuXHRcdH1cblxuXHRcdC8vQ3JlYXRlIHRoZSBwbGFjZWhvbGRlclxuXHRcdHRoaXMuX2NyZWF0ZVBsYWNlaG9sZGVyKCk7XG5cblx0XHQvL1NldCBhIGNvbnRhaW5tZW50IGlmIGdpdmVuIGluIHRoZSBvcHRpb25zXG5cdFx0aWYgKCBvLmNvbnRhaW5tZW50ICkge1xuXHRcdFx0dGhpcy5fc2V0Q29udGFpbm1lbnQoKTtcblx0XHR9XG5cblx0XHRpZiAoIG8uY3Vyc29yICYmIG8uY3Vyc29yICE9PSBcImF1dG9cIiApIHsgLy8gY3Vyc29yIG9wdGlvblxuXHRcdFx0Ym9keSA9IHRoaXMuZG9jdW1lbnQuZmluZCggXCJib2R5XCIgKTtcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUVcblx0XHRcdHRoaXMuc3RvcmVkQ3Vyc29yID0gYm9keS5jc3MoIFwiY3Vyc29yXCIgKTtcblx0XHRcdGJvZHkuY3NzKCBcImN1cnNvclwiLCBvLmN1cnNvciApO1xuXG5cdFx0XHR0aGlzLnN0b3JlZFN0eWxlc2hlZXQgPVxuXHRcdFx0XHQkKCBcIjxzdHlsZT4qeyBjdXJzb3I6IFwiICsgby5jdXJzb3IgKyBcIiAhaW1wb3J0YW50OyB9PC9zdHlsZT5cIiApLmFwcGVuZFRvKCBib2R5ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBvLm9wYWNpdHkgKSB7IC8vIG9wYWNpdHkgb3B0aW9uXG5cdFx0XHRpZiAoIHRoaXMuaGVscGVyLmNzcyggXCJvcGFjaXR5XCIgKSApIHtcblx0XHRcdFx0dGhpcy5fc3RvcmVkT3BhY2l0eSA9IHRoaXMuaGVscGVyLmNzcyggXCJvcGFjaXR5XCIgKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuaGVscGVyLmNzcyggXCJvcGFjaXR5XCIsIG8ub3BhY2l0eSApO1xuXHRcdH1cblxuXHRcdGlmICggby56SW5kZXggKSB7IC8vIHpJbmRleCBvcHRpb25cblx0XHRcdGlmICggdGhpcy5oZWxwZXIuY3NzKCBcInpJbmRleFwiICkgKSB7XG5cdFx0XHRcdHRoaXMuX3N0b3JlZFpJbmRleCA9IHRoaXMuaGVscGVyLmNzcyggXCJ6SW5kZXhcIiApO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5oZWxwZXIuY3NzKCBcInpJbmRleFwiLCBvLnpJbmRleCApO1xuXHRcdH1cblxuXHRcdC8vUHJlcGFyZSBzY3JvbGxpbmdcblx0XHRpZiAoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gIT09IHRoaXMuZG9jdW1lbnRbIDAgXSAmJlxuXHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnRhZ05hbWUgIT09IFwiSFRNTFwiICkge1xuXHRcdFx0dGhpcy5vdmVyZmxvd09mZnNldCA9IHRoaXMuc2Nyb2xsUGFyZW50Lm9mZnNldCgpO1xuXHRcdH1cblxuXHRcdC8vQ2FsbCBjYWxsYmFja3Ncblx0XHR0aGlzLl90cmlnZ2VyKCBcInN0YXJ0XCIsIGV2ZW50LCB0aGlzLl91aUhhc2goKSApO1xuXG5cdFx0Ly9SZWNhY2hlIHRoZSBoZWxwZXIgc2l6ZVxuXHRcdGlmICggIXRoaXMuX3ByZXNlcnZlSGVscGVyUHJvcG9ydGlvbnMgKSB7XG5cdFx0XHR0aGlzLl9jYWNoZUhlbHBlclByb3BvcnRpb25zKCk7XG5cdFx0fVxuXG5cdFx0Ly9Qb3N0IFwiYWN0aXZhdGVcIiBldmVudHMgdG8gcG9zc2libGUgY29udGFpbmVyc1xuXHRcdGlmICggIW5vQWN0aXZhdGlvbiApIHtcblx0XHRcdGZvciAoIGkgPSB0aGlzLmNvbnRhaW5lcnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLl90cmlnZ2VyKCBcImFjdGl2YXRlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIHRoaXMgKSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vUHJlcGFyZSBwb3NzaWJsZSBkcm9wcGFibGVzXG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLmN1cnJlbnQgPSB0aGlzO1xuXHRcdH1cblxuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgJiYgIW8uZHJvcEJlaGF2aW91ciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLnByZXBhcmVPZmZzZXRzKCB0aGlzLCBldmVudCApO1xuXHRcdH1cblxuXHRcdHRoaXMuZHJhZ2dpbmcgPSB0cnVlO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaGVscGVyLCBcInVpLXNvcnRhYmxlLWhlbHBlclwiICk7XG5cblx0XHQvLyBFeGVjdXRlIHRoZSBkcmFnIG9uY2UgLSB0aGlzIGNhdXNlcyB0aGUgaGVscGVyIG5vdCB0byBiZSB2aXNpYmxlYmVmb3JlIGdldHRpbmcgaXRzXG5cdFx0Ly8gY29ycmVjdCBwb3NpdGlvblxuXHRcdHRoaXMuX21vdXNlRHJhZyggZXZlbnQgKTtcblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9LFxuXG5cdF9tb3VzZURyYWc6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgaSwgaXRlbSwgaXRlbUVsZW1lbnQsIGludGVyc2VjdGlvbixcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRzY3JvbGxlZCA9IGZhbHNlO1xuXG5cdFx0Ly9Db21wdXRlIHRoZSBoZWxwZXJzIHBvc2l0aW9uXG5cdFx0dGhpcy5wb3NpdGlvbiA9IHRoaXMuX2dlbmVyYXRlUG9zaXRpb24oIGV2ZW50ICk7XG5cdFx0dGhpcy5wb3NpdGlvbkFicyA9IHRoaXMuX2NvbnZlcnRQb3NpdGlvblRvKCBcImFic29sdXRlXCIgKTtcblxuXHRcdGlmICggIXRoaXMubGFzdFBvc2l0aW9uQWJzICkge1xuXHRcdFx0dGhpcy5sYXN0UG9zaXRpb25BYnMgPSB0aGlzLnBvc2l0aW9uQWJzO1xuXHRcdH1cblxuXHRcdC8vRG8gc2Nyb2xsaW5nXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuc2Nyb2xsICkge1xuXHRcdFx0aWYgKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICE9PSB0aGlzLmRvY3VtZW50WyAwIF0gJiZcblx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnRhZ05hbWUgIT09IFwiSFRNTFwiICkge1xuXG5cdFx0XHRcdGlmICggKCB0aGlzLm92ZXJmbG93T2Zmc2V0LnRvcCArIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0ub2Zmc2V0SGVpZ2h0ICkgLVxuXHRcdFx0XHRcdFx0ZXZlbnQucGFnZVkgPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0uc2Nyb2xsVG9wID1cblx0XHRcdFx0XHRcdHNjcm9sbGVkID0gdGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5zY3JvbGxUb3AgKyBvLnNjcm9sbFNwZWVkO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCBldmVudC5wYWdlWSAtIHRoaXMub3ZlcmZsb3dPZmZzZXQudG9wIDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnNjcm9sbFRvcCA9XG5cdFx0XHRcdFx0XHRzY3JvbGxlZCA9IHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0uc2Nyb2xsVG9wIC0gby5zY3JvbGxTcGVlZDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggKCB0aGlzLm92ZXJmbG93T2Zmc2V0LmxlZnQgKyB0aGlzLnNjcm9sbFBhcmVudFsgMCBdLm9mZnNldFdpZHRoICkgLVxuXHRcdFx0XHRcdFx0ZXZlbnQucGFnZVggPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0uc2Nyb2xsTGVmdCA9IHNjcm9sbGVkID1cblx0XHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0uc2Nyb2xsTGVmdCArIG8uc2Nyb2xsU3BlZWQ7XG5cdFx0XHRcdH0gZWxzZSBpZiAoIGV2ZW50LnBhZ2VYIC0gdGhpcy5vdmVyZmxvd09mZnNldC5sZWZ0IDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnNjcm9sbExlZnQgPSBzY3JvbGxlZCA9XG5cdFx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnNjcm9sbExlZnQgLSBvLnNjcm9sbFNwZWVkO1xuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWSAtIHRoaXMuZG9jdW1lbnQuc2Nyb2xsVG9wKCkgPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbGVkID0gdGhpcy5kb2N1bWVudC5zY3JvbGxUb3AoIHRoaXMuZG9jdW1lbnQuc2Nyb2xsVG9wKCkgLSBvLnNjcm9sbFNwZWVkICk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoIHRoaXMud2luZG93LmhlaWdodCgpIC0gKCBldmVudC5wYWdlWSAtIHRoaXMuZG9jdW1lbnQuc2Nyb2xsVG9wKCkgKSA8XG5cdFx0XHRcdFx0XHRvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbGVkID0gdGhpcy5kb2N1bWVudC5zY3JvbGxUb3AoIHRoaXMuZG9jdW1lbnQuc2Nyb2xsVG9wKCkgKyBvLnNjcm9sbFNwZWVkICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VYIC0gdGhpcy5kb2N1bWVudC5zY3JvbGxMZWZ0KCkgPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbGVkID0gdGhpcy5kb2N1bWVudC5zY3JvbGxMZWZ0KFxuXHRcdFx0XHRcdFx0dGhpcy5kb2N1bWVudC5zY3JvbGxMZWZ0KCkgLSBvLnNjcm9sbFNwZWVkXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0fSBlbHNlIGlmICggdGhpcy53aW5kb3cud2lkdGgoKSAtICggZXZlbnQucGFnZVggLSB0aGlzLmRvY3VtZW50LnNjcm9sbExlZnQoKSApIDxcblx0XHRcdFx0XHRcdG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsZWQgPSB0aGlzLmRvY3VtZW50LnNjcm9sbExlZnQoXG5cdFx0XHRcdFx0XHR0aGlzLmRvY3VtZW50LnNjcm9sbExlZnQoKSArIG8uc2Nyb2xsU3BlZWRcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBzY3JvbGxlZCAhPT0gZmFsc2UgJiYgJC51aS5kZG1hbmFnZXIgJiYgIW8uZHJvcEJlaGF2aW91ciApIHtcblx0XHRcdFx0JC51aS5kZG1hbmFnZXIucHJlcGFyZU9mZnNldHMoIHRoaXMsIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly9SZWdlbmVyYXRlIHRoZSBhYnNvbHV0ZSBwb3NpdGlvbiB1c2VkIGZvciBwb3NpdGlvbiBjaGVja3Ncblx0XHR0aGlzLnBvc2l0aW9uQWJzID0gdGhpcy5fY29udmVydFBvc2l0aW9uVG8oIFwiYWJzb2x1dGVcIiApO1xuXG5cdFx0Ly9TZXQgdGhlIGhlbHBlciBwb3NpdGlvblxuXHRcdGlmICggIXRoaXMub3B0aW9ucy5heGlzIHx8IHRoaXMub3B0aW9ucy5heGlzICE9PSBcInlcIiApIHtcblx0XHRcdHRoaXMuaGVscGVyWyAwIF0uc3R5bGUubGVmdCA9IHRoaXMucG9zaXRpb24ubGVmdCArIFwicHhcIjtcblx0XHR9XG5cdFx0aWYgKCAhdGhpcy5vcHRpb25zLmF4aXMgfHwgdGhpcy5vcHRpb25zLmF4aXMgIT09IFwieFwiICkge1xuXHRcdFx0dGhpcy5oZWxwZXJbIDAgXS5zdHlsZS50b3AgPSB0aGlzLnBvc2l0aW9uLnRvcCArIFwicHhcIjtcblx0XHR9XG5cblx0XHQvL1JlYXJyYW5nZVxuXHRcdGZvciAoIGkgPSB0aGlzLml0ZW1zLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXG5cdFx0XHQvL0NhY2hlIHZhcmlhYmxlcyBhbmQgaW50ZXJzZWN0aW9uLCBjb250aW51ZSBpZiBubyBpbnRlcnNlY3Rpb25cblx0XHRcdGl0ZW0gPSB0aGlzLml0ZW1zWyBpIF07XG5cdFx0XHRpdGVtRWxlbWVudCA9IGl0ZW0uaXRlbVsgMCBdO1xuXHRcdFx0aW50ZXJzZWN0aW9uID0gdGhpcy5faW50ZXJzZWN0c1dpdGhQb2ludGVyKCBpdGVtICk7XG5cdFx0XHRpZiAoICFpbnRlcnNlY3Rpb24gKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBPbmx5IHB1dCB0aGUgcGxhY2Vob2xkZXIgaW5zaWRlIHRoZSBjdXJyZW50IENvbnRhaW5lciwgc2tpcCBhbGxcblx0XHRcdC8vIGl0ZW1zIGZyb20gb3RoZXIgY29udGFpbmVycy4gVGhpcyB3b3JrcyBiZWNhdXNlIHdoZW4gbW92aW5nXG5cdFx0XHQvLyBhbiBpdGVtIGZyb20gb25lIGNvbnRhaW5lciB0byBhbm90aGVyIHRoZVxuXHRcdFx0Ly8gY3VycmVudENvbnRhaW5lciBpcyBzd2l0Y2hlZCBiZWZvcmUgdGhlIHBsYWNlaG9sZGVyIGlzIG1vdmVkLlxuXHRcdFx0Ly9cblx0XHRcdC8vIFdpdGhvdXQgdGhpcywgbW92aW5nIGl0ZW1zIGluIFwic3ViLXNvcnRhYmxlc1wiIGNhbiBjYXVzZVxuXHRcdFx0Ly8gdGhlIHBsYWNlaG9sZGVyIHRvIGppdHRlciBiZXR3ZWVuIHRoZSBvdXRlciBhbmQgaW5uZXIgY29udGFpbmVyLlxuXHRcdFx0aWYgKCBpdGVtLmluc3RhbmNlICE9PSB0aGlzLmN1cnJlbnRDb250YWluZXIgKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDYW5ub3QgaW50ZXJzZWN0IHdpdGggaXRzZWxmXG5cdFx0XHQvLyBubyB1c2VsZXNzIGFjdGlvbnMgdGhhdCBoYXZlIGJlZW4gZG9uZSBiZWZvcmVcblx0XHRcdC8vIG5vIGFjdGlvbiBpZiB0aGUgaXRlbSBtb3ZlZCBpcyB0aGUgcGFyZW50IG9mIHRoZSBpdGVtIGNoZWNrZWRcblx0XHRcdGlmICggaXRlbUVsZW1lbnQgIT09IHRoaXMuY3VycmVudEl0ZW1bIDAgXSAmJlxuXHRcdFx0XHR0aGlzLnBsYWNlaG9sZGVyWyBpbnRlcnNlY3Rpb24gPT09IDEgPyBcIm5leHRcIiA6IFwicHJldlwiIF0oKVsgMCBdICE9PSBpdGVtRWxlbWVudCAmJlxuXHRcdFx0XHQhJC5jb250YWlucyggdGhpcy5wbGFjZWhvbGRlclsgMCBdLCBpdGVtRWxlbWVudCApICYmXG5cdFx0XHRcdCggdGhpcy5vcHRpb25zLnR5cGUgPT09IFwic2VtaS1keW5hbWljXCIgP1xuXHRcdFx0XHRcdCEkLmNvbnRhaW5zKCB0aGlzLmVsZW1lbnRbIDAgXSwgaXRlbUVsZW1lbnQgKSA6XG5cdFx0XHRcdFx0dHJ1ZVxuXHRcdFx0XHQpXG5cdFx0XHQpIHtcblxuXHRcdFx0XHR0aGlzLmRpcmVjdGlvbiA9IGludGVyc2VjdGlvbiA9PT0gMSA/IFwiZG93blwiIDogXCJ1cFwiO1xuXG5cdFx0XHRcdGlmICggdGhpcy5vcHRpb25zLnRvbGVyYW5jZSA9PT0gXCJwb2ludGVyXCIgfHwgdGhpcy5faW50ZXJzZWN0c1dpdGhTaWRlcyggaXRlbSApICkge1xuXHRcdFx0XHRcdHRoaXMuX3JlYXJyYW5nZSggZXZlbnQsIGl0ZW0gKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY2hhbmdlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goKSApO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvL1Bvc3QgZXZlbnRzIHRvIGNvbnRhaW5lcnNcblx0XHR0aGlzLl9jb250YWN0Q29udGFpbmVycyggZXZlbnQgKTtcblxuXHRcdC8vSW50ZXJjb25uZWN0IHdpdGggZHJvcHBhYmxlc1xuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5kcmFnKCB0aGlzLCBldmVudCApO1xuXHRcdH1cblxuXHRcdC8vQ2FsbCBjYWxsYmFja3Ncblx0XHR0aGlzLl90cmlnZ2VyKCBcInNvcnRcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCgpICk7XG5cblx0XHR0aGlzLmxhc3RQb3NpdGlvbkFicyA9IHRoaXMucG9zaXRpb25BYnM7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXG5cdH0sXG5cblx0X21vdXNlU3RvcDogZnVuY3Rpb24oIGV2ZW50LCBub1Byb3BhZ2F0aW9uICkge1xuXG5cdFx0aWYgKCAhZXZlbnQgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly9JZiB3ZSBhcmUgdXNpbmcgZHJvcHBhYmxlcywgaW5mb3JtIHRoZSBtYW5hZ2VyIGFib3V0IHRoZSBkcm9wXG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciAmJiAhdGhpcy5vcHRpb25zLmRyb3BCZWhhdmlvdXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5kcm9wKCB0aGlzLCBldmVudCApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vcHRpb25zLnJldmVydCApIHtcblx0XHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdFx0Y3VyID0gdGhpcy5wbGFjZWhvbGRlci5vZmZzZXQoKSxcblx0XHRcdFx0YXhpcyA9IHRoaXMub3B0aW9ucy5heGlzLFxuXHRcdFx0XHRhbmltYXRpb24gPSB7fTtcblxuXHRcdFx0aWYgKCAhYXhpcyB8fCBheGlzID09PSBcInhcIiApIHtcblx0XHRcdFx0YW5pbWF0aW9uLmxlZnQgPSBjdXIubGVmdCAtIHRoaXMub2Zmc2V0LnBhcmVudC5sZWZ0IC0gdGhpcy5tYXJnaW5zLmxlZnQgK1xuXHRcdFx0XHRcdCggdGhpcy5vZmZzZXRQYXJlbnRbIDAgXSA9PT0gdGhpcy5kb2N1bWVudFsgMCBdLmJvZHkgP1xuXHRcdFx0XHRcdFx0MCA6XG5cdFx0XHRcdFx0XHR0aGlzLm9mZnNldFBhcmVudFsgMCBdLnNjcm9sbExlZnRcblx0XHRcdFx0XHQpO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAhYXhpcyB8fCBheGlzID09PSBcInlcIiApIHtcblx0XHRcdFx0YW5pbWF0aW9uLnRvcCA9IGN1ci50b3AgLSB0aGlzLm9mZnNldC5wYXJlbnQudG9wIC0gdGhpcy5tYXJnaW5zLnRvcCArXG5cdFx0XHRcdFx0KCB0aGlzLm9mZnNldFBhcmVudFsgMCBdID09PSB0aGlzLmRvY3VtZW50WyAwIF0uYm9keSA/XG5cdFx0XHRcdFx0XHQwIDpcblx0XHRcdFx0XHRcdHRoaXMub2Zmc2V0UGFyZW50WyAwIF0uc2Nyb2xsVG9wXG5cdFx0XHRcdFx0KTtcblx0XHRcdH1cblx0XHRcdHRoaXMucmV2ZXJ0aW5nID0gdHJ1ZTtcblx0XHRcdCQoIHRoaXMuaGVscGVyICkuYW5pbWF0ZShcblx0XHRcdFx0YW5pbWF0aW9uLFxuXHRcdFx0XHRwYXJzZUludCggdGhpcy5vcHRpb25zLnJldmVydCwgMTAgKSB8fCA1MDAsXG5cdFx0XHRcdGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHRoYXQuX2NsZWFyKCBldmVudCApO1xuXHRcdFx0XHR9XG5cdFx0XHQpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9jbGVhciggZXZlbnQsIG5vUHJvcGFnYXRpb24gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cblx0fSxcblxuXHRjYW5jZWw6IGZ1bmN0aW9uKCkge1xuXG5cdFx0aWYgKCB0aGlzLmRyYWdnaW5nICkge1xuXG5cdFx0XHR0aGlzLl9tb3VzZVVwKCBuZXcgJC5FdmVudCggXCJtb3VzZXVwXCIsIHsgdGFyZ2V0OiBudWxsIH0gKSApO1xuXG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5oZWxwZXIgPT09IFwib3JpZ2luYWxcIiApIHtcblx0XHRcdFx0dGhpcy5jdXJyZW50SXRlbS5jc3MoIHRoaXMuX3N0b3JlZENTUyApO1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5jdXJyZW50SXRlbSwgXCJ1aS1zb3J0YWJsZS1oZWxwZXJcIiApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5jdXJyZW50SXRlbS5zaG93KCk7XG5cdFx0XHR9XG5cblx0XHRcdC8vUG9zdCBkZWFjdGl2YXRpbmcgZXZlbnRzIHRvIGNvbnRhaW5lcnNcblx0XHRcdGZvciAoIHZhciBpID0gdGhpcy5jb250YWluZXJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5fdHJpZ2dlciggXCJkZWFjdGl2YXRlXCIsIG51bGwsIHRoaXMuX3VpSGFzaCggdGhpcyApICk7XG5cdFx0XHRcdGlmICggdGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUub3ZlciApIHtcblx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5fdHJpZ2dlciggXCJvdXRcIiwgbnVsbCwgdGhpcy5fdWlIYXNoKCB0aGlzICkgKTtcblx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS5vdmVyID0gMDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLnBsYWNlaG9sZGVyICkge1xuXG5cdFx0XHQvLyQodGhpcy5wbGFjZWhvbGRlclswXSkucmVtb3ZlKCk7IHdvdWxkIGhhdmUgYmVlbiB0aGUgalF1ZXJ5IHdheSAtIHVuZm9ydHVuYXRlbHksXG5cdFx0XHQvLyBpdCB1bmJpbmRzIEFMTCBldmVudHMgZnJvbSB0aGUgb3JpZ2luYWwgbm9kZSFcblx0XHRcdGlmICggdGhpcy5wbGFjZWhvbGRlclsgMCBdLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdHRoaXMucGxhY2Vob2xkZXJbIDAgXS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKCB0aGlzLnBsYWNlaG9sZGVyWyAwIF0gKTtcblx0XHRcdH1cblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmhlbHBlciAhPT0gXCJvcmlnaW5hbFwiICYmIHRoaXMuaGVscGVyICYmXG5cdFx0XHRcdFx0dGhpcy5oZWxwZXJbIDAgXS5wYXJlbnROb2RlICkge1xuXHRcdFx0XHR0aGlzLmhlbHBlci5yZW1vdmUoKTtcblx0XHRcdH1cblxuXHRcdFx0JC5leHRlbmQoIHRoaXMsIHtcblx0XHRcdFx0aGVscGVyOiBudWxsLFxuXHRcdFx0XHRkcmFnZ2luZzogZmFsc2UsXG5cdFx0XHRcdHJldmVydGluZzogZmFsc2UsXG5cdFx0XHRcdF9ub0ZpbmFsU29ydDogbnVsbFxuXHRcdFx0fSApO1xuXG5cdFx0XHRpZiAoIHRoaXMuZG9tUG9zaXRpb24ucHJldiApIHtcblx0XHRcdFx0JCggdGhpcy5kb21Qb3NpdGlvbi5wcmV2ICkuYWZ0ZXIoIHRoaXMuY3VycmVudEl0ZW0gKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdCQoIHRoaXMuZG9tUG9zaXRpb24ucGFyZW50ICkucHJlcGVuZCggdGhpcy5jdXJyZW50SXRlbSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH0sXG5cblx0c2VyaWFsaXplOiBmdW5jdGlvbiggbyApIHtcblxuXHRcdHZhciBpdGVtcyA9IHRoaXMuX2dldEl0ZW1zQXNqUXVlcnkoIG8gJiYgby5jb25uZWN0ZWQgKSxcblx0XHRcdHN0ciA9IFtdO1xuXHRcdG8gPSBvIHx8IHt9O1xuXG5cdFx0JCggaXRlbXMgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciByZXMgPSAoICQoIG8uaXRlbSB8fCB0aGlzICkuYXR0ciggby5hdHRyaWJ1dGUgfHwgXCJpZFwiICkgfHwgXCJcIiApXG5cdFx0XHRcdC5tYXRjaCggby5leHByZXNzaW9uIHx8ICggLyguKylbXFwtPV9dKC4rKS8gKSApO1xuXHRcdFx0aWYgKCByZXMgKSB7XG5cdFx0XHRcdHN0ci5wdXNoKFxuXHRcdFx0XHRcdCggby5rZXkgfHwgcmVzWyAxIF0gKyBcIltdXCIgKSArXG5cdFx0XHRcdFx0XCI9XCIgKyAoIG8ua2V5ICYmIG8uZXhwcmVzc2lvbiA/IHJlc1sgMSBdIDogcmVzWyAyIF0gKSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdGlmICggIXN0ci5sZW5ndGggJiYgby5rZXkgKSB7XG5cdFx0XHRzdHIucHVzaCggby5rZXkgKyBcIj1cIiApO1xuXHRcdH1cblxuXHRcdHJldHVybiBzdHIuam9pbiggXCImXCIgKTtcblxuXHR9LFxuXG5cdHRvQXJyYXk6IGZ1bmN0aW9uKCBvICkge1xuXG5cdFx0dmFyIGl0ZW1zID0gdGhpcy5fZ2V0SXRlbXNBc2pRdWVyeSggbyAmJiBvLmNvbm5lY3RlZCApLFxuXHRcdFx0cmV0ID0gW107XG5cblx0XHRvID0gbyB8fCB7fTtcblxuXHRcdGl0ZW1zLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0LnB1c2goICQoIG8uaXRlbSB8fCB0aGlzICkuYXR0ciggby5hdHRyaWJ1dGUgfHwgXCJpZFwiICkgfHwgXCJcIiApO1xuXHRcdH0gKTtcblx0XHRyZXR1cm4gcmV0O1xuXG5cdH0sXG5cblx0LyogQmUgY2FyZWZ1bCB3aXRoIHRoZSBmb2xsb3dpbmcgY29yZSBmdW5jdGlvbnMgKi9cblx0X2ludGVyc2VjdHNXaXRoOiBmdW5jdGlvbiggaXRlbSApIHtcblxuXHRcdHZhciB4MSA9IHRoaXMucG9zaXRpb25BYnMubGVmdCxcblx0XHRcdHgyID0geDEgKyB0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoLFxuXHRcdFx0eTEgPSB0aGlzLnBvc2l0aW9uQWJzLnRvcCxcblx0XHRcdHkyID0geTEgKyB0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCxcblx0XHRcdGwgPSBpdGVtLmxlZnQsXG5cdFx0XHRyID0gbCArIGl0ZW0ud2lkdGgsXG5cdFx0XHR0ID0gaXRlbS50b3AsXG5cdFx0XHRiID0gdCArIGl0ZW0uaGVpZ2h0LFxuXHRcdFx0ZHlDbGljayA9IHRoaXMub2Zmc2V0LmNsaWNrLnRvcCxcblx0XHRcdGR4Q2xpY2sgPSB0aGlzLm9mZnNldC5jbGljay5sZWZ0LFxuXHRcdFx0aXNPdmVyRWxlbWVudEhlaWdodCA9ICggdGhpcy5vcHRpb25zLmF4aXMgPT09IFwieFwiICkgfHwgKCAoIHkxICsgZHlDbGljayApID4gdCAmJlxuXHRcdFx0XHQoIHkxICsgZHlDbGljayApIDwgYiApLFxuXHRcdFx0aXNPdmVyRWxlbWVudFdpZHRoID0gKCB0aGlzLm9wdGlvbnMuYXhpcyA9PT0gXCJ5XCIgKSB8fCAoICggeDEgKyBkeENsaWNrICkgPiBsICYmXG5cdFx0XHRcdCggeDEgKyBkeENsaWNrICkgPCByICksXG5cdFx0XHRpc092ZXJFbGVtZW50ID0gaXNPdmVyRWxlbWVudEhlaWdodCAmJiBpc092ZXJFbGVtZW50V2lkdGg7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy50b2xlcmFuY2UgPT09IFwicG9pbnRlclwiIHx8XG5cdFx0XHR0aGlzLm9wdGlvbnMuZm9yY2VQb2ludGVyRm9yQ29udGFpbmVycyB8fFxuXHRcdFx0KCB0aGlzLm9wdGlvbnMudG9sZXJhbmNlICE9PSBcInBvaW50ZXJcIiAmJlxuXHRcdFx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zWyB0aGlzLmZsb2F0aW5nID8gXCJ3aWR0aFwiIDogXCJoZWlnaHRcIiBdID5cblx0XHRcdFx0aXRlbVsgdGhpcy5mbG9hdGluZyA/IFwid2lkdGhcIiA6IFwiaGVpZ2h0XCIgXSApXG5cdFx0KSB7XG5cdFx0XHRyZXR1cm4gaXNPdmVyRWxlbWVudDtcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRyZXR1cm4gKCBsIDwgeDEgKyAoIHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLyAyICkgJiYgLy8gUmlnaHQgSGFsZlxuXHRcdFx0XHR4MiAtICggdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAvIDIgKSA8IHIgJiYgLy8gTGVmdCBIYWxmXG5cdFx0XHRcdHQgPCB5MSArICggdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLyAyICkgJiYgLy8gQm90dG9tIEhhbGZcblx0XHRcdFx0eTIgLSAoIHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC8gMiApIDwgYiApOyAvLyBUb3AgSGFsZlxuXG5cdFx0fVxuXHR9LFxuXG5cdF9pbnRlcnNlY3RzV2l0aFBvaW50ZXI6IGZ1bmN0aW9uKCBpdGVtICkge1xuXHRcdHZhciB2ZXJ0aWNhbERpcmVjdGlvbiwgaG9yaXpvbnRhbERpcmVjdGlvbixcblx0XHRcdGlzT3ZlckVsZW1lbnRIZWlnaHQgPSAoIHRoaXMub3B0aW9ucy5heGlzID09PSBcInhcIiApIHx8XG5cdFx0XHRcdHRoaXMuX2lzT3ZlckF4aXMoXG5cdFx0XHRcdFx0dGhpcy5wb3NpdGlvbkFicy50b3AgKyB0aGlzLm9mZnNldC5jbGljay50b3AsIGl0ZW0udG9wLCBpdGVtLmhlaWdodCApLFxuXHRcdFx0aXNPdmVyRWxlbWVudFdpZHRoID0gKCB0aGlzLm9wdGlvbnMuYXhpcyA9PT0gXCJ5XCIgKSB8fFxuXHRcdFx0XHR0aGlzLl9pc092ZXJBeGlzKFxuXHRcdFx0XHRcdHRoaXMucG9zaXRpb25BYnMubGVmdCArIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQsIGl0ZW0ubGVmdCwgaXRlbS53aWR0aCApLFxuXHRcdFx0aXNPdmVyRWxlbWVudCA9IGlzT3ZlckVsZW1lbnRIZWlnaHQgJiYgaXNPdmVyRWxlbWVudFdpZHRoO1xuXG5cdFx0aWYgKCAhaXNPdmVyRWxlbWVudCApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHR2ZXJ0aWNhbERpcmVjdGlvbiA9IHRoaXMuX2dldERyYWdWZXJ0aWNhbERpcmVjdGlvbigpO1xuXHRcdGhvcml6b250YWxEaXJlY3Rpb24gPSB0aGlzLl9nZXREcmFnSG9yaXpvbnRhbERpcmVjdGlvbigpO1xuXG5cdFx0cmV0dXJuIHRoaXMuZmxvYXRpbmcgP1xuXHRcdFx0KCAoIGhvcml6b250YWxEaXJlY3Rpb24gPT09IFwicmlnaHRcIiB8fCB2ZXJ0aWNhbERpcmVjdGlvbiA9PT0gXCJkb3duXCIgKSA/IDIgOiAxIClcblx0XHRcdDogKCB2ZXJ0aWNhbERpcmVjdGlvbiAmJiAoIHZlcnRpY2FsRGlyZWN0aW9uID09PSBcImRvd25cIiA/IDIgOiAxICkgKTtcblxuXHR9LFxuXG5cdF9pbnRlcnNlY3RzV2l0aFNpZGVzOiBmdW5jdGlvbiggaXRlbSApIHtcblxuXHRcdHZhciBpc092ZXJCb3R0b21IYWxmID0gdGhpcy5faXNPdmVyQXhpcyggdGhpcy5wb3NpdGlvbkFicy50b3AgK1xuXHRcdFx0XHR0aGlzLm9mZnNldC5jbGljay50b3AsIGl0ZW0udG9wICsgKCBpdGVtLmhlaWdodCAvIDIgKSwgaXRlbS5oZWlnaHQgKSxcblx0XHRcdGlzT3ZlclJpZ2h0SGFsZiA9IHRoaXMuX2lzT3ZlckF4aXMoIHRoaXMucG9zaXRpb25BYnMubGVmdCArXG5cdFx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQsIGl0ZW0ubGVmdCArICggaXRlbS53aWR0aCAvIDIgKSwgaXRlbS53aWR0aCApLFxuXHRcdFx0dmVydGljYWxEaXJlY3Rpb24gPSB0aGlzLl9nZXREcmFnVmVydGljYWxEaXJlY3Rpb24oKSxcblx0XHRcdGhvcml6b250YWxEaXJlY3Rpb24gPSB0aGlzLl9nZXREcmFnSG9yaXpvbnRhbERpcmVjdGlvbigpO1xuXG5cdFx0aWYgKCB0aGlzLmZsb2F0aW5nICYmIGhvcml6b250YWxEaXJlY3Rpb24gKSB7XG5cdFx0XHRyZXR1cm4gKCAoIGhvcml6b250YWxEaXJlY3Rpb24gPT09IFwicmlnaHRcIiAmJiBpc092ZXJSaWdodEhhbGYgKSB8fFxuXHRcdFx0XHQoIGhvcml6b250YWxEaXJlY3Rpb24gPT09IFwibGVmdFwiICYmICFpc092ZXJSaWdodEhhbGYgKSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gdmVydGljYWxEaXJlY3Rpb24gJiYgKCAoIHZlcnRpY2FsRGlyZWN0aW9uID09PSBcImRvd25cIiAmJiBpc092ZXJCb3R0b21IYWxmICkgfHxcblx0XHRcdFx0KCB2ZXJ0aWNhbERpcmVjdGlvbiA9PT0gXCJ1cFwiICYmICFpc092ZXJCb3R0b21IYWxmICkgKTtcblx0XHR9XG5cblx0fSxcblxuXHRfZ2V0RHJhZ1ZlcnRpY2FsRGlyZWN0aW9uOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZGVsdGEgPSB0aGlzLnBvc2l0aW9uQWJzLnRvcCAtIHRoaXMubGFzdFBvc2l0aW9uQWJzLnRvcDtcblx0XHRyZXR1cm4gZGVsdGEgIT09IDAgJiYgKCBkZWx0YSA+IDAgPyBcImRvd25cIiA6IFwidXBcIiApO1xuXHR9LFxuXG5cdF9nZXREcmFnSG9yaXpvbnRhbERpcmVjdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGRlbHRhID0gdGhpcy5wb3NpdGlvbkFicy5sZWZ0IC0gdGhpcy5sYXN0UG9zaXRpb25BYnMubGVmdDtcblx0XHRyZXR1cm4gZGVsdGEgIT09IDAgJiYgKCBkZWx0YSA+IDAgPyBcInJpZ2h0XCIgOiBcImxlZnRcIiApO1xuXHR9LFxuXG5cdHJlZnJlc2g6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR0aGlzLl9yZWZyZXNoSXRlbXMoIGV2ZW50ICk7XG5cdFx0dGhpcy5fc2V0SGFuZGxlQ2xhc3NOYW1lKCk7XG5cdFx0dGhpcy5yZWZyZXNoUG9zaXRpb25zKCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X2Nvbm5lY3RXaXRoOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblx0XHRyZXR1cm4gb3B0aW9ucy5jb25uZWN0V2l0aC5jb25zdHJ1Y3RvciA9PT0gU3RyaW5nID9cblx0XHRcdFsgb3B0aW9ucy5jb25uZWN0V2l0aCBdIDpcblx0XHRcdG9wdGlvbnMuY29ubmVjdFdpdGg7XG5cdH0sXG5cblx0X2dldEl0ZW1zQXNqUXVlcnk6IGZ1bmN0aW9uKCBjb25uZWN0ZWQgKSB7XG5cblx0XHR2YXIgaSwgaiwgY3VyLCBpbnN0LFxuXHRcdFx0aXRlbXMgPSBbXSxcblx0XHRcdHF1ZXJpZXMgPSBbXSxcblx0XHRcdGNvbm5lY3RXaXRoID0gdGhpcy5fY29ubmVjdFdpdGgoKTtcblxuXHRcdGlmICggY29ubmVjdFdpdGggJiYgY29ubmVjdGVkICkge1xuXHRcdFx0Zm9yICggaSA9IGNvbm5lY3RXaXRoLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0XHRjdXIgPSAkKCBjb25uZWN0V2l0aFsgaSBdLCB0aGlzLmRvY3VtZW50WyAwIF0gKTtcblx0XHRcdFx0Zm9yICggaiA9IGN1ci5sZW5ndGggLSAxOyBqID49IDA7IGotLSApIHtcblx0XHRcdFx0XHRpbnN0ID0gJC5kYXRhKCBjdXJbIGogXSwgdGhpcy53aWRnZXRGdWxsTmFtZSApO1xuXHRcdFx0XHRcdGlmICggaW5zdCAmJiBpbnN0ICE9PSB0aGlzICYmICFpbnN0Lm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHRcdFx0XHRxdWVyaWVzLnB1c2goIFsgJC5pc0Z1bmN0aW9uKCBpbnN0Lm9wdGlvbnMuaXRlbXMgKSA/XG5cdFx0XHRcdFx0XHRcdGluc3Qub3B0aW9ucy5pdGVtcy5jYWxsKCBpbnN0LmVsZW1lbnQgKSA6XG5cdFx0XHRcdFx0XHRcdCQoIGluc3Qub3B0aW9ucy5pdGVtcywgaW5zdC5lbGVtZW50IClcblx0XHRcdFx0XHRcdFx0XHQubm90KCBcIi51aS1zb3J0YWJsZS1oZWxwZXJcIiApXG5cdFx0XHRcdFx0XHRcdFx0Lm5vdCggXCIudWktc29ydGFibGUtcGxhY2Vob2xkZXJcIiApLCBpbnN0IF0gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRxdWVyaWVzLnB1c2goIFsgJC5pc0Z1bmN0aW9uKCB0aGlzLm9wdGlvbnMuaXRlbXMgKSA/XG5cdFx0XHR0aGlzLm9wdGlvbnMuaXRlbXNcblx0XHRcdFx0LmNhbGwoIHRoaXMuZWxlbWVudCwgbnVsbCwgeyBvcHRpb25zOiB0aGlzLm9wdGlvbnMsIGl0ZW06IHRoaXMuY3VycmVudEl0ZW0gfSApIDpcblx0XHRcdCQoIHRoaXMub3B0aW9ucy5pdGVtcywgdGhpcy5lbGVtZW50IClcblx0XHRcdFx0Lm5vdCggXCIudWktc29ydGFibGUtaGVscGVyXCIgKVxuXHRcdFx0XHQubm90KCBcIi51aS1zb3J0YWJsZS1wbGFjZWhvbGRlclwiICksIHRoaXMgXSApO1xuXG5cdFx0ZnVuY3Rpb24gYWRkSXRlbXMoKSB7XG5cdFx0XHRpdGVtcy5wdXNoKCB0aGlzICk7XG5cdFx0fVxuXHRcdGZvciAoIGkgPSBxdWVyaWVzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0cXVlcmllc1sgaSBdWyAwIF0uZWFjaCggYWRkSXRlbXMgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gJCggaXRlbXMgKTtcblxuXHR9LFxuXG5cdF9yZW1vdmVDdXJyZW50c0Zyb21JdGVtczogZnVuY3Rpb24oKSB7XG5cblx0XHR2YXIgbGlzdCA9IHRoaXMuY3VycmVudEl0ZW0uZmluZCggXCI6ZGF0YShcIiArIHRoaXMud2lkZ2V0TmFtZSArIFwiLWl0ZW0pXCIgKTtcblxuXHRcdHRoaXMuaXRlbXMgPSAkLmdyZXAoIHRoaXMuaXRlbXMsIGZ1bmN0aW9uKCBpdGVtICkge1xuXHRcdFx0Zm9yICggdmFyIGogPSAwOyBqIDwgbGlzdC5sZW5ndGg7IGorKyApIHtcblx0XHRcdFx0aWYgKCBsaXN0WyBqIF0gPT09IGl0ZW0uaXRlbVsgMCBdICkge1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fSApO1xuXG5cdH0sXG5cblx0X3JlZnJlc2hJdGVtczogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dGhpcy5pdGVtcyA9IFtdO1xuXHRcdHRoaXMuY29udGFpbmVycyA9IFsgdGhpcyBdO1xuXG5cdFx0dmFyIGksIGosIGN1ciwgaW5zdCwgdGFyZ2V0RGF0YSwgX3F1ZXJpZXMsIGl0ZW0sIHF1ZXJpZXNMZW5ndGgsXG5cdFx0XHRpdGVtcyA9IHRoaXMuaXRlbXMsXG5cdFx0XHRxdWVyaWVzID0gWyBbICQuaXNGdW5jdGlvbiggdGhpcy5vcHRpb25zLml0ZW1zICkgP1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMuaXRlbXMuY2FsbCggdGhpcy5lbGVtZW50WyAwIF0sIGV2ZW50LCB7IGl0ZW06IHRoaXMuY3VycmVudEl0ZW0gfSApIDpcblx0XHRcdFx0JCggdGhpcy5vcHRpb25zLml0ZW1zLCB0aGlzLmVsZW1lbnQgKSwgdGhpcyBdIF0sXG5cdFx0XHRjb25uZWN0V2l0aCA9IHRoaXMuX2Nvbm5lY3RXaXRoKCk7XG5cblx0XHQvL1Nob3VsZG4ndCBiZSBydW4gdGhlIGZpcnN0IHRpbWUgdGhyb3VnaCBkdWUgdG8gbWFzc2l2ZSBzbG93LWRvd25cblx0XHRpZiAoIGNvbm5lY3RXaXRoICYmIHRoaXMucmVhZHkgKSB7XG5cdFx0XHRmb3IgKCBpID0gY29ubmVjdFdpdGgubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHRcdGN1ciA9ICQoIGNvbm5lY3RXaXRoWyBpIF0sIHRoaXMuZG9jdW1lbnRbIDAgXSApO1xuXHRcdFx0XHRmb3IgKCBqID0gY3VyLmxlbmd0aCAtIDE7IGogPj0gMDsgai0tICkge1xuXHRcdFx0XHRcdGluc3QgPSAkLmRhdGEoIGN1clsgaiBdLCB0aGlzLndpZGdldEZ1bGxOYW1lICk7XG5cdFx0XHRcdFx0aWYgKCBpbnN0ICYmIGluc3QgIT09IHRoaXMgJiYgIWluc3Qub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdFx0XHRcdHF1ZXJpZXMucHVzaCggWyAkLmlzRnVuY3Rpb24oIGluc3Qub3B0aW9ucy5pdGVtcyApID9cblx0XHRcdFx0XHRcdFx0aW5zdC5vcHRpb25zLml0ZW1zXG5cdFx0XHRcdFx0XHRcdFx0LmNhbGwoIGluc3QuZWxlbWVudFsgMCBdLCBldmVudCwgeyBpdGVtOiB0aGlzLmN1cnJlbnRJdGVtIH0gKSA6XG5cdFx0XHRcdFx0XHRcdCQoIGluc3Qub3B0aW9ucy5pdGVtcywgaW5zdC5lbGVtZW50ICksIGluc3QgXSApO1xuXHRcdFx0XHRcdFx0dGhpcy5jb250YWluZXJzLnB1c2goIGluc3QgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRmb3IgKCBpID0gcXVlcmllcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdHRhcmdldERhdGEgPSBxdWVyaWVzWyBpIF1bIDEgXTtcblx0XHRcdF9xdWVyaWVzID0gcXVlcmllc1sgaSBdWyAwIF07XG5cblx0XHRcdGZvciAoIGogPSAwLCBxdWVyaWVzTGVuZ3RoID0gX3F1ZXJpZXMubGVuZ3RoOyBqIDwgcXVlcmllc0xlbmd0aDsgaisrICkge1xuXHRcdFx0XHRpdGVtID0gJCggX3F1ZXJpZXNbIGogXSApO1xuXG5cdFx0XHRcdC8vIERhdGEgZm9yIHRhcmdldCBjaGVja2luZyAobW91c2UgbWFuYWdlcilcblx0XHRcdFx0aXRlbS5kYXRhKCB0aGlzLndpZGdldE5hbWUgKyBcIi1pdGVtXCIsIHRhcmdldERhdGEgKTtcblxuXHRcdFx0XHRpdGVtcy5wdXNoKCB7XG5cdFx0XHRcdFx0aXRlbTogaXRlbSxcblx0XHRcdFx0XHRpbnN0YW5jZTogdGFyZ2V0RGF0YSxcblx0XHRcdFx0XHR3aWR0aDogMCwgaGVpZ2h0OiAwLFxuXHRcdFx0XHRcdGxlZnQ6IDAsIHRvcDogMFxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdH0sXG5cblx0cmVmcmVzaFBvc2l0aW9uczogZnVuY3Rpb24oIGZhc3QgKSB7XG5cblx0XHQvLyBEZXRlcm1pbmUgd2hldGhlciBpdGVtcyBhcmUgYmVpbmcgZGlzcGxheWVkIGhvcml6b250YWxseVxuXHRcdHRoaXMuZmxvYXRpbmcgPSB0aGlzLml0ZW1zLmxlbmd0aCA/XG5cdFx0XHR0aGlzLm9wdGlvbnMuYXhpcyA9PT0gXCJ4XCIgfHwgdGhpcy5faXNGbG9hdGluZyggdGhpcy5pdGVtc1sgMCBdLml0ZW0gKSA6XG5cdFx0XHRmYWxzZTtcblxuXHRcdC8vVGhpcyBoYXMgdG8gYmUgcmVkb25lIGJlY2F1c2UgZHVlIHRvIHRoZSBpdGVtIGJlaW5nIG1vdmVkIG91dC9pbnRvIHRoZSBvZmZzZXRQYXJlbnQsXG5cdFx0Ly8gdGhlIG9mZnNldFBhcmVudCdzIHBvc2l0aW9uIHdpbGwgY2hhbmdlXG5cdFx0aWYgKCB0aGlzLm9mZnNldFBhcmVudCAmJiB0aGlzLmhlbHBlciApIHtcblx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudCA9IHRoaXMuX2dldFBhcmVudE9mZnNldCgpO1xuXHRcdH1cblxuXHRcdHZhciBpLCBpdGVtLCB0LCBwO1xuXG5cdFx0Zm9yICggaSA9IHRoaXMuaXRlbXMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHRpdGVtID0gdGhpcy5pdGVtc1sgaSBdO1xuXG5cdFx0XHQvL1dlIGlnbm9yZSBjYWxjdWxhdGluZyBwb3NpdGlvbnMgb2YgYWxsIGNvbm5lY3RlZCBjb250YWluZXJzIHdoZW4gd2UncmUgbm90IG92ZXIgdGhlbVxuXHRcdFx0aWYgKCBpdGVtLmluc3RhbmNlICE9PSB0aGlzLmN1cnJlbnRDb250YWluZXIgJiYgdGhpcy5jdXJyZW50Q29udGFpbmVyICYmXG5cdFx0XHRcdFx0aXRlbS5pdGVtWyAwIF0gIT09IHRoaXMuY3VycmVudEl0ZW1bIDAgXSApIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdHQgPSB0aGlzLm9wdGlvbnMudG9sZXJhbmNlRWxlbWVudCA/XG5cdFx0XHRcdCQoIHRoaXMub3B0aW9ucy50b2xlcmFuY2VFbGVtZW50LCBpdGVtLml0ZW0gKSA6XG5cdFx0XHRcdGl0ZW0uaXRlbTtcblxuXHRcdFx0aWYgKCAhZmFzdCApIHtcblx0XHRcdFx0aXRlbS53aWR0aCA9IHQub3V0ZXJXaWR0aCgpO1xuXHRcdFx0XHRpdGVtLmhlaWdodCA9IHQub3V0ZXJIZWlnaHQoKTtcblx0XHRcdH1cblxuXHRcdFx0cCA9IHQub2Zmc2V0KCk7XG5cdFx0XHRpdGVtLmxlZnQgPSBwLmxlZnQ7XG5cdFx0XHRpdGVtLnRvcCA9IHAudG9wO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmN1c3RvbSAmJiB0aGlzLm9wdGlvbnMuY3VzdG9tLnJlZnJlc2hDb250YWluZXJzICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLmN1c3RvbS5yZWZyZXNoQ29udGFpbmVycy5jYWxsKCB0aGlzICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAoIGkgPSB0aGlzLmNvbnRhaW5lcnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHRcdHAgPSB0aGlzLmNvbnRhaW5lcnNbIGkgXS5lbGVtZW50Lm9mZnNldCgpO1xuXHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS5sZWZ0ID0gcC5sZWZ0O1xuXHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS50b3AgPSBwLnRvcDtcblx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUud2lkdGggPVxuXHRcdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmVsZW1lbnQub3V0ZXJXaWR0aCgpO1xuXHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS5oZWlnaHQgPVxuXHRcdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmVsZW1lbnQub3V0ZXJIZWlnaHQoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRfY3JlYXRlUGxhY2Vob2xkZXI6IGZ1bmN0aW9uKCB0aGF0ICkge1xuXHRcdHRoYXQgPSB0aGF0IHx8IHRoaXM7XG5cdFx0dmFyIGNsYXNzTmFtZSxcblx0XHRcdG8gPSB0aGF0Lm9wdGlvbnM7XG5cblx0XHRpZiAoICFvLnBsYWNlaG9sZGVyIHx8IG8ucGxhY2Vob2xkZXIuY29uc3RydWN0b3IgPT09IFN0cmluZyApIHtcblx0XHRcdGNsYXNzTmFtZSA9IG8ucGxhY2Vob2xkZXI7XG5cdFx0XHRvLnBsYWNlaG9sZGVyID0ge1xuXHRcdFx0XHRlbGVtZW50OiBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHRcdHZhciBub2RlTmFtZSA9IHRoYXQuY3VycmVudEl0ZW1bIDAgXS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpLFxuXHRcdFx0XHRcdFx0ZWxlbWVudCA9ICQoIFwiPFwiICsgbm9kZU5hbWUgKyBcIj5cIiwgdGhhdC5kb2N1bWVudFsgMCBdICk7XG5cblx0XHRcdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBlbGVtZW50LCBcInVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyXCIsXG5cdFx0XHRcdFx0XHRcdFx0Y2xhc3NOYW1lIHx8IHRoYXQuY3VycmVudEl0ZW1bIDAgXS5jbGFzc05hbWUgKVxuXHRcdFx0XHRcdFx0XHQuX3JlbW92ZUNsYXNzKCBlbGVtZW50LCBcInVpLXNvcnRhYmxlLWhlbHBlclwiICk7XG5cblx0XHRcdFx0XHRpZiAoIG5vZGVOYW1lID09PSBcInRib2R5XCIgKSB7XG5cdFx0XHRcdFx0XHR0aGF0Ll9jcmVhdGVUclBsYWNlaG9sZGVyKFxuXHRcdFx0XHRcdFx0XHR0aGF0LmN1cnJlbnRJdGVtLmZpbmQoIFwidHJcIiApLmVxKCAwICksXG5cdFx0XHRcdFx0XHRcdCQoIFwiPHRyPlwiLCB0aGF0LmRvY3VtZW50WyAwIF0gKS5hcHBlbmRUbyggZWxlbWVudCApXG5cdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoIG5vZGVOYW1lID09PSBcInRyXCIgKSB7XG5cdFx0XHRcdFx0XHR0aGF0Ll9jcmVhdGVUclBsYWNlaG9sZGVyKCB0aGF0LmN1cnJlbnRJdGVtLCBlbGVtZW50ICk7XG5cdFx0XHRcdFx0fSBlbHNlIGlmICggbm9kZU5hbWUgPT09IFwiaW1nXCIgKSB7XG5cdFx0XHRcdFx0XHRlbGVtZW50LmF0dHIoIFwic3JjXCIsIHRoYXQuY3VycmVudEl0ZW0uYXR0ciggXCJzcmNcIiApICk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCAhY2xhc3NOYW1lICkge1xuXHRcdFx0XHRcdFx0ZWxlbWVudC5jc3MoIFwidmlzaWJpbGl0eVwiLCBcImhpZGRlblwiICk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0cmV0dXJuIGVsZW1lbnQ7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHVwZGF0ZTogZnVuY3Rpb24oIGNvbnRhaW5lciwgcCApIHtcblxuXHRcdFx0XHRcdC8vIDEuIElmIGEgY2xhc3NOYW1lIGlzIHNldCBhcyAncGxhY2Vob2xkZXIgb3B0aW9uLCB3ZSBkb24ndCBmb3JjZSBzaXplcyAtXG5cdFx0XHRcdFx0Ly8gdGhlIGNsYXNzIGlzIHJlc3BvbnNpYmxlIGZvciB0aGF0XG5cdFx0XHRcdFx0Ly8gMi4gVGhlIG9wdGlvbiAnZm9yY2VQbGFjZWhvbGRlclNpemUgY2FuIGJlIGVuYWJsZWQgdG8gZm9yY2UgaXQgZXZlbiBpZiBhXG5cdFx0XHRcdFx0Ly8gY2xhc3MgbmFtZSBpcyBzcGVjaWZpZWRcblx0XHRcdFx0XHRpZiAoIGNsYXNzTmFtZSAmJiAhby5mb3JjZVBsYWNlaG9sZGVyU2l6ZSApIHtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvL0lmIHRoZSBlbGVtZW50IGRvZXNuJ3QgaGF2ZSBhIGFjdHVhbCBoZWlnaHQgYnkgaXRzZWxmICh3aXRob3V0IHN0eWxlcyBjb21pbmdcblx0XHRcdFx0XHQvLyBmcm9tIGEgc3R5bGVzaGVldCksIGl0IHJlY2VpdmVzIHRoZSBpbmxpbmUgaGVpZ2h0IGZyb20gdGhlIGRyYWdnZWQgaXRlbVxuXHRcdFx0XHRcdGlmICggIXAuaGVpZ2h0KCkgKSB7XG5cdFx0XHRcdFx0XHRwLmhlaWdodChcblx0XHRcdFx0XHRcdFx0dGhhdC5jdXJyZW50SXRlbS5pbm5lckhlaWdodCgpIC1cblx0XHRcdFx0XHRcdFx0cGFyc2VJbnQoIHRoYXQuY3VycmVudEl0ZW0uY3NzKCBcInBhZGRpbmdUb3BcIiApIHx8IDAsIDEwICkgLVxuXHRcdFx0XHRcdFx0XHRwYXJzZUludCggdGhhdC5jdXJyZW50SXRlbS5jc3MoIFwicGFkZGluZ0JvdHRvbVwiICkgfHwgMCwgMTAgKSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZiAoICFwLndpZHRoKCkgKSB7XG5cdFx0XHRcdFx0XHRwLndpZHRoKFxuXHRcdFx0XHRcdFx0XHR0aGF0LmN1cnJlbnRJdGVtLmlubmVyV2lkdGgoKSAtXG5cdFx0XHRcdFx0XHRcdHBhcnNlSW50KCB0aGF0LmN1cnJlbnRJdGVtLmNzcyggXCJwYWRkaW5nTGVmdFwiICkgfHwgMCwgMTAgKSAtXG5cdFx0XHRcdFx0XHRcdHBhcnNlSW50KCB0aGF0LmN1cnJlbnRJdGVtLmNzcyggXCJwYWRkaW5nUmlnaHRcIiApIHx8IDAsIDEwICkgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0Ly9DcmVhdGUgdGhlIHBsYWNlaG9sZGVyXG5cdFx0dGhhdC5wbGFjZWhvbGRlciA9ICQoIG8ucGxhY2Vob2xkZXIuZWxlbWVudC5jYWxsKCB0aGF0LmVsZW1lbnQsIHRoYXQuY3VycmVudEl0ZW0gKSApO1xuXG5cdFx0Ly9BcHBlbmQgaXQgYWZ0ZXIgdGhlIGFjdHVhbCBjdXJyZW50IGl0ZW1cblx0XHR0aGF0LmN1cnJlbnRJdGVtLmFmdGVyKCB0aGF0LnBsYWNlaG9sZGVyICk7XG5cblx0XHQvL1VwZGF0ZSB0aGUgc2l6ZSBvZiB0aGUgcGxhY2Vob2xkZXIgKFRPRE86IExvZ2ljIHRvIGZ1enp5LCBzZWUgbGluZSAzMTYvMzE3KVxuXHRcdG8ucGxhY2Vob2xkZXIudXBkYXRlKCB0aGF0LCB0aGF0LnBsYWNlaG9sZGVyICk7XG5cblx0fSxcblxuXHRfY3JlYXRlVHJQbGFjZWhvbGRlcjogZnVuY3Rpb24oIHNvdXJjZVRyLCB0YXJnZXRUciApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHRzb3VyY2VUci5jaGlsZHJlbigpLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0JCggXCI8dGQ+JiMxNjA7PC90ZD5cIiwgdGhhdC5kb2N1bWVudFsgMCBdIClcblx0XHRcdFx0LmF0dHIoIFwiY29sc3BhblwiLCAkKCB0aGlzICkuYXR0ciggXCJjb2xzcGFuXCIgKSB8fCAxIClcblx0XHRcdFx0LmFwcGVuZFRvKCB0YXJnZXRUciApO1xuXHRcdH0gKTtcblx0fSxcblxuXHRfY29udGFjdENvbnRhaW5lcnM6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgaSwgaiwgZGlzdCwgaXRlbVdpdGhMZWFzdERpc3RhbmNlLCBwb3NQcm9wZXJ0eSwgc2l6ZVByb3BlcnR5LCBjdXIsIG5lYXJCb3R0b20sXG5cdFx0XHRmbG9hdGluZywgYXhpcyxcblx0XHRcdGlubmVybW9zdENvbnRhaW5lciA9IG51bGwsXG5cdFx0XHRpbm5lcm1vc3RJbmRleCA9IG51bGw7XG5cblx0XHQvLyBHZXQgaW5uZXJtb3N0IGNvbnRhaW5lciB0aGF0IGludGVyc2VjdHMgd2l0aCBpdGVtXG5cdFx0Zm9yICggaSA9IHRoaXMuY29udGFpbmVycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblxuXHRcdFx0Ly8gTmV2ZXIgY29uc2lkZXIgYSBjb250YWluZXIgdGhhdCdzIGxvY2F0ZWQgd2l0aGluIHRoZSBpdGVtIGl0c2VsZlxuXHRcdFx0aWYgKCAkLmNvbnRhaW5zKCB0aGlzLmN1cnJlbnRJdGVtWyAwIF0sIHRoaXMuY29udGFpbmVyc1sgaSBdLmVsZW1lbnRbIDAgXSApICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0aGlzLl9pbnRlcnNlY3RzV2l0aCggdGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUgKSApIHtcblxuXHRcdFx0XHQvLyBJZiB3ZSd2ZSBhbHJlYWR5IGZvdW5kIGEgY29udGFpbmVyIGFuZCBpdCdzIG1vcmUgXCJpbm5lclwiIHRoYW4gdGhpcywgdGhlbiBjb250aW51ZVxuXHRcdFx0XHRpZiAoIGlubmVybW9zdENvbnRhaW5lciAmJlxuXHRcdFx0XHRcdFx0JC5jb250YWlucyhcblx0XHRcdFx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uZWxlbWVudFsgMCBdLFxuXHRcdFx0XHRcdFx0XHRpbm5lcm1vc3RDb250YWluZXIuZWxlbWVudFsgMCBdICkgKSB7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpbm5lcm1vc3RDb250YWluZXIgPSB0aGlzLmNvbnRhaW5lcnNbIGkgXTtcblx0XHRcdFx0aW5uZXJtb3N0SW5kZXggPSBpO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIGNvbnRhaW5lciBkb2Vzbid0IGludGVyc2VjdC4gdHJpZ2dlciBcIm91dFwiIGV2ZW50IGlmIG5lY2Vzc2FyeVxuXHRcdFx0XHRpZiAoIHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLm92ZXIgKSB7XG5cdFx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uX3RyaWdnZXIoIFwib3V0XCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIHRoaXMgKSApO1xuXHRcdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLm92ZXIgPSAwO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBJZiBubyBpbnRlcnNlY3RpbmcgY29udGFpbmVycyBmb3VuZCwgcmV0dXJuXG5cdFx0aWYgKCAhaW5uZXJtb3N0Q29udGFpbmVyICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIE1vdmUgdGhlIGl0ZW0gaW50byB0aGUgY29udGFpbmVyIGlmIGl0J3Mgbm90IHRoZXJlIGFscmVhZHlcblx0XHRpZiAoIHRoaXMuY29udGFpbmVycy5sZW5ndGggPT09IDEgKSB7XG5cdFx0XHRpZiAoICF0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0uY29udGFpbmVyQ2FjaGUub3ZlciApIHtcblx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdLl90cmlnZ2VyKCBcIm92ZXJcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggdGhpcyApICk7XG5cdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXS5jb250YWluZXJDYWNoZS5vdmVyID0gMTtcblx0XHRcdH1cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBXaGVuIGVudGVyaW5nIGEgbmV3IGNvbnRhaW5lciwgd2Ugd2lsbCBmaW5kIHRoZSBpdGVtIHdpdGggdGhlIGxlYXN0IGRpc3RhbmNlIGFuZFxuXHRcdFx0Ly8gYXBwZW5kIG91ciBpdGVtIG5lYXIgaXRcblx0XHRcdGRpc3QgPSAxMDAwMDtcblx0XHRcdGl0ZW1XaXRoTGVhc3REaXN0YW5jZSA9IG51bGw7XG5cdFx0XHRmbG9hdGluZyA9IGlubmVybW9zdENvbnRhaW5lci5mbG9hdGluZyB8fCB0aGlzLl9pc0Zsb2F0aW5nKCB0aGlzLmN1cnJlbnRJdGVtICk7XG5cdFx0XHRwb3NQcm9wZXJ0eSA9IGZsb2F0aW5nID8gXCJsZWZ0XCIgOiBcInRvcFwiO1xuXHRcdFx0c2l6ZVByb3BlcnR5ID0gZmxvYXRpbmcgPyBcIndpZHRoXCIgOiBcImhlaWdodFwiO1xuXHRcdFx0YXhpcyA9IGZsb2F0aW5nID8gXCJwYWdlWFwiIDogXCJwYWdlWVwiO1xuXG5cdFx0XHRmb3IgKCBqID0gdGhpcy5pdGVtcy5sZW5ndGggLSAxOyBqID49IDA7IGotLSApIHtcblx0XHRcdFx0aWYgKCAhJC5jb250YWlucyhcblx0XHRcdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXS5lbGVtZW50WyAwIF0sIHRoaXMuaXRlbXNbIGogXS5pdGVtWyAwIF0gKVxuXHRcdFx0XHQpIHtcblx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIHRoaXMuaXRlbXNbIGogXS5pdGVtWyAwIF0gPT09IHRoaXMuY3VycmVudEl0ZW1bIDAgXSApIHtcblx0XHRcdFx0XHRjb250aW51ZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGN1ciA9IHRoaXMuaXRlbXNbIGogXS5pdGVtLm9mZnNldCgpWyBwb3NQcm9wZXJ0eSBdO1xuXHRcdFx0XHRuZWFyQm90dG9tID0gZmFsc2U7XG5cdFx0XHRcdGlmICggZXZlbnRbIGF4aXMgXSAtIGN1ciA+IHRoaXMuaXRlbXNbIGogXVsgc2l6ZVByb3BlcnR5IF0gLyAyICkge1xuXHRcdFx0XHRcdG5lYXJCb3R0b20gPSB0cnVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBNYXRoLmFicyggZXZlbnRbIGF4aXMgXSAtIGN1ciApIDwgZGlzdCApIHtcblx0XHRcdFx0XHRkaXN0ID0gTWF0aC5hYnMoIGV2ZW50WyBheGlzIF0gLSBjdXIgKTtcblx0XHRcdFx0XHRpdGVtV2l0aExlYXN0RGlzdGFuY2UgPSB0aGlzLml0ZW1zWyBqIF07XG5cdFx0XHRcdFx0dGhpcy5kaXJlY3Rpb24gPSBuZWFyQm90dG9tID8gXCJ1cFwiIDogXCJkb3duXCI7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly9DaGVjayBpZiBkcm9wT25FbXB0eSBpcyBlbmFibGVkXG5cdFx0XHRpZiAoICFpdGVtV2l0aExlYXN0RGlzdGFuY2UgJiYgIXRoaXMub3B0aW9ucy5kcm9wT25FbXB0eSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRoaXMuY3VycmVudENvbnRhaW5lciA9PT0gdGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdICkge1xuXHRcdFx0XHRpZiAoICF0aGlzLmN1cnJlbnRDb250YWluZXIuY29udGFpbmVyQ2FjaGUub3ZlciApIHtcblx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0uX3RyaWdnZXIoIFwib3ZlclwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCkgKTtcblx0XHRcdFx0XHR0aGlzLmN1cnJlbnRDb250YWluZXIuY29udGFpbmVyQ2FjaGUub3ZlciA9IDE7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRpdGVtV2l0aExlYXN0RGlzdGFuY2UgP1xuXHRcdFx0XHR0aGlzLl9yZWFycmFuZ2UoIGV2ZW50LCBpdGVtV2l0aExlYXN0RGlzdGFuY2UsIG51bGwsIHRydWUgKSA6XG5cdFx0XHRcdHRoaXMuX3JlYXJyYW5nZSggZXZlbnQsIG51bGwsIHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXS5lbGVtZW50LCB0cnVlICk7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNoYW5nZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCkgKTtcblx0XHRcdHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXS5fdHJpZ2dlciggXCJjaGFuZ2VcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggdGhpcyApICk7XG5cdFx0XHR0aGlzLmN1cnJlbnRDb250YWluZXIgPSB0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF07XG5cblx0XHRcdC8vVXBkYXRlIHRoZSBwbGFjZWhvbGRlclxuXHRcdFx0dGhpcy5vcHRpb25zLnBsYWNlaG9sZGVyLnVwZGF0ZSggdGhpcy5jdXJyZW50Q29udGFpbmVyLCB0aGlzLnBsYWNlaG9sZGVyICk7XG5cblx0XHRcdHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXS5fdHJpZ2dlciggXCJvdmVyXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIHRoaXMgKSApO1xuXHRcdFx0dGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdLmNvbnRhaW5lckNhY2hlLm92ZXIgPSAxO1xuXHRcdH1cblxuXHR9LFxuXG5cdF9jcmVhdGVIZWxwZXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHZhciBvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0aGVscGVyID0gJC5pc0Z1bmN0aW9uKCBvLmhlbHBlciApID9cblx0XHRcdFx0JCggby5oZWxwZXIuYXBwbHkoIHRoaXMuZWxlbWVudFsgMCBdLCBbIGV2ZW50LCB0aGlzLmN1cnJlbnRJdGVtIF0gKSApIDpcblx0XHRcdFx0KCBvLmhlbHBlciA9PT0gXCJjbG9uZVwiID8gdGhpcy5jdXJyZW50SXRlbS5jbG9uZSgpIDogdGhpcy5jdXJyZW50SXRlbSApO1xuXG5cdFx0Ly9BZGQgdGhlIGhlbHBlciB0byB0aGUgRE9NIGlmIHRoYXQgZGlkbid0IGhhcHBlbiBhbHJlYWR5XG5cdFx0aWYgKCAhaGVscGVyLnBhcmVudHMoIFwiYm9keVwiICkubGVuZ3RoICkge1xuXHRcdFx0JCggby5hcHBlbmRUbyAhPT0gXCJwYXJlbnRcIiA/XG5cdFx0XHRcdG8uYXBwZW5kVG8gOlxuXHRcdFx0XHR0aGlzLmN1cnJlbnRJdGVtWyAwIF0ucGFyZW50Tm9kZSApWyAwIF0uYXBwZW5kQ2hpbGQoIGhlbHBlclsgMCBdICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBoZWxwZXJbIDAgXSA9PT0gdGhpcy5jdXJyZW50SXRlbVsgMCBdICkge1xuXHRcdFx0dGhpcy5fc3RvcmVkQ1NTID0ge1xuXHRcdFx0XHR3aWR0aDogdGhpcy5jdXJyZW50SXRlbVsgMCBdLnN0eWxlLndpZHRoLFxuXHRcdFx0XHRoZWlnaHQ6IHRoaXMuY3VycmVudEl0ZW1bIDAgXS5zdHlsZS5oZWlnaHQsXG5cdFx0XHRcdHBvc2l0aW9uOiB0aGlzLmN1cnJlbnRJdGVtLmNzcyggXCJwb3NpdGlvblwiICksXG5cdFx0XHRcdHRvcDogdGhpcy5jdXJyZW50SXRlbS5jc3MoIFwidG9wXCIgKSxcblx0XHRcdFx0bGVmdDogdGhpcy5jdXJyZW50SXRlbS5jc3MoIFwibGVmdFwiIClcblx0XHRcdH07XG5cdFx0fVxuXG5cdFx0aWYgKCAhaGVscGVyWyAwIF0uc3R5bGUud2lkdGggfHwgby5mb3JjZUhlbHBlclNpemUgKSB7XG5cdFx0XHRoZWxwZXIud2lkdGgoIHRoaXMuY3VycmVudEl0ZW0ud2lkdGgoKSApO1xuXHRcdH1cblx0XHRpZiAoICFoZWxwZXJbIDAgXS5zdHlsZS5oZWlnaHQgfHwgby5mb3JjZUhlbHBlclNpemUgKSB7XG5cdFx0XHRoZWxwZXIuaGVpZ2h0KCB0aGlzLmN1cnJlbnRJdGVtLmhlaWdodCgpICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGhlbHBlcjtcblxuXHR9LFxuXG5cdF9hZGp1c3RPZmZzZXRGcm9tSGVscGVyOiBmdW5jdGlvbiggb2JqICkge1xuXHRcdGlmICggdHlwZW9mIG9iaiA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdG9iaiA9IG9iai5zcGxpdCggXCIgXCIgKTtcblx0XHR9XG5cdFx0aWYgKCAkLmlzQXJyYXkoIG9iaiApICkge1xuXHRcdFx0b2JqID0geyBsZWZ0OiArb2JqWyAwIF0sIHRvcDogK29ialsgMSBdIHx8IDAgfTtcblx0XHR9XG5cdFx0aWYgKCBcImxlZnRcIiBpbiBvYmogKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5jbGljay5sZWZ0ID0gb2JqLmxlZnQgKyB0aGlzLm1hcmdpbnMubGVmdDtcblx0XHR9XG5cdFx0aWYgKCBcInJpZ2h0XCIgaW4gb2JqICkge1xuXHRcdFx0dGhpcy5vZmZzZXQuY2xpY2subGVmdCA9IHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLSBvYmoucmlnaHQgKyB0aGlzLm1hcmdpbnMubGVmdDtcblx0XHR9XG5cdFx0aWYgKCBcInRvcFwiIGluIG9iaiApIHtcblx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA9IG9iai50b3AgKyB0aGlzLm1hcmdpbnMudG9wO1xuXHRcdH1cblx0XHRpZiAoIFwiYm90dG9tXCIgaW4gb2JqICkge1xuXHRcdFx0dGhpcy5vZmZzZXQuY2xpY2sudG9wID0gdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLSBvYmouYm90dG9tICsgdGhpcy5tYXJnaW5zLnRvcDtcblx0XHR9XG5cdH0sXG5cblx0X2dldFBhcmVudE9mZnNldDogZnVuY3Rpb24oKSB7XG5cblx0XHQvL0dldCB0aGUgb2Zmc2V0UGFyZW50IGFuZCBjYWNoZSBpdHMgcG9zaXRpb25cblx0XHR0aGlzLm9mZnNldFBhcmVudCA9IHRoaXMuaGVscGVyLm9mZnNldFBhcmVudCgpO1xuXHRcdHZhciBwbyA9IHRoaXMub2Zmc2V0UGFyZW50Lm9mZnNldCgpO1xuXG5cdFx0Ly8gVGhpcyBpcyBhIHNwZWNpYWwgY2FzZSB3aGVyZSB3ZSBuZWVkIHRvIG1vZGlmeSBhIG9mZnNldCBjYWxjdWxhdGVkIG9uIHN0YXJ0LCBzaW5jZSB0aGVcblx0XHQvLyBmb2xsb3dpbmcgaGFwcGVuZWQ6XG5cdFx0Ly8gMS4gVGhlIHBvc2l0aW9uIG9mIHRoZSBoZWxwZXIgaXMgYWJzb2x1dGUsIHNvIGl0J3MgcG9zaXRpb24gaXMgY2FsY3VsYXRlZCBiYXNlZCBvbiB0aGVcblx0XHQvLyBuZXh0IHBvc2l0aW9uZWQgcGFyZW50XG5cdFx0Ly8gMi4gVGhlIGFjdHVhbCBvZmZzZXQgcGFyZW50IGlzIGEgY2hpbGQgb2YgdGhlIHNjcm9sbCBwYXJlbnQsIGFuZCB0aGUgc2Nyb2xsIHBhcmVudCBpc24ndFxuXHRcdC8vIHRoZSBkb2N1bWVudCwgd2hpY2ggbWVhbnMgdGhhdCB0aGUgc2Nyb2xsIGlzIGluY2x1ZGVkIGluIHRoZSBpbml0aWFsIGNhbGN1bGF0aW9uIG9mIHRoZVxuXHRcdC8vIG9mZnNldCBvZiB0aGUgcGFyZW50LCBhbmQgbmV2ZXIgcmVjYWxjdWxhdGVkIHVwb24gZHJhZ1xuXHRcdGlmICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiICYmIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gIT09IHRoaXMuZG9jdW1lbnRbIDAgXSAmJlxuXHRcdFx0XHQkLmNvbnRhaW5zKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdLCB0aGlzLm9mZnNldFBhcmVudFsgMCBdICkgKSB7XG5cdFx0XHRwby5sZWZ0ICs9IHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbExlZnQoKTtcblx0XHRcdHBvLnRvcCArPSB0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxUb3AoKTtcblx0XHR9XG5cblx0XHQvLyBUaGlzIG5lZWRzIHRvIGJlIGFjdHVhbGx5IGRvbmUgZm9yIGFsbCBicm93c2Vycywgc2luY2UgcGFnZVgvcGFnZVkgaW5jbHVkZXMgdGhpc1xuXHRcdC8vIGluZm9ybWF0aW9uIHdpdGggYW4gdWdseSBJRSBmaXhcblx0XHRpZiAoIHRoaXMub2Zmc2V0UGFyZW50WyAwIF0gPT09IHRoaXMuZG9jdW1lbnRbIDAgXS5ib2R5IHx8XG5cdFx0XHRcdCggdGhpcy5vZmZzZXRQYXJlbnRbIDAgXS50YWdOYW1lICYmXG5cdFx0XHRcdHRoaXMub2Zmc2V0UGFyZW50WyAwIF0udGFnTmFtZS50b0xvd2VyQ2FzZSgpID09PSBcImh0bWxcIiAmJiAkLnVpLmllICkgKSB7XG5cdFx0XHRwbyA9IHsgdG9wOiAwLCBsZWZ0OiAwIH07XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogcG8udG9wICsgKCBwYXJzZUludCggdGhpcy5vZmZzZXRQYXJlbnQuY3NzKCBcImJvcmRlclRvcFdpZHRoXCIgKSwgMTAgKSB8fCAwICksXG5cdFx0XHRsZWZ0OiBwby5sZWZ0ICsgKCBwYXJzZUludCggdGhpcy5vZmZzZXRQYXJlbnQuY3NzKCBcImJvcmRlckxlZnRXaWR0aFwiICksIDEwICkgfHwgMCApXG5cdFx0fTtcblxuXHR9LFxuXG5cdF9nZXRSZWxhdGl2ZU9mZnNldDogZnVuY3Rpb24oKSB7XG5cblx0XHRpZiAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwicmVsYXRpdmVcIiApIHtcblx0XHRcdHZhciBwID0gdGhpcy5jdXJyZW50SXRlbS5wb3NpdGlvbigpO1xuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0dG9wOiBwLnRvcCAtICggcGFyc2VJbnQoIHRoaXMuaGVscGVyLmNzcyggXCJ0b3BcIiApLCAxMCApIHx8IDAgKSArXG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsVG9wKCksXG5cdFx0XHRcdGxlZnQ6IHAubGVmdCAtICggcGFyc2VJbnQoIHRoaXMuaGVscGVyLmNzcyggXCJsZWZ0XCIgKSwgMTAgKSB8fCAwICkgK1xuXHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbExlZnQoKVxuXHRcdFx0fTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0cmV0dXJuIHsgdG9wOiAwLCBsZWZ0OiAwIH07XG5cdFx0fVxuXG5cdH0sXG5cblx0X2NhY2hlTWFyZ2luczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5tYXJnaW5zID0ge1xuXHRcdFx0bGVmdDogKCBwYXJzZUludCggdGhpcy5jdXJyZW50SXRlbS5jc3MoIFwibWFyZ2luTGVmdFwiICksIDEwICkgfHwgMCApLFxuXHRcdFx0dG9wOiAoIHBhcnNlSW50KCB0aGlzLmN1cnJlbnRJdGVtLmNzcyggXCJtYXJnaW5Ub3BcIiApLCAxMCApIHx8IDAgKVxuXHRcdH07XG5cdH0sXG5cblx0X2NhY2hlSGVscGVyUHJvcG9ydGlvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMgPSB7XG5cdFx0XHR3aWR0aDogdGhpcy5oZWxwZXIub3V0ZXJXaWR0aCgpLFxuXHRcdFx0aGVpZ2h0OiB0aGlzLmhlbHBlci5vdXRlckhlaWdodCgpXG5cdFx0fTtcblx0fSxcblxuXHRfc2V0Q29udGFpbm1lbnQ6IGZ1bmN0aW9uKCkge1xuXG5cdFx0dmFyIGNlLCBjbywgb3Zlcixcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnM7XG5cdFx0aWYgKCBvLmNvbnRhaW5tZW50ID09PSBcInBhcmVudFwiICkge1xuXHRcdFx0by5jb250YWlubWVudCA9IHRoaXMuaGVscGVyWyAwIF0ucGFyZW50Tm9kZTtcblx0XHR9XG5cdFx0aWYgKCBvLmNvbnRhaW5tZW50ID09PSBcImRvY3VtZW50XCIgfHwgby5jb250YWlubWVudCA9PT0gXCJ3aW5kb3dcIiApIHtcblx0XHRcdHRoaXMuY29udGFpbm1lbnQgPSBbXG5cdFx0XHRcdDAgLSB0aGlzLm9mZnNldC5yZWxhdGl2ZS5sZWZ0IC0gdGhpcy5vZmZzZXQucGFyZW50LmxlZnQsXG5cdFx0XHRcdDAgLSB0aGlzLm9mZnNldC5yZWxhdGl2ZS50b3AgLSB0aGlzLm9mZnNldC5wYXJlbnQudG9wLFxuXHRcdFx0XHRvLmNvbnRhaW5tZW50ID09PSBcImRvY3VtZW50XCIgP1xuXHRcdFx0XHRcdHRoaXMuZG9jdW1lbnQud2lkdGgoKSA6XG5cdFx0XHRcdFx0dGhpcy53aW5kb3cud2lkdGgoKSAtIHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLSB0aGlzLm1hcmdpbnMubGVmdCxcblx0XHRcdFx0KCBvLmNvbnRhaW5tZW50ID09PSBcImRvY3VtZW50XCIgP1xuXHRcdFx0XHRcdCggdGhpcy5kb2N1bWVudC5oZWlnaHQoKSB8fCBkb2N1bWVudC5ib2R5LnBhcmVudE5vZGUuc2Nyb2xsSGVpZ2h0ICkgOlxuXHRcdFx0XHRcdHRoaXMud2luZG93LmhlaWdodCgpIHx8IHRoaXMuZG9jdW1lbnRbIDAgXS5ib2R5LnBhcmVudE5vZGUuc2Nyb2xsSGVpZ2h0XG5cdFx0XHRcdCkgLSB0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAtIHRoaXMubWFyZ2lucy50b3Bcblx0XHRcdF07XG5cdFx0fVxuXG5cdFx0aWYgKCAhKCAvXihkb2N1bWVudHx3aW5kb3d8cGFyZW50KSQvICkudGVzdCggby5jb250YWlubWVudCApICkge1xuXHRcdFx0Y2UgPSAkKCBvLmNvbnRhaW5tZW50IClbIDAgXTtcblx0XHRcdGNvID0gJCggby5jb250YWlubWVudCApLm9mZnNldCgpO1xuXHRcdFx0b3ZlciA9ICggJCggY2UgKS5jc3MoIFwib3ZlcmZsb3dcIiApICE9PSBcImhpZGRlblwiICk7XG5cblx0XHRcdHRoaXMuY29udGFpbm1lbnQgPSBbXG5cdFx0XHRcdGNvLmxlZnQgKyAoIHBhcnNlSW50KCAkKCBjZSApLmNzcyggXCJib3JkZXJMZWZ0V2lkdGhcIiApLCAxMCApIHx8IDAgKSArXG5cdFx0XHRcdFx0KCBwYXJzZUludCggJCggY2UgKS5jc3MoIFwicGFkZGluZ0xlZnRcIiApLCAxMCApIHx8IDAgKSAtIHRoaXMubWFyZ2lucy5sZWZ0LFxuXHRcdFx0XHRjby50b3AgKyAoIHBhcnNlSW50KCAkKCBjZSApLmNzcyggXCJib3JkZXJUb3BXaWR0aFwiICksIDEwICkgfHwgMCApICtcblx0XHRcdFx0XHQoIHBhcnNlSW50KCAkKCBjZSApLmNzcyggXCJwYWRkaW5nVG9wXCIgKSwgMTAgKSB8fCAwICkgLSB0aGlzLm1hcmdpbnMudG9wLFxuXHRcdFx0XHRjby5sZWZ0ICsgKCBvdmVyID8gTWF0aC5tYXgoIGNlLnNjcm9sbFdpZHRoLCBjZS5vZmZzZXRXaWR0aCApIDogY2Uub2Zmc2V0V2lkdGggKSAtXG5cdFx0XHRcdFx0KCBwYXJzZUludCggJCggY2UgKS5jc3MoIFwiYm9yZGVyTGVmdFdpZHRoXCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHRcdCggcGFyc2VJbnQoICQoIGNlICkuY3NzKCBcInBhZGRpbmdSaWdodFwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC0gdGhpcy5tYXJnaW5zLmxlZnQsXG5cdFx0XHRcdGNvLnRvcCArICggb3ZlciA/IE1hdGgubWF4KCBjZS5zY3JvbGxIZWlnaHQsIGNlLm9mZnNldEhlaWdodCApIDogY2Uub2Zmc2V0SGVpZ2h0ICkgLVxuXHRcdFx0XHRcdCggcGFyc2VJbnQoICQoIGNlICkuY3NzKCBcImJvcmRlclRvcFdpZHRoXCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHRcdCggcGFyc2VJbnQoICQoIGNlICkuY3NzKCBcInBhZGRpbmdCb3R0b21cIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLSB0aGlzLm1hcmdpbnMudG9wXG5cdFx0XHRdO1xuXHRcdH1cblxuXHR9LFxuXG5cdF9jb252ZXJ0UG9zaXRpb25UbzogZnVuY3Rpb24oIGQsIHBvcyApIHtcblxuXHRcdGlmICggIXBvcyApIHtcblx0XHRcdHBvcyA9IHRoaXMucG9zaXRpb247XG5cdFx0fVxuXHRcdHZhciBtb2QgPSBkID09PSBcImFic29sdXRlXCIgPyAxIDogLTEsXG5cdFx0XHRzY3JvbGwgPSB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImFic29sdXRlXCIgJiZcblx0XHRcdFx0ISggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSAhPT0gdGhpcy5kb2N1bWVudFsgMCBdICYmXG5cdFx0XHRcdCQuY29udGFpbnMoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0sIHRoaXMub2Zmc2V0UGFyZW50WyAwIF0gKSApID9cblx0XHRcdFx0XHR0aGlzLm9mZnNldFBhcmVudCA6XG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnQsXG5cdFx0XHRzY3JvbGxJc1Jvb3ROb2RlID0gKCAvKGh0bWx8Ym9keSkvaSApLnRlc3QoIHNjcm9sbFsgMCBdLnRhZ05hbWUgKTtcblxuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IChcblxuXHRcdFx0XHQvLyBUaGUgYWJzb2x1dGUgbW91c2UgcG9zaXRpb25cblx0XHRcdFx0cG9zLnRvcFx0K1xuXG5cdFx0XHRcdC8vIE9ubHkgZm9yIHJlbGF0aXZlIHBvc2l0aW9uZWQgbm9kZXM6IFJlbGF0aXZlIG9mZnNldCBmcm9tIGVsZW1lbnQgdG8gb2Zmc2V0IHBhcmVudFxuXHRcdFx0XHR0aGlzLm9mZnNldC5yZWxhdGl2ZS50b3AgKiBtb2QgK1xuXG5cdFx0XHRcdC8vIFRoZSBvZmZzZXRQYXJlbnQncyBvZmZzZXQgd2l0aG91dCBib3JkZXJzIChvZmZzZXQgKyBib3JkZXIpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudC50b3AgKiBtb2QgLVxuXHRcdFx0XHQoICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJmaXhlZFwiID9cblx0XHRcdFx0XHQtdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsVG9wKCkgOlxuXHRcdFx0XHRcdCggc2Nyb2xsSXNSb290Tm9kZSA/IDAgOiBzY3JvbGwuc2Nyb2xsVG9wKCkgKSApICogbW9kIClcblx0XHRcdCksXG5cdFx0XHRsZWZ0OiAoXG5cblx0XHRcdFx0Ly8gVGhlIGFic29sdXRlIG1vdXNlIHBvc2l0aW9uXG5cdFx0XHRcdHBvcy5sZWZ0ICtcblxuXHRcdFx0XHQvLyBPbmx5IGZvciByZWxhdGl2ZSBwb3NpdGlvbmVkIG5vZGVzOiBSZWxhdGl2ZSBvZmZzZXQgZnJvbSBlbGVtZW50IHRvIG9mZnNldCBwYXJlbnRcblx0XHRcdFx0dGhpcy5vZmZzZXQucmVsYXRpdmUubGVmdCAqIG1vZCArXG5cblx0XHRcdFx0Ly8gVGhlIG9mZnNldFBhcmVudCdzIG9mZnNldCB3aXRob3V0IGJvcmRlcnMgKG9mZnNldCArIGJvcmRlcilcblx0XHRcdFx0dGhpcy5vZmZzZXQucGFyZW50LmxlZnQgKiBtb2RcdC1cblx0XHRcdFx0KCAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiZml4ZWRcIiA/XG5cdFx0XHRcdFx0LXRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbExlZnQoKSA6IHNjcm9sbElzUm9vdE5vZGUgPyAwIDpcblx0XHRcdFx0XHRzY3JvbGwuc2Nyb2xsTGVmdCgpICkgKiBtb2QgKVxuXHRcdFx0KVxuXHRcdH07XG5cblx0fSxcblxuXHRfZ2VuZXJhdGVQb3NpdGlvbjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dmFyIHRvcCwgbGVmdCxcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRwYWdlWCA9IGV2ZW50LnBhZ2VYLFxuXHRcdFx0cGFnZVkgPSBldmVudC5wYWdlWSxcblx0XHRcdHNjcm9sbCA9IHRoaXMuY3NzUG9zaXRpb24gPT09IFwiYWJzb2x1dGVcIiAmJlxuXHRcdFx0XHQhKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICE9PSB0aGlzLmRvY3VtZW50WyAwIF0gJiZcblx0XHRcdFx0JC5jb250YWlucyggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSwgdGhpcy5vZmZzZXRQYXJlbnRbIDAgXSApICkgP1xuXHRcdFx0XHRcdHRoaXMub2Zmc2V0UGFyZW50IDpcblx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudCxcblx0XHRcdFx0c2Nyb2xsSXNSb290Tm9kZSA9ICggLyhodG1sfGJvZHkpL2kgKS50ZXN0KCBzY3JvbGxbIDAgXS50YWdOYW1lICk7XG5cblx0XHQvLyBUaGlzIGlzIGFub3RoZXIgdmVyeSB3ZWlyZCBzcGVjaWFsIGNhc2UgdGhhdCBvbmx5IGhhcHBlbnMgZm9yIHJlbGF0aXZlIGVsZW1lbnRzOlxuXHRcdC8vIDEuIElmIHRoZSBjc3MgcG9zaXRpb24gaXMgcmVsYXRpdmVcblx0XHQvLyAyLiBhbmQgdGhlIHNjcm9sbCBwYXJlbnQgaXMgdGhlIGRvY3VtZW50IG9yIHNpbWlsYXIgdG8gdGhlIG9mZnNldCBwYXJlbnRcblx0XHQvLyB3ZSBoYXZlIHRvIHJlZnJlc2ggdGhlIHJlbGF0aXZlIG9mZnNldCBkdXJpbmcgdGhlIHNjcm9sbCBzbyB0aGVyZSBhcmUgbm8ganVtcHNcblx0XHRpZiAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwicmVsYXRpdmVcIiAmJiAhKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICE9PSB0aGlzLmRvY3VtZW50WyAwIF0gJiZcblx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnRbIDAgXSAhPT0gdGhpcy5vZmZzZXRQYXJlbnRbIDAgXSApICkge1xuXHRcdFx0dGhpcy5vZmZzZXQucmVsYXRpdmUgPSB0aGlzLl9nZXRSZWxhdGl2ZU9mZnNldCgpO1xuXHRcdH1cblxuXHRcdC8qXG5cdFx0ICogLSBQb3NpdGlvbiBjb25zdHJhaW5pbmcgLVxuXHRcdCAqIENvbnN0cmFpbiB0aGUgcG9zaXRpb24gdG8gYSBtaXggb2YgZ3JpZCwgY29udGFpbm1lbnQuXG5cdFx0ICovXG5cblx0XHRpZiAoIHRoaXMub3JpZ2luYWxQb3NpdGlvbiApIHsgLy9JZiB3ZSBhcmUgbm90IGRyYWdnaW5nIHlldCwgd2Ugd29uJ3QgY2hlY2sgZm9yIG9wdGlvbnNcblxuXHRcdFx0aWYgKCB0aGlzLmNvbnRhaW5tZW50ICkge1xuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VYIC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA8IHRoaXMuY29udGFpbm1lbnRbIDAgXSApIHtcblx0XHRcdFx0XHRwYWdlWCA9IHRoaXMuY29udGFpbm1lbnRbIDAgXSArIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWSAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA8IHRoaXMuY29udGFpbm1lbnRbIDEgXSApIHtcblx0XHRcdFx0XHRwYWdlWSA9IHRoaXMuY29udGFpbm1lbnRbIDEgXSArIHRoaXMub2Zmc2V0LmNsaWNrLnRvcDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VYIC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA+IHRoaXMuY29udGFpbm1lbnRbIDIgXSApIHtcblx0XHRcdFx0XHRwYWdlWCA9IHRoaXMuY29udGFpbm1lbnRbIDIgXSArIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQ7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWSAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA+IHRoaXMuY29udGFpbm1lbnRbIDMgXSApIHtcblx0XHRcdFx0XHRwYWdlWSA9IHRoaXMuY29udGFpbm1lbnRbIDMgXSArIHRoaXMub2Zmc2V0LmNsaWNrLnRvcDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG8uZ3JpZCApIHtcblx0XHRcdFx0dG9wID0gdGhpcy5vcmlnaW5hbFBhZ2VZICsgTWF0aC5yb3VuZCggKCBwYWdlWSAtIHRoaXMub3JpZ2luYWxQYWdlWSApIC9cblx0XHRcdFx0XHRvLmdyaWRbIDEgXSApICogby5ncmlkWyAxIF07XG5cdFx0XHRcdHBhZ2VZID0gdGhpcy5jb250YWlubWVudCA/XG5cdFx0XHRcdFx0KCAoIHRvcCAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA+PSB0aGlzLmNvbnRhaW5tZW50WyAxIF0gJiZcblx0XHRcdFx0XHRcdHRvcCAtIHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA8PSB0aGlzLmNvbnRhaW5tZW50WyAzIF0gKSA/XG5cdFx0XHRcdFx0XHRcdHRvcCA6XG5cdFx0XHRcdFx0XHRcdCggKCB0b3AgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPj0gdGhpcy5jb250YWlubWVudFsgMSBdICkgP1xuXHRcdFx0XHRcdFx0XHRcdHRvcCAtIG8uZ3JpZFsgMSBdIDogdG9wICsgby5ncmlkWyAxIF0gKSApIDpcblx0XHRcdFx0XHRcdFx0XHR0b3A7XG5cblx0XHRcdFx0bGVmdCA9IHRoaXMub3JpZ2luYWxQYWdlWCArIE1hdGgucm91bmQoICggcGFnZVggLSB0aGlzLm9yaWdpbmFsUGFnZVggKSAvXG5cdFx0XHRcdFx0by5ncmlkWyAwIF0gKSAqIG8uZ3JpZFsgMCBdO1xuXHRcdFx0XHRwYWdlWCA9IHRoaXMuY29udGFpbm1lbnQgP1xuXHRcdFx0XHRcdCggKCBsZWZ0IC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA+PSB0aGlzLmNvbnRhaW5tZW50WyAwIF0gJiZcblx0XHRcdFx0XHRcdGxlZnQgLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0IDw9IHRoaXMuY29udGFpbm1lbnRbIDIgXSApID9cblx0XHRcdFx0XHRcdFx0bGVmdCA6XG5cdFx0XHRcdFx0XHRcdCggKCBsZWZ0IC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA+PSB0aGlzLmNvbnRhaW5tZW50WyAwIF0gKSA/XG5cdFx0XHRcdFx0XHRcdFx0bGVmdCAtIG8uZ3JpZFsgMCBdIDogbGVmdCArIG8uZ3JpZFsgMCBdICkgKSA6XG5cdFx0XHRcdFx0XHRcdFx0bGVmdDtcblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IChcblxuXHRcdFx0XHQvLyBUaGUgYWJzb2x1dGUgbW91c2UgcG9zaXRpb25cblx0XHRcdFx0cGFnZVkgLVxuXG5cdFx0XHRcdC8vIENsaWNrIG9mZnNldCAocmVsYXRpdmUgdG8gdGhlIGVsZW1lbnQpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLnRvcCAtXG5cblx0XHRcdFx0Ly8gT25seSBmb3IgcmVsYXRpdmUgcG9zaXRpb25lZCBub2RlczogUmVsYXRpdmUgb2Zmc2V0IGZyb20gZWxlbWVudCB0byBvZmZzZXQgcGFyZW50XG5cdFx0XHRcdHRoaXMub2Zmc2V0LnJlbGF0aXZlLnRvcCAtXG5cblx0XHRcdFx0Ly8gVGhlIG9mZnNldFBhcmVudCdzIG9mZnNldCB3aXRob3V0IGJvcmRlcnMgKG9mZnNldCArIGJvcmRlcilcblx0XHRcdFx0dGhpcy5vZmZzZXQucGFyZW50LnRvcCArXG5cdFx0XHRcdCggKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImZpeGVkXCIgP1xuXHRcdFx0XHRcdC10aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxUb3AoKSA6XG5cdFx0XHRcdFx0KCBzY3JvbGxJc1Jvb3ROb2RlID8gMCA6IHNjcm9sbC5zY3JvbGxUb3AoKSApICkgKVxuXHRcdFx0KSxcblx0XHRcdGxlZnQ6IChcblxuXHRcdFx0XHQvLyBUaGUgYWJzb2x1dGUgbW91c2UgcG9zaXRpb25cblx0XHRcdFx0cGFnZVggLVxuXG5cdFx0XHRcdC8vIENsaWNrIG9mZnNldCAocmVsYXRpdmUgdG8gdGhlIGVsZW1lbnQpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgLVxuXG5cdFx0XHRcdC8vIE9ubHkgZm9yIHJlbGF0aXZlIHBvc2l0aW9uZWQgbm9kZXM6IFJlbGF0aXZlIG9mZnNldCBmcm9tIGVsZW1lbnQgdG8gb2Zmc2V0IHBhcmVudFxuXHRcdFx0XHR0aGlzLm9mZnNldC5yZWxhdGl2ZS5sZWZ0IC1cblxuXHRcdFx0XHQvLyBUaGUgb2Zmc2V0UGFyZW50J3Mgb2Zmc2V0IHdpdGhvdXQgYm9yZGVycyAob2Zmc2V0ICsgYm9yZGVyKVxuXHRcdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQubGVmdCArXG5cdFx0XHRcdCggKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImZpeGVkXCIgP1xuXHRcdFx0XHRcdC10aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0KCkgOlxuXHRcdFx0XHRcdHNjcm9sbElzUm9vdE5vZGUgPyAwIDogc2Nyb2xsLnNjcm9sbExlZnQoKSApIClcblx0XHRcdClcblx0XHR9O1xuXG5cdH0sXG5cblx0X3JlYXJyYW5nZTogZnVuY3Rpb24oIGV2ZW50LCBpLCBhLCBoYXJkUmVmcmVzaCApIHtcblxuXHRcdGEgPyBhWyAwIF0uYXBwZW5kQ2hpbGQoIHRoaXMucGxhY2Vob2xkZXJbIDAgXSApIDpcblx0XHRcdGkuaXRlbVsgMCBdLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKCB0aGlzLnBsYWNlaG9sZGVyWyAwIF0sXG5cdFx0XHRcdCggdGhpcy5kaXJlY3Rpb24gPT09IFwiZG93blwiID8gaS5pdGVtWyAwIF0gOiBpLml0ZW1bIDAgXS5uZXh0U2libGluZyApICk7XG5cblx0XHQvL1ZhcmlvdXMgdGhpbmdzIGRvbmUgaGVyZSB0byBpbXByb3ZlIHRoZSBwZXJmb3JtYW5jZTpcblx0XHQvLyAxLiB3ZSBjcmVhdGUgYSBzZXRUaW1lb3V0LCB0aGF0IGNhbGxzIHJlZnJlc2hQb3NpdGlvbnNcblx0XHQvLyAyLiBvbiB0aGUgaW5zdGFuY2UsIHdlIGhhdmUgYSBjb3VudGVyIHZhcmlhYmxlLCB0aGF0IGdldCdzIGhpZ2hlciBhZnRlciBldmVyeSBhcHBlbmRcblx0XHQvLyAzLiBvbiB0aGUgbG9jYWwgc2NvcGUsIHdlIGNvcHkgdGhlIGNvdW50ZXIgdmFyaWFibGUsIGFuZCBjaGVjayBpbiB0aGUgdGltZW91dCxcblx0XHQvLyBpZiBpdCdzIHN0aWxsIHRoZSBzYW1lXG5cdFx0Ly8gNC4gdGhpcyBsZXRzIG9ubHkgdGhlIGxhc3QgYWRkaXRpb24gdG8gdGhlIHRpbWVvdXQgc3RhY2sgdGhyb3VnaFxuXHRcdHRoaXMuY291bnRlciA9IHRoaXMuY291bnRlciA/ICsrdGhpcy5jb3VudGVyIDogMTtcblx0XHR2YXIgY291bnRlciA9IHRoaXMuY291bnRlcjtcblxuXHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggY291bnRlciA9PT0gdGhpcy5jb3VudGVyICkge1xuXG5cdFx0XHRcdC8vUHJlY29tcHV0ZSBhZnRlciBlYWNoIERPTSBpbnNlcnRpb24sIE5PVCBvbiBtb3VzZW1vdmVcblx0XHRcdFx0dGhpcy5yZWZyZXNoUG9zaXRpb25zKCAhaGFyZFJlZnJlc2ggKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0fSxcblxuXHRfY2xlYXI6IGZ1bmN0aW9uKCBldmVudCwgbm9Qcm9wYWdhdGlvbiApIHtcblxuXHRcdHRoaXMucmV2ZXJ0aW5nID0gZmFsc2U7XG5cblx0XHQvLyBXZSBkZWxheSBhbGwgZXZlbnRzIHRoYXQgaGF2ZSB0byBiZSB0cmlnZ2VyZWQgdG8gYWZ0ZXIgdGhlIHBvaW50IHdoZXJlIHRoZSBwbGFjZWhvbGRlclxuXHRcdC8vIGhhcyBiZWVuIHJlbW92ZWQgYW5kIGV2ZXJ5dGhpbmcgZWxzZSBub3JtYWxpemVkIGFnYWluXG5cdFx0dmFyIGksXG5cdFx0XHRkZWxheWVkVHJpZ2dlcnMgPSBbXTtcblxuXHRcdC8vIFdlIGZpcnN0IGhhdmUgdG8gdXBkYXRlIHRoZSBkb20gcG9zaXRpb24gb2YgdGhlIGFjdHVhbCBjdXJyZW50SXRlbVxuXHRcdC8vIE5vdGU6IGRvbid0IGRvIGl0IGlmIHRoZSBjdXJyZW50IGl0ZW0gaXMgYWxyZWFkeSByZW1vdmVkIChieSBhIHVzZXIpLCBvciBpdCBnZXRzXG5cdFx0Ly8gcmVhcHBlbmRlZCAoc2VlICM0MDg4KVxuXHRcdGlmICggIXRoaXMuX25vRmluYWxTb3J0ICYmIHRoaXMuY3VycmVudEl0ZW0ucGFyZW50KCkubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5wbGFjZWhvbGRlci5iZWZvcmUoIHRoaXMuY3VycmVudEl0ZW0gKTtcblx0XHR9XG5cdFx0dGhpcy5fbm9GaW5hbFNvcnQgPSBudWxsO1xuXG5cdFx0aWYgKCB0aGlzLmhlbHBlclsgMCBdID09PSB0aGlzLmN1cnJlbnRJdGVtWyAwIF0gKSB7XG5cdFx0XHRmb3IgKCBpIGluIHRoaXMuX3N0b3JlZENTUyApIHtcblx0XHRcdFx0aWYgKCB0aGlzLl9zdG9yZWRDU1NbIGkgXSA9PT0gXCJhdXRvXCIgfHwgdGhpcy5fc3RvcmVkQ1NTWyBpIF0gPT09IFwic3RhdGljXCIgKSB7XG5cdFx0XHRcdFx0dGhpcy5fc3RvcmVkQ1NTWyBpIF0gPSBcIlwiO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0aGlzLmN1cnJlbnRJdGVtLmNzcyggdGhpcy5fc3RvcmVkQ1NTICk7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5jdXJyZW50SXRlbSwgXCJ1aS1zb3J0YWJsZS1oZWxwZXJcIiApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmN1cnJlbnRJdGVtLnNob3coKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuZnJvbU91dHNpZGUgJiYgIW5vUHJvcGFnYXRpb24gKSB7XG5cdFx0XHRkZWxheWVkVHJpZ2dlcnMucHVzaCggZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLl90cmlnZ2VyKCBcInJlY2VpdmVcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggdGhpcy5mcm9tT3V0c2lkZSApICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHRcdGlmICggKCB0aGlzLmZyb21PdXRzaWRlIHx8XG5cdFx0XHRcdHRoaXMuZG9tUG9zaXRpb24ucHJldiAhPT1cblx0XHRcdFx0dGhpcy5jdXJyZW50SXRlbS5wcmV2KCkubm90KCBcIi51aS1zb3J0YWJsZS1oZWxwZXJcIiApWyAwIF0gfHxcblx0XHRcdFx0dGhpcy5kb21Qb3NpdGlvbi5wYXJlbnQgIT09IHRoaXMuY3VycmVudEl0ZW0ucGFyZW50KClbIDAgXSApICYmICFub1Byb3BhZ2F0aW9uICkge1xuXG5cdFx0XHQvLyBUcmlnZ2VyIHVwZGF0ZSBjYWxsYmFjayBpZiB0aGUgRE9NIHBvc2l0aW9uIGhhcyBjaGFuZ2VkXG5cdFx0XHRkZWxheWVkVHJpZ2dlcnMucHVzaCggZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLl90cmlnZ2VyKCBcInVwZGF0ZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCkgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHQvLyBDaGVjayBpZiB0aGUgaXRlbXMgQ29udGFpbmVyIGhhcyBDaGFuZ2VkIGFuZCB0cmlnZ2VyIGFwcHJvcHJpYXRlXG5cdFx0Ly8gZXZlbnRzLlxuXHRcdGlmICggdGhpcyAhPT0gdGhpcy5jdXJyZW50Q29udGFpbmVyICkge1xuXHRcdFx0aWYgKCAhbm9Qcm9wYWdhdGlvbiApIHtcblx0XHRcdFx0ZGVsYXllZFRyaWdnZXJzLnB1c2goIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0XHR0aGlzLl90cmlnZ2VyKCBcInJlbW92ZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCkgKTtcblx0XHRcdFx0fSApO1xuXHRcdFx0XHRkZWxheWVkVHJpZ2dlcnMucHVzaCggKCBmdW5jdGlvbiggYyApIHtcblx0XHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRcdFx0Yy5fdHJpZ2dlciggXCJyZWNlaXZlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIHRoaXMgKSApO1xuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH0gKS5jYWxsKCB0aGlzLCB0aGlzLmN1cnJlbnRDb250YWluZXIgKSApO1xuXHRcdFx0XHRkZWxheWVkVHJpZ2dlcnMucHVzaCggKCBmdW5jdGlvbiggYyApIHtcblx0XHRcdFx0XHRyZXR1cm4gZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRcdFx0Yy5fdHJpZ2dlciggXCJ1cGRhdGVcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggdGhpcyApICk7XG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0fSApLmNhbGwoIHRoaXMsIHRoaXMuY3VycmVudENvbnRhaW5lciApICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly9Qb3N0IGV2ZW50cyB0byBjb250YWluZXJzXG5cdFx0ZnVuY3Rpb24gZGVsYXlFdmVudCggdHlwZSwgaW5zdGFuY2UsIGNvbnRhaW5lciApIHtcblx0XHRcdHJldHVybiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGNvbnRhaW5lci5fdHJpZ2dlciggdHlwZSwgZXZlbnQsIGluc3RhbmNlLl91aUhhc2goIGluc3RhbmNlICkgKTtcblx0XHRcdH07XG5cdFx0fVxuXHRcdGZvciAoIGkgPSB0aGlzLmNvbnRhaW5lcnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHRpZiAoICFub1Byb3BhZ2F0aW9uICkge1xuXHRcdFx0XHRkZWxheWVkVHJpZ2dlcnMucHVzaCggZGVsYXlFdmVudCggXCJkZWFjdGl2YXRlXCIsIHRoaXMsIHRoaXMuY29udGFpbmVyc1sgaSBdICkgKTtcblx0XHRcdH1cblx0XHRcdGlmICggdGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUub3ZlciApIHtcblx0XHRcdFx0ZGVsYXllZFRyaWdnZXJzLnB1c2goIGRlbGF5RXZlbnQoIFwib3V0XCIsIHRoaXMsIHRoaXMuY29udGFpbmVyc1sgaSBdICkgKTtcblx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUub3ZlciA9IDA7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly9EbyB3aGF0IHdhcyBvcmlnaW5hbGx5IGluIHBsdWdpbnNcblx0XHRpZiAoIHRoaXMuc3RvcmVkQ3Vyc29yICkge1xuXHRcdFx0dGhpcy5kb2N1bWVudC5maW5kKCBcImJvZHlcIiApLmNzcyggXCJjdXJzb3JcIiwgdGhpcy5zdG9yZWRDdXJzb3IgKTtcblx0XHRcdHRoaXMuc3RvcmVkU3R5bGVzaGVldC5yZW1vdmUoKTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLl9zdG9yZWRPcGFjaXR5ICkge1xuXHRcdFx0dGhpcy5oZWxwZXIuY3NzKCBcIm9wYWNpdHlcIiwgdGhpcy5fc3RvcmVkT3BhY2l0eSApO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuX3N0b3JlZFpJbmRleCApIHtcblx0XHRcdHRoaXMuaGVscGVyLmNzcyggXCJ6SW5kZXhcIiwgdGhpcy5fc3RvcmVkWkluZGV4ID09PSBcImF1dG9cIiA/IFwiXCIgOiB0aGlzLl9zdG9yZWRaSW5kZXggKTtcblx0XHR9XG5cblx0XHR0aGlzLmRyYWdnaW5nID0gZmFsc2U7XG5cblx0XHRpZiAoICFub1Byb3BhZ2F0aW9uICkge1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJiZWZvcmVTdG9wXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goKSApO1xuXHRcdH1cblxuXHRcdC8vJCh0aGlzLnBsYWNlaG9sZGVyWzBdKS5yZW1vdmUoKTsgd291bGQgaGF2ZSBiZWVuIHRoZSBqUXVlcnkgd2F5IC0gdW5mb3J0dW5hdGVseSxcblx0XHQvLyBpdCB1bmJpbmRzIEFMTCBldmVudHMgZnJvbSB0aGUgb3JpZ2luYWwgbm9kZSFcblx0XHR0aGlzLnBsYWNlaG9sZGVyWyAwIF0ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggdGhpcy5wbGFjZWhvbGRlclsgMCBdICk7XG5cblx0XHRpZiAoICF0aGlzLmNhbmNlbEhlbHBlclJlbW92YWwgKSB7XG5cdFx0XHRpZiAoIHRoaXMuaGVscGVyWyAwIF0gIT09IHRoaXMuY3VycmVudEl0ZW1bIDAgXSApIHtcblx0XHRcdFx0dGhpcy5oZWxwZXIucmVtb3ZlKCk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLmhlbHBlciA9IG51bGw7XG5cdFx0fVxuXG5cdFx0aWYgKCAhbm9Qcm9wYWdhdGlvbiApIHtcblx0XHRcdGZvciAoIGkgPSAwOyBpIDwgZGVsYXllZFRyaWdnZXJzLmxlbmd0aDsgaSsrICkge1xuXG5cdFx0XHRcdC8vIFRyaWdnZXIgYWxsIGRlbGF5ZWQgZXZlbnRzXG5cdFx0XHRcdGRlbGF5ZWRUcmlnZ2Vyc1sgaSBdLmNhbGwoIHRoaXMsIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcInN0b3BcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCgpICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5mcm9tT3V0c2lkZSA9IGZhbHNlO1xuXHRcdHJldHVybiAhdGhpcy5jYW5jZWxIZWxwZXJSZW1vdmFsO1xuXG5cdH0sXG5cblx0X3RyaWdnZXI6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggJC5XaWRnZXQucHJvdG90eXBlLl90cmlnZ2VyLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHR0aGlzLmNhbmNlbCgpO1xuXHRcdH1cblx0fSxcblxuXHRfdWlIYXNoOiBmdW5jdGlvbiggX2luc3QgKSB7XG5cdFx0dmFyIGluc3QgPSBfaW5zdCB8fCB0aGlzO1xuXHRcdHJldHVybiB7XG5cdFx0XHRoZWxwZXI6IGluc3QuaGVscGVyLFxuXHRcdFx0cGxhY2Vob2xkZXI6IGluc3QucGxhY2Vob2xkZXIgfHwgJCggW10gKSxcblx0XHRcdHBvc2l0aW9uOiBpbnN0LnBvc2l0aW9uLFxuXHRcdFx0b3JpZ2luYWxQb3NpdGlvbjogaW5zdC5vcmlnaW5hbFBvc2l0aW9uLFxuXHRcdFx0b2Zmc2V0OiBpbnN0LnBvc2l0aW9uQWJzLFxuXHRcdFx0aXRlbTogaW5zdC5jdXJyZW50SXRlbSxcblx0XHRcdHNlbmRlcjogX2luc3QgPyBfaW5zdC5lbGVtZW50IDogbnVsbFxuXHRcdH07XG5cdH1cblxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFNwaW5uZXIgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFNwaW5uZXJcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBEaXNwbGF5cyBidXR0b25zIHRvIGVhc2lseSBpbnB1dCBudW1iZXJzIHZpYSB0aGUga2V5Ym9hcmQgb3IgbW91c2UuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc3Bpbm5lci9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9zcGlubmVyL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2Uvc3Bpbm5lci5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxuZnVuY3Rpb24gc3Bpbm5lck1vZGlmZXIoIGZuICkge1xuXHRyZXR1cm4gZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHByZXZpb3VzID0gdGhpcy5lbGVtZW50LnZhbCgpO1xuXHRcdGZuLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cdFx0aWYgKCBwcmV2aW91cyAhPT0gdGhpcy5lbGVtZW50LnZhbCgpICkge1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjaGFuZ2VcIiApO1xuXHRcdH1cblx0fTtcbn1cblxuJC53aWRnZXQoIFwidWkuc3Bpbm5lclwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdGRlZmF1bHRFbGVtZW50OiBcIjxpbnB1dD5cIixcblx0d2lkZ2V0RXZlbnRQcmVmaXg6IFwic3BpblwiLFxuXHRvcHRpb25zOiB7XG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS1zcGlubmVyXCI6IFwidWktY29ybmVyLWFsbFwiLFxuXHRcdFx0XCJ1aS1zcGlubmVyLWRvd25cIjogXCJ1aS1jb3JuZXItYnJcIixcblx0XHRcdFwidWktc3Bpbm5lci11cFwiOiBcInVpLWNvcm5lci10clwiXG5cdFx0fSxcblx0XHRjdWx0dXJlOiBudWxsLFxuXHRcdGljb25zOiB7XG5cdFx0XHRkb3duOiBcInVpLWljb24tdHJpYW5nbGUtMS1zXCIsXG5cdFx0XHR1cDogXCJ1aS1pY29uLXRyaWFuZ2xlLTEtblwiXG5cdFx0fSxcblx0XHRpbmNyZW1lbnRhbDogdHJ1ZSxcblx0XHRtYXg6IG51bGwsXG5cdFx0bWluOiBudWxsLFxuXHRcdG51bWJlckZvcm1hdDogbnVsbCxcblx0XHRwYWdlOiAxMCxcblx0XHRzdGVwOiAxLFxuXG5cdFx0Y2hhbmdlOiBudWxsLFxuXHRcdHNwaW46IG51bGwsXG5cdFx0c3RhcnQ6IG51bGwsXG5cdFx0c3RvcDogbnVsbFxuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly8gaGFuZGxlIHN0cmluZyB2YWx1ZXMgdGhhdCBuZWVkIHRvIGJlIHBhcnNlZFxuXHRcdHRoaXMuX3NldE9wdGlvbiggXCJtYXhcIiwgdGhpcy5vcHRpb25zLm1heCApO1xuXHRcdHRoaXMuX3NldE9wdGlvbiggXCJtaW5cIiwgdGhpcy5vcHRpb25zLm1pbiApO1xuXHRcdHRoaXMuX3NldE9wdGlvbiggXCJzdGVwXCIsIHRoaXMub3B0aW9ucy5zdGVwICk7XG5cblx0XHQvLyBPbmx5IGZvcm1hdCBpZiB0aGVyZSBpcyBhIHZhbHVlLCBwcmV2ZW50cyB0aGUgZmllbGQgZnJvbSBiZWluZyBtYXJrZWRcblx0XHQvLyBhcyBpbnZhbGlkIGluIEZpcmVmb3gsIHNlZSAjOTU3My5cblx0XHRpZiAoIHRoaXMudmFsdWUoKSAhPT0gXCJcIiApIHtcblxuXHRcdFx0Ly8gRm9ybWF0IHRoZSB2YWx1ZSwgYnV0IGRvbid0IGNvbnN0cmFpbi5cblx0XHRcdHRoaXMuX3ZhbHVlKCB0aGlzLmVsZW1lbnQudmFsKCksIHRydWUgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9kcmF3KCk7XG5cdFx0dGhpcy5fb24oIHRoaXMuX2V2ZW50cyApO1xuXHRcdHRoaXMuX3JlZnJlc2goKTtcblxuXHRcdC8vIFR1cm5pbmcgb2ZmIGF1dG9jb21wbGV0ZSBwcmV2ZW50cyB0aGUgYnJvd3NlciBmcm9tIHJlbWVtYmVyaW5nIHRoZVxuXHRcdC8vIHZhbHVlIHdoZW4gbmF2aWdhdGluZyB0aHJvdWdoIGhpc3RvcnksIHNvIHdlIHJlLWVuYWJsZSBhdXRvY29tcGxldGVcblx0XHQvLyBpZiB0aGUgcGFnZSBpcyB1bmxvYWRlZCBiZWZvcmUgdGhlIHdpZGdldCBpcyBkZXN0cm95ZWQuICM3NzkwXG5cdFx0dGhpcy5fb24oIHRoaXMud2luZG93LCB7XG5cdFx0XHRiZWZvcmV1bmxvYWQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQXR0ciggXCJhdXRvY29tcGxldGVcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfZ2V0Q3JlYXRlT3B0aW9uczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLl9zdXBlcigpO1xuXHRcdHZhciBlbGVtZW50ID0gdGhpcy5lbGVtZW50O1xuXG5cdFx0JC5lYWNoKCBbIFwibWluXCIsIFwibWF4XCIsIFwic3RlcFwiIF0sIGZ1bmN0aW9uKCBpLCBvcHRpb24gKSB7XG5cdFx0XHR2YXIgdmFsdWUgPSBlbGVtZW50LmF0dHIoIG9wdGlvbiApO1xuXHRcdFx0aWYgKCB2YWx1ZSAhPSBudWxsICYmIHZhbHVlLmxlbmd0aCApIHtcblx0XHRcdFx0b3B0aW9uc1sgb3B0aW9uIF0gPSB2YWx1ZTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHRyZXR1cm4gb3B0aW9ucztcblx0fSxcblxuXHRfZXZlbnRzOiB7XG5cdFx0a2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0aWYgKCB0aGlzLl9zdGFydCggZXZlbnQgKSAmJiB0aGlzLl9rZXlkb3duKCBldmVudCApICkge1xuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0a2V5dXA6IFwiX3N0b3BcIixcblx0XHRmb2N1czogZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLnByZXZpb3VzID0gdGhpcy5lbGVtZW50LnZhbCgpO1xuXHRcdH0sXG5cdFx0Ymx1cjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0aWYgKCB0aGlzLmNhbmNlbEJsdXIgKSB7XG5cdFx0XHRcdGRlbGV0ZSB0aGlzLmNhbmNlbEJsdXI7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fc3RvcCgpO1xuXHRcdFx0dGhpcy5fcmVmcmVzaCgpO1xuXHRcdFx0aWYgKCB0aGlzLnByZXZpb3VzICE9PSB0aGlzLmVsZW1lbnQudmFsKCkgKSB7XG5cdFx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY2hhbmdlXCIsIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHRtb3VzZXdoZWVsOiBmdW5jdGlvbiggZXZlbnQsIGRlbHRhICkge1xuXHRcdFx0aWYgKCAhZGVsdGEgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHRcdGlmICggIXRoaXMuc3Bpbm5pbmcgJiYgIXRoaXMuX3N0YXJ0KCBldmVudCApICkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX3NwaW4oICggZGVsdGEgPiAwID8gMSA6IC0xICkgKiB0aGlzLm9wdGlvbnMuc3RlcCwgZXZlbnQgKTtcblx0XHRcdGNsZWFyVGltZW91dCggdGhpcy5tb3VzZXdoZWVsVGltZXIgKTtcblx0XHRcdHRoaXMubW91c2V3aGVlbFRpbWVyID0gdGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIHRoaXMuc3Bpbm5pbmcgKSB7XG5cdFx0XHRcdFx0dGhpcy5fc3RvcCggZXZlbnQgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSwgMTAwICk7XG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdH0sXG5cdFx0XCJtb3VzZWRvd24gLnVpLXNwaW5uZXItYnV0dG9uXCI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHZhciBwcmV2aW91cztcblxuXHRcdFx0Ly8gV2UgbmV2ZXIgd2FudCB0aGUgYnV0dG9ucyB0byBoYXZlIGZvY3VzOyB3aGVuZXZlciB0aGUgdXNlciBpc1xuXHRcdFx0Ly8gaW50ZXJhY3Rpbmcgd2l0aCB0aGUgc3Bpbm5lciwgdGhlIGZvY3VzIHNob3VsZCBiZSBvbiB0aGUgaW5wdXQuXG5cdFx0XHQvLyBJZiB0aGUgaW5wdXQgaXMgZm9jdXNlZCB0aGVuIHRoaXMucHJldmlvdXMgaXMgcHJvcGVybHkgc2V0IGZyb21cblx0XHRcdC8vIHdoZW4gdGhlIGlucHV0IGZpcnN0IHJlY2VpdmVkIGZvY3VzLiBJZiB0aGUgaW5wdXQgaXMgbm90IGZvY3VzZWRcblx0XHRcdC8vIHRoZW4gd2UgbmVlZCB0byBzZXQgdGhpcy5wcmV2aW91cyBiYXNlZCBvbiB0aGUgdmFsdWUgYmVmb3JlIHNwaW5uaW5nLlxuXHRcdFx0cHJldmlvdXMgPSB0aGlzLmVsZW1lbnRbIDAgXSA9PT0gJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICkgP1xuXHRcdFx0XHR0aGlzLnByZXZpb3VzIDogdGhpcy5lbGVtZW50LnZhbCgpO1xuXHRcdFx0ZnVuY3Rpb24gY2hlY2tGb2N1cygpIHtcblx0XHRcdFx0dmFyIGlzQWN0aXZlID0gdGhpcy5lbGVtZW50WyAwIF0gPT09ICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApO1xuXHRcdFx0XHRpZiAoICFpc0FjdGl2ZSApIHtcblx0XHRcdFx0XHR0aGlzLmVsZW1lbnQudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHRcdFx0dGhpcy5wcmV2aW91cyA9IHByZXZpb3VzO1xuXG5cdFx0XHRcdFx0Ly8gc3VwcG9ydDogSUVcblx0XHRcdFx0XHQvLyBJRSBzZXRzIGZvY3VzIGFzeW5jaHJvbm91c2x5LCBzbyB3ZSBuZWVkIHRvIGNoZWNrIGlmIGZvY3VzXG5cdFx0XHRcdFx0Ly8gbW92ZWQgb2ZmIG9mIHRoZSBpbnB1dCBiZWNhdXNlIHRoZSB1c2VyIGNsaWNrZWQgb24gdGhlIGJ1dHRvbi5cblx0XHRcdFx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHR0aGlzLnByZXZpb3VzID0gcHJldmlvdXM7XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIEVuc3VyZSBmb2N1cyBpcyBvbiAob3Igc3RheXMgb24pIHRoZSB0ZXh0IGZpZWxkXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0Y2hlY2tGb2N1cy5jYWxsKCB0aGlzICk7XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFXG5cdFx0XHQvLyBJRSBkb2Vzbid0IHByZXZlbnQgbW92aW5nIGZvY3VzIGV2ZW4gd2l0aCBldmVudC5wcmV2ZW50RGVmYXVsdCgpXG5cdFx0XHQvLyBzbyB3ZSBzZXQgYSBmbGFnIHRvIGtub3cgd2hlbiB3ZSBzaG91bGQgaWdub3JlIHRoZSBibHVyIGV2ZW50XG5cdFx0XHQvLyBhbmQgY2hlY2sgKGFnYWluKSBpZiBmb2N1cyBtb3ZlZCBvZmYgb2YgdGhlIGlucHV0LlxuXHRcdFx0dGhpcy5jYW5jZWxCbHVyID0gdHJ1ZTtcblx0XHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0ZGVsZXRlIHRoaXMuY2FuY2VsQmx1cjtcblx0XHRcdFx0Y2hlY2tGb2N1cy5jYWxsKCB0aGlzICk7XG5cdFx0XHR9ICk7XG5cblx0XHRcdGlmICggdGhpcy5fc3RhcnQoIGV2ZW50ICkgPT09IGZhbHNlICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX3JlcGVhdCggbnVsbCwgJCggZXZlbnQuY3VycmVudFRhcmdldCApXG5cdFx0XHRcdC5oYXNDbGFzcyggXCJ1aS1zcGlubmVyLXVwXCIgKSA/IDEgOiAtMSwgZXZlbnQgKTtcblx0XHR9LFxuXHRcdFwibW91c2V1cCAudWktc3Bpbm5lci1idXR0b25cIjogXCJfc3RvcFwiLFxuXHRcdFwibW91c2VlbnRlciAudWktc3Bpbm5lci1idXR0b25cIjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0XHQvLyBidXR0b24gd2lsbCBhZGQgdWktc3RhdGUtYWN0aXZlIGlmIG1vdXNlIHdhcyBkb3duIHdoaWxlIG1vdXNlbGVhdmUgYW5kIGtlcHQgZG93blxuXHRcdFx0aWYgKCAhJCggZXZlbnQuY3VycmVudFRhcmdldCApLmhhc0NsYXNzKCBcInVpLXN0YXRlLWFjdGl2ZVwiICkgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0aGlzLl9zdGFydCggZXZlbnQgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH1cblx0XHRcdHRoaXMuX3JlcGVhdCggbnVsbCwgJCggZXZlbnQuY3VycmVudFRhcmdldCApXG5cdFx0XHRcdC5oYXNDbGFzcyggXCJ1aS1zcGlubmVyLXVwXCIgKSA/IDEgOiAtMSwgZXZlbnQgKTtcblx0XHR9LFxuXG5cdFx0Ly8gVE9ETzogZG8gd2UgcmVhbGx5IHdhbnQgdG8gY29uc2lkZXIgdGhpcyBhIHN0b3A/XG5cdFx0Ly8gc2hvdWxkbid0IHdlIGp1c3Qgc3RvcCB0aGUgcmVwZWF0ZXIgYW5kIHdhaXQgdW50aWwgbW91c2V1cCBiZWZvcmVcblx0XHQvLyB3ZSB0cmlnZ2VyIHRoZSBzdG9wIGV2ZW50P1xuXHRcdFwibW91c2VsZWF2ZSAudWktc3Bpbm5lci1idXR0b25cIjogXCJfc3RvcFwiXG5cdH0sXG5cblx0Ly8gU3VwcG9ydCBtb2JpbGUgZW5oYW5jZWQgb3B0aW9uIGFuZCBtYWtlIGJhY2tjb21wYXQgbW9yZSBzYW5lXG5cdF9lbmhhbmNlOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLnVpU3Bpbm5lciA9IHRoaXMuZWxlbWVudFxuXHRcdFx0LmF0dHIoIFwiYXV0b2NvbXBsZXRlXCIsIFwib2ZmXCIgKVxuXHRcdFx0LndyYXAoIFwiPHNwYW4+XCIgKVxuXHRcdFx0LnBhcmVudCgpXG5cblx0XHRcdFx0Ly8gQWRkIGJ1dHRvbnNcblx0XHRcdFx0LmFwcGVuZChcblx0XHRcdFx0XHRcIjxhPjwvYT48YT48L2E+XCJcblx0XHRcdFx0KTtcblx0fSxcblxuXHRfZHJhdzogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fZW5oYW5jZSgpO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudWlTcGlubmVyLCBcInVpLXNwaW5uZXJcIiwgXCJ1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLXNwaW5uZXItaW5wdXRcIiApO1xuXG5cdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwicm9sZVwiLCBcInNwaW5idXR0b25cIiApO1xuXG5cdFx0Ly8gQnV0dG9uIGJpbmRpbmdzXG5cdFx0dGhpcy5idXR0b25zID0gdGhpcy51aVNwaW5uZXIuY2hpbGRyZW4oIFwiYVwiIClcblx0XHRcdC5hdHRyKCBcInRhYkluZGV4XCIsIC0xIClcblx0XHRcdC5hdHRyKCBcImFyaWEtaGlkZGVuXCIsIHRydWUgKVxuXHRcdFx0LmJ1dHRvbigge1xuXHRcdFx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcdFx0XCJ1aS1idXR0b25cIjogXCJcIlxuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cblx0XHQvLyBUT0RPOiBSaWdodCBub3cgYnV0dG9uIGRvZXMgbm90IHN1cHBvcnQgY2xhc3NlcyB0aGlzIGlzIGFscmVhZHkgdXBkYXRlZCBpbiBidXR0b24gUFJcblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5idXR0b25zLCBcInVpLWNvcm5lci1hbGxcIiApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuYnV0dG9ucy5maXJzdCgpLCBcInVpLXNwaW5uZXItYnV0dG9uIHVpLXNwaW5uZXItdXBcIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmJ1dHRvbnMubGFzdCgpLCBcInVpLXNwaW5uZXItYnV0dG9uIHVpLXNwaW5uZXItZG93blwiICk7XG5cdFx0dGhpcy5idXR0b25zLmZpcnN0KCkuYnV0dG9uKCB7XG5cdFx0XHRcImljb25cIjogdGhpcy5vcHRpb25zLmljb25zLnVwLFxuXHRcdFx0XCJzaG93TGFiZWxcIjogZmFsc2Vcblx0XHR9ICk7XG5cdFx0dGhpcy5idXR0b25zLmxhc3QoKS5idXR0b24oIHtcblx0XHRcdFwiaWNvblwiOiB0aGlzLm9wdGlvbnMuaWNvbnMuZG93bixcblx0XHRcdFwic2hvd0xhYmVsXCI6IGZhbHNlXG5cdFx0fSApO1xuXG5cdFx0Ly8gSUUgNiBkb2Vzbid0IHVuZGVyc3RhbmQgaGVpZ2h0OiA1MCUgZm9yIHRoZSBidXR0b25zXG5cdFx0Ly8gdW5sZXNzIHRoZSB3cmFwcGVyIGhhcyBhbiBleHBsaWNpdCBoZWlnaHRcblx0XHRpZiAoIHRoaXMuYnV0dG9ucy5oZWlnaHQoKSA+IE1hdGguY2VpbCggdGhpcy51aVNwaW5uZXIuaGVpZ2h0KCkgKiAwLjUgKSAmJlxuXHRcdFx0XHR0aGlzLnVpU3Bpbm5lci5oZWlnaHQoKSA+IDAgKSB7XG5cdFx0XHR0aGlzLnVpU3Bpbm5lci5oZWlnaHQoIHRoaXMudWlTcGlubmVyLmhlaWdodCgpICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9rZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRrZXlDb2RlID0gJC51aS5rZXlDb2RlO1xuXG5cdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRjYXNlIGtleUNvZGUuVVA6XG5cdFx0XHR0aGlzLl9yZXBlYXQoIG51bGwsIDEsIGV2ZW50ICk7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRjYXNlIGtleUNvZGUuRE9XTjpcblx0XHRcdHRoaXMuX3JlcGVhdCggbnVsbCwgLTEsIGV2ZW50ICk7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRjYXNlIGtleUNvZGUuUEFHRV9VUDpcblx0XHRcdHRoaXMuX3JlcGVhdCggbnVsbCwgb3B0aW9ucy5wYWdlLCBldmVudCApO1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0Y2FzZSBrZXlDb2RlLlBBR0VfRE9XTjpcblx0XHRcdHRoaXMuX3JlcGVhdCggbnVsbCwgLW9wdGlvbnMucGFnZSwgZXZlbnQgKTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblxuXHRfc3RhcnQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoICF0aGlzLnNwaW5uaW5nICYmIHRoaXMuX3RyaWdnZXIoIFwic3RhcnRcIiwgZXZlbnQgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0aWYgKCAhdGhpcy5jb3VudGVyICkge1xuXHRcdFx0dGhpcy5jb3VudGVyID0gMTtcblx0XHR9XG5cdFx0dGhpcy5zcGlubmluZyA9IHRydWU7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0X3JlcGVhdDogZnVuY3Rpb24oIGksIHN0ZXBzLCBldmVudCApIHtcblx0XHRpID0gaSB8fCA1MDA7XG5cblx0XHRjbGVhclRpbWVvdXQoIHRoaXMudGltZXIgKTtcblx0XHR0aGlzLnRpbWVyID0gdGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5fcmVwZWF0KCA0MCwgc3RlcHMsIGV2ZW50ICk7XG5cdFx0fSwgaSApO1xuXG5cdFx0dGhpcy5fc3Bpbiggc3RlcHMgKiB0aGlzLm9wdGlvbnMuc3RlcCwgZXZlbnQgKTtcblx0fSxcblxuXHRfc3BpbjogZnVuY3Rpb24oIHN0ZXAsIGV2ZW50ICkge1xuXHRcdHZhciB2YWx1ZSA9IHRoaXMudmFsdWUoKSB8fCAwO1xuXG5cdFx0aWYgKCAhdGhpcy5jb3VudGVyICkge1xuXHRcdFx0dGhpcy5jb3VudGVyID0gMTtcblx0XHR9XG5cblx0XHR2YWx1ZSA9IHRoaXMuX2FkanVzdFZhbHVlKCB2YWx1ZSArIHN0ZXAgKiB0aGlzLl9pbmNyZW1lbnQoIHRoaXMuY291bnRlciApICk7XG5cblx0XHRpZiAoICF0aGlzLnNwaW5uaW5nIHx8IHRoaXMuX3RyaWdnZXIoIFwic3BpblwiLCBldmVudCwgeyB2YWx1ZTogdmFsdWUgfSApICE9PSBmYWxzZSApIHtcblx0XHRcdHRoaXMuX3ZhbHVlKCB2YWx1ZSApO1xuXHRcdFx0dGhpcy5jb3VudGVyKys7XG5cdFx0fVxuXHR9LFxuXG5cdF9pbmNyZW1lbnQ6IGZ1bmN0aW9uKCBpICkge1xuXHRcdHZhciBpbmNyZW1lbnRhbCA9IHRoaXMub3B0aW9ucy5pbmNyZW1lbnRhbDtcblxuXHRcdGlmICggaW5jcmVtZW50YWwgKSB7XG5cdFx0XHRyZXR1cm4gJC5pc0Z1bmN0aW9uKCBpbmNyZW1lbnRhbCApID9cblx0XHRcdFx0aW5jcmVtZW50YWwoIGkgKSA6XG5cdFx0XHRcdE1hdGguZmxvb3IoIGkgKiBpICogaSAvIDUwMDAwIC0gaSAqIGkgLyA1MDAgKyAxNyAqIGkgLyAyMDAgKyAxICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIDE7XG5cdH0sXG5cblx0X3ByZWNpc2lvbjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHByZWNpc2lvbiA9IHRoaXMuX3ByZWNpc2lvbk9mKCB0aGlzLm9wdGlvbnMuc3RlcCApO1xuXHRcdGlmICggdGhpcy5vcHRpb25zLm1pbiAhPT0gbnVsbCApIHtcblx0XHRcdHByZWNpc2lvbiA9IE1hdGgubWF4KCBwcmVjaXNpb24sIHRoaXMuX3ByZWNpc2lvbk9mKCB0aGlzLm9wdGlvbnMubWluICkgKTtcblx0XHR9XG5cdFx0cmV0dXJuIHByZWNpc2lvbjtcblx0fSxcblxuXHRfcHJlY2lzaW9uT2Y6IGZ1bmN0aW9uKCBudW0gKSB7XG5cdFx0dmFyIHN0ciA9IG51bS50b1N0cmluZygpLFxuXHRcdFx0ZGVjaW1hbCA9IHN0ci5pbmRleE9mKCBcIi5cIiApO1xuXHRcdHJldHVybiBkZWNpbWFsID09PSAtMSA/IDAgOiBzdHIubGVuZ3RoIC0gZGVjaW1hbCAtIDE7XG5cdH0sXG5cblx0X2FkanVzdFZhbHVlOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dmFyIGJhc2UsIGFib3ZlTWluLFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblxuXHRcdC8vIE1ha2Ugc3VyZSB3ZSdyZSBhdCBhIHZhbGlkIHN0ZXBcblx0XHQvLyAtIGZpbmQgb3V0IHdoZXJlIHdlIGFyZSByZWxhdGl2ZSB0byB0aGUgYmFzZSAobWluIG9yIDApXG5cdFx0YmFzZSA9IG9wdGlvbnMubWluICE9PSBudWxsID8gb3B0aW9ucy5taW4gOiAwO1xuXHRcdGFib3ZlTWluID0gdmFsdWUgLSBiYXNlO1xuXG5cdFx0Ly8gLSByb3VuZCB0byB0aGUgbmVhcmVzdCBzdGVwXG5cdFx0YWJvdmVNaW4gPSBNYXRoLnJvdW5kKCBhYm92ZU1pbiAvIG9wdGlvbnMuc3RlcCApICogb3B0aW9ucy5zdGVwO1xuXG5cdFx0Ly8gLSByb3VuZGluZyBpcyBiYXNlZCBvbiAwLCBzbyBhZGp1c3QgYmFjayB0byBvdXIgYmFzZVxuXHRcdHZhbHVlID0gYmFzZSArIGFib3ZlTWluO1xuXG5cdFx0Ly8gRml4IHByZWNpc2lvbiBmcm9tIGJhZCBKUyBmbG9hdGluZyBwb2ludCBtYXRoXG5cdFx0dmFsdWUgPSBwYXJzZUZsb2F0KCB2YWx1ZS50b0ZpeGVkKCB0aGlzLl9wcmVjaXNpb24oKSApICk7XG5cblx0XHQvLyBDbGFtcCB0aGUgdmFsdWVcblx0XHRpZiAoIG9wdGlvbnMubWF4ICE9PSBudWxsICYmIHZhbHVlID4gb3B0aW9ucy5tYXggKSB7XG5cdFx0XHRyZXR1cm4gb3B0aW9ucy5tYXg7XG5cdFx0fVxuXHRcdGlmICggb3B0aW9ucy5taW4gIT09IG51bGwgJiYgdmFsdWUgPCBvcHRpb25zLm1pbiApIHtcblx0XHRcdHJldHVybiBvcHRpb25zLm1pbjtcblx0XHR9XG5cblx0XHRyZXR1cm4gdmFsdWU7XG5cdH0sXG5cblx0X3N0b3A6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoICF0aGlzLnNwaW5uaW5nICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGNsZWFyVGltZW91dCggdGhpcy50aW1lciApO1xuXHRcdGNsZWFyVGltZW91dCggdGhpcy5tb3VzZXdoZWVsVGltZXIgKTtcblx0XHR0aGlzLmNvdW50ZXIgPSAwO1xuXHRcdHRoaXMuc3Bpbm5pbmcgPSBmYWxzZTtcblx0XHR0aGlzLl90cmlnZ2VyKCBcInN0b3BcIiwgZXZlbnQgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHR2YXIgcHJldlZhbHVlLCBmaXJzdCwgbGFzdDtcblxuXHRcdGlmICgga2V5ID09PSBcImN1bHR1cmVcIiB8fCBrZXkgPT09IFwibnVtYmVyRm9ybWF0XCIgKSB7XG5cdFx0XHRwcmV2VmFsdWUgPSB0aGlzLl9wYXJzZSggdGhpcy5lbGVtZW50LnZhbCgpICk7XG5cdFx0XHR0aGlzLm9wdGlvbnNbIGtleSBdID0gdmFsdWU7XG5cdFx0XHR0aGlzLmVsZW1lbnQudmFsKCB0aGlzLl9mb3JtYXQoIHByZXZWYWx1ZSApICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwibWF4XCIgfHwga2V5ID09PSBcIm1pblwiIHx8IGtleSA9PT0gXCJzdGVwXCIgKSB7XG5cdFx0XHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdFx0dmFsdWUgPSB0aGlzLl9wYXJzZSggdmFsdWUgKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0aWYgKCBrZXkgPT09IFwiaWNvbnNcIiApIHtcblx0XHRcdGZpcnN0ID0gdGhpcy5idXR0b25zLmZpcnN0KCkuZmluZCggXCIudWktaWNvblwiICk7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggZmlyc3QsIG51bGwsIHRoaXMub3B0aW9ucy5pY29ucy51cCApO1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIGZpcnN0LCBudWxsLCB2YWx1ZS51cCApO1xuXHRcdFx0bGFzdCA9IHRoaXMuYnV0dG9ucy5sYXN0KCkuZmluZCggXCIudWktaWNvblwiICk7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggbGFzdCwgbnVsbCwgdGhpcy5vcHRpb25zLmljb25zLmRvd24gKTtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCBsYXN0LCBudWxsLCB2YWx1ZS5kb3duICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uRGlzYWJsZWQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlciggdmFsdWUgKTtcblxuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCB0aGlzLnVpU3Bpbm5lciwgbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiLCAhIXZhbHVlICk7XG5cdFx0dGhpcy5lbGVtZW50LnByb3AoIFwiZGlzYWJsZWRcIiwgISF2YWx1ZSApO1xuXHRcdHRoaXMuYnV0dG9ucy5idXR0b24oIHZhbHVlID8gXCJkaXNhYmxlXCIgOiBcImVuYWJsZVwiICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbnM6IHNwaW5uZXJNb2RpZmVyKCBmdW5jdGlvbiggb3B0aW9ucyApIHtcblx0XHR0aGlzLl9zdXBlciggb3B0aW9ucyApO1xuXHR9ICksXG5cblx0X3BhcnNlOiBmdW5jdGlvbiggdmFsICkge1xuXHRcdGlmICggdHlwZW9mIHZhbCA9PT0gXCJzdHJpbmdcIiAmJiB2YWwgIT09IFwiXCIgKSB7XG5cdFx0XHR2YWwgPSB3aW5kb3cuR2xvYmFsaXplICYmIHRoaXMub3B0aW9ucy5udW1iZXJGb3JtYXQgP1xuXHRcdFx0XHRHbG9iYWxpemUucGFyc2VGbG9hdCggdmFsLCAxMCwgdGhpcy5vcHRpb25zLmN1bHR1cmUgKSA6ICt2YWw7XG5cdFx0fVxuXHRcdHJldHVybiB2YWwgPT09IFwiXCIgfHwgaXNOYU4oIHZhbCApID8gbnVsbCA6IHZhbDtcblx0fSxcblxuXHRfZm9ybWF0OiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0aWYgKCB2YWx1ZSA9PT0gXCJcIiApIHtcblx0XHRcdHJldHVybiBcIlwiO1xuXHRcdH1cblx0XHRyZXR1cm4gd2luZG93Lkdsb2JhbGl6ZSAmJiB0aGlzLm9wdGlvbnMubnVtYmVyRm9ybWF0ID9cblx0XHRcdEdsb2JhbGl6ZS5mb3JtYXQoIHZhbHVlLCB0aGlzLm9wdGlvbnMubnVtYmVyRm9ybWF0LCB0aGlzLm9wdGlvbnMuY3VsdHVyZSApIDpcblx0XHRcdHZhbHVlO1xuXHR9LFxuXG5cdF9yZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmVsZW1lbnQuYXR0cigge1xuXHRcdFx0XCJhcmlhLXZhbHVlbWluXCI6IHRoaXMub3B0aW9ucy5taW4sXG5cdFx0XHRcImFyaWEtdmFsdWVtYXhcIjogdGhpcy5vcHRpb25zLm1heCxcblxuXHRcdFx0Ly8gVE9ETzogd2hhdCBzaG91bGQgd2UgZG8gd2l0aCB2YWx1ZXMgdGhhdCBjYW4ndCBiZSBwYXJzZWQ/XG5cdFx0XHRcImFyaWEtdmFsdWVub3dcIjogdGhpcy5fcGFyc2UoIHRoaXMuZWxlbWVudC52YWwoKSApXG5cdFx0fSApO1xuXHR9LFxuXG5cdGlzVmFsaWQ6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB2YWx1ZSA9IHRoaXMudmFsdWUoKTtcblxuXHRcdC8vIE51bGwgaXMgaW52YWxpZFxuXHRcdGlmICggdmFsdWUgPT09IG51bGwgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly8gSWYgdmFsdWUgZ2V0cyBhZGp1c3RlZCwgaXQncyBpbnZhbGlkXG5cdFx0cmV0dXJuIHZhbHVlID09PSB0aGlzLl9hZGp1c3RWYWx1ZSggdmFsdWUgKTtcblx0fSxcblxuXHQvLyBVcGRhdGUgdGhlIHZhbHVlIHdpdGhvdXQgdHJpZ2dlcmluZyBjaGFuZ2Vcblx0X3ZhbHVlOiBmdW5jdGlvbiggdmFsdWUsIGFsbG93QW55ICkge1xuXHRcdHZhciBwYXJzZWQ7XG5cdFx0aWYgKCB2YWx1ZSAhPT0gXCJcIiApIHtcblx0XHRcdHBhcnNlZCA9IHRoaXMuX3BhcnNlKCB2YWx1ZSApO1xuXHRcdFx0aWYgKCBwYXJzZWQgIT09IG51bGwgKSB7XG5cdFx0XHRcdGlmICggIWFsbG93QW55ICkge1xuXHRcdFx0XHRcdHBhcnNlZCA9IHRoaXMuX2FkanVzdFZhbHVlKCBwYXJzZWQgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR2YWx1ZSA9IHRoaXMuX2Zvcm1hdCggcGFyc2VkICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHRoaXMuZWxlbWVudC52YWwoIHZhbHVlICk7XG5cdFx0dGhpcy5fcmVmcmVzaCgpO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdC5wcm9wKCBcImRpc2FibGVkXCIsIGZhbHNlIClcblx0XHRcdC5yZW1vdmVBdHRyKCBcImF1dG9jb21wbGV0ZSByb2xlIGFyaWEtdmFsdWVtaW4gYXJpYS12YWx1ZW1heCBhcmlhLXZhbHVlbm93XCIgKTtcblxuXHRcdHRoaXMudWlTcGlubmVyLnJlcGxhY2VXaXRoKCB0aGlzLmVsZW1lbnQgKTtcblx0fSxcblxuXHRzdGVwVXA6IHNwaW5uZXJNb2RpZmVyKCBmdW5jdGlvbiggc3RlcHMgKSB7XG5cdFx0dGhpcy5fc3RlcFVwKCBzdGVwcyApO1xuXHR9ICksXG5cdF9zdGVwVXA6IGZ1bmN0aW9uKCBzdGVwcyApIHtcblx0XHRpZiAoIHRoaXMuX3N0YXJ0KCkgKSB7XG5cdFx0XHR0aGlzLl9zcGluKCAoIHN0ZXBzIHx8IDEgKSAqIHRoaXMub3B0aW9ucy5zdGVwICk7XG5cdFx0XHR0aGlzLl9zdG9wKCk7XG5cdFx0fVxuXHR9LFxuXG5cdHN0ZXBEb3duOiBzcGlubmVyTW9kaWZlciggZnVuY3Rpb24oIHN0ZXBzICkge1xuXHRcdHRoaXMuX3N0ZXBEb3duKCBzdGVwcyApO1xuXHR9ICksXG5cdF9zdGVwRG93bjogZnVuY3Rpb24oIHN0ZXBzICkge1xuXHRcdGlmICggdGhpcy5fc3RhcnQoKSApIHtcblx0XHRcdHRoaXMuX3NwaW4oICggc3RlcHMgfHwgMSApICogLXRoaXMub3B0aW9ucy5zdGVwICk7XG5cdFx0XHR0aGlzLl9zdG9wKCk7XG5cdFx0fVxuXHR9LFxuXG5cdHBhZ2VVcDogc3Bpbm5lck1vZGlmZXIoIGZ1bmN0aW9uKCBwYWdlcyApIHtcblx0XHR0aGlzLl9zdGVwVXAoICggcGFnZXMgfHwgMSApICogdGhpcy5vcHRpb25zLnBhZ2UgKTtcblx0fSApLFxuXG5cdHBhZ2VEb3duOiBzcGlubmVyTW9kaWZlciggZnVuY3Rpb24oIHBhZ2VzICkge1xuXHRcdHRoaXMuX3N0ZXBEb3duKCAoIHBhZ2VzIHx8IDEgKSAqIHRoaXMub3B0aW9ucy5wYWdlICk7XG5cdH0gKSxcblxuXHR2YWx1ZTogZnVuY3Rpb24oIG5ld1ZhbCApIHtcblx0XHRpZiAoICFhcmd1bWVudHMubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuX3BhcnNlKCB0aGlzLmVsZW1lbnQudmFsKCkgKTtcblx0XHR9XG5cdFx0c3Bpbm5lck1vZGlmZXIoIHRoaXMuX3ZhbHVlICkuY2FsbCggdGhpcywgbmV3VmFsICk7XG5cdH0sXG5cblx0d2lkZ2V0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy51aVNwaW5uZXI7XG5cdH1cbn0gKTtcblxuLy8gREVQUkVDQVRFRFxuLy8gVE9ETzogc3dpdGNoIHJldHVybiBiYWNrIHRvIHdpZGdldCBkZWNsYXJhdGlvbiBhdCB0b3Agb2YgZmlsZSB3aGVuIHRoaXMgaXMgcmVtb3ZlZFxuaWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgKSB7XG5cblx0Ly8gQmFja2NvbXBhdCBmb3Igc3Bpbm5lciBodG1sIGV4dGVuc2lvbiBwb2ludHNcblx0JC53aWRnZXQoIFwidWkuc3Bpbm5lclwiLCAkLnVpLnNwaW5uZXIsIHtcblx0XHRfZW5oYW5jZTogZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLnVpU3Bpbm5lciA9IHRoaXMuZWxlbWVudFxuXHRcdFx0XHQuYXR0ciggXCJhdXRvY29tcGxldGVcIiwgXCJvZmZcIiApXG5cdFx0XHRcdC53cmFwKCB0aGlzLl91aVNwaW5uZXJIdG1sKCkgKVxuXHRcdFx0XHQucGFyZW50KClcblxuXHRcdFx0XHRcdC8vIEFkZCBidXR0b25zXG5cdFx0XHRcdFx0LmFwcGVuZCggdGhpcy5fYnV0dG9uSHRtbCgpICk7XG5cdFx0fSxcblx0XHRfdWlTcGlubmVySHRtbDogZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4gXCI8c3Bhbj5cIjtcblx0XHR9LFxuXG5cdFx0X2J1dHRvbkh0bWw6IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIFwiPGE+PC9hPjxhPjwvYT5cIjtcblx0XHR9XG5cdH0gKTtcbn1cblxudmFyIHdpZGdldHNTcGlubmVyID0gJC51aS5zcGlubmVyO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFRhYnMgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFRhYnNcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBUcmFuc2Zvcm1zIGEgc2V0IG9mIGNvbnRhaW5lciBlbGVtZW50cyBpbnRvIGEgdGFiIHN0cnVjdHVyZS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS90YWJzL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3RhYnMvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS90YWJzLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG4kLndpZGdldCggXCJ1aS50YWJzXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0ZGVsYXk6IDMwMCxcblx0b3B0aW9uczoge1xuXHRcdGFjdGl2ZTogbnVsbCxcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLXRhYnNcIjogXCJ1aS1jb3JuZXItYWxsXCIsXG5cdFx0XHRcInVpLXRhYnMtbmF2XCI6IFwidWktY29ybmVyLWFsbFwiLFxuXHRcdFx0XCJ1aS10YWJzLXBhbmVsXCI6IFwidWktY29ybmVyLWJvdHRvbVwiLFxuXHRcdFx0XCJ1aS10YWJzLXRhYlwiOiBcInVpLWNvcm5lci10b3BcIlxuXHRcdH0sXG5cdFx0Y29sbGFwc2libGU6IGZhbHNlLFxuXHRcdGV2ZW50OiBcImNsaWNrXCIsXG5cdFx0aGVpZ2h0U3R5bGU6IFwiY29udGVudFwiLFxuXHRcdGhpZGU6IG51bGwsXG5cdFx0c2hvdzogbnVsbCxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGFjdGl2YXRlOiBudWxsLFxuXHRcdGJlZm9yZUFjdGl2YXRlOiBudWxsLFxuXHRcdGJlZm9yZUxvYWQ6IG51bGwsXG5cdFx0bG9hZDogbnVsbFxuXHR9LFxuXG5cdF9pc0xvY2FsOiAoIGZ1bmN0aW9uKCkge1xuXHRcdHZhciByaGFzaCA9IC8jLiokLztcblxuXHRcdHJldHVybiBmdW5jdGlvbiggYW5jaG9yICkge1xuXHRcdFx0dmFyIGFuY2hvclVybCwgbG9jYXRpb25Vcmw7XG5cblx0XHRcdGFuY2hvclVybCA9IGFuY2hvci5ocmVmLnJlcGxhY2UoIHJoYXNoLCBcIlwiICk7XG5cdFx0XHRsb2NhdGlvblVybCA9IGxvY2F0aW9uLmhyZWYucmVwbGFjZSggcmhhc2gsIFwiXCIgKTtcblxuXHRcdFx0Ly8gRGVjb2RpbmcgbWF5IHRocm93IGFuIGVycm9yIGlmIHRoZSBVUkwgaXNuJ3QgVVRGLTggKCM5NTE4KVxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0YW5jaG9yVXJsID0gZGVjb2RlVVJJQ29tcG9uZW50KCBhbmNob3JVcmwgKTtcblx0XHRcdH0gY2F0Y2ggKCBlcnJvciApIHt9XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRsb2NhdGlvblVybCA9IGRlY29kZVVSSUNvbXBvbmVudCggbG9jYXRpb25VcmwgKTtcblx0XHRcdH0gY2F0Y2ggKCBlcnJvciApIHt9XG5cblx0XHRcdHJldHVybiBhbmNob3IuaGFzaC5sZW5ndGggPiAxICYmIGFuY2hvclVybCA9PT0gbG9jYXRpb25Vcmw7XG5cdFx0fTtcblx0fSApKCksXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblxuXHRcdHRoaXMucnVubmluZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktdGFic1wiLCBcInVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudFwiICk7XG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIFwidWktdGFicy1jb2xsYXBzaWJsZVwiLCBudWxsLCBvcHRpb25zLmNvbGxhcHNpYmxlICk7XG5cblx0XHR0aGlzLl9wcm9jZXNzVGFicygpO1xuXHRcdG9wdGlvbnMuYWN0aXZlID0gdGhpcy5faW5pdGlhbEFjdGl2ZSgpO1xuXG5cdFx0Ly8gVGFrZSBkaXNhYmxpbmcgdGFicyB2aWEgY2xhc3MgYXR0cmlidXRlIGZyb20gSFRNTFxuXHRcdC8vIGludG8gYWNjb3VudCBhbmQgdXBkYXRlIG9wdGlvbiBwcm9wZXJseS5cblx0XHRpZiAoICQuaXNBcnJheSggb3B0aW9ucy5kaXNhYmxlZCApICkge1xuXHRcdFx0b3B0aW9ucy5kaXNhYmxlZCA9ICQudW5pcXVlKCBvcHRpb25zLmRpc2FibGVkLmNvbmNhdChcblx0XHRcdFx0JC5tYXAoIHRoaXMudGFicy5maWx0ZXIoIFwiLnVpLXN0YXRlLWRpc2FibGVkXCIgKSwgZnVuY3Rpb24oIGxpICkge1xuXHRcdFx0XHRcdHJldHVybiB0aGF0LnRhYnMuaW5kZXgoIGxpICk7XG5cdFx0XHRcdH0gKVxuXHRcdFx0KSApLnNvcnQoKTtcblx0XHR9XG5cblx0XHQvLyBDaGVjayBmb3IgbGVuZ3RoIGF2b2lkcyBlcnJvciB3aGVuIGluaXRpYWxpemluZyBlbXB0eSBsaXN0XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuYWN0aXZlICE9PSBmYWxzZSAmJiB0aGlzLmFuY2hvcnMubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5hY3RpdmUgPSB0aGlzLl9maW5kQWN0aXZlKCBvcHRpb25zLmFjdGl2ZSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmFjdGl2ZSA9ICQoKTtcblx0XHR9XG5cblx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cblx0XHRpZiAoIHRoaXMuYWN0aXZlLmxlbmd0aCApIHtcblx0XHRcdHRoaXMubG9hZCggb3B0aW9ucy5hY3RpdmUgKTtcblx0XHR9XG5cdH0sXG5cblx0X2luaXRpYWxBY3RpdmU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBhY3RpdmUgPSB0aGlzLm9wdGlvbnMuYWN0aXZlLFxuXHRcdFx0Y29sbGFwc2libGUgPSB0aGlzLm9wdGlvbnMuY29sbGFwc2libGUsXG5cdFx0XHRsb2NhdGlvbkhhc2ggPSBsb2NhdGlvbi5oYXNoLnN1YnN0cmluZyggMSApO1xuXG5cdFx0aWYgKCBhY3RpdmUgPT09IG51bGwgKSB7XG5cblx0XHRcdC8vIGNoZWNrIHRoZSBmcmFnbWVudCBpZGVudGlmaWVyIGluIHRoZSBVUkxcblx0XHRcdGlmICggbG9jYXRpb25IYXNoICkge1xuXHRcdFx0XHR0aGlzLnRhYnMuZWFjaCggZnVuY3Rpb24oIGksIHRhYiApIHtcblx0XHRcdFx0XHRpZiAoICQoIHRhYiApLmF0dHIoIFwiYXJpYS1jb250cm9sc1wiICkgPT09IGxvY2F0aW9uSGFzaCApIHtcblx0XHRcdFx0XHRcdGFjdGl2ZSA9IGk7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENoZWNrIGZvciBhIHRhYiBtYXJrZWQgYWN0aXZlIHZpYSBhIGNsYXNzXG5cdFx0XHRpZiAoIGFjdGl2ZSA9PT0gbnVsbCApIHtcblx0XHRcdFx0YWN0aXZlID0gdGhpcy50YWJzLmluZGV4KCB0aGlzLnRhYnMuZmlsdGVyKCBcIi51aS10YWJzLWFjdGl2ZVwiICkgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTm8gYWN0aXZlIHRhYiwgc2V0IHRvIGZhbHNlXG5cdFx0XHRpZiAoIGFjdGl2ZSA9PT0gbnVsbCB8fCBhY3RpdmUgPT09IC0xICkge1xuXHRcdFx0XHRhY3RpdmUgPSB0aGlzLnRhYnMubGVuZ3RoID8gMCA6IGZhbHNlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIEhhbmRsZSBudW1iZXJzOiBuZWdhdGl2ZSwgb3V0IG9mIHJhbmdlXG5cdFx0aWYgKCBhY3RpdmUgIT09IGZhbHNlICkge1xuXHRcdFx0YWN0aXZlID0gdGhpcy50YWJzLmluZGV4KCB0aGlzLnRhYnMuZXEoIGFjdGl2ZSApICk7XG5cdFx0XHRpZiAoIGFjdGl2ZSA9PT0gLTEgKSB7XG5cdFx0XHRcdGFjdGl2ZSA9IGNvbGxhcHNpYmxlID8gZmFsc2UgOiAwO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIERvbid0IGFsbG93IGNvbGxhcHNpYmxlOiBmYWxzZSBhbmQgYWN0aXZlOiBmYWxzZVxuXHRcdGlmICggIWNvbGxhcHNpYmxlICYmIGFjdGl2ZSA9PT0gZmFsc2UgJiYgdGhpcy5hbmNob3JzLmxlbmd0aCApIHtcblx0XHRcdGFjdGl2ZSA9IDA7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFjdGl2ZTtcblx0fSxcblxuXHRfZ2V0Q3JlYXRlRXZlbnREYXRhOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0dGFiOiB0aGlzLmFjdGl2ZSxcblx0XHRcdHBhbmVsOiAhdGhpcy5hY3RpdmUubGVuZ3RoID8gJCgpIDogdGhpcy5fZ2V0UGFuZWxGb3JUYWIoIHRoaXMuYWN0aXZlIClcblx0XHR9O1xuXHR9LFxuXG5cdF90YWJLZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGZvY3VzZWRUYWIgPSAkKCAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKSApLmNsb3Nlc3QoIFwibGlcIiApLFxuXHRcdFx0c2VsZWN0ZWRJbmRleCA9IHRoaXMudGFicy5pbmRleCggZm9jdXNlZFRhYiApLFxuXHRcdFx0Z29pbmdGb3J3YXJkID0gdHJ1ZTtcblxuXHRcdGlmICggdGhpcy5faGFuZGxlUGFnZU5hdiggZXZlbnQgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLlJJR0hUOlxuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkRPV046XG5cdFx0XHRzZWxlY3RlZEluZGV4Kys7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5VUDpcblx0XHRjYXNlICQudWkua2V5Q29kZS5MRUZUOlxuXHRcdFx0Z29pbmdGb3J3YXJkID0gZmFsc2U7XG5cdFx0XHRzZWxlY3RlZEluZGV4LS07XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5FTkQ6XG5cdFx0XHRzZWxlY3RlZEluZGV4ID0gdGhpcy5hbmNob3JzLmxlbmd0aCAtIDE7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5IT01FOlxuXHRcdFx0c2VsZWN0ZWRJbmRleCA9IDA7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5TUEFDRTpcblxuXHRcdFx0Ly8gQWN0aXZhdGUgb25seSwgbm8gY29sbGFwc2luZ1xuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdGNsZWFyVGltZW91dCggdGhpcy5hY3RpdmF0aW5nICk7XG5cdFx0XHR0aGlzLl9hY3RpdmF0ZSggc2VsZWN0ZWRJbmRleCApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkVOVEVSOlxuXG5cdFx0XHQvLyBUb2dnbGUgKGNhbmNlbCBkZWxheWVkIGFjdGl2YXRpb24sIGFsbG93IGNvbGxhcHNpbmcpXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLmFjdGl2YXRpbmcgKTtcblxuXHRcdFx0Ly8gRGV0ZXJtaW5lIGlmIHdlIHNob3VsZCBjb2xsYXBzZSBvciBhY3RpdmF0ZVxuXHRcdFx0dGhpcy5fYWN0aXZhdGUoIHNlbGVjdGVkSW5kZXggPT09IHRoaXMub3B0aW9ucy5hY3RpdmUgPyBmYWxzZSA6IHNlbGVjdGVkSW5kZXggKTtcblx0XHRcdHJldHVybjtcblx0XHRkZWZhdWx0OlxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIEZvY3VzIHRoZSBhcHByb3ByaWF0ZSB0YWIsIGJhc2VkIG9uIHdoaWNoIGtleSB3YXMgcHJlc3NlZFxuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLmFjdGl2YXRpbmcgKTtcblx0XHRzZWxlY3RlZEluZGV4ID0gdGhpcy5fZm9jdXNOZXh0VGFiKCBzZWxlY3RlZEluZGV4LCBnb2luZ0ZvcndhcmQgKTtcblxuXHRcdC8vIE5hdmlnYXRpbmcgd2l0aCBjb250cm9sL2NvbW1hbmQga2V5IHdpbGwgcHJldmVudCBhdXRvbWF0aWMgYWN0aXZhdGlvblxuXHRcdGlmICggIWV2ZW50LmN0cmxLZXkgJiYgIWV2ZW50Lm1ldGFLZXkgKSB7XG5cblx0XHRcdC8vIFVwZGF0ZSBhcmlhLXNlbGVjdGVkIGltbWVkaWF0ZWx5IHNvIHRoYXQgQVQgdGhpbmsgdGhlIHRhYiBpcyBhbHJlYWR5IHNlbGVjdGVkLlxuXHRcdFx0Ly8gT3RoZXJ3aXNlIEFUIG1heSBjb25mdXNlIHRoZSB1c2VyIGJ5IHN0YXRpbmcgdGhhdCB0aGV5IG5lZWQgdG8gYWN0aXZhdGUgdGhlIHRhYixcblx0XHRcdC8vIGJ1dCB0aGUgdGFiIHdpbGwgYWxyZWFkeSBiZSBhY3RpdmF0ZWQgYnkgdGhlIHRpbWUgdGhlIGFubm91bmNlbWVudCBmaW5pc2hlcy5cblx0XHRcdGZvY3VzZWRUYWIuYXR0ciggXCJhcmlhLXNlbGVjdGVkXCIsIFwiZmFsc2VcIiApO1xuXHRcdFx0dGhpcy50YWJzLmVxKCBzZWxlY3RlZEluZGV4ICkuYXR0ciggXCJhcmlhLXNlbGVjdGVkXCIsIFwidHJ1ZVwiICk7XG5cblx0XHRcdHRoaXMuYWN0aXZhdGluZyA9IHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5vcHRpb24oIFwiYWN0aXZlXCIsIHNlbGVjdGVkSW5kZXggKTtcblx0XHRcdH0sIHRoaXMuZGVsYXkgKTtcblx0XHR9XG5cdH0sXG5cblx0X3BhbmVsS2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggdGhpcy5faGFuZGxlUGFnZU5hdiggZXZlbnQgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBDdHJsK3VwIG1vdmVzIGZvY3VzIHRvIHRoZSBjdXJyZW50IHRhYlxuXHRcdGlmICggZXZlbnQuY3RybEtleSAmJiBldmVudC5rZXlDb2RlID09PSAkLnVpLmtleUNvZGUuVVAgKSB7XG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0dGhpcy5hY3RpdmUudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIEFsdCtwYWdlIHVwL2Rvd24gbW92ZXMgZm9jdXMgdG8gdGhlIHByZXZpb3VzL25leHQgdGFiIChhbmQgYWN0aXZhdGVzKVxuXHRfaGFuZGxlUGFnZU5hdjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggZXZlbnQuYWx0S2V5ICYmIGV2ZW50LmtleUNvZGUgPT09ICQudWkua2V5Q29kZS5QQUdFX1VQICkge1xuXHRcdFx0dGhpcy5fYWN0aXZhdGUoIHRoaXMuX2ZvY3VzTmV4dFRhYiggdGhpcy5vcHRpb25zLmFjdGl2ZSAtIDEsIGZhbHNlICkgKTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblx0XHRpZiAoIGV2ZW50LmFsdEtleSAmJiBldmVudC5rZXlDb2RlID09PSAkLnVpLmtleUNvZGUuUEFHRV9ET1dOICkge1xuXHRcdFx0dGhpcy5fYWN0aXZhdGUoIHRoaXMuX2ZvY3VzTmV4dFRhYiggdGhpcy5vcHRpb25zLmFjdGl2ZSArIDEsIHRydWUgKSApO1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXHR9LFxuXG5cdF9maW5kTmV4dFRhYjogZnVuY3Rpb24oIGluZGV4LCBnb2luZ0ZvcndhcmQgKSB7XG5cdFx0dmFyIGxhc3RUYWJJbmRleCA9IHRoaXMudGFicy5sZW5ndGggLSAxO1xuXG5cdFx0ZnVuY3Rpb24gY29uc3RyYWluKCkge1xuXHRcdFx0aWYgKCBpbmRleCA+IGxhc3RUYWJJbmRleCApIHtcblx0XHRcdFx0aW5kZXggPSAwO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBpbmRleCA8IDAgKSB7XG5cdFx0XHRcdGluZGV4ID0gbGFzdFRhYkluZGV4O1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGluZGV4O1xuXHRcdH1cblxuXHRcdHdoaWxlICggJC5pbkFycmF5KCBjb25zdHJhaW4oKSwgdGhpcy5vcHRpb25zLmRpc2FibGVkICkgIT09IC0xICkge1xuXHRcdFx0aW5kZXggPSBnb2luZ0ZvcndhcmQgPyBpbmRleCArIDEgOiBpbmRleCAtIDE7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGluZGV4O1xuXHR9LFxuXG5cdF9mb2N1c05leHRUYWI6IGZ1bmN0aW9uKCBpbmRleCwgZ29pbmdGb3J3YXJkICkge1xuXHRcdGluZGV4ID0gdGhpcy5fZmluZE5leHRUYWIoIGluZGV4LCBnb2luZ0ZvcndhcmQgKTtcblx0XHR0aGlzLnRhYnMuZXEoIGluZGV4ICkudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0cmV0dXJuIGluZGV4O1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdGlmICgga2V5ID09PSBcImFjdGl2ZVwiICkge1xuXG5cdFx0XHQvLyBfYWN0aXZhdGUoKSB3aWxsIGhhbmRsZSBpbnZhbGlkIHZhbHVlcyBhbmQgdXBkYXRlIHRoaXMub3B0aW9uc1xuXHRcdFx0dGhpcy5fYWN0aXZhdGUoIHZhbHVlICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdGlmICgga2V5ID09PSBcImNvbGxhcHNpYmxlXCIgKSB7XG5cdFx0XHR0aGlzLl90b2dnbGVDbGFzcyggXCJ1aS10YWJzLWNvbGxhcHNpYmxlXCIsIG51bGwsIHZhbHVlICk7XG5cblx0XHRcdC8vIFNldHRpbmcgY29sbGFwc2libGU6IGZhbHNlIHdoaWxlIGNvbGxhcHNlZDsgb3BlbiBmaXJzdCBwYW5lbFxuXHRcdFx0aWYgKCAhdmFsdWUgJiYgdGhpcy5vcHRpb25zLmFjdGl2ZSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdHRoaXMuX2FjdGl2YXRlKCAwICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwiZXZlbnRcIiApIHtcblx0XHRcdHRoaXMuX3NldHVwRXZlbnRzKCB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcImhlaWdodFN0eWxlXCIgKSB7XG5cdFx0XHR0aGlzLl9zZXR1cEhlaWdodFN0eWxlKCB2YWx1ZSApO1xuXHRcdH1cblx0fSxcblxuXHRfc2FuaXRpemVTZWxlY3RvcjogZnVuY3Rpb24oIGhhc2ggKSB7XG5cdFx0cmV0dXJuIGhhc2ggPyBoYXNoLnJlcGxhY2UoIC9bIVwiJCUmJygpKissLlxcLzo7PD0+P0BcXFtcXF1cXF5ge3x9fl0vZywgXCJcXFxcJCZcIiApIDogXCJcIjtcblx0fSxcblxuXHRyZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGxpcyA9IHRoaXMudGFibGlzdC5jaGlsZHJlbiggXCI6aGFzKGFbaHJlZl0pXCIgKTtcblxuXHRcdC8vIEdldCBkaXNhYmxlZCB0YWJzIGZyb20gY2xhc3MgYXR0cmlidXRlIGZyb20gSFRNTFxuXHRcdC8vIHRoaXMgd2lsbCBnZXQgY29udmVydGVkIHRvIGEgYm9vbGVhbiBpZiBuZWVkZWQgaW4gX3JlZnJlc2goKVxuXHRcdG9wdGlvbnMuZGlzYWJsZWQgPSAkLm1hcCggbGlzLmZpbHRlciggXCIudWktc3RhdGUtZGlzYWJsZWRcIiApLCBmdW5jdGlvbiggdGFiICkge1xuXHRcdFx0cmV0dXJuIGxpcy5pbmRleCggdGFiICk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy5fcHJvY2Vzc1RhYnMoKTtcblxuXHRcdC8vIFdhcyBjb2xsYXBzZWQgb3Igbm8gdGFic1xuXHRcdGlmICggb3B0aW9ucy5hY3RpdmUgPT09IGZhbHNlIHx8ICF0aGlzLmFuY2hvcnMubGVuZ3RoICkge1xuXHRcdFx0b3B0aW9ucy5hY3RpdmUgPSBmYWxzZTtcblx0XHRcdHRoaXMuYWN0aXZlID0gJCgpO1xuXG5cdFx0Ly8gd2FzIGFjdGl2ZSwgYnV0IGFjdGl2ZSB0YWIgaXMgZ29uZVxuXHRcdH0gZWxzZSBpZiAoIHRoaXMuYWN0aXZlLmxlbmd0aCAmJiAhJC5jb250YWlucyggdGhpcy50YWJsaXN0WyAwIF0sIHRoaXMuYWN0aXZlWyAwIF0gKSApIHtcblxuXHRcdFx0Ly8gYWxsIHJlbWFpbmluZyB0YWJzIGFyZSBkaXNhYmxlZFxuXHRcdFx0aWYgKCB0aGlzLnRhYnMubGVuZ3RoID09PSBvcHRpb25zLmRpc2FibGVkLmxlbmd0aCApIHtcblx0XHRcdFx0b3B0aW9ucy5hY3RpdmUgPSBmYWxzZTtcblx0XHRcdFx0dGhpcy5hY3RpdmUgPSAkKCk7XG5cblx0XHRcdC8vIGFjdGl2YXRlIHByZXZpb3VzIHRhYlxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5fYWN0aXZhdGUoIHRoaXMuX2ZpbmROZXh0VGFiKCBNYXRoLm1heCggMCwgb3B0aW9ucy5hY3RpdmUgLSAxICksIGZhbHNlICkgKTtcblx0XHRcdH1cblxuXHRcdC8vIHdhcyBhY3RpdmUsIGFjdGl2ZSB0YWIgc3RpbGwgZXhpc3RzXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gbWFrZSBzdXJlIGFjdGl2ZSBpbmRleCBpcyBjb3JyZWN0XG5cdFx0XHRvcHRpb25zLmFjdGl2ZSA9IHRoaXMudGFicy5pbmRleCggdGhpcy5hY3RpdmUgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cdH0sXG5cblx0X3JlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX3NldE9wdGlvbkRpc2FibGVkKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKTtcblx0XHR0aGlzLl9zZXR1cEV2ZW50cyggdGhpcy5vcHRpb25zLmV2ZW50ICk7XG5cdFx0dGhpcy5fc2V0dXBIZWlnaHRTdHlsZSggdGhpcy5vcHRpb25zLmhlaWdodFN0eWxlICk7XG5cblx0XHR0aGlzLnRhYnMubm90KCB0aGlzLmFjdGl2ZSApLmF0dHIoIHtcblx0XHRcdFwiYXJpYS1zZWxlY3RlZFwiOiBcImZhbHNlXCIsXG5cdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJmYWxzZVwiLFxuXHRcdFx0dGFiSW5kZXg6IC0xXG5cdFx0fSApO1xuXHRcdHRoaXMucGFuZWxzLm5vdCggdGhpcy5fZ2V0UGFuZWxGb3JUYWIoIHRoaXMuYWN0aXZlICkgKVxuXHRcdFx0LmhpZGUoKVxuXHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0XCJhcmlhLWhpZGRlblwiOiBcInRydWVcIlxuXHRcdFx0fSApO1xuXG5cdFx0Ly8gTWFrZSBzdXJlIG9uZSB0YWIgaXMgaW4gdGhlIHRhYiBvcmRlclxuXHRcdGlmICggIXRoaXMuYWN0aXZlLmxlbmd0aCApIHtcblx0XHRcdHRoaXMudGFicy5lcSggMCApLmF0dHIoIFwidGFiSW5kZXhcIiwgMCApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmFjdGl2ZVxuXHRcdFx0XHQuYXR0cigge1xuXHRcdFx0XHRcdFwiYXJpYS1zZWxlY3RlZFwiOiBcInRydWVcIixcblx0XHRcdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJ0cnVlXCIsXG5cdFx0XHRcdFx0dGFiSW5kZXg6IDBcblx0XHRcdFx0fSApO1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuYWN0aXZlLCBcInVpLXRhYnMtYWN0aXZlXCIsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdHRoaXMuX2dldFBhbmVsRm9yVGFiKCB0aGlzLmFjdGl2ZSApXG5cdFx0XHRcdC5zaG93KClcblx0XHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0XHRcImFyaWEtaGlkZGVuXCI6IFwiZmFsc2VcIlxuXHRcdFx0XHR9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9wcm9jZXNzVGFiczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0cHJldlRhYnMgPSB0aGlzLnRhYnMsXG5cdFx0XHRwcmV2QW5jaG9ycyA9IHRoaXMuYW5jaG9ycyxcblx0XHRcdHByZXZQYW5lbHMgPSB0aGlzLnBhbmVscztcblxuXHRcdHRoaXMudGFibGlzdCA9IHRoaXMuX2dldExpc3QoKS5hdHRyKCBcInJvbGVcIiwgXCJ0YWJsaXN0XCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy50YWJsaXN0LCBcInVpLXRhYnMtbmF2XCIsXG5cdFx0XHRcInVpLWhlbHBlci1yZXNldCB1aS1oZWxwZXItY2xlYXJmaXggdWktd2lkZ2V0LWhlYWRlclwiICk7XG5cblx0XHQvLyBQcmV2ZW50IHVzZXJzIGZyb20gZm9jdXNpbmcgZGlzYWJsZWQgdGFicyB2aWEgY2xpY2tcblx0XHR0aGlzLnRhYmxpc3Rcblx0XHRcdC5vbiggXCJtb3VzZWRvd25cIiArIHRoaXMuZXZlbnROYW1lc3BhY2UsIFwiPiBsaVwiLCBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggJCggdGhpcyApLmlzKCBcIi51aS1zdGF0ZS1kaXNhYmxlZFwiICkgKSB7XG5cdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApXG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFIDw5XG5cdFx0XHQvLyBQcmV2ZW50aW5nIHRoZSBkZWZhdWx0IGFjdGlvbiBpbiBtb3VzZWRvd24gZG9lc24ndCBwcmV2ZW50IElFXG5cdFx0XHQvLyBmcm9tIGZvY3VzaW5nIHRoZSBlbGVtZW50LCBzbyBpZiB0aGUgYW5jaG9yIGdldHMgZm9jdXNlZCwgYmx1ci5cblx0XHRcdC8vIFdlIGRvbid0IGhhdmUgdG8gd29ycnkgYWJvdXQgZm9jdXNpbmcgdGhlIHByZXZpb3VzbHkgZm9jdXNlZFxuXHRcdFx0Ly8gZWxlbWVudCBzaW5jZSBjbGlja2luZyBvbiBhIG5vbi1mb2N1c2FibGUgZWxlbWVudCBzaG91bGQgZm9jdXNcblx0XHRcdC8vIHRoZSBib2R5IGFueXdheS5cblx0XHRcdC5vbiggXCJmb2N1c1wiICsgdGhpcy5ldmVudE5hbWVzcGFjZSwgXCIudWktdGFicy1hbmNob3JcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggJCggdGhpcyApLmNsb3Nlc3QoIFwibGlcIiApLmlzKCBcIi51aS1zdGF0ZS1kaXNhYmxlZFwiICkgKSB7XG5cdFx0XHRcdFx0dGhpcy5ibHVyKCk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblxuXHRcdHRoaXMudGFicyA9IHRoaXMudGFibGlzdC5maW5kKCBcIj4gbGk6aGFzKGFbaHJlZl0pXCIgKVxuXHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0cm9sZTogXCJ0YWJcIixcblx0XHRcdFx0dGFiSW5kZXg6IC0xXG5cdFx0XHR9ICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudGFicywgXCJ1aS10YWJzLXRhYlwiLCBcInVpLXN0YXRlLWRlZmF1bHRcIiApO1xuXG5cdFx0dGhpcy5hbmNob3JzID0gdGhpcy50YWJzLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4gJCggXCJhXCIsIHRoaXMgKVsgMCBdO1xuXHRcdH0gKVxuXHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0cm9sZTogXCJwcmVzZW50YXRpb25cIixcblx0XHRcdFx0dGFiSW5kZXg6IC0xXG5cdFx0XHR9ICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuYW5jaG9ycywgXCJ1aS10YWJzLWFuY2hvclwiICk7XG5cblx0XHR0aGlzLnBhbmVscyA9ICQoKTtcblxuXHRcdHRoaXMuYW5jaG9ycy5lYWNoKCBmdW5jdGlvbiggaSwgYW5jaG9yICkge1xuXHRcdFx0dmFyIHNlbGVjdG9yLCBwYW5lbCwgcGFuZWxJZCxcblx0XHRcdFx0YW5jaG9ySWQgPSAkKCBhbmNob3IgKS51bmlxdWVJZCgpLmF0dHIoIFwiaWRcIiApLFxuXHRcdFx0XHR0YWIgPSAkKCBhbmNob3IgKS5jbG9zZXN0KCBcImxpXCIgKSxcblx0XHRcdFx0b3JpZ2luYWxBcmlhQ29udHJvbHMgPSB0YWIuYXR0ciggXCJhcmlhLWNvbnRyb2xzXCIgKTtcblxuXHRcdFx0Ly8gSW5saW5lIHRhYlxuXHRcdFx0aWYgKCB0aGF0Ll9pc0xvY2FsKCBhbmNob3IgKSApIHtcblx0XHRcdFx0c2VsZWN0b3IgPSBhbmNob3IuaGFzaDtcblx0XHRcdFx0cGFuZWxJZCA9IHNlbGVjdG9yLnN1YnN0cmluZyggMSApO1xuXHRcdFx0XHRwYW5lbCA9IHRoYXQuZWxlbWVudC5maW5kKCB0aGF0Ll9zYW5pdGl6ZVNlbGVjdG9yKCBzZWxlY3RvciApICk7XG5cblx0XHRcdC8vIHJlbW90ZSB0YWJcblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gSWYgdGhlIHRhYiBkb2Vzbid0IGFscmVhZHkgaGF2ZSBhcmlhLWNvbnRyb2xzLFxuXHRcdFx0XHQvLyBnZW5lcmF0ZSBhbiBpZCBieSB1c2luZyBhIHRocm93LWF3YXkgZWxlbWVudFxuXHRcdFx0XHRwYW5lbElkID0gdGFiLmF0dHIoIFwiYXJpYS1jb250cm9sc1wiICkgfHwgJCgge30gKS51bmlxdWVJZCgpWyAwIF0uaWQ7XG5cdFx0XHRcdHNlbGVjdG9yID0gXCIjXCIgKyBwYW5lbElkO1xuXHRcdFx0XHRwYW5lbCA9IHRoYXQuZWxlbWVudC5maW5kKCBzZWxlY3RvciApO1xuXHRcdFx0XHRpZiAoICFwYW5lbC5sZW5ndGggKSB7XG5cdFx0XHRcdFx0cGFuZWwgPSB0aGF0Ll9jcmVhdGVQYW5lbCggcGFuZWxJZCApO1xuXHRcdFx0XHRcdHBhbmVsLmluc2VydEFmdGVyKCB0aGF0LnBhbmVsc1sgaSAtIDEgXSB8fCB0aGF0LnRhYmxpc3QgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRwYW5lbC5hdHRyKCBcImFyaWEtbGl2ZVwiLCBcInBvbGl0ZVwiICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggcGFuZWwubGVuZ3RoICkge1xuXHRcdFx0XHR0aGF0LnBhbmVscyA9IHRoYXQucGFuZWxzLmFkZCggcGFuZWwgKTtcblx0XHRcdH1cblx0XHRcdGlmICggb3JpZ2luYWxBcmlhQ29udHJvbHMgKSB7XG5cdFx0XHRcdHRhYi5kYXRhKCBcInVpLXRhYnMtYXJpYS1jb250cm9sc1wiLCBvcmlnaW5hbEFyaWFDb250cm9scyApO1xuXHRcdFx0fVxuXHRcdFx0dGFiLmF0dHIoIHtcblx0XHRcdFx0XCJhcmlhLWNvbnRyb2xzXCI6IHBhbmVsSWQsXG5cdFx0XHRcdFwiYXJpYS1sYWJlbGxlZGJ5XCI6IGFuY2hvcklkXG5cdFx0XHR9ICk7XG5cdFx0XHRwYW5lbC5hdHRyKCBcImFyaWEtbGFiZWxsZWRieVwiLCBhbmNob3JJZCApO1xuXHRcdH0gKTtcblxuXHRcdHRoaXMucGFuZWxzLmF0dHIoIFwicm9sZVwiLCBcInRhYnBhbmVsXCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5wYW5lbHMsIFwidWktdGFicy1wYW5lbFwiLCBcInVpLXdpZGdldC1jb250ZW50XCIgKTtcblxuXHRcdC8vIEF2b2lkIG1lbW9yeSBsZWFrcyAoIzEwMDU2KVxuXHRcdGlmICggcHJldlRhYnMgKSB7XG5cdFx0XHR0aGlzLl9vZmYoIHByZXZUYWJzLm5vdCggdGhpcy50YWJzICkgKTtcblx0XHRcdHRoaXMuX29mZiggcHJldkFuY2hvcnMubm90KCB0aGlzLmFuY2hvcnMgKSApO1xuXHRcdFx0dGhpcy5fb2ZmKCBwcmV2UGFuZWxzLm5vdCggdGhpcy5wYW5lbHMgKSApO1xuXHRcdH1cblx0fSxcblxuXHQvLyBBbGxvdyBvdmVycmlkaW5nIGhvdyB0byBmaW5kIHRoZSBsaXN0IGZvciByYXJlIHVzYWdlIHNjZW5hcmlvcyAoIzc3MTUpXG5cdF9nZXRMaXN0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy50YWJsaXN0IHx8IHRoaXMuZWxlbWVudC5maW5kKCBcIm9sLCB1bFwiICkuZXEoIDAgKTtcblx0fSxcblxuXHRfY3JlYXRlUGFuZWw6IGZ1bmN0aW9uKCBpZCApIHtcblx0XHRyZXR1cm4gJCggXCI8ZGl2PlwiIClcblx0XHRcdC5hdHRyKCBcImlkXCIsIGlkIClcblx0XHRcdC5kYXRhKCBcInVpLXRhYnMtZGVzdHJveVwiLCB0cnVlICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbkRpc2FibGVkOiBmdW5jdGlvbiggZGlzYWJsZWQgKSB7XG5cdFx0dmFyIGN1cnJlbnRJdGVtLCBsaSwgaTtcblxuXHRcdGlmICggJC5pc0FycmF5KCBkaXNhYmxlZCApICkge1xuXHRcdFx0aWYgKCAhZGlzYWJsZWQubGVuZ3RoICkge1xuXHRcdFx0XHRkaXNhYmxlZCA9IGZhbHNlO1xuXHRcdFx0fSBlbHNlIGlmICggZGlzYWJsZWQubGVuZ3RoID09PSB0aGlzLmFuY2hvcnMubGVuZ3RoICkge1xuXHRcdFx0XHRkaXNhYmxlZCA9IHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gRGlzYWJsZSB0YWJzXG5cdFx0Zm9yICggaSA9IDA7ICggbGkgPSB0aGlzLnRhYnNbIGkgXSApOyBpKysgKSB7XG5cdFx0XHRjdXJyZW50SXRlbSA9ICQoIGxpICk7XG5cdFx0XHRpZiAoIGRpc2FibGVkID09PSB0cnVlIHx8ICQuaW5BcnJheSggaSwgZGlzYWJsZWQgKSAhPT0gLTEgKSB7XG5cdFx0XHRcdGN1cnJlbnRJdGVtLmF0dHIoIFwiYXJpYS1kaXNhYmxlZFwiLCBcInRydWVcIiApO1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggY3VycmVudEl0ZW0sIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0Y3VycmVudEl0ZW0ucmVtb3ZlQXR0ciggXCJhcmlhLWRpc2FibGVkXCIgKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGN1cnJlbnRJdGVtLCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLm9wdGlvbnMuZGlzYWJsZWQgPSBkaXNhYmxlZDtcblxuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCB0aGlzLndpZGdldCgpLCB0aGlzLndpZGdldEZ1bGxOYW1lICsgXCItZGlzYWJsZWRcIiwgbnVsbCxcblx0XHRcdGRpc2FibGVkID09PSB0cnVlICk7XG5cdH0sXG5cblx0X3NldHVwRXZlbnRzOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGV2ZW50cyA9IHt9O1xuXHRcdGlmICggZXZlbnQgKSB7XG5cdFx0XHQkLmVhY2goIGV2ZW50LnNwbGl0KCBcIiBcIiApLCBmdW5jdGlvbiggaW5kZXgsIGV2ZW50TmFtZSApIHtcblx0XHRcdFx0ZXZlbnRzWyBldmVudE5hbWUgXSA9IFwiX2V2ZW50SGFuZGxlclwiO1xuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX29mZiggdGhpcy5hbmNob3JzLmFkZCggdGhpcy50YWJzICkuYWRkKCB0aGlzLnBhbmVscyApICk7XG5cblx0XHQvLyBBbHdheXMgcHJldmVudCB0aGUgZGVmYXVsdCBhY3Rpb24sIGV2ZW4gd2hlbiBkaXNhYmxlZFxuXHRcdHRoaXMuX29uKCB0cnVlLCB0aGlzLmFuY2hvcnMsIHtcblx0XHRcdGNsaWNrOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdHRoaXMuX29uKCB0aGlzLmFuY2hvcnMsIGV2ZW50cyApO1xuXHRcdHRoaXMuX29uKCB0aGlzLnRhYnMsIHsga2V5ZG93bjogXCJfdGFiS2V5ZG93blwiIH0gKTtcblx0XHR0aGlzLl9vbiggdGhpcy5wYW5lbHMsIHsga2V5ZG93bjogXCJfcGFuZWxLZXlkb3duXCIgfSApO1xuXG5cdFx0dGhpcy5fZm9jdXNhYmxlKCB0aGlzLnRhYnMgKTtcblx0XHR0aGlzLl9ob3ZlcmFibGUoIHRoaXMudGFicyApO1xuXHR9LFxuXG5cdF9zZXR1cEhlaWdodFN0eWxlOiBmdW5jdGlvbiggaGVpZ2h0U3R5bGUgKSB7XG5cdFx0dmFyIG1heEhlaWdodCxcblx0XHRcdHBhcmVudCA9IHRoaXMuZWxlbWVudC5wYXJlbnQoKTtcblxuXHRcdGlmICggaGVpZ2h0U3R5bGUgPT09IFwiZmlsbFwiICkge1xuXHRcdFx0bWF4SGVpZ2h0ID0gcGFyZW50LmhlaWdodCgpO1xuXHRcdFx0bWF4SGVpZ2h0IC09IHRoaXMuZWxlbWVudC5vdXRlckhlaWdodCgpIC0gdGhpcy5lbGVtZW50LmhlaWdodCgpO1xuXG5cdFx0XHR0aGlzLmVsZW1lbnQuc2libGluZ3MoIFwiOnZpc2libGVcIiApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgZWxlbSA9ICQoIHRoaXMgKSxcblx0XHRcdFx0XHRwb3NpdGlvbiA9IGVsZW0uY3NzKCBcInBvc2l0aW9uXCIgKTtcblxuXHRcdFx0XHRpZiAoIHBvc2l0aW9uID09PSBcImFic29sdXRlXCIgfHwgcG9zaXRpb24gPT09IFwiZml4ZWRcIiApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdFx0bWF4SGVpZ2h0IC09IGVsZW0ub3V0ZXJIZWlnaHQoIHRydWUgKTtcblx0XHRcdH0gKTtcblxuXHRcdFx0dGhpcy5lbGVtZW50LmNoaWxkcmVuKCkubm90KCB0aGlzLnBhbmVscyApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRtYXhIZWlnaHQgLT0gJCggdGhpcyApLm91dGVySGVpZ2h0KCB0cnVlICk7XG5cdFx0XHR9ICk7XG5cblx0XHRcdHRoaXMucGFuZWxzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQkKCB0aGlzICkuaGVpZ2h0KCBNYXRoLm1heCggMCwgbWF4SGVpZ2h0IC1cblx0XHRcdFx0XHQkKCB0aGlzICkuaW5uZXJIZWlnaHQoKSArICQoIHRoaXMgKS5oZWlnaHQoKSApICk7XG5cdFx0XHR9IClcblx0XHRcdFx0LmNzcyggXCJvdmVyZmxvd1wiLCBcImF1dG9cIiApO1xuXHRcdH0gZWxzZSBpZiAoIGhlaWdodFN0eWxlID09PSBcImF1dG9cIiApIHtcblx0XHRcdG1heEhlaWdodCA9IDA7XG5cdFx0XHR0aGlzLnBhbmVscy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0bWF4SGVpZ2h0ID0gTWF0aC5tYXgoIG1heEhlaWdodCwgJCggdGhpcyApLmhlaWdodCggXCJcIiApLmhlaWdodCgpICk7XG5cdFx0XHR9ICkuaGVpZ2h0KCBtYXhIZWlnaHQgKTtcblx0XHR9XG5cdH0sXG5cblx0X2V2ZW50SGFuZGxlcjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0YWN0aXZlID0gdGhpcy5hY3RpdmUsXG5cdFx0XHRhbmNob3IgPSAkKCBldmVudC5jdXJyZW50VGFyZ2V0ICksXG5cdFx0XHR0YWIgPSBhbmNob3IuY2xvc2VzdCggXCJsaVwiICksXG5cdFx0XHRjbGlja2VkSXNBY3RpdmUgPSB0YWJbIDAgXSA9PT0gYWN0aXZlWyAwIF0sXG5cdFx0XHRjb2xsYXBzaW5nID0gY2xpY2tlZElzQWN0aXZlICYmIG9wdGlvbnMuY29sbGFwc2libGUsXG5cdFx0XHR0b1Nob3cgPSBjb2xsYXBzaW5nID8gJCgpIDogdGhpcy5fZ2V0UGFuZWxGb3JUYWIoIHRhYiApLFxuXHRcdFx0dG9IaWRlID0gIWFjdGl2ZS5sZW5ndGggPyAkKCkgOiB0aGlzLl9nZXRQYW5lbEZvclRhYiggYWN0aXZlICksXG5cdFx0XHRldmVudERhdGEgPSB7XG5cdFx0XHRcdG9sZFRhYjogYWN0aXZlLFxuXHRcdFx0XHRvbGRQYW5lbDogdG9IaWRlLFxuXHRcdFx0XHRuZXdUYWI6IGNvbGxhcHNpbmcgPyAkKCkgOiB0YWIsXG5cdFx0XHRcdG5ld1BhbmVsOiB0b1Nob3dcblx0XHRcdH07XG5cblx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0aWYgKCB0YWIuaGFzQ2xhc3MoIFwidWktc3RhdGUtZGlzYWJsZWRcIiApIHx8XG5cblx0XHRcdFx0Ly8gdGFiIGlzIGFscmVhZHkgbG9hZGluZ1xuXHRcdFx0XHR0YWIuaGFzQ2xhc3MoIFwidWktdGFicy1sb2FkaW5nXCIgKSB8fFxuXG5cdFx0XHRcdC8vIGNhbid0IHN3aXRjaCBkdXJuaW5nIGFuIGFuaW1hdGlvblxuXHRcdFx0XHR0aGlzLnJ1bm5pbmcgfHxcblxuXHRcdFx0XHQvLyBjbGljayBvbiBhY3RpdmUgaGVhZGVyLCBidXQgbm90IGNvbGxhcHNpYmxlXG5cdFx0XHRcdCggY2xpY2tlZElzQWN0aXZlICYmICFvcHRpb25zLmNvbGxhcHNpYmxlICkgfHxcblxuXHRcdFx0XHQvLyBhbGxvdyBjYW5jZWxpbmcgYWN0aXZhdGlvblxuXHRcdFx0XHQoIHRoaXMuX3RyaWdnZXIoIFwiYmVmb3JlQWN0aXZhdGVcIiwgZXZlbnQsIGV2ZW50RGF0YSApID09PSBmYWxzZSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdG9wdGlvbnMuYWN0aXZlID0gY29sbGFwc2luZyA/IGZhbHNlIDogdGhpcy50YWJzLmluZGV4KCB0YWIgKTtcblxuXHRcdHRoaXMuYWN0aXZlID0gY2xpY2tlZElzQWN0aXZlID8gJCgpIDogdGFiO1xuXHRcdGlmICggdGhpcy54aHIgKSB7XG5cdFx0XHR0aGlzLnhoci5hYm9ydCgpO1xuXHRcdH1cblxuXHRcdGlmICggIXRvSGlkZS5sZW5ndGggJiYgIXRvU2hvdy5sZW5ndGggKSB7XG5cdFx0XHQkLmVycm9yKCBcImpRdWVyeSBVSSBUYWJzOiBNaXNtYXRjaGluZyBmcmFnbWVudCBpZGVudGlmaWVyLlwiICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0b1Nob3cubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5sb2FkKCB0aGlzLnRhYnMuaW5kZXgoIHRhYiApLCBldmVudCApO1xuXHRcdH1cblx0XHR0aGlzLl90b2dnbGUoIGV2ZW50LCBldmVudERhdGEgKTtcblx0fSxcblxuXHQvLyBIYW5kbGVzIHNob3cvaGlkZSBmb3Igc2VsZWN0aW5nIHRhYnNcblx0X3RvZ2dsZTogZnVuY3Rpb24oIGV2ZW50LCBldmVudERhdGEgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0dG9TaG93ID0gZXZlbnREYXRhLm5ld1BhbmVsLFxuXHRcdFx0dG9IaWRlID0gZXZlbnREYXRhLm9sZFBhbmVsO1xuXG5cdFx0dGhpcy5ydW5uaW5nID0gdHJ1ZTtcblxuXHRcdGZ1bmN0aW9uIGNvbXBsZXRlKCkge1xuXHRcdFx0dGhhdC5ydW5uaW5nID0gZmFsc2U7XG5cdFx0XHR0aGF0Ll90cmlnZ2VyKCBcImFjdGl2YXRlXCIsIGV2ZW50LCBldmVudERhdGEgKTtcblx0XHR9XG5cblx0XHRmdW5jdGlvbiBzaG93KCkge1xuXHRcdFx0dGhhdC5fYWRkQ2xhc3MoIGV2ZW50RGF0YS5uZXdUYWIuY2xvc2VzdCggXCJsaVwiICksIFwidWktdGFicy1hY3RpdmVcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXG5cdFx0XHRpZiAoIHRvU2hvdy5sZW5ndGggJiYgdGhhdC5vcHRpb25zLnNob3cgKSB7XG5cdFx0XHRcdHRoYXQuX3Nob3coIHRvU2hvdywgdGhhdC5vcHRpb25zLnNob3csIGNvbXBsZXRlICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0b1Nob3cuc2hvdygpO1xuXHRcdFx0XHRjb21wbGV0ZSgpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIFN0YXJ0IG91dCBieSBoaWRpbmcsIHRoZW4gc2hvd2luZywgdGhlbiBjb21wbGV0aW5nXG5cdFx0aWYgKCB0b0hpZGUubGVuZ3RoICYmIHRoaXMub3B0aW9ucy5oaWRlICkge1xuXHRcdFx0dGhpcy5faGlkZSggdG9IaWRlLCB0aGlzLm9wdGlvbnMuaGlkZSwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBldmVudERhdGEub2xkVGFiLmNsb3Nlc3QoIFwibGlcIiApLFxuXHRcdFx0XHRcdFwidWktdGFicy1hY3RpdmVcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0XHRzaG93KCk7XG5cdFx0XHR9ICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBldmVudERhdGEub2xkVGFiLmNsb3Nlc3QoIFwibGlcIiApLFxuXHRcdFx0XHRcInVpLXRhYnMtYWN0aXZlXCIsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdHRvSGlkZS5oaWRlKCk7XG5cdFx0XHRzaG93KCk7XG5cdFx0fVxuXG5cdFx0dG9IaWRlLmF0dHIoIFwiYXJpYS1oaWRkZW5cIiwgXCJ0cnVlXCIgKTtcblx0XHRldmVudERhdGEub2xkVGFiLmF0dHIoIHtcblx0XHRcdFwiYXJpYS1zZWxlY3RlZFwiOiBcImZhbHNlXCIsXG5cdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJmYWxzZVwiXG5cdFx0fSApO1xuXG5cdFx0Ly8gSWYgd2UncmUgc3dpdGNoaW5nIHRhYnMsIHJlbW92ZSB0aGUgb2xkIHRhYiBmcm9tIHRoZSB0YWIgb3JkZXIuXG5cdFx0Ly8gSWYgd2UncmUgb3BlbmluZyBmcm9tIGNvbGxhcHNlZCBzdGF0ZSwgcmVtb3ZlIHRoZSBwcmV2aW91cyB0YWIgZnJvbSB0aGUgdGFiIG9yZGVyLlxuXHRcdC8vIElmIHdlJ3JlIGNvbGxhcHNpbmcsIHRoZW4ga2VlcCB0aGUgY29sbGFwc2luZyB0YWIgaW4gdGhlIHRhYiBvcmRlci5cblx0XHRpZiAoIHRvU2hvdy5sZW5ndGggJiYgdG9IaWRlLmxlbmd0aCApIHtcblx0XHRcdGV2ZW50RGF0YS5vbGRUYWIuYXR0ciggXCJ0YWJJbmRleFwiLCAtMSApO1xuXHRcdH0gZWxzZSBpZiAoIHRvU2hvdy5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLnRhYnMuZmlsdGVyKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0cmV0dXJuICQoIHRoaXMgKS5hdHRyKCBcInRhYkluZGV4XCIgKSA9PT0gMDtcblx0XHRcdH0gKVxuXHRcdFx0XHQuYXR0ciggXCJ0YWJJbmRleFwiLCAtMSApO1xuXHRcdH1cblxuXHRcdHRvU2hvdy5hdHRyKCBcImFyaWEtaGlkZGVuXCIsIFwiZmFsc2VcIiApO1xuXHRcdGV2ZW50RGF0YS5uZXdUYWIuYXR0cigge1xuXHRcdFx0XCJhcmlhLXNlbGVjdGVkXCI6IFwidHJ1ZVwiLFxuXHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwidHJ1ZVwiLFxuXHRcdFx0dGFiSW5kZXg6IDBcblx0XHR9ICk7XG5cdH0sXG5cblx0X2FjdGl2YXRlOiBmdW5jdGlvbiggaW5kZXggKSB7XG5cdFx0dmFyIGFuY2hvcixcblx0XHRcdGFjdGl2ZSA9IHRoaXMuX2ZpbmRBY3RpdmUoIGluZGV4ICk7XG5cblx0XHQvLyBUcnlpbmcgdG8gYWN0aXZhdGUgdGhlIGFscmVhZHkgYWN0aXZlIHBhbmVsXG5cdFx0aWYgKCBhY3RpdmVbIDAgXSA9PT0gdGhpcy5hY3RpdmVbIDAgXSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBUcnlpbmcgdG8gY29sbGFwc2UsIHNpbXVsYXRlIGEgY2xpY2sgb24gdGhlIGN1cnJlbnQgYWN0aXZlIGhlYWRlclxuXHRcdGlmICggIWFjdGl2ZS5sZW5ndGggKSB7XG5cdFx0XHRhY3RpdmUgPSB0aGlzLmFjdGl2ZTtcblx0XHR9XG5cblx0XHRhbmNob3IgPSBhY3RpdmUuZmluZCggXCIudWktdGFicy1hbmNob3JcIiApWyAwIF07XG5cdFx0dGhpcy5fZXZlbnRIYW5kbGVyKCB7XG5cdFx0XHR0YXJnZXQ6IGFuY2hvcixcblx0XHRcdGN1cnJlbnRUYXJnZXQ6IGFuY2hvcixcblx0XHRcdHByZXZlbnREZWZhdWx0OiAkLm5vb3Bcblx0XHR9ICk7XG5cdH0sXG5cblx0X2ZpbmRBY3RpdmU6IGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHRyZXR1cm4gaW5kZXggPT09IGZhbHNlID8gJCgpIDogdGhpcy50YWJzLmVxKCBpbmRleCApO1xuXHR9LFxuXG5cdF9nZXRJbmRleDogZnVuY3Rpb24oIGluZGV4ICkge1xuXG5cdFx0Ly8gbWV0YS1mdW5jdGlvbiB0byBnaXZlIHVzZXJzIG9wdGlvbiB0byBwcm92aWRlIGEgaHJlZiBzdHJpbmcgaW5zdGVhZCBvZiBhIG51bWVyaWNhbCBpbmRleC5cblx0XHRpZiAoIHR5cGVvZiBpbmRleCA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdGluZGV4ID0gdGhpcy5hbmNob3JzLmluZGV4KCB0aGlzLmFuY2hvcnMuZmlsdGVyKCBcIltocmVmJD0nXCIgK1xuXHRcdFx0XHQkLnVpLmVzY2FwZVNlbGVjdG9yKCBpbmRleCApICsgXCInXVwiICkgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gaW5kZXg7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggdGhpcy54aHIgKSB7XG5cdFx0XHR0aGlzLnhoci5hYm9ydCgpO1xuXHRcdH1cblxuXHRcdHRoaXMudGFibGlzdFxuXHRcdFx0LnJlbW92ZUF0dHIoIFwicm9sZVwiIClcblx0XHRcdC5vZmYoIHRoaXMuZXZlbnROYW1lc3BhY2UgKTtcblxuXHRcdHRoaXMuYW5jaG9yc1xuXHRcdFx0LnJlbW92ZUF0dHIoIFwicm9sZSB0YWJJbmRleFwiIClcblx0XHRcdC5yZW1vdmVVbmlxdWVJZCgpO1xuXG5cdFx0dGhpcy50YWJzLmFkZCggdGhpcy5wYW5lbHMgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggJC5kYXRhKCB0aGlzLCBcInVpLXRhYnMtZGVzdHJveVwiICkgKSB7XG5cdFx0XHRcdCQoIHRoaXMgKS5yZW1vdmUoKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdCQoIHRoaXMgKS5yZW1vdmVBdHRyKCBcInJvbGUgdGFiSW5kZXggXCIgK1xuXHRcdFx0XHRcdFwiYXJpYS1saXZlIGFyaWEtYnVzeSBhcmlhLXNlbGVjdGVkIGFyaWEtbGFiZWxsZWRieSBhcmlhLWhpZGRlbiBhcmlhLWV4cGFuZGVkXCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHR0aGlzLnRhYnMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgbGkgPSAkKCB0aGlzICksXG5cdFx0XHRcdHByZXYgPSBsaS5kYXRhKCBcInVpLXRhYnMtYXJpYS1jb250cm9sc1wiICk7XG5cdFx0XHRpZiAoIHByZXYgKSB7XG5cdFx0XHRcdGxpXG5cdFx0XHRcdFx0LmF0dHIoIFwiYXJpYS1jb250cm9sc1wiLCBwcmV2IClcblx0XHRcdFx0XHQucmVtb3ZlRGF0YSggXCJ1aS10YWJzLWFyaWEtY29udHJvbHNcIiApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0bGkucmVtb3ZlQXR0ciggXCJhcmlhLWNvbnRyb2xzXCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHR0aGlzLnBhbmVscy5zaG93KCk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5oZWlnaHRTdHlsZSAhPT0gXCJjb250ZW50XCIgKSB7XG5cdFx0XHR0aGlzLnBhbmVscy5jc3MoIFwiaGVpZ2h0XCIsIFwiXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0ZW5hYmxlOiBmdW5jdGlvbiggaW5kZXggKSB7XG5cdFx0dmFyIGRpc2FibGVkID0gdGhpcy5vcHRpb25zLmRpc2FibGVkO1xuXHRcdGlmICggZGlzYWJsZWQgPT09IGZhbHNlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggaW5kZXggPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGRpc2FibGVkID0gZmFsc2U7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGluZGV4ID0gdGhpcy5fZ2V0SW5kZXgoIGluZGV4ICk7XG5cdFx0XHRpZiAoICQuaXNBcnJheSggZGlzYWJsZWQgKSApIHtcblx0XHRcdFx0ZGlzYWJsZWQgPSAkLm1hcCggZGlzYWJsZWQsIGZ1bmN0aW9uKCBudW0gKSB7XG5cdFx0XHRcdFx0cmV0dXJuIG51bSAhPT0gaW5kZXggPyBudW0gOiBudWxsO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRkaXNhYmxlZCA9ICQubWFwKCB0aGlzLnRhYnMsIGZ1bmN0aW9uKCBsaSwgbnVtICkge1xuXHRcdFx0XHRcdHJldHVybiBudW0gIT09IGluZGV4ID8gbnVtIDogbnVsbDtcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdH1cblx0XHR0aGlzLl9zZXRPcHRpb25EaXNhYmxlZCggZGlzYWJsZWQgKTtcblx0fSxcblxuXHRkaXNhYmxlOiBmdW5jdGlvbiggaW5kZXggKSB7XG5cdFx0dmFyIGRpc2FibGVkID0gdGhpcy5vcHRpb25zLmRpc2FibGVkO1xuXHRcdGlmICggZGlzYWJsZWQgPT09IHRydWUgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBpbmRleCA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0ZGlzYWJsZWQgPSB0cnVlO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRpbmRleCA9IHRoaXMuX2dldEluZGV4KCBpbmRleCApO1xuXHRcdFx0aWYgKCAkLmluQXJyYXkoIGluZGV4LCBkaXNhYmxlZCApICE9PSAtMSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAkLmlzQXJyYXkoIGRpc2FibGVkICkgKSB7XG5cdFx0XHRcdGRpc2FibGVkID0gJC5tZXJnZSggWyBpbmRleCBdLCBkaXNhYmxlZCApLnNvcnQoKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGRpc2FibGVkID0gWyBpbmRleCBdO1xuXHRcdFx0fVxuXHRcdH1cblx0XHR0aGlzLl9zZXRPcHRpb25EaXNhYmxlZCggZGlzYWJsZWQgKTtcblx0fSxcblxuXHRsb2FkOiBmdW5jdGlvbiggaW5kZXgsIGV2ZW50ICkge1xuXHRcdGluZGV4ID0gdGhpcy5fZ2V0SW5kZXgoIGluZGV4ICk7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0dGFiID0gdGhpcy50YWJzLmVxKCBpbmRleCApLFxuXHRcdFx0YW5jaG9yID0gdGFiLmZpbmQoIFwiLnVpLXRhYnMtYW5jaG9yXCIgKSxcblx0XHRcdHBhbmVsID0gdGhpcy5fZ2V0UGFuZWxGb3JUYWIoIHRhYiApLFxuXHRcdFx0ZXZlbnREYXRhID0ge1xuXHRcdFx0XHR0YWI6IHRhYixcblx0XHRcdFx0cGFuZWw6IHBhbmVsXG5cdFx0XHR9LFxuXHRcdFx0Y29tcGxldGUgPSBmdW5jdGlvbigganFYSFIsIHN0YXR1cyApIHtcblx0XHRcdFx0aWYgKCBzdGF0dXMgPT09IFwiYWJvcnRcIiApIHtcblx0XHRcdFx0XHR0aGF0LnBhbmVscy5zdG9wKCBmYWxzZSwgdHJ1ZSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHRhYiwgXCJ1aS10YWJzLWxvYWRpbmdcIiApO1xuXHRcdFx0XHRwYW5lbC5yZW1vdmVBdHRyKCBcImFyaWEtYnVzeVwiICk7XG5cblx0XHRcdFx0aWYgKCBqcVhIUiA9PT0gdGhhdC54aHIgKSB7XG5cdFx0XHRcdFx0ZGVsZXRlIHRoYXQueGhyO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXG5cdFx0Ly8gTm90IHJlbW90ZVxuXHRcdGlmICggdGhpcy5faXNMb2NhbCggYW5jaG9yWyAwIF0gKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLnhociA9ICQuYWpheCggdGhpcy5fYWpheFNldHRpbmdzKCBhbmNob3IsIGV2ZW50LCBldmVudERhdGEgKSApO1xuXG5cdFx0Ly8gU3VwcG9ydDogalF1ZXJ5IDwxLjhcblx0XHQvLyBqUXVlcnkgPDEuOCByZXR1cm5zIGZhbHNlIGlmIHRoZSByZXF1ZXN0IGlzIGNhbmNlbGVkIGluIGJlZm9yZVNlbmQsXG5cdFx0Ly8gYnV0IGFzIG9mIDEuOCwgJC5hamF4KCkgYWx3YXlzIHJldHVybnMgYSBqcVhIUiBvYmplY3QuXG5cdFx0aWYgKCB0aGlzLnhociAmJiB0aGlzLnhoci5zdGF0dXNUZXh0ICE9PSBcImNhbmNlbGVkXCIgKSB7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGFiLCBcInVpLXRhYnMtbG9hZGluZ1wiICk7XG5cdFx0XHRwYW5lbC5hdHRyKCBcImFyaWEtYnVzeVwiLCBcInRydWVcIiApO1xuXG5cdFx0XHR0aGlzLnhoclxuXHRcdFx0XHQuZG9uZSggZnVuY3Rpb24oIHJlc3BvbnNlLCBzdGF0dXMsIGpxWEhSICkge1xuXG5cdFx0XHRcdFx0Ly8gc3VwcG9ydDogalF1ZXJ5IDwxLjhcblx0XHRcdFx0XHQvLyBodHRwOi8vYnVncy5qcXVlcnkuY29tL3RpY2tldC8xMTc3OFxuXHRcdFx0XHRcdHNldFRpbWVvdXQoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0cGFuZWwuaHRtbCggcmVzcG9uc2UgKTtcblx0XHRcdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwibG9hZFwiLCBldmVudCwgZXZlbnREYXRhICk7XG5cblx0XHRcdFx0XHRcdGNvbXBsZXRlKCBqcVhIUiwgc3RhdHVzICk7XG5cdFx0XHRcdFx0fSwgMSApO1xuXHRcdFx0XHR9IClcblx0XHRcdFx0LmZhaWwoIGZ1bmN0aW9uKCBqcVhIUiwgc3RhdHVzICkge1xuXG5cdFx0XHRcdFx0Ly8gc3VwcG9ydDogalF1ZXJ5IDwxLjhcblx0XHRcdFx0XHQvLyBodHRwOi8vYnVncy5qcXVlcnkuY29tL3RpY2tldC8xMTc3OFxuXHRcdFx0XHRcdHNldFRpbWVvdXQoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0Y29tcGxldGUoIGpxWEhSLCBzdGF0dXMgKTtcblx0XHRcdFx0XHR9LCAxICk7XG5cdFx0XHRcdH0gKTtcblx0XHR9XG5cdH0sXG5cblx0X2FqYXhTZXR0aW5nczogZnVuY3Rpb24oIGFuY2hvciwgZXZlbnQsIGV2ZW50RGF0YSApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cdFx0cmV0dXJuIHtcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUUgPDExIG9ubHlcblx0XHRcdC8vIFN0cmlwIGFueSBoYXNoIHRoYXQgZXhpc3RzIHRvIHByZXZlbnQgZXJyb3JzIHdpdGggdGhlIEFqYXggcmVxdWVzdFxuXHRcdFx0dXJsOiBhbmNob3IuYXR0ciggXCJocmVmXCIgKS5yZXBsYWNlKCAvIy4qJC8sIFwiXCIgKSxcblx0XHRcdGJlZm9yZVNlbmQ6IGZ1bmN0aW9uKCBqcVhIUiwgc2V0dGluZ3MgKSB7XG5cdFx0XHRcdHJldHVybiB0aGF0Ll90cmlnZ2VyKCBcImJlZm9yZUxvYWRcIiwgZXZlbnQsXG5cdFx0XHRcdFx0JC5leHRlbmQoIHsganFYSFI6IGpxWEhSLCBhamF4U2V0dGluZ3M6IHNldHRpbmdzIH0sIGV2ZW50RGF0YSApICk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fSxcblxuXHRfZ2V0UGFuZWxGb3JUYWI6IGZ1bmN0aW9uKCB0YWIgKSB7XG5cdFx0dmFyIGlkID0gJCggdGFiICkuYXR0ciggXCJhcmlhLWNvbnRyb2xzXCIgKTtcblx0XHRyZXR1cm4gdGhpcy5lbGVtZW50LmZpbmQoIHRoaXMuX3Nhbml0aXplU2VsZWN0b3IoIFwiI1wiICsgaWQgKSApO1xuXHR9XG59ICk7XG5cbi8vIERFUFJFQ0FURURcbi8vIFRPRE86IFN3aXRjaCByZXR1cm4gYmFjayB0byB3aWRnZXQgZGVjbGFyYXRpb24gYXQgdG9wIG9mIGZpbGUgd2hlbiB0aGlzIGlzIHJlbW92ZWRcbmlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICkge1xuXG5cdC8vIEJhY2tjb21wYXQgZm9yIHVpLXRhYiBjbGFzcyAobm93IHVpLXRhYnMtdGFiKVxuXHQkLndpZGdldCggXCJ1aS50YWJzXCIsICQudWkudGFicywge1xuXHRcdF9wcm9jZXNzVGFiczogZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLl9zdXBlckFwcGx5KCBhcmd1bWVudHMgKTtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnRhYnMsIFwidWktdGFiXCIgKTtcblx0XHR9XG5cdH0gKTtcbn1cblxudmFyIHdpZGdldHNUYWJzID0gJC51aS50YWJzO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFRvb2x0aXAgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFRvb2x0aXBcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBTaG93cyBhZGRpdGlvbmFsIGluZm9ybWF0aW9uIGZvciBhbnkgZWxlbWVudCBvbiBob3ZlciBvciBmb2N1cy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS90b29sdGlwL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3Rvb2x0aXAvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS90b29sdGlwLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG4kLndpZGdldCggXCJ1aS50b29sdGlwXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0b3B0aW9uczoge1xuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktdG9vbHRpcFwiOiBcInVpLWNvcm5lci1hbGwgdWktd2lkZ2V0LXNoYWRvd1wiXG5cdFx0fSxcblx0XHRjb250ZW50OiBmdW5jdGlvbigpIHtcblxuXHRcdFx0Ly8gc3VwcG9ydDogSUU8OSwgT3BlcmEgaW4galF1ZXJ5IDwxLjdcblx0XHRcdC8vIC50ZXh0KCkgY2FuJ3QgYWNjZXB0IHVuZGVmaW5lZCwgc28gY29lcmNlIHRvIGEgc3RyaW5nXG5cdFx0XHR2YXIgdGl0bGUgPSAkKCB0aGlzICkuYXR0ciggXCJ0aXRsZVwiICkgfHwgXCJcIjtcblxuXHRcdFx0Ly8gRXNjYXBlIHRpdGxlLCBzaW5jZSB3ZSdyZSBnb2luZyBmcm9tIGFuIGF0dHJpYnV0ZSB0byByYXcgSFRNTFxuXHRcdFx0cmV0dXJuICQoIFwiPGE+XCIgKS50ZXh0KCB0aXRsZSApLmh0bWwoKTtcblx0XHR9LFxuXHRcdGhpZGU6IHRydWUsXG5cblx0XHQvLyBEaXNhYmxlZCBlbGVtZW50cyBoYXZlIGluY29uc2lzdGVudCBiZWhhdmlvciBhY3Jvc3MgYnJvd3NlcnMgKCM4NjYxKVxuXHRcdGl0ZW1zOiBcIlt0aXRsZV06bm90KFtkaXNhYmxlZF0pXCIsXG5cdFx0cG9zaXRpb246IHtcblx0XHRcdG15OiBcImxlZnQgdG9wKzE1XCIsXG5cdFx0XHRhdDogXCJsZWZ0IGJvdHRvbVwiLFxuXHRcdFx0Y29sbGlzaW9uOiBcImZsaXBmaXQgZmxpcFwiXG5cdFx0fSxcblx0XHRzaG93OiB0cnVlLFxuXHRcdHRyYWNrOiBmYWxzZSxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGNsb3NlOiBudWxsLFxuXHRcdG9wZW46IG51bGxcblx0fSxcblxuXHRfYWRkRGVzY3JpYmVkQnk6IGZ1bmN0aW9uKCBlbGVtLCBpZCApIHtcblx0XHR2YXIgZGVzY3JpYmVkYnkgPSAoIGVsZW0uYXR0ciggXCJhcmlhLWRlc2NyaWJlZGJ5XCIgKSB8fCBcIlwiICkuc3BsaXQoIC9cXHMrLyApO1xuXHRcdGRlc2NyaWJlZGJ5LnB1c2goIGlkICk7XG5cdFx0ZWxlbVxuXHRcdFx0LmRhdGEoIFwidWktdG9vbHRpcC1pZFwiLCBpZCApXG5cdFx0XHQuYXR0ciggXCJhcmlhLWRlc2NyaWJlZGJ5XCIsICQudHJpbSggZGVzY3JpYmVkYnkuam9pbiggXCIgXCIgKSApICk7XG5cdH0sXG5cblx0X3JlbW92ZURlc2NyaWJlZEJ5OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHR2YXIgaWQgPSBlbGVtLmRhdGEoIFwidWktdG9vbHRpcC1pZFwiICksXG5cdFx0XHRkZXNjcmliZWRieSA9ICggZWxlbS5hdHRyKCBcImFyaWEtZGVzY3JpYmVkYnlcIiApIHx8IFwiXCIgKS5zcGxpdCggL1xccysvICksXG5cdFx0XHRpbmRleCA9ICQuaW5BcnJheSggaWQsIGRlc2NyaWJlZGJ5ICk7XG5cblx0XHRpZiAoIGluZGV4ICE9PSAtMSApIHtcblx0XHRcdGRlc2NyaWJlZGJ5LnNwbGljZSggaW5kZXgsIDEgKTtcblx0XHR9XG5cblx0XHRlbGVtLnJlbW92ZURhdGEoIFwidWktdG9vbHRpcC1pZFwiICk7XG5cdFx0ZGVzY3JpYmVkYnkgPSAkLnRyaW0oIGRlc2NyaWJlZGJ5LmpvaW4oIFwiIFwiICkgKTtcblx0XHRpZiAoIGRlc2NyaWJlZGJ5ICkge1xuXHRcdFx0ZWxlbS5hdHRyKCBcImFyaWEtZGVzY3JpYmVkYnlcIiwgZGVzY3JpYmVkYnkgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZWxlbS5yZW1vdmVBdHRyKCBcImFyaWEtZGVzY3JpYmVkYnlcIiApO1xuXHRcdH1cblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9vbigge1xuXHRcdFx0bW91c2VvdmVyOiBcIm9wZW5cIixcblx0XHRcdGZvY3VzaW46IFwib3BlblwiXG5cdFx0fSApO1xuXG5cdFx0Ly8gSURzIG9mIGdlbmVyYXRlZCB0b29sdGlwcywgbmVlZGVkIGZvciBkZXN0cm95XG5cdFx0dGhpcy50b29sdGlwcyA9IHt9O1xuXG5cdFx0Ly8gSURzIG9mIHBhcmVudCB0b29sdGlwcyB3aGVyZSB3ZSByZW1vdmVkIHRoZSB0aXRsZSBhdHRyaWJ1dGVcblx0XHR0aGlzLnBhcmVudHMgPSB7fTtcblxuXHRcdC8vIEFwcGVuZCB0aGUgYXJpYS1saXZlIHJlZ2lvbiBzbyB0b29sdGlwcyBhbm5vdW5jZSBjb3JyZWN0bHlcblx0XHR0aGlzLmxpdmVSZWdpb24gPSAkKCBcIjxkaXY+XCIgKVxuXHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0cm9sZTogXCJsb2dcIixcblx0XHRcdFx0XCJhcmlhLWxpdmVcIjogXCJhc3NlcnRpdmVcIixcblx0XHRcdFx0XCJhcmlhLXJlbGV2YW50XCI6IFwiYWRkaXRpb25zXCJcblx0XHRcdH0gKVxuXHRcdFx0LmFwcGVuZFRvKCB0aGlzLmRvY3VtZW50WyAwIF0uYm9keSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmxpdmVSZWdpb24sIG51bGwsIFwidWktaGVscGVyLWhpZGRlbi1hY2Nlc3NpYmxlXCIgKTtcblxuXHRcdHRoaXMuZGlzYWJsZWRUaXRsZXMgPSAkKCBbXSApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJjb250ZW50XCIgKSB7XG5cdFx0XHQkLmVhY2goIHRoaXMudG9vbHRpcHMsIGZ1bmN0aW9uKCBpZCwgdG9vbHRpcERhdGEgKSB7XG5cdFx0XHRcdHRoYXQuX3VwZGF0ZUNvbnRlbnQoIHRvb2x0aXBEYXRhLmVsZW1lbnQgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbkRpc2FibGVkOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dGhpc1sgdmFsdWUgPyBcIl9kaXNhYmxlXCIgOiBcIl9lbmFibGVcIiBdKCk7XG5cdH0sXG5cblx0X2Rpc2FibGU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdC8vIENsb3NlIG9wZW4gdG9vbHRpcHNcblx0XHQkLmVhY2goIHRoaXMudG9vbHRpcHMsIGZ1bmN0aW9uKCBpZCwgdG9vbHRpcERhdGEgKSB7XG5cdFx0XHR2YXIgZXZlbnQgPSAkLkV2ZW50KCBcImJsdXJcIiApO1xuXHRcdFx0ZXZlbnQudGFyZ2V0ID0gZXZlbnQuY3VycmVudFRhcmdldCA9IHRvb2x0aXBEYXRhLmVsZW1lbnRbIDAgXTtcblx0XHRcdHRoYXQuY2xvc2UoIGV2ZW50LCB0cnVlICk7XG5cdFx0fSApO1xuXG5cdFx0Ly8gUmVtb3ZlIHRpdGxlIGF0dHJpYnV0ZXMgdG8gcHJldmVudCBuYXRpdmUgdG9vbHRpcHNcblx0XHR0aGlzLmRpc2FibGVkVGl0bGVzID0gdGhpcy5kaXNhYmxlZFRpdGxlcy5hZGQoXG5cdFx0XHR0aGlzLmVsZW1lbnQuZmluZCggdGhpcy5vcHRpb25zLml0ZW1zICkuYWRkQmFjaygpXG5cdFx0XHRcdC5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHZhciBlbGVtZW50ID0gJCggdGhpcyApO1xuXHRcdFx0XHRcdGlmICggZWxlbWVudC5pcyggXCJbdGl0bGVdXCIgKSApIHtcblx0XHRcdFx0XHRcdHJldHVybiBlbGVtZW50XG5cdFx0XHRcdFx0XHRcdC5kYXRhKCBcInVpLXRvb2x0aXAtdGl0bGVcIiwgZWxlbWVudC5hdHRyKCBcInRpdGxlXCIgKSApXG5cdFx0XHRcdFx0XHRcdC5yZW1vdmVBdHRyKCBcInRpdGxlXCIgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKVxuXHRcdCk7XG5cdH0sXG5cblx0X2VuYWJsZTogZnVuY3Rpb24oKSB7XG5cblx0XHQvLyByZXN0b3JlIHRpdGxlIGF0dHJpYnV0ZXNcblx0XHR0aGlzLmRpc2FibGVkVGl0bGVzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGVsZW1lbnQgPSAkKCB0aGlzICk7XG5cdFx0XHRpZiAoIGVsZW1lbnQuZGF0YSggXCJ1aS10b29sdGlwLXRpdGxlXCIgKSApIHtcblx0XHRcdFx0ZWxlbWVudC5hdHRyKCBcInRpdGxlXCIsIGVsZW1lbnQuZGF0YSggXCJ1aS10b29sdGlwLXRpdGxlXCIgKSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XHR0aGlzLmRpc2FibGVkVGl0bGVzID0gJCggW10gKTtcblx0fSxcblxuXHRvcGVuOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0dGFyZ2V0ID0gJCggZXZlbnQgPyBldmVudC50YXJnZXQgOiB0aGlzLmVsZW1lbnQgKVxuXG5cdFx0XHRcdC8vIHdlIG5lZWQgY2xvc2VzdCBoZXJlIGR1ZSB0byBtb3VzZW92ZXIgYnViYmxpbmcsXG5cdFx0XHRcdC8vIGJ1dCBhbHdheXMgcG9pbnRpbmcgYXQgdGhlIHNhbWUgZXZlbnQgdGFyZ2V0XG5cdFx0XHRcdC5jbG9zZXN0KCB0aGlzLm9wdGlvbnMuaXRlbXMgKTtcblxuXHRcdC8vIE5vIGVsZW1lbnQgdG8gc2hvdyBhIHRvb2x0aXAgZm9yIG9yIHRoZSB0b29sdGlwIGlzIGFscmVhZHkgb3BlblxuXHRcdGlmICggIXRhcmdldC5sZW5ndGggfHwgdGFyZ2V0LmRhdGEoIFwidWktdG9vbHRpcC1pZFwiICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCB0YXJnZXQuYXR0ciggXCJ0aXRsZVwiICkgKSB7XG5cdFx0XHR0YXJnZXQuZGF0YSggXCJ1aS10b29sdGlwLXRpdGxlXCIsIHRhcmdldC5hdHRyKCBcInRpdGxlXCIgKSApO1xuXHRcdH1cblxuXHRcdHRhcmdldC5kYXRhKCBcInVpLXRvb2x0aXAtb3BlblwiLCB0cnVlICk7XG5cblx0XHQvLyBLaWxsIHBhcmVudCB0b29sdGlwcywgY3VzdG9tIG9yIG5hdGl2ZSwgZm9yIGhvdmVyXG5cdFx0aWYgKCBldmVudCAmJiBldmVudC50eXBlID09PSBcIm1vdXNlb3ZlclwiICkge1xuXHRcdFx0dGFyZ2V0LnBhcmVudHMoKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIHBhcmVudCA9ICQoIHRoaXMgKSxcblx0XHRcdFx0XHRibHVyRXZlbnQ7XG5cdFx0XHRcdGlmICggcGFyZW50LmRhdGEoIFwidWktdG9vbHRpcC1vcGVuXCIgKSApIHtcblx0XHRcdFx0XHRibHVyRXZlbnQgPSAkLkV2ZW50KCBcImJsdXJcIiApO1xuXHRcdFx0XHRcdGJsdXJFdmVudC50YXJnZXQgPSBibHVyRXZlbnQuY3VycmVudFRhcmdldCA9IHRoaXM7XG5cdFx0XHRcdFx0dGhhdC5jbG9zZSggYmx1ckV2ZW50LCB0cnVlICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBwYXJlbnQuYXR0ciggXCJ0aXRsZVwiICkgKSB7XG5cdFx0XHRcdFx0cGFyZW50LnVuaXF1ZUlkKCk7XG5cdFx0XHRcdFx0dGhhdC5wYXJlbnRzWyB0aGlzLmlkIF0gPSB7XG5cdFx0XHRcdFx0XHRlbGVtZW50OiB0aGlzLFxuXHRcdFx0XHRcdFx0dGl0bGU6IHBhcmVudC5hdHRyKCBcInRpdGxlXCIgKVxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0cGFyZW50LmF0dHIoIFwidGl0bGVcIiwgXCJcIiApO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fcmVnaXN0ZXJDbG9zZUhhbmRsZXJzKCBldmVudCwgdGFyZ2V0ICk7XG5cdFx0dGhpcy5fdXBkYXRlQ29udGVudCggdGFyZ2V0LCBldmVudCApO1xuXHR9LFxuXG5cdF91cGRhdGVDb250ZW50OiBmdW5jdGlvbiggdGFyZ2V0LCBldmVudCApIHtcblx0XHR2YXIgY29udGVudCxcblx0XHRcdGNvbnRlbnRPcHRpb24gPSB0aGlzLm9wdGlvbnMuY29udGVudCxcblx0XHRcdHRoYXQgPSB0aGlzLFxuXHRcdFx0ZXZlbnRUeXBlID0gZXZlbnQgPyBldmVudC50eXBlIDogbnVsbDtcblxuXHRcdGlmICggdHlwZW9mIGNvbnRlbnRPcHRpb24gPT09IFwic3RyaW5nXCIgfHwgY29udGVudE9wdGlvbi5ub2RlVHlwZSB8fFxuXHRcdFx0XHRjb250ZW50T3B0aW9uLmpxdWVyeSApIHtcblx0XHRcdHJldHVybiB0aGlzLl9vcGVuKCBldmVudCwgdGFyZ2V0LCBjb250ZW50T3B0aW9uICk7XG5cdFx0fVxuXG5cdFx0Y29udGVudCA9IGNvbnRlbnRPcHRpb24uY2FsbCggdGFyZ2V0WyAwIF0sIGZ1bmN0aW9uKCByZXNwb25zZSApIHtcblxuXHRcdFx0Ly8gSUUgbWF5IGluc3RhbnRseSBzZXJ2ZSBhIGNhY2hlZCByZXNwb25zZSBmb3IgYWpheCByZXF1ZXN0c1xuXHRcdFx0Ly8gZGVsYXkgdGhpcyBjYWxsIHRvIF9vcGVuIHNvIHRoZSBvdGhlciBjYWxsIHRvIF9vcGVuIHJ1bnMgZmlyc3Rcblx0XHRcdHRoYXQuX2RlbGF5KCBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHQvLyBJZ25vcmUgYXN5bmMgcmVzcG9uc2UgaWYgdG9vbHRpcCB3YXMgY2xvc2VkIGFscmVhZHlcblx0XHRcdFx0aWYgKCAhdGFyZ2V0LmRhdGEoIFwidWktdG9vbHRpcC1vcGVuXCIgKSApIHtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBKUXVlcnkgY3JlYXRlcyBhIHNwZWNpYWwgZXZlbnQgZm9yIGZvY3VzaW4gd2hlbiBpdCBkb2Vzbid0XG5cdFx0XHRcdC8vIGV4aXN0IG5hdGl2ZWx5LiBUbyBpbXByb3ZlIHBlcmZvcm1hbmNlLCB0aGUgbmF0aXZlIGV2ZW50XG5cdFx0XHRcdC8vIG9iamVjdCBpcyByZXVzZWQgYW5kIHRoZSB0eXBlIGlzIGNoYW5nZWQuIFRoZXJlZm9yZSwgd2UgY2FuJ3Rcblx0XHRcdFx0Ly8gcmVseSBvbiB0aGUgdHlwZSBiZWluZyBjb3JyZWN0IGFmdGVyIHRoZSBldmVudCBmaW5pc2hlZFxuXHRcdFx0XHQvLyBidWJibGluZywgc28gd2Ugc2V0IGl0IGJhY2sgdG8gdGhlIHByZXZpb3VzIHZhbHVlLiAoIzg3NDApXG5cdFx0XHRcdGlmICggZXZlbnQgKSB7XG5cdFx0XHRcdFx0ZXZlbnQudHlwZSA9IGV2ZW50VHlwZTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGlzLl9vcGVuKCBldmVudCwgdGFyZ2V0LCByZXNwb25zZSApO1xuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0XHRpZiAoIGNvbnRlbnQgKSB7XG5cdFx0XHR0aGlzLl9vcGVuKCBldmVudCwgdGFyZ2V0LCBjb250ZW50ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9vcGVuOiBmdW5jdGlvbiggZXZlbnQsIHRhcmdldCwgY29udGVudCApIHtcblx0XHR2YXIgdG9vbHRpcERhdGEsIHRvb2x0aXAsIGRlbGF5ZWRTaG93LCBhMTF5Q29udGVudCxcblx0XHRcdHBvc2l0aW9uT3B0aW9uID0gJC5leHRlbmQoIHt9LCB0aGlzLm9wdGlvbnMucG9zaXRpb24gKTtcblxuXHRcdGlmICggIWNvbnRlbnQgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gQ29udGVudCBjYW4gYmUgdXBkYXRlZCBtdWx0aXBsZSB0aW1lcy4gSWYgdGhlIHRvb2x0aXAgYWxyZWFkeVxuXHRcdC8vIGV4aXN0cywgdGhlbiBqdXN0IHVwZGF0ZSB0aGUgY29udGVudCBhbmQgYmFpbC5cblx0XHR0b29sdGlwRGF0YSA9IHRoaXMuX2ZpbmQoIHRhcmdldCApO1xuXHRcdGlmICggdG9vbHRpcERhdGEgKSB7XG5cdFx0XHR0b29sdGlwRGF0YS50b29sdGlwLmZpbmQoIFwiLnVpLXRvb2x0aXAtY29udGVudFwiICkuaHRtbCggY29udGVudCApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIElmIHdlIGhhdmUgYSB0aXRsZSwgY2xlYXIgaXQgdG8gcHJldmVudCB0aGUgbmF0aXZlIHRvb2x0aXBcblx0XHQvLyB3ZSBoYXZlIHRvIGNoZWNrIGZpcnN0IHRvIGF2b2lkIGRlZmluaW5nIGEgdGl0bGUgaWYgbm9uZSBleGlzdHNcblx0XHQvLyAod2UgZG9uJ3Qgd2FudCB0byBjYXVzZSBhbiBlbGVtZW50IHRvIHN0YXJ0IG1hdGNoaW5nIFt0aXRsZV0pXG5cdFx0Ly9cblx0XHQvLyBXZSB1c2UgcmVtb3ZlQXR0ciBvbmx5IGZvciBrZXkgZXZlbnRzLCB0byBhbGxvdyBJRSB0byBleHBvcnQgdGhlIGNvcnJlY3Rcblx0XHQvLyBhY2Nlc3NpYmxlIGF0dHJpYnV0ZXMuIEZvciBtb3VzZSBldmVudHMsIHNldCB0byBlbXB0eSBzdHJpbmcgdG8gYXZvaWRcblx0XHQvLyBuYXRpdmUgdG9vbHRpcCBzaG93aW5nIHVwIChoYXBwZW5zIG9ubHkgd2hlbiByZW1vdmluZyBpbnNpZGUgbW91c2VvdmVyKS5cblx0XHRpZiAoIHRhcmdldC5pcyggXCJbdGl0bGVdXCIgKSApIHtcblx0XHRcdGlmICggZXZlbnQgJiYgZXZlbnQudHlwZSA9PT0gXCJtb3VzZW92ZXJcIiApIHtcblx0XHRcdFx0dGFyZ2V0LmF0dHIoIFwidGl0bGVcIiwgXCJcIiApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGFyZ2V0LnJlbW92ZUF0dHIoIFwidGl0bGVcIiApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRvb2x0aXBEYXRhID0gdGhpcy5fdG9vbHRpcCggdGFyZ2V0ICk7XG5cdFx0dG9vbHRpcCA9IHRvb2x0aXBEYXRhLnRvb2x0aXA7XG5cdFx0dGhpcy5fYWRkRGVzY3JpYmVkQnkoIHRhcmdldCwgdG9vbHRpcC5hdHRyKCBcImlkXCIgKSApO1xuXHRcdHRvb2x0aXAuZmluZCggXCIudWktdG9vbHRpcC1jb250ZW50XCIgKS5odG1sKCBjb250ZW50ICk7XG5cblx0XHQvLyBTdXBwb3J0OiBWb2ljZW92ZXIgb24gT1MgWCwgSkFXUyBvbiBJRSA8PSA5XG5cdFx0Ly8gSkFXUyBhbm5vdW5jZXMgZGVsZXRpb25zIGV2ZW4gd2hlbiBhcmlhLXJlbGV2YW50PVwiYWRkaXRpb25zXCJcblx0XHQvLyBWb2ljZW92ZXIgd2lsbCBzb21ldGltZXMgcmUtcmVhZCB0aGUgZW50aXJlIGxvZyByZWdpb24ncyBjb250ZW50cyBmcm9tIHRoZSBiZWdpbm5pbmdcblx0XHR0aGlzLmxpdmVSZWdpb24uY2hpbGRyZW4oKS5oaWRlKCk7XG5cdFx0YTExeUNvbnRlbnQgPSAkKCBcIjxkaXY+XCIgKS5odG1sKCB0b29sdGlwLmZpbmQoIFwiLnVpLXRvb2x0aXAtY29udGVudFwiICkuaHRtbCgpICk7XG5cdFx0YTExeUNvbnRlbnQucmVtb3ZlQXR0ciggXCJuYW1lXCIgKS5maW5kKCBcIltuYW1lXVwiICkucmVtb3ZlQXR0ciggXCJuYW1lXCIgKTtcblx0XHRhMTF5Q29udGVudC5yZW1vdmVBdHRyKCBcImlkXCIgKS5maW5kKCBcIltpZF1cIiApLnJlbW92ZUF0dHIoIFwiaWRcIiApO1xuXHRcdGExMXlDb250ZW50LmFwcGVuZFRvKCB0aGlzLmxpdmVSZWdpb24gKTtcblxuXHRcdGZ1bmN0aW9uIHBvc2l0aW9uKCBldmVudCApIHtcblx0XHRcdHBvc2l0aW9uT3B0aW9uLm9mID0gZXZlbnQ7XG5cdFx0XHRpZiAoIHRvb2x0aXAuaXMoIFwiOmhpZGRlblwiICkgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHRcdHRvb2x0aXAucG9zaXRpb24oIHBvc2l0aW9uT3B0aW9uICk7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5vcHRpb25zLnRyYWNrICYmIGV2ZW50ICYmIC9ebW91c2UvLnRlc3QoIGV2ZW50LnR5cGUgKSApIHtcblx0XHRcdHRoaXMuX29uKCB0aGlzLmRvY3VtZW50LCB7XG5cdFx0XHRcdG1vdXNlbW92ZTogcG9zaXRpb25cblx0XHRcdH0gKTtcblxuXHRcdFx0Ly8gdHJpZ2dlciBvbmNlIHRvIG92ZXJyaWRlIGVsZW1lbnQtcmVsYXRpdmUgcG9zaXRpb25pbmdcblx0XHRcdHBvc2l0aW9uKCBldmVudCApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0b29sdGlwLnBvc2l0aW9uKCAkLmV4dGVuZCgge1xuXHRcdFx0XHRvZjogdGFyZ2V0XG5cdFx0XHR9LCB0aGlzLm9wdGlvbnMucG9zaXRpb24gKSApO1xuXHRcdH1cblxuXHRcdHRvb2x0aXAuaGlkZSgpO1xuXG5cdFx0dGhpcy5fc2hvdyggdG9vbHRpcCwgdGhpcy5vcHRpb25zLnNob3cgKTtcblxuXHRcdC8vIEhhbmRsZSB0cmFja2luZyB0b29sdGlwcyB0aGF0IGFyZSBzaG93biB3aXRoIGEgZGVsYXkgKCM4NjQ0KS4gQXMgc29vblxuXHRcdC8vIGFzIHRoZSB0b29sdGlwIGlzIHZpc2libGUsIHBvc2l0aW9uIHRoZSB0b29sdGlwIHVzaW5nIHRoZSBtb3N0IHJlY2VudFxuXHRcdC8vIGV2ZW50LlxuXHRcdC8vIEFkZHMgdGhlIGNoZWNrIHRvIGFkZCB0aGUgdGltZXJzIG9ubHkgd2hlbiBib3RoIGRlbGF5IGFuZCB0cmFjayBvcHRpb25zIGFyZSBzZXQgKCMxNDY4Milcblx0XHRpZiAoIHRoaXMub3B0aW9ucy50cmFjayAmJiB0aGlzLm9wdGlvbnMuc2hvdyAmJiB0aGlzLm9wdGlvbnMuc2hvdy5kZWxheSApIHtcblx0XHRcdGRlbGF5ZWRTaG93ID0gdGhpcy5kZWxheWVkU2hvdyA9IHNldEludGVydmFsKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCB0b29sdGlwLmlzKCBcIjp2aXNpYmxlXCIgKSApIHtcblx0XHRcdFx0XHRwb3NpdGlvbiggcG9zaXRpb25PcHRpb24ub2YgKTtcblx0XHRcdFx0XHRjbGVhckludGVydmFsKCBkZWxheWVkU2hvdyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9LCAkLmZ4LmludGVydmFsICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJvcGVuXCIsIGV2ZW50LCB7IHRvb2x0aXA6IHRvb2x0aXAgfSApO1xuXHR9LFxuXG5cdF9yZWdpc3RlckNsb3NlSGFuZGxlcnM6IGZ1bmN0aW9uKCBldmVudCwgdGFyZ2V0ICkge1xuXHRcdHZhciBldmVudHMgPSB7XG5cdFx0XHRrZXl1cDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoIGV2ZW50LmtleUNvZGUgPT09ICQudWkua2V5Q29kZS5FU0NBUEUgKSB7XG5cdFx0XHRcdFx0dmFyIGZha2VFdmVudCA9ICQuRXZlbnQoIGV2ZW50ICk7XG5cdFx0XHRcdFx0ZmFrZUV2ZW50LmN1cnJlbnRUYXJnZXQgPSB0YXJnZXRbIDAgXTtcblx0XHRcdFx0XHR0aGlzLmNsb3NlKCBmYWtlRXZlbnQsIHRydWUgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cblx0XHQvLyBPbmx5IGJpbmQgcmVtb3ZlIGhhbmRsZXIgZm9yIGRlbGVnYXRlZCB0YXJnZXRzLiBOb24tZGVsZWdhdGVkXG5cdFx0Ly8gdG9vbHRpcHMgd2lsbCBoYW5kbGUgdGhpcyBpbiBkZXN0cm95LlxuXHRcdGlmICggdGFyZ2V0WyAwIF0gIT09IHRoaXMuZWxlbWVudFsgMCBdICkge1xuXHRcdFx0ZXZlbnRzLnJlbW92ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVUb29sdGlwKCB0aGlzLl9maW5kKCB0YXJnZXQgKS50b29sdGlwICk7XG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdGlmICggIWV2ZW50IHx8IGV2ZW50LnR5cGUgPT09IFwibW91c2VvdmVyXCIgKSB7XG5cdFx0XHRldmVudHMubW91c2VsZWF2ZSA9IFwiY2xvc2VcIjtcblx0XHR9XG5cdFx0aWYgKCAhZXZlbnQgfHwgZXZlbnQudHlwZSA9PT0gXCJmb2N1c2luXCIgKSB7XG5cdFx0XHRldmVudHMuZm9jdXNvdXQgPSBcImNsb3NlXCI7XG5cdFx0fVxuXHRcdHRoaXMuX29uKCB0cnVlLCB0YXJnZXQsIGV2ZW50cyApO1xuXHR9LFxuXG5cdGNsb3NlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHRvb2x0aXAsXG5cdFx0XHR0aGF0ID0gdGhpcyxcblx0XHRcdHRhcmdldCA9ICQoIGV2ZW50ID8gZXZlbnQuY3VycmVudFRhcmdldCA6IHRoaXMuZWxlbWVudCApLFxuXHRcdFx0dG9vbHRpcERhdGEgPSB0aGlzLl9maW5kKCB0YXJnZXQgKTtcblxuXHRcdC8vIFRoZSB0b29sdGlwIG1heSBhbHJlYWR5IGJlIGNsb3NlZFxuXHRcdGlmICggIXRvb2x0aXBEYXRhICkge1xuXG5cdFx0XHQvLyBXZSBzZXQgdWktdG9vbHRpcC1vcGVuIGltbWVkaWF0ZWx5IHVwb24gb3BlbiAoaW4gb3BlbigpKSwgYnV0IG9ubHkgc2V0IHRoZVxuXHRcdFx0Ly8gYWRkaXRpb25hbCBkYXRhIG9uY2UgdGhlcmUncyBhY3R1YWxseSBjb250ZW50IHRvIHNob3cgKGluIF9vcGVuKCkpLiBTbyBldmVuIGlmIHRoZVxuXHRcdFx0Ly8gdG9vbHRpcCBkb2Vzbid0IGhhdmUgZnVsbCBkYXRhLCB3ZSBhbHdheXMgcmVtb3ZlIHVpLXRvb2x0aXAtb3BlbiBpbiBjYXNlIHdlJ3JlIGluXG5cdFx0XHQvLyB0aGUgcGVyaW9kIGJldHdlZW4gb3BlbigpIGFuZCBfb3BlbigpLlxuXHRcdFx0dGFyZ2V0LnJlbW92ZURhdGEoIFwidWktdG9vbHRpcC1vcGVuXCIgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0b29sdGlwID0gdG9vbHRpcERhdGEudG9vbHRpcDtcblxuXHRcdC8vIERpc2FibGluZyBjbG9zZXMgdGhlIHRvb2x0aXAsIHNvIHdlIG5lZWQgdG8gdHJhY2sgd2hlbiB3ZSdyZSBjbG9zaW5nXG5cdFx0Ly8gdG8gYXZvaWQgYW4gaW5maW5pdGUgbG9vcCBpbiBjYXNlIHRoZSB0b29sdGlwIGJlY29tZXMgZGlzYWJsZWQgb24gY2xvc2Vcblx0XHRpZiAoIHRvb2x0aXBEYXRhLmNsb3NpbmcgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gQ2xlYXIgdGhlIGludGVydmFsIGZvciBkZWxheWVkIHRyYWNraW5nIHRvb2x0aXBzXG5cdFx0Y2xlYXJJbnRlcnZhbCggdGhpcy5kZWxheWVkU2hvdyApO1xuXG5cdFx0Ly8gT25seSBzZXQgdGl0bGUgaWYgd2UgaGFkIG9uZSBiZWZvcmUgKHNlZSBjb21tZW50IGluIF9vcGVuKCkpXG5cdFx0Ly8gSWYgdGhlIHRpdGxlIGF0dHJpYnV0ZSBoYXMgY2hhbmdlZCBzaW5jZSBvcGVuKCksIGRvbid0IHJlc3RvcmVcblx0XHRpZiAoIHRhcmdldC5kYXRhKCBcInVpLXRvb2x0aXAtdGl0bGVcIiApICYmICF0YXJnZXQuYXR0ciggXCJ0aXRsZVwiICkgKSB7XG5cdFx0XHR0YXJnZXQuYXR0ciggXCJ0aXRsZVwiLCB0YXJnZXQuZGF0YSggXCJ1aS10b29sdGlwLXRpdGxlXCIgKSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3JlbW92ZURlc2NyaWJlZEJ5KCB0YXJnZXQgKTtcblxuXHRcdHRvb2x0aXBEYXRhLmhpZGluZyA9IHRydWU7XG5cdFx0dG9vbHRpcC5zdG9wKCB0cnVlICk7XG5cdFx0dGhpcy5faGlkZSggdG9vbHRpcCwgdGhpcy5vcHRpb25zLmhpZGUsIGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhhdC5fcmVtb3ZlVG9vbHRpcCggJCggdGhpcyApICk7XG5cdFx0fSApO1xuXG5cdFx0dGFyZ2V0LnJlbW92ZURhdGEoIFwidWktdG9vbHRpcC1vcGVuXCIgKTtcblx0XHR0aGlzLl9vZmYoIHRhcmdldCwgXCJtb3VzZWxlYXZlIGZvY3Vzb3V0IGtleXVwXCIgKTtcblxuXHRcdC8vIFJlbW92ZSAncmVtb3ZlJyBiaW5kaW5nIG9ubHkgb24gZGVsZWdhdGVkIHRhcmdldHNcblx0XHRpZiAoIHRhcmdldFsgMCBdICE9PSB0aGlzLmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdHRoaXMuX29mZiggdGFyZ2V0LCBcInJlbW92ZVwiICk7XG5cdFx0fVxuXHRcdHRoaXMuX29mZiggdGhpcy5kb2N1bWVudCwgXCJtb3VzZW1vdmVcIiApO1xuXG5cdFx0aWYgKCBldmVudCAmJiBldmVudC50eXBlID09PSBcIm1vdXNlbGVhdmVcIiApIHtcblx0XHRcdCQuZWFjaCggdGhpcy5wYXJlbnRzLCBmdW5jdGlvbiggaWQsIHBhcmVudCApIHtcblx0XHRcdFx0JCggcGFyZW50LmVsZW1lbnQgKS5hdHRyKCBcInRpdGxlXCIsIHBhcmVudC50aXRsZSApO1xuXHRcdFx0XHRkZWxldGUgdGhhdC5wYXJlbnRzWyBpZCBdO1xuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdHRvb2x0aXBEYXRhLmNsb3NpbmcgPSB0cnVlO1xuXHRcdHRoaXMuX3RyaWdnZXIoIFwiY2xvc2VcIiwgZXZlbnQsIHsgdG9vbHRpcDogdG9vbHRpcCB9ICk7XG5cdFx0aWYgKCAhdG9vbHRpcERhdGEuaGlkaW5nICkge1xuXHRcdFx0dG9vbHRpcERhdGEuY2xvc2luZyA9IGZhbHNlO1xuXHRcdH1cblx0fSxcblxuXHRfdG9vbHRpcDogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0dmFyIHRvb2x0aXAgPSAkKCBcIjxkaXY+XCIgKS5hdHRyKCBcInJvbGVcIiwgXCJ0b29sdGlwXCIgKSxcblx0XHRcdGNvbnRlbnQgPSAkKCBcIjxkaXY+XCIgKS5hcHBlbmRUbyggdG9vbHRpcCApLFxuXHRcdFx0aWQgPSB0b29sdGlwLnVuaXF1ZUlkKCkuYXR0ciggXCJpZFwiICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggY29udGVudCwgXCJ1aS10b29sdGlwLWNvbnRlbnRcIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0b29sdGlwLCBcInVpLXRvb2x0aXBcIiwgXCJ1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXG5cdFx0dG9vbHRpcC5hcHBlbmRUbyggdGhpcy5fYXBwZW5kVG8oIGVsZW1lbnQgKSApO1xuXG5cdFx0cmV0dXJuIHRoaXMudG9vbHRpcHNbIGlkIF0gPSB7XG5cdFx0XHRlbGVtZW50OiBlbGVtZW50LFxuXHRcdFx0dG9vbHRpcDogdG9vbHRpcFxuXHRcdH07XG5cdH0sXG5cblx0X2ZpbmQ6IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cdFx0dmFyIGlkID0gdGFyZ2V0LmRhdGEoIFwidWktdG9vbHRpcC1pZFwiICk7XG5cdFx0cmV0dXJuIGlkID8gdGhpcy50b29sdGlwc1sgaWQgXSA6IG51bGw7XG5cdH0sXG5cblx0X3JlbW92ZVRvb2x0aXA6IGZ1bmN0aW9uKCB0b29sdGlwICkge1xuXHRcdHRvb2x0aXAucmVtb3ZlKCk7XG5cdFx0ZGVsZXRlIHRoaXMudG9vbHRpcHNbIHRvb2x0aXAuYXR0ciggXCJpZFwiICkgXTtcblx0fSxcblxuXHRfYXBwZW5kVG86IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cdFx0dmFyIGVsZW1lbnQgPSB0YXJnZXQuY2xvc2VzdCggXCIudWktZnJvbnQsIGRpYWxvZ1wiICk7XG5cblx0XHRpZiAoICFlbGVtZW50Lmxlbmd0aCApIHtcblx0XHRcdGVsZW1lbnQgPSB0aGlzLmRvY3VtZW50WyAwIF0uYm9keTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZWxlbWVudDtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0Ly8gQ2xvc2Ugb3BlbiB0b29sdGlwc1xuXHRcdCQuZWFjaCggdGhpcy50b29sdGlwcywgZnVuY3Rpb24oIGlkLCB0b29sdGlwRGF0YSApIHtcblxuXHRcdFx0Ly8gRGVsZWdhdGUgdG8gY2xvc2UgbWV0aG9kIHRvIGhhbmRsZSBjb21tb24gY2xlYW51cFxuXHRcdFx0dmFyIGV2ZW50ID0gJC5FdmVudCggXCJibHVyXCIgKSxcblx0XHRcdFx0ZWxlbWVudCA9IHRvb2x0aXBEYXRhLmVsZW1lbnQ7XG5cdFx0XHRldmVudC50YXJnZXQgPSBldmVudC5jdXJyZW50VGFyZ2V0ID0gZWxlbWVudFsgMCBdO1xuXHRcdFx0dGhhdC5jbG9zZSggZXZlbnQsIHRydWUgKTtcblxuXHRcdFx0Ly8gUmVtb3ZlIGltbWVkaWF0ZWx5OyBkZXN0cm95aW5nIGFuIG9wZW4gdG9vbHRpcCBkb2Vzbid0IHVzZSB0aGVcblx0XHRcdC8vIGhpZGUgYW5pbWF0aW9uXG5cdFx0XHQkKCBcIiNcIiArIGlkICkucmVtb3ZlKCk7XG5cblx0XHRcdC8vIFJlc3RvcmUgdGhlIHRpdGxlXG5cdFx0XHRpZiAoIGVsZW1lbnQuZGF0YSggXCJ1aS10b29sdGlwLXRpdGxlXCIgKSApIHtcblxuXHRcdFx0XHQvLyBJZiB0aGUgdGl0bGUgYXR0cmlidXRlIGhhcyBjaGFuZ2VkIHNpbmNlIG9wZW4oKSwgZG9uJ3QgcmVzdG9yZVxuXHRcdFx0XHRpZiAoICFlbGVtZW50LmF0dHIoIFwidGl0bGVcIiApICkge1xuXHRcdFx0XHRcdGVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiLCBlbGVtZW50LmRhdGEoIFwidWktdG9vbHRpcC10aXRsZVwiICkgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRlbGVtZW50LnJlbW92ZURhdGEoIFwidWktdG9vbHRpcC10aXRsZVwiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdHRoaXMubGl2ZVJlZ2lvbi5yZW1vdmUoKTtcblx0fVxufSApO1xuXG4vLyBERVBSRUNBVEVEXG4vLyBUT0RPOiBTd2l0Y2ggcmV0dXJuIGJhY2sgdG8gd2lkZ2V0IGRlY2xhcmF0aW9uIGF0IHRvcCBvZiBmaWxlIHdoZW4gdGhpcyBpcyByZW1vdmVkXG5pZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSApIHtcblxuXHQvLyBCYWNrY29tcGF0IGZvciB0b29sdGlwQ2xhc3Mgb3B0aW9uXG5cdCQud2lkZ2V0KCBcInVpLnRvb2x0aXBcIiwgJC51aS50b29sdGlwLCB7XG5cdFx0b3B0aW9uczoge1xuXHRcdFx0dG9vbHRpcENsYXNzOiBudWxsXG5cdFx0fSxcblx0XHRfdG9vbHRpcDogZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgdG9vbHRpcERhdGEgPSB0aGlzLl9zdXBlckFwcGx5KCBhcmd1bWVudHMgKTtcblx0XHRcdGlmICggdGhpcy5vcHRpb25zLnRvb2x0aXBDbGFzcyApIHtcblx0XHRcdFx0dG9vbHRpcERhdGEudG9vbHRpcC5hZGRDbGFzcyggdGhpcy5vcHRpb25zLnRvb2x0aXBDbGFzcyApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRvb2x0aXBEYXRhO1xuXHRcdH1cblx0fSApO1xufVxuXG52YXIgd2lkZ2V0c1Rvb2x0aXAgPSAkLnVpLnRvb2x0aXA7XG5cblxuXG5cbn0pKTsiXSwic291cmNlUm9vdCI6IiJ9