1// ======================= imagesLoaded Plugin =============================== 2// https://github.com/desandro/imagesloaded 3 4// $('#my-container').imagesLoaded(myFunction) 5// execute a callback when all images have loaded. 6// needed because .load() doesn't work on cached images 7 8// callback function gets image collection as argument 9// this is the container 10 11// original: MIT license. Paul Irish. 2010. 12// contributors: Oren Solomianik, David DeSandro, Yiannis Chatzikonstantinou 13 14// blank image data-uri bypasses webkit log warning (thx doug jones) 15var BLANK = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw=='; 16 17$.fn.imagesLoaded = function( callback ) { 18 var $this = this, 19 deferred = $.isFunction($.Deferred) ? $.Deferred() : 0, 20 hasNotify = $.isFunction(deferred.notify), 21 $images = $this.find('img').add( $this.filter('img') ), 22 loaded = [], 23 proper = [], 24 broken = []; 25 26 // Register deferred callbacks 27 if ($.isPlainObject(callback)) { 28 $.each(callback, function (key, value) { 29 if (key === 'callback') { 30 callback = value; 31 } else if (deferred) { 32 deferred[key](value); 33 } 34 }); 35 } 36 37 function doneLoading() { 38 var $proper = $(proper), 39 $broken = $(broken); 40 41 if ( deferred ) { 42 if ( broken.length ) { 43 deferred.reject( $images, $proper, $broken ); 44 } else { 45 deferred.resolve( $images ); 46 } 47 } 48 49 if ( $.isFunction( callback ) ) { 50 callback.call( $this, $images, $proper, $broken ); 51 } 52 } 53 54 function imgLoaded( img, isBroken ) { 55 // don't proceed if BLANK image, or image is already loaded 56 if ( img.src === BLANK || $.inArray( img, loaded ) !== -1 ) { 57 return; 58 } 59 60 // store element in loaded images array 61 loaded.push( img ); 62 63 // keep track of broken and properly loaded images 64 if ( isBroken ) { 65 broken.push( img ); 66 } else { 67 proper.push( img ); 68 } 69 70 // cache image and its state for future calls 71 $.data( img, 'imagesLoaded', { isBroken: isBroken, src: img.src } ); 72 73 // trigger deferred progress method if present 74 if ( hasNotify ) { 75 deferred.notifyWith( $(img), [ isBroken, $images, $(proper), $(broken) ] ); 76 } 77 78 // call doneLoading and clean listeners if all images are loaded 79 if ( $images.length === loaded.length ){ 80 setTimeout( doneLoading ); 81 $images.unbind( '.imagesLoaded' ); 82 } 83 } 84 85 // if no images, trigger immediately 86 if ( !$images.length ) { 87 doneLoading(); 88 } else { 89 $images.bind( 'load.imagesLoaded error.imagesLoaded', function( event ){ 90 // trigger imgLoaded 91 imgLoaded( event.target, event.type === 'error' ); 92 }).each( function( i, el ) { 93 var src = el.src; 94 95 // find out if this image has been already checked for status 96 // if it was, and src has not changed, call imgLoaded on it 97 var cached = $.data( el, 'imagesLoaded' ); 98 if ( cached && cached.src === src ) { 99 imgLoaded( el, cached.isBroken ); 100 return; 101 } 102 103 // if complete is true and browser supports natural sizes, try 104 // to check for image status manually 105 if ( el.complete && el.naturalWidth !== undefined ) { 106 imgLoaded( el, el.naturalWidth === 0 || el.naturalHeight === 0 ); 107 return; 108 } 109 110 // cached images don't fire load sometimes, so we reset src, but only when 111 // dealing with IE, or image is complete (loaded) and failed manual check 112 // webkit hack from http://groups.google.com/group/jquery-dev/browse_thread/thread/eee6ab7b2da50e1f 113 if ( el.readyState || el.complete ) { 114 el.src = BLANK; 115 el.src = src; 116 } 117 }); 118 } 119 120 return deferred ? deferred.promise( $this ) : $this; 121}; 122/*jshint browser:true */ 123/*! 124* FitVids 1.1 125* 126* Copyright 2013, Chris Coyier - http://css-tricks.com + Dave Rupert - http://daverupert.com 127* Credit to Thierry Koblentz - http://www.alistapart.com/articles/creating-intrinsic-ratios-for-video/ 128* Released under the WTFPL license - http://sam.zoy.org/wtfpl/ 129* 130*/ 131 132;(function( $ ){ 133 134 'use strict'; 135 136 $.fn.fitVids = function( options ) { 137 var settings = { 138 customSelector: null, 139 ignore: null 140 }; 141 142 if(!document.getElementById('fit-vids-style')) { 143 // appendStyles: https://github.com/toddmotto/fluidvids/blob/master/dist/fluidvids.js 144 var head = document.head || document.getElementsByTagName('head')[0]; 145 var css = '.fluid-width-video-wrapper{width:100%;position:relative;padding:0;}.fluid-width-video-wrapper iframe,.fluid-width-video-wrapper object,.fluid-width-video-wrapper embed {position:absolute;top:0;left:0;width:100%;height:100%;}'; 146 var div = document.createElement("div"); 147 div.innerHTML = '<p>
147x</p><style id="fit-vids-style">' + css + '</style>'; 148 head.appendChild(div.childNodes[1]); 149 } 150 151 if ( options ) { 152 $.extend( settings, options ); 153 } 154 155 return this.each(function(){ 156 var selectors = [ 157 'iframe[src*="player.vimeo.com"]', 158 'iframe[src*="youtube.com"]', 159 'iframe[src*="youtube-nocookie.com"]', 160 'iframe[src*="kickstarter.com"][src*="video.html"]', 161 'object', 162 'embed' 163 ]; 164 165 if (settings.customSelector) { 166 selectors.push(settings.customSelector); 167 } 168 169 var ignoreList = '.fitvidsignore'; 170 171 if(settings.ignore) { 172 ignoreList = ignoreList + ', ' + settings.ignore; 173 } 174 175 var $allVideos = $(this).find(selectors.join(',')); 176 $allVideos = $allVideos.not('object object'); // SwfObj conflict patch 177 $allVideos = $allVideos.not(ignoreList); // Disable FitVids on this video. 178 179 $allVideos.each(function(){ 180 var $this = $(this); 181 if($this.parents(ignoreList).length > 0) { 182 return; // Disable FitVids on this video. 183 } 184 if (this.tagName.toLowerCase() === 'embed' && $this.parent('object').length || $this.parent('.fluid-width-video-wrapper').length) { return; } 185 if ((!$this.css('height') && !$this.css('width')) && (isNaN($this.attr('height')) || isNaN($this.attr('width')))) 186 { 187 $this.attr('height', 9); 188 $this.attr('width', 16); 189 } 190 var height = ( this.tagName.toLowerCase() === 'object' || ($this.attr('height') && !isNaN(parseInt($this.attr('height'), 10))) ) ? parseInt($this.attr('height'), 10) : $this.height(), 191 width = !isNaN(parseInt($this.attr('width'), 10)) ? parseInt($this.attr('width'), 10) : $this.width(), 192 aspectRatio = height / width; 193 if(!$this.attr('name')){ 194 var videoName = 'fitvid' + $.fn.fitVids._count; 195 $this.attr('name', videoName); 196 $.fn.fitVids._count++; 197 } 198 $this.wrap('<div class="fluid-width-video-wrapper"></div>').parent('.fluid-width-video-wrapper').css('padding-top', (aspectRatio * 100)+'%'); 199 $this.removeAttr('height').removeAttr('width'); 200 }); 201 }); 202 }; 203 204 // Internal counter for unique video names. 205 $.fn.fitVids._count = 0; 206 207// Works with either jQuery or Zepto 208})( window.jQuery || window.Zepto ); 209 210/*! 211 * jQuery Lazy - v1.6.5 212 * http://jquery.eisbehr.de/lazy/ 213 * 214 * Copyright 2012 - 2016, Daniel 'Eisbehr' Kern 215 * 216 * Dual licensed under the MIT and GPL-2.0 licenses: 217 * http://www.opensource.org/licenses/mit-license.php 218 * http://www.gnu.org/licenses/gpl-2.0.html 219 * 220 * $("img.lazy").lazy(); 221 */ 222 223;(function($, window, document, undefined) 224{ 225 "use strict"; 226 227 // make lazy a bit more case-insensitive :) 228 $.fn.Lazy = $.fn.lazy = function(settings) 229 { 230 return new LazyPlugin(this, settings); 231 }; 232 233 /** 234 * contains all logic and the whole element handling 235 * is packed in a private function outside class to reduce memory usage, because it will not be created on every plugin instance 236 * @access private 237 * @type {function} 238 * @param {LazyPlugin} instance 239 * @param {function} configuration 240 * @param {object} items 241 * @param {object} events 242 * @return void 243 */ 244 function _executeLazy(instance, configuration, items, events) 245 { 246 /** 247 * a helper to trigger the 'onFinishedAll' callback after all other events 248 * @access private 249 * @type {number} 250 */ 251 var _awaitingAfterLoad = 0, 252 253 /** 254 * visible content width 255 * @access private 256 * @type {number} 257 */ 258 _actualWidth = -1, 259 260 /** 261 * visible content height 262 * @access private 263 * @type {number} 264 */ 265 _actualHeight = -1, 266 267 /** 268 * determine possible detected high pixel density 269 * @access private 270 * @type {boolean} 271 */ 272 _isRetinaDisplay = false; 273 274 /** 275 * initialize plugin 276 * bind loading to events or set delay time to load all items at once 277 * @access private 278 * @return void 279 */ 280 function _initialize() 281 { 282 // detect actual device pixel ratio 283 // noinspection JSUnresolvedVariable 284 _isRetinaDisplay = window.devicePixelRatio > 1;
285 286 // prepare all initial items 287 _prepareItems(items); 288 289 // if delay time is set load all items at once after delay time 290 if( configuration("delay") >= 0 ) setTimeout(function() { _lazyLoadItems(true); }, configuration("delay")); 291 292 // if no delay is set or combine usage is active bind events 293 if( configuration("delay") < 0 || configuration("combined") ) 294 { 295 // create unique event function 296 events.e = _throttle(configuration("throttle"), function(event) 297 { 298 // reset detected window size on resize event 299 if( event.type === "resize" ) 300 _actualWidth = _actualHeight = -1; 301 302 // execute 'lazy magic' 303 _lazyLoadItems(event.all); 304 }); 305 306 // create function to add new items to instance 307 events.a = function(additionalItems) 308 { 309 _prepareItems(additionalItems); 310 items.push.apply(items, additionalItems); 311 }; 312 313 // create function to get all instance items left 314 events.g = function() 315 { 316 return items; 317 }; 318 319 // load initial items 320 _lazyLoadItems(); 321 322 // bind lazy load functions to scroll and resize event 323 $(configuration("appendScroll")).on("scroll." + instance.name + " resize." + instance.name, events.e); 324 } 325 } 326 327 /** 328 * prepare items before handle them 329 * @access private 330 * @param {Array|object|jQuery} items 331 * @return void 332 */ 333 function _prepareItems(items) 334 { 335 // filter items and only add those who not handled yet and got needed attributes available 336 items = $(items).filter(function() 337 { 338 return !$(this).data(configuration("handledName")) && ($(this).attr(configuration("attribute")) || $(this).attr(configuration("loaderAttribute"))); 339 }) 340 341 // append plugin instance to all elements 342 .data("plugin_" + instance.name, instance); 343 344 // set default image and/or placeholder to elements if configured 345 if( configuration("defaultImage") || configuration("placeholder") ) 346 for( var i = 0; i < items.length; i++ ) 347 { 348 var element = $(items[i]), 349 tag = items[i].tagName.toLowerCase(), 350 propertyName = "background-image"; 351 352 // set default image on every element without source 353 if( tag == "img" && configuration("defaultImage") && !element.attr("src") ) 354 element.attr("src", configuration("defaultImage")); 355 356 // set placeholder on every element without background image 357 else if( tag != "img" && configuration("placeholder") && (!element.css(propertyName) || element.css(propertyName) == "none") ) 358 element.css(propertyName, "url(" + configuration("placeholder") + ")"); 359 } 360 } 361 362 /** 363 * the 'lazy magic' - check all items 364 * @access private 365 * @param {boolean} [allItems] 366 * @return void 367 */ 368 function _lazyLoadItems(allItems) 369 { 370 // skip if no items where left 371 if( !items.length ) 372 { 373 // destroy instance if option is enabled 374 if( configuration("autoDestroy") ) 375 // noinspection JSUnresolvedFunction 376 instance.destroy(); 377 378 return; 379 } 380 381 // helper to see if something was changed 382 var loadTriggered = false, 383 384 // get image base once, not on every image loop 385 imageBase = configuration("imageBase") ? configuration("imageBase") : ""; 386 387 // loop all available items 388 for( var i = 0; i < items.length; i++ ) 389 (function(item) 390 { 391 // item is at least in loadable area 392 if( _isInLoadableArea(item) || allItems ) 393 { 394 var element = $(item), 395 tag = item.tagName.toLowerCase(), 396 attribute = element.attr(configuration("attribute")), 397 customLoader; 398 399 // is not already handled 400 if( !element.data(configuration("handledName")) && 401 // and is visible or visibility doesn't matter 402 (!configuration("visibleOnly") || element.is(":visible")) && ( 403 // and image source attribute is available 404 attribute && ( 405 // and is image tag where attribute is not equal source 406 (tag == "img" && imageBase + attribute != element.attr("src")) || 407 // or is non image tag where attribute is not equal background 408 (tag != "img" && imageBase + attribute != element.css("background-image")) ) || 409 // or custom loader is available 410 (customLoader = element.attr(configuration("loaderAttribute"))) )) 411 {
412 // mark element always as handled as this point to prevent double loading 413 loadTriggered = true; 414 element.data(configuration("handledName"), true); 415 416 // load item 417 _handleItem(element, tag, imageBase, customLoader); 418 } 419 } 420 })(items[i]); 421 422 // when something was loaded remove them from remaining items 423 if( loadTriggered ) 424 items = $(items).filter(function() 425 { 426 return !$(this).data(configuration("handledName")); 427 }); 428 } 429 430 /** 431 * load the given element the lazy way 432 * @access private 433 * @param {object} element 434 * @param {string} tag 435 * @param {string} imageBase 436 * @param {function} [customLoader] 437 * @return void 438 */ 439 function _handleItem(element, tag, imageBase, customLoader) 440 { 441 // increment count of items waiting for after load 442 ++_awaitingAfterLoad; 443 444 // extended error callback for correct 'onFinishedAll' handling 445 var errorCallback = function() 446 { 447 _triggerCallback("onError", element); 448 _reduceAwaiting(); 449 }; 450 451 // trigger function before loading image 452 _triggerCallback("beforeLoad", element); 453 454 // handle custom loader 455 if( customLoader ) 456 { 457 // bind error event to trigger callback and reduce waiting amount 458 element.off("error").one("error", errorCallback); 459 460 // bind after load callback to image 461 element.one("load", function() 462 { 463 // remove attribute from element 464 if( configuration("removeAttribute") ) 465 element.removeAttr(configuration("loaderAttribute")); 466 467 // call after load event 468 _triggerCallback("afterLoad", element); 469 470 // remove item from waiting queue and possible trigger finished event 471 _reduceAwaiting(); 472 }); 473 474 // trigger custom loader 475 if( !_triggerCallback(customLoader, element, function(response) 476 { 477 if( response ) element.load(); 478 else element.error(); 479 })) element.error(); 480 } 481 482 // handle images 483 else 484 { 485 // create image object 486 var imageObj = $(new Image()); 487 488 // bind error event to trigger callback and reduce waiting amount 489 imageObj.one("error", errorCallback); 490 491 // bind after load callback to image 492 imageObj.one("load", function() 493 { 494 // remove element from view 495 element.hide(); 496 497 // set image back to element 498 if( tag == "img" ) element.attr("src", imageObj.attr("src")); 499 else element.css("background-image", "url(" + imageObj.attr("src") + ")"); 500 501 // bring it back with some effect! 502 element[configuration("effect")](configuration("effectTime")); 503 504 // remove attribute from element 505 if( configuration("removeAttribute") ) 506 element.removeAttr(configuration("attribute") + " " + configuration("retinaAttribute")); 507 508 // call after load event 509 _triggerCallback("afterLoad", element); 510 511 // cleanup image object 512 imageObj.remove(); 513 514 // remove item from waiting queue and possible trigger finished event 515 _reduceAwaiting(); 516 }); 517 518 // set source 519 imageObj.attr("src", imageBase + element.attr(configuration(_isRetinaDisplay && element.attr(configuration("retinaAttribute")) ? "retinaAttribute" : "attribute"))); 520 521 // call after load even on cached image 522 if( imageObj.complete ) imageObj.load(); 523 } 524 } 525 526 /** 527 * check if the given element is inside the current viewport or threshold 528 * @access private 529 * @param {object} element 530 * @return {boolean} 531 */ 532 function _isInLoadableArea(element) 533 { 534 var elementBound = element.getBoundingClientRect(), 535 direction = configuration("scrollDirection"), 536 threshold = configuration("threshold"), 537 vertical = // check if element is in loadable area from top 538 ((_getActualHeight() + threshold) > elementBound.top) && 539 // check if element is even in loadable are from bottom 540 (-threshold < elementBound.bottom), 541 horizontal = // check if element is in loadable area from left 542 ((_getActualWidth() + threshold) > elementBound.left) && 543 // check if element is even in loadable area from right 544 (-threshold < elementBound.right); 545 546 if( direction == "vertical" ) return vertical; 547 else if( direction == "horizontal" ) return horizontal; 548 549 return vertical && horizontal; 550 } 551 552 /** 553 * receive the current viewed width of the browser 554 * @access private 555 * @return {number} 556 */ 557 function _getActualWidth() 558 { 559 return _actualWidth >= 0 ? _actualWidth : (_actualWidth = $(window).width()); 560 } 561 562 /** 563 * receive the current viewed height of the browser 564 * @access private 565 * @return {number} 566 */ 567 function _getActualHeight() 568 { 569 return _actualHeight >= 0 ? _actualHeight : (_actualHeight = $(window).height()); 570 } 571 572 /** 573 * helper function to throttle down event triggering 574 * @access private 575 * @param {number} delay 576 * @param {function} callback 577 * @return {function} 578 */ 579 function _throttle(delay, callback) 580 { 581 var timeout, lastExecute = 0; 582 583 return function(event, ignoreThrottle) 584 {
585 var elapsed = +new Date() - lastExecute; 586 587 function run() 588 { 589 lastExecute = +new Date(); 590 callback.call(instance, event); 591 } 592 593 timeout && clearTimeout(timeout); 594 595 if( elapsed > delay || !configuration("enableThrottle") || ignoreThrottle ) run(); 596 else timeout = setTimeout(run, delay - elapsed); 597 }; 598 } 599 600 /** 601 * reduce count of awaiting elements to 'afterLoad' event and fire 'onFinishedAll' if reached zero 602 * @access private 603 * @return void 604 */ 605 function _reduceAwaiting() 606 { 607 --_awaitingAfterLoad; 608 609 // if no items were left trigger finished event 610 if( !items.length && !_awaitingAfterLoad ) _triggerCallback("onFinishedAll"); 611 } 612 613 /** 614 * single implementation to handle callbacks, pass element and set 'this' to current instance 615 * @access private 616 * @param {string|function} callback 617 * @param {object} [element] 618 * @param {*} [args] 619 * @return {boolean} 620 */ 621 function _triggerCallback(callback, element, args) 622 { 623 if( (callback = configuration(callback)) ) 624 { 625 // jQuery's internal '$(arguments).slice(1)' are causing problems at least on old iPads 626 // below is shorthand of 'Array.prototype.slice.call(arguments, 1)' 627 callback.apply(instance, [].slice.call(arguments, 1)); 628 return true; 629 } 630 631 return false; 632 } 633 634 // set up lazy 635 (function() 636 { 637 // if event driven don't wait for page loading 638 if( configuration("bind") == "event" ) _initialize(); 639 640 // otherwise load initial items and start lazy after page load 641 else $(window).on('load', _initialize); 642 })(); 643 } 644 645 /** 646 * lazy plugin class constructor 647 * @constructor 648 * @access private 649 * @param {object} elements 650 * @param {object} settings 651 * @return {object|LazyPlugin} 652 */ 653 function LazyPlugin(elements, settings) 654 { 655 /** 656 * this lazy plugin instance 657 * @access private 658 * @type {object|LazyPlugin} 659 */ 660 var _instance = this, 661 662 /** 663 * this lazy plugin instance configuration 664 * @access private 665 * @type {object} 666 */ 667 _config = $.extend({}, _instance.configuration, settings), 668 669 /** 670 * instance generated event executed on container scroll or resize 671 * packed in an object to be referenceable and short named because properties will not be minified 672 * @access private 673 * @type {object} 674 */ 675 _events = {}; 676 677 // noinspection JSUndefinedPropertyAssignment 678 /** 679 * wrapper to get or set an entry from plugin instance configuration 680 * much smaller on minify as direct access 681 * @access private 682 * @type {function} 683 * @param {string} entryName 684 * @param {*} [value] 685 * @return {LazyPlugin|*} 686 */ 687 _instance.config = function(entryName, value) 688 { 689 if( value === undefined ) 690 return _config[entryName]; 691 else 692 _config[entryName] = value; 693 694 return _instance; 695 }; 696 697 // noinspection JSUndefinedPropertyAssignment 698 /** 699 * add additional items to current instance 700 * @access public 701 * @param {Array|object|string} items 702 * @return {LazyPlugin} 703 */ 704 _instance.addItems = function(items) 705 { 706 if( _events.a ) 707 _events.a($.type(items) === "string" ? $(items) : items); 708 709 return _instance; 710 }; 711 712 // noinspection JSUndefinedPropertyAssignment 713 /** 714 * get all left items of this instance 715 * @access public 716 * @returns {object} 717 */ 718 _instance.getItems = function() 719 { 720 return _events.g ? _events.g() : {}; 721 }; 722 723 // noinspection JSUndefinedPropertyAssignment 724 /** 725 * force lazy to load all items in loadable area right now 726 * by default without throttle 727 * @access public 728 * @type {function} 729 * @param {boolean} [useThrottle] 730 * @return {LazyPlugin} 731 */ 732 _instance.update = function(useThrottle) 733 { 734 if( _events.e ) 735 _events.e({}, !useThrottle); 736 737 return _instance; 738 }; 739 740 // noinspection JSUndefinedPropertyAssignment 741 /** 742 * force lazy to load all available items right now 743 * this call ignores throttling 744 * @access public 745 * @type {function} 746 * @return {LazyPlugin} 747 */ 748 _instance.loadAll = function() 749 { 750 if( _events.e ) 751 _events.e({all: true}, true); 752 753 return _instance; 754 }; 755 756 // noinspection JSUndefinedPropertyAssignment 757 /** 758 * destroy this plugin instance 759 * @access public 760 * @type {function} 761 * @return undefined 762 */ 763 _instance.destroy = function () 764 { 765 // unbind instance generated events 766 // noinspection JSUnresolvedFunction 767 $(_instance.config("appendScroll")).off("." + _instance.name, _events.e); 768 769 // clear events 770 _events = {}; 771 772 return undefined; 773 }; 774 775 // start using lazy and return all elements to be chainable or instance for further use 776 // noinspection JSUnresolvedVariable 777 _executeLazy(_instance, _instance.config, elements, _events); 778 // noinspection JSUnresolvedFunction 779 return _instance.config("chainable") ? elements : _instance; 780 } 781 782 // use jquery to extend class prototype without conflicts 783 $.extend(LazyPlugin.prototype, 784 { 785 /** 786 * internal name used for bindings and namespaces 787 * @access public 788 * @var {string} 789 */ 790 name: "lazy", 791 792 /** 793 * settings and configuration data 794 * @access public 795 * @type {object} 796 */ 797 configuration: 798 { 799 // general 800 chainable : true, 801 autoDestroy : true, 802 bind : "load", 803 threshold : 500, 804 visibleOnly : false, 805 appendScroll : window, 806 scrollDirection : "both", 807 imageBase : null, 808 defaultImage : "data:image/gif;base64,R0lGODlhAQABAIAAAP///wAAACH5BAEAAAAALAAAAAABAAEAAAICRAEAOw==", 809 placeholder : null, 810 delay : -1, 811 combined : false, 812 813 // attributes 814 attribute : "data-src", 815 retinaAttribute : "data-retina", 816 loaderAttribute : "data-loader", 817 removeAttribute : true, 818 handledName : "handled", 819 820 // effect 821 effect : "show", 822 effectTime : 0, 823 824 // throttle 825 enableThrottle : true, 826 throttle : 250, 827 828 // callbacks 829 beforeLoad : null, 830 afterLoad : null, 831 onError : null, 832 onFinishedAll : null 833 } 834 });
vendor: 10,988 bytes, lines 835-1187
835})(jQuery, window, document); 836/** 837* jquery.matchHeight.js master 838* http://brm.io/jquery-match-height/ 839* License: MIT 840*/ 841 842;(function($) { 843 /* 844 * internal 845 */ 846 847 var _previousResizeWidth = -1, 848 _updateTimeout = -1; 849 850 /* 851 * _parse 852 * value parse utility function 853 */ 854 855 var _parse = function(value) { 856 // parse value and convert NaN to 0 857 return parseFloat(value) || 0; 858 }; 859 860 /* 861 * _rows 862 * utility function returns array of jQuery selections representing each row 863 * (as displayed after float wrapping applied by browser) 864 */ 865 866 var _rows = function(elements) { 867 var tolerance = 1, 868 $elements = $(elements), 869 lastTop = null, 870 rows = []; 871 872 // group elements by their top position 873 $elements.each(function(){ 874 var $that = $(this), 875 top = $that.offset().top - _parse($that.css('margin-top')), 876 lastRow = rows.length > 0 ? rows[rows.length - 1] : null; 877 878 if (lastRow === null) { 879 // first item on the row, so just push it 880 rows.push($that); 881 } else { 882 // if the row top is the same, add to the row group 883 if (Math.floor(Math.abs(lastTop - top)) <= tolerance) { 884 rows[rows.length - 1] = lastRow.add($that); 885 } else { 886 // otherwise start a new row group 887 rows.push($that); 888 } 889 } 890 891 // keep track of the last row top 892 lastTop = top; 893 }); 894 895 return rows; 896 }; 897 898 /* 899 * _parseOptions 900 * handle plugin options 901 */ 902 903 var _parseOptions = function(options) { 904 var opts = { 905 byRow: true, 906 property: 'height', 907 target: null, 908 remove: false 909 }; 910 911 if (typeof options === 'object') { 912 return $.extend(opts, options); 913 } 914 915 if (typeof options === 'boolean') { 916 opts.byRow = options; 917 } else if (options === 'remove') { 918 opts.remove = true; 919 } 920 921 return opts; 922 }; 923 924 /* 925 * matchHeight 926 * plugin definition 927 */ 928 929 var matchHeight = $.fn.matchHeight = function(options) { 930 var opts = _parseOptions(options); 931 932 // handle remove 933 if (opts.remove) { 934 var that = this; 935 936 // remove fixed height from all selected elements 937 this.css(opts.property, ''); 938 939 // remove selected elements from all groups 940 $.each(matchHeight._groups, function(key, group) { 941 group.elements = group.elements.not(that); 942 }); 943 944 // TODO: cleanup empty groups 945 946 return this; 947 } 948 949 if (this.length <= 1 && !opts.target) { 950 return this; 951 } 952 953 // keep track of this group so we can re-apply later on load and resize events 954 matchHeight._groups.push({ 955 elements: this, 956 options: opts 957 }); 958 959 // match each element's height to the tallest element in the selection 960 matchHeight._apply(this, opts); 961 962 return this; 963 }; 964 965 /* 966 * plugin global options 967 */ 968 969 matchHeight._groups = []; 970 matchHeight._throttle = 80; 971 matchHeight._maintainScroll = false; 972 matchHeight._beforeUpdate = null; 973 matchHeight._afterUpdate = null; 974 matchHeight._rows = _rows; 975 976 /* 977 * matchHeight._apply 978 * apply matchHeight to given elements 979 */ 980 981 matchHeight._apply = function(elements, options) { 982 var opts = _parseOptions(options), 983 $elements = $(elements), 984 rows = [$elements]; 985 986 // take note of scroll position 987 var scrollTop = $(window).scrollTop(), 988 htmlHeight = $('html').outerHeight(true); 989 990 // get hidden parents 991 var $hiddenParents = $elements.parents().filter(':hidden'); 992 993 // cache the original inline style 994 $hiddenParents.each(function() { 995 var $that = $(this); 996 $that.data('style-cache', $that.attr('style')); 997 }); 998 999 // temporarily must force hidden parents visible 1000 $hiddenParents.css('display', 'block'); 1001 1002 // get rows if using byRow, otherwise assume one row 1003 if (opts.byRow && !opts.target) { 1004 1005 // must first force an arbitrary equal height so floating elements break evenly 1006 $elements.each(function() { 1007 var $that = $(this), 1008 display = $that.css('display'); 1009 1010 // temporarily force a usable display value 1011 if (display !== 'inline-block' && display !== 'inline-flex') { 1012 display = 'block'; 1013 } 1014 1015 // cache the original inline style 1016 $that.data('style-cache', $that.attr('style')); 1017 1018 $that.css({ 1019 'display': display, 1020 'padding-top': '0', 1021 'padding-bottom': '0', 1022 'margin-top': '0', 1023 'margin-bottom': '0', 1024 'border-top-width': '0', 1025 'border-bottom-width': '0', 1026 'height': '100px' 1027 }); 1028 }); 1029 1030 // get the array of rows (based on element top position) 1031 rows = _rows($elements); 1032 1033 // revert original inline styles 1034 $elements.each(function() { 1035 var $that = $(this); 1036 $that.attr('style', $that.data('style-cache') || ''); 1037 }); 1038 } 1039 1040 $.each(rows, function(key, row) { 1041 var $row = $(row), 1042 targetHeight = 0; 1043 1044 if (!opts.target) { 1045 // skip apply to rows with only one item 1046 if (opts.byRow && $row.length <= 1) { 1047 $row.css(opts.property, ''); 1048 return; 1049 } 1050 1051 // iterate the row and find the max height 1052 $row.each(function(){ 1053 var $that = $(this), 1054 display = $that.css('display'); 1055 1056 // temporarily force a usable display value 1057 if (display !== 'inline-block' && display !== 'inline-flex') { 1058 display = 'block'; 1059 } 1060 1061 // ensure we get the correct actual height (and not a previously set height value) 1062 var css = { 'display': display }; 1063 css[opts.property] = ''; 1064 $that.css(css); 1065 1066 // find the max height (including padding, but not margin) 1067 if ($that.outerHeight(false) > targetHeight) { 1068 targetHeight = $that.outerHeight(false); 1069 } 1070 1071 // revert display block 1072 $that.css('display', ''); 1073 }); 1074 } else { 1075 // if target set, use the height of the target element 1076 targetHeight = opts.target.outerHeight(false); 1077 } 1078 1079 // iterate the row and apply the height to all elements 1080 $row.each(function(){ 1081 var $that = $(this), 1082 verticalPadding = 0; 1083 1084 // don't apply to a target 1085 if (opts.target && $that.is(opts.target)) { 1086 return; 1087 } 1088 1089 // handle padding and border correctly (required when not using border-box) 1090 if ($that.css('box-sizing') !== 'border-box') { 1091 verticalPadding += _parse($that.css('border-top-width')) + _parse($that.css('border-bottom-width')); 1092 verticalPadding += _parse($that.css('padding-top')) + _parse($that.css('padding-bottom')); 1093 } 1094 1095 // set the height (accounting for padding and border) 1096 $that.css(opts.property, (targetHeight - verticalPadding) + 'px'); 1097 }); 1098 }); 1099 1100 // revert hidden parents 1101 $hiddenParents.each(function() { 1102 var $that = $(this); 1103 $that.attr('style', $that.data('style-cache') || null); 1104 }); 1105 1106 // restore scroll position if enabled 1107 if (matchHeight._maintainScroll) { 1108 $(window).scrollTop((scrollTop / htmlHeight) * $('html').outerHeight(true)); 1109 } 1110 1111 return this; 1112 }; 1113 1114 /* 1115 * matchHeight._applyDataApi 1116 * applies matchHeight to all elements with a data-match-height attribute 1117 */ 1118 1119 matchHeight._applyDataApi = function() { 1120 var groups = {}; 1121 1122 // generate groups by their groupId set by elements using data-match-height 1123 $('[data-match-height], [data-mh]').each(function() { 1124 var $this = $(this), 1125 groupId = $this.attr('data-mh') || $this.attr('data-match-height'); 1126 1127 if (groupId in groups) { 1128 groups[groupId] = groups[groupId].add($this); 1129 } else { 1130 groups[groupId] = $this; 1131 } 1132 }); 1133 1134 // apply matchHeight to each group 1135 $.each(groups, function() { 1136 this.matchHeight(true); 1137 }); 1138 }; 1139 1140 /* 1141 * matchHeight._update 1142 * updates matchHeight on all current groups with their correct options 1143 */ 1144 1145 var _update = function(event) { 1146 if (matchHeight._beforeUpdate) { 1147 matchHeight._beforeUpdate(event, matchHeight._groups); 1148 } 1149 1150 $.each(matchHeight._groups, function() { 1151 matchHeight._apply(this.elements, this.options); 1152 }); 1153 1154 if (matchHeight._afterUpdate) { 1155 matchHeight._afterUpdate(event, matchHeight._groups); 1156 } 1157 }; 1158 1159 matchHeight._update = function(throttle, event) { 1160 // prevent update if fired from a resize event 1161 // where the viewport width hasn't actually changed 1162 // fixes an event looping bug in IE8 1163 if (event && event.type === 'resize') { 1164 var windowWidth = $(window).width(); 1165 if (windowWidth === _previousResizeWidth) { 1166 return; 1167 } 1168 _previousResizeWidth = windowWidth; 1169 } 1170 1171 // throttle updates 1172 if (!throttle) { 1173 _update(event); 1174 } else if (_updateTimeout === -1) { 1175 _updateTimeout = setTimeout(function() { 1176 _update(event); 1177 _updateTimeout = -1; 1178 }, matchHeight._throttle); 1179 } 1180 }; 1181 1182 /* 1183 * bind events 1184 */ 1185 1186 // apply on DOM ready event 1187 $(matchHeight._applyDataApi);
1188 1189 // update heights on load and resize events 1190 $(window).bind('load', function(event) { 1191 matchHeight._update(false, event); 1192 }); 1193 1194 // throttled update heights on resize events 1195 $(window).bind('resize orientationchange', function(event) { 1196 matchHeight._update(true, event); 1197 }); 1198 1199})(jQuery); 1200 1201/* 1202* debouncedresize: special jQuery event that happens once after a window resize 1203* 1204* latest version and complete README available on Github: 1205* https://github.com/louisremi/jquery-smartresize/blob/master/jquery.debouncedresize.js 1206* 1207* Copyright 2011 @louis_remi 1208* Licensed under the MIT license. 1209*/ 1210var $event = $.event, 1211$special, 1212resizeTimeout; 1213 1214$special = $event.special.debouncedresize = { 1215 setup: function() { 1216 $( this ).on( "resize", $special.handler ); 1217 }, 1218 teardown: function() { 1219 $( this ).off( "resize", $special.handler ); 1220 }, 1221 handler: function( event, execAsap ) { 1222 // Save the context 1223 var context = this, 1224 args = arguments, 1225 dispatch = function() { 1226 // set correct event type 1227 event.type = "debouncedresize"; 1228 $event.dispatch.apply( context, args ); 1229 }; 1230 1231 if ( resizeTimeout ) { 1232 clearTimeout( resizeTimeout ); 1233 } 1234 1235 execAsap ? 1236 dispatch() : 1237 resizeTimeout = setTimeout( dispatch, $special.threshold ); 1238 }, 1239 threshold: 250 1240}; 1241 1242var mediaGallery = (function() { 1243 1244 // list of items 1245 1246 var $grid = $( '.mg-grid' ), 1247 // the items 1248 $items = $grid.children( 'li' ), 1249 // current expanded item's index 1250 current = -1, 1251 // position (top) of the expanded item 1252 // used to know if the preview will expand in a different row 1253 previewPos = -1, 1254 // extra amount of pixels to scroll the window 1255 scrollExtra = 0, 1256 // extra margin when expanded (between preview overlay and the next items) 1257 marginExpanded = 10, 1258 $window = $( window ), winsize, 1259 $body = $( 'html, body' ), 1260 // transitionend events 1261 transEndEventNames = { 1262 'WebkitTransition' : 'webkitTransitionEnd', 1263 'MozTransition' : 'transitionend', 1264 'OTransition' : 'oTransitionEnd', 1265 'msTransition' : 'MSTransitionEnd', 1266 'transition' : 'transitionend' 1267 }, 1268 transEndEventName = transEndEventNames[ Modernizr.prefixed( 'transition' ) ], 1269 // support for csstransitions 1270 support = Modernizr.csstransitions, 1271 // default settings 1272 settings = { 1273 minHeight : 500, 1274 speed : 350, 1275 easing : 'ease' 1276 }; 1277 1278 function init( config ) { 1279 1280 // the settings.. 1281 settings = $.extend( true, {}, settings, config ); 1282 1283 // preload all images 1284 $grid.imagesLoaded( function() { 1285 1286 // save item´s size and offset 1287 saveItemInfo( true ); 1288 // get window´s size 1289 getWinSize(); 1290 // initialize some events 1291 initEvents(); 1292 1293 } ); 1294 1295 } 1296 1297 // add more items to the grid. 1298 // the new items need to appended to the grid. 1299 // after that call Grid.addItems(theItems); 1300 function addItems( $newitems ) { 1301 1302 $items = $items.add( $newitems ); 1303 1304 $newitems.each( function() { 1305 var $item = $( this ); 1306 $item.data( { 1307 offsetTop : $item.offset().top, 1308 height : $item.height() 1309 1310 } ); 1311 } ); 1312 1313 initItemsEvents( $newitems ); 1314 1315 } 1316 1317 // saves the item´s offset top and height (if saveheight is true) 1318 function saveItemInfo( saveheight ) { 1319 $items.each( function() { 1320 var $item = $( this ); 1321 $item.data( 'offsetTop', $item.offset().top ); 1322 if( saveheight ) { 1323 $item.data( 'height', $item.height() ); 1324 } 1325 } ); 1326 } 1327 1328 function initEvents() { 1329 1330 // when clicking an item, show the preview with the item´s info and large image. 1331 // close the item if already expanded. 1332 // also close if clicking on the item´s cross 1333 initItemsEvents( $items ); 1334 1335 // on window resize get the window´s size again 1336 // reset some values.. 1337 $window.on( 'debouncedresize', function() { 1338 1339 scrollExtra = 0; 1340 previewPos = -1; 1341 // save item´s offset 1342 saveItemInfo(true); 1343 getWinSize(); 1344 var preview = $.data( this, 'preview' ); 1345 if( typeof preview != 'undefined' ) { 1346 hidePreview(); 1347 } 1348 1349 } ); 1350 1351 } 1352 1353 function initItemsEvents( $items ) { 1354 $items.on( 'click', 'span.og-close', function() { 1355 $('.og-expanded').removeClass('og-expanded'); 1356 hidePreview(); 1357 return false; 1358 } ).children( 'a' ).on( 'click', function(e) { 1359 1360 var $item = $( this ).parent(); 1361 1362 $('.og-expanded').removeClass('og-expanded'); 1363 1364 // check if item already opened 1365 current === $item.index() ? hidePreview() : showPreview( $item ); 1366 return false; 1367 1368 } ); 1369 } 1370 1371 function getWinSize() { 1372 winsize = { width : $window.width(), height : $window.height() }; 1373 } 1374 1375 function showPreview( $item ) { 1376 1377 var preview = $.data( this, 'preview' ), 1378 // item´s offset top 1379 position = $item.data( 'offsetTop' ); 1380 1381 scrollExtra = 0; 1382 1383 // if a preview exists and previewPos is different (different row) from item´s top then close it 1384 if( typeof preview != 'undefined' ) { 1385 1386 // not in the same row 1387 if( previewPos !== position ) { 1388 // if position > previewPos then we need to take te current preview´s height in consideration when scrolling the window 1389 if( position > previewPos ) { 1390 scrollExtra = preview.height; 1391 } 1392 hidePreview(); 1393 } 1394 // same row 1395 else { 1396 preview.update( $item ); 1397 return false; 1398 } 1399 1400 } 1401 1402 // update previewPos 1403 previewPos = position; 1404 // initialize new preview for the clicked item 1405 preview = $.data( this, 'preview', new Preview( $item ) ); 1406 // expand preview overlay 1407 preview.open(); 1408 1409 } 1410 1411 function hidePreview() { 1412 current = -1; 1413 var preview = $.data( this, 'preview' ); 1414 preview.close(); 1415 1416 $.removeData( this, 'preview' ); 1417 } 1418 1419 // the preview obj / overlay 1420 function Preview( $item ) { 1421 this.$item = $item; 1422 this.expandedIdx = this.$item.index(); 1423 this.create(); 1424 this.update(); 1425 } 1426 1427 Preview.prototype = { 1428 create : function() { 1429 // create Preview structure: 1430 this.$title = $( '<h3></h3>' ); 1431 this.$tag = $( '<h3 class="tag"></h3>' ); 1432 this.$href = $( '<a href="#">Visit website</a>' ); 1433 1434 this.$filename = $( '<p class="filename"></p>' ); 1435 this.$filesize = $( '<a href="#" class="filesize">Download</a>' ); 1436 this.$description = $( '<p class="description"></p>' ); 1437 1438 this.$details = $( '<div class="og-details"></div>' ).append( this.$tag, this.$description, this.$filename, this.$filesize); 1439 this.$loading = $( '<div class="og-loading"></div>' ); 1440 this.$fullimage = $( '<div class="og-fullimg"></div>' ).append( this.$loading ); 1441 this.$closePreview = $( '<span class="og-close"></span>' ); 1442 this.$previewInner = $( '<div class="og-expander-inner"></div>' ).append( this.$closePreview, this.$fullimage, this.$details ); 1443 this.$previewEl = $( '<div class="og-expander"></div>' ).append( this.$previewInner ); 1444 // append preview element to the item 1445 this.$item.append( this.getEl() ); 1446 // set the transitions for the preview and the item 1447 if( support ) { 1448 this.setTransition(); 1449 } 1450 }, 1451 update : function( $item ) { 1452 1453 if( $item ) { 1454 this.$item = $item; 1455 } 1456 1457 // if already expanded remove class "og-expanded" from current item and add it to new item 1458 if( current !== -1 ) { 1459 var $currentItem = $items.eq( current ); 1460 $currentItem.removeClass( 'og-expanded' ); 1461 this.$item.addClass( 'og-expanded' ); 1462 // position the preview correctly 1463 this.positionPreview(); 1464 } 1465 1466 // update current value 1467 current = this.$item.index(); 1468 1469 // update preview´s content 1470 var $itemEl = this.$item.children( 'a' ), 1471 eldata = { 1472 href : $itemEl.attr( 'href' ), 1473 tag : $itemEl.data( 'tag' ), 1474 filesize : $itemEl.attr( 'data-filesize' ), 1475 filename : $itemEl.data( 'filename' ), 1476 largesrc : $itemEl.data( 'largesrc' ), 1477 title : $itemEl.data( 'title' ), 1478 description : $itemEl.data( 'description' ), 1479 isVideo : ($itemEl.data( 'isvideo' ).toLowerCase() == 'true') 1480 }; 1481 this.$title.html( eldata.title ); 1482 this.$tag.html( eldata.title ); 1483 if (eldata.isVideo) 1484 { 1485 this.$filesize.html('Watch on Vimeo').attr('href', eldata.href); 1486 this.$filename.html(eldata.href); 1487 } 1488 else 1489 { 1490 this.$filesize.html( 'Download '+ eldata.filesize ).attr( 'href', eldata.href ); 1491 this.$filename.html( eldata.filename ); 1492 } 1493 1494 this.$description.html( eldata.description ); 1495 this.$href.attr( 'href', eldata.href ); 1496 1497 var self = this; 1498 1499 // remove the current image in the preview 1500 if( typeof self.$largeImg != 'undefined' ) { 1501 self.$largeImg.remove(); 1502 } 1503 1504 // preload large image and add it to the preview
1505 // for smaller screens we don´t display the large image (the media query will hide the fullimage wrapper) 1506 if( self.$fullimage.is( ':visible' ) ) { 1507 if(eldata.isVideo){ 1508 var $iframe = $('<iframe width="100%" height="100%" frameborder="0"/>'); 1509 $iframe.attr( 'src', self.cleanseVideoUrl(eldata.largesrc) ); 1510 if( $iframe.attr( 'src' ) === self.cleanseVideoUrl(self.$item.children('a').data( 'largesrc' )) ) { 1511 self.$loading.hide(); 1512 self.$fullimage.empty(); 1513 self.$largeImg = $iframe.fadeIn( 350 ); 1514 self.$fullimage.append( self.$largeImg ); 1515 } 1516 }else{ 1517 this.$loading.show(); 1518 $( '<img/>' ).on('load', function() { 1519 var $img = $( this ); 1520 if( $img.attr( 'src' ) === self.$item.children('a').data( 'largesrc' ) ) { 1521 self.$loading.hide(); 1522 self.$fullimage.empty(); 1523 self.$largeImg = $img.fadeIn( 350 ); 1524 self.$fullimage.append( self.$largeImg ); 1525 } 1526 }).attr( 'src', eldata.largesrc ); 1527 } 1528 } 1529 1530 }, 1531 cleanseVideoUrl : function(url){ 1532 return url.replace("//vimeo.com/", '//player.vimeo.com/video/') 1533 .replace("http:", "") 1534 .replace("https:", ""); 1535 }, 1536 open : function() { 1537 1538 setTimeout( $.proxy( function() { 1539 // set the height for the preview and the item 1540 this.setHeights(); 1541 // scroll to position the preview in the right place 1542 this.positionPreview(); 1543 }, this ), 25 ); 1544 1545 }, 1546 close : function() { 1547 1548 var self = this, 1549 onEndFn = function() { 1550 if( support ) { 1551 $( this ).off( transEndEventName ); 1552 } 1553 self.$item.removeClass( 'og-expanded' ); 1554 self.$previewEl.remove(); 1555 }; 1556 1557 setTimeout( $.proxy( function() { 1558 1559 var that = this; 1560 1561 if( typeof this.$largeImg !== 'undefined' ) { 1562 this.$largeImg.fadeOut( 'fast' ); 1563 } 1564 this.$previewEl.css( 'height', 0 ); 1565 // the current expanded item (might be different from this.$item) 1566 1567 1568 $grid.each(function (i,d) { 1569 var $expandedItem = $(d).children('li').eq( that.expandedIdx ); 1570 $expandedItem.css( 'height', $expandedItem.data( 'height' ) ).on( transEndEventName, onEndFn ); 1571 1572 if( !support ) { 1573 onEndFn.call(); 1574 } 1575 }); 1576 1577 }, this ), 25 ); 1578 1579 return false; 1580 1581 }, 1582 calcHeight : function() { 1583 1584 var heightPreview = winsize.height - this.$item.data( 'height' ) - marginExpanded, 1585 itemHeight = winsize.height; 1586 console.log(itemHeight); 1587 if( heightPreview < settings.minHeight ) { 1588 heightPreview = settings.minHeight; 1589 itemHeight = settings.minHeight + this.$item.data( 'height' ) + marginExpanded; 1590 } 1591 1592 this.height = heightPreview; 1593 this.itemHeight = itemHeight; 1594 1595 }, 1596 setHeights : function() { 1597 1598 var self = this, 1599 onEndFn = function() { 1600 if( support ) { 1601 self.$item.off( transEndEventName ); 1602 } 1603 self.$item.addClass( 'og-expanded' ); 1604 }; 1605 1606 this.calcHeight(); 1607 this.$previewEl.css( 'height', this.height ); 1608 this.$item.css( 'height', this.itemHeight ).on( transEndEventName, onEndFn ); 1609 1610 if( !support ) { 1611 onEndFn.call(); 1612 } 1613 1614 }, 1615 positionPreview : function() { 1616 1617 // scroll page 1618 // case 1 : preview height + item height fits in window´s height 1619 // case 2 : preview height + item height does not fit in window´s height and preview height is smaller than window´s height 1620 // case 3 : preview height + item height does not fit in window´s height and preview height is bigger than window´s height 1621 var position = this.$item.data( 'offsetTop' ), 1622 previewOffsetT = this.$previewEl.offset().top - scrollExtra, 1623 scrollVal = this.height + this.$item.data( 'height' ) + marginExpanded <= winsize.height ? position : this.height < winsize.height ? previewOffsetT - ( winsize.height - this.height ) : previewOffsetT; 1624 1625 $body.animate( { scrollTop : scrollVal }, settings.speed ); 1626 1627 }, 1628 setTransition : function() { 1629 this.$previewEl.css( 'transition', 'height ' + settings.speed + 'ms ' + settings.easing ); 1630 this.$item.css( 'transition', 'height ' + settings.speed + 'ms ' + settings.easing ); 1631 }, 1632 getEl : function() { 1633 return this.$previewEl; 1634 } 1635 } 1636 1637 return { 1638 init : init, 1639 addItems : addItems 1640 }; 1641 1642})(); 1643/*! Picturefill - v3.0.1 - 2015-09-30 1644 * http://scottjehl.github.io/picturefill 1645 * Copyright (c) 2015 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; Licensed MIT 1646 */ 1647/*! Gecko-Picture - v1.0 1648 * https://github.com/scottjehl/picturefill/tree/3.0/src/plugins/gecko-picture 1649 * Firefox's early picture implementation (prior to FF41) is static and does 1650 * not react to viewport changes. This tiny module fixes this. 1651 */ 1652(function(window) { 1653 /*jshint eqnull:true */ 1654 var ua = navigator.userAgent; 1655 1656 if ( window.HTMLPictureElement && ((/ecko/).test(ua) && ua.match(/rv\:(\d+)/) && RegExp.$1 < 41) ) { 1657 addEventListener("resize", (function() { 1658 var timer; 1659 1660 var dummySrc = document.createElement("source"); 1661 1662 var fixRespimg = function(img) { 1663 var source, sizes;
vendor: 20,989 bytes, lines 1664-2373
1664 var picture = img.parentNode; 1665 1666 if (picture.nodeName.toUpperCase() === "PICTURE") { 1667 source = dummySrc.cloneNode(); 1668 1669 picture.insertBefore(source, picture.firstElementChild); 1670 setTimeout(function() { 1671 picture.removeChild(source); 1672 }); 1673 } else if (!img._pfLastSize || img.offsetWidth > img._pfLastSize) { 1674 img._pfLastSize = img.offsetWidth; 1675 sizes = img.sizes; 1676 img.sizes += ",100vw"; 1677 setTimeout(function() { 1678 img.sizes = sizes; 1679 }); 1680 } 1681 }; 1682 1683 var findPictureImgs = function() { 1684 var i; 1685 var imgs = document.querySelectorAll("picture > img, img[srcset][sizes]"); 1686 for (i = 0; i < imgs.length; i++) { 1687 fixRespimg(imgs[i]); 1688 } 1689 }; 1690 var onResize = function() { 1691 clearTimeout(timer); 1692 timer = setTimeout(findPictureImgs, 99); 1693 }; 1694 var mq = window.matchMedia && matchMedia("(orientation: landscape)"); 1695 var init = function() { 1696 onResize(); 1697 1698 if (mq && mq.addListener) { 1699 mq.addListener(onResize); 1700 } 1701 }; 1702 1703 dummySrc.srcset = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw=="; 1704 1705 if (/^[c|i]|d$/.test(document.readyState || "")) { 1706 init(); 1707 } else { 1708 document.addEventListener("DOMContentLoaded", init); 1709 } 1710 1711 return onResize; 1712 })()); 1713 } 1714})(window); 1715 1716/*! Picturefill - v3.0.1 1717 * http://scottjehl.github.io/picturefill 1718 * Copyright (c) 2015 https://github.com/scottjehl/picturefill/blob/master/Authors.txt; 1719 * License: MIT 1720 */ 1721 1722(function( window, document, undefined ) { 1723 // Enable strict mode 1724 "use strict"; 1725 1726 // HTML shim|v it for old IE (IE9 will still need the HTML video tag workaround) 1727 document.createElement( "picture" ); 1728 1729 var warn, eminpx, alwaysCheckWDescriptor, evalId; 1730 // local object for method references and testing exposure 1731 var pf = {}; 1732 var noop = function() {}; 1733 var image = document.createElement( "img" ); 1734 var getImgAttr = image.getAttribute; 1735 var setImgAttr = image.setAttribute; 1736 var removeImgAttr = image.removeAttribute; 1737 var docElem = document.documentElement; 1738 var types = {}; 1739 var cfg = { 1740 //resource selection: 1741 algorithm: "" 1742 }; 1743 var srcAttr = "data-pfsrc"; 1744 var srcsetAttr = srcAttr + "set"; 1745 // ua sniffing is done for undetectable img loading features, 1746 // to do some non crucial perf optimizations 1747 var ua = navigator.userAgent; 1748 var supportAbort = (/rident/).test(ua) || ((/ecko/).test(ua) && ua.match(/rv\:(\d+)/) && RegExp.$1 > 35 ); 1749 var curSrcProp = "currentSrc"; 1750 var regWDesc = /\s+\+?\d+(e\d+)?w/; 1751 var regSize = /(\([^)]+\))?\s*(.+)/; 1752 var setOptions = window.picturefillCFG; 1753 /** 1754 * Shortcut property for https://w3c.github.io/webappsec/specs/mixedcontent/#restricts-mixed-content ( for easy overriding in tests ) 1755 */ 1756 // baseStyle also used by getEmValue (i.e.: width: 1em is important) 1757 var baseStyle = "position:absolute;left:0;visibility:hidden;display:block;padding:0;border:none;font-size:1em;width:1em;overflow:hidden;clip:rect(0px, 0px, 0px, 0px)"; 1758 var fsCss = "font-size:100%!important;"; 1759 var isVwDirty = true; 1760 1761 var cssCache = {}; 1762 var sizeLengthCache = {}; 1763 var DPR = window.devicePixelRatio; 1764 var units = { 1765 px: 1, 1766 "in": 96 1767 }; 1768 var anchor = document.createElement( "a" ); 1769 /** 1770 * alreadyRun flag used for setOptions. is it true setOptions will reevaluate 1771 * @type {boolean} 1772 */ 1773 var alreadyRun = false; 1774 1775 // Reusable, non-"g" Regexes 1776 1777 // (Don't use \s, to avoid matching non-breaking space.) 1778 var regexLeadingSpaces = /^[ \t\n\r\u000c]+/, 1779 regexLeadingCommasOrSpaces = /^[, \t\n\r\u000c]+/, 1780 regexLeadingNotSpaces = /^[^ \t\n\r\u000c]+/, 1781 regexTrailingCommas = /[,]+$/, 1782 regexNonNegativeInteger = /^\d+$/, 1783 1784 // ( Positive or negative or unsigned integers or decimals, without or without exponents. 1785 // Must include at least one digit. 1786 // According to spec tests any decimal point must be followed by a digit. 1787 // No leading plus sign is allowed.) 1788 // https://html.spec.whatwg.org/multipage/infrastructure.html#valid-floating-point-number 1789 regexFloatingPoint = /^-?(?:[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?$/; 1790 1791 var on = function(obj, evt, fn, capture) { 1792 if ( obj.addEventListener ) { 1793 obj.addEventListener(evt, fn, capture || false); 1794 } else if ( obj.attachEvent ) { 1795 obj.attachEvent( "on" + evt, fn); 1796 } 1797 }; 1798 1799 /** 1800 * simple memoize function: 1801 */ 1802 1803 var memoize = function(fn) { 1804 var cache = {}; 1805 return function(input) { 1806 if ( !(input in cache) ) { 1807 cache[ input ] = fn(input); 1808 } 1809 return cache[ input ]; 1810 }; 1811 }; 1812 1813 // UTILITY FUNCTIONS 1814 1815 // Manual is faster than RegEx 1816 // http://jsperf.com/whitespace-character/5 1817 function isSpace(c) { 1818 return (c === "\u0020" || // space 1819 c === "\u0009" || // horizontal tab 1820 c === "\u000A" || // new line 1821 c === "\u000C" || // form feed 1822 c === "\u000D"); // carriage return 1823 } 1824 1825 /** 1826 * gets a mediaquery and returns a boolean or gets a css length and returns a number 1827 * @param css mediaqueries or css length 1828 * @returns {boolean|number} 1829 * 1830 * based on: https://gist.github.com/jonathantneal/db4f77009b155f083738 1831 */ 1832 var evalCSS = (function() { 1833 1834 var regLength = /^([\d\.]+)(em|vw|px)$/; 1835 var replace = function() { 1836 var args = arguments, index = 0, string = args[0]; 1837 while (++index in args) { 1838 string = string.replace(args[index], args[++index]); 1839 } 1840 return string; 1841 }; 1842 1843 var buildStr = memoize(function(css) { 1844 1845 return "return " + replace((css || "").toLowerCase(), 1846 // interpret `and` 1847 /\band\b/g, "&&", 1848 1849 // interpret `,` 1850 /,/g, "||", 1851 1852 // interpret `min-` as >= 1853 /min-([a-z-\s]+):/g, "e.$1>=", 1854 1855 // interpret `max-` as <= 1856 /max-([a-z-\s]+):/g, "e.$1<=", 1857 1858 //calc value 1859 /calc([^)]+)/g, "($1)", 1860 1861 // interpret css values 1862 /(\d+[\.]*[\d]*)([a-z]+)/g, "($1 * e.$2)", 1863 //make eval less evil 1864 /^(?!(e.[a-z]|[0-9\.&=|><\+\-\*\(\)\/])).*/ig, "" 1865 ) + ";"; 1866 }); 1867 1868 return function(css, length) { 1869 var parsedLength; 1870 if (!(css in cssCache)) { 1871 cssCache[css] = false; 1872 if (length && (parsedLength = css.match( regLength ))) { 1873 cssCache[css] = parsedLength[ 1 ] * units[parsedLength[ 2 ]]; 1874 } else { 1875 /*jshint evil:true */ 1876 try{ 1877 cssCache[css] = new Function("e", buildStr(css))(units); 1878 } catch(e) {} 1879 /*jshint evil:false */ 1880 } 1881 } 1882 return cssCache[css]; 1883 }; 1884 })(); 1885 1886 var setResolution = function( candidate, sizesattr ) { 1887 if ( candidate.w ) { // h = means height: || descriptor.type === 'h' do not handle yet... 1888 candidate.cWidth = pf.calcListLength( sizesattr || "100vw" ); 1889 candidate.res = candidate.w / candidate.cWidth ; 1890 } else { 1891 candidate.res = candidate.d; 1892 } 1893 return candidate; 1894 }; 1895 1896 /** 1897 * 1898 * @param opt 1899 */ 1900 var picturefill = function( opt ) { 1901 var elements, i, plen; 1902 1903 var options = opt || {}; 1904 1905 if ( options.elements && options.elements.nodeType === 1 ) { 1906 if ( options.elements.nodeName.toUpperCase() === "IMG" ) { 1907 options.elements = [ options.elements ]; 1908 } else { 1909 options.context = options.elements; 1910 options.elements = null; 1911 } 1912 } 1913 1914 elements = options.elements || pf.qsa( (options.context || document), ( options.reevaluate || options.reselect ) ? pf.sel : pf.selShort ); 1915 1916 if ( (plen = elements.length) ) { 1917 1918 pf.setupRun( options ); 1919 alreadyRun = true; 1920 1921 // Loop through all elements 1922 for ( i = 0; i < plen; i++ ) { 1923 pf.fillImg(elements[ i ], options); 1924 } 1925 1926 pf.teardownRun( options ); 1927 } 1928 }; 1929 1930 /** 1931 * outputs a warning for the developer 1932 * @param {message} 1933 * @type {Function} 1934 */ 1935 warn = ( window.console && console.warn ) ? 1936 function( message ) { 1937 console.warn( message ); 1938 } : 1939 noop 1940 ; 1941 1942 if ( !(curSrcProp in image) ) { 1943 curSrcProp = "src"; 1944 } 1945 1946 // Add support for standard mime types. 1947 types[ "image/jpeg" ] = true; 1948 types[ "image/gif" ] = true; 1949 types[ "image/png" ] = true; 1950 1951 function detectTypeSupport( type, typeUri ) { 1952 // based on Modernizr's lossless img-webp test 1953 // note: asynchronous 1954 var image = new window.Image(); 1955 image.onerror = function() { 1956 types[ type ] = false; 1957 picturefill(); 1958 }; 1959 image.onload = function() { 1960 types[ type ] = image.width === 1; 1961 picturefill(); 1962 }; 1963 image.src = typeUri; 1964 return "pending"; 1965 } 1966 1967 // test svg support 1968 types[ "image/svg+xml" ] = document.implementation.hasFeature( "http://wwwindow.w3.org/TR/SVG11/feature#Image", "1.1" ); 1969 1970 /** 1971 * updates the internal vW property with the current viewport width in px 1972 */ 1973 function updateMetrics() { 1974 1975 isVwDirty = false; 1976 DPR = window.devicePixelRatio; 1977 cssCache = {}; 1978 sizeLengthCache = {}; 1979 1980 pf.DPR = DPR || 1; 1981 1982 units.width = Math.max(window.innerWidth || 0, docElem.clientWidth); 1983 units.height = Math.max(window.innerHeight || 0, docElem.clientHeight); 1984 1985 units.vw = units.width / 100; 1986 units.vh = units.height / 100; 1987 1988 evalId = [ units.height, units.width, DPR ].join("-"); 1989 1990 units.em = pf.getEmValue(); 1991 units.rem = units.em; 1992 } 1993 1994 function chooseLowRes( lowerValue, higherValue, dprValue, isCached ) { 1995 var bonusFactor, tooMuch, bonus, meanDensity; 1996 1997 //experimental 1998 if (cfg.algorithm === "saveData" ){ 1999 if ( lowerValue > 2.7 ) { 2000 meanDensity = dprValue + 1; 2001 } else { 2002 tooMuch = higherValue - dprValue; 2003 bonusFactor = Math.pow(lowerValue - 0.6, 1.5); 2004 2005 bonus = tooMuch * bonusFactor; 2006 2007 if (isCached) { 2008 bonus += 0.1 * bonusFactor; 2009 } 2010 2011 meanDensity = lowerValue + bonus; 2012 } 2013 } else { 2014 meanDensity = (dprValue > 1) ? 2015 Math.sqrt(lowerValue * higherValue) : 2016 lowerValue; 2017 } 2018 2019 return meanDensity > dprValue; 2020 } 2021 2022 function applyBestCandidate( img ) { 2023 var srcSetCandidates; 2024 var matchingSet = pf.getSet( img ); 2025 var evaluated = false; 2026 if ( matchingSet !== "pending" ) { 2027 evaluated = evalId; 2028 if ( matchingSet ) { 2029 srcSetCandidates = pf.setRes( matchingSet ); 2030 pf.applySetCandidate( srcSetCandidates, img ); 2031 } 2032 } 2033 img[ pf.ns ].evaled = evaluated; 2034 } 2035 2036 function ascendingSort( a, b ) { 2037 return a.res - b.res; 2038 } 2039 2040 function setSrcToCur( img, src, set ) { 2041 var candidate; 2042 if ( !set && src ) { 2043 set = img[ pf.ns ].sets; 2044 set = set && set[set.length - 1]; 2045 } 2046 2047 candidate = getCandidateForSrc(src, set); 2048 2049 if ( candidate ) { 2050 src = pf.makeUrl(src); 2051 img[ pf.ns ].curSrc = src; 2052 img[ pf.ns ].curCan = candidate; 2053 2054 if ( !candidate.res ) { 2055 setResolution( candidate, candidate.set.sizes ); 2056 } 2057 } 2058 return candidate; 2059 } 2060 2061 function getCandidateForSrc( src, set ) { 2062 var i, candidate, candidates; 2063 if ( src && set ) { 2064 candidates = pf.parseSet( set ); 2065 src = pf.makeUrl(src); 2066 for ( i = 0; i < candidates.length; i++ ) { 2067 if ( src === pf.makeUrl(candidates[ i ].url) ) { 2068 candidate = candidates[ i ]; 2069 break; 2070 } 2071 } 2072 } 2073 return candidate; 2074 } 2075 2076 function getAllSourceElements( picture, candidates ) { 2077 var i, len, source, srcset; 2078 2079 // SPEC mismatch intended for size and perf: 2080 // actually only source elements preceding the img should be used 2081 // also note: don't use qsa here, because IE8 sometimes doesn't like source as the key part in a selector 2082 var sources = picture.getElementsByTagName( "source" ); 2083 2084 for ( i = 0, len = sources.length; i < len; i++ ) { 2085 source = sources[ i ]; 2086 source[ pf.ns ] = true; 2087 srcset = source.getAttribute( "srcset" ); 2088 2089 // if source does not have a srcset attribute, skip 2090 if ( srcset ) { 2091 candidates.push( { 2092 srcset: srcset, 2093 media: source.getAttribute( "media" ), 2094 type: source.getAttribute( "type" ), 2095 sizes: source.getAttribute( "sizes" ) 2096 } ); 2097 } 2098 } 2099 } 2100 2101 /** 2102 * Srcset Parser 2103 * By Alex Bell | MIT License 2104 * 2105 * @returns Array [{url: _, d: _, w: _, h:_, set:_(????)}, ...] 2106 * 2107 * Based super duper closely on the reference algorithm at: 2108 * https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-srcset-attribute 2109 */ 2110 2111 // 1. Let input be the value passed to this algorithm. 2112 // (TO-DO : Explain what "set" argument is here. Maybe choose a more 2113 // descriptive & more searchable name. Since passing the "set" in really has 2114 // nothing to do with parsing proper, I would prefer this assignment eventually 2115 // go in an external fn.) 2116 function parseSrcset(input, set) { 2117 2118 function collectCharacters(regEx) { 2119 var chars, 2120 match = regEx.exec(input.substring(pos)); 2121 if (match) { 2122 chars = match[ 0 ]; 2123 pos += chars.length; 2124 return chars; 2125 } 2126 } 2127 2128 var inputLength = input.length, 2129 url, 2130 descriptors, 2131 currentDescriptor, 2132 state, 2133 c, 2134 2135 // 2. Let position be a pointer into input, initially pointing at the start 2136 // of the string. 2137 pos = 0, 2138 2139 // 3. Let candidates be an initially empty source set. 2140 candidates = []; 2141 2142 /** 2143 * Adds descriptor properties to a candidate, pushes to the candidates array 2144 * @return undefined 2145 */ 2146 // (Declared outside of the while loop so that it's only created once. 2147 // (This fn is defined before it is used, in order to pass JSHINT. 2148 // Unfortunately this breaks the sequencing of the spec comments. :/ ) 2149 function parseDescriptors() { 2150 2151 // 9. Descriptor parser: Let error be no. 2152 var pError = false, 2153 2154 // 10. Let width be absent. 2155 // 11. Let density be absent. 2156 // 12. Let future-compat-h be absent. (We're implementing it now as h) 2157 w, d, h, i, 2158 candidate = {}, 2159 desc, lastChar, value, intVal, floatVal; 2160 2161 // 13. For each descriptor in descriptors, run the appropriate set of steps 2162 // from the following list: 2163 for (i = 0 ; i < descriptors.length; i++) { 2164 desc = descriptors[ i ]; 2165 2166 lastChar = desc[ desc.length - 1 ]; 2167 value = desc.substring(0, desc.length - 1); 2168 intVal = parseInt(value, 10); 2169 floatVal = parseFloat(value); 2170 2171 // If the descriptor consists of a valid non-negative integer followed by 2172 // a U+0077 LATIN SMALL LETTER W character 2173 if (regexNonNegativeInteger.test(value) && (lastChar === "w")) { 2174 2175 // If width and density are not both absent, then let error be yes. 2176 if (w || d) {pError = true;} 2177 2178 // Apply the rules for parsing non-negative integers to the descriptor. 2179 // If the result is zero, let error be yes. 2180 // Otherwise, let width be the result. 2181 if (intVal === 0) {pError = true;} else {w = intVal;} 2182 2183 // If the descriptor consists of a valid floating-point number followed by 2184 // a U+0078 LATIN SMALL LETTER X character 2185 } else if (regexFloatingPoint.test(value) && (lastChar === "x")) { 2186 2187 // If width, density and future-compat-h are not all absent, then let error 2188 // be yes. 2189 if (w || d || h) {pError = true;} 2190 2191 // Apply the rules for parsing floating-point number values to the descriptor. 2192 // If the result is less than zero, let error be yes. Otherwise, let density 2193 // be the result. 2194 if (floatVal < 0) {pError = true;} else {d = floatVal;} 2195 2196 // If the descriptor consists of a valid non-negative integer followed by 2197 // a U+0068 LATIN SMALL LETTER H character 2198 } else if (regexNonNegativeInteger.test(value) && (lastChar === "h")) { 2199 2200 // If height and density are not both absent, then let error be yes. 2201 if (h || d) {pError = true;} 2202 2203 // Apply the rules for parsing non-negative integers to the descriptor. 2204 // If the result is zero, let error be yes. Otherwise, let future-compat-h 2205 // be the result. 2206 if (intVal === 0) {pError = true;} else {h = intVal;} 2207 2208 // Anything else, Let error be yes. 2209 } else {pError = true;} 2210 } // (close step 13 for loop) 2211 2212 // 15. If error is still no, then append a new image source to candidates whose 2213 // URL is url, associated with a width width if not absent and a pixel 2214 // density density if not absent. Otherwise, there is a parse error. 2215 if (!pError) { 2216 candidate.url = url; 2217 2218 if (w) { candidate.w = w;} 2219 if (d) { candidate.d = d;} 2220 if (h) { candidate.h = h;} 2221 if (!h && !d && !w) {candidate.d = 1;} 2222 if (candidate.d === 1) {set.has1x = true;} 2223 candidate.set = set; 2224 2225 candidates.push(candidate); 2226 } 2227 } // (close parseDescriptors fn) 2228 2229 /** 2230 * Tokenizes descriptor properties prior to parsing 2231 * Returns undefined. 2232 * (Again, this fn is defined before it is used, in order to pass JSHINT. 2233 * Unfortunately this breaks the logical sequencing of the spec comments. :/ ) 2234 */ 2235 function tokenize() { 2236 2237 // 8.1. Descriptor tokeniser: Skip whitespace 2238 collectCharacters(regexLeadingSpaces); 2239 2240 // 8.2. Let current descriptor be the empty string. 2241 currentDescriptor = ""; 2242 2243 // 8.3. Let state be in descriptor. 2244 state = "in descriptor"; 2245 2246 while (true) { 2247 2248 // 8.4. Let c be the character at position. 2249 c = input.charAt(pos); 2250 2251 // Do the following depending on the value of state. 2252 // For the purpose of this step, "EOF" is a special character representing 2253 // that position is past the end of input. 2254 2255 // In descriptor 2256 if (state === "in descriptor") { 2257 // Do the following, depending on the value of c: 2258 2259 // Space character 2260 // If current descriptor is not empty, append current descriptor to 2261 // descriptors and let current descriptor be the empty string. 2262 // Set state to after descriptor. 2263 if (isSpace(c)) { 2264 if (currentDescriptor) { 2265 descriptors.push(currentDescriptor); 2266 currentDescriptor = ""; 2267 state = "after descriptor"; 2268 } 2269 2270 // U+002C COMMA (,) 2271 // Advance position to the next character in input. If current descriptor 2272 // is not empty, append current descriptor to descriptors. Jump to the step 2273 // labeled descriptor parser. 2274 } else if (c === ",") { 2275 pos += 1; 2276 if (currentDescriptor) { 2277 descriptors.push(currentDescriptor); 2278 } 2279 parseDescriptors(); 2280 return; 2281 2282 // U+0028 LEFT PARENTHESIS (() 2283 // Append c to current descriptor. Set state to in parens. 2284 } else if (c === "\u0028") { 2285 currentDescriptor = currentDescriptor + c; 2286 state = "in parens"; 2287 2288 // EOF 2289 // If current descriptor is not empty, append current descriptor to 2290 // descriptors. Jump to the step labeled descriptor parser. 2291 } else if (c === "") { 2292 if (currentDescriptor) { 2293 descriptors.push(currentDescriptor); 2294 } 2295 parseDescriptors(); 2296 return; 2297 2298 // Anything else 2299 // Append c to current descriptor. 2300 } else { 2301 currentDescriptor = currentDescriptor + c; 2302 } 2303 // (end "in descriptor" 2304 2305 // In parens 2306 } else if (state === "in parens") { 2307 2308 // U+0029 RIGHT PARENTHESIS ()) 2309 // Append c to current descriptor. Set state to in descriptor. 2310 if (c === ")") { 2311 currentDescriptor = currentDescriptor + c; 2312 state = "in descriptor"; 2313 2314 // EOF 2315 // Append current descriptor to descriptors. Jump to the step labeled 2316 // descriptor parser. 2317 } else if (c === "") { 2318 descriptors.push(currentDescriptor); 2319 parseDescriptors(); 2320 return; 2321 2322 // Anything else 2323 // Append c to current descriptor. 2324 } else { 2325 currentDescriptor = currentDescriptor + c; 2326 } 2327 2328 // After descriptor 2329 } else if (state === "after descriptor") { 2330 2331 // Do the following, depending on the value of c: 2332 // Space character: Stay in this state. 2333 if (isSpace(c)) { 2334 2335 // EOF: Jump to the step labeled descriptor parser. 2336 } else if (c === "") { 2337 parseDescriptors(); 2338 return; 2339 2340 // Anything else 2341 // Set state to in descriptor. Set position to the previous character in input. 2342 } else { 2343 state = "in descriptor"; 2344 pos -= 1; 2345 2346 } 2347 } 2348 2349 // Advance position to the next character in input. 2350 pos += 1; 2351 2352 // Repeat this step. 2353 } // (close while true loop) 2354 } 2355 2356 // 4. Splitting loop: Collect a sequence of characters that are space 2357 // characters or U+002C COMMA characters. If any U+002C COMMA characters 2358 // were collected, that is a parse error. 2359 while (true) { 2360 collectCharacters(regexLeadingCommasOrSpaces); 2361 2362 // 5. If position is past the end of input, return candidates and abort these steps. 2363 if (pos >= inputLength) { 2364 return candidates; // (we're done, this is the sole return path) 2365 } 2366 2367 // 6. Collect a sequence of characters that are not space characters, 2368 // and let that be url. 2369 url = collectCharacters(regexLeadingNotSpaces); 2370 2371 // 7. Let descriptors be a new empty list. 2372 descriptors = []; 2373
2374 // 8. If url ends with a U+002C COMMA character (,), follow these substeps: 2375 // (1). Remove all trailing U+002C COMMA characters from url. If this removed 2376 // more than one character, that is a parse error. 2377 if (url.slice(-1) === ",") { 2378 url = url.replace(regexTrailingCommas, ""); 2379 // (Jump ahead to step 9 to skip tokenization and just push the candidate). 2380 parseDescriptors(); 2381 2382 // Otherwise, follow these substeps: 2383 } else { 2384 tokenize(); 2385 } // (close else of step 8) 2386 2387 // 16. Return to the step labeled splitting loop. 2388 } // (Close of big while loop.) 2389 } 2390 2391 /* 2392 * Sizes Parser 2393 * 2394 * By Alex Bell | MIT License 2395 * 2396 * Non-strict but accurate and lightweight JS Parser for the string value <img sizes="here"> 2397 * 2398 * Reference algorithm at: 2399 * https://html.spec.whatwg.org/multipage/embedded-content.html#parse-a-sizes-attribute 2400 * 2401 * Most comments are copied in directly from the spec 2402 * (except for comments in parens). 2403 * 2404 * Grammar is: 2405 * <source-size-list> = <source-size># [ , <source-size-value> ]? | <source-size-value> 2406 * <source-size> = <media-condition> <source-size-value> 2407 * <source-size-value> = <length> 2408 * http://www.w3.org/html/wg/drafts/html/master/embedded-content.html#attr-img-sizes 2409 * 2410 * E.g. "(max-width: 30em) 100vw, (max-width: 50em) 70vw, 100vw"
vendor: 35,501 bytes, lines 2411-3155
2411 * or "(min-width: 30em), calc(30vw - 15px)" or just "30vw" 2412 * 2413 * Returns the first valid <css-length> with a media condition that evaluates to true, 2414 * or "100vw" if all valid media conditions evaluate to false. 2415 * 2416 */ 2417 2418 function parseSizes(strValue) { 2419 2420 // (Percentage CSS lengths are not allowed in this case, to avoid confusion: 2421 // https://html.spec.whatwg.org/multipage/embedded-content.html#valid-source-size-list 2422 // CSS allows a single optional plus or minus sign: 2423 // http://www.w3.org/TR/CSS2/syndata.html#numbers 2424 // CSS is ASCII case-insensitive: 2425 // http://www.w3.org/TR/CSS2/syndata.html#characters ) 2426 // Spec allows exponential notation for <number> type: 2427 // http://dev.w3.org/csswg/css-values/#numbers 2428 var regexCssLengthWithUnits = /^(?:[+-]?[0-9]+|[0-9]*\.[0-9]+)(?:[eE][+-]?[0-9]+)?(?:ch|cm|em|ex|in|mm|pc|pt|px|rem|vh|vmin|vmax|vw)$/i; 2429 2430 // (This is a quick and lenient test. Because of optional unlimited-depth internal 2431 // grouping parens and strict spacing rules, this could get very complicated.) 2432 var regexCssCalc = /^calc\((?:[0-9a-z \.\+\-\*\/\(\)]+)\)$/i; 2433 2434 var i; 2435 var unparsedSizesList; 2436 var unparsedSizesListLength; 2437 var unparsedSize; 2438 var lastComponentValue; 2439 var size; 2440 2441 // UTILITY FUNCTIONS 2442 2443 // (Toy CSS parser. The goals here are: 2444 // 1) expansive test coverage without the weight of a full CSS parser. 2445 // 2) Avoiding regex wherever convenient. 2446 // Quick tests: http://jsfiddle.net/gtntL4gr/3/ 2447 // Returns an array of arrays.) 2448 function parseComponentValues(str) { 2449 var chrctr; 2450 var component = ""; 2451 var componentArray = []; 2452 var listArray = []; 2453 var parenDepth = 0; 2454 var pos = 0; 2455 var inComment = false; 2456 2457 function pushComponent() { 2458 if (component) { 2459 componentArray.push(component); 2460 component = ""; 2461 } 2462 } 2463 2464 function pushComponentArray() { 2465 if (componentArray[0]) { 2466 listArray.push(componentArray); 2467 componentArray = []; 2468 } 2469 } 2470 2471 // (Loop forwards from the beginning of the string.) 2472 while (true) { 2473 chrctr = str.charAt(pos); 2474 2475 if (chrctr === "") { // ( End of string reached.) 2476 pushComponent(); 2477 pushComponentArray(); 2478 return listArray; 2479 } else if (inComment) { 2480 if ((chrctr === "*") && (str[pos + 1] === "/")) { // (At end of a comment.) 2481 inComment = false; 2482 pos += 2; 2483 pushComponent(); 2484 continue; 2485 } else { 2486 pos += 1; // (Skip all characters inside comments.) 2487 continue; 2488 } 2489 } else if (isSpace(chrctr)) { 2490 // (If previous character in loop was also a space, or if 2491 // at the beginning of the string, do not add space char to 2492 // component.) 2493 if ( (str.charAt(pos - 1) && isSpace( str.charAt(pos - 1) ) ) || !component ) { 2494 pos += 1; 2495 continue; 2496 } else if (parenDepth === 0) { 2497 pushComponent(); 2498 pos +=1; 2499 continue; 2500 } else { 2501 // (Replace any space character with a plain space for legibility.) 2502 chrctr = " "; 2503 } 2504 } else if (chrctr === "(") { 2505 parenDepth += 1; 2506 } else if (chrctr === ")") { 2507 parenDepth -= 1; 2508 } else if (chrctr === ",") { 2509 pushComponent(); 2510 pushComponentArray(); 2511 pos += 1; 2512 continue; 2513 } else if ( (chrctr === "/") && (str.charAt(pos + 1) === "*") ) { 2514 inComment = true; 2515 pos += 2; 2516 continue; 2517 } 2518 2519 component = component + chrctr; 2520 pos += 1; 2521 } 2522 } 2523 2524 function isValidNonNegativeSourceSizeValue(s) { 2525 if (regexCssLengthWithUnits.test(s) && (parseFloat(s) >= 0)) {return true;} 2526 if (regexCssCalc.test(s)) {return true;} 2527 // ( http://www.w3.org/TR/CSS2/syndata.html#numbers says: 2528 // "-0 is equivalent to 0 and is not a negative number." which means that 2529 // unitless zero and unitless negative zero must be accepted as special cases.) 2530 if ((s === "0") || (s === "-0") || (s === "+0")) {return true;} 2531 return false; 2532 } 2533 2534 // When asked to parse a sizes attribute from an element, parse a 2535 // comma-separated list of component values from the value of the element's 2536 // sizes attribute (or the empty string, if the attribute is absent), and let 2537 // unparsed sizes list be the result. 2538 // http://dev.w3.org/csswg/css-syntax/#parse-comma-separated-list-of-component-values 2539 2540 unparsedSizesList = parseComponentValues(strValue); 2541 unparsedSizesListLength = unparsedSizesList.length; 2542 2543 // For each unparsed size in unparsed sizes list: 2544 for (i = 0; i < unparsedSizesListLength; i++) { 2545 unparsedSize = unparsedSizesList[i]; 2546 2547 // 1. Remove all consecutive <whitespace-token>s from the end of unparsed size. 2548 // ( parseComponentValues() already omits spaces outside of parens. ) 2549 2550 // If unparsed size is now empty, that is a parse error; continue to the next 2551 // iteration of this algorithm. 2552 // ( parseComponentValues() won't push an empty array. ) 2553 2554 // 2. If the last component value in unparsed size is a valid non-negative 2555 // <source-size-value>, let size be its value and remove the component value 2556 // from unparsed size. Any CSS function other than the calc() function is 2557 // invalid. Otherwise, there is a parse error; continue to the next iteration 2558 // of this algorithm. 2559 // http://dev.w3.org/csswg/css-syntax/#parse-component-value 2560 lastComponentValue = unparsedSize[unparsedSize.length - 1]; 2561 2562 if (isValidNonNegativeSourceSizeValue(lastComponentValue)) { 2563 size = lastComponentValue; 2564 unparsedSize.pop(); 2565 } else { 2566 continue; 2567 } 2568 2569 // 3. Remove all consecutive <whitespace-token>s from the end of unparsed 2570 // size. If unparsed size is now empty, return size and exit this algorithm. 2571 // If this was not the last item in unparsed sizes list, that is a parse error. 2572 if (unparsedSize.length === 0) { 2573 return size; 2574 } 2575 2576 // 4. Parse the remaining component values in unparsed size as a 2577 // <media-condition>. If it does not parse correctly, or it does parse 2578 // correctly but the <media-condition> evaluates to false, continue to the 2579 // next iteration of this algorithm. 2580 // (Parsing all possible compound media conditions in JS is heavy, complicated, 2581 // and the payoff is unclear. Is there ever an situation where the 2582 // media condition parses incorrectly but still somehow evaluates to true? 2583 // Can we just rely on the browser/polyfill to do it?) 2584 unparsedSize = unparsedSize.join(" "); 2585 if (!(pf.matchesMedia( unparsedSize ) ) ) { 2586 continue; 2587 } 2588 2589 // 5. Return size and exit this algorithm. 2590 return size; 2591 } 2592 2593 // If the above algorithm exhausts unparsed sizes list without returning a 2594 // size value, return 100vw. 2595 return "100vw"; 2596 } 2597 2598 // namespace 2599 pf.ns = ("pf" + new Date().getTime()).substr(0, 9); 2600 2601 // srcset support test 2602 pf.supSrcset = "srcset" in image; 2603 pf.supSizes = "sizes" in image; 2604 pf.supPicture = !!window.HTMLPictureElement; 2605 2606 if (pf.supSrcset && pf.supPicture && !pf.supSizes) { 2607 (function(image2) { 2608 image.srcset = "data:,a"; 2609 image2.src = "data:,a"; 2610 pf.supSrcset = image.complete === image2.complete; 2611 pf.supPicture = pf.supSrcset && pf.supPicture; 2612 })(document.createElement("img")); 2613 } 2614 2615 // using pf.qsa instead of dom traversing does scale much better, 2616 // especially on sites mixing responsive and non-responsive images 2617 pf.selShort = "picture>img,img[srcset]"; 2618 pf.sel = pf.selShort; 2619 pf.cfg = cfg; 2620 2621 if ( pf.supSrcset ) { 2622 pf.sel += ",img[" + srcsetAttr + "]"; 2623 } 2624 2625 /** 2626 * Shortcut property for `devicePixelRatio` ( for easy overriding in tests ) 2627 */ 2628 pf.DPR = (DPR || 1 ); 2629 pf.u = units; 2630 2631 // container of supported mime types that one might need to qualify before using 2632 pf.types = types; 2633 2634 alwaysCheckWDescriptor = pf.supSrcset && !pf.supSizes; 2635 2636 pf.setSize = noop; 2637 2638 /** 2639 * Gets a string and returns the absolute URL 2640 * @param src 2641 * @returns {String} absolute URL 2642 */ 2643 2644 pf.makeUrl = memoize(function(src) { 2645 anchor.href = src; 2646 return anchor.href; 2647 }); 2648 2649 /** 2650 * Gets a DOM element or document and a selctor and returns the found matches 2651 * Can be extended with jQuery/Sizzle for IE7 support 2652 * @param context 2653 * @param sel 2654 * @returns {NodeList} 2655 */ 2656 pf.qsa = function(context, sel) { 2657 return context.querySelectorAll(sel); 2658 }; 2659 2660 /** 2661 * Shortcut method for matchMedia ( for easy overriding in tests ) 2662 * wether native or pf.mMQ is used will be decided lazy on first call 2663 * @returns {boolean} 2664 */ 2665 pf.matchesMedia = function() { 2666 if ( window.matchMedia && (matchMedia( "(min-width: 0.1em)" ) || {}).matches ) { 2667 pf.matchesMedia = function( media ) { 2668 return !media || ( matchMedia( media ).matches ); 2669 }; 2670 } else { 2671 pf.matchesMedia = pf.mMQ; 2672 } 2673 2674 return pf.matchesMedia.apply( this, arguments ); 2675 }; 2676 2677 /** 2678 * A simplified matchMedia implementation for IE8 and IE9 2679 * handles only min-width/max-width with px or em values 2680 * @param media 2681 * @returns {boolean} 2682 */ 2683 pf.mMQ = function( media ) { 2684 return media ? evalCSS(media) : true; 2685 }; 2686 2687 /** 2688 * Returns the calculated length in css pixel from the given sourceSizeValue 2689 * http://dev.w3.org/csswg/css-values-3/#length-value 2690 * intended Spec mismatches: 2691 * * Does not check for invalid use of CSS functions 2692 * * Does handle a computed length of 0 the same as a negative and therefore invalid value 2693 * @param sourceSizeValue 2694 * @returns {Number} 2695 */ 2696 pf.calcLength = function( sourceSizeValue ) { 2697 2698 var value = evalCSS(sourceSizeValue, true) || false; 2699 if (value < 0) { 2700 value = false; 2701 } 2702 2703 return value; 2704 }; 2705 2706 /** 2707 * Takes a type string and checks if its supported 2708 */ 2709 2710 pf.supportsType = function( type ) { 2711 return ( type ) ? types[ type ] : true; 2712 }; 2713 2714 /** 2715 * Parses a sourceSize into mediaCondition (media) and sourceSizeValue (length) 2716 * @param sourceSizeStr 2717 * @returns {*} 2718 */ 2719 pf.parseSize = memoize(function( sourceSizeStr ) { 2720 var match = ( sourceSizeStr || "" ).match(regSize); 2721 return { 2722 media: match && match[1], 2723 length: match && match[2] 2724 }; 2725 }); 2726 2727 pf.parseSet = function( set ) { 2728 if ( !set.cands ) { 2729 set.cands = parseSrcset(set.srcset, set); 2730 } 2731 return set.cands; 2732 }; 2733 2734 /** 2735 * returns 1em in css px for html/body default size 2736 * function taken from respondjs 2737 * @returns {*|number} 2738 */ 2739 pf.getEmValue = function() { 2740 var body; 2741 if ( !eminpx && (body = document.body) ) { 2742 var div = document.createElement( "div" ), 2743 originalHTMLCSS = docElem.style.cssText, 2744 originalBodyCSS = body.style.cssText; 2745 2746 div.style.cssText = baseStyle; 2747 2748 // 1em in a media query is the value of the default font size of the browser 2749 // reset docElem and body to ensure the correct value is returned 2750 docElem.style.cssText = fsCss; 2751 body.style.cssText = fsCss; 2752 2753 body.appendChild( div ); 2754 eminpx = div.offsetWidth; 2755 body.removeChild( div ); 2756 2757 //also update eminpx before returning 2758 eminpx = parseFloat( eminpx, 10 ); 2759 2760 // restore the original values 2761 docElem.style.cssText = originalHTMLCSS; 2762 body.style.cssText = originalBodyCSS; 2763 2764 } 2765 return eminpx || 16; 2766 }; 2767 2768 /** 2769 * Takes a string of sizes and returns the width in pixels as a number 2770 */ 2771 pf.calcListLength = function( sourceSizeListStr ) { 2772 // Split up source size list, ie ( max-width: 30em ) 100%, ( max-width: 50em ) 50%, 33% 2773 // 2774 // or (min-width:30em) calc(30% - 15px) 2775 if ( !(sourceSizeListStr in sizeLengthCache) || cfg.uT ) { 2776 var winningLength = pf.calcLength( parseSizes( sourceSizeListStr ) ); 2777 2778 sizeLengthCache[ sourceSizeListStr ] = !winningLength ? units.width : winningLength; 2779 } 2780 2781 return sizeLengthCache[ sourceSizeListStr ]; 2782 }; 2783 2784 /** 2785 * Takes a candidate object with a srcset property in the form of url/ 2786 * ex. "images/pic-medium.png 1x, images/pic-medium-2x.png 2x" or 2787 * "images/pic-medium.png 400w, images/pic-medium-2x.png 800w" or 2788 * "images/pic-small.png" 2789 * Get an array of image candidates in the form of 2790 * {url: "/foo/bar.png", resolution: 1} 2791 * where resolution is http://dev.w3.org/csswg/css-values-3/#resolution-value 2792 * If sizes is specified, res is calculated 2793 */ 2794 pf.setRes = function( set ) { 2795 var candidates; 2796 if ( set ) { 2797 2798 candidates = pf.parseSet( set ); 2799 2800 for ( var i = 0, len = candidates.length; i < len; i++ ) { 2801 setResolution( candidates[ i ], set.sizes ); 2802 } 2803 } 2804 return candidates; 2805 }; 2806 2807 pf.setRes.res = setResolution; 2808 2809 pf.applySetCandidate = function( candidates, img ) { 2810 if ( !candidates.length ) {return;} 2811 var candidate, 2812 i, 2813 j, 2814 length, 2815 bestCandidate, 2816 curSrc, 2817 curCan, 2818 candidateSrc, 2819 abortCurSrc; 2820 2821 var imageData = img[ pf.ns ]; 2822 var dpr = pf.DPR; 2823 2824 curSrc = imageData.curSrc || img[curSrcProp]; 2825 2826 curCan = imageData.curCan || setSrcToCur(img, curSrc, candidates[0].set); 2827 2828 // if we have a current source, we might either become lazy or give this source some advantage 2829 if ( curCan && curCan.set === candidates[ 0 ].set ) { 2830 2831 // if browser can abort image request and the image has a higher pixel density than needed 2832 // and this image isn't downloaded yet, we skip next part and try to save bandwidth 2833 abortCurSrc = (supportAbort && !img.complete && curCan.res - 0.1 > dpr); 2834 2835 if ( !abortCurSrc ) { 2836 curCan.cached = true; 2837 2838 // if current candidate is "best", "better" or "okay", 2839 // set it to bestCandidate 2840 if ( curCan.res >= dpr ) { 2841 bestCandidate = curCan; 2842 } 2843 } 2844 } 2845 2846 if ( !bestCandidate ) { 2847 2848 candidates.sort( ascendingSort ); 2849 2850 length = candidates.length; 2851 bestCandidate = candidates[ length - 1 ]; 2852 2853 for ( i = 0; i < length; i++ ) { 2854 candidate = candidates[ i ]; 2855 if ( candidate.res >= dpr ) { 2856 j = i - 1; 2857 2858 // we have found the perfect candidate, 2859 // but let's improve this a little bit with some assumptions ;-) 2860 if (candidates[ j ] && 2861 (abortCurSrc || curSrc !== pf.makeUrl( candidate.url )) && 2862 chooseLowRes(candidates[ j ].res, candidate.res, dpr, candidates[ j ].cached)) { 2863 2864 bestCandidate = candidates[ j ]; 2865 2866 } else { 2867 bestCandidate = candidate; 2868 } 2869 break; 2870 } 2871 } 2872 } 2873 2874 if ( bestCandidate ) { 2875 2876 candidateSrc = pf.makeUrl( bestCandidate.url ); 2877 2878 imageData.curSrc = candidateSrc; 2879 imageData.curCan = bestCandidate; 2880 2881 if ( candidateSrc !== curSrc ) { 2882 pf.setSrc( img, bestCandidate ); 2883 } 2884 pf.setSize( img ); 2885 } 2886 }; 2887 2888 pf.setSrc = function( img, bestCandidate ) { 2889 var origWidth; 2890 img.src = bestCandidate.url; 2891 2892 // although this is a specific Safari issue, we don't want to take too much different code paths 2893 if ( bestCandidate.set.type === "image/svg+xml" ) { 2894 origWidth = img.style.width; 2895 img.style.width = (img.offsetWidth + 1) + "px"; 2896 2897 // next line only should trigger a repaint 2898 // if... is only done to trick dead code removal 2899 if ( img.offsetWidth + 1 ) { 2900 img.style.width = origWidth; 2901 } 2902 } 2903 }; 2904 2905 pf.getSet = function( img ) { 2906 var i, set, supportsType; 2907 var match = false; 2908 var sets = img [ pf.ns ].sets; 2909 2910 for ( i = 0; i < sets.length && !match; i++ ) { 2911 set = sets[i]; 2912 2913 if ( !set.srcset || !pf.matchesMedia( set.media ) || !(supportsType = pf.supportsType( set.type )) ) { 2914 continue; 2915 } 2916 2917 if ( supportsType === "pending" ) { 2918 set = supportsType; 2919 } 2920 2921 match = set; 2922 break; 2923 } 2924 2925 return match; 2926 }; 2927 2928 pf.parseSets = function( element, parent, options ) { 2929 var srcsetAttribute, imageSet, isWDescripor, srcsetParsed; 2930 2931 var hasPicture = parent && parent.nodeName.toUpperCase() === "PICTURE"; 2932 var imageData = element[ pf.ns ]; 2933 2934 if ( imageData.src === undefined || options.src ) { 2935 imageData.src = getImgAttr.call( element, "src" ); 2936 if ( imageData.src ) { 2937 setImgAttr.call( element, srcAttr, imageData.src ); 2938 } else { 2939 removeImgAttr.call( element, srcAttr ); 2940 } 2941 } 2942 2943 if ( imageData.srcset === undefined || options.srcset || !pf.supSrcset || element.srcset ) { 2944 srcsetAttribute = getImgAttr.call( element, "srcset" ); 2945 imageData.srcset = srcsetAttribute; 2946 srcsetParsed = true; 2947 } 2948 2949 imageData.sets = []; 2950 2951 if ( hasPicture ) { 2952 imageData.pic = true; 2953 getAllSourceElements( parent, imageData.sets ); 2954 } 2955 2956 if ( imageData.srcset ) { 2957 imageSet = { 2958 srcset: imageData.srcset, 2959 sizes: getImgAttr.call( element, "sizes" ) 2960 }; 2961 2962 imageData.sets.push( imageSet ); 2963 2964 isWDescripor = (alwaysCheckWDescriptor || imageData.src) && regWDesc.test(imageData.srcset || ""); 2965 2966 // add normal src as candidate, if source has no w descriptor 2967 if ( !isWDescripor && imageData.src && !getCandidateForSrc(imageData.src, imageSet) && !imageSet.has1x ) { 2968 imageSet.srcset += ", " + imageData.src; 2969 imageSet.cands.push({ 2970 url: imageData.src, 2971 d: 1, 2972 set: imageSet 2973 }); 2974 } 2975 2976 } else if ( imageData.src ) { 2977 imageData.sets.push( { 2978 srcset: imageData.src, 2979 sizes: null 2980 } ); 2981 } 2982 2983 imageData.curCan = null; 2984 imageData.curSrc = undefined; 2985 2986 // if img has picture or the srcset was removed or has a srcset and does not support srcset at all 2987 // or has a w descriptor (and does not support sizes) set support to false to evaluate 2988 imageData.supported = !( hasPicture || ( imageSet && !pf.supSrcset ) || isWDescripor ); 2989 2990 if ( srcsetParsed && pf.supSrcset && !imageData.supported ) { 2991 if ( srcsetAttribute ) { 2992 setImgAttr.call( element, srcsetAttr, srcsetAttribute ); 2993 element.srcset = ""; 2994 } else { 2995 removeImgAttr.call( element, srcsetAttr ); 2996 } 2997 } 2998 2999 if (imageData.supported && !imageData.srcset && ((!imageData.src && element.src) || element.src !== pf.makeUrl(imageData.src))) { 3000 if (imageData.src === null) { 3001 element.removeAttribute("src"); 3002 } else { 3003 element.src = imageData.src; 3004 } 3005 } 3006 3007 imageData.parsed = true; 3008 }; 3009 3010 pf.fillImg = function(element, options) { 3011 var imageData; 3012 var extreme = options.reselect || options.reevaluate; 3013 3014 // expando for caching data on the img 3015 if ( !element[ pf.ns ] ) { 3016 element[ pf.ns ] = {}; 3017 } 3018 3019 imageData = element[ pf.ns ]; 3020 3021 // if the element has already been evaluated, skip it 3022 // unless `options.reevaluate` is set to true ( this, for example, 3023 // is set to true when running `picturefill` on `resize` ). 3024 if ( !extreme && imageData.evaled === evalId ) { 3025 return; 3026 } 3027 3028 if ( !imageData.parsed || options.reevaluate ) { 3029 pf.parseSets( element, element.parentNode, options ); 3030 } 3031 3032 if ( !imageData.supported ) { 3033 applyBestCandidate( element ); 3034 } else { 3035 imageData.evaled = evalId; 3036 } 3037 }; 3038 3039 pf.setupRun = function() { 3040 if ( !alreadyRun || isVwDirty || (DPR !== window.devicePixelRatio) ) { 3041 updateMetrics(); 3042 } 3043 }; 3044 3045 // If picture is supported, well, that's awesome. 3046 if ( pf.supPicture ) { 3047 picturefill = noop; 3048 pf.fillImg = noop; 3049 } else { 3050 3051 // Set up picture polyfill by polling the document 3052 (function() { 3053 var isDomReady; 3054 var regReady = window.attachEvent ? /d$|^c/ : /d$|^c|^i/; 3055 3056 var run = function() { 3057 var readyState = document.readyState || ""; 3058 3059 timerId = setTimeout(run, readyState === "loading" ? 200 : 999); 3060 if ( document.body ) { 3061 pf.fillImgs(); 3062 isDomReady = isDomReady || regReady.test(readyState); 3063 if ( isDomReady ) { 3064 clearTimeout( timerId ); 3065 } 3066 3067 } 3068 }; 3069 3070 var timerId = setTimeout(run, document.body ? 9 : 99); 3071 3072 // Also attach picturefill on resize and readystatechange 3073 // http://modernjavascript.blogspot.com/2013/08/building-better-debounce.html 3074 var debounce = function(func, wait) { 3075 var timeout, timestamp; 3076 var later = function() { 3077 var last = (new Date()) - timestamp; 3078 3079 if (last < wait) { 3080 timeout = setTimeout(later, wait - last); 3081 } else { 3082 timeout = null; 3083 func(); 3084 } 3085 }; 3086 3087 return function() { 3088 timestamp = new Date(); 3089 3090 if (!timeout) { 3091 timeout = setTimeout(later, wait); 3092 } 3093 }; 3094 }; 3095 var lastClientWidth = docElem.clientHeight; 3096 var onResize = function() { 3097 isVwDirty = Math.max(window.innerWidth || 0, docElem.clientWidth) !== units.width || docElem.clientHeight !== lastClientWidth; 3098 lastClientWidth = docElem.clientHeight; 3099 if ( isVwDirty ) { 3100 pf.fillImgs(); 3101 } 3102 }; 3103 3104 on( window, "resize", debounce(onResize, 99 ) ); 3105 on( document, "readystatechange", run ); 3106 })(); 3107 } 3108 3109 pf.picturefill = picturefill; 3110 //use this internally for easy monkey patching/performance testing 3111 pf.fillImgs = picturefill; 3112 pf.teardownRun = noop; 3113 3114 /* expose methods for testing */ 3115 picturefill._ = pf; 3116 3117 window.picturefillCFG = { 3118 pf: pf, 3119 push: function(args) { 3120 var name = args.shift(); 3121 if (typeof pf[name] === "function") { 3122 pf[name].apply(pf, args); 3123 } else { 3124 cfg[name] = args[0]; 3125 if (alreadyRun) { 3126 pf.fillImgs( { reselect: true } ); 3127 } 3128 } 3129 } 3130 }; 3131 3132 while (setOptions && setOptions.length) { 3133 window.picturefillCFG.push(setOptions.shift()); 3134 } 3135 3136 /* expose picturefill */ 3137 window.picturefill = picturefill; 3138 3139 /* expose picturefill */ 3140 if ( typeof module === "object" && typeof module.exports === "object" ) { 3141 // CommonJS, just export 3142 module.exports = picturefill; 3143 } else if ( typeof define === "function" && define.amd ) { 3144 // AMD support 3145 define( "picturefill", function() { return picturefill; } ); 3146 } 3147 3148 // IE8 evals this sync, so it must be the last thing we do 3149 if ( !pf.supPicture ) { 3150 types[ "image/webp" ] = detectTypeSupport("image/webp", "data:image/webp;base64,UklGRkoAAABXRUJQVlA4WAoAAAAQAAAAAAAAAAAAQUxQSAwAAAABBxAR/Q9ERP8DAABWUDggGAAAADABAJ0BKgEAAQADADQlpAADcAD++/1QAA==" ); 3151 } 3152 3153} )( window, document ); 3154 3155//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImltYWdlc0xvYWRlZC5qcyIsImpxdWVyeS5maXR2aWRzLmpzIiwianF1ZXJ5LmxhenkuanMiLCJqcXVlcnkubWF0Y2hIZWlnaHQuanMiLCJtZWRpYS1nYWxsZXJ5LmpzIiwicGljdHVyZWZpbGwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUN4SEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUN2RkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ2puQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQzVXQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ3piQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUN
3155BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoidmVuZG9yLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLy8gPT09PT09PT09PT09PT09PT09PT09PT0gaW1hZ2VzTG9h
3155ZGVkIFBsdWdpbiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XHJcbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9kZXNhbmRyby9pbWFnZXNsb2FkZWRcclxuXHJcbi8vICQoJyNteS1jb250YWluZXInKS5pbWFnZXNMb2FkZWQobXlGdW5jdGlvbilcclxuLy8gZXhlY3V0ZSBhIGNhbGxiYWNrIHdoZW4gYWxsIGltYWdlcyBoYXZlIGxvYWRlZC5cclxuLy8gbmVlZGVkIGJlY2F1c2UgLmxvYWQoKSBkb2Vzbid0IHdvcmsgb24gY2FjaGVkIGltYWdlc1xyXG5cclxuLy8gY2FsbGJhY2sgZnVuY3Rpb24gZ2V0cyBpbWFnZSBjb2xsZWN0aW9uIGFzIGFyZ3VtZW50XHJcbi8vICB0aGlzIGlzIHRoZSBjb250YWluZXJcclxuXHJcbi8vIG9yaWdpbmFsOiBNSVQgbGljZW5zZS4gUGF1bCBJcmlzaC4gMjAxMC5cclxuLy8gY29udHJpYnV0b3JzOiBPcmVuIFNvbG9taWFuaWssIERhdmlkIERlU2FuZHJvLCBZaWFubmlzIENoYXR6aWtvbnN0YW50aW5vdVxyXG5cclxuLy8gYmxhbmsgaW1hZ2UgZGF0YS11cmkgYnlwYXNzZXMgd2Via2l0IGxvZyB3YXJuaW5nICh0aHggZG91ZyBqb25lcylcclxudmFyIEJMQU5LID0gJ2RhdGE6aW1hZ2UvZ2lmO2Jhc2U2NCxSMGxHT0RsaEFRQUJBSUFBQUFBQUFQLy8veXdBQUFBQUFRQUJBQUFDQVV3QU93PT0nO1xyXG5cclxuJC5mbi5pbWFnZXNMb2FkZWQgPSBmdW5jdGlvbiggY2FsbGJhY2sgKSB7XHJcblx0dmFyICR0aGlzID0gdGhpcyxcclxuXHRcdGRlZmVycmVkID0gJC5pc0Z1bmN0aW9uKCQuRGVmZXJyZWQpID8gJC5EZWZlcnJlZCgpIDogMCxcclxuXHRcdGhhc05vdGlmeSA9ICQuaXNGdW5jdGlvbihkZWZlcnJlZC5ub3RpZnkpLFxyXG5cdFx0JGltYWdlcyA9ICR0aGlzLmZpbmQoJ2ltZycpLmFkZCggJHRoaXMuZmlsdGVyKCdpbWcnKSApLFxyXG5cdFx0bG9hZGVkID0gW10sXHJcblx0XHRwcm9wZXIgPSBbXSxcclxuXHRcdGJyb2tlbiA9IFtdO1xyXG5cclxuXHQvLyBSZWdpc3RlciBkZWZlcnJlZCBjYWxsYmFja3NcclxuXHRpZiAoJC5pc1BsYWluT2JqZWN0KGNhbGxiYWNrKSkge1xyXG5cdFx0JC5lYWNoKGNhbGxiYWNrLCBmdW5jdGlvbiAoa2V5LCB2YWx1ZSkge1xyXG5cdFx0XHRpZiAoa2V5ID09PSAnY2FsbGJhY2snKSB7XHJcblx0XHRcdFx0Y2FsbGJhY2sgPSB2YWx1ZTtcclxuXHRcdFx0fSBlbHNlIGlmIChkZWZlcnJlZCkge1xyXG5cdFx0XHRcdGRlZmVycmVkW2tleV0odmFsdWUpO1xyXG5cdFx0XHR9XHJcblx0XHR9KTtcclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGRvbmVMb2FkaW5nKCkge1xyXG5cdFx0dmFyICRwcm9wZXIgPSAkKHByb3BlciksXHJcblx0XHRcdCRicm9rZW4gPSAkKGJyb2tlbik7XHJcblxyXG5cdFx0aWYgKCBkZWZlcnJlZCApIHtcclxuXHRcdFx0aWYgKCBicm9rZW4ubGVuZ3RoICkge1xyXG5cdFx0XHRcdGRlZmVycmVkLnJlamVjdCggJGltYWdlcywgJHByb3BlciwgJGJyb2tlbiApO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGRlZmVycmVkLnJlc29sdmUoICRpbWFnZXMgKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggJC5pc0Z1bmN0aW9uKCBjYWxsYmFjayApICkge1xyXG5cdFx0XHRjYWxsYmFjay5jYWxsKCAkdGhpcywgJGltYWdlcywgJHByb3BlciwgJGJyb2tlbiApO1xyXG5cdFx0fVxyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaW1nTG9hZGVkKCBpbWcsIGlzQnJva2VuICkge1xyXG5cdFx0Ly8gZG9uJ3QgcHJvY2VlZCBpZiBCTEFOSyBpbWFnZSwgb3IgaW1hZ2UgaXMgYWxyZWFkeSBsb2FkZWRcclxuXHRcdGlmICggaW1nLnNyYyA9PT0gQkxBTksgfHwgJC5pbkFycmF5KCBpbWcsIGxvYWRlZCApICE9PSAtMSApIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIHN0b3JlIGVsZW1lbnQgaW4gbG9hZGVkIGltYWdlcyBhcnJheVxyXG5cdFx0bG9hZGVkLnB1c2goIGltZyApO1xyXG5cclxuXHRcdC8vIGtlZXAgdHJhY2sgb2YgYnJva2VuIGFuZCBwcm9wZXJseSBsb2FkZWQgaW1hZ2VzXHJcblx0XHRpZiAoIGlzQnJva2VuICkge1xyXG5cdFx0XHRicm9rZW4ucHVzaCggaW1nICk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRwcm9wZXIucHVzaCggaW1nICk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gY2FjaGUgaW1hZ2UgYW5kIGl0cyBzdGF0ZSBmb3IgZnV0dXJlIGNhbGxzXHJcblx0XHQkLmRhdGEoIGltZywgJ2ltYWdlc0xvYWRlZCcsIHsgaXNCcm9rZW46IGlzQnJva2VuLCBzcmM6IGltZy5zcmMgfSApO1xyXG5cclxuXHRcdC8vIHRyaWdnZXIgZGVmZXJyZWQgcHJvZ3Jlc3MgbWV0aG9kIGlmIHByZXNlbnRcclxuXHRcdGlmICggaGFzTm90aWZ5ICkge1xyXG5cdFx0XHRkZWZlcnJlZC5ub3RpZnlXaXRoKCAkKGltZyksIFsgaXNCcm9rZW4sICRpbWFnZXMsICQocHJvcGVyKSwgJChicm9rZW4pIF0gKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBjYWxsIGRvbmVMb2FkaW5nIGFuZCBjbGVhbiBsaXN0ZW5lcnMgaWYgYWxsIGltYWdlcyBhcmUgbG9hZGVkXHJcblx0XHRpZiAoICRpbWFnZXMubGVuZ3RoID09PSBsb2FkZWQubGVuZ3RoICl7XHJcblx0XHRcdHNldFRpbWVvdXQoIGRvbmVMb2FkaW5nICk7XHJcblx0XHRcdCRpbWFnZXMudW5iaW5kKCAnLmltYWdlc0xvYWRlZCcgKTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8vIGlmIG5vIGltYWdlcywgdHJpZ2dlciBpbW1lZGlhdGVseVxyXG5cdGlmICggISRpbWFnZXMubGVuZ3RoICkge1xyXG5cdFx0ZG9uZUxvYWRpbmcoKTtcclxuXHR9IGVsc2Uge1xyXG5cdFx0JGltYWdlcy5iaW5kKCAnbG9hZC5pbWFnZXNMb2FkZWQgZXJyb3IuaW1hZ2VzTG9hZGVkJywgZnVuY3Rpb24oIGV2ZW50ICl7XHJcblx0XHRcdC8vIHRyaWdnZXIgaW1nTG9hZGVkXHJcblx0XHRcdGltZ0xvYWRlZCggZXZlbnQudGFyZ2V0LCBldmVudC50eXBlID09PSAnZXJyb3InICk7XHJcblx0XHR9KS5lYWNoKCBmdW5jdGlvbiggaSwgZWwgKSB7XHJcblx0XHRcdHZhciBzcmMgPSBlbC5zcmM7XHJcblxyXG5cdFx0XHQvLyBmaW5kIG91dCBpZiB0aGlzIGltYWdlIGhhcyBiZWVuIGFscmVhZHkgY2hlY2tlZCBmb3Igc3RhdHVzXHJcblx0XHRcdC8vIGlmIGl0IHdhcywgYW5kIHNyYyBoYXMgbm90IGNoYW5nZWQsIGNhbGwgaW1nTG9hZGVkIG9uIGl0XHJcblx0XHRcdHZhciBjYWNoZWQgPSAkLmRhdGEoIGVsLCAnaW1hZ2VzTG9h
3155ZGVkJyApO1xyXG5cdFx0XHRpZiAoIGNhY2hlZCAmJiBjYWNoZWQuc3JjID09PSBzcmMgKSB7XHJcblx0XHRcdFx0aW1nTG9hZGVkKCBlbCwgY2FjaGVkLmlzQnJva2VuICk7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBpZiBjb21wbGV0ZSBpcyB0cnVlIGFuZCBicm93c2VyIHN1cHBvcnRzIG5hdHVyYWwgc2l6ZXMsIHRyeVxyXG5cdFx0XHQvLyB0byBjaGVjayBmb3IgaW1hZ2Ugc3RhdHVzIG1hbnVhbGx5XHJcblx0XHRcdGlmICggZWwuY29tcGxldGUgJiYgZWwubmF0dXJhbFdpZHRoICE9PSB1bmRlZmluZWQgKSB7XHJcblx0XHRcdFx0aW1nTG9hZGVkKCBlbCwgZWwubmF0dXJhbFdpZHRoID09PSAwIHx8IGVsLm5hdHVyYWxIZWlnaHQgPT09IDAgKTtcclxuXHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGNhY2hlZCBpbWFnZXMgZG9uJ3QgZmlyZSBsb2FkIHNvbWV0aW1lcywgc28gd2UgcmVzZXQgc3JjLCBidXQgb25seSB3aGVuXHJcblx0XHRcdC8vIGRlYWxpbmcgd2l0aCBJRSwgb3IgaW1hZ2UgaXMgY29tcGxldGUgKGxvYWRlZCkgYW5kIGZhaWxlZCBtYW51YWwgY2hlY2tcclxuXHRcdFx0Ly8gd2Via2l0IGhhY2sgZnJvbSBodHRwOi8vZ3JvdXBzLmdvb2dsZS5jb20vZ3JvdXAvanF1ZXJ5LWRldi9icm93c2VfdGhyZWFkL3RocmVhZC9lZWU2YWI3YjJkYTUwZTFmXHJcblx0XHRcdGlmICggZWwucmVhZHlTdGF0ZSB8fCBlbC5jb21wbGV0ZSApIHtcclxuXHRcdFx0XHRlbC5zcmMgPSBCTEFOSztcclxuXHRcdFx0XHRlbC5zcmMgPSBzcmM7XHJcblx0XHRcdH1cclxuXHRcdH0pO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIGRlZmVycmVkID8gZGVmZXJyZWQucHJvbWlzZSggJHRoaXMgKSA6ICR0aGlzO1xyXG59OyIsIi8qanNoaW50IGJyb3dzZXI6dHJ1ZSAqL1xyXG4vKiFcclxuKiBGaXRWaWRzIDEuMVxyXG4qXHJcbiogQ29weXJpZ2h0IDIwMTMsIENocmlzIENveWllciAtIGh0dHA6Ly9jc3MtdHJpY2tzLmNvbSArIERhdmUgUnVwZXJ0IC0gaHR0cDovL2RhdmVydXBlcnQuY29tXHJcbiogQ3JlZGl0IHRvIFRoaWVycnkgS29ibGVudHogLSBodHRwOi8vd3d3LmFsaXN0YXBhcnQuY29tL2FydGljbGVzL2NyZWF0aW5nLWludHJpbnNpYy1yYXRpb3MtZm9yLXZpZGVvL1xyXG4qIFJlbGVhc2VkIHVuZGVyIHRoZSBXVEZQTCBsaWNlbnNlIC0gaHR0cDovL3NhbS56b3kub3JnL3d0ZnBsL1xyXG4qXHJcbiovXHJcblxyXG47KGZ1bmN0aW9uKCAkICl7XHJcblxyXG4gICd1c2Ugc3RyaWN0JztcclxuXHJcbiAgJC5mbi5maXRWaWRzID0gZnVuY3Rpb24oIG9wdGlvbnMgKSB7XHJcbiAgICB2YXIgc2V0dGluZ3MgPSB7XHJcbiAgICAgIGN1c3RvbVNlbGVjdG9yOiBudWxsLFxyXG4gICAgICBpZ25vcmU6IG51bGxcclxuICAgIH07XHJcblxyXG4gICAgaWYoIWRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdmaXQtdmlkcy1zdHlsZScpKSB7XHJcbiAgICAgIC8vIGFwcGVuZFN0eWxlczogaHR0cHM6Ly9naXRodWIuY29tL3RvZGRtb3R0by9mbHVpZHZpZHMvYmxvYi9tYXN0ZXIvZGlzdC9mbHVpZHZpZHMuanNcclxuICAgICAgdmFyIGhlYWQgPSBkb2N1bWVudC5oZWFkIHx8IGRvY3VtZW50LmdldEVsZW1lbnRzQnlUYWdOYW1lKCdoZWFkJylbMF07XHJcbiAgICAgIHZhciBjc3MgPSAnLmZsdWlkLXdpZHRoLXZpZGVvLXdyYXBwZXJ7d2lkdGg6MTAwJTtwb3NpdGlvbjpyZWxhdGl2ZTtwYWRkaW5nOjA7fS5mbHVpZC13aWR0aC12aWRlby13cmFwcGVyIGlmcmFtZSwuZmx1aWQtd2lkdGgtdmlkZW8td3JhcHBlciBvYmplY3QsLmZsdWlkLXdpZHRoLXZpZGVvLXdyYXBwZXIgZW1iZWQge3Bvc2l0aW9uOmFic29sdXRlO3RvcDowO2xlZnQ6MDt3aWR0aDoxMDAlO2hlaWdodDoxMDAlO30nO1xyXG4gICAgICB2Y
3155XIgZGl2ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcclxuICAgICAgZGl2LmlubmVySFRNTCA9ICc8cD54PC9wPjxzdHlsZSBpZD1cImZpdC12aWRzLXN0eWxlXCI+JyArIGNzcyArICc8L3N0eWxlPic7XHJcbiAgICAgIGhlYWQuYXBwZW5kQ2hpbGQoZGl2LmNoaWxkTm9kZXNbMV0pO1xyXG4gICAgfVxyXG5cclxuICAgIGlmICggb3B0aW9ucyApIHtcclxuICAgICAgJC5leHRlbmQoIHNldHRpbmdzLCBvcHRpb25zICk7XHJcbiAgICB9XHJcblxyXG4gICAgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbigpe1xyXG4gICAgICB2YXIgc2VsZWN0b3JzID0gW1xyXG4gICAgICAgICdpZnJhbWVbc3JjKj1cInBsYXllci52aW1lby5jb21cIl0nLFxyXG4gICAgICAgICdpZnJhbWVbc3JjKj1cInlvdXR1YmUuY29tXCJdJyxcclxuICAgICAgICAnaWZyYW1lW3NyYyo9XCJ5b3V0dWJlLW5vY29va2llLmNvbVwiXScsXHJcbiAgICAgICAgJ2lmcmFtZVtzcmMqPVwia2lja3N0YXJ0ZXIuY29tXCJdW3NyYyo9XCJ2aWRlby5odG1sXCJdJyxcclxuICAgICAgICAnb2JqZWN0JyxcclxuICAgICAgICAnZW1iZWQnXHJcbiAgICAgIF07XHJcblxyXG4gICAgICBpZiAoc2V0dGluZ3MuY3VzdG9tU2VsZWN0b3IpIHtcclxuICAgICAgICBzZWxlY3RvcnMucHVzaChzZXR0aW5ncy5jdXN0b21TZWxlY3Rvcik7XHJcbiAgICAgIH1cclxuXHJcbiAgICAgIHZhciBpZ25vcmVMaXN0ID0gJy5maXR2aWRzaWdub3JlJztcclxuXHJcbiAgICAgIGlmKHNldHRpbmdzLmlnbm9yZSkge1xyXG4gICAgICAgIGlnbm9yZUxpc3QgPSBpZ25vcmVMaXN0ICsgJywgJyArIHNldHRpbmdzLmlnbm9yZTtcclxuICAgICAgfVxyXG5cclxuICAgICAgdmFyICRhbGxWaWRlb3MgPSAkKHRoaXMpLmZpbmQoc2VsZWN0b3JzLmpvaW4oJywnKSk7XHJcbiAgICAgICRhbGxWaWRlb3MgPSAkYWxsVmlkZW9zLm5vdCgnb2JqZWN0IG9iamVjdCcpOyAvLyBTd2ZPYmogY29uZmxpY3QgcGF0Y2hcclxuICAgICAgJGFsbFZpZGVvcyA9ICRhbGxWaWRlb3Mubm90KGlnbm9yZUxpc3QpOyAvLyBEaXNhYmxlIEZpdFZpZHMgb24gdGhpcyB2aWRlby5cclxuXHJcbiAgICAgICRhbGxWaWRlb3MuZWFjaChmdW5jdGlvbigpe1xyXG4gICAgICAgIHZhciAkdGhpcyA9ICQodGhpcyk7XHJcbiAgICAgICAgaWYoJHRoaXMucGFyZW50cyhpZ25vcmVMaXN0KS5sZW5ndGggPiAwKSB7XHJcbiAgICAgICAgICByZXR1cm47IC8vIERpc2FibGUgRml0VmlkcyBvbiB0aGlzIHZpZGVvLlxyXG4gICAgICAgIH1cclxuICAgICAgICBpZiAodGhpcy50YWdOYW1lLnRvTG93ZXJDYXNlKCkgPT09ICdlbWJlZCcgJiYgJHRoaXMucGFyZW50KCdvYmplY3QnKS5sZW5ndGggfHwgJHRoaXMucGFyZW50KCcuZmx1aWQtd2lkdGgtdmlkZW8td3JhcHBlcicpLmxlbmd0aCkgeyByZXR1cm47IH1cclxuICAgICAgICBpZiAoKCEkdGhpcy5jc3MoJ2hlaWdodCcpICYmICEkdGhpcy5jc3MoJ3dpZHRoJykpICYmIChpc05hTigkdGhpcy5hdHRyKCdoZWlnaHQnKSkgfHwgaXNOYU4oJHRoaXMuYXR0cignd2lkdGgnKSkpKVxyXG4gICAgICAgIHtcclxuICAgICAgICAgICR0aGlzLmF0dHIoJ2hlaWdodCcsIDkpO1xyXG4gICAgICAgICAgJHRoaXMuYXR0cignd2lkdGgnLCAxNik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIHZhciBoZWlnaHQgPSAoIHRoaXMudGFnTmFtZS50b0xvd2VyQ2FzZSgpID09PSAnb2JqZWN0JyB8fCAoJHRoaXMuYXR0cignaGVpZ2h0JykgJiYgIWlzTmFOKHBhcnNlSW50KCR0aGlzLmF0dHIoJ2hlaWdodCcpLCAxMCkpKSApID8gcGFyc2VJbnQoJHRoaXMuYXR0cignaGVpZ2h0JyksIDEwKSA6ICR0aGlzLmhlaWdodCgpLFxyXG4gICAgICAgICAgICB3aWR0aCA9ICFpc05hTihwYXJzZUludCgk
3155dGhpcy5hdHRyKCd3aWR0aCcpLCAxMCkpID8gcGFyc2VJbnQoJHRoaXMuYXR0cignd2lkdGgnKSwgMTApIDogJHRoaXMud2lkdGgoKSxcclxuICAgICAgICAgICAgYXNwZWN0UmF0aW8gPSBoZWlnaHQgLyB3aWR0aDtcclxuICAgICAgICBpZighJHRoaXMuYXR0cignbmFtZScpKXtcclxuICAgICAgICAgIHZhciB2aWRlb05hbWUgPSAnZml0dmlkJyArICQuZm4uZml0Vmlkcy5fY291bnQ7XHJcbiAgICAgICAgICAkdGhpcy5hdHRyKCduYW1lJywgdmlkZW9OYW1lKTtcclxuICAgICAgICAgICQuZm4uZml0Vmlkcy5fY291bnQrKztcclxuICAgICAgICB9XHJcbiAgICAgICAgJHRoaXMud3JhcCgnPGRpdiBjbGFzcz1cImZsdWlkLXdpZHRoLXZpZGVvLXdyYXBwZXJcIj48L2Rpdj4nKS5wYXJlbnQoJy5mbHVpZC13aWR0aC12aWRlby13cmFwcGVyJykuY3NzKCdwYWRkaW5nLXRvcCcsIChhc3BlY3RSYXRpbyAqIDEwMCkrJyUnKTtcclxuICAgICAgICAkdGhpcy5yZW1vdmVBdHRyKCdoZWlnaHQnKS5yZW1vdmVBdHRyKCd3aWR0aCcpO1xyXG4gICAgICB9KTtcclxuICAgIH0pO1xyXG4gIH07XHJcbiAgXHJcbiAgLy8gSW50ZXJuYWwgY291bnRlciBmb3IgdW5pcXVlIHZpZGVvIG5hbWVzLlxyXG4gICQuZm4uZml0Vmlkcy5fY291bnQgPSAwO1xyXG4gIFxyXG4vLyBXb3JrcyB3aXRoIGVpdGhlciBqUXVlcnkgb3IgWmVwdG9cclxufSkoIHdpbmRvdy5qUXVlcnkgfHwgd2luZG93LlplcHRvICk7XHJcbiIsIi8qIVxyXG4gKiBqUXVlcnkgTGF6eSAtIHYxLjYuNVxyXG4gKiBodHRwOi8vanF1ZXJ5LmVpc2JlaHIuZGUvbGF6eS9cclxuICpcclxuICogQ29weXJpZ2h0IDIwMTIgLSAyMDE2LCBEYW5pZWwgJ0Vpc2JlaHInIEtlcm5cclxuICpcclxuICogRHVhbCBsaWNlbnNlZCB1bmRlciB0aGUgTUlUIGFuZCBHUEwtMi4wIGxpY2Vuc2VzOlxyXG4gKiBodHRwOi8vd3d3Lm9wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL21pdC1saWNlbnNlLnBocFxyXG4gKiBodHRwOi8vd3d3LmdudS5vcmcvbGljZW5zZXMvZ3BsLTIuMC5odG1sXHJcbiAqXHJcbiAqICQoXCJpbWcubGF6eVwiKS5sYXp5KCk7XHJcbiAqL1xyXG5cclxuOyhmdW5jdGlvbigkLCB3aW5kb3csIGRvY3VtZW50LCB1bmRlZmluZWQpXHJcbntcclxuICAgIFwidXNlIHN0cmljdFwiO1xyXG5cclxuICAgIC8vIG1ha2UgbGF6eSBhIGJpdCBtb3JlIGNhc2UtaW5zZW5zaXRpdmUgOilcclxuICAgICQuZm4uTGF6eSA9ICQuZm4ubGF6eSA9IGZ1bmN0aW9uKHNldH
3155RpbmdzKVxyXG4gICAge1xyXG4gICAgICAgIHJldHVybiBuZXcgTGF6eVBsdWdpbih0aGlzLCBzZXR0aW5ncyk7XHJcbiAgICB9O1xyXG5cclxuICAgIC8qKlxyXG4gICAgICogY29udGFpbnMgYWxsIGxvZ2ljIGFuZCB0aGUgd2hvbGUgZWxlbWVudCBoYW5kbGluZ1xyXG4gICAgICogaXMgcGFja2VkIGluIGEgcHJpdmF0ZSBmdW5jdGlvbiBvdXRzaWRlIGNsYXNzIHRvIHJlZHVjZSBtZW1vcnkgdXNhZ2UsIGJlY2F1c2UgaXQgd2lsbCBub3QgYmUgY3JlYXRlZCBvbiBldmVyeSBwbHVnaW4gaW5zdGFuY2VcclxuICAgICAqIEBhY2Nlc3MgcHJpdmF0ZVxyXG4gICAgICogQHR5cGUge2Z1bmN0aW9ufVxyXG4gICAgICogQHBhcmFtIHtMYXp5UGx1Z2lufSBpbnN0YW5jZVxyXG4gICAgICogQHBhcmFtIHtmdW5jdGlvbn0gY29uZmlndXJhdGlvblxyXG4gICAgICogQHBhcmFtIHtvYmplY3R9IGl0ZW1zXHJcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gZXZlbnRzXHJcbiAgICAgKiBAcmV0dXJuIHZvaWRcclxuICAgICAqL1xyXG4gICAgZnVuY3Rpb24gX2V4ZWN1dGVMYXp5KGluc3RhbmNlLCBjb25maWd1cmF0aW9uLCBpdGVtcywgZXZlbnRzKVxyXG4gICAge1xyXG4gICAgICAgIC8qKlxyXG4gICAgICAgICAqIGEgaGVscGVyIHRvIHRyaWdnZXIgdGhlICdvbkZpbmlzaGVkQWxsJyBjYWxsYmFjayBhZnRlciBhbGwgb3RoZXIgZXZlbnRzXHJcbiAgICAgICAgICogQGFjY2VzcyBwcml2YXRlXHJcbiAgICAgICAgICogQHR5cGUge251bWJlcn1cclxuICAgICAgICAgKi9cclxuICAgICAgICB2Y
3155XIgX2F3YWl0aW5nQWZ0ZXJMb2FkID0gMCxcclxuXHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogdmlzaWJsZSBjb250ZW50IHdpZHRoXHJcbiAgICAgICAgICogQGFjY2VzcyBwcml2YXRlXHJcbiAgICAgICAgICogQHR5cGUge251bWJlcn1cclxuICAgICAgICAgKi9cclxuICAgICAgICBfYWN0dWFsV2lkdGggPSAtMSxcclxuXHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogdmlzaWJsZSBjb250ZW50IGhlaWdodFxyXG4gICAgICAgICAqIEBhY2Nlc3MgcHJpdmF0ZVxyXG4gICAgICAgICAqIEB0eXBlIHtudW1iZXJ9XHJcbiAgICAgICAgICovXHJcbiAgICAgICAgX2FjdHVhbEhlaWdodCA9IC0xLFxyXG5cclxuICAgICAgICAvKipcclxuICAgICAgICAgKiBkZXRlcm1pbmUgcG9zc2libGUgZGV0ZWN0ZWQgaGlnaCBwaXhlbCBkZW5zaXR5XHJcbiAgICAgICAgICogQGFjY2VzcyBwcml2YXRlXHJcbiAgICAgICAgICogQHR5cGUge2Jvb2xlYW59XHJcbiAgICAgICAgICovXHJcbiAgICAgICAgX2lzUmV0aW5hRGlzcGxheSA9IGZhbHNlO1xyXG5cclxuICAgICAgICAvKipcclxuICAgICAgICAgKiBpbml0aWFsaXplIHBsdWdpblxyXG4gICAgICAgICAqIGJpbmQgbG9hZGluZyB0byBldmVudHMgb3Igc2V0IGRlbGF5IHRpbWUgdG8gbG9hZCBhbGwgaXRlbXMgYXQgb25jZVxyXG4gICAgICAgICAqIEBhY2Nlc3MgcHJpdmF0ZVxyXG4gICAgICAgICAqIEByZXR1cm4gdm9pZFxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIGZ1bmN0aW9uIF9pbml0aWFsaXplKClcclxuICAgICAgICB7XHJcbiAgICAgICAgICAgIC8vIGRldGVjdCBhY3R1YWwgZGV2aWNlIHBpeGVsIHJhdGlvXHJcbiAgICAgICAgICAgIC8vIG5vaW5zcGVjdGlvbiBKU1VucmVzb2x2ZWRWYXJpYWJsZVxyXG4gICAgICAgICAgICBfaXNSZXRpbmFEaXNwbGF5ID0gd2luZG93LmRldmljZVBpeGVsUmF0aW8gPiAxO1xyXG5cclxuICAgICAgICAgICAgLy8gcHJlcGFyZSBhbGwgaW5pdGlhbCBpdGVtc1xyXG4gICAgICAgICAgICBfcHJlcGFyZUl0ZW1zKGl0ZW1zKTtcclxuXHJcbiAgICAgICAgICAgIC8vIGlmIGRlbGF5IHRpbWUgaXMgc2V0IGxvYWQgYWxsIGl0ZW1zIGF0IG9uY2UgYWZ0ZXIgZGVsYXkgdGltZVxyXG4gICAgICAgICAgICBpZiggY29uZmlndXJhdGlvbihcImRlbGF5XCIpID49IDAgKSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkgeyBfbGF6eUxvYWRJdGVtcyh0cnVlKTsgfSwgY29uZmlndXJhdGlvbihcImRlbGF5XCIpKTtcclxuXHJcbiAgICAgICAgICAgIC8vIGlmIG5vIGRlbGF5IGlzIHNldCBvciBjb21iaW5lIHVzYWdlIGlzIGFjdGl2ZSBiaW5kIGV2ZW50c1xyXG4gICAgICAgICAgICBpZiggY29uZmlndXJhdGlvbihcImRlbGF5XCIpIDwgMCB8fCBjb25maWd1cmF0aW9uKFwiY29tYmluZWRcIikgKVxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAvLyBjcmVhdGUgdW5pcXVlIGV2ZW50IGZ1bmN0aW9uXHJcbiAgICAgICAgICAgICAgICBldmVudHMuZSA9IF90aHJvdHRsZShjb25maWd1cmF0aW9uKFwidGhyb3R0bGVcIiksIGZ1bmN0aW9uKGV2ZW50KVxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIHJlc2V0IGRldGVjdGVkIHdpbmRvdyBzaXplIG9uIHJlc2l6ZSBldmVudFxyXG4gICAgICAgICAgICAgICAgICAgIGlmKCBldmVudC50eXBlID09PSBcInJlc2l6ZVwiIClcclxuICAgICAgICAgICAgICAgICAgICAgICAgX2FjdHVhbFdpZHRoID0gX2FjdHVhbEhlaWdodCA9IC0xO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBleGVjdXRlICdsYXp5IG1hZ2ljJ1xyXG4gICAgICAgICAgICAgICAgICAgIF9sYXp5TG9hZEl0ZW1zKGV2ZW50LmFsbCk7XHJcbiAgICAgICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBjcmVhdGUgZnVuY3Rpb24gdG8gYWRkIG5ldyBpdGVtcyB0byBpbnN0YW5jZVxyXG4gICAgICAgICAgICAgICAgZXZlbnRzLmEgPSBmdW5jdGlvbihhZGRpdGlvbmFsSXRlbXMpXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgICAgX3ByZXBhcmVJdGVtcyhhZGRpdGlvbmFsSXRlbXMpO1xyXG4gICAgICAgICAgICAgICAgICAgIGl0ZW1zLnB1c2guYXBwbHkoaXRlbXMsIGFkZGl0aW9uYWxJdGVtcyk7XHJcbiAgICAgICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIGNyZWF0ZSBmdW5jdGlvbiB0byBnZXQgYWxsIGluc3RhbmNlIGl0ZW1zIGxlZnRcclxuICAgICAgICAgICAgICAgIGV2ZW50cy5nID0gZnVuY3Rpb24oKVxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBpdGVtcztcclxuICAgICAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gbG9hZCBpbml0aWFsIGl0ZW1zXHJcbiAgICAgICAgICAgICAgICBfbGF6eUxvYWRJdGVtcygpO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIGJpbmQgbGF6eSBsb2FkIGZ1bmN0aW9ucyB0byBzY3JvbGwgYW5kIHJlc2l6ZSBldmVudFxyXG4gICAgICAgICAgICAgICAgJChjb25maWd1cmF0aW9uKFwiYXBwZW5kU2Nyb2xsXCIpKS5vbihcInNjcm9sbC5cIiArIGluc3RhbmNlLm5hbWUgKyBcIiByZXNpemUuXCIgKyBpbnN0YW5jZS5uYW1lLCBldmVudHMuZSk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8qKlxyXG4gICAgICAgICAqIHByZXBhcmUgaXRlbXMgYmVmb3JlIGhhbmRsZSB0aGVtXHJcbiAgICAgICAgICogQGFjY2VzcyBwcml2YXRlXHJcbiAgICAgICAgICogQHBhcmFtIHtBcnJheXxvYmplY3R8alF1ZXJ5fSBpdGVtc1xyXG4gICAgICAgICAqIEByZXR1cm4gdm9pZFxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIGZ1bmN0aW9uIF9wcmVwYXJlSXRlbXMoaXRlbXMpXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgICAvLyBmaWx0ZXIgaXRlbXMgYW5kIG9ubHkgYWRkIHRob3NlIHdobyBub3QgaGFuZGxlZCB5ZXQgYW5kIGdvdCBuZWVkZWQgYXR0cmlidXRlcyBhdmFpbGFibGVcclxuICAgICAgICAgICAgaXRlbXMgPSAkKGl0ZW1zKS5maWx0ZXIoZnVuY3Rpb24oKVxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm4gISQodGhpcykuZGF0YShjb25maWd1cmF0aW9uKFwiaGFuZGxlZE5hbWVcIikpICYmICgkKHRoaXMpLmF0dHIoY29uZmlndXJhdGlvbihcImF0dHJpYnV0ZVwiKSkgfHwgJCh0aGlzKS5hdHRyKGNvbmZpZ3VyYXRpb24oXCJsb2FkZXJBdHRyaWJ1dGVcIikpKTtcclxuICAgICAgICAgICAgfSlcclxuXHJcbiAgICAgICAgICAgIC8vIGFwcGVuZCBwbHVnaW4gaW5zdGFuY2UgdG8gYWxsIGVsZW1lbnRzXHJcbiAgICAgICAgICAgIC5kYXRhKFwicGx1Z2luX1wiICsgaW5zdGFuY2UubmFtZSwgaW5zdGFuY2UpO1xyXG5cclxuICAgICAgICAgICAgLy8gc2V0IGRlZmF1bHQgaW1hZ2UgYW5kL29yIHBsYWNlaG9sZG
3155VyIHRvIGVsZW1lbnRzIGlmIGNvbmZpZ3VyZWRcclxuICAgICAgICAgICAgaWYoIGNvbmZpZ3VyYXRpb24oXCJkZWZhdWx0SW1hZ2VcIikgfHwgY29uZmlndXJhdGlvbihcInBsYWNlaG9sZGVyXCIpIClcclxuICAgICAgICAgICAgICAgIGZvciggdmFyIGkgPSAwOyBpIDwgaXRlbXMubGVuZ3RoOyBpKysgKVxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciBlbGVtZW50ID0gJChpdGVtc1tpXSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRhZyA9IGl0ZW1zW2ldLnRhZ05hbWUudG9Mb3dlckNhc2UoKSxcclxuICAgICAgICAgICAgICAgICAgICAgICAgcHJvcGVydHlOYW1lID0gXCJiYWNrZ3JvdW5kLWltYWdlXCI7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIC8vIHNldCBkZWZhdWx0IGltYWdlIG9uIGV2ZXJ5IGVsZW1lbnQgd2l0aG91dCBzb3VyY2VcclxuICAgICAgICAgICAgICAgICAgICBpZiggdGFnID09IFwiaW1nXCIgJiYgY29uZmlndXJhdGlvbihcImRlZmF1bHRJbWFnZVwiKSAmJiAhZWxlbWVudC5hdHRyKFwic3JjXCIpIClcclxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5hdHRyKFwic3JjXCIsIGNvbmZpZ3VyYXRpb24oXCJkZWZhdWx0SW1hZ2VcIikpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBzZXQgcGxhY2Vob2xkZXIgb24gZXZlcnkgZWxlbWVudCB3aXRob3V0IGJhY2tncm91bmQgaW1hZ2VcclxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmKCB0YWcgIT0gXCJpbWdcIiAmJiBjb25maWd1cmF0aW9uKFwicGxhY2Vob2xkZXJcIikgJiYgKCFlbGVtZW50LmNzcyhwcm9wZXJ0eU5hbWUpIHx8IGVsZW1lbnQuY3NzKHByb3BlcnR5TmFtZSkgPT0gXCJub25lXCIpIClcclxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5jc3MocHJvcGVydHlOYW1lLCBcInVybChcIiArIGNvbmZpZ3VyYXRpb24oXCJwbGFjZWhvbGRlclwiKSArIFwiKVwiKTtcclxuICAgICAgICAgICAgICAgIH1cclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8qKlxyXG4gICAgICAgICAqIHRoZSAnbGF6eSBtYWdpYycgLSBjaGVjayBhbGwgaXRlbXNcclxuICAgICAgICAgKiBAYWNjZXNzIHByaXZhdGVcclxuICAgICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFthbGxJdGVtc11cclxuICAgICAgICAgKiBAcmV0dXJuIHZvaWRcclxuICAgICAgICAgKi9cclxuICAgICAgICBmdW5jdGlvbiBfbGF6eUxvYWRJdGVtcyhhbGxJdGVtcylcclxuICAgICAgICB7XHJcbiAgICAgICAgICAgIC8vIHNraXAgaWYgbm8gaXRlbXMgd2hlcmUgbGVmdFxyXG4gICAgICAgICAgICBpZiggIWl0ZW1zLmxlbmd0aCApXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIC8vIGRlc3Ryb3kgaW5zdGFuY2UgaWYgb3B0aW9uIGlzIGVuYWJsZWRcclxuICAgICAgICAgICAgICAgIGlmKCBjb25maWd1cmF0aW9uKFwiYXV0b0Rlc3Ryb3lcIikgKVxyXG4gICAgICAgICAgICAgICAgICAgIC8vIG5vaW5zcGVjdGlvbiBKU1VucmVzb2x2ZWRGdW5jdGlvblxyXG4gICAgICAgICAgICAgICAgICAgIGluc3RhbmNlLmRlc3Ryb3koKTtcclxuXHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIGhlbHBlciB0byBzZWUgaWYgc29tZXRoaW5nIHdhcyBjaGFuZ2VkXHJcbiAgICAgICAgICAgIHZhciBsb2FkVHJpZ2dlcmVkID0gZmFsc2UsXHJcblxyXG4gICAgICAgICAgICAvLyBnZXQgaW1hZ2UgYmFzZSBvbmNlLCBub3Qgb24gZXZlcnkgaW1hZ2UgbG9vcFxyXG4gICAgICAgICAgICBpbWFnZUJhc2UgPSBjb25maWd1cmF0aW9uKFwiaW1hZ2VCYXNlXCIpID8gY29uZmlndXJhdGlvbihcImltYWdlQmFzZVwiKSA6IFwiXCI7XHJcblxyXG4gICAgICAgICAgICAvLyBsb29wIGFsbCBhdmFpbGFibGUgaXRlbXNcclxuICAgICAgICAgICAgZm9yKCB2YXIgaSA9IDA7IGkgPCBpdGVtcy5sZW5ndGg7IGkrKyApXHJcbiAgICAgICAgICAgICAgICAoZnVuY3Rpb24oaXRlbSlcclxuICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgICAvLyBpdGVtIGlzIGF0IGxlYXN0IGluIGxvYWRhYmxlIGFyZWFcclxuICAgICAgICAgICAgICAgICAgICBpZiggX2lzSW5Mb2FkYWJsZUFyZWEoaXRlbSkgfHwgYWxsSXRlbXMgKVxyXG4gICAgICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGVsZW1lbnQgPSAkKGl0ZW0pLFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGFnID0gaXRlbS50YWdOYW1lLnRvTG93ZXJDYXNlKCksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBhdHRyaWJ1dGUgPSBlbGVtZW50LmF0dHIoY29uZmlndXJhdGlvbihcImF0dHJpYnV0ZVwiKSksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjdXN0b21Mb2FkZXI7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gaXMgbm90IGFscmVhZHkgaGFuZGxlZCBcclxuICAgICAgICAgICAgICAgICAgICAgICAgaWYoICFlbGVtZW50LmRhdGEoY29uZmlndXJhdGlvbihcImhhbmRsZWROYW1lXCIpKSAmJlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gYW5kIGlzIHZpc2libGUgb3IgdmlzaWJpbGl0eSBkb2Vzbid0IG1hdHRlclxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKCFjb25maWd1cmF0aW9uKFwidmlzaWJsZU9ubHlcIikgfHwgZWxlbWVudC5pcyhcIjp2aXNpYmxlXCIpKSAmJiAoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhbmQgaW1hZ2Ugc291cmNlIGF0dHJpYnV0ZSBpcyBhdmFpbGFibGVcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF0dHJpYnV0ZSAmJiAoXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhbmQgaXMgaW1hZ2UgdGFnIHdoZXJlIGF0dHJpYnV0ZSBpcyBub3QgZXF1YWwgc291cmNlXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGFnID09IFwiaW1nXCIgJiYgaW1hZ2VCYXNlICsgYXR0cmlidXRlICE9IGVsZW1lbnQuYXR0cihcInNyY1wiKSkgfHxcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG9yIGlzIG5vbiBpbWFnZSB0YWcgd2hlcmUgYXR0cmlidXRlIGlzIG5vdCBlcXVhbCBiYWNrZ3JvdW5kXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAodGFnICE9IFwiaW1nXCIgJiYgaW1hZ2VCYXNlICsgYXR0cmlidXRlICE9IGVsZW1lbnQuY3NzKFwiYmFja2dyb3VuZC1pbWFnZVwiKSkgKSB8fFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gb3IgY3VzdG9tIGxvYWRlciBpcyBhdmFpbGFibGVcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChjdXN0b21Mb2FkZXIgPSBlbGVtZW50LmF0dHIoY29uZmlndXJhdGlvbihcImxvYWRlckF0dHJpYnV0ZVwiKSkpICkpXHJcbiAgICAgICAgICAgICAgICAgICAgICAgI
3155HtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG1hcmsgZWxlbWVudCBhbHdheXMgYXMgaGFuZGxlZCBhcyB0aGlzIHBvaW50IHRvIHByZXZlbnQgZG91YmxlIGxvYWRpbmdcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvYWRUcmlnZ2VyZWQgPSB0cnVlO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5kYXRhKGNvbmZpZ3VyYXRpb24oXCJoYW5kbGVkTmFtZVwiKSwgdHJ1ZSk7XHJcblxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbG9hZCBpdGVtXHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBfaGFuZGxlSXRlbShlbGVtZW50LCB0YWcsIGltYWdlQmFzZSwgY3VzdG9tTG9hZGVyKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0pKGl0ZW1zW2ldKTtcclxuXHJcbiAgICAgICAgICAgIC8vIHdoZW4gc29tZXRoaW5nIHdhcyBsb2FkZWQgcmVtb3ZlIHRoZW0gZnJvbSByZW1haW5pbmcgaXRlbXNcclxuICAgICAgICAgICAgaWYoIGxvYWRUcmlnZ2VyZWQgKVxyXG4gICAgICAgICAgICAgICAgaXRlbXMgPSAkKGl0ZW1zKS5maWx0ZXIoZnVuY3Rpb24oKVxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAhJCh0aGlzKS5kYXRhKGNvbmZpZ3VyYXRpb24oXCJoYW5kbGVkTmFtZVwiKSk7XHJcbiAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8qKlxyXG4gICAgICAgICAqIGxvYWQgdGhlIGdpdmVuIGVsZW1lbnQgdGhlIGxhenkgd2F5XHJcbiAgICAgICAgICogQGFjY2VzcyBwcml2YXRlXHJcbiAgICAgICAgICogQHBhcmFtIHtvYmplY3R9IGVsZW1lbnRcclxuICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ30gdGFnXHJcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGltYWdlQmFzZVxyXG4gICAgICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IFtjdXN0b21Mb2FkZXJdXHJcbiAgICAgICAgICogQHJldHVybiB2b2lkXHJcbiAgICAgICAgICovXHJcbiAgICAgICAgZnVuY3Rpb24gX2hhbmRsZUl0ZW0oZWxlbWVudCwgdGFnLCBpbWFnZUJhc2UsIGN1c3RvbUxvYWRlcilcclxuICAgICAgICB7XHJcbiAgICAgICAgICAgIC8vIGluY3JlbWVudCBjb3VudCBvZiBpdGVtcyB3YWl0aW5nIGZvciBhZnRlciBsb2FkXHJcbiAgICAgICAgICAgICsrX2F3YWl0aW5nQWZ0ZXJMb2FkO1xyXG5cclxuICAgICAgICAgICAgLy8gZXh0ZW5kZWQgZXJyb3IgY2FsbGJhY2sgZm9yIGNvcnJlY3QgJ29uRmluaXNoZWRBbGwnIGhhbmRsaW5nXHJcbiAgICAgICAgICAgIHZhciBlcnJvckNhbGxiYWNrID0gZnVuY3Rpb24oKVxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICBfdHJpZ2dlckNhbGxiYWNrKFwib25FcnJvclwiLCBlbGVtZW50KTtcclxuICAgICAgICAgICAgICAgIF9yZWR1Y2VBd2FpdGluZygpO1xyXG4gICAgICAgICAgICB9O1xyXG5cclxuICAgICAgICAgICAgLy8gdHJpZ2dlciBmdW5jdGlvbiBiZWZvcmUgbG9hZGluZyBpbWFnZVxyXG4gICAgICAgICAgICBfdHJpZ2dlckNhbGxiYWNrKFwiYmVmb3JlTG9hZFwiLCBlbGVtZW50KTtcclxuXHJcbiAgICAgICAgICAgIC8vIGhhbmRsZSBjdXN0b20gbG9hZGVyXHJcbiAgICAgICAgICAgIGlmKCBjdXN0b21Mb2FkZXIgKVxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAvLyBiaW5kIGVycm9yIGV2ZW50IHRvIHRyaWdnZXIgY2FsbGJhY2sgYW5kIHJlZHVjZSB3YWl0aW5nIGFtb3VudFxyXG4gICAgICAgICAgICAgICAgZWxlbWVudC5vZmYoXCJlcnJvclwiKS5vbmUoXCJlcnJvclwiLCBlcnJvckNhbGxiYWNrKTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBiaW5kIGFmdGVyIGxvYWQgY2FsbGJhY2sgdG8gaW1hZ2VcclxuICAgICAgICAgICAgICAgIGVsZW1lbnQub25lKFwibG9hZFwiLCBmdW5jdGlvbigpXHJcbiAgICAgICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gcmVtb3ZlIGF0dHJpYnV0ZSBmcm9tIGVsZW1lbnRcclxuICAgICAgICAgICAgICAgICAgICBpZiggY29uZmlndXJhdGlvbihcInJlbW92ZUF0dHJpYnV0ZVwiKSApXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW1lbnQucmVtb3ZlQXR0cihjb25maWd1cmF0aW9uKFwibG9hZGVyQXR0cmlidXRlXCIpKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gY2FsbCBhZnRlciBsb2FkIGV2ZW50XHJcbiAgICAgICAgICAgICAgICAgICAgX3RyaWdnZXJDYWxsYmFjayhcImFmdGVyTG9hZFwiLCBlbGVtZW50KTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gcmVtb3ZlIGl0ZW0gZnJvbSB3YWl0aW5nIHF1ZXVlIGFuZCBwb3NzaWJsZSB0cmlnZ2VyIGZpbmlzaGVkIGV2ZW50XHJcbiAgICAgICAgICAgICAgICAgICAgX3JlZHVjZUF3YWl0aW5nKCk7XHJcbiAgICAgICAgICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyB0cmlnZ2VyIGN1c3RvbSBsb2FkZXJcclxuICAgICAgICAgICAgICAgIGlmKCAhX3RyaWdnZXJDYWxsYmFjayhjdXN0b21Mb2FkZXIsIGVsZW1lbnQsIGZ1bmN0aW9uKHJlc3BvbnNlKVxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICAgIGlmKCByZXNwb25zZSApIGVsZW1lbnQubG9hZCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIGVsc2UgZWxlbWVudC5lcnJvcigpO1xyXG4gICAgICAgICAgICAgICAgfSkpIGVsZW1lbnQuZXJyb3IoKTtcclxuICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgLy8gaGFuZGxlIGltYWdlc1xyXG4gICAgICAgICAgICBlbHNlXHJcbiAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgIC8vIGNyZWF0ZSBpbWFnZSBvYmplY3RcclxuICAgICAgICAgICAgICAgIHZhciBpbWFnZU9iaiA9ICQobmV3IEltYWdlKCkpO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIGJpbmQgZXJyb3IgZXZlbnQgdG8gdHJpZ2dlciBjYWxsYmFjayBhbmQgcmVkdWNlIHdhaXRpbmcgYW1vdW50XHJcbiAgICAgICAgICAgICAgICBpbWFnZU9iai5vbmUoXCJlcnJvclwiLCBlcnJvckNhbGxiYWNrKTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBiaW5kIGFmdGVyIGxvYWQgY2FsbGJhY2sgdG8gaW1hZ2VcclxuICAgICAgICAgICAgICAgIGltYWdlT2JqLm9uZShcImxvYWRcIiwgZnVuY3Rpb24oKVxyXG4gICAgICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZSBlbGVtZW50IGZyb20gdmlld1xyXG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnQuaGlkZSgpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBzZXQgaW1hZ2UgYmFjayB0byBlbGVtZW50XHJcbiAgICAgICAgICAgICAgICAgICAgaWYoIHRhZyA9PSBcImltZ1wiICkgZWxlbWVudC5hdHRyKFwic3JjXCIsIGltYWdlT2JqLmF0dHIoXCJzcmNcIikpO1xyXG4gICAgICAgICAgICAgICAgICAgIGVsc2UgZWxlbWVudC5jc3MoXCJiYWNrZ3JvdW5kLWltYWdlXCIsIFwidXJsKFwiICsgaW1hZ2VPYmouYXR0cihcInNyY1wiKSArIFwiKVwiKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gYnJpbmcgaXQgYmFjayB3aXRoIHNvbWUgZWZmZWN0IVxyXG4gICAgICAgICAgICAgICAgICAgIGVsZW1lbnRbY29uZmlndXJhdGlvbihcImVmZmVjdFwiKV0oY29uZmlndXJhdGlvbihcImVmZmVjdFRpbWVcIikpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyByZW1vdmUgYXR0cmlidXRlIGZyb20gZWxlbWVudFxyXG4gICAgICAgICAgICAgICAgICAgIGlmKCBjb25maWd1cmF0aW9uKFwicmVtb3ZlQXR0cmlidXRlXCIpIClcclxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbWVudC5yZW1vdmVBdHRyKGNvbmZpZ3VyYXRpb24oXCJhdHRyaWJ1dGVcIikgKyBcIiBcIiArIGNvbmZpZ3VyYXRpb24oXCJyZXRpbmFBdHRyaWJ1dGVcIikpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBjYWxsIGFmdGVyIGxvYWQgZXZlbnRcclxuICAgICAgICAgICAgICAgICAgICBfdHJpZ2dlckNhbGxiYWNrKFwiYWZ0ZXJMb2FkXCIsIGVsZW1lbnQpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBjbGVhbnVwIGltYWdlIG9iamVjdFxyXG4gICAgICAgICAgICAgICAgICAgIGltYWdlT2JqLnJlbW92ZSgpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyByZW1vdmUgaXRlbSBmcm9tIHdhaXRpbmcgcXVldWUgYW5kIHBvc3NpYmxlIHRyaWdnZXIgZmluaXNoZWQgZXZlbnRcclxuICAgICAgICAgICAgICAgICAgICBfcmVkdWNlQXdhaXRpbmcoKTtcclxuICAgICAgICAgICAgICAgI
3155H0pO1xyXG5cclxuICAgICAgICAgICAgICAgIC8vIHNldCBzb3VyY2VcclxuICAgICAgICAgICAgICAgIGltYWdlT2JqLmF0dHIoXCJzcmNcIiwgaW1hZ2VCYXNlICsgZWxlbWVudC5hdHRyKGNvbmZpZ3VyYXRpb24oX2lzUmV0aW5hRGlzcGxheSAmJiBlbGVtZW50LmF0dHIoY29uZmlndXJhdGlvbihcInJldGluYUF0dHJpYnV0ZVwiKSkgPyBcInJldGluYUF0dHJpYnV0ZVwiIDogXCJhdHRyaWJ1dGVcIikpKTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBjYWxsIGFmdGVyIGxvYWQgZXZlbiBvbiBjYWNoZWQgaW1hZ2VcclxuICAgICAgICAgICAgICAgIGlmKCBpbWFnZU9iai5jb21wbGV0ZSApIGltYWdlT2JqLmxvYWQoKTtcclxuICAgICAgICAgICAgfVxyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogY2hlY2sgaWYgdGhlIGdpdmVuIGVsZW1lbnQgaXMgaW5zaWRlIHRoZSBjdXJyZW50IHZpZXdwb3J0IG9yIHRocmVzaG9sZFxyXG4gICAgICAgICAqIEBhY2Nlc3MgcHJpdmF0ZVxyXG4gICAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBlbGVtZW50XHJcbiAgICAgICAgICogQHJldHVybiB7Ym9vbGVhbn1cclxuICAgICAgICAgKi9cclxuICAgICAgICBmdW5jdGlvbiBfaXNJbkxvYWRhYmxlQXJlYShlbGVtZW50KVxyXG4gICAgICAgIHtcclxuICAgICAgICAgICAgdmFyIGVsZW1lbnRCb3VuZCA9IGVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksXHJcbiAgICAgICAgICAgICAgICBkaXJlY3Rpb24gICAgPSBjb25maWd1cmF0aW9uKFwic2Nyb2xsRGlyZWN0aW9uXCIpLFxyXG4gICAgICAgICAgICAgICAgdGhyZXNob2xkICAgID0gY29uZmlndXJhdGlvbihcInRocmVzaG9sZFwiKSxcclxuICAgICAgICAgICAgICAgIHZlcnRpY2FsICAgICA9IC8vIGNoZWNrIGlmIGVsZW1lbnQgaXMgaW4gbG9hZGFibGUgYXJlYSBmcm9tIHRvcFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKChfZ2V0QWN0dWFsSGVpZ2h0KCkgKyB0aHJlc2hvbGQpID4gZWxlbWVudEJvdW5kLnRvcCkgJiZcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNoZWNrIGlmIGVsZW1lbnQgaXMgZXZlbiBpbiBsb2FkYWJsZSBhcmUgZnJvbSBib3R0b21cclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICgtdGhyZXNob2xkIDwgZWxlbWVudEJvdW5kLmJvdHRvbSksXHJcbiAgICAgICAgICAgICAgICBob3Jpem9udGFsICAgPSAvLyBjaGVjayBpZiBlbGVtZW50IGlzIGluIGxvYWRhYmxlIGFyZWEgZnJvbSBsZWZ0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoKF9nZXRBY3R1YWxXaWR0aCgpICsgdGhyZXNob2xkKSA+IGVsZW1lbnRCb3VuZC5sZWZ0KSAmJlxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gY2hlY2sgaWYgZWxlbWVudCBpcyBldmVuIGluIGxvYWRhYmxlIGFyZWEgZnJvbSByaWdodFxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKC10aHJlc2hvbGQgPCBlbGVtZW50Qm91bmQucmlnaHQpO1xyXG5cclxuICAgICAgICAgICAgaWYoIGRpcmVjdGlvbiA9PSBcInZlcnRpY2FsXCIgKSByZXR1cm4gdmVydGljYWw7XHJcbiAgICAgICAgICAgIGVsc2UgaWYoIGRpcmVjdGlvbiA9PSBcImhvcml6b250YWxcIiApIHJldHVybiBob3Jpem9udGFsO1xyXG5cclxuICAgICAgICAgICAgcmV0dXJuIHZlcnRpY2FsICYmIGhvcml6b250YWw7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvKipcclxuICAgICAgICAgKiByZWNlaXZlIHRoZSBjdXJyZW50IHZpZXdlZCB3aWR0aCBvZiB0aGUgYnJvd3NlclxyXG4gICAgICAgICAqIEBhY2Nlc3MgcHJpdmF0ZVxyXG4gICAgICAgICAqIEByZXR1cm4ge251bWJlcn1cclxuICAgICAgICAgKi9cclxuICAgICAgICBmdW5jdGlvbiBfZ2V0QWN0dWFsV2lkdGgoKVxyXG4gICAgICAgIHtcclxuICAgICAgICAgICAgcmV0dXJuIF9hY3R1YWxXaWR0aCA+PSAwID8gX2FjdHVhbFdpZHRoIDogKF9hY3R1YWxXaWR0aCA9ICQod2luZG93KS53aWR0aCgpKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8qKlxyXG4gICAgICAgICAqIHJlY2VpdmUgdGhlIGN1cnJlbnQgdmlld2VkIGhlaWdodCBvZiB0aGUgYnJvd3NlclxyXG4gICAgICAgICAqIEBhY2Nlc3MgcHJpdmF0ZVxyXG4gICAgICAgICAqIEByZXR1cm4ge251bWJlcn1cclxuICAgICAgICAgKi9cclxuICAgICAgICBmdW5jdGlvbiBfZ2V0QWN0dWFsSGVpZ2h0KClcclxuICAgICAgICB7XHJcbiAgICAgICAgICAgIHJldHVybiBfYWN0dWFsSGVpZ2h0ID49IDAgPyBfYWN0dWFsSGVpZ2h0IDogKF9hY3R1YWxIZWlnaHQgPSAkKHdpbmRvdykuaGVpZ2h0KCkpO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogaGVscGVyIGZ1bmN0aW9uIHRvIHRocm90dGxlIGRvd24gZXZlbnQgdHJpZ2dlcmluZ1xyXG4gICAgICAgICAqIEBhY2Nlc3MgcHJpdmF0ZVxyXG4gICAgICAgICAqIEBwYXJhbSB7bnVtYmVyfSBkZWxheVxyXG4gICAgICAgICAqIEBwYXJhbSB7ZnVuY3Rpb259IGNhbGxiYWNrXHJcbiAgICAgICAgICogQHJldHVybiB7ZnVuY3Rpb259XHJcbiAgICAgICAgICovXHJcbiAgICAgICAgZnVuY3Rpb24gX3Rocm90dGxlKGRlbGF5LCBjYWxsYmFjaylcclxuICAgICAgICB7XHJcbiAgICAgICAgICAgIHZhciB0aW1lb3V0LCBsYXN0RXhlY3V0ZSA9IDA7XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24oZXZlbnQsIGlnbm9yZVRocm90dGxlKVxyXG4gICAgICAgICAgICB7XHJcbiAgICAgICAgICAgICAgICB2Y
3155XIgZWxhcHNlZCA9ICtuZXcgRGF0ZSgpIC0gbGFzdEV4ZWN1dGU7XHJcblxyXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gcnVuKClcclxuICAgICAgICAgICAgICAgIHtcclxuICAgICAgICAgICAgICAgICAgICBsYXN0RXhlY3V0ZSA9ICtuZXcgRGF0ZSgpO1xyXG4gICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrLmNhbGwoaW5zdGFuY2UsIGV2ZW50KTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICB0aW1lb3V0ICYmIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcclxuXHJcbiAgICAgICAgICAgICAgICBpZiggZWxhcHNlZCA+IGRlbGF5IHx8ICFjb25maWd1cmF0aW9uKFwiZW5hYmxlVGhyb3R0bGVcIikgfHwgaWdub3JlVGhyb3R0bGUgKSBydW4oKTtcclxuICAgICAgICAgICAgICAgIGVsc2UgdGltZW91dCA9IHNldFRpbWVvdXQocnVuLCBkZWxheSAtIGVsYXBzZWQpO1xyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogcmVkdWNlIGNvdW50IG9mIGF3YWl0aW5nIGVsZW1lbnRzIHRvICdhZnRlckxvYWQnIGV2ZW50IGFuZCBmaXJlICdvbkZpbmlzaGVkQWxsJyBpZiByZWFjaGVkIHplcm9cclxuICAgICAgICAgKiBAYWNjZXNzIHByaXZhdGVcclxuICAgICAgICAgKiBAcmV0dXJuIHZvaWRcclxuICAgICAgICAgKi9cclxuICAgICAgICBmdW5jdGlvbiBfcmVkdWNlQXdhaXRpbmcoKVxyXG4gICAgICAgIHtcclxuICAgICAgICAgICAgLS1fYXdhaXRpbmdBZnRlckxvYWQ7XHJcblxyXG4gICAgICAgICAgICAvLyBpZiBubyBpdGVtcyB3ZXJlIGxlZnQgdHJpZ2dlciBmaW5pc2hlZCBldmVudFxyXG4gICAgICAgICAgICBpZiggIWl0ZW1zLnNpemUoKSAmJiAhX2F3YWl0aW5nQWZ0ZXJMb2FkICkgX3RyaWdnZXJDYWxsYmFjayhcIm9uRmluaXNoZWRBbGxcIik7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvKipcclxuICAgICAgICAgKiBzaW5nbGUgaW1wbGVtZW50YXRpb24gdG8gaGFuZGxlIGNhbGxiYWNrcywgcGFzcyBlbGVtZW50IGFuZCBzZXQgJ3RoaXMnIHRvIGN1cnJlbnQgaW5zdGFuY2VcclxuICAgICAgICAgKiBAYWNjZXNzIHByaXZhdGVcclxuICAgICAgICAgKiBAcGFyYW0ge3N0cmluZ3xmdW5jdGlvbn0gY2FsbGJhY2tcclxuICAgICAgICAgKiBAcGFyYW0ge29iamVjdH0gW2VsZW1lbnRdXHJcbiAgICAgICAgICogQHBhcmFtIHsqfSBbYXJnc11cclxuICAgICAgICAgKiBAcmV0dXJuIHtib29sZWFufVxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIGZ1bmN0aW9uIF90cmlnZ2VyQ2FsbGJhY2soY2FsbGJhY2ssIGVsZW1lbnQsIGFyZ3MpXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgICBpZiggKGNhbGxiYWNrID0gY29uZmlndXJhdGlvbihjYWxsYmFjaykpIClcclxuICAgICAgICAgICAge1xyXG4gICAgICAgICAgICAgICAgLy8galF1ZXJ5J3MgaW50ZXJuYWwgJyQoYXJndW1lbnRzKS5zbGljZSgxKScgYXJlIGNhdXNpbmcgcHJvYmxlbXMgYXQgbGVhc3Qgb24gb2xkIGlQYWRzXHJcbiAgICAgICAgICAgICAgICAvLyBiZWxvdyBpcyBzaG9ydGhhbmQgb2YgJ0FycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSknXHJcbiAgICAgICAgICAgICAgICBjYWxsYmFjay5hcHBseShpbnN0YW5jZSwgW10uc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpKTtcclxuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xyXG4gICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICAvLyBzZXQgdXAgbGF6eVxyXG4gICAgICAgIChmdW5jdGlvbigpXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgICAvLyBpZiBldmVudCBkcml2ZW4gZG9uJ3Qgd2FpdCBmb3IgcGFnZSBsb2FkaW5nXHJcbiAgICAgICAgICAgIGlmKCBjb25maWd1cmF0aW9uKFwiYmluZFwiKSA9PSBcImV2ZW50XCIgKSBfaW5pdGlhbGl6ZSgpO1xyXG5cclxuICAgICAgICAgICAgLy8gb3RoZXJ3aXNlIGxvYWQgaW5pdGlhbCBpdGVtcyBhbmQgc3RhcnQgbGF6eSBhZnRlciBwYWdlIGxvYWRcclxuICAgICAgICAgICAgZWxzZSAkKHdpbmRvdykubG9hZChfaW5pdGlhbGl6ZSk7XHJcbiAgICAgICAgfSkoKTtcclxuICAgIH1cclxuXHJcbiAgICAvKipcclxuICAgICAqIGxhenkgcGx1Z2luIGNsYXNzIGNvbnN0cnVjdG9yXHJcbiAgICAgKiBAY29uc3RydWN0b3JcclxuICAgICAqIEBhY2Nlc3MgcHJpdmF0ZVxyXG4gICAgICogQHBhcmFtIHtvYmplY3R9IGVsZW1lbnRzXHJcbiAgICAgKiBAcGFyYW0ge29iamVjdH0gc2V0dGluZ3NcclxuICAgICAqIEByZXR1cm4ge29iamVjdHxMYXp5UGx1Z2lufVxyXG4gICAgICovXHJcbiAgICBmdW5jdGlvbiBMYXp5UGx1Z2luKGVsZW1lbnRzLCBzZXR0aW5ncylcclxuICAgIHtcclxuICAgICAgICAvKipcclxuICAgICAgICAgKiB0aGlzIGxhenkgcGx1Z2luIGluc3RhbmNlXHJcbiAgICAgICAgICogQGFjY2VzcyBwcml2YXRlXHJcbiAgICAgICAgICogQHR5cGUge29iamVjdHxMYXp5UGx1Z2lufVxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIHZhciBfaW5zdGFuY2UgPSB0aGlzLFxyXG5cclxuICAgICAgICAvKipcclxuICAgICAgICAgKiB0aGlzIGxhenkgcGx1Z2luIGluc3RhbmNlIGNvbmZpZ3VyYXRpb25cclxuICAgICAgICAgKiBAYWNjZXNzIHByaXZhdGVcclxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIF9jb25maWcgPSAkLmV4dGVuZCh7fSwgX2luc3RhbmNlLmNvbmZpZ3VyYXRpb24sIHNldHRpbmdzKSxcclxuXHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogaW5zdGFuY2UgZ2VuZXJhdGVkIGV2ZW50IGV4ZWN1dGVkIG9uIGNvbnRhaW5lciBzY3JvbGwgb3IgcmVzaXplXHJcbiAgICAgICAgICogcGFja2VkIGluIGFuIG9iamVjdCB0byBiZSByZWZlcmVuY2VhYmxlIGFuZCBzaG9ydCBuYW1lZCBiZWNhdXNlIHByb3BlcnRpZXMgd2lsbCBub3QgYmUgbWluaWZpZWRcclxuICAgICAgICAgKiBAYWNjZXNzIHByaXZhdGVcclxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIF9ldmVudHMgPSB7fTtcclxuXHJcbiAgICAgICAgLy8gbm9pbnNwZWN0aW9uIEpTVW5kZWZpbmVkUHJvcGVydHlBc3NpZ25tZW50XHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogd3JhcHBlciB0byBnZXQgb3Igc2V0IGFuIGVudHJ5IGZyb20gcGx1Z2luIGluc3RhbmNlIGNvbmZpZ3VyYXRpb25cclxuICAgICAgICAgKiBtdWNoIHNtYWxsZXIgb24gbWluaWZ5IGFzIGRpcmVjdCBhY2Nlc3NcclxuICAgICAgICAgKiBAYWNjZXNzIHByaXZhdGVcclxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XHJcbiAgICAgICAgICogQHBhcmFtIHtzdHJpbmd9IGVudHJ5TmFtZVxyXG4gICAgICAgICAqIEBwYXJhbSB7Kn0gW3ZhbHVlXVxyXG4gICAgICAgICAqIEByZXR1cm4ge0xhenlQbHVnaW58Kn1cclxuICAgICAgICAgKi9cclxuICAgICAgICBfaW5zdGFuY2UuY29uZmlnID0gZnVuY3Rpb24oZW50cnlOYW1lLCB2YWx1ZSlcclxuICAgICAgICB7XHJcbiAgICAgICAgICAgIGlmKCB2YWx1ZSA9PT0gdW5kZWZpbmVkIClcclxuICAgICAgICAgICAgICAgI
3155HJldHVybiBfY29uZmlnW2VudHJ5TmFtZV07XHJcbiAgICAgICAgICAgIGVsc2VcclxuICAgICAgICAgICAgICAgIF9jb25maWdbZW50cnlOYW1lXSA9IHZhbHVlO1xyXG5cclxuICAgICAgICAgICAgcmV0dXJuIF9pbnN0YW5jZTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICAvLyBub2luc3BlY3Rpb24gSlNVbmRlZmluZWRQcm9wZXJ0eUFzc2lnbm1lbnRcclxuICAgICAgICAvKipcclxuICAgICAgICAgKiBhZGQgYWRkaXRpb25hbCBpdGVtcyB0byBjdXJyZW50IGluc3RhbmNlXHJcbiAgICAgICAgICogQGFjY2VzcyBwdWJsaWNcclxuICAgICAgICAgKiBAcGFyYW0ge0FycmF5fG9iamVjdHxzdHJpbmd9IGl0ZW1zXHJcbiAgICAgICAgICogQHJldHVybiB7TGF6eVBsdWdpbn1cclxuICAgICAgICAgKi9cclxuICAgICAgICBfaW5zdGFuY2UuYWRkSXRlbXMgPSBmdW5jdGlvbihpdGVtcylcclxuICAgICAgICB7XHJcbiAgICAgICAgICAgIGlmKCBfZXZlbnRzLmEgKVxyXG4gICAgICAgICAgICAgICAgX2V2ZW50cy5hKCQudHlwZShpdGVtcykgPT09IFwic3RyaW5nXCIgPyAkKGl0ZW1zKSA6IGl0ZW1zKTtcclxuXHJcbiAgICAgICAgICAgIHJldHVybiBfaW5zdGFuY2U7XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gbm9pbnNwZWN0aW9uIEpTVW5kZWZpbmVkUHJvcGVydHlBc3NpZ25tZW50XHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogZ2V0IGFsbCBsZWZ0IGl0ZW1zIG9mIHRoaXMgaW5zdGFuY2VcclxuICAgICAgICAgKiBAYWNjZXNzIHB1YmxpY1xyXG4gICAgICAgICAqIEByZXR1cm5zIHtvYmplY3R9XHJcbiAgICAgICAgICovXHJcbiAgICAgICAgX2luc3RhbmNlLmdldEl0ZW1zID0gZnVuY3Rpb24oKVxyXG4gICAgICAgIHtcclxuICAgICAgICAgICAgcmV0dXJuIF9ldmVudHMuZyA/IF9ldmVudHMuZygpIDoge307XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgLy8gbm9pbnNwZWN0aW9uIEpTVW5kZWZpbmVkUHJvcGVydHlBc3NpZ25tZW50XHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogZm9yY2UgbGF6eSB0byBsb2FkIGFsbCBpdGVtcyBpbiBsb2FkYWJsZSBhcmVhIHJpZ2h0IG5vd1xyXG4gICAgICAgICAqIGJ5IGRlZmF1bHQgd2l0aG91dCB0aHJvdHRsZVxyXG4gICAgICAgICAqIEBhY2Nlc3MgcHVibGljXHJcbiAgICAgICAgICogQHR5cGUge2Z1bmN0aW9ufVxyXG4gICAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW3VzZVRocm90dGxlXVxyXG4gICAgICAgICAqIEByZXR1cm4ge0xhenlQbHVnaW59XHJcbiAgICAgICAgICovXHJcbiAgICAgICAgX2luc3RhbmNlLnVwZGF0ZSA9IGZ1bmN0aW9uKHVzZVRocm90dGxlKVxyXG4gICAgICAgIHtcclxuICAgICAgICAgICAgaWYoIF9ldmVudHMuZSApXHJcbiAgICAgICAgICAgICAgICBfZXZlbnRzLmUoe30sICF1c2VUaHJvdHRsZSk7XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gX2luc3RhbmNlO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIC8vIG5vaW5zcGVjdGlvbiBKU1VuZGVmaW5lZFByb3BlcnR5QXNzaWdubWVudFxyXG4gICAgICAgIC8qKlxyXG4gICAgICAgICAqIGZvcmNlIGxhenkgdG8gbG9hZCBhbGwgYXZhaWxhYmxlIGl0ZW1zIHJpZ2h0IG5vd1xyXG4gICAgICAgICAqIHRoaXMgY2FsbCBpZ25vcmVzIHRocm90dGxpbmdcclxuICAgICAgICAgKiBAYWNjZXNzIHB1YmxpY1xyXG4gICAgICAgICAqIEB0eXBlIHtmdW5jdGlvbn1cclxuICAgICAgICAgKiBAcmV0dXJuIHtMYXp5UGx1Z2lufVxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIF9pbnN0YW5jZS5sb2FkQWxsID0gZnVuY3Rpb24oKVxyXG4gICAgICAgIHtcclxuICAgICAgICAgICAgaWYoIF9ldmVudHMuZSApXHJcbiAgICAgICAgICAgICAgICBfZXZlbnRzLmUoe2FsbDogdHJ1ZX0sIHRydWUpO1xyXG5cclxuICAgICAgICAgICAgcmV0dXJuIF9pbnN0YW5jZTtcclxuICAgICAgICB9O1xyXG5cclxuICAgICAgICAvLyBub2luc3BlY3Rpb24gSlNVbmRlZmluZWRQcm9wZXJ0eUFzc2lnbm1lbnRcclxuICAgICAgICAvKipcclxuICAgICAgICAgKiBkZXN0cm95IHRoaXMgcGx1Z2luIGluc3RhbmNlXHJcbiAgICAgICAgICogQGFjY2VzcyBwdWJsaWNcclxuICAgICAgICAgKiBAdHlwZSB7ZnVuY3Rpb259XHJcbiAgICAgICAgICogQHJldHVybiB1bmRlZmluZWRcclxuICAgICAgICAgKi9cclxuICAgICAgICBfaW5zdGFuY2UuZGVzdHJveSA9IGZ1bmN0aW9uICgpXHJcbiAgICAgICAge1xyXG4gICAgICAgICAgICAvLyB1bmJpbmQgaW5zdGFuY2UgZ2VuZXJhdGVkIGV2ZW50c1xyXG4gICAgICAgICAgICAvLyBub2luc3BlY3Rpb24gSlNVbnJlc29sdmVkRnVuY3Rpb25cclxuICAgICAgICAgICAgJChfaW5zdGFuY2UuY29uZmlnKFwiYXBwZW5kU2Nyb2xsXCIpKS5vZmYoXCIuXCIgKyBfaW5zdGFuY2UubmFtZSwgX2V2ZW50cy5lKTtcclxuXHJcbiAgICAgICAgICAgIC8vIGNsZWFyIGV2ZW50c1xyXG4gICAgICAgICAgICBfZXZlbnRzID0ge307XHJcblxyXG4gICAgICAgICAgICByZXR1cm4gdW5kZWZpbmVkO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIC8vIHN0YXJ0IHVzaW5nIGxhenkgYW5kIHJldHVybiBhbGwgZWxlbWVudHMgdG8gYmUgY2hhaW5hYmxlIG9yIGluc3RhbmNlIGZvciBmdXJ0aGVyIHVzZVxyXG4gICAgICAgIC8vIG5vaW5zcGVjdGlvbiBKU1VucmVzb2x2ZWRWYXJpYWJsZVxyXG4gICAgICAgIF9leGVjdXRlTGF6eShfaW5zdGFuY2UsIF9pbnN0YW5jZS5jb25maWcsIGVsZW1lbnRzLCBfZXZlbnRzKTtcclxuICAgICAgICAvLyBub2luc3BlY3Rpb24gSlNVbnJlc29sdmVkRnVuY3Rpb25cclxuICAgICAgICByZXR1cm4gX2luc3RhbmNlLmNvbmZpZyhcImNoYWluYWJsZVwiKSA/IGVsZW1lbnRzIDogX2luc3RhbmNlO1xyXG4gICAgfVxyXG5cclxuICAgIC8vIHVzZSBqcXVlcnkgdG8gZXh0ZW5kIGNsYXNzIHByb3RvdHlwZSB3aXRob3V0IGNvbmZsaWN0c1xyXG4gICAgJC5leHRlbmQoTGF6eVBsdWdpbi5wcm90b3R5cGUsXHJcbiAgICB7XHJcbiAgICAgICAgLyoqXHJcbiAgICAgICAgICogaW50ZXJuYWwgbmFtZSB1c2VkIGZvciBiaW5kaW5ncyBhbmQgbmFtZXNwYWNlc1xyXG4gICAgICAgICAqIEBhY2Nlc3MgcHVibGljXHJcbiAgICAgICAgICogQHZhciB7c3RyaW5nfVxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIG5hbWU6IFwibGF6eVwiLFxyXG5cclxuICAgICAgICAvKipcclxuICAgICAgICAgKiBzZXR0aW5ncyBhbmQgY29uZmlndXJhdGlvbiBkYXRhXHJcbiAgICAgICAgICogQGFjY2VzcyBwdWJsaWNcclxuICAgICAgICAgKiBAdHlwZSB7b2JqZWN0fVxyXG4gICAgICAgICAqL1xyXG4gICAgICAgIGNvbmZpZ3VyYXRpb246XHJcbiAgICAgICAge1xyXG4gICAgICAgICAgICAvLyBnZW5lcmFsXHJcbiAgICAgICAgICAgIGNoYWluYWJsZSAgICAgICA6IHRydWUsXHJcbiAgICAgICAgICAgIGF1dG9EZXN0cm95ICAgICA6IHRydWUsXHJcbiAgICAgICAgICAgIGJpbmQgICAgICAgICAgICA6IFwibG9h
3155ZFwiLFxyXG4gICAgICAgICAgICB0aHJlc2hvbGQgICAgICAgOiA1MDAsXHJcbiAgICAgICAgICAgIHZpc2libGVPbmx5ICAgICA6IGZhbHNlLFxyXG4gICAgICAgICAgICBhcHBlbmRTY3JvbGwgICAgOiB3aW5kb3csXHJcbiAgICAgICAgICAgIHNjcm9sbERpcmVjdGlvbiA6IFwiYm90aFwiLFxyXG4gICAgICAgICAgICBpbWFnZUJhc2UgICAgICAgOiBudWxsLFxyXG4gICAgICAgICAgICBkZWZhdWx0SW1hZ2UgICAgOiBcImRhdGE6aW1hZ2UvZ2lmO2Jhc2U2NCxSMGxHT0RsaEFRQUJBSUFBQVAvLy93QUFBQ0g1QkFFQUFBQUFMQUFBQUFBQkFBRUFBQUlDUkFFQU93PT1cIixcclxuICAgICAgICAgICAgcGxhY2Vob2xkZXIgICAgIDogbnVsbCxcclxuICAgICAgICAgICAgZGVsYXkgICAgICAgICAgIDogLTEsXHJcbiAgICAgICAgICAgIGNvbWJpbmVkICAgICAgICA6IGZhbHNlLFxyXG5cclxuICAgICAgICAgICAgLy8gYXR0cmlidXRlc1xyXG4gICAgICAgICAgICBhdHRyaWJ1dGUgICAgICAgOiBcImRhdGEtc3JjXCIsXHJcbiAgICAgICAgICAgIHJldGluYUF0dHJpYnV0ZSA6IFwiZGF0YS1yZXRpbmFcIixcclxuICAgICAgICAgICAgbG9hZGVyQXR0cmlidXRlIDogXCJkYXRhLWxvYWRlclwiLFxyXG4gICAgICAgICAgICByZW1vdmVBdHRyaWJ1dGUgOiB0cnVlLFxyXG4gICAgICAgICAgICBoYW5kbGVkTmFtZSAgICAgOiBcImhhbmRsZWRcIixcclxuXHJcbiAgICAgICAgICAgIC8vIGVmZmVjdFxyXG4gICAgICAgICAgICBlZmZlY3QgICAgICAgICAgOiBcInNob3dcIixcclxuICAgICAgICAgICAgZWZmZWN0VGltZSAgICAgIDogMCxcclxuXHJcbiAgICAgICAgICAgIC8vIHRocm90dGxlXHJcbiAgICAgICAgICAgIGVuYWJsZVRocm90dGxlICA6IHRydWUsXHJcbiAgICAgICAgICAgIHRocm90dGxlICAgICAgICA6IDI1MCxcclxuXHJcbiAgICAgICAgICAgIC8vIGNhbGxiYWNrc1xyXG4gICAgICAgICAgICBiZWZvcmVMb2FkICAgICAgOiBudWxsLFxyXG4gICAgICAgICAgICBhZnRlckxvYWQgICAgICAgOiBudWxsLFxyXG4gICAgICAgICAgICBvbkVycm9yICAgICAgICAgOiBudWxsLFxyXG4gICAgICAgICAgICBvbkZpbmlzaGVkQWxsICAgOiBudWxsXHJcbiAgICAgICAgfVxyXG4gICAgfSk7XHJcbn0pKGpRdWVyeSwgd2luZG93LCBkb2N1bWVudCk7IiwiLyoqXHJcbioganF1ZXJ5Lm1hdGNoSGVpZ2h0LmpzIG1hc3RlclxyXG4qIGh0dHA6Ly9icm0uaW8vanF1ZXJ5LW1hdGNoLWhlaWdodC9cclxuKiBMaWNlbnNlOiBNSVRcclxuKi9cclxuXHJcbjsoZnVuY3Rpb24oJCkge1xyXG4gICAgLypcclxuICAgICogIGludGVybmFsXHJcbiAgICAqL1xyXG5cclxuICAgIHZhciBfcHJldmlvdXNSZXNpemVXaWR0aCA9IC0xLFxyXG4gICAgICAgIF91cGRhdGVUaW1lb3V0ID0gLTE7XHJcblxyXG4gICAgLypcclxuICAgICogIF9wYXJzZVxyXG4gICAgKiAgdmFsdWUgcGFyc2UgdXRpbGl0eSBmdW5jdGlvblxyXG4gICAgKi9cclxuXHJcbiAgICB2YXIgX3BhcnNlID0gZnVuY3Rpb24odmFsdWUpIHtcclxuICAgICAgICAvLyBwYXJzZSB2YWx1ZSBhbmQgY29udmVydCBOYU4gdG8gMFxyXG4gICAgICAgIHJldHVybiBwYXJzZUZsb2F0KHZhbHVlKSB8fCAwO1xyXG4gICAgfTtcclxuXHJcbiAgICAvKlxyXG4gICAgKiAgX3Jvd3NcclxuICAgICogIHV0aWxpdHkgZnVuY3Rpb24gcmV0dXJucyBhcnJheSBvZiBqUXVlcnkgc2VsZWN0aW9ucyByZXByZXNlbnRpbmcgZWFjaCByb3dcclxuICAgICogIChhcyBkaXNwbGF5ZWQgYWZ0ZXIgZmxvYXQgd3JhcHBpbmcgYXBwbGllZCBieSBicm93c2VyKVxyXG4gICAgKi9cclxuXHJcbiAgICB2YXIgX3Jvd3MgPSBmdW5jdGlvbihlbGVtZW50cykge1xyXG4gICAgICAgIHZhciB0b2xlcmFuY2UgPSAxLFxyXG4gICAgICAgICAgICAkZWxlbWVudHMgPSAkKGVsZW1lbnRzKSxcclxuICAgICAgICAgICAgbGFzdFRvcCA9IG51bGwsXHJcbiAgICAgICAgICAgIHJvd3MgPSBbXTtcclxuXHJcbiAgICAgICAgLy8gZ3JvdXAgZWxlbWVudHMgYnkgdGhlaXIgdG9wIHBvc2l0aW9uXHJcbiAgICAgICAgJGVsZW1lbnRzLmVhY2goZnVuY3Rpb24oKXtcclxuICAgICAgICAgICAgdmFyICR0aGF0ID0gJCh0aGlzKSxcclxuICAgICAgICAgICAgICAgIHRvcCA9ICR0aGF0Lm9mZnNldCgpLnRvcCAtIF9wYXJzZSgkdGhhdC5jc3MoJ21hcmdpbi10b3AnKSksXHJcbiAgICAgICAgICAgICAgICBsYXN0Um93ID0gcm93cy5sZW5ndGggPiAwID8gcm93c1tyb3dzLmxlbmd0aCAtIDFdIDogbnVsbDtcclxuXHJcbiAgICAgICAgICAgIGlmIChsYXN0Um93ID09PSBudWxsKSB7XHJcbiAgICAgICAgICAgICAgICAvLyBmaXJzdCBpdGVtIG9uIHRoZSByb3csIHNvIGp1c3QgcHVzaCBpdFxyXG4gICAgICAgICAgICAgICAgcm93cy5wdXNoKCR0aGF0KTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIC8vIGlmIHRoZSByb3cgdG9wIGlzIHRoZSBzYW1lLCBhZGQgdG8gdGhlIHJvdyBncm91cFxyXG4gICAgICAgICAgICAgICAgaWYgKE1hdGguZmxvb3IoTWF0aC5hYnMobGFzdFRvcCAtIHRvcCkpIDw9IHRvbGVyYW5jZSkge1xyXG4gICAgICAgICAgICAgICAgICAgIHJvd3Nbcm93cy5sZW5ndGggLSAxXSA9IGxhc3RSb3cuYWRkKCR0aGF0KTtcclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gb3RoZXJ3aXNlIHN0YXJ0IGEgbmV3IHJvdyBncm91cFxyXG4gICAgICAgICAgICAgICAgICAgIHJvd3MucHVzaCgkdGhhdCk7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIGtlZXAgdHJhY2sgb2YgdGhlIGxhc3Qgcm93IHRvcFxyXG4gICAgICAgICAgICBsYXN0VG9wID0gdG9wO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICByZXR1cm4gcm93cztcclxuICAgIH07XHJcblxyXG4gICAgLypcclxuICAgICogIF9wYXJzZU9wdGlvbnNcclxuICAgICogIGhhbmRsZSBwbHVnaW4gb3B0aW9uc1xyXG4gICAgKi9cclxuXHJcbiAgICB2YXIgX3BhcnNlT3B0aW9ucyA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcclxuICAgICAgICB2Y
3155XIgb3B0cyA9IHtcclxuICAgICAgICAgICAgYnlSb3c6IHRydWUsXHJcbiAgICAgICAgICAgIHByb3BlcnR5OiAnaGVpZ2h0JyxcclxuICAgICAgICAgICAgdGFyZ2V0OiBudWxsLFxyXG4gICAgICAgICAgICByZW1vdmU6IGZhbHNlXHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgaWYgKHR5cGVvZiBvcHRpb25zID09PSAnb2JqZWN0Jykge1xyXG4gICAgICAgICAgICByZXR1cm4gJC5leHRlbmQob3B0cywgb3B0aW9ucyk7XHJcbiAgICAgICAgfVxyXG5cclxuICAgICAgICBpZiAodHlwZW9mIG9wdGlvbnMgPT09ICdib29sZWFuJykge1xyXG4gICAgICAgICAgICBvcHRzLmJ5Um93ID0gb3B0aW9ucztcclxuICAgICAgICB9IGVsc2UgaWYgKG9wdGlvbnMgPT09ICdyZW1vdmUnKSB7XHJcbiAgICAgICAgICAgIG9wdHMucmVtb3ZlID0gdHJ1ZTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiBvcHRzO1xyXG4gICAgfTtcclxuXHJcbiAgICAvKlxyXG4gICAgKiAgbWF0Y2hIZWlnaHRcclxuICAgICogIHBsdWdpbiBkZWZpbml0aW9uXHJcbiAgICAqL1xyXG5cclxuICAgIHZhciBtYXRjaEhlaWdodCA9ICQuZm4ubWF0Y2hIZWlnaHQgPSBmdW5jdGlvbihvcHRpb25zKSB7XHJcbiAgICAgICAgdmFyIG9wdHMgPSBfcGFyc2VPcHRpb25zKG9wdGlvbnMpO1xyXG5cclxuICAgICAgICAvLyBoYW5kbGUgcmVtb3ZlXHJcbiAgICAgICAgaWYgKG9wdHMucmVtb3ZlKSB7XHJcbiAgICAgICAgICAgIHZhciB0aGF0ID0gdGhpcztcclxuXHJcbiAgICAgICAgICAgIC8vIHJlbW92ZSBmaXhlZCBoZWlnaHQgZnJvbSBhbGwgc2VsZWN0ZWQgZWxlbWVudHNcclxuICAgICAgICAgICAgdGhpcy5jc3Mob3B0cy5wcm9wZXJ0eSwgJycpO1xyXG5cclxuICAgICAgICAgICAgLy8gcmVtb3ZlIHNlbGVjdGVkIGVsZW1lbnRzIGZyb20gYWxsIGdyb3Vwc1xyXG4gICAgICAgICAgICAkLmVhY2gobWF0Y2hIZWlnaHQuX2dyb3VwcywgZnVuY3Rpb24oa2V5LCBncm91cCkge1xyXG4gICAgICAgICAgICAgICAgZ3JvdXAuZWxlbWVudHMgPSBncm91cC5lbGVtZW50cy5ub3QodGhhdCk7XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgLy8gVE9ETzogY2xlYW51cCBlbXB0eSBncm91cHNcclxuXHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgaWYgKHRoaXMubGVuZ3RoIDw9IDEgJiYgIW9wdHMudGFyZ2V0KSB7XHJcbiAgICAgICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgICAgIH1cclxuXHJcbiAgICAgICAgLy8ga2VlcCB0cmFjayBvZiB0aGlzIGdyb3VwIHNvIHdlIGNhbiByZS1hcHBseSBsYXRlciBvbiBsb2FkIGFuZCByZXNpemUgZXZlbnRzXHJcbiAgICAgICAgbWF0Y2hIZWlnaHQuX2dyb3Vwcy5wdXNoKHtcclxuICAgICAgICAgICAgZWxlbWVudHM6IHRoaXMsXHJcbiAgICAgICAgICAgIG9wdGlvbnM6IG9wdHNcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gbWF0Y2ggZWFjaCBlbGVtZW50J3MgaGVpZ2h0IHRvIHRoZSB0YWxsZXN0IGVsZW1lbnQgaW4gdGhlIHNlbGVjdGlvblxyXG4gICAgICAgIG1hdGNoSGVpZ2h0Ll9hcHBseSh0aGlzLCBvcHRzKTtcclxuXHJcbiAgICAgICAgcmV0dXJuIHRoaXM7XHJcbiAgICB9O1xyXG5cclxuICAgIC8qXHJcbiAgICAqICBwbHVnaW4gZ2xvYmFsIG9wdGlvbnNcclxuICAgICovXHJcblxyXG4gICAgbWF0Y2hIZWlnaHQuX2dyb3VwcyA9IFtdO1xyXG4gICAgbWF0Y2hIZWlnaHQuX3Rocm90dGxlID0gODA7XHJcbiAgICBtYXRjaEhlaWdodC5fbWFpbnRhaW5TY3JvbGwgPSBmYWxzZTtcclxuICAgIG1hdGNoSGVpZ2h0Ll9iZWZvcmVVcGRhdGUgPSBudWxsO1xyXG4gICAgbWF0Y2hIZWlnaHQuX2FmdGVyVXBkYXRlID0gbnVsbDtcclxuICAgIG1hdGNoSGVpZ2h0Ll9yb3dzID0gX3Jvd3M7XHJcblxyXG4gICAgLypcclxuICAgICogIG1hdGNoSGVpZ2h0Ll9hcHBseVxyXG4gICAgKiAgYXBwbHkgbWF0Y2hIZWlnaHQgdG8gZ2l2ZW4gZWxlbWVudHNcclxuICAgICovXHJcblxyXG4gICAgbWF0Y2hIZWlnaHQuX2FwcGx5ID0gZnVuY3Rpb24oZWxlbWVudHMsIG9wdGlvbnMpIHtcclxuICAgICAgICB2Y
3155XIgb3B0cyA9IF9wYXJzZU9wdGlvbnMob3B0aW9ucyksXHJcbiAgICAgICAgICAgICRlbGVtZW50cyA9ICQoZWxlbWVudHMpLFxyXG4gICAgICAgICAgICByb3dzID0gWyRlbGVtZW50c107XHJcblxyXG4gICAgICAgIC8vIHRha2Ugbm90ZSBvZiBzY3JvbGwgcG9zaXRpb25cclxuICAgICAgICB2YXIgc2Nyb2xsVG9wID0gJCh3aW5kb3cpLnNjcm9sbFRvcCgpLFxyXG4gICAgICAgICAgICBodG1sSGVpZ2h0ID0gJCgnaHRtbCcpLm91dGVySGVpZ2h0KHRydWUpO1xyXG5cclxuICAgICAgICAvLyBnZXQgaGlkZGVuIHBhcmVudHNcclxuICAgICAgICB2YXIgJGhpZGRlblBhcmVudHMgPSAkZWxlbWVudHMucGFyZW50cygpLmZpbHRlcignOmhpZGRlbicpO1xyXG5cclxuICAgICAgICAvLyBjYWNoZSB0aGUgb3JpZ2luYWwgaW5saW5lIHN0eWxlXHJcbiAgICAgICAgJGhpZGRlblBhcmVudHMuZWFjaChmdW5jdGlvbigpIHtcclxuICAgICAgICAgICAgdmFyICR0aGF0ID0gJCh0aGlzKTtcclxuICAgICAgICAgICAgJHRoYXQuZGF0YSgnc3R5bGUtY2FjaGUnLCAkdGhhdC5hdHRyKCdzdHlsZScpKTtcclxuICAgICAgICB9KTtcclxuXHJcbiAgICAgICAgLy8gdGVtcG9yYXJpbHkgbXVzdCBmb3JjZSBoaWRkZW4gcGFyZW50cyB2aXNpYmxlXHJcbiAgICAgICAgJGhpZGRlblBhcmVudHMuY3NzKCdkaXNwbGF5JywgJ2Jsb2NrJyk7XHJcblxyXG4gICAgICAgIC8vIGdldCByb3dzIGlmIHVzaW5nIGJ5Um93LCBvdGhlcndpc2UgYXNzdW1lIG9uZSByb3dcclxuICAgICAgICBpZiAob3B0cy5ieVJvdyAmJiAhb3B0cy50YXJnZXQpIHtcclxuXHJcbiAgICAgICAgICAgIC8vIG11c3QgZmlyc3QgZm9yY2UgYW4gYXJiaXRyYXJ5IGVxdWFsIGhlaWdodCBzbyBmbG9hdGluZyBlbGVtZW50cyBicmVhayBldmVubHlcclxuICAgICAgICAgICAgJGVsZW1lbnRzLmVhY2goZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgICAgICAgICB2Y
3155XIgJHRoYXQgPSAkKHRoaXMpLFxyXG4gICAgICAgICAgICAgICAgICAgIGRpc3BsYXkgPSAkdGhhdC5jc3MoJ2Rpc3BsYXknKTtcclxuXHJcbiAgICAgICAgICAgICAgICAvLyB0ZW1wb3JhcmlseSBmb3JjZSBhIHVzYWJsZSBkaXNwbGF5IHZhbHVlXHJcbiAgICAgICAgICAgICAgICBpZiAoZGlzcGxheSAhPT0gJ2lubGluZS1ibG9jaycgJiYgZGlzcGxheSAhPT0gJ2lubGluZS1mbGV4Jykge1xyXG4gICAgICAgICAgICAgICAgICAgIGRpc3BsYXkgPSAnYmxvY2snO1xyXG4gICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgIC8vIGNhY2hlIHRoZSBvcmlnaW5hbCBpbmxpbmUgc3R5bGVcclxuICAgICAgICAgICAgICAgICR0aGF0LmRhdGEoJ3N0eWxlLWNhY2hlJywgJHRoYXQuYXR0cignc3R5bGUnKSk7XHJcblxyXG4gICAgICAgICAgICAgICAgJHRoYXQuY3NzKHtcclxuICAgICAgICAgICAgICAgICAgICAnZGlzcGxheSc6IGRpc3BsYXksXHJcbiAgICAgICAgICAgICAgICAgICAgJ3BhZGRpbmctdG9wJzogJzAnLFxyXG4gICAgICAgICAgICAgICAgICAgICdwYWRkaW5nLWJvdHRvbSc6ICcwJyxcclxuICAgICAgICAgICAgICAgICAgICAnbWFyZ2luLXRvcCc6ICcwJyxcclxuICAgICAgICAgICAgICAgICAgICAnbWFyZ2luLWJvdHRvbSc6ICcwJyxcclxuICAgICAgICAgICAgICAgICAgICAnYm9yZGVyLXRvcC13aWR0aCc6ICcwJyxcclxuICAgICAgICAgICAgICAgICAgICAnYm9yZGVyLWJvdHRvbS13aWR0aCc6ICcwJyxcclxuICAgICAgICAgICAgICAgICAgICAnaGVpZ2h0JzogJzEwMHB4J1xyXG4gICAgICAgICAgICAgICAgfSk7XHJcbiAgICAgICAgICAgIH0pO1xyXG5cclxuICAgICAgICAgICAgLy8gZ2V0IHRoZSBhcnJheSBvZiByb3dzIChiYXNlZCBvbiBlbGVtZW50IHRvcCBwb3NpdGlvbilcclxuICAgICAgICAgICAgcm93cyA9IF9yb3dzKCRlbGVtZW50cyk7XHJcblxyXG4gICAgICAgICAgICAvLyByZXZlcnQgb3JpZ2luYWwgaW5saW5lIHN0eWxlc1xyXG4gICAgICAgICAgICAkZWxlbWVudHMuZWFjaChmdW5jdGlvbigpIHtcclxuICAgICAgICAgICAgICAgIHZhciAkdGhhdCA9ICQodGhpcyk7XHJcbiAgICAgICAgICAgICAgICAkdGhhdC5hdHRyKCdzdHlsZScsICR0aGF0LmRhdGEoJ3N0eWxlLWNhY2hlJykgfHwgJycpO1xyXG4gICAgICAgICAgICB9KTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICQuZWFjaChyb3dzLCBmdW5jdGlvbihrZXksIHJvdykge1xyXG4gICAgICAgICAgICB2Y
3155XIgJHJvdyA9ICQocm93KSxcclxuICAgICAgICAgICAgICAgIHRhcmdldEhlaWdodCA9IDA7XHJcblxyXG4gICAgICAgICAgICBpZiAoIW9wdHMudGFyZ2V0KSB7XHJcbiAgICAgICAgICAgICAgICAvLyBza2lwIGFwcGx5IHRvIHJvd3Mgd2l0aCBvbmx5IG9uZSBpdGVtXHJcbiAgICAgICAgICAgICAgICBpZiAob3B0cy5ieVJvdyAmJiAkcm93Lmxlbmd0aCA8PSAxKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgJHJvdy5jc3Mob3B0cy5wcm9wZXJ0eSwgJycpO1xyXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBpdGVyYXRlIHRoZSByb3cgYW5kIGZpbmQgdGhlIG1heCBoZWlnaHRcclxuICAgICAgICAgICAgICAgICRyb3cuZWFjaChmdW5jdGlvbigpe1xyXG4gICAgICAgICAgICAgICAgICAgIHZhciAkdGhhdCA9ICQodGhpcyksXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXkgPSAkdGhhdC5jc3MoJ2Rpc3BsYXknKTtcclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gdGVtcG9yYXJpbHkgZm9yY2UgYSB1c2FibGUgZGlzcGxheSB2YWx1ZVxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChkaXNwbGF5ICE9PSAnaW5saW5lLWJsb2NrJyAmJiBkaXNwbGF5ICE9PSAnaW5saW5lLWZsZXgnKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGRpc3BsYXkgPSAnYmxvY2snO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAgICAgLy8gZW5zdXJlIHdlIGdldCB0aGUgY29ycmVjdCBhY3R1YWwgaGVpZ2h0IChhbmQgbm90IGEgcHJldmlvdXNseSBzZXQgaGVpZ2h0IHZhbHVlKVxyXG4gICAgICAgICAgICAgICAgICAgIHZhciBjc3MgPSB7ICdkaXNwbGF5JzogZGlzcGxheSB9O1xyXG4gICAgICAgICAgICAgICAgICAgIGNzc1tvcHRzLnByb3BlcnR5XSA9ICcnO1xyXG4gICAgICAgICAgICAgICAgICAgICR0aGF0LmNzcyhjc3MpO1xyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyBmaW5kIHRoZSBtYXggaGVpZ2h0IChpbmNsdWRpbmcgcGFkZGluZywgYnV0IG5vdCBtYXJnaW4pXHJcbiAgICAgICAgICAgICAgICAgICAgaWYgKCR0aGF0Lm91dGVySGVpZ2h0KGZhbHNlKSA+IHRhcmdldEhlaWdodCkge1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0YXJnZXRIZWlnaHQgPSAkdGhhdC5vdXRlckhlaWdodChmYWxzZSk7XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG5cclxuICAgICAgICAgICAgICAgICAgICAvLyByZXZlcnQgZGlzcGxheSBibG9ja1xyXG4gICAgICAgICAgICAgICAgICAgICR0aGF0LmNzcygnZGlzcGxheScsICcnKTtcclxuICAgICAgICAgICAgICAgIH0pO1xyXG4gICAgICAgICAgICB9IGVsc2Uge1xyXG4gICAgICAgICAgICAgICAgLy8gaWYgdGFyZ2V0IHNldCwgdXNlIHRoZSBoZWlnaHQgb2YgdGhlIHRhcmdldCBlbGVtZW50XHJcbiAgICAgICAgICAgICAgICB0YXJnZXRIZWlnaHQgPSBvcHRzLnRhcmdldC5vdXRlckhlaWdodChmYWxzZSk7XHJcbiAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgIC8vIGl0ZXJhdGUgdGhlIHJvdyBhbmQgYXBwbHkgdGhlIGhlaWdodCB0byBhbGwgZWxlbWVudHNcclxuICAgICAgICAgICAgJHJvdy5lYWNoKGZ1bmN0aW9uKCl7XHJcbiAgICAgICAgICAgICAgICB2Y
3155XIgJHRoYXQgPSAkKHRoaXMpLFxyXG4gICAgICAgICAgICAgICAgICAgIHZlcnRpY2FsUGFkZGluZyA9IDA7XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gZG9uJ3QgYXBwbHkgdG8gYSB0YXJnZXRcclxuICAgICAgICAgICAgICAgIGlmIChvcHRzLnRhcmdldCAmJiAkdGhhdC5pcyhvcHRzLnRhcmdldCkpIHtcclxuICAgICAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgICAgICB9XHJcblxyXG4gICAgICAgICAgICAgICAgLy8gaGFuZGxlIHBhZGRpbmcgYW5kIGJvcmRlciBjb3JyZWN0bHkgKHJlcXVpcmVkIHdoZW4gbm90IHVzaW5nIGJvcmRlci1ib3gpXHJcbiAgICAgICAgICAgICAgICBpZiAoJHRoYXQuY3NzKCdib3gtc2l6aW5nJykgIT09ICdib3JkZXItYm94Jykge1xyXG4gICAgICAgICAgICAgICAgICAgIHZlcnRpY2FsUGFkZGluZyArPSBfcGFyc2UoJHRoYXQuY3NzKCdib3JkZXItdG9wLXdpZHRoJykpICsgX3BhcnNlKCR0aGF0LmNzcygnYm9yZGVyLWJvdHRvbS13aWR0aCcpKTtcclxuICAgICAgICAgICAgICAgICAgICB2ZXJ0aWNhbFBhZGRpbmcgKz0gX3BhcnNlKCR0aGF0LmNzcygncGFkZGluZy10b3AnKSkgKyBfcGFyc2UoJHRoYXQuY3NzKCdwYWRkaW5nLWJvdHRvbScpKTtcclxuICAgICAgICAgICAgICAgIH1cclxuXHJcbiAgICAgICAgICAgICAgICAvLyBzZXQgdGhlIGhlaWdodCAoYWNjb3VudGluZyBmb3IgcGFkZGluZyBhbmQgYm9yZGVyKVxyXG4gICAgICAgICAgICAgICAgJHRoYXQuY3NzKG9wdHMucHJvcGVydHksICh0YXJnZXRIZWlnaHQgLSB2ZXJ0aWNhbFBhZGRpbmcpICsgJ3B4Jyk7XHJcbiAgICAgICAgICAgIH0pO1xyXG4gICAgICAgIH0pO1xyXG5cclxuICAgICAgICAvLyByZXZlcnQgaGlkZGVuIHBhcmVudHNcclxuICAgICAgICAkaGlkZGVuUGFyZW50cy5lYWNoKGZ1bmN0aW9uKCkge1xyXG4gICAgICAgICAgICB2Y
3155XIgJHRoYXQgPSAkKHRoaXMpO1xyXG4gICAgICAgICAgICAkdGhhdC5hdHRyKCdzdHlsZScsICR0aGF0LmRhdGEoJ3N0eWxlLWNhY2hlJykgfHwgbnVsbCk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIHJlc3RvcmUgc2Nyb2xsIHBvc2l0aW9uIGlmIGVuYWJsZWRcclxuICAgICAgICBpZiAobWF0Y2hIZWlnaHQuX21haW50YWluU2Nyb2xsKSB7XHJcbiAgICAgICAgICAgICQod2luZG93KS5zY3JvbGxUb3AoKHNjcm9sbFRvcCAvIGh0bWxIZWlnaHQpICogJCgnaHRtbCcpLm91dGVySGVpZ2h0KHRydWUpKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIHJldHVybiB0aGlzO1xyXG4gICAgfTtcclxuXHJcbiAgICAvKlxyXG4gICAgKiAgbWF0Y2hIZWlnaHQuX2FwcGx5RGF0YUFwaVxyXG4gICAgKiAgYXBwbGllcyBtYXRjaEhlaWdodCB0byBhbGwgZWxlbWVudHMgd2l0aCBhIGRhdGEtbWF0Y2gtaGVpZ2h0IGF0dHJpYnV0ZVxyXG4gICAgKi9cclxuXHJcbiAgICBtYXRjaEhlaWdodC5fYXBwbHlEYXRhQXBpID0gZnVuY3Rpb24oKSB7XHJcbiAgICAgICAgdmFyIGdyb3VwcyA9IHt9O1xyXG5cclxuICAgICAgICAvLyBnZW5lcmF0ZSBncm91cHMgYnkgdGhlaXIgZ3JvdXBJZCBzZXQgYnkgZWxlbWVudHMgdXNpbmcgZGF0YS1tYXRjaC1oZWlnaHRcclxuICAgICAgICAkKCdbZGF0YS1tYXRjaC1oZWlnaHRdLCBbZGF0YS1taF0nKS5lYWNoKGZ1bmN0aW9uKCkge1xyXG4gICAgICAgICAgICB2YXIgJHRoaXMgPSAkKHRoaXMpLFxyXG4gICAgICAgICAgICAgICAgZ3JvdXBJZCA9ICR0aGlzLmF0dHIoJ2RhdGEtbWgnKSB8fCAkdGhpcy5hdHRyKCdkYXRhLW1hdGNoLWhlaWdodCcpO1xyXG5cclxuICAgICAgICAgICAgaWYgKGdyb3VwSWQgaW4gZ3JvdXBzKSB7XHJcbiAgICAgICAgICAgICAgICBncm91cHNbZ3JvdXBJZF0gPSBncm91cHNbZ3JvdXBJZF0uYWRkKCR0aGlzKTtcclxuICAgICAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgICAgIGdyb3Vwc1tncm91cElkXSA9ICR0aGlzO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIC8vIGFwcGx5IG1hdGNoSGVpZ2h0IHRvIGVhY2ggZ3JvdXBcclxuICAgICAgICAkLmVhY2goZ3JvdXBzLCBmdW5jdGlvbigpIHtcclxuICAgICAgICAgICAgdGhpcy5tYXRjaEhlaWdodCh0cnVlKTtcclxuICAgICAgICB9KTtcclxuICAgIH07XHJcblxyXG4gICAgLypcclxuICAgICogIG1hdGNoSGVpZ2h0Ll91cGRhdGVcclxuICAgICogIHVwZGF0ZXMgbWF0Y2hIZWlnaHQgb24gYWxsIGN1cnJlbnQgZ3JvdXBzIHdpdGggdGhlaXIgY29ycmVjdCBvcHRpb25zXHJcbiAgICAqL1xyXG5cclxuICAgIHZhciBfdXBkYXRlID0gZnVuY3Rpb24oZXZlbnQpIHtcclxuICAgICAgICBpZiAobWF0Y2hIZWlnaHQuX2JlZm9yZVVwZGF0ZSkge1xyXG4gICAgICAgICAgICBtYXRjaEhlaWdodC5fYmVmb3JlVXBkYXRlKGV2ZW50LCBtYXRjaEhlaWdodC5fZ3JvdXBzKTtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgICQuZWFjaChtYXRjaEhlaWdodC5fZ3JvdXBzLCBmdW5jdGlvbigpIHtcclxuICAgICAgICAgICAgbWF0Y2hIZWlnaHQuX2FwcGx5KHRoaXMuZWxlbWVudHMsIHRoaXMub3B0aW9ucyk7XHJcbiAgICAgICAgfSk7XHJcblxyXG4gICAgICAgIGlmIChtYXRjaEhlaWdodC5fYWZ0ZXJVcGRhdGUpIHtcclxuICAgICAgICAgICAgbWF0Y2hIZWlnaHQuX2FmdGVyVXBkYXRlKGV2ZW50LCBtYXRjaEhlaWdodC5fZ3JvdXBzKTtcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIG1hdGNoSGVpZ2h0Ll91cGRhdGUgPSBmdW5jdGlvbih0aHJvdHRsZSwgZXZlbnQpIHtcclxuICAgICAgICAvLyBwcmV2ZW50IHVwZGF0ZSBpZiBmaXJlZCBmcm9tIGEgcmVzaXplIGV2ZW50XHJcbiAgICAgICAgLy8gd2hlcmUgdGhlIHZpZXdwb3J0IHdpZHRoIGhhc24ndCBhY3R1YWxseSBjaGFuZ2VkXHJcbiAgICAgICAgLy8gZml4ZXMgYW4gZXZlbnQgbG9vcGluZyBidWcgaW4gSUU4XHJcbiAgICAgICAgaWYgKGV2ZW50ICYmIGV2ZW50LnR5cGUgPT09ICdyZXNpemUnKSB7XHJcbiAgICAgICAgICAgIHZhciB3aW5kb3dXaWR0aCA9ICQod2luZG93KS53aWR0aCgpO1xyXG4gICAgICAgICAgICBpZiAod2luZG93V2lkdGggPT09IF9wcmV2aW91c1Jlc2l6ZVdpZHRoKSB7XHJcbiAgICAgICAgICAgICAgICByZXR1cm47XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgX3ByZXZpb3VzUmVzaXplV2lkdGggPSB3aW5kb3dXaWR0aDtcclxuICAgICAgICB9XHJcblxyXG4gICAgICAgIC8vIHRocm90dGxlIHVwZGF0ZXNcclxuICAgICAgICBpZiAoIXRocm90dGxlKSB7XHJcbiAgICAgICAgICAgIF91cGRhdGUoZXZlbnQpO1xyXG4gICAgICAgIH0gZWxzZSBpZiAoX3VwZGF0ZVRpbWVvdXQgPT09IC0xKSB7XHJcbiAgICAgICAgICAgIF91cGRhdGVUaW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbigpIHtcclxuICAgICAgICAgICAgICAgIF91cGRhdGUoZXZlbnQpO1xyXG4gICAgICAgICAgICAgICAgX3VwZGF0ZVRpbWVvdXQgPSAtMTtcclxuICAgICAgICAgICAgfSwgbWF0Y2hIZWlnaHQuX3Rocm90dGxlKTtcclxuICAgICAgICB9XHJcbiAgICB9O1xyXG5cclxuICAgIC8qXHJcbiAgICAqICBiaW5kIGV2ZW50c1xyXG4gICAgKi9cclxuXHJcbiAgICAvLyBhcHBseSBvbiBET00gcmVhZHkgZXZlbnRcclxuICAgICQobWF0Y2hIZWlnaHQuX2FwcGx5RGF0YUFwaSk7XHJcblxyXG4gICAgLy8gdXBkYXRlIGhlaWdodHMgb24gbG9hZCBhbmQgcmVzaXplIGV2ZW50c1xyXG4gICAgJCh3aW5kb3cpLmJpbmQoJ2xvYWQnLCBmdW5jdGlvbihldmVudCkge1xyXG4gICAgICAgIG1hdGNoSGVpZ2h0Ll91cGRhdGUoZmFsc2UsIGV2ZW50KTtcclxuICAgIH0pO1xyXG5cclxuICAgIC8vIHRocm90dGxlZCB1cGRhdGUgaGVpZ2h0cyBvbiByZXNpemUgZXZlbnRzXHJcbiAgICAkKHdpbmRvdykuYmluZCgncmVzaXplIG9yaWVudGF0aW9uY2hhbmdlJywgZnVuY3Rpb24oZXZlbnQpIHtcclxuICAgICAgICBtYXRjaEhlaWdodC5fdXBkYXRlKHRydWUsIGV2ZW50KTtcclxuICAgIH0pO1xyXG5cclxufSkoalF1ZXJ5KTtcclxuIiwiLypcclxuKiBkZWJvdW5jZWRyZXNpemU6IHNwZWNpYWwgalF1ZXJ5IGV2ZW50IHRoYXQgaGFwcGVucyBvbmNlIGFmdGVyIGEgd2luZG93IHJlc2l6ZVxyXG4qXHJcbiogbGF0ZXN0IHZlcnNpb24gYW5kIGNvbXBsZXRlIFJFQURNRSBhdmFpbGFibGUgb24gR2l0aHViOlxyXG4qIGh0dHBzOi8vZ2l0aHViLmNvbS9sb3Vpc3JlbWkvanF1ZXJ5LXNtYXJ0cmVzaXplL2Jsb2IvbWFzdGVyL2pxdWVyeS5k
3155ZWJvdW5jZWRyZXNpemUuanNcclxuKlxyXG4qIENvcHlyaWdodCAyMDExIEBsb3Vpc19yZW1pXHJcbiogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxyXG4qL1xyXG52YXIgJGV2ZW50ID0gJC5ldmVudCxcclxuJHNwZWNpYWwsXHJcbnJlc2l6ZVRpbWVvdXQ7XHJcblxyXG4kc3BlY2lhbCA9ICRldmVudC5zcGVjaWFsLmRlYm91bmNlZHJlc2l6ZSA9IHtcclxuXHRzZXR1cDogZnVuY3Rpb24oKSB7XHJcblx0XHQkKCB0aGlzICkub24oIFwicmVzaXplXCIsICRzcGVjaWFsLmhhbmRsZXIgKTtcclxuXHR9LFxyXG5cdHRlYXJkb3duOiBmdW5jdGlvbigpIHtcclxuXHRcdCQoIHRoaXMgKS5vZmYoIFwicmVzaXplXCIsICRzcGVjaWFsLmhhbmRsZXIgKTtcclxuXHR9LFxyXG5cdGhhbmRsZXI6IGZ1bmN0aW9uKCBldmVudCwgZXhlY0FzYXAgKSB7XHJcblx0XHQvLyBTYXZlIHRoZSBjb250ZXh0XHJcblx0XHR2YXIgY29udGV4dCA9IHRoaXMsXHJcblx0XHRcdGFyZ3MgPSBhcmd1bWVudHMsXHJcblx0XHRcdGRpc3BhdGNoID0gZnVuY3Rpb24oKSB7XHJcblx0XHRcdFx0Ly8gc2V0IGNvcnJlY3QgZXZlbnQgdHlwZVxyXG5cdFx0XHRcdGV2ZW50LnR5cGUgPSBcImRlYm91bmNlZHJlc2l6ZVwiO1xyXG5cdFx0XHRcdCRldmVudC5kaXNwYXRjaC5hcHBseSggY29udGV4dCwgYXJncyApO1xyXG5cdFx0XHR9O1xyXG5cclxuXHRcdGlmICggcmVzaXplVGltZW91dCApIHtcclxuXHRcdFx0Y2xlYXJUaW1lb3V0KCByZXNpemVUaW1lb3V0ICk7XHJcblx0XHR9XHJcblxyXG5cdFx0ZXhlY0FzYXAgP1xyXG5cdFx0XHRkaXNwYXRjaCgpIDpcclxuXHRcdFx0cmVzaXplVGltZW91dCA9IHNldFRpbWVvdXQoIGRpc3BhdGNoLCAkc3BlY2lhbC50aHJlc2hvbGQgKTtcclxuXHR9LFxyXG5cdHRocmVzaG9sZDogMjUwXHJcbn07XHJcblxyXG52YXIgbWVkaWFHYWxsZXJ5ID0gKGZ1bmN0aW9uKCkge1xyXG5cclxuXHRcdC8vIGxpc3Qgb2YgaXRlbXNcclxuXHJcblx0XHR2YXIgJGdyaWQgPSAkKCAnLm1nLWdyaWQnICksXHJcblx0XHQvLyB0aGUgaXRlbXNcclxuXHRcdCRpdGVtcyA9ICRncmlkLmNoaWxkcmVuKCAnbGknICksXHJcblx0XHQvLyBjdXJyZW50IGV4cGFuZGVkIGl0ZW0ncyBpbmRleFxyXG5cdFx0Y3VycmVudCA9IC0xLFxyXG5cdFx0Ly8gcG9zaXRpb24gKHRvcCkgb2YgdGhlIGV4cGFuZGVkIGl0ZW1cclxuXHRcdC8vIHVzZWQgdG8ga25vdyBpZiB0aGUgcHJldmlldyB3aWxsIGV4cGFuZCBpbiBhIGRpZmZlcmVudCByb3dcclxuXHRcdHByZXZpZXdQb3MgPSAtMSxcclxuXHRcdC8vIGV4dHJhIGFtb3VudCBvZiBwaXhlbHMgdG8gc2Nyb2xsIHRoZSB3aW5kb3dcclxuXHRcdHNjcm9sbEV4dHJhID0gMCxcclxuXHRcdC8vIGV4dHJhIG1hcmdpbiB3aGVuIGV4cGFuZGVkIChiZXR3ZWVuIHByZXZpZXcgb3ZlcmxheSBhbmQgdGhlIG5leHQgaXRlbXMpXHJcblx0XHRtYXJnaW5FeHBhbmRlZCA9IDEwLFxyXG5cdFx0JHdpbmRvdyA9ICQoIHdpbmRvdyApLCB3aW5zaXplLFxyXG5cdFx0JGJvZHkgPSAkKCAnaHRtbCwgYm9keScgKSxcclxuXHRcdC8vIHRyYW5zaXRpb25lbmQgZXZlbnRzXHJcblx0XHR0cmFuc0VuZEV2ZW50TmFtZXMgPSB7XHJcblx0XHRcdCdXZWJraXRUcmFuc2l0aW9uJyA6ICd3ZWJraXRUcmFuc2l0aW9uRW5kJyxcclxuXHRcdFx0J01velRyYW5zaXRpb24nIDogJ3RyYW5zaXRpb25lbmQnLFxyXG5cdFx0XHQnT1RyYW5zaXRpb24nIDogJ29UcmFuc2l0aW9uRW5kJyxcclxuXHRcdFx0J21zVHJhbnNpdGlvbicgOiAnTVNUcmFuc2l0aW9uRW5kJyxcclxuXHRcdFx0J3RyYW5zaXRpb24nIDogJ3RyYW5zaXRpb25lbmQnXHJcblx0XHR9LFxyXG5cdFx0dHJhbnNFbmRFdmVudE5hbWUgPSB0cmFuc0VuZEV2ZW50TmFtZXNbIE1vZGVybml6ci5wcmVmaXhlZCggJ3RyYW5zaXRpb24nICkgXSxcclxuXHRcdC8vIHN1cHBvcnQgZm9yIGNzc3RyYW5zaXRpb25zXHJcblx0XHRzdXBwb3J0ID0gTW9kZXJuaXpyLmNzc3RyYW5zaXRpb25zLFxyXG5cdFx0Ly8gZGVmYXVsdCBzZXR0aW5nc1xyXG5cdFx0c2V0dGluZ3MgPSB7XHJcblx0XHRcdG1pbkhlaWdodCA6IDUwMCxcclxuXHRcdFx0c3BlZWQgOiAzNTAsXHJcblx0XHRcdGVhc2luZyA6ICdlYXNlJ1xyXG5cdFx0fTtcclxuXHJcblx0ZnVuY3Rpb24gaW5pdCggY29uZmlnICkge1xyXG5cdFx0XHJcblx0XHQvLyB0aGUgc2V0dGluZ3MuLlxyXG5cdFx0c2V0dGluZ3MgPSAkLmV4dGVuZCggdHJ1ZSwge30sIHNldHRpbmdzLCBjb25maWcgKTtcclxuXHJcblx0XHQvLyBwcmVsb2FkIGFsbCBpbWFnZXNcclxuXHRcdCRncmlkLmltYWdlc0xvYWRlZCggZnVuY3Rpb24oKSB7XHJcblxyXG5cdFx0XHQvLyBzYXZlIGl0ZW3CtHMgc2l6ZSBhbmQgb2Zmc2V0XHJcblx0XHRcdHNhdmVJdGVtSW5mbyggdHJ1ZSApO1xyXG5cdFx0XHQvLyBnZXQgd2luZG93wrRzIHNpemVcclxuXHRcdFx0Z2V0V2luU2l6ZSgpO1xyXG5cdFx0XHQvLyBpbml0aWFsaXplIHNvbWUgZXZlbnRzXHJcblx0XHRcdGluaXRFdmVudHMoKTtcclxuXHJcblx0XHR9ICk7XHJcblxyXG5cdH1cclxuXHJcblx0Ly8gYWRkIG1vcmUgaXRlbXMgdG8gdGhlIGdyaWQuXHJcblx0Ly8gdGhlIG5ldyBpdGVtcyBuZWVkIHRvIGFwcGVuZGVkIHRvIHRoZSBncmlkLlxyXG5cdC8vIGFmdGVyIHRoYXQgY2FsbCBHcmlkLmFkZEl0ZW1zKHRoZUl0ZW1zKTtcclxuXHRmdW5jdGlvbiBhZGRJdGVtcyggJG5ld2l0ZW1zICkge1xyXG5cclxuXHRcdCRpdGVtcyA9ICRpdGVtcy5hZGQoICRuZXdpdGVtcyApO1xyXG5cclxuXHRcdCRuZXdpdGVtcy5lYWNoKCBmdW5jdGlvbigpIHtcclxuXHRcdFx0dmFyICRpdGVtID0gJCggdGhpcyApO1xyXG5cdFx0XHQkaXRlbS5kYXRhKCB7XHJcblx0XHRcdFx0b2Zmc2V0VG9wIDogJGl0ZW0ub2Zmc2V0KCkudG9wLFxyXG5cdFx0XHRcdGhlaWdodCA6ICRpdGVtLmhlaWdodCgpXHJcblxyXG5cdFx0XHR9ICk7XHJcblx0XHR9ICk7XHJcblxyXG5cdFx0aW5pdEl0ZW1zRXZlbnRzKCAkbmV3aXRlbXMgKTtcclxuXHJcblx0fVxyXG5cclxuXHQvLyBzYXZlcyB0aGUgaXRlbcK0cyBvZmZzZXQgdG9wIGFuZCBoZWlnaHQgKGlmIHNhdmVoZWlnaHQgaXMgdHJ1ZSlcclxuXHRmdW5jdGlvbiBzYXZlSXRlbUluZm8oIHNhdmVoZWlnaHQgKSB7XHJcblx0XHQkaXRlbXMuZWFjaCggZnVuY3Rpb24oKSB7XHJcblx0XHRcdHZhciAkaXRlbSA9ICQoIHRoaXMgKTtcclxuXHRcdFx0JGl0ZW0uZGF0YSggJ29mZnNldFRvcCcsICRpdGVtLm9mZnNldCgpLnRvcCApO1xyXG5cdFx0XHRpZiggc2F2ZWhlaWdodCApIHtcclxuXHRcdFx0XHQkaXRlbS5kYXRhKCAnaGVpZ2h0JywgJGl0ZW0uaGVpZ2h0KCkgKTtcclxuXHRcdFx0fVxyXG5cdFx0fSApO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gaW5pdEV2ZW50cygpIHtcclxuXHRcdFxyXG5cdFx0Ly8gd2hlbiBjbGlja2luZyBhbiBpdGVtLCBzaG93IHRoZSBwcmV2aWV3IHdpdGggdGhlIGl0ZW3CtHMgaW5mbyBhbmQgbGFyZ2UgaW1hZ2UuXHJcblx0XHQvLyBjbG9zZSB0aGUgaXRlbSBpZiBhbHJlYWR5IGV4cGFuZGVkLlxyXG5cdFx0Ly8gYWxzbyBjbG9zZSBpZiBjbGlja2luZyBvbiB0aGUgaXRlbcK0cyBjcm9zc1xyXG5cdFx0aW5pdEl0ZW1zRXZlbnRzKCAkaXRlbXMgKTtcclxuXHRcdFxyXG5cdFx0Ly8gb24gd2luZG93IHJlc2l6ZSBnZXQgdGhlIHdpbmRvd8K0cyBzaXplIGFnYWluXHJcblx0XHQvLyByZXNldCBzb21lIHZhbHVlcy4uXHJcblx0XHQkd2luZG93Lm9uKCAnZGVib3VuY2VkcmVzaXplJywgZnVuY3Rpb24oKSB7XHJcblx0XHRcdFxyXG5cdFx0XHRzY3JvbGxFeHRyYSA9IDA7XHJcblx0XHRcdHByZXZpZXdQb3MgPSAtMTtcclxuXHRcdFx0Ly8gc2F2ZSBpdGVtwrRzIG9mZnNldFxyXG5cdFx0XHRzYXZlSXRlbUluZm8odHJ1ZSk7XHJcblx0XHRcdGdldFdpblNpemUoKTtcclxuXHRcdFx0dmFyIHByZXZpZXcgPSAkLmRhdGEoIHRoaXMsICdwcmV2aWV3JyApO1xyXG5cdFx0XHRpZiggdHlwZW9mIHByZXZpZXcgIT0gJ3VuZGVmaW5lZCcgKSB7XHJcblx0XHRcdFx0aGlkZVByZXZpZXcoKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gKTtcclxuXHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBpbml0SXRlbXNFdmVudHMoICRpdGVtcyApIHtcclxuXHRcdCRpdGVtcy5vbiggJ2NsaWNrJywgJ3NwYW4ub2ctY2xvc2UnLCBmdW5jdGlvbigpIHtcclxuXHRcdFx0JCgnLm9nLWV4cGFuZGVkJykucmVtb3ZlQ2xhc3MoJ29nLWV4cGFuZGVkJyk7XHJcblx0XHRcdGhpZGVQcmV2aWV3KCk7XHJcblx0XHRcdHJldHVybi
3155BmYWxzZTtcclxuXHRcdH0gKS5jaGlsZHJlbiggJ2EnICkub24oICdjbGljaycsIGZ1bmN0aW9uKGUpIHtcclxuXHJcblx0XHRcdHZhciAkaXRlbSA9ICQoIHRoaXMgKS5wYXJlbnQoKTtcclxuXHJcblx0XHRcdCQoJy5vZy1leHBhbmRlZCcpLnJlbW92ZUNsYXNzKCdvZy1leHBhbmRlZCcpO1xyXG5cclxuXHRcdFx0Ly8gY2hlY2sgaWYgaXRlbSBhbHJlYWR5IG9wZW5lZFxyXG5cdFx0XHRjdXJyZW50ID09PSAkaXRlbS5pbmRleCgpID8gaGlkZVByZXZpZXcoKSA6IHNob3dQcmV2aWV3KCAkaXRlbSApO1xyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblxyXG5cdFx0fSApO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gZ2V0V2luU2l6ZSgpIHtcclxuXHRcdHdpbnNpemUgPSB7IHdpZHRoIDogJHdpbmRvdy53aWR0aCgpLCBoZWlnaHQgOiAkd2luZG93LmhlaWdodCgpIH07XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBzaG93UHJldmlldyggJGl0ZW0gKSB7XHJcblxyXG5cdFx0dmFyIHByZXZpZXcgPSAkLmRhdGEoIHRoaXMsICdwcmV2aWV3JyApLFxyXG5cdFx0XHQvLyBpdGVtwrRzIG9mZnNldCB0b3BcclxuXHRcdFx0cG9zaXRpb24gPSAkaXRlbS5kYXRhKCAnb2Zmc2V0VG9wJyApO1xyXG5cclxuXHRcdHNjcm9sbEV4dHJhID0gMDtcclxuXHJcblx0XHQvLyBpZiBhIHByZXZpZXcgZXhpc3RzIGFuZCBwcmV2aWV3UG9zIGlzIGRpZmZlcmVudCAoZGlmZmVyZW50IHJvdykgZnJvbSBpdGVtwrRzIHRvcCB0aGVuIGNsb3NlIGl0XHJcblx0XHRpZiggdHlwZW9mIHByZXZpZXcgIT0gJ3VuZGVmaW5lZCcgKSB7XHJcblxyXG5cdFx0XHQvLyBub3QgaW4gdGhlIHNhbWUgcm93XHJcblx0XHRcdGlmKCBwcmV2aWV3UG9zICE9PSBwb3NpdGlvbiApIHtcclxuXHRcdFx0XHQvLyBpZiBwb3NpdGlvbiA+IHByZXZpZXdQb3MgdGhlbiB3ZSBuZWVkIHRvIHRha2UgdGUgY3VycmVudCBwcmV2aWV3wrRzIGhlaWdodCBpbiBjb25zaWRlcmF0aW9uIHdoZW4gc2Nyb2xsaW5nIHRoZSB3aW5kb3dcclxuXHRcdFx0XHRpZiggcG9zaXRpb24gPiBwcmV2aWV3UG9zICkge1xyXG5cdFx0XHRcdFx0c2Nyb2xsRXh0cmEgPSBwcmV2aWV3LmhlaWdodDtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0aGlkZVByZXZpZXcoKTtcclxuXHRcdFx0fVxyXG5cdFx0XHQvLyBzYW1lIHJvd1xyXG5cdFx0XHRlbHNlIHtcclxuXHRcdFx0XHRwcmV2aWV3LnVwZGF0ZSggJGl0ZW0gKTtcclxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gdXBkYXRlIHByZXZpZXdQb3NcclxuXHRcdHByZXZpZXdQb3MgPSBwb3NpdGlvbjtcclxuXHRcdC8vIGluaXRpYWxpemUgbmV3IHByZXZpZXcgZm9yIHRoZSBjbGlja2VkIGl0ZW1cclxuXHRcdHByZXZpZXcgPSAkLmRhdGEoIHRoaXMsICdwcmV2aWV3JywgbmV3IFByZXZpZXcoICRpdGVtICkgKTtcclxuXHRcdC8vIGV4cGFuZCBwcmV2aWV3IG92ZXJsYXlcclxuXHRcdHByZXZpZXcub3BlbigpO1xyXG5cclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGhpZGVQcmV2aWV3KCkge1xyXG5cdFx0Y3VycmVudCA9IC0xO1xyXG5cdFx0dmFyIHByZXZpZXcgPSAkLmRhdGEoIHRoaXMsICdwcmV2aWV3JyApO1xyXG5cdFx0cHJldmlldy5jbG9zZSgpO1xyXG5cclxuXHRcdCQucmVtb3ZlRGF0YSggdGhpcywgJ3ByZXZpZXcnICk7XHJcblx0fVxyXG5cclxuXHQvLyB0aGUgcHJldmlldyBvYmogLyBvdmVybGF5XHJcblx0ZnVuY3Rpb24gUHJldmlldyggJGl0ZW0gKSB7XHJcblx0XHR0aGlzLiRpdGVtID0gJGl0ZW07XHJcblx0XHR0aGlzLmV4cGFuZGVkSWR4ID0gdGhpcy4kaXRlbS5pbmRleCgpO1xyXG5cdFx0dGhpcy5jcmVhdGUoKTtcclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblx0fVxyXG5cclxuXHRQcmV2aWV3LnByb3RvdHlwZSA9IHtcclxuXHRcdGNyZWF0ZSA6IGZ1bmN0aW9uKCkge1xyXG5cdFx0XHQvLyBjcmVhdGUgUHJldmlldyBzdHJ1Y3R1cmU6XHJcblx0XHRcdHRoaXMuJHRpdGxlID0gJCggJzxoMz48L2gzPicgKTtcclxuXHRcdFx0dGhpcy4kdGFnID0gJCggJzxoMyBjbGFzcz1cInRhZ1wiPjwvaDM+JyApO1xyXG5cdFx0XHR0aGlzLiRocmVmID0gJCggJzxhIGhyZWY9XCIjXCI+VmlzaXQgd2Vic2l0ZTwvYT4nICk7XHJcblx0XHRcdFxyXG5cdFx0XHR0aGlzLiRmaWxlbmFtZSA9ICQoICc8cCBjbGFzcz1cImZpbGVuYW1lXCI+PC9wPicgKTtcclxuXHRcdFx0dGhpcy4kZmlsZXNpemUgPSAkKCAnPGEgaHJlZj1cIiNcIiBjbGFzcz1cImZpbGVzaXplXCI+RG93bmxvYWQ8L2E+JyApO1xyXG5cdFx0XHR0aGlzLiRkZXNjcmlwdGlvbiA9ICQoICc8cCBjbGFzcz1cImRlc2NyaXB0aW9uXCI+PC9wPicgKTtcclxuXHRcdFx0XHJcblx0XHRcdHRoaXMuJGRldGFpbHMgPSAkKCAnPGRpdiBjbGFzcz1cIm9nLWRldGFpbHNcIj48L2Rpdj4nICkuYXBwZW5kKCB0aGlzLiR0YWcsIHRoaXMuJGRlc2NyaXB0aW9uLCB0aGlzLiRmaWxlbmFtZSwgdGhpcy4kZmlsZXNpemUpO1xyXG5cdFx0XHR0aGlzLiRsb2FkaW5nID0gJCggJzxkaXYgY2xhc3M9XCJvZy1sb2FkaW5nXCI+PC9kaXY+JyApO1xyXG5cdFx0XHR0aGlzLiRmdWxsaW1hZ2UgPSAkKCAnPGRpdiBjbGFzcz1cIm9nLWZ1bGxpbWdcIj48L2Rpdj4nICkuYXBwZW5kKCB0aGlzLiRsb2FkaW5nICk7XHJcblx0XHRcdHRoaXMuJGNsb3NlUHJldmlldyA9ICQoICc8c3BhbiBjbGFzcz1cIm9nLWNsb3NlXCI+PC9zcGFuPicgKTtcclxuXHRcdFx0dGhpcy4kcHJldmlld0lubmVyID0gJCggJzxkaXYgY2xhc3M9XCJvZy1leHBhbmRlci1pbm5lclwiPjwvZGl2PicgKS5hcHBlbmQoIHRoaXMuJGNsb3NlUHJldmlldywgdGhpcy4kZnVsbGltYWdlLCB0aGlzLiRkZXRhaWxzICk7XHJcblx0XHRcdHRoaXMuJHByZXZpZXdFbCA9ICQoICc8ZGl2IGNsYXNzPVwib2ctZXhwYW5kZXJcIj48L2Rpdj4nICkuYXBwZW5kKCB0aGlzLiRwcmV2aWV3SW5uZXIgKTtcclxuXHRcdFx0Ly8gYXBwZW5kIHByZXZpZXcgZWxlbWVudCB0byB0aGUgaXRlbVxyXG5cdFx0XHR0aGlzLiRpdGVtLmFwcGVuZCggdGhpcy5nZXRFbCgpICk7XHJcblx0XHRcdC8vIHNldCB0aGUgdHJhbnNpdGlvbnMgZm9yIHRoZSBwcmV2aWV3IGFuZCB0aGUgaXRlbVxyXG5cdFx0XHRpZiggc3VwcG9ydCApIHtcclxuXHRcdFx0XHR0aGlzLnNldFRyYW5zaXRpb24oKTtcclxuXHRcdFx0fVxyXG5cdFx0fSxcclxuXHRcdHVwZGF0ZSA6IGZ1bmN0aW9uKCAkaXRlbSApIHtcclxuXHJcblx0XHRcdGlmKCAkaXRlbSApIHtcclxuXHRcdFx0XHR0aGlzLiRpdGVtID0gJGl0ZW07XHJcblx0XHRcdH1cclxuXHRcdFx0XHJcblx0XHRcdC8vIGlmIGFscmVhZHkgZXhwYW5kZWQgcmVtb3ZlIGNsYXNzIFwib2ctZXhwYW5kZWRcIiBmcm9tIGN1cnJlbnQgaXRlbSBhbmQgYWRkIGl0IHRvIG5ldyBpdGVtXHJcblx0XHRcdGlmKCBjdXJyZW50ICE9PSAtMSApIHtcclxuXHRcdFx0XHR2YXIgJGN1cnJlbnRJdGVtID0gJGl0ZW1zLmVxKCBjdXJyZW50ICk7XHJcblx0XHRcdFx0JGN1cnJlbnRJdGVtLnJlbW92ZUNsYXNzKCAnb2ctZXhwYW5kZWQnICk7XHJcblx0XHRcdFx0dGhpcy4kaXRlbS5hZGRDbGFzcyggJ29nLWV4cGFuZGVkJyApO1xyXG5cdFx0XHRcdC8vIHBvc2l0aW9uIHRoZSBwcmV2aWV3IGNvcnJlY3RseVxyXG5cdFx0XHRcdHRoaXMucG9zaXRpb25QcmV2aWV3KCk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIHVwZGF0ZSBjdXJyZW50IHZhbHVlXHJcblx0XHRcdGN1cnJlbnQgPSB0aGlzLiRpdGVtLmluZGV4KCk7XHJcblxyXG5cdFx0XHQvLyB1cGRhdGUgcHJldmlld8K0cyBjb250ZW50XHJcblx0XHRcdHZhciAkaXRlbUVsID0gdGhpcy4kaXRlbS5jaGlsZHJlbiggJ2EnICksXHJcblx0XHRcdFx0ZWxkYXRhID0ge1xyXG5cdFx0XHRcdFx0aHJlZiA6ICRpdGVtRWwuYXR0ciggJ2hyZWYnICksXHJcblx0XHRcdFx0XHR0YWcgOiAkaXRlbUVsLmRhdGEoICd0YWcnICksXHJcblx0XHRcdFx0XHRmaWxlc2l6ZSA6ICRpdGVtRWwuYXR0ciggJ2RhdGEtZmlsZXNpemUnICksXHJcblx0XHRcdFx0XHRmaWxlbmFtZSA6ICRpdGVtRWwuZGF0YSggJ2ZpbGVuYW1lJyApLFxyXG5cdFx0XHRcdFx0bGFyZ2VzcmMgOiAkaXRlbUVsLmRhdGEoICdsYXJnZXNyYycgKSxcclxuXHRcdFx0XHRcdHRpdGxlIDogJGl0ZW1FbC5kYXRhKCAndGl0bGUnICksXHJcblx0XHRcdFx0XHRkZXNjcmlwdGlvbiA6ICRpdGVtRWwuZGF0YSggJ2Rlc2NyaXB0aW9uJyApLFxyXG5cdFx0XHRcdFx0aXNWaWRlbyA6ICgkaXRlbUVsLmRhdGEoICdpc3ZpZGVvJyApLnRvTG93ZXJDYXNlKCkgPT0gJ3RydWUnKVxyXG5cdFx0XHRcdH07XHJcblx0XHRcdHRoaXMuJHRpdGxlLmh0bWwoIGVsZGF0YS50aXRsZSApO1xyXG5cdFx0XHR0aGlzLiR0YWcuaHRtbCggZWxkYXRhLnRpdGxlICk7XHJcblx0XHRcdGlmIChlbGRhdGEuaXNWaWRlbykgXHJcblx0XHRcdHsgXHJcblx0XHRcdFx0dGhpcy4kZmlsZXNpemUuaHRtbCgnV2F0Y2ggb24gVmltZW8nKS5hdHRyKCdocmVmJywgZWxkYXRhLmhyZWYpO1xyXG5cdFx0XHRcdHRoaXMuJGZpbGVuYW1lLmh0bWwoZWxkYXRhLmhyZWYpO1xyXG5cdFx0XHR9IFxyXG5cdFx0XHRlbHNlIFxyXG5cdFx0XHR7XHJcblx0XHRcdFx0dGhpcy4kZmlsZXNpemUuaHRtbCggJ0Rvd25sb2FkICcrIGVsZGF0YS5maWxlc2l6ZSApLmF0dHIoICdocmVmJywgZWxkYXRhLmhyZWYgKTtcdFxyXG5cdFx0XHRcdHRoaXMuJGZpbGVuYW1lLmh0bWwoIGVsZGF0YS5maWxlbmFtZSApO1xyXG5cdFx0XHR9XHJcblx0XHRcdFxyXG5cdFx0XHR0aGlzLiRkZXNjcmlwdGlvbi5odG1sKCBlbGRhdGEuZGVzY3JpcHRpb24gKTtcclxuXHRcdFx0dGhpcy4kaHJlZi5hdHRyKCAnaHJlZicsIGVsZGF0YS5ocmVmICk7XHJcblxyXG5cdFx0XHR2YXIgc2VsZiA9IHRoaXM7XHJcblx0XHRcdFxyXG5cdFx0XHQvLyByZW1vdmUgdGhlIGN1cnJlbnQgaW1hZ2UgaW4gdGhlIHByZXZpZXdcclxuXHRcdFx0aWYoIHR5cGVvZiBzZWxmLiRsYXJnZUltZyAhPSAndW5kZWZpbmVkJyApIHtcclxuXHRcdFx0XHRzZWxmLiRsYXJnZUltZy5yZW1vdmUoKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gcHJlbG9hZCBsYXJnZSBpbWFnZSBhbmQgYWRkIGl0IHRvIHRoZSBwcmV2aWV3XHJcblx0XHRcdC8vIGZvciBzbWFsbGVyIHNjcmVlbnMgd2UgZG9uwrR0IGRpc3BsYXkgdGhlIGxhcmdlIGltYWdlICh0aGUgbWVkaWEgcXVlcnkgd2lsbCB
3155oaWRlIHRoZSBmdWxsaW1hZ2Ugd3JhcHBlcilcclxuXHRcdFx0aWYoIHNlbGYuJGZ1bGxpbWFnZS5pcyggJzp2aXNpYmxlJyApICkge1xyXG5cdFx0XHRcdGlmKGVsZGF0YS5pc1ZpZGVvKXtcdFx0XHRcdFx0XHJcblx0XHRcdFx0XHR2YXIgJGlmcmFtZSA9ICQoJzxpZnJhbWUgd2lkdGg9XCIxMDAlXCIgaGVpZ2h0PVwiMTAwJVwiIGZyYW1lYm9yZGVyPVwiMFwiLz4nKTtcclxuXHRcdFx0XHRcdCRpZnJhbWUuYXR0ciggJ3NyYycsIHNlbGYuY2xlYW5zZVZpZGVvVXJsKGVsZGF0YS5sYXJnZXNyYykgKTtcclxuXHRcdFx0XHRcdGlmKCAkaWZyYW1lLmF0dHIoICdzcmMnICkgPT09IHNlbGYuY2xlYW5zZVZpZGVvVXJsKHNlbGYuJGl0ZW0uY2hpbGRyZW4oJ2EnKS5kYXRhKCAnbGFyZ2VzcmMnICkpICkge1xyXG5cdFx0XHRcdFx0XHRzZWxmLiRsb2FkaW5nLmhpZGUoKTtcclxuXHRcdFx0XHRcdFx0c2VsZi4kZnVsbGltYWdlLmVtcHR5KCk7XHJcblx0XHRcdFx0XHRcdHNlbGYuJGxhcmdlSW1nID0gJGlmcmFtZS5mYWRlSW4oIDM1MCApO1xyXG5cdFx0XHRcdFx0XHRzZWxmLiRmdWxsaW1hZ2UuYXBwZW5kKCBzZWxmLiRsYXJnZUltZyApO1xyXG5cdFx0XHRcdFx0fVx0XHRcdFx0XHRcdFx0XHRcdFx0XHJcblx0XHRcdFx0fWVsc2V7XHJcblx0XHRcdFx0XHR0aGlzLiRsb2FkaW5nLnNob3coKTtcclxuXHRcdFx0XHRcdCQoICc8aW1nLz4nICkubG9hZCggZnVuY3Rpb24oKSB7XHJcblx0XHRcdFx0XHRcdHZhciAkaW1nID0gJCggdGhpcyApO1xyXG5cdFx0XHRcdFx0XHRpZiggJGltZy5hdHRyKCAnc3JjJyApID09PSBzZWxmLiRpdGVtLmNoaWxkcmVuKCdhJykuZGF0YSggJ2xhcmdlc3JjJyApICkge1xyXG5cdFx0XHRcdFx0XHRcdHNlbGYuJGxvYWRpbmcuaGlkZSgpO1xyXG5cdFx0XHRcdFx0XHRcdHNlbGYuJGZ1bGxpbWFnZS5lbXB0eSgpO1xyXG5cdFx0XHRcdFx0XHRcdHNlbGYuJGxhcmdlSW1nID0gJGltZy5mYWRlSW4oIDM1MCApO1xyXG5cdFx0XHRcdFx0XHRcdHNlbGYuJGZ1bGxpbWFnZS5hcHBlbmQoIHNlbGYuJGxhcmdlSW1nICk7XHJcblx0XHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdH0pLmF0dHIoICdzcmMnLCBlbGRhdGEubGFyZ2VzcmMgKTtcclxuXHRcdFx0XHR9XHRcclxuXHRcdFx0fVxyXG5cclxuXHRcdH0sXHJcblx0XHRjbGVhbnNlVmlkZW9VcmwgOiBmdW5jdGlvbih1cmwpe1xyXG5cdFx0XHRyZXR1cm4gdXJsLnJlcGxhY2UoXCIvL3ZpbWVvLmNvbS9cIiwgJy8vcGxheWVyLnZpbWVvLmNvbS92aWRlby8nKVxyXG5cdFx0XHQucmVwbGFjZShcImh0dHA6XCIsIFwiXCIpXHJcblx0XHRcdC5yZXBsYWNlKFwiaHR0cHM6XCIsIFwiXCIpO1xyXG5cdFx0fSxcclxuXHRcdG9wZW4gOiBmdW5jdGlvbigpIHtcclxuXHJcblx0XHRcdHNldFRpbWVvdXQoICQucHJveHkoIGZ1bmN0aW9uKCkge1x0XHJcblx0XHRcdFx0Ly8gc2V0IHRoZSBoZWlnaHQgZm9yIHRoZSBwcmV2aWV3IGFuZCB0aGUgaXRlbVxyXG5cdFx0XHRcdHRoaXMuc2V0SGVpZ2h0cygpO1xyXG5cdFx0XHRcdC8vIHNjcm9sbCB0byBwb3NpdGlvbiB0aGUgcHJldmlldyBpbiB0aGUgcmlnaHQgcGxhY2VcclxuXHRcdFx0XHR0aGlzLnBvc2l0aW9uUHJldmlldygpO1xyXG5cdFx0XHR9LCB0aGlzICksIDI1ICk7XHJcblxyXG5cdFx0fSxcclxuXHRcdGNsb3NlIDogZnVuY3Rpb24oKSB7XHJcblxyXG5cdFx0XHR2YXIgc2VsZiA9IHRoaXMsXHJcblx0XHRcdFx0b25FbmRGbiA9IGZ1bmN0aW9uKCkge1xyXG5cdFx0XHRcdFx0aWYoIHN1cHBvcnQgKSB7XHJcblx0XHRcdFx0XHRcdCQoIHRoaXMgKS5vZmYoIHRyYW5zRW5kRXZlbnROYW1lICk7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRzZWxmLiRpdGVtLnJlbW92ZUNsYXNzKCAnb2ctZXhwYW5kZWQnICk7XHJcblx0XHRcdFx0XHRzZWxmLiRwcmV2aWV3RWwucmVtb3ZlKCk7XHJcblx0XHRcdFx0fTtcclxuXHJcblx0XHRcdHNldFRpbWVvdXQoICQucHJveHkoIGZ1bmN0aW9uKCkge1xyXG5cclxuXHRcdFx0XHR2YXIgdGhhdCA9IHRoaXM7XHJcblxyXG5cdFx0XHRcdGlmKCB0eXBlb2YgdGhpcy4kbGFyZ2VJbWcgIT09ICd1bmRlZmluZWQnICkge1xyXG5cdFx0XHRcdFx0dGhpcy4kbGFyZ2VJbWcuZmFkZU91dCggJ2Zhc3QnICk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHRcdHRoaXMuJHByZXZpZXdFbC5jc3MoICdoZWlnaHQnLCAwICk7XHJcblx0XHRcdFx0Ly8gdGhlIGN1cnJlbnQgZXhwYW5kZWQgaXRlbSAobWlnaHQgYmUgZGlmZmVyZW50IGZyb20gdGhpcy4kaXRlbSlcclxuXHJcblx0XHRcdFx0XHJcblx0XHRcdFx0JGdyaWQuZWFjaChmdW5jdGlvbiAoaSxkKSB7XHJcblx0XHRcdFx0XHR2YXIgJGV4cGFuZGVkSXRlbSA9ICQoZCkuY2hpbGRyZW4oJ2xpJykuZXEoIHRoYXQuZXhwYW5kZWRJZHggKTtcclxuXHRcdFx0XHRcdCRleHBhbmRlZEl0ZW0uY3NzKCAnaGVpZ2h0JywgJGV4cGFuZGVkSXRlbS5kYXRhKCAnaGVpZ2h0JyApICkub24oIHRyYW5zRW5kRXZlbnROYW1lLCBvbkVuZEZuICk7XHJcblxyXG5cdFx0XHRcdFx0aWYoICFzdXBwb3J0ICkge1xyXG5cdFx0XHRcdFx0XHRvbkVuZEZuLmNhbGwoKTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9KTtcclxuXHJcblx0XHRcdH0sIHRoaXMgKSwgMjUgKTtcclxuXHRcdFx0XHJcblx0XHRcdHJldHVybiBmYWxzZTtcclxuXHJcblx0XHR9LFxyXG5cdFx0Y2FsY0hlaWdodCA6IGZ1bmN0aW9uKCkge1xyXG5cclxuXHRcdFx0dmFyIGhlaWdodFByZXZpZXcgPSB3aW5zaXplLmhlaWdodCAtIHRoaXMuJGl0ZW0uZGF0YSggJ2hlaWdodCcgKSAtIG1hcmdpbkV4cGFuZGVkLFxyXG5cdFx0XHRcdGl0ZW1IZWlnaHQgPSB3aW5zaXplLmhlaWdodDtcclxuXHRcdFx0XHRjb25zb2xlLmxvZyhpdGVtSGVpZ2h0KTtcclxuXHRcdFx0aWYoIGhlaWdodFByZXZpZXcgPCBzZXR0aW5ncy5taW5IZWlnaHQgKSB7XHJcblx0XHRcdFx0aGVpZ2h0UHJldmlldyA9IHNldHRpbmdzLm1pbkhlaWdodDtcclxuXHRcdFx0XHRpdGVtSGVpZ2h0ID0gc2V0dGluZ3MubWluSGVpZ2h0ICsgdGh
3155pcy4kaXRlbS5kYXRhKCAnaGVpZ2h0JyApICsgbWFyZ2luRXhwYW5kZWQ7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuaGVpZ2h0ID0gaGVpZ2h0UHJldmlldztcclxuXHRcdFx0dGhpcy5pdGVtSGVpZ2h0ID0gaXRlbUhlaWdodDtcclxuXHJcblx0XHR9LFxyXG5cdFx0c2V0SGVpZ2h0cyA6IGZ1bmN0aW9uKCkge1xyXG5cclxuXHRcdFx0dmFyIHNlbGYgPSB0aGlzLFxyXG5cdFx0XHRcdG9uRW5kRm4gPSBmdW5jdGlvbigpIHtcclxuXHRcdFx0XHRcdGlmKCBzdXBwb3J0ICkge1xyXG5cdFx0XHRcdFx0XHRzZWxmLiRpdGVtLm9mZiggdHJhbnNFbmRFdmVudE5hbWUgKTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHRcdHNlbGYuJGl0ZW0uYWRkQ2xhc3MoICdvZy1leHBhbmRlZCcgKTtcclxuXHRcdFx0XHR9O1xyXG5cclxuXHRcdFx0dGhpcy5jYWxjSGVpZ2h0KCk7XHJcblx0XHRcdHRoaXMuJHByZXZpZXdFbC5jc3MoICdoZWlnaHQnLCB0aGlzLmhlaWdodCApO1xyXG5cdFx0XHR0aGlzLiRpdGVtLmNzcyggJ2hlaWdodCcsIHRoaXMuaXRlbUhlaWdodCApLm9uKCB0cmFuc0VuZEV2ZW50TmFtZSwgb25FbmRGbiApO1xyXG5cclxuXHRcdFx0aWYoICFzdXBwb3J0ICkge1xyXG5cdFx0XHRcdG9uRW5kRm4uY2FsbCgpO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSxcclxuXHRcdHBvc2l0aW9uUHJldmlldyA6IGZ1bmN0aW9uKCkge1xyXG5cclxuXHRcdFx0Ly8gc2Nyb2xsIHBhZ2VcclxuXHRcdFx0Ly8gY2FzZSAxIDogcHJldmlldyBoZWlnaHQgKyBpdGVtIGhlaWdodCBmaXRzIGluIHdpbmRvd8K0cyBoZWlnaHRcclxuXHRcdFx0Ly8gY2FzZSAyIDogcHJldmlldyBoZWlnaHQgKyBpdGVtIGhlaWdodCBkb2VzIG5vdCBmaXQgaW4gd2luZG93wrRzIGhlaWdodCBhbmQgcHJldmlldyBoZWlnaHQgaXMgc21hbGxlciB0aGFuIHdpbmRvd8K0cyBoZWlnaHRcclxuXHRcdFx0Ly8gY2FzZSAzIDogcHJldmlldyBoZWlnaHQgKyBpdGVtIGhlaWdodCBkb2VzIG5vdCBmaXQgaW4gd2luZG93wrRzIGhlaWdodCBhbmQgcHJldmlldyBoZWlnaHQgaXMgYmlnZ2VyIHRoYW4gd2luZG93wrRzIGhlaWdodFxyXG5cdFx0XHR2YXIgcG9zaXRpb24gPSB0aGlzLiRpdGVtLmRhdGEoICdvZmZzZXRUb3AnICksXHJcblx0XHRcdFx0cHJldmlld09mZnNldFQgPSB0aGlzLiRwcmV2aWV3RWwub2Zmc2V0KCkudG9wIC0gc2Nyb2xsRXh0cmEsXHJcblx0XHRcdFx0c2Nyb2xsVmFsID0gdGhpcy5oZWlnaHQgKyB0aGlzLiRpdGVtLmRhdGEoICdoZWlnaHQnICkgKyBtYXJnaW5FeHBhbmRlZCA8PSB3aW5zaXplLmhlaWdodCA/IHBvc2l0aW9uIDogdGhpcy5oZWlnaHQgPCB3aW5zaXplLmhlaWdodCA/IHByZXZpZXdPZmZzZXRUIC0gKCB3aW5zaXplLmhlaWdodCAtIHRoaXMuaGVpZ2h0ICkgOiBwcmV2aWV3T2Zmc2V0VDtcclxuXHRcdFx0XHJcblx0XHRcdCRib2R5LmFuaW1hdGUoIHsgc2Nyb2xsVG9wIDogc2Nyb2xsVmFsIH0sIHNldHRpbmdzLnNwZWVkICk7XHJcblxyXG5cdFx0fSxcclxuXHRcdHNldFRyYW5zaXRpb24gIDogZnVuY3Rpb24oKSB7XHJcblx0XHRcdHRoaXMuJHByZXZpZXdFbC5jc3MoICd0cmFuc2l0aW9uJywgJ2hlaWdodCAnICsgc2V0dGluZ3Muc3BlZWQgKyAnbXMgJyArIHNldHRpbmdzLmVhc2luZyApO1xyXG5cdFx0XHR0aGlzLiRpdGVtLmNzcyggJ3RyYW5zaXRpb24nLCAnaGVpZ2h0ICcgKyBzZXR0aW5ncy5zcGVlZCArICdtcyAnICsgc2V0dGluZ3MuZWFzaW5nICk7XHJcblx0XHR9LFxyXG5cdFx0Z2V0RWwgOiBmdW5jdGlvbigpIHtcclxuXHRcdFx0cmV0dXJuIHRoaXMuJHByZXZpZXdFbDtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdHJldHVybiB7IFxyXG5cdFx0aW5pdCA6IGluaXQsXHJcblx0XHRhZGRJdGVtcyA6IGFkZEl0ZW1zXHJcblx0fTtcclxuXHJcbn0pKCk7IiwiLyohIFBpY3R1cmVmaWxsIC0gdjMuMC4xIC0gMjAxNS0wOS0zMFxyXG4gKiBodHRwOi8vc2NvdHRqZWhsLmdpdGh1Yi5pby9waWN0dXJlZmlsbFxyXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTUgaHR0cHM6Ly9naXRodWIuY29tL3Njb3R0amVobC9waWN0dXJlZmlsbC9ibG9iL21hc3Rlci9BdXRob3JzLnR4dDsgTGljZW5zZWQgTUlUXHJcbiAqL1xyXG4vKiEgR2Vja28tUGljdHVyZSAtIHYxLjBcclxuICogaHR0cHM6Ly9naXRodWIuY29tL3Njb3R0amVobC9waWN0dXJlZmlsbC90cmVlLzMuMC9zcmMvcGx1Z2lucy9nZWNrby1waWN0dXJlXHJcbiAqIEZpcmVmb3gncyBlYXJseSBwaWN0dXJlIGltcGxlbWVudGF0aW9uIChwcmlvciB0byBGRjQxKSBpcyBzdGF0aWMgYW5kIGRvZXNcclxuICogbm90IHJlYWN0IHRvIHZpZXdwb3J0IGNoYW5nZXMuIFRoaXMgdGlueSBtb2R1bGUgZml4ZXMgdGhpcy5cclxuICovXHJcbihmdW5jdGlvbih3aW5kb3cpIHtcclxuXHQvKmpzaGludCBlcW51bGw6dHJ1ZSAqL1xyXG5cdHZhciB1YSA9IG5hdmlnYXRvci51c2VyQWdlbnQ7XHJcblxyXG5cdGlmICggd2luZG93LkhUTUxQaWN0dXJlRWxlbWVudCAmJiAoKC9lY2tvLykudGVzdCh1YSkgJiYgdWEubWF0Y2goL3J2XFw6KFxcZCspLykgJiYgUmVnRXhwLiQxIDwgNDEpICkge1xyXG5cdFx0YWRkRXZlbnRMaXN0ZW5lcihcInJlc2l6ZVwiLCAoZnVuY3Rpb24oKSB7XHJcblx0XHRcdHZhciB0aW1lcjtcclxuXHJcblx0XHRcdHZhciBkdW1teVNyYyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJzb3VyY2VcIik7XHJcblxyXG5cdFx0XHR2YXIgZml4UmVzcGltZyA9IGZ1bmN0aW9uKGltZykge1xyXG5cdFx0XHRcdHZhciBzb3VyY2UsIHNpemVzO1xyXG5cdFx0XHRcdHZhciBwaWN0dXJlID0gaW1nLnBhcmVudE5vZGU7XHJcblxyXG5cdFx0XHRcdGlmIChwaWN0dXJlLm5vZGVOYW1lLnRvVXBwZXJDYXNlKCkgPT09IFwiUElDVFVSRVwiKSB7XHJcblx0XHRcdFx0XHRzb3VyY2UgPSBkdW1teVNyYy5jbG9uZU5vZGUoKTtcclxuXHJcblx0XHRcdFx0XHRwaWN0dXJlLmluc2VydEJlZm9yZShzb3VyY2UsIHBpY3R1cmUuZmlyc3RFbGVtZW50Q2hpbGQpO1xyXG5cdFx0XHRcdFx0c2V0VGltZW91dChmdW5jdGlvbigpIHtcclxuXHRcdFx0XHRcdFx0cGljdHVyZS5yZW1vdmVDaGlsZChzb3VyY2UpO1xyXG5cdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0fSBlbHNlIGlmICghaW1nLl9wZkxhc3RTaXplIHx8IGltZy5vZmZzZXRXaWR0aCA+IGltZy5fcGZMYXN0U2l6ZSkge1xyXG5cdFx0XHRcdFx0aW1nLl9wZkxhc3RTaXplID0gaW1nLm9mZnNldFdpZHRoO1xyXG5cdFx0XHRcdFx0c2l6ZXMgPSBpbWcuc2l6ZXM7XHJcblx0XHRcdFx0XHRpbWcuc2l6ZXMgKz0gXCIsMTAwdndcIjtcclxuXHRcdFx0XHRcdHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XHJcblx0XHRcdFx0XHRcdGltZy5zaXplcyA9IHNpemVzO1xyXG5cdFx0XHRcdFx0fSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9O1xyXG5cclxuXHRcdFx0dmFyIGZpbmRQaWN0dXJlSW1ncyA9IGZ1bmN0aW9uKCkge1xyXG5cdFx0XHRcdHZhciBpO1xyXG5cdFx0XHRcdHZhciBpbWdzID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvckFsbChcInBpY3R1cmUgPiBpbWcsIGltZ1tzcmNzZXRdW3NpemVzXVwiKTtcclxuXHRcdFx0XHRmb3IgKGkgPSAwOyBpIDwgaW1ncy5sZW5ndGg7IGkrKykge1xyXG5cdFx0XHRcdFx0Zml4UmVzcGltZy
3155hpbWdzW2ldKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH07XHJcblx0XHRcdHZhciBvblJlc2l6ZSA9IGZ1bmN0aW9uKCkge1xyXG5cdFx0XHRcdGNsZWFyVGltZW91dCh0aW1lcik7XHJcblx0XHRcdFx0dGltZXIgPSBzZXRUaW1lb3V0KGZpbmRQaWN0dXJlSW1ncywgOTkpO1xyXG5cdFx0XHR9O1xyXG5cdFx0XHR2YXIgbXEgPSB3aW5kb3cubWF0Y2hNZWRpYSAmJiBtYXRjaE1lZGlhKFwiKG9yaWVudGF0aW9uOiBsYW5kc2NhcGUpXCIpO1xyXG5cdFx0XHR2YXIgaW5pdCA9IGZ1bmN0aW9uKCkge1xyXG5cdFx0XHRcdG9uUmVzaXplKCk7XHJcblxyXG5cdFx0XHRcdGlmIChtcSAmJiBtcS5hZGRMaXN0ZW5lcikge1xyXG5cdFx0XHRcdFx0bXEuYWRkTGlzdGVuZXIob25SZXNpemUpO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fTtcclxuXHJcblx0XHRcdGR1bW15U3JjLnNyY3NldCA9IFwiZGF0YTppbWFnZS9naWY7YmFzZTY0LFIwbEdPRGxoQVFBQkFBQUFBQ0g1QkFFS0FBRUFMQUFBQUFBQkFBRUFBQUlDVEFFQU93PT1cIjtcclxuXHJcblx0XHRcdGlmICgvXltjfGldfGQkLy50ZXN0KGRvY3VtZW50LnJlYWR5U3RhdGUgfHwgXCJcIikpIHtcclxuXHRcdFx0XHRpbml0KCk7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lcihcIkRPTUNvbnRlbnRMb2FkZWRcIiwgaW5pdCk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHJldHVybiBvblJlc2l6ZTtcclxuXHRcdH0pKCkpO1xyXG5cdH1cclxufSkod2luZG93KTtcclxuXHJcbi8qISBQaWN0dXJlZmlsbCAtIHYzLjAuMVxyXG4gKiBodHRwOi8vc2NvdHRqZWhsLmdpdGh1Yi5pby9waWN0dXJlZmlsbFxyXG4gKiBDb3B5cmlnaHQgKGMpIDIwMTUgaHR0cHM6Ly9naXRodWIuY29tL3Njb3R0amVobC9waWN0dXJlZmlsbC9ibG9iL21hc3Rlci9BdXRob3JzLnR4dDtcclxuICogIExpY2Vuc2U6IE1JVFxyXG4gKi9cclxuXHJcbihmdW5jdGlvbiggd2luZG93LCBkb2N1bWVudCwgdW5kZWZpbmVkICkge1xyXG5cdC8vIEVuYWJsZSBzdHJpY3QgbW9kZVxyXG5cdFwidXNlIHN0cmljdFwiO1xyXG5cclxuXHQvLyBIVE1MIHNoaW18diBpdCBmb3Igb2xkIElFIChJRTkgd2lsbCBzdGlsbCBuZWVkIHRoZSBIVE1MIHZpZGVvIHRhZyB3b3JrYXJvdW5kKVxyXG5cdGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwicGljdHVyZVwiICk7XHJcblxyXG5cdHZhciB3YXJuLCBlbWlucHgsIGFsd2F5c0NoZWNrV0Rlc2NyaXB0b3IsIGV2YWxJZDtcclxuXHQvLyBsb2NhbCBvYmplY3QgZm9yIG1ldGhvZCByZWZlcmVuY2VzIGFuZCB0ZXN0aW5nIGV4cG9zdXJlXHJcblx0dmFyIHBmID0ge307XHJcblx0dmFyIG5vb3AgPSBmdW5jdGlvbigpIHt9O1xyXG5cdHZhciBpbWFnZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiaW1nXCIgKTtcclxuXHR2YXIgZ2V0SW1nQXR0ciA9IGltYWdlLmdldEF0dHJpYnV0ZTtcclxuXHR2YXIgc2V0SW1nQXR0ciA9IGltYWdlLnNldEF0dHJpYnV0ZTtcclxuXHR2YXIgcmVtb3ZlSW1nQXR0ciA9IGltYWdlLnJlbW92ZUF0dHJpYnV0ZTtcclxuXHR2YXIgZG9jRWxlbSA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcclxuXHR2YXIgdHlwZXMgPSB7fTtcclxuXHR2YXIgY2ZnID0ge1xyXG5cdFx0Ly9yZXNvdXJjZSBzZWxlY3Rpb246XHJcblx0XHRhbGdvcml0aG06IFwiXCJcclxuXHR9O1xyXG5cdHZhciBzcmNBdHRyID0gXCJkYXRhLXBmc3JjXCI7XHJcblx0dmFyIHNyY3NldEF0dHIgPSBzcmNBdHRyICsgXCJzZXRcIjtcclxuXHQvLyB1YSBzbmlmZmluZyBpcyBkb25lIGZvciB1bmRldGVjdGFibGUgaW1nIGxvYWRpbmcgZmVhdHVyZXMsXHJcblx0Ly8gdG8gZG8gc29tZSBub24gY3J1Y2lhbCBwZXJmIG9wdGltaXphdGlvbnNcclxuXHR2YXIgdWEgPSBuYXZpZ2F0b3IudXNlckFnZW50O1xyXG5cdHZhciBzdXBwb3J0QWJvcnQgPSAoL3JpZGVudC8pLnRlc3QodWEpIHx8ICgoL2Vja28vKS50ZXN0KHVhKSAmJiB1YS5tYXRjaCgvcnZcXDooXFxkKykvKSAmJiBSZWdFeHAuJDEgPiAzNSApO1xyXG5cdHZhciBjdXJTcmNQcm9wID0gXCJjdXJyZW50U3JjXCI7XHJcblx0dmFyIHJlZ1dEZXNjID0gL1xccytcXCs/XFxkKyhlXFxkKyk/dy87XHJcblx0dmFyIHJlZ1NpemUgPSAvKFxcKFteKV0rXFwpKT9cXHMqKC4rKS87XHJcblx0dmFyIHNldE9wdGlvbnMgPSB3aW5kb3cucGljdHVyZWZpbGxDRkc7XHJcblx0LyoqXHJcblx0ICogU2hvcnRjdXQgcHJvcGVydHkgZm9yIGh0dHBzOi8vdzNjLmdpdGh1Yi5pby93ZWJhcHBzZWMvc3BlY3MvbWl4ZWRjb250ZW50LyNyZXN0cmljdHMtbWl4ZWQtY29udGVudCAoIGZvciBlYXN5IG92ZXJyaWRpbmcgaW4gdGVzdHMgKVxyXG5cdCAqL1xyXG5cdC8vIGJhc2VTdHlsZSBhbHNvIHVzZWQgYnkgZ2V0RW1WYWx1ZSAoaS5lLjogd2lkdGg6IDFlbSBpcyBpbXBvcnRhbnQpXHJcblx0dmFyIGJhc2VTdHlsZSA9IFwicG9zaXRpb246YWJzb2x1dGU7bGVmdDowO3Zpc2liaWxpdHk6aGlkZGVuO2Rpc3BsYXk6YmxvY2s7cGFkZGluZzowO2JvcmRlcjpub25lO2ZvbnQtc2l6ZToxZW07d2lkdGg6MWVtO292ZXJmbG93OmhpZGRlbjtjbGlwOnJlY3QoMHB4LCAwcHgsIDBweCwgMHB4KVwiO1xyXG5cdHZhciBmc0NzcyA9IFwiZm9udC1zaXplOjEwMCUhaW1wb3J0YW50O1wiO1xyXG5cdHZhciBpc1Z3RGlydHkgPSB0cnVlO1xyXG5cclxuXHR2YXIgY3NzQ2FjaGUgPSB7fTtcclxuXHR2YXIgc2l6ZUxlbmd0aENhY2hlID0ge307XHJcblx0dmFyIERQUiA9IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvO1xyXG5cdHZhciB1bml0cyA9IHtcclxuXHRcdHB4OiAxLFxyXG5cdFx0XCJpblwiOiA5NlxyXG5cdH07XHJcblx0dmFyIGFuY2hvciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiYVwiICk7XHJcblx0LyoqXHJcblx0ICogYWxyZWFkeVJ1biBmbGFnIHVzZWQgZm9yIHNldE9wdGlvbnMuIGlzIGl0IHRydWUgc2V0T3B0aW9ucyB3aWxsIHJlZXZhbHVhdGVcclxuXHQgKiBAdHlwZSB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHR2YXIgYWxyZWFkeVJ1biA9IGZhbHNlO1xyXG5cclxuXHQvLyBSZXVzYWJsZSwgbm9uLVwiZ1wiIFJlZ2V4ZXNcclxuXHJcblx0Ly8gKERvbid0IHVzZSBcXHMsIHRvIGF2b2lkIG1hdGNoaW5nIG5vbi1icmVha2luZyBzcGFjZS4pXHJcblx0dmFyIHJlZ2V4TGVhZGluZ1NwYWNlcyA9IC9eWyBcXHRcXG5cXHJcXHUwMDBjXSsvLFxyXG5cdCAgICByZWdleExlYWRpbmdDb21tYXNPclNwYWNlcyA9IC9eWywgXFx0XFxuXFxyXFx1MDAwY10rLyxcclxuXHQgICAgcmVnZXhMZWFkaW5nTm90U3BhY2VzID0gL15bXiBcXHRcXG5cXHJcXHUwMDBjXSsvLFxyXG5cdCAgICByZWdleFRyYWlsaW5nQ29tbWFzID0gL1ssXSskLyxcclxuXHQgICAgcmVnZXhOb25OZWdhdGl2ZUludGVnZXIgPSAvXlxcZCskLyxcclxuXHJcblx0ICAgIC8vICggUG9zaXRpdmUgb3IgbmVnYXRpdmUgb3IgdW5zaWduZWQgaW50ZWdlcnMgb3IgZGVjaW1hbHMsIHdpdGhvdXQgb3Igd2l0aG91dCBleHBvbmVudHMuXHJcblx0ICAgIC8vIE11c3QgaW5jbHVkZSBhdCBsZWFzdCBvbmUgZGlnaXQuXHJcblx0ICAgIC8vIEFjY29yZGluZyB0byBzcGVjIHRlc3RzIGFueSBkZWNpbWFsIHBvaW50IG11c3QgYmUgZm9sbG93ZWQgYnkgYSBkaWdpdC5cclxuXHQgICAgLy8gTm8gbGVhZGluZyBwbHVzIHNpZ24gaXMgYWxsb3dlZC4pXHJcblx0ICAgIC8vIGh0dHBzOi8vaHRtbC5zcGVjLndoYXR3Zy5vcmcvbXVsdGlwYWdlL2luZnJhc3RydWN0dXJlLmh0bWwjdmFsaWQtZmxvYXRpbmctcG9pbnQtbnVtYmVyXHJcblx0ICAgIHJlZ2V4RmxvYXRpbmdQb2ludCA9IC9eLT8oPzpbMC05XSt8WzAtOV0qXFwuWzAtOV0rKSg/OltlRV1bKy1dP1swLTldKyk/JC87XHJcblxyXG5cdHZhciBvbiA9IGZ1bmN0aW9uKG9iaiwgZXZ0LCBmbiwgY2FwdHVyZSkge1xyXG5cdFx0aWYgKCBvYmouYWRkRXZlbnRMaXN0ZW5lciApIHtcclxuXHRcdFx0b2JqLmFkZEV2ZW50TGlzdGVuZXIoZXZ0LCBmbiwgY2FwdHVyZSB8fCBmYWxzZSk7XHJcblx0XHR9IGVsc2UgaWYgKCBvYmouYXR0YWNoRXZlbnQgKSB7XHJcblx0XHRcdG9iai5hdHRhY2hFdmVudCggXCJvblwiICsgZXZ0LCBmbik7XHJcblx0XHR9XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogc2ltcGxlIG1lbW9pemUgZnVuY3Rpb246XHJcblx0ICovXHJcblxyXG5cdHZhciBtZW1vaXplID0gZnVuY3Rpb24oZm4pIHtcclxuXHRcdHZhciBjYWNoZSA9IHt9O1xyXG5cdFx0cmV0dXJuIGZ1bmN0aW9uKGlucHV0KSB7XHJcblx0XHRcdGlmICggIShpbnB1dCBpbiBjYWNoZSkgKSB7XHJcblx0XHRcdFx0Y2FjaGVbIGlucHV0IF0gPSBmbihpbnB1dCk7XHJcblx0XHRcdH1cclxuXHRcdFx0cmV0dXJuIGNhY2hlWyBpbnB1dCBdO1xyXG5cdFx0fTtcclxuXHR9O1xyXG5cclxuXHQvLyBVVElMSVRZIEZVTkNUSU9OU1xyXG5cclxuXHQvLyBNYW51YWwgaXMgZmFzdGVyIHRoYW4gUmVnRXhcclxuXHQvLyBodHRwOi8vanNwZXJmLmNvbS93aGl0ZXNwYWNlLWNoYXJhY3Rlci81XHJcblx0ZnVuY3Rpb24gaXNTcGFjZShjKSB7XHJcblx0XHRyZXR1cm4gKGMgPT09IFwiXFx1MDAyMFwiIHx8IC8vIHNwYWNlXHJcblx0XHQgICAgICAgIGMgPT09IFwiXFx1MDAwOVwiIHx8IC8vIGhvcml6b250YWwgdGFiXHJcblx0XHQgICAgICAgIGMgPT09IFwiXFx1MDAwQVwiIHx8IC8vIG5ldyBsaW5lXHJcblx0XHQgICAgICAgIGMgPT09IFwiXFx1MDAwQ1wiIHx8IC8vIGZvcm0gZmVlZFxyXG5cdFx0ICAgICAgICBjID09PSBcIlxcdTAwMERcIik7ICAvLyBjYXJyaWFnZSByZXR1cm5cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIGdldHMgYSBtZWRpYXF1ZXJ5IGFuZCByZXR1cm5zIGEgYm9vbGVhbiBvciBnZXRzIGEgY3NzIGxlbmd0aCBhbmQgcmV0dXJucyBhIG51bWJlclxyXG5cdCAqIEBwYXJhbSBjc3MgbWVkaWFxdWVyaWVzIG9yIGNzcyBsZW5ndGhcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbnxudW1iZXJ9XHJcblx0ICpcclxuXHQgKiBiYXNlZCBvbjogaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20vam9uYXRoYW50bmVhbC9kYjRmNzcwMDliMTU1ZjA4MzczOFxyXG5cdCAqL1xyXG5cdHZhciBldmFsQ1NTID0gKGZ1bmN0aW9uKCkge1xyXG5cclxuXHRcdHZhciByZWdMZW5ndGggPSAvXihbXFxkXFwuXSspKGVtfHZ3fHB4KSQvO1xyXG5cdFx0dmFyIHJlcGxhY2UgPSBmdW5jdGlvbigpIHtcclxuXHRcdFx0dmFyIGFyZ3MgPSBhcmd1bWVudHMsIGluZGV4ID0gMCwgc3RyaW5nID0gYXJnc1swXTtcclxuXHRcdFx0d2hpbGUgKCsraW5kZXggaW4gYXJncykge1xyXG5cdFx0XHRcdHN0cmluZyA9IHN0cmluZy5yZXBsYWNlKGFyZ3NbaW5kZXhdLCBhcmdzWysraW5kZXhdKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gc3RyaW5nO1xyXG5cdFx0fTtcclxuXHJcblx0XHR2YXIgYnVpbGRTdHIgPSBtZW1vaXplKGZ1bmN0aW9uKGNzcykge1xyXG5cclxuXHRcdFx0cmV0dXJuIFwicmV0dXJuIFwiICsgcmVwbGFjZSgoY3NzIHx8IFwiXCIpLnRvTG93ZXJDYXNlKCksXHJcblx0XHRcdFx0Ly8gaW50ZXJwcmV0IGBhbmRgXHJcblx0XHRcdFx0L1xcYmFuZFxcYi9nLCBcIiYmXCIsXHJcblxyXG5cdFx0XHRcdC8vIGludGVycHJldCBgLGBcclxuXHRcdFx0XHQvLC9nLCBcInx8XCIsXHJcblxyXG5cdFx0XHRcdC8vIGludGVycHJldCBgbWluLWAgYXMgPj1cclxuXHRcdFx0XHQvbWluLShbYS16LVxcc10rKTovZywgXCJlLiQxPj1cIixcclxuXHJcblx0XHRcdFx0Ly8gaW50ZXJwcmV0IGBtYXgtYCBhcyA8PVxyXG5cdFx0XHRcdC9tYXgtKFthLXotXFxzXSspOi9nLCBcImUuJDE8PVwiLFxyXG5cclxuXHRcdFx0XHQvL2NhbGMgdmFsdWVcclxuXHRcdFx0XHQvY2FsYyhbXildKykvZywgXCIoJDEpXCIsXHJcblxyXG5cdFx0XHRcdC8vIGludGVycHJldCBjc3MgdmFsdWVzXHJcblx0XHRcdFx0LyhcXGQrW1xcLl0qW1xcZF0qKShbYS16XSspL2csIFwiKCQxICogZS4kMilcIixcclxuXHRcdFx0XHQvL21ha2UgZXZhbCBsZXNzIGV2aWxcclxuXHRcdFx0XHQvXig/IShlLlthLXpdfFswLTlcXC4mPXw+PFxcK1xcLVxcKlxcKFxcKVxcL10pKS4qL2lnLCBcIlwiXHJcblx0XHRcdCkgKyBcIjtcIjtcclxuXHRcdH0pO1xyXG5cclxuXHRcdHJldHVybi
3155BmdW5jdGlvbihjc3MsIGxlbmd0aCkge1xyXG5cdFx0XHR2YXIgcGFyc2VkTGVuZ3RoO1xyXG5cdFx0XHRpZiAoIShjc3MgaW4gY3NzQ2FjaGUpKSB7XHJcblx0XHRcdFx0Y3NzQ2FjaGVbY3NzXSA9IGZhbHNlO1xyXG5cdFx0XHRcdGlmIChsZW5ndGggJiYgKHBhcnNlZExlbmd0aCA9IGNzcy5tYXRjaCggcmVnTGVuZ3RoICkpKSB7XHJcblx0XHRcdFx0XHRjc3NDYWNoZVtjc3NdID0gcGFyc2VkTGVuZ3RoWyAxIF0gKiB1bml0c1twYXJzZWRMZW5ndGhbIDIgXV07XHJcblx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdC8qanNoaW50IGV2aWw6dHJ1ZSAqL1xyXG5cdFx0XHRcdFx0dHJ5e1xyXG5cdFx0XHRcdFx0XHRjc3NDYWNoZVtjc3NdID0gbmV3IEZ1bmN0aW9uKFwiZVwiLCBidWlsZFN0cihjc3MpKSh1bml0cyk7XHJcblx0XHRcdFx0XHR9IGNhdGNoKGUpIHt9XHJcblx0XHRcdFx0XHQvKmpzaGludCBldmlsOmZhbHNlICovXHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBjc3NDYWNoZVtjc3NdO1xyXG5cdFx0fTtcclxuXHR9KSgpO1xyXG5cclxuXHR2YXIgc2V0UmVzb2x1dGlvbiA9IGZ1bmN0aW9uKCBjYW5kaWRhdGUsIHNpemVzYXR0ciApIHtcclxuXHRcdGlmICggY2FuZGlkYXRlLncgKSB7IC8vIGggPSBtZWFucyBoZWlnaHQ6IHx8IGRlc2NyaXB0b3IudHlwZSA9PT0gJ2gnIGRvIG5vdCBoYW5kbGUgeWV0Li4uXHJcblx0XHRcdGNhbmRpZGF0ZS5jV2lkdGggPSBwZi5jYWxjTGlzdExlbmd0aCggc2l6ZXNhdHRyIHx8IFwiMTAwdndcIiApO1xyXG5cdFx0XHRjYW5kaWRhdGUucmVzID0gY2FuZGlkYXRlLncgLyBjYW5kaWRhdGUuY1dpZHRoIDtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGNhbmRpZGF0ZS5yZXMgPSBjYW5kaWRhdGUuZDtcclxuXHRcdH1cclxuXHRcdHJldHVybiBjYW5kaWRhdGU7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICpcclxuXHQgKiBAcGFyYW0gb3B0XHJcblx0ICovXHJcblx0dmFyIHBpY3R1cmVmaWxsID0gZnVuY3Rpb24oIG9wdCApIHtcclxuXHRcdHZhciBlbGVtZW50cywgaSwgcGxlbjtcclxuXHJcblx0XHR2YXIgb3B0aW9ucyA9IG9wdCB8fCB7fTtcclxuXHJcblx0XHRpZiAoIG9wdGlvbnMuZWxlbWVudHMgJiYgb3B0aW9ucy5lbGVtZW50cy5ub2RlVHlwZSA9PT0gMSApIHtcclxuXHRcdFx0aWYgKCBvcHRpb25zLmVsZW1lbnRzLm5vZGVOYW1lLnRvVXBwZXJDYXNlKCkgPT09IFwiSU1HXCIgKSB7XHJcblx0XHRcdFx0b3B0aW9ucy5lbGVtZW50cyA9ICBbIG9wdGlvbnMuZWxlbWVudHMgXTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRvcHRpb25zLmNvbnRleHQgPSBvcHRpb25zLmVsZW1lbnRzO1xyXG5cdFx0XHRcdG9wdGlvbnMuZWxlbWVudHMgPSAgbnVsbDtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdGVsZW1lbnRzID0gb3B0aW9ucy5lbGVtZW50cyB8fCBwZi5xc2EoIChvcHRpb25zLmNvbnRleHQgfHwgZG9jdW1lbnQpLCAoIG9wdGlvbnMucmVldmFsdWF0ZSB8fCBvcHRpb25zLnJlc2VsZWN0ICkgPyBwZi5zZWwgOiBwZi5zZWxTaG9ydCApO1xyXG5cclxuXHRcdGlmICggKHBsZW4gPSBlbGVtZW50cy5sZW5ndGgpICkge1xyXG5cclxuXHRcdFx0cGYuc2V0dXBSdW4oIG9wdGlvbnMgKTtcclxuXHRcdFx0YWxyZWFkeVJ1biA9IHRydWU7XHJcblxyXG5cdFx0XHQvLyBMb29wIHRocm91Z2ggYWxsIGVsZW1lbnRzXHJcblx0XHRcdGZvciAoIGkgPSAwOyBpIDwgcGxlbjsgaSsrICkge1xyXG5cdFx0XHRcdHBmLmZpbGxJbWcoZWxlbWVudHNbIGkgXSwgb3B0aW9ucyk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHBmLnRlYXJkb3duUnVuKCBvcHRpb25zICk7XHJcblx0XHR9XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogb3V0cHV0cyBhIHdhcm5pbmcgZm9yIHRoZSBkZXZlbG9wZXJcclxuXHQgKiBAcGFyYW0ge21lc3NhZ2V9XHJcblx0ICogQHR5cGUge0Z1bmN0aW9ufVxyXG5cdCAqL1xyXG5cdHdhcm4gPSAoIHdpbmRvdy5jb25zb2xlICYmIGNvbnNvbGUud2FybiApID9cclxuXHRcdGZ1bmN0aW9uKCBtZXNzYWdlICkge1xyXG5cdFx0XHRjb25zb2xlLndhcm4oIG1lc3NhZ2UgKTtcclxuXHRcdH0gOlxyXG5cdFx0bm9vcFxyXG5cdDtcclxuXHJcblx0aWYgKCAhKGN1clNyY1Byb3AgaW4gaW1hZ2UpICkge1xyXG5cdFx0Y3VyU3JjUHJvcCA9IFwic3JjXCI7XHJcblx0fVxyXG5cclxuXHQvLyBBZGQgc3VwcG9ydCBmb3Igc3RhbmRhcmQgbWltZSB0eXBlcy5cclxuXHR0eXBlc1sgXCJpbWFnZS9qcGVnXCIgXSA9IHRydWU7XHJcblx0dHlwZXNbIFwiaW1hZ2UvZ2lmXCIgXSA9IHRydWU7XHJcblx0dHlwZXNbIFwiaW1hZ2UvcG5nXCIgXSA9IHRydWU7XHJcblxyXG5cdGZ1bmN0aW9uIGRldGVjdFR5cGVTdXBwb3J0KCB0eXBlLCB0eXBlVXJpICkge1xyXG5cdFx0Ly8gYmFzZWQgb24gTW9kZXJuaXpyJ3MgbG9zc2xlc3MgaW1nLXdlYnAgdGVzdFxyXG5cdFx0Ly8gbm90ZTogYXN5bmNocm9ub3VzXHJcblx0XHR2YXIgaW1hZ2UgPSBuZXcgd2luZG93LkltYWdlKCk7XHJcblx0XHRpbWFnZS5vbmVycm9yID0gZnVuY3Rpb24oKSB7XHJcblx0XHRcdHR5cGVzWyB0eXBlIF0gPSBmYWxzZTtcclxuXHRcdFx0cGljdHVyZWZpbGwoKTtcclxuXHRcdH07XHJcblx0XHRpbWFnZS5vbmxvYWQgPSBmdW5jdGlvbigpIHtcclxuXHRcdFx0dHlwZXNbIHR5cGUgXSA9IGltYWdlLndpZHRoID09PSAxO1xyXG5cdFx0XHRwaWN0dXJlZmlsbCgpO1xyXG5cdFx0fTtcclxuXHRcdGltYWdlLnNyYyA9IHR5cGVVcmk7XHJcblx0XHRyZXR1cm4gXCJwZW5kaW5nXCI7XHJcblx0fVxyXG5cclxuXHQvLyB0ZXN0IHN2ZyBzdXBwb3J0XHJcblx0dHlwZXNbIFwiaW1hZ2Uvc3ZnK3htbFwiIF0gPSBkb2N1bWVudC5pbXBsZW1lbnRhdGlvbi5oYXNGZWF0dXJlKCBcImh0dHA6Ly93d3dpbmRvdy53My5vcmcvVFIvU1ZHMTEvZmVhdHVyZSNJbWFnZVwiLCBcIjEuMVwiICk7XHJcblxyXG5cdC8qKlxyXG5cdCAqIHVwZGF0ZXMgdGhlIGludGVybmFsIHZXIHByb3BlcnR5IHdpdGggdGhlIGN1cnJlbnQgdmlld3BvcnQgd2lkdGggaW4gcHhcclxuXHQgKi9cclxuXHRmdW5jdGlvbiB1cGRhdGVNZXRyaWNzKCkge1xyXG5cclxuXHRcdGlzVndEaXJ0eSA9IGZ
3155hbHNlO1xyXG5cdFx0RFBSID0gd2luZG93LmRldmljZVBpeGVsUmF0aW87XHJcblx0XHRjc3NDYWNoZSA9IHt9O1xyXG5cdFx0c2l6ZUxlbmd0aENhY2hlID0ge307XHJcblxyXG5cdFx0cGYuRFBSID0gRFBSIHx8IDE7XHJcblxyXG5cdFx0dW5pdHMud2lkdGggPSBNYXRoLm1heCh3aW5kb3cuaW5uZXJXaWR0aCB8fCAwLCBkb2NFbGVtLmNsaWVudFdpZHRoKTtcclxuXHRcdHVuaXRzLmhlaWdodCA9IE1hdGgubWF4KHdpbmRvdy5pbm5lckhlaWdodCB8fCAwLCBkb2NFbGVtLmNsaWVudEhlaWdodCk7XHJcblxyXG5cdFx0dW5pdHMudncgPSB1bml0cy53aWR0aCAvIDEwMDtcclxuXHRcdHVuaXRzLnZoID0gdW5pdHMuaGVpZ2h0IC8gMTAwO1xyXG5cclxuXHRcdGV2YWxJZCA9IFsgdW5pdHMuaGVpZ2h0LCB1bml0cy53aWR0aCwgRFBSIF0uam9pbihcIi1cIik7XHJcblxyXG5cdFx0dW5pdHMuZW0gPSBwZi5nZXRFbVZhbHVlKCk7XHJcblx0XHR1bml0cy5yZW0gPSB1bml0cy5lbTtcclxuXHR9XHJcblxyXG5cdGZ1bmN0aW9uIGNob29zZUxvd1JlcyggbG93ZXJWYWx1ZSwgaGlnaGVyVmFsdWUsIGRwclZhbHVlLCBpc0NhY2hlZCApIHtcclxuXHRcdHZhciBib251c0ZhY3RvciwgdG9vTXVjaCwgYm9udXMsIG1lYW5EZW5zaXR5O1xyXG5cclxuXHRcdC8vZXhwZXJpbWVudGFsXHJcblx0XHRpZiAoY2ZnLmFsZ29yaXRobSA9PT0gXCJzYXZlRGF0YVwiICl7XHJcblx0XHRcdGlmICggbG93ZXJWYWx1ZSA+IDIuNyApIHtcclxuXHRcdFx0XHRtZWFuRGVuc2l0eSA9IGRwclZhbHVlICsgMTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHR0b29NdWNoID0gaGlnaGVyVmFsdWUgLSBkcHJWYWx1ZTtcclxuXHRcdFx0XHRib251c0ZhY3RvciA9IE1hdGgucG93KGxvd2VyVmFsdWUgLSAwLjYsIDEuNSk7XHJcblxyXG5cdFx0XHRcdGJvbnVzID0gdG9vTXVjaCAqIGJvbnVzRmFjdG9yO1xyXG5cclxuXHRcdFx0XHRpZiAoaXNDYWNoZWQpIHtcclxuXHRcdFx0XHRcdGJvbnVzICs9IDAuMSAqIGJvbnVzRmFjdG9yO1xyXG5cdFx0XHRcdH1cclxuXHJcblx0XHRcdFx0bWVhbkRlbnNpdHkgPSBsb3dlclZhbHVlICsgYm9udXM7XHJcblx0XHRcdH1cclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdG1lYW5EZW5zaXR5ID0gKGRwclZhbHVlID4gMSkgP1xyXG5cdFx0XHRcdE1hdGguc3FydChsb3dlclZhbHVlICogaGlnaGVyVmFsdWUpIDpcclxuXHRcdFx0XHRsb3dlclZhbHVlO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBtZWFuRGVuc2l0eSA+IGRwclZhbHVlO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gYXBwbHlCZXN0Q2FuZGlkYXRlKCBpbWcgKSB7XHJcblx0XHR2YXIgc3JjU2V0Q2FuZGlkYXRlcztcclxuXHRcdHZhciBtYXRjaGluZ1NldCA9IHBmLmdldFNldCggaW1nICk7XHJcblx0XHR2YXIgZXZhbHVhdGVkID0gZmFsc2U7XHJcblx0XHRpZiAoIG1hdGNoaW5nU2V0ICE9PSBcInBlbmRpbmdcIiApIHtcclxuXHRcdFx0ZXZhbHVhdGVkID0gZXZhbElkO1xyXG5cdFx0XHRpZiAoIG1hdGNoaW5nU2V0ICkge1xyXG5cdFx0XHRcdHNyY1NldENhbmRpZGF0ZXMgPSBwZi5zZXRSZXMoIG1hdGNoaW5nU2V0ICk7XHJcblx0XHRcdFx0cGYuYXBwbHlTZXRDYW5kaWRhdGUoIHNyY1NldENhbmRpZGF0ZXMsIGltZyApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRpbWdbIHBmLm5zIF0uZXZhbGVkID0gZXZhbHVhdGVkO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gYXNjZW5kaW5nU29ydCggYSwgYiApIHtcclxuXHRcdHJldHVybiBhLnJlcyAtIGIucmVzO1xyXG5cdH1cclxuXHJcblx0ZnVuY3Rpb24gc2V0U3JjVG9DdXIoIGltZywgc3JjLCBzZXQgKSB7XHJcblx0XHR2YXIgY2FuZGlkYXRlO1xyXG5cdFx0aWYgKCAhc2V0ICYmIHNyYyApIHtcclxuXHRcdFx0c2V0ID0gaW1nWyBwZi5ucyBdLnNldHM7XHJcblx0XHRcdHNldCA9IHNldCAmJiBzZXRbc2V0Lmxlbmd0aCAtIDFdO1xyXG5cdFx0fVxyXG5cclxuXHRcdGNhbmRpZGF0ZSA9IGdldENhbmRpZGF0ZUZvclNyYyhzcmMsIHNldCk7XHJcblxyXG5cdFx0aWYgKCBjYW5kaWRhdGUgKSB7XHJcblx0XHRcdHNyYyA9IHBmLm1ha2VVcmwoc3JjKTtcclxuXHRcdFx0aW1nWyBwZi5ucyBdLmN1clNyYyA9IHNyYztcclxuXHRcdFx0aW1nWyBwZi5ucyBdLmN1ckNhbiA9IGNhbmRpZGF0ZTtcclxuXHJcblx0XHRcdGlmICggIWNhbmRpZGF0ZS5yZXMgKSB7XHJcblx0XHRcdFx0c2V0UmVzb2x1dGlvbiggY2FuZGlkYXRlLCBjYW5kaWRhdGUuc2V0LnNpemVzICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdHJldHVybiBjYW5kaWRhdGU7XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRDYW5kaWRhdGVGb3JTcmMoIHNyYywgc2V0ICkge1xyXG5cdFx0dmFyIGksIGNhbmRpZGF0ZSwgY2FuZGlkYXRlcztcclxuXHRcdGlmICggc3JjICYmIHNldCApIHtcclxuXHRcdFx0Y2FuZGlkYXRlcyA9IHBmLnBhcnNlU2V0KCBzZXQgKTtcclxuXHRcdFx0c3JjID0gcGYubWFrZVVybChzcmMpO1xyXG5cdFx0XHRmb3IgKCBpID0gMDsgaSA8IGNhbmRpZGF0ZXMubGVuZ3RoOyBpKysgKSB7XHJcblx0XHRcdFx0aWYgKCBzcmMgPT09IHBmLm1ha2VVcmwoY2FuZGlkYXRlc1sgaSBdLnVybCkgKSB7XHJcblx0XHRcdFx0XHRjYW5kaWRhdGUgPSBjYW5kaWRhdGVzWyBpIF07XHJcblx0XHRcdFx0XHRicmVhaztcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdHJldHVybiBjYW5kaWRhdGU7XHJcblx0fVxyXG5cclxuXHRmdW5jdGlvbiBnZXRBbGxTb3VyY2VFbGVtZW50cyggcGljdHVyZSwgY2FuZGlkYXRlcyApIHtcclxuXHRcdHZhciBpLCBsZW4sIHNvdXJjZSwgc3Jjc2V0O1xyXG5cclxuXHRcdC8vIFNQRUMgbWlzbWF0Y2ggaW50ZW5kZWQgZm9yIHNpemUgYW5kIHBlcmY6XHJcblx0XHQvLyBhY3R1YWxseSBvbmx5IHNvdXJjZSBlbGVtZW50cyBwcmVjZWRpbmcgdGhlIGltZyBzaG91bGQgYmUgdXNlZFxyXG5cdFx0Ly8gYWxzbyBub3RlOiBkb24ndCB1c2UgcXNhIGhlcmUsIGJlY2F1c2UgSUU4IHNvbWV0aW1lcyBkb2Vzbid0IGxpa2Ugc291cmNlIGFzIHRoZSBrZXkgcGFydCBpbiBhIHNlbGVjdG9yXHJcblx0XHR2YXIgc291cmNlcyA9IHBpY3R1cmUuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIFwic291cmNlXCIgKTtcclxuXHJcblx0XHRmb3IgKCBpID0gMCwgbGVuID0gc291cmNlcy5sZW5ndGg7IGkgPCBsZW47IGkrKyApIHtcclxuXHRcdFx0c291cmNlID0gc291cmNlc1sgaSBdO1xyXG5cdFx0XHRzb3VyY2VbIHBmLm5zIF0gPSB0cnVlO1xyXG5cdFx0XHRzcmNzZXQgPSBzb3VyY2UuZ2V0QXR0cmlidXRlKCBcInNyY3NldFwiICk7XHJcblxyXG5cdFx0XHQvLyBpZiBzb3VyY2UgZG9lcyBub3QgaGF2ZSBhIHNyY3NldCBhdHRyaWJ1dGUsIHNraXBcclxuXHRcdFx0aWYgKCBzcmNzZXQgKSB7XHJcblx0XHRcdFx0Y2FuZGlkYXRlcy5wdXNoKCB7XHJcblx0XHRcdFx0XHRzcmNzZXQ6IHNyY3NldCxcclxuXHRcdFx0XHRcdG1lZGlhOiBzb3VyY2UuZ2V0QXR0cmlidXRlKCBcIm1lZGlhXCIgKSxcclxuXHRcdFx0XHRcdHR5cGU6IHNvdXJjZS5nZXRBdHRyaWJ1dGUoIFwidHlwZVwiICksXHJcblx0XHRcdFx0XHRzaXplczogc291cmNlLmdldEF0dHJpYnV0ZSggXCJzaXplc1wiIClcclxuXHRcdFx0XHR9ICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8qKlxyXG5cdCAqIFNyY3NldCBQYXJzZXJcclxuXHQgKiBCeSBBbGV4IEJlbGwgfCAgTUlUIExpY2Vuc2VcclxuXHQgKlxyXG5cdCAqIEByZXR1cm5zIEFycmF5IFt7dXJsOiBfLCBkOiBfLCB3OiBfLCBoOl8sIHNldDpfKD8/Pz8pfSwgLi4uXVxyXG5cdCAqXHJcblx0ICogQmFzZWQgc3VwZXIgZHVwZXIgY2xvc2VseSBvbiB0aGUgcmVmZXJlbmNlIGFsZ29yaXRobSBhdDpcclxuXHQgKiBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS9lbWJlZGRlZC1jb250ZW50Lmh0bWwjcGFyc2UtYS1zcmNzZXQtYXR0cmlidXRlXHJcblx0ICovXHJcblxyXG5cdC8vIDEuIExldCBpbnB1dCBiZSB0aGUgdmFsdWUgcGFzc2VkIHRvIHRoaXMgYWxnb3JpdGhtLlxyXG5cdC8vIChUTy1ETyA6IEV4cGxhaW4gd2hhdCBcInNldFwiIGFyZ3VtZW50IGlzIGhlcmUuIE1heWJlIGNob29zZSBhIG1vcmVcclxuXHQvLyBkZXNjcmlwdGl2ZSAmIG1vcmUgc2VhcmNoYWJsZSBuYW1lLiAgU2luY2UgcGFzc2luZyB0aGUgXCJzZXRcIiBpbiByZWFsbHkgaGFzXHJcblx0Ly8gbm90aGluZyB0byBkbyB3aXRoIHBhcnNpbmcgcHJvcGVyLCBJIHdvdWxkIHByZWZlciB0aGlzIGFzc2lnbm1lbnQgZXZlbnR1YWxseVxyXG5cdC8vIGdvIGluIGFuIGV4dGVybmFsIGZuLilcclxuXHRmdW5jdGlvbiBwYXJzZVNyY3NldChpbnB1dCwgc2V0KSB7XHJcblxyXG5cdFx0ZnVuY3Rpb24gY29sbGVjdENoYXJhY3RlcnMocmVnRXgpIHtcclxuXHRcdFx0dmFyIGNoYXJzLFxyXG5cdFx0XHQgICAgbWF0Y2ggPSByZWdFeC5leGVjKGlucHV0LnN1YnN0cmluZyhwb3MpKTtcclxuXHRcdFx0aWYgKG1hdGNoKSB7XHJcblx0XHRcdFx0Y2hhcnMgPSBtYXRjaFsgMCBdO1xyXG5cdFx0XHRcdHBvcyArPSBjaGFycy5sZW5ndGg7XHJcblx0XHRcdFx0cmV0dXJuIGNoYXJzO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIGlucHV0TGVuZ3RoID0gaW5wdXQubGVuZ3RoLFxyXG5cdFx0ICAgIHVybCxcclxuXHRcdCAgICBkZXNjcmlwdG9ycyxcclxuXHRcdCAgICBjdXJyZW50RGVzY3JpcHRvcixcclxuXHRcdCAgICBzdGF0ZSxcclxuXHRcdCAgICBjLFxyXG5cclxuXHRcdCAgICAvLyAyLiBMZXQgcG9zaXRpb24gYmUgYSBwb2ludGVyIGludG8gaW5wdXQsIGluaXRpYWxseSBwb2ludGluZyBhdCB0aGUgc3RhcnRcclxuXHRcdCAgICAvLyAgICBvZiB0aGUgc3RyaW5nLlxyXG5cdFx0ICAgIHBvcyA9IDAsXHJcblxyXG5cdFx0ICAgIC8vIDMuIExldCBjYW5kaWRhdGVzIGJlIGFuIGluaXRpYWxseSBlbXB0eSBzb3VyY2Ugc2V0LlxyXG5cdFx0ICAgIGNhbmRpZGF0ZXMgPSBbXTtcclxuXHJcblx0XHQvKipcclxuXHRcdCogQWRkcyBkZXNjcmlwdG9yIHByb3BlcnRpZXMgdG8gYSBjYW5kaWRhdGUsIHB1c2hlcyB0byB0aGUgY2FuZGlkYXRlcyBhcnJheVxyXG5cdFx0KiBAcmV0dXJuIHVuZGVmaW5lZFxyXG5cdFx0Ki9cclxuXHRcdC8vIChEZWNsYXJlZCBvdXRzaWRlIG9mIHRoZSB3aGlsZSBsb29wIHNvIHRoYXQgaXQncyBvbmx5IGNyZWF0ZWQgb25jZS5cclxuXHRcdC8vIChUaGlzIGZuIGlzIGRlZmluZWQgYmVmb3JlIGl0IGlzIHVzZWQsIGluIG9yZGVyIHRvIHBhc3MgSlNISU5ULlxyXG5cdFx0Ly8gVW5mb3J0dW5hdGVseSB0aGlzIGJyZWFrcyB0aGUgc2VxdWVuY2luZyBvZiB0aGUgc3BlYyBjb21tZW50cy4gOi8gKVxyXG5cdFx0ZnVuY3Rpb24gcGFyc2VEZXNjcmlwdG9ycygpIHtcclxuXHJcblx0XHRcdC8vIDkuIERlc2NyaXB0b3IgcGFyc2VyOiBMZXQgZXJyb3IgYmUgbm8uXHJcblx0XHRcdHZhciBwRXJyb3IgPSBmYWxzZSxcclxuXHJcblx0XHRcdC8vIDEwLiBMZXQgd2lkdGggYmUgYWJzZW50LlxyXG5cdFx0XHQvLyAxMS4gTGV0IGRlbnNpdHkgYmUgYWJzZW50LlxyXG5cdFx0XHQvLyAxMi4gTGV0IGZ1dHVyZS1jb21wYXQtaCBiZSBhYnNlbnQuIChXZSdyZSBpbXBsZW1lbnRpbmcgaXQgbm93IGFzIGgpXHJcblx0XHRcdCAgICB3LCBkLCBoLCBpLFxyXG5cdFx0XHQgICAgY2FuZGlkYXRlID0ge30sXHJcblx0XHRcdCAgICBkZXNjLCBsYXN0Q2hhciwgdmFsdWUsIGludFZhbCwgZmxvYXRWYWw7XHJcblxyXG5cdFx0XHQvLyAxMy4gRm9yIGVhY2ggZGVzY3JpcHRvciBpbiBkZXNjcmlwdG9ycywgcnVuIHRoZSBhcHByb3ByaWF0ZSBzZXQgb2Ygc3RlcHNcclxuXHRcdFx0Ly8gZnJvbSB0aGUgZm9sbG93aW5nIGxpc3Q6XHJcblx0XHRcdGZvciAoaSA9IDAgOyBpIDwgZGVzY3JpcHRvcnMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0XHRkZXNjID0gZGVzY3JpcHRvcnNbIG
3155kgXTtcclxuXHJcblx0XHRcdFx0bGFzdENoYXIgPSBkZXNjWyBkZXNjLmxlbmd0aCAtIDEgXTtcclxuXHRcdFx0XHR2YWx1ZSA9IGRlc2Muc3Vic3RyaW5nKDAsIGRlc2MubGVuZ3RoIC0gMSk7XHJcblx0XHRcdFx0aW50VmFsID0gcGFyc2VJbnQodmFsdWUsIDEwKTtcclxuXHRcdFx0XHRmbG9hdFZhbCA9IHBhcnNlRmxvYXQodmFsdWUpO1xyXG5cclxuXHRcdFx0XHQvLyBJZiB0aGUgZGVzY3JpcHRvciBjb25zaXN0cyBvZiBhIHZhbGlkIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyIGZvbGxvd2VkIGJ5XHJcblx0XHRcdFx0Ly8gYSBVKzAwNzcgTEFUSU4gU01BTEwgTEVUVEVSIFcgY2hhcmFjdGVyXHJcblx0XHRcdFx0aWYgKHJlZ2V4Tm9uTmVnYXRpdmVJbnRlZ2VyLnRlc3QodmFsdWUpICYmIChsYXN0Q2hhciA9PT0gXCJ3XCIpKSB7XHJcblxyXG5cdFx0XHRcdFx0Ly8gSWYgd2lkdGggYW5kIGRlbnNpdHkgYXJlIG5vdCBib3RoIGFic2VudCwgdGhlbiBsZXQgZXJyb3IgYmUgeWVzLlxyXG5cdFx0XHRcdFx0aWYgKHcgfHwgZCkge3BFcnJvciA9IHRydWU7fVxyXG5cclxuXHRcdFx0XHRcdC8vIEFwcGx5IHRoZSBydWxlcyBmb3IgcGFyc2luZyBub24tbmVnYXRpdmUgaW50ZWdlcnMgdG8gdGhlIGRlc2NyaXB0b3IuXHJcblx0XHRcdFx0XHQvLyBJZiB0aGUgcmVzdWx0IGlzIHplcm8sIGxldCBlcnJvciBiZSB5ZXMuXHJcblx0XHRcdFx0XHQvLyBPdGhlcndpc2UsIGxldCB3aWR0aCBiZSB0aGUgcmVzdWx0LlxyXG5cdFx0XHRcdFx0aWYgKGludFZhbCA9PT0gMCkge3BFcnJvciA9IHRydWU7fSBlbHNlIHt3ID0gaW50VmFsO31cclxuXHJcblx0XHRcdFx0Ly8gSWYgdGhlIGRlc2NyaXB0b3IgY29uc2lzdHMgb2YgYSB2YWxpZCBmbG9hdGluZy1wb2ludCBudW1iZXIgZm9sbG93ZWQgYnlcclxuXHRcdFx0XHQvLyBhIFUrMDA3OCBMQVRJTiBTTUFMTCBMRVRURVIgWCBjaGFyYWN0ZXJcclxuXHRcdFx0XHR9IGVsc2UgaWYgKHJlZ2V4RmxvYXRpbmdQb2ludC50ZXN0KHZhbHVlKSAmJiAobGFzdENoYXIgPT09IFwieFwiKSkge1xyXG5cclxuXHRcdFx0XHRcdC8vIElmIHdpZHRoLCBkZW5zaXR5IGFuZCBmdXR1cmUtY29tcGF0LWggYXJlIG5vdCBhbGwgYWJzZW50LCB0aGVuIGxldCBlcnJvclxyXG5cdFx0XHRcdFx0Ly8gYmUgeWVzLlxyXG5cdFx0XHRcdFx0aWYgKHcgfHwgZCB8fCBoKSB7cEVycm9yID0gdHJ1ZTt9XHJcblxyXG5cdFx0XHRcdFx0Ly8gQXBwbHkgdGhlIHJ1bGVzIGZvciBwYXJzaW5nIGZsb2F0aW5nLXBvaW50IG51bWJlciB2YWx1ZXMgdG8gdGhlIGRlc2NyaXB0b3IuXHJcblx0XHRcdFx0XHQvLyBJZiB0aGUgcmVzdWx0IGlzIGxlc3MgdGhhbiB6ZXJvLCBsZXQgZXJyb3IgYmUgeWVzLiBPdGhlcndpc2UsIGxldCBkZW5zaXR5XHJcblx0XHRcdFx0XHQvLyBiZSB0aGUgcmVzdWx0LlxyXG5cdFx0XHRcdFx0aWYgKGZsb2F0VmFsIDwgMCkge3BFcnJvciA9IHRydWU7fSBlbHNlIHtkID0gZmxvYXRWYWw7fVxyXG5cclxuXHRcdFx0XHQvLyBJZiB0aGUgZGVzY3JpcHRvciBjb25zaXN0cyBvZiBhIHZhbGlkIG5vbi1uZWdhdGl2ZSBpbnRlZ2VyIGZvbGxvd2VkIGJ5XHJcblx0XHRcdFx0Ly8gYSBVKzAwNjggTEFUSU4gU01BTEwgTEVUVEVSIEggY2hhcmFjdGVyXHJcblx0XHRcdFx0fSBlbHNlIGlmIChyZWdleE5vbk5lZ2F0aXZlSW50ZWdlci50ZXN0KHZhbHVlKSAmJiAobGFzdENoYXIgPT09IFwiaFwiKSkge1xyXG5cclxuXHRcdFx0XHRcdC8vIElmIGhlaWdodCBhbmQgZGVuc2l0eSBhcmUgbm90IGJvdGggYWJzZW50LCB0aGVuIGxldCBlcnJvciBiZSB5ZXMuXHJcblx0XHRcdFx0XHRpZiAoaCB8fCBkKSB7cEVycm9yID0gdHJ1ZTt9XHJcblxyXG5cdFx0XHRcdFx0Ly8gQXBwbHkgdGhlIHJ1bGVzIGZvciBwYXJzaW5nIG5vbi1uZWdhdGl2ZSBpbnRlZ2VycyB0byB0aGUgZGVzY3JpcHRvci
31555cclxuXHRcdFx0XHRcdC8vIElmIHRoZSByZXN1bHQgaXMgemVybywgbGV0IGVycm9yIGJlIHllcy4gT3RoZXJ3aXNlLCBsZXQgZnV0dXJlLWNvbXBhdC1oXHJcblx0XHRcdFx0XHQvLyBiZSB0aGUgcmVzdWx0LlxyXG5cdFx0XHRcdFx0aWYgKGludFZhbCA9PT0gMCkge3BFcnJvciA9IHRydWU7fSBlbHNlIHtoID0gaW50VmFsO31cclxuXHJcblx0XHRcdFx0Ly8gQW55dGhpbmcgZWxzZSwgTGV0IGVycm9yIGJlIHllcy5cclxuXHRcdFx0XHR9IGVsc2Uge3BFcnJvciA9IHRydWU7fVxyXG5cdFx0XHR9IC8vIChjbG9zZSBzdGVwIDEzIGZvciBsb29wKVxyXG5cclxuXHRcdFx0Ly8gMTUuIElmIGVycm9yIGlzIHN0aWxsIG5vLCB0aGVuIGFwcGVuZCBhIG5ldyBpbWFnZSBzb3VyY2UgdG8gY2FuZGlkYXRlcyB3aG9zZVxyXG5cdFx0XHQvLyBVUkwgaXMgdXJsLCBhc3NvY2lhdGVkIHdpdGggYSB3aWR0aCB3aWR0aCBpZiBub3QgYWJzZW50IGFuZCBhIHBpeGVsXHJcblx0XHRcdC8vIGRlbnNpdHkgZGVuc2l0eSBpZiBub3QgYWJzZW50LiBPdGhlcndpc2UsIHRoZXJlIGlzIGEgcGFyc2UgZXJyb3IuXHJcblx0XHRcdGlmICghcEVycm9yKSB7XHJcblx0XHRcdFx0Y2FuZGlkYXRlLnVybCA9IHVybDtcclxuXHJcblx0XHRcdFx0aWYgKHcpIHsgY2FuZGlkYXRlLncgPSB3O31cclxuXHRcdFx0XHRpZiAoZCkgeyBjYW5kaWRhdGUuZCA9IGQ7fVxyXG5cdFx0XHRcdGlmIChoKSB7IGNhbmRpZGF0ZS5oID0gaDt9XHJcblx0XHRcdFx0aWYgKCFoICYmICFkICYmICF3KSB7Y2FuZGlkYXRlLmQgPSAxO31cclxuXHRcdFx0XHRpZiAoY2FuZGlkYXRlLmQgPT09IDEpIHtzZXQuaGFzMXggPSB0cnVlO31cclxuXHRcdFx0XHRjYW5kaWRhdGUuc2V0ID0gc2V0O1xyXG5cclxuXHRcdFx0XHRjYW5kaWRhdGVzLnB1c2goY2FuZGlkYXRlKTtcclxuXHRcdFx0fVxyXG5cdFx0fSAvLyAoY2xvc2UgcGFyc2VEZXNjcmlwdG9ycyBmbilcclxuXHJcblx0XHQvKipcclxuXHRcdCogVG9rZW5pemVzIGRlc2NyaXB0b3IgcHJvcGVydGllcyBwcmlvciB0byBwYXJzaW5nXHJcblx0XHQqIFJldHVybnMgdW5kZWZpbmVkLlxyXG5cdFx0KiAoQWdhaW4sIHRoaXMgZm4gaXMgZGVmaW5lZCBiZWZvcmUgaXQgaXMgdXNlZCwgaW4gb3JkZXIgdG8gcGFzcyBKU0hJTlQuXHJcblx0XHQqIFVuZm9ydHVuYXRlbHkgdGhpcyBicmVha3MgdGhlIGxvZ2ljYWwgc2VxdWVuY2luZyBvZiB0aGUgc3BlYyBjb21tZW50cy4gOi8gKVxyXG5cdFx0Ki9cclxuXHRcdGZ1bmN0aW9uIHRva2VuaXplKCkge1xyXG5cclxuXHRcdFx0Ly8gOC4xLiBEZXNjcmlwdG9yIHRva2VuaXNlcjogU2tpcCB3aGl0ZXNwYWNlXHJcblx0XHRcdGNvbGxlY3RDaGFyYWN0ZXJzKHJlZ2V4TGVhZGluZ1NwYWNlcyk7XHJcblxyXG5cdFx0XHQvLyA4LjIuIExldCBjdXJyZW50IGRlc2NyaXB0b3IgYmUgdGhlIGVtcHR5IHN0cmluZy5cclxuXHRcdFx0Y3VycmVudERlc2NyaXB0b3IgPSBcIlwiO1xyXG5cclxuXHRcdFx0Ly8gOC4zLiBMZXQgc3RhdGUgYmUgaW4gZGVzY3JpcHRvci
31555cclxuXHRcdFx0c3RhdGUgPSBcImluIGRlc2NyaXB0b3JcIjtcclxuXHJcblx0XHRcdHdoaWxlICh0cnVlKSB7XHJcblxyXG5cdFx0XHRcdC8vIDguNC4gTGV0IGMgYmUgdGhlIGNoYXJhY3RlciBhdCBwb3NpdGlvbi5cclxuXHRcdFx0XHRjID0gaW5wdXQuY2hhckF0KHBvcyk7XHJcblxyXG5cdFx0XHRcdC8vICBEbyB0aGUgZm9sbG93aW5nIGRlcGVuZGluZyBvbiB0aGUgdmFsdWUgb2Ygc3RhdGUuXHJcblx0XHRcdFx0Ly8gIEZvciB0aGUgcHVycG9zZSBvZiB0aGlzIHN0ZXAsIFwiRU9GXCIgaXMgYSBzcGVjaWFsIGNoYXJhY3RlciByZXByZXNlbnRpbmdcclxuXHRcdFx0XHQvLyAgdGhhdCBwb3NpdGlvbiBpcyBwYXN0IHRoZSBlbmQgb2YgaW5wdXQuXHJcblxyXG5cdFx0XHRcdC8vIEluIGRlc2NyaXB0b3JcclxuXHRcdFx0XHRpZiAoc3RhdGUgPT09IFwiaW4gZGVzY3JpcHRvclwiKSB7XHJcblx0XHRcdFx0XHQvLyBEbyB0aGUgZm9sbG93aW5nLCBkZXBlbmRpbmcgb24gdGhlIHZhbHVlIG9mIGM6XHJcblxyXG5cdFx0XHRcdCAgLy8gU3BhY2UgY2hhcmFjdGVyXHJcblx0XHRcdFx0ICAvLyBJZiBjdXJyZW50IGRlc2NyaXB0b3IgaXMgbm90IGVtcHR5LCBhcHBlbmQgY3VycmVudCBkZXNjcmlwdG9yIHRvXHJcblx0XHRcdFx0ICAvLyBkZXNjcmlwdG9ycyBhbmQgbGV0IGN1cnJlbnQgZGVzY3JpcHRvciBiZSB0aGUgZW1wdHkgc3RyaW5nLlxyXG5cdFx0XHRcdCAgLy8gU2V0IHN0YXRlIHRvIGFmdGVyIGRlc2NyaXB0b3IuXHJcblx0XHRcdFx0XHRpZiAoaXNTcGFjZShjKSkge1xyXG5cdFx0XHRcdFx0XHRpZiAoY3VycmVudERlc2NyaXB0b3IpIHtcclxuXHRcdFx0XHRcdFx0XHRkZXNjcmlwdG9ycy5wdXNoKGN1cnJlbnREZXNjcmlwdG9yKTtcclxuXHRcdFx0XHRcdFx0XHRjdXJyZW50RGVzY3JpcHRvciA9IFwiXCI7XHJcblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBcImFmdGVyIGRlc2NyaXB0b3JcIjtcclxuXHRcdFx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRcdC8vIFUrMDAyQyBDT01NQSAoLClcclxuXHRcdFx0XHRcdC8vIEFkdmFuY2UgcG9zaXRpb24gdG8gdGhlIG5leHQgY2hhcmFjdGVyIGluIGlucHV0LiBJZiBjdXJyZW50IGRlc2NyaXB0b3JcclxuXHRcdFx0XHRcdC8vIGlzIG5vdCBlbXB0eSwgYXBwZW5kIGN1cnJlbnQgZGVzY3JpcHRvciB0byBkZXNjcmlwdG9ycy4gSnVtcCB0byB0aGUgc3RlcFxyXG5cdFx0XHRcdFx0Ly8gbGFiZWxlZCBkZXNjcmlwdG9yIHBhcnNlci5cclxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoYyA9PT0gXCIsXCIpIHtcclxuXHRcdFx0XHRcdFx0cG9zICs9IDE7XHJcblx0XHRcdFx0XHRcdGlmIChjdXJyZW50RGVzY3JpcHRvcikge1xyXG5cdFx0XHRcdFx0XHRcdGRlc2NyaXB0b3JzLnB1c2goY3VycmVudERlc2NyaXB0b3IpO1xyXG5cdFx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRcdHBhcnNlRGVzY3JpcHRvcnMoKTtcclxuXHRcdFx0XHRcdFx0cmV0dXJuO1xyXG5cclxuXHRcdFx0XHRcdC8vIFUrMDAyOCBMRUZUIFBBUkVOVEhFU0lTICgoKVxyXG5cdFx0XHRcdFx0Ly8gQXBwZW5kIGMgdG8gY3VycmVudCBkZXNjcmlwdG9yLiBTZXQgc3RhdGUgdG8gaW4gcGFyZW5zLlxyXG5cdFx0XHRcdFx0fSBlbHNlIGlmIChjID09PSBcIlxcdTAwMjhcIikge1xyXG5cdFx0XHRcdFx0XHRjdXJyZW50RGVzY3JpcHRvciA9IGN1cnJlbnREZXNjcmlwdG9yICsgYztcclxuXHRcdFx0XHRcdFx0c3RhdGUgPSBcImluIHBhcmVuc1wiO1xyXG5cclxuXHRcdFx0XHRcdC8vIEVPRlxyXG5cdFx0XHRcdFx0Ly8gSWYgY3VycmVudCBkZXNjcmlwdG9yIGlzIG5vdCBlbXB0eSwgYXBwZW5kIGN1cnJlbnQgZGVzY3JpcHRvciB0b1xyXG5cdFx0XHRcdFx0Ly8gZGVzY3JpcHRvcnMuIEp1bXAgdG8gdGhlIHN0ZXAgbGFiZWxlZCBkZXNjcmlwdG9yIHBhcnNlci5cclxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoYyA9PT0gXCJcIikge1xyXG5cdFx0XHRcdFx0XHRpZiAoY3VycmVudERlc2NyaXB0b3IpIHtcclxuXHRcdFx0XHRcdFx0XHRkZXNjcmlwdG9ycy5wdXNoKGN1cnJlbnREZXNjcmlwdG9yKTtcclxuXHRcdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0XHRwYXJzZURlc2NyaXB0b3JzKCk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHQvLyBBbnl0aGluZyBlbHNlXHJcblx0XHRcdFx0XHQvLyBBcHBlbmQgYyB0byBjdXJyZW50IGRlc2NyaXB0b3IuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRjdXJyZW50RGVzY3JpcHRvciA9IGN1cnJlbnREZXNjcmlwdG9yICsgYztcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHQvLyAoZW5kIFwiaW4gZGVzY3JpcHRvclwiXHJcblxyXG5cdFx0XHRcdC8vIEluIHBhcmVuc1xyXG5cdFx0XHRcdH0gZWxzZSBpZiAoc3RhdGUgPT09IFwiaW4gcGFyZW5zXCIpIHtcclxuXHJcblx0XHRcdFx0XHQvLyBVKzAwMjkgUklHSFQgUEFSRU5USEVTSVMgKCkpXHJcblx0XHRcdFx0XHQvLyBBcHBlbmQgYyB0byBjdXJyZW50IGRlc2NyaXB0b3IuIFNldCBzdGF0ZSB0byBpbiBkZXNjcmlwdG9yLlxyXG5cdFx0XHRcdFx0aWYgKGMgPT09IFwiKVwiKSB7XHJcblx0XHRcdFx0XHRcdGN1cnJlbnREZXNjcmlwdG9yID0gY3VycmVudERlc2NyaXB0b3IgKyBjO1xyXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFwiaW4gZGVzY3JpcHRvclwiO1xyXG5cclxuXHRcdFx0XHRcdC8vIEVPRlxyXG5cdFx0XHRcdFx0Ly8gQXBwZW5kIGN1cnJlbnQgZGVzY3JpcHRvciB0byBkZXNjcmlwdG9ycy4gSnVtcCB0byB0aGUgc3RlcCBsYWJlbGVkXHJcblx0XHRcdFx0XHQvLyBkZXNjcmlwdG9yIHBhcnNlci5cclxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoYyA9PT0gXCJcIikge1xyXG5cdFx0XHRcdFx0XHRkZXNjcmlwdG9ycy5wdXNoKGN1cnJlbnREZXNjcmlwdG9yKTtcclxuXHRcdFx0XHRcdFx0cGFyc2VEZXNjcmlwdG9ycygpO1xyXG5cdFx0XHRcdFx0XHRyZXR1cm47XHJcblxyXG5cdFx0XHRcdFx0Ly8gQW55dGhpbmcgZWxzZVxyXG5cdFx0XHRcdFx0Ly8gQXBwZW5kIGMgdG8gY3VycmVudCBkZXNjcmlwdG9yLlxyXG5cdFx0XHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRcdFx0Y3VycmVudERlc2NyaXB0b3IgPSBjdXJyZW50RGVzY3JpcHRvciArIGM7XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdC8vIEFmdGVyIGRlc2NyaXB0b3JcclxuXHRcdFx0XHR9IGVsc2UgaWYgKHN0YXRlID09PSBcImFmdGVyIGRlc2NyaXB0b3JcIikge1xyXG5cclxuXHRcdFx0XHRcdC8vIERvIHRoZSBmb2xsb3dpbmcsIGRlcGVuZGluZyBvbiB0aGUgdmFsdWUgb2YgYzpcclxuXHRcdFx0XHRcdC8vIFNwYWNlIGNoYXJhY3RlcjogU3RheSBpbiB0aGlzIHN0YXRlLlxyXG5cdFx0XHRcdFx0aWYgKGlzU3BhY2UoYykpIHtcclxuXHJcblx0XHRcdFx0XHQvLyBFT0Y6IEp1bXAgdG8gdGhlIHN0ZXAgbGFiZWxlZCBkZXNjcmlwdG9yIHBhcnNlci5cclxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoYyA9PT0gXCJcIikge1xyXG5cdFx0XHRcdFx0XHRwYXJzZURlc2NyaXB0b3JzKCk7XHJcblx0XHRcdFx0XHRcdHJldHVybjtcclxuXHJcblx0XHRcdFx0XHQvLyBBbnl0aGluZyBlbHNlXHJcblx0XHRcdFx0XHQvLyBTZXQgc3RhdGUgdG8gaW4gZGVzY3JpcHRvci4gU2V0IHBvc2l0aW9uIHRvIHRoZSBwcmV2aW91cyBjaGFyYWN0ZXIgaW4gaW5wdXQuXHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFwiaW4gZGVzY3JpcHRvclwiO1xyXG5cdFx0XHRcdFx0XHRwb3MgLT0gMTtcclxuXHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHQvLyBBZHZhbmNlIHBvc2l0aW9uIHRvIHRoZSBuZXh0IGNoYXJhY3RlciBpbiBpbnB1dC5cclxuXHRcdFx0XHRwb3MgKz0gMTtcclxuXHJcblx0XHRcdC8vIFJlcGVhdCB0aGlzIHN0ZXAuXHJcblx0XHRcdH0gLy8gKGNsb3NlIHdoaWxlIHRydWUgbG9vcClcclxuXHRcdH1cclxuXHJcblx0XHQvLyA0LiBTcGxpdHRpbmcgbG9vcDogQ29sbGVjdCBhIHNlcXVlbmNlIG9mIGNoYXJhY3RlcnMgdGhhdCBhcmUgc3BhY2VcclxuXHRcdC8vICAgIGNoYXJhY3RlcnMgb3IgVSswMDJDIENPTU1BIGNoYXJhY3RlcnMuIElmIGFueSBVKzAwMkMgQ09NTUEgY2hhcmFjdGVyc1xyXG5cdFx0Ly8gICAgd2VyZSBjb2xsZWN0ZWQsIHRoYXQgaXMgYSBwYXJzZSBlcnJvci5cclxuXHRcdHd
3155oaWxlICh0cnVlKSB7XHJcblx0XHRcdGNvbGxlY3RDaGFyYWN0ZXJzKHJlZ2V4TGVhZGluZ0NvbW1hc09yU3BhY2VzKTtcclxuXHJcblx0XHRcdC8vIDUuIElmIHBvc2l0aW9uIGlzIHBhc3QgdGhlIGVuZCBvZiBpbnB1dCwgcmV0dXJuIGNhbmRpZGF0ZXMgYW5kIGFib3J0IHRoZXNlIHN0ZXBzLlxyXG5cdFx0XHRpZiAocG9zID49IGlucHV0TGVuZ3RoKSB7XHJcblx0XHRcdFx0cmV0dXJuIGNhbmRpZGF0ZXM7IC8vICh3ZSdyZSBkb25lLCB0aGlzIGlzIHRoZSBzb2xlIHJldHVybiBwYXRoKVxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyA2LiBDb2xsZWN0IGEgc2VxdWVuY2Ugb2YgY2hhcmFjdGVycyB0aGF0IGFyZSBub3Qgc3BhY2UgY2hhcmFjdGVycyxcclxuXHRcdFx0Ly8gICAgYW5kIGxldCB0aGF0IGJlIHVybC5cclxuXHRcdFx0dXJsID0gY29sbGVjdENoYXJhY3RlcnMocmVnZXhMZWFkaW5nTm90U3BhY2VzKTtcclxuXHJcblx0XHRcdC8vIDcuIExldCBkZXNjcmlwdG9ycyBiZSBhIG5ldyBlbXB0eSBsaXN0LlxyXG5cdFx0XHRkZXNjcmlwdG9ycyA9IFtdO1xyXG5cclxuXHRcdFx0Ly8gOC4gSWYgdXJsIGVuZHMgd2l0aCBhIFUrMDAyQyBDT01NQSBjaGFyYWN0ZXIgKCwpLCBmb2xsb3cgdGhlc2Ugc3Vic3RlcHM6XHJcblx0XHRcdC8vXHRcdCgxKS4gUmVtb3ZlIGFsbCB0cmFpbGluZyBVKzAwMkMgQ09NTUEgY2hhcmFjdGVycyBmcm9tIHVybC4gSWYgdGhpcyByZW1vdmVkXHJcblx0XHRcdC8vICAgICAgICAgbW9yZSB0aGFuIG9uZSBjaGFyYWN0ZXIsIHRoYXQgaXMgYSBwYXJzZSBlcnJvci5cclxuXHRcdFx0aWYgKHVybC5zbGljZSgtMSkgPT09IFwiLFwiKSB7XHJcblx0XHRcdFx0dXJsID0gdXJsLnJlcGxhY2UocmVnZXhUcmFpbGluZ0NvbW1hcywgXCJcIik7XHJcblx0XHRcdFx0Ly8gKEp1bXAgYWhlYWQgdG8gc3RlcCA5IHRvIHNraXAgdG9rZW5pemF0aW9uIGFuZCBqdXN0IHB1c2ggdGhlIGNhbmRpZGF0ZSkuXHJcblx0XHRcdFx0cGFyc2VEZXNjcmlwdG9ycygpO1xyXG5cclxuXHRcdFx0Ly9cdE90aGVyd2lzZSwgZm9sbG93IHRoZXNlIHN1YnN0ZXBzOlxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHRva2VuaXplKCk7XHJcblx0XHRcdH0gLy8gKGNsb3NlIGVsc2Ugb2Ygc3RlcCA4KVxyXG5cclxuXHRcdC8vIDE2LiBSZXR1cm4gdG8gdGhlIHN0ZXAgbGFiZWxlZCBzcGxpdHRpbmcgbG9vcC5cclxuXHRcdH0gLy8gKENsb3NlIG9mIGJpZyB3aGlsZSBsb29wLilcclxuXHR9XHJcblxyXG5cdC8qXHJcblx0ICogU2l6ZXMgUGFyc2VyXHJcblx0ICpcclxuXHQgKiBCeSBBbGV4IEJlbGwgfCAgTUlUIExpY2Vuc2VcclxuXHQgKlxyXG5cdCAqIE5vbi1zdHJpY3QgYnV0IGFjY3VyYXRlIGFuZCBsaWdodHdlaWdodCBKUyBQYXJzZXIgZm9yIHRoZSBzdHJpbmcgdmFsdWUgPGltZyBzaXplcz1cImhlcmVcIj5cclxuXHQgKlxyXG5cdCAqIFJlZmVyZW5jZSBhbGdvcml0aG0gYXQ6XHJcblx0ICogaHR0cHM6Ly9odG1sLnNwZWMud2hhdHdnLm9yZy9tdWx0aXBhZ2UvZW1iZWRkZWQtY29udGVudC5odG1sI3BhcnNlLWEtc2l6ZXMtYXR0cmlidXRlXHJcblx0ICpcclxuXHQgKiBNb3N0IGNvbW1lbnRzIGFyZSBjb3BpZWQgaW4gZGlyZWN0bHkgZnJvbSB0aGUgc3BlY1xyXG5cdCAqIChleGNlcHQgZm9yIGNvbW1lbnRzIGluIHBhcmVucykuXHJcblx0ICpcclxuXHQgKiBHcmFtbWFyIGlzOlxyXG5cdCAqIDxzb3VyY2Utc2l6ZS1saXN0PiA9IDxzb3VyY2Utc2l6ZT4jIFsgLCA8c291cmNlLXNpemUtdmFsdWU+IF0/IHwgPHNvdXJjZS1zaXplLXZhbHVlPlxyXG5cdCAqIDxzb3VyY2Utc2l6ZT4gPSA8bWVkaWEtY29uZGl0aW9uPiA8c291cmNlLXNpemUtdmFsdWU+XHJcblx0ICogPHNvdXJjZS1zaXplLXZhbHVlPiA9IDxsZW5ndGg+XHJcblx0ICogaHR0cDovL3d3dy53My5vcmcvaHRtbC93Zy9kcmFmdHMvaHRtbC9tYXN0ZXIvZW1iZWRkZWQtY29udGVudC5odG1sI2F0dHItaW1nLXNpemVzXHJcblx0ICpcclxuXHQgKiBFLmcuIFwiKG1heC13aWR0aDogMzBlbSkgMTAwdncsIChtYXgtd2lkdGg6IDUwZW0pIDcwdncsIDEwMHZ3XCJcclxuXHQgKiBvciBcIihtaW4td2lkdGg6IDMwZW0pLCBjYWxjKDMwdncgLSAxNXB4KVwiIG9yIGp1c3QgXCIzMHZ3XCJcclxuXHQgKlxyXG5cdCAqIFJldHVybnMgdGhlIGZpcnN0IHZhbGlkIDxjc3MtbGVuZ3RoPiB3aXRoIGEgbWVkaWEgY29uZGl0aW9uIHRoYXQgZXZhbHVhdGVzIHRvIHRydWUsXHJcblx0ICogb3IgXCIxMDB2d1wiIGlmIGFsbCB2YWxpZCBtZWRpYSBjb25kaXRpb25zIGV2YWx1YXRlIHRvIGZhbHNlLlxyXG5cdCAqXHJcblx0ICovXHJcblxyXG5cdGZ1bmN0aW9uIHBhcnNlU2l6ZXMoc3RyVmFsdWUpIHtcclxuXHJcblx0XHQvLyAoUGVyY2VudGFnZSBDU1MgbGVuZ3RocyBhcmUgbm90IGFsbG93ZWQgaW4gdGhpcyBjYXNlLCB0byBhdm9pZCBjb25mdXNpb246XHJcblx0XHQvLyBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS9lbWJlZGRlZC1jb250ZW50Lmh0bWwjdmFsaWQtc291cmNlLXNpemUtbGlzdFxyXG5cdFx0Ly8gQ1NTIGFsbG93cyBhIHNpbmdsZSBvcHRpb25hbCBwbHVzIG9yIG1pbnVzIHNpZ246XHJcblx0XHQvLyBodHRwOi8vd3d3LnczLm9yZy9UUi9DU1MyL3N5bmRhdGEuaHRtbCNudW1iZXJzXHJcblx0XHQvLyBDU1MgaXMgQVNDSUkgY2FzZS1pbnNlbnNpdGl2ZTpcclxuXHRcdC8vIGh0dHA6Ly93d3cudzMub3JnL1RSL0NTUzIvc3luZGF0YS5odG1sI2NoYXJhY3RlcnMgKVxyXG5cdFx0Ly8gU3BlYyBhbGxvd3MgZXhwb25lbnRpYWwgbm90YXRpb24gZm9yIDxudW1iZXI+IHR5cGU6XHJcblx0XHQvLyBodHRwOi8vZGV2LnczLm9yZy9jc3N3Zy9jc3MtdmFsdWVzLyNudW1iZXJzXHJcblx0XHR2YXIgcmVnZXhDc3NMZW5ndGhXaXRoVW5pdHMgPSAvXig/OlsrLV0/WzAtOV0rfFswLTldKlxcLlswLTldKykoPzpbZUVdWystXT9bMC05XSspPyg/OmNofGNtfGVtfGV4fGlufG1tfHBjfHB0fHB4fHJlbXx2aHx2bWlufHZtYXh8dncpJC9pO1xyXG5cclxuXHRcdC8vIChUaGlzIGlzIGEgcXVpY2sgYW5kIGxlbmllbnQgdGVzdC4gQmVjYXVzZSBvZiBvcHRpb25hbCB1bmxpbWl0ZWQtZGVwdGggaW50ZXJuYWxcclxuXHRcdC8vIGdyb3VwaW5nIHBhcmVucyBhbmQgc3RyaWN0IHNwYWNpbmcgcnVsZXMsIHR
3155oaXMgY291bGQgZ2V0IHZlcnkgY29tcGxpY2F0ZWQuKVxyXG5cdFx0dmFyIHJlZ2V4Q3NzQ2FsYyA9IC9eY2FsY1xcKCg/OlswLTlhLXogXFwuXFwrXFwtXFwqXFwvXFwoXFwpXSspXFwpJC9pO1xyXG5cclxuXHRcdHZhciBpO1xyXG5cdFx0dmFyIHVucGFyc2VkU2l6ZXNMaXN0O1xyXG5cdFx0dmFyIHVucGFyc2VkU2l6ZXNMaXN0TGVuZ3RoO1xyXG5cdFx0dmFyIHVucGFyc2VkU2l6ZTtcclxuXHRcdHZhciBsYXN0Q29tcG9uZW50VmFsdWU7XHJcblx0XHR2YXIgc2l6ZTtcclxuXHJcblx0XHQvLyBVVElMSVRZIEZVTkNUSU9OU1xyXG5cclxuXHRcdC8vICAoVG95IENTUyBwYXJzZXIuIFRoZSBnb2FscyBoZXJlIGFyZTpcclxuXHRcdC8vICAxKSBleHBhbnNpdmUgdGVzdCBjb3ZlcmFnZSB3aXRob3V0IHRoZSB3ZWlnaHQgb2YgYSBmdWxsIENTUyBwYXJzZXIuXHJcblx0XHQvLyAgMikgQXZvaWRpbmcgcmVnZXggd2hlcmV2ZXIgY29udmVuaWVudC5cclxuXHRcdC8vICBRdWljayB0ZXN0czogaHR0cDovL2pzZmlkZGxlLm5ldC9ndG50TDRnci8zL1xyXG5cdFx0Ly8gIFJldHVybnMgYW4gYXJyYXkgb2YgYXJyYXlzLilcclxuXHRcdGZ1bmN0aW9uIHBhcnNlQ29tcG9uZW50VmFsdWVzKHN0cikge1xyXG5cdFx0XHR2YXIgY2hyY3RyO1xyXG5cdFx0XHR2YXIgY29tcG9uZW50ID0gXCJcIjtcclxuXHRcdFx0dmFyIGNvbXBvbmVudEFycmF5ID0gW107XHJcblx0XHRcdHZhciBsaXN0QXJyYXkgPSBbXTtcclxuXHRcdFx0dmFyIHBhcmVuRGVwdGggPSAwO1xyXG5cdFx0XHR2YXIgcG9zID0gMDtcclxuXHRcdFx0dmFyIGluQ29tbWVudCA9IGZhbHNlO1xyXG5cclxuXHRcdFx0ZnVuY3Rpb24gcHVzaENvbXBvbmVudCgpIHtcclxuXHRcdFx0XHRpZiAoY29tcG9uZW50KSB7XHJcblx0XHRcdFx0XHRjb21wb25lbnRBcnJheS5wdXNoKGNvbXBvbmVudCk7XHJcblx0XHRcdFx0XHRjb21wb25lbnQgPSBcIlwiO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0ZnVuY3Rpb24gcHVzaENvbXBvbmVudEFycmF5KCkge1xyXG5cdFx0XHRcdGlmIChjb21wb25lbnRBcnJheVswXSkge1xyXG5cdFx0XHRcdFx0bGlzdEFycmF5LnB1c2goY29tcG9uZW50QXJyYXkpO1xyXG5cdFx0XHRcdFx0Y29tcG9uZW50QXJyYXkgPSBbXTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIChMb29wIGZvcndhcmRzIGZyb20gdGhlIGJlZ2lubmluZyBvZiB0aGUgc3RyaW5nLilcclxuXHRcdFx0d2hpbGUgKHRydWUpIHtcclxuXHRcdFx0XHRjaHJjdHIgPSBzdHIuY2hhckF0KHBvcyk7XHJcblxyXG5cdFx0XHRcdGlmIChjaHJjdHIgPT09IFwiXCIpIHsgLy8gKCBFbmQgb2Ygc3RyaW5nIHJlYWNoZWQuKVxyXG5cdFx0XHRcdFx0cHVzaENvbXBvbmVudCgpO1xyXG5cdFx0XHRcdFx0cHVzaENvbXBvbmVudEFycmF5KCk7XHJcblx0XHRcdFx0XHRyZXR1cm4gbGlzdEFycmF5O1xyXG5cdFx0XHRcdH0gZWxzZSBpZiAoaW5Db21tZW50KSB7XHJcblx0XHRcdFx0XHRpZiAoKGNocmN0ciA9PT0gXCIqXCIpICYmIChzdHJbcG9zICsgMV0gPT09IFwiL1wiKSkgeyAvLyAoQXQgZW5kIG9mIGEgY29tbWVudC4pXHJcblx0XHRcdFx0XHRcdGluQ29tbWVudCA9IGZhbHNlO1xyXG5cdFx0XHRcdFx0XHRwb3MgKz0gMjtcclxuXHRcdFx0XHRcdFx0cHVzaENvbXBvbmVudCgpO1xyXG5cdFx0XHRcdFx0XHRjb250aW51ZTtcclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdHBvcyArPSAxOyAvLyAoU2tpcCBhbGwgY2hhcmFjdGVycyBpbnNpZGUgY29tbWVudHMuKVxyXG5cdFx0XHRcdFx0XHRjb250aW51ZTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9IGVsc2UgaWYgKGlzU3BhY2UoY2hyY3RyKSkge1xyXG5cdFx0XHRcdFx0Ly8gKElmIHByZXZpb3VzIGNoYXJhY3RlciBpbiBsb29wIHdhcyBhbHNvIGEgc3BhY2UsIG9yIGlmXHJcblx0XHRcdFx0XHQvLyBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBzdHJpbmcsIGRvIG5vdCBhZGQgc3BhY2UgY2hhciB0b1xyXG5cdFx0XHRcdFx0Ly8gY29tcG9uZW50LilcclxuXHRcdFx0XHRcdGlmICggKHN0ci5jaGFyQXQocG9zIC0gMSkgJiYgaXNTcGFjZSggc3RyLmNoYXJBdChwb3MgLSAxKSApICkgfHwgIWNvbXBvbmVudCApIHtcclxuXHRcdFx0XHRcdFx0cG9zICs9IDE7XHJcblx0XHRcdFx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0XHRcdFx0fSBlbHNlIGlmIChwYXJlbkRlcHRoID09PSAwKSB7XHJcblx0XHRcdFx0XHRcdHB1c2hDb21wb25lbnQoKTtcclxuXHRcdFx0XHRcdFx0cG9zICs9MTtcclxuXHRcdFx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHQvLyAoUmVwbGFjZSBhbnkgc3BhY2UgY2hhcmFjdGVyIHdpdGggYSBwbGFpbiBzcGFjZSBmb3IgbGVnaWJpbGl0eS4pXHJcblx0XHRcdFx0XHRcdGNocmN0ciA9IFwiIFwiO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH0gZWxzZSBpZiAoY2hyY3RyID09PSBcIihcIikge1xyXG5cdFx0XHRcdFx0cGFyZW5EZXB0aCArPSAxO1xyXG5cdFx0XHRcdH0gZWxzZSBpZiAoY2hyY3RyID09PSBcIilcIikge1xyXG5cdFx0XHRcdFx0cGFyZW5EZXB0aCAtPSAxO1xyXG5cdFx0XHRcdH0gZWxzZSBpZiAoY2hyY3RyID09PSBcIixcIikge1xyXG5cdFx0XHRcdFx0cHVzaENvbXBvbmVudCgpO1xyXG5cdFx0XHRcdFx0cHVzaENvbXBvbmVudEFycmF5KCk7XHJcblx0XHRcdFx0XHRwb3MgKz0gMTtcclxuXHRcdFx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0XHRcdH0gZWxzZSBpZiAoIChjaHJjdHIgPT09IFwiL1wiKSAmJiAoc3RyLmNoYXJBdChwb3MgKyAxKSA9PT0gXCIqXCIpICkge1xyXG5cdFx0XHRcdFx0aW5Db21tZW50ID0gdHJ1ZTtcclxuXHRcdFx0XHRcdHBvcyArPSAyO1xyXG5cdFx0XHRcdFx0Y29udGludWU7XHJcblx0XHRcdFx0fVxyXG5cclxuXHRcdFx0XHRjb21wb25lbnQgPSBjb21wb25lbnQgKyBjaHJjdHI7XHJcblx0XHRcdFx0cG9zICs9IDE7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBpc1ZhbGlkTm9uTmVnYXRpdmVTb3VyY2VTaXplVmFsdWUocykge1xyXG5cdFx0XHRpZiAocmVnZXhDc3NMZW5ndGhXaXRoVW5pdHMudGVzdChzKSAmJiAocGFyc2VGbG9hdChzKSA+PSAwKSkge3JldHVybiB0cnVlO31cclxuXHRcdFx0aWYgKHJlZ2V4Q3NzQ2FsYy50ZXN0KHMpKSB7cmV0dXJuIHRydWU7fVxyXG5cdFx0XHQvLyAoIGh0dHA6Ly93d3cudzMub3JnL1RSL0NTUzIvc3luZGF0YS5odG1sI251bWJlcnMgc2F5czpcclxuXHRcdFx0Ly8gXCItMCBpcyBlcXVpdmFsZW50IHRvIDAgYW5kIGlzIG5vdCBhIG5lZ2F0aXZlIG51bWJlci5cIiB3aGljaCBtZWFucyB0aGF0XHJcblx0XHRcdC8vIHVuaXRsZXNzIHplcm8gYW5kIHVuaXRsZXNzIG5lZ2F0aXZlIHplcm8gbXVzdCBiZSBhY2NlcHRlZCBhcyBzcGVjaWFsIGNhc2VzLilcclxuXHRcdFx0aWYgKChzID09PSBcIjBcIikgfHwgKHMgPT09IFwiLTBcIikgfHwgKHMgPT09IFwiKzBcIikpIHtyZXR1cm4gdHJ1ZTt9XHJcblx0XHRcdHJldHVybi
3155BmYWxzZTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBXaGVuIGFza2VkIHRvIHBhcnNlIGEgc2l6ZXMgYXR0cmlidXRlIGZyb20gYW4gZWxlbWVudCwgcGFyc2UgYVxyXG5cdFx0Ly8gY29tbWEtc2VwYXJhdGVkIGxpc3Qgb2YgY29tcG9uZW50IHZhbHVlcyBmcm9tIHRoZSB2YWx1ZSBvZiB0aGUgZWxlbWVudCdzXHJcblx0XHQvLyBzaXplcyBhdHRyaWJ1dGUgKG9yIHRoZSBlbXB0eSBzdHJpbmcsIGlmIHRoZSBhdHRyaWJ1dGUgaXMgYWJzZW50KSwgYW5kIGxldFxyXG5cdFx0Ly8gdW5wYXJzZWQgc2l6ZXMgbGlzdCBiZSB0aGUgcmVzdWx0LlxyXG5cdFx0Ly8gaHR0cDovL2Rldi53My5vcmcvY3Nzd2cvY3NzLXN5bnRheC8jcGFyc2UtY29tbWEtc2VwYXJhdGVkLWxpc3Qtb2YtY29tcG9uZW50LXZhbHVlc1xyXG5cclxuXHRcdHVucGFyc2VkU2l6ZXNMaXN0ID0gcGFyc2VDb21wb25lbnRWYWx1ZXMoc3RyVmFsdWUpO1xyXG5cdFx0dW5wYXJzZWRTaXplc0xpc3RMZW5ndGggPSB1bnBhcnNlZFNpemVzTGlzdC5sZW5ndGg7XHJcblxyXG5cdFx0Ly8gRm9yIGVhY2ggdW5wYXJzZWQgc2l6ZSBpbiB1bnBhcnNlZCBzaXplcyBsaXN0OlxyXG5cdFx0Zm9yIChpID0gMDsgaSA8IHVucGFyc2VkU2l6ZXNMaXN0TGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0dW5wYXJzZWRTaXplID0gdW5wYXJzZWRTaXplc0xpc3RbaV07XHJcblxyXG5cdFx0XHQvLyAxLiBSZW1vdmUgYWxsIGNvbnNlY3V0aXZlIDx3aGl0ZXNwYWNlLXRva2VuPnMgZnJvbSB0aGUgZW5kIG9mIHVucGFyc2VkIHNpemUuXHJcblx0XHRcdC8vICggcGFyc2VDb21wb25lbnRWYWx1ZXMoKSBhbHJlYWR5IG9taXRzIHNwYWNlcyBvdXRzaWRlIG9mIHBhcmVucy4gKVxyXG5cclxuXHRcdFx0Ly8gSWYgdW5wYXJzZWQgc2l6ZSBpcyBub3cgZW1wdHksIHRoYXQgaXMgYSBwYXJzZSBlcnJvcjsgY29udGludWUgdG8gdGhlIG5leHRcclxuXHRcdFx0Ly8gaXRlcmF0aW9uIG9mIHRoaXMgYWxnb3JpdGhtLlxyXG5cdFx0XHQvLyAoIHBhcnNlQ29tcG9uZW50VmFsdWVzKCkgd29uJ3QgcHVzaCBhbiBlbXB0eSBhcnJheS4gKVxyXG5cclxuXHRcdFx0Ly8gMi4gSWYgdGhlIGxhc3QgY29tcG9uZW50IHZhbHVlIGluIHVucGFyc2VkIHNpemUgaXMgYSB2YWxpZCBub24tbmVnYXRpdmVcclxuXHRcdFx0Ly8gPHNvdXJjZS1zaXplLXZhbHVlPiwgbGV0IHNpemUgYmUgaXRzIHZhbHVlIGFuZCByZW1vdmUgdGhlIGNvbXBvbmVudCB2YWx1ZVxyXG5cdFx0XHQvLyBmcm9tIHVucGFyc2VkIHNpemUuIEFueSBDU1MgZnVuY3Rpb24gb3RoZXIgdGhhbiB0aGUgY2FsYygpIGZ1bmN0aW9uIGlzXHJcblx0XHRcdC8vIGludmFsaWQuIE90aGVyd2lzZSwgdGhlcmUgaXMgYSBwYXJzZSBlcnJvcjsgY29udGludWUgdG8gdGhlIG5leHQgaXRlcmF0aW9uXHJcblx0XHRcdC8vIG9mIHRoaXMgYWxnb3JpdGhtLlxyXG5cdFx0XHQvLyBodHRwOi8vZGV2LnczLm9yZy9jc3N3Zy9jc3Mtc3ludGF4LyNwYXJzZS1jb21wb25lbnQtdmFsdWVcclxuXHRcdFx0bGFzdENvbXBvbmVudFZhbHVlID0gdW5wYXJzZWRTaXplW3VucGFyc2VkU2l6ZS5sZW5ndGggLSAxXTtcclxuXHJcblx0XHRcdGlmIChpc1ZhbGlkTm9uTmVnYXRpdmVTb3VyY2VTaXplVmFsdWUobGFzdENvbXBvbmVudFZhbHVlKSkge1xyXG5cdFx0XHRcdHNpemUgPSBsYXN0Q29tcG9uZW50VmFsdWU7XHJcblx0XHRcdFx0dW5wYXJzZWRTaXplLnBvcCgpO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGNvbnRpbnVlO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyAzLiBSZW1vdmUgYWxsIGNvbnNlY3V0aXZlIDx3aGl0ZXNwYWNlLXRva2VuPnMgZnJvbSB0aGUgZW5kIG9mIHVucGFyc2VkXHJcblx0XHRcdC8vIHNpemUuIElmIHVucGFyc2VkIHNpemUgaXMgbm93IGVtcHR5LCByZXR1cm4gc2l6ZSBhbmQgZXhpdCB0aGlzIGFsZ29yaXRobS5cclxuXHRcdFx0Ly8gSWYgdGhpcyB3YXMgbm90IHRoZSBsYXN0IGl0ZW0gaW4gdW5wYXJzZWQgc2l6ZXMgbGlzdCwgdGhhdCBpcyBhIHBhcnNlIGVycm9yLlxyXG5cdFx0XHRpZiAodW5wYXJzZWRTaXplLmxlbmd0aCA9PT0gMCkge1xyXG5cdFx0XHRcdHJldHVybiBzaXplO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyA0LiBQYXJzZSB0aGUgcmVtYWluaW5nIGNvbXBvbmVudCB2YWx1ZXMgaW4gdW5wYXJzZWQgc2l6ZSBhcyBhXHJcblx0XHRcdC8vIDxtZWRpYS1jb25kaXRpb24+LiBJZiBpdCBkb2VzIG5vdCBwYXJzZSBjb3JyZWN0bHksIG9yIGl0IGRvZXMgcGFyc2VcclxuXHRcdFx0Ly8gY29ycmVjdGx5IGJ1dCB0aGUgPG1lZGlhLWNvbmRpdGlvbj4gZXZhbHVhdGVzIHRvIGZhbHNlLCBjb250aW51ZSB0byB0aGVcclxuXHRcdFx0Ly8gbmV4dCBpdGVyYXRpb24gb2YgdGhpcyBhbGdvcml0aG0uXHJcblx0XHRcdC8vIChQYXJzaW5nIGFsbCBwb3NzaWJsZSBjb21wb3VuZCBtZWRpYSBjb25kaXRpb25zIGluIEpTIGlzIGhlYXZ5LCBjb21wbGljYXRlZCxcclxuXHRcdFx0Ly8gYW5kIHRoZSBwYXlvZmYgaXMgdW5jbGVhci4gSXMgdGhlcmUgZXZlciBhbiBzaXR1YXRpb24gd2hlcmUgdGhlXHJcblx0XHRcdC8vIG1lZGlhIGNvbmRpdGlvbiBwYXJzZXMgaW5jb3JyZWN0bHkgYnV0IHN0aWxsIHNvbWVob3cgZXZhbHVhdGVzIHRvIHRydWU/XHJcblx0XHRcdC8vIENhbiB3ZSBqdXN0IHJlbHkgb24gdGhlIGJyb3dzZXIvcG9seWZpbGwgdG8gZG8gaXQ/KVxyXG5cdFx0XHR1bnBhcnNlZFNpemUgPSB1bnBhcnNlZFNpemUuam9pbihcIiBcIik7XHJcblx0XHRcdGlmICghKHBmLm1hdGNoZXNNZWRpYSggdW5wYXJzZWRTaXplICkgKSApIHtcclxuXHRcdFx0XHRjb250aW51ZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gNS4gUmV0dXJuIHNpemUgYW5kIGV4aXQgdGhpcyBhbGdvcml0aG0uXHJcblx0XHRcdHJldHVybiBzaXplO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIElmIHRoZSBhYm92ZSBhbGdvcml0aG0gZXhoYXVzdHMgdW5wYXJzZWQgc2l6ZXMgbGlzdCB3aXRob3V0IHJldHVybmluZyBhXHJcblx0XHQvLyBzaXplIHZhbHVlLCByZXR1cm4gMTAwdncuXHJcblx0XHRyZXR1cm4gXCIxMDB2d1wiO1xyXG5cdH1cclxuXHJcblx0Ly8gbmFtZXNwYWNlXHJcblx0cGYubnMgPSAoXCJwZlwiICsgbmV3IERhdGUoKS5nZXRUaW1lKCkpLnN1YnN0cigwLCA5KTtcclxuXHJcblx0Ly8gc3Jjc2V0IHN1cHBvcnQgdGVzdFxyXG5cdHBmLnN1cFNyY3NldCA9IFwic3Jjc2V0XCIgaW4gaW1hZ2U7XHJcblx0cGYuc3VwU2l6ZXMgPSBcInNpemVzXCIgaW4gaW1hZ2U7XHJcblx0cGYuc3VwUGljdHVyZSA9ICEhd2luZG93LkhUTUxQaWN0dXJlRWxlbWVudDtcclxuXHJcblx0aWYgKHBmLnN1cFNyY3NldCAmJiBwZi5zdXBQaWN0dXJlICYmICFwZi5zdXBTaXplcykge1xyXG5cdFx0KGZ1bmN0aW9uKGltYWdlMikge1xyXG5cdFx0XHRpbWFnZS5zcmNzZXQgPSBcImRhdGE6LGFcIjtcclxuXHRcdFx0aW1hZ2UyLnNyYyA9IFwiZGF0YTosYVwiO1xyXG5cdFx0XHRwZi5zdXBTcmNzZXQgPSBpbWFnZS5jb21wbGV0ZSA9PT0gaW1hZ2UyLmNvbXBsZXRlO1xyXG5cdFx0XHRwZi5zdXBQaWN0dXJlID0gcGYuc3VwU3Jjc2V0ICYmIHBmLnN1cFBpY3R1cmU7XHJcblx0XHR9KShkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwiaW1nXCIpKTtcclxuXHR9XHJcblxyXG5cdC8vIHVzaW5nIHBmLnFzYSBpbnN0ZWFkIG9mIGRvbSB0cmF2ZXJzaW5nIGRvZXMgc2NhbGUgbXVjaCBiZXR0ZXIsXHJcblx0Ly8gZXNwZWNpYWxseSBvbiBzaXRlcyBtaXhpbmcgcmVzcG9uc2l2ZSBhbmQgbm9uLXJlc3BvbnNpdmUgaW1hZ2VzXHJcblx0cGYuc2VsU2hvcnQgPSBcInBpY3R1cmU+aW1nLGltZ1tzcmNzZXRdXCI7XHJcblx0cGYuc2VsID0gcGYuc2VsU2hvcnQ7XHJcblx0cGYuY2ZnID0gY2ZnO1xyXG5cclxuXHRpZiAoIHBmLnN1cFNyY3NldCApIHtcclxuXHRcdH
3155BmLnNlbCArPSBcIixpbWdbXCIgKyBzcmNzZXRBdHRyICsgXCJdXCI7XHJcblx0fVxyXG5cclxuXHQvKipcclxuXHQgKiBTaG9ydGN1dCBwcm9wZXJ0eSBmb3IgYGRldmljZVBpeGVsUmF0aW9gICggZm9yIGVhc3kgb3ZlcnJpZGluZyBpbiB0ZXN0cyApXHJcblx0ICovXHJcblx0cGYuRFBSID0gKERQUiAgfHwgMSApO1xyXG5cdHBmLnUgPSB1bml0cztcclxuXHJcblx0Ly8gY29udGFpbmVyIG9mIHN1cHBvcnRlZCBtaW1lIHR5cGVzIHRoYXQgb25lIG1pZ2h0IG5lZWQgdG8gcXVhbGlmeSBiZWZvcmUgdXNpbmdcclxuXHRwZi50eXBlcyA9ICB0eXBlcztcclxuXHJcblx0YWx3YXlzQ2hlY2tXRGVzY3JpcHRvciA9IHBmLnN1cFNyY3NldCAmJiAhcGYuc3VwU2l6ZXM7XHJcblxyXG5cdHBmLnNldFNpemUgPSBub29wO1xyXG5cclxuXHQvKipcclxuXHQgKiBHZXRzIGEgc3RyaW5nIGFuZCByZXR1cm5zIHRoZSBhYnNvbHV0ZSBVUkxcclxuXHQgKiBAcGFyYW0gc3JjXHJcblx0ICogQHJldHVybnMge1N0cmluZ30gYWJzb2x1dGUgVVJMXHJcblx0ICovXHJcblxyXG5cdHBmLm1ha2VVcmwgPSBtZW1vaXplKGZ1bmN0aW9uKHNyYykge1xyXG5cdFx0YW5jaG9yLmhyZWYgPSBzcmM7XHJcblx0XHRyZXR1cm4gYW5jaG9yLmhyZWY7XHJcblx0fSk7XHJcblxyXG5cdC8qKlxyXG5cdCAqIEdldHMgYSBET00gZWxlbWVudCBvciBkb2N1bWVudCBhbmQgYSBzZWxjdG9yIGFuZCByZXR1cm5zIHRoZSBmb3VuZCBtYXRjaGVzXHJcblx0ICogQ2FuIGJlIGV4dGVuZGVkIHdpdGggalF1ZXJ5L1NpenpsZSBmb3IgSUU3IHN1cHBvcnRcclxuXHQgKiBAcGFyYW0gY29udGV4dFxyXG5cdCAqIEBwYXJhbSBzZWxcclxuXHQgKiBAcmV0dXJucyB7Tm9kZUxpc3R9XHJcblx0ICovXHJcblx0cGYucXNhID0gZnVuY3Rpb24oY29udGV4dCwgc2VsKSB7XHJcblx0XHRyZXR1cm4gY29udGV4dC5xdWVyeVNlbGVjdG9yQWxsKHNlbCk7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogU2hvcnRjdXQgbWV0aG9kIGZvciBtYXRjaE1lZGlhICggZm9yIGVhc3kgb3ZlcnJpZGluZyBpbiB0ZXN0cyApXHJcblx0ICogd2V0aGVyIG5hdGl2ZSBvciBwZi5tTVEgaXMgdXNlZCB3aWxsIGJlIGRlY2lkZWQgbGF6eSBvbiBmaXJzdCBjYWxsXHJcblx0ICogQHJldHVybnMge2Jvb2xlYW59XHJcblx0ICovXHJcblx0cGYubWF0Y2hlc01lZGlhID0gZnVuY3Rpb24oKSB7XHJcblx0XHRpZiAoIHdpbmRvdy5tYXRjaE1lZGlhICYmIChtYXRjaE1lZGlhKCBcIihtaW4td2lkdGg6IDAuMWVtKVwiICkgfHwge30pLm1hdGNoZXMgKSB7XHJcblx0XHRcdHBmLm1hdGNoZXNNZWRpYSA9IGZ1bmN0aW9uKCBtZWRpYSApIHtcclxuXHRcdFx0XHRyZXR1cm4gIW1lZGlhIHx8ICggbWF0Y2hNZWRpYSggbWVkaWEgKS5tYXRjaGVzICk7XHJcblx0XHRcdH07XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRwZi5tYXRjaGVzTWVkaWEgPSBwZi5tTVE7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHBmLm1hdGNoZXNNZWRpYS5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogQSBzaW1wbGlmaWVkIG1hdGNoTWVkaWEgaW1wbGVtZW50YXRpb24gZm9yIElFOCBhbmQgSUU5XHJcblx0ICogaGFuZGxlcyBvbmx5IG1pbi13aWR0aC9tYXgtd2lkdGggd2l0aCBweCBvciBlbSB2YWx1ZXNcclxuXHQgKiBAcGFyYW0gbWVkaWFcclxuXHQgKiBAcmV0dXJucyB7Ym9vbGVhbn1cclxuXHQgKi9cclxuXHRwZi5tTVEgPSBmdW5jdGlvbiggbWVkaWEgKSB7XHJcblx0XHRyZXR1cm4gbWVkaWEgPyBldmFsQ1NTKG1lZGlhKSA6IHRydWU7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogUmV0dXJucyB0aGUgY2FsY3VsYXRlZCBsZW5ndGggaW4gY3NzIHBpeGVsIGZyb20gdGhlIGdpdmVuIHNvdXJjZVNpemVWYWx1ZVxyXG5cdCAqIGh0dHA6Ly9kZXYudzMub3JnL2Nzc3dnL2Nzcy12YWx1ZXMtMy8jbGVuZ3RoLXZhbHVlXHJcblx0ICogaW50ZW5kZWQgU3BlYyBtaXNtYXRjaGVzOlxyXG5cdCAqICogRG9lcyBub3QgY2hlY2sgZm9yIGludmFsaWQgdXNlIG9mIENTUyBmdW5jdGlvbnNcclxuXHQgKiAqIERvZXMgaGFuZGxlIGEgY29tcHV0ZWQgbGVuZ3RoIG9mIDAgdGhlIHNhbWUgYXMgYSBuZWdhdGl2ZSBhbmQgdGhlcmVmb3JlIGludmFsaWQgdmFsdWVcclxuXHQgKiBAcGFyYW0gc291cmNlU2l6ZVZhbHVlXHJcblx0ICogQHJldHVybnMge051bWJlcn1cclxuXHQgKi9cclxuXHRwZi5jYWxjTGVuZ3RoID0gZnVuY3Rpb24oIHNvdXJjZVNpemVWYWx1ZSApIHtcclxuXHJcblx0XHR2YXIgdmFsdWUgPSBldmFsQ1NTKHNvdXJjZVNpemVWYWx1ZSwgdHJ1ZSkgfHwgZmFsc2U7XHJcblx0XHRpZiAodmFsdWUgPCAwKSB7XHJcblx0XHRcdHZhbHVlID0gZmFsc2U7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHZhbHVlO1xyXG5cdH07XHJcblxyXG5cdC8qKlxyXG5cdCAqIFRha2VzIGEgdHlwZSBzdHJpbmcgYW5kIGNoZWNrcyBpZiBpdHMgc3VwcG9ydGVkXHJcblx0ICovXHJcblxyXG5cdHBmLnN1cHBvcnRzVHlwZSA9IGZ1bmN0aW9uKCB0eXBlICkge1xyXG5cdFx0cmV0dXJuICggdHlwZSApID8gdHlwZXNbIHR5cGUgXSA6IHRydWU7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogUGFyc2VzIGEgc291cmNlU2l6ZSBpbnRvIG1lZGlhQ29uZGl0aW9uIChtZWRpYSkgYW5kIHNvdXJjZVNpemVWYWx1ZSAobGVuZ3RoKVxyXG5cdCAqIEBwYXJhbSBzb3VyY2VTaXplU3RyXHJcblx0ICogQHJldHVybnMgeyp9XHJcblx0ICovXHJcblx0cGYucGFyc2VTaXplID0gbWVtb2l6ZShmdW5jdGlvbiggc291cmNlU2l6ZVN0ciApIHtcclxuXHRcdHZhciBtYXRjaCA9ICggc291cmNlU2l6ZVN0ciB8fCBcIlwiICkubWF0Y2gocmVnU2l6ZSk7XHJcblx0XHRyZXR1cm4ge1xyXG5cdFx0XHRtZWRpYTogbWF0Y2ggJiYgbWF0Y2hbMV0sXHJcblx0XHRcdGxlbmd0aDogbWF0Y2ggJiYgbWF0Y2hbMl1cclxuXHRcdH07XHJcblx0fSk7XHJcblxyXG5cdHBmLnBhcnNlU2V0ID0gZnVuY3Rpb24oIHNldCApIHtcclxuXHRcdGlmICggIXNldC5jYW5kcyApIHtcclxuXHRcdFx0c2V0LmNhbmRzID0gcGFyc2VTcmNzZXQoc2V0LnNyY3NldCwgc2V0KTtcclxuXHRcdH1cclxuXHRcdHJldHVybi
3155BzZXQuY2FuZHM7XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogcmV0dXJucyAxZW0gaW4gY3NzIHB4IGZvciBodG1sL2JvZHkgZGVmYXVsdCBzaXplXHJcblx0ICogZnVuY3Rpb24gdGFrZW4gZnJvbSByZXNwb25kanNcclxuXHQgKiBAcmV0dXJucyB7KnxudW1iZXJ9XHJcblx0ICovXHJcblx0cGYuZ2V0RW1WYWx1ZSA9IGZ1bmN0aW9uKCkge1xyXG5cdFx0dmFyIGJvZHk7XHJcblx0XHRpZiAoICFlbWlucHggJiYgKGJvZHkgPSBkb2N1bWVudC5ib2R5KSApIHtcclxuXHRcdFx0dmFyIGRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiZGl2XCIgKSxcclxuXHRcdFx0XHRvcmlnaW5hbEhUTUxDU1MgPSBkb2NFbGVtLnN0eWxlLmNzc1RleHQsXHJcblx0XHRcdFx0b3JpZ2luYWxCb2R5Q1NTID0gYm9keS5zdHlsZS5jc3NUZXh0O1xyXG5cclxuXHRcdFx0ZGl2LnN0eWxlLmNzc1RleHQgPSBiYXNlU3R5bGU7XHJcblxyXG5cdFx0XHQvLyAxZW0gaW4gYSBtZWRpYSBxdWVyeSBpcyB0aGUgdmFsdWUgb2YgdGhlIGRlZmF1bHQgZm9udCBzaXplIG9mIHRoZSBicm93c2VyXHJcblx0XHRcdC8vIHJlc2V0IGRvY0VsZW0gYW5kIGJvZHkgdG8gZW5zdXJlIHRoZSBjb3JyZWN0IHZhbHVlIGlzIHJldHVybmVkXHJcblx0XHRcdGRvY0VsZW0uc3R5bGUuY3NzVGV4dCA9IGZzQ3NzO1xyXG5cdFx0XHRib2R5LnN0eWxlLmNzc1RleHQgPSBmc0NzcztcclxuXHJcblx0XHRcdGJvZHkuYXBwZW5kQ2hpbGQoIGRpdiApO1xyXG5cdFx0XHRlbWlucHggPSBkaXYub2Zmc2V0V2lkdGg7XHJcblx0XHRcdGJvZHkucmVtb3ZlQ2hpbGQoIGRpdiApO1xyXG5cclxuXHRcdFx0Ly9hbHNvIHVwZGF0ZSBlbWlucHggYmVmb3JlIHJldHVybmluZ1xyXG5cdFx0XHRlbWlucHggPSBwYXJzZUZsb2F0KCBlbWlucHgsIDEwICk7XHJcblxyXG5cdFx0XHQvLyByZXN0b3JlIHRoZSBvcmlnaW5hbCB2YWx1ZXNcclxuXHRcdFx0ZG9jRWxlbS5zdHlsZS5jc3NUZXh0ID0gb3JpZ2luYWxIVE1MQ1NTO1xyXG5cdFx0XHRib2R5LnN0eWxlLmNzc1RleHQgPSBvcmlnaW5hbEJvZHlDU1M7XHJcblxyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIGVtaW5weCB8fCAxNjtcclxuXHR9O1xyXG5cclxuXHQvKipcclxuXHQgKiBUYWtlcyBhIHN0cmluZyBvZiBzaXplcyBhbmQgcmV0dXJucyB0aGUgd2lkdGggaW4gcGl4ZWxzIGFzIGEgbnVtYmVyXHJcblx0ICovXHJcblx0cGYuY2FsY0xpc3RMZW5ndGggPSBmdW5jdGlvbiggc291cmNlU2l6ZUxpc3RTdHIgKSB7XHJcblx0XHQvLyBTcGxpdCB1cCBzb3VyY2Ugc2l6ZSBsaXN0LCBpZSAoIG1heC13aWR0aDogMzBlbSApIDEwMCUsICggbWF4LXdpZHRoOiA1MGVtICkgNTAlLCAzMyVcclxuXHRcdC8vXHJcblx0XHQvLyAgICAgICAgICAgICAgICAgICAgICAgICAgIG9yIChtaW4td2lkdGg6MzBlbSkgY2FsYygzMCUgLSAxNXB4KVxyXG5cdFx0aWYgKCAhKHNvdXJjZVNpemVMaXN0U3RyIGluIHNpemVMZW5ndGhDYWNoZSkgfHwgY2ZnLnVUICkge1xyXG5cdFx0XHR2YXIgd2lubmluZ0xlbmd0aCA9IHBmLmNhbGNMZW5ndGgoIHBhcnNlU2l6ZXMoIHNvdXJjZVNpemVMaXN0U3RyICkgKTtcclxuXHJcblx0XHRcdHNpemVMZW5ndGhDYWNoZVsgc291cmNlU2l6ZUxpc3RTdHIgXSA9ICF3aW5uaW5nTGVuZ3RoID8gdW5pdHMud2lkdGggOiB3aW5uaW5nTGVuZ3RoO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBzaXplTGVuZ3RoQ2FjaGVbIHNvdXJjZVNpemVMaXN0U3RyIF07XHJcblx0fTtcclxuXHJcblx0LyoqXHJcblx0ICogVGFrZXMgYSBjYW5kaWRhdGUgb2JqZWN0IHdpdGggYSBzcmNzZXQgcHJvcGVydHkgaW4gdGhlIGZvcm0gb2YgdXJsL1xyXG5cdCAqIGV4LiBcImltYWdlcy9waWMtbWVkaXVtLnBuZyAxeCwgaW1hZ2VzL3BpYy1tZWRpdW0tMngucG5nIDJ4XCIgb3JcclxuXHQgKiAgICAgXCJpbWFnZXMvcGljLW1lZGl1bS5wbmcgNDAwdywgaW1hZ2VzL3BpYy1tZWRpdW0tMngucG5nIDgwMHdcIiBvclxyXG5cdCAqICAgICBcImltYWdlcy9waWMtc21hbGwucG5nXCJcclxuXHQgKiBHZXQgYW4gYXJyYXkgb2YgaW1hZ2UgY2FuZGlkYXRlcyBpbiB0aGUgZm9ybSBvZlxyXG5cdCAqICAgICAge3VybDogXCIvZm9vL2Jhci5wbmdcIiwgcmVzb2x1dGlvbj
3155ogMX1cclxuXHQgKiB3aGVyZSByZXNvbHV0aW9uIGlzIGh0dHA6Ly9kZXYudzMub3JnL2Nzc3dnL2Nzcy12YWx1ZXMtMy8jcmVzb2x1dGlvbi12YWx1ZVxyXG5cdCAqIElmIHNpemVzIGlzIHNwZWNpZmllZCwgcmVzIGlzIGNhbGN1bGF0ZWRcclxuXHQgKi9cclxuXHRwZi5zZXRSZXMgPSBmdW5jdGlvbiggc2V0ICkge1xyXG5cdFx0dmFyIGNhbmRpZGF0ZXM7XHJcblx0XHRpZiAoIHNldCApIHtcclxuXHJcblx0XHRcdGNhbmRpZGF0ZXMgPSBwZi5wYXJzZVNldCggc2V0ICk7XHJcblxyXG5cdFx0XHRmb3IgKCB2YXIgaSA9IDAsIGxlbiA9IGNhbmRpZGF0ZXMubGVuZ3RoOyBpIDwgbGVuOyBpKysgKSB7XHJcblx0XHRcdFx0c2V0UmVzb2x1dGlvbiggY2FuZGlkYXRlc1sgaSBdLCBzZXQuc2l6ZXMgKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIGNhbmRpZGF0ZXM7XHJcblx0fTtcclxuXHJcblx0cGYuc2V0UmVzLnJlcyA9IHNldFJlc29sdXRpb247XHJcblxyXG5cdHBmLmFwcGx5U2V0Q2FuZGlkYXRlID0gZnVuY3Rpb24oIGNhbmRpZGF0ZXMsIGltZyApIHtcclxuXHRcdGlmICggIWNhbmRpZGF0ZXMubGVuZ3RoICkge3JldHVybjt9XHJcblx0XHR2YXIgY2FuZGlkYXRlLFxyXG5cdFx0XHRpLFxyXG5cdFx0XHRqLFxyXG5cdFx0XHRsZW5ndGgsXHJcblx0XHRcdGJlc3RDYW5kaWRhdGUsXHJcblx0XHRcdGN1clNyYyxcclxuXHRcdFx0Y3VyQ2FuLFxyXG5cdFx0XHRjYW5kaWRhdGVTcmMsXHJcblx0XHRcdGFib3J0Q3VyU3JjO1xyXG5cclxuXHRcdHZhciBpbWFnZURhdGEgPSBpbWdbIHBmLm5zIF07XHJcblx0XHR2YXIgZHByID0gcGYuRFBSO1xyXG5cclxuXHRcdGN1clNyYyA9IGltYWdlRGF0YS5jdXJTcmMgfHwgaW1nW2N1clNyY1Byb3BdO1xyXG5cclxuXHRcdGN1ckNhbiA9IGltYWdlRGF0YS5jdXJDYW4gfHwgc2V0U3JjVG9DdXIoaW1nLCBjdXJTcmMsIGNhbmRpZGF0ZXNbMF0uc2V0KTtcclxuXHJcblx0XHQvLyBpZiB3ZSBoYXZlIGEgY3VycmVudCBzb3VyY2UsIHdlIG1pZ2h0IGVpdGhlciBiZWNvbWUgbGF6eSBvciBnaXZlIHRoaXMgc291cmNlIHNvbWUgYWR2YW50YWdlXHJcblx0XHRpZiAoIGN1ckNhbiAmJiBjdXJDYW4uc2V0ID09PSBjYW5kaWRhdGVzWyAwIF0uc2V0ICkge1xyXG5cclxuXHRcdFx0Ly8gaWYgYnJvd3NlciBjYW4gYWJvcnQgaW1hZ2UgcmVxdWVzdCBhbmQgdGhlIGltYWdlIGhhcyBhIGhpZ2hlciBwaXhlbCBkZW5zaXR5IHRoYW4gbmVlZGVkXHJcblx0XHRcdC8vIGFuZCB0aGlzIGltYWdlIGlzbid0IGRvd25sb2FkZWQgeWV0LCB3ZSBza2lwIG5leHQgcGFydCBhbmQgdHJ5IHRvIHNhdmUgYmFuZHdpZHRoXHJcblx0XHRcdGFib3J0Q3VyU3JjID0gKHN1cHBvcnRBYm9ydCAmJiAhaW1nLmNvbXBsZXRlICYmIGN1ckNhbi5yZXMgLSAwLjEgPiBkcHIpO1xyXG5cclxuXHRcdFx0aWYgKCAhYWJvcnRDdXJTcmMgKSB7XHJcblx0XHRcdFx0Y3VyQ2FuLmNhY2hlZCA9IHRydWU7XHJcblxyXG5cdFx0XHRcdC8vIGlmIGN1cnJlbnQgY2FuZGlkYXRlIGlzIFwiYmVzdFwiLCBcImJldHRlclwiIG9yIFwib2theVwiLFxyXG5cdFx0XHRcdC8vIHNldCBpdCB0byBiZXN0Q2FuZGlkYXRlXHJcblx0XHRcdFx0aWYgKCBjdXJDYW4ucmVzID49IGRwciApIHtcclxuXHRcdFx0XHRcdGJlc3RDYW5kaWRhdGUgPSBjdXJDYW47XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCAhYmVzdENhbmRpZGF0ZSApIHtcclxuXHJcblx0XHRcdGNhbmRpZGF0ZXMuc29ydCggYXNjZW5kaW5nU29ydCApO1xyXG5cclxuXHRcdFx0bGVuZ3RoID0gY2FuZGlkYXRlcy5sZW5ndGg7XHJcblx0XHRcdGJlc3RDYW5kaWRhdGUgPSBjYW5kaWRhdGVzWyBsZW5ndGggLSAxIF07XHJcblxyXG5cdFx0XHRmb3IgKCBpID0gMDsgaSA8IGxlbmd0aDsgaSsrICkge1xyXG5cdFx0XHRcdGNhbmRpZGF0ZSA9IGNhbmRpZGF0ZXNbIGkgXTtcclxuXHRcdFx0XHRpZiAoIGNhbmRpZGF0ZS5yZXMgPj0gZHByICkge1xyXG5cdFx0XHRcdFx0aiA9IGkgLSAxO1xyXG5cclxuXHRcdFx0XHRcdC8vIHdlIGhhdmUgZm91bmQgdGhlIHBlcmZlY3QgY2FuZGlkYXRlLFxyXG5cdFx0XHRcdFx0Ly8gYnV0IGxldCdzIGltcHJvdmUgdGhpcyBhIGxpdHRsZSBiaXQgd2l0aCBzb21lIGFzc3VtcHRpb25zIDstKVxyXG5cdFx0XHRcdFx0aWYgKGNhbmRpZGF0ZXNbIGogXSAmJlxyXG5cdFx0XHRcdFx0XHQoYWJvcnRDdXJTcmMgfHwgY3VyU3JjICE9PSBwZi5tYWtlVXJsKCBjYW5kaWRhdGUudXJsICkpICYmXHJcblx0XHRcdFx0XHRcdGNob29zZUxvd1JlcyhjYW5kaWRhdGVzWyBqIF0ucmVzLCBjYW5kaWRhdGUucmVzLCBkcHIsIGNhbmRpZGF0ZXNbIGogXS5jYWNoZWQpKSB7XHJcblxyXG5cdFx0XHRcdFx0XHRiZXN0Q2FuZGlkYXRlID0gY2FuZGlkYXRlc1sgaiBdO1xyXG5cclxuXHRcdFx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0XHRcdGJlc3RDYW5kaWRhdGUgPSBjYW5kaWRhdGU7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHRicmVhaztcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGJlc3RDYW5kaWRhdGUgKSB7XHJcblxyXG5cdFx0XHRjYW5kaWRhdGVTcmMgPSBwZi5tYWtlVXJsKCBiZXN0Q2FuZGlkYXRlLnVybCApO1xyXG5cclxuXHRcdFx0aW1hZ2VEYXRhLmN1clNyYyA9IGNhbmRpZGF0ZVNyYztcclxuXHRcdFx0aW1hZ2VEYXRhLmN1ckNhbiA9IGJlc3RDYW5kaWRhdGU7XHJcblxyXG5cdFx0XHRpZiAoIGNhbmRpZGF0ZVNyYyAhPT0gY3VyU3JjICkge1xyXG5cdFx0XHRcdHBmLnNldFNyYyggaW1nLCBiZXN0Q2FuZGlkYXRlICk7XHJcblx0XHRcdH1cclxuXHRcdFx0cGYuc2V0U2l6ZSggaW1nICk7XHJcblx0XHR9XHJcblx0fTtcclxuXHJcblx0cGYuc2V0U3JjID0gZnVuY3Rpb24oIGltZywgYmVzdENhbmRpZGF0ZSApIHtcclxuXHRcdHZhciBvcmlnV2lkdGg7XHJcblx0XHRpbWcuc3JjID0gYmVzdENhbmRpZGF0ZS51cmw7XHJcblxyXG5cdFx0Ly8gYWx0aG91Z2ggdGhpcyBpcyBhIHNwZWNpZmljIFNhZmFyaSBpc3N1ZSwgd2UgZG9uJ3Qgd2FudCB0byB0YWtlIHRvbyBtdWNoIGRpZmZlcmVudCBjb2RlIHBhdGhzXHJcblx0XHRpZiAoIGJlc3RDYW5kaWRhdGUuc2V0LnR5cGUgPT09IFwiaW1hZ2Uvc3ZnK3htbFwiICkge1xyXG5cdFx0XHRvcmlnV2lkdGggPSBpbWcuc3R5bGUud2lkdGg7XHJcblx0XHRcdGltZy5zdHlsZS53aWR0aCA9IChpbWcub2Zmc2V0V2lkdGggKyAxKSArIFwicHhcIjtcclxuXHJcblx0XHRcdC8vIG5leHQgbGluZSBvbmx5IHNob3VsZCB0cmlnZ2VyIGEg
3155cmVwYWludFxyXG5cdFx0XHQvLyBpZi4uLiBpcyBvbmx5IGRvbmUgdG8gdHJpY2sgZGVhZCBjb2RlIHJlbW92YWxcclxuXHRcdFx0aWYgKCBpbWcub2Zmc2V0V2lkdGggKyAxICkge1xyXG5cdFx0XHRcdGltZy5zdHlsZS53aWR0aCA9IG9yaWdXaWR0aDtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH07XHJcblxyXG5cdHBmLmdldFNldCA9IGZ1bmN0aW9uKCBpbWcgKSB7XHJcblx0XHR2YXIgaSwgc2V0LCBzdXBwb3J0c1R5cGU7XHJcblx0XHR2YXIgbWF0Y2ggPSBmYWxzZTtcclxuXHRcdHZhciBzZXRzID0gaW1nIFsgcGYubnMgXS5zZXRzO1xyXG5cclxuXHRcdGZvciAoIGkgPSAwOyBpIDwgc2V0cy5sZW5ndGggJiYgIW1hdGNoOyBpKysgKSB7XHJcblx0XHRcdHNldCA9IHNldHNbaV07XHJcblxyXG5cdFx0XHRpZiAoICFzZXQuc3Jjc2V0IHx8ICFwZi5tYXRjaGVzTWVkaWEoIHNldC5tZWRpYSApIHx8ICEoc3VwcG9ydHNUeXBlID0gcGYuc3VwcG9ydHNUeXBlKCBzZXQudHlwZSApKSApIHtcclxuXHRcdFx0XHRjb250aW51ZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0aWYgKCBzdXBwb3J0c1R5cGUgPT09IFwicGVuZGluZ1wiICkge1xyXG5cdFx0XHRcdHNldCA9IHN1cHBvcnRzVHlwZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0bWF0Y2ggPSBzZXQ7XHJcblx0XHRcdGJyZWFrO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBtYXRjaDtcclxuXHR9O1xyXG5cclxuXHRwZi5wYXJzZVNldHMgPSBmdW5jdGlvbiggZWxlbWVudCwgcGFyZW50LCBvcHRpb25zICkge1xyXG5cdFx0dmFyIHNyY3NldEF0dHJpYnV0ZSwgaW1hZ2VTZXQsIGlzV0Rlc2NyaXBvciwgc3Jjc2V0UGFyc2VkO1xyXG5cclxuXHRcdHZhciBoYXNQaWN0dXJlID0gcGFyZW50ICYmIHBhcmVudC5ub2RlTmFtZS50b1VwcGVyQ2FzZSgpID09PSBcIlBJQ1RVUkVcIjtcclxuXHRcdHZhciBpbWFnZURhdGEgPSBlbGVtZW50WyBwZi5ucyBdO1xyXG5cclxuXHRcdGlmICggaW1hZ2VEYXRhLnNyYyA9PT0gdW5kZWZpbmVkIHx8IG9wdGlvbnMuc3JjICkge1xyXG5cdFx0XHRpbWFnZURhdGEuc3JjID0gZ2V0SW1nQXR0ci5jYWxsKCBlbGVtZW50LCBcInNyY1wiICk7XHJcblx0XHRcdGlmICggaW1hZ2VEYXRhLnNyYyApIHtcclxuXHRcdFx0XHRzZXRJbWdBdHRyLmNhbGwoIGVsZW1lbnQsIHNyY0F0dHIsIGltYWdlRGF0YS5zcmMgKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRyZW1vdmVJbWdBdHRyLmNhbGwoIGVsZW1lbnQsIHNyY0F0dHIgKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdGlmICggaW1hZ2VEYXRhLnNyY3NldCA9PT0gdW5kZWZpbmVkIHx8IG9wdGlvbnMuc3Jjc2V0IHx8ICFwZi5zdXBTcmNzZXQgfHwgZWxlbWVudC5zcmNzZXQgKSB7XHJcblx0XHRcdHNyY3NldEF0dHJpYnV0ZSA9IGdldEltZ0F0dHIuY2FsbCggZWxlbWVudCwgXCJzcmNzZXRcIiApO1xyXG5cdFx0XHRpbWFnZURhdGEuc3Jjc2V0ID0gc3Jjc2V0QXR0cmlidXRlO1xyXG5cdFx0XHRzcmNzZXRQYXJzZWQgPSB0cnVlO1xyXG5cdFx0fVxyXG5cclxuXHRcdGltYWdlRGF0YS5zZXRzID0gW107XHJcblxyXG5cdFx0aWYgKCBoYXNQaWN0dXJlICkge1xyXG5cdFx0XHRpbWFnZURhdGEucGljID0gdHJ1ZTtcclxuXHRcdFx0Z2V0QWxsU291cmNlRWxlbWVudHMoIHBhcmVudCwgaW1hZ2VEYXRhLnNldHMgKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIGltYWdlRGF0YS5zcmNzZXQgKSB7XHJcblx0XHRcdGltYWdlU2V0ID0ge1xyXG5cdFx0XHRcdHNyY3NldDogaW1hZ2VEYXRhLnNyY3NldCxcclxuXHRcdFx0XHRzaXplczogZ2V0SW1nQXR0ci5jYWxsKCBlbGVtZW50LCBcInNpemVzXCIgKVxyXG5cdFx0XHR9O1xyXG5cclxuXHRcdFx0aW1hZ2VEYXRhLnNldHMucHVzaCggaW1hZ2VTZXQgKTtcclxuXHJcblx0XHRcdGlzV0Rlc2NyaXBvciA9IChhbHdheXNDaGVja1dEZXNjcmlwdG9yIHx8IGltYWdlRGF0YS5zcmMpICYmIHJlZ1dEZXNjLnRlc3QoaW1hZ2VEYXRhLnNyY3NldCB8fCBcIlwiKTtcclxuXHJcblx0XHRcdC8vIGFkZCBub3JtYWwgc3JjIGFzIGNhbmRpZGF0ZSwgaWYgc291cmNlIGhhcyBubyB3IGRlc2NyaXB0b3JcclxuXHRcdFx0aWYgKCAhaXNXRGVzY3JpcG9yICYmIGltYWdlRGF0YS5zcmMgJiYgIWdldENhbmRpZGF0ZUZvclNyYyhpbWFnZURhdGEuc3JjLCBpbWFnZVNldCkgJiYgIWltYWdlU2V0LmhhczF4ICkge1xyXG5cdFx0XHRcdGltYWdlU2V0LnNyY3NldCArPSBcIiwgXCIgKyBpbWFnZURhdGEuc3JjO1xyXG5cdFx0XHRcdGltYWdlU2V0LmNhbmRzLnB1c2goe1xyXG5cdFx0XHRcdFx0dXJsOiBpbWFnZURhdGEuc3JjLFxyXG5cdFx0XHRcdFx0ZDogMSxcclxuXHRcdFx0XHRcdHNldDogaW1hZ2VTZXRcclxuXHRcdFx0XHR9KTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoIGltYWdlRGF0YS5zcmMgKSB7XHJcblx0XHRcdGltYWdlRGF0YS5zZXRzLnB1c2goIHtcclxuXHRcdFx0XHRzcmNzZXQ6IGltYWdlRGF0YS5zcmMsXHJcblx0XHRcdFx0c2l6ZXM6IG51bGxcclxuXHRcdFx0fSApO1xyXG5cdFx0fVxyXG5cclxuXHRcdGltYWdlRGF0YS5jdXJDYW4gPSBudWxsO1xyXG5cdFx0aW1hZ2VEYXRhLmN1clNyYyA9IHVuZGVmaW5lZDtcclxuXHJcblx0XHQvLyBpZiBpbWcgaGFzIHBpY3R1cmUgb3IgdGhlIHNyY3NldCB3YXMgcmVtb3ZlZCBvciBoYXMgYSBzcmNzZXQgYW5kIGRvZXMgbm90IHN1cHBvcnQgc3Jjc2V0IGF0IGFsbFxyXG5cdFx0Ly8gb3IgaGFzIGEgdyBkZXNjcmlwdG9yIChhbmQgZG9lcyBub3Qgc3VwcG9ydCBzaXplcykgc2V0IHN1cHBvcnQgdG8gZmFsc2UgdG8gZXZhbHVhdGVcclxuXHRcdGltYWdlRGF0YS5zdXBwb3J0ZWQgPSAhKCBoYXNQaWN0dXJlIHx8ICggaW1hZ2VTZXQgJiYgIXBmLnN1cFNyY3NldCApIHx8IGlzV0Rlc2NyaXBvciApO1xyXG5cclxuXHRcdGlmICggc3Jjc2V0UGFyc2VkICYmIHBmLnN1cFNyY3NldCAmJiAhaW1hZ2VEYXRhLnN1cHBvcnRlZCApIHtcclxuXHRcdFx0aWYgKCBzcmNzZXRBdHRyaWJ1dGUgKSB7XHJcblx0XHRcdFx0c2V0SW1nQXR0ci5jYWxsKCBlbGVtZW50LCBzcmNzZXRBdHRyLCBzcmNzZXRBdHRyaWJ1dGUgKTtcclxuXHRcdFx0XHRlbGVtZW50LnNyY3NldCA9IFwiXCI7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0cmVtb3ZlSW1nQXR0ci5jYWxsKCBlbGVtZW50LCBzcmNzZXRBdHRyICk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRpZiAoaW1hZ2VEYXRhLnN1cHBvcnRlZCAmJiAhaW1hZ2VEYXRhLnNyY3NldCAmJiAoKCFpbWFnZURhdGEuc3JjICYmIGVsZW1lbnQuc3JjKSB8fCAgZWxlbWVudC5zcmMgIT09I
3155HBmLm1ha2VVcmwoaW1hZ2VEYXRhLnNyYykpKSB7XHJcblx0XHRcdGlmIChpbWFnZURhdGEuc3JjID09PSBudWxsKSB7XHJcblx0XHRcdFx0ZWxlbWVudC5yZW1vdmVBdHRyaWJ1dGUoXCJzcmNcIik7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0ZWxlbWVudC5zcmMgPSBpbWFnZURhdGEuc3JjO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0aW1hZ2VEYXRhLnBhcnNlZCA9IHRydWU7XHJcblx0fTtcclxuXHJcblx0cGYuZmlsbEltZyA9IGZ1bmN0aW9uKGVsZW1lbnQsIG9wdGlvbnMpIHtcclxuXHRcdHZhciBpbWFnZURhdGE7XHJcblx0XHR2YXIgZXh0cmVtZSA9IG9wdGlvbnMucmVzZWxlY3QgfHwgb3B0aW9ucy5yZWV2YWx1YXRlO1xyXG5cclxuXHRcdC8vIGV4cGFuZG8gZm9yIGNhY2hpbmcgZGF0YSBvbiB0aGUgaW1nXHJcblx0XHRpZiAoICFlbGVtZW50WyBwZi5ucyBdICkge1xyXG5cdFx0XHRlbGVtZW50WyBwZi5ucyBdID0ge307XHJcblx0XHR9XHJcblxyXG5cdFx0aW1hZ2VEYXRhID0gZWxlbWVudFsgcGYubnMgXTtcclxuXHJcblx0XHQvLyBpZiB0aGUgZWxlbWVudCBoYXMgYWxyZWFkeSBiZWVuIGV2YWx1YXRlZCwgc2tpcCBpdFxyXG5cdFx0Ly8gdW5sZXNzIGBvcHRpb25zLnJlZXZhbHVhdGVgIGlzIHNldCB0byB0cnVlICggdGhpcywgZm9yIGV4YW1wbGUsXHJcblx0XHQvLyBpcyBzZXQgdG8gdHJ1ZSB3aGVuIHJ1bm5pbmcgYHBpY3R1cmVmaWxsYCBvbiBgcmVzaXplYCApLlxyXG5cdFx0aWYgKCAhZXh0cmVtZSAmJiBpbWFnZURhdGEuZXZhbGVkID09PSBldmFsSWQgKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICFpbWFnZURhdGEucGFyc2VkIHx8IG9wdGlvbnMucmVldmFsdWF0ZSApIHtcclxuXHRcdFx0cGYucGFyc2VTZXRzKCBlbGVtZW50LCBlbGVtZW50LnBhcmVudE5vZGUsIG9wdGlvbnMgKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoICFpbWFnZURhdGEuc3VwcG9ydGVkICkge1xyXG5cdFx0XHRhcHBseUJlc3RDYW5kaWRhdGUoIGVsZW1lbnQgKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGltYWdlRGF0YS5ldmFsZWQgPSBldmFsSWQ7XHJcblx0XHR9XHJcblx0fTtcclxuXHJcblx0cGYuc2V0dXBSdW4gPSBmdW5jdGlvbigpIHtcclxuXHRcdGlmICggIWFscmVhZHlSdW4gfHwgaXNWd0RpcnR5IHx8IChEUFIgIT09IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvKSApIHtcclxuXHRcdFx0dXBkYXRlTWV0cmljcygpO1xyXG5cdFx0fVxyXG5cdH07XHJcblxyXG5cdC8vIElmIHBpY3R1cmUgaXMgc3VwcG9ydGVkLCB3ZWxsLCB0aGF0J3MgYXdlc29tZS5cclxuXHRpZiAoIHBmLnN1cFBpY3R1cmUgKSB7XHJcblx0XHRwaWN0dXJlZmlsbCA9IG5vb3A7XHJcblx0XHRwZi5maWxsSW1nID0gbm9vcDtcclxuXHR9IGVsc2Uge1xyXG5cclxuXHRcdCAvLyBTZXQgdXAgcGljdHVyZSBwb2x5ZmlsbCBieSBwb2xsaW5nIHRoZSBkb2N1bWVudFxyXG5cdFx0KGZ1bmN0aW9uKCkge1xyXG5cdFx0XHR2YXIgaXNEb21SZWFkeTtcclxuXHRcdFx0dmFyIHJlZ1JlYWR5ID0gd2luZG93LmF0dGFjaEV2ZW50ID8gL2QkfF5jLyA6IC9kJHxeY3xeaS87XHJcblxyXG5cdFx0XHR2YXIgcnVuID0gZnVuY3Rpb24oKSB7XHJcblx0XHRcdFx0dmFyIHJlYWR5U3RhdGUgPSBkb2N1bWVudC5yZWFkeVN0YXRlIHx8IFwiXCI7XHJcblxyXG5cdFx0XHRcdHRpbWVySWQgPSBzZXRUaW1lb3V0KHJ1biwgcmVhZHlTdGF0ZSA9PT0gXCJsb2FkaW5nXCIgPyAyMDAgOiAgOTk5KTtcclxuXHRcdFx0XHRpZiAoIGRvY3VtZW50LmJvZHkgKSB7XHJcblx0XHRcdFx0XHRwZi5maWxsSW1ncygpO1xyXG5cdFx0XHRcdFx0aXNEb21SZWFkeSA9IGlzRG9tUmVhZHkgfHwgcmVnUmVhZHkudGVzdChyZWFkeVN0YXRlKTtcclxuXHRcdFx0XHRcdGlmICggaXNEb21SZWFkeSApIHtcclxuXHRcdFx0XHRcdFx0Y2xlYXJUaW1lb3V0KCB0aW1lcklkICk7XHJcblx0XHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fTtcclxuXHJcblx0XHRcdHZhciB0aW1lcklkID0gc2V0VGltZW91dChydW4sIGRvY3VtZW50LmJvZHkgPyA5IDogOTkpO1xyXG5cclxuXHRcdFx0Ly8gQWxzbyBhdHRhY2ggcGljdHVyZWZpbGwgb24gcmVzaXplIGFuZCByZWFkeXN0YXRlY2hhbmdlXHJcblx0XHRcdC8vIGh0dHA6Ly9tb2Rlcm5qYXZhc2NyaXB0LmJsb2dzcG90LmNvbS8yMDEzLzA4L2J1aWxkaW5nLWJldHRlci1kZWJvdW5jZS5odG1sXHJcblx0XHRcdHZhciBkZWJvdW5jZSA9IGZ1bmN0aW9uKGZ1bmMsIHdhaXQpIHtcclxuXHRcdFx0XHR2YXIgdGltZW91dCwgdGltZXN0YW1wO1xyXG5cdFx0XHRcdHZhciBsYXRlciA9IGZ1bmN0aW9uKCkge1xyXG5cdFx0XHRcdFx0dmFyIGxhc3QgPSAobmV3IERhdGUoKSkgLSB0aW1lc3RhbXA7XHJcblxyXG5cdFx0XHRcdFx0aWYgKGxhc3QgPCB3YWl0KSB7XHJcblx0XHRcdFx0XHRcdHRpbWVvdXQgPSBzZXRUaW1lb3V0KGxhdGVyLCB3YWl0IC0gbGFzdCk7XHJcblx0XHRcdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdFx0XHR0aW1lb3V0ID0gbnVsbDtcclxuXHRcdFx0XHRcdFx0ZnVuYygpO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdH07XHJcblxyXG5cdFx0XHRcdHJldHVybiBmdW5jdGlvbigpIHtcclxuXHRcdFx0XHRcdHRpbWVzdGFtcCA9IG5ldyBEYXRlKCk7XHJcblxyXG5cdFx0XHRcdFx0aWYgKCF0aW1lb3V0KSB7XHJcblx0XHRcdFx0XHRcdHRpbWVvdXQgPSBzZXRUaW1lb3V0KGxhdGVyLCB3YWl0KTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9O1xyXG5cdFx0XHR9O1xyXG5cdFx0XHR2YXIgbGFzdENsaWVudFdpZHRoID0gZG9jRWxlbS5jbGllbnRIZWlnaHQ7XHJcblx0XHRcdHZhciBvblJlc2l6ZSA9IGZ1bmN0aW9uKCkge1xyXG5cdFx0XHRcdGlzVndEaXJ0eSA9IE1hdGgubWF4KHdpbmRvdy5pbm5lcldpZHRoIHx8IDAsIGRvY0VsZW0uY2xpZW50V2lkdGgpICE9PSB1bml0cy53aWR0aCB8fCBkb2NFbGVtLmNsaWVudEhlaWdodCAhPT0gbGFzdENsaWVudFdpZHRoO1xyXG5cdFx0XHRcdGxhc3RDbGllbnRXaWR0aCA9IGRvY0VsZW0uY2xpZW50SGVpZ2h0O1xyXG5cdFx0XHRcdGlmICggaXNWd0RpcnR5ICkge1xyXG5cdFx0XHRcdFx0cGYuZmlsbEltZ3MoKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH07XHJcblxyXG5cdFx0XHRvbiggd2luZG93LCBcInJlc2l6ZVwiLCBkZWJvdW5jZShvblJlc2l6ZSwgOTkgKSApO
31551xyXG5cdFx0XHRvbiggZG9jdW1lbnQsIFwicmVhZHlzdGF0ZWNoYW5nZVwiLCBydW4gKTtcclxuXHRcdH0pKCk7XHJcblx0fVxyXG5cclxuXHRwZi5waWN0dXJlZmlsbCA9IHBpY3R1cmVmaWxsO1xyXG5cdC8vdXNlIHRoaXMgaW50ZXJuYWxseSBmb3IgZWFzeSBtb25rZXkgcGF0Y2hpbmcvcGVyZm9ybWFuY2UgdGVzdGluZ1xyXG5cdHBmLmZpbGxJbWdzID0gcGljdHVyZWZpbGw7XHJcblx0cGYudGVhcmRvd25SdW4gPSBub29wO1xyXG5cclxuXHQvKiBleHBvc2UgbWV0aG9kcyBmb3IgdGVzdGluZyAqL1xyXG5cdHBpY3R1cmVmaWxsLl8gPSBwZjtcclxuXHJcblx0d2luZG93LnBpY3R1cmVmaWxsQ0ZHID0ge1xyXG5cdFx0cGY6IHBmLFxyXG5cdFx0cHVzaDogZnVuY3Rpb24oYXJncykge1xyXG5cdFx0XHR2YXIgbmFtZSA9IGFyZ3Muc2hpZnQoKTtcclxuXHRcdFx0aWYgKHR5cGVvZiBwZltuYW1lXSA9PT0gXCJmdW5jdGlvblwiKSB7XHJcblx0XHRcdFx0cGZbbmFtZV0uYXBwbHkocGYsIGFyZ3MpO1xyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdGNmZ1tuYW1lXSA9IGFyZ3NbMF07XHJcblx0XHRcdFx0aWYgKGFscmVhZHlSdW4pIHtcclxuXHRcdFx0XHRcdHBmLmZpbGxJbWdzKCB7IHJlc2VsZWN0OiB0cnVlIH0gKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9O1xyXG5cclxuXHR3aGlsZSAoc2V0T3B0aW9ucyAmJiBzZXRPcHRpb25zLmxlbmd0aCkge1xyXG5cdFx0d2luZG93LnBpY3R1cmVmaWxsQ0ZHLnB1c2goc2V0T3B0aW9ucy5zaGlmdCgpKTtcclxuXHR9XHJcblxyXG5cdC8qIGV4cG9zZSBwaWN0dXJlZmlsbCAqL1xyXG5cdHdpbmRvdy5waWN0dXJlZmlsbCA9IHBpY3R1cmVmaWxsO1xyXG5cclxuXHQvKiBleHBvc2UgcGljdHVyZWZpbGwgKi9cclxuXHRpZiAoIHR5cGVvZiBtb2R1bGUgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIG1vZHVsZS5leHBvcnRzID09PSBcIm9iamVjdFwiICkge1xyXG5cdFx0Ly8gQ29tbW9uSlMsIGp1c3QgZXhwb3J0XHJcblx0XHRtb2R1bGUuZXhwb3J0cyA9IHBpY3R1cmVmaWxsO1xyXG5cdH0gZWxzZSBpZiAoIHR5cGVvZiBkZWZpbmUgPT09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kICkge1xyXG5cdFx0Ly8gQU1EIHN1cHBvcnRcclxuXHRcdGRlZmluZSggXCJwaWN0dXJlZmlsbFwiLCBmdW5jdGlvbigpIHsgcmV0dXJuIHBpY3R1cmVmaWxsOyB9ICk7XHJcblx0fVxyXG5cclxuXHQvLyBJRTggZXZhbHMgdGhpcyBzeW5jLCBzbyBpdCBtdXN0IGJlIHRoZSBsYXN0IHRoaW5nIHdlIGRvXHJcblx0aWYgKCAhcGYuc3VwUGljdHVyZSApIHtcclxuXHRcdHR5cGVzWyBcImltYWdlL3dlYnBcIiBdID0gZGV0ZWN0VHlwZVN1cHBvcnQoXCJpbWFnZS93ZWJwXCIsIFwiZGF0YTppbWFnZS93ZWJwO2Jhc2U2NCxVa2xHUmtvQUFBQlhSVUpRVmxBNFdBb0FBQUFRQUFBQUFBQUFBQUFBUVV4UVNBd0FBQUFCQnhBUi9ROUVSUDhEQUFCV1VEZ2dHQUFBQURBQkFKMEJLZ0VBQVFBREFEUWxwQUFEY0FEKysvMVFBQT09XCIgKTtcclxuXHR9XHJcblxyXG59ICkoIHdpbmRvdywgZG9jdW1lbnQgKTtcclxuIl19
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.