PageSourceSearch

https://www.wesfarmers.com.au/ResourcePackages/Wesfarmers/assets/dist/js/vendor.js?package=Wesfarmers

js wesfarmers.com.au collected 2026-10-02 07:19:08 UTC 266,919 bytes, 3,155 lines download raw bytes

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.