| Server IP : 85.158.181.41 / Your IP : 216.73.217.12 Web Server : Apache System : Linux cloud9-vm129 6.1.178+1-ph #ph SMP PREEMPT_DYNAMIC Wed Jul 29 09:00:54 UTC 2026 x86_64 User : moncbefd ( 1024) PHP Version : 7.3.33 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : OFF | Pkexec : OFF Directory : /home/moncbefd/www.moneta.at/StyleEdit3/assets/javascript/ |
Upload File : |
/**
* @version: 1.0 Alpha-1
* @author: Coolite Inc. http://www.coolite.com/
* @date: 2008-05-13
* @copyright: Copyright (c) 2006-2008, Coolite Inc. (http://www.coolite.com/). All rights reserved.
* @license: Licensed under The MIT License. See license.txt and http://www.datejs.com/license/.
* @website: http://www.datejs.com/
*/
Date.CultureInfo={name:"en-US",englishName:"English (United States)",nativeName:"English (United States)",dayNames:["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"],abbreviatedDayNames:["Sun","Mon","Tue","Wed","Thu","Fri","Sat"],shortestDayNames:["Su","Mo","Tu","We","Th","Fr","Sa"],firstLetterDayNames:["S","M","T","W","T","F","S"],monthNames:["January","February","March","April","May","June","July","August","September","October","November","December"],abbreviatedMonthNames:["Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec"],amDesignator:"AM",pmDesignator:"PM",firstDayOfWeek:0,twoDigitYearMax:2029,dateElementOrder:"mdy",formatPatterns:{shortDate:"M/d/yyyy",longDate:"dddd, MMMM dd, yyyy",shortTime:"h:mm tt",longTime:"h:mm:ss tt",fullDateTime:"dddd, MMMM dd, yyyy h:mm:ss tt",sortableDateTime:"yyyy-MM-ddTHH:mm:ss",universalSortableDateTime:"yyyy-MM-dd HH:mm:ssZ",rfc1123:"ddd, dd MMM yyyy HH:mm:ss GMT",monthDay:"MMMM dd",yearMonth:"MMMM, yyyy"},regexPatterns:{jan:/^jan(uary)?/i,feb:/^feb(ruary)?/i,mar:/^mar(ch)?/i,apr:/^apr(il)?/i,may:/^may/i,jun:/^jun(e)?/i,jul:/^jul(y)?/i,aug:/^aug(ust)?/i,sep:/^sep(t(ember)?)?/i,oct:/^oct(ober)?/i,nov:/^nov(ember)?/i,dec:/^dec(ember)?/i,sun:/^su(n(day)?)?/i,mon:/^mo(n(day)?)?/i,tue:/^tu(e(s(day)?)?)?/i,wed:/^we(d(nesday)?)?/i,thu:/^th(u(r(s(day)?)?)?)?/i,fri:/^fr(i(day)?)?/i,sat:/^sa(t(urday)?)?/i,future:/^next/i,past:/^last|past|prev(ious)?/i,add:/^(\+|aft(er)?|from|hence)/i,subtract:/^(\-|bef(ore)?|ago)/i,yesterday:/^yes(terday)?/i,today:/^t(od(ay)?)?/i,tomorrow:/^tom(orrow)?/i,now:/^n(ow)?/i,millisecond:/^ms|milli(second)?s?/i,second:/^sec(ond)?s?/i,minute:/^mn|min(ute)?s?/i,hour:/^h(our)?s?/i,week:/^w(eek)?s?/i,month:/^m(onth)?s?/i,day:/^d(ay)?s?/i,year:/^y(ear)?s?/i,shortMeridian:/^(a|p)/i,longMeridian:/^(a\.?m?\.?|p\.?m?\.?)/i,timezone:/^((e(s|d)t|c(s|d)t|m(s|d)t|p(s|d)t)|((gmt)?\s*(\+|\-)\s*\d\d\d\d?)|gmt|utc)/i,ordinalSuffix:/^\s*(st|nd|rd|th)/i,timeContext:/^\s*(\:|a(?!u|p)|p)/i},timezones:[{name:"UTC",offset:"-000"},{name:"GMT",offset:"-000"},{name:"EST",offset:"-0500"},{name:"EDT",offset:"-0400"},{name:"CST",offset:"-0600"},{name:"CDT",offset:"-0500"},{name:"MST",offset:"-0700"},{name:"MDT",offset:"-0600"},{name:"PST",offset:"-0800"},{name:"PDT",offset:"-0700"}]};
(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo,p=function(s,l){if(!l){l=2;}
return("000"+s).slice(l*-1);};$P.clearTime=function(){this.setHours(0);this.setMinutes(0);this.setSeconds(0);this.setMilliseconds(0);return this;};$P.setTimeToNow=function(){var n=new Date();this.setHours(n.getHours());this.setMinutes(n.getMinutes());this.setSeconds(n.getSeconds());this.setMilliseconds(n.getMilliseconds());return this;};$D.today=function(){return new Date().clearTime();};$D.compare=function(date1,date2){if(isNaN(date1)||isNaN(date2)){throw new Error(date1+" - "+date2);}else if(date1 instanceof Date&&date2 instanceof Date){return(date1<date2)?-1:(date1>date2)?1:0;}else{throw new TypeError(date1+" - "+date2);}};$D.equals=function(date1,date2){return(date1.compareTo(date2)===0);};$D.getDayNumberFromName=function(name){var n=$C.dayNames,m=$C.abbreviatedDayNames,o=$C.shortestDayNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s||o[i].toLowerCase()==s){return i;}}
return-1;};$D.getMonthNumberFromName=function(name){var n=$C.monthNames,m=$C.abbreviatedMonthNames,s=name.toLowerCase();for(var i=0;i<n.length;i++){if(n[i].toLowerCase()==s||m[i].toLowerCase()==s){return i;}}
return-1;};$D.isLeapYear=function(year){return((year%4===0&&year%100!==0)||year%400===0);};$D.getDaysInMonth=function(year,month){return[31,($D.isLeapYear(year)?29:28),31,30,31,30,31,31,30,31,30,31][month];};$D.getTimezoneAbbreviation=function(offset){var z=$C.timezones,p;for(var i=0;i<z.length;i++){if(z[i].offset===offset){return z[i].name;}}
return null;};$D.getTimezoneOffset=function(name){var z=$C.timezones,p;for(var i=0;i<z.length;i++){if(z[i].name===name.toUpperCase()){return z[i].offset;}}
return null;};$P.clone=function(){return new Date(this.getTime());};$P.compareTo=function(date){return Date.compare(this,date);};$P.equals=function(date){return Date.equals(this,date||new Date());};$P.between=function(start,end){return this.getTime()>=start.getTime()&&this.getTime()<=end.getTime();};$P.isAfter=function(date){return this.compareTo(date||new Date())===1;};$P.isBefore=function(date){return(this.compareTo(date||new Date())===-1);};$P.isToday=function(){return this.isSameDay(new Date());};$P.isSameDay=function(date){return this.clone().clearTime().equals(date.clone().clearTime());};$P.addMilliseconds=function(value){this.setMilliseconds(this.getMilliseconds()+value);return this;};$P.addSeconds=function(value){return this.addMilliseconds(value*1000);};$P.addMinutes=function(value){return this.addMilliseconds(value*60000);};$P.addHours=function(value){return this.addMilliseconds(value*3600000);};$P.addDays=function(value){this.setDate(this.getDate()+value);return this;};$P.addWeeks=function(value){return this.addDays(value*7);};$P.addMonths=function(value){var n=this.getDate();this.setDate(1);this.setMonth(this.getMonth()+value);this.setDate(Math.min(n,$D.getDaysInMonth(this.getFullYear(),this.getMonth())));return this;};$P.addYears=function(value){return this.addMonths(value*12);};$P.add=function(config){if(typeof config=="number"){this._orient=config;return this;}
var x=config;if(x.milliseconds){this.addMilliseconds(x.milliseconds);}
if(x.seconds){this.addSeconds(x.seconds);}
if(x.minutes){this.addMinutes(x.minutes);}
if(x.hours){this.addHours(x.hours);}
if(x.weeks){this.addWeeks(x.weeks);}
if(x.months){this.addMonths(x.months);}
if(x.years){this.addYears(x.years);}
if(x.days){this.addDays(x.days);}
return this;};var $y,$m,$d;$P.getWeek=function(){var a,b,c,d,e,f,g,n,s,w;$y=(!$y)?this.getFullYear():$y;$m=(!$m)?this.getMonth()+1:$m;$d=(!$d)?this.getDate():$d;if($m<=2){a=$y-1;b=(a/4|0)-(a/100|0)+(a/400|0);c=((a-1)/4|0)-((a-1)/100|0)+((a-1)/400|0);s=b-c;e=0;f=$d-1+(31*($m-1));}else{a=$y;b=(a/4|0)-(a/100|0)+(a/400|0);c=((a-1)/4|0)-((a-1)/100|0)+((a-1)/400|0);s=b-c;e=s+1;f=$d+((153*($m-3)+2)/5)+58+s;}
g=(a+b)%7;d=(f+g-e)%7;n=(f+3-d)|0;if(n<0){w=53-((g-s)/5|0);}else if(n>364+s){w=1;}else{w=(n/7|0)+1;}
$y=$m=$d=null;return w;};$P.getISOWeek=function(){$y=this.getUTCFullYear();$m=this.getUTCMonth()+1;$d=this.getUTCDate();return p(this.getWeek());};$P.setWeek=function(n){return this.moveToDayOfWeek(1).addWeeks(n-this.getWeek());};$D._validate=function(n,min,max,name){if(typeof n=="undefined"){return false;}else if(typeof n!="number"){throw new TypeError(n+" is not a Number.");}else if(n<min||n>max){throw new RangeError(n+" is not a valid value for "+name+".");}
return true;};$D.validateMillisecond=function(value){return $D._validate(value,0,999,"millisecond");};$D.validateSecond=function(value){return $D._validate(value,0,59,"second");};$D.validateMinute=function(value){return $D._validate(value,0,59,"minute");};$D.validateHour=function(value){return $D._validate(value,0,23,"hour");};$D.validateDay=function(value,year,month){return $D._validate(value,1,$D.getDaysInMonth(year,month),"day");};$D.validateMonth=function(value){return $D._validate(value,0,11,"month");};$D.validateYear=function(value){return $D._validate(value,0,9999,"year");};$P.set=function(config){if($D.validateMillisecond(config.millisecond)){this.addMilliseconds(config.millisecond-this.getMilliseconds());}
if($D.validateSecond(config.second)){this.addSeconds(config.second-this.getSeconds());}
if($D.validateMinute(config.minute)){this.addMinutes(config.minute-this.getMinutes());}
if($D.validateHour(config.hour)){this.addHours(config.hour-this.getHours());}
if($D.validateMonth(config.month)){this.addMonths(config.month-this.getMonth());}
if($D.validateYear(config.year)){this.addYears(config.year-this.getFullYear());}
if($D.validateDay(config.day,this.getFullYear(),this.getMonth())){this.addDays(config.day-this.getDate());}
if(config.timezone){this.setTimezone(config.timezone);}
if(config.timezoneOffset){this.setTimezoneOffset(config.timezoneOffset);}
if(config.week&&$D._validate(config.week,0,53,"week")){this.setWeek(config.week);}
return this;};$P.moveToFirstDayOfMonth=function(){return this.set({day:1});};$P.moveToLastDayOfMonth=function(){return this.set({day:$D.getDaysInMonth(this.getFullYear(),this.getMonth())});};$P.moveToNthOccurrence=function(dayOfWeek,occurrence){var shift=0;if(occurrence>0){shift=occurrence-1;}
else if(occurrence===-1){this.moveToLastDayOfMonth();if(this.getDay()!==dayOfWeek){this.moveToDayOfWeek(dayOfWeek,-1);}
return this;}
return this.moveToFirstDayOfMonth().addDays(-1).moveToDayOfWeek(dayOfWeek,+1).addWeeks(shift);};$P.moveToDayOfWeek=function(dayOfWeek,orient){var diff=(dayOfWeek-this.getDay()+7*(orient||+1))%7;return this.addDays((diff===0)?diff+=7*(orient||+1):diff);};$P.moveToMonth=function(month,orient){var diff=(month-this.getMonth()+12*(orient||+1))%12;return this.addMonths((diff===0)?diff+=12*(orient||+1):diff);};$P.getOrdinalNumber=function(){return Math.ceil((this.clone().clearTime()-new Date(this.getFullYear(),0,1))/86400000)+1;};$P.getTimezone=function(){return $D.getTimezoneAbbreviation(this.getUTCOffset());};$P.setTimezoneOffset=function(offset){var here=this.getTimezoneOffset(),there=Number(offset)*-6/10;return this.addMinutes(there-here);};$P.setTimezone=function(offset){return this.setTimezoneOffset($D.getTimezoneOffset(offset));};$P.hasDaylightSavingTime=function(){return(Date.today().set({month:0,day:1}).getTimezoneOffset()!==Date.today().set({month:6,day:1}).getTimezoneOffset());};$P.isDaylightSavingTime=function(){return(this.hasDaylightSavingTime()&&new Date().getTimezoneOffset()===Date.today().set({month:6,day:1}).getTimezoneOffset());};$P.getUTCOffset=function(){var n=this.getTimezoneOffset()*-10/6,r;if(n<0){r=(n-10000).toString();return r.charAt(0)+r.substr(2);}else{r=(n+10000).toString();return"+"+r.substr(1);}};$P.getElapsed=function(date){return(date||new Date())-this;};if(!$P.toISOString){$P.toISOString=function(){function f(n){return n<10?'0'+n:n;}
return'"'+this.getUTCFullYear()+'-'+
f(this.getUTCMonth()+1)+'-'+
f(this.getUTCDate())+'T'+
f(this.getUTCHours())+':'+
f(this.getUTCMinutes())+':'+
f(this.getUTCSeconds())+'Z"';};}
$P._toString=$P.toString;$P.toString=function(format){var x=this;if(format&&format.length==1){var c=$C.formatPatterns;x.t=x.toString;switch(format){case"d":return x.t(c.shortDate);case"D":return x.t(c.longDate);case"F":return x.t(c.fullDateTime);case"m":return x.t(c.monthDay);case"r":return x.t(c.rfc1123);case"s":return x.t(c.sortableDateTime);case"t":return x.t(c.shortTime);case"T":return x.t(c.longTime);case"u":return x.t(c.universalSortableDateTime);case"y":return x.t(c.yearMonth);}}
var ord=function(n){switch(n*1){case 1:case 21:case 31:return"st";case 2:case 22:return"nd";case 3:case 23:return"rd";default:return"th";}};return format?format.replace(/(\\)?(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|S)/g,function(m){if(m.charAt(0)==="\\"){return m.replace("\\","");}
x.h=x.getHours;switch(m){case"hh":return p(x.h()<13?(x.h()===0?12:x.h()):(x.h()-12));case"h":return x.h()<13?(x.h()===0?12:x.h()):(x.h()-12);case"HH":return p(x.h());case"H":return x.h();case"mm":return p(x.getMinutes());case"m":return x.getMinutes();case"ss":return p(x.getSeconds());case"s":return x.getSeconds();case"yyyy":return p(x.getFullYear(),4);case"yy":return p(x.getFullYear());case"dddd":return $C.dayNames[x.getDay()];case"ddd":return $C.abbreviatedDayNames[x.getDay()];case"dd":return p(x.getDate());case"d":return x.getDate();case"MMMM":return $C.monthNames[x.getMonth()];case"MMM":return $C.abbreviatedMonthNames[x.getMonth()];case"MM":return p((x.getMonth()+1));case"M":return x.getMonth()+1;case"t":return x.h()<12?$C.amDesignator.substring(0,1):$C.pmDesignator.substring(0,1);case"tt":return x.h()<12?$C.amDesignator:$C.pmDesignator;case"S":return ord(x.getDate());default:return m;}}):this._toString();};}());
(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo,$N=Number.prototype;$P._orient=+1;$P._nth=null;$P._is=false;$P._same=false;$P._isSecond=false;$N._dateElement="day";$P.next=function(){this._orient=+1;return this;};$D.next=function(){return $D.today().next();};$P.last=$P.prev=$P.previous=function(){this._orient=-1;return this;};$D.last=$D.prev=$D.previous=function(){return $D.today().last();};$P.is=function(){this._is=true;return this;};$P.same=function(){this._same=true;this._isSecond=false;return this;};$P.today=function(){return this.same().day();};$P.weekday=function(){if(this._is){this._is=false;return(!this.is().sat()&&!this.is().sun());}
return false;};$P.at=function(time){return(typeof time==="string")?$D.parse(this.toString("d")+" "+time):this.set(time);};$N.fromNow=$N.after=function(date){var c={};c[this._dateElement]=this;return((!date)?new Date():date.clone()).add(c);};$N.ago=$N.before=function(date){var c={};c[this._dateElement]=this*-1;return((!date)?new Date():date.clone()).add(c);};var dx=("sunday monday tuesday wednesday thursday friday saturday").split(/\s/),mx=("january february march april may june july august september october november december").split(/\s/),px=("Millisecond Second Minute Hour Day Week Month Year").split(/\s/),pxf=("Milliseconds Seconds Minutes Hours Date Week Month FullYear").split(/\s/),nth=("final first second third fourth fifth").split(/\s/),de;$P.toObject=function(){var o={};for(var i=0;i<px.length;i++){o[px[i].toLowerCase()]=this["get"+pxf[i]]();}
return o;};$D.fromObject=function(config){config.week=null;return Date.today().set(config);};var df=function(n){return function(){if(this._is){this._is=false;return this.getDay()==n;}
if(this._nth!==null){if(this._isSecond){this.addSeconds(this._orient*-1);}
this._isSecond=false;var ntemp=this._nth;this._nth=null;var temp=this.clone().moveToLastDayOfMonth();this.moveToNthOccurrence(n,ntemp);if(this>temp){throw new RangeError($D.getDayName(n)+" does not occur "+ntemp+" times in the month of "+$D.getMonthName(temp.getMonth())+" "+temp.getFullYear()+".");}
return this;}
return this.moveToDayOfWeek(n,this._orient);};};var sdf=function(n){return function(){var t=$D.today(),shift=n-t.getDay();if(n===0&&$C.firstDayOfWeek===1&&t.getDay()!==0){shift=shift+7;}
return t.addDays(shift);};};for(var i=0;i<dx.length;i++){$D[dx[i].toUpperCase()]=$D[dx[i].toUpperCase().substring(0,3)]=i;$D[dx[i]]=$D[dx[i].substring(0,3)]=sdf(i);$P[dx[i]]=$P[dx[i].substring(0,3)]=df(i);}
var mf=function(n){return function(){if(this._is){this._is=false;return this.getMonth()===n;}
return this.moveToMonth(n,this._orient);};};var smf=function(n){return function(){return $D.today().set({month:n,day:1});};};for(var j=0;j<mx.length;j++){$D[mx[j].toUpperCase()]=$D[mx[j].toUpperCase().substring(0,3)]=j;$D[mx[j]]=$D[mx[j].substring(0,3)]=smf(j);$P[mx[j]]=$P[mx[j].substring(0,3)]=mf(j);}
var ef=function(j){return function(){if(this._isSecond){this._isSecond=false;return this;}
if(this._same){this._same=this._is=false;var o1=this.toObject(),o2=(arguments[0]||new Date()).toObject(),v="",k=j.toLowerCase();for(var m=(px.length-1);m>-1;m--){v=px[m].toLowerCase();if(o1[v]!=o2[v]){return false;}
if(k==v){break;}}
return true;}
if(j.substring(j.length-1)!="s"){j+="s";}
return this["add"+j](this._orient);};};var nf=function(n){return function(){this._dateElement=n;return this;};};for(var k=0;k<px.length;k++){de=px[k].toLowerCase();$P[de]=$P[de+"s"]=ef(px[k]);$N[de]=$N[de+"s"]=nf(de);}
$P._ss=ef("Second");var nthfn=function(n){return function(dayOfWeek){if(this._same){return this._ss(arguments[0]);}
if(dayOfWeek||dayOfWeek===0){return this.moveToNthOccurrence(dayOfWeek,n);}
this._nth=n;if(n===2&&(dayOfWeek===undefined||dayOfWeek===null)){this._isSecond=true;return this.addSeconds(this._orient);}
return this;};};for(var l=0;l<nth.length;l++){$P[nth[l]]=(l===0)?nthfn(-1):nthfn(l);}}());
(function(){Date.Parsing={Exception:function(s){this.message="Parse error at '"+s.substring(0,10)+" ...'";}};var $P=Date.Parsing;var _=$P.Operators={rtoken:function(r){return function(s){var mx=s.match(r);if(mx){return([mx[0],s.substring(mx[0].length)]);}else{throw new $P.Exception(s);}};},token:function(s){return function(s){return _.rtoken(new RegExp("^\s*"+s+"\s*"))(s);};},stoken:function(s){return _.rtoken(new RegExp("^"+s));},until:function(p){return function(s){var qx=[],rx=null;while(s.length){try{rx=p.call(this,s);}catch(e){qx.push(rx[0]);s=rx[1];continue;}
break;}
return[qx,s];};},many:function(p){return function(s){var rx=[],r=null;while(s.length){try{r=p.call(this,s);}catch(e){return[rx,s];}
rx.push(r[0]);s=r[1];}
return[rx,s];};},optional:function(p){return function(s){var r=null;try{r=p.call(this,s);}catch(e){return[null,s];}
return[r[0],r[1]];};},not:function(p){return function(s){try{p.call(this,s);}catch(e){return[null,s];}
throw new $P.Exception(s);};},ignore:function(p){return p?function(s){var r=null;r=p.call(this,s);return[null,r[1]];}:null;},product:function(){var px=arguments[0],qx=Array.prototype.slice.call(arguments,1),rx=[];for(var i=0;i<px.length;i++){rx.push(_.each(px[i],qx));}
return rx;},cache:function(rule){var cache={},r=null;return function(s){try{r=cache[s]=(cache[s]||rule.call(this,s));}catch(e){r=cache[s]=e;}
if(r instanceof $P.Exception){throw r;}else{return r;}};},any:function(){var px=arguments;return function(s){var r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
try{r=(px[i].call(this,s));}catch(e){r=null;}
if(r){return r;}}
throw new $P.Exception(s);};},each:function(){var px=arguments;return function(s){var rx=[],r=null;for(var i=0;i<px.length;i++){if(px[i]==null){continue;}
try{r=(px[i].call(this,s));}catch(e){throw new $P.Exception(s);}
rx.push(r[0]);s=r[1];}
return[rx,s];};},all:function(){var px=arguments,_=_;return _.each(_.optional(px));},sequence:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;if(px.length==1){return px[0];}
return function(s){var r=null,q=null;var rx=[];for(var i=0;i<px.length;i++){try{r=px[i].call(this,s);}catch(e){break;}
rx.push(r[0]);try{q=d.call(this,r[1]);}catch(ex){q=null;break;}
s=q[1];}
if(!r){throw new $P.Exception(s);}
if(q){throw new $P.Exception(q[1]);}
if(c){try{r=c.call(this,r[1]);}catch(ey){throw new $P.Exception(r[1]);}}
return[rx,(r?r[1]:s)];};},between:function(d1,p,d2){d2=d2||d1;var _fn=_.each(_.ignore(d1),p,_.ignore(d2));return function(s){var rx=_fn.call(this,s);return[[rx[0][0],r[0][2]],rx[1]];};},list:function(p,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return(p instanceof Array?_.each(_.product(p.slice(0,-1),_.ignore(d)),p.slice(-1),_.ignore(c)):_.each(_.many(_.each(p,_.ignore(d))),px,_.ignore(c)));},set:function(px,d,c){d=d||_.rtoken(/^\s*/);c=c||null;return function(s){var r=null,p=null,q=null,rx=null,best=[[],s],last=false;for(var i=0;i<px.length;i++){q=null;p=null;r=null;last=(px.length==1);try{r=px[i].call(this,s);}catch(e){continue;}
rx=[[r[0]],r[1]];if(r[1].length>0&&!last){try{q=d.call(this,r[1]);}catch(ex){last=true;}}else{last=true;}
if(!last&&q[1].length===0){last=true;}
if(!last){var qx=[];for(var j=0;j<px.length;j++){if(i!=j){qx.push(px[j]);}}
p=_.set(qx,d).call(this,q[1]);if(p[0].length>0){rx[0]=rx[0].concat(p[0]);rx[1]=p[1];}}
if(rx[1].length<best[1].length){best=rx;}
if(best[1].length===0){break;}}
if(best[0].length===0){return best;}
if(c){try{q=c.call(this,best[1]);}catch(ey){throw new $P.Exception(best[1]);}
best[1]=q[1];}
return best;};},forward:function(gr,fname){return function(s){return gr[fname].call(this,s);};},replace:function(rule,repl){return function(s){var r=rule.call(this,s);return[repl,r[1]];};},process:function(rule,fn){return function(s){var r=rule.call(this,s);return[fn.call(this,r[0]),r[1]];};},min:function(min,rule){return function(s){var rx=rule.call(this,s);if(rx[0].length<min){throw new $P.Exception(s);}
return rx;};}};var _generator=function(op){return function(){var args=null,rx=[];if(arguments.length>1){args=Array.prototype.slice.call(arguments);}else if(arguments[0]instanceof Array){args=arguments[0];}
if(args){for(var i=0,px=args.shift();i<px.length;i++){args.unshift(px[i]);rx.push(op.apply(null,args));args.shift();return rx;}}else{return op.apply(null,arguments);}};};var gx="optional not ignore cache".split(/\s/);for(var i=0;i<gx.length;i++){_[gx[i]]=_generator(_[gx[i]]);}
var _vector=function(op){return function(){if(arguments[0]instanceof Array){return op.apply(null,arguments[0]);}else{return op.apply(null,arguments);}};};var vx="each any all".split(/\s/);for(var j=0;j<vx.length;j++){_[vx[j]]=_vector(_[vx[j]]);}}());(function(){var $D=Date,$P=$D.prototype,$C=$D.CultureInfo;var flattenAndCompact=function(ax){var rx=[];for(var i=0;i<ax.length;i++){if(ax[i]instanceof Array){rx=rx.concat(flattenAndCompact(ax[i]));}else{if(ax[i]){rx.push(ax[i]);}}}
return rx;};$D.Grammar={};$D.Translator={hour:function(s){return function(){this.hour=Number(s);};},minute:function(s){return function(){this.minute=Number(s);};},second:function(s){return function(){this.second=Number(s);};},meridian:function(s){return function(){this.meridian=s.slice(0,1).toLowerCase();};},timezone:function(s){return function(){var n=s.replace(/[^\d\+\-]/g,"");if(n.length){this.timezoneOffset=Number(n);}else{this.timezone=s.toLowerCase();}};},day:function(x){var s=x[0];return function(){this.day=Number(s.match(/\d+/)[0]);};},month:function(s){return function(){this.month=(s.length==3)?"jan feb mar apr may jun jul aug sep oct nov dec".indexOf(s)/4:Number(s)-1;};},year:function(s){return function(){var n=Number(s);this.year=((s.length>2)?n:(n+(((n+2000)<$C.twoDigitYearMax)?2000:1900)));};},rday:function(s){return function(){switch(s){case"yesterday":this.days=-1;break;case"tomorrow":this.days=1;break;case"today":this.days=0;break;case"now":this.days=0;this.now=true;break;}};},finishExact:function(x){x=(x instanceof Array)?x:[x];for(var i=0;i<x.length;i++){if(x[i]){x[i].call(this);}}
var now=new Date();if((this.hour||this.minute)&&(!this.month&&!this.year&&!this.day)){this.day=now.getDate();}
if(!this.year){this.year=now.getFullYear();}
if(!this.month&&this.month!==0){this.month=now.getMonth();}
if(!this.day){this.day=1;}
if(!this.hour){this.hour=0;}
if(!this.minute){this.minute=0;}
if(!this.second){this.second=0;}
if(this.meridian&&this.hour){if(this.meridian=="p"&&this.hour<12){this.hour=this.hour+12;}else if(this.meridian=="a"&&this.hour==12){this.hour=0;}}
if(this.day>$D.getDaysInMonth(this.year,this.month)){throw new RangeError(this.day+" is not a valid value for days.");}
var r=new Date(this.year,this.month,this.day,this.hour,this.minute,this.second);if(this.timezone){r.set({timezone:this.timezone});}else if(this.timezoneOffset){r.set({timezoneOffset:this.timezoneOffset});}
return r;},finish:function(x){x=(x instanceof Array)?flattenAndCompact(x):[x];if(x.length===0){return null;}
for(var i=0;i<x.length;i++){if(typeof x[i]=="function"){x[i].call(this);}}
var today=$D.today();if(this.now&&!this.unit&&!this.operator){return new Date();}else if(this.now){today=new Date();}
var expression=!!(this.days&&this.days!==null||this.orient||this.operator);var gap,mod,orient;orient=((this.orient=="past"||this.operator=="subtract")?-1:1);if(!this.now&&"hour minute second".indexOf(this.unit)!=-1){today.setTimeToNow();}
if(this.month||this.month===0){if("year day hour minute second".indexOf(this.unit)!=-1){this.value=this.month+1;this.month=null;expression=true;}}
if(!expression&&this.weekday&&!this.day&&!this.days){var temp=Date[this.weekday]();this.day=temp.getDate();if(!this.month){this.month=temp.getMonth();}
this.year=temp.getFullYear();}
if(expression&&this.weekday&&this.unit!="month"){this.unit="day";gap=($D.getDayNumberFromName(this.weekday)-today.getDay());mod=7;this.days=gap?((gap+(orient*mod))%mod):(orient*mod);}
if(this.month&&this.unit=="day"&&this.operator){this.value=(this.month+1);this.month=null;}
if(this.value!=null&&this.month!=null&&this.year!=null){this.day=this.value*1;}
if(this.month&&!this.day&&this.value){today.set({day:this.value*1});if(!expression){this.day=this.value*1;}}
if(!this.month&&this.value&&this.unit=="month"&&!this.now){this.month=this.value;expression=true;}
if(expression&&(this.month||this.month===0)&&this.unit!="year"){this.unit="month";gap=(this.month-today.getMonth());mod=12;this.months=gap?((gap+(orient*mod))%mod):(orient*mod);this.month=null;}
if(!this.unit){this.unit="day";}
if(!this.value&&this.operator&&this.operator!==null&&this[this.unit+"s"]&&this[this.unit+"s"]!==null){this[this.unit+"s"]=this[this.unit+"s"]+((this.operator=="add")?1:-1)+(this.value||0)*orient;}else if(this[this.unit+"s"]==null||this.operator!=null){if(!this.value){this.value=1;}
this[this.unit+"s"]=this.value*orient;}
if(this.meridian&&this.hour){if(this.meridian=="p"&&this.hour<12){this.hour=this.hour+12;}else if(this.meridian=="a"&&this.hour==12){this.hour=0;}}
if(this.weekday&&!this.day&&!this.days){var temp=Date[this.weekday]();this.day=temp.getDate();if(temp.getMonth()!==today.getMonth()){this.month=temp.getMonth();}}
if((this.month||this.month===0)&&!this.day){this.day=1;}
if(!this.orient&&!this.operator&&this.unit=="week"&&this.value&&!this.day&&!this.month){return Date.today().setWeek(this.value);}
if(expression&&this.timezone&&this.day&&this.days){this.day=this.days;}
return(expression)?today.add(this):today.set(this);}};var _=$D.Parsing.Operators,g=$D.Grammar,t=$D.Translator,_fn;g.datePartDelimiter=_.rtoken(/^([\s\-\.\,\/\x27]+)/);g.timePartDelimiter=_.stoken(":");g.whiteSpace=_.rtoken(/^\s*/);g.generalDelimiter=_.rtoken(/^(([\s\,]|at|@|on)+)/);var _C={};g.ctoken=function(keys){var fn=_C[keys];if(!fn){var c=$C.regexPatterns;var kx=keys.split(/\s+/),px=[];for(var i=0;i<kx.length;i++){px.push(_.replace(_.rtoken(c[kx[i]]),kx[i]));}
fn=_C[keys]=_.any.apply(null,px);}
return fn;};g.ctoken2=function(key){return _.rtoken($C.regexPatterns[key]);};g.h=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2]|[1-9])/),t.hour));g.hh=_.cache(_.process(_.rtoken(/^(0[0-9]|1[0-2])/),t.hour));g.H=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3]|[0-9])/),t.hour));g.HH=_.cache(_.process(_.rtoken(/^([0-1][0-9]|2[0-3])/),t.hour));g.m=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.minute));g.mm=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.minute));g.s=_.cache(_.process(_.rtoken(/^([0-5][0-9]|[0-9])/),t.second));g.ss=_.cache(_.process(_.rtoken(/^[0-5][0-9]/),t.second));g.hms=_.cache(_.sequence([g.H,g.m,g.s],g.timePartDelimiter));g.t=_.cache(_.process(g.ctoken2("shortMeridian"),t.meridian));g.tt=_.cache(_.process(g.ctoken2("longMeridian"),t.meridian));g.z=_.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/),t.timezone));g.zz=_.cache(_.process(_.rtoken(/^((\+|\-)\s*\d\d\d\d)|((\+|\-)\d\d\:?\d\d)/),t.timezone));g.zzz=_.cache(_.process(g.ctoken2("timezone"),t.timezone));g.timeSuffix=_.each(_.ignore(g.whiteSpace),_.set([g.tt,g.zzz]));g.time=_.each(_.optional(_.ignore(_.stoken("T"))),g.hms,g.timeSuffix);g.d=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1]|\d)/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.dd=_.cache(_.process(_.each(_.rtoken(/^([0-2]\d|3[0-1])/),_.optional(g.ctoken2("ordinalSuffix"))),t.day));g.ddd=g.dddd=_.cache(_.process(g.ctoken("sun mon tue wed thu fri sat"),function(s){return function(){this.weekday=s;};}));g.M=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d|\d)/),t.month));g.MM=_.cache(_.process(_.rtoken(/^(1[0-2]|0\d)/),t.month));g.MMM=g.MMMM=_.cache(_.process(g.ctoken("jan feb mar apr may jun jul aug sep oct nov dec"),t.month));g.y=_.cache(_.process(_.rtoken(/^(\d\d?)/),t.year));g.yy=_.cache(_.process(_.rtoken(/^(\d\d)/),t.year));g.yyy=_.cache(_.process(_.rtoken(/^(\d\d?\d?\d?)/),t.year));g.yyyy=_.cache(_.process(_.rtoken(/^(\d\d\d\d)/),t.year));_fn=function(){return _.each(_.any.apply(null,arguments),_.not(g.ctoken2("timeContext")));};g.day=_fn(g.d,g.dd);g.month=_fn(g.M,g.MMM);g.year=_fn(g.yyyy,g.yy);g.orientation=_.process(g.ctoken("past future"),function(s){return function(){this.orient=s;};});g.operator=_.process(g.ctoken("add subtract"),function(s){return function(){this.operator=s;};});g.rday=_.process(g.ctoken("yesterday tomorrow today now"),t.rday);g.unit=_.process(g.ctoken("second minute hour day week month year"),function(s){return function(){this.unit=s;};});g.value=_.process(_.rtoken(/^\d\d?(st|nd|rd|th)?/),function(s){return function(){this.value=s.replace(/\D/g,"");};});g.expression=_.set([g.rday,g.operator,g.value,g.unit,g.orientation,g.ddd,g.MMM]);_fn=function(){return _.set(arguments,g.datePartDelimiter);};g.mdy=_fn(g.ddd,g.month,g.day,g.year);g.ymd=_fn(g.ddd,g.year,g.month,g.day);g.dmy=_fn(g.ddd,g.day,g.month,g.year);g.date=function(s){return((g[$C.dateElementOrder]||g.mdy).call(this,s));};g.format=_.process(_.many(_.any(_.process(_.rtoken(/^(dd?d?d?|MM?M?M?|yy?y?y?|hh?|HH?|mm?|ss?|tt?|zz?z?)/),function(fmt){if(g[fmt]){return g[fmt];}else{throw $D.Parsing.Exception(fmt);}}),_.process(_.rtoken(/^[^dMyhHmstz]+/),function(s){return _.ignore(_.stoken(s));}))),function(rules){return _.process(_.each.apply(null,rules),t.finishExact);});var _F={};var _get=function(f){return _F[f]=(_F[f]||g.format(f)[0]);};g.formats=function(fx){if(fx instanceof Array){var rx=[];for(var i=0;i<fx.length;i++){rx.push(_get(fx[i]));}
return _.any.apply(null,rx);}else{return _get(fx);}};g._formats=g.formats(["\"yyyy-MM-ddTHH:mm:ssZ\"","yyyy-MM-ddTHH:mm:ssZ","yyyy-MM-ddTHH:mm:ssz","yyyy-MM-ddTHH:mm:ss","yyyy-MM-ddTHH:mmZ","yyyy-MM-ddTHH:mmz","yyyy-MM-ddTHH:mm","ddd, MMM dd, yyyy H:mm:ss tt","ddd MMM d yyyy HH:mm:ss zzz","MMddyyyy","ddMMyyyy","Mddyyyy","ddMyyyy","Mdyyyy","dMyyyy","yyyy","Mdyy","dMyy","d"]);g._start=_.process(_.set([g.date,g.time,g.expression],g.generalDelimiter,g.whiteSpace),t.finish);g.start=function(s){try{var r=g._formats.call({},s);if(r[1].length===0){return r;}}catch(e){}
return g._start.call({},s);};$D._parse=$D.parse;$D.parse=function(s){var r=null;if(!s){return null;}
if(s instanceof Date){return s;}
try{r=$D.Grammar.start.call({},s.replace(/^\s*(\S*(\s+\S+)*)\s*$/,"$1"));}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};$D.getParseFunction=function(fx){var fn=$D.Grammar.formats(fx);return function(s){var r=null;try{r=fn.call({},s);}catch(e){return null;}
return((r[1].length===0)?r[0]:null);};};$D.parseExact=function(s,fx){return $D.getParseFunction(fx)(s);};}());
/*!
* jQuery JavaScript Library v3.4.1
* https://jquery.com/
*
* Includes Sizzle.js
* https://sizzlejs.com/
*
* Copyright JS Foundation and other contributors
* Released under the MIT license
* https://jquery.org/license
*
* Date: 2019-05-01T21:04Z
*/
( function( global, factory ) {
"use strict";
if ( typeof module === "object" && typeof module.exports === "object" ) {
// For CommonJS and CommonJS-like environments where a proper `window`
// is present, execute the factory and get jQuery.
// For environments that do not have a `window` with a `document`
// (such as Node.js), expose a factory as module.exports.
// This accentuates the need for the creation of a real `window`.
// e.g. var jQuery = require("jquery")(window);
// See ticket #14549 for more info.
module.exports = global.document ?
factory( global, true ) :
function( w ) {
if ( !w.document ) {
throw new Error( "jQuery requires a window with a document" );
}
return factory( w );
};
} else {
factory( global );
}
// Pass this if window is not defined yet
} )( typeof window !== "undefined" ? window : this, function( window, noGlobal ) {
// Edge <= 12 - 13+, Firefox <=18 - 45+, IE 10 - 11, Safari 5.1 - 9+, iOS 6 - 9.1
// throw exceptions when non-strict code (e.g., ASP.NET 4.5) accesses strict mode
// arguments.callee.caller (trac-13335). But as of jQuery 3.0 (2016), strict mode should be common
// enough that all such attempts are guarded in a try block.
"use strict";
var arr = [];
var document = window.document;
var getProto = Object.getPrototypeOf;
var slice = arr.slice;
var concat = arr.concat;
var push = arr.push;
var indexOf = arr.indexOf;
var class2type = {};
var toString = class2type.toString;
var hasOwn = class2type.hasOwnProperty;
var fnToString = hasOwn.toString;
var ObjectFunctionString = fnToString.call( Object );
var support = {};
var isFunction = function isFunction( obj ) {
// Support: Chrome <=57, Firefox <=52
// In some browsers, typeof returns "function" for HTML <object> elements
// (i.e., `typeof document.createElement( "object" ) === "function"`).
// We don't want to classify *any* DOM node as a function.
return typeof obj === "function" && typeof obj.nodeType !== "number";
};
var isWindow = function isWindow( obj ) {
return obj != null && obj === obj.window;
};
var preservedScriptAttributes = {
type: true,
src: true,
nonce: true,
noModule: true
};
function DOMEval( code, node, doc ) {
doc = doc || document;
var i, val,
script = doc.createElement( "script" );
script.text = code;
if ( node ) {
for ( i in preservedScriptAttributes ) {
// Support: Firefox 64+, Edge 18+
// Some browsers don't support the "nonce" property on scripts.
// On the other hand, just using `getAttribute` is not enough as
// the `nonce` attribute is reset to an empty string whenever it
// becomes browsing-context connected.
// See https://github.com/whatwg/html/issues/2369
// See https://html.spec.whatwg.org/#nonce-attributes
// The `node.getAttribute` check was added for the sake of
// `jQuery.globalEval` so that it can fake a nonce-containing node
// via an object.
val = node[ i ] || node.getAttribute && node.getAttribute( i );
if ( val ) {
script.setAttribute( i, val );
}
}
}
doc.head.appendChild( script ).parentNode.removeChild( script );
}
function toType( obj ) {
if ( obj == null ) {
return obj + "";
}
// Support: Android <=2.3 only (functionish RegExp)
return typeof obj === "object" || typeof obj === "function" ?
class2type[ toString.call( obj ) ] || "object" :
typeof obj;
}
/* global Symbol */
// Defining this global in .eslintrc.json would create a danger of using the global
// unguarded in another place, it seems safer to define global only for this module
var
version = "3.4.1",
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},
// Support: Android <=4.0 only
// Make sure we trim BOM and NBSP
rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;
jQuery.fn = jQuery.prototype = {
// The current version of jQuery being used
jquery: version,
constructor: jQuery,
// The default length of a jQuery object is 0
length: 0,
toArray: function() {
return slice.call( this );
},
// Get the Nth element in the matched element set OR
// Get the whole matched element set as a clean array
get: function( num ) {
// Return all the elements in a clean array
if ( num == null ) {
return slice.call( this );
}
// Return just the one element from the set
return num < 0 ? this[ num + this.length ] : this[ num ];
},
// Take an array of elements and push it onto the stack
// (returning the new matched element set)
pushStack: function( elems ) {
// Build a new jQuery matched element set
var ret = jQuery.merge( this.constructor(), elems );
// Add the old object onto the stack (as a reference)
ret.prevObject = this;
// Return the newly-formed element set
return ret;
},
// Execute a callback for every element in the matched set.
each: function( callback ) {
return jQuery.each( this, callback );
},
map: function( callback ) {
return this.pushStack( jQuery.map( this, function( elem, i ) {
return callback.call( elem, i, elem );
} ) );
},
slice: function() {
return this.pushStack( slice.apply( this, arguments ) );
},
first: function() {
return this.eq( 0 );
},
last: function() {
return this.eq( -1 );
},
eq: function( i ) {
var len = this.length,
j = +i + ( i < 0 ? len : 0 );
return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] );
},
end: function() {
return this.prevObject || this.constructor();
},
// For internal use only.
// Behaves like an Array's method, not like a jQuery method.
push: push,
sort: arr.sort,
splice: arr.splice
};
jQuery.extend = jQuery.fn.extend = function() {
var options, name, src, copy, copyIsArray, clone,
target = arguments[ 0 ] || {},
i = 1,
length = arguments.length,
deep = false;
// Handle a deep copy situation
if ( typeof target === "boolean" ) {
deep = target;
// Skip the boolean and the target
target = arguments[ i ] || {};
i++;
}
// Handle case when target is a string or something (possible in deep copy)
if ( typeof target !== "object" && !isFunction( target ) ) {
target = {};
}
// Extend jQuery itself if only one argument is passed
if ( i === length ) {
target = this;
i--;
}
for ( ; i < length; i++ ) {
// Only deal with non-null/undefined values
if ( ( options = arguments[ i ] ) != null ) {
// Extend the base object
for ( name in options ) {
copy = options[ name ];
// Prevent Object.prototype pollution
// Prevent never-ending loop
if ( name === "__proto__" || target === copy ) {
continue;
}
// Recurse if we're merging plain objects or arrays
if ( deep && copy && ( jQuery.isPlainObject( copy ) ||
( copyIsArray = Array.isArray( copy ) ) ) ) {
src = target[ name ];
// Ensure proper type for the source value
if ( copyIsArray && !Array.isArray( src ) ) {
clone = [];
} else if ( !copyIsArray && !jQuery.isPlainObject( src ) ) {
clone = {};
} else {
clone = src;
}
copyIsArray = false;
// Never move original objects, clone them
target[ name ] = jQuery.extend( deep, clone, copy );
// Don't bring in undefined values
} else if ( copy !== undefined ) {
target[ name ] = copy;
}
}
}
}
// Return the modified object
return target;
};
jQuery.extend( {
// Unique for each copy of jQuery on the page
expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ),
// Assume jQuery is ready without the ready module
isReady: true,
error: function( msg ) {
throw new Error( msg );
},
noop: function() {},
isPlainObject: function( obj ) {
var proto, Ctor;
// Detect obvious negatives
// Use toString instead of jQuery.type to catch host objects
if ( !obj || toString.call( obj ) !== "[object Object]" ) {
return false;
}
proto = getProto( obj );
// Objects with no prototype (e.g., `Object.create( null )`) are plain
if ( !proto ) {
return true;
}
// Objects with prototype are plain iff they were constructed by a global Object function
Ctor = hasOwn.call( proto, "constructor" ) && proto.constructor;
return typeof Ctor === "function" && fnToString.call( Ctor ) === ObjectFunctionString;
},
isEmptyObject: function( obj ) {
var name;
for ( name in obj ) {
return false;
}
return true;
},
// Evaluates a script in a global context
globalEval: function( code, options ) {
DOMEval( code, { nonce: options && options.nonce } );
},
each: function( obj, callback ) {
var length, i = 0;
if ( isArrayLike( obj ) ) {
length = obj.length;
for ( ; i < length; i++ ) {
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
} else {
for ( i in obj ) {
if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) {
break;
}
}
}
return obj;
},
// Support: Android <=4.0 only
trim: function( text ) {
return text == null ?
"" :
( text + "" ).replace( rtrim, "" );
},
// results is for internal usage only
makeArray: function( arr, results ) {
var ret = results || [];
if ( arr != null ) {
if ( isArrayLike( Object( arr ) ) ) {
jQuery.merge( ret,
typeof arr === "string" ?
[ arr ] : arr
);
} else {
push.call( ret, arr );
}
}
return ret;
},
inArray: function( elem, arr, i ) {
return arr == null ? -1 : indexOf.call( arr, elem, i );
},
// Support: Android <=4.0 only, PhantomJS 1 only
// push.apply(_, arraylike) throws on ancient WebKit
merge: function( first, second ) {
var len = +second.length,
j = 0,
i = first.length;
for ( ; j < len; j++ ) {
first[ i++ ] = second[ j ];
}
first.length = i;
return first;
},
grep: function( elems, callback, invert ) {
var callbackInverse,
matches = [],
i = 0,
length = elems.length,
callbackExpect = !invert;
// Go through the array, only saving the items
// that pass the validator function
for ( ; i < length; i++ ) {
callbackInverse = !callback( elems[ i ], i );
if ( callbackInverse !== callbackExpect ) {
matches.push( elems[ i ] );
}
}
return matches;
},
// arg is for internal usage only
map: function( elems, callback, arg ) {
var length, value,
i = 0,
ret = [];
// Go through the array, translating each of the items to their new values
if ( isArrayLike( elems ) ) {
length = elems.length;
for ( ; i < length; i++ ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret.push( value );
}
}
// Go through every key on the object,
} else {
for ( i in elems ) {
value = callback( elems[ i ], i, arg );
if ( value != null ) {
ret.push( value );
}
}
}
// Flatten any nested arrays
return concat.apply( [], ret );
},
// A global GUID counter for objects
guid: 1,
// jQuery.support is not used in Core but other projects attach their
// properties to it so it needs to exist.
support: support
} );
if ( typeof Symbol === "function" ) {
jQuery.fn[ Symbol.iterator ] = arr[ Symbol.iterator ];
}
// Populate the class2type map
jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ),
function( i, name ) {
class2type[ "[object " + name + "]" ] = name.toLowerCase();
} );
function isArrayLike( obj ) {
// Support: real iOS 8.2 only (not reproducible in simulator)
// `in` check used to prevent JIT error (gh-2145)
// hasOwn isn't used here due to false negatives
// regarding Nodelist length in IE
var length = !!obj && "length" in obj && obj.length,
type = toType( obj );
if ( isFunction( obj ) || isWindow( obj ) ) {
return false;
}
return type === "array" || length === 0 ||
typeof length === "number" && length > 0 && ( length - 1 ) in obj;
}
var Sizzle =
/*!
* Sizzle CSS Selector Engine v2.3.4
* https://sizzlejs.com/
*
* Copyright JS Foundation and other contributors
* Released under the MIT license
* https://js.foundation/
*
* Date: 2019-04-08
*/
(function( window ) {
var i,
support,
Expr,
getText,
isXML,
tokenize,
compile,
select,
outermostContext,
sortInput,
hasDuplicate,
// Local document vars
setDocument,
document,
docElem,
documentIsHTML,
rbuggyQSA,
rbuggyMatches,
matches,
contains,
// Instance-specific data
expando = "sizzle" + 1 * new Date(),
preferredDoc = window.document,
dirruns = 0,
done = 0,
classCache = createCache(),
tokenCache = createCache(),
compilerCache = createCache(),
nonnativeSelectorCache = createCache(),
sortOrder = function( a, b ) {
if ( a === b ) {
hasDuplicate = true;
}
return 0;
},
// Instance methods
hasOwn = ({}).hasOwnProperty,
arr = [],
pop = arr.pop,
push_native = arr.push,
push = arr.push,
slice = arr.slice,
// Use a stripped-down indexOf as it's faster than native
// https://jsperf.com/thor-indexof-vs-for/5
indexOf = function( list, elem ) {
var i = 0,
len = list.length;
for ( ; i < len; i++ ) {
if ( list[i] === elem ) {
return i;
}
}
return -1;
},
booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",
// Regular expressions
// http://www.w3.org/TR/css3-selectors/#whitespace
whitespace = "[\\x20\\t\\r\\n\\f]",
// http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier
identifier = "(?:\\\\.|[\\w-]|[^\0-\\xa0])+",
// Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors
attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace +
// Operator (capture 2)
"*([*^$|!~]?=)" + whitespace +
// "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]"
"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace +
"*\\]",
pseudos = ":(" + identifier + ")(?:\\((" +
// To reduce the number of selectors needing tokenize in the preFilter, prefer arguments:
// 1. quoted (capture 3; capture 4 or capture 5)
"('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" +
// 2. simple (capture 6)
"((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" +
// 3. anything else (capture 2)
".*" +
")\\)|)",
// Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter
rwhitespace = new RegExp( whitespace + "+", "g" ),
rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ),
rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ),
rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ),
rdescend = new RegExp( whitespace + "|>" ),
rpseudo = new RegExp( pseudos ),
ridentifier = new RegExp( "^" + identifier + "$" ),
matchExpr = {
"ID": new RegExp( "^#(" + identifier + ")" ),
"CLASS": new RegExp( "^\\.(" + identifier + ")" ),
"TAG": new RegExp( "^(" + identifier + "|[*])" ),
"ATTR": new RegExp( "^" + attributes ),
"PSEUDO": new RegExp( "^" + pseudos ),
"CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace +
"*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace +
"*(\\d+)|))" + whitespace + "*\\)|)", "i" ),
"bool": new RegExp( "^(?:" + booleans + ")$", "i" ),
// For use in libraries implementing .is()
// We use this for POS matching in `select`
"needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" +
whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" )
},
rhtml = /HTML$/i,
rinputs = /^(?:input|select|textarea|button)$/i,
rheader = /^h\d$/i,
rnative = /^[^{]+\{\s*\[native \w/,
// Easily-parseable/retrievable ID or TAG or CLASS selectors
rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,
rsibling = /[+~]/,
// CSS escapes
// http://www.w3.org/TR/CSS21/syndata.html#escaped-characters
runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ),
funescape = function( _, escaped, escapedWhitespace ) {
var high = "0x" + escaped - 0x10000;
// NaN means non-codepoint
// Support: Firefox<24
// Workaround erroneous numeric interpretation of +"0x"
return high !== high || escapedWhitespace ?
escaped :
high < 0 ?
// BMP codepoint
String.fromCharCode( high + 0x10000 ) :
// Supplemental Plane codepoint (surrogate pair)
String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 );
},
// CSS string/identifier serialization
// https://drafts.csswg.org/cssom/#common-serializing-idioms
rcssescape = /([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,
fcssescape = function( ch, asCodePoint ) {
if ( asCodePoint ) {
// U+0000 NULL becomes U+FFFD REPLACEMENT CHARACTER
if ( ch === "\0" ) {
return "\uFFFD";
}
// Control characters and (dependent upon position) numbers get escaped as code points
return ch.slice( 0, -1 ) + "\\" + ch.charCodeAt( ch.length - 1 ).toString( 16 ) + " ";
}
// Other potentially-special ASCII characters get backslash-escaped
return "\\" + ch;
},
// Used for iframes
// See setDocument()
// Removing the function wrapper causes a "Permission Denied"
// error in IE
unloadHandler = function() {
setDocument();
},
inDisabledFieldset = addCombinator(
function( elem ) {
return elem.disabled === true && elem.nodeName.toLowerCase() === "fieldset";
},
{ dir: "parentNode", next: "legend" }
);
// Optimize for push.apply( _, NodeList )
try {
push.apply(
(arr = slice.call( preferredDoc.childNodes )),
preferredDoc.childNodes
);
// Support: Android<4.0
// Detect silently failing push.apply
arr[ preferredDoc.childNodes.length ].nodeType;
} catch ( e ) {
push = { apply: arr.length ?
// Leverage slice if possible
function( target, els ) {
push_native.apply( target, slice.call(els) );
} :
// Support: IE<9
// Otherwise append directly
function( target, els ) {
var j = target.length,
i = 0;
// Can't trust NodeList.length
while ( (target[j++] = els[i++]) ) {}
target.length = j - 1;
}
};
}
function Sizzle( selector, context, results, seed ) {
var m, i, elem, nid, match, groups, newSelector,
newContext = context && context.ownerDocument,
// nodeType defaults to 9, since context defaults to document
nodeType = context ? context.nodeType : 9;
results = results || [];
// Return early from calls with invalid selector or context
if ( typeof selector !== "string" || !selector ||
nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) {
return results;
}
// Try to shortcut find operations (as opposed to filters) in HTML documents
if ( !seed ) {
if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) {
setDocument( context );
}
context = context || document;
if ( documentIsHTML ) {
// If the selector is sufficiently simple, try using a "get*By*" DOM method
// (excepting DocumentFragment context, where the methods don't exist)
if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) {
// ID selector
if ( (m = match[1]) ) {
// Document context
if ( nodeType === 9 ) {
if ( (elem = context.getElementById( m )) ) {
// Support: IE, Opera, Webkit
// TODO: identify versions
// getElementById can match elements by name instead of ID
if ( elem.id === m ) {
results.push( elem );
return results;
}
} else {
return results;
}
// Element context
} else {
// Support: IE, Opera, Webkit
// TODO: identify versions
// getElementById can match elements by name instead of ID
if ( newContext && (elem = newContext.getElementById( m )) &&
contains( context, elem ) &&
elem.id === m ) {
results.push( elem );
return results;
}
}
// Type selector
} else if ( match[2] ) {
push.apply( results, context.getElementsByTagName( selector ) );
return results;
// Class selector
} else if ( (m = match[3]) && support.getElementsByClassName &&
context.getElementsByClassName ) {
push.apply( results, context.getElementsByClassName( m ) );
return results;
}
}
// Take advantage of querySelectorAll
if ( support.qsa &&
!nonnativeSelectorCache[ selector + " " ] &&
(!rbuggyQSA || !rbuggyQSA.test( selector )) &&
// Support: IE 8 only
// Exclude object elements
(nodeType !== 1 || context.nodeName.toLowerCase() !== "object") ) {
newSelector = selector;
newContext = context;
// qSA considers elements outside a scoping root when evaluating child or
// descendant combinators, which is not what we want.
// In such cases, we work around the behavior by prefixing every selector in the
// list with an ID selector referencing the scope context.
// Thanks to Andrew Dupont for this technique.
if ( nodeType === 1 && rdescend.test( selector ) ) {
// Capture the context ID, setting it first if necessary
if ( (nid = context.getAttribute( "id" )) ) {
nid = nid.replace( rcssescape, fcssescape );
} else {
context.setAttribute( "id", (nid = expando) );
}
// Prefix every selector in the list
groups = tokenize( selector );
i = groups.length;
while ( i-- ) {
groups[i] = "#" + nid + " " + toSelector( groups[i] );
}
newSelector = groups.join( "," );
// Expand context for sibling selectors
newContext = rsibling.test( selector ) && testContext( context.parentNode ) ||
context;
}
try {
push.apply( results,
newContext.querySelectorAll( newSelector )
);
return results;
} catch ( qsaError ) {
nonnativeSelectorCache( selector, true );
} finally {
if ( nid === expando ) {
context.removeAttribute( "id" );
}
}
}
}
}
// All others
return select( selector.replace( rtrim, "$1" ), context, results, seed );
}
/**
* Create key-value caches of limited size
* @returns {function(string, object)} Returns the Object data after storing it on itself with
* property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength)
* deleting the oldest entry
*/
function createCache() {
var keys = [];
function cache( key, value ) {
// Use (key + " ") to avoid collision with native prototype properties (see Issue #157)
if ( keys.push( key + " " ) > Expr.cacheLength ) {
// Only keep the most recent entries
delete cache[ keys.shift() ];
}
return (cache[ key + " " ] = value);
}
return cache;
}
/**
* Mark a function for special use by Sizzle
* @param {Function} fn The function to mark
*/
function markFunction( fn ) {
fn[ expando ] = true;
return fn;
}
/**
* Support testing using an element
* @param {Function} fn Passed the created element and returns a boolean result
*/
function assert( fn ) {
var el = document.createElement("fieldset");
try {
return !!fn( el );
} catch (e) {
return false;
} finally {
// Remove from its parent by default
if ( el.parentNode ) {
el.parentNode.removeChild( el );
}
// release memory in IE
el = null;
}
}
/**
* Adds the same handler for all of the specified attrs
* @param {String} attrs Pipe-separated list of attributes
* @param {Function} handler The method that will be applied
*/
function addHandle( attrs, handler ) {
var arr = attrs.split("|"),
i = arr.length;
while ( i-- ) {
Expr.attrHandle[ arr[i] ] = handler;
}
}
/**
* Checks document order of two siblings
* @param {Element} a
* @param {Element} b
* @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b
*/
function siblingCheck( a, b ) {
var cur = b && a,
diff = cur && a.nodeType === 1 && b.nodeType === 1 &&
a.sourceIndex - b.sourceIndex;
// Use IE sourceIndex if available on both nodes
if ( diff ) {
return diff;
}
// Check if b follows a
if ( cur ) {
while ( (cur = cur.nextSibling) ) {
if ( cur === b ) {
return -1;
}
}
}
return a ? 1 : -1;
}
/**
* Returns a function to use in pseudos for input types
* @param {String} type
*/
function createInputPseudo( type ) {
return function( elem ) {
var name = elem.nodeName.toLowerCase();
return name === "input" && elem.type === type;
};
}
/**
* Returns a function to use in pseudos for buttons
* @param {String} type
*/
function createButtonPseudo( type ) {
return function( elem ) {
var name = elem.nodeName.toLowerCase();
return (name === "input" || name === "button") && elem.type === type;
};
}
/**
* Returns a function to use in pseudos for :enabled/:disabled
* @param {Boolean} disabled true for :disabled; false for :enabled
*/
function createDisabledPseudo( disabled ) {
// Known :disabled false positives: fieldset[disabled] > legend:nth-of-type(n+2) :can-disable
return function( elem ) {
// Only certain elements can match :enabled or :disabled
// https://html.spec.whatwg.org/multipage/scripting.html#selector-enabled
// https://html.spec.whatwg.org/multipage/scripting.html#selector-disabled
if ( "form" in elem ) {
// Check for inherited disabledness on relevant non-disabled elements:
// * listed form-associated elements in a disabled fieldset
// https://html.spec.whatwg.org/multipage/forms.html#category-listed
// https://html.spec.whatwg.org/multipage/forms.html#concept-fe-disabled
// * option elements in a disabled optgroup
// https://html.spec.whatwg.org/multipage/forms.html#concept-option-disabled
// All such elements have a "form" property.
if ( elem.parentNode && elem.disabled === false ) {
// Option elements defer to a parent optgroup if present
if ( "label" in elem ) {
if ( "label" in elem.parentNode ) {
return elem.parentNode.disabled === disabled;
} else {
return elem.disabled === disabled;
}
}
// Support: IE 6 - 11
// Use the isDisabled shortcut property to check for disabled fieldset ancestors
return elem.isDisabled === disabled ||
// Where there is no isDisabled, check manually
/* jshint -W018 */
elem.isDisabled !== !disabled &&
inDisabledFieldset( elem ) === disabled;
}
return elem.disabled === disabled;
// Try to winnow out elements that can't be disabled before trusting the disabled property.
// Some victims get caught in our net (label, legend, menu, track), but it shouldn't
// even exist on them, let alone have a boolean value.
} else if ( "label" in elem ) {
return elem.disabled === disabled;
}
// Remaining elements are neither :enabled nor :disabled
return false;
};
}
/**
* Returns a function to use in pseudos for positionals
* @param {Function} fn
*/
function createPositionalPseudo( fn ) {
return markFunction(function( argument ) {
argument = +argument;
return markFunction(function( seed, matches ) {
var j,
matchIndexes = fn( [], seed.length, argument ),
i = matchIndexes.length;
// Match elements found at the specified indexes
while ( i-- ) {
if ( seed[ (j = matchIndexes[i]) ] ) {
seed[j] = !(matches[j] = seed[j]);
}
}
});
});
}
/**
* Checks a node for validity as a Sizzle context
* @param {Element|Object=} context
* @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value
*/
function testContext( context ) {
return context && typeof context.getElementsByTagName !== "undefined" && context;
}
// Expose support vars for convenience
support = Sizzle.support = {};
/**
* Detects XML nodes
* @param {Element|Object} elem An element or a document
* @returns {Boolean} True iff elem is a non-HTML XML node
*/
isXML = Sizzle.isXML = function( elem ) {
var namespace = elem.namespaceURI,
docElem = (elem.ownerDocument || elem).documentElement;
// Support: IE <=8
// Assume HTML when documentElement doesn't yet exist, such as inside loading iframes
// https://bugs.jquery.com/ticket/4833
return !rhtml.test( namespace || docElem && docElem.nodeName || "HTML" );
};
/**
* Sets document-related variables once based on the current document
* @param {Element|Object} [doc] An element or document object to use to set the document
* @returns {Object} Returns the current document
*/
setDocument = Sizzle.setDocument = function( node ) {
var hasCompare, subWindow,
doc = node ? node.ownerDocument || node : preferredDoc;
// Return early if doc is invalid or already selected
if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) {
return document;
}
// Update global variables
document = doc;
docElem = document.documentElement;
documentIsHTML = !isXML( document );
// Support: IE 9-11, Edge
// Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936)
if ( preferredDoc !== document &&
(subWindow = document.defaultView) && subWindow.top !== subWindow ) {
// Support: IE 11, Edge
if ( subWindow.addEventListener ) {
subWindow.addEventListener( "unload", unloadHandler, false );
// Support: IE 9 - 10 only
} else if ( subWindow.attachEvent ) {
subWindow.attachEvent( "onunload", unloadHandler );
}
}
/* Attributes
---------------------------------------------------------------------- */
// Support: IE<8
// Verify that getAttribute really returns attributes and not properties
// (excepting IE8 booleans)
support.attributes = assert(function( el ) {
el.className = "i";
return !el.getAttribute("className");
});
/* getElement(s)By*
---------------------------------------------------------------------- */
// Check if getElementsByTagName("*") returns only elements
support.getElementsByTagName = assert(function( el ) {
el.appendChild( document.createComment("") );
return !el.getElementsByTagName("*").length;
});
// Support: IE<9
support.getElementsByClassName = rnative.test( document.getElementsByClassName );
// Support: IE<10
// Check if getElementById returns elements by name
// The broken getElementById methods don't pick up programmatically-set names,
// so use a roundabout getElementsByName test
support.getById = assert(function( el ) {
docElem.appendChild( el ).id = expando;
return !document.getElementsByName || !document.getElementsByName( expando ).length;
});
// ID filter and find
if ( support.getById ) {
Expr.filter["ID"] = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {
return elem.getAttribute("id") === attrId;
};
};
Expr.find["ID"] = function( id, context ) {
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
var elem = context.getElementById( id );
return elem ? [ elem ] : [];
}
};
} else {
Expr.filter["ID"] = function( id ) {
var attrId = id.replace( runescape, funescape );
return function( elem ) {
var node = typeof elem.getAttributeNode !== "undefined" &&
elem.getAttributeNode("id");
return node && node.value === attrId;
};
};
// Support: IE 6 - 7 only
// getElementById is not reliable as a find shortcut
Expr.find["ID"] = function( id, context ) {
if ( typeof context.getElementById !== "undefined" && documentIsHTML ) {
var node, i, elems,
elem = context.getElementById( id );
if ( elem ) {
// Verify the id attribute
node = elem.getAttributeNode("id");
if ( node && node.value === id ) {
return [ elem ];
}
// Fall back on getElementsByName
elems = context.getElementsByName( id );
i = 0;
while ( (elem = elems[i++]) ) {
node = elem.getAttributeNode("id");
if ( node && node.value === id ) {
return [ elem ];
}
}
}
return [];
}
};
}
// Tag
Expr.find["TAG"] = support.getElementsByTagName ?
function( tag, context ) {
if ( typeof context.getElementsByTagName !== "undefined" ) {
return context.getElementsByTagName( tag );
// DocumentFragment nodes don't have gEBTN
} else if ( support.qsa ) {
return context.querySelectorAll( tag );
}
} :
function( tag, context ) {
var elem,
tmp = [],
i = 0,
// By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too
results = context.getElementsByTagName( tag );
// Filter out possible comments
if ( tag === "*" ) {
while ( (elem = results[i++]) ) {
if ( elem.nodeType === 1 ) {
tmp.push( elem );
}
}
return tmp;
}
return results;
};
// Class
Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) {
if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) {
return context.getElementsByClassName( className );
}
};
/* QSA/matchesSelector
---------------------------------------------------------------------- */
// QSA and matchesSelector support
// matchesSelector(:active) reports false when true (IE9/Opera 11.5)
rbuggyMatches = [];
// qSa(:focus) reports false when true (Chrome 21)
// We allow this because of a bug in IE8/9 that throws an error
// whenever `document.activeElement` is accessed on an iframe
// So, we allow :focus to pass through QSA all the time to avoid the IE error
// See https://bugs.jquery.com/ticket/13378
rbuggyQSA = [];
if ( (support.qsa = rnative.test( document.querySelectorAll )) ) {
// Build QSA regex
// Regex strategy adopted from Diego Perini
assert(function( el ) {
// Select is set to empty string on purpose
// This is to test IE's treatment of not explicitly
// setting a boolean content attribute,
// since its presence should be enough
// https://bugs.jquery.com/ticket/12359
docElem.appendChild( el ).innerHTML = "<a id='" + expando + "'></a>" +
"<select id='" + expando + "-\r\\' msallowcapture=''>" +
"<option selected=''></option></select>";
// Support: IE8, Opera 11-12.16
// Nothing should be selected when empty strings follow ^= or $= or *=
// The test attribute must be unknown in Opera but "safe" for WinRT
// https://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section
if ( el.querySelectorAll("[msallowcapture^='']").length ) {
rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" );
}
// Support: IE8
// Boolean attributes and "value" are not treated correctly
if ( !el.querySelectorAll("[selected]").length ) {
rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" );
}
// Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+
if ( !el.querySelectorAll( "[id~=" + expando + "-]" ).length ) {
rbuggyQSA.push("~=");
}
// Webkit/Opera - :checked should return selected option elements
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
// IE8 throws error here and will not see later tests
if ( !el.querySelectorAll(":checked").length ) {
rbuggyQSA.push(":checked");
}
// Support: Safari 8+, iOS 8+
// https://bugs.webkit.org/show_bug.cgi?id=136851
// In-page `selector#id sibling-combinator selector` fails
if ( !el.querySelectorAll( "a#" + expando + "+*" ).length ) {
rbuggyQSA.push(".#.+[+~]");
}
});
assert(function( el ) {
el.innerHTML = "<a href='' disabled='disabled'></a>" +
"<select disabled='disabled'><option/></select>";
// Support: Windows 8 Native Apps
// The type and name attributes are restricted during .innerHTML assignment
var input = document.createElement("input");
input.setAttribute( "type", "hidden" );
el.appendChild( input ).setAttribute( "name", "D" );
// Support: IE8
// Enforce case-sensitivity of name attribute
if ( el.querySelectorAll("[name=d]").length ) {
rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" );
}
// FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled)
// IE8 throws error here and will not see later tests
if ( el.querySelectorAll(":enabled").length !== 2 ) {
rbuggyQSA.push( ":enabled", ":disabled" );
}
// Support: IE9-11+
// IE's :disabled selector does not pick up the children of disabled fieldsets
docElem.appendChild( el ).disabled = true;
if ( el.querySelectorAll(":disabled").length !== 2 ) {
rbuggyQSA.push( ":enabled", ":disabled" );
}
// Opera 10-11 does not throw on post-comma invalid pseudos
el.querySelectorAll("*,:x");
rbuggyQSA.push(",.*:");
});
}
if ( (support.matchesSelector = rnative.test( (matches = docElem.matches ||
docElem.webkitMatchesSelector ||
docElem.mozMatchesSelector ||
docElem.oMatchesSelector ||
docElem.msMatchesSelector) )) ) {
assert(function( el ) {
// Check to see if it's possible to do matchesSelector
// on a disconnected node (IE 9)
support.disconnectedMatch = matches.call( el, "*" );
// This should fail with an exception
// Gecko does not error, returns false instead
matches.call( el, "[s!='']:x" );
rbuggyMatches.push( "!=", pseudos );
});
}
rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") );
rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") );
/* Contains
---------------------------------------------------------------------- */
hasCompare = rnative.test( docElem.compareDocumentPosition );
// Element contains another
// Purposefully self-exclusive
// As in, an element does not contain itself
contains = hasCompare || rnative.test( docElem.contains ) ?
function( a, b ) {
var adown = a.nodeType === 9 ? a.documentElement : a,
bup = b && b.parentNode;
return a === bup || !!( bup && bup.nodeType === 1 && (
adown.contains ?
adown.contains( bup ) :
a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16
));
} :
function( a, b ) {
if ( b ) {
while ( (b = b.parentNode) ) {
if ( b === a ) {
return true;
}
}
}
return false;
};
/* Sorting
---------------------------------------------------------------------- */
// Document order sorting
sortOrder = hasCompare ?
function( a, b ) {
// Flag for duplicate removal
if ( a === b ) {
hasDuplicate = true;
return 0;
}
// Sort on method existence if only one input has compareDocumentPosition
var compare = !a.compareDocumentPosition - !b.compareDocumentPosition;
if ( compare ) {
return compare;
}
// Calculate position if both inputs belong to the same document
compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ?
a.compareDocumentPosition( b ) :
// Otherwise we know they are disconnected
1;
// Disconnected nodes
if ( compare & 1 ||
(!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) {
// Choose the first element that is related to our preferred document
if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) {
return -1;
}
if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) {
return 1;
}
// Maintain original order
return sortInput ?
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
0;
}
return compare & 4 ? -1 : 1;
} :
function( a, b ) {
// Exit early if the nodes are identical
if ( a === b ) {
hasDuplicate = true;
return 0;
}
var cur,
i = 0,
aup = a.parentNode,
bup = b.parentNode,
ap = [ a ],
bp = [ b ];
// Parentless nodes are either documents or disconnected
if ( !aup || !bup ) {
return a === document ? -1 :
b === document ? 1 :
aup ? -1 :
bup ? 1 :
sortInput ?
( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) :
0;
// If the nodes are siblings, we can do a quick check
} else if ( aup === bup ) {
return siblingCheck( a, b );
}
// Otherwise we need full lists of their ancestors for comparison
cur = a;
while ( (cur = cur.parentNode) ) {
ap.unshift( cur );
}
cur = b;
while ( (cur = cur.parentNode) ) {
bp.unshift( cur );
}
// Walk down the tree looking for a discrepancy
while ( ap[i] === bp[i] ) {
i++;
}
return i ?
// Do a sibling check if the nodes have a common ancestor
siblingCheck( ap[i], bp[i] ) :
// Otherwise nodes in our document sort first
ap[i] === preferredDoc ? -1 :
bp[i] === preferredDoc ? 1 :
0;
};
return document;
};
Sizzle.matches = function( expr, elements ) {
return Sizzle( expr, null, null, elements );
};
Sizzle.matchesSelector = function( elem, expr ) {
// Set document vars if needed
if ( ( elem.ownerDocument || elem ) !== document ) {
setDocument( elem );
}
if ( support.matchesSelector && documentIsHTML &&
!nonnativeSelectorCache[ expr + " " ] &&
( !rbuggyMatches || !rbuggyMatches.test( expr ) ) &&
( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) {
try {
var ret = matches.call( elem, expr );
// IE 9's matchesSelector returns false on disconnected nodes
if ( ret || support.disconnectedMatch ||
// As well, disconnected nodes are said to be in a document
// fragment in IE 9
elem.document && elem.document.nodeType !== 11 ) {
return ret;
}
} catch (e) {
nonnativeSelectorCache( expr, true );
}
}
return Sizzle( expr, document, null, [ elem ] ).length > 0;
};
Sizzle.contains = function( context, elem ) {
// Set document vars if needed
if ( ( context.ownerDocument || context ) !== document ) {
setDocument( context );
}
return contains( context, elem );
};
Sizzle.attr = function( elem, name ) {
// Set document vars if needed
if ( ( elem.ownerDocument || elem ) !== document ) {
setDocument( elem );
}
var fn = Expr.attrHandle[ name.toLowerCase() ],
// Don't get fooled by Object.prototype properties (jQuery #13807)
val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ?
fn( elem, name, !documentIsHTML ) :
undefined;
return val !== undefined ?
val :
support.attributes || !documentIsHTML ?
elem.getAttribute( name ) :
(val = elem.getAttributeNode(name)) && val.specified ?
val.value :
null;
};
Sizzle.escape = function( sel ) {
return (sel + "").replace( rcssescape, fcssescape );
};
Sizzle.error = function( msg ) {
throw new Error( "Syntax error, unrecognized expression: " + msg );
};
/**
* Document sorting and removing duplicates
* @param {ArrayLike} results
*/
Sizzle.uniqueSort = function( results ) {
var elem,
duplicates = [],
j = 0,
i = 0;
// Unless we *know* we can detect duplicates, assume their presence
hasDuplicate = !support.detectDuplicates;
sortInput = !support.sortStable && results.slice( 0 );
results.sort( sortOrder );
if ( hasDuplicate ) {
while ( (elem = results[i++]) ) {
if ( elem === results[ i ] ) {
j = duplicates.push( i );
}
}
while ( j-- ) {
results.splice( duplicates[ j ], 1 );
}
}
// Clear input after sorting to release objects
// See https://github.com/jquery/sizzle/pull/225
sortInput = null;
return results;
};
/**
* Utility function for retrieving the text value of an array of DOM nodes
* @param {Array|Element} elem
*/
getText = Sizzle.getText = function( elem ) {
var node,
ret = "",
i = 0,
nodeType = elem.nodeType;
if ( !nodeType ) {
// If no nodeType, this is expected to be an array
while ( (node = elem[i++]) ) {
// Do not traverse comment nodes
ret += getText( node );
}
} else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) {
// Use textContent for elements
// innerText usage removed for consistency of new lines (jQuery #11153)
if ( typeof elem.textContent === "string" ) {
return elem.textContent;
} else {
// Traverse its children
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
ret += getText( elem );
}
}
} else if ( nodeType === 3 || nodeType === 4 ) {
return elem.nodeValue;
}
// Do not include comment or processing instruction nodes
return ret;
};
Expr = Sizzle.selectors = {
// Can be adjusted by the user
cacheLength: 50,
createPseudo: markFunction,
match: matchExpr,
attrHandle: {},
find: {},
relative: {
">": { dir: "parentNode", first: true },
" ": { dir: "parentNode" },
"+": { dir: "previousSibling", first: true },
"~": { dir: "previousSibling" }
},
preFilter: {
"ATTR": function( match ) {
match[1] = match[1].replace( runescape, funescape );
// Move the given value to match[3] whether quoted or unquoted
match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape );
if ( match[2] === "~=" ) {
match[3] = " " + match[3] + " ";
}
return match.slice( 0, 4 );
},
"CHILD": function( match ) {
/* matches from matchExpr["CHILD"]
1 type (only|nth|...)
2 what (child|of-type)
3 argument (even|odd|\d*|\d*n([+-]\d+)?|...)
4 xn-component of xn+y argument ([+-]?\d*n|)
5 sign of xn-component
6 x of xn-component
7 sign of y-component
8 y of y-component
*/
match[1] = match[1].toLowerCase();
if ( match[1].slice( 0, 3 ) === "nth" ) {
// nth-* requires argument
if ( !match[3] ) {
Sizzle.error( match[0] );
}
// numeric x and y parameters for Expr.filter.CHILD
// remember that false/true cast respectively to 0/1
match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) );
match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" );
// other types prohibit arguments
} else if ( match[3] ) {
Sizzle.error( match[0] );
}
return match;
},
"PSEUDO": function( match ) {
var excess,
unquoted = !match[6] && match[2];
if ( matchExpr["CHILD"].test( match[0] ) ) {
return null;
}
// Accept quoted arguments as-is
if ( match[3] ) {
match[2] = match[4] || match[5] || "";
// Strip excess characters from unquoted arguments
} else if ( unquoted && rpseudo.test( unquoted ) &&
// Get excess from tokenize (recursively)
(excess = tokenize( unquoted, true )) &&
// advance to the next closing parenthesis
(excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) {
// excess is a negative index
match[0] = match[0].slice( 0, excess );
match[2] = unquoted.slice( 0, excess );
}
// Return only captures needed by the pseudo filter method (type and argument)
return match.slice( 0, 3 );
}
},
filter: {
"TAG": function( nodeNameSelector ) {
var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase();
return nodeNameSelector === "*" ?
function() { return true; } :
function( elem ) {
return elem.nodeName && elem.nodeName.toLowerCase() === nodeName;
};
},
"CLASS": function( className ) {
var pattern = classCache[ className + " " ];
return pattern ||
(pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) &&
classCache( className, function( elem ) {
return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" );
});
},
"ATTR": function( name, operator, check ) {
return function( elem ) {
var result = Sizzle.attr( elem, name );
if ( result == null ) {
return operator === "!=";
}
if ( !operator ) {
return true;
}
result += "";
return operator === "=" ? result === check :
operator === "!=" ? result !== check :
operator === "^=" ? check && result.indexOf( check ) === 0 :
operator === "*=" ? check && result.indexOf( check ) > -1 :
operator === "$=" ? check && result.slice( -check.length ) === check :
operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 :
operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" :
false;
};
},
"CHILD": function( type, what, argument, first, last ) {
var simple = type.slice( 0, 3 ) !== "nth",
forward = type.slice( -4 ) !== "last",
ofType = what === "of-type";
return first === 1 && last === 0 ?
// Shortcut for :nth-*(n)
function( elem ) {
return !!elem.parentNode;
} :
function( elem, context, xml ) {
var cache, uniqueCache, outerCache, node, nodeIndex, start,
dir = simple !== forward ? "nextSibling" : "previousSibling",
parent = elem.parentNode,
name = ofType && elem.nodeName.toLowerCase(),
useCache = !xml && !ofType,
diff = false;
if ( parent ) {
// :(first|last|only)-(child|of-type)
if ( simple ) {
while ( dir ) {
node = elem;
while ( (node = node[ dir ]) ) {
if ( ofType ?
node.nodeName.toLowerCase() === name :
node.nodeType === 1 ) {
return false;
}
}
// Reverse direction for :only-* (if we haven't yet done so)
start = dir = type === "only" && !start && "nextSibling";
}
return true;
}
start = [ forward ? parent.firstChild : parent.lastChild ];
// non-xml :nth-child(...) stores cache data on `parent`
if ( forward && useCache ) {
// Seek `elem` from a previously-cached index
// ...in a gzip-friendly way
node = parent;
outerCache = node[ expando ] || (node[ expando ] = {});
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ node.uniqueID ] ||
(outerCache[ node.uniqueID ] = {});
cache = uniqueCache[ type ] || [];
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex && cache[ 2 ];
node = nodeIndex && parent.childNodes[ nodeIndex ];
while ( (node = ++nodeIndex && node && node[ dir ] ||
// Fallback to seeking `elem` from the start
(diff = nodeIndex = 0) || start.pop()) ) {
// When found, cache indexes on `parent` and break
if ( node.nodeType === 1 && ++diff && node === elem ) {
uniqueCache[ type ] = [ dirruns, nodeIndex, diff ];
break;
}
}
} else {
// Use previously-cached element index if available
if ( useCache ) {
// ...in a gzip-friendly way
node = elem;
outerCache = node[ expando ] || (node[ expando ] = {});
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ node.uniqueID ] ||
(outerCache[ node.uniqueID ] = {});
cache = uniqueCache[ type ] || [];
nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ];
diff = nodeIndex;
}
// xml :nth-child(...)
// or :nth-last-child(...) or :nth(-last)?-of-type(...)
if ( diff === false ) {
// Use the same loop as above to seek `elem` from the start
while ( (node = ++nodeIndex && node && node[ dir ] ||
(diff = nodeIndex = 0) || start.pop()) ) {
if ( ( ofType ?
node.nodeName.toLowerCase() === name :
node.nodeType === 1 ) &&
++diff ) {
// Cache the index of each encountered element
if ( useCache ) {
outerCache = node[ expando ] || (node[ expando ] = {});
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ node.uniqueID ] ||
(outerCache[ node.uniqueID ] = {});
uniqueCache[ type ] = [ dirruns, diff ];
}
if ( node === elem ) {
break;
}
}
}
}
}
// Incorporate the offset, then check against cycle size
diff -= last;
return diff === first || ( diff % first === 0 && diff / first >= 0 );
}
};
},
"PSEUDO": function( pseudo, argument ) {
// pseudo-class names are case-insensitive
// http://www.w3.org/TR/selectors/#pseudo-classes
// Prioritize by case sensitivity in case custom pseudos are added with uppercase letters
// Remember that setFilters inherits from pseudos
var args,
fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] ||
Sizzle.error( "unsupported pseudo: " + pseudo );
// The user may use createPseudo to indicate that
// arguments are needed to create the filter function
// just as Sizzle does
if ( fn[ expando ] ) {
return fn( argument );
}
// But maintain support for old signatures
if ( fn.length > 1 ) {
args = [ pseudo, pseudo, "", argument ];
return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ?
markFunction(function( seed, matches ) {
var idx,
matched = fn( seed, argument ),
i = matched.length;
while ( i-- ) {
idx = indexOf( seed, matched[i] );
seed[ idx ] = !( matches[ idx ] = matched[i] );
}
}) :
function( elem ) {
return fn( elem, 0, args );
};
}
return fn;
}
},
pseudos: {
// Potentially complex pseudos
"not": markFunction(function( selector ) {
// Trim the selector passed to compile
// to avoid treating leading and trailing
// spaces as combinators
var input = [],
results = [],
matcher = compile( selector.replace( rtrim, "$1" ) );
return matcher[ expando ] ?
markFunction(function( seed, matches, context, xml ) {
var elem,
unmatched = matcher( seed, null, xml, [] ),
i = seed.length;
// Match elements unmatched by `matcher`
while ( i-- ) {
if ( (elem = unmatched[i]) ) {
seed[i] = !(matches[i] = elem);
}
}
}) :
function( elem, context, xml ) {
input[0] = elem;
matcher( input, null, xml, results );
// Don't keep the element (issue #299)
input[0] = null;
return !results.pop();
};
}),
"has": markFunction(function( selector ) {
return function( elem ) {
return Sizzle( selector, elem ).length > 0;
};
}),
"contains": markFunction(function( text ) {
text = text.replace( runescape, funescape );
return function( elem ) {
return ( elem.textContent || getText( elem ) ).indexOf( text ) > -1;
};
}),
// "Whether an element is represented by a :lang() selector
// is based solely on the element's language value
// being equal to the identifier C,
// or beginning with the identifier C immediately followed by "-".
// The matching of C against the element's language value is performed case-insensitively.
// The identifier C does not have to be a valid language name."
// http://www.w3.org/TR/selectors/#lang-pseudo
"lang": markFunction( function( lang ) {
// lang value must be a valid identifier
if ( !ridentifier.test(lang || "") ) {
Sizzle.error( "unsupported lang: " + lang );
}
lang = lang.replace( runescape, funescape ).toLowerCase();
return function( elem ) {
var elemLang;
do {
if ( (elemLang = documentIsHTML ?
elem.lang :
elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) {
elemLang = elemLang.toLowerCase();
return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0;
}
} while ( (elem = elem.parentNode) && elem.nodeType === 1 );
return false;
};
}),
// Miscellaneous
"target": function( elem ) {
var hash = window.location && window.location.hash;
return hash && hash.slice( 1 ) === elem.id;
},
"root": function( elem ) {
return elem === docElem;
},
"focus": function( elem ) {
return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex);
},
// Boolean properties
"enabled": createDisabledPseudo( false ),
"disabled": createDisabledPseudo( true ),
"checked": function( elem ) {
// In CSS3, :checked should return both checked and selected elements
// http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked
var nodeName = elem.nodeName.toLowerCase();
return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected);
},
"selected": function( elem ) {
// Accessing this property makes selected-by-default
// options in Safari work properly
if ( elem.parentNode ) {
elem.parentNode.selectedIndex;
}
return elem.selected === true;
},
// Contents
"empty": function( elem ) {
// http://www.w3.org/TR/selectors/#empty-pseudo
// :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5),
// but not by others (comment: 8; processing instruction: 7; etc.)
// nodeType < 6 works because attributes (2) do not appear as children
for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) {
if ( elem.nodeType < 6 ) {
return false;
}
}
return true;
},
"parent": function( elem ) {
return !Expr.pseudos["empty"]( elem );
},
// Element/input types
"header": function( elem ) {
return rheader.test( elem.nodeName );
},
"input": function( elem ) {
return rinputs.test( elem.nodeName );
},
"button": function( elem ) {
var name = elem.nodeName.toLowerCase();
return name === "input" && elem.type === "button" || name === "button";
},
"text": function( elem ) {
var attr;
return elem.nodeName.toLowerCase() === "input" &&
elem.type === "text" &&
// Support: IE<8
// New HTML5 attribute values (e.g., "search") appear with elem.type === "text"
( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" );
},
// Position-in-collection
"first": createPositionalPseudo(function() {
return [ 0 ];
}),
"last": createPositionalPseudo(function( matchIndexes, length ) {
return [ length - 1 ];
}),
"eq": createPositionalPseudo(function( matchIndexes, length, argument ) {
return [ argument < 0 ? argument + length : argument ];
}),
"even": createPositionalPseudo(function( matchIndexes, length ) {
var i = 0;
for ( ; i < length; i += 2 ) {
matchIndexes.push( i );
}
return matchIndexes;
}),
"odd": createPositionalPseudo(function( matchIndexes, length ) {
var i = 1;
for ( ; i < length; i += 2 ) {
matchIndexes.push( i );
}
return matchIndexes;
}),
"lt": createPositionalPseudo(function( matchIndexes, length, argument ) {
var i = argument < 0 ?
argument + length :
argument > length ?
length :
argument;
for ( ; --i >= 0; ) {
matchIndexes.push( i );
}
return matchIndexes;
}),
"gt": createPositionalPseudo(function( matchIndexes, length, argument ) {
var i = argument < 0 ? argument + length : argument;
for ( ; ++i < length; ) {
matchIndexes.push( i );
}
return matchIndexes;
})
}
};
Expr.pseudos["nth"] = Expr.pseudos["eq"];
// Add button/input type pseudos
for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) {
Expr.pseudos[ i ] = createInputPseudo( i );
}
for ( i in { submit: true, reset: true } ) {
Expr.pseudos[ i ] = createButtonPseudo( i );
}
// Easy API for creating new setFilters
function setFilters() {}
setFilters.prototype = Expr.filters = Expr.pseudos;
Expr.setFilters = new setFilters();
tokenize = Sizzle.tokenize = function( selector, parseOnly ) {
var matched, match, tokens, type,
soFar, groups, preFilters,
cached = tokenCache[ selector + " " ];
if ( cached ) {
return parseOnly ? 0 : cached.slice( 0 );
}
soFar = selector;
groups = [];
preFilters = Expr.preFilter;
while ( soFar ) {
// Comma and first run
if ( !matched || (match = rcomma.exec( soFar )) ) {
if ( match ) {
// Don't consume trailing commas as valid
soFar = soFar.slice( match[0].length ) || soFar;
}
groups.push( (tokens = []) );
}
matched = false;
// Combinators
if ( (match = rcombinators.exec( soFar )) ) {
matched = match.shift();
tokens.push({
value: matched,
// Cast descendant combinators to space
type: match[0].replace( rtrim, " " )
});
soFar = soFar.slice( matched.length );
}
// Filters
for ( type in Expr.filter ) {
if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] ||
(match = preFilters[ type ]( match ))) ) {
matched = match.shift();
tokens.push({
value: matched,
type: type,
matches: match
});
soFar = soFar.slice( matched.length );
}
}
if ( !matched ) {
break;
}
}
// Return the length of the invalid excess
// if we're just parsing
// Otherwise, throw an error or return tokens
return parseOnly ?
soFar.length :
soFar ?
Sizzle.error( selector ) :
// Cache the tokens
tokenCache( selector, groups ).slice( 0 );
};
function toSelector( tokens ) {
var i = 0,
len = tokens.length,
selector = "";
for ( ; i < len; i++ ) {
selector += tokens[i].value;
}
return selector;
}
function addCombinator( matcher, combinator, base ) {
var dir = combinator.dir,
skip = combinator.next,
key = skip || dir,
checkNonElements = base && key === "parentNode",
doneName = done++;
return combinator.first ?
// Check against closest ancestor/preceding element
function( elem, context, xml ) {
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) {
return matcher( elem, context, xml );
}
}
return false;
} :
// Check against all ancestor/preceding elements
function( elem, context, xml ) {
var oldCache, uniqueCache, outerCache,
newCache = [ dirruns, doneName ];
// We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching
if ( xml ) {
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) {
if ( matcher( elem, context, xml ) ) {
return true;
}
}
}
} else {
while ( (elem = elem[ dir ]) ) {
if ( elem.nodeType === 1 || checkNonElements ) {
outerCache = elem[ expando ] || (elem[ expando ] = {});
// Support: IE <9 only
// Defend against cloned attroperties (jQuery gh-1709)
uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {});
if ( skip && skip === elem.nodeName.toLowerCase() ) {
elem = elem[ dir ] || elem;
} else if ( (oldCache = uniqueCache[ key ]) &&
oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) {
// Assign to newCache so results back-propagate to previous elements
return (newCache[ 2 ] = oldCache[ 2 ]);
} else {
// Reuse newcache so results back-propagate to previous elements
uniqueCache[ key ] = newCache;
// A match means we're done; a fail means we have to keep checking
if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) {
return true;
}
}
}
}
}
return false;
};
}
function elementMatcher( matchers ) {
return matchers.length > 1 ?
function( elem, context, xml ) {
var i = matchers.length;
while ( i-- ) {
if ( !matchers[i]( elem, context, xml ) ) {
return false;
}
}
return true;
} :
matchers[0];
}
function multipleContexts( selector, contexts, results ) {
var i = 0,
len = contexts.length;
for ( ; i < len; i++ ) {
Sizzle( selector, contexts[i], results );
}
return results;
}
function condense( unmatched, map, filter, context, xml ) {
var elem,
newUnmatched = [],
i = 0,
len = unmatched.length,
mapped = map != null;
for ( ; i < len; i++ ) {
if ( (elem = unmatched[i]) ) {
if ( !filter || filter( elem, context, xml ) ) {
newUnmatched.push( elem );
if ( mapped ) {
map.push( i );
}
}
}
}
return newUnmatched;
}
function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) {
if ( postFilter && !postFilter[ expando ] ) {
postFilter = setMatcher( postFilter );
}
if ( postFinder && !postFinder[ expando ] ) {
postFinder = setMatcher( postFinder, postSelector );
}
return markFunction(function( seed, results, context, xml ) {
var temp, i, elem,
preMap = [],
postMap = [],
preexisting = results.length,
// Get initial elements from seed or context
elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ),
// Prefilter to get matcher input, preserving a map for seed-results synchronization
matcherIn = preFilter && ( seed || !selector ) ?
condense( elems, preMap, preFilter, context, xml ) :
elems,
matcherOut = matcher ?
// If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results,
postFinder || ( seed ? preFilter : preexisting || postFilter ) ?
// ...intermediate processing is necessary
[] :
// ...otherwise use results directly
results :
matcherIn;
// Find primary matches
if ( matcher ) {
matcher( matcherIn, matcherOut, context, xml );
}
// Apply postFilter
if ( postFilter ) {
temp = condense( matcherOut, postMap );
postFilter( temp, [], context, xml );
// Un-match failing elements by moving them back to matcherIn
i = temp.length;
while ( i-- ) {
if ( (elem = temp[i]) ) {
matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem);
}
}
}
if ( seed ) {
if ( postFinder || preFilter ) {
if ( postFinder ) {
// Get the final matcherOut by condensing this intermediate into postFinder contexts
temp = [];
i = matcherOut.length;
while ( i-- ) {
if ( (elem = matcherOut[i]) ) {
// Restore matcherIn since elem is not yet a final match
temp.push( (matcherIn[i] = elem) );
}
}
postFinder( null, (matcherOut = []), temp, xml );
}
// Move matched elements from seed to results to keep them synchronized
i = matcherOut.length;
while ( i-- ) {
if ( (elem = matcherOut[i]) &&
(temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) {
seed[temp] = !(results[temp] = elem);
}
}
}
// Add elements to results, through postFinder if defined
} else {
matcherOut = condense(
matcherOut === results ?
matcherOut.splice( preexisting, matcherOut.length ) :
matcherOut
);
if ( postFinder ) {
postFinder( null, results, matcherOut, xml );
} else {
push.apply( results, matcherOut );
}
}
});
}
function matcherFromTokens( tokens ) {
var checkContext, matcher, j,
len = tokens.length,
leadingRelative = Expr.relative[ tokens[0].type ],
implicitRelative = leadingRelative || Expr.relative[" "],
i = leadingRelative ? 1 : 0,
// The foundational matcher ensures that elements are reachable from top-level context(s)
matchContext = addCombinator( function( elem ) {
return elem === checkContext;
}, implicitRelative, true ),
matchAnyContext = addCombinator( function( elem ) {
return indexOf( checkContext, elem ) > -1;
}, implicitRelative, true ),
matchers = [ function( elem, context, xml ) {
var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || (
(checkContext = context).nodeType ?
matchContext( elem, context, xml ) :
matchAnyContext( elem, context, xml ) );
// Avoid hanging onto element (issue #299)
checkContext = null;
return ret;
} ];
for ( ; i < len; i++ ) {
if ( (matcher = Expr.relative[ tokens[i].type ]) ) {
matchers = [ addCombinator(elementMatcher( matchers ), matcher) ];
} else {
matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches );
// Return special upon seeing a positional matcher
if ( matcher[ expando ] ) {
// Find the next relative operator (if any) for proper handling
j = ++i;
for ( ; j < len; j++ ) {
if ( Expr.relative[ tokens[j].type ] ) {
break;
}
}
return setMatcher(
i > 1 && elementMatcher( matchers ),
i > 1 && toSelector(
// If the preceding token was a descendant combinator, insert an implicit any-element `*`
tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" })
).replace( rtrim, "$1" ),
matcher,
i < j && matcherFromTokens( tokens.slice( i, j ) ),
j < len && matcherFromTokens( (tokens = tokens.slice( j )) ),
j < len && toSelector( tokens )
);
}
matchers.push( matcher );
}
}
return elementMatcher( matchers );
}
function matcherFromGroupMatchers( elementMatchers, setMatchers ) {
var bySet = setMatchers.length > 0,
byElement = elementMatchers.length > 0,
superMatcher = function( seed, context, xml, results, outermost ) {
var elem, j, matcher,
matchedCount = 0,
i = "0",
unmatched = seed && [],
setMatched = [],
contextBackup = outermostContext,
// We must always have either seed elements or outermost context
elems = seed || byElement && Expr.find["TAG"]( "*", outermost ),
// Use integer dirruns iff this is the outermost matcher
dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1),
len = elems.length;
if ( outermost ) {
outermostContext = context === document || context || outermost;
}
// Add elements passing elementMatchers directly to results
// Support: IE<9, Safari
// Tolerate NodeList properties (IE: "length"; Safari: <number>) matching elements by id
for ( ; i !== len && (elem = elems[i]) != null; i++ ) {
if ( byElement && elem ) {
j = 0;
if ( !context && elem.ownerDocument !== document ) {
setDocument( elem );
xml = !documentIsHTML;
}
while ( (matcher = elementMatchers[j++]) ) {
if ( matcher( elem, context || document, xml) ) {
results.push( elem );
break;
}
}
if ( outermost ) {
dirruns = dirrunsUnique;
}
}
// Track unmatched elements for set filters
if ( bySet ) {
// They will have gone through all possible matchers
if ( (elem = !matcher && elem) ) {
matchedCount--;
}
// Lengthen the array for every element, matched or not
if ( seed ) {
unmatched.push( elem );
}
}
}
// `i` is now the count of elements visited above, and adding it to `matchedCount`
// makes the latter nonnegative.
matchedCount += i;
// Apply set filters to unmatched elements
// NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount`
// equals `i`), unless we didn't visit _any_ elements in the above loop because we have
// no element matchers and no seed.
// Incrementing an initially-string "0" `i` allows `i` to remain a string only in that
// case, which will result in a "00" `matchedCount` that differs from `i` but is also
// numerically zero.
if ( bySet && i !== matchedCount ) {
j = 0;
while ( (matcher = setMatchers[j++]) ) {
matcher( unmatched, setMatched, context, xml );
}
if ( seed ) {
// Reintegrate element matches to eliminate the need for sorting
if ( matchedCount > 0 ) {
while ( i-- ) {
if ( !(unmatched[i] || setMatched[i]) ) {
setMatched[i] = pop.call( results );
}
}
}
// Discard index placeholder values to get only actual matches
setMatched = condense( setMatched );
}
// Add matches to results
push.apply( results, setMatched );
// Seedless set matches succeeding multiple successful matchers stipulate sorting
if ( outermost && !seed && setMatched.length > 0 &&
( matchedCount + setMatchers.length ) > 1 ) {
Sizzle.uniqueSort( results );
}
}
// Override manipulation of globals by nested matchers
if ( outermost ) {
dirruns = dirrunsUnique;
outermostContext = contextBackup;
}
return unmatched;
};
return bySet ?
markFunction( superMatcher ) :
superMatcher;
}
compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) {
var i,
setMatchers = [],
elementMatchers = [],
cached = compilerCache[ selector + " " ];
if ( !cached ) {
// Generate a function of recursive functions that can be used to check each element
if ( !match ) {
match = tokenize( selector );
}
i = match.length;
while ( i-- ) {
cached = matcherFromTokens( match[i] );
if ( cached[ expando ] ) {
setMatchers.push( cached );
} else {
elementMatchers.push( cached );
}
}
// Cache the compiled function
cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) );
// Save selector and tokenization
cached.selector = selector;
}
return cached;
};
/**
* A low-level selection function that works with Sizzle's compiled
* selector functions
* @param {String|Function} selector A selector or a pre-compiled
* selector function built with Sizzle.compile
* @param {Element} context
* @param {Array} [results]
* @param {Array} [seed] A set of elements to match against
*/
select = Sizzle.select = function( selector, context, results, seed ) {
var i, tokens, token, type, find,
compiled = typeof selector === "function" && selector,
match = !seed && tokenize( (selector = compiled.selector || selector) );
results = results || [];
// Try to minimize operations if there is only one selector in the list and no seed
// (the latter of which guarantees us context)
if ( match.length === 1 ) {
// Reduce context if the leading compound selector is an ID
tokens = match[0] = match[0].slice( 0 );
if ( tokens.length > 2 && (token = tokens[0]).type === "ID" &&
context.nodeType === 9 && documentIsHTML && Expr.relative[ tokens[1].type ] ) {
context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0];
if ( !context ) {
return results;
// Precompiled matchers will still verify ancestry, so step up a level
} else if ( compiled ) {
context = context.parentNode;
}
selector = selector.slice( tokens.shift().value.length );
}
// Fetch a seed set for right-to-left matching
i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length;
while ( i-- ) {
token = tokens[i];
// Abort if we hit a combinator
if ( Expr.relative[ (type = token.type) ] ) {
break;
}
if ( (find = Expr.find[ type ]) ) {
// Search, expanding context for leading sibling combinators
if ( (seed = find(
token.matches[0].replace( runescape, funescape ),
rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context
)) ) {
// If seed is empty or no tokens remain, we can return early
tokens.splice( i, 1 );
selector = seed.length && toSelector( tokens );
if ( !selector ) {
push.apply( results, seed );
return results;
}
break;
}
}
}
}
// Compile and execute a filtering function if one is not provided
// Provide `match` to avoid retokenization if we modified the selector above
( compiled || compile( selector, match ) )(
seed,
context,
!documentIsHTML,
results,
!context || rsibling.test( selector ) && testContext( context.parentNode ) || context
);
return results;
};
// One-time assignments
// Sort stability
support.sortStable = expando.split("").sort( sortOrder ).join("") === expando;
// Support: Chrome 14-35+
// Always assume duplicates if they aren't passed to the comparison function
support.detectDuplicates = !!hasDuplicate;
// Initialize against the default document
setDocument();
// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27)
// Detached nodes confoundingly follow *each other*
support.sortDetached = assert(function( el ) {
// Should return 1, but returns 4 (following)
return el.compareDocumentPosition( document.createElement("fieldset") ) & 1;
});
// Support: IE<8
// Prevent attribute/property "interpolation"
// https://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx
if ( !assert(function( el ) {
el.innerHTML = "<a href='#'></a>";
return el.firstChild.getAttribute("href") === "#" ;
}) ) {
addHandle( "type|href|height|width", function( elem, name, isXML ) {
if ( !isXML ) {
return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 );
}
});
}
// Support: IE<9
// Use defaultValue in place of getAttribute("value")
if ( !support.attributes || !assert(function( el ) {
el.innerHTML = "<input/>";
el.firstChild.setAttribute( "value", "" );
return el.firstChild.getAttribute( "value" ) === "";
}) ) {
addHandle( "value", function( elem, name, isXML ) {
if ( !isXML && elem.nodeName.toLowerCase() === "input" ) {
return elem.defaultValue;
}
});
}
// Support: IE<9
// Use getAttributeNode to fetch booleans when getAttribute lies
if ( !assert(function( el ) {
return el.getAttribute("disabled") == null;
}) ) {
addHandle( booleans, function( elem, name, isXML ) {
var val;
if ( !isXML ) {
return elem[ name ] === true ? name.toLowerCase() :
(val = elem.getAttributeNode( name )) && val.specified ?
val.value :
null;
}
});
}
return Sizzle;
})( window );
jQuery.find = Sizzle;
jQuery.expr = Sizzle.selectors;
// Deprecated
jQuery.expr[ ":" ] = jQuery.expr.pseudos;
jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort;
jQuery.text = Sizzle.getText;
jQuery.isXMLDoc = Sizzle.isXML;
jQuery.contains = Sizzle.contains;
jQuery.escapeSelector = Sizzle.escape;
var dir = function( elem, dir, until ) {
var matched = [],
truncate = until !== undefined;
while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) {
if ( elem.nodeType === 1 ) {
if ( truncate && jQuery( elem ).is( until ) ) {
break;
}
matched.push( elem );
}
}
return matched;
};
var siblings = function( n, elem ) {
var matched = [];
for ( ; n; n = n.nextSibling ) {
if ( n.nodeType === 1 && n !== elem ) {
matched.push( n );
}
}
return matched;
};
var rneedsContext = jQuery.expr.match.needsContext;
function nodeName( elem, name ) {
return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase();
};
var rsingleTag = ( /^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i );
// Implement the identical functionality for filter and not
function winnow( elements, qualifier, not ) {
if ( isFunction( qualifier ) ) {
return jQuery.grep( elements, function( elem, i ) {
return !!qualifier.call( elem, i, elem ) !== not;
} );
}
// Single element
if ( qualifier.nodeType ) {
return jQuery.grep( elements, function( elem ) {
return ( elem === qualifier ) !== not;
} );
}
// Arraylike of elements (jQuery, arguments, Array)
if ( typeof qualifier !== "string" ) {
return jQuery.grep( elements, function( elem ) {
return ( indexOf.call( qualifier, elem ) > -1 ) !== not;
} );
}
// Filtered directly for both simple and complex selectors
return jQuery.filter( qualifier, elements, not );
}
jQuery.filter = function( expr, elems, not ) {
var elem = elems[ 0 ];
if ( not ) {
expr = ":not(" + expr + ")";
}
if ( elems.length === 1 && elem.nodeType === 1 ) {
return jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [];
}
return jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) {
return elem.nodeType === 1;
} ) );
};
jQuery.fn.extend( {
find: function( selector ) {
var i, ret,
len = this.length,
self = this;
if ( typeof selector !== "string" ) {
return this.pushStack( jQuery( selector ).filter( function() {
for ( i = 0; i < len; i++ ) {
if ( jQuery.contains( self[ i ], this ) ) {
return true;
}
}
} ) );
}
ret = this.pushStack( [] );
for ( i = 0; i < len; i++ ) {
jQuery.find( selector, self[ i ], ret );
}
return len > 1 ? jQuery.uniqueSort( ret ) : ret;
},
filter: function( selector ) {
return this.pushStack( winnow( this, selector || [], false ) );
},
not: function( selector ) {
return this.pushStack( winnow( this, selector || [], true ) );
},
is: function( selector ) {
return !!winnow(
this,
// If this is a positional/relative selector, check membership in the returned set
// so $("p:first").is("p:last") won't return true for a doc with two "p".
typeof selector === "string" && rneedsContext.test( selector ) ?
jQuery( selector ) :
selector || [],
false
).length;
}
} );
// Initialize a jQuery object
// A central reference to the root jQuery(document)
var rootjQuery,
// A simple way to check for HTML strings
// Prioritize #id over <tag> to avoid XSS via location.hash (#9521)
// Strict HTML recognition (#11290: must start with <)
// Shortcut simple #id case for speed
rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/,
init = jQuery.fn.init = function( selector, context, root ) {
var match, elem;
// HANDLE: $(""), $(null), $(undefined), $(false)
if ( !selector ) {
return this;
}
// Method init() accepts an alternate rootjQuery
// so migrate can support jQuery.sub (gh-2101)
root = root || rootjQuery;
// Handle HTML strings
if ( typeof selector === "string" ) {
if ( selector[ 0 ] === "<" &&
selector[ selector.length - 1 ] === ">" &&
selector.length >= 3 ) {
// Assume that strings that start and end with <> are HTML and skip the regex check
match = [ null, selector, null ];
} else {
match = rquickExpr.exec( selector );
}
// Match html or make sure no context is specified for #id
if ( match && ( match[ 1 ] || !context ) ) {
// HANDLE: $(html) -> $(array)
if ( match[ 1 ] ) {
context = context instanceof jQuery ? context[ 0 ] : context;
// Option to run scripts is true for back-compat
// Intentionally let the error be thrown if parseHTML is not present
jQuery.merge( this, jQuery.parseHTML(
match[ 1 ],
context && context.nodeType ? context.ownerDocument || context : document,
true
) );
// HANDLE: $(html, props)
if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) {
for ( match in context ) {
// Properties of context are called as methods if possible
if ( isFunction( this[ match ] ) ) {
this[ match ]( context[ match ] );
// ...and otherwise set as attributes
} else {
this.attr( match, context[ match ] );
}
}
}
return this;
// HANDLE: $(#id)
} else {
elem = document.getElementById( match[ 2 ] );
if ( elem ) {
// Inject the element directly into the jQuery object
this[ 0 ] = elem;
this.length = 1;
}
return this;
}
// HANDLE: $(expr, $(...))
} else if ( !context || context.jquery ) {
return ( context || root ).find( selector );
// HANDLE: $(expr, context)
// (which is just equivalent to: $(context).find(expr)
} else {
return this.constructor( context ).find( selector );
}
// HANDLE: $(DOMElement)
} else if ( selector.nodeType ) {
this[ 0 ] = selector;
this.length = 1;
return this;
// HANDLE: $(function)
// Shortcut for document ready
} else if ( isFunction( selector ) ) {
return root.ready !== undefined ?
root.ready( selector ) :
// Execute immediately if ready is not present
selector( jQuery );
}
return jQuery.makeArray( selector, this );
};
// Give the init function the jQuery prototype for later instantiation
init.prototype = jQuery.fn;
// Initialize central reference
rootjQuery = jQuery( document );
var rparentsprev = /^(?:parents|prev(?:Until|All))/,
// Methods guaranteed to produce a unique set when starting from a unique set
guaranteedUnique = {
children: true,
contents: true,
next: true,
prev: true
};
jQuery.fn.extend( {
has: function( target ) {
var targets = jQuery( target, this ),
l = targets.length;
return this.filter( function() {
var i = 0;
for ( ; i < l; i++ ) {
if ( jQuery.contains( this, targets[ i ] ) ) {
return true;
}
}
} );
},
closest: function( selectors, context ) {
var cur,
i = 0,
l = this.length,
matched = [],
targets = typeof selectors !== "string" && jQuery( selectors );
// Positional selectors never match, since there's no _selection_ context
if ( !rneedsContext.test( selectors ) ) {
for ( ; i < l; i++ ) {
for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) {
// Always skip document fragments
if ( cur.nodeType < 11 && ( targets ?
targets.index( cur ) > -1 :
// Don't pass non-elements to Sizzle
cur.nodeType === 1 &&
jQuery.find.matchesSelector( cur, selectors ) ) ) {
matched.push( cur );
break;
}
}
}
}
return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched );
},
// Determine the position of an element within the set
index: function( elem ) {
// No argument, return index in parent
if ( !elem ) {
return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1;
}
// Index in selector
if ( typeof elem === "string" ) {
return indexOf.call( jQuery( elem ), this[ 0 ] );
}
// Locate the position of the desired element
return indexOf.call( this,
// If it receives a jQuery object, the first element is used
elem.jquery ? elem[ 0 ] : elem
);
},
add: function( selector, context ) {
return this.pushStack(
jQuery.uniqueSort(
jQuery.merge( this.get(), jQuery( selector, context ) )
)
);
},
addBack: function( selector ) {
return this.add( selector == null ?
this.prevObject : this.prevObject.filter( selector )
);
}
} );
function sibling( cur, dir ) {
while ( ( cur = cur[ dir ] ) && cur.nodeType !== 1 ) {}
return cur;
}
jQuery.each( {
parent: function( elem ) {
var parent = elem.parentNode;
return parent && parent.nodeType !== 11 ? parent : null;
},
parents: function( elem ) {
return dir( elem, "parentNode" );
},
parentsUntil: function( elem, i, until ) {
return dir( elem, "parentNode", until );
},
next: function( elem ) {
return sibling( elem, "nextSibling" );
},
prev: function( elem ) {
return sibling( elem, "previousSibling" );
},
nextAll: function( elem ) {
return dir( elem, "nextSibling" );
},
prevAll: function( elem ) {
return dir( elem, "previousSibling" );
},
nextUntil: function( elem, i, until ) {
return dir( elem, "nextSibling", until );
},
prevUntil: function( elem, i, until ) {
return dir( elem, "previousSibling", until );
},
siblings: function( elem ) {
return siblings( ( elem.parentNode || {} ).firstChild, elem );
},
children: function( elem ) {
return siblings( elem.firstChild );
},
contents: function( elem ) {
if ( typeof elem.contentDocument !== "undefined" ) {
return elem.contentDocument;
}
// Support: IE 9 - 11 only, iOS 7 only, Android Browser <=4.3 only
// Treat the template element as a regular one in browsers that
// don't support it.
if ( nodeName( elem, "template" ) ) {
elem = elem.content || elem;
}
return jQuery.merge( [], elem.childNodes );
}
}, function( name, fn ) {
jQuery.fn[ name ] = function( until, selector ) {
var matched = jQuery.map( this, fn, until );
if ( name.slice( -5 ) !== "Until" ) {
selector = until;
}
if ( selector && typeof selector === "string" ) {
matched = jQuery.filter( selector, matched );
}
if ( this.length > 1 ) {
// Remove duplicates
if ( !guaranteedUnique[ name ] ) {
jQuery.uniqueSort( matched );
}
// Reverse order for parents* and prev-derivatives
if ( rparentsprev.test( name ) ) {
matched.reverse();
}
}
return this.pushStack( matched );
};
} );
var rnothtmlwhite = ( /[^\x20\t\r\n\f]+/g );
// Convert String-formatted options into Object-formatted ones
function createOptions( options ) {
var object = {};
jQuery.each( options.match( rnothtmlwhite ) || [], function( _, flag ) {
object[ flag ] = true;
} );
return object;
}
/*
* Create a callback list using the following parameters:
*
* options: an optional list of space-separated options that will change how
* the callback list behaves or a more traditional option object
*
* By default a callback list will act like an event callback list and can be
* "fired" multiple times.
*
* Possible options:
*
* once: will ensure the callback list can only be fired once (like a Deferred)
*
* memory: will keep track of previous values and will call any callback added
* after the list has been fired right away with the latest "memorized"
* values (like a Deferred)
*
* unique: will ensure a callback can only be added once (no duplicate in the list)
*
* stopOnFalse: interrupt callings when a callback returns false
*
*/
jQuery.Callbacks = function( options ) {
// Convert options from String-formatted to Object-formatted if needed
// (we check in cache first)
options = typeof options === "string" ?
createOptions( options ) :
jQuery.extend( {}, options );
var // Flag to know if list is currently firing
firing,
// Last fire value for non-forgettable lists
memory,
// Flag to know if list was already fired
fired,
// Flag to prevent firing
locked,
// Actual callback list
list = [],
// Queue of execution data for repeatable lists
queue = [],
// Index of currently firing callback (modified by add/remove as needed)
firingIndex = -1,
// Fire callbacks
fire = function() {
// Enforce single-firing
locked = locked || options.once;
// Execute callbacks for all pending executions,
// respecting firingIndex overrides and runtime changes
fired = firing = true;
for ( ; queue.length; firingIndex = -1 ) {
memory = queue.shift();
while ( ++firingIndex < list.length ) {
// Run callback and check for early termination
if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false &&
options.stopOnFalse ) {
// Jump to end and forget the data so .add doesn't re-fire
firingIndex = list.length;
memory = false;
}
}
}
// Forget the data if we're done with it
if ( !options.memory ) {
memory = false;
}
firing = false;
// Clean up if we're done firing for good
if ( locked ) {
// Keep an empty list if we have data for future add calls
if ( memory ) {
list = [];
// Otherwise, this object is spent
} else {
list = "";
}
}
},
// Actual Callbacks object
self = {
// Add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
// If we have memory from a past run, we should fire after adding
if ( memory && !firing ) {
firingIndex = list.length - 1;
queue.push( memory );
}
( function add( args ) {
jQuery.each( args, function( _, arg ) {
if ( isFunction( arg ) ) {
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
} else if ( arg && arg.length && toType( arg ) !== "string" ) {
// Inspect recursively
add( arg );
}
} );
} )( arguments );
if ( memory && !firing ) {
fire();
}
}
return this;
},
// Remove a callback from the list
remove: function() {
jQuery.each( arguments, function( _, arg ) {
var index;
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
// Handle firing indexes
if ( index <= firingIndex ) {
firingIndex--;
}
}
} );
return this;
},
// Check if a given callback is in the list.
// If no argument is given, return whether or not list has callbacks attached.
has: function( fn ) {
return fn ?
jQuery.inArray( fn, list ) > -1 :
list.length > 0;
},
// Remove all callbacks from the list
empty: function() {
if ( list ) {
list = [];
}
return this;
},
// Disable .fire and .add
// Abort any current/pending executions
// Clear all callbacks and values
disable: function() {
locked = queue = [];
list = memory = "";
return this;
},
disabled: function() {
return !list;
},
// Disable .fire
// Also disable .add unless we have memory (since it would have no effect)
// Abort any pending executions
lock: function() {
locked = queue = [];
if ( !memory && !firing ) {
list = memory = "";
}
return this;
},
locked: function() {
return !!locked;
},
// Call all callbacks with the given context and arguments
fireWith: function( context, args ) {
if ( !locked ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
queue.push( args );
if ( !firing ) {
fire();
}
}
return this;
},
// Call all the callbacks with the given arguments
fire: function() {
self.fireWith( this, arguments );
return this;
},
// To know if the callbacks have already been called at least once
fired: function() {
return !!fired;
}
};
return self;
};
function Identity( v ) {
return v;
}
function Thrower( ex ) {
throw ex;
}
function adoptValue( value, resolve, reject, noValue ) {
var method;
try {
// Check for promise aspect first to privilege synchronous behavior
if ( value && isFunction( ( method = value.promise ) ) ) {
method.call( value ).done( resolve ).fail( reject );
// Other thenables
} else if ( value && isFunction( ( method = value.then ) ) ) {
method.call( value, resolve, reject );
// Other non-thenables
} else {
// Control `resolve` arguments by letting Array#slice cast boolean `noValue` to integer:
// * false: [ value ].slice( 0 ) => resolve( value )
// * true: [ value ].slice( 1 ) => resolve()
resolve.apply( undefined, [ value ].slice( noValue ) );
}
// For Promises/A+, convert exceptions into rejections
// Since jQuery.when doesn't unwrap thenables, we can skip the extra checks appearing in
// Deferred#then to conditionally suppress rejection.
} catch ( value ) {
// Support: Android 4.0 only
// Strict mode functions invoked without .call/.apply get global-object context
reject.apply( undefined, [ value ] );
}
}
jQuery.extend( {
Deferred: function( func ) {
var tuples = [
// action, add listener, callbacks,
// ... .then handlers, argument index, [final state]
[ "notify", "progress", jQuery.Callbacks( "memory" ),
jQuery.Callbacks( "memory" ), 2 ],
[ "resolve", "done", jQuery.Callbacks( "once memory" ),
jQuery.Callbacks( "once memory" ), 0, "resolved" ],
[ "reject", "fail", jQuery.Callbacks( "once memory" ),
jQuery.Callbacks( "once memory" ), 1, "rejected" ]
],
state = "pending",
promise = {
state: function() {
return state;
},
always: function() {
deferred.done( arguments ).fail( arguments );
return this;
},
"catch": function( fn ) {
return promise.then( null, fn );
},
// Keep pipe for back-compat
pipe: function( /* fnDone, fnFail, fnProgress */ ) {
var fns = arguments;
return jQuery.Deferred( function( newDefer ) {
jQuery.each( tuples, function( i, tuple ) {
// Map tuples (progress, done, fail) to arguments (done, fail, progress)
var fn = isFunction( fns[ tuple[ 4 ] ] ) && fns[ tuple[ 4 ] ];
// deferred.progress(function() { bind to newDefer or newDefer.notify })
// deferred.done(function() { bind to newDefer or newDefer.resolve })
// deferred.fail(function() { bind to newDefer or newDefer.reject })
deferred[ tuple[ 1 ] ]( function() {
var returned = fn && fn.apply( this, arguments );
if ( returned && isFunction( returned.promise ) ) {
returned.promise()
.progress( newDefer.notify )
.done( newDefer.resolve )
.fail( newDefer.reject );
} else {
newDefer[ tuple[ 0 ] + "With" ](
this,
fn ? [ returned ] : arguments
);
}
} );
} );
fns = null;
} ).promise();
},
then: function( onFulfilled, onRejected, onProgress ) {
var maxDepth = 0;
function resolve( depth, deferred, handler, special ) {
return function() {
var that = this,
args = arguments,
mightThrow = function() {
var returned, then;
// Support: Promises/A+ section 2.3.3.3.3
// https://promisesaplus.com/#point-59
// Ignore double-resolution attempts
if ( depth < maxDepth ) {
return;
}
returned = handler.apply( that, args );
// Support: Promises/A+ section 2.3.1
// https://promisesaplus.com/#point-48
if ( returned === deferred.promise() ) {
throw new TypeError( "Thenable self-resolution" );
}
// Support: Promises/A+ sections 2.3.3.1, 3.5
// https://promisesaplus.com/#point-54
// https://promisesaplus.com/#point-75
// Retrieve `then` only once
then = returned &&
// Support: Promises/A+ section 2.3.4
// https://promisesaplus.com/#point-64
// Only check objects and functions for thenability
( typeof returned === "object" ||
typeof returned === "function" ) &&
returned.then;
// Handle a returned thenable
if ( isFunction( then ) ) {
// Special processors (notify) just wait for resolution
if ( special ) {
then.call(
returned,
resolve( maxDepth, deferred, Identity, special ),
resolve( maxDepth, deferred, Thrower, special )
);
// Normal processors (resolve) also hook into progress
} else {
// ...and disregard older resolution values
maxDepth++;
then.call(
returned,
resolve( maxDepth, deferred, Identity, special ),
resolve( maxDepth, deferred, Thrower, special ),
resolve( maxDepth, deferred, Identity,
deferred.notifyWith )
);
}
// Handle all other returned values
} else {
// Only substitute handlers pass on context
// and multiple values (non-spec behavior)
if ( handler !== Identity ) {
that = undefined;
args = [ returned ];
}
// Process the value(s)
// Default process is resolve
( special || deferred.resolveWith )( that, args );
}
},
// Only normal processors (resolve) catch and reject exceptions
process = special ?
mightThrow :
function() {
try {
mightThrow();
} catch ( e ) {
if ( jQuery.Deferred.exceptionHook ) {
jQuery.Deferred.exceptionHook( e,
process.stackTrace );
}
// Support: Promises/A+ section 2.3.3.3.4.1
// https://promisesaplus.com/#point-61
// Ignore post-resolution exceptions
if ( depth + 1 >= maxDepth ) {
// Only substitute handlers pass on context
// and multiple values (non-spec behavior)
if ( handler !== Thrower ) {
that = undefined;
args = [ e ];
}
deferred.rejectWith( that, args );
}
}
};
// Support: Promises/A+ section 2.3.3.3.1
// https://promisesaplus.com/#point-57
// Re-resolve promises immediately to dodge false rejection from
// subsequent errors
if ( depth ) {
process();
} else {
// Call an optional hook to record the stack, in case of exception
// since it's otherwise lost when execution goes async
if ( jQuery.Deferred.getStackHook ) {
process.stackTrace = jQuery.Deferred.getStackHook();
}
window.setTimeout( process );
}
};
}
return jQuery.Deferred( function( newDefer ) {
// progress_handlers.add( ... )
tuples[ 0 ][ 3 ].add(
resolve(
0,
newDefer,
isFunction( onProgress ) ?
onProgress :
Identity,
newDefer.notifyWith
)
);
// fulfilled_handlers.add( ... )
tuples[ 1 ][ 3 ].add(
resolve(
0,
newDefer,
isFunction( onFulfilled ) ?
onFulfilled :
Identity
)
);
// rejected_handlers.add( ... )
tuples[ 2 ][ 3 ].add(
resolve(
0,
newDefer,
isFunction( onRejected ) ?
onRejected :
Thrower
)
);
} ).promise();
},
// Get a promise for this deferred
// If obj is provided, the promise aspect is added to the object
promise: function( obj ) {
return obj != null ? jQuery.extend( obj, promise ) : promise;
}
},
deferred = {};
// Add list-specific methods
jQuery.each( tuples, function( i, tuple ) {
var list = tuple[ 2 ],
stateString = tuple[ 5 ];
// promise.progress = list.add
// promise.done = list.add
// promise.fail = list.add
promise[ tuple[ 1 ] ] = list.add;
// Handle state
if ( stateString ) {
list.add(
function() {
// state = "resolved" (i.e., fulfilled)
// state = "rejected"
state = stateString;
},
// rejected_callbacks.disable
// fulfilled_callbacks.disable
tuples[ 3 - i ][ 2 ].disable,
// rejected_handlers.disable
// fulfilled_handlers.disable
tuples[ 3 - i ][ 3 ].disable,
// progress_callbacks.lock
tuples[ 0 ][ 2 ].lock,
// progress_handlers.lock
tuples[ 0 ][ 3 ].lock
);
}
// progress_handlers.fire
// fulfilled_handlers.fire
// rejected_handlers.fire
list.add( tuple[ 3 ].fire );
// deferred.notify = function() { deferred.notifyWith(...) }
// deferred.resolve = function() { deferred.resolveWith(...) }
// deferred.reject = function() { deferred.rejectWith(...) }
deferred[ tuple[ 0 ] ] = function() {
deferred[ tuple[ 0 ] + "With" ]( this === deferred ? undefined : this, arguments );
return this;
};
// deferred.notifyWith = list.fireWith
// deferred.resolveWith = list.fireWith
// deferred.rejectWith = list.fireWith
deferred[ tuple[ 0 ] + "With" ] = list.fireWith;
} );
// Make the deferred a promise
promise.promise( deferred );
// Call given func if any
if ( func ) {
func.call( deferred, deferred );
}
// All done!
return deferred;
},
// Deferred helper
when: function( singleValue ) {
var
// count of uncompleted subordinates
remaining = arguments.length,
// count of unprocessed arguments
i = remaining,
// subordinate fulfillment data
resolveContexts = Array( i ),
resolveValues = slice.call( arguments ),
// the master Deferred
master = jQuery.Deferred(),
// subordinate callback factory
updateFunc = function( i ) {
return function( value ) {
resolveContexts[ i ] = this;
resolveValues[ i ] = arguments.length > 1 ? slice.call( arguments ) : value;
if ( !( --remaining ) ) {
master.resolveWith( resolveContexts, resolveValues );
}
};
};
// Single- and empty arguments are adopted like Promise.resolve
if ( remaining <= 1 ) {
adoptValue( singleValue, master.done( updateFunc( i ) ).resolve, master.reject,
!remaining );
// Use .then() to unwrap secondary thenables (cf. gh-3000)
if ( master.state() === "pending" ||
isFunction( resolveValues[ i ] && resolveValues[ i ].then ) ) {
return master.then();
}
}
// Multiple arguments are aggregated like Promise.all array elements
while ( i-- ) {
adoptValue( resolveValues[ i ], updateFunc( i ), master.reject );
}
return master.promise();
}
} );
// These usually indicate a programmer mistake during development,
// warn about them ASAP rather than swallowing them by default.
var rerrorNames = /^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;
jQuery.Deferred.exceptionHook = function( error, stack ) {
// Support: IE 8 - 9 only
// Console exists when dev tools are open, which can happen at any time
if ( window.console && window.console.warn && error && rerrorNames.test( error.name ) ) {
window.console.warn( "jQuery.Deferred exception: " + error.message, error.stack, stack );
}
};
jQuery.readyException = function( error ) {
window.setTimeout( function() {
throw error;
} );
};
// The deferred used on DOM ready
var readyList = jQuery.Deferred();
jQuery.fn.ready = function( fn ) {
readyList
.then( fn )
// Wrap jQuery.readyException in a function so that the lookup
// happens at the time of error handling instead of callback
// registration.
.catch( function( error ) {
jQuery.readyException( error );
} );
return this;
};
jQuery.extend( {
// Is the DOM ready to be used? Set to true once it occurs.
isReady: false,
// A counter to track how many items to wait for before
// the ready event fires. See #6781
readyWait: 1,
// Handle when the DOM is ready
ready: function( wait ) {
// Abort if there are pending holds or we're already ready
if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) {
return;
}
// Remember that the DOM is ready
jQuery.isReady = true;
// If a normal DOM Ready event fired, decrement, and wait if need be
if ( wait !== true && --jQuery.readyWait > 0 ) {
return;
}
// If there are functions bound, to execute
readyList.resolveWith( document, [ jQuery ] );
}
} );
jQuery.ready.then = readyList.then;
// The ready event handler and self cleanup method
function completed() {
document.removeEventListener( "DOMContentLoaded", completed );
window.removeEventListener( "load", completed );
jQuery.ready();
}
// Catch cases where $(document).ready() is called
// after the browser event has already occurred.
// Support: IE <=9 - 10 only
// Older IE sometimes signals "interactive" too soon
if ( document.readyState === "complete" ||
( document.readyState !== "loading" && !document.documentElement.doScroll ) ) {
// Handle it asynchronously to allow scripts the opportunity to delay ready
window.setTimeout( jQuery.ready );
} else {
// Use the handy event callback
document.addEventListener( "DOMContentLoaded", completed );
// A fallback to window.onload, that will always work
window.addEventListener( "load", completed );
}
// Multifunctional method to get and set values of a collection
// The value/s can optionally be executed if it's a function
var access = function( elems, fn, key, value, chainable, emptyGet, raw ) {
var i = 0,
len = elems.length,
bulk = key == null;
// Sets many values
if ( toType( key ) === "object" ) {
chainable = true;
for ( i in key ) {
access( elems, fn, i, key[ i ], true, emptyGet, raw );
}
// Sets one value
} else if ( value !== undefined ) {
chainable = true;
if ( !isFunction( value ) ) {
raw = true;
}
if ( bulk ) {
// Bulk operations run against the entire set
if ( raw ) {
fn.call( elems, value );
fn = null;
// ...except when executing function values
} else {
bulk = fn;
fn = function( elem, key, value ) {
return bulk.call( jQuery( elem ), value );
};
}
}
if ( fn ) {
for ( ; i < len; i++ ) {
fn(
elems[ i ], key, raw ?
value :
value.call( elems[ i ], i, fn( elems[ i ], key ) )
);
}
}
}
if ( chainable ) {
return elems;
}
// Gets
if ( bulk ) {
return fn.call( elems );
}
return len ? fn( elems[ 0 ], key ) : emptyGet;
};
// Matches dashed string for camelizing
var rmsPrefix = /^-ms-/,
rdashAlpha = /-([a-z])/g;
// Used by camelCase as callback to replace()
function fcamelCase( all, letter ) {
return letter.toUpperCase();
}
// Convert dashed to camelCase; used by the css and data modules
// Support: IE <=9 - 11, Edge 12 - 15
// Microsoft forgot to hump their vendor prefix (#9572)
function camelCase( string ) {
return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase );
}
var acceptData = function( owner ) {
// Accepts only:
// - Node
// - Node.ELEMENT_NODE
// - Node.DOCUMENT_NODE
// - Object
// - Any
return owner.nodeType === 1 || owner.nodeType === 9 || !( +owner.nodeType );
};
function Data() {
this.expando = jQuery.expando + Data.uid++;
}
Data.uid = 1;
Data.prototype = {
cache: function( owner ) {
// Check if the owner object already has a cache
var value = owner[ this.expando ];
// If not, create one
if ( !value ) {
value = {};
// We can accept data for non-element nodes in modern browsers,
// but we should not, see #8335.
// Always return an empty object.
if ( acceptData( owner ) ) {
// If it is a node unlikely to be stringify-ed or looped over
// use plain assignment
if ( owner.nodeType ) {
owner[ this.expando ] = value;
// Otherwise secure it in a non-enumerable property
// configurable must be true to allow the property to be
// deleted when data is removed
} else {
Object.defineProperty( owner, this.expando, {
value: value,
configurable: true
} );
}
}
}
return value;
},
set: function( owner, data, value ) {
var prop,
cache = this.cache( owner );
// Handle: [ owner, key, value ] args
// Always use camelCase key (gh-2257)
if ( typeof data === "string" ) {
cache[ camelCase( data ) ] = value;
// Handle: [ owner, { properties } ] args
} else {
// Copy the properties one-by-one to the cache object
for ( prop in data ) {
cache[ camelCase( prop ) ] = data[ prop ];
}
}
return cache;
},
get: function( owner, key ) {
return key === undefined ?
this.cache( owner ) :
// Always use camelCase key (gh-2257)
owner[ this.expando ] && owner[ this.expando ][ camelCase( key ) ];
},
access: function( owner, key, value ) {
// In cases where either:
//
// 1. No key was specified
// 2. A string key was specified, but no value provided
//
// Take the "read" path and allow the get method to determine
// which value to return, respectively either:
//
// 1. The entire cache object
// 2. The data stored at the key
//
if ( key === undefined ||
( ( key && typeof key === "string" ) && value === undefined ) ) {
return this.get( owner, key );
}
// When the key is not a string, or both a key and value
// are specified, set or extend (existing objects) with either:
//
// 1. An object of properties
// 2. A key and value
//
this.set( owner, key, value );
// Since the "set" path can have two possible entry points
// return the expected data based on which path was taken[*]
return value !== undefined ? value : key;
},
remove: function( owner, key ) {
var i,
cache = owner[ this.expando ];
if ( cache === undefined ) {
return;
}
if ( key !== undefined ) {
// Support array or space separated string of keys
if ( Array.isArray( key ) ) {
// If key is an array of keys...
// We always set camelCase keys, so remove that.
key = key.map( camelCase );
} else {
key = camelCase( key );
// If a key with the spaces exists, use it.
// Otherwise, create an array by matching non-whitespace
key = key in cache ?
[ key ] :
( key.match( rnothtmlwhite ) || [] );
}
i = key.length;
while ( i-- ) {
delete cache[ key[ i ] ];
}
}
// Remove the expando if there's no more data
if ( key === undefined || jQuery.isEmptyObject( cache ) ) {
// Support: Chrome <=35 - 45
// Webkit & Blink performance suffers when deleting properties
// from DOM nodes, so set to undefined instead
// https://bugs.chromium.org/p/chromium/issues/detail?id=378607 (bug restricted)
if ( owner.nodeType ) {
owner[ this.expando ] = undefined;
} else {
delete owner[ this.expando ];
}
}
},
hasData: function( owner ) {
var cache = owner[ this.expando ];
return cache !== undefined && !jQuery.isEmptyObject( cache );
}
};
var dataPriv = new Data();
var dataUser = new Data();
// Implementation Summary
//
// 1. Enforce API surface and semantic compatibility with 1.9.x branch
// 2. Improve the module's maintainability by reducing the storage
// paths to a single mechanism.
// 3. Use the same single mechanism to support "private" and "user" data.
// 4. _Never_ expose "private" data to user code (TODO: Drop _data, _removeData)
// 5. Avoid exposing implementation details on user objects (eg. expando properties)
// 6. Provide a clear path for implementation upgrade to WeakMap in 2014
var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,
rmultiDash = /[A-Z]/g;
function getData( data ) {
if ( data === "true" ) {
return true;
}
if ( data === "false" ) {
return false;
}
if ( data === "null" ) {
return null;
}
// Only convert to a number if it doesn't change the string
if ( data === +data + "" ) {
return +data;
}
if ( rbrace.test( data ) ) {
return JSON.parse( data );
}
return data;
}
function dataAttr( elem, key, data ) {
var name;
// If nothing was found internally, try to fetch any
// data from the HTML5 data-* attribute
if ( data === undefined && elem.nodeType === 1 ) {
name = "data-" + key.replace( rmultiDash, "-$&" ).toLowerCase();
data = elem.getAttribute( name );
if ( typeof data === "string" ) {
try {
data = getData( data );
} catch ( e ) {}
// Make sure we set the data so it isn't changed later
dataUser.set( elem, key, data );
} else {
data = undefined;
}
}
return data;
}
jQuery.extend( {
hasData: function( elem ) {
return dataUser.hasData( elem ) || dataPriv.hasData( elem );
},
data: function( elem, name, data ) {
return dataUser.access( elem, name, data );
},
removeData: function( elem, name ) {
dataUser.remove( elem, name );
},
// TODO: Now that all calls to _data and _removeData have been replaced
// with direct calls to dataPriv methods, these can be deprecated.
_data: function( elem, name, data ) {
return dataPriv.access( elem, name, data );
},
_removeData: function( elem, name ) {
dataPriv.remove( elem, name );
}
} );
jQuery.fn.extend( {
data: function( key, value ) {
var i, name, data,
elem = this[ 0 ],
attrs = elem && elem.attributes;
// Gets all values
if ( key === undefined ) {
if ( this.length ) {
data = dataUser.get( elem );
if ( elem.nodeType === 1 && !dataPriv.get( elem, "hasDataAttrs" ) ) {
i = attrs.length;
while ( i-- ) {
// Support: IE 11 only
// The attrs elements can be null (#14894)
if ( attrs[ i ] ) {
name = attrs[ i ].name;
if ( name.indexOf( "data-" ) === 0 ) {
name = camelCase( name.slice( 5 ) );
dataAttr( elem, name, data[ name ] );
}
}
}
dataPriv.set( elem, "hasDataAttrs", true );
}
}
return data;
}
// Sets multiple values
if ( typeof key === "object" ) {
return this.each( function() {
dataUser.set( this, key );
} );
}
return access( this, function( value ) {
var data;
// The calling jQuery object (element matches) is not empty
// (and therefore has an element appears at this[ 0 ]) and the
// `value` parameter was not undefined. An empty jQuery object
// will result in `undefined` for elem = this[ 0 ] which will
// throw an exception if an attempt to read a data cache is made.
if ( elem && value === undefined ) {
// Attempt to get data from the cache
// The key will always be camelCased in Data
data = dataUser.get( elem, key );
if ( data !== undefined ) {
return data;
}
// Attempt to "discover" the data in
// HTML5 custom data-* attrs
data = dataAttr( elem, key );
if ( data !== undefined ) {
return data;
}
// We tried really hard, but the data doesn't exist.
return;
}
// Set the data...
this.each( function() {
// We always store the camelCased key
dataUser.set( this, key, value );
} );
}, null, value, arguments.length > 1, null, true );
},
removeData: function( key ) {
return this.each( function() {
dataUser.remove( this, key );
} );
}
} );
jQuery.extend( {
queue: function( elem, type, data ) {
var queue;
if ( elem ) {
type = ( type || "fx" ) + "queue";
queue = dataPriv.get( elem, type );
// Speed up dequeue by getting out quickly if this is just a lookup
if ( data ) {
if ( !queue || Array.isArray( data ) ) {
queue = dataPriv.access( elem, type, jQuery.makeArray( data ) );
} else {
queue.push( data );
}
}
return queue || [];
}
},
dequeue: function( elem, type ) {
type = type || "fx";
var queue = jQuery.queue( elem, type ),
startLength = queue.length,
fn = queue.shift(),
hooks = jQuery._queueHooks( elem, type ),
next = function() {
jQuery.dequeue( elem, type );
};
// If the fx queue is dequeued, always remove the progress sentinel
if ( fn === "inprogress" ) {
fn = queue.shift();
startLength--;
}
if ( fn ) {
// Add a progress sentinel to prevent the fx queue from being
// automatically dequeued
if ( type === "fx" ) {
queue.unshift( "inprogress" );
}
// Clear up the last queue stop function
delete hooks.stop;
fn.call( elem, next, hooks );
}
if ( !startLength && hooks ) {
hooks.empty.fire();
}
},
// Not public - generate a queueHooks object, or return the current one
_queueHooks: function( elem, type ) {
var key = type + "queueHooks";
return dataPriv.get( elem, key ) || dataPriv.access( elem, key, {
empty: jQuery.Callbacks( "once memory" ).add( function() {
dataPriv.remove( elem, [ type + "queue", key ] );
} )
} );
}
} );
jQuery.fn.extend( {
queue: function( type, data ) {
var setter = 2;
if ( typeof type !== "string" ) {
data = type;
type = "fx";
setter--;
}
if ( arguments.length < setter ) {
return jQuery.queue( this[ 0 ], type );
}
return data === undefined ?
this :
this.each( function() {
var queue = jQuery.queue( this, type, data );
// Ensure a hooks for this queue
jQuery._queueHooks( this, type );
if ( type === "fx" && queue[ 0 ] !== "inprogress" ) {
jQuery.dequeue( this, type );
}
} );
},
dequeue: function( type ) {
return this.each( function() {
jQuery.dequeue( this, type );
} );
},
clearQueue: function( type ) {
return this.queue( type || "fx", [] );
},
// Get a promise resolved when queues of a certain type
// are emptied (fx is the type by default)
promise: function( type, obj ) {
var tmp,
count = 1,
defer = jQuery.Deferred(),
elements = this,
i = this.length,
resolve = function() {
if ( !( --count ) ) {
defer.resolveWith( elements, [ elements ] );
}
};
if ( typeof type !== "string" ) {
obj = type;
type = undefined;
}
type = type || "fx";
while ( i-- ) {
tmp = dataPriv.get( elements[ i ], type + "queueHooks" );
if ( tmp && tmp.empty ) {
count++;
tmp.empty.add( resolve );
}
}
resolve();
return defer.promise( obj );
}
} );
var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source;
var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" );
var cssExpand = [ "Top", "Right", "Bottom", "Left" ];
var documentElement = document.documentElement;
var isAttached = function( elem ) {
return jQuery.contains( elem.ownerDocument, elem );
},
composed = { composed: true };
// Support: IE 9 - 11+, Edge 12 - 18+, iOS 10.0 - 10.2 only
// Check attachment across shadow DOM boundaries when possible (gh-3504)
// Support: iOS 10.0-10.2 only
// Early iOS 10 versions support `attachShadow` but not `getRootNode`,
// leading to errors. We need to check for `getRootNode`.
if ( documentElement.getRootNode ) {
isAttached = function( elem ) {
return jQuery.contains( elem.ownerDocument, elem ) ||
elem.getRootNode( composed ) === elem.ownerDocument;
};
}
var isHiddenWithinTree = function( elem, el ) {
// isHiddenWithinTree might be called from jQuery#filter function;
// in that case, element will be second argument
elem = el || elem;
// Inline style trumps all
return elem.style.display === "none" ||
elem.style.display === "" &&
// Otherwise, check computed style
// Support: Firefox <=43 - 45
// Disconnected elements can have computed display: none, so first confirm that elem is
// in the document.
isAttached( elem ) &&
jQuery.css( elem, "display" ) === "none";
};
var swap = function( elem, options, callback, args ) {
var ret, name,
old = {};
// Remember the old values, and insert the new ones
for ( name in options ) {
old[ name ] = elem.style[ name ];
elem.style[ name ] = options[ name ];
}
ret = callback.apply( elem, args || [] );
// Revert the old values
for ( name in options ) {
elem.style[ name ] = old[ name ];
}
return ret;
};
function adjustCSS( elem, prop, valueParts, tween ) {
var adjusted, scale,
maxIterations = 20,
currentValue = tween ?
function() {
return tween.cur();
} :
function() {
return jQuery.css( elem, prop, "" );
},
initial = currentValue(),
unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ),
// Starting value computation is required for potential unit mismatches
initialInUnit = elem.nodeType &&
( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) &&
rcssNum.exec( jQuery.css( elem, prop ) );
if ( initialInUnit && initialInUnit[ 3 ] !== unit ) {
// Support: Firefox <=54
// Halve the iteration target value to prevent interference from CSS upper bounds (gh-2144)
initial = initial / 2;
// Trust units reported by jQuery.css
unit = unit || initialInUnit[ 3 ];
// Iteratively approximate from a nonzero starting point
initialInUnit = +initial || 1;
while ( maxIterations-- ) {
// Evaluate and update our best guess (doubling guesses that zero out).
// Finish if the scale equals or crosses 1 (making the old*new product non-positive).
jQuery.style( elem, prop, initialInUnit + unit );
if ( ( 1 - scale ) * ( 1 - ( scale = currentValue() / initial || 0.5 ) ) <= 0 ) {
maxIterations = 0;
}
initialInUnit = initialInUnit / scale;
}
initialInUnit = initialInUnit * 2;
jQuery.style( elem, prop, initialInUnit + unit );
// Make sure we update the tween properties later on
valueParts = valueParts || [];
}
if ( valueParts ) {
initialInUnit = +initialInUnit || +initial || 0;
// Apply relative offset (+=/-=) if specified
adjusted = valueParts[ 1 ] ?
initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] :
+valueParts[ 2 ];
if ( tween ) {
tween.unit = unit;
tween.start = initialInUnit;
tween.end = adjusted;
}
}
return adjusted;
}
var defaultDisplayMap = {};
function getDefaultDisplay( elem ) {
var temp,
doc = elem.ownerDocument,
nodeName = elem.nodeName,
display = defaultDisplayMap[ nodeName ];
if ( display ) {
return display;
}
temp = doc.body.appendChild( doc.createElement( nodeName ) );
display = jQuery.css( temp, "display" );
temp.parentNode.removeChild( temp );
if ( display === "none" ) {
display = "block";
}
defaultDisplayMap[ nodeName ] = display;
return display;
}
function showHide( elements, show ) {
var display, elem,
values = [],
index = 0,
length = elements.length;
// Determine new display value for elements that need to change
for ( ; index < length; index++ ) {
elem = elements[ index ];
if ( !elem.style ) {
continue;
}
display = elem.style.display;
if ( show ) {
// Since we force visibility upon cascade-hidden elements, an immediate (and slow)
// check is required in this first loop unless we have a nonempty display value (either
// inline or about-to-be-restored)
if ( display === "none" ) {
values[ index ] = dataPriv.get( elem, "display" ) || null;
if ( !values[ index ] ) {
elem.style.display = "";
}
}
if ( elem.style.display === "" && isHiddenWithinTree( elem ) ) {
values[ index ] = getDefaultDisplay( elem );
}
} else {
if ( display !== "none" ) {
values[ index ] = "none";
// Remember what we're overwriting
dataPriv.set( elem, "display", display );
}
}
}
// Set the display of the elements in a second loop to avoid constant reflow
for ( index = 0; index < length; index++ ) {
if ( values[ index ] != null ) {
elements[ index ].style.display = values[ index ];
}
}
return elements;
}
jQuery.fn.extend( {
show: function() {
return showHide( this, true );
},
hide: function() {
return showHide( this );
},
toggle: function( state ) {
if ( typeof state === "boolean" ) {
return state ? this.show() : this.hide();
}
return this.each( function() {
if ( isHiddenWithinTree( this ) ) {
jQuery( this ).show();
} else {
jQuery( this ).hide();
}
} );
}
} );
var rcheckableType = ( /^(?:checkbox|radio)$/i );
var rtagName = ( /<([a-z][^\/\0>\x20\t\r\n\f]*)/i );
var rscriptType = ( /^$|^module$|\/(?:java|ecma)script/i );
// We have to close these tags to support XHTML (#13200)
var wrapMap = {
// Support: IE <=9 only
option: [ 1, "<select multiple='multiple'>", "</select>" ],
// XHTML parsers do not magically insert elements in the
// same way that tag soup parsers do. So we cannot shorten
// this by omitting <tbody> or other required elements.
thead: [ 1, "<table>", "</table>" ],
col: [ 2, "<table><colgroup>", "</colgroup></table>" ],
tr: [ 2, "<table><tbody>", "</tbody></table>" ],
td: [ 3, "<table><tbody><tr>", "</tr></tbody></table>" ],
_default: [ 0, "", "" ]
};
// Support: IE <=9 only
wrapMap.optgroup = wrapMap.option;
wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead;
wrapMap.th = wrapMap.td;
function getAll( context, tag ) {
// Support: IE <=9 - 11 only
// Use typeof to avoid zero-argument method invocation on host objects (#15151)
var ret;
if ( typeof context.getElementsByTagName !== "undefined" ) {
ret = context.getElementsByTagName( tag || "*" );
} else if ( typeof context.querySelectorAll !== "undefined" ) {
ret = context.querySelectorAll( tag || "*" );
} else {
ret = [];
}
if ( tag === undefined || tag && nodeName( context, tag ) ) {
return jQuery.merge( [ context ], ret );
}
return ret;
}
// Mark scripts as having already been evaluated
function setGlobalEval( elems, refElements ) {
var i = 0,
l = elems.length;
for ( ; i < l; i++ ) {
dataPriv.set(
elems[ i ],
"globalEval",
!refElements || dataPriv.get( refElements[ i ], "globalEval" )
);
}
}
var rhtml = /<|&#?\w+;/;
function buildFragment( elems, context, scripts, selection, ignored ) {
var elem, tmp, tag, wrap, attached, j,
fragment = context.createDocumentFragment(),
nodes = [],
i = 0,
l = elems.length;
for ( ; i < l; i++ ) {
elem = elems[ i ];
if ( elem || elem === 0 ) {
// Add nodes directly
if ( toType( elem ) === "object" ) {
// Support: Android <=4.0 only, PhantomJS 1 only
// push.apply(_, arraylike) throws on ancient WebKit
jQuery.merge( nodes, elem.nodeType ? [ elem ] : elem );
// Convert non-html into a text node
} else if ( !rhtml.test( elem ) ) {
nodes.push( context.createTextNode( elem ) );
// Convert html into DOM nodes
} else {
tmp = tmp || fragment.appendChild( context.createElement( "div" ) );
// Deserialize a standard representation
tag = ( rtagName.exec( elem ) || [ "", "" ] )[ 1 ].toLowerCase();
wrap = wrapMap[ tag ] || wrapMap._default;
tmp.innerHTML = wrap[ 1 ] + jQuery.htmlPrefilter( elem ) + wrap[ 2 ];
// Descend through wrappers to the right content
j = wrap[ 0 ];
while ( j-- ) {
tmp = tmp.lastChild;
}
// Support: Android <=4.0 only, PhantomJS 1 only
// push.apply(_, arraylike) throws on ancient WebKit
jQuery.merge( nodes, tmp.childNodes );
// Remember the top-level container
tmp = fragment.firstChild;
// Ensure the created nodes are orphaned (#12392)
tmp.textContent = "";
}
}
}
// Remove wrapper from fragment
fragment.textContent = "";
i = 0;
while ( ( elem = nodes[ i++ ] ) ) {
// Skip elements already in the context collection (trac-4087)
if ( selection && jQuery.inArray( elem, selection ) > -1 ) {
if ( ignored ) {
ignored.push( elem );
}
continue;
}
attached = isAttached( elem );
// Append to fragment
tmp = getAll( fragment.appendChild( elem ), "script" );
// Preserve script evaluation history
if ( attached ) {
setGlobalEval( tmp );
}
// Capture executables
if ( scripts ) {
j = 0;
while ( ( elem = tmp[ j++ ] ) ) {
if ( rscriptType.test( elem.type || "" ) ) {
scripts.push( elem );
}
}
}
}
return fragment;
}
( function() {
var fragment = document.createDocumentFragment(),
div = fragment.appendChild( document.createElement( "div" ) ),
input = document.createElement( "input" );
// Support: Android 4.0 - 4.3 only
// Check state lost if the name is set (#11217)
// Support: Windows Web Apps (WWA)
// `name` and `type` must use .setAttribute for WWA (#14901)
input.setAttribute( "type", "radio" );
input.setAttribute( "checked", "checked" );
input.setAttribute( "name", "t" );
div.appendChild( input );
// Support: Android <=4.1 only
// Older WebKit doesn't clone checked state correctly in fragments
support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked;
// Support: IE <=11 only
// Make sure textarea (and checkbox) defaultValue is properly cloned
div.innerHTML = "<textarea>x</textarea>";
support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue;
} )();
var
rkeyEvent = /^key/,
rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/,
rtypenamespace = /^([^.]*)(?:\.(.+)|)/;
function returnTrue() {
return true;
}
function returnFalse() {
return false;
}
// Support: IE <=9 - 11+
// focus() and blur() are asynchronous, except when they are no-op.
// So expect focus to be synchronous when the element is already active,
// and blur to be synchronous when the element is not already active.
// (focus and blur are always synchronous in other supported browsers,
// this just defines when we can count on it).
function expectSync( elem, type ) {
return ( elem === safeActiveElement() ) === ( type === "focus" );
}
// Support: IE <=9 only
// Accessing document.activeElement can throw unexpectedly
// https://bugs.jquery.com/ticket/13393
function safeActiveElement() {
try {
return document.activeElement;
} catch ( err ) { }
}
function on( elem, types, selector, data, fn, one ) {
var origFn, type;
// Types can be a map of types/handlers
if ( typeof types === "object" ) {
// ( types-Object, selector, data )
if ( typeof selector !== "string" ) {
// ( types-Object, data )
data = data || selector;
selector = undefined;
}
for ( type in types ) {
on( elem, type, selector, data, types[ type ], one );
}
return elem;
}
if ( data == null && fn == null ) {
// ( types, fn )
fn = selector;
data = selector = undefined;
} else if ( fn == null ) {
if ( typeof selector === "string" ) {
// ( types, selector, fn )
fn = data;
data = undefined;
} else {
// ( types, data, fn )
fn = data;
data = selector;
selector = undefined;
}
}
if ( fn === false ) {
fn = returnFalse;
} else if ( !fn ) {
return elem;
}
if ( one === 1 ) {
origFn = fn;
fn = function( event ) {
// Can use an empty set, since event contains the info
jQuery().off( event );
return origFn.apply( this, arguments );
};
// Use same guid so caller can remove using origFn
fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ );
}
return elem.each( function() {
jQuery.event.add( this, types, fn, data, selector );
} );
}
/*
* Helper functions for managing events -- not part of the public interface.
* Props to Dean Edwards' addEvent library for many of the ideas.
*/
jQuery.event = {
global: {},
add: function( elem, types, handler, data, selector ) {
var handleObjIn, eventHandle, tmp,
events, t, handleObj,
special, handlers, type, namespaces, origType,
elemData = dataPriv.get( elem );
// Don't attach events to noData or text/comment nodes (but allow plain objects)
if ( !elemData ) {
return;
}
// Caller can pass in an object of custom data in lieu of the handler
if ( handler.handler ) {
handleObjIn = handler;
handler = handleObjIn.handler;
selector = handleObjIn.selector;
}
// Ensure that invalid selectors throw exceptions at attach time
// Evaluate against documentElement in case elem is a non-element node (e.g., document)
if ( selector ) {
jQuery.find.matchesSelector( documentElement, selector );
}
// Make sure that the handler has a unique ID, used to find/remove it later
if ( !handler.guid ) {
handler.guid = jQuery.guid++;
}
// Init the element's event structure and main handler, if this is the first
if ( !( events = elemData.events ) ) {
events = elemData.events = {};
}
if ( !( eventHandle = elemData.handle ) ) {
eventHandle = elemData.handle = function( e ) {
// Discard the second event of a jQuery.event.trigger() and
// when an event is called after a page has unloaded
return typeof jQuery !== "undefined" && jQuery.event.triggered !== e.type ?
jQuery.event.dispatch.apply( elem, arguments ) : undefined;
};
}
// Handle multiple events separated by a space
types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
t = types.length;
while ( t-- ) {
tmp = rtypenamespace.exec( types[ t ] ) || [];
type = origType = tmp[ 1 ];
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
// There *must* be a type, no attaching namespace-only handlers
if ( !type ) {
continue;
}
// If event changes its type, use the special event handlers for the changed type
special = jQuery.event.special[ type ] || {};
// If selector defined, determine special event api type, otherwise given type
type = ( selector ? special.delegateType : special.bindType ) || type;
// Update special based on newly reset type
special = jQuery.event.special[ type ] || {};
// handleObj is passed to all event handlers
handleObj = jQuery.extend( {
type: type,
origType: origType,
data: data,
handler: handler,
guid: handler.guid,
selector: selector,
needsContext: selector && jQuery.expr.match.needsContext.test( selector ),
namespace: namespaces.join( "." )
}, handleObjIn );
// Init the event handler queue if we're the first
if ( !( handlers = events[ type ] ) ) {
handlers = events[ type ] = [];
handlers.delegateCount = 0;
// Only use addEventListener if the special events handler returns false
if ( !special.setup ||
special.setup.call( elem, data, namespaces, eventHandle ) === false ) {
if ( elem.addEventListener ) {
elem.addEventListener( type, eventHandle );
}
}
}
if ( special.add ) {
special.add.call( elem, handleObj );
if ( !handleObj.handler.guid ) {
handleObj.handler.guid = handler.guid;
}
}
// Add to the element's handler list, delegates in front
if ( selector ) {
handlers.splice( handlers.delegateCount++, 0, handleObj );
} else {
handlers.push( handleObj );
}
// Keep track of which events have ever been used, for event optimization
jQuery.event.global[ type ] = true;
}
},
// Detach an event or set of events from an element
remove: function( elem, types, handler, selector, mappedTypes ) {
var j, origCount, tmp,
events, t, handleObj,
special, handlers, type, namespaces, origType,
elemData = dataPriv.hasData( elem ) && dataPriv.get( elem );
if ( !elemData || !( events = elemData.events ) ) {
return;
}
// Once for each type.namespace in types; type may be omitted
types = ( types || "" ).match( rnothtmlwhite ) || [ "" ];
t = types.length;
while ( t-- ) {
tmp = rtypenamespace.exec( types[ t ] ) || [];
type = origType = tmp[ 1 ];
namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort();
// Unbind all events (on this namespace, if provided) for the element
if ( !type ) {
for ( type in events ) {
jQuery.event.remove( elem, type + types[ t ], handler, selector, true );
}
continue;
}
special = jQuery.event.special[ type ] || {};
type = ( selector ? special.delegateType : special.bindType ) || type;
handlers = events[ type ] || [];
tmp = tmp[ 2 ] &&
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" );
// Remove matching events
origCount = j = handlers.length;
while ( j-- ) {
handleObj = handlers[ j ];
if ( ( mappedTypes || origType === handleObj.origType ) &&
( !handler || handler.guid === handleObj.guid ) &&
( !tmp || tmp.test( handleObj.namespace ) ) &&
( !selector || selector === handleObj.selector ||
selector === "**" && handleObj.selector ) ) {
handlers.splice( j, 1 );
if ( handleObj.selector ) {
handlers.delegateCount--;
}
if ( special.remove ) {
special.remove.call( elem, handleObj );
}
}
}
// Remove generic event handler if we removed something and no more handlers exist
// (avoids potential for endless recursion during removal of special event handlers)
if ( origCount && !handlers.length ) {
if ( !special.teardown ||
special.teardown.call( elem, namespaces, elemData.handle ) === false ) {
jQuery.removeEvent( elem, type, elemData.handle );
}
delete events[ type ];
}
}
// Remove data and the expando if it's no longer used
if ( jQuery.isEmptyObject( events ) ) {
dataPriv.remove( elem, "handle events" );
}
},
dispatch: function( nativeEvent ) {
// Make a writable jQuery.Event from the native event object
var event = jQuery.event.fix( nativeEvent );
var i, j, ret, matched, handleObj, handlerQueue,
args = new Array( arguments.length ),
handlers = ( dataPriv.get( this, "events" ) || {} )[ event.type ] || [],
special = jQuery.event.special[ event.type ] || {};
// Use the fix-ed jQuery.Event rather than the (read-only) native event
args[ 0 ] = event;
for ( i = 1; i < arguments.length; i++ ) {
args[ i ] = arguments[ i ];
}
event.delegateTarget = this;
// Call the preDispatch hook for the mapped type, and let it bail if desired
if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) {
return;
}
// Determine handlers
handlerQueue = jQuery.event.handlers.call( this, event, handlers );
// Run delegates first; they may want to stop propagation beneath us
i = 0;
while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) {
event.currentTarget = matched.elem;
j = 0;
while ( ( handleObj = matched.handlers[ j++ ] ) &&
!event.isImmediatePropagationStopped() ) {
// If the event is namespaced, then each handler is only invoked if it is
// specially universal or its namespaces are a superset of the event's.
if ( !event.rnamespace || handleObj.namespace === false ||
event.rnamespace.test( handleObj.namespace ) ) {
event.handleObj = handleObj;
event.data = handleObj.data;
ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle ||
handleObj.handler ).apply( matched.elem, args );
if ( ret !== undefined ) {
if ( ( event.result = ret ) === false ) {
event.preventDefault();
event.stopPropagation();
}
}
}
}
}
// Call the postDispatch hook for the mapped type
if ( special.postDispatch ) {
special.postDispatch.call( this, event );
}
return event.result;
},
handlers: function( event, handlers ) {
var i, handleObj, sel, matchedHandlers, matchedSelectors,
handlerQueue = [],
delegateCount = handlers.delegateCount,
cur = event.target;
// Find delegate handlers
if ( delegateCount &&
// Support: IE <=9
// Black-hole SVG <use> instance trees (trac-13180)
cur.nodeType &&
// Support: Firefox <=42
// Suppress spec-violating clicks indicating a non-primary pointer button (trac-3861)
// https://www.w3.org/TR/DOM-Level-3-Events/#event-type-click
// Support: IE 11 only
// ...but not arrow key "clicks" of radio inputs, which can have `button` -1 (gh-2343)
!( event.type === "click" && event.button >= 1 ) ) {
for ( ; cur !== this; cur = cur.parentNode || this ) {
// Don't check non-elements (#13208)
// Don't process clicks on disabled elements (#6911, #8165, #11382, #11764)
if ( cur.nodeType === 1 && !( event.type === "click" && cur.disabled === true ) ) {
matchedHandlers = [];
matchedSelectors = {};
for ( i = 0; i < delegateCount; i++ ) {
handleObj = handlers[ i ];
// Don't conflict with Object.prototype properties (#13203)
sel = handleObj.selector + " ";
if ( matchedSelectors[ sel ] === undefined ) {
matchedSelectors[ sel ] = handleObj.needsContext ?
jQuery( sel, this ).index( cur ) > -1 :
jQuery.find( sel, this, null, [ cur ] ).length;
}
if ( matchedSelectors[ sel ] ) {
matchedHandlers.push( handleObj );
}
}
if ( matchedHandlers.length ) {
handlerQueue.push( { elem: cur, handlers: matchedHandlers } );
}
}
}
}
// Add the remaining (directly-bound) handlers
cur = this;
if ( delegateCount < handlers.length ) {
handlerQueue.push( { elem: cur, handlers: handlers.slice( delegateCount ) } );
}
return handlerQueue;
},
addProp: function( name, hook ) {
Object.defineProperty( jQuery.Event.prototype, name, {
enumerable: true,
configurable: true,
get: isFunction( hook ) ?
function() {
if ( this.originalEvent ) {
return hook( this.originalEvent );
}
} :
function() {
if ( this.originalEvent ) {
return this.originalEvent[ name ];
}
},
set: function( value ) {
Object.defineProperty( this, name, {
enumerable: true,
configurable: true,
writable: true,
value: value
} );
}
} );
},
fix: function( originalEvent ) {
return originalEvent[ jQuery.expando ] ?
originalEvent :
new jQuery.Event( originalEvent );
},
special: {
load: {
// Prevent triggered image.load events from bubbling to window.load
noBubble: true
},
click: {
// Utilize native event to ensure correct state for checkable inputs
setup: function( data ) {
// For mutual compressibility with _default, replace `this` access with a local var.
// `|| data` is dead code meant only to preserve the variable through minification.
var el = this || data;
// Claim the first handler
if ( rcheckableType.test( el.type ) &&
el.click && nodeName( el, "input" ) ) {
// dataPriv.set( el, "click", ... )
leverageNative( el, "click", returnTrue );
}
// Return false to allow normal processing in the caller
return false;
},
trigger: function( data ) {
// For mutual compressibility with _default, replace `this` access with a local var.
// `|| data` is dead code meant only to preserve the variable through minification.
var el = this || data;
// Force setup before triggering a click
if ( rcheckableType.test( el.type ) &&
el.click && nodeName( el, "input" ) ) {
leverageNative( el, "click" );
}
// Return non-false to allow normal event-path propagation
return true;
},
// For cross-browser consistency, suppress native .click() on links
// Also prevent it if we're currently inside a leveraged native-event stack
_default: function( event ) {
var target = event.target;
return rcheckableType.test( target.type ) &&
target.click && nodeName( target, "input" ) &&
dataPriv.get( target, "click" ) ||
nodeName( target, "a" );
}
},
beforeunload: {
postDispatch: function( event ) {
// Support: Firefox 20+
// Firefox doesn't alert if the returnValue field is not set.
if ( event.result !== undefined && event.originalEvent ) {
event.originalEvent.returnValue = event.result;
}
}
}
}
};
// Ensure the presence of an event listener that handles manually-triggered
// synthetic events by interrupting progress until reinvoked in response to
// *native* events that it fires directly, ensuring that state changes have
// already occurred before other listeners are invoked.
function leverageNative( el, type, expectSync ) {
// Missing expectSync indicates a trigger call, which must force setup through jQuery.event.add
if ( !expectSync ) {
if ( dataPriv.get( el, type ) === undefined ) {
jQuery.event.add( el, type, returnTrue );
}
return;
}
// Register the controller as a special universal handler for all event namespaces
dataPriv.set( el, type, false );
jQuery.event.add( el, type, {
namespace: false,
handler: function( event ) {
var notAsync, result,
saved = dataPriv.get( this, type );
if ( ( event.isTrigger & 1 ) && this[ type ] ) {
// Interrupt processing of the outer synthetic .trigger()ed event
// Saved data should be false in such cases, but might be a leftover capture object
// from an async native handler (gh-4350)
if ( !saved.length ) {
// Store arguments for use when handling the inner native event
// There will always be at least one argument (an event object), so this array
// will not be confused with a leftover capture object.
saved = slice.call( arguments );
dataPriv.set( this, type, saved );
// Trigger the native event and capture its result
// Support: IE <=9 - 11+
// focus() and blur() are asynchronous
notAsync = expectSync( this, type );
this[ type ]();
result = dataPriv.get( this, type );
if ( saved !== result || notAsync ) {
dataPriv.set( this, type, false );
} else {
result = {};
}
if ( saved !== result ) {
// Cancel the outer synthetic event
event.stopImmediatePropagation();
event.preventDefault();
return result.value;
}
// If this is an inner synthetic event for an event with a bubbling surrogate
// (focus or blur), assume that the surrogate already propagated from triggering the
// native event and prevent that from happening again here.
// This technically gets the ordering wrong w.r.t. to `.trigger()` (in which the
// bubbling surrogate propagates *after* the non-bubbling base), but that seems
// less bad than duplication.
} else if ( ( jQuery.event.special[ type ] || {} ).delegateType ) {
event.stopPropagation();
}
// If this is a native event triggered above, everything is now in order
// Fire an inner synthetic event with the original arguments
} else if ( saved.length ) {
// ...and capture the result
dataPriv.set( this, type, {
value: jQuery.event.trigger(
// Support: IE <=9 - 11+
// Extend with the prototype to reset the above stopImmediatePropagation()
jQuery.extend( saved[ 0 ], jQuery.Event.prototype ),
saved.slice( 1 ),
this
)
} );
// Abort handling of the native event
event.stopImmediatePropagation();
}
}
} );
}
jQuery.removeEvent = function( elem, type, handle ) {
// This "if" is needed for plain objects
if ( elem.removeEventListener ) {
elem.removeEventListener( type, handle );
}
};
jQuery.Event = function( src, props ) {
// Allow instantiation without the 'new' keyword
if ( !( this instanceof jQuery.Event ) ) {
return new jQuery.Event( src, props );
}
// Event object
if ( src && src.type ) {
this.originalEvent = src;
this.type = src.type;
// Events bubbling up the document may have been marked as prevented
// by a handler lower down the tree; reflect the correct value.
this.isDefaultPrevented = src.defaultPrevented ||
src.defaultPrevented === undefined &&
// Support: Android <=2.3 only
src.returnValue === false ?
returnTrue :
returnFalse;
// Create target properties
// Support: Safari <=6 - 7 only
// Target should not be a text node (#504, #13143)
this.target = ( src.target && src.target.nodeType === 3 ) ?
src.target.parentNode :
src.target;
this.currentTarget = src.currentTarget;
this.relatedTarget = src.relatedTarget;
// Event type
} else {
this.type = src;
}
// Put explicitly provided properties onto the event object
if ( props ) {
jQuery.extend( this, props );
}
// Create a timestamp if incoming event doesn't have one
this.timeStamp = src && src.timeStamp || Date.now();
// Mark it as fixed
this[ jQuery.expando ] = true;
};
// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding
// https://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html
jQuery.Event.prototype = {
constructor: jQuery.Event,
isDefaultPrevented: returnFalse,
isPropagationStopped: returnFalse,
isImmediatePropagationStopped: returnFalse,
isSimulated: false,
preventDefault: function() {
var e = this.originalEvent;
this.isDefaultPrevented = returnTrue;
if ( e && !this.isSimulated ) {
e.preventDefault();
}
},
stopPropagation: function() {
var e = this.originalEvent;
this.isPropagationStopped = returnTrue;
if ( e && !this.isSimulated ) {
e.stopPropagation();
}
},
stopImmediatePropagation: function() {
var e = this.originalEvent;
this.isImmediatePropagationStopped = returnTrue;
if ( e && !this.isSimulated ) {
e.stopImmediatePropagation();
}
this.stopPropagation();
}
};
// Includes all common event props including KeyEvent and MouseEvent specific props
jQuery.each( {
altKey: true,
bubbles: true,
cancelable: true,
changedTouches: true,
ctrlKey: true,
detail: true,
eventPhase: true,
metaKey: true,
pageX: true,
pageY: true,
shiftKey: true,
view: true,
"char": true,
code: true,
charCode: true,
key: true,
keyCode: true,
button: true,
buttons: true,
clientX: true,
clientY: true,
offsetX: true,
offsetY: true,
pointerId: true,
pointerType: true,
screenX: true,
screenY: true,
targetTouches: true,
toElement: true,
touches: true,
which: function( event ) {
var button = event.button;
// Add which for key events
if ( event.which == null && rkeyEvent.test( event.type ) ) {
return event.charCode != null ? event.charCode : event.keyCode;
}
// Add which for click: 1 === left; 2 === middle; 3 === right
if ( !event.which && button !== undefined && rmouseEvent.test( event.type ) ) {
if ( button & 1 ) {
return 1;
}
if ( button & 2 ) {
return 3;
}
if ( button & 4 ) {
return 2;
}
return 0;
}
return event.which;
}
}, jQuery.event.addProp );
jQuery.each( { focus: "focusin", blur: "focusout" }, function( type, delegateType ) {
jQuery.event.special[ type ] = {
// Utilize native event if possible so blur/focus sequence is correct
setup: function() {
// Claim the first handler
// dataPriv.set( this, "focus", ... )
// dataPriv.set( this, "blur", ... )
leverageNative( this, type, expectSync );
// Return false to allow normal processing in the caller
return false;
},
trigger: function() {
// Force setup before trigger
leverageNative( this, type );
// Return non-false to allow normal event-path propagation
return true;
},
delegateType: delegateType
};
} );
// Create mouseenter/leave events using mouseover/out and event-time checks
// so that event delegation works in jQuery.
// Do the same for pointerenter/pointerleave and pointerover/pointerout
//
// Support: Safari 7 only
// Safari sends mouseenter too often; see:
// https://bugs.chromium.org/p/chromium/issues/detail?id=470258
// for the description of the bug (it existed in older Chrome versions as well).
jQuery.each( {
mouseenter: "mouseover",
mouseleave: "mouseout",
pointerenter: "pointerover",
pointerleave: "pointerout"
}, function( orig, fix ) {
jQuery.event.special[ orig ] = {
delegateType: fix,
bindType: fix,
handle: function( event ) {
var ret,
target = this,
related = event.relatedTarget,
handleObj = event.handleObj;
// For mouseenter/leave call the handler if related is outside the target.
// NB: No relatedTarget if the mouse left/entered the browser window
if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) {
event.type = handleObj.origType;
ret = handleObj.handler.apply( this, arguments );
event.type = fix;
}
return ret;
}
};
} );
jQuery.fn.extend( {
on: function( types, selector, data, fn ) {
return on( this, types, selector, data, fn );
},
one: function( types, selector, data, fn ) {
return on( this, types, selector, data, fn, 1 );
},
off: function( types, selector, fn ) {
var handleObj, type;
if ( types && types.preventDefault && types.handleObj ) {
// ( event ) dispatched jQuery.Event
handleObj = types.handleObj;
jQuery( types.delegateTarget ).off(
handleObj.namespace ?
handleObj.origType + "." + handleObj.namespace :
handleObj.origType,
handleObj.selector,
handleObj.handler
);
return this;
}
if ( typeof types === "object" ) {
// ( types-object [, selector] )
for ( type in types ) {
this.off( type, selector, types[ type ] );
}
return this;
}
if ( selector === false || typeof selector === "function" ) {
// ( types [, fn] )
fn = selector;
selector = undefined;
}
if ( fn === false ) {
fn = returnFalse;
}
return this.each( function() {
jQuery.event.remove( this, types, fn, selector );
} );
}
} );
var
/* eslint-disable max-len */
// See https://github.com/eslint/eslint/issues/3229
rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([a-z][^\/\0>\x20\t\r\n\f]*)[^>]*)\/>/gi,
/* eslint-enable */
// Support: IE <=10 - 11, Edge 12 - 13 only
// In IE/Edge using regex groups here causes severe slowdowns.
// See https://connect.microsoft.com/IE/feedback/details/1736512/
rnoInnerhtml = /<script|<style|<link/i,
// checked="checked" or checked
rchecked = /checked\s*(?:[^=]|=\s*.checked.)/i,
rcleanScript = /^\s*<!(?:\[CDATA\[|--)|(?:\]\]|--)>\s*$/g;
// Prefer a tbody over its parent table for containing new rows
function manipulationTarget( elem, content ) {
if ( nodeName( elem, "table" ) &&
nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ) {
return jQuery( elem ).children( "tbody" )[ 0 ] || elem;
}
return elem;
}
// Replace/restore the type attribute of script elements for safe DOM manipulation
function disableScript( elem ) {
elem.type = ( elem.getAttribute( "type" ) !== null ) + "/" + elem.type;
return elem;
}
function restoreScript( elem ) {
if ( ( elem.type || "" ).slice( 0, 5 ) === "true/" ) {
elem.type = elem.type.slice( 5 );
} else {
elem.removeAttribute( "type" );
}
return elem;
}
function cloneCopyEvent( src, dest ) {
var i, l, type, pdataOld, pdataCur, udataOld, udataCur, events;
if ( dest.nodeType !== 1 ) {
return;
}
// 1. Copy private data: events, handlers, etc.
if ( dataPriv.hasData( src ) ) {
pdataOld = dataPriv.access( src );
pdataCur = dataPriv.set( dest, pdataOld );
events = pdataOld.events;
if ( events ) {
delete pdataCur.handle;
pdataCur.events = {};
for ( type in events ) {
for ( i = 0, l = events[ type ].length; i < l; i++ ) {
jQuery.event.add( dest, type, events[ type ][ i ] );
}
}
}
}
// 2. Copy user data
if ( dataUser.hasData( src ) ) {
udataOld = dataUser.access( src );
udataCur = jQuery.extend( {}, udataOld );
dataUser.set( dest, udataCur );
}
}
// Fix IE bugs, see support tests
function fixInput( src, dest ) {
var nodeName = dest.nodeName.toLowerCase();
// Fails to persist the checked state of a cloned checkbox or radio button.
if ( nodeName === "input" && rcheckableType.test( src.type ) ) {
dest.checked = src.checked;
// Fails to return the selected option to the default selected state when cloning options
} else if ( nodeName === "input" || nodeName === "textarea" ) {
dest.defaultValue = src.defaultValue;
}
}
function domManip( collection, args, callback, ignored ) {
// Flatten any nested arrays
args = concat.apply( [], args );
var fragment, first, scripts, hasScripts, node, doc,
i = 0,
l = collection.length,
iNoClone = l - 1,
value = args[ 0 ],
valueIsFunction = isFunction( value );
// We can't cloneNode fragments that contain checked, in WebKit
if ( valueIsFunction ||
( l > 1 && typeof value === "string" &&
!support.checkClone && rchecked.test( value ) ) ) {
return collection.each( function( index ) {
var self = collection.eq( index );
if ( valueIsFunction ) {
args[ 0 ] = value.call( this, index, self.html() );
}
domManip( self, args, callback, ignored );
} );
}
if ( l ) {
fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored );
first = fragment.firstChild;
if ( fragment.childNodes.length === 1 ) {
fragment = first;
}
// Require either new content or an interest in ignored elements to invoke the callback
if ( first || ignored ) {
scripts = jQuery.map( getAll( fragment, "script" ), disableScript );
hasScripts = scripts.length;
// Use the original fragment for the last item
// instead of the first because it can end up
// being emptied incorrectly in certain situations (#8070).
for ( ; i < l; i++ ) {
node = fragment;
if ( i !== iNoClone ) {
node = jQuery.clone( node, true, true );
// Keep references to cloned scripts for later restoration
if ( hasScripts ) {
// Support: Android <=4.0 only, PhantomJS 1 only
// push.apply(_, arraylike) throws on ancient WebKit
jQuery.merge( scripts, getAll( node, "script" ) );
}
}
callback.call( collection[ i ], node, i );
}
if ( hasScripts ) {
doc = scripts[ scripts.length - 1 ].ownerDocument;
// Reenable scripts
jQuery.map( scripts, restoreScript );
// Evaluate executable scripts on first document insertion
for ( i = 0; i < hasScripts; i++ ) {
node = scripts[ i ];
if ( rscriptType.test( node.type || "" ) &&
!dataPriv.access( node, "globalEval" ) &&
jQuery.contains( doc, node ) ) {
if ( node.src && ( node.type || "" ).toLowerCase() !== "module" ) {
// Optional AJAX dependency, but won't run scripts if not present
if ( jQuery._evalUrl && !node.noModule ) {
jQuery._evalUrl( node.src, {
nonce: node.nonce || node.getAttribute( "nonce" )
} );
}
} else {
DOMEval( node.textContent.replace( rcleanScript, "" ), node, doc );
}
}
}
}
}
}
return collection;
}
function remove( elem, selector, keepData ) {
var node,
nodes = selector ? jQuery.filter( selector, elem ) : elem,
i = 0;
for ( ; ( node = nodes[ i ] ) != null; i++ ) {
if ( !keepData && node.nodeType === 1 ) {
jQuery.cleanData( getAll( node ) );
}
if ( node.parentNode ) {
if ( keepData && isAttached( node ) ) {
setGlobalEval( getAll( node, "script" ) );
}
node.parentNode.removeChild( node );
}
}
return elem;
}
jQuery.extend( {
htmlPrefilter: function( html ) {
return html.replace( rxhtmlTag, "<$1></$2>" );
},
clone: function( elem, dataAndEvents, deepDataAndEvents ) {
var i, l, srcElements, destElements,
clone = elem.cloneNode( true ),
inPage = isAttached( elem );
// Fix IE cloning issues
if ( !support.noCloneChecked && ( elem.nodeType === 1 || elem.nodeType === 11 ) &&
!jQuery.isXMLDoc( elem ) ) {
// We eschew Sizzle here for performance reasons: https://jsperf.com/getall-vs-sizzle/2
destElements = getAll( clone );
srcElements = getAll( elem );
for ( i = 0, l = srcElements.length; i < l; i++ ) {
fixInput( srcElements[ i ], destElements[ i ] );
}
}
// Copy the events from the original to the clone
if ( dataAndEvents ) {
if ( deepDataAndEvents ) {
srcElements = srcElements || getAll( elem );
destElements = destElements || getAll( clone );
for ( i = 0, l = srcElements.length; i < l; i++ ) {
cloneCopyEvent( srcElements[ i ], destElements[ i ] );
}
} else {
cloneCopyEvent( elem, clone );
}
}
// Preserve script evaluation history
destElements = getAll( clone, "script" );
if ( destElements.length > 0 ) {
setGlobalEval( destElements, !inPage && getAll( elem, "script" ) );
}
// Return the cloned set
return clone;
},
cleanData: function( elems ) {
var data, elem, type,
special = jQuery.event.special,
i = 0;
for ( ; ( elem = elems[ i ] ) !== undefined; i++ ) {
if ( acceptData( elem ) ) {
if ( ( data = elem[ dataPriv.expando ] ) ) {
if ( data.events ) {
for ( type in data.events ) {
if ( special[ type ] ) {
jQuery.event.remove( elem, type );
// This is a shortcut to avoid jQuery.event.remove's overhead
} else {
jQuery.removeEvent( elem, type, data.handle );
}
}
}
// Support: Chrome <=35 - 45+
// Assign undefined instead of using delete, see Data#remove
elem[ dataPriv.expando ] = undefined;
}
if ( elem[ dataUser.expando ] ) {
// Support: Chrome <=35 - 45+
// Assign undefined instead of using delete, see Data#remove
elem[ dataUser.expando ] = undefined;
}
}
}
}
} );
jQuery.fn.extend( {
detach: function( selector ) {
return remove( this, selector, true );
},
remove: function( selector ) {
return remove( this, selector );
},
text: function( value ) {
return access( this, function( value ) {
return value === undefined ?
jQuery.text( this ) :
this.empty().each( function() {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
this.textContent = value;
}
} );
}, null, value, arguments.length );
},
append: function() {
return domManip( this, arguments, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
var target = manipulationTarget( this, elem );
target.appendChild( elem );
}
} );
},
prepend: function() {
return domManip( this, arguments, function( elem ) {
if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) {
var target = manipulationTarget( this, elem );
target.insertBefore( elem, target.firstChild );
}
} );
},
before: function() {
return domManip( this, arguments, function( elem ) {
if ( this.parentNode ) {
this.parentNode.insertBefore( elem, this );
}
} );
},
after: function() {
return domManip( this, arguments, function( elem ) {
if ( this.parentNode ) {
this.parentNode.insertBefore( elem, this.nextSibling );
}
} );
},
empty: function() {
var elem,
i = 0;
for ( ; ( elem = this[ i ] ) != null; i++ ) {
if ( elem.nodeType === 1 ) {
// Prevent memory leaks
jQuery.cleanData( getAll( elem, false ) );
// Remove any remaining nodes
elem.textContent = "";
}
}
return this;
},
clone: function( dataAndEvents, deepDataAndEvents ) {
dataAndEvents = dataAndEvents == null ? false : dataAndEvents;
deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents;
return this.map( function() {
return jQuery.clone( this, dataAndEvents, deepDataAndEvents );
} );
},
html: function( value ) {
return access( this, function( value ) {
var elem = this[ 0 ] || {},
i = 0,
l = this.length;
if ( value === undefined && elem.nodeType === 1 ) {
return elem.innerHTML;
}
// See if we can take a shortcut and just use innerHTML
if ( typeof value === "string" && !rnoInnerhtml.test( value ) &&
!wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) {
value = jQuery.htmlPrefilter( value );
try {
for ( ; i < l; i++ ) {
elem = this[ i ] || {};
// Remove element nodes and prevent memory leaks
if ( elem.nodeType === 1 ) {
jQuery.cleanData( getAll( elem, false ) );
elem.innerHTML = value;
}
}
elem = 0;
// If using innerHTML throws an exception, use the fallback method
} catch ( e ) {}
}
if ( elem ) {
this.empty().append( value );
}
}, null, value, arguments.length );
},
replaceWith: function() {
var ignored = [];
// Make the changes, replacing each non-ignored context element with the new content
return domManip( this, arguments, function( elem ) {
var parent = this.parentNode;
if ( jQuery.inArray( this, ignored ) < 0 ) {
jQuery.cleanData( getAll( this ) );
if ( parent ) {
parent.replaceChild( elem, this );
}
}
// Force callback invocation
}, ignored );
}
} );
jQuery.each( {
appendTo: "append",
prependTo: "prepend",
insertBefore: "before",
insertAfter: "after",
replaceAll: "replaceWith"
}, function( name, original ) {
jQuery.fn[ name ] = function( selector ) {
var elems,
ret = [],
insert = jQuery( selector ),
last = insert.length - 1,
i = 0;
for ( ; i <= last; i++ ) {
elems = i === last ? this : this.clone( true );
jQuery( insert[ i ] )[ original ]( elems );
// Support: Android <=4.0 only, PhantomJS 1 only
// .get() because push.apply(_, arraylike) throws on ancient WebKit
push.apply( ret, elems.get() );
}
return this.pushStack( ret );
};
} );
var rnumnonpx = new RegExp( "^(" + pnum + ")(?!px)[a-z%]+$", "i" );
var getStyles = function( elem ) {
// Support: IE <=11 only, Firefox <=30 (#15098, #14150)
// IE throws on elements created in popups
// FF meanwhile throws on frame elements through "defaultView.getComputedStyle"
var view = elem.ownerDocument.defaultView;
if ( !view || !view.opener ) {
view = window;
}
return view.getComputedStyle( elem );
};
var rboxStyle = new RegExp( cssExpand.join( "|" ), "i" );
( function() {
// Executing both pixelPosition & boxSizingReliable tests require only one layout
// so they're executed at the same time to save the second computation.
function computeStyleTests() {
// This is a singleton, we need to execute it only once
if ( !div ) {
return;
}
container.style.cssText = "position:absolute;left:-11111px;width:60px;" +
"margin-top:1px;padding:0;border:0";
div.style.cssText =
"position:relative;display:block;box-sizing:border-box;overflow:scroll;" +
"margin:auto;border:1px;padding:1px;" +
"width:60%;top:1%";
documentElement.appendChild( container ).appendChild( div );
var divStyle = window.getComputedStyle( div );
pixelPositionVal = divStyle.top !== "1%";
// Support: Android 4.0 - 4.3 only, Firefox <=3 - 44
reliableMarginLeftVal = roundPixelMeasures( divStyle.marginLeft ) === 12;
// Support: Android 4.0 - 4.3 only, Safari <=9.1 - 10.1, iOS <=7.0 - 9.3
// Some styles come back with percentage values, even though they shouldn't
div.style.right = "60%";
pixelBoxStylesVal = roundPixelMeasures( divStyle.right ) === 36;
// Support: IE 9 - 11 only
// Detect misreporting of content dimensions for box-sizing:border-box elements
boxSizingReliableVal = roundPixelMeasures( divStyle.width ) === 36;
// Support: IE 9 only
// Detect overflow:scroll screwiness (gh-3699)
// Support: Chrome <=64
// Don't get tricked when zoom affects offsetWidth (gh-4029)
div.style.position = "absolute";
scrollboxSizeVal = roundPixelMeasures( div.offsetWidth / 3 ) === 12;
documentElement.removeChild( container );
// Nullify the div so it wouldn't be stored in the memory and
// it will also be a sign that checks already performed
div = null;
}
function roundPixelMeasures( measure ) {
return Math.round( parseFloat( measure ) );
}
var pixelPositionVal, boxSizingReliableVal, scrollboxSizeVal, pixelBoxStylesVal,
reliableMarginLeftVal,
container = document.createElement( "div" ),
div = document.createElement( "div" );
// Finish early in limited (non-browser) environments
if ( !div.style ) {
return;
}
// Support: IE <=9 - 11 only
// Style of cloned element affects source element cloned (#8908)
div.style.backgroundClip = "content-box";
div.cloneNode( true ).style.backgroundClip = "";
support.clearCloneStyle = div.style.backgroundClip === "content-box";
jQuery.extend( support, {
boxSizingReliable: function() {
computeStyleTests();
return boxSizingReliableVal;
},
pixelBoxStyles: function() {
computeStyleTests();
return pixelBoxStylesVal;
},
pixelPosition: function() {
computeStyleTests();
return pixelPositionVal;
},
reliableMarginLeft: function() {
computeStyleTests();
return reliableMarginLeftVal;
},
scrollboxSize: function() {
computeStyleTests();
return scrollboxSizeVal;
}
} );
} )();
function curCSS( elem, name, computed ) {
var width, minWidth, maxWidth, ret,
// Support: Firefox 51+
// Retrieving style before computed somehow
// fixes an issue with getting wrong values
// on detached elements
style = elem.style;
computed = computed || getStyles( elem );
// getPropertyValue is needed for:
// .css('filter') (IE 9 only, #12537)
// .css('--customProperty) (#3144)
if ( computed ) {
ret = computed.getPropertyValue( name ) || computed[ name ];
if ( ret === "" && !isAttached( elem ) ) {
ret = jQuery.style( elem, name );
}
// A tribute to the "awesome hack by Dean Edwards"
// Android Browser returns percentage for some values,
// but width seems to be reliably pixels.
// This is against the CSSOM draft spec:
// https://drafts.csswg.org/cssom/#resolved-values
if ( !support.pixelBoxStyles() && rnumnonpx.test( ret ) && rboxStyle.test( name ) ) {
// Remember the original values
width = style.width;
minWidth = style.minWidth;
maxWidth = style.maxWidth;
// Put in the new values to get a computed value out
style.minWidth = style.maxWidth = style.width = ret;
ret = computed.width;
// Revert the changed values
style.width = width;
style.minWidth = minWidth;
style.maxWidth = maxWidth;
}
}
return ret !== undefined ?
// Support: IE <=9 - 11 only
// IE returns zIndex value as an integer.
ret + "" :
ret;
}
function addGetHookIf( conditionFn, hookFn ) {
// Define the hook, we'll check on the first run if it's really needed.
return {
get: function() {
if ( conditionFn() ) {
// Hook not needed (or it's not possible to use it due
// to missing dependency), remove it.
delete this.get;
return;
}
// Hook needed; redefine it so that the support test is not executed again.
return ( this.get = hookFn ).apply( this, arguments );
}
};
}
var cssPrefixes = [ "Webkit", "Moz", "ms" ],
emptyStyle = document.createElement( "div" ).style,
vendorProps = {};
// Return a vendor-prefixed property or undefined
function vendorPropName( name ) {
// Check for vendor prefixed names
var capName = name[ 0 ].toUpperCase() + name.slice( 1 ),
i = cssPrefixes.length;
while ( i-- ) {
name = cssPrefixes[ i ] + capName;
if ( name in emptyStyle ) {
return name;
}
}
}
// Return a potentially-mapped jQuery.cssProps or vendor prefixed property
function finalPropName( name ) {
var final = jQuery.cssProps[ name ] || vendorProps[ name ];
if ( final ) {
return final;
}
if ( name in emptyStyle ) {
return name;
}
return vendorProps[ name ] = vendorPropName( name ) || name;
}
var
// Swappable if display is none or starts with table
// except "table", "table-cell", or "table-caption"
// See here for display values: https://developer.mozilla.org/en-US/docs/CSS/display
rdisplayswap = /^(none|table(?!-c[ea]).+)/,
rcustomProp = /^--/,
cssShow = { position: "absolute", visibility: "hidden", display: "block" },
cssNormalTransform = {
letterSpacing: "0",
fontWeight: "400"
};
function setPositiveNumber( elem, value, subtract ) {
// Any relative (+/-) values have already been
// normalized at this point
var matches = rcssNum.exec( value );
return matches ?
// Guard against undefined "subtract", e.g., when used as in cssHooks
Math.max( 0, matches[ 2 ] - ( subtract || 0 ) ) + ( matches[ 3 ] || "px" ) :
value;
}
function boxModelAdjustment( elem, dimension, box, isBorderBox, styles, computedVal ) {
var i = dimension === "width" ? 1 : 0,
extra = 0,
delta = 0;
// Adjustment may not be necessary
if ( box === ( isBorderBox ? "border" : "content" ) ) {
return 0;
}
for ( ; i < 4; i += 2 ) {
// Both box models exclude margin
if ( box === "margin" ) {
delta += jQuery.css( elem, box + cssExpand[ i ], true, styles );
}
// If we get here with a content-box, we're seeking "padding" or "border" or "margin"
if ( !isBorderBox ) {
// Add padding
delta += jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
// For "border" or "margin", add border
if ( box !== "padding" ) {
delta += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
// But still keep track of it otherwise
} else {
extra += jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
// If we get here with a border-box (content + padding + border), we're seeking "content" or
// "padding" or "margin"
} else {
// For "content", subtract padding
if ( box === "content" ) {
delta -= jQuery.css( elem, "padding" + cssExpand[ i ], true, styles );
}
// For "content" or "padding", subtract border
if ( box !== "margin" ) {
delta -= jQuery.css( elem, "border" + cssExpand[ i ] + "Width", true, styles );
}
}
}
// Account for positive content-box scroll gutter when requested by providing computedVal
if ( !isBorderBox && computedVal >= 0 ) {
// offsetWidth/offsetHeight is a rounded sum of content, padding, scroll gutter, and border
// Assuming integer scroll gutter, subtract the rest and round down
delta += Math.max( 0, Math.ceil(
elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
computedVal -
delta -
extra -
0.5
// If offsetWidth/offsetHeight is unknown, then we can't determine content-box scroll gutter
// Use an explicit zero to avoid NaN (gh-3964)
) ) || 0;
}
return delta;
}
function getWidthOrHeight( elem, dimension, extra ) {
// Start with computed style
var styles = getStyles( elem ),
// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-4322).
// Fake content-box until we know it's needed to know the true value.
boxSizingNeeded = !support.boxSizingReliable() || extra,
isBorderBox = boxSizingNeeded &&
jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
valueIsBorderBox = isBorderBox,
val = curCSS( elem, dimension, styles ),
offsetProp = "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 );
// Support: Firefox <=54
// Return a confounding non-pixel value or feign ignorance, as appropriate.
if ( rnumnonpx.test( val ) ) {
if ( !extra ) {
return val;
}
val = "auto";
}
// Fall back to offsetWidth/offsetHeight when value is "auto"
// This happens for inline elements with no explicit setting (gh-3571)
// Support: Android <=4.1 - 4.3 only
// Also use offsetWidth/offsetHeight for misreported inline dimensions (gh-3602)
// Support: IE 9-11 only
// Also use offsetWidth/offsetHeight for when box sizing is unreliable
// We use getClientRects() to check for hidden/disconnected.
// In those cases, the computed value can be trusted to be border-box
if ( ( !support.boxSizingReliable() && isBorderBox ||
val === "auto" ||
!parseFloat( val ) && jQuery.css( elem, "display", false, styles ) === "inline" ) &&
elem.getClientRects().length ) {
isBorderBox = jQuery.css( elem, "boxSizing", false, styles ) === "border-box";
// Where available, offsetWidth/offsetHeight approximate border box dimensions.
// Where not available (e.g., SVG), assume unreliable box-sizing and interpret the
// retrieved value as a content box dimension.
valueIsBorderBox = offsetProp in elem;
if ( valueIsBorderBox ) {
val = elem[ offsetProp ];
}
}
// Normalize "" and auto
val = parseFloat( val ) || 0;
// Adjust for the element's box model
return ( val +
boxModelAdjustment(
elem,
dimension,
extra || ( isBorderBox ? "border" : "content" ),
valueIsBorderBox,
styles,
// Provide the current computed size to request scroll gutter calculation (gh-3589)
val
)
) + "px";
}
jQuery.extend( {
// Add in style property hooks for overriding the default
// behavior of getting and setting a style property
cssHooks: {
opacity: {
get: function( elem, computed ) {
if ( computed ) {
// We should always get a number back from opacity
var ret = curCSS( elem, "opacity" );
return ret === "" ? "1" : ret;
}
}
}
},
// Don't automatically add "px" to these possibly-unitless properties
cssNumber: {
"animationIterationCount": true,
"columnCount": true,
"fillOpacity": true,
"flexGrow": true,
"flexShrink": true,
"fontWeight": true,
"gridArea": true,
"gridColumn": true,
"gridColumnEnd": true,
"gridColumnStart": true,
"gridRow": true,
"gridRowEnd": true,
"gridRowStart": true,
"lineHeight": true,
"opacity": true,
"order": true,
"orphans": true,
"widows": true,
"zIndex": true,
"zoom": true
},
// Add in properties whose names you wish to fix before
// setting or getting the value
cssProps: {},
// Get and set the style property on a DOM Node
style: function( elem, name, value, extra ) {
// Don't set styles on text and comment nodes
if ( !elem || elem.nodeType === 3 || elem.nodeType === 8 || !elem.style ) {
return;
}
// Make sure that we're working with the right name
var ret, type, hooks,
origName = camelCase( name ),
isCustomProp = rcustomProp.test( name ),
style = elem.style;
// Make sure that we're working with the right name. We don't
// want to query the value if it is a CSS custom property
// since they are user-defined.
if ( !isCustomProp ) {
name = finalPropName( origName );
}
// Gets hook for the prefixed version, then unprefixed version
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// Check if we're setting a value
if ( value !== undefined ) {
type = typeof value;
// Convert "+=" or "-=" to relative numbers (#7345)
if ( type === "string" && ( ret = rcssNum.exec( value ) ) && ret[ 1 ] ) {
value = adjustCSS( elem, name, ret );
// Fixes bug #9237
type = "number";
}
// Make sure that null and NaN values aren't set (#7116)
if ( value == null || value !== value ) {
return;
}
// If a number was passed in, add the unit (except for certain CSS properties)
// The isCustomProp check can be removed in jQuery 4.0 when we only auto-append
// "px" to a few hardcoded values.
if ( type === "number" && !isCustomProp ) {
value += ret && ret[ 3 ] || ( jQuery.cssNumber[ origName ] ? "" : "px" );
}
// background-* props affect original clone's values
if ( !support.clearCloneStyle && value === "" && name.indexOf( "background" ) === 0 ) {
style[ name ] = "inherit";
}
// If a hook was provided, use that value, otherwise just set the specified value
if ( !hooks || !( "set" in hooks ) ||
( value = hooks.set( elem, value, extra ) ) !== undefined ) {
if ( isCustomProp ) {
style.setProperty( name, value );
} else {
style[ name ] = value;
}
}
} else {
// If a hook was provided get the non-computed value from there
if ( hooks && "get" in hooks &&
( ret = hooks.get( elem, false, extra ) ) !== undefined ) {
return ret;
}
// Otherwise just get the value from the style object
return style[ name ];
}
},
css: function( elem, name, extra, styles ) {
var val, num, hooks,
origName = camelCase( name ),
isCustomProp = rcustomProp.test( name );
// Make sure that we're working with the right name. We don't
// want to modify the value if it is a CSS custom property
// since they are user-defined.
if ( !isCustomProp ) {
name = finalPropName( origName );
}
// Try prefixed name followed by the unprefixed name
hooks = jQuery.cssHooks[ name ] || jQuery.cssHooks[ origName ];
// If a hook was provided get the computed value from there
if ( hooks && "get" in hooks ) {
val = hooks.get( elem, true, extra );
}
// Otherwise, if a way to get the computed value exists, use that
if ( val === undefined ) {
val = curCSS( elem, name, styles );
}
// Convert "normal" to computed value
if ( val === "normal" && name in cssNormalTransform ) {
val = cssNormalTransform[ name ];
}
// Make numeric if forced or a qualifier was provided and val looks numeric
if ( extra === "" || extra ) {
num = parseFloat( val );
return extra === true || isFinite( num ) ? num || 0 : val;
}
return val;
}
} );
jQuery.each( [ "height", "width" ], function( i, dimension ) {
jQuery.cssHooks[ dimension ] = {
get: function( elem, computed, extra ) {
if ( computed ) {
// Certain elements can have dimension info if we invisibly show them
// but it must have a current display style that would benefit
return rdisplayswap.test( jQuery.css( elem, "display" ) ) &&
// Support: Safari 8+
// Table columns in Safari have non-zero offsetWidth & zero
// getBoundingClientRect().width unless display is changed.
// Support: IE <=11 only
// Running getBoundingClientRect on a disconnected node
// in IE throws an error.
( !elem.getClientRects().length || !elem.getBoundingClientRect().width ) ?
swap( elem, cssShow, function() {
return getWidthOrHeight( elem, dimension, extra );
} ) :
getWidthOrHeight( elem, dimension, extra );
}
},
set: function( elem, value, extra ) {
var matches,
styles = getStyles( elem ),
// Only read styles.position if the test has a chance to fail
// to avoid forcing a reflow.
scrollboxSizeBuggy = !support.scrollboxSize() &&
styles.position === "absolute",
// To avoid forcing a reflow, only fetch boxSizing if we need it (gh-3991)
boxSizingNeeded = scrollboxSizeBuggy || extra,
isBorderBox = boxSizingNeeded &&
jQuery.css( elem, "boxSizing", false, styles ) === "border-box",
subtract = extra ?
boxModelAdjustment(
elem,
dimension,
extra,
isBorderBox,
styles
) :
0;
// Account for unreliable border-box dimensions by comparing offset* to computed and
// faking a content-box to get border and padding (gh-3699)
if ( isBorderBox && scrollboxSizeBuggy ) {
subtract -= Math.ceil(
elem[ "offset" + dimension[ 0 ].toUpperCase() + dimension.slice( 1 ) ] -
parseFloat( styles[ dimension ] ) -
boxModelAdjustment( elem, dimension, "border", false, styles ) -
0.5
);
}
// Convert to pixels if value adjustment is needed
if ( subtract && ( matches = rcssNum.exec( value ) ) &&
( matches[ 3 ] || "px" ) !== "px" ) {
elem.style[ dimension ] = value;
value = jQuery.css( elem, dimension );
}
return setPositiveNumber( elem, value, subtract );
}
};
} );
jQuery.cssHooks.marginLeft = addGetHookIf( support.reliableMarginLeft,
function( elem, computed ) {
if ( computed ) {
return ( parseFloat( curCSS( elem, "marginLeft" ) ) ||
elem.getBoundingClientRect().left -
swap( elem, { marginLeft: 0 }, function() {
return elem.getBoundingClientRect().left;
} )
) + "px";
}
}
);
// These hooks are used by animate to expand properties
jQuery.each( {
margin: "",
padding: "",
border: "Width"
}, function( prefix, suffix ) {
jQuery.cssHooks[ prefix + suffix ] = {
expand: function( value ) {
var i = 0,
expanded = {},
// Assumes a single number if not a string
parts = typeof value === "string" ? value.split( " " ) : [ value ];
for ( ; i < 4; i++ ) {
expanded[ prefix + cssExpand[ i ] + suffix ] =
parts[ i ] || parts[ i - 2 ] || parts[ 0 ];
}
return expanded;
}
};
if ( prefix !== "margin" ) {
jQuery.cssHooks[ prefix + suffix ].set = setPositiveNumber;
}
} );
jQuery.fn.extend( {
css: function( name, value ) {
return access( this, function( elem, name, value ) {
var styles, len,
map = {},
i = 0;
if ( Array.isArray( name ) ) {
styles = getStyles( elem );
len = name.length;
for ( ; i < len; i++ ) {
map[ name[ i ] ] = jQuery.css( elem, name[ i ], false, styles );
}
return map;
}
return value !== undefined ?
jQuery.style( elem, name, value ) :
jQuery.css( elem, name );
}, name, value, arguments.length > 1 );
}
} );
function Tween( elem, options, prop, end, easing ) {
return new Tween.prototype.init( elem, options, prop, end, easing );
}
jQuery.Tween = Tween;
Tween.prototype = {
constructor: Tween,
init: function( elem, options, prop, end, easing, unit ) {
this.elem = elem;
this.prop = prop;
this.easing = easing || jQuery.easing._default;
this.options = options;
this.start = this.now = this.cur();
this.end = end;
this.unit = unit || ( jQuery.cssNumber[ prop ] ? "" : "px" );
},
cur: function() {
var hooks = Tween.propHooks[ this.prop ];
return hooks && hooks.get ?
hooks.get( this ) :
Tween.propHooks._default.get( this );
},
run: function( percent ) {
var eased,
hooks = Tween.propHooks[ this.prop ];
if ( this.options.duration ) {
this.pos = eased = jQuery.easing[ this.easing ](
percent, this.options.duration * percent, 0, 1, this.options.duration
);
} else {
this.pos = eased = percent;
}
this.now = ( this.end - this.start ) * eased + this.start;
if ( this.options.step ) {
this.options.step.call( this.elem, this.now, this );
}
if ( hooks && hooks.set ) {
hooks.set( this );
} else {
Tween.propHooks._default.set( this );
}
return this;
}
};
Tween.prototype.init.prototype = Tween.prototype;
Tween.propHooks = {
_default: {
get: function( tween ) {
var result;
// Use a property on the element directly when it is not a DOM element,
// or when there is no matching style property that exists.
if ( tween.elem.nodeType !== 1 ||
tween.elem[ tween.prop ] != null && tween.elem.style[ tween.prop ] == null ) {
return tween.elem[ tween.prop ];
}
// Passing an empty string as a 3rd parameter to .css will automatically
// attempt a parseFloat and fallback to a string if the parse fails.
// Simple values such as "10px" are parsed to Float;
// complex values such as "rotate(1rad)" are returned as-is.
result = jQuery.css( tween.elem, tween.prop, "" );
// Empty strings, null, undefined and "auto" are converted to 0.
return !result || result === "auto" ? 0 : result;
},
set: function( tween ) {
// Use step hook for back compat.
// Use cssHook if its there.
// Use .style if available and use plain properties where available.
if ( jQuery.fx.step[ tween.prop ] ) {
jQuery.fx.step[ tween.prop ]( tween );
} else if ( tween.elem.nodeType === 1 && (
jQuery.cssHooks[ tween.prop ] ||
tween.elem.style[ finalPropName( tween.prop ) ] != null ) ) {
jQuery.style( tween.elem, tween.prop, tween.now + tween.unit );
} else {
tween.elem[ tween.prop ] = tween.now;
}
}
}
};
// Support: IE <=9 only
// Panic based approach to setting things on disconnected nodes
Tween.propHooks.scrollTop = Tween.propHooks.scrollLeft = {
set: function( tween ) {
if ( tween.elem.nodeType && tween.elem.parentNode ) {
tween.elem[ tween.prop ] = tween.now;
}
}
};
jQuery.easing = {
linear: function( p ) {
return p;
},
swing: function( p ) {
return 0.5 - Math.cos( p * Math.PI ) / 2;
},
_default: "swing"
};
jQuery.fx = Tween.prototype.init;
// Back compat <1.8 extension point
jQuery.fx.step = {};
var
fxNow, inProgress,
rfxtypes = /^(?:toggle|show|hide)$/,
rrun = /queueHooks$/;
function schedule() {
if ( inProgress ) {
if ( document.hidden === false && window.requestAnimationFrame ) {
window.requestAnimationFrame( schedule );
} else {
window.setTimeout( schedule, jQuery.fx.interval );
}
jQuery.fx.tick();
}
}
// Animations created synchronously will run synchronously
function createFxNow() {
window.setTimeout( function() {
fxNow = undefined;
} );
return ( fxNow = Date.now() );
}
// Generate parameters to create a standard animation
function genFx( type, includeWidth ) {
var which,
i = 0,
attrs = { height: type };
// If we include width, step value is 1 to do all cssExpand values,
// otherwise step value is 2 to skip over Left and Right
includeWidth = includeWidth ? 1 : 0;
for ( ; i < 4; i += 2 - includeWidth ) {
which = cssExpand[ i ];
attrs[ "margin" + which ] = attrs[ "padding" + which ] = type;
}
if ( includeWidth ) {
attrs.opacity = attrs.width = type;
}
return attrs;
}
function createTween( value, prop, animation ) {
var tween,
collection = ( Animation.tweeners[ prop ] || [] ).concat( Animation.tweeners[ "*" ] ),
index = 0,
length = collection.length;
for ( ; index < length; index++ ) {
if ( ( tween = collection[ index ].call( animation, prop, value ) ) ) {
// We're done with this property
return tween;
}
}
}
function defaultPrefilter( elem, props, opts ) {
var prop, value, toggle, hooks, oldfire, propTween, restoreDisplay, display,
isBox = "width" in props || "height" in props,
anim = this,
orig = {},
style = elem.style,
hidden = elem.nodeType && isHiddenWithinTree( elem ),
dataShow = dataPriv.get( elem, "fxshow" );
// Queue-skipping animations hijack the fx hooks
if ( !opts.queue ) {
hooks = jQuery._queueHooks( elem, "fx" );
if ( hooks.unqueued == null ) {
hooks.unqueued = 0;
oldfire = hooks.empty.fire;
hooks.empty.fire = function() {
if ( !hooks.unqueued ) {
oldfire();
}
};
}
hooks.unqueued++;
anim.always( function() {
// Ensure the complete handler is called before this completes
anim.always( function() {
hooks.unqueued--;
if ( !jQuery.queue( elem, "fx" ).length ) {
hooks.empty.fire();
}
} );
} );
}
// Detect show/hide animations
for ( prop in props ) {
value = props[ prop ];
if ( rfxtypes.test( value ) ) {
delete props[ prop ];
toggle = toggle || value === "toggle";
if ( value === ( hidden ? "hide" : "show" ) ) {
// Pretend to be hidden if this is a "show" and
// there is still data from a stopped show/hide
if ( value === "show" && dataShow && dataShow[ prop ] !== undefined ) {
hidden = true;
// Ignore all other no-op show/hide data
} else {
continue;
}
}
orig[ prop ] = dataShow && dataShow[ prop ] || jQuery.style( elem, prop );
}
}
// Bail out if this is a no-op like .hide().hide()
propTween = !jQuery.isEmptyObject( props );
if ( !propTween && jQuery.isEmptyObject( orig ) ) {
return;
}
// Restrict "overflow" and "display" styles during box animations
if ( isBox && elem.nodeType === 1 ) {
// Support: IE <=9 - 11, Edge 12 - 15
// Record all 3 overflow attributes because IE does not infer the shorthand
// from identically-valued overflowX and overflowY and Edge just mirrors
// the overflowX value there.
opts.overflow = [ style.overflow, style.overflowX, style.overflowY ];
// Identify a display type, preferring old show/hide data over the CSS cascade
restoreDisplay = dataShow && dataShow.display;
if ( restoreDisplay == null ) {
restoreDisplay = dataPriv.get( elem, "display" );
}
display = jQuery.css( elem, "display" );
if ( display === "none" ) {
if ( restoreDisplay ) {
display = restoreDisplay;
} else {
// Get nonempty value(s) by temporarily forcing visibility
showHide( [ elem ], true );
restoreDisplay = elem.style.display || restoreDisplay;
display = jQuery.css( elem, "display" );
showHide( [ elem ] );
}
}
// Animate inline elements as inline-block
if ( display === "inline" || display === "inline-block" && restoreDisplay != null ) {
if ( jQuery.css( elem, "float" ) === "none" ) {
// Restore the original display value at the end of pure show/hide animations
if ( !propTween ) {
anim.done( function() {
style.display = restoreDisplay;
} );
if ( restoreDisplay == null ) {
display = style.display;
restoreDisplay = display === "none" ? "" : display;
}
}
style.display = "inline-block";
}
}
}
if ( opts.overflow ) {
style.overflow = "hidden";
anim.always( function() {
style.overflow = opts.overflow[ 0 ];
style.overflowX = opts.overflow[ 1 ];
style.overflowY = opts.overflow[ 2 ];
} );
}
// Implement show/hide animations
propTween = false;
for ( prop in orig ) {
// General show/hide setup for this element animation
if ( !propTween ) {
if ( dataShow ) {
if ( "hidden" in dataShow ) {
hidden = dataShow.hidden;
}
} else {
dataShow = dataPriv.access( elem, "fxshow", { display: restoreDisplay } );
}
// Store hidden/visible for toggle so `.stop().toggle()` "reverses"
if ( toggle ) {
dataShow.hidden = !hidden;
}
// Show elements before animating them
if ( hidden ) {
showHide( [ elem ], true );
}
/* eslint-disable no-loop-func */
anim.done( function() {
/* eslint-enable no-loop-func */
// The final step of a "hide" animation is actually hiding the element
if ( !hidden ) {
showHide( [ elem ] );
}
dataPriv.remove( elem, "fxshow" );
for ( prop in orig ) {
jQuery.style( elem, prop, orig[ prop ] );
}
} );
}
// Per-property setup
propTween = createTween( hidden ? dataShow[ prop ] : 0, prop, anim );
if ( !( prop in dataShow ) ) {
dataShow[ prop ] = propTween.start;
if ( hidden ) {
propTween.end = propTween.start;
propTween.start = 0;
}
}
}
}
function propFilter( props, specialEasing ) {
var index, name, easing, value, hooks;
// camelCase, specialEasing and expand cssHook pass
for ( index in props ) {
name = camelCase( index );
easing = specialEasing[ name ];
value = props[ index ];
if ( Array.isArray( value ) ) {
easing = value[ 1 ];
value = props[ index ] = value[ 0 ];
}
if ( index !== name ) {
props[ name ] = value;
delete props[ index ];
}
hooks = jQuery.cssHooks[ name ];
if ( hooks && "expand" in hooks ) {
value = hooks.expand( value );
delete props[ name ];
// Not quite $.extend, this won't overwrite existing keys.
// Reusing 'index' because we have the correct "name"
for ( index in value ) {
if ( !( index in props ) ) {
props[ index ] = value[ index ];
specialEasing[ index ] = easing;
}
}
} else {
specialEasing[ name ] = easing;
}
}
}
function Animation( elem, properties, options ) {
var result,
stopped,
index = 0,
length = Animation.prefilters.length,
deferred = jQuery.Deferred().always( function() {
// Don't match elem in the :animated selector
delete tick.elem;
} ),
tick = function() {
if ( stopped ) {
return false;
}
var currentTime = fxNow || createFxNow(),
remaining = Math.max( 0, animation.startTime + animation.duration - currentTime ),
// Support: Android 2.3 only
// Archaic crash bug won't allow us to use `1 - ( 0.5 || 0 )` (#12497)
temp = remaining / animation.duration || 0,
percent = 1 - temp,
index = 0,
length = animation.tweens.length;
for ( ; index < length; index++ ) {
animation.tweens[ index ].run( percent );
}
deferred.notifyWith( elem, [ animation, percent, remaining ] );
// If there's more to do, yield
if ( percent < 1 && length ) {
return remaining;
}
// If this was an empty animation, synthesize a final progress notification
if ( !length ) {
deferred.notifyWith( elem, [ animation, 1, 0 ] );
}
// Resolve the animation and report its conclusion
deferred.resolveWith( elem, [ animation ] );
return false;
},
animation = deferred.promise( {
elem: elem,
props: jQuery.extend( {}, properties ),
opts: jQuery.extend( true, {
specialEasing: {},
easing: jQuery.easing._default
}, options ),
originalProperties: properties,
originalOptions: options,
startTime: fxNow || createFxNow(),
duration: options.duration,
tweens: [],
createTween: function( prop, end ) {
var tween = jQuery.Tween( elem, animation.opts, prop, end,
animation.opts.specialEasing[ prop ] || animation.opts.easing );
animation.tweens.push( tween );
return tween;
},
stop: function( gotoEnd ) {
var index = 0,
// If we are going to the end, we want to run all the tweens
// otherwise we skip this part
length = gotoEnd ? animation.tweens.length : 0;
if ( stopped ) {
return this;
}
stopped = true;
for ( ; index < length; index++ ) {
animation.tweens[ index ].run( 1 );
}
// Resolve when we played the last frame; otherwise, reject
if ( gotoEnd ) {
deferred.notifyWith( elem, [ animation, 1, 0 ] );
deferred.resolveWith( elem, [ animation, gotoEnd ] );
} else {
deferred.rejectWith( elem, [ animation, gotoEnd ] );
}
return this;
}
} ),
props = animation.props;
propFilter( props, animation.opts.specialEasing );
for ( ; index < length; index++ ) {
result = Animation.prefilters[ index ].call( animation, elem, props, animation.opts );
if ( result ) {
if ( isFunction( result.stop ) ) {
jQuery._queueHooks( animation.elem, animation.opts.queue ).stop =
result.stop.bind( result );
}
return result;
}
}
jQuery.map( props, createTween, animation );
if ( isFunction( animation.opts.start ) ) {
animation.opts.start.call( elem, animation );
}
// Attach callbacks from options
animation
.progress( animation.opts.progress )
.done( animation.opts.done, animation.opts.complete )
.fail( animation.opts.fail )
.always( animation.opts.always );
jQuery.fx.timer(
jQuery.extend( tick, {
elem: elem,
anim: animation,
queue: animation.opts.queue
} )
);
return animation;
}
jQuery.Animation = jQuery.extend( Animation, {
tweeners: {
"*": [ function( prop, value ) {
var tween = this.createTween( prop, value );
adjustCSS( tween.elem, prop, rcssNum.exec( value ), tween );
return tween;
} ]
},
tweener: function( props, callback ) {
if ( isFunction( props ) ) {
callback = props;
props = [ "*" ];
} else {
props = props.match( rnothtmlwhite );
}
var prop,
index = 0,
length = props.length;
for ( ; index < length; index++ ) {
prop = props[ index ];
Animation.tweeners[ prop ] = Animation.tweeners[ prop ] || [];
Animation.tweeners[ prop ].unshift( callback );
}
},
prefilters: [ defaultPrefilter ],
prefilter: function( callback, prepend ) {
if ( prepend ) {
Animation.prefilters.unshift( callback );
} else {
Animation.prefilters.push( callback );
}
}
} );
jQuery.speed = function( speed, easing, fn ) {
var opt = speed && typeof speed === "object" ? jQuery.extend( {}, speed ) : {
complete: fn || !fn && easing ||
isFunction( speed ) && speed,
duration: speed,
easing: fn && easing || easing && !isFunction( easing ) && easing
};
// Go to the end state if fx are off
if ( jQuery.fx.off ) {
opt.duration = 0;
} else {
if ( typeof opt.duration !== "number" ) {
if ( opt.duration in jQuery.fx.speeds ) {
opt.duration = jQuery.fx.speeds[ opt.duration ];
} else {
opt.duration = jQuery.fx.speeds._default;
}
}
}
// Normalize opt.queue - true/undefined/null -> "fx"
if ( opt.queue == null || opt.queue === true ) {
opt.queue = "fx";
}
// Queueing
opt.old = opt.complete;
opt.complete = function() {
if ( isFunction( opt.old ) ) {
opt.old.call( this );
}
if ( opt.queue ) {
jQuery.dequeue( this, opt.queue );
}
};
return opt;
};
jQuery.fn.extend( {
fadeTo: function( speed, to, easing, callback ) {
// Show any hidden elements after setting opacity to 0
return this.filter( isHiddenWithinTree ).css( "opacity", 0 ).show()
// Animate to the value specified
.end().animate( { opacity: to }, speed, easing, callback );
},
animate: function( prop, speed, easing, callback ) {
var empty = jQuery.isEmptyObject( prop ),
optall = jQuery.speed( speed, easing, callback ),
doAnimation = function() {
// Operate on a copy of prop so per-property easing won't be lost
var anim = Animation( this, jQuery.extend( {}, prop ), optall );
// Empty animations, or finishing resolves immediately
if ( empty || dataPriv.get( this, "finish" ) ) {
anim.stop( true );
}
};
doAnimation.finish = doAnimation;
return empty || optall.queue === false ?
this.each( doAnimation ) :
this.queue( optall.queue, doAnimation );
},
stop: function( type, clearQueue, gotoEnd ) {
var stopQueue = function( hooks ) {
var stop = hooks.stop;
delete hooks.stop;
stop( gotoEnd );
};
if ( typeof type !== "string" ) {
gotoEnd = clearQueue;
clearQueue = type;
type = undefined;
}
if ( clearQueue && type !== false ) {
this.queue( type || "fx", [] );
}
return this.each( function() {
var dequeue = true,
index = type != null && type + "queueHooks",
timers = jQuery.timers,
data = dataPriv.get( this );
if ( index ) {
if ( data[ index ] && data[ index ].stop ) {
stopQueue( data[ index ] );
}
} else {
for ( index in data ) {
if ( data[ index ] && data[ index ].stop && rrun.test( index ) ) {
stopQueue( data[ index ] );
}
}
}
for ( index = timers.length; index--; ) {
if ( timers[ index ].elem === this &&
( type == null || timers[ index ].queue === type ) ) {
timers[ index ].anim.stop( gotoEnd );
dequeue = false;
timers.splice( index, 1 );
}
}
// Start the next in the queue if the last step wasn't forced.
// Timers currently will call their complete callbacks, which
// will dequeue but only if they were gotoEnd.
if ( dequeue || !gotoEnd ) {
jQuery.dequeue( this, type );
}
} );
},
finish: function( type ) {
if ( type !== false ) {
type = type || "fx";
}
return this.each( function() {
var index,
data = dataPriv.get( this ),
queue = data[ type + "queue" ],
hooks = data[ type + "queueHooks" ],
timers = jQuery.timers,
length = queue ? queue.length : 0;
// Enable finishing flag on private data
data.finish = true;
// Empty the queue first
jQuery.queue( this, type, [] );
if ( hooks && hooks.stop ) {
hooks.stop.call( this, true );
}
// Look for any active animations, and finish them
for ( index = timers.length; index--; ) {
if ( timers[ index ].elem === this && timers[ index ].queue === type ) {
timers[ index ].anim.stop( true );
timers.splice( index, 1 );
}
}
// Look for any animations in the old queue and finish them
for ( index = 0; index < length; index++ ) {
if ( queue[ index ] && queue[ index ].finish ) {
queue[ index ].finish.call( this );
}
}
// Turn off finishing flag
delete data.finish;
} );
}
} );
jQuery.each( [ "toggle", "show", "hide" ], function( i, name ) {
var cssFn = jQuery.fn[ name ];
jQuery.fn[ name ] = function( speed, easing, callback ) {
return speed == null || typeof speed === "boolean" ?
cssFn.apply( this, arguments ) :
this.animate( genFx( name, true ), speed, easing, callback );
};
} );
// Generate shortcuts for custom animations
jQuery.each( {
slideDown: genFx( "show" ),
slideUp: genFx( "hide" ),
slideToggle: genFx( "toggle" ),
fadeIn: { opacity: "show" },
fadeOut: { opacity: "hide" },
fadeToggle: { opacity: "toggle" }
}, function( name, props ) {
jQuery.fn[ name ] = function( speed, easing, callback ) {
return this.animate( props, speed, easing, callback );
};
} );
jQuery.timers = [];
jQuery.fx.tick = function() {
var timer,
i = 0,
timers = jQuery.timers;
fxNow = Date.now();
for ( ; i < timers.length; i++ ) {
timer = timers[ i ];
// Run the timer and safely remove it when done (allowing for external removal)
if ( !timer() && timers[ i ] === timer ) {
timers.splice( i--, 1 );
}
}
if ( !timers.length ) {
jQuery.fx.stop();
}
fxNow = undefined;
};
jQuery.fx.timer = function( timer ) {
jQuery.timers.push( timer );
jQuery.fx.start();
};
jQuery.fx.interval = 13;
jQuery.fx.start = function() {
if ( inProgress ) {
return;
}
inProgress = true;
schedule();
};
jQuery.fx.stop = function() {
inProgress = null;
};
jQuery.fx.speeds = {
slow: 600,
fast: 200,
// Default speed
_default: 400
};
// Based off of the plugin by Clint Helfers, with permission.
// https://web.archive.org/web/20100324014747/http://blindsignals.com/index.php/2009/07/jquery-delay/
jQuery.fn.delay = function( time, type ) {
time = jQuery.fx ? jQuery.fx.speeds[ time ] || time : time;
type = type || "fx";
return this.queue( type, function( next, hooks ) {
var timeout = window.setTimeout( next, time );
hooks.stop = function() {
window.clearTimeout( timeout );
};
} );
};
( function() {
var input = document.createElement( "input" ),
select = document.createElement( "select" ),
opt = select.appendChild( document.createElement( "option" ) );
input.type = "checkbox";
// Support: Android <=4.3 only
// Default value for a checkbox should be "on"
support.checkOn = input.value !== "";
// Support: IE <=11 only
// Must access selectedIndex to make default options select
support.optSelected = opt.selected;
// Support: IE <=11 only
// An input loses its value after becoming a radio
input = document.createElement( "input" );
input.value = "t";
input.type = "radio";
support.radioValue = input.value === "t";
} )();
var boolHook,
attrHandle = jQuery.expr.attrHandle;
jQuery.fn.extend( {
attr: function( name, value ) {
return access( this, jQuery.attr, name, value, arguments.length > 1 );
},
removeAttr: function( name ) {
return this.each( function() {
jQuery.removeAttr( this, name );
} );
}
} );
jQuery.extend( {
attr: function( elem, name, value ) {
var ret, hooks,
nType = elem.nodeType;
// Don't get/set attributes on text, comment and attribute nodes
if ( nType === 3 || nType === 8 || nType === 2 ) {
return;
}
// Fallback to prop when attributes are not supported
if ( typeof elem.getAttribute === "undefined" ) {
return jQuery.prop( elem, name, value );
}
// Attribute hooks are determined by the lowercase version
// Grab necessary hook if one is defined
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
hooks = jQuery.attrHooks[ name.toLowerCase() ] ||
( jQuery.expr.match.bool.test( name ) ? boolHook : undefined );
}
if ( value !== undefined ) {
if ( value === null ) {
jQuery.removeAttr( elem, name );
return;
}
if ( hooks && "set" in hooks &&
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
return ret;
}
elem.setAttribute( name, value + "" );
return value;
}
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
return ret;
}
ret = jQuery.find.attr( elem, name );
// Non-existent attributes return null, we normalize to undefined
return ret == null ? undefined : ret;
},
attrHooks: {
type: {
set: function( elem, value ) {
if ( !support.radioValue && value === "radio" &&
nodeName( elem, "input" ) ) {
var val = elem.value;
elem.setAttribute( "type", value );
if ( val ) {
elem.value = val;
}
return value;
}
}
}
},
removeAttr: function( elem, value ) {
var name,
i = 0,
// Attribute names can contain non-HTML whitespace characters
// https://html.spec.whatwg.org/multipage/syntax.html#attributes-2
attrNames = value && value.match( rnothtmlwhite );
if ( attrNames && elem.nodeType === 1 ) {
while ( ( name = attrNames[ i++ ] ) ) {
elem.removeAttribute( name );
}
}
}
} );
// Hooks for boolean attributes
boolHook = {
set: function( elem, value, name ) {
if ( value === false ) {
// Remove boolean attributes when set to false
jQuery.removeAttr( elem, name );
} else {
elem.setAttribute( name, name );
}
return name;
}
};
jQuery.each( jQuery.expr.match.bool.source.match( /\w+/g ), function( i, name ) {
var getter = attrHandle[ name ] || jQuery.find.attr;
attrHandle[ name ] = function( elem, name, isXML ) {
var ret, handle,
lowercaseName = name.toLowerCase();
if ( !isXML ) {
// Avoid an infinite loop by temporarily removing this function from the getter
handle = attrHandle[ lowercaseName ];
attrHandle[ lowercaseName ] = ret;
ret = getter( elem, name, isXML ) != null ?
lowercaseName :
null;
attrHandle[ lowercaseName ] = handle;
}
return ret;
};
} );
var rfocusable = /^(?:input|select|textarea|button)$/i,
rclickable = /^(?:a|area)$/i;
jQuery.fn.extend( {
prop: function( name, value ) {
return access( this, jQuery.prop, name, value, arguments.length > 1 );
},
removeProp: function( name ) {
return this.each( function() {
delete this[ jQuery.propFix[ name ] || name ];
} );
}
} );
jQuery.extend( {
prop: function( elem, name, value ) {
var ret, hooks,
nType = elem.nodeType;
// Don't get/set properties on text, comment and attribute nodes
if ( nType === 3 || nType === 8 || nType === 2 ) {
return;
}
if ( nType !== 1 || !jQuery.isXMLDoc( elem ) ) {
// Fix name and attach hooks
name = jQuery.propFix[ name ] || name;
hooks = jQuery.propHooks[ name ];
}
if ( value !== undefined ) {
if ( hooks && "set" in hooks &&
( ret = hooks.set( elem, value, name ) ) !== undefined ) {
return ret;
}
return ( elem[ name ] = value );
}
if ( hooks && "get" in hooks && ( ret = hooks.get( elem, name ) ) !== null ) {
return ret;
}
return elem[ name ];
},
propHooks: {
tabIndex: {
get: function( elem ) {
// Support: IE <=9 - 11 only
// elem.tabIndex doesn't always return the
// correct value when it hasn't been explicitly set
// https://web.archive.org/web/20141116233347/http://fluidproject.org/blog/2008/01/09/getting-setting-and-removing-tabindex-values-with-javascript/
// Use proper attribute retrieval(#12072)
var tabindex = jQuery.find.attr( elem, "tabindex" );
if ( tabindex ) {
return parseInt( tabindex, 10 );
}
if (
rfocusable.test( elem.nodeName ) ||
rclickable.test( elem.nodeName ) &&
elem.href
) {
return 0;
}
return -1;
}
}
},
propFix: {
"for": "htmlFor",
"class": "className"
}
} );
// Support: IE <=11 only
// Accessing the selectedIndex property
// forces the browser to respect setting selected
// on the option
// The getter ensures a default option is selected
// when in an optgroup
// eslint rule "no-unused-expressions" is disabled for this code
// since it considers such accessions noop
if ( !support.optSelected ) {
jQuery.propHooks.selected = {
get: function( elem ) {
/* eslint no-unused-expressions: "off" */
var parent = elem.parentNode;
if ( parent && parent.parentNode ) {
parent.parentNode.selectedIndex;
}
return null;
},
set: function( elem ) {
/* eslint no-unused-expressions: "off" */
var parent = elem.parentNode;
if ( parent ) {
parent.selectedIndex;
if ( parent.parentNode ) {
parent.parentNode.selectedIndex;
}
}
}
};
}
jQuery.each( [
"tabIndex",
"readOnly",
"maxLength",
"cellSpacing",
"cellPadding",
"rowSpan",
"colSpan",
"useMap",
"frameBorder",
"contentEditable"
], function() {
jQuery.propFix[ this.toLowerCase() ] = this;
} );
// Strip and collapse whitespace according to HTML spec
// https://infra.spec.whatwg.org/#strip-and-collapse-ascii-whitespace
function stripAndCollapse( value ) {
var tokens = value.match( rnothtmlwhite ) || [];
return tokens.join( " " );
}
function getClass( elem ) {
return elem.getAttribute && elem.getAttribute( "class" ) || "";
}
function classesToArray( value ) {
if ( Array.isArray( value ) ) {
return value;
}
if ( typeof value === "string" ) {
return value.match( rnothtmlwhite ) || [];
}
return [];
}
jQuery.fn.extend( {
addClass: function( value ) {
var classes, elem, cur, curValue, clazz, j, finalValue,
i = 0;
if ( isFunction( value ) ) {
return this.each( function( j ) {
jQuery( this ).addClass( value.call( this, j, getClass( this ) ) );
} );
}
classes = classesToArray( value );
if ( classes.length ) {
while ( ( elem = this[ i++ ] ) ) {
curValue = getClass( elem );
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
if ( cur ) {
j = 0;
while ( ( clazz = classes[ j++ ] ) ) {
if ( cur.indexOf( " " + clazz + " " ) < 0 ) {
cur += clazz + " ";
}
}
// Only assign if different to avoid unneeded rendering.
finalValue = stripAndCollapse( cur );
if ( curValue !== finalValue ) {
elem.setAttribute( "class", finalValue );
}
}
}
}
return this;
},
removeClass: function( value ) {
var classes, elem, cur, curValue, clazz, j, finalValue,
i = 0;
if ( isFunction( value ) ) {
return this.each( function( j ) {
jQuery( this ).removeClass( value.call( this, j, getClass( this ) ) );
} );
}
if ( !arguments.length ) {
return this.attr( "class", "" );
}
classes = classesToArray( value );
if ( classes.length ) {
while ( ( elem = this[ i++ ] ) ) {
curValue = getClass( elem );
// This expression is here for better compressibility (see addClass)
cur = elem.nodeType === 1 && ( " " + stripAndCollapse( curValue ) + " " );
if ( cur ) {
j = 0;
while ( ( clazz = classes[ j++ ] ) ) {
// Remove *all* instances
while ( cur.indexOf( " " + clazz + " " ) > -1 ) {
cur = cur.replace( " " + clazz + " ", " " );
}
}
// Only assign if different to avoid unneeded rendering.
finalValue = stripAndCollapse( cur );
if ( curValue !== finalValue ) {
elem.setAttribute( "class", finalValue );
}
}
}
}
return this;
},
toggleClass: function( value, stateVal ) {
var type = typeof value,
isValidValue = type === "string" || Array.isArray( value );
if ( typeof stateVal === "boolean" && isValidValue ) {
return stateVal ? this.addClass( value ) : this.removeClass( value );
}
if ( isFunction( value ) ) {
return this.each( function( i ) {
jQuery( this ).toggleClass(
value.call( this, i, getClass( this ), stateVal ),
stateVal
);
} );
}
return this.each( function() {
var className, i, self, classNames;
if ( isValidValue ) {
// Toggle individual class names
i = 0;
self = jQuery( this );
classNames = classesToArray( value );
while ( ( className = classNames[ i++ ] ) ) {
// Check each className given, space separated list
if ( self.hasClass( className ) ) {
self.removeClass( className );
} else {
self.addClass( className );
}
}
// Toggle whole class name
} else if ( value === undefined || type === "boolean" ) {
className = getClass( this );
if ( className ) {
// Store className if set
dataPriv.set( this, "__className__", className );
}
// If the element has a class name or if we're passed `false`,
// then remove the whole classname (if there was one, the above saved it).
// Otherwise bring back whatever was previously saved (if anything),
// falling back to the empty string if nothing was stored.
if ( this.setAttribute ) {
this.setAttribute( "class",
className || value === false ?
"" :
dataPriv.get( this, "__className__" ) || ""
);
}
}
} );
},
hasClass: function( selector ) {
var className, elem,
i = 0;
className = " " + selector + " ";
while ( ( elem = this[ i++ ] ) ) {
if ( elem.nodeType === 1 &&
( " " + stripAndCollapse( getClass( elem ) ) + " " ).indexOf( className ) > -1 ) {
return true;
}
}
return false;
}
} );
var rreturn = /\r/g;
jQuery.fn.extend( {
val: function( value ) {
var hooks, ret, valueIsFunction,
elem = this[ 0 ];
if ( !arguments.length ) {
if ( elem ) {
hooks = jQuery.valHooks[ elem.type ] ||
jQuery.valHooks[ elem.nodeName.toLowerCase() ];
if ( hooks &&
"get" in hooks &&
( ret = hooks.get( elem, "value" ) ) !== undefined
) {
return ret;
}
ret = elem.value;
// Handle most common string cases
if ( typeof ret === "string" ) {
return ret.replace( rreturn, "" );
}
// Handle cases where value is null/undef or number
return ret == null ? "" : ret;
}
return;
}
valueIsFunction = isFunction( value );
return this.each( function( i ) {
var val;
if ( this.nodeType !== 1 ) {
return;
}
if ( valueIsFunction ) {
val = value.call( this, i, jQuery( this ).val() );
} else {
val = value;
}
// Treat null/undefined as ""; convert numbers to string
if ( val == null ) {
val = "";
} else if ( typeof val === "number" ) {
val += "";
} else if ( Array.isArray( val ) ) {
val = jQuery.map( val, function( value ) {
return value == null ? "" : value + "";
} );
}
hooks = jQuery.valHooks[ this.type ] || jQuery.valHooks[ this.nodeName.toLowerCase() ];
// If set returns undefined, fall back to normal setting
if ( !hooks || !( "set" in hooks ) || hooks.set( this, val, "value" ) === undefined ) {
this.value = val;
}
} );
}
} );
jQuery.extend( {
valHooks: {
option: {
get: function( elem ) {
var val = jQuery.find.attr( elem, "value" );
return val != null ?
val :
// Support: IE <=10 - 11 only
// option.text throws exceptions (#14686, #14858)
// Strip and collapse whitespace
// https://html.spec.whatwg.org/#strip-and-collapse-whitespace
stripAndCollapse( jQuery.text( elem ) );
}
},
select: {
get: function( elem ) {
var value, option, i,
options = elem.options,
index = elem.selectedIndex,
one = elem.type === "select-one",
values = one ? null : [],
max = one ? index + 1 : options.length;
if ( index < 0 ) {
i = max;
} else {
i = one ? index : 0;
}
// Loop through all the selected options
for ( ; i < max; i++ ) {
option = options[ i ];
// Support: IE <=9 only
// IE8-9 doesn't update selected after form reset (#2551)
if ( ( option.selected || i === index ) &&
// Don't return options that are disabled or in a disabled optgroup
!option.disabled &&
( !option.parentNode.disabled ||
!nodeName( option.parentNode, "optgroup" ) ) ) {
// Get the specific value for the option
value = jQuery( option ).val();
// We don't need an array for one selects
if ( one ) {
return value;
}
// Multi-Selects return an array
values.push( value );
}
}
return values;
},
set: function( elem, value ) {
var optionSet, option,
options = elem.options,
values = jQuery.makeArray( value ),
i = options.length;
while ( i-- ) {
option = options[ i ];
/* eslint-disable no-cond-assign */
if ( option.selected =
jQuery.inArray( jQuery.valHooks.option.get( option ), values ) > -1
) {
optionSet = true;
}
/* eslint-enable no-cond-assign */
}
// Force browsers to behave consistently when non-matching value is set
if ( !optionSet ) {
elem.selectedIndex = -1;
}
return values;
}
}
}
} );
// Radios and checkboxes getter/setter
jQuery.each( [ "radio", "checkbox" ], function() {
jQuery.valHooks[ this ] = {
set: function( elem, value ) {
if ( Array.isArray( value ) ) {
return ( elem.checked = jQuery.inArray( jQuery( elem ).val(), value ) > -1 );
}
}
};
if ( !support.checkOn ) {
jQuery.valHooks[ this ].get = function( elem ) {
return elem.getAttribute( "value" ) === null ? "on" : elem.value;
};
}
} );
// Return jQuery for attributes-only inclusion
support.focusin = "onfocusin" in window;
var rfocusMorph = /^(?:focusinfocus|focusoutblur)$/,
stopPropagationCallback = function( e ) {
e.stopPropagation();
};
jQuery.extend( jQuery.event, {
trigger: function( event, data, elem, onlyHandlers ) {
var i, cur, tmp, bubbleType, ontype, handle, special, lastElement,
eventPath = [ elem || document ],
type = hasOwn.call( event, "type" ) ? event.type : event,
namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : [];
cur = lastElement = tmp = elem = elem || document;
// Don't do events on text and comment nodes
if ( elem.nodeType === 3 || elem.nodeType === 8 ) {
return;
}
// focus/blur morphs to focusin/out; ensure we're not firing them right now
if ( rfocusMorph.test( type + jQuery.event.triggered ) ) {
return;
}
if ( type.indexOf( "." ) > -1 ) {
// Namespaced trigger; create a regexp to match event type in handle()
namespaces = type.split( "." );
type = namespaces.shift();
namespaces.sort();
}
ontype = type.indexOf( ":" ) < 0 && "on" + type;
// Caller can pass in a jQuery.Event object, Object, or just an event type string
event = event[ jQuery.expando ] ?
event :
new jQuery.Event( type, typeof event === "object" && event );
// Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true)
event.isTrigger = onlyHandlers ? 2 : 3;
event.namespace = namespaces.join( "." );
event.rnamespace = event.namespace ?
new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) :
null;
// Clean up the event in case it is being reused
event.result = undefined;
if ( !event.target ) {
event.target = elem;
}
// Clone any incoming data and prepend the event, creating the handler arg list
data = data == null ?
[ event ] :
jQuery.makeArray( data, [ event ] );
// Allow special events to draw outside the lines
special = jQuery.event.special[ type ] || {};
if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) {
return;
}
// Determine event propagation path in advance, per W3C events spec (#9951)
// Bubble up to document, then to window; watch for a global ownerDocument var (#9724)
if ( !onlyHandlers && !special.noBubble && !isWindow( elem ) ) {
bubbleType = special.delegateType || type;
if ( !rfocusMorph.test( bubbleType + type ) ) {
cur = cur.parentNode;
}
for ( ; cur; cur = cur.parentNode ) {
eventPath.push( cur );
tmp = cur;
}
// Only add window if we got to document (e.g., not plain obj or detached DOM)
if ( tmp === ( elem.ownerDocument || document ) ) {
eventPath.push( tmp.defaultView || tmp.parentWindow || window );
}
}
// Fire handlers on the event path
i = 0;
while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) {
lastElement = cur;
event.type = i > 1 ?
bubbleType :
special.bindType || type;
// jQuery handler
handle = ( dataPriv.get( cur, "events" ) || {} )[ event.type ] &&
dataPriv.get( cur, "handle" );
if ( handle ) {
handle.apply( cur, data );
}
// Native handler
handle = ontype && cur[ ontype ];
if ( handle && handle.apply && acceptData( cur ) ) {
event.result = handle.apply( cur, data );
if ( event.result === false ) {
event.preventDefault();
}
}
}
event.type = type;
// If nobody prevented the default action, do it now
if ( !onlyHandlers && !event.isDefaultPrevented() ) {
if ( ( !special._default ||
special._default.apply( eventPath.pop(), data ) === false ) &&
acceptData( elem ) ) {
// Call a native DOM method on the target with the same name as the event.
// Don't do default actions on window, that's where global variables be (#6170)
if ( ontype && isFunction( elem[ type ] ) && !isWindow( elem ) ) {
// Don't re-trigger an onFOO event when we call its FOO() method
tmp = elem[ ontype ];
if ( tmp ) {
elem[ ontype ] = null;
}
// Prevent re-triggering of the same event, since we already bubbled it above
jQuery.event.triggered = type;
if ( event.isPropagationStopped() ) {
lastElement.addEventListener( type, stopPropagationCallback );
}
elem[ type ]();
if ( event.isPropagationStopped() ) {
lastElement.removeEventListener( type, stopPropagationCallback );
}
jQuery.event.triggered = undefined;
if ( tmp ) {
elem[ ontype ] = tmp;
}
}
}
}
return event.result;
},
// Piggyback on a donor event to simulate a different one
// Used only for `focus(in | out)` events
simulate: function( type, elem, event ) {
var e = jQuery.extend(
new jQuery.Event(),
event,
{
type: type,
isSimulated: true
}
);
jQuery.event.trigger( e, null, elem );
}
} );
jQuery.fn.extend( {
trigger: function( type, data ) {
return this.each( function() {
jQuery.event.trigger( type, data, this );
} );
},
triggerHandler: function( type, data ) {
var elem = this[ 0 ];
if ( elem ) {
return jQuery.event.trigger( type, data, elem, true );
}
}
} );
// Support: Firefox <=44
// Firefox doesn't have focus(in | out) events
// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787
//
// Support: Chrome <=48 - 49, Safari <=9.0 - 9.1
// focus(in | out) events fire after focus & blur events,
// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order
// Related ticket - https://bugs.chromium.org/p/chromium/issues/detail?id=449857
if ( !support.focusin ) {
jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) {
// Attach a single capturing handler on the document while someone wants focusin/focusout
var handler = function( event ) {
jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) );
};
jQuery.event.special[ fix ] = {
setup: function() {
var doc = this.ownerDocument || this,
attaches = dataPriv.access( doc, fix );
if ( !attaches ) {
doc.addEventListener( orig, handler, true );
}
dataPriv.access( doc, fix, ( attaches || 0 ) + 1 );
},
teardown: function() {
var doc = this.ownerDocument || this,
attaches = dataPriv.access( doc, fix ) - 1;
if ( !attaches ) {
doc.removeEventListener( orig, handler, true );
dataPriv.remove( doc, fix );
} else {
dataPriv.access( doc, fix, attaches );
}
}
};
} );
}
var location = window.location;
var nonce = Date.now();
var rquery = ( /\?/ );
// Cross-browser xml parsing
jQuery.parseXML = function( data ) {
var xml;
if ( !data || typeof data !== "string" ) {
return null;
}
// Support: IE 9 - 11 only
// IE throws on parseFromString with invalid input.
try {
xml = ( new window.DOMParser() ).parseFromString( data, "text/xml" );
} catch ( e ) {
xml = undefined;
}
if ( !xml || xml.getElementsByTagName( "parsererror" ).length ) {
jQuery.error( "Invalid XML: " + data );
}
return xml;
};
var
rbracket = /\[\]$/,
rCRLF = /\r?\n/g,
rsubmitterTypes = /^(?:submit|button|image|reset|file)$/i,
rsubmittable = /^(?:input|select|textarea|keygen)/i;
function buildParams( prefix, obj, traditional, add ) {
var name;
if ( Array.isArray( obj ) ) {
// Serialize array item.
jQuery.each( obj, function( i, v ) {
if ( traditional || rbracket.test( prefix ) ) {
// Treat each array item as a scalar.
add( prefix, v );
} else {
// Item is non-scalar (array or object), encode its numeric index.
buildParams(
prefix + "[" + ( typeof v === "object" && v != null ? i : "" ) + "]",
v,
traditional,
add
);
}
} );
} else if ( !traditional && toType( obj ) === "object" ) {
// Serialize object item.
for ( name in obj ) {
buildParams( prefix + "[" + name + "]", obj[ name ], traditional, add );
}
} else {
// Serialize scalar item.
add( prefix, obj );
}
}
// Serialize an array of form elements or a set of
// key/values into a query string
jQuery.param = function( a, traditional ) {
var prefix,
s = [],
add = function( key, valueOrFunction ) {
// If value is a function, invoke it and use its return value
var value = isFunction( valueOrFunction ) ?
valueOrFunction() :
valueOrFunction;
s[ s.length ] = encodeURIComponent( key ) + "=" +
encodeURIComponent( value == null ? "" : value );
};
if ( a == null ) {
return "";
}
// If an array was passed in, assume that it is an array of form elements.
if ( Array.isArray( a ) || ( a.jquery && !jQuery.isPlainObject( a ) ) ) {
// Serialize the form elements
jQuery.each( a, function() {
add( this.name, this.value );
} );
} else {
// If traditional, encode the "old" way (the way 1.3.2 or older
// did it), otherwise encode params recursively.
for ( prefix in a ) {
buildParams( prefix, a[ prefix ], traditional, add );
}
}
// Return the resulting serialization
return s.join( "&" );
};
jQuery.fn.extend( {
serialize: function() {
return jQuery.param( this.serializeArray() );
},
serializeArray: function() {
return this.map( function() {
// Can add propHook for "elements" to filter or add form elements
var elements = jQuery.prop( this, "elements" );
return elements ? jQuery.makeArray( elements ) : this;
} )
.filter( function() {
var type = this.type;
// Use .is( ":disabled" ) so that fieldset[disabled] works
return this.name && !jQuery( this ).is( ":disabled" ) &&
rsubmittable.test( this.nodeName ) && !rsubmitterTypes.test( type ) &&
( this.checked || !rcheckableType.test( type ) );
} )
.map( function( i, elem ) {
var val = jQuery( this ).val();
if ( val == null ) {
return null;
}
if ( Array.isArray( val ) ) {
return jQuery.map( val, function( val ) {
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
} );
}
return { name: elem.name, value: val.replace( rCRLF, "\r\n" ) };
} ).get();
}
} );
var
r20 = /%20/g,
rhash = /#.*$/,
rantiCache = /([?&])_=[^&]*/,
rheaders = /^(.*?):[ \t]*([^\r\n]*)$/mg,
// #7653, #8125, #8152: local protocol detection
rlocalProtocol = /^(?:about|app|app-storage|.+-extension|file|res|widget):$/,
rnoContent = /^(?:GET|HEAD)$/,
rprotocol = /^\/\//,
/* Prefilters
* 1) They are useful to introduce custom dataTypes (see ajax/jsonp.js for an example)
* 2) These are called:
* - BEFORE asking for a transport
* - AFTER param serialization (s.data is a string if s.processData is true)
* 3) key is the dataType
* 4) the catchall symbol "*" can be used
* 5) execution will start with transport dataType and THEN continue down to "*" if needed
*/
prefilters = {},
/* Transports bindings
* 1) key is the dataType
* 2) the catchall symbol "*" can be used
* 3) selection will start with transport dataType and THEN go to "*" if needed
*/
transports = {},
// Avoid comment-prolog char sequence (#10098); must appease lint and evade compression
allTypes = "*/".concat( "*" ),
// Anchor tag for parsing the document origin
originAnchor = document.createElement( "a" );
originAnchor.href = location.href;
// Base "constructor" for jQuery.ajaxPrefilter and jQuery.ajaxTransport
function addToPrefiltersOrTransports( structure ) {
// dataTypeExpression is optional and defaults to "*"
return function( dataTypeExpression, func ) {
if ( typeof dataTypeExpression !== "string" ) {
func = dataTypeExpression;
dataTypeExpression = "*";
}
var dataType,
i = 0,
dataTypes = dataTypeExpression.toLowerCase().match( rnothtmlwhite ) || [];
if ( isFunction( func ) ) {
// For each dataType in the dataTypeExpression
while ( ( dataType = dataTypes[ i++ ] ) ) {
// Prepend if requested
if ( dataType[ 0 ] === "+" ) {
dataType = dataType.slice( 1 ) || "*";
( structure[ dataType ] = structure[ dataType ] || [] ).unshift( func );
// Otherwise append
} else {
( structure[ dataType ] = structure[ dataType ] || [] ).push( func );
}
}
}
};
}
// Base inspection function for prefilters and transports
function inspectPrefiltersOrTransports( structure, options, originalOptions, jqXHR ) {
var inspected = {},
seekingTransport = ( structure === transports );
function inspect( dataType ) {
var selected;
inspected[ dataType ] = true;
jQuery.each( structure[ dataType ] || [], function( _, prefilterOrFactory ) {
var dataTypeOrTransport = prefilterOrFactory( options, originalOptions, jqXHR );
if ( typeof dataTypeOrTransport === "string" &&
!seekingTransport && !inspected[ dataTypeOrTransport ] ) {
options.dataTypes.unshift( dataTypeOrTransport );
inspect( dataTypeOrTransport );
return false;
} else if ( seekingTransport ) {
return !( selected = dataTypeOrTransport );
}
} );
return selected;
}
return inspect( options.dataTypes[ 0 ] ) || !inspected[ "*" ] && inspect( "*" );
}
// A special extend for ajax options
// that takes "flat" options (not to be deep extended)
// Fixes #9887
function ajaxExtend( target, src ) {
var key, deep,
flatOptions = jQuery.ajaxSettings.flatOptions || {};
for ( key in src ) {
if ( src[ key ] !== undefined ) {
( flatOptions[ key ] ? target : ( deep || ( deep = {} ) ) )[ key ] = src[ key ];
}
}
if ( deep ) {
jQuery.extend( true, target, deep );
}
return target;
}
/* Handles responses to an ajax request:
* - finds the right dataType (mediates between content-type and expected dataType)
* - returns the corresponding response
*/
function ajaxHandleResponses( s, jqXHR, responses ) {
var ct, type, finalDataType, firstDataType,
contents = s.contents,
dataTypes = s.dataTypes;
// Remove auto dataType and get content-type in the process
while ( dataTypes[ 0 ] === "*" ) {
dataTypes.shift();
if ( ct === undefined ) {
ct = s.mimeType || jqXHR.getResponseHeader( "Content-Type" );
}
}
// Check if we're dealing with a known content-type
if ( ct ) {
for ( type in contents ) {
if ( contents[ type ] && contents[ type ].test( ct ) ) {
dataTypes.unshift( type );
break;
}
}
}
// Check to see if we have a response for the expected dataType
if ( dataTypes[ 0 ] in responses ) {
finalDataType = dataTypes[ 0 ];
} else {
// Try convertible dataTypes
for ( type in responses ) {
if ( !dataTypes[ 0 ] || s.converters[ type + " " + dataTypes[ 0 ] ] ) {
finalDataType = type;
break;
}
if ( !firstDataType ) {
firstDataType = type;
}
}
// Or just use first one
finalDataType = finalDataType || firstDataType;
}
// If we found a dataType
// We add the dataType to the list if needed
// and return the corresponding response
if ( finalDataType ) {
if ( finalDataType !== dataTypes[ 0 ] ) {
dataTypes.unshift( finalDataType );
}
return responses[ finalDataType ];
}
}
/* Chain conversions given the request and the original response
* Also sets the responseXXX fields on the jqXHR instance
*/
function ajaxConvert( s, response, jqXHR, isSuccess ) {
var conv2, current, conv, tmp, prev,
converters = {},
// Work with a copy of dataTypes in case we need to modify it for conversion
dataTypes = s.dataTypes.slice();
// Create converters map with lowercased keys
if ( dataTypes[ 1 ] ) {
for ( conv in s.converters ) {
converters[ conv.toLowerCase() ] = s.converters[ conv ];
}
}
current = dataTypes.shift();
// Convert to each sequential dataType
while ( current ) {
if ( s.responseFields[ current ] ) {
jqXHR[ s.responseFields[ current ] ] = response;
}
// Apply the dataFilter if provided
if ( !prev && isSuccess && s.dataFilter ) {
response = s.dataFilter( response, s.dataType );
}
prev = current;
current = dataTypes.shift();
if ( current ) {
// There's only work to do if current dataType is non-auto
if ( current === "*" ) {
current = prev;
// Convert response if prev dataType is non-auto and differs from current
} else if ( prev !== "*" && prev !== current ) {
// Seek a direct converter
conv = converters[ prev + " " + current ] || converters[ "* " + current ];
// If none found, seek a pair
if ( !conv ) {
for ( conv2 in converters ) {
// If conv2 outputs current
tmp = conv2.split( " " );
if ( tmp[ 1 ] === current ) {
// If prev can be converted to accepted input
conv = converters[ prev + " " + tmp[ 0 ] ] ||
converters[ "* " + tmp[ 0 ] ];
if ( conv ) {
// Condense equivalence converters
if ( conv === true ) {
conv = converters[ conv2 ];
// Otherwise, insert the intermediate dataType
} else if ( converters[ conv2 ] !== true ) {
current = tmp[ 0 ];
dataTypes.unshift( tmp[ 1 ] );
}
break;
}
}
}
}
// Apply converter (if not an equivalence)
if ( conv !== true ) {
// Unless errors are allowed to bubble, catch and return them
if ( conv && s.throws ) {
response = conv( response );
} else {
try {
response = conv( response );
} catch ( e ) {
return {
state: "parsererror",
error: conv ? e : "No conversion from " + prev + " to " + current
};
}
}
}
}
}
}
return { state: "success", data: response };
}
jQuery.extend( {
// Counter for holding the number of active queries
active: 0,
// Last-Modified header cache for next request
lastModified: {},
etag: {},
ajaxSettings: {
url: location.href,
type: "GET",
isLocal: rlocalProtocol.test( location.protocol ),
global: true,
processData: true,
async: true,
contentType: "application/x-www-form-urlencoded; charset=UTF-8",
/*
timeout: 0,
data: null,
dataType: null,
username: null,
password: null,
cache: null,
throws: false,
traditional: false,
headers: {},
*/
accepts: {
"*": allTypes,
text: "text/plain",
html: "text/html",
xml: "application/xml, text/xml",
json: "application/json, text/javascript"
},
contents: {
xml: /\bxml\b/,
html: /\bhtml/,
json: /\bjson\b/
},
responseFields: {
xml: "responseXML",
text: "responseText",
json: "responseJSON"
},
// Data converters
// Keys separate source (or catchall "*") and destination types with a single space
converters: {
// Convert anything to text
"* text": String,
// Text to html (true = no transformation)
"text html": true,
// Evaluate text as a json expression
"text json": JSON.parse,
// Parse text as xml
"text xml": jQuery.parseXML
},
// For options that shouldn't be deep extended:
// you can add your own custom options here if
// and when you create one that shouldn't be
// deep extended (see ajaxExtend)
flatOptions: {
url: true,
context: true
}
},
// Creates a full fledged settings object into target
// with both ajaxSettings and settings fields.
// If target is omitted, writes into ajaxSettings.
ajaxSetup: function( target, settings ) {
return settings ?
// Building a settings object
ajaxExtend( ajaxExtend( target, jQuery.ajaxSettings ), settings ) :
// Extending ajaxSettings
ajaxExtend( jQuery.ajaxSettings, target );
},
ajaxPrefilter: addToPrefiltersOrTransports( prefilters ),
ajaxTransport: addToPrefiltersOrTransports( transports ),
// Main method
ajax: function( url, options ) {
// If url is an object, simulate pre-1.5 signature
if ( typeof url === "object" ) {
options = url;
url = undefined;
}
// Force options to be an object
options = options || {};
var transport,
// URL without anti-cache param
cacheURL,
// Response headers
responseHeadersString,
responseHeaders,
// timeout handle
timeoutTimer,
// Url cleanup var
urlAnchor,
// Request state (becomes false upon send and true upon completion)
completed,
// To know if global events are to be dispatched
fireGlobals,
// Loop variable
i,
// uncached part of the url
uncached,
// Create the final options object
s = jQuery.ajaxSetup( {}, options ),
// Callbacks context
callbackContext = s.context || s,
// Context for global events is callbackContext if it is a DOM node or jQuery collection
globalEventContext = s.context &&
( callbackContext.nodeType || callbackContext.jquery ) ?
jQuery( callbackContext ) :
jQuery.event,
// Deferreds
deferred = jQuery.Deferred(),
completeDeferred = jQuery.Callbacks( "once memory" ),
// Status-dependent callbacks
statusCode = s.statusCode || {},
// Headers (they are sent all at once)
requestHeaders = {},
requestHeadersNames = {},
// Default abort message
strAbort = "canceled",
// Fake xhr
jqXHR = {
readyState: 0,
// Builds headers hashtable if needed
getResponseHeader: function( key ) {
var match;
if ( completed ) {
if ( !responseHeaders ) {
responseHeaders = {};
while ( ( match = rheaders.exec( responseHeadersString ) ) ) {
responseHeaders[ match[ 1 ].toLowerCase() + " " ] =
( responseHeaders[ match[ 1 ].toLowerCase() + " " ] || [] )
.concat( match[ 2 ] );
}
}
match = responseHeaders[ key.toLowerCase() + " " ];
}
return match == null ? null : match.join( ", " );
},
// Raw string
getAllResponseHeaders: function() {
return completed ? responseHeadersString : null;
},
// Caches the header
setRequestHeader: function( name, value ) {
if ( completed == null ) {
name = requestHeadersNames[ name.toLowerCase() ] =
requestHeadersNames[ name.toLowerCase() ] || name;
requestHeaders[ name ] = value;
}
return this;
},
// Overrides response content-type header
overrideMimeType: function( type ) {
if ( completed == null ) {
s.mimeType = type;
}
return this;
},
// Status-dependent callbacks
statusCode: function( map ) {
var code;
if ( map ) {
if ( completed ) {
// Execute the appropriate callbacks
jqXHR.always( map[ jqXHR.status ] );
} else {
// Lazy-add the new callbacks in a way that preserves old ones
for ( code in map ) {
statusCode[ code ] = [ statusCode[ code ], map[ code ] ];
}
}
}
return this;
},
// Cancel the request
abort: function( statusText ) {
var finalText = statusText || strAbort;
if ( transport ) {
transport.abort( finalText );
}
done( 0, finalText );
return this;
}
};
// Attach deferreds
deferred.promise( jqXHR );
// Add protocol if not provided (prefilters might expect it)
// Handle falsy url in the settings object (#10093: consistency with old signature)
// We also use the url parameter if available
s.url = ( ( url || s.url || location.href ) + "" )
.replace( rprotocol, location.protocol + "//" );
// Alias method option to type as per ticket #12004
s.type = options.method || options.type || s.method || s.type;
// Extract dataTypes list
s.dataTypes = ( s.dataType || "*" ).toLowerCase().match( rnothtmlwhite ) || [ "" ];
// A cross-domain request is in order when the origin doesn't match the current origin.
if ( s.crossDomain == null ) {
urlAnchor = document.createElement( "a" );
// Support: IE <=8 - 11, Edge 12 - 15
// IE throws exception on accessing the href property if url is malformed,
// e.g. http://example.com:80x/
try {
urlAnchor.href = s.url;
// Support: IE <=8 - 11 only
// Anchor's host property isn't correctly set when s.url is relative
urlAnchor.href = urlAnchor.href;
s.crossDomain = originAnchor.protocol + "//" + originAnchor.host !==
urlAnchor.protocol + "//" + urlAnchor.host;
} catch ( e ) {
// If there is an error parsing the URL, assume it is crossDomain,
// it can be rejected by the transport if it is invalid
s.crossDomain = true;
}
}
// Convert data if not already a string
if ( s.data && s.processData && typeof s.data !== "string" ) {
s.data = jQuery.param( s.data, s.traditional );
}
// Apply prefilters
inspectPrefiltersOrTransports( prefilters, s, options, jqXHR );
// If request was aborted inside a prefilter, stop there
if ( completed ) {
return jqXHR;
}
// We can fire global events as of now if asked to
// Don't fire events if jQuery.event is undefined in an AMD-usage scenario (#15118)
fireGlobals = jQuery.event && s.global;
// Watch for a new set of requests
if ( fireGlobals && jQuery.active++ === 0 ) {
jQuery.event.trigger( "ajaxStart" );
}
// Uppercase the type
s.type = s.type.toUpperCase();
// Determine if request has content
s.hasContent = !rnoContent.test( s.type );
// Save the URL in case we're toying with the If-Modified-Since
// and/or If-None-Match header later on
// Remove hash to simplify url manipulation
cacheURL = s.url.replace( rhash, "" );
// More options handling for requests with no content
if ( !s.hasContent ) {
// Remember the hash so we can put it back
uncached = s.url.slice( cacheURL.length );
// If data is available and should be processed, append data to url
if ( s.data && ( s.processData || typeof s.data === "string" ) ) {
cacheURL += ( rquery.test( cacheURL ) ? "&" : "?" ) + s.data;
// #9682: remove data so that it's not used in an eventual retry
delete s.data;
}
// Add or update anti-cache param if needed
if ( s.cache === false ) {
cacheURL = cacheURL.replace( rantiCache, "$1" );
uncached = ( rquery.test( cacheURL ) ? "&" : "?" ) + "_=" + ( nonce++ ) + uncached;
}
// Put hash and anti-cache on the URL that will be requested (gh-1732)
s.url = cacheURL + uncached;
// Change '%20' to '+' if this is encoded form body content (gh-2658)
} else if ( s.data && s.processData &&
( s.contentType || "" ).indexOf( "application/x-www-form-urlencoded" ) === 0 ) {
s.data = s.data.replace( r20, "+" );
}
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
if ( jQuery.lastModified[ cacheURL ] ) {
jqXHR.setRequestHeader( "If-Modified-Since", jQuery.lastModified[ cacheURL ] );
}
if ( jQuery.etag[ cacheURL ] ) {
jqXHR.setRequestHeader( "If-None-Match", jQuery.etag[ cacheURL ] );
}
}
// Set the correct header, if data is being sent
if ( s.data && s.hasContent && s.contentType !== false || options.contentType ) {
jqXHR.setRequestHeader( "Content-Type", s.contentType );
}
// Set the Accepts header for the server, depending on the dataType
jqXHR.setRequestHeader(
"Accept",
s.dataTypes[ 0 ] && s.accepts[ s.dataTypes[ 0 ] ] ?
s.accepts[ s.dataTypes[ 0 ] ] +
( s.dataTypes[ 0 ] !== "*" ? ", " + allTypes + "; q=0.01" : "" ) :
s.accepts[ "*" ]
);
// Check for headers option
for ( i in s.headers ) {
jqXHR.setRequestHeader( i, s.headers[ i ] );
}
// Allow custom headers/mimetypes and early abort
if ( s.beforeSend &&
( s.beforeSend.call( callbackContext, jqXHR, s ) === false || completed ) ) {
// Abort if not done already and return
return jqXHR.abort();
}
// Aborting is no longer a cancellation
strAbort = "abort";
// Install callbacks on deferreds
completeDeferred.add( s.complete );
jqXHR.done( s.success );
jqXHR.fail( s.error );
// Get transport
transport = inspectPrefiltersOrTransports( transports, s, options, jqXHR );
// If no transport, we auto-abort
if ( !transport ) {
done( -1, "No Transport" );
} else {
jqXHR.readyState = 1;
// Send global event
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxSend", [ jqXHR, s ] );
}
// If request was aborted inside ajaxSend, stop there
if ( completed ) {
return jqXHR;
}
// Timeout
if ( s.async && s.timeout > 0 ) {
timeoutTimer = window.setTimeout( function() {
jqXHR.abort( "timeout" );
}, s.timeout );
}
try {
completed = false;
transport.send( requestHeaders, done );
} catch ( e ) {
// Rethrow post-completion exceptions
if ( completed ) {
throw e;
}
// Propagate others as results
done( -1, e );
}
}
// Callback for when everything is done
function done( status, nativeStatusText, responses, headers ) {
var isSuccess, success, error, response, modified,
statusText = nativeStatusText;
// Ignore repeat invocations
if ( completed ) {
return;
}
completed = true;
// Clear timeout if it exists
if ( timeoutTimer ) {
window.clearTimeout( timeoutTimer );
}
// Dereference transport for early garbage collection
// (no matter how long the jqXHR object will be used)
transport = undefined;
// Cache response headers
responseHeadersString = headers || "";
// Set readyState
jqXHR.readyState = status > 0 ? 4 : 0;
// Determine if successful
isSuccess = status >= 200 && status < 300 || status === 304;
// Get response data
if ( responses ) {
response = ajaxHandleResponses( s, jqXHR, responses );
}
// Convert no matter what (that way responseXXX fields are always set)
response = ajaxConvert( s, response, jqXHR, isSuccess );
// If successful, handle type chaining
if ( isSuccess ) {
// Set the If-Modified-Since and/or If-None-Match header, if in ifModified mode.
if ( s.ifModified ) {
modified = jqXHR.getResponseHeader( "Last-Modified" );
if ( modified ) {
jQuery.lastModified[ cacheURL ] = modified;
}
modified = jqXHR.getResponseHeader( "etag" );
if ( modified ) {
jQuery.etag[ cacheURL ] = modified;
}
}
// if no content
if ( status === 204 || s.type === "HEAD" ) {
statusText = "nocontent";
// if not modified
} else if ( status === 304 ) {
statusText = "notmodified";
// If we have data, let's convert it
} else {
statusText = response.state;
success = response.data;
error = response.error;
isSuccess = !error;
}
} else {
// Extract error from statusText and normalize for non-aborts
error = statusText;
if ( status || !statusText ) {
statusText = "error";
if ( status < 0 ) {
status = 0;
}
}
}
// Set data for the fake xhr object
jqXHR.status = status;
jqXHR.statusText = ( nativeStatusText || statusText ) + "";
// Success/Error
if ( isSuccess ) {
deferred.resolveWith( callbackContext, [ success, statusText, jqXHR ] );
} else {
deferred.rejectWith( callbackContext, [ jqXHR, statusText, error ] );
}
// Status-dependent callbacks
jqXHR.statusCode( statusCode );
statusCode = undefined;
if ( fireGlobals ) {
globalEventContext.trigger( isSuccess ? "ajaxSuccess" : "ajaxError",
[ jqXHR, s, isSuccess ? success : error ] );
}
// Complete
completeDeferred.fireWith( callbackContext, [ jqXHR, statusText ] );
if ( fireGlobals ) {
globalEventContext.trigger( "ajaxComplete", [ jqXHR, s ] );
// Handle the global AJAX counter
if ( !( --jQuery.active ) ) {
jQuery.event.trigger( "ajaxStop" );
}
}
}
return jqXHR;
},
getJSON: function( url, data, callback ) {
return jQuery.get( url, data, callback, "json" );
},
getScript: function( url, callback ) {
return jQuery.get( url, undefined, callback, "script" );
}
} );
jQuery.each( [ "get", "post" ], function( i, method ) {
jQuery[ method ] = function( url, data, callback, type ) {
// Shift arguments if data argument was omitted
if ( isFunction( data ) ) {
type = type || callback;
callback = data;
data = undefined;
}
// The url can be an options object (which then must have .url)
return jQuery.ajax( jQuery.extend( {
url: url,
type: method,
dataType: type,
data: data,
success: callback
}, jQuery.isPlainObject( url ) && url ) );
};
} );
jQuery._evalUrl = function( url, options ) {
return jQuery.ajax( {
url: url,
// Make this explicit, since user can override this through ajaxSetup (#11264)
type: "GET",
dataType: "script",
cache: true,
async: false,
global: false,
// Only evaluate the response if it is successful (gh-4126)
// dataFilter is not invoked for failure responses, so using it instead
// of the default converter is kludgy but it works.
converters: {
"text script": function() {}
},
dataFilter: function( response ) {
jQuery.globalEval( response, options );
}
} );
};
jQuery.fn.extend( {
wrapAll: function( html ) {
var wrap;
if ( this[ 0 ] ) {
if ( isFunction( html ) ) {
html = html.call( this[ 0 ] );
}
// The elements to wrap the target around
wrap = jQuery( html, this[ 0 ].ownerDocument ).eq( 0 ).clone( true );
if ( this[ 0 ].parentNode ) {
wrap.insertBefore( this[ 0 ] );
}
wrap.map( function() {
var elem = this;
while ( elem.firstElementChild ) {
elem = elem.firstElementChild;
}
return elem;
} ).append( this );
}
return this;
},
wrapInner: function( html ) {
if ( isFunction( html ) ) {
return this.each( function( i ) {
jQuery( this ).wrapInner( html.call( this, i ) );
} );
}
return this.each( function() {
var self = jQuery( this ),
contents = self.contents();
if ( contents.length ) {
contents.wrapAll( html );
} else {
self.append( html );
}
} );
},
wrap: function( html ) {
var htmlIsFunction = isFunction( html );
return this.each( function( i ) {
jQuery( this ).wrapAll( htmlIsFunction ? html.call( this, i ) : html );
} );
},
unwrap: function( selector ) {
this.parent( selector ).not( "body" ).each( function() {
jQuery( this ).replaceWith( this.childNodes );
} );
return this;
}
} );
jQuery.expr.pseudos.hidden = function( elem ) {
return !jQuery.expr.pseudos.visible( elem );
};
jQuery.expr.pseudos.visible = function( elem ) {
return !!( elem.offsetWidth || elem.offsetHeight || elem.getClientRects().length );
};
jQuery.ajaxSettings.xhr = function() {
try {
return new window.XMLHttpRequest();
} catch ( e ) {}
};
var xhrSuccessStatus = {
// File protocol always yields status code 0, assume 200
0: 200,
// Support: IE <=9 only
// #1450: sometimes IE returns 1223 when it should be 204
1223: 204
},
xhrSupported = jQuery.ajaxSettings.xhr();
support.cors = !!xhrSupported && ( "withCredentials" in xhrSupported );
support.ajax = xhrSupported = !!xhrSupported;
jQuery.ajaxTransport( function( options ) {
var callback, errorCallback;
// Cross domain only allowed if supported through XMLHttpRequest
if ( support.cors || xhrSupported && !options.crossDomain ) {
return {
send: function( headers, complete ) {
var i,
xhr = options.xhr();
xhr.open(
options.type,
options.url,
options.async,
options.username,
options.password
);
// Apply custom fields if provided
if ( options.xhrFields ) {
for ( i in options.xhrFields ) {
xhr[ i ] = options.xhrFields[ i ];
}
}
// Override mime type if needed
if ( options.mimeType && xhr.overrideMimeType ) {
xhr.overrideMimeType( options.mimeType );
}
// X-Requested-With header
// For cross-domain requests, seeing as conditions for a preflight are
// akin to a jigsaw puzzle, we simply never set it to be sure.
// (it can always be set on a per-request basis or even using ajaxSetup)
// For same-domain requests, won't change header if already provided.
if ( !options.crossDomain && !headers[ "X-Requested-With" ] ) {
headers[ "X-Requested-With" ] = "XMLHttpRequest";
}
// Set headers
for ( i in headers ) {
xhr.setRequestHeader( i, headers[ i ] );
}
// Callback
callback = function( type ) {
return function() {
if ( callback ) {
callback = errorCallback = xhr.onload =
xhr.onerror = xhr.onabort = xhr.ontimeout =
xhr.onreadystatechange = null;
if ( type === "abort" ) {
xhr.abort();
} else if ( type === "error" ) {
// Support: IE <=9 only
// On a manual native abort, IE9 throws
// errors on any property access that is not readyState
if ( typeof xhr.status !== "number" ) {
complete( 0, "error" );
} else {
complete(
// File: protocol always yields status 0; see #8605, #14207
xhr.status,
xhr.statusText
);
}
} else {
complete(
xhrSuccessStatus[ xhr.status ] || xhr.status,
xhr.statusText,
// Support: IE <=9 only
// IE9 has no XHR2 but throws on binary (trac-11426)
// For XHR2 non-text, let the caller handle it (gh-2498)
( xhr.responseType || "text" ) !== "text" ||
typeof xhr.responseText !== "string" ?
{ binary: xhr.response } :
{ text: xhr.responseText },
xhr.getAllResponseHeaders()
);
}
}
};
};
// Listen to events
xhr.onload = callback();
errorCallback = xhr.onerror = xhr.ontimeout = callback( "error" );
// Support: IE 9 only
// Use onreadystatechange to replace onabort
// to handle uncaught aborts
if ( xhr.onabort !== undefined ) {
xhr.onabort = errorCallback;
} else {
xhr.onreadystatechange = function() {
// Check readyState before timeout as it changes
if ( xhr.readyState === 4 ) {
// Allow onerror to be called first,
// but that will not handle a native abort
// Also, save errorCallback to a variable
// as xhr.onerror cannot be accessed
window.setTimeout( function() {
if ( callback ) {
errorCallback();
}
} );
}
};
}
// Create the abort callback
callback = callback( "abort" );
try {
// Do send the request (this may raise an exception)
xhr.send( options.hasContent && options.data || null );
} catch ( e ) {
// #14683: Only rethrow if this hasn't been notified as an error yet
if ( callback ) {
throw e;
}
}
},
abort: function() {
if ( callback ) {
callback();
}
}
};
}
} );
// Prevent auto-execution of scripts when no explicit dataType was provided (See gh-2432)
jQuery.ajaxPrefilter( function( s ) {
if ( s.crossDomain ) {
s.contents.script = false;
}
} );
// Install script dataType
jQuery.ajaxSetup( {
accepts: {
script: "text/javascript, application/javascript, " +
"application/ecmascript, application/x-ecmascript"
},
contents: {
script: /\b(?:java|ecma)script\b/
},
converters: {
"text script": function( text ) {
jQuery.globalEval( text );
return text;
}
}
} );
// Handle cache's special case and crossDomain
jQuery.ajaxPrefilter( "script", function( s ) {
if ( s.cache === undefined ) {
s.cache = false;
}
if ( s.crossDomain ) {
s.type = "GET";
}
} );
// Bind script tag hack transport
jQuery.ajaxTransport( "script", function( s ) {
// This transport only deals with cross domain or forced-by-attrs requests
if ( s.crossDomain || s.scriptAttrs ) {
var script, callback;
return {
send: function( _, complete ) {
script = jQuery( "<script>" )
.attr( s.scriptAttrs || {} )
.prop( { charset: s.scriptCharset, src: s.url } )
.on( "load error", callback = function( evt ) {
script.remove();
callback = null;
if ( evt ) {
complete( evt.type === "error" ? 404 : 200, evt.type );
}
} );
// Use native DOM manipulation to avoid our domManip AJAX trickery
document.head.appendChild( script[ 0 ] );
},
abort: function() {
if ( callback ) {
callback();
}
}
};
}
} );
var oldCallbacks = [],
rjsonp = /(=)\?(?=&|$)|\?\?/;
// Default jsonp settings
jQuery.ajaxSetup( {
jsonp: "callback",
jsonpCallback: function() {
var callback = oldCallbacks.pop() || ( jQuery.expando + "_" + ( nonce++ ) );
this[ callback ] = true;
return callback;
}
} );
// Detect, normalize options and install callbacks for jsonp requests
jQuery.ajaxPrefilter( "json jsonp", function( s, originalSettings, jqXHR ) {
var callbackName, overwritten, responseContainer,
jsonProp = s.jsonp !== false && ( rjsonp.test( s.url ) ?
"url" :
typeof s.data === "string" &&
( s.contentType || "" )
.indexOf( "application/x-www-form-urlencoded" ) === 0 &&
rjsonp.test( s.data ) && "data"
);
// Handle iff the expected data type is "jsonp" or we have a parameter to set
if ( jsonProp || s.dataTypes[ 0 ] === "jsonp" ) {
// Get callback name, remembering preexisting value associated with it
callbackName = s.jsonpCallback = isFunction( s.jsonpCallback ) ?
s.jsonpCallback() :
s.jsonpCallback;
// Insert callback into url or form data
if ( jsonProp ) {
s[ jsonProp ] = s[ jsonProp ].replace( rjsonp, "$1" + callbackName );
} else if ( s.jsonp !== false ) {
s.url += ( rquery.test( s.url ) ? "&" : "?" ) + s.jsonp + "=" + callbackName;
}
// Use data converter to retrieve json after script execution
s.converters[ "script json" ] = function() {
if ( !responseContainer ) {
jQuery.error( callbackName + " was not called" );
}
return responseContainer[ 0 ];
};
// Force json dataType
s.dataTypes[ 0 ] = "json";
// Install callback
overwritten = window[ callbackName ];
window[ callbackName ] = function() {
responseContainer = arguments;
};
// Clean-up function (fires after converters)
jqXHR.always( function() {
// If previous value didn't exist - remove it
if ( overwritten === undefined ) {
jQuery( window ).removeProp( callbackName );
// Otherwise restore preexisting value
} else {
window[ callbackName ] = overwritten;
}
// Save back as free
if ( s[ callbackName ] ) {
// Make sure that re-using the options doesn't screw things around
s.jsonpCallback = originalSettings.jsonpCallback;
// Save the callback name for future use
oldCallbacks.push( callbackName );
}
// Call if it was a function and we have a response
if ( responseContainer && isFunction( overwritten ) ) {
overwritten( responseContainer[ 0 ] );
}
responseContainer = overwritten = undefined;
} );
// Delegate to script
return "script";
}
} );
// Support: Safari 8 only
// In Safari 8 documents created via document.implementation.createHTMLDocument
// collapse sibling forms: the second one becomes a child of the first one.
// Because of that, this security measure has to be disabled in Safari 8.
// https://bugs.webkit.org/show_bug.cgi?id=137337
support.createHTMLDocument = ( function() {
var body = document.implementation.createHTMLDocument( "" ).body;
body.innerHTML = "<form></form><form></form>";
return body.childNodes.length === 2;
} )();
// Argument "data" should be string of html
// context (optional): If specified, the fragment will be created in this context,
// defaults to document
// keepScripts (optional): If true, will include scripts passed in the html string
jQuery.parseHTML = function( data, context, keepScripts ) {
if ( typeof data !== "string" ) {
return [];
}
if ( typeof context === "boolean" ) {
keepScripts = context;
context = false;
}
var base, parsed, scripts;
if ( !context ) {
// Stop scripts or inline event handlers from being executed immediately
// by using document.implementation
if ( support.createHTMLDocument ) {
context = document.implementation.createHTMLDocument( "" );
// Set the base href for the created document
// so any parsed elements with URLs
// are based on the document's URL (gh-2965)
base = context.createElement( "base" );
base.href = document.location.href;
context.head.appendChild( base );
} else {
context = document;
}
}
parsed = rsingleTag.exec( data );
scripts = !keepScripts && [];
// Single tag
if ( parsed ) {
return [ context.createElement( parsed[ 1 ] ) ];
}
parsed = buildFragment( [ data ], context, scripts );
if ( scripts && scripts.length ) {
jQuery( scripts ).remove();
}
return jQuery.merge( [], parsed.childNodes );
};
/**
* Load a url into a page
*/
jQuery.fn.load = function( url, params, callback ) {
var selector, type, response,
self = this,
off = url.indexOf( " " );
if ( off > -1 ) {
selector = stripAndCollapse( url.slice( off ) );
url = url.slice( 0, off );
}
// If it's a function
if ( isFunction( params ) ) {
// We assume that it's the callback
callback = params;
params = undefined;
// Otherwise, build a param string
} else if ( params && typeof params === "object" ) {
type = "POST";
}
// If we have elements to modify, make the request
if ( self.length > 0 ) {
jQuery.ajax( {
url: url,
// If "type" variable is undefined, then "GET" method will be used.
// Make value of this field explicit since
// user can override it through ajaxSetup method
type: type || "GET",
dataType: "html",
data: params
} ).done( function( responseText ) {
// Save response for use in complete callback
response = arguments;
self.html( selector ?
// If a selector was specified, locate the right elements in a dummy div
// Exclude scripts to avoid IE 'Permission Denied' errors
jQuery( "<div>" ).append( jQuery.parseHTML( responseText ) ).find( selector ) :
// Otherwise use the full result
responseText );
// If the request succeeds, this function gets "data", "status", "jqXHR"
// but they are ignored because response was set above.
// If it fails, this function gets "jqXHR", "status", "error"
} ).always( callback && function( jqXHR, status ) {
self.each( function() {
callback.apply( this, response || [ jqXHR.responseText, status, jqXHR ] );
} );
} );
}
return this;
};
// Attach a bunch of functions for handling common AJAX events
jQuery.each( [
"ajaxStart",
"ajaxStop",
"ajaxComplete",
"ajaxError",
"ajaxSuccess",
"ajaxSend"
], function( i, type ) {
jQuery.fn[ type ] = function( fn ) {
return this.on( type, fn );
};
} );
jQuery.expr.pseudos.animated = function( elem ) {
return jQuery.grep( jQuery.timers, function( fn ) {
return elem === fn.elem;
} ).length;
};
jQuery.offset = {
setOffset: function( elem, options, i ) {
var curPosition, curLeft, curCSSTop, curTop, curOffset, curCSSLeft, calculatePosition,
position = jQuery.css( elem, "position" ),
curElem = jQuery( elem ),
props = {};
// Set position first, in-case top/left are set even on static elem
if ( position === "static" ) {
elem.style.position = "relative";
}
curOffset = curElem.offset();
curCSSTop = jQuery.css( elem, "top" );
curCSSLeft = jQuery.css( elem, "left" );
calculatePosition = ( position === "absolute" || position === "fixed" ) &&
( curCSSTop + curCSSLeft ).indexOf( "auto" ) > -1;
// Need to be able to calculate position if either
// top or left is auto and position is either absolute or fixed
if ( calculatePosition ) {
curPosition = curElem.position();
curTop = curPosition.top;
curLeft = curPosition.left;
} else {
curTop = parseFloat( curCSSTop ) || 0;
curLeft = parseFloat( curCSSLeft ) || 0;
}
if ( isFunction( options ) ) {
// Use jQuery.extend here to allow modification of coordinates argument (gh-1848)
options = options.call( elem, i, jQuery.extend( {}, curOffset ) );
}
if ( options.top != null ) {
props.top = ( options.top - curOffset.top ) + curTop;
}
if ( options.left != null ) {
props.left = ( options.left - curOffset.left ) + curLeft;
}
if ( "using" in options ) {
options.using.call( elem, props );
} else {
curElem.css( props );
}
}
};
jQuery.fn.extend( {
// offset() relates an element's border box to the document origin
offset: function( options ) {
// Preserve chaining for setter
if ( arguments.length ) {
return options === undefined ?
this :
this.each( function( i ) {
jQuery.offset.setOffset( this, options, i );
} );
}
var rect, win,
elem = this[ 0 ];
if ( !elem ) {
return;
}
// Return zeros for disconnected and hidden (display: none) elements (gh-2310)
// Support: IE <=11 only
// Running getBoundingClientRect on a
// disconnected node in IE throws an error
if ( !elem.getClientRects().length ) {
return { top: 0, left: 0 };
}
// Get document-relative position by adding viewport scroll to viewport-relative gBCR
rect = elem.getBoundingClientRect();
win = elem.ownerDocument.defaultView;
return {
top: rect.top + win.pageYOffset,
left: rect.left + win.pageXOffset
};
},
// position() relates an element's margin box to its offset parent's padding box
// This corresponds to the behavior of CSS absolute positioning
position: function() {
if ( !this[ 0 ] ) {
return;
}
var offsetParent, offset, doc,
elem = this[ 0 ],
parentOffset = { top: 0, left: 0 };
// position:fixed elements are offset from the viewport, which itself always has zero offset
if ( jQuery.css( elem, "position" ) === "fixed" ) {
// Assume position:fixed implies availability of getBoundingClientRect
offset = elem.getBoundingClientRect();
} else {
offset = this.offset();
// Account for the *real* offset parent, which can be the document or its root element
// when a statically positioned element is identified
doc = elem.ownerDocument;
offsetParent = elem.offsetParent || doc.documentElement;
while ( offsetParent &&
( offsetParent === doc.body || offsetParent === doc.documentElement ) &&
jQuery.css( offsetParent, "position" ) === "static" ) {
offsetParent = offsetParent.parentNode;
}
if ( offsetParent && offsetParent !== elem && offsetParent.nodeType === 1 ) {
// Incorporate borders into its offset, since they are outside its content origin
parentOffset = jQuery( offsetParent ).offset();
parentOffset.top += jQuery.css( offsetParent, "borderTopWidth", true );
parentOffset.left += jQuery.css( offsetParent, "borderLeftWidth", true );
}
}
// Subtract parent offsets and element margins
return {
top: offset.top - parentOffset.top - jQuery.css( elem, "marginTop", true ),
left: offset.left - parentOffset.left - jQuery.css( elem, "marginLeft", true )
};
},
// This method will return documentElement in the following cases:
// 1) For the element inside the iframe without offsetParent, this method will return
// documentElement of the parent window
// 2) For the hidden or detached element
// 3) For body or html element, i.e. in case of the html node - it will return itself
//
// but those exceptions were never presented as a real life use-cases
// and might be considered as more preferable results.
//
// This logic, however, is not guaranteed and can change at any point in the future
offsetParent: function() {
return this.map( function() {
var offsetParent = this.offsetParent;
while ( offsetParent && jQuery.css( offsetParent, "position" ) === "static" ) {
offsetParent = offsetParent.offsetParent;
}
return offsetParent || documentElement;
} );
}
} );
// Create scrollLeft and scrollTop methods
jQuery.each( { scrollLeft: "pageXOffset", scrollTop: "pageYOffset" }, function( method, prop ) {
var top = "pageYOffset" === prop;
jQuery.fn[ method ] = function( val ) {
return access( this, function( elem, method, val ) {
// Coalesce documents and windows
var win;
if ( isWindow( elem ) ) {
win = elem;
} else if ( elem.nodeType === 9 ) {
win = elem.defaultView;
}
if ( val === undefined ) {
return win ? win[ prop ] : elem[ method ];
}
if ( win ) {
win.scrollTo(
!top ? val : win.pageXOffset,
top ? val : win.pageYOffset
);
} else {
elem[ method ] = val;
}
}, method, val, arguments.length );
};
} );
// Support: Safari <=7 - 9.1, Chrome <=37 - 49
// Add the top/left cssHooks using jQuery.fn.position
// Webkit bug: https://bugs.webkit.org/show_bug.cgi?id=29084
// Blink bug: https://bugs.chromium.org/p/chromium/issues/detail?id=589347
// getComputedStyle returns percent when specified for top/left/bottom/right;
// rather than make the css module depend on the offset module, just check for it here
jQuery.each( [ "top", "left" ], function( i, prop ) {
jQuery.cssHooks[ prop ] = addGetHookIf( support.pixelPosition,
function( elem, computed ) {
if ( computed ) {
computed = curCSS( elem, prop );
// If curCSS returns percentage, fallback to offset
return rnumnonpx.test( computed ) ?
jQuery( elem ).position()[ prop ] + "px" :
computed;
}
}
);
} );
// Create innerHeight, innerWidth, height, width, outerHeight and outerWidth methods
jQuery.each( { Height: "height", Width: "width" }, function( name, type ) {
jQuery.each( { padding: "inner" + name, content: type, "": "outer" + name },
function( defaultExtra, funcName ) {
// Margin is only for outerHeight, outerWidth
jQuery.fn[ funcName ] = function( margin, value ) {
var chainable = arguments.length && ( defaultExtra || typeof margin !== "boolean" ),
extra = defaultExtra || ( margin === true || value === true ? "margin" : "border" );
return access( this, function( elem, type, value ) {
var doc;
if ( isWindow( elem ) ) {
// $( window ).outerWidth/Height return w/h including scrollbars (gh-1729)
return funcName.indexOf( "outer" ) === 0 ?
elem[ "inner" + name ] :
elem.document.documentElement[ "client" + name ];
}
// Get document width or height
if ( elem.nodeType === 9 ) {
doc = elem.documentElement;
// Either scroll[Width/Height] or offset[Width/Height] or client[Width/Height],
// whichever is greatest
return Math.max(
elem.body[ "scroll" + name ], doc[ "scroll" + name ],
elem.body[ "offset" + name ], doc[ "offset" + name ],
doc[ "client" + name ]
);
}
return value === undefined ?
// Get width or height on the element, requesting but not forcing parseFloat
jQuery.css( elem, type, extra ) :
// Set width or height on the element
jQuery.style( elem, type, value, extra );
}, type, chainable ? margin : undefined, chainable );
};
} );
} );
jQuery.each( ( "blur focus focusin focusout resize scroll click dblclick " +
"mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave " +
"change select submit keydown keypress keyup contextmenu" ).split( " " ),
function( i, name ) {
// Handle event binding
jQuery.fn[ name ] = function( data, fn ) {
return arguments.length > 0 ?
this.on( name, null, data, fn ) :
this.trigger( name );
};
} );
jQuery.fn.extend( {
hover: function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
}
} );
jQuery.fn.extend( {
bind: function( types, data, fn ) {
return this.on( types, null, data, fn );
},
unbind: function( types, fn ) {
return this.off( types, null, fn );
},
delegate: function( selector, types, data, fn ) {
return this.on( types, selector, data, fn );
},
undelegate: function( selector, types, fn ) {
// ( namespace ) or ( selector, types [, fn] )
return arguments.length === 1 ?
this.off( selector, "**" ) :
this.off( types, selector || "**", fn );
}
} );
// Bind a function to a context, optionally partially applying any
// arguments.
// jQuery.proxy is deprecated to promote standards (specifically Function#bind)
// However, it is not slated for removal any time soon
jQuery.proxy = function( fn, context ) {
var tmp, args, proxy;
if ( typeof context === "string" ) {
tmp = fn[ context ];
context = fn;
fn = tmp;
}
// Quick check to determine if target is callable, in the spec
// this throws a TypeError, but we will just return undefined.
if ( !isFunction( fn ) ) {
return undefined;
}
// Simulated bind
args = slice.call( arguments, 2 );
proxy = function() {
return fn.apply( context || this, args.concat( slice.call( arguments ) ) );
};
// Set the guid of unique handler to the same of original handler, so it can be removed
proxy.guid = fn.guid = fn.guid || jQuery.guid++;
return proxy;
};
jQuery.holdReady = function( hold ) {
if ( hold ) {
jQuery.readyWait++;
} else {
jQuery.ready( true );
}
};
jQuery.isArray = Array.isArray;
jQuery.parseJSON = JSON.parse;
jQuery.nodeName = nodeName;
jQuery.isFunction = isFunction;
jQuery.isWindow = isWindow;
jQuery.camelCase = camelCase;
jQuery.type = toType;
jQuery.now = Date.now;
jQuery.isNumeric = function( obj ) {
// As of jQuery 3.0, isNumeric is limited to
// strings and numbers (primitives or objects)
// that can be coerced to finite numbers (gh-2662)
var type = jQuery.type( obj );
return ( type === "number" || type === "string" ) &&
// parseFloat NaNs numeric-cast false positives ("")
// ...but misinterprets leading-number strings, particularly hex literals ("0x...")
// subtraction forces infinities to NaN
!isNaN( obj - parseFloat( obj ) );
};
// Register as a named AMD module, since jQuery can be concatenated with other
// files that may use define, but not via a proper concatenation script that
// understands anonymous AMD modules. A named AMD is safest and most robust
// way to register. Lowercase jquery is used because AMD module names are
// derived from file names, and jQuery is normally delivered in a lowercase
// file name. Do this after creating the global so that if an AMD module wants
// to call noConflict to hide this version of jQuery, it will work.
// Note that for maximum portability, libraries that are not jQuery should
// declare themselves as anonymous modules, and avoid setting a global if an
// AMD loader is present. jQuery is a special case. For more information, see
// https://github.com/jrburke/requirejs/wiki/Updating-existing-libraries#wiki-anon
if ( typeof define === "function" && define.amd ) {
define( "jquery", [], function() {
return jQuery;
} );
}
var
// Map over jQuery in case of overwrite
_jQuery = window.jQuery,
// Map over the $ in case of overwrite
_$ = window.$;
jQuery.noConflict = function( deep ) {
if ( window.$ === jQuery ) {
window.$ = _$;
}
if ( deep && window.jQuery === jQuery ) {
window.jQuery = _jQuery;
}
return jQuery;
};
// Expose jQuery and $ identifiers, even in AMD
// (#7102#comment:10, https://github.com/jquery/jquery/pull/557)
// and CommonJS for browser emulators (#13566)
if ( !noGlobal ) {
window.jQuery = window.$ = jQuery;
}
return jQuery;
} );
/*! jQuery UI - v1.12.1 - 2016-09-14
* http://jqueryui.com
* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-1-7.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js
* Copyright jQuery Foundation and other contributors; Licensed MIT */
(function( factory ) {
if ( typeof define === "function" && define.amd ) {
// AMD. Register as an anonymous module.
define([ "jquery" ], factory );
} else {
// Browser globals
factory( jQuery );
}
}(function( $ ) {
$.ui = $.ui || {};
var version = $.ui.version = "1.12.1";
/*!
* jQuery UI Widget 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Widget
//>>group: Core
//>>description: Provides a factory for creating stateful widgets with a common API.
//>>docs: http://api.jqueryui.com/jQuery.widget/
//>>demos: http://jqueryui.com/widget/
var widgetUuid = 0;
var widgetSlice = Array.prototype.slice;
$.cleanData = ( function( orig ) {
return function( elems ) {
var events, elem, i;
for ( i = 0; ( elem = elems[ i ] ) != null; i++ ) {
try {
// Only trigger remove when necessary to save time
events = $._data( elem, "events" );
if ( events && events.remove ) {
$( elem ).triggerHandler( "remove" );
}
// Http://bugs.jquery.com/ticket/8235
} catch ( e ) {}
}
orig( elems );
};
} )( $.cleanData );
$.widget = function( name, base, prototype ) {
var existingConstructor, constructor, basePrototype;
// ProxiedPrototype allows the provided prototype to remain unmodified
// so that it can be used as a mixin for multiple widgets (#8876)
var proxiedPrototype = {};
var namespace = name.split( "." )[ 0 ];
name = name.split( "." )[ 1 ];
var fullName = namespace + "-" + name;
if ( !prototype ) {
prototype = base;
base = $.Widget;
}
if ( $.isArray( prototype ) ) {
prototype = $.extend.apply( null, [ {} ].concat( prototype ) );
}
// Create selector for plugin
$.expr[ ":" ][ fullName.toLowerCase() ] = function( elem ) {
return !!$.data( elem, fullName );
};
$[ namespace ] = $[ namespace ] || {};
existingConstructor = $[ namespace ][ name ];
constructor = $[ namespace ][ name ] = function( options, element ) {
// Allow instantiation without "new" keyword
if ( !this._createWidget ) {
return new constructor( options, element );
}
// Allow instantiation without initializing for simple inheritance
// must use "new" keyword (the code above always passes args)
if ( arguments.length ) {
this._createWidget( options, element );
}
};
// Extend with the existing constructor to carry over any static properties
$.extend( constructor, existingConstructor, {
version: prototype.version,
// Copy the object used to create the prototype in case we need to
// redefine the widget later
_proto: $.extend( {}, prototype ),
// Track widgets that inherit from this widget in case this widget is
// redefined after a widget inherits from it
_childConstructors: []
} );
basePrototype = new base();
// We need to make the options hash a property directly on the new instance
// otherwise we'll modify the options hash on the prototype that we're
// inheriting from
basePrototype.options = $.widget.extend( {}, basePrototype.options );
$.each( prototype, function( prop, value ) {
if ( !$.isFunction( value ) ) {
proxiedPrototype[ prop ] = value;
return;
}
proxiedPrototype[ prop ] = ( function() {
function _super() {
return base.prototype[ prop ].apply( this, arguments );
}
function _superApply( args ) {
return base.prototype[ prop ].apply( this, args );
}
return function() {
var __super = this._super;
var __superApply = this._superApply;
var returnValue;
this._super = _super;
this._superApply = _superApply;
returnValue = value.apply( this, arguments );
this._super = __super;
this._superApply = __superApply;
return returnValue;
};
} )();
} );
constructor.prototype = $.widget.extend( basePrototype, {
// TODO: remove support for widgetEventPrefix
// always use the name + a colon as the prefix, e.g., draggable:start
// don't prefix for widgets that aren't DOM-based
widgetEventPrefix: existingConstructor ? ( basePrototype.widgetEventPrefix || name ) : name
}, proxiedPrototype, {
constructor: constructor,
namespace: namespace,
widgetName: name,
widgetFullName: fullName
} );
// If this widget is being redefined then we need to find all widgets that
// are inheriting from it and redefine all of them so that they inherit from
// the new version of this widget. We're essentially trying to replace one
// level in the prototype chain.
if ( existingConstructor ) {
$.each( existingConstructor._childConstructors, function( i, child ) {
var childPrototype = child.prototype;
// Redefine the child widget using the same prototype that was
// originally used, but inherit from the new version of the base
$.widget( childPrototype.namespace + "." + childPrototype.widgetName, constructor,
child._proto );
} );
// Remove the list of existing child constructors from the old constructor
// so the old child constructors can be garbage collected
delete existingConstructor._childConstructors;
} else {
base._childConstructors.push( constructor );
}
$.widget.bridge( name, constructor );
return constructor;
};
$.widget.extend = function( target ) {
var input = widgetSlice.call( arguments, 1 );
var inputIndex = 0;
var inputLength = input.length;
var key;
var value;
for ( ; inputIndex < inputLength; inputIndex++ ) {
for ( key in input[ inputIndex ] ) {
value = input[ inputIndex ][ key ];
if ( input[ inputIndex ].hasOwnProperty( key ) && value !== undefined ) {
// Clone objects
if ( $.isPlainObject( value ) ) {
target[ key ] = $.isPlainObject( target[ key ] ) ?
$.widget.extend( {}, target[ key ], value ) :
// Don't extend strings, arrays, etc. with objects
$.widget.extend( {}, value );
// Copy everything else by reference
} else {
target[ key ] = value;
}
}
}
}
return target;
};
$.widget.bridge = function( name, object ) {
var fullName = object.prototype.widgetFullName || name;
$.fn[ name ] = function( options ) {
var isMethodCall = typeof options === "string";
var args = widgetSlice.call( arguments, 1 );
var returnValue = this;
if ( isMethodCall ) {
// If this is an empty collection, we need to have the instance method
// return undefined instead of the jQuery instance
if ( !this.length && options === "instance" ) {
returnValue = undefined;
} else {
this.each( function() {
var methodValue;
var instance = $.data( this, fullName );
if ( options === "instance" ) {
returnValue = instance;
return false;
}
if ( !instance ) {
return $.error( "cannot call methods on " + name +
" prior to initialization; " +
"attempted to call method '" + options + "'" );
}
if ( !$.isFunction( instance[ options ] ) || options.charAt( 0 ) === "_" ) {
return $.error( "no such method '" + options + "' for " + name +
" widget instance" );
}
methodValue = instance[ options ].apply( instance, args );
if ( methodValue !== instance && methodValue !== undefined ) {
returnValue = methodValue && methodValue.jquery ?
returnValue.pushStack( methodValue.get() ) :
methodValue;
return false;
}
} );
}
} else {
// Allow multiple hashes to be passed on init
if ( args.length ) {
options = $.widget.extend.apply( null, [ options ].concat( args ) );
}
this.each( function() {
var instance = $.data( this, fullName );
if ( instance ) {
instance.option( options || {} );
if ( instance._init ) {
instance._init();
}
} else {
$.data( this, fullName, new object( options, this ) );
}
} );
}
return returnValue;
};
};
$.Widget = function( /* options, element */ ) {};
$.Widget._childConstructors = [];
$.Widget.prototype = {
widgetName: "widget",
widgetEventPrefix: "",
defaultElement: "<div>",
options: {
classes: {},
disabled: false,
// Callbacks
create: null
},
_createWidget: function( options, element ) {
element = $( element || this.defaultElement || this )[ 0 ];
this.element = $( element );
this.uuid = widgetUuid++;
this.eventNamespace = "." + this.widgetName + this.uuid;
this.bindings = $();
this.hoverable = $();
this.focusable = $();
this.classesElementLookup = {};
if ( element !== this ) {
$.data( element, this.widgetFullName, this );
this._on( true, this.element, {
remove: function( event ) {
if ( event.target === element ) {
this.destroy();
}
}
} );
this.document = $( element.style ?
// Element within the document
element.ownerDocument :
// Element is window or document
element.document || element );
this.window = $( this.document[ 0 ].defaultView || this.document[ 0 ].parentWindow );
}
this.options = $.widget.extend( {},
this.options,
this._getCreateOptions(),
options );
this._create();
if ( this.options.disabled ) {
this._setOptionDisabled( this.options.disabled );
}
this._trigger( "create", null, this._getCreateEventData() );
this._init();
},
_getCreateOptions: function() {
return {};
},
_getCreateEventData: $.noop,
_create: $.noop,
_init: $.noop,
destroy: function() {
var that = this;
this._destroy();
$.each( this.classesElementLookup, function( key, value ) {
that._removeClass( value, key );
} );
// We can probably remove the unbind calls in 2.0
// all event bindings should go through this._on()
this.element
.off( this.eventNamespace )
.removeData( this.widgetFullName );
this.widget()
.off( this.eventNamespace )
.removeAttr( "aria-disabled" );
// Clean up events and states
this.bindings.off( this.eventNamespace );
},
_destroy: $.noop,
widget: function() {
return this.element;
},
option: function( key, value ) {
var options = key;
var parts;
var curOption;
var i;
if ( arguments.length === 0 ) {
// Don't return a reference to the internal hash
return $.widget.extend( {}, this.options );
}
if ( typeof key === "string" ) {
// Handle nested keys, e.g., "foo.bar" => { foo: { bar: ___ } }
options = {};
parts = key.split( "." );
key = parts.shift();
if ( parts.length ) {
curOption = options[ key ] = $.widget.extend( {}, this.options[ key ] );
for ( i = 0; i < parts.length - 1; i++ ) {
curOption[ parts[ i ] ] = curOption[ parts[ i ] ] || {};
curOption = curOption[ parts[ i ] ];
}
key = parts.pop();
if ( arguments.length === 1 ) {
return curOption[ key ] === undefined ? null : curOption[ key ];
}
curOption[ key ] = value;
} else {
if ( arguments.length === 1 ) {
return this.options[ key ] === undefined ? null : this.options[ key ];
}
options[ key ] = value;
}
}
this._setOptions( options );
return this;
},
_setOptions: function( options ) {
var key;
for ( key in options ) {
this._setOption( key, options[ key ] );
}
return this;
},
_setOption: function( key, value ) {
if ( key === "classes" ) {
this._setOptionClasses( value );
}
this.options[ key ] = value;
if ( key === "disabled" ) {
this._setOptionDisabled( value );
}
return this;
},
_setOptionClasses: function( value ) {
var classKey, elements, currentElements;
for ( classKey in value ) {
currentElements = this.classesElementLookup[ classKey ];
if ( value[ classKey ] === this.options.classes[ classKey ] ||
!currentElements ||
!currentElements.length ) {
continue;
}
// We are doing this to create a new jQuery object because the _removeClass() call
// on the next line is going to destroy the reference to the current elements being
// tracked. We need to save a copy of this collection so that we can add the new classes
// below.
elements = $( currentElements.get() );
this._removeClass( currentElements, classKey );
// We don't use _addClass() here, because that uses this.options.classes
// for generating the string of classes. We want to use the value passed in from
// _setOption(), this is the new value of the classes option which was passed to
// _setOption(). We pass this value directly to _classes().
elements.addClass( this._classes( {
element: elements,
keys: classKey,
classes: value,
add: true
} ) );
}
},
_setOptionDisabled: function( value ) {
this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null, !!value );
// If the widget is becoming disabled, then nothing is interactive
if ( value ) {
this._removeClass( this.hoverable, null, "ui-state-hover" );
this._removeClass( this.focusable, null, "ui-state-focus" );
}
},
enable: function() {
return this._setOptions( { disabled: false } );
},
disable: function() {
return this._setOptions( { disabled: true } );
},
_classes: function( options ) {
var full = [];
var that = this;
options = $.extend( {
element: this.element,
classes: this.options.classes || {}
}, options );
function processClassString( classes, checkOption ) {
var current, i;
for ( i = 0; i < classes.length; i++ ) {
current = that.classesElementLookup[ classes[ i ] ] || $();
if ( options.add ) {
current = $( $.unique( current.get().concat( options.element.get() ) ) );
} else {
current = $( current.not( options.element ).get() );
}
that.classesElementLookup[ classes[ i ] ] = current;
full.push( classes[ i ] );
if ( checkOption && options.classes[ classes[ i ] ] ) {
full.push( options.classes[ classes[ i ] ] );
}
}
}
this._on( options.element, {
"remove": "_untrackClassesElement"
} );
if ( options.keys ) {
processClassString( options.keys.match( /\S+/g ) || [], true );
}
if ( options.extra ) {
processClassString( options.extra.match( /\S+/g ) || [] );
}
return full.join( " " );
},
_untrackClassesElement: function( event ) {
var that = this;
$.each( that.classesElementLookup, function( key, value ) {
if ( $.inArray( event.target, value ) !== -1 ) {
that.classesElementLookup[ key ] = $( value.not( event.target ).get() );
}
} );
},
_removeClass: function( element, keys, extra ) {
return this._toggleClass( element, keys, extra, false );
},
_addClass: function( element, keys, extra ) {
return this._toggleClass( element, keys, extra, true );
},
_toggleClass: function( element, keys, extra, add ) {
add = ( typeof add === "boolean" ) ? add : extra;
var shift = ( typeof element === "string" || element === null ),
options = {
extra: shift ? keys : extra,
keys: shift ? element : keys,
element: shift ? this.element : element,
add: add
};
options.element.toggleClass( this._classes( options ), add );
return this;
},
_on: function( suppressDisabledCheck, element, handlers ) {
var delegateElement;
var instance = this;
// No suppressDisabledCheck flag, shuffle arguments
if ( typeof suppressDisabledCheck !== "boolean" ) {
handlers = element;
element = suppressDisabledCheck;
suppressDisabledCheck = false;
}
// No element argument, shuffle and use this.element
if ( !handlers ) {
handlers = element;
element = this.element;
delegateElement = this.widget();
} else {
element = delegateElement = $( element );
this.bindings = this.bindings.add( element );
}
$.each( handlers, function( event, handler ) {
function handlerProxy() {
// Allow widgets to customize the disabled handling
// - disabled as an array instead of boolean
// - disabled class as method for disabling individual parts
if ( !suppressDisabledCheck &&
( instance.options.disabled === true ||
$( this ).hasClass( "ui-state-disabled" ) ) ) {
return;
}
return ( typeof handler === "string" ? instance[ handler ] : handler )
.apply( instance, arguments );
}
// Copy the guid so direct unbinding works
if ( typeof handler !== "string" ) {
handlerProxy.guid = handler.guid =
handler.guid || handlerProxy.guid || $.guid++;
}
var match = event.match( /^([\w:-]*)\s*(.*)$/ );
var eventName = match[ 1 ] + instance.eventNamespace;
var selector = match[ 2 ];
if ( selector ) {
delegateElement.on( eventName, selector, handlerProxy );
} else {
element.on( eventName, handlerProxy );
}
} );
},
_off: function( element, eventName ) {
eventName = ( eventName || "" ).split( " " ).join( this.eventNamespace + " " ) +
this.eventNamespace;
element.off( eventName ).off( eventName );
// Clear the stack to avoid memory leaks (#10056)
this.bindings = $( this.bindings.not( element ).get() );
this.focusable = $( this.focusable.not( element ).get() );
this.hoverable = $( this.hoverable.not( element ).get() );
},
_delay: function( handler, delay ) {
function handlerProxy() {
return ( typeof handler === "string" ? instance[ handler ] : handler )
.apply( instance, arguments );
}
var instance = this;
return setTimeout( handlerProxy, delay || 0 );
},
_hoverable: function( element ) {
this.hoverable = this.hoverable.add( element );
this._on( element, {
mouseenter: function( event ) {
this._addClass( $( event.currentTarget ), null, "ui-state-hover" );
},
mouseleave: function( event ) {
this._removeClass( $( event.currentTarget ), null, "ui-state-hover" );
}
} );
},
_focusable: function( element ) {
this.focusable = this.focusable.add( element );
this._on( element, {
focusin: function( event ) {
this._addClass( $( event.currentTarget ), null, "ui-state-focus" );
},
focusout: function( event ) {
this._removeClass( $( event.currentTarget ), null, "ui-state-focus" );
}
} );
},
_trigger: function( type, event, data ) {
var prop, orig;
var callback = this.options[ type ];
data = data || {};
event = $.Event( event );
event.type = ( type === this.widgetEventPrefix ?
type :
this.widgetEventPrefix + type ).toLowerCase();
// The original event may come from any element
// so we need to reset the target on the new event
event.target = this.element[ 0 ];
// Copy original event properties over to the new event
orig = event.originalEvent;
if ( orig ) {
for ( prop in orig ) {
if ( !( prop in event ) ) {
event[ prop ] = orig[ prop ];
}
}
}
this.element.trigger( event, data );
return !( $.isFunction( callback ) &&
callback.apply( this.element[ 0 ], [ event ].concat( data ) ) === false ||
event.isDefaultPrevented() );
}
};
$.each( { show: "fadeIn", hide: "fadeOut" }, function( method, defaultEffect ) {
$.Widget.prototype[ "_" + method ] = function( element, options, callback ) {
if ( typeof options === "string" ) {
options = { effect: options };
}
var hasOptions;
var effectName = !options ?
method :
options === true || typeof options === "number" ?
defaultEffect :
options.effect || defaultEffect;
options = options || {};
if ( typeof options === "number" ) {
options = { duration: options };
}
hasOptions = !$.isEmptyObject( options );
options.complete = callback;
if ( options.delay ) {
element.delay( options.delay );
}
if ( hasOptions && $.effects && $.effects.effect[ effectName ] ) {
element[ method ]( options );
} else if ( effectName !== method && element[ effectName ] ) {
element[ effectName ]( options.duration, options.easing, callback );
} else {
element.queue( function( next ) {
$( this )[ method ]();
if ( callback ) {
callback.call( element[ 0 ] );
}
next();
} );
}
};
} );
var widget = $.widget;
/*!
* jQuery UI Position 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* http://api.jqueryui.com/position/
*/
//>>label: Position
//>>group: Core
//>>description: Positions elements relative to other elements.
//>>docs: http://api.jqueryui.com/position/
//>>demos: http://jqueryui.com/position/
( function() {
var cachedScrollbarWidth,
max = Math.max,
abs = Math.abs,
rhorizontal = /left|center|right/,
rvertical = /top|center|bottom/,
roffset = /[\+\-]\d+(\.[\d]+)?%?/,
rposition = /^\w+/,
rpercent = /%$/,
_position = $.fn.position;
function getOffsets( offsets, width, height ) {
return [
parseFloat( offsets[ 0 ] ) * ( rpercent.test( offsets[ 0 ] ) ? width / 100 : 1 ),
parseFloat( offsets[ 1 ] ) * ( rpercent.test( offsets[ 1 ] ) ? height / 100 : 1 )
];
}
function parseCss( element, property ) {
return parseInt( $.css( element, property ), 10 ) || 0;
}
function getDimensions( elem ) {
var raw = elem[ 0 ];
if ( raw.nodeType === 9 ) {
return {
width: elem.width(),
height: elem.height(),
offset: { top: 0, left: 0 }
};
}
if ( $.isWindow( raw ) ) {
return {
width: elem.width(),
height: elem.height(),
offset: { top: elem.scrollTop(), left: elem.scrollLeft() }
};
}
if ( raw.preventDefault ) {
return {
width: 0,
height: 0,
offset: { top: raw.pageY, left: raw.pageX }
};
}
return {
width: elem.outerWidth(),
height: elem.outerHeight(),
offset: elem.offset()
};
}
$.position = {
scrollbarWidth: function() {
if ( cachedScrollbarWidth !== undefined ) {
return cachedScrollbarWidth;
}
var w1, w2,
div = $( "<div " +
"style='display:block;position:absolute;width:50px;height:50px;overflow:hidden;'>" +
"<div style='height:100px;width:auto;'></div></div>" ),
innerDiv = div.children()[ 0 ];
$( "body" ).append( div );
w1 = innerDiv.offsetWidth;
div.css( "overflow", "scroll" );
w2 = innerDiv.offsetWidth;
if ( w1 === w2 ) {
w2 = div[ 0 ].clientWidth;
}
div.remove();
return ( cachedScrollbarWidth = w1 - w2 );
},
getScrollInfo: function( within ) {
var overflowX = within.isWindow || within.isDocument ? "" :
within.element.css( "overflow-x" ),
overflowY = within.isWindow || within.isDocument ? "" :
within.element.css( "overflow-y" ),
hasOverflowX = overflowX === "scroll" ||
( overflowX === "auto" && within.width < within.element[ 0 ].scrollWidth ),
hasOverflowY = overflowY === "scroll" ||
( overflowY === "auto" && within.height < within.element[ 0 ].scrollHeight );
return {
width: hasOverflowY ? $.position.scrollbarWidth() : 0,
height: hasOverflowX ? $.position.scrollbarWidth() : 0
};
},
getWithinInfo: function( element ) {
var withinElement = $( element || window ),
isWindow = $.isWindow( withinElement[ 0 ] ),
isDocument = !!withinElement[ 0 ] && withinElement[ 0 ].nodeType === 9,
hasOffset = !isWindow && !isDocument;
return {
element: withinElement,
isWindow: isWindow,
isDocument: isDocument,
offset: hasOffset ? $( element ).offset() : { left: 0, top: 0 },
scrollLeft: withinElement.scrollLeft(),
scrollTop: withinElement.scrollTop(),
width: withinElement.outerWidth(),
height: withinElement.outerHeight()
};
}
};
$.fn.position = function( options ) {
if ( !options || !options.of ) {
return _position.apply( this, arguments );
}
// Make a copy, we don't want to modify arguments
options = $.extend( {}, options );
var atOffset, targetWidth, targetHeight, targetOffset, basePosition, dimensions,
target = $( options.of ),
within = $.position.getWithinInfo( options.within ),
scrollInfo = $.position.getScrollInfo( within ),
collision = ( options.collision || "flip" ).split( " " ),
offsets = {};
dimensions = getDimensions( target );
if ( target[ 0 ].preventDefault ) {
// Force left top to allow flipping
options.at = "left top";
}
targetWidth = dimensions.width;
targetHeight = dimensions.height;
targetOffset = dimensions.offset;
// Clone to reuse original targetOffset later
basePosition = $.extend( {}, targetOffset );
// Force my and at to have valid horizontal and vertical positions
// if a value is missing or invalid, it will be converted to center
$.each( [ "my", "at" ], function() {
var pos = ( options[ this ] || "" ).split( " " ),
horizontalOffset,
verticalOffset;
if ( pos.length === 1 ) {
pos = rhorizontal.test( pos[ 0 ] ) ?
pos.concat( [ "center" ] ) :
rvertical.test( pos[ 0 ] ) ?
[ "center" ].concat( pos ) :
[ "center", "center" ];
}
pos[ 0 ] = rhorizontal.test( pos[ 0 ] ) ? pos[ 0 ] : "center";
pos[ 1 ] = rvertical.test( pos[ 1 ] ) ? pos[ 1 ] : "center";
// Calculate offsets
horizontalOffset = roffset.exec( pos[ 0 ] );
verticalOffset = roffset.exec( pos[ 1 ] );
offsets[ this ] = [
horizontalOffset ? horizontalOffset[ 0 ] : 0,
verticalOffset ? verticalOffset[ 0 ] : 0
];
// Reduce to just the positions without the offsets
options[ this ] = [
rposition.exec( pos[ 0 ] )[ 0 ],
rposition.exec( pos[ 1 ] )[ 0 ]
];
} );
// Normalize collision option
if ( collision.length === 1 ) {
collision[ 1 ] = collision[ 0 ];
}
if ( options.at[ 0 ] === "right" ) {
basePosition.left += targetWidth;
} else if ( options.at[ 0 ] === "center" ) {
basePosition.left += targetWidth / 2;
}
if ( options.at[ 1 ] === "bottom" ) {
basePosition.top += targetHeight;
} else if ( options.at[ 1 ] === "center" ) {
basePosition.top += targetHeight / 2;
}
atOffset = getOffsets( offsets.at, targetWidth, targetHeight );
basePosition.left += atOffset[ 0 ];
basePosition.top += atOffset[ 1 ];
return this.each( function() {
var collisionPosition, using,
elem = $( this ),
elemWidth = elem.outerWidth(),
elemHeight = elem.outerHeight(),
marginLeft = parseCss( this, "marginLeft" ),
marginTop = parseCss( this, "marginTop" ),
collisionWidth = elemWidth + marginLeft + parseCss( this, "marginRight" ) +
scrollInfo.width,
collisionHeight = elemHeight + marginTop + parseCss( this, "marginBottom" ) +
scrollInfo.height,
position = $.extend( {}, basePosition ),
myOffset = getOffsets( offsets.my, elem.outerWidth(), elem.outerHeight() );
if ( options.my[ 0 ] === "right" ) {
position.left -= elemWidth;
} else if ( options.my[ 0 ] === "center" ) {
position.left -= elemWidth / 2;
}
if ( options.my[ 1 ] === "bottom" ) {
position.top -= elemHeight;
} else if ( options.my[ 1 ] === "center" ) {
position.top -= elemHeight / 2;
}
position.left += myOffset[ 0 ];
position.top += myOffset[ 1 ];
collisionPosition = {
marginLeft: marginLeft,
marginTop: marginTop
};
$.each( [ "left", "top" ], function( i, dir ) {
if ( $.ui.position[ collision[ i ] ] ) {
$.ui.position[ collision[ i ] ][ dir ]( position, {
targetWidth: targetWidth,
targetHeight: targetHeight,
elemWidth: elemWidth,
elemHeight: elemHeight,
collisionPosition: collisionPosition,
collisionWidth: collisionWidth,
collisionHeight: collisionHeight,
offset: [ atOffset[ 0 ] + myOffset[ 0 ], atOffset [ 1 ] + myOffset[ 1 ] ],
my: options.my,
at: options.at,
within: within,
elem: elem
} );
}
} );
if ( options.using ) {
// Adds feedback as second argument to using callback, if present
using = function( props ) {
var left = targetOffset.left - position.left,
right = left + targetWidth - elemWidth,
top = targetOffset.top - position.top,
bottom = top + targetHeight - elemHeight,
feedback = {
target: {
element: target,
left: targetOffset.left,
top: targetOffset.top,
width: targetWidth,
height: targetHeight
},
element: {
element: elem,
left: position.left,
top: position.top,
width: elemWidth,
height: elemHeight
},
horizontal: right < 0 ? "left" : left > 0 ? "right" : "center",
vertical: bottom < 0 ? "top" : top > 0 ? "bottom" : "middle"
};
if ( targetWidth < elemWidth && abs( left + right ) < targetWidth ) {
feedback.horizontal = "center";
}
if ( targetHeight < elemHeight && abs( top + bottom ) < targetHeight ) {
feedback.vertical = "middle";
}
if ( max( abs( left ), abs( right ) ) > max( abs( top ), abs( bottom ) ) ) {
feedback.important = "horizontal";
} else {
feedback.important = "vertical";
}
options.using.call( this, props, feedback );
};
}
elem.offset( $.extend( position, { using: using } ) );
} );
};
$.ui.position = {
fit: {
left: function( position, data ) {
var within = data.within,
withinOffset = within.isWindow ? within.scrollLeft : within.offset.left,
outerWidth = within.width,
collisionPosLeft = position.left - data.collisionPosition.marginLeft,
overLeft = withinOffset - collisionPosLeft,
overRight = collisionPosLeft + data.collisionWidth - outerWidth - withinOffset,
newOverRight;
// Element is wider than within
if ( data.collisionWidth > outerWidth ) {
// Element is initially over the left side of within
if ( overLeft > 0 && overRight <= 0 ) {
newOverRight = position.left + overLeft + data.collisionWidth - outerWidth -
withinOffset;
position.left += overLeft - newOverRight;
// Element is initially over right side of within
} else if ( overRight > 0 && overLeft <= 0 ) {
position.left = withinOffset;
// Element is initially over both left and right sides of within
} else {
if ( overLeft > overRight ) {
position.left = withinOffset + outerWidth - data.collisionWidth;
} else {
position.left = withinOffset;
}
}
// Too far left -> align with left edge
} else if ( overLeft > 0 ) {
position.left += overLeft;
// Too far right -> align with right edge
} else if ( overRight > 0 ) {
position.left -= overRight;
// Adjust based on position and margin
} else {
position.left = max( position.left - collisionPosLeft, position.left );
}
},
top: function( position, data ) {
var within = data.within,
withinOffset = within.isWindow ? within.scrollTop : within.offset.top,
outerHeight = data.within.height,
collisionPosTop = position.top - data.collisionPosition.marginTop,
overTop = withinOffset - collisionPosTop,
overBottom = collisionPosTop + data.collisionHeight - outerHeight - withinOffset,
newOverBottom;
// Element is taller than within
if ( data.collisionHeight > outerHeight ) {
// Element is initially over the top of within
if ( overTop > 0 && overBottom <= 0 ) {
newOverBottom = position.top + overTop + data.collisionHeight - outerHeight -
withinOffset;
position.top += overTop - newOverBottom;
// Element is initially over bottom of within
} else if ( overBottom > 0 && overTop <= 0 ) {
position.top = withinOffset;
// Element is initially over both top and bottom of within
} else {
if ( overTop > overBottom ) {
position.top = withinOffset + outerHeight - data.collisionHeight;
} else {
position.top = withinOffset;
}
}
// Too far up -> align with top
} else if ( overTop > 0 ) {
position.top += overTop;
// Too far down -> align with bottom edge
} else if ( overBottom > 0 ) {
position.top -= overBottom;
// Adjust based on position and margin
} else {
position.top = max( position.top - collisionPosTop, position.top );
}
}
},
flip: {
left: function( position, data ) {
var within = data.within,
withinOffset = within.offset.left + within.scrollLeft,
outerWidth = within.width,
offsetLeft = within.isWindow ? within.scrollLeft : within.offset.left,
collisionPosLeft = position.left - data.collisionPosition.marginLeft,
overLeft = collisionPosLeft - offsetLeft,
overRight = collisionPosLeft + data.collisionWidth - outerWidth - offsetLeft,
myOffset = data.my[ 0 ] === "left" ?
-data.elemWidth :
data.my[ 0 ] === "right" ?
data.elemWidth :
0,
atOffset = data.at[ 0 ] === "left" ?
data.targetWidth :
data.at[ 0 ] === "right" ?
-data.targetWidth :
0,
offset = -2 * data.offset[ 0 ],
newOverRight,
newOverLeft;
if ( overLeft < 0 ) {
newOverRight = position.left + myOffset + atOffset + offset + data.collisionWidth -
outerWidth - withinOffset;
if ( newOverRight < 0 || newOverRight < abs( overLeft ) ) {
position.left += myOffset + atOffset + offset;
}
} else if ( overRight > 0 ) {
newOverLeft = position.left - data.collisionPosition.marginLeft + myOffset +
atOffset + offset - offsetLeft;
if ( newOverLeft > 0 || abs( newOverLeft ) < overRight ) {
position.left += myOffset + atOffset + offset;
}
}
},
top: function( position, data ) {
var within = data.within,
withinOffset = within.offset.top + within.scrollTop,
outerHeight = within.height,
offsetTop = within.isWindow ? within.scrollTop : within.offset.top,
collisionPosTop = position.top - data.collisionPosition.marginTop,
overTop = collisionPosTop - offsetTop,
overBottom = collisionPosTop + data.collisionHeight - outerHeight - offsetTop,
top = data.my[ 1 ] === "top",
myOffset = top ?
-data.elemHeight :
data.my[ 1 ] === "bottom" ?
data.elemHeight :
0,
atOffset = data.at[ 1 ] === "top" ?
data.targetHeight :
data.at[ 1 ] === "bottom" ?
-data.targetHeight :
0,
offset = -2 * data.offset[ 1 ],
newOverTop,
newOverBottom;
if ( overTop < 0 ) {
newOverBottom = position.top + myOffset + atOffset + offset + data.collisionHeight -
outerHeight - withinOffset;
if ( newOverBottom < 0 || newOverBottom < abs( overTop ) ) {
position.top += myOffset + atOffset + offset;
}
} else if ( overBottom > 0 ) {
newOverTop = position.top - data.collisionPosition.marginTop + myOffset + atOffset +
offset - offsetTop;
if ( newOverTop > 0 || abs( newOverTop ) < overBottom ) {
position.top += myOffset + atOffset + offset;
}
}
}
},
flipfit: {
left: function() {
$.ui.position.flip.left.apply( this, arguments );
$.ui.position.fit.left.apply( this, arguments );
},
top: function() {
$.ui.position.flip.top.apply( this, arguments );
$.ui.position.fit.top.apply( this, arguments );
}
}
};
} )();
var position = $.ui.position;
/*!
* jQuery UI :data 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: :data Selector
//>>group: Core
//>>description: Selects elements which have data stored under the specified key.
//>>docs: http://api.jqueryui.com/data-selector/
var data = $.extend( $.expr[ ":" ], {
data: $.expr.createPseudo ?
$.expr.createPseudo( function( dataName ) {
return function( elem ) {
return !!$.data( elem, dataName );
};
} ) :
// Support: jQuery <1.8
function( elem, i, match ) {
return !!$.data( elem, match[ 3 ] );
}
} );
/*!
* jQuery UI Disable Selection 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: disableSelection
//>>group: Core
//>>description: Disable selection of text content within the set of matched elements.
//>>docs: http://api.jqueryui.com/disableSelection/
// This file is deprecated
var disableSelection = $.fn.extend( {
disableSelection: ( function() {
var eventType = "onselectstart" in document.createElement( "div" ) ?
"selectstart" :
"mousedown";
return function() {
return this.on( eventType + ".ui-disableSelection", function( event ) {
event.preventDefault();
} );
};
} )(),
enableSelection: function() {
return this.off( ".ui-disableSelection" );
}
} );
/*!
* jQuery UI Effects 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Effects Core
//>>group: Effects
// jscs:disable maximumLineLength
//>>description: Extends the internal jQuery effects. Includes morphing and easing. Required by all other effects.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/category/effects-core/
//>>demos: http://jqueryui.com/effect/
var dataSpace = "ui-effects-",
dataSpaceStyle = "ui-effects-style",
dataSpaceAnimated = "ui-effects-animated",
// Create a local jQuery because jQuery Color relies on it and the
// global may not exist with AMD and a custom build (#10199)
jQuery = $;
$.effects = {
effect: {}
};
/*!
* jQuery Color Animations v2.1.2
* https://github.com/jquery/jquery-color
*
* Copyright 2014 jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
* Date: Wed Jan 16 08:47:09 2013 -0600
*/
( function( jQuery, undefined ) {
var stepHooks = "backgroundColor borderBottomColor borderLeftColor borderRightColor " +
"borderTopColor color columnRuleColor outlineColor textDecorationColor textEmphasisColor",
// Plusequals test for += 100 -= 100
rplusequals = /^([\-+])=\s*(\d+\.?\d*)/,
// A set of RE's that can match strings and generate color tuples.
stringParsers = [ {
re: /rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
execResult[ 1 ],
execResult[ 2 ],
execResult[ 3 ],
execResult[ 4 ]
];
}
}, {
re: /rgba?\(\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
parse: function( execResult ) {
return [
execResult[ 1 ] * 2.55,
execResult[ 2 ] * 2.55,
execResult[ 3 ] * 2.55,
execResult[ 4 ]
];
}
}, {
// This regex ignores A-F because it's compared against an already lowercased string
re: /#([a-f0-9]{2})([a-f0-9]{2})([a-f0-9]{2})/,
parse: function( execResult ) {
return [
parseInt( execResult[ 1 ], 16 ),
parseInt( execResult[ 2 ], 16 ),
parseInt( execResult[ 3 ], 16 )
];
}
}, {
// This regex ignores A-F because it's compared against an already lowercased string
re: /#([a-f0-9])([a-f0-9])([a-f0-9])/,
parse: function( execResult ) {
return [
parseInt( execResult[ 1 ] + execResult[ 1 ], 16 ),
parseInt( execResult[ 2 ] + execResult[ 2 ], 16 ),
parseInt( execResult[ 3 ] + execResult[ 3 ], 16 )
];
}
}, {
re: /hsla?\(\s*(\d+(?:\.\d+)?)\s*,\s*(\d+(?:\.\d+)?)\%\s*,\s*(\d+(?:\.\d+)?)\%\s*(?:,\s*(\d?(?:\.\d+)?)\s*)?\)/,
space: "hsla",
parse: function( execResult ) {
return [
execResult[ 1 ],
execResult[ 2 ] / 100,
execResult[ 3 ] / 100,
execResult[ 4 ]
];
}
} ],
// JQuery.Color( )
color = jQuery.Color = function( color, green, blue, alpha ) {
return new jQuery.Color.fn.parse( color, green, blue, alpha );
},
spaces = {
rgba: {
props: {
red: {
idx: 0,
type: "byte"
},
green: {
idx: 1,
type: "byte"
},
blue: {
idx: 2,
type: "byte"
}
}
},
hsla: {
props: {
hue: {
idx: 0,
type: "degrees"
},
saturation: {
idx: 1,
type: "percent"
},
lightness: {
idx: 2,
type: "percent"
}
}
}
},
propTypes = {
"byte": {
floor: true,
max: 255
},
"percent": {
max: 1
},
"degrees": {
mod: 360,
floor: true
}
},
support = color.support = {},
// Element for support tests
supportElem = jQuery( "<p>" )[ 0 ],
// Colors = jQuery.Color.names
colors,
// Local aliases of functions called often
each = jQuery.each;
// Determine rgba support immediately
supportElem.style.cssText = "background-color:rgba(1,1,1,.5)";
support.rgba = supportElem.style.backgroundColor.indexOf( "rgba" ) > -1;
// Define cache name and alpha properties
// for rgba and hsla spaces
each( spaces, function( spaceName, space ) {
space.cache = "_" + spaceName;
space.props.alpha = {
idx: 3,
type: "percent",
def: 1
};
} );
function clamp( value, prop, allowEmpty ) {
var type = propTypes[ prop.type ] || {};
if ( value == null ) {
return ( allowEmpty || !prop.def ) ? null : prop.def;
}
// ~~ is an short way of doing floor for positive numbers
value = type.floor ? ~~value : parseFloat( value );
// IE will pass in empty strings as value for alpha,
// which will hit this case
if ( isNaN( value ) ) {
return prop.def;
}
if ( type.mod ) {
// We add mod before modding to make sure that negatives values
// get converted properly: -10 -> 350
return ( value + type.mod ) % type.mod;
}
// For now all property types without mod have min and max
return 0 > value ? 0 : type.max < value ? type.max : value;
}
function stringParse( string ) {
var inst = color(),
rgba = inst._rgba = [];
string = string.toLowerCase();
each( stringParsers, function( i, parser ) {
var parsed,
match = parser.re.exec( string ),
values = match && parser.parse( match ),
spaceName = parser.space || "rgba";
if ( values ) {
parsed = inst[ spaceName ]( values );
// If this was an rgba parse the assignment might happen twice
// oh well....
inst[ spaces[ spaceName ].cache ] = parsed[ spaces[ spaceName ].cache ];
rgba = inst._rgba = parsed._rgba;
// Exit each( stringParsers ) here because we matched
return false;
}
} );
// Found a stringParser that handled it
if ( rgba.length ) {
// If this came from a parsed string, force "transparent" when alpha is 0
// chrome, (and maybe others) return "transparent" as rgba(0,0,0,0)
if ( rgba.join() === "0,0,0,0" ) {
jQuery.extend( rgba, colors.transparent );
}
return inst;
}
// Named colors
return colors[ string ];
}
color.fn = jQuery.extend( color.prototype, {
parse: function( red, green, blue, alpha ) {
if ( red === undefined ) {
this._rgba = [ null, null, null, null ];
return this;
}
if ( red.jquery || red.nodeType ) {
red = jQuery( red ).css( green );
green = undefined;
}
var inst = this,
type = jQuery.type( red ),
rgba = this._rgba = [];
// More than 1 argument specified - assume ( red, green, blue, alpha )
if ( green !== undefined ) {
red = [ red, green, blue, alpha ];
type = "array";
}
if ( type === "string" ) {
return this.parse( stringParse( red ) || colors._default );
}
if ( type === "array" ) {
each( spaces.rgba.props, function( key, prop ) {
rgba[ prop.idx ] = clamp( red[ prop.idx ], prop );
} );
return this;
}
if ( type === "object" ) {
if ( red instanceof color ) {
each( spaces, function( spaceName, space ) {
if ( red[ space.cache ] ) {
inst[ space.cache ] = red[ space.cache ].slice();
}
} );
} else {
each( spaces, function( spaceName, space ) {
var cache = space.cache;
each( space.props, function( key, prop ) {
// If the cache doesn't exist, and we know how to convert
if ( !inst[ cache ] && space.to ) {
// If the value was null, we don't need to copy it
// if the key was alpha, we don't need to copy it either
if ( key === "alpha" || red[ key ] == null ) {
return;
}
inst[ cache ] = space.to( inst._rgba );
}
// This is the only case where we allow nulls for ALL properties.
// call clamp with alwaysAllowEmpty
inst[ cache ][ prop.idx ] = clamp( red[ key ], prop, true );
} );
// Everything defined but alpha?
if ( inst[ cache ] &&
jQuery.inArray( null, inst[ cache ].slice( 0, 3 ) ) < 0 ) {
// Use the default of 1
inst[ cache ][ 3 ] = 1;
if ( space.from ) {
inst._rgba = space.from( inst[ cache ] );
}
}
} );
}
return this;
}
},
is: function( compare ) {
var is = color( compare ),
same = true,
inst = this;
each( spaces, function( _, space ) {
var localCache,
isCache = is[ space.cache ];
if ( isCache ) {
localCache = inst[ space.cache ] || space.to && space.to( inst._rgba ) || [];
each( space.props, function( _, prop ) {
if ( isCache[ prop.idx ] != null ) {
same = ( isCache[ prop.idx ] === localCache[ prop.idx ] );
return same;
}
} );
}
return same;
} );
return same;
},
_space: function() {
var used = [],
inst = this;
each( spaces, function( spaceName, space ) {
if ( inst[ space.cache ] ) {
used.push( spaceName );
}
} );
return used.pop();
},
transition: function( other, distance ) {
var end = color( other ),
spaceName = end._space(),
space = spaces[ spaceName ],
startColor = this.alpha() === 0 ? color( "transparent" ) : this,
start = startColor[ space.cache ] || space.to( startColor._rgba ),
result = start.slice();
end = end[ space.cache ];
each( space.props, function( key, prop ) {
var index = prop.idx,
startValue = start[ index ],
endValue = end[ index ],
type = propTypes[ prop.type ] || {};
// If null, don't override start value
if ( endValue === null ) {
return;
}
// If null - use end
if ( startValue === null ) {
result[ index ] = endValue;
} else {
if ( type.mod ) {
if ( endValue - startValue > type.mod / 2 ) {
startValue += type.mod;
} else if ( startValue - endValue > type.mod / 2 ) {
startValue -= type.mod;
}
}
result[ index ] = clamp( ( endValue - startValue ) * distance + startValue, prop );
}
} );
return this[ spaceName ]( result );
},
blend: function( opaque ) {
// If we are already opaque - return ourself
if ( this._rgba[ 3 ] === 1 ) {
return this;
}
var rgb = this._rgba.slice(),
a = rgb.pop(),
blend = color( opaque )._rgba;
return color( jQuery.map( rgb, function( v, i ) {
return ( 1 - a ) * blend[ i ] + a * v;
} ) );
},
toRgbaString: function() {
var prefix = "rgba(",
rgba = jQuery.map( this._rgba, function( v, i ) {
return v == null ? ( i > 2 ? 1 : 0 ) : v;
} );
if ( rgba[ 3 ] === 1 ) {
rgba.pop();
prefix = "rgb(";
}
return prefix + rgba.join() + ")";
},
toHslaString: function() {
var prefix = "hsla(",
hsla = jQuery.map( this.hsla(), function( v, i ) {
if ( v == null ) {
v = i > 2 ? 1 : 0;
}
// Catch 1 and 2
if ( i && i < 3 ) {
v = Math.round( v * 100 ) + "%";
}
return v;
} );
if ( hsla[ 3 ] === 1 ) {
hsla.pop();
prefix = "hsl(";
}
return prefix + hsla.join() + ")";
},
toHexString: function( includeAlpha ) {
var rgba = this._rgba.slice(),
alpha = rgba.pop();
if ( includeAlpha ) {
rgba.push( ~~( alpha * 255 ) );
}
return "#" + jQuery.map( rgba, function( v ) {
// Default to 0 when nulls exist
v = ( v || 0 ).toString( 16 );
return v.length === 1 ? "0" + v : v;
} ).join( "" );
},
toString: function() {
return this._rgba[ 3 ] === 0 ? "transparent" : this.toRgbaString();
}
} );
color.fn.parse.prototype = color.fn;
// Hsla conversions adapted from:
// https://code.google.com/p/maashaack/source/browse/packages/graphics/trunk/src/graphics/colors/HUE2RGB.as?r=5021
function hue2rgb( p, q, h ) {
h = ( h + 1 ) % 1;
if ( h * 6 < 1 ) {
return p + ( q - p ) * h * 6;
}
if ( h * 2 < 1 ) {
return q;
}
if ( h * 3 < 2 ) {
return p + ( q - p ) * ( ( 2 / 3 ) - h ) * 6;
}
return p;
}
spaces.hsla.to = function( rgba ) {
if ( rgba[ 0 ] == null || rgba[ 1 ] == null || rgba[ 2 ] == null ) {
return [ null, null, null, rgba[ 3 ] ];
}
var r = rgba[ 0 ] / 255,
g = rgba[ 1 ] / 255,
b = rgba[ 2 ] / 255,
a = rgba[ 3 ],
max = Math.max( r, g, b ),
min = Math.min( r, g, b ),
diff = max - min,
add = max + min,
l = add * 0.5,
h, s;
if ( min === max ) {
h = 0;
} else if ( r === max ) {
h = ( 60 * ( g - b ) / diff ) + 360;
} else if ( g === max ) {
h = ( 60 * ( b - r ) / diff ) + 120;
} else {
h = ( 60 * ( r - g ) / diff ) + 240;
}
// Chroma (diff) == 0 means greyscale which, by definition, saturation = 0%
// otherwise, saturation is based on the ratio of chroma (diff) to lightness (add)
if ( diff === 0 ) {
s = 0;
} else if ( l <= 0.5 ) {
s = diff / add;
} else {
s = diff / ( 2 - add );
}
return [ Math.round( h ) % 360, s, l, a == null ? 1 : a ];
};
spaces.hsla.from = function( hsla ) {
if ( hsla[ 0 ] == null || hsla[ 1 ] == null || hsla[ 2 ] == null ) {
return [ null, null, null, hsla[ 3 ] ];
}
var h = hsla[ 0 ] / 360,
s = hsla[ 1 ],
l = hsla[ 2 ],
a = hsla[ 3 ],
q = l <= 0.5 ? l * ( 1 + s ) : l + s - l * s,
p = 2 * l - q;
return [
Math.round( hue2rgb( p, q, h + ( 1 / 3 ) ) * 255 ),
Math.round( hue2rgb( p, q, h ) * 255 ),
Math.round( hue2rgb( p, q, h - ( 1 / 3 ) ) * 255 ),
a
];
};
each( spaces, function( spaceName, space ) {
var props = space.props,
cache = space.cache,
to = space.to,
from = space.from;
// Makes rgba() and hsla()
color.fn[ spaceName ] = function( value ) {
// Generate a cache for this space if it doesn't exist
if ( to && !this[ cache ] ) {
this[ cache ] = to( this._rgba );
}
if ( value === undefined ) {
return this[ cache ].slice();
}
var ret,
type = jQuery.type( value ),
arr = ( type === "array" || type === "object" ) ? value : arguments,
local = this[ cache ].slice();
each( props, function( key, prop ) {
var val = arr[ type === "object" ? key : prop.idx ];
if ( val == null ) {
val = local[ prop.idx ];
}
local[ prop.idx ] = clamp( val, prop );
} );
if ( from ) {
ret = color( from( local ) );
ret[ cache ] = local;
return ret;
} else {
return color( local );
}
};
// Makes red() green() blue() alpha() hue() saturation() lightness()
each( props, function( key, prop ) {
// Alpha is included in more than one space
if ( color.fn[ key ] ) {
return;
}
color.fn[ key ] = function( value ) {
var vtype = jQuery.type( value ),
fn = ( key === "alpha" ? ( this._hsla ? "hsla" : "rgba" ) : spaceName ),
local = this[ fn ](),
cur = local[ prop.idx ],
match;
if ( vtype === "undefined" ) {
return cur;
}
if ( vtype === "function" ) {
value = value.call( this, cur );
vtype = jQuery.type( value );
}
if ( value == null && prop.empty ) {
return this;
}
if ( vtype === "string" ) {
match = rplusequals.exec( value );
if ( match ) {
value = cur + parseFloat( match[ 2 ] ) * ( match[ 1 ] === "+" ? 1 : -1 );
}
}
local[ prop.idx ] = value;
return this[ fn ]( local );
};
} );
} );
// Add cssHook and .fx.step function for each named hook.
// accept a space separated string of properties
color.hook = function( hook ) {
var hooks = hook.split( " " );
each( hooks, function( i, hook ) {
jQuery.cssHooks[ hook ] = {
set: function( elem, value ) {
var parsed, curElem,
backgroundColor = "";
if ( value !== "transparent" && ( jQuery.type( value ) !== "string" ||
( parsed = stringParse( value ) ) ) ) {
value = color( parsed || value );
if ( !support.rgba && value._rgba[ 3 ] !== 1 ) {
curElem = hook === "backgroundColor" ? elem.parentNode : elem;
while (
( backgroundColor === "" || backgroundColor === "transparent" ) &&
curElem && curElem.style
) {
try {
backgroundColor = jQuery.css( curElem, "backgroundColor" );
curElem = curElem.parentNode;
} catch ( e ) {
}
}
value = value.blend( backgroundColor && backgroundColor !== "transparent" ?
backgroundColor :
"_default" );
}
value = value.toRgbaString();
}
try {
elem.style[ hook ] = value;
} catch ( e ) {
// Wrapped to prevent IE from throwing errors on "invalid" values like
// 'auto' or 'inherit'
}
}
};
jQuery.fx.step[ hook ] = function( fx ) {
if ( !fx.colorInit ) {
fx.start = color( fx.elem, hook );
fx.end = color( fx.end );
fx.colorInit = true;
}
jQuery.cssHooks[ hook ].set( fx.elem, fx.start.transition( fx.end, fx.pos ) );
};
} );
};
color.hook( stepHooks );
jQuery.cssHooks.borderColor = {
expand: function( value ) {
var expanded = {};
each( [ "Top", "Right", "Bottom", "Left" ], function( i, part ) {
expanded[ "border" + part + "Color" ] = value;
} );
return expanded;
}
};
// Basic color names only.
// Usage of any of the other color names requires adding yourself or including
// jquery.color.svg-names.js.
colors = jQuery.Color.names = {
// 4.1. Basic color keywords
aqua: "#00ffff",
black: "#000000",
blue: "#0000ff",
fuchsia: "#ff00ff",
gray: "#808080",
green: "#008000",
lime: "#00ff00",
maroon: "#800000",
navy: "#000080",
olive: "#808000",
purple: "#800080",
red: "#ff0000",
silver: "#c0c0c0",
teal: "#008080",
white: "#ffffff",
yellow: "#ffff00",
// 4.2.3. "transparent" color keyword
transparent: [ null, null, null, 0 ],
_default: "#ffffff"
};
} )( jQuery );
/******************************************************************************/
/****************************** CLASS ANIMATIONS ******************************/
/******************************************************************************/
( function() {
var classAnimationActions = [ "add", "remove", "toggle" ],
shorthandStyles = {
border: 1,
borderBottom: 1,
borderColor: 1,
borderLeft: 1,
borderRight: 1,
borderTop: 1,
borderWidth: 1,
margin: 1,
padding: 1
};
$.each(
[ "borderLeftStyle", "borderRightStyle", "borderBottomStyle", "borderTopStyle" ],
function( _, prop ) {
$.fx.step[ prop ] = function( fx ) {
if ( fx.end !== "none" && !fx.setAttr || fx.pos === 1 && !fx.setAttr ) {
jQuery.style( fx.elem, prop, fx.end );
fx.setAttr = true;
}
};
}
);
function getElementStyles( elem ) {
var key, len,
style = elem.ownerDocument.defaultView ?
elem.ownerDocument.defaultView.getComputedStyle( elem, null ) :
elem.currentStyle,
styles = {};
if ( style && style.length && style[ 0 ] && style[ style[ 0 ] ] ) {
len = style.length;
while ( len-- ) {
key = style[ len ];
if ( typeof style[ key ] === "string" ) {
styles[ $.camelCase( key ) ] = style[ key ];
}
}
// Support: Opera, IE <9
} else {
for ( key in style ) {
if ( typeof style[ key ] === "string" ) {
styles[ key ] = style[ key ];
}
}
}
return styles;
}
function styleDifference( oldStyle, newStyle ) {
var diff = {},
name, value;
for ( name in newStyle ) {
value = newStyle[ name ];
if ( oldStyle[ name ] !== value ) {
if ( !shorthandStyles[ name ] ) {
if ( $.fx.step[ name ] || !isNaN( parseFloat( value ) ) ) {
diff[ name ] = value;
}
}
}
}
return diff;
}
// Support: jQuery <1.8
if ( !$.fn.addBack ) {
$.fn.addBack = function( selector ) {
return this.add( selector == null ?
this.prevObject : this.prevObject.filter( selector )
);
};
}
$.effects.animateClass = function( value, duration, easing, callback ) {
var o = $.speed( duration, easing, callback );
return this.queue( function() {
var animated = $( this ),
baseClass = animated.attr( "class" ) || "",
applyClassChange,
allAnimations = o.children ? animated.find( "*" ).addBack() : animated;
// Map the animated objects to store the original styles.
allAnimations = allAnimations.map( function() {
var el = $( this );
return {
el: el,
start: getElementStyles( this )
};
} );
// Apply class change
applyClassChange = function() {
$.each( classAnimationActions, function( i, action ) {
if ( value[ action ] ) {
animated[ action + "Class" ]( value[ action ] );
}
} );
};
applyClassChange();
// Map all animated objects again - calculate new styles and diff
allAnimations = allAnimations.map( function() {
this.end = getElementStyles( this.el[ 0 ] );
this.diff = styleDifference( this.start, this.end );
return this;
} );
// Apply original class
animated.attr( "class", baseClass );
// Map all animated objects again - this time collecting a promise
allAnimations = allAnimations.map( function() {
var styleInfo = this,
dfd = $.Deferred(),
opts = $.extend( {}, o, {
queue: false,
complete: function() {
dfd.resolve( styleInfo );
}
} );
this.el.animate( this.diff, opts );
return dfd.promise();
} );
// Once all animations have completed:
$.when.apply( $, allAnimations.get() ).done( function() {
// Set the final class
applyClassChange();
// For each animated element,
// clear all css properties that were animated
$.each( arguments, function() {
var el = this.el;
$.each( this.diff, function( key ) {
el.css( key, "" );
} );
} );
// This is guarnteed to be there if you use jQuery.speed()
// it also handles dequeuing the next anim...
o.complete.call( animated[ 0 ] );
} );
} );
};
$.fn.extend( {
addClass: ( function( orig ) {
return function( classNames, speed, easing, callback ) {
return speed ?
$.effects.animateClass.call( this,
{ add: classNames }, speed, easing, callback ) :
orig.apply( this, arguments );
};
} )( $.fn.addClass ),
removeClass: ( function( orig ) {
return function( classNames, speed, easing, callback ) {
return arguments.length > 1 ?
$.effects.animateClass.call( this,
{ remove: classNames }, speed, easing, callback ) :
orig.apply( this, arguments );
};
} )( $.fn.removeClass ),
toggleClass: ( function( orig ) {
return function( classNames, force, speed, easing, callback ) {
if ( typeof force === "boolean" || force === undefined ) {
if ( !speed ) {
// Without speed parameter
return orig.apply( this, arguments );
} else {
return $.effects.animateClass.call( this,
( force ? { add: classNames } : { remove: classNames } ),
speed, easing, callback );
}
} else {
// Without force parameter
return $.effects.animateClass.call( this,
{ toggle: classNames }, force, speed, easing );
}
};
} )( $.fn.toggleClass ),
switchClass: function( remove, add, speed, easing, callback ) {
return $.effects.animateClass.call( this, {
add: add,
remove: remove
}, speed, easing, callback );
}
} );
} )();
/******************************************************************************/
/*********************************** EFFECTS **********************************/
/******************************************************************************/
( function() {
if ( $.expr && $.expr.filters && $.expr.filters.animated ) {
$.expr.filters.animated = ( function( orig ) {
return function( elem ) {
return !!$( elem ).data( dataSpaceAnimated ) || orig( elem );
};
} )( $.expr.filters.animated );
}
if ( $.uiBackCompat !== false ) {
$.extend( $.effects, {
// Saves a set of properties in a data storage
save: function( element, set ) {
var i = 0, length = set.length;
for ( ; i < length; i++ ) {
if ( set[ i ] !== null ) {
element.data( dataSpace + set[ i ], element[ 0 ].style[ set[ i ] ] );
}
}
},
// Restores a set of previously saved properties from a data storage
restore: function( element, set ) {
var val, i = 0, length = set.length;
for ( ; i < length; i++ ) {
if ( set[ i ] !== null ) {
val = element.data( dataSpace + set[ i ] );
element.css( set[ i ], val );
}
}
},
setMode: function( el, mode ) {
if ( mode === "toggle" ) {
mode = el.is( ":hidden" ) ? "show" : "hide";
}
return mode;
},
// Wraps the element around a wrapper that copies position properties
createWrapper: function( element ) {
// If the element is already wrapped, return it
if ( element.parent().is( ".ui-effects-wrapper" ) ) {
return element.parent();
}
// Wrap the element
var props = {
width: element.outerWidth( true ),
height: element.outerHeight( true ),
"float": element.css( "float" )
},
wrapper = $( "<div></div>" )
.addClass( "ui-effects-wrapper" )
.css( {
fontSize: "100%",
background: "transparent",
border: "none",
margin: 0,
padding: 0
} ),
// Store the size in case width/height are defined in % - Fixes #5245
size = {
width: element.width(),
height: element.height()
},
active = document.activeElement;
// Support: Firefox
// Firefox incorrectly exposes anonymous content
// https://bugzilla.mozilla.org/show_bug.cgi?id=561664
try {
active.id;
} catch ( e ) {
active = document.body;
}
element.wrap( wrapper );
// Fixes #7595 - Elements lose focus when wrapped.
if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
$( active ).trigger( "focus" );
}
// Hotfix for jQuery 1.4 since some change in wrap() seems to actually
// lose the reference to the wrapped element
wrapper = element.parent();
// Transfer positioning properties to the wrapper
if ( element.css( "position" ) === "static" ) {
wrapper.css( { position: "relative" } );
element.css( { position: "relative" } );
} else {
$.extend( props, {
position: element.css( "position" ),
zIndex: element.css( "z-index" )
} );
$.each( [ "top", "left", "bottom", "right" ], function( i, pos ) {
props[ pos ] = element.css( pos );
if ( isNaN( parseInt( props[ pos ], 10 ) ) ) {
props[ pos ] = "auto";
}
} );
element.css( {
position: "relative",
top: 0,
left: 0,
right: "auto",
bottom: "auto"
} );
}
element.css( size );
return wrapper.css( props ).show();
},
removeWrapper: function( element ) {
var active = document.activeElement;
if ( element.parent().is( ".ui-effects-wrapper" ) ) {
element.parent().replaceWith( element );
// Fixes #7595 - Elements lose focus when wrapped.
if ( element[ 0 ] === active || $.contains( element[ 0 ], active ) ) {
$( active ).trigger( "focus" );
}
}
return element;
}
} );
}
$.extend( $.effects, {
version: "1.12.1",
define: function( name, mode, effect ) {
if ( !effect ) {
effect = mode;
mode = "effect";
}
$.effects.effect[ name ] = effect;
$.effects.effect[ name ].mode = mode;
return effect;
},
scaledDimensions: function( element, percent, direction ) {
if ( percent === 0 ) {
return {
height: 0,
width: 0,
outerHeight: 0,
outerWidth: 0
};
}
var x = direction !== "horizontal" ? ( ( percent || 100 ) / 100 ) : 1,
y = direction !== "vertical" ? ( ( percent || 100 ) / 100 ) : 1;
return {
height: element.height() * y,
width: element.width() * x,
outerHeight: element.outerHeight() * y,
outerWidth: element.outerWidth() * x
};
},
clipToBox: function( animation ) {
return {
width: animation.clip.right - animation.clip.left,
height: animation.clip.bottom - animation.clip.top,
left: animation.clip.left,
top: animation.clip.top
};
},
// Injects recently queued functions to be first in line (after "inprogress")
unshift: function( element, queueLength, count ) {
var queue = element.queue();
if ( queueLength > 1 ) {
queue.splice.apply( queue,
[ 1, 0 ].concat( queue.splice( queueLength, count ) ) );
}
element.dequeue();
},
saveStyle: function( element ) {
element.data( dataSpaceStyle, element[ 0 ].style.cssText );
},
restoreStyle: function( element ) {
element[ 0 ].style.cssText = element.data( dataSpaceStyle ) || "";
element.removeData( dataSpaceStyle );
},
mode: function( element, mode ) {
var hidden = element.is( ":hidden" );
if ( mode === "toggle" ) {
mode = hidden ? "show" : "hide";
}
if ( hidden ? mode === "hide" : mode === "show" ) {
mode = "none";
}
return mode;
},
// Translates a [top,left] array into a baseline value
getBaseline: function( origin, original ) {
var y, x;
switch ( origin[ 0 ] ) {
case "top":
y = 0;
break;
case "middle":
y = 0.5;
break;
case "bottom":
y = 1;
break;
default:
y = origin[ 0 ] / original.height;
}
switch ( origin[ 1 ] ) {
case "left":
x = 0;
break;
case "center":
x = 0.5;
break;
case "right":
x = 1;
break;
default:
x = origin[ 1 ] / original.width;
}
return {
x: x,
y: y
};
},
// Creates a placeholder element so that the original element can be made absolute
createPlaceholder: function( element ) {
var placeholder,
cssPosition = element.css( "position" ),
position = element.position();
// Lock in margins first to account for form elements, which
// will change margin if you explicitly set height
// see: http://jsfiddle.net/JZSMt/3/ https://bugs.webkit.org/show_bug.cgi?id=107380
// Support: Safari
element.css( {
marginTop: element.css( "marginTop" ),
marginBottom: element.css( "marginBottom" ),
marginLeft: element.css( "marginLeft" ),
marginRight: element.css( "marginRight" )
} )
.outerWidth( element.outerWidth() )
.outerHeight( element.outerHeight() );
if ( /^(static|relative)/.test( cssPosition ) ) {
cssPosition = "absolute";
placeholder = $( "<" + element[ 0 ].nodeName + ">" ).insertAfter( element ).css( {
// Convert inline to inline block to account for inline elements
// that turn to inline block based on content (like img)
display: /^(inline|ruby)/.test( element.css( "display" ) ) ?
"inline-block" :
"block",
visibility: "hidden",
// Margins need to be set to account for margin collapse
marginTop: element.css( "marginTop" ),
marginBottom: element.css( "marginBottom" ),
marginLeft: element.css( "marginLeft" ),
marginRight: element.css( "marginRight" ),
"float": element.css( "float" )
} )
.outerWidth( element.outerWidth() )
.outerHeight( element.outerHeight() )
.addClass( "ui-effects-placeholder" );
element.data( dataSpace + "placeholder", placeholder );
}
element.css( {
position: cssPosition,
left: position.left,
top: position.top
} );
return placeholder;
},
removePlaceholder: function( element ) {
var dataKey = dataSpace + "placeholder",
placeholder = element.data( dataKey );
if ( placeholder ) {
placeholder.remove();
element.removeData( dataKey );
}
},
// Removes a placeholder if it exists and restores
// properties that were modified during placeholder creation
cleanUp: function( element ) {
$.effects.restoreStyle( element );
$.effects.removePlaceholder( element );
},
setTransition: function( element, list, factor, value ) {
value = value || {};
$.each( list, function( i, x ) {
var unit = element.cssUnit( x );
if ( unit[ 0 ] > 0 ) {
value[ x ] = unit[ 0 ] * factor + unit[ 1 ];
}
} );
return value;
}
} );
// Return an effect options object for the given parameters:
function _normalizeArguments( effect, options, speed, callback ) {
// Allow passing all options as the first parameter
if ( $.isPlainObject( effect ) ) {
options = effect;
effect = effect.effect;
}
// Convert to an object
effect = { effect: effect };
// Catch (effect, null, ...)
if ( options == null ) {
options = {};
}
// Catch (effect, callback)
if ( $.isFunction( options ) ) {
callback = options;
speed = null;
options = {};
}
// Catch (effect, speed, ?)
if ( typeof options === "number" || $.fx.speeds[ options ] ) {
callback = speed;
speed = options;
options = {};
}
// Catch (effect, options, callback)
if ( $.isFunction( speed ) ) {
callback = speed;
speed = null;
}
// Add options to effect
if ( options ) {
$.extend( effect, options );
}
speed = speed || options.duration;
effect.duration = $.fx.off ? 0 :
typeof speed === "number" ? speed :
speed in $.fx.speeds ? $.fx.speeds[ speed ] :
$.fx.speeds._default;
effect.complete = callback || options.complete;
return effect;
}
function standardAnimationOption( option ) {
// Valid standard speeds (nothing, number, named speed)
if ( !option || typeof option === "number" || $.fx.speeds[ option ] ) {
return true;
}
// Invalid strings - treat as "normal" speed
if ( typeof option === "string" && !$.effects.effect[ option ] ) {
return true;
}
// Complete callback
if ( $.isFunction( option ) ) {
return true;
}
// Options hash (but not naming an effect)
if ( typeof option === "object" && !option.effect ) {
return true;
}
// Didn't match any standard API
return false;
}
$.fn.extend( {
effect: function( /* effect, options, speed, callback */ ) {
var args = _normalizeArguments.apply( this, arguments ),
effectMethod = $.effects.effect[ args.effect ],
defaultMode = effectMethod.mode,
queue = args.queue,
queueName = queue || "fx",
complete = args.complete,
mode = args.mode,
modes = [],
prefilter = function( next ) {
var el = $( this ),
normalizedMode = $.effects.mode( el, mode ) || defaultMode;
// Sentinel for duck-punching the :animated psuedo-selector
el.data( dataSpaceAnimated, true );
// Save effect mode for later use,
// we can't just call $.effects.mode again later,
// as the .show() below destroys the initial state
modes.push( normalizedMode );
// See $.uiBackCompat inside of run() for removal of defaultMode in 1.13
if ( defaultMode && ( normalizedMode === "show" ||
( normalizedMode === defaultMode && normalizedMode === "hide" ) ) ) {
el.show();
}
if ( !defaultMode || normalizedMode !== "none" ) {
$.effects.saveStyle( el );
}
if ( $.isFunction( next ) ) {
next();
}
};
if ( $.fx.off || !effectMethod ) {
// Delegate to the original method (e.g., .show()) if possible
if ( mode ) {
return this[ mode ]( args.duration, complete );
} else {
return this.each( function() {
if ( complete ) {
complete.call( this );
}
} );
}
}
function run( next ) {
var elem = $( this );
function cleanup() {
elem.removeData( dataSpaceAnimated );
$.effects.cleanUp( elem );
if ( args.mode === "hide" ) {
elem.hide();
}
done();
}
function done() {
if ( $.isFunction( complete ) ) {
complete.call( elem[ 0 ] );
}
if ( $.isFunction( next ) ) {
next();
}
}
// Override mode option on a per element basis,
// as toggle can be either show or hide depending on element state
args.mode = modes.shift();
if ( $.uiBackCompat !== false && !defaultMode ) {
if ( elem.is( ":hidden" ) ? mode === "hide" : mode === "show" ) {
// Call the core method to track "olddisplay" properly
elem[ mode ]();
done();
} else {
effectMethod.call( elem[ 0 ], args, done );
}
} else {
if ( args.mode === "none" ) {
// Call the core method to track "olddisplay" properly
elem[ mode ]();
done();
} else {
effectMethod.call( elem[ 0 ], args, cleanup );
}
}
}
// Run prefilter on all elements first to ensure that
// any showing or hiding happens before placeholder creation,
// which ensures that any layout changes are correctly captured.
return queue === false ?
this.each( prefilter ).each( run ) :
this.queue( queueName, prefilter ).queue( queueName, run );
},
show: ( function( orig ) {
return function( option ) {
if ( standardAnimationOption( option ) ) {
return orig.apply( this, arguments );
} else {
var args = _normalizeArguments.apply( this, arguments );
args.mode = "show";
return this.effect.call( this, args );
}
};
} )( $.fn.show ),
hide: ( function( orig ) {
return function( option ) {
if ( standardAnimationOption( option ) ) {
return orig.apply( this, arguments );
} else {
var args = _normalizeArguments.apply( this, arguments );
args.mode = "hide";
return this.effect.call( this, args );
}
};
} )( $.fn.hide ),
toggle: ( function( orig ) {
return function( option ) {
if ( standardAnimationOption( option ) || typeof option === "boolean" ) {
return orig.apply( this, arguments );
} else {
var args = _normalizeArguments.apply( this, arguments );
args.mode = "toggle";
return this.effect.call( this, args );
}
};
} )( $.fn.toggle ),
cssUnit: function( key ) {
var style = this.css( key ),
val = [];
$.each( [ "em", "px", "%", "pt" ], function( i, unit ) {
if ( style.indexOf( unit ) > 0 ) {
val = [ parseFloat( style ), unit ];
}
} );
return val;
},
cssClip: function( clipObj ) {
if ( clipObj ) {
return this.css( "clip", "rect(" + clipObj.top + "px " + clipObj.right + "px " +
clipObj.bottom + "px " + clipObj.left + "px)" );
}
return parseClip( this.css( "clip" ), this );
},
transfer: function( options, done ) {
var element = $( this ),
target = $( options.to ),
targetFixed = target.css( "position" ) === "fixed",
body = $( "body" ),
fixTop = targetFixed ? body.scrollTop() : 0,
fixLeft = targetFixed ? body.scrollLeft() : 0,
endPosition = target.offset(),
animation = {
top: endPosition.top - fixTop,
left: endPosition.left - fixLeft,
height: target.innerHeight(),
width: target.innerWidth()
},
startPosition = element.offset(),
transfer = $( "<div class='ui-effects-transfer'></div>" )
.appendTo( "body" )
.addClass( options.className )
.css( {
top: startPosition.top - fixTop,
left: startPosition.left - fixLeft,
height: element.innerHeight(),
width: element.innerWidth(),
position: targetFixed ? "fixed" : "absolute"
} )
.animate( animation, options.duration, options.easing, function() {
transfer.remove();
if ( $.isFunction( done ) ) {
done();
}
} );
}
} );
function parseClip( str, element ) {
var outerWidth = element.outerWidth(),
outerHeight = element.outerHeight(),
clipRegex = /^rect\((-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto),?\s*(-?\d*\.?\d*px|-?\d+%|auto)\)$/,
values = clipRegex.exec( str ) || [ "", 0, outerWidth, outerHeight, 0 ];
return {
top: parseFloat( values[ 1 ] ) || 0,
right: values[ 2 ] === "auto" ? outerWidth : parseFloat( values[ 2 ] ),
bottom: values[ 3 ] === "auto" ? outerHeight : parseFloat( values[ 3 ] ),
left: parseFloat( values[ 4 ] ) || 0
};
}
$.fx.step.clip = function( fx ) {
if ( !fx.clipInit ) {
fx.start = $( fx.elem ).cssClip();
if ( typeof fx.end === "string" ) {
fx.end = parseClip( fx.end, fx.elem );
}
fx.clipInit = true;
}
$( fx.elem ).cssClip( {
top: fx.pos * ( fx.end.top - fx.start.top ) + fx.start.top,
right: fx.pos * ( fx.end.right - fx.start.right ) + fx.start.right,
bottom: fx.pos * ( fx.end.bottom - fx.start.bottom ) + fx.start.bottom,
left: fx.pos * ( fx.end.left - fx.start.left ) + fx.start.left
} );
};
} )();
/******************************************************************************/
/*********************************** EASING ***********************************/
/******************************************************************************/
( function() {
// Based on easing equations from Robert Penner (http://www.robertpenner.com/easing)
var baseEasings = {};
$.each( [ "Quad", "Cubic", "Quart", "Quint", "Expo" ], function( i, name ) {
baseEasings[ name ] = function( p ) {
return Math.pow( p, i + 2 );
};
} );
$.extend( baseEasings, {
Sine: function( p ) {
return 1 - Math.cos( p * Math.PI / 2 );
},
Circ: function( p ) {
return 1 - Math.sqrt( 1 - p * p );
},
Elastic: function( p ) {
return p === 0 || p === 1 ? p :
-Math.pow( 2, 8 * ( p - 1 ) ) * Math.sin( ( ( p - 1 ) * 80 - 7.5 ) * Math.PI / 15 );
},
Back: function( p ) {
return p * p * ( 3 * p - 2 );
},
Bounce: function( p ) {
var pow2,
bounce = 4;
while ( p < ( ( pow2 = Math.pow( 2, --bounce ) ) - 1 ) / 11 ) {}
return 1 / Math.pow( 4, 3 - bounce ) - 7.5625 * Math.pow( ( pow2 * 3 - 2 ) / 22 - p, 2 );
}
} );
$.each( baseEasings, function( name, easeIn ) {
$.easing[ "easeIn" + name ] = easeIn;
$.easing[ "easeOut" + name ] = function( p ) {
return 1 - easeIn( 1 - p );
};
$.easing[ "easeInOut" + name ] = function( p ) {
return p < 0.5 ?
easeIn( p * 2 ) / 2 :
1 - easeIn( p * -2 + 2 ) / 2;
};
} );
} )();
var effect = $.effects;
/*!
* jQuery UI Effects Blind 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Blind Effect
//>>group: Effects
//>>description: Blinds the element.
//>>docs: http://api.jqueryui.com/blind-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectBlind = $.effects.define( "blind", "hide", function( options, done ) {
var map = {
up: [ "bottom", "top" ],
vertical: [ "bottom", "top" ],
down: [ "top", "bottom" ],
left: [ "right", "left" ],
horizontal: [ "right", "left" ],
right: [ "left", "right" ]
},
element = $( this ),
direction = options.direction || "up",
start = element.cssClip(),
animate = { clip: $.extend( {}, start ) },
placeholder = $.effects.createPlaceholder( element );
animate.clip[ map[ direction ][ 0 ] ] = animate.clip[ map[ direction ][ 1 ] ];
if ( options.mode === "show" ) {
element.cssClip( animate.clip );
if ( placeholder ) {
placeholder.css( $.effects.clipToBox( animate ) );
}
animate.clip = start;
}
if ( placeholder ) {
placeholder.animate( $.effects.clipToBox( animate ), options.duration, options.easing );
}
element.animate( animate, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Bounce 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Bounce Effect
//>>group: Effects
//>>description: Bounces an element horizontally or vertically n times.
//>>docs: http://api.jqueryui.com/bounce-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectBounce = $.effects.define( "bounce", function( options, done ) {
var upAnim, downAnim, refValue,
element = $( this ),
// Defaults:
mode = options.mode,
hide = mode === "hide",
show = mode === "show",
direction = options.direction || "up",
distance = options.distance,
times = options.times || 5,
// Number of internal animations
anims = times * 2 + ( show || hide ? 1 : 0 ),
speed = options.duration / anims,
easing = options.easing,
// Utility:
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
motion = ( direction === "up" || direction === "left" ),
i = 0,
queuelen = element.queue().length;
$.effects.createPlaceholder( element );
refValue = element.css( ref );
// Default distance for the BIGGEST bounce is the outer Distance / 3
if ( !distance ) {
distance = element[ ref === "top" ? "outerHeight" : "outerWidth" ]() / 3;
}
if ( show ) {
downAnim = { opacity: 1 };
downAnim[ ref ] = refValue;
// If we are showing, force opacity 0 and set the initial position
// then do the "first" animation
element
.css( "opacity", 0 )
.css( ref, motion ? -distance * 2 : distance * 2 )
.animate( downAnim, speed, easing );
}
// Start at the smallest distance if we are hiding
if ( hide ) {
distance = distance / Math.pow( 2, times - 1 );
}
downAnim = {};
downAnim[ ref ] = refValue;
// Bounces up/down/left/right then back to 0 -- times * 2 animations happen here
for ( ; i < times; i++ ) {
upAnim = {};
upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
element
.animate( upAnim, speed, easing )
.animate( downAnim, speed, easing );
distance = hide ? distance * 2 : distance / 2;
}
// Last Bounce when Hiding
if ( hide ) {
upAnim = { opacity: 0 };
upAnim[ ref ] = ( motion ? "-=" : "+=" ) + distance;
element.animate( upAnim, speed, easing );
}
element.queue( done );
$.effects.unshift( element, queuelen, anims + 1 );
} );
/*!
* jQuery UI Effects Clip 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Clip Effect
//>>group: Effects
//>>description: Clips the element on and off like an old TV.
//>>docs: http://api.jqueryui.com/clip-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectClip = $.effects.define( "clip", "hide", function( options, done ) {
var start,
animate = {},
element = $( this ),
direction = options.direction || "vertical",
both = direction === "both",
horizontal = both || direction === "horizontal",
vertical = both || direction === "vertical";
start = element.cssClip();
animate.clip = {
top: vertical ? ( start.bottom - start.top ) / 2 : start.top,
right: horizontal ? ( start.right - start.left ) / 2 : start.right,
bottom: vertical ? ( start.bottom - start.top ) / 2 : start.bottom,
left: horizontal ? ( start.right - start.left ) / 2 : start.left
};
$.effects.createPlaceholder( element );
if ( options.mode === "show" ) {
element.cssClip( animate.clip );
animate.clip = start;
}
element.animate( animate, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Drop 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Drop Effect
//>>group: Effects
//>>description: Moves an element in one direction and hides it at the same time.
//>>docs: http://api.jqueryui.com/drop-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectDrop = $.effects.define( "drop", "hide", function( options, done ) {
var distance,
element = $( this ),
mode = options.mode,
show = mode === "show",
direction = options.direction || "left",
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
motion = ( direction === "up" || direction === "left" ) ? "-=" : "+=",
oppositeMotion = ( motion === "+=" ) ? "-=" : "+=",
animation = {
opacity: 0
};
$.effects.createPlaceholder( element );
distance = options.distance ||
element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ) / 2;
animation[ ref ] = motion + distance;
if ( show ) {
element.css( animation );
animation[ ref ] = oppositeMotion + distance;
animation.opacity = 1;
}
// Animate
element.animate( animation, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Explode 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Explode Effect
//>>group: Effects
// jscs:disable maximumLineLength
//>>description: Explodes an element in all directions into n pieces. Implodes an element to its original wholeness.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/explode-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectExplode = $.effects.define( "explode", "hide", function( options, done ) {
var i, j, left, top, mx, my,
rows = options.pieces ? Math.round( Math.sqrt( options.pieces ) ) : 3,
cells = rows,
element = $( this ),
mode = options.mode,
show = mode === "show",
// Show and then visibility:hidden the element before calculating offset
offset = element.show().css( "visibility", "hidden" ).offset(),
// Width and height of a piece
width = Math.ceil( element.outerWidth() / cells ),
height = Math.ceil( element.outerHeight() / rows ),
pieces = [];
// Children animate complete:
function childComplete() {
pieces.push( this );
if ( pieces.length === rows * cells ) {
animComplete();
}
}
// Clone the element for each row and cell.
for ( i = 0; i < rows; i++ ) { // ===>
top = offset.top + i * height;
my = i - ( rows - 1 ) / 2;
for ( j = 0; j < cells; j++ ) { // |||
left = offset.left + j * width;
mx = j - ( cells - 1 ) / 2;
// Create a clone of the now hidden main element that will be absolute positioned
// within a wrapper div off the -left and -top equal to size of our pieces
element
.clone()
.appendTo( "body" )
.wrap( "<div></div>" )
.css( {
position: "absolute",
visibility: "visible",
left: -j * width,
top: -i * height
} )
// Select the wrapper - make it overflow: hidden and absolute positioned based on
// where the original was located +left and +top equal to the size of pieces
.parent()
.addClass( "ui-effects-explode" )
.css( {
position: "absolute",
overflow: "hidden",
width: width,
height: height,
left: left + ( show ? mx * width : 0 ),
top: top + ( show ? my * height : 0 ),
opacity: show ? 0 : 1
} )
.animate( {
left: left + ( show ? 0 : mx * width ),
top: top + ( show ? 0 : my * height ),
opacity: show ? 1 : 0
}, options.duration || 500, options.easing, childComplete );
}
}
function animComplete() {
element.css( {
visibility: "visible"
} );
$( pieces ).remove();
done();
}
} );
/*!
* jQuery UI Effects Fade 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Fade Effect
//>>group: Effects
//>>description: Fades the element.
//>>docs: http://api.jqueryui.com/fade-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectFade = $.effects.define( "fade", "toggle", function( options, done ) {
var show = options.mode === "show";
$( this )
.css( "opacity", show ? 0 : 1 )
.animate( {
opacity: show ? 1 : 0
}, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Fold 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Fold Effect
//>>group: Effects
//>>description: Folds an element first horizontally and then vertically.
//>>docs: http://api.jqueryui.com/fold-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectFold = $.effects.define( "fold", "hide", function( options, done ) {
// Create element
var element = $( this ),
mode = options.mode,
show = mode === "show",
hide = mode === "hide",
size = options.size || 15,
percent = /([0-9]+)%/.exec( size ),
horizFirst = !!options.horizFirst,
ref = horizFirst ? [ "right", "bottom" ] : [ "bottom", "right" ],
duration = options.duration / 2,
placeholder = $.effects.createPlaceholder( element ),
start = element.cssClip(),
animation1 = { clip: $.extend( {}, start ) },
animation2 = { clip: $.extend( {}, start ) },
distance = [ start[ ref[ 0 ] ], start[ ref[ 1 ] ] ],
queuelen = element.queue().length;
if ( percent ) {
size = parseInt( percent[ 1 ], 10 ) / 100 * distance[ hide ? 0 : 1 ];
}
animation1.clip[ ref[ 0 ] ] = size;
animation2.clip[ ref[ 0 ] ] = size;
animation2.clip[ ref[ 1 ] ] = 0;
if ( show ) {
element.cssClip( animation2.clip );
if ( placeholder ) {
placeholder.css( $.effects.clipToBox( animation2 ) );
}
animation2.clip = start;
}
// Animate
element
.queue( function( next ) {
if ( placeholder ) {
placeholder
.animate( $.effects.clipToBox( animation1 ), duration, options.easing )
.animate( $.effects.clipToBox( animation2 ), duration, options.easing );
}
next();
} )
.animate( animation1, duration, options.easing )
.animate( animation2, duration, options.easing )
.queue( done );
$.effects.unshift( element, queuelen, 4 );
} );
/*!
* jQuery UI Effects Highlight 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Highlight Effect
//>>group: Effects
//>>description: Highlights the background of an element in a defined color for a custom duration.
//>>docs: http://api.jqueryui.com/highlight-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectHighlight = $.effects.define( "highlight", "show", function( options, done ) {
var element = $( this ),
animation = {
backgroundColor: element.css( "backgroundColor" )
};
if ( options.mode === "hide" ) {
animation.opacity = 0;
}
$.effects.saveStyle( element );
element
.css( {
backgroundImage: "none",
backgroundColor: options.color || "#ffff99"
} )
.animate( animation, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Size 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Size Effect
//>>group: Effects
//>>description: Resize an element to a specified width and height.
//>>docs: http://api.jqueryui.com/size-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectSize = $.effects.define( "size", function( options, done ) {
// Create element
var baseline, factor, temp,
element = $( this ),
// Copy for children
cProps = [ "fontSize" ],
vProps = [ "borderTopWidth", "borderBottomWidth", "paddingTop", "paddingBottom" ],
hProps = [ "borderLeftWidth", "borderRightWidth", "paddingLeft", "paddingRight" ],
// Set options
mode = options.mode,
restore = mode !== "effect",
scale = options.scale || "both",
origin = options.origin || [ "middle", "center" ],
position = element.css( "position" ),
pos = element.position(),
original = $.effects.scaledDimensions( element ),
from = options.from || original,
to = options.to || $.effects.scaledDimensions( element, 0 );
$.effects.createPlaceholder( element );
if ( mode === "show" ) {
temp = from;
from = to;
to = temp;
}
// Set scaling factor
factor = {
from: {
y: from.height / original.height,
x: from.width / original.width
},
to: {
y: to.height / original.height,
x: to.width / original.width
}
};
// Scale the css box
if ( scale === "box" || scale === "both" ) {
// Vertical props scaling
if ( factor.from.y !== factor.to.y ) {
from = $.effects.setTransition( element, vProps, factor.from.y, from );
to = $.effects.setTransition( element, vProps, factor.to.y, to );
}
// Horizontal props scaling
if ( factor.from.x !== factor.to.x ) {
from = $.effects.setTransition( element, hProps, factor.from.x, from );
to = $.effects.setTransition( element, hProps, factor.to.x, to );
}
}
// Scale the content
if ( scale === "content" || scale === "both" ) {
// Vertical props scaling
if ( factor.from.y !== factor.to.y ) {
from = $.effects.setTransition( element, cProps, factor.from.y, from );
to = $.effects.setTransition( element, cProps, factor.to.y, to );
}
}
// Adjust the position properties based on the provided origin points
if ( origin ) {
baseline = $.effects.getBaseline( origin, original );
from.top = ( original.outerHeight - from.outerHeight ) * baseline.y + pos.top;
from.left = ( original.outerWidth - from.outerWidth ) * baseline.x + pos.left;
to.top = ( original.outerHeight - to.outerHeight ) * baseline.y + pos.top;
to.left = ( original.outerWidth - to.outerWidth ) * baseline.x + pos.left;
}
element.css( from );
// Animate the children if desired
if ( scale === "content" || scale === "both" ) {
vProps = vProps.concat( [ "marginTop", "marginBottom" ] ).concat( cProps );
hProps = hProps.concat( [ "marginLeft", "marginRight" ] );
// Only animate children with width attributes specified
// TODO: is this right? should we include anything with css width specified as well
element.find( "*[width]" ).each( function() {
var child = $( this ),
childOriginal = $.effects.scaledDimensions( child ),
childFrom = {
height: childOriginal.height * factor.from.y,
width: childOriginal.width * factor.from.x,
outerHeight: childOriginal.outerHeight * factor.from.y,
outerWidth: childOriginal.outerWidth * factor.from.x
},
childTo = {
height: childOriginal.height * factor.to.y,
width: childOriginal.width * factor.to.x,
outerHeight: childOriginal.height * factor.to.y,
outerWidth: childOriginal.width * factor.to.x
};
// Vertical props scaling
if ( factor.from.y !== factor.to.y ) {
childFrom = $.effects.setTransition( child, vProps, factor.from.y, childFrom );
childTo = $.effects.setTransition( child, vProps, factor.to.y, childTo );
}
// Horizontal props scaling
if ( factor.from.x !== factor.to.x ) {
childFrom = $.effects.setTransition( child, hProps, factor.from.x, childFrom );
childTo = $.effects.setTransition( child, hProps, factor.to.x, childTo );
}
if ( restore ) {
$.effects.saveStyle( child );
}
// Animate children
child.css( childFrom );
child.animate( childTo, options.duration, options.easing, function() {
// Restore children
if ( restore ) {
$.effects.restoreStyle( child );
}
} );
} );
}
// Animate
element.animate( to, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: function() {
var offset = element.offset();
if ( to.opacity === 0 ) {
element.css( "opacity", from.opacity );
}
if ( !restore ) {
element
.css( "position", position === "static" ? "relative" : position )
.offset( offset );
// Need to save style here so that automatic style restoration
// doesn't restore to the original styles from before the animation.
$.effects.saveStyle( element );
}
done();
}
} );
} );
/*!
* jQuery UI Effects Scale 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Scale Effect
//>>group: Effects
//>>description: Grows or shrinks an element and its content.
//>>docs: http://api.jqueryui.com/scale-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectScale = $.effects.define( "scale", function( options, done ) {
// Create element
var el = $( this ),
mode = options.mode,
percent = parseInt( options.percent, 10 ) ||
( parseInt( options.percent, 10 ) === 0 ? 0 : ( mode !== "effect" ? 0 : 100 ) ),
newOptions = $.extend( true, {
from: $.effects.scaledDimensions( el ),
to: $.effects.scaledDimensions( el, percent, options.direction || "both" ),
origin: options.origin || [ "middle", "center" ]
}, options );
// Fade option to support puff
if ( options.fade ) {
newOptions.from.opacity = 1;
newOptions.to.opacity = 0;
}
$.effects.effect.size.call( this, newOptions, done );
} );
/*!
* jQuery UI Effects Puff 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Puff Effect
//>>group: Effects
//>>description: Creates a puff effect by scaling the element up and hiding it at the same time.
//>>docs: http://api.jqueryui.com/puff-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectPuff = $.effects.define( "puff", "hide", function( options, done ) {
var newOptions = $.extend( true, {}, options, {
fade: true,
percent: parseInt( options.percent, 10 ) || 150
} );
$.effects.effect.scale.call( this, newOptions, done );
} );
/*!
* jQuery UI Effects Pulsate 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Pulsate Effect
//>>group: Effects
//>>description: Pulsates an element n times by changing the opacity to zero and back.
//>>docs: http://api.jqueryui.com/pulsate-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectPulsate = $.effects.define( "pulsate", "show", function( options, done ) {
var element = $( this ),
mode = options.mode,
show = mode === "show",
hide = mode === "hide",
showhide = show || hide,
// Showing or hiding leaves off the "last" animation
anims = ( ( options.times || 5 ) * 2 ) + ( showhide ? 1 : 0 ),
duration = options.duration / anims,
animateTo = 0,
i = 1,
queuelen = element.queue().length;
if ( show || !element.is( ":visible" ) ) {
element.css( "opacity", 0 ).show();
animateTo = 1;
}
// Anims - 1 opacity "toggles"
for ( ; i < anims; i++ ) {
element.animate( { opacity: animateTo }, duration, options.easing );
animateTo = 1 - animateTo;
}
element.animate( { opacity: animateTo }, duration, options.easing );
element.queue( done );
$.effects.unshift( element, queuelen, anims + 1 );
} );
/*!
* jQuery UI Effects Shake 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Shake Effect
//>>group: Effects
//>>description: Shakes an element horizontally or vertically n times.
//>>docs: http://api.jqueryui.com/shake-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectShake = $.effects.define( "shake", function( options, done ) {
var i = 1,
element = $( this ),
direction = options.direction || "left",
distance = options.distance || 20,
times = options.times || 3,
anims = times * 2 + 1,
speed = Math.round( options.duration / anims ),
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
positiveMotion = ( direction === "up" || direction === "left" ),
animation = {},
animation1 = {},
animation2 = {},
queuelen = element.queue().length;
$.effects.createPlaceholder( element );
// Animation
animation[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance;
animation1[ ref ] = ( positiveMotion ? "+=" : "-=" ) + distance * 2;
animation2[ ref ] = ( positiveMotion ? "-=" : "+=" ) + distance * 2;
// Animate
element.animate( animation, speed, options.easing );
// Shakes
for ( ; i < times; i++ ) {
element
.animate( animation1, speed, options.easing )
.animate( animation2, speed, options.easing );
}
element
.animate( animation1, speed, options.easing )
.animate( animation, speed / 2, options.easing )
.queue( done );
$.effects.unshift( element, queuelen, anims + 1 );
} );
/*!
* jQuery UI Effects Slide 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Slide Effect
//>>group: Effects
//>>description: Slides an element in and out of the viewport.
//>>docs: http://api.jqueryui.com/slide-effect/
//>>demos: http://jqueryui.com/effect/
var effectsEffectSlide = $.effects.define( "slide", "show", function( options, done ) {
var startClip, startRef,
element = $( this ),
map = {
up: [ "bottom", "top" ],
down: [ "top", "bottom" ],
left: [ "right", "left" ],
right: [ "left", "right" ]
},
mode = options.mode,
direction = options.direction || "left",
ref = ( direction === "up" || direction === "down" ) ? "top" : "left",
positiveMotion = ( direction === "up" || direction === "left" ),
distance = options.distance ||
element[ ref === "top" ? "outerHeight" : "outerWidth" ]( true ),
animation = {};
$.effects.createPlaceholder( element );
startClip = element.cssClip();
startRef = element.position()[ ref ];
// Define hide animation
animation[ ref ] = ( positiveMotion ? -1 : 1 ) * distance + startRef;
animation.clip = element.cssClip();
animation.clip[ map[ direction ][ 1 ] ] = animation.clip[ map[ direction ][ 0 ] ];
// Reverse the animation if we're showing
if ( mode === "show" ) {
element.cssClip( animation.clip );
element.css( ref, animation[ ref ] );
animation.clip = startClip;
animation[ ref ] = startRef;
}
// Actually animate
element.animate( animation, {
queue: false,
duration: options.duration,
easing: options.easing,
complete: done
} );
} );
/*!
* jQuery UI Effects Transfer 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Transfer Effect
//>>group: Effects
//>>description: Displays a transfer effect from one element to another.
//>>docs: http://api.jqueryui.com/transfer-effect/
//>>demos: http://jqueryui.com/effect/
var effect;
if ( $.uiBackCompat !== false ) {
effect = $.effects.define( "transfer", function( options, done ) {
$( this ).transfer( options, done );
} );
}
var effectsEffectTransfer = effect;
/*!
* jQuery UI Focusable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: :focusable Selector
//>>group: Core
//>>description: Selects elements which can be focused.
//>>docs: http://api.jqueryui.com/focusable-selector/
// Selectors
$.ui.focusable = function( element, hasTabindex ) {
var map, mapName, img, focusableIfVisible, fieldset,
nodeName = element.nodeName.toLowerCase();
if ( "area" === nodeName ) {
map = element.parentNode;
mapName = map.name;
if ( !element.href || !mapName || map.nodeName.toLowerCase() !== "map" ) {
return false;
}
img = $( "img[usemap='#" + mapName + "']" );
return img.length > 0 && img.is( ":visible" );
}
if ( /^(input|select|textarea|button|object)$/.test( nodeName ) ) {
focusableIfVisible = !element.disabled;
if ( focusableIfVisible ) {
// Form controls within a disabled fieldset are disabled.
// However, controls within the fieldset's legend do not get disabled.
// Since controls generally aren't placed inside legends, we skip
// this portion of the check.
fieldset = $( element ).closest( "fieldset" )[ 0 ];
if ( fieldset ) {
focusableIfVisible = !fieldset.disabled;
}
}
} else if ( "a" === nodeName ) {
focusableIfVisible = element.href || hasTabindex;
} else {
focusableIfVisible = hasTabindex;
}
return focusableIfVisible && $( element ).is( ":visible" ) && visible( $( element ) );
};
// Support: IE 8 only
// IE 8 doesn't resolve inherit to visible/hidden for computed values
function visible( element ) {
var visibility = element.css( "visibility" );
while ( visibility === "inherit" ) {
element = element.parent();
visibility = element.css( "visibility" );
}
return visibility !== "hidden";
}
$.extend( $.expr[ ":" ], {
focusable: function( element ) {
return $.ui.focusable( element, $.attr( element, "tabindex" ) != null );
}
} );
var focusable = $.ui.focusable;
// Support: IE8 Only
// IE8 does not support the form attribute and when it is supplied. It overwrites the form prop
// with a string, so we need to find the proper form.
var form = $.fn.form = function() {
return typeof this[ 0 ].form === "string" ? this.closest( "form" ) : $( this[ 0 ].form );
};
/*!
* jQuery UI Form Reset Mixin 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Form Reset Mixin
//>>group: Core
//>>description: Refresh input widgets when their form is reset
//>>docs: http://api.jqueryui.com/form-reset-mixin/
var formResetMixin = $.ui.formResetMixin = {
_formResetHandler: function() {
var form = $( this );
// Wait for the form reset to actually happen before refreshing
setTimeout( function() {
var instances = form.data( "ui-form-reset-instances" );
$.each( instances, function() {
this.refresh();
} );
} );
},
_bindFormResetHandler: function() {
this.form = this.element.form();
if ( !this.form.length ) {
return;
}
var instances = this.form.data( "ui-form-reset-instances" ) || [];
if ( !instances.length ) {
// We don't use _on() here because we use a single event handler per form
this.form.on( "reset.ui-form-reset", this._formResetHandler );
}
instances.push( this );
this.form.data( "ui-form-reset-instances", instances );
},
_unbindFormResetHandler: function() {
if ( !this.form.length ) {
return;
}
var instances = this.form.data( "ui-form-reset-instances" );
instances.splice( $.inArray( this, instances ), 1 );
if ( instances.length ) {
this.form.data( "ui-form-reset-instances", instances );
} else {
this.form
.removeData( "ui-form-reset-instances" )
.off( "reset.ui-form-reset" );
}
}
};
/*!
* jQuery UI Support for jQuery core 1.7.x 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*
*/
//>>label: jQuery 1.7 Support
//>>group: Core
//>>description: Support version 1.7.x of jQuery core
// Support: jQuery 1.7 only
// Not a great way to check versions, but since we only support 1.7+ and only
// need to detect <1.8, this is a simple check that should suffice. Checking
// for "1.7." would be a bit safer, but the version string is 1.7, not 1.7.0
// and we'll never reach 1.70.0 (if we do, we certainly won't be supporting
// 1.7 anymore). See #11197 for why we're not using feature detection.
if ( $.fn.jquery.substring( 0, 3 ) === "1.7" ) {
// Setters for .innerWidth(), .innerHeight(), .outerWidth(), .outerHeight()
// Unlike jQuery Core 1.8+, these only support numeric values to set the
// dimensions in pixels
$.each( [ "Width", "Height" ], function( i, name ) {
var side = name === "Width" ? [ "Left", "Right" ] : [ "Top", "Bottom" ],
type = name.toLowerCase(),
orig = {
innerWidth: $.fn.innerWidth,
innerHeight: $.fn.innerHeight,
outerWidth: $.fn.outerWidth,
outerHeight: $.fn.outerHeight
};
function reduce( elem, size, border, margin ) {
$.each( side, function() {
size -= parseFloat( $.css( elem, "padding" + this ) ) || 0;
if ( border ) {
size -= parseFloat( $.css( elem, "border" + this + "Width" ) ) || 0;
}
if ( margin ) {
size -= parseFloat( $.css( elem, "margin" + this ) ) || 0;
}
} );
return size;
}
$.fn[ "inner" + name ] = function( size ) {
if ( size === undefined ) {
return orig[ "inner" + name ].call( this );
}
return this.each( function() {
$( this ).css( type, reduce( this, size ) + "px" );
} );
};
$.fn[ "outer" + name ] = function( size, margin ) {
if ( typeof size !== "number" ) {
return orig[ "outer" + name ].call( this, size );
}
return this.each( function() {
$( this ).css( type, reduce( this, size, true, margin ) + "px" );
} );
};
} );
$.fn.addBack = function( selector ) {
return this.add( selector == null ?
this.prevObject : this.prevObject.filter( selector )
);
};
}
;
/*!
* jQuery UI Keycode 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Keycode
//>>group: Core
//>>description: Provide keycodes as keynames
//>>docs: http://api.jqueryui.com/jQuery.ui.keyCode/
var keycode = $.ui.keyCode = {
BACKSPACE: 8,
COMMA: 188,
DELETE: 46,
DOWN: 40,
END: 35,
ENTER: 13,
ESCAPE: 27,
HOME: 36,
LEFT: 37,
PAGE_DOWN: 34,
PAGE_UP: 33,
PERIOD: 190,
RIGHT: 39,
SPACE: 32,
TAB: 9,
UP: 38
};
// Internal use only
var escapeSelector = $.ui.escapeSelector = ( function() {
var selectorEscape = /([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;
return function( selector ) {
return selector.replace( selectorEscape, "\\$1" );
};
} )();
/*!
* jQuery UI Labels 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: labels
//>>group: Core
//>>description: Find all the labels associated with a given input
//>>docs: http://api.jqueryui.com/labels/
var labels = $.fn.labels = function() {
var ancestor, selector, id, labels, ancestors;
// Check control.labels first
if ( this[ 0 ].labels && this[ 0 ].labels.length ) {
return this.pushStack( this[ 0 ].labels );
}
// Support: IE <= 11, FF <= 37, Android <= 2.3 only
// Above browsers do not support control.labels. Everything below is to support them
// as well as document fragments. control.labels does not work on document fragments
labels = this.eq( 0 ).parents( "label" );
// Look for the label based on the id
id = this.attr( "id" );
if ( id ) {
// We don't search against the document in case the element
// is disconnected from the DOM
ancestor = this.eq( 0 ).parents().last();
// Get a full set of top level ancestors
ancestors = ancestor.add( ancestor.length ? ancestor.siblings() : this.siblings() );
// Create a selector for the label based on the id
selector = "label[for='" + $.ui.escapeSelector( id ) + "']";
labels = labels.add( ancestors.find( selector ).addBack( selector ) );
}
// Return whatever we have found for labels
return this.pushStack( labels );
};
/*!
* jQuery UI Scroll Parent 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: scrollParent
//>>group: Core
//>>description: Get the closest ancestor element that is scrollable.
//>>docs: http://api.jqueryui.com/scrollParent/
var scrollParent = $.fn.scrollParent = function( includeHidden ) {
var position = this.css( "position" ),
excludeStaticParent = position === "absolute",
overflowRegex = includeHidden ? /(auto|scroll|hidden)/ : /(auto|scroll)/,
scrollParent = this.parents().filter( function() {
var parent = $( this );
if ( excludeStaticParent && parent.css( "position" ) === "static" ) {
return false;
}
return overflowRegex.test( parent.css( "overflow" ) + parent.css( "overflow-y" ) +
parent.css( "overflow-x" ) );
} ).eq( 0 );
return position === "fixed" || !scrollParent.length ?
$( this[ 0 ].ownerDocument || document ) :
scrollParent;
};
/*!
* jQuery UI Tabbable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: :tabbable Selector
//>>group: Core
//>>description: Selects elements which can be tabbed to.
//>>docs: http://api.jqueryui.com/tabbable-selector/
var tabbable = $.extend( $.expr[ ":" ], {
tabbable: function( element ) {
var tabIndex = $.attr( element, "tabindex" ),
hasTabindex = tabIndex != null;
return ( !hasTabindex || tabIndex >= 0 ) && $.ui.focusable( element, hasTabindex );
}
} );
/*!
* jQuery UI Unique ID 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: uniqueId
//>>group: Core
//>>description: Functions to generate and remove uniqueId's
//>>docs: http://api.jqueryui.com/uniqueId/
var uniqueId = $.fn.extend( {
uniqueId: ( function() {
var uuid = 0;
return function() {
return this.each( function() {
if ( !this.id ) {
this.id = "ui-id-" + ( ++uuid );
}
} );
};
} )(),
removeUniqueId: function() {
return this.each( function() {
if ( /^ui-id-\d+$/.test( this.id ) ) {
$( this ).removeAttr( "id" );
}
} );
}
} );
/*!
* jQuery UI Accordion 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Accordion
//>>group: Widgets
// jscs:disable maximumLineLength
//>>description: Displays collapsible content panels for presenting information in a limited amount of space.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/accordion/
//>>demos: http://jqueryui.com/accordion/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/accordion.css
//>>css.theme: ../../themes/base/theme.css
var widgetsAccordion = $.widget( "ui.accordion", {
version: "1.12.1",
options: {
active: 0,
animate: {},
classes: {
"ui-accordion-header": "ui-corner-top",
"ui-accordion-header-collapsed": "ui-corner-all",
"ui-accordion-content": "ui-corner-bottom"
},
collapsible: false,
event: "click",
header: "> li > :first-child, > :not(li):even",
heightStyle: "auto",
icons: {
activeHeader: "ui-icon-triangle-1-s",
header: "ui-icon-triangle-1-e"
},
// Callbacks
activate: null,
beforeActivate: null
},
hideProps: {
borderTopWidth: "hide",
borderBottomWidth: "hide",
paddingTop: "hide",
paddingBottom: "hide",
height: "hide"
},
showProps: {
borderTopWidth: "show",
borderBottomWidth: "show",
paddingTop: "show",
paddingBottom: "show",
height: "show"
},
_create: function() {
var options = this.options;
this.prevShow = this.prevHide = $();
this._addClass( "ui-accordion", "ui-widget ui-helper-reset" );
this.element.attr( "role", "tablist" );
// Don't allow collapsible: false and active: false / null
if ( !options.collapsible && ( options.active === false || options.active == null ) ) {
options.active = 0;
}
this._processPanels();
// handle negative values
if ( options.active < 0 ) {
options.active += this.headers.length;
}
this._refresh();
},
_getCreateEventData: function() {
return {
header: this.active,
panel: !this.active.length ? $() : this.active.next()
};
},
_createIcons: function() {
var icon, children,
icons = this.options.icons;
if ( icons ) {
icon = $( "<span>" );
this._addClass( icon, "ui-accordion-header-icon", "ui-icon " + icons.header );
icon.prependTo( this.headers );
children = this.active.children( ".ui-accordion-header-icon" );
this._removeClass( children, icons.header )
._addClass( children, null, icons.activeHeader )
._addClass( this.headers, "ui-accordion-icons" );
}
},
_destroyIcons: function() {
this._removeClass( this.headers, "ui-accordion-icons" );
this.headers.children( ".ui-accordion-header-icon" ).remove();
},
_destroy: function() {
var contents;
// Clean up main element
this.element.removeAttr( "role" );
// Clean up headers
this.headers
.removeAttr( "role aria-expanded aria-selected aria-controls tabIndex" )
.removeUniqueId();
this._destroyIcons();
// Clean up content panels
contents = this.headers.next()
.css( "display", "" )
.removeAttr( "role aria-hidden aria-labelledby" )
.removeUniqueId();
if ( this.options.heightStyle !== "content" ) {
contents.css( "height", "" );
}
},
_setOption: function( key, value ) {
if ( key === "active" ) {
// _activate() will handle invalid values and update this.options
this._activate( value );
return;
}
if ( key === "event" ) {
if ( this.options.event ) {
this._off( this.headers, this.options.event );
}
this._setupEvents( value );
}
this._super( key, value );
// Setting collapsible: false while collapsed; open first panel
if ( key === "collapsible" && !value && this.options.active === false ) {
this._activate( 0 );
}
if ( key === "icons" ) {
this._destroyIcons();
if ( value ) {
this._createIcons();
}
}
},
_setOptionDisabled: function( value ) {
this._super( value );
this.element.attr( "aria-disabled", value );
// Support: IE8 Only
// #5332 / #6059 - opacity doesn't cascade to positioned elements in IE
// so we need to add the disabled class to the headers and panels
this._toggleClass( null, "ui-state-disabled", !!value );
this._toggleClass( this.headers.add( this.headers.next() ), null, "ui-state-disabled",
!!value );
},
_keydown: function( event ) {
if ( event.altKey || event.ctrlKey ) {
return;
}
var keyCode = $.ui.keyCode,
length = this.headers.length,
currentIndex = this.headers.index( event.target ),
toFocus = false;
switch ( event.keyCode ) {
case keyCode.RIGHT:
case keyCode.DOWN:
toFocus = this.headers[ ( currentIndex + 1 ) % length ];
break;
case keyCode.LEFT:
case keyCode.UP:
toFocus = this.headers[ ( currentIndex - 1 + length ) % length ];
break;
case keyCode.SPACE:
case keyCode.ENTER:
this._eventHandler( event );
break;
case keyCode.HOME:
toFocus = this.headers[ 0 ];
break;
case keyCode.END:
toFocus = this.headers[ length - 1 ];
break;
}
if ( toFocus ) {
$( event.target ).attr( "tabIndex", -1 );
$( toFocus ).attr( "tabIndex", 0 );
$( toFocus ).trigger( "focus" );
event.preventDefault();
}
},
_panelKeyDown: function( event ) {
if ( event.keyCode === $.ui.keyCode.UP && event.ctrlKey ) {
$( event.currentTarget ).prev().trigger( "focus" );
}
},
refresh: function() {
var options = this.options;
this._processPanels();
// Was collapsed or no panel
if ( ( options.active === false && options.collapsible === true ) ||
!this.headers.length ) {
options.active = false;
this.active = $();
// active false only when collapsible is true
} else if ( options.active === false ) {
this._activate( 0 );
// was active, but active panel is gone
} else if ( this.active.length && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
// all remaining panel are disabled
if ( this.headers.length === this.headers.find( ".ui-state-disabled" ).length ) {
options.active = false;
this.active = $();
// activate previous panel
} else {
this._activate( Math.max( 0, options.active - 1 ) );
}
// was active, active panel still exists
} else {
// make sure active index is correct
options.active = this.headers.index( this.active );
}
this._destroyIcons();
this._refresh();
},
_processPanels: function() {
var prevHeaders = this.headers,
prevPanels = this.panels;
this.headers = this.element.find( this.options.header );
this._addClass( this.headers, "ui-accordion-header ui-accordion-header-collapsed",
"ui-state-default" );
this.panels = this.headers.next().filter( ":not(.ui-accordion-content-active)" ).hide();
this._addClass( this.panels, "ui-accordion-content", "ui-helper-reset ui-widget-content" );
// Avoid memory leaks (#10056)
if ( prevPanels ) {
this._off( prevHeaders.not( this.headers ) );
this._off( prevPanels.not( this.panels ) );
}
},
_refresh: function() {
var maxHeight,
options = this.options,
heightStyle = options.heightStyle,
parent = this.element.parent();
this.active = this._findActive( options.active );
this._addClass( this.active, "ui-accordion-header-active", "ui-state-active" )
._removeClass( this.active, "ui-accordion-header-collapsed" );
this._addClass( this.active.next(), "ui-accordion-content-active" );
this.active.next().show();
this.headers
.attr( "role", "tab" )
.each( function() {
var header = $( this ),
headerId = header.uniqueId().attr( "id" ),
panel = header.next(),
panelId = panel.uniqueId().attr( "id" );
header.attr( "aria-controls", panelId );
panel.attr( "aria-labelledby", headerId );
} )
.next()
.attr( "role", "tabpanel" );
this.headers
.not( this.active )
.attr( {
"aria-selected": "false",
"aria-expanded": "false",
tabIndex: -1
} )
.next()
.attr( {
"aria-hidden": "true"
} )
.hide();
// Make sure at least one header is in the tab order
if ( !this.active.length ) {
this.headers.eq( 0 ).attr( "tabIndex", 0 );
} else {
this.active.attr( {
"aria-selected": "true",
"aria-expanded": "true",
tabIndex: 0
} )
.next()
.attr( {
"aria-hidden": "false"
} );
}
this._createIcons();
this._setupEvents( options.event );
if ( heightStyle === "fill" ) {
maxHeight = parent.height();
this.element.siblings( ":visible" ).each( function() {
var elem = $( this ),
position = elem.css( "position" );
if ( position === "absolute" || position === "fixed" ) {
return;
}
maxHeight -= elem.outerHeight( true );
} );
this.headers.each( function() {
maxHeight -= $( this ).outerHeight( true );
} );
this.headers.next()
.each( function() {
$( this ).height( Math.max( 0, maxHeight -
$( this ).innerHeight() + $( this ).height() ) );
} )
.css( "overflow", "auto" );
} else if ( heightStyle === "auto" ) {
maxHeight = 0;
this.headers.next()
.each( function() {
var isVisible = $( this ).is( ":visible" );
if ( !isVisible ) {
$( this ).show();
}
maxHeight = Math.max( maxHeight, $( this ).css( "height", "" ).height() );
if ( !isVisible ) {
$( this ).hide();
}
} )
.height( maxHeight );
}
},
_activate: function( index ) {
var active = this._findActive( index )[ 0 ];
// Trying to activate the already active panel
if ( active === this.active[ 0 ] ) {
return;
}
// Trying to collapse, simulate a click on the currently active header
active = active || this.active[ 0 ];
this._eventHandler( {
target: active,
currentTarget: active,
preventDefault: $.noop
} );
},
_findActive: function( selector ) {
return typeof selector === "number" ? this.headers.eq( selector ) : $();
},
_setupEvents: function( event ) {
var events = {
keydown: "_keydown"
};
if ( event ) {
$.each( event.split( " " ), function( index, eventName ) {
events[ eventName ] = "_eventHandler";
} );
}
this._off( this.headers.add( this.headers.next() ) );
this._on( this.headers, events );
this._on( this.headers.next(), { keydown: "_panelKeyDown" } );
this._hoverable( this.headers );
this._focusable( this.headers );
},
_eventHandler: function( event ) {
var activeChildren, clickedChildren,
options = this.options,
active = this.active,
clicked = $( event.currentTarget ),
clickedIsActive = clicked[ 0 ] === active[ 0 ],
collapsing = clickedIsActive && options.collapsible,
toShow = collapsing ? $() : clicked.next(),
toHide = active.next(),
eventData = {
oldHeader: active,
oldPanel: toHide,
newHeader: collapsing ? $() : clicked,
newPanel: toShow
};
event.preventDefault();
if (
// click on active header, but not collapsible
( clickedIsActive && !options.collapsible ) ||
// allow canceling activation
( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
return;
}
options.active = collapsing ? false : this.headers.index( clicked );
// When the call to ._toggle() comes after the class changes
// it causes a very odd bug in IE 8 (see #6720)
this.active = clickedIsActive ? $() : clicked;
this._toggle( eventData );
// Switch classes
// corner classes on the previously active header stay after the animation
this._removeClass( active, "ui-accordion-header-active", "ui-state-active" );
if ( options.icons ) {
activeChildren = active.children( ".ui-accordion-header-icon" );
this._removeClass( activeChildren, null, options.icons.activeHeader )
._addClass( activeChildren, null, options.icons.header );
}
if ( !clickedIsActive ) {
this._removeClass( clicked, "ui-accordion-header-collapsed" )
._addClass( clicked, "ui-accordion-header-active", "ui-state-active" );
if ( options.icons ) {
clickedChildren = clicked.children( ".ui-accordion-header-icon" );
this._removeClass( clickedChildren, null, options.icons.header )
._addClass( clickedChildren, null, options.icons.activeHeader );
}
this._addClass( clicked.next(), "ui-accordion-content-active" );
}
},
_toggle: function( data ) {
var toShow = data.newPanel,
toHide = this.prevShow.length ? this.prevShow : data.oldPanel;
// Handle activating a panel during the animation for another activation
this.prevShow.add( this.prevHide ).stop( true, true );
this.prevShow = toShow;
this.prevHide = toHide;
if ( this.options.animate ) {
this._animate( toShow, toHide, data );
} else {
toHide.hide();
toShow.show();
this._toggleComplete( data );
}
toHide.attr( {
"aria-hidden": "true"
} );
toHide.prev().attr( {
"aria-selected": "false",
"aria-expanded": "false"
} );
// if we're switching panels, remove the old header from the tab order
// if we're opening from collapsed state, remove the previous header from the tab order
// if we're collapsing, then keep the collapsing header in the tab order
if ( toShow.length && toHide.length ) {
toHide.prev().attr( {
"tabIndex": -1,
"aria-expanded": "false"
} );
} else if ( toShow.length ) {
this.headers.filter( function() {
return parseInt( $( this ).attr( "tabIndex" ), 10 ) === 0;
} )
.attr( "tabIndex", -1 );
}
toShow
.attr( "aria-hidden", "false" )
.prev()
.attr( {
"aria-selected": "true",
"aria-expanded": "true",
tabIndex: 0
} );
},
_animate: function( toShow, toHide, data ) {
var total, easing, duration,
that = this,
adjust = 0,
boxSizing = toShow.css( "box-sizing" ),
down = toShow.length &&
( !toHide.length || ( toShow.index() < toHide.index() ) ),
animate = this.options.animate || {},
options = down && animate.down || animate,
complete = function() {
that._toggleComplete( data );
};
if ( typeof options === "number" ) {
duration = options;
}
if ( typeof options === "string" ) {
easing = options;
}
// fall back from options to animation in case of partial down settings
easing = easing || options.easing || animate.easing;
duration = duration || options.duration || animate.duration;
if ( !toHide.length ) {
return toShow.animate( this.showProps, duration, easing, complete );
}
if ( !toShow.length ) {
return toHide.animate( this.hideProps, duration, easing, complete );
}
total = toShow.show().outerHeight();
toHide.animate( this.hideProps, {
duration: duration,
easing: easing,
step: function( now, fx ) {
fx.now = Math.round( now );
}
} );
toShow
.hide()
.animate( this.showProps, {
duration: duration,
easing: easing,
complete: complete,
step: function( now, fx ) {
fx.now = Math.round( now );
if ( fx.prop !== "height" ) {
if ( boxSizing === "content-box" ) {
adjust += fx.now;
}
} else if ( that.options.heightStyle !== "content" ) {
fx.now = Math.round( total - toHide.outerHeight() - adjust );
adjust = 0;
}
}
} );
},
_toggleComplete: function( data ) {
var toHide = data.oldPanel,
prev = toHide.prev();
this._removeClass( toHide, "ui-accordion-content-active" );
this._removeClass( prev, "ui-accordion-header-active" )
._addClass( prev, "ui-accordion-header-collapsed" );
// Work around for rendering bug in IE (#5421)
if ( toHide.length ) {
toHide.parent()[ 0 ].className = toHide.parent()[ 0 ].className;
}
this._trigger( "activate", null, data );
}
} );
var safeActiveElement = $.ui.safeActiveElement = function( document ) {
var activeElement;
// Support: IE 9 only
// IE9 throws an "Unspecified error" accessing document.activeElement from an <iframe>
try {
activeElement = document.activeElement;
} catch ( error ) {
activeElement = document.body;
}
// Support: IE 9 - 11 only
// IE may return null instead of an element
// Interestingly, this only seems to occur when NOT in an iframe
if ( !activeElement ) {
activeElement = document.body;
}
// Support: IE 11 only
// IE11 returns a seemingly empty object in some cases when accessing
// document.activeElement from an <iframe>
if ( !activeElement.nodeName ) {
activeElement = document.body;
}
return activeElement;
};
/*!
* jQuery UI Menu 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Menu
//>>group: Widgets
//>>description: Creates nestable menus.
//>>docs: http://api.jqueryui.com/menu/
//>>demos: http://jqueryui.com/menu/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/menu.css
//>>css.theme: ../../themes/base/theme.css
var widgetsMenu = $.widget( "ui.menu", {
version: "1.12.1",
defaultElement: "<ul>",
delay: 300,
options: {
icons: {
submenu: "ui-icon-caret-1-e"
},
items: "> *",
menus: "ul",
position: {
my: "left top",
at: "right top"
},
role: "menu",
// Callbacks
blur: null,
focus: null,
select: null
},
_create: function() {
this.activeMenu = this.element;
// Flag used to prevent firing of the click handler
// as the event bubbles up through nested menus
this.mouseHandled = false;
this.element
.uniqueId()
.attr( {
role: this.options.role,
tabIndex: 0
} );
this._addClass( "ui-menu", "ui-widget ui-widget-content" );
this._on( {
// Prevent focus from sticking to links inside menu after clicking
// them (focus should always stay on UL during navigation).
"mousedown .ui-menu-item": function( event ) {
event.preventDefault();
},
"click .ui-menu-item": function( event ) {
var target = $( event.target );
var active = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
if ( !this.mouseHandled && target.not( ".ui-state-disabled" ).length ) {
this.select( event );
// Only set the mouseHandled flag if the event will bubble, see #9469.
if ( !event.isPropagationStopped() ) {
this.mouseHandled = true;
}
// Open submenu on click
if ( target.has( ".ui-menu" ).length ) {
this.expand( event );
} else if ( !this.element.is( ":focus" ) &&
active.closest( ".ui-menu" ).length ) {
// Redirect focus to the menu
this.element.trigger( "focus", [ true ] );
// If the active item is on the top level, let it stay active.
// Otherwise, blur the active item since it is no longer visible.
if ( this.active && this.active.parents( ".ui-menu" ).length === 1 ) {
clearTimeout( this.timer );
}
}
}
},
"mouseenter .ui-menu-item": function( event ) {
// Ignore mouse events while typeahead is active, see #10458.
// Prevents focusing the wrong item when typeahead causes a scroll while the mouse
// is over an item in the menu
if ( this.previousFilter ) {
return;
}
var actualTarget = $( event.target ).closest( ".ui-menu-item" ),
target = $( event.currentTarget );
// Ignore bubbled events on parent items, see #11641
if ( actualTarget[ 0 ] !== target[ 0 ] ) {
return;
}
// Remove ui-state-active class from siblings of the newly focused menu item
// to avoid a jump caused by adjacent elements both having a class with a border
this._removeClass( target.siblings().children( ".ui-state-active" ),
null, "ui-state-active" );
this.focus( event, target );
},
mouseleave: "collapseAll",
"mouseleave .ui-menu": "collapseAll",
focus: function( event, keepActiveItem ) {
// If there's already an active item, keep it active
// If not, activate the first item
var item = this.active || this.element.find( this.options.items ).eq( 0 );
if ( !keepActiveItem ) {
this.focus( event, item );
}
},
blur: function( event ) {
this._delay( function() {
var notContained = !$.contains(
this.element[ 0 ],
$.ui.safeActiveElement( this.document[ 0 ] )
);
if ( notContained ) {
this.collapseAll( event );
}
} );
},
keydown: "_keydown"
} );
this.refresh();
// Clicks outside of a menu collapse any open menus
this._on( this.document, {
click: function( event ) {
if ( this._closeOnDocumentClick( event ) ) {
this.collapseAll( event );
}
// Reset the mouseHandled flag
this.mouseHandled = false;
}
} );
},
_destroy: function() {
var items = this.element.find( ".ui-menu-item" )
.removeAttr( "role aria-disabled" ),
submenus = items.children( ".ui-menu-item-wrapper" )
.removeUniqueId()
.removeAttr( "tabIndex role aria-haspopup" );
// Destroy (sub)menus
this.element
.removeAttr( "aria-activedescendant" )
.find( ".ui-menu" ).addBack()
.removeAttr( "role aria-labelledby aria-expanded aria-hidden aria-disabled " +
"tabIndex" )
.removeUniqueId()
.show();
submenus.children().each( function() {
var elem = $( this );
if ( elem.data( "ui-menu-submenu-caret" ) ) {
elem.remove();
}
} );
},
_keydown: function( event ) {
var match, prev, character, skip,
preventDefault = true;
switch ( event.keyCode ) {
case $.ui.keyCode.PAGE_UP:
this.previousPage( event );
break;
case $.ui.keyCode.PAGE_DOWN:
this.nextPage( event );
break;
case $.ui.keyCode.HOME:
this._move( "first", "first", event );
break;
case $.ui.keyCode.END:
this._move( "last", "last", event );
break;
case $.ui.keyCode.UP:
this.previous( event );
break;
case $.ui.keyCode.DOWN:
this.next( event );
break;
case $.ui.keyCode.LEFT:
this.collapse( event );
break;
case $.ui.keyCode.RIGHT:
if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
this.expand( event );
}
break;
case $.ui.keyCode.ENTER:
case $.ui.keyCode.SPACE:
this._activate( event );
break;
case $.ui.keyCode.ESCAPE:
this.collapse( event );
break;
default:
preventDefault = false;
prev = this.previousFilter || "";
skip = false;
// Support number pad values
character = event.keyCode >= 96 && event.keyCode <= 105 ?
( event.keyCode - 96 ).toString() : String.fromCharCode( event.keyCode );
clearTimeout( this.filterTimer );
if ( character === prev ) {
skip = true;
} else {
character = prev + character;
}
match = this._filterMenuItems( character );
match = skip && match.index( this.active.next() ) !== -1 ?
this.active.nextAll( ".ui-menu-item" ) :
match;
// If no matches on the current filter, reset to the last character pressed
// to move down the menu to the first item that starts with that character
if ( !match.length ) {
character = String.fromCharCode( event.keyCode );
match = this._filterMenuItems( character );
}
if ( match.length ) {
this.focus( event, match );
this.previousFilter = character;
this.filterTimer = this._delay( function() {
delete this.previousFilter;
}, 1000 );
} else {
delete this.previousFilter;
}
}
if ( preventDefault ) {
event.preventDefault();
}
},
_activate: function( event ) {
if ( this.active && !this.active.is( ".ui-state-disabled" ) ) {
if ( this.active.children( "[aria-haspopup='true']" ).length ) {
this.expand( event );
} else {
this.select( event );
}
}
},
refresh: function() {
var menus, items, newSubmenus, newItems, newWrappers,
that = this,
icon = this.options.icons.submenu,
submenus = this.element.find( this.options.menus );
this._toggleClass( "ui-menu-icons", null, !!this.element.find( ".ui-icon" ).length );
// Initialize nested menus
newSubmenus = submenus.filter( ":not(.ui-menu)" )
.hide()
.attr( {
role: this.options.role,
"aria-hidden": "true",
"aria-expanded": "false"
} )
.each( function() {
var menu = $( this ),
item = menu.prev(),
submenuCaret = $( "<span>" ).data( "ui-menu-submenu-caret", true );
that._addClass( submenuCaret, "ui-menu-icon", "ui-icon " + icon );
item
.attr( "aria-haspopup", "true" )
.prepend( submenuCaret );
menu.attr( "aria-labelledby", item.attr( "id" ) );
} );
this._addClass( newSubmenus, "ui-menu", "ui-widget ui-widget-content ui-front" );
menus = submenus.add( this.element );
items = menus.find( this.options.items );
// Initialize menu-items containing spaces and/or dashes only as dividers
items.not( ".ui-menu-item" ).each( function() {
var item = $( this );
if ( that._isDivider( item ) ) {
that._addClass( item, "ui-menu-divider", "ui-widget-content" );
}
} );
// Don't refresh list items that are already adapted
newItems = items.not( ".ui-menu-item, .ui-menu-divider" );
newWrappers = newItems.children()
.not( ".ui-menu" )
.uniqueId()
.attr( {
tabIndex: -1,
role: this._itemRole()
} );
this._addClass( newItems, "ui-menu-item" )
._addClass( newWrappers, "ui-menu-item-wrapper" );
// Add aria-disabled attribute to any disabled menu item
items.filter( ".ui-state-disabled" ).attr( "aria-disabled", "true" );
// If the active item has been removed, blur the menu
if ( this.active && !$.contains( this.element[ 0 ], this.active[ 0 ] ) ) {
this.blur();
}
},
_itemRole: function() {
return {
menu: "menuitem",
listbox: "option"
}[ this.options.role ];
},
_setOption: function( key, value ) {
if ( key === "icons" ) {
var icons = this.element.find( ".ui-menu-icon" );
this._removeClass( icons, null, this.options.icons.submenu )
._addClass( icons, null, value.submenu );
}
this._super( key, value );
},
_setOptionDisabled: function( value ) {
this._super( value );
this.element.attr( "aria-disabled", String( value ) );
this._toggleClass( null, "ui-state-disabled", !!value );
},
focus: function( event, item ) {
var nested, focused, activeParent;
this.blur( event, event && event.type === "focus" );
this._scrollIntoView( item );
this.active = item.first();
focused = this.active.children( ".ui-menu-item-wrapper" );
this._addClass( focused, null, "ui-state-active" );
// Only update aria-activedescendant if there's a role
// otherwise we assume focus is managed elsewhere
if ( this.options.role ) {
this.element.attr( "aria-activedescendant", focused.attr( "id" ) );
}
// Highlight active parent menu item, if any
activeParent = this.active
.parent()
.closest( ".ui-menu-item" )
.children( ".ui-menu-item-wrapper" );
this._addClass( activeParent, null, "ui-state-active" );
if ( event && event.type === "keydown" ) {
this._close();
} else {
this.timer = this._delay( function() {
this._close();
}, this.delay );
}
nested = item.children( ".ui-menu" );
if ( nested.length && event && ( /^mouse/.test( event.type ) ) ) {
this._startOpening( nested );
}
this.activeMenu = item.parent();
this._trigger( "focus", event, { item: item } );
},
_scrollIntoView: function( item ) {
var borderTop, paddingTop, offset, scroll, elementHeight, itemHeight;
if ( this._hasScroll() ) {
borderTop = parseFloat( $.css( this.activeMenu[ 0 ], "borderTopWidth" ) ) || 0;
paddingTop = parseFloat( $.css( this.activeMenu[ 0 ], "paddingTop" ) ) || 0;
offset = item.offset().top - this.activeMenu.offset().top - borderTop - paddingTop;
scroll = this.activeMenu.scrollTop();
elementHeight = this.activeMenu.height();
itemHeight = item.outerHeight();
if ( offset < 0 ) {
this.activeMenu.scrollTop( scroll + offset );
} else if ( offset + itemHeight > elementHeight ) {
this.activeMenu.scrollTop( scroll + offset - elementHeight + itemHeight );
}
}
},
blur: function( event, fromFocus ) {
if ( !fromFocus ) {
clearTimeout( this.timer );
}
if ( !this.active ) {
return;
}
this._removeClass( this.active.children( ".ui-menu-item-wrapper" ),
null, "ui-state-active" );
this._trigger( "blur", event, { item: this.active } );
this.active = null;
},
_startOpening: function( submenu ) {
clearTimeout( this.timer );
// Don't open if already open fixes a Firefox bug that caused a .5 pixel
// shift in the submenu position when mousing over the caret icon
if ( submenu.attr( "aria-hidden" ) !== "true" ) {
return;
}
this.timer = this._delay( function() {
this._close();
this._open( submenu );
}, this.delay );
},
_open: function( submenu ) {
var position = $.extend( {
of: this.active
}, this.options.position );
clearTimeout( this.timer );
this.element.find( ".ui-menu" ).not( submenu.parents( ".ui-menu" ) )
.hide()
.attr( "aria-hidden", "true" );
submenu
.show()
.removeAttr( "aria-hidden" )
.attr( "aria-expanded", "true" )
.position( position );
},
collapseAll: function( event, all ) {
clearTimeout( this.timer );
this.timer = this._delay( function() {
// If we were passed an event, look for the submenu that contains the event
var currentMenu = all ? this.element :
$( event && event.target ).closest( this.element.find( ".ui-menu" ) );
// If we found no valid submenu ancestor, use the main menu to close all
// sub menus anyway
if ( !currentMenu.length ) {
currentMenu = this.element;
}
this._close( currentMenu );
this.blur( event );
// Work around active item staying active after menu is blurred
this._removeClass( currentMenu.find( ".ui-state-active" ), null, "ui-state-active" );
this.activeMenu = currentMenu;
}, this.delay );
},
// With no arguments, closes the currently active menu - if nothing is active
// it closes all menus. If passed an argument, it will search for menus BELOW
_close: function( startMenu ) {
if ( !startMenu ) {
startMenu = this.active ? this.active.parent() : this.element;
}
startMenu.find( ".ui-menu" )
.hide()
.attr( "aria-hidden", "true" )
.attr( "aria-expanded", "false" );
},
_closeOnDocumentClick: function( event ) {
return !$( event.target ).closest( ".ui-menu" ).length;
},
_isDivider: function( item ) {
// Match hyphen, em dash, en dash
return !/[^\-\u2014\u2013\s]/.test( item.text() );
},
collapse: function( event ) {
var newItem = this.active &&
this.active.parent().closest( ".ui-menu-item", this.element );
if ( newItem && newItem.length ) {
this._close();
this.focus( event, newItem );
}
},
expand: function( event ) {
var newItem = this.active &&
this.active
.children( ".ui-menu " )
.find( this.options.items )
.first();
if ( newItem && newItem.length ) {
this._open( newItem.parent() );
// Delay so Firefox will not hide activedescendant change in expanding submenu from AT
this._delay( function() {
this.focus( event, newItem );
} );
}
},
next: function( event ) {
this._move( "next", "first", event );
},
previous: function( event ) {
this._move( "prev", "last", event );
},
isFirstItem: function() {
return this.active && !this.active.prevAll( ".ui-menu-item" ).length;
},
isLastItem: function() {
return this.active && !this.active.nextAll( ".ui-menu-item" ).length;
},
_move: function( direction, filter, event ) {
var next;
if ( this.active ) {
if ( direction === "first" || direction === "last" ) {
next = this.active
[ direction === "first" ? "prevAll" : "nextAll" ]( ".ui-menu-item" )
.eq( -1 );
} else {
next = this.active
[ direction + "All" ]( ".ui-menu-item" )
.eq( 0 );
}
}
if ( !next || !next.length || !this.active ) {
next = this.activeMenu.find( this.options.items )[ filter ]();
}
this.focus( event, next );
},
nextPage: function( event ) {
var item, base, height;
if ( !this.active ) {
this.next( event );
return;
}
if ( this.isLastItem() ) {
return;
}
if ( this._hasScroll() ) {
base = this.active.offset().top;
height = this.element.height();
this.active.nextAll( ".ui-menu-item" ).each( function() {
item = $( this );
return item.offset().top - base - height < 0;
} );
this.focus( event, item );
} else {
this.focus( event, this.activeMenu.find( this.options.items )
[ !this.active ? "first" : "last" ]() );
}
},
previousPage: function( event ) {
var item, base, height;
if ( !this.active ) {
this.next( event );
return;
}
if ( this.isFirstItem() ) {
return;
}
if ( this._hasScroll() ) {
base = this.active.offset().top;
height = this.element.height();
this.active.prevAll( ".ui-menu-item" ).each( function() {
item = $( this );
return item.offset().top - base + height > 0;
} );
this.focus( event, item );
} else {
this.focus( event, this.activeMenu.find( this.options.items ).first() );
}
},
_hasScroll: function() {
return this.element.outerHeight() < this.element.prop( "scrollHeight" );
},
select: function( event ) {
// TODO: It should never be possible to not have an active item at this
// point, but the tests don't trigger mouseenter before click.
this.active = this.active || $( event.target ).closest( ".ui-menu-item" );
var ui = { item: this.active };
if ( !this.active.has( ".ui-menu" ).length ) {
this.collapseAll( event, true );
}
this._trigger( "select", event, ui );
},
_filterMenuItems: function( character ) {
var escapedCharacter = character.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" ),
regex = new RegExp( "^" + escapedCharacter, "i" );
return this.activeMenu
.find( this.options.items )
// Only match on items, not dividers or other content (#10571)
.filter( ".ui-menu-item" )
.filter( function() {
return regex.test(
$.trim( $( this ).children( ".ui-menu-item-wrapper" ).text() ) );
} );
}
} );
/*!
* jQuery UI Autocomplete 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Autocomplete
//>>group: Widgets
//>>description: Lists suggested words as the user is typing.
//>>docs: http://api.jqueryui.com/autocomplete/
//>>demos: http://jqueryui.com/autocomplete/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/autocomplete.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.autocomplete", {
version: "1.12.1",
defaultElement: "<input>",
options: {
appendTo: null,
autoFocus: false,
delay: 300,
minLength: 1,
position: {
my: "left top",
at: "left bottom",
collision: "none"
},
source: null,
// Callbacks
change: null,
close: null,
focus: null,
open: null,
response: null,
search: null,
select: null
},
requestIndex: 0,
pending: 0,
_create: function() {
// Some browsers only repeat keydown events, not keypress events,
// so we use the suppressKeyPress flag to determine if we've already
// handled the keydown event. #7269
// Unfortunately the code for & in keypress is the same as the up arrow,
// so we use the suppressKeyPressRepeat flag to avoid handling keypress
// events when we know the keydown event was used to modify the
// search term. #7799
var suppressKeyPress, suppressKeyPressRepeat, suppressInput,
nodeName = this.element[ 0 ].nodeName.toLowerCase(),
isTextarea = nodeName === "textarea",
isInput = nodeName === "input";
// Textareas are always multi-line
// Inputs are always single-line, even if inside a contentEditable element
// IE also treats inputs as contentEditable
// All other element types are determined by whether or not they're contentEditable
this.isMultiLine = isTextarea || !isInput && this._isContentEditable( this.element );
this.valueMethod = this.element[ isTextarea || isInput ? "val" : "text" ];
this.isNewMenu = true;
this._addClass( "ui-autocomplete-input" );
this.element.attr( "autocomplete", "off" );
this._on( this.element, {
keydown: function( event ) {
if ( this.element.prop( "readOnly" ) ) {
suppressKeyPress = true;
suppressInput = true;
suppressKeyPressRepeat = true;
return;
}
suppressKeyPress = false;
suppressInput = false;
suppressKeyPressRepeat = false;
var keyCode = $.ui.keyCode;
switch ( event.keyCode ) {
case keyCode.PAGE_UP:
suppressKeyPress = true;
this._move( "previousPage", event );
break;
case keyCode.PAGE_DOWN:
suppressKeyPress = true;
this._move( "nextPage", event );
break;
case keyCode.UP:
suppressKeyPress = true;
this._keyEvent( "previous", event );
break;
case keyCode.DOWN:
suppressKeyPress = true;
this._keyEvent( "next", event );
break;
case keyCode.ENTER:
// when menu is open and has focus
if ( this.menu.active ) {
// #6055 - Opera still allows the keypress to occur
// which causes forms to submit
suppressKeyPress = true;
event.preventDefault();
this.menu.select( event );
}
break;
case keyCode.TAB:
if ( this.menu.active ) {
this.menu.select( event );
}
break;
case keyCode.ESCAPE:
if ( this.menu.element.is( ":visible" ) ) {
if ( !this.isMultiLine ) {
this._value( this.term );
}
this.close( event );
// Different browsers have different default behavior for escape
// Single press can mean undo or clear
// Double press in IE means clear the whole form
event.preventDefault();
}
break;
default:
suppressKeyPressRepeat = true;
// search timeout should be triggered before the input value is changed
this._searchTimeout( event );
break;
}
},
keypress: function( event ) {
if ( suppressKeyPress ) {
suppressKeyPress = false;
if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
event.preventDefault();
}
return;
}
if ( suppressKeyPressRepeat ) {
return;
}
// Replicate some key handlers to allow them to repeat in Firefox and Opera
var keyCode = $.ui.keyCode;
switch ( event.keyCode ) {
case keyCode.PAGE_UP:
this._move( "previousPage", event );
break;
case keyCode.PAGE_DOWN:
this._move( "nextPage", event );
break;
case keyCode.UP:
this._keyEvent( "previous", event );
break;
case keyCode.DOWN:
this._keyEvent( "next", event );
break;
}
},
input: function( event ) {
if ( suppressInput ) {
suppressInput = false;
event.preventDefault();
return;
}
this._searchTimeout( event );
},
focus: function() {
this.selectedItem = null;
this.previous = this._value();
},
blur: function( event ) {
if ( this.cancelBlur ) {
delete this.cancelBlur;
return;
}
clearTimeout( this.searching );
this.close( event );
this._change( event );
}
} );
this._initSource();
this.menu = $( "<ul>" )
.appendTo( this._appendTo() )
.menu( {
// disable ARIA support, the live region takes care of that
role: null
} )
.hide()
.menu( "instance" );
this._addClass( this.menu.element, "ui-autocomplete", "ui-front" );
this._on( this.menu.element, {
mousedown: function( event ) {
// prevent moving focus out of the text field
event.preventDefault();
// IE doesn't prevent moving focus even with event.preventDefault()
// so we set a flag to know when we should ignore the blur event
this.cancelBlur = true;
this._delay( function() {
delete this.cancelBlur;
// Support: IE 8 only
// Right clicking a menu item or selecting text from the menu items will
// result in focus moving out of the input. However, we've already received
// and ignored the blur event because of the cancelBlur flag set above. So
// we restore focus to ensure that the menu closes properly based on the user's
// next actions.
if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
this.element.trigger( "focus" );
}
} );
},
menufocus: function( event, ui ) {
var label, item;
// support: Firefox
// Prevent accidental activation of menu items in Firefox (#7024 #9118)
if ( this.isNewMenu ) {
this.isNewMenu = false;
if ( event.originalEvent && /^mouse/.test( event.originalEvent.type ) ) {
this.menu.blur();
this.document.one( "mousemove", function() {
$( event.target ).trigger( event.originalEvent );
} );
return;
}
}
item = ui.item.data( "ui-autocomplete-item" );
if ( false !== this._trigger( "focus", event, { item: item } ) ) {
// use value to match what will end up in the input, if it was a key event
if ( event.originalEvent && /^key/.test( event.originalEvent.type ) ) {
this._value( item.value );
}
}
// Announce the value in the liveRegion
label = ui.item.attr( "aria-label" ) || item.value;
if ( label && $.trim( label ).length ) {
this.liveRegion.children().hide();
$( "<div>" ).text( label ).appendTo( this.liveRegion );
}
},
menuselect: function( event, ui ) {
var item = ui.item.data( "ui-autocomplete-item" ),
previous = this.previous;
// Only trigger when focus was lost (click on menu)
if ( this.element[ 0 ] !== $.ui.safeActiveElement( this.document[ 0 ] ) ) {
this.element.trigger( "focus" );
this.previous = previous;
// #6109 - IE triggers two focus events and the second
// is asynchronous, so we need to reset the previous
// term synchronously and asynchronously :-(
this._delay( function() {
this.previous = previous;
this.selectedItem = item;
} );
}
if ( false !== this._trigger( "select", event, { item: item } ) ) {
this._value( item.value );
}
// reset the term after the select event
// this allows custom select handling to work properly
this.term = this._value();
this.close( event );
this.selectedItem = item;
}
} );
this.liveRegion = $( "<div>", {
role: "status",
"aria-live": "assertive",
"aria-relevant": "additions"
} )
.appendTo( this.document[ 0 ].body );
this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
// Turning off autocomplete prevents the browser from remembering the
// value when navigating through history, so we re-enable autocomplete
// if the page is unloaded before the widget is destroyed. #7790
this._on( this.window, {
beforeunload: function() {
this.element.removeAttr( "autocomplete" );
}
} );
},
_destroy: function() {
clearTimeout( this.searching );
this.element.removeAttr( "autocomplete" );
this.menu.element.remove();
this.liveRegion.remove();
},
_setOption: function( key, value ) {
this._super( key, value );
if ( key === "source" ) {
this._initSource();
}
if ( key === "appendTo" ) {
this.menu.element.appendTo( this._appendTo() );
}
if ( key === "disabled" && value && this.xhr ) {
this.xhr.abort();
}
},
_isEventTargetInWidget: function( event ) {
var menuElement = this.menu.element[ 0 ];
return event.target === this.element[ 0 ] ||
event.target === menuElement ||
$.contains( menuElement, event.target );
},
_closeOnClickOutside: function( event ) {
if ( !this._isEventTargetInWidget( event ) ) {
this.close();
}
},
_appendTo: function() {
var element = this.options.appendTo;
if ( element ) {
element = element.jquery || element.nodeType ?
$( element ) :
this.document.find( element ).eq( 0 );
}
if ( !element || !element[ 0 ] ) {
element = this.element.closest( ".ui-front, dialog" );
}
if ( !element.length ) {
element = this.document[ 0 ].body;
}
return element;
},
_initSource: function() {
var array, url,
that = this;
if ( $.isArray( this.options.source ) ) {
array = this.options.source;
this.source = function( request, response ) {
response( $.ui.autocomplete.filter( array, request.term ) );
};
} else if ( typeof this.options.source === "string" ) {
url = this.options.source;
this.source = function( request, response ) {
if ( that.xhr ) {
that.xhr.abort();
}
that.xhr = $.ajax( {
url: url,
data: request,
dataType: "json",
success: function( data ) {
response( data );
},
error: function() {
response( [] );
}
} );
};
} else {
this.source = this.options.source;
}
},
_searchTimeout: function( event ) {
clearTimeout( this.searching );
this.searching = this._delay( function() {
// Search if the value has changed, or if the user retypes the same value (see #7434)
var equalValues = this.term === this._value(),
menuVisible = this.menu.element.is( ":visible" ),
modifierKey = event.altKey || event.ctrlKey || event.metaKey || event.shiftKey;
if ( !equalValues || ( equalValues && !menuVisible && !modifierKey ) ) {
this.selectedItem = null;
this.search( null, event );
}
}, this.options.delay );
},
search: function( value, event ) {
value = value != null ? value : this._value();
// Always save the actual value, not the one passed as an argument
this.term = this._value();
if ( value.length < this.options.minLength ) {
return this.close( event );
}
if ( this._trigger( "search", event ) === false ) {
return;
}
return this._search( value );
},
_search: function( value ) {
this.pending++;
this._addClass( "ui-autocomplete-loading" );
this.cancelSearch = false;
this.source( { term: value }, this._response() );
},
_response: function() {
var index = ++this.requestIndex;
return $.proxy( function( content ) {
if ( index === this.requestIndex ) {
this.__response( content );
}
this.pending--;
if ( !this.pending ) {
this._removeClass( "ui-autocomplete-loading" );
}
}, this );
},
__response: function( content ) {
if ( content ) {
content = this._normalize( content );
}
this._trigger( "response", null, { content: content } );
if ( !this.options.disabled && content && content.length && !this.cancelSearch ) {
this._suggest( content );
this._trigger( "open" );
} else {
// use ._close() instead of .close() so we don't cancel future searches
this._close();
}
},
close: function( event ) {
this.cancelSearch = true;
this._close( event );
},
_close: function( event ) {
// Remove the handler that closes the menu on outside clicks
this._off( this.document, "mousedown" );
if ( this.menu.element.is( ":visible" ) ) {
this.menu.element.hide();
this.menu.blur();
this.isNewMenu = true;
this._trigger( "close", event );
}
},
_change: function( event ) {
if ( this.previous !== this._value() ) {
this._trigger( "change", event, { item: this.selectedItem } );
}
},
_normalize: function( items ) {
// assume all items have the right format when the first item is complete
if ( items.length && items[ 0 ].label && items[ 0 ].value ) {
return items;
}
return $.map( items, function( item ) {
if ( typeof item === "string" ) {
return {
label: item,
value: item
};
}
return $.extend( {}, item, {
label: item.label || item.value,
value: item.value || item.label
} );
} );
},
_suggest: function( items ) {
var ul = this.menu.element.empty();
this._renderMenu( ul, items );
this.isNewMenu = true;
this.menu.refresh();
// Size and position menu
ul.show();
this._resizeMenu();
ul.position( $.extend( {
of: this.element
}, this.options.position ) );
if ( this.options.autoFocus ) {
this.menu.next();
}
// Listen for interactions outside of the widget (#6642)
this._on( this.document, {
mousedown: "_closeOnClickOutside"
} );
},
_resizeMenu: function() {
var ul = this.menu.element;
ul.outerWidth( Math.max(
// Firefox wraps long text (possibly a rounding bug)
// so we add 1px to avoid the wrapping (#7513)
ul.width( "" ).outerWidth() + 1,
this.element.outerWidth()
) );
},
_renderMenu: function( ul, items ) {
var that = this;
$.each( items, function( index, item ) {
that._renderItemData( ul, item );
} );
},
_renderItemData: function( ul, item ) {
return this._renderItem( ul, item ).data( "ui-autocomplete-item", item );
},
_renderItem: function( ul, item ) {
return $( "<li>" )
.append( $( "<div>" ).text( item.label ) )
.appendTo( ul );
},
_move: function( direction, event ) {
if ( !this.menu.element.is( ":visible" ) ) {
this.search( null, event );
return;
}
if ( this.menu.isFirstItem() && /^previous/.test( direction ) ||
this.menu.isLastItem() && /^next/.test( direction ) ) {
if ( !this.isMultiLine ) {
this._value( this.term );
}
this.menu.blur();
return;
}
this.menu[ direction ]( event );
},
widget: function() {
return this.menu.element;
},
_value: function() {
return this.valueMethod.apply( this.element, arguments );
},
_keyEvent: function( keyEvent, event ) {
if ( !this.isMultiLine || this.menu.element.is( ":visible" ) ) {
this._move( keyEvent, event );
// Prevents moving cursor to beginning/end of the text field in some browsers
event.preventDefault();
}
},
// Support: Chrome <=50
// We should be able to just use this.element.prop( "isContentEditable" )
// but hidden elements always report false in Chrome.
// https://code.google.com/p/chromium/issues/detail?id=313082
_isContentEditable: function( element ) {
if ( !element.length ) {
return false;
}
var editable = element.prop( "contentEditable" );
if ( editable === "inherit" ) {
return this._isContentEditable( element.parent() );
}
return editable === "true";
}
} );
$.extend( $.ui.autocomplete, {
escapeRegex: function( value ) {
return value.replace( /[\-\[\]{}()*+?.,\\\^$|#\s]/g, "\\$&" );
},
filter: function( array, term ) {
var matcher = new RegExp( $.ui.autocomplete.escapeRegex( term ), "i" );
return $.grep( array, function( value ) {
return matcher.test( value.label || value.value || value );
} );
}
} );
// Live region extension, adding a `messages` option
// NOTE: This is an experimental API. We are still investigating
// a full solution for string manipulation and internationalization.
$.widget( "ui.autocomplete", $.ui.autocomplete, {
options: {
messages: {
noResults: "No search results.",
results: function( amount ) {
return amount + ( amount > 1 ? " results are" : " result is" ) +
" available, use up and down arrow keys to navigate.";
}
}
},
__response: function( content ) {
var message;
this._superApply( arguments );
if ( this.options.disabled || this.cancelSearch ) {
return;
}
if ( content && content.length ) {
message = this.options.messages.results( content.length );
} else {
message = this.options.messages.noResults;
}
this.liveRegion.children().hide();
$( "<div>" ).text( message ).appendTo( this.liveRegion );
}
} );
var widgetsAutocomplete = $.ui.autocomplete;
/*!
* jQuery UI Controlgroup 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Controlgroup
//>>group: Widgets
//>>description: Visually groups form control widgets
//>>docs: http://api.jqueryui.com/controlgroup/
//>>demos: http://jqueryui.com/controlgroup/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/controlgroup.css
//>>css.theme: ../../themes/base/theme.css
var controlgroupCornerRegex = /ui-corner-([a-z]){2,6}/g;
var widgetsControlgroup = $.widget( "ui.controlgroup", {
version: "1.12.1",
defaultElement: "<div>",
options: {
direction: "horizontal",
disabled: null,
onlyVisible: true,
items: {
"button": "input[type=button], input[type=submit], input[type=reset], button, a",
"controlgroupLabel": ".ui-controlgroup-label",
"checkboxradio": "input[type='checkbox'], input[type='radio']",
"selectmenu": "select",
"spinner": ".ui-spinner-input"
}
},
_create: function() {
this._enhance();
},
// To support the enhanced option in jQuery Mobile, we isolate DOM manipulation
_enhance: function() {
this.element.attr( "role", "toolbar" );
this.refresh();
},
_destroy: function() {
this._callChildMethod( "destroy" );
this.childWidgets.removeData( "ui-controlgroup-data" );
this.element.removeAttr( "role" );
if ( this.options.items.controlgroupLabel ) {
this.element
.find( this.options.items.controlgroupLabel )
.find( ".ui-controlgroup-label-contents" )
.contents().unwrap();
}
},
_initWidgets: function() {
var that = this,
childWidgets = [];
// First we iterate over each of the items options
$.each( this.options.items, function( widget, selector ) {
var labels;
var options = {};
// Make sure the widget has a selector set
if ( !selector ) {
return;
}
if ( widget === "controlgroupLabel" ) {
labels = that.element.find( selector );
labels.each( function() {
var element = $( this );
if ( element.children( ".ui-controlgroup-label-contents" ).length ) {
return;
}
element.contents()
.wrapAll( "<span class='ui-controlgroup-label-contents'></span>" );
} );
that._addClass( labels, null, "ui-widget ui-widget-content ui-state-default" );
childWidgets = childWidgets.concat( labels.get() );
return;
}
// Make sure the widget actually exists
if ( !$.fn[ widget ] ) {
return;
}
// We assume everything is in the middle to start because we can't determine
// first / last elements until all enhancments are done.
if ( that[ "_" + widget + "Options" ] ) {
options = that[ "_" + widget + "Options" ]( "middle" );
} else {
options = { classes: {} };
}
// Find instances of this widget inside controlgroup and init them
that.element
.find( selector )
.each( function() {
var element = $( this );
var instance = element[ widget ]( "instance" );
// We need to clone the default options for this type of widget to avoid
// polluting the variable options which has a wider scope than a single widget.
var instanceOptions = $.widget.extend( {}, options );
// If the button is the child of a spinner ignore it
// TODO: Find a more generic solution
if ( widget === "button" && element.parent( ".ui-spinner" ).length ) {
return;
}
// Create the widget if it doesn't exist
if ( !instance ) {
instance = element[ widget ]()[ widget ]( "instance" );
}
if ( instance ) {
instanceOptions.classes =
that._resolveClassesValues( instanceOptions.classes, instance );
}
element[ widget ]( instanceOptions );
// Store an instance of the controlgroup to be able to reference
// from the outermost element for changing options and refresh
var widgetElement = element[ widget ]( "widget" );
$.data( widgetElement[ 0 ], "ui-controlgroup-data",
instance ? instance : element[ widget ]( "instance" ) );
childWidgets.push( widgetElement[ 0 ] );
} );
} );
this.childWidgets = $( $.unique( childWidgets ) );
this._addClass( this.childWidgets, "ui-controlgroup-item" );
},
_callChildMethod: function( method ) {
this.childWidgets.each( function() {
var element = $( this ),
data = element.data( "ui-controlgroup-data" );
if ( data && data[ method ] ) {
data[ method ]();
}
} );
},
_updateCornerClass: function( element, position ) {
var remove = "ui-corner-top ui-corner-bottom ui-corner-left ui-corner-right ui-corner-all";
var add = this._buildSimpleOptions( position, "label" ).classes.label;
this._removeClass( element, null, remove );
this._addClass( element, null, add );
},
_buildSimpleOptions: function( position, key ) {
var direction = this.options.direction === "vertical";
var result = {
classes: {}
};
result.classes[ key ] = {
"middle": "",
"first": "ui-corner-" + ( direction ? "top" : "left" ),
"last": "ui-corner-" + ( direction ? "bottom" : "right" ),
"only": "ui-corner-all"
}[ position ];
return result;
},
_spinnerOptions: function( position ) {
var options = this._buildSimpleOptions( position, "ui-spinner" );
options.classes[ "ui-spinner-up" ] = "";
options.classes[ "ui-spinner-down" ] = "";
return options;
},
_buttonOptions: function( position ) {
return this._buildSimpleOptions( position, "ui-button" );
},
_checkboxradioOptions: function( position ) {
return this._buildSimpleOptions( position, "ui-checkboxradio-label" );
},
_selectmenuOptions: function( position ) {
var direction = this.options.direction === "vertical";
return {
width: direction ? "auto" : false,
classes: {
middle: {
"ui-selectmenu-button-open": "",
"ui-selectmenu-button-closed": ""
},
first: {
"ui-selectmenu-button-open": "ui-corner-" + ( direction ? "top" : "tl" ),
"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "top" : "left" )
},
last: {
"ui-selectmenu-button-open": direction ? "" : "ui-corner-tr",
"ui-selectmenu-button-closed": "ui-corner-" + ( direction ? "bottom" : "right" )
},
only: {
"ui-selectmenu-button-open": "ui-corner-top",
"ui-selectmenu-button-closed": "ui-corner-all"
}
}[ position ]
};
},
_resolveClassesValues: function( classes, instance ) {
var result = {};
$.each( classes, function( key ) {
var current = instance.options.classes[ key ] || "";
current = $.trim( current.replace( controlgroupCornerRegex, "" ) );
result[ key ] = ( current + " " + classes[ key ] ).replace( /\s+/g, " " );
} );
return result;
},
_setOption: function( key, value ) {
if ( key === "direction" ) {
this._removeClass( "ui-controlgroup-" + this.options.direction );
}
this._super( key, value );
if ( key === "disabled" ) {
this._callChildMethod( value ? "disable" : "enable" );
return;
}
this.refresh();
},
refresh: function() {
var children,
that = this;
this._addClass( "ui-controlgroup ui-controlgroup-" + this.options.direction );
if ( this.options.direction === "horizontal" ) {
this._addClass( null, "ui-helper-clearfix" );
}
this._initWidgets();
children = this.childWidgets;
// We filter here because we need to track all childWidgets not just the visible ones
if ( this.options.onlyVisible ) {
children = children.filter( ":visible" );
}
if ( children.length ) {
// We do this last because we need to make sure all enhancment is done
// before determining first and last
$.each( [ "first", "last" ], function( index, value ) {
var instance = children[ value ]().data( "ui-controlgroup-data" );
if ( instance && that[ "_" + instance.widgetName + "Options" ] ) {
var options = that[ "_" + instance.widgetName + "Options" ](
children.length === 1 ? "only" : value
);
options.classes = that._resolveClassesValues( options.classes, instance );
instance.element[ instance.widgetName ]( options );
} else {
that._updateCornerClass( children[ value ](), value );
}
} );
// Finally call the refresh method on each of the child widgets.
this._callChildMethod( "refresh" );
}
}
} );
/*!
* jQuery UI Checkboxradio 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Checkboxradio
//>>group: Widgets
//>>description: Enhances a form with multiple themeable checkboxes or radio buttons.
//>>docs: http://api.jqueryui.com/checkboxradio/
//>>demos: http://jqueryui.com/checkboxradio/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/button.css
//>>css.structure: ../../themes/base/checkboxradio.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.checkboxradio", [ $.ui.formResetMixin, {
version: "1.12.1",
options: {
disabled: null,
label: null,
icon: true,
classes: {
"ui-checkboxradio-label": "ui-corner-all",
"ui-checkboxradio-icon": "ui-corner-all"
}
},
_getCreateOptions: function() {
var disabled, labels;
var that = this;
var options = this._super() || {};
// We read the type here, because it makes more sense to throw a element type error first,
// rather then the error for lack of a label. Often if its the wrong type, it
// won't have a label (e.g. calling on a div, btn, etc)
this._readType();
labels = this.element.labels();
// If there are multiple labels, use the last one
this.label = $( labels[ labels.length - 1 ] );
if ( !this.label.length ) {
$.error( "No label found for checkboxradio widget" );
}
this.originalLabel = "";
// We need to get the label text but this may also need to make sure it does not contain the
// input itself.
this.label.contents().not( this.element[ 0 ] ).each( function() {
// The label contents could be text, html, or a mix. We concat each element to get a
// string representation of the label, without the input as part of it.
that.originalLabel += this.nodeType === 3 ? $( this ).text() : this.outerHTML;
} );
// Set the label option if we found label text
if ( this.originalLabel ) {
options.label = this.originalLabel;
}
disabled = this.element[ 0 ].disabled;
if ( disabled != null ) {
options.disabled = disabled;
}
return options;
},
_create: function() {
var checked = this.element[ 0 ].checked;
this._bindFormResetHandler();
if ( this.options.disabled == null ) {
this.options.disabled = this.element[ 0 ].disabled;
}
this._setOption( "disabled", this.options.disabled );
this._addClass( "ui-checkboxradio", "ui-helper-hidden-accessible" );
this._addClass( this.label, "ui-checkboxradio-label", "ui-button ui-widget" );
if ( this.type === "radio" ) {
this._addClass( this.label, "ui-checkboxradio-radio-label" );
}
if ( this.options.label && this.options.label !== this.originalLabel ) {
this._updateLabel();
} else if ( this.originalLabel ) {
this.options.label = this.originalLabel;
}
this._enhance();
if ( checked ) {
this._addClass( this.label, "ui-checkboxradio-checked", "ui-state-active" );
if ( this.icon ) {
this._addClass( this.icon, null, "ui-state-hover" );
}
}
this._on( {
change: "_toggleClasses",
focus: function() {
this._addClass( this.label, null, "ui-state-focus ui-visual-focus" );
},
blur: function() {
this._removeClass( this.label, null, "ui-state-focus ui-visual-focus" );
}
} );
},
_readType: function() {
var nodeName = this.element[ 0 ].nodeName.toLowerCase();
this.type = this.element[ 0 ].type;
if ( nodeName !== "input" || !/radio|checkbox/.test( this.type ) ) {
$.error( "Can't create checkboxradio on element.nodeName=" + nodeName +
" and element.type=" + this.type );
}
},
// Support jQuery Mobile enhanced option
_enhance: function() {
this._updateIcon( this.element[ 0 ].checked );
},
widget: function() {
return this.label;
},
_getRadioGroup: function() {
var group;
var name = this.element[ 0 ].name;
var nameSelector = "input[name='" + $.ui.escapeSelector( name ) + "']";
if ( !name ) {
return $( [] );
}
if ( this.form.length ) {
group = $( this.form[ 0 ].elements ).filter( nameSelector );
} else {
// Not inside a form, check all inputs that also are not inside a form
group = $( nameSelector ).filter( function() {
return $( this ).form().length === 0;
} );
}
return group.not( this.element );
},
_toggleClasses: function() {
var checked = this.element[ 0 ].checked;
this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
if ( this.options.icon && this.type === "checkbox" ) {
this._toggleClass( this.icon, null, "ui-icon-check ui-state-checked", checked )
._toggleClass( this.icon, null, "ui-icon-blank", !checked );
}
if ( this.type === "radio" ) {
this._getRadioGroup()
.each( function() {
var instance = $( this ).checkboxradio( "instance" );
if ( instance ) {
instance._removeClass( instance.label,
"ui-checkboxradio-checked", "ui-state-active" );
}
} );
}
},
_destroy: function() {
this._unbindFormResetHandler();
if ( this.icon ) {
this.icon.remove();
this.iconSpace.remove();
}
},
_setOption: function( key, value ) {
// We don't allow the value to be set to nothing
if ( key === "label" && !value ) {
return;
}
this._super( key, value );
if ( key === "disabled" ) {
this._toggleClass( this.label, null, "ui-state-disabled", value );
this.element[ 0 ].disabled = value;
// Don't refresh when setting disabled
return;
}
this.refresh();
},
_updateIcon: function( checked ) {
var toAdd = "ui-icon ui-icon-background ";
if ( this.options.icon ) {
if ( !this.icon ) {
this.icon = $( "<span>" );
this.iconSpace = $( "<span> </span>" );
this._addClass( this.iconSpace, "ui-checkboxradio-icon-space" );
}
if ( this.type === "checkbox" ) {
toAdd += checked ? "ui-icon-check ui-state-checked" : "ui-icon-blank";
this._removeClass( this.icon, null, checked ? "ui-icon-blank" : "ui-icon-check" );
} else {
toAdd += "ui-icon-blank";
}
this._addClass( this.icon, "ui-checkboxradio-icon", toAdd );
if ( !checked ) {
this._removeClass( this.icon, null, "ui-icon-check ui-state-checked" );
}
this.icon.prependTo( this.label ).after( this.iconSpace );
} else if ( this.icon !== undefined ) {
this.icon.remove();
this.iconSpace.remove();
delete this.icon;
}
},
_updateLabel: function() {
// Remove the contents of the label ( minus the icon, icon space, and input )
var contents = this.label.contents().not( this.element[ 0 ] );
if ( this.icon ) {
contents = contents.not( this.icon[ 0 ] );
}
if ( this.iconSpace ) {
contents = contents.not( this.iconSpace[ 0 ] );
}
contents.remove();
this.label.append( this.options.label );
},
refresh: function() {
var checked = this.element[ 0 ].checked,
isDisabled = this.element[ 0 ].disabled;
this._updateIcon( checked );
this._toggleClass( this.label, "ui-checkboxradio-checked", "ui-state-active", checked );
if ( this.options.label !== null ) {
this._updateLabel();
}
if ( isDisabled !== this.options.disabled ) {
this._setOptions( { "disabled": isDisabled } );
}
}
} ] );
var widgetsCheckboxradio = $.ui.checkboxradio;
/*!
* jQuery UI Button 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Button
//>>group: Widgets
//>>description: Enhances a form with themeable buttons.
//>>docs: http://api.jqueryui.com/button/
//>>demos: http://jqueryui.com/button/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/button.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.button", {
version: "1.12.1",
defaultElement: "<button>",
options: {
classes: {
"ui-button": "ui-corner-all"
},
disabled: null,
icon: null,
iconPosition: "beginning",
label: null,
showLabel: true
},
_getCreateOptions: function() {
var disabled,
// This is to support cases like in jQuery Mobile where the base widget does have
// an implementation of _getCreateOptions
options = this._super() || {};
this.isInput = this.element.is( "input" );
disabled = this.element[ 0 ].disabled;
if ( disabled != null ) {
options.disabled = disabled;
}
this.originalLabel = this.isInput ? this.element.val() : this.element.html();
if ( this.originalLabel ) {
options.label = this.originalLabel;
}
return options;
},
_create: function() {
if ( !this.option.showLabel & !this.options.icon ) {
this.options.showLabel = true;
}
// We have to check the option again here even though we did in _getCreateOptions,
// because null may have been passed on init which would override what was set in
// _getCreateOptions
if ( this.options.disabled == null ) {
this.options.disabled = this.element[ 0 ].disabled || false;
}
this.hasTitle = !!this.element.attr( "title" );
// Check to see if the label needs to be set or if its already correct
if ( this.options.label && this.options.label !== this.originalLabel ) {
if ( this.isInput ) {
this.element.val( this.options.label );
} else {
this.element.html( this.options.label );
}
}
this._addClass( "ui-button", "ui-widget" );
this._setOption( "disabled", this.options.disabled );
this._enhance();
if ( this.element.is( "a" ) ) {
this._on( {
"keyup": function( event ) {
if ( event.keyCode === $.ui.keyCode.SPACE ) {
event.preventDefault();
// Support: PhantomJS <= 1.9, IE 8 Only
// If a native click is available use it so we actually cause navigation
// otherwise just trigger a click event
if ( this.element[ 0 ].click ) {
this.element[ 0 ].click();
} else {
this.element.trigger( "click" );
}
}
}
} );
}
},
_enhance: function() {
if ( !this.element.is( "button" ) ) {
this.element.attr( "role", "button" );
}
if ( this.options.icon ) {
this._updateIcon( "icon", this.options.icon );
this._updateTooltip();
}
},
_updateTooltip: function() {
this.title = this.element.attr( "title" );
if ( !this.options.showLabel && !this.title ) {
this.element.attr( "title", this.options.label );
}
},
_updateIcon: function( option, value ) {
var icon = option !== "iconPosition",
position = icon ? this.options.iconPosition : value,
displayBlock = position === "top" || position === "bottom";
// Create icon
if ( !this.icon ) {
this.icon = $( "<span>" );
this._addClass( this.icon, "ui-button-icon", "ui-icon" );
if ( !this.options.showLabel ) {
this._addClass( "ui-button-icon-only" );
}
} else if ( icon ) {
// If we are updating the icon remove the old icon class
this._removeClass( this.icon, null, this.options.icon );
}
// If we are updating the icon add the new icon class
if ( icon ) {
this._addClass( this.icon, null, value );
}
this._attachIcon( position );
// If the icon is on top or bottom we need to add the ui-widget-icon-block class and remove
// the iconSpace if there is one.
if ( displayBlock ) {
this._addClass( this.icon, null, "ui-widget-icon-block" );
if ( this.iconSpace ) {
this.iconSpace.remove();
}
} else {
// Position is beginning or end so remove the ui-widget-icon-block class and add the
// space if it does not exist
if ( !this.iconSpace ) {
this.iconSpace = $( "<span> </span>" );
this._addClass( this.iconSpace, "ui-button-icon-space" );
}
this._removeClass( this.icon, null, "ui-wiget-icon-block" );
this._attachIconSpace( position );
}
},
_destroy: function() {
this.element.removeAttr( "role" );
if ( this.icon ) {
this.icon.remove();
}
if ( this.iconSpace ) {
this.iconSpace.remove();
}
if ( !this.hasTitle ) {
this.element.removeAttr( "title" );
}
},
_attachIconSpace: function( iconPosition ) {
this.icon[ /^(?:end|bottom)/.test( iconPosition ) ? "before" : "after" ]( this.iconSpace );
},
_attachIcon: function( iconPosition ) {
this.element[ /^(?:end|bottom)/.test( iconPosition ) ? "append" : "prepend" ]( this.icon );
},
_setOptions: function( options ) {
var newShowLabel = options.showLabel === undefined ?
this.options.showLabel :
options.showLabel,
newIcon = options.icon === undefined ? this.options.icon : options.icon;
if ( !newShowLabel && !newIcon ) {
options.showLabel = true;
}
this._super( options );
},
_setOption: function( key, value ) {
if ( key === "icon" ) {
if ( value ) {
this._updateIcon( key, value );
} else if ( this.icon ) {
this.icon.remove();
if ( this.iconSpace ) {
this.iconSpace.remove();
}
}
}
if ( key === "iconPosition" ) {
this._updateIcon( key, value );
}
// Make sure we can't end up with a button that has neither text nor icon
if ( key === "showLabel" ) {
this._toggleClass( "ui-button-icon-only", null, !value );
this._updateTooltip();
}
if ( key === "label" ) {
if ( this.isInput ) {
this.element.val( value );
} else {
// If there is an icon, append it, else nothing then append the value
// this avoids removal of the icon when setting label text
this.element.html( value );
if ( this.icon ) {
this._attachIcon( this.options.iconPosition );
this._attachIconSpace( this.options.iconPosition );
}
}
}
this._super( key, value );
if ( key === "disabled" ) {
this._toggleClass( null, "ui-state-disabled", value );
this.element[ 0 ].disabled = value;
if ( value ) {
this.element.blur();
}
}
},
refresh: function() {
// Make sure to only check disabled if its an element that supports this otherwise
// check for the disabled class to determine state
var isDisabled = this.element.is( "input, button" ) ?
this.element[ 0 ].disabled : this.element.hasClass( "ui-button-disabled" );
if ( isDisabled !== this.options.disabled ) {
this._setOptions( { disabled: isDisabled } );
}
this._updateTooltip();
}
} );
// DEPRECATED
if ( $.uiBackCompat !== false ) {
// Text and Icons options
$.widget( "ui.button", $.ui.button, {
options: {
text: true,
icons: {
primary: null,
secondary: null
}
},
_create: function() {
if ( this.options.showLabel && !this.options.text ) {
this.options.showLabel = this.options.text;
}
if ( !this.options.showLabel && this.options.text ) {
this.options.text = this.options.showLabel;
}
if ( !this.options.icon && ( this.options.icons.primary ||
this.options.icons.secondary ) ) {
if ( this.options.icons.primary ) {
this.options.icon = this.options.icons.primary;
} else {
this.options.icon = this.options.icons.secondary;
this.options.iconPosition = "end";
}
} else if ( this.options.icon ) {
this.options.icons.primary = this.options.icon;
}
this._super();
},
_setOption: function( key, value ) {
if ( key === "text" ) {
this._super( "showLabel", value );
return;
}
if ( key === "showLabel" ) {
this.options.text = value;
}
if ( key === "icon" ) {
this.options.icons.primary = value;
}
if ( key === "icons" ) {
if ( value.primary ) {
this._super( "icon", value.primary );
this._super( "iconPosition", "beginning" );
} else if ( value.secondary ) {
this._super( "icon", value.secondary );
this._super( "iconPosition", "end" );
}
}
this._superApply( arguments );
}
} );
$.fn.button = ( function( orig ) {
return function() {
if ( !this.length || ( this.length && this[ 0 ].tagName !== "INPUT" ) ||
( this.length && this[ 0 ].tagName === "INPUT" && (
this.attr( "type" ) !== "checkbox" && this.attr( "type" ) !== "radio"
) ) ) {
return orig.apply( this, arguments );
}
if ( !$.ui.checkboxradio ) {
$.error( "Checkboxradio widget missing" );
}
if ( arguments.length === 0 ) {
return this.checkboxradio( {
"icon": false
} );
}
return this.checkboxradio.apply( this, arguments );
};
} )( $.fn.button );
$.fn.buttonset = function() {
if ( !$.ui.controlgroup ) {
$.error( "Controlgroup widget missing" );
}
if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" && arguments[ 2 ] ) {
return this.controlgroup.apply( this,
[ arguments[ 0 ], "items.button", arguments[ 2 ] ] );
}
if ( arguments[ 0 ] === "option" && arguments[ 1 ] === "items" ) {
return this.controlgroup.apply( this, [ arguments[ 0 ], "items.button" ] );
}
if ( typeof arguments[ 0 ] === "object" && arguments[ 0 ].items ) {
arguments[ 0 ].items = {
button: arguments[ 0 ].items
};
}
return this.controlgroup.apply( this, arguments );
};
}
var widgetsButton = $.ui.button;
// jscs:disable maximumLineLength
/* jscs:disable requireCamelCaseOrUpperCaseIdentifiers */
/*!
* jQuery UI Datepicker 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Datepicker
//>>group: Widgets
//>>description: Displays a calendar from an input or inline for selecting dates.
//>>docs: http://api.jqueryui.com/datepicker/
//>>demos: http://jqueryui.com/datepicker/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/datepicker.css
//>>css.theme: ../../themes/base/theme.css
$.extend( $.ui, { datepicker: { version: "1.12.1" } } );
var datepicker_instActive;
function datepicker_getZindex( elem ) {
var position, value;
while ( elem.length && elem[ 0 ] !== document ) {
// Ignore z-index if position is set to a value where z-index is ignored by the browser
// This makes behavior of this function consistent across browsers
// WebKit always returns auto if the element is positioned
position = elem.css( "position" );
if ( position === "absolute" || position === "relative" || position === "fixed" ) {
// IE returns 0 when zIndex is not specified
// other browsers return a string
// we ignore the case of nested elements with an explicit value of 0
// <div style="z-index: -10;"><div style="z-index: 0;"></div></div>
value = parseInt( elem.css( "zIndex" ), 10 );
if ( !isNaN( value ) && value !== 0 ) {
return value;
}
}
elem = elem.parent();
}
return 0;
}
/* Date picker manager.
Use the singleton instance of this class, $.datepicker, to interact with the date picker.
Settings for (groups of) date pickers are maintained in an instance object,
allowing multiple different settings on the same page. */
function Datepicker() {
this._curInst = null; // The current instance in use
this._keyEvent = false; // If the last event was a key event
this._disabledInputs = []; // List of date picker inputs that have been disabled
this._datepickerShowing = false; // True if the popup picker is showing , false if not
this._inDialog = false; // True if showing within a "dialog", false if not
this._mainDivId = "ui-datepicker-div"; // The ID of the main datepicker division
this._inlineClass = "ui-datepicker-inline"; // The name of the inline marker class
this._appendClass = "ui-datepicker-append"; // The name of the append marker class
this._triggerClass = "ui-datepicker-trigger"; // The name of the trigger marker class
this._dialogClass = "ui-datepicker-dialog"; // The name of the dialog marker class
this._disableClass = "ui-datepicker-disabled"; // The name of the disabled covering marker class
this._unselectableClass = "ui-datepicker-unselectable"; // The name of the unselectable cell marker class
this._currentClass = "ui-datepicker-current-day"; // The name of the current day marker class
this._dayOverClass = "ui-datepicker-days-cell-over"; // The name of the day hover marker class
this.regional = []; // Available regional settings, indexed by language code
this.regional[ "" ] = { // Default regional settings
closeText: "Done", // Display text for close link
prevText: "Prev", // Display text for previous month link
nextText: "Next", // Display text for next month link
currentText: "Today", // Display text for current month link
monthNames: [ "January","February","March","April","May","June",
"July","August","September","October","November","December" ], // Names of months for drop-down and formatting
monthNamesShort: [ "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ], // For formatting
dayNames: [ "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" ], // For formatting
dayNamesShort: [ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" ], // For formatting
dayNamesMin: [ "Su","Mo","Tu","We","Th","Fr","Sa" ], // Column headings for days starting at Sunday
weekHeader: "Wk", // Column header for week of the year
dateFormat: "mm/dd/yy", // See format options on parseDate
firstDay: 0, // The first day of the week, Sun = 0, Mon = 1, ...
isRTL: false, // True if right-to-left language, false if left-to-right
showMonthAfterYear: false, // True if the year select precedes month, false for month then year
yearSuffix: "" // Additional text to append to the year in the month headers
};
this._defaults = { // Global defaults for all the date picker instances
showOn: "focus", // "focus" for popup on focus,
// "button" for trigger button, or "both" for either
showAnim: "fadeIn", // Name of jQuery animation for popup
showOptions: {}, // Options for enhanced animations
defaultDate: null, // Used when field is blank: actual date,
// +/-number for offset from today, null for today
appendText: "", // Display text following the input box, e.g. showing the format
buttonText: "...", // Text for trigger button
buttonImage: "", // URL for trigger button image
buttonImageOnly: false, // True if the image appears alone, false if it appears on a button
hideIfNoPrevNext: false, // True to hide next/previous month links
// if not applicable, false to just disable them
navigationAsDateFormat: false, // True if date formatting applied to prev/today/next links
gotoCurrent: false, // True if today link goes back to current selection instead
changeMonth: false, // True if month can be selected directly, false if only prev/next
changeYear: false, // True if year can be selected directly, false if only prev/next
yearRange: "c-10:c+10", // Range of years to display in drop-down,
// either relative to today's year (-nn:+nn), relative to currently displayed year
// (c-nn:c+nn), absolute (nnnn:nnnn), or a combination of the above (nnnn:-n)
showOtherMonths: false, // True to show dates in other months, false to leave blank
selectOtherMonths: false, // True to allow selection of dates in other months, false for unselectable
showWeek: false, // True to show week of the year, false to not show it
calculateWeek: this.iso8601Week, // How to calculate the week of the year,
// takes a Date and returns the number of the week for it
shortYearCutoff: "+10", // Short year values < this are in the current century,
// > this are in the previous century,
// string value starting with "+" for current year + value
minDate: null, // The earliest selectable date, or null for no limit
maxDate: null, // The latest selectable date, or null for no limit
duration: "fast", // Duration of display/closure
beforeShowDay: null, // Function that takes a date and returns an array with
// [0] = true if selectable, false if not, [1] = custom CSS class name(s) or "",
// [2] = cell title (optional), e.g. $.datepicker.noWeekends
beforeShow: null, // Function that takes an input field and
// returns a set of custom settings for the date picker
onSelect: null, // Define a callback function when a date is selected
onChangeMonthYear: null, // Define a callback function when the month or year is changed
onClose: null, // Define a callback function when the datepicker is closed
numberOfMonths: 1, // Number of months to show at a time
showCurrentAtPos: 0, // The position in multipe months at which to show the current month (starting at 0)
stepMonths: 1, // Number of months to step back/forward
stepBigMonths: 12, // Number of months to step back/forward for the big links
altField: "", // Selector for an alternate field to store selected dates into
altFormat: "", // The date format to use for the alternate field
constrainInput: true, // The input is constrained by the current date format
showButtonPanel: false, // True to show button panel, false to not show it
autoSize: false, // True to size the input for the date format, false to leave as is
disabled: false // The initial disabled state
};
$.extend( this._defaults, this.regional[ "" ] );
this.regional.en = $.extend( true, {}, this.regional[ "" ] );
this.regional[ "en-US" ] = $.extend( true, {}, this.regional.en );
this.dpDiv = datepicker_bindHover( $( "<div id='" + this._mainDivId + "' class='ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) );
}
$.extend( Datepicker.prototype, {
/* Class name added to elements to indicate already configured with a date picker. */
markerClassName: "hasDatepicker",
//Keep track of the maximum number of rows displayed (see #7043)
maxRows: 4,
// TODO rename to "widget" when switching to widget factory
_widgetDatepicker: function() {
return this.dpDiv;
},
/* Override the default settings for all instances of the date picker.
* @param settings object - the new settings to use as defaults (anonymous object)
* @return the manager object
*/
setDefaults: function( settings ) {
datepicker_extendRemove( this._defaults, settings || {} );
return this;
},
/* Attach the date picker to a jQuery selection.
* @param target element - the target input field or division or span
* @param settings object - the new settings to use for this date picker instance (anonymous)
*/
_attachDatepicker: function( target, settings ) {
var nodeName, inline, inst;
nodeName = target.nodeName.toLowerCase();
inline = ( nodeName === "div" || nodeName === "span" );
if ( !target.id ) {
this.uuid += 1;
target.id = "dp" + this.uuid;
}
inst = this._newInst( $( target ), inline );
inst.settings = $.extend( {}, settings || {} );
if ( nodeName === "input" ) {
this._connectDatepicker( target, inst );
} else if ( inline ) {
this._inlineDatepicker( target, inst );
}
},
/* Create a new instance object. */
_newInst: function( target, inline ) {
var id = target[ 0 ].id.replace( /([^A-Za-z0-9_\-])/g, "\\\\$1" ); // escape jQuery meta chars
return { id: id, input: target, // associated target
selectedDay: 0, selectedMonth: 0, selectedYear: 0, // current selection
drawMonth: 0, drawYear: 0, // month being drawn
inline: inline, // is datepicker inline or not
dpDiv: ( !inline ? this.dpDiv : // presentation div
datepicker_bindHover( $( "<div class='" + this._inlineClass + " ui-datepicker ui-widget ui-widget-content ui-helper-clearfix ui-corner-all'></div>" ) ) ) };
},
/* Attach the date picker to an input field. */
_connectDatepicker: function( target, inst ) {
var input = $( target );
inst.append = $( [] );
inst.trigger = $( [] );
if ( input.hasClass( this.markerClassName ) ) {
return;
}
this._attachments( input, inst );
input.addClass( this.markerClassName ).on( "keydown", this._doKeyDown ).
on( "keypress", this._doKeyPress ).on( "keyup", this._doKeyUp );
this._autoSize( inst );
$.data( target, "datepicker", inst );
//If disabled option is true, disable the datepicker once it has been attached to the input (see ticket #5665)
if ( inst.settings.disabled ) {
this._disableDatepicker( target );
}
},
/* Make attachments based on settings. */
_attachments: function( input, inst ) {
var showOn, buttonText, buttonImage,
appendText = this._get( inst, "appendText" ),
isRTL = this._get( inst, "isRTL" );
if ( inst.append ) {
inst.append.remove();
}
if ( appendText ) {
inst.append = $( "<span class='" + this._appendClass + "'>" + appendText + "</span>" );
input[ isRTL ? "before" : "after" ]( inst.append );
}
input.off( "focus", this._showDatepicker );
if ( inst.trigger ) {
inst.trigger.remove();
}
showOn = this._get( inst, "showOn" );
if ( showOn === "focus" || showOn === "both" ) { // pop-up date picker when in the marked field
input.on( "focus", this._showDatepicker );
}
if ( showOn === "button" || showOn === "both" ) { // pop-up date picker when button clicked
buttonText = this._get( inst, "buttonText" );
buttonImage = this._get( inst, "buttonImage" );
inst.trigger = $( this._get( inst, "buttonImageOnly" ) ?
$( "<img/>" ).addClass( this._triggerClass ).
attr( { src: buttonImage, alt: buttonText, title: buttonText } ) :
$( "<button type='button'></button>" ).addClass( this._triggerClass ).
html( !buttonImage ? buttonText : $( "<img/>" ).attr(
{ src:buttonImage, alt:buttonText, title:buttonText } ) ) );
input[ isRTL ? "before" : "after" ]( inst.trigger );
inst.trigger.on( "click", function() {
if ( $.datepicker._datepickerShowing && $.datepicker._lastInput === input[ 0 ] ) {
$.datepicker._hideDatepicker();
} else if ( $.datepicker._datepickerShowing && $.datepicker._lastInput !== input[ 0 ] ) {
$.datepicker._hideDatepicker();
$.datepicker._showDatepicker( input[ 0 ] );
} else {
$.datepicker._showDatepicker( input[ 0 ] );
}
return false;
} );
}
},
/* Apply the maximum length for the date format. */
_autoSize: function( inst ) {
if ( this._get( inst, "autoSize" ) && !inst.inline ) {
var findMax, max, maxI, i,
date = new Date( 2009, 12 - 1, 20 ), // Ensure double digits
dateFormat = this._get( inst, "dateFormat" );
if ( dateFormat.match( /[DM]/ ) ) {
findMax = function( names ) {
max = 0;
maxI = 0;
for ( i = 0; i < names.length; i++ ) {
if ( names[ i ].length > max ) {
max = names[ i ].length;
maxI = i;
}
}
return maxI;
};
date.setMonth( findMax( this._get( inst, ( dateFormat.match( /MM/ ) ?
"monthNames" : "monthNamesShort" ) ) ) );
date.setDate( findMax( this._get( inst, ( dateFormat.match( /DD/ ) ?
"dayNames" : "dayNamesShort" ) ) ) + 20 - date.getDay() );
}
inst.input.attr( "size", this._formatDate( inst, date ).length );
}
},
/* Attach an inline date picker to a div. */
_inlineDatepicker: function( target, inst ) {
var divSpan = $( target );
if ( divSpan.hasClass( this.markerClassName ) ) {
return;
}
divSpan.addClass( this.markerClassName ).append( inst.dpDiv );
$.data( target, "datepicker", inst );
this._setDate( inst, this._getDefaultDate( inst ), true );
this._updateDatepicker( inst );
this._updateAlternate( inst );
//If disabled option is true, disable the datepicker before showing it (see ticket #5665)
if ( inst.settings.disabled ) {
this._disableDatepicker( target );
}
// Set display:block in place of inst.dpDiv.show() which won't work on disconnected elements
// http://bugs.jqueryui.com/ticket/7552 - A Datepicker created on a detached div has zero height
inst.dpDiv.css( "display", "block" );
},
/* Pop-up the date picker in a "dialog" box.
* @param input element - ignored
* @param date string or Date - the initial date to display
* @param onSelect function - the function to call when a date is selected
* @param settings object - update the dialog date picker instance's settings (anonymous object)
* @param pos int[2] - coordinates for the dialog's position within the screen or
* event - with x/y coordinates or
* leave empty for default (screen centre)
* @return the manager object
*/
_dialogDatepicker: function( input, date, onSelect, settings, pos ) {
var id, browserWidth, browserHeight, scrollX, scrollY,
inst = this._dialogInst; // internal instance
if ( !inst ) {
this.uuid += 1;
id = "dp" + this.uuid;
this._dialogInput = $( "<input type='text' id='" + id +
"' style='position: absolute; top: -100px; width: 0px;'/>" );
this._dialogInput.on( "keydown", this._doKeyDown );
$( "body" ).append( this._dialogInput );
inst = this._dialogInst = this._newInst( this._dialogInput, false );
inst.settings = {};
$.data( this._dialogInput[ 0 ], "datepicker", inst );
}
datepicker_extendRemove( inst.settings, settings || {} );
date = ( date && date.constructor === Date ? this._formatDate( inst, date ) : date );
this._dialogInput.val( date );
this._pos = ( pos ? ( pos.length ? pos : [ pos.pageX, pos.pageY ] ) : null );
if ( !this._pos ) {
browserWidth = document.documentElement.clientWidth;
browserHeight = document.documentElement.clientHeight;
scrollX = document.documentElement.scrollLeft || document.body.scrollLeft;
scrollY = document.documentElement.scrollTop || document.body.scrollTop;
this._pos = // should use actual width/height below
[ ( browserWidth / 2 ) - 100 + scrollX, ( browserHeight / 2 ) - 150 + scrollY ];
}
// Move input on screen for focus, but hidden behind dialog
this._dialogInput.css( "left", ( this._pos[ 0 ] + 20 ) + "px" ).css( "top", this._pos[ 1 ] + "px" );
inst.settings.onSelect = onSelect;
this._inDialog = true;
this.dpDiv.addClass( this._dialogClass );
this._showDatepicker( this._dialogInput[ 0 ] );
if ( $.blockUI ) {
$.blockUI( this.dpDiv );
}
$.data( this._dialogInput[ 0 ], "datepicker", inst );
return this;
},
/* Detach a datepicker from its control.
* @param target element - the target input field or division or span
*/
_destroyDatepicker: function( target ) {
var nodeName,
$target = $( target ),
inst = $.data( target, "datepicker" );
if ( !$target.hasClass( this.markerClassName ) ) {
return;
}
nodeName = target.nodeName.toLowerCase();
$.removeData( target, "datepicker" );
if ( nodeName === "input" ) {
inst.append.remove();
inst.trigger.remove();
$target.removeClass( this.markerClassName ).
off( "focus", this._showDatepicker ).
off( "keydown", this._doKeyDown ).
off( "keypress", this._doKeyPress ).
off( "keyup", this._doKeyUp );
} else if ( nodeName === "div" || nodeName === "span" ) {
$target.removeClass( this.markerClassName ).empty();
}
if ( datepicker_instActive === inst ) {
datepicker_instActive = null;
}
},
/* Enable the date picker to a jQuery selection.
* @param target element - the target input field or division or span
*/
_enableDatepicker: function( target ) {
var nodeName, inline,
$target = $( target ),
inst = $.data( target, "datepicker" );
if ( !$target.hasClass( this.markerClassName ) ) {
return;
}
nodeName = target.nodeName.toLowerCase();
if ( nodeName === "input" ) {
target.disabled = false;
inst.trigger.filter( "button" ).
each( function() { this.disabled = false; } ).end().
filter( "img" ).css( { opacity: "1.0", cursor: "" } );
} else if ( nodeName === "div" || nodeName === "span" ) {
inline = $target.children( "." + this._inlineClass );
inline.children().removeClass( "ui-state-disabled" );
inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
prop( "disabled", false );
}
this._disabledInputs = $.map( this._disabledInputs,
function( value ) { return ( value === target ? null : value ); } ); // delete entry
},
/* Disable the date picker to a jQuery selection.
* @param target element - the target input field or division or span
*/
_disableDatepicker: function( target ) {
var nodeName, inline,
$target = $( target ),
inst = $.data( target, "datepicker" );
if ( !$target.hasClass( this.markerClassName ) ) {
return;
}
nodeName = target.nodeName.toLowerCase();
if ( nodeName === "input" ) {
target.disabled = true;
inst.trigger.filter( "button" ).
each( function() { this.disabled = true; } ).end().
filter( "img" ).css( { opacity: "0.5", cursor: "default" } );
} else if ( nodeName === "div" || nodeName === "span" ) {
inline = $target.children( "." + this._inlineClass );
inline.children().addClass( "ui-state-disabled" );
inline.find( "select.ui-datepicker-month, select.ui-datepicker-year" ).
prop( "disabled", true );
}
this._disabledInputs = $.map( this._disabledInputs,
function( value ) { return ( value === target ? null : value ); } ); // delete entry
this._disabledInputs[ this._disabledInputs.length ] = target;
},
/* Is the first field in a jQuery collection disabled as a datepicker?
* @param target element - the target input field or division or span
* @return boolean - true if disabled, false if enabled
*/
_isDisabledDatepicker: function( target ) {
if ( !target ) {
return false;
}
for ( var i = 0; i < this._disabledInputs.length; i++ ) {
if ( this._disabledInputs[ i ] === target ) {
return true;
}
}
return false;
},
/* Retrieve the instance data for the target control.
* @param target element - the target input field or division or span
* @return object - the associated instance data
* @throws error if a jQuery problem getting data
*/
_getInst: function( target ) {
try {
return $.data( target, "datepicker" );
}
catch ( err ) {
throw "Missing instance data for this datepicker";
}
},
/* Update or retrieve the settings for a date picker attached to an input field or division.
* @param target element - the target input field or division or span
* @param name object - the new settings to update or
* string - the name of the setting to change or retrieve,
* when retrieving also "all" for all instance settings or
* "defaults" for all global defaults
* @param value any - the new value for the setting
* (omit if above is an object or to retrieve a value)
*/
_optionDatepicker: function( target, name, value ) {
var settings, date, minDate, maxDate,
inst = this._getInst( target );
if ( arguments.length === 2 && typeof name === "string" ) {
return ( name === "defaults" ? $.extend( {}, $.datepicker._defaults ) :
( inst ? ( name === "all" ? $.extend( {}, inst.settings ) :
this._get( inst, name ) ) : null ) );
}
settings = name || {};
if ( typeof name === "string" ) {
settings = {};
settings[ name ] = value;
}
if ( inst ) {
if ( this._curInst === inst ) {
this._hideDatepicker();
}
date = this._getDateDatepicker( target, true );
minDate = this._getMinMaxDate( inst, "min" );
maxDate = this._getMinMaxDate( inst, "max" );
datepicker_extendRemove( inst.settings, settings );
// reformat the old minDate/maxDate values if dateFormat changes and a new minDate/maxDate isn't provided
if ( minDate !== null && settings.dateFormat !== undefined && settings.minDate === undefined ) {
inst.settings.minDate = this._formatDate( inst, minDate );
}
if ( maxDate !== null && settings.dateFormat !== undefined && settings.maxDate === undefined ) {
inst.settings.maxDate = this._formatDate( inst, maxDate );
}
if ( "disabled" in settings ) {
if ( settings.disabled ) {
this._disableDatepicker( target );
} else {
this._enableDatepicker( target );
}
}
this._attachments( $( target ), inst );
this._autoSize( inst );
this._setDate( inst, date );
this._updateAlternate( inst );
this._updateDatepicker( inst );
}
},
// Change method deprecated
_changeDatepicker: function( target, name, value ) {
this._optionDatepicker( target, name, value );
},
/* Redraw the date picker attached to an input field or division.
* @param target element - the target input field or division or span
*/
_refreshDatepicker: function( target ) {
var inst = this._getInst( target );
if ( inst ) {
this._updateDatepicker( inst );
}
},
/* Set the dates for a jQuery selection.
* @param target element - the target input field or division or span
* @param date Date - the new date
*/
_setDateDatepicker: function( target, date ) {
var inst = this._getInst( target );
if ( inst ) {
this._setDate( inst, date );
this._updateDatepicker( inst );
this._updateAlternate( inst );
}
},
/* Get the date(s) for the first entry in a jQuery selection.
* @param target element - the target input field or division or span
* @param noDefault boolean - true if no default date is to be used
* @return Date - the current date
*/
_getDateDatepicker: function( target, noDefault ) {
var inst = this._getInst( target );
if ( inst && !inst.inline ) {
this._setDateFromField( inst, noDefault );
}
return ( inst ? this._getDate( inst ) : null );
},
/* Handle keystrokes. */
_doKeyDown: function( event ) {
var onSelect, dateStr, sel,
inst = $.datepicker._getInst( event.target ),
handled = true,
isRTL = inst.dpDiv.is( ".ui-datepicker-rtl" );
inst._keyEvent = true;
if ( $.datepicker._datepickerShowing ) {
switch ( event.keyCode ) {
case 9: $.datepicker._hideDatepicker();
handled = false;
break; // hide on tab out
case 13: sel = $( "td." + $.datepicker._dayOverClass + ":not(." +
$.datepicker._currentClass + ")", inst.dpDiv );
if ( sel[ 0 ] ) {
$.datepicker._selectDay( event.target, inst.selectedMonth, inst.selectedYear, sel[ 0 ] );
}
onSelect = $.datepicker._get( inst, "onSelect" );
if ( onSelect ) {
dateStr = $.datepicker._formatDate( inst );
// Trigger custom callback
onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] );
} else {
$.datepicker._hideDatepicker();
}
return false; // don't submit the form
case 27: $.datepicker._hideDatepicker();
break; // hide on escape
case 33: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
-$.datepicker._get( inst, "stepBigMonths" ) :
-$.datepicker._get( inst, "stepMonths" ) ), "M" );
break; // previous month/year on page up/+ ctrl
case 34: $.datepicker._adjustDate( event.target, ( event.ctrlKey ?
+$.datepicker._get( inst, "stepBigMonths" ) :
+$.datepicker._get( inst, "stepMonths" ) ), "M" );
break; // next month/year on page down/+ ctrl
case 35: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._clearDate( event.target );
}
handled = event.ctrlKey || event.metaKey;
break; // clear on ctrl or command +end
case 36: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._gotoToday( event.target );
}
handled = event.ctrlKey || event.metaKey;
break; // current on ctrl or command +home
case 37: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._adjustDate( event.target, ( isRTL ? +1 : -1 ), "D" );
}
handled = event.ctrlKey || event.metaKey;
// -1 day on ctrl or command +left
if ( event.originalEvent.altKey ) {
$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
-$.datepicker._get( inst, "stepBigMonths" ) :
-$.datepicker._get( inst, "stepMonths" ) ), "M" );
}
// next month/year on alt +left on Mac
break;
case 38: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._adjustDate( event.target, -7, "D" );
}
handled = event.ctrlKey || event.metaKey;
break; // -1 week on ctrl or command +up
case 39: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._adjustDate( event.target, ( isRTL ? -1 : +1 ), "D" );
}
handled = event.ctrlKey || event.metaKey;
// +1 day on ctrl or command +right
if ( event.originalEvent.altKey ) {
$.datepicker._adjustDate( event.target, ( event.ctrlKey ?
+$.datepicker._get( inst, "stepBigMonths" ) :
+$.datepicker._get( inst, "stepMonths" ) ), "M" );
}
// next month/year on alt +right
break;
case 40: if ( event.ctrlKey || event.metaKey ) {
$.datepicker._adjustDate( event.target, +7, "D" );
}
handled = event.ctrlKey || event.metaKey;
break; // +1 week on ctrl or command +down
default: handled = false;
}
} else if ( event.keyCode === 36 && event.ctrlKey ) { // display the date picker on ctrl+home
$.datepicker._showDatepicker( this );
} else {
handled = false;
}
if ( handled ) {
event.preventDefault();
event.stopPropagation();
}
},
/* Filter entered characters - based on date format. */
_doKeyPress: function( event ) {
var chars, chr,
inst = $.datepicker._getInst( event.target );
if ( $.datepicker._get( inst, "constrainInput" ) ) {
chars = $.datepicker._possibleChars( $.datepicker._get( inst, "dateFormat" ) );
chr = String.fromCharCode( event.charCode == null ? event.keyCode : event.charCode );
return event.ctrlKey || event.metaKey || ( chr < " " || !chars || chars.indexOf( chr ) > -1 );
}
},
/* Synchronise manual entry and field/alternate field. */
_doKeyUp: function( event ) {
var date,
inst = $.datepicker._getInst( event.target );
if ( inst.input.val() !== inst.lastVal ) {
try {
date = $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
( inst.input ? inst.input.val() : null ),
$.datepicker._getFormatConfig( inst ) );
if ( date ) { // only if valid
$.datepicker._setDateFromField( inst );
$.datepicker._updateAlternate( inst );
$.datepicker._updateDatepicker( inst );
}
}
catch ( err ) {
}
}
return true;
},
/* Pop-up the date picker for a given input field.
* If false returned from beforeShow event handler do not show.
* @param input element - the input field attached to the date picker or
* event - if triggered by focus
*/
_showDatepicker: function( input ) {
input = input.target || input;
if ( input.nodeName.toLowerCase() !== "input" ) { // find from button/image trigger
input = $( "input", input.parentNode )[ 0 ];
}
if ( $.datepicker._isDisabledDatepicker( input ) || $.datepicker._lastInput === input ) { // already here
return;
}
var inst, beforeShow, beforeShowSettings, isFixed,
offset, showAnim, duration;
inst = $.datepicker._getInst( input );
if ( $.datepicker._curInst && $.datepicker._curInst !== inst ) {
$.datepicker._curInst.dpDiv.stop( true, true );
if ( inst && $.datepicker._datepickerShowing ) {
$.datepicker._hideDatepicker( $.datepicker._curInst.input[ 0 ] );
}
}
beforeShow = $.datepicker._get( inst, "beforeShow" );
beforeShowSettings = beforeShow ? beforeShow.apply( input, [ input, inst ] ) : {};
if ( beforeShowSettings === false ) {
return;
}
datepicker_extendRemove( inst.settings, beforeShowSettings );
inst.lastVal = null;
$.datepicker._lastInput = input;
$.datepicker._setDateFromField( inst );
if ( $.datepicker._inDialog ) { // hide cursor
input.value = "";
}
if ( !$.datepicker._pos ) { // position below input
$.datepicker._pos = $.datepicker._findPos( input );
$.datepicker._pos[ 1 ] += input.offsetHeight; // add the height
}
isFixed = false;
$( input ).parents().each( function() {
isFixed |= $( this ).css( "position" ) === "fixed";
return !isFixed;
} );
offset = { left: $.datepicker._pos[ 0 ], top: $.datepicker._pos[ 1 ] };
$.datepicker._pos = null;
//to avoid flashes on Firefox
inst.dpDiv.empty();
// determine sizing offscreen
inst.dpDiv.css( { position: "absolute", display: "block", top: "-1000px" } );
$.datepicker._updateDatepicker( inst );
// fix width for dynamic number of date pickers
// and adjust position before showing
offset = $.datepicker._checkOffset( inst, offset, isFixed );
inst.dpDiv.css( { position: ( $.datepicker._inDialog && $.blockUI ?
"static" : ( isFixed ? "fixed" : "absolute" ) ), display: "none",
left: offset.left + "px", top: offset.top + "px" } );
if ( !inst.inline ) {
showAnim = $.datepicker._get( inst, "showAnim" );
duration = $.datepicker._get( inst, "duration" );
inst.dpDiv.css( "z-index", datepicker_getZindex( $( input ) ) + 1 );
$.datepicker._datepickerShowing = true;
if ( $.effects && $.effects.effect[ showAnim ] ) {
inst.dpDiv.show( showAnim, $.datepicker._get( inst, "showOptions" ), duration );
} else {
inst.dpDiv[ showAnim || "show" ]( showAnim ? duration : null );
}
if ( $.datepicker._shouldFocusInput( inst ) ) {
inst.input.trigger( "focus" );
}
$.datepicker._curInst = inst;
}
},
/* Generate the date picker content. */
_updateDatepicker: function( inst ) {
this.maxRows = 4; //Reset the max number of rows being displayed (see #7043)
datepicker_instActive = inst; // for delegate hover events
inst.dpDiv.empty().append( this._generateHTML( inst ) );
this._attachHandlers( inst );
var origyearshtml,
numMonths = this._getNumberOfMonths( inst ),
cols = numMonths[ 1 ],
width = 17,
activeCell = inst.dpDiv.find( "." + this._dayOverClass + " a" );
if ( activeCell.length > 0 ) {
datepicker_handleMouseover.apply( activeCell.get( 0 ) );
}
inst.dpDiv.removeClass( "ui-datepicker-multi-2 ui-datepicker-multi-3 ui-datepicker-multi-4" ).width( "" );
if ( cols > 1 ) {
inst.dpDiv.addClass( "ui-datepicker-multi-" + cols ).css( "width", ( width * cols ) + "em" );
}
inst.dpDiv[ ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ? "add" : "remove" ) +
"Class" ]( "ui-datepicker-multi" );
inst.dpDiv[ ( this._get( inst, "isRTL" ) ? "add" : "remove" ) +
"Class" ]( "ui-datepicker-rtl" );
if ( inst === $.datepicker._curInst && $.datepicker._datepickerShowing && $.datepicker._shouldFocusInput( inst ) ) {
inst.input.trigger( "focus" );
}
// Deffered render of the years select (to avoid flashes on Firefox)
if ( inst.yearshtml ) {
origyearshtml = inst.yearshtml;
setTimeout( function() {
//assure that inst.yearshtml didn't change.
if ( origyearshtml === inst.yearshtml && inst.yearshtml ) {
inst.dpDiv.find( "select.ui-datepicker-year:first" ).replaceWith( inst.yearshtml );
}
origyearshtml = inst.yearshtml = null;
}, 0 );
}
},
// #6694 - don't focus the input if it's already focused
// this breaks the change event in IE
// Support: IE and jQuery <1.9
_shouldFocusInput: function( inst ) {
return inst.input && inst.input.is( ":visible" ) && !inst.input.is( ":disabled" ) && !inst.input.is( ":focus" );
},
/* Check positioning to remain on screen. */
_checkOffset: function( inst, offset, isFixed ) {
var dpWidth = inst.dpDiv.outerWidth(),
dpHeight = inst.dpDiv.outerHeight(),
inputWidth = inst.input ? inst.input.outerWidth() : 0,
inputHeight = inst.input ? inst.input.outerHeight() : 0,
viewWidth = document.documentElement.clientWidth + ( isFixed ? 0 : $( document ).scrollLeft() ),
viewHeight = document.documentElement.clientHeight + ( isFixed ? 0 : $( document ).scrollTop() );
offset.left -= ( this._get( inst, "isRTL" ) ? ( dpWidth - inputWidth ) : 0 );
offset.left -= ( isFixed && offset.left === inst.input.offset().left ) ? $( document ).scrollLeft() : 0;
offset.top -= ( isFixed && offset.top === ( inst.input.offset().top + inputHeight ) ) ? $( document ).scrollTop() : 0;
// Now check if datepicker is showing outside window viewport - move to a better place if so.
offset.left -= Math.min( offset.left, ( offset.left + dpWidth > viewWidth && viewWidth > dpWidth ) ?
Math.abs( offset.left + dpWidth - viewWidth ) : 0 );
offset.top -= Math.min( offset.top, ( offset.top + dpHeight > viewHeight && viewHeight > dpHeight ) ?
Math.abs( dpHeight + inputHeight ) : 0 );
return offset;
},
/* Find an object's position on the screen. */
_findPos: function( obj ) {
var position,
inst = this._getInst( obj ),
isRTL = this._get( inst, "isRTL" );
while ( obj && ( obj.type === "hidden" || obj.nodeType !== 1 || $.expr.filters.hidden( obj ) ) ) {
obj = obj[ isRTL ? "previousSibling" : "nextSibling" ];
}
position = $( obj ).offset();
return [ position.left, position.top ];
},
/* Hide the date picker from view.
* @param input element - the input field attached to the date picker
*/
_hideDatepicker: function( input ) {
var showAnim, duration, postProcess, onClose,
inst = this._curInst;
if ( !inst || ( input && inst !== $.data( input, "datepicker" ) ) ) {
return;
}
if ( this._datepickerShowing ) {
showAnim = this._get( inst, "showAnim" );
duration = this._get( inst, "duration" );
postProcess = function() {
$.datepicker._tidyDialog( inst );
};
// DEPRECATED: after BC for 1.8.x $.effects[ showAnim ] is not needed
if ( $.effects && ( $.effects.effect[ showAnim ] || $.effects[ showAnim ] ) ) {
inst.dpDiv.hide( showAnim, $.datepicker._get( inst, "showOptions" ), duration, postProcess );
} else {
inst.dpDiv[ ( showAnim === "slideDown" ? "slideUp" :
( showAnim === "fadeIn" ? "fadeOut" : "hide" ) ) ]( ( showAnim ? duration : null ), postProcess );
}
if ( !showAnim ) {
postProcess();
}
this._datepickerShowing = false;
onClose = this._get( inst, "onClose" );
if ( onClose ) {
onClose.apply( ( inst.input ? inst.input[ 0 ] : null ), [ ( inst.input ? inst.input.val() : "" ), inst ] );
}
this._lastInput = null;
if ( this._inDialog ) {
this._dialogInput.css( { position: "absolute", left: "0", top: "-100px" } );
if ( $.blockUI ) {
$.unblockUI();
$( "body" ).append( this.dpDiv );
}
}
this._inDialog = false;
}
},
/* Tidy up after a dialog display. */
_tidyDialog: function( inst ) {
inst.dpDiv.removeClass( this._dialogClass ).off( ".ui-datepicker-calendar" );
},
/* Close date picker if clicked elsewhere. */
_checkExternalClick: function( event ) {
if ( !$.datepicker._curInst ) {
return;
}
var $target = $( event.target ),
inst = $.datepicker._getInst( $target[ 0 ] );
if ( ( ( $target[ 0 ].id !== $.datepicker._mainDivId &&
$target.parents( "#" + $.datepicker._mainDivId ).length === 0 &&
!$target.hasClass( $.datepicker.markerClassName ) &&
!$target.closest( "." + $.datepicker._triggerClass ).length &&
$.datepicker._datepickerShowing && !( $.datepicker._inDialog && $.blockUI ) ) ) ||
( $target.hasClass( $.datepicker.markerClassName ) && $.datepicker._curInst !== inst ) ) {
$.datepicker._hideDatepicker();
}
},
/* Adjust one of the date sub-fields. */
_adjustDate: function( id, offset, period ) {
var target = $( id ),
inst = this._getInst( target[ 0 ] );
if ( this._isDisabledDatepicker( target[ 0 ] ) ) {
return;
}
this._adjustInstDate( inst, offset +
( period === "M" ? this._get( inst, "showCurrentAtPos" ) : 0 ), // undo positioning
period );
this._updateDatepicker( inst );
},
/* Action for current link. */
_gotoToday: function( id ) {
var date,
target = $( id ),
inst = this._getInst( target[ 0 ] );
if ( this._get( inst, "gotoCurrent" ) && inst.currentDay ) {
inst.selectedDay = inst.currentDay;
inst.drawMonth = inst.selectedMonth = inst.currentMonth;
inst.drawYear = inst.selectedYear = inst.currentYear;
} else {
date = new Date();
inst.selectedDay = date.getDate();
inst.drawMonth = inst.selectedMonth = date.getMonth();
inst.drawYear = inst.selectedYear = date.getFullYear();
}
this._notifyChange( inst );
this._adjustDate( target );
},
/* Action for selecting a new month/year. */
_selectMonthYear: function( id, select, period ) {
var target = $( id ),
inst = this._getInst( target[ 0 ] );
inst[ "selected" + ( period === "M" ? "Month" : "Year" ) ] =
inst[ "draw" + ( period === "M" ? "Month" : "Year" ) ] =
parseInt( select.options[ select.selectedIndex ].value, 10 );
this._notifyChange( inst );
this._adjustDate( target );
},
/* Action for selecting a day. */
_selectDay: function( id, month, year, td ) {
var inst,
target = $( id );
if ( $( td ).hasClass( this._unselectableClass ) || this._isDisabledDatepicker( target[ 0 ] ) ) {
return;
}
inst = this._getInst( target[ 0 ] );
inst.selectedDay = inst.currentDay = $( "a", td ).html();
inst.selectedMonth = inst.currentMonth = month;
inst.selectedYear = inst.currentYear = year;
this._selectDate( id, this._formatDate( inst,
inst.currentDay, inst.currentMonth, inst.currentYear ) );
},
/* Erase the input field and hide the date picker. */
_clearDate: function( id ) {
var target = $( id );
this._selectDate( target, "" );
},
/* Update the input field with the selected date. */
_selectDate: function( id, dateStr ) {
var onSelect,
target = $( id ),
inst = this._getInst( target[ 0 ] );
dateStr = ( dateStr != null ? dateStr : this._formatDate( inst ) );
if ( inst.input ) {
inst.input.val( dateStr );
}
this._updateAlternate( inst );
onSelect = this._get( inst, "onSelect" );
if ( onSelect ) {
onSelect.apply( ( inst.input ? inst.input[ 0 ] : null ), [ dateStr, inst ] ); // trigger custom callback
} else if ( inst.input ) {
inst.input.trigger( "change" ); // fire the change event
}
if ( inst.inline ) {
this._updateDatepicker( inst );
} else {
this._hideDatepicker();
this._lastInput = inst.input[ 0 ];
if ( typeof( inst.input[ 0 ] ) !== "object" ) {
inst.input.trigger( "focus" ); // restore focus
}
this._lastInput = null;
}
},
/* Update any alternate field to synchronise with the main field. */
_updateAlternate: function( inst ) {
var altFormat, date, dateStr,
altField = this._get( inst, "altField" );
if ( altField ) { // update alternate field too
altFormat = this._get( inst, "altFormat" ) || this._get( inst, "dateFormat" );
date = this._getDate( inst );
dateStr = this.formatDate( altFormat, date, this._getFormatConfig( inst ) );
$( altField ).val( dateStr );
}
},
/* Set as beforeShowDay function to prevent selection of weekends.
* @param date Date - the date to customise
* @return [boolean, string] - is this date selectable?, what is its CSS class?
*/
noWeekends: function( date ) {
var day = date.getDay();
return [ ( day > 0 && day < 6 ), "" ];
},
/* Set as calculateWeek to determine the week of the year based on the ISO 8601 definition.
* @param date Date - the date to get the week for
* @return number - the number of the week within the year that contains this date
*/
iso8601Week: function( date ) {
var time,
checkDate = new Date( date.getTime() );
// Find Thursday of this week starting on Monday
checkDate.setDate( checkDate.getDate() + 4 - ( checkDate.getDay() || 7 ) );
time = checkDate.getTime();
checkDate.setMonth( 0 ); // Compare with Jan 1
checkDate.setDate( 1 );
return Math.floor( Math.round( ( time - checkDate ) / 86400000 ) / 7 ) + 1;
},
/* Parse a string value into a date object.
* See formatDate below for the possible formats.
*
* @param format string - the expected format of the date
* @param value string - the date in the above format
* @param settings Object - attributes include:
* shortYearCutoff number - the cutoff year for determining the century (optional)
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
* dayNames string[7] - names of the days from Sunday (optional)
* monthNamesShort string[12] - abbreviated names of the months (optional)
* monthNames string[12] - names of the months (optional)
* @return Date - the extracted date value or null if value is blank
*/
parseDate: function( format, value, settings ) {
if ( format == null || value == null ) {
throw "Invalid arguments";
}
value = ( typeof value === "object" ? value.toString() : value + "" );
if ( value === "" ) {
return null;
}
var iFormat, dim, extra,
iValue = 0,
shortYearCutoffTemp = ( settings ? settings.shortYearCutoff : null ) || this._defaults.shortYearCutoff,
shortYearCutoff = ( typeof shortYearCutoffTemp !== "string" ? shortYearCutoffTemp :
new Date().getFullYear() % 100 + parseInt( shortYearCutoffTemp, 10 ) ),
dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
year = -1,
month = -1,
day = -1,
doy = -1,
literal = false,
date,
// Check whether a format character is doubled
lookAhead = function( match ) {
var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
if ( matches ) {
iFormat++;
}
return matches;
},
// Extract a number from the string value
getNumber = function( match ) {
var isDoubled = lookAhead( match ),
size = ( match === "@" ? 14 : ( match === "!" ? 20 :
( match === "y" && isDoubled ? 4 : ( match === "o" ? 3 : 2 ) ) ) ),
minSize = ( match === "y" ? size : 1 ),
digits = new RegExp( "^\\d{" + minSize + "," + size + "}" ),
num = value.substring( iValue ).match( digits );
if ( !num ) {
throw "Missing number at position " + iValue;
}
iValue += num[ 0 ].length;
return parseInt( num[ 0 ], 10 );
},
// Extract a name from the string value and convert to an index
getName = function( match, shortNames, longNames ) {
var index = -1,
names = $.map( lookAhead( match ) ? longNames : shortNames, function( v, k ) {
return [ [ k, v ] ];
} ).sort( function( a, b ) {
return -( a[ 1 ].length - b[ 1 ].length );
} );
$.each( names, function( i, pair ) {
var name = pair[ 1 ];
if ( value.substr( iValue, name.length ).toLowerCase() === name.toLowerCase() ) {
index = pair[ 0 ];
iValue += name.length;
return false;
}
} );
if ( index !== -1 ) {
return index + 1;
} else {
throw "Unknown name at position " + iValue;
}
},
// Confirm that a literal character matches the string value
checkLiteral = function() {
if ( value.charAt( iValue ) !== format.charAt( iFormat ) ) {
throw "Unexpected literal at position " + iValue;
}
iValue++;
};
for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
if ( literal ) {
if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
literal = false;
} else {
checkLiteral();
}
} else {
switch ( format.charAt( iFormat ) ) {
case "d":
day = getNumber( "d" );
break;
case "D":
getName( "D", dayNamesShort, dayNames );
break;
case "o":
doy = getNumber( "o" );
break;
case "m":
month = getNumber( "m" );
break;
case "M":
month = getName( "M", monthNamesShort, monthNames );
break;
case "y":
year = getNumber( "y" );
break;
case "@":
date = new Date( getNumber( "@" ) );
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
break;
case "!":
date = new Date( ( getNumber( "!" ) - this._ticksTo1970 ) / 10000 );
year = date.getFullYear();
month = date.getMonth() + 1;
day = date.getDate();
break;
case "'":
if ( lookAhead( "'" ) ) {
checkLiteral();
} else {
literal = true;
}
break;
default:
checkLiteral();
}
}
}
if ( iValue < value.length ) {
extra = value.substr( iValue );
if ( !/^\s+/.test( extra ) ) {
throw "Extra/unparsed characters found in date: " + extra;
}
}
if ( year === -1 ) {
year = new Date().getFullYear();
} else if ( year < 100 ) {
year += new Date().getFullYear() - new Date().getFullYear() % 100 +
( year <= shortYearCutoff ? 0 : -100 );
}
if ( doy > -1 ) {
month = 1;
day = doy;
do {
dim = this._getDaysInMonth( year, month - 1 );
if ( day <= dim ) {
break;
}
month++;
day -= dim;
} while ( true );
}
date = this._daylightSavingAdjust( new Date( year, month - 1, day ) );
if ( date.getFullYear() !== year || date.getMonth() + 1 !== month || date.getDate() !== day ) {
throw "Invalid date"; // E.g. 31/02/00
}
return date;
},
/* Standard date formats. */
ATOM: "yy-mm-dd", // RFC 3339 (ISO 8601)
COOKIE: "D, dd M yy",
ISO_8601: "yy-mm-dd",
RFC_822: "D, d M y",
RFC_850: "DD, dd-M-y",
RFC_1036: "D, d M y",
RFC_1123: "D, d M yy",
RFC_2822: "D, d M yy",
RSS: "D, d M y", // RFC 822
TICKS: "!",
TIMESTAMP: "@",
W3C: "yy-mm-dd", // ISO 8601
_ticksTo1970: ( ( ( 1970 - 1 ) * 365 + Math.floor( 1970 / 4 ) - Math.floor( 1970 / 100 ) +
Math.floor( 1970 / 400 ) ) * 24 * 60 * 60 * 10000000 ),
/* Format a date object into a string value.
* The format can be combinations of the following:
* d - day of month (no leading zero)
* dd - day of month (two digit)
* o - day of year (no leading zeros)
* oo - day of year (three digit)
* D - day name short
* DD - day name long
* m - month of year (no leading zero)
* mm - month of year (two digit)
* M - month name short
* MM - month name long
* y - year (two digit)
* yy - year (four digit)
* @ - Unix timestamp (ms since 01/01/1970)
* ! - Windows ticks (100ns since 01/01/0001)
* "..." - literal text
* '' - single quote
*
* @param format string - the desired format of the date
* @param date Date - the date value to format
* @param settings Object - attributes include:
* dayNamesShort string[7] - abbreviated names of the days from Sunday (optional)
* dayNames string[7] - names of the days from Sunday (optional)
* monthNamesShort string[12] - abbreviated names of the months (optional)
* monthNames string[12] - names of the months (optional)
* @return string - the date in the above format
*/
formatDate: function( format, date, settings ) {
if ( !date ) {
return "";
}
var iFormat,
dayNamesShort = ( settings ? settings.dayNamesShort : null ) || this._defaults.dayNamesShort,
dayNames = ( settings ? settings.dayNames : null ) || this._defaults.dayNames,
monthNamesShort = ( settings ? settings.monthNamesShort : null ) || this._defaults.monthNamesShort,
monthNames = ( settings ? settings.monthNames : null ) || this._defaults.monthNames,
// Check whether a format character is doubled
lookAhead = function( match ) {
var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
if ( matches ) {
iFormat++;
}
return matches;
},
// Format a number, with leading zero if necessary
formatNumber = function( match, value, len ) {
var num = "" + value;
if ( lookAhead( match ) ) {
while ( num.length < len ) {
num = "0" + num;
}
}
return num;
},
// Format a name, short or long as requested
formatName = function( match, value, shortNames, longNames ) {
return ( lookAhead( match ) ? longNames[ value ] : shortNames[ value ] );
},
output = "",
literal = false;
if ( date ) {
for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
if ( literal ) {
if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
literal = false;
} else {
output += format.charAt( iFormat );
}
} else {
switch ( format.charAt( iFormat ) ) {
case "d":
output += formatNumber( "d", date.getDate(), 2 );
break;
case "D":
output += formatName( "D", date.getDay(), dayNamesShort, dayNames );
break;
case "o":
output += formatNumber( "o",
Math.round( ( new Date( date.getFullYear(), date.getMonth(), date.getDate() ).getTime() - new Date( date.getFullYear(), 0, 0 ).getTime() ) / 86400000 ), 3 );
break;
case "m":
output += formatNumber( "m", date.getMonth() + 1, 2 );
break;
case "M":
output += formatName( "M", date.getMonth(), monthNamesShort, monthNames );
break;
case "y":
output += ( lookAhead( "y" ) ? date.getFullYear() :
( date.getFullYear() % 100 < 10 ? "0" : "" ) + date.getFullYear() % 100 );
break;
case "@":
output += date.getTime();
break;
case "!":
output += date.getTime() * 10000 + this._ticksTo1970;
break;
case "'":
if ( lookAhead( "'" ) ) {
output += "'";
} else {
literal = true;
}
break;
default:
output += format.charAt( iFormat );
}
}
}
}
return output;
},
/* Extract all possible characters from the date format. */
_possibleChars: function( format ) {
var iFormat,
chars = "",
literal = false,
// Check whether a format character is doubled
lookAhead = function( match ) {
var matches = ( iFormat + 1 < format.length && format.charAt( iFormat + 1 ) === match );
if ( matches ) {
iFormat++;
}
return matches;
};
for ( iFormat = 0; iFormat < format.length; iFormat++ ) {
if ( literal ) {
if ( format.charAt( iFormat ) === "'" && !lookAhead( "'" ) ) {
literal = false;
} else {
chars += format.charAt( iFormat );
}
} else {
switch ( format.charAt( iFormat ) ) {
case "d": case "m": case "y": case "@":
chars += "0123456789";
break;
case "D": case "M":
return null; // Accept anything
case "'":
if ( lookAhead( "'" ) ) {
chars += "'";
} else {
literal = true;
}
break;
default:
chars += format.charAt( iFormat );
}
}
}
return chars;
},
/* Get a setting value, defaulting if necessary. */
_get: function( inst, name ) {
return inst.settings[ name ] !== undefined ?
inst.settings[ name ] : this._defaults[ name ];
},
/* Parse existing date and initialise date picker. */
_setDateFromField: function( inst, noDefault ) {
if ( inst.input.val() === inst.lastVal ) {
return;
}
var dateFormat = this._get( inst, "dateFormat" ),
dates = inst.lastVal = inst.input ? inst.input.val() : null,
defaultDate = this._getDefaultDate( inst ),
date = defaultDate,
settings = this._getFormatConfig( inst );
try {
date = this.parseDate( dateFormat, dates, settings ) || defaultDate;
} catch ( event ) {
dates = ( noDefault ? "" : dates );
}
inst.selectedDay = date.getDate();
inst.drawMonth = inst.selectedMonth = date.getMonth();
inst.drawYear = inst.selectedYear = date.getFullYear();
inst.currentDay = ( dates ? date.getDate() : 0 );
inst.currentMonth = ( dates ? date.getMonth() : 0 );
inst.currentYear = ( dates ? date.getFullYear() : 0 );
this._adjustInstDate( inst );
},
/* Retrieve the default date shown on opening. */
_getDefaultDate: function( inst ) {
return this._restrictMinMax( inst,
this._determineDate( inst, this._get( inst, "defaultDate" ), new Date() ) );
},
/* A date may be specified as an exact value or a relative one. */
_determineDate: function( inst, date, defaultDate ) {
var offsetNumeric = function( offset ) {
var date = new Date();
date.setDate( date.getDate() + offset );
return date;
},
offsetString = function( offset ) {
try {
return $.datepicker.parseDate( $.datepicker._get( inst, "dateFormat" ),
offset, $.datepicker._getFormatConfig( inst ) );
}
catch ( e ) {
// Ignore
}
var date = ( offset.toLowerCase().match( /^c/ ) ?
$.datepicker._getDate( inst ) : null ) || new Date(),
year = date.getFullYear(),
month = date.getMonth(),
day = date.getDate(),
pattern = /([+\-]?[0-9]+)\s*(d|D|w|W|m|M|y|Y)?/g,
matches = pattern.exec( offset );
while ( matches ) {
switch ( matches[ 2 ] || "d" ) {
case "d" : case "D" :
day += parseInt( matches[ 1 ], 10 ); break;
case "w" : case "W" :
day += parseInt( matches[ 1 ], 10 ) * 7; break;
case "m" : case "M" :
month += parseInt( matches[ 1 ], 10 );
day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
break;
case "y": case "Y" :
year += parseInt( matches[ 1 ], 10 );
day = Math.min( day, $.datepicker._getDaysInMonth( year, month ) );
break;
}
matches = pattern.exec( offset );
}
return new Date( year, month, day );
},
newDate = ( date == null || date === "" ? defaultDate : ( typeof date === "string" ? offsetString( date ) :
( typeof date === "number" ? ( isNaN( date ) ? defaultDate : offsetNumeric( date ) ) : new Date( date.getTime() ) ) ) );
newDate = ( newDate && newDate.toString() === "Invalid Date" ? defaultDate : newDate );
if ( newDate ) {
newDate.setHours( 0 );
newDate.setMinutes( 0 );
newDate.setSeconds( 0 );
newDate.setMilliseconds( 0 );
}
return this._daylightSavingAdjust( newDate );
},
/* Handle switch to/from daylight saving.
* Hours may be non-zero on daylight saving cut-over:
* > 12 when midnight changeover, but then cannot generate
* midnight datetime, so jump to 1AM, otherwise reset.
* @param date (Date) the date to check
* @return (Date) the corrected date
*/
_daylightSavingAdjust: function( date ) {
if ( !date ) {
return null;
}
date.setHours( date.getHours() > 12 ? date.getHours() + 2 : 0 );
return date;
},
/* Set the date(s) directly. */
_setDate: function( inst, date, noChange ) {
var clear = !date,
origMonth = inst.selectedMonth,
origYear = inst.selectedYear,
newDate = this._restrictMinMax( inst, this._determineDate( inst, date, new Date() ) );
inst.selectedDay = inst.currentDay = newDate.getDate();
inst.drawMonth = inst.selectedMonth = inst.currentMonth = newDate.getMonth();
inst.drawYear = inst.selectedYear = inst.currentYear = newDate.getFullYear();
if ( ( origMonth !== inst.selectedMonth || origYear !== inst.selectedYear ) && !noChange ) {
this._notifyChange( inst );
}
this._adjustInstDate( inst );
if ( inst.input ) {
inst.input.val( clear ? "" : this._formatDate( inst ) );
}
},
/* Retrieve the date(s) directly. */
_getDate: function( inst ) {
var startDate = ( !inst.currentYear || ( inst.input && inst.input.val() === "" ) ? null :
this._daylightSavingAdjust( new Date(
inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
return startDate;
},
/* Attach the onxxx handlers. These are declared statically so
* they work with static code transformers like Caja.
*/
_attachHandlers: function( inst ) {
var stepMonths = this._get( inst, "stepMonths" ),
id = "#" + inst.id.replace( /\\\\/g, "\\" );
inst.dpDiv.find( "[data-handler]" ).map( function() {
var handler = {
prev: function() {
$.datepicker._adjustDate( id, -stepMonths, "M" );
},
next: function() {
$.datepicker._adjustDate( id, +stepMonths, "M" );
},
hide: function() {
$.datepicker._hideDatepicker();
},
today: function() {
$.datepicker._gotoToday( id );
},
selectDay: function() {
$.datepicker._selectDay( id, +this.getAttribute( "data-month" ), +this.getAttribute( "data-year" ), this );
return false;
},
selectMonth: function() {
$.datepicker._selectMonthYear( id, this, "M" );
return false;
},
selectYear: function() {
$.datepicker._selectMonthYear( id, this, "Y" );
return false;
}
};
$( this ).on( this.getAttribute( "data-event" ), handler[ this.getAttribute( "data-handler" ) ] );
} );
},
/* Generate the HTML for the current state of the date picker. */
_generateHTML: function( inst ) {
var maxDraw, prevText, prev, nextText, next, currentText, gotoDate,
controls, buttonPanel, firstDay, showWeek, dayNames, dayNamesMin,
monthNames, monthNamesShort, beforeShowDay, showOtherMonths,
selectOtherMonths, defaultDate, html, dow, row, group, col, selectedDate,
cornerClass, calender, thead, day, daysInMonth, leadDays, curRows, numRows,
printDate, dRow, tbody, daySettings, otherMonth, unselectable,
tempDate = new Date(),
today = this._daylightSavingAdjust(
new Date( tempDate.getFullYear(), tempDate.getMonth(), tempDate.getDate() ) ), // clear time
isRTL = this._get( inst, "isRTL" ),
showButtonPanel = this._get( inst, "showButtonPanel" ),
hideIfNoPrevNext = this._get( inst, "hideIfNoPrevNext" ),
navigationAsDateFormat = this._get( inst, "navigationAsDateFormat" ),
numMonths = this._getNumberOfMonths( inst ),
showCurrentAtPos = this._get( inst, "showCurrentAtPos" ),
stepMonths = this._get( inst, "stepMonths" ),
isMultiMonth = ( numMonths[ 0 ] !== 1 || numMonths[ 1 ] !== 1 ),
currentDate = this._daylightSavingAdjust( ( !inst.currentDay ? new Date( 9999, 9, 9 ) :
new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) ),
minDate = this._getMinMaxDate( inst, "min" ),
maxDate = this._getMinMaxDate( inst, "max" ),
drawMonth = inst.drawMonth - showCurrentAtPos,
drawYear = inst.drawYear;
if ( drawMonth < 0 ) {
drawMonth += 12;
drawYear--;
}
if ( maxDate ) {
maxDraw = this._daylightSavingAdjust( new Date( maxDate.getFullYear(),
maxDate.getMonth() - ( numMonths[ 0 ] * numMonths[ 1 ] ) + 1, maxDate.getDate() ) );
maxDraw = ( minDate && maxDraw < minDate ? minDate : maxDraw );
while ( this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 ) ) > maxDraw ) {
drawMonth--;
if ( drawMonth < 0 ) {
drawMonth = 11;
drawYear--;
}
}
}
inst.drawMonth = drawMonth;
inst.drawYear = drawYear;
prevText = this._get( inst, "prevText" );
prevText = ( !navigationAsDateFormat ? prevText : this.formatDate( prevText,
this._daylightSavingAdjust( new Date( drawYear, drawMonth - stepMonths, 1 ) ),
this._getFormatConfig( inst ) ) );
prev = ( this._canAdjustMonth( inst, -1, drawYear, drawMonth ) ?
"<a class='ui-datepicker-prev ui-corner-all' data-handler='prev' data-event='click'" +
" title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" :
( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-prev ui-corner-all ui-state-disabled' title='" + prevText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "e" : "w" ) + "'>" + prevText + "</span></a>" ) );
nextText = this._get( inst, "nextText" );
nextText = ( !navigationAsDateFormat ? nextText : this.formatDate( nextText,
this._daylightSavingAdjust( new Date( drawYear, drawMonth + stepMonths, 1 ) ),
this._getFormatConfig( inst ) ) );
next = ( this._canAdjustMonth( inst, +1, drawYear, drawMonth ) ?
"<a class='ui-datepicker-next ui-corner-all' data-handler='next' data-event='click'" +
" title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" :
( hideIfNoPrevNext ? "" : "<a class='ui-datepicker-next ui-corner-all ui-state-disabled' title='" + nextText + "'><span class='ui-icon ui-icon-circle-triangle-" + ( isRTL ? "w" : "e" ) + "'>" + nextText + "</span></a>" ) );
currentText = this._get( inst, "currentText" );
gotoDate = ( this._get( inst, "gotoCurrent" ) && inst.currentDay ? currentDate : today );
currentText = ( !navigationAsDateFormat ? currentText :
this.formatDate( currentText, gotoDate, this._getFormatConfig( inst ) ) );
controls = ( !inst.inline ? "<button type='button' class='ui-datepicker-close ui-state-default ui-priority-primary ui-corner-all' data-handler='hide' data-event='click'>" +
this._get( inst, "closeText" ) + "</button>" : "" );
buttonPanel = ( showButtonPanel ) ? "<div class='ui-datepicker-buttonpane ui-widget-content'>" + ( isRTL ? controls : "" ) +
( this._isInRange( inst, gotoDate ) ? "<button type='button' class='ui-datepicker-current ui-state-default ui-priority-secondary ui-corner-all' data-handler='today' data-event='click'" +
">" + currentText + "</button>" : "" ) + ( isRTL ? "" : controls ) + "</div>" : "";
firstDay = parseInt( this._get( inst, "firstDay" ), 10 );
firstDay = ( isNaN( firstDay ) ? 0 : firstDay );
showWeek = this._get( inst, "showWeek" );
dayNames = this._get( inst, "dayNames" );
dayNamesMin = this._get( inst, "dayNamesMin" );
monthNames = this._get( inst, "monthNames" );
monthNamesShort = this._get( inst, "monthNamesShort" );
beforeShowDay = this._get( inst, "beforeShowDay" );
showOtherMonths = this._get( inst, "showOtherMonths" );
selectOtherMonths = this._get( inst, "selectOtherMonths" );
defaultDate = this._getDefaultDate( inst );
html = "";
for ( row = 0; row < numMonths[ 0 ]; row++ ) {
group = "";
this.maxRows = 4;
for ( col = 0; col < numMonths[ 1 ]; col++ ) {
selectedDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, inst.selectedDay ) );
cornerClass = " ui-corner-all";
calender = "";
if ( isMultiMonth ) {
calender += "<div class='ui-datepicker-group";
if ( numMonths[ 1 ] > 1 ) {
switch ( col ) {
case 0: calender += " ui-datepicker-group-first";
cornerClass = " ui-corner-" + ( isRTL ? "right" : "left" ); break;
case numMonths[ 1 ] - 1: calender += " ui-datepicker-group-last";
cornerClass = " ui-corner-" + ( isRTL ? "left" : "right" ); break;
default: calender += " ui-datepicker-group-middle"; cornerClass = ""; break;
}
}
calender += "'>";
}
calender += "<div class='ui-datepicker-header ui-widget-header ui-helper-clearfix" + cornerClass + "'>" +
( /all|left/.test( cornerClass ) && row === 0 ? ( isRTL ? next : prev ) : "" ) +
( /all|right/.test( cornerClass ) && row === 0 ? ( isRTL ? prev : next ) : "" ) +
this._generateMonthYearHeader( inst, drawMonth, drawYear, minDate, maxDate,
row > 0 || col > 0, monthNames, monthNamesShort ) + // draw month headers
"</div><table class='ui-datepicker-calendar'><thead>" +
"<tr>";
thead = ( showWeek ? "<th class='ui-datepicker-week-col'>" + this._get( inst, "weekHeader" ) + "</th>" : "" );
for ( dow = 0; dow < 7; dow++ ) { // days of the week
day = ( dow + firstDay ) % 7;
thead += "<th scope='col'" + ( ( dow + firstDay + 6 ) % 7 >= 5 ? " class='ui-datepicker-week-end'" : "" ) + ">" +
"<span title='" + dayNames[ day ] + "'>" + dayNamesMin[ day ] + "</span></th>";
}
calender += thead + "</tr></thead><tbody>";
daysInMonth = this._getDaysInMonth( drawYear, drawMonth );
if ( drawYear === inst.selectedYear && drawMonth === inst.selectedMonth ) {
inst.selectedDay = Math.min( inst.selectedDay, daysInMonth );
}
leadDays = ( this._getFirstDayOfMonth( drawYear, drawMonth ) - firstDay + 7 ) % 7;
curRows = Math.ceil( ( leadDays + daysInMonth ) / 7 ); // calculate the number of rows to generate
numRows = ( isMultiMonth ? this.maxRows > curRows ? this.maxRows : curRows : curRows ); //If multiple months, use the higher number of rows (see #7043)
this.maxRows = numRows;
printDate = this._daylightSavingAdjust( new Date( drawYear, drawMonth, 1 - leadDays ) );
for ( dRow = 0; dRow < numRows; dRow++ ) { // create date picker rows
calender += "<tr>";
tbody = ( !showWeek ? "" : "<td class='ui-datepicker-week-col'>" +
this._get( inst, "calculateWeek" )( printDate ) + "</td>" );
for ( dow = 0; dow < 7; dow++ ) { // create date picker days
daySettings = ( beforeShowDay ?
beforeShowDay.apply( ( inst.input ? inst.input[ 0 ] : null ), [ printDate ] ) : [ true, "" ] );
otherMonth = ( printDate.getMonth() !== drawMonth );
unselectable = ( otherMonth && !selectOtherMonths ) || !daySettings[ 0 ] ||
( minDate && printDate < minDate ) || ( maxDate && printDate > maxDate );
tbody += "<td class='" +
( ( dow + firstDay + 6 ) % 7 >= 5 ? " ui-datepicker-week-end" : "" ) + // highlight weekends
( otherMonth ? " ui-datepicker-other-month" : "" ) + // highlight days from other months
( ( printDate.getTime() === selectedDate.getTime() && drawMonth === inst.selectedMonth && inst._keyEvent ) || // user pressed key
( defaultDate.getTime() === printDate.getTime() && defaultDate.getTime() === selectedDate.getTime() ) ?
// or defaultDate is current printedDate and defaultDate is selectedDate
" " + this._dayOverClass : "" ) + // highlight selected day
( unselectable ? " " + this._unselectableClass + " ui-state-disabled" : "" ) + // highlight unselectable days
( otherMonth && !showOtherMonths ? "" : " " + daySettings[ 1 ] + // highlight custom dates
( printDate.getTime() === currentDate.getTime() ? " " + this._currentClass : "" ) + // highlight selected day
( printDate.getTime() === today.getTime() ? " ui-datepicker-today" : "" ) ) + "'" + // highlight today (if different)
( ( !otherMonth || showOtherMonths ) && daySettings[ 2 ] ? " title='" + daySettings[ 2 ].replace( /'/g, "'" ) + "'" : "" ) + // cell title
( unselectable ? "" : " data-handler='selectDay' data-event='click' data-month='" + printDate.getMonth() + "' data-year='" + printDate.getFullYear() + "'" ) + ">" + // actions
( otherMonth && !showOtherMonths ? " " : // display for other months
( unselectable ? "<span class='ui-state-default'>" + printDate.getDate() + "</span>" : "<a class='ui-state-default" +
( printDate.getTime() === today.getTime() ? " ui-state-highlight" : "" ) +
( printDate.getTime() === currentDate.getTime() ? " ui-state-active" : "" ) + // highlight selected day
( otherMonth ? " ui-priority-secondary" : "" ) + // distinguish dates from other months
"' href='#'>" + printDate.getDate() + "</a>" ) ) + "</td>"; // display selectable date
printDate.setDate( printDate.getDate() + 1 );
printDate = this._daylightSavingAdjust( printDate );
}
calender += tbody + "</tr>";
}
drawMonth++;
if ( drawMonth > 11 ) {
drawMonth = 0;
drawYear++;
}
calender += "</tbody></table>" + ( isMultiMonth ? "</div>" +
( ( numMonths[ 0 ] > 0 && col === numMonths[ 1 ] - 1 ) ? "<div class='ui-datepicker-row-break'></div>" : "" ) : "" );
group += calender;
}
html += group;
}
html += buttonPanel;
inst._keyEvent = false;
return html;
},
/* Generate the month and year header. */
_generateMonthYearHeader: function( inst, drawMonth, drawYear, minDate, maxDate,
secondary, monthNames, monthNamesShort ) {
var inMinYear, inMaxYear, month, years, thisYear, determineYear, year, endYear,
changeMonth = this._get( inst, "changeMonth" ),
changeYear = this._get( inst, "changeYear" ),
showMonthAfterYear = this._get( inst, "showMonthAfterYear" ),
html = "<div class='ui-datepicker-title'>",
monthHtml = "";
// Month selection
if ( secondary || !changeMonth ) {
monthHtml += "<span class='ui-datepicker-month'>" + monthNames[ drawMonth ] + "</span>";
} else {
inMinYear = ( minDate && minDate.getFullYear() === drawYear );
inMaxYear = ( maxDate && maxDate.getFullYear() === drawYear );
monthHtml += "<select class='ui-datepicker-month' data-handler='selectMonth' data-event='change'>";
for ( month = 0; month < 12; month++ ) {
if ( ( !inMinYear || month >= minDate.getMonth() ) && ( !inMaxYear || month <= maxDate.getMonth() ) ) {
monthHtml += "<option value='" + month + "'" +
( month === drawMonth ? " selected='selected'" : "" ) +
">" + monthNamesShort[ month ] + "</option>";
}
}
monthHtml += "</select>";
}
if ( !showMonthAfterYear ) {
html += monthHtml + ( secondary || !( changeMonth && changeYear ) ? " " : "" );
}
// Year selection
if ( !inst.yearshtml ) {
inst.yearshtml = "";
if ( secondary || !changeYear ) {
html += "<span class='ui-datepicker-year'>" + drawYear + "</span>";
} else {
// determine range of years to display
years = this._get( inst, "yearRange" ).split( ":" );
thisYear = new Date().getFullYear();
determineYear = function( value ) {
var year = ( value.match( /c[+\-].*/ ) ? drawYear + parseInt( value.substring( 1 ), 10 ) :
( value.match( /[+\-].*/ ) ? thisYear + parseInt( value, 10 ) :
parseInt( value, 10 ) ) );
return ( isNaN( year ) ? thisYear : year );
};
year = determineYear( years[ 0 ] );
endYear = Math.max( year, determineYear( years[ 1 ] || "" ) );
year = ( minDate ? Math.max( year, minDate.getFullYear() ) : year );
endYear = ( maxDate ? Math.min( endYear, maxDate.getFullYear() ) : endYear );
inst.yearshtml += "<select class='ui-datepicker-year' data-handler='selectYear' data-event='change'>";
for ( ; year <= endYear; year++ ) {
inst.yearshtml += "<option value='" + year + "'" +
( year === drawYear ? " selected='selected'" : "" ) +
">" + year + "</option>";
}
inst.yearshtml += "</select>";
html += inst.yearshtml;
inst.yearshtml = null;
}
}
html += this._get( inst, "yearSuffix" );
if ( showMonthAfterYear ) {
html += ( secondary || !( changeMonth && changeYear ) ? " " : "" ) + monthHtml;
}
html += "</div>"; // Close datepicker_header
return html;
},
/* Adjust one of the date sub-fields. */
_adjustInstDate: function( inst, offset, period ) {
var year = inst.selectedYear + ( period === "Y" ? offset : 0 ),
month = inst.selectedMonth + ( period === "M" ? offset : 0 ),
day = Math.min( inst.selectedDay, this._getDaysInMonth( year, month ) ) + ( period === "D" ? offset : 0 ),
date = this._restrictMinMax( inst, this._daylightSavingAdjust( new Date( year, month, day ) ) );
inst.selectedDay = date.getDate();
inst.drawMonth = inst.selectedMonth = date.getMonth();
inst.drawYear = inst.selectedYear = date.getFullYear();
if ( period === "M" || period === "Y" ) {
this._notifyChange( inst );
}
},
/* Ensure a date is within any min/max bounds. */
_restrictMinMax: function( inst, date ) {
var minDate = this._getMinMaxDate( inst, "min" ),
maxDate = this._getMinMaxDate( inst, "max" ),
newDate = ( minDate && date < minDate ? minDate : date );
return ( maxDate && newDate > maxDate ? maxDate : newDate );
},
/* Notify change of month/year. */
_notifyChange: function( inst ) {
var onChange = this._get( inst, "onChangeMonthYear" );
if ( onChange ) {
onChange.apply( ( inst.input ? inst.input[ 0 ] : null ),
[ inst.selectedYear, inst.selectedMonth + 1, inst ] );
}
},
/* Determine the number of months to show. */
_getNumberOfMonths: function( inst ) {
var numMonths = this._get( inst, "numberOfMonths" );
return ( numMonths == null ? [ 1, 1 ] : ( typeof numMonths === "number" ? [ 1, numMonths ] : numMonths ) );
},
/* Determine the current maximum date - ensure no time components are set. */
_getMinMaxDate: function( inst, minMax ) {
return this._determineDate( inst, this._get( inst, minMax + "Date" ), null );
},
/* Find the number of days in a given month. */
_getDaysInMonth: function( year, month ) {
return 32 - this._daylightSavingAdjust( new Date( year, month, 32 ) ).getDate();
},
/* Find the day of the week of the first of a month. */
_getFirstDayOfMonth: function( year, month ) {
return new Date( year, month, 1 ).getDay();
},
/* Determines if we should allow a "next/prev" month display change. */
_canAdjustMonth: function( inst, offset, curYear, curMonth ) {
var numMonths = this._getNumberOfMonths( inst ),
date = this._daylightSavingAdjust( new Date( curYear,
curMonth + ( offset < 0 ? offset : numMonths[ 0 ] * numMonths[ 1 ] ), 1 ) );
if ( offset < 0 ) {
date.setDate( this._getDaysInMonth( date.getFullYear(), date.getMonth() ) );
}
return this._isInRange( inst, date );
},
/* Is the given date in the accepted range? */
_isInRange: function( inst, date ) {
var yearSplit, currentYear,
minDate = this._getMinMaxDate( inst, "min" ),
maxDate = this._getMinMaxDate( inst, "max" ),
minYear = null,
maxYear = null,
years = this._get( inst, "yearRange" );
if ( years ) {
yearSplit = years.split( ":" );
currentYear = new Date().getFullYear();
minYear = parseInt( yearSplit[ 0 ], 10 );
maxYear = parseInt( yearSplit[ 1 ], 10 );
if ( yearSplit[ 0 ].match( /[+\-].*/ ) ) {
minYear += currentYear;
}
if ( yearSplit[ 1 ].match( /[+\-].*/ ) ) {
maxYear += currentYear;
}
}
return ( ( !minDate || date.getTime() >= minDate.getTime() ) &&
( !maxDate || date.getTime() <= maxDate.getTime() ) &&
( !minYear || date.getFullYear() >= minYear ) &&
( !maxYear || date.getFullYear() <= maxYear ) );
},
/* Provide the configuration settings for formatting/parsing. */
_getFormatConfig: function( inst ) {
var shortYearCutoff = this._get( inst, "shortYearCutoff" );
shortYearCutoff = ( typeof shortYearCutoff !== "string" ? shortYearCutoff :
new Date().getFullYear() % 100 + parseInt( shortYearCutoff, 10 ) );
return { shortYearCutoff: shortYearCutoff,
dayNamesShort: this._get( inst, "dayNamesShort" ), dayNames: this._get( inst, "dayNames" ),
monthNamesShort: this._get( inst, "monthNamesShort" ), monthNames: this._get( inst, "monthNames" ) };
},
/* Format the given date for display. */
_formatDate: function( inst, day, month, year ) {
if ( !day ) {
inst.currentDay = inst.selectedDay;
inst.currentMonth = inst.selectedMonth;
inst.currentYear = inst.selectedYear;
}
var date = ( day ? ( typeof day === "object" ? day :
this._daylightSavingAdjust( new Date( year, month, day ) ) ) :
this._daylightSavingAdjust( new Date( inst.currentYear, inst.currentMonth, inst.currentDay ) ) );
return this.formatDate( this._get( inst, "dateFormat" ), date, this._getFormatConfig( inst ) );
}
} );
/*
* Bind hover events for datepicker elements.
* Done via delegate so the binding only occurs once in the lifetime of the parent div.
* Global datepicker_instActive, set by _updateDatepicker allows the handlers to find their way back to the active picker.
*/
function datepicker_bindHover( dpDiv ) {
var selector = "button, .ui-datepicker-prev, .ui-datepicker-next, .ui-datepicker-calendar td a";
return dpDiv.on( "mouseout", selector, function() {
$( this ).removeClass( "ui-state-hover" );
if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
$( this ).removeClass( "ui-datepicker-prev-hover" );
}
if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
$( this ).removeClass( "ui-datepicker-next-hover" );
}
} )
.on( "mouseover", selector, datepicker_handleMouseover );
}
function datepicker_handleMouseover() {
if ( !$.datepicker._isDisabledDatepicker( datepicker_instActive.inline ? datepicker_instActive.dpDiv.parent()[ 0 ] : datepicker_instActive.input[ 0 ] ) ) {
$( this ).parents( ".ui-datepicker-calendar" ).find( "a" ).removeClass( "ui-state-hover" );
$( this ).addClass( "ui-state-hover" );
if ( this.className.indexOf( "ui-datepicker-prev" ) !== -1 ) {
$( this ).addClass( "ui-datepicker-prev-hover" );
}
if ( this.className.indexOf( "ui-datepicker-next" ) !== -1 ) {
$( this ).addClass( "ui-datepicker-next-hover" );
}
}
}
/* jQuery extend now ignores nulls! */
function datepicker_extendRemove( target, props ) {
$.extend( target, props );
for ( var name in props ) {
if ( props[ name ] == null ) {
target[ name ] = props[ name ];
}
}
return target;
}
/* Invoke the datepicker functionality.
@param options string - a command, optionally followed by additional parameters or
Object - settings for attaching new datepicker functionality
@return jQuery object */
$.fn.datepicker = function( options ) {
/* Verify an empty collection wasn't passed - Fixes #6976 */
if ( !this.length ) {
return this;
}
/* Initialise the date picker. */
if ( !$.datepicker.initialized ) {
$( document ).on( "mousedown", $.datepicker._checkExternalClick );
$.datepicker.initialized = true;
}
/* Append datepicker main container to body if not exist. */
if ( $( "#" + $.datepicker._mainDivId ).length === 0 ) {
$( "body" ).append( $.datepicker.dpDiv );
}
var otherArgs = Array.prototype.slice.call( arguments, 1 );
if ( typeof options === "string" && ( options === "isDisabled" || options === "getDate" || options === "widget" ) ) {
return $.datepicker[ "_" + options + "Datepicker" ].
apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
}
if ( options === "option" && arguments.length === 2 && typeof arguments[ 1 ] === "string" ) {
return $.datepicker[ "_" + options + "Datepicker" ].
apply( $.datepicker, [ this[ 0 ] ].concat( otherArgs ) );
}
return this.each( function() {
typeof options === "string" ?
$.datepicker[ "_" + options + "Datepicker" ].
apply( $.datepicker, [ this ].concat( otherArgs ) ) :
$.datepicker._attachDatepicker( this, options );
} );
};
$.datepicker = new Datepicker(); // singleton instance
$.datepicker.initialized = false;
$.datepicker.uuid = new Date().getTime();
$.datepicker.version = "1.12.1";
var widgetsDatepicker = $.datepicker;
// This file is deprecated
var ie = $.ui.ie = !!/msie [\w.]+/.exec( navigator.userAgent.toLowerCase() );
/*!
* jQuery UI Mouse 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Mouse
//>>group: Widgets
//>>description: Abstracts mouse-based interactions to assist in creating certain widgets.
//>>docs: http://api.jqueryui.com/mouse/
var mouseHandled = false;
$( document ).on( "mouseup", function() {
mouseHandled = false;
} );
var widgetsMouse = $.widget( "ui.mouse", {
version: "1.12.1",
options: {
cancel: "input, textarea, button, select, option",
distance: 1,
delay: 0
},
_mouseInit: function() {
var that = this;
this.element
.on( "mousedown." + this.widgetName, function( event ) {
return that._mouseDown( event );
} )
.on( "click." + this.widgetName, function( event ) {
if ( true === $.data( event.target, that.widgetName + ".preventClickEvent" ) ) {
$.removeData( event.target, that.widgetName + ".preventClickEvent" );
event.stopImmediatePropagation();
return false;
}
} );
this.started = false;
},
// TODO: make sure destroying one instance of mouse doesn't mess with
// other instances of mouse
_mouseDestroy: function() {
this.element.off( "." + this.widgetName );
if ( this._mouseMoveDelegate ) {
this.document
.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
}
},
_mouseDown: function( event ) {
// don't let more than one widget handle mouseStart
if ( mouseHandled ) {
return;
}
this._mouseMoved = false;
// We may have missed mouseup (out of window)
( this._mouseStarted && this._mouseUp( event ) );
this._mouseDownEvent = event;
var that = this,
btnIsLeft = ( event.which === 1 ),
// event.target.nodeName works around a bug in IE 8 with
// disabled inputs (#7620)
elIsCancel = ( typeof this.options.cancel === "string" && event.target.nodeName ?
$( event.target ).closest( this.options.cancel ).length : false );
if ( !btnIsLeft || elIsCancel || !this._mouseCapture( event ) ) {
return true;
}
this.mouseDelayMet = !this.options.delay;
if ( !this.mouseDelayMet ) {
this._mouseDelayTimer = setTimeout( function() {
that.mouseDelayMet = true;
}, this.options.delay );
}
if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
this._mouseStarted = ( this._mouseStart( event ) !== false );
if ( !this._mouseStarted ) {
event.preventDefault();
return true;
}
}
// Click event may never have fired (Gecko & Opera)
if ( true === $.data( event.target, this.widgetName + ".preventClickEvent" ) ) {
$.removeData( event.target, this.widgetName + ".preventClickEvent" );
}
// These delegates are required to keep context
this._mouseMoveDelegate = function( event ) {
return that._mouseMove( event );
};
this._mouseUpDelegate = function( event ) {
return that._mouseUp( event );
};
this.document
.on( "mousemove." + this.widgetName, this._mouseMoveDelegate )
.on( "mouseup." + this.widgetName, this._mouseUpDelegate );
event.preventDefault();
mouseHandled = true;
return true;
},
_mouseMove: function( event ) {
// Only check for mouseups outside the document if you've moved inside the document
// at least once. This prevents the firing of mouseup in the case of IE<9, which will
// fire a mousemove event if content is placed under the cursor. See #7778
// Support: IE <9
if ( this._mouseMoved ) {
// IE mouseup check - mouseup happened when mouse was out of window
if ( $.ui.ie && ( !document.documentMode || document.documentMode < 9 ) &&
!event.button ) {
return this._mouseUp( event );
// Iframe mouseup check - mouseup occurred in another document
} else if ( !event.which ) {
// Support: Safari <=8 - 9
// Safari sets which to 0 if you press any of the following keys
// during a drag (#14461)
if ( event.originalEvent.altKey || event.originalEvent.ctrlKey ||
event.originalEvent.metaKey || event.originalEvent.shiftKey ) {
this.ignoreMissingWhich = true;
} else if ( !this.ignoreMissingWhich ) {
return this._mouseUp( event );
}
}
}
if ( event.which || event.button ) {
this._mouseMoved = true;
}
if ( this._mouseStarted ) {
this._mouseDrag( event );
return event.preventDefault();
}
if ( this._mouseDistanceMet( event ) && this._mouseDelayMet( event ) ) {
this._mouseStarted =
( this._mouseStart( this._mouseDownEvent, event ) !== false );
( this._mouseStarted ? this._mouseDrag( event ) : this._mouseUp( event ) );
}
return !this._mouseStarted;
},
_mouseUp: function( event ) {
this.document
.off( "mousemove." + this.widgetName, this._mouseMoveDelegate )
.off( "mouseup." + this.widgetName, this._mouseUpDelegate );
if ( this._mouseStarted ) {
this._mouseStarted = false;
if ( event.target === this._mouseDownEvent.target ) {
$.data( event.target, this.widgetName + ".preventClickEvent", true );
}
this._mouseStop( event );
}
if ( this._mouseDelayTimer ) {
clearTimeout( this._mouseDelayTimer );
delete this._mouseDelayTimer;
}
this.ignoreMissingWhich = false;
mouseHandled = false;
event.preventDefault();
},
_mouseDistanceMet: function( event ) {
return ( Math.max(
Math.abs( this._mouseDownEvent.pageX - event.pageX ),
Math.abs( this._mouseDownEvent.pageY - event.pageY )
) >= this.options.distance
);
},
_mouseDelayMet: function( /* event */ ) {
return this.mouseDelayMet;
},
// These are placeholder methods, to be overriden by extending plugin
_mouseStart: function( /* event */ ) {},
_mouseDrag: function( /* event */ ) {},
_mouseStop: function( /* event */ ) {},
_mouseCapture: function( /* event */ ) { return true; }
} );
// $.ui.plugin is deprecated. Use $.widget() extensions instead.
var plugin = $.ui.plugin = {
add: function( module, option, set ) {
var i,
proto = $.ui[ module ].prototype;
for ( i in set ) {
proto.plugins[ i ] = proto.plugins[ i ] || [];
proto.plugins[ i ].push( [ option, set[ i ] ] );
}
},
call: function( instance, name, args, allowDisconnected ) {
var i,
set = instance.plugins[ name ];
if ( !set ) {
return;
}
if ( !allowDisconnected && ( !instance.element[ 0 ].parentNode ||
instance.element[ 0 ].parentNode.nodeType === 11 ) ) {
return;
}
for ( i = 0; i < set.length; i++ ) {
if ( instance.options[ set[ i ][ 0 ] ] ) {
set[ i ][ 1 ].apply( instance.element, args );
}
}
}
};
var safeBlur = $.ui.safeBlur = function( element ) {
// Support: IE9 - 10 only
// If the <body> is blurred, IE will switch windows, see #9420
if ( element && element.nodeName.toLowerCase() !== "body" ) {
$( element ).trigger( "blur" );
}
};
/*!
* jQuery UI Draggable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Draggable
//>>group: Interactions
//>>description: Enables dragging functionality for any element.
//>>docs: http://api.jqueryui.com/draggable/
//>>demos: http://jqueryui.com/draggable/
//>>css.structure: ../../themes/base/draggable.css
$.widget( "ui.draggable", $.ui.mouse, {
version: "1.12.1",
widgetEventPrefix: "drag",
options: {
addClasses: true,
appendTo: "parent",
axis: false,
connectToSortable: false,
containment: false,
cursor: "auto",
cursorAt: false,
grid: false,
handle: false,
helper: "original",
iframeFix: false,
opacity: false,
refreshPositions: false,
revert: false,
revertDuration: 500,
scope: "default",
scroll: true,
scrollSensitivity: 20,
scrollSpeed: 20,
snap: false,
snapMode: "both",
snapTolerance: 20,
stack: false,
zIndex: false,
// Callbacks
drag: null,
start: null,
stop: null
},
_create: function() {
if ( this.options.helper === "original" ) {
this._setPositionRelative();
}
if ( this.options.addClasses ) {
this._addClass( "ui-draggable" );
}
this._setHandleClassName();
this._mouseInit();
},
_setOption: function( key, value ) {
this._super( key, value );
if ( key === "handle" ) {
this._removeHandleClassName();
this._setHandleClassName();
}
},
_destroy: function() {
if ( ( this.helper || this.element ).is( ".ui-draggable-dragging" ) ) {
this.destroyOnClear = true;
return;
}
this._removeHandleClassName();
this._mouseDestroy();
},
_mouseCapture: function( event ) {
var o = this.options;
// Among others, prevent a drag on a resizable-handle
if ( this.helper || o.disabled ||
$( event.target ).closest( ".ui-resizable-handle" ).length > 0 ) {
return false;
}
//Quit if we're not on a valid handle
this.handle = this._getHandle( event );
if ( !this.handle ) {
return false;
}
this._blurActiveElement( event );
this._blockFrames( o.iframeFix === true ? "iframe" : o.iframeFix );
return true;
},
_blockFrames: function( selector ) {
this.iframeBlocks = this.document.find( selector ).map( function() {
var iframe = $( this );
return $( "<div>" )
.css( "position", "absolute" )
.appendTo( iframe.parent() )
.outerWidth( iframe.outerWidth() )
.outerHeight( iframe.outerHeight() )
.offset( iframe.offset() )[ 0 ];
} );
},
_unblockFrames: function() {
if ( this.iframeBlocks ) {
this.iframeBlocks.remove();
delete this.iframeBlocks;
}
},
_blurActiveElement: function( event ) {
var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
target = $( event.target );
// Don't blur if the event occurred on an element that is within
// the currently focused element
// See #10527, #12472
if ( target.closest( activeElement ).length ) {
return;
}
// Blur any element that currently has focus, see #4261
$.ui.safeBlur( activeElement );
},
_mouseStart: function( event ) {
var o = this.options;
//Create and append the visible helper
this.helper = this._createHelper( event );
this._addClass( this.helper, "ui-draggable-dragging" );
//Cache the helper size
this._cacheHelperProportions();
//If ddmanager is used for droppables, set the global draggable
if ( $.ui.ddmanager ) {
$.ui.ddmanager.current = this;
}
/*
* - Position generation -
* This block generates everything position related - it's the core of draggables.
*/
//Cache the margins of the original element
this._cacheMargins();
//Store the helper's css position
this.cssPosition = this.helper.css( "position" );
this.scrollParent = this.helper.scrollParent( true );
this.offsetParent = this.helper.offsetParent();
this.hasFixedAncestor = this.helper.parents().filter( function() {
return $( this ).css( "position" ) === "fixed";
} ).length > 0;
//The element's absolute position on the page minus margins
this.positionAbs = this.element.offset();
this._refreshOffsets( event );
//Generate the original position
this.originalPosition = this.position = this._generatePosition( event, false );
this.originalPageX = event.pageX;
this.originalPageY = event.pageY;
//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
//Set a containment if given in the options
this._setContainment();
//Trigger event + callbacks
if ( this._trigger( "start", event ) === false ) {
this._clear();
return false;
}
//Recache the helper size
this._cacheHelperProportions();
//Prepare the droppable offsets
if ( $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( this, event );
}
// Execute the drag once - this causes the helper not to be visible before getting its
// correct position
this._mouseDrag( event, true );
// If the ddmanager is used for droppables, inform the manager that dragging has started
// (see #5003)
if ( $.ui.ddmanager ) {
$.ui.ddmanager.dragStart( this, event );
}
return true;
},
_refreshOffsets: function( event ) {
this.offset = {
top: this.positionAbs.top - this.margins.top,
left: this.positionAbs.left - this.margins.left,
scroll: false,
parent: this._getParentOffset(),
relative: this._getRelativeOffset()
};
this.offset.click = {
left: event.pageX - this.offset.left,
top: event.pageY - this.offset.top
};
},
_mouseDrag: function( event, noPropagation ) {
// reset any necessary cached properties (see #5009)
if ( this.hasFixedAncestor ) {
this.offset.parent = this._getParentOffset();
}
//Compute the helpers position
this.position = this._generatePosition( event, true );
this.positionAbs = this._convertPositionTo( "absolute" );
//Call plugins and callbacks and use the resulting position if something is returned
if ( !noPropagation ) {
var ui = this._uiHash();
if ( this._trigger( "drag", event, ui ) === false ) {
this._mouseUp( new $.Event( "mouseup", event ) );
return false;
}
this.position = ui.position;
}
this.helper[ 0 ].style.left = this.position.left + "px";
this.helper[ 0 ].style.top = this.position.top + "px";
if ( $.ui.ddmanager ) {
$.ui.ddmanager.drag( this, event );
}
return false;
},
_mouseStop: function( event ) {
//If we are using droppables, inform the manager about the drop
var that = this,
dropped = false;
if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
dropped = $.ui.ddmanager.drop( this, event );
}
//if a drop comes from outside (a sortable)
if ( this.dropped ) {
dropped = this.dropped;
this.dropped = false;
}
if ( ( this.options.revert === "invalid" && !dropped ) ||
( this.options.revert === "valid" && dropped ) ||
this.options.revert === true || ( $.isFunction( this.options.revert ) &&
this.options.revert.call( this.element, dropped ) )
) {
$( this.helper ).animate(
this.originalPosition,
parseInt( this.options.revertDuration, 10 ),
function() {
if ( that._trigger( "stop", event ) !== false ) {
that._clear();
}
}
);
} else {
if ( this._trigger( "stop", event ) !== false ) {
this._clear();
}
}
return false;
},
_mouseUp: function( event ) {
this._unblockFrames();
// If the ddmanager is used for droppables, inform the manager that dragging has stopped
// (see #5003)
if ( $.ui.ddmanager ) {
$.ui.ddmanager.dragStop( this, event );
}
// Only need to focus if the event occurred on the draggable itself, see #10527
if ( this.handleElement.is( event.target ) ) {
// The interaction is over; whether or not the click resulted in a drag,
// focus the element
this.element.trigger( "focus" );
}
return $.ui.mouse.prototype._mouseUp.call( this, event );
},
cancel: function() {
if ( this.helper.is( ".ui-draggable-dragging" ) ) {
this._mouseUp( new $.Event( "mouseup", { target: this.element[ 0 ] } ) );
} else {
this._clear();
}
return this;
},
_getHandle: function( event ) {
return this.options.handle ?
!!$( event.target ).closest( this.element.find( this.options.handle ) ).length :
true;
},
_setHandleClassName: function() {
this.handleElement = this.options.handle ?
this.element.find( this.options.handle ) : this.element;
this._addClass( this.handleElement, "ui-draggable-handle" );
},
_removeHandleClassName: function() {
this._removeClass( this.handleElement, "ui-draggable-handle" );
},
_createHelper: function( event ) {
var o = this.options,
helperIsFunction = $.isFunction( o.helper ),
helper = helperIsFunction ?
$( o.helper.apply( this.element[ 0 ], [ event ] ) ) :
( o.helper === "clone" ?
this.element.clone().removeAttr( "id" ) :
this.element );
if ( !helper.parents( "body" ).length ) {
helper.appendTo( ( o.appendTo === "parent" ?
this.element[ 0 ].parentNode :
o.appendTo ) );
}
// Http://bugs.jqueryui.com/ticket/9446
// a helper function can return the original element
// which wouldn't have been set to relative in _create
if ( helperIsFunction && helper[ 0 ] === this.element[ 0 ] ) {
this._setPositionRelative();
}
if ( helper[ 0 ] !== this.element[ 0 ] &&
!( /(fixed|absolute)/ ).test( helper.css( "position" ) ) ) {
helper.css( "position", "absolute" );
}
return helper;
},
_setPositionRelative: function() {
if ( !( /^(?:r|a|f)/ ).test( this.element.css( "position" ) ) ) {
this.element[ 0 ].style.position = "relative";
}
},
_adjustOffsetFromHelper: function( obj ) {
if ( typeof obj === "string" ) {
obj = obj.split( " " );
}
if ( $.isArray( obj ) ) {
obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
}
if ( "left" in obj ) {
this.offset.click.left = obj.left + this.margins.left;
}
if ( "right" in obj ) {
this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
}
if ( "top" in obj ) {
this.offset.click.top = obj.top + this.margins.top;
}
if ( "bottom" in obj ) {
this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
}
},
_isRootNode: function( element ) {
return ( /(html|body)/i ).test( element.tagName ) || element === this.document[ 0 ];
},
_getParentOffset: function() {
//Get the offsetParent and cache its position
var po = this.offsetParent.offset(),
document = this.document[ 0 ];
// This is a special case where we need to modify a offset calculated on start, since the
// following happened:
// 1. The position of the helper is absolute, so it's position is calculated based on the
// next positioned parent
// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
// the document, which means that the scroll is included in the initial calculation of the
// offset of the parent, and never recalculated upon drag
if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== document &&
$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
po.left += this.scrollParent.scrollLeft();
po.top += this.scrollParent.scrollTop();
}
if ( this._isRootNode( this.offsetParent[ 0 ] ) ) {
po = { top: 0, left: 0 };
}
return {
top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
};
},
_getRelativeOffset: function() {
if ( this.cssPosition !== "relative" ) {
return { top: 0, left: 0 };
}
var p = this.element.position(),
scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
return {
top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
( !scrollIsRootNode ? this.scrollParent.scrollTop() : 0 ),
left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
( !scrollIsRootNode ? this.scrollParent.scrollLeft() : 0 )
};
},
_cacheMargins: function() {
this.margins = {
left: ( parseInt( this.element.css( "marginLeft" ), 10 ) || 0 ),
top: ( parseInt( this.element.css( "marginTop" ), 10 ) || 0 ),
right: ( parseInt( this.element.css( "marginRight" ), 10 ) || 0 ),
bottom: ( parseInt( this.element.css( "marginBottom" ), 10 ) || 0 )
};
},
_cacheHelperProportions: function() {
this.helperProportions = {
width: this.helper.outerWidth(),
height: this.helper.outerHeight()
};
},
_setContainment: function() {
var isUserScrollable, c, ce,
o = this.options,
document = this.document[ 0 ];
this.relativeContainer = null;
if ( !o.containment ) {
this.containment = null;
return;
}
if ( o.containment === "window" ) {
this.containment = [
$( window ).scrollLeft() - this.offset.relative.left - this.offset.parent.left,
$( window ).scrollTop() - this.offset.relative.top - this.offset.parent.top,
$( window ).scrollLeft() + $( window ).width() -
this.helperProportions.width - this.margins.left,
$( window ).scrollTop() +
( $( window ).height() || document.body.parentNode.scrollHeight ) -
this.helperProportions.height - this.margins.top
];
return;
}
if ( o.containment === "document" ) {
this.containment = [
0,
0,
$( document ).width() - this.helperProportions.width - this.margins.left,
( $( document ).height() || document.body.parentNode.scrollHeight ) -
this.helperProportions.height - this.margins.top
];
return;
}
if ( o.containment.constructor === Array ) {
this.containment = o.containment;
return;
}
if ( o.containment === "parent" ) {
o.containment = this.helper[ 0 ].parentNode;
}
c = $( o.containment );
ce = c[ 0 ];
if ( !ce ) {
return;
}
isUserScrollable = /(scroll|auto)/.test( c.css( "overflow" ) );
this.containment = [
( parseInt( c.css( "borderLeftWidth" ), 10 ) || 0 ) +
( parseInt( c.css( "paddingLeft" ), 10 ) || 0 ),
( parseInt( c.css( "borderTopWidth" ), 10 ) || 0 ) +
( parseInt( c.css( "paddingTop" ), 10 ) || 0 ),
( isUserScrollable ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
( parseInt( c.css( "borderRightWidth" ), 10 ) || 0 ) -
( parseInt( c.css( "paddingRight" ), 10 ) || 0 ) -
this.helperProportions.width -
this.margins.left -
this.margins.right,
( isUserScrollable ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
( parseInt( c.css( "borderBottomWidth" ), 10 ) || 0 ) -
( parseInt( c.css( "paddingBottom" ), 10 ) || 0 ) -
this.helperProportions.height -
this.margins.top -
this.margins.bottom
];
this.relativeContainer = c;
},
_convertPositionTo: function( d, pos ) {
if ( !pos ) {
pos = this.position;
}
var mod = d === "absolute" ? 1 : -1,
scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] );
return {
top: (
// The absolute mouse position
pos.top +
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.top * mod +
// The offsetParent's offset without borders (offset + border)
this.offset.parent.top * mod -
( ( this.cssPosition === "fixed" ?
-this.offset.scroll.top :
( scrollIsRootNode ? 0 : this.offset.scroll.top ) ) * mod )
),
left: (
// The absolute mouse position
pos.left +
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.left * mod +
// The offsetParent's offset without borders (offset + border)
this.offset.parent.left * mod -
( ( this.cssPosition === "fixed" ?
-this.offset.scroll.left :
( scrollIsRootNode ? 0 : this.offset.scroll.left ) ) * mod )
)
};
},
_generatePosition: function( event, constrainPosition ) {
var containment, co, top, left,
o = this.options,
scrollIsRootNode = this._isRootNode( this.scrollParent[ 0 ] ),
pageX = event.pageX,
pageY = event.pageY;
// Cache the scroll
if ( !scrollIsRootNode || !this.offset.scroll ) {
this.offset.scroll = {
top: this.scrollParent.scrollTop(),
left: this.scrollParent.scrollLeft()
};
}
/*
* - Position constraining -
* Constrain the position to a mix of grid, containment.
*/
// If we are not dragging yet, we won't check for options
if ( constrainPosition ) {
if ( this.containment ) {
if ( this.relativeContainer ) {
co = this.relativeContainer.offset();
containment = [
this.containment[ 0 ] + co.left,
this.containment[ 1 ] + co.top,
this.containment[ 2 ] + co.left,
this.containment[ 3 ] + co.top
];
} else {
containment = this.containment;
}
if ( event.pageX - this.offset.click.left < containment[ 0 ] ) {
pageX = containment[ 0 ] + this.offset.click.left;
}
if ( event.pageY - this.offset.click.top < containment[ 1 ] ) {
pageY = containment[ 1 ] + this.offset.click.top;
}
if ( event.pageX - this.offset.click.left > containment[ 2 ] ) {
pageX = containment[ 2 ] + this.offset.click.left;
}
if ( event.pageY - this.offset.click.top > containment[ 3 ] ) {
pageY = containment[ 3 ] + this.offset.click.top;
}
}
if ( o.grid ) {
//Check for grid elements set to 0 to prevent divide by 0 error causing invalid
// argument errors in IE (see ticket #6950)
top = o.grid[ 1 ] ? this.originalPageY + Math.round( ( pageY -
this.originalPageY ) / o.grid[ 1 ] ) * o.grid[ 1 ] : this.originalPageY;
pageY = containment ? ( ( top - this.offset.click.top >= containment[ 1 ] ||
top - this.offset.click.top > containment[ 3 ] ) ?
top :
( ( top - this.offset.click.top >= containment[ 1 ] ) ?
top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) : top;
left = o.grid[ 0 ] ? this.originalPageX +
Math.round( ( pageX - this.originalPageX ) / o.grid[ 0 ] ) * o.grid[ 0 ] :
this.originalPageX;
pageX = containment ? ( ( left - this.offset.click.left >= containment[ 0 ] ||
left - this.offset.click.left > containment[ 2 ] ) ?
left :
( ( left - this.offset.click.left >= containment[ 0 ] ) ?
left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) : left;
}
if ( o.axis === "y" ) {
pageX = this.originalPageX;
}
if ( o.axis === "x" ) {
pageY = this.originalPageY;
}
}
return {
top: (
// The absolute mouse position
pageY -
// Click offset (relative to the element)
this.offset.click.top -
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.top -
// The offsetParent's offset without borders (offset + border)
this.offset.parent.top +
( this.cssPosition === "fixed" ?
-this.offset.scroll.top :
( scrollIsRootNode ? 0 : this.offset.scroll.top ) )
),
left: (
// The absolute mouse position
pageX -
// Click offset (relative to the element)
this.offset.click.left -
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.left -
// The offsetParent's offset without borders (offset + border)
this.offset.parent.left +
( this.cssPosition === "fixed" ?
-this.offset.scroll.left :
( scrollIsRootNode ? 0 : this.offset.scroll.left ) )
)
};
},
_clear: function() {
this._removeClass( this.helper, "ui-draggable-dragging" );
if ( this.helper[ 0 ] !== this.element[ 0 ] && !this.cancelHelperRemoval ) {
this.helper.remove();
}
this.helper = null;
this.cancelHelperRemoval = false;
if ( this.destroyOnClear ) {
this.destroy();
}
},
// From now on bulk stuff - mainly helpers
_trigger: function( type, event, ui ) {
ui = ui || this._uiHash();
$.ui.plugin.call( this, type, [ event, ui, this ], true );
// Absolute position and offset (see #6884 ) have to be recalculated after plugins
if ( /^(drag|start|stop)/.test( type ) ) {
this.positionAbs = this._convertPositionTo( "absolute" );
ui.offset = this.positionAbs;
}
return $.Widget.prototype._trigger.call( this, type, event, ui );
},
plugins: {},
_uiHash: function() {
return {
helper: this.helper,
position: this.position,
originalPosition: this.originalPosition,
offset: this.positionAbs
};
}
} );
$.ui.plugin.add( "draggable", "connectToSortable", {
start: function( event, ui, draggable ) {
var uiSortable = $.extend( {}, ui, {
item: draggable.element
} );
draggable.sortables = [];
$( draggable.options.connectToSortable ).each( function() {
var sortable = $( this ).sortable( "instance" );
if ( sortable && !sortable.options.disabled ) {
draggable.sortables.push( sortable );
// RefreshPositions is called at drag start to refresh the containerCache
// which is used in drag. This ensures it's initialized and synchronized
// with any changes that might have happened on the page since initialization.
sortable.refreshPositions();
sortable._trigger( "activate", event, uiSortable );
}
} );
},
stop: function( event, ui, draggable ) {
var uiSortable = $.extend( {}, ui, {
item: draggable.element
} );
draggable.cancelHelperRemoval = false;
$.each( draggable.sortables, function() {
var sortable = this;
if ( sortable.isOver ) {
sortable.isOver = 0;
// Allow this sortable to handle removing the helper
draggable.cancelHelperRemoval = true;
sortable.cancelHelperRemoval = false;
// Use _storedCSS To restore properties in the sortable,
// as this also handles revert (#9675) since the draggable
// may have modified them in unexpected ways (#8809)
sortable._storedCSS = {
position: sortable.placeholder.css( "position" ),
top: sortable.placeholder.css( "top" ),
left: sortable.placeholder.css( "left" )
};
sortable._mouseStop( event );
// Once drag has ended, the sortable should return to using
// its original helper, not the shared helper from draggable
sortable.options.helper = sortable.options._helper;
} else {
// Prevent this Sortable from removing the helper.
// However, don't set the draggable to remove the helper
// either as another connected Sortable may yet handle the removal.
sortable.cancelHelperRemoval = true;
sortable._trigger( "deactivate", event, uiSortable );
}
} );
},
drag: function( event, ui, draggable ) {
$.each( draggable.sortables, function() {
var innermostIntersecting = false,
sortable = this;
// Copy over variables that sortable's _intersectsWith uses
sortable.positionAbs = draggable.positionAbs;
sortable.helperProportions = draggable.helperProportions;
sortable.offset.click = draggable.offset.click;
if ( sortable._intersectsWith( sortable.containerCache ) ) {
innermostIntersecting = true;
$.each( draggable.sortables, function() {
// Copy over variables that sortable's _intersectsWith uses
this.positionAbs = draggable.positionAbs;
this.helperProportions = draggable.helperProportions;
this.offset.click = draggable.offset.click;
if ( this !== sortable &&
this._intersectsWith( this.containerCache ) &&
$.contains( sortable.element[ 0 ], this.element[ 0 ] ) ) {
innermostIntersecting = false;
}
return innermostIntersecting;
} );
}
if ( innermostIntersecting ) {
// If it intersects, we use a little isOver variable and set it once,
// so that the move-in stuff gets fired only once.
if ( !sortable.isOver ) {
sortable.isOver = 1;
// Store draggable's parent in case we need to reappend to it later.
draggable._parent = ui.helper.parent();
sortable.currentItem = ui.helper
.appendTo( sortable.element )
.data( "ui-sortable-item", true );
// Store helper option to later restore it
sortable.options._helper = sortable.options.helper;
sortable.options.helper = function() {
return ui.helper[ 0 ];
};
// Fire the start events of the sortable with our passed browser event,
// and our own helper (so it doesn't create a new one)
event.target = sortable.currentItem[ 0 ];
sortable._mouseCapture( event, true );
sortable._mouseStart( event, true, true );
// Because the browser event is way off the new appended portlet,
// modify necessary variables to reflect the changes
sortable.offset.click.top = draggable.offset.click.top;
sortable.offset.click.left = draggable.offset.click.left;
sortable.offset.parent.left -= draggable.offset.parent.left -
sortable.offset.parent.left;
sortable.offset.parent.top -= draggable.offset.parent.top -
sortable.offset.parent.top;
draggable._trigger( "toSortable", event );
// Inform draggable that the helper is in a valid drop zone,
// used solely in the revert option to handle "valid/invalid".
draggable.dropped = sortable.element;
// Need to refreshPositions of all sortables in the case that
// adding to one sortable changes the location of the other sortables (#9675)
$.each( draggable.sortables, function() {
this.refreshPositions();
} );
// Hack so receive/update callbacks work (mostly)
draggable.currentItem = draggable.element;
sortable.fromOutside = draggable;
}
if ( sortable.currentItem ) {
sortable._mouseDrag( event );
// Copy the sortable's position because the draggable's can potentially reflect
// a relative position, while sortable is always absolute, which the dragged
// element has now become. (#8809)
ui.position = sortable.position;
}
} else {
// If it doesn't intersect with the sortable, and it intersected before,
// we fake the drag stop of the sortable, but make sure it doesn't remove
// the helper by using cancelHelperRemoval.
if ( sortable.isOver ) {
sortable.isOver = 0;
sortable.cancelHelperRemoval = true;
// Calling sortable's mouseStop would trigger a revert,
// so revert must be temporarily false until after mouseStop is called.
sortable.options._revert = sortable.options.revert;
sortable.options.revert = false;
sortable._trigger( "out", event, sortable._uiHash( sortable ) );
sortable._mouseStop( event, true );
// Restore sortable behaviors that were modfied
// when the draggable entered the sortable area (#9481)
sortable.options.revert = sortable.options._revert;
sortable.options.helper = sortable.options._helper;
if ( sortable.placeholder ) {
sortable.placeholder.remove();
}
// Restore and recalculate the draggable's offset considering the sortable
// may have modified them in unexpected ways. (#8809, #10669)
ui.helper.appendTo( draggable._parent );
draggable._refreshOffsets( event );
ui.position = draggable._generatePosition( event, true );
draggable._trigger( "fromSortable", event );
// Inform draggable that the helper is no longer in a valid drop zone
draggable.dropped = false;
// Need to refreshPositions of all sortables just in case removing
// from one sortable changes the location of other sortables (#9675)
$.each( draggable.sortables, function() {
this.refreshPositions();
} );
}
}
} );
}
} );
$.ui.plugin.add( "draggable", "cursor", {
start: function( event, ui, instance ) {
var t = $( "body" ),
o = instance.options;
if ( t.css( "cursor" ) ) {
o._cursor = t.css( "cursor" );
}
t.css( "cursor", o.cursor );
},
stop: function( event, ui, instance ) {
var o = instance.options;
if ( o._cursor ) {
$( "body" ).css( "cursor", o._cursor );
}
}
} );
$.ui.plugin.add( "draggable", "opacity", {
start: function( event, ui, instance ) {
var t = $( ui.helper ),
o = instance.options;
if ( t.css( "opacity" ) ) {
o._opacity = t.css( "opacity" );
}
t.css( "opacity", o.opacity );
},
stop: function( event, ui, instance ) {
var o = instance.options;
if ( o._opacity ) {
$( ui.helper ).css( "opacity", o._opacity );
}
}
} );
$.ui.plugin.add( "draggable", "scroll", {
start: function( event, ui, i ) {
if ( !i.scrollParentNotHidden ) {
i.scrollParentNotHidden = i.helper.scrollParent( false );
}
if ( i.scrollParentNotHidden[ 0 ] !== i.document[ 0 ] &&
i.scrollParentNotHidden[ 0 ].tagName !== "HTML" ) {
i.overflowOffset = i.scrollParentNotHidden.offset();
}
},
drag: function( event, ui, i ) {
var o = i.options,
scrolled = false,
scrollParent = i.scrollParentNotHidden[ 0 ],
document = i.document[ 0 ];
if ( scrollParent !== document && scrollParent.tagName !== "HTML" ) {
if ( !o.axis || o.axis !== "x" ) {
if ( ( i.overflowOffset.top + scrollParent.offsetHeight ) - event.pageY <
o.scrollSensitivity ) {
scrollParent.scrollTop = scrolled = scrollParent.scrollTop + o.scrollSpeed;
} else if ( event.pageY - i.overflowOffset.top < o.scrollSensitivity ) {
scrollParent.scrollTop = scrolled = scrollParent.scrollTop - o.scrollSpeed;
}
}
if ( !o.axis || o.axis !== "y" ) {
if ( ( i.overflowOffset.left + scrollParent.offsetWidth ) - event.pageX <
o.scrollSensitivity ) {
scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft + o.scrollSpeed;
} else if ( event.pageX - i.overflowOffset.left < o.scrollSensitivity ) {
scrollParent.scrollLeft = scrolled = scrollParent.scrollLeft - o.scrollSpeed;
}
}
} else {
if ( !o.axis || o.axis !== "x" ) {
if ( event.pageY - $( document ).scrollTop() < o.scrollSensitivity ) {
scrolled = $( document ).scrollTop( $( document ).scrollTop() - o.scrollSpeed );
} else if ( $( window ).height() - ( event.pageY - $( document ).scrollTop() ) <
o.scrollSensitivity ) {
scrolled = $( document ).scrollTop( $( document ).scrollTop() + o.scrollSpeed );
}
}
if ( !o.axis || o.axis !== "y" ) {
if ( event.pageX - $( document ).scrollLeft() < o.scrollSensitivity ) {
scrolled = $( document ).scrollLeft(
$( document ).scrollLeft() - o.scrollSpeed
);
} else if ( $( window ).width() - ( event.pageX - $( document ).scrollLeft() ) <
o.scrollSensitivity ) {
scrolled = $( document ).scrollLeft(
$( document ).scrollLeft() + o.scrollSpeed
);
}
}
}
if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( i, event );
}
}
} );
$.ui.plugin.add( "draggable", "snap", {
start: function( event, ui, i ) {
var o = i.options;
i.snapElements = [];
$( o.snap.constructor !== String ? ( o.snap.items || ":data(ui-draggable)" ) : o.snap )
.each( function() {
var $t = $( this ),
$o = $t.offset();
if ( this !== i.element[ 0 ] ) {
i.snapElements.push( {
item: this,
width: $t.outerWidth(), height: $t.outerHeight(),
top: $o.top, left: $o.left
} );
}
} );
},
drag: function( event, ui, inst ) {
var ts, bs, ls, rs, l, r, t, b, i, first,
o = inst.options,
d = o.snapTolerance,
x1 = ui.offset.left, x2 = x1 + inst.helperProportions.width,
y1 = ui.offset.top, y2 = y1 + inst.helperProportions.height;
for ( i = inst.snapElements.length - 1; i >= 0; i-- ) {
l = inst.snapElements[ i ].left - inst.margins.left;
r = l + inst.snapElements[ i ].width;
t = inst.snapElements[ i ].top - inst.margins.top;
b = t + inst.snapElements[ i ].height;
if ( x2 < l - d || x1 > r + d || y2 < t - d || y1 > b + d ||
!$.contains( inst.snapElements[ i ].item.ownerDocument,
inst.snapElements[ i ].item ) ) {
if ( inst.snapElements[ i ].snapping ) {
( inst.options.snap.release &&
inst.options.snap.release.call(
inst.element,
event,
$.extend( inst._uiHash(), { snapItem: inst.snapElements[ i ].item } )
) );
}
inst.snapElements[ i ].snapping = false;
continue;
}
if ( o.snapMode !== "inner" ) {
ts = Math.abs( t - y2 ) <= d;
bs = Math.abs( b - y1 ) <= d;
ls = Math.abs( l - x2 ) <= d;
rs = Math.abs( r - x1 ) <= d;
if ( ts ) {
ui.position.top = inst._convertPositionTo( "relative", {
top: t - inst.helperProportions.height,
left: 0
} ).top;
}
if ( bs ) {
ui.position.top = inst._convertPositionTo( "relative", {
top: b,
left: 0
} ).top;
}
if ( ls ) {
ui.position.left = inst._convertPositionTo( "relative", {
top: 0,
left: l - inst.helperProportions.width
} ).left;
}
if ( rs ) {
ui.position.left = inst._convertPositionTo( "relative", {
top: 0,
left: r
} ).left;
}
}
first = ( ts || bs || ls || rs );
if ( o.snapMode !== "outer" ) {
ts = Math.abs( t - y1 ) <= d;
bs = Math.abs( b - y2 ) <= d;
ls = Math.abs( l - x1 ) <= d;
rs = Math.abs( r - x2 ) <= d;
if ( ts ) {
ui.position.top = inst._convertPositionTo( "relative", {
top: t,
left: 0
} ).top;
}
if ( bs ) {
ui.position.top = inst._convertPositionTo( "relative", {
top: b - inst.helperProportions.height,
left: 0
} ).top;
}
if ( ls ) {
ui.position.left = inst._convertPositionTo( "relative", {
top: 0,
left: l
} ).left;
}
if ( rs ) {
ui.position.left = inst._convertPositionTo( "relative", {
top: 0,
left: r - inst.helperProportions.width
} ).left;
}
}
if ( !inst.snapElements[ i ].snapping && ( ts || bs || ls || rs || first ) ) {
( inst.options.snap.snap &&
inst.options.snap.snap.call(
inst.element,
event,
$.extend( inst._uiHash(), {
snapItem: inst.snapElements[ i ].item
} ) ) );
}
inst.snapElements[ i ].snapping = ( ts || bs || ls || rs || first );
}
}
} );
$.ui.plugin.add( "draggable", "stack", {
start: function( event, ui, instance ) {
var min,
o = instance.options,
group = $.makeArray( $( o.stack ) ).sort( function( a, b ) {
return ( parseInt( $( a ).css( "zIndex" ), 10 ) || 0 ) -
( parseInt( $( b ).css( "zIndex" ), 10 ) || 0 );
} );
if ( !group.length ) { return; }
min = parseInt( $( group[ 0 ] ).css( "zIndex" ), 10 ) || 0;
$( group ).each( function( i ) {
$( this ).css( "zIndex", min + i );
} );
this.css( "zIndex", ( min + group.length ) );
}
} );
$.ui.plugin.add( "draggable", "zIndex", {
start: function( event, ui, instance ) {
var t = $( ui.helper ),
o = instance.options;
if ( t.css( "zIndex" ) ) {
o._zIndex = t.css( "zIndex" );
}
t.css( "zIndex", o.zIndex );
},
stop: function( event, ui, instance ) {
var o = instance.options;
if ( o._zIndex ) {
$( ui.helper ).css( "zIndex", o._zIndex );
}
}
} );
var widgetsDraggable = $.ui.draggable;
/*!
* jQuery UI Resizable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Resizable
//>>group: Interactions
//>>description: Enables resize functionality for any element.
//>>docs: http://api.jqueryui.com/resizable/
//>>demos: http://jqueryui.com/resizable/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/resizable.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.resizable", $.ui.mouse, {
version: "1.12.1",
widgetEventPrefix: "resize",
options: {
alsoResize: false,
animate: false,
animateDuration: "slow",
animateEasing: "swing",
aspectRatio: false,
autoHide: false,
classes: {
"ui-resizable-se": "ui-icon ui-icon-gripsmall-diagonal-se"
},
containment: false,
ghost: false,
grid: false,
handles: "e,s,se",
helper: false,
maxHeight: null,
maxWidth: null,
minHeight: 10,
minWidth: 10,
// See #7960
zIndex: 90,
// Callbacks
resize: null,
start: null,
stop: null
},
_num: function( value ) {
return parseFloat( value ) || 0;
},
_isNumber: function( value ) {
return !isNaN( parseFloat( value ) );
},
_hasScroll: function( el, a ) {
if ( $( el ).css( "overflow" ) === "hidden" ) {
return false;
}
var scroll = ( a && a === "left" ) ? "scrollLeft" : "scrollTop",
has = false;
if ( el[ scroll ] > 0 ) {
return true;
}
// TODO: determine which cases actually cause this to happen
// if the element doesn't have the scroll set, see if it's possible to
// set the scroll
el[ scroll ] = 1;
has = ( el[ scroll ] > 0 );
el[ scroll ] = 0;
return has;
},
_create: function() {
var margins,
o = this.options,
that = this;
this._addClass( "ui-resizable" );
$.extend( this, {
_aspectRatio: !!( o.aspectRatio ),
aspectRatio: o.aspectRatio,
originalElement: this.element,
_proportionallyResizeElements: [],
_helper: o.helper || o.ghost || o.animate ? o.helper || "ui-resizable-helper" : null
} );
// Wrap the element if it cannot hold child nodes
if ( this.element[ 0 ].nodeName.match( /^(canvas|textarea|input|select|button|img)$/i ) ) {
this.element.wrap(
$( "<div class='ui-wrapper' style='overflow: hidden;'></div>" ).css( {
position: this.element.css( "position" ),
width: this.element.outerWidth(),
height: this.element.outerHeight(),
top: this.element.css( "top" ),
left: this.element.css( "left" )
} )
);
this.element = this.element.parent().data(
"ui-resizable", this.element.resizable( "instance" )
);
this.elementIsWrapper = true;
margins = {
marginTop: this.originalElement.css( "marginTop" ),
marginRight: this.originalElement.css( "marginRight" ),
marginBottom: this.originalElement.css( "marginBottom" ),
marginLeft: this.originalElement.css( "marginLeft" )
};
this.element.css( margins );
this.originalElement.css( "margin", 0 );
// support: Safari
// Prevent Safari textarea resize
this.originalResizeStyle = this.originalElement.css( "resize" );
this.originalElement.css( "resize", "none" );
this._proportionallyResizeElements.push( this.originalElement.css( {
position: "static",
zoom: 1,
display: "block"
} ) );
// Support: IE9
// avoid IE jump (hard set the margin)
this.originalElement.css( margins );
this._proportionallyResize();
}
this._setupHandles();
if ( o.autoHide ) {
$( this.element )
.on( "mouseenter", function() {
if ( o.disabled ) {
return;
}
that._removeClass( "ui-resizable-autohide" );
that._handles.show();
} )
.on( "mouseleave", function() {
if ( o.disabled ) {
return;
}
if ( !that.resizing ) {
that._addClass( "ui-resizable-autohide" );
that._handles.hide();
}
} );
}
this._mouseInit();
},
_destroy: function() {
this._mouseDestroy();
var wrapper,
_destroy = function( exp ) {
$( exp )
.removeData( "resizable" )
.removeData( "ui-resizable" )
.off( ".resizable" )
.find( ".ui-resizable-handle" )
.remove();
};
// TODO: Unwrap at same DOM position
if ( this.elementIsWrapper ) {
_destroy( this.element );
wrapper = this.element;
this.originalElement.css( {
position: wrapper.css( "position" ),
width: wrapper.outerWidth(),
height: wrapper.outerHeight(),
top: wrapper.css( "top" ),
left: wrapper.css( "left" )
} ).insertAfter( wrapper );
wrapper.remove();
}
this.originalElement.css( "resize", this.originalResizeStyle );
_destroy( this.originalElement );
return this;
},
_setOption: function( key, value ) {
this._super( key, value );
switch ( key ) {
case "handles":
this._removeHandles();
this._setupHandles();
break;
default:
break;
}
},
_setupHandles: function() {
var o = this.options, handle, i, n, hname, axis, that = this;
this.handles = o.handles ||
( !$( ".ui-resizable-handle", this.element ).length ?
"e,s,se" : {
n: ".ui-resizable-n",
e: ".ui-resizable-e",
s: ".ui-resizable-s",
w: ".ui-resizable-w",
se: ".ui-resizable-se",
sw: ".ui-resizable-sw",
ne: ".ui-resizable-ne",
nw: ".ui-resizable-nw"
} );
this._handles = $();
if ( this.handles.constructor === String ) {
if ( this.handles === "all" ) {
this.handles = "n,e,s,w,se,sw,ne,nw";
}
n = this.handles.split( "," );
this.handles = {};
for ( i = 0; i < n.length; i++ ) {
handle = $.trim( n[ i ] );
hname = "ui-resizable-" + handle;
axis = $( "<div>" );
this._addClass( axis, "ui-resizable-handle " + hname );
axis.css( { zIndex: o.zIndex } );
this.handles[ handle ] = ".ui-resizable-" + handle;
this.element.append( axis );
}
}
this._renderAxis = function( target ) {
var i, axis, padPos, padWrapper;
target = target || this.element;
for ( i in this.handles ) {
if ( this.handles[ i ].constructor === String ) {
this.handles[ i ] = this.element.children( this.handles[ i ] ).first().show();
} else if ( this.handles[ i ].jquery || this.handles[ i ].nodeType ) {
this.handles[ i ] = $( this.handles[ i ] );
this._on( this.handles[ i ], { "mousedown": that._mouseDown } );
}
if ( this.elementIsWrapper &&
this.originalElement[ 0 ]
.nodeName
.match( /^(textarea|input|select|button)$/i ) ) {
axis = $( this.handles[ i ], this.element );
padWrapper = /sw|ne|nw|se|n|s/.test( i ) ?
axis.outerHeight() :
axis.outerWidth();
padPos = [ "padding",
/ne|nw|n/.test( i ) ? "Top" :
/se|sw|s/.test( i ) ? "Bottom" :
/^e$/.test( i ) ? "Right" : "Left" ].join( "" );
target.css( padPos, padWrapper );
this._proportionallyResize();
}
this._handles = this._handles.add( this.handles[ i ] );
}
};
// TODO: make renderAxis a prototype function
this._renderAxis( this.element );
this._handles = this._handles.add( this.element.find( ".ui-resizable-handle" ) );
this._handles.disableSelection();
this._handles.on( "mouseover", function() {
if ( !that.resizing ) {
if ( this.className ) {
axis = this.className.match( /ui-resizable-(se|sw|ne|nw|n|e|s|w)/i );
}
that.axis = axis && axis[ 1 ] ? axis[ 1 ] : "se";
}
} );
if ( o.autoHide ) {
this._handles.hide();
this._addClass( "ui-resizable-autohide" );
}
},
_removeHandles: function() {
this._handles.remove();
},
_mouseCapture: function( event ) {
var i, handle,
capture = false;
for ( i in this.handles ) {
handle = $( this.handles[ i ] )[ 0 ];
if ( handle === event.target || $.contains( handle, event.target ) ) {
capture = true;
}
}
return !this.options.disabled && capture;
},
_mouseStart: function( event ) {
var curleft, curtop, cursor,
o = this.options,
el = this.element;
this.resizing = true;
this._renderProxy();
curleft = this._num( this.helper.css( "left" ) );
curtop = this._num( this.helper.css( "top" ) );
if ( o.containment ) {
curleft += $( o.containment ).scrollLeft() || 0;
curtop += $( o.containment ).scrollTop() || 0;
}
this.offset = this.helper.offset();
this.position = { left: curleft, top: curtop };
this.size = this._helper ? {
width: this.helper.width(),
height: this.helper.height()
} : {
width: el.width(),
height: el.height()
};
this.originalSize = this._helper ? {
width: el.outerWidth(),
height: el.outerHeight()
} : {
width: el.width(),
height: el.height()
};
this.sizeDiff = {
width: el.outerWidth() - el.width(),
height: el.outerHeight() - el.height()
};
this.originalPosition = { left: curleft, top: curtop };
this.originalMousePosition = { left: event.pageX, top: event.pageY };
this.aspectRatio = ( typeof o.aspectRatio === "number" ) ?
o.aspectRatio :
( ( this.originalSize.width / this.originalSize.height ) || 1 );
cursor = $( ".ui-resizable-" + this.axis ).css( "cursor" );
$( "body" ).css( "cursor", cursor === "auto" ? this.axis + "-resize" : cursor );
this._addClass( "ui-resizable-resizing" );
this._propagate( "start", event );
return true;
},
_mouseDrag: function( event ) {
var data, props,
smp = this.originalMousePosition,
a = this.axis,
dx = ( event.pageX - smp.left ) || 0,
dy = ( event.pageY - smp.top ) || 0,
trigger = this._change[ a ];
this._updatePrevProperties();
if ( !trigger ) {
return false;
}
data = trigger.apply( this, [ event, dx, dy ] );
this._updateVirtualBoundaries( event.shiftKey );
if ( this._aspectRatio || event.shiftKey ) {
data = this._updateRatio( data, event );
}
data = this._respectSize( data, event );
this._updateCache( data );
this._propagate( "resize", event );
props = this._applyChanges();
if ( !this._helper && this._proportionallyResizeElements.length ) {
this._proportionallyResize();
}
if ( !$.isEmptyObject( props ) ) {
this._updatePrevProperties();
this._trigger( "resize", event, this.ui() );
this._applyChanges();
}
return false;
},
_mouseStop: function( event ) {
this.resizing = false;
var pr, ista, soffseth, soffsetw, s, left, top,
o = this.options, that = this;
if ( this._helper ) {
pr = this._proportionallyResizeElements;
ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName );
soffseth = ista && this._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height;
soffsetw = ista ? 0 : that.sizeDiff.width;
s = {
width: ( that.helper.width() - soffsetw ),
height: ( that.helper.height() - soffseth )
};
left = ( parseFloat( that.element.css( "left" ) ) +
( that.position.left - that.originalPosition.left ) ) || null;
top = ( parseFloat( that.element.css( "top" ) ) +
( that.position.top - that.originalPosition.top ) ) || null;
if ( !o.animate ) {
this.element.css( $.extend( s, { top: top, left: left } ) );
}
that.helper.height( that.size.height );
that.helper.width( that.size.width );
if ( this._helper && !o.animate ) {
this._proportionallyResize();
}
}
$( "body" ).css( "cursor", "auto" );
this._removeClass( "ui-resizable-resizing" );
this._propagate( "stop", event );
if ( this._helper ) {
this.helper.remove();
}
return false;
},
_updatePrevProperties: function() {
this.prevPosition = {
top: this.position.top,
left: this.position.left
};
this.prevSize = {
width: this.size.width,
height: this.size.height
};
},
_applyChanges: function() {
var props = {};
if ( this.position.top !== this.prevPosition.top ) {
props.top = this.position.top + "px";
}
if ( this.position.left !== this.prevPosition.left ) {
props.left = this.position.left + "px";
}
if ( this.size.width !== this.prevSize.width ) {
props.width = this.size.width + "px";
}
if ( this.size.height !== this.prevSize.height ) {
props.height = this.size.height + "px";
}
this.helper.css( props );
return props;
},
_updateVirtualBoundaries: function( forceAspectRatio ) {
var pMinWidth, pMaxWidth, pMinHeight, pMaxHeight, b,
o = this.options;
b = {
minWidth: this._isNumber( o.minWidth ) ? o.minWidth : 0,
maxWidth: this._isNumber( o.maxWidth ) ? o.maxWidth : Infinity,
minHeight: this._isNumber( o.minHeight ) ? o.minHeight : 0,
maxHeight: this._isNumber( o.maxHeight ) ? o.maxHeight : Infinity
};
if ( this._aspectRatio || forceAspectRatio ) {
pMinWidth = b.minHeight * this.aspectRatio;
pMinHeight = b.minWidth / this.aspectRatio;
pMaxWidth = b.maxHeight * this.aspectRatio;
pMaxHeight = b.maxWidth / this.aspectRatio;
if ( pMinWidth > b.minWidth ) {
b.minWidth = pMinWidth;
}
if ( pMinHeight > b.minHeight ) {
b.minHeight = pMinHeight;
}
if ( pMaxWidth < b.maxWidth ) {
b.maxWidth = pMaxWidth;
}
if ( pMaxHeight < b.maxHeight ) {
b.maxHeight = pMaxHeight;
}
}
this._vBoundaries = b;
},
_updateCache: function( data ) {
this.offset = this.helper.offset();
if ( this._isNumber( data.left ) ) {
this.position.left = data.left;
}
if ( this._isNumber( data.top ) ) {
this.position.top = data.top;
}
if ( this._isNumber( data.height ) ) {
this.size.height = data.height;
}
if ( this._isNumber( data.width ) ) {
this.size.width = data.width;
}
},
_updateRatio: function( data ) {
var cpos = this.position,
csize = this.size,
a = this.axis;
if ( this._isNumber( data.height ) ) {
data.width = ( data.height * this.aspectRatio );
} else if ( this._isNumber( data.width ) ) {
data.height = ( data.width / this.aspectRatio );
}
if ( a === "sw" ) {
data.left = cpos.left + ( csize.width - data.width );
data.top = null;
}
if ( a === "nw" ) {
data.top = cpos.top + ( csize.height - data.height );
data.left = cpos.left + ( csize.width - data.width );
}
return data;
},
_respectSize: function( data ) {
var o = this._vBoundaries,
a = this.axis,
ismaxw = this._isNumber( data.width ) && o.maxWidth && ( o.maxWidth < data.width ),
ismaxh = this._isNumber( data.height ) && o.maxHeight && ( o.maxHeight < data.height ),
isminw = this._isNumber( data.width ) && o.minWidth && ( o.minWidth > data.width ),
isminh = this._isNumber( data.height ) && o.minHeight && ( o.minHeight > data.height ),
dw = this.originalPosition.left + this.originalSize.width,
dh = this.originalPosition.top + this.originalSize.height,
cw = /sw|nw|w/.test( a ), ch = /nw|ne|n/.test( a );
if ( isminw ) {
data.width = o.minWidth;
}
if ( isminh ) {
data.height = o.minHeight;
}
if ( ismaxw ) {
data.width = o.maxWidth;
}
if ( ismaxh ) {
data.height = o.maxHeight;
}
if ( isminw && cw ) {
data.left = dw - o.minWidth;
}
if ( ismaxw && cw ) {
data.left = dw - o.maxWidth;
}
if ( isminh && ch ) {
data.top = dh - o.minHeight;
}
if ( ismaxh && ch ) {
data.top = dh - o.maxHeight;
}
// Fixing jump error on top/left - bug #2330
if ( !data.width && !data.height && !data.left && data.top ) {
data.top = null;
} else if ( !data.width && !data.height && !data.top && data.left ) {
data.left = null;
}
return data;
},
_getPaddingPlusBorderDimensions: function( element ) {
var i = 0,
widths = [],
borders = [
element.css( "borderTopWidth" ),
element.css( "borderRightWidth" ),
element.css( "borderBottomWidth" ),
element.css( "borderLeftWidth" )
],
paddings = [
element.css( "paddingTop" ),
element.css( "paddingRight" ),
element.css( "paddingBottom" ),
element.css( "paddingLeft" )
];
for ( ; i < 4; i++ ) {
widths[ i ] = ( parseFloat( borders[ i ] ) || 0 );
widths[ i ] += ( parseFloat( paddings[ i ] ) || 0 );
}
return {
height: widths[ 0 ] + widths[ 2 ],
width: widths[ 1 ] + widths[ 3 ]
};
},
_proportionallyResize: function() {
if ( !this._proportionallyResizeElements.length ) {
return;
}
var prel,
i = 0,
element = this.helper || this.element;
for ( ; i < this._proportionallyResizeElements.length; i++ ) {
prel = this._proportionallyResizeElements[ i ];
// TODO: Seems like a bug to cache this.outerDimensions
// considering that we are in a loop.
if ( !this.outerDimensions ) {
this.outerDimensions = this._getPaddingPlusBorderDimensions( prel );
}
prel.css( {
height: ( element.height() - this.outerDimensions.height ) || 0,
width: ( element.width() - this.outerDimensions.width ) || 0
} );
}
},
_renderProxy: function() {
var el = this.element, o = this.options;
this.elementOffset = el.offset();
if ( this._helper ) {
this.helper = this.helper || $( "<div style='overflow:hidden;'></div>" );
this._addClass( this.helper, this._helper );
this.helper.css( {
width: this.element.outerWidth(),
height: this.element.outerHeight(),
position: "absolute",
left: this.elementOffset.left + "px",
top: this.elementOffset.top + "px",
zIndex: ++o.zIndex //TODO: Don't modify option
} );
this.helper
.appendTo( "body" )
.disableSelection();
} else {
this.helper = this.element;
}
},
_change: {
e: function( event, dx ) {
return { width: this.originalSize.width + dx };
},
w: function( event, dx ) {
var cs = this.originalSize, sp = this.originalPosition;
return { left: sp.left + dx, width: cs.width - dx };
},
n: function( event, dx, dy ) {
var cs = this.originalSize, sp = this.originalPosition;
return { top: sp.top + dy, height: cs.height - dy };
},
s: function( event, dx, dy ) {
return { height: this.originalSize.height + dy };
},
se: function( event, dx, dy ) {
return $.extend( this._change.s.apply( this, arguments ),
this._change.e.apply( this, [ event, dx, dy ] ) );
},
sw: function( event, dx, dy ) {
return $.extend( this._change.s.apply( this, arguments ),
this._change.w.apply( this, [ event, dx, dy ] ) );
},
ne: function( event, dx, dy ) {
return $.extend( this._change.n.apply( this, arguments ),
this._change.e.apply( this, [ event, dx, dy ] ) );
},
nw: function( event, dx, dy ) {
return $.extend( this._change.n.apply( this, arguments ),
this._change.w.apply( this, [ event, dx, dy ] ) );
}
},
_propagate: function( n, event ) {
$.ui.plugin.call( this, n, [ event, this.ui() ] );
( n !== "resize" && this._trigger( n, event, this.ui() ) );
},
plugins: {},
ui: function() {
return {
originalElement: this.originalElement,
element: this.element,
helper: this.helper,
position: this.position,
size: this.size,
originalSize: this.originalSize,
originalPosition: this.originalPosition
};
}
} );
/*
* Resizable Extensions
*/
$.ui.plugin.add( "resizable", "animate", {
stop: function( event ) {
var that = $( this ).resizable( "instance" ),
o = that.options,
pr = that._proportionallyResizeElements,
ista = pr.length && ( /textarea/i ).test( pr[ 0 ].nodeName ),
soffseth = ista && that._hasScroll( pr[ 0 ], "left" ) ? 0 : that.sizeDiff.height,
soffsetw = ista ? 0 : that.sizeDiff.width,
style = {
width: ( that.size.width - soffsetw ),
height: ( that.size.height - soffseth )
},
left = ( parseFloat( that.element.css( "left" ) ) +
( that.position.left - that.originalPosition.left ) ) || null,
top = ( parseFloat( that.element.css( "top" ) ) +
( that.position.top - that.originalPosition.top ) ) || null;
that.element.animate(
$.extend( style, top && left ? { top: top, left: left } : {} ), {
duration: o.animateDuration,
easing: o.animateEasing,
step: function() {
var data = {
width: parseFloat( that.element.css( "width" ) ),
height: parseFloat( that.element.css( "height" ) ),
top: parseFloat( that.element.css( "top" ) ),
left: parseFloat( that.element.css( "left" ) )
};
if ( pr && pr.length ) {
$( pr[ 0 ] ).css( { width: data.width, height: data.height } );
}
// Propagating resize, and updating values for each animation step
that._updateCache( data );
that._propagate( "resize", event );
}
}
);
}
} );
$.ui.plugin.add( "resizable", "containment", {
start: function() {
var element, p, co, ch, cw, width, height,
that = $( this ).resizable( "instance" ),
o = that.options,
el = that.element,
oc = o.containment,
ce = ( oc instanceof $ ) ?
oc.get( 0 ) :
( /parent/.test( oc ) ) ? el.parent().get( 0 ) : oc;
if ( !ce ) {
return;
}
that.containerElement = $( ce );
if ( /document/.test( oc ) || oc === document ) {
that.containerOffset = {
left: 0,
top: 0
};
that.containerPosition = {
left: 0,
top: 0
};
that.parentData = {
element: $( document ),
left: 0,
top: 0,
width: $( document ).width(),
height: $( document ).height() || document.body.parentNode.scrollHeight
};
} else {
element = $( ce );
p = [];
$( [ "Top", "Right", "Left", "Bottom" ] ).each( function( i, name ) {
p[ i ] = that._num( element.css( "padding" + name ) );
} );
that.containerOffset = element.offset();
that.containerPosition = element.position();
that.containerSize = {
height: ( element.innerHeight() - p[ 3 ] ),
width: ( element.innerWidth() - p[ 1 ] )
};
co = that.containerOffset;
ch = that.containerSize.height;
cw = that.containerSize.width;
width = ( that._hasScroll ( ce, "left" ) ? ce.scrollWidth : cw );
height = ( that._hasScroll ( ce ) ? ce.scrollHeight : ch ) ;
that.parentData = {
element: ce,
left: co.left,
top: co.top,
width: width,
height: height
};
}
},
resize: function( event ) {
var woset, hoset, isParent, isOffsetRelative,
that = $( this ).resizable( "instance" ),
o = that.options,
co = that.containerOffset,
cp = that.position,
pRatio = that._aspectRatio || event.shiftKey,
cop = {
top: 0,
left: 0
},
ce = that.containerElement,
continueResize = true;
if ( ce[ 0 ] !== document && ( /static/ ).test( ce.css( "position" ) ) ) {
cop = co;
}
if ( cp.left < ( that._helper ? co.left : 0 ) ) {
that.size.width = that.size.width +
( that._helper ?
( that.position.left - co.left ) :
( that.position.left - cop.left ) );
if ( pRatio ) {
that.size.height = that.size.width / that.aspectRatio;
continueResize = false;
}
that.position.left = o.helper ? co.left : 0;
}
if ( cp.top < ( that._helper ? co.top : 0 ) ) {
that.size.height = that.size.height +
( that._helper ?
( that.position.top - co.top ) :
that.position.top );
if ( pRatio ) {
that.size.width = that.size.height * that.aspectRatio;
continueResize = false;
}
that.position.top = that._helper ? co.top : 0;
}
isParent = that.containerElement.get( 0 ) === that.element.parent().get( 0 );
isOffsetRelative = /relative|absolute/.test( that.containerElement.css( "position" ) );
if ( isParent && isOffsetRelative ) {
that.offset.left = that.parentData.left + that.position.left;
that.offset.top = that.parentData.top + that.position.top;
} else {
that.offset.left = that.element.offset().left;
that.offset.top = that.element.offset().top;
}
woset = Math.abs( that.sizeDiff.width +
( that._helper ?
that.offset.left - cop.left :
( that.offset.left - co.left ) ) );
hoset = Math.abs( that.sizeDiff.height +
( that._helper ?
that.offset.top - cop.top :
( that.offset.top - co.top ) ) );
if ( woset + that.size.width >= that.parentData.width ) {
that.size.width = that.parentData.width - woset;
if ( pRatio ) {
that.size.height = that.size.width / that.aspectRatio;
continueResize = false;
}
}
if ( hoset + that.size.height >= that.parentData.height ) {
that.size.height = that.parentData.height - hoset;
if ( pRatio ) {
that.size.width = that.size.height * that.aspectRatio;
continueResize = false;
}
}
if ( !continueResize ) {
that.position.left = that.prevPosition.left;
that.position.top = that.prevPosition.top;
that.size.width = that.prevSize.width;
that.size.height = that.prevSize.height;
}
},
stop: function() {
var that = $( this ).resizable( "instance" ),
o = that.options,
co = that.containerOffset,
cop = that.containerPosition,
ce = that.containerElement,
helper = $( that.helper ),
ho = helper.offset(),
w = helper.outerWidth() - that.sizeDiff.width,
h = helper.outerHeight() - that.sizeDiff.height;
if ( that._helper && !o.animate && ( /relative/ ).test( ce.css( "position" ) ) ) {
$( this ).css( {
left: ho.left - cop.left - co.left,
width: w,
height: h
} );
}
if ( that._helper && !o.animate && ( /static/ ).test( ce.css( "position" ) ) ) {
$( this ).css( {
left: ho.left - cop.left - co.left,
width: w,
height: h
} );
}
}
} );
$.ui.plugin.add( "resizable", "alsoResize", {
start: function() {
var that = $( this ).resizable( "instance" ),
o = that.options;
$( o.alsoResize ).each( function() {
var el = $( this );
el.data( "ui-resizable-alsoresize", {
width: parseFloat( el.width() ), height: parseFloat( el.height() ),
left: parseFloat( el.css( "left" ) ), top: parseFloat( el.css( "top" ) )
} );
} );
},
resize: function( event, ui ) {
var that = $( this ).resizable( "instance" ),
o = that.options,
os = that.originalSize,
op = that.originalPosition,
delta = {
height: ( that.size.height - os.height ) || 0,
width: ( that.size.width - os.width ) || 0,
top: ( that.position.top - op.top ) || 0,
left: ( that.position.left - op.left ) || 0
};
$( o.alsoResize ).each( function() {
var el = $( this ), start = $( this ).data( "ui-resizable-alsoresize" ), style = {},
css = el.parents( ui.originalElement[ 0 ] ).length ?
[ "width", "height" ] :
[ "width", "height", "top", "left" ];
$.each( css, function( i, prop ) {
var sum = ( start[ prop ] || 0 ) + ( delta[ prop ] || 0 );
if ( sum && sum >= 0 ) {
style[ prop ] = sum || null;
}
} );
el.css( style );
} );
},
stop: function() {
$( this ).removeData( "ui-resizable-alsoresize" );
}
} );
$.ui.plugin.add( "resizable", "ghost", {
start: function() {
var that = $( this ).resizable( "instance" ), cs = that.size;
that.ghost = that.originalElement.clone();
that.ghost.css( {
opacity: 0.25,
display: "block",
position: "relative",
height: cs.height,
width: cs.width,
margin: 0,
left: 0,
top: 0
} );
that._addClass( that.ghost, "ui-resizable-ghost" );
// DEPRECATED
// TODO: remove after 1.12
if ( $.uiBackCompat !== false && typeof that.options.ghost === "string" ) {
// Ghost option
that.ghost.addClass( this.options.ghost );
}
that.ghost.appendTo( that.helper );
},
resize: function() {
var that = $( this ).resizable( "instance" );
if ( that.ghost ) {
that.ghost.css( {
position: "relative",
height: that.size.height,
width: that.size.width
} );
}
},
stop: function() {
var that = $( this ).resizable( "instance" );
if ( that.ghost && that.helper ) {
that.helper.get( 0 ).removeChild( that.ghost.get( 0 ) );
}
}
} );
$.ui.plugin.add( "resizable", "grid", {
resize: function() {
var outerDimensions,
that = $( this ).resizable( "instance" ),
o = that.options,
cs = that.size,
os = that.originalSize,
op = that.originalPosition,
a = that.axis,
grid = typeof o.grid === "number" ? [ o.grid, o.grid ] : o.grid,
gridX = ( grid[ 0 ] || 1 ),
gridY = ( grid[ 1 ] || 1 ),
ox = Math.round( ( cs.width - os.width ) / gridX ) * gridX,
oy = Math.round( ( cs.height - os.height ) / gridY ) * gridY,
newWidth = os.width + ox,
newHeight = os.height + oy,
isMaxWidth = o.maxWidth && ( o.maxWidth < newWidth ),
isMaxHeight = o.maxHeight && ( o.maxHeight < newHeight ),
isMinWidth = o.minWidth && ( o.minWidth > newWidth ),
isMinHeight = o.minHeight && ( o.minHeight > newHeight );
o.grid = grid;
if ( isMinWidth ) {
newWidth += gridX;
}
if ( isMinHeight ) {
newHeight += gridY;
}
if ( isMaxWidth ) {
newWidth -= gridX;
}
if ( isMaxHeight ) {
newHeight -= gridY;
}
if ( /^(se|s|e)$/.test( a ) ) {
that.size.width = newWidth;
that.size.height = newHeight;
} else if ( /^(ne)$/.test( a ) ) {
that.size.width = newWidth;
that.size.height = newHeight;
that.position.top = op.top - oy;
} else if ( /^(sw)$/.test( a ) ) {
that.size.width = newWidth;
that.size.height = newHeight;
that.position.left = op.left - ox;
} else {
if ( newHeight - gridY <= 0 || newWidth - gridX <= 0 ) {
outerDimensions = that._getPaddingPlusBorderDimensions( this );
}
if ( newHeight - gridY > 0 ) {
that.size.height = newHeight;
that.position.top = op.top - oy;
} else {
newHeight = gridY - outerDimensions.height;
that.size.height = newHeight;
that.position.top = op.top + os.height - newHeight;
}
if ( newWidth - gridX > 0 ) {
that.size.width = newWidth;
that.position.left = op.left - ox;
} else {
newWidth = gridX - outerDimensions.width;
that.size.width = newWidth;
that.position.left = op.left + os.width - newWidth;
}
}
}
} );
var widgetsResizable = $.ui.resizable;
/*!
* jQuery UI Dialog 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Dialog
//>>group: Widgets
//>>description: Displays customizable dialog windows.
//>>docs: http://api.jqueryui.com/dialog/
//>>demos: http://jqueryui.com/dialog/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/dialog.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.dialog", {
version: "1.12.1",
options: {
appendTo: "body",
autoOpen: true,
buttons: [],
classes: {
"ui-dialog": "ui-corner-all",
"ui-dialog-titlebar": "ui-corner-all"
},
closeOnEscape: true,
closeText: "Close",
draggable: true,
hide: null,
height: "auto",
maxHeight: null,
maxWidth: null,
minHeight: 150,
minWidth: 150,
modal: false,
position: {
my: "center",
at: "center",
of: window,
collision: "fit",
// Ensure the titlebar is always visible
using: function( pos ) {
var topOffset = $( this ).css( pos ).offset().top;
if ( topOffset < 0 ) {
$( this ).css( "top", pos.top - topOffset );
}
}
},
resizable: true,
show: null,
title: null,
width: 300,
// Callbacks
beforeClose: null,
close: null,
drag: null,
dragStart: null,
dragStop: null,
focus: null,
open: null,
resize: null,
resizeStart: null,
resizeStop: null
},
sizeRelatedOptions: {
buttons: true,
height: true,
maxHeight: true,
maxWidth: true,
minHeight: true,
minWidth: true,
width: true
},
resizableRelatedOptions: {
maxHeight: true,
maxWidth: true,
minHeight: true,
minWidth: true
},
_create: function() {
this.originalCss = {
display: this.element[ 0 ].style.display,
width: this.element[ 0 ].style.width,
minHeight: this.element[ 0 ].style.minHeight,
maxHeight: this.element[ 0 ].style.maxHeight,
height: this.element[ 0 ].style.height
};
this.originalPosition = {
parent: this.element.parent(),
index: this.element.parent().children().index( this.element )
};
this.originalTitle = this.element.attr( "title" );
if ( this.options.title == null && this.originalTitle != null ) {
this.options.title = this.originalTitle;
}
// Dialogs can't be disabled
if ( this.options.disabled ) {
this.options.disabled = false;
}
this._createWrapper();
this.element
.show()
.removeAttr( "title" )
.appendTo( this.uiDialog );
this._addClass( "ui-dialog-content", "ui-widget-content" );
this._createTitlebar();
this._createButtonPane();
if ( this.options.draggable && $.fn.draggable ) {
this._makeDraggable();
}
if ( this.options.resizable && $.fn.resizable ) {
this._makeResizable();
}
this._isOpen = false;
this._trackFocus();
},
_init: function() {
if ( this.options.autoOpen ) {
this.open();
}
},
_appendTo: function() {
var element = this.options.appendTo;
if ( element && ( element.jquery || element.nodeType ) ) {
return $( element );
}
return this.document.find( element || "body" ).eq( 0 );
},
_destroy: function() {
var next,
originalPosition = this.originalPosition;
this._untrackInstance();
this._destroyOverlay();
this.element
.removeUniqueId()
.css( this.originalCss )
// Without detaching first, the following becomes really slow
.detach();
this.uiDialog.remove();
if ( this.originalTitle ) {
this.element.attr( "title", this.originalTitle );
}
next = originalPosition.parent.children().eq( originalPosition.index );
// Don't try to place the dialog next to itself (#8613)
if ( next.length && next[ 0 ] !== this.element[ 0 ] ) {
next.before( this.element );
} else {
originalPosition.parent.append( this.element );
}
},
widget: function() {
return this.uiDialog;
},
disable: $.noop,
enable: $.noop,
close: function( event ) {
var that = this;
if ( !this._isOpen || this._trigger( "beforeClose", event ) === false ) {
return;
}
this._isOpen = false;
this._focusedElement = null;
this._destroyOverlay();
this._untrackInstance();
if ( !this.opener.filter( ":focusable" ).trigger( "focus" ).length ) {
// Hiding a focused element doesn't trigger blur in WebKit
// so in case we have nothing to focus on, explicitly blur the active element
// https://bugs.webkit.org/show_bug.cgi?id=47182
$.ui.safeBlur( $.ui.safeActiveElement( this.document[ 0 ] ) );
}
this._hide( this.uiDialog, this.options.hide, function() {
that._trigger( "close", event );
} );
},
isOpen: function() {
return this._isOpen;
},
moveToTop: function() {
this._moveToTop();
},
_moveToTop: function( event, silent ) {
var moved = false,
zIndices = this.uiDialog.siblings( ".ui-front:visible" ).map( function() {
return +$( this ).css( "z-index" );
} ).get(),
zIndexMax = Math.max.apply( null, zIndices );
if ( zIndexMax >= +this.uiDialog.css( "z-index" ) ) {
this.uiDialog.css( "z-index", zIndexMax + 1 );
moved = true;
}
if ( moved && !silent ) {
this._trigger( "focus", event );
}
return moved;
},
open: function() {
var that = this;
if ( this._isOpen ) {
if ( this._moveToTop() ) {
this._focusTabbable();
}
return;
}
this._isOpen = true;
this.opener = $( $.ui.safeActiveElement( this.document[ 0 ] ) );
this._size();
this._position();
this._createOverlay();
this._moveToTop( null, true );
// Ensure the overlay is moved to the top with the dialog, but only when
// opening. The overlay shouldn't move after the dialog is open so that
// modeless dialogs opened after the modal dialog stack properly.
if ( this.overlay ) {
this.overlay.css( "z-index", this.uiDialog.css( "z-index" ) - 1 );
}
this._show( this.uiDialog, this.options.show, function() {
that._focusTabbable();
that._trigger( "focus" );
} );
// Track the dialog immediately upon openening in case a focus event
// somehow occurs outside of the dialog before an element inside the
// dialog is focused (#10152)
this._makeFocusTarget();
this._trigger( "open" );
},
_focusTabbable: function() {
// Set focus to the first match:
// 1. An element that was focused previously
// 2. First element inside the dialog matching [autofocus]
// 3. Tabbable element inside the content element
// 4. Tabbable element inside the buttonpane
// 5. The close button
// 6. The dialog itself
var hasFocus = this._focusedElement;
if ( !hasFocus ) {
hasFocus = this.element.find( "[autofocus]" );
}
if ( !hasFocus.length ) {
hasFocus = this.element.find( ":tabbable" );
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialogButtonPane.find( ":tabbable" );
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialogTitlebarClose.filter( ":tabbable" );
}
if ( !hasFocus.length ) {
hasFocus = this.uiDialog;
}
hasFocus.eq( 0 ).trigger( "focus" );
},
_keepFocus: function( event ) {
function checkFocus() {
var activeElement = $.ui.safeActiveElement( this.document[ 0 ] ),
isActive = this.uiDialog[ 0 ] === activeElement ||
$.contains( this.uiDialog[ 0 ], activeElement );
if ( !isActive ) {
this._focusTabbable();
}
}
event.preventDefault();
checkFocus.call( this );
// support: IE
// IE <= 8 doesn't prevent moving focus even with event.preventDefault()
// so we check again later
this._delay( checkFocus );
},
_createWrapper: function() {
this.uiDialog = $( "<div>" )
.hide()
.attr( {
// Setting tabIndex makes the div focusable
tabIndex: -1,
role: "dialog"
} )
.appendTo( this._appendTo() );
this._addClass( this.uiDialog, "ui-dialog", "ui-widget ui-widget-content ui-front" );
this._on( this.uiDialog, {
keydown: function( event ) {
if ( this.options.closeOnEscape && !event.isDefaultPrevented() && event.keyCode &&
event.keyCode === $.ui.keyCode.ESCAPE ) {
event.preventDefault();
this.close( event );
return;
}
// Prevent tabbing out of dialogs
if ( event.keyCode !== $.ui.keyCode.TAB || event.isDefaultPrevented() ) {
return;
}
var tabbables = this.uiDialog.find( ":tabbable" ),
first = tabbables.filter( ":first" ),
last = tabbables.filter( ":last" );
if ( ( event.target === last[ 0 ] || event.target === this.uiDialog[ 0 ] ) &&
!event.shiftKey ) {
this._delay( function() {
first.trigger( "focus" );
} );
event.preventDefault();
} else if ( ( event.target === first[ 0 ] ||
event.target === this.uiDialog[ 0 ] ) && event.shiftKey ) {
this._delay( function() {
last.trigger( "focus" );
} );
event.preventDefault();
}
},
mousedown: function( event ) {
if ( this._moveToTop( event ) ) {
this._focusTabbable();
}
}
} );
// We assume that any existing aria-describedby attribute means
// that the dialog content is marked up properly
// otherwise we brute force the content as the description
if ( !this.element.find( "[aria-describedby]" ).length ) {
this.uiDialog.attr( {
"aria-describedby": this.element.uniqueId().attr( "id" )
} );
}
},
_createTitlebar: function() {
var uiDialogTitle;
this.uiDialogTitlebar = $( "<div>" );
this._addClass( this.uiDialogTitlebar,
"ui-dialog-titlebar", "ui-widget-header ui-helper-clearfix" );
this._on( this.uiDialogTitlebar, {
mousedown: function( event ) {
// Don't prevent click on close button (#8838)
// Focusing a dialog that is partially scrolled out of view
// causes the browser to scroll it into view, preventing the click event
if ( !$( event.target ).closest( ".ui-dialog-titlebar-close" ) ) {
// Dialog isn't getting focus when dragging (#8063)
this.uiDialog.trigger( "focus" );
}
}
} );
// Support: IE
// Use type="button" to prevent enter keypresses in textboxes from closing the
// dialog in IE (#9312)
this.uiDialogTitlebarClose = $( "<button type='button'></button>" )
.button( {
label: $( "<a>" ).text( this.options.closeText ).html(),
icon: "ui-icon-closethick",
showLabel: false
} )
.appendTo( this.uiDialogTitlebar );
this._addClass( this.uiDialogTitlebarClose, "ui-dialog-titlebar-close" );
this._on( this.uiDialogTitlebarClose, {
click: function( event ) {
event.preventDefault();
this.close( event );
}
} );
uiDialogTitle = $( "<span>" ).uniqueId().prependTo( this.uiDialogTitlebar );
this._addClass( uiDialogTitle, "ui-dialog-title" );
this._title( uiDialogTitle );
this.uiDialogTitlebar.prependTo( this.uiDialog );
this.uiDialog.attr( {
"aria-labelledby": uiDialogTitle.attr( "id" )
} );
},
_title: function( title ) {
if ( this.options.title ) {
title.text( this.options.title );
} else {
title.html( " " );
}
},
_createButtonPane: function() {
this.uiDialogButtonPane = $( "<div>" );
this._addClass( this.uiDialogButtonPane, "ui-dialog-buttonpane",
"ui-widget-content ui-helper-clearfix" );
this.uiButtonSet = $( "<div>" )
.appendTo( this.uiDialogButtonPane );
this._addClass( this.uiButtonSet, "ui-dialog-buttonset" );
this._createButtons();
},
_createButtons: function() {
var that = this,
buttons = this.options.buttons;
// If we already have a button pane, remove it
this.uiDialogButtonPane.remove();
this.uiButtonSet.empty();
if ( $.isEmptyObject( buttons ) || ( $.isArray( buttons ) && !buttons.length ) ) {
this._removeClass( this.uiDialog, "ui-dialog-buttons" );
return;
}
$.each( buttons, function( name, props ) {
var click, buttonOptions;
props = $.isFunction( props ) ?
{ click: props, text: name } :
props;
// Default to a non-submitting button
props = $.extend( { type: "button" }, props );
// Change the context for the click callback to be the main element
click = props.click;
buttonOptions = {
icon: props.icon,
iconPosition: props.iconPosition,
showLabel: props.showLabel,
// Deprecated options
icons: props.icons,
text: props.text
};
delete props.click;
delete props.icon;
delete props.iconPosition;
delete props.showLabel;
// Deprecated options
delete props.icons;
if ( typeof props.text === "boolean" ) {
delete props.text;
}
$( "<button></button>", props )
.button( buttonOptions )
.appendTo( that.uiButtonSet )
.on( "click", function() {
click.apply( that.element[ 0 ], arguments );
} );
} );
this._addClass( this.uiDialog, "ui-dialog-buttons" );
this.uiDialogButtonPane.appendTo( this.uiDialog );
},
_makeDraggable: function() {
var that = this,
options = this.options;
function filteredUi( ui ) {
return {
position: ui.position,
offset: ui.offset
};
}
this.uiDialog.draggable( {
cancel: ".ui-dialog-content, .ui-dialog-titlebar-close",
handle: ".ui-dialog-titlebar",
containment: "document",
start: function( event, ui ) {
that._addClass( $( this ), "ui-dialog-dragging" );
that._blockFrames();
that._trigger( "dragStart", event, filteredUi( ui ) );
},
drag: function( event, ui ) {
that._trigger( "drag", event, filteredUi( ui ) );
},
stop: function( event, ui ) {
var left = ui.offset.left - that.document.scrollLeft(),
top = ui.offset.top - that.document.scrollTop();
options.position = {
my: "left top",
at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
"top" + ( top >= 0 ? "+" : "" ) + top,
of: that.window
};
that._removeClass( $( this ), "ui-dialog-dragging" );
that._unblockFrames();
that._trigger( "dragStop", event, filteredUi( ui ) );
}
} );
},
_makeResizable: function() {
var that = this,
options = this.options,
handles = options.resizable,
// .ui-resizable has position: relative defined in the stylesheet
// but dialogs have to use absolute or fixed positioning
position = this.uiDialog.css( "position" ),
resizeHandles = typeof handles === "string" ?
handles :
"n,e,s,w,se,sw,ne,nw";
function filteredUi( ui ) {
return {
originalPosition: ui.originalPosition,
originalSize: ui.originalSize,
position: ui.position,
size: ui.size
};
}
this.uiDialog.resizable( {
cancel: ".ui-dialog-content",
containment: "document",
alsoResize: this.element,
maxWidth: options.maxWidth,
maxHeight: options.maxHeight,
minWidth: options.minWidth,
minHeight: this._minHeight(),
handles: resizeHandles,
start: function( event, ui ) {
that._addClass( $( this ), "ui-dialog-resizing" );
that._blockFrames();
that._trigger( "resizeStart", event, filteredUi( ui ) );
},
resize: function( event, ui ) {
that._trigger( "resize", event, filteredUi( ui ) );
},
stop: function( event, ui ) {
var offset = that.uiDialog.offset(),
left = offset.left - that.document.scrollLeft(),
top = offset.top - that.document.scrollTop();
options.height = that.uiDialog.height();
options.width = that.uiDialog.width();
options.position = {
my: "left top",
at: "left" + ( left >= 0 ? "+" : "" ) + left + " " +
"top" + ( top >= 0 ? "+" : "" ) + top,
of: that.window
};
that._removeClass( $( this ), "ui-dialog-resizing" );
that._unblockFrames();
that._trigger( "resizeStop", event, filteredUi( ui ) );
}
} )
.css( "position", position );
},
_trackFocus: function() {
this._on( this.widget(), {
focusin: function( event ) {
this._makeFocusTarget();
this._focusedElement = $( event.target );
}
} );
},
_makeFocusTarget: function() {
this._untrackInstance();
this._trackingInstances().unshift( this );
},
_untrackInstance: function() {
var instances = this._trackingInstances(),
exists = $.inArray( this, instances );
if ( exists !== -1 ) {
instances.splice( exists, 1 );
}
},
_trackingInstances: function() {
var instances = this.document.data( "ui-dialog-instances" );
if ( !instances ) {
instances = [];
this.document.data( "ui-dialog-instances", instances );
}
return instances;
},
_minHeight: function() {
var options = this.options;
return options.height === "auto" ?
options.minHeight :
Math.min( options.minHeight, options.height );
},
_position: function() {
// Need to show the dialog to get the actual offset in the position plugin
var isVisible = this.uiDialog.is( ":visible" );
if ( !isVisible ) {
this.uiDialog.show();
}
this.uiDialog.position( this.options.position );
if ( !isVisible ) {
this.uiDialog.hide();
}
},
_setOptions: function( options ) {
var that = this,
resize = false,
resizableOptions = {};
$.each( options, function( key, value ) {
that._setOption( key, value );
if ( key in that.sizeRelatedOptions ) {
resize = true;
}
if ( key in that.resizableRelatedOptions ) {
resizableOptions[ key ] = value;
}
} );
if ( resize ) {
this._size();
this._position();
}
if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
this.uiDialog.resizable( "option", resizableOptions );
}
},
_setOption: function( key, value ) {
var isDraggable, isResizable,
uiDialog = this.uiDialog;
if ( key === "disabled" ) {
return;
}
this._super( key, value );
if ( key === "appendTo" ) {
this.uiDialog.appendTo( this._appendTo() );
}
if ( key === "buttons" ) {
this._createButtons();
}
if ( key === "closeText" ) {
this.uiDialogTitlebarClose.button( {
// Ensure that we always pass a string
label: $( "<a>" ).text( "" + this.options.closeText ).html()
} );
}
if ( key === "draggable" ) {
isDraggable = uiDialog.is( ":data(ui-draggable)" );
if ( isDraggable && !value ) {
uiDialog.draggable( "destroy" );
}
if ( !isDraggable && value ) {
this._makeDraggable();
}
}
if ( key === "position" ) {
this._position();
}
if ( key === "resizable" ) {
// currently resizable, becoming non-resizable
isResizable = uiDialog.is( ":data(ui-resizable)" );
if ( isResizable && !value ) {
uiDialog.resizable( "destroy" );
}
// Currently resizable, changing handles
if ( isResizable && typeof value === "string" ) {
uiDialog.resizable( "option", "handles", value );
}
// Currently non-resizable, becoming resizable
if ( !isResizable && value !== false ) {
this._makeResizable();
}
}
if ( key === "title" ) {
this._title( this.uiDialogTitlebar.find( ".ui-dialog-title" ) );
}
},
_size: function() {
// If the user has resized the dialog, the .ui-dialog and .ui-dialog-content
// divs will both have width and height set, so we need to reset them
var nonContentHeight, minContentHeight, maxContentHeight,
options = this.options;
// Reset content sizing
this.element.show().css( {
width: "auto",
minHeight: 0,
maxHeight: "none",
height: 0
} );
if ( options.minWidth > options.width ) {
options.width = options.minWidth;
}
// Reset wrapper sizing
// determine the height of all the non-content elements
nonContentHeight = this.uiDialog.css( {
height: "auto",
width: options.width
} )
.outerHeight();
minContentHeight = Math.max( 0, options.minHeight - nonContentHeight );
maxContentHeight = typeof options.maxHeight === "number" ?
Math.max( 0, options.maxHeight - nonContentHeight ) :
"none";
if ( options.height === "auto" ) {
this.element.css( {
minHeight: minContentHeight,
maxHeight: maxContentHeight,
height: "auto"
} );
} else {
this.element.height( Math.max( 0, options.height - nonContentHeight ) );
}
if ( this.uiDialog.is( ":data(ui-resizable)" ) ) {
this.uiDialog.resizable( "option", "minHeight", this._minHeight() );
}
},
_blockFrames: function() {
this.iframeBlocks = this.document.find( "iframe" ).map( function() {
var iframe = $( this );
return $( "<div>" )
.css( {
position: "absolute",
width: iframe.outerWidth(),
height: iframe.outerHeight()
} )
.appendTo( iframe.parent() )
.offset( iframe.offset() )[ 0 ];
} );
},
_unblockFrames: function() {
if ( this.iframeBlocks ) {
this.iframeBlocks.remove();
delete this.iframeBlocks;
}
},
_allowInteraction: function( event ) {
if ( $( event.target ).closest( ".ui-dialog" ).length ) {
return true;
}
// TODO: Remove hack when datepicker implements
// the .ui-front logic (#8989)
return !!$( event.target ).closest( ".ui-datepicker" ).length;
},
_createOverlay: function() {
if ( !this.options.modal ) {
return;
}
// We use a delay in case the overlay is created from an
// event that we're going to be cancelling (#2804)
var isOpening = true;
this._delay( function() {
isOpening = false;
} );
if ( !this.document.data( "ui-dialog-overlays" ) ) {
// Prevent use of anchors and inputs
// Using _on() for an event handler shared across many instances is
// safe because the dialogs stack and must be closed in reverse order
this._on( this.document, {
focusin: function( event ) {
if ( isOpening ) {
return;
}
if ( !this._allowInteraction( event ) ) {
event.preventDefault();
this._trackingInstances()[ 0 ]._focusTabbable();
}
}
} );
}
this.overlay = $( "<div>" )
.appendTo( this._appendTo() );
this._addClass( this.overlay, null, "ui-widget-overlay ui-front" );
this._on( this.overlay, {
mousedown: "_keepFocus"
} );
this.document.data( "ui-dialog-overlays",
( this.document.data( "ui-dialog-overlays" ) || 0 ) + 1 );
},
_destroyOverlay: function() {
if ( !this.options.modal ) {
return;
}
if ( this.overlay ) {
var overlays = this.document.data( "ui-dialog-overlays" ) - 1;
if ( !overlays ) {
this._off( this.document, "focusin" );
this.document.removeData( "ui-dialog-overlays" );
} else {
this.document.data( "ui-dialog-overlays", overlays );
}
this.overlay.remove();
this.overlay = null;
}
}
} );
// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for dialogClass option
$.widget( "ui.dialog", $.ui.dialog, {
options: {
dialogClass: ""
},
_createWrapper: function() {
this._super();
this.uiDialog.addClass( this.options.dialogClass );
},
_setOption: function( key, value ) {
if ( key === "dialogClass" ) {
this.uiDialog
.removeClass( this.options.dialogClass )
.addClass( value );
}
this._superApply( arguments );
}
} );
}
var widgetsDialog = $.ui.dialog;
/*!
* jQuery UI Droppable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Droppable
//>>group: Interactions
//>>description: Enables drop targets for draggable elements.
//>>docs: http://api.jqueryui.com/droppable/
//>>demos: http://jqueryui.com/droppable/
$.widget( "ui.droppable", {
version: "1.12.1",
widgetEventPrefix: "drop",
options: {
accept: "*",
addClasses: true,
greedy: false,
scope: "default",
tolerance: "intersect",
// Callbacks
activate: null,
deactivate: null,
drop: null,
out: null,
over: null
},
_create: function() {
var proportions,
o = this.options,
accept = o.accept;
this.isover = false;
this.isout = true;
this.accept = $.isFunction( accept ) ? accept : function( d ) {
return d.is( accept );
};
this.proportions = function( /* valueToWrite */ ) {
if ( arguments.length ) {
// Store the droppable's proportions
proportions = arguments[ 0 ];
} else {
// Retrieve or derive the droppable's proportions
return proportions ?
proportions :
proportions = {
width: this.element[ 0 ].offsetWidth,
height: this.element[ 0 ].offsetHeight
};
}
};
this._addToManager( o.scope );
o.addClasses && this._addClass( "ui-droppable" );
},
_addToManager: function( scope ) {
// Add the reference and positions to the manager
$.ui.ddmanager.droppables[ scope ] = $.ui.ddmanager.droppables[ scope ] || [];
$.ui.ddmanager.droppables[ scope ].push( this );
},
_splice: function( drop ) {
var i = 0;
for ( ; i < drop.length; i++ ) {
if ( drop[ i ] === this ) {
drop.splice( i, 1 );
}
}
},
_destroy: function() {
var drop = $.ui.ddmanager.droppables[ this.options.scope ];
this._splice( drop );
},
_setOption: function( key, value ) {
if ( key === "accept" ) {
this.accept = $.isFunction( value ) ? value : function( d ) {
return d.is( value );
};
} else if ( key === "scope" ) {
var drop = $.ui.ddmanager.droppables[ this.options.scope ];
this._splice( drop );
this._addToManager( value );
}
this._super( key, value );
},
_activate: function( event ) {
var draggable = $.ui.ddmanager.current;
this._addActiveClass();
if ( draggable ) {
this._trigger( "activate", event, this.ui( draggable ) );
}
},
_deactivate: function( event ) {
var draggable = $.ui.ddmanager.current;
this._removeActiveClass();
if ( draggable ) {
this._trigger( "deactivate", event, this.ui( draggable ) );
}
},
_over: function( event ) {
var draggable = $.ui.ddmanager.current;
// Bail if draggable and droppable are same element
if ( !draggable || ( draggable.currentItem ||
draggable.element )[ 0 ] === this.element[ 0 ] ) {
return;
}
if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
draggable.element ) ) ) {
this._addHoverClass();
this._trigger( "over", event, this.ui( draggable ) );
}
},
_out: function( event ) {
var draggable = $.ui.ddmanager.current;
// Bail if draggable and droppable are same element
if ( !draggable || ( draggable.currentItem ||
draggable.element )[ 0 ] === this.element[ 0 ] ) {
return;
}
if ( this.accept.call( this.element[ 0 ], ( draggable.currentItem ||
draggable.element ) ) ) {
this._removeHoverClass();
this._trigger( "out", event, this.ui( draggable ) );
}
},
_drop: function( event, custom ) {
var draggable = custom || $.ui.ddmanager.current,
childrenIntersection = false;
// Bail if draggable and droppable are same element
if ( !draggable || ( draggable.currentItem ||
draggable.element )[ 0 ] === this.element[ 0 ] ) {
return false;
}
this.element
.find( ":data(ui-droppable)" )
.not( ".ui-draggable-dragging" )
.each( function() {
var inst = $( this ).droppable( "instance" );
if (
inst.options.greedy &&
!inst.options.disabled &&
inst.options.scope === draggable.options.scope &&
inst.accept.call(
inst.element[ 0 ], ( draggable.currentItem || draggable.element )
) &&
intersect(
draggable,
$.extend( inst, { offset: inst.element.offset() } ),
inst.options.tolerance, event
)
) {
childrenIntersection = true;
return false; }
} );
if ( childrenIntersection ) {
return false;
}
if ( this.accept.call( this.element[ 0 ],
( draggable.currentItem || draggable.element ) ) ) {
this._removeActiveClass();
this._removeHoverClass();
this._trigger( "drop", event, this.ui( draggable ) );
return this.element;
}
return false;
},
ui: function( c ) {
return {
draggable: ( c.currentItem || c.element ),
helper: c.helper,
position: c.position,
offset: c.positionAbs
};
},
// Extension points just to make backcompat sane and avoid duplicating logic
// TODO: Remove in 1.13 along with call to it below
_addHoverClass: function() {
this._addClass( "ui-droppable-hover" );
},
_removeHoverClass: function() {
this._removeClass( "ui-droppable-hover" );
},
_addActiveClass: function() {
this._addClass( "ui-droppable-active" );
},
_removeActiveClass: function() {
this._removeClass( "ui-droppable-active" );
}
} );
var intersect = $.ui.intersect = ( function() {
function isOverAxis( x, reference, size ) {
return ( x >= reference ) && ( x < ( reference + size ) );
}
return function( draggable, droppable, toleranceMode, event ) {
if ( !droppable.offset ) {
return false;
}
var x1 = ( draggable.positionAbs ||
draggable.position.absolute ).left + draggable.margins.left,
y1 = ( draggable.positionAbs ||
draggable.position.absolute ).top + draggable.margins.top,
x2 = x1 + draggable.helperProportions.width,
y2 = y1 + draggable.helperProportions.height,
l = droppable.offset.left,
t = droppable.offset.top,
r = l + droppable.proportions().width,
b = t + droppable.proportions().height;
switch ( toleranceMode ) {
case "fit":
return ( l <= x1 && x2 <= r && t <= y1 && y2 <= b );
case "intersect":
return ( l < x1 + ( draggable.helperProportions.width / 2 ) && // Right Half
x2 - ( draggable.helperProportions.width / 2 ) < r && // Left Half
t < y1 + ( draggable.helperProportions.height / 2 ) && // Bottom Half
y2 - ( draggable.helperProportions.height / 2 ) < b ); // Top Half
case "pointer":
return isOverAxis( event.pageY, t, droppable.proportions().height ) &&
isOverAxis( event.pageX, l, droppable.proportions().width );
case "touch":
return (
( y1 >= t && y1 <= b ) || // Top edge touching
( y2 >= t && y2 <= b ) || // Bottom edge touching
( y1 < t && y2 > b ) // Surrounded vertically
) && (
( x1 >= l && x1 <= r ) || // Left edge touching
( x2 >= l && x2 <= r ) || // Right edge touching
( x1 < l && x2 > r ) // Surrounded horizontally
);
default:
return false;
}
};
} )();
/*
This manager tracks offsets of draggables and droppables
*/
$.ui.ddmanager = {
current: null,
droppables: { "default": [] },
prepareOffsets: function( t, event ) {
var i, j,
m = $.ui.ddmanager.droppables[ t.options.scope ] || [],
type = event ? event.type : null, // workaround for #2317
list = ( t.currentItem || t.element ).find( ":data(ui-droppable)" ).addBack();
droppablesLoop: for ( i = 0; i < m.length; i++ ) {
// No disabled and non-accepted
if ( m[ i ].options.disabled || ( t && !m[ i ].accept.call( m[ i ].element[ 0 ],
( t.currentItem || t.element ) ) ) ) {
continue;
}
// Filter out elements in the current dragged item
for ( j = 0; j < list.length; j++ ) {
if ( list[ j ] === m[ i ].element[ 0 ] ) {
m[ i ].proportions().height = 0;
continue droppablesLoop;
}
}
m[ i ].visible = m[ i ].element.css( "display" ) !== "none";
if ( !m[ i ].visible ) {
continue;
}
// Activate the droppable if used directly from draggables
if ( type === "mousedown" ) {
m[ i ]._activate.call( m[ i ], event );
}
m[ i ].offset = m[ i ].element.offset();
m[ i ].proportions( {
width: m[ i ].element[ 0 ].offsetWidth,
height: m[ i ].element[ 0 ].offsetHeight
} );
}
},
drop: function( draggable, event ) {
var dropped = false;
// Create a copy of the droppables in case the list changes during the drop (#9116)
$.each( ( $.ui.ddmanager.droppables[ draggable.options.scope ] || [] ).slice(), function() {
if ( !this.options ) {
return;
}
if ( !this.options.disabled && this.visible &&
intersect( draggable, this, this.options.tolerance, event ) ) {
dropped = this._drop.call( this, event ) || dropped;
}
if ( !this.options.disabled && this.visible && this.accept.call( this.element[ 0 ],
( draggable.currentItem || draggable.element ) ) ) {
this.isout = true;
this.isover = false;
this._deactivate.call( this, event );
}
} );
return dropped;
},
dragStart: function( draggable, event ) {
// Listen for scrolling so that if the dragging causes scrolling the position of the
// droppables can be recalculated (see #5003)
draggable.element.parentsUntil( "body" ).on( "scroll.droppable", function() {
if ( !draggable.options.refreshPositions ) {
$.ui.ddmanager.prepareOffsets( draggable, event );
}
} );
},
drag: function( draggable, event ) {
// If you have a highly dynamic page, you might try this option. It renders positions
// every time you move the mouse.
if ( draggable.options.refreshPositions ) {
$.ui.ddmanager.prepareOffsets( draggable, event );
}
// Run through all droppables and check their positions based on specific tolerance options
$.each( $.ui.ddmanager.droppables[ draggable.options.scope ] || [], function() {
if ( this.options.disabled || this.greedyChild || !this.visible ) {
return;
}
var parentInstance, scope, parent,
intersects = intersect( draggable, this, this.options.tolerance, event ),
c = !intersects && this.isover ?
"isout" :
( intersects && !this.isover ? "isover" : null );
if ( !c ) {
return;
}
if ( this.options.greedy ) {
// find droppable parents with same scope
scope = this.options.scope;
parent = this.element.parents( ":data(ui-droppable)" ).filter( function() {
return $( this ).droppable( "instance" ).options.scope === scope;
} );
if ( parent.length ) {
parentInstance = $( parent[ 0 ] ).droppable( "instance" );
parentInstance.greedyChild = ( c === "isover" );
}
}
// We just moved into a greedy child
if ( parentInstance && c === "isover" ) {
parentInstance.isover = false;
parentInstance.isout = true;
parentInstance._out.call( parentInstance, event );
}
this[ c ] = true;
this[ c === "isout" ? "isover" : "isout" ] = false;
this[ c === "isover" ? "_over" : "_out" ].call( this, event );
// We just moved out of a greedy child
if ( parentInstance && c === "isout" ) {
parentInstance.isout = false;
parentInstance.isover = true;
parentInstance._over.call( parentInstance, event );
}
} );
},
dragStop: function( draggable, event ) {
draggable.element.parentsUntil( "body" ).off( "scroll.droppable" );
// Call prepareOffsets one final time since IE does not fire return scroll events when
// overflow was caused by drag (see #5003)
if ( !draggable.options.refreshPositions ) {
$.ui.ddmanager.prepareOffsets( draggable, event );
}
}
};
// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for activeClass and hoverClass options
$.widget( "ui.droppable", $.ui.droppable, {
options: {
hoverClass: false,
activeClass: false
},
_addActiveClass: function() {
this._super();
if ( this.options.activeClass ) {
this.element.addClass( this.options.activeClass );
}
},
_removeActiveClass: function() {
this._super();
if ( this.options.activeClass ) {
this.element.removeClass( this.options.activeClass );
}
},
_addHoverClass: function() {
this._super();
if ( this.options.hoverClass ) {
this.element.addClass( this.options.hoverClass );
}
},
_removeHoverClass: function() {
this._super();
if ( this.options.hoverClass ) {
this.element.removeClass( this.options.hoverClass );
}
}
} );
}
var widgetsDroppable = $.ui.droppable;
/*!
* jQuery UI Progressbar 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Progressbar
//>>group: Widgets
// jscs:disable maximumLineLength
//>>description: Displays a status indicator for loading state, standard percentage, and other progress indicators.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/progressbar/
//>>demos: http://jqueryui.com/progressbar/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/progressbar.css
//>>css.theme: ../../themes/base/theme.css
var widgetsProgressbar = $.widget( "ui.progressbar", {
version: "1.12.1",
options: {
classes: {
"ui-progressbar": "ui-corner-all",
"ui-progressbar-value": "ui-corner-left",
"ui-progressbar-complete": "ui-corner-right"
},
max: 100,
value: 0,
change: null,
complete: null
},
min: 0,
_create: function() {
// Constrain initial value
this.oldValue = this.options.value = this._constrainedValue();
this.element.attr( {
// Only set static values; aria-valuenow and aria-valuemax are
// set inside _refreshValue()
role: "progressbar",
"aria-valuemin": this.min
} );
this._addClass( "ui-progressbar", "ui-widget ui-widget-content" );
this.valueDiv = $( "<div>" ).appendTo( this.element );
this._addClass( this.valueDiv, "ui-progressbar-value", "ui-widget-header" );
this._refreshValue();
},
_destroy: function() {
this.element.removeAttr( "role aria-valuemin aria-valuemax aria-valuenow" );
this.valueDiv.remove();
},
value: function( newValue ) {
if ( newValue === undefined ) {
return this.options.value;
}
this.options.value = this._constrainedValue( newValue );
this._refreshValue();
},
_constrainedValue: function( newValue ) {
if ( newValue === undefined ) {
newValue = this.options.value;
}
this.indeterminate = newValue === false;
// Sanitize value
if ( typeof newValue !== "number" ) {
newValue = 0;
}
return this.indeterminate ? false :
Math.min( this.options.max, Math.max( this.min, newValue ) );
},
_setOptions: function( options ) {
// Ensure "value" option is set after other values (like max)
var value = options.value;
delete options.value;
this._super( options );
this.options.value = this._constrainedValue( value );
this._refreshValue();
},
_setOption: function( key, value ) {
if ( key === "max" ) {
// Don't allow a max less than min
value = Math.max( this.min, value );
}
this._super( key, value );
},
_setOptionDisabled: function( value ) {
this._super( value );
this.element.attr( "aria-disabled", value );
this._toggleClass( null, "ui-state-disabled", !!value );
},
_percentage: function() {
return this.indeterminate ?
100 :
100 * ( this.options.value - this.min ) / ( this.options.max - this.min );
},
_refreshValue: function() {
var value = this.options.value,
percentage = this._percentage();
this.valueDiv
.toggle( this.indeterminate || value > this.min )
.width( percentage.toFixed( 0 ) + "%" );
this
._toggleClass( this.valueDiv, "ui-progressbar-complete", null,
value === this.options.max )
._toggleClass( "ui-progressbar-indeterminate", null, this.indeterminate );
if ( this.indeterminate ) {
this.element.removeAttr( "aria-valuenow" );
if ( !this.overlayDiv ) {
this.overlayDiv = $( "<div>" ).appendTo( this.valueDiv );
this._addClass( this.overlayDiv, "ui-progressbar-overlay" );
}
} else {
this.element.attr( {
"aria-valuemax": this.options.max,
"aria-valuenow": value
} );
if ( this.overlayDiv ) {
this.overlayDiv.remove();
this.overlayDiv = null;
}
}
if ( this.oldValue !== value ) {
this.oldValue = value;
this._trigger( "change" );
}
if ( value === this.options.max ) {
this._trigger( "complete" );
}
}
} );
/*!
* jQuery UI Selectable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Selectable
//>>group: Interactions
//>>description: Allows groups of elements to be selected with the mouse.
//>>docs: http://api.jqueryui.com/selectable/
//>>demos: http://jqueryui.com/selectable/
//>>css.structure: ../../themes/base/selectable.css
var widgetsSelectable = $.widget( "ui.selectable", $.ui.mouse, {
version: "1.12.1",
options: {
appendTo: "body",
autoRefresh: true,
distance: 0,
filter: "*",
tolerance: "touch",
// Callbacks
selected: null,
selecting: null,
start: null,
stop: null,
unselected: null,
unselecting: null
},
_create: function() {
var that = this;
this._addClass( "ui-selectable" );
this.dragged = false;
// Cache selectee children based on filter
this.refresh = function() {
that.elementPos = $( that.element[ 0 ] ).offset();
that.selectees = $( that.options.filter, that.element[ 0 ] );
that._addClass( that.selectees, "ui-selectee" );
that.selectees.each( function() {
var $this = $( this ),
selecteeOffset = $this.offset(),
pos = {
left: selecteeOffset.left - that.elementPos.left,
top: selecteeOffset.top - that.elementPos.top
};
$.data( this, "selectable-item", {
element: this,
$element: $this,
left: pos.left,
top: pos.top,
right: pos.left + $this.outerWidth(),
bottom: pos.top + $this.outerHeight(),
startselected: false,
selected: $this.hasClass( "ui-selected" ),
selecting: $this.hasClass( "ui-selecting" ),
unselecting: $this.hasClass( "ui-unselecting" )
} );
} );
};
this.refresh();
this._mouseInit();
this.helper = $( "<div>" );
this._addClass( this.helper, "ui-selectable-helper" );
},
_destroy: function() {
this.selectees.removeData( "selectable-item" );
this._mouseDestroy();
},
_mouseStart: function( event ) {
var that = this,
options = this.options;
this.opos = [ event.pageX, event.pageY ];
this.elementPos = $( this.element[ 0 ] ).offset();
if ( this.options.disabled ) {
return;
}
this.selectees = $( options.filter, this.element[ 0 ] );
this._trigger( "start", event );
$( options.appendTo ).append( this.helper );
// position helper (lasso)
this.helper.css( {
"left": event.pageX,
"top": event.pageY,
"width": 0,
"height": 0
} );
if ( options.autoRefresh ) {
this.refresh();
}
this.selectees.filter( ".ui-selected" ).each( function() {
var selectee = $.data( this, "selectable-item" );
selectee.startselected = true;
if ( !event.metaKey && !event.ctrlKey ) {
that._removeClass( selectee.$element, "ui-selected" );
selectee.selected = false;
that._addClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = true;
// selectable UNSELECTING callback
that._trigger( "unselecting", event, {
unselecting: selectee.element
} );
}
} );
$( event.target ).parents().addBack().each( function() {
var doSelect,
selectee = $.data( this, "selectable-item" );
if ( selectee ) {
doSelect = ( !event.metaKey && !event.ctrlKey ) ||
!selectee.$element.hasClass( "ui-selected" );
that._removeClass( selectee.$element, doSelect ? "ui-unselecting" : "ui-selected" )
._addClass( selectee.$element, doSelect ? "ui-selecting" : "ui-unselecting" );
selectee.unselecting = !doSelect;
selectee.selecting = doSelect;
selectee.selected = doSelect;
// selectable (UN)SELECTING callback
if ( doSelect ) {
that._trigger( "selecting", event, {
selecting: selectee.element
} );
} else {
that._trigger( "unselecting", event, {
unselecting: selectee.element
} );
}
return false;
}
} );
},
_mouseDrag: function( event ) {
this.dragged = true;
if ( this.options.disabled ) {
return;
}
var tmp,
that = this,
options = this.options,
x1 = this.opos[ 0 ],
y1 = this.opos[ 1 ],
x2 = event.pageX,
y2 = event.pageY;
if ( x1 > x2 ) { tmp = x2; x2 = x1; x1 = tmp; }
if ( y1 > y2 ) { tmp = y2; y2 = y1; y1 = tmp; }
this.helper.css( { left: x1, top: y1, width: x2 - x1, height: y2 - y1 } );
this.selectees.each( function() {
var selectee = $.data( this, "selectable-item" ),
hit = false,
offset = {};
//prevent helper from being selected if appendTo: selectable
if ( !selectee || selectee.element === that.element[ 0 ] ) {
return;
}
offset.left = selectee.left + that.elementPos.left;
offset.right = selectee.right + that.elementPos.left;
offset.top = selectee.top + that.elementPos.top;
offset.bottom = selectee.bottom + that.elementPos.top;
if ( options.tolerance === "touch" ) {
hit = ( !( offset.left > x2 || offset.right < x1 || offset.top > y2 ||
offset.bottom < y1 ) );
} else if ( options.tolerance === "fit" ) {
hit = ( offset.left > x1 && offset.right < x2 && offset.top > y1 &&
offset.bottom < y2 );
}
if ( hit ) {
// SELECT
if ( selectee.selected ) {
that._removeClass( selectee.$element, "ui-selected" );
selectee.selected = false;
}
if ( selectee.unselecting ) {
that._removeClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = false;
}
if ( !selectee.selecting ) {
that._addClass( selectee.$element, "ui-selecting" );
selectee.selecting = true;
// selectable SELECTING callback
that._trigger( "selecting", event, {
selecting: selectee.element
} );
}
} else {
// UNSELECT
if ( selectee.selecting ) {
if ( ( event.metaKey || event.ctrlKey ) && selectee.startselected ) {
that._removeClass( selectee.$element, "ui-selecting" );
selectee.selecting = false;
that._addClass( selectee.$element, "ui-selected" );
selectee.selected = true;
} else {
that._removeClass( selectee.$element, "ui-selecting" );
selectee.selecting = false;
if ( selectee.startselected ) {
that._addClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = true;
}
// selectable UNSELECTING callback
that._trigger( "unselecting", event, {
unselecting: selectee.element
} );
}
}
if ( selectee.selected ) {
if ( !event.metaKey && !event.ctrlKey && !selectee.startselected ) {
that._removeClass( selectee.$element, "ui-selected" );
selectee.selected = false;
that._addClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = true;
// selectable UNSELECTING callback
that._trigger( "unselecting", event, {
unselecting: selectee.element
} );
}
}
}
} );
return false;
},
_mouseStop: function( event ) {
var that = this;
this.dragged = false;
$( ".ui-unselecting", this.element[ 0 ] ).each( function() {
var selectee = $.data( this, "selectable-item" );
that._removeClass( selectee.$element, "ui-unselecting" );
selectee.unselecting = false;
selectee.startselected = false;
that._trigger( "unselected", event, {
unselected: selectee.element
} );
} );
$( ".ui-selecting", this.element[ 0 ] ).each( function() {
var selectee = $.data( this, "selectable-item" );
that._removeClass( selectee.$element, "ui-selecting" )
._addClass( selectee.$element, "ui-selected" );
selectee.selecting = false;
selectee.selected = true;
selectee.startselected = true;
that._trigger( "selected", event, {
selected: selectee.element
} );
} );
this._trigger( "stop", event );
this.helper.remove();
return false;
}
} );
/*!
* jQuery UI Selectmenu 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Selectmenu
//>>group: Widgets
// jscs:disable maximumLineLength
//>>description: Duplicates and extends the functionality of a native HTML select element, allowing it to be customizable in behavior and appearance far beyond the limitations of a native select.
// jscs:enable maximumLineLength
//>>docs: http://api.jqueryui.com/selectmenu/
//>>demos: http://jqueryui.com/selectmenu/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/selectmenu.css, ../../themes/base/button.css
//>>css.theme: ../../themes/base/theme.css
var widgetsSelectmenu = $.widget( "ui.selectmenu", [ $.ui.formResetMixin, {
version: "1.12.1",
defaultElement: "<select>",
options: {
appendTo: null,
classes: {
"ui-selectmenu-button-open": "ui-corner-top",
"ui-selectmenu-button-closed": "ui-corner-all"
},
disabled: null,
icons: {
button: "ui-icon-triangle-1-s"
},
position: {
my: "left top",
at: "left bottom",
collision: "none"
},
width: false,
// Callbacks
change: null,
close: null,
focus: null,
open: null,
select: null
},
_create: function() {
var selectmenuId = this.element.uniqueId().attr( "id" );
this.ids = {
element: selectmenuId,
button: selectmenuId + "-button",
menu: selectmenuId + "-menu"
};
this._drawButton();
this._drawMenu();
this._bindFormResetHandler();
this._rendered = false;
this.menuItems = $();
},
_drawButton: function() {
var icon,
that = this,
item = this._parseOption(
this.element.find( "option:selected" ),
this.element[ 0 ].selectedIndex
);
// Associate existing label with the new button
this.labels = this.element.labels().attr( "for", this.ids.button );
this._on( this.labels, {
click: function( event ) {
this.button.focus();
event.preventDefault();
}
} );
// Hide original select element
this.element.hide();
// Create button
this.button = $( "<span>", {
tabindex: this.options.disabled ? -1 : 0,
id: this.ids.button,
role: "combobox",
"aria-expanded": "false",
"aria-autocomplete": "list",
"aria-owns": this.ids.menu,
"aria-haspopup": "true",
title: this.element.attr( "title" )
} )
.insertAfter( this.element );
this._addClass( this.button, "ui-selectmenu-button ui-selectmenu-button-closed",
"ui-button ui-widget" );
icon = $( "<span>" ).appendTo( this.button );
this._addClass( icon, "ui-selectmenu-icon", "ui-icon " + this.options.icons.button );
this.buttonItem = this._renderButtonItem( item )
.appendTo( this.button );
if ( this.options.width !== false ) {
this._resizeButton();
}
this._on( this.button, this._buttonEvents );
this.button.one( "focusin", function() {
// Delay rendering the menu items until the button receives focus.
// The menu may have already been rendered via a programmatic open.
if ( !that._rendered ) {
that._refreshMenu();
}
} );
},
_drawMenu: function() {
var that = this;
// Create menu
this.menu = $( "<ul>", {
"aria-hidden": "true",
"aria-labelledby": this.ids.button,
id: this.ids.menu
} );
// Wrap menu
this.menuWrap = $( "<div>" ).append( this.menu );
this._addClass( this.menuWrap, "ui-selectmenu-menu", "ui-front" );
this.menuWrap.appendTo( this._appendTo() );
// Initialize menu widget
this.menuInstance = this.menu
.menu( {
classes: {
"ui-menu": "ui-corner-bottom"
},
role: "listbox",
select: function( event, ui ) {
event.preventDefault();
// Support: IE8
// If the item was selected via a click, the text selection
// will be destroyed in IE
that._setSelection();
that._select( ui.item.data( "ui-selectmenu-item" ), event );
},
focus: function( event, ui ) {
var item = ui.item.data( "ui-selectmenu-item" );
// Prevent inital focus from firing and check if its a newly focused item
if ( that.focusIndex != null && item.index !== that.focusIndex ) {
that._trigger( "focus", event, { item: item } );
if ( !that.isOpen ) {
that._select( item, event );
}
}
that.focusIndex = item.index;
that.button.attr( "aria-activedescendant",
that.menuItems.eq( item.index ).attr( "id" ) );
}
} )
.menu( "instance" );
// Don't close the menu on mouseleave
this.menuInstance._off( this.menu, "mouseleave" );
// Cancel the menu's collapseAll on document click
this.menuInstance._closeOnDocumentClick = function() {
return false;
};
// Selects often contain empty items, but never contain dividers
this.menuInstance._isDivider = function() {
return false;
};
},
refresh: function() {
this._refreshMenu();
this.buttonItem.replaceWith(
this.buttonItem = this._renderButtonItem(
// Fall back to an empty object in case there are no options
this._getSelectedItem().data( "ui-selectmenu-item" ) || {}
)
);
if ( this.options.width === null ) {
this._resizeButton();
}
},
_refreshMenu: function() {
var item,
options = this.element.find( "option" );
this.menu.empty();
this._parseOptions( options );
this._renderMenu( this.menu, this.items );
this.menuInstance.refresh();
this.menuItems = this.menu.find( "li" )
.not( ".ui-selectmenu-optgroup" )
.find( ".ui-menu-item-wrapper" );
this._rendered = true;
if ( !options.length ) {
return;
}
item = this._getSelectedItem();
// Update the menu to have the correct item focused
this.menuInstance.focus( null, item );
this._setAria( item.data( "ui-selectmenu-item" ) );
// Set disabled state
this._setOption( "disabled", this.element.prop( "disabled" ) );
},
open: function( event ) {
if ( this.options.disabled ) {
return;
}
// If this is the first time the menu is being opened, render the items
if ( !this._rendered ) {
this._refreshMenu();
} else {
// Menu clears focus on close, reset focus to selected item
this._removeClass( this.menu.find( ".ui-state-active" ), null, "ui-state-active" );
this.menuInstance.focus( null, this._getSelectedItem() );
}
// If there are no options, don't open the menu
if ( !this.menuItems.length ) {
return;
}
this.isOpen = true;
this._toggleAttr();
this._resizeMenu();
this._position();
this._on( this.document, this._documentClick );
this._trigger( "open", event );
},
_position: function() {
this.menuWrap.position( $.extend( { of: this.button }, this.options.position ) );
},
close: function( event ) {
if ( !this.isOpen ) {
return;
}
this.isOpen = false;
this._toggleAttr();
this.range = null;
this._off( this.document );
this._trigger( "close", event );
},
widget: function() {
return this.button;
},
menuWidget: function() {
return this.menu;
},
_renderButtonItem: function( item ) {
var buttonItem = $( "<span>" );
this._setText( buttonItem, item.label );
this._addClass( buttonItem, "ui-selectmenu-text" );
return buttonItem;
},
_renderMenu: function( ul, items ) {
var that = this,
currentOptgroup = "";
$.each( items, function( index, item ) {
var li;
if ( item.optgroup !== currentOptgroup ) {
li = $( "<li>", {
text: item.optgroup
} );
that._addClass( li, "ui-selectmenu-optgroup", "ui-menu-divider" +
( item.element.parent( "optgroup" ).prop( "disabled" ) ?
" ui-state-disabled" :
"" ) );
li.appendTo( ul );
currentOptgroup = item.optgroup;
}
that._renderItemData( ul, item );
} );
},
_renderItemData: function( ul, item ) {
return this._renderItem( ul, item ).data( "ui-selectmenu-item", item );
},
_renderItem: function( ul, item ) {
var li = $( "<li>" ),
wrapper = $( "<div>", {
title: item.element.attr( "title" )
} );
if ( item.disabled ) {
this._addClass( li, null, "ui-state-disabled" );
}
this._setText( wrapper, item.label );
return li.append( wrapper ).appendTo( ul );
},
_setText: function( element, value ) {
if ( value ) {
element.text( value );
} else {
element.html( " " );
}
},
_move: function( direction, event ) {
var item, next,
filter = ".ui-menu-item";
if ( this.isOpen ) {
item = this.menuItems.eq( this.focusIndex ).parent( "li" );
} else {
item = this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
filter += ":not(.ui-state-disabled)";
}
if ( direction === "first" || direction === "last" ) {
next = item[ direction === "first" ? "prevAll" : "nextAll" ]( filter ).eq( -1 );
} else {
next = item[ direction + "All" ]( filter ).eq( 0 );
}
if ( next.length ) {
this.menuInstance.focus( event, next );
}
},
_getSelectedItem: function() {
return this.menuItems.eq( this.element[ 0 ].selectedIndex ).parent( "li" );
},
_toggle: function( event ) {
this[ this.isOpen ? "close" : "open" ]( event );
},
_setSelection: function() {
var selection;
if ( !this.range ) {
return;
}
if ( window.getSelection ) {
selection = window.getSelection();
selection.removeAllRanges();
selection.addRange( this.range );
// Support: IE8
} else {
this.range.select();
}
// Support: IE
// Setting the text selection kills the button focus in IE, but
// restoring the focus doesn't kill the selection.
this.button.focus();
},
_documentClick: {
mousedown: function( event ) {
if ( !this.isOpen ) {
return;
}
if ( !$( event.target ).closest( ".ui-selectmenu-menu, #" +
$.ui.escapeSelector( this.ids.button ) ).length ) {
this.close( event );
}
}
},
_buttonEvents: {
// Prevent text selection from being reset when interacting with the selectmenu (#10144)
mousedown: function() {
var selection;
if ( window.getSelection ) {
selection = window.getSelection();
if ( selection.rangeCount ) {
this.range = selection.getRangeAt( 0 );
}
// Support: IE8
} else {
this.range = document.selection.createRange();
}
},
click: function( event ) {
this._setSelection();
this._toggle( event );
},
keydown: function( event ) {
var preventDefault = true;
switch ( event.keyCode ) {
case $.ui.keyCode.TAB:
case $.ui.keyCode.ESCAPE:
this.close( event );
preventDefault = false;
break;
case $.ui.keyCode.ENTER:
if ( this.isOpen ) {
this._selectFocusedItem( event );
}
break;
case $.ui.keyCode.UP:
if ( event.altKey ) {
this._toggle( event );
} else {
this._move( "prev", event );
}
break;
case $.ui.keyCode.DOWN:
if ( event.altKey ) {
this._toggle( event );
} else {
this._move( "next", event );
}
break;
case $.ui.keyCode.SPACE:
if ( this.isOpen ) {
this._selectFocusedItem( event );
} else {
this._toggle( event );
}
break;
case $.ui.keyCode.LEFT:
this._move( "prev", event );
break;
case $.ui.keyCode.RIGHT:
this._move( "next", event );
break;
case $.ui.keyCode.HOME:
case $.ui.keyCode.PAGE_UP:
this._move( "first", event );
break;
case $.ui.keyCode.END:
case $.ui.keyCode.PAGE_DOWN:
this._move( "last", event );
break;
default:
this.menu.trigger( event );
preventDefault = false;
}
if ( preventDefault ) {
event.preventDefault();
}
}
},
_selectFocusedItem: function( event ) {
var item = this.menuItems.eq( this.focusIndex ).parent( "li" );
if ( !item.hasClass( "ui-state-disabled" ) ) {
this._select( item.data( "ui-selectmenu-item" ), event );
}
},
_select: function( item, event ) {
var oldIndex = this.element[ 0 ].selectedIndex;
// Change native select element
this.element[ 0 ].selectedIndex = item.index;
this.buttonItem.replaceWith( this.buttonItem = this._renderButtonItem( item ) );
this._setAria( item );
this._trigger( "select", event, { item: item } );
if ( item.index !== oldIndex ) {
this._trigger( "change", event, { item: item } );
}
this.close( event );
},
_setAria: function( item ) {
var id = this.menuItems.eq( item.index ).attr( "id" );
this.button.attr( {
"aria-labelledby": id,
"aria-activedescendant": id
} );
this.menu.attr( "aria-activedescendant", id );
},
_setOption: function( key, value ) {
if ( key === "icons" ) {
var icon = this.button.find( "span.ui-icon" );
this._removeClass( icon, null, this.options.icons.button )
._addClass( icon, null, value.button );
}
this._super( key, value );
if ( key === "appendTo" ) {
this.menuWrap.appendTo( this._appendTo() );
}
if ( key === "width" ) {
this._resizeButton();
}
},
_setOptionDisabled: function( value ) {
this._super( value );
this.menuInstance.option( "disabled", value );
this.button.attr( "aria-disabled", value );
this._toggleClass( this.button, null, "ui-state-disabled", value );
this.element.prop( "disabled", value );
if ( value ) {
this.button.attr( "tabindex", -1 );
this.close();
} else {
this.button.attr( "tabindex", 0 );
}
},
_appendTo: function() {
var element = this.options.appendTo;
if ( element ) {
element = element.jquery || element.nodeType ?
$( element ) :
this.document.find( element ).eq( 0 );
}
if ( !element || !element[ 0 ] ) {
element = this.element.closest( ".ui-front, dialog" );
}
if ( !element.length ) {
element = this.document[ 0 ].body;
}
return element;
},
_toggleAttr: function() {
this.button.attr( "aria-expanded", this.isOpen );
// We can't use two _toggleClass() calls here, because we need to make sure
// we always remove classes first and add them second, otherwise if both classes have the
// same theme class, it will be removed after we add it.
this._removeClass( this.button, "ui-selectmenu-button-" +
( this.isOpen ? "closed" : "open" ) )
._addClass( this.button, "ui-selectmenu-button-" +
( this.isOpen ? "open" : "closed" ) )
._toggleClass( this.menuWrap, "ui-selectmenu-open", null, this.isOpen );
this.menu.attr( "aria-hidden", !this.isOpen );
},
_resizeButton: function() {
var width = this.options.width;
// For `width: false`, just remove inline style and stop
if ( width === false ) {
this.button.css( "width", "" );
return;
}
// For `width: null`, match the width of the original element
if ( width === null ) {
width = this.element.show().outerWidth();
this.element.hide();
}
this.button.outerWidth( width );
},
_resizeMenu: function() {
this.menu.outerWidth( Math.max(
this.button.outerWidth(),
// Support: IE10
// IE10 wraps long text (possibly a rounding bug)
// so we add 1px to avoid the wrapping
this.menu.width( "" ).outerWidth() + 1
) );
},
_getCreateOptions: function() {
var options = this._super();
options.disabled = this.element.prop( "disabled" );
return options;
},
_parseOptions: function( options ) {
var that = this,
data = [];
options.each( function( index, item ) {
data.push( that._parseOption( $( item ), index ) );
} );
this.items = data;
},
_parseOption: function( option, index ) {
var optgroup = option.parent( "optgroup" );
return {
element: option,
index: index,
value: option.val(),
label: option.text(),
optgroup: optgroup.attr( "label" ) || "",
disabled: optgroup.prop( "disabled" ) || option.prop( "disabled" )
};
},
_destroy: function() {
this._unbindFormResetHandler();
this.menuWrap.remove();
this.button.remove();
this.element.show();
this.element.removeUniqueId();
this.labels.attr( "for", this.ids.element );
}
} ] );
/*!
* jQuery UI Slider 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Slider
//>>group: Widgets
//>>description: Displays a flexible slider with ranges and accessibility via keyboard.
//>>docs: http://api.jqueryui.com/slider/
//>>demos: http://jqueryui.com/slider/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/slider.css
//>>css.theme: ../../themes/base/theme.css
var widgetsSlider = $.widget( "ui.slider", $.ui.mouse, {
version: "1.12.1",
widgetEventPrefix: "slide",
options: {
animate: false,
classes: {
"ui-slider": "ui-corner-all",
"ui-slider-handle": "ui-corner-all",
// Note: ui-widget-header isn't the most fittingly semantic framework class for this
// element, but worked best visually with a variety of themes
"ui-slider-range": "ui-corner-all ui-widget-header"
},
distance: 0,
max: 100,
min: 0,
orientation: "horizontal",
range: false,
step: 1,
value: 0,
values: null,
// Callbacks
change: null,
slide: null,
start: null,
stop: null
},
// Number of pages in a slider
// (how many times can you page up/down to go through the whole range)
numPages: 5,
_create: function() {
this._keySliding = false;
this._mouseSliding = false;
this._animateOff = true;
this._handleIndex = null;
this._detectOrientation();
this._mouseInit();
this._calculateNewMax();
this._addClass( "ui-slider ui-slider-" + this.orientation,
"ui-widget ui-widget-content" );
this._refresh();
this._animateOff = false;
},
_refresh: function() {
this._createRange();
this._createHandles();
this._setupEvents();
this._refreshValue();
},
_createHandles: function() {
var i, handleCount,
options = this.options,
existingHandles = this.element.find( ".ui-slider-handle" ),
handle = "<span tabindex='0'></span>",
handles = [];
handleCount = ( options.values && options.values.length ) || 1;
if ( existingHandles.length > handleCount ) {
existingHandles.slice( handleCount ).remove();
existingHandles = existingHandles.slice( 0, handleCount );
}
for ( i = existingHandles.length; i < handleCount; i++ ) {
handles.push( handle );
}
this.handles = existingHandles.add( $( handles.join( "" ) ).appendTo( this.element ) );
this._addClass( this.handles, "ui-slider-handle", "ui-state-default" );
this.handle = this.handles.eq( 0 );
this.handles.each( function( i ) {
$( this )
.data( "ui-slider-handle-index", i )
.attr( "tabIndex", 0 );
} );
},
_createRange: function() {
var options = this.options;
if ( options.range ) {
if ( options.range === true ) {
if ( !options.values ) {
options.values = [ this._valueMin(), this._valueMin() ];
} else if ( options.values.length && options.values.length !== 2 ) {
options.values = [ options.values[ 0 ], options.values[ 0 ] ];
} else if ( $.isArray( options.values ) ) {
options.values = options.values.slice( 0 );
}
}
if ( !this.range || !this.range.length ) {
this.range = $( "<div>" )
.appendTo( this.element );
this._addClass( this.range, "ui-slider-range" );
} else {
this._removeClass( this.range, "ui-slider-range-min ui-slider-range-max" );
// Handle range switching from true to min/max
this.range.css( {
"left": "",
"bottom": ""
} );
}
if ( options.range === "min" || options.range === "max" ) {
this._addClass( this.range, "ui-slider-range-" + options.range );
}
} else {
if ( this.range ) {
this.range.remove();
}
this.range = null;
}
},
_setupEvents: function() {
this._off( this.handles );
this._on( this.handles, this._handleEvents );
this._hoverable( this.handles );
this._focusable( this.handles );
},
_destroy: function() {
this.handles.remove();
if ( this.range ) {
this.range.remove();
}
this._mouseDestroy();
},
_mouseCapture: function( event ) {
var position, normValue, distance, closestHandle, index, allowed, offset, mouseOverHandle,
that = this,
o = this.options;
if ( o.disabled ) {
return false;
}
this.elementSize = {
width: this.element.outerWidth(),
height: this.element.outerHeight()
};
this.elementOffset = this.element.offset();
position = { x: event.pageX, y: event.pageY };
normValue = this._normValueFromMouse( position );
distance = this._valueMax() - this._valueMin() + 1;
this.handles.each( function( i ) {
var thisDistance = Math.abs( normValue - that.values( i ) );
if ( ( distance > thisDistance ) ||
( distance === thisDistance &&
( i === that._lastChangedValue || that.values( i ) === o.min ) ) ) {
distance = thisDistance;
closestHandle = $( this );
index = i;
}
} );
allowed = this._start( event, index );
if ( allowed === false ) {
return false;
}
this._mouseSliding = true;
this._handleIndex = index;
this._addClass( closestHandle, null, "ui-state-active" );
closestHandle.trigger( "focus" );
offset = closestHandle.offset();
mouseOverHandle = !$( event.target ).parents().addBack().is( ".ui-slider-handle" );
this._clickOffset = mouseOverHandle ? { left: 0, top: 0 } : {
left: event.pageX - offset.left - ( closestHandle.width() / 2 ),
top: event.pageY - offset.top -
( closestHandle.height() / 2 ) -
( parseInt( closestHandle.css( "borderTopWidth" ), 10 ) || 0 ) -
( parseInt( closestHandle.css( "borderBottomWidth" ), 10 ) || 0 ) +
( parseInt( closestHandle.css( "marginTop" ), 10 ) || 0 )
};
if ( !this.handles.hasClass( "ui-state-hover" ) ) {
this._slide( event, index, normValue );
}
this._animateOff = true;
return true;
},
_mouseStart: function() {
return true;
},
_mouseDrag: function( event ) {
var position = { x: event.pageX, y: event.pageY },
normValue = this._normValueFromMouse( position );
this._slide( event, this._handleIndex, normValue );
return false;
},
_mouseStop: function( event ) {
this._removeClass( this.handles, null, "ui-state-active" );
this._mouseSliding = false;
this._stop( event, this._handleIndex );
this._change( event, this._handleIndex );
this._handleIndex = null;
this._clickOffset = null;
this._animateOff = false;
return false;
},
_detectOrientation: function() {
this.orientation = ( this.options.orientation === "vertical" ) ? "vertical" : "horizontal";
},
_normValueFromMouse: function( position ) {
var pixelTotal,
pixelMouse,
percentMouse,
valueTotal,
valueMouse;
if ( this.orientation === "horizontal" ) {
pixelTotal = this.elementSize.width;
pixelMouse = position.x - this.elementOffset.left -
( this._clickOffset ? this._clickOffset.left : 0 );
} else {
pixelTotal = this.elementSize.height;
pixelMouse = position.y - this.elementOffset.top -
( this._clickOffset ? this._clickOffset.top : 0 );
}
percentMouse = ( pixelMouse / pixelTotal );
if ( percentMouse > 1 ) {
percentMouse = 1;
}
if ( percentMouse < 0 ) {
percentMouse = 0;
}
if ( this.orientation === "vertical" ) {
percentMouse = 1 - percentMouse;
}
valueTotal = this._valueMax() - this._valueMin();
valueMouse = this._valueMin() + percentMouse * valueTotal;
return this._trimAlignValue( valueMouse );
},
_uiHash: function( index, value, values ) {
var uiHash = {
handle: this.handles[ index ],
handleIndex: index,
value: value !== undefined ? value : this.value()
};
if ( this._hasMultipleValues() ) {
uiHash.value = value !== undefined ? value : this.values( index );
uiHash.values = values || this.values();
}
return uiHash;
},
_hasMultipleValues: function() {
return this.options.values && this.options.values.length;
},
_start: function( event, index ) {
return this._trigger( "start", event, this._uiHash( index ) );
},
_slide: function( event, index, newVal ) {
var allowed, otherVal,
currentValue = this.value(),
newValues = this.values();
if ( this._hasMultipleValues() ) {
otherVal = this.values( index ? 0 : 1 );
currentValue = this.values( index );
if ( this.options.values.length === 2 && this.options.range === true ) {
newVal = index === 0 ? Math.min( otherVal, newVal ) : Math.max( otherVal, newVal );
}
newValues[ index ] = newVal;
}
if ( newVal === currentValue ) {
return;
}
allowed = this._trigger( "slide", event, this._uiHash( index, newVal, newValues ) );
// A slide can be canceled by returning false from the slide callback
if ( allowed === false ) {
return;
}
if ( this._hasMultipleValues() ) {
this.values( index, newVal );
} else {
this.value( newVal );
}
},
_stop: function( event, index ) {
this._trigger( "stop", event, this._uiHash( index ) );
},
_change: function( event, index ) {
if ( !this._keySliding && !this._mouseSliding ) {
//store the last changed value index for reference when handles overlap
this._lastChangedValue = index;
this._trigger( "change", event, this._uiHash( index ) );
}
},
value: function( newValue ) {
if ( arguments.length ) {
this.options.value = this._trimAlignValue( newValue );
this._refreshValue();
this._change( null, 0 );
return;
}
return this._value();
},
values: function( index, newValue ) {
var vals,
newValues,
i;
if ( arguments.length > 1 ) {
this.options.values[ index ] = this._trimAlignValue( newValue );
this._refreshValue();
this._change( null, index );
return;
}
if ( arguments.length ) {
if ( $.isArray( arguments[ 0 ] ) ) {
vals = this.options.values;
newValues = arguments[ 0 ];
for ( i = 0; i < vals.length; i += 1 ) {
vals[ i ] = this._trimAlignValue( newValues[ i ] );
this._change( null, i );
}
this._refreshValue();
} else {
if ( this._hasMultipleValues() ) {
return this._values( index );
} else {
return this.value();
}
}
} else {
return this._values();
}
},
_setOption: function( key, value ) {
var i,
valsLength = 0;
if ( key === "range" && this.options.range === true ) {
if ( value === "min" ) {
this.options.value = this._values( 0 );
this.options.values = null;
} else if ( value === "max" ) {
this.options.value = this._values( this.options.values.length - 1 );
this.options.values = null;
}
}
if ( $.isArray( this.options.values ) ) {
valsLength = this.options.values.length;
}
this._super( key, value );
switch ( key ) {
case "orientation":
this._detectOrientation();
this._removeClass( "ui-slider-horizontal ui-slider-vertical" )
._addClass( "ui-slider-" + this.orientation );
this._refreshValue();
if ( this.options.range ) {
this._refreshRange( value );
}
// Reset positioning from previous orientation
this.handles.css( value === "horizontal" ? "bottom" : "left", "" );
break;
case "value":
this._animateOff = true;
this._refreshValue();
this._change( null, 0 );
this._animateOff = false;
break;
case "values":
this._animateOff = true;
this._refreshValue();
// Start from the last handle to prevent unreachable handles (#9046)
for ( i = valsLength - 1; i >= 0; i-- ) {
this._change( null, i );
}
this._animateOff = false;
break;
case "step":
case "min":
case "max":
this._animateOff = true;
this._calculateNewMax();
this._refreshValue();
this._animateOff = false;
break;
case "range":
this._animateOff = true;
this._refresh();
this._animateOff = false;
break;
}
},
_setOptionDisabled: function( value ) {
this._super( value );
this._toggleClass( null, "ui-state-disabled", !!value );
},
//internal value getter
// _value() returns value trimmed by min and max, aligned by step
_value: function() {
var val = this.options.value;
val = this._trimAlignValue( val );
return val;
},
//internal values getter
// _values() returns array of values trimmed by min and max, aligned by step
// _values( index ) returns single value trimmed by min and max, aligned by step
_values: function( index ) {
var val,
vals,
i;
if ( arguments.length ) {
val = this.options.values[ index ];
val = this._trimAlignValue( val );
return val;
} else if ( this._hasMultipleValues() ) {
// .slice() creates a copy of the array
// this copy gets trimmed by min and max and then returned
vals = this.options.values.slice();
for ( i = 0; i < vals.length; i += 1 ) {
vals[ i ] = this._trimAlignValue( vals[ i ] );
}
return vals;
} else {
return [];
}
},
// Returns the step-aligned value that val is closest to, between (inclusive) min and max
_trimAlignValue: function( val ) {
if ( val <= this._valueMin() ) {
return this._valueMin();
}
if ( val >= this._valueMax() ) {
return this._valueMax();
}
var step = ( this.options.step > 0 ) ? this.options.step : 1,
valModStep = ( val - this._valueMin() ) % step,
alignValue = val - valModStep;
if ( Math.abs( valModStep ) * 2 >= step ) {
alignValue += ( valModStep > 0 ) ? step : ( -step );
}
// Since JavaScript has problems with large floats, round
// the final value to 5 digits after the decimal point (see #4124)
return parseFloat( alignValue.toFixed( 5 ) );
},
_calculateNewMax: function() {
var max = this.options.max,
min = this._valueMin(),
step = this.options.step,
aboveMin = Math.round( ( max - min ) / step ) * step;
max = aboveMin + min;
if ( max > this.options.max ) {
//If max is not divisible by step, rounding off may increase its value
max -= step;
}
this.max = parseFloat( max.toFixed( this._precision() ) );
},
_precision: function() {
var precision = this._precisionOf( this.options.step );
if ( this.options.min !== null ) {
precision = Math.max( precision, this._precisionOf( this.options.min ) );
}
return precision;
},
_precisionOf: function( num ) {
var str = num.toString(),
decimal = str.indexOf( "." );
return decimal === -1 ? 0 : str.length - decimal - 1;
},
_valueMin: function() {
return this.options.min;
},
_valueMax: function() {
return this.max;
},
_refreshRange: function( orientation ) {
if ( orientation === "vertical" ) {
this.range.css( { "width": "", "left": "" } );
}
if ( orientation === "horizontal" ) {
this.range.css( { "height": "", "bottom": "" } );
}
},
_refreshValue: function() {
var lastValPercent, valPercent, value, valueMin, valueMax,
oRange = this.options.range,
o = this.options,
that = this,
animate = ( !this._animateOff ) ? o.animate : false,
_set = {};
if ( this._hasMultipleValues() ) {
this.handles.each( function( i ) {
valPercent = ( that.values( i ) - that._valueMin() ) / ( that._valueMax() -
that._valueMin() ) * 100;
_set[ that.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
$( this ).stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
if ( that.options.range === true ) {
if ( that.orientation === "horizontal" ) {
if ( i === 0 ) {
that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
left: valPercent + "%"
}, o.animate );
}
if ( i === 1 ) {
that.range[ animate ? "animate" : "css" ]( {
width: ( valPercent - lastValPercent ) + "%"
}, {
queue: false,
duration: o.animate
} );
}
} else {
if ( i === 0 ) {
that.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
bottom: ( valPercent ) + "%"
}, o.animate );
}
if ( i === 1 ) {
that.range[ animate ? "animate" : "css" ]( {
height: ( valPercent - lastValPercent ) + "%"
}, {
queue: false,
duration: o.animate
} );
}
}
}
lastValPercent = valPercent;
} );
} else {
value = this.value();
valueMin = this._valueMin();
valueMax = this._valueMax();
valPercent = ( valueMax !== valueMin ) ?
( value - valueMin ) / ( valueMax - valueMin ) * 100 :
0;
_set[ this.orientation === "horizontal" ? "left" : "bottom" ] = valPercent + "%";
this.handle.stop( 1, 1 )[ animate ? "animate" : "css" ]( _set, o.animate );
if ( oRange === "min" && this.orientation === "horizontal" ) {
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
width: valPercent + "%"
}, o.animate );
}
if ( oRange === "max" && this.orientation === "horizontal" ) {
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
width: ( 100 - valPercent ) + "%"
}, o.animate );
}
if ( oRange === "min" && this.orientation === "vertical" ) {
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
height: valPercent + "%"
}, o.animate );
}
if ( oRange === "max" && this.orientation === "vertical" ) {
this.range.stop( 1, 1 )[ animate ? "animate" : "css" ]( {
height: ( 100 - valPercent ) + "%"
}, o.animate );
}
}
},
_handleEvents: {
keydown: function( event ) {
var allowed, curVal, newVal, step,
index = $( event.target ).data( "ui-slider-handle-index" );
switch ( event.keyCode ) {
case $.ui.keyCode.HOME:
case $.ui.keyCode.END:
case $.ui.keyCode.PAGE_UP:
case $.ui.keyCode.PAGE_DOWN:
case $.ui.keyCode.UP:
case $.ui.keyCode.RIGHT:
case $.ui.keyCode.DOWN:
case $.ui.keyCode.LEFT:
event.preventDefault();
if ( !this._keySliding ) {
this._keySliding = true;
this._addClass( $( event.target ), null, "ui-state-active" );
allowed = this._start( event, index );
if ( allowed === false ) {
return;
}
}
break;
}
step = this.options.step;
if ( this._hasMultipleValues() ) {
curVal = newVal = this.values( index );
} else {
curVal = newVal = this.value();
}
switch ( event.keyCode ) {
case $.ui.keyCode.HOME:
newVal = this._valueMin();
break;
case $.ui.keyCode.END:
newVal = this._valueMax();
break;
case $.ui.keyCode.PAGE_UP:
newVal = this._trimAlignValue(
curVal + ( ( this._valueMax() - this._valueMin() ) / this.numPages )
);
break;
case $.ui.keyCode.PAGE_DOWN:
newVal = this._trimAlignValue(
curVal - ( ( this._valueMax() - this._valueMin() ) / this.numPages ) );
break;
case $.ui.keyCode.UP:
case $.ui.keyCode.RIGHT:
if ( curVal === this._valueMax() ) {
return;
}
newVal = this._trimAlignValue( curVal + step );
break;
case $.ui.keyCode.DOWN:
case $.ui.keyCode.LEFT:
if ( curVal === this._valueMin() ) {
return;
}
newVal = this._trimAlignValue( curVal - step );
break;
}
this._slide( event, index, newVal );
},
keyup: function( event ) {
var index = $( event.target ).data( "ui-slider-handle-index" );
if ( this._keySliding ) {
this._keySliding = false;
this._stop( event, index );
this._change( event, index );
this._removeClass( $( event.target ), null, "ui-state-active" );
}
}
}
} );
/*!
* jQuery UI Sortable 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Sortable
//>>group: Interactions
//>>description: Enables items in a list to be sorted using the mouse.
//>>docs: http://api.jqueryui.com/sortable/
//>>demos: http://jqueryui.com/sortable/
//>>css.structure: ../../themes/base/sortable.css
var widgetsSortable = $.widget( "ui.sortable", $.ui.mouse, {
version: "1.12.1",
widgetEventPrefix: "sort",
ready: false,
options: {
appendTo: "parent",
axis: false,
connectWith: false,
containment: false,
cursor: "auto",
cursorAt: false,
dropOnEmpty: true,
forcePlaceholderSize: false,
forceHelperSize: false,
grid: false,
handle: false,
helper: "original",
items: "> *",
opacity: false,
placeholder: false,
revert: false,
scroll: true,
scrollSensitivity: 20,
scrollSpeed: 20,
scope: "default",
tolerance: "intersect",
zIndex: 1000,
// Callbacks
activate: null,
beforeStop: null,
change: null,
deactivate: null,
out: null,
over: null,
receive: null,
remove: null,
sort: null,
start: null,
stop: null,
update: null
},
_isOverAxis: function( x, reference, size ) {
return ( x >= reference ) && ( x < ( reference + size ) );
},
_isFloating: function( item ) {
return ( /left|right/ ).test( item.css( "float" ) ) ||
( /inline|table-cell/ ).test( item.css( "display" ) );
},
_create: function() {
this.containerCache = {};
this._addClass( "ui-sortable" );
//Get the items
this.refresh();
//Let's determine the parent's offset
this.offset = this.element.offset();
//Initialize mouse events for interaction
this._mouseInit();
this._setHandleClassName();
//We're ready to go
this.ready = true;
},
_setOption: function( key, value ) {
this._super( key, value );
if ( key === "handle" ) {
this._setHandleClassName();
}
},
_setHandleClassName: function() {
var that = this;
this._removeClass( this.element.find( ".ui-sortable-handle" ), "ui-sortable-handle" );
$.each( this.items, function() {
that._addClass(
this.instance.options.handle ?
this.item.find( this.instance.options.handle ) :
this.item,
"ui-sortable-handle"
);
} );
},
_destroy: function() {
this._mouseDestroy();
for ( var i = this.items.length - 1; i >= 0; i-- ) {
this.items[ i ].item.removeData( this.widgetName + "-item" );
}
return this;
},
_mouseCapture: function( event, overrideHandle ) {
var currentItem = null,
validHandle = false,
that = this;
if ( this.reverting ) {
return false;
}
if ( this.options.disabled || this.options.type === "static" ) {
return false;
}
//We have to refresh the items data once first
this._refreshItems( event );
//Find out if the clicked node (or one of its parents) is a actual item in this.items
$( event.target ).parents().each( function() {
if ( $.data( this, that.widgetName + "-item" ) === that ) {
currentItem = $( this );
return false;
}
} );
if ( $.data( event.target, that.widgetName + "-item" ) === that ) {
currentItem = $( event.target );
}
if ( !currentItem ) {
return false;
}
if ( this.options.handle && !overrideHandle ) {
$( this.options.handle, currentItem ).find( "*" ).addBack().each( function() {
if ( this === event.target ) {
validHandle = true;
}
} );
if ( !validHandle ) {
return false;
}
}
this.currentItem = currentItem;
this._removeCurrentsFromItems();
return true;
},
_mouseStart: function( event, overrideHandle, noActivation ) {
var i, body,
o = this.options;
this.currentContainer = this;
//We only need to call refreshPositions, because the refreshItems call has been moved to
// mouseCapture
this.refreshPositions();
//Create and append the visible helper
this.helper = this._createHelper( event );
//Cache the helper size
this._cacheHelperProportions();
/*
* - Position generation -
* This block generates everything position related - it's the core of draggables.
*/
//Cache the margins of the original element
this._cacheMargins();
//Get the next scrolling parent
this.scrollParent = this.helper.scrollParent();
//The element's absolute position on the page minus margins
this.offset = this.currentItem.offset();
this.offset = {
top: this.offset.top - this.margins.top,
left: this.offset.left - this.margins.left
};
$.extend( this.offset, {
click: { //Where the click happened, relative to the element
left: event.pageX - this.offset.left,
top: event.pageY - this.offset.top
},
parent: this._getParentOffset(),
// This is a relative to absolute position minus the actual position calculation -
// only used for relative positioned helper
relative: this._getRelativeOffset()
} );
// Only after we got the offset, we can change the helper's position to absolute
// TODO: Still need to figure out a way to make relative sorting possible
this.helper.css( "position", "absolute" );
this.cssPosition = this.helper.css( "position" );
//Generate the original position
this.originalPosition = this._generatePosition( event );
this.originalPageX = event.pageX;
this.originalPageY = event.pageY;
//Adjust the mouse offset relative to the helper if "cursorAt" is supplied
( o.cursorAt && this._adjustOffsetFromHelper( o.cursorAt ) );
//Cache the former DOM position
this.domPosition = {
prev: this.currentItem.prev()[ 0 ],
parent: this.currentItem.parent()[ 0 ]
};
// If the helper is not the original, hide the original so it's not playing any role during
// the drag, won't cause anything bad this way
if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
this.currentItem.hide();
}
//Create the placeholder
this._createPlaceholder();
//Set a containment if given in the options
if ( o.containment ) {
this._setContainment();
}
if ( o.cursor && o.cursor !== "auto" ) { // cursor option
body = this.document.find( "body" );
// Support: IE
this.storedCursor = body.css( "cursor" );
body.css( "cursor", o.cursor );
this.storedStylesheet =
$( "<style>*{ cursor: " + o.cursor + " !important; }</style>" ).appendTo( body );
}
if ( o.opacity ) { // opacity option
if ( this.helper.css( "opacity" ) ) {
this._storedOpacity = this.helper.css( "opacity" );
}
this.helper.css( "opacity", o.opacity );
}
if ( o.zIndex ) { // zIndex option
if ( this.helper.css( "zIndex" ) ) {
this._storedZIndex = this.helper.css( "zIndex" );
}
this.helper.css( "zIndex", o.zIndex );
}
//Prepare scrolling
if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
this.scrollParent[ 0 ].tagName !== "HTML" ) {
this.overflowOffset = this.scrollParent.offset();
}
//Call callbacks
this._trigger( "start", event, this._uiHash() );
//Recache the helper size
if ( !this._preserveHelperProportions ) {
this._cacheHelperProportions();
}
//Post "activate" events to possible containers
if ( !noActivation ) {
for ( i = this.containers.length - 1; i >= 0; i-- ) {
this.containers[ i ]._trigger( "activate", event, this._uiHash( this ) );
}
}
//Prepare possible droppables
if ( $.ui.ddmanager ) {
$.ui.ddmanager.current = this;
}
if ( $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( this, event );
}
this.dragging = true;
this._addClass( this.helper, "ui-sortable-helper" );
// Execute the drag once - this causes the helper not to be visiblebefore getting its
// correct position
this._mouseDrag( event );
return true;
},
_mouseDrag: function( event ) {
var i, item, itemElement, intersection,
o = this.options,
scrolled = false;
//Compute the helpers position
this.position = this._generatePosition( event );
this.positionAbs = this._convertPositionTo( "absolute" );
if ( !this.lastPositionAbs ) {
this.lastPositionAbs = this.positionAbs;
}
//Do scrolling
if ( this.options.scroll ) {
if ( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
this.scrollParent[ 0 ].tagName !== "HTML" ) {
if ( ( this.overflowOffset.top + this.scrollParent[ 0 ].offsetHeight ) -
event.pageY < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollTop =
scrolled = this.scrollParent[ 0 ].scrollTop + o.scrollSpeed;
} else if ( event.pageY - this.overflowOffset.top < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollTop =
scrolled = this.scrollParent[ 0 ].scrollTop - o.scrollSpeed;
}
if ( ( this.overflowOffset.left + this.scrollParent[ 0 ].offsetWidth ) -
event.pageX < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollLeft = scrolled =
this.scrollParent[ 0 ].scrollLeft + o.scrollSpeed;
} else if ( event.pageX - this.overflowOffset.left < o.scrollSensitivity ) {
this.scrollParent[ 0 ].scrollLeft = scrolled =
this.scrollParent[ 0 ].scrollLeft - o.scrollSpeed;
}
} else {
if ( event.pageY - this.document.scrollTop() < o.scrollSensitivity ) {
scrolled = this.document.scrollTop( this.document.scrollTop() - o.scrollSpeed );
} else if ( this.window.height() - ( event.pageY - this.document.scrollTop() ) <
o.scrollSensitivity ) {
scrolled = this.document.scrollTop( this.document.scrollTop() + o.scrollSpeed );
}
if ( event.pageX - this.document.scrollLeft() < o.scrollSensitivity ) {
scrolled = this.document.scrollLeft(
this.document.scrollLeft() - o.scrollSpeed
);
} else if ( this.window.width() - ( event.pageX - this.document.scrollLeft() ) <
o.scrollSensitivity ) {
scrolled = this.document.scrollLeft(
this.document.scrollLeft() + o.scrollSpeed
);
}
}
if ( scrolled !== false && $.ui.ddmanager && !o.dropBehaviour ) {
$.ui.ddmanager.prepareOffsets( this, event );
}
}
//Regenerate the absolute position used for position checks
this.positionAbs = this._convertPositionTo( "absolute" );
//Set the helper position
if ( !this.options.axis || this.options.axis !== "y" ) {
this.helper[ 0 ].style.left = this.position.left + "px";
}
if ( !this.options.axis || this.options.axis !== "x" ) {
this.helper[ 0 ].style.top = this.position.top + "px";
}
//Rearrange
for ( i = this.items.length - 1; i >= 0; i-- ) {
//Cache variables and intersection, continue if no intersection
item = this.items[ i ];
itemElement = item.item[ 0 ];
intersection = this._intersectsWithPointer( item );
if ( !intersection ) {
continue;
}
// Only put the placeholder inside the current Container, skip all
// items from other containers. This works because when moving
// an item from one container to another the
// currentContainer is switched before the placeholder is moved.
//
// Without this, moving items in "sub-sortables" can cause
// the placeholder to jitter between the outer and inner container.
if ( item.instance !== this.currentContainer ) {
continue;
}
// Cannot intersect with itself
// no useless actions that have been done before
// no action if the item moved is the parent of the item checked
if ( itemElement !== this.currentItem[ 0 ] &&
this.placeholder[ intersection === 1 ? "next" : "prev" ]()[ 0 ] !== itemElement &&
!$.contains( this.placeholder[ 0 ], itemElement ) &&
( this.options.type === "semi-dynamic" ?
!$.contains( this.element[ 0 ], itemElement ) :
true
)
) {
this.direction = intersection === 1 ? "down" : "up";
if ( this.options.tolerance === "pointer" || this._intersectsWithSides( item ) ) {
this._rearrange( event, item );
} else {
break;
}
this._trigger( "change", event, this._uiHash() );
break;
}
}
//Post events to containers
this._contactContainers( event );
//Interconnect with droppables
if ( $.ui.ddmanager ) {
$.ui.ddmanager.drag( this, event );
}
//Call callbacks
this._trigger( "sort", event, this._uiHash() );
this.lastPositionAbs = this.positionAbs;
return false;
},
_mouseStop: function( event, noPropagation ) {
if ( !event ) {
return;
}
//If we are using droppables, inform the manager about the drop
if ( $.ui.ddmanager && !this.options.dropBehaviour ) {
$.ui.ddmanager.drop( this, event );
}
if ( this.options.revert ) {
var that = this,
cur = this.placeholder.offset(),
axis = this.options.axis,
animation = {};
if ( !axis || axis === "x" ) {
animation.left = cur.left - this.offset.parent.left - this.margins.left +
( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
0 :
this.offsetParent[ 0 ].scrollLeft
);
}
if ( !axis || axis === "y" ) {
animation.top = cur.top - this.offset.parent.top - this.margins.top +
( this.offsetParent[ 0 ] === this.document[ 0 ].body ?
0 :
this.offsetParent[ 0 ].scrollTop
);
}
this.reverting = true;
$( this.helper ).animate(
animation,
parseInt( this.options.revert, 10 ) || 500,
function() {
that._clear( event );
}
);
} else {
this._clear( event, noPropagation );
}
return false;
},
cancel: function() {
if ( this.dragging ) {
this._mouseUp( new $.Event( "mouseup", { target: null } ) );
if ( this.options.helper === "original" ) {
this.currentItem.css( this._storedCSS );
this._removeClass( this.currentItem, "ui-sortable-helper" );
} else {
this.currentItem.show();
}
//Post deactivating events to containers
for ( var i = this.containers.length - 1; i >= 0; i-- ) {
this.containers[ i ]._trigger( "deactivate", null, this._uiHash( this ) );
if ( this.containers[ i ].containerCache.over ) {
this.containers[ i ]._trigger( "out", null, this._uiHash( this ) );
this.containers[ i ].containerCache.over = 0;
}
}
}
if ( this.placeholder ) {
//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
// it unbinds ALL events from the original node!
if ( this.placeholder[ 0 ].parentNode ) {
this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
}
if ( this.options.helper !== "original" && this.helper &&
this.helper[ 0 ].parentNode ) {
this.helper.remove();
}
$.extend( this, {
helper: null,
dragging: false,
reverting: false,
_noFinalSort: null
} );
if ( this.domPosition.prev ) {
$( this.domPosition.prev ).after( this.currentItem );
} else {
$( this.domPosition.parent ).prepend( this.currentItem );
}
}
return this;
},
serialize: function( o ) {
var items = this._getItemsAsjQuery( o && o.connected ),
str = [];
o = o || {};
$( items ).each( function() {
var res = ( $( o.item || this ).attr( o.attribute || "id" ) || "" )
.match( o.expression || ( /(.+)[\-=_](.+)/ ) );
if ( res ) {
str.push(
( o.key || res[ 1 ] + "[]" ) +
"=" + ( o.key && o.expression ? res[ 1 ] : res[ 2 ] ) );
}
} );
if ( !str.length && o.key ) {
str.push( o.key + "=" );
}
return str.join( "&" );
},
toArray: function( o ) {
var items = this._getItemsAsjQuery( o && o.connected ),
ret = [];
o = o || {};
items.each( function() {
ret.push( $( o.item || this ).attr( o.attribute || "id" ) || "" );
} );
return ret;
},
/* Be careful with the following core functions */
_intersectsWith: function( item ) {
var x1 = this.positionAbs.left,
x2 = x1 + this.helperProportions.width,
y1 = this.positionAbs.top,
y2 = y1 + this.helperProportions.height,
l = item.left,
r = l + item.width,
t = item.top,
b = t + item.height,
dyClick = this.offset.click.top,
dxClick = this.offset.click.left,
isOverElementHeight = ( this.options.axis === "x" ) || ( ( y1 + dyClick ) > t &&
( y1 + dyClick ) < b ),
isOverElementWidth = ( this.options.axis === "y" ) || ( ( x1 + dxClick ) > l &&
( x1 + dxClick ) < r ),
isOverElement = isOverElementHeight && isOverElementWidth;
if ( this.options.tolerance === "pointer" ||
this.options.forcePointerForContainers ||
( this.options.tolerance !== "pointer" &&
this.helperProportions[ this.floating ? "width" : "height" ] >
item[ this.floating ? "width" : "height" ] )
) {
return isOverElement;
} else {
return ( l < x1 + ( this.helperProportions.width / 2 ) && // Right Half
x2 - ( this.helperProportions.width / 2 ) < r && // Left Half
t < y1 + ( this.helperProportions.height / 2 ) && // Bottom Half
y2 - ( this.helperProportions.height / 2 ) < b ); // Top Half
}
},
_intersectsWithPointer: function( item ) {
var verticalDirection, horizontalDirection,
isOverElementHeight = ( this.options.axis === "x" ) ||
this._isOverAxis(
this.positionAbs.top + this.offset.click.top, item.top, item.height ),
isOverElementWidth = ( this.options.axis === "y" ) ||
this._isOverAxis(
this.positionAbs.left + this.offset.click.left, item.left, item.width ),
isOverElement = isOverElementHeight && isOverElementWidth;
if ( !isOverElement ) {
return false;
}
verticalDirection = this._getDragVerticalDirection();
horizontalDirection = this._getDragHorizontalDirection();
return this.floating ?
( ( horizontalDirection === "right" || verticalDirection === "down" ) ? 2 : 1 )
: ( verticalDirection && ( verticalDirection === "down" ? 2 : 1 ) );
},
_intersectsWithSides: function( item ) {
var isOverBottomHalf = this._isOverAxis( this.positionAbs.top +
this.offset.click.top, item.top + ( item.height / 2 ), item.height ),
isOverRightHalf = this._isOverAxis( this.positionAbs.left +
this.offset.click.left, item.left + ( item.width / 2 ), item.width ),
verticalDirection = this._getDragVerticalDirection(),
horizontalDirection = this._getDragHorizontalDirection();
if ( this.floating && horizontalDirection ) {
return ( ( horizontalDirection === "right" && isOverRightHalf ) ||
( horizontalDirection === "left" && !isOverRightHalf ) );
} else {
return verticalDirection && ( ( verticalDirection === "down" && isOverBottomHalf ) ||
( verticalDirection === "up" && !isOverBottomHalf ) );
}
},
_getDragVerticalDirection: function() {
var delta = this.positionAbs.top - this.lastPositionAbs.top;
return delta !== 0 && ( delta > 0 ? "down" : "up" );
},
_getDragHorizontalDirection: function() {
var delta = this.positionAbs.left - this.lastPositionAbs.left;
return delta !== 0 && ( delta > 0 ? "right" : "left" );
},
refresh: function( event ) {
this._refreshItems( event );
this._setHandleClassName();
this.refreshPositions();
return this;
},
_connectWith: function() {
var options = this.options;
return options.connectWith.constructor === String ?
[ options.connectWith ] :
options.connectWith;
},
_getItemsAsjQuery: function( connected ) {
var i, j, cur, inst,
items = [],
queries = [],
connectWith = this._connectWith();
if ( connectWith && connected ) {
for ( i = connectWith.length - 1; i >= 0; i-- ) {
cur = $( connectWith[ i ], this.document[ 0 ] );
for ( j = cur.length - 1; j >= 0; j-- ) {
inst = $.data( cur[ j ], this.widgetFullName );
if ( inst && inst !== this && !inst.options.disabled ) {
queries.push( [ $.isFunction( inst.options.items ) ?
inst.options.items.call( inst.element ) :
$( inst.options.items, inst.element )
.not( ".ui-sortable-helper" )
.not( ".ui-sortable-placeholder" ), inst ] );
}
}
}
}
queries.push( [ $.isFunction( this.options.items ) ?
this.options.items
.call( this.element, null, { options: this.options, item: this.currentItem } ) :
$( this.options.items, this.element )
.not( ".ui-sortable-helper" )
.not( ".ui-sortable-placeholder" ), this ] );
function addItems() {
items.push( this );
}
for ( i = queries.length - 1; i >= 0; i-- ) {
queries[ i ][ 0 ].each( addItems );
}
return $( items );
},
_removeCurrentsFromItems: function() {
var list = this.currentItem.find( ":data(" + this.widgetName + "-item)" );
this.items = $.grep( this.items, function( item ) {
for ( var j = 0; j < list.length; j++ ) {
if ( list[ j ] === item.item[ 0 ] ) {
return false;
}
}
return true;
} );
},
_refreshItems: function( event ) {
this.items = [];
this.containers = [ this ];
var i, j, cur, inst, targetData, _queries, item, queriesLength,
items = this.items,
queries = [ [ $.isFunction( this.options.items ) ?
this.options.items.call( this.element[ 0 ], event, { item: this.currentItem } ) :
$( this.options.items, this.element ), this ] ],
connectWith = this._connectWith();
//Shouldn't be run the first time through due to massive slow-down
if ( connectWith && this.ready ) {
for ( i = connectWith.length - 1; i >= 0; i-- ) {
cur = $( connectWith[ i ], this.document[ 0 ] );
for ( j = cur.length - 1; j >= 0; j-- ) {
inst = $.data( cur[ j ], this.widgetFullName );
if ( inst && inst !== this && !inst.options.disabled ) {
queries.push( [ $.isFunction( inst.options.items ) ?
inst.options.items
.call( inst.element[ 0 ], event, { item: this.currentItem } ) :
$( inst.options.items, inst.element ), inst ] );
this.containers.push( inst );
}
}
}
}
for ( i = queries.length - 1; i >= 0; i-- ) {
targetData = queries[ i ][ 1 ];
_queries = queries[ i ][ 0 ];
for ( j = 0, queriesLength = _queries.length; j < queriesLength; j++ ) {
item = $( _queries[ j ] );
// Data for target checking (mouse manager)
item.data( this.widgetName + "-item", targetData );
items.push( {
item: item,
instance: targetData,
width: 0, height: 0,
left: 0, top: 0
} );
}
}
},
refreshPositions: function( fast ) {
// Determine whether items are being displayed horizontally
this.floating = this.items.length ?
this.options.axis === "x" || this._isFloating( this.items[ 0 ].item ) :
false;
//This has to be redone because due to the item being moved out/into the offsetParent,
// the offsetParent's position will change
if ( this.offsetParent && this.helper ) {
this.offset.parent = this._getParentOffset();
}
var i, item, t, p;
for ( i = this.items.length - 1; i >= 0; i-- ) {
item = this.items[ i ];
//We ignore calculating positions of all connected containers when we're not over them
if ( item.instance !== this.currentContainer && this.currentContainer &&
item.item[ 0 ] !== this.currentItem[ 0 ] ) {
continue;
}
t = this.options.toleranceElement ?
$( this.options.toleranceElement, item.item ) :
item.item;
if ( !fast ) {
item.width = t.outerWidth();
item.height = t.outerHeight();
}
p = t.offset();
item.left = p.left;
item.top = p.top;
}
if ( this.options.custom && this.options.custom.refreshContainers ) {
this.options.custom.refreshContainers.call( this );
} else {
for ( i = this.containers.length - 1; i >= 0; i-- ) {
p = this.containers[ i ].element.offset();
this.containers[ i ].containerCache.left = p.left;
this.containers[ i ].containerCache.top = p.top;
this.containers[ i ].containerCache.width =
this.containers[ i ].element.outerWidth();
this.containers[ i ].containerCache.height =
this.containers[ i ].element.outerHeight();
}
}
return this;
},
_createPlaceholder: function( that ) {
that = that || this;
var className,
o = that.options;
if ( !o.placeholder || o.placeholder.constructor === String ) {
className = o.placeholder;
o.placeholder = {
element: function() {
var nodeName = that.currentItem[ 0 ].nodeName.toLowerCase(),
element = $( "<" + nodeName + ">", that.document[ 0 ] );
that._addClass( element, "ui-sortable-placeholder",
className || that.currentItem[ 0 ].className )
._removeClass( element, "ui-sortable-helper" );
if ( nodeName === "tbody" ) {
that._createTrPlaceholder(
that.currentItem.find( "tr" ).eq( 0 ),
$( "<tr>", that.document[ 0 ] ).appendTo( element )
);
} else if ( nodeName === "tr" ) {
that._createTrPlaceholder( that.currentItem, element );
} else if ( nodeName === "img" ) {
element.attr( "src", that.currentItem.attr( "src" ) );
}
if ( !className ) {
element.css( "visibility", "hidden" );
}
return element;
},
update: function( container, p ) {
// 1. If a className is set as 'placeholder option, we don't force sizes -
// the class is responsible for that
// 2. The option 'forcePlaceholderSize can be enabled to force it even if a
// class name is specified
if ( className && !o.forcePlaceholderSize ) {
return;
}
//If the element doesn't have a actual height by itself (without styles coming
// from a stylesheet), it receives the inline height from the dragged item
if ( !p.height() ) {
p.height(
that.currentItem.innerHeight() -
parseInt( that.currentItem.css( "paddingTop" ) || 0, 10 ) -
parseInt( that.currentItem.css( "paddingBottom" ) || 0, 10 ) );
}
if ( !p.width() ) {
p.width(
that.currentItem.innerWidth() -
parseInt( that.currentItem.css( "paddingLeft" ) || 0, 10 ) -
parseInt( that.currentItem.css( "paddingRight" ) || 0, 10 ) );
}
}
};
}
//Create the placeholder
that.placeholder = $( o.placeholder.element.call( that.element, that.currentItem ) );
//Append it after the actual current item
that.currentItem.after( that.placeholder );
//Update the size of the placeholder (TODO: Logic to fuzzy, see line 316/317)
o.placeholder.update( that, that.placeholder );
},
_createTrPlaceholder: function( sourceTr, targetTr ) {
var that = this;
sourceTr.children().each( function() {
$( "<td> </td>", that.document[ 0 ] )
.attr( "colspan", $( this ).attr( "colspan" ) || 1 )
.appendTo( targetTr );
} );
},
_contactContainers: function( event ) {
var i, j, dist, itemWithLeastDistance, posProperty, sizeProperty, cur, nearBottom,
floating, axis,
innermostContainer = null,
innermostIndex = null;
// Get innermost container that intersects with item
for ( i = this.containers.length - 1; i >= 0; i-- ) {
// Never consider a container that's located within the item itself
if ( $.contains( this.currentItem[ 0 ], this.containers[ i ].element[ 0 ] ) ) {
continue;
}
if ( this._intersectsWith( this.containers[ i ].containerCache ) ) {
// If we've already found a container and it's more "inner" than this, then continue
if ( innermostContainer &&
$.contains(
this.containers[ i ].element[ 0 ],
innermostContainer.element[ 0 ] ) ) {
continue;
}
innermostContainer = this.containers[ i ];
innermostIndex = i;
} else {
// container doesn't intersect. trigger "out" event if necessary
if ( this.containers[ i ].containerCache.over ) {
this.containers[ i ]._trigger( "out", event, this._uiHash( this ) );
this.containers[ i ].containerCache.over = 0;
}
}
}
// If no intersecting containers found, return
if ( !innermostContainer ) {
return;
}
// Move the item into the container if it's not there already
if ( this.containers.length === 1 ) {
if ( !this.containers[ innermostIndex ].containerCache.over ) {
this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
this.containers[ innermostIndex ].containerCache.over = 1;
}
} else {
// When entering a new container, we will find the item with the least distance and
// append our item near it
dist = 10000;
itemWithLeastDistance = null;
floating = innermostContainer.floating || this._isFloating( this.currentItem );
posProperty = floating ? "left" : "top";
sizeProperty = floating ? "width" : "height";
axis = floating ? "pageX" : "pageY";
for ( j = this.items.length - 1; j >= 0; j-- ) {
if ( !$.contains(
this.containers[ innermostIndex ].element[ 0 ], this.items[ j ].item[ 0 ] )
) {
continue;
}
if ( this.items[ j ].item[ 0 ] === this.currentItem[ 0 ] ) {
continue;
}
cur = this.items[ j ].item.offset()[ posProperty ];
nearBottom = false;
if ( event[ axis ] - cur > this.items[ j ][ sizeProperty ] / 2 ) {
nearBottom = true;
}
if ( Math.abs( event[ axis ] - cur ) < dist ) {
dist = Math.abs( event[ axis ] - cur );
itemWithLeastDistance = this.items[ j ];
this.direction = nearBottom ? "up" : "down";
}
}
//Check if dropOnEmpty is enabled
if ( !itemWithLeastDistance && !this.options.dropOnEmpty ) {
return;
}
if ( this.currentContainer === this.containers[ innermostIndex ] ) {
if ( !this.currentContainer.containerCache.over ) {
this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash() );
this.currentContainer.containerCache.over = 1;
}
return;
}
itemWithLeastDistance ?
this._rearrange( event, itemWithLeastDistance, null, true ) :
this._rearrange( event, null, this.containers[ innermostIndex ].element, true );
this._trigger( "change", event, this._uiHash() );
this.containers[ innermostIndex ]._trigger( "change", event, this._uiHash( this ) );
this.currentContainer = this.containers[ innermostIndex ];
//Update the placeholder
this.options.placeholder.update( this.currentContainer, this.placeholder );
this.containers[ innermostIndex ]._trigger( "over", event, this._uiHash( this ) );
this.containers[ innermostIndex ].containerCache.over = 1;
}
},
_createHelper: function( event ) {
var o = this.options,
helper = $.isFunction( o.helper ) ?
$( o.helper.apply( this.element[ 0 ], [ event, this.currentItem ] ) ) :
( o.helper === "clone" ? this.currentItem.clone() : this.currentItem );
//Add the helper to the DOM if that didn't happen already
if ( !helper.parents( "body" ).length ) {
$( o.appendTo !== "parent" ?
o.appendTo :
this.currentItem[ 0 ].parentNode )[ 0 ].appendChild( helper[ 0 ] );
}
if ( helper[ 0 ] === this.currentItem[ 0 ] ) {
this._storedCSS = {
width: this.currentItem[ 0 ].style.width,
height: this.currentItem[ 0 ].style.height,
position: this.currentItem.css( "position" ),
top: this.currentItem.css( "top" ),
left: this.currentItem.css( "left" )
};
}
if ( !helper[ 0 ].style.width || o.forceHelperSize ) {
helper.width( this.currentItem.width() );
}
if ( !helper[ 0 ].style.height || o.forceHelperSize ) {
helper.height( this.currentItem.height() );
}
return helper;
},
_adjustOffsetFromHelper: function( obj ) {
if ( typeof obj === "string" ) {
obj = obj.split( " " );
}
if ( $.isArray( obj ) ) {
obj = { left: +obj[ 0 ], top: +obj[ 1 ] || 0 };
}
if ( "left" in obj ) {
this.offset.click.left = obj.left + this.margins.left;
}
if ( "right" in obj ) {
this.offset.click.left = this.helperProportions.width - obj.right + this.margins.left;
}
if ( "top" in obj ) {
this.offset.click.top = obj.top + this.margins.top;
}
if ( "bottom" in obj ) {
this.offset.click.top = this.helperProportions.height - obj.bottom + this.margins.top;
}
},
_getParentOffset: function() {
//Get the offsetParent and cache its position
this.offsetParent = this.helper.offsetParent();
var po = this.offsetParent.offset();
// This is a special case where we need to modify a offset calculated on start, since the
// following happened:
// 1. The position of the helper is absolute, so it's position is calculated based on the
// next positioned parent
// 2. The actual offset parent is a child of the scroll parent, and the scroll parent isn't
// the document, which means that the scroll is included in the initial calculation of the
// offset of the parent, and never recalculated upon drag
if ( this.cssPosition === "absolute" && this.scrollParent[ 0 ] !== this.document[ 0 ] &&
$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) {
po.left += this.scrollParent.scrollLeft();
po.top += this.scrollParent.scrollTop();
}
// This needs to be actually done for all browsers, since pageX/pageY includes this
// information with an ugly IE fix
if ( this.offsetParent[ 0 ] === this.document[ 0 ].body ||
( this.offsetParent[ 0 ].tagName &&
this.offsetParent[ 0 ].tagName.toLowerCase() === "html" && $.ui.ie ) ) {
po = { top: 0, left: 0 };
}
return {
top: po.top + ( parseInt( this.offsetParent.css( "borderTopWidth" ), 10 ) || 0 ),
left: po.left + ( parseInt( this.offsetParent.css( "borderLeftWidth" ), 10 ) || 0 )
};
},
_getRelativeOffset: function() {
if ( this.cssPosition === "relative" ) {
var p = this.currentItem.position();
return {
top: p.top - ( parseInt( this.helper.css( "top" ), 10 ) || 0 ) +
this.scrollParent.scrollTop(),
left: p.left - ( parseInt( this.helper.css( "left" ), 10 ) || 0 ) +
this.scrollParent.scrollLeft()
};
} else {
return { top: 0, left: 0 };
}
},
_cacheMargins: function() {
this.margins = {
left: ( parseInt( this.currentItem.css( "marginLeft" ), 10 ) || 0 ),
top: ( parseInt( this.currentItem.css( "marginTop" ), 10 ) || 0 )
};
},
_cacheHelperProportions: function() {
this.helperProportions = {
width: this.helper.outerWidth(),
height: this.helper.outerHeight()
};
},
_setContainment: function() {
var ce, co, over,
o = this.options;
if ( o.containment === "parent" ) {
o.containment = this.helper[ 0 ].parentNode;
}
if ( o.containment === "document" || o.containment === "window" ) {
this.containment = [
0 - this.offset.relative.left - this.offset.parent.left,
0 - this.offset.relative.top - this.offset.parent.top,
o.containment === "document" ?
this.document.width() :
this.window.width() - this.helperProportions.width - this.margins.left,
( o.containment === "document" ?
( this.document.height() || document.body.parentNode.scrollHeight ) :
this.window.height() || this.document[ 0 ].body.parentNode.scrollHeight
) - this.helperProportions.height - this.margins.top
];
}
if ( !( /^(document|window|parent)$/ ).test( o.containment ) ) {
ce = $( o.containment )[ 0 ];
co = $( o.containment ).offset();
over = ( $( ce ).css( "overflow" ) !== "hidden" );
this.containment = [
co.left + ( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) +
( parseInt( $( ce ).css( "paddingLeft" ), 10 ) || 0 ) - this.margins.left,
co.top + ( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) +
( parseInt( $( ce ).css( "paddingTop" ), 10 ) || 0 ) - this.margins.top,
co.left + ( over ? Math.max( ce.scrollWidth, ce.offsetWidth ) : ce.offsetWidth ) -
( parseInt( $( ce ).css( "borderLeftWidth" ), 10 ) || 0 ) -
( parseInt( $( ce ).css( "paddingRight" ), 10 ) || 0 ) -
this.helperProportions.width - this.margins.left,
co.top + ( over ? Math.max( ce.scrollHeight, ce.offsetHeight ) : ce.offsetHeight ) -
( parseInt( $( ce ).css( "borderTopWidth" ), 10 ) || 0 ) -
( parseInt( $( ce ).css( "paddingBottom" ), 10 ) || 0 ) -
this.helperProportions.height - this.margins.top
];
}
},
_convertPositionTo: function( d, pos ) {
if ( !pos ) {
pos = this.position;
}
var mod = d === "absolute" ? 1 : -1,
scroll = this.cssPosition === "absolute" &&
!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
this.offsetParent :
this.scrollParent,
scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
return {
top: (
// The absolute mouse position
pos.top +
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.top * mod +
// The offsetParent's offset without borders (offset + border)
this.offset.parent.top * mod -
( ( this.cssPosition === "fixed" ?
-this.scrollParent.scrollTop() :
( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) * mod )
),
left: (
// The absolute mouse position
pos.left +
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.left * mod +
// The offsetParent's offset without borders (offset + border)
this.offset.parent.left * mod -
( ( this.cssPosition === "fixed" ?
-this.scrollParent.scrollLeft() : scrollIsRootNode ? 0 :
scroll.scrollLeft() ) * mod )
)
};
},
_generatePosition: function( event ) {
var top, left,
o = this.options,
pageX = event.pageX,
pageY = event.pageY,
scroll = this.cssPosition === "absolute" &&
!( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
$.contains( this.scrollParent[ 0 ], this.offsetParent[ 0 ] ) ) ?
this.offsetParent :
this.scrollParent,
scrollIsRootNode = ( /(html|body)/i ).test( scroll[ 0 ].tagName );
// This is another very weird special case that only happens for relative elements:
// 1. If the css position is relative
// 2. and the scroll parent is the document or similar to the offset parent
// we have to refresh the relative offset during the scroll so there are no jumps
if ( this.cssPosition === "relative" && !( this.scrollParent[ 0 ] !== this.document[ 0 ] &&
this.scrollParent[ 0 ] !== this.offsetParent[ 0 ] ) ) {
this.offset.relative = this._getRelativeOffset();
}
/*
* - Position constraining -
* Constrain the position to a mix of grid, containment.
*/
if ( this.originalPosition ) { //If we are not dragging yet, we won't check for options
if ( this.containment ) {
if ( event.pageX - this.offset.click.left < this.containment[ 0 ] ) {
pageX = this.containment[ 0 ] + this.offset.click.left;
}
if ( event.pageY - this.offset.click.top < this.containment[ 1 ] ) {
pageY = this.containment[ 1 ] + this.offset.click.top;
}
if ( event.pageX - this.offset.click.left > this.containment[ 2 ] ) {
pageX = this.containment[ 2 ] + this.offset.click.left;
}
if ( event.pageY - this.offset.click.top > this.containment[ 3 ] ) {
pageY = this.containment[ 3 ] + this.offset.click.top;
}
}
if ( o.grid ) {
top = this.originalPageY + Math.round( ( pageY - this.originalPageY ) /
o.grid[ 1 ] ) * o.grid[ 1 ];
pageY = this.containment ?
( ( top - this.offset.click.top >= this.containment[ 1 ] &&
top - this.offset.click.top <= this.containment[ 3 ] ) ?
top :
( ( top - this.offset.click.top >= this.containment[ 1 ] ) ?
top - o.grid[ 1 ] : top + o.grid[ 1 ] ) ) :
top;
left = this.originalPageX + Math.round( ( pageX - this.originalPageX ) /
o.grid[ 0 ] ) * o.grid[ 0 ];
pageX = this.containment ?
( ( left - this.offset.click.left >= this.containment[ 0 ] &&
left - this.offset.click.left <= this.containment[ 2 ] ) ?
left :
( ( left - this.offset.click.left >= this.containment[ 0 ] ) ?
left - o.grid[ 0 ] : left + o.grid[ 0 ] ) ) :
left;
}
}
return {
top: (
// The absolute mouse position
pageY -
// Click offset (relative to the element)
this.offset.click.top -
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.top -
// The offsetParent's offset without borders (offset + border)
this.offset.parent.top +
( ( this.cssPosition === "fixed" ?
-this.scrollParent.scrollTop() :
( scrollIsRootNode ? 0 : scroll.scrollTop() ) ) )
),
left: (
// The absolute mouse position
pageX -
// Click offset (relative to the element)
this.offset.click.left -
// Only for relative positioned nodes: Relative offset from element to offset parent
this.offset.relative.left -
// The offsetParent's offset without borders (offset + border)
this.offset.parent.left +
( ( this.cssPosition === "fixed" ?
-this.scrollParent.scrollLeft() :
scrollIsRootNode ? 0 : scroll.scrollLeft() ) )
)
};
},
_rearrange: function( event, i, a, hardRefresh ) {
a ? a[ 0 ].appendChild( this.placeholder[ 0 ] ) :
i.item[ 0 ].parentNode.insertBefore( this.placeholder[ 0 ],
( this.direction === "down" ? i.item[ 0 ] : i.item[ 0 ].nextSibling ) );
//Various things done here to improve the performance:
// 1. we create a setTimeout, that calls refreshPositions
// 2. on the instance, we have a counter variable, that get's higher after every append
// 3. on the local scope, we copy the counter variable, and check in the timeout,
// if it's still the same
// 4. this lets only the last addition to the timeout stack through
this.counter = this.counter ? ++this.counter : 1;
var counter = this.counter;
this._delay( function() {
if ( counter === this.counter ) {
//Precompute after each DOM insertion, NOT on mousemove
this.refreshPositions( !hardRefresh );
}
} );
},
_clear: function( event, noPropagation ) {
this.reverting = false;
// We delay all events that have to be triggered to after the point where the placeholder
// has been removed and everything else normalized again
var i,
delayedTriggers = [];
// We first have to update the dom position of the actual currentItem
// Note: don't do it if the current item is already removed (by a user), or it gets
// reappended (see #4088)
if ( !this._noFinalSort && this.currentItem.parent().length ) {
this.placeholder.before( this.currentItem );
}
this._noFinalSort = null;
if ( this.helper[ 0 ] === this.currentItem[ 0 ] ) {
for ( i in this._storedCSS ) {
if ( this._storedCSS[ i ] === "auto" || this._storedCSS[ i ] === "static" ) {
this._storedCSS[ i ] = "";
}
}
this.currentItem.css( this._storedCSS );
this._removeClass( this.currentItem, "ui-sortable-helper" );
} else {
this.currentItem.show();
}
if ( this.fromOutside && !noPropagation ) {
delayedTriggers.push( function( event ) {
this._trigger( "receive", event, this._uiHash( this.fromOutside ) );
} );
}
if ( ( this.fromOutside ||
this.domPosition.prev !==
this.currentItem.prev().not( ".ui-sortable-helper" )[ 0 ] ||
this.domPosition.parent !== this.currentItem.parent()[ 0 ] ) && !noPropagation ) {
// Trigger update callback if the DOM position has changed
delayedTriggers.push( function( event ) {
this._trigger( "update", event, this._uiHash() );
} );
}
// Check if the items Container has Changed and trigger appropriate
// events.
if ( this !== this.currentContainer ) {
if ( !noPropagation ) {
delayedTriggers.push( function( event ) {
this._trigger( "remove", event, this._uiHash() );
} );
delayedTriggers.push( ( function( c ) {
return function( event ) {
c._trigger( "receive", event, this._uiHash( this ) );
};
} ).call( this, this.currentContainer ) );
delayedTriggers.push( ( function( c ) {
return function( event ) {
c._trigger( "update", event, this._uiHash( this ) );
};
} ).call( this, this.currentContainer ) );
}
}
//Post events to containers
function delayEvent( type, instance, container ) {
return function( event ) {
container._trigger( type, event, instance._uiHash( instance ) );
};
}
for ( i = this.containers.length - 1; i >= 0; i-- ) {
if ( !noPropagation ) {
delayedTriggers.push( delayEvent( "deactivate", this, this.containers[ i ] ) );
}
if ( this.containers[ i ].containerCache.over ) {
delayedTriggers.push( delayEvent( "out", this, this.containers[ i ] ) );
this.containers[ i ].containerCache.over = 0;
}
}
//Do what was originally in plugins
if ( this.storedCursor ) {
this.document.find( "body" ).css( "cursor", this.storedCursor );
this.storedStylesheet.remove();
}
if ( this._storedOpacity ) {
this.helper.css( "opacity", this._storedOpacity );
}
if ( this._storedZIndex ) {
this.helper.css( "zIndex", this._storedZIndex === "auto" ? "" : this._storedZIndex );
}
this.dragging = false;
if ( !noPropagation ) {
this._trigger( "beforeStop", event, this._uiHash() );
}
//$(this.placeholder[0]).remove(); would have been the jQuery way - unfortunately,
// it unbinds ALL events from the original node!
this.placeholder[ 0 ].parentNode.removeChild( this.placeholder[ 0 ] );
if ( !this.cancelHelperRemoval ) {
if ( this.helper[ 0 ] !== this.currentItem[ 0 ] ) {
this.helper.remove();
}
this.helper = null;
}
if ( !noPropagation ) {
for ( i = 0; i < delayedTriggers.length; i++ ) {
// Trigger all delayed events
delayedTriggers[ i ].call( this, event );
}
this._trigger( "stop", event, this._uiHash() );
}
this.fromOutside = false;
return !this.cancelHelperRemoval;
},
_trigger: function() {
if ( $.Widget.prototype._trigger.apply( this, arguments ) === false ) {
this.cancel();
}
},
_uiHash: function( _inst ) {
var inst = _inst || this;
return {
helper: inst.helper,
placeholder: inst.placeholder || $( [] ),
position: inst.position,
originalPosition: inst.originalPosition,
offset: inst.positionAbs,
item: inst.currentItem,
sender: _inst ? _inst.element : null
};
}
} );
/*!
* jQuery UI Spinner 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Spinner
//>>group: Widgets
//>>description: Displays buttons to easily input numbers via the keyboard or mouse.
//>>docs: http://api.jqueryui.com/spinner/
//>>demos: http://jqueryui.com/spinner/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/spinner.css
//>>css.theme: ../../themes/base/theme.css
function spinnerModifer( fn ) {
return function() {
var previous = this.element.val();
fn.apply( this, arguments );
this._refresh();
if ( previous !== this.element.val() ) {
this._trigger( "change" );
}
};
}
$.widget( "ui.spinner", {
version: "1.12.1",
defaultElement: "<input>",
widgetEventPrefix: "spin",
options: {
classes: {
"ui-spinner": "ui-corner-all",
"ui-spinner-down": "ui-corner-br",
"ui-spinner-up": "ui-corner-tr"
},
culture: null,
icons: {
down: "ui-icon-triangle-1-s",
up: "ui-icon-triangle-1-n"
},
incremental: true,
max: null,
min: null,
numberFormat: null,
page: 10,
step: 1,
change: null,
spin: null,
start: null,
stop: null
},
_create: function() {
// handle string values that need to be parsed
this._setOption( "max", this.options.max );
this._setOption( "min", this.options.min );
this._setOption( "step", this.options.step );
// Only format if there is a value, prevents the field from being marked
// as invalid in Firefox, see #9573.
if ( this.value() !== "" ) {
// Format the value, but don't constrain.
this._value( this.element.val(), true );
}
this._draw();
this._on( this._events );
this._refresh();
// Turning off autocomplete prevents the browser from remembering the
// value when navigating through history, so we re-enable autocomplete
// if the page is unloaded before the widget is destroyed. #7790
this._on( this.window, {
beforeunload: function() {
this.element.removeAttr( "autocomplete" );
}
} );
},
_getCreateOptions: function() {
var options = this._super();
var element = this.element;
$.each( [ "min", "max", "step" ], function( i, option ) {
var value = element.attr( option );
if ( value != null && value.length ) {
options[ option ] = value;
}
} );
return options;
},
_events: {
keydown: function( event ) {
if ( this._start( event ) && this._keydown( event ) ) {
event.preventDefault();
}
},
keyup: "_stop",
focus: function() {
this.previous = this.element.val();
},
blur: function( event ) {
if ( this.cancelBlur ) {
delete this.cancelBlur;
return;
}
this._stop();
this._refresh();
if ( this.previous !== this.element.val() ) {
this._trigger( "change", event );
}
},
mousewheel: function( event, delta ) {
if ( !delta ) {
return;
}
if ( !this.spinning && !this._start( event ) ) {
return false;
}
this._spin( ( delta > 0 ? 1 : -1 ) * this.options.step, event );
clearTimeout( this.mousewheelTimer );
this.mousewheelTimer = this._delay( function() {
if ( this.spinning ) {
this._stop( event );
}
}, 100 );
event.preventDefault();
},
"mousedown .ui-spinner-button": function( event ) {
var previous;
// We never want the buttons to have focus; whenever the user is
// interacting with the spinner, the focus should be on the input.
// If the input is focused then this.previous is properly set from
// when the input first received focus. If the input is not focused
// then we need to set this.previous based on the value before spinning.
previous = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] ) ?
this.previous : this.element.val();
function checkFocus() {
var isActive = this.element[ 0 ] === $.ui.safeActiveElement( this.document[ 0 ] );
if ( !isActive ) {
this.element.trigger( "focus" );
this.previous = previous;
// support: IE
// IE sets focus asynchronously, so we need to check if focus
// moved off of the input because the user clicked on the button.
this._delay( function() {
this.previous = previous;
} );
}
}
// Ensure focus is on (or stays on) the text field
event.preventDefault();
checkFocus.call( this );
// Support: IE
// IE doesn't prevent moving focus even with event.preventDefault()
// so we set a flag to know when we should ignore the blur event
// and check (again) if focus moved off of the input.
this.cancelBlur = true;
this._delay( function() {
delete this.cancelBlur;
checkFocus.call( this );
} );
if ( this._start( event ) === false ) {
return;
}
this._repeat( null, $( event.currentTarget )
.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
},
"mouseup .ui-spinner-button": "_stop",
"mouseenter .ui-spinner-button": function( event ) {
// button will add ui-state-active if mouse was down while mouseleave and kept down
if ( !$( event.currentTarget ).hasClass( "ui-state-active" ) ) {
return;
}
if ( this._start( event ) === false ) {
return false;
}
this._repeat( null, $( event.currentTarget )
.hasClass( "ui-spinner-up" ) ? 1 : -1, event );
},
// TODO: do we really want to consider this a stop?
// shouldn't we just stop the repeater and wait until mouseup before
// we trigger the stop event?
"mouseleave .ui-spinner-button": "_stop"
},
// Support mobile enhanced option and make backcompat more sane
_enhance: function() {
this.uiSpinner = this.element
.attr( "autocomplete", "off" )
.wrap( "<span>" )
.parent()
// Add buttons
.append(
"<a></a><a></a>"
);
},
_draw: function() {
this._enhance();
this._addClass( this.uiSpinner, "ui-spinner", "ui-widget ui-widget-content" );
this._addClass( "ui-spinner-input" );
this.element.attr( "role", "spinbutton" );
// Button bindings
this.buttons = this.uiSpinner.children( "a" )
.attr( "tabIndex", -1 )
.attr( "aria-hidden", true )
.button( {
classes: {
"ui-button": ""
}
} );
// TODO: Right now button does not support classes this is already updated in button PR
this._removeClass( this.buttons, "ui-corner-all" );
this._addClass( this.buttons.first(), "ui-spinner-button ui-spinner-up" );
this._addClass( this.buttons.last(), "ui-spinner-button ui-spinner-down" );
this.buttons.first().button( {
"icon": this.options.icons.up,
"showLabel": false
} );
this.buttons.last().button( {
"icon": this.options.icons.down,
"showLabel": false
} );
// IE 6 doesn't understand height: 50% for the buttons
// unless the wrapper has an explicit height
if ( this.buttons.height() > Math.ceil( this.uiSpinner.height() * 0.5 ) &&
this.uiSpinner.height() > 0 ) {
this.uiSpinner.height( this.uiSpinner.height() );
}
},
_keydown: function( event ) {
var options = this.options,
keyCode = $.ui.keyCode;
switch ( event.keyCode ) {
case keyCode.UP:
this._repeat( null, 1, event );
return true;
case keyCode.DOWN:
this._repeat( null, -1, event );
return true;
case keyCode.PAGE_UP:
this._repeat( null, options.page, event );
return true;
case keyCode.PAGE_DOWN:
this._repeat( null, -options.page, event );
return true;
}
return false;
},
_start: function( event ) {
if ( !this.spinning && this._trigger( "start", event ) === false ) {
return false;
}
if ( !this.counter ) {
this.counter = 1;
}
this.spinning = true;
return true;
},
_repeat: function( i, steps, event ) {
i = i || 500;
clearTimeout( this.timer );
this.timer = this._delay( function() {
this._repeat( 40, steps, event );
}, i );
this._spin( steps * this.options.step, event );
},
_spin: function( step, event ) {
var value = this.value() || 0;
if ( !this.counter ) {
this.counter = 1;
}
value = this._adjustValue( value + step * this._increment( this.counter ) );
if ( !this.spinning || this._trigger( "spin", event, { value: value } ) !== false ) {
this._value( value );
this.counter++;
}
},
_increment: function( i ) {
var incremental = this.options.incremental;
if ( incremental ) {
return $.isFunction( incremental ) ?
incremental( i ) :
Math.floor( i * i * i / 50000 - i * i / 500 + 17 * i / 200 + 1 );
}
return 1;
},
_precision: function() {
var precision = this._precisionOf( this.options.step );
if ( this.options.min !== null ) {
precision = Math.max( precision, this._precisionOf( this.options.min ) );
}
return precision;
},
_precisionOf: function( num ) {
var str = num.toString(),
decimal = str.indexOf( "." );
return decimal === -1 ? 0 : str.length - decimal - 1;
},
_adjustValue: function( value ) {
var base, aboveMin,
options = this.options;
// Make sure we're at a valid step
// - find out where we are relative to the base (min or 0)
base = options.min !== null ? options.min : 0;
aboveMin = value - base;
// - round to the nearest step
aboveMin = Math.round( aboveMin / options.step ) * options.step;
// - rounding is based on 0, so adjust back to our base
value = base + aboveMin;
// Fix precision from bad JS floating point math
value = parseFloat( value.toFixed( this._precision() ) );
// Clamp the value
if ( options.max !== null && value > options.max ) {
return options.max;
}
if ( options.min !== null && value < options.min ) {
return options.min;
}
return value;
},
_stop: function( event ) {
if ( !this.spinning ) {
return;
}
clearTimeout( this.timer );
clearTimeout( this.mousewheelTimer );
this.counter = 0;
this.spinning = false;
this._trigger( "stop", event );
},
_setOption: function( key, value ) {
var prevValue, first, last;
if ( key === "culture" || key === "numberFormat" ) {
prevValue = this._parse( this.element.val() );
this.options[ key ] = value;
this.element.val( this._format( prevValue ) );
return;
}
if ( key === "max" || key === "min" || key === "step" ) {
if ( typeof value === "string" ) {
value = this._parse( value );
}
}
if ( key === "icons" ) {
first = this.buttons.first().find( ".ui-icon" );
this._removeClass( first, null, this.options.icons.up );
this._addClass( first, null, value.up );
last = this.buttons.last().find( ".ui-icon" );
this._removeClass( last, null, this.options.icons.down );
this._addClass( last, null, value.down );
}
this._super( key, value );
},
_setOptionDisabled: function( value ) {
this._super( value );
this._toggleClass( this.uiSpinner, null, "ui-state-disabled", !!value );
this.element.prop( "disabled", !!value );
this.buttons.button( value ? "disable" : "enable" );
},
_setOptions: spinnerModifer( function( options ) {
this._super( options );
} ),
_parse: function( val ) {
if ( typeof val === "string" && val !== "" ) {
val = window.Globalize && this.options.numberFormat ?
Globalize.parseFloat( val, 10, this.options.culture ) : +val;
}
return val === "" || isNaN( val ) ? null : val;
},
_format: function( value ) {
if ( value === "" ) {
return "";
}
return window.Globalize && this.options.numberFormat ?
Globalize.format( value, this.options.numberFormat, this.options.culture ) :
value;
},
_refresh: function() {
this.element.attr( {
"aria-valuemin": this.options.min,
"aria-valuemax": this.options.max,
// TODO: what should we do with values that can't be parsed?
"aria-valuenow": this._parse( this.element.val() )
} );
},
isValid: function() {
var value = this.value();
// Null is invalid
if ( value === null ) {
return false;
}
// If value gets adjusted, it's invalid
return value === this._adjustValue( value );
},
// Update the value without triggering change
_value: function( value, allowAny ) {
var parsed;
if ( value !== "" ) {
parsed = this._parse( value );
if ( parsed !== null ) {
if ( !allowAny ) {
parsed = this._adjustValue( parsed );
}
value = this._format( parsed );
}
}
this.element.val( value );
this._refresh();
},
_destroy: function() {
this.element
.prop( "disabled", false )
.removeAttr( "autocomplete role aria-valuemin aria-valuemax aria-valuenow" );
this.uiSpinner.replaceWith( this.element );
},
stepUp: spinnerModifer( function( steps ) {
this._stepUp( steps );
} ),
_stepUp: function( steps ) {
if ( this._start() ) {
this._spin( ( steps || 1 ) * this.options.step );
this._stop();
}
},
stepDown: spinnerModifer( function( steps ) {
this._stepDown( steps );
} ),
_stepDown: function( steps ) {
if ( this._start() ) {
this._spin( ( steps || 1 ) * -this.options.step );
this._stop();
}
},
pageUp: spinnerModifer( function( pages ) {
this._stepUp( ( pages || 1 ) * this.options.page );
} ),
pageDown: spinnerModifer( function( pages ) {
this._stepDown( ( pages || 1 ) * this.options.page );
} ),
value: function( newVal ) {
if ( !arguments.length ) {
return this._parse( this.element.val() );
}
spinnerModifer( this._value ).call( this, newVal );
},
widget: function() {
return this.uiSpinner;
}
} );
// DEPRECATED
// TODO: switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for spinner html extension points
$.widget( "ui.spinner", $.ui.spinner, {
_enhance: function() {
this.uiSpinner = this.element
.attr( "autocomplete", "off" )
.wrap( this._uiSpinnerHtml() )
.parent()
// Add buttons
.append( this._buttonHtml() );
},
_uiSpinnerHtml: function() {
return "<span>";
},
_buttonHtml: function() {
return "<a></a><a></a>";
}
} );
}
var widgetsSpinner = $.ui.spinner;
/*!
* jQuery UI Tabs 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Tabs
//>>group: Widgets
//>>description: Transforms a set of container elements into a tab structure.
//>>docs: http://api.jqueryui.com/tabs/
//>>demos: http://jqueryui.com/tabs/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/tabs.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.tabs", {
version: "1.12.1",
delay: 300,
options: {
active: null,
classes: {
"ui-tabs": "ui-corner-all",
"ui-tabs-nav": "ui-corner-all",
"ui-tabs-panel": "ui-corner-bottom",
"ui-tabs-tab": "ui-corner-top"
},
collapsible: false,
event: "click",
heightStyle: "content",
hide: null,
show: null,
// Callbacks
activate: null,
beforeActivate: null,
beforeLoad: null,
load: null
},
_isLocal: ( function() {
var rhash = /#.*$/;
return function( anchor ) {
var anchorUrl, locationUrl;
anchorUrl = anchor.href.replace( rhash, "" );
locationUrl = location.href.replace( rhash, "" );
// Decoding may throw an error if the URL isn't UTF-8 (#9518)
try {
anchorUrl = decodeURIComponent( anchorUrl );
} catch ( error ) {}
try {
locationUrl = decodeURIComponent( locationUrl );
} catch ( error ) {}
return anchor.hash.length > 1 && anchorUrl === locationUrl;
};
} )(),
_create: function() {
var that = this,
options = this.options;
this.running = false;
this._addClass( "ui-tabs", "ui-widget ui-widget-content" );
this._toggleClass( "ui-tabs-collapsible", null, options.collapsible );
this._processTabs();
options.active = this._initialActive();
// Take disabling tabs via class attribute from HTML
// into account and update option properly.
if ( $.isArray( options.disabled ) ) {
options.disabled = $.unique( options.disabled.concat(
$.map( this.tabs.filter( ".ui-state-disabled" ), function( li ) {
return that.tabs.index( li );
} )
) ).sort();
}
// Check for length avoids error when initializing empty list
if ( this.options.active !== false && this.anchors.length ) {
this.active = this._findActive( options.active );
} else {
this.active = $();
}
this._refresh();
if ( this.active.length ) {
this.load( options.active );
}
},
_initialActive: function() {
var active = this.options.active,
collapsible = this.options.collapsible,
locationHash = location.hash.substring( 1 );
if ( active === null ) {
// check the fragment identifier in the URL
if ( locationHash ) {
this.tabs.each( function( i, tab ) {
if ( $( tab ).attr( "aria-controls" ) === locationHash ) {
active = i;
return false;
}
} );
}
// Check for a tab marked active via a class
if ( active === null ) {
active = this.tabs.index( this.tabs.filter( ".ui-tabs-active" ) );
}
// No active tab, set to false
if ( active === null || active === -1 ) {
active = this.tabs.length ? 0 : false;
}
}
// Handle numbers: negative, out of range
if ( active !== false ) {
active = this.tabs.index( this.tabs.eq( active ) );
if ( active === -1 ) {
active = collapsible ? false : 0;
}
}
// Don't allow collapsible: false and active: false
if ( !collapsible && active === false && this.anchors.length ) {
active = 0;
}
return active;
},
_getCreateEventData: function() {
return {
tab: this.active,
panel: !this.active.length ? $() : this._getPanelForTab( this.active )
};
},
_tabKeydown: function( event ) {
var focusedTab = $( $.ui.safeActiveElement( this.document[ 0 ] ) ).closest( "li" ),
selectedIndex = this.tabs.index( focusedTab ),
goingForward = true;
if ( this._handlePageNav( event ) ) {
return;
}
switch ( event.keyCode ) {
case $.ui.keyCode.RIGHT:
case $.ui.keyCode.DOWN:
selectedIndex++;
break;
case $.ui.keyCode.UP:
case $.ui.keyCode.LEFT:
goingForward = false;
selectedIndex--;
break;
case $.ui.keyCode.END:
selectedIndex = this.anchors.length - 1;
break;
case $.ui.keyCode.HOME:
selectedIndex = 0;
break;
case $.ui.keyCode.SPACE:
// Activate only, no collapsing
event.preventDefault();
clearTimeout( this.activating );
this._activate( selectedIndex );
return;
case $.ui.keyCode.ENTER:
// Toggle (cancel delayed activation, allow collapsing)
event.preventDefault();
clearTimeout( this.activating );
// Determine if we should collapse or activate
this._activate( selectedIndex === this.options.active ? false : selectedIndex );
return;
default:
return;
}
// Focus the appropriate tab, based on which key was pressed
event.preventDefault();
clearTimeout( this.activating );
selectedIndex = this._focusNextTab( selectedIndex, goingForward );
// Navigating with control/command key will prevent automatic activation
if ( !event.ctrlKey && !event.metaKey ) {
// Update aria-selected immediately so that AT think the tab is already selected.
// Otherwise AT may confuse the user by stating that they need to activate the tab,
// but the tab will already be activated by the time the announcement finishes.
focusedTab.attr( "aria-selected", "false" );
this.tabs.eq( selectedIndex ).attr( "aria-selected", "true" );
this.activating = this._delay( function() {
this.option( "active", selectedIndex );
}, this.delay );
}
},
_panelKeydown: function( event ) {
if ( this._handlePageNav( event ) ) {
return;
}
// Ctrl+up moves focus to the current tab
if ( event.ctrlKey && event.keyCode === $.ui.keyCode.UP ) {
event.preventDefault();
this.active.trigger( "focus" );
}
},
// Alt+page up/down moves focus to the previous/next tab (and activates)
_handlePageNav: function( event ) {
if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_UP ) {
this._activate( this._focusNextTab( this.options.active - 1, false ) );
return true;
}
if ( event.altKey && event.keyCode === $.ui.keyCode.PAGE_DOWN ) {
this._activate( this._focusNextTab( this.options.active + 1, true ) );
return true;
}
},
_findNextTab: function( index, goingForward ) {
var lastTabIndex = this.tabs.length - 1;
function constrain() {
if ( index > lastTabIndex ) {
index = 0;
}
if ( index < 0 ) {
index = lastTabIndex;
}
return index;
}
while ( $.inArray( constrain(), this.options.disabled ) !== -1 ) {
index = goingForward ? index + 1 : index - 1;
}
return index;
},
_focusNextTab: function( index, goingForward ) {
index = this._findNextTab( index, goingForward );
this.tabs.eq( index ).trigger( "focus" );
return index;
},
_setOption: function( key, value ) {
if ( key === "active" ) {
// _activate() will handle invalid values and update this.options
this._activate( value );
return;
}
this._super( key, value );
if ( key === "collapsible" ) {
this._toggleClass( "ui-tabs-collapsible", null, value );
// Setting collapsible: false while collapsed; open first panel
if ( !value && this.options.active === false ) {
this._activate( 0 );
}
}
if ( key === "event" ) {
this._setupEvents( value );
}
if ( key === "heightStyle" ) {
this._setupHeightStyle( value );
}
},
_sanitizeSelector: function( hash ) {
return hash ? hash.replace( /[!"$%&'()*+,.\/:;<=>?@\[\]\^`{|}~]/g, "\\$&" ) : "";
},
refresh: function() {
var options = this.options,
lis = this.tablist.children( ":has(a[href])" );
// Get disabled tabs from class attribute from HTML
// this will get converted to a boolean if needed in _refresh()
options.disabled = $.map( lis.filter( ".ui-state-disabled" ), function( tab ) {
return lis.index( tab );
} );
this._processTabs();
// Was collapsed or no tabs
if ( options.active === false || !this.anchors.length ) {
options.active = false;
this.active = $();
// was active, but active tab is gone
} else if ( this.active.length && !$.contains( this.tablist[ 0 ], this.active[ 0 ] ) ) {
// all remaining tabs are disabled
if ( this.tabs.length === options.disabled.length ) {
options.active = false;
this.active = $();
// activate previous tab
} else {
this._activate( this._findNextTab( Math.max( 0, options.active - 1 ), false ) );
}
// was active, active tab still exists
} else {
// make sure active index is correct
options.active = this.tabs.index( this.active );
}
this._refresh();
},
_refresh: function() {
this._setOptionDisabled( this.options.disabled );
this._setupEvents( this.options.event );
this._setupHeightStyle( this.options.heightStyle );
this.tabs.not( this.active ).attr( {
"aria-selected": "false",
"aria-expanded": "false",
tabIndex: -1
} );
this.panels.not( this._getPanelForTab( this.active ) )
.hide()
.attr( {
"aria-hidden": "true"
} );
// Make sure one tab is in the tab order
if ( !this.active.length ) {
this.tabs.eq( 0 ).attr( "tabIndex", 0 );
} else {
this.active
.attr( {
"aria-selected": "true",
"aria-expanded": "true",
tabIndex: 0
} );
this._addClass( this.active, "ui-tabs-active", "ui-state-active" );
this._getPanelForTab( this.active )
.show()
.attr( {
"aria-hidden": "false"
} );
}
},
_processTabs: function() {
var that = this,
prevTabs = this.tabs,
prevAnchors = this.anchors,
prevPanels = this.panels;
this.tablist = this._getList().attr( "role", "tablist" );
this._addClass( this.tablist, "ui-tabs-nav",
"ui-helper-reset ui-helper-clearfix ui-widget-header" );
// Prevent users from focusing disabled tabs via click
this.tablist
.on( "mousedown" + this.eventNamespace, "> li", function( event ) {
if ( $( this ).is( ".ui-state-disabled" ) ) {
event.preventDefault();
}
} )
// Support: IE <9
// Preventing the default action in mousedown doesn't prevent IE
// from focusing the element, so if the anchor gets focused, blur.
// We don't have to worry about focusing the previously focused
// element since clicking on a non-focusable element should focus
// the body anyway.
.on( "focus" + this.eventNamespace, ".ui-tabs-anchor", function() {
if ( $( this ).closest( "li" ).is( ".ui-state-disabled" ) ) {
this.blur();
}
} );
this.tabs = this.tablist.find( "> li:has(a[href])" )
.attr( {
role: "tab",
tabIndex: -1
} );
this._addClass( this.tabs, "ui-tabs-tab", "ui-state-default" );
this.anchors = this.tabs.map( function() {
return $( "a", this )[ 0 ];
} )
.attr( {
role: "presentation",
tabIndex: -1
} );
this._addClass( this.anchors, "ui-tabs-anchor" );
this.panels = $();
this.anchors.each( function( i, anchor ) {
var selector, panel, panelId,
anchorId = $( anchor ).uniqueId().attr( "id" ),
tab = $( anchor ).closest( "li" ),
originalAriaControls = tab.attr( "aria-controls" );
// Inline tab
if ( that._isLocal( anchor ) ) {
selector = anchor.hash;
panelId = selector.substring( 1 );
panel = that.element.find( that._sanitizeSelector( selector ) );
// remote tab
} else {
// If the tab doesn't already have aria-controls,
// generate an id by using a throw-away element
panelId = tab.attr( "aria-controls" ) || $( {} ).uniqueId()[ 0 ].id;
selector = "#" + panelId;
panel = that.element.find( selector );
if ( !panel.length ) {
panel = that._createPanel( panelId );
panel.insertAfter( that.panels[ i - 1 ] || that.tablist );
}
panel.attr( "aria-live", "polite" );
}
if ( panel.length ) {
that.panels = that.panels.add( panel );
}
if ( originalAriaControls ) {
tab.data( "ui-tabs-aria-controls", originalAriaControls );
}
tab.attr( {
"aria-controls": panelId,
"aria-labelledby": anchorId
} );
panel.attr( "aria-labelledby", anchorId );
} );
this.panels.attr( "role", "tabpanel" );
this._addClass( this.panels, "ui-tabs-panel", "ui-widget-content" );
// Avoid memory leaks (#10056)
if ( prevTabs ) {
this._off( prevTabs.not( this.tabs ) );
this._off( prevAnchors.not( this.anchors ) );
this._off( prevPanels.not( this.panels ) );
}
},
// Allow overriding how to find the list for rare usage scenarios (#7715)
_getList: function() {
return this.tablist || this.element.find( "ol, ul" ).eq( 0 );
},
_createPanel: function( id ) {
return $( "<div>" )
.attr( "id", id )
.data( "ui-tabs-destroy", true );
},
_setOptionDisabled: function( disabled ) {
var currentItem, li, i;
if ( $.isArray( disabled ) ) {
if ( !disabled.length ) {
disabled = false;
} else if ( disabled.length === this.anchors.length ) {
disabled = true;
}
}
// Disable tabs
for ( i = 0; ( li = this.tabs[ i ] ); i++ ) {
currentItem = $( li );
if ( disabled === true || $.inArray( i, disabled ) !== -1 ) {
currentItem.attr( "aria-disabled", "true" );
this._addClass( currentItem, null, "ui-state-disabled" );
} else {
currentItem.removeAttr( "aria-disabled" );
this._removeClass( currentItem, null, "ui-state-disabled" );
}
}
this.options.disabled = disabled;
this._toggleClass( this.widget(), this.widgetFullName + "-disabled", null,
disabled === true );
},
_setupEvents: function( event ) {
var events = {};
if ( event ) {
$.each( event.split( " " ), function( index, eventName ) {
events[ eventName ] = "_eventHandler";
} );
}
this._off( this.anchors.add( this.tabs ).add( this.panels ) );
// Always prevent the default action, even when disabled
this._on( true, this.anchors, {
click: function( event ) {
event.preventDefault();
}
} );
this._on( this.anchors, events );
this._on( this.tabs, { keydown: "_tabKeydown" } );
this._on( this.panels, { keydown: "_panelKeydown" } );
this._focusable( this.tabs );
this._hoverable( this.tabs );
},
_setupHeightStyle: function( heightStyle ) {
var maxHeight,
parent = this.element.parent();
if ( heightStyle === "fill" ) {
maxHeight = parent.height();
maxHeight -= this.element.outerHeight() - this.element.height();
this.element.siblings( ":visible" ).each( function() {
var elem = $( this ),
position = elem.css( "position" );
if ( position === "absolute" || position === "fixed" ) {
return;
}
maxHeight -= elem.outerHeight( true );
} );
this.element.children().not( this.panels ).each( function() {
maxHeight -= $( this ).outerHeight( true );
} );
this.panels.each( function() {
$( this ).height( Math.max( 0, maxHeight -
$( this ).innerHeight() + $( this ).height() ) );
} )
.css( "overflow", "auto" );
} else if ( heightStyle === "auto" ) {
maxHeight = 0;
this.panels.each( function() {
maxHeight = Math.max( maxHeight, $( this ).height( "" ).height() );
} ).height( maxHeight );
}
},
_eventHandler: function( event ) {
var options = this.options,
active = this.active,
anchor = $( event.currentTarget ),
tab = anchor.closest( "li" ),
clickedIsActive = tab[ 0 ] === active[ 0 ],
collapsing = clickedIsActive && options.collapsible,
toShow = collapsing ? $() : this._getPanelForTab( tab ),
toHide = !active.length ? $() : this._getPanelForTab( active ),
eventData = {
oldTab: active,
oldPanel: toHide,
newTab: collapsing ? $() : tab,
newPanel: toShow
};
event.preventDefault();
if ( tab.hasClass( "ui-state-disabled" ) ||
// tab is already loading
tab.hasClass( "ui-tabs-loading" ) ||
// can't switch durning an animation
this.running ||
// click on active header, but not collapsible
( clickedIsActive && !options.collapsible ) ||
// allow canceling activation
( this._trigger( "beforeActivate", event, eventData ) === false ) ) {
return;
}
options.active = collapsing ? false : this.tabs.index( tab );
this.active = clickedIsActive ? $() : tab;
if ( this.xhr ) {
this.xhr.abort();
}
if ( !toHide.length && !toShow.length ) {
$.error( "jQuery UI Tabs: Mismatching fragment identifier." );
}
if ( toShow.length ) {
this.load( this.tabs.index( tab ), event );
}
this._toggle( event, eventData );
},
// Handles show/hide for selecting tabs
_toggle: function( event, eventData ) {
var that = this,
toShow = eventData.newPanel,
toHide = eventData.oldPanel;
this.running = true;
function complete() {
that.running = false;
that._trigger( "activate", event, eventData );
}
function show() {
that._addClass( eventData.newTab.closest( "li" ), "ui-tabs-active", "ui-state-active" );
if ( toShow.length && that.options.show ) {
that._show( toShow, that.options.show, complete );
} else {
toShow.show();
complete();
}
}
// Start out by hiding, then showing, then completing
if ( toHide.length && this.options.hide ) {
this._hide( toHide, this.options.hide, function() {
that._removeClass( eventData.oldTab.closest( "li" ),
"ui-tabs-active", "ui-state-active" );
show();
} );
} else {
this._removeClass( eventData.oldTab.closest( "li" ),
"ui-tabs-active", "ui-state-active" );
toHide.hide();
show();
}
toHide.attr( "aria-hidden", "true" );
eventData.oldTab.attr( {
"aria-selected": "false",
"aria-expanded": "false"
} );
// If we're switching tabs, remove the old tab from the tab order.
// If we're opening from collapsed state, remove the previous tab from the tab order.
// If we're collapsing, then keep the collapsing tab in the tab order.
if ( toShow.length && toHide.length ) {
eventData.oldTab.attr( "tabIndex", -1 );
} else if ( toShow.length ) {
this.tabs.filter( function() {
return $( this ).attr( "tabIndex" ) === 0;
} )
.attr( "tabIndex", -1 );
}
toShow.attr( "aria-hidden", "false" );
eventData.newTab.attr( {
"aria-selected": "true",
"aria-expanded": "true",
tabIndex: 0
} );
},
_activate: function( index ) {
var anchor,
active = this._findActive( index );
// Trying to activate the already active panel
if ( active[ 0 ] === this.active[ 0 ] ) {
return;
}
// Trying to collapse, simulate a click on the current active header
if ( !active.length ) {
active = this.active;
}
anchor = active.find( ".ui-tabs-anchor" )[ 0 ];
this._eventHandler( {
target: anchor,
currentTarget: anchor,
preventDefault: $.noop
} );
},
_findActive: function( index ) {
return index === false ? $() : this.tabs.eq( index );
},
_getIndex: function( index ) {
// meta-function to give users option to provide a href string instead of a numerical index.
if ( typeof index === "string" ) {
index = this.anchors.index( this.anchors.filter( "[href$='" +
$.ui.escapeSelector( index ) + "']" ) );
}
return index;
},
_destroy: function() {
if ( this.xhr ) {
this.xhr.abort();
}
this.tablist
.removeAttr( "role" )
.off( this.eventNamespace );
this.anchors
.removeAttr( "role tabIndex" )
.removeUniqueId();
this.tabs.add( this.panels ).each( function() {
if ( $.data( this, "ui-tabs-destroy" ) ) {
$( this ).remove();
} else {
$( this ).removeAttr( "role tabIndex " +
"aria-live aria-busy aria-selected aria-labelledby aria-hidden aria-expanded" );
}
} );
this.tabs.each( function() {
var li = $( this ),
prev = li.data( "ui-tabs-aria-controls" );
if ( prev ) {
li
.attr( "aria-controls", prev )
.removeData( "ui-tabs-aria-controls" );
} else {
li.removeAttr( "aria-controls" );
}
} );
this.panels.show();
if ( this.options.heightStyle !== "content" ) {
this.panels.css( "height", "" );
}
},
enable: function( index ) {
var disabled = this.options.disabled;
if ( disabled === false ) {
return;
}
if ( index === undefined ) {
disabled = false;
} else {
index = this._getIndex( index );
if ( $.isArray( disabled ) ) {
disabled = $.map( disabled, function( num ) {
return num !== index ? num : null;
} );
} else {
disabled = $.map( this.tabs, function( li, num ) {
return num !== index ? num : null;
} );
}
}
this._setOptionDisabled( disabled );
},
disable: function( index ) {
var disabled = this.options.disabled;
if ( disabled === true ) {
return;
}
if ( index === undefined ) {
disabled = true;
} else {
index = this._getIndex( index );
if ( $.inArray( index, disabled ) !== -1 ) {
return;
}
if ( $.isArray( disabled ) ) {
disabled = $.merge( [ index ], disabled ).sort();
} else {
disabled = [ index ];
}
}
this._setOptionDisabled( disabled );
},
load: function( index, event ) {
index = this._getIndex( index );
var that = this,
tab = this.tabs.eq( index ),
anchor = tab.find( ".ui-tabs-anchor" ),
panel = this._getPanelForTab( tab ),
eventData = {
tab: tab,
panel: panel
},
complete = function( jqXHR, status ) {
if ( status === "abort" ) {
that.panels.stop( false, true );
}
that._removeClass( tab, "ui-tabs-loading" );
panel.removeAttr( "aria-busy" );
if ( jqXHR === that.xhr ) {
delete that.xhr;
}
};
// Not remote
if ( this._isLocal( anchor[ 0 ] ) ) {
return;
}
this.xhr = $.ajax( this._ajaxSettings( anchor, event, eventData ) );
// Support: jQuery <1.8
// jQuery <1.8 returns false if the request is canceled in beforeSend,
// but as of 1.8, $.ajax() always returns a jqXHR object.
if ( this.xhr && this.xhr.statusText !== "canceled" ) {
this._addClass( tab, "ui-tabs-loading" );
panel.attr( "aria-busy", "true" );
this.xhr
.done( function( response, status, jqXHR ) {
// support: jQuery <1.8
// http://bugs.jquery.com/ticket/11778
setTimeout( function() {
panel.html( response );
that._trigger( "load", event, eventData );
complete( jqXHR, status );
}, 1 );
} )
.fail( function( jqXHR, status ) {
// support: jQuery <1.8
// http://bugs.jquery.com/ticket/11778
setTimeout( function() {
complete( jqXHR, status );
}, 1 );
} );
}
},
_ajaxSettings: function( anchor, event, eventData ) {
var that = this;
return {
// Support: IE <11 only
// Strip any hash that exists to prevent errors with the Ajax request
url: anchor.attr( "href" ).replace( /#.*$/, "" ),
beforeSend: function( jqXHR, settings ) {
return that._trigger( "beforeLoad", event,
$.extend( { jqXHR: jqXHR, ajaxSettings: settings }, eventData ) );
}
};
},
_getPanelForTab: function( tab ) {
var id = $( tab ).attr( "aria-controls" );
return this.element.find( this._sanitizeSelector( "#" + id ) );
}
} );
// DEPRECATED
// TODO: Switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for ui-tab class (now ui-tabs-tab)
$.widget( "ui.tabs", $.ui.tabs, {
_processTabs: function() {
this._superApply( arguments );
this._addClass( this.tabs, "ui-tab" );
}
} );
}
var widgetsTabs = $.ui.tabs;
/*!
* jQuery UI Tooltip 1.12.1
* http://jqueryui.com
*
* Copyright jQuery Foundation and other contributors
* Released under the MIT license.
* http://jquery.org/license
*/
//>>label: Tooltip
//>>group: Widgets
//>>description: Shows additional information for any element on hover or focus.
//>>docs: http://api.jqueryui.com/tooltip/
//>>demos: http://jqueryui.com/tooltip/
//>>css.structure: ../../themes/base/core.css
//>>css.structure: ../../themes/base/tooltip.css
//>>css.theme: ../../themes/base/theme.css
$.widget( "ui.tooltip", {
version: "1.12.1",
options: {
classes: {
"ui-tooltip": "ui-corner-all ui-widget-shadow"
},
content: function() {
// support: IE<9, Opera in jQuery <1.7
// .text() can't accept undefined, so coerce to a string
var title = $( this ).attr( "title" ) || "";
// Escape title, since we're going from an attribute to raw HTML
return $( "<a>" ).text( title ).html();
},
hide: true,
// Disabled elements have inconsistent behavior across browsers (#8661)
items: "[title]:not([disabled])",
position: {
my: "left top+15",
at: "left bottom",
collision: "flipfit flip"
},
show: true,
track: false,
// Callbacks
close: null,
open: null
},
_addDescribedBy: function( elem, id ) {
var describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ );
describedby.push( id );
elem
.data( "ui-tooltip-id", id )
.attr( "aria-describedby", $.trim( describedby.join( " " ) ) );
},
_removeDescribedBy: function( elem ) {
var id = elem.data( "ui-tooltip-id" ),
describedby = ( elem.attr( "aria-describedby" ) || "" ).split( /\s+/ ),
index = $.inArray( id, describedby );
if ( index !== -1 ) {
describedby.splice( index, 1 );
}
elem.removeData( "ui-tooltip-id" );
describedby = $.trim( describedby.join( " " ) );
if ( describedby ) {
elem.attr( "aria-describedby", describedby );
} else {
elem.removeAttr( "aria-describedby" );
}
},
_create: function() {
this._on( {
mouseover: "open",
focusin: "open"
} );
// IDs of generated tooltips, needed for destroy
this.tooltips = {};
// IDs of parent tooltips where we removed the title attribute
this.parents = {};
// Append the aria-live region so tooltips announce correctly
this.liveRegion = $( "<div>" )
.attr( {
role: "log",
"aria-live": "assertive",
"aria-relevant": "additions"
} )
.appendTo( this.document[ 0 ].body );
this._addClass( this.liveRegion, null, "ui-helper-hidden-accessible" );
this.disabledTitles = $( [] );
},
_setOption: function( key, value ) {
var that = this;
this._super( key, value );
if ( key === "content" ) {
$.each( this.tooltips, function( id, tooltipData ) {
that._updateContent( tooltipData.element );
} );
}
},
_setOptionDisabled: function( value ) {
this[ value ? "_disable" : "_enable" ]();
},
_disable: function() {
var that = this;
// Close open tooltips
$.each( this.tooltips, function( id, tooltipData ) {
var event = $.Event( "blur" );
event.target = event.currentTarget = tooltipData.element[ 0 ];
that.close( event, true );
} );
// Remove title attributes to prevent native tooltips
this.disabledTitles = this.disabledTitles.add(
this.element.find( this.options.items ).addBack()
.filter( function() {
var element = $( this );
if ( element.is( "[title]" ) ) {
return element
.data( "ui-tooltip-title", element.attr( "title" ) )
.removeAttr( "title" );
}
} )
);
},
_enable: function() {
// restore title attributes
this.disabledTitles.each( function() {
var element = $( this );
if ( element.data( "ui-tooltip-title" ) ) {
element.attr( "title", element.data( "ui-tooltip-title" ) );
}
} );
this.disabledTitles = $( [] );
},
open: function( event ) {
var that = this,
target = $( event ? event.target : this.element )
// we need closest here due to mouseover bubbling,
// but always pointing at the same event target
.closest( this.options.items );
// No element to show a tooltip for or the tooltip is already open
if ( !target.length || target.data( "ui-tooltip-id" ) ) {
return;
}
if ( target.attr( "title" ) ) {
target.data( "ui-tooltip-title", target.attr( "title" ) );
}
target.data( "ui-tooltip-open", true );
// Kill parent tooltips, custom or native, for hover
if ( event && event.type === "mouseover" ) {
target.parents().each( function() {
var parent = $( this ),
blurEvent;
if ( parent.data( "ui-tooltip-open" ) ) {
blurEvent = $.Event( "blur" );
blurEvent.target = blurEvent.currentTarget = this;
that.close( blurEvent, true );
}
if ( parent.attr( "title" ) ) {
parent.uniqueId();
that.parents[ this.id ] = {
element: this,
title: parent.attr( "title" )
};
parent.attr( "title", "" );
}
} );
}
this._registerCloseHandlers( event, target );
this._updateContent( target, event );
},
_updateContent: function( target, event ) {
var content,
contentOption = this.options.content,
that = this,
eventType = event ? event.type : null;
if ( typeof contentOption === "string" || contentOption.nodeType ||
contentOption.jquery ) {
return this._open( event, target, contentOption );
}
content = contentOption.call( target[ 0 ], function( response ) {
// IE may instantly serve a cached response for ajax requests
// delay this call to _open so the other call to _open runs first
that._delay( function() {
// Ignore async response if tooltip was closed already
if ( !target.data( "ui-tooltip-open" ) ) {
return;
}
// JQuery creates a special event for focusin when it doesn't
// exist natively. To improve performance, the native event
// object is reused and the type is changed. Therefore, we can't
// rely on the type being correct after the event finished
// bubbling, so we set it back to the previous value. (#8740)
if ( event ) {
event.type = eventType;
}
this._open( event, target, response );
} );
} );
if ( content ) {
this._open( event, target, content );
}
},
_open: function( event, target, content ) {
var tooltipData, tooltip, delayedShow, a11yContent,
positionOption = $.extend( {}, this.options.position );
if ( !content ) {
return;
}
// Content can be updated multiple times. If the tooltip already
// exists, then just update the content and bail.
tooltipData = this._find( target );
if ( tooltipData ) {
tooltipData.tooltip.find( ".ui-tooltip-content" ).html( content );
return;
}
// If we have a title, clear it to prevent the native tooltip
// we have to check first to avoid defining a title if none exists
// (we don't want to cause an element to start matching [title])
//
// We use removeAttr only for key events, to allow IE to export the correct
// accessible attributes. For mouse events, set to empty string to avoid
// native tooltip showing up (happens only when removing inside mouseover).
if ( target.is( "[title]" ) ) {
if ( event && event.type === "mouseover" ) {
target.attr( "title", "" );
} else {
target.removeAttr( "title" );
}
}
tooltipData = this._tooltip( target );
tooltip = tooltipData.tooltip;
this._addDescribedBy( target, tooltip.attr( "id" ) );
tooltip.find( ".ui-tooltip-content" ).html( content );
// Support: Voiceover on OS X, JAWS on IE <= 9
// JAWS announces deletions even when aria-relevant="additions"
// Voiceover will sometimes re-read the entire log region's contents from the beginning
this.liveRegion.children().hide();
a11yContent = $( "<div>" ).html( tooltip.find( ".ui-tooltip-content" ).html() );
a11yContent.removeAttr( "name" ).find( "[name]" ).removeAttr( "name" );
a11yContent.removeAttr( "id" ).find( "[id]" ).removeAttr( "id" );
a11yContent.appendTo( this.liveRegion );
function position( event ) {
positionOption.of = event;
if ( tooltip.is( ":hidden" ) ) {
return;
}
tooltip.position( positionOption );
}
if ( this.options.track && event && /^mouse/.test( event.type ) ) {
this._on( this.document, {
mousemove: position
} );
// trigger once to override element-relative positioning
position( event );
} else {
tooltip.position( $.extend( {
of: target
}, this.options.position ) );
}
tooltip.hide();
this._show( tooltip, this.options.show );
// Handle tracking tooltips that are shown with a delay (#8644). As soon
// as the tooltip is visible, position the tooltip using the most recent
// event.
// Adds the check to add the timers only when both delay and track options are set (#14682)
if ( this.options.track && this.options.show && this.options.show.delay ) {
delayedShow = this.delayedShow = setInterval( function() {
if ( tooltip.is( ":visible" ) ) {
position( positionOption.of );
clearInterval( delayedShow );
}
}, $.fx.interval );
}
this._trigger( "open", event, { tooltip: tooltip } );
},
_registerCloseHandlers: function( event, target ) {
var events = {
keyup: function( event ) {
if ( event.keyCode === $.ui.keyCode.ESCAPE ) {
var fakeEvent = $.Event( event );
fakeEvent.currentTarget = target[ 0 ];
this.close( fakeEvent, true );
}
}
};
// Only bind remove handler for delegated targets. Non-delegated
// tooltips will handle this in destroy.
if ( target[ 0 ] !== this.element[ 0 ] ) {
events.remove = function() {
this._removeTooltip( this._find( target ).tooltip );
};
}
if ( !event || event.type === "mouseover" ) {
events.mouseleave = "close";
}
if ( !event || event.type === "focusin" ) {
events.focusout = "close";
}
this._on( true, target, events );
},
close: function( event ) {
var tooltip,
that = this,
target = $( event ? event.currentTarget : this.element ),
tooltipData = this._find( target );
// The tooltip may already be closed
if ( !tooltipData ) {
// We set ui-tooltip-open immediately upon open (in open()), but only set the
// additional data once there's actually content to show (in _open()). So even if the
// tooltip doesn't have full data, we always remove ui-tooltip-open in case we're in
// the period between open() and _open().
target.removeData( "ui-tooltip-open" );
return;
}
tooltip = tooltipData.tooltip;
// Disabling closes the tooltip, so we need to track when we're closing
// to avoid an infinite loop in case the tooltip becomes disabled on close
if ( tooltipData.closing ) {
return;
}
// Clear the interval for delayed tracking tooltips
clearInterval( this.delayedShow );
// Only set title if we had one before (see comment in _open())
// If the title attribute has changed since open(), don't restore
if ( target.data( "ui-tooltip-title" ) && !target.attr( "title" ) ) {
target.attr( "title", target.data( "ui-tooltip-title" ) );
}
this._removeDescribedBy( target );
tooltipData.hiding = true;
tooltip.stop( true );
this._hide( tooltip, this.options.hide, function() {
that._removeTooltip( $( this ) );
} );
target.removeData( "ui-tooltip-open" );
this._off( target, "mouseleave focusout keyup" );
// Remove 'remove' binding only on delegated targets
if ( target[ 0 ] !== this.element[ 0 ] ) {
this._off( target, "remove" );
}
this._off( this.document, "mousemove" );
if ( event && event.type === "mouseleave" ) {
$.each( this.parents, function( id, parent ) {
$( parent.element ).attr( "title", parent.title );
delete that.parents[ id ];
} );
}
tooltipData.closing = true;
this._trigger( "close", event, { tooltip: tooltip } );
if ( !tooltipData.hiding ) {
tooltipData.closing = false;
}
},
_tooltip: function( element ) {
var tooltip = $( "<div>" ).attr( "role", "tooltip" ),
content = $( "<div>" ).appendTo( tooltip ),
id = tooltip.uniqueId().attr( "id" );
this._addClass( content, "ui-tooltip-content" );
this._addClass( tooltip, "ui-tooltip", "ui-widget ui-widget-content" );
tooltip.appendTo( this._appendTo( element ) );
return this.tooltips[ id ] = {
element: element,
tooltip: tooltip
};
},
_find: function( target ) {
var id = target.data( "ui-tooltip-id" );
return id ? this.tooltips[ id ] : null;
},
_removeTooltip: function( tooltip ) {
tooltip.remove();
delete this.tooltips[ tooltip.attr( "id" ) ];
},
_appendTo: function( target ) {
var element = target.closest( ".ui-front, dialog" );
if ( !element.length ) {
element = this.document[ 0 ].body;
}
return element;
},
_destroy: function() {
var that = this;
// Close open tooltips
$.each( this.tooltips, function( id, tooltipData ) {
// Delegate to close method to handle common cleanup
var event = $.Event( "blur" ),
element = tooltipData.element;
event.target = event.currentTarget = element[ 0 ];
that.close( event, true );
// Remove immediately; destroying an open tooltip doesn't use the
// hide animation
$( "#" + id ).remove();
// Restore the title
if ( element.data( "ui-tooltip-title" ) ) {
// If the title attribute has changed since open(), don't restore
if ( !element.attr( "title" ) ) {
element.attr( "title", element.data( "ui-tooltip-title" ) );
}
element.removeData( "ui-tooltip-title" );
}
} );
this.liveRegion.remove();
}
} );
// DEPRECATED
// TODO: Switch return back to widget declaration at top of file when this is removed
if ( $.uiBackCompat !== false ) {
// Backcompat for tooltipClass option
$.widget( "ui.tooltip", $.ui.tooltip, {
options: {
tooltipClass: null
},
_tooltip: function() {
var tooltipData = this._superApply( arguments );
if ( this.options.tooltipClass ) {
tooltipData.tooltip.addClass( this.options.tooltipClass );
}
return tooltipData;
}
} );
}
var widgetsTooltip = $.ui.tooltip;
}));
(function defineMustache(global,factory){if(typeof exports==="object"&&exports&&typeof exports.nodeName!=="string"){factory(exports)}else if(typeof define==="function"&&define.amd){define(["exports"],factory)}else{global.Mustache={};factory(global.Mustache)}})(this,function mustacheFactory(mustache){var objectToString=Object.prototype.toString;var isArray=Array.isArray||function isArrayPolyfill(object){return objectToString.call(object)==="[object Array]"};function isFunction(object){return typeof object==="function"}function typeStr(obj){return isArray(obj)?"array":typeof obj}function escapeRegExp(string){return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g,"\\$&")}function hasProperty(obj,propName){return obj!=null&&typeof obj==="object"&&propName in obj}var regExpTest=RegExp.prototype.test;function testRegExp(re,string){return regExpTest.call(re,string)}var nonSpaceRe=/\S/;function isWhitespace(string){return!testRegExp(nonSpaceRe,string)}var entityMap={"&":"&","<":"<",">":">",'"':""","'":"'","/":"/","`":"`","=":"="};function escapeHtml(string){return String(string).replace(/[&<>"'`=\/]/g,function fromEntityMap(s){return entityMap[s]})}var whiteRe=/\s*/;var spaceRe=/\s+/;var equalsRe=/\s*=/;var curlyRe=/\s*\}/;var tagRe=/#|\^|\/|>|\{|&|=|!/;function parseTemplate(template,tags){if(!template)return[];var sections=[];var tokens=[];var spaces=[];var hasTag=false;var nonSpace=false;function stripSpace(){if(hasTag&&!nonSpace){while(spaces.length)delete tokens[spaces.pop()]}else{spaces=[]}hasTag=false;nonSpace=false}var openingTagRe,closingTagRe,closingCurlyRe;function compileTags(tagsToCompile){if(typeof tagsToCompile==="string")tagsToCompile=tagsToCompile.split(spaceRe,2);if(!isArray(tagsToCompile)||tagsToCompile.length!==2)throw new Error("Invalid tags: "+tagsToCompile);openingTagRe=new RegExp(escapeRegExp(tagsToCompile[0])+"\\s*");closingTagRe=new RegExp("\\s*"+escapeRegExp(tagsToCompile[1]));closingCurlyRe=new RegExp("\\s*"+escapeRegExp("}"+tagsToCompile[1]))}compileTags(tags||mustache.tags);var scanner=new Scanner(template);var start,type,value,chr,token,openSection;while(!scanner.eos()){start=scanner.pos;value=scanner.scanUntil(openingTagRe);if(value){for(var i=0,valueLength=value.length;i<valueLength;++i){chr=value.charAt(i);if(isWhitespace(chr)){spaces.push(tokens.length)}else{nonSpace=true}tokens.push(["text",chr,start,start+1]);start+=1;if(chr==="\n")stripSpace()}}if(!scanner.scan(openingTagRe))break;hasTag=true;type=scanner.scan(tagRe)||"name";scanner.scan(whiteRe);if(type==="="){value=scanner.scanUntil(equalsRe);scanner.scan(equalsRe);scanner.scanUntil(closingTagRe)}else if(type==="{"){value=scanner.scanUntil(closingCurlyRe);scanner.scan(curlyRe);scanner.scanUntil(closingTagRe);type="&"}else{value=scanner.scanUntil(closingTagRe)}if(!scanner.scan(closingTagRe))throw new Error("Unclosed tag at "+scanner.pos);token=[type,value,start,scanner.pos];tokens.push(token);if(type==="#"||type==="^"){sections.push(token)}else if(type==="/"){openSection=sections.pop();if(!openSection)throw new Error('Unopened section "'+value+'" at '+start);if(openSection[1]!==value)throw new Error('Unclosed section "'+openSection[1]+'" at '+start)}else if(type==="name"||type==="{"||type==="&"){nonSpace=true}else if(type==="="){compileTags(value)}}openSection=sections.pop();if(openSection)throw new Error('Unclosed section "'+openSection[1]+'" at '+scanner.pos);return nestTokens(squashTokens(tokens))}function squashTokens(tokens){var squashedTokens=[];var token,lastToken;for(var i=0,numTokens=tokens.length;i<numTokens;++i){token=tokens[i];if(token){if(token[0]==="text"&&lastToken&&lastToken[0]==="text"){lastToken[1]+=token[1];lastToken[3]=token[3]}else{squashedTokens.push(token);lastToken=token}}}return squashedTokens}function nestTokens(tokens){var nestedTokens=[];var collector=nestedTokens;var sections=[];var token,section;for(var i=0,numTokens=tokens.length;i<numTokens;++i){token=tokens[i];switch(token[0]){case"#":case"^":collector.push(token);sections.push(token);collector=token[4]=[];break;case"/":section=sections.pop();section[5]=token[2];collector=sections.length>0?sections[sections.length-1][4]:nestedTokens;break;default:collector.push(token)}}return nestedTokens}function Scanner(string){this.string=string;this.tail=string;this.pos=0}Scanner.prototype.eos=function eos(){return this.tail===""};Scanner.prototype.scan=function scan(re){var match=this.tail.match(re);if(!match||match.index!==0)return"";var string=match[0];this.tail=this.tail.substring(string.length);this.pos+=string.length;return string};Scanner.prototype.scanUntil=function scanUntil(re){var index=this.tail.search(re),match;switch(index){case-1:match=this.tail;this.tail="";break;case 0:match="";break;default:match=this.tail.substring(0,index);this.tail=this.tail.substring(index)}this.pos+=match.length;return match};function Context(view,parentContext){this.view=view;this.cache={".":this.view};this.parent=parentContext}Context.prototype.push=function push(view){return new Context(view,this)};Context.prototype.lookup=function lookup(name){var cache=this.cache;var value;if(cache.hasOwnProperty(name)){value=cache[name]}else{var context=this,names,index,lookupHit=false;while(context){if(name.indexOf(".")>0){value=context.view;names=name.split(".");index=0;while(value!=null&&index<names.length){if(index===names.length-1)lookupHit=hasProperty(value,names[index]);value=value[names[index++]]}}else{value=context.view[name];lookupHit=hasProperty(context.view,name)}if(lookupHit)break;context=context.parent}cache[name]=value}if(isFunction(value))value=value.call(this.view);return value};function Writer(){this.cache={}}Writer.prototype.clearCache=function clearCache(){this.cache={}};Writer.prototype.parse=function parse(template,tags){var cache=this.cache;var tokens=cache[template];if(tokens==null)tokens=cache[template]=parseTemplate(template,tags);return tokens};Writer.prototype.render=function render(template,view,partials){var tokens=this.parse(template);var context=view instanceof Context?view:new Context(view);return this.renderTokens(tokens,context,partials,template)};Writer.prototype.renderTokens=function renderTokens(tokens,context,partials,originalTemplate){var buffer="";var token,symbol,value;for(var i=0,numTokens=tokens.length;i<numTokens;++i){value=undefined;token=tokens[i];symbol=token[0];if(symbol==="#")value=this.renderSection(token,context,partials,originalTemplate);else if(symbol==="^")value=this.renderInverted(token,context,partials,originalTemplate);else if(symbol===">")value=this.renderPartial(token,context,partials,originalTemplate);else if(symbol==="&")value=this.unescapedValue(token,context);else if(symbol==="name")value=this.escapedValue(token,context);else if(symbol==="text")value=this.rawValue(token);if(value!==undefined)buffer+=value}return buffer};Writer.prototype.renderSection=function renderSection(token,context,partials,originalTemplate){var self=this;var buffer="";var value=context.lookup(token[1]);function subRender(template){return self.render(template,context,partials)}if(!value)return;if(isArray(value)){for(var j=0,valueLength=value.length;j<valueLength;++j){buffer+=this.renderTokens(token[4],context.push(value[j]),partials,originalTemplate)}}else if(typeof value==="object"||typeof value==="string"||typeof value==="number"){buffer+=this.renderTokens(token[4],context.push(value),partials,originalTemplate)}else if(isFunction(value)){if(typeof originalTemplate!=="string")throw new Error("Cannot use higher-order sections without the original template");value=value.call(context.view,originalTemplate.slice(token[3],token[5]),subRender);if(value!=null)buffer+=value}else{buffer+=this.renderTokens(token[4],context,partials,originalTemplate)}return buffer};Writer.prototype.renderInverted=function renderInverted(token,context,partials,originalTemplate){var value=context.lookup(token[1]);if(!value||isArray(value)&&value.length===0)return this.renderTokens(token[4],context,partials,originalTemplate)};Writer.prototype.renderPartial=function renderPartial(token,context,partials){if(!partials)return;var value=isFunction(partials)?partials(token[1]):partials[token[1]];if(value!=null)return this.renderTokens(this.parse(value),context,partials,value)};Writer.prototype.unescapedValue=function unescapedValue(token,context){var value=context.lookup(token[1]);if(value!=null)return value};Writer.prototype.escapedValue=function escapedValue(token,context){var value=context.lookup(token[1]);if(value!=null)return mustache.escape(value)};Writer.prototype.rawValue=function rawValue(token){return token[1]};mustache.name="mustache.js";mustache.version="2.3.2";mustache.tags=["{{","}}"];var defaultWriter=new Writer;mustache.clearCache=function clearCache(){return defaultWriter.clearCache()};mustache.parse=function parse(template,tags){return defaultWriter.parse(template,tags)};mustache.render=function render(template,view,partials){if(typeof template!=="string"){throw new TypeError('Invalid template! Template should be a "string" '+'but "'+typeStr(template)+'" was given as the first '+"argument for mustache#render(template, view, partials)")}return defaultWriter.render(template,view,partials)};mustache.to_html=function to_html(template,view,partials,send){var result=mustache.render(template,view,partials);if(isFunction(send)){send(result)}else{return result}};mustache.escape=escapeHtml;mustache.Scanner=Scanner;mustache.Context=Context;mustache.Writer=Writer;return mustache});
/* globals jQuery */
(function($) {
// Selector to select only not already processed elements
$.expr[":"].notmdproc = function(obj){
if ($(obj).data("mdproc")) {
return false;
} else {
return true;
}
};
function _isChar(evt) {
if (typeof evt.which == "undefined") {
return true;
} else if (typeof evt.which == "number" && evt.which > 0) {
return !evt.ctrlKey && !evt.metaKey && !evt.altKey && evt.which != 8 && evt.which != 9;
}
return false;
}
function _addFormGroupFocus(element){
$(element).closest(".form-group").addClass("is-focused");
}
function _removeFormGroupFocus(element){
$(element).closest(".form-group").removeClass("is-focused"); // remove class from form-group
}
$.material = {
"options": {
// These options set what will be started by $.material.init()
"input": true,
"ripples": true,
"checkbox": true,
"togglebutton": true,
"radio": true,
"arrive": true,
"autofill": false,
"withRipples": [
".btn:not(.btn-link)",
".card-image",
".navbar a:not(.withoutripple)",
".dropdown-menu a",
".nav-tabs a:not(.withoutripple)",
".withripple",
".pagination li:not(.active):not(.disabled) a:not(.withoutripple)"
].join(","),
"inputElements": "input.form-control, textarea.form-control, select.form-control",
"checkboxElements": ".checkbox > label > input[type=checkbox]",
"togglebuttonElements": ".togglebutton > label > input[type=checkbox]",
"radioElements": ".radio > label > input[type=radio]"
},
"checkbox": function(selector) {
// Add fake-checkbox to material checkboxes
$((selector) ? selector : this.options.checkboxElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class='checkbox-material'><span class='check'></span></span>");
},
"togglebutton": function(selector) {
// Add fake-checkbox to material checkboxes
$((selector) ? selector : this.options.togglebuttonElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class='toggle'></span>");
},
"radio": function(selector) {
// Add fake-radio to material radios
$((selector) ? selector : this.options.radioElements)
.filter(":notmdproc")
.data("mdproc", true)
.after("<span class='circle'></span><span class='check'></span>");
},
"input": function(selector) {
$((selector) ? selector : this.options.inputElements)
.filter(":notmdproc")
.data("mdproc", true)
.each( function() {
var $input = $(this);
// Requires form-group standard markup (will add it if necessary)
var $formGroup = $input.closest(".form-group"); // note that form-group may be grandparent in the case of an input-group
if($formGroup.length === 0){
$input.wrap("<div class='form-group'></div>");
$formGroup = $input.closest(".form-group"); // find node after attached (otherwise additional attachments don't work)
}
// Legacy - Add hint label if using the old shorthand data-hint attribute on the input
if ($input.attr("data-hint")) {
$input.after("<p class='help-block'>" + $input.attr("data-hint") + "</p>");
$input.removeAttr("data-hint");
}
// Legacy - Change input-sm/lg to form-group-sm/lg instead (preferred standard and simpler css/less variants)
var legacySizes = {
"input-lg": "form-group-lg",
"input-sm": "form-group-sm"
};
$.each( legacySizes, function( legacySize, standardSize ) {
if ($input.hasClass(legacySize)) {
$input.removeClass(legacySize);
$formGroup.addClass(standardSize);
}
});
// Legacy - Add label-floating if using old shorthand <input class="floating-label" placeholder="foo">
if ($input.hasClass("floating-label")) {
var placeholder = $input.attr("placeholder");
$input.attr("placeholder", null).removeClass("floating-label");
var id = $input.attr("id");
var forAttribute = "";
if(id) {
forAttribute = "for='" + id + "'";
}
$formGroup.addClass("label-floating");
$input.after("<label " + forAttribute + "class='control-label'>" + placeholder + "</label>");
}
// Set as empty if is empty (damn I must improve this...)
if ($input.val() === null || $input.val() == "undefined" || $input.val() === "") {
$formGroup.addClass("is-empty");
}
// Add at the end of the form-group
$formGroup.append("<span class='material-input'></span>");
// Support for file input
if ($formGroup.find("input[type=file]").length > 0) {
$formGroup.addClass("is-fileinput");
}
});
},
"attachInputEventHandlers": function() {
// checkboxes didn't appear to bubble to the document, so we'll bind these directly
$(".form-group .checkbox label").hover(function() {
_addFormGroupFocus(this);
}, function() {
_removeFormGroupFocus(this);
});
$(document)
.on("change", ".checkbox input[type=checkbox]", function() { $(this).blur(); })
.on("keydown paste", ".form-control", function(e) {
if(_isChar(e)) {
$(this).closest(".form-group").removeClass("is-empty");
}
})
.on("keyup change", ".form-control", function() {
var $input = $(this);
var $formGroup = $input.closest(".form-group");
var isValid = (typeof $input[0].checkValidity === "undefined" || $input[0].checkValidity());
if ($input.val() === "" && isValid) {
$formGroup.addClass("is-empty");
}
else {
$formGroup.removeClass("is-empty");
}
// Validation events do not bubble, so they must be attached directly to the input: http://jsfiddle.net/PEpRM/1/
// Further, even the bind method is being caught, but since we are already calling #checkValidity here, just alter
// the form-group on change.
//
// NOTE: I'm not sure we should be intervening regarding validation, this seems better as a README and snippet of code.
// BUT, I've left it here for backwards compatibility.
if(isValid){
$formGroup.removeClass("has-error");
}
else{
$formGroup.addClass("has-error");
}
})
.on("focus", ".form-control, .form-group.is-fileinput", function() {
_addFormGroupFocus(this);
})
.on("blur", ".form-control, .form-group.is-fileinput", function() {
_removeFormGroupFocus(this);
})
// make sure empty is added back when there is a programmatic value change.
// NOTE: programmatic changing of value using $.val() must trigger the change event i.e. $.val('x').trigger('change')
.on("change", ".form-group input", function() {
var $input = $(this);
if($input.attr("type") == "file") {
return;
}
var $formGroup = $input.closest(".form-group");
var value = $input.val();
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
})
// set the fileinput readonly field with the name of the file
.on("change", ".form-group.is-fileinput input[type='file']", function() {
var $input = $(this);
var $formGroup = $input.closest(".form-group");
var value = "";
$.each(this.files, function(i, file) {
value += file.name + ", ";
});
value = value.substring(0, value.length - 2);
if (value) {
$formGroup.removeClass("is-empty");
} else {
$formGroup.addClass("is-empty");
}
$formGroup.find("input.form-control[readonly]").val(value);
});
},
"ripples": function(selector) {
$((selector) ? selector : this.options.withRipples).ripples();
},
"autofill": function() {
// This part of code will detect autofill when the page is loading (username and password inputs for example)
var loading = setInterval(function() {
$("input[type!=checkbox]").each(function() {
var $this = $(this);
if ($this.val() && $this.val() !== $this.attr("value")) {
$this.trigger("change");
}
});
}, 100);
// After 10 seconds we are quite sure all the needed inputs are autofilled then we can stop checking them
setTimeout(function() {
clearInterval(loading);
}, 10000);
},
"attachAutofillEventHandlers": function() {
// Listen on inputs of the focused form (because user can select from the autofill dropdown only when the input has focus)
var focused;
$(document)
.on("focus", "input", function() {
var $inputs = $(this).parents("form").find("input").not("[type=file]");
focused = setInterval(function() {
$inputs.each(function() {
var $this = $(this);
if ($this.val() !== $this.attr("value")) {
$this.trigger("change");
}
});
}, 100);
})
.on("blur", ".form-group input", function() {
clearInterval(focused);
});
},
"init": function() {
var $document = $(document);
if ($.fn.ripples && this.options.ripples) {
this.ripples();
}
if (this.options.input) {
this.input();
this.attachInputEventHandlers();
}
if (this.options.checkbox) {
this.checkbox();
}
if (this.options.togglebutton) {
this.togglebutton();
}
if (this.options.radio) {
this.radio();
}
if (this.options.autofill) {
this.autofill();
this.attachAutofillEventHandlers();
}
if (document.arrive && this.options.arrive) {
if ($.fn.ripples && this.options.ripples) {
$document.arrive(this.options.withRipples, function() {
$.material.ripples($(this));
});
}
if (this.options.input) {
$document.arrive(this.options.inputElements, function() {
$.material.input($(this));
});
}
if (this.options.checkbox) {
$document.arrive(this.options.checkboxElements, function() {
$.material.checkbox($(this));
});
}
if (this.options.radio) {
$document.arrive(this.options.radioElements, function() {
$.material.radio($(this));
});
}
if (this.options.togglebutton) {
$document.arrive(this.options.togglebuttonElements, function() {
$.material.togglebutton($(this));
});
}
}
}
};
})(jQuery);
/* Copyright 2014+, Federico Zivolo, LICENSE at https://github.com/FezVrasta/bootstrap-material-design/blob/master/LICENSE.md */
/* globals jQuery, navigator */
(function($, window, document, undefined) {
"use strict";
/**
* Define the name of the plugin
*/
var ripples = "ripples";
/**
* Get an instance of the plugin
*/
var self = null;
/**
* Define the defaults of the plugin
*/
var defaults = {};
/**
* Create the main plugin function
*/
function Ripples(element, options) {
self = this;
this.element = $(element);
this.options = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = ripples;
this.init();
}
/**
* Initialize the plugin
*/
Ripples.prototype.init = function() {
var $element = this.element;
$element.on("mousedown touchstart", function(event) {
/**
* Verify if the user is just touching on a device and return if so
*/
if(self.isTouch() && event.type === "mousedown") {
return;
}
/**
* Verify if the current element already has a ripple wrapper element and
* creates if it doesn't
*/
if(!($element.find(".ripple-container").length)) {
$element.append("<div class=\"ripple-container\"></div>");
}
/**
* Find the ripple wrapper
*/
var $wrapper = $element.children(".ripple-container");
/**
* Get relY and relX positions
*/
var relY = self.getRelY($wrapper, event);
var relX = self.getRelX($wrapper, event);
/**
* If relY and/or relX are false, return the event
*/
if(!relY && !relX) {
return;
}
/**
* Get the ripple color
*/
var rippleColor = self.getRipplesColor($element);
/**
* Create the ripple element
*/
var $ripple = $("<div></div>");
$ripple
.addClass("ripple")
.css({
"left": relX,
"top": relY,
"background-color": rippleColor
});
/**
* Append the ripple to the wrapper
*/
$wrapper.append($ripple);
/**
* Make sure the ripple has the styles applied (ugly hack but it works)
*/
(function() { return window.getComputedStyle($ripple[0]).opacity; })();
/**
* Turn on the ripple animation
*/
self.rippleOn($element, $ripple);
/**
* Call the rippleEnd function when the transition "on" ends
*/
setTimeout(function() {
self.rippleEnd($ripple);
}, 500);
/**
* Detect when the user leaves the element
*/
$element.on("mouseup mouseleave touchend", function() {
$ripple.data("mousedown", "off");
if($ripple.data("animating") === "off") {
self.rippleOut($ripple);
}
});
});
};
/**
* Get the new size based on the element height/width and the ripple width
*/
Ripples.prototype.getNewSize = function($element, $ripple) {
return (Math.max($element.outerWidth(), $element.outerHeight()) / $ripple.outerWidth()) * 2.5;
};
/**
* Get the relX
*/
Ripples.prototype.getRelX = function($wrapper, event) {
var wrapperOffset = $wrapper.offset();
if(!self.isTouch()) {
/**
* Get the mouse position relative to the ripple wrapper
*/
return event.pageX - wrapperOffset.left;
} else {
/**
* Make sure the user is using only one finger and then get the touch
* position relative to the ripple wrapper
*/
event = event.originalEvent;
if(event.touches.length === 1) {
return event.touches[0].pageX - wrapperOffset.left;
}
return false;
}
};
/**
* Get the relY
*/
Ripples.prototype.getRelY = function($wrapper, event) {
var wrapperOffset = $wrapper.offset();
if(!self.isTouch()) {
/**
* Get the mouse position relative to the ripple wrapper
*/
return event.pageY - wrapperOffset.top;
} else {
/**
* Make sure the user is using only one finger and then get the touch
* position relative to the ripple wrapper
*/
event = event.originalEvent;
if(event.touches.length === 1) {
return event.touches[0].pageY - wrapperOffset.top;
}
return false;
}
};
/**
* Get the ripple color
*/
Ripples.prototype.getRipplesColor = function($element) {
var color = $element.data("ripple-color") ? $element.data("ripple-color") : window.getComputedStyle($element[0]).color;
return color;
};
/**
* Verify if the client browser has transistion support
*/
Ripples.prototype.hasTransitionSupport = function() {
var thisBody = document.body || document.documentElement;
var thisStyle = thisBody.style;
var support = (
thisStyle.transition !== undefined ||
thisStyle.WebkitTransition !== undefined ||
thisStyle.MozTransition !== undefined ||
thisStyle.MsTransition !== undefined ||
thisStyle.OTransition !== undefined
);
return support;
};
/**
* Verify if the client is using a mobile device
*/
Ripples.prototype.isTouch = function() {
return /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
};
/**
* End the animation of the ripple
*/
Ripples.prototype.rippleEnd = function($ripple) {
$ripple.data("animating", "off");
if($ripple.data("mousedown") === "off") {
self.rippleOut($ripple);
}
};
/**
* Turn off the ripple effect
*/
Ripples.prototype.rippleOut = function($ripple) {
$ripple.off();
if(self.hasTransitionSupport()) {
$ripple.addClass("ripple-out");
} else {
$ripple.animate({"opacity": 0}, 100, function() {
$ripple.trigger("transitionend");
});
}
$ripple.on("transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd", function() {
$ripple.remove();
});
};
/**
* Turn on the ripple effect
*/
Ripples.prototype.rippleOn = function($element, $ripple) {
var size = self.getNewSize($element, $ripple);
if(self.hasTransitionSupport()) {
$ripple
.css({
"-ms-transform": "scale(" + size + ")",
"-moz-transform": "scale(" + size + ")",
"-webkit-transform": "scale(" + size + ")",
"transform": "scale(" + size + ")"
})
.addClass("ripple-on")
.data("animating", "on")
.data("mousedown", "on");
} else {
$ripple.animate({
"width": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
"height": Math.max($element.outerWidth(), $element.outerHeight()) * 2,
"margin-left": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
"margin-top": Math.max($element.outerWidth(), $element.outerHeight()) * (-1),
"opacity": 0.2
}, 500, function() {
$ripple.trigger("transitionend");
});
}
};
/**
* Create the jquery plugin function
*/
$.fn.ripples = function(options) {
return this.each(function() {
if(!$.data(this, "plugin_" + ripples)) {
$.data(this, "plugin_" + ripples, new Ripples(this, options));
}
});
};
})(jQuery, window, document);
/*!
* Bootstrap v3.4.1 (https://getbootstrap.com/)
* Copyright 2011-2019 Twitter, Inc.
* Licensed under the MIT license
*/
if (typeof jQuery === 'undefined') {
throw new Error('Bootstrap\'s JavaScript requires jQuery')
}
+function ($) {
'use strict';
var version = $.fn.jquery.split(' ')[0].split('.')
if ((version[0] < 2 && version[1] < 9) || (version[0] == 1 && version[1] == 9 && version[2] < 1) || (version[0] > 3)) {
throw new Error('Bootstrap\'s JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4')
}
}(jQuery);
/* ========================================================================
* Bootstrap: transition.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#transitions
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CSS TRANSITION SUPPORT (Shoutout: https://modernizr.com/)
// ============================================================
function transitionEnd() {
var el = document.createElement('bootstrap')
var transEndEventNames = {
WebkitTransition : 'webkitTransitionEnd',
MozTransition : 'transitionend',
OTransition : 'oTransitionEnd otransitionend',
transition : 'transitionend'
}
for (var name in transEndEventNames) {
if (el.style[name] !== undefined) {
return { end: transEndEventNames[name] }
}
}
return false // explicit for ie8 ( ._.)
}
// https://blog.alexmaccaw.com/css-transitions
$.fn.emulateTransitionEnd = function (duration) {
var called = false
var $el = this
$(this).one('bsTransitionEnd', function () { called = true })
var callback = function () { if (!called) $($el).trigger($.support.transition.end) }
setTimeout(callback, duration)
return this
}
$(function () {
$.support.transition = transitionEnd()
if (!$.support.transition) return
$.event.special.bsTransitionEnd = {
bindType: $.support.transition.end,
delegateType: $.support.transition.end,
handle: function (e) {
if ($(e.target).is(this)) return e.handleObj.handler.apply(this, arguments)
}
}
})
}(jQuery);
/* ========================================================================
* Bootstrap: alert.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#alerts
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// ALERT CLASS DEFINITION
// ======================
var dismiss = '[data-dismiss="alert"]'
var Alert = function (el) {
$(el).on('click', dismiss, this.close)
}
Alert.VERSION = '3.4.1'
Alert.TRANSITION_DURATION = 150
Alert.prototype.close = function (e) {
var $this = $(this)
var selector = $this.attr('data-target')
if (!selector) {
selector = $this.attr('href')
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
selector = selector === '#' ? [] : selector
var $parent = $(document).find(selector)
if (e) e.preventDefault()
if (!$parent.length) {
$parent = $this.closest('.alert')
}
$parent.trigger(e = $.Event('close.bs.alert'))
if (e.isDefaultPrevented()) return
$parent.removeClass('in')
function removeElement() {
// detach from parent, fire event then clean up data
$parent.detach().trigger('closed.bs.alert').remove()
}
$.support.transition && $parent.hasClass('fade') ?
$parent
.one('bsTransitionEnd', removeElement)
.emulateTransitionEnd(Alert.TRANSITION_DURATION) :
removeElement()
}
// ALERT PLUGIN DEFINITION
// =======================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.alert')
if (!data) $this.data('bs.alert', (data = new Alert(this)))
if (typeof option == 'string') data[option].call($this)
})
}
var old = $.fn.alert
$.fn.alert = Plugin
$.fn.alert.Constructor = Alert
// ALERT NO CONFLICT
// =================
$.fn.alert.noConflict = function () {
$.fn.alert = old
return this
}
// ALERT DATA-API
// ==============
$(document).on('click.bs.alert.data-api', dismiss, Alert.prototype.close)
}(jQuery);
/* ========================================================================
* Bootstrap: button.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#buttons
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// BUTTON PUBLIC CLASS DEFINITION
// ==============================
var Button = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Button.DEFAULTS, options)
this.isLoading = false
}
Button.VERSION = '3.4.1'
Button.DEFAULTS = {
loadingText: 'loading...'
}
Button.prototype.setState = function (state) {
var d = 'disabled'
var $el = this.$element
var val = $el.is('input') ? 'val' : 'html'
var data = $el.data()
state += 'Text'
if (data.resetText == null) $el.data('resetText', $el[val]())
// push to event loop to allow forms to submit
setTimeout($.proxy(function () {
$el[val](data[state] == null ? this.options[state] : data[state])
if (state == 'loadingText') {
this.isLoading = true
$el.addClass(d).attr(d, d).prop(d, true)
} else if (this.isLoading) {
this.isLoading = false
$el.removeClass(d).removeAttr(d).prop(d, false)
}
}, this), 0)
}
Button.prototype.toggle = function () {
var changed = true
var $parent = this.$element.closest('[data-toggle="buttons"]')
if ($parent.length) {
var $input = this.$element.find('input')
if ($input.prop('type') == 'radio') {
if ($input.prop('checked')) changed = false
$parent.find('.active').removeClass('active')
this.$element.addClass('active')
} else if ($input.prop('type') == 'checkbox') {
if (($input.prop('checked')) !== this.$element.hasClass('active')) changed = false
this.$element.toggleClass('active')
}
$input.prop('checked', this.$element.hasClass('active'))
if (changed) $input.trigger('change')
} else {
this.$element.attr('aria-pressed', !this.$element.hasClass('active'))
this.$element.toggleClass('active')
}
}
// BUTTON PLUGIN DEFINITION
// ========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.button')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.button', (data = new Button(this, options)))
if (option == 'toggle') data.toggle()
else if (option) data.setState(option)
})
}
var old = $.fn.button
$.fn.button = Plugin
$.fn.button.Constructor = Button
// BUTTON NO CONFLICT
// ==================
$.fn.button.noConflict = function () {
$.fn.button = old
return this
}
// BUTTON DATA-API
// ===============
$(document)
.on('click.bs.button.data-api', '[data-toggle^="button"]', function (e) {
var $btn = $(e.target).closest('.btn')
Plugin.call($btn, 'toggle')
if (!($(e.target).is('input[type="radio"], input[type="checkbox"]'))) {
// Prevent double click on radios, and the double selections (so cancellation) on checkboxes
e.preventDefault()
// The target component still receive the focus
if ($btn.is('input,button')) $btn.trigger('focus')
else $btn.find('input:visible,button:visible').first().trigger('focus')
}
})
.on('focus.bs.button.data-api blur.bs.button.data-api', '[data-toggle^="button"]', function (e) {
$(e.target).closest('.btn').toggleClass('focus', /^focus(in)?$/.test(e.type))
})
}(jQuery);
/* ========================================================================
* Bootstrap: carousel.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#carousel
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// CAROUSEL CLASS DEFINITION
// =========================
var Carousel = function (element, options) {
this.$element = $(element)
this.$indicators = this.$element.find('.carousel-indicators')
this.options = options
this.paused = null
this.sliding = null
this.interval = null
this.$active = null
this.$items = null
this.options.keyboard && this.$element.on('keydown.bs.carousel', $.proxy(this.keydown, this))
this.options.pause == 'hover' && !('ontouchstart' in document.documentElement) && this.$element
.on('mouseenter.bs.carousel', $.proxy(this.pause, this))
.on('mouseleave.bs.carousel', $.proxy(this.cycle, this))
}
Carousel.VERSION = '3.4.1'
Carousel.TRANSITION_DURATION = 600
Carousel.DEFAULTS = {
interval: 5000,
pause: 'hover',
wrap: true,
keyboard: true
}
Carousel.prototype.keydown = function (e) {
if (/input|textarea/i.test(e.target.tagName)) return
switch (e.which) {
case 37: this.prev(); break
case 39: this.next(); break
default: return
}
e.preventDefault()
}
Carousel.prototype.cycle = function (e) {
e || (this.paused = false)
this.interval && clearInterval(this.interval)
this.options.interval
&& !this.paused
&& (this.interval = setInterval($.proxy(this.next, this), this.options.interval))
return this
}
Carousel.prototype.getItemIndex = function (item) {
this.$items = item.parent().children('.item')
return this.$items.index(item || this.$active)
}
Carousel.prototype.getItemForDirection = function (direction, active) {
var activeIndex = this.getItemIndex(active)
var willWrap = (direction == 'prev' && activeIndex === 0)
|| (direction == 'next' && activeIndex == (this.$items.length - 1))
if (willWrap && !this.options.wrap) return active
var delta = direction == 'prev' ? -1 : 1
var itemIndex = (activeIndex + delta) % this.$items.length
return this.$items.eq(itemIndex)
}
Carousel.prototype.to = function (pos) {
var that = this
var activeIndex = this.getItemIndex(this.$active = this.$element.find('.item.active'))
if (pos > (this.$items.length - 1) || pos < 0) return
if (this.sliding) return this.$element.one('slid.bs.carousel', function () { that.to(pos) }) // yes, "slid"
if (activeIndex == pos) return this.pause().cycle()
return this.slide(pos > activeIndex ? 'next' : 'prev', this.$items.eq(pos))
}
Carousel.prototype.pause = function (e) {
e || (this.paused = true)
if (this.$element.find('.next, .prev').length && $.support.transition) {
this.$element.trigger($.support.transition.end)
this.cycle(true)
}
this.interval = clearInterval(this.interval)
return this
}
Carousel.prototype.next = function () {
if (this.sliding) return
return this.slide('next')
}
Carousel.prototype.prev = function () {
if (this.sliding) return
return this.slide('prev')
}
Carousel.prototype.slide = function (type, next) {
var $active = this.$element.find('.item.active')
var $next = next || this.getItemForDirection(type, $active)
var isCycling = this.interval
var direction = type == 'next' ? 'left' : 'right'
var that = this
if ($next.hasClass('active')) return (this.sliding = false)
var relatedTarget = $next[0]
var slideEvent = $.Event('slide.bs.carousel', {
relatedTarget: relatedTarget,
direction: direction
})
this.$element.trigger(slideEvent)
if (slideEvent.isDefaultPrevented()) return
this.sliding = true
isCycling && this.pause()
if (this.$indicators.length) {
this.$indicators.find('.active').removeClass('active')
var $nextIndicator = $(this.$indicators.children()[this.getItemIndex($next)])
$nextIndicator && $nextIndicator.addClass('active')
}
var slidEvent = $.Event('slid.bs.carousel', { relatedTarget: relatedTarget, direction: direction }) // yes, "slid"
if ($.support.transition && this.$element.hasClass('slide')) {
$next.addClass(type)
if (typeof $next === 'object' && $next.length) {
$next[0].offsetWidth // force reflow
}
$active.addClass(direction)
$next.addClass(direction)
$active
.one('bsTransitionEnd', function () {
$next.removeClass([type, direction].join(' ')).addClass('active')
$active.removeClass(['active', direction].join(' '))
that.sliding = false
setTimeout(function () {
that.$element.trigger(slidEvent)
}, 0)
})
.emulateTransitionEnd(Carousel.TRANSITION_DURATION)
} else {
$active.removeClass('active')
$next.addClass('active')
this.sliding = false
this.$element.trigger(slidEvent)
}
isCycling && this.cycle()
return this
}
// CAROUSEL PLUGIN DEFINITION
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.carousel')
var options = $.extend({}, Carousel.DEFAULTS, $this.data(), typeof option == 'object' && option)
var action = typeof option == 'string' ? option : options.slide
if (!data) $this.data('bs.carousel', (data = new Carousel(this, options)))
if (typeof option == 'number') data.to(option)
else if (action) data[action]()
else if (options.interval) data.pause().cycle()
})
}
var old = $.fn.carousel
$.fn.carousel = Plugin
$.fn.carousel.Constructor = Carousel
// CAROUSEL NO CONFLICT
// ====================
$.fn.carousel.noConflict = function () {
$.fn.carousel = old
return this
}
// CAROUSEL DATA-API
// =================
var clickHandler = function (e) {
var $this = $(this)
var href = $this.attr('href')
if (href) {
href = href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
}
var target = $this.attr('data-target') || href
var $target = $(document).find(target)
if (!$target.hasClass('carousel')) return
var options = $.extend({}, $target.data(), $this.data())
var slideIndex = $this.attr('data-slide-to')
if (slideIndex) options.interval = false
Plugin.call($target, options)
if (slideIndex) {
$target.data('bs.carousel').to(slideIndex)
}
e.preventDefault()
}
$(document)
.on('click.bs.carousel.data-api', '[data-slide]', clickHandler)
.on('click.bs.carousel.data-api', '[data-slide-to]', clickHandler)
$(window).on('load', function () {
$('[data-ride="carousel"]').each(function () {
var $carousel = $(this)
Plugin.call($carousel, $carousel.data())
})
})
}(jQuery);
/* ========================================================================
* Bootstrap: collapse.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#collapse
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
/* jshint latedef: false */
+function ($) {
'use strict';
// COLLAPSE PUBLIC CLASS DEFINITION
// ================================
var Collapse = function (element, options) {
this.$element = $(element)
this.options = $.extend({}, Collapse.DEFAULTS, options)
this.$trigger = $('[data-toggle="collapse"][href="#' + element.id + '"],' +
'[data-toggle="collapse"][data-target="#' + element.id + '"]')
this.transitioning = null
if (this.options.parent) {
this.$parent = this.getParent()
} else {
this.addAriaAndCollapsedClass(this.$element, this.$trigger)
}
if (this.options.toggle) this.toggle()
}
Collapse.VERSION = '3.4.1'
Collapse.TRANSITION_DURATION = 350
Collapse.DEFAULTS = {
toggle: true
}
Collapse.prototype.dimension = function () {
var hasWidth = this.$element.hasClass('width')
return hasWidth ? 'width' : 'height'
}
Collapse.prototype.show = function () {
if (this.transitioning || this.$element.hasClass('in')) return
var activesData
var actives = this.$parent && this.$parent.children('.panel').children('.in, .collapsing')
if (actives && actives.length) {
activesData = actives.data('bs.collapse')
if (activesData && activesData.transitioning) return
}
var startEvent = $.Event('show.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
if (actives && actives.length) {
Plugin.call(actives, 'hide')
activesData || actives.data('bs.collapse', null)
}
var dimension = this.dimension()
this.$element
.removeClass('collapse')
.addClass('collapsing')[dimension](0)
.attr('aria-expanded', true)
this.$trigger
.removeClass('collapsed')
.attr('aria-expanded', true)
this.transitioning = 1
var complete = function () {
this.$element
.removeClass('collapsing')
.addClass('collapse in')[dimension]('')
this.transitioning = 0
this.$element
.trigger('shown.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
var scrollSize = $.camelCase(['scroll', dimension].join('-'))
this.$element
.one('bsTransitionEnd', $.proxy(complete, this))
.emulateTransitionEnd(Collapse.TRANSITION_DURATION)[dimension](this.$element[0][scrollSize])
}
Collapse.prototype.hide = function () {
if (this.transitioning || !this.$element.hasClass('in')) return
var startEvent = $.Event('hide.bs.collapse')
this.$element.trigger(startEvent)
if (startEvent.isDefaultPrevented()) return
var dimension = this.dimension()
this.$element[dimension](this.$element[dimension]())[0].offsetHeight
this.$element
.addClass('collapsing')
.removeClass('collapse in')
.attr('aria-expanded', false)
this.$trigger
.addClass('collapsed')
.attr('aria-expanded', false)
this.transitioning = 1
var complete = function () {
this.transitioning = 0
this.$element
.removeClass('collapsing')
.addClass('collapse')
.trigger('hidden.bs.collapse')
}
if (!$.support.transition) return complete.call(this)
this.$element
[dimension](0)
.one('bsTransitionEnd', $.proxy(complete, this))
.emulateTransitionEnd(Collapse.TRANSITION_DURATION)
}
Collapse.prototype.toggle = function () {
this[this.$element.hasClass('in') ? 'hide' : 'show']()
}
Collapse.prototype.getParent = function () {
return $(document).find(this.options.parent)
.find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]')
.each($.proxy(function (i, element) {
var $element = $(element)
this.addAriaAndCollapsedClass(getTargetFromTrigger($element), $element)
}, this))
.end()
}
Collapse.prototype.addAriaAndCollapsedClass = function ($element, $trigger) {
var isOpen = $element.hasClass('in')
$element.attr('aria-expanded', isOpen)
$trigger
.toggleClass('collapsed', !isOpen)
.attr('aria-expanded', isOpen)
}
function getTargetFromTrigger($trigger) {
var href
var target = $trigger.attr('data-target')
|| (href = $trigger.attr('href')) && href.replace(/.*(?=#[^\s]+$)/, '') // strip for ie7
return $(document).find(target)
}
// COLLAPSE PLUGIN DEFINITION
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.collapse')
var options = $.extend({}, Collapse.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data && options.toggle && /show|hide/.test(option)) options.toggle = false
if (!data) $this.data('bs.collapse', (data = new Collapse(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.collapse
$.fn.collapse = Plugin
$.fn.collapse.Constructor = Collapse
// COLLAPSE NO CONFLICT
// ====================
$.fn.collapse.noConflict = function () {
$.fn.collapse = old
return this
}
// COLLAPSE DATA-API
// =================
$(document).on('click.bs.collapse.data-api', '[data-toggle="collapse"]', function (e) {
var $this = $(this)
if (!$this.attr('data-target')) e.preventDefault()
var $target = getTargetFromTrigger($this)
var data = $target.data('bs.collapse')
var option = data ? 'toggle' : $this.data()
Plugin.call($target, option)
})
}(jQuery);
/* ========================================================================
* Bootstrap: dropdown.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#dropdowns
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// DROPDOWN CLASS DEFINITION
// =========================
var backdrop = '.dropdown-backdrop'
var toggle = '[data-toggle="dropdown"]'
var Dropdown = function (element) {
$(element).on('click.bs.dropdown', this.toggle)
}
Dropdown.VERSION = '3.4.1'
function getParent($this) {
var selector = $this.attr('data-target')
if (!selector) {
selector = $this.attr('href')
selector = selector && /#[A-Za-z]/.test(selector) && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
var $parent = selector !== '#' ? $(document).find(selector) : null
return $parent && $parent.length ? $parent : $this.parent()
}
function clearMenus(e) {
if (e && e.which === 3) return
$(backdrop).remove()
$(toggle).each(function () {
var $this = $(this)
var $parent = getParent($this)
var relatedTarget = { relatedTarget: this }
if (!$parent.hasClass('open')) return
if (e && e.type == 'click' && /input|textarea/i.test(e.target.tagName) && $.contains($parent[0], e.target)) return
$parent.trigger(e = $.Event('hide.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$this.attr('aria-expanded', 'false')
$parent.removeClass('open').trigger($.Event('hidden.bs.dropdown', relatedTarget))
})
}
Dropdown.prototype.toggle = function (e) {
var $this = $(this)
if ($this.is('.disabled, :disabled')) return
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
clearMenus()
if (!isActive) {
if ('ontouchstart' in document.documentElement && !$parent.closest('.navbar-nav').length) {
// if mobile we use a backdrop because click events don't delegate
$(document.createElement('div'))
.addClass('dropdown-backdrop')
.insertAfter($(this))
.on('click', clearMenus)
}
var relatedTarget = { relatedTarget: this }
$parent.trigger(e = $.Event('show.bs.dropdown', relatedTarget))
if (e.isDefaultPrevented()) return
$this
.trigger('focus')
.attr('aria-expanded', 'true')
$parent
.toggleClass('open')
.trigger($.Event('shown.bs.dropdown', relatedTarget))
}
return false
}
Dropdown.prototype.keydown = function (e) {
if (!/(38|40|27|32)/.test(e.which) || /input|textarea/i.test(e.target.tagName)) return
var $this = $(this)
e.preventDefault()
e.stopPropagation()
if ($this.is('.disabled, :disabled')) return
var $parent = getParent($this)
var isActive = $parent.hasClass('open')
if (!isActive && e.which != 27 || isActive && e.which == 27) {
if (e.which == 27) $parent.find(toggle).trigger('focus')
return $this.trigger('click')
}
var desc = ' li:not(.disabled):visible a'
var $items = $parent.find('.dropdown-menu' + desc)
if (!$items.length) return
var index = $items.index(e.target)
if (e.which == 38 && index > 0) index-- // up
if (e.which == 40 && index < $items.length - 1) index++ // down
if (!~index) index = 0
$items.eq(index).trigger('focus')
}
// DROPDOWN PLUGIN DEFINITION
// ==========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.dropdown')
if (!data) $this.data('bs.dropdown', (data = new Dropdown(this)))
if (typeof option == 'string') data[option].call($this)
})
}
var old = $.fn.dropdown
$.fn.dropdown = Plugin
$.fn.dropdown.Constructor = Dropdown
// DROPDOWN NO CONFLICT
// ====================
$.fn.dropdown.noConflict = function () {
$.fn.dropdown = old
return this
}
// APPLY TO STANDARD DROPDOWN ELEMENTS
// ===================================
$(document)
.on('click.bs.dropdown.data-api', clearMenus)
.on('click.bs.dropdown.data-api', '.dropdown form', function (e) { e.stopPropagation() })
.on('click.bs.dropdown.data-api', toggle, Dropdown.prototype.toggle)
.on('keydown.bs.dropdown.data-api', toggle, Dropdown.prototype.keydown)
.on('keydown.bs.dropdown.data-api', '.dropdown-menu', Dropdown.prototype.keydown)
}(jQuery);
/* ========================================================================
* Bootstrap: modal.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#modals
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// MODAL CLASS DEFINITION
// ======================
var Modal = function (element, options) {
this.options = options
this.$body = $(document.body)
this.$element = $(element)
this.$dialog = this.$element.find('.modal-dialog')
this.$backdrop = null
this.isShown = null
this.originalBodyPad = null
this.scrollbarWidth = 0
this.ignoreBackdropClick = false
this.fixedContent = '.navbar-fixed-top, .navbar-fixed-bottom'
if (this.options.remote) {
this.$element
.find('.modal-content')
.load(this.options.remote, $.proxy(function () {
this.$element.trigger('loaded.bs.modal')
}, this))
}
}
Modal.VERSION = '3.4.1'
Modal.TRANSITION_DURATION = 300
Modal.BACKDROP_TRANSITION_DURATION = 150
Modal.DEFAULTS = {
backdrop: true,
keyboard: true,
show: true
}
Modal.prototype.toggle = function (_relatedTarget) {
return this.isShown ? this.hide() : this.show(_relatedTarget)
}
Modal.prototype.show = function (_relatedTarget) {
var that = this
var e = $.Event('show.bs.modal', { relatedTarget: _relatedTarget })
this.$element.trigger(e)
if (this.isShown || e.isDefaultPrevented()) return
this.isShown = true
this.checkScrollbar()
this.setScrollbar()
this.$body.addClass('modal-open')
this.escape()
this.resize()
this.$element.on('click.dismiss.bs.modal', '[data-dismiss="modal"]', $.proxy(this.hide, this))
this.$dialog.on('mousedown.dismiss.bs.modal', function () {
that.$element.one('mouseup.dismiss.bs.modal', function (e) {
if ($(e.target).is(that.$element)) that.ignoreBackdropClick = true
})
})
this.backdrop(function () {
var transition = $.support.transition && that.$element.hasClass('fade')
if (!that.$element.parent().length) {
that.$element.appendTo(that.$body) // don't move modals dom position
}
that.$element
.show()
.scrollTop(0)
that.adjustDialog()
if (transition) {
that.$element[0].offsetWidth // force reflow
}
that.$element.addClass('in')
that.enforceFocus()
var e = $.Event('shown.bs.modal', { relatedTarget: _relatedTarget })
transition ?
that.$dialog // wait for modal to slide in
.one('bsTransitionEnd', function () {
that.$element.trigger('focus').trigger(e)
})
.emulateTransitionEnd(Modal.TRANSITION_DURATION) :
that.$element.trigger('focus').trigger(e)
})
}
Modal.prototype.hide = function (e) {
if (e) e.preventDefault()
e = $.Event('hide.bs.modal')
this.$element.trigger(e)
if (!this.isShown || e.isDefaultPrevented()) return
this.isShown = false
this.escape()
this.resize()
$(document).off('focusin.bs.modal')
this.$element
.removeClass('in')
.off('click.dismiss.bs.modal')
.off('mouseup.dismiss.bs.modal')
this.$dialog.off('mousedown.dismiss.bs.modal')
$.support.transition && this.$element.hasClass('fade') ?
this.$element
.one('bsTransitionEnd', $.proxy(this.hideModal, this))
.emulateTransitionEnd(Modal.TRANSITION_DURATION) :
this.hideModal()
}
Modal.prototype.enforceFocus = function () {
$(document)
.off('focusin.bs.modal') // guard against infinite focus loop
.on('focusin.bs.modal', $.proxy(function (e) {
if (document !== e.target &&
this.$element[0] !== e.target &&
!this.$element.has(e.target).length) {
this.$element.trigger('focus')
}
}, this))
}
Modal.prototype.escape = function () {
if (this.isShown && this.options.keyboard) {
this.$element.on('keydown.dismiss.bs.modal', $.proxy(function (e) {
e.which == 27 && this.hide()
}, this))
} else if (!this.isShown) {
this.$element.off('keydown.dismiss.bs.modal')
}
}
Modal.prototype.resize = function () {
if (this.isShown) {
$(window).on('resize.bs.modal', $.proxy(this.handleUpdate, this))
} else {
$(window).off('resize.bs.modal')
}
}
Modal.prototype.hideModal = function () {
var that = this
this.$element.hide()
this.backdrop(function () {
that.$body.removeClass('modal-open')
that.resetAdjustments()
that.resetScrollbar()
that.$element.trigger('hidden.bs.modal')
})
}
Modal.prototype.removeBackdrop = function () {
this.$backdrop && this.$backdrop.remove()
this.$backdrop = null
}
Modal.prototype.backdrop = function (callback) {
var that = this
var animate = this.$element.hasClass('fade') ? 'fade' : ''
if (this.isShown && this.options.backdrop) {
var doAnimate = $.support.transition && animate
this.$backdrop = $(document.createElement('div'))
.addClass('modal-backdrop ' + animate)
.appendTo(this.$body)
this.$element.on('click.dismiss.bs.modal', $.proxy(function (e) {
if (this.ignoreBackdropClick) {
this.ignoreBackdropClick = false
return
}
if (e.target !== e.currentTarget) return
this.options.backdrop == 'static'
? this.$element[0].focus()
: this.hide()
}, this))
if (doAnimate) this.$backdrop[0].offsetWidth // force reflow
this.$backdrop.addClass('in')
if (!callback) return
doAnimate ?
this.$backdrop
.one('bsTransitionEnd', callback)
.emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
callback()
} else if (!this.isShown && this.$backdrop) {
this.$backdrop.removeClass('in')
var callbackRemove = function () {
that.removeBackdrop()
callback && callback()
}
$.support.transition && this.$element.hasClass('fade') ?
this.$backdrop
.one('bsTransitionEnd', callbackRemove)
.emulateTransitionEnd(Modal.BACKDROP_TRANSITION_DURATION) :
callbackRemove()
} else if (callback) {
callback()
}
}
// these following methods are used to handle overflowing modals
Modal.prototype.handleUpdate = function () {
this.adjustDialog()
}
Modal.prototype.adjustDialog = function () {
var modalIsOverflowing = this.$element[0].scrollHeight > document.documentElement.clientHeight
this.$element.css({
paddingLeft: !this.bodyIsOverflowing && modalIsOverflowing ? this.scrollbarWidth : '',
paddingRight: this.bodyIsOverflowing && !modalIsOverflowing ? this.scrollbarWidth : ''
})
}
Modal.prototype.resetAdjustments = function () {
this.$element.css({
paddingLeft: '',
paddingRight: ''
})
}
Modal.prototype.checkScrollbar = function () {
var fullWindowWidth = window.innerWidth
if (!fullWindowWidth) { // workaround for missing window.innerWidth in IE8
var documentElementRect = document.documentElement.getBoundingClientRect()
fullWindowWidth = documentElementRect.right - Math.abs(documentElementRect.left)
}
this.bodyIsOverflowing = document.body.clientWidth < fullWindowWidth
this.scrollbarWidth = this.measureScrollbar()
}
Modal.prototype.setScrollbar = function () {
var bodyPad = parseInt((this.$body.css('padding-right') || 0), 10)
this.originalBodyPad = document.body.style.paddingRight || ''
var scrollbarWidth = this.scrollbarWidth
if (this.bodyIsOverflowing) {
this.$body.css('padding-right', bodyPad + scrollbarWidth)
$(this.fixedContent).each(function (index, element) {
var actualPadding = element.style.paddingRight
var calculatedPadding = $(element).css('padding-right')
$(element)
.data('padding-right', actualPadding)
.css('padding-right', parseFloat(calculatedPadding) + scrollbarWidth + 'px')
})
}
}
Modal.prototype.resetScrollbar = function () {
this.$body.css('padding-right', this.originalBodyPad)
$(this.fixedContent).each(function (index, element) {
var padding = $(element).data('padding-right')
$(element).removeData('padding-right')
element.style.paddingRight = padding ? padding : ''
})
}
Modal.prototype.measureScrollbar = function () { // thx walsh
var scrollDiv = document.createElement('div')
scrollDiv.className = 'modal-scrollbar-measure'
this.$body.append(scrollDiv)
var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth
this.$body[0].removeChild(scrollDiv)
return scrollbarWidth
}
// MODAL PLUGIN DEFINITION
// =======================
function Plugin(option, _relatedTarget) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.modal')
var options = $.extend({}, Modal.DEFAULTS, $this.data(), typeof option == 'object' && option)
if (!data) $this.data('bs.modal', (data = new Modal(this, options)))
if (typeof option == 'string') data[option](_relatedTarget)
else if (options.show) data.show(_relatedTarget)
})
}
var old = $.fn.modal
$.fn.modal = Plugin
$.fn.modal.Constructor = Modal
// MODAL NO CONFLICT
// =================
$.fn.modal.noConflict = function () {
$.fn.modal = old
return this
}
// MODAL DATA-API
// ==============
$(document).on('click.bs.modal.data-api', '[data-toggle="modal"]', function (e) {
var $this = $(this)
var href = $this.attr('href')
var target = $this.attr('data-target') ||
(href && href.replace(/.*(?=#[^\s]+$)/, '')) // strip for ie7
var $target = $(document).find(target)
var option = $target.data('bs.modal') ? 'toggle' : $.extend({ remote: !/#/.test(href) && href }, $target.data(), $this.data())
if ($this.is('a')) e.preventDefault()
$target.one('show.bs.modal', function (showEvent) {
if (showEvent.isDefaultPrevented()) return // only register focus restorer if modal will actually get shown
$target.one('hidden.bs.modal', function () {
$this.is(':visible') && $this.trigger('focus')
})
})
Plugin.call($target, option, this)
})
}(jQuery);
/* ========================================================================
* Bootstrap: tooltip.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#tooltip
* Inspired by the original jQuery.tipsy by Jason Frame
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn']
var uriAttrs = [
'background',
'cite',
'href',
'itemtype',
'longdesc',
'poster',
'src',
'xlink:href'
]
var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
var DefaultWhitelist = {
// Global attributes allowed on any supplied element below.
'*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
a: ['target', 'href', 'title', 'rel'],
area: [],
b: [],
br: [],
col: [],
code: [],
div: [],
em: [],
hr: [],
h1: [],
h2: [],
h3: [],
h4: [],
h5: [],
h6: [],
i: [],
img: ['src', 'alt', 'title', 'width', 'height'],
li: [],
ol: [],
p: [],
pre: [],
s: [],
small: [],
span: [],
sub: [],
sup: [],
strong: [],
u: [],
ul: []
}
/**
* A pattern that recognizes a commonly useful subset of URLs that are safe.
*
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
*/
var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi
/**
* A pattern that matches safe data URLs. Only matches image, video and audio types.
*
* Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
*/
var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i
function allowedAttribute(attr, allowedAttributeList) {
var attrName = attr.nodeName.toLowerCase()
if ($.inArray(attrName, allowedAttributeList) !== -1) {
if ($.inArray(attrName, uriAttrs) !== -1) {
return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
}
return true
}
var regExp = $(allowedAttributeList).filter(function (index, value) {
return value instanceof RegExp
})
// Check if a regular expression validates the attribute.
for (var i = 0, l = regExp.length; i < l; i++) {
if (attrName.match(regExp[i])) {
return true
}
}
return false
}
function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
if (unsafeHtml.length === 0) {
return unsafeHtml
}
if (sanitizeFn && typeof sanitizeFn === 'function') {
return sanitizeFn(unsafeHtml)
}
// IE 8 and below don't support createHTMLDocument
if (!document.implementation || !document.implementation.createHTMLDocument) {
return unsafeHtml
}
var createdDocument = document.implementation.createHTMLDocument('sanitization')
createdDocument.body.innerHTML = unsafeHtml
var whitelistKeys = $.map(whiteList, function (el, i) { return i })
var elements = $(createdDocument.body).find('*')
for (var i = 0, len = elements.length; i < len; i++) {
var el = elements[i]
var elName = el.nodeName.toLowerCase()
if ($.inArray(elName, whitelistKeys) === -1) {
el.parentNode.removeChild(el)
continue
}
var attributeList = $.map(el.attributes, function (el) { return el })
var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
for (var j = 0, len2 = attributeList.length; j < len2; j++) {
if (!allowedAttribute(attributeList[j], whitelistedAttributes)) {
el.removeAttribute(attributeList[j].nodeName)
}
}
}
return createdDocument.body.innerHTML
}
// TOOLTIP PUBLIC CLASS DEFINITION
// ===============================
var Tooltip = function (element, options) {
this.type = null
this.options = null
this.enabled = null
this.timeout = null
this.hoverState = null
this.$element = null
this.inState = null
this.init('tooltip', element, options)
}
Tooltip.VERSION = '3.4.1'
Tooltip.TRANSITION_DURATION = 150
Tooltip.DEFAULTS = {
animation: true,
placement: 'top',
selector: false,
template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>',
trigger: 'hover focus',
title: '',
delay: 0,
html: false,
container: false,
viewport: {
selector: 'body',
padding: 0
},
sanitize : true,
sanitizeFn : null,
whiteList : DefaultWhitelist
}
Tooltip.prototype.init = function (type, element, options) {
this.enabled = true
this.type = type
this.$element = $(element)
this.options = this.getOptions(options)
this.$viewport = this.options.viewport && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport))
this.inState = { click: false, hover: false, focus: false }
if (this.$element[0] instanceof document.constructor && !this.options.selector) {
throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!')
}
var triggers = this.options.trigger.split(' ')
for (var i = triggers.length; i--;) {
var trigger = triggers[i]
if (trigger == 'click') {
this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this))
} else if (trigger != 'manual') {
var eventIn = trigger == 'hover' ? 'mouseenter' : 'focusin'
var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout'
this.$element.on(eventIn + '.' + this.type, this.options.selector, $.proxy(this.enter, this))
this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this))
}
}
this.options.selector ?
(this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) :
this.fixTitle()
}
Tooltip.prototype.getDefaults = function () {
return Tooltip.DEFAULTS
}
Tooltip.prototype.getOptions = function (options) {
var dataAttributes = this.$element.data()
for (var dataAttr in dataAttributes) {
if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) {
delete dataAttributes[dataAttr]
}
}
options = $.extend({}, this.getDefaults(), dataAttributes, options)
if (options.delay && typeof options.delay == 'number') {
options.delay = {
show: options.delay,
hide: options.delay
}
}
if (options.sanitize) {
options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn)
}
return options
}
Tooltip.prototype.getDelegateOptions = function () {
var options = {}
var defaults = this.getDefaults()
this._options && $.each(this._options, function (key, value) {
if (defaults[key] != value) options[key] = value
})
return options
}
Tooltip.prototype.enter = function (obj) {
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget).data('bs.' + this.type)
if (!self) {
self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
$(obj.currentTarget).data('bs.' + this.type, self)
}
if (obj instanceof $.Event) {
self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true
}
if (self.tip().hasClass('in') || self.hoverState == 'in') {
self.hoverState = 'in'
return
}
clearTimeout(self.timeout)
self.hoverState = 'in'
if (!self.options.delay || !self.options.delay.show) return self.show()
self.timeout = setTimeout(function () {
if (self.hoverState == 'in') self.show()
}, self.options.delay.show)
}
Tooltip.prototype.isInStateTrue = function () {
for (var key in this.inState) {
if (this.inState[key]) return true
}
return false
}
Tooltip.prototype.leave = function (obj) {
var self = obj instanceof this.constructor ?
obj : $(obj.currentTarget).data('bs.' + this.type)
if (!self) {
self = new this.constructor(obj.currentTarget, this.getDelegateOptions())
$(obj.currentTarget).data('bs.' + this.type, self)
}
if (obj instanceof $.Event) {
self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
}
if (self.isInStateTrue()) return
clearTimeout(self.timeout)
self.hoverState = 'out'
if (!self.options.delay || !self.options.delay.hide) return self.hide()
self.timeout = setTimeout(function () {
if (self.hoverState == 'out') self.hide()
}, self.options.delay.hide)
}
Tooltip.prototype.show = function () {
var e = $.Event('show.bs.' + this.type)
if (this.hasContent() && this.enabled) {
this.$element.trigger(e)
var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
if (e.isDefaultPrevented() || !inDom) return
var that = this
var $tip = this.tip()
var tipId = this.getUID(this.type)
this.setContent()
$tip.attr('id', tipId)
this.$element.attr('aria-describedby', tipId)
if (this.options.animation) $tip.addClass('fade')
var placement = typeof this.options.placement == 'function' ?
this.options.placement.call(this, $tip[0], this.$element[0]) :
this.options.placement
var autoToken = /\s?auto?\s?/i
var autoPlace = autoToken.test(placement)
if (autoPlace) placement = placement.replace(autoToken, '') || 'top'
$tip
.detach()
.css({ top: 0, left: 0, display: 'block' })
.addClass(placement)
.data('bs.' + this.type, this)
this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
this.$element.trigger('inserted.bs.' + this.type)
var pos = this.getPosition()
var actualWidth = $tip[0].offsetWidth
var actualHeight = $tip[0].offsetHeight
if (autoPlace) {
var orgPlacement = placement
var viewportDim = this.getPosition(this.$viewport)
placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top' :
placement == 'top' && pos.top - actualHeight < viewportDim.top ? 'bottom' :
placement == 'right' && pos.right + actualWidth > viewportDim.width ? 'left' :
placement == 'left' && pos.left - actualWidth < viewportDim.left ? 'right' :
placement
$tip
.removeClass(orgPlacement)
.addClass(placement)
}
var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight)
this.applyPlacement(calculatedOffset, placement)
var complete = function () {
var prevHoverState = that.hoverState
that.$element.trigger('shown.bs.' + that.type)
that.hoverState = null
if (prevHoverState == 'out') that.leave(that)
}
$.support.transition && this.$tip.hasClass('fade') ?
$tip
.one('bsTransitionEnd', complete)
.emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
complete()
}
}
Tooltip.prototype.applyPlacement = function (offset, placement) {
var $tip = this.tip()
var width = $tip[0].offsetWidth
var height = $tip[0].offsetHeight
// manually read margins because getBoundingClientRect includes difference
var marginTop = parseInt($tip.css('margin-top'), 10)
var marginLeft = parseInt($tip.css('margin-left'), 10)
// we must check for NaN for ie 8/9
if (isNaN(marginTop)) marginTop = 0
if (isNaN(marginLeft)) marginLeft = 0
offset.top += marginTop
offset.left += marginLeft
// $.fn.offset doesn't round pixel values
// so we use setOffset directly with our own function B-0
$.offset.setOffset($tip[0], $.extend({
using: function (props) {
$tip.css({
top: Math.round(props.top),
left: Math.round(props.left)
})
}
}, offset), 0)
$tip.addClass('in')
// check to see if placing tip in new offset caused the tip to resize itself
var actualWidth = $tip[0].offsetWidth
var actualHeight = $tip[0].offsetHeight
if (placement == 'top' && actualHeight != height) {
offset.top = offset.top + height - actualHeight
}
var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight)
if (delta.left) offset.left += delta.left
else offset.top += delta.top
var isVertical = /top|bottom/.test(placement)
var arrowDelta = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight
var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight'
$tip.offset(offset)
this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
}
Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) {
this.arrow()
.css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%')
.css(isVertical ? 'top' : 'left', '')
}
Tooltip.prototype.setContent = function () {
var $tip = this.tip()
var title = this.getTitle()
if (this.options.html) {
if (this.options.sanitize) {
title = sanitizeHtml(title, this.options.whiteList, this.options.sanitizeFn)
}
$tip.find('.tooltip-inner').html(title)
} else {
$tip.find('.tooltip-inner').text(title)
}
$tip.removeClass('fade in top bottom left right')
}
Tooltip.prototype.hide = function (callback) {
var that = this
var $tip = $(this.$tip)
var e = $.Event('hide.bs.' + this.type)
function complete() {
if (that.hoverState != 'in') $tip.detach()
if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary.
that.$element
.removeAttr('aria-describedby')
.trigger('hidden.bs.' + that.type)
}
callback && callback()
}
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
$tip.removeClass('in')
$.support.transition && $tip.hasClass('fade') ?
$tip
.one('bsTransitionEnd', complete)
.emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
complete()
this.hoverState = null
return this
}
Tooltip.prototype.fixTitle = function () {
var $e = this.$element
if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
$e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
}
}
Tooltip.prototype.hasContent = function () {
return this.getTitle()
}
Tooltip.prototype.getPosition = function ($element) {
$element = $element || this.$element
var el = $element[0]
var isBody = el.tagName == 'BODY'
var elRect = el.getBoundingClientRect()
if (elRect.width == null) {
// width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093
elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top })
}
var isSvg = window.SVGElement && el instanceof window.SVGElement
// Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3.
// See https://github.com/twbs/bootstrap/issues/20280
var elOffset = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset())
var scroll = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() }
var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null
return $.extend({}, elRect, scroll, outerDims, elOffset)
}
Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
/* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
}
Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) {
var delta = { top: 0, left: 0 }
if (!this.$viewport) return delta
var viewportPadding = this.options.viewport && this.options.viewport.padding || 0
var viewportDimensions = this.getPosition(this.$viewport)
if (/right|left/.test(placement)) {
var topEdgeOffset = pos.top - viewportPadding - viewportDimensions.scroll
var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight
if (topEdgeOffset < viewportDimensions.top) { // top overflow
delta.top = viewportDimensions.top - topEdgeOffset
} else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow
delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset
}
} else {
var leftEdgeOffset = pos.left - viewportPadding
var rightEdgeOffset = pos.left + viewportPadding + actualWidth
if (leftEdgeOffset < viewportDimensions.left) { // left overflow
delta.left = viewportDimensions.left - leftEdgeOffset
} else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
}
}
return delta
}
Tooltip.prototype.getTitle = function () {
var title
var $e = this.$element
var o = this.options
title = $e.attr('data-original-title')
|| (typeof o.title == 'function' ? o.title.call($e[0]) : o.title)
return title
}
Tooltip.prototype.getUID = function (prefix) {
do prefix += ~~(Math.random() * 1000000)
while (document.getElementById(prefix))
return prefix
}
Tooltip.prototype.tip = function () {
if (!this.$tip) {
this.$tip = $(this.options.template)
if (this.$tip.length != 1) {
throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!')
}
}
return this.$tip
}
Tooltip.prototype.arrow = function () {
return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
}
Tooltip.prototype.enable = function () {
this.enabled = true
}
Tooltip.prototype.disable = function () {
this.enabled = false
}
Tooltip.prototype.toggleEnabled = function () {
this.enabled = !this.enabled
}
Tooltip.prototype.toggle = function (e) {
var self = this
if (e) {
self = $(e.currentTarget).data('bs.' + this.type)
if (!self) {
self = new this.constructor(e.currentTarget, this.getDelegateOptions())
$(e.currentTarget).data('bs.' + this.type, self)
}
}
if (e) {
self.inState.click = !self.inState.click
if (self.isInStateTrue()) self.enter(self)
else self.leave(self)
} else {
self.tip().hasClass('in') ? self.leave(self) : self.enter(self)
}
}
Tooltip.prototype.destroy = function () {
var that = this
clearTimeout(this.timeout)
this.hide(function () {
that.$element.off('.' + that.type).removeData('bs.' + that.type)
if (that.$tip) {
that.$tip.detach()
}
that.$tip = null
that.$arrow = null
that.$viewport = null
that.$element = null
})
}
Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
}
// TOOLTIP PLUGIN DEFINITION
// =========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.tooltip')
var options = typeof option == 'object' && option
if (!data && /destroy|hide/.test(option)) return
if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.tooltip
$.fn.tooltip = Plugin
$.fn.tooltip.Constructor = Tooltip
// TOOLTIP NO CONFLICT
// ===================
$.fn.tooltip.noConflict = function () {
$.fn.tooltip = old
return this
}
}(jQuery);
/* ========================================================================
* Bootstrap: popover.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#popovers
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// POPOVER PUBLIC CLASS DEFINITION
// ===============================
var Popover = function (element, options) {
this.init('popover', element, options)
}
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
Popover.VERSION = '3.4.1'
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
placement: 'right',
trigger: 'click',
content: '',
template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>'
})
// NOTE: POPOVER EXTENDS tooltip.js
// ================================
Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype)
Popover.prototype.constructor = Popover
Popover.prototype.getDefaults = function () {
return Popover.DEFAULTS
}
Popover.prototype.setContent = function () {
var $tip = this.tip()
var title = this.getTitle()
var content = this.getContent()
if (this.options.html) {
var typeContent = typeof content
if (this.options.sanitize) {
title = this.sanitizeHtml(title)
if (typeContent === 'string') {
content = this.sanitizeHtml(content)
}
}
$tip.find('.popover-title').html(title)
$tip.find('.popover-content').children().detach().end()[
typeContent === 'string' ? 'html' : 'append'
](content)
} else {
$tip.find('.popover-title').text(title)
$tip.find('.popover-content').children().detach().end().text(content)
}
$tip.removeClass('fade top bottom left right in')
// IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
// this manually by checking the contents.
if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide()
}
Popover.prototype.hasContent = function () {
return this.getTitle() || this.getContent()
}
Popover.prototype.getContent = function () {
var $e = this.$element
var o = this.options
return $e.attr('data-content')
|| (typeof o.content == 'function' ?
o.content.call($e[0]) :
o.content)
}
Popover.prototype.arrow = function () {
return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
}
// POPOVER PLUGIN DEFINITION
// =========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.popover')
var options = typeof option == 'object' && option
if (!data && /destroy|hide/.test(option)) return
if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.popover
$.fn.popover = Plugin
$.fn.popover.Constructor = Popover
// POPOVER NO CONFLICT
// ===================
$.fn.popover.noConflict = function () {
$.fn.popover = old
return this
}
}(jQuery);
/* ========================================================================
* Bootstrap: scrollspy.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#scrollspy
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// SCROLLSPY CLASS DEFINITION
// ==========================
function ScrollSpy(element, options) {
this.$body = $(document.body)
this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
this.selector = (this.options.target || '') + ' .nav li > a'
this.offsets = []
this.targets = []
this.activeTarget = null
this.scrollHeight = 0
this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
this.refresh()
this.process()
}
ScrollSpy.VERSION = '3.4.1'
ScrollSpy.DEFAULTS = {
offset: 10
}
ScrollSpy.prototype.getScrollHeight = function () {
return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight)
}
ScrollSpy.prototype.refresh = function () {
var that = this
var offsetMethod = 'offset'
var offsetBase = 0
this.offsets = []
this.targets = []
this.scrollHeight = this.getScrollHeight()
if (!$.isWindow(this.$scrollElement[0])) {
offsetMethod = 'position'
offsetBase = this.$scrollElement.scrollTop()
}
this.$body
.find(this.selector)
.map(function () {
var $el = $(this)
var href = $el.data('target') || $el.attr('href')
var $href = /^#./.test(href) && $(href)
return ($href
&& $href.length
&& $href.is(':visible')
&& [[$href[offsetMethod]().top + offsetBase, href]]) || null
})
.sort(function (a, b) { return a[0] - b[0] })
.each(function () {
that.offsets.push(this[0])
that.targets.push(this[1])
})
}
ScrollSpy.prototype.process = function () {
var scrollTop = this.$scrollElement.scrollTop() + this.options.offset
var scrollHeight = this.getScrollHeight()
var maxScroll = this.options.offset + scrollHeight - this.$scrollElement.height()
var offsets = this.offsets
var targets = this.targets
var activeTarget = this.activeTarget
var i
if (this.scrollHeight != scrollHeight) {
this.refresh()
}
if (scrollTop >= maxScroll) {
return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
}
if (activeTarget && scrollTop < offsets[0]) {
this.activeTarget = null
return this.clear()
}
for (i = offsets.length; i--;) {
activeTarget != targets[i]
&& scrollTop >= offsets[i]
&& (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
&& this.activate(targets[i])
}
}
ScrollSpy.prototype.activate = function (target) {
this.activeTarget = target
this.clear()
var selector = this.selector +
'[data-target="' + target + '"],' +
this.selector + '[href="' + target + '"]'
var active = $(selector)
.parents('li')
.addClass('active')
if (active.parent('.dropdown-menu').length) {
active = active
.closest('li.dropdown')
.addClass('active')
}
active.trigger('activate.bs.scrollspy')
}
ScrollSpy.prototype.clear = function () {
$(this.selector)
.parentsUntil(this.options.target, '.active')
.removeClass('active')
}
// SCROLLSPY PLUGIN DEFINITION
// ===========================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.scrollspy')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.scrollspy', (data = new ScrollSpy(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.scrollspy
$.fn.scrollspy = Plugin
$.fn.scrollspy.Constructor = ScrollSpy
// SCROLLSPY NO CONFLICT
// =====================
$.fn.scrollspy.noConflict = function () {
$.fn.scrollspy = old
return this
}
// SCROLLSPY DATA-API
// ==================
$(window).on('load.bs.scrollspy.data-api', function () {
$('[data-spy="scroll"]').each(function () {
var $spy = $(this)
Plugin.call($spy, $spy.data())
})
})
}(jQuery);
/* ========================================================================
* Bootstrap: tab.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#tabs
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// TAB CLASS DEFINITION
// ====================
var Tab = function (element) {
// jscs:disable requireDollarBeforejQueryAssignment
this.element = $(element)
// jscs:enable requireDollarBeforejQueryAssignment
}
Tab.VERSION = '3.4.1'
Tab.TRANSITION_DURATION = 150
Tab.prototype.show = function () {
var $this = this.element
var $ul = $this.closest('ul:not(.dropdown-menu)')
var selector = $this.data('target')
if (!selector) {
selector = $this.attr('href')
selector = selector && selector.replace(/.*(?=#[^\s]*$)/, '') // strip for ie7
}
if ($this.parent('li').hasClass('active')) return
var $previous = $ul.find('.active:last a')
var hideEvent = $.Event('hide.bs.tab', {
relatedTarget: $this[0]
})
var showEvent = $.Event('show.bs.tab', {
relatedTarget: $previous[0]
})
$previous.trigger(hideEvent)
$this.trigger(showEvent)
if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
var $target = $(document).find(selector)
this.activate($this.closest('li'), $ul)
this.activate($target, $target.parent(), function () {
$previous.trigger({
type: 'hidden.bs.tab',
relatedTarget: $this[0]
})
$this.trigger({
type: 'shown.bs.tab',
relatedTarget: $previous[0]
})
})
}
Tab.prototype.activate = function (element, container, callback) {
var $active = container.find('> .active')
var transition = callback
&& $.support.transition
&& ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
function next() {
$active
.removeClass('active')
.find('> .dropdown-menu > .active')
.removeClass('active')
.end()
.find('[data-toggle="tab"]')
.attr('aria-expanded', false)
element
.addClass('active')
.find('[data-toggle="tab"]')
.attr('aria-expanded', true)
if (transition) {
element[0].offsetWidth // reflow for transition
element.addClass('in')
} else {
element.removeClass('fade')
}
if (element.parent('.dropdown-menu').length) {
element
.closest('li.dropdown')
.addClass('active')
.end()
.find('[data-toggle="tab"]')
.attr('aria-expanded', true)
}
callback && callback()
}
$active.length && transition ?
$active
.one('bsTransitionEnd', next)
.emulateTransitionEnd(Tab.TRANSITION_DURATION) :
next()
$active.removeClass('in')
}
// TAB PLUGIN DEFINITION
// =====================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.tab')
if (!data) $this.data('bs.tab', (data = new Tab(this)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.tab
$.fn.tab = Plugin
$.fn.tab.Constructor = Tab
// TAB NO CONFLICT
// ===============
$.fn.tab.noConflict = function () {
$.fn.tab = old
return this
}
// TAB DATA-API
// ============
var clickHandler = function (e) {
e.preventDefault()
Plugin.call($(this), 'show')
}
$(document)
.on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
.on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
}(jQuery);
/* ========================================================================
* Bootstrap: affix.js v3.4.1
* https://getbootstrap.com/docs/3.4/javascript/#affix
* ========================================================================
* Copyright 2011-2019 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
* ======================================================================== */
+function ($) {
'use strict';
// AFFIX CLASS DEFINITION
// ======================
var Affix = function (element, options) {
this.options = $.extend({}, Affix.DEFAULTS, options)
var target = this.options.target === Affix.DEFAULTS.target ? $(this.options.target) : $(document).find(this.options.target)
this.$target = target
.on('scroll.bs.affix.data-api', $.proxy(this.checkPosition, this))
.on('click.bs.affix.data-api', $.proxy(this.checkPositionWithEventLoop, this))
this.$element = $(element)
this.affixed = null
this.unpin = null
this.pinnedOffset = null
this.checkPosition()
}
Affix.VERSION = '3.4.1'
Affix.RESET = 'affix affix-top affix-bottom'
Affix.DEFAULTS = {
offset: 0,
target: window
}
Affix.prototype.getState = function (scrollHeight, height, offsetTop, offsetBottom) {
var scrollTop = this.$target.scrollTop()
var position = this.$element.offset()
var targetHeight = this.$target.height()
if (offsetTop != null && this.affixed == 'top') return scrollTop < offsetTop ? 'top' : false
if (this.affixed == 'bottom') {
if (offsetTop != null) return (scrollTop + this.unpin <= position.top) ? false : 'bottom'
return (scrollTop + targetHeight <= scrollHeight - offsetBottom) ? false : 'bottom'
}
var initializing = this.affixed == null
var colliderTop = initializing ? scrollTop : position.top
var colliderHeight = initializing ? targetHeight : height
if (offsetTop != null && scrollTop <= offsetTop) return 'top'
if (offsetBottom != null && (colliderTop + colliderHeight >= scrollHeight - offsetBottom)) return 'bottom'
return false
}
Affix.prototype.getPinnedOffset = function () {
if (this.pinnedOffset) return this.pinnedOffset
this.$element.removeClass(Affix.RESET).addClass('affix')
var scrollTop = this.$target.scrollTop()
var position = this.$element.offset()
return (this.pinnedOffset = position.top - scrollTop)
}
Affix.prototype.checkPositionWithEventLoop = function () {
setTimeout($.proxy(this.checkPosition, this), 1)
}
Affix.prototype.checkPosition = function () {
if (!this.$element.is(':visible')) return
var height = this.$element.height()
var offset = this.options.offset
var offsetTop = offset.top
var offsetBottom = offset.bottom
var scrollHeight = Math.max($(document).height(), $(document.body).height())
if (typeof offset != 'object') offsetBottom = offsetTop = offset
if (typeof offsetTop == 'function') offsetTop = offset.top(this.$element)
if (typeof offsetBottom == 'function') offsetBottom = offset.bottom(this.$element)
var affix = this.getState(scrollHeight, height, offsetTop, offsetBottom)
if (this.affixed != affix) {
if (this.unpin != null) this.$element.css('top', '')
var affixType = 'affix' + (affix ? '-' + affix : '')
var e = $.Event(affixType + '.bs.affix')
this.$element.trigger(e)
if (e.isDefaultPrevented()) return
this.affixed = affix
this.unpin = affix == 'bottom' ? this.getPinnedOffset() : null
this.$element
.removeClass(Affix.RESET)
.addClass(affixType)
.trigger(affixType.replace('affix', 'affixed') + '.bs.affix')
}
if (affix == 'bottom') {
this.$element.offset({
top: scrollHeight - height - offsetBottom
})
}
}
// AFFIX PLUGIN DEFINITION
// =======================
function Plugin(option) {
return this.each(function () {
var $this = $(this)
var data = $this.data('bs.affix')
var options = typeof option == 'object' && option
if (!data) $this.data('bs.affix', (data = new Affix(this, options)))
if (typeof option == 'string') data[option]()
})
}
var old = $.fn.affix
$.fn.affix = Plugin
$.fn.affix.Constructor = Affix
// AFFIX NO CONFLICT
// =================
$.fn.affix.noConflict = function () {
$.fn.affix = old
return this
}
// AFFIX DATA-API
// ==============
$(window).on('load', function () {
$('[data-spy="affix"]').each(function () {
var $spy = $(this)
var data = $spy.data()
data.offset = data.offset || {}
if (data.offsetBottom != null) data.offset.bottom = data.offsetBottom
if (data.offsetTop != null) data.offset.top = data.offsetTop
Plugin.call($spy, data)
})
})
}(jQuery);
/*
* jQuery Iframe Transport Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2011, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* https://opensource.org/licenses/MIT
*/
/* global define, require, window, document, JSON */
;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define(['jquery'], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS:
factory(require('jquery'));
} else {
// Browser globals:
factory(window.jQuery);
}
}(function ($) {
'use strict';
// Helper variable to create unique names for the transport iframes:
var counter = 0,
jsonAPI = $,
jsonParse = 'parseJSON';
if ('JSON' in window && 'parse' in JSON) {
jsonAPI = JSON;
jsonParse = 'parse';
}
// The iframe transport accepts four additional options:
// options.fileInput: a jQuery collection of file input fields
// options.paramName: the parameter name for the file form data,
// overrides the name property of the file input field(s),
// can be a string or an array of strings.
// options.formData: an array of objects with name and value properties,
// equivalent to the return data of .serializeArray(), e.g.:
// [{name: 'a', value: 1}, {name: 'b', value: 2}]
// options.initialIframeSrc: the URL of the initial iframe src,
// by default set to "javascript:false;"
$.ajaxTransport('iframe', function (options) {
if (options.async) {
// javascript:false as initial iframe src
// prevents warning popups on HTTPS in IE6:
/*jshint scripturl: true */
var initialIframeSrc = options.initialIframeSrc || 'javascript:false;',
/*jshint scripturl: false */
form,
iframe,
addParamChar;
return {
send: function (_, completeCallback) {
form = $('<form style="display:none;"></form>');
form.attr('accept-charset', options.formAcceptCharset);
addParamChar = /\?/.test(options.url) ? '&' : '?';
// XDomainRequest only supports GET and POST:
if (options.type === 'DELETE') {
options.url = options.url + addParamChar + '_method=DELETE';
options.type = 'POST';
} else if (options.type === 'PUT') {
options.url = options.url + addParamChar + '_method=PUT';
options.type = 'POST';
} else if (options.type === 'PATCH') {
options.url = options.url + addParamChar + '_method=PATCH';
options.type = 'POST';
}
// IE versions below IE8 cannot set the name property of
// elements that have already been added to the DOM,
// so we set the name along with the iframe HTML markup:
counter += 1;
iframe = $(
'<iframe src="' + initialIframeSrc +
'" name="iframe-transport-' + counter + '"></iframe>'
).bind('load', function () {
var fileInputClones,
paramNames = $.isArray(options.paramName) ?
options.paramName : [options.paramName];
iframe
.unbind('load')
.bind('load', function () {
var response;
// Wrap in a try/catch block to catch exceptions thrown
// when trying to access cross-domain iframe contents:
try {
response = iframe.contents();
// Google Chrome and Firefox do not throw an
// exception when calling iframe.contents() on
// cross-domain requests, so we unify the response:
if (!response.length || !response[0].firstChild) {
throw new Error();
}
} catch (e) {
response = undefined;
}
// The complete callback returns the
// iframe content document as response object:
completeCallback(
200,
'success',
{'iframe': response}
);
// Fix for IE endless progress bar activity bug
// (happens on form submits to iframe targets):
$('<iframe src="' + initialIframeSrc + '"></iframe>')
.appendTo(form);
window.setTimeout(function () {
// Removing the form in a setTimeout call
// allows Chrome's developer tools to display
// the response result
form.remove();
}, 0);
});
form
.prop('target', iframe.prop('name'))
.prop('action', options.url)
.prop('method', options.type);
if (options.formData) {
$.each(options.formData, function (index, field) {
$('<input type="hidden"/>')
.prop('name', field.name)
.val(field.value)
.appendTo(form);
});
}
if (options.fileInput && options.fileInput.length &&
options.type === 'POST') {
fileInputClones = options.fileInput.clone();
// Insert a clone for each file input field:
options.fileInput.after(function (index) {
return fileInputClones[index];
});
if (options.paramName) {
options.fileInput.each(function (index) {
$(this).prop(
'name',
paramNames[index] || options.paramName
);
});
}
// Appending the file input fields to the hidden form
// removes them from their original location:
form
.append(options.fileInput)
.prop('enctype', 'multipart/form-data')
// enctype must be set as encoding for IE:
.prop('encoding', 'multipart/form-data');
// Remove the HTML5 form attribute from the input(s):
options.fileInput.removeAttr('form');
}
form.submit();
// Insert the file input fields at their original location
// by replacing the clones with the originals:
if (fileInputClones && fileInputClones.length) {
options.fileInput.each(function (index, input) {
var clone = $(fileInputClones[index]);
// Restore the original name and form properties:
$(input)
.prop('name', clone.prop('name'))
.attr('form', clone.attr('form'));
clone.replaceWith(input);
});
}
});
form.append(iframe).appendTo(document.body);
},
abort: function () {
if (iframe) {
// javascript:false as iframe src aborts the request
// and prevents warning popups on HTTPS in IE6.
// concat is used to avoid the "Script URL" JSLint error:
iframe
.unbind('load')
.prop('src', initialIframeSrc);
}
if (form) {
form.remove();
}
}
};
}
});
// The iframe transport returns the iframe content document as response.
// The following adds converters from iframe to text, json, html, xml
// and script.
// Please note that the Content-Type for JSON responses has to be text/plain
// or text/html, if the browser doesn't include application/json in the
// Accept header, else IE will show a download dialog.
// The Content-Type for XML responses on the other hand has to be always
// application/xml or text/xml, so IE properly parses the XML response.
// See also
// https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#content-type-negotiation
$.ajaxSetup({
converters: {
'iframe text': function (iframe) {
return iframe && $(iframe[0].body).text();
},
'iframe json': function (iframe) {
return iframe && jsonAPI[jsonParse]($(iframe[0].body).text());
},
'iframe html': function (iframe) {
return iframe && $(iframe[0].body).html();
},
'iframe xml': function (iframe) {
var xmlDoc = iframe && iframe[0];
return xmlDoc && $.isXMLDoc(xmlDoc) ? xmlDoc :
$.parseXML((xmlDoc.XMLDocument && xmlDoc.XMLDocument.xml) ||
$(xmlDoc.body).html());
},
'iframe script': function (iframe) {
return iframe && $.globalEval($(iframe[0].body).text());
}
}
});
}));
/*
* jQuery File Upload Plugin
* https://github.com/blueimp/jQuery-File-Upload
*
* Copyright 2010, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* https://opensource.org/licenses/MIT
*/
/* jshint nomen:false */
/* global define, require, window, document, location, Blob, FormData */
;(function (factory) {
'use strict';
if (typeof define === 'function' && define.amd) {
// Register as an anonymous AMD module:
define([
'jquery',
'jquery-ui/ui/widget'
], factory);
} else if (typeof exports === 'object') {
// Node/CommonJS:
factory(
require('jquery'),
require('./vendor/jquery.ui.widget')
);
} else {
// Browser globals:
factory(window.jQuery);
}
}(function ($) {
'use strict';
// Detect file input support, based on
// http://viljamis.com/blog/2012/file-upload-support-on-mobile/
$.support.fileInput = !(new RegExp(
// Handle devices which give false positives for the feature detection:
'(Android (1\\.[0156]|2\\.[01]))' +
'|(Windows Phone (OS 7|8\\.0))|(XBLWP)|(ZuneWP)|(WPDesktop)' +
'|(w(eb)?OSBrowser)|(webOS)' +
'|(Kindle/(1\\.0|2\\.[05]|3\\.0))'
).test(window.navigator.userAgent) ||
// Feature detection for all other devices:
$('<input type="file"/>').prop('disabled'));
// The FileReader API is not actually used, but works as feature detection,
// as some Safari versions (5?) support XHR file uploads via the FormData API,
// but not non-multipart XHR file uploads.
// window.XMLHttpRequestUpload is not available on IE10, so we check for
// window.ProgressEvent instead to detect XHR2 file upload capability:
$.support.xhrFileUpload = !!(window.ProgressEvent && window.FileReader);
$.support.xhrFormDataFileUpload = !!window.FormData;
// Detect support for Blob slicing (required for chunked uploads):
$.support.blobSlice = window.Blob && (Blob.prototype.slice ||
Blob.prototype.webkitSlice || Blob.prototype.mozSlice);
// Helper function to create drag handlers for dragover/dragenter/dragleave:
function getDragHandler(type) {
var isDragOver = type === 'dragover';
return function (e) {
e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
var dataTransfer = e.dataTransfer;
if (dataTransfer && $.inArray('Files', dataTransfer.types) !== -1 &&
this._trigger(
type,
$.Event(type, {delegatedEvent: e})
) !== false) {
e.preventDefault();
if (isDragOver) {
dataTransfer.dropEffect = 'copy';
}
}
};
}
// The fileupload widget listens for change events on file input fields defined
// via fileInput setting and paste or drop events of the given dropZone.
// In addition to the default jQuery Widget methods, the fileupload widget
// exposes the "add" and "send" methods, to add or directly send files using
// the fileupload API.
// By default, files added via file input selection, paste, drag & drop or
// "add" method are uploaded immediately, but it is possible to override
// the "add" callback option to queue file uploads.
$.widget('blueimp.fileupload', {
options: {
// The drop target element(s), by the default the complete document.
// Set to null to disable drag & drop support:
dropZone: $(document),
// The paste target element(s), by the default undefined.
// Set to a DOM node or jQuery object to enable file pasting:
pasteZone: undefined,
// The file input field(s), that are listened to for change events.
// If undefined, it is set to the file input fields inside
// of the widget element on plugin initialization.
// Set to null to disable the change listener.
fileInput: undefined,
// By default, the file input field is replaced with a clone after
// each input field change event. This is required for iframe transport
// queues and allows change events to be fired for the same file
// selection, but can be disabled by setting the following option to false:
replaceFileInput: true,
// The parameter name for the file form data (the request argument name).
// If undefined or empty, the name property of the file input field is
// used, or "files[]" if the file input name property is also empty,
// can be a string or an array of strings:
paramName: undefined,
// By default, each file of a selection is uploaded using an individual
// request for XHR type uploads. Set to false to upload file
// selections in one request each:
singleFileUploads: true,
// To limit the number of files uploaded with one XHR request,
// set the following option to an integer greater than 0:
limitMultiFileUploads: undefined,
// The following option limits the number of files uploaded with one
// XHR request to keep the request size under or equal to the defined
// limit in bytes:
limitMultiFileUploadSize: undefined,
// Multipart file uploads add a number of bytes to each uploaded file,
// therefore the following option adds an overhead for each file used
// in the limitMultiFileUploadSize configuration:
limitMultiFileUploadSizeOverhead: 512,
// Set the following option to true to issue all file upload requests
// in a sequential order:
sequentialUploads: false,
// To limit the number of concurrent uploads,
// set the following option to an integer greater than 0:
limitConcurrentUploads: undefined,
// Set the following option to true to force iframe transport uploads:
forceIframeTransport: false,
// Set the following option to the location of a redirect url on the
// origin server, for cross-domain iframe transport uploads:
redirect: undefined,
// The parameter name for the redirect url, sent as part of the form
// data and set to 'redirect' if this option is empty:
redirectParamName: undefined,
// Set the following option to the location of a postMessage window,
// to enable postMessage transport uploads:
postMessage: undefined,
// By default, XHR file uploads are sent as multipart/form-data.
// The iframe transport is always using multipart/form-data.
// Set to false to enable non-multipart XHR uploads:
multipart: true,
// To upload large files in smaller chunks, set the following option
// to a preferred maximum chunk size. If set to 0, null or undefined,
// or the browser does not support the required Blob API, files will
// be uploaded as a whole.
maxChunkSize: undefined,
// When a non-multipart upload or a chunked multipart upload has been
// aborted, this option can be used to resume the upload by setting
// it to the size of the already uploaded bytes. This option is most
// useful when modifying the options object inside of the "add" or
// "send" callbacks, as the options are cloned for each file upload.
uploadedBytes: undefined,
// By default, failed (abort or error) file uploads are removed from the
// global progress calculation. Set the following option to false to
// prevent recalculating the global progress data:
recalculateProgress: true,
// Interval in milliseconds to calculate and trigger progress events:
progressInterval: 100,
// Interval in milliseconds to calculate progress bitrate:
bitrateInterval: 500,
// By default, uploads are started automatically when adding files:
autoUpload: true,
// Error and info messages:
messages: {
uploadedBytes: 'Uploaded bytes exceed file size'
},
// Translation function, gets the message key to be translated
// and an object with context specific data as arguments:
i18n: function (message, context) {
message = this.messages[message] || message.toString();
if (context) {
$.each(context, function (key, value) {
message = message.replace('{' + key + '}', value);
});
}
return message;
},
// Additional form data to be sent along with the file uploads can be set
// using this option, which accepts an array of objects with name and
// value properties, a function returning such an array, a FormData
// object (for XHR file uploads), or a simple object.
// The form of the first fileInput is given as parameter to the function:
formData: function (form) {
return form.serializeArray();
},
// The add callback is invoked as soon as files are added to the fileupload
// widget (via file input selection, drag & drop, paste or add API call).
// If the singleFileUploads option is enabled, this callback will be
// called once for each file in the selection for XHR file uploads, else
// once for each file selection.
//
// The upload starts when the submit method is invoked on the data parameter.
// The data object contains a files property holding the added files
// and allows you to override plugin options as well as define ajax settings.
//
// Listeners for this callback can also be bound the following way:
// .bind('fileuploadadd', func);
//
// data.submit() returns a Promise object and allows to attach additional
// handlers using jQuery's Deferred callbacks:
// data.submit().done(func).fail(func).always(func);
add: function (e, data) {
if (e.isDefaultPrevented()) {
return false;
}
if (data.autoUpload || (data.autoUpload !== false &&
$(this).fileupload('option', 'autoUpload'))) {
data.process().done(function () {
data.submit();
});
}
},
// Other callbacks:
// Callback for the submit event of each file upload:
// submit: function (e, data) {}, // .bind('fileuploadsubmit', func);
// Callback for the start of each file upload request:
// send: function (e, data) {}, // .bind('fileuploadsend', func);
// Callback for successful uploads:
// done: function (e, data) {}, // .bind('fileuploaddone', func);
// Callback for failed (abort or error) uploads:
// fail: function (e, data) {}, // .bind('fileuploadfail', func);
// Callback for completed (success, abort or error) requests:
// always: function (e, data) {}, // .bind('fileuploadalways', func);
// Callback for upload progress events:
// progress: function (e, data) {}, // .bind('fileuploadprogress', func);
// Callback for global upload progress events:
// progressall: function (e, data) {}, // .bind('fileuploadprogressall', func);
// Callback for uploads start, equivalent to the global ajaxStart event:
// start: function (e) {}, // .bind('fileuploadstart', func);
// Callback for uploads stop, equivalent to the global ajaxStop event:
// stop: function (e) {}, // .bind('fileuploadstop', func);
// Callback for change events of the fileInput(s):
// change: function (e, data) {}, // .bind('fileuploadchange', func);
// Callback for paste events to the pasteZone(s):
// paste: function (e, data) {}, // .bind('fileuploadpaste', func);
// Callback for drop events of the dropZone(s):
// drop: function (e, data) {}, // .bind('fileuploaddrop', func);
// Callback for dragover events of the dropZone(s):
// dragover: function (e) {}, // .bind('fileuploaddragover', func);
// Callback before the start of each chunk upload request (before form data initialization):
// chunkbeforesend: function (e, data) {}, // .bind('fileuploadchunkbeforesend', func);
// Callback for the start of each chunk upload request:
// chunksend: function (e, data) {}, // .bind('fileuploadchunksend', func);
// Callback for successful chunk uploads:
// chunkdone: function (e, data) {}, // .bind('fileuploadchunkdone', func);
// Callback for failed (abort or error) chunk uploads:
// chunkfail: function (e, data) {}, // .bind('fileuploadchunkfail', func);
// Callback for completed (success, abort or error) chunk upload requests:
// chunkalways: function (e, data) {}, // .bind('fileuploadchunkalways', func);
// The plugin options are used as settings object for the ajax calls.
// The following are jQuery ajax settings required for the file uploads:
processData: false,
contentType: false,
cache: false,
timeout: 0
},
// A list of options that require reinitializing event listeners and/or
// special initialization code:
_specialOptions: [
'fileInput',
'dropZone',
'pasteZone',
'multipart',
'forceIframeTransport'
],
_blobSlice: $.support.blobSlice && function () {
var slice = this.slice || this.webkitSlice || this.mozSlice;
return slice.apply(this, arguments);
},
_BitrateTimer: function () {
this.timestamp = ((Date.now) ? Date.now() : (new Date()).getTime());
this.loaded = 0;
this.bitrate = 0;
this.getBitrate = function (now, loaded, interval) {
var timeDiff = now - this.timestamp;
if (!this.bitrate || !interval || timeDiff > interval) {
this.bitrate = (loaded - this.loaded) * (1000 / timeDiff) * 8;
this.loaded = loaded;
this.timestamp = now;
}
return this.bitrate;
};
},
_isXHRUpload: function (options) {
return !options.forceIframeTransport &&
((!options.multipart && $.support.xhrFileUpload) ||
$.support.xhrFormDataFileUpload);
},
_getFormData: function (options) {
var formData;
if ($.type(options.formData) === 'function') {
return options.formData(options.form);
}
if ($.isArray(options.formData)) {
return options.formData;
}
if ($.type(options.formData) === 'object') {
formData = [];
$.each(options.formData, function (name, value) {
formData.push({name: name, value: value});
});
return formData;
}
return [];
},
_getTotal: function (files) {
var total = 0;
$.each(files, function (index, file) {
total += file.size || 1;
});
return total;
},
_initProgressObject: function (obj) {
var progress = {
loaded: 0,
total: 0,
bitrate: 0
};
if (obj._progress) {
$.extend(obj._progress, progress);
} else {
obj._progress = progress;
}
},
_initResponseObject: function (obj) {
var prop;
if (obj._response) {
for (prop in obj._response) {
if (obj._response.hasOwnProperty(prop)) {
delete obj._response[prop];
}
}
} else {
obj._response = {};
}
},
_onProgress: function (e, data) {
if (e.lengthComputable) {
var now = ((Date.now) ? Date.now() : (new Date()).getTime()),
loaded;
if (data._time && data.progressInterval &&
(now - data._time < data.progressInterval) &&
e.loaded !== e.total) {
return;
}
data._time = now;
loaded = Math.floor(
e.loaded / e.total * (data.chunkSize || data._progress.total)
) + (data.uploadedBytes || 0);
// Add the difference from the previously loaded state
// to the global loaded counter:
this._progress.loaded += (loaded - data._progress.loaded);
this._progress.bitrate = this._bitrateTimer.getBitrate(
now,
this._progress.loaded,
data.bitrateInterval
);
data._progress.loaded = data.loaded = loaded;
data._progress.bitrate = data.bitrate = data._bitrateTimer.getBitrate(
now,
loaded,
data.bitrateInterval
);
// Trigger a custom progress event with a total data property set
// to the file size(s) of the current upload and a loaded data
// property calculated accordingly:
this._trigger(
'progress',
$.Event('progress', {delegatedEvent: e}),
data
);
// Trigger a global progress event for all current file uploads,
// including ajax calls queued for sequential file uploads:
this._trigger(
'progressall',
$.Event('progressall', {delegatedEvent: e}),
this._progress
);
}
},
_initProgressListener: function (options) {
var that = this,
xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
// Accesss to the native XHR object is required to add event listeners
// for the upload progress event:
if (xhr.upload) {
$(xhr.upload).bind('progress', function (e) {
var oe = e.originalEvent;
// Make sure the progress event properties get copied over:
e.lengthComputable = oe.lengthComputable;
e.loaded = oe.loaded;
e.total = oe.total;
that._onProgress(e, options);
});
options.xhr = function () {
return xhr;
};
}
},
_deinitProgressListener: function (options) {
var xhr = options.xhr ? options.xhr() : $.ajaxSettings.xhr();
if (xhr.upload) {
$(xhr.upload).unbind('progress');
}
},
_isInstanceOf: function (type, obj) {
// Cross-frame instanceof check
return Object.prototype.toString.call(obj) === '[object ' + type + ']';
},
_initXHRData: function (options) {
var that = this,
formData,
file = options.files[0],
// Ignore non-multipart setting if not supported:
multipart = options.multipart || !$.support.xhrFileUpload,
paramName = $.type(options.paramName) === 'array' ?
options.paramName[0] : options.paramName;
options.headers = $.extend({}, options.headers);
if (options.contentRange) {
options.headers['Content-Range'] = options.contentRange;
}
if (!multipart || options.blob || !this._isInstanceOf('File', file)) {
options.headers['Content-Disposition'] = 'attachment; filename="' +
encodeURI(file.uploadName || file.name) + '"';
}
if (!multipart) {
options.contentType = file.type || 'application/octet-stream';
options.data = options.blob || file;
} else if ($.support.xhrFormDataFileUpload) {
if (options.postMessage) {
// window.postMessage does not allow sending FormData
// objects, so we just add the File/Blob objects to
// the formData array and let the postMessage window
// create the FormData object out of this array:
formData = this._getFormData(options);
if (options.blob) {
formData.push({
name: paramName,
value: options.blob
});
} else {
$.each(options.files, function (index, file) {
formData.push({
name: ($.type(options.paramName) === 'array' &&
options.paramName[index]) || paramName,
value: file
});
});
}
} else {
if (that._isInstanceOf('FormData', options.formData)) {
formData = options.formData;
} else {
formData = new FormData();
$.each(this._getFormData(options), function (index, field) {
formData.append(field.name, field.value);
});
}
if (options.blob) {
formData.append(
paramName,
options.blob,
file.uploadName || file.name
);
} else {
$.each(options.files, function (index, file) {
// This check allows the tests to run with
// dummy objects:
if (that._isInstanceOf('File', file) ||
that._isInstanceOf('Blob', file)) {
formData.append(
($.type(options.paramName) === 'array' &&
options.paramName[index]) || paramName,
file,
file.uploadName || file.name
);
}
});
}
}
options.data = formData;
}
// Blob reference is not needed anymore, free memory:
options.blob = null;
},
_initIframeSettings: function (options) {
var targetHost = $('<a></a>').prop('href', options.url).prop('host');
// Setting the dataType to iframe enables the iframe transport:
options.dataType = 'iframe ' + (options.dataType || '');
// The iframe transport accepts a serialized array as form data:
options.formData = this._getFormData(options);
// Add redirect url to form data on cross-domain uploads:
if (options.redirect && targetHost && targetHost !== location.host) {
options.formData.push({
name: options.redirectParamName || 'redirect',
value: options.redirect
});
}
},
_initDataSettings: function (options) {
if (this._isXHRUpload(options)) {
if (!this._chunkedUpload(options, true)) {
if (!options.data) {
this._initXHRData(options);
}
this._initProgressListener(options);
}
if (options.postMessage) {
// Setting the dataType to postmessage enables the
// postMessage transport:
options.dataType = 'postmessage ' + (options.dataType || '');
}
} else {
this._initIframeSettings(options);
}
},
_getParamName: function (options) {
var fileInput = $(options.fileInput),
paramName = options.paramName;
if (!paramName) {
paramName = [];
fileInput.each(function () {
var input = $(this),
name = input.prop('name') || 'files[]',
i = (input.prop('files') || [1]).length;
while (i) {
paramName.push(name);
i -= 1;
}
});
if (!paramName.length) {
paramName = [fileInput.prop('name') || 'files[]'];
}
} else if (!$.isArray(paramName)) {
paramName = [paramName];
}
return paramName;
},
_initFormSettings: function (options) {
// Retrieve missing options from the input field and the
// associated form, if available:
if (!options.form || !options.form.length) {
options.form = $(options.fileInput.prop('form'));
// If the given file input doesn't have an associated form,
// use the default widget file input's form:
if (!options.form.length) {
options.form = $(this.options.fileInput.prop('form'));
}
}
options.paramName = this._getParamName(options);
if (!options.url) {
options.url = options.form.prop('action') || location.href;
}
// The HTTP request method must be "POST" or "PUT":
options.type = (options.type ||
($.type(options.form.prop('method')) === 'string' &&
options.form.prop('method')) || ''
).toUpperCase();
if (options.type !== 'POST' && options.type !== 'PUT' &&
options.type !== 'PATCH') {
options.type = 'POST';
}
if (!options.formAcceptCharset) {
options.formAcceptCharset = options.form.attr('accept-charset');
}
},
_getAJAXSettings: function (data) {
var options = $.extend({}, this.options, data);
this._initFormSettings(options);
this._initDataSettings(options);
return options;
},
// jQuery 1.6 doesn't provide .state(),
// while jQuery 1.8+ removed .isRejected() and .isResolved():
_getDeferredState: function (deferred) {
if (deferred.state) {
return deferred.state();
}
if (deferred.isResolved()) {
return 'resolved';
}
if (deferred.isRejected()) {
return 'rejected';
}
return 'pending';
},
// Maps jqXHR callbacks to the equivalent
// methods of the given Promise object:
_enhancePromise: function (promise) {
promise.success = promise.done;
promise.error = promise.fail;
promise.complete = promise.always;
return promise;
},
// Creates and returns a Promise object enhanced with
// the jqXHR methods abort, success, error and complete:
_getXHRPromise: function (resolveOrReject, context, args) {
var dfd = $.Deferred(),
promise = dfd.promise();
context = context || this.options.context || promise;
if (resolveOrReject === true) {
dfd.resolveWith(context, args);
} else if (resolveOrReject === false) {
dfd.rejectWith(context, args);
}
promise.abort = dfd.promise;
return this._enhancePromise(promise);
},
// Adds convenience methods to the data callback argument:
_addConvenienceMethods: function (e, data) {
var that = this,
getPromise = function (args) {
return $.Deferred().resolveWith(that, args).promise();
};
data.process = function (resolveFunc, rejectFunc) {
if (resolveFunc || rejectFunc) {
data._processQueue = this._processQueue =
(this._processQueue || getPromise([this])).then(
function () {
if (data.errorThrown) {
return $.Deferred()
.rejectWith(that, [data]).promise();
}
return getPromise(arguments);
}
).then(resolveFunc, rejectFunc);
}
return this._processQueue || getPromise([this]);
};
data.submit = function () {
if (this.state() !== 'pending') {
data.jqXHR = this.jqXHR =
(that._trigger(
'submit',
$.Event('submit', {delegatedEvent: e}),
this
) !== false) && that._onSend(e, this);
}
return this.jqXHR || that._getXHRPromise();
};
data.abort = function () {
if (this.jqXHR) {
return this.jqXHR.abort();
}
this.errorThrown = 'abort';
that._trigger('fail', null, this);
return that._getXHRPromise(false);
};
data.state = function () {
if (this.jqXHR) {
return that._getDeferredState(this.jqXHR);
}
if (this._processQueue) {
return that._getDeferredState(this._processQueue);
}
};
data.processing = function () {
return !this.jqXHR && this._processQueue && that
._getDeferredState(this._processQueue) === 'pending';
};
data.progress = function () {
return this._progress;
};
data.response = function () {
return this._response;
};
},
// Parses the Range header from the server response
// and returns the uploaded bytes:
_getUploadedBytes: function (jqXHR) {
var range = jqXHR.getResponseHeader('Range'),
parts = range && range.split('-'),
upperBytesPos = parts && parts.length > 1 &&
parseInt(parts[1], 10);
return upperBytesPos && upperBytesPos + 1;
},
// Uploads a file in multiple, sequential requests
// by splitting the file up in multiple blob chunks.
// If the second parameter is true, only tests if the file
// should be uploaded in chunks, but does not invoke any
// upload requests:
_chunkedUpload: function (options, testOnly) {
options.uploadedBytes = options.uploadedBytes || 0;
var that = this,
file = options.files[0],
fs = file.size,
ub = options.uploadedBytes,
mcs = options.maxChunkSize || fs,
slice = this._blobSlice,
dfd = $.Deferred(),
promise = dfd.promise(),
jqXHR,
upload;
if (!(this._isXHRUpload(options) && slice && (ub || ($.type(mcs) === 'function' ? mcs(options) : mcs) < fs)) ||
options.data) {
return false;
}
if (testOnly) {
return true;
}
if (ub >= fs) {
file.error = options.i18n('uploadedBytes');
return this._getXHRPromise(
false,
options.context,
[null, 'error', file.error]
);
}
// The chunk upload method:
upload = function () {
// Clone the options object for each chunk upload:
var o = $.extend({}, options),
currentLoaded = o._progress.loaded;
o.blob = slice.call(
file,
ub,
ub + ($.type(mcs) === 'function' ? mcs(o) : mcs),
file.type
);
// Store the current chunk size, as the blob itself
// will be dereferenced after data processing:
o.chunkSize = o.blob.size;
// Expose the chunk bytes position range:
o.contentRange = 'bytes ' + ub + '-' +
(ub + o.chunkSize - 1) + '/' + fs;
// Trigger chunkbeforesend to allow form data to be updated for this chunk
that._trigger('chunkbeforesend', null, o);
// Process the upload data (the blob and potential form data):
that._initXHRData(o);
// Add progress listeners for this chunk upload:
that._initProgressListener(o);
jqXHR = ((that._trigger('chunksend', null, o) !== false && $.ajax(o)) ||
that._getXHRPromise(false, o.context))
.done(function (result, textStatus, jqXHR) {
ub = that._getUploadedBytes(jqXHR) ||
(ub + o.chunkSize);
// Create a progress event if no final progress event
// with loaded equaling total has been triggered
// for this chunk:
if (currentLoaded + o.chunkSize - o._progress.loaded) {
that._onProgress($.Event('progress', {
lengthComputable: true,
loaded: ub - o.uploadedBytes,
total: ub - o.uploadedBytes
}), o);
}
options.uploadedBytes = o.uploadedBytes = ub;
o.result = result;
o.textStatus = textStatus;
o.jqXHR = jqXHR;
that._trigger('chunkdone', null, o);
that._trigger('chunkalways', null, o);
if (ub < fs) {
// File upload not yet complete,
// continue with the next chunk:
upload();
} else {
dfd.resolveWith(
o.context,
[result, textStatus, jqXHR]
);
}
})
.fail(function (jqXHR, textStatus, errorThrown) {
o.jqXHR = jqXHR;
o.textStatus = textStatus;
o.errorThrown = errorThrown;
that._trigger('chunkfail', null, o);
that._trigger('chunkalways', null, o);
dfd.rejectWith(
o.context,
[jqXHR, textStatus, errorThrown]
);
})
.always(function () {
that._deinitProgressListener(o);
});
};
this._enhancePromise(promise);
promise.abort = function () {
return jqXHR.abort();
};
upload();
return promise;
},
_beforeSend: function (e, data) {
if (this._active === 0) {
// the start callback is triggered when an upload starts
// and no other uploads are currently running,
// equivalent to the global ajaxStart event:
this._trigger('start');
// Set timer for global bitrate progress calculation:
this._bitrateTimer = new this._BitrateTimer();
// Reset the global progress values:
this._progress.loaded = this._progress.total = 0;
this._progress.bitrate = 0;
}
// Make sure the container objects for the .response() and
// .progress() methods on the data object are available
// and reset to their initial state:
this._initResponseObject(data);
this._initProgressObject(data);
data._progress.loaded = data.loaded = data.uploadedBytes || 0;
data._progress.total = data.total = this._getTotal(data.files) || 1;
data._progress.bitrate = data.bitrate = 0;
this._active += 1;
// Initialize the global progress values:
this._progress.loaded += data.loaded;
this._progress.total += data.total;
},
_onDone: function (result, textStatus, jqXHR, options) {
var total = options._progress.total,
response = options._response;
if (options._progress.loaded < total) {
// Create a progress event if no final progress event
// with loaded equaling total has been triggered:
this._onProgress($.Event('progress', {
lengthComputable: true,
loaded: total,
total: total
}), options);
}
response.result = options.result = result;
response.textStatus = options.textStatus = textStatus;
response.jqXHR = options.jqXHR = jqXHR;
this._trigger('done', null, options);
},
_onFail: function (jqXHR, textStatus, errorThrown, options) {
var response = options._response;
if (options.recalculateProgress) {
// Remove the failed (error or abort) file upload from
// the global progress calculation:
this._progress.loaded -= options._progress.loaded;
this._progress.total -= options._progress.total;
}
response.jqXHR = options.jqXHR = jqXHR;
response.textStatus = options.textStatus = textStatus;
response.errorThrown = options.errorThrown = errorThrown;
this._trigger('fail', null, options);
},
_onAlways: function (jqXHRorResult, textStatus, jqXHRorError, options) {
// jqXHRorResult, textStatus and jqXHRorError are added to the
// options object via done and fail callbacks
this._trigger('always', null, options);
},
_onSend: function (e, data) {
if (!data.submit) {
this._addConvenienceMethods(e, data);
}
var that = this,
jqXHR,
aborted,
slot,
pipe,
options = that._getAJAXSettings(data),
send = function () {
that._sending += 1;
// Set timer for bitrate progress calculation:
options._bitrateTimer = new that._BitrateTimer();
jqXHR = jqXHR || (
((aborted || that._trigger(
'send',
$.Event('send', {delegatedEvent: e}),
options
) === false) &&
that._getXHRPromise(false, options.context, aborted)) ||
that._chunkedUpload(options) || $.ajax(options)
).done(function (result, textStatus, jqXHR) {
that._onDone(result, textStatus, jqXHR, options);
}).fail(function (jqXHR, textStatus, errorThrown) {
that._onFail(jqXHR, textStatus, errorThrown, options);
}).always(function (jqXHRorResult, textStatus, jqXHRorError) {
that._deinitProgressListener(options);
that._onAlways(
jqXHRorResult,
textStatus,
jqXHRorError,
options
);
that._sending -= 1;
that._active -= 1;
if (options.limitConcurrentUploads &&
options.limitConcurrentUploads > that._sending) {
// Start the next queued upload,
// that has not been aborted:
var nextSlot = that._slots.shift();
while (nextSlot) {
if (that._getDeferredState(nextSlot) === 'pending') {
nextSlot.resolve();
break;
}
nextSlot = that._slots.shift();
}
}
if (that._active === 0) {
// The stop callback is triggered when all uploads have
// been completed, equivalent to the global ajaxStop event:
that._trigger('stop');
}
});
return jqXHR;
};
this._beforeSend(e, options);
if (this.options.sequentialUploads ||
(this.options.limitConcurrentUploads &&
this.options.limitConcurrentUploads <= this._sending)) {
if (this.options.limitConcurrentUploads > 1) {
slot = $.Deferred();
this._slots.push(slot);
pipe = slot.then(send);
} else {
this._sequence = this._sequence.then(send, send);
pipe = this._sequence;
}
// Return the piped Promise object, enhanced with an abort method,
// which is delegated to the jqXHR object of the current upload,
// and jqXHR callbacks mapped to the equivalent Promise methods:
pipe.abort = function () {
aborted = [undefined, 'abort', 'abort'];
if (!jqXHR) {
if (slot) {
slot.rejectWith(options.context, aborted);
}
return send();
}
return jqXHR.abort();
};
return this._enhancePromise(pipe);
}
return send();
},
_onAdd: function (e, data) {
var that = this,
result = true,
options = $.extend({}, this.options, data),
files = data.files,
filesLength = files.length,
limit = options.limitMultiFileUploads,
limitSize = options.limitMultiFileUploadSize,
overhead = options.limitMultiFileUploadSizeOverhead,
batchSize = 0,
paramName = this._getParamName(options),
paramNameSet,
paramNameSlice,
fileSet,
i,
j = 0;
if (!filesLength) {
return false;
}
if (limitSize && files[0].size === undefined) {
limitSize = undefined;
}
if (!(options.singleFileUploads || limit || limitSize) ||
!this._isXHRUpload(options)) {
fileSet = [files];
paramNameSet = [paramName];
} else if (!(options.singleFileUploads || limitSize) && limit) {
fileSet = [];
paramNameSet = [];
for (i = 0; i < filesLength; i += limit) {
fileSet.push(files.slice(i, i + limit));
paramNameSlice = paramName.slice(i, i + limit);
if (!paramNameSlice.length) {
paramNameSlice = paramName;
}
paramNameSet.push(paramNameSlice);
}
} else if (!options.singleFileUploads && limitSize) {
fileSet = [];
paramNameSet = [];
for (i = 0; i < filesLength; i = i + 1) {
batchSize += files[i].size + overhead;
if (i + 1 === filesLength ||
((batchSize + files[i + 1].size + overhead) > limitSize) ||
(limit && i + 1 - j >= limit)) {
fileSet.push(files.slice(j, i + 1));
paramNameSlice = paramName.slice(j, i + 1);
if (!paramNameSlice.length) {
paramNameSlice = paramName;
}
paramNameSet.push(paramNameSlice);
j = i + 1;
batchSize = 0;
}
}
} else {
paramNameSet = paramName;
}
data.originalFiles = files;
$.each(fileSet || files, function (index, element) {
var newData = $.extend({}, data);
newData.files = fileSet ? element : [element];
newData.paramName = paramNameSet[index];
that._initResponseObject(newData);
that._initProgressObject(newData);
that._addConvenienceMethods(e, newData);
result = that._trigger(
'add',
$.Event('add', {delegatedEvent: e}),
newData
);
return result;
});
return result;
},
_replaceFileInput: function (data) {
var input = data.fileInput,
inputClone = input.clone(true),
restoreFocus = input.is(document.activeElement);
// Add a reference for the new cloned file input to the data argument:
data.fileInputClone = inputClone;
$('<form></form>').append(inputClone)[0].reset();
// Detaching allows to insert the fileInput on another form
// without loosing the file input value:
input.after(inputClone).detach();
// If the fileInput had focus before it was detached,
// restore focus to the inputClone.
if (restoreFocus) {
inputClone.focus();
}
// Avoid memory leaks with the detached file input:
$.cleanData(input.unbind('remove'));
// Replace the original file input element in the fileInput
// elements set with the clone, which has been copied including
// event handlers:
this.options.fileInput = this.options.fileInput.map(function (i, el) {
if (el === input[0]) {
return inputClone[0];
}
return el;
});
// If the widget has been initialized on the file input itself,
// override this.element with the file input clone:
if (input[0] === this.element[0]) {
this.element = inputClone;
}
},
_handleFileTreeEntry: function (entry, path) {
var that = this,
dfd = $.Deferred(),
entries = [],
dirReader,
errorHandler = function (e) {
if (e && !e.entry) {
e.entry = entry;
}
// Since $.when returns immediately if one
// Deferred is rejected, we use resolve instead.
// This allows valid files and invalid items
// to be returned together in one set:
dfd.resolve([e]);
},
successHandler = function (entries) {
that._handleFileTreeEntries(
entries,
path + entry.name + '/'
).done(function (files) {
dfd.resolve(files);
}).fail(errorHandler);
},
readEntries = function () {
dirReader.readEntries(function (results) {
if (!results.length) {
successHandler(entries);
} else {
entries = entries.concat(results);
readEntries();
}
}, errorHandler);
};
path = path || '';
if (entry.isFile) {
if (entry._file) {
// Workaround for Chrome bug #149735
entry._file.relativePath = path;
dfd.resolve(entry._file);
} else {
entry.file(function (file) {
file.relativePath = path;
dfd.resolve(file);
}, errorHandler);
}
} else if (entry.isDirectory) {
dirReader = entry.createReader();
readEntries();
} else {
// Return an empty list for file system items
// other than files or directories:
dfd.resolve([]);
}
return dfd.promise();
},
_handleFileTreeEntries: function (entries, path) {
var that = this;
return $.when.apply(
$,
$.map(entries, function (entry) {
return that._handleFileTreeEntry(entry, path);
})
).then(function () {
return Array.prototype.concat.apply(
[],
arguments
);
});
},
_getDroppedFiles: function (dataTransfer) {
dataTransfer = dataTransfer || {};
var items = dataTransfer.items;
if (items && items.length && (items[0].webkitGetAsEntry ||
items[0].getAsEntry)) {
return this._handleFileTreeEntries(
$.map(items, function (item) {
var entry;
if (item.webkitGetAsEntry) {
entry = item.webkitGetAsEntry();
if (entry) {
// Workaround for Chrome bug #149735:
entry._file = item.getAsFile();
}
return entry;
}
return item.getAsEntry();
})
);
}
return $.Deferred().resolve(
$.makeArray(dataTransfer.files)
).promise();
},
_getSingleFileInputFiles: function (fileInput) {
fileInput = $(fileInput);
var entries = fileInput.prop('webkitEntries') ||
fileInput.prop('entries'),
files,
value;
if (entries && entries.length) {
return this._handleFileTreeEntries(entries);
}
files = $.makeArray(fileInput.prop('files'));
if (!files.length) {
value = fileInput.prop('value');
if (!value) {
return $.Deferred().resolve([]).promise();
}
// If the files property is not available, the browser does not
// support the File API and we add a pseudo File object with
// the input value as name with path information removed:
files = [{name: value.replace(/^.*\\/, '')}];
} else if (files[0].name === undefined && files[0].fileName) {
// File normalization for Safari 4 and Firefox 3:
$.each(files, function (index, file) {
file.name = file.fileName;
file.size = file.fileSize;
});
}
return $.Deferred().resolve(files).promise();
},
_getFileInputFiles: function (fileInput) {
if (!(fileInput instanceof $) || fileInput.length === 1) {
return this._getSingleFileInputFiles(fileInput);
}
return $.when.apply(
$,
$.map(fileInput, this._getSingleFileInputFiles)
).then(function () {
return Array.prototype.concat.apply(
[],
arguments
);
});
},
_onChange: function (e) {
var that = this,
data = {
fileInput: $(e.target),
form: $(e.target.form)
};
this._getFileInputFiles(data.fileInput).always(function (files) {
data.files = files;
if (that.options.replaceFileInput) {
that._replaceFileInput(data);
}
if (that._trigger(
'change',
$.Event('change', {delegatedEvent: e}),
data
) !== false) {
that._onAdd(e, data);
}
});
},
_onPaste: function (e) {
var items = e.originalEvent && e.originalEvent.clipboardData &&
e.originalEvent.clipboardData.items,
data = {files: []};
if (items && items.length) {
$.each(items, function (index, item) {
var file = item.getAsFile && item.getAsFile();
if (file) {
data.files.push(file);
}
});
if (this._trigger(
'paste',
$.Event('paste', {delegatedEvent: e}),
data
) !== false) {
this._onAdd(e, data);
}
}
},
_onDrop: function (e) {
e.dataTransfer = e.originalEvent && e.originalEvent.dataTransfer;
var that = this,
dataTransfer = e.dataTransfer,
data = {};
if (dataTransfer && dataTransfer.files && dataTransfer.files.length) {
e.preventDefault();
this._getDroppedFiles(dataTransfer).always(function (files) {
data.files = files;
if (that._trigger(
'drop',
$.Event('drop', {delegatedEvent: e}),
data
) !== false) {
that._onAdd(e, data);
}
});
}
},
_onDragOver: getDragHandler('dragover'),
_onDragEnter: getDragHandler('dragenter'),
_onDragLeave: getDragHandler('dragleave'),
_initEventHandlers: function () {
if (this._isXHRUpload(this.options)) {
this._on(this.options.dropZone, {
dragover: this._onDragOver,
drop: this._onDrop,
// event.preventDefault() on dragenter is required for IE10+:
dragenter: this._onDragEnter,
// dragleave is not required, but added for completeness:
dragleave: this._onDragLeave
});
this._on(this.options.pasteZone, {
paste: this._onPaste
});
}
if ($.support.fileInput) {
this._on(this.options.fileInput, {
change: this._onChange
});
}
},
_destroyEventHandlers: function () {
this._off(this.options.dropZone, 'dragenter dragleave dragover drop');
this._off(this.options.pasteZone, 'paste');
this._off(this.options.fileInput, 'change');
},
_destroy: function () {
this._destroyEventHandlers();
},
_setOption: function (key, value) {
var reinit = $.inArray(key, this._specialOptions) !== -1;
if (reinit) {
this._destroyEventHandlers();
}
this._super(key, value);
if (reinit) {
this._initSpecialOptions();
this._initEventHandlers();
}
},
_initSpecialOptions: function () {
var options = this.options;
if (options.fileInput === undefined) {
options.fileInput = this.element.is('input[type="file"]') ?
this.element : this.element.find('input[type="file"]');
} else if (!(options.fileInput instanceof $)) {
options.fileInput = $(options.fileInput);
}
if (!(options.dropZone instanceof $)) {
options.dropZone = $(options.dropZone);
}
if (!(options.pasteZone instanceof $)) {
options.pasteZone = $(options.pasteZone);
}
},
_getRegExp: function (str) {
var parts = str.split('/'),
modifiers = parts.pop();
parts.shift();
return new RegExp(parts.join('/'), modifiers);
},
_isRegExpOption: function (key, value) {
return key !== 'url' && $.type(value) === 'string' &&
/^\/.*\/[igm]{0,3}$/.test(value);
},
_initDataAttributes: function () {
var that = this,
options = this.options,
data = this.element.data();
// Initialize options set via HTML5 data-attributes:
$.each(
this.element[0].attributes,
function (index, attr) {
var key = attr.name.toLowerCase(),
value;
if (/^data-/.test(key)) {
// Convert hyphen-ated key to camelCase:
key = key.slice(5).replace(/-[a-z]/g, function (str) {
return str.charAt(1).toUpperCase();
});
value = data[key];
if (that._isRegExpOption(key, value)) {
value = that._getRegExp(value);
}
options[key] = value;
}
}
);
},
_create: function () {
this._initDataAttributes();
this._initSpecialOptions();
this._slots = [];
this._sequence = this._getXHRPromise(true);
this._sending = this._active = 0;
this._initProgressObject(this);
this._initEventHandlers();
},
// This method is exposed to the widget API and allows to query
// the number of active uploads:
active: function () {
return this._active;
},
// This method is exposed to the widget API and allows to query
// the widget upload progress.
// It returns an object with loaded, total and bitrate properties
// for the running uploads:
progress: function () {
return this._progress;
},
// This method is exposed to the widget API and allows adding files
// using the fileupload API. The data parameter accepts an object which
// must have a files property and can contain additional options:
// .fileupload('add', {files: filesList});
add: function (data) {
var that = this;
if (!data || this.options.disabled) {
return;
}
if (data.fileInput && !data.files) {
this._getFileInputFiles(data.fileInput).always(function (files) {
data.files = files;
that._onAdd(null, data);
});
} else {
data.files = $.makeArray(data.files);
this._onAdd(null, data);
}
},
// This method is exposed to the widget API and allows sending files
// using the fileupload API. The data parameter accepts an object which
// must have a files or fileInput property and can contain additional options:
// .fileupload('send', {files: filesList});
// The method returns a Promise object for the file upload call.
send: function (data) {
if (data && !this.options.disabled) {
if (data.fileInput && !data.files) {
var that = this,
dfd = $.Deferred(),
promise = dfd.promise(),
jqXHR,
aborted;
promise.abort = function () {
aborted = true;
if (jqXHR) {
return jqXHR.abort();
}
dfd.reject(null, 'abort', 'abort');
return promise;
};
this._getFileInputFiles(data.fileInput).always(
function (files) {
if (aborted) {
return;
}
if (!files.length) {
dfd.reject();
return;
}
data.files = files;
jqXHR = that._onSend(null, data);
jqXHR.then(
function (result, textStatus, jqXHR) {
dfd.resolve(result, textStatus, jqXHR);
},
function (jqXHR, textStatus, errorThrown) {
dfd.reject(jqXHR, textStatus, errorThrown);
}
);
}
);
return this._enhancePromise(promise);
}
data.files = $.makeArray(data.files);
if (data.files.length) {
return this._onSend(null, data);
}
}
return this._getXHRPromise(false, data && data.context);
}
});
}));
// Spectrum Colorpicker v1.8.0
// https://github.com/bgrins/spectrum
// Author: Brian Grinstead
// License: MIT
(function (factory) {
"use strict";
if (typeof define === 'function' && define.amd) { // AMD
define(['jquery'], factory);
}
else if (typeof exports == "object" && typeof module == "object") { // CommonJS
module.exports = factory(require('jquery'));
}
else { // Browser
factory(jQuery);
}
})(function($, undefined) {
"use strict";
var defaultOpts = {
// Callbacks
beforeShow: noop,
move: noop,
change: noop,
show: noop,
hide: noop,
// Options
color: false,
flat: false,
showInput: false,
allowEmpty: false,
showButtons: true,
clickoutFiresChange: true,
showInitial: false,
showPalette: false,
showPaletteOnly: false,
hideAfterPaletteSelect: false,
togglePaletteOnly: false,
showSelectionPalette: true,
localStorageKey: false,
appendTo: "body",
maxSelectionSize: 7,
cancelText: "cancel",
chooseText: "choose",
togglePaletteMoreText: "more",
togglePaletteLessText: "less",
clearText: "Clear Color Selection",
noColorSelectedText: "No Color Selected",
preferredFormat: false,
className: "", // Deprecated - use containerClassName and replacerClassName instead.
containerClassName: "",
replacerClassName: "",
showAlpha: false,
theme: "sp-light",
palette: [["#ffffff", "#000000", "#ff0000", "#ff8000", "#ffff00", "#008000", "#0000ff", "#4b0082", "#9400d3"]],
selectionPalette: [],
disabled: false,
offset: null
},
spectrums = [],
IE = !!/msie/i.exec( window.navigator.userAgent ),
rgbaSupport = (function() {
function contains( str, substr ) {
return !!~('' + str).indexOf(substr);
}
var elem = document.createElement('div');
var style = elem.style;
style.cssText = 'background-color:rgba(0,0,0,.5)';
return contains(style.backgroundColor, 'rgba') || contains(style.backgroundColor, 'hsla');
})(),
replaceInput = [
"<div class='sp-replacer'>",
"<div class='sp-preview'><div class='sp-preview-inner'></div></div>",
"<div class='sp-dd'>▼</div>",
"</div>"
].join(''),
markup = (function () {
// IE does not support gradients with multiple stops, so we need to simulate
// that for the rainbow slider with 8 divs that each have a single gradient
var gradientFix = "";
if (IE) {
for (var i = 1; i <= 6; i++) {
gradientFix += "<div class='sp-" + i + "'></div>";
}
}
return [
"<div class='sp-container sp-hidden'>",
"<div class='sp-palette-container'>",
"<div class='sp-palette sp-thumb sp-cf'></div>",
"<div class='sp-palette-button-container sp-cf'>",
"<button type='button' class='sp-palette-toggle'></button>",
"</div>",
"</div>",
"<div class='sp-picker-container'>",
"<div class='sp-top sp-cf'>",
"<div class='sp-fill'></div>",
"<div class='sp-top-inner'>",
"<div class='sp-color'>",
"<div class='sp-sat'>",
"<div class='sp-val'>",
"<div class='sp-dragger'></div>",
"</div>",
"</div>",
"</div>",
"<div class='sp-clear sp-clear-display'>",
"</div>",
"<div class='sp-hue'>",
"<div class='sp-slider'></div>",
gradientFix,
"</div>",
"</div>",
"<div class='sp-alpha'><div class='sp-alpha-inner'><div class='sp-alpha-handle'></div></div></div>",
"</div>",
"<div class='sp-input-container sp-cf'>",
"<input class='sp-input' type='text' spellcheck='false' />",
"</div>",
"<div class='sp-initial sp-thumb sp-cf'></div>",
"<div class='sp-button-container sp-cf'>",
"<a class='sp-cancel' href='#'></a>",
"<button type='button' class='sp-choose'></button>",
"</div>",
"</div>",
"</div>"
].join("");
})();
function paletteTemplate (p, color, className, opts) {
var html = [];
for (var i = 0; i < p.length; i++) {
var current = p[i];
if(current) {
var tiny = tinycolor(current);
var c = tiny.toHsl().l < 0.5 ? "sp-thumb-el sp-thumb-dark" : "sp-thumb-el sp-thumb-light";
c += (tinycolor.equals(color, current)) ? " sp-thumb-active" : "";
var formattedString = tiny.toString(opts.preferredFormat || "rgb");
var swatchStyle = rgbaSupport ? ("background-color:" + tiny.toRgbString()) : "filter:" + tiny.toFilter();
html.push('<span title="' + formattedString + '" data-color="' + tiny.toRgbString() + '" class="' + c + '"><span class="sp-thumb-inner" style="' + swatchStyle + ';" /></span>');
} else {
var cls = 'sp-clear-display';
html.push($('<div />')
.append($('<span data-color="" style="background-color:transparent;" class="' + cls + '"></span>')
.attr('title', opts.noColorSelectedText)
)
.html()
);
}
}
return "<div class='sp-cf " + className + "'>" + html.join('') + "</div>";
}
function hideAll() {
for (var i = 0; i < spectrums.length; i++) {
if (spectrums[i]) {
spectrums[i].hide();
}
}
}
function instanceOptions(o, callbackContext) {
var opts = $.extend({}, defaultOpts, o);
opts.callbacks = {
'move': bind(opts.move, callbackContext),
'change': bind(opts.change, callbackContext),
'show': bind(opts.show, callbackContext),
'hide': bind(opts.hide, callbackContext),
'beforeShow': bind(opts.beforeShow, callbackContext)
};
return opts;
}
function spectrum(element, o) {
var opts = instanceOptions(o, element),
flat = opts.flat,
showSelectionPalette = opts.showSelectionPalette,
localStorageKey = opts.localStorageKey,
theme = opts.theme,
callbacks = opts.callbacks,
resize = throttle(reflow, 10),
visible = false,
isDragging = false,
dragWidth = 0,
dragHeight = 0,
dragHelperHeight = 0,
slideHeight = 0,
slideWidth = 0,
alphaWidth = 0,
alphaSlideHelperWidth = 0,
slideHelperHeight = 0,
currentHue = 0,
currentSaturation = 0,
currentValue = 0,
currentAlpha = 1,
palette = [],
paletteArray = [],
paletteLookup = {},
selectionPalette = opts.selectionPalette.slice(0),
maxSelectionSize = opts.maxSelectionSize,
draggingClass = "sp-dragging",
shiftMovementDirection = null;
var doc = element.ownerDocument,
body = doc.body,
boundElement = $(element),
disabled = false,
container = $(markup, doc).addClass(theme),
pickerContainer = container.find(".sp-picker-container"),
dragger = container.find(".sp-color"),
dragHelper = container.find(".sp-dragger"),
slider = container.find(".sp-hue"),
slideHelper = container.find(".sp-slider"),
alphaSliderInner = container.find(".sp-alpha-inner"),
alphaSlider = container.find(".sp-alpha"),
alphaSlideHelper = container.find(".sp-alpha-handle"),
textInput = container.find(".sp-input"),
paletteContainer = container.find(".sp-palette"),
initialColorContainer = container.find(".sp-initial"),
cancelButton = container.find(".sp-cancel"),
clearButton = container.find(".sp-clear"),
chooseButton = container.find(".sp-choose"),
toggleButton = container.find(".sp-palette-toggle"),
isInput = boundElement.is("input"),
isInputTypeColor = isInput && boundElement.attr("type") === "color" && inputTypeColorSupport(),
shouldReplace = isInput && !flat,
replacer = (shouldReplace) ? $(replaceInput).addClass(theme).addClass(opts.className).addClass(opts.replacerClassName) : $([]),
offsetElement = (shouldReplace) ? replacer : boundElement,
previewElement = replacer.find(".sp-preview-inner"),
initialColor = opts.color || (isInput && boundElement.val()),
colorOnShow = false,
currentPreferredFormat = opts.preferredFormat,
clickoutFiresChange = !opts.showButtons || opts.clickoutFiresChange,
isEmpty = !initialColor,
allowEmpty = opts.allowEmpty && !isInputTypeColor;
function applyOptions() {
if (opts.showPaletteOnly) {
opts.showPalette = true;
}
toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
if (opts.palette) {
palette = opts.palette.slice(0);
paletteArray = $.isArray(palette[0]) ? palette : [palette];
paletteLookup = {};
for (var i = 0; i < paletteArray.length; i++) {
for (var j = 0; j < paletteArray[i].length; j++) {
var rgb = tinycolor(paletteArray[i][j]).toRgbString();
paletteLookup[rgb] = true;
}
}
}
container.toggleClass("sp-flat", flat);
container.toggleClass("sp-input-disabled", !opts.showInput);
container.toggleClass("sp-alpha-enabled", opts.showAlpha);
container.toggleClass("sp-clear-enabled", allowEmpty);
container.toggleClass("sp-buttons-disabled", !opts.showButtons);
container.toggleClass("sp-palette-buttons-disabled", !opts.togglePaletteOnly);
container.toggleClass("sp-palette-disabled", !opts.showPalette);
container.toggleClass("sp-palette-only", opts.showPaletteOnly);
container.toggleClass("sp-initial-disabled", !opts.showInitial);
container.addClass(opts.className).addClass(opts.containerClassName);
reflow();
}
function initialize() {
if (IE) {
container.find("*:not(input)").attr("unselectable", "on");
}
applyOptions();
if (shouldReplace) {
boundElement.after(replacer).hide();
}
if (!allowEmpty) {
clearButton.hide();
}
if (flat) {
boundElement.after(container).hide();
}
else {
var appendTo = opts.appendTo === "parent" ? boundElement.parent() : $(opts.appendTo);
if (appendTo.length !== 1) {
appendTo = $("body");
}
appendTo.append(container);
}
updateSelectionPaletteFromStorage();
offsetElement.bind("click.spectrum touchstart.spectrum", function (e) {
if (!disabled) {
toggle();
}
e.stopPropagation();
if (!$(e.target).is("input")) {
e.preventDefault();
}
});
if(boundElement.is(":disabled") || (opts.disabled === true)) {
disable();
}
// Prevent clicks from bubbling up to document. This would cause it to be hidden.
container.click(stopPropagation);
// Handle user typed input
textInput.change(setFromTextInput);
textInput.bind("paste", function () {
setTimeout(setFromTextInput, 1);
});
textInput.keydown(function (e) { if (e.keyCode == 13) { setFromTextInput(); } });
cancelButton.text(opts.cancelText);
cancelButton.bind("click.spectrum", function (e) {
e.stopPropagation();
e.preventDefault();
revert();
hide();
});
clearButton.attr("title", opts.clearText);
clearButton.bind("click.spectrum", function (e) {
e.stopPropagation();
e.preventDefault();
isEmpty = true;
move();
if(flat) {
//for the flat style, this is a change event
updateOriginalInput(true);
}
});
chooseButton.text(opts.chooseText);
chooseButton.bind("click.spectrum", function (e) {
e.stopPropagation();
e.preventDefault();
if (IE && textInput.is(":focus")) {
textInput.trigger('change');
}
if (isValid()) {
updateOriginalInput(true);
hide();
}
});
toggleButton.text(opts.showPaletteOnly ? opts.togglePaletteMoreText : opts.togglePaletteLessText);
toggleButton.bind("click.spectrum", function (e) {
e.stopPropagation();
e.preventDefault();
opts.showPaletteOnly = !opts.showPaletteOnly;
// To make sure the Picker area is drawn on the right, next to the
// Palette area (and not below the palette), first move the Palette
// to the left to make space for the picker, plus 5px extra.
// The 'applyOptions' function puts the whole container back into place
// and takes care of the button-text and the sp-palette-only CSS class.
if (!opts.showPaletteOnly && !flat) {
container.css('left', '-=' + (pickerContainer.outerWidth(true) + 5));
}
applyOptions();
});
draggable(alphaSlider, function (dragX, dragY, e) {
currentAlpha = (dragX / alphaWidth);
isEmpty = false;
if (e.shiftKey) {
currentAlpha = Math.round(currentAlpha * 10) / 10;
}
move();
}, dragStart, dragStop);
draggable(slider, function (dragX, dragY) {
currentHue = parseFloat(dragY / slideHeight);
isEmpty = false;
if (!opts.showAlpha) {
currentAlpha = 1;
}
move();
}, dragStart, dragStop);
draggable(dragger, function (dragX, dragY, e) {
// shift+drag should snap the movement to either the x or y axis.
if (!e.shiftKey) {
shiftMovementDirection = null;
}
else if (!shiftMovementDirection) {
var oldDragX = currentSaturation * dragWidth;
var oldDragY = dragHeight - (currentValue * dragHeight);
var furtherFromX = Math.abs(dragX - oldDragX) > Math.abs(dragY - oldDragY);
shiftMovementDirection = furtherFromX ? "x" : "y";
}
var setSaturation = !shiftMovementDirection || shiftMovementDirection === "x";
var setValue = !shiftMovementDirection || shiftMovementDirection === "y";
if (setSaturation) {
currentSaturation = parseFloat(dragX / dragWidth);
}
if (setValue) {
currentValue = parseFloat((dragHeight - dragY) / dragHeight);
}
isEmpty = false;
if (!opts.showAlpha) {
currentAlpha = 1;
}
move();
}, dragStart, dragStop);
if (!!initialColor) {
set(initialColor);
// In case color was black - update the preview UI and set the format
// since the set function will not run (default color is black).
updateUI();
currentPreferredFormat = opts.preferredFormat || tinycolor(initialColor).format;
addColorToSelectionPalette(initialColor);
}
else {
updateUI();
}
if (flat) {
show();
}
function paletteElementClick(e) {
if (e.data && e.data.ignore) {
set($(e.target).closest(".sp-thumb-el").data("color"));
move();
}
else {
set($(e.target).closest(".sp-thumb-el").data("color"));
move();
updateOriginalInput(true);
if (opts.hideAfterPaletteSelect) {
hide();
}
}
return false;
}
var paletteEvent = IE ? "mousedown.spectrum" : "click.spectrum touchstart.spectrum";
paletteContainer.delegate(".sp-thumb-el", paletteEvent, paletteElementClick);
initialColorContainer.delegate(".sp-thumb-el:nth-child(1)", paletteEvent, { ignore: true }, paletteElementClick);
}
function updateSelectionPaletteFromStorage() {
if (localStorageKey && window.localStorage) {
// Migrate old palettes over to new format. May want to remove this eventually.
try {
var oldPalette = window.localStorage[localStorageKey].split(",#");
if (oldPalette.length > 1) {
delete window.localStorage[localStorageKey];
$.each(oldPalette, function(i, c) {
addColorToSelectionPalette(c);
});
}
}
catch(e) { }
try {
selectionPalette = window.localStorage[localStorageKey].split(";");
}
catch (e) { }
}
}
function addColorToSelectionPalette(color) {
if (showSelectionPalette) {
var rgb = tinycolor(color).toRgbString();
if (!paletteLookup[rgb] && $.inArray(rgb, selectionPalette) === -1) {
selectionPalette.push(rgb);
while(selectionPalette.length > maxSelectionSize) {
selectionPalette.shift();
}
}
if (localStorageKey && window.localStorage) {
try {
window.localStorage[localStorageKey] = selectionPalette.join(";");
}
catch(e) { }
}
}
}
function getUniqueSelectionPalette() {
var unique = [];
if (opts.showPalette) {
for (var i = 0; i < selectionPalette.length; i++) {
var rgb = tinycolor(selectionPalette[i]).toRgbString();
if (!paletteLookup[rgb]) {
unique.push(selectionPalette[i]);
}
}
}
return unique.reverse().slice(0, opts.maxSelectionSize);
}
function drawPalette() {
var currentColor = get();
var html = $.map(paletteArray, function (palette, i) {
return paletteTemplate(palette, currentColor, "sp-palette-row sp-palette-row-" + i, opts);
});
updateSelectionPaletteFromStorage();
if (selectionPalette) {
html.push(paletteTemplate(getUniqueSelectionPalette(), currentColor, "sp-palette-row sp-palette-row-selection", opts));
}
paletteContainer.html(html.join(""));
}
function drawInitial() {
if (opts.showInitial) {
var initial = colorOnShow;
var current = get();
initialColorContainer.html(paletteTemplate([initial, current], current, "sp-palette-row-initial", opts));
}
}
function dragStart() {
if (dragHeight <= 0 || dragWidth <= 0 || slideHeight <= 0) {
reflow();
}
isDragging = true;
container.addClass(draggingClass);
shiftMovementDirection = null;
boundElement.trigger('dragstart.spectrum', [ get() ]);
}
function dragStop() {
isDragging = false;
container.removeClass(draggingClass);
boundElement.trigger('dragstop.spectrum', [ get() ]);
}
function setFromTextInput() {
var value = textInput.val();
if ((value === null || value === "") && allowEmpty) {
set(null);
updateOriginalInput(true);
}
else {
var tiny = tinycolor(value);
if (tiny.isValid()) {
set(tiny);
updateOriginalInput(true);
}
else {
textInput.addClass("sp-validation-error");
}
}
}
function toggle() {
if (visible) {
hide();
}
else {
show();
}
}
function show() {
var event = $.Event('beforeShow.spectrum');
if (visible) {
reflow();
return;
}
boundElement.trigger(event, [ get() ]);
if (callbacks.beforeShow(get()) === false || event.isDefaultPrevented()) {
return;
}
hideAll();
visible = true;
$(doc).bind("keydown.spectrum", onkeydown);
$(doc).bind("click.spectrum", clickout);
$(window).bind("resize.spectrum", resize);
replacer.addClass("sp-active");
container.removeClass("sp-hidden");
reflow();
updateUI();
colorOnShow = get();
drawInitial();
callbacks.show(colorOnShow);
boundElement.trigger('show.spectrum', [ colorOnShow ]);
}
function onkeydown(e) {
// Close on ESC
if (e.keyCode === 27) {
hide();
}
}
function clickout(e) {
// Return on right click.
if (e.button == 2) { return; }
// If a drag event was happening during the mouseup, don't hide
// on click.
if (isDragging) { return; }
if (clickoutFiresChange) {
updateOriginalInput(true);
}
else {
revert();
}
hide();
}
function hide() {
// Return if hiding is unnecessary
if (!visible || flat) { return; }
visible = false;
$(doc).unbind("keydown.spectrum", onkeydown);
$(doc).unbind("click.spectrum", clickout);
$(window).unbind("resize.spectrum", resize);
replacer.removeClass("sp-active");
container.addClass("sp-hidden");
callbacks.hide(get());
boundElement.trigger('hide.spectrum', [ get() ]);
}
function revert() {
set(colorOnShow, true);
}
function set(color, ignoreFormatChange) {
if (tinycolor.equals(color, get())) {
// Update UI just in case a validation error needs
// to be cleared.
updateUI();
return;
}
var newColor, newHsv;
if (!color && allowEmpty) {
isEmpty = true;
} else {
isEmpty = false;
newColor = tinycolor(color);
newHsv = newColor.toHsv();
currentHue = (newHsv.h % 360) / 360;
currentSaturation = newHsv.s;
currentValue = newHsv.v;
currentAlpha = newHsv.a;
}
updateUI();
if (newColor && newColor.isValid() && !ignoreFormatChange) {
currentPreferredFormat = opts.preferredFormat || newColor.getFormat();
}
}
function get(opts) {
opts = opts || { };
if (allowEmpty && isEmpty) {
return null;
}
return tinycolor.fromRatio({
h: currentHue,
s: currentSaturation,
v: currentValue,
a: Math.round(currentAlpha * 100) / 100
}, { format: opts.format || currentPreferredFormat });
}
function isValid() {
return !textInput.hasClass("sp-validation-error");
}
function move() {
updateUI();
callbacks.move(get());
boundElement.trigger('move.spectrum', [ get() ]);
}
function updateUI() {
textInput.removeClass("sp-validation-error");
updateHelperLocations();
// Update dragger background color (gradients take care of saturation and value).
var flatColor = tinycolor.fromRatio({ h: currentHue, s: 1, v: 1 });
dragger.css("background-color", flatColor.toHexString());
// Get a format that alpha will be included in (hex and names ignore alpha)
var format = currentPreferredFormat;
if (currentAlpha < 1 && !(currentAlpha === 0 && format === "name")) {
if (format === "hex" || format === "hex3" || format === "hex6" || format === "name") {
format = "rgb";
}
}
var realColor = get({ format: format }),
displayColor = '';
//reset background info for preview element
previewElement.removeClass("sp-clear-display");
previewElement.css('background-color', 'transparent');
if (!realColor && allowEmpty) {
// Update the replaced elements background with icon indicating no color selection
previewElement.addClass("sp-clear-display");
}
else {
var realHex = realColor.toHexString(),
realRgb = realColor.toRgbString();
// Update the replaced elements background color (with actual selected color)
if (rgbaSupport || realColor.alpha === 1) {
previewElement.css("background-color", realRgb);
}
else {
previewElement.css("background-color", "transparent");
previewElement.css("filter", realColor.toFilter());
}
if (opts.showAlpha) {
var rgb = realColor.toRgb();
rgb.a = 0;
var realAlpha = tinycolor(rgb).toRgbString();
var gradient = "linear-gradient(left, " + realAlpha + ", " + realHex + ")";
if (IE) {
alphaSliderInner.css("filter", tinycolor(realAlpha).toFilter({ gradientType: 1 }, realHex));
}
else {
alphaSliderInner.css("background", "-webkit-" + gradient);
alphaSliderInner.css("background", "-moz-" + gradient);
alphaSliderInner.css("background", "-ms-" + gradient);
// Use current syntax gradient on unprefixed property.
alphaSliderInner.css("background",
"linear-gradient(to right, " + realAlpha + ", " + realHex + ")");
}
}
displayColor = realColor.toString(format);
}
// Update the text entry input as it changes happen
if (opts.showInput) {
textInput.val(displayColor);
}
if (opts.showPalette) {
drawPalette();
}
drawInitial();
}
function updateHelperLocations() {
var s = currentSaturation;
var v = currentValue;
if(allowEmpty && isEmpty) {
//if selected color is empty, hide the helpers
alphaSlideHelper.hide();
slideHelper.hide();
dragHelper.hide();
}
else {
//make sure helpers are visible
alphaSlideHelper.show();
slideHelper.show();
dragHelper.show();
// Where to show the little circle in that displays your current selected color
var dragX = s * dragWidth;
var dragY = dragHeight - (v * dragHeight);
dragX = Math.max(
-dragHelperHeight,
Math.min(dragWidth - dragHelperHeight, dragX - dragHelperHeight)
);
dragY = Math.max(
-dragHelperHeight,
Math.min(dragHeight - dragHelperHeight, dragY - dragHelperHeight)
);
dragHelper.css({
"top": dragY + "px",
"left": dragX + "px"
});
var alphaX = currentAlpha * alphaWidth;
alphaSlideHelper.css({
"left": (alphaX - (alphaSlideHelperWidth / 2)) + "px"
});
// Where to show the bar that displays your current selected hue
var slideY = (currentHue) * slideHeight;
slideHelper.css({
"top": (slideY - slideHelperHeight) + "px"
});
}
}
function updateOriginalInput(fireCallback) {
var color = get(),
displayColor = '',
hasChanged = !tinycolor.equals(color, colorOnShow);
if (color) {
displayColor = color.toString(currentPreferredFormat);
// Update the selection palette with the current color
addColorToSelectionPalette(color);
}
if (isInput) {
boundElement.val(displayColor);
}
if (fireCallback && hasChanged) {
callbacks.change(color);
boundElement.trigger('change', [ color ]);
}
}
function reflow() {
if (!visible) {
return; // Calculations would be useless and wouldn't be reliable anyways
}
dragWidth = dragger.width();
dragHeight = dragger.height();
dragHelperHeight = dragHelper.height();
slideWidth = slider.width();
slideHeight = slider.height();
slideHelperHeight = slideHelper.height();
alphaWidth = alphaSlider.width();
alphaSlideHelperWidth = alphaSlideHelper.width();
if (!flat) {
container.css("position", "absolute");
if (opts.offset) {
container.offset(opts.offset);
} else {
container.offset(getOffset(container, offsetElement));
}
}
updateHelperLocations();
if (opts.showPalette) {
drawPalette();
}
boundElement.trigger('reflow.spectrum');
}
function destroy() {
boundElement.show();
offsetElement.unbind("click.spectrum touchstart.spectrum");
container.remove();
replacer.remove();
spectrums[spect.id] = null;
}
function option(optionName, optionValue) {
if (optionName === undefined) {
return $.extend({}, opts);
}
if (optionValue === undefined) {
return opts[optionName];
}
opts[optionName] = optionValue;
if (optionName === "preferredFormat") {
currentPreferredFormat = opts.preferredFormat;
}
applyOptions();
}
function enable() {
disabled = false;
boundElement.attr("disabled", false);
offsetElement.removeClass("sp-disabled");
}
function disable() {
hide();
disabled = true;
boundElement.attr("disabled", true);
offsetElement.addClass("sp-disabled");
}
function setOffset(coord) {
opts.offset = coord;
reflow();
}
initialize();
var spect = {
show: show,
hide: hide,
toggle: toggle,
reflow: reflow,
option: option,
enable: enable,
disable: disable,
offset: setOffset,
set: function (c) {
set(c);
updateOriginalInput();
},
get: get,
destroy: destroy,
container: container
};
spect.id = spectrums.push(spect) - 1;
return spect;
}
/**
* checkOffset - get the offset below/above and left/right element depending on screen position
* Thanks https://github.com/jquery/jquery-ui/blob/master/ui/jquery.ui.datepicker.js
*/
function getOffset(picker, input) {
var extraY = 0;
var dpWidth = picker.outerWidth();
var dpHeight = picker.outerHeight();
var inputHeight = input.outerHeight();
var doc = picker[0].ownerDocument;
var docElem = doc.documentElement;
var viewWidth = docElem.clientWidth + $(doc).scrollLeft();
var viewHeight = docElem.clientHeight + $(doc).scrollTop();
var offset = input.offset();
offset.top += inputHeight;
offset.left -=
Math.min(offset.left, (offset.left + dpWidth > viewWidth && viewWidth > dpWidth) ?
Math.abs(offset.left + dpWidth - viewWidth) : 0);
offset.top -=
Math.min(offset.top, ((offset.top + dpHeight > viewHeight && viewHeight > dpHeight) ?
Math.abs(dpHeight + inputHeight - extraY) : extraY));
return offset;
}
/**
* noop - do nothing
*/
function noop() {
}
/**
* stopPropagation - makes the code only doing this a little easier to read in line
*/
function stopPropagation(e) {
e.stopPropagation();
}
/**
* Create a function bound to a given object
* Thanks to underscore.js
*/
function bind(func, obj) {
var slice = Array.prototype.slice;
var args = slice.call(arguments, 2);
return function () {
return func.apply(obj, args.concat(slice.call(arguments)));
};
}
/**
* Lightweight drag helper. Handles containment within the element, so that
* when dragging, the x is within [0,element.width] and y is within [0,element.height]
*/
function draggable(element, onmove, onstart, onstop) {
onmove = onmove || function () { };
onstart = onstart || function () { };
onstop = onstop || function () { };
var doc = document;
var dragging = false;
var offset = {};
var maxHeight = 0;
var maxWidth = 0;
var hasTouch = ('ontouchstart' in window);
var duringDragEvents = {};
duringDragEvents["selectstart"] = prevent;
duringDragEvents["dragstart"] = prevent;
duringDragEvents["touchmove mousemove"] = move;
duringDragEvents["touchend mouseup"] = stop;
function prevent(e) {
if (e.stopPropagation) {
e.stopPropagation();
}
if (e.preventDefault) {
e.preventDefault();
}
e.returnValue = false;
}
function move(e) {
if (dragging) {
// Mouseup happened outside of window
if (IE && doc.documentMode < 9 && !e.button) {
return stop();
}
var t0 = e.originalEvent && e.originalEvent.touches && e.originalEvent.touches[0];
var pageX = t0 && t0.pageX || e.pageX;
var pageY = t0 && t0.pageY || e.pageY;
var dragX = Math.max(0, Math.min(pageX - offset.left, maxWidth));
var dragY = Math.max(0, Math.min(pageY - offset.top, maxHeight));
if (hasTouch) {
// Stop scrolling in iOS
prevent(e);
}
onmove.apply(element, [dragX, dragY, e]);
}
}
function start(e) {
var rightclick = (e.which) ? (e.which == 3) : (e.button == 2);
if (!rightclick && !dragging) {
if (onstart.apply(element, arguments) !== false) {
dragging = true;
maxHeight = $(element).height();
maxWidth = $(element).width();
offset = $(element).offset();
$(doc).bind(duringDragEvents);
$(doc.body).addClass("sp-dragging");
move(e);
prevent(e);
}
}
}
function stop() {
if (dragging) {
$(doc).unbind(duringDragEvents);
$(doc.body).removeClass("sp-dragging");
// Wait a tick before notifying observers to allow the click event
// to fire in Chrome.
setTimeout(function() {
onstop.apply(element, arguments);
}, 0);
}
dragging = false;
}
$(element).bind("touchstart mousedown", start);
}
function throttle(func, wait, debounce) {
var timeout;
return function () {
var context = this, args = arguments;
var throttler = function () {
timeout = null;
func.apply(context, args);
};
if (debounce) clearTimeout(timeout);
if (debounce || !timeout) timeout = setTimeout(throttler, wait);
};
}
function inputTypeColorSupport() {
return $.fn.spectrum.inputTypeColorSupport();
}
/**
* Define a jQuery plugin
*/
var dataID = "spectrum.id";
$.fn.spectrum = function (opts, extra) {
if (typeof opts == "string") {
var returnValue = this;
var args = Array.prototype.slice.call( arguments, 1 );
this.each(function () {
var spect = spectrums[$(this).data(dataID)];
if (spect) {
var method = spect[opts];
if (!method) {
throw new Error( "Spectrum: no such method: '" + opts + "'" );
}
if (opts == "get") {
returnValue = spect.get();
}
else if (opts == "container") {
returnValue = spect.container;
}
else if (opts == "option") {
returnValue = spect.option.apply(spect, args);
}
else if (opts == "destroy") {
spect.destroy();
$(this).removeData(dataID);
}
else {
method.apply(spect, args);
}
}
});
return returnValue;
}
// Initializing a new instance of spectrum
return this.spectrum("destroy").each(function () {
var options = $.extend({}, opts, $(this).data());
var spect = spectrum(this, options);
$(this).data(dataID, spect.id);
});
};
$.fn.spectrum.load = true;
$.fn.spectrum.loadOpts = {};
$.fn.spectrum.draggable = draggable;
$.fn.spectrum.defaults = defaultOpts;
$.fn.spectrum.inputTypeColorSupport = function inputTypeColorSupport() {
if (typeof inputTypeColorSupport._cachedResult === "undefined") {
var colorInput = $("<input type='color'/>")[0]; // if color element is supported, value will default to not null
inputTypeColorSupport._cachedResult = colorInput.type === "color" && colorInput.value !== "";
}
return inputTypeColorSupport._cachedResult;
};
$.spectrum = { };
$.spectrum.localization = { };
$.spectrum.palettes = { };
$.fn.spectrum.processNativeColorInputs = function () {
var colorInputs = $("input[type=color]");
if (colorInputs.length && !inputTypeColorSupport()) {
colorInputs.spectrum({
preferredFormat: "hex6"
});
}
};
// TinyColor v1.1.2
// https://github.com/bgrins/TinyColor
// Brian Grinstead, MIT License
(function() {
var trimLeft = /^[\s,#]+/,
trimRight = /\s+$/,
tinyCounter = 0,
math = Math,
mathRound = math.round,
mathMin = math.min,
mathMax = math.max,
mathRandom = math.random;
var tinycolor = function(color, opts) {
color = (color) ? color : '';
opts = opts || { };
// If input is already a tinycolor, return itself
if (color instanceof tinycolor) {
return color;
}
// If we are called as a function, call using new instead
if (!(this instanceof tinycolor)) {
return new tinycolor(color, opts);
}
var rgb = inputToRGB(color);
this._originalInput = color,
this._r = rgb.r,
this._g = rgb.g,
this._b = rgb.b,
this._a = rgb.a,
this._roundA = mathRound(100*this._a) / 100,
this._format = opts.format || rgb.format;
this._gradientType = opts.gradientType;
// Don't let the range of [0,255] come back in [0,1].
// Potentially lose a little bit of precision here, but will fix issues where
// .5 gets interpreted as half of the total, instead of half of 1
// If it was supposed to be 128, this was already taken care of by `inputToRgb`
if (this._r < 1) { this._r = mathRound(this._r); }
if (this._g < 1) { this._g = mathRound(this._g); }
if (this._b < 1) { this._b = mathRound(this._b); }
this._ok = rgb.ok;
this._tc_id = tinyCounter++;
};
tinycolor.prototype = {
isDark: function() {
return this.getBrightness() < 128;
},
isLight: function() {
return !this.isDark();
},
isValid: function() {
return this._ok;
},
getOriginalInput: function() {
return this._originalInput;
},
getFormat: function() {
return this._format;
},
getAlpha: function() {
return this._a;
},
getBrightness: function() {
var rgb = this.toRgb();
return (rgb.r * 299 + rgb.g * 587 + rgb.b * 114) / 1000;
},
setAlpha: function(value) {
this._a = boundAlpha(value);
this._roundA = mathRound(100*this._a) / 100;
return this;
},
toHsv: function() {
var hsv = rgbToHsv(this._r, this._g, this._b);
return { h: hsv.h * 360, s: hsv.s, v: hsv.v, a: this._a };
},
toHsvString: function() {
var hsv = rgbToHsv(this._r, this._g, this._b);
var h = mathRound(hsv.h * 360), s = mathRound(hsv.s * 100), v = mathRound(hsv.v * 100);
return (this._a == 1) ?
"hsv(" + h + ", " + s + "%, " + v + "%)" :
"hsva(" + h + ", " + s + "%, " + v + "%, "+ this._roundA + ")";
},
toHsl: function() {
var hsl = rgbToHsl(this._r, this._g, this._b);
return { h: hsl.h * 360, s: hsl.s, l: hsl.l, a: this._a };
},
toHslString: function() {
var hsl = rgbToHsl(this._r, this._g, this._b);
var h = mathRound(hsl.h * 360), s = mathRound(hsl.s * 100), l = mathRound(hsl.l * 100);
return (this._a == 1) ?
"hsl(" + h + ", " + s + "%, " + l + "%)" :
"hsla(" + h + ", " + s + "%, " + l + "%, "+ this._roundA + ")";
},
toHex: function(allow3Char) {
return rgbToHex(this._r, this._g, this._b, allow3Char);
},
toHexString: function(allow3Char) {
return '#' + this.toHex(allow3Char);
},
toHex8: function() {
return rgbaToHex(this._r, this._g, this._b, this._a);
},
toHex8String: function() {
return '#' + this.toHex8();
},
toRgb: function() {
return { r: mathRound(this._r), g: mathRound(this._g), b: mathRound(this._b), a: this._a };
},
toRgbString: function() {
return (this._a == 1) ?
"rgb(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ")" :
"rgba(" + mathRound(this._r) + ", " + mathRound(this._g) + ", " + mathRound(this._b) + ", " + this._roundA + ")";
},
toPercentageRgb: function() {
return { r: mathRound(bound01(this._r, 255) * 100) + "%", g: mathRound(bound01(this._g, 255) * 100) + "%", b: mathRound(bound01(this._b, 255) * 100) + "%", a: this._a };
},
toPercentageRgbString: function() {
return (this._a == 1) ?
"rgb(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%)" :
"rgba(" + mathRound(bound01(this._r, 255) * 100) + "%, " + mathRound(bound01(this._g, 255) * 100) + "%, " + mathRound(bound01(this._b, 255) * 100) + "%, " + this._roundA + ")";
},
toName: function() {
if (this._a === 0) {
return "transparent";
}
if (this._a < 1) {
return false;
}
return hexNames[rgbToHex(this._r, this._g, this._b, true)] || false;
},
toFilter: function(secondColor) {
var hex8String = '#' + rgbaToHex(this._r, this._g, this._b, this._a);
var secondHex8String = hex8String;
var gradientType = this._gradientType ? "GradientType = 1, " : "";
if (secondColor) {
var s = tinycolor(secondColor);
secondHex8String = s.toHex8String();
}
return "progid:DXImageTransform.Microsoft.gradient("+gradientType+"startColorstr="+hex8String+",endColorstr="+secondHex8String+")";
},
toString: function(format) {
var formatSet = !!format;
format = format || this._format;
var formattedString = false;
var hasAlpha = this._a < 1 && this._a >= 0;
var needsAlphaFormat = !formatSet && hasAlpha && (format === "hex" || format === "hex6" || format === "hex3" || format === "name");
if (needsAlphaFormat) {
// Special case for "transparent", all other non-alpha formats
// will return rgba when there is transparency.
if (format === "name" && this._a === 0) {
return this.toName();
}
return this.toRgbString();
}
if (format === "rgb") {
formattedString = this.toRgbString();
}
if (format === "prgb") {
formattedString = this.toPercentageRgbString();
}
if (format === "hex" || format === "hex6") {
formattedString = this.toHexString();
}
if (format === "hex3") {
formattedString = this.toHexString(true);
}
if (format === "hex8") {
formattedString = this.toHex8String();
}
if (format === "name") {
formattedString = this.toName();
}
if (format === "hsl") {
formattedString = this.toHslString();
}
if (format === "hsv") {
formattedString = this.toHsvString();
}
return formattedString || this.toHexString();
},
_applyModification: function(fn, args) {
var color = fn.apply(null, [this].concat([].slice.call(args)));
this._r = color._r;
this._g = color._g;
this._b = color._b;
this.setAlpha(color._a);
return this;
},
lighten: function() {
return this._applyModification(lighten, arguments);
},
brighten: function() {
return this._applyModification(brighten, arguments);
},
darken: function() {
return this._applyModification(darken, arguments);
},
desaturate: function() {
return this._applyModification(desaturate, arguments);
},
saturate: function() {
return this._applyModification(saturate, arguments);
},
greyscale: function() {
return this._applyModification(greyscale, arguments);
},
spin: function() {
return this._applyModification(spin, arguments);
},
_applyCombination: function(fn, args) {
return fn.apply(null, [this].concat([].slice.call(args)));
},
analogous: function() {
return this._applyCombination(analogous, arguments);
},
complement: function() {
return this._applyCombination(complement, arguments);
},
monochromatic: function() {
return this._applyCombination(monochromatic, arguments);
},
splitcomplement: function() {
return this._applyCombination(splitcomplement, arguments);
},
triad: function() {
return this._applyCombination(triad, arguments);
},
tetrad: function() {
return this._applyCombination(tetrad, arguments);
}
};
// If input is an object, force 1 into "1.0" to handle ratios properly
// String input requires "1.0" as input, so 1 will be treated as 1
tinycolor.fromRatio = function(color, opts) {
if (typeof color == "object") {
var newColor = {};
for (var i in color) {
if (color.hasOwnProperty(i)) {
if (i === "a") {
newColor[i] = color[i];
}
else {
newColor[i] = convertToPercentage(color[i]);
}
}
}
color = newColor;
}
return tinycolor(color, opts);
};
// Given a string or object, convert that input to RGB
// Possible string inputs:
//
// "red"
// "#f00" or "f00"
// "#ff0000" or "ff0000"
// "#ff000000" or "ff000000"
// "rgb 255 0 0" or "rgb (255, 0, 0)"
// "rgb 1.0 0 0" or "rgb (1, 0, 0)"
// "rgba (255, 0, 0, 1)" or "rgba 255, 0, 0, 1"
// "rgba (1.0, 0, 0, 1)" or "rgba 1.0, 0, 0, 1"
// "hsl(0, 100%, 50%)" or "hsl 0 100% 50%"
// "hsla(0, 100%, 50%, 1)" or "hsla 0 100% 50%, 1"
// "hsv(0, 100%, 100%)" or "hsv 0 100% 100%"
//
function inputToRGB(color) {
var rgb = { r: 0, g: 0, b: 0 };
var a = 1;
var ok = false;
var format = false;
if (typeof color == "string") {
color = stringInputToObject(color);
}
if (typeof color == "object") {
if (color.hasOwnProperty("r") && color.hasOwnProperty("g") && color.hasOwnProperty("b")) {
rgb = rgbToRgb(color.r, color.g, color.b);
ok = true;
format = String(color.r).substr(-1) === "%" ? "prgb" : "rgb";
}
else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("v")) {
color.s = convertToPercentage(color.s);
color.v = convertToPercentage(color.v);
rgb = hsvToRgb(color.h, color.s, color.v);
ok = true;
format = "hsv";
}
else if (color.hasOwnProperty("h") && color.hasOwnProperty("s") && color.hasOwnProperty("l")) {
color.s = convertToPercentage(color.s);
color.l = convertToPercentage(color.l);
rgb = hslToRgb(color.h, color.s, color.l);
ok = true;
format = "hsl";
}
if (color.hasOwnProperty("a")) {
a = color.a;
}
}
a = boundAlpha(a);
return {
ok: ok,
format: color.format || format,
r: mathMin(255, mathMax(rgb.r, 0)),
g: mathMin(255, mathMax(rgb.g, 0)),
b: mathMin(255, mathMax(rgb.b, 0)),
a: a
};
}
// Conversion Functions
// --------------------
// `rgbToHsl`, `rgbToHsv`, `hslToRgb`, `hsvToRgb` modified from:
// <http://mjijackson.com/2008/02/rgb-to-hsl-and-rgb-to-hsv-color-model-conversion-algorithms-in-javascript>
// `rgbToRgb`
// Handle bounds / percentage checking to conform to CSS color spec
// <http://www.w3.org/TR/css3-color/>
// *Assumes:* r, g, b in [0, 255] or [0, 1]
// *Returns:* { r, g, b } in [0, 255]
function rgbToRgb(r, g, b){
return {
r: bound01(r, 255) * 255,
g: bound01(g, 255) * 255,
b: bound01(b, 255) * 255
};
}
// `rgbToHsl`
// Converts an RGB color value to HSL.
// *Assumes:* r, g, and b are contained in [0, 255] or [0, 1]
// *Returns:* { h, s, l } in [0,1]
function rgbToHsl(r, g, b) {
r = bound01(r, 255);
g = bound01(g, 255);
b = bound01(b, 255);
var max = mathMax(r, g, b), min = mathMin(r, g, b);
var h, s, l = (max + min) / 2;
if(max == min) {
h = s = 0; // achromatic
}
else {
var d = max - min;
s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { h: h, s: s, l: l };
}
// `hslToRgb`
// Converts an HSL color value to RGB.
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and l are contained [0, 1] or [0, 100]
// *Returns:* { r, g, b } in the set [0, 255]
function hslToRgb(h, s, l) {
var r, g, b;
h = bound01(h, 360);
s = bound01(s, 100);
l = bound01(l, 100);
function hue2rgb(p, q, t) {
if(t < 0) t += 1;
if(t > 1) t -= 1;
if(t < 1/6) return p + (q - p) * 6 * t;
if(t < 1/2) return q;
if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
return p;
}
if(s === 0) {
r = g = b = l; // achromatic
}
else {
var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
var p = 2 * l - q;
r = hue2rgb(p, q, h + 1/3);
g = hue2rgb(p, q, h);
b = hue2rgb(p, q, h - 1/3);
}
return { r: r * 255, g: g * 255, b: b * 255 };
}
// `rgbToHsv`
// Converts an RGB color value to HSV
// *Assumes:* r, g, and b are contained in the set [0, 255] or [0, 1]
// *Returns:* { h, s, v } in [0,1]
function rgbToHsv(r, g, b) {
r = bound01(r, 255);
g = bound01(g, 255);
b = bound01(b, 255);
var max = mathMax(r, g, b), min = mathMin(r, g, b);
var h, s, v = max;
var d = max - min;
s = max === 0 ? 0 : d / max;
if(max == min) {
h = 0; // achromatic
}
else {
switch(max) {
case r: h = (g - b) / d + (g < b ? 6 : 0); break;
case g: h = (b - r) / d + 2; break;
case b: h = (r - g) / d + 4; break;
}
h /= 6;
}
return { h: h, s: s, v: v };
}
// `hsvToRgb`
// Converts an HSV color value to RGB.
// *Assumes:* h is contained in [0, 1] or [0, 360] and s and v are contained in [0, 1] or [0, 100]
// *Returns:* { r, g, b } in the set [0, 255]
function hsvToRgb(h, s, v) {
h = bound01(h, 360) * 6;
s = bound01(s, 100);
v = bound01(v, 100);
var i = math.floor(h),
f = h - i,
p = v * (1 - s),
q = v * (1 - f * s),
t = v * (1 - (1 - f) * s),
mod = i % 6,
r = [v, q, p, p, t, v][mod],
g = [t, v, v, q, p, p][mod],
b = [p, p, t, v, v, q][mod];
return { r: r * 255, g: g * 255, b: b * 255 };
}
// `rgbToHex`
// Converts an RGB color to hex
// Assumes r, g, and b are contained in the set [0, 255]
// Returns a 3 or 6 character hex
function rgbToHex(r, g, b, allow3Char) {
var hex = [
pad2(mathRound(r).toString(16)),
pad2(mathRound(g).toString(16)),
pad2(mathRound(b).toString(16))
];
// Return a 3 character hex if possible
if (allow3Char && hex[0].charAt(0) == hex[0].charAt(1) && hex[1].charAt(0) == hex[1].charAt(1) && hex[2].charAt(0) == hex[2].charAt(1)) {
return hex[0].charAt(0) + hex[1].charAt(0) + hex[2].charAt(0);
}
return hex.join("");
}
// `rgbaToHex`
// Converts an RGBA color plus alpha transparency to hex
// Assumes r, g, b and a are contained in the set [0, 255]
// Returns an 8 character hex
function rgbaToHex(r, g, b, a) {
var hex = [
pad2(convertDecimalToHex(a)),
pad2(mathRound(r).toString(16)),
pad2(mathRound(g).toString(16)),
pad2(mathRound(b).toString(16))
];
return hex.join("");
}
// `equals`
// Can be called with any tinycolor input
tinycolor.equals = function (color1, color2) {
if (!color1 || !color2) { return false; }
return tinycolor(color1).toRgbString() == tinycolor(color2).toRgbString();
};
tinycolor.random = function() {
return tinycolor.fromRatio({
r: mathRandom(),
g: mathRandom(),
b: mathRandom()
});
};
// Modification Functions
// ----------------------
// Thanks to less.js for some of the basics here
// <https://github.com/cloudhead/less.js/blob/master/lib/less/functions.js>
function desaturate(color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
hsl.s -= amount / 100;
hsl.s = clamp01(hsl.s);
return tinycolor(hsl);
}
function saturate(color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
hsl.s += amount / 100;
hsl.s = clamp01(hsl.s);
return tinycolor(hsl);
}
function greyscale(color) {
return tinycolor(color).desaturate(100);
}
function lighten (color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
hsl.l += amount / 100;
hsl.l = clamp01(hsl.l);
return tinycolor(hsl);
}
function brighten(color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var rgb = tinycolor(color).toRgb();
rgb.r = mathMax(0, mathMin(255, rgb.r - mathRound(255 * - (amount / 100))));
rgb.g = mathMax(0, mathMin(255, rgb.g - mathRound(255 * - (amount / 100))));
rgb.b = mathMax(0, mathMin(255, rgb.b - mathRound(255 * - (amount / 100))));
return tinycolor(rgb);
}
function darken (color, amount) {
amount = (amount === 0) ? 0 : (amount || 10);
var hsl = tinycolor(color).toHsl();
hsl.l -= amount / 100;
hsl.l = clamp01(hsl.l);
return tinycolor(hsl);
}
// Spin takes a positive or negative amount within [-360, 360] indicating the change of hue.
// Values outside of this range will be wrapped into this range.
function spin(color, amount) {
var hsl = tinycolor(color).toHsl();
var hue = (mathRound(hsl.h) + amount) % 360;
hsl.h = hue < 0 ? 360 + hue : hue;
return tinycolor(hsl);
}
// Combination Functions
// ---------------------
// Thanks to jQuery xColor for some of the ideas behind these
// <https://github.com/infusion/jQuery-xcolor/blob/master/jquery.xcolor.js>
function complement(color) {
var hsl = tinycolor(color).toHsl();
hsl.h = (hsl.h + 180) % 360;
return tinycolor(hsl);
}
function triad(color) {
var hsl = tinycolor(color).toHsl();
var h = hsl.h;
return [
tinycolor(color),
tinycolor({ h: (h + 120) % 360, s: hsl.s, l: hsl.l }),
tinycolor({ h: (h + 240) % 360, s: hsl.s, l: hsl.l })
];
}
function tetrad(color) {
var hsl = tinycolor(color).toHsl();
var h = hsl.h;
return [
tinycolor(color),
tinycolor({ h: (h + 90) % 360, s: hsl.s, l: hsl.l }),
tinycolor({ h: (h + 180) % 360, s: hsl.s, l: hsl.l }),
tinycolor({ h: (h + 270) % 360, s: hsl.s, l: hsl.l })
];
}
function splitcomplement(color) {
var hsl = tinycolor(color).toHsl();
var h = hsl.h;
return [
tinycolor(color),
tinycolor({ h: (h + 72) % 360, s: hsl.s, l: hsl.l}),
tinycolor({ h: (h + 216) % 360, s: hsl.s, l: hsl.l})
];
}
function analogous(color, results, slices) {
results = results || 6;
slices = slices || 30;
var hsl = tinycolor(color).toHsl();
var part = 360 / slices;
var ret = [tinycolor(color)];
for (hsl.h = ((hsl.h - (part * results >> 1)) + 720) % 360; --results; ) {
hsl.h = (hsl.h + part) % 360;
ret.push(tinycolor(hsl));
}
return ret;
}
function monochromatic(color, results) {
results = results || 6;
var hsv = tinycolor(color).toHsv();
var h = hsv.h, s = hsv.s, v = hsv.v;
var ret = [];
var modification = 1 / results;
while (results--) {
ret.push(tinycolor({ h: h, s: s, v: v}));
v = (v + modification) % 1;
}
return ret;
}
// Utility Functions
// ---------------------
tinycolor.mix = function(color1, color2, amount) {
amount = (amount === 0) ? 0 : (amount || 50);
var rgb1 = tinycolor(color1).toRgb();
var rgb2 = tinycolor(color2).toRgb();
var p = amount / 100;
var w = p * 2 - 1;
var a = rgb2.a - rgb1.a;
var w1;
if (w * a == -1) {
w1 = w;
} else {
w1 = (w + a) / (1 + w * a);
}
w1 = (w1 + 1) / 2;
var w2 = 1 - w1;
var rgba = {
r: rgb2.r * w1 + rgb1.r * w2,
g: rgb2.g * w1 + rgb1.g * w2,
b: rgb2.b * w1 + rgb1.b * w2,
a: rgb2.a * p + rgb1.a * (1 - p)
};
return tinycolor(rgba);
};
// Readability Functions
// ---------------------
// <http://www.w3.org/TR/AERT#color-contrast>
// `readability`
// Analyze the 2 colors and returns an object with the following properties:
// `brightness`: difference in brightness between the two colors
// `color`: difference in color/hue between the two colors
tinycolor.readability = function(color1, color2) {
var c1 = tinycolor(color1);
var c2 = tinycolor(color2);
var rgb1 = c1.toRgb();
var rgb2 = c2.toRgb();
var brightnessA = c1.getBrightness();
var brightnessB = c2.getBrightness();
var colorDiff = (
Math.max(rgb1.r, rgb2.r) - Math.min(rgb1.r, rgb2.r) +
Math.max(rgb1.g, rgb2.g) - Math.min(rgb1.g, rgb2.g) +
Math.max(rgb1.b, rgb2.b) - Math.min(rgb1.b, rgb2.b)
);
return {
brightness: Math.abs(brightnessA - brightnessB),
color: colorDiff
};
};
// `readable`
// http://www.w3.org/TR/AERT#color-contrast
// Ensure that foreground and background color combinations provide sufficient contrast.
// *Example*
// tinycolor.isReadable("#000", "#111") => false
tinycolor.isReadable = function(color1, color2) {
var readability = tinycolor.readability(color1, color2);
return readability.brightness > 125 && readability.color > 500;
};
// `mostReadable`
// Given a base color and a list of possible foreground or background
// colors for that base, returns the most readable color.
// *Example*
// tinycolor.mostReadable("#123", ["#fff", "#000"]) => "#000"
tinycolor.mostReadable = function(baseColor, colorList) {
var bestColor = null;
var bestScore = 0;
var bestIsReadable = false;
for (var i=0; i < colorList.length; i++) {
// We normalize both around the "acceptable" breaking point,
// but rank brightness constrast higher than hue.
var readability = tinycolor.readability(baseColor, colorList[i]);
var readable = readability.brightness > 125 && readability.color > 500;
var score = 3 * (readability.brightness / 125) + (readability.color / 500);
if ((readable && ! bestIsReadable) ||
(readable && bestIsReadable && score > bestScore) ||
((! readable) && (! bestIsReadable) && score > bestScore)) {
bestIsReadable = readable;
bestScore = score;
bestColor = tinycolor(colorList[i]);
}
}
return bestColor;
};
// Big List of Colors
// ------------------
// <http://www.w3.org/TR/css3-color/#svg-color>
var names = tinycolor.names = {
aliceblue: "f0f8ff",
antiquewhite: "faebd7",
aqua: "0ff",
aquamarine: "7fffd4",
azure: "f0ffff",
beige: "f5f5dc",
bisque: "ffe4c4",
black: "000",
blanchedalmond: "ffebcd",
blue: "00f",
blueviolet: "8a2be2",
brown: "a52a2a",
burlywood: "deb887",
burntsienna: "ea7e5d",
cadetblue: "5f9ea0",
chartreuse: "7fff00",
chocolate: "d2691e",
coral: "ff7f50",
cornflowerblue: "6495ed",
cornsilk: "fff8dc",
crimson: "dc143c",
cyan: "0ff",
darkblue: "00008b",
darkcyan: "008b8b",
darkgoldenrod: "b8860b",
darkgray: "a9a9a9",
darkgreen: "006400",
darkgrey: "a9a9a9",
darkkhaki: "bdb76b",
darkmagenta: "8b008b",
darkolivegreen: "556b2f",
darkorange: "ff8c00",
darkorchid: "9932cc",
darkred: "8b0000",
darksalmon: "e9967a",
darkseagreen: "8fbc8f",
darkslateblue: "483d8b",
darkslategray: "2f4f4f",
darkslategrey: "2f4f4f",
darkturquoise: "00ced1",
darkviolet: "9400d3",
deeppink: "ff1493",
deepskyblue: "00bfff",
dimgray: "696969",
dimgrey: "696969",
dodgerblue: "1e90ff",
firebrick: "b22222",
floralwhite: "fffaf0",
forestgreen: "228b22",
fuchsia: "f0f",
gainsboro: "dcdcdc",
ghostwhite: "f8f8ff",
gold: "ffd700",
goldenrod: "daa520",
gray: "808080",
green: "008000",
greenyellow: "adff2f",
grey: "808080",
honeydew: "f0fff0",
hotpink: "ff69b4",
indianred: "cd5c5c",
indigo: "4b0082",
ivory: "fffff0",
khaki: "f0e68c",
lavender: "e6e6fa",
lavenderblush: "fff0f5",
lawngreen: "7cfc00",
lemonchiffon: "fffacd",
lightblue: "add8e6",
lightcoral: "f08080",
lightcyan: "e0ffff",
lightgoldenrodyellow: "fafad2",
lightgray: "d3d3d3",
lightgreen: "90ee90",
lightgrey: "d3d3d3",
lightpink: "ffb6c1",
lightsalmon: "ffa07a",
lightseagreen: "20b2aa",
lightskyblue: "87cefa",
lightslategray: "789",
lightslategrey: "789",
lightsteelblue: "b0c4de",
lightyellow: "ffffe0",
lime: "0f0",
limegreen: "32cd32",
linen: "faf0e6",
magenta: "f0f",
maroon: "800000",
mediumaquamarine: "66cdaa",
mediumblue: "0000cd",
mediumorchid: "ba55d3",
mediumpurple: "9370db",
mediumseagreen: "3cb371",
mediumslateblue: "7b68ee",
mediumspringgreen: "00fa9a",
mediumturquoise: "48d1cc",
mediumvioletred: "c71585",
midnightblue: "191970",
mintcream: "f5fffa",
mistyrose: "ffe4e1",
moccasin: "ffe4b5",
navajowhite: "ffdead",
navy: "000080",
oldlace: "fdf5e6",
olive: "808000",
olivedrab: "6b8e23",
orange: "ffa500",
orangered: "ff4500",
orchid: "da70d6",
palegoldenrod: "eee8aa",
palegreen: "98fb98",
paleturquoise: "afeeee",
palevioletred: "db7093",
papayawhip: "ffefd5",
peachpuff: "ffdab9",
peru: "cd853f",
pink: "ffc0cb",
plum: "dda0dd",
powderblue: "b0e0e6",
purple: "800080",
rebeccapurple: "663399",
red: "f00",
rosybrown: "bc8f8f",
royalblue: "4169e1",
saddlebrown: "8b4513",
salmon: "fa8072",
sandybrown: "f4a460",
seagreen: "2e8b57",
seashell: "fff5ee",
sienna: "a0522d",
silver: "c0c0c0",
skyblue: "87ceeb",
slateblue: "6a5acd",
slategray: "708090",
slategrey: "708090",
snow: "fffafa",
springgreen: "00ff7f",
steelblue: "4682b4",
tan: "d2b48c",
teal: "008080",
thistle: "d8bfd8",
tomato: "ff6347",
turquoise: "40e0d0",
violet: "ee82ee",
wheat: "f5deb3",
white: "fff",
whitesmoke: "f5f5f5",
yellow: "ff0",
yellowgreen: "9acd32"
};
// Make it easy to access colors via `hexNames[hex]`
var hexNames = tinycolor.hexNames = flip(names);
// Utilities
// ---------
// `{ 'name1': 'val1' }` becomes `{ 'val1': 'name1' }`
function flip(o) {
var flipped = { };
for (var i in o) {
if (o.hasOwnProperty(i)) {
flipped[o[i]] = i;
}
}
return flipped;
}
// Return a valid alpha value [0,1] with all invalid values being set to 1
function boundAlpha(a) {
a = parseFloat(a);
if (isNaN(a) || a < 0 || a > 1) {
a = 1;
}
return a;
}
// Take input from [0, n] and return it as [0, 1]
function bound01(n, max) {
if (isOnePointZero(n)) { n = "100%"; }
var processPercent = isPercentage(n);
n = mathMin(max, mathMax(0, parseFloat(n)));
// Automatically convert percentage into number
if (processPercent) {
n = parseInt(n * max, 10) / 100;
}
// Handle floating point rounding errors
if ((math.abs(n - max) < 0.000001)) {
return 1;
}
// Convert into [0, 1] range if it isn't already
return (n % max) / parseFloat(max);
}
// Force a number between 0 and 1
function clamp01(val) {
return mathMin(1, mathMax(0, val));
}
// Parse a base-16 hex value into a base-10 integer
function parseIntFromHex(val) {
return parseInt(val, 16);
}
// Need to handle 1.0 as 100%, since once it is a number, there is no difference between it and 1
// <http://stackoverflow.com/questions/7422072/javascript-how-to-detect-number-as-a-decimal-including-1-0>
function isOnePointZero(n) {
return typeof n == "string" && n.indexOf('.') != -1 && parseFloat(n) === 1;
}
// Check to see if string passed in is a percentage
function isPercentage(n) {
return typeof n === "string" && n.indexOf('%') != -1;
}
// Force a hex value to have 2 characters
function pad2(c) {
return c.length == 1 ? '0' + c : '' + c;
}
// Replace a decimal with it's percentage value
function convertToPercentage(n) {
if (n <= 1) {
n = (n * 100) + "%";
}
return n;
}
// Converts a decimal to a hex value
function convertDecimalToHex(d) {
return Math.round(parseFloat(d) * 255).toString(16);
}
// Converts a hex value to a decimal
function convertHexToDecimal(h) {
return (parseIntFromHex(h) / 255);
}
var matchers = (function() {
// <http://www.w3.org/TR/css3-values/#integers>
var CSS_INTEGER = "[-\\+]?\\d+%?";
// <http://www.w3.org/TR/css3-values/#number-value>
var CSS_NUMBER = "[-\\+]?\\d*\\.\\d+%?";
// Allow positive/negative integer/number. Don't capture the either/or, just the entire outcome.
var CSS_UNIT = "(?:" + CSS_NUMBER + ")|(?:" + CSS_INTEGER + ")";
// Actual matching.
// Parentheses and commas are optional, but not required.
// Whitespace can take the place of commas or opening paren
var PERMISSIVE_MATCH3 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
var PERMISSIVE_MATCH4 = "[\\s|\\(]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")[,|\\s]+(" + CSS_UNIT + ")\\s*\\)?";
return {
rgb: new RegExp("rgb" + PERMISSIVE_MATCH3),
rgba: new RegExp("rgba" + PERMISSIVE_MATCH4),
hsl: new RegExp("hsl" + PERMISSIVE_MATCH3),
hsla: new RegExp("hsla" + PERMISSIVE_MATCH4),
hsv: new RegExp("hsv" + PERMISSIVE_MATCH3),
hsva: new RegExp("hsva" + PERMISSIVE_MATCH4),
hex3: /^([0-9a-fA-F]{1})([0-9a-fA-F]{1})([0-9a-fA-F]{1})$/,
hex6: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/,
hex8: /^([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})([0-9a-fA-F]{2})$/
};
})();
// `stringInputToObject`
// Permissive string parsing. Take in a number of formats, and output an object
// based on detected format. Returns `{ r, g, b }` or `{ h, s, l }` or `{ h, s, v}`
function stringInputToObject(color) {
color = color.replace(trimLeft,'').replace(trimRight, '').toLowerCase();
var named = false;
if (names[color]) {
color = names[color];
named = true;
}
else if (color == 'transparent') {
return { r: 0, g: 0, b: 0, a: 0, format: "name" };
}
// Try to match string input using regular expressions.
// Keep most of the number bounding out of this function - don't worry about [0,1] or [0,100] or [0,360]
// Just return an object and let the conversion functions handle that.
// This way the result will be the same whether the tinycolor is initialized with string or object.
var match;
if ((match = matchers.rgb.exec(color))) {
return { r: match[1], g: match[2], b: match[3] };
}
if ((match = matchers.rgba.exec(color))) {
return { r: match[1], g: match[2], b: match[3], a: match[4] };
}
if ((match = matchers.hsl.exec(color))) {
return { h: match[1], s: match[2], l: match[3] };
}
if ((match = matchers.hsla.exec(color))) {
return { h: match[1], s: match[2], l: match[3], a: match[4] };
}
if ((match = matchers.hsv.exec(color))) {
return { h: match[1], s: match[2], v: match[3] };
}
if ((match = matchers.hsva.exec(color))) {
return { h: match[1], s: match[2], v: match[3], a: match[4] };
}
if ((match = matchers.hex8.exec(color))) {
return {
a: convertHexToDecimal(match[1]),
r: parseIntFromHex(match[2]),
g: parseIntFromHex(match[3]),
b: parseIntFromHex(match[4]),
format: named ? "name" : "hex8"
};
}
if ((match = matchers.hex6.exec(color))) {
return {
r: parseIntFromHex(match[1]),
g: parseIntFromHex(match[2]),
b: parseIntFromHex(match[3]),
format: named ? "name" : "hex"
};
}
if ((match = matchers.hex3.exec(color))) {
return {
r: parseIntFromHex(match[1] + '' + match[1]),
g: parseIntFromHex(match[2] + '' + match[2]),
b: parseIntFromHex(match[3] + '' + match[3]),
format: named ? "name" : "hex"
};
}
return false;
}
window.tinycolor = tinycolor;
})();
$(function () {
if ($.fn.spectrum.load) {
$.fn.spectrum.processNativeColorInputs();
}
});
});
/* perfect-scrollbar v0.7.1 */
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
'use strict';
var ps = require('../main');
var psInstances = require('../plugin/instances');
function mountJQuery(jQuery) {
jQuery.fn.perfectScrollbar = function (settingOrCommand) {
return this.each(function () {
if (typeof settingOrCommand === 'object' ||
typeof settingOrCommand === 'undefined') {
// If it's an object or none, initialize.
var settings = settingOrCommand;
if (!psInstances.get(this)) {
ps.initialize(this, settings);
}
} else {
// Unless, it may be a command.
var command = settingOrCommand;
if (command === 'update') {
ps.update(this);
} else if (command === 'destroy') {
ps.destroy(this);
}
}
});
};
}
if (typeof define === 'function' && define.amd) {
// AMD. Register as an anonymous module.
define(['jquery'], mountJQuery);
} else {
var jq = window.jQuery ? window.jQuery : window.$;
if (typeof jq !== 'undefined') {
mountJQuery(jq);
}
}
module.exports = mountJQuery;
},{"../main":7,"../plugin/instances":18}],2:[function(require,module,exports){
'use strict';
function oldAdd(element, className) {
var classes = element.className.split(' ');
if (classes.indexOf(className) < 0) {
classes.push(className);
}
element.className = classes.join(' ');
}
function oldRemove(element, className) {
var classes = element.className.split(' ');
var idx = classes.indexOf(className);
if (idx >= 0) {
classes.splice(idx, 1);
}
element.className = classes.join(' ');
}
exports.add = function (element, className) {
if (element.classList) {
element.classList.add(className);
} else {
oldAdd(element, className);
}
};
exports.remove = function (element, className) {
if (element.classList) {
element.classList.remove(className);
} else {
oldRemove(element, className);
}
};
exports.list = function (element) {
if (element.classList) {
return Array.prototype.slice.apply(element.classList);
} else {
return element.className.split(' ');
}
};
},{}],3:[function(require,module,exports){
'use strict';
var DOM = {};
DOM.e = function (tagName, className) {
var element = document.createElement(tagName);
element.className = className;
return element;
};
DOM.appendTo = function (child, parent) {
parent.appendChild(child);
return child;
};
function cssGet(element, styleName) {
return window.getComputedStyle(element)[styleName];
}
function cssSet(element, styleName, styleValue) {
if (typeof styleValue === 'number') {
styleValue = styleValue.toString() + 'px';
}
element.style[styleName] = styleValue;
return element;
}
function cssMultiSet(element, obj) {
for (var key in obj) {
var val = obj[key];
if (typeof val === 'number') {
val = val.toString() + 'px';
}
element.style[key] = val;
}
return element;
}
DOM.css = function (element, styleNameOrObject, styleValue) {
if (typeof styleNameOrObject === 'object') {
// multiple set with object
return cssMultiSet(element, styleNameOrObject);
} else {
if (typeof styleValue === 'undefined') {
return cssGet(element, styleNameOrObject);
} else {
return cssSet(element, styleNameOrObject, styleValue);
}
}
};
DOM.matches = function (element, query) {
if (typeof element.matches !== 'undefined') {
return element.matches(query);
} else {
if (typeof element.matchesSelector !== 'undefined') {
return element.matchesSelector(query);
} else if (typeof element.webkitMatchesSelector !== 'undefined') {
return element.webkitMatchesSelector(query);
} else if (typeof element.mozMatchesSelector !== 'undefined') {
return element.mozMatchesSelector(query);
} else if (typeof element.msMatchesSelector !== 'undefined') {
return element.msMatchesSelector(query);
}
}
};
DOM.remove = function (element) {
if (typeof element.remove !== 'undefined') {
element.remove();
} else {
if (element.parentNode) {
element.parentNode.removeChild(element);
}
}
};
DOM.queryChildren = function (element, selector) {
return Array.prototype.filter.call(element.childNodes, function (child) {
return DOM.matches(child, selector);
});
};
module.exports = DOM;
},{}],4:[function(require,module,exports){
'use strict';
var EventElement = function (element) {
this.element = element;
this.events = {};
};
EventElement.prototype.bind = function (eventName, handler) {
if (typeof this.events[eventName] === 'undefined') {
this.events[eventName] = [];
}
this.events[eventName].push(handler);
this.element.addEventListener(eventName, handler, false);
};
EventElement.prototype.unbind = function (eventName, handler) {
var isHandlerProvided = (typeof handler !== 'undefined');
this.events[eventName] = this.events[eventName].filter(function (hdlr) {
if (isHandlerProvided && hdlr !== handler) {
return true;
}
this.element.removeEventListener(eventName, hdlr, false);
return false;
}, this);
};
EventElement.prototype.unbindAll = function () {
for (var name in this.events) {
this.unbind(name);
}
};
var EventManager = function () {
this.eventElements = [];
};
EventManager.prototype.eventElement = function (element) {
var ee = this.eventElements.filter(function (eventElement) {
return eventElement.element === element;
})[0];
if (typeof ee === 'undefined') {
ee = new EventElement(element);
this.eventElements.push(ee);
}
return ee;
};
EventManager.prototype.bind = function (element, eventName, handler) {
this.eventElement(element).bind(eventName, handler);
};
EventManager.prototype.unbind = function (element, eventName, handler) {
this.eventElement(element).unbind(eventName, handler);
};
EventManager.prototype.unbindAll = function () {
for (var i = 0; i < this.eventElements.length; i++) {
this.eventElements[i].unbindAll();
}
};
EventManager.prototype.once = function (element, eventName, handler) {
var ee = this.eventElement(element);
var onceHandler = function (e) {
ee.unbind(eventName, onceHandler);
handler(e);
};
ee.bind(eventName, onceHandler);
};
module.exports = EventManager;
},{}],5:[function(require,module,exports){
'use strict';
module.exports = (function () {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return function () {
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
};
})();
},{}],6:[function(require,module,exports){
'use strict';
var cls = require('./class');
var dom = require('./dom');
var toInt = exports.toInt = function (x) {
return parseInt(x, 10) || 0;
};
var clone = exports.clone = function (obj) {
if (!obj) {
return null;
} else if (Array.isArray(obj)) {
return obj.map(clone);
} else if (typeof obj === 'object') {
var result = {};
for (var key in obj) {
result[key] = clone(obj[key]);
}
return result;
} else {
return obj;
}
};
exports.extend = function (original, source) {
var result = clone(original);
for (var key in source) {
result[key] = clone(source[key]);
}
return result;
};
exports.isEditable = function (el) {
return dom.matches(el, "input,[contenteditable]") ||
dom.matches(el, "select,[contenteditable]") ||
dom.matches(el, "textarea,[contenteditable]") ||
dom.matches(el, "button,[contenteditable]");
};
exports.removePsClasses = function (element) {
var clsList = cls.list(element);
for (var i = 0; i < clsList.length; i++) {
var className = clsList[i];
if (className.indexOf('ps-') === 0) {
cls.remove(element, className);
}
}
};
exports.outerWidth = function (element) {
return toInt(dom.css(element, 'width')) +
toInt(dom.css(element, 'paddingLeft')) +
toInt(dom.css(element, 'paddingRight')) +
toInt(dom.css(element, 'borderLeftWidth')) +
toInt(dom.css(element, 'borderRightWidth'));
};
function toggleScrolling(handler) {
return function (element, axis) {
handler(element, 'ps--in-scrolling');
if (typeof axis !== 'undefined') {
handler(element, 'ps--' + axis);
} else {
handler(element, 'ps--x');
handler(element, 'ps--y');
}
};
}
exports.startScrolling = toggleScrolling(cls.add);
exports.stopScrolling = toggleScrolling(cls.remove);
exports.env = {
isWebKit: typeof document !== 'undefined' && 'WebkitAppearance' in document.documentElement.style,
supportsTouch: typeof window !== 'undefined' && (('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch),
supportsIePointer: typeof window !== 'undefined' && window.navigator.msMaxTouchPoints !== null
};
},{"./class":2,"./dom":3}],7:[function(require,module,exports){
'use strict';
var destroy = require('./plugin/destroy');
var initialize = require('./plugin/initialize');
var update = require('./plugin/update');
module.exports = {
initialize: initialize,
update: update,
destroy: destroy
};
},{"./plugin/destroy":9,"./plugin/initialize":17,"./plugin/update":21}],8:[function(require,module,exports){
'use strict';
module.exports = {
handlers: ['click-rail', 'drag-scrollbar', 'keyboard', 'wheel', 'touch'],
maxScrollbarLength: null,
minScrollbarLength: null,
scrollXMarginOffset: 0,
scrollYMarginOffset: 0,
suppressScrollX: false,
suppressScrollY: false,
swipePropagation: true,
swipeEasing: true,
useBothWheelAxes: false,
wheelPropagation: false,
wheelSpeed: 1,
theme: 'default'
};
},{}],9:[function(require,module,exports){
'use strict';
var _ = require('../lib/helper');
var dom = require('../lib/dom');
var instances = require('./instances');
module.exports = function (element) {
var i = instances.get(element);
if (!i) {
return;
}
i.event.unbindAll();
dom.remove(i.scrollbarX);
dom.remove(i.scrollbarY);
dom.remove(i.scrollbarXRail);
dom.remove(i.scrollbarYRail);
_.removePsClasses(element);
instances.remove(element);
};
},{"../lib/dom":3,"../lib/helper":6,"./instances":18}],10:[function(require,module,exports){
'use strict';
var instances = require('../instances');
var updateGeometry = require('../update-geometry');
var updateScroll = require('../update-scroll');
function bindClickRailHandler(element, i) {
function pageOffset(el) {
return el.getBoundingClientRect();
}
var stopPropagation = function (e) { e.stopPropagation(); };
i.event.bind(i.scrollbarY, 'click', stopPropagation);
i.event.bind(i.scrollbarYRail, 'click', function (e) {
var positionTop = e.pageY - window.pageYOffset - pageOffset(i.scrollbarYRail).top;
var direction = positionTop > i.scrollbarYTop ? 1 : -1;
updateScroll(element, 'top', element.scrollTop + direction * i.containerHeight);
updateGeometry(element);
e.stopPropagation();
});
i.event.bind(i.scrollbarX, 'click', stopPropagation);
i.event.bind(i.scrollbarXRail, 'click', function (e) {
var positionLeft = e.pageX - window.pageXOffset - pageOffset(i.scrollbarXRail).left;
var direction = positionLeft > i.scrollbarXLeft ? 1 : -1;
updateScroll(element, 'left', element.scrollLeft + direction * i.containerWidth);
updateGeometry(element);
e.stopPropagation();
});
}
module.exports = function (element) {
var i = instances.get(element);
bindClickRailHandler(element, i);
};
},{"../instances":18,"../update-geometry":19,"../update-scroll":20}],11:[function(require,module,exports){
'use strict';
var _ = require('../../lib/helper');
var dom = require('../../lib/dom');
var instances = require('../instances');
var updateGeometry = require('../update-geometry');
var updateScroll = require('../update-scroll');
function bindMouseScrollXHandler(element, i) {
var currentLeft = null;
var currentPageX = null;
function updateScrollLeft(deltaX) {
var newLeft = currentLeft + (deltaX * i.railXRatio);
var maxLeft = Math.max(0, i.scrollbarXRail.getBoundingClientRect().left) + (i.railXRatio * (i.railXWidth - i.scrollbarXWidth));
if (newLeft < 0) {
i.scrollbarXLeft = 0;
} else if (newLeft > maxLeft) {
i.scrollbarXLeft = maxLeft;
} else {
i.scrollbarXLeft = newLeft;
}
var scrollLeft = _.toInt(i.scrollbarXLeft * (i.contentWidth - i.containerWidth) / (i.containerWidth - (i.railXRatio * i.scrollbarXWidth))) - i.negativeScrollAdjustment;
updateScroll(element, 'left', scrollLeft);
}
var mouseMoveHandler = function (e) {
updateScrollLeft(e.pageX - currentPageX);
updateGeometry(element);
e.stopPropagation();
e.preventDefault();
};
var mouseUpHandler = function () {
_.stopScrolling(element, 'x');
i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);
};
i.event.bind(i.scrollbarX, 'mousedown', function (e) {
currentPageX = e.pageX;
currentLeft = _.toInt(dom.css(i.scrollbarX, 'left')) * i.railXRatio;
_.startScrolling(element, 'x');
i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
e.stopPropagation();
e.preventDefault();
});
}
function bindMouseScrollYHandler(element, i) {
var currentTop = null;
var currentPageY = null;
function updateScrollTop(deltaY) {
var newTop = currentTop + (deltaY * i.railYRatio);
var maxTop = Math.max(0, i.scrollbarYRail.getBoundingClientRect().top) + (i.railYRatio * (i.railYHeight - i.scrollbarYHeight));
if (newTop < 0) {
i.scrollbarYTop = 0;
} else if (newTop > maxTop) {
i.scrollbarYTop = maxTop;
} else {
i.scrollbarYTop = newTop;
}
var scrollTop = _.toInt(i.scrollbarYTop * (i.contentHeight - i.containerHeight) / (i.containerHeight - (i.railYRatio * i.scrollbarYHeight)));
updateScroll(element, 'top', scrollTop);
}
var mouseMoveHandler = function (e) {
updateScrollTop(e.pageY - currentPageY);
updateGeometry(element);
e.stopPropagation();
e.preventDefault();
};
var mouseUpHandler = function () {
_.stopScrolling(element, 'y');
i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);
};
i.event.bind(i.scrollbarY, 'mousedown', function (e) {
currentPageY = e.pageY;
currentTop = _.toInt(dom.css(i.scrollbarY, 'top')) * i.railYRatio;
_.startScrolling(element, 'y');
i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);
i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);
e.stopPropagation();
e.preventDefault();
});
}
module.exports = function (element) {
var i = instances.get(element);
bindMouseScrollXHandler(element, i);
bindMouseScrollYHandler(element, i);
};
},{"../../lib/dom":3,"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],12:[function(require,module,exports){
'use strict';
var _ = require('../../lib/helper');
var dom = require('../../lib/dom');
var instances = require('../instances');
var updateGeometry = require('../update-geometry');
var updateScroll = require('../update-scroll');
function bindKeyboardHandler(element, i) {
var hovered = false;
i.event.bind(element, 'mouseenter', function () {
hovered = true;
});
i.event.bind(element, 'mouseleave', function () {
hovered = false;
});
var shouldPrevent = false;
function shouldPreventDefault(deltaX, deltaY) {
var scrollTop = element.scrollTop;
if (deltaX === 0) {
if (!i.scrollbarYActive) {
return false;
}
if ((scrollTop === 0 && deltaY > 0) || (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)) {
return !i.settings.wheelPropagation;
}
}
var scrollLeft = element.scrollLeft;
if (deltaY === 0) {
if (!i.scrollbarXActive) {
return false;
}
if ((scrollLeft === 0 && deltaX < 0) || (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)) {
return !i.settings.wheelPropagation;
}
}
return true;
}
i.event.bind(i.ownerDocument, 'keydown', function (e) {
if ((e.isDefaultPrevented && e.isDefaultPrevented()) || e.defaultPrevented) {
return;
}
var focused = dom.matches(i.scrollbarX, ':focus') ||
dom.matches(i.scrollbarY, ':focus');
if (!hovered && !focused) {
return;
}
var activeElement = document.activeElement ? document.activeElement : i.ownerDocument.activeElement;
if (activeElement) {
if (activeElement.tagName === 'IFRAME') {
activeElement = activeElement.contentDocument.activeElement;
} else {
// go deeper if element is a webcomponent
while (activeElement.shadowRoot) {
activeElement = activeElement.shadowRoot.activeElement;
}
}
if (_.isEditable(activeElement)) {
return;
}
}
var deltaX = 0;
var deltaY = 0;
switch (e.which) {
case 37: // left
if (e.metaKey) {
deltaX = -i.contentWidth;
} else if (e.altKey) {
deltaX = -i.containerWidth;
} else {
deltaX = -30;
}
break;
case 38: // up
if (e.metaKey) {
deltaY = i.contentHeight;
} else if (e.altKey) {
deltaY = i.containerHeight;
} else {
deltaY = 30;
}
break;
case 39: // right
if (e.metaKey) {
deltaX = i.contentWidth;
} else if (e.altKey) {
deltaX = i.containerWidth;
} else {
deltaX = 30;
}
break;
case 40: // down
if (e.metaKey) {
deltaY = -i.contentHeight;
} else if (e.altKey) {
deltaY = -i.containerHeight;
} else {
deltaY = -30;
}
break;
case 33: // page up
deltaY = 90;
break;
case 32: // space bar
if (e.shiftKey) {
deltaY = 90;
} else {
deltaY = -90;
}
break;
case 34: // page down
deltaY = -90;
break;
case 35: // end
if (e.ctrlKey) {
deltaY = -i.contentHeight;
} else {
deltaY = -i.containerHeight;
}
break;
case 36: // home
if (e.ctrlKey) {
deltaY = element.scrollTop;
} else {
deltaY = i.containerHeight;
}
break;
default:
return;
}
updateScroll(element, 'top', element.scrollTop - deltaY);
updateScroll(element, 'left', element.scrollLeft + deltaX);
updateGeometry(element);
shouldPrevent = shouldPreventDefault(deltaX, deltaY);
if (shouldPrevent) {
e.preventDefault();
}
});
}
module.exports = function (element) {
var i = instances.get(element);
bindKeyboardHandler(element, i);
};
},{"../../lib/dom":3,"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],13:[function(require,module,exports){
'use strict';
var instances = require('../instances');
var updateGeometry = require('../update-geometry');
var updateScroll = require('../update-scroll');
function bindMouseWheelHandler(element, i) {
var shouldPrevent = false;
function shouldPreventDefault(deltaX, deltaY) {
var scrollTop = element.scrollTop;
if (deltaX === 0) {
if (!i.scrollbarYActive) {
return false;
}
if ((scrollTop === 0 && deltaY > 0) || (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)) {
return !i.settings.wheelPropagation;
}
}
var scrollLeft = element.scrollLeft;
if (deltaY === 0) {
if (!i.scrollbarXActive) {
return false;
}
if ((scrollLeft === 0 && deltaX < 0) || (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)) {
return !i.settings.wheelPropagation;
}
}
return true;
}
function getDeltaFromEvent(e) {
var deltaX = e.deltaX;
var deltaY = -1 * e.deltaY;
if (typeof deltaX === "undefined" || typeof deltaY === "undefined") {
// OS X Safari
deltaX = -1 * e.wheelDeltaX / 6;
deltaY = e.wheelDeltaY / 6;
}
if (e.deltaMode && e.deltaMode === 1) {
// Firefox in deltaMode 1: Line scrolling
deltaX *= 10;
deltaY *= 10;
}
if (deltaX !== deltaX && deltaY !== deltaY/* NaN checks */) {
// IE in some mouse drivers
deltaX = 0;
deltaY = e.wheelDelta;
}
if (e.shiftKey) {
// reverse axis with shift key
return [-deltaY, -deltaX];
}
return [deltaX, deltaY];
}
function shouldBeConsumedByChild(deltaX, deltaY) {
var child = element.querySelector('textarea:hover, select[multiple]:hover, .ps-child:hover');
if (child) {
var style = window.getComputedStyle(child);
var overflow = [
style.overflow,
style.overflowX,
style.overflowY
].join('');
if (!overflow.match(/(scroll|auto)/)) {
// if not scrollable
return false;
}
var maxScrollTop = child.scrollHeight - child.clientHeight;
if (maxScrollTop > 0) {
if (!(child.scrollTop === 0 && deltaY > 0) && !(child.scrollTop === maxScrollTop && deltaY < 0)) {
return true;
}
}
var maxScrollLeft = child.scrollLeft - child.clientWidth;
if (maxScrollLeft > 0) {
if (!(child.scrollLeft === 0 && deltaX < 0) && !(child.scrollLeft === maxScrollLeft && deltaX > 0)) {
return true;
}
}
}
return false;
}
function mousewheelHandler(e) {
var delta = getDeltaFromEvent(e);
var deltaX = delta[0];
var deltaY = delta[1];
if (shouldBeConsumedByChild(deltaX, deltaY)) {
return;
}
shouldPrevent = false;
if (!i.settings.useBothWheelAxes) {
// deltaX will only be used for horizontal scrolling and deltaY will
// only be used for vertical scrolling - this is the default
updateScroll(element, 'top', element.scrollTop - (deltaY * i.settings.wheelSpeed));
updateScroll(element, 'left', element.scrollLeft + (deltaX * i.settings.wheelSpeed));
} else if (i.scrollbarYActive && !i.scrollbarXActive) {
// only vertical scrollbar is active and useBothWheelAxes option is
// active, so let's scroll vertical bar using both mouse wheel axes
if (deltaY) {
updateScroll(element, 'top', element.scrollTop - (deltaY * i.settings.wheelSpeed));
} else {
updateScroll(element, 'top', element.scrollTop + (deltaX * i.settings.wheelSpeed));
}
shouldPrevent = true;
} else if (i.scrollbarXActive && !i.scrollbarYActive) {
// useBothWheelAxes and only horizontal bar is active, so use both
// wheel axes for horizontal bar
if (deltaX) {
updateScroll(element, 'left', element.scrollLeft + (deltaX * i.settings.wheelSpeed));
} else {
updateScroll(element, 'left', element.scrollLeft - (deltaY * i.settings.wheelSpeed));
}
shouldPrevent = true;
}
updateGeometry(element);
shouldPrevent = (shouldPrevent || shouldPreventDefault(deltaX, deltaY));
if (shouldPrevent) {
e.stopPropagation();
e.preventDefault();
}
}
if (typeof window.onwheel !== "undefined") {
i.event.bind(element, 'wheel', mousewheelHandler);
} else if (typeof window.onmousewheel !== "undefined") {
i.event.bind(element, 'mousewheel', mousewheelHandler);
}
}
module.exports = function (element) {
var i = instances.get(element);
bindMouseWheelHandler(element, i);
};
},{"../instances":18,"../update-geometry":19,"../update-scroll":20}],14:[function(require,module,exports){
'use strict';
var instances = require('../instances');
var updateGeometry = require('../update-geometry');
function bindNativeScrollHandler(element, i) {
i.event.bind(element, 'scroll', function () {
updateGeometry(element);
});
}
module.exports = function (element) {
var i = instances.get(element);
bindNativeScrollHandler(element, i);
};
},{"../instances":18,"../update-geometry":19}],15:[function(require,module,exports){
'use strict';
var _ = require('../../lib/helper');
var instances = require('../instances');
var updateGeometry = require('../update-geometry');
var updateScroll = require('../update-scroll');
function bindSelectionHandler(element, i) {
function getRangeNode() {
var selection = window.getSelection ? window.getSelection() :
document.getSelection ? document.getSelection() : '';
if (selection.toString().length === 0) {
return null;
} else {
return selection.getRangeAt(0).commonAncestorContainer;
}
}
var scrollingLoop = null;
var scrollDiff = {top: 0, left: 0};
function startScrolling() {
if (!scrollingLoop) {
scrollingLoop = setInterval(function () {
if (!instances.get(element)) {
clearInterval(scrollingLoop);
return;
}
updateScroll(element, 'top', element.scrollTop + scrollDiff.top);
updateScroll(element, 'left', element.scrollLeft + scrollDiff.left);
updateGeometry(element);
}, 50); // every .1 sec
}
}
function stopScrolling() {
if (scrollingLoop) {
clearInterval(scrollingLoop);
scrollingLoop = null;
}
_.stopScrolling(element);
}
var isSelected = false;
i.event.bind(i.ownerDocument, 'selectionchange', function () {
if (element.contains(getRangeNode())) {
isSelected = true;
} else {
isSelected = false;
stopScrolling();
}
});
i.event.bind(window, 'mouseup', function () {
if (isSelected) {
isSelected = false;
stopScrolling();
}
});
i.event.bind(window, 'keyup', function () {
if (isSelected) {
isSelected = false;
stopScrolling();
}
});
i.event.bind(window, 'mousemove', function (e) {
if (isSelected) {
var mousePosition = {x: e.pageX, y: e.pageY};
var containerGeometry = {
left: element.offsetLeft,
right: element.offsetLeft + element.offsetWidth,
top: element.offsetTop,
bottom: element.offsetTop + element.offsetHeight
};
if (mousePosition.x < containerGeometry.left + 3) {
scrollDiff.left = -5;
_.startScrolling(element, 'x');
} else if (mousePosition.x > containerGeometry.right - 3) {
scrollDiff.left = 5;
_.startScrolling(element, 'x');
} else {
scrollDiff.left = 0;
}
if (mousePosition.y < containerGeometry.top + 3) {
if (containerGeometry.top + 3 - mousePosition.y < 5) {
scrollDiff.top = -5;
} else {
scrollDiff.top = -20;
}
_.startScrolling(element, 'y');
} else if (mousePosition.y > containerGeometry.bottom - 3) {
if (mousePosition.y - containerGeometry.bottom + 3 < 5) {
scrollDiff.top = 5;
} else {
scrollDiff.top = 20;
}
_.startScrolling(element, 'y');
} else {
scrollDiff.top = 0;
}
if (scrollDiff.top === 0 && scrollDiff.left === 0) {
stopScrolling();
} else {
startScrolling();
}
}
});
}
module.exports = function (element) {
var i = instances.get(element);
bindSelectionHandler(element, i);
};
},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],16:[function(require,module,exports){
'use strict';
var _ = require('../../lib/helper');
var instances = require('../instances');
var updateGeometry = require('../update-geometry');
var updateScroll = require('../update-scroll');
function bindTouchHandler(element, i, supportsTouch, supportsIePointer) {
function shouldPreventDefault(deltaX, deltaY) {
var scrollTop = element.scrollTop;
var scrollLeft = element.scrollLeft;
var magnitudeX = Math.abs(deltaX);
var magnitudeY = Math.abs(deltaY);
if (magnitudeY > magnitudeX) {
// user is perhaps trying to swipe up/down the page
if (((deltaY < 0) && (scrollTop === i.contentHeight - i.containerHeight)) ||
((deltaY > 0) && (scrollTop === 0))) {
return !i.settings.swipePropagation;
}
} else if (magnitudeX > magnitudeY) {
// user is perhaps trying to swipe left/right across the page
if (((deltaX < 0) && (scrollLeft === i.contentWidth - i.containerWidth)) ||
((deltaX > 0) && (scrollLeft === 0))) {
return !i.settings.swipePropagation;
}
}
return true;
}
function applyTouchMove(differenceX, differenceY) {
updateScroll(element, 'top', element.scrollTop - differenceY);
updateScroll(element, 'left', element.scrollLeft - differenceX);
updateGeometry(element);
}
var startOffset = {};
var startTime = 0;
var speed = {};
var easingLoop = null;
var inGlobalTouch = false;
var inLocalTouch = false;
function globalTouchStart() {
inGlobalTouch = true;
}
function globalTouchEnd() {
inGlobalTouch = false;
}
function getTouch(e) {
if (e.targetTouches) {
return e.targetTouches[0];
} else {
// Maybe IE pointer
return e;
}
}
function shouldHandle(e) {
if (e.targetTouches && e.targetTouches.length === 1) {
return true;
}
if (e.pointerType && e.pointerType !== 'mouse' && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
return true;
}
return false;
}
function touchStart(e) {
if (shouldHandle(e)) {
inLocalTouch = true;
var touch = getTouch(e);
startOffset.pageX = touch.pageX;
startOffset.pageY = touch.pageY;
startTime = (new Date()).getTime();
if (easingLoop !== null) {
clearInterval(easingLoop);
}
e.stopPropagation();
}
}
function touchMove(e) {
if (!inLocalTouch && i.settings.swipePropagation) {
touchStart(e);
}
if (!inGlobalTouch && inLocalTouch && shouldHandle(e)) {
var touch = getTouch(e);
var currentOffset = {pageX: touch.pageX, pageY: touch.pageY};
var differenceX = currentOffset.pageX - startOffset.pageX;
var differenceY = currentOffset.pageY - startOffset.pageY;
applyTouchMove(differenceX, differenceY);
startOffset = currentOffset;
var currentTime = (new Date()).getTime();
var timeGap = currentTime - startTime;
if (timeGap > 0) {
speed.x = differenceX / timeGap;
speed.y = differenceY / timeGap;
startTime = currentTime;
}
if (shouldPreventDefault(differenceX, differenceY)) {
e.stopPropagation();
e.preventDefault();
}
}
}
function touchEnd() {
if (!inGlobalTouch && inLocalTouch) {
inLocalTouch = false;
if (i.settings.swipeEasing) {
clearInterval(easingLoop);
easingLoop = setInterval(function () {
if (!instances.get(element)) {
clearInterval(easingLoop);
return;
}
if (!speed.x && !speed.y) {
clearInterval(easingLoop);
return;
}
if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {
clearInterval(easingLoop);
return;
}
applyTouchMove(speed.x * 30, speed.y * 30);
speed.x *= 0.8;
speed.y *= 0.8;
}, 10);
}
}
}
if (supportsTouch) {
i.event.bind(window, 'touchstart', globalTouchStart);
i.event.bind(window, 'touchend', globalTouchEnd);
i.event.bind(element, 'touchstart', touchStart);
i.event.bind(element, 'touchmove', touchMove);
i.event.bind(element, 'touchend', touchEnd);
} else if (supportsIePointer) {
if (window.PointerEvent) {
i.event.bind(window, 'pointerdown', globalTouchStart);
i.event.bind(window, 'pointerup', globalTouchEnd);
i.event.bind(element, 'pointerdown', touchStart);
i.event.bind(element, 'pointermove', touchMove);
i.event.bind(element, 'pointerup', touchEnd);
} else if (window.MSPointerEvent) {
i.event.bind(window, 'MSPointerDown', globalTouchStart);
i.event.bind(window, 'MSPointerUp', globalTouchEnd);
i.event.bind(element, 'MSPointerDown', touchStart);
i.event.bind(element, 'MSPointerMove', touchMove);
i.event.bind(element, 'MSPointerUp', touchEnd);
}
}
}
module.exports = function (element) {
if (!_.env.supportsTouch && !_.env.supportsIePointer) {
return;
}
var i = instances.get(element);
bindTouchHandler(element, i, _.env.supportsTouch, _.env.supportsIePointer);
};
},{"../../lib/helper":6,"../instances":18,"../update-geometry":19,"../update-scroll":20}],17:[function(require,module,exports){
'use strict';
var _ = require('../lib/helper');
var cls = require('../lib/class');
var instances = require('./instances');
var updateGeometry = require('./update-geometry');
// Handlers
var handlers = {
'click-rail': require('./handler/click-rail'),
'drag-scrollbar': require('./handler/drag-scrollbar'),
'keyboard': require('./handler/keyboard'),
'wheel': require('./handler/mouse-wheel'),
'touch': require('./handler/touch'),
'selection': require('./handler/selection')
};
var nativeScrollHandler = require('./handler/native-scroll');
module.exports = function (element, userSettings) {
userSettings = typeof userSettings === 'object' ? userSettings : {};
cls.add(element, 'ps');
// Create a plugin instance.
var i = instances.add(element);
i.settings = _.extend(i.settings, userSettings);
cls.add(element, 'ps--theme_' + i.settings.theme);
i.settings.handlers.forEach(function (handlerName) {
handlers[handlerName](element);
});
nativeScrollHandler(element);
updateGeometry(element);
};
},{"../lib/class":2,"../lib/helper":6,"./handler/click-rail":10,"./handler/drag-scrollbar":11,"./handler/keyboard":12,"./handler/mouse-wheel":13,"./handler/native-scroll":14,"./handler/selection":15,"./handler/touch":16,"./instances":18,"./update-geometry":19}],18:[function(require,module,exports){
'use strict';
var _ = require('../lib/helper');
var cls = require('../lib/class');
var defaultSettings = require('./default-setting');
var dom = require('../lib/dom');
var EventManager = require('../lib/event-manager');
var guid = require('../lib/guid');
var instances = {};
function Instance(element) {
var i = this;
i.settings = _.clone(defaultSettings);
i.containerWidth = null;
i.containerHeight = null;
i.contentWidth = null;
i.contentHeight = null;
i.isRtl = dom.css(element, 'direction') === "rtl";
i.isNegativeScroll = (function () {
var originalScrollLeft = element.scrollLeft;
var result = null;
element.scrollLeft = -1;
result = element.scrollLeft < 0;
element.scrollLeft = originalScrollLeft;
return result;
})();
i.negativeScrollAdjustment = i.isNegativeScroll ? element.scrollWidth - element.clientWidth : 0;
i.event = new EventManager();
i.ownerDocument = element.ownerDocument || document;
function focus() {
cls.add(element, 'ps--focus');
}
function blur() {
cls.remove(element, 'ps--focus');
}
i.scrollbarXRail = dom.appendTo(dom.e('div', 'ps__scrollbar-x-rail'), element);
i.scrollbarX = dom.appendTo(dom.e('div', 'ps__scrollbar-x'), i.scrollbarXRail);
i.scrollbarX.setAttribute('tabindex', 0);
i.event.bind(i.scrollbarX, 'focus', focus);
i.event.bind(i.scrollbarX, 'blur', blur);
i.scrollbarXActive = null;
i.scrollbarXWidth = null;
i.scrollbarXLeft = null;
i.scrollbarXBottom = _.toInt(dom.css(i.scrollbarXRail, 'bottom'));
i.isScrollbarXUsingBottom = i.scrollbarXBottom === i.scrollbarXBottom; // !isNaN
i.scrollbarXTop = i.isScrollbarXUsingBottom ? null : _.toInt(dom.css(i.scrollbarXRail, 'top'));
i.railBorderXWidth = _.toInt(dom.css(i.scrollbarXRail, 'borderLeftWidth')) + _.toInt(dom.css(i.scrollbarXRail, 'borderRightWidth'));
// Set rail to display:block to calculate margins
dom.css(i.scrollbarXRail, 'display', 'block');
i.railXMarginWidth = _.toInt(dom.css(i.scrollbarXRail, 'marginLeft')) + _.toInt(dom.css(i.scrollbarXRail, 'marginRight'));
dom.css(i.scrollbarXRail, 'display', '');
i.railXWidth = null;
i.railXRatio = null;
i.scrollbarYRail = dom.appendTo(dom.e('div', 'ps__scrollbar-y-rail'), element);
i.scrollbarY = dom.appendTo(dom.e('div', 'ps__scrollbar-y'), i.scrollbarYRail);
i.scrollbarY.setAttribute('tabindex', 0);
i.event.bind(i.scrollbarY, 'focus', focus);
i.event.bind(i.scrollbarY, 'blur', blur);
i.scrollbarYActive = null;
i.scrollbarYHeight = null;
i.scrollbarYTop = null;
i.scrollbarYRight = _.toInt(dom.css(i.scrollbarYRail, 'right'));
i.isScrollbarYUsingRight = i.scrollbarYRight === i.scrollbarYRight; // !isNaN
i.scrollbarYLeft = i.isScrollbarYUsingRight ? null : _.toInt(dom.css(i.scrollbarYRail, 'left'));
i.scrollbarYOuterWidth = i.isRtl ? _.outerWidth(i.scrollbarY) : null;
i.railBorderYWidth = _.toInt(dom.css(i.scrollbarYRail, 'borderTopWidth')) + _.toInt(dom.css(i.scrollbarYRail, 'borderBottomWidth'));
dom.css(i.scrollbarYRail, 'display', 'block');
i.railYMarginHeight = _.toInt(dom.css(i.scrollbarYRail, 'marginTop')) + _.toInt(dom.css(i.scrollbarYRail, 'marginBottom'));
dom.css(i.scrollbarYRail, 'display', '');
i.railYHeight = null;
i.railYRatio = null;
}
function getId(element) {
return element.getAttribute('data-ps-id');
}
function setId(element, id) {
element.setAttribute('data-ps-id', id);
}
function removeId(element) {
element.removeAttribute('data-ps-id');
}
exports.add = function (element) {
var newId = guid();
setId(element, newId);
instances[newId] = new Instance(element);
return instances[newId];
};
exports.remove = function (element) {
delete instances[getId(element)];
removeId(element);
};
exports.get = function (element) {
return instances[getId(element)];
};
},{"../lib/class":2,"../lib/dom":3,"../lib/event-manager":4,"../lib/guid":5,"../lib/helper":6,"./default-setting":8}],19:[function(require,module,exports){
'use strict';
var _ = require('../lib/helper');
var cls = require('../lib/class');
var dom = require('../lib/dom');
var instances = require('./instances');
var updateScroll = require('./update-scroll');
function getThumbSize(i, thumbSize) {
if (i.settings.minScrollbarLength) {
thumbSize = Math.max(thumbSize, i.settings.minScrollbarLength);
}
if (i.settings.maxScrollbarLength) {
thumbSize = Math.min(thumbSize, i.settings.maxScrollbarLength);
}
return thumbSize;
}
function updateCss(element, i) {
var xRailOffset = {width: i.railXWidth};
if (i.isRtl) {
xRailOffset.left = i.negativeScrollAdjustment + element.scrollLeft + i.containerWidth - i.contentWidth;
} else {
xRailOffset.left = element.scrollLeft;
}
if (i.isScrollbarXUsingBottom) {
xRailOffset.bottom = i.scrollbarXBottom - element.scrollTop;
} else {
xRailOffset.top = i.scrollbarXTop + element.scrollTop;
}
dom.css(i.scrollbarXRail, xRailOffset);
var yRailOffset = {top: element.scrollTop, height: i.railYHeight};
if (i.isScrollbarYUsingRight) {
if (i.isRtl) {
yRailOffset.right = i.contentWidth - (i.negativeScrollAdjustment + element.scrollLeft) - i.scrollbarYRight - i.scrollbarYOuterWidth;
} else {
yRailOffset.right = i.scrollbarYRight - element.scrollLeft;
}
} else {
if (i.isRtl) {
yRailOffset.left = i.negativeScrollAdjustment + element.scrollLeft + i.containerWidth * 2 - i.contentWidth - i.scrollbarYLeft - i.scrollbarYOuterWidth;
} else {
yRailOffset.left = i.scrollbarYLeft + element.scrollLeft;
}
}
dom.css(i.scrollbarYRail, yRailOffset);
dom.css(i.scrollbarX, {left: i.scrollbarXLeft, width: i.scrollbarXWidth - i.railBorderXWidth});
dom.css(i.scrollbarY, {top: i.scrollbarYTop, height: i.scrollbarYHeight - i.railBorderYWidth});
}
module.exports = function (element) {
var i = instances.get(element);
i.containerWidth = element.clientWidth;
i.containerHeight = element.clientHeight;
i.contentWidth = element.scrollWidth;
i.contentHeight = element.scrollHeight;
var existingRails;
if (!element.contains(i.scrollbarXRail)) {
existingRails = dom.queryChildren(element, '.ps__scrollbar-x-rail');
if (existingRails.length > 0) {
existingRails.forEach(function (rail) {
dom.remove(rail);
});
}
dom.appendTo(i.scrollbarXRail, element);
}
if (!element.contains(i.scrollbarYRail)) {
existingRails = dom.queryChildren(element, '.ps__scrollbar-y-rail');
if (existingRails.length > 0) {
existingRails.forEach(function (rail) {
dom.remove(rail);
});
}
dom.appendTo(i.scrollbarYRail, element);
}
if (!i.settings.suppressScrollX && i.containerWidth + i.settings.scrollXMarginOffset < i.contentWidth) {
i.scrollbarXActive = true;
i.railXWidth = i.containerWidth - i.railXMarginWidth;
i.railXRatio = i.containerWidth / i.railXWidth;
i.scrollbarXWidth = getThumbSize(i, _.toInt(i.railXWidth * i.containerWidth / i.contentWidth));
i.scrollbarXLeft = _.toInt((i.negativeScrollAdjustment + element.scrollLeft) * (i.railXWidth - i.scrollbarXWidth) / (i.contentWidth - i.containerWidth));
} else {
i.scrollbarXActive = false;
}
if (!i.settings.suppressScrollY && i.containerHeight + i.settings.scrollYMarginOffset < i.contentHeight) {
i.scrollbarYActive = true;
i.railYHeight = i.containerHeight - i.railYMarginHeight;
i.railYRatio = i.containerHeight / i.railYHeight;
i.scrollbarYHeight = getThumbSize(i, _.toInt(i.railYHeight * i.containerHeight / i.contentHeight));
i.scrollbarYTop = _.toInt(element.scrollTop * (i.railYHeight - i.scrollbarYHeight) / (i.contentHeight - i.containerHeight));
} else {
i.scrollbarYActive = false;
}
if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) {
i.scrollbarXLeft = i.railXWidth - i.scrollbarXWidth;
}
if (i.scrollbarYTop >= i.railYHeight - i.scrollbarYHeight) {
i.scrollbarYTop = i.railYHeight - i.scrollbarYHeight;
}
updateCss(element, i);
if (i.scrollbarXActive) {
cls.add(element, 'ps--active-x');
} else {
cls.remove(element, 'ps--active-x');
i.scrollbarXWidth = 0;
i.scrollbarXLeft = 0;
updateScroll(element, 'left', 0);
}
if (i.scrollbarYActive) {
cls.add(element, 'ps--active-y');
} else {
cls.remove(element, 'ps--active-y');
i.scrollbarYHeight = 0;
i.scrollbarYTop = 0;
updateScroll(element, 'top', 0);
}
};
},{"../lib/class":2,"../lib/dom":3,"../lib/helper":6,"./instances":18,"./update-scroll":20}],20:[function(require,module,exports){
'use strict';
var instances = require('./instances');
var createDOMEvent = function (name) {
var event = document.createEvent("Event");
event.initEvent(name, true, true);
return event;
};
module.exports = function (element, axis, value) {
if (typeof element === 'undefined') {
throw 'You must provide an element to the update-scroll function';
}
if (typeof axis === 'undefined') {
throw 'You must provide an axis to the update-scroll function';
}
if (typeof value === 'undefined') {
throw 'You must provide a value to the update-scroll function';
}
if (axis === 'top' && value <= 0) {
element.scrollTop = value = 0; // don't allow negative scroll
element.dispatchEvent(createDOMEvent('ps-y-reach-start'));
}
if (axis === 'left' && value <= 0) {
element.scrollLeft = value = 0; // don't allow negative scroll
element.dispatchEvent(createDOMEvent('ps-x-reach-start'));
}
var i = instances.get(element);
if (axis === 'top' && value >= i.contentHeight - i.containerHeight) {
// don't allow scroll past container
value = i.contentHeight - i.containerHeight;
if (value - element.scrollTop <= 1) {
// mitigates rounding errors on non-subpixel scroll values
value = element.scrollTop;
} else {
element.scrollTop = value;
}
element.dispatchEvent(createDOMEvent('ps-y-reach-end'));
}
if (axis === 'left' && value >= i.contentWidth - i.containerWidth) {
// don't allow scroll past container
value = i.contentWidth - i.containerWidth;
if (value - element.scrollLeft <= 1) {
// mitigates rounding errors on non-subpixel scroll values
value = element.scrollLeft;
} else {
element.scrollLeft = value;
}
element.dispatchEvent(createDOMEvent('ps-x-reach-end'));
}
if (i.lastTop === undefined) {
i.lastTop = element.scrollTop;
}
if (i.lastLeft === undefined) {
i.lastLeft = element.scrollLeft;
}
if (axis === 'top' && value < i.lastTop) {
element.dispatchEvent(createDOMEvent('ps-scroll-up'));
}
if (axis === 'top' && value > i.lastTop) {
element.dispatchEvent(createDOMEvent('ps-scroll-down'));
}
if (axis === 'left' && value < i.lastLeft) {
element.dispatchEvent(createDOMEvent('ps-scroll-left'));
}
if (axis === 'left' && value > i.lastLeft) {
element.dispatchEvent(createDOMEvent('ps-scroll-right'));
}
if (axis === 'top' && value !== i.lastTop) {
element.scrollTop = i.lastTop = value;
element.dispatchEvent(createDOMEvent('ps-scroll-y'));
}
if (axis === 'left' && value !== i.lastLeft) {
element.scrollLeft = i.lastLeft = value;
element.dispatchEvent(createDOMEvent('ps-scroll-x'));
}
};
},{"./instances":18}],21:[function(require,module,exports){
'use strict';
var _ = require('../lib/helper');
var dom = require('../lib/dom');
var instances = require('./instances');
var updateGeometry = require('./update-geometry');
var updateScroll = require('./update-scroll');
module.exports = function (element) {
var i = instances.get(element);
if (!i) {
return;
}
// Recalcuate negative scrollLeft adjustment
i.negativeScrollAdjustment = i.isNegativeScroll ? element.scrollWidth - element.clientWidth : 0;
// Recalculate rail margins
dom.css(i.scrollbarXRail, 'display', 'block');
dom.css(i.scrollbarYRail, 'display', 'block');
i.railXMarginWidth = _.toInt(dom.css(i.scrollbarXRail, 'marginLeft')) + _.toInt(dom.css(i.scrollbarXRail, 'marginRight'));
i.railYMarginHeight = _.toInt(dom.css(i.scrollbarYRail, 'marginTop')) + _.toInt(dom.css(i.scrollbarYRail, 'marginBottom'));
// Hide scrollbars not to affect scrollWidth and scrollHeight
dom.css(i.scrollbarXRail, 'display', 'none');
dom.css(i.scrollbarYRail, 'display', 'none');
updateGeometry(element);
// Update top/left scroll to trigger events
updateScroll(element, 'top', element.scrollTop);
updateScroll(element, 'left', element.scrollLeft);
dom.css(i.scrollbarXRail, 'display', '');
dom.css(i.scrollbarYRail, 'display', '');
};
},{"../lib/dom":3,"../lib/helper":6,"./instances":18,"./update-geometry":19,"./update-scroll":20}]},{},[1]);
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
// This is CodeMirror (https://codemirror.net), a code editor
// implemented in JavaScript on top of the browser's DOM.
//
// You can find some technical background for some of the code below
// at http://marijnhaverbeke.nl/blog/#cm-internals .
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
typeof define === 'function' && define.amd ? define(factory) :
(global.CodeMirror = factory());
}(this, (function () { 'use strict';
// Kludges for bugs and behavior differences that can't be feature
// detected are enabled based on userAgent etc sniffing.
var userAgent = navigator.userAgent;
var platform = navigator.platform;
var gecko = /gecko\/\d/i.test(userAgent);
var ie_upto10 = /MSIE \d/.test(userAgent);
var ie_11up = /Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(userAgent);
var edge = /Edge\/(\d+)/.exec(userAgent);
var ie = ie_upto10 || ie_11up || edge;
var ie_version = ie && (ie_upto10 ? document.documentMode || 6 : +(edge || ie_11up)[1]);
var webkit = !edge && /WebKit\//.test(userAgent);
var qtwebkit = webkit && /Qt\/\d+\.\d+/.test(userAgent);
var chrome = !edge && /Chrome\//.test(userAgent);
var presto = /Opera\//.test(userAgent);
var safari = /Apple Computer/.test(navigator.vendor);
var mac_geMountainLion = /Mac OS X 1\d\D([8-9]|\d\d)\D/.test(userAgent);
var phantom = /PhantomJS/.test(userAgent);
var ios = !edge && /AppleWebKit/.test(userAgent) && /Mobile\/\w+/.test(userAgent);
var android = /Android/.test(userAgent);
// This is woefully incomplete. Suggestions for alternative methods welcome.
var mobile = ios || android || /webOS|BlackBerry|Opera Mini|Opera Mobi|IEMobile/i.test(userAgent);
var mac = ios || /Mac/.test(platform);
var chromeOS = /\bCrOS\b/.test(userAgent);
var windows = /win/i.test(platform);
var presto_version = presto && userAgent.match(/Version\/(\d*\.\d*)/);
if (presto_version) { presto_version = Number(presto_version[1]); }
if (presto_version && presto_version >= 15) { presto = false; webkit = true; }
// Some browsers use the wrong event properties to signal cmd/ctrl on OS X
var flipCtrlCmd = mac && (qtwebkit || presto && (presto_version == null || presto_version < 12.11));
var captureRightClick = gecko || (ie && ie_version >= 9);
function classTest(cls) { return new RegExp("(^|\\s)" + cls + "(?:$|\\s)\\s*") }
var rmClass = function(node, cls) {
var current = node.className;
var match = classTest(cls).exec(current);
if (match) {
var after = current.slice(match.index + match[0].length);
node.className = current.slice(0, match.index) + (after ? match[1] + after : "");
}
};
function removeChildren(e) {
for (var count = e.childNodes.length; count > 0; --count)
{ e.removeChild(e.firstChild); }
return e
}
function removeChildrenAndAdd(parent, e) {
return removeChildren(parent).appendChild(e)
}
function elt(tag, content, className, style) {
var e = document.createElement(tag);
if (className) { e.className = className; }
if (style) { e.style.cssText = style; }
if (typeof content == "string") { e.appendChild(document.createTextNode(content)); }
else if (content) { for (var i = 0; i < content.length; ++i) { e.appendChild(content[i]); } }
return e
}
// wrapper for elt, which removes the elt from the accessibility tree
function eltP(tag, content, className, style) {
var e = elt(tag, content, className, style);
e.setAttribute("role", "presentation");
return e
}
var range;
if (document.createRange) { range = function(node, start, end, endNode) {
var r = document.createRange();
r.setEnd(endNode || node, end);
r.setStart(node, start);
return r
}; }
else { range = function(node, start, end) {
var r = document.body.createTextRange();
try { r.moveToElementText(node.parentNode); }
catch(e) { return r }
r.collapse(true);
r.moveEnd("character", end);
r.moveStart("character", start);
return r
}; }
function contains(parent, child) {
if (child.nodeType == 3) // Android browser always returns false when child is a textnode
{ child = child.parentNode; }
if (parent.contains)
{ return parent.contains(child) }
do {
if (child.nodeType == 11) { child = child.host; }
if (child == parent) { return true }
} while (child = child.parentNode)
}
function activeElt() {
// IE and Edge may throw an "Unspecified Error" when accessing document.activeElement.
// IE < 10 will throw when accessed while the page is loading or in an iframe.
// IE > 9 and Edge will throw when accessed in an iframe if document.body is unavailable.
var activeElement;
try {
activeElement = document.activeElement;
} catch(e) {
activeElement = document.body || null;
}
while (activeElement && activeElement.shadowRoot && activeElement.shadowRoot.activeElement)
{ activeElement = activeElement.shadowRoot.activeElement; }
return activeElement
}
function addClass(node, cls) {
var current = node.className;
if (!classTest(cls).test(current)) { node.className += (current ? " " : "") + cls; }
}
function joinClasses(a, b) {
var as = a.split(" ");
for (var i = 0; i < as.length; i++)
{ if (as[i] && !classTest(as[i]).test(b)) { b += " " + as[i]; } }
return b
}
var selectInput = function(node) { node.select(); };
if (ios) // Mobile Safari apparently has a bug where select() is broken.
{ selectInput = function(node) { node.selectionStart = 0; node.selectionEnd = node.value.length; }; }
else if (ie) // Suppress mysterious IE10 errors
{ selectInput = function(node) { try { node.select(); } catch(_e) {} }; }
function bind(f) {
var args = Array.prototype.slice.call(arguments, 1);
return function(){return f.apply(null, args)}
}
function copyObj(obj, target, overwrite) {
if (!target) { target = {}; }
for (var prop in obj)
{ if (obj.hasOwnProperty(prop) && (overwrite !== false || !target.hasOwnProperty(prop)))
{ target[prop] = obj[prop]; } }
return target
}
// Counts the column offset in a string, taking tabs into account.
// Used mostly to find indentation.
function countColumn(string, end, tabSize, startIndex, startValue) {
if (end == null) {
end = string.search(/[^\s\u00a0]/);
if (end == -1) { end = string.length; }
}
for (var i = startIndex || 0, n = startValue || 0;;) {
var nextTab = string.indexOf("\t", i);
if (nextTab < 0 || nextTab >= end)
{ return n + (end - i) }
n += nextTab - i;
n += tabSize - (n % tabSize);
i = nextTab + 1;
}
}
var Delayed = function() {this.id = null;};
Delayed.prototype.set = function (ms, f) {
clearTimeout(this.id);
this.id = setTimeout(f, ms);
};
function indexOf(array, elt) {
for (var i = 0; i < array.length; ++i)
{ if (array[i] == elt) { return i } }
return -1
}
// Number of pixels added to scroller and sizer to hide scrollbar
var scrollerGap = 30;
// Returned or thrown by various protocols to signal 'I'm not
// handling this'.
var Pass = {toString: function(){return "CodeMirror.Pass"}};
// Reused option objects for setSelection & friends
var sel_dontScroll = {scroll: false}, sel_mouse = {origin: "*mouse"}, sel_move = {origin: "+move"};
// The inverse of countColumn -- find the offset that corresponds to
// a particular column.
function findColumn(string, goal, tabSize) {
for (var pos = 0, col = 0;;) {
var nextTab = string.indexOf("\t", pos);
if (nextTab == -1) { nextTab = string.length; }
var skipped = nextTab - pos;
if (nextTab == string.length || col + skipped >= goal)
{ return pos + Math.min(skipped, goal - col) }
col += nextTab - pos;
col += tabSize - (col % tabSize);
pos = nextTab + 1;
if (col >= goal) { return pos }
}
}
var spaceStrs = [""];
function spaceStr(n) {
while (spaceStrs.length <= n)
{ spaceStrs.push(lst(spaceStrs) + " "); }
return spaceStrs[n]
}
function lst(arr) { return arr[arr.length-1] }
function map(array, f) {
var out = [];
for (var i = 0; i < array.length; i++) { out[i] = f(array[i], i); }
return out
}
function insertSorted(array, value, score) {
var pos = 0, priority = score(value);
while (pos < array.length && score(array[pos]) <= priority) { pos++; }
array.splice(pos, 0, value);
}
function nothing() {}
function createObj(base, props) {
var inst;
if (Object.create) {
inst = Object.create(base);
} else {
nothing.prototype = base;
inst = new nothing();
}
if (props) { copyObj(props, inst); }
return inst
}
var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;
function isWordCharBasic(ch) {
return /\w/.test(ch) || ch > "\x80" &&
(ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))
}
function isWordChar(ch, helper) {
if (!helper) { return isWordCharBasic(ch) }
if (helper.source.indexOf("\\w") > -1 && isWordCharBasic(ch)) { return true }
return helper.test(ch)
}
function isEmpty(obj) {
for (var n in obj) { if (obj.hasOwnProperty(n) && obj[n]) { return false } }
return true
}
// Extending unicode characters. A series of a non-extending char +
// any number of extending chars is treated as a single unit as far
// as editing and measuring is concerned. This is not fully correct,
// since some scripts/fonts/browsers also treat other configurations
// of code points as a group.
var extendingChars = /[\u0300-\u036f\u0483-\u0489\u0591-\u05bd\u05bf\u05c1\u05c2\u05c4\u05c5\u05c7\u0610-\u061a\u064b-\u065e\u0670\u06d6-\u06dc\u06de-\u06e4\u06e7\u06e8\u06ea-\u06ed\u0711\u0730-\u074a\u07a6-\u07b0\u07eb-\u07f3\u0816-\u0819\u081b-\u0823\u0825-\u0827\u0829-\u082d\u0900-\u0902\u093c\u0941-\u0948\u094d\u0951-\u0955\u0962\u0963\u0981\u09bc\u09be\u09c1-\u09c4\u09cd\u09d7\u09e2\u09e3\u0a01\u0a02\u0a3c\u0a41\u0a42\u0a47\u0a48\u0a4b-\u0a4d\u0a51\u0a70\u0a71\u0a75\u0a81\u0a82\u0abc\u0ac1-\u0ac5\u0ac7\u0ac8\u0acd\u0ae2\u0ae3\u0b01\u0b3c\u0b3e\u0b3f\u0b41-\u0b44\u0b4d\u0b56\u0b57\u0b62\u0b63\u0b82\u0bbe\u0bc0\u0bcd\u0bd7\u0c3e-\u0c40\u0c46-\u0c48\u0c4a-\u0c4d\u0c55\u0c56\u0c62\u0c63\u0cbc\u0cbf\u0cc2\u0cc6\u0ccc\u0ccd\u0cd5\u0cd6\u0ce2\u0ce3\u0d3e\u0d41-\u0d44\u0d4d\u0d57\u0d62\u0d63\u0dca\u0dcf\u0dd2-\u0dd4\u0dd6\u0ddf\u0e31\u0e34-\u0e3a\u0e47-\u0e4e\u0eb1\u0eb4-\u0eb9\u0ebb\u0ebc\u0ec8-\u0ecd\u0f18\u0f19\u0f35\u0f37\u0f39\u0f71-\u0f7e\u0f80-\u0f84\u0f86\u0f87\u0f90-\u0f97\u0f99-\u0fbc\u0fc6\u102d-\u1030\u1032-\u1037\u1039\u103a\u103d\u103e\u1058\u1059\u105e-\u1060\u1071-\u1074\u1082\u1085\u1086\u108d\u109d\u135f\u1712-\u1714\u1732-\u1734\u1752\u1753\u1772\u1773\u17b7-\u17bd\u17c6\u17c9-\u17d3\u17dd\u180b-\u180d\u18a9\u1920-\u1922\u1927\u1928\u1932\u1939-\u193b\u1a17\u1a18\u1a56\u1a58-\u1a5e\u1a60\u1a62\u1a65-\u1a6c\u1a73-\u1a7c\u1a7f\u1b00-\u1b03\u1b34\u1b36-\u1b3a\u1b3c\u1b42\u1b6b-\u1b73\u1b80\u1b81\u1ba2-\u1ba5\u1ba8\u1ba9\u1c2c-\u1c33\u1c36\u1c37\u1cd0-\u1cd2\u1cd4-\u1ce0\u1ce2-\u1ce8\u1ced\u1dc0-\u1de6\u1dfd-\u1dff\u200c\u200d\u20d0-\u20f0\u2cef-\u2cf1\u2de0-\u2dff\u302a-\u302f\u3099\u309a\ua66f-\ua672\ua67c\ua67d\ua6f0\ua6f1\ua802\ua806\ua80b\ua825\ua826\ua8c4\ua8e0-\ua8f1\ua926-\ua92d\ua947-\ua951\ua980-\ua982\ua9b3\ua9b6-\ua9b9\ua9bc\uaa29-\uaa2e\uaa31\uaa32\uaa35\uaa36\uaa43\uaa4c\uaab0\uaab2-\uaab4\uaab7\uaab8\uaabe\uaabf\uaac1\uabe5\uabe8\uabed\udc00-\udfff\ufb1e\ufe00-\ufe0f\ufe20-\ufe26\uff9e\uff9f]/;
function isExtendingChar(ch) { return ch.charCodeAt(0) >= 768 && extendingChars.test(ch) }
// Returns a number from the range [`0`; `str.length`] unless `pos` is outside that range.
function skipExtendingChars(str, pos, dir) {
while ((dir < 0 ? pos > 0 : pos < str.length) && isExtendingChar(str.charAt(pos))) { pos += dir; }
return pos
}
// Returns the value from the range [`from`; `to`] that satisfies
// `pred` and is closest to `from`. Assumes that at least `to`
// satisfies `pred`. Supports `from` being greater than `to`.
function findFirst(pred, from, to) {
// At any point we are certain `to` satisfies `pred`, don't know
// whether `from` does.
var dir = from > to ? -1 : 1;
for (;;) {
if (from == to) { return from }
var midF = (from + to) / 2, mid = dir < 0 ? Math.ceil(midF) : Math.floor(midF);
if (mid == from) { return pred(mid) ? from : to }
if (pred(mid)) { to = mid; }
else { from = mid + dir; }
}
}
// The display handles the DOM integration, both for input reading
// and content drawing. It holds references to DOM nodes and
// display-related state.
function Display(place, doc, input) {
var d = this;
this.input = input;
// Covers bottom-right square when both scrollbars are present.
d.scrollbarFiller = elt("div", null, "CodeMirror-scrollbar-filler");
d.scrollbarFiller.setAttribute("cm-not-content", "true");
// Covers bottom of gutter when coverGutterNextToScrollbar is on
// and h scrollbar is present.
d.gutterFiller = elt("div", null, "CodeMirror-gutter-filler");
d.gutterFiller.setAttribute("cm-not-content", "true");
// Will contain the actual code, positioned to cover the viewport.
d.lineDiv = eltP("div", null, "CodeMirror-code");
// Elements are added to these to represent selection and cursors.
d.selectionDiv = elt("div", null, null, "position: relative; z-index: 1");
d.cursorDiv = elt("div", null, "CodeMirror-cursors");
// A visibility: hidden element used to find the size of things.
d.measure = elt("div", null, "CodeMirror-measure");
// When lines outside of the viewport are measured, they are drawn in this.
d.lineMeasure = elt("div", null, "CodeMirror-measure");
// Wraps everything that needs to exist inside the vertically-padded coordinate system
d.lineSpace = eltP("div", [d.measure, d.lineMeasure, d.selectionDiv, d.cursorDiv, d.lineDiv],
null, "position: relative; outline: none");
var lines = eltP("div", [d.lineSpace], "CodeMirror-lines");
// Moved around its parent to cover visible view.
d.mover = elt("div", [lines], null, "position: relative");
// Set to the height of the document, allowing scrolling.
d.sizer = elt("div", [d.mover], "CodeMirror-sizer");
d.sizerWidth = null;
// Behavior of elts with overflow: auto and padding is
// inconsistent across browsers. This is used to ensure the
// scrollable area is big enough.
d.heightForcer = elt("div", null, null, "position: absolute; height: " + scrollerGap + "px; width: 1px;");
// Will contain the gutters, if any.
d.gutters = elt("div", null, "CodeMirror-gutters");
d.lineGutter = null;
// Actual scrollable element.
d.scroller = elt("div", [d.sizer, d.heightForcer, d.gutters], "CodeMirror-scroll");
d.scroller.setAttribute("tabIndex", "-1");
// The element in which the editor lives.
d.wrapper = elt("div", [d.scrollbarFiller, d.gutterFiller, d.scroller], "CodeMirror");
// Work around IE7 z-index bug (not perfect, hence IE7 not really being supported)
if (ie && ie_version < 8) { d.gutters.style.zIndex = -1; d.scroller.style.paddingRight = 0; }
if (!webkit && !(gecko && mobile)) { d.scroller.draggable = true; }
if (place) {
if (place.appendChild) { place.appendChild(d.wrapper); }
else { place(d.wrapper); }
}
// Current rendered range (may be bigger than the view window).
d.viewFrom = d.viewTo = doc.first;
d.reportedViewFrom = d.reportedViewTo = doc.first;
// Information about the rendered lines.
d.view = [];
d.renderedView = null;
// Holds info about a single rendered line when it was rendered
// for measurement, while not in view.
d.externalMeasured = null;
// Empty space (in pixels) above the view
d.viewOffset = 0;
d.lastWrapHeight = d.lastWrapWidth = 0;
d.updateLineNumbers = null;
d.nativeBarWidth = d.barHeight = d.barWidth = 0;
d.scrollbarsClipped = false;
// Used to only resize the line number gutter when necessary (when
// the amount of lines crosses a boundary that makes its width change)
d.lineNumWidth = d.lineNumInnerWidth = d.lineNumChars = null;
// Set to true when a non-horizontal-scrolling line widget is
// added. As an optimization, line widget aligning is skipped when
// this is false.
d.alignWidgets = false;
d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
// Tracks the maximum line length so that the horizontal scrollbar
// can be kept static when scrolling.
d.maxLine = null;
d.maxLineLength = 0;
d.maxLineChanged = false;
// Used for measuring wheel scrolling granularity
d.wheelDX = d.wheelDY = d.wheelStartX = d.wheelStartY = null;
// True when shift is held down.
d.shift = false;
// Used to track whether anything happened since the context menu
// was opened.
d.selForContextMenu = null;
d.activeTouch = null;
input.init(d);
}
// Find the line object corresponding to the given line number.
function getLine(doc, n) {
n -= doc.first;
if (n < 0 || n >= doc.size) { throw new Error("There is no line " + (n + doc.first) + " in the document.") }
var chunk = doc;
while (!chunk.lines) {
for (var i = 0;; ++i) {
var child = chunk.children[i], sz = child.chunkSize();
if (n < sz) { chunk = child; break }
n -= sz;
}
}
return chunk.lines[n]
}
// Get the part of a document between two positions, as an array of
// strings.
function getBetween(doc, start, end) {
var out = [], n = start.line;
doc.iter(start.line, end.line + 1, function (line) {
var text = line.text;
if (n == end.line) { text = text.slice(0, end.ch); }
if (n == start.line) { text = text.slice(start.ch); }
out.push(text);
++n;
});
return out
}
// Get the lines between from and to, as array of strings.
function getLines(doc, from, to) {
var out = [];
doc.iter(from, to, function (line) { out.push(line.text); }); // iter aborts when callback returns truthy value
return out
}
// Update the height of a line, propagating the height change
// upwards to parent nodes.
function updateLineHeight(line, height) {
var diff = height - line.height;
if (diff) { for (var n = line; n; n = n.parent) { n.height += diff; } }
}
// Given a line object, find its line number by walking up through
// its parent links.
function lineNo(line) {
if (line.parent == null) { return null }
var cur = line.parent, no = indexOf(cur.lines, line);
for (var chunk = cur.parent; chunk; cur = chunk, chunk = chunk.parent) {
for (var i = 0;; ++i) {
if (chunk.children[i] == cur) { break }
no += chunk.children[i].chunkSize();
}
}
return no + cur.first
}
// Find the line at the given vertical position, using the height
// information in the document tree.
function lineAtHeight(chunk, h) {
var n = chunk.first;
outer: do {
for (var i$1 = 0; i$1 < chunk.children.length; ++i$1) {
var child = chunk.children[i$1], ch = child.height;
if (h < ch) { chunk = child; continue outer }
h -= ch;
n += child.chunkSize();
}
return n
} while (!chunk.lines)
var i = 0;
for (; i < chunk.lines.length; ++i) {
var line = chunk.lines[i], lh = line.height;
if (h < lh) { break }
h -= lh;
}
return n + i
}
function isLine(doc, l) {return l >= doc.first && l < doc.first + doc.size}
function lineNumberFor(options, i) {
return String(options.lineNumberFormatter(i + options.firstLineNumber))
}
// A Pos instance represents a position within the text.
function Pos(line, ch, sticky) {
if ( sticky === void 0 ) sticky = null;
if (!(this instanceof Pos)) { return new Pos(line, ch, sticky) }
this.line = line;
this.ch = ch;
this.sticky = sticky;
}
// Compare two positions, return 0 if they are the same, a negative
// number when a is less, and a positive number otherwise.
function cmp(a, b) { return a.line - b.line || a.ch - b.ch }
function equalCursorPos(a, b) { return a.sticky == b.sticky && cmp(a, b) == 0 }
function copyPos(x) {return Pos(x.line, x.ch)}
function maxPos(a, b) { return cmp(a, b) < 0 ? b : a }
function minPos(a, b) { return cmp(a, b) < 0 ? a : b }
// Most of the external API clips given positions to make sure they
// actually exist within the document.
function clipLine(doc, n) {return Math.max(doc.first, Math.min(n, doc.first + doc.size - 1))}
function clipPos(doc, pos) {
if (pos.line < doc.first) { return Pos(doc.first, 0) }
var last = doc.first + doc.size - 1;
if (pos.line > last) { return Pos(last, getLine(doc, last).text.length) }
return clipToLen(pos, getLine(doc, pos.line).text.length)
}
function clipToLen(pos, linelen) {
var ch = pos.ch;
if (ch == null || ch > linelen) { return Pos(pos.line, linelen) }
else if (ch < 0) { return Pos(pos.line, 0) }
else { return pos }
}
function clipPosArray(doc, array) {
var out = [];
for (var i = 0; i < array.length; i++) { out[i] = clipPos(doc, array[i]); }
return out
}
// Optimize some code when these features are not used.
var sawReadOnlySpans = false, sawCollapsedSpans = false;
function seeReadOnlySpans() {
sawReadOnlySpans = true;
}
function seeCollapsedSpans() {
sawCollapsedSpans = true;
}
// TEXTMARKER SPANS
function MarkedSpan(marker, from, to) {
this.marker = marker;
this.from = from; this.to = to;
}
// Search an array of spans for a span matching the given marker.
function getMarkedSpanFor(spans, marker) {
if (spans) { for (var i = 0; i < spans.length; ++i) {
var span = spans[i];
if (span.marker == marker) { return span }
} }
}
// Remove a span from an array, returning undefined if no spans are
// left (we don't store arrays for lines without spans).
function removeMarkedSpan(spans, span) {
var r;
for (var i = 0; i < spans.length; ++i)
{ if (spans[i] != span) { (r || (r = [])).push(spans[i]); } }
return r
}
// Add a span to a line.
function addMarkedSpan(line, span) {
line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span];
span.marker.attachLine(line);
}
// Used for the algorithm that adjusts markers for a change in the
// document. These functions cut an array of spans at a given
// character position, returning an array of remaining chunks (or
// undefined if nothing remains).
function markedSpansBefore(old, startCh, isInsert) {
var nw;
if (old) { for (var i = 0; i < old.length; ++i) {
var span = old[i], marker = span.marker;
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= startCh : span.from < startCh);
if (startsBefore || span.from == startCh && marker.type == "bookmark" && (!isInsert || !span.marker.insertLeft)) {
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= startCh : span.to > startCh)
;(nw || (nw = [])).push(new MarkedSpan(marker, span.from, endsAfter ? null : span.to));
}
} }
return nw
}
function markedSpansAfter(old, endCh, isInsert) {
var nw;
if (old) { for (var i = 0; i < old.length; ++i) {
var span = old[i], marker = span.marker;
var endsAfter = span.to == null || (marker.inclusiveRight ? span.to >= endCh : span.to > endCh);
if (endsAfter || span.from == endCh && marker.type == "bookmark" && (!isInsert || span.marker.insertLeft)) {
var startsBefore = span.from == null || (marker.inclusiveLeft ? span.from <= endCh : span.from < endCh)
;(nw || (nw = [])).push(new MarkedSpan(marker, startsBefore ? null : span.from - endCh,
span.to == null ? null : span.to - endCh));
}
} }
return nw
}
// Given a change object, compute the new set of marker spans that
// cover the line in which the change took place. Removes spans
// entirely within the change, reconnects spans belonging to the
// same marker that appear on both sides of the change, and cuts off
// spans partially within the change. Returns an array of span
// arrays with one element for each line in (after) the change.
function stretchSpansOverChange(doc, change) {
if (change.full) { return null }
var oldFirst = isLine(doc, change.from.line) && getLine(doc, change.from.line).markedSpans;
var oldLast = isLine(doc, change.to.line) && getLine(doc, change.to.line).markedSpans;
if (!oldFirst && !oldLast) { return null }
var startCh = change.from.ch, endCh = change.to.ch, isInsert = cmp(change.from, change.to) == 0;
// Get the spans that 'stick out' on both sides
var first = markedSpansBefore(oldFirst, startCh, isInsert);
var last = markedSpansAfter(oldLast, endCh, isInsert);
// Next, merge those two ends
var sameLine = change.text.length == 1, offset = lst(change.text).length + (sameLine ? startCh : 0);
if (first) {
// Fix up .to properties of first
for (var i = 0; i < first.length; ++i) {
var span = first[i];
if (span.to == null) {
var found = getMarkedSpanFor(last, span.marker);
if (!found) { span.to = startCh; }
else if (sameLine) { span.to = found.to == null ? null : found.to + offset; }
}
}
}
if (last) {
// Fix up .from in last (or move them into first in case of sameLine)
for (var i$1 = 0; i$1 < last.length; ++i$1) {
var span$1 = last[i$1];
if (span$1.to != null) { span$1.to += offset; }
if (span$1.from == null) {
var found$1 = getMarkedSpanFor(first, span$1.marker);
if (!found$1) {
span$1.from = offset;
if (sameLine) { (first || (first = [])).push(span$1); }
}
} else {
span$1.from += offset;
if (sameLine) { (first || (first = [])).push(span$1); }
}
}
}
// Make sure we didn't create any zero-length spans
if (first) { first = clearEmptySpans(first); }
if (last && last != first) { last = clearEmptySpans(last); }
var newMarkers = [first];
if (!sameLine) {
// Fill gap with whole-line-spans
var gap = change.text.length - 2, gapMarkers;
if (gap > 0 && first)
{ for (var i$2 = 0; i$2 < first.length; ++i$2)
{ if (first[i$2].to == null)
{ (gapMarkers || (gapMarkers = [])).push(new MarkedSpan(first[i$2].marker, null, null)); } } }
for (var i$3 = 0; i$3 < gap; ++i$3)
{ newMarkers.push(gapMarkers); }
newMarkers.push(last);
}
return newMarkers
}
// Remove spans that are empty and don't have a clearWhenEmpty
// option of false.
function clearEmptySpans(spans) {
for (var i = 0; i < spans.length; ++i) {
var span = spans[i];
if (span.from != null && span.from == span.to && span.marker.clearWhenEmpty !== false)
{ spans.splice(i--, 1); }
}
if (!spans.length) { return null }
return spans
}
// Used to 'clip' out readOnly ranges when making a change.
function removeReadOnlyRanges(doc, from, to) {
var markers = null;
doc.iter(from.line, to.line + 1, function (line) {
if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
var mark = line.markedSpans[i].marker;
if (mark.readOnly && (!markers || indexOf(markers, mark) == -1))
{ (markers || (markers = [])).push(mark); }
} }
});
if (!markers) { return null }
var parts = [{from: from, to: to}];
for (var i = 0; i < markers.length; ++i) {
var mk = markers[i], m = mk.find(0);
for (var j = 0; j < parts.length; ++j) {
var p = parts[j];
if (cmp(p.to, m.from) < 0 || cmp(p.from, m.to) > 0) { continue }
var newParts = [j, 1], dfrom = cmp(p.from, m.from), dto = cmp(p.to, m.to);
if (dfrom < 0 || !mk.inclusiveLeft && !dfrom)
{ newParts.push({from: p.from, to: m.from}); }
if (dto > 0 || !mk.inclusiveRight && !dto)
{ newParts.push({from: m.to, to: p.to}); }
parts.splice.apply(parts, newParts);
j += newParts.length - 3;
}
}
return parts
}
// Connect or disconnect spans from a line.
function detachMarkedSpans(line) {
var spans = line.markedSpans;
if (!spans) { return }
for (var i = 0; i < spans.length; ++i)
{ spans[i].marker.detachLine(line); }
line.markedSpans = null;
}
function attachMarkedSpans(line, spans) {
if (!spans) { return }
for (var i = 0; i < spans.length; ++i)
{ spans[i].marker.attachLine(line); }
line.markedSpans = spans;
}
// Helpers used when computing which overlapping collapsed span
// counts as the larger one.
function extraLeft(marker) { return marker.inclusiveLeft ? -1 : 0 }
function extraRight(marker) { return marker.inclusiveRight ? 1 : 0 }
// Returns a number indicating which of two overlapping collapsed
// spans is larger (and thus includes the other). Falls back to
// comparing ids when the spans cover exactly the same range.
function compareCollapsedMarkers(a, b) {
var lenDiff = a.lines.length - b.lines.length;
if (lenDiff != 0) { return lenDiff }
var aPos = a.find(), bPos = b.find();
var fromCmp = cmp(aPos.from, bPos.from) || extraLeft(a) - extraLeft(b);
if (fromCmp) { return -fromCmp }
var toCmp = cmp(aPos.to, bPos.to) || extraRight(a) - extraRight(b);
if (toCmp) { return toCmp }
return b.id - a.id
}
// Find out whether a line ends or starts in a collapsed span. If
// so, return the marker for that span.
function collapsedSpanAtSide(line, start) {
var sps = sawCollapsedSpans && line.markedSpans, found;
if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
sp = sps[i];
if (sp.marker.collapsed && (start ? sp.from : sp.to) == null &&
(!found || compareCollapsedMarkers(found, sp.marker) < 0))
{ found = sp.marker; }
} }
return found
}
function collapsedSpanAtStart(line) { return collapsedSpanAtSide(line, true) }
function collapsedSpanAtEnd(line) { return collapsedSpanAtSide(line, false) }
function collapsedSpanAround(line, ch) {
var sps = sawCollapsedSpans && line.markedSpans, found;
if (sps) { for (var i = 0; i < sps.length; ++i) {
var sp = sps[i];
if (sp.marker.collapsed && (sp.from == null || sp.from < ch) && (sp.to == null || sp.to > ch) &&
(!found || compareCollapsedMarkers(found, sp.marker) < 0)) { found = sp.marker; }
} }
return found
}
// Test whether there exists a collapsed span that partially
// overlaps (covers the start or end, but not both) of a new span.
// Such overlap is not allowed.
function conflictingCollapsedRange(doc, lineNo$$1, from, to, marker) {
var line = getLine(doc, lineNo$$1);
var sps = sawCollapsedSpans && line.markedSpans;
if (sps) { for (var i = 0; i < sps.length; ++i) {
var sp = sps[i];
if (!sp.marker.collapsed) { continue }
var found = sp.marker.find(0);
var fromCmp = cmp(found.from, from) || extraLeft(sp.marker) - extraLeft(marker);
var toCmp = cmp(found.to, to) || extraRight(sp.marker) - extraRight(marker);
if (fromCmp >= 0 && toCmp <= 0 || fromCmp <= 0 && toCmp >= 0) { continue }
if (fromCmp <= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.to, from) >= 0 : cmp(found.to, from) > 0) ||
fromCmp >= 0 && (sp.marker.inclusiveRight && marker.inclusiveLeft ? cmp(found.from, to) <= 0 : cmp(found.from, to) < 0))
{ return true }
} }
}
// A visual line is a line as drawn on the screen. Folding, for
// example, can cause multiple logical lines to appear on the same
// visual line. This finds the start of the visual line that the
// given line is part of (usually that is the line itself).
function visualLine(line) {
var merged;
while (merged = collapsedSpanAtStart(line))
{ line = merged.find(-1, true).line; }
return line
}
function visualLineEnd(line) {
var merged;
while (merged = collapsedSpanAtEnd(line))
{ line = merged.find(1, true).line; }
return line
}
// Returns an array of logical lines that continue the visual line
// started by the argument, or undefined if there are no such lines.
function visualLineContinued(line) {
var merged, lines;
while (merged = collapsedSpanAtEnd(line)) {
line = merged.find(1, true).line
;(lines || (lines = [])).push(line);
}
return lines
}
// Get the line number of the start of the visual line that the
// given line number is part of.
function visualLineNo(doc, lineN) {
var line = getLine(doc, lineN), vis = visualLine(line);
if (line == vis) { return lineN }
return lineNo(vis)
}
// Get the line number of the start of the next visual line after
// the given line.
function visualLineEndNo(doc, lineN) {
if (lineN > doc.lastLine()) { return lineN }
var line = getLine(doc, lineN), merged;
if (!lineIsHidden(doc, line)) { return lineN }
while (merged = collapsedSpanAtEnd(line))
{ line = merged.find(1, true).line; }
return lineNo(line) + 1
}
// Compute whether a line is hidden. Lines count as hidden when they
// are part of a visual line that starts with another line, or when
// they are entirely covered by collapsed, non-widget span.
function lineIsHidden(doc, line) {
var sps = sawCollapsedSpans && line.markedSpans;
if (sps) { for (var sp = (void 0), i = 0; i < sps.length; ++i) {
sp = sps[i];
if (!sp.marker.collapsed) { continue }
if (sp.from == null) { return true }
if (sp.marker.widgetNode) { continue }
if (sp.from == 0 && sp.marker.inclusiveLeft && lineIsHiddenInner(doc, line, sp))
{ return true }
} }
}
function lineIsHiddenInner(doc, line, span) {
if (span.to == null) {
var end = span.marker.find(1, true);
return lineIsHiddenInner(doc, end.line, getMarkedSpanFor(end.line.markedSpans, span.marker))
}
if (span.marker.inclusiveRight && span.to == line.text.length)
{ return true }
for (var sp = (void 0), i = 0; i < line.markedSpans.length; ++i) {
sp = line.markedSpans[i];
if (sp.marker.collapsed && !sp.marker.widgetNode && sp.from == span.to &&
(sp.to == null || sp.to != span.from) &&
(sp.marker.inclusiveLeft || span.marker.inclusiveRight) &&
lineIsHiddenInner(doc, line, sp)) { return true }
}
}
// Find the height above the given line.
function heightAtLine(lineObj) {
lineObj = visualLine(lineObj);
var h = 0, chunk = lineObj.parent;
for (var i = 0; i < chunk.lines.length; ++i) {
var line = chunk.lines[i];
if (line == lineObj) { break }
else { h += line.height; }
}
for (var p = chunk.parent; p; chunk = p, p = chunk.parent) {
for (var i$1 = 0; i$1 < p.children.length; ++i$1) {
var cur = p.children[i$1];
if (cur == chunk) { break }
else { h += cur.height; }
}
}
return h
}
// Compute the character length of a line, taking into account
// collapsed ranges (see markText) that might hide parts, and join
// other lines onto it.
function lineLength(line) {
if (line.height == 0) { return 0 }
var len = line.text.length, merged, cur = line;
while (merged = collapsedSpanAtStart(cur)) {
var found = merged.find(0, true);
cur = found.from.line;
len += found.from.ch - found.to.ch;
}
cur = line;
while (merged = collapsedSpanAtEnd(cur)) {
var found$1 = merged.find(0, true);
len -= cur.text.length - found$1.from.ch;
cur = found$1.to.line;
len += cur.text.length - found$1.to.ch;
}
return len
}
// Find the longest line in the document.
function findMaxLine(cm) {
var d = cm.display, doc = cm.doc;
d.maxLine = getLine(doc, doc.first);
d.maxLineLength = lineLength(d.maxLine);
d.maxLineChanged = true;
doc.iter(function (line) {
var len = lineLength(line);
if (len > d.maxLineLength) {
d.maxLineLength = len;
d.maxLine = line;
}
});
}
// BIDI HELPERS
function iterateBidiSections(order, from, to, f) {
if (!order) { return f(from, to, "ltr", 0) }
var found = false;
for (var i = 0; i < order.length; ++i) {
var part = order[i];
if (part.from < to && part.to > from || from == to && part.to == from) {
f(Math.max(part.from, from), Math.min(part.to, to), part.level == 1 ? "rtl" : "ltr", i);
found = true;
}
}
if (!found) { f(from, to, "ltr"); }
}
var bidiOther = null;
function getBidiPartAt(order, ch, sticky) {
var found;
bidiOther = null;
for (var i = 0; i < order.length; ++i) {
var cur = order[i];
if (cur.from < ch && cur.to > ch) { return i }
if (cur.to == ch) {
if (cur.from != cur.to && sticky == "before") { found = i; }
else { bidiOther = i; }
}
if (cur.from == ch) {
if (cur.from != cur.to && sticky != "before") { found = i; }
else { bidiOther = i; }
}
}
return found != null ? found : bidiOther
}
// Bidirectional ordering algorithm
// See http://unicode.org/reports/tr9/tr9-13.html for the algorithm
// that this (partially) implements.
// One-char codes used for character types:
// L (L): Left-to-Right
// R (R): Right-to-Left
// r (AL): Right-to-Left Arabic
// 1 (EN): European Number
// + (ES): European Number Separator
// % (ET): European Number Terminator
// n (AN): Arabic Number
// , (CS): Common Number Separator
// m (NSM): Non-Spacing Mark
// b (BN): Boundary Neutral
// s (B): Paragraph Separator
// t (S): Segment Separator
// w (WS): Whitespace
// N (ON): Other Neutrals
// Returns null if characters are ordered as they appear
// (left-to-right), or an array of sections ({from, to, level}
// objects) in the order in which they occur visually.
var bidiOrdering = (function() {
// Character types for codepoints 0 to 0xff
var lowTypes = "bbbbbbbbbtstwsbbbbbbbbbbbbbbssstwNN%%%NNNNNN,N,N1111111111NNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNNNLLLLLLLLLLLLLLLLLLLLLLLLLLNNNNbbbbbbsbbbbbbbbbbbbbbbbbbbbbbbbbb,N%%%%NNNNLNNNNN%%11NLNNN1LNNNNNLLLLLLLLLLLLLLLLLLLLLLLNLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLN";
// Character types for codepoints 0x600 to 0x6f9
var arabicTypes = "nnnnnnNNr%%r,rNNmmmmmmmmmmmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmmmmmmmmmmmmmmmnnnnnnnnnn%nnrrrmrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrmmmmmmmnNmmmmmmrrmmNmmmmrr1111111111";
function charType(code) {
if (code <= 0xf7) { return lowTypes.charAt(code) }
else if (0x590 <= code && code <= 0x5f4) { return "R" }
else if (0x600 <= code && code <= 0x6f9) { return arabicTypes.charAt(code - 0x600) }
else if (0x6ee <= code && code <= 0x8ac) { return "r" }
else if (0x2000 <= code && code <= 0x200b) { return "w" }
else if (code == 0x200c) { return "b" }
else { return "L" }
}
var bidiRE = /[\u0590-\u05f4\u0600-\u06ff\u0700-\u08ac]/;
var isNeutral = /[stwN]/, isStrong = /[LRr]/, countsAsLeft = /[Lb1n]/, countsAsNum = /[1n]/;
function BidiSpan(level, from, to) {
this.level = level;
this.from = from; this.to = to;
}
return function(str, direction) {
var outerType = direction == "ltr" ? "L" : "R";
if (str.length == 0 || direction == "ltr" && !bidiRE.test(str)) { return false }
var len = str.length, types = [];
for (var i = 0; i < len; ++i)
{ types.push(charType(str.charCodeAt(i))); }
// W1. Examine each non-spacing mark (NSM) in the level run, and
// change the type of the NSM to the type of the previous
// character. If the NSM is at the start of the level run, it will
// get the type of sor.
for (var i$1 = 0, prev = outerType; i$1 < len; ++i$1) {
var type = types[i$1];
if (type == "m") { types[i$1] = prev; }
else { prev = type; }
}
// W2. Search backwards from each instance of a European number
// until the first strong type (R, L, AL, or sor) is found. If an
// AL is found, change the type of the European number to Arabic
// number.
// W3. Change all ALs to R.
for (var i$2 = 0, cur = outerType; i$2 < len; ++i$2) {
var type$1 = types[i$2];
if (type$1 == "1" && cur == "r") { types[i$2] = "n"; }
else if (isStrong.test(type$1)) { cur = type$1; if (type$1 == "r") { types[i$2] = "R"; } }
}
// W4. A single European separator between two European numbers
// changes to a European number. A single common separator between
// two numbers of the same type changes to that type.
for (var i$3 = 1, prev$1 = types[0]; i$3 < len - 1; ++i$3) {
var type$2 = types[i$3];
if (type$2 == "+" && prev$1 == "1" && types[i$3+1] == "1") { types[i$3] = "1"; }
else if (type$2 == "," && prev$1 == types[i$3+1] &&
(prev$1 == "1" || prev$1 == "n")) { types[i$3] = prev$1; }
prev$1 = type$2;
}
// W5. A sequence of European terminators adjacent to European
// numbers changes to all European numbers.
// W6. Otherwise, separators and terminators change to Other
// Neutral.
for (var i$4 = 0; i$4 < len; ++i$4) {
var type$3 = types[i$4];
if (type$3 == ",") { types[i$4] = "N"; }
else if (type$3 == "%") {
var end = (void 0);
for (end = i$4 + 1; end < len && types[end] == "%"; ++end) {}
var replace = (i$4 && types[i$4-1] == "!") || (end < len && types[end] == "1") ? "1" : "N";
for (var j = i$4; j < end; ++j) { types[j] = replace; }
i$4 = end - 1;
}
}
// W7. Search backwards from each instance of a European number
// until the first strong type (R, L, or sor) is found. If an L is
// found, then change the type of the European number to L.
for (var i$5 = 0, cur$1 = outerType; i$5 < len; ++i$5) {
var type$4 = types[i$5];
if (cur$1 == "L" && type$4 == "1") { types[i$5] = "L"; }
else if (isStrong.test(type$4)) { cur$1 = type$4; }
}
// N1. A sequence of neutrals takes the direction of the
// surrounding strong text if the text on both sides has the same
// direction. European and Arabic numbers act as if they were R in
// terms of their influence on neutrals. Start-of-level-run (sor)
// and end-of-level-run (eor) are used at level run boundaries.
// N2. Any remaining neutrals take the embedding direction.
for (var i$6 = 0; i$6 < len; ++i$6) {
if (isNeutral.test(types[i$6])) {
var end$1 = (void 0);
for (end$1 = i$6 + 1; end$1 < len && isNeutral.test(types[end$1]); ++end$1) {}
var before = (i$6 ? types[i$6-1] : outerType) == "L";
var after = (end$1 < len ? types[end$1] : outerType) == "L";
var replace$1 = before == after ? (before ? "L" : "R") : outerType;
for (var j$1 = i$6; j$1 < end$1; ++j$1) { types[j$1] = replace$1; }
i$6 = end$1 - 1;
}
}
// Here we depart from the documented algorithm, in order to avoid
// building up an actual levels array. Since there are only three
// levels (0, 1, 2) in an implementation that doesn't take
// explicit embedding into account, we can build up the order on
// the fly, without following the level-based algorithm.
var order = [], m;
for (var i$7 = 0; i$7 < len;) {
if (countsAsLeft.test(types[i$7])) {
var start = i$7;
for (++i$7; i$7 < len && countsAsLeft.test(types[i$7]); ++i$7) {}
order.push(new BidiSpan(0, start, i$7));
} else {
var pos = i$7, at = order.length;
for (++i$7; i$7 < len && types[i$7] != "L"; ++i$7) {}
for (var j$2 = pos; j$2 < i$7;) {
if (countsAsNum.test(types[j$2])) {
if (pos < j$2) { order.splice(at, 0, new BidiSpan(1, pos, j$2)); }
var nstart = j$2;
for (++j$2; j$2 < i$7 && countsAsNum.test(types[j$2]); ++j$2) {}
order.splice(at, 0, new BidiSpan(2, nstart, j$2));
pos = j$2;
} else { ++j$2; }
}
if (pos < i$7) { order.splice(at, 0, new BidiSpan(1, pos, i$7)); }
}
}
if (direction == "ltr") {
if (order[0].level == 1 && (m = str.match(/^\s+/))) {
order[0].from = m[0].length;
order.unshift(new BidiSpan(0, 0, m[0].length));
}
if (lst(order).level == 1 && (m = str.match(/\s+$/))) {
lst(order).to -= m[0].length;
order.push(new BidiSpan(0, len - m[0].length, len));
}
}
return direction == "rtl" ? order.reverse() : order
}
})();
// Get the bidi ordering for the given line (and cache it). Returns
// false for lines that are fully left-to-right, and an array of
// BidiSpan objects otherwise.
function getOrder(line, direction) {
var order = line.order;
if (order == null) { order = line.order = bidiOrdering(line.text, direction); }
return order
}
// EVENT HANDLING
// Lightweight event framework. on/off also work on DOM nodes,
// registering native DOM handlers.
var noHandlers = [];
var on = function(emitter, type, f) {
if (emitter.addEventListener) {
emitter.addEventListener(type, f, false);
} else if (emitter.attachEvent) {
emitter.attachEvent("on" + type, f);
} else {
var map$$1 = emitter._handlers || (emitter._handlers = {});
map$$1[type] = (map$$1[type] || noHandlers).concat(f);
}
};
function getHandlers(emitter, type) {
return emitter._handlers && emitter._handlers[type] || noHandlers
}
function off(emitter, type, f) {
if (emitter.removeEventListener) {
emitter.removeEventListener(type, f, false);
} else if (emitter.detachEvent) {
emitter.detachEvent("on" + type, f);
} else {
var map$$1 = emitter._handlers, arr = map$$1 && map$$1[type];
if (arr) {
var index = indexOf(arr, f);
if (index > -1)
{ map$$1[type] = arr.slice(0, index).concat(arr.slice(index + 1)); }
}
}
}
function signal(emitter, type /*, values...*/) {
var handlers = getHandlers(emitter, type);
if (!handlers.length) { return }
var args = Array.prototype.slice.call(arguments, 2);
for (var i = 0; i < handlers.length; ++i) { handlers[i].apply(null, args); }
}
// The DOM events that CodeMirror handles can be overridden by
// registering a (non-DOM) handler on the editor for the event name,
// and preventDefault-ing the event in that handler.
function signalDOMEvent(cm, e, override) {
if (typeof e == "string")
{ e = {type: e, preventDefault: function() { this.defaultPrevented = true; }}; }
signal(cm, override || e.type, cm, e);
return e_defaultPrevented(e) || e.codemirrorIgnore
}
function signalCursorActivity(cm) {
var arr = cm._handlers && cm._handlers.cursorActivity;
if (!arr) { return }
var set = cm.curOp.cursorActivityHandlers || (cm.curOp.cursorActivityHandlers = []);
for (var i = 0; i < arr.length; ++i) { if (indexOf(set, arr[i]) == -1)
{ set.push(arr[i]); } }
}
function hasHandler(emitter, type) {
return getHandlers(emitter, type).length > 0
}
// Add on and off methods to a constructor's prototype, to make
// registering events on such objects more convenient.
function eventMixin(ctor) {
ctor.prototype.on = function(type, f) {on(this, type, f);};
ctor.prototype.off = function(type, f) {off(this, type, f);};
}
// Due to the fact that we still support jurassic IE versions, some
// compatibility wrappers are needed.
function e_preventDefault(e) {
if (e.preventDefault) { e.preventDefault(); }
else { e.returnValue = false; }
}
function e_stopPropagation(e) {
if (e.stopPropagation) { e.stopPropagation(); }
else { e.cancelBubble = true; }
}
function e_defaultPrevented(e) {
return e.defaultPrevented != null ? e.defaultPrevented : e.returnValue == false
}
function e_stop(e) {e_preventDefault(e); e_stopPropagation(e);}
function e_target(e) {return e.target || e.srcElement}
function e_button(e) {
var b = e.which;
if (b == null) {
if (e.button & 1) { b = 1; }
else if (e.button & 2) { b = 3; }
else if (e.button & 4) { b = 2; }
}
if (mac && e.ctrlKey && b == 1) { b = 3; }
return b
}
// Detect drag-and-drop
var dragAndDrop = function() {
// There is *some* kind of drag-and-drop support in IE6-8, but I
// couldn't get it to work yet.
if (ie && ie_version < 9) { return false }
var div = elt('div');
return "draggable" in div || "dragDrop" in div
}();
var zwspSupported;
function zeroWidthElement(measure) {
if (zwspSupported == null) {
var test = elt("span", "\u200b");
removeChildrenAndAdd(measure, elt("span", [test, document.createTextNode("x")]));
if (measure.firstChild.offsetHeight != 0)
{ zwspSupported = test.offsetWidth <= 1 && test.offsetHeight > 2 && !(ie && ie_version < 8); }
}
var node = zwspSupported ? elt("span", "\u200b") :
elt("span", "\u00a0", null, "display: inline-block; width: 1px; margin-right: -1px");
node.setAttribute("cm-text", "");
return node
}
// Feature-detect IE's crummy client rect reporting for bidi text
var badBidiRects;
function hasBadBidiRects(measure) {
if (badBidiRects != null) { return badBidiRects }
var txt = removeChildrenAndAdd(measure, document.createTextNode("A\u062eA"));
var r0 = range(txt, 0, 1).getBoundingClientRect();
var r1 = range(txt, 1, 2).getBoundingClientRect();
removeChildren(measure);
if (!r0 || r0.left == r0.right) { return false } // Safari returns null in some cases (#2780)
return badBidiRects = (r1.right - r0.right < 3)
}
// See if "".split is the broken IE version, if so, provide an
// alternative way to split lines.
var splitLinesAuto = "\n\nb".split(/\n/).length != 3 ? function (string) {
var pos = 0, result = [], l = string.length;
while (pos <= l) {
var nl = string.indexOf("\n", pos);
if (nl == -1) { nl = string.length; }
var line = string.slice(pos, string.charAt(nl - 1) == "\r" ? nl - 1 : nl);
var rt = line.indexOf("\r");
if (rt != -1) {
result.push(line.slice(0, rt));
pos += rt + 1;
} else {
result.push(line);
pos = nl + 1;
}
}
return result
} : function (string) { return string.split(/\r\n?|\n/); };
var hasSelection = window.getSelection ? function (te) {
try { return te.selectionStart != te.selectionEnd }
catch(e) { return false }
} : function (te) {
var range$$1;
try {range$$1 = te.ownerDocument.selection.createRange();}
catch(e) {}
if (!range$$1 || range$$1.parentElement() != te) { return false }
return range$$1.compareEndPoints("StartToEnd", range$$1) != 0
};
var hasCopyEvent = (function () {
var e = elt("div");
if ("oncopy" in e) { return true }
e.setAttribute("oncopy", "return;");
return typeof e.oncopy == "function"
})();
var badZoomedRects = null;
function hasBadZoomedRects(measure) {
if (badZoomedRects != null) { return badZoomedRects }
var node = removeChildrenAndAdd(measure, elt("span", "x"));
var normal = node.getBoundingClientRect();
var fromRange = range(node, 0, 1).getBoundingClientRect();
return badZoomedRects = Math.abs(normal.left - fromRange.left) > 1
}
// Known modes, by name and by MIME
var modes = {}, mimeModes = {};
// Extra arguments are stored as the mode's dependencies, which is
// used by (legacy) mechanisms like loadmode.js to automatically
// load a mode. (Preferred mechanism is the require/define calls.)
function defineMode(name, mode) {
if (arguments.length > 2)
{ mode.dependencies = Array.prototype.slice.call(arguments, 2); }
modes[name] = mode;
}
function defineMIME(mime, spec) {
mimeModes[mime] = spec;
}
// Given a MIME type, a {name, ...options} config object, or a name
// string, return a mode config object.
function resolveMode(spec) {
if (typeof spec == "string" && mimeModes.hasOwnProperty(spec)) {
spec = mimeModes[spec];
} else if (spec && typeof spec.name == "string" && mimeModes.hasOwnProperty(spec.name)) {
var found = mimeModes[spec.name];
if (typeof found == "string") { found = {name: found}; }
spec = createObj(found, spec);
spec.name = found.name;
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+xml$/.test(spec)) {
return resolveMode("application/xml")
} else if (typeof spec == "string" && /^[\w\-]+\/[\w\-]+\+json$/.test(spec)) {
return resolveMode("application/json")
}
if (typeof spec == "string") { return {name: spec} }
else { return spec || {name: "null"} }
}
// Given a mode spec (anything that resolveMode accepts), find and
// initialize an actual mode object.
function getMode(options, spec) {
spec = resolveMode(spec);
var mfactory = modes[spec.name];
if (!mfactory) { return getMode(options, "text/plain") }
var modeObj = mfactory(options, spec);
if (modeExtensions.hasOwnProperty(spec.name)) {
var exts = modeExtensions[spec.name];
for (var prop in exts) {
if (!exts.hasOwnProperty(prop)) { continue }
if (modeObj.hasOwnProperty(prop)) { modeObj["_" + prop] = modeObj[prop]; }
modeObj[prop] = exts[prop];
}
}
modeObj.name = spec.name;
if (spec.helperType) { modeObj.helperType = spec.helperType; }
if (spec.modeProps) { for (var prop$1 in spec.modeProps)
{ modeObj[prop$1] = spec.modeProps[prop$1]; } }
return modeObj
}
// This can be used to attach properties to mode objects from
// outside the actual mode definition.
var modeExtensions = {};
function extendMode(mode, properties) {
var exts = modeExtensions.hasOwnProperty(mode) ? modeExtensions[mode] : (modeExtensions[mode] = {});
copyObj(properties, exts);
}
function copyState(mode, state) {
if (state === true) { return state }
if (mode.copyState) { return mode.copyState(state) }
var nstate = {};
for (var n in state) {
var val = state[n];
if (val instanceof Array) { val = val.concat([]); }
nstate[n] = val;
}
return nstate
}
// Given a mode and a state (for that mode), find the inner mode and
// state at the position that the state refers to.
function innerMode(mode, state) {
var info;
while (mode.innerMode) {
info = mode.innerMode(state);
if (!info || info.mode == mode) { break }
state = info.state;
mode = info.mode;
}
return info || {mode: mode, state: state}
}
function startState(mode, a1, a2) {
return mode.startState ? mode.startState(a1, a2) : true
}
// STRING STREAM
// Fed to the mode parsers, provides helper functions to make
// parsers more succinct.
var StringStream = function(string, tabSize, lineOracle) {
this.pos = this.start = 0;
this.string = string;
this.tabSize = tabSize || 8;
this.lastColumnPos = this.lastColumnValue = 0;
this.lineStart = 0;
this.lineOracle = lineOracle;
};
StringStream.prototype.eol = function () {return this.pos >= this.string.length};
StringStream.prototype.sol = function () {return this.pos == this.lineStart};
StringStream.prototype.peek = function () {return this.string.charAt(this.pos) || undefined};
StringStream.prototype.next = function () {
if (this.pos < this.string.length)
{ return this.string.charAt(this.pos++) }
};
StringStream.prototype.eat = function (match) {
var ch = this.string.charAt(this.pos);
var ok;
if (typeof match == "string") { ok = ch == match; }
else { ok = ch && (match.test ? match.test(ch) : match(ch)); }
if (ok) {++this.pos; return ch}
};
StringStream.prototype.eatWhile = function (match) {
var start = this.pos;
while (this.eat(match)){}
return this.pos > start
};
StringStream.prototype.eatSpace = function () {
var this$1 = this;
var start = this.pos;
while (/[\s\u00a0]/.test(this.string.charAt(this.pos))) { ++this$1.pos; }
return this.pos > start
};
StringStream.prototype.skipToEnd = function () {this.pos = this.string.length;};
StringStream.prototype.skipTo = function (ch) {
var found = this.string.indexOf(ch, this.pos);
if (found > -1) {this.pos = found; return true}
};
StringStream.prototype.backUp = function (n) {this.pos -= n;};
StringStream.prototype.column = function () {
if (this.lastColumnPos < this.start) {
this.lastColumnValue = countColumn(this.string, this.start, this.tabSize, this.lastColumnPos, this.lastColumnValue);
this.lastColumnPos = this.start;
}
return this.lastColumnValue - (this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
};
StringStream.prototype.indentation = function () {
return countColumn(this.string, null, this.tabSize) -
(this.lineStart ? countColumn(this.string, this.lineStart, this.tabSize) : 0)
};
StringStream.prototype.match = function (pattern, consume, caseInsensitive) {
if (typeof pattern == "string") {
var cased = function (str) { return caseInsensitive ? str.toLowerCase() : str; };
var substr = this.string.substr(this.pos, pattern.length);
if (cased(substr) == cased(pattern)) {
if (consume !== false) { this.pos += pattern.length; }
return true
}
} else {
var match = this.string.slice(this.pos).match(pattern);
if (match && match.index > 0) { return null }
if (match && consume !== false) { this.pos += match[0].length; }
return match
}
};
StringStream.prototype.current = function (){return this.string.slice(this.start, this.pos)};
StringStream.prototype.hideFirstChars = function (n, inner) {
this.lineStart += n;
try { return inner() }
finally { this.lineStart -= n; }
};
StringStream.prototype.lookAhead = function (n) {
var oracle = this.lineOracle;
return oracle && oracle.lookAhead(n)
};
StringStream.prototype.baseToken = function () {
var oracle = this.lineOracle;
return oracle && oracle.baseToken(this.pos)
};
var SavedContext = function(state, lookAhead) {
this.state = state;
this.lookAhead = lookAhead;
};
var Context = function(doc, state, line, lookAhead) {
this.state = state;
this.doc = doc;
this.line = line;
this.maxLookAhead = lookAhead || 0;
this.baseTokens = null;
this.baseTokenPos = 1;
};
Context.prototype.lookAhead = function (n) {
var line = this.doc.getLine(this.line + n);
if (line != null && n > this.maxLookAhead) { this.maxLookAhead = n; }
return line
};
Context.prototype.baseToken = function (n) {
var this$1 = this;
if (!this.baseTokens) { return null }
while (this.baseTokens[this.baseTokenPos] <= n)
{ this$1.baseTokenPos += 2; }
var type = this.baseTokens[this.baseTokenPos + 1];
return {type: type && type.replace(/( |^)overlay .*/, ""),
size: this.baseTokens[this.baseTokenPos] - n}
};
Context.prototype.nextLine = function () {
this.line++;
if (this.maxLookAhead > 0) { this.maxLookAhead--; }
};
Context.fromSaved = function (doc, saved, line) {
if (saved instanceof SavedContext)
{ return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead) }
else
{ return new Context(doc, copyState(doc.mode, saved), line) }
};
Context.prototype.save = function (copy) {
var state = copy !== false ? copyState(this.doc.mode, this.state) : this.state;
return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
};
// Compute a style array (an array starting with a mode generation
// -- for invalidation -- followed by pairs of end positions and
// style strings), which is used to highlight the tokens on the
// line.
function highlightLine(cm, line, context, forceToEnd) {
// A styles array always starts with a number identifying the
// mode/overlays that it is based on (for easy invalidation).
var st = [cm.state.modeGen], lineClasses = {};
// Compute the base array of styles
runMode(cm, line.text, cm.doc.mode, context, function (end, style) { return st.push(end, style); },
lineClasses, forceToEnd);
var state = context.state;
// Run overlays, adjust style array.
var loop = function ( o ) {
context.baseTokens = st;
var overlay = cm.state.overlays[o], i = 1, at = 0;
context.state = true;
runMode(cm, line.text, overlay.mode, context, function (end, style) {
var start = i;
// Ensure there's a token end at the current position, and that i points at it
while (at < end) {
var i_end = st[i];
if (i_end > end)
{ st.splice(i, 1, end, st[i+1], i_end); }
i += 2;
at = Math.min(end, i_end);
}
if (!style) { return }
if (overlay.opaque) {
st.splice(start, i - start, end, "overlay " + style);
i = start + 2;
} else {
for (; start < i; start += 2) {
var cur = st[start+1];
st[start+1] = (cur ? cur + " " : "") + "overlay " + style;
}
}
}, lineClasses);
context.state = state;
context.baseTokens = null;
context.baseTokenPos = 1;
};
for (var o = 0; o < cm.state.overlays.length; ++o) loop( o );
return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
}
function getLineStyles(cm, line, updateFrontier) {
if (!line.styles || line.styles[0] != cm.state.modeGen) {
var context = getContextBefore(cm, lineNo(line));
var resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state);
var result = highlightLine(cm, line, context);
if (resetState) { context.state = resetState; }
line.stateAfter = context.save(!resetState);
line.styles = result.styles;
if (result.classes) { line.styleClasses = result.classes; }
else if (line.styleClasses) { line.styleClasses = null; }
if (updateFrontier === cm.doc.highlightFrontier)
{ cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier); }
}
return line.styles
}
function getContextBefore(cm, n, precise) {
var doc = cm.doc, display = cm.display;
if (!doc.mode.startState) { return new Context(doc, true, n) }
var start = findStartLine(cm, n, precise);
var saved = start > doc.first && getLine(doc, start - 1).stateAfter;
var context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start);
doc.iter(start, n, function (line) {
processLine(cm, line.text, context);
var pos = context.line;
line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null;
context.nextLine();
});
if (precise) { doc.modeFrontier = context.line; }
return context
}
// Lightweight form of highlight -- proceed over this line and
// update state, but don't save a style array. Used for lines that
// aren't currently visible.
function processLine(cm, text, context, startAt) {
var mode = cm.doc.mode;
var stream = new StringStream(text, cm.options.tabSize, context);
stream.start = stream.pos = startAt || 0;
if (text == "") { callBlankLine(mode, context.state); }
while (!stream.eol()) {
readToken(mode, stream, context.state);
stream.start = stream.pos;
}
}
function callBlankLine(mode, state) {
if (mode.blankLine) { return mode.blankLine(state) }
if (!mode.innerMode) { return }
var inner = innerMode(mode, state);
if (inner.mode.blankLine) { return inner.mode.blankLine(inner.state) }
}
function readToken(mode, stream, state, inner) {
for (var i = 0; i < 10; i++) {
if (inner) { inner[0] = innerMode(mode, state).mode; }
var style = mode.token(stream, state);
if (stream.pos > stream.start) { return style }
}
throw new Error("Mode " + mode.name + " failed to advance stream.")
}
var Token = function(stream, type, state) {
this.start = stream.start; this.end = stream.pos;
this.string = stream.current();
this.type = type || null;
this.state = state;
};
// Utility for getTokenAt and getLineTokens
function takeToken(cm, pos, precise, asArray) {
var doc = cm.doc, mode = doc.mode, style;
pos = clipPos(doc, pos);
var line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise);
var stream = new StringStream(line.text, cm.options.tabSize, context), tokens;
if (asArray) { tokens = []; }
while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
stream.start = stream.pos;
style = readToken(mode, stream, context.state);
if (asArray) { tokens.push(new Token(stream, style, copyState(doc.mode, context.state))); }
}
return asArray ? tokens : new Token(stream, style, context.state)
}
function extractLineClasses(type, output) {
if (type) { for (;;) {
var lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/);
if (!lineClass) { break }
type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length);
var prop = lineClass[1] ? "bgClass" : "textClass";
if (output[prop] == null)
{ output[prop] = lineClass[2]; }
else if (!(new RegExp("(?:^|\s)" + lineClass[2] + "(?:$|\s)")).test(output[prop]))
{ output[prop] += " " + lineClass[2]; }
} }
return type
}
// Run the given mode's parser over a line, calling f for each token.
function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
var flattenSpans = mode.flattenSpans;
if (flattenSpans == null) { flattenSpans = cm.options.flattenSpans; }
var curStart = 0, curStyle = null;
var stream = new StringStream(text, cm.options.tabSize, context), style;
var inner = cm.options.addModeClass && [null];
if (text == "") { extractLineClasses(callBlankLine(mode, context.state), lineClasses); }
while (!stream.eol()) {
if (stream.pos > cm.options.maxHighlightLength) {
flattenSpans = false;
if (forceToEnd) { processLine(cm, text, context, stream.pos); }
stream.pos = text.length;
style = null;
} else {
style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses);
}
if (inner) {
var mName = inner[0].name;
if (mName) { style = "m-" + (style ? mName + " " + style : mName); }
}
if (!flattenSpans || curStyle != style) {
while (curStart < stream.start) {
curStart = Math.min(stream.start, curStart + 5000);
f(curStart, curStyle);
}
curStyle = style;
}
stream.start = stream.pos;
}
while (curStart < stream.pos) {
// Webkit seems to refuse to render text nodes longer than 57444
// characters, and returns inaccurate measurements in nodes
// starting around 5000 chars.
var pos = Math.min(stream.pos, curStart + 5000);
f(pos, curStyle);
curStart = pos;
}
}
// Finds the line to start with when starting a parse. Tries to
// find a line with a stateAfter, so that it can start with a
// valid state. If that fails, it returns the line with the
// smallest indentation, which tends to need the least context to
// parse correctly.
function findStartLine(cm, n, precise) {
var minindent, minline, doc = cm.doc;
var lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100);
for (var search = n; search > lim; --search) {
if (search <= doc.first) { return doc.first }
var line = getLine(doc, search - 1), after = line.stateAfter;
if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
{ return search }
var indented = countColumn(line.text, null, cm.options.tabSize);
if (minline == null || minindent > indented) {
minline = search - 1;
minindent = indented;
}
}
return minline
}
function retreatFrontier(doc, n) {
doc.modeFrontier = Math.min(doc.modeFrontier, n);
if (doc.highlightFrontier < n - 10) { return }
var start = doc.first;
for (var line = n - 1; line > start; line--) {
var saved = getLine(doc, line).stateAfter;
// change is on 3
// state on line 1 looked ahead 2 -- so saw 3
// test 1 + 2 < 3 should cover this
if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
start = line + 1;
break
}
}
doc.highlightFrontier = Math.min(doc.highlightFrontier, start);
}
// LINE DATA STRUCTURE
// Line objects. These hold state related to a line, including
// highlighting info (the styles array).
var Line = function(text, markedSpans, estimateHeight) {
this.text = text;
attachMarkedSpans(this, markedSpans);
this.height = estimateHeight ? estimateHeight(this) : 1;
};
Line.prototype.lineNo = function () { return lineNo(this) };
eventMixin(Line);
// Change the content (text, markers) of a line. Automatically
// invalidates cached information and tries to re-estimate the
// line's height.
function updateLine(line, text, markedSpans, estimateHeight) {
line.text = text;
if (line.stateAfter) { line.stateAfter = null; }
if (line.styles) { line.styles = null; }
if (line.order != null) { line.order = null; }
detachMarkedSpans(line);
attachMarkedSpans(line, markedSpans);
var estHeight = estimateHeight ? estimateHeight(line) : 1;
if (estHeight != line.height) { updateLineHeight(line, estHeight); }
}
// Detach a line from the document tree and its markers.
function cleanUpLine(line) {
line.parent = null;
detachMarkedSpans(line);
}
// Convert a style as returned by a mode (either null, or a string
// containing one or more styles) to a CSS style. This is cached,
// and also looks for line-wide styles.
var styleToClassCache = {}, styleToClassCacheWithMode = {};
function interpretTokenStyle(style, options) {
if (!style || /^\s*$/.test(style)) { return null }
var cache = options.addModeClass ? styleToClassCacheWithMode : styleToClassCache;
return cache[style] ||
(cache[style] = style.replace(/\S+/g, "cm-$&"))
}
// Render the DOM representation of the text of a line. Also builds
// up a 'line map', which points at the DOM nodes that represent
// specific stretches of text, and is used by the measuring code.
// The returned object contains the DOM node, this map, and
// information about line-wide styles that were set by the mode.
function buildLineContent(cm, lineView) {
// The padding-right forces the element to have a 'border', which
// is needed on Webkit to be able to get line-level bounding
// rectangles for it (in measureChar).
var content = eltP("span", null, null, webkit ? "padding-right: .1px" : null);
var builder = {pre: eltP("pre", [content], "CodeMirror-line"), content: content,
col: 0, pos: 0, cm: cm,
trailingSpace: false,
splitSpaces: cm.getOption("lineWrapping")};
lineView.measure = {};
// Iterate over the logical lines that make up this visual line.
for (var i = 0; i <= (lineView.rest ? lineView.rest.length : 0); i++) {
var line = i ? lineView.rest[i - 1] : lineView.line, order = (void 0);
builder.pos = 0;
builder.addToken = buildToken;
// Optionally wire in some hacks into the token-rendering
// algorithm, to deal with browser quirks.
if (hasBadBidiRects(cm.display.measure) && (order = getOrder(line, cm.doc.direction)))
{ builder.addToken = buildTokenBadBidi(builder.addToken, order); }
builder.map = [];
var allowFrontierUpdate = lineView != cm.display.externalMeasured && lineNo(line);
insertLineContent(line, builder, getLineStyles(cm, line, allowFrontierUpdate));
if (line.styleClasses) {
if (line.styleClasses.bgClass)
{ builder.bgClass = joinClasses(line.styleClasses.bgClass, builder.bgClass || ""); }
if (line.styleClasses.textClass)
{ builder.textClass = joinClasses(line.styleClasses.textClass, builder.textClass || ""); }
}
// Ensure at least a single node is present, for measuring.
if (builder.map.length == 0)
{ builder.map.push(0, 0, builder.content.appendChild(zeroWidthElement(cm.display.measure))); }
// Store the map and a cache object for the current logical line
if (i == 0) {
lineView.measure.map = builder.map;
lineView.measure.cache = {};
} else {
(lineView.measure.maps || (lineView.measure.maps = [])).push(builder.map)
;(lineView.measure.caches || (lineView.measure.caches = [])).push({});
}
}
// See issue #2901
if (webkit) {
var last = builder.content.lastChild;
if (/\bcm-tab\b/.test(last.className) || (last.querySelector && last.querySelector(".cm-tab")))
{ builder.content.className = "cm-tab-wrap-hack"; }
}
signal(cm, "renderLine", cm, lineView.line, builder.pre);
if (builder.pre.className)
{ builder.textClass = joinClasses(builder.pre.className, builder.textClass || ""); }
return builder
}
function defaultSpecialCharPlaceholder(ch) {
var token = elt("span", "\u2022", "cm-invalidchar");
token.title = "\\u" + ch.charCodeAt(0).toString(16);
token.setAttribute("aria-label", token.title);
return token
}
// Build up the DOM representation for a single token, and add it to
// the line map. Takes care to render special characters separately.
function buildToken(builder, text, style, startStyle, endStyle, css, attributes) {
if (!text) { return }
var displayText = builder.splitSpaces ? splitSpaces(text, builder.trailingSpace) : text;
var special = builder.cm.state.specialChars, mustWrap = false;
var content;
if (!special.test(text)) {
builder.col += text.length;
content = document.createTextNode(displayText);
builder.map.push(builder.pos, builder.pos + text.length, content);
if (ie && ie_version < 9) { mustWrap = true; }
builder.pos += text.length;
} else {
content = document.createDocumentFragment();
var pos = 0;
while (true) {
special.lastIndex = pos;
var m = special.exec(text);
var skipped = m ? m.index - pos : text.length - pos;
if (skipped) {
var txt = document.createTextNode(displayText.slice(pos, pos + skipped));
if (ie && ie_version < 9) { content.appendChild(elt("span", [txt])); }
else { content.appendChild(txt); }
builder.map.push(builder.pos, builder.pos + skipped, txt);
builder.col += skipped;
builder.pos += skipped;
}
if (!m) { break }
pos += skipped + 1;
var txt$1 = (void 0);
if (m[0] == "\t") {
var tabSize = builder.cm.options.tabSize, tabWidth = tabSize - builder.col % tabSize;
txt$1 = content.appendChild(elt("span", spaceStr(tabWidth), "cm-tab"));
txt$1.setAttribute("role", "presentation");
txt$1.setAttribute("cm-text", "\t");
builder.col += tabWidth;
} else if (m[0] == "\r" || m[0] == "\n") {
txt$1 = content.appendChild(elt("span", m[0] == "\r" ? "\u240d" : "\u2424", "cm-invalidchar"));
txt$1.setAttribute("cm-text", m[0]);
builder.col += 1;
} else {
txt$1 = builder.cm.options.specialCharPlaceholder(m[0]);
txt$1.setAttribute("cm-text", m[0]);
if (ie && ie_version < 9) { content.appendChild(elt("span", [txt$1])); }
else { content.appendChild(txt$1); }
builder.col += 1;
}
builder.map.push(builder.pos, builder.pos + 1, txt$1);
builder.pos++;
}
}
builder.trailingSpace = displayText.charCodeAt(text.length - 1) == 32;
if (style || startStyle || endStyle || mustWrap || css) {
var fullStyle = style || "";
if (startStyle) { fullStyle += startStyle; }
if (endStyle) { fullStyle += endStyle; }
var token = elt("span", [content], fullStyle, css);
if (attributes) {
for (var attr in attributes) { if (attributes.hasOwnProperty(attr) && attr != "style" && attr != "class")
{ token.setAttribute(attr, attributes[attr]); } }
}
return builder.content.appendChild(token)
}
builder.content.appendChild(content);
}
// Change some spaces to NBSP to prevent the browser from collapsing
// trailing spaces at the end of a line when rendering text (issue #1362).
function splitSpaces(text, trailingBefore) {
if (text.length > 1 && !/ /.test(text)) { return text }
var spaceBefore = trailingBefore, result = "";
for (var i = 0; i < text.length; i++) {
var ch = text.charAt(i);
if (ch == " " && spaceBefore && (i == text.length - 1 || text.charCodeAt(i + 1) == 32))
{ ch = "\u00a0"; }
result += ch;
spaceBefore = ch == " ";
}
return result
}
// Work around nonsense dimensions being reported for stretches of
// right-to-left text.
function buildTokenBadBidi(inner, order) {
return function (builder, text, style, startStyle, endStyle, css, attributes) {
style = style ? style + " cm-force-border" : "cm-force-border";
var start = builder.pos, end = start + text.length;
for (;;) {
// Find the part that overlaps with the start of this text
var part = (void 0);
for (var i = 0; i < order.length; i++) {
part = order[i];
if (part.to > start && part.from <= start) { break }
}
if (part.to >= end) { return inner(builder, text, style, startStyle, endStyle, css, attributes) }
inner(builder, text.slice(0, part.to - start), style, startStyle, null, css, attributes);
startStyle = null;
text = text.slice(part.to - start);
start = part.to;
}
}
}
function buildCollapsedSpan(builder, size, marker, ignoreWidget) {
var widget = !ignoreWidget && marker.widgetNode;
if (widget) { builder.map.push(builder.pos, builder.pos + size, widget); }
if (!ignoreWidget && builder.cm.display.input.needsContentAttribute) {
if (!widget)
{ widget = builder.content.appendChild(document.createElement("span")); }
widget.setAttribute("cm-marker", marker.id);
}
if (widget) {
builder.cm.display.input.setUneditable(widget);
builder.content.appendChild(widget);
}
builder.pos += size;
builder.trailingSpace = false;
}
// Outputs a number of spans to make up a line, taking highlighting
// and marked text into account.
function insertLineContent(line, builder, styles) {
var spans = line.markedSpans, allText = line.text, at = 0;
if (!spans) {
for (var i$1 = 1; i$1 < styles.length; i$1+=2)
{ builder.addToken(builder, allText.slice(at, at = styles[i$1]), interpretTokenStyle(styles[i$1+1], builder.cm.options)); }
return
}
var len = allText.length, pos = 0, i = 1, text = "", style, css;
var nextChange = 0, spanStyle, spanEndStyle, spanStartStyle, collapsed, attributes;
for (;;) {
if (nextChange == pos) { // Update current marker set
spanStyle = spanEndStyle = spanStartStyle = css = "";
attributes = null;
collapsed = null; nextChange = Infinity;
var foundBookmarks = [], endStyles = (void 0);
for (var j = 0; j < spans.length; ++j) {
var sp = spans[j], m = sp.marker;
if (m.type == "bookmark" && sp.from == pos && m.widgetNode) {
foundBookmarks.push(m);
} else if (sp.from <= pos && (sp.to == null || sp.to > pos || m.collapsed && sp.to == pos && sp.from == pos)) {
if (sp.to != null && sp.to != pos && nextChange > sp.to) {
nextChange = sp.to;
spanEndStyle = "";
}
if (m.className) { spanStyle += " " + m.className; }
if (m.css) { css = (css ? css + ";" : "") + m.css; }
if (m.startStyle && sp.from == pos) { spanStartStyle += " " + m.startStyle; }
if (m.endStyle && sp.to == nextChange) { (endStyles || (endStyles = [])).push(m.endStyle, sp.to); }
// support for the old title property
// https://github.com/codemirror/CodeMirror/pull/5673
if (m.title) { (attributes || (attributes = {})).title = m.title; }
if (m.attributes) {
for (var attr in m.attributes)
{ (attributes || (attributes = {}))[attr] = m.attributes[attr]; }
}
if (m.collapsed && (!collapsed || compareCollapsedMarkers(collapsed.marker, m) < 0))
{ collapsed = sp; }
} else if (sp.from > pos && nextChange > sp.from) {
nextChange = sp.from;
}
}
if (endStyles) { for (var j$1 = 0; j$1 < endStyles.length; j$1 += 2)
{ if (endStyles[j$1 + 1] == nextChange) { spanEndStyle += " " + endStyles[j$1]; } } }
if (!collapsed || collapsed.from == pos) { for (var j$2 = 0; j$2 < foundBookmarks.length; ++j$2)
{ buildCollapsedSpan(builder, 0, foundBookmarks[j$2]); } }
if (collapsed && (collapsed.from || 0) == pos) {
buildCollapsedSpan(builder, (collapsed.to == null ? len + 1 : collapsed.to) - pos,
collapsed.marker, collapsed.from == null);
if (collapsed.to == null) { return }
if (collapsed.to == pos) { collapsed = false; }
}
}
if (pos >= len) { break }
var upto = Math.min(len, nextChange);
while (true) {
if (text) {
var end = pos + text.length;
if (!collapsed) {
var tokenText = end > upto ? text.slice(0, upto - pos) : text;
builder.addToken(builder, tokenText, style ? style + spanStyle : spanStyle,
spanStartStyle, pos + tokenText.length == nextChange ? spanEndStyle : "", css, attributes);
}
if (end >= upto) {text = text.slice(upto - pos); pos = upto; break}
pos = end;
spanStartStyle = "";
}
text = allText.slice(at, at = styles[i++]);
style = interpretTokenStyle(styles[i++], builder.cm.options);
}
}
}
// These objects are used to represent the visible (currently drawn)
// part of the document. A LineView may correspond to multiple
// logical lines, if those are connected by collapsed ranges.
function LineView(doc, line, lineN) {
// The starting line
this.line = line;
// Continuing lines, if any
this.rest = visualLineContinued(line);
// Number of logical lines in this visual line
this.size = this.rest ? lineNo(lst(this.rest)) - lineN + 1 : 1;
this.node = this.text = null;
this.hidden = lineIsHidden(doc, line);
}
// Create a range of LineView objects for the given lines.
function buildViewArray(cm, from, to) {
var array = [], nextPos;
for (var pos = from; pos < to; pos = nextPos) {
var view = new LineView(cm.doc, getLine(cm.doc, pos), pos);
nextPos = pos + view.size;
array.push(view);
}
return array
}
var operationGroup = null;
function pushOperation(op) {
if (operationGroup) {
operationGroup.ops.push(op);
} else {
op.ownsGroup = operationGroup = {
ops: [op],
delayedCallbacks: []
};
}
}
function fireCallbacksForOps(group) {
// Calls delayed callbacks and cursorActivity handlers until no
// new ones appear
var callbacks = group.delayedCallbacks, i = 0;
do {
for (; i < callbacks.length; i++)
{ callbacks[i].call(null); }
for (var j = 0; j < group.ops.length; j++) {
var op = group.ops[j];
if (op.cursorActivityHandlers)
{ while (op.cursorActivityCalled < op.cursorActivityHandlers.length)
{ op.cursorActivityHandlers[op.cursorActivityCalled++].call(null, op.cm); } }
}
} while (i < callbacks.length)
}
function finishOperation(op, endCb) {
var group = op.ownsGroup;
if (!group) { return }
try { fireCallbacksForOps(group); }
finally {
operationGroup = null;
endCb(group);
}
}
var orphanDelayedCallbacks = null;
// Often, we want to signal events at a point where we are in the
// middle of some work, but don't want the handler to start calling
// other methods on the editor, which might be in an inconsistent
// state or simply not expect any other events to happen.
// signalLater looks whether there are any handlers, and schedules
// them to be executed when the last operation ends, or, if no
// operation is active, when a timeout fires.
function signalLater(emitter, type /*, values...*/) {
var arr = getHandlers(emitter, type);
if (!arr.length) { return }
var args = Array.prototype.slice.call(arguments, 2), list;
if (operationGroup) {
list = operationGroup.delayedCallbacks;
} else if (orphanDelayedCallbacks) {
list = orphanDelayedCallbacks;
} else {
list = orphanDelayedCallbacks = [];
setTimeout(fireOrphanDelayed, 0);
}
var loop = function ( i ) {
list.push(function () { return arr[i].apply(null, args); });
};
for (var i = 0; i < arr.length; ++i)
loop( i );
}
function fireOrphanDelayed() {
var delayed = orphanDelayedCallbacks;
orphanDelayedCallbacks = null;
for (var i = 0; i < delayed.length; ++i) { delayed[i](); }
}
// When an aspect of a line changes, a string is added to
// lineView.changes. This updates the relevant part of the line's
// DOM structure.
function updateLineForChanges(cm, lineView, lineN, dims) {
for (var j = 0; j < lineView.changes.length; j++) {
var type = lineView.changes[j];
if (type == "text") { updateLineText(cm, lineView); }
else if (type == "gutter") { updateLineGutter(cm, lineView, lineN, dims); }
else if (type == "class") { updateLineClasses(cm, lineView); }
else if (type == "widget") { updateLineWidgets(cm, lineView, dims); }
}
lineView.changes = null;
}
// Lines with gutter elements, widgets or a background class need to
// be wrapped, and have the extra elements added to the wrapper div
function ensureLineWrapped(lineView) {
if (lineView.node == lineView.text) {
lineView.node = elt("div", null, null, "position: relative");
if (lineView.text.parentNode)
{ lineView.text.parentNode.replaceChild(lineView.node, lineView.text); }
lineView.node.appendChild(lineView.text);
if (ie && ie_version < 8) { lineView.node.style.zIndex = 2; }
}
return lineView.node
}
function updateLineBackground(cm, lineView) {
var cls = lineView.bgClass ? lineView.bgClass + " " + (lineView.line.bgClass || "") : lineView.line.bgClass;
if (cls) { cls += " CodeMirror-linebackground"; }
if (lineView.background) {
if (cls) { lineView.background.className = cls; }
else { lineView.background.parentNode.removeChild(lineView.background); lineView.background = null; }
} else if (cls) {
var wrap = ensureLineWrapped(lineView);
lineView.background = wrap.insertBefore(elt("div", null, cls), wrap.firstChild);
cm.display.input.setUneditable(lineView.background);
}
}
// Wrapper around buildLineContent which will reuse the structure
// in display.externalMeasured when possible.
function getLineContent(cm, lineView) {
var ext = cm.display.externalMeasured;
if (ext && ext.line == lineView.line) {
cm.display.externalMeasured = null;
lineView.measure = ext.measure;
return ext.built
}
return buildLineContent(cm, lineView)
}
// Redraw the line's text. Interacts with the background and text
// classes because the mode may output tokens that influence these
// classes.
function updateLineText(cm, lineView) {
var cls = lineView.text.className;
var built = getLineContent(cm, lineView);
if (lineView.text == lineView.node) { lineView.node = built.pre; }
lineView.text.parentNode.replaceChild(built.pre, lineView.text);
lineView.text = built.pre;
if (built.bgClass != lineView.bgClass || built.textClass != lineView.textClass) {
lineView.bgClass = built.bgClass;
lineView.textClass = built.textClass;
updateLineClasses(cm, lineView);
} else if (cls) {
lineView.text.className = cls;
}
}
function updateLineClasses(cm, lineView) {
updateLineBackground(cm, lineView);
if (lineView.line.wrapClass)
{ ensureLineWrapped(lineView).className = lineView.line.wrapClass; }
else if (lineView.node != lineView.text)
{ lineView.node.className = ""; }
var textClass = lineView.textClass ? lineView.textClass + " " + (lineView.line.textClass || "") : lineView.line.textClass;
lineView.text.className = textClass || "";
}
function updateLineGutter(cm, lineView, lineN, dims) {
if (lineView.gutter) {
lineView.node.removeChild(lineView.gutter);
lineView.gutter = null;
}
if (lineView.gutterBackground) {
lineView.node.removeChild(lineView.gutterBackground);
lineView.gutterBackground = null;
}
if (lineView.line.gutterClass) {
var wrap = ensureLineWrapped(lineView);
lineView.gutterBackground = elt("div", null, "CodeMirror-gutter-background " + lineView.line.gutterClass,
("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px; width: " + (dims.gutterTotalWidth) + "px"));
cm.display.input.setUneditable(lineView.gutterBackground);
wrap.insertBefore(lineView.gutterBackground, lineView.text);
}
var markers = lineView.line.gutterMarkers;
if (cm.options.lineNumbers || markers) {
var wrap$1 = ensureLineWrapped(lineView);
var gutterWrap = lineView.gutter = elt("div", null, "CodeMirror-gutter-wrapper", ("left: " + (cm.options.fixedGutter ? dims.fixedPos : -dims.gutterTotalWidth) + "px"));
cm.display.input.setUneditable(gutterWrap);
wrap$1.insertBefore(gutterWrap, lineView.text);
if (lineView.line.gutterClass)
{ gutterWrap.className += " " + lineView.line.gutterClass; }
if (cm.options.lineNumbers && (!markers || !markers["CodeMirror-linenumbers"]))
{ lineView.lineNumber = gutterWrap.appendChild(
elt("div", lineNumberFor(cm.options, lineN),
"CodeMirror-linenumber CodeMirror-gutter-elt",
("left: " + (dims.gutterLeft["CodeMirror-linenumbers"]) + "px; width: " + (cm.display.lineNumInnerWidth) + "px"))); }
if (markers) { for (var k = 0; k < cm.options.gutters.length; ++k) {
var id = cm.options.gutters[k], found = markers.hasOwnProperty(id) && markers[id];
if (found)
{ gutterWrap.appendChild(elt("div", [found], "CodeMirror-gutter-elt",
("left: " + (dims.gutterLeft[id]) + "px; width: " + (dims.gutterWidth[id]) + "px"))); }
} }
}
}
function updateLineWidgets(cm, lineView, dims) {
if (lineView.alignable) { lineView.alignable = null; }
for (var node = lineView.node.firstChild, next = (void 0); node; node = next) {
next = node.nextSibling;
if (node.className == "CodeMirror-linewidget")
{ lineView.node.removeChild(node); }
}
insertLineWidgets(cm, lineView, dims);
}
// Build a line's DOM representation from scratch
function buildLineElement(cm, lineView, lineN, dims) {
var built = getLineContent(cm, lineView);
lineView.text = lineView.node = built.pre;
if (built.bgClass) { lineView.bgClass = built.bgClass; }
if (built.textClass) { lineView.textClass = built.textClass; }
updateLineClasses(cm, lineView);
updateLineGutter(cm, lineView, lineN, dims);
insertLineWidgets(cm, lineView, dims);
return lineView.node
}
// A lineView may contain multiple logical lines (when merged by
// collapsed spans). The widgets for all of them need to be drawn.
function insertLineWidgets(cm, lineView, dims) {
insertLineWidgetsFor(cm, lineView.line, lineView, dims, true);
if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
{ insertLineWidgetsFor(cm, lineView.rest[i], lineView, dims, false); } }
}
function insertLineWidgetsFor(cm, line, lineView, dims, allowAbove) {
if (!line.widgets) { return }
var wrap = ensureLineWrapped(lineView);
for (var i = 0, ws = line.widgets; i < ws.length; ++i) {
var widget = ws[i], node = elt("div", [widget.node], "CodeMirror-linewidget");
if (!widget.handleMouseEvents) { node.setAttribute("cm-ignore-events", "true"); }
positionLineWidget(widget, node, lineView, dims);
cm.display.input.setUneditable(node);
if (allowAbove && widget.above)
{ wrap.insertBefore(node, lineView.gutter || lineView.text); }
else
{ wrap.appendChild(node); }
signalLater(widget, "redraw");
}
}
function positionLineWidget(widget, node, lineView, dims) {
if (widget.noHScroll) {
(lineView.alignable || (lineView.alignable = [])).push(node);
var width = dims.wrapperWidth;
node.style.left = dims.fixedPos + "px";
if (!widget.coverGutter) {
width -= dims.gutterTotalWidth;
node.style.paddingLeft = dims.gutterTotalWidth + "px";
}
node.style.width = width + "px";
}
if (widget.coverGutter) {
node.style.zIndex = 5;
node.style.position = "relative";
if (!widget.noHScroll) { node.style.marginLeft = -dims.gutterTotalWidth + "px"; }
}
}
function widgetHeight(widget) {
if (widget.height != null) { return widget.height }
var cm = widget.doc.cm;
if (!cm) { return 0 }
if (!contains(document.body, widget.node)) {
var parentStyle = "position: relative;";
if (widget.coverGutter)
{ parentStyle += "margin-left: -" + cm.display.gutters.offsetWidth + "px;"; }
if (widget.noHScroll)
{ parentStyle += "width: " + cm.display.wrapper.clientWidth + "px;"; }
removeChildrenAndAdd(cm.display.measure, elt("div", [widget.node], null, parentStyle));
}
return widget.height = widget.node.parentNode.offsetHeight
}
// Return true when the given mouse event happened in a widget
function eventInWidget(display, e) {
for (var n = e_target(e); n != display.wrapper; n = n.parentNode) {
if (!n || (n.nodeType == 1 && n.getAttribute("cm-ignore-events") == "true") ||
(n.parentNode == display.sizer && n != display.mover))
{ return true }
}
}
// POSITION MEASUREMENT
function paddingTop(display) {return display.lineSpace.offsetTop}
function paddingVert(display) {return display.mover.offsetHeight - display.lineSpace.offsetHeight}
function paddingH(display) {
if (display.cachedPaddingH) { return display.cachedPaddingH }
var e = removeChildrenAndAdd(display.measure, elt("pre", "x"));
var style = window.getComputedStyle ? window.getComputedStyle(e) : e.currentStyle;
var data = {left: parseInt(style.paddingLeft), right: parseInt(style.paddingRight)};
if (!isNaN(data.left) && !isNaN(data.right)) { display.cachedPaddingH = data; }
return data
}
function scrollGap(cm) { return scrollerGap - cm.display.nativeBarWidth }
function displayWidth(cm) {
return cm.display.scroller.clientWidth - scrollGap(cm) - cm.display.barWidth
}
function displayHeight(cm) {
return cm.display.scroller.clientHeight - scrollGap(cm) - cm.display.barHeight
}
// Ensure the lineView.wrapping.heights array is populated. This is
// an array of bottom offsets for the lines that make up a drawn
// line. When lineWrapping is on, there might be more than one
// height.
function ensureLineHeights(cm, lineView, rect) {
var wrapping = cm.options.lineWrapping;
var curWidth = wrapping && displayWidth(cm);
if (!lineView.measure.heights || wrapping && lineView.measure.width != curWidth) {
var heights = lineView.measure.heights = [];
if (wrapping) {
lineView.measure.width = curWidth;
var rects = lineView.text.firstChild.getClientRects();
for (var i = 0; i < rects.length - 1; i++) {
var cur = rects[i], next = rects[i + 1];
if (Math.abs(cur.bottom - next.bottom) > 2)
{ heights.push((cur.bottom + next.top) / 2 - rect.top); }
}
}
heights.push(rect.bottom - rect.top);
}
}
// Find a line map (mapping character offsets to text nodes) and a
// measurement cache for the given line number. (A line view might
// contain multiple lines when collapsed ranges are present.)
function mapFromLineView(lineView, line, lineN) {
if (lineView.line == line)
{ return {map: lineView.measure.map, cache: lineView.measure.cache} }
for (var i = 0; i < lineView.rest.length; i++)
{ if (lineView.rest[i] == line)
{ return {map: lineView.measure.maps[i], cache: lineView.measure.caches[i]} } }
for (var i$1 = 0; i$1 < lineView.rest.length; i$1++)
{ if (lineNo(lineView.rest[i$1]) > lineN)
{ return {map: lineView.measure.maps[i$1], cache: lineView.measure.caches[i$1], before: true} } }
}
// Render a line into the hidden node display.externalMeasured. Used
// when measurement is needed for a line that's not in the viewport.
function updateExternalMeasurement(cm, line) {
line = visualLine(line);
var lineN = lineNo(line);
var view = cm.display.externalMeasured = new LineView(cm.doc, line, lineN);
view.lineN = lineN;
var built = view.built = buildLineContent(cm, view);
view.text = built.pre;
removeChildrenAndAdd(cm.display.lineMeasure, built.pre);
return view
}
// Get a {top, bottom, left, right} box (in line-local coordinates)
// for a given character.
function measureChar(cm, line, ch, bias) {
return measureCharPrepared(cm, prepareMeasureForLine(cm, line), ch, bias)
}
// Find a line view that corresponds to the given line number.
function findViewForLine(cm, lineN) {
if (lineN >= cm.display.viewFrom && lineN < cm.display.viewTo)
{ return cm.display.view[findViewIndex(cm, lineN)] }
var ext = cm.display.externalMeasured;
if (ext && lineN >= ext.lineN && lineN < ext.lineN + ext.size)
{ return ext }
}
// Measurement can be split in two steps, the set-up work that
// applies to the whole line, and the measurement of the actual
// character. Functions like coordsChar, that need to do a lot of
// measurements in a row, can thus ensure that the set-up work is
// only done once.
function prepareMeasureForLine(cm, line) {
var lineN = lineNo(line);
var view = findViewForLine(cm, lineN);
if (view && !view.text) {
view = null;
} else if (view && view.changes) {
updateLineForChanges(cm, view, lineN, getDimensions(cm));
cm.curOp.forceUpdate = true;
}
if (!view)
{ view = updateExternalMeasurement(cm, line); }
var info = mapFromLineView(view, line, lineN);
return {
line: line, view: view, rect: null,
map: info.map, cache: info.cache, before: info.before,
hasHeights: false
}
}
// Given a prepared measurement object, measures the position of an
// actual character (or fetches it from the cache).
function measureCharPrepared(cm, prepared, ch, bias, varHeight) {
if (prepared.before) { ch = -1; }
var key = ch + (bias || ""), found;
if (prepared.cache.hasOwnProperty(key)) {
found = prepared.cache[key];
} else {
if (!prepared.rect)
{ prepared.rect = prepared.view.text.getBoundingClientRect(); }
if (!prepared.hasHeights) {
ensureLineHeights(cm, prepared.view, prepared.rect);
prepared.hasHeights = true;
}
found = measureCharInner(cm, prepared, ch, bias);
if (!found.bogus) { prepared.cache[key] = found; }
}
return {left: found.left, right: found.right,
top: varHeight ? found.rtop : found.top,
bottom: varHeight ? found.rbottom : found.bottom}
}
var nullRect = {left: 0, right: 0, top: 0, bottom: 0};
function nodeAndOffsetInLineMap(map$$1, ch, bias) {
var node, start, end, collapse, mStart, mEnd;
// First, search the line map for the text node corresponding to,
// or closest to, the target character.
for (var i = 0; i < map$$1.length; i += 3) {
mStart = map$$1[i];
mEnd = map$$1[i + 1];
if (ch < mStart) {
start = 0; end = 1;
collapse = "left";
} else if (ch < mEnd) {
start = ch - mStart;
end = start + 1;
} else if (i == map$$1.length - 3 || ch == mEnd && map$$1[i + 3] > ch) {
end = mEnd - mStart;
start = end - 1;
if (ch >= mEnd) { collapse = "right"; }
}
if (start != null) {
node = map$$1[i + 2];
if (mStart == mEnd && bias == (node.insertLeft ? "left" : "right"))
{ collapse = bias; }
if (bias == "left" && start == 0)
{ while (i && map$$1[i - 2] == map$$1[i - 3] && map$$1[i - 1].insertLeft) {
node = map$$1[(i -= 3) + 2];
collapse = "left";
} }
if (bias == "right" && start == mEnd - mStart)
{ while (i < map$$1.length - 3 && map$$1[i + 3] == map$$1[i + 4] && !map$$1[i + 5].insertLeft) {
node = map$$1[(i += 3) + 2];
collapse = "right";
} }
break
}
}
return {node: node, start: start, end: end, collapse: collapse, coverStart: mStart, coverEnd: mEnd}
}
function getUsefulRect(rects, bias) {
var rect = nullRect;
if (bias == "left") { for (var i = 0; i < rects.length; i++) {
if ((rect = rects[i]).left != rect.right) { break }
} } else { for (var i$1 = rects.length - 1; i$1 >= 0; i$1--) {
if ((rect = rects[i$1]).left != rect.right) { break }
} }
return rect
}
function measureCharInner(cm, prepared, ch, bias) {
var place = nodeAndOffsetInLineMap(prepared.map, ch, bias);
var node = place.node, start = place.start, end = place.end, collapse = place.collapse;
var rect;
if (node.nodeType == 3) { // If it is a text node, use a range to retrieve the coordinates.
for (var i$1 = 0; i$1 < 4; i$1++) { // Retry a maximum of 4 times when nonsense rectangles are returned
while (start && isExtendingChar(prepared.line.text.charAt(place.coverStart + start))) { --start; }
while (place.coverStart + end < place.coverEnd && isExtendingChar(prepared.line.text.charAt(place.coverStart + end))) { ++end; }
if (ie && ie_version < 9 && start == 0 && end == place.coverEnd - place.coverStart)
{ rect = node.parentNode.getBoundingClientRect(); }
else
{ rect = getUsefulRect(range(node, start, end).getClientRects(), bias); }
if (rect.left || rect.right || start == 0) { break }
end = start;
start = start - 1;
collapse = "right";
}
if (ie && ie_version < 11) { rect = maybeUpdateRectForZooming(cm.display.measure, rect); }
} else { // If it is a widget, simply get the box for the whole widget.
if (start > 0) { collapse = bias = "right"; }
var rects;
if (cm.options.lineWrapping && (rects = node.getClientRects()).length > 1)
{ rect = rects[bias == "right" ? rects.length - 1 : 0]; }
else
{ rect = node.getBoundingClientRect(); }
}
if (ie && ie_version < 9 && !start && (!rect || !rect.left && !rect.right)) {
var rSpan = node.parentNode.getClientRects()[0];
if (rSpan)
{ rect = {left: rSpan.left, right: rSpan.left + charWidth(cm.display), top: rSpan.top, bottom: rSpan.bottom}; }
else
{ rect = nullRect; }
}
var rtop = rect.top - prepared.rect.top, rbot = rect.bottom - prepared.rect.top;
var mid = (rtop + rbot) / 2;
var heights = prepared.view.measure.heights;
var i = 0;
for (; i < heights.length - 1; i++)
{ if (mid < heights[i]) { break } }
var top = i ? heights[i - 1] : 0, bot = heights[i];
var result = {left: (collapse == "right" ? rect.right : rect.left) - prepared.rect.left,
right: (collapse == "left" ? rect.left : rect.right) - prepared.rect.left,
top: top, bottom: bot};
if (!rect.left && !rect.right) { result.bogus = true; }
if (!cm.options.singleCursorHeightPerLine) { result.rtop = rtop; result.rbottom = rbot; }
return result
}
// Work around problem with bounding client rects on ranges being
// returned incorrectly when zoomed on IE10 and below.
function maybeUpdateRectForZooming(measure, rect) {
if (!window.screen || screen.logicalXDPI == null ||
screen.logicalXDPI == screen.deviceXDPI || !hasBadZoomedRects(measure))
{ return rect }
var scaleX = screen.logicalXDPI / screen.deviceXDPI;
var scaleY = screen.logicalYDPI / screen.deviceYDPI;
return {left: rect.left * scaleX, right: rect.right * scaleX,
top: rect.top * scaleY, bottom: rect.bottom * scaleY}
}
function clearLineMeasurementCacheFor(lineView) {
if (lineView.measure) {
lineView.measure.cache = {};
lineView.measure.heights = null;
if (lineView.rest) { for (var i = 0; i < lineView.rest.length; i++)
{ lineView.measure.caches[i] = {}; } }
}
}
function clearLineMeasurementCache(cm) {
cm.display.externalMeasure = null;
removeChildren(cm.display.lineMeasure);
for (var i = 0; i < cm.display.view.length; i++)
{ clearLineMeasurementCacheFor(cm.display.view[i]); }
}
function clearCaches(cm) {
clearLineMeasurementCache(cm);
cm.display.cachedCharWidth = cm.display.cachedTextHeight = cm.display.cachedPaddingH = null;
if (!cm.options.lineWrapping) { cm.display.maxLineChanged = true; }
cm.display.lineNumChars = null;
}
function pageScrollX() {
// Work around https://bugs.chromium.org/p/chromium/issues/detail?id=489206
// which causes page_Offset and bounding client rects to use
// different reference viewports and invalidate our calculations.
if (chrome && android) { return -(document.body.getBoundingClientRect().left - parseInt(getComputedStyle(document.body).marginLeft)) }
return window.pageXOffset || (document.documentElement || document.body).scrollLeft
}
function pageScrollY() {
if (chrome && android) { return -(document.body.getBoundingClientRect().top - parseInt(getComputedStyle(document.body).marginTop)) }
return window.pageYOffset || (document.documentElement || document.body).scrollTop
}
function widgetTopHeight(lineObj) {
var height = 0;
if (lineObj.widgets) { for (var i = 0; i < lineObj.widgets.length; ++i) { if (lineObj.widgets[i].above)
{ height += widgetHeight(lineObj.widgets[i]); } } }
return height
}
// Converts a {top, bottom, left, right} box from line-local
// coordinates into another coordinate system. Context may be one of
// "line", "div" (display.lineDiv), "local"./null (editor), "window",
// or "page".
function intoCoordSystem(cm, lineObj, rect, context, includeWidgets) {
if (!includeWidgets) {
var height = widgetTopHeight(lineObj);
rect.top += height; rect.bottom += height;
}
if (context == "line") { return rect }
if (!context) { context = "local"; }
var yOff = heightAtLine(lineObj);
if (context == "local") { yOff += paddingTop(cm.display); }
else { yOff -= cm.display.viewOffset; }
if (context == "page" || context == "window") {
var lOff = cm.display.lineSpace.getBoundingClientRect();
yOff += lOff.top + (context == "window" ? 0 : pageScrollY());
var xOff = lOff.left + (context == "window" ? 0 : pageScrollX());
rect.left += xOff; rect.right += xOff;
}
rect.top += yOff; rect.bottom += yOff;
return rect
}
// Coverts a box from "div" coords to another coordinate system.
// Context may be "window", "page", "div", or "local"./null.
function fromCoordSystem(cm, coords, context) {
if (context == "div") { return coords }
var left = coords.left, top = coords.top;
// First move into "page" coordinate system
if (context == "page") {
left -= pageScrollX();
top -= pageScrollY();
} else if (context == "local" || !context) {
var localBox = cm.display.sizer.getBoundingClientRect();
left += localBox.left;
top += localBox.top;
}
var lineSpaceBox = cm.display.lineSpace.getBoundingClientRect();
return {left: left - lineSpaceBox.left, top: top - lineSpaceBox.top}
}
function charCoords(cm, pos, context, lineObj, bias) {
if (!lineObj) { lineObj = getLine(cm.doc, pos.line); }
return intoCoordSystem(cm, lineObj, measureChar(cm, lineObj, pos.ch, bias), context)
}
// Returns a box for a given cursor position, which may have an
// 'other' property containing the position of the secondary cursor
// on a bidi boundary.
// A cursor Pos(line, char, "before") is on the same visual line as `char - 1`
// and after `char - 1` in writing order of `char - 1`
// A cursor Pos(line, char, "after") is on the same visual line as `char`
// and before `char` in writing order of `char`
// Examples (upper-case letters are RTL, lower-case are LTR):
// Pos(0, 1, ...)
// before after
// ab a|b a|b
// aB a|B aB|
// Ab |Ab A|b
// AB B|A B|A
// Every position after the last character on a line is considered to stick
// to the last character on the line.
function cursorCoords(cm, pos, context, lineObj, preparedMeasure, varHeight) {
lineObj = lineObj || getLine(cm.doc, pos.line);
if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
function get(ch, right) {
var m = measureCharPrepared(cm, preparedMeasure, ch, right ? "right" : "left", varHeight);
if (right) { m.left = m.right; } else { m.right = m.left; }
return intoCoordSystem(cm, lineObj, m, context)
}
var order = getOrder(lineObj, cm.doc.direction), ch = pos.ch, sticky = pos.sticky;
if (ch >= lineObj.text.length) {
ch = lineObj.text.length;
sticky = "before";
} else if (ch <= 0) {
ch = 0;
sticky = "after";
}
if (!order) { return get(sticky == "before" ? ch - 1 : ch, sticky == "before") }
function getBidi(ch, partPos, invert) {
var part = order[partPos], right = part.level == 1;
return get(invert ? ch - 1 : ch, right != invert)
}
var partPos = getBidiPartAt(order, ch, sticky);
var other = bidiOther;
var val = getBidi(ch, partPos, sticky == "before");
if (other != null) { val.other = getBidi(ch, other, sticky != "before"); }
return val
}
// Used to cheaply estimate the coordinates for a position. Used for
// intermediate scroll updates.
function estimateCoords(cm, pos) {
var left = 0;
pos = clipPos(cm.doc, pos);
if (!cm.options.lineWrapping) { left = charWidth(cm.display) * pos.ch; }
var lineObj = getLine(cm.doc, pos.line);
var top = heightAtLine(lineObj) + paddingTop(cm.display);
return {left: left, right: left, top: top, bottom: top + lineObj.height}
}
// Positions returned by coordsChar contain some extra information.
// xRel is the relative x position of the input coordinates compared
// to the found position (so xRel > 0 means the coordinates are to
// the right of the character position, for example). When outside
// is true, that means the coordinates lie outside the line's
// vertical range.
function PosWithInfo(line, ch, sticky, outside, xRel) {
var pos = Pos(line, ch, sticky);
pos.xRel = xRel;
if (outside) { pos.outside = true; }
return pos
}
// Compute the character position closest to the given coordinates.
// Input must be lineSpace-local ("div" coordinate system).
function coordsChar(cm, x, y) {
var doc = cm.doc;
y += cm.display.viewOffset;
if (y < 0) { return PosWithInfo(doc.first, 0, null, true, -1) }
var lineN = lineAtHeight(doc, y), last = doc.first + doc.size - 1;
if (lineN > last)
{ return PosWithInfo(doc.first + doc.size - 1, getLine(doc, last).text.length, null, true, 1) }
if (x < 0) { x = 0; }
var lineObj = getLine(doc, lineN);
for (;;) {
var found = coordsCharInner(cm, lineObj, lineN, x, y);
var collapsed = collapsedSpanAround(lineObj, found.ch + (found.xRel > 0 ? 1 : 0));
if (!collapsed) { return found }
var rangeEnd = collapsed.find(1);
if (rangeEnd.line == lineN) { return rangeEnd }
lineObj = getLine(doc, lineN = rangeEnd.line);
}
}
function wrappedLineExtent(cm, lineObj, preparedMeasure, y) {
y -= widgetTopHeight(lineObj);
var end = lineObj.text.length;
var begin = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch - 1).bottom <= y; }, end, 0);
end = findFirst(function (ch) { return measureCharPrepared(cm, preparedMeasure, ch).top > y; }, begin, end);
return {begin: begin, end: end}
}
function wrappedLineExtentChar(cm, lineObj, preparedMeasure, target) {
if (!preparedMeasure) { preparedMeasure = prepareMeasureForLine(cm, lineObj); }
var targetTop = intoCoordSystem(cm, lineObj, measureCharPrepared(cm, preparedMeasure, target), "line").top;
return wrappedLineExtent(cm, lineObj, preparedMeasure, targetTop)
}
// Returns true if the given side of a box is after the given
// coordinates, in top-to-bottom, left-to-right order.
function boxIsAfter(box, x, y, left) {
return box.bottom <= y ? false : box.top > y ? true : (left ? box.left : box.right) > x
}
function coordsCharInner(cm, lineObj, lineNo$$1, x, y) {
// Move y into line-local coordinate space
y -= heightAtLine(lineObj);
var preparedMeasure = prepareMeasureForLine(cm, lineObj);
// When directly calling `measureCharPrepared`, we have to adjust
// for the widgets at this line.
var widgetHeight$$1 = widgetTopHeight(lineObj);
var begin = 0, end = lineObj.text.length, ltr = true;
var order = getOrder(lineObj, cm.doc.direction);
// If the line isn't plain left-to-right text, first figure out
// which bidi section the coordinates fall into.
if (order) {
var part = (cm.options.lineWrapping ? coordsBidiPartWrapped : coordsBidiPart)
(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y);
ltr = part.level != 1;
// The awkward -1 offsets are needed because findFirst (called
// on these below) will treat its first bound as inclusive,
// second as exclusive, but we want to actually address the
// characters in the part's range
begin = ltr ? part.from : part.to - 1;
end = ltr ? part.to : part.from - 1;
}
// A binary search to find the first character whose bounding box
// starts after the coordinates. If we run across any whose box wrap
// the coordinates, store that.
var chAround = null, boxAround = null;
var ch = findFirst(function (ch) {
var box = measureCharPrepared(cm, preparedMeasure, ch);
box.top += widgetHeight$$1; box.bottom += widgetHeight$$1;
if (!boxIsAfter(box, x, y, false)) { return false }
if (box.top <= y && box.left <= x) {
chAround = ch;
boxAround = box;
}
return true
}, begin, end);
var baseX, sticky, outside = false;
// If a box around the coordinates was found, use that
if (boxAround) {
// Distinguish coordinates nearer to the left or right side of the box
var atLeft = x - boxAround.left < boxAround.right - x, atStart = atLeft == ltr;
ch = chAround + (atStart ? 0 : 1);
sticky = atStart ? "after" : "before";
baseX = atLeft ? boxAround.left : boxAround.right;
} else {
// (Adjust for extended bound, if necessary.)
if (!ltr && (ch == end || ch == begin)) { ch++; }
// To determine which side to associate with, get the box to the
// left of the character and compare it's vertical position to the
// coordinates
sticky = ch == 0 ? "after" : ch == lineObj.text.length ? "before" :
(measureCharPrepared(cm, preparedMeasure, ch - (ltr ? 1 : 0)).bottom + widgetHeight$$1 <= y) == ltr ?
"after" : "before";
// Now get accurate coordinates for this place, in order to get a
// base X position
var coords = cursorCoords(cm, Pos(lineNo$$1, ch, sticky), "line", lineObj, preparedMeasure);
baseX = coords.left;
outside = y < coords.top || y >= coords.bottom;
}
ch = skipExtendingChars(lineObj.text, ch, 1);
return PosWithInfo(lineNo$$1, ch, sticky, outside, x - baseX)
}
function coordsBidiPart(cm, lineObj, lineNo$$1, preparedMeasure, order, x, y) {
// Bidi parts are sorted left-to-right, and in a non-line-wrapping
// situation, we can take this ordering to correspond to the visual
// ordering. This finds the first part whose end is after the given
// coordinates.
var index = findFirst(function (i) {
var part = order[i], ltr = part.level != 1;
return boxIsAfter(cursorCoords(cm, Pos(lineNo$$1, ltr ? part.to : part.from, ltr ? "before" : "after"),
"line", lineObj, preparedMeasure), x, y, true)
}, 0, order.length - 1);
var part = order[index];
// If this isn't the first part, the part's start is also after
// the coordinates, and the coordinates aren't on the same line as
// that start, move one part back.
if (index > 0) {
var ltr = part.level != 1;
var start = cursorCoords(cm, Pos(lineNo$$1, ltr ? part.from : part.to, ltr ? "after" : "before"),
"line", lineObj, preparedMeasure);
if (boxIsAfter(start, x, y, true) && start.top > y)
{ part = order[index - 1]; }
}
return part
}
function coordsBidiPartWrapped(cm, lineObj, _lineNo, preparedMeasure, order, x, y) {
// In a wrapped line, rtl text on wrapping boundaries can do things
// that don't correspond to the ordering in our `order` array at
// all, so a binary search doesn't work, and we want to return a
// part that only spans one line so that the binary search in
// coordsCharInner is safe. As such, we first find the extent of the
// wrapped line, and then do a flat search in which we discard any
// spans that aren't on the line.
var ref = wrappedLineExtent(cm, lineObj, preparedMeasure, y);
var begin = ref.begin;
var end = ref.end;
if (/\s/.test(lineObj.text.charAt(end - 1))) { end--; }
var part = null, closestDist = null;
for (var i = 0; i < order.length; i++) {
var p = order[i];
if (p.from >= end || p.to <= begin) { continue }
var ltr = p.level != 1;
var endX = measureCharPrepared(cm, preparedMeasure, ltr ? Math.min(end, p.to) - 1 : Math.max(begin, p.from)).right;
// Weigh against spans ending before this, so that they are only
// picked if nothing ends after
var dist = endX < x ? x - endX + 1e9 : endX - x;
if (!part || closestDist > dist) {
part = p;
closestDist = dist;
}
}
if (!part) { part = order[order.length - 1]; }
// Clip the part to the wrapped line.
if (part.from < begin) { part = {from: begin, to: part.to, level: part.level}; }
if (part.to > end) { part = {from: part.from, to: end, level: part.level}; }
return part
}
var measureText;
// Compute the default text height.
function textHeight(display) {
if (display.cachedTextHeight != null) { return display.cachedTextHeight }
if (measureText == null) {
measureText = elt("pre");
// Measure a bunch of lines, for browsers that compute
// fractional heights.
for (var i = 0; i < 49; ++i) {
measureText.appendChild(document.createTextNode("x"));
measureText.appendChild(elt("br"));
}
measureText.appendChild(document.createTextNode("x"));
}
removeChildrenAndAdd(display.measure, measureText);
var height = measureText.offsetHeight / 50;
if (height > 3) { display.cachedTextHeight = height; }
removeChildren(display.measure);
return height || 1
}
// Compute the default character width.
function charWidth(display) {
if (display.cachedCharWidth != null) { return display.cachedCharWidth }
var anchor = elt("span", "xxxxxxxxxx");
var pre = elt("pre", [anchor]);
removeChildrenAndAdd(display.measure, pre);
var rect = anchor.getBoundingClientRect(), width = (rect.right - rect.left) / 10;
if (width > 2) { display.cachedCharWidth = width; }
return width || 10
}
// Do a bulk-read of the DOM positions and sizes needed to draw the
// view, so that we don't interleave reading and writing to the DOM.
function getDimensions(cm) {
var d = cm.display, left = {}, width = {};
var gutterLeft = d.gutters.clientLeft;
for (var n = d.gutters.firstChild, i = 0; n; n = n.nextSibling, ++i) {
left[cm.options.gutters[i]] = n.offsetLeft + n.clientLeft + gutterLeft;
width[cm.options.gutters[i]] = n.clientWidth;
}
return {fixedPos: compensateForHScroll(d),
gutterTotalWidth: d.gutters.offsetWidth,
gutterLeft: left,
gutterWidth: width,
wrapperWidth: d.wrapper.clientWidth}
}
// Computes display.scroller.scrollLeft + display.gutters.offsetWidth,
// but using getBoundingClientRect to get a sub-pixel-accurate
// result.
function compensateForHScroll(display) {
return display.scroller.getBoundingClientRect().left - display.sizer.getBoundingClientRect().left
}
// Returns a function that estimates the height of a line, to use as
// first approximation until the line becomes visible (and is thus
// properly measurable).
function estimateHeight(cm) {
var th = textHeight(cm.display), wrapping = cm.options.lineWrapping;
var perLine = wrapping && Math.max(5, cm.display.scroller.clientWidth / charWidth(cm.display) - 3);
return function (line) {
if (lineIsHidden(cm.doc, line)) { return 0 }
var widgetsHeight = 0;
if (line.widgets) { for (var i = 0; i < line.widgets.length; i++) {
if (line.widgets[i].height) { widgetsHeight += line.widgets[i].height; }
} }
if (wrapping)
{ return widgetsHeight + (Math.ceil(line.text.length / perLine) || 1) * th }
else
{ return widgetsHeight + th }
}
}
function estimateLineHeights(cm) {
var doc = cm.doc, est = estimateHeight(cm);
doc.iter(function (line) {
var estHeight = est(line);
if (estHeight != line.height) { updateLineHeight(line, estHeight); }
});
}
// Given a mouse event, find the corresponding position. If liberal
// is false, it checks whether a gutter or scrollbar was clicked,
// and returns null if it was. forRect is used by rectangular
// selections, and tries to estimate a character position even for
// coordinates beyond the right of the text.
function posFromMouse(cm, e, liberal, forRect) {
var display = cm.display;
if (!liberal && e_target(e).getAttribute("cm-not-content") == "true") { return null }
var x, y, space = display.lineSpace.getBoundingClientRect();
// Fails unpredictably on IE[67] when mouse is dragged around quickly.
try { x = e.clientX - space.left; y = e.clientY - space.top; }
catch (e) { return null }
var coords = coordsChar(cm, x, y), line;
if (forRect && coords.xRel == 1 && (line = getLine(cm.doc, coords.line).text).length == coords.ch) {
var colDiff = countColumn(line, line.length, cm.options.tabSize) - line.length;
coords = Pos(coords.line, Math.max(0, Math.round((x - paddingH(cm.display).left) / charWidth(cm.display)) - colDiff));
}
return coords
}
// Find the view element corresponding to a given line. Return null
// when the line isn't visible.
function findViewIndex(cm, n) {
if (n >= cm.display.viewTo) { return null }
n -= cm.display.viewFrom;
if (n < 0) { return null }
var view = cm.display.view;
for (var i = 0; i < view.length; i++) {
n -= view[i].size;
if (n < 0) { return i }
}
}
function updateSelection(cm) {
cm.display.input.showSelection(cm.display.input.prepareSelection());
}
function prepareSelection(cm, primary) {
if ( primary === void 0 ) primary = true;
var doc = cm.doc, result = {};
var curFragment = result.cursors = document.createDocumentFragment();
var selFragment = result.selection = document.createDocumentFragment();
for (var i = 0; i < doc.sel.ranges.length; i++) {
if (!primary && i == doc.sel.primIndex) { continue }
var range$$1 = doc.sel.ranges[i];
if (range$$1.from().line >= cm.display.viewTo || range$$1.to().line < cm.display.viewFrom) { continue }
var collapsed = range$$1.empty();
if (collapsed || cm.options.showCursorWhenSelecting)
{ drawSelectionCursor(cm, range$$1.head, curFragment); }
if (!collapsed)
{ drawSelectionRange(cm, range$$1, selFragment); }
}
return result
}
// Draws a cursor for the given range
function drawSelectionCursor(cm, head, output) {
var pos = cursorCoords(cm, head, "div", null, null, !cm.options.singleCursorHeightPerLine);
var cursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor"));
cursor.style.left = pos.left + "px";
cursor.style.top = pos.top + "px";
cursor.style.height = Math.max(0, pos.bottom - pos.top) * cm.options.cursorHeight + "px";
if (pos.other) {
// Secondary cursor, shown when on a 'jump' in bi-directional text
var otherCursor = output.appendChild(elt("div", "\u00a0", "CodeMirror-cursor CodeMirror-secondarycursor"));
otherCursor.style.display = "";
otherCursor.style.left = pos.other.left + "px";
otherCursor.style.top = pos.other.top + "px";
otherCursor.style.height = (pos.other.bottom - pos.other.top) * .85 + "px";
}
}
function cmpCoords(a, b) { return a.top - b.top || a.left - b.left }
// Draws the given range as a highlighted selection
function drawSelectionRange(cm, range$$1, output) {
var display = cm.display, doc = cm.doc;
var fragment = document.createDocumentFragment();
var padding = paddingH(cm.display), leftSide = padding.left;
var rightSide = Math.max(display.sizerWidth, displayWidth(cm) - display.sizer.offsetLeft) - padding.right;
var docLTR = doc.direction == "ltr";
function add(left, top, width, bottom) {
if (top < 0) { top = 0; }
top = Math.round(top);
bottom = Math.round(bottom);
fragment.appendChild(elt("div", null, "CodeMirror-selected", ("position: absolute; left: " + left + "px;\n top: " + top + "px; width: " + (width == null ? rightSide - left : width) + "px;\n height: " + (bottom - top) + "px")));
}
function drawForLine(line, fromArg, toArg) {
var lineObj = getLine(doc, line);
var lineLen = lineObj.text.length;
var start, end;
function coords(ch, bias) {
return charCoords(cm, Pos(line, ch), "div", lineObj, bias)
}
function wrapX(pos, dir, side) {
var extent = wrappedLineExtentChar(cm, lineObj, null, pos);
var prop = (dir == "ltr") == (side == "after") ? "left" : "right";
var ch = side == "after" ? extent.begin : extent.end - (/\s/.test(lineObj.text.charAt(extent.end - 1)) ? 2 : 1);
return coords(ch, prop)[prop]
}
var order = getOrder(lineObj, doc.direction);
iterateBidiSections(order, fromArg || 0, toArg == null ? lineLen : toArg, function (from, to, dir, i) {
var ltr = dir == "ltr";
var fromPos = coords(from, ltr ? "left" : "right");
var toPos = coords(to - 1, ltr ? "right" : "left");
var openStart = fromArg == null && from == 0, openEnd = toArg == null && to == lineLen;
var first = i == 0, last = !order || i == order.length - 1;
if (toPos.top - fromPos.top <= 3) { // Single line
var openLeft = (docLTR ? openStart : openEnd) && first;
var openRight = (docLTR ? openEnd : openStart) && last;
var left = openLeft ? leftSide : (ltr ? fromPos : toPos).left;
var right = openRight ? rightSide : (ltr ? toPos : fromPos).right;
add(left, fromPos.top, right - left, fromPos.bottom);
} else { // Multiple lines
var topLeft, topRight, botLeft, botRight;
if (ltr) {
topLeft = docLTR && openStart && first ? leftSide : fromPos.left;
topRight = docLTR ? rightSide : wrapX(from, dir, "before");
botLeft = docLTR ? leftSide : wrapX(to, dir, "after");
botRight = docLTR && openEnd && last ? rightSide : toPos.right;
} else {
topLeft = !docLTR ? leftSide : wrapX(from, dir, "before");
topRight = !docLTR && openStart && first ? rightSide : fromPos.right;
botLeft = !docLTR && openEnd && last ? leftSide : toPos.left;
botRight = !docLTR ? rightSide : wrapX(to, dir, "after");
}
add(topLeft, fromPos.top, topRight - topLeft, fromPos.bottom);
if (fromPos.bottom < toPos.top) { add(leftSide, fromPos.bottom, null, toPos.top); }
add(botLeft, toPos.top, botRight - botLeft, toPos.bottom);
}
if (!start || cmpCoords(fromPos, start) < 0) { start = fromPos; }
if (cmpCoords(toPos, start) < 0) { start = toPos; }
if (!end || cmpCoords(fromPos, end) < 0) { end = fromPos; }
if (cmpCoords(toPos, end) < 0) { end = toPos; }
});
return {start: start, end: end}
}
var sFrom = range$$1.from(), sTo = range$$1.to();
if (sFrom.line == sTo.line) {
drawForLine(sFrom.line, sFrom.ch, sTo.ch);
} else {
var fromLine = getLine(doc, sFrom.line), toLine = getLine(doc, sTo.line);
var singleVLine = visualLine(fromLine) == visualLine(toLine);
var leftEnd = drawForLine(sFrom.line, sFrom.ch, singleVLine ? fromLine.text.length + 1 : null).end;
var rightStart = drawForLine(sTo.line, singleVLine ? 0 : null, sTo.ch).start;
if (singleVLine) {
if (leftEnd.top < rightStart.top - 2) {
add(leftEnd.right, leftEnd.top, null, leftEnd.bottom);
add(leftSide, rightStart.top, rightStart.left, rightStart.bottom);
} else {
add(leftEnd.right, leftEnd.top, rightStart.left - leftEnd.right, leftEnd.bottom);
}
}
if (leftEnd.bottom < rightStart.top)
{ add(leftSide, leftEnd.bottom, null, rightStart.top); }
}
output.appendChild(fragment);
}
// Cursor-blinking
function restartBlink(cm) {
if (!cm.state.focused) { return }
var display = cm.display;
clearInterval(display.blinker);
var on = true;
display.cursorDiv.style.visibility = "";
if (cm.options.cursorBlinkRate > 0)
{ display.blinker = setInterval(function () { return display.cursorDiv.style.visibility = (on = !on) ? "" : "hidden"; },
cm.options.cursorBlinkRate); }
else if (cm.options.cursorBlinkRate < 0)
{ display.cursorDiv.style.visibility = "hidden"; }
}
function ensureFocus(cm) {
if (!cm.state.focused) { cm.display.input.focus(); onFocus(cm); }
}
function delayBlurEvent(cm) {
cm.state.delayingBlurEvent = true;
setTimeout(function () { if (cm.state.delayingBlurEvent) {
cm.state.delayingBlurEvent = false;
onBlur(cm);
} }, 100);
}
function onFocus(cm, e) {
if (cm.state.delayingBlurEvent) { cm.state.delayingBlurEvent = false; }
if (cm.options.readOnly == "nocursor") { return }
if (!cm.state.focused) {
signal(cm, "focus", cm, e);
cm.state.focused = true;
addClass(cm.display.wrapper, "CodeMirror-focused");
// This test prevents this from firing when a context
// menu is closed (since the input reset would kill the
// select-all detection hack)
if (!cm.curOp && cm.display.selForContextMenu != cm.doc.sel) {
cm.display.input.reset();
if (webkit) { setTimeout(function () { return cm.display.input.reset(true); }, 20); } // Issue #1730
}
cm.display.input.receivedFocus();
}
restartBlink(cm);
}
function onBlur(cm, e) {
if (cm.state.delayingBlurEvent) { return }
if (cm.state.focused) {
signal(cm, "blur", cm, e);
cm.state.focused = false;
rmClass(cm.display.wrapper, "CodeMirror-focused");
}
clearInterval(cm.display.blinker);
setTimeout(function () { if (!cm.state.focused) { cm.display.shift = false; } }, 150);
}
// Read the actual heights of the rendered lines, and update their
// stored heights to match.
function updateHeightsInViewport(cm) {
var display = cm.display;
var prevBottom = display.lineDiv.offsetTop;
for (var i = 0; i < display.view.length; i++) {
var cur = display.view[i], wrapping = cm.options.lineWrapping;
var height = (void 0), width = 0;
if (cur.hidden) { continue }
if (ie && ie_version < 8) {
var bot = cur.node.offsetTop + cur.node.offsetHeight;
height = bot - prevBottom;
prevBottom = bot;
} else {
var box = cur.node.getBoundingClientRect();
height = box.bottom - box.top;
// Check that lines don't extend past the right of the current
// editor width
if (!wrapping && cur.text.firstChild)
{ width = cur.text.firstChild.getBoundingClientRect().right - box.left - 1; }
}
var diff = cur.line.height - height;
if (height < 2) { height = textHeight(display); }
if (diff > .005 || diff < -.005) {
updateLineHeight(cur.line, height);
updateWidgetHeight(cur.line);
if (cur.rest) { for (var j = 0; j < cur.rest.length; j++)
{ updateWidgetHeight(cur.rest[j]); } }
}
if (width > cm.display.sizerWidth) {
var chWidth = Math.ceil(width / charWidth(cm.display));
if (chWidth > cm.display.maxLineLength) {
cm.display.maxLineLength = chWidth;
cm.display.maxLine = cur.line;
cm.display.maxLineChanged = true;
}
}
}
}
// Read and store the height of line widgets associated with the
// given line.
function updateWidgetHeight(line) {
if (line.widgets) { for (var i = 0; i < line.widgets.length; ++i) {
var w = line.widgets[i], parent = w.node.parentNode;
if (parent) { w.height = parent.offsetHeight; }
} }
}
// Compute the lines that are visible in a given viewport (defaults
// the the current scroll position). viewport may contain top,
// height, and ensure (see op.scrollToPos) properties.
function visibleLines(display, doc, viewport) {
var top = viewport && viewport.top != null ? Math.max(0, viewport.top) : display.scroller.scrollTop;
top = Math.floor(top - paddingTop(display));
var bottom = viewport && viewport.bottom != null ? viewport.bottom : top + display.wrapper.clientHeight;
var from = lineAtHeight(doc, top), to = lineAtHeight(doc, bottom);
// Ensure is a {from: {line, ch}, to: {line, ch}} object, and
// forces those lines into the viewport (if possible).
if (viewport && viewport.ensure) {
var ensureFrom = viewport.ensure.from.line, ensureTo = viewport.ensure.to.line;
if (ensureFrom < from) {
from = ensureFrom;
to = lineAtHeight(doc, heightAtLine(getLine(doc, ensureFrom)) + display.wrapper.clientHeight);
} else if (Math.min(ensureTo, doc.lastLine()) >= to) {
from = lineAtHeight(doc, heightAtLine(getLine(doc, ensureTo)) - display.wrapper.clientHeight);
to = ensureTo;
}
}
return {from: from, to: Math.max(to, from + 1)}
}
// Re-align line numbers and gutter marks to compensate for
// horizontal scrolling.
function alignHorizontally(cm) {
var display = cm.display, view = display.view;
if (!display.alignWidgets && (!display.gutters.firstChild || !cm.options.fixedGutter)) { return }
var comp = compensateForHScroll(display) - display.scroller.scrollLeft + cm.doc.scrollLeft;
var gutterW = display.gutters.offsetWidth, left = comp + "px";
for (var i = 0; i < view.length; i++) { if (!view[i].hidden) {
if (cm.options.fixedGutter) {
if (view[i].gutter)
{ view[i].gutter.style.left = left; }
if (view[i].gutterBackground)
{ view[i].gutterBackground.style.left = left; }
}
var align = view[i].alignable;
if (align) { for (var j = 0; j < align.length; j++)
{ align[j].style.left = left; } }
} }
if (cm.options.fixedGutter)
{ display.gutters.style.left = (comp + gutterW) + "px"; }
}
// Used to ensure that the line number gutter is still the right
// size for the current document size. Returns true when an update
// is needed.
function maybeUpdateLineNumberWidth(cm) {
if (!cm.options.lineNumbers) { return false }
var doc = cm.doc, last = lineNumberFor(cm.options, doc.first + doc.size - 1), display = cm.display;
if (last.length != display.lineNumChars) {
var test = display.measure.appendChild(elt("div", [elt("div", last)],
"CodeMirror-linenumber CodeMirror-gutter-elt"));
var innerW = test.firstChild.offsetWidth, padding = test.offsetWidth - innerW;
display.lineGutter.style.width = "";
display.lineNumInnerWidth = Math.max(innerW, display.lineGutter.offsetWidth - padding) + 1;
display.lineNumWidth = display.lineNumInnerWidth + padding;
display.lineNumChars = display.lineNumInnerWidth ? last.length : -1;
display.lineGutter.style.width = display.lineNumWidth + "px";
updateGutterSpace(cm);
return true
}
return false
}
// SCROLLING THINGS INTO VIEW
// If an editor sits on the top or bottom of the window, partially
// scrolled out of view, this ensures that the cursor is visible.
function maybeScrollWindow(cm, rect) {
if (signalDOMEvent(cm, "scrollCursorIntoView")) { return }
var display = cm.display, box = display.sizer.getBoundingClientRect(), doScroll = null;
if (rect.top + box.top < 0) { doScroll = true; }
else if (rect.bottom + box.top > (window.innerHeight || document.documentElement.clientHeight)) { doScroll = false; }
if (doScroll != null && !phantom) {
var scrollNode = elt("div", "\u200b", null, ("position: absolute;\n top: " + (rect.top - display.viewOffset - paddingTop(cm.display)) + "px;\n height: " + (rect.bottom - rect.top + scrollGap(cm) + display.barHeight) + "px;\n left: " + (rect.left) + "px; width: " + (Math.max(2, rect.right - rect.left)) + "px;"));
cm.display.lineSpace.appendChild(scrollNode);
scrollNode.scrollIntoView(doScroll);
cm.display.lineSpace.removeChild(scrollNode);
}
}
// Scroll a given position into view (immediately), verifying that
// it actually became visible (as line heights are accurately
// measured, the position of something may 'drift' during drawing).
function scrollPosIntoView(cm, pos, end, margin) {
if (margin == null) { margin = 0; }
var rect;
if (!cm.options.lineWrapping && pos == end) {
// Set pos and end to the cursor positions around the character pos sticks to
// If pos.sticky == "before", that is around pos.ch - 1, otherwise around pos.ch
// If pos == Pos(_, 0, "before"), pos and end are unchanged
pos = pos.ch ? Pos(pos.line, pos.sticky == "before" ? pos.ch - 1 : pos.ch, "after") : pos;
end = pos.sticky == "before" ? Pos(pos.line, pos.ch + 1, "before") : pos;
}
for (var limit = 0; limit < 5; limit++) {
var changed = false;
var coords = cursorCoords(cm, pos);
var endCoords = !end || end == pos ? coords : cursorCoords(cm, end);
rect = {left: Math.min(coords.left, endCoords.left),
top: Math.min(coords.top, endCoords.top) - margin,
right: Math.max(coords.left, endCoords.left),
bottom: Math.max(coords.bottom, endCoords.bottom) + margin};
var scrollPos = calculateScrollPos(cm, rect);
var startTop = cm.doc.scrollTop, startLeft = cm.doc.scrollLeft;
if (scrollPos.scrollTop != null) {
updateScrollTop(cm, scrollPos.scrollTop);
if (Math.abs(cm.doc.scrollTop - startTop) > 1) { changed = true; }
}
if (scrollPos.scrollLeft != null) {
setScrollLeft(cm, scrollPos.scrollLeft);
if (Math.abs(cm.doc.scrollLeft - startLeft) > 1) { changed = true; }
}
if (!changed) { break }
}
return rect
}
// Scroll a given set of coordinates into view (immediately).
function scrollIntoView(cm, rect) {
var scrollPos = calculateScrollPos(cm, rect);
if (scrollPos.scrollTop != null) { updateScrollTop(cm, scrollPos.scrollTop); }
if (scrollPos.scrollLeft != null) { setScrollLeft(cm, scrollPos.scrollLeft); }
}
// Calculate a new scroll position needed to scroll the given
// rectangle into view. Returns an object with scrollTop and
// scrollLeft properties. When these are undefined, the
// vertical/horizontal position does not need to be adjusted.
function calculateScrollPos(cm, rect) {
var display = cm.display, snapMargin = textHeight(cm.display);
if (rect.top < 0) { rect.top = 0; }
var screentop = cm.curOp && cm.curOp.scrollTop != null ? cm.curOp.scrollTop : display.scroller.scrollTop;
var screen = displayHeight(cm), result = {};
if (rect.bottom - rect.top > screen) { rect.bottom = rect.top + screen; }
var docBottom = cm.doc.height + paddingVert(display);
var atTop = rect.top < snapMargin, atBottom = rect.bottom > docBottom - snapMargin;
if (rect.top < screentop) {
result.scrollTop = atTop ? 0 : rect.top;
} else if (rect.bottom > screentop + screen) {
var newTop = Math.min(rect.top, (atBottom ? docBottom : rect.bottom) - screen);
if (newTop != screentop) { result.scrollTop = newTop; }
}
var screenleft = cm.curOp && cm.curOp.scrollLeft != null ? cm.curOp.scrollLeft : display.scroller.scrollLeft;
var screenw = displayWidth(cm) - (cm.options.fixedGutter ? display.gutters.offsetWidth : 0);
var tooWide = rect.right - rect.left > screenw;
if (tooWide) { rect.right = rect.left + screenw; }
if (rect.left < 10)
{ result.scrollLeft = 0; }
else if (rect.left < screenleft)
{ result.scrollLeft = Math.max(0, rect.left - (tooWide ? 0 : 10)); }
else if (rect.right > screenw + screenleft - 3)
{ result.scrollLeft = rect.right + (tooWide ? 0 : 10) - screenw; }
return result
}
// Store a relative adjustment to the scroll position in the current
// operation (to be applied when the operation finishes).
function addToScrollTop(cm, top) {
if (top == null) { return }
resolveScrollToPos(cm);
cm.curOp.scrollTop = (cm.curOp.scrollTop == null ? cm.doc.scrollTop : cm.curOp.scrollTop) + top;
}
// Make sure that at the end of the operation the current cursor is
// shown.
function ensureCursorVisible(cm) {
resolveScrollToPos(cm);
var cur = cm.getCursor();
cm.curOp.scrollToPos = {from: cur, to: cur, margin: cm.options.cursorScrollMargin};
}
function scrollToCoords(cm, x, y) {
if (x != null || y != null) { resolveScrollToPos(cm); }
if (x != null) { cm.curOp.scrollLeft = x; }
if (y != null) { cm.curOp.scrollTop = y; }
}
function scrollToRange(cm, range$$1) {
resolveScrollToPos(cm);
cm.curOp.scrollToPos = range$$1;
}
// When an operation has its scrollToPos property set, and another
// scroll action is applied before the end of the operation, this
// 'simulates' scrolling that position into view in a cheap way, so
// that the effect of intermediate scroll commands is not ignored.
function resolveScrollToPos(cm) {
var range$$1 = cm.curOp.scrollToPos;
if (range$$1) {
cm.curOp.scrollToPos = null;
var from = estimateCoords(cm, range$$1.from), to = estimateCoords(cm, range$$1.to);
scrollToCoordsRange(cm, from, to, range$$1.margin);
}
}
function scrollToCoordsRange(cm, from, to, margin) {
var sPos = calculateScrollPos(cm, {
left: Math.min(from.left, to.left),
top: Math.min(from.top, to.top) - margin,
right: Math.max(from.right, to.right),
bottom: Math.max(from.bottom, to.bottom) + margin
});
scrollToCoords(cm, sPos.scrollLeft, sPos.scrollTop);
}
// Sync the scrollable area and scrollbars, ensure the viewport
// covers the visible area.
function updateScrollTop(cm, val) {
if (Math.abs(cm.doc.scrollTop - val) < 2) { return }
if (!gecko) { updateDisplaySimple(cm, {top: val}); }
setScrollTop(cm, val, true);
if (gecko) { updateDisplaySimple(cm); }
startWorker(cm, 100);
}
function setScrollTop(cm, val, forceScroll) {
val = Math.min(cm.display.scroller.scrollHeight - cm.display.scroller.clientHeight, val);
if (cm.display.scroller.scrollTop == val && !forceScroll) { return }
cm.doc.scrollTop = val;
cm.display.scrollbars.setScrollTop(val);
if (cm.display.scroller.scrollTop != val) { cm.display.scroller.scrollTop = val; }
}
// Sync scroller and scrollbar, ensure the gutter elements are
// aligned.
function setScrollLeft(cm, val, isScroller, forceScroll) {
val = Math.min(val, cm.display.scroller.scrollWidth - cm.display.scroller.clientWidth);
if ((isScroller ? val == cm.doc.scrollLeft : Math.abs(cm.doc.scrollLeft - val) < 2) && !forceScroll) { return }
cm.doc.scrollLeft = val;
alignHorizontally(cm);
if (cm.display.scroller.scrollLeft != val) { cm.display.scroller.scrollLeft = val; }
cm.display.scrollbars.setScrollLeft(val);
}
// SCROLLBARS
// Prepare DOM reads needed to update the scrollbars. Done in one
// shot to minimize update/measure roundtrips.
function measureForScrollbars(cm) {
var d = cm.display, gutterW = d.gutters.offsetWidth;
var docH = Math.round(cm.doc.height + paddingVert(cm.display));
return {
clientHeight: d.scroller.clientHeight,
viewHeight: d.wrapper.clientHeight,
scrollWidth: d.scroller.scrollWidth, clientWidth: d.scroller.clientWidth,
viewWidth: d.wrapper.clientWidth,
barLeft: cm.options.fixedGutter ? gutterW : 0,
docHeight: docH,
scrollHeight: docH + scrollGap(cm) + d.barHeight,
nativeBarWidth: d.nativeBarWidth,
gutterWidth: gutterW
}
}
var NativeScrollbars = function(place, scroll, cm) {
this.cm = cm;
var vert = this.vert = elt("div", [elt("div", null, null, "min-width: 1px")], "CodeMirror-vscrollbar");
var horiz = this.horiz = elt("div", [elt("div", null, null, "height: 100%; min-height: 1px")], "CodeMirror-hscrollbar");
vert.tabIndex = horiz.tabIndex = -1;
place(vert); place(horiz);
on(vert, "scroll", function () {
if (vert.clientHeight) { scroll(vert.scrollTop, "vertical"); }
});
on(horiz, "scroll", function () {
if (horiz.clientWidth) { scroll(horiz.scrollLeft, "horizontal"); }
});
this.checkedZeroWidth = false;
// Need to set a minimum width to see the scrollbar on IE7 (but must not set it on IE8).
if (ie && ie_version < 8) { this.horiz.style.minHeight = this.vert.style.minWidth = "18px"; }
};
NativeScrollbars.prototype.update = function (measure) {
var needsH = measure.scrollWidth > measure.clientWidth + 1;
var needsV = measure.scrollHeight > measure.clientHeight + 1;
var sWidth = measure.nativeBarWidth;
if (needsV) {
this.vert.style.display = "block";
this.vert.style.bottom = needsH ? sWidth + "px" : "0";
var totalHeight = measure.viewHeight - (needsH ? sWidth : 0);
// A bug in IE8 can cause this value to be negative, so guard it.
this.vert.firstChild.style.height =
Math.max(0, measure.scrollHeight - measure.clientHeight + totalHeight) + "px";
} else {
this.vert.style.display = "";
this.vert.firstChild.style.height = "0";
}
if (needsH) {
this.horiz.style.display = "block";
this.horiz.style.right = needsV ? sWidth + "px" : "0";
this.horiz.style.left = measure.barLeft + "px";
var totalWidth = measure.viewWidth - measure.barLeft - (needsV ? sWidth : 0);
this.horiz.firstChild.style.width =
Math.max(0, measure.scrollWidth - measure.clientWidth + totalWidth) + "px";
} else {
this.horiz.style.display = "";
this.horiz.firstChild.style.width = "0";
}
if (!this.checkedZeroWidth && measure.clientHeight > 0) {
if (sWidth == 0) { this.zeroWidthHack(); }
this.checkedZeroWidth = true;
}
return {right: needsV ? sWidth : 0, bottom: needsH ? sWidth : 0}
};
NativeScrollbars.prototype.setScrollLeft = function (pos) {
if (this.horiz.scrollLeft != pos) { this.horiz.scrollLeft = pos; }
if (this.disableHoriz) { this.enableZeroWidthBar(this.horiz, this.disableHoriz, "horiz"); }
};
NativeScrollbars.prototype.setScrollTop = function (pos) {
if (this.vert.scrollTop != pos) { this.vert.scrollTop = pos; }
if (this.disableVert) { this.enableZeroWidthBar(this.vert, this.disableVert, "vert"); }
};
NativeScrollbars.prototype.zeroWidthHack = function () {
var w = mac && !mac_geMountainLion ? "12px" : "18px";
this.horiz.style.height = this.vert.style.width = w;
this.horiz.style.pointerEvents = this.vert.style.pointerEvents = "none";
this.disableHoriz = new Delayed;
this.disableVert = new Delayed;
};
NativeScrollbars.prototype.enableZeroWidthBar = function (bar, delay, type) {
bar.style.pointerEvents = "auto";
function maybeDisable() {
// To find out whether the scrollbar is still visible, we
// check whether the element under the pixel in the bottom
// right corner of the scrollbar box is the scrollbar box
// itself (when the bar is still visible) or its filler child
// (when the bar is hidden). If it is still visible, we keep
// it enabled, if it's hidden, we disable pointer events.
var box = bar.getBoundingClientRect();
var elt$$1 = type == "vert" ? document.elementFromPoint(box.right - 1, (box.top + box.bottom) / 2)
: document.elementFromPoint((box.right + box.left) / 2, box.bottom - 1);
if (elt$$1 != bar) { bar.style.pointerEvents = "none"; }
else { delay.set(1000, maybeDisable); }
}
delay.set(1000, maybeDisable);
};
NativeScrollbars.prototype.clear = function () {
var parent = this.horiz.parentNode;
parent.removeChild(this.horiz);
parent.removeChild(this.vert);
};
var NullScrollbars = function () {};
NullScrollbars.prototype.update = function () { return {bottom: 0, right: 0} };
NullScrollbars.prototype.setScrollLeft = function () {};
NullScrollbars.prototype.setScrollTop = function () {};
NullScrollbars.prototype.clear = function () {};
function updateScrollbars(cm, measure) {
if (!measure) { measure = measureForScrollbars(cm); }
var startWidth = cm.display.barWidth, startHeight = cm.display.barHeight;
updateScrollbarsInner(cm, measure);
for (var i = 0; i < 4 && startWidth != cm.display.barWidth || startHeight != cm.display.barHeight; i++) {
if (startWidth != cm.display.barWidth && cm.options.lineWrapping)
{ updateHeightsInViewport(cm); }
updateScrollbarsInner(cm, measureForScrollbars(cm));
startWidth = cm.display.barWidth; startHeight = cm.display.barHeight;
}
}
// Re-synchronize the fake scrollbars with the actual size of the
// content.
function updateScrollbarsInner(cm, measure) {
var d = cm.display;
var sizes = d.scrollbars.update(measure);
d.sizer.style.paddingRight = (d.barWidth = sizes.right) + "px";
d.sizer.style.paddingBottom = (d.barHeight = sizes.bottom) + "px";
d.heightForcer.style.borderBottom = sizes.bottom + "px solid transparent";
if (sizes.right && sizes.bottom) {
d.scrollbarFiller.style.display = "block";
d.scrollbarFiller.style.height = sizes.bottom + "px";
d.scrollbarFiller.style.width = sizes.right + "px";
} else { d.scrollbarFiller.style.display = ""; }
if (sizes.bottom && cm.options.coverGutterNextToScrollbar && cm.options.fixedGutter) {
d.gutterFiller.style.display = "block";
d.gutterFiller.style.height = sizes.bottom + "px";
d.gutterFiller.style.width = measure.gutterWidth + "px";
} else { d.gutterFiller.style.display = ""; }
}
var scrollbarModel = {"native": NativeScrollbars, "null": NullScrollbars};
function initScrollbars(cm) {
if (cm.display.scrollbars) {
cm.display.scrollbars.clear();
if (cm.display.scrollbars.addClass)
{ rmClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
}
cm.display.scrollbars = new scrollbarModel[cm.options.scrollbarStyle](function (node) {
cm.display.wrapper.insertBefore(node, cm.display.scrollbarFiller);
// Prevent clicks in the scrollbars from killing focus
on(node, "mousedown", function () {
if (cm.state.focused) { setTimeout(function () { return cm.display.input.focus(); }, 0); }
});
node.setAttribute("cm-not-content", "true");
}, function (pos, axis) {
if (axis == "horizontal") { setScrollLeft(cm, pos); }
else { updateScrollTop(cm, pos); }
}, cm);
if (cm.display.scrollbars.addClass)
{ addClass(cm.display.wrapper, cm.display.scrollbars.addClass); }
}
// Operations are used to wrap a series of changes to the editor
// state in such a way that each change won't have to update the
// cursor and display (which would be awkward, slow, and
// error-prone). Instead, display updates are batched and then all
// combined and executed at once.
var nextOpId = 0;
// Start a new operation.
function startOperation(cm) {
cm.curOp = {
cm: cm,
viewChanged: false, // Flag that indicates that lines might need to be redrawn
startHeight: cm.doc.height, // Used to detect need to update scrollbar
forceUpdate: false, // Used to force a redraw
updateInput: 0, // Whether to reset the input textarea
typing: false, // Whether this reset should be careful to leave existing text (for compositing)
changeObjs: null, // Accumulated changes, for firing change events
cursorActivityHandlers: null, // Set of handlers to fire cursorActivity on
cursorActivityCalled: 0, // Tracks which cursorActivity handlers have been called already
selectionChanged: false, // Whether the selection needs to be redrawn
updateMaxLine: false, // Set when the widest line needs to be determined anew
scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
scrollToPos: null, // Used to scroll to a specific position
focus: false,
id: ++nextOpId // Unique ID
};
pushOperation(cm.curOp);
}
// Finish an operation, updating the display and signalling delayed events
function endOperation(cm) {
var op = cm.curOp;
if (op) { finishOperation(op, function (group) {
for (var i = 0; i < group.ops.length; i++)
{ group.ops[i].cm.curOp = null; }
endOperations(group);
}); }
}
// The DOM updates done when an operation finishes are batched so
// that the minimum number of relayouts are required.
function endOperations(group) {
var ops = group.ops;
for (var i = 0; i < ops.length; i++) // Read DOM
{ endOperation_R1(ops[i]); }
for (var i$1 = 0; i$1 < ops.length; i$1++) // Write DOM (maybe)
{ endOperation_W1(ops[i$1]); }
for (var i$2 = 0; i$2 < ops.length; i$2++) // Read DOM
{ endOperation_R2(ops[i$2]); }
for (var i$3 = 0; i$3 < ops.length; i$3++) // Write DOM (maybe)
{ endOperation_W2(ops[i$3]); }
for (var i$4 = 0; i$4 < ops.length; i$4++) // Read DOM
{ endOperation_finish(ops[i$4]); }
}
function endOperation_R1(op) {
var cm = op.cm, display = cm.display;
maybeClipScrollbars(cm);
if (op.updateMaxLine) { findMaxLine(cm); }
op.mustUpdate = op.viewChanged || op.forceUpdate || op.scrollTop != null ||
op.scrollToPos && (op.scrollToPos.from.line < display.viewFrom ||
op.scrollToPos.to.line >= display.viewTo) ||
display.maxLineChanged && cm.options.lineWrapping;
op.update = op.mustUpdate &&
new DisplayUpdate(cm, op.mustUpdate && {top: op.scrollTop, ensure: op.scrollToPos}, op.forceUpdate);
}
function endOperation_W1(op) {
op.updatedDisplay = op.mustUpdate && updateDisplayIfNeeded(op.cm, op.update);
}
function endOperation_R2(op) {
var cm = op.cm, display = cm.display;
if (op.updatedDisplay) { updateHeightsInViewport(cm); }
op.barMeasure = measureForScrollbars(cm);
// If the max line changed since it was last measured, measure it,
// and ensure the document's width matches it.
// updateDisplay_W2 will use these properties to do the actual resizing
if (display.maxLineChanged && !cm.options.lineWrapping) {
op.adjustWidthTo = measureChar(cm, display.maxLine, display.maxLine.text.length).left + 3;
cm.display.sizerWidth = op.adjustWidthTo;
op.barMeasure.scrollWidth =
Math.max(display.scroller.clientWidth, display.sizer.offsetLeft + op.adjustWidthTo + scrollGap(cm) + cm.display.barWidth);
op.maxScrollLeft = Math.max(0, display.sizer.offsetLeft + op.adjustWidthTo - displayWidth(cm));
}
if (op.updatedDisplay || op.selectionChanged)
{ op.preparedSelection = display.input.prepareSelection(); }
}
function endOperation_W2(op) {
var cm = op.cm;
if (op.adjustWidthTo != null) {
cm.display.sizer.style.minWidth = op.adjustWidthTo + "px";
if (op.maxScrollLeft < cm.doc.scrollLeft)
{ setScrollLeft(cm, Math.min(cm.display.scroller.scrollLeft, op.maxScrollLeft), true); }
cm.display.maxLineChanged = false;
}
var takeFocus = op.focus && op.focus == activeElt();
if (op.preparedSelection)
{ cm.display.input.showSelection(op.preparedSelection, takeFocus); }
if (op.updatedDisplay || op.startHeight != cm.doc.height)
{ updateScrollbars(cm, op.barMeasure); }
if (op.updatedDisplay)
{ setDocumentHeight(cm, op.barMeasure); }
if (op.selectionChanged) { restartBlink(cm); }
if (cm.state.focused && op.updateInput)
{ cm.display.input.reset(op.typing); }
if (takeFocus) { ensureFocus(op.cm); }
}
function endOperation_finish(op) {
var cm = op.cm, display = cm.display, doc = cm.doc;
if (op.updatedDisplay) { postUpdateDisplay(cm, op.update); }
// Abort mouse wheel delta measurement, when scrolling explicitly
if (display.wheelStartX != null && (op.scrollTop != null || op.scrollLeft != null || op.scrollToPos))
{ display.wheelStartX = display.wheelStartY = null; }
// Propagate the scroll position to the actual DOM scroller
if (op.scrollTop != null) { setScrollTop(cm, op.scrollTop, op.forceScroll); }
if (op.scrollLeft != null) { setScrollLeft(cm, op.scrollLeft, true, true); }
// If we need to scroll a specific position into view, do so.
if (op.scrollToPos) {
var rect = scrollPosIntoView(cm, clipPos(doc, op.scrollToPos.from),
clipPos(doc, op.scrollToPos.to), op.scrollToPos.margin);
maybeScrollWindow(cm, rect);
}
// Fire events for markers that are hidden/unidden by editing or
// undoing
var hidden = op.maybeHiddenMarkers, unhidden = op.maybeUnhiddenMarkers;
if (hidden) { for (var i = 0; i < hidden.length; ++i)
{ if (!hidden[i].lines.length) { signal(hidden[i], "hide"); } } }
if (unhidden) { for (var i$1 = 0; i$1 < unhidden.length; ++i$1)
{ if (unhidden[i$1].lines.length) { signal(unhidden[i$1], "unhide"); } } }
if (display.wrapper.offsetHeight)
{ doc.scrollTop = cm.display.scroller.scrollTop; }
// Fire change events, and delayed event handlers
if (op.changeObjs)
{ signal(cm, "changes", cm, op.changeObjs); }
if (op.update)
{ op.update.finish(); }
}
// Run the given function in an operation
function runInOp(cm, f) {
if (cm.curOp) { return f() }
startOperation(cm);
try { return f() }
finally { endOperation(cm); }
}
// Wraps a function in an operation. Returns the wrapped function.
function operation(cm, f) {
return function() {
if (cm.curOp) { return f.apply(cm, arguments) }
startOperation(cm);
try { return f.apply(cm, arguments) }
finally { endOperation(cm); }
}
}
// Used to add methods to editor and doc instances, wrapping them in
// operations.
function methodOp(f) {
return function() {
if (this.curOp) { return f.apply(this, arguments) }
startOperation(this);
try { return f.apply(this, arguments) }
finally { endOperation(this); }
}
}
function docMethodOp(f) {
return function() {
var cm = this.cm;
if (!cm || cm.curOp) { return f.apply(this, arguments) }
startOperation(cm);
try { return f.apply(this, arguments) }
finally { endOperation(cm); }
}
}
// Updates the display.view data structure for a given change to the
// document. From and to are in pre-change coordinates. Lendiff is
// the amount of lines added or subtracted by the change. This is
// used for changes that span multiple lines, or change the way
// lines are divided into visual lines. regLineChange (below)
// registers single-line changes.
function regChange(cm, from, to, lendiff) {
if (from == null) { from = cm.doc.first; }
if (to == null) { to = cm.doc.first + cm.doc.size; }
if (!lendiff) { lendiff = 0; }
var display = cm.display;
if (lendiff && to < display.viewTo &&
(display.updateLineNumbers == null || display.updateLineNumbers > from))
{ display.updateLineNumbers = from; }
cm.curOp.viewChanged = true;
if (from >= display.viewTo) { // Change after
if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo)
{ resetView(cm); }
} else if (to <= display.viewFrom) { // Change before
if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) {
resetView(cm);
} else {
display.viewFrom += lendiff;
display.viewTo += lendiff;
}
} else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap
resetView(cm);
} else if (from <= display.viewFrom) { // Top overlap
var cut = viewCuttingPoint(cm, to, to + lendiff, 1);
if (cut) {
display.view = display.view.slice(cut.index);
display.viewFrom = cut.lineN;
display.viewTo += lendiff;
} else {
resetView(cm);
}
} else if (to >= display.viewTo) { // Bottom overlap
var cut$1 = viewCuttingPoint(cm, from, from, -1);
if (cut$1) {
display.view = display.view.slice(0, cut$1.index);
display.viewTo = cut$1.lineN;
} else {
resetView(cm);
}
} else { // Gap in the middle
var cutTop = viewCuttingPoint(cm, from, from, -1);
var cutBot = viewCuttingPoint(cm, to, to + lendiff, 1);
if (cutTop && cutBot) {
display.view = display.view.slice(0, cutTop.index)
.concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN))
.concat(display.view.slice(cutBot.index));
display.viewTo += lendiff;
} else {
resetView(cm);
}
}
var ext = display.externalMeasured;
if (ext) {
if (to < ext.lineN)
{ ext.lineN += lendiff; }
else if (from < ext.lineN + ext.size)
{ display.externalMeasured = null; }
}
}
// Register a change to a single line. Type must be one of "text",
// "gutter", "class", "widget"
function regLineChange(cm, line, type) {
cm.curOp.viewChanged = true;
var display = cm.display, ext = cm.display.externalMeasured;
if (ext && line >= ext.lineN && line < ext.lineN + ext.size)
{ display.externalMeasured = null; }
if (line < display.viewFrom || line >= display.viewTo) { return }
var lineView = display.view[findViewIndex(cm, line)];
if (lineView.node == null) { return }
var arr = lineView.changes || (lineView.changes = []);
if (indexOf(arr, type) == -1) { arr.push(type); }
}
// Clear the view.
function resetView(cm) {
cm.display.viewFrom = cm.display.viewTo = cm.doc.first;
cm.display.view = [];
cm.display.viewOffset = 0;
}
function viewCuttingPoint(cm, oldN, newN, dir) {
var index = findViewIndex(cm, oldN), diff, view = cm.display.view;
if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size)
{ return {index: index, lineN: newN} }
var n = cm.display.viewFrom;
for (var i = 0; i < index; i++)
{ n += view[i].size; }
if (n != oldN) {
if (dir > 0) {
if (index == view.length - 1) { return null }
diff = (n + view[index].size) - oldN;
index++;
} else {
diff = n - oldN;
}
oldN += diff; newN += diff;
}
while (visualLineNo(cm.doc, newN) != newN) {
if (index == (dir < 0 ? 0 : view.length - 1)) { return null }
newN += dir * view[index - (dir < 0 ? 1 : 0)].size;
index += dir;
}
return {index: index, lineN: newN}
}
// Force the view to cover a given range, adding empty view element
// or clipping off existing ones as needed.
function adjustView(cm, from, to) {
var display = cm.display, view = display.view;
if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) {
display.view = buildViewArray(cm, from, to);
display.viewFrom = from;
} else {
if (display.viewFrom > from)
{ display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view); }
else if (display.viewFrom < from)
{ display.view = display.view.slice(findViewIndex(cm, from)); }
display.viewFrom = from;
if (display.viewTo < to)
{ display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)); }
else if (display.viewTo > to)
{ display.view = display.view.slice(0, findViewIndex(cm, to)); }
}
display.viewTo = to;
}
// Count the number of lines in the view whose DOM representation is
// out of date (or nonexistent).
function countDirtyView(cm) {
var view = cm.display.view, dirty = 0;
for (var i = 0; i < view.length; i++) {
var lineView = view[i];
if (!lineView.hidden && (!lineView.node || lineView.changes)) { ++dirty; }
}
return dirty
}
// HIGHLIGHT WORKER
function startWorker(cm, time) {
if (cm.doc.highlightFrontier < cm.display.viewTo)
{ cm.state.highlight.set(time, bind(highlightWorker, cm)); }
}
function highlightWorker(cm) {
var doc = cm.doc;
if (doc.highlightFrontier >= cm.display.viewTo) { return }
var end = +new Date + cm.options.workTime;
var context = getContextBefore(cm, doc.highlightFrontier);
var changedLines = [];
doc.iter(context.line, Math.min(doc.first + doc.size, cm.display.viewTo + 500), function (line) {
if (context.line >= cm.display.viewFrom) { // Visible
var oldStyles = line.styles;
var resetState = line.text.length > cm.options.maxHighlightLength ? copyState(doc.mode, context.state) : null;
var highlighted = highlightLine(cm, line, context, true);
if (resetState) { context.state = resetState; }
line.styles = highlighted.styles;
var oldCls = line.styleClasses, newCls = highlighted.classes;
if (newCls) { line.styleClasses = newCls; }
else if (oldCls) { line.styleClasses = null; }
var ischange = !oldStyles || oldStyles.length != line.styles.length ||
oldCls != newCls && (!oldCls || !newCls || oldCls.bgClass != newCls.bgClass || oldCls.textClass != newCls.textClass);
for (var i = 0; !ischange && i < oldStyles.length; ++i) { ischange = oldStyles[i] != line.styles[i]; }
if (ischange) { changedLines.push(context.line); }
line.stateAfter = context.save();
context.nextLine();
} else {
if (line.text.length <= cm.options.maxHighlightLength)
{ processLine(cm, line.text, context); }
line.stateAfter = context.line % 5 == 0 ? context.save() : null;
context.nextLine();
}
if (+new Date > end) {
startWorker(cm, cm.options.workDelay);
return true
}
});
doc.highlightFrontier = context.line;
doc.modeFrontier = Math.max(doc.modeFrontier, context.line);
if (changedLines.length) { runInOp(cm, function () {
for (var i = 0; i < changedLines.length; i++)
{ regLineChange(cm, changedLines[i], "text"); }
}); }
}
// DISPLAY DRAWING
var DisplayUpdate = function(cm, viewport, force) {
var display = cm.display;
this.viewport = viewport;
// Store some values that we'll need later (but don't want to force a relayout for)
this.visible = visibleLines(display, cm.doc, viewport);
this.editorIsHidden = !display.wrapper.offsetWidth;
this.wrapperHeight = display.wrapper.clientHeight;
this.wrapperWidth = display.wrapper.clientWidth;
this.oldDisplayWidth = displayWidth(cm);
this.force = force;
this.dims = getDimensions(cm);
this.events = [];
};
DisplayUpdate.prototype.signal = function (emitter, type) {
if (hasHandler(emitter, type))
{ this.events.push(arguments); }
};
DisplayUpdate.prototype.finish = function () {
var this$1 = this;
for (var i = 0; i < this.events.length; i++)
{ signal.apply(null, this$1.events[i]); }
};
function maybeClipScrollbars(cm) {
var display = cm.display;
if (!display.scrollbarsClipped && display.scroller.offsetWidth) {
display.nativeBarWidth = display.scroller.offsetWidth - display.scroller.clientWidth;
display.heightForcer.style.height = scrollGap(cm) + "px";
display.sizer.style.marginBottom = -display.nativeBarWidth + "px";
display.sizer.style.borderRightWidth = scrollGap(cm) + "px";
display.scrollbarsClipped = true;
}
}
function selectionSnapshot(cm) {
if (cm.hasFocus()) { return null }
var active = activeElt();
if (!active || !contains(cm.display.lineDiv, active)) { return null }
var result = {activeElt: active};
if (window.getSelection) {
var sel = window.getSelection();
if (sel.anchorNode && sel.extend && contains(cm.display.lineDiv, sel.anchorNode)) {
result.anchorNode = sel.anchorNode;
result.anchorOffset = sel.anchorOffset;
result.focusNode = sel.focusNode;
result.focusOffset = sel.focusOffset;
}
}
return result
}
function restoreSelection(snapshot) {
if (!snapshot || !snapshot.activeElt || snapshot.activeElt == activeElt()) { return }
snapshot.activeElt.focus();
if (snapshot.anchorNode && contains(document.body, snapshot.anchorNode) && contains(document.body, snapshot.focusNode)) {
var sel = window.getSelection(), range$$1 = document.createRange();
range$$1.setEnd(snapshot.anchorNode, snapshot.anchorOffset);
range$$1.collapse(false);
sel.removeAllRanges();
sel.addRange(range$$1);
sel.extend(snapshot.focusNode, snapshot.focusOffset);
}
}
// Does the actual updating of the line display. Bails out
// (returning false) when there is nothing to be done and forced is
// false.
function updateDisplayIfNeeded(cm, update) {
var display = cm.display, doc = cm.doc;
if (update.editorIsHidden) {
resetView(cm);
return false
}
// Bail out if the visible area is already rendered and nothing changed.
if (!update.force &&
update.visible.from >= display.viewFrom && update.visible.to <= display.viewTo &&
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo) &&
display.renderedView == display.view && countDirtyView(cm) == 0)
{ return false }
if (maybeUpdateLineNumberWidth(cm)) {
resetView(cm);
update.dims = getDimensions(cm);
}
// Compute a suitable new viewport (from & to)
var end = doc.first + doc.size;
var from = Math.max(update.visible.from - cm.options.viewportMargin, doc.first);
var to = Math.min(end, update.visible.to + cm.options.viewportMargin);
if (display.viewFrom < from && from - display.viewFrom < 20) { from = Math.max(doc.first, display.viewFrom); }
if (display.viewTo > to && display.viewTo - to < 20) { to = Math.min(end, display.viewTo); }
if (sawCollapsedSpans) {
from = visualLineNo(cm.doc, from);
to = visualLineEndNo(cm.doc, to);
}
var different = from != display.viewFrom || to != display.viewTo ||
display.lastWrapHeight != update.wrapperHeight || display.lastWrapWidth != update.wrapperWidth;
adjustView(cm, from, to);
display.viewOffset = heightAtLine(getLine(cm.doc, display.viewFrom));
// Position the mover div to align with the current scroll position
cm.display.mover.style.top = display.viewOffset + "px";
var toUpdate = countDirtyView(cm);
if (!different && toUpdate == 0 && !update.force && display.renderedView == display.view &&
(display.updateLineNumbers == null || display.updateLineNumbers >= display.viewTo))
{ return false }
// For big changes, we hide the enclosing element during the
// update, since that speeds up the operations on most browsers.
var selSnapshot = selectionSnapshot(cm);
if (toUpdate > 4) { display.lineDiv.style.display = "none"; }
patchDisplay(cm, display.updateLineNumbers, update.dims);
if (toUpdate > 4) { display.lineDiv.style.display = ""; }
display.renderedView = display.view;
// There might have been a widget with a focused element that got
// hidden or updated, if so re-focus it.
restoreSelection(selSnapshot);
// Prevent selection and cursors from interfering with the scroll
// width and height.
removeChildren(display.cursorDiv);
removeChildren(display.selectionDiv);
display.gutters.style.height = display.sizer.style.minHeight = 0;
if (different) {
display.lastWrapHeight = update.wrapperHeight;
display.lastWrapWidth = update.wrapperWidth;
startWorker(cm, 400);
}
display.updateLineNumbers = null;
return true
}
function postUpdateDisplay(cm, update) {
var viewport = update.viewport;
for (var first = true;; first = false) {
if (!first || !cm.options.lineWrapping || update.oldDisplayWidth == displayWidth(cm)) {
// Clip forced viewport to actual scrollable area.
if (viewport && viewport.top != null)
{ viewport = {top: Math.min(cm.doc.height + paddingVert(cm.display) - displayHeight(cm), viewport.top)}; }
// Updated line heights might result in the drawn area not
// actually covering the viewport. Keep looping until it does.
update.visible = visibleLines(cm.display, cm.doc, viewport);
if (update.visible.from >= cm.display.viewFrom && update.visible.to <= cm.display.viewTo)
{ break }
}
if (!updateDisplayIfNeeded(cm, update)) { break }
updateHeightsInViewport(cm);
var barMeasure = measureForScrollbars(cm);
updateSelection(cm);
updateScrollbars(cm, barMeasure);
setDocumentHeight(cm, barMeasure);
update.force = false;
}
update.signal(cm, "update", cm);
if (cm.display.viewFrom != cm.display.reportedViewFrom || cm.display.viewTo != cm.display.reportedViewTo) {
update.signal(cm, "viewportChange", cm, cm.display.viewFrom, cm.display.viewTo);
cm.display.reportedViewFrom = cm.display.viewFrom; cm.display.reportedViewTo = cm.display.viewTo;
}
}
function updateDisplaySimple(cm, viewport) {
var update = new DisplayUpdate(cm, viewport);
if (updateDisplayIfNeeded(cm, update)) {
updateHeightsInViewport(cm);
postUpdateDisplay(cm, update);
var barMeasure = measureForScrollbars(cm);
updateSelection(cm);
updateScrollbars(cm, barMeasure);
setDocumentHeight(cm, barMeasure);
update.finish();
}
}
// Sync the actual display DOM structure with display.view, removing
// nodes for lines that are no longer in view, and creating the ones
// that are not there yet, and updating the ones that are out of
// date.
function patchDisplay(cm, updateNumbersFrom, dims) {
var display = cm.display, lineNumbers = cm.options.lineNumbers;
var container = display.lineDiv, cur = container.firstChild;
function rm(node) {
var next = node.nextSibling;
// Works around a throw-scroll bug in OS X Webkit
if (webkit && mac && cm.display.currentWheelTarget == node)
{ node.style.display = "none"; }
else
{ node.parentNode.removeChild(node); }
return next
}
var view = display.view, lineN = display.viewFrom;
// Loop over the elements in the view, syncing cur (the DOM nodes
// in display.lineDiv) with the view as we go.
for (var i = 0; i < view.length; i++) {
var lineView = view[i];
if (lineView.hidden) ; else if (!lineView.node || lineView.node.parentNode != container) { // Not drawn yet
var node = buildLineElement(cm, lineView, lineN, dims);
container.insertBefore(node, cur);
} else { // Already drawn
while (cur != lineView.node) { cur = rm(cur); }
var updateNumber = lineNumbers && updateNumbersFrom != null &&
updateNumbersFrom <= lineN && lineView.lineNumber;
if (lineView.changes) {
if (indexOf(lineView.changes, "gutter") > -1) { updateNumber = false; }
updateLineForChanges(cm, lineView, lineN, dims);
}
if (updateNumber) {
removeChildren(lineView.lineNumber);
lineView.lineNumber.appendChild(document.createTextNode(lineNumberFor(cm.options, lineN)));
}
cur = lineView.node.nextSibling;
}
lineN += lineView.size;
}
while (cur) { cur = rm(cur); }
}
function updateGutterSpace(cm) {
var width = cm.display.gutters.offsetWidth;
cm.display.sizer.style.marginLeft = width + "px";
}
function setDocumentHeight(cm, measure) {
cm.display.sizer.style.minHeight = measure.docHeight + "px";
cm.display.heightForcer.style.top = measure.docHeight + "px";
cm.display.gutters.style.height = (measure.docHeight + cm.display.barHeight + scrollGap(cm)) + "px";
}
// Rebuild the gutter elements, ensure the margin to the left of the
// code matches their width.
function updateGutters(cm) {
var gutters = cm.display.gutters, specs = cm.options.gutters;
removeChildren(gutters);
var i = 0;
for (; i < specs.length; ++i) {
var gutterClass = specs[i];
var gElt = gutters.appendChild(elt("div", null, "CodeMirror-gutter " + gutterClass));
if (gutterClass == "CodeMirror-linenumbers") {
cm.display.lineGutter = gElt;
gElt.style.width = (cm.display.lineNumWidth || 1) + "px";
}
}
gutters.style.display = i ? "" : "none";
updateGutterSpace(cm);
}
// Make sure the gutters options contains the element
// "CodeMirror-linenumbers" when the lineNumbers option is true.
function setGuttersForLineNumbers(options) {
var found = indexOf(options.gutters, "CodeMirror-linenumbers");
if (found == -1 && options.lineNumbers) {
options.gutters = options.gutters.concat(["CodeMirror-linenumbers"]);
} else if (found > -1 && !options.lineNumbers) {
options.gutters = options.gutters.slice(0);
options.gutters.splice(found, 1);
}
}
// Since the delta values reported on mouse wheel events are
// unstandardized between browsers and even browser versions, and
// generally horribly unpredictable, this code starts by measuring
// the scroll effect that the first few mouse wheel events have,
// and, from that, detects the way it can convert deltas to pixel
// offsets afterwards.
//
// The reason we want to know the amount a wheel event will scroll
// is that it gives us a chance to update the display before the
// actual scrolling happens, reducing flickering.
var wheelSamples = 0, wheelPixelsPerUnit = null;
// Fill in a browser-detected starting value on browsers where we
// know one. These don't have to be accurate -- the result of them
// being wrong would just be a slight flicker on the first wheel
// scroll (if it is large enough).
if (ie) { wheelPixelsPerUnit = -.53; }
else if (gecko) { wheelPixelsPerUnit = 15; }
else if (chrome) { wheelPixelsPerUnit = -.7; }
else if (safari) { wheelPixelsPerUnit = -1/3; }
function wheelEventDelta(e) {
var dx = e.wheelDeltaX, dy = e.wheelDeltaY;
if (dx == null && e.detail && e.axis == e.HORIZONTAL_AXIS) { dx = e.detail; }
if (dy == null && e.detail && e.axis == e.VERTICAL_AXIS) { dy = e.detail; }
else if (dy == null) { dy = e.wheelDelta; }
return {x: dx, y: dy}
}
function wheelEventPixels(e) {
var delta = wheelEventDelta(e);
delta.x *= wheelPixelsPerUnit;
delta.y *= wheelPixelsPerUnit;
return delta
}
function onScrollWheel(cm, e) {
var delta = wheelEventDelta(e), dx = delta.x, dy = delta.y;
var display = cm.display, scroll = display.scroller;
// Quit if there's nothing to scroll here
var canScrollX = scroll.scrollWidth > scroll.clientWidth;
var canScrollY = scroll.scrollHeight > scroll.clientHeight;
if (!(dx && canScrollX || dy && canScrollY)) { return }
// Webkit browsers on OS X abort momentum scrolls when the target
// of the scroll event is removed from the scrollable element.
// This hack (see related code in patchDisplay) makes sure the
// element is kept around.
if (dy && mac && webkit) {
outer: for (var cur = e.target, view = display.view; cur != scroll; cur = cur.parentNode) {
for (var i = 0; i < view.length; i++) {
if (view[i].node == cur) {
cm.display.currentWheelTarget = cur;
break outer
}
}
}
}
// On some browsers, horizontal scrolling will cause redraws to
// happen before the gutter has been realigned, causing it to
// wriggle around in a most unseemly way. When we have an
// estimated pixels/delta value, we just handle horizontal
// scrolling entirely here. It'll be slightly off from native, but
// better than glitching out.
if (dx && !gecko && !presto && wheelPixelsPerUnit != null) {
if (dy && canScrollY)
{ updateScrollTop(cm, Math.max(0, scroll.scrollTop + dy * wheelPixelsPerUnit)); }
setScrollLeft(cm, Math.max(0, scroll.scrollLeft + dx * wheelPixelsPerUnit));
// Only prevent default scrolling if vertical scrolling is
// actually possible. Otherwise, it causes vertical scroll
// jitter on OSX trackpads when deltaX is small and deltaY
// is large (issue #3579)
if (!dy || (dy && canScrollY))
{ e_preventDefault(e); }
display.wheelStartX = null; // Abort measurement, if in progress
return
}
// 'Project' the visible viewport to cover the area that is being
// scrolled into view (if we know enough to estimate it).
if (dy && wheelPixelsPerUnit != null) {
var pixels = dy * wheelPixelsPerUnit;
var top = cm.doc.scrollTop, bot = top + display.wrapper.clientHeight;
if (pixels < 0) { top = Math.max(0, top + pixels - 50); }
else { bot = Math.min(cm.doc.height, bot + pixels + 50); }
updateDisplaySimple(cm, {top: top, bottom: bot});
}
if (wheelSamples < 20) {
if (display.wheelStartX == null) {
display.wheelStartX = scroll.scrollLeft; display.wheelStartY = scroll.scrollTop;
display.wheelDX = dx; display.wheelDY = dy;
setTimeout(function () {
if (display.wheelStartX == null) { return }
var movedX = scroll.scrollLeft - display.wheelStartX;
var movedY = scroll.scrollTop - display.wheelStartY;
var sample = (movedY && display.wheelDY && movedY / display.wheelDY) ||
(movedX && display.wheelDX && movedX / display.wheelDX);
display.wheelStartX = display.wheelStartY = null;
if (!sample) { return }
wheelPixelsPerUnit = (wheelPixelsPerUnit * wheelSamples + sample) / (wheelSamples + 1);
++wheelSamples;
}, 200);
} else {
display.wheelDX += dx; display.wheelDY += dy;
}
}
}
// Selection objects are immutable. A new one is created every time
// the selection changes. A selection is one or more non-overlapping
// (and non-touching) ranges, sorted, and an integer that indicates
// which one is the primary selection (the one that's scrolled into
// view, that getCursor returns, etc).
var Selection = function(ranges, primIndex) {
this.ranges = ranges;
this.primIndex = primIndex;
};
Selection.prototype.primary = function () { return this.ranges[this.primIndex] };
Selection.prototype.equals = function (other) {
var this$1 = this;
if (other == this) { return true }
if (other.primIndex != this.primIndex || other.ranges.length != this.ranges.length) { return false }
for (var i = 0; i < this.ranges.length; i++) {
var here = this$1.ranges[i], there = other.ranges[i];
if (!equalCursorPos(here.anchor, there.anchor) || !equalCursorPos(here.head, there.head)) { return false }
}
return true
};
Selection.prototype.deepCopy = function () {
var this$1 = this;
var out = [];
for (var i = 0; i < this.ranges.length; i++)
{ out[i] = new Range(copyPos(this$1.ranges[i].anchor), copyPos(this$1.ranges[i].head)); }
return new Selection(out, this.primIndex)
};
Selection.prototype.somethingSelected = function () {
var this$1 = this;
for (var i = 0; i < this.ranges.length; i++)
{ if (!this$1.ranges[i].empty()) { return true } }
return false
};
Selection.prototype.contains = function (pos, end) {
var this$1 = this;
if (!end) { end = pos; }
for (var i = 0; i < this.ranges.length; i++) {
var range = this$1.ranges[i];
if (cmp(end, range.from()) >= 0 && cmp(pos, range.to()) <= 0)
{ return i }
}
return -1
};
var Range = function(anchor, head) {
this.anchor = anchor; this.head = head;
};
Range.prototype.from = function () { return minPos(this.anchor, this.head) };
Range.prototype.to = function () { return maxPos(this.anchor, this.head) };
Range.prototype.empty = function () { return this.head.line == this.anchor.line && this.head.ch == this.anchor.ch };
// Take an unsorted, potentially overlapping set of ranges, and
// build a selection out of it. 'Consumes' ranges array (modifying
// it).
function normalizeSelection(cm, ranges, primIndex) {
var mayTouch = cm && cm.options.selectionsMayTouch;
var prim = ranges[primIndex];
ranges.sort(function (a, b) { return cmp(a.from(), b.from()); });
primIndex = indexOf(ranges, prim);
for (var i = 1; i < ranges.length; i++) {
var cur = ranges[i], prev = ranges[i - 1];
var diff = cmp(prev.to(), cur.from());
if (mayTouch && !cur.empty() ? diff > 0 : diff >= 0) {
var from = minPos(prev.from(), cur.from()), to = maxPos(prev.to(), cur.to());
var inv = prev.empty() ? cur.from() == cur.head : prev.from() == prev.head;
if (i <= primIndex) { --primIndex; }
ranges.splice(--i, 2, new Range(inv ? to : from, inv ? from : to));
}
}
return new Selection(ranges, primIndex)
}
function simpleSelection(anchor, head) {
return new Selection([new Range(anchor, head || anchor)], 0)
}
// Compute the position of the end of a change (its 'to' property
// refers to the pre-change end).
function changeEnd(change) {
if (!change.text) { return change.to }
return Pos(change.from.line + change.text.length - 1,
lst(change.text).length + (change.text.length == 1 ? change.from.ch : 0))
}
// Adjust a position to refer to the post-change position of the
// same text, or the end of the change if the change covers it.
function adjustForChange(pos, change) {
if (cmp(pos, change.from) < 0) { return pos }
if (cmp(pos, change.to) <= 0) { return changeEnd(change) }
var line = pos.line + change.text.length - (change.to.line - change.from.line) - 1, ch = pos.ch;
if (pos.line == change.to.line) { ch += changeEnd(change).ch - change.to.ch; }
return Pos(line, ch)
}
function computeSelAfterChange(doc, change) {
var out = [];
for (var i = 0; i < doc.sel.ranges.length; i++) {
var range = doc.sel.ranges[i];
out.push(new Range(adjustForChange(range.anchor, change),
adjustForChange(range.head, change)));
}
return normalizeSelection(doc.cm, out, doc.sel.primIndex)
}
function offsetPos(pos, old, nw) {
if (pos.line == old.line)
{ return Pos(nw.line, pos.ch - old.ch + nw.ch) }
else
{ return Pos(nw.line + (pos.line - old.line), pos.ch) }
}
// Used by replaceSelections to allow moving the selection to the
// start or around the replaced test. Hint may be "start" or "around".
function computeReplacedSel(doc, changes, hint) {
var out = [];
var oldPrev = Pos(doc.first, 0), newPrev = oldPrev;
for (var i = 0; i < changes.length; i++) {
var change = changes[i];
var from = offsetPos(change.from, oldPrev, newPrev);
var to = offsetPos(changeEnd(change), oldPrev, newPrev);
oldPrev = change.to;
newPrev = to;
if (hint == "around") {
var range = doc.sel.ranges[i], inv = cmp(range.head, range.anchor) < 0;
out[i] = new Range(inv ? to : from, inv ? from : to);
} else {
out[i] = new Range(from, from);
}
}
return new Selection(out, doc.sel.primIndex)
}
// Used to get the editor into a consistent state again when options change.
function loadMode(cm) {
cm.doc.mode = getMode(cm.options, cm.doc.modeOption);
resetModeState(cm);
}
function resetModeState(cm) {
cm.doc.iter(function (line) {
if (line.stateAfter) { line.stateAfter = null; }
if (line.styles) { line.styles = null; }
});
cm.doc.modeFrontier = cm.doc.highlightFrontier = cm.doc.first;
startWorker(cm, 100);
cm.state.modeGen++;
if (cm.curOp) { regChange(cm); }
}
// DOCUMENT DATA STRUCTURE
// By default, updates that start and end at the beginning of a line
// are treated specially, in order to make the association of line
// widgets and marker elements with the text behave more intuitive.
function isWholeLineUpdate(doc, change) {
return change.from.ch == 0 && change.to.ch == 0 && lst(change.text) == "" &&
(!doc.cm || doc.cm.options.wholeLineUpdateBefore)
}
// Perform a change on the document data structure.
function updateDoc(doc, change, markedSpans, estimateHeight$$1) {
function spansFor(n) {return markedSpans ? markedSpans[n] : null}
function update(line, text, spans) {
updateLine(line, text, spans, estimateHeight$$1);
signalLater(line, "change", line, change);
}
function linesFor(start, end) {
var result = [];
for (var i = start; i < end; ++i)
{ result.push(new Line(text[i], spansFor(i), estimateHeight$$1)); }
return result
}
var from = change.from, to = change.to, text = change.text;
var firstLine = getLine(doc, from.line), lastLine = getLine(doc, to.line);
var lastText = lst(text), lastSpans = spansFor(text.length - 1), nlines = to.line - from.line;
// Adjust the line structure
if (change.full) {
doc.insert(0, linesFor(0, text.length));
doc.remove(text.length, doc.size - text.length);
} else if (isWholeLineUpdate(doc, change)) {
// This is a whole-line replace. Treated specially to make
// sure line objects move the way they are supposed to.
var added = linesFor(0, text.length - 1);
update(lastLine, lastLine.text, lastSpans);
if (nlines) { doc.remove(from.line, nlines); }
if (added.length) { doc.insert(from.line, added); }
} else if (firstLine == lastLine) {
if (text.length == 1) {
update(firstLine, firstLine.text.slice(0, from.ch) + lastText + firstLine.text.slice(to.ch), lastSpans);
} else {
var added$1 = linesFor(1, text.length - 1);
added$1.push(new Line(lastText + firstLine.text.slice(to.ch), lastSpans, estimateHeight$$1));
update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
doc.insert(from.line + 1, added$1);
}
} else if (text.length == 1) {
update(firstLine, firstLine.text.slice(0, from.ch) + text[0] + lastLine.text.slice(to.ch), spansFor(0));
doc.remove(from.line + 1, nlines);
} else {
update(firstLine, firstLine.text.slice(0, from.ch) + text[0], spansFor(0));
update(lastLine, lastText + lastLine.text.slice(to.ch), lastSpans);
var added$2 = linesFor(1, text.length - 1);
if (nlines > 1) { doc.remove(from.line + 1, nlines - 1); }
doc.insert(from.line + 1, added$2);
}
signalLater(doc, "change", doc, change);
}
// Call f for all linked documents.
function linkedDocs(doc, f, sharedHistOnly) {
function propagate(doc, skip, sharedHist) {
if (doc.linked) { for (var i = 0; i < doc.linked.length; ++i) {
var rel = doc.linked[i];
if (rel.doc == skip) { continue }
var shared = sharedHist && rel.sharedHist;
if (sharedHistOnly && !shared) { continue }
f(rel.doc, shared);
propagate(rel.doc, doc, shared);
} }
}
propagate(doc, null, true);
}
// Attach a document to an editor.
function attachDoc(cm, doc) {
if (doc.cm) { throw new Error("This document is already in use.") }
cm.doc = doc;
doc.cm = cm;
estimateLineHeights(cm);
loadMode(cm);
setDirectionClass(cm);
if (!cm.options.lineWrapping) { findMaxLine(cm); }
cm.options.mode = doc.modeOption;
regChange(cm);
}
function setDirectionClass(cm) {
(cm.doc.direction == "rtl" ? addClass : rmClass)(cm.display.lineDiv, "CodeMirror-rtl");
}
function directionChanged(cm) {
runInOp(cm, function () {
setDirectionClass(cm);
regChange(cm);
});
}
function History(startGen) {
// Arrays of change events and selections. Doing something adds an
// event to done and clears undo. Undoing moves events from done
// to undone, redoing moves them in the other direction.
this.done = []; this.undone = [];
this.undoDepth = Infinity;
// Used to track when changes can be merged into a single undo
// event
this.lastModTime = this.lastSelTime = 0;
this.lastOp = this.lastSelOp = null;
this.lastOrigin = this.lastSelOrigin = null;
// Used by the isClean() method
this.generation = this.maxGeneration = startGen || 1;
}
// Create a history change event from an updateDoc-style change
// object.
function historyChangeFromChange(doc, change) {
var histChange = {from: copyPos(change.from), to: changeEnd(change), text: getBetween(doc, change.from, change.to)};
attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1);
linkedDocs(doc, function (doc) { return attachLocalSpans(doc, histChange, change.from.line, change.to.line + 1); }, true);
return histChange
}
// Pop all selection events off the end of a history array. Stop at
// a change event.
function clearSelectionEvents(array) {
while (array.length) {
var last = lst(array);
if (last.ranges) { array.pop(); }
else { break }
}
}
// Find the top change event in the history. Pop off selection
// events that are in the way.
function lastChangeEvent(hist, force) {
if (force) {
clearSelectionEvents(hist.done);
return lst(hist.done)
} else if (hist.done.length && !lst(hist.done).ranges) {
return lst(hist.done)
} else if (hist.done.length > 1 && !hist.done[hist.done.length - 2].ranges) {
hist.done.pop();
return lst(hist.done)
}
}
// Register a change in the history. Merges changes that are within
// a single operation, or are close together with an origin that
// allows merging (starting with "+") into a single event.
function addChangeToHistory(doc, change, selAfter, opId) {
var hist = doc.history;
hist.undone.length = 0;
var time = +new Date, cur;
var last;
if ((hist.lastOp == opId ||
hist.lastOrigin == change.origin && change.origin &&
((change.origin.charAt(0) == "+" && hist.lastModTime > time - (doc.cm ? doc.cm.options.historyEventDelay : 500)) ||
change.origin.charAt(0) == "*")) &&
(cur = lastChangeEvent(hist, hist.lastOp == opId))) {
// Merge this change into the last event
last = lst(cur.changes);
if (cmp(change.from, change.to) == 0 && cmp(change.from, last.to) == 0) {
// Optimized case for simple insertion -- don't want to add
// new changesets for every character typed
last.to = changeEnd(change);
} else {
// Add new sub-event
cur.changes.push(historyChangeFromChange(doc, change));
}
} else {
// Can not be merged, start a new event.
var before = lst(hist.done);
if (!before || !before.ranges)
{ pushSelectionToHistory(doc.sel, hist.done); }
cur = {changes: [historyChangeFromChange(doc, change)],
generation: hist.generation};
hist.done.push(cur);
while (hist.done.length > hist.undoDepth) {
hist.done.shift();
if (!hist.done[0].ranges) { hist.done.shift(); }
}
}
hist.done.push(selAfter);
hist.generation = ++hist.maxGeneration;
hist.lastModTime = hist.lastSelTime = time;
hist.lastOp = hist.lastSelOp = opId;
hist.lastOrigin = hist.lastSelOrigin = change.origin;
if (!last) { signal(doc, "historyAdded"); }
}
function selectionEventCanBeMerged(doc, origin, prev, sel) {
var ch = origin.charAt(0);
return ch == "*" ||
ch == "+" &&
prev.ranges.length == sel.ranges.length &&
prev.somethingSelected() == sel.somethingSelected() &&
new Date - doc.history.lastSelTime <= (doc.cm ? doc.cm.options.historyEventDelay : 500)
}
// Called whenever the selection changes, sets the new selection as
// the pending selection in the history, and pushes the old pending
// selection into the 'done' array when it was significantly
// different (in number of selected ranges, emptiness, or time).
function addSelectionToHistory(doc, sel, opId, options) {
var hist = doc.history, origin = options && options.origin;
// A new event is started when the previous origin does not match
// the current, or the origins don't allow matching. Origins
// starting with * are always merged, those starting with + are
// merged when similar and close together in time.
if (opId == hist.lastSelOp ||
(origin && hist.lastSelOrigin == origin &&
(hist.lastModTime == hist.lastSelTime && hist.lastOrigin == origin ||
selectionEventCanBeMerged(doc, origin, lst(hist.done), sel))))
{ hist.done[hist.done.length - 1] = sel; }
else
{ pushSelectionToHistory(sel, hist.done); }
hist.lastSelTime = +new Date;
hist.lastSelOrigin = origin;
hist.lastSelOp = opId;
if (options && options.clearRedo !== false)
{ clearSelectionEvents(hist.undone); }
}
function pushSelectionToHistory(sel, dest) {
var top = lst(dest);
if (!(top && top.ranges && top.equals(sel)))
{ dest.push(sel); }
}
// Used to store marked span information in the history.
function attachLocalSpans(doc, change, from, to) {
var existing = change["spans_" + doc.id], n = 0;
doc.iter(Math.max(doc.first, from), Math.min(doc.first + doc.size, to), function (line) {
if (line.markedSpans)
{ (existing || (existing = change["spans_" + doc.id] = {}))[n] = line.markedSpans; }
++n;
});
}
// When un/re-doing restores text containing marked spans, those
// that have been explicitly cleared should not be restored.
function removeClearedSpans(spans) {
if (!spans) { return null }
var out;
for (var i = 0; i < spans.length; ++i) {
if (spans[i].marker.explicitlyCleared) { if (!out) { out = spans.slice(0, i); } }
else if (out) { out.push(spans[i]); }
}
return !out ? spans : out.length ? out : null
}
// Retrieve and filter the old marked spans stored in a change event.
function getOldSpans(doc, change) {
var found = change["spans_" + doc.id];
if (!found) { return null }
var nw = [];
for (var i = 0; i < change.text.length; ++i)
{ nw.push(removeClearedSpans(found[i])); }
return nw
}
// Used for un/re-doing changes from the history. Combines the
// result of computing the existing spans with the set of spans that
// existed in the history (so that deleting around a span and then
// undoing brings back the span).
function mergeOldSpans(doc, change) {
var old = getOldSpans(doc, change);
var stretched = stretchSpansOverChange(doc, change);
if (!old) { return stretched }
if (!stretched) { return old }
for (var i = 0; i < old.length; ++i) {
var oldCur = old[i], stretchCur = stretched[i];
if (oldCur && stretchCur) {
spans: for (var j = 0; j < stretchCur.length; ++j) {
var span = stretchCur[j];
for (var k = 0; k < oldCur.length; ++k)
{ if (oldCur[k].marker == span.marker) { continue spans } }
oldCur.push(span);
}
} else if (stretchCur) {
old[i] = stretchCur;
}
}
return old
}
// Used both to provide a JSON-safe object in .getHistory, and, when
// detaching a document, to split the history in two
function copyHistoryArray(events, newGroup, instantiateSel) {
var copy = [];
for (var i = 0; i < events.length; ++i) {
var event = events[i];
if (event.ranges) {
copy.push(instantiateSel ? Selection.prototype.deepCopy.call(event) : event);
continue
}
var changes = event.changes, newChanges = [];
copy.push({changes: newChanges});
for (var j = 0; j < changes.length; ++j) {
var change = changes[j], m = (void 0);
newChanges.push({from: change.from, to: change.to, text: change.text});
if (newGroup) { for (var prop in change) { if (m = prop.match(/^spans_(\d+)$/)) {
if (indexOf(newGroup, Number(m[1])) > -1) {
lst(newChanges)[prop] = change[prop];
delete change[prop];
}
} } }
}
}
return copy
}
// The 'scroll' parameter given to many of these indicated whether
// the new cursor position should be scrolled into view after
// modifying the selection.
// If shift is held or the extend flag is set, extends a range to
// include a given position (and optionally a second position).
// Otherwise, simply returns the range between the given positions.
// Used for cursor motion and such.
function extendRange(range, head, other, extend) {
if (extend) {
var anchor = range.anchor;
if (other) {
var posBefore = cmp(head, anchor) < 0;
if (posBefore != (cmp(other, anchor) < 0)) {
anchor = head;
head = other;
} else if (posBefore != (cmp(head, other) < 0)) {
head = other;
}
}
return new Range(anchor, head)
} else {
return new Range(other || head, head)
}
}
// Extend the primary selection range, discard the rest.
function extendSelection(doc, head, other, options, extend) {
if (extend == null) { extend = doc.cm && (doc.cm.display.shift || doc.extend); }
setSelection(doc, new Selection([extendRange(doc.sel.primary(), head, other, extend)], 0), options);
}
// Extend all selections (pos is an array of selections with length
// equal the number of selections)
function extendSelections(doc, heads, options) {
var out = [];
var extend = doc.cm && (doc.cm.display.shift || doc.extend);
for (var i = 0; i < doc.sel.ranges.length; i++)
{ out[i] = extendRange(doc.sel.ranges[i], heads[i], null, extend); }
var newSel = normalizeSelection(doc.cm, out, doc.sel.primIndex);
setSelection(doc, newSel, options);
}
// Updates a single range in the selection.
function replaceOneSelection(doc, i, range, options) {
var ranges = doc.sel.ranges.slice(0);
ranges[i] = range;
setSelection(doc, normalizeSelection(doc.cm, ranges, doc.sel.primIndex), options);
}
// Reset the selection to a single range.
function setSimpleSelection(doc, anchor, head, options) {
setSelection(doc, simpleSelection(anchor, head), options);
}
// Give beforeSelectionChange handlers a change to influence a
// selection update.
function filterSelectionChange(doc, sel, options) {
var obj = {
ranges: sel.ranges,
update: function(ranges) {
var this$1 = this;
this.ranges = [];
for (var i = 0; i < ranges.length; i++)
{ this$1.ranges[i] = new Range(clipPos(doc, ranges[i].anchor),
clipPos(doc, ranges[i].head)); }
},
origin: options && options.origin
};
signal(doc, "beforeSelectionChange", doc, obj);
if (doc.cm) { signal(doc.cm, "beforeSelectionChange", doc.cm, obj); }
if (obj.ranges != sel.ranges) { return normalizeSelection(doc.cm, obj.ranges, obj.ranges.length - 1) }
else { return sel }
}
function setSelectionReplaceHistory(doc, sel, options) {
var done = doc.history.done, last = lst(done);
if (last && last.ranges) {
done[done.length - 1] = sel;
setSelectionNoUndo(doc, sel, options);
} else {
setSelection(doc, sel, options);
}
}
// Set a new selection.
function setSelection(doc, sel, options) {
setSelectionNoUndo(doc, sel, options);
addSelectionToHistory(doc, doc.sel, doc.cm ? doc.cm.curOp.id : NaN, options);
}
function setSelectionNoUndo(doc, sel, options) {
if (hasHandler(doc, "beforeSelectionChange") || doc.cm && hasHandler(doc.cm, "beforeSelectionChange"))
{ sel = filterSelectionChange(doc, sel, options); }
var bias = options && options.bias ||
(cmp(sel.primary().head, doc.sel.primary().head) < 0 ? -1 : 1);
setSelectionInner(doc, skipAtomicInSelection(doc, sel, bias, true));
if (!(options && options.scroll === false) && doc.cm)
{ ensureCursorVisible(doc.cm); }
}
function setSelectionInner(doc, sel) {
if (sel.equals(doc.sel)) { return }
doc.sel = sel;
if (doc.cm) {
doc.cm.curOp.updateInput = 1;
doc.cm.curOp.selectionChanged = true;
signalCursorActivity(doc.cm);
}
signalLater(doc, "cursorActivity", doc);
}
// Verify that the selection does not partially select any atomic
// marked ranges.
function reCheckSelection(doc) {
setSelectionInner(doc, skipAtomicInSelection(doc, doc.sel, null, false));
}
// Return a selection that does not partially select any atomic
// ranges.
function skipAtomicInSelection(doc, sel, bias, mayClear) {
var out;
for (var i = 0; i < sel.ranges.length; i++) {
var range = sel.ranges[i];
var old = sel.ranges.length == doc.sel.ranges.length && doc.sel.ranges[i];
var newAnchor = skipAtomic(doc, range.anchor, old && old.anchor, bias, mayClear);
var newHead = skipAtomic(doc, range.head, old && old.head, bias, mayClear);
if (out || newAnchor != range.anchor || newHead != range.head) {
if (!out) { out = sel.ranges.slice(0, i); }
out[i] = new Range(newAnchor, newHead);
}
}
return out ? normalizeSelection(doc.cm, out, sel.primIndex) : sel
}
function skipAtomicInner(doc, pos, oldPos, dir, mayClear) {
var line = getLine(doc, pos.line);
if (line.markedSpans) { for (var i = 0; i < line.markedSpans.length; ++i) {
var sp = line.markedSpans[i], m = sp.marker;
if ((sp.from == null || (m.inclusiveLeft ? sp.from <= pos.ch : sp.from < pos.ch)) &&
(sp.to == null || (m.inclusiveRight ? sp.to >= pos.ch : sp.to > pos.ch))) {
if (mayClear) {
signal(m, "beforeCursorEnter");
if (m.explicitlyCleared) {
if (!line.markedSpans) { break }
else {--i; continue}
}
}
if (!m.atomic) { continue }
if (oldPos) {
var near = m.find(dir < 0 ? 1 : -1), diff = (void 0);
if (dir < 0 ? m.inclusiveRight : m.inclusiveLeft)
{ near = movePos(doc, near, -dir, near && near.line == pos.line ? line : null); }
if (near && near.line == pos.line && (diff = cmp(near, oldPos)) && (dir < 0 ? diff < 0 : diff > 0))
{ return skipAtomicInner(doc, near, pos, dir, mayClear) }
}
var far = m.find(dir < 0 ? -1 : 1);
if (dir < 0 ? m.inclusiveLeft : m.inclusiveRight)
{ far = movePos(doc, far, dir, far.line == pos.line ? line : null); }
return far ? skipAtomicInner(doc, far, pos, dir, mayClear) : null
}
} }
return pos
}
// Ensure a given position is not inside an atomic range.
function skipAtomic(doc, pos, oldPos, bias, mayClear) {
var dir = bias || 1;
var found = skipAtomicInner(doc, pos, oldPos, dir, mayClear) ||
(!mayClear && skipAtomicInner(doc, pos, oldPos, dir, true)) ||
skipAtomicInner(doc, pos, oldPos, -dir, mayClear) ||
(!mayClear && skipAtomicInner(doc, pos, oldPos, -dir, true));
if (!found) {
doc.cantEdit = true;
return Pos(doc.first, 0)
}
return found
}
function movePos(doc, pos, dir, line) {
if (dir < 0 && pos.ch == 0) {
if (pos.line > doc.first) { return clipPos(doc, Pos(pos.line - 1)) }
else { return null }
} else if (dir > 0 && pos.ch == (line || getLine(doc, pos.line)).text.length) {
if (pos.line < doc.first + doc.size - 1) { return Pos(pos.line + 1, 0) }
else { return null }
} else {
return new Pos(pos.line, pos.ch + dir)
}
}
function selectAll(cm) {
cm.setSelection(Pos(cm.firstLine(), 0), Pos(cm.lastLine()), sel_dontScroll);
}
// UPDATING
// Allow "beforeChange" event handlers to influence a change
function filterChange(doc, change, update) {
var obj = {
canceled: false,
from: change.from,
to: change.to,
text: change.text,
origin: change.origin,
cancel: function () { return obj.canceled = true; }
};
if (update) { obj.update = function (from, to, text, origin) {
if (from) { obj.from = clipPos(doc, from); }
if (to) { obj.to = clipPos(doc, to); }
if (text) { obj.text = text; }
if (origin !== undefined) { obj.origin = origin; }
}; }
signal(doc, "beforeChange", doc, obj);
if (doc.cm) { signal(doc.cm, "beforeChange", doc.cm, obj); }
if (obj.canceled) {
if (doc.cm) { doc.cm.curOp.updateInput = 2; }
return null
}
return {from: obj.from, to: obj.to, text: obj.text, origin: obj.origin}
}
// Apply a change to a document, and add it to the document's
// history, and propagating it to all linked documents.
function makeChange(doc, change, ignoreReadOnly) {
if (doc.cm) {
if (!doc.cm.curOp) { return operation(doc.cm, makeChange)(doc, change, ignoreReadOnly) }
if (doc.cm.state.suppressEdits) { return }
}
if (hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange")) {
change = filterChange(doc, change, true);
if (!change) { return }
}
// Possibly split or suppress the update based on the presence
// of read-only spans in its range.
var split = sawReadOnlySpans && !ignoreReadOnly && removeReadOnlyRanges(doc, change.from, change.to);
if (split) {
for (var i = split.length - 1; i >= 0; --i)
{ makeChangeInner(doc, {from: split[i].from, to: split[i].to, text: i ? [""] : change.text, origin: change.origin}); }
} else {
makeChangeInner(doc, change);
}
}
function makeChangeInner(doc, change) {
if (change.text.length == 1 && change.text[0] == "" && cmp(change.from, change.to) == 0) { return }
var selAfter = computeSelAfterChange(doc, change);
addChangeToHistory(doc, change, selAfter, doc.cm ? doc.cm.curOp.id : NaN);
makeChangeSingleDoc(doc, change, selAfter, stretchSpansOverChange(doc, change));
var rebased = [];
linkedDocs(doc, function (doc, sharedHist) {
if (!sharedHist && indexOf(rebased, doc.history) == -1) {
rebaseHist(doc.history, change);
rebased.push(doc.history);
}
makeChangeSingleDoc(doc, change, null, stretchSpansOverChange(doc, change));
});
}
// Revert a change stored in a document's history.
function makeChangeFromHistory(doc, type, allowSelectionOnly) {
var suppress = doc.cm && doc.cm.state.suppressEdits;
if (suppress && !allowSelectionOnly) { return }
var hist = doc.history, event, selAfter = doc.sel;
var source = type == "undo" ? hist.done : hist.undone, dest = type == "undo" ? hist.undone : hist.done;
// Verify that there is a useable event (so that ctrl-z won't
// needlessly clear selection events)
var i = 0;
for (; i < source.length; i++) {
event = source[i];
if (allowSelectionOnly ? event.ranges && !event.equals(doc.sel) : !event.ranges)
{ break }
}
if (i == source.length) { return }
hist.lastOrigin = hist.lastSelOrigin = null;
for (;;) {
event = source.pop();
if (event.ranges) {
pushSelectionToHistory(event, dest);
if (allowSelectionOnly && !event.equals(doc.sel)) {
setSelection(doc, event, {clearRedo: false});
return
}
selAfter = event;
} else if (suppress) {
source.push(event);
return
} else { break }
}
// Build up a reverse change object to add to the opposite history
// stack (redo when undoing, and vice versa).
var antiChanges = [];
pushSelectionToHistory(selAfter, dest);
dest.push({changes: antiChanges, generation: hist.generation});
hist.generation = event.generation || ++hist.maxGeneration;
var filter = hasHandler(doc, "beforeChange") || doc.cm && hasHandler(doc.cm, "beforeChange");
var loop = function ( i ) {
var change = event.changes[i];
change.origin = type;
if (filter && !filterChange(doc, change, false)) {
source.length = 0;
return {}
}
antiChanges.push(historyChangeFromChange(doc, change));
var after = i ? computeSelAfterChange(doc, change) : lst(source);
makeChangeSingleDoc(doc, change, after, mergeOldSpans(doc, change));
if (!i && doc.cm) { doc.cm.scrollIntoView({from: change.from, to: changeEnd(change)}); }
var rebased = [];
// Propagate to the linked documents
linkedDocs(doc, function (doc, sharedHist) {
if (!sharedHist && indexOf(rebased, doc.history) == -1) {
rebaseHist(doc.history, change);
rebased.push(doc.history);
}
makeChangeSingleDoc(doc, change, null, mergeOldSpans(doc, change));
});
};
for (var i$1 = event.changes.length - 1; i$1 >= 0; --i$1) {
var returned = loop( i$1 );
if ( returned ) return returned.v;
}
}
// Sub-views need their line numbers shifted when text is added
// above or below them in the parent document.
function shiftDoc(doc, distance) {
if (distance == 0) { return }
doc.first += distance;
doc.sel = new Selection(map(doc.sel.ranges, function (range) { return new Range(
Pos(range.anchor.line + distance, range.anchor.ch),
Pos(range.head.line + distance, range.head.ch)
); }), doc.sel.primIndex);
if (doc.cm) {
regChange(doc.cm, doc.first, doc.first - distance, distance);
for (var d = doc.cm.display, l = d.viewFrom; l < d.viewTo; l++)
{ regLineChange(doc.cm, l, "gutter"); }
}
}
// More lower-level change function, handling only a single document
// (not linked ones).
function makeChangeSingleDoc(doc, change, selAfter, spans) {
if (doc.cm && !doc.cm.curOp)
{ return operation(doc.cm, makeChangeSingleDoc)(doc, change, selAfter, spans) }
if (change.to.line < doc.first) {
shiftDoc(doc, change.text.length - 1 - (change.to.line - change.from.line));
return
}
if (change.from.line > doc.lastLine()) { return }
// Clip the change to the size of this doc
if (change.from.line < doc.first) {
var shift = change.text.length - 1 - (doc.first - change.from.line);
shiftDoc(doc, shift);
change = {from: Pos(doc.first, 0), to: Pos(change.to.line + shift, change.to.ch),
text: [lst(change.text)], origin: change.origin};
}
var last = doc.lastLine();
if (change.to.line > last) {
change = {from: change.from, to: Pos(last, getLine(doc, last).text.length),
text: [change.text[0]], origin: change.origin};
}
change.removed = getBetween(doc, change.from, change.to);
if (!selAfter) { selAfter = computeSelAfterChange(doc, change); }
if (doc.cm) { makeChangeSingleDocInEditor(doc.cm, change, spans); }
else { updateDoc(doc, change, spans); }
setSelectionNoUndo(doc, selAfter, sel_dontScroll);
}
// Handle the interaction of a change to a document with the editor
// that this document is part of.
function makeChangeSingleDocInEditor(cm, change, spans) {
var doc = cm.doc, display = cm.display, from = change.from, to = change.to;
var recomputeMaxLength = false, checkWidthStart = from.line;
if (!cm.options.lineWrapping) {
checkWidthStart = lineNo(visualLine(getLine(doc, from.line)));
doc.iter(checkWidthStart, to.line + 1, function (line) {
if (line == display.maxLine) {
recomputeMaxLength = true;
return true
}
});
}
if (doc.sel.contains(change.from, change.to) > -1)
{ signalCursorActivity(cm); }
updateDoc(doc, change, spans, estimateHeight(cm));
if (!cm.options.lineWrapping) {
doc.iter(checkWidthStart, from.line + change.text.length, function (line) {
var len = lineLength(line);
if (len > display.maxLineLength) {
display.maxLine = line;
display.maxLineLength = len;
display.maxLineChanged = true;
recomputeMaxLength = false;
}
});
if (recomputeMaxLength) { cm.curOp.updateMaxLine = true; }
}
retreatFrontier(doc, from.line);
startWorker(cm, 400);
var lendiff = change.text.length - (to.line - from.line) - 1;
// Remember that these lines changed, for updating the display
if (change.full)
{ regChange(cm); }
else if (from.line == to.line && change.text.length == 1 && !isWholeLineUpdate(cm.doc, change))
{ regLineChange(cm, from.line, "text"); }
else
{ regChange(cm, from.line, to.line + 1, lendiff); }
var changesHandler = hasHandler(cm, "changes"), changeHandler = hasHandler(cm, "change");
if (changeHandler || changesHandler) {
var obj = {
from: from, to: to,
text: change.text,
removed: change.removed,
origin: change.origin
};
if (changeHandler) { signalLater(cm, "change", cm, obj); }
if (changesHandler) { (cm.curOp.changeObjs || (cm.curOp.changeObjs = [])).push(obj); }
}
cm.display.selForContextMenu = null;
}
function replaceRange(doc, code, from, to, origin) {
var assign;
if (!to) { to = from; }
if (cmp(to, from) < 0) { (assign = [to, from], from = assign[0], to = assign[1]); }
if (typeof code == "string") { code = doc.splitLines(code); }
makeChange(doc, {from: from, to: to, text: code, origin: origin});
}
// Rebasing/resetting history to deal with externally-sourced changes
function rebaseHistSelSingle(pos, from, to, diff) {
if (to < pos.line) {
pos.line += diff;
} else if (from < pos.line) {
pos.line = from;
pos.ch = 0;
}
}
// Tries to rebase an array of history events given a change in the
// document. If the change touches the same lines as the event, the
// event, and everything 'behind' it, is discarded. If the change is
// before the event, the event's positions are updated. Uses a
// copy-on-write scheme for the positions, to avoid having to
// reallocate them all on every rebase, but also avoid problems with
// shared position objects being unsafely updated.
function rebaseHistArray(array, from, to, diff) {
for (var i = 0; i < array.length; ++i) {
var sub = array[i], ok = true;
if (sub.ranges) {
if (!sub.copied) { sub = array[i] = sub.deepCopy(); sub.copied = true; }
for (var j = 0; j < sub.ranges.length; j++) {
rebaseHistSelSingle(sub.ranges[j].anchor, from, to, diff);
rebaseHistSelSingle(sub.ranges[j].head, from, to, diff);
}
continue
}
for (var j$1 = 0; j$1 < sub.changes.length; ++j$1) {
var cur = sub.changes[j$1];
if (to < cur.from.line) {
cur.from = Pos(cur.from.line + diff, cur.from.ch);
cur.to = Pos(cur.to.line + diff, cur.to.ch);
} else if (from <= cur.to.line) {
ok = false;
break
}
}
if (!ok) {
array.splice(0, i + 1);
i = 0;
}
}
}
function rebaseHist(hist, change) {
var from = change.from.line, to = change.to.line, diff = change.text.length - (to - from) - 1;
rebaseHistArray(hist.done, from, to, diff);
rebaseHistArray(hist.undone, from, to, diff);
}
// Utility for applying a change to a line by handle or number,
// returning the number and optionally registering the line as
// changed.
function changeLine(doc, handle, changeType, op) {
var no = handle, line = handle;
if (typeof handle == "number") { line = getLine(doc, clipLine(doc, handle)); }
else { no = lineNo(handle); }
if (no == null) { return null }
if (op(line, no) && doc.cm) { regLineChange(doc.cm, no, changeType); }
return line
}
// The document is represented as a BTree consisting of leaves, with
// chunk of lines in them, and branches, with up to ten leaves or
// other branch nodes below them. The top node is always a branch
// node, and is the document object itself (meaning it has
// additional methods and properties).
//
// All nodes have parent links. The tree is used both to go from
// line numbers to line objects, and to go from objects to numbers.
// It also indexes by height, and is used to convert between height
// and line object, and to find the total height of the document.
//
// See also http://marijnhaverbeke.nl/blog/codemirror-line-tree.html
function LeafChunk(lines) {
var this$1 = this;
this.lines = lines;
this.parent = null;
var height = 0;
for (var i = 0; i < lines.length; ++i) {
lines[i].parent = this$1;
height += lines[i].height;
}
this.height = height;
}
LeafChunk.prototype = {
chunkSize: function() { return this.lines.length },
// Remove the n lines at offset 'at'.
removeInner: function(at, n) {
var this$1 = this;
for (var i = at, e = at + n; i < e; ++i) {
var line = this$1.lines[i];
this$1.height -= line.height;
cleanUpLine(line);
signalLater(line, "delete");
}
this.lines.splice(at, n);
},
// Helper used to collapse a small branch into a single leaf.
collapse: function(lines) {
lines.push.apply(lines, this.lines);
},
// Insert the given array of lines at offset 'at', count them as
// having the given height.
insertInner: function(at, lines, height) {
var this$1 = this;
this.height += height;
this.lines = this.lines.slice(0, at).concat(lines).concat(this.lines.slice(at));
for (var i = 0; i < lines.length; ++i) { lines[i].parent = this$1; }
},
// Used to iterate over a part of the tree.
iterN: function(at, n, op) {
var this$1 = this;
for (var e = at + n; at < e; ++at)
{ if (op(this$1.lines[at])) { return true } }
}
};
function BranchChunk(children) {
var this$1 = this;
this.children = children;
var size = 0, height = 0;
for (var i = 0; i < children.length; ++i) {
var ch = children[i];
size += ch.chunkSize(); height += ch.height;
ch.parent = this$1;
}
this.size = size;
this.height = height;
this.parent = null;
}
BranchChunk.prototype = {
chunkSize: function() { return this.size },
removeInner: function(at, n) {
var this$1 = this;
this.size -= n;
for (var i = 0; i < this.children.length; ++i) {
var child = this$1.children[i], sz = child.chunkSize();
if (at < sz) {
var rm = Math.min(n, sz - at), oldHeight = child.height;
child.removeInner(at, rm);
this$1.height -= oldHeight - child.height;
if (sz == rm) { this$1.children.splice(i--, 1); child.parent = null; }
if ((n -= rm) == 0) { break }
at = 0;
} else { at -= sz; }
}
// If the result is smaller than 25 lines, ensure that it is a
// single leaf node.
if (this.size - n < 25 &&
(this.children.length > 1 || !(this.children[0] instanceof LeafChunk))) {
var lines = [];
this.collapse(lines);
this.children = [new LeafChunk(lines)];
this.children[0].parent = this;
}
},
collapse: function(lines) {
var this$1 = this;
for (var i = 0; i < this.children.length; ++i) { this$1.children[i].collapse(lines); }
},
insertInner: function(at, lines, height) {
var this$1 = this;
this.size += lines.length;
this.height += height;
for (var i = 0; i < this.children.length; ++i) {
var child = this$1.children[i], sz = child.chunkSize();
if (at <= sz) {
child.insertInner(at, lines, height);
if (child.lines && child.lines.length > 50) {
// To avoid memory thrashing when child.lines is huge (e.g. first view of a large file), it's never spliced.
// Instead, small slices are taken. They're taken in order because sequential memory accesses are fastest.
var remaining = child.lines.length % 25 + 25;
for (var pos = remaining; pos < child.lines.length;) {
var leaf = new LeafChunk(child.lines.slice(pos, pos += 25));
child.height -= leaf.height;
this$1.children.splice(++i, 0, leaf);
leaf.parent = this$1;
}
child.lines = child.lines.slice(0, remaining);
this$1.maybeSpill();
}
break
}
at -= sz;
}
},
// When a node has grown, check whether it should be split.
maybeSpill: function() {
if (this.children.length <= 10) { return }
var me = this;
do {
var spilled = me.children.splice(me.children.length - 5, 5);
var sibling = new BranchChunk(spilled);
if (!me.parent) { // Become the parent node
var copy = new BranchChunk(me.children);
copy.parent = me;
me.children = [copy, sibling];
me = copy;
} else {
me.size -= sibling.size;
me.height -= sibling.height;
var myIndex = indexOf(me.parent.children, me);
me.parent.children.splice(myIndex + 1, 0, sibling);
}
sibling.parent = me.parent;
} while (me.children.length > 10)
me.parent.maybeSpill();
},
iterN: function(at, n, op) {
var this$1 = this;
for (var i = 0; i < this.children.length; ++i) {
var child = this$1.children[i], sz = child.chunkSize();
if (at < sz) {
var used = Math.min(n, sz - at);
if (child.iterN(at, used, op)) { return true }
if ((n -= used) == 0) { break }
at = 0;
} else { at -= sz; }
}
}
};
// Line widgets are block elements displayed above or below a line.
var LineWidget = function(doc, node, options) {
var this$1 = this;
if (options) { for (var opt in options) { if (options.hasOwnProperty(opt))
{ this$1[opt] = options[opt]; } } }
this.doc = doc;
this.node = node;
};
LineWidget.prototype.clear = function () {
var this$1 = this;
var cm = this.doc.cm, ws = this.line.widgets, line = this.line, no = lineNo(line);
if (no == null || !ws) { return }
for (var i = 0; i < ws.length; ++i) { if (ws[i] == this$1) { ws.splice(i--, 1); } }
if (!ws.length) { line.widgets = null; }
var height = widgetHeight(this);
updateLineHeight(line, Math.max(0, line.height - height));
if (cm) {
runInOp(cm, function () {
adjustScrollWhenAboveVisible(cm, line, -height);
regLineChange(cm, no, "widget");
});
signalLater(cm, "lineWidgetCleared", cm, this, no);
}
};
LineWidget.prototype.changed = function () {
var this$1 = this;
var oldH = this.height, cm = this.doc.cm, line = this.line;
this.height = null;
var diff = widgetHeight(this) - oldH;
if (!diff) { return }
if (!lineIsHidden(this.doc, line)) { updateLineHeight(line, line.height + diff); }
if (cm) {
runInOp(cm, function () {
cm.curOp.forceUpdate = true;
adjustScrollWhenAboveVisible(cm, line, diff);
signalLater(cm, "lineWidgetChanged", cm, this$1, lineNo(line));
});
}
};
eventMixin(LineWidget);
function adjustScrollWhenAboveVisible(cm, line, diff) {
if (heightAtLine(line) < ((cm.curOp && cm.curOp.scrollTop) || cm.doc.scrollTop))
{ addToScrollTop(cm, diff); }
}
function addLineWidget(doc, handle, node, options) {
var widget = new LineWidget(doc, node, options);
var cm = doc.cm;
if (cm && widget.noHScroll) { cm.display.alignWidgets = true; }
changeLine(doc, handle, "widget", function (line) {
var widgets = line.widgets || (line.widgets = []);
if (widget.insertAt == null) { widgets.push(widget); }
else { widgets.splice(Math.min(widgets.length - 1, Math.max(0, widget.insertAt)), 0, widget); }
widget.line = line;
if (cm && !lineIsHidden(doc, line)) {
var aboveVisible = heightAtLine(line) < doc.scrollTop;
updateLineHeight(line, line.height + widgetHeight(widget));
if (aboveVisible) { addToScrollTop(cm, widget.height); }
cm.curOp.forceUpdate = true;
}
return true
});
if (cm) { signalLater(cm, "lineWidgetAdded", cm, widget, typeof handle == "number" ? handle : lineNo(handle)); }
return widget
}
// TEXTMARKERS
// Created with markText and setBookmark methods. A TextMarker is a
// handle that can be used to clear or find a marked position in the
// document. Line objects hold arrays (markedSpans) containing
// {from, to, marker} object pointing to such marker objects, and
// indicating that such a marker is present on that line. Multiple
// lines may point to the same marker when it spans across lines.
// The spans will have null for their from/to properties when the
// marker continues beyond the start/end of the line. Markers have
// links back to the lines they currently touch.
// Collapsed markers have unique ids, in order to be able to order
// them, which is needed for uniquely determining an outer marker
// when they overlap (they may nest, but not partially overlap).
var nextMarkerId = 0;
var TextMarker = function(doc, type) {
this.lines = [];
this.type = type;
this.doc = doc;
this.id = ++nextMarkerId;
};
// Clear the marker.
TextMarker.prototype.clear = function () {
var this$1 = this;
if (this.explicitlyCleared) { return }
var cm = this.doc.cm, withOp = cm && !cm.curOp;
if (withOp) { startOperation(cm); }
if (hasHandler(this, "clear")) {
var found = this.find();
if (found) { signalLater(this, "clear", found.from, found.to); }
}
var min = null, max = null;
for (var i = 0; i < this.lines.length; ++i) {
var line = this$1.lines[i];
var span = getMarkedSpanFor(line.markedSpans, this$1);
if (cm && !this$1.collapsed) { regLineChange(cm, lineNo(line), "text"); }
else if (cm) {
if (span.to != null) { max = lineNo(line); }
if (span.from != null) { min = lineNo(line); }
}
line.markedSpans = removeMarkedSpan(line.markedSpans, span);
if (span.from == null && this$1.collapsed && !lineIsHidden(this$1.doc, line) && cm)
{ updateLineHeight(line, textHeight(cm.display)); }
}
if (cm && this.collapsed && !cm.options.lineWrapping) { for (var i$1 = 0; i$1 < this.lines.length; ++i$1) {
var visual = visualLine(this$1.lines[i$1]), len = lineLength(visual);
if (len > cm.display.maxLineLength) {
cm.display.maxLine = visual;
cm.display.maxLineLength = len;
cm.display.maxLineChanged = true;
}
} }
if (min != null && cm && this.collapsed) { regChange(cm, min, max + 1); }
this.lines.length = 0;
this.explicitlyCleared = true;
if (this.atomic && this.doc.cantEdit) {
this.doc.cantEdit = false;
if (cm) { reCheckSelection(cm.doc); }
}
if (cm) { signalLater(cm, "markerCleared", cm, this, min, max); }
if (withOp) { endOperation(cm); }
if (this.parent) { this.parent.clear(); }
};
// Find the position of the marker in the document. Returns a {from,
// to} object by default. Side can be passed to get a specific side
// -- 0 (both), -1 (left), or 1 (right). When lineObj is true, the
// Pos objects returned contain a line object, rather than a line
// number (used to prevent looking up the same line twice).
TextMarker.prototype.find = function (side, lineObj) {
var this$1 = this;
if (side == null && this.type == "bookmark") { side = 1; }
var from, to;
for (var i = 0; i < this.lines.length; ++i) {
var line = this$1.lines[i];
var span = getMarkedSpanFor(line.markedSpans, this$1);
if (span.from != null) {
from = Pos(lineObj ? line : lineNo(line), span.from);
if (side == -1) { return from }
}
if (span.to != null) {
to = Pos(lineObj ? line : lineNo(line), span.to);
if (side == 1) { return to }
}
}
return from && {from: from, to: to}
};
// Signals that the marker's widget changed, and surrounding layout
// should be recomputed.
TextMarker.prototype.changed = function () {
var this$1 = this;
var pos = this.find(-1, true), widget = this, cm = this.doc.cm;
if (!pos || !cm) { return }
runInOp(cm, function () {
var line = pos.line, lineN = lineNo(pos.line);
var view = findViewForLine(cm, lineN);
if (view) {
clearLineMeasurementCacheFor(view);
cm.curOp.selectionChanged = cm.curOp.forceUpdate = true;
}
cm.curOp.updateMaxLine = true;
if (!lineIsHidden(widget.doc, line) && widget.height != null) {
var oldHeight = widget.height;
widget.height = null;
var dHeight = widgetHeight(widget) - oldHeight;
if (dHeight)
{ updateLineHeight(line, line.height + dHeight); }
}
signalLater(cm, "markerChanged", cm, this$1);
});
};
TextMarker.prototype.attachLine = function (line) {
if (!this.lines.length && this.doc.cm) {
var op = this.doc.cm.curOp;
if (!op.maybeHiddenMarkers || indexOf(op.maybeHiddenMarkers, this) == -1)
{ (op.maybeUnhiddenMarkers || (op.maybeUnhiddenMarkers = [])).push(this); }
}
this.lines.push(line);
};
TextMarker.prototype.detachLine = function (line) {
this.lines.splice(indexOf(this.lines, line), 1);
if (!this.lines.length && this.doc.cm) {
var op = this.doc.cm.curOp
;(op.maybeHiddenMarkers || (op.maybeHiddenMarkers = [])).push(this);
}
};
eventMixin(TextMarker);
// Create a marker, wire it up to the right lines, and
function markText(doc, from, to, options, type) {
// Shared markers (across linked documents) are handled separately
// (markTextShared will call out to this again, once per
// document).
if (options && options.shared) { return markTextShared(doc, from, to, options, type) }
// Ensure we are in an operation.
if (doc.cm && !doc.cm.curOp) { return operation(doc.cm, markText)(doc, from, to, options, type) }
var marker = new TextMarker(doc, type), diff = cmp(from, to);
if (options) { copyObj(options, marker, false); }
// Don't connect empty markers unless clearWhenEmpty is false
if (diff > 0 || diff == 0 && marker.clearWhenEmpty !== false)
{ return marker }
if (marker.replacedWith) {
// Showing up as a widget implies collapsed (widget replaces text)
marker.collapsed = true;
marker.widgetNode = eltP("span", [marker.replacedWith], "CodeMirror-widget");
if (!options.handleMouseEvents) { marker.widgetNode.setAttribute("cm-ignore-events", "true"); }
if (options.insertLeft) { marker.widgetNode.insertLeft = true; }
}
if (marker.collapsed) {
if (conflictingCollapsedRange(doc, from.line, from, to, marker) ||
from.line != to.line && conflictingCollapsedRange(doc, to.line, from, to, marker))
{ throw new Error("Inserting collapsed marker partially overlapping an existing one") }
seeCollapsedSpans();
}
if (marker.addToHistory)
{ addChangeToHistory(doc, {from: from, to: to, origin: "markText"}, doc.sel, NaN); }
var curLine = from.line, cm = doc.cm, updateMaxLine;
doc.iter(curLine, to.line + 1, function (line) {
if (cm && marker.collapsed && !cm.options.lineWrapping && visualLine(line) == cm.display.maxLine)
{ updateMaxLine = true; }
if (marker.collapsed && curLine != from.line) { updateLineHeight(line, 0); }
addMarkedSpan(line, new MarkedSpan(marker,
curLine == from.line ? from.ch : null,
curLine == to.line ? to.ch : null));
++curLine;
});
// lineIsHidden depends on the presence of the spans, so needs a second pass
if (marker.collapsed) { doc.iter(from.line, to.line + 1, function (line) {
if (lineIsHidden(doc, line)) { updateLineHeight(line, 0); }
}); }
if (marker.clearOnEnter) { on(marker, "beforeCursorEnter", function () { return marker.clear(); }); }
if (marker.readOnly) {
seeReadOnlySpans();
if (doc.history.done.length || doc.history.undone.length)
{ doc.clearHistory(); }
}
if (marker.collapsed) {
marker.id = ++nextMarkerId;
marker.atomic = true;
}
if (cm) {
// Sync editor state
if (updateMaxLine) { cm.curOp.updateMaxLine = true; }
if (marker.collapsed)
{ regChange(cm, from.line, to.line + 1); }
else if (marker.className || marker.startStyle || marker.endStyle || marker.css ||
marker.attributes || marker.title)
{ for (var i = from.line; i <= to.line; i++) { regLineChange(cm, i, "text"); } }
if (marker.atomic) { reCheckSelection(cm.doc); }
signalLater(cm, "markerAdded", cm, marker);
}
return marker
}
// SHARED TEXTMARKERS
// A shared marker spans multiple linked documents. It is
// implemented as a meta-marker-object controlling multiple normal
// markers.
var SharedTextMarker = function(markers, primary) {
var this$1 = this;
this.markers = markers;
this.primary = primary;
for (var i = 0; i < markers.length; ++i)
{ markers[i].parent = this$1; }
};
SharedTextMarker.prototype.clear = function () {
var this$1 = this;
if (this.explicitlyCleared) { return }
this.explicitlyCleared = true;
for (var i = 0; i < this.markers.length; ++i)
{ this$1.markers[i].clear(); }
signalLater(this, "clear");
};
SharedTextMarker.prototype.find = function (side, lineObj) {
return this.primary.find(side, lineObj)
};
eventMixin(SharedTextMarker);
function markTextShared(doc, from, to, options, type) {
options = copyObj(options);
options.shared = false;
var markers = [markText(doc, from, to, options, type)], primary = markers[0];
var widget = options.widgetNode;
linkedDocs(doc, function (doc) {
if (widget) { options.widgetNode = widget.cloneNode(true); }
markers.push(markText(doc, clipPos(doc, from), clipPos(doc, to), options, type));
for (var i = 0; i < doc.linked.length; ++i)
{ if (doc.linked[i].isParent) { return } }
primary = lst(markers);
});
return new SharedTextMarker(markers, primary)
}
function findSharedMarkers(doc) {
return doc.findMarks(Pos(doc.first, 0), doc.clipPos(Pos(doc.lastLine())), function (m) { return m.parent; })
}
function copySharedMarkers(doc, markers) {
for (var i = 0; i < markers.length; i++) {
var marker = markers[i], pos = marker.find();
var mFrom = doc.clipPos(pos.from), mTo = doc.clipPos(pos.to);
if (cmp(mFrom, mTo)) {
var subMark = markText(doc, mFrom, mTo, marker.primary, marker.primary.type);
marker.markers.push(subMark);
subMark.parent = marker;
}
}
}
function detachSharedMarkers(markers) {
var loop = function ( i ) {
var marker = markers[i], linked = [marker.primary.doc];
linkedDocs(marker.primary.doc, function (d) { return linked.push(d); });
for (var j = 0; j < marker.markers.length; j++) {
var subMarker = marker.markers[j];
if (indexOf(linked, subMarker.doc) == -1) {
subMarker.parent = null;
marker.markers.splice(j--, 1);
}
}
};
for (var i = 0; i < markers.length; i++) loop( i );
}
var nextDocId = 0;
var Doc = function(text, mode, firstLine, lineSep, direction) {
if (!(this instanceof Doc)) { return new Doc(text, mode, firstLine, lineSep, direction) }
if (firstLine == null) { firstLine = 0; }
BranchChunk.call(this, [new LeafChunk([new Line("", null)])]);
this.first = firstLine;
this.scrollTop = this.scrollLeft = 0;
this.cantEdit = false;
this.cleanGeneration = 1;
this.modeFrontier = this.highlightFrontier = firstLine;
var start = Pos(firstLine, 0);
this.sel = simpleSelection(start);
this.history = new History(null);
this.id = ++nextDocId;
this.modeOption = mode;
this.lineSep = lineSep;
this.direction = (direction == "rtl") ? "rtl" : "ltr";
this.extend = false;
if (typeof text == "string") { text = this.splitLines(text); }
updateDoc(this, {from: start, to: start, text: text});
setSelection(this, simpleSelection(start), sel_dontScroll);
};
Doc.prototype = createObj(BranchChunk.prototype, {
constructor: Doc,
// Iterate over the document. Supports two forms -- with only one
// argument, it calls that for each line in the document. With
// three, it iterates over the range given by the first two (with
// the second being non-inclusive).
iter: function(from, to, op) {
if (op) { this.iterN(from - this.first, to - from, op); }
else { this.iterN(this.first, this.first + this.size, from); }
},
// Non-public interface for adding and removing lines.
insert: function(at, lines) {
var height = 0;
for (var i = 0; i < lines.length; ++i) { height += lines[i].height; }
this.insertInner(at - this.first, lines, height);
},
remove: function(at, n) { this.removeInner(at - this.first, n); },
// From here, the methods are part of the public interface. Most
// are also available from CodeMirror (editor) instances.
getValue: function(lineSep) {
var lines = getLines(this, this.first, this.first + this.size);
if (lineSep === false) { return lines }
return lines.join(lineSep || this.lineSeparator())
},
setValue: docMethodOp(function(code) {
var top = Pos(this.first, 0), last = this.first + this.size - 1;
makeChange(this, {from: top, to: Pos(last, getLine(this, last).text.length),
text: this.splitLines(code), origin: "setValue", full: true}, true);
if (this.cm) { scrollToCoords(this.cm, 0, 0); }
setSelection(this, simpleSelection(top), sel_dontScroll);
}),
replaceRange: function(code, from, to, origin) {
from = clipPos(this, from);
to = to ? clipPos(this, to) : from;
replaceRange(this, code, from, to, origin);
},
getRange: function(from, to, lineSep) {
var lines = getBetween(this, clipPos(this, from), clipPos(this, to));
if (lineSep === false) { return lines }
return lines.join(lineSep || this.lineSeparator())
},
getLine: function(line) {var l = this.getLineHandle(line); return l && l.text},
getLineHandle: function(line) {if (isLine(this, line)) { return getLine(this, line) }},
getLineNumber: function(line) {return lineNo(line)},
getLineHandleVisualStart: function(line) {
if (typeof line == "number") { line = getLine(this, line); }
return visualLine(line)
},
lineCount: function() {return this.size},
firstLine: function() {return this.first},
lastLine: function() {return this.first + this.size - 1},
clipPos: function(pos) {return clipPos(this, pos)},
getCursor: function(start) {
var range$$1 = this.sel.primary(), pos;
if (start == null || start == "head") { pos = range$$1.head; }
else if (start == "anchor") { pos = range$$1.anchor; }
else if (start == "end" || start == "to" || start === false) { pos = range$$1.to(); }
else { pos = range$$1.from(); }
return pos
},
listSelections: function() { return this.sel.ranges },
somethingSelected: function() {return this.sel.somethingSelected()},
setCursor: docMethodOp(function(line, ch, options) {
setSimpleSelection(this, clipPos(this, typeof line == "number" ? Pos(line, ch || 0) : line), null, options);
}),
setSelection: docMethodOp(function(anchor, head, options) {
setSimpleSelection(this, clipPos(this, anchor), clipPos(this, head || anchor), options);
}),
extendSelection: docMethodOp(function(head, other, options) {
extendSelection(this, clipPos(this, head), other && clipPos(this, other), options);
}),
extendSelections: docMethodOp(function(heads, options) {
extendSelections(this, clipPosArray(this, heads), options);
}),
extendSelectionsBy: docMethodOp(function(f, options) {
var heads = map(this.sel.ranges, f);
extendSelections(this, clipPosArray(this, heads), options);
}),
setSelections: docMethodOp(function(ranges, primary, options) {
var this$1 = this;
if (!ranges.length) { return }
var out = [];
for (var i = 0; i < ranges.length; i++)
{ out[i] = new Range(clipPos(this$1, ranges[i].anchor),
clipPos(this$1, ranges[i].head)); }
if (primary == null) { primary = Math.min(ranges.length - 1, this.sel.primIndex); }
setSelection(this, normalizeSelection(this.cm, out, primary), options);
}),
addSelection: docMethodOp(function(anchor, head, options) {
var ranges = this.sel.ranges.slice(0);
ranges.push(new Range(clipPos(this, anchor), clipPos(this, head || anchor)));
setSelection(this, normalizeSelection(this.cm, ranges, ranges.length - 1), options);
}),
getSelection: function(lineSep) {
var this$1 = this;
var ranges = this.sel.ranges, lines;
for (var i = 0; i < ranges.length; i++) {
var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
lines = lines ? lines.concat(sel) : sel;
}
if (lineSep === false) { return lines }
else { return lines.join(lineSep || this.lineSeparator()) }
},
getSelections: function(lineSep) {
var this$1 = this;
var parts = [], ranges = this.sel.ranges;
for (var i = 0; i < ranges.length; i++) {
var sel = getBetween(this$1, ranges[i].from(), ranges[i].to());
if (lineSep !== false) { sel = sel.join(lineSep || this$1.lineSeparator()); }
parts[i] = sel;
}
return parts
},
replaceSelection: function(code, collapse, origin) {
var dup = [];
for (var i = 0; i < this.sel.ranges.length; i++)
{ dup[i] = code; }
this.replaceSelections(dup, collapse, origin || "+input");
},
replaceSelections: docMethodOp(function(code, collapse, origin) {
var this$1 = this;
var changes = [], sel = this.sel;
for (var i = 0; i < sel.ranges.length; i++) {
var range$$1 = sel.ranges[i];
changes[i] = {from: range$$1.from(), to: range$$1.to(), text: this$1.splitLines(code[i]), origin: origin};
}
var newSel = collapse && collapse != "end" && computeReplacedSel(this, changes, collapse);
for (var i$1 = changes.length - 1; i$1 >= 0; i$1--)
{ makeChange(this$1, changes[i$1]); }
if (newSel) { setSelectionReplaceHistory(this, newSel); }
else if (this.cm) { ensureCursorVisible(this.cm); }
}),
undo: docMethodOp(function() {makeChangeFromHistory(this, "undo");}),
redo: docMethodOp(function() {makeChangeFromHistory(this, "redo");}),
undoSelection: docMethodOp(function() {makeChangeFromHistory(this, "undo", true);}),
redoSelection: docMethodOp(function() {makeChangeFromHistory(this, "redo", true);}),
setExtending: function(val) {this.extend = val;},
getExtending: function() {return this.extend},
historySize: function() {
var hist = this.history, done = 0, undone = 0;
for (var i = 0; i < hist.done.length; i++) { if (!hist.done[i].ranges) { ++done; } }
for (var i$1 = 0; i$1 < hist.undone.length; i$1++) { if (!hist.undone[i$1].ranges) { ++undone; } }
return {undo: done, redo: undone}
},
clearHistory: function() {this.history = new History(this.history.maxGeneration);},
markClean: function() {
this.cleanGeneration = this.changeGeneration(true);
},
changeGeneration: function(forceSplit) {
if (forceSplit)
{ this.history.lastOp = this.history.lastSelOp = this.history.lastOrigin = null; }
return this.history.generation
},
isClean: function (gen) {
return this.history.generation == (gen || this.cleanGeneration)
},
getHistory: function() {
return {done: copyHistoryArray(this.history.done),
undone: copyHistoryArray(this.history.undone)}
},
setHistory: function(histData) {
var hist = this.history = new History(this.history.maxGeneration);
hist.done = copyHistoryArray(histData.done.slice(0), null, true);
hist.undone = copyHistoryArray(histData.undone.slice(0), null, true);
},
setGutterMarker: docMethodOp(function(line, gutterID, value) {
return changeLine(this, line, "gutter", function (line) {
var markers = line.gutterMarkers || (line.gutterMarkers = {});
markers[gutterID] = value;
if (!value && isEmpty(markers)) { line.gutterMarkers = null; }
return true
})
}),
clearGutter: docMethodOp(function(gutterID) {
var this$1 = this;
this.iter(function (line) {
if (line.gutterMarkers && line.gutterMarkers[gutterID]) {
changeLine(this$1, line, "gutter", function () {
line.gutterMarkers[gutterID] = null;
if (isEmpty(line.gutterMarkers)) { line.gutterMarkers = null; }
return true
});
}
});
}),
lineInfo: function(line) {
var n;
if (typeof line == "number") {
if (!isLine(this, line)) { return null }
n = line;
line = getLine(this, line);
if (!line) { return null }
} else {
n = lineNo(line);
if (n == null) { return null }
}
return {line: n, handle: line, text: line.text, gutterMarkers: line.gutterMarkers,
textClass: line.textClass, bgClass: line.bgClass, wrapClass: line.wrapClass,
widgets: line.widgets}
},
addLineClass: docMethodOp(function(handle, where, cls) {
return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
var prop = where == "text" ? "textClass"
: where == "background" ? "bgClass"
: where == "gutter" ? "gutterClass" : "wrapClass";
if (!line[prop]) { line[prop] = cls; }
else if (classTest(cls).test(line[prop])) { return false }
else { line[prop] += " " + cls; }
return true
})
}),
removeLineClass: docMethodOp(function(handle, where, cls) {
return changeLine(this, handle, where == "gutter" ? "gutter" : "class", function (line) {
var prop = where == "text" ? "textClass"
: where == "background" ? "bgClass"
: where == "gutter" ? "gutterClass" : "wrapClass";
var cur = line[prop];
if (!cur) { return false }
else if (cls == null) { line[prop] = null; }
else {
var found = cur.match(classTest(cls));
if (!found) { return false }
var end = found.index + found[0].length;
line[prop] = cur.slice(0, found.index) + (!found.index || end == cur.length ? "" : " ") + cur.slice(end) || null;
}
return true
})
}),
addLineWidget: docMethodOp(function(handle, node, options) {
return addLineWidget(this, handle, node, options)
}),
removeLineWidget: function(widget) { widget.clear(); },
markText: function(from, to, options) {
return markText(this, clipPos(this, from), clipPos(this, to), options, options && options.type || "range")
},
setBookmark: function(pos, options) {
var realOpts = {replacedWith: options && (options.nodeType == null ? options.widget : options),
insertLeft: options && options.insertLeft,
clearWhenEmpty: false, shared: options && options.shared,
handleMouseEvents: options && options.handleMouseEvents};
pos = clipPos(this, pos);
return markText(this, pos, pos, realOpts, "bookmark")
},
findMarksAt: function(pos) {
pos = clipPos(this, pos);
var markers = [], spans = getLine(this, pos.line).markedSpans;
if (spans) { for (var i = 0; i < spans.length; ++i) {
var span = spans[i];
if ((span.from == null || span.from <= pos.ch) &&
(span.to == null || span.to >= pos.ch))
{ markers.push(span.marker.parent || span.marker); }
} }
return markers
},
findMarks: function(from, to, filter) {
from = clipPos(this, from); to = clipPos(this, to);
var found = [], lineNo$$1 = from.line;
this.iter(from.line, to.line + 1, function (line) {
var spans = line.markedSpans;
if (spans) { for (var i = 0; i < spans.length; i++) {
var span = spans[i];
if (!(span.to != null && lineNo$$1 == from.line && from.ch >= span.to ||
span.from == null && lineNo$$1 != from.line ||
span.from != null && lineNo$$1 == to.line && span.from >= to.ch) &&
(!filter || filter(span.marker)))
{ found.push(span.marker.parent || span.marker); }
} }
++lineNo$$1;
});
return found
},
getAllMarks: function() {
var markers = [];
this.iter(function (line) {
var sps = line.markedSpans;
if (sps) { for (var i = 0; i < sps.length; ++i)
{ if (sps[i].from != null) { markers.push(sps[i].marker); } } }
});
return markers
},
posFromIndex: function(off) {
var ch, lineNo$$1 = this.first, sepSize = this.lineSeparator().length;
this.iter(function (line) {
var sz = line.text.length + sepSize;
if (sz > off) { ch = off; return true }
off -= sz;
++lineNo$$1;
});
return clipPos(this, Pos(lineNo$$1, ch))
},
indexFromPos: function (coords) {
coords = clipPos(this, coords);
var index = coords.ch;
if (coords.line < this.first || coords.ch < 0) { return 0 }
var sepSize = this.lineSeparator().length;
this.iter(this.first, coords.line, function (line) { // iter aborts when callback returns a truthy value
index += line.text.length + sepSize;
});
return index
},
copy: function(copyHistory) {
var doc = new Doc(getLines(this, this.first, this.first + this.size),
this.modeOption, this.first, this.lineSep, this.direction);
doc.scrollTop = this.scrollTop; doc.scrollLeft = this.scrollLeft;
doc.sel = this.sel;
doc.extend = false;
if (copyHistory) {
doc.history.undoDepth = this.history.undoDepth;
doc.setHistory(this.getHistory());
}
return doc
},
linkedDoc: function(options) {
if (!options) { options = {}; }
var from = this.first, to = this.first + this.size;
if (options.from != null && options.from > from) { from = options.from; }
if (options.to != null && options.to < to) { to = options.to; }
var copy = new Doc(getLines(this, from, to), options.mode || this.modeOption, from, this.lineSep, this.direction);
if (options.sharedHist) { copy.history = this.history
; }(this.linked || (this.linked = [])).push({doc: copy, sharedHist: options.sharedHist});
copy.linked = [{doc: this, isParent: true, sharedHist: options.sharedHist}];
copySharedMarkers(copy, findSharedMarkers(this));
return copy
},
unlinkDoc: function(other) {
var this$1 = this;
if (other instanceof CodeMirror) { other = other.doc; }
if (this.linked) { for (var i = 0; i < this.linked.length; ++i) {
var link = this$1.linked[i];
if (link.doc != other) { continue }
this$1.linked.splice(i, 1);
other.unlinkDoc(this$1);
detachSharedMarkers(findSharedMarkers(this$1));
break
} }
// If the histories were shared, split them again
if (other.history == this.history) {
var splitIds = [other.id];
linkedDocs(other, function (doc) { return splitIds.push(doc.id); }, true);
other.history = new History(null);
other.history.done = copyHistoryArray(this.history.done, splitIds);
other.history.undone = copyHistoryArray(this.history.undone, splitIds);
}
},
iterLinkedDocs: function(f) {linkedDocs(this, f);},
getMode: function() {return this.mode},
getEditor: function() {return this.cm},
splitLines: function(str) {
if (this.lineSep) { return str.split(this.lineSep) }
return splitLinesAuto(str)
},
lineSeparator: function() { return this.lineSep || "\n" },
setDirection: docMethodOp(function (dir) {
if (dir != "rtl") { dir = "ltr"; }
if (dir == this.direction) { return }
this.direction = dir;
this.iter(function (line) { return line.order = null; });
if (this.cm) { directionChanged(this.cm); }
})
});
// Public alias.
Doc.prototype.eachLine = Doc.prototype.iter;
// Kludge to work around strange IE behavior where it'll sometimes
// re-fire a series of drag-related events right after the drop (#1551)
var lastDrop = 0;
function onDrop(e) {
var cm = this;
clearDragCursor(cm);
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e))
{ return }
e_preventDefault(e);
if (ie) { lastDrop = +new Date; }
var pos = posFromMouse(cm, e, true), files = e.dataTransfer.files;
if (!pos || cm.isReadOnly()) { return }
// Might be a file drop, in which case we simply extract the text
// and insert it.
if (files && files.length && window.FileReader && window.File) {
var n = files.length, text = Array(n), read = 0;
var loadFile = function (file, i) {
if (cm.options.allowDropFileTypes &&
indexOf(cm.options.allowDropFileTypes, file.type) == -1)
{ return }
var reader = new FileReader;
reader.onload = operation(cm, function () {
var content = reader.result;
if (/[\x00-\x08\x0e-\x1f]{2}/.test(content)) { content = ""; }
text[i] = content;
if (++read == n) {
pos = clipPos(cm.doc, pos);
var change = {from: pos, to: pos,
text: cm.doc.splitLines(text.join(cm.doc.lineSeparator())),
origin: "paste"};
makeChange(cm.doc, change);
setSelectionReplaceHistory(cm.doc, simpleSelection(pos, changeEnd(change)));
}
});
reader.readAsText(file);
};
for (var i = 0; i < n; ++i) { loadFile(files[i], i); }
} else { // Normal drop
// Don't do a replace if the drop happened inside of the selected text.
if (cm.state.draggingText && cm.doc.sel.contains(pos) > -1) {
cm.state.draggingText(e);
// Ensure the editor is re-focused
setTimeout(function () { return cm.display.input.focus(); }, 20);
return
}
try {
var text$1 = e.dataTransfer.getData("Text");
if (text$1) {
var selected;
if (cm.state.draggingText && !cm.state.draggingText.copy)
{ selected = cm.listSelections(); }
setSelectionNoUndo(cm.doc, simpleSelection(pos, pos));
if (selected) { for (var i$1 = 0; i$1 < selected.length; ++i$1)
{ replaceRange(cm.doc, "", selected[i$1].anchor, selected[i$1].head, "drag"); } }
cm.replaceSelection(text$1, "around", "paste");
cm.display.input.focus();
}
}
catch(e){}
}
}
function onDragStart(cm, e) {
if (ie && (!cm.state.draggingText || +new Date - lastDrop < 100)) { e_stop(e); return }
if (signalDOMEvent(cm, e) || eventInWidget(cm.display, e)) { return }
e.dataTransfer.setData("Text", cm.getSelection());
e.dataTransfer.effectAllowed = "copyMove";
// Use dummy image instead of default browsers image.
// Recent Safari (~6.0.2) have a tendency to segfault when this happens, so we don't do it there.
if (e.dataTransfer.setDragImage && !safari) {
var img = elt("img", null, null, "position: fixed; left: 0; top: 0;");
img.src = "data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==";
if (presto) {
img.width = img.height = 1;
cm.display.wrapper.appendChild(img);
// Force a relayout, or Opera won't use our image for some obscure reason
img._top = img.offsetTop;
}
e.dataTransfer.setDragImage(img, 0, 0);
if (presto) { img.parentNode.removeChild(img); }
}
}
function onDragOver(cm, e) {
var pos = posFromMouse(cm, e);
if (!pos) { return }
var frag = document.createDocumentFragment();
drawSelectionCursor(cm, pos, frag);
if (!cm.display.dragCursor) {
cm.display.dragCursor = elt("div", null, "CodeMirror-cursors CodeMirror-dragcursors");
cm.display.lineSpace.insertBefore(cm.display.dragCursor, cm.display.cursorDiv);
}
removeChildrenAndAdd(cm.display.dragCursor, frag);
}
function clearDragCursor(cm) {
if (cm.display.dragCursor) {
cm.display.lineSpace.removeChild(cm.display.dragCursor);
cm.display.dragCursor = null;
}
}
// These must be handled carefully, because naively registering a
// handler for each editor will cause the editors to never be
// garbage collected.
function forEachCodeMirror(f) {
if (!document.getElementsByClassName) { return }
var byClass = document.getElementsByClassName("CodeMirror"), editors = [];
for (var i = 0; i < byClass.length; i++) {
var cm = byClass[i].CodeMirror;
if (cm) { editors.push(cm); }
}
if (editors.length) { editors[0].operation(function () {
for (var i = 0; i < editors.length; i++) { f(editors[i]); }
}); }
}
var globalsRegistered = false;
function ensureGlobalHandlers() {
if (globalsRegistered) { return }
registerGlobalHandlers();
globalsRegistered = true;
}
function registerGlobalHandlers() {
// When the window resizes, we need to refresh active editors.
var resizeTimer;
on(window, "resize", function () {
if (resizeTimer == null) { resizeTimer = setTimeout(function () {
resizeTimer = null;
forEachCodeMirror(onResize);
}, 100); }
});
// When the window loses focus, we want to show the editor as blurred
on(window, "blur", function () { return forEachCodeMirror(onBlur); });
}
// Called when the window resizes
function onResize(cm) {
var d = cm.display;
// Might be a text scaling operation, clear size caches.
d.cachedCharWidth = d.cachedTextHeight = d.cachedPaddingH = null;
d.scrollbarsClipped = false;
cm.setSize();
}
var keyNames = {
3: "Pause", 8: "Backspace", 9: "Tab", 13: "Enter", 16: "Shift", 17: "Ctrl", 18: "Alt",
19: "Pause", 20: "CapsLock", 27: "Esc", 32: "Space", 33: "PageUp", 34: "PageDown", 35: "End",
36: "Home", 37: "Left", 38: "Up", 39: "Right", 40: "Down", 44: "PrintScrn", 45: "Insert",
46: "Delete", 59: ";", 61: "=", 91: "Mod", 92: "Mod", 93: "Mod",
106: "*", 107: "=", 109: "-", 110: ".", 111: "/", 127: "Delete", 145: "ScrollLock",
173: "-", 186: ";", 187: "=", 188: ",", 189: "-", 190: ".", 191: "/", 192: "`", 219: "[", 220: "\\",
221: "]", 222: "'", 63232: "Up", 63233: "Down", 63234: "Left", 63235: "Right", 63272: "Delete",
63273: "Home", 63275: "End", 63276: "PageUp", 63277: "PageDown", 63302: "Insert"
};
// Number keys
for (var i = 0; i < 10; i++) { keyNames[i + 48] = keyNames[i + 96] = String(i); }
// Alphabetic keys
for (var i$1 = 65; i$1 <= 90; i$1++) { keyNames[i$1] = String.fromCharCode(i$1); }
// Function keys
for (var i$2 = 1; i$2 <= 12; i$2++) { keyNames[i$2 + 111] = keyNames[i$2 + 63235] = "F" + i$2; }
var keyMap = {};
keyMap.basic = {
"Left": "goCharLeft", "Right": "goCharRight", "Up": "goLineUp", "Down": "goLineDown",
"End": "goLineEnd", "Home": "goLineStartSmart", "PageUp": "goPageUp", "PageDown": "goPageDown",
"Delete": "delCharAfter", "Backspace": "delCharBefore", "Shift-Backspace": "delCharBefore",
"Tab": "defaultTab", "Shift-Tab": "indentAuto",
"Enter": "newlineAndIndent", "Insert": "toggleOverwrite",
"Esc": "singleSelection"
};
// Note that the save and find-related commands aren't defined by
// default. User code or addons can define them. Unknown commands
// are simply ignored.
keyMap.pcDefault = {
"Ctrl-A": "selectAll", "Ctrl-D": "deleteLine", "Ctrl-Z": "undo", "Shift-Ctrl-Z": "redo", "Ctrl-Y": "redo",
"Ctrl-Home": "goDocStart", "Ctrl-End": "goDocEnd", "Ctrl-Up": "goLineUp", "Ctrl-Down": "goLineDown",
"Ctrl-Left": "goGroupLeft", "Ctrl-Right": "goGroupRight", "Alt-Left": "goLineStart", "Alt-Right": "goLineEnd",
"Ctrl-Backspace": "delGroupBefore", "Ctrl-Delete": "delGroupAfter", "Ctrl-S": "save", "Ctrl-F": "find",
"Ctrl-G": "findNext", "Shift-Ctrl-G": "findPrev", "Shift-Ctrl-F": "replace", "Shift-Ctrl-R": "replaceAll",
"Ctrl-[": "indentLess", "Ctrl-]": "indentMore",
"Ctrl-U": "undoSelection", "Shift-Ctrl-U": "redoSelection", "Alt-U": "redoSelection",
"fallthrough": "basic"
};
// Very basic readline/emacs-style bindings, which are standard on Mac.
keyMap.emacsy = {
"Ctrl-F": "goCharRight", "Ctrl-B": "goCharLeft", "Ctrl-P": "goLineUp", "Ctrl-N": "goLineDown",
"Alt-F": "goWordRight", "Alt-B": "goWordLeft", "Ctrl-A": "goLineStart", "Ctrl-E": "goLineEnd",
"Ctrl-V": "goPageDown", "Shift-Ctrl-V": "goPageUp", "Ctrl-D": "delCharAfter", "Ctrl-H": "delCharBefore",
"Alt-D": "delWordAfter", "Alt-Backspace": "delWordBefore", "Ctrl-K": "killLine", "Ctrl-T": "transposeChars",
"Ctrl-O": "openLine"
};
keyMap.macDefault = {
"Cmd-A": "selectAll", "Cmd-D": "deleteLine", "Cmd-Z": "undo", "Shift-Cmd-Z": "redo", "Cmd-Y": "redo",
"Cmd-Home": "goDocStart", "Cmd-Up": "goDocStart", "Cmd-End": "goDocEnd", "Cmd-Down": "goDocEnd", "Alt-Left": "goGroupLeft",
"Alt-Right": "goGroupRight", "Cmd-Left": "goLineLeft", "Cmd-Right": "goLineRight", "Alt-Backspace": "delGroupBefore",
"Ctrl-Alt-Backspace": "delGroupAfter", "Alt-Delete": "delGroupAfter", "Cmd-S": "save", "Cmd-F": "find",
"Cmd-G": "findNext", "Shift-Cmd-G": "findPrev", "Cmd-Alt-F": "replace", "Shift-Cmd-Alt-F": "replaceAll",
"Cmd-[": "indentLess", "Cmd-]": "indentMore", "Cmd-Backspace": "delWrappedLineLeft", "Cmd-Delete": "delWrappedLineRight",
"Cmd-U": "undoSelection", "Shift-Cmd-U": "redoSelection", "Ctrl-Up": "goDocStart", "Ctrl-Down": "goDocEnd",
"fallthrough": ["basic", "emacsy"]
};
keyMap["default"] = mac ? keyMap.macDefault : keyMap.pcDefault;
// KEYMAP DISPATCH
function normalizeKeyName(name) {
var parts = name.split(/-(?!$)/);
name = parts[parts.length - 1];
var alt, ctrl, shift, cmd;
for (var i = 0; i < parts.length - 1; i++) {
var mod = parts[i];
if (/^(cmd|meta|m)$/i.test(mod)) { cmd = true; }
else if (/^a(lt)?$/i.test(mod)) { alt = true; }
else if (/^(c|ctrl|control)$/i.test(mod)) { ctrl = true; }
else if (/^s(hift)?$/i.test(mod)) { shift = true; }
else { throw new Error("Unrecognized modifier name: " + mod) }
}
if (alt) { name = "Alt-" + name; }
if (ctrl) { name = "Ctrl-" + name; }
if (cmd) { name = "Cmd-" + name; }
if (shift) { name = "Shift-" + name; }
return name
}
// This is a kludge to keep keymaps mostly working as raw objects
// (backwards compatibility) while at the same time support features
// like normalization and multi-stroke key bindings. It compiles a
// new normalized keymap, and then updates the old object to reflect
// this.
function normalizeKeyMap(keymap) {
var copy = {};
for (var keyname in keymap) { if (keymap.hasOwnProperty(keyname)) {
var value = keymap[keyname];
if (/^(name|fallthrough|(de|at)tach)$/.test(keyname)) { continue }
if (value == "...") { delete keymap[keyname]; continue }
var keys = map(keyname.split(" "), normalizeKeyName);
for (var i = 0; i < keys.length; i++) {
var val = (void 0), name = (void 0);
if (i == keys.length - 1) {
name = keys.join(" ");
val = value;
} else {
name = keys.slice(0, i + 1).join(" ");
val = "...";
}
var prev = copy[name];
if (!prev) { copy[name] = val; }
else if (prev != val) { throw new Error("Inconsistent bindings for " + name) }
}
delete keymap[keyname];
} }
for (var prop in copy) { keymap[prop] = copy[prop]; }
return keymap
}
function lookupKey(key, map$$1, handle, context) {
map$$1 = getKeyMap(map$$1);
var found = map$$1.call ? map$$1.call(key, context) : map$$1[key];
if (found === false) { return "nothing" }
if (found === "...") { return "multi" }
if (found != null && handle(found)) { return "handled" }
if (map$$1.fallthrough) {
if (Object.prototype.toString.call(map$$1.fallthrough) != "[object Array]")
{ return lookupKey(key, map$$1.fallthrough, handle, context) }
for (var i = 0; i < map$$1.fallthrough.length; i++) {
var result = lookupKey(key, map$$1.fallthrough[i], handle, context);
if (result) { return result }
}
}
}
// Modifier key presses don't count as 'real' key presses for the
// purpose of keymap fallthrough.
function isModifierKey(value) {
var name = typeof value == "string" ? value : keyNames[value.keyCode];
return name == "Ctrl" || name == "Alt" || name == "Shift" || name == "Mod"
}
function addModifierNames(name, event, noShift) {
var base = name;
if (event.altKey && base != "Alt") { name = "Alt-" + name; }
if ((flipCtrlCmd ? event.metaKey : event.ctrlKey) && base != "Ctrl") { name = "Ctrl-" + name; }
if ((flipCtrlCmd ? event.ctrlKey : event.metaKey) && base != "Cmd") { name = "Cmd-" + name; }
if (!noShift && event.shiftKey && base != "Shift") { name = "Shift-" + name; }
return name
}
// Look up the name of a key as indicated by an event object.
function keyName(event, noShift) {
if (presto && event.keyCode == 34 && event["char"]) { return false }
var name = keyNames[event.keyCode];
if (name == null || event.altGraphKey) { return false }
// Ctrl-ScrollLock has keyCode 3, same as Ctrl-Pause,
// so we'll use event.code when available (Chrome 48+, FF 38+, Safari 10.1+)
if (event.keyCode == 3 && event.code) { name = event.code; }
return addModifierNames(name, event, noShift)
}
function getKeyMap(val) {
return typeof val == "string" ? keyMap[val] : val
}
// Helper for deleting text near the selection(s), used to implement
// backspace, delete, and similar functionality.
function deleteNearSelection(cm, compute) {
var ranges = cm.doc.sel.ranges, kill = [];
// Build up a set of ranges to kill first, merging overlapping
// ranges.
for (var i = 0; i < ranges.length; i++) {
var toKill = compute(ranges[i]);
while (kill.length && cmp(toKill.from, lst(kill).to) <= 0) {
var replaced = kill.pop();
if (cmp(replaced.from, toKill.from) < 0) {
toKill.from = replaced.from;
break
}
}
kill.push(toKill);
}
// Next, remove those actual ranges.
runInOp(cm, function () {
for (var i = kill.length - 1; i >= 0; i--)
{ replaceRange(cm.doc, "", kill[i].from, kill[i].to, "+delete"); }
ensureCursorVisible(cm);
});
}
function moveCharLogically(line, ch, dir) {
var target = skipExtendingChars(line.text, ch + dir, dir);
return target < 0 || target > line.text.length ? null : target
}
function moveLogically(line, start, dir) {
var ch = moveCharLogically(line, start.ch, dir);
return ch == null ? null : new Pos(start.line, ch, dir < 0 ? "after" : "before")
}
function endOfLine(visually, cm, lineObj, lineNo, dir) {
if (visually) {
var order = getOrder(lineObj, cm.doc.direction);
if (order) {
var part = dir < 0 ? lst(order) : order[0];
var moveInStorageOrder = (dir < 0) == (part.level == 1);
var sticky = moveInStorageOrder ? "after" : "before";
var ch;
// With a wrapped rtl chunk (possibly spanning multiple bidi parts),
// it could be that the last bidi part is not on the last visual line,
// since visual lines contain content order-consecutive chunks.
// Thus, in rtl, we are looking for the first (content-order) character
// in the rtl chunk that is on the last line (that is, the same line
// as the last (content-order) character).
if (part.level > 0 || cm.doc.direction == "rtl") {
var prep = prepareMeasureForLine(cm, lineObj);
ch = dir < 0 ? lineObj.text.length - 1 : 0;
var targetTop = measureCharPrepared(cm, prep, ch).top;
ch = findFirst(function (ch) { return measureCharPrepared(cm, prep, ch).top == targetTop; }, (dir < 0) == (part.level == 1) ? part.from : part.to - 1, ch);
if (sticky == "before") { ch = moveCharLogically(lineObj, ch, 1); }
} else { ch = dir < 0 ? part.to : part.from; }
return new Pos(lineNo, ch, sticky)
}
}
return new Pos(lineNo, dir < 0 ? lineObj.text.length : 0, dir < 0 ? "before" : "after")
}
function moveVisually(cm, line, start, dir) {
var bidi = getOrder(line, cm.doc.direction);
if (!bidi) { return moveLogically(line, start, dir) }
if (start.ch >= line.text.length) {
start.ch = line.text.length;
start.sticky = "before";
} else if (start.ch <= 0) {
start.ch = 0;
start.sticky = "after";
}
var partPos = getBidiPartAt(bidi, start.ch, start.sticky), part = bidi[partPos];
if (cm.doc.direction == "ltr" && part.level % 2 == 0 && (dir > 0 ? part.to > start.ch : part.from < start.ch)) {
// Case 1: We move within an ltr part in an ltr editor. Even with wrapped lines,
// nothing interesting happens.
return moveLogically(line, start, dir)
}
var mv = function (pos, dir) { return moveCharLogically(line, pos instanceof Pos ? pos.ch : pos, dir); };
var prep;
var getWrappedLineExtent = function (ch) {
if (!cm.options.lineWrapping) { return {begin: 0, end: line.text.length} }
prep = prep || prepareMeasureForLine(cm, line);
return wrappedLineExtentChar(cm, line, prep, ch)
};
var wrappedLineExtent = getWrappedLineExtent(start.sticky == "before" ? mv(start, -1) : start.ch);
if (cm.doc.direction == "rtl" || part.level == 1) {
var moveInStorageOrder = (part.level == 1) == (dir < 0);
var ch = mv(start, moveInStorageOrder ? 1 : -1);
if (ch != null && (!moveInStorageOrder ? ch >= part.from && ch >= wrappedLineExtent.begin : ch <= part.to && ch <= wrappedLineExtent.end)) {
// Case 2: We move within an rtl part or in an rtl editor on the same visual line
var sticky = moveInStorageOrder ? "before" : "after";
return new Pos(start.line, ch, sticky)
}
}
// Case 3: Could not move within this bidi part in this visual line, so leave
// the current bidi part
var searchInVisualLine = function (partPos, dir, wrappedLineExtent) {
var getRes = function (ch, moveInStorageOrder) { return moveInStorageOrder
? new Pos(start.line, mv(ch, 1), "before")
: new Pos(start.line, ch, "after"); };
for (; partPos >= 0 && partPos < bidi.length; partPos += dir) {
var part = bidi[partPos];
var moveInStorageOrder = (dir > 0) == (part.level != 1);
var ch = moveInStorageOrder ? wrappedLineExtent.begin : mv(wrappedLineExtent.end, -1);
if (part.from <= ch && ch < part.to) { return getRes(ch, moveInStorageOrder) }
ch = moveInStorageOrder ? part.from : mv(part.to, -1);
if (wrappedLineExtent.begin <= ch && ch < wrappedLineExtent.end) { return getRes(ch, moveInStorageOrder) }
}
};
// Case 3a: Look for other bidi parts on the same visual line
var res = searchInVisualLine(partPos + dir, dir, wrappedLineExtent);
if (res) { return res }
// Case 3b: Look for other bidi parts on the next visual line
var nextCh = dir > 0 ? wrappedLineExtent.end : mv(wrappedLineExtent.begin, -1);
if (nextCh != null && !(dir > 0 && nextCh == line.text.length)) {
res = searchInVisualLine(dir > 0 ? 0 : bidi.length - 1, dir, getWrappedLineExtent(nextCh));
if (res) { return res }
}
// Case 4: Nowhere to move
return null
}
// Commands are parameter-less actions that can be performed on an
// editor, mostly used for keybindings.
var commands = {
selectAll: selectAll,
singleSelection: function (cm) { return cm.setSelection(cm.getCursor("anchor"), cm.getCursor("head"), sel_dontScroll); },
killLine: function (cm) { return deleteNearSelection(cm, function (range) {
if (range.empty()) {
var len = getLine(cm.doc, range.head.line).text.length;
if (range.head.ch == len && range.head.line < cm.lastLine())
{ return {from: range.head, to: Pos(range.head.line + 1, 0)} }
else
{ return {from: range.head, to: Pos(range.head.line, len)} }
} else {
return {from: range.from(), to: range.to()}
}
}); },
deleteLine: function (cm) { return deleteNearSelection(cm, function (range) { return ({
from: Pos(range.from().line, 0),
to: clipPos(cm.doc, Pos(range.to().line + 1, 0))
}); }); },
delLineLeft: function (cm) { return deleteNearSelection(cm, function (range) { return ({
from: Pos(range.from().line, 0), to: range.from()
}); }); },
delWrappedLineLeft: function (cm) { return deleteNearSelection(cm, function (range) {
var top = cm.charCoords(range.head, "div").top + 5;
var leftPos = cm.coordsChar({left: 0, top: top}, "div");
return {from: leftPos, to: range.from()}
}); },
delWrappedLineRight: function (cm) { return deleteNearSelection(cm, function (range) {
var top = cm.charCoords(range.head, "div").top + 5;
var rightPos = cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div");
return {from: range.from(), to: rightPos }
}); },
undo: function (cm) { return cm.undo(); },
redo: function (cm) { return cm.redo(); },
undoSelection: function (cm) { return cm.undoSelection(); },
redoSelection: function (cm) { return cm.redoSelection(); },
goDocStart: function (cm) { return cm.extendSelection(Pos(cm.firstLine(), 0)); },
goDocEnd: function (cm) { return cm.extendSelection(Pos(cm.lastLine())); },
goLineStart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStart(cm, range.head.line); },
{origin: "+move", bias: 1}
); },
goLineStartSmart: function (cm) { return cm.extendSelectionsBy(function (range) { return lineStartSmart(cm, range.head); },
{origin: "+move", bias: 1}
); },
goLineEnd: function (cm) { return cm.extendSelectionsBy(function (range) { return lineEnd(cm, range.head.line); },
{origin: "+move", bias: -1}
); },
goLineRight: function (cm) { return cm.extendSelectionsBy(function (range) {
var top = cm.cursorCoords(range.head, "div").top + 5;
return cm.coordsChar({left: cm.display.lineDiv.offsetWidth + 100, top: top}, "div")
}, sel_move); },
goLineLeft: function (cm) { return cm.extendSelectionsBy(function (range) {
var top = cm.cursorCoords(range.head, "div").top + 5;
return cm.coordsChar({left: 0, top: top}, "div")
}, sel_move); },
goLineLeftSmart: function (cm) { return cm.extendSelectionsBy(function (range) {
var top = cm.cursorCoords(range.head, "div").top + 5;
var pos = cm.coordsChar({left: 0, top: top}, "div");
if (pos.ch < cm.getLine(pos.line).search(/\S/)) { return lineStartSmart(cm, range.head) }
return pos
}, sel_move); },
goLineUp: function (cm) { return cm.moveV(-1, "line"); },
goLineDown: function (cm) { return cm.moveV(1, "line"); },
goPageUp: function (cm) { return cm.moveV(-1, "page"); },
goPageDown: function (cm) { return cm.moveV(1, "page"); },
goCharLeft: function (cm) { return cm.moveH(-1, "char"); },
goCharRight: function (cm) { return cm.moveH(1, "char"); },
goColumnLeft: function (cm) { return cm.moveH(-1, "column"); },
goColumnRight: function (cm) { return cm.moveH(1, "column"); },
goWordLeft: function (cm) { return cm.moveH(-1, "word"); },
goGroupRight: function (cm) { return cm.moveH(1, "group"); },
goGroupLeft: function (cm) { return cm.moveH(-1, "group"); },
goWordRight: function (cm) { return cm.moveH(1, "word"); },
delCharBefore: function (cm) { return cm.deleteH(-1, "char"); },
delCharAfter: function (cm) { return cm.deleteH(1, "char"); },
delWordBefore: function (cm) { return cm.deleteH(-1, "word"); },
delWordAfter: function (cm) { return cm.deleteH(1, "word"); },
delGroupBefore: function (cm) { return cm.deleteH(-1, "group"); },
delGroupAfter: function (cm) { return cm.deleteH(1, "group"); },
indentAuto: function (cm) { return cm.indentSelection("smart"); },
indentMore: function (cm) { return cm.indentSelection("add"); },
indentLess: function (cm) { return cm.indentSelection("subtract"); },
insertTab: function (cm) { return cm.replaceSelection("\t"); },
insertSoftTab: function (cm) {
var spaces = [], ranges = cm.listSelections(), tabSize = cm.options.tabSize;
for (var i = 0; i < ranges.length; i++) {
var pos = ranges[i].from();
var col = countColumn(cm.getLine(pos.line), pos.ch, tabSize);
spaces.push(spaceStr(tabSize - col % tabSize));
}
cm.replaceSelections(spaces);
},
defaultTab: function (cm) {
if (cm.somethingSelected()) { cm.indentSelection("add"); }
else { cm.execCommand("insertTab"); }
},
// Swap the two chars left and right of each selection's head.
// Move cursor behind the two swapped characters afterwards.
//
// Doesn't consider line feeds a character.
// Doesn't scan more than one line above to find a character.
// Doesn't do anything on an empty line.
// Doesn't do anything with non-empty selections.
transposeChars: function (cm) { return runInOp(cm, function () {
var ranges = cm.listSelections(), newSel = [];
for (var i = 0; i < ranges.length; i++) {
if (!ranges[i].empty()) { continue }
var cur = ranges[i].head, line = getLine(cm.doc, cur.line).text;
if (line) {
if (cur.ch == line.length) { cur = new Pos(cur.line, cur.ch - 1); }
if (cur.ch > 0) {
cur = new Pos(cur.line, cur.ch + 1);
cm.replaceRange(line.charAt(cur.ch - 1) + line.charAt(cur.ch - 2),
Pos(cur.line, cur.ch - 2), cur, "+transpose");
} else if (cur.line > cm.doc.first) {
var prev = getLine(cm.doc, cur.line - 1).text;
if (prev) {
cur = new Pos(cur.line, 1);
cm.replaceRange(line.charAt(0) + cm.doc.lineSeparator() +
prev.charAt(prev.length - 1),
Pos(cur.line - 1, prev.length - 1), cur, "+transpose");
}
}
}
newSel.push(new Range(cur, cur));
}
cm.setSelections(newSel);
}); },
newlineAndIndent: function (cm) { return runInOp(cm, function () {
var sels = cm.listSelections();
for (var i = sels.length - 1; i >= 0; i--)
{ cm.replaceRange(cm.doc.lineSeparator(), sels[i].anchor, sels[i].head, "+input"); }
sels = cm.listSelections();
for (var i$1 = 0; i$1 < sels.length; i$1++)
{ cm.indentLine(sels[i$1].from().line, null, true); }
ensureCursorVisible(cm);
}); },
openLine: function (cm) { return cm.replaceSelection("\n", "start"); },
toggleOverwrite: function (cm) { return cm.toggleOverwrite(); }
};
function lineStart(cm, lineN) {
var line = getLine(cm.doc, lineN);
var visual = visualLine(line);
if (visual != line) { lineN = lineNo(visual); }
return endOfLine(true, cm, visual, lineN, 1)
}
function lineEnd(cm, lineN) {
var line = getLine(cm.doc, lineN);
var visual = visualLineEnd(line);
if (visual != line) { lineN = lineNo(visual); }
return endOfLine(true, cm, line, lineN, -1)
}
function lineStartSmart(cm, pos) {
var start = lineStart(cm, pos.line);
var line = getLine(cm.doc, start.line);
var order = getOrder(line, cm.doc.direction);
if (!order || order[0].level == 0) {
var firstNonWS = Math.max(0, line.text.search(/\S/));
var inWS = pos.line == start.line && pos.ch <= firstNonWS && pos.ch;
return Pos(start.line, inWS ? 0 : firstNonWS, start.sticky)
}
return start
}
// Run a handler that was bound to a key.
function doHandleBinding(cm, bound, dropShift) {
if (typeof bound == "string") {
bound = commands[bound];
if (!bound) { return false }
}
// Ensure previous input has been read, so that the handler sees a
// consistent view of the document
cm.display.input.ensurePolled();
var prevShift = cm.display.shift, done = false;
try {
if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
if (dropShift) { cm.display.shift = false; }
done = bound(cm) != Pass;
} finally {
cm.display.shift = prevShift;
cm.state.suppressEdits = false;
}
return done
}
function lookupKeyForEditor(cm, name, handle) {
for (var i = 0; i < cm.state.keyMaps.length; i++) {
var result = lookupKey(name, cm.state.keyMaps[i], handle, cm);
if (result) { return result }
}
return (cm.options.extraKeys && lookupKey(name, cm.options.extraKeys, handle, cm))
|| lookupKey(name, cm.options.keyMap, handle, cm)
}
// Note that, despite the name, this function is also used to check
// for bound mouse clicks.
var stopSeq = new Delayed;
function dispatchKey(cm, name, e, handle) {
var seq = cm.state.keySeq;
if (seq) {
if (isModifierKey(name)) { return "handled" }
if (/\'$/.test(name))
{ cm.state.keySeq = null; }
else
{ stopSeq.set(50, function () {
if (cm.state.keySeq == seq) {
cm.state.keySeq = null;
cm.display.input.reset();
}
}); }
if (dispatchKeyInner(cm, seq + " " + name, e, handle)) { return true }
}
return dispatchKeyInner(cm, name, e, handle)
}
function dispatchKeyInner(cm, name, e, handle) {
var result = lookupKeyForEditor(cm, name, handle);
if (result == "multi")
{ cm.state.keySeq = name; }
if (result == "handled")
{ signalLater(cm, "keyHandled", cm, name, e); }
if (result == "handled" || result == "multi") {
e_preventDefault(e);
restartBlink(cm);
}
return !!result
}
// Handle a key from the keydown event.
function handleKeyBinding(cm, e) {
var name = keyName(e, true);
if (!name) { return false }
if (e.shiftKey && !cm.state.keySeq) {
// First try to resolve full name (including 'Shift-'). Failing
// that, see if there is a cursor-motion command (starting with
// 'go') bound to the keyname without 'Shift-'.
return dispatchKey(cm, "Shift-" + name, e, function (b) { return doHandleBinding(cm, b, true); })
|| dispatchKey(cm, name, e, function (b) {
if (typeof b == "string" ? /^go[A-Z]/.test(b) : b.motion)
{ return doHandleBinding(cm, b) }
})
} else {
return dispatchKey(cm, name, e, function (b) { return doHandleBinding(cm, b); })
}
}
// Handle a key from the keypress event
function handleCharBinding(cm, e, ch) {
return dispatchKey(cm, "'" + ch + "'", e, function (b) { return doHandleBinding(cm, b, true); })
}
var lastStoppedKey = null;
function onKeyDown(e) {
var cm = this;
cm.curOp.focus = activeElt();
if (signalDOMEvent(cm, e)) { return }
// IE does strange things with escape.
if (ie && ie_version < 11 && e.keyCode == 27) { e.returnValue = false; }
var code = e.keyCode;
cm.display.shift = code == 16 || e.shiftKey;
var handled = handleKeyBinding(cm, e);
if (presto) {
lastStoppedKey = handled ? code : null;
// Opera has no cut event... we try to at least catch the key combo
if (!handled && code == 88 && !hasCopyEvent && (mac ? e.metaKey : e.ctrlKey))
{ cm.replaceSelection("", null, "cut"); }
}
// Turn mouse into crosshair when Alt is held on Mac.
if (code == 18 && !/\bCodeMirror-crosshair\b/.test(cm.display.lineDiv.className))
{ showCrossHair(cm); }
}
function showCrossHair(cm) {
var lineDiv = cm.display.lineDiv;
addClass(lineDiv, "CodeMirror-crosshair");
function up(e) {
if (e.keyCode == 18 || !e.altKey) {
rmClass(lineDiv, "CodeMirror-crosshair");
off(document, "keyup", up);
off(document, "mouseover", up);
}
}
on(document, "keyup", up);
on(document, "mouseover", up);
}
function onKeyUp(e) {
if (e.keyCode == 16) { this.doc.sel.shift = false; }
signalDOMEvent(this, e);
}
function onKeyPress(e) {
var cm = this;
if (eventInWidget(cm.display, e) || signalDOMEvent(cm, e) || e.ctrlKey && !e.altKey || mac && e.metaKey) { return }
var keyCode = e.keyCode, charCode = e.charCode;
if (presto && keyCode == lastStoppedKey) {lastStoppedKey = null; e_preventDefault(e); return}
if ((presto && (!e.which || e.which < 10)) && handleKeyBinding(cm, e)) { return }
var ch = String.fromCharCode(charCode == null ? keyCode : charCode);
// Some browsers fire keypress events for backspace
if (ch == "\x08") { return }
if (handleCharBinding(cm, e, ch)) { return }
cm.display.input.onKeyPress(e);
}
var DOUBLECLICK_DELAY = 400;
var PastClick = function(time, pos, button) {
this.time = time;
this.pos = pos;
this.button = button;
};
PastClick.prototype.compare = function (time, pos, button) {
return this.time + DOUBLECLICK_DELAY > time &&
cmp(pos, this.pos) == 0 && button == this.button
};
var lastClick, lastDoubleClick;
function clickRepeat(pos, button) {
var now = +new Date;
if (lastDoubleClick && lastDoubleClick.compare(now, pos, button)) {
lastClick = lastDoubleClick = null;
return "triple"
} else if (lastClick && lastClick.compare(now, pos, button)) {
lastDoubleClick = new PastClick(now, pos, button);
lastClick = null;
return "double"
} else {
lastClick = new PastClick(now, pos, button);
lastDoubleClick = null;
return "single"
}
}
// A mouse down can be a single click, double click, triple click,
// start of selection drag, start of text drag, new cursor
// (ctrl-click), rectangle drag (alt-drag), or xwin
// middle-click-paste. Or it might be a click on something we should
// not interfere with, such as a scrollbar or widget.
function onMouseDown(e) {
var cm = this, display = cm.display;
if (signalDOMEvent(cm, e) || display.activeTouch && display.input.supportsTouch()) { return }
display.input.ensurePolled();
display.shift = e.shiftKey;
if (eventInWidget(display, e)) {
if (!webkit) {
// Briefly turn off draggability, to allow widgets to do
// normal dragging things.
display.scroller.draggable = false;
setTimeout(function () { return display.scroller.draggable = true; }, 100);
}
return
}
if (clickInGutter(cm, e)) { return }
var pos = posFromMouse(cm, e), button = e_button(e), repeat = pos ? clickRepeat(pos, button) : "single";
window.focus();
// #3261: make sure, that we're not starting a second selection
if (button == 1 && cm.state.selectingText)
{ cm.state.selectingText(e); }
if (pos && handleMappedButton(cm, button, pos, repeat, e)) { return }
if (button == 1) {
if (pos) { leftButtonDown(cm, pos, repeat, e); }
else if (e_target(e) == display.scroller) { e_preventDefault(e); }
} else if (button == 2) {
if (pos) { extendSelection(cm.doc, pos); }
setTimeout(function () { return display.input.focus(); }, 20);
} else if (button == 3) {
if (captureRightClick) { cm.display.input.onContextMenu(e); }
else { delayBlurEvent(cm); }
}
}
function handleMappedButton(cm, button, pos, repeat, event) {
var name = "Click";
if (repeat == "double") { name = "Double" + name; }
else if (repeat == "triple") { name = "Triple" + name; }
name = (button == 1 ? "Left" : button == 2 ? "Middle" : "Right") + name;
return dispatchKey(cm, addModifierNames(name, event), event, function (bound) {
if (typeof bound == "string") { bound = commands[bound]; }
if (!bound) { return false }
var done = false;
try {
if (cm.isReadOnly()) { cm.state.suppressEdits = true; }
done = bound(cm, pos) != Pass;
} finally {
cm.state.suppressEdits = false;
}
return done
})
}
function configureMouse(cm, repeat, event) {
var option = cm.getOption("configureMouse");
var value = option ? option(cm, repeat, event) : {};
if (value.unit == null) {
var rect = chromeOS ? event.shiftKey && event.metaKey : event.altKey;
value.unit = rect ? "rectangle" : repeat == "single" ? "char" : repeat == "double" ? "word" : "line";
}
if (value.extend == null || cm.doc.extend) { value.extend = cm.doc.extend || event.shiftKey; }
if (value.addNew == null) { value.addNew = mac ? event.metaKey : event.ctrlKey; }
if (value.moveOnDrag == null) { value.moveOnDrag = !(mac ? event.altKey : event.ctrlKey); }
return value
}
function leftButtonDown(cm, pos, repeat, event) {
if (ie) { setTimeout(bind(ensureFocus, cm), 0); }
else { cm.curOp.focus = activeElt(); }
var behavior = configureMouse(cm, repeat, event);
var sel = cm.doc.sel, contained;
if (cm.options.dragDrop && dragAndDrop && !cm.isReadOnly() &&
repeat == "single" && (contained = sel.contains(pos)) > -1 &&
(cmp((contained = sel.ranges[contained]).from(), pos) < 0 || pos.xRel > 0) &&
(cmp(contained.to(), pos) > 0 || pos.xRel < 0))
{ leftButtonStartDrag(cm, event, pos, behavior); }
else
{ leftButtonSelect(cm, event, pos, behavior); }
}
// Start a text drag. When it ends, see if any dragging actually
// happen, and treat as a click if it didn't.
function leftButtonStartDrag(cm, event, pos, behavior) {
var display = cm.display, moved = false;
var dragEnd = operation(cm, function (e) {
if (webkit) { display.scroller.draggable = false; }
cm.state.draggingText = false;
off(display.wrapper.ownerDocument, "mouseup", dragEnd);
off(display.wrapper.ownerDocument, "mousemove", mouseMove);
off(display.scroller, "dragstart", dragStart);
off(display.scroller, "drop", dragEnd);
if (!moved) {
e_preventDefault(e);
if (!behavior.addNew)
{ extendSelection(cm.doc, pos, null, null, behavior.extend); }
// Work around unexplainable focus problem in IE9 (#2127) and Chrome (#3081)
if (webkit || ie && ie_version == 9)
{ setTimeout(function () {display.wrapper.ownerDocument.body.focus(); display.input.focus();}, 20); }
else
{ display.input.focus(); }
}
});
var mouseMove = function(e2) {
moved = moved || Math.abs(event.clientX - e2.clientX) + Math.abs(event.clientY - e2.clientY) >= 10;
};
var dragStart = function () { return moved = true; };
// Let the drag handler handle this.
if (webkit) { display.scroller.draggable = true; }
cm.state.draggingText = dragEnd;
dragEnd.copy = !behavior.moveOnDrag;
// IE's approach to draggable
if (display.scroller.dragDrop) { display.scroller.dragDrop(); }
on(display.wrapper.ownerDocument, "mouseup", dragEnd);
on(display.wrapper.ownerDocument, "mousemove", mouseMove);
on(display.scroller, "dragstart", dragStart);
on(display.scroller, "drop", dragEnd);
delayBlurEvent(cm);
setTimeout(function () { return display.input.focus(); }, 20);
}
function rangeForUnit(cm, pos, unit) {
if (unit == "char") { return new Range(pos, pos) }
if (unit == "word") { return cm.findWordAt(pos) }
if (unit == "line") { return new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))) }
var result = unit(cm, pos);
return new Range(result.from, result.to)
}
// Normal selection, as opposed to text dragging.
function leftButtonSelect(cm, event, start, behavior) {
var display = cm.display, doc = cm.doc;
e_preventDefault(event);
var ourRange, ourIndex, startSel = doc.sel, ranges = startSel.ranges;
if (behavior.addNew && !behavior.extend) {
ourIndex = doc.sel.contains(start);
if (ourIndex > -1)
{ ourRange = ranges[ourIndex]; }
else
{ ourRange = new Range(start, start); }
} else {
ourRange = doc.sel.primary();
ourIndex = doc.sel.primIndex;
}
if (behavior.unit == "rectangle") {
if (!behavior.addNew) { ourRange = new Range(start, start); }
start = posFromMouse(cm, event, true, true);
ourIndex = -1;
} else {
var range$$1 = rangeForUnit(cm, start, behavior.unit);
if (behavior.extend)
{ ourRange = extendRange(ourRange, range$$1.anchor, range$$1.head, behavior.extend); }
else
{ ourRange = range$$1; }
}
if (!behavior.addNew) {
ourIndex = 0;
setSelection(doc, new Selection([ourRange], 0), sel_mouse);
startSel = doc.sel;
} else if (ourIndex == -1) {
ourIndex = ranges.length;
setSelection(doc, normalizeSelection(cm, ranges.concat([ourRange]), ourIndex),
{scroll: false, origin: "*mouse"});
} else if (ranges.length > 1 && ranges[ourIndex].empty() && behavior.unit == "char" && !behavior.extend) {
setSelection(doc, normalizeSelection(cm, ranges.slice(0, ourIndex).concat(ranges.slice(ourIndex + 1)), 0),
{scroll: false, origin: "*mouse"});
startSel = doc.sel;
} else {
replaceOneSelection(doc, ourIndex, ourRange, sel_mouse);
}
var lastPos = start;
function extendTo(pos) {
if (cmp(lastPos, pos) == 0) { return }
lastPos = pos;
if (behavior.unit == "rectangle") {
var ranges = [], tabSize = cm.options.tabSize;
var startCol = countColumn(getLine(doc, start.line).text, start.ch, tabSize);
var posCol = countColumn(getLine(doc, pos.line).text, pos.ch, tabSize);
var left = Math.min(startCol, posCol), right = Math.max(startCol, posCol);
for (var line = Math.min(start.line, pos.line), end = Math.min(cm.lastLine(), Math.max(start.line, pos.line));
line <= end; line++) {
var text = getLine(doc, line).text, leftPos = findColumn(text, left, tabSize);
if (left == right)
{ ranges.push(new Range(Pos(line, leftPos), Pos(line, leftPos))); }
else if (text.length > leftPos)
{ ranges.push(new Range(Pos(line, leftPos), Pos(line, findColumn(text, right, tabSize)))); }
}
if (!ranges.length) { ranges.push(new Range(start, start)); }
setSelection(doc, normalizeSelection(cm, startSel.ranges.slice(0, ourIndex).concat(ranges), ourIndex),
{origin: "*mouse", scroll: false});
cm.scrollIntoView(pos);
} else {
var oldRange = ourRange;
var range$$1 = rangeForUnit(cm, pos, behavior.unit);
var anchor = oldRange.anchor, head;
if (cmp(range$$1.anchor, anchor) > 0) {
head = range$$1.head;
anchor = minPos(oldRange.from(), range$$1.anchor);
} else {
head = range$$1.anchor;
anchor = maxPos(oldRange.to(), range$$1.head);
}
var ranges$1 = startSel.ranges.slice(0);
ranges$1[ourIndex] = bidiSimplify(cm, new Range(clipPos(doc, anchor), head));
setSelection(doc, normalizeSelection(cm, ranges$1, ourIndex), sel_mouse);
}
}
var editorSize = display.wrapper.getBoundingClientRect();
// Used to ensure timeout re-tries don't fire when another extend
// happened in the meantime (clearTimeout isn't reliable -- at
// least on Chrome, the timeouts still happen even when cleared,
// if the clear happens after their scheduled firing time).
var counter = 0;
function extend(e) {
var curCount = ++counter;
var cur = posFromMouse(cm, e, true, behavior.unit == "rectangle");
if (!cur) { return }
if (cmp(cur, lastPos) != 0) {
cm.curOp.focus = activeElt();
extendTo(cur);
var visible = visibleLines(display, doc);
if (cur.line >= visible.to || cur.line < visible.from)
{ setTimeout(operation(cm, function () {if (counter == curCount) { extend(e); }}), 150); }
} else {
var outside = e.clientY < editorSize.top ? -20 : e.clientY > editorSize.bottom ? 20 : 0;
if (outside) { setTimeout(operation(cm, function () {
if (counter != curCount) { return }
display.scroller.scrollTop += outside;
extend(e);
}), 50); }
}
}
function done(e) {
cm.state.selectingText = false;
counter = Infinity;
e_preventDefault(e);
display.input.focus();
off(display.wrapper.ownerDocument, "mousemove", move);
off(display.wrapper.ownerDocument, "mouseup", up);
doc.history.lastSelOrigin = null;
}
var move = operation(cm, function (e) {
if (e.buttons === 0 || !e_button(e)) { done(e); }
else { extend(e); }
});
var up = operation(cm, done);
cm.state.selectingText = up;
on(display.wrapper.ownerDocument, "mousemove", move);
on(display.wrapper.ownerDocument, "mouseup", up);
}
// Used when mouse-selecting to adjust the anchor to the proper side
// of a bidi jump depending on the visual position of the head.
function bidiSimplify(cm, range$$1) {
var anchor = range$$1.anchor;
var head = range$$1.head;
var anchorLine = getLine(cm.doc, anchor.line);
if (cmp(anchor, head) == 0 && anchor.sticky == head.sticky) { return range$$1 }
var order = getOrder(anchorLine);
if (!order) { return range$$1 }
var index = getBidiPartAt(order, anchor.ch, anchor.sticky), part = order[index];
if (part.from != anchor.ch && part.to != anchor.ch) { return range$$1 }
var boundary = index + ((part.from == anchor.ch) == (part.level != 1) ? 0 : 1);
if (boundary == 0 || boundary == order.length) { return range$$1 }
// Compute the relative visual position of the head compared to the
// anchor (<0 is to the left, >0 to the right)
var leftSide;
if (head.line != anchor.line) {
leftSide = (head.line - anchor.line) * (cm.doc.direction == "ltr" ? 1 : -1) > 0;
} else {
var headIndex = getBidiPartAt(order, head.ch, head.sticky);
var dir = headIndex - index || (head.ch - anchor.ch) * (part.level == 1 ? -1 : 1);
if (headIndex == boundary - 1 || headIndex == boundary)
{ leftSide = dir < 0; }
else
{ leftSide = dir > 0; }
}
var usePart = order[boundary + (leftSide ? -1 : 0)];
var from = leftSide == (usePart.level == 1);
var ch = from ? usePart.from : usePart.to, sticky = from ? "after" : "before";
return anchor.ch == ch && anchor.sticky == sticky ? range$$1 : new Range(new Pos(anchor.line, ch, sticky), head)
}
// Determines whether an event happened in the gutter, and fires the
// handlers for the corresponding event.
function gutterEvent(cm, e, type, prevent) {
var mX, mY;
if (e.touches) {
mX = e.touches[0].clientX;
mY = e.touches[0].clientY;
} else {
try { mX = e.clientX; mY = e.clientY; }
catch(e) { return false }
}
if (mX >= Math.floor(cm.display.gutters.getBoundingClientRect().right)) { return false }
if (prevent) { e_preventDefault(e); }
var display = cm.display;
var lineBox = display.lineDiv.getBoundingClientRect();
if (mY > lineBox.bottom || !hasHandler(cm, type)) { return e_defaultPrevented(e) }
mY -= lineBox.top - display.viewOffset;
for (var i = 0; i < cm.options.gutters.length; ++i) {
var g = display.gutters.childNodes[i];
if (g && g.getBoundingClientRect().right >= mX) {
var line = lineAtHeight(cm.doc, mY);
var gutter = cm.options.gutters[i];
signal(cm, type, cm, line, gutter, e);
return e_defaultPrevented(e)
}
}
}
function clickInGutter(cm, e) {
return gutterEvent(cm, e, "gutterClick", true)
}
// CONTEXT MENU HANDLING
// To make the context menu work, we need to briefly unhide the
// textarea (making it as unobtrusive as possible) to let the
// right-click take effect on it.
function onContextMenu(cm, e) {
if (eventInWidget(cm.display, e) || contextMenuInGutter(cm, e)) { return }
if (signalDOMEvent(cm, e, "contextmenu")) { return }
if (!captureRightClick) { cm.display.input.onContextMenu(e); }
}
function contextMenuInGutter(cm, e) {
if (!hasHandler(cm, "gutterContextMenu")) { return false }
return gutterEvent(cm, e, "gutterContextMenu", false)
}
function themeChanged(cm) {
cm.display.wrapper.className = cm.display.wrapper.className.replace(/\s*cm-s-\S+/g, "") +
cm.options.theme.replace(/(^|\s)\s*/g, " cm-s-");
clearCaches(cm);
}
var Init = {toString: function(){return "CodeMirror.Init"}};
var defaults = {};
var optionHandlers = {};
function defineOptions(CodeMirror) {
var optionHandlers = CodeMirror.optionHandlers;
function option(name, deflt, handle, notOnInit) {
CodeMirror.defaults[name] = deflt;
if (handle) { optionHandlers[name] =
notOnInit ? function (cm, val, old) {if (old != Init) { handle(cm, val, old); }} : handle; }
}
CodeMirror.defineOption = option;
// Passed to option handlers when there is no old value.
CodeMirror.Init = Init;
// These two are, on init, called from the constructor because they
// have to be initialized before the editor can start at all.
option("value", "", function (cm, val) { return cm.setValue(val); }, true);
option("mode", null, function (cm, val) {
cm.doc.modeOption = val;
loadMode(cm);
}, true);
option("indentUnit", 2, loadMode, true);
option("indentWithTabs", false);
option("smartIndent", true);
option("tabSize", 4, function (cm) {
resetModeState(cm);
clearCaches(cm);
regChange(cm);
}, true);
option("lineSeparator", null, function (cm, val) {
cm.doc.lineSep = val;
if (!val) { return }
var newBreaks = [], lineNo = cm.doc.first;
cm.doc.iter(function (line) {
for (var pos = 0;;) {
var found = line.text.indexOf(val, pos);
if (found == -1) { break }
pos = found + val.length;
newBreaks.push(Pos(lineNo, found));
}
lineNo++;
});
for (var i = newBreaks.length - 1; i >= 0; i--)
{ replaceRange(cm.doc, val, newBreaks[i], Pos(newBreaks[i].line, newBreaks[i].ch + val.length)); }
});
option("specialChars", /[\u0000-\u001f\u007f-\u009f\u00ad\u061c\u200b-\u200f\u2028\u2029\ufeff]/g, function (cm, val, old) {
cm.state.specialChars = new RegExp(val.source + (val.test("\t") ? "" : "|\t"), "g");
if (old != Init) { cm.refresh(); }
});
option("specialCharPlaceholder", defaultSpecialCharPlaceholder, function (cm) { return cm.refresh(); }, true);
option("electricChars", true);
option("inputStyle", mobile ? "contenteditable" : "textarea", function () {
throw new Error("inputStyle can not (yet) be changed in a running editor") // FIXME
}, true);
option("spellcheck", false, function (cm, val) { return cm.getInputField().spellcheck = val; }, true);
option("rtlMoveVisually", !windows);
option("wholeLineUpdateBefore", true);
option("theme", "default", function (cm) {
themeChanged(cm);
guttersChanged(cm);
}, true);
option("keyMap", "default", function (cm, val, old) {
var next = getKeyMap(val);
var prev = old != Init && getKeyMap(old);
if (prev && prev.detach) { prev.detach(cm, next); }
if (next.attach) { next.attach(cm, prev || null); }
});
option("extraKeys", null);
option("configureMouse", null);
option("lineWrapping", false, wrappingChanged, true);
option("gutters", [], function (cm) {
setGuttersForLineNumbers(cm.options);
guttersChanged(cm);
}, true);
option("fixedGutter", true, function (cm, val) {
cm.display.gutters.style.left = val ? compensateForHScroll(cm.display) + "px" : "0";
cm.refresh();
}, true);
option("coverGutterNextToScrollbar", false, function (cm) { return updateScrollbars(cm); }, true);
option("scrollbarStyle", "native", function (cm) {
initScrollbars(cm);
updateScrollbars(cm);
cm.display.scrollbars.setScrollTop(cm.doc.scrollTop);
cm.display.scrollbars.setScrollLeft(cm.doc.scrollLeft);
}, true);
option("lineNumbers", false, function (cm) {
setGuttersForLineNumbers(cm.options);
guttersChanged(cm);
}, true);
option("firstLineNumber", 1, guttersChanged, true);
option("lineNumberFormatter", function (integer) { return integer; }, guttersChanged, true);
option("showCursorWhenSelecting", false, updateSelection, true);
option("resetSelectionOnContextMenu", true);
option("lineWiseCopyCut", true);
option("pasteLinesPerSelection", true);
option("selectionsMayTouch", false);
option("readOnly", false, function (cm, val) {
if (val == "nocursor") {
onBlur(cm);
cm.display.input.blur();
}
cm.display.input.readOnlyChanged(val);
});
option("disableInput", false, function (cm, val) {if (!val) { cm.display.input.reset(); }}, true);
option("dragDrop", true, dragDropChanged);
option("allowDropFileTypes", null);
option("cursorBlinkRate", 530);
option("cursorScrollMargin", 0);
option("cursorHeight", 1, updateSelection, true);
option("singleCursorHeightPerLine", true, updateSelection, true);
option("workTime", 100);
option("workDelay", 100);
option("flattenSpans", true, resetModeState, true);
option("addModeClass", false, resetModeState, true);
option("pollInterval", 100);
option("undoDepth", 200, function (cm, val) { return cm.doc.history.undoDepth = val; });
option("historyEventDelay", 1250);
option("viewportMargin", 10, function (cm) { return cm.refresh(); }, true);
option("maxHighlightLength", 10000, resetModeState, true);
option("moveInputWithCursor", true, function (cm, val) {
if (!val) { cm.display.input.resetPosition(); }
});
option("tabindex", null, function (cm, val) { return cm.display.input.getField().tabIndex = val || ""; });
option("autofocus", null);
option("direction", "ltr", function (cm, val) { return cm.doc.setDirection(val); }, true);
option("phrases", null);
}
function guttersChanged(cm) {
updateGutters(cm);
regChange(cm);
alignHorizontally(cm);
}
function dragDropChanged(cm, value, old) {
var wasOn = old && old != Init;
if (!value != !wasOn) {
var funcs = cm.display.dragFunctions;
var toggle = value ? on : off;
toggle(cm.display.scroller, "dragstart", funcs.start);
toggle(cm.display.scroller, "dragenter", funcs.enter);
toggle(cm.display.scroller, "dragover", funcs.over);
toggle(cm.display.scroller, "dragleave", funcs.leave);
toggle(cm.display.scroller, "drop", funcs.drop);
}
}
function wrappingChanged(cm) {
if (cm.options.lineWrapping) {
addClass(cm.display.wrapper, "CodeMirror-wrap");
cm.display.sizer.style.minWidth = "";
cm.display.sizerWidth = null;
} else {
rmClass(cm.display.wrapper, "CodeMirror-wrap");
findMaxLine(cm);
}
estimateLineHeights(cm);
regChange(cm);
clearCaches(cm);
setTimeout(function () { return updateScrollbars(cm); }, 100);
}
// A CodeMirror instance represents an editor. This is the object
// that user code is usually dealing with.
function CodeMirror(place, options) {
var this$1 = this;
if (!(this instanceof CodeMirror)) { return new CodeMirror(place, options) }
this.options = options = options ? copyObj(options) : {};
// Determine effective options based on given values and defaults.
copyObj(defaults, options, false);
setGuttersForLineNumbers(options);
var doc = options.value;
if (typeof doc == "string") { doc = new Doc(doc, options.mode, null, options.lineSeparator, options.direction); }
else if (options.mode) { doc.modeOption = options.mode; }
this.doc = doc;
var input = new CodeMirror.inputStyles[options.inputStyle](this);
var display = this.display = new Display(place, doc, input);
display.wrapper.CodeMirror = this;
updateGutters(this);
themeChanged(this);
if (options.lineWrapping)
{ this.display.wrapper.className += " CodeMirror-wrap"; }
initScrollbars(this);
this.state = {
keyMaps: [], // stores maps added by addKeyMap
overlays: [], // highlighting overlays, as added by addOverlay
modeGen: 0, // bumped when mode/overlay changes, used to invalidate highlighting info
overwrite: false,
delayingBlurEvent: false,
focused: false,
suppressEdits: false, // used to disable editing during key handlers when in readOnly mode
pasteIncoming: false, cutIncoming: false, // help recognize paste/cut edits in input.poll
selectingText: false,
draggingText: false,
highlight: new Delayed(), // stores highlight worker timeout
keySeq: null, // Unfinished key sequence
specialChars: null
};
if (options.autofocus && !mobile) { display.input.focus(); }
// Override magic textarea content restore that IE sometimes does
// on our hidden textarea on reload
if (ie && ie_version < 11) { setTimeout(function () { return this$1.display.input.reset(true); }, 20); }
registerEventHandlers(this);
ensureGlobalHandlers();
startOperation(this);
this.curOp.forceUpdate = true;
attachDoc(this, doc);
if ((options.autofocus && !mobile) || this.hasFocus())
{ setTimeout(bind(onFocus, this), 20); }
else
{ onBlur(this); }
for (var opt in optionHandlers) { if (optionHandlers.hasOwnProperty(opt))
{ optionHandlers[opt](this$1, options[opt], Init); } }
maybeUpdateLineNumberWidth(this);
if (options.finishInit) { options.finishInit(this); }
for (var i = 0; i < initHooks.length; ++i) { initHooks[i](this$1); }
endOperation(this);
// Suppress optimizelegibility in Webkit, since it breaks text
// measuring on line wrapping boundaries.
if (webkit && options.lineWrapping &&
getComputedStyle(display.lineDiv).textRendering == "optimizelegibility")
{ display.lineDiv.style.textRendering = "auto"; }
}
// The default configuration options.
CodeMirror.defaults = defaults;
// Functions to run when options are changed.
CodeMirror.optionHandlers = optionHandlers;
// Attach the necessary event handlers when initializing the editor
function registerEventHandlers(cm) {
var d = cm.display;
on(d.scroller, "mousedown", operation(cm, onMouseDown));
// Older IE's will not fire a second mousedown for a double click
if (ie && ie_version < 11)
{ on(d.scroller, "dblclick", operation(cm, function (e) {
if (signalDOMEvent(cm, e)) { return }
var pos = posFromMouse(cm, e);
if (!pos || clickInGutter(cm, e) || eventInWidget(cm.display, e)) { return }
e_preventDefault(e);
var word = cm.findWordAt(pos);
extendSelection(cm.doc, word.anchor, word.head);
})); }
else
{ on(d.scroller, "dblclick", function (e) { return signalDOMEvent(cm, e) || e_preventDefault(e); }); }
// Some browsers fire contextmenu *after* opening the menu, at
// which point we can't mess with it anymore. Context menu is
// handled in onMouseDown for these browsers.
on(d.scroller, "contextmenu", function (e) { return onContextMenu(cm, e); });
// Used to suppress mouse event handling when a touch happens
var touchFinished, prevTouch = {end: 0};
function finishTouch() {
if (d.activeTouch) {
touchFinished = setTimeout(function () { return d.activeTouch = null; }, 1000);
prevTouch = d.activeTouch;
prevTouch.end = +new Date;
}
}
function isMouseLikeTouchEvent(e) {
if (e.touches.length != 1) { return false }
var touch = e.touches[0];
return touch.radiusX <= 1 && touch.radiusY <= 1
}
function farAway(touch, other) {
if (other.left == null) { return true }
var dx = other.left - touch.left, dy = other.top - touch.top;
return dx * dx + dy * dy > 20 * 20
}
on(d.scroller, "touchstart", function (e) {
if (!signalDOMEvent(cm, e) && !isMouseLikeTouchEvent(e) && !clickInGutter(cm, e)) {
d.input.ensurePolled();
clearTimeout(touchFinished);
var now = +new Date;
d.activeTouch = {start: now, moved: false,
prev: now - prevTouch.end <= 300 ? prevTouch : null};
if (e.touches.length == 1) {
d.activeTouch.left = e.touches[0].pageX;
d.activeTouch.top = e.touches[0].pageY;
}
}
});
on(d.scroller, "touchmove", function () {
if (d.activeTouch) { d.activeTouch.moved = true; }
});
on(d.scroller, "touchend", function (e) {
var touch = d.activeTouch;
if (touch && !eventInWidget(d, e) && touch.left != null &&
!touch.moved && new Date - touch.start < 300) {
var pos = cm.coordsChar(d.activeTouch, "page"), range;
if (!touch.prev || farAway(touch, touch.prev)) // Single tap
{ range = new Range(pos, pos); }
else if (!touch.prev.prev || farAway(touch, touch.prev.prev)) // Double tap
{ range = cm.findWordAt(pos); }
else // Triple tap
{ range = new Range(Pos(pos.line, 0), clipPos(cm.doc, Pos(pos.line + 1, 0))); }
cm.setSelection(range.anchor, range.head);
cm.focus();
e_preventDefault(e);
}
finishTouch();
});
on(d.scroller, "touchcancel", finishTouch);
// Sync scrolling between fake scrollbars and real scrollable
// area, ensure viewport is updated when scrolling.
on(d.scroller, "scroll", function () {
if (d.scroller.clientHeight) {
updateScrollTop(cm, d.scroller.scrollTop);
setScrollLeft(cm, d.scroller.scrollLeft, true);
signal(cm, "scroll", cm);
}
});
// Listen to wheel events in order to try and update the viewport on time.
on(d.scroller, "mousewheel", function (e) { return onScrollWheel(cm, e); });
on(d.scroller, "DOMMouseScroll", function (e) { return onScrollWheel(cm, e); });
// Prevent wrapper from ever scrolling
on(d.wrapper, "scroll", function () { return d.wrapper.scrollTop = d.wrapper.scrollLeft = 0; });
d.dragFunctions = {
enter: function (e) {if (!signalDOMEvent(cm, e)) { e_stop(e); }},
over: function (e) {if (!signalDOMEvent(cm, e)) { onDragOver(cm, e); e_stop(e); }},
start: function (e) { return onDragStart(cm, e); },
drop: operation(cm, onDrop),
leave: function (e) {if (!signalDOMEvent(cm, e)) { clearDragCursor(cm); }}
};
var inp = d.input.getField();
on(inp, "keyup", function (e) { return onKeyUp.call(cm, e); });
on(inp, "keydown", operation(cm, onKeyDown));
on(inp, "keypress", operation(cm, onKeyPress));
on(inp, "focus", function (e) { return onFocus(cm, e); });
on(inp, "blur", function (e) { return onBlur(cm, e); });
}
var initHooks = [];
CodeMirror.defineInitHook = function (f) { return initHooks.push(f); };
// Indent the given line. The how parameter can be "smart",
// "add"/null, "subtract", or "prev". When aggressive is false
// (typically set to true for forced single-line indents), empty
// lines are not indented, and places where the mode returns Pass
// are left alone.
function indentLine(cm, n, how, aggressive) {
var doc = cm.doc, state;
if (how == null) { how = "add"; }
if (how == "smart") {
// Fall back to "prev" when the mode doesn't have an indentation
// method.
if (!doc.mode.indent) { how = "prev"; }
else { state = getContextBefore(cm, n).state; }
}
var tabSize = cm.options.tabSize;
var line = getLine(doc, n), curSpace = countColumn(line.text, null, tabSize);
if (line.stateAfter) { line.stateAfter = null; }
var curSpaceString = line.text.match(/^\s*/)[0], indentation;
if (!aggressive && !/\S/.test(line.text)) {
indentation = 0;
how = "not";
} else if (how == "smart") {
indentation = doc.mode.indent(state, line.text.slice(curSpaceString.length), line.text);
if (indentation == Pass || indentation > 150) {
if (!aggressive) { return }
how = "prev";
}
}
if (how == "prev") {
if (n > doc.first) { indentation = countColumn(getLine(doc, n-1).text, null, tabSize); }
else { indentation = 0; }
} else if (how == "add") {
indentation = curSpace + cm.options.indentUnit;
} else if (how == "subtract") {
indentation = curSpace - cm.options.indentUnit;
} else if (typeof how == "number") {
indentation = curSpace + how;
}
indentation = Math.max(0, indentation);
var indentString = "", pos = 0;
if (cm.options.indentWithTabs)
{ for (var i = Math.floor(indentation / tabSize); i; --i) {pos += tabSize; indentString += "\t";} }
if (pos < indentation) { indentString += spaceStr(indentation - pos); }
if (indentString != curSpaceString) {
replaceRange(doc, indentString, Pos(n, 0), Pos(n, curSpaceString.length), "+input");
line.stateAfter = null;
return true
} else {
// Ensure that, if the cursor was in the whitespace at the start
// of the line, it is moved to the end of that space.
for (var i$1 = 0; i$1 < doc.sel.ranges.length; i$1++) {
var range = doc.sel.ranges[i$1];
if (range.head.line == n && range.head.ch < curSpaceString.length) {
var pos$1 = Pos(n, curSpaceString.length);
replaceOneSelection(doc, i$1, new Range(pos$1, pos$1));
break
}
}
}
}
// This will be set to a {lineWise: bool, text: [string]} object, so
// that, when pasting, we know what kind of selections the copied
// text was made out of.
var lastCopied = null;
function setLastCopied(newLastCopied) {
lastCopied = newLastCopied;
}
function applyTextInput(cm, inserted, deleted, sel, origin) {
var doc = cm.doc;
cm.display.shift = false;
if (!sel) { sel = doc.sel; }
var paste = cm.state.pasteIncoming || origin == "paste";
var textLines = splitLinesAuto(inserted), multiPaste = null;
// When pasting N lines into N selections, insert one line per selection
if (paste && sel.ranges.length > 1) {
if (lastCopied && lastCopied.text.join("\n") == inserted) {
if (sel.ranges.length % lastCopied.text.length == 0) {
multiPaste = [];
for (var i = 0; i < lastCopied.text.length; i++)
{ multiPaste.push(doc.splitLines(lastCopied.text[i])); }
}
} else if (textLines.length == sel.ranges.length && cm.options.pasteLinesPerSelection) {
multiPaste = map(textLines, function (l) { return [l]; });
}
}
var updateInput = cm.curOp.updateInput;
// Normal behavior is to insert the new text into every selection
for (var i$1 = sel.ranges.length - 1; i$1 >= 0; i$1--) {
var range$$1 = sel.ranges[i$1];
var from = range$$1.from(), to = range$$1.to();
if (range$$1.empty()) {
if (deleted && deleted > 0) // Handle deletion
{ from = Pos(from.line, from.ch - deleted); }
else if (cm.state.overwrite && !paste) // Handle overwrite
{ to = Pos(to.line, Math.min(getLine(doc, to.line).text.length, to.ch + lst(textLines).length)); }
else if (paste && lastCopied && lastCopied.lineWise && lastCopied.text.join("\n") == inserted)
{ from = to = Pos(from.line, 0); }
}
var changeEvent = {from: from, to: to, text: multiPaste ? multiPaste[i$1 % multiPaste.length] : textLines,
origin: origin || (paste ? "paste" : cm.state.cutIncoming ? "cut" : "+input")};
makeChange(cm.doc, changeEvent);
signalLater(cm, "inputRead", cm, changeEvent);
}
if (inserted && !paste)
{ triggerElectric(cm, inserted); }
ensureCursorVisible(cm);
if (cm.curOp.updateInput < 2) { cm.curOp.updateInput = updateInput; }
cm.curOp.typing = true;
cm.state.pasteIncoming = cm.state.cutIncoming = false;
}
function handlePaste(e, cm) {
var pasted = e.clipboardData && e.clipboardData.getData("Text");
if (pasted) {
e.preventDefault();
if (!cm.isReadOnly() && !cm.options.disableInput)
{ runInOp(cm, function () { return applyTextInput(cm, pasted, 0, null, "paste"); }); }
return true
}
}
function triggerElectric(cm, inserted) {
// When an 'electric' character is inserted, immediately trigger a reindent
if (!cm.options.electricChars || !cm.options.smartIndent) { return }
var sel = cm.doc.sel;
for (var i = sel.ranges.length - 1; i >= 0; i--) {
var range$$1 = sel.ranges[i];
if (range$$1.head.ch > 100 || (i && sel.ranges[i - 1].head.line == range$$1.head.line)) { continue }
var mode = cm.getModeAt(range$$1.head);
var indented = false;
if (mode.electricChars) {
for (var j = 0; j < mode.electricChars.length; j++)
{ if (inserted.indexOf(mode.electricChars.charAt(j)) > -1) {
indented = indentLine(cm, range$$1.head.line, "smart");
break
} }
} else if (mode.electricInput) {
if (mode.electricInput.test(getLine(cm.doc, range$$1.head.line).text.slice(0, range$$1.head.ch)))
{ indented = indentLine(cm, range$$1.head.line, "smart"); }
}
if (indented) { signalLater(cm, "electricInput", cm, range$$1.head.line); }
}
}
function copyableRanges(cm) {
var text = [], ranges = [];
for (var i = 0; i < cm.doc.sel.ranges.length; i++) {
var line = cm.doc.sel.ranges[i].head.line;
var lineRange = {anchor: Pos(line, 0), head: Pos(line + 1, 0)};
ranges.push(lineRange);
text.push(cm.getRange(lineRange.anchor, lineRange.head));
}
return {text: text, ranges: ranges}
}
function disableBrowserMagic(field, spellcheck) {
field.setAttribute("autocorrect", "off");
field.setAttribute("autocapitalize", "off");
field.setAttribute("spellcheck", !!spellcheck);
}
function hiddenTextarea() {
var te = elt("textarea", null, null, "position: absolute; bottom: -1em; padding: 0; width: 1px; height: 1em; outline: none");
var div = elt("div", [te], null, "overflow: hidden; position: relative; width: 3px; height: 0px;");
// The textarea is kept positioned near the cursor to prevent the
// fact that it'll be scrolled into view on input from scrolling
// our fake cursor out of view. On webkit, when wrap=off, paste is
// very slow. So make the area wide instead.
if (webkit) { te.style.width = "1000px"; }
else { te.setAttribute("wrap", "off"); }
// If border: 0; -- iOS fails to open keyboard (issue #1287)
if (ios) { te.style.border = "1px solid black"; }
disableBrowserMagic(te);
return div
}
// The publicly visible API. Note that methodOp(f) means
// 'wrap f in an operation, performed on its `this` parameter'.
// This is not the complete set of editor methods. Most of the
// methods defined on the Doc type are also injected into
// CodeMirror.prototype, for backwards compatibility and
// convenience.
function addEditorMethods(CodeMirror) {
var optionHandlers = CodeMirror.optionHandlers;
var helpers = CodeMirror.helpers = {};
CodeMirror.prototype = {
constructor: CodeMirror,
focus: function(){window.focus(); this.display.input.focus();},
setOption: function(option, value) {
var options = this.options, old = options[option];
if (options[option] == value && option != "mode") { return }
options[option] = value;
if (optionHandlers.hasOwnProperty(option))
{ operation(this, optionHandlers[option])(this, value, old); }
signal(this, "optionChange", this, option);
},
getOption: function(option) {return this.options[option]},
getDoc: function() {return this.doc},
addKeyMap: function(map$$1, bottom) {
this.state.keyMaps[bottom ? "push" : "unshift"](getKeyMap(map$$1));
},
removeKeyMap: function(map$$1) {
var maps = this.state.keyMaps;
for (var i = 0; i < maps.length; ++i)
{ if (maps[i] == map$$1 || maps[i].name == map$$1) {
maps.splice(i, 1);
return true
} }
},
addOverlay: methodOp(function(spec, options) {
var mode = spec.token ? spec : CodeMirror.getMode(this.options, spec);
if (mode.startState) { throw new Error("Overlays may not be stateful.") }
insertSorted(this.state.overlays,
{mode: mode, modeSpec: spec, opaque: options && options.opaque,
priority: (options && options.priority) || 0},
function (overlay) { return overlay.priority; });
this.state.modeGen++;
regChange(this);
}),
removeOverlay: methodOp(function(spec) {
var this$1 = this;
var overlays = this.state.overlays;
for (var i = 0; i < overlays.length; ++i) {
var cur = overlays[i].modeSpec;
if (cur == spec || typeof spec == "string" && cur.name == spec) {
overlays.splice(i, 1);
this$1.state.modeGen++;
regChange(this$1);
return
}
}
}),
indentLine: methodOp(function(n, dir, aggressive) {
if (typeof dir != "string" && typeof dir != "number") {
if (dir == null) { dir = this.options.smartIndent ? "smart" : "prev"; }
else { dir = dir ? "add" : "subtract"; }
}
if (isLine(this.doc, n)) { indentLine(this, n, dir, aggressive); }
}),
indentSelection: methodOp(function(how) {
var this$1 = this;
var ranges = this.doc.sel.ranges, end = -1;
for (var i = 0; i < ranges.length; i++) {
var range$$1 = ranges[i];
if (!range$$1.empty()) {
var from = range$$1.from(), to = range$$1.to();
var start = Math.max(end, from.line);
end = Math.min(this$1.lastLine(), to.line - (to.ch ? 0 : 1)) + 1;
for (var j = start; j < end; ++j)
{ indentLine(this$1, j, how); }
var newRanges = this$1.doc.sel.ranges;
if (from.ch == 0 && ranges.length == newRanges.length && newRanges[i].from().ch > 0)
{ replaceOneSelection(this$1.doc, i, new Range(from, newRanges[i].to()), sel_dontScroll); }
} else if (range$$1.head.line > end) {
indentLine(this$1, range$$1.head.line, how, true);
end = range$$1.head.line;
if (i == this$1.doc.sel.primIndex) { ensureCursorVisible(this$1); }
}
}
}),
// Fetch the parser token for a given character. Useful for hacks
// that want to inspect the mode state (say, for completion).
getTokenAt: function(pos, precise) {
return takeToken(this, pos, precise)
},
getLineTokens: function(line, precise) {
return takeToken(this, Pos(line), precise, true)
},
getTokenTypeAt: function(pos) {
pos = clipPos(this.doc, pos);
var styles = getLineStyles(this, getLine(this.doc, pos.line));
var before = 0, after = (styles.length - 1) / 2, ch = pos.ch;
var type;
if (ch == 0) { type = styles[2]; }
else { for (;;) {
var mid = (before + after) >> 1;
if ((mid ? styles[mid * 2 - 1] : 0) >= ch) { after = mid; }
else if (styles[mid * 2 + 1] < ch) { before = mid + 1; }
else { type = styles[mid * 2 + 2]; break }
} }
var cut = type ? type.indexOf("overlay ") : -1;
return cut < 0 ? type : cut == 0 ? null : type.slice(0, cut - 1)
},
getModeAt: function(pos) {
var mode = this.doc.mode;
if (!mode.innerMode) { return mode }
return CodeMirror.innerMode(mode, this.getTokenAt(pos).state).mode
},
getHelper: function(pos, type) {
return this.getHelpers(pos, type)[0]
},
getHelpers: function(pos, type) {
var this$1 = this;
var found = [];
if (!helpers.hasOwnProperty(type)) { return found }
var help = helpers[type], mode = this.getModeAt(pos);
if (typeof mode[type] == "string") {
if (help[mode[type]]) { found.push(help[mode[type]]); }
} else if (mode[type]) {
for (var i = 0; i < mode[type].length; i++) {
var val = help[mode[type][i]];
if (val) { found.push(val); }
}
} else if (mode.helperType && help[mode.helperType]) {
found.push(help[mode.helperType]);
} else if (help[mode.name]) {
found.push(help[mode.name]);
}
for (var i$1 = 0; i$1 < help._global.length; i$1++) {
var cur = help._global[i$1];
if (cur.pred(mode, this$1) && indexOf(found, cur.val) == -1)
{ found.push(cur.val); }
}
return found
},
getStateAfter: function(line, precise) {
var doc = this.doc;
line = clipLine(doc, line == null ? doc.first + doc.size - 1: line);
return getContextBefore(this, line + 1, precise).state
},
cursorCoords: function(start, mode) {
var pos, range$$1 = this.doc.sel.primary();
if (start == null) { pos = range$$1.head; }
else if (typeof start == "object") { pos = clipPos(this.doc, start); }
else { pos = start ? range$$1.from() : range$$1.to(); }
return cursorCoords(this, pos, mode || "page")
},
charCoords: function(pos, mode) {
return charCoords(this, clipPos(this.doc, pos), mode || "page")
},
coordsChar: function(coords, mode) {
coords = fromCoordSystem(this, coords, mode || "page");
return coordsChar(this, coords.left, coords.top)
},
lineAtHeight: function(height, mode) {
height = fromCoordSystem(this, {top: height, left: 0}, mode || "page").top;
return lineAtHeight(this.doc, height + this.display.viewOffset)
},
heightAtLine: function(line, mode, includeWidgets) {
var end = false, lineObj;
if (typeof line == "number") {
var last = this.doc.first + this.doc.size - 1;
if (line < this.doc.first) { line = this.doc.first; }
else if (line > last) { line = last; end = true; }
lineObj = getLine(this.doc, line);
} else {
lineObj = line;
}
return intoCoordSystem(this, lineObj, {top: 0, left: 0}, mode || "page", includeWidgets || end).top +
(end ? this.doc.height - heightAtLine(lineObj) : 0)
},
defaultTextHeight: function() { return textHeight(this.display) },
defaultCharWidth: function() { return charWidth(this.display) },
getViewport: function() { return {from: this.display.viewFrom, to: this.display.viewTo}},
addWidget: function(pos, node, scroll, vert, horiz) {
var display = this.display;
pos = cursorCoords(this, clipPos(this.doc, pos));
var top = pos.bottom, left = pos.left;
node.style.position = "absolute";
node.setAttribute("cm-ignore-events", "true");
this.display.input.setUneditable(node);
display.sizer.appendChild(node);
if (vert == "over") {
top = pos.top;
} else if (vert == "above" || vert == "near") {
var vspace = Math.max(display.wrapper.clientHeight, this.doc.height),
hspace = Math.max(display.sizer.clientWidth, display.lineSpace.clientWidth);
// Default to positioning above (if specified and possible); otherwise default to positioning below
if ((vert == 'above' || pos.bottom + node.offsetHeight > vspace) && pos.top > node.offsetHeight)
{ top = pos.top - node.offsetHeight; }
else if (pos.bottom + node.offsetHeight <= vspace)
{ top = pos.bottom; }
if (left + node.offsetWidth > hspace)
{ left = hspace - node.offsetWidth; }
}
node.style.top = top + "px";
node.style.left = node.style.right = "";
if (horiz == "right") {
left = display.sizer.clientWidth - node.offsetWidth;
node.style.right = "0px";
} else {
if (horiz == "left") { left = 0; }
else if (horiz == "middle") { left = (display.sizer.clientWidth - node.offsetWidth) / 2; }
node.style.left = left + "px";
}
if (scroll)
{ scrollIntoView(this, {left: left, top: top, right: left + node.offsetWidth, bottom: top + node.offsetHeight}); }
},
triggerOnKeyDown: methodOp(onKeyDown),
triggerOnKeyPress: methodOp(onKeyPress),
triggerOnKeyUp: onKeyUp,
triggerOnMouseDown: methodOp(onMouseDown),
execCommand: function(cmd) {
if (commands.hasOwnProperty(cmd))
{ return commands[cmd].call(null, this) }
},
triggerElectric: methodOp(function(text) { triggerElectric(this, text); }),
findPosH: function(from, amount, unit, visually) {
var this$1 = this;
var dir = 1;
if (amount < 0) { dir = -1; amount = -amount; }
var cur = clipPos(this.doc, from);
for (var i = 0; i < amount; ++i) {
cur = findPosH(this$1.doc, cur, dir, unit, visually);
if (cur.hitSide) { break }
}
return cur
},
moveH: methodOp(function(dir, unit) {
var this$1 = this;
this.extendSelectionsBy(function (range$$1) {
if (this$1.display.shift || this$1.doc.extend || range$$1.empty())
{ return findPosH(this$1.doc, range$$1.head, dir, unit, this$1.options.rtlMoveVisually) }
else
{ return dir < 0 ? range$$1.from() : range$$1.to() }
}, sel_move);
}),
deleteH: methodOp(function(dir, unit) {
var sel = this.doc.sel, doc = this.doc;
if (sel.somethingSelected())
{ doc.replaceSelection("", null, "+delete"); }
else
{ deleteNearSelection(this, function (range$$1) {
var other = findPosH(doc, range$$1.head, dir, unit, false);
return dir < 0 ? {from: other, to: range$$1.head} : {from: range$$1.head, to: other}
}); }
}),
findPosV: function(from, amount, unit, goalColumn) {
var this$1 = this;
var dir = 1, x = goalColumn;
if (amount < 0) { dir = -1; amount = -amount; }
var cur = clipPos(this.doc, from);
for (var i = 0; i < amount; ++i) {
var coords = cursorCoords(this$1, cur, "div");
if (x == null) { x = coords.left; }
else { coords.left = x; }
cur = findPosV(this$1, coords, dir, unit);
if (cur.hitSide) { break }
}
return cur
},
moveV: methodOp(function(dir, unit) {
var this$1 = this;
var doc = this.doc, goals = [];
var collapse = !this.display.shift && !doc.extend && doc.sel.somethingSelected();
doc.extendSelectionsBy(function (range$$1) {
if (collapse)
{ return dir < 0 ? range$$1.from() : range$$1.to() }
var headPos = cursorCoords(this$1, range$$1.head, "div");
if (range$$1.goalColumn != null) { headPos.left = range$$1.goalColumn; }
goals.push(headPos.left);
var pos = findPosV(this$1, headPos, dir, unit);
if (unit == "page" && range$$1 == doc.sel.primary())
{ addToScrollTop(this$1, charCoords(this$1, pos, "div").top - headPos.top); }
return pos
}, sel_move);
if (goals.length) { for (var i = 0; i < doc.sel.ranges.length; i++)
{ doc.sel.ranges[i].goalColumn = goals[i]; } }
}),
// Find the word at the given position (as returned by coordsChar).
findWordAt: function(pos) {
var doc = this.doc, line = getLine(doc, pos.line).text;
var start = pos.ch, end = pos.ch;
if (line) {
var helper = this.getHelper(pos, "wordChars");
if ((pos.sticky == "before" || end == line.length) && start) { --start; } else { ++end; }
var startChar = line.charAt(start);
var check = isWordChar(startChar, helper)
? function (ch) { return isWordChar(ch, helper); }
: /\s/.test(startChar) ? function (ch) { return /\s/.test(ch); }
: function (ch) { return (!/\s/.test(ch) && !isWordChar(ch)); };
while (start > 0 && check(line.charAt(start - 1))) { --start; }
while (end < line.length && check(line.charAt(end))) { ++end; }
}
return new Range(Pos(pos.line, start), Pos(pos.line, end))
},
toggleOverwrite: function(value) {
if (value != null && value == this.state.overwrite) { return }
if (this.state.overwrite = !this.state.overwrite)
{ addClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
else
{ rmClass(this.display.cursorDiv, "CodeMirror-overwrite"); }
signal(this, "overwriteToggle", this, this.state.overwrite);
},
hasFocus: function() { return this.display.input.getField() == activeElt() },
isReadOnly: function() { return !!(this.options.readOnly || this.doc.cantEdit) },
scrollTo: methodOp(function (x, y) { scrollToCoords(this, x, y); }),
getScrollInfo: function() {
var scroller = this.display.scroller;
return {left: scroller.scrollLeft, top: scroller.scrollTop,
height: scroller.scrollHeight - scrollGap(this) - this.display.barHeight,
width: scroller.scrollWidth - scrollGap(this) - this.display.barWidth,
clientHeight: displayHeight(this), clientWidth: displayWidth(this)}
},
scrollIntoView: methodOp(function(range$$1, margin) {
if (range$$1 == null) {
range$$1 = {from: this.doc.sel.primary().head, to: null};
if (margin == null) { margin = this.options.cursorScrollMargin; }
} else if (typeof range$$1 == "number") {
range$$1 = {from: Pos(range$$1, 0), to: null};
} else if (range$$1.from == null) {
range$$1 = {from: range$$1, to: null};
}
if (!range$$1.to) { range$$1.to = range$$1.from; }
range$$1.margin = margin || 0;
if (range$$1.from.line != null) {
scrollToRange(this, range$$1);
} else {
scrollToCoordsRange(this, range$$1.from, range$$1.to, range$$1.margin);
}
}),
setSize: methodOp(function(width, height) {
var this$1 = this;
var interpret = function (val) { return typeof val == "number" || /^\d+$/.test(String(val)) ? val + "px" : val; };
if (width != null) { this.display.wrapper.style.width = interpret(width); }
if (height != null) { this.display.wrapper.style.height = interpret(height); }
if (this.options.lineWrapping) { clearLineMeasurementCache(this); }
var lineNo$$1 = this.display.viewFrom;
this.doc.iter(lineNo$$1, this.display.viewTo, function (line) {
if (line.widgets) { for (var i = 0; i < line.widgets.length; i++)
{ if (line.widgets[i].noHScroll) { regLineChange(this$1, lineNo$$1, "widget"); break } } }
++lineNo$$1;
});
this.curOp.forceUpdate = true;
signal(this, "refresh", this);
}),
operation: function(f){return runInOp(this, f)},
startOperation: function(){return startOperation(this)},
endOperation: function(){return endOperation(this)},
refresh: methodOp(function() {
var oldHeight = this.display.cachedTextHeight;
regChange(this);
this.curOp.forceUpdate = true;
clearCaches(this);
scrollToCoords(this, this.doc.scrollLeft, this.doc.scrollTop);
updateGutterSpace(this);
if (oldHeight == null || Math.abs(oldHeight - textHeight(this.display)) > .5)
{ estimateLineHeights(this); }
signal(this, "refresh", this);
}),
swapDoc: methodOp(function(doc) {
var old = this.doc;
old.cm = null;
attachDoc(this, doc);
clearCaches(this);
this.display.input.reset();
scrollToCoords(this, doc.scrollLeft, doc.scrollTop);
this.curOp.forceScroll = true;
signalLater(this, "swapDoc", this, old);
return old
}),
phrase: function(phraseText) {
var phrases = this.options.phrases;
return phrases && Object.prototype.hasOwnProperty.call(phrases, phraseText) ? phrases[phraseText] : phraseText
},
getInputField: function(){return this.display.input.getField()},
getWrapperElement: function(){return this.display.wrapper},
getScrollerElement: function(){return this.display.scroller},
getGutterElement: function(){return this.display.gutters}
};
eventMixin(CodeMirror);
CodeMirror.registerHelper = function(type, name, value) {
if (!helpers.hasOwnProperty(type)) { helpers[type] = CodeMirror[type] = {_global: []}; }
helpers[type][name] = value;
};
CodeMirror.registerGlobalHelper = function(type, name, predicate, value) {
CodeMirror.registerHelper(type, name, value);
helpers[type]._global.push({pred: predicate, val: value});
};
}
// Used for horizontal relative motion. Dir is -1 or 1 (left or
// right), unit can be "char", "column" (like char, but doesn't
// cross line boundaries), "word" (across next word), or "group" (to
// the start of next group of word or non-word-non-whitespace
// chars). The visually param controls whether, in right-to-left
// text, direction 1 means to move towards the next index in the
// string, or towards the character to the right of the current
// position. The resulting position will have a hitSide=true
// property if it reached the end of the document.
function findPosH(doc, pos, dir, unit, visually) {
var oldPos = pos;
var origDir = dir;
var lineObj = getLine(doc, pos.line);
function findNextLine() {
var l = pos.line + dir;
if (l < doc.first || l >= doc.first + doc.size) { return false }
pos = new Pos(l, pos.ch, pos.sticky);
return lineObj = getLine(doc, l)
}
function moveOnce(boundToLine) {
var next;
if (visually) {
next = moveVisually(doc.cm, lineObj, pos, dir);
} else {
next = moveLogically(lineObj, pos, dir);
}
if (next == null) {
if (!boundToLine && findNextLine())
{ pos = endOfLine(visually, doc.cm, lineObj, pos.line, dir); }
else
{ return false }
} else {
pos = next;
}
return true
}
if (unit == "char") {
moveOnce();
} else if (unit == "column") {
moveOnce(true);
} else if (unit == "word" || unit == "group") {
var sawType = null, group = unit == "group";
var helper = doc.cm && doc.cm.getHelper(pos, "wordChars");
for (var first = true;; first = false) {
if (dir < 0 && !moveOnce(!first)) { break }
var cur = lineObj.text.charAt(pos.ch) || "\n";
var type = isWordChar(cur, helper) ? "w"
: group && cur == "\n" ? "n"
: !group || /\s/.test(cur) ? null
: "p";
if (group && !first && !type) { type = "s"; }
if (sawType && sawType != type) {
if (dir < 0) {dir = 1; moveOnce(); pos.sticky = "after";}
break
}
if (type) { sawType = type; }
if (dir > 0 && !moveOnce(!first)) { break }
}
}
var result = skipAtomic(doc, pos, oldPos, origDir, true);
if (equalCursorPos(oldPos, result)) { result.hitSide = true; }
return result
}
// For relative vertical movement. Dir may be -1 or 1. Unit can be
// "page" or "line". The resulting position will have a hitSide=true
// property if it reached the end of the document.
function findPosV(cm, pos, dir, unit) {
var doc = cm.doc, x = pos.left, y;
if (unit == "page") {
var pageSize = Math.min(cm.display.wrapper.clientHeight, window.innerHeight || document.documentElement.clientHeight);
var moveAmount = Math.max(pageSize - .5 * textHeight(cm.display), 3);
y = (dir > 0 ? pos.bottom : pos.top) + dir * moveAmount;
} else if (unit == "line") {
y = dir > 0 ? pos.bottom + 3 : pos.top - 3;
}
var target;
for (;;) {
target = coordsChar(cm, x, y);
if (!target.outside) { break }
if (dir < 0 ? y <= 0 : y >= doc.height) { target.hitSide = true; break }
y += dir * 5;
}
return target
}
// CONTENTEDITABLE INPUT STYLE
var ContentEditableInput = function(cm) {
this.cm = cm;
this.lastAnchorNode = this.lastAnchorOffset = this.lastFocusNode = this.lastFocusOffset = null;
this.polling = new Delayed();
this.composing = null;
this.gracePeriod = false;
this.readDOMTimeout = null;
};
ContentEditableInput.prototype.init = function (display) {
var this$1 = this;
var input = this, cm = input.cm;
var div = input.div = display.lineDiv;
disableBrowserMagic(div, cm.options.spellcheck);
on(div, "paste", function (e) {
if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
// IE doesn't fire input events, so we schedule a read for the pasted content in this way
if (ie_version <= 11) { setTimeout(operation(cm, function () { return this$1.updateFromDOM(); }), 20); }
});
on(div, "compositionstart", function (e) {
this$1.composing = {data: e.data, done: false};
});
on(div, "compositionupdate", function (e) {
if (!this$1.composing) { this$1.composing = {data: e.data, done: false}; }
});
on(div, "compositionend", function (e) {
if (this$1.composing) {
if (e.data != this$1.composing.data) { this$1.readFromDOMSoon(); }
this$1.composing.done = true;
}
});
on(div, "touchstart", function () { return input.forceCompositionEnd(); });
on(div, "input", function () {
if (!this$1.composing) { this$1.readFromDOMSoon(); }
});
function onCopyCut(e) {
if (signalDOMEvent(cm, e)) { return }
if (cm.somethingSelected()) {
setLastCopied({lineWise: false, text: cm.getSelections()});
if (e.type == "cut") { cm.replaceSelection("", null, "cut"); }
} else if (!cm.options.lineWiseCopyCut) {
return
} else {
var ranges = copyableRanges(cm);
setLastCopied({lineWise: true, text: ranges.text});
if (e.type == "cut") {
cm.operation(function () {
cm.setSelections(ranges.ranges, 0, sel_dontScroll);
cm.replaceSelection("", null, "cut");
});
}
}
if (e.clipboardData) {
e.clipboardData.clearData();
var content = lastCopied.text.join("\n");
// iOS exposes the clipboard API, but seems to discard content inserted into it
e.clipboardData.setData("Text", content);
if (e.clipboardData.getData("Text") == content) {
e.preventDefault();
return
}
}
// Old-fashioned briefly-focus-a-textarea hack
var kludge = hiddenTextarea(), te = kludge.firstChild;
cm.display.lineSpace.insertBefore(kludge, cm.display.lineSpace.firstChild);
te.value = lastCopied.text.join("\n");
var hadFocus = document.activeElement;
selectInput(te);
setTimeout(function () {
cm.display.lineSpace.removeChild(kludge);
hadFocus.focus();
if (hadFocus == div) { input.showPrimarySelection(); }
}, 50);
}
on(div, "copy", onCopyCut);
on(div, "cut", onCopyCut);
};
ContentEditableInput.prototype.prepareSelection = function () {
var result = prepareSelection(this.cm, false);
result.focus = this.cm.state.focused;
return result
};
ContentEditableInput.prototype.showSelection = function (info, takeFocus) {
if (!info || !this.cm.display.view.length) { return }
if (info.focus || takeFocus) { this.showPrimarySelection(); }
this.showMultipleSelections(info);
};
ContentEditableInput.prototype.getSelection = function () {
return this.cm.display.wrapper.ownerDocument.getSelection()
};
ContentEditableInput.prototype.showPrimarySelection = function () {
var sel = this.getSelection(), cm = this.cm, prim = cm.doc.sel.primary();
var from = prim.from(), to = prim.to();
if (cm.display.viewTo == cm.display.viewFrom || from.line >= cm.display.viewTo || to.line < cm.display.viewFrom) {
sel.removeAllRanges();
return
}
var curAnchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
var curFocus = domToPos(cm, sel.focusNode, sel.focusOffset);
if (curAnchor && !curAnchor.bad && curFocus && !curFocus.bad &&
cmp(minPos(curAnchor, curFocus), from) == 0 &&
cmp(maxPos(curAnchor, curFocus), to) == 0)
{ return }
var view = cm.display.view;
var start = (from.line >= cm.display.viewFrom && posToDOM(cm, from)) ||
{node: view[0].measure.map[2], offset: 0};
var end = to.line < cm.display.viewTo && posToDOM(cm, to);
if (!end) {
var measure = view[view.length - 1].measure;
var map$$1 = measure.maps ? measure.maps[measure.maps.length - 1] : measure.map;
end = {node: map$$1[map$$1.length - 1], offset: map$$1[map$$1.length - 2] - map$$1[map$$1.length - 3]};
}
if (!start || !end) {
sel.removeAllRanges();
return
}
var old = sel.rangeCount && sel.getRangeAt(0), rng;
try { rng = range(start.node, start.offset, end.offset, end.node); }
catch(e) {} // Our model of the DOM might be outdated, in which case the range we try to set can be impossible
if (rng) {
if (!gecko && cm.state.focused) {
sel.collapse(start.node, start.offset);
if (!rng.collapsed) {
sel.removeAllRanges();
sel.addRange(rng);
}
} else {
sel.removeAllRanges();
sel.addRange(rng);
}
if (old && sel.anchorNode == null) { sel.addRange(old); }
else if (gecko) { this.startGracePeriod(); }
}
this.rememberSelection();
};
ContentEditableInput.prototype.startGracePeriod = function () {
var this$1 = this;
clearTimeout(this.gracePeriod);
this.gracePeriod = setTimeout(function () {
this$1.gracePeriod = false;
if (this$1.selectionChanged())
{ this$1.cm.operation(function () { return this$1.cm.curOp.selectionChanged = true; }); }
}, 20);
};
ContentEditableInput.prototype.showMultipleSelections = function (info) {
removeChildrenAndAdd(this.cm.display.cursorDiv, info.cursors);
removeChildrenAndAdd(this.cm.display.selectionDiv, info.selection);
};
ContentEditableInput.prototype.rememberSelection = function () {
var sel = this.getSelection();
this.lastAnchorNode = sel.anchorNode; this.lastAnchorOffset = sel.anchorOffset;
this.lastFocusNode = sel.focusNode; this.lastFocusOffset = sel.focusOffset;
};
ContentEditableInput.prototype.selectionInEditor = function () {
var sel = this.getSelection();
if (!sel.rangeCount) { return false }
var node = sel.getRangeAt(0).commonAncestorContainer;
return contains(this.div, node)
};
ContentEditableInput.prototype.focus = function () {
if (this.cm.options.readOnly != "nocursor") {
if (!this.selectionInEditor())
{ this.showSelection(this.prepareSelection(), true); }
this.div.focus();
}
};
ContentEditableInput.prototype.blur = function () { this.div.blur(); };
ContentEditableInput.prototype.getField = function () { return this.div };
ContentEditableInput.prototype.supportsTouch = function () { return true };
ContentEditableInput.prototype.receivedFocus = function () {
var input = this;
if (this.selectionInEditor())
{ this.pollSelection(); }
else
{ runInOp(this.cm, function () { return input.cm.curOp.selectionChanged = true; }); }
function poll() {
if (input.cm.state.focused) {
input.pollSelection();
input.polling.set(input.cm.options.pollInterval, poll);
}
}
this.polling.set(this.cm.options.pollInterval, poll);
};
ContentEditableInput.prototype.selectionChanged = function () {
var sel = this.getSelection();
return sel.anchorNode != this.lastAnchorNode || sel.anchorOffset != this.lastAnchorOffset ||
sel.focusNode != this.lastFocusNode || sel.focusOffset != this.lastFocusOffset
};
ContentEditableInput.prototype.pollSelection = function () {
if (this.readDOMTimeout != null || this.gracePeriod || !this.selectionChanged()) { return }
var sel = this.getSelection(), cm = this.cm;
// On Android Chrome (version 56, at least), backspacing into an
// uneditable block element will put the cursor in that element,
// and then, because it's not editable, hide the virtual keyboard.
// Because Android doesn't allow us to actually detect backspace
// presses in a sane way, this code checks for when that happens
// and simulates a backspace press in this case.
if (android && chrome && this.cm.options.gutters.length && isInGutter(sel.anchorNode)) {
this.cm.triggerOnKeyDown({type: "keydown", keyCode: 8, preventDefault: Math.abs});
this.blur();
this.focus();
return
}
if (this.composing) { return }
this.rememberSelection();
var anchor = domToPos(cm, sel.anchorNode, sel.anchorOffset);
var head = domToPos(cm, sel.focusNode, sel.focusOffset);
if (anchor && head) { runInOp(cm, function () {
setSelection(cm.doc, simpleSelection(anchor, head), sel_dontScroll);
if (anchor.bad || head.bad) { cm.curOp.selectionChanged = true; }
}); }
};
ContentEditableInput.prototype.pollContent = function () {
if (this.readDOMTimeout != null) {
clearTimeout(this.readDOMTimeout);
this.readDOMTimeout = null;
}
var cm = this.cm, display = cm.display, sel = cm.doc.sel.primary();
var from = sel.from(), to = sel.to();
if (from.ch == 0 && from.line > cm.firstLine())
{ from = Pos(from.line - 1, getLine(cm.doc, from.line - 1).length); }
if (to.ch == getLine(cm.doc, to.line).text.length && to.line < cm.lastLine())
{ to = Pos(to.line + 1, 0); }
if (from.line < display.viewFrom || to.line > display.viewTo - 1) { return false }
var fromIndex, fromLine, fromNode;
if (from.line == display.viewFrom || (fromIndex = findViewIndex(cm, from.line)) == 0) {
fromLine = lineNo(display.view[0].line);
fromNode = display.view[0].node;
} else {
fromLine = lineNo(display.view[fromIndex].line);
fromNode = display.view[fromIndex - 1].node.nextSibling;
}
var toIndex = findViewIndex(cm, to.line);
var toLine, toNode;
if (toIndex == display.view.length - 1) {
toLine = display.viewTo - 1;
toNode = display.lineDiv.lastChild;
} else {
toLine = lineNo(display.view[toIndex + 1].line) - 1;
toNode = display.view[toIndex + 1].node.previousSibling;
}
if (!fromNode) { return false }
var newText = cm.doc.splitLines(domTextBetween(cm, fromNode, toNode, fromLine, toLine));
var oldText = getBetween(cm.doc, Pos(fromLine, 0), Pos(toLine, getLine(cm.doc, toLine).text.length));
while (newText.length > 1 && oldText.length > 1) {
if (lst(newText) == lst(oldText)) { newText.pop(); oldText.pop(); toLine--; }
else if (newText[0] == oldText[0]) { newText.shift(); oldText.shift(); fromLine++; }
else { break }
}
var cutFront = 0, cutEnd = 0;
var newTop = newText[0], oldTop = oldText[0], maxCutFront = Math.min(newTop.length, oldTop.length);
while (cutFront < maxCutFront && newTop.charCodeAt(cutFront) == oldTop.charCodeAt(cutFront))
{ ++cutFront; }
var newBot = lst(newText), oldBot = lst(oldText);
var maxCutEnd = Math.min(newBot.length - (newText.length == 1 ? cutFront : 0),
oldBot.length - (oldText.length == 1 ? cutFront : 0));
while (cutEnd < maxCutEnd &&
newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1))
{ ++cutEnd; }
// Try to move start of change to start of selection if ambiguous
if (newText.length == 1 && oldText.length == 1 && fromLine == from.line) {
while (cutFront && cutFront > from.ch &&
newBot.charCodeAt(newBot.length - cutEnd - 1) == oldBot.charCodeAt(oldBot.length - cutEnd - 1)) {
cutFront--;
cutEnd++;
}
}
newText[newText.length - 1] = newBot.slice(0, newBot.length - cutEnd).replace(/^\u200b+/, "");
newText[0] = newText[0].slice(cutFront).replace(/\u200b+$/, "");
var chFrom = Pos(fromLine, cutFront);
var chTo = Pos(toLine, oldText.length ? lst(oldText).length - cutEnd : 0);
if (newText.length > 1 || newText[0] || cmp(chFrom, chTo)) {
replaceRange(cm.doc, newText, chFrom, chTo, "+input");
return true
}
};
ContentEditableInput.prototype.ensurePolled = function () {
this.forceCompositionEnd();
};
ContentEditableInput.prototype.reset = function () {
this.forceCompositionEnd();
};
ContentEditableInput.prototype.forceCompositionEnd = function () {
if (!this.composing) { return }
clearTimeout(this.readDOMTimeout);
this.composing = null;
this.updateFromDOM();
this.div.blur();
this.div.focus();
};
ContentEditableInput.prototype.readFromDOMSoon = function () {
var this$1 = this;
if (this.readDOMTimeout != null) { return }
this.readDOMTimeout = setTimeout(function () {
this$1.readDOMTimeout = null;
if (this$1.composing) {
if (this$1.composing.done) { this$1.composing = null; }
else { return }
}
this$1.updateFromDOM();
}, 80);
};
ContentEditableInput.prototype.updateFromDOM = function () {
var this$1 = this;
if (this.cm.isReadOnly() || !this.pollContent())
{ runInOp(this.cm, function () { return regChange(this$1.cm); }); }
};
ContentEditableInput.prototype.setUneditable = function (node) {
node.contentEditable = "false";
};
ContentEditableInput.prototype.onKeyPress = function (e) {
if (e.charCode == 0 || this.composing) { return }
e.preventDefault();
if (!this.cm.isReadOnly())
{ operation(this.cm, applyTextInput)(this.cm, String.fromCharCode(e.charCode == null ? e.keyCode : e.charCode), 0); }
};
ContentEditableInput.prototype.readOnlyChanged = function (val) {
this.div.contentEditable = String(val != "nocursor");
};
ContentEditableInput.prototype.onContextMenu = function () {};
ContentEditableInput.prototype.resetPosition = function () {};
ContentEditableInput.prototype.needsContentAttribute = true;
function posToDOM(cm, pos) {
var view = findViewForLine(cm, pos.line);
if (!view || view.hidden) { return null }
var line = getLine(cm.doc, pos.line);
var info = mapFromLineView(view, line, pos.line);
var order = getOrder(line, cm.doc.direction), side = "left";
if (order) {
var partPos = getBidiPartAt(order, pos.ch);
side = partPos % 2 ? "right" : "left";
}
var result = nodeAndOffsetInLineMap(info.map, pos.ch, side);
result.offset = result.collapse == "right" ? result.end : result.start;
return result
}
function isInGutter(node) {
for (var scan = node; scan; scan = scan.parentNode)
{ if (/CodeMirror-gutter-wrapper/.test(scan.className)) { return true } }
return false
}
function badPos(pos, bad) { if (bad) { pos.bad = true; } return pos }
function domTextBetween(cm, from, to, fromLine, toLine) {
var text = "", closing = false, lineSep = cm.doc.lineSeparator(), extraLinebreak = false;
function recognizeMarker(id) { return function (marker) { return marker.id == id; } }
function close() {
if (closing) {
text += lineSep;
if (extraLinebreak) { text += lineSep; }
closing = extraLinebreak = false;
}
}
function addText(str) {
if (str) {
close();
text += str;
}
}
function walk(node) {
if (node.nodeType == 1) {
var cmText = node.getAttribute("cm-text");
if (cmText) {
addText(cmText);
return
}
var markerID = node.getAttribute("cm-marker"), range$$1;
if (markerID) {
var found = cm.findMarks(Pos(fromLine, 0), Pos(toLine + 1, 0), recognizeMarker(+markerID));
if (found.length && (range$$1 = found[0].find(0)))
{ addText(getBetween(cm.doc, range$$1.from, range$$1.to).join(lineSep)); }
return
}
if (node.getAttribute("contenteditable") == "false") { return }
var isBlock = /^(pre|div|p|li|table|br)$/i.test(node.nodeName);
if (!/^br$/i.test(node.nodeName) && node.textContent.length == 0) { return }
if (isBlock) { close(); }
for (var i = 0; i < node.childNodes.length; i++)
{ walk(node.childNodes[i]); }
if (/^(pre|p)$/i.test(node.nodeName)) { extraLinebreak = true; }
if (isBlock) { closing = true; }
} else if (node.nodeType == 3) {
addText(node.nodeValue.replace(/\u200b/g, "").replace(/\u00a0/g, " "));
}
}
for (;;) {
walk(from);
if (from == to) { break }
from = from.nextSibling;
extraLinebreak = false;
}
return text
}
function domToPos(cm, node, offset) {
var lineNode;
if (node == cm.display.lineDiv) {
lineNode = cm.display.lineDiv.childNodes[offset];
if (!lineNode) { return badPos(cm.clipPos(Pos(cm.display.viewTo - 1)), true) }
node = null; offset = 0;
} else {
for (lineNode = node;; lineNode = lineNode.parentNode) {
if (!lineNode || lineNode == cm.display.lineDiv) { return null }
if (lineNode.parentNode && lineNode.parentNode == cm.display.lineDiv) { break }
}
}
for (var i = 0; i < cm.display.view.length; i++) {
var lineView = cm.display.view[i];
if (lineView.node == lineNode)
{ return locateNodeInLineView(lineView, node, offset) }
}
}
function locateNodeInLineView(lineView, node, offset) {
var wrapper = lineView.text.firstChild, bad = false;
if (!node || !contains(wrapper, node)) { return badPos(Pos(lineNo(lineView.line), 0), true) }
if (node == wrapper) {
bad = true;
node = wrapper.childNodes[offset];
offset = 0;
if (!node) {
var line = lineView.rest ? lst(lineView.rest) : lineView.line;
return badPos(Pos(lineNo(line), line.text.length), bad)
}
}
var textNode = node.nodeType == 3 ? node : null, topNode = node;
if (!textNode && node.childNodes.length == 1 && node.firstChild.nodeType == 3) {
textNode = node.firstChild;
if (offset) { offset = textNode.nodeValue.length; }
}
while (topNode.parentNode != wrapper) { topNode = topNode.parentNode; }
var measure = lineView.measure, maps = measure.maps;
function find(textNode, topNode, offset) {
for (var i = -1; i < (maps ? maps.length : 0); i++) {
var map$$1 = i < 0 ? measure.map : maps[i];
for (var j = 0; j < map$$1.length; j += 3) {
var curNode = map$$1[j + 2];
if (curNode == textNode || curNode == topNode) {
var line = lineNo(i < 0 ? lineView.line : lineView.rest[i]);
var ch = map$$1[j] + offset;
if (offset < 0 || curNode != textNode) { ch = map$$1[j + (offset ? 1 : 0)]; }
return Pos(line, ch)
}
}
}
}
var found = find(textNode, topNode, offset);
if (found) { return badPos(found, bad) }
// FIXME this is all really shaky. might handle the few cases it needs to handle, but likely to cause problems
for (var after = topNode.nextSibling, dist = textNode ? textNode.nodeValue.length - offset : 0; after; after = after.nextSibling) {
found = find(after, after.firstChild, 0);
if (found)
{ return badPos(Pos(found.line, found.ch - dist), bad) }
else
{ dist += after.textContent.length; }
}
for (var before = topNode.previousSibling, dist$1 = offset; before; before = before.previousSibling) {
found = find(before, before.firstChild, -1);
if (found)
{ return badPos(Pos(found.line, found.ch + dist$1), bad) }
else
{ dist$1 += before.textContent.length; }
}
}
// TEXTAREA INPUT STYLE
var TextareaInput = function(cm) {
this.cm = cm;
// See input.poll and input.reset
this.prevInput = "";
// Flag that indicates whether we expect input to appear real soon
// now (after some event like 'keypress' or 'input') and are
// polling intensively.
this.pollingFast = false;
// Self-resetting timeout for the poller
this.polling = new Delayed();
// Used to work around IE issue with selection being forgotten when focus moves away from textarea
this.hasSelection = false;
this.composing = null;
};
TextareaInput.prototype.init = function (display) {
var this$1 = this;
var input = this, cm = this.cm;
this.createField(display);
var te = this.textarea;
display.wrapper.insertBefore(this.wrapper, display.wrapper.firstChild);
// Needed to hide big blue blinking cursor on Mobile Safari (doesn't seem to work in iOS 8 anymore)
if (ios) { te.style.width = "0px"; }
on(te, "input", function () {
if (ie && ie_version >= 9 && this$1.hasSelection) { this$1.hasSelection = null; }
input.poll();
});
on(te, "paste", function (e) {
if (signalDOMEvent(cm, e) || handlePaste(e, cm)) { return }
cm.state.pasteIncoming = true;
input.fastPoll();
});
function prepareCopyCut(e) {
if (signalDOMEvent(cm, e)) { return }
if (cm.somethingSelected()) {
setLastCopied({lineWise: false, text: cm.getSelections()});
} else if (!cm.options.lineWiseCopyCut) {
return
} else {
var ranges = copyableRanges(cm);
setLastCopied({lineWise: true, text: ranges.text});
if (e.type == "cut") {
cm.setSelections(ranges.ranges, null, sel_dontScroll);
} else {
input.prevInput = "";
te.value = ranges.text.join("\n");
selectInput(te);
}
}
if (e.type == "cut") { cm.state.cutIncoming = true; }
}
on(te, "cut", prepareCopyCut);
on(te, "copy", prepareCopyCut);
on(display.scroller, "paste", function (e) {
if (eventInWidget(display, e) || signalDOMEvent(cm, e)) { return }
cm.state.pasteIncoming = true;
input.focus();
});
// Prevent normal selection in the editor (we handle our own)
on(display.lineSpace, "selectstart", function (e) {
if (!eventInWidget(display, e)) { e_preventDefault(e); }
});
on(te, "compositionstart", function () {
var start = cm.getCursor("from");
if (input.composing) { input.composing.range.clear(); }
input.composing = {
start: start,
range: cm.markText(start, cm.getCursor("to"), {className: "CodeMirror-composing"})
};
});
on(te, "compositionend", function () {
if (input.composing) {
input.poll();
input.composing.range.clear();
input.composing = null;
}
});
};
TextareaInput.prototype.createField = function (_display) {
// Wraps and hides input textarea
this.wrapper = hiddenTextarea();
// The semihidden textarea that is focused when the editor is
// focused, and receives input.
this.textarea = this.wrapper.firstChild;
};
TextareaInput.prototype.prepareSelection = function () {
// Redraw the selection and/or cursor
var cm = this.cm, display = cm.display, doc = cm.doc;
var result = prepareSelection(cm);
// Move the hidden textarea near the cursor to prevent scrolling artifacts
if (cm.options.moveInputWithCursor) {
var headPos = cursorCoords(cm, doc.sel.primary().head, "div");
var wrapOff = display.wrapper.getBoundingClientRect(), lineOff = display.lineDiv.getBoundingClientRect();
result.teTop = Math.max(0, Math.min(display.wrapper.clientHeight - 10,
headPos.top + lineOff.top - wrapOff.top));
result.teLeft = Math.max(0, Math.min(display.wrapper.clientWidth - 10,
headPos.left + lineOff.left - wrapOff.left));
}
return result
};
TextareaInput.prototype.showSelection = function (drawn) {
var cm = this.cm, display = cm.display;
removeChildrenAndAdd(display.cursorDiv, drawn.cursors);
removeChildrenAndAdd(display.selectionDiv, drawn.selection);
if (drawn.teTop != null) {
this.wrapper.style.top = drawn.teTop + "px";
this.wrapper.style.left = drawn.teLeft + "px";
}
};
// Reset the input to correspond to the selection (or to be empty,
// when not typing and nothing is selected)
TextareaInput.prototype.reset = function (typing) {
if (this.contextMenuPending || this.composing) { return }
var cm = this.cm;
if (cm.somethingSelected()) {
this.prevInput = "";
var content = cm.getSelection();
this.textarea.value = content;
if (cm.state.focused) { selectInput(this.textarea); }
if (ie && ie_version >= 9) { this.hasSelection = content; }
} else if (!typing) {
this.prevInput = this.textarea.value = "";
if (ie && ie_version >= 9) { this.hasSelection = null; }
}
};
TextareaInput.prototype.getField = function () { return this.textarea };
TextareaInput.prototype.supportsTouch = function () { return false };
TextareaInput.prototype.focus = function () {
if (this.cm.options.readOnly != "nocursor" && (!mobile || activeElt() != this.textarea)) {
try { this.textarea.focus(); }
catch (e) {} // IE8 will throw if the textarea is display: none or not in DOM
}
};
TextareaInput.prototype.blur = function () { this.textarea.blur(); };
TextareaInput.prototype.resetPosition = function () {
this.wrapper.style.top = this.wrapper.style.left = 0;
};
TextareaInput.prototype.receivedFocus = function () { this.slowPoll(); };
// Poll for input changes, using the normal rate of polling. This
// runs as long as the editor is focused.
TextareaInput.prototype.slowPoll = function () {
var this$1 = this;
if (this.pollingFast) { return }
this.polling.set(this.cm.options.pollInterval, function () {
this$1.poll();
if (this$1.cm.state.focused) { this$1.slowPoll(); }
});
};
// When an event has just come in that is likely to add or change
// something in the input textarea, we poll faster, to ensure that
// the change appears on the screen quickly.
TextareaInput.prototype.fastPoll = function () {
var missed = false, input = this;
input.pollingFast = true;
function p() {
var changed = input.poll();
if (!changed && !missed) {missed = true; input.polling.set(60, p);}
else {input.pollingFast = false; input.slowPoll();}
}
input.polling.set(20, p);
};
// Read input from the textarea, and update the document to match.
// When something is selected, it is present in the textarea, and
// selected (unless it is huge, in which case a placeholder is
// used). When nothing is selected, the cursor sits after previously
// seen text (can be empty), which is stored in prevInput (we must
// not reset the textarea when typing, because that breaks IME).
TextareaInput.prototype.poll = function () {
var this$1 = this;
var cm = this.cm, input = this.textarea, prevInput = this.prevInput;
// Since this is called a *lot*, try to bail out as cheaply as
// possible when it is clear that nothing happened. hasSelection
// will be the case when there is a lot of text in the textarea,
// in which case reading its value would be expensive.
if (this.contextMenuPending || !cm.state.focused ||
(hasSelection(input) && !prevInput && !this.composing) ||
cm.isReadOnly() || cm.options.disableInput || cm.state.keySeq)
{ return false }
var text = input.value;
// If nothing changed, bail.
if (text == prevInput && !cm.somethingSelected()) { return false }
// Work around nonsensical selection resetting in IE9/10, and
// inexplicable appearance of private area unicode characters on
// some key combos in Mac (#2689).
if (ie && ie_version >= 9 && this.hasSelection === text ||
mac && /[\uf700-\uf7ff]/.test(text)) {
cm.display.input.reset();
return false
}
if (cm.doc.sel == cm.display.selForContextMenu) {
var first = text.charCodeAt(0);
if (first == 0x200b && !prevInput) { prevInput = "\u200b"; }
if (first == 0x21da) { this.reset(); return this.cm.execCommand("undo") }
}
// Find the part of the input that is actually new
var same = 0, l = Math.min(prevInput.length, text.length);
while (same < l && prevInput.charCodeAt(same) == text.charCodeAt(same)) { ++same; }
runInOp(cm, function () {
applyTextInput(cm, text.slice(same), prevInput.length - same,
null, this$1.composing ? "*compose" : null);
// Don't leave long text in the textarea, since it makes further polling slow
if (text.length > 1000 || text.indexOf("\n") > -1) { input.value = this$1.prevInput = ""; }
else { this$1.prevInput = text; }
if (this$1.composing) {
this$1.composing.range.clear();
this$1.composing.range = cm.markText(this$1.composing.start, cm.getCursor("to"),
{className: "CodeMirror-composing"});
}
});
return true
};
TextareaInput.prototype.ensurePolled = function () {
if (this.pollingFast && this.poll()) { this.pollingFast = false; }
};
TextareaInput.prototype.onKeyPress = function () {
if (ie && ie_version >= 9) { this.hasSelection = null; }
this.fastPoll();
};
TextareaInput.prototype.onContextMenu = function (e) {
var input = this, cm = input.cm, display = cm.display, te = input.textarea;
if (input.contextMenuPending) { input.contextMenuPending(); }
var pos = posFromMouse(cm, e), scrollPos = display.scroller.scrollTop;
if (!pos || presto) { return } // Opera is difficult.
// Reset the current text selection only if the click is done outside of the selection
// and 'resetSelectionOnContextMenu' option is true.
var reset = cm.options.resetSelectionOnContextMenu;
if (reset && cm.doc.sel.contains(pos) == -1)
{ operation(cm, setSelection)(cm.doc, simpleSelection(pos), sel_dontScroll); }
var oldCSS = te.style.cssText, oldWrapperCSS = input.wrapper.style.cssText;
var wrapperBox = input.wrapper.offsetParent.getBoundingClientRect();
input.wrapper.style.cssText = "position: static";
te.style.cssText = "position: absolute; width: 30px; height: 30px;\n top: " + (e.clientY - wrapperBox.top - 5) + "px; left: " + (e.clientX - wrapperBox.left - 5) + "px;\n z-index: 1000; background: " + (ie ? "rgba(255, 255, 255, .05)" : "transparent") + ";\n outline: none; border-width: 0; outline: none; overflow: hidden; opacity: .05; filter: alpha(opacity=5);";
var oldScrollY;
if (webkit) { oldScrollY = window.scrollY; } // Work around Chrome issue (#2712)
display.input.focus();
if (webkit) { window.scrollTo(null, oldScrollY); }
display.input.reset();
// Adds "Select all" to context menu in FF
if (!cm.somethingSelected()) { te.value = input.prevInput = " "; }
input.contextMenuPending = rehide;
display.selForContextMenu = cm.doc.sel;
clearTimeout(display.detectingSelectAll);
// Select-all will be greyed out if there's nothing to select, so
// this adds a zero-width space so that we can later check whether
// it got selected.
function prepareSelectAllHack() {
if (te.selectionStart != null) {
var selected = cm.somethingSelected();
var extval = "\u200b" + (selected ? te.value : "");
te.value = "\u21da"; // Used to catch context-menu undo
te.value = extval;
input.prevInput = selected ? "" : "\u200b";
te.selectionStart = 1; te.selectionEnd = extval.length;
// Re-set this, in case some other handler touched the
// selection in the meantime.
display.selForContextMenu = cm.doc.sel;
}
}
function rehide() {
if (input.contextMenuPending != rehide) { return }
input.contextMenuPending = false;
input.wrapper.style.cssText = oldWrapperCSS;
te.style.cssText = oldCSS;
if (ie && ie_version < 9) { display.scrollbars.setScrollTop(display.scroller.scrollTop = scrollPos); }
// Try to detect the user choosing select-all
if (te.selectionStart != null) {
if (!ie || (ie && ie_version < 9)) { prepareSelectAllHack(); }
var i = 0, poll = function () {
if (display.selForContextMenu == cm.doc.sel && te.selectionStart == 0 &&
te.selectionEnd > 0 && input.prevInput == "\u200b") {
operation(cm, selectAll)(cm);
} else if (i++ < 10) {
display.detectingSelectAll = setTimeout(poll, 500);
} else {
display.selForContextMenu = null;
display.input.reset();
}
};
display.detectingSelectAll = setTimeout(poll, 200);
}
}
if (ie && ie_version >= 9) { prepareSelectAllHack(); }
if (captureRightClick) {
e_stop(e);
var mouseup = function () {
off(window, "mouseup", mouseup);
setTimeout(rehide, 20);
};
on(window, "mouseup", mouseup);
} else {
setTimeout(rehide, 50);
}
};
TextareaInput.prototype.readOnlyChanged = function (val) {
if (!val) { this.reset(); }
this.textarea.disabled = val == "nocursor";
};
TextareaInput.prototype.setUneditable = function () {};
TextareaInput.prototype.needsContentAttribute = false;
function fromTextArea(textarea, options) {
options = options ? copyObj(options) : {};
options.value = textarea.value;
if (!options.tabindex && textarea.tabIndex)
{ options.tabindex = textarea.tabIndex; }
if (!options.placeholder && textarea.placeholder)
{ options.placeholder = textarea.placeholder; }
// Set autofocus to true if this textarea is focused, or if it has
// autofocus and no other element is focused.
if (options.autofocus == null) {
var hasFocus = activeElt();
options.autofocus = hasFocus == textarea ||
textarea.getAttribute("autofocus") != null && hasFocus == document.body;
}
function save() {textarea.value = cm.getValue();}
var realSubmit;
if (textarea.form) {
on(textarea.form, "submit", save);
// Deplorable hack to make the submit method do the right thing.
if (!options.leaveSubmitMethodAlone) {
var form = textarea.form;
realSubmit = form.submit;
try {
var wrappedSubmit = form.submit = function () {
save();
form.submit = realSubmit;
form.submit();
form.submit = wrappedSubmit;
};
} catch(e) {}
}
}
options.finishInit = function (cm) {
cm.save = save;
cm.getTextArea = function () { return textarea; };
cm.toTextArea = function () {
cm.toTextArea = isNaN; // Prevent this from being ran twice
save();
textarea.parentNode.removeChild(cm.getWrapperElement());
textarea.style.display = "";
if (textarea.form) {
off(textarea.form, "submit", save);
if (typeof textarea.form.submit == "function")
{ textarea.form.submit = realSubmit; }
}
};
};
textarea.style.display = "none";
var cm = CodeMirror(function (node) { return textarea.parentNode.insertBefore(node, textarea.nextSibling); },
options);
return cm
}
function addLegacyProps(CodeMirror) {
CodeMirror.off = off;
CodeMirror.on = on;
CodeMirror.wheelEventPixels = wheelEventPixels;
CodeMirror.Doc = Doc;
CodeMirror.splitLines = splitLinesAuto;
CodeMirror.countColumn = countColumn;
CodeMirror.findColumn = findColumn;
CodeMirror.isWordChar = isWordCharBasic;
CodeMirror.Pass = Pass;
CodeMirror.signal = signal;
CodeMirror.Line = Line;
CodeMirror.changeEnd = changeEnd;
CodeMirror.scrollbarModel = scrollbarModel;
CodeMirror.Pos = Pos;
CodeMirror.cmpPos = cmp;
CodeMirror.modes = modes;
CodeMirror.mimeModes = mimeModes;
CodeMirror.resolveMode = resolveMode;
CodeMirror.getMode = getMode;
CodeMirror.modeExtensions = modeExtensions;
CodeMirror.extendMode = extendMode;
CodeMirror.copyState = copyState;
CodeMirror.startState = startState;
CodeMirror.innerMode = innerMode;
CodeMirror.commands = commands;
CodeMirror.keyMap = keyMap;
CodeMirror.keyName = keyName;
CodeMirror.isModifierKey = isModifierKey;
CodeMirror.lookupKey = lookupKey;
CodeMirror.normalizeKeyMap = normalizeKeyMap;
CodeMirror.StringStream = StringStream;
CodeMirror.SharedTextMarker = SharedTextMarker;
CodeMirror.TextMarker = TextMarker;
CodeMirror.LineWidget = LineWidget;
CodeMirror.e_preventDefault = e_preventDefault;
CodeMirror.e_stopPropagation = e_stopPropagation;
CodeMirror.e_stop = e_stop;
CodeMirror.addClass = addClass;
CodeMirror.contains = contains;
CodeMirror.rmClass = rmClass;
CodeMirror.keyNames = keyNames;
}
// EDITOR CONSTRUCTOR
defineOptions(CodeMirror);
addEditorMethods(CodeMirror);
// Set up methods on CodeMirror's prototype to redirect to the editor's document.
var dontDelegate = "iter insert remove copy getEditor constructor".split(" ");
for (var prop in Doc.prototype) { if (Doc.prototype.hasOwnProperty(prop) && indexOf(dontDelegate, prop) < 0)
{ CodeMirror.prototype[prop] = (function(method) {
return function() {return method.apply(this.doc, arguments)}
})(Doc.prototype[prop]); } }
eventMixin(Doc);
CodeMirror.inputStyles = {"textarea": TextareaInput, "contenteditable": ContentEditableInput};
// Extra arguments are stored as the mode's dependencies, which is
// used by (legacy) mechanisms like loadmode.js to automatically
// load a mode. (Preferred mechanism is the require/define calls.)
CodeMirror.defineMode = function(name/*, mode, …*/) {
if (!CodeMirror.defaults.mode && name != "null") { CodeMirror.defaults.mode = name; }
defineMode.apply(this, arguments);
};
CodeMirror.defineMIME = defineMIME;
// Minimal default mode.
CodeMirror.defineMode("null", function () { return ({token: function (stream) { return stream.skipToEnd(); }}); });
CodeMirror.defineMIME("text/plain", "null");
// EXTENSIONS
CodeMirror.defineExtension = function (name, func) {
CodeMirror.prototype[name] = func;
};
CodeMirror.defineDocExtension = function (name, func) {
Doc.prototype[name] = func;
};
CodeMirror.fromTextArea = fromTextArea;
addLegacyProps(CodeMirror);
CodeMirror.version = "5.42.2";
return CodeMirror;
})));
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("css", function(config, parserConfig) {
var inline = parserConfig.inline
if (!parserConfig.propertyKeywords) parserConfig = CodeMirror.resolveMode("text/css");
var indentUnit = config.indentUnit,
tokenHooks = parserConfig.tokenHooks,
documentTypes = parserConfig.documentTypes || {},
mediaTypes = parserConfig.mediaTypes || {},
mediaFeatures = parserConfig.mediaFeatures || {},
mediaValueKeywords = parserConfig.mediaValueKeywords || {},
propertyKeywords = parserConfig.propertyKeywords || {},
nonStandardPropertyKeywords = parserConfig.nonStandardPropertyKeywords || {},
fontProperties = parserConfig.fontProperties || {},
counterDescriptors = parserConfig.counterDescriptors || {},
colorKeywords = parserConfig.colorKeywords || {},
valueKeywords = parserConfig.valueKeywords || {},
allowNested = parserConfig.allowNested,
lineComment = parserConfig.lineComment,
supportsAtComponent = parserConfig.supportsAtComponent === true;
var type, override;
function ret(style, tp) { type = tp; return style; }
// Tokenizers
function tokenBase(stream, state) {
var ch = stream.next();
if (tokenHooks[ch]) {
var result = tokenHooks[ch](stream, state);
if (result !== false) return result;
}
if (ch == "@") {
stream.eatWhile(/[\w\\\-]/);
return ret("def", stream.current());
} else if (ch == "=" || (ch == "~" || ch == "|") && stream.eat("=")) {
return ret(null, "compare");
} else if (ch == "\"" || ch == "'") {
state.tokenize = tokenString(ch);
return state.tokenize(stream, state);
} else if (ch == "#") {
stream.eatWhile(/[\w\\\-]/);
return ret("atom", "hash");
} else if (ch == "!") {
stream.match(/^\s*\w*/);
return ret("keyword", "important");
} else if (/\d/.test(ch) || ch == "." && stream.eat(/\d/)) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (ch === "-") {
if (/[\d.]/.test(stream.peek())) {
stream.eatWhile(/[\w.%]/);
return ret("number", "unit");
} else if (stream.match(/^-[\w\\\-]*/)) {
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ret("variable-2", "variable-definition");
return ret("variable-2", "variable");
} else if (stream.match(/^\w+-/)) {
return ret("meta", "meta");
}
} else if (/[,+>*\/]/.test(ch)) {
return ret(null, "select-op");
} else if (ch == "." && stream.match(/^-?[_a-z][_a-z0-9-]*/i)) {
return ret("qualifier", "qualifier");
} else if (/[:;{}\[\]\(\)]/.test(ch)) {
return ret(null, ch);
} else if (((ch == "u" || ch == "U") && stream.match(/rl(-prefix)?\(/i)) ||
((ch == "d" || ch == "D") && stream.match("omain(", true, true)) ||
((ch == "r" || ch == "R") && stream.match("egexp(", true, true))) {
stream.backUp(1);
state.tokenize = tokenParenthesized;
return ret("property", "word");
} else if (/[\w\\\-]/.test(ch)) {
stream.eatWhile(/[\w\\\-]/);
return ret("property", "word");
} else {
return ret(null, null);
}
}
function tokenString(quote) {
return function(stream, state) {
var escaped = false, ch;
while ((ch = stream.next()) != null) {
if (ch == quote && !escaped) {
if (quote == ")") stream.backUp(1);
break;
}
escaped = !escaped && ch == "\\";
}
if (ch == quote || !escaped && quote != ")") state.tokenize = null;
return ret("string", "string");
};
}
function tokenParenthesized(stream, state) {
stream.next(); // Must be '('
if (!stream.match(/\s*[\"\')]/, false))
state.tokenize = tokenString(")");
else
state.tokenize = null;
return ret(null, "(");
}
// Context management
function Context(type, indent, prev) {
this.type = type;
this.indent = indent;
this.prev = prev;
}
function pushContext(state, stream, type, indent) {
state.context = new Context(type, stream.indentation() + (indent === false ? 0 : indentUnit), state.context);
return type;
}
function popContext(state) {
if (state.context.prev)
state.context = state.context.prev;
return state.context.type;
}
function pass(type, stream, state) {
return states[state.context.type](type, stream, state);
}
function popAndPass(type, stream, state, n) {
for (var i = n || 1; i > 0; i--)
state.context = state.context.prev;
return pass(type, stream, state);
}
// Parser
function wordAsValue(stream) {
var word = stream.current().toLowerCase();
if (valueKeywords.hasOwnProperty(word))
override = "atom";
else if (colorKeywords.hasOwnProperty(word))
override = "keyword";
else
override = "variable";
}
var states = {};
states.top = function(type, stream, state) {
if (type == "{") {
return pushContext(state, stream, "block");
} else if (type == "}" && state.context.prev) {
return popContext(state);
} else if (supportsAtComponent && /@component/i.test(type)) {
return pushContext(state, stream, "atComponentBlock");
} else if (/^@(-moz-)?document$/i.test(type)) {
return pushContext(state, stream, "documentTypes");
} else if (/^@(media|supports|(-moz-)?document|import)$/i.test(type)) {
return pushContext(state, stream, "atBlock");
} else if (/^@(font-face|counter-style)/i.test(type)) {
state.stateArg = type;
return "restricted_atBlock_before";
} else if (/^@(-(moz|ms|o|webkit)-)?keyframes$/i.test(type)) {
return "keyframes";
} else if (type && type.charAt(0) == "@") {
return pushContext(state, stream, "at");
} else if (type == "hash") {
override = "builtin";
} else if (type == "word") {
override = "tag";
} else if (type == "variable-definition") {
return "maybeprop";
} else if (type == "interpolation") {
return pushContext(state, stream, "interpolation");
} else if (type == ":") {
return "pseudo";
} else if (allowNested && type == "(") {
return pushContext(state, stream, "parens");
}
return state.context.type;
};
states.block = function(type, stream, state) {
if (type == "word") {
var word = stream.current().toLowerCase();
if (propertyKeywords.hasOwnProperty(word)) {
override = "property";
return "maybeprop";
} else if (nonStandardPropertyKeywords.hasOwnProperty(word)) {
override = "string-2";
return "maybeprop";
} else if (allowNested) {
override = stream.match(/^\s*:(?:\s|$)/, false) ? "property" : "tag";
return "block";
} else {
override += " error";
return "maybeprop";
}
} else if (type == "meta") {
return "block";
} else if (!allowNested && (type == "hash" || type == "qualifier")) {
override = "error";
return "block";
} else {
return states.top(type, stream, state);
}
};
states.maybeprop = function(type, stream, state) {
if (type == ":") return pushContext(state, stream, "prop");
return pass(type, stream, state);
};
states.prop = function(type, stream, state) {
if (type == ";") return popContext(state);
if (type == "{" && allowNested) return pushContext(state, stream, "propBlock");
if (type == "}" || type == "{") return popAndPass(type, stream, state);
if (type == "(") return pushContext(state, stream, "parens");
if (type == "hash" && !/^#([0-9a-fA-f]{3,4}|[0-9a-fA-f]{6}|[0-9a-fA-f]{8})$/.test(stream.current())) {
override += " error";
} else if (type == "word") {
wordAsValue(stream);
} else if (type == "interpolation") {
return pushContext(state, stream, "interpolation");
}
return "prop";
};
states.propBlock = function(type, _stream, state) {
if (type == "}") return popContext(state);
if (type == "word") { override = "property"; return "maybeprop"; }
return state.context.type;
};
states.parens = function(type, stream, state) {
if (type == "{" || type == "}") return popAndPass(type, stream, state);
if (type == ")") return popContext(state);
if (type == "(") return pushContext(state, stream, "parens");
if (type == "interpolation") return pushContext(state, stream, "interpolation");
if (type == "word") wordAsValue(stream);
return "parens";
};
states.pseudo = function(type, stream, state) {
if (type == "meta") return "pseudo";
if (type == "word") {
override = "variable-3";
return state.context.type;
}
return pass(type, stream, state);
};
states.documentTypes = function(type, stream, state) {
if (type == "word" && documentTypes.hasOwnProperty(stream.current())) {
override = "tag";
return state.context.type;
} else {
return states.atBlock(type, stream, state);
}
};
states.atBlock = function(type, stream, state) {
if (type == "(") return pushContext(state, stream, "atBlock_parens");
if (type == "}" || type == ";") return popAndPass(type, stream, state);
if (type == "{") return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top");
if (type == "interpolation") return pushContext(state, stream, "interpolation");
if (type == "word") {
var word = stream.current().toLowerCase();
if (word == "only" || word == "not" || word == "and" || word == "or")
override = "keyword";
else if (mediaTypes.hasOwnProperty(word))
override = "attribute";
else if (mediaFeatures.hasOwnProperty(word))
override = "property";
else if (mediaValueKeywords.hasOwnProperty(word))
override = "keyword";
else if (propertyKeywords.hasOwnProperty(word))
override = "property";
else if (nonStandardPropertyKeywords.hasOwnProperty(word))
override = "string-2";
else if (valueKeywords.hasOwnProperty(word))
override = "atom";
else if (colorKeywords.hasOwnProperty(word))
override = "keyword";
else
override = "error";
}
return state.context.type;
};
states.atComponentBlock = function(type, stream, state) {
if (type == "}")
return popAndPass(type, stream, state);
if (type == "{")
return popContext(state) && pushContext(state, stream, allowNested ? "block" : "top", false);
if (type == "word")
override = "error";
return state.context.type;
};
states.atBlock_parens = function(type, stream, state) {
if (type == ")") return popContext(state);
if (type == "{" || type == "}") return popAndPass(type, stream, state, 2);
return states.atBlock(type, stream, state);
};
states.restricted_atBlock_before = function(type, stream, state) {
if (type == "{")
return pushContext(state, stream, "restricted_atBlock");
if (type == "word" && state.stateArg == "@counter-style") {
override = "variable";
return "restricted_atBlock_before";
}
return pass(type, stream, state);
};
states.restricted_atBlock = function(type, stream, state) {
if (type == "}") {
state.stateArg = null;
return popContext(state);
}
if (type == "word") {
if ((state.stateArg == "@font-face" && !fontProperties.hasOwnProperty(stream.current().toLowerCase())) ||
(state.stateArg == "@counter-style" && !counterDescriptors.hasOwnProperty(stream.current().toLowerCase())))
override = "error";
else
override = "property";
return "maybeprop";
}
return "restricted_atBlock";
};
states.keyframes = function(type, stream, state) {
if (type == "word") { override = "variable"; return "keyframes"; }
if (type == "{") return pushContext(state, stream, "top");
return pass(type, stream, state);
};
states.at = function(type, stream, state) {
if (type == ";") return popContext(state);
if (type == "{" || type == "}") return popAndPass(type, stream, state);
if (type == "word") override = "tag";
else if (type == "hash") override = "builtin";
return "at";
};
states.interpolation = function(type, stream, state) {
if (type == "}") return popContext(state);
if (type == "{" || type == ";") return popAndPass(type, stream, state);
if (type == "word") override = "variable";
else if (type != "variable" && type != "(" && type != ")") override = "error";
return "interpolation";
};
return {
startState: function(base) {
return {tokenize: null,
state: inline ? "block" : "top",
stateArg: null,
context: new Context(inline ? "block" : "top", base || 0, null)};
},
token: function(stream, state) {
if (!state.tokenize && stream.eatSpace()) return null;
var style = (state.tokenize || tokenBase)(stream, state);
if (style && typeof style == "object") {
type = style[1];
style = style[0];
}
override = style;
if (type != "comment")
state.state = states[state.state](type, stream, state);
return override;
},
indent: function(state, textAfter) {
var cx = state.context, ch = textAfter && textAfter.charAt(0);
var indent = cx.indent;
if (cx.type == "prop" && (ch == "}" || ch == ")")) cx = cx.prev;
if (cx.prev) {
if (ch == "}" && (cx.type == "block" || cx.type == "top" ||
cx.type == "interpolation" || cx.type == "restricted_atBlock")) {
// Resume indentation from parent context.
cx = cx.prev;
indent = cx.indent;
} else if (ch == ")" && (cx.type == "parens" || cx.type == "atBlock_parens") ||
ch == "{" && (cx.type == "at" || cx.type == "atBlock")) {
// Dedent relative to current context.
indent = Math.max(0, cx.indent - indentUnit);
}
}
return indent;
},
electricChars: "}",
blockCommentStart: "/*",
blockCommentEnd: "*/",
blockCommentContinue: " * ",
lineComment: lineComment,
fold: "brace"
};
});
function keySet(array) {
var keys = {};
for (var i = 0; i < array.length; ++i) {
keys[array[i].toLowerCase()] = true;
}
return keys;
}
var documentTypes_ = [
"domain", "regexp", "url", "url-prefix"
], documentTypes = keySet(documentTypes_);
var mediaTypes_ = [
"all", "aural", "braille", "handheld", "print", "projection", "screen",
"tty", "tv", "embossed"
], mediaTypes = keySet(mediaTypes_);
var mediaFeatures_ = [
"width", "min-width", "max-width", "height", "min-height", "max-height",
"device-width", "min-device-width", "max-device-width", "device-height",
"min-device-height", "max-device-height", "aspect-ratio",
"min-aspect-ratio", "max-aspect-ratio", "device-aspect-ratio",
"min-device-aspect-ratio", "max-device-aspect-ratio", "color", "min-color",
"max-color", "color-index", "min-color-index", "max-color-index",
"monochrome", "min-monochrome", "max-monochrome", "resolution",
"min-resolution", "max-resolution", "scan", "grid", "orientation",
"device-pixel-ratio", "min-device-pixel-ratio", "max-device-pixel-ratio",
"pointer", "any-pointer", "hover", "any-hover"
], mediaFeatures = keySet(mediaFeatures_);
var mediaValueKeywords_ = [
"landscape", "portrait", "none", "coarse", "fine", "on-demand", "hover",
"interlace", "progressive"
], mediaValueKeywords = keySet(mediaValueKeywords_);
var propertyKeywords_ = [
"align-content", "align-items", "align-self", "alignment-adjust",
"alignment-baseline", "anchor-point", "animation", "animation-delay",
"animation-direction", "animation-duration", "animation-fill-mode",
"animation-iteration-count", "animation-name", "animation-play-state",
"animation-timing-function", "appearance", "azimuth", "backface-visibility",
"background", "background-attachment", "background-blend-mode", "background-clip",
"background-color", "background-image", "background-origin", "background-position",
"background-repeat", "background-size", "baseline-shift", "binding",
"bleed", "bookmark-label", "bookmark-level", "bookmark-state",
"bookmark-target", "border", "border-bottom", "border-bottom-color",
"border-bottom-left-radius", "border-bottom-right-radius",
"border-bottom-style", "border-bottom-width", "border-collapse",
"border-color", "border-image", "border-image-outset",
"border-image-repeat", "border-image-slice", "border-image-source",
"border-image-width", "border-left", "border-left-color",
"border-left-style", "border-left-width", "border-radius", "border-right",
"border-right-color", "border-right-style", "border-right-width",
"border-spacing", "border-style", "border-top", "border-top-color",
"border-top-left-radius", "border-top-right-radius", "border-top-style",
"border-top-width", "border-width", "bottom", "box-decoration-break",
"box-shadow", "box-sizing", "break-after", "break-before", "break-inside",
"caption-side", "caret-color", "clear", "clip", "color", "color-profile", "column-count",
"column-fill", "column-gap", "column-rule", "column-rule-color",
"column-rule-style", "column-rule-width", "column-span", "column-width",
"columns", "content", "counter-increment", "counter-reset", "crop", "cue",
"cue-after", "cue-before", "cursor", "direction", "display",
"dominant-baseline", "drop-initial-after-adjust",
"drop-initial-after-align", "drop-initial-before-adjust",
"drop-initial-before-align", "drop-initial-size", "drop-initial-value",
"elevation", "empty-cells", "fit", "fit-position", "flex", "flex-basis",
"flex-direction", "flex-flow", "flex-grow", "flex-shrink", "flex-wrap",
"float", "float-offset", "flow-from", "flow-into", "font", "font-feature-settings",
"font-family", "font-kerning", "font-language-override", "font-size", "font-size-adjust",
"font-stretch", "font-style", "font-synthesis", "font-variant",
"font-variant-alternates", "font-variant-caps", "font-variant-east-asian",
"font-variant-ligatures", "font-variant-numeric", "font-variant-position",
"font-weight", "grid", "grid-area", "grid-auto-columns", "grid-auto-flow",
"grid-auto-rows", "grid-column", "grid-column-end", "grid-column-gap",
"grid-column-start", "grid-gap", "grid-row", "grid-row-end", "grid-row-gap",
"grid-row-start", "grid-template", "grid-template-areas", "grid-template-columns",
"grid-template-rows", "hanging-punctuation", "height", "hyphens",
"icon", "image-orientation", "image-rendering", "image-resolution",
"inline-box-align", "justify-content", "justify-items", "justify-self", "left", "letter-spacing",
"line-break", "line-height", "line-stacking", "line-stacking-ruby",
"line-stacking-shift", "line-stacking-strategy", "list-style",
"list-style-image", "list-style-position", "list-style-type", "margin",
"margin-bottom", "margin-left", "margin-right", "margin-top",
"marks", "marquee-direction", "marquee-loop",
"marquee-play-count", "marquee-speed", "marquee-style", "max-height",
"max-width", "min-height", "min-width", "mix-blend-mode", "move-to", "nav-down", "nav-index",
"nav-left", "nav-right", "nav-up", "object-fit", "object-position",
"opacity", "order", "orphans", "outline",
"outline-color", "outline-offset", "outline-style", "outline-width",
"overflow", "overflow-style", "overflow-wrap", "overflow-x", "overflow-y",
"padding", "padding-bottom", "padding-left", "padding-right", "padding-top",
"page", "page-break-after", "page-break-before", "page-break-inside",
"page-policy", "pause", "pause-after", "pause-before", "perspective",
"perspective-origin", "pitch", "pitch-range", "place-content", "place-items", "place-self", "play-during", "position",
"presentation-level", "punctuation-trim", "quotes", "region-break-after",
"region-break-before", "region-break-inside", "region-fragment",
"rendering-intent", "resize", "rest", "rest-after", "rest-before", "richness",
"right", "rotation", "rotation-point", "ruby-align", "ruby-overhang",
"ruby-position", "ruby-span", "shape-image-threshold", "shape-inside", "shape-margin",
"shape-outside", "size", "speak", "speak-as", "speak-header",
"speak-numeral", "speak-punctuation", "speech-rate", "stress", "string-set",
"tab-size", "table-layout", "target", "target-name", "target-new",
"target-position", "text-align", "text-align-last", "text-decoration",
"text-decoration-color", "text-decoration-line", "text-decoration-skip",
"text-decoration-style", "text-emphasis", "text-emphasis-color",
"text-emphasis-position", "text-emphasis-style", "text-height",
"text-indent", "text-justify", "text-outline", "text-overflow", "text-shadow",
"text-size-adjust", "text-space-collapse", "text-transform", "text-underline-position",
"text-wrap", "top", "transform", "transform-origin", "transform-style",
"transition", "transition-delay", "transition-duration",
"transition-property", "transition-timing-function", "unicode-bidi",
"user-select", "vertical-align", "visibility", "voice-balance", "voice-duration",
"voice-family", "voice-pitch", "voice-range", "voice-rate", "voice-stress",
"voice-volume", "volume", "white-space", "widows", "width", "will-change", "word-break",
"word-spacing", "word-wrap", "z-index",
// SVG-specific
"clip-path", "clip-rule", "mask", "enable-background", "filter", "flood-color",
"flood-opacity", "lighting-color", "stop-color", "stop-opacity", "pointer-events",
"color-interpolation", "color-interpolation-filters",
"color-rendering", "fill", "fill-opacity", "fill-rule", "image-rendering",
"marker", "marker-end", "marker-mid", "marker-start", "shape-rendering", "stroke",
"stroke-dasharray", "stroke-dashoffset", "stroke-linecap", "stroke-linejoin",
"stroke-miterlimit", "stroke-opacity", "stroke-width", "text-rendering",
"baseline-shift", "dominant-baseline", "glyph-orientation-horizontal",
"glyph-orientation-vertical", "text-anchor", "writing-mode"
], propertyKeywords = keySet(propertyKeywords_);
var nonStandardPropertyKeywords_ = [
"scrollbar-arrow-color", "scrollbar-base-color", "scrollbar-dark-shadow-color",
"scrollbar-face-color", "scrollbar-highlight-color", "scrollbar-shadow-color",
"scrollbar-3d-light-color", "scrollbar-track-color", "shape-inside",
"searchfield-cancel-button", "searchfield-decoration", "searchfield-results-button",
"searchfield-results-decoration", "zoom"
], nonStandardPropertyKeywords = keySet(nonStandardPropertyKeywords_);
var fontProperties_ = [
"font-family", "src", "unicode-range", "font-variant", "font-feature-settings",
"font-stretch", "font-weight", "font-style"
], fontProperties = keySet(fontProperties_);
var counterDescriptors_ = [
"additive-symbols", "fallback", "negative", "pad", "prefix", "range",
"speak-as", "suffix", "symbols", "system"
], counterDescriptors = keySet(counterDescriptors_);
var colorKeywords_ = [
"aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige",
"bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown",
"burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue",
"cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod",
"darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen",
"darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen",
"darkslateblue", "darkslategray", "darkturquoise", "darkviolet",
"deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick",
"floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite",
"gold", "goldenrod", "gray", "grey", "green", "greenyellow", "honeydew",
"hotpink", "indianred", "indigo", "ivory", "khaki", "lavender",
"lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral",
"lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightpink",
"lightsalmon", "lightseagreen", "lightskyblue", "lightslategray",
"lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta",
"maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple",
"mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise",
"mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin",
"navajowhite", "navy", "oldlace", "olive", "olivedrab", "orange", "orangered",
"orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred",
"papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue",
"purple", "rebeccapurple", "red", "rosybrown", "royalblue", "saddlebrown",
"salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue",
"slateblue", "slategray", "snow", "springgreen", "steelblue", "tan",
"teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white",
"whitesmoke", "yellow", "yellowgreen"
], colorKeywords = keySet(colorKeywords_);
var valueKeywords_ = [
"above", "absolute", "activeborder", "additive", "activecaption", "afar",
"after-white-space", "ahead", "alias", "all", "all-scroll", "alphabetic", "alternate",
"always", "amharic", "amharic-abegede", "antialiased", "appworkspace",
"arabic-indic", "armenian", "asterisks", "attr", "auto", "auto-flow", "avoid", "avoid-column", "avoid-page",
"avoid-region", "background", "backwards", "baseline", "below", "bidi-override", "binary",
"bengali", "blink", "block", "block-axis", "bold", "bolder", "border", "border-box",
"both", "bottom", "break", "break-all", "break-word", "bullets", "button", "button-bevel",
"buttonface", "buttonhighlight", "buttonshadow", "buttontext", "calc", "cambodian",
"capitalize", "caps-lock-indicator", "caption", "captiontext", "caret",
"cell", "center", "checkbox", "circle", "cjk-decimal", "cjk-earthly-branch",
"cjk-heavenly-stem", "cjk-ideographic", "clear", "clip", "close-quote",
"col-resize", "collapse", "color", "color-burn", "color-dodge", "column", "column-reverse",
"compact", "condensed", "contain", "content", "contents",
"content-box", "context-menu", "continuous", "copy", "counter", "counters", "cover", "crop",
"cross", "crosshair", "currentcolor", "cursive", "cyclic", "darken", "dashed", "decimal",
"decimal-leading-zero", "default", "default-button", "dense", "destination-atop",
"destination-in", "destination-out", "destination-over", "devanagari", "difference",
"disc", "discard", "disclosure-closed", "disclosure-open", "document",
"dot-dash", "dot-dot-dash",
"dotted", "double", "down", "e-resize", "ease", "ease-in", "ease-in-out", "ease-out",
"element", "ellipse", "ellipsis", "embed", "end", "ethiopic", "ethiopic-abegede",
"ethiopic-abegede-am-et", "ethiopic-abegede-gez", "ethiopic-abegede-ti-er",
"ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er",
"ethiopic-halehame-aa-et", "ethiopic-halehame-am-et",
"ethiopic-halehame-gez", "ethiopic-halehame-om-et",
"ethiopic-halehame-sid-et", "ethiopic-halehame-so-et",
"ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig",
"ethiopic-numeric", "ew-resize", "exclusion", "expanded", "extends", "extra-condensed",
"extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "flex", "flex-end", "flex-start", "footnotes",
"forwards", "from", "geometricPrecision", "georgian", "graytext", "grid", "groove",
"gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hard-light", "hebrew",
"help", "hidden", "hide", "higher", "highlight", "highlighttext",
"hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "hue", "icon", "ignore",
"inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite",
"infobackground", "infotext", "inherit", "initial", "inline", "inline-axis",
"inline-block", "inline-flex", "inline-grid", "inline-table", "inset", "inside", "intrinsic", "invert",
"italic", "japanese-formal", "japanese-informal", "justify", "kannada",
"katakana", "katakana-iroha", "keep-all", "khmer",
"korean-hangul-formal", "korean-hanja-formal", "korean-hanja-informal",
"landscape", "lao", "large", "larger", "left", "level", "lighter", "lighten",
"line-through", "linear", "linear-gradient", "lines", "list-item", "listbox", "listitem",
"local", "logical", "loud", "lower", "lower-alpha", "lower-armenian",
"lower-greek", "lower-hexadecimal", "lower-latin", "lower-norwegian",
"lower-roman", "lowercase", "ltr", "luminosity", "malayalam", "match", "matrix", "matrix3d",
"media-controls-background", "media-current-time-display",
"media-fullscreen-button", "media-mute-button", "media-play-button",
"media-return-to-realtime-button", "media-rewind-button",
"media-seek-back-button", "media-seek-forward-button", "media-slider",
"media-sliderthumb", "media-time-remaining-display", "media-volume-slider",
"media-volume-slider-container", "media-volume-sliderthumb", "medium",
"menu", "menulist", "menulist-button", "menulist-text",
"menulist-textfield", "menutext", "message-box", "middle", "min-intrinsic",
"mix", "mongolian", "monospace", "move", "multiple", "multiply", "myanmar", "n-resize",
"narrower", "ne-resize", "nesw-resize", "no-close-quote", "no-drop",
"no-open-quote", "no-repeat", "none", "normal", "not-allowed", "nowrap",
"ns-resize", "numbers", "numeric", "nw-resize", "nwse-resize", "oblique", "octal", "opacity", "open-quote",
"optimizeLegibility", "optimizeSpeed", "oriya", "oromo", "outset",
"outside", "outside-shape", "overlay", "overline", "padding", "padding-box",
"painted", "page", "paused", "persian", "perspective", "plus-darker", "plus-lighter",
"pointer", "polygon", "portrait", "pre", "pre-line", "pre-wrap", "preserve-3d",
"progress", "push-button", "radial-gradient", "radio", "read-only",
"read-write", "read-write-plaintext-only", "rectangle", "region",
"relative", "repeat", "repeating-linear-gradient",
"repeating-radial-gradient", "repeat-x", "repeat-y", "reset", "reverse",
"rgb", "rgba", "ridge", "right", "rotate", "rotate3d", "rotateX", "rotateY",
"rotateZ", "round", "row", "row-resize", "row-reverse", "rtl", "run-in", "running",
"s-resize", "sans-serif", "saturation", "scale", "scale3d", "scaleX", "scaleY", "scaleZ", "screen",
"scroll", "scrollbar", "scroll-position", "se-resize", "searchfield",
"searchfield-cancel-button", "searchfield-decoration",
"searchfield-results-button", "searchfield-results-decoration", "self-start", "self-end",
"semi-condensed", "semi-expanded", "separate", "serif", "show", "sidama",
"simp-chinese-formal", "simp-chinese-informal", "single",
"skew", "skewX", "skewY", "skip-white-space", "slide", "slider-horizontal",
"slider-vertical", "sliderthumb-horizontal", "sliderthumb-vertical", "slow",
"small", "small-caps", "small-caption", "smaller", "soft-light", "solid", "somali",
"source-atop", "source-in", "source-out", "source-over", "space", "space-around", "space-between", "space-evenly", "spell-out", "square",
"square-button", "start", "static", "status-bar", "stretch", "stroke", "sub",
"subpixel-antialiased", "super", "sw-resize", "symbolic", "symbols", "system-ui", "table",
"table-caption", "table-cell", "table-column", "table-column-group",
"table-footer-group", "table-header-group", "table-row", "table-row-group",
"tamil",
"telugu", "text", "text-bottom", "text-top", "textarea", "textfield", "thai",
"thick", "thin", "threeddarkshadow", "threedface", "threedhighlight",
"threedlightshadow", "threedshadow", "tibetan", "tigre", "tigrinya-er",
"tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", "to", "top",
"trad-chinese-formal", "trad-chinese-informal", "transform",
"translate", "translate3d", "translateX", "translateY", "translateZ",
"transparent", "ultra-condensed", "ultra-expanded", "underline", "unset", "up",
"upper-alpha", "upper-armenian", "upper-greek", "upper-hexadecimal",
"upper-latin", "upper-norwegian", "upper-roman", "uppercase", "urdu", "url",
"var", "vertical", "vertical-text", "visible", "visibleFill", "visiblePainted",
"visibleStroke", "visual", "w-resize", "wait", "wave", "wider",
"window", "windowframe", "windowtext", "words", "wrap", "wrap-reverse", "x-large", "x-small", "xor",
"xx-large", "xx-small"
], valueKeywords = keySet(valueKeywords_);
var allWords = documentTypes_.concat(mediaTypes_).concat(mediaFeatures_).concat(mediaValueKeywords_)
.concat(propertyKeywords_).concat(nonStandardPropertyKeywords_).concat(colorKeywords_)
.concat(valueKeywords_);
CodeMirror.registerHelper("hintWords", "css", allWords);
function tokenCComment(stream, state) {
var maybeEnd = false, ch;
while ((ch = stream.next()) != null) {
if (maybeEnd && ch == "/") {
state.tokenize = null;
break;
}
maybeEnd = (ch == "*");
}
return ["comment", "comment"];
}
CodeMirror.defineMIME("text/css", {
documentTypes: documentTypes,
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
mediaValueKeywords: mediaValueKeywords,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
fontProperties: fontProperties,
counterDescriptors: counterDescriptors,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
tokenHooks: {
"/": function(stream, state) {
if (!stream.eat("*")) return false;
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
},
name: "css"
});
CodeMirror.defineMIME("text/x-scss", {
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
mediaValueKeywords: mediaValueKeywords,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
fontProperties: fontProperties,
allowNested: true,
lineComment: "//",
tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
":": function(stream) {
if (stream.match(/\s*\{/, false))
return [null, null]
return false;
},
"$": function(stream) {
stream.match(/^[\w-]+/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
return ["variable-2", "variable"];
},
"#": function(stream) {
if (!stream.eat("{")) return false;
return [null, "interpolation"];
}
},
name: "css",
helperType: "scss"
});
CodeMirror.defineMIME("text/x-less", {
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
mediaValueKeywords: mediaValueKeywords,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
fontProperties: fontProperties,
allowNested: true,
lineComment: "//",
tokenHooks: {
"/": function(stream, state) {
if (stream.eat("/")) {
stream.skipToEnd();
return ["comment", "comment"];
} else if (stream.eat("*")) {
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
} else {
return ["operator", "operator"];
}
},
"@": function(stream) {
if (stream.eat("{")) return [null, "interpolation"];
if (stream.match(/^(charset|document|font-face|import|(-(moz|ms|o|webkit)-)?keyframes|media|namespace|page|supports)\b/i, false)) return false;
stream.eatWhile(/[\w\\\-]/);
if (stream.match(/^\s*:/, false))
return ["variable-2", "variable-definition"];
return ["variable-2", "variable"];
},
"&": function() {
return ["atom", "atom"];
}
},
name: "css",
helperType: "less"
});
CodeMirror.defineMIME("text/x-gss", {
documentTypes: documentTypes,
mediaTypes: mediaTypes,
mediaFeatures: mediaFeatures,
propertyKeywords: propertyKeywords,
nonStandardPropertyKeywords: nonStandardPropertyKeywords,
fontProperties: fontProperties,
counterDescriptors: counterDescriptors,
colorKeywords: colorKeywords,
valueKeywords: valueKeywords,
supportsAtComponent: true,
tokenHooks: {
"/": function(stream, state) {
if (!stream.eat("*")) return false;
state.tokenize = tokenCComment;
return tokenCComment(stream, state);
}
},
name: "css",
helperType: "gss"
});
});
// CodeMirror, copyright (c) by Marijn Haverbeke and others
// Distributed under an MIT license: https://codemirror.net/LICENSE
(function(mod) {
if (typeof exports == "object" && typeof module == "object") // CommonJS
mod(require("../../lib/codemirror"), require("../css/css"));
else if (typeof define == "function" && define.amd) // AMD
define(["../../lib/codemirror", "../css/css"], mod);
else // Plain browser env
mod(CodeMirror);
})(function(CodeMirror) {
"use strict";
CodeMirror.defineMode("sass", function(config) {
var cssMode = CodeMirror.mimeModes["text/css"];
var propertyKeywords = cssMode.propertyKeywords || {},
colorKeywords = cssMode.colorKeywords || {},
valueKeywords = cssMode.valueKeywords || {},
fontProperties = cssMode.fontProperties || {};
function tokenRegexp(words) {
return new RegExp("^" + words.join("|"));
}
var keywords = ["true", "false", "null", "auto"];
var keywordsRegexp = new RegExp("^" + keywords.join("|"));
var operators = ["\\(", "\\)", "=", ">", "<", "==", ">=", "<=", "\\+", "-",
"\\!=", "/", "\\*", "%", "and", "or", "not", ";","\\{","\\}",":"];
var opRegexp = tokenRegexp(operators);
var pseudoElementsRegexp = /^::?[a-zA-Z_][\w\-]*/;
var word;
function isEndLine(stream) {
return !stream.peek() || stream.match(/\s+$/, false);
}
function urlTokens(stream, state) {
var ch = stream.peek();
if (ch === ")") {
stream.next();
state.tokenizer = tokenBase;
return "operator";
} else if (ch === "(") {
stream.next();
stream.eatSpace();
return "operator";
} else if (ch === "'" || ch === '"') {
state.tokenizer = buildStringTokenizer(stream.next());
return "string";
} else {
state.tokenizer = buildStringTokenizer(")", false);
return "string";
}
}
function comment(indentation, multiLine) {
return function(stream, state) {
if (stream.sol() && stream.indentation() <= indentation) {
state.tokenizer = tokenBase;
return tokenBase(stream, state);
}
if (multiLine && stream.skipTo("*/")) {
stream.next();
stream.next();
state.tokenizer = tokenBase;
} else {
stream.skipToEnd();
}
return "comment";
};
}
function buildStringTokenizer(quote, greedy) {
if (greedy == null) { greedy = true; }
function stringTokenizer(stream, state) {
var nextChar = stream.next();
var peekChar = stream.peek();
var previousChar = stream.string.charAt(stream.pos-2);
var endingString = ((nextChar !== "\\" && peekChar === quote) || (nextChar === quote && previousChar !== "\\"));
if (endingString) {
if (nextChar !== quote && greedy) { stream.next(); }
if (isEndLine(stream)) {
state.cursorHalf = 0;
}
state.tokenizer = tokenBase;
return "string";
} else if (nextChar === "#" && peekChar === "{") {
state.tokenizer = buildInterpolationTokenizer(stringTokenizer);
stream.next();
return "operator";
} else {
return "string";
}
}
return stringTokenizer;
}
function buildInterpolationTokenizer(currentTokenizer) {
return function(stream, state) {
if (stream.peek() === "}") {
stream.next();
state.tokenizer = currentTokenizer;
return "operator";
} else {
return tokenBase(stream, state);
}
};
}
function indent(state) {
if (state.indentCount == 0) {
state.indentCount++;
var lastScopeOffset = state.scopes[0].offset;
var currentOffset = lastScopeOffset + config.indentUnit;
state.scopes.unshift({ offset:currentOffset });
}
}
function dedent(state) {
if (state.scopes.length == 1) return;
state.scopes.shift();
}
function tokenBase(stream, state) {
var ch = stream.peek();
// Comment
if (stream.match("/*")) {
state.tokenizer = comment(stream.indentation(), true);
return state.tokenizer(stream, state);
}
if (stream.match("//")) {
state.tokenizer = comment(stream.indentation(), false);
return state.tokenizer(stream, state);
}
// Interpolation
if (stream.match("#{")) {
state.tokenizer = buildInterpolationTokenizer(tokenBase);
return "operator";
}
// Strings
if (ch === '"' || ch === "'") {
stream.next();
state.tokenizer = buildStringTokenizer(ch);
return "string";
}
if(!state.cursorHalf){// state.cursorHalf === 0
// first half i.e. before : for key-value pairs
// including selectors
if (ch === "-") {
if (stream.match(/^-\w+-/)) {
return "meta";
}
}
if (ch === ".") {
stream.next();
if (stream.match(/^[\w-]+/)) {
indent(state);
return "qualifier";
} else if (stream.peek() === "#") {
indent(state);
return "tag";
}
}
if (ch === "#") {
stream.next();
// ID selectors
if (stream.match(/^[\w-]+/)) {
indent(state);
return "builtin";
}
if (stream.peek() === "#") {
indent(state);
return "tag";
}
}
// Variables
if (ch === "$") {
stream.next();
stream.eatWhile(/[\w-]/);
return "variable-2";
}
// Numbers
if (stream.match(/^-?[0-9\.]+/))
return "number";
// Units
if (stream.match(/^(px|em|in)\b/))
return "unit";
if (stream.match(keywordsRegexp))
return "keyword";
if (stream.match(/^url/) && stream.peek() === "(") {
state.tokenizer = urlTokens;
return "atom";
}
if (ch === "=") {
// Match shortcut mixin definition
if (stream.match(/^=[\w-]+/)) {
indent(state);
return "meta";
}
}
if (ch === "+") {
// Match shortcut mixin definition
if (stream.match(/^\+[\w-]+/)){
return "variable-3";
}
}
if(ch === "@"){
if(stream.match(/@extend/)){
if(!stream.match(/\s*[\w]/))
dedent(state);
}
}
// Indent Directives
if (stream.match(/^@(else if|if|media|else|for|each|while|mixin|function)/)) {
indent(state);
return "def";
}
// Other Directives
if (ch === "@") {
stream.next();
stream.eatWhile(/[\w-]/);
return "def";
}
if (stream.eatWhile(/[\w-]/)){
if(stream.match(/ *: *[\w-\+\$#!\("']/,false)){
word = stream.current().toLowerCase();
var prop = state.prevProp + "-" + word;
if (propertyKeywords.hasOwnProperty(prop)) {
return "property";
} else if (propertyKeywords.hasOwnProperty(word)) {
state.prevProp = word;
return "property";
} else if (fontProperties.hasOwnProperty(word)) {
return "property";
}
return "tag";
}
else if(stream.match(/ *:/,false)){
indent(state);
state.cursorHalf = 1;
state.prevProp = stream.current().toLowerCase();
return "property";
}
else if(stream.match(/ *,/,false)){
return "tag";
}
else{
indent(state);
return "tag";
}
}
if(ch === ":"){
if (stream.match(pseudoElementsRegexp)){ // could be a pseudo-element
return "variable-3";
}
stream.next();
state.cursorHalf=1;
return "operator";
}
} // cursorHalf===0 ends here
else{
if (ch === "#") {
stream.next();
// Hex numbers
if (stream.match(/[0-9a-fA-F]{6}|[0-9a-fA-F]{3}/)){
if (isEndLine(stream)) {
state.cursorHalf = 0;
}
return "number";
}
}
// Numbers
if (stream.match(/^-?[0-9\.]+/)){
if (isEndLine(stream)) {
state.cursorHalf = 0;
}
return "number";
}
// Units
if (stream.match(/^(px|em|in)\b/)){
if (isEndLine(stream)) {
state.cursorHalf = 0;
}
return "unit";
}
if (stream.match(keywordsRegexp)){
if (isEndLine(stream)) {
state.cursorHalf = 0;
}
return "keyword";
}
if (stream.match(/^url/) && stream.peek() === "(") {
state.tokenizer = urlTokens;
if (isEndLine(stream)) {
state.cursorHalf = 0;
}
return "atom";
}
// Variables
if (ch === "$") {
stream.next();
stream.eatWhile(/[\w-]/);
if (isEndLine(stream)) {
state.cursorHalf = 0;
}
return "variable-2";
}
// bang character for !important, !default, etc.
if (ch === "!") {
stream.next();
state.cursorHalf = 0;
return stream.match(/^[\w]+/) ? "keyword": "operator";
}
if (stream.match(opRegexp)){
if (isEndLine(stream)) {
state.cursorHalf = 0;
}
return "operator";
}
// attributes
if (stream.eatWhile(/[\w-]/)) {
if (isEndLine(stream)) {
state.cursorHalf = 0;
}
word = stream.current().toLowerCase();
if (valueKeywords.hasOwnProperty(word)) {
return "atom";
} else if (colorKeywords.hasOwnProperty(word)) {
return "keyword";
} else if (propertyKeywords.hasOwnProperty(word)) {
state.prevProp = stream.current().toLowerCase();
return "property";
} else {
return "tag";
}
}
//stream.eatSpace();
if (isEndLine(stream)) {
state.cursorHalf = 0;
return null;
}
} // else ends here
if (stream.match(opRegexp))
return "operator";
// If we haven't returned by now, we move 1 character
// and return an error
stream.next();
return null;
}
function tokenLexer(stream, state) {
if (stream.sol()) state.indentCount = 0;
var style = state.tokenizer(stream, state);
var current = stream.current();
if (current === "@return" || current === "}"){
dedent(state);
}
if (style !== null) {
var startOfToken = stream.pos - current.length;
var withCurrentIndent = startOfToken + (config.indentUnit * state.indentCount);
var newScopes = [];
for (var i = 0; i < state.scopes.length; i++) {
var scope = state.scopes[i];
if (scope.offset <= withCurrentIndent)
newScopes.push(scope);
}
state.scopes = newScopes;
}
return style;
}
return {
startState: function() {
return {
tokenizer: tokenBase,
scopes: [{offset: 0, type: "sass"}],
indentCount: 0,
cursorHalf: 0, // cursor half tells us if cursor lies after (1)
// or before (0) colon (well... more or less)
definedVars: [],
definedMixins: []
};
},
token: function(stream, state) {
var style = tokenLexer(stream, state);
state.lastToken = { style: style, content: stream.current() };
return style;
},
indent: function(state) {
return state.scopes[0].offset;
}
};
}, "css");
CodeMirror.defineMIME("text/x-sass", "sass");
});
//# sourceMappingURL=data:application/json;charset=utf8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbImRhdGUuanMiLCJqcXVlcnkuanMiLCJqcXVlcnktdWkuanMiLCJtdXN0YWNoZS5taW4uanMiLCJtYXRlcmlhbC5qcyIsInJpcHBsZXMuanMiLCJib290c3RyYXAuanMiLCJqcXVlcnkuaWZyYW1lLXRyYW5zcG9ydC5qcyIsImpxdWVyeS5maWxldXBsb2FkLmpzIiwic3BlY3RydW0uanMiLCJwZXJmZWN0LXNjcm9sbGJhci5qcXVlcnkuanMiLCJjb2RlbWlycm9yLmpzIiwiY3NzLmpzIiwic2Fzcy5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDakpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQ3QyVUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNqeGtCQTtBQUNBO0FDREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDcFRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDcFVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDcGhGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNoT0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDOTlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FDbnhFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUM1aURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNsZ1RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUNoMEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EiLCJmaWxlIjoidmVuZG9yLmpzIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXHJcbiAqIEB2ZXJzaW9uOiAxLjAgQWxwaGEtMVxyXG4gKiBAYXV0aG9yOiBDb29saXRlIEluYy4gaHR0cDovL3d3dy5jb29saXRlLmNvbS9cclxuICogQGRhdGU6IDIwMDgtMDUtMTNcclxuICogQGNvcHlyaWdodDogQ29weXJpZ2h0IChjKSAyMDA2LTIwMDgsIENvb2xpdGUgSW5jLiAoaHR0cDovL3d3dy5jb29saXRlLmNvbS8pLiBBbGwgcmlnaHRzIHJlc2VydmVkLlxyXG4gKiBAbGljZW5zZTogTGljZW5zZWQgdW5kZXIgVGhlIE1JVCBMaWNlbnNlLiBTZWUgbGljZW5zZS50eHQgYW5kIGh0dHA6Ly93d3cuZGF0ZWpzLmNvbS9saWNlbnNlLy4gXHJcbiAqIEB3ZWJzaXRlOiBodHRwOi8vd3d3LmRhdGVqcy5jb20vXHJcbiAqL1xyXG5EYXRlLkN1bHR1cmVJbmZvPXtuYW1lOlwiZW4tVVNcIixlbmdsaXNoTmFtZTpcIkVuZ2xpc2ggKFVuaXRlZCBTdGF0ZXMpXCIsbmF0aXZlTmFtZTpcIkVuZ2xpc2ggKFVuaXRlZCBTdGF0ZXMpXCIsZGF5TmFtZXM6W1wiU3VuZGF5XCIsXCJNb25kYXlcIixcIlR1ZXNkYXlcIixcIldlZG5lc2RheVwiLFwiVGh1cnNkYXlcIixcIkZyaWRheVwiLFwiU2F0dXJkYXlcIl0sYWJicmV2aWF0ZWREYXlOYW1lczpbXCJTdW5cIixcIk1vblwiLFwiVHVlXCIsXCJXZWRcIixcIlRodVwiLFwiRnJpXCIsXCJTYXRcIl0sc2hvcnRlc3REYXlOYW1lczpbXCJTdVwiLFwiTW9cIixcIlR1XCIsXCJXZVwiLFwiVGhcIixcIkZyXCIsXCJTYVwiXSxmaXJzdExldHRlckRheU5hbWVzOltcIlNcIixcIk1cIixcIlRcIixcIldcIixcIlRcIixcIkZcIixcIlNcIl0sbW9udGhOYW1lczpbXCJKYW51YXJ5XCIsXCJGZWJydWFyeVwiLFwiTWFyY2hcIixcIkFwcmlsXCIsXCJNYXlcIixcIkp1bmVcIixcIkp1bHlcIixcIkF1Z3VzdFwiLFwiU2VwdGVtYmVyXCIsXCJPY3RvYmVyXCIsXCJOb3ZlbWJlclwiLFwiRGVjZW1iZXJcIl0sYWJicmV2aWF0ZWRNb250aE5hbWVzOltcIkphblwiLFwiRmViXCIsXCJNYXJcIixcIkFwclwiLFwiTWF5XCIsXCJKdW5cIixcIkp1bFwiLFwiQXVnXCIsXCJTZXBcIixcIk9jdFwiLFwiTm92XCIsXCJEZWNcIl0sYW1EZXNpZ25hdG9yOlwiQU1cIixwbURlc2lnbmF0b3I6XCJQTVwiLGZpcnN0RGF5T2ZXZWVrOjAsdHdvRGlnaXRZZWFyTWF4OjIwMjksZGF0ZUVsZW1lbnRPcmRlcjpcIm1keVwiLGZvcm1hdFBhdHRlcm5zOntzaG9ydERhdGU6XCJNL2QveXl5eVwiLGxvbmdEYXRlOlwiZGRkZCwgTU1NTSBkZCwgeXl5eVwiLHNob3J0VGltZTpcImg6bW0gdHRcIixsb25nVGltZTpcImg6bW06c3MgdHRcIixmdWxsRGF0ZVRpbWU6XCJkZGRkLCBNTU1NIGRkLCB5eXl5IGg6bW06c3MgdHRcIixzb3J0YWJsZURhdGVUaW1lOlwieXl5eS1NTS1kZFRISDptbTpzc1wiLHVuaXZlcnNhbFNvcnRhYmxlRGF0ZVRpbWU6XCJ5eXl5LU1NLWRkIEhIOm1tOnNzWlwiLHJmYzExMjM6XCJkZGQsIGRkIE1NTSB5eXl5IEhIOm1tOnNzIEdNVFwiLG1vbnRoRGF5OlwiTU1NTSBkZFwiLHllYXJNb250aDpcIk1NTU0sIHl5eXlcIn0scmVnZXhQYXR0ZXJuczp7amFuOi9eamFuKHVhcnkpPy9pLGZlYjovXmZlYihydWFyeSk/L2ksbWFyOi9ebWFyKGNoKT8vaSxhcHI6L15hcHIoaWwpPy9pLG1heTovXm1heS9pLGp1bjovXmp1bihlKT8vaSxqdWw6L15qdWwoeSk/L2ksYXVnOi9eYXVnKHVzdCk/L2ksc2VwOi9ec2VwKHQoZW1iZXIpPyk/L2ksb2N0Oi9eb2N0KG9iZXIpPy9pLG5vdjovXm5vdihlbWJlcik/L2ksZGVjOi9eZGVjKGVtYmVyKT8vaSxzdW46L15zdShuKGRheSk/KT8vaSxtb246L15tbyhuKGRheSk/KT8vaSx0dWU6L150dShlKHMoZGF5KT8pPyk/L2ksd2VkOi9ed2UoZChuZXNkYXkpPyk/L2ksdGh1Oi9edGgodShyKHMoZGF5KT8pPyk/KT8vaSxmcmk6L15mcihpKGRheSk/KT8vaSxzYXQ6L15zYSh0KHVyZGF5KT8pPy9pLGZ1dHVyZTovXm5leHQvaSxwYXN0Oi9ebGFzdHxwYXN0fHByZXYoaW91cyk/L2ksYWRkOi9eKFxcK3xhZnQoZXIpP3xmcm9tfGhlbmNlKS9pLHN1YnRyYWN0Oi9eKFxcLXxiZWYob3JlKT98YWdvKS9pLHllc3RlcmRheTovXnllcyh0ZXJkYXkpPy9pLHRvZGF5Oi9edChvZChheSk/KT8vaSx0b21vcnJvdzovXnRvbShvcnJvdyk/L2ksbm93Oi9ebihvdyk/L2ksbWlsbGlzZWNvbmQ6L15tc3xtaWxsaShzZWNvbmQpP3M/L2ksc2Vjb25kOi9ec2VjKG9uZCk/cz8vaSxtaW51dGU6L15tbnxtaW4odXRlKT9zPy9pLGhvdXI6L15oKG91cik/cz8vaSx3ZWVrOi9edyhlZWspP3M/L2ksbW9udGg6L15tKG9udGgpP3M/L2ksZGF5Oi9eZChheSk/cz8vaSx5ZWFyOi9eeShlYXIpP3M/L2ksc2hvcnRNZXJpZGlhbjovXihhfHApL2ksbG9uZ01lcmlkaWFuOi9eKGFcXC4/bT9cXC4/fHBcXC4/bT9cXC4/KS9pLHRpbWV6b25lOi9eKChlKHN8ZCl0fGMoc3xkKXR8bShzfGQpdHxwKHN8ZCl0KXwoKGdtdCk/XFxzKihcXCt8XFwtKVxccypcXGRcXGRcXGRcXGQ/KXxnbXR8dXRjKS9pLG9yZGluYWxTdWZmaXg6L15cXHMqKHN0fG5kfHJkfHRoKS9pLHRpbWVDb250ZXh0Oi9eXFxzKihcXDp8YSg/IXV8cCl8cCkvaX0sdGltZXpvbmVzOlt7bmFtZTpcIlVUQ1wiLG9mZnNldDpcIi0wMDBcIn0se25hbWU6XCJHTVRcIixvZmZzZXQ6XCItMDAwXCJ9LHtuYW1lOlwiRVNUXCIsb2Zmc2V0OlwiLTA1MDBcIn0se25hbWU6XCJFRFRcIixvZmZzZXQ6XCItMDQwMFwifSx7bmFtZTpcIkNTVFwiLG9mZnNldDpcIi0wNjAwXCJ9LHtuYW1lOlwiQ0RUXCIsb2Zmc2V0OlwiLTA1MDBcIn0se25hbWU6XCJNU1RcIixvZmZzZXQ6XCItMDcwMFwifSx7bmFtZTpcIk1EVFwiLG9mZnNldDpcIi0wNjAwXCJ9LHtuYW1lOlwiUFNUXCIsb2Zmc2V0OlwiLTA4MDBcIn0se25hbWU6XCJQRFRcIixvZmZzZXQ6XCItMDcwMFwifV19O1xuKGZ1bmN0aW9uKCl7dmFyICREPURhdGUsJFA9JEQucHJvdG90eXBlLCRDPSRELkN1bHR1cmVJbmZvLHA9ZnVuY3Rpb24ocyxsKXtpZighbCl7bD0yO31cbnJldHVybihcIjAwMFwiK3MpLnNsaWNlKGwqLTEpO307JFAuY2xlYXJUaW1lPWZ1bmN0aW9uKCl7dGhpcy5zZXRIb3VycygwKTt0aGlzLnNldE1pbnV0ZXMoMCk7dGhpcy5zZXRTZWNvbmRzKDApO3RoaXMuc2V0TWlsbGlzZWNvbmRzKDApO3JldHVybiB0aGlzO307JFAuc2V0VGltZVRvTm93PWZ1bmN0aW9uKCl7dmFyIG49bmV3IERhdGUoKTt0aGlzLnNldEhvdXJzKG4uZ2V0SG91cnMoKSk7dGhpcy5zZXRNaW51dGVzKG4uZ2V0TWludXRlcygpKTt0aGlzLnNldFNlY29uZHMobi5nZXRTZWNvbmRzKCkpO3RoaXMuc2V0TWlsbGlzZWNvbmRzKG4uZ2V0TWlsbGlzZWNvbmRzKCkpO3JldHVybiB0aGlzO307JEQudG9kYXk9ZnVuY3Rpb24oKXtyZXR1cm4gbmV3IERhdGUoKS5jbGVhclRpbWUoKTt9OyRELmNvbXBhcmU9ZnVuY3Rpb24oZGF0ZTEsZGF0ZTIpe2lmKGlzTmFOKGRhdGUxKXx8aXNOYU4oZGF0ZTIpKXt0aHJvdyBuZXcgRXJyb3IoZGF0ZTErXCIgLSBcIitkYXRlMik7fWVsc2UgaWYoZGF0ZTEgaW5zdGFuY2VvZiBEYXRlJiZkYXRlMiBpbnN0YW5jZW9mIERhdGUpe3JldHVybihkYXRlMTxkYXRlMik/LTE6KGRhdGUxPmRhdGUyKT8xOjA7fWVsc2V7dGhyb3cgbmV3IFR5cGVFcnJvcihkYXRlMStcIiAtIFwiK2RhdGUyKTt9fTskRC5lcXVhbHM9ZnVuY3Rpb24oZGF0ZTEsZGF0ZTIpe3JldHVybihkYXRlMS5jb21wYXJlVG8oZGF0ZTIpPT09MCk7fTskRC5nZXREYXlOdW1iZXJGcm9tTmFtZT1mdW5jdGlvbihuYW1lKXt2YXIgbj0kQy5kYXlOYW1lcyxtPSRDLmFiYnJldmlhdGVkRGF5TmFtZXMsbz0kQy5zaG9ydGVzdERheU5hbWVzLHM9bmFtZS50b0xvd2VyQ2FzZSgpO2Zvcih2YXIgaT0wO2k8bi5sZW5ndGg7aSsrKXtpZihuW2ldLnRvTG93ZXJDYXNlKCk9PXN8fG1baV0udG9Mb3dlckNhc2UoKT09c3x8b1tpXS50b0xvd2VyQ2FzZSgpPT1zKXtyZXR1cm4gaTt9fVxucmV0dXJuLTE7fTskRC5nZXRNb250aE51bWJlckZyb21OYW1lPWZ1bmN0aW9uKG5hbWUpe3ZhciBuPSRDLm1vbnRoTmFtZXMsbT0kQy5hYmJyZXZpYXRlZE1vbnRoTmFtZXMscz1uYW1lLnRvTG93ZXJDYXNlKCk7Zm9yKHZhciBpPTA7aTxuLmxlbmd0aDtpKyspe2lmKG5baV0udG9Mb3dlckNhc2UoKT09c3x8bVtpXS50b0xvd2VyQ2FzZSgpPT1zKXtyZXR1cm4gaTt9fVxucmV0dXJuLTE7fTskRC5pc0xlYXBZZWFyPWZ1bmN0aW9uKHllYXIpe3JldHVybigoeWVhciU0PT09MCYmeWVhciUxMDAhPT0wKXx8eWVhciU0MDA9PT0wKTt9OyRELmdldERheXNJbk1vbnRoPWZ1bmN0aW9uKHllYXIsbW9udGgpe3JldHVyblszMSwoJEQuaXNMZWFwWWVhcih5ZWFyKT8yOToyOCksMzEsMzAsMzEsMzAsMzEsMzEsMzAsMzEsMzAsMzFdW21vbnRoXTt9OyRELmdldFRpbWV6b25lQWJicmV2aWF0aW9uPWZ1bmN0aW9uKG9mZnNldCl7dmFyIHo9JEMudGltZXpvbmVzLHA7Zm9yKHZhciBpPTA7aTx6Lmxlbmd0aDtpKyspe2lmKHpbaV0ub2Zmc2V0PT09b2Zmc2V0KXtyZXR1cm4geltpXS5uYW1lO319XG5yZXR1cm4gbnVsbDt9OyRELmdldFRpbWV6b25lT2Zmc2V0PWZ1bmN0aW9uKG5hbWUpe3ZhciB6PSRDLnRpbWV6b25lcyxwO2Zvcih2YXIgaT0wO2k8ei5sZW5ndGg7aSsrKXtpZih6W2ldLm5hbWU9PT1uYW1lLnRvVXBwZXJDYXNlKCkpe3JldHVybiB6W2ldLm9mZnNldDt9fVxucmV0dXJuIG51bGw7fTskUC5jbG9uZT1mdW5jdGlvbigpe3JldHVybiBuZXcgRGF0ZSh0aGlzLmdldFRpbWUoKSk7fTskUC5jb21wYXJlVG89ZnVuY3Rpb24oZGF0ZSl7cmV0dXJuIERhdGUuY29tcGFyZSh0aGlzLGRhdGUpO307JFAuZXF1YWxzPWZ1bmN0aW9uKGRhdGUpe3JldHVybiBEYXRlLmVxdWFscyh0aGlzLGRhdGV8fG5ldyBEYXRlKCkpO307JFAuYmV0d2Vlbj1mdW5jdGlvbihzdGFydCxlbmQpe3JldHVybiB0aGlzLmdldFRpbWUoKT49c3RhcnQuZ2V0VGltZSgpJiZ0aGlzLmdldFRpbWUoKTw9ZW5kLmdldFRpbWUoKTt9OyRQLmlzQWZ0ZXI9ZnVuY3Rpb24oZGF0ZSl7cmV0dXJuIHRoaXMuY29tcGFyZVRvKGRhdGV8fG5ldyBEYXRlKCkpPT09MTt9OyRQLmlzQmVmb3JlPWZ1bmN0aW9uKGRhdGUpe3JldHVybih0aGlzLmNvbXBhcmVUbyhkYXRlfHxuZXcgRGF0ZSgpKT09PS0xKTt9OyRQLmlzVG9kYXk9ZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5pc1NhbWVEYXkobmV3IERhdGUoKSk7fTskUC5pc1NhbWVEYXk9ZnVuY3Rpb24oZGF0ZSl7cmV0dXJuIHRoaXMuY2xvbmUoKS5jbGVhclRpbWUoKS5lcXVhbHMoZGF0ZS5jbG9uZSgpLmNsZWFyVGltZSgpKTt9OyRQLmFkZE1pbGxpc2Vjb25kcz1mdW5jdGlvbih2YWx1ZSl7dGhpcy5zZXRNaWxsaXNlY29uZHModGhpcy5nZXRNaWxsaXNlY29uZHMoKSt2YWx1ZSk7cmV0dXJuIHRoaXM7fTskUC5hZGRTZWNvbmRzPWZ1bmN0aW9uKHZhbHVlKXtyZXR1cm4gdGhpcy5hZGRNaWxsaXNlY29uZHModmFsdWUqMTAwMCk7fTskUC5hZGRNaW51dGVzPWZ1bmN0aW9uKHZhbHVlKXtyZXR1cm4gdGhpcy5hZGRNaWxsaXNlY29uZHModmFsdWUqNjAwMDApO307JFAuYWRkSG91cnM9ZnVuY3Rpb24odmFsdWUpe3JldHVybiB0aGlzLmFkZE1pbGxpc2Vjb25kcyh2YWx1ZSozNjAwMDAwKTt9OyRQLmFkZERheXM9ZnVuY3Rpb24odmFsdWUpe3RoaXMuc2V0RGF0ZSh0aGlzLmdldERhdGUoKSt2YWx1ZSk7cmV0dXJuIHRoaXM7fTskUC5hZGRXZWVrcz1mdW5jdGlvbih2YWx1ZSl7cmV0dXJuIHRoaXMuYWRkRGF5cyh2YWx1ZSo3KTt9OyRQLmFkZE1vbnRocz1mdW5jdGlvbih2YWx1ZSl7dmFyIG49dGhpcy5nZXREYXRlKCk7dGhpcy5zZXREYXRlKDEpO3RoaXMuc2V0TW9udGgodGhpcy5nZXRNb250aCgpK3ZhbHVlKTt0aGlzLnNldERhdGUoTWF0aC5taW4obiwkRC5nZXREYXlzSW5Nb250aCh0aGlzLmdldEZ1bGxZZWFyKCksdGhpcy5nZXRNb250aCgpKSkpO3JldHVybiB0aGlzO307JFAuYWRkWWVhcnM9ZnVuY3Rpb24odmFsdWUpe3JldHVybiB0aGlzLmFkZE1vbnRocyh2YWx1ZSoxMik7fTskUC5hZGQ9ZnVuY3Rpb24oY29uZmlnKXtpZih0eXBlb2YgY29uZmlnPT1cIm51bWJlclwiKXt0aGlzLl9vcmllbnQ9Y29uZmlnO3JldHVybiB0aGlzO31cbnZhciB4PWNvbmZpZztpZih4Lm1pbGxpc2Vjb25kcyl7dGhpcy5hZGRNaWxsaXNlY29uZHMoeC5taWxsaXNlY29uZHMpO31cbmlmKHguc2Vjb25kcyl7dGhpcy5hZGRTZWNvbmRzKHguc2Vjb25kcyk7fVxuaWYoeC5taW51dGVzKXt0aGlzLmFkZE1pbnV0ZXMoeC5taW51dGVzKTt9XG5pZih4LmhvdXJzKXt0aGlzLmFkZEhvdXJzKHguaG91cnMpO31cbmlmKHgud2Vla3Mpe3RoaXMuYWRkV2Vla3MoeC53ZWVrcyk7fVxuaWYoeC5tb250aHMpe3RoaXMuYWRkTW9udGhzKHgubW9udGhzKTt9XG5pZih4LnllYXJzKXt0aGlzLmFkZFllYXJzKHgueWVhcnMpO31cbmlmKHguZGF5cyl7dGhpcy5hZGREYXlzKHguZGF5cyk7fVxucmV0dXJuIHRoaXM7fTt2YXIgJHksJG0sJGQ7JFAuZ2V0V2Vlaz1mdW5jdGlvbigpe3ZhciBhLGIsYyxkLGUsZixnLG4scyx3OyR5PSghJHkpP3RoaXMuZ2V0RnVsbFllYXIoKTokeTskbT0oISRtKT90aGlzLmdldE1vbnRoKCkrMTokbTskZD0oISRkKT90aGlzLmdldERhdGUoKTokZDtpZigkbTw9Mil7YT0keS0xO2I9KGEvNHwwKS0oYS8xMDB8MCkrKGEvNDAwfDApO2M9KChhLTEpLzR8MCktKChhLTEpLzEwMHwwKSsoKGEtMSkvNDAwfDApO3M9Yi1jO2U9MDtmPSRkLTErKDMxKigkbS0xKSk7fWVsc2V7YT0keTtiPShhLzR8MCktKGEvMTAwfDApKyhhLzQwMHwwKTtjPSgoYS0xKS80fDApLSgoYS0xKS8xMDB8MCkrKChhLTEpLzQwMHwwKTtzPWItYztlPXMrMTtmPSRkKygoMTUzKigkbS0zKSsyKS81KSs1OCtzO31cbmc9KGErYiklNztkPShmK2ctZSklNztuPShmKzMtZCl8MDtpZihuPDApe3c9NTMtKChnLXMpLzV8MCk7fWVsc2UgaWYobj4zNjQrcyl7dz0xO31lbHNle3c9KG4vN3wwKSsxO31cbiR5PSRtPSRkPW51bGw7cmV0dXJuIHc7fTskUC5nZXRJU09XZWVrPWZ1bmN0aW9uKCl7JHk9dGhpcy5nZXRVVENGdWxsWWVhcigpOyRtPXRoaXMuZ2V0VVRDTW9udGgoKSsxOyRkPXRoaXMuZ2V0VVRDRGF0ZSgpO3JldHVybiBwKHRoaXMuZ2V0V2VlaygpKTt9OyRQLnNldFdlZWs9ZnVuY3Rpb24obil7cmV0dXJuIHRoaXMubW92ZVRvRGF5T2ZXZWVrKDEpLmFkZFdlZWtzKG4tdGhpcy5nZXRXZWVrKCkpO307JEQuX3ZhbGlkYXRlPWZ1bmN0aW9uKG4sbWluLG1heCxuYW1lKXtpZih0eXBlb2Ygbj09XCJ1bmRlZmluZWRcIil7cmV0dXJuIGZhbHNlO31lbHNlIGlmKHR5cGVvZiBuIT1cIm51bWJlclwiKXt0aHJvdyBuZXcgVHlwZUVycm9yKG4rXCIgaXMgbm90IGEgTnVtYmVyLlwiKTt9ZWxzZSBpZihuPG1pbnx8bj5tYXgpe3Rocm93IG5ldyBSYW5nZUVycm9yKG4rXCIgaXMgbm90IGEgdmFsaWQgdmFsdWUgZm9yIFwiK25hbWUrXCIuXCIpO31cbnJldHVybiB0cnVlO307JEQudmFsaWRhdGVNaWxsaXNlY29uZD1mdW5jdGlvbih2YWx1ZSl7cmV0dXJuICRELl92YWxpZGF0ZSh2YWx1ZSwwLDk5OSxcIm1pbGxpc2Vjb25kXCIpO307JEQudmFsaWRhdGVTZWNvbmQ9ZnVuY3Rpb24odmFsdWUpe3JldHVybiAkRC5fdmFsaWRhdGUodmFsdWUsMCw1OSxcInNlY29uZFwiKTt9OyRELnZhbGlkYXRlTWludXRlPWZ1bmN0aW9uKHZhbHVlKXtyZXR1cm4gJEQuX3ZhbGlkYXRlKHZhbHVlLDAsNTksXCJtaW51dGVcIik7fTskRC52YWxpZGF0ZUhvdXI9ZnVuY3Rpb24odmFsdWUpe3JldHVybiAkRC5fdmFsaWRhdGUodmFsdWUsMCwyMyxcImhvdXJcIik7fTskRC52YWxpZGF0ZURheT1mdW5jdGlvbih2YWx1ZSx5ZWFyLG1vbnRoKXtyZXR1cm4gJEQuX3ZhbGlkYXRlKHZhbHVlLDEsJEQuZ2V0RGF5c0luTW9udGgoeWVhcixtb250aCksXCJkYXlcIik7fTskRC52YWxpZGF0ZU1vbnRoPWZ1bmN0aW9uKHZhbHVlKXtyZXR1cm4gJEQuX3ZhbGlkYXRlKHZhbHVlLDAsMTEsXCJtb250aFwiKTt9OyRELnZhbGlkYXRlWWVhcj1mdW5jdGlvbih2YWx1ZSl7cmV0dXJuICRELl92YWxpZGF0ZSh2YWx1ZSwwLDk5OTksXCJ5ZWFyXCIpO307JFAuc2V0PWZ1bmN0aW9uKGNvbmZpZyl7aWYoJEQudmFsaWRhdGVNaWxsaXNlY29uZChjb25maWcubWlsbGlzZWNvbmQpKXt0aGlzLmFkZE1pbGxpc2Vjb25kcyhjb25maWcubWlsbGlzZWNvbmQtdGhpcy5nZXRNaWxsaXNlY29uZHMoKSk7fVxuaWYoJEQudmFsaWRhdGVTZWNvbmQoY29uZmlnLnNlY29uZCkpe3RoaXMuYWRkU2Vjb25kcyhjb25maWcuc2Vjb25kLXRoaXMuZ2V0U2Vjb25kcygpKTt9XG5pZigkRC52YWxpZGF0ZU1pbnV0ZShjb25maWcubWludXRlKSl7dGhpcy5hZGRNaW51dGVzKGNvbmZpZy5taW51dGUtdGhpcy5nZXRNaW51dGVzKCkpO31cbmlmKCRELnZhbGlkYXRlSG91cihjb25maWcuaG91cikpe3RoaXMuYWRkSG91cnMoY29uZmlnLmhvdXItdGhpcy5nZXRIb3VycygpKTt9XG5pZigkRC52YWxpZGF0ZU1vbnRoKGNvbmZpZy5tb250aCkpe3RoaXMuYWRkTW9udGhzKGNvbmZpZy5tb250aC10aGlzLmdldE1vbnRoKCkpO31cbmlmKCRELnZhbGlkYXRlWWVhcihjb25maWcueWVhcikpe3RoaXMuYWRkWWVhcnMoY29uZmlnLnllYXItdGhpcy5nZXRGdWxsWWVhcigpKTt9XG5pZigkRC52YWxpZGF0ZURheShjb25maWcuZGF5LHRoaXMuZ2V0RnVsbFllYXIoKSx0aGlzLmdldE1vbnRoKCkpKXt0aGlzLmFkZERheXMoY29uZmlnLmRheS10aGlzLmdldERhdGUoKSk7fVxuaWYoY29uZmlnLnRpbWV6b25lKXt0aGlzLnNldFRpbWV6b25lKGNvbmZpZy50aW1lem9uZSk7fVxuaWYoY29uZmlnLnRpbWV6b25lT2Zmc2V0KXt0aGlzLnNldFRpbWV6b25lT2Zmc2V0KGNvbmZpZy50aW1lem9uZU9mZnNldCk7fVxuaWYoY29uZmlnLndlZWsmJiRELl92YWxpZGF0ZShjb25maWcud2VlaywwLDUzLFwid2Vla1wiKSl7dGhpcy5zZXRXZWVrKGNvbmZpZy53ZWVrKTt9XG5yZXR1cm4gdGhpczt9OyRQLm1vdmVUb0ZpcnN0RGF5T2ZNb250aD1mdW5jdGlvbigpe3JldHVybiB0aGlzLnNldCh7ZGF5OjF9KTt9OyRQLm1vdmVUb0xhc3REYXlPZk1vbnRoPWZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuc2V0KHtkYXk6JEQuZ2V0RGF5c0luTW9udGgodGhpcy5nZXRGdWxsWWVhcigpLHRoaXMuZ2V0TW9udGgoKSl9KTt9OyRQLm1vdmVUb050aE9jY3VycmVuY2U9ZnVuY3Rpb24oZGF5T2ZXZWVrLG9jY3VycmVuY2Upe3ZhciBzaGlmdD0wO2lmKG9jY3VycmVuY2U+MCl7c2hpZnQ9b2NjdXJyZW5jZS0xO31cbmVsc2UgaWYob2NjdXJyZW5jZT09PS0xKXt0aGlzLm1vdmVUb0xhc3REYXlPZk1vbnRoKCk7aWYodGhpcy5nZXREYXkoKSE9PWRheU9mV2Vlayl7dGhpcy5tb3ZlVG9EYXlPZldlZWsoZGF5T2ZXZWVrLC0xKTt9XG5yZXR1cm4gdGhpczt9XG5yZXR1cm4gdGhpcy5tb3ZlVG9GaXJzdERheU9mTW9udGgoKS5hZGREYXlzKC0xKS5tb3ZlVG9EYXlPZldlZWsoZGF5T2ZXZWVrLCsxKS5hZGRXZWVrcyhzaGlmdCk7fTskUC5tb3ZlVG9EYXlPZldlZWs9ZnVuY3Rpb24oZGF5T2ZXZWVrLG9yaWVudCl7dmFyIGRpZmY9KGRheU9mV2Vlay10aGlzLmdldERheSgpKzcqKG9yaWVudHx8KzEpKSU3O3JldHVybiB0aGlzLmFkZERheXMoKGRpZmY9PT0wKT9kaWZmKz03KihvcmllbnR8fCsxKTpkaWZmKTt9OyRQLm1vdmVUb01vbnRoPWZ1bmN0aW9uKG1vbnRoLG9yaWVudCl7dmFyIGRpZmY9KG1vbnRoLXRoaXMuZ2V0TW9udGgoKSsxMioob3JpZW50fHwrMSkpJTEyO3JldHVybiB0aGlzLmFkZE1vbnRocygoZGlmZj09PTApP2RpZmYrPTEyKihvcmllbnR8fCsxKTpkaWZmKTt9OyRQLmdldE9yZGluYWxOdW1iZXI9ZnVuY3Rpb24oKXtyZXR1cm4gTWF0aC5jZWlsKCh0aGlzLmNsb25lKCkuY2xlYXJUaW1lKCktbmV3IERhdGUodGhpcy5nZXRGdWxsWWVhcigpLDAsMSkpLzg2NDAwMDAwKSsxO307JFAuZ2V0VGltZXpvbmU9ZnVuY3Rpb24oKXtyZXR1cm4gJEQuZ2V0VGltZXpvbmVBYmJyZXZpYXRpb24odGhpcy5nZXRVVENPZmZzZXQoKSk7fTskUC5zZXRUaW1lem9uZU9mZnNldD1mdW5jdGlvbihvZmZzZXQpe3ZhciBoZXJlPXRoaXMuZ2V0VGltZXpvbmVPZmZzZXQoKSx0aGVyZT1OdW1iZXIob2Zmc2V0KSotNi8xMDtyZXR1cm4gdGhpcy5hZGRNaW51dGVzKHRoZXJlLWhlcmUpO307JFAuc2V0VGltZXpvbmU9ZnVuY3Rpb24ob2Zmc2V0KXtyZXR1cm4gdGhpcy5zZXRUaW1lem9uZU9mZnNldCgkRC5nZXRUaW1lem9uZU9mZnNldChvZmZzZXQpKTt9OyRQLmhhc0RheWxpZ2h0U2F2aW5nVGltZT1mdW5jdGlvbigpe3JldHVybihEYXRlLnRvZGF5KCkuc2V0KHttb250aDowLGRheToxfSkuZ2V0VGltZXpvbmVPZmZzZXQoKSE9PURhdGUudG9kYXkoKS5zZXQoe21vbnRoOjYsZGF5OjF9KS5nZXRUaW1lem9uZU9mZnNldCgpKTt9OyRQLmlzRGF5bGlnaHRTYXZpbmdUaW1lPWZ1bmN0aW9uKCl7cmV0dXJuKHRoaXMuaGFzRGF5bGlnaHRTYXZpbmdUaW1lKCkmJm5ldyBEYXRlKCkuZ2V0VGltZXpvbmVPZmZzZXQoKT09PURhdGUudG9kYXkoKS5zZXQoe21vbnRoOjYsZGF5OjF9KS5nZXRUaW1lem9uZU9mZnNldCgpKTt9OyRQLmdldFVUQ09mZnNldD1mdW5jdGlvbigpe3ZhciBuPXRoaXMuZ2V0VGltZXpvbmVPZmZzZXQoKSotMTAvNixyO2lmKG48MCl7cj0obi0xMDAwMCkudG9TdHJpbmcoKTtyZXR1cm4gci5jaGFyQXQoMCkrci5zdWJzdHIoMik7fWVsc2V7cj0obisxMDAwMCkudG9TdHJpbmcoKTtyZXR1cm5cIitcIityLnN1YnN0cigxKTt9fTskUC5nZXRFbGFwc2VkPWZ1bmN0aW9uKGRhdGUpe3JldHVybihkYXRlfHxuZXcgRGF0ZSgpKS10aGlzO307aWYoISRQLnRvSVNPU3RyaW5nKXskUC50b0lTT1N0cmluZz1mdW5jdGlvbigpe2Z1bmN0aW9uIGYobil7cmV0dXJuIG48MTA/JzAnK246bjt9XG5yZXR1cm4nXCInK3RoaXMuZ2V0VVRDRnVsbFllYXIoKSsnLScrXG5mKHRoaXMuZ2V0VVRDTW9udGgoKSsxKSsnLScrXG5mKHRoaXMuZ2V0VVRDRGF0ZSgpKSsnVCcrXG5mKHRoaXMuZ2V0VVRDSG91cnMoKSkrJzonK1xuZih0aGlzLmdldFVUQ01pbnV0ZXMoKSkrJzonK1xuZih0aGlzLmdldFVUQ1NlY29uZHMoKSkrJ1pcIic7fTt9XG4kUC5fdG9TdHJpbmc9JFAudG9TdHJpbmc7JFAudG9TdHJpbmc9ZnVuY3Rpb24oZm9ybWF0KXt2YXIgeD10aGlzO2lmKGZvcm1hdCYmZm9ybWF0Lmxlbmd0aD09MSl7dmFyIGM9JEMuZm9ybWF0UGF0dGVybnM7eC50PXgudG9TdHJpbmc7c3dpdGNoKGZvcm1hdCl7Y2FzZVwiZFwiOnJldHVybiB4LnQoYy5zaG9ydERhdGUpO2Nhc2VcIkRcIjpyZXR1cm4geC50KGMubG9uZ0RhdGUpO2Nhc2VcIkZcIjpyZXR1cm4geC50KGMuZnVsbERhdGVUaW1lKTtjYXNlXCJtXCI6cmV0dXJuIHgudChjLm1vbnRoRGF5KTtjYXNlXCJyXCI6cmV0dXJuIHgudChjLnJmYzExMjMpO2Nhc2VcInNcIjpyZXR1cm4geC50KGMuc29ydGFibGVEYXRlVGltZSk7Y2FzZVwidFwiOnJldHVybiB4LnQoYy5zaG9ydFRpbWUpO2Nhc2VcIlRcIjpyZXR1cm4geC50KGMubG9uZ1RpbWUpO2Nhc2VcInVcIjpyZXR1cm4geC50KGMudW5pdmVyc2FsU29ydGFibGVEYXRlVGltZSk7Y2FzZVwieVwiOnJldHVybiB4LnQoYy55ZWFyTW9udGgpO319XG52YXIgb3JkPWZ1bmN0aW9uKG4pe3N3aXRjaChuKjEpe2Nhc2UgMTpjYXNlIDIxOmNhc2UgMzE6cmV0dXJuXCJzdFwiO2Nhc2UgMjpjYXNlIDIyOnJldHVyblwibmRcIjtjYXNlIDM6Y2FzZSAyMzpyZXR1cm5cInJkXCI7ZGVmYXVsdDpyZXR1cm5cInRoXCI7fX07cmV0dXJuIGZvcm1hdD9mb3JtYXQucmVwbGFjZSgvKFxcXFwpPyhkZD9kP2Q/fE1NP00/TT98eXk/eT95P3xoaD98SEg/fG1tP3xzcz98dHQ/fFMpL2csZnVuY3Rpb24obSl7aWYobS5jaGFyQXQoMCk9PT1cIlxcXFxcIil7cmV0dXJuIG0ucmVwbGFjZShcIlxcXFxcIixcIlwiKTt9XG54Lmg9eC5nZXRIb3Vycztzd2l0Y2gobSl7Y2FzZVwiaGhcIjpyZXR1cm4gcCh4LmgoKTwxMz8oeC5oKCk9PT0wPzEyOnguaCgpKTooeC5oKCktMTIpKTtjYXNlXCJoXCI6cmV0dXJuIHguaCgpPDEzPyh4LmgoKT09PTA/MTI6eC5oKCkpOih4LmgoKS0xMik7Y2FzZVwiSEhcIjpyZXR1cm4gcCh4LmgoKSk7Y2FzZVwiSFwiOnJldHVybiB4LmgoKTtjYXNlXCJtbVwiOnJldHVybiBwKHguZ2V0TWludXRlcygpKTtjYXNlXCJtXCI6cmV0dXJuIHguZ2V0TWludXRlcygpO2Nhc2VcInNzXCI6cmV0dXJuIHAoeC5nZXRTZWNvbmRzKCkpO2Nhc2VcInNcIjpyZXR1cm4geC5nZXRTZWNvbmRzKCk7Y2FzZVwieXl5eVwiOnJldHVybiBwKHguZ2V0RnVsbFllYXIoKSw0KTtjYXNlXCJ5eVwiOnJldHVybiBwKHguZ2V0RnVsbFllYXIoKSk7Y2FzZVwiZGRkZFwiOnJldHVybiAkQy5kYXlOYW1lc1t4LmdldERheSgpXTtjYXNlXCJkZGRcIjpyZXR1cm4gJEMuYWJicmV2aWF0ZWREYXlOYW1lc1t4LmdldERheSgpXTtjYXNlXCJkZFwiOnJldHVybiBwKHguZ2V0RGF0ZSgpKTtjYXNlXCJkXCI6cmV0dXJuIHguZ2V0RGF0ZSgpO2Nhc2VcIk1NTU1cIjpyZXR1cm4gJEMubW9udGhOYW1lc1t4LmdldE1vbnRoKCldO2Nhc2VcIk1NTVwiOnJldHVybiAkQy5hYmJyZXZpYXRlZE1vbnRoTmFtZXNbeC5nZXRNb250aCgpXTtjYXNlXCJNTVwiOnJldHVybiBwKCh4LmdldE1vbnRoKCkrMSkpO2Nhc2VcIk1cIjpyZXR1cm4geC5nZXRNb250aCgpKzE7Y2FzZVwidFwiOnJldHVybiB4LmgoKTwxMj8kQy5hbURlc2lnbmF0b3Iuc3Vic3RyaW5nKDAsMSk6JEMucG1EZXNpZ25hdG9yLnN1YnN0cmluZygwLDEpO2Nhc2VcInR0XCI6cmV0dXJuIHguaCgpPDEyPyRDLmFtRGVzaWduYXRvcjokQy5wbURlc2lnbmF0b3I7Y2FzZVwiU1wiOnJldHVybiBvcmQoeC5nZXREYXRlKCkpO2RlZmF1bHQ6cmV0dXJuIG07fX0pOnRoaXMuX3RvU3RyaW5nKCk7fTt9KCkpO1xuKGZ1bmN0aW9uKCl7dmFyICREPURhdGUsJFA9JEQucHJvdG90eXBlLCRDPSRELkN1bHR1cmVJbmZvLCROPU51bWJlci5wcm90b3R5cGU7JFAuX29yaWVudD0rMTskUC5fbnRoPW51bGw7JFAuX2lzPWZhbHNlOyRQLl9zYW1lPWZhbHNlOyRQLl9pc1NlY29uZD1mYWxzZTskTi5fZGF0ZUVsZW1lbnQ9XCJkYXlcIjskUC5uZXh0PWZ1bmN0aW9uKCl7dGhpcy5fb3JpZW50PSsxO3JldHVybiB0aGlzO307JEQubmV4dD1mdW5jdGlvbigpe3JldHVybiAkRC50b2RheSgpLm5leHQoKTt9OyRQLmxhc3Q9JFAucHJldj0kUC5wcmV2aW91cz1mdW5jdGlvbigpe3RoaXMuX29yaWVudD0tMTtyZXR1cm4gdGhpczt9OyRELmxhc3Q9JEQucHJldj0kRC5wcmV2aW91cz1mdW5jdGlvbigpe3JldHVybiAkRC50b2RheSgpLmxhc3QoKTt9OyRQLmlzPWZ1bmN0aW9uKCl7dGhpcy5faXM9dHJ1ZTtyZXR1cm4gdGhpczt9OyRQLnNhbWU9ZnVuY3Rpb24oKXt0aGlzLl9zYW1lPXRydWU7dGhpcy5faXNTZWNvbmQ9ZmFsc2U7cmV0dXJuIHRoaXM7fTskUC50b2RheT1mdW5jdGlvbigpe3JldHVybiB0aGlzLnNhbWUoKS5kYXkoKTt9OyRQLndlZWtkYXk9ZnVuY3Rpb24oKXtpZih0aGlzLl9pcyl7dGhpcy5faXM9ZmFsc2U7cmV0dXJuKCF0aGlzLmlzKCkuc2F0KCkmJiF0aGlzLmlzKCkuc3VuKCkpO31cbnJldHVybiBmYWxzZTt9OyRQLmF0PWZ1bmN0aW9uKHRpbWUpe3JldHVybih0eXBlb2YgdGltZT09PVwic3RyaW5nXCIpPyRELnBhcnNlKHRoaXMudG9TdHJpbmcoXCJkXCIpK1wiIFwiK3RpbWUpOnRoaXMuc2V0KHRpbWUpO307JE4uZnJvbU5vdz0kTi5hZnRlcj1mdW5jdGlvbihkYXRlKXt2YXIgYz17fTtjW3RoaXMuX2RhdGVFbGVtZW50XT10aGlzO3JldHVybigoIWRhdGUpP25ldyBEYXRlKCk6ZGF0ZS5jbG9uZSgpKS5hZGQoYyk7fTskTi5hZ289JE4uYmVmb3JlPWZ1bmN0aW9uKGRhdGUpe3ZhciBjPXt9O2NbdGhpcy5fZGF0ZUVsZW1lbnRdPXRoaXMqLTE7cmV0dXJuKCghZGF0ZSk/bmV3IERhdGUoKTpkYXRlLmNsb25lKCkpLmFkZChjKTt9O3ZhciBkeD0oXCJzdW5kYXkgbW9uZGF5IHR1ZXNkYXkgd2VkbmVzZGF5IHRodXJzZGF5IGZyaWRheSBzYXR1cmRheVwiKS5zcGxpdCgvXFxzLyksbXg9KFwiamFudWFyeSBmZWJydWFyeSBtYXJjaCBhcHJpbCBtYXkganVuZSBqdWx5IGF1Z3VzdCBzZXB0ZW1iZXIgb2N0b2JlciBub3ZlbWJlciBkZWNlbWJlclwiKS5zcGxpdCgvXFxzLykscHg9KFwiTWlsbGlzZWNvbmQgU2Vjb25kIE1pbnV0ZSBIb3VyIERheSBXZWVrIE1vbnRoIFllYXJcIikuc3BsaXQoL1xccy8pLHB4Zj0oXCJNaWxsaXNlY29uZHMgU2Vjb25kcyBNaW51dGVzIEhvdXJzIERhdGUgV2VlayBNb250aCBGdWxsWWVhclwiKS5zcGxpdCgvXFxzLyksbnRoPShcImZpbmFsIGZpcnN0IHNlY29uZCB0aGlyZCBmb3VydGggZmlmdGhcIikuc3BsaXQoL1xccy8pLGRlOyRQLnRvT2JqZWN0PWZ1bmN0aW9uKCl7dmFyIG89e307Zm9yKHZhciBpPTA7aTxweC5sZW5ndGg7aSsrKXtvW3B4W2ldLnRvTG93ZXJDYXNlKCldPXRoaXNbXCJnZXRcIitweGZbaV1dKCk7fVxucmV0dXJuIG87fTskRC5mcm9tT2JqZWN0PWZ1bmN0aW9uKGNvbmZpZyl7Y29uZmlnLndlZWs9bnVsbDtyZXR1cm4gRGF0ZS50b2RheSgpLnNldChjb25maWcpO307dmFyIGRmPWZ1bmN0aW9uKG4pe3JldHVybiBmdW5jdGlvbigpe2lmKHRoaXMuX2lzKXt0aGlzLl9pcz1mYWxzZTtyZXR1cm4gdGhpcy5nZXREYXkoKT09bjt9XG5pZih0aGlzLl9udGghPT1udWxsKXtpZih0aGlzLl9pc1NlY29uZCl7dGhpcy5hZGRTZWNvbmRzKHRoaXMuX29yaWVudCotMSk7fVxudGhpcy5faXNTZWNvbmQ9ZmFsc2U7dmFyIG50ZW1wPXRoaXMuX250aDt0aGlzLl9udGg9bnVsbDt2YXIgdGVtcD10aGlzLmNsb25lKCkubW92ZVRvTGFzdERheU9mTW9udGgoKTt0aGlzLm1vdmVUb050aE9jY3VycmVuY2UobixudGVtcCk7aWYodGhpcz50ZW1wKXt0aHJvdyBuZXcgUmFuZ2VFcnJvcigkRC5nZXREYXlOYW1lKG4pK1wiIGRvZXMgbm90IG9jY3VyIFwiK250ZW1wK1wiIHRpbWVzIGluIHRoZSBtb250aCBvZiBcIiskRC5nZXRNb250aE5hbWUodGVtcC5nZXRNb250aCgpKStcIiBcIit0ZW1wLmdldEZ1bGxZZWFyKCkrXCIuXCIpO31cbnJldHVybiB0aGlzO31cbnJldHVybiB0aGlzLm1vdmVUb0RheU9mV2VlayhuLHRoaXMuX29yaWVudCk7fTt9O3ZhciBzZGY9ZnVuY3Rpb24obil7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIHQ9JEQudG9kYXkoKSxzaGlmdD1uLXQuZ2V0RGF5KCk7aWYobj09PTAmJiRDLmZpcnN0RGF5T2ZXZWVrPT09MSYmdC5nZXREYXkoKSE9PTApe3NoaWZ0PXNoaWZ0Kzc7fVxucmV0dXJuIHQuYWRkRGF5cyhzaGlmdCk7fTt9O2Zvcih2YXIgaT0wO2k8ZHgubGVuZ3RoO2krKyl7JERbZHhbaV0udG9VcHBlckNhc2UoKV09JERbZHhbaV0udG9VcHBlckNhc2UoKS5zdWJzdHJpbmcoMCwzKV09aTskRFtkeFtpXV09JERbZHhbaV0uc3Vic3RyaW5nKDAsMyldPXNkZihpKTskUFtkeFtpXV09JFBbZHhbaV0uc3Vic3RyaW5nKDAsMyldPWRmKGkpO31cbnZhciBtZj1mdW5jdGlvbihuKXtyZXR1cm4gZnVuY3Rpb24oKXtpZih0aGlzLl9pcyl7dGhpcy5faXM9ZmFsc2U7cmV0dXJuIHRoaXMuZ2V0TW9udGgoKT09PW47fVxucmV0dXJuIHRoaXMubW92ZVRvTW9udGgobix0aGlzLl9vcmllbnQpO307fTt2YXIgc21mPWZ1bmN0aW9uKG4pe3JldHVybiBmdW5jdGlvbigpe3JldHVybiAkRC50b2RheSgpLnNldCh7bW9udGg6bixkYXk6MX0pO307fTtmb3IodmFyIGo9MDtqPG14Lmxlbmd0aDtqKyspeyREW214W2pdLnRvVXBwZXJDYXNlKCldPSREW214W2pdLnRvVXBwZXJDYXNlKCkuc3Vic3RyaW5nKDAsMyldPWo7JERbbXhbal1dPSREW214W2pdLnN1YnN0cmluZygwLDMpXT1zbWYoaik7JFBbbXhbal1dPSRQW214W2pdLnN1YnN0cmluZygwLDMpXT1tZihqKTt9XG52YXIgZWY9ZnVuY3Rpb24oail7cmV0dXJuIGZ1bmN0aW9uKCl7aWYodGhpcy5faXNTZWNvbmQpe3RoaXMuX2lzU2Vjb25kPWZhbHNlO3JldHVybiB0aGlzO31cbmlmKHRoaXMuX3NhbWUpe3RoaXMuX3NhbWU9dGhpcy5faXM9ZmFsc2U7dmFyIG8xPXRoaXMudG9PYmplY3QoKSxvMj0oYXJndW1lbnRzWzBdfHxuZXcgRGF0ZSgpKS50b09iamVjdCgpLHY9XCJcIixrPWoudG9Mb3dlckNhc2UoKTtmb3IodmFyIG09KHB4Lmxlbmd0aC0xKTttPi0xO20tLSl7dj1weFttXS50b0xvd2VyQ2FzZSgpO2lmKG8xW3ZdIT1vMlt2XSl7cmV0dXJuIGZhbHNlO31cbmlmKGs9PXYpe2JyZWFrO319XG5yZXR1cm4gdHJ1ZTt9XG5pZihqLnN1YnN0cmluZyhqLmxlbmd0aC0xKSE9XCJzXCIpe2orPVwic1wiO31cbnJldHVybiB0aGlzW1wiYWRkXCIral0odGhpcy5fb3JpZW50KTt9O307dmFyIG5mPWZ1bmN0aW9uKG4pe3JldHVybiBmdW5jdGlvbigpe3RoaXMuX2RhdGVFbGVtZW50PW47cmV0dXJuIHRoaXM7fTt9O2Zvcih2YXIgaz0wO2s8cHgubGVuZ3RoO2srKyl7ZGU9cHhba10udG9Mb3dlckNhc2UoKTskUFtkZV09JFBbZGUrXCJzXCJdPWVmKHB4W2tdKTskTltkZV09JE5bZGUrXCJzXCJdPW5mKGRlKTt9XG4kUC5fc3M9ZWYoXCJTZWNvbmRcIik7dmFyIG50aGZuPWZ1bmN0aW9uKG4pe3JldHVybiBmdW5jdGlvbihkYXlPZldlZWspe2lmKHRoaXMuX3NhbWUpe3JldHVybiB0aGlzLl9zcyhhcmd1bWVudHNbMF0pO31cbmlmKGRheU9mV2Vla3x8ZGF5T2ZXZWVrPT09MCl7cmV0dXJuIHRoaXMubW92ZVRvTnRoT2NjdXJyZW5jZShkYXlPZldlZWssbik7fVxudGhpcy5fbnRoPW47aWYobj09PTImJihkYXlPZldlZWs9PT11bmRlZmluZWR8fGRheU9mV2Vlaz09PW51bGwpKXt0aGlzLl9pc1NlY29uZD10cnVlO3JldHVybiB0aGlzLmFkZFNlY29uZHModGhpcy5fb3JpZW50KTt9XG5yZXR1cm4gdGhpczt9O307Zm9yKHZhciBsPTA7bDxudGgubGVuZ3RoO2wrKyl7JFBbbnRoW2xdXT0obD09PTApP250aGZuKC0xKTpudGhmbihsKTt9fSgpKTtcbihmdW5jdGlvbigpe0RhdGUuUGFyc2luZz17RXhjZXB0aW9uOmZ1bmN0aW9uKHMpe3RoaXMubWVzc2FnZT1cIlBhcnNlIGVycm9yIGF0ICdcIitzLnN1YnN0cmluZygwLDEwKStcIiAuLi4nXCI7fX07dmFyICRQPURhdGUuUGFyc2luZzt2YXIgXz0kUC5PcGVyYXRvcnM9e3J0b2tlbjpmdW5jdGlvbihyKXtyZXR1cm4gZnVuY3Rpb24ocyl7dmFyIG14PXMubWF0Y2gocik7aWYobXgpe3JldHVybihbbXhbMF0scy5zdWJzdHJpbmcobXhbMF0ubGVuZ3RoKV0pO31lbHNle3Rocm93IG5ldyAkUC5FeGNlcHRpb24ocyk7fX07fSx0b2tlbjpmdW5jdGlvbihzKXtyZXR1cm4gZnVuY3Rpb24ocyl7cmV0dXJuIF8ucnRva2VuKG5ldyBSZWdFeHAoXCJeXFxzKlwiK3MrXCJcXHMqXCIpKShzKTt9O30sc3Rva2VuOmZ1bmN0aW9uKHMpe3JldHVybiBfLnJ0b2tlbihuZXcgUmVnRXhwKFwiXlwiK3MpKTt9LHVudGlsOmZ1bmN0aW9uKHApe3JldHVybiBmdW5jdGlvbihzKXt2YXIgcXg9W10scng9bnVsbDt3aGlsZShzLmxlbmd0aCl7dHJ5e3J4PXAuY2FsbCh0aGlzLHMpO31jYXRjaChlKXtxeC5wdXNoKHJ4WzBdKTtzPXJ4WzFdO2NvbnRpbnVlO31cbmJyZWFrO31cbnJldHVybltxeCxzXTt9O30sbWFueTpmdW5jdGlvbihwKXtyZXR1cm4gZnVuY3Rpb24ocyl7dmFyIHJ4PVtdLHI9bnVsbDt3aGlsZShzLmxlbmd0aCl7dHJ5e3I9cC5jYWxsKHRoaXMscyk7fWNhdGNoKGUpe3JldHVybltyeCxzXTt9XG5yeC5wdXNoKHJbMF0pO3M9clsxXTt9XG5yZXR1cm5bcngsc107fTt9LG9wdGlvbmFsOmZ1bmN0aW9uKHApe3JldHVybiBmdW5jdGlvbihzKXt2YXIgcj1udWxsO3RyeXtyPXAuY2FsbCh0aGlzLHMpO31jYXRjaChlKXtyZXR1cm5bbnVsbCxzXTt9XG5yZXR1cm5bclswXSxyWzFdXTt9O30sbm90OmZ1bmN0aW9uKHApe3JldHVybiBmdW5jdGlvbihzKXt0cnl7cC5jYWxsKHRoaXMscyk7fWNhdGNoKGUpe3JldHVybltudWxsLHNdO31cbnRocm93IG5ldyAkUC5FeGNlcHRpb24ocyk7fTt9LGlnbm9yZTpmdW5jdGlvbihwKXtyZXR1cm4gcD9mdW5jdGlvbihzKXt2YXIgcj1udWxsO3I9cC5jYWxsKHRoaXMscyk7cmV0dXJuW251bGwsclsxXV07fTpudWxsO30scHJvZHVjdDpmdW5jdGlvbigpe3ZhciBweD1hcmd1bWVudHNbMF0scXg9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLDEpLHJ4PVtdO2Zvcih2YXIgaT0wO2k8cHgubGVuZ3RoO2krKyl7cngucHVzaChfLmVhY2gocHhbaV0scXgpKTt9XG5yZXR1cm4gcng7fSxjYWNoZTpmdW5jdGlvbihydWxlKXt2YXIgY2FjaGU9e30scj1udWxsO3JldHVybiBmdW5jdGlvbihzKXt0cnl7cj1jYWNoZVtzXT0oY2FjaGVbc118fHJ1bGUuY2FsbCh0aGlzLHMpKTt9Y2F0Y2goZSl7cj1jYWNoZVtzXT1lO31cbmlmKHIgaW5zdGFuY2VvZiAkUC5FeGNlcHRpb24pe3Rocm93IHI7fWVsc2V7cmV0dXJuIHI7fX07fSxhbnk6ZnVuY3Rpb24oKXt2YXIgcHg9YXJndW1lbnRzO3JldHVybiBmdW5jdGlvbihzKXt2YXIgcj1udWxsO2Zvcih2YXIgaT0wO2k8cHgubGVuZ3RoO2krKyl7aWYocHhbaV09PW51bGwpe2NvbnRpbnVlO31cbnRyeXtyPShweFtpXS5jYWxsKHRoaXMscykpO31jYXRjaChlKXtyPW51bGw7fVxuaWYocil7cmV0dXJuIHI7fX1cbnRocm93IG5ldyAkUC5FeGNlcHRpb24ocyk7fTt9LGVhY2g6ZnVuY3Rpb24oKXt2YXIgcHg9YXJndW1lbnRzO3JldHVybiBmdW5jdGlvbihzKXt2YXIgcng9W10scj1udWxsO2Zvcih2YXIgaT0wO2k8cHgubGVuZ3RoO2krKyl7aWYocHhbaV09PW51bGwpe2NvbnRpbnVlO31cbnRyeXtyPShweFtpXS5jYWxsKHRoaXMscykpO31jYXRjaChlKXt0aHJvdyBuZXcgJFAuRXhjZXB0aW9uKHMpO31cbnJ4LnB1c2goclswXSk7cz1yWzFdO31cbnJldHVybltyeCxzXTt9O30sYWxsOmZ1bmN0aW9uKCl7dmFyIHB4PWFyZ3VtZW50cyxfPV87cmV0dXJuIF8uZWFjaChfLm9wdGlvbmFsKHB4KSk7fSxzZXF1ZW5jZTpmdW5jdGlvbihweCxkLGMpe2Q9ZHx8Xy5ydG9rZW4oL15cXHMqLyk7Yz1jfHxudWxsO2lmKHB4Lmxlbmd0aD09MSl7cmV0dXJuIHB4WzBdO31cbnJldHVybiBmdW5jdGlvbihzKXt2YXIgcj1udWxsLHE9bnVsbDt2YXIgcng9W107Zm9yKHZhciBpPTA7aTxweC5sZW5ndGg7aSsrKXt0cnl7cj1weFtpXS5jYWxsKHRoaXMscyk7fWNhdGNoKGUpe2JyZWFrO31cbnJ4LnB1c2goclswXSk7dHJ5e3E9ZC5jYWxsKHRoaXMsclsxXSk7fWNhdGNoKGV4KXtxPW51bGw7YnJlYWs7fVxucz1xWzFdO31cbmlmKCFyKXt0aHJvdyBuZXcgJFAuRXhjZXB0aW9uKHMpO31cbmlmKHEpe3Rocm93IG5ldyAkUC5FeGNlcHRpb24ocVsxXSk7fVxuaWYoYyl7dHJ5e3I9Yy5jYWxsKHRoaXMsclsxXSk7fWNhdGNoKGV5KXt0aHJvdyBuZXcgJFAuRXhjZXB0aW9uKHJbMV0pO319XG5yZXR1cm5bcngsKHI/clsxXTpzKV07fTt9LGJldHdlZW46ZnVuY3Rpb24oZDEscCxkMil7ZDI9ZDJ8fGQxO3ZhciBfZm49Xy5lYWNoKF8uaWdub3JlKGQxKSxwLF8uaWdub3JlKGQyKSk7cmV0dXJuIGZ1bmN0aW9uKHMpe3ZhciByeD1fZm4uY2FsbCh0aGlzLHMpO3JldHVybltbcnhbMF1bMF0sclswXVsyXV0scnhbMV1dO307fSxsaXN0OmZ1bmN0aW9uKHAsZCxjKXtkPWR8fF8ucnRva2VuKC9eXFxzKi8pO2M9Y3x8bnVsbDtyZXR1cm4ocCBpbnN0YW5jZW9mIEFycmF5P18uZWFjaChfLnByb2R1Y3QocC5zbGljZSgwLC0xKSxfLmlnbm9yZShkKSkscC5zbGljZSgtMSksXy5pZ25vcmUoYykpOl8uZWFjaChfLm1hbnkoXy5lYWNoKHAsXy5pZ25vcmUoZCkpKSxweCxfLmlnbm9yZShjKSkpO30sc2V0OmZ1bmN0aW9uKHB4LGQsYyl7ZD1kfHxfLnJ0b2tlbigvXlxccyovKTtjPWN8fG51bGw7cmV0dXJuIGZ1bmN0aW9uKHMpe3ZhciByPW51bGwscD1udWxsLHE9bnVsbCxyeD1udWxsLGJlc3Q9W1tdLHNdLGxhc3Q9ZmFsc2U7Zm9yKHZhciBpPTA7aTxweC5sZW5ndGg7aSsrKXtxPW51bGw7cD1udWxsO3I9bnVsbDtsYXN0PShweC5sZW5ndGg9PTEpO3RyeXtyPXB4W2ldLmNhbGwodGhpcyxzKTt9Y2F0Y2goZSl7Y29udGludWU7fVxucng9W1tyWzBdXSxyWzFdXTtpZihyWzFdLmxlbmd0aD4wJiYhbGFzdCl7dHJ5e3E9ZC5jYWxsKHRoaXMsclsxXSk7fWNhdGNoKGV4KXtsYXN0PXRydWU7fX1lbHNle2xhc3Q9dHJ1ZTt9XG5pZighbGFzdCYmcVsxXS5sZW5ndGg9PT0wKXtsYXN0PXRydWU7fVxuaWYoIWxhc3Qpe3ZhciBxeD1bXTtmb3IodmFyIGo9MDtqPHB4Lmxlbmd0aDtqKyspe2lmKGkhPWope3F4LnB1c2gocHhbal0pO319XG5wPV8uc2V0KHF4LGQpLmNhbGwodGhpcyxxWzFdKTtpZihwWzBdLmxlbmd0aD4wKXtyeFswXT1yeFswXS5jb25jYXQocFswXSk7cnhbMV09cFsxXTt9fVxuaWYocnhbMV0ubGVuZ3RoPGJlc3RbMV0ubGVuZ3RoKXtiZXN0PXJ4O31cbmlmKGJlc3RbMV0ubGVuZ3RoPT09MCl7YnJlYWs7fX1cbmlmKGJlc3RbMF0ubGVuZ3RoPT09MCl7cmV0dXJuIGJlc3Q7fVxuaWYoYyl7dHJ5e3E9Yy5jYWxsKHRoaXMsYmVzdFsxXSk7fWNhdGNoKGV5KXt0aHJvdyBuZXcgJFAuRXhjZXB0aW9uKGJlc3RbMV0pO31cbmJlc3RbMV09cVsxXTt9XG5yZXR1cm4gYmVzdDt9O30sZm9yd2FyZDpmdW5jdGlvbihncixmbmFtZSl7cmV0dXJuIGZ1bmN0aW9uKHMpe3JldHVybiBncltmbmFtZV0uY2FsbCh0aGlzLHMpO307fSxyZXBsYWNlOmZ1bmN0aW9uKHJ1bGUscmVwbCl7cmV0dXJuIGZ1bmN0aW9uKHMpe3ZhciByPXJ1bGUuY2FsbCh0aGlzLHMpO3JldHVybltyZXBsLHJbMV1dO307fSxwcm9jZXNzOmZ1bmN0aW9uKHJ1bGUsZm4pe3JldHVybiBmdW5jdGlvbihzKXt2YXIgcj1ydWxlLmNhbGwodGhpcyxzKTtyZXR1cm5bZm4uY2FsbCh0aGlzLHJbMF0pLHJbMV1dO307fSxtaW46ZnVuY3Rpb24obWluLHJ1bGUpe3JldHVybiBmdW5jdGlvbihzKXt2YXIgcng9cnVsZS5jYWxsKHRoaXMscyk7aWYocnhbMF0ubGVuZ3RoPG1pbil7dGhyb3cgbmV3ICRQLkV4Y2VwdGlvbihzKTt9XG5yZXR1cm4gcng7fTt9fTt2YXIgX2dlbmVyYXRvcj1mdW5jdGlvbihvcCl7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIGFyZ3M9bnVsbCxyeD1bXTtpZihhcmd1bWVudHMubGVuZ3RoPjEpe2FyZ3M9QXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzKTt9ZWxzZSBpZihhcmd1bWVudHNbMF1pbnN0YW5jZW9mIEFycmF5KXthcmdzPWFyZ3VtZW50c1swXTt9XG5pZihhcmdzKXtmb3IodmFyIGk9MCxweD1hcmdzLnNoaWZ0KCk7aTxweC5sZW5ndGg7aSsrKXthcmdzLnVuc2hpZnQocHhbaV0pO3J4LnB1c2gob3AuYXBwbHkobnVsbCxhcmdzKSk7YXJncy5zaGlmdCgpO3JldHVybiByeDt9fWVsc2V7cmV0dXJuIG9wLmFwcGx5KG51bGwsYXJndW1lbnRzKTt9fTt9O3ZhciBneD1cIm9wdGlvbmFsIG5vdCBpZ25vcmUgY2FjaGVcIi5zcGxpdCgvXFxzLyk7Zm9yKHZhciBpPTA7aTxneC5sZW5ndGg7aSsrKXtfW2d4W2ldXT1fZ2VuZXJhdG9yKF9bZ3hbaV1dKTt9XG52YXIgX3ZlY3Rvcj1mdW5jdGlvbihvcCl7cmV0dXJuIGZ1bmN0aW9uKCl7aWYoYXJndW1lbnRzWzBdaW5zdGFuY2VvZiBBcnJheSl7cmV0dXJuIG9wLmFwcGx5KG51bGwsYXJndW1lbnRzWzBdKTt9ZWxzZXtyZXR1cm4gb3AuYXBwbHkobnVsbCxhcmd1bWVudHMpO319O307dmFyIHZ4PVwiZWFjaCBhbnkgYWxsXCIuc3BsaXQoL1xccy8pO2Zvcih2YXIgaj0wO2o8dngubGVuZ3RoO2orKyl7X1t2eFtqXV09X3ZlY3RvcihfW3Z4W2pdXSk7fX0oKSk7KGZ1bmN0aW9uKCl7dmFyICREPURhdGUsJFA9JEQucHJvdG90eXBlLCRDPSRELkN1bHR1cmVJbmZvO3ZhciBmbGF0dGVuQW5kQ29tcGFjdD1mdW5jdGlvbihheCl7dmFyIHJ4PVtdO2Zvcih2YXIgaT0wO2k8YXgubGVuZ3RoO2krKyl7aWYoYXhbaV1pbnN0YW5jZW9mIEFycmF5KXtyeD1yeC5jb25jYXQoZmxhdHRlbkFuZENvbXBhY3QoYXhbaV0pKTt9ZWxzZXtpZihheFtpXSl7cngucHVzaChheFtpXSk7fX19XG5yZXR1cm4gcng7fTskRC5HcmFtbWFyPXt9OyRELlRyYW5zbGF0b3I9e2hvdXI6ZnVuY3Rpb24ocyl7cmV0dXJuIGZ1bmN0aW9uKCl7dGhpcy5ob3VyPU51bWJlcihzKTt9O30sbWludXRlOmZ1bmN0aW9uKHMpe3JldHVybiBmdW5jdGlvbigpe3RoaXMubWludXRlPU51bWJlcihzKTt9O30sc2Vjb25kOmZ1bmN0aW9uKHMpe3JldHVybiBmdW5jdGlvbigpe3RoaXMuc2Vjb25kPU51bWJlcihzKTt9O30sbWVyaWRpYW46ZnVuY3Rpb24ocyl7cmV0dXJuIGZ1bmN0aW9uKCl7dGhpcy5tZXJpZGlhbj1zLnNsaWNlKDAsMSkudG9Mb3dlckNhc2UoKTt9O30sdGltZXpvbmU6ZnVuY3Rpb24ocyl7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIG49cy5yZXBsYWNlKC9bXlxcZFxcK1xcLV0vZyxcIlwiKTtpZihuLmxlbmd0aCl7dGhpcy50aW1lem9uZU9mZnNldD1OdW1iZXIobik7fWVsc2V7dGhpcy50aW1lem9uZT1zLnRvTG93ZXJDYXNlKCk7fX07fSxkYXk6ZnVuY3Rpb24oeCl7dmFyIHM9eFswXTtyZXR1cm4gZnVuY3Rpb24oKXt0aGlzLmRheT1OdW1iZXIocy5tYXRjaCgvXFxkKy8pWzBdKTt9O30sbW9udGg6ZnVuY3Rpb24ocyl7cmV0dXJuIGZ1bmN0aW9uKCl7dGhpcy5tb250aD0ocy5sZW5ndGg9PTMpP1wiamFuIGZlYiBtYXIgYXByIG1heSBqdW4ganVsIGF1ZyBzZXAgb2N0IG5vdiBkZWNcIi5pbmRleE9mKHMpLzQ6TnVtYmVyKHMpLTE7fTt9LHllYXI6ZnVuY3Rpb24ocyl7cmV0dXJuIGZ1bmN0aW9uKCl7dmFyIG49TnVtYmVyKHMpO3RoaXMueWVhcj0oKHMubGVuZ3RoPjIpP246KG4rKCgobisyMDAwKTwkQy50d29EaWdpdFllYXJNYXgpPzIwMDA6MTkwMCkpKTt9O30scmRheTpmdW5jdGlvbihzKXtyZXR1cm4gZnVuY3Rpb24oKXtzd2l0Y2gocyl7Y2FzZVwieWVzdGVyZGF5XCI6dGhpcy5kYXlzPS0xO2JyZWFrO2Nhc2VcInRvbW9ycm93XCI6dGhpcy5kYXlzPTE7YnJlYWs7Y2FzZVwidG9kYXlcIjp0aGlzLmRheXM9MDticmVhaztjYXNlXCJub3dcIjp0aGlzLmRheXM9MDt0aGlzLm5vdz10cnVlO2JyZWFrO319O30sZmluaXNoRXhhY3Q6ZnVuY3Rpb24oeCl7eD0oeCBpbnN0YW5jZW9mIEFycmF5KT94Olt4XTtmb3IodmFyIGk9MDtpPHgubGVuZ3RoO2krKyl7aWYoeFtpXSl7eFtpXS5jYWxsKHRoaXMpO319XG52YXIgbm93PW5ldyBEYXRlKCk7aWYoKHRoaXMuaG91cnx8dGhpcy5taW51dGUpJiYoIXRoaXMubW9udGgmJiF0aGlzLnllYXImJiF0aGlzLmRheSkpe3RoaXMuZGF5PW5vdy5nZXREYXRlKCk7fVxuaWYoIXRoaXMueWVhcil7dGhpcy55ZWFyPW5vdy5nZXRGdWxsWWVhcigpO31cbmlmKCF0aGlzLm1vbnRoJiZ0aGlzLm1vbnRoIT09MCl7dGhpcy5tb250aD1ub3cuZ2V0TW9udGgoKTt9XG5pZighdGhpcy5kYXkpe3RoaXMuZGF5PTE7fVxuaWYoIXRoaXMuaG91cil7dGhpcy5ob3VyPTA7fVxuaWYoIXRoaXMubWludXRlKXt0aGlzLm1pbnV0ZT0wO31cbmlmKCF0aGlzLnNlY29uZCl7dGhpcy5zZWNvbmQ9MDt9XG5pZih0aGlzLm1lcmlkaWFuJiZ0aGlzLmhvdXIpe2lmKHRoaXMubWVyaWRpYW49PVwicFwiJiZ0aGlzLmhvdXI8MTIpe3RoaXMuaG91cj10aGlzLmhvdXIrMTI7fWVsc2UgaWYodGhpcy5tZXJpZGlhbj09XCJhXCImJnRoaXMuaG91cj09MTIpe3RoaXMuaG91cj0wO319XG5pZih0aGlzLmRheT4kRC5nZXREYXlzSW5Nb250aCh0aGlzLnllYXIsdGhpcy5tb250aCkpe3Rocm93IG5ldyBSYW5nZUVycm9yKHRoaXMuZGF5K1wiIGlzIG5vdCBhIHZhbGlkIHZhbHVlIGZvciBkYXlzLlwiKTt9XG52YXIgcj1uZXcgRGF0ZSh0aGlzLnllYXIsdGhpcy5tb250aCx0aGlzLmRheSx0aGlzLmhvdXIsdGhpcy5taW51dGUsdGhpcy5zZWNvbmQpO2lmKHRoaXMudGltZXpvbmUpe3Iuc2V0KHt0aW1lem9uZTp0aGlzLnRpbWV6b25lfSk7fWVsc2UgaWYodGhpcy50aW1lem9uZU9mZnNldCl7ci5zZXQoe3RpbWV6b25lT2Zmc2V0OnRoaXMudGltZXpvbmVPZmZzZXR9KTt9XG5yZXR1cm4gcjt9LGZpbmlzaDpmdW5jdGlvbih4KXt4PSh4IGluc3RhbmNlb2YgQXJyYXkpP2ZsYXR0ZW5BbmRDb21wYWN0KHgpOlt4XTtpZih4Lmxlbmd0aD09PTApe3JldHVybiBudWxsO31cbmZvcih2YXIgaT0wO2k8eC5sZW5ndGg7aSsrKXtpZih0eXBlb2YgeFtpXT09XCJmdW5jdGlvblwiKXt4W2ldLmNhbGwodGhpcyk7fX1cbnZhciB0b2RheT0kRC50b2RheSgpO2lmKHRoaXMubm93JiYhdGhpcy51bml0JiYhdGhpcy5vcGVyYXRvcil7cmV0dXJuIG5ldyBEYXRlKCk7fWVsc2UgaWYodGhpcy5ub3cpe3RvZGF5PW5ldyBEYXRlKCk7fVxudmFyIGV4cHJlc3Npb249ISEodGhpcy5kYXlzJiZ0aGlzLmRheXMhPT1udWxsfHx0aGlzLm9yaWVudHx8dGhpcy5vcGVyYXRvcik7dmFyIGdhcCxtb2Qsb3JpZW50O29yaWVudD0oKHRoaXMub3JpZW50PT1cInBhc3RcInx8dGhpcy5vcGVyYXRvcj09XCJzdWJ0cmFjdFwiKT8tMToxKTtpZighdGhpcy5ub3cmJlwiaG91ciBtaW51dGUgc2Vjb25kXCIuaW5kZXhPZih0aGlzLnVuaXQpIT0tMSl7dG9kYXkuc2V0VGltZVRvTm93KCk7fVxuaWYodGhpcy5tb250aHx8dGhpcy5tb250aD09PTApe2lmKFwieWVhciBkYXkgaG91ciBtaW51dGUgc2Vjb25kXCIuaW5kZXhPZih0aGlzLnVuaXQpIT0tMSl7dGhpcy52YWx1ZT10aGlzLm1vbnRoKzE7dGhpcy5tb250aD1udWxsO2V4cHJlc3Npb249dHJ1ZTt9fVxuaWYoIWV4cHJlc3Npb24mJnRoaXMud2Vla2RheSYmIXRoaXMuZGF5JiYhdGhpcy5kYXlzKXt2YXIgdGVtcD1EYXRlW3RoaXMud2Vla2RheV0oKTt0aGlzLmRheT10ZW1wLmdldERhdGUoKTtpZighdGhpcy5tb250aCl7dGhpcy5tb250aD10ZW1wLmdldE1vbnRoKCk7fVxudGhpcy55ZWFyPXRlbXAuZ2V0RnVsbFllYXIoKTt9XG5pZihleHByZXNzaW9uJiZ0aGlzLndlZWtkYXkmJnRoaXMudW5pdCE9XCJtb250aFwiKXt0aGlzLnVuaXQ9XCJkYXlcIjtnYXA9KCRELmdldERheU51bWJlckZyb21OYW1lKHRoaXMud2Vla2RheSktdG9kYXkuZ2V0RGF5KCkpO21vZD03O3RoaXMuZGF5cz1nYXA/KChnYXArKG9yaWVudCptb2QpKSVtb2QpOihvcmllbnQqbW9kKTt9XG5pZih0aGlzLm1vbnRoJiZ0aGlzLnVuaXQ9PVwiZGF5XCImJnRoaXMub3BlcmF0b3Ipe3RoaXMudmFsdWU9KHRoaXMubW9udGgrMSk7dGhpcy5tb250aD1udWxsO31cbmlmKHRoaXMudmFsdWUhPW51bGwmJnRoaXMubW9udGghPW51bGwmJnRoaXMueWVhciE9bnVsbCl7dGhpcy5kYXk9dGhpcy52YWx1ZSoxO31cbmlmKHRoaXMubW9udGgmJiF0aGlzLmRheSYmdGhpcy52YWx1ZSl7dG9kYXkuc2V0KHtkYXk6dGhpcy52YWx1ZSoxfSk7aWYoIWV4cHJlc3Npb24pe3RoaXMuZGF5PXRoaXMudmFsdWUqMTt9fVxuaWYoIXRoaXMubW9udGgmJnRoaXMudmFsdWUmJnRoaXMudW5pdD09XCJtb250aFwiJiYhdGhpcy5ub3cpe3RoaXMubW9udGg9dGhpcy52YWx1ZTtleHByZXNzaW9uPXRydWU7fVxuaWYoZXhwcmVzc2lvbiYmKHRoaXMubW9udGh8fHRoaXMubW9udGg9PT0wKSYmdGhpcy51bml0IT1cInllYXJcIil7dGhpcy51bml0PVwibW9udGhcIjtnYXA9KHRoaXMubW9udGgtdG9kYXkuZ2V0TW9udGgoKSk7bW9kPTEyO3RoaXMubW9udGhzPWdhcD8oKGdhcCsob3JpZW50Km1vZCkpJW1vZCk6KG9yaWVudCptb2QpO3RoaXMubW9udGg9bnVsbDt9XG5pZighdGhpcy51bml0KXt0aGlzLnVuaXQ9XCJkYXlcIjt9XG5pZighdGhpcy52YWx1ZSYmdGhpcy5vcGVyYXRvciYmdGhpcy5vcGVyYXRvciE9PW51bGwmJnRoaXNbdGhpcy51bml0K1wic1wiXSYmdGhpc1t0aGlzLnVuaXQrXCJzXCJdIT09bnVsbCl7dGhpc1t0aGlzLnVuaXQrXCJzXCJdPXRoaXNbdGhpcy51bml0K1wic1wiXSsoKHRoaXMub3BlcmF0b3I9PVwiYWRkXCIpPzE6LTEpKyh0aGlzLnZhbHVlfHwwKSpvcmllbnQ7fWVsc2UgaWYodGhpc1t0aGlzLnVuaXQrXCJzXCJdPT1udWxsfHx0aGlzLm9wZXJhdG9yIT1udWxsKXtpZighdGhpcy52YWx1ZSl7dGhpcy52YWx1ZT0xO31cbnRoaXNbdGhpcy51bml0K1wic1wiXT10aGlzLnZhbHVlKm9yaWVudDt9XG5pZih0aGlzLm1lcmlkaWFuJiZ0aGlzLmhvdXIpe2lmKHRoaXMubWVyaWRpYW49PVwicFwiJiZ0aGlzLmhvdXI8MTIpe3RoaXMuaG91cj10aGlzLmhvdXIrMTI7fWVsc2UgaWYodGhpcy5tZXJpZGlhbj09XCJhXCImJnRoaXMuaG91cj09MTIpe3RoaXMuaG91cj0wO319XG5pZih0aGlzLndlZWtkYXkmJiF0aGlzLmRheSYmIXRoaXMuZGF5cyl7dmFyIHRlbXA9RGF0ZVt0aGlzLndlZWtkYXldKCk7dGhpcy5kYXk9dGVtcC5nZXREYXRlKCk7aWYodGVtcC5nZXRNb250aCgpIT09dG9kYXkuZ2V0TW9udGgoKSl7dGhpcy5tb250aD10ZW1wLmdldE1vbnRoKCk7fX1cbmlmKCh0aGlzLm1vbnRofHx0aGlzLm1vbnRoPT09MCkmJiF0aGlzLmRheSl7dGhpcy5kYXk9MTt9XG5pZighdGhpcy5vcmllbnQmJiF0aGlzLm9wZXJhdG9yJiZ0aGlzLnVuaXQ9PVwid2Vla1wiJiZ0aGlzLnZhbHVlJiYhdGhpcy5kYXkmJiF0aGlzLm1vbnRoKXtyZXR1cm4gRGF0ZS50b2RheSgpLnNldFdlZWsodGhpcy52YWx1ZSk7fVxuaWYoZXhwcmVzc2lvbiYmdGhpcy50aW1lem9uZSYmdGhpcy5kYXkmJnRoaXMuZGF5cyl7dGhpcy5kYXk9dGhpcy5kYXlzO31cbnJldHVybihleHByZXNzaW9uKT90b2RheS5hZGQodGhpcyk6dG9kYXkuc2V0KHRoaXMpO319O3ZhciBfPSRELlBhcnNpbmcuT3BlcmF0b3JzLGc9JEQuR3JhbW1hcix0PSRELlRyYW5zbGF0b3IsX2ZuO2cuZGF0ZVBhcnREZWxpbWl0ZXI9Xy5ydG9rZW4oL14oW1xcc1xcLVxcLlxcLFxcL1xceDI3XSspLyk7Zy50aW1lUGFydERlbGltaXRlcj1fLnN0b2tlbihcIjpcIik7Zy53aGl0ZVNwYWNlPV8ucnRva2VuKC9eXFxzKi8pO2cuZ2VuZXJhbERlbGltaXRlcj1fLnJ0b2tlbigvXigoW1xcc1xcLF18YXR8QHxvbikrKS8pO3ZhciBfQz17fTtnLmN0b2tlbj1mdW5jdGlvbihrZXlzKXt2YXIgZm49X0Nba2V5c107aWYoIWZuKXt2YXIgYz0kQy5yZWdleFBhdHRlcm5zO3ZhciBreD1rZXlzLnNwbGl0KC9cXHMrLykscHg9W107Zm9yKHZhciBpPTA7aTxreC5sZW5ndGg7aSsrKXtweC5wdXNoKF8ucmVwbGFjZShfLnJ0b2tlbihjW2t4W2ldXSksa3hbaV0pKTt9XG5mbj1fQ1trZXlzXT1fLmFueS5hcHBseShudWxsLHB4KTt9XG5yZXR1cm4gZm47fTtnLmN0b2tlbjI9ZnVuY3Rpb24oa2V5KXtyZXR1cm4gXy5ydG9rZW4oJEMucmVnZXhQYXR0ZXJuc1trZXldKTt9O2cuaD1fLmNhY2hlKF8ucHJvY2VzcyhfLnJ0b2tlbigvXigwWzAtOV18MVswLTJdfFsxLTldKS8pLHQuaG91cikpO2cuaGg9Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL14oMFswLTldfDFbMC0yXSkvKSx0LmhvdXIpKTtnLkg9Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL14oWzAtMV1bMC05XXwyWzAtM118WzAtOV0pLyksdC5ob3VyKSk7Zy5ISD1fLmNhY2hlKF8ucHJvY2VzcyhfLnJ0b2tlbigvXihbMC0xXVswLTldfDJbMC0zXSkvKSx0LmhvdXIpKTtnLm09Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL14oWzAtNV1bMC05XXxbMC05XSkvKSx0Lm1pbnV0ZSkpO2cubW09Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL15bMC01XVswLTldLyksdC5taW51dGUpKTtnLnM9Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL14oWzAtNV1bMC05XXxbMC05XSkvKSx0LnNlY29uZCkpO2cuc3M9Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL15bMC01XVswLTldLyksdC5zZWNvbmQpKTtnLmhtcz1fLmNhY2hlKF8uc2VxdWVuY2UoW2cuSCxnLm0sZy5zXSxnLnRpbWVQYXJ0RGVsaW1pdGVyKSk7Zy50PV8uY2FjaGUoXy5wcm9jZXNzKGcuY3Rva2VuMihcInNob3J0TWVyaWRpYW5cIiksdC5tZXJpZGlhbikpO2cudHQ9Xy5jYWNoZShfLnByb2Nlc3MoZy5jdG9rZW4yKFwibG9uZ01lcmlkaWFuXCIpLHQubWVyaWRpYW4pKTtnLno9Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL14oKFxcK3xcXC0pXFxzKlxcZFxcZFxcZFxcZCl8KChcXCt8XFwtKVxcZFxcZFxcOj9cXGRcXGQpLyksdC50aW1lem9uZSkpO2cueno9Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL14oKFxcK3xcXC0pXFxzKlxcZFxcZFxcZFxcZCl8KChcXCt8XFwtKVxcZFxcZFxcOj9cXGRcXGQpLyksdC50aW1lem9uZSkpO2cuenp6PV8uY2FjaGUoXy5wcm9jZXNzKGcuY3Rva2VuMihcInRpbWV6b25lXCIpLHQudGltZXpvbmUpKTtnLnRpbWVTdWZmaXg9Xy5lYWNoKF8uaWdub3JlKGcud2hpdGVTcGFjZSksXy5zZXQoW2cudHQsZy56enpdKSk7Zy50aW1lPV8uZWFjaChfLm9wdGlvbmFsKF8uaWdub3JlKF8uc3Rva2VuKFwiVFwiKSkpLGcuaG1zLGcudGltZVN1ZmZpeCk7Zy5kPV8uY2FjaGUoXy5wcm9jZXNzKF8uZWFjaChfLnJ0b2tlbigvXihbMC0yXVxcZHwzWzAtMV18XFxkKS8pLF8ub3B0aW9uYWwoZy5jdG9rZW4yKFwib3JkaW5hbFN1ZmZpeFwiKSkpLHQuZGF5KSk7Zy5kZD1fLmNhY2hlKF8ucHJvY2VzcyhfLmVhY2goXy5ydG9rZW4oL14oWzAtMl1cXGR8M1swLTFdKS8pLF8ub3B0aW9uYWwoZy5jdG9rZW4yKFwib3JkaW5hbFN1ZmZpeFwiKSkpLHQuZGF5KSk7Zy5kZGQ9Zy5kZGRkPV8uY2FjaGUoXy5wcm9jZXNzKGcuY3Rva2VuKFwic3VuIG1vbiB0dWUgd2VkIHRodSBmcmkgc2F0XCIpLGZ1bmN0aW9uKHMpe3JldHVybiBmdW5jdGlvbigpe3RoaXMud2Vla2RheT1zO307fSkpO2cuTT1fLmNhY2hlKF8ucHJvY2VzcyhfLnJ0b2tlbigvXigxWzAtMl18MFxcZHxcXGQpLyksdC5tb250aCkpO2cuTU09Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL14oMVswLTJdfDBcXGQpLyksdC5tb250aCkpO2cuTU1NPWcuTU1NTT1fLmNhY2hlKF8ucHJvY2VzcyhnLmN0b2tlbihcImphbiBmZWIgbWFyIGFwciBtYXkganVuIGp1bCBhdWcgc2VwIG9jdCBub3YgZGVjXCIpLHQubW9udGgpKTtnLnk9Xy5jYWNoZShfLnByb2Nlc3MoXy5ydG9rZW4oL14oXFxkXFxkPykvKSx0LnllYXIpKTtnLnl5PV8uY2FjaGUoXy5wcm9jZXNzKF8ucnRva2VuKC9eKFxcZFxcZCkvKSx0LnllYXIpKTtnLnl5eT1fLmNhY2hlKF8ucHJvY2VzcyhfLnJ0b2tlbigvXihcXGRcXGQ/XFxkP1xcZD8pLyksdC55ZWFyKSk7Zy55eXl5PV8uY2FjaGUoXy5wcm9jZXNzKF8ucnRva2VuKC9eKFxcZFxcZFxcZFxcZCkvKSx0LnllYXIpKTtfZm49ZnVuY3Rpb24oKXtyZXR1cm4gXy5lYWNoKF8uYW55LmFwcGx5KG51bGwsYXJndW1lbnRzKSxfLm5vdChnLmN0b2tlbjIoXCJ0aW1lQ29udGV4dFwiKSkpO307Zy5kYXk9X2ZuKGcuZCxnLmRkKTtnLm1vbnRoPV9mbihnLk0sZy5NTU0pO2cueWVhcj1fZm4oZy55eXl5LGcueXkpO2cub3JpZW50YXRpb249Xy5wcm9jZXNzKGcuY3Rva2VuKFwicGFzdCBmdXR1cmVcIiksZnVuY3Rpb24ocyl7cmV0dXJuIGZ1bmN0aW9uKCl7dGhpcy5vcmllbnQ9czt9O30pO2cub3BlcmF0b3I9Xy5wcm9jZXNzKGcuY3Rva2VuKFwiYWRkIHN1YnRyYWN0XCIpLGZ1bmN0aW9uKHMpe3JldHVybiBmdW5jdGlvbigpe3RoaXMub3BlcmF0b3I9czt9O30pO2cucmRheT1fLnByb2Nlc3MoZy5jdG9rZW4oXCJ5ZXN0ZXJkYXkgdG9tb3Jyb3cgdG9kYXkgbm93XCIpLHQucmRheSk7Zy51bml0PV8ucHJvY2VzcyhnLmN0b2tlbihcInNlY29uZCBtaW51dGUgaG91ciBkYXkgd2VlayBtb250aCB5ZWFyXCIpLGZ1bmN0aW9uKHMpe3JldHVybiBmdW5jdGlvbigpe3RoaXMudW5pdD1zO307fSk7Zy52YWx1ZT1fLnByb2Nlc3MoXy5ydG9rZW4oL15cXGRcXGQ/KHN0fG5kfHJkfHRoKT8vKSxmdW5jdGlvbihzKXtyZXR1cm4gZnVuY3Rpb24oKXt0aGlzLnZhbHVlPXMucmVwbGFjZSgvXFxEL2csXCJcIik7fTt9KTtnLmV4cHJlc3Npb249Xy5zZXQoW2cucmRheSxnLm9wZXJhdG9yLGcudmFsdWUsZy51bml0LGcub3JpZW50YXRpb24sZy5kZGQsZy5NTU1dKTtfZm49ZnVuY3Rpb24oKXtyZXR1cm4gXy5zZXQoYXJndW1lbnRzLGcuZGF0ZVBhcnREZWxpbWl0ZXIpO307Zy5tZHk9X2ZuKGcuZGRkLGcubW9udGgsZy5kYXksZy55ZWFyKTtnLnltZD1fZm4oZy5kZGQsZy55ZWFyLGcubW9udGgsZy5kYXkpO2cuZG15PV9mbihnLmRkZCxnLmRheSxnLm1vbnRoLGcueWVhcik7Zy5kYXRlPWZ1bmN0aW9uKHMpe3JldHVybigoZ1skQy5kYXRlRWxlbWVudE9yZGVyXXx8Zy5tZHkpLmNhbGwodGhpcyxzKSk7fTtnLmZvcm1hdD1fLnByb2Nlc3MoXy5tYW55KF8uYW55KF8ucHJvY2VzcyhfLnJ0b2tlbigvXihkZD9kP2Q/fE1NP00/TT98eXk/eT95P3xoaD98SEg/fG1tP3xzcz98dHQ/fHp6P3o/KS8pLGZ1bmN0aW9uKGZtdCl7aWYoZ1tmbXRdKXtyZXR1cm4gZ1tmbXRdO31lbHNle3Rocm93ICRELlBhcnNpbmcuRXhjZXB0aW9uKGZtdCk7fX0pLF8ucHJvY2VzcyhfLnJ0b2tlbigvXlteZE15aEhtc3R6XSsvKSxmdW5jdGlvbihzKXtyZXR1cm4gXy5pZ25vcmUoXy5zdG9rZW4ocykpO30pKSksZnVuY3Rpb24ocnVsZXMpe3JldHVybiBfLnByb2Nlc3MoXy5lYWNoLmFwcGx5KG51bGwscnVsZXMpLHQuZmluaXNoRXhhY3QpO30pO3ZhciBfRj17fTt2YXIgX2dldD1mdW5jdGlvbihmKXtyZXR1cm4gX0ZbZl09KF9GW2ZdfHxnLmZvcm1hdChmKVswXSk7fTtnLmZvcm1hdHM9ZnVuY3Rpb24oZngpe2lmKGZ4IGluc3RhbmNlb2YgQXJyYXkpe3ZhciByeD1bXTtmb3IodmFyIGk9MDtpPGZ4Lmxlbmd0aDtpKyspe3J4LnB1c2goX2dldChmeFtpXSkpO31cbnJldHVybiBfLmFueS5hcHBseShudWxsLHJ4KTt9ZWxzZXtyZXR1cm4gX2dldChmeCk7fX07Zy5fZm9ybWF0cz1nLmZvcm1hdHMoW1wiXFxcInl5eXktTU0tZGRUSEg6bW06c3NaXFxcIlwiLFwieXl5eS1NTS1kZFRISDptbTpzc1pcIixcInl5eXktTU0tZGRUSEg6bW06c3N6XCIsXCJ5eXl5LU1NLWRkVEhIOm1tOnNzXCIsXCJ5eXl5LU1NLWRkVEhIOm1tWlwiLFwieXl5eS1NTS1kZFRISDptbXpcIixcInl5eXktTU0tZGRUSEg6bW1cIixcImRkZCwgTU1NIGRkLCB5eXl5IEg6bW06c3MgdHRcIixcImRkZCBNTU0gZCB5eXl5IEhIOm1tOnNzIHp6elwiLFwiTU1kZHl5eXlcIixcImRkTU15eXl5XCIsXCJNZGR5eXl5XCIsXCJkZE15eXl5XCIsXCJNZHl5eXlcIixcImRNeXl5eVwiLFwieXl5eVwiLFwiTWR5eVwiLFwiZE15eVwiLFwiZFwiXSk7Zy5fc3RhcnQ9Xy5wcm9jZXNzKF8uc2V0KFtnLmRhdGUsZy50aW1lLGcuZXhwcmVzc2lvbl0sZy5nZW5lcmFsRGVsaW1pdGVyLGcud2hpdGVTcGFjZSksdC5maW5pc2gpO2cuc3RhcnQ9ZnVuY3Rpb24ocyl7dHJ5e3ZhciByPWcuX2Zvcm1hdHMuY2FsbCh7fSxzKTtpZihyWzFdLmxlbmd0aD09PTApe3JldHVybiByO319Y2F0Y2goZSl7fVxucmV0dXJuIGcuX3N0YXJ0LmNhbGwoe30scyk7fTskRC5fcGFyc2U9JEQucGFyc2U7JEQucGFyc2U9ZnVuY3Rpb24ocyl7dmFyIHI9bnVsbDtpZighcyl7cmV0dXJuIG51bGw7fVxuaWYocyBpbnN0YW5jZW9mIERhdGUpe3JldHVybiBzO31cbnRyeXtyPSRELkdyYW1tYXIuc3RhcnQuY2FsbCh7fSxzLnJlcGxhY2UoL15cXHMqKFxcUyooXFxzK1xcUyspKilcXHMqJC8sXCIkMVwiKSk7fWNhdGNoKGUpe3JldHVybiBudWxsO31cbnJldHVybigoclsxXS5sZW5ndGg9PT0wKT9yWzBdOm51bGwpO307JEQuZ2V0UGFyc2VGdW5jdGlvbj1mdW5jdGlvbihmeCl7dmFyIGZuPSRELkdyYW1tYXIuZm9ybWF0cyhmeCk7cmV0dXJuIGZ1bmN0aW9uKHMpe3ZhciByPW51bGw7dHJ5e3I9Zm4uY2FsbCh7fSxzKTt9Y2F0Y2goZSl7cmV0dXJuIG51bGw7fVxucmV0dXJuKChyWzFdLmxlbmd0aD09PTApP3JbMF06bnVsbCk7fTt9OyRELnBhcnNlRXhhY3Q9ZnVuY3Rpb24ocyxmeCl7cmV0dXJuICRELmdldFBhcnNlRnVuY3Rpb24oZngpKHMpO307fSgpKTtcclxuIiwiLyohXG4gKiBqUXVlcnkgSmF2YVNjcmlwdCBMaWJyYXJ5IHYzLjQuMVxuICogaHR0cHM6Ly9qcXVlcnkuY29tL1xuICpcbiAqIEluY2x1ZGVzIFNpenpsZS5qc1xuICogaHR0cHM6Ly9zaXp6bGVqcy5jb20vXG4gKlxuICogQ29weXJpZ2h0IEpTIEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlXG4gKiBodHRwczovL2pxdWVyeS5vcmcvbGljZW5zZVxuICpcbiAqIERhdGU6IDIwMTktMDUtMDFUMjE6MDRaXG4gKi9cbiggZnVuY3Rpb24oIGdsb2JhbCwgZmFjdG9yeSApIHtcblxuXHRcInVzZSBzdHJpY3RcIjtcblxuXHRpZiAoIHR5cGVvZiBtb2R1bGUgPT09IFwib2JqZWN0XCIgJiYgdHlwZW9mIG1vZHVsZS5leHBvcnRzID09PSBcIm9iamVjdFwiICkge1xuXG5cdFx0Ly8gRm9yIENvbW1vbkpTIGFuZCBDb21tb25KUy1saWtlIGVudmlyb25tZW50cyB3aGVyZSBhIHByb3BlciBgd2luZG93YFxuXHRcdC8vIGlzIHByZXNlbnQsIGV4ZWN1dGUgdGhlIGZhY3RvcnkgYW5kIGdldCBqUXVlcnkuXG5cdFx0Ly8gRm9yIGVudmlyb25tZW50cyB0aGF0IGRvIG5vdCBoYXZlIGEgYHdpbmRvd2Agd2l0aCBhIGBkb2N1bWVudGBcblx0XHQvLyAoc3VjaCBhcyBOb2RlLmpzKSwgZXhwb3NlIGEgZmFjdG9yeSBhcyBtb2R1bGUuZXhwb3J0cy5cblx0XHQvLyBUaGlzIGFjY2VudHVhdGVzIHRoZSBuZWVkIGZvciB0aGUgY3JlYXRpb24gb2YgYSByZWFsIGB3aW5kb3dgLlxuXHRcdC8vIGUuZy4gdmFyIGpRdWVyeSA9IHJlcXVpcmUoXCJqcXVlcnlcIikod2luZG93KTtcblx0XHQvLyBTZWUgdGlja2V0ICMxNDU0OSBmb3IgbW9yZSBpbmZvLlxuXHRcdG1vZHVsZS5leHBvcnRzID0gZ2xvYmFsLmRvY3VtZW50ID9cblx0XHRcdGZhY3RvcnkoIGdsb2JhbCwgdHJ1ZSApIDpcblx0XHRcdGZ1bmN0aW9uKCB3ICkge1xuXHRcdFx0XHRpZiAoICF3LmRvY3VtZW50ICkge1xuXHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggXCJqUXVlcnkgcmVxdWlyZXMgYSB3aW5kb3cgd2l0aCBhIGRvY3VtZW50XCIgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gZmFjdG9yeSggdyApO1xuXHRcdFx0fTtcblx0fSBlbHNlIHtcblx0XHRmYWN0b3J5KCBnbG9iYWwgKTtcblx0fVxuXG4vLyBQYXNzIHRoaXMgaWYgd2luZG93IGlzIG5vdCBkZWZpbmVkIHlldFxufSApKCB0eXBlb2Ygd2luZG93ICE9PSBcInVuZGVmaW5lZFwiID8gd2luZG93IDogdGhpcywgZnVuY3Rpb24oIHdpbmRvdywgbm9HbG9iYWwgKSB7XG5cbi8vIEVkZ2UgPD0gMTIgLSAxMyssIEZpcmVmb3ggPD0xOCAtIDQ1KywgSUUgMTAgLSAxMSwgU2FmYXJpIDUuMSAtIDkrLCBpT1MgNiAtIDkuMVxuLy8gdGhyb3cgZXhjZXB0aW9ucyB3aGVuIG5vbi1zdHJpY3QgY29kZSAoZS5nLiwgQVNQLk5FVCA0LjUpIGFjY2Vzc2VzIHN0cmljdCBtb2RlXG4vLyBhcmd1bWVudHMuY2FsbGVlLmNhbGxlciAodHJhYy0xMzMzNSkuIEJ1dCBhcyBvZiBqUXVlcnkgMy4wICgyMDE2KSwgc3RyaWN0IG1vZGUgc2hvdWxkIGJlIGNvbW1vblxuLy8gZW5vdWdoIHRoYXQgYWxsIHN1Y2ggYXR0ZW1wdHMgYXJlIGd1YXJkZWQgaW4gYSB0cnkgYmxvY2suXG5cInVzZSBzdHJpY3RcIjtcblxudmFyIGFyciA9IFtdO1xuXG52YXIgZG9jdW1lbnQgPSB3aW5kb3cuZG9jdW1lbnQ7XG5cbnZhciBnZXRQcm90byA9IE9iamVjdC5nZXRQcm90b3R5cGVPZjtcblxudmFyIHNsaWNlID0gYXJyLnNsaWNlO1xuXG52YXIgY29uY2F0ID0gYXJyLmNvbmNhdDtcblxudmFyIHB1c2ggPSBhcnIucHVzaDtcblxudmFyIGluZGV4T2YgPSBhcnIuaW5kZXhPZjtcblxudmFyIGNsYXNzMnR5cGUgPSB7fTtcblxudmFyIHRvU3RyaW5nID0gY2xhc3MydHlwZS50b1N0cmluZztcblxudmFyIGhhc093biA9IGNsYXNzMnR5cGUuaGFzT3duUHJvcGVydHk7XG5cbnZhciBmblRvU3RyaW5nID0gaGFzT3duLnRvU3RyaW5nO1xuXG52YXIgT2JqZWN0RnVuY3Rpb25TdHJpbmcgPSBmblRvU3RyaW5nLmNhbGwoIE9iamVjdCApO1xuXG52YXIgc3VwcG9ydCA9IHt9O1xuXG52YXIgaXNGdW5jdGlvbiA9IGZ1bmN0aW9uIGlzRnVuY3Rpb24oIG9iaiApIHtcblxuICAgICAgLy8gU3VwcG9ydDogQ2hyb21lIDw9NTcsIEZpcmVmb3ggPD01MlxuICAgICAgLy8gSW4gc29tZSBicm93c2VycywgdHlwZW9mIHJldHVybnMgXCJmdW5jdGlvblwiIGZvciBIVE1MIDxvYmplY3Q+IGVsZW1lbnRzXG4gICAgICAvLyAoaS5lLiwgYHR5cGVvZiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcIm9iamVjdFwiICkgPT09IFwiZnVuY3Rpb25cImApLlxuICAgICAgLy8gV2UgZG9uJ3Qgd2FudCB0byBjbGFzc2lmeSAqYW55KiBET00gbm9kZSBhcyBhIGZ1bmN0aW9uLlxuICAgICAgcmV0dXJuIHR5cGVvZiBvYmogPT09IFwiZnVuY3Rpb25cIiAmJiB0eXBlb2Ygb2JqLm5vZGVUeXBlICE9PSBcIm51bWJlclwiO1xuICB9O1xuXG5cbnZhciBpc1dpbmRvdyA9IGZ1bmN0aW9uIGlzV2luZG93KCBvYmogKSB7XG5cdFx0cmV0dXJuIG9iaiAhPSBudWxsICYmIG9iaiA9PT0gb2JqLndpbmRvdztcblx0fTtcblxuXG5cblxuXHR2YXIgcHJlc2VydmVkU2NyaXB0QXR0cmlidXRlcyA9IHtcblx0XHR0eXBlOiB0cnVlLFxuXHRcdHNyYzogdHJ1ZSxcblx0XHRub25jZTogdHJ1ZSxcblx0XHRub01vZHVsZTogdHJ1ZVxuXHR9O1xuXG5cdGZ1bmN0aW9uIERPTUV2YWwoIGNvZGUsIG5vZGUsIGRvYyApIHtcblx0XHRkb2MgPSBkb2MgfHwgZG9jdW1lbnQ7XG5cblx0XHR2YXIgaSwgdmFsLFxuXHRcdFx0c2NyaXB0ID0gZG9jLmNyZWF0ZUVsZW1lbnQoIFwic2NyaXB0XCIgKTtcblxuXHRcdHNjcmlwdC50ZXh0ID0gY29kZTtcblx0XHRpZiAoIG5vZGUgKSB7XG5cdFx0XHRmb3IgKCBpIGluIHByZXNlcnZlZFNjcmlwdEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogRmlyZWZveCA2NCssIEVkZ2UgMTgrXG5cdFx0XHRcdC8vIFNvbWUgYnJvd3NlcnMgZG9uJ3Qgc3VwcG9ydCB0aGUgXCJub25jZVwiIHByb3BlcnR5IG9uIHNjcmlwdHMuXG5cdFx0XHRcdC8vIE9uIHRoZSBvdGhlciBoYW5kLCBqdXN0IHVzaW5nIGBnZXRBdHRyaWJ1dGVgIGlzIG5vdCBlbm91Z2ggYXNcblx0XHRcdFx0Ly8gdGhlIGBub25jZWAgYXR0cmlidXRlIGlzIHJlc2V0IHRvIGFuIGVtcHR5IHN0cmluZyB3aGVuZXZlciBpdFxuXHRcdFx0XHQvLyBiZWNvbWVzIGJyb3dzaW5nLWNvbnRleHQgY29ubmVjdGVkLlxuXHRcdFx0XHQvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL3doYXR3Zy9odG1sL2lzc3Vlcy8yMzY5XG5cdFx0XHRcdC8vIFNlZSBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnLyNub25jZS1hdHRyaWJ1dGVzXG5cdFx0XHRcdC8vIFRoZSBgbm9kZS5nZXRBdHRyaWJ1dGVgIGNoZWNrIHdhcyBhZGRlZCBmb3IgdGhlIHNha2Ugb2Zcblx0XHRcdFx0Ly8gYGpRdWVyeS5nbG9iYWxFdmFsYCBzbyB0aGF0IGl0IGNhbiBmYWtlIGEgbm9uY2UtY29udGFpbmluZyBub2RlXG5cdFx0XHRcdC8vIHZpYSBhbiBvYmplY3QuXG5cdFx0XHRcdHZhbCA9IG5vZGVbIGkgXSB8fCBub2RlLmdldEF0dHJpYnV0ZSAmJiBub2RlLmdldEF0dHJpYnV0ZSggaSApO1xuXHRcdFx0XHRpZiAoIHZhbCApIHtcblx0XHRcdFx0XHRzY3JpcHQuc2V0QXR0cmlidXRlKCBpLCB2YWwgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRkb2MuaGVhZC5hcHBlbmRDaGlsZCggc2NyaXB0ICkucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggc2NyaXB0ICk7XG5cdH1cblxuXG5mdW5jdGlvbiB0b1R5cGUoIG9iaiApIHtcblx0aWYgKCBvYmogPT0gbnVsbCApIHtcblx0XHRyZXR1cm4gb2JqICsgXCJcIjtcblx0fVxuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD0yLjMgb25seSAoZnVuY3Rpb25pc2ggUmVnRXhwKVxuXHRyZXR1cm4gdHlwZW9mIG9iaiA9PT0gXCJvYmplY3RcIiB8fCB0eXBlb2Ygb2JqID09PSBcImZ1bmN0aW9uXCIgP1xuXHRcdGNsYXNzMnR5cGVbIHRvU3RyaW5nLmNhbGwoIG9iaiApIF0gfHwgXCJvYmplY3RcIiA6XG5cdFx0dHlwZW9mIG9iajtcbn1cbi8qIGdsb2JhbCBTeW1ib2wgKi9cbi8vIERlZmluaW5nIHRoaXMgZ2xvYmFsIGluIC5lc2xpbnRyYy5qc29uIHdvdWxkIGNyZWF0ZSBhIGRhbmdlciBvZiB1c2luZyB0aGUgZ2xvYmFsXG4vLyB1bmd1YXJkZWQgaW4gYW5vdGhlciBwbGFjZSwgaXQgc2VlbXMgc2FmZXIgdG8gZGVmaW5lIGdsb2JhbCBvbmx5IGZvciB0aGlzIG1vZHVsZVxuXG5cblxudmFyXG5cdHZlcnNpb24gPSBcIjMuNC4xXCIsXG5cblx0Ly8gRGVmaW5lIGEgbG9jYWwgY29weSBvZiBqUXVlcnlcblx0alF1ZXJ5ID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBjb250ZXh0ICkge1xuXG5cdFx0Ly8gVGhlIGpRdWVyeSBvYmplY3QgaXMgYWN0dWFsbHkganVzdCB0aGUgaW5pdCBjb25zdHJ1Y3RvciAnZW5oYW5jZWQnXG5cdFx0Ly8gTmVlZCBpbml0IGlmIGpRdWVyeSBpcyBjYWxsZWQgKGp1c3QgYWxsb3cgZXJyb3IgdG8gYmUgdGhyb3duIGlmIG5vdCBpbmNsdWRlZClcblx0XHRyZXR1cm4gbmV3IGpRdWVyeS5mbi5pbml0KCBzZWxlY3RvciwgY29udGV4dCApO1xuXHR9LFxuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD00LjAgb25seVxuXHQvLyBNYWtlIHN1cmUgd2UgdHJpbSBCT00gYW5kIE5CU1Bcblx0cnRyaW0gPSAvXltcXHNcXHVGRUZGXFx4QTBdK3xbXFxzXFx1RkVGRlxceEEwXSskL2c7XG5cbmpRdWVyeS5mbiA9IGpRdWVyeS5wcm90b3R5cGUgPSB7XG5cblx0Ly8gVGhlIGN1cnJlbnQgdmVyc2lvbiBvZiBqUXVlcnkgYmVpbmcgdXNlZFxuXHRqcXVlcnk6IHZlcnNpb24sXG5cblx0Y29uc3RydWN0b3I6IGpRdWVyeSxcblxuXHQvLyBUaGUgZGVmYXVsdCBsZW5ndGggb2YgYSBqUXVlcnkgb2JqZWN0IGlzIDBcblx0bGVuZ3RoOiAwLFxuXG5cdHRvQXJyYXk6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBzbGljZS5jYWxsKCB0aGlzICk7XG5cdH0sXG5cblx0Ly8gR2V0IHRoZSBOdGggZWxlbWVudCBpbiB0aGUgbWF0Y2hlZCBlbGVtZW50IHNldCBPUlxuXHQvLyBHZXQgdGhlIHdob2xlIG1hdGNoZWQgZWxlbWVudCBzZXQgYXMgYSBjbGVhbiBhcnJheVxuXHRnZXQ6IGZ1bmN0aW9uKCBudW0gKSB7XG5cblx0XHQvLyBSZXR1cm4gYWxsIHRoZSBlbGVtZW50cyBpbiBhIGNsZWFuIGFycmF5XG5cdFx0aWYgKCBudW0gPT0gbnVsbCApIHtcblx0XHRcdHJldHVybiBzbGljZS5jYWxsKCB0aGlzICk7XG5cdFx0fVxuXG5cdFx0Ly8gUmV0dXJuIGp1c3QgdGhlIG9uZSBlbGVtZW50IGZyb20gdGhlIHNldFxuXHRcdHJldHVybiBudW0gPCAwID8gdGhpc1sgbnVtICsgdGhpcy5sZW5ndGggXSA6IHRoaXNbIG51bSBdO1xuXHR9LFxuXG5cdC8vIFRha2UgYW4gYXJyYXkgb2YgZWxlbWVudHMgYW5kIHB1c2ggaXQgb250byB0aGUgc3RhY2tcblx0Ly8gKHJldHVybmluZyB0aGUgbmV3IG1hdGNoZWQgZWxlbWVudCBzZXQpXG5cdHB1c2hTdGFjazogZnVuY3Rpb24oIGVsZW1zICkge1xuXG5cdFx0Ly8gQnVpbGQgYSBuZXcgalF1ZXJ5IG1hdGNoZWQgZWxlbWVudCBzZXRcblx0XHR2YXIgcmV0ID0galF1ZXJ5Lm1lcmdlKCB0aGlzLmNvbnN0cnVjdG9yKCksIGVsZW1zICk7XG5cblx0XHQvLyBBZGQgdGhlIG9sZCBvYmplY3Qgb250byB0aGUgc3RhY2sgKGFzIGEgcmVmZXJlbmNlKVxuXHRcdHJldC5wcmV2T2JqZWN0ID0gdGhpcztcblxuXHRcdC8vIFJldHVybiB0aGUgbmV3bHktZm9ybWVkIGVsZW1lbnQgc2V0XG5cdFx0cmV0dXJuIHJldDtcblx0fSxcblxuXHQvLyBFeGVjdXRlIGEgY2FsbGJhY2sgZm9yIGV2ZXJ5IGVsZW1lbnQgaW4gdGhlIG1hdGNoZWQgc2V0LlxuXHRlYWNoOiBmdW5jdGlvbiggY2FsbGJhY2sgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5lYWNoKCB0aGlzLCBjYWxsYmFjayApO1xuXHR9LFxuXG5cdG1hcDogZnVuY3Rpb24oIGNhbGxiYWNrICkge1xuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggalF1ZXJ5Lm1hcCggdGhpcywgZnVuY3Rpb24oIGVsZW0sIGkgKSB7XG5cdFx0XHRyZXR1cm4gY2FsbGJhY2suY2FsbCggZWxlbSwgaSwgZWxlbSApO1xuXHRcdH0gKSApO1xuXHR9LFxuXG5cdHNsaWNlOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIHNsaWNlLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSApO1xuXHR9LFxuXG5cdGZpcnN0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5lcSggMCApO1xuXHR9LFxuXG5cdGxhc3Q6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmVxKCAtMSApO1xuXHR9LFxuXG5cdGVxOiBmdW5jdGlvbiggaSApIHtcblx0XHR2YXIgbGVuID0gdGhpcy5sZW5ndGgsXG5cdFx0XHRqID0gK2kgKyAoIGkgPCAwID8gbGVuIDogMCApO1xuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggaiA+PSAwICYmIGogPCBsZW4gPyBbIHRoaXNbIGogXSBdIDogW10gKTtcblx0fSxcblxuXHRlbmQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLnByZXZPYmplY3QgfHwgdGhpcy5jb25zdHJ1Y3RvcigpO1xuXHR9LFxuXG5cdC8vIEZvciBpbnRlcm5hbCB1c2Ugb25seS5cblx0Ly8gQmVoYXZlcyBsaWtlIGFuIEFycmF5J3MgbWV0aG9kLCBub3QgbGlrZSBhIGpRdWVyeSBtZXRob2QuXG5cdHB1c2g6IHB1c2gsXG5cdHNvcnQ6IGFyci5zb3J0LFxuXHRzcGxpY2U6IGFyci5zcGxpY2Vcbn07XG5cbmpRdWVyeS5leHRlbmQgPSBqUXVlcnkuZm4uZXh0ZW5kID0gZnVuY3Rpb24oKSB7XG5cdHZhciBvcHRpb25zLCBuYW1lLCBzcmMsIGNvcHksIGNvcHlJc0FycmF5LCBjbG9uZSxcblx0XHR0YXJnZXQgPSBhcmd1bWVudHNbIDAgXSB8fCB7fSxcblx0XHRpID0gMSxcblx0XHRsZW5ndGggPSBhcmd1bWVudHMubGVuZ3RoLFxuXHRcdGRlZXAgPSBmYWxzZTtcblxuXHQvLyBIYW5kbGUgYSBkZWVwIGNvcHkgc2l0dWF0aW9uXG5cdGlmICggdHlwZW9mIHRhcmdldCA9PT0gXCJib29sZWFuXCIgKSB7XG5cdFx0ZGVlcCA9IHRhcmdldDtcblxuXHRcdC8vIFNraXAgdGhlIGJvb2xlYW4gYW5kIHRoZSB0YXJnZXRcblx0XHR0YXJnZXQgPSBhcmd1bWVudHNbIGkgXSB8fCB7fTtcblx0XHRpKys7XG5cdH1cblxuXHQvLyBIYW5kbGUgY2FzZSB3aGVuIHRhcmdldCBpcyBhIHN0cmluZyBvciBzb21ldGhpbmcgKHBvc3NpYmxlIGluIGRlZXAgY29weSlcblx0aWYgKCB0eXBlb2YgdGFyZ2V0ICE9PSBcIm9iamVjdFwiICYmICFpc0Z1bmN0aW9uKCB0YXJnZXQgKSApIHtcblx0XHR0YXJnZXQgPSB7fTtcblx0fVxuXG5cdC8vIEV4dGVuZCBqUXVlcnkgaXRzZWxmIGlmIG9ubHkgb25lIGFyZ3VtZW50IGlzIHBhc3NlZFxuXHRpZiAoIGkgPT09IGxlbmd0aCApIHtcblx0XHR0YXJnZXQgPSB0aGlzO1xuXHRcdGktLTtcblx0fVxuXG5cdGZvciAoIDsgaSA8IGxlbmd0aDsgaSsrICkge1xuXG5cdFx0Ly8gT25seSBkZWFsIHdpdGggbm9uLW51bGwvdW5kZWZpbmVkIHZhbHVlc1xuXHRcdGlmICggKCBvcHRpb25zID0gYXJndW1lbnRzWyBpIF0gKSAhPSBudWxsICkge1xuXG5cdFx0XHQvLyBFeHRlbmQgdGhlIGJhc2Ugb2JqZWN0XG5cdFx0XHRmb3IgKCBuYW1lIGluIG9wdGlvbnMgKSB7XG5cdFx0XHRcdGNvcHkgPSBvcHRpb25zWyBuYW1lIF07XG5cblx0XHRcdFx0Ly8gUHJldmVudCBPYmplY3QucHJvdG90eXBlIHBvbGx1dGlvblxuXHRcdFx0XHQvLyBQcmV2ZW50IG5ldmVyLWVuZGluZyBsb29wXG5cdFx0XHRcdGlmICggbmFtZSA9PT0gXCJfX3Byb3RvX19cIiB8fCB0YXJnZXQgPT09IGNvcHkgKSB7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBSZWN1cnNlIGlmIHdlJ3JlIG1lcmdpbmcgcGxhaW4gb2JqZWN0cyBvciBhcnJheXNcblx0XHRcdFx0aWYgKCBkZWVwICYmIGNvcHkgJiYgKCBqUXVlcnkuaXNQbGFpbk9iamVjdCggY29weSApIHx8XG5cdFx0XHRcdFx0KCBjb3B5SXNBcnJheSA9IEFycmF5LmlzQXJyYXkoIGNvcHkgKSApICkgKSB7XG5cdFx0XHRcdFx0c3JjID0gdGFyZ2V0WyBuYW1lIF07XG5cblx0XHRcdFx0XHQvLyBFbnN1cmUgcHJvcGVyIHR5cGUgZm9yIHRoZSBzb3VyY2UgdmFsdWVcblx0XHRcdFx0XHRpZiAoIGNvcHlJc0FycmF5ICYmICFBcnJheS5pc0FycmF5KCBzcmMgKSApIHtcblx0XHRcdFx0XHRcdGNsb25lID0gW107XG5cdFx0XHRcdFx0fSBlbHNlIGlmICggIWNvcHlJc0FycmF5ICYmICFqUXVlcnkuaXNQbGFpbk9iamVjdCggc3JjICkgKSB7XG5cdFx0XHRcdFx0XHRjbG9uZSA9IHt9O1xuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRjbG9uZSA9IHNyYztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0Y29weUlzQXJyYXkgPSBmYWxzZTtcblxuXHRcdFx0XHRcdC8vIE5ldmVyIG1vdmUgb3JpZ2luYWwgb2JqZWN0cywgY2xvbmUgdGhlbVxuXHRcdFx0XHRcdHRhcmdldFsgbmFtZSBdID0galF1ZXJ5LmV4dGVuZCggZGVlcCwgY2xvbmUsIGNvcHkgKTtcblxuXHRcdFx0XHQvLyBEb24ndCBicmluZyBpbiB1bmRlZmluZWQgdmFsdWVzXG5cdFx0XHRcdH0gZWxzZSBpZiAoIGNvcHkgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHR0YXJnZXRbIG5hbWUgXSA9IGNvcHk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLyBSZXR1cm4gdGhlIG1vZGlmaWVkIG9iamVjdFxuXHRyZXR1cm4gdGFyZ2V0O1xufTtcblxualF1ZXJ5LmV4dGVuZCgge1xuXG5cdC8vIFVuaXF1ZSBmb3IgZWFjaCBjb3B5IG9mIGpRdWVyeSBvbiB0aGUgcGFnZVxuXHRleHBhbmRvOiBcImpRdWVyeVwiICsgKCB2ZXJzaW9uICsgTWF0aC5yYW5kb20oKSApLnJlcGxhY2UoIC9cXEQvZywgXCJcIiApLFxuXG5cdC8vIEFzc3VtZSBqUXVlcnkgaXMgcmVhZHkgd2l0aG91dCB0aGUgcmVhZHkgbW9kdWxlXG5cdGlzUmVhZHk6IHRydWUsXG5cblx0ZXJyb3I6IGZ1bmN0aW9uKCBtc2cgKSB7XG5cdFx0dGhyb3cgbmV3IEVycm9yKCBtc2cgKTtcblx0fSxcblxuXHRub29wOiBmdW5jdGlvbigpIHt9LFxuXG5cdGlzUGxhaW5PYmplY3Q6IGZ1bmN0aW9uKCBvYmogKSB7XG5cdFx0dmFyIHByb3RvLCBDdG9yO1xuXG5cdFx0Ly8gRGV0ZWN0IG9idmlvdXMgbmVnYXRpdmVzXG5cdFx0Ly8gVXNlIHRvU3RyaW5nIGluc3RlYWQgb2YgalF1ZXJ5LnR5cGUgdG8gY2F0Y2ggaG9zdCBvYmplY3RzXG5cdFx0aWYgKCAhb2JqIHx8IHRvU3RyaW5nLmNhbGwoIG9iaiApICE9PSBcIltvYmplY3QgT2JqZWN0XVwiICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHByb3RvID0gZ2V0UHJvdG8oIG9iaiApO1xuXG5cdFx0Ly8gT2JqZWN0cyB3aXRoIG5vIHByb3RvdHlwZSAoZS5nLiwgYE9iamVjdC5jcmVhdGUoIG51bGwgKWApIGFyZSBwbGFpblxuXHRcdGlmICggIXByb3RvICkge1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXG5cdFx0Ly8gT2JqZWN0cyB3aXRoIHByb3RvdHlwZSBhcmUgcGxhaW4gaWZmIHRoZXkgd2VyZSBjb25zdHJ1Y3RlZCBieSBhIGdsb2JhbCBPYmplY3QgZnVuY3Rpb25cblx0XHRDdG9yID0gaGFzT3duLmNhbGwoIHByb3RvLCBcImNvbnN0cnVjdG9yXCIgKSAmJiBwcm90by5jb25zdHJ1Y3Rvcjtcblx0XHRyZXR1cm4gdHlwZW9mIEN0b3IgPT09IFwiZnVuY3Rpb25cIiAmJiBmblRvU3RyaW5nLmNhbGwoIEN0b3IgKSA9PT0gT2JqZWN0RnVuY3Rpb25TdHJpbmc7XG5cdH0sXG5cblx0aXNFbXB0eU9iamVjdDogZnVuY3Rpb24oIG9iaiApIHtcblx0XHR2YXIgbmFtZTtcblxuXHRcdGZvciAoIG5hbWUgaW4gb2JqICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHQvLyBFdmFsdWF0ZXMgYSBzY3JpcHQgaW4gYSBnbG9iYWwgY29udGV4dFxuXHRnbG9iYWxFdmFsOiBmdW5jdGlvbiggY29kZSwgb3B0aW9ucyApIHtcblx0XHRET01FdmFsKCBjb2RlLCB7IG5vbmNlOiBvcHRpb25zICYmIG9wdGlvbnMubm9uY2UgfSApO1xuXHR9LFxuXG5cdGVhY2g6IGZ1bmN0aW9uKCBvYmosIGNhbGxiYWNrICkge1xuXHRcdHZhciBsZW5ndGgsIGkgPSAwO1xuXG5cdFx0aWYgKCBpc0FycmF5TGlrZSggb2JqICkgKSB7XG5cdFx0XHRsZW5ndGggPSBvYmoubGVuZ3RoO1xuXHRcdFx0Zm9yICggOyBpIDwgbGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRcdGlmICggY2FsbGJhY2suY2FsbCggb2JqWyBpIF0sIGksIG9ialsgaSBdICkgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGZvciAoIGkgaW4gb2JqICkge1xuXHRcdFx0XHRpZiAoIGNhbGxiYWNrLmNhbGwoIG9ialsgaSBdLCBpLCBvYmpbIGkgXSApID09PSBmYWxzZSApIHtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiBvYmo7XG5cdH0sXG5cblx0Ly8gU3VwcG9ydDogQW5kcm9pZCA8PTQuMCBvbmx5XG5cdHRyaW06IGZ1bmN0aW9uKCB0ZXh0ICkge1xuXHRcdHJldHVybiB0ZXh0ID09IG51bGwgP1xuXHRcdFx0XCJcIiA6XG5cdFx0XHQoIHRleHQgKyBcIlwiICkucmVwbGFjZSggcnRyaW0sIFwiXCIgKTtcblx0fSxcblxuXHQvLyByZXN1bHRzIGlzIGZvciBpbnRlcm5hbCB1c2FnZSBvbmx5XG5cdG1ha2VBcnJheTogZnVuY3Rpb24oIGFyciwgcmVzdWx0cyApIHtcblx0XHR2YXIgcmV0ID0gcmVzdWx0cyB8fCBbXTtcblxuXHRcdGlmICggYXJyICE9IG51bGwgKSB7XG5cdFx0XHRpZiAoIGlzQXJyYXlMaWtlKCBPYmplY3QoIGFyciApICkgKSB7XG5cdFx0XHRcdGpRdWVyeS5tZXJnZSggcmV0LFxuXHRcdFx0XHRcdHR5cGVvZiBhcnIgPT09IFwic3RyaW5nXCIgP1xuXHRcdFx0XHRcdFsgYXJyIF0gOiBhcnJcblx0XHRcdFx0KTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHB1c2guY2FsbCggcmV0LCBhcnIgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gcmV0O1xuXHR9LFxuXG5cdGluQXJyYXk6IGZ1bmN0aW9uKCBlbGVtLCBhcnIsIGkgKSB7XG5cdFx0cmV0dXJuIGFyciA9PSBudWxsID8gLTEgOiBpbmRleE9mLmNhbGwoIGFyciwgZWxlbSwgaSApO1xuXHR9LFxuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD00LjAgb25seSwgUGhhbnRvbUpTIDEgb25seVxuXHQvLyBwdXNoLmFwcGx5KF8sIGFycmF5bGlrZSkgdGhyb3dzIG9uIGFuY2llbnQgV2ViS2l0XG5cdG1lcmdlOiBmdW5jdGlvbiggZmlyc3QsIHNlY29uZCApIHtcblx0XHR2YXIgbGVuID0gK3NlY29uZC5sZW5ndGgsXG5cdFx0XHRqID0gMCxcblx0XHRcdGkgPSBmaXJzdC5sZW5ndGg7XG5cblx0XHRmb3IgKCA7IGogPCBsZW47IGorKyApIHtcblx0XHRcdGZpcnN0WyBpKysgXSA9IHNlY29uZFsgaiBdO1xuXHRcdH1cblxuXHRcdGZpcnN0Lmxlbmd0aCA9IGk7XG5cblx0XHRyZXR1cm4gZmlyc3Q7XG5cdH0sXG5cblx0Z3JlcDogZnVuY3Rpb24oIGVsZW1zLCBjYWxsYmFjaywgaW52ZXJ0ICkge1xuXHRcdHZhciBjYWxsYmFja0ludmVyc2UsXG5cdFx0XHRtYXRjaGVzID0gW10sXG5cdFx0XHRpID0gMCxcblx0XHRcdGxlbmd0aCA9IGVsZW1zLmxlbmd0aCxcblx0XHRcdGNhbGxiYWNrRXhwZWN0ID0gIWludmVydDtcblxuXHRcdC8vIEdvIHRocm91Z2ggdGhlIGFycmF5LCBvbmx5IHNhdmluZyB0aGUgaXRlbXNcblx0XHQvLyB0aGF0IHBhc3MgdGhlIHZhbGlkYXRvciBmdW5jdGlvblxuXHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSsrICkge1xuXHRcdFx0Y2FsbGJhY2tJbnZlcnNlID0gIWNhbGxiYWNrKCBlbGVtc1sgaSBdLCBpICk7XG5cdFx0XHRpZiAoIGNhbGxiYWNrSW52ZXJzZSAhPT0gY2FsbGJhY2tFeHBlY3QgKSB7XG5cdFx0XHRcdG1hdGNoZXMucHVzaCggZWxlbXNbIGkgXSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiBtYXRjaGVzO1xuXHR9LFxuXG5cdC8vIGFyZyBpcyBmb3IgaW50ZXJuYWwgdXNhZ2Ugb25seVxuXHRtYXA6IGZ1bmN0aW9uKCBlbGVtcywgY2FsbGJhY2ssIGFyZyApIHtcblx0XHR2YXIgbGVuZ3RoLCB2YWx1ZSxcblx0XHRcdGkgPSAwLFxuXHRcdFx0cmV0ID0gW107XG5cblx0XHQvLyBHbyB0aHJvdWdoIHRoZSBhcnJheSwgdHJhbnNsYXRpbmcgZWFjaCBvZiB0aGUgaXRlbXMgdG8gdGhlaXIgbmV3IHZhbHVlc1xuXHRcdGlmICggaXNBcnJheUxpa2UoIGVsZW1zICkgKSB7XG5cdFx0XHRsZW5ndGggPSBlbGVtcy5sZW5ndGg7XG5cdFx0XHRmb3IgKCA7IGkgPCBsZW5ndGg7IGkrKyApIHtcblx0XHRcdFx0dmFsdWUgPSBjYWxsYmFjayggZWxlbXNbIGkgXSwgaSwgYXJnICk7XG5cblx0XHRcdFx0aWYgKCB2YWx1ZSAhPSBudWxsICkge1xuXHRcdFx0XHRcdHJldC5wdXNoKCB2YWx1ZSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHQvLyBHbyB0aHJvdWdoIGV2ZXJ5IGtleSBvbiB0aGUgb2JqZWN0LFxuXHRcdH0gZWxzZSB7XG5cdFx0XHRmb3IgKCBpIGluIGVsZW1zICkge1xuXHRcdFx0XHR2YWx1ZSA9IGNhbGxiYWNrKCBlbGVtc1sgaSBdLCBpLCBhcmcgKTtcblxuXHRcdFx0XHRpZiAoIHZhbHVlICE9IG51bGwgKSB7XG5cdFx0XHRcdFx0cmV0LnB1c2goIHZhbHVlICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBGbGF0dGVuIGFueSBuZXN0ZWQgYXJyYXlzXG5cdFx0cmV0dXJuIGNvbmNhdC5hcHBseSggW10sIHJldCApO1xuXHR9LFxuXG5cdC8vIEEgZ2xvYmFsIEdVSUQgY291bnRlciBmb3Igb2JqZWN0c1xuXHRndWlkOiAxLFxuXG5cdC8vIGpRdWVyeS5zdXBwb3J0IGlzIG5vdCB1c2VkIGluIENvcmUgYnV0IG90aGVyIHByb2plY3RzIGF0dGFjaCB0aGVpclxuXHQvLyBwcm9wZXJ0aWVzIHRvIGl0IHNvIGl0IG5lZWRzIHRvIGV4aXN0LlxuXHRzdXBwb3J0OiBzdXBwb3J0XG59ICk7XG5cbmlmICggdHlwZW9mIFN5bWJvbCA9PT0gXCJmdW5jdGlvblwiICkge1xuXHRqUXVlcnkuZm5bIFN5bWJvbC5pdGVyYXRvciBdID0gYXJyWyBTeW1ib2wuaXRlcmF0b3IgXTtcbn1cblxuLy8gUG9wdWxhdGUgdGhlIGNsYXNzMnR5cGUgbWFwXG5qUXVlcnkuZWFjaCggXCJCb29sZWFuIE51bWJlciBTdHJpbmcgRnVuY3Rpb24gQXJyYXkgRGF0ZSBSZWdFeHAgT2JqZWN0IEVycm9yIFN5bWJvbFwiLnNwbGl0KCBcIiBcIiApLFxuZnVuY3Rpb24oIGksIG5hbWUgKSB7XG5cdGNsYXNzMnR5cGVbIFwiW29iamVjdCBcIiArIG5hbWUgKyBcIl1cIiBdID0gbmFtZS50b0xvd2VyQ2FzZSgpO1xufSApO1xuXG5mdW5jdGlvbiBpc0FycmF5TGlrZSggb2JqICkge1xuXG5cdC8vIFN1cHBvcnQ6IHJlYWwgaU9TIDguMiBvbmx5IChub3QgcmVwcm9kdWNpYmxlIGluIHNpbXVsYXRvcilcblx0Ly8gYGluYCBjaGVjayB1c2VkIHRvIHByZXZlbnQgSklUIGVycm9yIChnaC0yMTQ1KVxuXHQvLyBoYXNPd24gaXNuJ3QgdXNlZCBoZXJlIGR1ZSB0byBmYWxzZSBuZWdhdGl2ZXNcblx0Ly8gcmVnYXJkaW5nIE5vZGVsaXN0IGxlbmd0aCBpbiBJRVxuXHR2YXIgbGVuZ3RoID0gISFvYmogJiYgXCJsZW5ndGhcIiBpbiBvYmogJiYgb2JqLmxlbmd0aCxcblx0XHR0eXBlID0gdG9UeXBlKCBvYmogKTtcblxuXHRpZiAoIGlzRnVuY3Rpb24oIG9iaiApIHx8IGlzV2luZG93KCBvYmogKSApIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHRyZXR1cm4gdHlwZSA9PT0gXCJhcnJheVwiIHx8IGxlbmd0aCA9PT0gMCB8fFxuXHRcdHR5cGVvZiBsZW5ndGggPT09IFwibnVtYmVyXCIgJiYgbGVuZ3RoID4gMCAmJiAoIGxlbmd0aCAtIDEgKSBpbiBvYmo7XG59XG52YXIgU2l6emxlID1cbi8qIVxuICogU2l6emxlIENTUyBTZWxlY3RvciBFbmdpbmUgdjIuMy40XG4gKiBodHRwczovL3NpenpsZWpzLmNvbS9cbiAqXG4gKiBDb3B5cmlnaHQgSlMgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2VcbiAqIGh0dHBzOi8vanMuZm91bmRhdGlvbi9cbiAqXG4gKiBEYXRlOiAyMDE5LTA0LTA4XG4gKi9cbihmdW5jdGlvbiggd2luZG93ICkge1xuXG52YXIgaSxcblx0c3VwcG9ydCxcblx0RXhwcixcblx0Z2V0VGV4dCxcblx0aXNYTUwsXG5cdHRva2VuaXplLFxuXHRjb21waWxlLFxuXHRzZWxlY3QsXG5cdG91dGVybW9zdENvbnRleHQsXG5cdHNvcnRJbnB1dCxcblx0aGFzRHVwbGljYXRlLFxuXG5cdC8vIExvY2FsIGRvY3VtZW50IHZhcnNcblx0c2V0RG9jdW1lbnQsXG5cdGRvY3VtZW50LFxuXHRkb2NFbGVtLFxuXHRkb2N1bWVudElzSFRNTCxcblx0cmJ1Z2d5UVNBLFxuXHRyYnVnZ3lNYXRjaGVzLFxuXHRtYXRjaGVzLFxuXHRjb250YWlucyxcblxuXHQvLyBJbnN0YW5jZS1zcGVjaWZpYyBkYXRhXG5cdGV4cGFuZG8gPSBcInNpenpsZVwiICsgMSAqIG5ldyBEYXRlKCksXG5cdHByZWZlcnJlZERvYyA9IHdpbmRvdy5kb2N1bWVudCxcblx0ZGlycnVucyA9IDAsXG5cdGRvbmUgPSAwLFxuXHRjbGFzc0NhY2hlID0gY3JlYXRlQ2FjaGUoKSxcblx0dG9rZW5DYWNoZSA9IGNyZWF0ZUNhY2hlKCksXG5cdGNvbXBpbGVyQ2FjaGUgPSBjcmVhdGVDYWNoZSgpLFxuXHRub25uYXRpdmVTZWxlY3RvckNhY2hlID0gY3JlYXRlQ2FjaGUoKSxcblx0c29ydE9yZGVyID0gZnVuY3Rpb24oIGEsIGIgKSB7XG5cdFx0aWYgKCBhID09PSBiICkge1xuXHRcdFx0aGFzRHVwbGljYXRlID0gdHJ1ZTtcblx0XHR9XG5cdFx0cmV0dXJuIDA7XG5cdH0sXG5cblx0Ly8gSW5zdGFuY2UgbWV0aG9kc1xuXHRoYXNPd24gPSAoe30pLmhhc093blByb3BlcnR5LFxuXHRhcnIgPSBbXSxcblx0cG9wID0gYXJyLnBvcCxcblx0cHVzaF9uYXRpdmUgPSBhcnIucHVzaCxcblx0cHVzaCA9IGFyci5wdXNoLFxuXHRzbGljZSA9IGFyci5zbGljZSxcblx0Ly8gVXNlIGEgc3RyaXBwZWQtZG93biBpbmRleE9mIGFzIGl0J3MgZmFzdGVyIHRoYW4gbmF0aXZlXG5cdC8vIGh0dHBzOi8vanNwZXJmLmNvbS90aG9yLWluZGV4b2YtdnMtZm9yLzVcblx0aW5kZXhPZiA9IGZ1bmN0aW9uKCBsaXN0LCBlbGVtICkge1xuXHRcdHZhciBpID0gMCxcblx0XHRcdGxlbiA9IGxpc3QubGVuZ3RoO1xuXHRcdGZvciAoIDsgaSA8IGxlbjsgaSsrICkge1xuXHRcdFx0aWYgKCBsaXN0W2ldID09PSBlbGVtICkge1xuXHRcdFx0XHRyZXR1cm4gaTtcblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIC0xO1xuXHR9LFxuXG5cdGJvb2xlYW5zID0gXCJjaGVja2VkfHNlbGVjdGVkfGFzeW5jfGF1dG9mb2N1c3xhdXRvcGxheXxjb250cm9sc3xkZWZlcnxkaXNhYmxlZHxoaWRkZW58aXNtYXB8bG9vcHxtdWx0aXBsZXxvcGVufHJlYWRvbmx5fHJlcXVpcmVkfHNjb3BlZFwiLFxuXG5cdC8vIFJlZ3VsYXIgZXhwcmVzc2lvbnNcblxuXHQvLyBodHRwOi8vd3d3LnczLm9yZy9UUi9jc3MzLXNlbGVjdG9ycy8jd2hpdGVzcGFjZVxuXHR3aGl0ZXNwYWNlID0gXCJbXFxcXHgyMFxcXFx0XFxcXHJcXFxcblxcXFxmXVwiLFxuXG5cdC8vIGh0dHA6Ly93d3cudzMub3JnL1RSL0NTUzIxL3N5bmRhdGEuaHRtbCN2YWx1ZS1kZWYtaWRlbnRpZmllclxuXHRpZGVudGlmaWVyID0gXCIoPzpcXFxcXFxcXC58W1xcXFx3LV18W15cXDAtXFxcXHhhMF0pK1wiLFxuXG5cdC8vIEF0dHJpYnV0ZSBzZWxlY3RvcnM6IGh0dHA6Ly93d3cudzMub3JnL1RSL3NlbGVjdG9ycy8jYXR0cmlidXRlLXNlbGVjdG9yc1xuXHRhdHRyaWJ1dGVzID0gXCJcXFxcW1wiICsgd2hpdGVzcGFjZSArIFwiKihcIiArIGlkZW50aWZpZXIgKyBcIikoPzpcIiArIHdoaXRlc3BhY2UgK1xuXHRcdC8vIE9wZXJhdG9yIChjYXB0dXJlIDIpXG5cdFx0XCIqKFsqXiR8IX5dPz0pXCIgKyB3aGl0ZXNwYWNlICtcblx0XHQvLyBcIkF0dHJpYnV0ZSB2YWx1ZXMgbXVzdCBiZSBDU1MgaWRlbnRpZmllcnMgW2NhcHR1cmUgNV0gb3Igc3RyaW5ncyBbY2FwdHVyZSAzIG9yIGNhcHR1cmUgNF1cIlxuXHRcdFwiKig/OicoKD86XFxcXFxcXFwufFteXFxcXFxcXFwnXSkqKSd8XFxcIigoPzpcXFxcXFxcXC58W15cXFxcXFxcXFxcXCJdKSopXFxcInwoXCIgKyBpZGVudGlmaWVyICsgXCIpKXwpXCIgKyB3aGl0ZXNwYWNlICtcblx0XHRcIipcXFxcXVwiLFxuXG5cdHBzZXVkb3MgPSBcIjooXCIgKyBpZGVudGlmaWVyICsgXCIpKD86XFxcXCgoXCIgK1xuXHRcdC8vIFRvIHJlZHVjZSB0aGUgbnVtYmVyIG9mIHNlbGVjdG9ycyBuZWVkaW5nIHRva2VuaXplIGluIHRoZSBwcmVGaWx0ZXIsIHByZWZlciBhcmd1bWVudHM6XG5cdFx0Ly8gMS4gcXVvdGVkIChjYXB0dXJlIDM7IGNhcHR1cmUgNCBvciBjYXB0dXJlIDUpXG5cdFx0XCIoJygoPzpcXFxcXFxcXC58W15cXFxcXFxcXCddKSopJ3xcXFwiKCg/OlxcXFxcXFxcLnxbXlxcXFxcXFxcXFxcIl0pKilcXFwiKXxcIiArXG5cdFx0Ly8gMi4gc2ltcGxlIChjYXB0dXJlIDYpXG5cdFx0XCIoKD86XFxcXFxcXFwufFteXFxcXFxcXFwoKVtcXFxcXV18XCIgKyBhdHRyaWJ1dGVzICsgXCIpKil8XCIgK1xuXHRcdC8vIDMuIGFueXRoaW5nIGVsc2UgKGNhcHR1cmUgMilcblx0XHRcIi4qXCIgK1xuXHRcdFwiKVxcXFwpfClcIixcblxuXHQvLyBMZWFkaW5nIGFuZCBub24tZXNjYXBlZCB0cmFpbGluZyB3aGl0ZXNwYWNlLCBjYXB0dXJpbmcgc29tZSBub24td2hpdGVzcGFjZSBjaGFyYWN0ZXJzIHByZWNlZGluZyB0aGUgbGF0dGVyXG5cdHJ3aGl0ZXNwYWNlID0gbmV3IFJlZ0V4cCggd2hpdGVzcGFjZSArIFwiK1wiLCBcImdcIiApLFxuXHRydHJpbSA9IG5ldyBSZWdFeHAoIFwiXlwiICsgd2hpdGVzcGFjZSArIFwiK3woKD86XnxbXlxcXFxcXFxcXSkoPzpcXFxcXFxcXC4pKilcIiArIHdoaXRlc3BhY2UgKyBcIiskXCIsIFwiZ1wiICksXG5cblx0cmNvbW1hID0gbmV3IFJlZ0V4cCggXCJeXCIgKyB3aGl0ZXNwYWNlICsgXCIqLFwiICsgd2hpdGVzcGFjZSArIFwiKlwiICksXG5cdHJjb21iaW5hdG9ycyA9IG5ldyBSZWdFeHAoIFwiXlwiICsgd2hpdGVzcGFjZSArIFwiKihbPit+XXxcIiArIHdoaXRlc3BhY2UgKyBcIilcIiArIHdoaXRlc3BhY2UgKyBcIipcIiApLFxuXHRyZGVzY2VuZCA9IG5ldyBSZWdFeHAoIHdoaXRlc3BhY2UgKyBcInw+XCIgKSxcblxuXHRycHNldWRvID0gbmV3IFJlZ0V4cCggcHNldWRvcyApLFxuXHRyaWRlbnRpZmllciA9IG5ldyBSZWdFeHAoIFwiXlwiICsgaWRlbnRpZmllciArIFwiJFwiICksXG5cblx0bWF0Y2hFeHByID0ge1xuXHRcdFwiSURcIjogbmV3IFJlZ0V4cCggXCJeIyhcIiArIGlkZW50aWZpZXIgKyBcIilcIiApLFxuXHRcdFwiQ0xBU1NcIjogbmV3IFJlZ0V4cCggXCJeXFxcXC4oXCIgKyBpZGVudGlmaWVyICsgXCIpXCIgKSxcblx0XHRcIlRBR1wiOiBuZXcgUmVnRXhwKCBcIl4oXCIgKyBpZGVudGlmaWVyICsgXCJ8WypdKVwiICksXG5cdFx0XCJBVFRSXCI6IG5ldyBSZWdFeHAoIFwiXlwiICsgYXR0cmlidXRlcyApLFxuXHRcdFwiUFNFVURPXCI6IG5ldyBSZWdFeHAoIFwiXlwiICsgcHNldWRvcyApLFxuXHRcdFwiQ0hJTERcIjogbmV3IFJlZ0V4cCggXCJeOihvbmx5fGZpcnN0fGxhc3R8bnRofG50aC1sYXN0KS0oY2hpbGR8b2YtdHlwZSkoPzpcXFxcKFwiICsgd2hpdGVzcGFjZSArXG5cdFx0XHRcIiooZXZlbnxvZGR8KChbKy1dfCkoXFxcXGQqKW58KVwiICsgd2hpdGVzcGFjZSArIFwiKig/OihbKy1dfClcIiArIHdoaXRlc3BhY2UgK1xuXHRcdFx0XCIqKFxcXFxkKyl8KSlcIiArIHdoaXRlc3BhY2UgKyBcIipcXFxcKXwpXCIsIFwiaVwiICksXG5cdFx0XCJib29sXCI6IG5ldyBSZWdFeHAoIFwiXig/OlwiICsgYm9vbGVhbnMgKyBcIikkXCIsIFwiaVwiICksXG5cdFx0Ly8gRm9yIHVzZSBpbiBsaWJyYXJpZXMgaW1wbGVtZW50aW5nIC5pcygpXG5cdFx0Ly8gV2UgdXNlIHRoaXMgZm9yIFBPUyBtYXRjaGluZyBpbiBgc2VsZWN0YFxuXHRcdFwibmVlZHNDb250ZXh0XCI6IG5ldyBSZWdFeHAoIFwiXlwiICsgd2hpdGVzcGFjZSArIFwiKls+K35dfDooZXZlbnxvZGR8ZXF8Z3R8bHR8bnRofGZpcnN0fGxhc3QpKD86XFxcXChcIiArXG5cdFx0XHR3aGl0ZXNwYWNlICsgXCIqKCg/Oi1cXFxcZCk/XFxcXGQqKVwiICsgd2hpdGVzcGFjZSArIFwiKlxcXFwpfCkoPz1bXi1dfCQpXCIsIFwiaVwiIClcblx0fSxcblxuXHRyaHRtbCA9IC9IVE1MJC9pLFxuXHRyaW5wdXRzID0gL14oPzppbnB1dHxzZWxlY3R8dGV4dGFyZWF8YnV0dG9uKSQvaSxcblx0cmhlYWRlciA9IC9eaFxcZCQvaSxcblxuXHRybmF0aXZlID0gL15bXntdK1xce1xccypcXFtuYXRpdmUgXFx3LyxcblxuXHQvLyBFYXNpbHktcGFyc2VhYmxlL3JldHJpZXZhYmxlIElEIG9yIFRBRyBvciBDTEFTUyBzZWxlY3RvcnNcblx0cnF1aWNrRXhwciA9IC9eKD86IyhbXFx3LV0rKXwoXFx3Kyl8XFwuKFtcXHctXSspKSQvLFxuXG5cdHJzaWJsaW5nID0gL1srfl0vLFxuXG5cdC8vIENTUyBlc2NhcGVzXG5cdC8vIGh0dHA6Ly93d3cudzMub3JnL1RSL0NTUzIxL3N5bmRhdGEuaHRtbCNlc2NhcGVkLWNoYXJhY3RlcnNcblx0cnVuZXNjYXBlID0gbmV3IFJlZ0V4cCggXCJcXFxcXFxcXChbXFxcXGRhLWZdezEsNn1cIiArIHdoaXRlc3BhY2UgKyBcIj98KFwiICsgd2hpdGVzcGFjZSArIFwiKXwuKVwiLCBcImlnXCIgKSxcblx0ZnVuZXNjYXBlID0gZnVuY3Rpb24oIF8sIGVzY2FwZWQsIGVzY2FwZWRXaGl0ZXNwYWNlICkge1xuXHRcdHZhciBoaWdoID0gXCIweFwiICsgZXNjYXBlZCAtIDB4MTAwMDA7XG5cdFx0Ly8gTmFOIG1lYW5zIG5vbi1jb2RlcG9pbnRcblx0XHQvLyBTdXBwb3J0OiBGaXJlZm94PDI0XG5cdFx0Ly8gV29ya2Fyb3VuZCBlcnJvbmVvdXMgbnVtZXJpYyBpbnRlcnByZXRhdGlvbiBvZiArXCIweFwiXG5cdFx0cmV0dXJuIGhpZ2ggIT09IGhpZ2ggfHwgZXNjYXBlZFdoaXRlc3BhY2UgP1xuXHRcdFx0ZXNjYXBlZCA6XG5cdFx0XHRoaWdoIDwgMCA/XG5cdFx0XHRcdC8vIEJNUCBjb2RlcG9pbnRcblx0XHRcdFx0U3RyaW5nLmZyb21DaGFyQ29kZSggaGlnaCArIDB4MTAwMDAgKSA6XG5cdFx0XHRcdC8vIFN1cHBsZW1lbnRhbCBQbGFuZSBjb2RlcG9pbnQgKHN1cnJvZ2F0ZSBwYWlyKVxuXHRcdFx0XHRTdHJpbmcuZnJvbUNoYXJDb2RlKCBoaWdoID4+IDEwIHwgMHhEODAwLCBoaWdoICYgMHgzRkYgfCAweERDMDAgKTtcblx0fSxcblxuXHQvLyBDU1Mgc3RyaW5nL2lkZW50aWZpZXIgc2VyaWFsaXphdGlvblxuXHQvLyBodHRwczovL2RyYWZ0cy5jc3N3Zy5vcmcvY3Nzb20vI2NvbW1vbi1zZXJpYWxpemluZy1pZGlvbXNcblx0cmNzc2VzY2FwZSA9IC8oW1xcMC1cXHgxZlxceDdmXXxeLT9cXGQpfF4tJHxbXlxcMC1cXHgxZlxceDdmLVxcdUZGRkZcXHctXS9nLFxuXHRmY3NzZXNjYXBlID0gZnVuY3Rpb24oIGNoLCBhc0NvZGVQb2ludCApIHtcblx0XHRpZiAoIGFzQ29kZVBvaW50ICkge1xuXG5cdFx0XHQvLyBVKzAwMDAgTlVMTCBiZWNvbWVzIFUrRkZGRCBSRVBMQUNFTUVOVCBDSEFSQUNURVJcblx0XHRcdGlmICggY2ggPT09IFwiXFwwXCIgKSB7XG5cdFx0XHRcdHJldHVybiBcIlxcdUZGRkRcIjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ29udHJvbCBjaGFyYWN0ZXJzIGFuZCAoZGVwZW5kZW50IHVwb24gcG9zaXRpb24pIG51bWJlcnMgZ2V0IGVzY2FwZWQgYXMgY29kZSBwb2ludHNcblx0XHRcdHJldHVybiBjaC5zbGljZSggMCwgLTEgKSArIFwiXFxcXFwiICsgY2guY2hhckNvZGVBdCggY2gubGVuZ3RoIC0gMSApLnRvU3RyaW5nKCAxNiApICsgXCIgXCI7XG5cdFx0fVxuXG5cdFx0Ly8gT3RoZXIgcG90ZW50aWFsbHktc3BlY2lhbCBBU0NJSSBjaGFyYWN0ZXJzIGdldCBiYWNrc2xhc2gtZXNjYXBlZFxuXHRcdHJldHVybiBcIlxcXFxcIiArIGNoO1xuXHR9LFxuXG5cdC8vIFVzZWQgZm9yIGlmcmFtZXNcblx0Ly8gU2VlIHNldERvY3VtZW50KClcblx0Ly8gUmVtb3ZpbmcgdGhlIGZ1bmN0aW9uIHdyYXBwZXIgY2F1c2VzIGEgXCJQZXJtaXNzaW9uIERlbmllZFwiXG5cdC8vIGVycm9yIGluIElFXG5cdHVubG9hZEhhbmRsZXIgPSBmdW5jdGlvbigpIHtcblx0XHRzZXREb2N1bWVudCgpO1xuXHR9LFxuXG5cdGluRGlzYWJsZWRGaWVsZHNldCA9IGFkZENvbWJpbmF0b3IoXG5cdFx0ZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5kaXNhYmxlZCA9PT0gdHJ1ZSAmJiBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IFwiZmllbGRzZXRcIjtcblx0XHR9LFxuXHRcdHsgZGlyOiBcInBhcmVudE5vZGVcIiwgbmV4dDogXCJsZWdlbmRcIiB9XG5cdCk7XG5cbi8vIE9wdGltaXplIGZvciBwdXNoLmFwcGx5KCBfLCBOb2RlTGlzdCApXG50cnkge1xuXHRwdXNoLmFwcGx5KFxuXHRcdChhcnIgPSBzbGljZS5jYWxsKCBwcmVmZXJyZWREb2MuY2hpbGROb2RlcyApKSxcblx0XHRwcmVmZXJyZWREb2MuY2hpbGROb2Rlc1xuXHQpO1xuXHQvLyBTdXBwb3J0OiBBbmRyb2lkPDQuMFxuXHQvLyBEZXRlY3Qgc2lsZW50bHkgZmFpbGluZyBwdXNoLmFwcGx5XG5cdGFyclsgcHJlZmVycmVkRG9jLmNoaWxkTm9kZXMubGVuZ3RoIF0ubm9kZVR5cGU7XG59IGNhdGNoICggZSApIHtcblx0cHVzaCA9IHsgYXBwbHk6IGFyci5sZW5ndGggP1xuXG5cdFx0Ly8gTGV2ZXJhZ2Ugc2xpY2UgaWYgcG9zc2libGVcblx0XHRmdW5jdGlvbiggdGFyZ2V0LCBlbHMgKSB7XG5cdFx0XHRwdXNoX25hdGl2ZS5hcHBseSggdGFyZ2V0LCBzbGljZS5jYWxsKGVscykgKTtcblx0XHR9IDpcblxuXHRcdC8vIFN1cHBvcnQ6IElFPDlcblx0XHQvLyBPdGhlcndpc2UgYXBwZW5kIGRpcmVjdGx5XG5cdFx0ZnVuY3Rpb24oIHRhcmdldCwgZWxzICkge1xuXHRcdFx0dmFyIGogPSB0YXJnZXQubGVuZ3RoLFxuXHRcdFx0XHRpID0gMDtcblx0XHRcdC8vIENhbid0IHRydXN0IE5vZGVMaXN0Lmxlbmd0aFxuXHRcdFx0d2hpbGUgKCAodGFyZ2V0W2orK10gPSBlbHNbaSsrXSkgKSB7fVxuXHRcdFx0dGFyZ2V0Lmxlbmd0aCA9IGogLSAxO1xuXHRcdH1cblx0fTtcbn1cblxuZnVuY3Rpb24gU2l6emxlKCBzZWxlY3RvciwgY29udGV4dCwgcmVzdWx0cywgc2VlZCApIHtcblx0dmFyIG0sIGksIGVsZW0sIG5pZCwgbWF0Y2gsIGdyb3VwcywgbmV3U2VsZWN0b3IsXG5cdFx0bmV3Q29udGV4dCA9IGNvbnRleHQgJiYgY29udGV4dC5vd25lckRvY3VtZW50LFxuXG5cdFx0Ly8gbm9kZVR5cGUgZGVmYXVsdHMgdG8gOSwgc2luY2UgY29udGV4dCBkZWZhdWx0cyB0byBkb2N1bWVudFxuXHRcdG5vZGVUeXBlID0gY29udGV4dCA/IGNvbnRleHQubm9kZVR5cGUgOiA5O1xuXG5cdHJlc3VsdHMgPSByZXN1bHRzIHx8IFtdO1xuXG5cdC8vIFJldHVybiBlYXJseSBmcm9tIGNhbGxzIHdpdGggaW52YWxpZCBzZWxlY3RvciBvciBjb250ZXh0XG5cdGlmICggdHlwZW9mIHNlbGVjdG9yICE9PSBcInN0cmluZ1wiIHx8ICFzZWxlY3RvciB8fFxuXHRcdG5vZGVUeXBlICE9PSAxICYmIG5vZGVUeXBlICE9PSA5ICYmIG5vZGVUeXBlICE9PSAxMSApIHtcblxuXHRcdHJldHVybiByZXN1bHRzO1xuXHR9XG5cblx0Ly8gVHJ5IHRvIHNob3J0Y3V0IGZpbmQgb3BlcmF0aW9ucyAoYXMgb3Bwb3NlZCB0byBmaWx0ZXJzKSBpbiBIVE1MIGRvY3VtZW50c1xuXHRpZiAoICFzZWVkICkge1xuXG5cdFx0aWYgKCAoIGNvbnRleHQgPyBjb250ZXh0Lm93bmVyRG9jdW1lbnQgfHwgY29udGV4dCA6IHByZWZlcnJlZERvYyApICE9PSBkb2N1bWVudCApIHtcblx0XHRcdHNldERvY3VtZW50KCBjb250ZXh0ICk7XG5cdFx0fVxuXHRcdGNvbnRleHQgPSBjb250ZXh0IHx8IGRvY3VtZW50O1xuXG5cdFx0aWYgKCBkb2N1bWVudElzSFRNTCApIHtcblxuXHRcdFx0Ly8gSWYgdGhlIHNlbGVjdG9yIGlzIHN1ZmZpY2llbnRseSBzaW1wbGUsIHRyeSB1c2luZyBhIFwiZ2V0KkJ5KlwiIERPTSBtZXRob2Rcblx0XHRcdC8vIChleGNlcHRpbmcgRG9jdW1lbnRGcmFnbWVudCBjb250ZXh0LCB3aGVyZSB0aGUgbWV0aG9kcyBkb24ndCBleGlzdClcblx0XHRcdGlmICggbm9kZVR5cGUgIT09IDExICYmIChtYXRjaCA9IHJxdWlja0V4cHIuZXhlYyggc2VsZWN0b3IgKSkgKSB7XG5cblx0XHRcdFx0Ly8gSUQgc2VsZWN0b3Jcblx0XHRcdFx0aWYgKCAobSA9IG1hdGNoWzFdKSApIHtcblxuXHRcdFx0XHRcdC8vIERvY3VtZW50IGNvbnRleHRcblx0XHRcdFx0XHRpZiAoIG5vZGVUeXBlID09PSA5ICkge1xuXHRcdFx0XHRcdFx0aWYgKCAoZWxlbSA9IGNvbnRleHQuZ2V0RWxlbWVudEJ5SWQoIG0gKSkgKSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUsIE9wZXJhLCBXZWJraXRcblx0XHRcdFx0XHRcdFx0Ly8gVE9ETzogaWRlbnRpZnkgdmVyc2lvbnNcblx0XHRcdFx0XHRcdFx0Ly8gZ2V0RWxlbWVudEJ5SWQgY2FuIG1hdGNoIGVsZW1lbnRzIGJ5IG5hbWUgaW5zdGVhZCBvZiBJRFxuXHRcdFx0XHRcdFx0XHRpZiAoIGVsZW0uaWQgPT09IG0gKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmVzdWx0cy5wdXNoKCBlbGVtICk7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiByZXN1bHRzO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gRWxlbWVudCBjb250ZXh0XG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUsIE9wZXJhLCBXZWJraXRcblx0XHRcdFx0XHRcdC8vIFRPRE86IGlkZW50aWZ5IHZlcnNpb25zXG5cdFx0XHRcdFx0XHQvLyBnZXRFbGVtZW50QnlJZCBjYW4gbWF0Y2ggZWxlbWVudHMgYnkgbmFtZSBpbnN0ZWFkIG9mIElEXG5cdFx0XHRcdFx0XHRpZiAoIG5ld0NvbnRleHQgJiYgKGVsZW0gPSBuZXdDb250ZXh0LmdldEVsZW1lbnRCeUlkKCBtICkpICYmXG5cdFx0XHRcdFx0XHRcdGNvbnRhaW5zKCBjb250ZXh0LCBlbGVtICkgJiZcblx0XHRcdFx0XHRcdFx0ZWxlbS5pZCA9PT0gbSApIHtcblxuXHRcdFx0XHRcdFx0XHRyZXN1bHRzLnB1c2goIGVsZW0gKTtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFR5cGUgc2VsZWN0b3Jcblx0XHRcdFx0fSBlbHNlIGlmICggbWF0Y2hbMl0gKSB7XG5cdFx0XHRcdFx0cHVzaC5hcHBseSggcmVzdWx0cywgY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSggc2VsZWN0b3IgKSApO1xuXHRcdFx0XHRcdHJldHVybiByZXN1bHRzO1xuXG5cdFx0XHRcdC8vIENsYXNzIHNlbGVjdG9yXG5cdFx0XHRcdH0gZWxzZSBpZiAoIChtID0gbWF0Y2hbM10pICYmIHN1cHBvcnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSAmJlxuXHRcdFx0XHRcdGNvbnRleHQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSApIHtcblxuXHRcdFx0XHRcdHB1c2guYXBwbHkoIHJlc3VsdHMsIGNvbnRleHQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSggbSApICk7XG5cdFx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Ly8gVGFrZSBhZHZhbnRhZ2Ugb2YgcXVlcnlTZWxlY3RvckFsbFxuXHRcdFx0aWYgKCBzdXBwb3J0LnFzYSAmJlxuXHRcdFx0XHQhbm9ubmF0aXZlU2VsZWN0b3JDYWNoZVsgc2VsZWN0b3IgKyBcIiBcIiBdICYmXG5cdFx0XHRcdCghcmJ1Z2d5UVNBIHx8ICFyYnVnZ3lRU0EudGVzdCggc2VsZWN0b3IgKSkgJiZcblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA4IG9ubHlcblx0XHRcdFx0Ly8gRXhjbHVkZSBvYmplY3QgZWxlbWVudHNcblx0XHRcdFx0KG5vZGVUeXBlICE9PSAxIHx8IGNvbnRleHQubm9kZU5hbWUudG9Mb3dlckNhc2UoKSAhPT0gXCJvYmplY3RcIikgKSB7XG5cblx0XHRcdFx0bmV3U2VsZWN0b3IgPSBzZWxlY3Rvcjtcblx0XHRcdFx0bmV3Q29udGV4dCA9IGNvbnRleHQ7XG5cblx0XHRcdFx0Ly8gcVNBIGNvbnNpZGVycyBlbGVtZW50cyBvdXRzaWRlIGEgc2NvcGluZyByb290IHdoZW4gZXZhbHVhdGluZyBjaGlsZCBvclxuXHRcdFx0XHQvLyBkZXNjZW5kYW50IGNvbWJpbmF0b3JzLCB3aGljaCBpcyBub3Qgd2hhdCB3ZSB3YW50LlxuXHRcdFx0XHQvLyBJbiBzdWNoIGNhc2VzLCB3ZSB3b3JrIGFyb3VuZCB0aGUgYmVoYXZpb3IgYnkgcHJlZml4aW5nIGV2ZXJ5IHNlbGVjdG9yIGluIHRoZVxuXHRcdFx0XHQvLyBsaXN0IHdpdGggYW4gSUQgc2VsZWN0b3IgcmVmZXJlbmNpbmcgdGhlIHNjb3BlIGNvbnRleHQuXG5cdFx0XHRcdC8vIFRoYW5rcyB0byBBbmRyZXcgRHVwb250IGZvciB0aGlzIHRlY2huaXF1ZS5cblx0XHRcdFx0aWYgKCBub2RlVHlwZSA9PT0gMSAmJiByZGVzY2VuZC50ZXN0KCBzZWxlY3RvciApICkge1xuXG5cdFx0XHRcdFx0Ly8gQ2FwdHVyZSB0aGUgY29udGV4dCBJRCwgc2V0dGluZyBpdCBmaXJzdCBpZiBuZWNlc3Nhcnlcblx0XHRcdFx0XHRpZiAoIChuaWQgPSBjb250ZXh0LmdldEF0dHJpYnV0ZSggXCJpZFwiICkpICkge1xuXHRcdFx0XHRcdFx0bmlkID0gbmlkLnJlcGxhY2UoIHJjc3Nlc2NhcGUsIGZjc3Nlc2NhcGUgKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0Y29udGV4dC5zZXRBdHRyaWJ1dGUoIFwiaWRcIiwgKG5pZCA9IGV4cGFuZG8pICk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gUHJlZml4IGV2ZXJ5IHNlbGVjdG9yIGluIHRoZSBsaXN0XG5cdFx0XHRcdFx0Z3JvdXBzID0gdG9rZW5pemUoIHNlbGVjdG9yICk7XG5cdFx0XHRcdFx0aSA9IGdyb3Vwcy5sZW5ndGg7XG5cdFx0XHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdFx0XHRncm91cHNbaV0gPSBcIiNcIiArIG5pZCArIFwiIFwiICsgdG9TZWxlY3RvciggZ3JvdXBzW2ldICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdG5ld1NlbGVjdG9yID0gZ3JvdXBzLmpvaW4oIFwiLFwiICk7XG5cblx0XHRcdFx0XHQvLyBFeHBhbmQgY29udGV4dCBmb3Igc2libGluZyBzZWxlY3RvcnNcblx0XHRcdFx0XHRuZXdDb250ZXh0ID0gcnNpYmxpbmcudGVzdCggc2VsZWN0b3IgKSAmJiB0ZXN0Q29udGV4dCggY29udGV4dC5wYXJlbnROb2RlICkgfHxcblx0XHRcdFx0XHRcdGNvbnRleHQ7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdHB1c2guYXBwbHkoIHJlc3VsdHMsXG5cdFx0XHRcdFx0XHRuZXdDb250ZXh0LnF1ZXJ5U2VsZWN0b3JBbGwoIG5ld1NlbGVjdG9yIClcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdHJldHVybiByZXN1bHRzO1xuXHRcdFx0XHR9IGNhdGNoICggcXNhRXJyb3IgKSB7XG5cdFx0XHRcdFx0bm9ubmF0aXZlU2VsZWN0b3JDYWNoZSggc2VsZWN0b3IsIHRydWUgKTtcblx0XHRcdFx0fSBmaW5hbGx5IHtcblx0XHRcdFx0XHRpZiAoIG5pZCA9PT0gZXhwYW5kbyApIHtcblx0XHRcdFx0XHRcdGNvbnRleHQucmVtb3ZlQXR0cmlidXRlKCBcImlkXCIgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLyBBbGwgb3RoZXJzXG5cdHJldHVybiBzZWxlY3QoIHNlbGVjdG9yLnJlcGxhY2UoIHJ0cmltLCBcIiQxXCIgKSwgY29udGV4dCwgcmVzdWx0cywgc2VlZCApO1xufVxuXG4vKipcbiAqIENyZWF0ZSBrZXktdmFsdWUgY2FjaGVzIG9mIGxpbWl0ZWQgc2l6ZVxuICogQHJldHVybnMge2Z1bmN0aW9uKHN0cmluZywgb2JqZWN0KX0gUmV0dXJucyB0aGUgT2JqZWN0IGRhdGEgYWZ0ZXIgc3RvcmluZyBpdCBvbiBpdHNlbGYgd2l0aFxuICpcdHByb3BlcnR5IG5hbWUgdGhlIChzcGFjZS1zdWZmaXhlZCkgc3RyaW5nIGFuZCAoaWYgdGhlIGNhY2hlIGlzIGxhcmdlciB0aGFuIEV4cHIuY2FjaGVMZW5ndGgpXG4gKlx0ZGVsZXRpbmcgdGhlIG9sZGVzdCBlbnRyeVxuICovXG5mdW5jdGlvbiBjcmVhdGVDYWNoZSgpIHtcblx0dmFyIGtleXMgPSBbXTtcblxuXHRmdW5jdGlvbiBjYWNoZSgga2V5LCB2YWx1ZSApIHtcblx0XHQvLyBVc2UgKGtleSArIFwiIFwiKSB0byBhdm9pZCBjb2xsaXNpb24gd2l0aCBuYXRpdmUgcHJvdG90eXBlIHByb3BlcnRpZXMgKHNlZSBJc3N1ZSAjMTU3KVxuXHRcdGlmICgga2V5cy5wdXNoKCBrZXkgKyBcIiBcIiApID4gRXhwci5jYWNoZUxlbmd0aCApIHtcblx0XHRcdC8vIE9ubHkga2VlcCB0aGUgbW9zdCByZWNlbnQgZW50cmllc1xuXHRcdFx0ZGVsZXRlIGNhY2hlWyBrZXlzLnNoaWZ0KCkgXTtcblx0XHR9XG5cdFx0cmV0dXJuIChjYWNoZVsga2V5ICsgXCIgXCIgXSA9IHZhbHVlKTtcblx0fVxuXHRyZXR1cm4gY2FjaGU7XG59XG5cbi8qKlxuICogTWFyayBhIGZ1bmN0aW9uIGZvciBzcGVjaWFsIHVzZSBieSBTaXp6bGVcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIFRoZSBmdW5jdGlvbiB0byBtYXJrXG4gKi9cbmZ1bmN0aW9uIG1hcmtGdW5jdGlvbiggZm4gKSB7XG5cdGZuWyBleHBhbmRvIF0gPSB0cnVlO1xuXHRyZXR1cm4gZm47XG59XG5cbi8qKlxuICogU3VwcG9ydCB0ZXN0aW5nIHVzaW5nIGFuIGVsZW1lbnRcbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIFBhc3NlZCB0aGUgY3JlYXRlZCBlbGVtZW50IGFuZCByZXR1cm5zIGEgYm9vbGVhbiByZXN1bHRcbiAqL1xuZnVuY3Rpb24gYXNzZXJ0KCBmbiApIHtcblx0dmFyIGVsID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImZpZWxkc2V0XCIpO1xuXG5cdHRyeSB7XG5cdFx0cmV0dXJuICEhZm4oIGVsICk7XG5cdH0gY2F0Y2ggKGUpIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0gZmluYWxseSB7XG5cdFx0Ly8gUmVtb3ZlIGZyb20gaXRzIHBhcmVudCBieSBkZWZhdWx0XG5cdFx0aWYgKCBlbC5wYXJlbnROb2RlICkge1xuXHRcdFx0ZWwucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggZWwgKTtcblx0XHR9XG5cdFx0Ly8gcmVsZWFzZSBtZW1vcnkgaW4gSUVcblx0XHRlbCA9IG51bGw7XG5cdH1cbn1cblxuLyoqXG4gKiBBZGRzIHRoZSBzYW1lIGhhbmRsZXIgZm9yIGFsbCBvZiB0aGUgc3BlY2lmaWVkIGF0dHJzXG4gKiBAcGFyYW0ge1N0cmluZ30gYXR0cnMgUGlwZS1zZXBhcmF0ZWQgbGlzdCBvZiBhdHRyaWJ1dGVzXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBoYW5kbGVyIFRoZSBtZXRob2QgdGhhdCB3aWxsIGJlIGFwcGxpZWRcbiAqL1xuZnVuY3Rpb24gYWRkSGFuZGxlKCBhdHRycywgaGFuZGxlciApIHtcblx0dmFyIGFyciA9IGF0dHJzLnNwbGl0KFwifFwiKSxcblx0XHRpID0gYXJyLmxlbmd0aDtcblxuXHR3aGlsZSAoIGktLSApIHtcblx0XHRFeHByLmF0dHJIYW5kbGVbIGFycltpXSBdID0gaGFuZGxlcjtcblx0fVxufVxuXG4vKipcbiAqIENoZWNrcyBkb2N1bWVudCBvcmRlciBvZiB0d28gc2libGluZ3NcbiAqIEBwYXJhbSB7RWxlbWVudH0gYVxuICogQHBhcmFtIHtFbGVtZW50fSBiXG4gKiBAcmV0dXJucyB7TnVtYmVyfSBSZXR1cm5zIGxlc3MgdGhhbiAwIGlmIGEgcHJlY2VkZXMgYiwgZ3JlYXRlciB0aGFuIDAgaWYgYSBmb2xsb3dzIGJcbiAqL1xuZnVuY3Rpb24gc2libGluZ0NoZWNrKCBhLCBiICkge1xuXHR2YXIgY3VyID0gYiAmJiBhLFxuXHRcdGRpZmYgPSBjdXIgJiYgYS5ub2RlVHlwZSA9PT0gMSAmJiBiLm5vZGVUeXBlID09PSAxICYmXG5cdFx0XHRhLnNvdXJjZUluZGV4IC0gYi5zb3VyY2VJbmRleDtcblxuXHQvLyBVc2UgSUUgc291cmNlSW5kZXggaWYgYXZhaWxhYmxlIG9uIGJvdGggbm9kZXNcblx0aWYgKCBkaWZmICkge1xuXHRcdHJldHVybiBkaWZmO1xuXHR9XG5cblx0Ly8gQ2hlY2sgaWYgYiBmb2xsb3dzIGFcblx0aWYgKCBjdXIgKSB7XG5cdFx0d2hpbGUgKCAoY3VyID0gY3VyLm5leHRTaWJsaW5nKSApIHtcblx0XHRcdGlmICggY3VyID09PSBiICkge1xuXHRcdFx0XHRyZXR1cm4gLTE7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGEgPyAxIDogLTE7XG59XG5cbi8qKlxuICogUmV0dXJucyBhIGZ1bmN0aW9uIHRvIHVzZSBpbiBwc2V1ZG9zIGZvciBpbnB1dCB0eXBlc1xuICogQHBhcmFtIHtTdHJpbmd9IHR5cGVcbiAqL1xuZnVuY3Rpb24gY3JlYXRlSW5wdXRQc2V1ZG8oIHR5cGUgKSB7XG5cdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHR2YXIgbmFtZSA9IGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHRyZXR1cm4gbmFtZSA9PT0gXCJpbnB1dFwiICYmIGVsZW0udHlwZSA9PT0gdHlwZTtcblx0fTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgZnVuY3Rpb24gdG8gdXNlIGluIHBzZXVkb3MgZm9yIGJ1dHRvbnNcbiAqIEBwYXJhbSB7U3RyaW5nfSB0eXBlXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUJ1dHRvblBzZXVkbyggdHlwZSApIHtcblx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHZhciBuYW1lID0gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdHJldHVybiAobmFtZSA9PT0gXCJpbnB1dFwiIHx8IG5hbWUgPT09IFwiYnV0dG9uXCIpICYmIGVsZW0udHlwZSA9PT0gdHlwZTtcblx0fTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGEgZnVuY3Rpb24gdG8gdXNlIGluIHBzZXVkb3MgZm9yIDplbmFibGVkLzpkaXNhYmxlZFxuICogQHBhcmFtIHtCb29sZWFufSBkaXNhYmxlZCB0cnVlIGZvciA6ZGlzYWJsZWQ7IGZhbHNlIGZvciA6ZW5hYmxlZFxuICovXG5mdW5jdGlvbiBjcmVhdGVEaXNhYmxlZFBzZXVkbyggZGlzYWJsZWQgKSB7XG5cblx0Ly8gS25vd24gOmRpc2FibGVkIGZhbHNlIHBvc2l0aXZlczogZmllbGRzZXRbZGlzYWJsZWRdID4gbGVnZW5kOm50aC1vZi10eXBlKG4rMikgOmNhbi1kaXNhYmxlXG5cdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblxuXHRcdC8vIE9ubHkgY2VydGFpbiBlbGVtZW50cyBjYW4gbWF0Y2ggOmVuYWJsZWQgb3IgOmRpc2FibGVkXG5cdFx0Ly8gaHR0cHM6Ly9odG1sLnNwZWMud2hhdHdnLm9yZy9tdWx0aXBhZ2Uvc2NyaXB0aW5nLmh0bWwjc2VsZWN0b3ItZW5hYmxlZFxuXHRcdC8vIGh0dHBzOi8vaHRtbC5zcGVjLndoYXR3Zy5vcmcvbXVsdGlwYWdlL3NjcmlwdGluZy5odG1sI3NlbGVjdG9yLWRpc2FibGVkXG5cdFx0aWYgKCBcImZvcm1cIiBpbiBlbGVtICkge1xuXG5cdFx0XHQvLyBDaGVjayBmb3IgaW5oZXJpdGVkIGRpc2FibGVkbmVzcyBvbiByZWxldmFudCBub24tZGlzYWJsZWQgZWxlbWVudHM6XG5cdFx0XHQvLyAqIGxpc3RlZCBmb3JtLWFzc29jaWF0ZWQgZWxlbWVudHMgaW4gYSBkaXNhYmxlZCBmaWVsZHNldFxuXHRcdFx0Ly8gICBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS9mb3Jtcy5odG1sI2NhdGVnb3J5LWxpc3RlZFxuXHRcdFx0Ly8gICBodHRwczovL2h0bWwuc3BlYy53aGF0d2cub3JnL211bHRpcGFnZS9mb3Jtcy5odG1sI2NvbmNlcHQtZmUtZGlzYWJsZWRcblx0XHRcdC8vICogb3B0aW9uIGVsZW1lbnRzIGluIGEgZGlzYWJsZWQgb3B0Z3JvdXBcblx0XHRcdC8vICAgaHR0cHM6Ly9odG1sLnNwZWMud2hhdHdnLm9yZy9tdWx0aXBhZ2UvZm9ybXMuaHRtbCNjb25jZXB0LW9wdGlvbi1kaXNhYmxlZFxuXHRcdFx0Ly8gQWxsIHN1Y2ggZWxlbWVudHMgaGF2ZSBhIFwiZm9ybVwiIHByb3BlcnR5LlxuXHRcdFx0aWYgKCBlbGVtLnBhcmVudE5vZGUgJiYgZWxlbS5kaXNhYmxlZCA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0Ly8gT3B0aW9uIGVsZW1lbnRzIGRlZmVyIHRvIGEgcGFyZW50IG9wdGdyb3VwIGlmIHByZXNlbnRcblx0XHRcdFx0aWYgKCBcImxhYmVsXCIgaW4gZWxlbSApIHtcblx0XHRcdFx0XHRpZiAoIFwibGFiZWxcIiBpbiBlbGVtLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZWxlbS5wYXJlbnROb2RlLmRpc2FibGVkID09PSBkaXNhYmxlZDtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0cmV0dXJuIGVsZW0uZGlzYWJsZWQgPT09IGRpc2FibGVkO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDYgLSAxMVxuXHRcdFx0XHQvLyBVc2UgdGhlIGlzRGlzYWJsZWQgc2hvcnRjdXQgcHJvcGVydHkgdG8gY2hlY2sgZm9yIGRpc2FibGVkIGZpZWxkc2V0IGFuY2VzdG9yc1xuXHRcdFx0XHRyZXR1cm4gZWxlbS5pc0Rpc2FibGVkID09PSBkaXNhYmxlZCB8fFxuXG5cdFx0XHRcdFx0Ly8gV2hlcmUgdGhlcmUgaXMgbm8gaXNEaXNhYmxlZCwgY2hlY2sgbWFudWFsbHlcblx0XHRcdFx0XHQvKiBqc2hpbnQgLVcwMTggKi9cblx0XHRcdFx0XHRlbGVtLmlzRGlzYWJsZWQgIT09ICFkaXNhYmxlZCAmJlxuXHRcdFx0XHRcdFx0aW5EaXNhYmxlZEZpZWxkc2V0KCBlbGVtICkgPT09IGRpc2FibGVkO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZWxlbS5kaXNhYmxlZCA9PT0gZGlzYWJsZWQ7XG5cblx0XHQvLyBUcnkgdG8gd2lubm93IG91dCBlbGVtZW50cyB0aGF0IGNhbid0IGJlIGRpc2FibGVkIGJlZm9yZSB0cnVzdGluZyB0aGUgZGlzYWJsZWQgcHJvcGVydHkuXG5cdFx0Ly8gU29tZSB2aWN0aW1zIGdldCBjYXVnaHQgaW4gb3VyIG5ldCAobGFiZWwsIGxlZ2VuZCwgbWVudSwgdHJhY2spLCBidXQgaXQgc2hvdWxkbid0XG5cdFx0Ly8gZXZlbiBleGlzdCBvbiB0aGVtLCBsZXQgYWxvbmUgaGF2ZSBhIGJvb2xlYW4gdmFsdWUuXG5cdFx0fSBlbHNlIGlmICggXCJsYWJlbFwiIGluIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5kaXNhYmxlZCA9PT0gZGlzYWJsZWQ7XG5cdFx0fVxuXG5cdFx0Ly8gUmVtYWluaW5nIGVsZW1lbnRzIGFyZSBuZWl0aGVyIDplbmFibGVkIG5vciA6ZGlzYWJsZWRcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH07XG59XG5cbi8qKlxuICogUmV0dXJucyBhIGZ1bmN0aW9uIHRvIHVzZSBpbiBwc2V1ZG9zIGZvciBwb3NpdGlvbmFsc1xuICogQHBhcmFtIHtGdW5jdGlvbn0gZm5cbiAqL1xuZnVuY3Rpb24gY3JlYXRlUG9zaXRpb25hbFBzZXVkbyggZm4gKSB7XG5cdHJldHVybiBtYXJrRnVuY3Rpb24oZnVuY3Rpb24oIGFyZ3VtZW50ICkge1xuXHRcdGFyZ3VtZW50ID0gK2FyZ3VtZW50O1xuXHRcdHJldHVybiBtYXJrRnVuY3Rpb24oZnVuY3Rpb24oIHNlZWQsIG1hdGNoZXMgKSB7XG5cdFx0XHR2YXIgaixcblx0XHRcdFx0bWF0Y2hJbmRleGVzID0gZm4oIFtdLCBzZWVkLmxlbmd0aCwgYXJndW1lbnQgKSxcblx0XHRcdFx0aSA9IG1hdGNoSW5kZXhlcy5sZW5ndGg7XG5cblx0XHRcdC8vIE1hdGNoIGVsZW1lbnRzIGZvdW5kIGF0IHRoZSBzcGVjaWZpZWQgaW5kZXhlc1xuXHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdGlmICggc2VlZFsgKGogPSBtYXRjaEluZGV4ZXNbaV0pIF0gKSB7XG5cdFx0XHRcdFx0c2VlZFtqXSA9ICEobWF0Y2hlc1tqXSA9IHNlZWRbal0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSk7XG5cdH0pO1xufVxuXG4vKipcbiAqIENoZWNrcyBhIG5vZGUgZm9yIHZhbGlkaXR5IGFzIGEgU2l6emxlIGNvbnRleHRcbiAqIEBwYXJhbSB7RWxlbWVudHxPYmplY3Q9fSBjb250ZXh0XG4gKiBAcmV0dXJucyB7RWxlbWVudHxPYmplY3R8Qm9vbGVhbn0gVGhlIGlucHV0IG5vZGUgaWYgYWNjZXB0YWJsZSwgb3RoZXJ3aXNlIGEgZmFsc3kgdmFsdWVcbiAqL1xuZnVuY3Rpb24gdGVzdENvbnRleHQoIGNvbnRleHQgKSB7XG5cdHJldHVybiBjb250ZXh0ICYmIHR5cGVvZiBjb250ZXh0LmdldEVsZW1lbnRzQnlUYWdOYW1lICE9PSBcInVuZGVmaW5lZFwiICYmIGNvbnRleHQ7XG59XG5cbi8vIEV4cG9zZSBzdXBwb3J0IHZhcnMgZm9yIGNvbnZlbmllbmNlXG5zdXBwb3J0ID0gU2l6emxlLnN1cHBvcnQgPSB7fTtcblxuLyoqXG4gKiBEZXRlY3RzIFhNTCBub2Rlc1xuICogQHBhcmFtIHtFbGVtZW50fE9iamVjdH0gZWxlbSBBbiBlbGVtZW50IG9yIGEgZG9jdW1lbnRcbiAqIEByZXR1cm5zIHtCb29sZWFufSBUcnVlIGlmZiBlbGVtIGlzIGEgbm9uLUhUTUwgWE1MIG5vZGVcbiAqL1xuaXNYTUwgPSBTaXp6bGUuaXNYTUwgPSBmdW5jdGlvbiggZWxlbSApIHtcblx0dmFyIG5hbWVzcGFjZSA9IGVsZW0ubmFtZXNwYWNlVVJJLFxuXHRcdGRvY0VsZW0gPSAoZWxlbS5vd25lckRvY3VtZW50IHx8IGVsZW0pLmRvY3VtZW50RWxlbWVudDtcblxuXHQvLyBTdXBwb3J0OiBJRSA8PThcblx0Ly8gQXNzdW1lIEhUTUwgd2hlbiBkb2N1bWVudEVsZW1lbnQgZG9lc24ndCB5ZXQgZXhpc3QsIHN1Y2ggYXMgaW5zaWRlIGxvYWRpbmcgaWZyYW1lc1xuXHQvLyBodHRwczovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvNDgzM1xuXHRyZXR1cm4gIXJodG1sLnRlc3QoIG5hbWVzcGFjZSB8fCBkb2NFbGVtICYmIGRvY0VsZW0ubm9kZU5hbWUgfHwgXCJIVE1MXCIgKTtcbn07XG5cbi8qKlxuICogU2V0cyBkb2N1bWVudC1yZWxhdGVkIHZhcmlhYmxlcyBvbmNlIGJhc2VkIG9uIHRoZSBjdXJyZW50IGRvY3VtZW50XG4gKiBAcGFyYW0ge0VsZW1lbnR8T2JqZWN0fSBbZG9jXSBBbiBlbGVtZW50IG9yIGRvY3VtZW50IG9iamVjdCB0byB1c2UgdG8gc2V0IHRoZSBkb2N1bWVudFxuICogQHJldHVybnMge09iamVjdH0gUmV0dXJucyB0aGUgY3VycmVudCBkb2N1bWVudFxuICovXG5zZXREb2N1bWVudCA9IFNpenpsZS5zZXREb2N1bWVudCA9IGZ1bmN0aW9uKCBub2RlICkge1xuXHR2YXIgaGFzQ29tcGFyZSwgc3ViV2luZG93LFxuXHRcdGRvYyA9IG5vZGUgPyBub2RlLm93bmVyRG9jdW1lbnQgfHwgbm9kZSA6IHByZWZlcnJlZERvYztcblxuXHQvLyBSZXR1cm4gZWFybHkgaWYgZG9jIGlzIGludmFsaWQgb3IgYWxyZWFkeSBzZWxlY3RlZFxuXHRpZiAoIGRvYyA9PT0gZG9jdW1lbnQgfHwgZG9jLm5vZGVUeXBlICE9PSA5IHx8ICFkb2MuZG9jdW1lbnRFbGVtZW50ICkge1xuXHRcdHJldHVybiBkb2N1bWVudDtcblx0fVxuXG5cdC8vIFVwZGF0ZSBnbG9iYWwgdmFyaWFibGVzXG5cdGRvY3VtZW50ID0gZG9jO1xuXHRkb2NFbGVtID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50O1xuXHRkb2N1bWVudElzSFRNTCA9ICFpc1hNTCggZG9jdW1lbnQgKTtcblxuXHQvLyBTdXBwb3J0OiBJRSA5LTExLCBFZGdlXG5cdC8vIEFjY2Vzc2luZyBpZnJhbWUgZG9jdW1lbnRzIGFmdGVyIHVubG9hZCB0aHJvd3MgXCJwZXJtaXNzaW9uIGRlbmllZFwiIGVycm9ycyAoalF1ZXJ5ICMxMzkzNilcblx0aWYgKCBwcmVmZXJyZWREb2MgIT09IGRvY3VtZW50ICYmXG5cdFx0KHN1YldpbmRvdyA9IGRvY3VtZW50LmRlZmF1bHRWaWV3KSAmJiBzdWJXaW5kb3cudG9wICE9PSBzdWJXaW5kb3cgKSB7XG5cblx0XHQvLyBTdXBwb3J0OiBJRSAxMSwgRWRnZVxuXHRcdGlmICggc3ViV2luZG93LmFkZEV2ZW50TGlzdGVuZXIgKSB7XG5cdFx0XHRzdWJXaW5kb3cuYWRkRXZlbnRMaXN0ZW5lciggXCJ1bmxvYWRcIiwgdW5sb2FkSGFuZGxlciwgZmFsc2UgKTtcblxuXHRcdC8vIFN1cHBvcnQ6IElFIDkgLSAxMCBvbmx5XG5cdFx0fSBlbHNlIGlmICggc3ViV2luZG93LmF0dGFjaEV2ZW50ICkge1xuXHRcdFx0c3ViV2luZG93LmF0dGFjaEV2ZW50KCBcIm9udW5sb2FkXCIsIHVubG9hZEhhbmRsZXIgKTtcblx0XHR9XG5cdH1cblxuXHQvKiBBdHRyaWJ1dGVzXG5cdC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblxuXHQvLyBTdXBwb3J0OiBJRTw4XG5cdC8vIFZlcmlmeSB0aGF0IGdldEF0dHJpYnV0ZSByZWFsbHkgcmV0dXJucyBhdHRyaWJ1dGVzIGFuZCBub3QgcHJvcGVydGllc1xuXHQvLyAoZXhjZXB0aW5nIElFOCBib29sZWFucylcblx0c3VwcG9ydC5hdHRyaWJ1dGVzID0gYXNzZXJ0KGZ1bmN0aW9uKCBlbCApIHtcblx0XHRlbC5jbGFzc05hbWUgPSBcImlcIjtcblx0XHRyZXR1cm4gIWVsLmdldEF0dHJpYnV0ZShcImNsYXNzTmFtZVwiKTtcblx0fSk7XG5cblx0LyogZ2V0RWxlbWVudChzKUJ5KlxuXHQtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cblx0Ly8gQ2hlY2sgaWYgZ2V0RWxlbWVudHNCeVRhZ05hbWUoXCIqXCIpIHJldHVybnMgb25seSBlbGVtZW50c1xuXHRzdXBwb3J0LmdldEVsZW1lbnRzQnlUYWdOYW1lID0gYXNzZXJ0KGZ1bmN0aW9uKCBlbCApIHtcblx0XHRlbC5hcHBlbmRDaGlsZCggZG9jdW1lbnQuY3JlYXRlQ29tbWVudChcIlwiKSApO1xuXHRcdHJldHVybiAhZWwuZ2V0RWxlbWVudHNCeVRhZ05hbWUoXCIqXCIpLmxlbmd0aDtcblx0fSk7XG5cblx0Ly8gU3VwcG9ydDogSUU8OVxuXHRzdXBwb3J0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgPSBybmF0aXZlLnRlc3QoIGRvY3VtZW50LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgKTtcblxuXHQvLyBTdXBwb3J0OiBJRTwxMFxuXHQvLyBDaGVjayBpZiBnZXRFbGVtZW50QnlJZCByZXR1cm5zIGVsZW1lbnRzIGJ5IG5hbWVcblx0Ly8gVGhlIGJyb2tlbiBnZXRFbGVtZW50QnlJZCBtZXRob2RzIGRvbid0IHBpY2sgdXAgcHJvZ3JhbW1hdGljYWxseS1zZXQgbmFtZXMsXG5cdC8vIHNvIHVzZSBhIHJvdW5kYWJvdXQgZ2V0RWxlbWVudHNCeU5hbWUgdGVzdFxuXHRzdXBwb3J0LmdldEJ5SWQgPSBhc3NlcnQoZnVuY3Rpb24oIGVsICkge1xuXHRcdGRvY0VsZW0uYXBwZW5kQ2hpbGQoIGVsICkuaWQgPSBleHBhbmRvO1xuXHRcdHJldHVybiAhZG9jdW1lbnQuZ2V0RWxlbWVudHNCeU5hbWUgfHwgIWRvY3VtZW50LmdldEVsZW1lbnRzQnlOYW1lKCBleHBhbmRvICkubGVuZ3RoO1xuXHR9KTtcblxuXHQvLyBJRCBmaWx0ZXIgYW5kIGZpbmRcblx0aWYgKCBzdXBwb3J0LmdldEJ5SWQgKSB7XG5cdFx0RXhwci5maWx0ZXJbXCJJRFwiXSA9IGZ1bmN0aW9uKCBpZCApIHtcblx0XHRcdHZhciBhdHRySWQgPSBpZC5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApO1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHRyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGUoXCJpZFwiKSA9PT0gYXR0cklkO1xuXHRcdFx0fTtcblx0XHR9O1xuXHRcdEV4cHIuZmluZFtcIklEXCJdID0gZnVuY3Rpb24oIGlkLCBjb250ZXh0ICkge1xuXHRcdFx0aWYgKCB0eXBlb2YgY29udGV4dC5nZXRFbGVtZW50QnlJZCAhPT0gXCJ1bmRlZmluZWRcIiAmJiBkb2N1bWVudElzSFRNTCApIHtcblx0XHRcdFx0dmFyIGVsZW0gPSBjb250ZXh0LmdldEVsZW1lbnRCeUlkKCBpZCApO1xuXHRcdFx0XHRyZXR1cm4gZWxlbSA/IFsgZWxlbSBdIDogW107XG5cdFx0XHR9XG5cdFx0fTtcblx0fSBlbHNlIHtcblx0XHRFeHByLmZpbHRlcltcIklEXCJdID0gIGZ1bmN0aW9uKCBpZCApIHtcblx0XHRcdHZhciBhdHRySWQgPSBpZC5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApO1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHR2YXIgbm9kZSA9IHR5cGVvZiBlbGVtLmdldEF0dHJpYnV0ZU5vZGUgIT09IFwidW5kZWZpbmVkXCIgJiZcblx0XHRcdFx0XHRlbGVtLmdldEF0dHJpYnV0ZU5vZGUoXCJpZFwiKTtcblx0XHRcdFx0cmV0dXJuIG5vZGUgJiYgbm9kZS52YWx1ZSA9PT0gYXR0cklkO1xuXHRcdFx0fTtcblx0XHR9O1xuXG5cdFx0Ly8gU3VwcG9ydDogSUUgNiAtIDcgb25seVxuXHRcdC8vIGdldEVsZW1lbnRCeUlkIGlzIG5vdCByZWxpYWJsZSBhcyBhIGZpbmQgc2hvcnRjdXRcblx0XHRFeHByLmZpbmRbXCJJRFwiXSA9IGZ1bmN0aW9uKCBpZCwgY29udGV4dCApIHtcblx0XHRcdGlmICggdHlwZW9mIGNvbnRleHQuZ2V0RWxlbWVudEJ5SWQgIT09IFwidW5kZWZpbmVkXCIgJiYgZG9jdW1lbnRJc0hUTUwgKSB7XG5cdFx0XHRcdHZhciBub2RlLCBpLCBlbGVtcyxcblx0XHRcdFx0XHRlbGVtID0gY29udGV4dC5nZXRFbGVtZW50QnlJZCggaWQgKTtcblxuXHRcdFx0XHRpZiAoIGVsZW0gKSB7XG5cblx0XHRcdFx0XHQvLyBWZXJpZnkgdGhlIGlkIGF0dHJpYnV0ZVxuXHRcdFx0XHRcdG5vZGUgPSBlbGVtLmdldEF0dHJpYnV0ZU5vZGUoXCJpZFwiKTtcblx0XHRcdFx0XHRpZiAoIG5vZGUgJiYgbm9kZS52YWx1ZSA9PT0gaWQgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gWyBlbGVtIF07XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gRmFsbCBiYWNrIG9uIGdldEVsZW1lbnRzQnlOYW1lXG5cdFx0XHRcdFx0ZWxlbXMgPSBjb250ZXh0LmdldEVsZW1lbnRzQnlOYW1lKCBpZCApO1xuXHRcdFx0XHRcdGkgPSAwO1xuXHRcdFx0XHRcdHdoaWxlICggKGVsZW0gPSBlbGVtc1tpKytdKSApIHtcblx0XHRcdFx0XHRcdG5vZGUgPSBlbGVtLmdldEF0dHJpYnV0ZU5vZGUoXCJpZFwiKTtcblx0XHRcdFx0XHRcdGlmICggbm9kZSAmJiBub2RlLnZhbHVlID09PSBpZCApIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIFsgZWxlbSBdO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBbXTtcblx0XHRcdH1cblx0XHR9O1xuXHR9XG5cblx0Ly8gVGFnXG5cdEV4cHIuZmluZFtcIlRBR1wiXSA9IHN1cHBvcnQuZ2V0RWxlbWVudHNCeVRhZ05hbWUgP1xuXHRcdGZ1bmN0aW9uKCB0YWcsIGNvbnRleHQgKSB7XG5cdFx0XHRpZiAoIHR5cGVvZiBjb250ZXh0LmdldEVsZW1lbnRzQnlUYWdOYW1lICE9PSBcInVuZGVmaW5lZFwiICkge1xuXHRcdFx0XHRyZXR1cm4gY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSggdGFnICk7XG5cblx0XHRcdC8vIERvY3VtZW50RnJhZ21lbnQgbm9kZXMgZG9uJ3QgaGF2ZSBnRUJUTlxuXHRcdFx0fSBlbHNlIGlmICggc3VwcG9ydC5xc2EgKSB7XG5cdFx0XHRcdHJldHVybiBjb250ZXh0LnF1ZXJ5U2VsZWN0b3JBbGwoIHRhZyApO1xuXHRcdFx0fVxuXHRcdH0gOlxuXG5cdFx0ZnVuY3Rpb24oIHRhZywgY29udGV4dCApIHtcblx0XHRcdHZhciBlbGVtLFxuXHRcdFx0XHR0bXAgPSBbXSxcblx0XHRcdFx0aSA9IDAsXG5cdFx0XHRcdC8vIEJ5IGhhcHB5IGNvaW5jaWRlbmNlLCBhIChicm9rZW4pIGdFQlROIGFwcGVhcnMgb24gRG9jdW1lbnRGcmFnbWVudCBub2RlcyB0b29cblx0XHRcdFx0cmVzdWx0cyA9IGNvbnRleHQuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIHRhZyApO1xuXG5cdFx0XHQvLyBGaWx0ZXIgb3V0IHBvc3NpYmxlIGNvbW1lbnRzXG5cdFx0XHRpZiAoIHRhZyA9PT0gXCIqXCIgKSB7XG5cdFx0XHRcdHdoaWxlICggKGVsZW0gPSByZXN1bHRzW2krK10pICkge1xuXHRcdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRcdFx0XHRcdHRtcC5wdXNoKCBlbGVtICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIHRtcDtcblx0XHRcdH1cblx0XHRcdHJldHVybiByZXN1bHRzO1xuXHRcdH07XG5cblx0Ly8gQ2xhc3Ncblx0RXhwci5maW5kW1wiQ0xBU1NcIl0gPSBzdXBwb3J0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgJiYgZnVuY3Rpb24oIGNsYXNzTmFtZSwgY29udGV4dCApIHtcblx0XHRpZiAoIHR5cGVvZiBjb250ZXh0LmdldEVsZW1lbnRzQnlDbGFzc05hbWUgIT09IFwidW5kZWZpbmVkXCIgJiYgZG9jdW1lbnRJc0hUTUwgKSB7XG5cdFx0XHRyZXR1cm4gY29udGV4dC5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCBjbGFzc05hbWUgKTtcblx0XHR9XG5cdH07XG5cblx0LyogUVNBL21hdGNoZXNTZWxlY3RvclxuXHQtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cblx0Ly8gUVNBIGFuZCBtYXRjaGVzU2VsZWN0b3Igc3VwcG9ydFxuXG5cdC8vIG1hdGNoZXNTZWxlY3Rvcig6YWN0aXZlKSByZXBvcnRzIGZhbHNlIHdoZW4gdHJ1ZSAoSUU5L09wZXJhIDExLjUpXG5cdHJidWdneU1hdGNoZXMgPSBbXTtcblxuXHQvLyBxU2EoOmZvY3VzKSByZXBvcnRzIGZhbHNlIHdoZW4gdHJ1ZSAoQ2hyb21lIDIxKVxuXHQvLyBXZSBhbGxvdyB0aGlzIGJlY2F1c2Ugb2YgYSBidWcgaW4gSUU4LzkgdGhhdCB0aHJvd3MgYW4gZXJyb3Jcblx0Ly8gd2hlbmV2ZXIgYGRvY3VtZW50LmFjdGl2ZUVsZW1lbnRgIGlzIGFjY2Vzc2VkIG9uIGFuIGlmcmFtZVxuXHQvLyBTbywgd2UgYWxsb3cgOmZvY3VzIHRvIHBhc3MgdGhyb3VnaCBRU0EgYWxsIHRoZSB0aW1lIHRvIGF2b2lkIHRoZSBJRSBlcnJvclxuXHQvLyBTZWUgaHR0cHM6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzEzMzc4XG5cdHJidWdneVFTQSA9IFtdO1xuXG5cdGlmICggKHN1cHBvcnQucXNhID0gcm5hdGl2ZS50ZXN0KCBkb2N1bWVudC5xdWVyeVNlbGVjdG9yQWxsICkpICkge1xuXHRcdC8vIEJ1aWxkIFFTQSByZWdleFxuXHRcdC8vIFJlZ2V4IHN0cmF0ZWd5IGFkb3B0ZWQgZnJvbSBEaWVnbyBQZXJpbmlcblx0XHRhc3NlcnQoZnVuY3Rpb24oIGVsICkge1xuXHRcdFx0Ly8gU2VsZWN0IGlzIHNldCB0byBlbXB0eSBzdHJpbmcgb24gcHVycG9zZVxuXHRcdFx0Ly8gVGhpcyBpcyB0byB0ZXN0IElFJ3MgdHJlYXRtZW50IG9mIG5vdCBleHBsaWNpdGx5XG5cdFx0XHQvLyBzZXR0aW5nIGEgYm9vbGVhbiBjb250ZW50IGF0dHJpYnV0ZSxcblx0XHRcdC8vIHNpbmNlIGl0cyBwcmVzZW5jZSBzaG91bGQgYmUgZW5vdWdoXG5cdFx0XHQvLyBodHRwczovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTIzNTlcblx0XHRcdGRvY0VsZW0uYXBwZW5kQ2hpbGQoIGVsICkuaW5uZXJIVE1MID0gXCI8YSBpZD0nXCIgKyBleHBhbmRvICsgXCInPjwvYT5cIiArXG5cdFx0XHRcdFwiPHNlbGVjdCBpZD0nXCIgKyBleHBhbmRvICsgXCItXFxyXFxcXCcgbXNhbGxvd2NhcHR1cmU9Jyc+XCIgK1xuXHRcdFx0XHRcIjxvcHRpb24gc2VsZWN0ZWQ9Jyc+PC9vcHRpb24+PC9zZWxlY3Q+XCI7XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFOCwgT3BlcmEgMTEtMTIuMTZcblx0XHRcdC8vIE5vdGhpbmcgc2hvdWxkIGJlIHNlbGVjdGVkIHdoZW4gZW1wdHkgc3RyaW5ncyBmb2xsb3cgXj0gb3IgJD0gb3IgKj1cblx0XHRcdC8vIFRoZSB0ZXN0IGF0dHJpYnV0ZSBtdXN0IGJlIHVua25vd24gaW4gT3BlcmEgYnV0IFwic2FmZVwiIGZvciBXaW5SVFxuXHRcdFx0Ly8gaHR0cHM6Ly9tc2RuLm1pY3Jvc29mdC5jb20vZW4tdXMvbGlicmFyeS9pZS9oaDQ2NTM4OC5hc3B4I2F0dHJpYnV0ZV9zZWN0aW9uXG5cdFx0XHRpZiAoIGVsLnF1ZXJ5U2VsZWN0b3JBbGwoXCJbbXNhbGxvd2NhcHR1cmVePScnXVwiKS5sZW5ndGggKSB7XG5cdFx0XHRcdHJidWdneVFTQS5wdXNoKCBcIlsqXiRdPVwiICsgd2hpdGVzcGFjZSArIFwiKig/OicnfFxcXCJcXFwiKVwiICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFOFxuXHRcdFx0Ly8gQm9vbGVhbiBhdHRyaWJ1dGVzIGFuZCBcInZhbHVlXCIgYXJlIG5vdCB0cmVhdGVkIGNvcnJlY3RseVxuXHRcdFx0aWYgKCAhZWwucXVlcnlTZWxlY3RvckFsbChcIltzZWxlY3RlZF1cIikubGVuZ3RoICkge1xuXHRcdFx0XHRyYnVnZ3lRU0EucHVzaCggXCJcXFxcW1wiICsgd2hpdGVzcGFjZSArIFwiKig/OnZhbHVlfFwiICsgYm9vbGVhbnMgKyBcIilcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTdXBwb3J0OiBDaHJvbWU8MjksIEFuZHJvaWQ8NC40LCBTYWZhcmk8Ny4wKywgaU9TPDcuMCssIFBoYW50b21KUzwxLjkuOCtcblx0XHRcdGlmICggIWVsLnF1ZXJ5U2VsZWN0b3JBbGwoIFwiW2lkfj1cIiArIGV4cGFuZG8gKyBcIi1dXCIgKS5sZW5ndGggKSB7XG5cdFx0XHRcdHJidWdneVFTQS5wdXNoKFwifj1cIik7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFdlYmtpdC9PcGVyYSAtIDpjaGVja2VkIHNob3VsZCByZXR1cm4gc2VsZWN0ZWQgb3B0aW9uIGVsZW1lbnRzXG5cdFx0XHQvLyBodHRwOi8vd3d3LnczLm9yZy9UUi8yMDExL1JFQy1jc3MzLXNlbGVjdG9ycy0yMDExMDkyOS8jY2hlY2tlZFxuXHRcdFx0Ly8gSUU4IHRocm93cyBlcnJvciBoZXJlIGFuZCB3aWxsIG5vdCBzZWUgbGF0ZXIgdGVzdHNcblx0XHRcdGlmICggIWVsLnF1ZXJ5U2VsZWN0b3JBbGwoXCI6Y2hlY2tlZFwiKS5sZW5ndGggKSB7XG5cdFx0XHRcdHJidWdneVFTQS5wdXNoKFwiOmNoZWNrZWRcIik7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFN1cHBvcnQ6IFNhZmFyaSA4KywgaU9TIDgrXG5cdFx0XHQvLyBodHRwczovL2J1Z3Mud2Via2l0Lm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTM2ODUxXG5cdFx0XHQvLyBJbi1wYWdlIGBzZWxlY3RvciNpZCBzaWJsaW5nLWNvbWJpbmF0b3Igc2VsZWN0b3JgIGZhaWxzXG5cdFx0XHRpZiAoICFlbC5xdWVyeVNlbGVjdG9yQWxsKCBcImEjXCIgKyBleHBhbmRvICsgXCIrKlwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRyYnVnZ3lRU0EucHVzaChcIi4jLitbK35dXCIpO1xuXHRcdFx0fVxuXHRcdH0pO1xuXG5cdFx0YXNzZXJ0KGZ1bmN0aW9uKCBlbCApIHtcblx0XHRcdGVsLmlubmVySFRNTCA9IFwiPGEgaHJlZj0nJyBkaXNhYmxlZD0nZGlzYWJsZWQnPjwvYT5cIiArXG5cdFx0XHRcdFwiPHNlbGVjdCBkaXNhYmxlZD0nZGlzYWJsZWQnPjxvcHRpb24vPjwvc2VsZWN0PlwiO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBXaW5kb3dzIDggTmF0aXZlIEFwcHNcblx0XHRcdC8vIFRoZSB0eXBlIGFuZCBuYW1lIGF0dHJpYnV0ZXMgYXJlIHJlc3RyaWN0ZWQgZHVyaW5nIC5pbm5lckhUTUwgYXNzaWdubWVudFxuXHRcdFx0dmFyIGlucHV0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImlucHV0XCIpO1xuXHRcdFx0aW5wdXQuc2V0QXR0cmlidXRlKCBcInR5cGVcIiwgXCJoaWRkZW5cIiApO1xuXHRcdFx0ZWwuYXBwZW5kQ2hpbGQoIGlucHV0ICkuc2V0QXR0cmlidXRlKCBcIm5hbWVcIiwgXCJEXCIgKTtcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUU4XG5cdFx0XHQvLyBFbmZvcmNlIGNhc2Utc2Vuc2l0aXZpdHkgb2YgbmFtZSBhdHRyaWJ1dGVcblx0XHRcdGlmICggZWwucXVlcnlTZWxlY3RvckFsbChcIltuYW1lPWRdXCIpLmxlbmd0aCApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwibmFtZVwiICsgd2hpdGVzcGFjZSArIFwiKlsqXiR8IX5dPz1cIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBGRiAzLjUgLSA6ZW5hYmxlZC86ZGlzYWJsZWQgYW5kIGhpZGRlbiBlbGVtZW50cyAoaGlkZGVuIGVsZW1lbnRzIGFyZSBzdGlsbCBlbmFibGVkKVxuXHRcdFx0Ly8gSUU4IHRocm93cyBlcnJvciBoZXJlIGFuZCB3aWxsIG5vdCBzZWUgbGF0ZXIgdGVzdHNcblx0XHRcdGlmICggZWwucXVlcnlTZWxlY3RvckFsbChcIjplbmFibGVkXCIpLmxlbmd0aCAhPT0gMiApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwiOmVuYWJsZWRcIiwgXCI6ZGlzYWJsZWRcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRTktMTErXG5cdFx0XHQvLyBJRSdzIDpkaXNhYmxlZCBzZWxlY3RvciBkb2VzIG5vdCBwaWNrIHVwIHRoZSBjaGlsZHJlbiBvZiBkaXNhYmxlZCBmaWVsZHNldHNcblx0XHRcdGRvY0VsZW0uYXBwZW5kQ2hpbGQoIGVsICkuZGlzYWJsZWQgPSB0cnVlO1xuXHRcdFx0aWYgKCBlbC5xdWVyeVNlbGVjdG9yQWxsKFwiOmRpc2FibGVkXCIpLmxlbmd0aCAhPT0gMiApIHtcblx0XHRcdFx0cmJ1Z2d5UVNBLnB1c2goIFwiOmVuYWJsZWRcIiwgXCI6ZGlzYWJsZWRcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBPcGVyYSAxMC0xMSBkb2VzIG5vdCB0aHJvdyBvbiBwb3N0LWNvbW1hIGludmFsaWQgcHNldWRvc1xuXHRcdFx0ZWwucXVlcnlTZWxlY3RvckFsbChcIiosOnhcIik7XG5cdFx0XHRyYnVnZ3lRU0EucHVzaChcIiwuKjpcIik7XG5cdFx0fSk7XG5cdH1cblxuXHRpZiAoIChzdXBwb3J0Lm1hdGNoZXNTZWxlY3RvciA9IHJuYXRpdmUudGVzdCggKG1hdGNoZXMgPSBkb2NFbGVtLm1hdGNoZXMgfHxcblx0XHRkb2NFbGVtLndlYmtpdE1hdGNoZXNTZWxlY3RvciB8fFxuXHRcdGRvY0VsZW0ubW96TWF0Y2hlc1NlbGVjdG9yIHx8XG5cdFx0ZG9jRWxlbS5vTWF0Y2hlc1NlbGVjdG9yIHx8XG5cdFx0ZG9jRWxlbS5tc01hdGNoZXNTZWxlY3RvcikgKSkgKSB7XG5cblx0XHRhc3NlcnQoZnVuY3Rpb24oIGVsICkge1xuXHRcdFx0Ly8gQ2hlY2sgdG8gc2VlIGlmIGl0J3MgcG9zc2libGUgdG8gZG8gbWF0Y2hlc1NlbGVjdG9yXG5cdFx0XHQvLyBvbiBhIGRpc2Nvbm5lY3RlZCBub2RlIChJRSA5KVxuXHRcdFx0c3VwcG9ydC5kaXNjb25uZWN0ZWRNYXRjaCA9IG1hdGNoZXMuY2FsbCggZWwsIFwiKlwiICk7XG5cblx0XHRcdC8vIFRoaXMgc2hvdWxkIGZhaWwgd2l0aCBhbiBleGNlcHRpb25cblx0XHRcdC8vIEdlY2tvIGRvZXMgbm90IGVycm9yLCByZXR1cm5zIGZhbHNlIGluc3RlYWRcblx0XHRcdG1hdGNoZXMuY2FsbCggZWwsIFwiW3MhPScnXTp4XCIgKTtcblx0XHRcdHJidWdneU1hdGNoZXMucHVzaCggXCIhPVwiLCBwc2V1ZG9zICk7XG5cdFx0fSk7XG5cdH1cblxuXHRyYnVnZ3lRU0EgPSByYnVnZ3lRU0EubGVuZ3RoICYmIG5ldyBSZWdFeHAoIHJidWdneVFTQS5qb2luKFwifFwiKSApO1xuXHRyYnVnZ3lNYXRjaGVzID0gcmJ1Z2d5TWF0Y2hlcy5sZW5ndGggJiYgbmV3IFJlZ0V4cCggcmJ1Z2d5TWF0Y2hlcy5qb2luKFwifFwiKSApO1xuXG5cdC8qIENvbnRhaW5zXG5cdC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0gKi9cblx0aGFzQ29tcGFyZSA9IHJuYXRpdmUudGVzdCggZG9jRWxlbS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiApO1xuXG5cdC8vIEVsZW1lbnQgY29udGFpbnMgYW5vdGhlclxuXHQvLyBQdXJwb3NlZnVsbHkgc2VsZi1leGNsdXNpdmVcblx0Ly8gQXMgaW4sIGFuIGVsZW1lbnQgZG9lcyBub3QgY29udGFpbiBpdHNlbGZcblx0Y29udGFpbnMgPSBoYXNDb21wYXJlIHx8IHJuYXRpdmUudGVzdCggZG9jRWxlbS5jb250YWlucyApID9cblx0XHRmdW5jdGlvbiggYSwgYiApIHtcblx0XHRcdHZhciBhZG93biA9IGEubm9kZVR5cGUgPT09IDkgPyBhLmRvY3VtZW50RWxlbWVudCA6IGEsXG5cdFx0XHRcdGJ1cCA9IGIgJiYgYi5wYXJlbnROb2RlO1xuXHRcdFx0cmV0dXJuIGEgPT09IGJ1cCB8fCAhISggYnVwICYmIGJ1cC5ub2RlVHlwZSA9PT0gMSAmJiAoXG5cdFx0XHRcdGFkb3duLmNvbnRhaW5zID9cblx0XHRcdFx0XHRhZG93bi5jb250YWlucyggYnVwICkgOlxuXHRcdFx0XHRcdGEuY29tcGFyZURvY3VtZW50UG9zaXRpb24gJiYgYS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggYnVwICkgJiAxNlxuXHRcdFx0KSk7XG5cdFx0fSA6XG5cdFx0ZnVuY3Rpb24oIGEsIGIgKSB7XG5cdFx0XHRpZiAoIGIgKSB7XG5cdFx0XHRcdHdoaWxlICggKGIgPSBiLnBhcmVudE5vZGUpICkge1xuXHRcdFx0XHRcdGlmICggYiA9PT0gYSApIHtcblx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH07XG5cblx0LyogU29ydGluZ1xuXHQtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tICovXG5cblx0Ly8gRG9jdW1lbnQgb3JkZXIgc29ydGluZ1xuXHRzb3J0T3JkZXIgPSBoYXNDb21wYXJlID9cblx0ZnVuY3Rpb24oIGEsIGIgKSB7XG5cblx0XHQvLyBGbGFnIGZvciBkdXBsaWNhdGUgcmVtb3ZhbFxuXHRcdGlmICggYSA9PT0gYiApIHtcblx0XHRcdGhhc0R1cGxpY2F0ZSA9IHRydWU7XG5cdFx0XHRyZXR1cm4gMDtcblx0XHR9XG5cblx0XHQvLyBTb3J0IG9uIG1ldGhvZCBleGlzdGVuY2UgaWYgb25seSBvbmUgaW5wdXQgaGFzIGNvbXBhcmVEb2N1bWVudFBvc2l0aW9uXG5cdFx0dmFyIGNvbXBhcmUgPSAhYS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiAtICFiLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uO1xuXHRcdGlmICggY29tcGFyZSApIHtcblx0XHRcdHJldHVybiBjb21wYXJlO1xuXHRcdH1cblxuXHRcdC8vIENhbGN1bGF0ZSBwb3NpdGlvbiBpZiBib3RoIGlucHV0cyBiZWxvbmcgdG8gdGhlIHNhbWUgZG9jdW1lbnRcblx0XHRjb21wYXJlID0gKCBhLm93bmVyRG9jdW1lbnQgfHwgYSApID09PSAoIGIub3duZXJEb2N1bWVudCB8fCBiICkgP1xuXHRcdFx0YS5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggYiApIDpcblxuXHRcdFx0Ly8gT3RoZXJ3aXNlIHdlIGtub3cgdGhleSBhcmUgZGlzY29ubmVjdGVkXG5cdFx0XHQxO1xuXG5cdFx0Ly8gRGlzY29ubmVjdGVkIG5vZGVzXG5cdFx0aWYgKCBjb21wYXJlICYgMSB8fFxuXHRcdFx0KCFzdXBwb3J0LnNvcnREZXRhY2hlZCAmJiBiLmNvbXBhcmVEb2N1bWVudFBvc2l0aW9uKCBhICkgPT09IGNvbXBhcmUpICkge1xuXG5cdFx0XHQvLyBDaG9vc2UgdGhlIGZpcnN0IGVsZW1lbnQgdGhhdCBpcyByZWxhdGVkIHRvIG91ciBwcmVmZXJyZWQgZG9jdW1lbnRcblx0XHRcdGlmICggYSA9PT0gZG9jdW1lbnQgfHwgYS5vd25lckRvY3VtZW50ID09PSBwcmVmZXJyZWREb2MgJiYgY29udGFpbnMocHJlZmVycmVkRG9jLCBhKSApIHtcblx0XHRcdFx0cmV0dXJuIC0xO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBiID09PSBkb2N1bWVudCB8fCBiLm93bmVyRG9jdW1lbnQgPT09IHByZWZlcnJlZERvYyAmJiBjb250YWlucyhwcmVmZXJyZWREb2MsIGIpICkge1xuXHRcdFx0XHRyZXR1cm4gMTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTWFpbnRhaW4gb3JpZ2luYWwgb3JkZXJcblx0XHRcdHJldHVybiBzb3J0SW5wdXQgP1xuXHRcdFx0XHQoIGluZGV4T2YoIHNvcnRJbnB1dCwgYSApIC0gaW5kZXhPZiggc29ydElucHV0LCBiICkgKSA6XG5cdFx0XHRcdDA7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNvbXBhcmUgJiA0ID8gLTEgOiAxO1xuXHR9IDpcblx0ZnVuY3Rpb24oIGEsIGIgKSB7XG5cdFx0Ly8gRXhpdCBlYXJseSBpZiB0aGUgbm9kZXMgYXJlIGlkZW50aWNhbFxuXHRcdGlmICggYSA9PT0gYiApIHtcblx0XHRcdGhhc0R1cGxpY2F0ZSA9IHRydWU7XG5cdFx0XHRyZXR1cm4gMDtcblx0XHR9XG5cblx0XHR2YXIgY3VyLFxuXHRcdFx0aSA9IDAsXG5cdFx0XHRhdXAgPSBhLnBhcmVudE5vZGUsXG5cdFx0XHRidXAgPSBiLnBhcmVudE5vZGUsXG5cdFx0XHRhcCA9IFsgYSBdLFxuXHRcdFx0YnAgPSBbIGIgXTtcblxuXHRcdC8vIFBhcmVudGxlc3Mgbm9kZXMgYXJlIGVpdGhlciBkb2N1bWVudHMgb3IgZGlzY29ubmVjdGVkXG5cdFx0aWYgKCAhYXVwIHx8ICFidXAgKSB7XG5cdFx0XHRyZXR1cm4gYSA9PT0gZG9jdW1lbnQgPyAtMSA6XG5cdFx0XHRcdGIgPT09IGRvY3VtZW50ID8gMSA6XG5cdFx0XHRcdGF1cCA/IC0xIDpcblx0XHRcdFx0YnVwID8gMSA6XG5cdFx0XHRcdHNvcnRJbnB1dCA/XG5cdFx0XHRcdCggaW5kZXhPZiggc29ydElucHV0LCBhICkgLSBpbmRleE9mKCBzb3J0SW5wdXQsIGIgKSApIDpcblx0XHRcdFx0MDtcblxuXHRcdC8vIElmIHRoZSBub2RlcyBhcmUgc2libGluZ3MsIHdlIGNhbiBkbyBhIHF1aWNrIGNoZWNrXG5cdFx0fSBlbHNlIGlmICggYXVwID09PSBidXAgKSB7XG5cdFx0XHRyZXR1cm4gc2libGluZ0NoZWNrKCBhLCBiICk7XG5cdFx0fVxuXG5cdFx0Ly8gT3RoZXJ3aXNlIHdlIG5lZWQgZnVsbCBsaXN0cyBvZiB0aGVpciBhbmNlc3RvcnMgZm9yIGNvbXBhcmlzb25cblx0XHRjdXIgPSBhO1xuXHRcdHdoaWxlICggKGN1ciA9IGN1ci5wYXJlbnROb2RlKSApIHtcblx0XHRcdGFwLnVuc2hpZnQoIGN1ciApO1xuXHRcdH1cblx0XHRjdXIgPSBiO1xuXHRcdHdoaWxlICggKGN1ciA9IGN1ci5wYXJlbnROb2RlKSApIHtcblx0XHRcdGJwLnVuc2hpZnQoIGN1ciApO1xuXHRcdH1cblxuXHRcdC8vIFdhbGsgZG93biB0aGUgdHJlZSBsb29raW5nIGZvciBhIGRpc2NyZXBhbmN5XG5cdFx0d2hpbGUgKCBhcFtpXSA9PT0gYnBbaV0gKSB7XG5cdFx0XHRpKys7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGkgP1xuXHRcdFx0Ly8gRG8gYSBzaWJsaW5nIGNoZWNrIGlmIHRoZSBub2RlcyBoYXZlIGEgY29tbW9uIGFuY2VzdG9yXG5cdFx0XHRzaWJsaW5nQ2hlY2soIGFwW2ldLCBicFtpXSApIDpcblxuXHRcdFx0Ly8gT3RoZXJ3aXNlIG5vZGVzIGluIG91ciBkb2N1bWVudCBzb3J0IGZpcnN0XG5cdFx0XHRhcFtpXSA9PT0gcHJlZmVycmVkRG9jID8gLTEgOlxuXHRcdFx0YnBbaV0gPT09IHByZWZlcnJlZERvYyA/IDEgOlxuXHRcdFx0MDtcblx0fTtcblxuXHRyZXR1cm4gZG9jdW1lbnQ7XG59O1xuXG5TaXp6bGUubWF0Y2hlcyA9IGZ1bmN0aW9uKCBleHByLCBlbGVtZW50cyApIHtcblx0cmV0dXJuIFNpenpsZSggZXhwciwgbnVsbCwgbnVsbCwgZWxlbWVudHMgKTtcbn07XG5cblNpenpsZS5tYXRjaGVzU2VsZWN0b3IgPSBmdW5jdGlvbiggZWxlbSwgZXhwciApIHtcblx0Ly8gU2V0IGRvY3VtZW50IHZhcnMgaWYgbmVlZGVkXG5cdGlmICggKCBlbGVtLm93bmVyRG9jdW1lbnQgfHwgZWxlbSApICE9PSBkb2N1bWVudCApIHtcblx0XHRzZXREb2N1bWVudCggZWxlbSApO1xuXHR9XG5cblx0aWYgKCBzdXBwb3J0Lm1hdGNoZXNTZWxlY3RvciAmJiBkb2N1bWVudElzSFRNTCAmJlxuXHRcdCFub25uYXRpdmVTZWxlY3RvckNhY2hlWyBleHByICsgXCIgXCIgXSAmJlxuXHRcdCggIXJidWdneU1hdGNoZXMgfHwgIXJidWdneU1hdGNoZXMudGVzdCggZXhwciApICkgJiZcblx0XHQoICFyYnVnZ3lRU0EgICAgIHx8ICFyYnVnZ3lRU0EudGVzdCggZXhwciApICkgKSB7XG5cblx0XHR0cnkge1xuXHRcdFx0dmFyIHJldCA9IG1hdGNoZXMuY2FsbCggZWxlbSwgZXhwciApO1xuXG5cdFx0XHQvLyBJRSA5J3MgbWF0Y2hlc1NlbGVjdG9yIHJldHVybnMgZmFsc2Ugb24gZGlzY29ubmVjdGVkIG5vZGVzXG5cdFx0XHRpZiAoIHJldCB8fCBzdXBwb3J0LmRpc2Nvbm5lY3RlZE1hdGNoIHx8XG5cdFx0XHRcdFx0Ly8gQXMgd2VsbCwgZGlzY29ubmVjdGVkIG5vZGVzIGFyZSBzYWlkIHRvIGJlIGluIGEgZG9jdW1lbnRcblx0XHRcdFx0XHQvLyBmcmFnbWVudCBpbiBJRSA5XG5cdFx0XHRcdFx0ZWxlbS5kb2N1bWVudCAmJiBlbGVtLmRvY3VtZW50Lm5vZGVUeXBlICE9PSAxMSApIHtcblx0XHRcdFx0cmV0dXJuIHJldDtcblx0XHRcdH1cblx0XHR9IGNhdGNoIChlKSB7XG5cdFx0XHRub25uYXRpdmVTZWxlY3RvckNhY2hlKCBleHByLCB0cnVlICk7XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIFNpenpsZSggZXhwciwgZG9jdW1lbnQsIG51bGwsIFsgZWxlbSBdICkubGVuZ3RoID4gMDtcbn07XG5cblNpenpsZS5jb250YWlucyA9IGZ1bmN0aW9uKCBjb250ZXh0LCBlbGVtICkge1xuXHQvLyBTZXQgZG9jdW1lbnQgdmFycyBpZiBuZWVkZWRcblx0aWYgKCAoIGNvbnRleHQub3duZXJEb2N1bWVudCB8fCBjb250ZXh0ICkgIT09IGRvY3VtZW50ICkge1xuXHRcdHNldERvY3VtZW50KCBjb250ZXh0ICk7XG5cdH1cblx0cmV0dXJuIGNvbnRhaW5zKCBjb250ZXh0LCBlbGVtICk7XG59O1xuXG5TaXp6bGUuYXR0ciA9IGZ1bmN0aW9uKCBlbGVtLCBuYW1lICkge1xuXHQvLyBTZXQgZG9jdW1lbnQgdmFycyBpZiBuZWVkZWRcblx0aWYgKCAoIGVsZW0ub3duZXJEb2N1bWVudCB8fCBlbGVtICkgIT09IGRvY3VtZW50ICkge1xuXHRcdHNldERvY3VtZW50KCBlbGVtICk7XG5cdH1cblxuXHR2YXIgZm4gPSBFeHByLmF0dHJIYW5kbGVbIG5hbWUudG9Mb3dlckNhc2UoKSBdLFxuXHRcdC8vIERvbid0IGdldCBmb29sZWQgYnkgT2JqZWN0LnByb3RvdHlwZSBwcm9wZXJ0aWVzIChqUXVlcnkgIzEzODA3KVxuXHRcdHZhbCA9IGZuICYmIGhhc093bi5jYWxsKCBFeHByLmF0dHJIYW5kbGUsIG5hbWUudG9Mb3dlckNhc2UoKSApID9cblx0XHRcdGZuKCBlbGVtLCBuYW1lLCAhZG9jdW1lbnRJc0hUTUwgKSA6XG5cdFx0XHR1bmRlZmluZWQ7XG5cblx0cmV0dXJuIHZhbCAhPT0gdW5kZWZpbmVkID9cblx0XHR2YWwgOlxuXHRcdHN1cHBvcnQuYXR0cmlidXRlcyB8fCAhZG9jdW1lbnRJc0hUTUwgP1xuXHRcdFx0ZWxlbS5nZXRBdHRyaWJ1dGUoIG5hbWUgKSA6XG5cdFx0XHQodmFsID0gZWxlbS5nZXRBdHRyaWJ1dGVOb2RlKG5hbWUpKSAmJiB2YWwuc3BlY2lmaWVkID9cblx0XHRcdFx0dmFsLnZhbHVlIDpcblx0XHRcdFx0bnVsbDtcbn07XG5cblNpenpsZS5lc2NhcGUgPSBmdW5jdGlvbiggc2VsICkge1xuXHRyZXR1cm4gKHNlbCArIFwiXCIpLnJlcGxhY2UoIHJjc3Nlc2NhcGUsIGZjc3Nlc2NhcGUgKTtcbn07XG5cblNpenpsZS5lcnJvciA9IGZ1bmN0aW9uKCBtc2cgKSB7XG5cdHRocm93IG5ldyBFcnJvciggXCJTeW50YXggZXJyb3IsIHVucmVjb2duaXplZCBleHByZXNzaW9uOiBcIiArIG1zZyApO1xufTtcblxuLyoqXG4gKiBEb2N1bWVudCBzb3J0aW5nIGFuZCByZW1vdmluZyBkdXBsaWNhdGVzXG4gKiBAcGFyYW0ge0FycmF5TGlrZX0gcmVzdWx0c1xuICovXG5TaXp6bGUudW5pcXVlU29ydCA9IGZ1bmN0aW9uKCByZXN1bHRzICkge1xuXHR2YXIgZWxlbSxcblx0XHRkdXBsaWNhdGVzID0gW10sXG5cdFx0aiA9IDAsXG5cdFx0aSA9IDA7XG5cblx0Ly8gVW5sZXNzIHdlICprbm93KiB3ZSBjYW4gZGV0ZWN0IGR1cGxpY2F0ZXMsIGFzc3VtZSB0aGVpciBwcmVzZW5jZVxuXHRoYXNEdXBsaWNhdGUgPSAhc3VwcG9ydC5kZXRlY3REdXBsaWNhdGVzO1xuXHRzb3J0SW5wdXQgPSAhc3VwcG9ydC5zb3J0U3RhYmxlICYmIHJlc3VsdHMuc2xpY2UoIDAgKTtcblx0cmVzdWx0cy5zb3J0KCBzb3J0T3JkZXIgKTtcblxuXHRpZiAoIGhhc0R1cGxpY2F0ZSApIHtcblx0XHR3aGlsZSAoIChlbGVtID0gcmVzdWx0c1tpKytdKSApIHtcblx0XHRcdGlmICggZWxlbSA9PT0gcmVzdWx0c1sgaSBdICkge1xuXHRcdFx0XHRqID0gZHVwbGljYXRlcy5wdXNoKCBpICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHdoaWxlICggai0tICkge1xuXHRcdFx0cmVzdWx0cy5zcGxpY2UoIGR1cGxpY2F0ZXNbIGogXSwgMSApO1xuXHRcdH1cblx0fVxuXG5cdC8vIENsZWFyIGlucHV0IGFmdGVyIHNvcnRpbmcgdG8gcmVsZWFzZSBvYmplY3RzXG5cdC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vanF1ZXJ5L3NpenpsZS9wdWxsLzIyNVxuXHRzb3J0SW5wdXQgPSBudWxsO1xuXG5cdHJldHVybiByZXN1bHRzO1xufTtcblxuLyoqXG4gKiBVdGlsaXR5IGZ1bmN0aW9uIGZvciByZXRyaWV2aW5nIHRoZSB0ZXh0IHZhbHVlIG9mIGFuIGFycmF5IG9mIERPTSBub2Rlc1xuICogQHBhcmFtIHtBcnJheXxFbGVtZW50fSBlbGVtXG4gKi9cbmdldFRleHQgPSBTaXp6bGUuZ2V0VGV4dCA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXHR2YXIgbm9kZSxcblx0XHRyZXQgPSBcIlwiLFxuXHRcdGkgPSAwLFxuXHRcdG5vZGVUeXBlID0gZWxlbS5ub2RlVHlwZTtcblxuXHRpZiAoICFub2RlVHlwZSApIHtcblx0XHQvLyBJZiBubyBub2RlVHlwZSwgdGhpcyBpcyBleHBlY3RlZCB0byBiZSBhbiBhcnJheVxuXHRcdHdoaWxlICggKG5vZGUgPSBlbGVtW2krK10pICkge1xuXHRcdFx0Ly8gRG8gbm90IHRyYXZlcnNlIGNvbW1lbnQgbm9kZXNcblx0XHRcdHJldCArPSBnZXRUZXh0KCBub2RlICk7XG5cdFx0fVxuXHR9IGVsc2UgaWYgKCBub2RlVHlwZSA9PT0gMSB8fCBub2RlVHlwZSA9PT0gOSB8fCBub2RlVHlwZSA9PT0gMTEgKSB7XG5cdFx0Ly8gVXNlIHRleHRDb250ZW50IGZvciBlbGVtZW50c1xuXHRcdC8vIGlubmVyVGV4dCB1c2FnZSByZW1vdmVkIGZvciBjb25zaXN0ZW5jeSBvZiBuZXcgbGluZXMgKGpRdWVyeSAjMTExNTMpXG5cdFx0aWYgKCB0eXBlb2YgZWxlbS50ZXh0Q29udGVudCA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHJldHVybiBlbGVtLnRleHRDb250ZW50O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBUcmF2ZXJzZSBpdHMgY2hpbGRyZW5cblx0XHRcdGZvciAoIGVsZW0gPSBlbGVtLmZpcnN0Q2hpbGQ7IGVsZW07IGVsZW0gPSBlbGVtLm5leHRTaWJsaW5nICkge1xuXHRcdFx0XHRyZXQgKz0gZ2V0VGV4dCggZWxlbSApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSBlbHNlIGlmICggbm9kZVR5cGUgPT09IDMgfHwgbm9kZVR5cGUgPT09IDQgKSB7XG5cdFx0cmV0dXJuIGVsZW0ubm9kZVZhbHVlO1xuXHR9XG5cdC8vIERvIG5vdCBpbmNsdWRlIGNvbW1lbnQgb3IgcHJvY2Vzc2luZyBpbnN0cnVjdGlvbiBub2Rlc1xuXG5cdHJldHVybiByZXQ7XG59O1xuXG5FeHByID0gU2l6emxlLnNlbGVjdG9ycyA9IHtcblxuXHQvLyBDYW4gYmUgYWRqdXN0ZWQgYnkgdGhlIHVzZXJcblx0Y2FjaGVMZW5ndGg6IDUwLFxuXG5cdGNyZWF0ZVBzZXVkbzogbWFya0Z1bmN0aW9uLFxuXG5cdG1hdGNoOiBtYXRjaEV4cHIsXG5cblx0YXR0ckhhbmRsZToge30sXG5cblx0ZmluZDoge30sXG5cblx0cmVsYXRpdmU6IHtcblx0XHRcIj5cIjogeyBkaXI6IFwicGFyZW50Tm9kZVwiLCBmaXJzdDogdHJ1ZSB9LFxuXHRcdFwiIFwiOiB7IGRpcjogXCJwYXJlbnROb2RlXCIgfSxcblx0XHRcIitcIjogeyBkaXI6IFwicHJldmlvdXNTaWJsaW5nXCIsIGZpcnN0OiB0cnVlIH0sXG5cdFx0XCJ+XCI6IHsgZGlyOiBcInByZXZpb3VzU2libGluZ1wiIH1cblx0fSxcblxuXHRwcmVGaWx0ZXI6IHtcblx0XHRcIkFUVFJcIjogZnVuY3Rpb24oIG1hdGNoICkge1xuXHRcdFx0bWF0Y2hbMV0gPSBtYXRjaFsxXS5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApO1xuXG5cdFx0XHQvLyBNb3ZlIHRoZSBnaXZlbiB2YWx1ZSB0byBtYXRjaFszXSB3aGV0aGVyIHF1b3RlZCBvciB1bnF1b3RlZFxuXHRcdFx0bWF0Y2hbM10gPSAoIG1hdGNoWzNdIHx8IG1hdGNoWzRdIHx8IG1hdGNoWzVdIHx8IFwiXCIgKS5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApO1xuXG5cdFx0XHRpZiAoIG1hdGNoWzJdID09PSBcIn49XCIgKSB7XG5cdFx0XHRcdG1hdGNoWzNdID0gXCIgXCIgKyBtYXRjaFszXSArIFwiIFwiO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gbWF0Y2guc2xpY2UoIDAsIDQgKTtcblx0XHR9LFxuXG5cdFx0XCJDSElMRFwiOiBmdW5jdGlvbiggbWF0Y2ggKSB7XG5cdFx0XHQvKiBtYXRjaGVzIGZyb20gbWF0Y2hFeHByW1wiQ0hJTERcIl1cblx0XHRcdFx0MSB0eXBlIChvbmx5fG50aHwuLi4pXG5cdFx0XHRcdDIgd2hhdCAoY2hpbGR8b2YtdHlwZSlcblx0XHRcdFx0MyBhcmd1bWVudCAoZXZlbnxvZGR8XFxkKnxcXGQqbihbKy1dXFxkKyk/fC4uLilcblx0XHRcdFx0NCB4bi1jb21wb25lbnQgb2YgeG4reSBhcmd1bWVudCAoWystXT9cXGQqbnwpXG5cdFx0XHRcdDUgc2lnbiBvZiB4bi1jb21wb25lbnRcblx0XHRcdFx0NiB4IG9mIHhuLWNvbXBvbmVudFxuXHRcdFx0XHQ3IHNpZ24gb2YgeS1jb21wb25lbnRcblx0XHRcdFx0OCB5IG9mIHktY29tcG9uZW50XG5cdFx0XHQqL1xuXHRcdFx0bWF0Y2hbMV0gPSBtYXRjaFsxXS50b0xvd2VyQ2FzZSgpO1xuXG5cdFx0XHRpZiAoIG1hdGNoWzFdLnNsaWNlKCAwLCAzICkgPT09IFwibnRoXCIgKSB7XG5cdFx0XHRcdC8vIG50aC0qIHJlcXVpcmVzIGFyZ3VtZW50XG5cdFx0XHRcdGlmICggIW1hdGNoWzNdICkge1xuXHRcdFx0XHRcdFNpenpsZS5lcnJvciggbWF0Y2hbMF0gKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIG51bWVyaWMgeCBhbmQgeSBwYXJhbWV0ZXJzIGZvciBFeHByLmZpbHRlci5DSElMRFxuXHRcdFx0XHQvLyByZW1lbWJlciB0aGF0IGZhbHNlL3RydWUgY2FzdCByZXNwZWN0aXZlbHkgdG8gMC8xXG5cdFx0XHRcdG1hdGNoWzRdID0gKyggbWF0Y2hbNF0gPyBtYXRjaFs1XSArIChtYXRjaFs2XSB8fCAxKSA6IDIgKiAoIG1hdGNoWzNdID09PSBcImV2ZW5cIiB8fCBtYXRjaFszXSA9PT0gXCJvZGRcIiApICk7XG5cdFx0XHRcdG1hdGNoWzVdID0gKyggKCBtYXRjaFs3XSArIG1hdGNoWzhdICkgfHwgbWF0Y2hbM10gPT09IFwib2RkXCIgKTtcblxuXHRcdFx0Ly8gb3RoZXIgdHlwZXMgcHJvaGliaXQgYXJndW1lbnRzXG5cdFx0XHR9IGVsc2UgaWYgKCBtYXRjaFszXSApIHtcblx0XHRcdFx0U2l6emxlLmVycm9yKCBtYXRjaFswXSApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gbWF0Y2g7XG5cdFx0fSxcblxuXHRcdFwiUFNFVURPXCI6IGZ1bmN0aW9uKCBtYXRjaCApIHtcblx0XHRcdHZhciBleGNlc3MsXG5cdFx0XHRcdHVucXVvdGVkID0gIW1hdGNoWzZdICYmIG1hdGNoWzJdO1xuXG5cdFx0XHRpZiAoIG1hdGNoRXhwcltcIkNISUxEXCJdLnRlc3QoIG1hdGNoWzBdICkgKSB7XG5cdFx0XHRcdHJldHVybiBudWxsO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBBY2NlcHQgcXVvdGVkIGFyZ3VtZW50cyBhcy1pc1xuXHRcdFx0aWYgKCBtYXRjaFszXSApIHtcblx0XHRcdFx0bWF0Y2hbMl0gPSBtYXRjaFs0XSB8fCBtYXRjaFs1XSB8fCBcIlwiO1xuXG5cdFx0XHQvLyBTdHJpcCBleGNlc3MgY2hhcmFjdGVycyBmcm9tIHVucXVvdGVkIGFyZ3VtZW50c1xuXHRcdFx0fSBlbHNlIGlmICggdW5xdW90ZWQgJiYgcnBzZXVkby50ZXN0KCB1bnF1b3RlZCApICYmXG5cdFx0XHRcdC8vIEdldCBleGNlc3MgZnJvbSB0b2tlbml6ZSAocmVjdXJzaXZlbHkpXG5cdFx0XHRcdChleGNlc3MgPSB0b2tlbml6ZSggdW5xdW90ZWQsIHRydWUgKSkgJiZcblx0XHRcdFx0Ly8gYWR2YW5jZSB0byB0aGUgbmV4dCBjbG9zaW5nIHBhcmVudGhlc2lzXG5cdFx0XHRcdChleGNlc3MgPSB1bnF1b3RlZC5pbmRleE9mKCBcIilcIiwgdW5xdW90ZWQubGVuZ3RoIC0gZXhjZXNzICkgLSB1bnF1b3RlZC5sZW5ndGgpICkge1xuXG5cdFx0XHRcdC8vIGV4Y2VzcyBpcyBhIG5lZ2F0aXZlIGluZGV4XG5cdFx0XHRcdG1hdGNoWzBdID0gbWF0Y2hbMF0uc2xpY2UoIDAsIGV4Y2VzcyApO1xuXHRcdFx0XHRtYXRjaFsyXSA9IHVucXVvdGVkLnNsaWNlKCAwLCBleGNlc3MgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gUmV0dXJuIG9ubHkgY2FwdHVyZXMgbmVlZGVkIGJ5IHRoZSBwc2V1ZG8gZmlsdGVyIG1ldGhvZCAodHlwZSBhbmQgYXJndW1lbnQpXG5cdFx0XHRyZXR1cm4gbWF0Y2guc2xpY2UoIDAsIDMgKTtcblx0XHR9XG5cdH0sXG5cblx0ZmlsdGVyOiB7XG5cblx0XHRcIlRBR1wiOiBmdW5jdGlvbiggbm9kZU5hbWVTZWxlY3RvciApIHtcblx0XHRcdHZhciBub2RlTmFtZSA9IG5vZGVOYW1lU2VsZWN0b3IucmVwbGFjZSggcnVuZXNjYXBlLCBmdW5lc2NhcGUgKS50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0cmV0dXJuIG5vZGVOYW1lU2VsZWN0b3IgPT09IFwiKlwiID9cblx0XHRcdFx0ZnVuY3Rpb24oKSB7IHJldHVybiB0cnVlOyB9IDpcblx0XHRcdFx0ZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGVsZW0ubm9kZU5hbWUgJiYgZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSBub2RlTmFtZTtcblx0XHRcdFx0fTtcblx0XHR9LFxuXG5cdFx0XCJDTEFTU1wiOiBmdW5jdGlvbiggY2xhc3NOYW1lICkge1xuXHRcdFx0dmFyIHBhdHRlcm4gPSBjbGFzc0NhY2hlWyBjbGFzc05hbWUgKyBcIiBcIiBdO1xuXG5cdFx0XHRyZXR1cm4gcGF0dGVybiB8fFxuXHRcdFx0XHQocGF0dGVybiA9IG5ldyBSZWdFeHAoIFwiKF58XCIgKyB3aGl0ZXNwYWNlICsgXCIpXCIgKyBjbGFzc05hbWUgKyBcIihcIiArIHdoaXRlc3BhY2UgKyBcInwkKVwiICkpICYmXG5cdFx0XHRcdGNsYXNzQ2FjaGUoIGNsYXNzTmFtZSwgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHBhdHRlcm4udGVzdCggdHlwZW9mIGVsZW0uY2xhc3NOYW1lID09PSBcInN0cmluZ1wiICYmIGVsZW0uY2xhc3NOYW1lIHx8IHR5cGVvZiBlbGVtLmdldEF0dHJpYnV0ZSAhPT0gXCJ1bmRlZmluZWRcIiAmJiBlbGVtLmdldEF0dHJpYnV0ZShcImNsYXNzXCIpIHx8IFwiXCIgKTtcblx0XHRcdFx0fSk7XG5cdFx0fSxcblxuXHRcdFwiQVRUUlwiOiBmdW5jdGlvbiggbmFtZSwgb3BlcmF0b3IsIGNoZWNrICkge1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0XHR2YXIgcmVzdWx0ID0gU2l6emxlLmF0dHIoIGVsZW0sIG5hbWUgKTtcblxuXHRcdFx0XHRpZiAoIHJlc3VsdCA9PSBudWxsICkge1xuXHRcdFx0XHRcdHJldHVybiBvcGVyYXRvciA9PT0gXCIhPVwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggIW9wZXJhdG9yICkge1xuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmVzdWx0ICs9IFwiXCI7XG5cblx0XHRcdFx0cmV0dXJuIG9wZXJhdG9yID09PSBcIj1cIiA/IHJlc3VsdCA9PT0gY2hlY2sgOlxuXHRcdFx0XHRcdG9wZXJhdG9yID09PSBcIiE9XCIgPyByZXN1bHQgIT09IGNoZWNrIDpcblx0XHRcdFx0XHRvcGVyYXRvciA9PT0gXCJePVwiID8gY2hlY2sgJiYgcmVzdWx0LmluZGV4T2YoIGNoZWNrICkgPT09IDAgOlxuXHRcdFx0XHRcdG9wZXJhdG9yID09PSBcIio9XCIgPyBjaGVjayAmJiByZXN1bHQuaW5kZXhPZiggY2hlY2sgKSA+IC0xIDpcblx0XHRcdFx0XHRvcGVyYXRvciA9PT0gXCIkPVwiID8gY2hlY2sgJiYgcmVzdWx0LnNsaWNlKCAtY2hlY2subGVuZ3RoICkgPT09IGNoZWNrIDpcblx0XHRcdFx0XHRvcGVyYXRvciA9PT0gXCJ+PVwiID8gKCBcIiBcIiArIHJlc3VsdC5yZXBsYWNlKCByd2hpdGVzcGFjZSwgXCIgXCIgKSArIFwiIFwiICkuaW5kZXhPZiggY2hlY2sgKSA+IC0xIDpcblx0XHRcdFx0XHRvcGVyYXRvciA9PT0gXCJ8PVwiID8gcmVzdWx0ID09PSBjaGVjayB8fCByZXN1bHQuc2xpY2UoIDAsIGNoZWNrLmxlbmd0aCArIDEgKSA9PT0gY2hlY2sgKyBcIi1cIiA6XG5cdFx0XHRcdFx0ZmFsc2U7XG5cdFx0XHR9O1xuXHRcdH0sXG5cblx0XHRcIkNISUxEXCI6IGZ1bmN0aW9uKCB0eXBlLCB3aGF0LCBhcmd1bWVudCwgZmlyc3QsIGxhc3QgKSB7XG5cdFx0XHR2YXIgc2ltcGxlID0gdHlwZS5zbGljZSggMCwgMyApICE9PSBcIm50aFwiLFxuXHRcdFx0XHRmb3J3YXJkID0gdHlwZS5zbGljZSggLTQgKSAhPT0gXCJsYXN0XCIsXG5cdFx0XHRcdG9mVHlwZSA9IHdoYXQgPT09IFwib2YtdHlwZVwiO1xuXG5cdFx0XHRyZXR1cm4gZmlyc3QgPT09IDEgJiYgbGFzdCA9PT0gMCA/XG5cblx0XHRcdFx0Ly8gU2hvcnRjdXQgZm9yIDpudGgtKihuKVxuXHRcdFx0XHRmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0XHRyZXR1cm4gISFlbGVtLnBhcmVudE5vZGU7XG5cdFx0XHRcdH0gOlxuXG5cdFx0XHRcdGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHRcdFx0dmFyIGNhY2hlLCB1bmlxdWVDYWNoZSwgb3V0ZXJDYWNoZSwgbm9kZSwgbm9kZUluZGV4LCBzdGFydCxcblx0XHRcdFx0XHRcdGRpciA9IHNpbXBsZSAhPT0gZm9yd2FyZCA/IFwibmV4dFNpYmxpbmdcIiA6IFwicHJldmlvdXNTaWJsaW5nXCIsXG5cdFx0XHRcdFx0XHRwYXJlbnQgPSBlbGVtLnBhcmVudE5vZGUsXG5cdFx0XHRcdFx0XHRuYW1lID0gb2ZUeXBlICYmIGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSxcblx0XHRcdFx0XHRcdHVzZUNhY2hlID0gIXhtbCAmJiAhb2ZUeXBlLFxuXHRcdFx0XHRcdFx0ZGlmZiA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0aWYgKCBwYXJlbnQgKSB7XG5cblx0XHRcdFx0XHRcdC8vIDooZmlyc3R8bGFzdHxvbmx5KS0oY2hpbGR8b2YtdHlwZSlcblx0XHRcdFx0XHRcdGlmICggc2ltcGxlICkge1xuXHRcdFx0XHRcdFx0XHR3aGlsZSAoIGRpciApIHtcblx0XHRcdFx0XHRcdFx0XHRub2RlID0gZWxlbTtcblx0XHRcdFx0XHRcdFx0XHR3aGlsZSAoIChub2RlID0gbm9kZVsgZGlyIF0pICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBvZlR5cGUgP1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRub2RlLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IG5hbWUgOlxuXHRcdFx0XHRcdFx0XHRcdFx0XHRub2RlLm5vZGVUeXBlID09PSAxICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0Ly8gUmV2ZXJzZSBkaXJlY3Rpb24gZm9yIDpvbmx5LSogKGlmIHdlIGhhdmVuJ3QgeWV0IGRvbmUgc28pXG5cdFx0XHRcdFx0XHRcdFx0c3RhcnQgPSBkaXIgPSB0eXBlID09PSBcIm9ubHlcIiAmJiAhc3RhcnQgJiYgXCJuZXh0U2libGluZ1wiO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRzdGFydCA9IFsgZm9yd2FyZCA/IHBhcmVudC5maXJzdENoaWxkIDogcGFyZW50Lmxhc3RDaGlsZCBdO1xuXG5cdFx0XHRcdFx0XHQvLyBub24teG1sIDpudGgtY2hpbGQoLi4uKSBzdG9yZXMgY2FjaGUgZGF0YSBvbiBgcGFyZW50YFxuXHRcdFx0XHRcdFx0aWYgKCBmb3J3YXJkICYmIHVzZUNhY2hlICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIFNlZWsgYGVsZW1gIGZyb20gYSBwcmV2aW91c2x5LWNhY2hlZCBpbmRleFxuXG5cdFx0XHRcdFx0XHRcdC8vIC4uLmluIGEgZ3ppcC1mcmllbmRseSB3YXlcblx0XHRcdFx0XHRcdFx0bm9kZSA9IHBhcmVudDtcblx0XHRcdFx0XHRcdFx0b3V0ZXJDYWNoZSA9IG5vZGVbIGV4cGFuZG8gXSB8fCAobm9kZVsgZXhwYW5kbyBdID0ge30pO1xuXG5cdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw5IG9ubHlcblx0XHRcdFx0XHRcdFx0Ly8gRGVmZW5kIGFnYWluc3QgY2xvbmVkIGF0dHJvcGVydGllcyAoalF1ZXJ5IGdoLTE3MDkpXG5cdFx0XHRcdFx0XHRcdHVuaXF1ZUNhY2hlID0gb3V0ZXJDYWNoZVsgbm9kZS51bmlxdWVJRCBdIHx8XG5cdFx0XHRcdFx0XHRcdFx0KG91dGVyQ2FjaGVbIG5vZGUudW5pcXVlSUQgXSA9IHt9KTtcblxuXHRcdFx0XHRcdFx0XHRjYWNoZSA9IHVuaXF1ZUNhY2hlWyB0eXBlIF0gfHwgW107XG5cdFx0XHRcdFx0XHRcdG5vZGVJbmRleCA9IGNhY2hlWyAwIF0gPT09IGRpcnJ1bnMgJiYgY2FjaGVbIDEgXTtcblx0XHRcdFx0XHRcdFx0ZGlmZiA9IG5vZGVJbmRleCAmJiBjYWNoZVsgMiBdO1xuXHRcdFx0XHRcdFx0XHRub2RlID0gbm9kZUluZGV4ICYmIHBhcmVudC5jaGlsZE5vZGVzWyBub2RlSW5kZXggXTtcblxuXHRcdFx0XHRcdFx0XHR3aGlsZSAoIChub2RlID0gKytub2RlSW5kZXggJiYgbm9kZSAmJiBub2RlWyBkaXIgXSB8fFxuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gRmFsbGJhY2sgdG8gc2Vla2luZyBgZWxlbWAgZnJvbSB0aGUgc3RhcnRcblx0XHRcdFx0XHRcdFx0XHQoZGlmZiA9IG5vZGVJbmRleCA9IDApIHx8IHN0YXJ0LnBvcCgpKSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIFdoZW4gZm91bmQsIGNhY2hlIGluZGV4ZXMgb24gYHBhcmVudGAgYW5kIGJyZWFrXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBub2RlLm5vZGVUeXBlID09PSAxICYmICsrZGlmZiAmJiBub2RlID09PSBlbGVtICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0dW5pcXVlQ2FjaGVbIHR5cGUgXSA9IFsgZGlycnVucywgbm9kZUluZGV4LCBkaWZmIF07XG5cdFx0XHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0Ly8gVXNlIHByZXZpb3VzbHktY2FjaGVkIGVsZW1lbnQgaW5kZXggaWYgYXZhaWxhYmxlXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlQ2FjaGUgKSB7XG5cdFx0XHRcdFx0XHRcdFx0Ly8gLi4uaW4gYSBnemlwLWZyaWVuZGx5IHdheVxuXHRcdFx0XHRcdFx0XHRcdG5vZGUgPSBlbGVtO1xuXHRcdFx0XHRcdFx0XHRcdG91dGVyQ2FjaGUgPSBub2RlWyBleHBhbmRvIF0gfHwgKG5vZGVbIGV4cGFuZG8gXSA9IHt9KTtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw5IG9ubHlcblx0XHRcdFx0XHRcdFx0XHQvLyBEZWZlbmQgYWdhaW5zdCBjbG9uZWQgYXR0cm9wZXJ0aWVzIChqUXVlcnkgZ2gtMTcwOSlcblx0XHRcdFx0XHRcdFx0XHR1bmlxdWVDYWNoZSA9IG91dGVyQ2FjaGVbIG5vZGUudW5pcXVlSUQgXSB8fFxuXHRcdFx0XHRcdFx0XHRcdFx0KG91dGVyQ2FjaGVbIG5vZGUudW5pcXVlSUQgXSA9IHt9KTtcblxuXHRcdFx0XHRcdFx0XHRcdGNhY2hlID0gdW5pcXVlQ2FjaGVbIHR5cGUgXSB8fCBbXTtcblx0XHRcdFx0XHRcdFx0XHRub2RlSW5kZXggPSBjYWNoZVsgMCBdID09PSBkaXJydW5zICYmIGNhY2hlWyAxIF07XG5cdFx0XHRcdFx0XHRcdFx0ZGlmZiA9IG5vZGVJbmRleDtcblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdC8vIHhtbCA6bnRoLWNoaWxkKC4uLilcblx0XHRcdFx0XHRcdFx0Ly8gb3IgOm50aC1sYXN0LWNoaWxkKC4uLikgb3IgOm50aCgtbGFzdCk/LW9mLXR5cGUoLi4uKVxuXHRcdFx0XHRcdFx0XHRpZiAoIGRpZmYgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdFx0XHRcdC8vIFVzZSB0aGUgc2FtZSBsb29wIGFzIGFib3ZlIHRvIHNlZWsgYGVsZW1gIGZyb20gdGhlIHN0YXJ0XG5cdFx0XHRcdFx0XHRcdFx0d2hpbGUgKCAobm9kZSA9ICsrbm9kZUluZGV4ICYmIG5vZGUgJiYgbm9kZVsgZGlyIF0gfHxcblx0XHRcdFx0XHRcdFx0XHRcdChkaWZmID0gbm9kZUluZGV4ID0gMCkgfHwgc3RhcnQucG9wKCkpICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoICggb2ZUeXBlID9cblx0XHRcdFx0XHRcdFx0XHRcdFx0bm9kZS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpID09PSBuYW1lIDpcblx0XHRcdFx0XHRcdFx0XHRcdFx0bm9kZS5ub2RlVHlwZSA9PT0gMSApICYmXG5cdFx0XHRcdFx0XHRcdFx0XHRcdCsrZGlmZiApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBDYWNoZSB0aGUgaW5kZXggb2YgZWFjaCBlbmNvdW50ZXJlZCBlbGVtZW50XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGlmICggdXNlQ2FjaGUgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0b3V0ZXJDYWNoZSA9IG5vZGVbIGV4cGFuZG8gXSB8fCAobm9kZVsgZXhwYW5kbyBdID0ge30pO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgPDkgb25seVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIERlZmVuZCBhZ2FpbnN0IGNsb25lZCBhdHRyb3BlcnRpZXMgKGpRdWVyeSBnaC0xNzA5KVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHVuaXF1ZUNhY2hlID0gb3V0ZXJDYWNoZVsgbm9kZS51bmlxdWVJRCBdIHx8XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHQob3V0ZXJDYWNoZVsgbm9kZS51bmlxdWVJRCBdID0ge30pO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0dW5pcXVlQ2FjaGVbIHR5cGUgXSA9IFsgZGlycnVucywgZGlmZiBdO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBub2RlID09PSBlbGVtICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIEluY29ycG9yYXRlIHRoZSBvZmZzZXQsIHRoZW4gY2hlY2sgYWdhaW5zdCBjeWNsZSBzaXplXG5cdFx0XHRcdFx0XHRkaWZmIC09IGxhc3Q7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZGlmZiA9PT0gZmlyc3QgfHwgKCBkaWZmICUgZmlyc3QgPT09IDAgJiYgZGlmZiAvIGZpcnN0ID49IDAgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH07XG5cdFx0fSxcblxuXHRcdFwiUFNFVURPXCI6IGZ1bmN0aW9uKCBwc2V1ZG8sIGFyZ3VtZW50ICkge1xuXHRcdFx0Ly8gcHNldWRvLWNsYXNzIG5hbWVzIGFyZSBjYXNlLWluc2Vuc2l0aXZlXG5cdFx0XHQvLyBodHRwOi8vd3d3LnczLm9yZy9UUi9zZWxlY3RvcnMvI3BzZXVkby1jbGFzc2VzXG5cdFx0XHQvLyBQcmlvcml0aXplIGJ5IGNhc2Ugc2Vuc2l0aXZpdHkgaW4gY2FzZSBjdXN0b20gcHNldWRvcyBhcmUgYWRkZWQgd2l0aCB1cHBlcmNhc2UgbGV0dGVyc1xuXHRcdFx0Ly8gUmVtZW1iZXIgdGhhdCBzZXRGaWx0ZXJzIGluaGVyaXRzIGZyb20gcHNldWRvc1xuXHRcdFx0dmFyIGFyZ3MsXG5cdFx0XHRcdGZuID0gRXhwci5wc2V1ZG9zWyBwc2V1ZG8gXSB8fCBFeHByLnNldEZpbHRlcnNbIHBzZXVkby50b0xvd2VyQ2FzZSgpIF0gfHxcblx0XHRcdFx0XHRTaXp6bGUuZXJyb3IoIFwidW5zdXBwb3J0ZWQgcHNldWRvOiBcIiArIHBzZXVkbyApO1xuXG5cdFx0XHQvLyBUaGUgdXNlciBtYXkgdXNlIGNyZWF0ZVBzZXVkbyB0byBpbmRpY2F0ZSB0aGF0XG5cdFx0XHQvLyBhcmd1bWVudHMgYXJlIG5lZWRlZCB0byBjcmVhdGUgdGhlIGZpbHRlciBmdW5jdGlvblxuXHRcdFx0Ly8ganVzdCBhcyBTaXp6bGUgZG9lc1xuXHRcdFx0aWYgKCBmblsgZXhwYW5kbyBdICkge1xuXHRcdFx0XHRyZXR1cm4gZm4oIGFyZ3VtZW50ICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEJ1dCBtYWludGFpbiBzdXBwb3J0IGZvciBvbGQgc2lnbmF0dXJlc1xuXHRcdFx0aWYgKCBmbi5sZW5ndGggPiAxICkge1xuXHRcdFx0XHRhcmdzID0gWyBwc2V1ZG8sIHBzZXVkbywgXCJcIiwgYXJndW1lbnQgXTtcblx0XHRcdFx0cmV0dXJuIEV4cHIuc2V0RmlsdGVycy5oYXNPd25Qcm9wZXJ0eSggcHNldWRvLnRvTG93ZXJDYXNlKCkgKSA/XG5cdFx0XHRcdFx0bWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCBzZWVkLCBtYXRjaGVzICkge1xuXHRcdFx0XHRcdFx0dmFyIGlkeCxcblx0XHRcdFx0XHRcdFx0bWF0Y2hlZCA9IGZuKCBzZWVkLCBhcmd1bWVudCApLFxuXHRcdFx0XHRcdFx0XHRpID0gbWF0Y2hlZC5sZW5ndGg7XG5cdFx0XHRcdFx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdFx0XHRcdFx0aWR4ID0gaW5kZXhPZiggc2VlZCwgbWF0Y2hlZFtpXSApO1xuXHRcdFx0XHRcdFx0XHRzZWVkWyBpZHggXSA9ICEoIG1hdGNoZXNbIGlkeCBdID0gbWF0Y2hlZFtpXSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0pIDpcblx0XHRcdFx0XHRmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0XHRcdHJldHVybiBmbiggZWxlbSwgMCwgYXJncyApO1xuXHRcdFx0XHRcdH07XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBmbjtcblx0XHR9XG5cdH0sXG5cblx0cHNldWRvczoge1xuXHRcdC8vIFBvdGVudGlhbGx5IGNvbXBsZXggcHNldWRvc1xuXHRcdFwibm90XCI6IG1hcmtGdW5jdGlvbihmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0XHQvLyBUcmltIHRoZSBzZWxlY3RvciBwYXNzZWQgdG8gY29tcGlsZVxuXHRcdFx0Ly8gdG8gYXZvaWQgdHJlYXRpbmcgbGVhZGluZyBhbmQgdHJhaWxpbmdcblx0XHRcdC8vIHNwYWNlcyBhcyBjb21iaW5hdG9yc1xuXHRcdFx0dmFyIGlucHV0ID0gW10sXG5cdFx0XHRcdHJlc3VsdHMgPSBbXSxcblx0XHRcdFx0bWF0Y2hlciA9IGNvbXBpbGUoIHNlbGVjdG9yLnJlcGxhY2UoIHJ0cmltLCBcIiQxXCIgKSApO1xuXG5cdFx0XHRyZXR1cm4gbWF0Y2hlclsgZXhwYW5kbyBdID9cblx0XHRcdFx0bWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCBzZWVkLCBtYXRjaGVzLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHRcdFx0dmFyIGVsZW0sXG5cdFx0XHRcdFx0XHR1bm1hdGNoZWQgPSBtYXRjaGVyKCBzZWVkLCBudWxsLCB4bWwsIFtdICksXG5cdFx0XHRcdFx0XHRpID0gc2VlZC5sZW5ndGg7XG5cblx0XHRcdFx0XHQvLyBNYXRjaCBlbGVtZW50cyB1bm1hdGNoZWQgYnkgYG1hdGNoZXJgXG5cdFx0XHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdFx0XHRpZiAoIChlbGVtID0gdW5tYXRjaGVkW2ldKSApIHtcblx0XHRcdFx0XHRcdFx0c2VlZFtpXSA9ICEobWF0Y2hlc1tpXSA9IGVsZW0pO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSkgOlxuXHRcdFx0XHRmdW5jdGlvbiggZWxlbSwgY29udGV4dCwgeG1sICkge1xuXHRcdFx0XHRcdGlucHV0WzBdID0gZWxlbTtcblx0XHRcdFx0XHRtYXRjaGVyKCBpbnB1dCwgbnVsbCwgeG1sLCByZXN1bHRzICk7XG5cdFx0XHRcdFx0Ly8gRG9uJ3Qga2VlcCB0aGUgZWxlbWVudCAoaXNzdWUgIzI5OSlcblx0XHRcdFx0XHRpbnB1dFswXSA9IG51bGw7XG5cdFx0XHRcdFx0cmV0dXJuICFyZXN1bHRzLnBvcCgpO1xuXHRcdFx0XHR9O1xuXHRcdH0pLFxuXG5cdFx0XCJoYXNcIjogbWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRcdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0cmV0dXJuIFNpenpsZSggc2VsZWN0b3IsIGVsZW0gKS5sZW5ndGggPiAwO1xuXHRcdFx0fTtcblx0XHR9KSxcblxuXHRcdFwiY29udGFpbnNcIjogbWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCB0ZXh0ICkge1xuXHRcdFx0dGV4dCA9IHRleHQucmVwbGFjZSggcnVuZXNjYXBlLCBmdW5lc2NhcGUgKTtcblx0XHRcdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0cmV0dXJuICggZWxlbS50ZXh0Q29udGVudCB8fCBnZXRUZXh0KCBlbGVtICkgKS5pbmRleE9mKCB0ZXh0ICkgPiAtMTtcblx0XHRcdH07XG5cdFx0fSksXG5cblx0XHQvLyBcIldoZXRoZXIgYW4gZWxlbWVudCBpcyByZXByZXNlbnRlZCBieSBhIDpsYW5nKCkgc2VsZWN0b3Jcblx0XHQvLyBpcyBiYXNlZCBzb2xlbHkgb24gdGhlIGVsZW1lbnQncyBsYW5ndWFnZSB2YWx1ZVxuXHRcdC8vIGJlaW5nIGVxdWFsIHRvIHRoZSBpZGVudGlmaWVyIEMsXG5cdFx0Ly8gb3IgYmVnaW5uaW5nIHdpdGggdGhlIGlkZW50aWZpZXIgQyBpbW1lZGlhdGVseSBmb2xsb3dlZCBieSBcIi1cIi5cblx0XHQvLyBUaGUgbWF0Y2hpbmcgb2YgQyBhZ2FpbnN0IHRoZSBlbGVtZW50J3MgbGFuZ3VhZ2UgdmFsdWUgaXMgcGVyZm9ybWVkIGNhc2UtaW5zZW5zaXRpdmVseS5cblx0XHQvLyBUaGUgaWRlbnRpZmllciBDIGRvZXMgbm90IGhhdmUgdG8gYmUgYSB2YWxpZCBsYW5ndWFnZSBuYW1lLlwiXG5cdFx0Ly8gaHR0cDovL3d3dy53My5vcmcvVFIvc2VsZWN0b3JzLyNsYW5nLXBzZXVkb1xuXHRcdFwibGFuZ1wiOiBtYXJrRnVuY3Rpb24oIGZ1bmN0aW9uKCBsYW5nICkge1xuXHRcdFx0Ly8gbGFuZyB2YWx1ZSBtdXN0IGJlIGEgdmFsaWQgaWRlbnRpZmllclxuXHRcdFx0aWYgKCAhcmlkZW50aWZpZXIudGVzdChsYW5nIHx8IFwiXCIpICkge1xuXHRcdFx0XHRTaXp6bGUuZXJyb3IoIFwidW5zdXBwb3J0ZWQgbGFuZzogXCIgKyBsYW5nICk7XG5cdFx0XHR9XG5cdFx0XHRsYW5nID0gbGFuZy5yZXBsYWNlKCBydW5lc2NhcGUsIGZ1bmVzY2FwZSApLnRvTG93ZXJDYXNlKCk7XG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRcdHZhciBlbGVtTGFuZztcblx0XHRcdFx0ZG8ge1xuXHRcdFx0XHRcdGlmICggKGVsZW1MYW5nID0gZG9jdW1lbnRJc0hUTUwgP1xuXHRcdFx0XHRcdFx0ZWxlbS5sYW5nIDpcblx0XHRcdFx0XHRcdGVsZW0uZ2V0QXR0cmlidXRlKFwieG1sOmxhbmdcIikgfHwgZWxlbS5nZXRBdHRyaWJ1dGUoXCJsYW5nXCIpKSApIHtcblxuXHRcdFx0XHRcdFx0ZWxlbUxhbmcgPSBlbGVtTGFuZy50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0XHRcdFx0cmV0dXJuIGVsZW1MYW5nID09PSBsYW5nIHx8IGVsZW1MYW5nLmluZGV4T2YoIGxhbmcgKyBcIi1cIiApID09PSAwO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSB3aGlsZSAoIChlbGVtID0gZWxlbS5wYXJlbnROb2RlKSAmJiBlbGVtLm5vZGVUeXBlID09PSAxICk7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH07XG5cdFx0fSksXG5cblx0XHQvLyBNaXNjZWxsYW5lb3VzXG5cdFx0XCJ0YXJnZXRcIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHR2YXIgaGFzaCA9IHdpbmRvdy5sb2NhdGlvbiAmJiB3aW5kb3cubG9jYXRpb24uaGFzaDtcblx0XHRcdHJldHVybiBoYXNoICYmIGhhc2guc2xpY2UoIDEgKSA9PT0gZWxlbS5pZDtcblx0XHR9LFxuXG5cdFx0XCJyb290XCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIGVsZW0gPT09IGRvY0VsZW07XG5cdFx0fSxcblxuXHRcdFwiZm9jdXNcIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gZWxlbSA9PT0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCAmJiAoIWRvY3VtZW50Lmhhc0ZvY3VzIHx8IGRvY3VtZW50Lmhhc0ZvY3VzKCkpICYmICEhKGVsZW0udHlwZSB8fCBlbGVtLmhyZWYgfHwgfmVsZW0udGFiSW5kZXgpO1xuXHRcdH0sXG5cblx0XHQvLyBCb29sZWFuIHByb3BlcnRpZXNcblx0XHRcImVuYWJsZWRcIjogY3JlYXRlRGlzYWJsZWRQc2V1ZG8oIGZhbHNlICksXG5cdFx0XCJkaXNhYmxlZFwiOiBjcmVhdGVEaXNhYmxlZFBzZXVkbyggdHJ1ZSApLFxuXG5cdFx0XCJjaGVja2VkXCI6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0Ly8gSW4gQ1NTMywgOmNoZWNrZWQgc2hvdWxkIHJldHVybiBib3RoIGNoZWNrZWQgYW5kIHNlbGVjdGVkIGVsZW1lbnRzXG5cdFx0XHQvLyBodHRwOi8vd3d3LnczLm9yZy9UUi8yMDExL1JFQy1jc3MzLXNlbGVjdG9ycy0yMDExMDkyOS8jY2hlY2tlZFxuXHRcdFx0dmFyIG5vZGVOYW1lID0gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXHRcdFx0cmV0dXJuIChub2RlTmFtZSA9PT0gXCJpbnB1dFwiICYmICEhZWxlbS5jaGVja2VkKSB8fCAobm9kZU5hbWUgPT09IFwib3B0aW9uXCIgJiYgISFlbGVtLnNlbGVjdGVkKTtcblx0XHR9LFxuXG5cdFx0XCJzZWxlY3RlZFwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdC8vIEFjY2Vzc2luZyB0aGlzIHByb3BlcnR5IG1ha2VzIHNlbGVjdGVkLWJ5LWRlZmF1bHRcblx0XHRcdC8vIG9wdGlvbnMgaW4gU2FmYXJpIHdvcmsgcHJvcGVybHlcblx0XHRcdGlmICggZWxlbS5wYXJlbnROb2RlICkge1xuXHRcdFx0XHRlbGVtLnBhcmVudE5vZGUuc2VsZWN0ZWRJbmRleDtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGVsZW0uc2VsZWN0ZWQgPT09IHRydWU7XG5cdFx0fSxcblxuXHRcdC8vIENvbnRlbnRzXG5cdFx0XCJlbXB0eVwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdC8vIGh0dHA6Ly93d3cudzMub3JnL1RSL3NlbGVjdG9ycy8jZW1wdHktcHNldWRvXG5cdFx0XHQvLyA6ZW1wdHkgaXMgbmVnYXRlZCBieSBlbGVtZW50ICgxKSBvciBjb250ZW50IG5vZGVzICh0ZXh0OiAzOyBjZGF0YTogNDsgZW50aXR5IHJlZjogNSksXG5cdFx0XHQvLyAgIGJ1dCBub3QgYnkgb3RoZXJzIChjb21tZW50OiA4OyBwcm9jZXNzaW5nIGluc3RydWN0aW9uOiA3OyBldGMuKVxuXHRcdFx0Ly8gbm9kZVR5cGUgPCA2IHdvcmtzIGJlY2F1c2UgYXR0cmlidXRlcyAoMikgZG8gbm90IGFwcGVhciBhcyBjaGlsZHJlblxuXHRcdFx0Zm9yICggZWxlbSA9IGVsZW0uZmlyc3RDaGlsZDsgZWxlbTsgZWxlbSA9IGVsZW0ubmV4dFNpYmxpbmcgKSB7XG5cdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA8IDYgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9LFxuXG5cdFx0XCJwYXJlbnRcIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gIUV4cHIucHNldWRvc1tcImVtcHR5XCJdKCBlbGVtICk7XG5cdFx0fSxcblxuXHRcdC8vIEVsZW1lbnQvaW5wdXQgdHlwZXNcblx0XHRcImhlYWRlclwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiByaGVhZGVyLnRlc3QoIGVsZW0ubm9kZU5hbWUgKTtcblx0XHR9LFxuXG5cdFx0XCJpbnB1dFwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiByaW5wdXRzLnRlc3QoIGVsZW0ubm9kZU5hbWUgKTtcblx0XHR9LFxuXG5cdFx0XCJidXR0b25cIjogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHR2YXIgbmFtZSA9IGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHRcdHJldHVybiBuYW1lID09PSBcImlucHV0XCIgJiYgZWxlbS50eXBlID09PSBcImJ1dHRvblwiIHx8IG5hbWUgPT09IFwiYnV0dG9uXCI7XG5cdFx0fSxcblxuXHRcdFwidGV4dFwiOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHZhciBhdHRyO1xuXHRcdFx0cmV0dXJuIGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0gXCJpbnB1dFwiICYmXG5cdFx0XHRcdGVsZW0udHlwZSA9PT0gXCJ0ZXh0XCIgJiZcblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBJRTw4XG5cdFx0XHRcdC8vIE5ldyBIVE1MNSBhdHRyaWJ1dGUgdmFsdWVzIChlLmcuLCBcInNlYXJjaFwiKSBhcHBlYXIgd2l0aCBlbGVtLnR5cGUgPT09IFwidGV4dFwiXG5cdFx0XHRcdCggKGF0dHIgPSBlbGVtLmdldEF0dHJpYnV0ZShcInR5cGVcIikpID09IG51bGwgfHwgYXR0ci50b0xvd2VyQ2FzZSgpID09PSBcInRleHRcIiApO1xuXHRcdH0sXG5cblx0XHQvLyBQb3NpdGlvbi1pbi1jb2xsZWN0aW9uXG5cdFx0XCJmaXJzdFwiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIFsgMCBdO1xuXHRcdH0pLFxuXG5cdFx0XCJsYXN0XCI6IGNyZWF0ZVBvc2l0aW9uYWxQc2V1ZG8oZnVuY3Rpb24oIG1hdGNoSW5kZXhlcywgbGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIFsgbGVuZ3RoIC0gMSBdO1xuXHRcdH0pLFxuXG5cdFx0XCJlcVwiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCwgYXJndW1lbnQgKSB7XG5cdFx0XHRyZXR1cm4gWyBhcmd1bWVudCA8IDAgPyBhcmd1bWVudCArIGxlbmd0aCA6IGFyZ3VtZW50IF07XG5cdFx0fSksXG5cblx0XHRcImV2ZW5cIjogY3JlYXRlUG9zaXRpb25hbFBzZXVkbyhmdW5jdGlvbiggbWF0Y2hJbmRleGVzLCBsZW5ndGggKSB7XG5cdFx0XHR2YXIgaSA9IDA7XG5cdFx0XHRmb3IgKCA7IGkgPCBsZW5ndGg7IGkgKz0gMiApIHtcblx0XHRcdFx0bWF0Y2hJbmRleGVzLnB1c2goIGkgKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiBtYXRjaEluZGV4ZXM7XG5cdFx0fSksXG5cblx0XHRcIm9kZFwiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCApIHtcblx0XHRcdHZhciBpID0gMTtcblx0XHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSArPSAyICkge1xuXHRcdFx0XHRtYXRjaEluZGV4ZXMucHVzaCggaSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG1hdGNoSW5kZXhlcztcblx0XHR9KSxcblxuXHRcdFwibHRcIjogY3JlYXRlUG9zaXRpb25hbFBzZXVkbyhmdW5jdGlvbiggbWF0Y2hJbmRleGVzLCBsZW5ndGgsIGFyZ3VtZW50ICkge1xuXHRcdFx0dmFyIGkgPSBhcmd1bWVudCA8IDAgP1xuXHRcdFx0XHRhcmd1bWVudCArIGxlbmd0aCA6XG5cdFx0XHRcdGFyZ3VtZW50ID4gbGVuZ3RoID9cblx0XHRcdFx0XHRsZW5ndGggOlxuXHRcdFx0XHRcdGFyZ3VtZW50O1xuXHRcdFx0Zm9yICggOyAtLWkgPj0gMDsgKSB7XG5cdFx0XHRcdG1hdGNoSW5kZXhlcy5wdXNoKCBpICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gbWF0Y2hJbmRleGVzO1xuXHRcdH0pLFxuXG5cdFx0XCJndFwiOiBjcmVhdGVQb3NpdGlvbmFsUHNldWRvKGZ1bmN0aW9uKCBtYXRjaEluZGV4ZXMsIGxlbmd0aCwgYXJndW1lbnQgKSB7XG5cdFx0XHR2YXIgaSA9IGFyZ3VtZW50IDwgMCA/IGFyZ3VtZW50ICsgbGVuZ3RoIDogYXJndW1lbnQ7XG5cdFx0XHRmb3IgKCA7ICsraSA8IGxlbmd0aDsgKSB7XG5cdFx0XHRcdG1hdGNoSW5kZXhlcy5wdXNoKCBpICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gbWF0Y2hJbmRleGVzO1xuXHRcdH0pXG5cdH1cbn07XG5cbkV4cHIucHNldWRvc1tcIm50aFwiXSA9IEV4cHIucHNldWRvc1tcImVxXCJdO1xuXG4vLyBBZGQgYnV0dG9uL2lucHV0IHR5cGUgcHNldWRvc1xuZm9yICggaSBpbiB7IHJhZGlvOiB0cnVlLCBjaGVja2JveDogdHJ1ZSwgZmlsZTogdHJ1ZSwgcGFzc3dvcmQ6IHRydWUsIGltYWdlOiB0cnVlIH0gKSB7XG5cdEV4cHIucHNldWRvc1sgaSBdID0gY3JlYXRlSW5wdXRQc2V1ZG8oIGkgKTtcbn1cbmZvciAoIGkgaW4geyBzdWJtaXQ6IHRydWUsIHJlc2V0OiB0cnVlIH0gKSB7XG5cdEV4cHIucHNldWRvc1sgaSBdID0gY3JlYXRlQnV0dG9uUHNldWRvKCBpICk7XG59XG5cbi8vIEVhc3kgQVBJIGZvciBjcmVhdGluZyBuZXcgc2V0RmlsdGVyc1xuZnVuY3Rpb24gc2V0RmlsdGVycygpIHt9XG5zZXRGaWx0ZXJzLnByb3RvdHlwZSA9IEV4cHIuZmlsdGVycyA9IEV4cHIucHNldWRvcztcbkV4cHIuc2V0RmlsdGVycyA9IG5ldyBzZXRGaWx0ZXJzKCk7XG5cbnRva2VuaXplID0gU2l6emxlLnRva2VuaXplID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBwYXJzZU9ubHkgKSB7XG5cdHZhciBtYXRjaGVkLCBtYXRjaCwgdG9rZW5zLCB0eXBlLFxuXHRcdHNvRmFyLCBncm91cHMsIHByZUZpbHRlcnMsXG5cdFx0Y2FjaGVkID0gdG9rZW5DYWNoZVsgc2VsZWN0b3IgKyBcIiBcIiBdO1xuXG5cdGlmICggY2FjaGVkICkge1xuXHRcdHJldHVybiBwYXJzZU9ubHkgPyAwIDogY2FjaGVkLnNsaWNlKCAwICk7XG5cdH1cblxuXHRzb0ZhciA9IHNlbGVjdG9yO1xuXHRncm91cHMgPSBbXTtcblx0cHJlRmlsdGVycyA9IEV4cHIucHJlRmlsdGVyO1xuXG5cdHdoaWxlICggc29GYXIgKSB7XG5cblx0XHQvLyBDb21tYSBhbmQgZmlyc3QgcnVuXG5cdFx0aWYgKCAhbWF0Y2hlZCB8fCAobWF0Y2ggPSByY29tbWEuZXhlYyggc29GYXIgKSkgKSB7XG5cdFx0XHRpZiAoIG1hdGNoICkge1xuXHRcdFx0XHQvLyBEb24ndCBjb25zdW1lIHRyYWlsaW5nIGNvbW1hcyBhcyB2YWxpZFxuXHRcdFx0XHRzb0ZhciA9IHNvRmFyLnNsaWNlKCBtYXRjaFswXS5sZW5ndGggKSB8fCBzb0Zhcjtcblx0XHRcdH1cblx0XHRcdGdyb3Vwcy5wdXNoKCAodG9rZW5zID0gW10pICk7XG5cdFx0fVxuXG5cdFx0bWF0Y2hlZCA9IGZhbHNlO1xuXG5cdFx0Ly8gQ29tYmluYXRvcnNcblx0XHRpZiAoIChtYXRjaCA9IHJjb21iaW5hdG9ycy5leGVjKCBzb0ZhciApKSApIHtcblx0XHRcdG1hdGNoZWQgPSBtYXRjaC5zaGlmdCgpO1xuXHRcdFx0dG9rZW5zLnB1c2goe1xuXHRcdFx0XHR2YWx1ZTogbWF0Y2hlZCxcblx0XHRcdFx0Ly8gQ2FzdCBkZXNjZW5kYW50IGNvbWJpbmF0b3JzIHRvIHNwYWNlXG5cdFx0XHRcdHR5cGU6IG1hdGNoWzBdLnJlcGxhY2UoIHJ0cmltLCBcIiBcIiApXG5cdFx0XHR9KTtcblx0XHRcdHNvRmFyID0gc29GYXIuc2xpY2UoIG1hdGNoZWQubGVuZ3RoICk7XG5cdFx0fVxuXG5cdFx0Ly8gRmlsdGVyc1xuXHRcdGZvciAoIHR5cGUgaW4gRXhwci5maWx0ZXIgKSB7XG5cdFx0XHRpZiAoIChtYXRjaCA9IG1hdGNoRXhwclsgdHlwZSBdLmV4ZWMoIHNvRmFyICkpICYmICghcHJlRmlsdGVyc1sgdHlwZSBdIHx8XG5cdFx0XHRcdChtYXRjaCA9IHByZUZpbHRlcnNbIHR5cGUgXSggbWF0Y2ggKSkpICkge1xuXHRcdFx0XHRtYXRjaGVkID0gbWF0Y2guc2hpZnQoKTtcblx0XHRcdFx0dG9rZW5zLnB1c2goe1xuXHRcdFx0XHRcdHZhbHVlOiBtYXRjaGVkLFxuXHRcdFx0XHRcdHR5cGU6IHR5cGUsXG5cdFx0XHRcdFx0bWF0Y2hlczogbWF0Y2hcblx0XHRcdFx0fSk7XG5cdFx0XHRcdHNvRmFyID0gc29GYXIuc2xpY2UoIG1hdGNoZWQubGVuZ3RoICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCAhbWF0Y2hlZCApIHtcblx0XHRcdGJyZWFrO1xuXHRcdH1cblx0fVxuXG5cdC8vIFJldHVybiB0aGUgbGVuZ3RoIG9mIHRoZSBpbnZhbGlkIGV4Y2Vzc1xuXHQvLyBpZiB3ZSdyZSBqdXN0IHBhcnNpbmdcblx0Ly8gT3RoZXJ3aXNlLCB0aHJvdyBhbiBlcnJvciBvciByZXR1cm4gdG9rZW5zXG5cdHJldHVybiBwYXJzZU9ubHkgP1xuXHRcdHNvRmFyLmxlbmd0aCA6XG5cdFx0c29GYXIgP1xuXHRcdFx0U2l6emxlLmVycm9yKCBzZWxlY3RvciApIDpcblx0XHRcdC8vIENhY2hlIHRoZSB0b2tlbnNcblx0XHRcdHRva2VuQ2FjaGUoIHNlbGVjdG9yLCBncm91cHMgKS5zbGljZSggMCApO1xufTtcblxuZnVuY3Rpb24gdG9TZWxlY3RvciggdG9rZW5zICkge1xuXHR2YXIgaSA9IDAsXG5cdFx0bGVuID0gdG9rZW5zLmxlbmd0aCxcblx0XHRzZWxlY3RvciA9IFwiXCI7XG5cdGZvciAoIDsgaSA8IGxlbjsgaSsrICkge1xuXHRcdHNlbGVjdG9yICs9IHRva2Vuc1tpXS52YWx1ZTtcblx0fVxuXHRyZXR1cm4gc2VsZWN0b3I7XG59XG5cbmZ1bmN0aW9uIGFkZENvbWJpbmF0b3IoIG1hdGNoZXIsIGNvbWJpbmF0b3IsIGJhc2UgKSB7XG5cdHZhciBkaXIgPSBjb21iaW5hdG9yLmRpcixcblx0XHRza2lwID0gY29tYmluYXRvci5uZXh0LFxuXHRcdGtleSA9IHNraXAgfHwgZGlyLFxuXHRcdGNoZWNrTm9uRWxlbWVudHMgPSBiYXNlICYmIGtleSA9PT0gXCJwYXJlbnROb2RlXCIsXG5cdFx0ZG9uZU5hbWUgPSBkb25lKys7XG5cblx0cmV0dXJuIGNvbWJpbmF0b3IuZmlyc3QgP1xuXHRcdC8vIENoZWNrIGFnYWluc3QgY2xvc2VzdCBhbmNlc3Rvci9wcmVjZWRpbmcgZWxlbWVudFxuXHRcdGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHR3aGlsZSAoIChlbGVtID0gZWxlbVsgZGlyIF0pICkge1xuXHRcdFx0XHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgfHwgY2hlY2tOb25FbGVtZW50cyApIHtcblx0XHRcdFx0XHRyZXR1cm4gbWF0Y2hlciggZWxlbSwgY29udGV4dCwgeG1sICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9IDpcblxuXHRcdC8vIENoZWNrIGFnYWluc3QgYWxsIGFuY2VzdG9yL3ByZWNlZGluZyBlbGVtZW50c1xuXHRcdGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHR2YXIgb2xkQ2FjaGUsIHVuaXF1ZUNhY2hlLCBvdXRlckNhY2hlLFxuXHRcdFx0XHRuZXdDYWNoZSA9IFsgZGlycnVucywgZG9uZU5hbWUgXTtcblxuXHRcdFx0Ly8gV2UgY2FuJ3Qgc2V0IGFyYml0cmFyeSBkYXRhIG9uIFhNTCBub2Rlcywgc28gdGhleSBkb24ndCBiZW5lZml0IGZyb20gY29tYmluYXRvciBjYWNoaW5nXG5cdFx0XHRpZiAoIHhtbCApIHtcblx0XHRcdFx0d2hpbGUgKCAoZWxlbSA9IGVsZW1bIGRpciBdKSApIHtcblx0XHRcdFx0XHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgfHwgY2hlY2tOb25FbGVtZW50cyApIHtcblx0XHRcdFx0XHRcdGlmICggbWF0Y2hlciggZWxlbSwgY29udGV4dCwgeG1sICkgKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0d2hpbGUgKCAoZWxlbSA9IGVsZW1bIGRpciBdKSApIHtcblx0XHRcdFx0XHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgfHwgY2hlY2tOb25FbGVtZW50cyApIHtcblx0XHRcdFx0XHRcdG91dGVyQ2FjaGUgPSBlbGVtWyBleHBhbmRvIF0gfHwgKGVsZW1bIGV4cGFuZG8gXSA9IHt9KTtcblxuXHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgPDkgb25seVxuXHRcdFx0XHRcdFx0Ly8gRGVmZW5kIGFnYWluc3QgY2xvbmVkIGF0dHJvcGVydGllcyAoalF1ZXJ5IGdoLTE3MDkpXG5cdFx0XHRcdFx0XHR1bmlxdWVDYWNoZSA9IG91dGVyQ2FjaGVbIGVsZW0udW5pcXVlSUQgXSB8fCAob3V0ZXJDYWNoZVsgZWxlbS51bmlxdWVJRCBdID0ge30pO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHNraXAgJiYgc2tpcCA9PT0gZWxlbS5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpICkge1xuXHRcdFx0XHRcdFx0XHRlbGVtID0gZWxlbVsgZGlyIF0gfHwgZWxlbTtcblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIChvbGRDYWNoZSA9IHVuaXF1ZUNhY2hlWyBrZXkgXSkgJiZcblx0XHRcdFx0XHRcdFx0b2xkQ2FjaGVbIDAgXSA9PT0gZGlycnVucyAmJiBvbGRDYWNoZVsgMSBdID09PSBkb25lTmFtZSApIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBBc3NpZ24gdG8gbmV3Q2FjaGUgc28gcmVzdWx0cyBiYWNrLXByb3BhZ2F0ZSB0byBwcmV2aW91cyBlbGVtZW50c1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gKG5ld0NhY2hlWyAyIF0gPSBvbGRDYWNoZVsgMiBdKTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdC8vIFJldXNlIG5ld2NhY2hlIHNvIHJlc3VsdHMgYmFjay1wcm9wYWdhdGUgdG8gcHJldmlvdXMgZWxlbWVudHNcblx0XHRcdFx0XHRcdFx0dW5pcXVlQ2FjaGVbIGtleSBdID0gbmV3Q2FjaGU7XG5cblx0XHRcdFx0XHRcdFx0Ly8gQSBtYXRjaCBtZWFucyB3ZSdyZSBkb25lOyBhIGZhaWwgbWVhbnMgd2UgaGF2ZSB0byBrZWVwIGNoZWNraW5nXG5cdFx0XHRcdFx0XHRcdGlmICggKG5ld0NhY2hlWyAyIF0gPSBtYXRjaGVyKCBlbGVtLCBjb250ZXh0LCB4bWwgKSkgKSB7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9O1xufVxuXG5mdW5jdGlvbiBlbGVtZW50TWF0Y2hlciggbWF0Y2hlcnMgKSB7XG5cdHJldHVybiBtYXRjaGVycy5sZW5ndGggPiAxID9cblx0XHRmdW5jdGlvbiggZWxlbSwgY29udGV4dCwgeG1sICkge1xuXHRcdFx0dmFyIGkgPSBtYXRjaGVycy5sZW5ndGg7XG5cdFx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdFx0aWYgKCAhbWF0Y2hlcnNbaV0oIGVsZW0sIGNvbnRleHQsIHhtbCApICkge1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fSA6XG5cdFx0bWF0Y2hlcnNbMF07XG59XG5cbmZ1bmN0aW9uIG11bHRpcGxlQ29udGV4dHMoIHNlbGVjdG9yLCBjb250ZXh0cywgcmVzdWx0cyApIHtcblx0dmFyIGkgPSAwLFxuXHRcdGxlbiA9IGNvbnRleHRzLmxlbmd0aDtcblx0Zm9yICggOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0U2l6emxlKCBzZWxlY3RvciwgY29udGV4dHNbaV0sIHJlc3VsdHMgKTtcblx0fVxuXHRyZXR1cm4gcmVzdWx0cztcbn1cblxuZnVuY3Rpb24gY29uZGVuc2UoIHVubWF0Y2hlZCwgbWFwLCBmaWx0ZXIsIGNvbnRleHQsIHhtbCApIHtcblx0dmFyIGVsZW0sXG5cdFx0bmV3VW5tYXRjaGVkID0gW10sXG5cdFx0aSA9IDAsXG5cdFx0bGVuID0gdW5tYXRjaGVkLmxlbmd0aCxcblx0XHRtYXBwZWQgPSBtYXAgIT0gbnVsbDtcblxuXHRmb3IgKCA7IGkgPCBsZW47IGkrKyApIHtcblx0XHRpZiAoIChlbGVtID0gdW5tYXRjaGVkW2ldKSApIHtcblx0XHRcdGlmICggIWZpbHRlciB8fCBmaWx0ZXIoIGVsZW0sIGNvbnRleHQsIHhtbCApICkge1xuXHRcdFx0XHRuZXdVbm1hdGNoZWQucHVzaCggZWxlbSApO1xuXHRcdFx0XHRpZiAoIG1hcHBlZCApIHtcblx0XHRcdFx0XHRtYXAucHVzaCggaSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIG5ld1VubWF0Y2hlZDtcbn1cblxuZnVuY3Rpb24gc2V0TWF0Y2hlciggcHJlRmlsdGVyLCBzZWxlY3RvciwgbWF0Y2hlciwgcG9zdEZpbHRlciwgcG9zdEZpbmRlciwgcG9zdFNlbGVjdG9yICkge1xuXHRpZiAoIHBvc3RGaWx0ZXIgJiYgIXBvc3RGaWx0ZXJbIGV4cGFuZG8gXSApIHtcblx0XHRwb3N0RmlsdGVyID0gc2V0TWF0Y2hlciggcG9zdEZpbHRlciApO1xuXHR9XG5cdGlmICggcG9zdEZpbmRlciAmJiAhcG9zdEZpbmRlclsgZXhwYW5kbyBdICkge1xuXHRcdHBvc3RGaW5kZXIgPSBzZXRNYXRjaGVyKCBwb3N0RmluZGVyLCBwb3N0U2VsZWN0b3IgKTtcblx0fVxuXHRyZXR1cm4gbWFya0Z1bmN0aW9uKGZ1bmN0aW9uKCBzZWVkLCByZXN1bHRzLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0dmFyIHRlbXAsIGksIGVsZW0sXG5cdFx0XHRwcmVNYXAgPSBbXSxcblx0XHRcdHBvc3RNYXAgPSBbXSxcblx0XHRcdHByZWV4aXN0aW5nID0gcmVzdWx0cy5sZW5ndGgsXG5cblx0XHRcdC8vIEdldCBpbml0aWFsIGVsZW1lbnRzIGZyb20gc2VlZCBvciBjb250ZXh0XG5cdFx0XHRlbGVtcyA9IHNlZWQgfHwgbXVsdGlwbGVDb250ZXh0cyggc2VsZWN0b3IgfHwgXCIqXCIsIGNvbnRleHQubm9kZVR5cGUgPyBbIGNvbnRleHQgXSA6IGNvbnRleHQsIFtdICksXG5cblx0XHRcdC8vIFByZWZpbHRlciB0byBnZXQgbWF0Y2hlciBpbnB1dCwgcHJlc2VydmluZyBhIG1hcCBmb3Igc2VlZC1yZXN1bHRzIHN5bmNocm9uaXphdGlvblxuXHRcdFx0bWF0Y2hlckluID0gcHJlRmlsdGVyICYmICggc2VlZCB8fCAhc2VsZWN0b3IgKSA/XG5cdFx0XHRcdGNvbmRlbnNlKCBlbGVtcywgcHJlTWFwLCBwcmVGaWx0ZXIsIGNvbnRleHQsIHhtbCApIDpcblx0XHRcdFx0ZWxlbXMsXG5cblx0XHRcdG1hdGNoZXJPdXQgPSBtYXRjaGVyID9cblx0XHRcdFx0Ly8gSWYgd2UgaGF2ZSBhIHBvc3RGaW5kZXIsIG9yIGZpbHRlcmVkIHNlZWQsIG9yIG5vbi1zZWVkIHBvc3RGaWx0ZXIgb3IgcHJlZXhpc3RpbmcgcmVzdWx0cyxcblx0XHRcdFx0cG9zdEZpbmRlciB8fCAoIHNlZWQgPyBwcmVGaWx0ZXIgOiBwcmVleGlzdGluZyB8fCBwb3N0RmlsdGVyICkgP1xuXG5cdFx0XHRcdFx0Ly8gLi4uaW50ZXJtZWRpYXRlIHByb2Nlc3NpbmcgaXMgbmVjZXNzYXJ5XG5cdFx0XHRcdFx0W10gOlxuXG5cdFx0XHRcdFx0Ly8gLi4ub3RoZXJ3aXNlIHVzZSByZXN1bHRzIGRpcmVjdGx5XG5cdFx0XHRcdFx0cmVzdWx0cyA6XG5cdFx0XHRcdG1hdGNoZXJJbjtcblxuXHRcdC8vIEZpbmQgcHJpbWFyeSBtYXRjaGVzXG5cdFx0aWYgKCBtYXRjaGVyICkge1xuXHRcdFx0bWF0Y2hlciggbWF0Y2hlckluLCBtYXRjaGVyT3V0LCBjb250ZXh0LCB4bWwgKTtcblx0XHR9XG5cblx0XHQvLyBBcHBseSBwb3N0RmlsdGVyXG5cdFx0aWYgKCBwb3N0RmlsdGVyICkge1xuXHRcdFx0dGVtcCA9IGNvbmRlbnNlKCBtYXRjaGVyT3V0LCBwb3N0TWFwICk7XG5cdFx0XHRwb3N0RmlsdGVyKCB0ZW1wLCBbXSwgY29udGV4dCwgeG1sICk7XG5cblx0XHRcdC8vIFVuLW1hdGNoIGZhaWxpbmcgZWxlbWVudHMgYnkgbW92aW5nIHRoZW0gYmFjayB0byBtYXRjaGVySW5cblx0XHRcdGkgPSB0ZW1wLmxlbmd0aDtcblx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRpZiAoIChlbGVtID0gdGVtcFtpXSkgKSB7XG5cdFx0XHRcdFx0bWF0Y2hlck91dFsgcG9zdE1hcFtpXSBdID0gIShtYXRjaGVySW5bIHBvc3RNYXBbaV0gXSA9IGVsZW0pO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBzZWVkICkge1xuXHRcdFx0aWYgKCBwb3N0RmluZGVyIHx8IHByZUZpbHRlciApIHtcblx0XHRcdFx0aWYgKCBwb3N0RmluZGVyICkge1xuXHRcdFx0XHRcdC8vIEdldCB0aGUgZmluYWwgbWF0Y2hlck91dCBieSBjb25kZW5zaW5nIHRoaXMgaW50ZXJtZWRpYXRlIGludG8gcG9zdEZpbmRlciBjb250ZXh0c1xuXHRcdFx0XHRcdHRlbXAgPSBbXTtcblx0XHRcdFx0XHRpID0gbWF0Y2hlck91dC5sZW5ndGg7XG5cdFx0XHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdFx0XHRpZiAoIChlbGVtID0gbWF0Y2hlck91dFtpXSkgKSB7XG5cdFx0XHRcdFx0XHRcdC8vIFJlc3RvcmUgbWF0Y2hlckluIHNpbmNlIGVsZW0gaXMgbm90IHlldCBhIGZpbmFsIG1hdGNoXG5cdFx0XHRcdFx0XHRcdHRlbXAucHVzaCggKG1hdGNoZXJJbltpXSA9IGVsZW0pICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHBvc3RGaW5kZXIoIG51bGwsIChtYXRjaGVyT3V0ID0gW10pLCB0ZW1wLCB4bWwgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIE1vdmUgbWF0Y2hlZCBlbGVtZW50cyBmcm9tIHNlZWQgdG8gcmVzdWx0cyB0byBrZWVwIHRoZW0gc3luY2hyb25pemVkXG5cdFx0XHRcdGkgPSBtYXRjaGVyT3V0Lmxlbmd0aDtcblx0XHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdFx0aWYgKCAoZWxlbSA9IG1hdGNoZXJPdXRbaV0pICYmXG5cdFx0XHRcdFx0XHQodGVtcCA9IHBvc3RGaW5kZXIgPyBpbmRleE9mKCBzZWVkLCBlbGVtICkgOiBwcmVNYXBbaV0pID4gLTEgKSB7XG5cblx0XHRcdFx0XHRcdHNlZWRbdGVtcF0gPSAhKHJlc3VsdHNbdGVtcF0gPSBlbGVtKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdC8vIEFkZCBlbGVtZW50cyB0byByZXN1bHRzLCB0aHJvdWdoIHBvc3RGaW5kZXIgaWYgZGVmaW5lZFxuXHRcdH0gZWxzZSB7XG5cdFx0XHRtYXRjaGVyT3V0ID0gY29uZGVuc2UoXG5cdFx0XHRcdG1hdGNoZXJPdXQgPT09IHJlc3VsdHMgP1xuXHRcdFx0XHRcdG1hdGNoZXJPdXQuc3BsaWNlKCBwcmVleGlzdGluZywgbWF0Y2hlck91dC5sZW5ndGggKSA6XG5cdFx0XHRcdFx0bWF0Y2hlck91dFxuXHRcdFx0KTtcblx0XHRcdGlmICggcG9zdEZpbmRlciApIHtcblx0XHRcdFx0cG9zdEZpbmRlciggbnVsbCwgcmVzdWx0cywgbWF0Y2hlck91dCwgeG1sICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRwdXNoLmFwcGx5KCByZXN1bHRzLCBtYXRjaGVyT3V0ICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9KTtcbn1cblxuZnVuY3Rpb24gbWF0Y2hlckZyb21Ub2tlbnMoIHRva2VucyApIHtcblx0dmFyIGNoZWNrQ29udGV4dCwgbWF0Y2hlciwgaixcblx0XHRsZW4gPSB0b2tlbnMubGVuZ3RoLFxuXHRcdGxlYWRpbmdSZWxhdGl2ZSA9IEV4cHIucmVsYXRpdmVbIHRva2Vuc1swXS50eXBlIF0sXG5cdFx0aW1wbGljaXRSZWxhdGl2ZSA9IGxlYWRpbmdSZWxhdGl2ZSB8fCBFeHByLnJlbGF0aXZlW1wiIFwiXSxcblx0XHRpID0gbGVhZGluZ1JlbGF0aXZlID8gMSA6IDAsXG5cblx0XHQvLyBUaGUgZm91bmRhdGlvbmFsIG1hdGNoZXIgZW5zdXJlcyB0aGF0IGVsZW1lbnRzIGFyZSByZWFjaGFibGUgZnJvbSB0b3AtbGV2ZWwgY29udGV4dChzKVxuXHRcdG1hdGNoQ29udGV4dCA9IGFkZENvbWJpbmF0b3IoIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIGVsZW0gPT09IGNoZWNrQ29udGV4dDtcblx0XHR9LCBpbXBsaWNpdFJlbGF0aXZlLCB0cnVlICksXG5cdFx0bWF0Y2hBbnlDb250ZXh0ID0gYWRkQ29tYmluYXRvciggZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gaW5kZXhPZiggY2hlY2tDb250ZXh0LCBlbGVtICkgPiAtMTtcblx0XHR9LCBpbXBsaWNpdFJlbGF0aXZlLCB0cnVlICksXG5cdFx0bWF0Y2hlcnMgPSBbIGZ1bmN0aW9uKCBlbGVtLCBjb250ZXh0LCB4bWwgKSB7XG5cdFx0XHR2YXIgcmV0ID0gKCAhbGVhZGluZ1JlbGF0aXZlICYmICggeG1sIHx8IGNvbnRleHQgIT09IG91dGVybW9zdENvbnRleHQgKSApIHx8IChcblx0XHRcdFx0KGNoZWNrQ29udGV4dCA9IGNvbnRleHQpLm5vZGVUeXBlID9cblx0XHRcdFx0XHRtYXRjaENvbnRleHQoIGVsZW0sIGNvbnRleHQsIHhtbCApIDpcblx0XHRcdFx0XHRtYXRjaEFueUNvbnRleHQoIGVsZW0sIGNvbnRleHQsIHhtbCApICk7XG5cdFx0XHQvLyBBdm9pZCBoYW5naW5nIG9udG8gZWxlbWVudCAoaXNzdWUgIzI5OSlcblx0XHRcdGNoZWNrQ29udGV4dCA9IG51bGw7XG5cdFx0XHRyZXR1cm4gcmV0O1xuXHRcdH0gXTtcblxuXHRmb3IgKCA7IGkgPCBsZW47IGkrKyApIHtcblx0XHRpZiAoIChtYXRjaGVyID0gRXhwci5yZWxhdGl2ZVsgdG9rZW5zW2ldLnR5cGUgXSkgKSB7XG5cdFx0XHRtYXRjaGVycyA9IFsgYWRkQ29tYmluYXRvcihlbGVtZW50TWF0Y2hlciggbWF0Y2hlcnMgKSwgbWF0Y2hlcikgXTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0bWF0Y2hlciA9IEV4cHIuZmlsdGVyWyB0b2tlbnNbaV0udHlwZSBdLmFwcGx5KCBudWxsLCB0b2tlbnNbaV0ubWF0Y2hlcyApO1xuXG5cdFx0XHQvLyBSZXR1cm4gc3BlY2lhbCB1cG9uIHNlZWluZyBhIHBvc2l0aW9uYWwgbWF0Y2hlclxuXHRcdFx0aWYgKCBtYXRjaGVyWyBleHBhbmRvIF0gKSB7XG5cdFx0XHRcdC8vIEZpbmQgdGhlIG5leHQgcmVsYXRpdmUgb3BlcmF0b3IgKGlmIGFueSkgZm9yIHByb3BlciBoYW5kbGluZ1xuXHRcdFx0XHRqID0gKytpO1xuXHRcdFx0XHRmb3IgKCA7IGogPCBsZW47IGorKyApIHtcblx0XHRcdFx0XHRpZiAoIEV4cHIucmVsYXRpdmVbIHRva2Vuc1tqXS50eXBlIF0gKSB7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHNldE1hdGNoZXIoXG5cdFx0XHRcdFx0aSA+IDEgJiYgZWxlbWVudE1hdGNoZXIoIG1hdGNoZXJzICksXG5cdFx0XHRcdFx0aSA+IDEgJiYgdG9TZWxlY3Rvcihcblx0XHRcdFx0XHRcdC8vIElmIHRoZSBwcmVjZWRpbmcgdG9rZW4gd2FzIGEgZGVzY2VuZGFudCBjb21iaW5hdG9yLCBpbnNlcnQgYW4gaW1wbGljaXQgYW55LWVsZW1lbnQgYCpgXG5cdFx0XHRcdFx0XHR0b2tlbnMuc2xpY2UoIDAsIGkgLSAxICkuY29uY2F0KHsgdmFsdWU6IHRva2Vuc1sgaSAtIDIgXS50eXBlID09PSBcIiBcIiA/IFwiKlwiIDogXCJcIiB9KVxuXHRcdFx0XHRcdCkucmVwbGFjZSggcnRyaW0sIFwiJDFcIiApLFxuXHRcdFx0XHRcdG1hdGNoZXIsXG5cdFx0XHRcdFx0aSA8IGogJiYgbWF0Y2hlckZyb21Ub2tlbnMoIHRva2Vucy5zbGljZSggaSwgaiApICksXG5cdFx0XHRcdFx0aiA8IGxlbiAmJiBtYXRjaGVyRnJvbVRva2VucyggKHRva2VucyA9IHRva2Vucy5zbGljZSggaiApKSApLFxuXHRcdFx0XHRcdGogPCBsZW4gJiYgdG9TZWxlY3RvciggdG9rZW5zIClcblx0XHRcdFx0KTtcblx0XHRcdH1cblx0XHRcdG1hdGNoZXJzLnB1c2goIG1hdGNoZXIgKTtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gZWxlbWVudE1hdGNoZXIoIG1hdGNoZXJzICk7XG59XG5cbmZ1bmN0aW9uIG1hdGNoZXJGcm9tR3JvdXBNYXRjaGVycyggZWxlbWVudE1hdGNoZXJzLCBzZXRNYXRjaGVycyApIHtcblx0dmFyIGJ5U2V0ID0gc2V0TWF0Y2hlcnMubGVuZ3RoID4gMCxcblx0XHRieUVsZW1lbnQgPSBlbGVtZW50TWF0Y2hlcnMubGVuZ3RoID4gMCxcblx0XHRzdXBlck1hdGNoZXIgPSBmdW5jdGlvbiggc2VlZCwgY29udGV4dCwgeG1sLCByZXN1bHRzLCBvdXRlcm1vc3QgKSB7XG5cdFx0XHR2YXIgZWxlbSwgaiwgbWF0Y2hlcixcblx0XHRcdFx0bWF0Y2hlZENvdW50ID0gMCxcblx0XHRcdFx0aSA9IFwiMFwiLFxuXHRcdFx0XHR1bm1hdGNoZWQgPSBzZWVkICYmIFtdLFxuXHRcdFx0XHRzZXRNYXRjaGVkID0gW10sXG5cdFx0XHRcdGNvbnRleHRCYWNrdXAgPSBvdXRlcm1vc3RDb250ZXh0LFxuXHRcdFx0XHQvLyBXZSBtdXN0IGFsd2F5cyBoYXZlIGVpdGhlciBzZWVkIGVsZW1lbnRzIG9yIG91dGVybW9zdCBjb250ZXh0XG5cdFx0XHRcdGVsZW1zID0gc2VlZCB8fCBieUVsZW1lbnQgJiYgRXhwci5maW5kW1wiVEFHXCJdKCBcIipcIiwgb3V0ZXJtb3N0ICksXG5cdFx0XHRcdC8vIFVzZSBpbnRlZ2VyIGRpcnJ1bnMgaWZmIHRoaXMgaXMgdGhlIG91dGVybW9zdCBtYXRjaGVyXG5cdFx0XHRcdGRpcnJ1bnNVbmlxdWUgPSAoZGlycnVucyArPSBjb250ZXh0QmFja3VwID09IG51bGwgPyAxIDogTWF0aC5yYW5kb20oKSB8fCAwLjEpLFxuXHRcdFx0XHRsZW4gPSBlbGVtcy5sZW5ndGg7XG5cblx0XHRcdGlmICggb3V0ZXJtb3N0ICkge1xuXHRcdFx0XHRvdXRlcm1vc3RDb250ZXh0ID0gY29udGV4dCA9PT0gZG9jdW1lbnQgfHwgY29udGV4dCB8fCBvdXRlcm1vc3Q7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFkZCBlbGVtZW50cyBwYXNzaW5nIGVsZW1lbnRNYXRjaGVycyBkaXJlY3RseSB0byByZXN1bHRzXG5cdFx0XHQvLyBTdXBwb3J0OiBJRTw5LCBTYWZhcmlcblx0XHRcdC8vIFRvbGVyYXRlIE5vZGVMaXN0IHByb3BlcnRpZXMgKElFOiBcImxlbmd0aFwiOyBTYWZhcmk6IDxudW1iZXI+KSBtYXRjaGluZyBlbGVtZW50cyBieSBpZFxuXHRcdFx0Zm9yICggOyBpICE9PSBsZW4gJiYgKGVsZW0gPSBlbGVtc1tpXSkgIT0gbnVsbDsgaSsrICkge1xuXHRcdFx0XHRpZiAoIGJ5RWxlbWVudCAmJiBlbGVtICkge1xuXHRcdFx0XHRcdGogPSAwO1xuXHRcdFx0XHRcdGlmICggIWNvbnRleHQgJiYgZWxlbS5vd25lckRvY3VtZW50ICE9PSBkb2N1bWVudCApIHtcblx0XHRcdFx0XHRcdHNldERvY3VtZW50KCBlbGVtICk7XG5cdFx0XHRcdFx0XHR4bWwgPSAhZG9jdW1lbnRJc0hUTUw7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHdoaWxlICggKG1hdGNoZXIgPSBlbGVtZW50TWF0Y2hlcnNbaisrXSkgKSB7XG5cdFx0XHRcdFx0XHRpZiAoIG1hdGNoZXIoIGVsZW0sIGNvbnRleHQgfHwgZG9jdW1lbnQsIHhtbCkgKSB7XG5cdFx0XHRcdFx0XHRcdHJlc3VsdHMucHVzaCggZWxlbSApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCBvdXRlcm1vc3QgKSB7XG5cdFx0XHRcdFx0XHRkaXJydW5zID0gZGlycnVuc1VuaXF1ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBUcmFjayB1bm1hdGNoZWQgZWxlbWVudHMgZm9yIHNldCBmaWx0ZXJzXG5cdFx0XHRcdGlmICggYnlTZXQgKSB7XG5cdFx0XHRcdFx0Ly8gVGhleSB3aWxsIGhhdmUgZ29uZSB0aHJvdWdoIGFsbCBwb3NzaWJsZSBtYXRjaGVyc1xuXHRcdFx0XHRcdGlmICggKGVsZW0gPSAhbWF0Y2hlciAmJiBlbGVtKSApIHtcblx0XHRcdFx0XHRcdG1hdGNoZWRDb3VudC0tO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIExlbmd0aGVuIHRoZSBhcnJheSBmb3IgZXZlcnkgZWxlbWVudCwgbWF0Y2hlZCBvciBub3Rcblx0XHRcdFx0XHRpZiAoIHNlZWQgKSB7XG5cdFx0XHRcdFx0XHR1bm1hdGNoZWQucHVzaCggZWxlbSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBgaWAgaXMgbm93IHRoZSBjb3VudCBvZiBlbGVtZW50cyB2aXNpdGVkIGFib3ZlLCBhbmQgYWRkaW5nIGl0IHRvIGBtYXRjaGVkQ291bnRgXG5cdFx0XHQvLyBtYWtlcyB0aGUgbGF0dGVyIG5vbm5lZ2F0aXZlLlxuXHRcdFx0bWF0Y2hlZENvdW50ICs9IGk7XG5cblx0XHRcdC8vIEFwcGx5IHNldCBmaWx0ZXJzIHRvIHVubWF0Y2hlZCBlbGVtZW50c1xuXHRcdFx0Ly8gTk9URTogVGhpcyBjYW4gYmUgc2tpcHBlZCBpZiB0aGVyZSBhcmUgbm8gdW5tYXRjaGVkIGVsZW1lbnRzIChpLmUuLCBgbWF0Y2hlZENvdW50YFxuXHRcdFx0Ly8gZXF1YWxzIGBpYCksIHVubGVzcyB3ZSBkaWRuJ3QgdmlzaXQgX2FueV8gZWxlbWVudHMgaW4gdGhlIGFib3ZlIGxvb3AgYmVjYXVzZSB3ZSBoYXZlXG5cdFx0XHQvLyBubyBlbGVtZW50IG1hdGNoZXJzIGFuZCBubyBzZWVkLlxuXHRcdFx0Ly8gSW5jcmVtZW50aW5nIGFuIGluaXRpYWxseS1zdHJpbmcgXCIwXCIgYGlgIGFsbG93cyBgaWAgdG8gcmVtYWluIGEgc3RyaW5nIG9ubHkgaW4gdGhhdFxuXHRcdFx0Ly8gY2FzZSwgd2hpY2ggd2lsbCByZXN1bHQgaW4gYSBcIjAwXCIgYG1hdGNoZWRDb3VudGAgdGhhdCBkaWZmZXJzIGZyb20gYGlgIGJ1dCBpcyBhbHNvXG5cdFx0XHQvLyBudW1lcmljYWxseSB6ZXJvLlxuXHRcdFx0aWYgKCBieVNldCAmJiBpICE9PSBtYXRjaGVkQ291bnQgKSB7XG5cdFx0XHRcdGogPSAwO1xuXHRcdFx0XHR3aGlsZSAoIChtYXRjaGVyID0gc2V0TWF0Y2hlcnNbaisrXSkgKSB7XG5cdFx0XHRcdFx0bWF0Y2hlciggdW5tYXRjaGVkLCBzZXRNYXRjaGVkLCBjb250ZXh0LCB4bWwgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggc2VlZCApIHtcblx0XHRcdFx0XHQvLyBSZWludGVncmF0ZSBlbGVtZW50IG1hdGNoZXMgdG8gZWxpbWluYXRlIHRoZSBuZWVkIGZvciBzb3J0aW5nXG5cdFx0XHRcdFx0aWYgKCBtYXRjaGVkQ291bnQgPiAwICkge1xuXHRcdFx0XHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdFx0XHRcdGlmICggISh1bm1hdGNoZWRbaV0gfHwgc2V0TWF0Y2hlZFtpXSkgKSB7XG5cdFx0XHRcdFx0XHRcdFx0c2V0TWF0Y2hlZFtpXSA9IHBvcC5jYWxsKCByZXN1bHRzICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBEaXNjYXJkIGluZGV4IHBsYWNlaG9sZGVyIHZhbHVlcyB0byBnZXQgb25seSBhY3R1YWwgbWF0Y2hlc1xuXHRcdFx0XHRcdHNldE1hdGNoZWQgPSBjb25kZW5zZSggc2V0TWF0Y2hlZCApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQWRkIG1hdGNoZXMgdG8gcmVzdWx0c1xuXHRcdFx0XHRwdXNoLmFwcGx5KCByZXN1bHRzLCBzZXRNYXRjaGVkICk7XG5cblx0XHRcdFx0Ly8gU2VlZGxlc3Mgc2V0IG1hdGNoZXMgc3VjY2VlZGluZyBtdWx0aXBsZSBzdWNjZXNzZnVsIG1hdGNoZXJzIHN0aXB1bGF0ZSBzb3J0aW5nXG5cdFx0XHRcdGlmICggb3V0ZXJtb3N0ICYmICFzZWVkICYmIHNldE1hdGNoZWQubGVuZ3RoID4gMCAmJlxuXHRcdFx0XHRcdCggbWF0Y2hlZENvdW50ICsgc2V0TWF0Y2hlcnMubGVuZ3RoICkgPiAxICkge1xuXG5cdFx0XHRcdFx0U2l6emxlLnVuaXF1ZVNvcnQoIHJlc3VsdHMgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBPdmVycmlkZSBtYW5pcHVsYXRpb24gb2YgZ2xvYmFscyBieSBuZXN0ZWQgbWF0Y2hlcnNcblx0XHRcdGlmICggb3V0ZXJtb3N0ICkge1xuXHRcdFx0XHRkaXJydW5zID0gZGlycnVuc1VuaXF1ZTtcblx0XHRcdFx0b3V0ZXJtb3N0Q29udGV4dCA9IGNvbnRleHRCYWNrdXA7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB1bm1hdGNoZWQ7XG5cdFx0fTtcblxuXHRyZXR1cm4gYnlTZXQgP1xuXHRcdG1hcmtGdW5jdGlvbiggc3VwZXJNYXRjaGVyICkgOlxuXHRcdHN1cGVyTWF0Y2hlcjtcbn1cblxuY29tcGlsZSA9IFNpenpsZS5jb21waWxlID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBtYXRjaCAvKiBJbnRlcm5hbCBVc2UgT25seSAqLyApIHtcblx0dmFyIGksXG5cdFx0c2V0TWF0Y2hlcnMgPSBbXSxcblx0XHRlbGVtZW50TWF0Y2hlcnMgPSBbXSxcblx0XHRjYWNoZWQgPSBjb21waWxlckNhY2hlWyBzZWxlY3RvciArIFwiIFwiIF07XG5cblx0aWYgKCAhY2FjaGVkICkge1xuXHRcdC8vIEdlbmVyYXRlIGEgZnVuY3Rpb24gb2YgcmVjdXJzaXZlIGZ1bmN0aW9ucyB0aGF0IGNhbiBiZSB1c2VkIHRvIGNoZWNrIGVhY2ggZWxlbWVudFxuXHRcdGlmICggIW1hdGNoICkge1xuXHRcdFx0bWF0Y2ggPSB0b2tlbml6ZSggc2VsZWN0b3IgKTtcblx0XHR9XG5cdFx0aSA9IG1hdGNoLmxlbmd0aDtcblx0XHR3aGlsZSAoIGktLSApIHtcblx0XHRcdGNhY2hlZCA9IG1hdGNoZXJGcm9tVG9rZW5zKCBtYXRjaFtpXSApO1xuXHRcdFx0aWYgKCBjYWNoZWRbIGV4cGFuZG8gXSApIHtcblx0XHRcdFx0c2V0TWF0Y2hlcnMucHVzaCggY2FjaGVkICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRlbGVtZW50TWF0Y2hlcnMucHVzaCggY2FjaGVkICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gQ2FjaGUgdGhlIGNvbXBpbGVkIGZ1bmN0aW9uXG5cdFx0Y2FjaGVkID0gY29tcGlsZXJDYWNoZSggc2VsZWN0b3IsIG1hdGNoZXJGcm9tR3JvdXBNYXRjaGVycyggZWxlbWVudE1hdGNoZXJzLCBzZXRNYXRjaGVycyApICk7XG5cblx0XHQvLyBTYXZlIHNlbGVjdG9yIGFuZCB0b2tlbml6YXRpb25cblx0XHRjYWNoZWQuc2VsZWN0b3IgPSBzZWxlY3Rvcjtcblx0fVxuXHRyZXR1cm4gY2FjaGVkO1xufTtcblxuLyoqXG4gKiBBIGxvdy1sZXZlbCBzZWxlY3Rpb24gZnVuY3Rpb24gdGhhdCB3b3JrcyB3aXRoIFNpenpsZSdzIGNvbXBpbGVkXG4gKiAgc2VsZWN0b3IgZnVuY3Rpb25zXG4gKiBAcGFyYW0ge1N0cmluZ3xGdW5jdGlvbn0gc2VsZWN0b3IgQSBzZWxlY3RvciBvciBhIHByZS1jb21waWxlZFxuICogIHNlbGVjdG9yIGZ1bmN0aW9uIGJ1aWx0IHdpdGggU2l6emxlLmNvbXBpbGVcbiAqIEBwYXJhbSB7RWxlbWVudH0gY29udGV4dFxuICogQHBhcmFtIHtBcnJheX0gW3Jlc3VsdHNdXG4gKiBAcGFyYW0ge0FycmF5fSBbc2VlZF0gQSBzZXQgb2YgZWxlbWVudHMgdG8gbWF0Y2ggYWdhaW5zdFxuICovXG5zZWxlY3QgPSBTaXp6bGUuc2VsZWN0ID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBjb250ZXh0LCByZXN1bHRzLCBzZWVkICkge1xuXHR2YXIgaSwgdG9rZW5zLCB0b2tlbiwgdHlwZSwgZmluZCxcblx0XHRjb21waWxlZCA9IHR5cGVvZiBzZWxlY3RvciA9PT0gXCJmdW5jdGlvblwiICYmIHNlbGVjdG9yLFxuXHRcdG1hdGNoID0gIXNlZWQgJiYgdG9rZW5pemUoIChzZWxlY3RvciA9IGNvbXBpbGVkLnNlbGVjdG9yIHx8IHNlbGVjdG9yKSApO1xuXG5cdHJlc3VsdHMgPSByZXN1bHRzIHx8IFtdO1xuXG5cdC8vIFRyeSB0byBtaW5pbWl6ZSBvcGVyYXRpb25zIGlmIHRoZXJlIGlzIG9ubHkgb25lIHNlbGVjdG9yIGluIHRoZSBsaXN0IGFuZCBubyBzZWVkXG5cdC8vICh0aGUgbGF0dGVyIG9mIHdoaWNoIGd1YXJhbnRlZXMgdXMgY29udGV4dClcblx0aWYgKCBtYXRjaC5sZW5ndGggPT09IDEgKSB7XG5cblx0XHQvLyBSZWR1Y2UgY29udGV4dCBpZiB0aGUgbGVhZGluZyBjb21wb3VuZCBzZWxlY3RvciBpcyBhbiBJRFxuXHRcdHRva2VucyA9IG1hdGNoWzBdID0gbWF0Y2hbMF0uc2xpY2UoIDAgKTtcblx0XHRpZiAoIHRva2Vucy5sZW5ndGggPiAyICYmICh0b2tlbiA9IHRva2Vuc1swXSkudHlwZSA9PT0gXCJJRFwiICYmXG5cdFx0XHRcdGNvbnRleHQubm9kZVR5cGUgPT09IDkgJiYgZG9jdW1lbnRJc0hUTUwgJiYgRXhwci5yZWxhdGl2ZVsgdG9rZW5zWzFdLnR5cGUgXSApIHtcblxuXHRcdFx0Y29udGV4dCA9ICggRXhwci5maW5kW1wiSURcIl0oIHRva2VuLm1hdGNoZXNbMF0ucmVwbGFjZShydW5lc2NhcGUsIGZ1bmVzY2FwZSksIGNvbnRleHQgKSB8fCBbXSApWzBdO1xuXHRcdFx0aWYgKCAhY29udGV4dCApIHtcblx0XHRcdFx0cmV0dXJuIHJlc3VsdHM7XG5cblx0XHRcdC8vIFByZWNvbXBpbGVkIG1hdGNoZXJzIHdpbGwgc3RpbGwgdmVyaWZ5IGFuY2VzdHJ5LCBzbyBzdGVwIHVwIGEgbGV2ZWxcblx0XHRcdH0gZWxzZSBpZiAoIGNvbXBpbGVkICkge1xuXHRcdFx0XHRjb250ZXh0ID0gY29udGV4dC5wYXJlbnROb2RlO1xuXHRcdFx0fVxuXG5cdFx0XHRzZWxlY3RvciA9IHNlbGVjdG9yLnNsaWNlKCB0b2tlbnMuc2hpZnQoKS52YWx1ZS5sZW5ndGggKTtcblx0XHR9XG5cblx0XHQvLyBGZXRjaCBhIHNlZWQgc2V0IGZvciByaWdodC10by1sZWZ0IG1hdGNoaW5nXG5cdFx0aSA9IG1hdGNoRXhwcltcIm5lZWRzQ29udGV4dFwiXS50ZXN0KCBzZWxlY3RvciApID8gMCA6IHRva2Vucy5sZW5ndGg7XG5cdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHR0b2tlbiA9IHRva2Vuc1tpXTtcblxuXHRcdFx0Ly8gQWJvcnQgaWYgd2UgaGl0IGEgY29tYmluYXRvclxuXHRcdFx0aWYgKCBFeHByLnJlbGF0aXZlWyAodHlwZSA9IHRva2VuLnR5cGUpIF0gKSB7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCAoZmluZCA9IEV4cHIuZmluZFsgdHlwZSBdKSApIHtcblx0XHRcdFx0Ly8gU2VhcmNoLCBleHBhbmRpbmcgY29udGV4dCBmb3IgbGVhZGluZyBzaWJsaW5nIGNvbWJpbmF0b3JzXG5cdFx0XHRcdGlmICggKHNlZWQgPSBmaW5kKFxuXHRcdFx0XHRcdHRva2VuLm1hdGNoZXNbMF0ucmVwbGFjZSggcnVuZXNjYXBlLCBmdW5lc2NhcGUgKSxcblx0XHRcdFx0XHRyc2libGluZy50ZXN0KCB0b2tlbnNbMF0udHlwZSApICYmIHRlc3RDb250ZXh0KCBjb250ZXh0LnBhcmVudE5vZGUgKSB8fCBjb250ZXh0XG5cdFx0XHRcdCkpICkge1xuXG5cdFx0XHRcdFx0Ly8gSWYgc2VlZCBpcyBlbXB0eSBvciBubyB0b2tlbnMgcmVtYWluLCB3ZSBjYW4gcmV0dXJuIGVhcmx5XG5cdFx0XHRcdFx0dG9rZW5zLnNwbGljZSggaSwgMSApO1xuXHRcdFx0XHRcdHNlbGVjdG9yID0gc2VlZC5sZW5ndGggJiYgdG9TZWxlY3RvciggdG9rZW5zICk7XG5cdFx0XHRcdFx0aWYgKCAhc2VsZWN0b3IgKSB7XG5cdFx0XHRcdFx0XHRwdXNoLmFwcGx5KCByZXN1bHRzLCBzZWVkICk7XG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzdWx0cztcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8vIENvbXBpbGUgYW5kIGV4ZWN1dGUgYSBmaWx0ZXJpbmcgZnVuY3Rpb24gaWYgb25lIGlzIG5vdCBwcm92aWRlZFxuXHQvLyBQcm92aWRlIGBtYXRjaGAgdG8gYXZvaWQgcmV0b2tlbml6YXRpb24gaWYgd2UgbW9kaWZpZWQgdGhlIHNlbGVjdG9yIGFib3ZlXG5cdCggY29tcGlsZWQgfHwgY29tcGlsZSggc2VsZWN0b3IsIG1hdGNoICkgKShcblx0XHRzZWVkLFxuXHRcdGNvbnRleHQsXG5cdFx0IWRvY3VtZW50SXNIVE1MLFxuXHRcdHJlc3VsdHMsXG5cdFx0IWNvbnRleHQgfHwgcnNpYmxpbmcudGVzdCggc2VsZWN0b3IgKSAmJiB0ZXN0Q29udGV4dCggY29udGV4dC5wYXJlbnROb2RlICkgfHwgY29udGV4dFxuXHQpO1xuXHRyZXR1cm4gcmVzdWx0cztcbn07XG5cbi8vIE9uZS10aW1lIGFzc2lnbm1lbnRzXG5cbi8vIFNvcnQgc3RhYmlsaXR5XG5zdXBwb3J0LnNvcnRTdGFibGUgPSBleHBhbmRvLnNwbGl0KFwiXCIpLnNvcnQoIHNvcnRPcmRlciApLmpvaW4oXCJcIikgPT09IGV4cGFuZG87XG5cbi8vIFN1cHBvcnQ6IENocm9tZSAxNC0zNStcbi8vIEFsd2F5cyBhc3N1bWUgZHVwbGljYXRlcyBpZiB0aGV5IGFyZW4ndCBwYXNzZWQgdG8gdGhlIGNvbXBhcmlzb24gZnVuY3Rpb25cbnN1cHBvcnQuZGV0ZWN0RHVwbGljYXRlcyA9ICEhaGFzRHVwbGljYXRlO1xuXG4vLyBJbml0aWFsaXplIGFnYWluc3QgdGhlIGRlZmF1bHQgZG9jdW1lbnRcbnNldERvY3VtZW50KCk7XG5cbi8vIFN1cHBvcnQ6IFdlYmtpdDw1MzcuMzIgLSBTYWZhcmkgNi4wLjMvQ2hyb21lIDI1IChmaXhlZCBpbiBDaHJvbWUgMjcpXG4vLyBEZXRhY2hlZCBub2RlcyBjb25mb3VuZGluZ2x5IGZvbGxvdyAqZWFjaCBvdGhlcipcbnN1cHBvcnQuc29ydERldGFjaGVkID0gYXNzZXJ0KGZ1bmN0aW9uKCBlbCApIHtcblx0Ly8gU2hvdWxkIHJldHVybiAxLCBidXQgcmV0dXJucyA0IChmb2xsb3dpbmcpXG5cdHJldHVybiBlbC5jb21wYXJlRG9jdW1lbnRQb3NpdGlvbiggZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImZpZWxkc2V0XCIpICkgJiAxO1xufSk7XG5cbi8vIFN1cHBvcnQ6IElFPDhcbi8vIFByZXZlbnQgYXR0cmlidXRlL3Byb3BlcnR5IFwiaW50ZXJwb2xhdGlvblwiXG4vLyBodHRwczovL21zZG4ubWljcm9zb2Z0LmNvbS9lbi11cy9saWJyYXJ5L21zNTM2NDI5JTI4VlMuODUlMjkuYXNweFxuaWYgKCAhYXNzZXJ0KGZ1bmN0aW9uKCBlbCApIHtcblx0ZWwuaW5uZXJIVE1MID0gXCI8YSBocmVmPScjJz48L2E+XCI7XG5cdHJldHVybiBlbC5maXJzdENoaWxkLmdldEF0dHJpYnV0ZShcImhyZWZcIikgPT09IFwiI1wiIDtcbn0pICkge1xuXHRhZGRIYW5kbGUoIFwidHlwZXxocmVmfGhlaWdodHx3aWR0aFwiLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgaXNYTUwgKSB7XG5cdFx0aWYgKCAhaXNYTUwgKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGUoIG5hbWUsIG5hbWUudG9Mb3dlckNhc2UoKSA9PT0gXCJ0eXBlXCIgPyAxIDogMiApO1xuXHRcdH1cblx0fSk7XG59XG5cbi8vIFN1cHBvcnQ6IElFPDlcbi8vIFVzZSBkZWZhdWx0VmFsdWUgaW4gcGxhY2Ugb2YgZ2V0QXR0cmlidXRlKFwidmFsdWVcIilcbmlmICggIXN1cHBvcnQuYXR0cmlidXRlcyB8fCAhYXNzZXJ0KGZ1bmN0aW9uKCBlbCApIHtcblx0ZWwuaW5uZXJIVE1MID0gXCI8aW5wdXQvPlwiO1xuXHRlbC5maXJzdENoaWxkLnNldEF0dHJpYnV0ZSggXCJ2YWx1ZVwiLCBcIlwiICk7XG5cdHJldHVybiBlbC5maXJzdENoaWxkLmdldEF0dHJpYnV0ZSggXCJ2YWx1ZVwiICkgPT09IFwiXCI7XG59KSApIHtcblx0YWRkSGFuZGxlKCBcInZhbHVlXCIsIGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCBpc1hNTCApIHtcblx0XHRpZiAoICFpc1hNTCAmJiBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgPT09IFwiaW5wdXRcIiApIHtcblx0XHRcdHJldHVybiBlbGVtLmRlZmF1bHRWYWx1ZTtcblx0XHR9XG5cdH0pO1xufVxuXG4vLyBTdXBwb3J0OiBJRTw5XG4vLyBVc2UgZ2V0QXR0cmlidXRlTm9kZSB0byBmZXRjaCBib29sZWFucyB3aGVuIGdldEF0dHJpYnV0ZSBsaWVzXG5pZiAoICFhc3NlcnQoZnVuY3Rpb24oIGVsICkge1xuXHRyZXR1cm4gZWwuZ2V0QXR0cmlidXRlKFwiZGlzYWJsZWRcIikgPT0gbnVsbDtcbn0pICkge1xuXHRhZGRIYW5kbGUoIGJvb2xlYW5zLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgaXNYTUwgKSB7XG5cdFx0dmFyIHZhbDtcblx0XHRpZiAoICFpc1hNTCApIHtcblx0XHRcdHJldHVybiBlbGVtWyBuYW1lIF0gPT09IHRydWUgPyBuYW1lLnRvTG93ZXJDYXNlKCkgOlxuXHRcdFx0XHRcdCh2YWwgPSBlbGVtLmdldEF0dHJpYnV0ZU5vZGUoIG5hbWUgKSkgJiYgdmFsLnNwZWNpZmllZCA/XG5cdFx0XHRcdFx0dmFsLnZhbHVlIDpcblx0XHRcdFx0bnVsbDtcblx0XHR9XG5cdH0pO1xufVxuXG5yZXR1cm4gU2l6emxlO1xuXG59KSggd2luZG93ICk7XG5cblxuXG5qUXVlcnkuZmluZCA9IFNpenpsZTtcbmpRdWVyeS5leHByID0gU2l6emxlLnNlbGVjdG9ycztcblxuLy8gRGVwcmVjYXRlZFxualF1ZXJ5LmV4cHJbIFwiOlwiIF0gPSBqUXVlcnkuZXhwci5wc2V1ZG9zO1xualF1ZXJ5LnVuaXF1ZVNvcnQgPSBqUXVlcnkudW5pcXVlID0gU2l6emxlLnVuaXF1ZVNvcnQ7XG5qUXVlcnkudGV4dCA9IFNpenpsZS5nZXRUZXh0O1xualF1ZXJ5LmlzWE1MRG9jID0gU2l6emxlLmlzWE1MO1xualF1ZXJ5LmNvbnRhaW5zID0gU2l6emxlLmNvbnRhaW5zO1xualF1ZXJ5LmVzY2FwZVNlbGVjdG9yID0gU2l6emxlLmVzY2FwZTtcblxuXG5cblxudmFyIGRpciA9IGZ1bmN0aW9uKCBlbGVtLCBkaXIsIHVudGlsICkge1xuXHR2YXIgbWF0Y2hlZCA9IFtdLFxuXHRcdHRydW5jYXRlID0gdW50aWwgIT09IHVuZGVmaW5lZDtcblxuXHR3aGlsZSAoICggZWxlbSA9IGVsZW1bIGRpciBdICkgJiYgZWxlbS5ub2RlVHlwZSAhPT0gOSApIHtcblx0XHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgKSB7XG5cdFx0XHRpZiAoIHRydW5jYXRlICYmIGpRdWVyeSggZWxlbSApLmlzKCB1bnRpbCApICkge1xuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHRcdG1hdGNoZWQucHVzaCggZWxlbSApO1xuXHRcdH1cblx0fVxuXHRyZXR1cm4gbWF0Y2hlZDtcbn07XG5cblxudmFyIHNpYmxpbmdzID0gZnVuY3Rpb24oIG4sIGVsZW0gKSB7XG5cdHZhciBtYXRjaGVkID0gW107XG5cblx0Zm9yICggOyBuOyBuID0gbi5uZXh0U2libGluZyApIHtcblx0XHRpZiAoIG4ubm9kZVR5cGUgPT09IDEgJiYgbiAhPT0gZWxlbSApIHtcblx0XHRcdG1hdGNoZWQucHVzaCggbiApO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiBtYXRjaGVkO1xufTtcblxuXG52YXIgcm5lZWRzQ29udGV4dCA9IGpRdWVyeS5leHByLm1hdGNoLm5lZWRzQ29udGV4dDtcblxuXG5cbmZ1bmN0aW9uIG5vZGVOYW1lKCBlbGVtLCBuYW1lICkge1xuXG4gIHJldHVybiBlbGVtLm5vZGVOYW1lICYmIGVsZW0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSA9PT0gbmFtZS50b0xvd2VyQ2FzZSgpO1xuXG59O1xudmFyIHJzaW5nbGVUYWcgPSAoIC9ePChbYS16XVteXFwvXFwwPjpcXHgyMFxcdFxcclxcblxcZl0qKVtcXHgyMFxcdFxcclxcblxcZl0qXFwvPz4oPzo8XFwvXFwxPnwpJC9pICk7XG5cblxuXG4vLyBJbXBsZW1lbnQgdGhlIGlkZW50aWNhbCBmdW5jdGlvbmFsaXR5IGZvciBmaWx0ZXIgYW5kIG5vdFxuZnVuY3Rpb24gd2lubm93KCBlbGVtZW50cywgcXVhbGlmaWVyLCBub3QgKSB7XG5cdGlmICggaXNGdW5jdGlvbiggcXVhbGlmaWVyICkgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5ncmVwKCBlbGVtZW50cywgZnVuY3Rpb24oIGVsZW0sIGkgKSB7XG5cdFx0XHRyZXR1cm4gISFxdWFsaWZpZXIuY2FsbCggZWxlbSwgaSwgZWxlbSApICE9PSBub3Q7XG5cdFx0fSApO1xuXHR9XG5cblx0Ly8gU2luZ2xlIGVsZW1lbnRcblx0aWYgKCBxdWFsaWZpZXIubm9kZVR5cGUgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5ncmVwKCBlbGVtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gKCBlbGVtID09PSBxdWFsaWZpZXIgKSAhPT0gbm90O1xuXHRcdH0gKTtcblx0fVxuXG5cdC8vIEFycmF5bGlrZSBvZiBlbGVtZW50cyAoalF1ZXJ5LCBhcmd1bWVudHMsIEFycmF5KVxuXHRpZiAoIHR5cGVvZiBxdWFsaWZpZXIgIT09IFwic3RyaW5nXCIgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5ncmVwKCBlbGVtZW50cywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gKCBpbmRleE9mLmNhbGwoIHF1YWxpZmllciwgZWxlbSApID4gLTEgKSAhPT0gbm90O1xuXHRcdH0gKTtcblx0fVxuXG5cdC8vIEZpbHRlcmVkIGRpcmVjdGx5IGZvciBib3RoIHNpbXBsZSBhbmQgY29tcGxleCBzZWxlY3RvcnNcblx0cmV0dXJuIGpRdWVyeS5maWx0ZXIoIHF1YWxpZmllciwgZWxlbWVudHMsIG5vdCApO1xufVxuXG5qUXVlcnkuZmlsdGVyID0gZnVuY3Rpb24oIGV4cHIsIGVsZW1zLCBub3QgKSB7XG5cdHZhciBlbGVtID0gZWxlbXNbIDAgXTtcblxuXHRpZiAoIG5vdCApIHtcblx0XHRleHByID0gXCI6bm90KFwiICsgZXhwciArIFwiKVwiO1xuXHR9XG5cblx0aWYgKCBlbGVtcy5sZW5ndGggPT09IDEgJiYgZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmZpbmQubWF0Y2hlc1NlbGVjdG9yKCBlbGVtLCBleHByICkgPyBbIGVsZW0gXSA6IFtdO1xuXHR9XG5cblx0cmV0dXJuIGpRdWVyeS5maW5kLm1hdGNoZXMoIGV4cHIsIGpRdWVyeS5ncmVwKCBlbGVtcywgZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIGVsZW0ubm9kZVR5cGUgPT09IDE7XG5cdH0gKSApO1xufTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHRmaW5kOiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0dmFyIGksIHJldCxcblx0XHRcdGxlbiA9IHRoaXMubGVuZ3RoLFxuXHRcdFx0c2VsZiA9IHRoaXM7XG5cblx0XHRpZiAoIHR5cGVvZiBzZWxlY3RvciAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggalF1ZXJ5KCBzZWxlY3RvciApLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRcdFx0aWYgKCBqUXVlcnkuY29udGFpbnMoIHNlbGZbIGkgXSwgdGhpcyApICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9ICkgKTtcblx0XHR9XG5cblx0XHRyZXQgPSB0aGlzLnB1c2hTdGFjayggW10gKTtcblxuXHRcdGZvciAoIGkgPSAwOyBpIDwgbGVuOyBpKysgKSB7XG5cdFx0XHRqUXVlcnkuZmluZCggc2VsZWN0b3IsIHNlbGZbIGkgXSwgcmV0ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGxlbiA+IDEgPyBqUXVlcnkudW5pcXVlU29ydCggcmV0ICkgOiByZXQ7XG5cdH0sXG5cdGZpbHRlcjogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggd2lubm93KCB0aGlzLCBzZWxlY3RvciB8fCBbXSwgZmFsc2UgKSApO1xuXHR9LFxuXHRub3Q6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIHdpbm5vdyggdGhpcywgc2VsZWN0b3IgfHwgW10sIHRydWUgKSApO1xuXHR9LFxuXHRpczogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiAhIXdpbm5vdyhcblx0XHRcdHRoaXMsXG5cblx0XHRcdC8vIElmIHRoaXMgaXMgYSBwb3NpdGlvbmFsL3JlbGF0aXZlIHNlbGVjdG9yLCBjaGVjayBtZW1iZXJzaGlwIGluIHRoZSByZXR1cm5lZCBzZXRcblx0XHRcdC8vIHNvICQoXCJwOmZpcnN0XCIpLmlzKFwicDpsYXN0XCIpIHdvbid0IHJldHVybiB0cnVlIGZvciBhIGRvYyB3aXRoIHR3byBcInBcIi5cblx0XHRcdHR5cGVvZiBzZWxlY3RvciA9PT0gXCJzdHJpbmdcIiAmJiBybmVlZHNDb250ZXh0LnRlc3QoIHNlbGVjdG9yICkgP1xuXHRcdFx0XHRqUXVlcnkoIHNlbGVjdG9yICkgOlxuXHRcdFx0XHRzZWxlY3RvciB8fCBbXSxcblx0XHRcdGZhbHNlXG5cdFx0KS5sZW5ndGg7XG5cdH1cbn0gKTtcblxuXG4vLyBJbml0aWFsaXplIGEgalF1ZXJ5IG9iamVjdFxuXG5cbi8vIEEgY2VudHJhbCByZWZlcmVuY2UgdG8gdGhlIHJvb3QgalF1ZXJ5KGRvY3VtZW50KVxudmFyIHJvb3RqUXVlcnksXG5cblx0Ly8gQSBzaW1wbGUgd2F5IHRvIGNoZWNrIGZvciBIVE1MIHN0cmluZ3Ncblx0Ly8gUHJpb3JpdGl6ZSAjaWQgb3ZlciA8dGFnPiB0byBhdm9pZCBYU1MgdmlhIGxvY2F0aW9uLmhhc2ggKCM5NTIxKVxuXHQvLyBTdHJpY3QgSFRNTCByZWNvZ25pdGlvbiAoIzExMjkwOiBtdXN0IHN0YXJ0IHdpdGggPClcblx0Ly8gU2hvcnRjdXQgc2ltcGxlICNpZCBjYXNlIGZvciBzcGVlZFxuXHRycXVpY2tFeHByID0gL14oPzpcXHMqKDxbXFx3XFxXXSs+KVtePl0qfCMoW1xcdy1dKykpJC8sXG5cblx0aW5pdCA9IGpRdWVyeS5mbi5pbml0ID0gZnVuY3Rpb24oIHNlbGVjdG9yLCBjb250ZXh0LCByb290ICkge1xuXHRcdHZhciBtYXRjaCwgZWxlbTtcblxuXHRcdC8vIEhBTkRMRTogJChcIlwiKSwgJChudWxsKSwgJCh1bmRlZmluZWQpLCAkKGZhbHNlKVxuXHRcdGlmICggIXNlbGVjdG9yICkge1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXG5cdFx0Ly8gTWV0aG9kIGluaXQoKSBhY2NlcHRzIGFuIGFsdGVybmF0ZSByb290alF1ZXJ5XG5cdFx0Ly8gc28gbWlncmF0ZSBjYW4gc3VwcG9ydCBqUXVlcnkuc3ViIChnaC0yMTAxKVxuXHRcdHJvb3QgPSByb290IHx8IHJvb3RqUXVlcnk7XG5cblx0XHQvLyBIYW5kbGUgSFRNTCBzdHJpbmdzXG5cdFx0aWYgKCB0eXBlb2Ygc2VsZWN0b3IgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRpZiAoIHNlbGVjdG9yWyAwIF0gPT09IFwiPFwiICYmXG5cdFx0XHRcdHNlbGVjdG9yWyBzZWxlY3Rvci5sZW5ndGggLSAxIF0gPT09IFwiPlwiICYmXG5cdFx0XHRcdHNlbGVjdG9yLmxlbmd0aCA+PSAzICkge1xuXG5cdFx0XHRcdC8vIEFzc3VtZSB0aGF0IHN0cmluZ3MgdGhhdCBzdGFydCBhbmQgZW5kIHdpdGggPD4gYXJlIEhUTUwgYW5kIHNraXAgdGhlIHJlZ2V4IGNoZWNrXG5cdFx0XHRcdG1hdGNoID0gWyBudWxsLCBzZWxlY3RvciwgbnVsbCBdO1xuXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRtYXRjaCA9IHJxdWlja0V4cHIuZXhlYyggc2VsZWN0b3IgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTWF0Y2ggaHRtbCBvciBtYWtlIHN1cmUgbm8gY29udGV4dCBpcyBzcGVjaWZpZWQgZm9yICNpZFxuXHRcdFx0aWYgKCBtYXRjaCAmJiAoIG1hdGNoWyAxIF0gfHwgIWNvbnRleHQgKSApIHtcblxuXHRcdFx0XHQvLyBIQU5ETEU6ICQoaHRtbCkgLT4gJChhcnJheSlcblx0XHRcdFx0aWYgKCBtYXRjaFsgMSBdICkge1xuXHRcdFx0XHRcdGNvbnRleHQgPSBjb250ZXh0IGluc3RhbmNlb2YgalF1ZXJ5ID8gY29udGV4dFsgMCBdIDogY29udGV4dDtcblxuXHRcdFx0XHRcdC8vIE9wdGlvbiB0byBydW4gc2NyaXB0cyBpcyB0cnVlIGZvciBiYWNrLWNvbXBhdFxuXHRcdFx0XHRcdC8vIEludGVudGlvbmFsbHkgbGV0IHRoZSBlcnJvciBiZSB0aHJvd24gaWYgcGFyc2VIVE1MIGlzIG5vdCBwcmVzZW50XG5cdFx0XHRcdFx0alF1ZXJ5Lm1lcmdlKCB0aGlzLCBqUXVlcnkucGFyc2VIVE1MKFxuXHRcdFx0XHRcdFx0bWF0Y2hbIDEgXSxcblx0XHRcdFx0XHRcdGNvbnRleHQgJiYgY29udGV4dC5ub2RlVHlwZSA/IGNvbnRleHQub3duZXJEb2N1bWVudCB8fCBjb250ZXh0IDogZG9jdW1lbnQsXG5cdFx0XHRcdFx0XHR0cnVlXG5cdFx0XHRcdFx0KSApO1xuXG5cdFx0XHRcdFx0Ly8gSEFORExFOiAkKGh0bWwsIHByb3BzKVxuXHRcdFx0XHRcdGlmICggcnNpbmdsZVRhZy50ZXN0KCBtYXRjaFsgMSBdICkgJiYgalF1ZXJ5LmlzUGxhaW5PYmplY3QoIGNvbnRleHQgKSApIHtcblx0XHRcdFx0XHRcdGZvciAoIG1hdGNoIGluIGNvbnRleHQgKSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gUHJvcGVydGllcyBvZiBjb250ZXh0IGFyZSBjYWxsZWQgYXMgbWV0aG9kcyBpZiBwb3NzaWJsZVxuXHRcdFx0XHRcdFx0XHRpZiAoIGlzRnVuY3Rpb24oIHRoaXNbIG1hdGNoIF0gKSApIHtcblx0XHRcdFx0XHRcdFx0XHR0aGlzWyBtYXRjaCBdKCBjb250ZXh0WyBtYXRjaCBdICk7XG5cblx0XHRcdFx0XHRcdFx0Ly8gLi4uYW5kIG90aGVyd2lzZSBzZXQgYXMgYXR0cmlidXRlc1xuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuYXR0ciggbWF0Y2gsIGNvbnRleHRbIG1hdGNoIF0gKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0XHRcdC8vIEhBTkRMRTogJCgjaWQpXG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0ZWxlbSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCBtYXRjaFsgMiBdICk7XG5cblx0XHRcdFx0XHRpZiAoIGVsZW0gKSB7XG5cblx0XHRcdFx0XHRcdC8vIEluamVjdCB0aGUgZWxlbWVudCBkaXJlY3RseSBpbnRvIHRoZSBqUXVlcnkgb2JqZWN0XG5cdFx0XHRcdFx0XHR0aGlzWyAwIF0gPSBlbGVtO1xuXHRcdFx0XHRcdFx0dGhpcy5sZW5ndGggPSAxO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdFx0fVxuXG5cdFx0XHQvLyBIQU5ETEU6ICQoZXhwciwgJCguLi4pKVxuXHRcdFx0fSBlbHNlIGlmICggIWNvbnRleHQgfHwgY29udGV4dC5qcXVlcnkgKSB7XG5cdFx0XHRcdHJldHVybiAoIGNvbnRleHQgfHwgcm9vdCApLmZpbmQoIHNlbGVjdG9yICk7XG5cblx0XHRcdC8vIEhBTkRMRTogJChleHByLCBjb250ZXh0KVxuXHRcdFx0Ly8gKHdoaWNoIGlzIGp1c3QgZXF1aXZhbGVudCB0bzogJChjb250ZXh0KS5maW5kKGV4cHIpXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5jb25zdHJ1Y3RvciggY29udGV4dCApLmZpbmQoIHNlbGVjdG9yICk7XG5cdFx0XHR9XG5cblx0XHQvLyBIQU5ETEU6ICQoRE9NRWxlbWVudClcblx0XHR9IGVsc2UgaWYgKCBzZWxlY3Rvci5ub2RlVHlwZSApIHtcblx0XHRcdHRoaXNbIDAgXSA9IHNlbGVjdG9yO1xuXHRcdFx0dGhpcy5sZW5ndGggPSAxO1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHQvLyBIQU5ETEU6ICQoZnVuY3Rpb24pXG5cdFx0Ly8gU2hvcnRjdXQgZm9yIGRvY3VtZW50IHJlYWR5XG5cdFx0fSBlbHNlIGlmICggaXNGdW5jdGlvbiggc2VsZWN0b3IgKSApIHtcblx0XHRcdHJldHVybiByb290LnJlYWR5ICE9PSB1bmRlZmluZWQgP1xuXHRcdFx0XHRyb290LnJlYWR5KCBzZWxlY3RvciApIDpcblxuXHRcdFx0XHQvLyBFeGVjdXRlIGltbWVkaWF0ZWx5IGlmIHJlYWR5IGlzIG5vdCBwcmVzZW50XG5cdFx0XHRcdHNlbGVjdG9yKCBqUXVlcnkgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4galF1ZXJ5Lm1ha2VBcnJheSggc2VsZWN0b3IsIHRoaXMgKTtcblx0fTtcblxuLy8gR2l2ZSB0aGUgaW5pdCBmdW5jdGlvbiB0aGUgalF1ZXJ5IHByb3RvdHlwZSBmb3IgbGF0ZXIgaW5zdGFudGlhdGlvblxuaW5pdC5wcm90b3R5cGUgPSBqUXVlcnkuZm47XG5cbi8vIEluaXRpYWxpemUgY2VudHJhbCByZWZlcmVuY2VcbnJvb3RqUXVlcnkgPSBqUXVlcnkoIGRvY3VtZW50ICk7XG5cblxudmFyIHJwYXJlbnRzcHJldiA9IC9eKD86cGFyZW50c3xwcmV2KD86VW50aWx8QWxsKSkvLFxuXG5cdC8vIE1ldGhvZHMgZ3VhcmFudGVlZCB0byBwcm9kdWNlIGEgdW5pcXVlIHNldCB3aGVuIHN0YXJ0aW5nIGZyb20gYSB1bmlxdWUgc2V0XG5cdGd1YXJhbnRlZWRVbmlxdWUgPSB7XG5cdFx0Y2hpbGRyZW46IHRydWUsXG5cdFx0Y29udGVudHM6IHRydWUsXG5cdFx0bmV4dDogdHJ1ZSxcblx0XHRwcmV2OiB0cnVlXG5cdH07XG5cbmpRdWVyeS5mbi5leHRlbmQoIHtcblx0aGFzOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHZhciB0YXJnZXRzID0galF1ZXJ5KCB0YXJnZXQsIHRoaXMgKSxcblx0XHRcdGwgPSB0YXJnZXRzLmxlbmd0aDtcblxuXHRcdHJldHVybiB0aGlzLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgaSA9IDA7XG5cdFx0XHRmb3IgKCA7IGkgPCBsOyBpKysgKSB7XG5cdFx0XHRcdGlmICggalF1ZXJ5LmNvbnRhaW5zKCB0aGlzLCB0YXJnZXRzWyBpIF0gKSApIHtcblx0XHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRjbG9zZXN0OiBmdW5jdGlvbiggc2VsZWN0b3JzLCBjb250ZXh0ICkge1xuXHRcdHZhciBjdXIsXG5cdFx0XHRpID0gMCxcblx0XHRcdGwgPSB0aGlzLmxlbmd0aCxcblx0XHRcdG1hdGNoZWQgPSBbXSxcblx0XHRcdHRhcmdldHMgPSB0eXBlb2Ygc2VsZWN0b3JzICE9PSBcInN0cmluZ1wiICYmIGpRdWVyeSggc2VsZWN0b3JzICk7XG5cblx0XHQvLyBQb3NpdGlvbmFsIHNlbGVjdG9ycyBuZXZlciBtYXRjaCwgc2luY2UgdGhlcmUncyBubyBfc2VsZWN0aW9uXyBjb250ZXh0XG5cdFx0aWYgKCAhcm5lZWRzQ29udGV4dC50ZXN0KCBzZWxlY3RvcnMgKSApIHtcblx0XHRcdGZvciAoIDsgaSA8IGw7IGkrKyApIHtcblx0XHRcdFx0Zm9yICggY3VyID0gdGhpc1sgaSBdOyBjdXIgJiYgY3VyICE9PSBjb250ZXh0OyBjdXIgPSBjdXIucGFyZW50Tm9kZSApIHtcblxuXHRcdFx0XHRcdC8vIEFsd2F5cyBza2lwIGRvY3VtZW50IGZyYWdtZW50c1xuXHRcdFx0XHRcdGlmICggY3VyLm5vZGVUeXBlIDwgMTEgJiYgKCB0YXJnZXRzID9cblx0XHRcdFx0XHRcdHRhcmdldHMuaW5kZXgoIGN1ciApID4gLTEgOlxuXG5cdFx0XHRcdFx0XHQvLyBEb24ndCBwYXNzIG5vbi1lbGVtZW50cyB0byBTaXp6bGVcblx0XHRcdFx0XHRcdGN1ci5ub2RlVHlwZSA9PT0gMSAmJlxuXHRcdFx0XHRcdFx0XHRqUXVlcnkuZmluZC5tYXRjaGVzU2VsZWN0b3IoIGN1ciwgc2VsZWN0b3JzICkgKSApIHtcblxuXHRcdFx0XHRcdFx0bWF0Y2hlZC5wdXNoKCBjdXIgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLnB1c2hTdGFjayggbWF0Y2hlZC5sZW5ndGggPiAxID8galF1ZXJ5LnVuaXF1ZVNvcnQoIG1hdGNoZWQgKSA6IG1hdGNoZWQgKTtcblx0fSxcblxuXHQvLyBEZXRlcm1pbmUgdGhlIHBvc2l0aW9uIG9mIGFuIGVsZW1lbnQgd2l0aGluIHRoZSBzZXRcblx0aW5kZXg6IGZ1bmN0aW9uKCBlbGVtICkge1xuXG5cdFx0Ly8gTm8gYXJndW1lbnQsIHJldHVybiBpbmRleCBpbiBwYXJlbnRcblx0XHRpZiAoICFlbGVtICkge1xuXHRcdFx0cmV0dXJuICggdGhpc1sgMCBdICYmIHRoaXNbIDAgXS5wYXJlbnROb2RlICkgPyB0aGlzLmZpcnN0KCkucHJldkFsbCgpLmxlbmd0aCA6IC0xO1xuXHRcdH1cblxuXHRcdC8vIEluZGV4IGluIHNlbGVjdG9yXG5cdFx0aWYgKCB0eXBlb2YgZWxlbSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHJldHVybiBpbmRleE9mLmNhbGwoIGpRdWVyeSggZWxlbSApLCB0aGlzWyAwIF0gKTtcblx0XHR9XG5cblx0XHQvLyBMb2NhdGUgdGhlIHBvc2l0aW9uIG9mIHRoZSBkZXNpcmVkIGVsZW1lbnRcblx0XHRyZXR1cm4gaW5kZXhPZi5jYWxsKCB0aGlzLFxuXG5cdFx0XHQvLyBJZiBpdCByZWNlaXZlcyBhIGpRdWVyeSBvYmplY3QsIHRoZSBmaXJzdCBlbGVtZW50IGlzIHVzZWRcblx0XHRcdGVsZW0uanF1ZXJ5ID8gZWxlbVsgMCBdIDogZWxlbVxuXHRcdCk7XG5cdH0sXG5cblx0YWRkOiBmdW5jdGlvbiggc2VsZWN0b3IsIGNvbnRleHQgKSB7XG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKFxuXHRcdFx0alF1ZXJ5LnVuaXF1ZVNvcnQoXG5cdFx0XHRcdGpRdWVyeS5tZXJnZSggdGhpcy5nZXQoKSwgalF1ZXJ5KCBzZWxlY3RvciwgY29udGV4dCApIClcblx0XHRcdClcblx0XHQpO1xuXHR9LFxuXG5cdGFkZEJhY2s6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gdGhpcy5hZGQoIHNlbGVjdG9yID09IG51bGwgP1xuXHRcdFx0dGhpcy5wcmV2T2JqZWN0IDogdGhpcy5wcmV2T2JqZWN0LmZpbHRlciggc2VsZWN0b3IgKVxuXHRcdCk7XG5cdH1cbn0gKTtcblxuZnVuY3Rpb24gc2libGluZyggY3VyLCBkaXIgKSB7XG5cdHdoaWxlICggKCBjdXIgPSBjdXJbIGRpciBdICkgJiYgY3VyLm5vZGVUeXBlICE9PSAxICkge31cblx0cmV0dXJuIGN1cjtcbn1cblxualF1ZXJ5LmVhY2goIHtcblx0cGFyZW50OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHR2YXIgcGFyZW50ID0gZWxlbS5wYXJlbnROb2RlO1xuXHRcdHJldHVybiBwYXJlbnQgJiYgcGFyZW50Lm5vZGVUeXBlICE9PSAxMSA/IHBhcmVudCA6IG51bGw7XG5cdH0sXG5cdHBhcmVudHM6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiBkaXIoIGVsZW0sIFwicGFyZW50Tm9kZVwiICk7XG5cdH0sXG5cdHBhcmVudHNVbnRpbDogZnVuY3Rpb24oIGVsZW0sIGksIHVudGlsICkge1xuXHRcdHJldHVybiBkaXIoIGVsZW0sIFwicGFyZW50Tm9kZVwiLCB1bnRpbCApO1xuXHR9LFxuXHRuZXh0OiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRyZXR1cm4gc2libGluZyggZWxlbSwgXCJuZXh0U2libGluZ1wiICk7XG5cdH0sXG5cdHByZXY6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiBzaWJsaW5nKCBlbGVtLCBcInByZXZpb3VzU2libGluZ1wiICk7XG5cdH0sXG5cdG5leHRBbGw6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiBkaXIoIGVsZW0sIFwibmV4dFNpYmxpbmdcIiApO1xuXHR9LFxuXHRwcmV2QWxsOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRyZXR1cm4gZGlyKCBlbGVtLCBcInByZXZpb3VzU2libGluZ1wiICk7XG5cdH0sXG5cdG5leHRVbnRpbDogZnVuY3Rpb24oIGVsZW0sIGksIHVudGlsICkge1xuXHRcdHJldHVybiBkaXIoIGVsZW0sIFwibmV4dFNpYmxpbmdcIiwgdW50aWwgKTtcblx0fSxcblx0cHJldlVudGlsOiBmdW5jdGlvbiggZWxlbSwgaSwgdW50aWwgKSB7XG5cdFx0cmV0dXJuIGRpciggZWxlbSwgXCJwcmV2aW91c1NpYmxpbmdcIiwgdW50aWwgKTtcblx0fSxcblx0c2libGluZ3M6IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiBzaWJsaW5ncyggKCBlbGVtLnBhcmVudE5vZGUgfHwge30gKS5maXJzdENoaWxkLCBlbGVtICk7XG5cdH0sXG5cdGNoaWxkcmVuOiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRyZXR1cm4gc2libGluZ3MoIGVsZW0uZmlyc3RDaGlsZCApO1xuXHR9LFxuXHRjb250ZW50czogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0aWYgKCB0eXBlb2YgZWxlbS5jb250ZW50RG9jdW1lbnQgIT09IFwidW5kZWZpbmVkXCIgKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5jb250ZW50RG9jdW1lbnQ7XG5cdFx0fVxuXG5cdFx0Ly8gU3VwcG9ydDogSUUgOSAtIDExIG9ubHksIGlPUyA3IG9ubHksIEFuZHJvaWQgQnJvd3NlciA8PTQuMyBvbmx5XG5cdFx0Ly8gVHJlYXQgdGhlIHRlbXBsYXRlIGVsZW1lbnQgYXMgYSByZWd1bGFyIG9uZSBpbiBicm93c2VycyB0aGF0XG5cdFx0Ly8gZG9uJ3Qgc3VwcG9ydCBpdC5cblx0XHRpZiAoIG5vZGVOYW1lKCBlbGVtLCBcInRlbXBsYXRlXCIgKSApIHtcblx0XHRcdGVsZW0gPSBlbGVtLmNvbnRlbnQgfHwgZWxlbTtcblx0XHR9XG5cblx0XHRyZXR1cm4galF1ZXJ5Lm1lcmdlKCBbXSwgZWxlbS5jaGlsZE5vZGVzICk7XG5cdH1cbn0sIGZ1bmN0aW9uKCBuYW1lLCBmbiApIHtcblx0alF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggdW50aWwsIHNlbGVjdG9yICkge1xuXHRcdHZhciBtYXRjaGVkID0galF1ZXJ5Lm1hcCggdGhpcywgZm4sIHVudGlsICk7XG5cblx0XHRpZiAoIG5hbWUuc2xpY2UoIC01ICkgIT09IFwiVW50aWxcIiApIHtcblx0XHRcdHNlbGVjdG9yID0gdW50aWw7XG5cdFx0fVxuXG5cdFx0aWYgKCBzZWxlY3RvciAmJiB0eXBlb2Ygc2VsZWN0b3IgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRtYXRjaGVkID0galF1ZXJ5LmZpbHRlciggc2VsZWN0b3IsIG1hdGNoZWQgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMubGVuZ3RoID4gMSApIHtcblxuXHRcdFx0Ly8gUmVtb3ZlIGR1cGxpY2F0ZXNcblx0XHRcdGlmICggIWd1YXJhbnRlZWRVbmlxdWVbIG5hbWUgXSApIHtcblx0XHRcdFx0alF1ZXJ5LnVuaXF1ZVNvcnQoIG1hdGNoZWQgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gUmV2ZXJzZSBvcmRlciBmb3IgcGFyZW50cyogYW5kIHByZXYtZGVyaXZhdGl2ZXNcblx0XHRcdGlmICggcnBhcmVudHNwcmV2LnRlc3QoIG5hbWUgKSApIHtcblx0XHRcdFx0bWF0Y2hlZC5yZXZlcnNlKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKCBtYXRjaGVkICk7XG5cdH07XG59ICk7XG52YXIgcm5vdGh0bWx3aGl0ZSA9ICggL1teXFx4MjBcXHRcXHJcXG5cXGZdKy9nICk7XG5cblxuXG4vLyBDb252ZXJ0IFN0cmluZy1mb3JtYXR0ZWQgb3B0aW9ucyBpbnRvIE9iamVjdC1mb3JtYXR0ZWQgb25lc1xuZnVuY3Rpb24gY3JlYXRlT3B0aW9ucyggb3B0aW9ucyApIHtcblx0dmFyIG9iamVjdCA9IHt9O1xuXHRqUXVlcnkuZWFjaCggb3B0aW9ucy5tYXRjaCggcm5vdGh0bWx3aGl0ZSApIHx8IFtdLCBmdW5jdGlvbiggXywgZmxhZyApIHtcblx0XHRvYmplY3RbIGZsYWcgXSA9IHRydWU7XG5cdH0gKTtcblx0cmV0dXJuIG9iamVjdDtcbn1cblxuLypcbiAqIENyZWF0ZSBhIGNhbGxiYWNrIGxpc3QgdXNpbmcgdGhlIGZvbGxvd2luZyBwYXJhbWV0ZXJzOlxuICpcbiAqXHRvcHRpb25zOiBhbiBvcHRpb25hbCBsaXN0IG9mIHNwYWNlLXNlcGFyYXRlZCBvcHRpb25zIHRoYXQgd2lsbCBjaGFuZ2UgaG93XG4gKlx0XHRcdHRoZSBjYWxsYmFjayBsaXN0IGJlaGF2ZXMgb3IgYSBtb3JlIHRyYWRpdGlvbmFsIG9wdGlvbiBvYmplY3RcbiAqXG4gKiBCeSBkZWZhdWx0IGEgY2FsbGJhY2sgbGlzdCB3aWxsIGFjdCBsaWtlIGFuIGV2ZW50IGNhbGxiYWNrIGxpc3QgYW5kIGNhbiBiZVxuICogXCJmaXJlZFwiIG11bHRpcGxlIHRpbWVzLlxuICpcbiAqIFBvc3NpYmxlIG9wdGlvbnM6XG4gKlxuICpcdG9uY2U6XHRcdFx0d2lsbCBlbnN1cmUgdGhlIGNhbGxiYWNrIGxpc3QgY2FuIG9ubHkgYmUgZmlyZWQgb25jZSAobGlrZSBhIERlZmVycmVkKVxuICpcbiAqXHRtZW1vcnk6XHRcdFx0d2lsbCBrZWVwIHRyYWNrIG9mIHByZXZpb3VzIHZhbHVlcyBhbmQgd2lsbCBjYWxsIGFueSBjYWxsYmFjayBhZGRlZFxuICpcdFx0XHRcdFx0YWZ0ZXIgdGhlIGxpc3QgaGFzIGJlZW4gZmlyZWQgcmlnaHQgYXdheSB3aXRoIHRoZSBsYXRlc3QgXCJtZW1vcml6ZWRcIlxuICpcdFx0XHRcdFx0dmFsdWVzIChsaWtlIGEgRGVmZXJyZWQpXG4gKlxuICpcdHVuaXF1ZTpcdFx0XHR3aWxsIGVuc3VyZSBhIGNhbGxiYWNrIGNhbiBvbmx5IGJlIGFkZGVkIG9uY2UgKG5vIGR1cGxpY2F0ZSBpbiB0aGUgbGlzdClcbiAqXG4gKlx0c3RvcE9uRmFsc2U6XHRpbnRlcnJ1cHQgY2FsbGluZ3Mgd2hlbiBhIGNhbGxiYWNrIHJldHVybnMgZmFsc2VcbiAqXG4gKi9cbmpRdWVyeS5DYWxsYmFja3MgPSBmdW5jdGlvbiggb3B0aW9ucyApIHtcblxuXHQvLyBDb252ZXJ0IG9wdGlvbnMgZnJvbSBTdHJpbmctZm9ybWF0dGVkIHRvIE9iamVjdC1mb3JtYXR0ZWQgaWYgbmVlZGVkXG5cdC8vICh3ZSBjaGVjayBpbiBjYWNoZSBmaXJzdClcblx0b3B0aW9ucyA9IHR5cGVvZiBvcHRpb25zID09PSBcInN0cmluZ1wiID9cblx0XHRjcmVhdGVPcHRpb25zKCBvcHRpb25zICkgOlxuXHRcdGpRdWVyeS5leHRlbmQoIHt9LCBvcHRpb25zICk7XG5cblx0dmFyIC8vIEZsYWcgdG8ga25vdyBpZiBsaXN0IGlzIGN1cnJlbnRseSBmaXJpbmdcblx0XHRmaXJpbmcsXG5cblx0XHQvLyBMYXN0IGZpcmUgdmFsdWUgZm9yIG5vbi1mb3JnZXR0YWJsZSBsaXN0c1xuXHRcdG1lbW9yeSxcblxuXHRcdC8vIEZsYWcgdG8ga25vdyBpZiBsaXN0IHdhcyBhbHJlYWR5IGZpcmVkXG5cdFx0ZmlyZWQsXG5cblx0XHQvLyBGbGFnIHRvIHByZXZlbnQgZmlyaW5nXG5cdFx0bG9ja2VkLFxuXG5cdFx0Ly8gQWN0dWFsIGNhbGxiYWNrIGxpc3Rcblx0XHRsaXN0ID0gW10sXG5cblx0XHQvLyBRdWV1ZSBvZiBleGVjdXRpb24gZGF0YSBmb3IgcmVwZWF0YWJsZSBsaXN0c1xuXHRcdHF1ZXVlID0gW10sXG5cblx0XHQvLyBJbmRleCBvZiBjdXJyZW50bHkgZmlyaW5nIGNhbGxiYWNrIChtb2RpZmllZCBieSBhZGQvcmVtb3ZlIGFzIG5lZWRlZClcblx0XHRmaXJpbmdJbmRleCA9IC0xLFxuXG5cdFx0Ly8gRmlyZSBjYWxsYmFja3Ncblx0XHRmaXJlID0gZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIEVuZm9yY2Ugc2luZ2xlLWZpcmluZ1xuXHRcdFx0bG9ja2VkID0gbG9ja2VkIHx8IG9wdGlvbnMub25jZTtcblxuXHRcdFx0Ly8gRXhlY3V0ZSBjYWxsYmFja3MgZm9yIGFsbCBwZW5kaW5nIGV4ZWN1dGlvbnMsXG5cdFx0XHQvLyByZXNwZWN0aW5nIGZpcmluZ0luZGV4IG92ZXJyaWRlcyBhbmQgcnVudGltZSBjaGFuZ2VzXG5cdFx0XHRmaXJlZCA9IGZpcmluZyA9IHRydWU7XG5cdFx0XHRmb3IgKCA7IHF1ZXVlLmxlbmd0aDsgZmlyaW5nSW5kZXggPSAtMSApIHtcblx0XHRcdFx0bWVtb3J5ID0gcXVldWUuc2hpZnQoKTtcblx0XHRcdFx0d2hpbGUgKCArK2ZpcmluZ0luZGV4IDwgbGlzdC5sZW5ndGggKSB7XG5cblx0XHRcdFx0XHQvLyBSdW4gY2FsbGJhY2sgYW5kIGNoZWNrIGZvciBlYXJseSB0ZXJtaW5hdGlvblxuXHRcdFx0XHRcdGlmICggbGlzdFsgZmlyaW5nSW5kZXggXS5hcHBseSggbWVtb3J5WyAwIF0sIG1lbW9yeVsgMSBdICkgPT09IGZhbHNlICYmXG5cdFx0XHRcdFx0XHRvcHRpb25zLnN0b3BPbkZhbHNlICkge1xuXG5cdFx0XHRcdFx0XHQvLyBKdW1wIHRvIGVuZCBhbmQgZm9yZ2V0IHRoZSBkYXRhIHNvIC5hZGQgZG9lc24ndCByZS1maXJlXG5cdFx0XHRcdFx0XHRmaXJpbmdJbmRleCA9IGxpc3QubGVuZ3RoO1xuXHRcdFx0XHRcdFx0bWVtb3J5ID0gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIEZvcmdldCB0aGUgZGF0YSBpZiB3ZSdyZSBkb25lIHdpdGggaXRcblx0XHRcdGlmICggIW9wdGlvbnMubWVtb3J5ICkge1xuXHRcdFx0XHRtZW1vcnkgPSBmYWxzZTtcblx0XHRcdH1cblxuXHRcdFx0ZmlyaW5nID0gZmFsc2U7XG5cblx0XHRcdC8vIENsZWFuIHVwIGlmIHdlJ3JlIGRvbmUgZmlyaW5nIGZvciBnb29kXG5cdFx0XHRpZiAoIGxvY2tlZCApIHtcblxuXHRcdFx0XHQvLyBLZWVwIGFuIGVtcHR5IGxpc3QgaWYgd2UgaGF2ZSBkYXRhIGZvciBmdXR1cmUgYWRkIGNhbGxzXG5cdFx0XHRcdGlmICggbWVtb3J5ICkge1xuXHRcdFx0XHRcdGxpc3QgPSBbXTtcblxuXHRcdFx0XHQvLyBPdGhlcndpc2UsIHRoaXMgb2JqZWN0IGlzIHNwZW50XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0bGlzdCA9IFwiXCI7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9LFxuXG5cdFx0Ly8gQWN0dWFsIENhbGxiYWNrcyBvYmplY3Rcblx0XHRzZWxmID0ge1xuXG5cdFx0XHQvLyBBZGQgYSBjYWxsYmFjayBvciBhIGNvbGxlY3Rpb24gb2YgY2FsbGJhY2tzIHRvIHRoZSBsaXN0XG5cdFx0XHRhZGQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIGxpc3QgKSB7XG5cblx0XHRcdFx0XHQvLyBJZiB3ZSBoYXZlIG1lbW9yeSBmcm9tIGEgcGFzdCBydW4sIHdlIHNob3VsZCBmaXJlIGFmdGVyIGFkZGluZ1xuXHRcdFx0XHRcdGlmICggbWVtb3J5ICYmICFmaXJpbmcgKSB7XG5cdFx0XHRcdFx0XHRmaXJpbmdJbmRleCA9IGxpc3QubGVuZ3RoIC0gMTtcblx0XHRcdFx0XHRcdHF1ZXVlLnB1c2goIG1lbW9yeSApO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdCggZnVuY3Rpb24gYWRkKCBhcmdzICkge1xuXHRcdFx0XHRcdFx0alF1ZXJ5LmVhY2goIGFyZ3MsIGZ1bmN0aW9uKCBfLCBhcmcgKSB7XG5cdFx0XHRcdFx0XHRcdGlmICggaXNGdW5jdGlvbiggYXJnICkgKSB7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKCAhb3B0aW9ucy51bmlxdWUgfHwgIXNlbGYuaGFzKCBhcmcgKSApIHtcblx0XHRcdFx0XHRcdFx0XHRcdGxpc3QucHVzaCggYXJnICk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9IGVsc2UgaWYgKCBhcmcgJiYgYXJnLmxlbmd0aCAmJiB0b1R5cGUoIGFyZyApICE9PSBcInN0cmluZ1wiICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gSW5zcGVjdCByZWN1cnNpdmVseVxuXHRcdFx0XHRcdFx0XHRcdGFkZCggYXJnICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHR9ICkoIGFyZ3VtZW50cyApO1xuXG5cdFx0XHRcdFx0aWYgKCBtZW1vcnkgJiYgIWZpcmluZyApIHtcblx0XHRcdFx0XHRcdGZpcmUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBSZW1vdmUgYSBjYWxsYmFjayBmcm9tIHRoZSBsaXN0XG5cdFx0XHRyZW1vdmU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRqUXVlcnkuZWFjaCggYXJndW1lbnRzLCBmdW5jdGlvbiggXywgYXJnICkge1xuXHRcdFx0XHRcdHZhciBpbmRleDtcblx0XHRcdFx0XHR3aGlsZSAoICggaW5kZXggPSBqUXVlcnkuaW5BcnJheSggYXJnLCBsaXN0LCBpbmRleCApICkgPiAtMSApIHtcblx0XHRcdFx0XHRcdGxpc3Quc3BsaWNlKCBpbmRleCwgMSApO1xuXG5cdFx0XHRcdFx0XHQvLyBIYW5kbGUgZmlyaW5nIGluZGV4ZXNcblx0XHRcdFx0XHRcdGlmICggaW5kZXggPD0gZmlyaW5nSW5kZXggKSB7XG5cdFx0XHRcdFx0XHRcdGZpcmluZ0luZGV4LS07XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gQ2hlY2sgaWYgYSBnaXZlbiBjYWxsYmFjayBpcyBpbiB0aGUgbGlzdC5cblx0XHRcdC8vIElmIG5vIGFyZ3VtZW50IGlzIGdpdmVuLCByZXR1cm4gd2hldGhlciBvciBub3QgbGlzdCBoYXMgY2FsbGJhY2tzIGF0dGFjaGVkLlxuXHRcdFx0aGFzOiBmdW5jdGlvbiggZm4gKSB7XG5cdFx0XHRcdHJldHVybiBmbiA/XG5cdFx0XHRcdFx0alF1ZXJ5LmluQXJyYXkoIGZuLCBsaXN0ICkgPiAtMSA6XG5cdFx0XHRcdFx0bGlzdC5sZW5ndGggPiAwO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gUmVtb3ZlIGFsbCBjYWxsYmFja3MgZnJvbSB0aGUgbGlzdFxuXHRcdFx0ZW1wdHk6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIGxpc3QgKSB7XG5cdFx0XHRcdFx0bGlzdCA9IFtdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gRGlzYWJsZSAuZmlyZSBhbmQgLmFkZFxuXHRcdFx0Ly8gQWJvcnQgYW55IGN1cnJlbnQvcGVuZGluZyBleGVjdXRpb25zXG5cdFx0XHQvLyBDbGVhciBhbGwgY2FsbGJhY2tzIGFuZCB2YWx1ZXNcblx0XHRcdGRpc2FibGU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRsb2NrZWQgPSBxdWV1ZSA9IFtdO1xuXHRcdFx0XHRsaXN0ID0gbWVtb3J5ID0gXCJcIjtcblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9LFxuXHRcdFx0ZGlzYWJsZWQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gIWxpc3Q7XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBEaXNhYmxlIC5maXJlXG5cdFx0XHQvLyBBbHNvIGRpc2FibGUgLmFkZCB1bmxlc3Mgd2UgaGF2ZSBtZW1vcnkgKHNpbmNlIGl0IHdvdWxkIGhhdmUgbm8gZWZmZWN0KVxuXHRcdFx0Ly8gQWJvcnQgYW55IHBlbmRpbmcgZXhlY3V0aW9uc1xuXHRcdFx0bG9jazogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGxvY2tlZCA9IHF1ZXVlID0gW107XG5cdFx0XHRcdGlmICggIW1lbW9yeSAmJiAhZmlyaW5nICkge1xuXHRcdFx0XHRcdGxpc3QgPSBtZW1vcnkgPSBcIlwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0fSxcblx0XHRcdGxvY2tlZDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiAhIWxvY2tlZDtcblx0XHRcdH0sXG5cblx0XHRcdC8vIENhbGwgYWxsIGNhbGxiYWNrcyB3aXRoIHRoZSBnaXZlbiBjb250ZXh0IGFuZCBhcmd1bWVudHNcblx0XHRcdGZpcmVXaXRoOiBmdW5jdGlvbiggY29udGV4dCwgYXJncyApIHtcblx0XHRcdFx0aWYgKCAhbG9ja2VkICkge1xuXHRcdFx0XHRcdGFyZ3MgPSBhcmdzIHx8IFtdO1xuXHRcdFx0XHRcdGFyZ3MgPSBbIGNvbnRleHQsIGFyZ3Muc2xpY2UgPyBhcmdzLnNsaWNlKCkgOiBhcmdzIF07XG5cdFx0XHRcdFx0cXVldWUucHVzaCggYXJncyApO1xuXHRcdFx0XHRcdGlmICggIWZpcmluZyApIHtcblx0XHRcdFx0XHRcdGZpcmUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBDYWxsIGFsbCB0aGUgY2FsbGJhY2tzIHdpdGggdGhlIGdpdmVuIGFyZ3VtZW50c1xuXHRcdFx0ZmlyZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHNlbGYuZmlyZVdpdGgoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH0sXG5cblx0XHRcdC8vIFRvIGtub3cgaWYgdGhlIGNhbGxiYWNrcyBoYXZlIGFscmVhZHkgYmVlbiBjYWxsZWQgYXQgbGVhc3Qgb25jZVxuXHRcdFx0ZmlyZWQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gISFmaXJlZDtcblx0XHRcdH1cblx0XHR9O1xuXG5cdHJldHVybiBzZWxmO1xufTtcblxuXG5mdW5jdGlvbiBJZGVudGl0eSggdiApIHtcblx0cmV0dXJuIHY7XG59XG5mdW5jdGlvbiBUaHJvd2VyKCBleCApIHtcblx0dGhyb3cgZXg7XG59XG5cbmZ1bmN0aW9uIGFkb3B0VmFsdWUoIHZhbHVlLCByZXNvbHZlLCByZWplY3QsIG5vVmFsdWUgKSB7XG5cdHZhciBtZXRob2Q7XG5cblx0dHJ5IHtcblxuXHRcdC8vIENoZWNrIGZvciBwcm9taXNlIGFzcGVjdCBmaXJzdCB0byBwcml2aWxlZ2Ugc3luY2hyb25vdXMgYmVoYXZpb3Jcblx0XHRpZiAoIHZhbHVlICYmIGlzRnVuY3Rpb24oICggbWV0aG9kID0gdmFsdWUucHJvbWlzZSApICkgKSB7XG5cdFx0XHRtZXRob2QuY2FsbCggdmFsdWUgKS5kb25lKCByZXNvbHZlICkuZmFpbCggcmVqZWN0ICk7XG5cblx0XHQvLyBPdGhlciB0aGVuYWJsZXNcblx0XHR9IGVsc2UgaWYgKCB2YWx1ZSAmJiBpc0Z1bmN0aW9uKCAoIG1ldGhvZCA9IHZhbHVlLnRoZW4gKSApICkge1xuXHRcdFx0bWV0aG9kLmNhbGwoIHZhbHVlLCByZXNvbHZlLCByZWplY3QgKTtcblxuXHRcdC8vIE90aGVyIG5vbi10aGVuYWJsZXNcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBDb250cm9sIGByZXNvbHZlYCBhcmd1bWVudHMgYnkgbGV0dGluZyBBcnJheSNzbGljZSBjYXN0IGJvb2xlYW4gYG5vVmFsdWVgIHRvIGludGVnZXI6XG5cdFx0XHQvLyAqIGZhbHNlOiBbIHZhbHVlIF0uc2xpY2UoIDAgKSA9PiByZXNvbHZlKCB2YWx1ZSApXG5cdFx0XHQvLyAqIHRydWU6IFsgdmFsdWUgXS5zbGljZSggMSApID0+IHJlc29sdmUoKVxuXHRcdFx0cmVzb2x2ZS5hcHBseSggdW5kZWZpbmVkLCBbIHZhbHVlIF0uc2xpY2UoIG5vVmFsdWUgKSApO1xuXHRcdH1cblxuXHQvLyBGb3IgUHJvbWlzZXMvQSssIGNvbnZlcnQgZXhjZXB0aW9ucyBpbnRvIHJlamVjdGlvbnNcblx0Ly8gU2luY2UgalF1ZXJ5LndoZW4gZG9lc24ndCB1bndyYXAgdGhlbmFibGVzLCB3ZSBjYW4gc2tpcCB0aGUgZXh0cmEgY2hlY2tzIGFwcGVhcmluZyBpblxuXHQvLyBEZWZlcnJlZCN0aGVuIHRvIGNvbmRpdGlvbmFsbHkgc3VwcHJlc3MgcmVqZWN0aW9uLlxuXHR9IGNhdGNoICggdmFsdWUgKSB7XG5cblx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkIDQuMCBvbmx5XG5cdFx0Ly8gU3RyaWN0IG1vZGUgZnVuY3Rpb25zIGludm9rZWQgd2l0aG91dCAuY2FsbC8uYXBwbHkgZ2V0IGdsb2JhbC1vYmplY3QgY29udGV4dFxuXHRcdHJlamVjdC5hcHBseSggdW5kZWZpbmVkLCBbIHZhbHVlIF0gKTtcblx0fVxufVxuXG5qUXVlcnkuZXh0ZW5kKCB7XG5cblx0RGVmZXJyZWQ6IGZ1bmN0aW9uKCBmdW5jICkge1xuXHRcdHZhciB0dXBsZXMgPSBbXG5cblx0XHRcdFx0Ly8gYWN0aW9uLCBhZGQgbGlzdGVuZXIsIGNhbGxiYWNrcyxcblx0XHRcdFx0Ly8gLi4uIC50aGVuIGhhbmRsZXJzLCBhcmd1bWVudCBpbmRleCwgW2ZpbmFsIHN0YXRlXVxuXHRcdFx0XHRbIFwibm90aWZ5XCIsIFwicHJvZ3Jlc3NcIiwgalF1ZXJ5LkNhbGxiYWNrcyggXCJtZW1vcnlcIiApLFxuXHRcdFx0XHRcdGpRdWVyeS5DYWxsYmFja3MoIFwibWVtb3J5XCIgKSwgMiBdLFxuXHRcdFx0XHRbIFwicmVzb2x2ZVwiLCBcImRvbmVcIiwgalF1ZXJ5LkNhbGxiYWNrcyggXCJvbmNlIG1lbW9yeVwiICksXG5cdFx0XHRcdFx0alF1ZXJ5LkNhbGxiYWNrcyggXCJvbmNlIG1lbW9yeVwiICksIDAsIFwicmVzb2x2ZWRcIiBdLFxuXHRcdFx0XHRbIFwicmVqZWN0XCIsIFwiZmFpbFwiLCBqUXVlcnkuQ2FsbGJhY2tzKCBcIm9uY2UgbWVtb3J5XCIgKSxcblx0XHRcdFx0XHRqUXVlcnkuQ2FsbGJhY2tzKCBcIm9uY2UgbWVtb3J5XCIgKSwgMSwgXCJyZWplY3RlZFwiIF1cblx0XHRcdF0sXG5cdFx0XHRzdGF0ZSA9IFwicGVuZGluZ1wiLFxuXHRcdFx0cHJvbWlzZSA9IHtcblx0XHRcdFx0c3RhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHJldHVybiBzdGF0ZTtcblx0XHRcdFx0fSxcblx0XHRcdFx0YWx3YXlzOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRkZWZlcnJlZC5kb25lKCBhcmd1bWVudHMgKS5mYWlsKCBhcmd1bWVudHMgKTtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdFx0fSxcblx0XHRcdFx0XCJjYXRjaFwiOiBmdW5jdGlvbiggZm4gKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHByb21pc2UudGhlbiggbnVsbCwgZm4gKTtcblx0XHRcdFx0fSxcblxuXHRcdFx0XHQvLyBLZWVwIHBpcGUgZm9yIGJhY2stY29tcGF0XG5cdFx0XHRcdHBpcGU6IGZ1bmN0aW9uKCAvKiBmbkRvbmUsIGZuRmFpbCwgZm5Qcm9ncmVzcyAqLyApIHtcblx0XHRcdFx0XHR2YXIgZm5zID0gYXJndW1lbnRzO1xuXG5cdFx0XHRcdFx0cmV0dXJuIGpRdWVyeS5EZWZlcnJlZCggZnVuY3Rpb24oIG5ld0RlZmVyICkge1xuXHRcdFx0XHRcdFx0alF1ZXJ5LmVhY2goIHR1cGxlcywgZnVuY3Rpb24oIGksIHR1cGxlICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIE1hcCB0dXBsZXMgKHByb2dyZXNzLCBkb25lLCBmYWlsKSB0byBhcmd1bWVudHMgKGRvbmUsIGZhaWwsIHByb2dyZXNzKVxuXHRcdFx0XHRcdFx0XHR2YXIgZm4gPSBpc0Z1bmN0aW9uKCBmbnNbIHR1cGxlWyA0IF0gXSApICYmIGZuc1sgdHVwbGVbIDQgXSBdO1xuXG5cdFx0XHRcdFx0XHRcdC8vIGRlZmVycmVkLnByb2dyZXNzKGZ1bmN0aW9uKCkgeyBiaW5kIHRvIG5ld0RlZmVyIG9yIG5ld0RlZmVyLm5vdGlmeSB9KVxuXHRcdFx0XHRcdFx0XHQvLyBkZWZlcnJlZC5kb25lKGZ1bmN0aW9uKCkgeyBiaW5kIHRvIG5ld0RlZmVyIG9yIG5ld0RlZmVyLnJlc29sdmUgfSlcblx0XHRcdFx0XHRcdFx0Ly8gZGVmZXJyZWQuZmFpbChmdW5jdGlvbigpIHsgYmluZCB0byBuZXdEZWZlciBvciBuZXdEZWZlci5yZWplY3QgfSlcblx0XHRcdFx0XHRcdFx0ZGVmZXJyZWRbIHR1cGxlWyAxIF0gXSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRcdFx0dmFyIHJldHVybmVkID0gZm4gJiYgZm4uYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0XHRcdFx0XHRcdGlmICggcmV0dXJuZWQgJiYgaXNGdW5jdGlvbiggcmV0dXJuZWQucHJvbWlzZSApICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuZWQucHJvbWlzZSgpXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC5wcm9ncmVzcyggbmV3RGVmZXIubm90aWZ5IClcblx0XHRcdFx0XHRcdFx0XHRcdFx0LmRvbmUoIG5ld0RlZmVyLnJlc29sdmUgKVxuXHRcdFx0XHRcdFx0XHRcdFx0XHQuZmFpbCggbmV3RGVmZXIucmVqZWN0ICk7XG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRcdG5ld0RlZmVyWyB0dXBsZVsgMCBdICsgXCJXaXRoXCIgXShcblx0XHRcdFx0XHRcdFx0XHRcdFx0dGhpcyxcblx0XHRcdFx0XHRcdFx0XHRcdFx0Zm4gPyBbIHJldHVybmVkIF0gOiBhcmd1bWVudHNcblx0XHRcdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0XHRmbnMgPSBudWxsO1xuXHRcdFx0XHRcdH0gKS5wcm9taXNlKCk7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHRoZW46IGZ1bmN0aW9uKCBvbkZ1bGZpbGxlZCwgb25SZWplY3RlZCwgb25Qcm9ncmVzcyApIHtcblx0XHRcdFx0XHR2YXIgbWF4RGVwdGggPSAwO1xuXHRcdFx0XHRcdGZ1bmN0aW9uIHJlc29sdmUoIGRlcHRoLCBkZWZlcnJlZCwgaGFuZGxlciwgc3BlY2lhbCApIHtcblx0XHRcdFx0XHRcdHJldHVybiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0XHRcdFx0XHRcdGFyZ3MgPSBhcmd1bWVudHMsXG5cdFx0XHRcdFx0XHRcdFx0bWlnaHRUaHJvdyA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0XHRcdFx0dmFyIHJldHVybmVkLCB0aGVuO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBQcm9taXNlcy9BKyBzZWN0aW9uIDIuMy4zLjMuM1xuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gaHR0cHM6Ly9wcm9taXNlc2FwbHVzLmNvbS8jcG9pbnQtNTlcblx0XHRcdFx0XHRcdFx0XHRcdC8vIElnbm9yZSBkb3VibGUtcmVzb2x1dGlvbiBhdHRlbXB0c1xuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkZXB0aCA8IG1heERlcHRoICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHRcdHJldHVybmVkID0gaGFuZGxlci5hcHBseSggdGhhdCwgYXJncyApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBQcm9taXNlcy9BKyBzZWN0aW9uIDIuMy4xXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBodHRwczovL3Byb21pc2VzYXBsdXMuY29tLyNwb2ludC00OFxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCByZXR1cm5lZCA9PT0gZGVmZXJyZWQucHJvbWlzZSgpICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR0aHJvdyBuZXcgVHlwZUVycm9yKCBcIlRoZW5hYmxlIHNlbGYtcmVzb2x1dGlvblwiICk7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IFByb21pc2VzL0ErIHNlY3Rpb25zIDIuMy4zLjEsIDMuNVxuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gaHR0cHM6Ly9wcm9taXNlc2FwbHVzLmNvbS8jcG9pbnQtNTRcblx0XHRcdFx0XHRcdFx0XHRcdC8vIGh0dHBzOi8vcHJvbWlzZXNhcGx1cy5jb20vI3BvaW50LTc1XG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBSZXRyaWV2ZSBgdGhlbmAgb25seSBvbmNlXG5cdFx0XHRcdFx0XHRcdFx0XHR0aGVuID0gcmV0dXJuZWQgJiZcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBQcm9taXNlcy9BKyBzZWN0aW9uIDIuMy40XG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGh0dHBzOi8vcHJvbWlzZXNhcGx1cy5jb20vI3BvaW50LTY0XG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIE9ubHkgY2hlY2sgb2JqZWN0cyBhbmQgZnVuY3Rpb25zIGZvciB0aGVuYWJpbGl0eVxuXHRcdFx0XHRcdFx0XHRcdFx0XHQoIHR5cGVvZiByZXR1cm5lZCA9PT0gXCJvYmplY3RcIiB8fFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHR5cGVvZiByZXR1cm5lZCA9PT0gXCJmdW5jdGlvblwiICkgJiZcblx0XHRcdFx0XHRcdFx0XHRcdFx0cmV0dXJuZWQudGhlbjtcblxuXHRcdFx0XHRcdFx0XHRcdFx0Ly8gSGFuZGxlIGEgcmV0dXJuZWQgdGhlbmFibGVcblx0XHRcdFx0XHRcdFx0XHRcdGlmICggaXNGdW5jdGlvbiggdGhlbiApICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFNwZWNpYWwgcHJvY2Vzc29ycyAobm90aWZ5KSBqdXN0IHdhaXQgZm9yIHJlc29sdXRpb25cblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBzcGVjaWFsICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRoZW4uY2FsbChcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHJldHVybmVkLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0cmVzb2x2ZSggbWF4RGVwdGgsIGRlZmVycmVkLCBJZGVudGl0eSwgc3BlY2lhbCApLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0cmVzb2x2ZSggbWF4RGVwdGgsIGRlZmVycmVkLCBUaHJvd2VyLCBzcGVjaWFsIClcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIE5vcm1hbCBwcm9jZXNzb3JzIChyZXNvbHZlKSBhbHNvIGhvb2sgaW50byBwcm9ncmVzc1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gLi4uYW5kIGRpc3JlZ2FyZCBvbGRlciByZXNvbHV0aW9uIHZhbHVlc1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdG1heERlcHRoKys7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0aGVuLmNhbGwoXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRyZXR1cm5lZCxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHJlc29sdmUoIG1heERlcHRoLCBkZWZlcnJlZCwgSWRlbnRpdHksIHNwZWNpYWwgKSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdHJlc29sdmUoIG1heERlcHRoLCBkZWZlcnJlZCwgVGhyb3dlciwgc3BlY2lhbCApLFxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0cmVzb2x2ZSggbWF4RGVwdGgsIGRlZmVycmVkLCBJZGVudGl0eSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0ZGVmZXJyZWQubm90aWZ5V2l0aCApXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBIYW5kbGUgYWxsIG90aGVyIHJldHVybmVkIHZhbHVlc1xuXHRcdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHQvLyBPbmx5IHN1YnN0aXR1dGUgaGFuZGxlcnMgcGFzcyBvbiBjb250ZXh0XG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGFuZCBtdWx0aXBsZSB2YWx1ZXMgKG5vbi1zcGVjIGJlaGF2aW9yKVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRpZiAoIGhhbmRsZXIgIT09IElkZW50aXR5ICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdHRoYXQgPSB1bmRlZmluZWQ7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0YXJncyA9IFsgcmV0dXJuZWQgXTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIFByb2Nlc3MgdGhlIHZhbHVlKHMpXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIERlZmF1bHQgcHJvY2VzcyBpcyByZXNvbHZlXG5cdFx0XHRcdFx0XHRcdFx0XHRcdCggc3BlY2lhbCB8fCBkZWZlcnJlZC5yZXNvbHZlV2l0aCApKCB0aGF0LCBhcmdzICk7XG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0fSxcblxuXHRcdFx0XHRcdFx0XHRcdC8vIE9ubHkgbm9ybWFsIHByb2Nlc3NvcnMgKHJlc29sdmUpIGNhdGNoIGFuZCByZWplY3QgZXhjZXB0aW9uc1xuXHRcdFx0XHRcdFx0XHRcdHByb2Nlc3MgPSBzcGVjaWFsID9cblx0XHRcdFx0XHRcdFx0XHRcdG1pZ2h0VGhyb3cgOlxuXHRcdFx0XHRcdFx0XHRcdFx0ZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0bWlnaHRUaHJvdygpO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR9IGNhdGNoICggZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGlmICggalF1ZXJ5LkRlZmVycmVkLmV4Y2VwdGlvbkhvb2sgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRqUXVlcnkuRGVmZXJyZWQuZXhjZXB0aW9uSG9vayggZSxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0cHJvY2Vzcy5zdGFja1RyYWNlICk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogUHJvbWlzZXMvQSsgc2VjdGlvbiAyLjMuMy4zLjQuMVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGh0dHBzOi8vcHJvbWlzZXNhcGx1cy5jb20vI3BvaW50LTYxXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Ly8gSWdub3JlIHBvc3QtcmVzb2x1dGlvbiBleGNlcHRpb25zXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkZXB0aCArIDEgPj0gbWF4RGVwdGggKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIE9ubHkgc3Vic3RpdHV0ZSBoYW5kbGVycyBwYXNzIG9uIGNvbnRleHRcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdC8vIGFuZCBtdWx0aXBsZSB2YWx1ZXMgKG5vbi1zcGVjIGJlaGF2aW9yKVxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBoYW5kbGVyICE9PSBUaHJvd2VyICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR0aGF0ID0gdW5kZWZpbmVkO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRhcmdzID0gWyBlIF07XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGRlZmVycmVkLnJlamVjdFdpdGgoIHRoYXQsIGFyZ3MgKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0XHRcdH07XG5cblx0XHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogUHJvbWlzZXMvQSsgc2VjdGlvbiAyLjMuMy4zLjFcblx0XHRcdFx0XHRcdFx0Ly8gaHR0cHM6Ly9wcm9taXNlc2FwbHVzLmNvbS8jcG9pbnQtNTdcblx0XHRcdFx0XHRcdFx0Ly8gUmUtcmVzb2x2ZSBwcm9taXNlcyBpbW1lZGlhdGVseSB0byBkb2RnZSBmYWxzZSByZWplY3Rpb24gZnJvbVxuXHRcdFx0XHRcdFx0XHQvLyBzdWJzZXF1ZW50IGVycm9yc1xuXHRcdFx0XHRcdFx0XHRpZiAoIGRlcHRoICkge1xuXHRcdFx0XHRcdFx0XHRcdHByb2Nlc3MoKTtcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIENhbGwgYW4gb3B0aW9uYWwgaG9vayB0byByZWNvcmQgdGhlIHN0YWNrLCBpbiBjYXNlIG9mIGV4Y2VwdGlvblxuXHRcdFx0XHRcdFx0XHRcdC8vIHNpbmNlIGl0J3Mgb3RoZXJ3aXNlIGxvc3Qgd2hlbiBleGVjdXRpb24gZ29lcyBhc3luY1xuXHRcdFx0XHRcdFx0XHRcdGlmICggalF1ZXJ5LkRlZmVycmVkLmdldFN0YWNrSG9vayApIHtcblx0XHRcdFx0XHRcdFx0XHRcdHByb2Nlc3Muc3RhY2tUcmFjZSA9IGpRdWVyeS5EZWZlcnJlZC5nZXRTdGFja0hvb2soKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdFx0d2luZG93LnNldFRpbWVvdXQoIHByb2Nlc3MgKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRyZXR1cm4galF1ZXJ5LkRlZmVycmVkKCBmdW5jdGlvbiggbmV3RGVmZXIgKSB7XG5cblx0XHRcdFx0XHRcdC8vIHByb2dyZXNzX2hhbmRsZXJzLmFkZCggLi4uIClcblx0XHRcdFx0XHRcdHR1cGxlc1sgMCBdWyAzIF0uYWRkKFxuXHRcdFx0XHRcdFx0XHRyZXNvbHZlKFxuXHRcdFx0XHRcdFx0XHRcdDAsXG5cdFx0XHRcdFx0XHRcdFx0bmV3RGVmZXIsXG5cdFx0XHRcdFx0XHRcdFx0aXNGdW5jdGlvbiggb25Qcm9ncmVzcyApID9cblx0XHRcdFx0XHRcdFx0XHRcdG9uUHJvZ3Jlc3MgOlxuXHRcdFx0XHRcdFx0XHRcdFx0SWRlbnRpdHksXG5cdFx0XHRcdFx0XHRcdFx0bmV3RGVmZXIubm90aWZ5V2l0aFxuXHRcdFx0XHRcdFx0XHQpXG5cdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0XHQvLyBmdWxmaWxsZWRfaGFuZGxlcnMuYWRkKCAuLi4gKVxuXHRcdFx0XHRcdFx0dHVwbGVzWyAxIF1bIDMgXS5hZGQoXG5cdFx0XHRcdFx0XHRcdHJlc29sdmUoXG5cdFx0XHRcdFx0XHRcdFx0MCxcblx0XHRcdFx0XHRcdFx0XHRuZXdEZWZlcixcblx0XHRcdFx0XHRcdFx0XHRpc0Z1bmN0aW9uKCBvbkZ1bGZpbGxlZCApID9cblx0XHRcdFx0XHRcdFx0XHRcdG9uRnVsZmlsbGVkIDpcblx0XHRcdFx0XHRcdFx0XHRcdElkZW50aXR5XG5cdFx0XHRcdFx0XHRcdClcblx0XHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHRcdC8vIHJlamVjdGVkX2hhbmRsZXJzLmFkZCggLi4uIClcblx0XHRcdFx0XHRcdHR1cGxlc1sgMiBdWyAzIF0uYWRkKFxuXHRcdFx0XHRcdFx0XHRyZXNvbHZlKFxuXHRcdFx0XHRcdFx0XHRcdDAsXG5cdFx0XHRcdFx0XHRcdFx0bmV3RGVmZXIsXG5cdFx0XHRcdFx0XHRcdFx0aXNGdW5jdGlvbiggb25SZWplY3RlZCApID9cblx0XHRcdFx0XHRcdFx0XHRcdG9uUmVqZWN0ZWQgOlxuXHRcdFx0XHRcdFx0XHRcdFx0VGhyb3dlclxuXHRcdFx0XHRcdFx0XHQpXG5cdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdH0gKS5wcm9taXNlKCk7XG5cdFx0XHRcdH0sXG5cblx0XHRcdFx0Ly8gR2V0IGEgcHJvbWlzZSBmb3IgdGhpcyBkZWZlcnJlZFxuXHRcdFx0XHQvLyBJZiBvYmogaXMgcHJvdmlkZWQsIHRoZSBwcm9taXNlIGFzcGVjdCBpcyBhZGRlZCB0byB0aGUgb2JqZWN0XG5cdFx0XHRcdHByb21pc2U6IGZ1bmN0aW9uKCBvYmogKSB7XG5cdFx0XHRcdFx0cmV0dXJuIG9iaiAhPSBudWxsID8galF1ZXJ5LmV4dGVuZCggb2JqLCBwcm9taXNlICkgOiBwcm9taXNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0ZGVmZXJyZWQgPSB7fTtcblxuXHRcdC8vIEFkZCBsaXN0LXNwZWNpZmljIG1ldGhvZHNcblx0XHRqUXVlcnkuZWFjaCggdHVwbGVzLCBmdW5jdGlvbiggaSwgdHVwbGUgKSB7XG5cdFx0XHR2YXIgbGlzdCA9IHR1cGxlWyAyIF0sXG5cdFx0XHRcdHN0YXRlU3RyaW5nID0gdHVwbGVbIDUgXTtcblxuXHRcdFx0Ly8gcHJvbWlzZS5wcm9ncmVzcyA9IGxpc3QuYWRkXG5cdFx0XHQvLyBwcm9taXNlLmRvbmUgPSBsaXN0LmFkZFxuXHRcdFx0Ly8gcHJvbWlzZS5mYWlsID0gbGlzdC5hZGRcblx0XHRcdHByb21pc2VbIHR1cGxlWyAxIF0gXSA9IGxpc3QuYWRkO1xuXG5cdFx0XHQvLyBIYW5kbGUgc3RhdGVcblx0XHRcdGlmICggc3RhdGVTdHJpbmcgKSB7XG5cdFx0XHRcdGxpc3QuYWRkKFxuXHRcdFx0XHRcdGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRcdFx0XHQvLyBzdGF0ZSA9IFwicmVzb2x2ZWRcIiAoaS5lLiwgZnVsZmlsbGVkKVxuXHRcdFx0XHRcdFx0Ly8gc3RhdGUgPSBcInJlamVjdGVkXCJcblx0XHRcdFx0XHRcdHN0YXRlID0gc3RhdGVTdHJpbmc7XG5cdFx0XHRcdFx0fSxcblxuXHRcdFx0XHRcdC8vIHJlamVjdGVkX2NhbGxiYWNrcy5kaXNhYmxlXG5cdFx0XHRcdFx0Ly8gZnVsZmlsbGVkX2NhbGxiYWNrcy5kaXNhYmxlXG5cdFx0XHRcdFx0dHVwbGVzWyAzIC0gaSBdWyAyIF0uZGlzYWJsZSxcblxuXHRcdFx0XHRcdC8vIHJlamVjdGVkX2hhbmRsZXJzLmRpc2FibGVcblx0XHRcdFx0XHQvLyBmdWxmaWxsZWRfaGFuZGxlcnMuZGlzYWJsZVxuXHRcdFx0XHRcdHR1cGxlc1sgMyAtIGkgXVsgMyBdLmRpc2FibGUsXG5cblx0XHRcdFx0XHQvLyBwcm9ncmVzc19jYWxsYmFja3MubG9ja1xuXHRcdFx0XHRcdHR1cGxlc1sgMCBdWyAyIF0ubG9jayxcblxuXHRcdFx0XHRcdC8vIHByb2dyZXNzX2hhbmRsZXJzLmxvY2tcblx0XHRcdFx0XHR0dXBsZXNbIDAgXVsgMyBdLmxvY2tcblx0XHRcdFx0KTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gcHJvZ3Jlc3NfaGFuZGxlcnMuZmlyZVxuXHRcdFx0Ly8gZnVsZmlsbGVkX2hhbmRsZXJzLmZpcmVcblx0XHRcdC8vIHJlamVjdGVkX2hhbmRsZXJzLmZpcmVcblx0XHRcdGxpc3QuYWRkKCB0dXBsZVsgMyBdLmZpcmUgKTtcblxuXHRcdFx0Ly8gZGVmZXJyZWQubm90aWZ5ID0gZnVuY3Rpb24oKSB7IGRlZmVycmVkLm5vdGlmeVdpdGgoLi4uKSB9XG5cdFx0XHQvLyBkZWZlcnJlZC5yZXNvbHZlID0gZnVuY3Rpb24oKSB7IGRlZmVycmVkLnJlc29sdmVXaXRoKC4uLikgfVxuXHRcdFx0Ly8gZGVmZXJyZWQucmVqZWN0ID0gZnVuY3Rpb24oKSB7IGRlZmVycmVkLnJlamVjdFdpdGgoLi4uKSB9XG5cdFx0XHRkZWZlcnJlZFsgdHVwbGVbIDAgXSBdID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGRlZmVycmVkWyB0dXBsZVsgMCBdICsgXCJXaXRoXCIgXSggdGhpcyA9PT0gZGVmZXJyZWQgPyB1bmRlZmluZWQgOiB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9O1xuXG5cdFx0XHQvLyBkZWZlcnJlZC5ub3RpZnlXaXRoID0gbGlzdC5maXJlV2l0aFxuXHRcdFx0Ly8gZGVmZXJyZWQucmVzb2x2ZVdpdGggPSBsaXN0LmZpcmVXaXRoXG5cdFx0XHQvLyBkZWZlcnJlZC5yZWplY3RXaXRoID0gbGlzdC5maXJlV2l0aFxuXHRcdFx0ZGVmZXJyZWRbIHR1cGxlWyAwIF0gKyBcIldpdGhcIiBdID0gbGlzdC5maXJlV2l0aDtcblx0XHR9ICk7XG5cblx0XHQvLyBNYWtlIHRoZSBkZWZlcnJlZCBhIHByb21pc2Vcblx0XHRwcm9taXNlLnByb21pc2UoIGRlZmVycmVkICk7XG5cblx0XHQvLyBDYWxsIGdpdmVuIGZ1bmMgaWYgYW55XG5cdFx0aWYgKCBmdW5jICkge1xuXHRcdFx0ZnVuYy5jYWxsKCBkZWZlcnJlZCwgZGVmZXJyZWQgKTtcblx0XHR9XG5cblx0XHQvLyBBbGwgZG9uZSFcblx0XHRyZXR1cm4gZGVmZXJyZWQ7XG5cdH0sXG5cblx0Ly8gRGVmZXJyZWQgaGVscGVyXG5cdHdoZW46IGZ1bmN0aW9uKCBzaW5nbGVWYWx1ZSApIHtcblx0XHR2YXJcblxuXHRcdFx0Ly8gY291bnQgb2YgdW5jb21wbGV0ZWQgc3Vib3JkaW5hdGVzXG5cdFx0XHRyZW1haW5pbmcgPSBhcmd1bWVudHMubGVuZ3RoLFxuXG5cdFx0XHQvLyBjb3VudCBvZiB1bnByb2Nlc3NlZCBhcmd1bWVudHNcblx0XHRcdGkgPSByZW1haW5pbmcsXG5cblx0XHRcdC8vIHN1Ym9yZGluYXRlIGZ1bGZpbGxtZW50IGRhdGFcblx0XHRcdHJlc29sdmVDb250ZXh0cyA9IEFycmF5KCBpICksXG5cdFx0XHRyZXNvbHZlVmFsdWVzID0gc2xpY2UuY2FsbCggYXJndW1lbnRzICksXG5cblx0XHRcdC8vIHRoZSBtYXN0ZXIgRGVmZXJyZWRcblx0XHRcdG1hc3RlciA9IGpRdWVyeS5EZWZlcnJlZCgpLFxuXG5cdFx0XHQvLyBzdWJvcmRpbmF0ZSBjYWxsYmFjayBmYWN0b3J5XG5cdFx0XHR1cGRhdGVGdW5jID0gZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHRcdHJldHVybiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0XHRcdFx0cmVzb2x2ZUNvbnRleHRzWyBpIF0gPSB0aGlzO1xuXHRcdFx0XHRcdHJlc29sdmVWYWx1ZXNbIGkgXSA9IGFyZ3VtZW50cy5sZW5ndGggPiAxID8gc2xpY2UuY2FsbCggYXJndW1lbnRzICkgOiB2YWx1ZTtcblx0XHRcdFx0XHRpZiAoICEoIC0tcmVtYWluaW5nICkgKSB7XG5cdFx0XHRcdFx0XHRtYXN0ZXIucmVzb2x2ZVdpdGgoIHJlc29sdmVDb250ZXh0cywgcmVzb2x2ZVZhbHVlcyApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fTtcblx0XHRcdH07XG5cblx0XHQvLyBTaW5nbGUtIGFuZCBlbXB0eSBhcmd1bWVudHMgYXJlIGFkb3B0ZWQgbGlrZSBQcm9taXNlLnJlc29sdmVcblx0XHRpZiAoIHJlbWFpbmluZyA8PSAxICkge1xuXHRcdFx0YWRvcHRWYWx1ZSggc2luZ2xlVmFsdWUsIG1hc3Rlci5kb25lKCB1cGRhdGVGdW5jKCBpICkgKS5yZXNvbHZlLCBtYXN0ZXIucmVqZWN0LFxuXHRcdFx0XHQhcmVtYWluaW5nICk7XG5cblx0XHRcdC8vIFVzZSAudGhlbigpIHRvIHVud3JhcCBzZWNvbmRhcnkgdGhlbmFibGVzIChjZi4gZ2gtMzAwMClcblx0XHRcdGlmICggbWFzdGVyLnN0YXRlKCkgPT09IFwicGVuZGluZ1wiIHx8XG5cdFx0XHRcdGlzRnVuY3Rpb24oIHJlc29sdmVWYWx1ZXNbIGkgXSAmJiByZXNvbHZlVmFsdWVzWyBpIF0udGhlbiApICkge1xuXG5cdFx0XHRcdHJldHVybiBtYXN0ZXIudGhlbigpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIE11bHRpcGxlIGFyZ3VtZW50cyBhcmUgYWdncmVnYXRlZCBsaWtlIFByb21pc2UuYWxsIGFycmF5IGVsZW1lbnRzXG5cdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRhZG9wdFZhbHVlKCByZXNvbHZlVmFsdWVzWyBpIF0sIHVwZGF0ZUZ1bmMoIGkgKSwgbWFzdGVyLnJlamVjdCApO1xuXHRcdH1cblxuXHRcdHJldHVybiBtYXN0ZXIucHJvbWlzZSgpO1xuXHR9XG59ICk7XG5cblxuLy8gVGhlc2UgdXN1YWxseSBpbmRpY2F0ZSBhIHByb2dyYW1tZXIgbWlzdGFrZSBkdXJpbmcgZGV2ZWxvcG1lbnQsXG4vLyB3YXJuIGFib3V0IHRoZW0gQVNBUCByYXRoZXIgdGhhbiBzd2FsbG93aW5nIHRoZW0gYnkgZGVmYXVsdC5cbnZhciByZXJyb3JOYW1lcyA9IC9eKEV2YWx8SW50ZXJuYWx8UmFuZ2V8UmVmZXJlbmNlfFN5bnRheHxUeXBlfFVSSSlFcnJvciQvO1xuXG5qUXVlcnkuRGVmZXJyZWQuZXhjZXB0aW9uSG9vayA9IGZ1bmN0aW9uKCBlcnJvciwgc3RhY2sgKSB7XG5cblx0Ly8gU3VwcG9ydDogSUUgOCAtIDkgb25seVxuXHQvLyBDb25zb2xlIGV4aXN0cyB3aGVuIGRldiB0b29scyBhcmUgb3Blbiwgd2hpY2ggY2FuIGhhcHBlbiBhdCBhbnkgdGltZVxuXHRpZiAoIHdpbmRvdy5jb25zb2xlICYmIHdpbmRvdy5jb25zb2xlLndhcm4gJiYgZXJyb3IgJiYgcmVycm9yTmFtZXMudGVzdCggZXJyb3IubmFtZSApICkge1xuXHRcdHdpbmRvdy5jb25zb2xlLndhcm4oIFwialF1ZXJ5LkRlZmVycmVkIGV4Y2VwdGlvbjogXCIgKyBlcnJvci5tZXNzYWdlLCBlcnJvci5zdGFjaywgc3RhY2sgKTtcblx0fVxufTtcblxuXG5cblxualF1ZXJ5LnJlYWR5RXhjZXB0aW9uID0gZnVuY3Rpb24oIGVycm9yICkge1xuXHR3aW5kb3cuc2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cdFx0dGhyb3cgZXJyb3I7XG5cdH0gKTtcbn07XG5cblxuXG5cbi8vIFRoZSBkZWZlcnJlZCB1c2VkIG9uIERPTSByZWFkeVxudmFyIHJlYWR5TGlzdCA9IGpRdWVyeS5EZWZlcnJlZCgpO1xuXG5qUXVlcnkuZm4ucmVhZHkgPSBmdW5jdGlvbiggZm4gKSB7XG5cblx0cmVhZHlMaXN0XG5cdFx0LnRoZW4oIGZuIClcblxuXHRcdC8vIFdyYXAgalF1ZXJ5LnJlYWR5RXhjZXB0aW9uIGluIGEgZnVuY3Rpb24gc28gdGhhdCB0aGUgbG9va3VwXG5cdFx0Ly8gaGFwcGVucyBhdCB0aGUgdGltZSBvZiBlcnJvciBoYW5kbGluZyBpbnN0ZWFkIG9mIGNhbGxiYWNrXG5cdFx0Ly8gcmVnaXN0cmF0aW9uLlxuXHRcdC5jYXRjaCggZnVuY3Rpb24oIGVycm9yICkge1xuXHRcdFx0alF1ZXJ5LnJlYWR5RXhjZXB0aW9uKCBlcnJvciApO1xuXHRcdH0gKTtcblxuXHRyZXR1cm4gdGhpcztcbn07XG5cbmpRdWVyeS5leHRlbmQoIHtcblxuXHQvLyBJcyB0aGUgRE9NIHJlYWR5IHRvIGJlIHVzZWQ/IFNldCB0byB0cnVlIG9uY2UgaXQgb2NjdXJzLlxuXHRpc1JlYWR5OiBmYWxzZSxcblxuXHQvLyBBIGNvdW50ZXIgdG8gdHJhY2sgaG93IG1hbnkgaXRlbXMgdG8gd2FpdCBmb3IgYmVmb3JlXG5cdC8vIHRoZSByZWFkeSBldmVudCBmaXJlcy4gU2VlICM2NzgxXG5cdHJlYWR5V2FpdDogMSxcblxuXHQvLyBIYW5kbGUgd2hlbiB0aGUgRE9NIGlzIHJlYWR5XG5cdHJlYWR5OiBmdW5jdGlvbiggd2FpdCApIHtcblxuXHRcdC8vIEFib3J0IGlmIHRoZXJlIGFyZSBwZW5kaW5nIGhvbGRzIG9yIHdlJ3JlIGFscmVhZHkgcmVhZHlcblx0XHRpZiAoIHdhaXQgPT09IHRydWUgPyAtLWpRdWVyeS5yZWFkeVdhaXQgOiBqUXVlcnkuaXNSZWFkeSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBSZW1lbWJlciB0aGF0IHRoZSBET00gaXMgcmVhZHlcblx0XHRqUXVlcnkuaXNSZWFkeSA9IHRydWU7XG5cblx0XHQvLyBJZiBhIG5vcm1hbCBET00gUmVhZHkgZXZlbnQgZmlyZWQsIGRlY3JlbWVudCwgYW5kIHdhaXQgaWYgbmVlZCBiZVxuXHRcdGlmICggd2FpdCAhPT0gdHJ1ZSAmJiAtLWpRdWVyeS5yZWFkeVdhaXQgPiAwICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIElmIHRoZXJlIGFyZSBmdW5jdGlvbnMgYm91bmQsIHRvIGV4ZWN1dGVcblx0XHRyZWFkeUxpc3QucmVzb2x2ZVdpdGgoIGRvY3VtZW50LCBbIGpRdWVyeSBdICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LnJlYWR5LnRoZW4gPSByZWFkeUxpc3QudGhlbjtcblxuLy8gVGhlIHJlYWR5IGV2ZW50IGhhbmRsZXIgYW5kIHNlbGYgY2xlYW51cCBtZXRob2RcbmZ1bmN0aW9uIGNvbXBsZXRlZCgpIHtcblx0ZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lciggXCJET01Db250ZW50TG9hZGVkXCIsIGNvbXBsZXRlZCApO1xuXHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggXCJsb2FkXCIsIGNvbXBsZXRlZCApO1xuXHRqUXVlcnkucmVhZHkoKTtcbn1cblxuLy8gQ2F0Y2ggY2FzZXMgd2hlcmUgJChkb2N1bWVudCkucmVhZHkoKSBpcyBjYWxsZWRcbi8vIGFmdGVyIHRoZSBicm93c2VyIGV2ZW50IGhhcyBhbHJlYWR5IG9jY3VycmVkLlxuLy8gU3VwcG9ydDogSUUgPD05IC0gMTAgb25seVxuLy8gT2xkZXIgSUUgc29tZXRpbWVzIHNpZ25hbHMgXCJpbnRlcmFjdGl2ZVwiIHRvbyBzb29uXG5pZiAoIGRvY3VtZW50LnJlYWR5U3RhdGUgPT09IFwiY29tcGxldGVcIiB8fFxuXHQoIGRvY3VtZW50LnJlYWR5U3RhdGUgIT09IFwibG9hZGluZ1wiICYmICFkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuZG9TY3JvbGwgKSApIHtcblxuXHQvLyBIYW5kbGUgaXQgYXN5bmNocm9ub3VzbHkgdG8gYWxsb3cgc2NyaXB0cyB0aGUgb3Bwb3J0dW5pdHkgdG8gZGVsYXkgcmVhZHlcblx0d2luZG93LnNldFRpbWVvdXQoIGpRdWVyeS5yZWFkeSApO1xuXG59IGVsc2Uge1xuXG5cdC8vIFVzZSB0aGUgaGFuZHkgZXZlbnQgY2FsbGJhY2tcblx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggXCJET01Db250ZW50TG9hZGVkXCIsIGNvbXBsZXRlZCApO1xuXG5cdC8vIEEgZmFsbGJhY2sgdG8gd2luZG93Lm9ubG9hZCwgdGhhdCB3aWxsIGFsd2F5cyB3b3JrXG5cdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCBcImxvYWRcIiwgY29tcGxldGVkICk7XG59XG5cblxuXG5cbi8vIE11bHRpZnVuY3Rpb25hbCBtZXRob2QgdG8gZ2V0IGFuZCBzZXQgdmFsdWVzIG9mIGEgY29sbGVjdGlvblxuLy8gVGhlIHZhbHVlL3MgY2FuIG9wdGlvbmFsbHkgYmUgZXhlY3V0ZWQgaWYgaXQncyBhIGZ1bmN0aW9uXG52YXIgYWNjZXNzID0gZnVuY3Rpb24oIGVsZW1zLCBmbiwga2V5LCB2YWx1ZSwgY2hhaW5hYmxlLCBlbXB0eUdldCwgcmF3ICkge1xuXHR2YXIgaSA9IDAsXG5cdFx0bGVuID0gZWxlbXMubGVuZ3RoLFxuXHRcdGJ1bGsgPSBrZXkgPT0gbnVsbDtcblxuXHQvLyBTZXRzIG1hbnkgdmFsdWVzXG5cdGlmICggdG9UeXBlKCBrZXkgKSA9PT0gXCJvYmplY3RcIiApIHtcblx0XHRjaGFpbmFibGUgPSB0cnVlO1xuXHRcdGZvciAoIGkgaW4ga2V5ICkge1xuXHRcdFx0YWNjZXNzKCBlbGVtcywgZm4sIGksIGtleVsgaSBdLCB0cnVlLCBlbXB0eUdldCwgcmF3ICk7XG5cdFx0fVxuXG5cdC8vIFNldHMgb25lIHZhbHVlXG5cdH0gZWxzZSBpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0Y2hhaW5hYmxlID0gdHJ1ZTtcblxuXHRcdGlmICggIWlzRnVuY3Rpb24oIHZhbHVlICkgKSB7XG5cdFx0XHRyYXcgPSB0cnVlO1xuXHRcdH1cblxuXHRcdGlmICggYnVsayApIHtcblxuXHRcdFx0Ly8gQnVsayBvcGVyYXRpb25zIHJ1biBhZ2FpbnN0IHRoZSBlbnRpcmUgc2V0XG5cdFx0XHRpZiAoIHJhdyApIHtcblx0XHRcdFx0Zm4uY2FsbCggZWxlbXMsIHZhbHVlICk7XG5cdFx0XHRcdGZuID0gbnVsbDtcblxuXHRcdFx0Ly8gLi4uZXhjZXB0IHdoZW4gZXhlY3V0aW5nIGZ1bmN0aW9uIHZhbHVlc1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0YnVsayA9IGZuO1xuXHRcdFx0XHRmbiA9IGZ1bmN0aW9uKCBlbGVtLCBrZXksIHZhbHVlICkge1xuXHRcdFx0XHRcdHJldHVybiBidWxrLmNhbGwoIGpRdWVyeSggZWxlbSApLCB2YWx1ZSApO1xuXHRcdFx0XHR9O1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggZm4gKSB7XG5cdFx0XHRmb3IgKCA7IGkgPCBsZW47IGkrKyApIHtcblx0XHRcdFx0Zm4oXG5cdFx0XHRcdFx0ZWxlbXNbIGkgXSwga2V5LCByYXcgP1xuXHRcdFx0XHRcdHZhbHVlIDpcblx0XHRcdFx0XHR2YWx1ZS5jYWxsKCBlbGVtc1sgaSBdLCBpLCBmbiggZWxlbXNbIGkgXSwga2V5ICkgKVxuXHRcdFx0XHQpO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdGlmICggY2hhaW5hYmxlICkge1xuXHRcdHJldHVybiBlbGVtcztcblx0fVxuXG5cdC8vIEdldHNcblx0aWYgKCBidWxrICkge1xuXHRcdHJldHVybiBmbi5jYWxsKCBlbGVtcyApO1xuXHR9XG5cblx0cmV0dXJuIGxlbiA/IGZuKCBlbGVtc1sgMCBdLCBrZXkgKSA6IGVtcHR5R2V0O1xufTtcblxuXG4vLyBNYXRjaGVzIGRhc2hlZCBzdHJpbmcgZm9yIGNhbWVsaXppbmdcbnZhciBybXNQcmVmaXggPSAvXi1tcy0vLFxuXHRyZGFzaEFscGhhID0gLy0oW2Etel0pL2c7XG5cbi8vIFVzZWQgYnkgY2FtZWxDYXNlIGFzIGNhbGxiYWNrIHRvIHJlcGxhY2UoKVxuZnVuY3Rpb24gZmNhbWVsQ2FzZSggYWxsLCBsZXR0ZXIgKSB7XG5cdHJldHVybiBsZXR0ZXIudG9VcHBlckNhc2UoKTtcbn1cblxuLy8gQ29udmVydCBkYXNoZWQgdG8gY2FtZWxDYXNlOyB1c2VkIGJ5IHRoZSBjc3MgYW5kIGRhdGEgbW9kdWxlc1xuLy8gU3VwcG9ydDogSUUgPD05IC0gMTEsIEVkZ2UgMTIgLSAxNVxuLy8gTWljcm9zb2Z0IGZvcmdvdCB0byBodW1wIHRoZWlyIHZlbmRvciBwcmVmaXggKCM5NTcyKVxuZnVuY3Rpb24gY2FtZWxDYXNlKCBzdHJpbmcgKSB7XG5cdHJldHVybiBzdHJpbmcucmVwbGFjZSggcm1zUHJlZml4LCBcIm1zLVwiICkucmVwbGFjZSggcmRhc2hBbHBoYSwgZmNhbWVsQ2FzZSApO1xufVxudmFyIGFjY2VwdERhdGEgPSBmdW5jdGlvbiggb3duZXIgKSB7XG5cblx0Ly8gQWNjZXB0cyBvbmx5OlxuXHQvLyAgLSBOb2RlXG5cdC8vICAgIC0gTm9kZS5FTEVNRU5UX05PREVcblx0Ly8gICAgLSBOb2RlLkRPQ1VNRU5UX05PREVcblx0Ly8gIC0gT2JqZWN0XG5cdC8vICAgIC0gQW55XG5cdHJldHVybiBvd25lci5ub2RlVHlwZSA9PT0gMSB8fCBvd25lci5ub2RlVHlwZSA9PT0gOSB8fCAhKCArb3duZXIubm9kZVR5cGUgKTtcbn07XG5cblxuXG5cbmZ1bmN0aW9uIERhdGEoKSB7XG5cdHRoaXMuZXhwYW5kbyA9IGpRdWVyeS5leHBhbmRvICsgRGF0YS51aWQrKztcbn1cblxuRGF0YS51aWQgPSAxO1xuXG5EYXRhLnByb3RvdHlwZSA9IHtcblxuXHRjYWNoZTogZnVuY3Rpb24oIG93bmVyICkge1xuXG5cdFx0Ly8gQ2hlY2sgaWYgdGhlIG93bmVyIG9iamVjdCBhbHJlYWR5IGhhcyBhIGNhY2hlXG5cdFx0dmFyIHZhbHVlID0gb3duZXJbIHRoaXMuZXhwYW5kbyBdO1xuXG5cdFx0Ly8gSWYgbm90LCBjcmVhdGUgb25lXG5cdFx0aWYgKCAhdmFsdWUgKSB7XG5cdFx0XHR2YWx1ZSA9IHt9O1xuXG5cdFx0XHQvLyBXZSBjYW4gYWNjZXB0IGRhdGEgZm9yIG5vbi1lbGVtZW50IG5vZGVzIGluIG1vZGVybiBicm93c2Vycyxcblx0XHRcdC8vIGJ1dCB3ZSBzaG91bGQgbm90LCBzZWUgIzgzMzUuXG5cdFx0XHQvLyBBbHdheXMgcmV0dXJuIGFuIGVtcHR5IG9iamVjdC5cblx0XHRcdGlmICggYWNjZXB0RGF0YSggb3duZXIgKSApIHtcblxuXHRcdFx0XHQvLyBJZiBpdCBpcyBhIG5vZGUgdW5saWtlbHkgdG8gYmUgc3RyaW5naWZ5LWVkIG9yIGxvb3BlZCBvdmVyXG5cdFx0XHRcdC8vIHVzZSBwbGFpbiBhc3NpZ25tZW50XG5cdFx0XHRcdGlmICggb3duZXIubm9kZVR5cGUgKSB7XG5cdFx0XHRcdFx0b3duZXJbIHRoaXMuZXhwYW5kbyBdID0gdmFsdWU7XG5cblx0XHRcdFx0Ly8gT3RoZXJ3aXNlIHNlY3VyZSBpdCBpbiBhIG5vbi1lbnVtZXJhYmxlIHByb3BlcnR5XG5cdFx0XHRcdC8vIGNvbmZpZ3VyYWJsZSBtdXN0IGJlIHRydWUgdG8gYWxsb3cgdGhlIHByb3BlcnR5IHRvIGJlXG5cdFx0XHRcdC8vIGRlbGV0ZWQgd2hlbiBkYXRhIGlzIHJlbW92ZWRcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIG93bmVyLCB0aGlzLmV4cGFuZG8sIHtcblx0XHRcdFx0XHRcdHZhbHVlOiB2YWx1ZSxcblx0XHRcdFx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZVxuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB2YWx1ZTtcblx0fSxcblx0c2V0OiBmdW5jdGlvbiggb3duZXIsIGRhdGEsIHZhbHVlICkge1xuXHRcdHZhciBwcm9wLFxuXHRcdFx0Y2FjaGUgPSB0aGlzLmNhY2hlKCBvd25lciApO1xuXG5cdFx0Ly8gSGFuZGxlOiBbIG93bmVyLCBrZXksIHZhbHVlIF0gYXJnc1xuXHRcdC8vIEFsd2F5cyB1c2UgY2FtZWxDYXNlIGtleSAoZ2gtMjI1Nylcblx0XHRpZiAoIHR5cGVvZiBkYXRhID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0Y2FjaGVbIGNhbWVsQ2FzZSggZGF0YSApIF0gPSB2YWx1ZTtcblxuXHRcdC8vIEhhbmRsZTogWyBvd25lciwgeyBwcm9wZXJ0aWVzIH0gXSBhcmdzXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gQ29weSB0aGUgcHJvcGVydGllcyBvbmUtYnktb25lIHRvIHRoZSBjYWNoZSBvYmplY3Rcblx0XHRcdGZvciAoIHByb3AgaW4gZGF0YSApIHtcblx0XHRcdFx0Y2FjaGVbIGNhbWVsQ2FzZSggcHJvcCApIF0gPSBkYXRhWyBwcm9wIF07XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBjYWNoZTtcblx0fSxcblx0Z2V0OiBmdW5jdGlvbiggb3duZXIsIGtleSApIHtcblx0XHRyZXR1cm4ga2V5ID09PSB1bmRlZmluZWQgP1xuXHRcdFx0dGhpcy5jYWNoZSggb3duZXIgKSA6XG5cblx0XHRcdC8vIEFsd2F5cyB1c2UgY2FtZWxDYXNlIGtleSAoZ2gtMjI1Nylcblx0XHRcdG93bmVyWyB0aGlzLmV4cGFuZG8gXSAmJiBvd25lclsgdGhpcy5leHBhbmRvIF1bIGNhbWVsQ2FzZSgga2V5ICkgXTtcblx0fSxcblx0YWNjZXNzOiBmdW5jdGlvbiggb3duZXIsIGtleSwgdmFsdWUgKSB7XG5cblx0XHQvLyBJbiBjYXNlcyB3aGVyZSBlaXRoZXI6XG5cdFx0Ly9cblx0XHQvLyAgIDEuIE5vIGtleSB3YXMgc3BlY2lmaWVkXG5cdFx0Ly8gICAyLiBBIHN0cmluZyBrZXkgd2FzIHNwZWNpZmllZCwgYnV0IG5vIHZhbHVlIHByb3ZpZGVkXG5cdFx0Ly9cblx0XHQvLyBUYWtlIHRoZSBcInJlYWRcIiBwYXRoIGFuZCBhbGxvdyB0aGUgZ2V0IG1ldGhvZCB0byBkZXRlcm1pbmVcblx0XHQvLyB3aGljaCB2YWx1ZSB0byByZXR1cm4sIHJlc3BlY3RpdmVseSBlaXRoZXI6XG5cdFx0Ly9cblx0XHQvLyAgIDEuIFRoZSBlbnRpcmUgY2FjaGUgb2JqZWN0XG5cdFx0Ly8gICAyLiBUaGUgZGF0YSBzdG9yZWQgYXQgdGhlIGtleVxuXHRcdC8vXG5cdFx0aWYgKCBrZXkgPT09IHVuZGVmaW5lZCB8fFxuXHRcdFx0XHQoICgga2V5ICYmIHR5cGVvZiBrZXkgPT09IFwic3RyaW5nXCIgKSAmJiB2YWx1ZSA9PT0gdW5kZWZpbmVkICkgKSB7XG5cblx0XHRcdHJldHVybiB0aGlzLmdldCggb3duZXIsIGtleSApO1xuXHRcdH1cblxuXHRcdC8vIFdoZW4gdGhlIGtleSBpcyBub3QgYSBzdHJpbmcsIG9yIGJvdGggYSBrZXkgYW5kIHZhbHVlXG5cdFx0Ly8gYXJlIHNwZWNpZmllZCwgc2V0IG9yIGV4dGVuZCAoZXhpc3Rpbmcgb2JqZWN0cykgd2l0aCBlaXRoZXI6XG5cdFx0Ly9cblx0XHQvLyAgIDEuIEFuIG9iamVjdCBvZiBwcm9wZXJ0aWVzXG5cdFx0Ly8gICAyLiBBIGtleSBhbmQgdmFsdWVcblx0XHQvL1xuXHRcdHRoaXMuc2V0KCBvd25lciwga2V5LCB2YWx1ZSApO1xuXG5cdFx0Ly8gU2luY2UgdGhlIFwic2V0XCIgcGF0aCBjYW4gaGF2ZSB0d28gcG9zc2libGUgZW50cnkgcG9pbnRzXG5cdFx0Ly8gcmV0dXJuIHRoZSBleHBlY3RlZCBkYXRhIGJhc2VkIG9uIHdoaWNoIHBhdGggd2FzIHRha2VuWypdXG5cdFx0cmV0dXJuIHZhbHVlICE9PSB1bmRlZmluZWQgPyB2YWx1ZSA6IGtleTtcblx0fSxcblx0cmVtb3ZlOiBmdW5jdGlvbiggb3duZXIsIGtleSApIHtcblx0XHR2YXIgaSxcblx0XHRcdGNhY2hlID0gb3duZXJbIHRoaXMuZXhwYW5kbyBdO1xuXG5cdFx0aWYgKCBjYWNoZSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIFN1cHBvcnQgYXJyYXkgb3Igc3BhY2Ugc2VwYXJhdGVkIHN0cmluZyBvZiBrZXlzXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGtleSApICkge1xuXG5cdFx0XHRcdC8vIElmIGtleSBpcyBhbiBhcnJheSBvZiBrZXlzLi4uXG5cdFx0XHRcdC8vIFdlIGFsd2F5cyBzZXQgY2FtZWxDYXNlIGtleXMsIHNvIHJlbW92ZSB0aGF0LlxuXHRcdFx0XHRrZXkgPSBrZXkubWFwKCBjYW1lbENhc2UgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGtleSA9IGNhbWVsQ2FzZSgga2V5ICk7XG5cblx0XHRcdFx0Ly8gSWYgYSBrZXkgd2l0aCB0aGUgc3BhY2VzIGV4aXN0cywgdXNlIGl0LlxuXHRcdFx0XHQvLyBPdGhlcndpc2UsIGNyZWF0ZSBhbiBhcnJheSBieSBtYXRjaGluZyBub24td2hpdGVzcGFjZVxuXHRcdFx0XHRrZXkgPSBrZXkgaW4gY2FjaGUgP1xuXHRcdFx0XHRcdFsga2V5IF0gOlxuXHRcdFx0XHRcdCgga2V5Lm1hdGNoKCBybm90aHRtbHdoaXRlICkgfHwgW10gKTtcblx0XHRcdH1cblxuXHRcdFx0aSA9IGtleS5sZW5ndGg7XG5cblx0XHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0XHRkZWxldGUgY2FjaGVbIGtleVsgaSBdIF07XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gUmVtb3ZlIHRoZSBleHBhbmRvIGlmIHRoZXJlJ3Mgbm8gbW9yZSBkYXRhXG5cdFx0aWYgKCBrZXkgPT09IHVuZGVmaW5lZCB8fCBqUXVlcnkuaXNFbXB0eU9iamVjdCggY2FjaGUgKSApIHtcblxuXHRcdFx0Ly8gU3VwcG9ydDogQ2hyb21lIDw9MzUgLSA0NVxuXHRcdFx0Ly8gV2Via2l0ICYgQmxpbmsgcGVyZm9ybWFuY2Ugc3VmZmVycyB3aGVuIGRlbGV0aW5nIHByb3BlcnRpZXNcblx0XHRcdC8vIGZyb20gRE9NIG5vZGVzLCBzbyBzZXQgdG8gdW5kZWZpbmVkIGluc3RlYWRcblx0XHRcdC8vIGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTM3ODYwNyAoYnVnIHJlc3RyaWN0ZWQpXG5cdFx0XHRpZiAoIG93bmVyLm5vZGVUeXBlICkge1xuXHRcdFx0XHRvd25lclsgdGhpcy5leHBhbmRvIF0gPSB1bmRlZmluZWQ7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRkZWxldGUgb3duZXJbIHRoaXMuZXhwYW5kbyBdO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblx0aGFzRGF0YTogZnVuY3Rpb24oIG93bmVyICkge1xuXHRcdHZhciBjYWNoZSA9IG93bmVyWyB0aGlzLmV4cGFuZG8gXTtcblx0XHRyZXR1cm4gY2FjaGUgIT09IHVuZGVmaW5lZCAmJiAhalF1ZXJ5LmlzRW1wdHlPYmplY3QoIGNhY2hlICk7XG5cdH1cbn07XG52YXIgZGF0YVByaXYgPSBuZXcgRGF0YSgpO1xuXG52YXIgZGF0YVVzZXIgPSBuZXcgRGF0YSgpO1xuXG5cblxuLy9cdEltcGxlbWVudGF0aW9uIFN1bW1hcnlcbi8vXG4vL1x0MS4gRW5mb3JjZSBBUEkgc3VyZmFjZSBhbmQgc2VtYW50aWMgY29tcGF0aWJpbGl0eSB3aXRoIDEuOS54IGJyYW5jaFxuLy9cdDIuIEltcHJvdmUgdGhlIG1vZHVsZSdzIG1haW50YWluYWJpbGl0eSBieSByZWR1Y2luZyB0aGUgc3RvcmFnZVxuLy9cdFx0cGF0aHMgdG8gYSBzaW5nbGUgbWVjaGFuaXNtLlxuLy9cdDMuIFVzZSB0aGUgc2FtZSBzaW5nbGUgbWVjaGFuaXNtIHRvIHN1cHBvcnQgXCJwcml2YXRlXCIgYW5kIFwidXNlclwiIGRhdGEuXG4vL1x0NC4gX05ldmVyXyBleHBvc2UgXCJwcml2YXRlXCIgZGF0YSB0byB1c2VyIGNvZGUgKFRPRE86IERyb3AgX2RhdGEsIF9yZW1vdmVEYXRhKVxuLy9cdDUuIEF2b2lkIGV4cG9zaW5nIGltcGxlbWVudGF0aW9uIGRldGFpbHMgb24gdXNlciBvYmplY3RzIChlZy4gZXhwYW5kbyBwcm9wZXJ0aWVzKVxuLy9cdDYuIFByb3ZpZGUgYSBjbGVhciBwYXRoIGZvciBpbXBsZW1lbnRhdGlvbiB1cGdyYWRlIHRvIFdlYWtNYXAgaW4gMjAxNFxuXG52YXIgcmJyYWNlID0gL14oPzpcXHtbXFx3XFxXXSpcXH18XFxbW1xcd1xcV10qXFxdKSQvLFxuXHRybXVsdGlEYXNoID0gL1tBLVpdL2c7XG5cbmZ1bmN0aW9uIGdldERhdGEoIGRhdGEgKSB7XG5cdGlmICggZGF0YSA9PT0gXCJ0cnVlXCIgKSB7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cblxuXHRpZiAoIGRhdGEgPT09IFwiZmFsc2VcIiApIHtcblx0XHRyZXR1cm4gZmFsc2U7XG5cdH1cblxuXHRpZiAoIGRhdGEgPT09IFwibnVsbFwiICkge1xuXHRcdHJldHVybiBudWxsO1xuXHR9XG5cblx0Ly8gT25seSBjb252ZXJ0IHRvIGEgbnVtYmVyIGlmIGl0IGRvZXNuJ3QgY2hhbmdlIHRoZSBzdHJpbmdcblx0aWYgKCBkYXRhID09PSArZGF0YSArIFwiXCIgKSB7XG5cdFx0cmV0dXJuICtkYXRhO1xuXHR9XG5cblx0aWYgKCByYnJhY2UudGVzdCggZGF0YSApICkge1xuXHRcdHJldHVybiBKU09OLnBhcnNlKCBkYXRhICk7XG5cdH1cblxuXHRyZXR1cm4gZGF0YTtcbn1cblxuZnVuY3Rpb24gZGF0YUF0dHIoIGVsZW0sIGtleSwgZGF0YSApIHtcblx0dmFyIG5hbWU7XG5cblx0Ly8gSWYgbm90aGluZyB3YXMgZm91bmQgaW50ZXJuYWxseSwgdHJ5IHRvIGZldGNoIGFueVxuXHQvLyBkYXRhIGZyb20gdGhlIEhUTUw1IGRhdGEtKiBhdHRyaWJ1dGVcblx0aWYgKCBkYXRhID09PSB1bmRlZmluZWQgJiYgZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblx0XHRuYW1lID0gXCJkYXRhLVwiICsga2V5LnJlcGxhY2UoIHJtdWx0aURhc2gsIFwiLSQmXCIgKS50b0xvd2VyQ2FzZSgpO1xuXHRcdGRhdGEgPSBlbGVtLmdldEF0dHJpYnV0ZSggbmFtZSApO1xuXG5cdFx0aWYgKCB0eXBlb2YgZGF0YSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdGRhdGEgPSBnZXREYXRhKCBkYXRhICk7XG5cdFx0XHR9IGNhdGNoICggZSApIHt9XG5cblx0XHRcdC8vIE1ha2Ugc3VyZSB3ZSBzZXQgdGhlIGRhdGEgc28gaXQgaXNuJ3QgY2hhbmdlZCBsYXRlclxuXHRcdFx0ZGF0YVVzZXIuc2V0KCBlbGVtLCBrZXksIGRhdGEgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZGF0YSA9IHVuZGVmaW5lZDtcblx0XHR9XG5cdH1cblx0cmV0dXJuIGRhdGE7XG59XG5cbmpRdWVyeS5leHRlbmQoIHtcblx0aGFzRGF0YTogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0cmV0dXJuIGRhdGFVc2VyLmhhc0RhdGEoIGVsZW0gKSB8fCBkYXRhUHJpdi5oYXNEYXRhKCBlbGVtICk7XG5cdH0sXG5cblx0ZGF0YTogZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGRhdGEgKSB7XG5cdFx0cmV0dXJuIGRhdGFVc2VyLmFjY2VzcyggZWxlbSwgbmFtZSwgZGF0YSApO1xuXHR9LFxuXG5cdHJlbW92ZURhdGE6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lICkge1xuXHRcdGRhdGFVc2VyLnJlbW92ZSggZWxlbSwgbmFtZSApO1xuXHR9LFxuXG5cdC8vIFRPRE86IE5vdyB0aGF0IGFsbCBjYWxscyB0byBfZGF0YSBhbmQgX3JlbW92ZURhdGEgaGF2ZSBiZWVuIHJlcGxhY2VkXG5cdC8vIHdpdGggZGlyZWN0IGNhbGxzIHRvIGRhdGFQcml2IG1ldGhvZHMsIHRoZXNlIGNhbiBiZSBkZXByZWNhdGVkLlxuXHRfZGF0YTogZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGRhdGEgKSB7XG5cdFx0cmV0dXJuIGRhdGFQcml2LmFjY2VzcyggZWxlbSwgbmFtZSwgZGF0YSApO1xuXHR9LFxuXG5cdF9yZW1vdmVEYXRhOiBmdW5jdGlvbiggZWxlbSwgbmFtZSApIHtcblx0XHRkYXRhUHJpdi5yZW1vdmUoIGVsZW0sIG5hbWUgKTtcblx0fVxufSApO1xuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdGRhdGE6IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHZhciBpLCBuYW1lLCBkYXRhLFxuXHRcdFx0ZWxlbSA9IHRoaXNbIDAgXSxcblx0XHRcdGF0dHJzID0gZWxlbSAmJiBlbGVtLmF0dHJpYnV0ZXM7XG5cblx0XHQvLyBHZXRzIGFsbCB2YWx1ZXNcblx0XHRpZiAoIGtleSA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0aWYgKCB0aGlzLmxlbmd0aCApIHtcblx0XHRcdFx0ZGF0YSA9IGRhdGFVc2VyLmdldCggZWxlbSApO1xuXG5cdFx0XHRcdGlmICggZWxlbS5ub2RlVHlwZSA9PT0gMSAmJiAhZGF0YVByaXYuZ2V0KCBlbGVtLCBcImhhc0RhdGFBdHRyc1wiICkgKSB7XG5cdFx0XHRcdFx0aSA9IGF0dHJzLmxlbmd0aDtcblx0XHRcdFx0XHR3aGlsZSAoIGktLSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgMTEgb25seVxuXHRcdFx0XHRcdFx0Ly8gVGhlIGF0dHJzIGVsZW1lbnRzIGNhbiBiZSBudWxsICgjMTQ4OTQpXG5cdFx0XHRcdFx0XHRpZiAoIGF0dHJzWyBpIF0gKSB7XG5cdFx0XHRcdFx0XHRcdG5hbWUgPSBhdHRyc1sgaSBdLm5hbWU7XG5cdFx0XHRcdFx0XHRcdGlmICggbmFtZS5pbmRleE9mKCBcImRhdGEtXCIgKSA9PT0gMCApIHtcblx0XHRcdFx0XHRcdFx0XHRuYW1lID0gY2FtZWxDYXNlKCBuYW1lLnNsaWNlKCA1ICkgKTtcblx0XHRcdFx0XHRcdFx0XHRkYXRhQXR0ciggZWxlbSwgbmFtZSwgZGF0YVsgbmFtZSBdICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZGF0YVByaXYuc2V0KCBlbGVtLCBcImhhc0RhdGFBdHRyc1wiLCB0cnVlICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGRhdGE7XG5cdFx0fVxuXG5cdFx0Ly8gU2V0cyBtdWx0aXBsZSB2YWx1ZXNcblx0XHRpZiAoIHR5cGVvZiBrZXkgPT09IFwib2JqZWN0XCIgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0ZGF0YVVzZXIuc2V0KCB0aGlzLCBrZXkgKTtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gYWNjZXNzKCB0aGlzLCBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0XHR2YXIgZGF0YTtcblxuXHRcdFx0Ly8gVGhlIGNhbGxpbmcgalF1ZXJ5IG9iamVjdCAoZWxlbWVudCBtYXRjaGVzKSBpcyBub3QgZW1wdHlcblx0XHRcdC8vIChhbmQgdGhlcmVmb3JlIGhhcyBhbiBlbGVtZW50IGFwcGVhcnMgYXQgdGhpc1sgMCBdKSBhbmQgdGhlXG5cdFx0XHQvLyBgdmFsdWVgIHBhcmFtZXRlciB3YXMgbm90IHVuZGVmaW5lZC4gQW4gZW1wdHkgalF1ZXJ5IG9iamVjdFxuXHRcdFx0Ly8gd2lsbCByZXN1bHQgaW4gYHVuZGVmaW5lZGAgZm9yIGVsZW0gPSB0aGlzWyAwIF0gd2hpY2ggd2lsbFxuXHRcdFx0Ly8gdGhyb3cgYW4gZXhjZXB0aW9uIGlmIGFuIGF0dGVtcHQgdG8gcmVhZCBhIGRhdGEgY2FjaGUgaXMgbWFkZS5cblx0XHRcdGlmICggZWxlbSAmJiB2YWx1ZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdC8vIEF0dGVtcHQgdG8gZ2V0IGRhdGEgZnJvbSB0aGUgY2FjaGVcblx0XHRcdFx0Ly8gVGhlIGtleSB3aWxsIGFsd2F5cyBiZSBjYW1lbENhc2VkIGluIERhdGFcblx0XHRcdFx0ZGF0YSA9IGRhdGFVc2VyLmdldCggZWxlbSwga2V5ICk7XG5cdFx0XHRcdGlmICggZGF0YSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdHJldHVybiBkYXRhO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQXR0ZW1wdCB0byBcImRpc2NvdmVyXCIgdGhlIGRhdGEgaW5cblx0XHRcdFx0Ly8gSFRNTDUgY3VzdG9tIGRhdGEtKiBhdHRyc1xuXHRcdFx0XHRkYXRhID0gZGF0YUF0dHIoIGVsZW0sIGtleSApO1xuXHRcdFx0XHRpZiAoIGRhdGEgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRyZXR1cm4gZGF0YTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFdlIHRyaWVkIHJlYWxseSBoYXJkLCBidXQgdGhlIGRhdGEgZG9lc24ndCBleGlzdC5cblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTZXQgdGhlIGRhdGEuLi5cblx0XHRcdHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0Ly8gV2UgYWx3YXlzIHN0b3JlIHRoZSBjYW1lbENhc2VkIGtleVxuXHRcdFx0XHRkYXRhVXNlci5zZXQoIHRoaXMsIGtleSwgdmFsdWUgKTtcblx0XHRcdH0gKTtcblx0XHR9LCBudWxsLCB2YWx1ZSwgYXJndW1lbnRzLmxlbmd0aCA+IDEsIG51bGwsIHRydWUgKTtcblx0fSxcblxuXHRyZW1vdmVEYXRhOiBmdW5jdGlvbigga2V5ICkge1xuXHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0ZGF0YVVzZXIucmVtb3ZlKCB0aGlzLCBrZXkgKTtcblx0XHR9ICk7XG5cdH1cbn0gKTtcblxuXG5qUXVlcnkuZXh0ZW5kKCB7XG5cdHF1ZXVlOiBmdW5jdGlvbiggZWxlbSwgdHlwZSwgZGF0YSApIHtcblx0XHR2YXIgcXVldWU7XG5cblx0XHRpZiAoIGVsZW0gKSB7XG5cdFx0XHR0eXBlID0gKCB0eXBlIHx8IFwiZnhcIiApICsgXCJxdWV1ZVwiO1xuXHRcdFx0cXVldWUgPSBkYXRhUHJpdi5nZXQoIGVsZW0sIHR5cGUgKTtcblxuXHRcdFx0Ly8gU3BlZWQgdXAgZGVxdWV1ZSBieSBnZXR0aW5nIG91dCBxdWlja2x5IGlmIHRoaXMgaXMganVzdCBhIGxvb2t1cFxuXHRcdFx0aWYgKCBkYXRhICkge1xuXHRcdFx0XHRpZiAoICFxdWV1ZSB8fCBBcnJheS5pc0FycmF5KCBkYXRhICkgKSB7XG5cdFx0XHRcdFx0cXVldWUgPSBkYXRhUHJpdi5hY2Nlc3MoIGVsZW0sIHR5cGUsIGpRdWVyeS5tYWtlQXJyYXkoIGRhdGEgKSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHF1ZXVlLnB1c2goIGRhdGEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHF1ZXVlIHx8IFtdO1xuXHRcdH1cblx0fSxcblxuXHRkZXF1ZXVlOiBmdW5jdGlvbiggZWxlbSwgdHlwZSApIHtcblx0XHR0eXBlID0gdHlwZSB8fCBcImZ4XCI7XG5cblx0XHR2YXIgcXVldWUgPSBqUXVlcnkucXVldWUoIGVsZW0sIHR5cGUgKSxcblx0XHRcdHN0YXJ0TGVuZ3RoID0gcXVldWUubGVuZ3RoLFxuXHRcdFx0Zm4gPSBxdWV1ZS5zaGlmdCgpLFxuXHRcdFx0aG9va3MgPSBqUXVlcnkuX3F1ZXVlSG9va3MoIGVsZW0sIHR5cGUgKSxcblx0XHRcdG5leHQgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0alF1ZXJ5LmRlcXVldWUoIGVsZW0sIHR5cGUgKTtcblx0XHRcdH07XG5cblx0XHQvLyBJZiB0aGUgZnggcXVldWUgaXMgZGVxdWV1ZWQsIGFsd2F5cyByZW1vdmUgdGhlIHByb2dyZXNzIHNlbnRpbmVsXG5cdFx0aWYgKCBmbiA9PT0gXCJpbnByb2dyZXNzXCIgKSB7XG5cdFx0XHRmbiA9IHF1ZXVlLnNoaWZ0KCk7XG5cdFx0XHRzdGFydExlbmd0aC0tO1xuXHRcdH1cblxuXHRcdGlmICggZm4gKSB7XG5cblx0XHRcdC8vIEFkZCBhIHByb2dyZXNzIHNlbnRpbmVsIHRvIHByZXZlbnQgdGhlIGZ4IHF1ZXVlIGZyb20gYmVpbmdcblx0XHRcdC8vIGF1dG9tYXRpY2FsbHkgZGVxdWV1ZWRcblx0XHRcdGlmICggdHlwZSA9PT0gXCJmeFwiICkge1xuXHRcdFx0XHRxdWV1ZS51bnNoaWZ0KCBcImlucHJvZ3Jlc3NcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDbGVhciB1cCB0aGUgbGFzdCBxdWV1ZSBzdG9wIGZ1bmN0aW9uXG5cdFx0XHRkZWxldGUgaG9va3Muc3RvcDtcblx0XHRcdGZuLmNhbGwoIGVsZW0sIG5leHQsIGhvb2tzICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhc3RhcnRMZW5ndGggJiYgaG9va3MgKSB7XG5cdFx0XHRob29rcy5lbXB0eS5maXJlKCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIE5vdCBwdWJsaWMgLSBnZW5lcmF0ZSBhIHF1ZXVlSG9va3Mgb2JqZWN0LCBvciByZXR1cm4gdGhlIGN1cnJlbnQgb25lXG5cdF9xdWV1ZUhvb2tzOiBmdW5jdGlvbiggZWxlbSwgdHlwZSApIHtcblx0XHR2YXIga2V5ID0gdHlwZSArIFwicXVldWVIb29rc1wiO1xuXHRcdHJldHVybiBkYXRhUHJpdi5nZXQoIGVsZW0sIGtleSApIHx8IGRhdGFQcml2LmFjY2VzcyggZWxlbSwga2V5LCB7XG5cdFx0XHRlbXB0eTogalF1ZXJ5LkNhbGxiYWNrcyggXCJvbmNlIG1lbW9yeVwiICkuYWRkKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0ZGF0YVByaXYucmVtb3ZlKCBlbGVtLCBbIHR5cGUgKyBcInF1ZXVlXCIsIGtleSBdICk7XG5cdFx0XHR9IClcblx0XHR9ICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHRxdWV1ZTogZnVuY3Rpb24oIHR5cGUsIGRhdGEgKSB7XG5cdFx0dmFyIHNldHRlciA9IDI7XG5cblx0XHRpZiAoIHR5cGVvZiB0eXBlICE9PSBcInN0cmluZ1wiICkge1xuXHRcdFx0ZGF0YSA9IHR5cGU7XG5cdFx0XHR0eXBlID0gXCJmeFwiO1xuXHRcdFx0c2V0dGVyLS07XG5cdFx0fVxuXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoIDwgc2V0dGVyICkge1xuXHRcdFx0cmV0dXJuIGpRdWVyeS5xdWV1ZSggdGhpc1sgMCBdLCB0eXBlICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGEgPT09IHVuZGVmaW5lZCA/XG5cdFx0XHR0aGlzIDpcblx0XHRcdHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBxdWV1ZSA9IGpRdWVyeS5xdWV1ZSggdGhpcywgdHlwZSwgZGF0YSApO1xuXG5cdFx0XHRcdC8vIEVuc3VyZSBhIGhvb2tzIGZvciB0aGlzIHF1ZXVlXG5cdFx0XHRcdGpRdWVyeS5fcXVldWVIb29rcyggdGhpcywgdHlwZSApO1xuXG5cdFx0XHRcdGlmICggdHlwZSA9PT0gXCJmeFwiICYmIHF1ZXVlWyAwIF0gIT09IFwiaW5wcm9ncmVzc1wiICkge1xuXHRcdFx0XHRcdGpRdWVyeS5kZXF1ZXVlKCB0aGlzLCB0eXBlICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0fSxcblx0ZGVxdWV1ZTogZnVuY3Rpb24oIHR5cGUgKSB7XG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRqUXVlcnkuZGVxdWV1ZSggdGhpcywgdHlwZSApO1xuXHRcdH0gKTtcblx0fSxcblx0Y2xlYXJRdWV1ZTogZnVuY3Rpb24oIHR5cGUgKSB7XG5cdFx0cmV0dXJuIHRoaXMucXVldWUoIHR5cGUgfHwgXCJmeFwiLCBbXSApO1xuXHR9LFxuXG5cdC8vIEdldCBhIHByb21pc2UgcmVzb2x2ZWQgd2hlbiBxdWV1ZXMgb2YgYSBjZXJ0YWluIHR5cGVcblx0Ly8gYXJlIGVtcHRpZWQgKGZ4IGlzIHRoZSB0eXBlIGJ5IGRlZmF1bHQpXG5cdHByb21pc2U6IGZ1bmN0aW9uKCB0eXBlLCBvYmogKSB7XG5cdFx0dmFyIHRtcCxcblx0XHRcdGNvdW50ID0gMSxcblx0XHRcdGRlZmVyID0galF1ZXJ5LkRlZmVycmVkKCksXG5cdFx0XHRlbGVtZW50cyA9IHRoaXMsXG5cdFx0XHRpID0gdGhpcy5sZW5ndGgsXG5cdFx0XHRyZXNvbHZlID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggISggLS1jb3VudCApICkge1xuXHRcdFx0XHRcdGRlZmVyLnJlc29sdmVXaXRoKCBlbGVtZW50cywgWyBlbGVtZW50cyBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cblx0XHRpZiAoIHR5cGVvZiB0eXBlICE9PSBcInN0cmluZ1wiICkge1xuXHRcdFx0b2JqID0gdHlwZTtcblx0XHRcdHR5cGUgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHRcdHR5cGUgPSB0eXBlIHx8IFwiZnhcIjtcblxuXHRcdHdoaWxlICggaS0tICkge1xuXHRcdFx0dG1wID0gZGF0YVByaXYuZ2V0KCBlbGVtZW50c1sgaSBdLCB0eXBlICsgXCJxdWV1ZUhvb2tzXCIgKTtcblx0XHRcdGlmICggdG1wICYmIHRtcC5lbXB0eSApIHtcblx0XHRcdFx0Y291bnQrKztcblx0XHRcdFx0dG1wLmVtcHR5LmFkZCggcmVzb2x2ZSApO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXNvbHZlKCk7XG5cdFx0cmV0dXJuIGRlZmVyLnByb21pc2UoIG9iaiApO1xuXHR9XG59ICk7XG52YXIgcG51bSA9ICggL1srLV0/KD86XFxkKlxcLnwpXFxkKyg/OltlRV1bKy1dP1xcZCt8KS8gKS5zb3VyY2U7XG5cbnZhciByY3NzTnVtID0gbmV3IFJlZ0V4cCggXCJeKD86KFsrLV0pPXwpKFwiICsgcG51bSArIFwiKShbYS16JV0qKSRcIiwgXCJpXCIgKTtcblxuXG52YXIgY3NzRXhwYW5kID0gWyBcIlRvcFwiLCBcIlJpZ2h0XCIsIFwiQm90dG9tXCIsIFwiTGVmdFwiIF07XG5cbnZhciBkb2N1bWVudEVsZW1lbnQgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQ7XG5cblxuXG5cdHZhciBpc0F0dGFjaGVkID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4galF1ZXJ5LmNvbnRhaW5zKCBlbGVtLm93bmVyRG9jdW1lbnQsIGVsZW0gKTtcblx0XHR9LFxuXHRcdGNvbXBvc2VkID0geyBjb21wb3NlZDogdHJ1ZSB9O1xuXG5cdC8vIFN1cHBvcnQ6IElFIDkgLSAxMSssIEVkZ2UgMTIgLSAxOCssIGlPUyAxMC4wIC0gMTAuMiBvbmx5XG5cdC8vIENoZWNrIGF0dGFjaG1lbnQgYWNyb3NzIHNoYWRvdyBET00gYm91bmRhcmllcyB3aGVuIHBvc3NpYmxlIChnaC0zNTA0KVxuXHQvLyBTdXBwb3J0OiBpT1MgMTAuMC0xMC4yIG9ubHlcblx0Ly8gRWFybHkgaU9TIDEwIHZlcnNpb25zIHN1cHBvcnQgYGF0dGFjaFNoYWRvd2AgYnV0IG5vdCBgZ2V0Um9vdE5vZGVgLFxuXHQvLyBsZWFkaW5nIHRvIGVycm9ycy4gV2UgbmVlZCB0byBjaGVjayBmb3IgYGdldFJvb3ROb2RlYC5cblx0aWYgKCBkb2N1bWVudEVsZW1lbnQuZ2V0Um9vdE5vZGUgKSB7XG5cdFx0aXNBdHRhY2hlZCA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIGpRdWVyeS5jb250YWlucyggZWxlbS5vd25lckRvY3VtZW50LCBlbGVtICkgfHxcblx0XHRcdFx0ZWxlbS5nZXRSb290Tm9kZSggY29tcG9zZWQgKSA9PT0gZWxlbS5vd25lckRvY3VtZW50O1xuXHRcdH07XG5cdH1cbnZhciBpc0hpZGRlbldpdGhpblRyZWUgPSBmdW5jdGlvbiggZWxlbSwgZWwgKSB7XG5cblx0XHQvLyBpc0hpZGRlbldpdGhpblRyZWUgbWlnaHQgYmUgY2FsbGVkIGZyb20galF1ZXJ5I2ZpbHRlciBmdW5jdGlvbjtcblx0XHQvLyBpbiB0aGF0IGNhc2UsIGVsZW1lbnQgd2lsbCBiZSBzZWNvbmQgYXJndW1lbnRcblx0XHRlbGVtID0gZWwgfHwgZWxlbTtcblxuXHRcdC8vIElubGluZSBzdHlsZSB0cnVtcHMgYWxsXG5cdFx0cmV0dXJuIGVsZW0uc3R5bGUuZGlzcGxheSA9PT0gXCJub25lXCIgfHxcblx0XHRcdGVsZW0uc3R5bGUuZGlzcGxheSA9PT0gXCJcIiAmJlxuXG5cdFx0XHQvLyBPdGhlcndpc2UsIGNoZWNrIGNvbXB1dGVkIHN0eWxlXG5cdFx0XHQvLyBTdXBwb3J0OiBGaXJlZm94IDw9NDMgLSA0NVxuXHRcdFx0Ly8gRGlzY29ubmVjdGVkIGVsZW1lbnRzIGNhbiBoYXZlIGNvbXB1dGVkIGRpc3BsYXk6IG5vbmUsIHNvIGZpcnN0IGNvbmZpcm0gdGhhdCBlbGVtIGlzXG5cdFx0XHQvLyBpbiB0aGUgZG9jdW1lbnQuXG5cdFx0XHRpc0F0dGFjaGVkKCBlbGVtICkgJiZcblxuXHRcdFx0alF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIgKSA9PT0gXCJub25lXCI7XG5cdH07XG5cbnZhciBzd2FwID0gZnVuY3Rpb24oIGVsZW0sIG9wdGlvbnMsIGNhbGxiYWNrLCBhcmdzICkge1xuXHR2YXIgcmV0LCBuYW1lLFxuXHRcdG9sZCA9IHt9O1xuXG5cdC8vIFJlbWVtYmVyIHRoZSBvbGQgdmFsdWVzLCBhbmQgaW5zZXJ0IHRoZSBuZXcgb25lc1xuXHRmb3IgKCBuYW1lIGluIG9wdGlvbnMgKSB7XG5cdFx0b2xkWyBuYW1lIF0gPSBlbGVtLnN0eWxlWyBuYW1lIF07XG5cdFx0ZWxlbS5zdHlsZVsgbmFtZSBdID0gb3B0aW9uc1sgbmFtZSBdO1xuXHR9XG5cblx0cmV0ID0gY2FsbGJhY2suYXBwbHkoIGVsZW0sIGFyZ3MgfHwgW10gKTtcblxuXHQvLyBSZXZlcnQgdGhlIG9sZCB2YWx1ZXNcblx0Zm9yICggbmFtZSBpbiBvcHRpb25zICkge1xuXHRcdGVsZW0uc3R5bGVbIG5hbWUgXSA9IG9sZFsgbmFtZSBdO1xuXHR9XG5cblx0cmV0dXJuIHJldDtcbn07XG5cblxuXG5cbmZ1bmN0aW9uIGFkanVzdENTUyggZWxlbSwgcHJvcCwgdmFsdWVQYXJ0cywgdHdlZW4gKSB7XG5cdHZhciBhZGp1c3RlZCwgc2NhbGUsXG5cdFx0bWF4SXRlcmF0aW9ucyA9IDIwLFxuXHRcdGN1cnJlbnRWYWx1ZSA9IHR3ZWVuID9cblx0XHRcdGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gdHdlZW4uY3VyKCk7XG5cdFx0XHR9IDpcblx0XHRcdGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4galF1ZXJ5LmNzcyggZWxlbSwgcHJvcCwgXCJcIiApO1xuXHRcdFx0fSxcblx0XHRpbml0aWFsID0gY3VycmVudFZhbHVlKCksXG5cdFx0dW5pdCA9IHZhbHVlUGFydHMgJiYgdmFsdWVQYXJ0c1sgMyBdIHx8ICggalF1ZXJ5LmNzc051bWJlclsgcHJvcCBdID8gXCJcIiA6IFwicHhcIiApLFxuXG5cdFx0Ly8gU3RhcnRpbmcgdmFsdWUgY29tcHV0YXRpb24gaXMgcmVxdWlyZWQgZm9yIHBvdGVudGlhbCB1bml0IG1pc21hdGNoZXNcblx0XHRpbml0aWFsSW5Vbml0ID0gZWxlbS5ub2RlVHlwZSAmJlxuXHRcdFx0KCBqUXVlcnkuY3NzTnVtYmVyWyBwcm9wIF0gfHwgdW5pdCAhPT0gXCJweFwiICYmICtpbml0aWFsICkgJiZcblx0XHRcdHJjc3NOdW0uZXhlYyggalF1ZXJ5LmNzcyggZWxlbSwgcHJvcCApICk7XG5cblx0aWYgKCBpbml0aWFsSW5Vbml0ICYmIGluaXRpYWxJblVuaXRbIDMgXSAhPT0gdW5pdCApIHtcblxuXHRcdC8vIFN1cHBvcnQ6IEZpcmVmb3ggPD01NFxuXHRcdC8vIEhhbHZlIHRoZSBpdGVyYXRpb24gdGFyZ2V0IHZhbHVlIHRvIHByZXZlbnQgaW50ZXJmZXJlbmNlIGZyb20gQ1NTIHVwcGVyIGJvdW5kcyAoZ2gtMjE0NClcblx0XHRpbml0aWFsID0gaW5pdGlhbCAvIDI7XG5cblx0XHQvLyBUcnVzdCB1bml0cyByZXBvcnRlZCBieSBqUXVlcnkuY3NzXG5cdFx0dW5pdCA9IHVuaXQgfHwgaW5pdGlhbEluVW5pdFsgMyBdO1xuXG5cdFx0Ly8gSXRlcmF0aXZlbHkgYXBwcm94aW1hdGUgZnJvbSBhIG5vbnplcm8gc3RhcnRpbmcgcG9pbnRcblx0XHRpbml0aWFsSW5Vbml0ID0gK2luaXRpYWwgfHwgMTtcblxuXHRcdHdoaWxlICggbWF4SXRlcmF0aW9ucy0tICkge1xuXG5cdFx0XHQvLyBFdmFsdWF0ZSBhbmQgdXBkYXRlIG91ciBiZXN0IGd1ZXNzIChkb3VibGluZyBndWVzc2VzIHRoYXQgemVybyBvdXQpLlxuXHRcdFx0Ly8gRmluaXNoIGlmIHRoZSBzY2FsZSBlcXVhbHMgb3IgY3Jvc3NlcyAxIChtYWtpbmcgdGhlIG9sZCpuZXcgcHJvZHVjdCBub24tcG9zaXRpdmUpLlxuXHRcdFx0alF1ZXJ5LnN0eWxlKCBlbGVtLCBwcm9wLCBpbml0aWFsSW5Vbml0ICsgdW5pdCApO1xuXHRcdFx0aWYgKCAoIDEgLSBzY2FsZSApICogKCAxIC0gKCBzY2FsZSA9IGN1cnJlbnRWYWx1ZSgpIC8gaW5pdGlhbCB8fCAwLjUgKSApIDw9IDAgKSB7XG5cdFx0XHRcdG1heEl0ZXJhdGlvbnMgPSAwO1xuXHRcdFx0fVxuXHRcdFx0aW5pdGlhbEluVW5pdCA9IGluaXRpYWxJblVuaXQgLyBzY2FsZTtcblxuXHRcdH1cblxuXHRcdGluaXRpYWxJblVuaXQgPSBpbml0aWFsSW5Vbml0ICogMjtcblx0XHRqUXVlcnkuc3R5bGUoIGVsZW0sIHByb3AsIGluaXRpYWxJblVuaXQgKyB1bml0ICk7XG5cblx0XHQvLyBNYWtlIHN1cmUgd2UgdXBkYXRlIHRoZSB0d2VlbiBwcm9wZXJ0aWVzIGxhdGVyIG9uXG5cdFx0dmFsdWVQYXJ0cyA9IHZhbHVlUGFydHMgfHwgW107XG5cdH1cblxuXHRpZiAoIHZhbHVlUGFydHMgKSB7XG5cdFx0aW5pdGlhbEluVW5pdCA9ICtpbml0aWFsSW5Vbml0IHx8ICtpbml0aWFsIHx8IDA7XG5cblx0XHQvLyBBcHBseSByZWxhdGl2ZSBvZmZzZXQgKCs9Ly09KSBpZiBzcGVjaWZpZWRcblx0XHRhZGp1c3RlZCA9IHZhbHVlUGFydHNbIDEgXSA/XG5cdFx0XHRpbml0aWFsSW5Vbml0ICsgKCB2YWx1ZVBhcnRzWyAxIF0gKyAxICkgKiB2YWx1ZVBhcnRzWyAyIF0gOlxuXHRcdFx0K3ZhbHVlUGFydHNbIDIgXTtcblx0XHRpZiAoIHR3ZWVuICkge1xuXHRcdFx0dHdlZW4udW5pdCA9IHVuaXQ7XG5cdFx0XHR0d2Vlbi5zdGFydCA9IGluaXRpYWxJblVuaXQ7XG5cdFx0XHR0d2Vlbi5lbmQgPSBhZGp1c3RlZDtcblx0XHR9XG5cdH1cblx0cmV0dXJuIGFkanVzdGVkO1xufVxuXG5cbnZhciBkZWZhdWx0RGlzcGxheU1hcCA9IHt9O1xuXG5mdW5jdGlvbiBnZXREZWZhdWx0RGlzcGxheSggZWxlbSApIHtcblx0dmFyIHRlbXAsXG5cdFx0ZG9jID0gZWxlbS5vd25lckRvY3VtZW50LFxuXHRcdG5vZGVOYW1lID0gZWxlbS5ub2RlTmFtZSxcblx0XHRkaXNwbGF5ID0gZGVmYXVsdERpc3BsYXlNYXBbIG5vZGVOYW1lIF07XG5cblx0aWYgKCBkaXNwbGF5ICkge1xuXHRcdHJldHVybiBkaXNwbGF5O1xuXHR9XG5cblx0dGVtcCA9IGRvYy5ib2R5LmFwcGVuZENoaWxkKCBkb2MuY3JlYXRlRWxlbWVudCggbm9kZU5hbWUgKSApO1xuXHRkaXNwbGF5ID0galF1ZXJ5LmNzcyggdGVtcCwgXCJkaXNwbGF5XCIgKTtcblxuXHR0ZW1wLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoIHRlbXAgKTtcblxuXHRpZiAoIGRpc3BsYXkgPT09IFwibm9uZVwiICkge1xuXHRcdGRpc3BsYXkgPSBcImJsb2NrXCI7XG5cdH1cblx0ZGVmYXVsdERpc3BsYXlNYXBbIG5vZGVOYW1lIF0gPSBkaXNwbGF5O1xuXG5cdHJldHVybiBkaXNwbGF5O1xufVxuXG5mdW5jdGlvbiBzaG93SGlkZSggZWxlbWVudHMsIHNob3cgKSB7XG5cdHZhciBkaXNwbGF5LCBlbGVtLFxuXHRcdHZhbHVlcyA9IFtdLFxuXHRcdGluZGV4ID0gMCxcblx0XHRsZW5ndGggPSBlbGVtZW50cy5sZW5ndGg7XG5cblx0Ly8gRGV0ZXJtaW5lIG5ldyBkaXNwbGF5IHZhbHVlIGZvciBlbGVtZW50cyB0aGF0IG5lZWQgdG8gY2hhbmdlXG5cdGZvciAoIDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KysgKSB7XG5cdFx0ZWxlbSA9IGVsZW1lbnRzWyBpbmRleCBdO1xuXHRcdGlmICggIWVsZW0uc3R5bGUgKSB7XG5cdFx0XHRjb250aW51ZTtcblx0XHR9XG5cblx0XHRkaXNwbGF5ID0gZWxlbS5zdHlsZS5kaXNwbGF5O1xuXHRcdGlmICggc2hvdyApIHtcblxuXHRcdFx0Ly8gU2luY2Ugd2UgZm9yY2UgdmlzaWJpbGl0eSB1cG9uIGNhc2NhZGUtaGlkZGVuIGVsZW1lbnRzLCBhbiBpbW1lZGlhdGUgKGFuZCBzbG93KVxuXHRcdFx0Ly8gY2hlY2sgaXMgcmVxdWlyZWQgaW4gdGhpcyBmaXJzdCBsb29wIHVubGVzcyB3ZSBoYXZlIGEgbm9uZW1wdHkgZGlzcGxheSB2YWx1ZSAoZWl0aGVyXG5cdFx0XHQvLyBpbmxpbmUgb3IgYWJvdXQtdG8tYmUtcmVzdG9yZWQpXG5cdFx0XHRpZiAoIGRpc3BsYXkgPT09IFwibm9uZVwiICkge1xuXHRcdFx0XHR2YWx1ZXNbIGluZGV4IF0gPSBkYXRhUHJpdi5nZXQoIGVsZW0sIFwiZGlzcGxheVwiICkgfHwgbnVsbDtcblx0XHRcdFx0aWYgKCAhdmFsdWVzWyBpbmRleCBdICkge1xuXHRcdFx0XHRcdGVsZW0uc3R5bGUuZGlzcGxheSA9IFwiXCI7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdGlmICggZWxlbS5zdHlsZS5kaXNwbGF5ID09PSBcIlwiICYmIGlzSGlkZGVuV2l0aGluVHJlZSggZWxlbSApICkge1xuXHRcdFx0XHR2YWx1ZXNbIGluZGV4IF0gPSBnZXREZWZhdWx0RGlzcGxheSggZWxlbSApO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRpZiAoIGRpc3BsYXkgIT09IFwibm9uZVwiICkge1xuXHRcdFx0XHR2YWx1ZXNbIGluZGV4IF0gPSBcIm5vbmVcIjtcblxuXHRcdFx0XHQvLyBSZW1lbWJlciB3aGF0IHdlJ3JlIG92ZXJ3cml0aW5nXG5cdFx0XHRcdGRhdGFQcml2LnNldCggZWxlbSwgXCJkaXNwbGF5XCIsIGRpc3BsYXkgKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLyBTZXQgdGhlIGRpc3BsYXkgb2YgdGhlIGVsZW1lbnRzIGluIGEgc2Vjb25kIGxvb3AgdG8gYXZvaWQgY29uc3RhbnQgcmVmbG93XG5cdGZvciAoIGluZGV4ID0gMDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KysgKSB7XG5cdFx0aWYgKCB2YWx1ZXNbIGluZGV4IF0gIT0gbnVsbCApIHtcblx0XHRcdGVsZW1lbnRzWyBpbmRleCBdLnN0eWxlLmRpc3BsYXkgPSB2YWx1ZXNbIGluZGV4IF07XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGVsZW1lbnRzO1xufVxuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdHNob3c6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBzaG93SGlkZSggdGhpcywgdHJ1ZSApO1xuXHR9LFxuXHRoaWRlOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gc2hvd0hpZGUoIHRoaXMgKTtcblx0fSxcblx0dG9nZ2xlOiBmdW5jdGlvbiggc3RhdGUgKSB7XG5cdFx0aWYgKCB0eXBlb2Ygc3RhdGUgPT09IFwiYm9vbGVhblwiICkge1xuXHRcdFx0cmV0dXJuIHN0YXRlID8gdGhpcy5zaG93KCkgOiB0aGlzLmhpZGUoKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggaXNIaWRkZW5XaXRoaW5UcmVlKCB0aGlzICkgKSB7XG5cdFx0XHRcdGpRdWVyeSggdGhpcyApLnNob3coKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGpRdWVyeSggdGhpcyApLmhpZGUoKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH1cbn0gKTtcbnZhciByY2hlY2thYmxlVHlwZSA9ICggL14oPzpjaGVja2JveHxyYWRpbykkL2kgKTtcblxudmFyIHJ0YWdOYW1lID0gKCAvPChbYS16XVteXFwvXFwwPlxceDIwXFx0XFxyXFxuXFxmXSopL2kgKTtcblxudmFyIHJzY3JpcHRUeXBlID0gKCAvXiR8Xm1vZHVsZSR8XFwvKD86amF2YXxlY21hKXNjcmlwdC9pICk7XG5cblxuXG4vLyBXZSBoYXZlIHRvIGNsb3NlIHRoZXNlIHRhZ3MgdG8gc3VwcG9ydCBYSFRNTCAoIzEzMjAwKVxudmFyIHdyYXBNYXAgPSB7XG5cblx0Ly8gU3VwcG9ydDogSUUgPD05IG9ubHlcblx0b3B0aW9uOiBbIDEsIFwiPHNlbGVjdCBtdWx0aXBsZT0nbXVsdGlwbGUnPlwiLCBcIjwvc2VsZWN0PlwiIF0sXG5cblx0Ly8gWEhUTUwgcGFyc2VycyBkbyBub3QgbWFnaWNhbGx5IGluc2VydCBlbGVtZW50cyBpbiB0aGVcblx0Ly8gc2FtZSB3YXkgdGhhdCB0YWcgc291cCBwYXJzZXJzIGRvLiBTbyB3ZSBjYW5ub3Qgc2hvcnRlblxuXHQvLyB0aGlzIGJ5IG9taXR0aW5nIDx0Ym9keT4gb3Igb3RoZXIgcmVxdWlyZWQgZWxlbWVudHMuXG5cdHRoZWFkOiBbIDEsIFwiPHRhYmxlPlwiLCBcIjwvdGFibGU+XCIgXSxcblx0Y29sOiBbIDIsIFwiPHRhYmxlPjxjb2xncm91cD5cIiwgXCI8L2NvbGdyb3VwPjwvdGFibGU+XCIgXSxcblx0dHI6IFsgMiwgXCI8dGFibGU+PHRib2R5PlwiLCBcIjwvdGJvZHk+PC90YWJsZT5cIiBdLFxuXHR0ZDogWyAzLCBcIjx0YWJsZT48dGJvZHk+PHRyPlwiLCBcIjwvdHI+PC90Ym9keT48L3RhYmxlPlwiIF0sXG5cblx0X2RlZmF1bHQ6IFsgMCwgXCJcIiwgXCJcIiBdXG59O1xuXG4vLyBTdXBwb3J0OiBJRSA8PTkgb25seVxud3JhcE1hcC5vcHRncm91cCA9IHdyYXBNYXAub3B0aW9uO1xuXG53cmFwTWFwLnRib2R5ID0gd3JhcE1hcC50Zm9vdCA9IHdyYXBNYXAuY29sZ3JvdXAgPSB3cmFwTWFwLmNhcHRpb24gPSB3cmFwTWFwLnRoZWFkO1xud3JhcE1hcC50aCA9IHdyYXBNYXAudGQ7XG5cblxuZnVuY3Rpb24gZ2V0QWxsKCBjb250ZXh0LCB0YWcgKSB7XG5cblx0Ly8gU3VwcG9ydDogSUUgPD05IC0gMTEgb25seVxuXHQvLyBVc2UgdHlwZW9mIHRvIGF2b2lkIHplcm8tYXJndW1lbnQgbWV0aG9kIGludm9jYXRpb24gb24gaG9zdCBvYmplY3RzICgjMTUxNTEpXG5cdHZhciByZXQ7XG5cblx0aWYgKCB0eXBlb2YgY29udGV4dC5nZXRFbGVtZW50c0J5VGFnTmFtZSAhPT0gXCJ1bmRlZmluZWRcIiApIHtcblx0XHRyZXQgPSBjb250ZXh0LmdldEVsZW1lbnRzQnlUYWdOYW1lKCB0YWcgfHwgXCIqXCIgKTtcblxuXHR9IGVsc2UgaWYgKCB0eXBlb2YgY29udGV4dC5xdWVyeVNlbGVjdG9yQWxsICE9PSBcInVuZGVmaW5lZFwiICkge1xuXHRcdHJldCA9IGNvbnRleHQucXVlcnlTZWxlY3RvckFsbCggdGFnIHx8IFwiKlwiICk7XG5cblx0fSBlbHNlIHtcblx0XHRyZXQgPSBbXTtcblx0fVxuXG5cdGlmICggdGFnID09PSB1bmRlZmluZWQgfHwgdGFnICYmIG5vZGVOYW1lKCBjb250ZXh0LCB0YWcgKSApIHtcblx0XHRyZXR1cm4galF1ZXJ5Lm1lcmdlKCBbIGNvbnRleHQgXSwgcmV0ICk7XG5cdH1cblxuXHRyZXR1cm4gcmV0O1xufVxuXG5cbi8vIE1hcmsgc2NyaXB0cyBhcyBoYXZpbmcgYWxyZWFkeSBiZWVuIGV2YWx1YXRlZFxuZnVuY3Rpb24gc2V0R2xvYmFsRXZhbCggZWxlbXMsIHJlZkVsZW1lbnRzICkge1xuXHR2YXIgaSA9IDAsXG5cdFx0bCA9IGVsZW1zLmxlbmd0aDtcblxuXHRmb3IgKCA7IGkgPCBsOyBpKysgKSB7XG5cdFx0ZGF0YVByaXYuc2V0KFxuXHRcdFx0ZWxlbXNbIGkgXSxcblx0XHRcdFwiZ2xvYmFsRXZhbFwiLFxuXHRcdFx0IXJlZkVsZW1lbnRzIHx8IGRhdGFQcml2LmdldCggcmVmRWxlbWVudHNbIGkgXSwgXCJnbG9iYWxFdmFsXCIgKVxuXHRcdCk7XG5cdH1cbn1cblxuXG52YXIgcmh0bWwgPSAvPHwmIz9cXHcrOy87XG5cbmZ1bmN0aW9uIGJ1aWxkRnJhZ21lbnQoIGVsZW1zLCBjb250ZXh0LCBzY3JpcHRzLCBzZWxlY3Rpb24sIGlnbm9yZWQgKSB7XG5cdHZhciBlbGVtLCB0bXAsIHRhZywgd3JhcCwgYXR0YWNoZWQsIGosXG5cdFx0ZnJhZ21lbnQgPSBjb250ZXh0LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKSxcblx0XHRub2RlcyA9IFtdLFxuXHRcdGkgPSAwLFxuXHRcdGwgPSBlbGVtcy5sZW5ndGg7XG5cblx0Zm9yICggOyBpIDwgbDsgaSsrICkge1xuXHRcdGVsZW0gPSBlbGVtc1sgaSBdO1xuXG5cdFx0aWYgKCBlbGVtIHx8IGVsZW0gPT09IDAgKSB7XG5cblx0XHRcdC8vIEFkZCBub2RlcyBkaXJlY3RseVxuXHRcdFx0aWYgKCB0b1R5cGUoIGVsZW0gKSA9PT0gXCJvYmplY3RcIiApIHtcblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkIDw9NC4wIG9ubHksIFBoYW50b21KUyAxIG9ubHlcblx0XHRcdFx0Ly8gcHVzaC5hcHBseShfLCBhcnJheWxpa2UpIHRocm93cyBvbiBhbmNpZW50IFdlYktpdFxuXHRcdFx0XHRqUXVlcnkubWVyZ2UoIG5vZGVzLCBlbGVtLm5vZGVUeXBlID8gWyBlbGVtIF0gOiBlbGVtICk7XG5cblx0XHRcdC8vIENvbnZlcnQgbm9uLWh0bWwgaW50byBhIHRleHQgbm9kZVxuXHRcdFx0fSBlbHNlIGlmICggIXJodG1sLnRlc3QoIGVsZW0gKSApIHtcblx0XHRcdFx0bm9kZXMucHVzaCggY29udGV4dC5jcmVhdGVUZXh0Tm9kZSggZWxlbSApICk7XG5cblx0XHRcdC8vIENvbnZlcnQgaHRtbCBpbnRvIERPTSBub2Rlc1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dG1wID0gdG1wIHx8IGZyYWdtZW50LmFwcGVuZENoaWxkKCBjb250ZXh0LmNyZWF0ZUVsZW1lbnQoIFwiZGl2XCIgKSApO1xuXG5cdFx0XHRcdC8vIERlc2VyaWFsaXplIGEgc3RhbmRhcmQgcmVwcmVzZW50YXRpb25cblx0XHRcdFx0dGFnID0gKCBydGFnTmFtZS5leGVjKCBlbGVtICkgfHwgWyBcIlwiLCBcIlwiIF0gKVsgMSBdLnRvTG93ZXJDYXNlKCk7XG5cdFx0XHRcdHdyYXAgPSB3cmFwTWFwWyB0YWcgXSB8fCB3cmFwTWFwLl9kZWZhdWx0O1xuXHRcdFx0XHR0bXAuaW5uZXJIVE1MID0gd3JhcFsgMSBdICsgalF1ZXJ5Lmh0bWxQcmVmaWx0ZXIoIGVsZW0gKSArIHdyYXBbIDIgXTtcblxuXHRcdFx0XHQvLyBEZXNjZW5kIHRocm91Z2ggd3JhcHBlcnMgdG8gdGhlIHJpZ2h0IGNvbnRlbnRcblx0XHRcdFx0aiA9IHdyYXBbIDAgXTtcblx0XHRcdFx0d2hpbGUgKCBqLS0gKSB7XG5cdFx0XHRcdFx0dG1wID0gdG1wLmxhc3RDaGlsZDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD00LjAgb25seSwgUGhhbnRvbUpTIDEgb25seVxuXHRcdFx0XHQvLyBwdXNoLmFwcGx5KF8sIGFycmF5bGlrZSkgdGhyb3dzIG9uIGFuY2llbnQgV2ViS2l0XG5cdFx0XHRcdGpRdWVyeS5tZXJnZSggbm9kZXMsIHRtcC5jaGlsZE5vZGVzICk7XG5cblx0XHRcdFx0Ly8gUmVtZW1iZXIgdGhlIHRvcC1sZXZlbCBjb250YWluZXJcblx0XHRcdFx0dG1wID0gZnJhZ21lbnQuZmlyc3RDaGlsZDtcblxuXHRcdFx0XHQvLyBFbnN1cmUgdGhlIGNyZWF0ZWQgbm9kZXMgYXJlIG9ycGhhbmVkICgjMTIzOTIpXG5cdFx0XHRcdHRtcC50ZXh0Q29udGVudCA9IFwiXCI7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0Ly8gUmVtb3ZlIHdyYXBwZXIgZnJvbSBmcmFnbWVudFxuXHRmcmFnbWVudC50ZXh0Q29udGVudCA9IFwiXCI7XG5cblx0aSA9IDA7XG5cdHdoaWxlICggKCBlbGVtID0gbm9kZXNbIGkrKyBdICkgKSB7XG5cblx0XHQvLyBTa2lwIGVsZW1lbnRzIGFscmVhZHkgaW4gdGhlIGNvbnRleHQgY29sbGVjdGlvbiAodHJhYy00MDg3KVxuXHRcdGlmICggc2VsZWN0aW9uICYmIGpRdWVyeS5pbkFycmF5KCBlbGVtLCBzZWxlY3Rpb24gKSA+IC0xICkge1xuXHRcdFx0aWYgKCBpZ25vcmVkICkge1xuXHRcdFx0XHRpZ25vcmVkLnB1c2goIGVsZW0gKTtcblx0XHRcdH1cblx0XHRcdGNvbnRpbnVlO1xuXHRcdH1cblxuXHRcdGF0dGFjaGVkID0gaXNBdHRhY2hlZCggZWxlbSApO1xuXG5cdFx0Ly8gQXBwZW5kIHRvIGZyYWdtZW50XG5cdFx0dG1wID0gZ2V0QWxsKCBmcmFnbWVudC5hcHBlbmRDaGlsZCggZWxlbSApLCBcInNjcmlwdFwiICk7XG5cblx0XHQvLyBQcmVzZXJ2ZSBzY3JpcHQgZXZhbHVhdGlvbiBoaXN0b3J5XG5cdFx0aWYgKCBhdHRhY2hlZCApIHtcblx0XHRcdHNldEdsb2JhbEV2YWwoIHRtcCApO1xuXHRcdH1cblxuXHRcdC8vIENhcHR1cmUgZXhlY3V0YWJsZXNcblx0XHRpZiAoIHNjcmlwdHMgKSB7XG5cdFx0XHRqID0gMDtcblx0XHRcdHdoaWxlICggKCBlbGVtID0gdG1wWyBqKysgXSApICkge1xuXHRcdFx0XHRpZiAoIHJzY3JpcHRUeXBlLnRlc3QoIGVsZW0udHlwZSB8fCBcIlwiICkgKSB7XG5cdFx0XHRcdFx0c2NyaXB0cy5wdXNoKCBlbGVtICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gZnJhZ21lbnQ7XG59XG5cblxuKCBmdW5jdGlvbigpIHtcblx0dmFyIGZyYWdtZW50ID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpLFxuXHRcdGRpdiA9IGZyYWdtZW50LmFwcGVuZENoaWxkKCBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImRpdlwiICkgKSxcblx0XHRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiaW5wdXRcIiApO1xuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgNC4wIC0gNC4zIG9ubHlcblx0Ly8gQ2hlY2sgc3RhdGUgbG9zdCBpZiB0aGUgbmFtZSBpcyBzZXQgKCMxMTIxNylcblx0Ly8gU3VwcG9ydDogV2luZG93cyBXZWIgQXBwcyAoV1dBKVxuXHQvLyBgbmFtZWAgYW5kIGB0eXBlYCBtdXN0IHVzZSAuc2V0QXR0cmlidXRlIGZvciBXV0EgKCMxNDkwMSlcblx0aW5wdXQuc2V0QXR0cmlidXRlKCBcInR5cGVcIiwgXCJyYWRpb1wiICk7XG5cdGlucHV0LnNldEF0dHJpYnV0ZSggXCJjaGVja2VkXCIsIFwiY2hlY2tlZFwiICk7XG5cdGlucHV0LnNldEF0dHJpYnV0ZSggXCJuYW1lXCIsIFwidFwiICk7XG5cblx0ZGl2LmFwcGVuZENoaWxkKCBpbnB1dCApO1xuXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD00LjEgb25seVxuXHQvLyBPbGRlciBXZWJLaXQgZG9lc24ndCBjbG9uZSBjaGVja2VkIHN0YXRlIGNvcnJlY3RseSBpbiBmcmFnbWVudHNcblx0c3VwcG9ydC5jaGVja0Nsb25lID0gZGl2LmNsb25lTm9kZSggdHJ1ZSApLmNsb25lTm9kZSggdHJ1ZSApLmxhc3RDaGlsZC5jaGVja2VkO1xuXG5cdC8vIFN1cHBvcnQ6IElFIDw9MTEgb25seVxuXHQvLyBNYWtlIHN1cmUgdGV4dGFyZWEgKGFuZCBjaGVja2JveCkgZGVmYXVsdFZhbHVlIGlzIHByb3Blcmx5IGNsb25lZFxuXHRkaXYuaW5uZXJIVE1MID0gXCI8dGV4dGFyZWE+eDwvdGV4dGFyZWE+XCI7XG5cdHN1cHBvcnQubm9DbG9uZUNoZWNrZWQgPSAhIWRpdi5jbG9uZU5vZGUoIHRydWUgKS5sYXN0Q2hpbGQuZGVmYXVsdFZhbHVlO1xufSApKCk7XG5cblxudmFyXG5cdHJrZXlFdmVudCA9IC9ea2V5Lyxcblx0cm1vdXNlRXZlbnQgPSAvXig/Om1vdXNlfHBvaW50ZXJ8Y29udGV4dG1lbnV8ZHJhZ3xkcm9wKXxjbGljay8sXG5cdHJ0eXBlbmFtZXNwYWNlID0gL14oW14uXSopKD86XFwuKC4rKXwpLztcblxuZnVuY3Rpb24gcmV0dXJuVHJ1ZSgpIHtcblx0cmV0dXJuIHRydWU7XG59XG5cbmZ1bmN0aW9uIHJldHVybkZhbHNlKCkge1xuXHRyZXR1cm4gZmFsc2U7XG59XG5cbi8vIFN1cHBvcnQ6IElFIDw9OSAtIDExK1xuLy8gZm9jdXMoKSBhbmQgYmx1cigpIGFyZSBhc3luY2hyb25vdXMsIGV4Y2VwdCB3aGVuIHRoZXkgYXJlIG5vLW9wLlxuLy8gU28gZXhwZWN0IGZvY3VzIHRvIGJlIHN5bmNocm9ub3VzIHdoZW4gdGhlIGVsZW1lbnQgaXMgYWxyZWFkeSBhY3RpdmUsXG4vLyBhbmQgYmx1ciB0byBiZSBzeW5jaHJvbm91cyB3aGVuIHRoZSBlbGVtZW50IGlzIG5vdCBhbHJlYWR5IGFjdGl2ZS5cbi8vIChmb2N1cyBhbmQgYmx1ciBhcmUgYWx3YXlzIHN5bmNocm9ub3VzIGluIG90aGVyIHN1cHBvcnRlZCBicm93c2Vycyxcbi8vIHRoaXMganVzdCBkZWZpbmVzIHdoZW4gd2UgY2FuIGNvdW50IG9uIGl0KS5cbmZ1bmN0aW9uIGV4cGVjdFN5bmMoIGVsZW0sIHR5cGUgKSB7XG5cdHJldHVybiAoIGVsZW0gPT09IHNhZmVBY3RpdmVFbGVtZW50KCkgKSA9PT0gKCB0eXBlID09PSBcImZvY3VzXCIgKTtcbn1cblxuLy8gU3VwcG9ydDogSUUgPD05IG9ubHlcbi8vIEFjY2Vzc2luZyBkb2N1bWVudC5hY3RpdmVFbGVtZW50IGNhbiB0aHJvdyB1bmV4cGVjdGVkbHlcbi8vIGh0dHBzOi8vYnVncy5qcXVlcnkuY29tL3RpY2tldC8xMzM5M1xuZnVuY3Rpb24gc2FmZUFjdGl2ZUVsZW1lbnQoKSB7XG5cdHRyeSB7XG5cdFx0cmV0dXJuIGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG5cdH0gY2F0Y2ggKCBlcnIgKSB7IH1cbn1cblxuZnVuY3Rpb24gb24oIGVsZW0sIHR5cGVzLCBzZWxlY3RvciwgZGF0YSwgZm4sIG9uZSApIHtcblx0dmFyIG9yaWdGbiwgdHlwZTtcblxuXHQvLyBUeXBlcyBjYW4gYmUgYSBtYXAgb2YgdHlwZXMvaGFuZGxlcnNcblx0aWYgKCB0eXBlb2YgdHlwZXMgPT09IFwib2JqZWN0XCIgKSB7XG5cblx0XHQvLyAoIHR5cGVzLU9iamVjdCwgc2VsZWN0b3IsIGRhdGEgKVxuXHRcdGlmICggdHlwZW9mIHNlbGVjdG9yICE9PSBcInN0cmluZ1wiICkge1xuXG5cdFx0XHQvLyAoIHR5cGVzLU9iamVjdCwgZGF0YSApXG5cdFx0XHRkYXRhID0gZGF0YSB8fCBzZWxlY3Rvcjtcblx0XHRcdHNlbGVjdG9yID0gdW5kZWZpbmVkO1xuXHRcdH1cblx0XHRmb3IgKCB0eXBlIGluIHR5cGVzICkge1xuXHRcdFx0b24oIGVsZW0sIHR5cGUsIHNlbGVjdG9yLCBkYXRhLCB0eXBlc1sgdHlwZSBdLCBvbmUgKTtcblx0XHR9XG5cdFx0cmV0dXJuIGVsZW07XG5cdH1cblxuXHRpZiAoIGRhdGEgPT0gbnVsbCAmJiBmbiA9PSBudWxsICkge1xuXG5cdFx0Ly8gKCB0eXBlcywgZm4gKVxuXHRcdGZuID0gc2VsZWN0b3I7XG5cdFx0ZGF0YSA9IHNlbGVjdG9yID0gdW5kZWZpbmVkO1xuXHR9IGVsc2UgaWYgKCBmbiA9PSBudWxsICkge1xuXHRcdGlmICggdHlwZW9mIHNlbGVjdG9yID09PSBcInN0cmluZ1wiICkge1xuXG5cdFx0XHQvLyAoIHR5cGVzLCBzZWxlY3RvciwgZm4gKVxuXHRcdFx0Zm4gPSBkYXRhO1xuXHRcdFx0ZGF0YSA9IHVuZGVmaW5lZDtcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyAoIHR5cGVzLCBkYXRhLCBmbiApXG5cdFx0XHRmbiA9IGRhdGE7XG5cdFx0XHRkYXRhID0gc2VsZWN0b3I7XG5cdFx0XHRzZWxlY3RvciA9IHVuZGVmaW5lZDtcblx0XHR9XG5cdH1cblx0aWYgKCBmbiA9PT0gZmFsc2UgKSB7XG5cdFx0Zm4gPSByZXR1cm5GYWxzZTtcblx0fSBlbHNlIGlmICggIWZuICkge1xuXHRcdHJldHVybiBlbGVtO1xuXHR9XG5cblx0aWYgKCBvbmUgPT09IDEgKSB7XG5cdFx0b3JpZ0ZuID0gZm47XG5cdFx0Zm4gPSBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHRcdC8vIENhbiB1c2UgYW4gZW1wdHkgc2V0LCBzaW5jZSBldmVudCBjb250YWlucyB0aGUgaW5mb1xuXHRcdFx0alF1ZXJ5KCkub2ZmKCBldmVudCApO1xuXHRcdFx0cmV0dXJuIG9yaWdGbi5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0fTtcblxuXHRcdC8vIFVzZSBzYW1lIGd1aWQgc28gY2FsbGVyIGNhbiByZW1vdmUgdXNpbmcgb3JpZ0ZuXG5cdFx0Zm4uZ3VpZCA9IG9yaWdGbi5ndWlkIHx8ICggb3JpZ0ZuLmd1aWQgPSBqUXVlcnkuZ3VpZCsrICk7XG5cdH1cblx0cmV0dXJuIGVsZW0uZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0alF1ZXJ5LmV2ZW50LmFkZCggdGhpcywgdHlwZXMsIGZuLCBkYXRhLCBzZWxlY3RvciApO1xuXHR9ICk7XG59XG5cbi8qXG4gKiBIZWxwZXIgZnVuY3Rpb25zIGZvciBtYW5hZ2luZyBldmVudHMgLS0gbm90IHBhcnQgb2YgdGhlIHB1YmxpYyBpbnRlcmZhY2UuXG4gKiBQcm9wcyB0byBEZWFuIEVkd2FyZHMnIGFkZEV2ZW50IGxpYnJhcnkgZm9yIG1hbnkgb2YgdGhlIGlkZWFzLlxuICovXG5qUXVlcnkuZXZlbnQgPSB7XG5cblx0Z2xvYmFsOiB7fSxcblxuXHRhZGQ6IGZ1bmN0aW9uKCBlbGVtLCB0eXBlcywgaGFuZGxlciwgZGF0YSwgc2VsZWN0b3IgKSB7XG5cblx0XHR2YXIgaGFuZGxlT2JqSW4sIGV2ZW50SGFuZGxlLCB0bXAsXG5cdFx0XHRldmVudHMsIHQsIGhhbmRsZU9iaixcblx0XHRcdHNwZWNpYWwsIGhhbmRsZXJzLCB0eXBlLCBuYW1lc3BhY2VzLCBvcmlnVHlwZSxcblx0XHRcdGVsZW1EYXRhID0gZGF0YVByaXYuZ2V0KCBlbGVtICk7XG5cblx0XHQvLyBEb24ndCBhdHRhY2ggZXZlbnRzIHRvIG5vRGF0YSBvciB0ZXh0L2NvbW1lbnQgbm9kZXMgKGJ1dCBhbGxvdyBwbGFpbiBvYmplY3RzKVxuXHRcdGlmICggIWVsZW1EYXRhICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIENhbGxlciBjYW4gcGFzcyBpbiBhbiBvYmplY3Qgb2YgY3VzdG9tIGRhdGEgaW4gbGlldSBvZiB0aGUgaGFuZGxlclxuXHRcdGlmICggaGFuZGxlci5oYW5kbGVyICkge1xuXHRcdFx0aGFuZGxlT2JqSW4gPSBoYW5kbGVyO1xuXHRcdFx0aGFuZGxlciA9IGhhbmRsZU9iakluLmhhbmRsZXI7XG5cdFx0XHRzZWxlY3RvciA9IGhhbmRsZU9iakluLnNlbGVjdG9yO1xuXHRcdH1cblxuXHRcdC8vIEVuc3VyZSB0aGF0IGludmFsaWQgc2VsZWN0b3JzIHRocm93IGV4Y2VwdGlvbnMgYXQgYXR0YWNoIHRpbWVcblx0XHQvLyBFdmFsdWF0ZSBhZ2FpbnN0IGRvY3VtZW50RWxlbWVudCBpbiBjYXNlIGVsZW0gaXMgYSBub24tZWxlbWVudCBub2RlIChlLmcuLCBkb2N1bWVudClcblx0XHRpZiAoIHNlbGVjdG9yICkge1xuXHRcdFx0alF1ZXJ5LmZpbmQubWF0Y2hlc1NlbGVjdG9yKCBkb2N1bWVudEVsZW1lbnQsIHNlbGVjdG9yICk7XG5cdFx0fVxuXG5cdFx0Ly8gTWFrZSBzdXJlIHRoYXQgdGhlIGhhbmRsZXIgaGFzIGEgdW5pcXVlIElELCB1c2VkIHRvIGZpbmQvcmVtb3ZlIGl0IGxhdGVyXG5cdFx0aWYgKCAhaGFuZGxlci5ndWlkICkge1xuXHRcdFx0aGFuZGxlci5ndWlkID0galF1ZXJ5Lmd1aWQrKztcblx0XHR9XG5cblx0XHQvLyBJbml0IHRoZSBlbGVtZW50J3MgZXZlbnQgc3RydWN0dXJlIGFuZCBtYWluIGhhbmRsZXIsIGlmIHRoaXMgaXMgdGhlIGZpcnN0XG5cdFx0aWYgKCAhKCBldmVudHMgPSBlbGVtRGF0YS5ldmVudHMgKSApIHtcblx0XHRcdGV2ZW50cyA9IGVsZW1EYXRhLmV2ZW50cyA9IHt9O1xuXHRcdH1cblx0XHRpZiAoICEoIGV2ZW50SGFuZGxlID0gZWxlbURhdGEuaGFuZGxlICkgKSB7XG5cdFx0XHRldmVudEhhbmRsZSA9IGVsZW1EYXRhLmhhbmRsZSA9IGZ1bmN0aW9uKCBlICkge1xuXG5cdFx0XHRcdC8vIERpc2NhcmQgdGhlIHNlY29uZCBldmVudCBvZiBhIGpRdWVyeS5ldmVudC50cmlnZ2VyKCkgYW5kXG5cdFx0XHRcdC8vIHdoZW4gYW4gZXZlbnQgaXMgY2FsbGVkIGFmdGVyIGEgcGFnZSBoYXMgdW5sb2FkZWRcblx0XHRcdFx0cmV0dXJuIHR5cGVvZiBqUXVlcnkgIT09IFwidW5kZWZpbmVkXCIgJiYgalF1ZXJ5LmV2ZW50LnRyaWdnZXJlZCAhPT0gZS50eXBlID9cblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQuZGlzcGF0Y2guYXBwbHkoIGVsZW0sIGFyZ3VtZW50cyApIDogdW5kZWZpbmVkO1xuXHRcdFx0fTtcblx0XHR9XG5cblx0XHQvLyBIYW5kbGUgbXVsdGlwbGUgZXZlbnRzIHNlcGFyYXRlZCBieSBhIHNwYWNlXG5cdFx0dHlwZXMgPSAoIHR5cGVzIHx8IFwiXCIgKS5tYXRjaCggcm5vdGh0bWx3aGl0ZSApIHx8IFsgXCJcIiBdO1xuXHRcdHQgPSB0eXBlcy5sZW5ndGg7XG5cdFx0d2hpbGUgKCB0LS0gKSB7XG5cdFx0XHR0bXAgPSBydHlwZW5hbWVzcGFjZS5leGVjKCB0eXBlc1sgdCBdICkgfHwgW107XG5cdFx0XHR0eXBlID0gb3JpZ1R5cGUgPSB0bXBbIDEgXTtcblx0XHRcdG5hbWVzcGFjZXMgPSAoIHRtcFsgMiBdIHx8IFwiXCIgKS5zcGxpdCggXCIuXCIgKS5zb3J0KCk7XG5cblx0XHRcdC8vIFRoZXJlICptdXN0KiBiZSBhIHR5cGUsIG5vIGF0dGFjaGluZyBuYW1lc3BhY2Utb25seSBoYW5kbGVyc1xuXHRcdFx0aWYgKCAhdHlwZSApIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdC8vIElmIGV2ZW50IGNoYW5nZXMgaXRzIHR5cGUsIHVzZSB0aGUgc3BlY2lhbCBldmVudCBoYW5kbGVycyBmb3IgdGhlIGNoYW5nZWQgdHlwZVxuXHRcdFx0c3BlY2lhbCA9IGpRdWVyeS5ldmVudC5zcGVjaWFsWyB0eXBlIF0gfHwge307XG5cblx0XHRcdC8vIElmIHNlbGVjdG9yIGRlZmluZWQsIGRldGVybWluZSBzcGVjaWFsIGV2ZW50IGFwaSB0eXBlLCBvdGhlcndpc2UgZ2l2ZW4gdHlwZVxuXHRcdFx0dHlwZSA9ICggc2VsZWN0b3IgPyBzcGVjaWFsLmRlbGVnYXRlVHlwZSA6IHNwZWNpYWwuYmluZFR5cGUgKSB8fCB0eXBlO1xuXG5cdFx0XHQvLyBVcGRhdGUgc3BlY2lhbCBiYXNlZCBvbiBuZXdseSByZXNldCB0eXBlXG5cdFx0XHRzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWxbIHR5cGUgXSB8fCB7fTtcblxuXHRcdFx0Ly8gaGFuZGxlT2JqIGlzIHBhc3NlZCB0byBhbGwgZXZlbnQgaGFuZGxlcnNcblx0XHRcdGhhbmRsZU9iaiA9IGpRdWVyeS5leHRlbmQoIHtcblx0XHRcdFx0dHlwZTogdHlwZSxcblx0XHRcdFx0b3JpZ1R5cGU6IG9yaWdUeXBlLFxuXHRcdFx0XHRkYXRhOiBkYXRhLFxuXHRcdFx0XHRoYW5kbGVyOiBoYW5kbGVyLFxuXHRcdFx0XHRndWlkOiBoYW5kbGVyLmd1aWQsXG5cdFx0XHRcdHNlbGVjdG9yOiBzZWxlY3Rvcixcblx0XHRcdFx0bmVlZHNDb250ZXh0OiBzZWxlY3RvciAmJiBqUXVlcnkuZXhwci5tYXRjaC5uZWVkc0NvbnRleHQudGVzdCggc2VsZWN0b3IgKSxcblx0XHRcdFx0bmFtZXNwYWNlOiBuYW1lc3BhY2VzLmpvaW4oIFwiLlwiIClcblx0XHRcdH0sIGhhbmRsZU9iakluICk7XG5cblx0XHRcdC8vIEluaXQgdGhlIGV2ZW50IGhhbmRsZXIgcXVldWUgaWYgd2UncmUgdGhlIGZpcnN0XG5cdFx0XHRpZiAoICEoIGhhbmRsZXJzID0gZXZlbnRzWyB0eXBlIF0gKSApIHtcblx0XHRcdFx0aGFuZGxlcnMgPSBldmVudHNbIHR5cGUgXSA9IFtdO1xuXHRcdFx0XHRoYW5kbGVycy5kZWxlZ2F0ZUNvdW50ID0gMDtcblxuXHRcdFx0XHQvLyBPbmx5IHVzZSBhZGRFdmVudExpc3RlbmVyIGlmIHRoZSBzcGVjaWFsIGV2ZW50cyBoYW5kbGVyIHJldHVybnMgZmFsc2Vcblx0XHRcdFx0aWYgKCAhc3BlY2lhbC5zZXR1cCB8fFxuXHRcdFx0XHRcdHNwZWNpYWwuc2V0dXAuY2FsbCggZWxlbSwgZGF0YSwgbmFtZXNwYWNlcywgZXZlbnRIYW5kbGUgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRpZiAoIGVsZW0uYWRkRXZlbnRMaXN0ZW5lciApIHtcblx0XHRcdFx0XHRcdGVsZW0uYWRkRXZlbnRMaXN0ZW5lciggdHlwZSwgZXZlbnRIYW5kbGUgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBzcGVjaWFsLmFkZCApIHtcblx0XHRcdFx0c3BlY2lhbC5hZGQuY2FsbCggZWxlbSwgaGFuZGxlT2JqICk7XG5cblx0XHRcdFx0aWYgKCAhaGFuZGxlT2JqLmhhbmRsZXIuZ3VpZCApIHtcblx0XHRcdFx0XHRoYW5kbGVPYmouaGFuZGxlci5ndWlkID0gaGFuZGxlci5ndWlkO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFkZCB0byB0aGUgZWxlbWVudCdzIGhhbmRsZXIgbGlzdCwgZGVsZWdhdGVzIGluIGZyb250XG5cdFx0XHRpZiAoIHNlbGVjdG9yICkge1xuXHRcdFx0XHRoYW5kbGVycy5zcGxpY2UoIGhhbmRsZXJzLmRlbGVnYXRlQ291bnQrKywgMCwgaGFuZGxlT2JqICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRoYW5kbGVycy5wdXNoKCBoYW5kbGVPYmogKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gS2VlcCB0cmFjayBvZiB3aGljaCBldmVudHMgaGF2ZSBldmVyIGJlZW4gdXNlZCwgZm9yIGV2ZW50IG9wdGltaXphdGlvblxuXHRcdFx0alF1ZXJ5LmV2ZW50Lmdsb2JhbFsgdHlwZSBdID0gdHJ1ZTtcblx0XHR9XG5cblx0fSxcblxuXHQvLyBEZXRhY2ggYW4gZXZlbnQgb3Igc2V0IG9mIGV2ZW50cyBmcm9tIGFuIGVsZW1lbnRcblx0cmVtb3ZlOiBmdW5jdGlvbiggZWxlbSwgdHlwZXMsIGhhbmRsZXIsIHNlbGVjdG9yLCBtYXBwZWRUeXBlcyApIHtcblxuXHRcdHZhciBqLCBvcmlnQ291bnQsIHRtcCxcblx0XHRcdGV2ZW50cywgdCwgaGFuZGxlT2JqLFxuXHRcdFx0c3BlY2lhbCwgaGFuZGxlcnMsIHR5cGUsIG5hbWVzcGFjZXMsIG9yaWdUeXBlLFxuXHRcdFx0ZWxlbURhdGEgPSBkYXRhUHJpdi5oYXNEYXRhKCBlbGVtICkgJiYgZGF0YVByaXYuZ2V0KCBlbGVtICk7XG5cblx0XHRpZiAoICFlbGVtRGF0YSB8fCAhKCBldmVudHMgPSBlbGVtRGF0YS5ldmVudHMgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBPbmNlIGZvciBlYWNoIHR5cGUubmFtZXNwYWNlIGluIHR5cGVzOyB0eXBlIG1heSBiZSBvbWl0dGVkXG5cdFx0dHlwZXMgPSAoIHR5cGVzIHx8IFwiXCIgKS5tYXRjaCggcm5vdGh0bWx3aGl0ZSApIHx8IFsgXCJcIiBdO1xuXHRcdHQgPSB0eXBlcy5sZW5ndGg7XG5cdFx0d2hpbGUgKCB0LS0gKSB7XG5cdFx0XHR0bXAgPSBydHlwZW5hbWVzcGFjZS5leGVjKCB0eXBlc1sgdCBdICkgfHwgW107XG5cdFx0XHR0eXBlID0gb3JpZ1R5cGUgPSB0bXBbIDEgXTtcblx0XHRcdG5hbWVzcGFjZXMgPSAoIHRtcFsgMiBdIHx8IFwiXCIgKS5zcGxpdCggXCIuXCIgKS5zb3J0KCk7XG5cblx0XHRcdC8vIFVuYmluZCBhbGwgZXZlbnRzIChvbiB0aGlzIG5hbWVzcGFjZSwgaWYgcHJvdmlkZWQpIGZvciB0aGUgZWxlbWVudFxuXHRcdFx0aWYgKCAhdHlwZSApIHtcblx0XHRcdFx0Zm9yICggdHlwZSBpbiBldmVudHMgKSB7XG5cdFx0XHRcdFx0alF1ZXJ5LmV2ZW50LnJlbW92ZSggZWxlbSwgdHlwZSArIHR5cGVzWyB0IF0sIGhhbmRsZXIsIHNlbGVjdG9yLCB0cnVlICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdHNwZWNpYWwgPSBqUXVlcnkuZXZlbnQuc3BlY2lhbFsgdHlwZSBdIHx8IHt9O1xuXHRcdFx0dHlwZSA9ICggc2VsZWN0b3IgPyBzcGVjaWFsLmRlbGVnYXRlVHlwZSA6IHNwZWNpYWwuYmluZFR5cGUgKSB8fCB0eXBlO1xuXHRcdFx0aGFuZGxlcnMgPSBldmVudHNbIHR5cGUgXSB8fCBbXTtcblx0XHRcdHRtcCA9IHRtcFsgMiBdICYmXG5cdFx0XHRcdG5ldyBSZWdFeHAoIFwiKF58XFxcXC4pXCIgKyBuYW1lc3BhY2VzLmpvaW4oIFwiXFxcXC4oPzouKlxcXFwufClcIiApICsgXCIoXFxcXC58JClcIiApO1xuXG5cdFx0XHQvLyBSZW1vdmUgbWF0Y2hpbmcgZXZlbnRzXG5cdFx0XHRvcmlnQ291bnQgPSBqID0gaGFuZGxlcnMubGVuZ3RoO1xuXHRcdFx0d2hpbGUgKCBqLS0gKSB7XG5cdFx0XHRcdGhhbmRsZU9iaiA9IGhhbmRsZXJzWyBqIF07XG5cblx0XHRcdFx0aWYgKCAoIG1hcHBlZFR5cGVzIHx8IG9yaWdUeXBlID09PSBoYW5kbGVPYmoub3JpZ1R5cGUgKSAmJlxuXHRcdFx0XHRcdCggIWhhbmRsZXIgfHwgaGFuZGxlci5ndWlkID09PSBoYW5kbGVPYmouZ3VpZCApICYmXG5cdFx0XHRcdFx0KCAhdG1wIHx8IHRtcC50ZXN0KCBoYW5kbGVPYmoubmFtZXNwYWNlICkgKSAmJlxuXHRcdFx0XHRcdCggIXNlbGVjdG9yIHx8IHNlbGVjdG9yID09PSBoYW5kbGVPYmouc2VsZWN0b3IgfHxcblx0XHRcdFx0XHRcdHNlbGVjdG9yID09PSBcIioqXCIgJiYgaGFuZGxlT2JqLnNlbGVjdG9yICkgKSB7XG5cdFx0XHRcdFx0aGFuZGxlcnMuc3BsaWNlKCBqLCAxICk7XG5cblx0XHRcdFx0XHRpZiAoIGhhbmRsZU9iai5zZWxlY3RvciApIHtcblx0XHRcdFx0XHRcdGhhbmRsZXJzLmRlbGVnYXRlQ291bnQtLTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCBzcGVjaWFsLnJlbW92ZSApIHtcblx0XHRcdFx0XHRcdHNwZWNpYWwucmVtb3ZlLmNhbGwoIGVsZW0sIGhhbmRsZU9iaiApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBSZW1vdmUgZ2VuZXJpYyBldmVudCBoYW5kbGVyIGlmIHdlIHJlbW92ZWQgc29tZXRoaW5nIGFuZCBubyBtb3JlIGhhbmRsZXJzIGV4aXN0XG5cdFx0XHQvLyAoYXZvaWRzIHBvdGVudGlhbCBmb3IgZW5kbGVzcyByZWN1cnNpb24gZHVyaW5nIHJlbW92YWwgb2Ygc3BlY2lhbCBldmVudCBoYW5kbGVycylcblx0XHRcdGlmICggb3JpZ0NvdW50ICYmICFoYW5kbGVycy5sZW5ndGggKSB7XG5cdFx0XHRcdGlmICggIXNwZWNpYWwudGVhcmRvd24gfHxcblx0XHRcdFx0XHRzcGVjaWFsLnRlYXJkb3duLmNhbGwoIGVsZW0sIG5hbWVzcGFjZXMsIGVsZW1EYXRhLmhhbmRsZSApID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRcdGpRdWVyeS5yZW1vdmVFdmVudCggZWxlbSwgdHlwZSwgZWxlbURhdGEuaGFuZGxlICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRkZWxldGUgZXZlbnRzWyB0eXBlIF07XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gUmVtb3ZlIGRhdGEgYW5kIHRoZSBleHBhbmRvIGlmIGl0J3Mgbm8gbG9uZ2VyIHVzZWRcblx0XHRpZiAoIGpRdWVyeS5pc0VtcHR5T2JqZWN0KCBldmVudHMgKSApIHtcblx0XHRcdGRhdGFQcml2LnJlbW92ZSggZWxlbSwgXCJoYW5kbGUgZXZlbnRzXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0ZGlzcGF0Y2g6IGZ1bmN0aW9uKCBuYXRpdmVFdmVudCApIHtcblxuXHRcdC8vIE1ha2UgYSB3cml0YWJsZSBqUXVlcnkuRXZlbnQgZnJvbSB0aGUgbmF0aXZlIGV2ZW50IG9iamVjdFxuXHRcdHZhciBldmVudCA9IGpRdWVyeS5ldmVudC5maXgoIG5hdGl2ZUV2ZW50ICk7XG5cblx0XHR2YXIgaSwgaiwgcmV0LCBtYXRjaGVkLCBoYW5kbGVPYmosIGhhbmRsZXJRdWV1ZSxcblx0XHRcdGFyZ3MgPSBuZXcgQXJyYXkoIGFyZ3VtZW50cy5sZW5ndGggKSxcblx0XHRcdGhhbmRsZXJzID0gKCBkYXRhUHJpdi5nZXQoIHRoaXMsIFwiZXZlbnRzXCIgKSB8fCB7fSApWyBldmVudC50eXBlIF0gfHwgW10sXG5cdFx0XHRzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWxbIGV2ZW50LnR5cGUgXSB8fCB7fTtcblxuXHRcdC8vIFVzZSB0aGUgZml4LWVkIGpRdWVyeS5FdmVudCByYXRoZXIgdGhhbiB0aGUgKHJlYWQtb25seSkgbmF0aXZlIGV2ZW50XG5cdFx0YXJnc1sgMCBdID0gZXZlbnQ7XG5cblx0XHRmb3IgKCBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKyApIHtcblx0XHRcdGFyZ3NbIGkgXSA9IGFyZ3VtZW50c1sgaSBdO1xuXHRcdH1cblxuXHRcdGV2ZW50LmRlbGVnYXRlVGFyZ2V0ID0gdGhpcztcblxuXHRcdC8vIENhbGwgdGhlIHByZURpc3BhdGNoIGhvb2sgZm9yIHRoZSBtYXBwZWQgdHlwZSwgYW5kIGxldCBpdCBiYWlsIGlmIGRlc2lyZWRcblx0XHRpZiAoIHNwZWNpYWwucHJlRGlzcGF0Y2ggJiYgc3BlY2lhbC5wcmVEaXNwYXRjaC5jYWxsKCB0aGlzLCBldmVudCApID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBEZXRlcm1pbmUgaGFuZGxlcnNcblx0XHRoYW5kbGVyUXVldWUgPSBqUXVlcnkuZXZlbnQuaGFuZGxlcnMuY2FsbCggdGhpcywgZXZlbnQsIGhhbmRsZXJzICk7XG5cblx0XHQvLyBSdW4gZGVsZWdhdGVzIGZpcnN0OyB0aGV5IG1heSB3YW50IHRvIHN0b3AgcHJvcGFnYXRpb24gYmVuZWF0aCB1c1xuXHRcdGkgPSAwO1xuXHRcdHdoaWxlICggKCBtYXRjaGVkID0gaGFuZGxlclF1ZXVlWyBpKysgXSApICYmICFldmVudC5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpICkge1xuXHRcdFx0ZXZlbnQuY3VycmVudFRhcmdldCA9IG1hdGNoZWQuZWxlbTtcblxuXHRcdFx0aiA9IDA7XG5cdFx0XHR3aGlsZSAoICggaGFuZGxlT2JqID0gbWF0Y2hlZC5oYW5kbGVyc1sgaisrIF0gKSAmJlxuXHRcdFx0XHQhZXZlbnQuaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQoKSApIHtcblxuXHRcdFx0XHQvLyBJZiB0aGUgZXZlbnQgaXMgbmFtZXNwYWNlZCwgdGhlbiBlYWNoIGhhbmRsZXIgaXMgb25seSBpbnZva2VkIGlmIGl0IGlzXG5cdFx0XHRcdC8vIHNwZWNpYWxseSB1bml2ZXJzYWwgb3IgaXRzIG5hbWVzcGFjZXMgYXJlIGEgc3VwZXJzZXQgb2YgdGhlIGV2ZW50J3MuXG5cdFx0XHRcdGlmICggIWV2ZW50LnJuYW1lc3BhY2UgfHwgaGFuZGxlT2JqLm5hbWVzcGFjZSA9PT0gZmFsc2UgfHxcblx0XHRcdFx0XHRldmVudC5ybmFtZXNwYWNlLnRlc3QoIGhhbmRsZU9iai5uYW1lc3BhY2UgKSApIHtcblxuXHRcdFx0XHRcdGV2ZW50LmhhbmRsZU9iaiA9IGhhbmRsZU9iajtcblx0XHRcdFx0XHRldmVudC5kYXRhID0gaGFuZGxlT2JqLmRhdGE7XG5cblx0XHRcdFx0XHRyZXQgPSAoICggalF1ZXJ5LmV2ZW50LnNwZWNpYWxbIGhhbmRsZU9iai5vcmlnVHlwZSBdIHx8IHt9ICkuaGFuZGxlIHx8XG5cdFx0XHRcdFx0XHRoYW5kbGVPYmouaGFuZGxlciApLmFwcGx5KCBtYXRjaGVkLmVsZW0sIGFyZ3MgKTtcblxuXHRcdFx0XHRcdGlmICggcmV0ICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0XHRpZiAoICggZXZlbnQucmVzdWx0ID0gcmV0ICkgPT09IGZhbHNlICkge1xuXHRcdFx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0XHRldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBDYWxsIHRoZSBwb3N0RGlzcGF0Y2ggaG9vayBmb3IgdGhlIG1hcHBlZCB0eXBlXG5cdFx0aWYgKCBzcGVjaWFsLnBvc3REaXNwYXRjaCApIHtcblx0XHRcdHNwZWNpYWwucG9zdERpc3BhdGNoLmNhbGwoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGV2ZW50LnJlc3VsdDtcblx0fSxcblxuXHRoYW5kbGVyczogZnVuY3Rpb24oIGV2ZW50LCBoYW5kbGVycyApIHtcblx0XHR2YXIgaSwgaGFuZGxlT2JqLCBzZWwsIG1hdGNoZWRIYW5kbGVycywgbWF0Y2hlZFNlbGVjdG9ycyxcblx0XHRcdGhhbmRsZXJRdWV1ZSA9IFtdLFxuXHRcdFx0ZGVsZWdhdGVDb3VudCA9IGhhbmRsZXJzLmRlbGVnYXRlQ291bnQsXG5cdFx0XHRjdXIgPSBldmVudC50YXJnZXQ7XG5cblx0XHQvLyBGaW5kIGRlbGVnYXRlIGhhbmRsZXJzXG5cdFx0aWYgKCBkZWxlZ2F0ZUNvdW50ICYmXG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFIDw9OVxuXHRcdFx0Ly8gQmxhY2staG9sZSBTVkcgPHVzZT4gaW5zdGFuY2UgdHJlZXMgKHRyYWMtMTMxODApXG5cdFx0XHRjdXIubm9kZVR5cGUgJiZcblxuXHRcdFx0Ly8gU3VwcG9ydDogRmlyZWZveCA8PTQyXG5cdFx0XHQvLyBTdXBwcmVzcyBzcGVjLXZpb2xhdGluZyBjbGlja3MgaW5kaWNhdGluZyBhIG5vbi1wcmltYXJ5IHBvaW50ZXIgYnV0dG9uICh0cmFjLTM4NjEpXG5cdFx0XHQvLyBodHRwczovL3d3dy53My5vcmcvVFIvRE9NLUxldmVsLTMtRXZlbnRzLyNldmVudC10eXBlLWNsaWNrXG5cdFx0XHQvLyBTdXBwb3J0OiBJRSAxMSBvbmx5XG5cdFx0XHQvLyAuLi5idXQgbm90IGFycm93IGtleSBcImNsaWNrc1wiIG9mIHJhZGlvIGlucHV0cywgd2hpY2ggY2FuIGhhdmUgYGJ1dHRvbmAgLTEgKGdoLTIzNDMpXG5cdFx0XHQhKCBldmVudC50eXBlID09PSBcImNsaWNrXCIgJiYgZXZlbnQuYnV0dG9uID49IDEgKSApIHtcblxuXHRcdFx0Zm9yICggOyBjdXIgIT09IHRoaXM7IGN1ciA9IGN1ci5wYXJlbnROb2RlIHx8IHRoaXMgKSB7XG5cblx0XHRcdFx0Ly8gRG9uJ3QgY2hlY2sgbm9uLWVsZW1lbnRzICgjMTMyMDgpXG5cdFx0XHRcdC8vIERvbid0IHByb2Nlc3MgY2xpY2tzIG9uIGRpc2FibGVkIGVsZW1lbnRzICgjNjkxMSwgIzgxNjUsICMxMTM4MiwgIzExNzY0KVxuXHRcdFx0XHRpZiAoIGN1ci5ub2RlVHlwZSA9PT0gMSAmJiAhKCBldmVudC50eXBlID09PSBcImNsaWNrXCIgJiYgY3VyLmRpc2FibGVkID09PSB0cnVlICkgKSB7XG5cdFx0XHRcdFx0bWF0Y2hlZEhhbmRsZXJzID0gW107XG5cdFx0XHRcdFx0bWF0Y2hlZFNlbGVjdG9ycyA9IHt9O1xuXHRcdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgZGVsZWdhdGVDb3VudDsgaSsrICkge1xuXHRcdFx0XHRcdFx0aGFuZGxlT2JqID0gaGFuZGxlcnNbIGkgXTtcblxuXHRcdFx0XHRcdFx0Ly8gRG9uJ3QgY29uZmxpY3Qgd2l0aCBPYmplY3QucHJvdG90eXBlIHByb3BlcnRpZXMgKCMxMzIwMylcblx0XHRcdFx0XHRcdHNlbCA9IGhhbmRsZU9iai5zZWxlY3RvciArIFwiIFwiO1xuXG5cdFx0XHRcdFx0XHRpZiAoIG1hdGNoZWRTZWxlY3RvcnNbIHNlbCBdID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0XHRcdG1hdGNoZWRTZWxlY3RvcnNbIHNlbCBdID0gaGFuZGxlT2JqLm5lZWRzQ29udGV4dCA/XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5KCBzZWwsIHRoaXMgKS5pbmRleCggY3VyICkgPiAtMSA6XG5cdFx0XHRcdFx0XHRcdFx0alF1ZXJ5LmZpbmQoIHNlbCwgdGhpcywgbnVsbCwgWyBjdXIgXSApLmxlbmd0aDtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmICggbWF0Y2hlZFNlbGVjdG9yc1sgc2VsIF0gKSB7XG5cdFx0XHRcdFx0XHRcdG1hdGNoZWRIYW5kbGVycy5wdXNoKCBoYW5kbGVPYmogKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCBtYXRjaGVkSGFuZGxlcnMubGVuZ3RoICkge1xuXHRcdFx0XHRcdFx0aGFuZGxlclF1ZXVlLnB1c2goIHsgZWxlbTogY3VyLCBoYW5kbGVyczogbWF0Y2hlZEhhbmRsZXJzIH0gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBBZGQgdGhlIHJlbWFpbmluZyAoZGlyZWN0bHktYm91bmQpIGhhbmRsZXJzXG5cdFx0Y3VyID0gdGhpcztcblx0XHRpZiAoIGRlbGVnYXRlQ291bnQgPCBoYW5kbGVycy5sZW5ndGggKSB7XG5cdFx0XHRoYW5kbGVyUXVldWUucHVzaCggeyBlbGVtOiBjdXIsIGhhbmRsZXJzOiBoYW5kbGVycy5zbGljZSggZGVsZWdhdGVDb3VudCApIH0gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gaGFuZGxlclF1ZXVlO1xuXHR9LFxuXG5cdGFkZFByb3A6IGZ1bmN0aW9uKCBuYW1lLCBob29rICkge1xuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggalF1ZXJ5LkV2ZW50LnByb3RvdHlwZSwgbmFtZSwge1xuXHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZSxcblxuXHRcdFx0Z2V0OiBpc0Z1bmN0aW9uKCBob29rICkgP1xuXHRcdFx0XHRmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRpZiAoIHRoaXMub3JpZ2luYWxFdmVudCApIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuIGhvb2soIHRoaXMub3JpZ2luYWxFdmVudCApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSA6XG5cdFx0XHRcdGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGlmICggdGhpcy5vcmlnaW5hbEV2ZW50ICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy5vcmlnaW5hbEV2ZW50WyBuYW1lIF07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9LFxuXG5cdFx0XHRzZXQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCBuYW1lLCB7XG5cdFx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdFx0XHRjb25maWd1cmFibGU6IHRydWUsXG5cdFx0XHRcdFx0d3JpdGFibGU6IHRydWUsXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlXG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0Zml4OiBmdW5jdGlvbiggb3JpZ2luYWxFdmVudCApIHtcblx0XHRyZXR1cm4gb3JpZ2luYWxFdmVudFsgalF1ZXJ5LmV4cGFuZG8gXSA/XG5cdFx0XHRvcmlnaW5hbEV2ZW50IDpcblx0XHRcdG5ldyBqUXVlcnkuRXZlbnQoIG9yaWdpbmFsRXZlbnQgKTtcblx0fSxcblxuXHRzcGVjaWFsOiB7XG5cdFx0bG9hZDoge1xuXG5cdFx0XHQvLyBQcmV2ZW50IHRyaWdnZXJlZCBpbWFnZS5sb2FkIGV2ZW50cyBmcm9tIGJ1YmJsaW5nIHRvIHdpbmRvdy5sb2FkXG5cdFx0XHRub0J1YmJsZTogdHJ1ZVxuXHRcdH0sXG5cdFx0Y2xpY2s6IHtcblxuXHRcdFx0Ly8gVXRpbGl6ZSBuYXRpdmUgZXZlbnQgdG8gZW5zdXJlIGNvcnJlY3Qgc3RhdGUgZm9yIGNoZWNrYWJsZSBpbnB1dHNcblx0XHRcdHNldHVwOiBmdW5jdGlvbiggZGF0YSApIHtcblxuXHRcdFx0XHQvLyBGb3IgbXV0dWFsIGNvbXByZXNzaWJpbGl0eSB3aXRoIF9kZWZhdWx0LCByZXBsYWNlIGB0aGlzYCBhY2Nlc3Mgd2l0aCBhIGxvY2FsIHZhci5cblx0XHRcdFx0Ly8gYHx8IGRhdGFgIGlzIGRlYWQgY29kZSBtZWFudCBvbmx5IHRvIHByZXNlcnZlIHRoZSB2YXJpYWJsZSB0aHJvdWdoIG1pbmlmaWNhdGlvbi5cblx0XHRcdFx0dmFyIGVsID0gdGhpcyB8fCBkYXRhO1xuXG5cdFx0XHRcdC8vIENsYWltIHRoZSBmaXJzdCBoYW5kbGVyXG5cdFx0XHRcdGlmICggcmNoZWNrYWJsZVR5cGUudGVzdCggZWwudHlwZSApICYmXG5cdFx0XHRcdFx0ZWwuY2xpY2sgJiYgbm9kZU5hbWUoIGVsLCBcImlucHV0XCIgKSApIHtcblxuXHRcdFx0XHRcdC8vIGRhdGFQcml2LnNldCggZWwsIFwiY2xpY2tcIiwgLi4uIClcblx0XHRcdFx0XHRsZXZlcmFnZU5hdGl2ZSggZWwsIFwiY2xpY2tcIiwgcmV0dXJuVHJ1ZSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUmV0dXJuIGZhbHNlIHRvIGFsbG93IG5vcm1hbCBwcm9jZXNzaW5nIGluIHRoZSBjYWxsZXJcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fSxcblx0XHRcdHRyaWdnZXI6IGZ1bmN0aW9uKCBkYXRhICkge1xuXG5cdFx0XHRcdC8vIEZvciBtdXR1YWwgY29tcHJlc3NpYmlsaXR5IHdpdGggX2RlZmF1bHQsIHJlcGxhY2UgYHRoaXNgIGFjY2VzcyB3aXRoIGEgbG9jYWwgdmFyLlxuXHRcdFx0XHQvLyBgfHwgZGF0YWAgaXMgZGVhZCBjb2RlIG1lYW50IG9ubHkgdG8gcHJlc2VydmUgdGhlIHZhcmlhYmxlIHRocm91Z2ggbWluaWZpY2F0aW9uLlxuXHRcdFx0XHR2YXIgZWwgPSB0aGlzIHx8IGRhdGE7XG5cblx0XHRcdFx0Ly8gRm9yY2Ugc2V0dXAgYmVmb3JlIHRyaWdnZXJpbmcgYSBjbGlja1xuXHRcdFx0XHRpZiAoIHJjaGVja2FibGVUeXBlLnRlc3QoIGVsLnR5cGUgKSAmJlxuXHRcdFx0XHRcdGVsLmNsaWNrICYmIG5vZGVOYW1lKCBlbCwgXCJpbnB1dFwiICkgKSB7XG5cblx0XHRcdFx0XHRsZXZlcmFnZU5hdGl2ZSggZWwsIFwiY2xpY2tcIiApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUmV0dXJuIG5vbi1mYWxzZSB0byBhbGxvdyBub3JtYWwgZXZlbnQtcGF0aCBwcm9wYWdhdGlvblxuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH0sXG5cblx0XHRcdC8vIEZvciBjcm9zcy1icm93c2VyIGNvbnNpc3RlbmN5LCBzdXBwcmVzcyBuYXRpdmUgLmNsaWNrKCkgb24gbGlua3Ncblx0XHRcdC8vIEFsc28gcHJldmVudCBpdCBpZiB3ZSdyZSBjdXJyZW50bHkgaW5zaWRlIGEgbGV2ZXJhZ2VkIG5hdGl2ZS1ldmVudCBzdGFja1xuXHRcdFx0X2RlZmF1bHQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dmFyIHRhcmdldCA9IGV2ZW50LnRhcmdldDtcblx0XHRcdFx0cmV0dXJuIHJjaGVja2FibGVUeXBlLnRlc3QoIHRhcmdldC50eXBlICkgJiZcblx0XHRcdFx0XHR0YXJnZXQuY2xpY2sgJiYgbm9kZU5hbWUoIHRhcmdldCwgXCJpbnB1dFwiICkgJiZcblx0XHRcdFx0XHRkYXRhUHJpdi5nZXQoIHRhcmdldCwgXCJjbGlja1wiICkgfHxcblx0XHRcdFx0XHRub2RlTmFtZSggdGFyZ2V0LCBcImFcIiApO1xuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHRiZWZvcmV1bmxvYWQ6IHtcblx0XHRcdHBvc3REaXNwYXRjaDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0XHRcdC8vIFN1cHBvcnQ6IEZpcmVmb3ggMjArXG5cdFx0XHRcdC8vIEZpcmVmb3ggZG9lc24ndCBhbGVydCBpZiB0aGUgcmV0dXJuVmFsdWUgZmllbGQgaXMgbm90IHNldC5cblx0XHRcdFx0aWYgKCBldmVudC5yZXN1bHQgIT09IHVuZGVmaW5lZCAmJiBldmVudC5vcmlnaW5hbEV2ZW50ICkge1xuXHRcdFx0XHRcdGV2ZW50Lm9yaWdpbmFsRXZlbnQucmV0dXJuVmFsdWUgPSBldmVudC5yZXN1bHQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cbn07XG5cbi8vIEVuc3VyZSB0aGUgcHJlc2VuY2Ugb2YgYW4gZXZlbnQgbGlzdGVuZXIgdGhhdCBoYW5kbGVzIG1hbnVhbGx5LXRyaWdnZXJlZFxuLy8gc3ludGhldGljIGV2ZW50cyBieSBpbnRlcnJ1cHRpbmcgcHJvZ3Jlc3MgdW50aWwgcmVpbnZva2VkIGluIHJlc3BvbnNlIHRvXG4vLyAqbmF0aXZlKiBldmVudHMgdGhhdCBpdCBmaXJlcyBkaXJlY3RseSwgZW5zdXJpbmcgdGhhdCBzdGF0ZSBjaGFuZ2VzIGhhdmVcbi8vIGFscmVhZHkgb2NjdXJyZWQgYmVmb3JlIG90aGVyIGxpc3RlbmVycyBhcmUgaW52b2tlZC5cbmZ1bmN0aW9uIGxldmVyYWdlTmF0aXZlKCBlbCwgdHlwZSwgZXhwZWN0U3luYyApIHtcblxuXHQvLyBNaXNzaW5nIGV4cGVjdFN5bmMgaW5kaWNhdGVzIGEgdHJpZ2dlciBjYWxsLCB3aGljaCBtdXN0IGZvcmNlIHNldHVwIHRocm91Z2ggalF1ZXJ5LmV2ZW50LmFkZFxuXHRpZiAoICFleHBlY3RTeW5jICkge1xuXHRcdGlmICggZGF0YVByaXYuZ2V0KCBlbCwgdHlwZSApID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRqUXVlcnkuZXZlbnQuYWRkKCBlbCwgdHlwZSwgcmV0dXJuVHJ1ZSApO1xuXHRcdH1cblx0XHRyZXR1cm47XG5cdH1cblxuXHQvLyBSZWdpc3RlciB0aGUgY29udHJvbGxlciBhcyBhIHNwZWNpYWwgdW5pdmVyc2FsIGhhbmRsZXIgZm9yIGFsbCBldmVudCBuYW1lc3BhY2VzXG5cdGRhdGFQcml2LnNldCggZWwsIHR5cGUsIGZhbHNlICk7XG5cdGpRdWVyeS5ldmVudC5hZGQoIGVsLCB0eXBlLCB7XG5cdFx0bmFtZXNwYWNlOiBmYWxzZSxcblx0XHRoYW5kbGVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHR2YXIgbm90QXN5bmMsIHJlc3VsdCxcblx0XHRcdFx0c2F2ZWQgPSBkYXRhUHJpdi5nZXQoIHRoaXMsIHR5cGUgKTtcblxuXHRcdFx0aWYgKCAoIGV2ZW50LmlzVHJpZ2dlciAmIDEgKSAmJiB0aGlzWyB0eXBlIF0gKSB7XG5cblx0XHRcdFx0Ly8gSW50ZXJydXB0IHByb2Nlc3Npbmcgb2YgdGhlIG91dGVyIHN5bnRoZXRpYyAudHJpZ2dlcigpZWQgZXZlbnRcblx0XHRcdFx0Ly8gU2F2ZWQgZGF0YSBzaG91bGQgYmUgZmFsc2UgaW4gc3VjaCBjYXNlcywgYnV0IG1pZ2h0IGJlIGEgbGVmdG92ZXIgY2FwdHVyZSBvYmplY3Rcblx0XHRcdFx0Ly8gZnJvbSBhbiBhc3luYyBuYXRpdmUgaGFuZGxlciAoZ2gtNDM1MClcblx0XHRcdFx0aWYgKCAhc2F2ZWQubGVuZ3RoICkge1xuXG5cdFx0XHRcdFx0Ly8gU3RvcmUgYXJndW1lbnRzIGZvciB1c2Ugd2hlbiBoYW5kbGluZyB0aGUgaW5uZXIgbmF0aXZlIGV2ZW50XG5cdFx0XHRcdFx0Ly8gVGhlcmUgd2lsbCBhbHdheXMgYmUgYXQgbGVhc3Qgb25lIGFyZ3VtZW50IChhbiBldmVudCBvYmplY3QpLCBzbyB0aGlzIGFycmF5XG5cdFx0XHRcdFx0Ly8gd2lsbCBub3QgYmUgY29uZnVzZWQgd2l0aCBhIGxlZnRvdmVyIGNhcHR1cmUgb2JqZWN0LlxuXHRcdFx0XHRcdHNhdmVkID0gc2xpY2UuY2FsbCggYXJndW1lbnRzICk7XG5cdFx0XHRcdFx0ZGF0YVByaXYuc2V0KCB0aGlzLCB0eXBlLCBzYXZlZCApO1xuXG5cdFx0XHRcdFx0Ly8gVHJpZ2dlciB0aGUgbmF0aXZlIGV2ZW50IGFuZCBjYXB0dXJlIGl0cyByZXN1bHRcblx0XHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA8PTkgLSAxMStcblx0XHRcdFx0XHQvLyBmb2N1cygpIGFuZCBibHVyKCkgYXJlIGFzeW5jaHJvbm91c1xuXHRcdFx0XHRcdG5vdEFzeW5jID0gZXhwZWN0U3luYyggdGhpcywgdHlwZSApO1xuXHRcdFx0XHRcdHRoaXNbIHR5cGUgXSgpO1xuXHRcdFx0XHRcdHJlc3VsdCA9IGRhdGFQcml2LmdldCggdGhpcywgdHlwZSApO1xuXHRcdFx0XHRcdGlmICggc2F2ZWQgIT09IHJlc3VsdCB8fCBub3RBc3luYyApIHtcblx0XHRcdFx0XHRcdGRhdGFQcml2LnNldCggdGhpcywgdHlwZSwgZmFsc2UgKTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0cmVzdWx0ID0ge307XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmICggc2F2ZWQgIT09IHJlc3VsdCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gQ2FuY2VsIHRoZSBvdXRlciBzeW50aGV0aWMgZXZlbnRcblx0XHRcdFx0XHRcdGV2ZW50LnN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpO1xuXHRcdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHRcdHJldHVybiByZXN1bHQudmFsdWU7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIElmIHRoaXMgaXMgYW4gaW5uZXIgc3ludGhldGljIGV2ZW50IGZvciBhbiBldmVudCB3aXRoIGEgYnViYmxpbmcgc3Vycm9nYXRlXG5cdFx0XHRcdC8vIChmb2N1cyBvciBibHVyKSwgYXNzdW1lIHRoYXQgdGhlIHN1cnJvZ2F0ZSBhbHJlYWR5IHByb3BhZ2F0ZWQgZnJvbSB0cmlnZ2VyaW5nIHRoZVxuXHRcdFx0XHQvLyBuYXRpdmUgZXZlbnQgYW5kIHByZXZlbnQgdGhhdCBmcm9tIGhhcHBlbmluZyBhZ2FpbiBoZXJlLlxuXHRcdFx0XHQvLyBUaGlzIHRlY2huaWNhbGx5IGdldHMgdGhlIG9yZGVyaW5nIHdyb25nIHcuci50LiB0byBgLnRyaWdnZXIoKWAgKGluIHdoaWNoIHRoZVxuXHRcdFx0XHQvLyBidWJibGluZyBzdXJyb2dhdGUgcHJvcGFnYXRlcyAqYWZ0ZXIqIHRoZSBub24tYnViYmxpbmcgYmFzZSksIGJ1dCB0aGF0IHNlZW1zXG5cdFx0XHRcdC8vIGxlc3MgYmFkIHRoYW4gZHVwbGljYXRpb24uXG5cdFx0XHRcdH0gZWxzZSBpZiAoICggalF1ZXJ5LmV2ZW50LnNwZWNpYWxbIHR5cGUgXSB8fCB7fSApLmRlbGVnYXRlVHlwZSApIHtcblx0XHRcdFx0XHRldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcblx0XHRcdFx0fVxuXG5cdFx0XHQvLyBJZiB0aGlzIGlzIGEgbmF0aXZlIGV2ZW50IHRyaWdnZXJlZCBhYm92ZSwgZXZlcnl0aGluZyBpcyBub3cgaW4gb3JkZXJcblx0XHRcdC8vIEZpcmUgYW4gaW5uZXIgc3ludGhldGljIGV2ZW50IHdpdGggdGhlIG9yaWdpbmFsIGFyZ3VtZW50c1xuXHRcdFx0fSBlbHNlIGlmICggc2F2ZWQubGVuZ3RoICkge1xuXG5cdFx0XHRcdC8vIC4uLmFuZCBjYXB0dXJlIHRoZSByZXN1bHRcblx0XHRcdFx0ZGF0YVByaXYuc2V0KCB0aGlzLCB0eXBlLCB7XG5cdFx0XHRcdFx0dmFsdWU6IGpRdWVyeS5ldmVudC50cmlnZ2VyKFxuXG5cdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA8PTkgLSAxMStcblx0XHRcdFx0XHRcdC8vIEV4dGVuZCB3aXRoIHRoZSBwcm90b3R5cGUgdG8gcmVzZXQgdGhlIGFib3ZlIHN0b3BJbW1lZGlhdGVQcm9wYWdhdGlvbigpXG5cdFx0XHRcdFx0XHRqUXVlcnkuZXh0ZW5kKCBzYXZlZFsgMCBdLCBqUXVlcnkuRXZlbnQucHJvdG90eXBlICksXG5cdFx0XHRcdFx0XHRzYXZlZC5zbGljZSggMSApLFxuXHRcdFx0XHRcdFx0dGhpc1xuXHRcdFx0XHRcdClcblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdC8vIEFib3J0IGhhbmRsaW5nIG9mIHRoZSBuYXRpdmUgZXZlbnRcblx0XHRcdFx0ZXZlbnQuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9ICk7XG59XG5cbmpRdWVyeS5yZW1vdmVFdmVudCA9IGZ1bmN0aW9uKCBlbGVtLCB0eXBlLCBoYW5kbGUgKSB7XG5cblx0Ly8gVGhpcyBcImlmXCIgaXMgbmVlZGVkIGZvciBwbGFpbiBvYmplY3RzXG5cdGlmICggZWxlbS5yZW1vdmVFdmVudExpc3RlbmVyICkge1xuXHRcdGVsZW0ucmVtb3ZlRXZlbnRMaXN0ZW5lciggdHlwZSwgaGFuZGxlICk7XG5cdH1cbn07XG5cbmpRdWVyeS5FdmVudCA9IGZ1bmN0aW9uKCBzcmMsIHByb3BzICkge1xuXG5cdC8vIEFsbG93IGluc3RhbnRpYXRpb24gd2l0aG91dCB0aGUgJ25ldycga2V5d29yZFxuXHRpZiAoICEoIHRoaXMgaW5zdGFuY2VvZiBqUXVlcnkuRXZlbnQgKSApIHtcblx0XHRyZXR1cm4gbmV3IGpRdWVyeS5FdmVudCggc3JjLCBwcm9wcyApO1xuXHR9XG5cblx0Ly8gRXZlbnQgb2JqZWN0XG5cdGlmICggc3JjICYmIHNyYy50eXBlICkge1xuXHRcdHRoaXMub3JpZ2luYWxFdmVudCA9IHNyYztcblx0XHR0aGlzLnR5cGUgPSBzcmMudHlwZTtcblxuXHRcdC8vIEV2ZW50cyBidWJibGluZyB1cCB0aGUgZG9jdW1lbnQgbWF5IGhhdmUgYmVlbiBtYXJrZWQgYXMgcHJldmVudGVkXG5cdFx0Ly8gYnkgYSBoYW5kbGVyIGxvd2VyIGRvd24gdGhlIHRyZWU7IHJlZmxlY3QgdGhlIGNvcnJlY3QgdmFsdWUuXG5cdFx0dGhpcy5pc0RlZmF1bHRQcmV2ZW50ZWQgPSBzcmMuZGVmYXVsdFByZXZlbnRlZCB8fFxuXHRcdFx0XHRzcmMuZGVmYXVsdFByZXZlbnRlZCA9PT0gdW5kZWZpbmVkICYmXG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogQW5kcm9pZCA8PTIuMyBvbmx5XG5cdFx0XHRcdHNyYy5yZXR1cm5WYWx1ZSA9PT0gZmFsc2UgP1xuXHRcdFx0cmV0dXJuVHJ1ZSA6XG5cdFx0XHRyZXR1cm5GYWxzZTtcblxuXHRcdC8vIENyZWF0ZSB0YXJnZXQgcHJvcGVydGllc1xuXHRcdC8vIFN1cHBvcnQ6IFNhZmFyaSA8PTYgLSA3IG9ubHlcblx0XHQvLyBUYXJnZXQgc2hvdWxkIG5vdCBiZSBhIHRleHQgbm9kZSAoIzUwNCwgIzEzMTQzKVxuXHRcdHRoaXMudGFyZ2V0ID0gKCBzcmMudGFyZ2V0ICYmIHNyYy50YXJnZXQubm9kZVR5cGUgPT09IDMgKSA/XG5cdFx0XHRzcmMudGFyZ2V0LnBhcmVudE5vZGUgOlxuXHRcdFx0c3JjLnRhcmdldDtcblxuXHRcdHRoaXMuY3VycmVudFRhcmdldCA9IHNyYy5jdXJyZW50VGFyZ2V0O1xuXHRcdHRoaXMucmVsYXRlZFRhcmdldCA9IHNyYy5yZWxhdGVkVGFyZ2V0O1xuXG5cdC8vIEV2ZW50IHR5cGVcblx0fSBlbHNlIHtcblx0XHR0aGlzLnR5cGUgPSBzcmM7XG5cdH1cblxuXHQvLyBQdXQgZXhwbGljaXRseSBwcm92aWRlZCBwcm9wZXJ0aWVzIG9udG8gdGhlIGV2ZW50IG9iamVjdFxuXHRpZiAoIHByb3BzICkge1xuXHRcdGpRdWVyeS5leHRlbmQoIHRoaXMsIHByb3BzICk7XG5cdH1cblxuXHQvLyBDcmVhdGUgYSB0aW1lc3RhbXAgaWYgaW5jb21pbmcgZXZlbnQgZG9lc24ndCBoYXZlIG9uZVxuXHR0aGlzLnRpbWVTdGFtcCA9IHNyYyAmJiBzcmMudGltZVN0YW1wIHx8IERhdGUubm93KCk7XG5cblx0Ly8gTWFyayBpdCBhcyBmaXhlZFxuXHR0aGlzWyBqUXVlcnkuZXhwYW5kbyBdID0gdHJ1ZTtcbn07XG5cbi8vIGpRdWVyeS5FdmVudCBpcyBiYXNlZCBvbiBET00zIEV2ZW50cyBhcyBzcGVjaWZpZWQgYnkgdGhlIEVDTUFTY3JpcHQgTGFuZ3VhZ2UgQmluZGluZ1xuLy8gaHR0cHM6Ly93d3cudzMub3JnL1RSLzIwMDMvV0QtRE9NLUxldmVsLTMtRXZlbnRzLTIwMDMwMzMxL2VjbWEtc2NyaXB0LWJpbmRpbmcuaHRtbFxualF1ZXJ5LkV2ZW50LnByb3RvdHlwZSA9IHtcblx0Y29uc3RydWN0b3I6IGpRdWVyeS5FdmVudCxcblx0aXNEZWZhdWx0UHJldmVudGVkOiByZXR1cm5GYWxzZSxcblx0aXNQcm9wYWdhdGlvblN0b3BwZWQ6IHJldHVybkZhbHNlLFxuXHRpc0ltbWVkaWF0ZVByb3BhZ2F0aW9uU3RvcHBlZDogcmV0dXJuRmFsc2UsXG5cdGlzU2ltdWxhdGVkOiBmYWxzZSxcblxuXHRwcmV2ZW50RGVmYXVsdDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGUgPSB0aGlzLm9yaWdpbmFsRXZlbnQ7XG5cblx0XHR0aGlzLmlzRGVmYXVsdFByZXZlbnRlZCA9IHJldHVyblRydWU7XG5cblx0XHRpZiAoIGUgJiYgIXRoaXMuaXNTaW11bGF0ZWQgKSB7XG5cdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0fVxuXHR9LFxuXHRzdG9wUHJvcGFnYXRpb246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBlID0gdGhpcy5vcmlnaW5hbEV2ZW50O1xuXG5cdFx0dGhpcy5pc1Byb3BhZ2F0aW9uU3RvcHBlZCA9IHJldHVyblRydWU7XG5cblx0XHRpZiAoIGUgJiYgIXRoaXMuaXNTaW11bGF0ZWQgKSB7XG5cdFx0XHRlLnN0b3BQcm9wYWdhdGlvbigpO1xuXHRcdH1cblx0fSxcblx0c3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZSA9IHRoaXMub3JpZ2luYWxFdmVudDtcblxuXHRcdHRoaXMuaXNJbW1lZGlhdGVQcm9wYWdhdGlvblN0b3BwZWQgPSByZXR1cm5UcnVlO1xuXG5cdFx0aWYgKCBlICYmICF0aGlzLmlzU2ltdWxhdGVkICkge1xuXHRcdFx0ZS5zdG9wSW1tZWRpYXRlUHJvcGFnYXRpb24oKTtcblx0XHR9XG5cblx0XHR0aGlzLnN0b3BQcm9wYWdhdGlvbigpO1xuXHR9XG59O1xuXG4vLyBJbmNsdWRlcyBhbGwgY29tbW9uIGV2ZW50IHByb3BzIGluY2x1ZGluZyBLZXlFdmVudCBhbmQgTW91c2VFdmVudCBzcGVjaWZpYyBwcm9wc1xualF1ZXJ5LmVhY2goIHtcblx0YWx0S2V5OiB0cnVlLFxuXHRidWJibGVzOiB0cnVlLFxuXHRjYW5jZWxhYmxlOiB0cnVlLFxuXHRjaGFuZ2VkVG91Y2hlczogdHJ1ZSxcblx0Y3RybEtleTogdHJ1ZSxcblx0ZGV0YWlsOiB0cnVlLFxuXHRldmVudFBoYXNlOiB0cnVlLFxuXHRtZXRhS2V5OiB0cnVlLFxuXHRwYWdlWDogdHJ1ZSxcblx0cGFnZVk6IHRydWUsXG5cdHNoaWZ0S2V5OiB0cnVlLFxuXHR2aWV3OiB0cnVlLFxuXHRcImNoYXJcIjogdHJ1ZSxcblx0Y29kZTogdHJ1ZSxcblx0Y2hhckNvZGU6IHRydWUsXG5cdGtleTogdHJ1ZSxcblx0a2V5Q29kZTogdHJ1ZSxcblx0YnV0dG9uOiB0cnVlLFxuXHRidXR0b25zOiB0cnVlLFxuXHRjbGllbnRYOiB0cnVlLFxuXHRjbGllbnRZOiB0cnVlLFxuXHRvZmZzZXRYOiB0cnVlLFxuXHRvZmZzZXRZOiB0cnVlLFxuXHRwb2ludGVySWQ6IHRydWUsXG5cdHBvaW50ZXJUeXBlOiB0cnVlLFxuXHRzY3JlZW5YOiB0cnVlLFxuXHRzY3JlZW5ZOiB0cnVlLFxuXHR0YXJnZXRUb3VjaGVzOiB0cnVlLFxuXHR0b0VsZW1lbnQ6IHRydWUsXG5cdHRvdWNoZXM6IHRydWUsXG5cblx0d2hpY2g6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgYnV0dG9uID0gZXZlbnQuYnV0dG9uO1xuXG5cdFx0Ly8gQWRkIHdoaWNoIGZvciBrZXkgZXZlbnRzXG5cdFx0aWYgKCBldmVudC53aGljaCA9PSBudWxsICYmIHJrZXlFdmVudC50ZXN0KCBldmVudC50eXBlICkgKSB7XG5cdFx0XHRyZXR1cm4gZXZlbnQuY2hhckNvZGUgIT0gbnVsbCA/IGV2ZW50LmNoYXJDb2RlIDogZXZlbnQua2V5Q29kZTtcblx0XHR9XG5cblx0XHQvLyBBZGQgd2hpY2ggZm9yIGNsaWNrOiAxID09PSBsZWZ0OyAyID09PSBtaWRkbGU7IDMgPT09IHJpZ2h0XG5cdFx0aWYgKCAhZXZlbnQud2hpY2ggJiYgYnV0dG9uICE9PSB1bmRlZmluZWQgJiYgcm1vdXNlRXZlbnQudGVzdCggZXZlbnQudHlwZSApICkge1xuXHRcdFx0aWYgKCBidXR0b24gJiAxICkge1xuXHRcdFx0XHRyZXR1cm4gMTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBidXR0b24gJiAyICkge1xuXHRcdFx0XHRyZXR1cm4gMztcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBidXR0b24gJiA0ICkge1xuXHRcdFx0XHRyZXR1cm4gMjtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIDA7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGV2ZW50LndoaWNoO1xuXHR9XG59LCBqUXVlcnkuZXZlbnQuYWRkUHJvcCApO1xuXG5qUXVlcnkuZWFjaCggeyBmb2N1czogXCJmb2N1c2luXCIsIGJsdXI6IFwiZm9jdXNvdXRcIiB9LCBmdW5jdGlvbiggdHlwZSwgZGVsZWdhdGVUeXBlICkge1xuXHRqUXVlcnkuZXZlbnQuc3BlY2lhbFsgdHlwZSBdID0ge1xuXG5cdFx0Ly8gVXRpbGl6ZSBuYXRpdmUgZXZlbnQgaWYgcG9zc2libGUgc28gYmx1ci9mb2N1cyBzZXF1ZW5jZSBpcyBjb3JyZWN0XG5cdFx0c2V0dXA6IGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBDbGFpbSB0aGUgZmlyc3QgaGFuZGxlclxuXHRcdFx0Ly8gZGF0YVByaXYuc2V0KCB0aGlzLCBcImZvY3VzXCIsIC4uLiApXG5cdFx0XHQvLyBkYXRhUHJpdi5zZXQoIHRoaXMsIFwiYmx1clwiLCAuLi4gKVxuXHRcdFx0bGV2ZXJhZ2VOYXRpdmUoIHRoaXMsIHR5cGUsIGV4cGVjdFN5bmMgKTtcblxuXHRcdFx0Ly8gUmV0dXJuIGZhbHNlIHRvIGFsbG93IG5vcm1hbCBwcm9jZXNzaW5nIGluIHRoZSBjYWxsZXJcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9LFxuXHRcdHRyaWdnZXI6IGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBGb3JjZSBzZXR1cCBiZWZvcmUgdHJpZ2dlclxuXHRcdFx0bGV2ZXJhZ2VOYXRpdmUoIHRoaXMsIHR5cGUgKTtcblxuXHRcdFx0Ly8gUmV0dXJuIG5vbi1mYWxzZSB0byBhbGxvdyBub3JtYWwgZXZlbnQtcGF0aCBwcm9wYWdhdGlvblxuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fSxcblxuXHRcdGRlbGVnYXRlVHlwZTogZGVsZWdhdGVUeXBlXG5cdH07XG59ICk7XG5cbi8vIENyZWF0ZSBtb3VzZWVudGVyL2xlYXZlIGV2ZW50cyB1c2luZyBtb3VzZW92ZXIvb3V0IGFuZCBldmVudC10aW1lIGNoZWNrc1xuLy8gc28gdGhhdCBldmVudCBkZWxlZ2F0aW9uIHdvcmtzIGluIGpRdWVyeS5cbi8vIERvIHRoZSBzYW1lIGZvciBwb2ludGVyZW50ZXIvcG9pbnRlcmxlYXZlIGFuZCBwb2ludGVyb3Zlci9wb2ludGVyb3V0XG4vL1xuLy8gU3VwcG9ydDogU2FmYXJpIDcgb25seVxuLy8gU2FmYXJpIHNlbmRzIG1vdXNlZW50ZXIgdG9vIG9mdGVuOyBzZWU6XG4vLyBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD00NzAyNThcbi8vIGZvciB0aGUgZGVzY3JpcHRpb24gb2YgdGhlIGJ1ZyAoaXQgZXhpc3RlZCBpbiBvbGRlciBDaHJvbWUgdmVyc2lvbnMgYXMgd2VsbCkuXG5qUXVlcnkuZWFjaCgge1xuXHRtb3VzZWVudGVyOiBcIm1vdXNlb3ZlclwiLFxuXHRtb3VzZWxlYXZlOiBcIm1vdXNlb3V0XCIsXG5cdHBvaW50ZXJlbnRlcjogXCJwb2ludGVyb3ZlclwiLFxuXHRwb2ludGVybGVhdmU6IFwicG9pbnRlcm91dFwiXG59LCBmdW5jdGlvbiggb3JpZywgZml4ICkge1xuXHRqUXVlcnkuZXZlbnQuc3BlY2lhbFsgb3JpZyBdID0ge1xuXHRcdGRlbGVnYXRlVHlwZTogZml4LFxuXHRcdGJpbmRUeXBlOiBmaXgsXG5cblx0XHRoYW5kbGU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHZhciByZXQsXG5cdFx0XHRcdHRhcmdldCA9IHRoaXMsXG5cdFx0XHRcdHJlbGF0ZWQgPSBldmVudC5yZWxhdGVkVGFyZ2V0LFxuXHRcdFx0XHRoYW5kbGVPYmogPSBldmVudC5oYW5kbGVPYmo7XG5cblx0XHRcdC8vIEZvciBtb3VzZWVudGVyL2xlYXZlIGNhbGwgdGhlIGhhbmRsZXIgaWYgcmVsYXRlZCBpcyBvdXRzaWRlIHRoZSB0YXJnZXQuXG5cdFx0XHQvLyBOQjogTm8gcmVsYXRlZFRhcmdldCBpZiB0aGUgbW91c2UgbGVmdC9lbnRlcmVkIHRoZSBicm93c2VyIHdpbmRvd1xuXHRcdFx0aWYgKCAhcmVsYXRlZCB8fCAoIHJlbGF0ZWQgIT09IHRhcmdldCAmJiAhalF1ZXJ5LmNvbnRhaW5zKCB0YXJnZXQsIHJlbGF0ZWQgKSApICkge1xuXHRcdFx0XHRldmVudC50eXBlID0gaGFuZGxlT2JqLm9yaWdUeXBlO1xuXHRcdFx0XHRyZXQgPSBoYW5kbGVPYmouaGFuZGxlci5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHRcdGV2ZW50LnR5cGUgPSBmaXg7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gcmV0O1xuXHRcdH1cblx0fTtcbn0gKTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXG5cdG9uOiBmdW5jdGlvbiggdHlwZXMsIHNlbGVjdG9yLCBkYXRhLCBmbiApIHtcblx0XHRyZXR1cm4gb24oIHRoaXMsIHR5cGVzLCBzZWxlY3RvciwgZGF0YSwgZm4gKTtcblx0fSxcblx0b25lOiBmdW5jdGlvbiggdHlwZXMsIHNlbGVjdG9yLCBkYXRhLCBmbiApIHtcblx0XHRyZXR1cm4gb24oIHRoaXMsIHR5cGVzLCBzZWxlY3RvciwgZGF0YSwgZm4sIDEgKTtcblx0fSxcblx0b2ZmOiBmdW5jdGlvbiggdHlwZXMsIHNlbGVjdG9yLCBmbiApIHtcblx0XHR2YXIgaGFuZGxlT2JqLCB0eXBlO1xuXHRcdGlmICggdHlwZXMgJiYgdHlwZXMucHJldmVudERlZmF1bHQgJiYgdHlwZXMuaGFuZGxlT2JqICkge1xuXG5cdFx0XHQvLyAoIGV2ZW50ICkgIGRpc3BhdGNoZWQgalF1ZXJ5LkV2ZW50XG5cdFx0XHRoYW5kbGVPYmogPSB0eXBlcy5oYW5kbGVPYmo7XG5cdFx0XHRqUXVlcnkoIHR5cGVzLmRlbGVnYXRlVGFyZ2V0ICkub2ZmKFxuXHRcdFx0XHRoYW5kbGVPYmoubmFtZXNwYWNlID9cblx0XHRcdFx0XHRoYW5kbGVPYmoub3JpZ1R5cGUgKyBcIi5cIiArIGhhbmRsZU9iai5uYW1lc3BhY2UgOlxuXHRcdFx0XHRcdGhhbmRsZU9iai5vcmlnVHlwZSxcblx0XHRcdFx0aGFuZGxlT2JqLnNlbGVjdG9yLFxuXHRcdFx0XHRoYW5kbGVPYmouaGFuZGxlclxuXHRcdFx0KTtcblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH1cblx0XHRpZiAoIHR5cGVvZiB0eXBlcyA9PT0gXCJvYmplY3RcIiApIHtcblxuXHRcdFx0Ly8gKCB0eXBlcy1vYmplY3QgWywgc2VsZWN0b3JdIClcblx0XHRcdGZvciAoIHR5cGUgaW4gdHlwZXMgKSB7XG5cdFx0XHRcdHRoaXMub2ZmKCB0eXBlLCBzZWxlY3RvciwgdHlwZXNbIHR5cGUgXSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXHRcdGlmICggc2VsZWN0b3IgPT09IGZhbHNlIHx8IHR5cGVvZiBzZWxlY3RvciA9PT0gXCJmdW5jdGlvblwiICkge1xuXG5cdFx0XHQvLyAoIHR5cGVzIFssIGZuXSApXG5cdFx0XHRmbiA9IHNlbGVjdG9yO1xuXHRcdFx0c2VsZWN0b3IgPSB1bmRlZmluZWQ7XG5cdFx0fVxuXHRcdGlmICggZm4gPT09IGZhbHNlICkge1xuXHRcdFx0Zm4gPSByZXR1cm5GYWxzZTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRqUXVlcnkuZXZlbnQucmVtb3ZlKCB0aGlzLCB0eXBlcywgZm4sIHNlbGVjdG9yICk7XG5cdFx0fSApO1xuXHR9XG59ICk7XG5cblxudmFyXG5cblx0LyogZXNsaW50LWRpc2FibGUgbWF4LWxlbiAqL1xuXG5cdC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vZXNsaW50L2VzbGludC9pc3N1ZXMvMzIyOVxuXHRyeGh0bWxUYWcgPSAvPCg/IWFyZWF8YnJ8Y29sfGVtYmVkfGhyfGltZ3xpbnB1dHxsaW5rfG1ldGF8cGFyYW0pKChbYS16XVteXFwvXFwwPlxceDIwXFx0XFxyXFxuXFxmXSopW14+XSopXFwvPi9naSxcblxuXHQvKiBlc2xpbnQtZW5hYmxlICovXG5cblx0Ly8gU3VwcG9ydDogSUUgPD0xMCAtIDExLCBFZGdlIDEyIC0gMTMgb25seVxuXHQvLyBJbiBJRS9FZGdlIHVzaW5nIHJlZ2V4IGdyb3VwcyBoZXJlIGNhdXNlcyBzZXZlcmUgc2xvd2Rvd25zLlxuXHQvLyBTZWUgaHR0cHM6Ly9jb25uZWN0Lm1pY3Jvc29mdC5jb20vSUUvZmVlZGJhY2svZGV0YWlscy8xNzM2NTEyL1xuXHRybm9Jbm5lcmh0bWwgPSAvPHNjcmlwdHw8c3R5bGV8PGxpbmsvaSxcblxuXHQvLyBjaGVja2VkPVwiY2hlY2tlZFwiIG9yIGNoZWNrZWRcblx0cmNoZWNrZWQgPSAvY2hlY2tlZFxccyooPzpbXj1dfD1cXHMqLmNoZWNrZWQuKS9pLFxuXHRyY2xlYW5TY3JpcHQgPSAvXlxccyo8ISg/OlxcW0NEQVRBXFxbfC0tKXwoPzpcXF1cXF18LS0pPlxccyokL2c7XG5cbi8vIFByZWZlciBhIHRib2R5IG92ZXIgaXRzIHBhcmVudCB0YWJsZSBmb3IgY29udGFpbmluZyBuZXcgcm93c1xuZnVuY3Rpb24gbWFuaXB1bGF0aW9uVGFyZ2V0KCBlbGVtLCBjb250ZW50ICkge1xuXHRpZiAoIG5vZGVOYW1lKCBlbGVtLCBcInRhYmxlXCIgKSAmJlxuXHRcdG5vZGVOYW1lKCBjb250ZW50Lm5vZGVUeXBlICE9PSAxMSA/IGNvbnRlbnQgOiBjb250ZW50LmZpcnN0Q2hpbGQsIFwidHJcIiApICkge1xuXG5cdFx0cmV0dXJuIGpRdWVyeSggZWxlbSApLmNoaWxkcmVuKCBcInRib2R5XCIgKVsgMCBdIHx8IGVsZW07XG5cdH1cblxuXHRyZXR1cm4gZWxlbTtcbn1cblxuLy8gUmVwbGFjZS9yZXN0b3JlIHRoZSB0eXBlIGF0dHJpYnV0ZSBvZiBzY3JpcHQgZWxlbWVudHMgZm9yIHNhZmUgRE9NIG1hbmlwdWxhdGlvblxuZnVuY3Rpb24gZGlzYWJsZVNjcmlwdCggZWxlbSApIHtcblx0ZWxlbS50eXBlID0gKCBlbGVtLmdldEF0dHJpYnV0ZSggXCJ0eXBlXCIgKSAhPT0gbnVsbCApICsgXCIvXCIgKyBlbGVtLnR5cGU7XG5cdHJldHVybiBlbGVtO1xufVxuZnVuY3Rpb24gcmVzdG9yZVNjcmlwdCggZWxlbSApIHtcblx0aWYgKCAoIGVsZW0udHlwZSB8fCBcIlwiICkuc2xpY2UoIDAsIDUgKSA9PT0gXCJ0cnVlL1wiICkge1xuXHRcdGVsZW0udHlwZSA9IGVsZW0udHlwZS5zbGljZSggNSApO1xuXHR9IGVsc2Uge1xuXHRcdGVsZW0ucmVtb3ZlQXR0cmlidXRlKCBcInR5cGVcIiApO1xuXHR9XG5cblx0cmV0dXJuIGVsZW07XG59XG5cbmZ1bmN0aW9uIGNsb25lQ29weUV2ZW50KCBzcmMsIGRlc3QgKSB7XG5cdHZhciBpLCBsLCB0eXBlLCBwZGF0YU9sZCwgcGRhdGFDdXIsIHVkYXRhT2xkLCB1ZGF0YUN1ciwgZXZlbnRzO1xuXG5cdGlmICggZGVzdC5ub2RlVHlwZSAhPT0gMSApIHtcblx0XHRyZXR1cm47XG5cdH1cblxuXHQvLyAxLiBDb3B5IHByaXZhdGUgZGF0YTogZXZlbnRzLCBoYW5kbGVycywgZXRjLlxuXHRpZiAoIGRhdGFQcml2Lmhhc0RhdGEoIHNyYyApICkge1xuXHRcdHBkYXRhT2xkID0gZGF0YVByaXYuYWNjZXNzKCBzcmMgKTtcblx0XHRwZGF0YUN1ciA9IGRhdGFQcml2LnNldCggZGVzdCwgcGRhdGFPbGQgKTtcblx0XHRldmVudHMgPSBwZGF0YU9sZC5ldmVudHM7XG5cblx0XHRpZiAoIGV2ZW50cyApIHtcblx0XHRcdGRlbGV0ZSBwZGF0YUN1ci5oYW5kbGU7XG5cdFx0XHRwZGF0YUN1ci5ldmVudHMgPSB7fTtcblxuXHRcdFx0Zm9yICggdHlwZSBpbiBldmVudHMgKSB7XG5cdFx0XHRcdGZvciAoIGkgPSAwLCBsID0gZXZlbnRzWyB0eXBlIF0ubGVuZ3RoOyBpIDwgbDsgaSsrICkge1xuXHRcdFx0XHRcdGpRdWVyeS5ldmVudC5hZGQoIGRlc3QsIHR5cGUsIGV2ZW50c1sgdHlwZSBdWyBpIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8vIDIuIENvcHkgdXNlciBkYXRhXG5cdGlmICggZGF0YVVzZXIuaGFzRGF0YSggc3JjICkgKSB7XG5cdFx0dWRhdGFPbGQgPSBkYXRhVXNlci5hY2Nlc3MoIHNyYyApO1xuXHRcdHVkYXRhQ3VyID0galF1ZXJ5LmV4dGVuZCgge30sIHVkYXRhT2xkICk7XG5cblx0XHRkYXRhVXNlci5zZXQoIGRlc3QsIHVkYXRhQ3VyICk7XG5cdH1cbn1cblxuLy8gRml4IElFIGJ1Z3MsIHNlZSBzdXBwb3J0IHRlc3RzXG5mdW5jdGlvbiBmaXhJbnB1dCggc3JjLCBkZXN0ICkge1xuXHR2YXIgbm9kZU5hbWUgPSBkZXN0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cblx0Ly8gRmFpbHMgdG8gcGVyc2lzdCB0aGUgY2hlY2tlZCBzdGF0ZSBvZiBhIGNsb25lZCBjaGVja2JveCBvciByYWRpbyBidXR0b24uXG5cdGlmICggbm9kZU5hbWUgPT09IFwiaW5wdXRcIiAmJiByY2hlY2thYmxlVHlwZS50ZXN0KCBzcmMudHlwZSApICkge1xuXHRcdGRlc3QuY2hlY2tlZCA9IHNyYy5jaGVja2VkO1xuXG5cdC8vIEZhaWxzIHRvIHJldHVybiB0aGUgc2VsZWN0ZWQgb3B0aW9uIHRvIHRoZSBkZWZhdWx0IHNlbGVjdGVkIHN0YXRlIHdoZW4gY2xvbmluZyBvcHRpb25zXG5cdH0gZWxzZSBpZiAoIG5vZGVOYW1lID09PSBcImlucHV0XCIgfHwgbm9kZU5hbWUgPT09IFwidGV4dGFyZWFcIiApIHtcblx0XHRkZXN0LmRlZmF1bHRWYWx1ZSA9IHNyYy5kZWZhdWx0VmFsdWU7XG5cdH1cbn1cblxuZnVuY3Rpb24gZG9tTWFuaXAoIGNvbGxlY3Rpb24sIGFyZ3MsIGNhbGxiYWNrLCBpZ25vcmVkICkge1xuXG5cdC8vIEZsYXR0ZW4gYW55IG5lc3RlZCBhcnJheXNcblx0YXJncyA9IGNvbmNhdC5hcHBseSggW10sIGFyZ3MgKTtcblxuXHR2YXIgZnJhZ21lbnQsIGZpcnN0LCBzY3JpcHRzLCBoYXNTY3JpcHRzLCBub2RlLCBkb2MsXG5cdFx0aSA9IDAsXG5cdFx0bCA9IGNvbGxlY3Rpb24ubGVuZ3RoLFxuXHRcdGlOb0Nsb25lID0gbCAtIDEsXG5cdFx0dmFsdWUgPSBhcmdzWyAwIF0sXG5cdFx0dmFsdWVJc0Z1bmN0aW9uID0gaXNGdW5jdGlvbiggdmFsdWUgKTtcblxuXHQvLyBXZSBjYW4ndCBjbG9uZU5vZGUgZnJhZ21lbnRzIHRoYXQgY29udGFpbiBjaGVja2VkLCBpbiBXZWJLaXRcblx0aWYgKCB2YWx1ZUlzRnVuY3Rpb24gfHxcblx0XHRcdCggbCA+IDEgJiYgdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICYmXG5cdFx0XHRcdCFzdXBwb3J0LmNoZWNrQ2xvbmUgJiYgcmNoZWNrZWQudGVzdCggdmFsdWUgKSApICkge1xuXHRcdHJldHVybiBjb2xsZWN0aW9uLmVhY2goIGZ1bmN0aW9uKCBpbmRleCApIHtcblx0XHRcdHZhciBzZWxmID0gY29sbGVjdGlvbi5lcSggaW5kZXggKTtcblx0XHRcdGlmICggdmFsdWVJc0Z1bmN0aW9uICkge1xuXHRcdFx0XHRhcmdzWyAwIF0gPSB2YWx1ZS5jYWxsKCB0aGlzLCBpbmRleCwgc2VsZi5odG1sKCkgKTtcblx0XHRcdH1cblx0XHRcdGRvbU1hbmlwKCBzZWxmLCBhcmdzLCBjYWxsYmFjaywgaWdub3JlZCApO1xuXHRcdH0gKTtcblx0fVxuXG5cdGlmICggbCApIHtcblx0XHRmcmFnbWVudCA9IGJ1aWxkRnJhZ21lbnQoIGFyZ3MsIGNvbGxlY3Rpb25bIDAgXS5vd25lckRvY3VtZW50LCBmYWxzZSwgY29sbGVjdGlvbiwgaWdub3JlZCApO1xuXHRcdGZpcnN0ID0gZnJhZ21lbnQuZmlyc3RDaGlsZDtcblxuXHRcdGlmICggZnJhZ21lbnQuY2hpbGROb2Rlcy5sZW5ndGggPT09IDEgKSB7XG5cdFx0XHRmcmFnbWVudCA9IGZpcnN0O1xuXHRcdH1cblxuXHRcdC8vIFJlcXVpcmUgZWl0aGVyIG5ldyBjb250ZW50IG9yIGFuIGludGVyZXN0IGluIGlnbm9yZWQgZWxlbWVudHMgdG8gaW52b2tlIHRoZSBjYWxsYmFja1xuXHRcdGlmICggZmlyc3QgfHwgaWdub3JlZCApIHtcblx0XHRcdHNjcmlwdHMgPSBqUXVlcnkubWFwKCBnZXRBbGwoIGZyYWdtZW50LCBcInNjcmlwdFwiICksIGRpc2FibGVTY3JpcHQgKTtcblx0XHRcdGhhc1NjcmlwdHMgPSBzY3JpcHRzLmxlbmd0aDtcblxuXHRcdFx0Ly8gVXNlIHRoZSBvcmlnaW5hbCBmcmFnbWVudCBmb3IgdGhlIGxhc3QgaXRlbVxuXHRcdFx0Ly8gaW5zdGVhZCBvZiB0aGUgZmlyc3QgYmVjYXVzZSBpdCBjYW4gZW5kIHVwXG5cdFx0XHQvLyBiZWluZyBlbXB0aWVkIGluY29ycmVjdGx5IGluIGNlcnRhaW4gc2l0dWF0aW9ucyAoIzgwNzApLlxuXHRcdFx0Zm9yICggOyBpIDwgbDsgaSsrICkge1xuXHRcdFx0XHRub2RlID0gZnJhZ21lbnQ7XG5cblx0XHRcdFx0aWYgKCBpICE9PSBpTm9DbG9uZSApIHtcblx0XHRcdFx0XHRub2RlID0galF1ZXJ5LmNsb25lKCBub2RlLCB0cnVlLCB0cnVlICk7XG5cblx0XHRcdFx0XHQvLyBLZWVwIHJlZmVyZW5jZXMgdG8gY2xvbmVkIHNjcmlwdHMgZm9yIGxhdGVyIHJlc3RvcmF0aW9uXG5cdFx0XHRcdFx0aWYgKCBoYXNTY3JpcHRzICkge1xuXG5cdFx0XHRcdFx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkIDw9NC4wIG9ubHksIFBoYW50b21KUyAxIG9ubHlcblx0XHRcdFx0XHRcdC8vIHB1c2guYXBwbHkoXywgYXJyYXlsaWtlKSB0aHJvd3Mgb24gYW5jaWVudCBXZWJLaXRcblx0XHRcdFx0XHRcdGpRdWVyeS5tZXJnZSggc2NyaXB0cywgZ2V0QWxsKCBub2RlLCBcInNjcmlwdFwiICkgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRjYWxsYmFjay5jYWxsKCBjb2xsZWN0aW9uWyBpIF0sIG5vZGUsIGkgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBoYXNTY3JpcHRzICkge1xuXHRcdFx0XHRkb2MgPSBzY3JpcHRzWyBzY3JpcHRzLmxlbmd0aCAtIDEgXS5vd25lckRvY3VtZW50O1xuXG5cdFx0XHRcdC8vIFJlZW5hYmxlIHNjcmlwdHNcblx0XHRcdFx0alF1ZXJ5Lm1hcCggc2NyaXB0cywgcmVzdG9yZVNjcmlwdCApO1xuXG5cdFx0XHRcdC8vIEV2YWx1YXRlIGV4ZWN1dGFibGUgc2NyaXB0cyBvbiBmaXJzdCBkb2N1bWVudCBpbnNlcnRpb25cblx0XHRcdFx0Zm9yICggaSA9IDA7IGkgPCBoYXNTY3JpcHRzOyBpKysgKSB7XG5cdFx0XHRcdFx0bm9kZSA9IHNjcmlwdHNbIGkgXTtcblx0XHRcdFx0XHRpZiAoIHJzY3JpcHRUeXBlLnRlc3QoIG5vZGUudHlwZSB8fCBcIlwiICkgJiZcblx0XHRcdFx0XHRcdCFkYXRhUHJpdi5hY2Nlc3MoIG5vZGUsIFwiZ2xvYmFsRXZhbFwiICkgJiZcblx0XHRcdFx0XHRcdGpRdWVyeS5jb250YWlucyggZG9jLCBub2RlICkgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggbm9kZS5zcmMgJiYgKCBub2RlLnR5cGUgfHwgXCJcIiApLnRvTG93ZXJDYXNlKCkgICE9PSBcIm1vZHVsZVwiICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIE9wdGlvbmFsIEFKQVggZGVwZW5kZW5jeSwgYnV0IHdvbid0IHJ1biBzY3JpcHRzIGlmIG5vdCBwcmVzZW50XG5cdFx0XHRcdFx0XHRcdGlmICggalF1ZXJ5Ll9ldmFsVXJsICYmICFub2RlLm5vTW9kdWxlICkge1xuXHRcdFx0XHRcdFx0XHRcdGpRdWVyeS5fZXZhbFVybCggbm9kZS5zcmMsIHtcblx0XHRcdFx0XHRcdFx0XHRcdG5vbmNlOiBub2RlLm5vbmNlIHx8IG5vZGUuZ2V0QXR0cmlidXRlKCBcIm5vbmNlXCIgKVxuXHRcdFx0XHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0RE9NRXZhbCggbm9kZS50ZXh0Q29udGVudC5yZXBsYWNlKCByY2xlYW5TY3JpcHQsIFwiXCIgKSwgbm9kZSwgZG9jICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGNvbGxlY3Rpb247XG59XG5cbmZ1bmN0aW9uIHJlbW92ZSggZWxlbSwgc2VsZWN0b3IsIGtlZXBEYXRhICkge1xuXHR2YXIgbm9kZSxcblx0XHRub2RlcyA9IHNlbGVjdG9yID8galF1ZXJ5LmZpbHRlciggc2VsZWN0b3IsIGVsZW0gKSA6IGVsZW0sXG5cdFx0aSA9IDA7XG5cblx0Zm9yICggOyAoIG5vZGUgPSBub2Rlc1sgaSBdICkgIT0gbnVsbDsgaSsrICkge1xuXHRcdGlmICggIWtlZXBEYXRhICYmIG5vZGUubm9kZVR5cGUgPT09IDEgKSB7XG5cdFx0XHRqUXVlcnkuY2xlYW5EYXRhKCBnZXRBbGwoIG5vZGUgKSApO1xuXHRcdH1cblxuXHRcdGlmICggbm9kZS5wYXJlbnROb2RlICkge1xuXHRcdFx0aWYgKCBrZWVwRGF0YSAmJiBpc0F0dGFjaGVkKCBub2RlICkgKSB7XG5cdFx0XHRcdHNldEdsb2JhbEV2YWwoIGdldEFsbCggbm9kZSwgXCJzY3JpcHRcIiApICk7XG5cdFx0XHR9XG5cdFx0XHRub2RlLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoIG5vZGUgKTtcblx0XHR9XG5cdH1cblxuXHRyZXR1cm4gZWxlbTtcbn1cblxualF1ZXJ5LmV4dGVuZCgge1xuXHRodG1sUHJlZmlsdGVyOiBmdW5jdGlvbiggaHRtbCApIHtcblx0XHRyZXR1cm4gaHRtbC5yZXBsYWNlKCByeGh0bWxUYWcsIFwiPCQxPjwvJDI+XCIgKTtcblx0fSxcblxuXHRjbG9uZTogZnVuY3Rpb24oIGVsZW0sIGRhdGFBbmRFdmVudHMsIGRlZXBEYXRhQW5kRXZlbnRzICkge1xuXHRcdHZhciBpLCBsLCBzcmNFbGVtZW50cywgZGVzdEVsZW1lbnRzLFxuXHRcdFx0Y2xvbmUgPSBlbGVtLmNsb25lTm9kZSggdHJ1ZSApLFxuXHRcdFx0aW5QYWdlID0gaXNBdHRhY2hlZCggZWxlbSApO1xuXG5cdFx0Ly8gRml4IElFIGNsb25pbmcgaXNzdWVzXG5cdFx0aWYgKCAhc3VwcG9ydC5ub0Nsb25lQ2hlY2tlZCAmJiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgfHwgZWxlbS5ub2RlVHlwZSA9PT0gMTEgKSAmJlxuXHRcdFx0XHQhalF1ZXJ5LmlzWE1MRG9jKCBlbGVtICkgKSB7XG5cblx0XHRcdC8vIFdlIGVzY2hldyBTaXp6bGUgaGVyZSBmb3IgcGVyZm9ybWFuY2UgcmVhc29uczogaHR0cHM6Ly9qc3BlcmYuY29tL2dldGFsbC12cy1zaXp6bGUvMlxuXHRcdFx0ZGVzdEVsZW1lbnRzID0gZ2V0QWxsKCBjbG9uZSApO1xuXHRcdFx0c3JjRWxlbWVudHMgPSBnZXRBbGwoIGVsZW0gKTtcblxuXHRcdFx0Zm9yICggaSA9IDAsIGwgPSBzcmNFbGVtZW50cy5sZW5ndGg7IGkgPCBsOyBpKysgKSB7XG5cdFx0XHRcdGZpeElucHV0KCBzcmNFbGVtZW50c1sgaSBdLCBkZXN0RWxlbWVudHNbIGkgXSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIENvcHkgdGhlIGV2ZW50cyBmcm9tIHRoZSBvcmlnaW5hbCB0byB0aGUgY2xvbmVcblx0XHRpZiAoIGRhdGFBbmRFdmVudHMgKSB7XG5cdFx0XHRpZiAoIGRlZXBEYXRhQW5kRXZlbnRzICkge1xuXHRcdFx0XHRzcmNFbGVtZW50cyA9IHNyY0VsZW1lbnRzIHx8IGdldEFsbCggZWxlbSApO1xuXHRcdFx0XHRkZXN0RWxlbWVudHMgPSBkZXN0RWxlbWVudHMgfHwgZ2V0QWxsKCBjbG9uZSApO1xuXG5cdFx0XHRcdGZvciAoIGkgPSAwLCBsID0gc3JjRWxlbWVudHMubGVuZ3RoOyBpIDwgbDsgaSsrICkge1xuXHRcdFx0XHRcdGNsb25lQ29weUV2ZW50KCBzcmNFbGVtZW50c1sgaSBdLCBkZXN0RWxlbWVudHNbIGkgXSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRjbG9uZUNvcHlFdmVudCggZWxlbSwgY2xvbmUgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBQcmVzZXJ2ZSBzY3JpcHQgZXZhbHVhdGlvbiBoaXN0b3J5XG5cdFx0ZGVzdEVsZW1lbnRzID0gZ2V0QWxsKCBjbG9uZSwgXCJzY3JpcHRcIiApO1xuXHRcdGlmICggZGVzdEVsZW1lbnRzLmxlbmd0aCA+IDAgKSB7XG5cdFx0XHRzZXRHbG9iYWxFdmFsKCBkZXN0RWxlbWVudHMsICFpblBhZ2UgJiYgZ2V0QWxsKCBlbGVtLCBcInNjcmlwdFwiICkgKTtcblx0XHR9XG5cblx0XHQvLyBSZXR1cm4gdGhlIGNsb25lZCBzZXRcblx0XHRyZXR1cm4gY2xvbmU7XG5cdH0sXG5cblx0Y2xlYW5EYXRhOiBmdW5jdGlvbiggZWxlbXMgKSB7XG5cdFx0dmFyIGRhdGEsIGVsZW0sIHR5cGUsXG5cdFx0XHRzcGVjaWFsID0galF1ZXJ5LmV2ZW50LnNwZWNpYWwsXG5cdFx0XHRpID0gMDtcblxuXHRcdGZvciAoIDsgKCBlbGVtID0gZWxlbXNbIGkgXSApICE9PSB1bmRlZmluZWQ7IGkrKyApIHtcblx0XHRcdGlmICggYWNjZXB0RGF0YSggZWxlbSApICkge1xuXHRcdFx0XHRpZiAoICggZGF0YSA9IGVsZW1bIGRhdGFQcml2LmV4cGFuZG8gXSApICkge1xuXHRcdFx0XHRcdGlmICggZGF0YS5ldmVudHMgKSB7XG5cdFx0XHRcdFx0XHRmb3IgKCB0eXBlIGluIGRhdGEuZXZlbnRzICkge1xuXHRcdFx0XHRcdFx0XHRpZiAoIHNwZWNpYWxbIHR5cGUgXSApIHtcblx0XHRcdFx0XHRcdFx0XHRqUXVlcnkuZXZlbnQucmVtb3ZlKCBlbGVtLCB0eXBlICk7XG5cblx0XHRcdFx0XHRcdFx0Ly8gVGhpcyBpcyBhIHNob3J0Y3V0IHRvIGF2b2lkIGpRdWVyeS5ldmVudC5yZW1vdmUncyBvdmVyaGVhZFxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRcdGpRdWVyeS5yZW1vdmVFdmVudCggZWxlbSwgdHlwZSwgZGF0YS5oYW5kbGUgKTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IENocm9tZSA8PTM1IC0gNDUrXG5cdFx0XHRcdFx0Ly8gQXNzaWduIHVuZGVmaW5lZCBpbnN0ZWFkIG9mIHVzaW5nIGRlbGV0ZSwgc2VlIERhdGEjcmVtb3ZlXG5cdFx0XHRcdFx0ZWxlbVsgZGF0YVByaXYuZXhwYW5kbyBdID0gdW5kZWZpbmVkO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggZWxlbVsgZGF0YVVzZXIuZXhwYW5kbyBdICkge1xuXG5cdFx0XHRcdFx0Ly8gU3VwcG9ydDogQ2hyb21lIDw9MzUgLSA0NStcblx0XHRcdFx0XHQvLyBBc3NpZ24gdW5kZWZpbmVkIGluc3RlYWQgb2YgdXNpbmcgZGVsZXRlLCBzZWUgRGF0YSNyZW1vdmVcblx0XHRcdFx0XHRlbGVtWyBkYXRhVXNlci5leHBhbmRvIF0gPSB1bmRlZmluZWQ7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH1cbn0gKTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHRkZXRhY2g6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gcmVtb3ZlKCB0aGlzLCBzZWxlY3RvciwgdHJ1ZSApO1xuXHR9LFxuXG5cdHJlbW92ZTogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiByZW1vdmUoIHRoaXMsIHNlbGVjdG9yICk7XG5cdH0sXG5cblx0dGV4dDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHJldHVybiBhY2Nlc3MoIHRoaXMsIGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdHJldHVybiB2YWx1ZSA9PT0gdW5kZWZpbmVkID9cblx0XHRcdFx0alF1ZXJ5LnRleHQoIHRoaXMgKSA6XG5cdFx0XHRcdHRoaXMuZW1wdHkoKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRpZiAoIHRoaXMubm9kZVR5cGUgPT09IDEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gMTEgfHwgdGhpcy5ub2RlVHlwZSA9PT0gOSApIHtcblx0XHRcdFx0XHRcdHRoaXMudGV4dENvbnRlbnQgPSB2YWx1ZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHR9LCBudWxsLCB2YWx1ZSwgYXJndW1lbnRzLmxlbmd0aCApO1xuXHR9LFxuXG5cdGFwcGVuZDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIGRvbU1hbmlwKCB0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0aWYgKCB0aGlzLm5vZGVUeXBlID09PSAxIHx8IHRoaXMubm9kZVR5cGUgPT09IDExIHx8IHRoaXMubm9kZVR5cGUgPT09IDkgKSB7XG5cdFx0XHRcdHZhciB0YXJnZXQgPSBtYW5pcHVsYXRpb25UYXJnZXQoIHRoaXMsIGVsZW0gKTtcblx0XHRcdFx0dGFyZ2V0LmFwcGVuZENoaWxkKCBlbGVtICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdHByZXBlbmQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBkb21NYW5pcCggdGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdGlmICggdGhpcy5ub2RlVHlwZSA9PT0gMSB8fCB0aGlzLm5vZGVUeXBlID09PSAxMSB8fCB0aGlzLm5vZGVUeXBlID09PSA5ICkge1xuXHRcdFx0XHR2YXIgdGFyZ2V0ID0gbWFuaXB1bGF0aW9uVGFyZ2V0KCB0aGlzLCBlbGVtICk7XG5cdFx0XHRcdHRhcmdldC5pbnNlcnRCZWZvcmUoIGVsZW0sIHRhcmdldC5maXJzdENoaWxkICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdGJlZm9yZTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIGRvbU1hbmlwKCB0aGlzLCBhcmd1bWVudHMsIGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdFx0aWYgKCB0aGlzLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdHRoaXMucGFyZW50Tm9kZS5pbnNlcnRCZWZvcmUoIGVsZW0sIHRoaXMgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0YWZ0ZXI6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiBkb21NYW5pcCggdGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdGlmICggdGhpcy5wYXJlbnROb2RlICkge1xuXHRcdFx0XHR0aGlzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKCBlbGVtLCB0aGlzLm5leHRTaWJsaW5nICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdGVtcHR5OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZWxlbSxcblx0XHRcdGkgPSAwO1xuXG5cdFx0Zm9yICggOyAoIGVsZW0gPSB0aGlzWyBpIF0gKSAhPSBudWxsOyBpKysgKSB7XG5cdFx0XHRpZiAoIGVsZW0ubm9kZVR5cGUgPT09IDEgKSB7XG5cblx0XHRcdFx0Ly8gUHJldmVudCBtZW1vcnkgbGVha3Ncblx0XHRcdFx0alF1ZXJ5LmNsZWFuRGF0YSggZ2V0QWxsKCBlbGVtLCBmYWxzZSApICk7XG5cblx0XHRcdFx0Ly8gUmVtb3ZlIGFueSByZW1haW5pbmcgbm9kZXNcblx0XHRcdFx0ZWxlbS50ZXh0Q29udGVudCA9IFwiXCI7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Y2xvbmU6IGZ1bmN0aW9uKCBkYXRhQW5kRXZlbnRzLCBkZWVwRGF0YUFuZEV2ZW50cyApIHtcblx0XHRkYXRhQW5kRXZlbnRzID0gZGF0YUFuZEV2ZW50cyA9PSBudWxsID8gZmFsc2UgOiBkYXRhQW5kRXZlbnRzO1xuXHRcdGRlZXBEYXRhQW5kRXZlbnRzID0gZGVlcERhdGFBbmRFdmVudHMgPT0gbnVsbCA/IGRhdGFBbmRFdmVudHMgOiBkZWVwRGF0YUFuZEV2ZW50cztcblxuXHRcdHJldHVybiB0aGlzLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4galF1ZXJ5LmNsb25lKCB0aGlzLCBkYXRhQW5kRXZlbnRzLCBkZWVwRGF0YUFuZEV2ZW50cyApO1xuXHRcdH0gKTtcblx0fSxcblxuXHRodG1sOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0cmV0dXJuIGFjY2VzcyggdGhpcywgZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0dmFyIGVsZW0gPSB0aGlzWyAwIF0gfHwge30sXG5cdFx0XHRcdGkgPSAwLFxuXHRcdFx0XHRsID0gdGhpcy5sZW5ndGg7XG5cblx0XHRcdGlmICggdmFsdWUgPT09IHVuZGVmaW5lZCAmJiBlbGVtLm5vZGVUeXBlID09PSAxICkge1xuXHRcdFx0XHRyZXR1cm4gZWxlbS5pbm5lckhUTUw7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFNlZSBpZiB3ZSBjYW4gdGFrZSBhIHNob3J0Y3V0IGFuZCBqdXN0IHVzZSBpbm5lckhUTUxcblx0XHRcdGlmICggdHlwZW9mIHZhbHVlID09PSBcInN0cmluZ1wiICYmICFybm9Jbm5lcmh0bWwudGVzdCggdmFsdWUgKSAmJlxuXHRcdFx0XHQhd3JhcE1hcFsgKCBydGFnTmFtZS5leGVjKCB2YWx1ZSApIHx8IFsgXCJcIiwgXCJcIiBdIClbIDEgXS50b0xvd2VyQ2FzZSgpIF0gKSB7XG5cblx0XHRcdFx0dmFsdWUgPSBqUXVlcnkuaHRtbFByZWZpbHRlciggdmFsdWUgKTtcblxuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdGZvciAoIDsgaSA8IGw7IGkrKyApIHtcblx0XHRcdFx0XHRcdGVsZW0gPSB0aGlzWyBpIF0gfHwge307XG5cblx0XHRcdFx0XHRcdC8vIFJlbW92ZSBlbGVtZW50IG5vZGVzIGFuZCBwcmV2ZW50IG1lbW9yeSBsZWFrc1xuXHRcdFx0XHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSAxICkge1xuXHRcdFx0XHRcdFx0XHRqUXVlcnkuY2xlYW5EYXRhKCBnZXRBbGwoIGVsZW0sIGZhbHNlICkgKTtcblx0XHRcdFx0XHRcdFx0ZWxlbS5pbm5lckhUTUwgPSB2YWx1ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRlbGVtID0gMDtcblxuXHRcdFx0XHQvLyBJZiB1c2luZyBpbm5lckhUTUwgdGhyb3dzIGFuIGV4Y2VwdGlvbiwgdXNlIHRoZSBmYWxsYmFjayBtZXRob2Rcblx0XHRcdFx0fSBjYXRjaCAoIGUgKSB7fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGVsZW0gKSB7XG5cdFx0XHRcdHRoaXMuZW1wdHkoKS5hcHBlbmQoIHZhbHVlICk7XG5cdFx0XHR9XG5cdFx0fSwgbnVsbCwgdmFsdWUsIGFyZ3VtZW50cy5sZW5ndGggKTtcblx0fSxcblxuXHRyZXBsYWNlV2l0aDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGlnbm9yZWQgPSBbXTtcblxuXHRcdC8vIE1ha2UgdGhlIGNoYW5nZXMsIHJlcGxhY2luZyBlYWNoIG5vbi1pZ25vcmVkIGNvbnRleHQgZWxlbWVudCB3aXRoIHRoZSBuZXcgY29udGVudFxuXHRcdHJldHVybiBkb21NYW5pcCggdGhpcywgYXJndW1lbnRzLCBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHZhciBwYXJlbnQgPSB0aGlzLnBhcmVudE5vZGU7XG5cblx0XHRcdGlmICggalF1ZXJ5LmluQXJyYXkoIHRoaXMsIGlnbm9yZWQgKSA8IDAgKSB7XG5cdFx0XHRcdGpRdWVyeS5jbGVhbkRhdGEoIGdldEFsbCggdGhpcyApICk7XG5cdFx0XHRcdGlmICggcGFyZW50ICkge1xuXHRcdFx0XHRcdHBhcmVudC5yZXBsYWNlQ2hpbGQoIGVsZW0sIHRoaXMgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0Ly8gRm9yY2UgY2FsbGJhY2sgaW52b2NhdGlvblxuXHRcdH0sIGlnbm9yZWQgKTtcblx0fVxufSApO1xuXG5qUXVlcnkuZWFjaCgge1xuXHRhcHBlbmRUbzogXCJhcHBlbmRcIixcblx0cHJlcGVuZFRvOiBcInByZXBlbmRcIixcblx0aW5zZXJ0QmVmb3JlOiBcImJlZm9yZVwiLFxuXHRpbnNlcnRBZnRlcjogXCJhZnRlclwiLFxuXHRyZXBsYWNlQWxsOiBcInJlcGxhY2VXaXRoXCJcbn0sIGZ1bmN0aW9uKCBuYW1lLCBvcmlnaW5hbCApIHtcblx0alF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0dmFyIGVsZW1zLFxuXHRcdFx0cmV0ID0gW10sXG5cdFx0XHRpbnNlcnQgPSBqUXVlcnkoIHNlbGVjdG9yICksXG5cdFx0XHRsYXN0ID0gaW5zZXJ0Lmxlbmd0aCAtIDEsXG5cdFx0XHRpID0gMDtcblxuXHRcdGZvciAoIDsgaSA8PSBsYXN0OyBpKysgKSB7XG5cdFx0XHRlbGVtcyA9IGkgPT09IGxhc3QgPyB0aGlzIDogdGhpcy5jbG9uZSggdHJ1ZSApO1xuXHRcdFx0alF1ZXJ5KCBpbnNlcnRbIGkgXSApWyBvcmlnaW5hbCBdKCBlbGVtcyApO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkIDw9NC4wIG9ubHksIFBoYW50b21KUyAxIG9ubHlcblx0XHRcdC8vIC5nZXQoKSBiZWNhdXNlIHB1c2guYXBwbHkoXywgYXJyYXlsaWtlKSB0aHJvd3Mgb24gYW5jaWVudCBXZWJLaXRcblx0XHRcdHB1c2guYXBwbHkoIHJldCwgZWxlbXMuZ2V0KCkgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5wdXNoU3RhY2soIHJldCApO1xuXHR9O1xufSApO1xudmFyIHJudW1ub25weCA9IG5ldyBSZWdFeHAoIFwiXihcIiArIHBudW0gKyBcIikoPyFweClbYS16JV0rJFwiLCBcImlcIiApO1xuXG52YXIgZ2V0U3R5bGVzID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cblx0XHQvLyBTdXBwb3J0OiBJRSA8PTExIG9ubHksIEZpcmVmb3ggPD0zMCAoIzE1MDk4LCAjMTQxNTApXG5cdFx0Ly8gSUUgdGhyb3dzIG9uIGVsZW1lbnRzIGNyZWF0ZWQgaW4gcG9wdXBzXG5cdFx0Ly8gRkYgbWVhbndoaWxlIHRocm93cyBvbiBmcmFtZSBlbGVtZW50cyB0aHJvdWdoIFwiZGVmYXVsdFZpZXcuZ2V0Q29tcHV0ZWRTdHlsZVwiXG5cdFx0dmFyIHZpZXcgPSBlbGVtLm93bmVyRG9jdW1lbnQuZGVmYXVsdFZpZXc7XG5cblx0XHRpZiAoICF2aWV3IHx8ICF2aWV3Lm9wZW5lciApIHtcblx0XHRcdHZpZXcgPSB3aW5kb3c7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHZpZXcuZ2V0Q29tcHV0ZWRTdHlsZSggZWxlbSApO1xuXHR9O1xuXG52YXIgcmJveFN0eWxlID0gbmV3IFJlZ0V4cCggY3NzRXhwYW5kLmpvaW4oIFwifFwiICksIFwiaVwiICk7XG5cblxuXG4oIGZ1bmN0aW9uKCkge1xuXG5cdC8vIEV4ZWN1dGluZyBib3RoIHBpeGVsUG9zaXRpb24gJiBib3hTaXppbmdSZWxpYWJsZSB0ZXN0cyByZXF1aXJlIG9ubHkgb25lIGxheW91dFxuXHQvLyBzbyB0aGV5J3JlIGV4ZWN1dGVkIGF0IHRoZSBzYW1lIHRpbWUgdG8gc2F2ZSB0aGUgc2Vjb25kIGNvbXB1dGF0aW9uLlxuXHRmdW5jdGlvbiBjb21wdXRlU3R5bGVUZXN0cygpIHtcblxuXHRcdC8vIFRoaXMgaXMgYSBzaW5nbGV0b24sIHdlIG5lZWQgdG8gZXhlY3V0ZSBpdCBvbmx5IG9uY2Vcblx0XHRpZiAoICFkaXYgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Y29udGFpbmVyLnN0eWxlLmNzc1RleHQgPSBcInBvc2l0aW9uOmFic29sdXRlO2xlZnQ6LTExMTExcHg7d2lkdGg6NjBweDtcIiArXG5cdFx0XHRcIm1hcmdpbi10b3A6MXB4O3BhZGRpbmc6MDtib3JkZXI6MFwiO1xuXHRcdGRpdi5zdHlsZS5jc3NUZXh0ID1cblx0XHRcdFwicG9zaXRpb246cmVsYXRpdmU7ZGlzcGxheTpibG9jaztib3gtc2l6aW5nOmJvcmRlci1ib3g7b3ZlcmZsb3c6c2Nyb2xsO1wiICtcblx0XHRcdFwibWFyZ2luOmF1dG87Ym9yZGVyOjFweDtwYWRkaW5nOjFweDtcIiArXG5cdFx0XHRcIndpZHRoOjYwJTt0b3A6MSVcIjtcblx0XHRkb2N1bWVudEVsZW1lbnQuYXBwZW5kQ2hpbGQoIGNvbnRhaW5lciApLmFwcGVuZENoaWxkKCBkaXYgKTtcblxuXHRcdHZhciBkaXZTdHlsZSA9IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKCBkaXYgKTtcblx0XHRwaXhlbFBvc2l0aW9uVmFsID0gZGl2U3R5bGUudG9wICE9PSBcIjElXCI7XG5cblx0XHQvLyBTdXBwb3J0OiBBbmRyb2lkIDQuMCAtIDQuMyBvbmx5LCBGaXJlZm94IDw9MyAtIDQ0XG5cdFx0cmVsaWFibGVNYXJnaW5MZWZ0VmFsID0gcm91bmRQaXhlbE1lYXN1cmVzKCBkaXZTdHlsZS5tYXJnaW5MZWZ0ICkgPT09IDEyO1xuXG5cdFx0Ly8gU3VwcG9ydDogQW5kcm9pZCA0LjAgLSA0LjMgb25seSwgU2FmYXJpIDw9OS4xIC0gMTAuMSwgaU9TIDw9Ny4wIC0gOS4zXG5cdFx0Ly8gU29tZSBzdHlsZXMgY29tZSBiYWNrIHdpdGggcGVyY2VudGFnZSB2YWx1ZXMsIGV2ZW4gdGhvdWdoIHRoZXkgc2hvdWxkbid0XG5cdFx0ZGl2LnN0eWxlLnJpZ2h0ID0gXCI2MCVcIjtcblx0XHRwaXhlbEJveFN0eWxlc1ZhbCA9IHJvdW5kUGl4ZWxNZWFzdXJlcyggZGl2U3R5bGUucmlnaHQgKSA9PT0gMzY7XG5cblx0XHQvLyBTdXBwb3J0OiBJRSA5IC0gMTEgb25seVxuXHRcdC8vIERldGVjdCBtaXNyZXBvcnRpbmcgb2YgY29udGVudCBkaW1lbnNpb25zIGZvciBib3gtc2l6aW5nOmJvcmRlci1ib3ggZWxlbWVudHNcblx0XHRib3hTaXppbmdSZWxpYWJsZVZhbCA9IHJvdW5kUGl4ZWxNZWFzdXJlcyggZGl2U3R5bGUud2lkdGggKSA9PT0gMzY7XG5cblx0XHQvLyBTdXBwb3J0OiBJRSA5IG9ubHlcblx0XHQvLyBEZXRlY3Qgb3ZlcmZsb3c6c2Nyb2xsIHNjcmV3aW5lc3MgKGdoLTM2OTkpXG5cdFx0Ly8gU3VwcG9ydDogQ2hyb21lIDw9NjRcblx0XHQvLyBEb24ndCBnZXQgdHJpY2tlZCB3aGVuIHpvb20gYWZmZWN0cyBvZmZzZXRXaWR0aCAoZ2gtNDAyOSlcblx0XHRkaXYuc3R5bGUucG9zaXRpb24gPSBcImFic29sdXRlXCI7XG5cdFx0c2Nyb2xsYm94U2l6ZVZhbCA9IHJvdW5kUGl4ZWxNZWFzdXJlcyggZGl2Lm9mZnNldFdpZHRoIC8gMyApID09PSAxMjtcblxuXHRcdGRvY3VtZW50RWxlbWVudC5yZW1vdmVDaGlsZCggY29udGFpbmVyICk7XG5cblx0XHQvLyBOdWxsaWZ5IHRoZSBkaXYgc28gaXQgd291bGRuJ3QgYmUgc3RvcmVkIGluIHRoZSBtZW1vcnkgYW5kXG5cdFx0Ly8gaXQgd2lsbCBhbHNvIGJlIGEgc2lnbiB0aGF0IGNoZWNrcyBhbHJlYWR5IHBlcmZvcm1lZFxuXHRcdGRpdiA9IG51bGw7XG5cdH1cblxuXHRmdW5jdGlvbiByb3VuZFBpeGVsTWVhc3VyZXMoIG1lYXN1cmUgKSB7XG5cdFx0cmV0dXJuIE1hdGgucm91bmQoIHBhcnNlRmxvYXQoIG1lYXN1cmUgKSApO1xuXHR9XG5cblx0dmFyIHBpeGVsUG9zaXRpb25WYWwsIGJveFNpemluZ1JlbGlhYmxlVmFsLCBzY3JvbGxib3hTaXplVmFsLCBwaXhlbEJveFN0eWxlc1ZhbCxcblx0XHRyZWxpYWJsZU1hcmdpbkxlZnRWYWwsXG5cdFx0Y29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJkaXZcIiApLFxuXHRcdGRpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiZGl2XCIgKTtcblxuXHQvLyBGaW5pc2ggZWFybHkgaW4gbGltaXRlZCAobm9uLWJyb3dzZXIpIGVudmlyb25tZW50c1xuXHRpZiAoICFkaXYuc3R5bGUgKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0Ly8gU3VwcG9ydDogSUUgPD05IC0gMTEgb25seVxuXHQvLyBTdHlsZSBvZiBjbG9uZWQgZWxlbWVudCBhZmZlY3RzIHNvdXJjZSBlbGVtZW50IGNsb25lZCAoIzg5MDgpXG5cdGRpdi5zdHlsZS5iYWNrZ3JvdW5kQ2xpcCA9IFwiY29udGVudC1ib3hcIjtcblx0ZGl2LmNsb25lTm9kZSggdHJ1ZSApLnN0eWxlLmJhY2tncm91bmRDbGlwID0gXCJcIjtcblx0c3VwcG9ydC5jbGVhckNsb25lU3R5bGUgPSBkaXYuc3R5bGUuYmFja2dyb3VuZENsaXAgPT09IFwiY29udGVudC1ib3hcIjtcblxuXHRqUXVlcnkuZXh0ZW5kKCBzdXBwb3J0LCB7XG5cdFx0Ym94U2l6aW5nUmVsaWFibGU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0Y29tcHV0ZVN0eWxlVGVzdHMoKTtcblx0XHRcdHJldHVybiBib3hTaXppbmdSZWxpYWJsZVZhbDtcblx0XHR9LFxuXHRcdHBpeGVsQm94U3R5bGVzOiBmdW5jdGlvbigpIHtcblx0XHRcdGNvbXB1dGVTdHlsZVRlc3RzKCk7XG5cdFx0XHRyZXR1cm4gcGl4ZWxCb3hTdHlsZXNWYWw7XG5cdFx0fSxcblx0XHRwaXhlbFBvc2l0aW9uOiBmdW5jdGlvbigpIHtcblx0XHRcdGNvbXB1dGVTdHlsZVRlc3RzKCk7XG5cdFx0XHRyZXR1cm4gcGl4ZWxQb3NpdGlvblZhbDtcblx0XHR9LFxuXHRcdHJlbGlhYmxlTWFyZ2luTGVmdDogZnVuY3Rpb24oKSB7XG5cdFx0XHRjb21wdXRlU3R5bGVUZXN0cygpO1xuXHRcdFx0cmV0dXJuIHJlbGlhYmxlTWFyZ2luTGVmdFZhbDtcblx0XHR9LFxuXHRcdHNjcm9sbGJveFNpemU6IGZ1bmN0aW9uKCkge1xuXHRcdFx0Y29tcHV0ZVN0eWxlVGVzdHMoKTtcblx0XHRcdHJldHVybiBzY3JvbGxib3hTaXplVmFsO1xuXHRcdH1cblx0fSApO1xufSApKCk7XG5cblxuZnVuY3Rpb24gY3VyQ1NTKCBlbGVtLCBuYW1lLCBjb21wdXRlZCApIHtcblx0dmFyIHdpZHRoLCBtaW5XaWR0aCwgbWF4V2lkdGgsIHJldCxcblxuXHRcdC8vIFN1cHBvcnQ6IEZpcmVmb3ggNTErXG5cdFx0Ly8gUmV0cmlldmluZyBzdHlsZSBiZWZvcmUgY29tcHV0ZWQgc29tZWhvd1xuXHRcdC8vIGZpeGVzIGFuIGlzc3VlIHdpdGggZ2V0dGluZyB3cm9uZyB2YWx1ZXNcblx0XHQvLyBvbiBkZXRhY2hlZCBlbGVtZW50c1xuXHRcdHN0eWxlID0gZWxlbS5zdHlsZTtcblxuXHRjb21wdXRlZCA9IGNvbXB1dGVkIHx8IGdldFN0eWxlcyggZWxlbSApO1xuXG5cdC8vIGdldFByb3BlcnR5VmFsdWUgaXMgbmVlZGVkIGZvcjpcblx0Ly8gICAuY3NzKCdmaWx0ZXInKSAoSUUgOSBvbmx5LCAjMTI1MzcpXG5cdC8vICAgLmNzcygnLS1jdXN0b21Qcm9wZXJ0eSkgKCMzMTQ0KVxuXHRpZiAoIGNvbXB1dGVkICkge1xuXHRcdHJldCA9IGNvbXB1dGVkLmdldFByb3BlcnR5VmFsdWUoIG5hbWUgKSB8fCBjb21wdXRlZFsgbmFtZSBdO1xuXG5cdFx0aWYgKCByZXQgPT09IFwiXCIgJiYgIWlzQXR0YWNoZWQoIGVsZW0gKSApIHtcblx0XHRcdHJldCA9IGpRdWVyeS5zdHlsZSggZWxlbSwgbmFtZSApO1xuXHRcdH1cblxuXHRcdC8vIEEgdHJpYnV0ZSB0byB0aGUgXCJhd2Vzb21lIGhhY2sgYnkgRGVhbiBFZHdhcmRzXCJcblx0XHQvLyBBbmRyb2lkIEJyb3dzZXIgcmV0dXJucyBwZXJjZW50YWdlIGZvciBzb21lIHZhbHVlcyxcblx0XHQvLyBidXQgd2lkdGggc2VlbXMgdG8gYmUgcmVsaWFibHkgcGl4ZWxzLlxuXHRcdC8vIFRoaXMgaXMgYWdhaW5zdCB0aGUgQ1NTT00gZHJhZnQgc3BlYzpcblx0XHQvLyBodHRwczovL2RyYWZ0cy5jc3N3Zy5vcmcvY3Nzb20vI3Jlc29sdmVkLXZhbHVlc1xuXHRcdGlmICggIXN1cHBvcnQucGl4ZWxCb3hTdHlsZXMoKSAmJiBybnVtbm9ucHgudGVzdCggcmV0ICkgJiYgcmJveFN0eWxlLnRlc3QoIG5hbWUgKSApIHtcblxuXHRcdFx0Ly8gUmVtZW1iZXIgdGhlIG9yaWdpbmFsIHZhbHVlc1xuXHRcdFx0d2lkdGggPSBzdHlsZS53aWR0aDtcblx0XHRcdG1pbldpZHRoID0gc3R5bGUubWluV2lkdGg7XG5cdFx0XHRtYXhXaWR0aCA9IHN0eWxlLm1heFdpZHRoO1xuXG5cdFx0XHQvLyBQdXQgaW4gdGhlIG5ldyB2YWx1ZXMgdG8gZ2V0IGEgY29tcHV0ZWQgdmFsdWUgb3V0XG5cdFx0XHRzdHlsZS5taW5XaWR0aCA9IHN0eWxlLm1heFdpZHRoID0gc3R5bGUud2lkdGggPSByZXQ7XG5cdFx0XHRyZXQgPSBjb21wdXRlZC53aWR0aDtcblxuXHRcdFx0Ly8gUmV2ZXJ0IHRoZSBjaGFuZ2VkIHZhbHVlc1xuXHRcdFx0c3R5bGUud2lkdGggPSB3aWR0aDtcblx0XHRcdHN0eWxlLm1pbldpZHRoID0gbWluV2lkdGg7XG5cdFx0XHRzdHlsZS5tYXhXaWR0aCA9IG1heFdpZHRoO1xuXHRcdH1cblx0fVxuXG5cdHJldHVybiByZXQgIT09IHVuZGVmaW5lZCA/XG5cblx0XHQvLyBTdXBwb3J0OiBJRSA8PTkgLSAxMSBvbmx5XG5cdFx0Ly8gSUUgcmV0dXJucyB6SW5kZXggdmFsdWUgYXMgYW4gaW50ZWdlci5cblx0XHRyZXQgKyBcIlwiIDpcblx0XHRyZXQ7XG59XG5cblxuZnVuY3Rpb24gYWRkR2V0SG9va0lmKCBjb25kaXRpb25GbiwgaG9va0ZuICkge1xuXG5cdC8vIERlZmluZSB0aGUgaG9vaywgd2UnbGwgY2hlY2sgb24gdGhlIGZpcnN0IHJ1biBpZiBpdCdzIHJlYWxseSBuZWVkZWQuXG5cdHJldHVybiB7XG5cdFx0Z2V0OiBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggY29uZGl0aW9uRm4oKSApIHtcblxuXHRcdFx0XHQvLyBIb29rIG5vdCBuZWVkZWQgKG9yIGl0J3Mgbm90IHBvc3NpYmxlIHRvIHVzZSBpdCBkdWVcblx0XHRcdFx0Ly8gdG8gbWlzc2luZyBkZXBlbmRlbmN5KSwgcmVtb3ZlIGl0LlxuXHRcdFx0XHRkZWxldGUgdGhpcy5nZXQ7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gSG9vayBuZWVkZWQ7IHJlZGVmaW5lIGl0IHNvIHRoYXQgdGhlIHN1cHBvcnQgdGVzdCBpcyBub3QgZXhlY3V0ZWQgYWdhaW4uXG5cdFx0XHRyZXR1cm4gKCB0aGlzLmdldCA9IGhvb2tGbiApLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHR9XG5cdH07XG59XG5cblxudmFyIGNzc1ByZWZpeGVzID0gWyBcIldlYmtpdFwiLCBcIk1velwiLCBcIm1zXCIgXSxcblx0ZW1wdHlTdHlsZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiZGl2XCIgKS5zdHlsZSxcblx0dmVuZG9yUHJvcHMgPSB7fTtcblxuLy8gUmV0dXJuIGEgdmVuZG9yLXByZWZpeGVkIHByb3BlcnR5IG9yIHVuZGVmaW5lZFxuZnVuY3Rpb24gdmVuZG9yUHJvcE5hbWUoIG5hbWUgKSB7XG5cblx0Ly8gQ2hlY2sgZm9yIHZlbmRvciBwcmVmaXhlZCBuYW1lc1xuXHR2YXIgY2FwTmFtZSA9IG5hbWVbIDAgXS50b1VwcGVyQ2FzZSgpICsgbmFtZS5zbGljZSggMSApLFxuXHRcdGkgPSBjc3NQcmVmaXhlcy5sZW5ndGg7XG5cblx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0bmFtZSA9IGNzc1ByZWZpeGVzWyBpIF0gKyBjYXBOYW1lO1xuXHRcdGlmICggbmFtZSBpbiBlbXB0eVN0eWxlICkge1xuXHRcdFx0cmV0dXJuIG5hbWU7XG5cdFx0fVxuXHR9XG59XG5cbi8vIFJldHVybiBhIHBvdGVudGlhbGx5LW1hcHBlZCBqUXVlcnkuY3NzUHJvcHMgb3IgdmVuZG9yIHByZWZpeGVkIHByb3BlcnR5XG5mdW5jdGlvbiBmaW5hbFByb3BOYW1lKCBuYW1lICkge1xuXHR2YXIgZmluYWwgPSBqUXVlcnkuY3NzUHJvcHNbIG5hbWUgXSB8fCB2ZW5kb3JQcm9wc1sgbmFtZSBdO1xuXG5cdGlmICggZmluYWwgKSB7XG5cdFx0cmV0dXJuIGZpbmFsO1xuXHR9XG5cdGlmICggbmFtZSBpbiBlbXB0eVN0eWxlICkge1xuXHRcdHJldHVybiBuYW1lO1xuXHR9XG5cdHJldHVybiB2ZW5kb3JQcm9wc1sgbmFtZSBdID0gdmVuZG9yUHJvcE5hbWUoIG5hbWUgKSB8fCBuYW1lO1xufVxuXG5cbnZhclxuXG5cdC8vIFN3YXBwYWJsZSBpZiBkaXNwbGF5IGlzIG5vbmUgb3Igc3RhcnRzIHdpdGggdGFibGVcblx0Ly8gZXhjZXB0IFwidGFibGVcIiwgXCJ0YWJsZS1jZWxsXCIsIG9yIFwidGFibGUtY2FwdGlvblwiXG5cdC8vIFNlZSBoZXJlIGZvciBkaXNwbGF5IHZhbHVlczogaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZW4tVVMvZG9jcy9DU1MvZGlzcGxheVxuXHRyZGlzcGxheXN3YXAgPSAvXihub25lfHRhYmxlKD8hLWNbZWFdKS4rKS8sXG5cdHJjdXN0b21Qcm9wID0gL14tLS8sXG5cdGNzc1Nob3cgPSB7IHBvc2l0aW9uOiBcImFic29sdXRlXCIsIHZpc2liaWxpdHk6IFwiaGlkZGVuXCIsIGRpc3BsYXk6IFwiYmxvY2tcIiB9LFxuXHRjc3NOb3JtYWxUcmFuc2Zvcm0gPSB7XG5cdFx0bGV0dGVyU3BhY2luZzogXCIwXCIsXG5cdFx0Zm9udFdlaWdodDogXCI0MDBcIlxuXHR9O1xuXG5mdW5jdGlvbiBzZXRQb3NpdGl2ZU51bWJlciggZWxlbSwgdmFsdWUsIHN1YnRyYWN0ICkge1xuXG5cdC8vIEFueSByZWxhdGl2ZSAoKy8tKSB2YWx1ZXMgaGF2ZSBhbHJlYWR5IGJlZW5cblx0Ly8gbm9ybWFsaXplZCBhdCB0aGlzIHBvaW50XG5cdHZhciBtYXRjaGVzID0gcmNzc051bS5leGVjKCB2YWx1ZSApO1xuXHRyZXR1cm4gbWF0Y2hlcyA/XG5cblx0XHQvLyBHdWFyZCBhZ2FpbnN0IHVuZGVmaW5lZCBcInN1YnRyYWN0XCIsIGUuZy4sIHdoZW4gdXNlZCBhcyBpbiBjc3NIb29rc1xuXHRcdE1hdGgubWF4KCAwLCBtYXRjaGVzWyAyIF0gLSAoIHN1YnRyYWN0IHx8IDAgKSApICsgKCBtYXRjaGVzWyAzIF0gfHwgXCJweFwiICkgOlxuXHRcdHZhbHVlO1xufVxuXG5mdW5jdGlvbiBib3hNb2RlbEFkanVzdG1lbnQoIGVsZW0sIGRpbWVuc2lvbiwgYm94LCBpc0JvcmRlckJveCwgc3R5bGVzLCBjb21wdXRlZFZhbCApIHtcblx0dmFyIGkgPSBkaW1lbnNpb24gPT09IFwid2lkdGhcIiA/IDEgOiAwLFxuXHRcdGV4dHJhID0gMCxcblx0XHRkZWx0YSA9IDA7XG5cblx0Ly8gQWRqdXN0bWVudCBtYXkgbm90IGJlIG5lY2Vzc2FyeVxuXHRpZiAoIGJveCA9PT0gKCBpc0JvcmRlckJveCA/IFwiYm9yZGVyXCIgOiBcImNvbnRlbnRcIiApICkge1xuXHRcdHJldHVybiAwO1xuXHR9XG5cblx0Zm9yICggOyBpIDwgNDsgaSArPSAyICkge1xuXG5cdFx0Ly8gQm90aCBib3ggbW9kZWxzIGV4Y2x1ZGUgbWFyZ2luXG5cdFx0aWYgKCBib3ggPT09IFwibWFyZ2luXCIgKSB7XG5cdFx0XHRkZWx0YSArPSBqUXVlcnkuY3NzKCBlbGVtLCBib3ggKyBjc3NFeHBhbmRbIGkgXSwgdHJ1ZSwgc3R5bGVzICk7XG5cdFx0fVxuXG5cdFx0Ly8gSWYgd2UgZ2V0IGhlcmUgd2l0aCBhIGNvbnRlbnQtYm94LCB3ZSdyZSBzZWVraW5nIFwicGFkZGluZ1wiIG9yIFwiYm9yZGVyXCIgb3IgXCJtYXJnaW5cIlxuXHRcdGlmICggIWlzQm9yZGVyQm94ICkge1xuXG5cdFx0XHQvLyBBZGQgcGFkZGluZ1xuXHRcdFx0ZGVsdGEgKz0galF1ZXJ5LmNzcyggZWxlbSwgXCJwYWRkaW5nXCIgKyBjc3NFeHBhbmRbIGkgXSwgdHJ1ZSwgc3R5bGVzICk7XG5cblx0XHRcdC8vIEZvciBcImJvcmRlclwiIG9yIFwibWFyZ2luXCIsIGFkZCBib3JkZXJcblx0XHRcdGlmICggYm94ICE9PSBcInBhZGRpbmdcIiApIHtcblx0XHRcdFx0ZGVsdGEgKz0galF1ZXJ5LmNzcyggZWxlbSwgXCJib3JkZXJcIiArIGNzc0V4cGFuZFsgaSBdICsgXCJXaWR0aFwiLCB0cnVlLCBzdHlsZXMgKTtcblxuXHRcdFx0Ly8gQnV0IHN0aWxsIGtlZXAgdHJhY2sgb2YgaXQgb3RoZXJ3aXNlXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRleHRyYSArPSBqUXVlcnkuY3NzKCBlbGVtLCBcImJvcmRlclwiICsgY3NzRXhwYW5kWyBpIF0gKyBcIldpZHRoXCIsIHRydWUsIHN0eWxlcyApO1xuXHRcdFx0fVxuXG5cdFx0Ly8gSWYgd2UgZ2V0IGhlcmUgd2l0aCBhIGJvcmRlci1ib3ggKGNvbnRlbnQgKyBwYWRkaW5nICsgYm9yZGVyKSwgd2UncmUgc2Vla2luZyBcImNvbnRlbnRcIiBvclxuXHRcdC8vIFwicGFkZGluZ1wiIG9yIFwibWFyZ2luXCJcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBGb3IgXCJjb250ZW50XCIsIHN1YnRyYWN0IHBhZGRpbmdcblx0XHRcdGlmICggYm94ID09PSBcImNvbnRlbnRcIiApIHtcblx0XHRcdFx0ZGVsdGEgLT0galF1ZXJ5LmNzcyggZWxlbSwgXCJwYWRkaW5nXCIgKyBjc3NFeHBhbmRbIGkgXSwgdHJ1ZSwgc3R5bGVzICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEZvciBcImNvbnRlbnRcIiBvciBcInBhZGRpbmdcIiwgc3VidHJhY3QgYm9yZGVyXG5cdFx0XHRpZiAoIGJveCAhPT0gXCJtYXJnaW5cIiApIHtcblx0XHRcdFx0ZGVsdGEgLT0galF1ZXJ5LmNzcyggZWxlbSwgXCJib3JkZXJcIiArIGNzc0V4cGFuZFsgaSBdICsgXCJXaWR0aFwiLCB0cnVlLCBzdHlsZXMgKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLyBBY2NvdW50IGZvciBwb3NpdGl2ZSBjb250ZW50LWJveCBzY3JvbGwgZ3V0dGVyIHdoZW4gcmVxdWVzdGVkIGJ5IHByb3ZpZGluZyBjb21wdXRlZFZhbFxuXHRpZiAoICFpc0JvcmRlckJveCAmJiBjb21wdXRlZFZhbCA+PSAwICkge1xuXG5cdFx0Ly8gb2Zmc2V0V2lkdGgvb2Zmc2V0SGVpZ2h0IGlzIGEgcm91bmRlZCBzdW0gb2YgY29udGVudCwgcGFkZGluZywgc2Nyb2xsIGd1dHRlciwgYW5kIGJvcmRlclxuXHRcdC8vIEFzc3VtaW5nIGludGVnZXIgc2Nyb2xsIGd1dHRlciwgc3VidHJhY3QgdGhlIHJlc3QgYW5kIHJvdW5kIGRvd25cblx0XHRkZWx0YSArPSBNYXRoLm1heCggMCwgTWF0aC5jZWlsKFxuXHRcdFx0ZWxlbVsgXCJvZmZzZXRcIiArIGRpbWVuc2lvblsgMCBdLnRvVXBwZXJDYXNlKCkgKyBkaW1lbnNpb24uc2xpY2UoIDEgKSBdIC1cblx0XHRcdGNvbXB1dGVkVmFsIC1cblx0XHRcdGRlbHRhIC1cblx0XHRcdGV4dHJhIC1cblx0XHRcdDAuNVxuXG5cdFx0Ly8gSWYgb2Zmc2V0V2lkdGgvb2Zmc2V0SGVpZ2h0IGlzIHVua25vd24sIHRoZW4gd2UgY2FuJ3QgZGV0ZXJtaW5lIGNvbnRlbnQtYm94IHNjcm9sbCBndXR0ZXJcblx0XHQvLyBVc2UgYW4gZXhwbGljaXQgemVybyB0byBhdm9pZCBOYU4gKGdoLTM5NjQpXG5cdFx0KSApIHx8IDA7XG5cdH1cblxuXHRyZXR1cm4gZGVsdGE7XG59XG5cbmZ1bmN0aW9uIGdldFdpZHRoT3JIZWlnaHQoIGVsZW0sIGRpbWVuc2lvbiwgZXh0cmEgKSB7XG5cblx0Ly8gU3RhcnQgd2l0aCBjb21wdXRlZCBzdHlsZVxuXHR2YXIgc3R5bGVzID0gZ2V0U3R5bGVzKCBlbGVtICksXG5cblx0XHQvLyBUbyBhdm9pZCBmb3JjaW5nIGEgcmVmbG93LCBvbmx5IGZldGNoIGJveFNpemluZyBpZiB3ZSBuZWVkIGl0IChnaC00MzIyKS5cblx0XHQvLyBGYWtlIGNvbnRlbnQtYm94IHVudGlsIHdlIGtub3cgaXQncyBuZWVkZWQgdG8ga25vdyB0aGUgdHJ1ZSB2YWx1ZS5cblx0XHRib3hTaXppbmdOZWVkZWQgPSAhc3VwcG9ydC5ib3hTaXppbmdSZWxpYWJsZSgpIHx8IGV4dHJhLFxuXHRcdGlzQm9yZGVyQm94ID0gYm94U2l6aW5nTmVlZGVkICYmXG5cdFx0XHRqUXVlcnkuY3NzKCBlbGVtLCBcImJveFNpemluZ1wiLCBmYWxzZSwgc3R5bGVzICkgPT09IFwiYm9yZGVyLWJveFwiLFxuXHRcdHZhbHVlSXNCb3JkZXJCb3ggPSBpc0JvcmRlckJveCxcblxuXHRcdHZhbCA9IGN1ckNTUyggZWxlbSwgZGltZW5zaW9uLCBzdHlsZXMgKSxcblx0XHRvZmZzZXRQcm9wID0gXCJvZmZzZXRcIiArIGRpbWVuc2lvblsgMCBdLnRvVXBwZXJDYXNlKCkgKyBkaW1lbnNpb24uc2xpY2UoIDEgKTtcblxuXHQvLyBTdXBwb3J0OiBGaXJlZm94IDw9NTRcblx0Ly8gUmV0dXJuIGEgY29uZm91bmRpbmcgbm9uLXBpeGVsIHZhbHVlIG9yIGZlaWduIGlnbm9yYW5jZSwgYXMgYXBwcm9wcmlhdGUuXG5cdGlmICggcm51bW5vbnB4LnRlc3QoIHZhbCApICkge1xuXHRcdGlmICggIWV4dHJhICkge1xuXHRcdFx0cmV0dXJuIHZhbDtcblx0XHR9XG5cdFx0dmFsID0gXCJhdXRvXCI7XG5cdH1cblxuXG5cdC8vIEZhbGwgYmFjayB0byBvZmZzZXRXaWR0aC9vZmZzZXRIZWlnaHQgd2hlbiB2YWx1ZSBpcyBcImF1dG9cIlxuXHQvLyBUaGlzIGhhcHBlbnMgZm9yIGlubGluZSBlbGVtZW50cyB3aXRoIG5vIGV4cGxpY2l0IHNldHRpbmcgKGdoLTM1NzEpXG5cdC8vIFN1cHBvcnQ6IEFuZHJvaWQgPD00LjEgLSA0LjMgb25seVxuXHQvLyBBbHNvIHVzZSBvZmZzZXRXaWR0aC9vZmZzZXRIZWlnaHQgZm9yIG1pc3JlcG9ydGVkIGlubGluZSBkaW1lbnNpb25zIChnaC0zNjAyKVxuXHQvLyBTdXBwb3J0OiBJRSA5LTExIG9ubHlcblx0Ly8gQWxzbyB1c2Ugb2Zmc2V0V2lkdGgvb2Zmc2V0SGVpZ2h0IGZvciB3aGVuIGJveCBzaXppbmcgaXMgdW5yZWxpYWJsZVxuXHQvLyBXZSB1c2UgZ2V0Q2xpZW50UmVjdHMoKSB0byBjaGVjayBmb3IgaGlkZGVuL2Rpc2Nvbm5lY3RlZC5cblx0Ly8gSW4gdGhvc2UgY2FzZXMsIHRoZSBjb21wdXRlZCB2YWx1ZSBjYW4gYmUgdHJ1c3RlZCB0byBiZSBib3JkZXItYm94XG5cdGlmICggKCAhc3VwcG9ydC5ib3hTaXppbmdSZWxpYWJsZSgpICYmIGlzQm9yZGVyQm94IHx8XG5cdFx0dmFsID09PSBcImF1dG9cIiB8fFxuXHRcdCFwYXJzZUZsb2F0KCB2YWwgKSAmJiBqUXVlcnkuY3NzKCBlbGVtLCBcImRpc3BsYXlcIiwgZmFsc2UsIHN0eWxlcyApID09PSBcImlubGluZVwiICkgJiZcblx0XHRlbGVtLmdldENsaWVudFJlY3RzKCkubGVuZ3RoICkge1xuXG5cdFx0aXNCb3JkZXJCb3ggPSBqUXVlcnkuY3NzKCBlbGVtLCBcImJveFNpemluZ1wiLCBmYWxzZSwgc3R5bGVzICkgPT09IFwiYm9yZGVyLWJveFwiO1xuXG5cdFx0Ly8gV2hlcmUgYXZhaWxhYmxlLCBvZmZzZXRXaWR0aC9vZmZzZXRIZWlnaHQgYXBwcm94aW1hdGUgYm9yZGVyIGJveCBkaW1lbnNpb25zLlxuXHRcdC8vIFdoZXJlIG5vdCBhdmFpbGFibGUgKGUuZy4sIFNWRyksIGFzc3VtZSB1bnJlbGlhYmxlIGJveC1zaXppbmcgYW5kIGludGVycHJldCB0aGVcblx0XHQvLyByZXRyaWV2ZWQgdmFsdWUgYXMgYSBjb250ZW50IGJveCBkaW1lbnNpb24uXG5cdFx0dmFsdWVJc0JvcmRlckJveCA9IG9mZnNldFByb3AgaW4gZWxlbTtcblx0XHRpZiAoIHZhbHVlSXNCb3JkZXJCb3ggKSB7XG5cdFx0XHR2YWwgPSBlbGVtWyBvZmZzZXRQcm9wIF07XG5cdFx0fVxuXHR9XG5cblx0Ly8gTm9ybWFsaXplIFwiXCIgYW5kIGF1dG9cblx0dmFsID0gcGFyc2VGbG9hdCggdmFsICkgfHwgMDtcblxuXHQvLyBBZGp1c3QgZm9yIHRoZSBlbGVtZW50J3MgYm94IG1vZGVsXG5cdHJldHVybiAoIHZhbCArXG5cdFx0Ym94TW9kZWxBZGp1c3RtZW50KFxuXHRcdFx0ZWxlbSxcblx0XHRcdGRpbWVuc2lvbixcblx0XHRcdGV4dHJhIHx8ICggaXNCb3JkZXJCb3ggPyBcImJvcmRlclwiIDogXCJjb250ZW50XCIgKSxcblx0XHRcdHZhbHVlSXNCb3JkZXJCb3gsXG5cdFx0XHRzdHlsZXMsXG5cblx0XHRcdC8vIFByb3ZpZGUgdGhlIGN1cnJlbnQgY29tcHV0ZWQgc2l6ZSB0byByZXF1ZXN0IHNjcm9sbCBndXR0ZXIgY2FsY3VsYXRpb24gKGdoLTM1ODkpXG5cdFx0XHR2YWxcblx0XHQpXG5cdCkgKyBcInB4XCI7XG59XG5cbmpRdWVyeS5leHRlbmQoIHtcblxuXHQvLyBBZGQgaW4gc3R5bGUgcHJvcGVydHkgaG9va3MgZm9yIG92ZXJyaWRpbmcgdGhlIGRlZmF1bHRcblx0Ly8gYmVoYXZpb3Igb2YgZ2V0dGluZyBhbmQgc2V0dGluZyBhIHN0eWxlIHByb3BlcnR5XG5cdGNzc0hvb2tzOiB7XG5cdFx0b3BhY2l0eToge1xuXHRcdFx0Z2V0OiBmdW5jdGlvbiggZWxlbSwgY29tcHV0ZWQgKSB7XG5cdFx0XHRcdGlmICggY29tcHV0ZWQgKSB7XG5cblx0XHRcdFx0XHQvLyBXZSBzaG91bGQgYWx3YXlzIGdldCBhIG51bWJlciBiYWNrIGZyb20gb3BhY2l0eVxuXHRcdFx0XHRcdHZhciByZXQgPSBjdXJDU1MoIGVsZW0sIFwib3BhY2l0eVwiICk7XG5cdFx0XHRcdFx0cmV0dXJuIHJldCA9PT0gXCJcIiA/IFwiMVwiIDogcmV0O1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdC8vIERvbid0IGF1dG9tYXRpY2FsbHkgYWRkIFwicHhcIiB0byB0aGVzZSBwb3NzaWJseS11bml0bGVzcyBwcm9wZXJ0aWVzXG5cdGNzc051bWJlcjoge1xuXHRcdFwiYW5pbWF0aW9uSXRlcmF0aW9uQ291bnRcIjogdHJ1ZSxcblx0XHRcImNvbHVtbkNvdW50XCI6IHRydWUsXG5cdFx0XCJmaWxsT3BhY2l0eVwiOiB0cnVlLFxuXHRcdFwiZmxleEdyb3dcIjogdHJ1ZSxcblx0XHRcImZsZXhTaHJpbmtcIjogdHJ1ZSxcblx0XHRcImZvbnRXZWlnaHRcIjogdHJ1ZSxcblx0XHRcImdyaWRBcmVhXCI6IHRydWUsXG5cdFx0XCJncmlkQ29sdW1uXCI6IHRydWUsXG5cdFx0XCJncmlkQ29sdW1uRW5kXCI6IHRydWUsXG5cdFx0XCJncmlkQ29sdW1uU3RhcnRcIjogdHJ1ZSxcblx0XHRcImdyaWRSb3dcIjogdHJ1ZSxcblx0XHRcImdyaWRSb3dFbmRcIjogdHJ1ZSxcblx0XHRcImdyaWRSb3dTdGFydFwiOiB0cnVlLFxuXHRcdFwibGluZUhlaWdodFwiOiB0cnVlLFxuXHRcdFwib3BhY2l0eVwiOiB0cnVlLFxuXHRcdFwib3JkZXJcIjogdHJ1ZSxcblx0XHRcIm9ycGhhbnNcIjogdHJ1ZSxcblx0XHRcIndpZG93c1wiOiB0cnVlLFxuXHRcdFwiekluZGV4XCI6IHRydWUsXG5cdFx0XCJ6b29tXCI6IHRydWVcblx0fSxcblxuXHQvLyBBZGQgaW4gcHJvcGVydGllcyB3aG9zZSBuYW1lcyB5b3Ugd2lzaCB0byBmaXggYmVmb3JlXG5cdC8vIHNldHRpbmcgb3IgZ2V0dGluZyB0aGUgdmFsdWVcblx0Y3NzUHJvcHM6IHt9LFxuXG5cdC8vIEdldCBhbmQgc2V0IHRoZSBzdHlsZSBwcm9wZXJ0eSBvbiBhIERPTSBOb2RlXG5cdHN0eWxlOiBmdW5jdGlvbiggZWxlbSwgbmFtZSwgdmFsdWUsIGV4dHJhICkge1xuXG5cdFx0Ly8gRG9uJ3Qgc2V0IHN0eWxlcyBvbiB0ZXh0IGFuZCBjb21tZW50IG5vZGVzXG5cdFx0aWYgKCAhZWxlbSB8fCBlbGVtLm5vZGVUeXBlID09PSAzIHx8IGVsZW0ubm9kZVR5cGUgPT09IDggfHwgIWVsZW0uc3R5bGUgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gTWFrZSBzdXJlIHRoYXQgd2UncmUgd29ya2luZyB3aXRoIHRoZSByaWdodCBuYW1lXG5cdFx0dmFyIHJldCwgdHlwZSwgaG9va3MsXG5cdFx0XHRvcmlnTmFtZSA9IGNhbWVsQ2FzZSggbmFtZSApLFxuXHRcdFx0aXNDdXN0b21Qcm9wID0gcmN1c3RvbVByb3AudGVzdCggbmFtZSApLFxuXHRcdFx0c3R5bGUgPSBlbGVtLnN0eWxlO1xuXG5cdFx0Ly8gTWFrZSBzdXJlIHRoYXQgd2UncmUgd29ya2luZyB3aXRoIHRoZSByaWdodCBuYW1lLiBXZSBkb24ndFxuXHRcdC8vIHdhbnQgdG8gcXVlcnkgdGhlIHZhbHVlIGlmIGl0IGlzIGEgQ1NTIGN1c3RvbSBwcm9wZXJ0eVxuXHRcdC8vIHNpbmNlIHRoZXkgYXJlIHVzZXItZGVmaW5lZC5cblx0XHRpZiAoICFpc0N1c3RvbVByb3AgKSB7XG5cdFx0XHRuYW1lID0gZmluYWxQcm9wTmFtZSggb3JpZ05hbWUgKTtcblx0XHR9XG5cblx0XHQvLyBHZXRzIGhvb2sgZm9yIHRoZSBwcmVmaXhlZCB2ZXJzaW9uLCB0aGVuIHVucHJlZml4ZWQgdmVyc2lvblxuXHRcdGhvb2tzID0galF1ZXJ5LmNzc0hvb2tzWyBuYW1lIF0gfHwgalF1ZXJ5LmNzc0hvb2tzWyBvcmlnTmFtZSBdO1xuXG5cdFx0Ly8gQ2hlY2sgaWYgd2UncmUgc2V0dGluZyBhIHZhbHVlXG5cdFx0aWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0dHlwZSA9IHR5cGVvZiB2YWx1ZTtcblxuXHRcdFx0Ly8gQ29udmVydCBcIis9XCIgb3IgXCItPVwiIHRvIHJlbGF0aXZlIG51bWJlcnMgKCM3MzQ1KVxuXHRcdFx0aWYgKCB0eXBlID09PSBcInN0cmluZ1wiICYmICggcmV0ID0gcmNzc051bS5leGVjKCB2YWx1ZSApICkgJiYgcmV0WyAxIF0gKSB7XG5cdFx0XHRcdHZhbHVlID0gYWRqdXN0Q1NTKCBlbGVtLCBuYW1lLCByZXQgKTtcblxuXHRcdFx0XHQvLyBGaXhlcyBidWcgIzkyMzdcblx0XHRcdFx0dHlwZSA9IFwibnVtYmVyXCI7XG5cdFx0XHR9XG5cblx0XHRcdC8vIE1ha2Ugc3VyZSB0aGF0IG51bGwgYW5kIE5hTiB2YWx1ZXMgYXJlbid0IHNldCAoIzcxMTYpXG5cdFx0XHRpZiAoIHZhbHVlID09IG51bGwgfHwgdmFsdWUgIT09IHZhbHVlICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdC8vIElmIGEgbnVtYmVyIHdhcyBwYXNzZWQgaW4sIGFkZCB0aGUgdW5pdCAoZXhjZXB0IGZvciBjZXJ0YWluIENTUyBwcm9wZXJ0aWVzKVxuXHRcdFx0Ly8gVGhlIGlzQ3VzdG9tUHJvcCBjaGVjayBjYW4gYmUgcmVtb3ZlZCBpbiBqUXVlcnkgNC4wIHdoZW4gd2Ugb25seSBhdXRvLWFwcGVuZFxuXHRcdFx0Ly8gXCJweFwiIHRvIGEgZmV3IGhhcmRjb2RlZCB2YWx1ZXMuXG5cdFx0XHRpZiAoIHR5cGUgPT09IFwibnVtYmVyXCIgJiYgIWlzQ3VzdG9tUHJvcCApIHtcblx0XHRcdFx0dmFsdWUgKz0gcmV0ICYmIHJldFsgMyBdIHx8ICggalF1ZXJ5LmNzc051bWJlclsgb3JpZ05hbWUgXSA/IFwiXCIgOiBcInB4XCIgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gYmFja2dyb3VuZC0qIHByb3BzIGFmZmVjdCBvcmlnaW5hbCBjbG9uZSdzIHZhbHVlc1xuXHRcdFx0aWYgKCAhc3VwcG9ydC5jbGVhckNsb25lU3R5bGUgJiYgdmFsdWUgPT09IFwiXCIgJiYgbmFtZS5pbmRleE9mKCBcImJhY2tncm91bmRcIiApID09PSAwICkge1xuXHRcdFx0XHRzdHlsZVsgbmFtZSBdID0gXCJpbmhlcml0XCI7XG5cdFx0XHR9XG5cblx0XHRcdC8vIElmIGEgaG9vayB3YXMgcHJvdmlkZWQsIHVzZSB0aGF0IHZhbHVlLCBvdGhlcndpc2UganVzdCBzZXQgdGhlIHNwZWNpZmllZCB2YWx1ZVxuXHRcdFx0aWYgKCAhaG9va3MgfHwgISggXCJzZXRcIiBpbiBob29rcyApIHx8XG5cdFx0XHRcdCggdmFsdWUgPSBob29rcy5zZXQoIGVsZW0sIHZhbHVlLCBleHRyYSApICkgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRpZiAoIGlzQ3VzdG9tUHJvcCApIHtcblx0XHRcdFx0XHRzdHlsZS5zZXRQcm9wZXJ0eSggbmFtZSwgdmFsdWUgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRzdHlsZVsgbmFtZSBdID0gdmFsdWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIElmIGEgaG9vayB3YXMgcHJvdmlkZWQgZ2V0IHRoZSBub24tY29tcHV0ZWQgdmFsdWUgZnJvbSB0aGVyZVxuXHRcdFx0aWYgKCBob29rcyAmJiBcImdldFwiIGluIGhvb2tzICYmXG5cdFx0XHRcdCggcmV0ID0gaG9va3MuZ2V0KCBlbGVtLCBmYWxzZSwgZXh0cmEgKSApICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0cmV0dXJuIHJldDtcblx0XHRcdH1cblxuXHRcdFx0Ly8gT3RoZXJ3aXNlIGp1c3QgZ2V0IHRoZSB2YWx1ZSBmcm9tIHRoZSBzdHlsZSBvYmplY3Rcblx0XHRcdHJldHVybiBzdHlsZVsgbmFtZSBdO1xuXHRcdH1cblx0fSxcblxuXHRjc3M6IGZ1bmN0aW9uKCBlbGVtLCBuYW1lLCBleHRyYSwgc3R5bGVzICkge1xuXHRcdHZhciB2YWwsIG51bSwgaG9va3MsXG5cdFx0XHRvcmlnTmFtZSA9IGNhbWVsQ2FzZSggbmFtZSApLFxuXHRcdFx0aXNDdXN0b21Qcm9wID0gcmN1c3RvbVByb3AudGVzdCggbmFtZSApO1xuXG5cdFx0Ly8gTWFrZSBzdXJlIHRoYXQgd2UncmUgd29ya2luZyB3aXRoIHRoZSByaWdodCBuYW1lLiBXZSBkb24ndFxuXHRcdC8vIHdhbnQgdG8gbW9kaWZ5IHRoZSB2YWx1ZSBpZiBpdCBpcyBhIENTUyBjdXN0b20gcHJvcGVydHlcblx0XHQvLyBzaW5jZSB0aGV5IGFyZSB1c2VyLWRlZmluZWQuXG5cdFx0aWYgKCAhaXNDdXN0b21Qcm9wICkge1xuXHRcdFx0bmFtZSA9IGZpbmFsUHJvcE5hbWUoIG9yaWdOYW1lICk7XG5cdFx0fVxuXG5cdFx0Ly8gVHJ5IHByZWZpeGVkIG5hbWUgZm9sbG93ZWQgYnkgdGhlIHVucHJlZml4ZWQgbmFtZVxuXHRcdGhvb2tzID0galF1ZXJ5LmNzc0hvb2tzWyBuYW1lIF0gfHwgalF1ZXJ5LmNzc0hvb2tzWyBvcmlnTmFtZSBdO1xuXG5cdFx0Ly8gSWYgYSBob29rIHdhcyBwcm92aWRlZCBnZXQgdGhlIGNvbXB1dGVkIHZhbHVlIGZyb20gdGhlcmVcblx0XHRpZiAoIGhvb2tzICYmIFwiZ2V0XCIgaW4gaG9va3MgKSB7XG5cdFx0XHR2YWwgPSBob29rcy5nZXQoIGVsZW0sIHRydWUsIGV4dHJhICk7XG5cdFx0fVxuXG5cdFx0Ly8gT3RoZXJ3aXNlLCBpZiBhIHdheSB0byBnZXQgdGhlIGNvbXB1dGVkIHZhbHVlIGV4aXN0cywgdXNlIHRoYXRcblx0XHRpZiAoIHZhbCA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0dmFsID0gY3VyQ1NTKCBlbGVtLCBuYW1lLCBzdHlsZXMgKTtcblx0XHR9XG5cblx0XHQvLyBDb252ZXJ0IFwibm9ybWFsXCIgdG8gY29tcHV0ZWQgdmFsdWVcblx0XHRpZiAoIHZhbCA9PT0gXCJub3JtYWxcIiAmJiBuYW1lIGluIGNzc05vcm1hbFRyYW5zZm9ybSApIHtcblx0XHRcdHZhbCA9IGNzc05vcm1hbFRyYW5zZm9ybVsgbmFtZSBdO1xuXHRcdH1cblxuXHRcdC8vIE1ha2UgbnVtZXJpYyBpZiBmb3JjZWQgb3IgYSBxdWFsaWZpZXIgd2FzIHByb3ZpZGVkIGFuZCB2YWwgbG9va3MgbnVtZXJpY1xuXHRcdGlmICggZXh0cmEgPT09IFwiXCIgfHwgZXh0cmEgKSB7XG5cdFx0XHRudW0gPSBwYXJzZUZsb2F0KCB2YWwgKTtcblx0XHRcdHJldHVybiBleHRyYSA9PT0gdHJ1ZSB8fCBpc0Zpbml0ZSggbnVtICkgPyBudW0gfHwgMCA6IHZhbDtcblx0XHR9XG5cblx0XHRyZXR1cm4gdmFsO1xuXHR9XG59ICk7XG5cbmpRdWVyeS5lYWNoKCBbIFwiaGVpZ2h0XCIsIFwid2lkdGhcIiBdLCBmdW5jdGlvbiggaSwgZGltZW5zaW9uICkge1xuXHRqUXVlcnkuY3NzSG9va3NbIGRpbWVuc2lvbiBdID0ge1xuXHRcdGdldDogZnVuY3Rpb24oIGVsZW0sIGNvbXB1dGVkLCBleHRyYSApIHtcblx0XHRcdGlmICggY29tcHV0ZWQgKSB7XG5cblx0XHRcdFx0Ly8gQ2VydGFpbiBlbGVtZW50cyBjYW4gaGF2ZSBkaW1lbnNpb24gaW5mbyBpZiB3ZSBpbnZpc2libHkgc2hvdyB0aGVtXG5cdFx0XHRcdC8vIGJ1dCBpdCBtdXN0IGhhdmUgYSBjdXJyZW50IGRpc3BsYXkgc3R5bGUgdGhhdCB3b3VsZCBiZW5lZml0XG5cdFx0XHRcdHJldHVybiByZGlzcGxheXN3YXAudGVzdCggalF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIgKSApICYmXG5cblx0XHRcdFx0XHQvLyBTdXBwb3J0OiBTYWZhcmkgOCtcblx0XHRcdFx0XHQvLyBUYWJsZSBjb2x1bW5zIGluIFNhZmFyaSBoYXZlIG5vbi16ZXJvIG9mZnNldFdpZHRoICYgemVyb1xuXHRcdFx0XHRcdC8vIGdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoIHVubGVzcyBkaXNwbGF5IGlzIGNoYW5nZWQuXG5cdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgPD0xMSBvbmx5XG5cdFx0XHRcdFx0Ly8gUnVubmluZyBnZXRCb3VuZGluZ0NsaWVudFJlY3Qgb24gYSBkaXNjb25uZWN0ZWQgbm9kZVxuXHRcdFx0XHRcdC8vIGluIElFIHRocm93cyBhbiBlcnJvci5cblx0XHRcdFx0XHQoICFlbGVtLmdldENsaWVudFJlY3RzKCkubGVuZ3RoIHx8ICFlbGVtLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLndpZHRoICkgP1xuXHRcdFx0XHRcdFx0c3dhcCggZWxlbSwgY3NzU2hvdywgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiBnZXRXaWR0aE9ySGVpZ2h0KCBlbGVtLCBkaW1lbnNpb24sIGV4dHJhICk7XG5cdFx0XHRcdFx0XHR9ICkgOlxuXHRcdFx0XHRcdFx0Z2V0V2lkdGhPckhlaWdodCggZWxlbSwgZGltZW5zaW9uLCBleHRyYSApO1xuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHRzZXQ6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSwgZXh0cmEgKSB7XG5cdFx0XHR2YXIgbWF0Y2hlcyxcblx0XHRcdFx0c3R5bGVzID0gZ2V0U3R5bGVzKCBlbGVtICksXG5cblx0XHRcdFx0Ly8gT25seSByZWFkIHN0eWxlcy5wb3NpdGlvbiBpZiB0aGUgdGVzdCBoYXMgYSBjaGFuY2UgdG8gZmFpbFxuXHRcdFx0XHQvLyB0byBhdm9pZCBmb3JjaW5nIGEgcmVmbG93LlxuXHRcdFx0XHRzY3JvbGxib3hTaXplQnVnZ3kgPSAhc3VwcG9ydC5zY3JvbGxib3hTaXplKCkgJiZcblx0XHRcdFx0XHRzdHlsZXMucG9zaXRpb24gPT09IFwiYWJzb2x1dGVcIixcblxuXHRcdFx0XHQvLyBUbyBhdm9pZCBmb3JjaW5nIGEgcmVmbG93LCBvbmx5IGZldGNoIGJveFNpemluZyBpZiB3ZSBuZWVkIGl0IChnaC0zOTkxKVxuXHRcdFx0XHRib3hTaXppbmdOZWVkZWQgPSBzY3JvbGxib3hTaXplQnVnZ3kgfHwgZXh0cmEsXG5cdFx0XHRcdGlzQm9yZGVyQm94ID0gYm94U2l6aW5nTmVlZGVkICYmXG5cdFx0XHRcdFx0alF1ZXJ5LmNzcyggZWxlbSwgXCJib3hTaXppbmdcIiwgZmFsc2UsIHN0eWxlcyApID09PSBcImJvcmRlci1ib3hcIixcblx0XHRcdFx0c3VidHJhY3QgPSBleHRyYSA/XG5cdFx0XHRcdFx0Ym94TW9kZWxBZGp1c3RtZW50KFxuXHRcdFx0XHRcdFx0ZWxlbSxcblx0XHRcdFx0XHRcdGRpbWVuc2lvbixcblx0XHRcdFx0XHRcdGV4dHJhLFxuXHRcdFx0XHRcdFx0aXNCb3JkZXJCb3gsXG5cdFx0XHRcdFx0XHRzdHlsZXNcblx0XHRcdFx0XHQpIDpcblx0XHRcdFx0XHQwO1xuXG5cdFx0XHQvLyBBY2NvdW50IGZvciB1bnJlbGlhYmxlIGJvcmRlci1ib3ggZGltZW5zaW9ucyBieSBjb21wYXJpbmcgb2Zmc2V0KiB0byBjb21wdXRlZCBhbmRcblx0XHRcdC8vIGZha2luZyBhIGNvbnRlbnQtYm94IHRvIGdldCBib3JkZXIgYW5kIHBhZGRpbmcgKGdoLTM2OTkpXG5cdFx0XHRpZiAoIGlzQm9yZGVyQm94ICYmIHNjcm9sbGJveFNpemVCdWdneSApIHtcblx0XHRcdFx0c3VidHJhY3QgLT0gTWF0aC5jZWlsKFxuXHRcdFx0XHRcdGVsZW1bIFwib2Zmc2V0XCIgKyBkaW1lbnNpb25bIDAgXS50b1VwcGVyQ2FzZSgpICsgZGltZW5zaW9uLnNsaWNlKCAxICkgXSAtXG5cdFx0XHRcdFx0cGFyc2VGbG9hdCggc3R5bGVzWyBkaW1lbnNpb24gXSApIC1cblx0XHRcdFx0XHRib3hNb2RlbEFkanVzdG1lbnQoIGVsZW0sIGRpbWVuc2lvbiwgXCJib3JkZXJcIiwgZmFsc2UsIHN0eWxlcyApIC1cblx0XHRcdFx0XHQwLjVcblx0XHRcdFx0KTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ29udmVydCB0byBwaXhlbHMgaWYgdmFsdWUgYWRqdXN0bWVudCBpcyBuZWVkZWRcblx0XHRcdGlmICggc3VidHJhY3QgJiYgKCBtYXRjaGVzID0gcmNzc051bS5leGVjKCB2YWx1ZSApICkgJiZcblx0XHRcdFx0KCBtYXRjaGVzWyAzIF0gfHwgXCJweFwiICkgIT09IFwicHhcIiApIHtcblxuXHRcdFx0XHRlbGVtLnN0eWxlWyBkaW1lbnNpb24gXSA9IHZhbHVlO1xuXHRcdFx0XHR2YWx1ZSA9IGpRdWVyeS5jc3MoIGVsZW0sIGRpbWVuc2lvbiApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gc2V0UG9zaXRpdmVOdW1iZXIoIGVsZW0sIHZhbHVlLCBzdWJ0cmFjdCApO1xuXHRcdH1cblx0fTtcbn0gKTtcblxualF1ZXJ5LmNzc0hvb2tzLm1hcmdpbkxlZnQgPSBhZGRHZXRIb29rSWYoIHN1cHBvcnQucmVsaWFibGVNYXJnaW5MZWZ0LFxuXHRmdW5jdGlvbiggZWxlbSwgY29tcHV0ZWQgKSB7XG5cdFx0aWYgKCBjb21wdXRlZCApIHtcblx0XHRcdHJldHVybiAoIHBhcnNlRmxvYXQoIGN1ckNTUyggZWxlbSwgXCJtYXJnaW5MZWZ0XCIgKSApIHx8XG5cdFx0XHRcdGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdCAtXG5cdFx0XHRcdFx0c3dhcCggZWxlbSwgeyBtYXJnaW5MZWZ0OiAwIH0sIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdDtcblx0XHRcdFx0XHR9IClcblx0XHRcdFx0KSArIFwicHhcIjtcblx0XHR9XG5cdH1cbik7XG5cbi8vIFRoZXNlIGhvb2tzIGFyZSB1c2VkIGJ5IGFuaW1hdGUgdG8gZXhwYW5kIHByb3BlcnRpZXNcbmpRdWVyeS5lYWNoKCB7XG5cdG1hcmdpbjogXCJcIixcblx0cGFkZGluZzogXCJcIixcblx0Ym9yZGVyOiBcIldpZHRoXCJcbn0sIGZ1bmN0aW9uKCBwcmVmaXgsIHN1ZmZpeCApIHtcblx0alF1ZXJ5LmNzc0hvb2tzWyBwcmVmaXggKyBzdWZmaXggXSA9IHtcblx0XHRleHBhbmQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdHZhciBpID0gMCxcblx0XHRcdFx0ZXhwYW5kZWQgPSB7fSxcblxuXHRcdFx0XHQvLyBBc3N1bWVzIGEgc2luZ2xlIG51bWJlciBpZiBub3QgYSBzdHJpbmdcblx0XHRcdFx0cGFydHMgPSB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgPyB2YWx1ZS5zcGxpdCggXCIgXCIgKSA6IFsgdmFsdWUgXTtcblxuXHRcdFx0Zm9yICggOyBpIDwgNDsgaSsrICkge1xuXHRcdFx0XHRleHBhbmRlZFsgcHJlZml4ICsgY3NzRXhwYW5kWyBpIF0gKyBzdWZmaXggXSA9XG5cdFx0XHRcdFx0cGFydHNbIGkgXSB8fCBwYXJ0c1sgaSAtIDIgXSB8fCBwYXJ0c1sgMCBdO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZXhwYW5kZWQ7XG5cdFx0fVxuXHR9O1xuXG5cdGlmICggcHJlZml4ICE9PSBcIm1hcmdpblwiICkge1xuXHRcdGpRdWVyeS5jc3NIb29rc1sgcHJlZml4ICsgc3VmZml4IF0uc2V0ID0gc2V0UG9zaXRpdmVOdW1iZXI7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHRjc3M6IGZ1bmN0aW9uKCBuYW1lLCB2YWx1ZSApIHtcblx0XHRyZXR1cm4gYWNjZXNzKCB0aGlzLCBmdW5jdGlvbiggZWxlbSwgbmFtZSwgdmFsdWUgKSB7XG5cdFx0XHR2YXIgc3R5bGVzLCBsZW4sXG5cdFx0XHRcdG1hcCA9IHt9LFxuXHRcdFx0XHRpID0gMDtcblxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBuYW1lICkgKSB7XG5cdFx0XHRcdHN0eWxlcyA9IGdldFN0eWxlcyggZWxlbSApO1xuXHRcdFx0XHRsZW4gPSBuYW1lLmxlbmd0aDtcblxuXHRcdFx0XHRmb3IgKCA7IGkgPCBsZW47IGkrKyApIHtcblx0XHRcdFx0XHRtYXBbIG5hbWVbIGkgXSBdID0galF1ZXJ5LmNzcyggZWxlbSwgbmFtZVsgaSBdLCBmYWxzZSwgc3R5bGVzICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gbWFwO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdmFsdWUgIT09IHVuZGVmaW5lZCA/XG5cdFx0XHRcdGpRdWVyeS5zdHlsZSggZWxlbSwgbmFtZSwgdmFsdWUgKSA6XG5cdFx0XHRcdGpRdWVyeS5jc3MoIGVsZW0sIG5hbWUgKTtcblx0XHR9LCBuYW1lLCB2YWx1ZSwgYXJndW1lbnRzLmxlbmd0aCA+IDEgKTtcblx0fVxufSApO1xuXG5cbmZ1bmN0aW9uIFR3ZWVuKCBlbGVtLCBvcHRpb25zLCBwcm9wLCBlbmQsIGVhc2luZyApIHtcblx0cmV0dXJuIG5ldyBUd2Vlbi5wcm90b3R5cGUuaW5pdCggZWxlbSwgb3B0aW9ucywgcHJvcCwgZW5kLCBlYXNpbmcgKTtcbn1cbmpRdWVyeS5Ud2VlbiA9IFR3ZWVuO1xuXG5Ud2Vlbi5wcm90b3R5cGUgPSB7XG5cdGNvbnN0cnVjdG9yOiBUd2Vlbixcblx0aW5pdDogZnVuY3Rpb24oIGVsZW0sIG9wdGlvbnMsIHByb3AsIGVuZCwgZWFzaW5nLCB1bml0ICkge1xuXHRcdHRoaXMuZWxlbSA9IGVsZW07XG5cdFx0dGhpcy5wcm9wID0gcHJvcDtcblx0XHR0aGlzLmVhc2luZyA9IGVhc2luZyB8fCBqUXVlcnkuZWFzaW5nLl9kZWZhdWx0O1xuXHRcdHRoaXMub3B0aW9ucyA9IG9wdGlvbnM7XG5cdFx0dGhpcy5zdGFydCA9IHRoaXMubm93ID0gdGhpcy5jdXIoKTtcblx0XHR0aGlzLmVuZCA9IGVuZDtcblx0XHR0aGlzLnVuaXQgPSB1bml0IHx8ICggalF1ZXJ5LmNzc051bWJlclsgcHJvcCBdID8gXCJcIiA6IFwicHhcIiApO1xuXHR9LFxuXHRjdXI6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBob29rcyA9IFR3ZWVuLnByb3BIb29rc1sgdGhpcy5wcm9wIF07XG5cblx0XHRyZXR1cm4gaG9va3MgJiYgaG9va3MuZ2V0ID9cblx0XHRcdGhvb2tzLmdldCggdGhpcyApIDpcblx0XHRcdFR3ZWVuLnByb3BIb29rcy5fZGVmYXVsdC5nZXQoIHRoaXMgKTtcblx0fSxcblx0cnVuOiBmdW5jdGlvbiggcGVyY2VudCApIHtcblx0XHR2YXIgZWFzZWQsXG5cdFx0XHRob29rcyA9IFR3ZWVuLnByb3BIb29rc1sgdGhpcy5wcm9wIF07XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kdXJhdGlvbiApIHtcblx0XHRcdHRoaXMucG9zID0gZWFzZWQgPSBqUXVlcnkuZWFzaW5nWyB0aGlzLmVhc2luZyBdKFxuXHRcdFx0XHRwZXJjZW50LCB0aGlzLm9wdGlvbnMuZHVyYXRpb24gKiBwZXJjZW50LCAwLCAxLCB0aGlzLm9wdGlvbnMuZHVyYXRpb25cblx0XHRcdCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMucG9zID0gZWFzZWQgPSBwZXJjZW50O1xuXHRcdH1cblx0XHR0aGlzLm5vdyA9ICggdGhpcy5lbmQgLSB0aGlzLnN0YXJ0ICkgKiBlYXNlZCArIHRoaXMuc3RhcnQ7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5zdGVwICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLnN0ZXAuY2FsbCggdGhpcy5lbGVtLCB0aGlzLm5vdywgdGhpcyApO1xuXHRcdH1cblxuXHRcdGlmICggaG9va3MgJiYgaG9va3Muc2V0ICkge1xuXHRcdFx0aG9va3Muc2V0KCB0aGlzICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdFR3ZWVuLnByb3BIb29rcy5fZGVmYXVsdC5zZXQoIHRoaXMgKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cbn07XG5cblR3ZWVuLnByb3RvdHlwZS5pbml0LnByb3RvdHlwZSA9IFR3ZWVuLnByb3RvdHlwZTtcblxuVHdlZW4ucHJvcEhvb2tzID0ge1xuXHRfZGVmYXVsdDoge1xuXHRcdGdldDogZnVuY3Rpb24oIHR3ZWVuICkge1xuXHRcdFx0dmFyIHJlc3VsdDtcblxuXHRcdFx0Ly8gVXNlIGEgcHJvcGVydHkgb24gdGhlIGVsZW1lbnQgZGlyZWN0bHkgd2hlbiBpdCBpcyBub3QgYSBET00gZWxlbWVudCxcblx0XHRcdC8vIG9yIHdoZW4gdGhlcmUgaXMgbm8gbWF0Y2hpbmcgc3R5bGUgcHJvcGVydHkgdGhhdCBleGlzdHMuXG5cdFx0XHRpZiAoIHR3ZWVuLmVsZW0ubm9kZVR5cGUgIT09IDEgfHxcblx0XHRcdFx0dHdlZW4uZWxlbVsgdHdlZW4ucHJvcCBdICE9IG51bGwgJiYgdHdlZW4uZWxlbS5zdHlsZVsgdHdlZW4ucHJvcCBdID09IG51bGwgKSB7XG5cdFx0XHRcdHJldHVybiB0d2Vlbi5lbGVtWyB0d2Vlbi5wcm9wIF07XG5cdFx0XHR9XG5cblx0XHRcdC8vIFBhc3NpbmcgYW4gZW1wdHkgc3RyaW5nIGFzIGEgM3JkIHBhcmFtZXRlciB0byAuY3NzIHdpbGwgYXV0b21hdGljYWxseVxuXHRcdFx0Ly8gYXR0ZW1wdCBhIHBhcnNlRmxvYXQgYW5kIGZhbGxiYWNrIHRvIGEgc3RyaW5nIGlmIHRoZSBwYXJzZSBmYWlscy5cblx0XHRcdC8vIFNpbXBsZSB2YWx1ZXMgc3VjaCBhcyBcIjEwcHhcIiBhcmUgcGFyc2VkIHRvIEZsb2F0O1xuXHRcdFx0Ly8gY29tcGxleCB2YWx1ZXMgc3VjaCBhcyBcInJvdGF0ZSgxcmFkKVwiIGFyZSByZXR1cm5lZCBhcy1pcy5cblx0XHRcdHJlc3VsdCA9IGpRdWVyeS5jc3MoIHR3ZWVuLmVsZW0sIHR3ZWVuLnByb3AsIFwiXCIgKTtcblxuXHRcdFx0Ly8gRW1wdHkgc3RyaW5ncywgbnVsbCwgdW5kZWZpbmVkIGFuZCBcImF1dG9cIiBhcmUgY29udmVydGVkIHRvIDAuXG5cdFx0XHRyZXR1cm4gIXJlc3VsdCB8fCByZXN1bHQgPT09IFwiYXV0b1wiID8gMCA6IHJlc3VsdDtcblx0XHR9LFxuXHRcdHNldDogZnVuY3Rpb24oIHR3ZWVuICkge1xuXG5cdFx0XHQvLyBVc2Ugc3RlcCBob29rIGZvciBiYWNrIGNvbXBhdC5cblx0XHRcdC8vIFVzZSBjc3NIb29rIGlmIGl0cyB0aGVyZS5cblx0XHRcdC8vIFVzZSAuc3R5bGUgaWYgYXZhaWxhYmxlIGFuZCB1c2UgcGxhaW4gcHJvcGVydGllcyB3aGVyZSBhdmFpbGFibGUuXG5cdFx0XHRpZiAoIGpRdWVyeS5meC5zdGVwWyB0d2Vlbi5wcm9wIF0gKSB7XG5cdFx0XHRcdGpRdWVyeS5meC5zdGVwWyB0d2Vlbi5wcm9wIF0oIHR3ZWVuICk7XG5cdFx0XHR9IGVsc2UgaWYgKCB0d2Vlbi5lbGVtLm5vZGVUeXBlID09PSAxICYmIChcblx0XHRcdFx0XHRqUXVlcnkuY3NzSG9va3NbIHR3ZWVuLnByb3AgXSB8fFxuXHRcdFx0XHRcdHR3ZWVuLmVsZW0uc3R5bGVbIGZpbmFsUHJvcE5hbWUoIHR3ZWVuLnByb3AgKSBdICE9IG51bGwgKSApIHtcblx0XHRcdFx0alF1ZXJ5LnN0eWxlKCB0d2Vlbi5lbGVtLCB0d2Vlbi5wcm9wLCB0d2Vlbi5ub3cgKyB0d2Vlbi51bml0ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0d2Vlbi5lbGVtWyB0d2Vlbi5wcm9wIF0gPSB0d2Vlbi5ub3c7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59O1xuXG4vLyBTdXBwb3J0OiBJRSA8PTkgb25seVxuLy8gUGFuaWMgYmFzZWQgYXBwcm9hY2ggdG8gc2V0dGluZyB0aGluZ3Mgb24gZGlzY29ubmVjdGVkIG5vZGVzXG5Ud2Vlbi5wcm9wSG9va3Muc2Nyb2xsVG9wID0gVHdlZW4ucHJvcEhvb2tzLnNjcm9sbExlZnQgPSB7XG5cdHNldDogZnVuY3Rpb24oIHR3ZWVuICkge1xuXHRcdGlmICggdHdlZW4uZWxlbS5ub2RlVHlwZSAmJiB0d2Vlbi5lbGVtLnBhcmVudE5vZGUgKSB7XG5cdFx0XHR0d2Vlbi5lbGVtWyB0d2Vlbi5wcm9wIF0gPSB0d2Vlbi5ub3c7XG5cdFx0fVxuXHR9XG59O1xuXG5qUXVlcnkuZWFzaW5nID0ge1xuXHRsaW5lYXI6IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiBwO1xuXHR9LFxuXHRzd2luZzogZnVuY3Rpb24oIHAgKSB7XG5cdFx0cmV0dXJuIDAuNSAtIE1hdGguY29zKCBwICogTWF0aC5QSSApIC8gMjtcblx0fSxcblx0X2RlZmF1bHQ6IFwic3dpbmdcIlxufTtcblxualF1ZXJ5LmZ4ID0gVHdlZW4ucHJvdG90eXBlLmluaXQ7XG5cbi8vIEJhY2sgY29tcGF0IDwxLjggZXh0ZW5zaW9uIHBvaW50XG5qUXVlcnkuZnguc3RlcCA9IHt9O1xuXG5cblxuXG52YXJcblx0ZnhOb3csIGluUHJvZ3Jlc3MsXG5cdHJmeHR5cGVzID0gL14oPzp0b2dnbGV8c2hvd3xoaWRlKSQvLFxuXHRycnVuID0gL3F1ZXVlSG9va3MkLztcblxuZnVuY3Rpb24gc2NoZWR1bGUoKSB7XG5cdGlmICggaW5Qcm9ncmVzcyApIHtcblx0XHRpZiAoIGRvY3VtZW50LmhpZGRlbiA9PT0gZmFsc2UgJiYgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZSApIHtcblx0XHRcdHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoIHNjaGVkdWxlICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHdpbmRvdy5zZXRUaW1lb3V0KCBzY2hlZHVsZSwgalF1ZXJ5LmZ4LmludGVydmFsICk7XG5cdFx0fVxuXG5cdFx0alF1ZXJ5LmZ4LnRpY2soKTtcblx0fVxufVxuXG4vLyBBbmltYXRpb25zIGNyZWF0ZWQgc3luY2hyb25vdXNseSB3aWxsIHJ1biBzeW5jaHJvbm91c2x5XG5mdW5jdGlvbiBjcmVhdGVGeE5vdygpIHtcblx0d2luZG93LnNldFRpbWVvdXQoIGZ1bmN0aW9uKCkge1xuXHRcdGZ4Tm93ID0gdW5kZWZpbmVkO1xuXHR9ICk7XG5cdHJldHVybiAoIGZ4Tm93ID0gRGF0ZS5ub3coKSApO1xufVxuXG4vLyBHZW5lcmF0ZSBwYXJhbWV0ZXJzIHRvIGNyZWF0ZSBhIHN0YW5kYXJkIGFuaW1hdGlvblxuZnVuY3Rpb24gZ2VuRngoIHR5cGUsIGluY2x1ZGVXaWR0aCApIHtcblx0dmFyIHdoaWNoLFxuXHRcdGkgPSAwLFxuXHRcdGF0dHJzID0geyBoZWlnaHQ6IHR5cGUgfTtcblxuXHQvLyBJZiB3ZSBpbmNsdWRlIHdpZHRoLCBzdGVwIHZhbHVlIGlzIDEgdG8gZG8gYWxsIGNzc0V4cGFuZCB2YWx1ZXMsXG5cdC8vIG90aGVyd2lzZSBzdGVwIHZhbHVlIGlzIDIgdG8gc2tpcCBvdmVyIExlZnQgYW5kIFJpZ2h0XG5cdGluY2x1ZGVXaWR0aCA9IGluY2x1ZGVXaWR0aCA/IDEgOiAwO1xuXHRmb3IgKCA7IGkgPCA0OyBpICs9IDIgLSBpbmNsdWRlV2lkdGggKSB7XG5cdFx0d2hpY2ggPSBjc3NFeHBhbmRbIGkgXTtcblx0XHRhdHRyc1sgXCJtYXJnaW5cIiArIHdoaWNoIF0gPSBhdHRyc1sgXCJwYWRkaW5nXCIgKyB3aGljaCBdID0gdHlwZTtcblx0fVxuXG5cdGlmICggaW5jbHVkZVdpZHRoICkge1xuXHRcdGF0dHJzLm9wYWNpdHkgPSBhdHRycy53aWR0aCA9IHR5cGU7XG5cdH1cblxuXHRyZXR1cm4gYXR0cnM7XG59XG5cbmZ1bmN0aW9uIGNyZWF0ZVR3ZWVuKCB2YWx1ZSwgcHJvcCwgYW5pbWF0aW9uICkge1xuXHR2YXIgdHdlZW4sXG5cdFx0Y29sbGVjdGlvbiA9ICggQW5pbWF0aW9uLnR3ZWVuZXJzWyBwcm9wIF0gfHwgW10gKS5jb25jYXQoIEFuaW1hdGlvbi50d2VlbmVyc1sgXCIqXCIgXSApLFxuXHRcdGluZGV4ID0gMCxcblx0XHRsZW5ndGggPSBjb2xsZWN0aW9uLmxlbmd0aDtcblx0Zm9yICggOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKyApIHtcblx0XHRpZiAoICggdHdlZW4gPSBjb2xsZWN0aW9uWyBpbmRleCBdLmNhbGwoIGFuaW1hdGlvbiwgcHJvcCwgdmFsdWUgKSApICkge1xuXG5cdFx0XHQvLyBXZSdyZSBkb25lIHdpdGggdGhpcyBwcm9wZXJ0eVxuXHRcdFx0cmV0dXJuIHR3ZWVuO1xuXHRcdH1cblx0fVxufVxuXG5mdW5jdGlvbiBkZWZhdWx0UHJlZmlsdGVyKCBlbGVtLCBwcm9wcywgb3B0cyApIHtcblx0dmFyIHByb3AsIHZhbHVlLCB0b2dnbGUsIGhvb2tzLCBvbGRmaXJlLCBwcm9wVHdlZW4sIHJlc3RvcmVEaXNwbGF5LCBkaXNwbGF5LFxuXHRcdGlzQm94ID0gXCJ3aWR0aFwiIGluIHByb3BzIHx8IFwiaGVpZ2h0XCIgaW4gcHJvcHMsXG5cdFx0YW5pbSA9IHRoaXMsXG5cdFx0b3JpZyA9IHt9LFxuXHRcdHN0eWxlID0gZWxlbS5zdHlsZSxcblx0XHRoaWRkZW4gPSBlbGVtLm5vZGVUeXBlICYmIGlzSGlkZGVuV2l0aGluVHJlZSggZWxlbSApLFxuXHRcdGRhdGFTaG93ID0gZGF0YVByaXYuZ2V0KCBlbGVtLCBcImZ4c2hvd1wiICk7XG5cblx0Ly8gUXVldWUtc2tpcHBpbmcgYW5pbWF0aW9ucyBoaWphY2sgdGhlIGZ4IGhvb2tzXG5cdGlmICggIW9wdHMucXVldWUgKSB7XG5cdFx0aG9va3MgPSBqUXVlcnkuX3F1ZXVlSG9va3MoIGVsZW0sIFwiZnhcIiApO1xuXHRcdGlmICggaG9va3MudW5xdWV1ZWQgPT0gbnVsbCApIHtcblx0XHRcdGhvb2tzLnVucXVldWVkID0gMDtcblx0XHRcdG9sZGZpcmUgPSBob29rcy5lbXB0eS5maXJlO1xuXHRcdFx0aG9va3MuZW1wdHkuZmlyZSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoICFob29rcy51bnF1ZXVlZCApIHtcblx0XHRcdFx0XHRvbGRmaXJlKCk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cdFx0fVxuXHRcdGhvb2tzLnVucXVldWVkKys7XG5cblx0XHRhbmltLmFsd2F5cyggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIEVuc3VyZSB0aGUgY29tcGxldGUgaGFuZGxlciBpcyBjYWxsZWQgYmVmb3JlIHRoaXMgY29tcGxldGVzXG5cdFx0XHRhbmltLmFsd2F5cyggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGhvb2tzLnVucXVldWVkLS07XG5cdFx0XHRcdGlmICggIWpRdWVyeS5xdWV1ZSggZWxlbSwgXCJmeFwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRcdGhvb2tzLmVtcHR5LmZpcmUoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0fVxuXG5cdC8vIERldGVjdCBzaG93L2hpZGUgYW5pbWF0aW9uc1xuXHRmb3IgKCBwcm9wIGluIHByb3BzICkge1xuXHRcdHZhbHVlID0gcHJvcHNbIHByb3AgXTtcblx0XHRpZiAoIHJmeHR5cGVzLnRlc3QoIHZhbHVlICkgKSB7XG5cdFx0XHRkZWxldGUgcHJvcHNbIHByb3AgXTtcblx0XHRcdHRvZ2dsZSA9IHRvZ2dsZSB8fCB2YWx1ZSA9PT0gXCJ0b2dnbGVcIjtcblx0XHRcdGlmICggdmFsdWUgPT09ICggaGlkZGVuID8gXCJoaWRlXCIgOiBcInNob3dcIiApICkge1xuXG5cdFx0XHRcdC8vIFByZXRlbmQgdG8gYmUgaGlkZGVuIGlmIHRoaXMgaXMgYSBcInNob3dcIiBhbmRcblx0XHRcdFx0Ly8gdGhlcmUgaXMgc3RpbGwgZGF0YSBmcm9tIGEgc3RvcHBlZCBzaG93L2hpZGVcblx0XHRcdFx0aWYgKCB2YWx1ZSA9PT0gXCJzaG93XCIgJiYgZGF0YVNob3cgJiYgZGF0YVNob3dbIHByb3AgXSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdGhpZGRlbiA9IHRydWU7XG5cblx0XHRcdFx0Ly8gSWdub3JlIGFsbCBvdGhlciBuby1vcCBzaG93L2hpZGUgZGF0YVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRvcmlnWyBwcm9wIF0gPSBkYXRhU2hvdyAmJiBkYXRhU2hvd1sgcHJvcCBdIHx8IGpRdWVyeS5zdHlsZSggZWxlbSwgcHJvcCApO1xuXHRcdH1cblx0fVxuXG5cdC8vIEJhaWwgb3V0IGlmIHRoaXMgaXMgYSBuby1vcCBsaWtlIC5oaWRlKCkuaGlkZSgpXG5cdHByb3BUd2VlbiA9ICFqUXVlcnkuaXNFbXB0eU9iamVjdCggcHJvcHMgKTtcblx0aWYgKCAhcHJvcFR3ZWVuICYmIGpRdWVyeS5pc0VtcHR5T2JqZWN0KCBvcmlnICkgKSB7XG5cdFx0cmV0dXJuO1xuXHR9XG5cblx0Ly8gUmVzdHJpY3QgXCJvdmVyZmxvd1wiIGFuZCBcImRpc3BsYXlcIiBzdHlsZXMgZHVyaW5nIGJveCBhbmltYXRpb25zXG5cdGlmICggaXNCb3ggJiYgZWxlbS5ub2RlVHlwZSA9PT0gMSApIHtcblxuXHRcdC8vIFN1cHBvcnQ6IElFIDw9OSAtIDExLCBFZGdlIDEyIC0gMTVcblx0XHQvLyBSZWNvcmQgYWxsIDMgb3ZlcmZsb3cgYXR0cmlidXRlcyBiZWNhdXNlIElFIGRvZXMgbm90IGluZmVyIHRoZSBzaG9ydGhhbmRcblx0XHQvLyBmcm9tIGlkZW50aWNhbGx5LXZhbHVlZCBvdmVyZmxvd1ggYW5kIG92ZXJmbG93WSBhbmQgRWRnZSBqdXN0IG1pcnJvcnNcblx0XHQvLyB0aGUgb3ZlcmZsb3dYIHZhbHVlIHRoZXJlLlxuXHRcdG9wdHMub3ZlcmZsb3cgPSBbIHN0eWxlLm92ZXJmbG93LCBzdHlsZS5vdmVyZmxvd1gsIHN0eWxlLm92ZXJmbG93WSBdO1xuXG5cdFx0Ly8gSWRlbnRpZnkgYSBkaXNwbGF5IHR5cGUsIHByZWZlcnJpbmcgb2xkIHNob3cvaGlkZSBkYXRhIG92ZXIgdGhlIENTUyBjYXNjYWRlXG5cdFx0cmVzdG9yZURpc3BsYXkgPSBkYXRhU2hvdyAmJiBkYXRhU2hvdy5kaXNwbGF5O1xuXHRcdGlmICggcmVzdG9yZURpc3BsYXkgPT0gbnVsbCApIHtcblx0XHRcdHJlc3RvcmVEaXNwbGF5ID0gZGF0YVByaXYuZ2V0KCBlbGVtLCBcImRpc3BsYXlcIiApO1xuXHRcdH1cblx0XHRkaXNwbGF5ID0galF1ZXJ5LmNzcyggZWxlbSwgXCJkaXNwbGF5XCIgKTtcblx0XHRpZiAoIGRpc3BsYXkgPT09IFwibm9uZVwiICkge1xuXHRcdFx0aWYgKCByZXN0b3JlRGlzcGxheSApIHtcblx0XHRcdFx0ZGlzcGxheSA9IHJlc3RvcmVEaXNwbGF5O1xuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBHZXQgbm9uZW1wdHkgdmFsdWUocykgYnkgdGVtcG9yYXJpbHkgZm9yY2luZyB2aXNpYmlsaXR5XG5cdFx0XHRcdHNob3dIaWRlKCBbIGVsZW0gXSwgdHJ1ZSApO1xuXHRcdFx0XHRyZXN0b3JlRGlzcGxheSA9IGVsZW0uc3R5bGUuZGlzcGxheSB8fCByZXN0b3JlRGlzcGxheTtcblx0XHRcdFx0ZGlzcGxheSA9IGpRdWVyeS5jc3MoIGVsZW0sIFwiZGlzcGxheVwiICk7XG5cdFx0XHRcdHNob3dIaWRlKCBbIGVsZW0gXSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIEFuaW1hdGUgaW5saW5lIGVsZW1lbnRzIGFzIGlubGluZS1ibG9ja1xuXHRcdGlmICggZGlzcGxheSA9PT0gXCJpbmxpbmVcIiB8fCBkaXNwbGF5ID09PSBcImlubGluZS1ibG9ja1wiICYmIHJlc3RvcmVEaXNwbGF5ICE9IG51bGwgKSB7XG5cdFx0XHRpZiAoIGpRdWVyeS5jc3MoIGVsZW0sIFwiZmxvYXRcIiApID09PSBcIm5vbmVcIiApIHtcblxuXHRcdFx0XHQvLyBSZXN0b3JlIHRoZSBvcmlnaW5hbCBkaXNwbGF5IHZhbHVlIGF0IHRoZSBlbmQgb2YgcHVyZSBzaG93L2hpZGUgYW5pbWF0aW9uc1xuXHRcdFx0XHRpZiAoICFwcm9wVHdlZW4gKSB7XG5cdFx0XHRcdFx0YW5pbS5kb25lKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHN0eWxlLmRpc3BsYXkgPSByZXN0b3JlRGlzcGxheTtcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0aWYgKCByZXN0b3JlRGlzcGxheSA9PSBudWxsICkge1xuXHRcdFx0XHRcdFx0ZGlzcGxheSA9IHN0eWxlLmRpc3BsYXk7XG5cdFx0XHRcdFx0XHRyZXN0b3JlRGlzcGxheSA9IGRpc3BsYXkgPT09IFwibm9uZVwiID8gXCJcIiA6IGRpc3BsYXk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdHN0eWxlLmRpc3BsYXkgPSBcImlubGluZS1ibG9ja1wiO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdGlmICggb3B0cy5vdmVyZmxvdyApIHtcblx0XHRzdHlsZS5vdmVyZmxvdyA9IFwiaGlkZGVuXCI7XG5cdFx0YW5pbS5hbHdheXMoIGZ1bmN0aW9uKCkge1xuXHRcdFx0c3R5bGUub3ZlcmZsb3cgPSBvcHRzLm92ZXJmbG93WyAwIF07XG5cdFx0XHRzdHlsZS5vdmVyZmxvd1ggPSBvcHRzLm92ZXJmbG93WyAxIF07XG5cdFx0XHRzdHlsZS5vdmVyZmxvd1kgPSBvcHRzLm92ZXJmbG93WyAyIF07XG5cdFx0fSApO1xuXHR9XG5cblx0Ly8gSW1wbGVtZW50IHNob3cvaGlkZSBhbmltYXRpb25zXG5cdHByb3BUd2VlbiA9IGZhbHNlO1xuXHRmb3IgKCBwcm9wIGluIG9yaWcgKSB7XG5cblx0XHQvLyBHZW5lcmFsIHNob3cvaGlkZSBzZXR1cCBmb3IgdGhpcyBlbGVtZW50IGFuaW1hdGlvblxuXHRcdGlmICggIXByb3BUd2VlbiApIHtcblx0XHRcdGlmICggZGF0YVNob3cgKSB7XG5cdFx0XHRcdGlmICggXCJoaWRkZW5cIiBpbiBkYXRhU2hvdyApIHtcblx0XHRcdFx0XHRoaWRkZW4gPSBkYXRhU2hvdy5oaWRkZW47XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGRhdGFTaG93ID0gZGF0YVByaXYuYWNjZXNzKCBlbGVtLCBcImZ4c2hvd1wiLCB7IGRpc3BsYXk6IHJlc3RvcmVEaXNwbGF5IH0gKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU3RvcmUgaGlkZGVuL3Zpc2libGUgZm9yIHRvZ2dsZSBzbyBgLnN0b3AoKS50b2dnbGUoKWAgXCJyZXZlcnNlc1wiXG5cdFx0XHRpZiAoIHRvZ2dsZSApIHtcblx0XHRcdFx0ZGF0YVNob3cuaGlkZGVuID0gIWhpZGRlbjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU2hvdyBlbGVtZW50cyBiZWZvcmUgYW5pbWF0aW5nIHRoZW1cblx0XHRcdGlmICggaGlkZGVuICkge1xuXHRcdFx0XHRzaG93SGlkZSggWyBlbGVtIF0sIHRydWUgKTtcblx0XHRcdH1cblxuXHRcdFx0LyogZXNsaW50LWRpc2FibGUgbm8tbG9vcC1mdW5jICovXG5cblx0XHRcdGFuaW0uZG9uZSggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8qIGVzbGludC1lbmFibGUgbm8tbG9vcC1mdW5jICovXG5cblx0XHRcdFx0Ly8gVGhlIGZpbmFsIHN0ZXAgb2YgYSBcImhpZGVcIiBhbmltYXRpb24gaXMgYWN0dWFsbHkgaGlkaW5nIHRoZSBlbGVtZW50XG5cdFx0XHRcdGlmICggIWhpZGRlbiApIHtcblx0XHRcdFx0XHRzaG93SGlkZSggWyBlbGVtIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRkYXRhUHJpdi5yZW1vdmUoIGVsZW0sIFwiZnhzaG93XCIgKTtcblx0XHRcdFx0Zm9yICggcHJvcCBpbiBvcmlnICkge1xuXHRcdFx0XHRcdGpRdWVyeS5zdHlsZSggZWxlbSwgcHJvcCwgb3JpZ1sgcHJvcCBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHQvLyBQZXItcHJvcGVydHkgc2V0dXBcblx0XHRwcm9wVHdlZW4gPSBjcmVhdGVUd2VlbiggaGlkZGVuID8gZGF0YVNob3dbIHByb3AgXSA6IDAsIHByb3AsIGFuaW0gKTtcblx0XHRpZiAoICEoIHByb3AgaW4gZGF0YVNob3cgKSApIHtcblx0XHRcdGRhdGFTaG93WyBwcm9wIF0gPSBwcm9wVHdlZW4uc3RhcnQ7XG5cdFx0XHRpZiAoIGhpZGRlbiApIHtcblx0XHRcdFx0cHJvcFR3ZWVuLmVuZCA9IHByb3BUd2Vlbi5zdGFydDtcblx0XHRcdFx0cHJvcFR3ZWVuLnN0YXJ0ID0gMDtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn1cblxuZnVuY3Rpb24gcHJvcEZpbHRlciggcHJvcHMsIHNwZWNpYWxFYXNpbmcgKSB7XG5cdHZhciBpbmRleCwgbmFtZSwgZWFzaW5nLCB2YWx1ZSwgaG9va3M7XG5cblx0Ly8gY2FtZWxDYXNlLCBzcGVjaWFsRWFzaW5nIGFuZCBleHBhbmQgY3NzSG9vayBwYXNzXG5cdGZvciAoIGluZGV4IGluIHByb3BzICkge1xuXHRcdG5hbWUgPSBjYW1lbENhc2UoIGluZGV4ICk7XG5cdFx0ZWFzaW5nID0gc3BlY2lhbEVhc2luZ1sgbmFtZSBdO1xuXHRcdHZhbHVlID0gcHJvcHNbIGluZGV4IF07XG5cdFx0aWYgKCBBcnJheS5pc0FycmF5KCB2YWx1ZSApICkge1xuXHRcdFx0ZWFzaW5nID0gdmFsdWVbIDEgXTtcblx0XHRcdHZhbHVlID0gcHJvcHNbIGluZGV4IF0gPSB2YWx1ZVsgMCBdO1xuXHRcdH1cblxuXHRcdGlmICggaW5kZXggIT09IG5hbWUgKSB7XG5cdFx0XHRwcm9wc1sgbmFtZSBdID0gdmFsdWU7XG5cdFx0XHRkZWxldGUgcHJvcHNbIGluZGV4IF07XG5cdFx0fVxuXG5cdFx0aG9va3MgPSBqUXVlcnkuY3NzSG9va3NbIG5hbWUgXTtcblx0XHRpZiAoIGhvb2tzICYmIFwiZXhwYW5kXCIgaW4gaG9va3MgKSB7XG5cdFx0XHR2YWx1ZSA9IGhvb2tzLmV4cGFuZCggdmFsdWUgKTtcblx0XHRcdGRlbGV0ZSBwcm9wc1sgbmFtZSBdO1xuXG5cdFx0XHQvLyBOb3QgcXVpdGUgJC5leHRlbmQsIHRoaXMgd29uJ3Qgb3ZlcndyaXRlIGV4aXN0aW5nIGtleXMuXG5cdFx0XHQvLyBSZXVzaW5nICdpbmRleCcgYmVjYXVzZSB3ZSBoYXZlIHRoZSBjb3JyZWN0IFwibmFtZVwiXG5cdFx0XHRmb3IgKCBpbmRleCBpbiB2YWx1ZSApIHtcblx0XHRcdFx0aWYgKCAhKCBpbmRleCBpbiBwcm9wcyApICkge1xuXHRcdFx0XHRcdHByb3BzWyBpbmRleCBdID0gdmFsdWVbIGluZGV4IF07XG5cdFx0XHRcdFx0c3BlY2lhbEVhc2luZ1sgaW5kZXggXSA9IGVhc2luZztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRzcGVjaWFsRWFzaW5nWyBuYW1lIF0gPSBlYXNpbmc7XG5cdFx0fVxuXHR9XG59XG5cbmZ1bmN0aW9uIEFuaW1hdGlvbiggZWxlbSwgcHJvcGVydGllcywgb3B0aW9ucyApIHtcblx0dmFyIHJlc3VsdCxcblx0XHRzdG9wcGVkLFxuXHRcdGluZGV4ID0gMCxcblx0XHRsZW5ndGggPSBBbmltYXRpb24ucHJlZmlsdGVycy5sZW5ndGgsXG5cdFx0ZGVmZXJyZWQgPSBqUXVlcnkuRGVmZXJyZWQoKS5hbHdheXMoIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBEb24ndCBtYXRjaCBlbGVtIGluIHRoZSA6YW5pbWF0ZWQgc2VsZWN0b3Jcblx0XHRcdGRlbGV0ZSB0aWNrLmVsZW07XG5cdFx0fSApLFxuXHRcdHRpY2sgPSBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggc3RvcHBlZCApIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dmFyIGN1cnJlbnRUaW1lID0gZnhOb3cgfHwgY3JlYXRlRnhOb3coKSxcblx0XHRcdFx0cmVtYWluaW5nID0gTWF0aC5tYXgoIDAsIGFuaW1hdGlvbi5zdGFydFRpbWUgKyBhbmltYXRpb24uZHVyYXRpb24gLSBjdXJyZW50VGltZSApLFxuXG5cdFx0XHRcdC8vIFN1cHBvcnQ6IEFuZHJvaWQgMi4zIG9ubHlcblx0XHRcdFx0Ly8gQXJjaGFpYyBjcmFzaCBidWcgd29uJ3QgYWxsb3cgdXMgdG8gdXNlIGAxIC0gKCAwLjUgfHwgMCApYCAoIzEyNDk3KVxuXHRcdFx0XHR0ZW1wID0gcmVtYWluaW5nIC8gYW5pbWF0aW9uLmR1cmF0aW9uIHx8IDAsXG5cdFx0XHRcdHBlcmNlbnQgPSAxIC0gdGVtcCxcblx0XHRcdFx0aW5kZXggPSAwLFxuXHRcdFx0XHRsZW5ndGggPSBhbmltYXRpb24udHdlZW5zLmxlbmd0aDtcblxuXHRcdFx0Zm9yICggOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKyApIHtcblx0XHRcdFx0YW5pbWF0aW9uLnR3ZWVuc1sgaW5kZXggXS5ydW4oIHBlcmNlbnQgKTtcblx0XHRcdH1cblxuXHRcdFx0ZGVmZXJyZWQubm90aWZ5V2l0aCggZWxlbSwgWyBhbmltYXRpb24sIHBlcmNlbnQsIHJlbWFpbmluZyBdICk7XG5cblx0XHRcdC8vIElmIHRoZXJlJ3MgbW9yZSB0byBkbywgeWllbGRcblx0XHRcdGlmICggcGVyY2VudCA8IDEgJiYgbGVuZ3RoICkge1xuXHRcdFx0XHRyZXR1cm4gcmVtYWluaW5nO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBJZiB0aGlzIHdhcyBhbiBlbXB0eSBhbmltYXRpb24sIHN5bnRoZXNpemUgYSBmaW5hbCBwcm9ncmVzcyBub3RpZmljYXRpb25cblx0XHRcdGlmICggIWxlbmd0aCApIHtcblx0XHRcdFx0ZGVmZXJyZWQubm90aWZ5V2l0aCggZWxlbSwgWyBhbmltYXRpb24sIDEsIDAgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBSZXNvbHZlIHRoZSBhbmltYXRpb24gYW5kIHJlcG9ydCBpdHMgY29uY2x1c2lvblxuXHRcdFx0ZGVmZXJyZWQucmVzb2x2ZVdpdGgoIGVsZW0sIFsgYW5pbWF0aW9uIF0gKTtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9LFxuXHRcdGFuaW1hdGlvbiA9IGRlZmVycmVkLnByb21pc2UoIHtcblx0XHRcdGVsZW06IGVsZW0sXG5cdFx0XHRwcm9wczogalF1ZXJ5LmV4dGVuZCgge30sIHByb3BlcnRpZXMgKSxcblx0XHRcdG9wdHM6IGpRdWVyeS5leHRlbmQoIHRydWUsIHtcblx0XHRcdFx0c3BlY2lhbEVhc2luZzoge30sXG5cdFx0XHRcdGVhc2luZzogalF1ZXJ5LmVhc2luZy5fZGVmYXVsdFxuXHRcdFx0fSwgb3B0aW9ucyApLFxuXHRcdFx0b3JpZ2luYWxQcm9wZXJ0aWVzOiBwcm9wZXJ0aWVzLFxuXHRcdFx0b3JpZ2luYWxPcHRpb25zOiBvcHRpb25zLFxuXHRcdFx0c3RhcnRUaW1lOiBmeE5vdyB8fCBjcmVhdGVGeE5vdygpLFxuXHRcdFx0ZHVyYXRpb246IG9wdGlvbnMuZHVyYXRpb24sXG5cdFx0XHR0d2VlbnM6IFtdLFxuXHRcdFx0Y3JlYXRlVHdlZW46IGZ1bmN0aW9uKCBwcm9wLCBlbmQgKSB7XG5cdFx0XHRcdHZhciB0d2VlbiA9IGpRdWVyeS5Ud2VlbiggZWxlbSwgYW5pbWF0aW9uLm9wdHMsIHByb3AsIGVuZCxcblx0XHRcdFx0XHRcdGFuaW1hdGlvbi5vcHRzLnNwZWNpYWxFYXNpbmdbIHByb3AgXSB8fCBhbmltYXRpb24ub3B0cy5lYXNpbmcgKTtcblx0XHRcdFx0YW5pbWF0aW9uLnR3ZWVucy5wdXNoKCB0d2VlbiApO1xuXHRcdFx0XHRyZXR1cm4gdHdlZW47XG5cdFx0XHR9LFxuXHRcdFx0c3RvcDogZnVuY3Rpb24oIGdvdG9FbmQgKSB7XG5cdFx0XHRcdHZhciBpbmRleCA9IDAsXG5cblx0XHRcdFx0XHQvLyBJZiB3ZSBhcmUgZ29pbmcgdG8gdGhlIGVuZCwgd2Ugd2FudCB0byBydW4gYWxsIHRoZSB0d2VlbnNcblx0XHRcdFx0XHQvLyBvdGhlcndpc2Ugd2Ugc2tpcCB0aGlzIHBhcnRcblx0XHRcdFx0XHRsZW5ndGggPSBnb3RvRW5kID8gYW5pbWF0aW9uLnR3ZWVucy5sZW5ndGggOiAwO1xuXHRcdFx0XHRpZiAoIHN0b3BwZWQgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHRcdH1cblx0XHRcdFx0c3RvcHBlZCA9IHRydWU7XG5cdFx0XHRcdGZvciAoIDsgaW5kZXggPCBsZW5ndGg7IGluZGV4KysgKSB7XG5cdFx0XHRcdFx0YW5pbWF0aW9uLnR3ZWVuc1sgaW5kZXggXS5ydW4oIDEgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFJlc29sdmUgd2hlbiB3ZSBwbGF5ZWQgdGhlIGxhc3QgZnJhbWU7IG90aGVyd2lzZSwgcmVqZWN0XG5cdFx0XHRcdGlmICggZ290b0VuZCApIHtcblx0XHRcdFx0XHRkZWZlcnJlZC5ub3RpZnlXaXRoKCBlbGVtLCBbIGFuaW1hdGlvbiwgMSwgMCBdICk7XG5cdFx0XHRcdFx0ZGVmZXJyZWQucmVzb2x2ZVdpdGgoIGVsZW0sIFsgYW5pbWF0aW9uLCBnb3RvRW5kIF0gKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRkZWZlcnJlZC5yZWplY3RXaXRoKCBlbGVtLCBbIGFuaW1hdGlvbiwgZ290b0VuZCBdICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHR9XG5cdFx0fSApLFxuXHRcdHByb3BzID0gYW5pbWF0aW9uLnByb3BzO1xuXG5cdHByb3BGaWx0ZXIoIHByb3BzLCBhbmltYXRpb24ub3B0cy5zcGVjaWFsRWFzaW5nICk7XG5cblx0Zm9yICggOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKyApIHtcblx0XHRyZXN1bHQgPSBBbmltYXRpb24ucHJlZmlsdGVyc1sgaW5kZXggXS5jYWxsKCBhbmltYXRpb24sIGVsZW0sIHByb3BzLCBhbmltYXRpb24ub3B0cyApO1xuXHRcdGlmICggcmVzdWx0ICkge1xuXHRcdFx0aWYgKCBpc0Z1bmN0aW9uKCByZXN1bHQuc3RvcCApICkge1xuXHRcdFx0XHRqUXVlcnkuX3F1ZXVlSG9va3MoIGFuaW1hdGlvbi5lbGVtLCBhbmltYXRpb24ub3B0cy5xdWV1ZSApLnN0b3AgPVxuXHRcdFx0XHRcdHJlc3VsdC5zdG9wLmJpbmQoIHJlc3VsdCApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHJlc3VsdDtcblx0XHR9XG5cdH1cblxuXHRqUXVlcnkubWFwKCBwcm9wcywgY3JlYXRlVHdlZW4sIGFuaW1hdGlvbiApO1xuXG5cdGlmICggaXNGdW5jdGlvbiggYW5pbWF0aW9uLm9wdHMuc3RhcnQgKSApIHtcblx0XHRhbmltYXRpb24ub3B0cy5zdGFydC5jYWxsKCBlbGVtLCBhbmltYXRpb24gKTtcblx0fVxuXG5cdC8vIEF0dGFjaCBjYWxsYmFja3MgZnJvbSBvcHRpb25zXG5cdGFuaW1hdGlvblxuXHRcdC5wcm9ncmVzcyggYW5pbWF0aW9uLm9wdHMucHJvZ3Jlc3MgKVxuXHRcdC5kb25lKCBhbmltYXRpb24ub3B0cy5kb25lLCBhbmltYXRpb24ub3B0cy5jb21wbGV0ZSApXG5cdFx0LmZhaWwoIGFuaW1hdGlvbi5vcHRzLmZhaWwgKVxuXHRcdC5hbHdheXMoIGFuaW1hdGlvbi5vcHRzLmFsd2F5cyApO1xuXG5cdGpRdWVyeS5meC50aW1lcihcblx0XHRqUXVlcnkuZXh0ZW5kKCB0aWNrLCB7XG5cdFx0XHRlbGVtOiBlbGVtLFxuXHRcdFx0YW5pbTogYW5pbWF0aW9uLFxuXHRcdFx0cXVldWU6IGFuaW1hdGlvbi5vcHRzLnF1ZXVlXG5cdFx0fSApXG5cdCk7XG5cblx0cmV0dXJuIGFuaW1hdGlvbjtcbn1cblxualF1ZXJ5LkFuaW1hdGlvbiA9IGpRdWVyeS5leHRlbmQoIEFuaW1hdGlvbiwge1xuXG5cdHR3ZWVuZXJzOiB7XG5cdFx0XCIqXCI6IFsgZnVuY3Rpb24oIHByb3AsIHZhbHVlICkge1xuXHRcdFx0dmFyIHR3ZWVuID0gdGhpcy5jcmVhdGVUd2VlbiggcHJvcCwgdmFsdWUgKTtcblx0XHRcdGFkanVzdENTUyggdHdlZW4uZWxlbSwgcHJvcCwgcmNzc051bS5leGVjKCB2YWx1ZSApLCB0d2VlbiApO1xuXHRcdFx0cmV0dXJuIHR3ZWVuO1xuXHRcdH0gXVxuXHR9LFxuXG5cdHR3ZWVuZXI6IGZ1bmN0aW9uKCBwcm9wcywgY2FsbGJhY2sgKSB7XG5cdFx0aWYgKCBpc0Z1bmN0aW9uKCBwcm9wcyApICkge1xuXHRcdFx0Y2FsbGJhY2sgPSBwcm9wcztcblx0XHRcdHByb3BzID0gWyBcIipcIiBdO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRwcm9wcyA9IHByb3BzLm1hdGNoKCBybm90aHRtbHdoaXRlICk7XG5cdFx0fVxuXG5cdFx0dmFyIHByb3AsXG5cdFx0XHRpbmRleCA9IDAsXG5cdFx0XHRsZW5ndGggPSBwcm9wcy5sZW5ndGg7XG5cblx0XHRmb3IgKCA7IGluZGV4IDwgbGVuZ3RoOyBpbmRleCsrICkge1xuXHRcdFx0cHJvcCA9IHByb3BzWyBpbmRleCBdO1xuXHRcdFx0QW5pbWF0aW9uLnR3ZWVuZXJzWyBwcm9wIF0gPSBBbmltYXRpb24udHdlZW5lcnNbIHByb3AgXSB8fCBbXTtcblx0XHRcdEFuaW1hdGlvbi50d2VlbmVyc1sgcHJvcCBdLnVuc2hpZnQoIGNhbGxiYWNrICk7XG5cdFx0fVxuXHR9LFxuXG5cdHByZWZpbHRlcnM6IFsgZGVmYXVsdFByZWZpbHRlciBdLFxuXG5cdHByZWZpbHRlcjogZnVuY3Rpb24oIGNhbGxiYWNrLCBwcmVwZW5kICkge1xuXHRcdGlmICggcHJlcGVuZCApIHtcblx0XHRcdEFuaW1hdGlvbi5wcmVmaWx0ZXJzLnVuc2hpZnQoIGNhbGxiYWNrICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdEFuaW1hdGlvbi5wcmVmaWx0ZXJzLnB1c2goIGNhbGxiYWNrICk7XG5cdFx0fVxuXHR9XG59ICk7XG5cbmpRdWVyeS5zcGVlZCA9IGZ1bmN0aW9uKCBzcGVlZCwgZWFzaW5nLCBmbiApIHtcblx0dmFyIG9wdCA9IHNwZWVkICYmIHR5cGVvZiBzcGVlZCA9PT0gXCJvYmplY3RcIiA/IGpRdWVyeS5leHRlbmQoIHt9LCBzcGVlZCApIDoge1xuXHRcdGNvbXBsZXRlOiBmbiB8fCAhZm4gJiYgZWFzaW5nIHx8XG5cdFx0XHRpc0Z1bmN0aW9uKCBzcGVlZCApICYmIHNwZWVkLFxuXHRcdGR1cmF0aW9uOiBzcGVlZCxcblx0XHRlYXNpbmc6IGZuICYmIGVhc2luZyB8fCBlYXNpbmcgJiYgIWlzRnVuY3Rpb24oIGVhc2luZyApICYmIGVhc2luZ1xuXHR9O1xuXG5cdC8vIEdvIHRvIHRoZSBlbmQgc3RhdGUgaWYgZnggYXJlIG9mZlxuXHRpZiAoIGpRdWVyeS5meC5vZmYgKSB7XG5cdFx0b3B0LmR1cmF0aW9uID0gMDtcblxuXHR9IGVsc2Uge1xuXHRcdGlmICggdHlwZW9mIG9wdC5kdXJhdGlvbiAhPT0gXCJudW1iZXJcIiApIHtcblx0XHRcdGlmICggb3B0LmR1cmF0aW9uIGluIGpRdWVyeS5meC5zcGVlZHMgKSB7XG5cdFx0XHRcdG9wdC5kdXJhdGlvbiA9IGpRdWVyeS5meC5zcGVlZHNbIG9wdC5kdXJhdGlvbiBdO1xuXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRvcHQuZHVyYXRpb24gPSBqUXVlcnkuZnguc3BlZWRzLl9kZWZhdWx0O1xuXHRcdFx0fVxuXHRcdH1cblx0fVxuXG5cdC8vIE5vcm1hbGl6ZSBvcHQucXVldWUgLSB0cnVlL3VuZGVmaW5lZC9udWxsIC0+IFwiZnhcIlxuXHRpZiAoIG9wdC5xdWV1ZSA9PSBudWxsIHx8IG9wdC5xdWV1ZSA9PT0gdHJ1ZSApIHtcblx0XHRvcHQucXVldWUgPSBcImZ4XCI7XG5cdH1cblxuXHQvLyBRdWV1ZWluZ1xuXHRvcHQub2xkID0gb3B0LmNvbXBsZXRlO1xuXG5cdG9wdC5jb21wbGV0ZSA9IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggaXNGdW5jdGlvbiggb3B0Lm9sZCApICkge1xuXHRcdFx0b3B0Lm9sZC5jYWxsKCB0aGlzICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBvcHQucXVldWUgKSB7XG5cdFx0XHRqUXVlcnkuZGVxdWV1ZSggdGhpcywgb3B0LnF1ZXVlICk7XG5cdFx0fVxuXHR9O1xuXG5cdHJldHVybiBvcHQ7XG59O1xuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdGZhZGVUbzogZnVuY3Rpb24oIHNwZWVkLCB0bywgZWFzaW5nLCBjYWxsYmFjayApIHtcblxuXHRcdC8vIFNob3cgYW55IGhpZGRlbiBlbGVtZW50cyBhZnRlciBzZXR0aW5nIG9wYWNpdHkgdG8gMFxuXHRcdHJldHVybiB0aGlzLmZpbHRlciggaXNIaWRkZW5XaXRoaW5UcmVlICkuY3NzKCBcIm9wYWNpdHlcIiwgMCApLnNob3coKVxuXG5cdFx0XHQvLyBBbmltYXRlIHRvIHRoZSB2YWx1ZSBzcGVjaWZpZWRcblx0XHRcdC5lbmQoKS5hbmltYXRlKCB7IG9wYWNpdHk6IHRvIH0sIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICk7XG5cdH0sXG5cdGFuaW1hdGU6IGZ1bmN0aW9uKCBwcm9wLCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIHtcblx0XHR2YXIgZW1wdHkgPSBqUXVlcnkuaXNFbXB0eU9iamVjdCggcHJvcCApLFxuXHRcdFx0b3B0YWxsID0galF1ZXJ5LnNwZWVkKCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApLFxuXHRcdFx0ZG9BbmltYXRpb24gPSBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHQvLyBPcGVyYXRlIG9uIGEgY29weSBvZiBwcm9wIHNvIHBlci1wcm9wZXJ0eSBlYXNpbmcgd29uJ3QgYmUgbG9zdFxuXHRcdFx0XHR2YXIgYW5pbSA9IEFuaW1hdGlvbiggdGhpcywgalF1ZXJ5LmV4dGVuZCgge30sIHByb3AgKSwgb3B0YWxsICk7XG5cblx0XHRcdFx0Ly8gRW1wdHkgYW5pbWF0aW9ucywgb3IgZmluaXNoaW5nIHJlc29sdmVzIGltbWVkaWF0ZWx5XG5cdFx0XHRcdGlmICggZW1wdHkgfHwgZGF0YVByaXYuZ2V0KCB0aGlzLCBcImZpbmlzaFwiICkgKSB7XG5cdFx0XHRcdFx0YW5pbS5zdG9wKCB0cnVlICk7XG5cdFx0XHRcdH1cblx0XHRcdH07XG5cdFx0XHRkb0FuaW1hdGlvbi5maW5pc2ggPSBkb0FuaW1hdGlvbjtcblxuXHRcdHJldHVybiBlbXB0eSB8fCBvcHRhbGwucXVldWUgPT09IGZhbHNlID9cblx0XHRcdHRoaXMuZWFjaCggZG9BbmltYXRpb24gKSA6XG5cdFx0XHR0aGlzLnF1ZXVlKCBvcHRhbGwucXVldWUsIGRvQW5pbWF0aW9uICk7XG5cdH0sXG5cdHN0b3A6IGZ1bmN0aW9uKCB0eXBlLCBjbGVhclF1ZXVlLCBnb3RvRW5kICkge1xuXHRcdHZhciBzdG9wUXVldWUgPSBmdW5jdGlvbiggaG9va3MgKSB7XG5cdFx0XHR2YXIgc3RvcCA9IGhvb2tzLnN0b3A7XG5cdFx0XHRkZWxldGUgaG9va3Muc3RvcDtcblx0XHRcdHN0b3AoIGdvdG9FbmQgKTtcblx0XHR9O1xuXG5cdFx0aWYgKCB0eXBlb2YgdHlwZSAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdGdvdG9FbmQgPSBjbGVhclF1ZXVlO1xuXHRcdFx0Y2xlYXJRdWV1ZSA9IHR5cGU7XG5cdFx0XHR0eXBlID0gdW5kZWZpbmVkO1xuXHRcdH1cblx0XHRpZiAoIGNsZWFyUXVldWUgJiYgdHlwZSAhPT0gZmFsc2UgKSB7XG5cdFx0XHR0aGlzLnF1ZXVlKCB0eXBlIHx8IFwiZnhcIiwgW10gKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBkZXF1ZXVlID0gdHJ1ZSxcblx0XHRcdFx0aW5kZXggPSB0eXBlICE9IG51bGwgJiYgdHlwZSArIFwicXVldWVIb29rc1wiLFxuXHRcdFx0XHR0aW1lcnMgPSBqUXVlcnkudGltZXJzLFxuXHRcdFx0XHRkYXRhID0gZGF0YVByaXYuZ2V0KCB0aGlzICk7XG5cblx0XHRcdGlmICggaW5kZXggKSB7XG5cdFx0XHRcdGlmICggZGF0YVsgaW5kZXggXSAmJiBkYXRhWyBpbmRleCBdLnN0b3AgKSB7XG5cdFx0XHRcdFx0c3RvcFF1ZXVlKCBkYXRhWyBpbmRleCBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGZvciAoIGluZGV4IGluIGRhdGEgKSB7XG5cdFx0XHRcdFx0aWYgKCBkYXRhWyBpbmRleCBdICYmIGRhdGFbIGluZGV4IF0uc3RvcCAmJiBycnVuLnRlc3QoIGluZGV4ICkgKSB7XG5cdFx0XHRcdFx0XHRzdG9wUXVldWUoIGRhdGFbIGluZGV4IF0gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0Zm9yICggaW5kZXggPSB0aW1lcnMubGVuZ3RoOyBpbmRleC0tOyApIHtcblx0XHRcdFx0aWYgKCB0aW1lcnNbIGluZGV4IF0uZWxlbSA9PT0gdGhpcyAmJlxuXHRcdFx0XHRcdCggdHlwZSA9PSBudWxsIHx8IHRpbWVyc1sgaW5kZXggXS5xdWV1ZSA9PT0gdHlwZSApICkge1xuXG5cdFx0XHRcdFx0dGltZXJzWyBpbmRleCBdLmFuaW0uc3RvcCggZ290b0VuZCApO1xuXHRcdFx0XHRcdGRlcXVldWUgPSBmYWxzZTtcblx0XHRcdFx0XHR0aW1lcnMuc3BsaWNlKCBpbmRleCwgMSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIFN0YXJ0IHRoZSBuZXh0IGluIHRoZSBxdWV1ZSBpZiB0aGUgbGFzdCBzdGVwIHdhc24ndCBmb3JjZWQuXG5cdFx0XHQvLyBUaW1lcnMgY3VycmVudGx5IHdpbGwgY2FsbCB0aGVpciBjb21wbGV0ZSBjYWxsYmFja3MsIHdoaWNoXG5cdFx0XHQvLyB3aWxsIGRlcXVldWUgYnV0IG9ubHkgaWYgdGhleSB3ZXJlIGdvdG9FbmQuXG5cdFx0XHRpZiAoIGRlcXVldWUgfHwgIWdvdG9FbmQgKSB7XG5cdFx0XHRcdGpRdWVyeS5kZXF1ZXVlKCB0aGlzLCB0eXBlICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXHRmaW5pc2g6IGZ1bmN0aW9uKCB0eXBlICkge1xuXHRcdGlmICggdHlwZSAhPT0gZmFsc2UgKSB7XG5cdFx0XHR0eXBlID0gdHlwZSB8fCBcImZ4XCI7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGluZGV4LFxuXHRcdFx0XHRkYXRhID0gZGF0YVByaXYuZ2V0KCB0aGlzICksXG5cdFx0XHRcdHF1ZXVlID0gZGF0YVsgdHlwZSArIFwicXVldWVcIiBdLFxuXHRcdFx0XHRob29rcyA9IGRhdGFbIHR5cGUgKyBcInF1ZXVlSG9va3NcIiBdLFxuXHRcdFx0XHR0aW1lcnMgPSBqUXVlcnkudGltZXJzLFxuXHRcdFx0XHRsZW5ndGggPSBxdWV1ZSA/IHF1ZXVlLmxlbmd0aCA6IDA7XG5cblx0XHRcdC8vIEVuYWJsZSBmaW5pc2hpbmcgZmxhZyBvbiBwcml2YXRlIGRhdGFcblx0XHRcdGRhdGEuZmluaXNoID0gdHJ1ZTtcblxuXHRcdFx0Ly8gRW1wdHkgdGhlIHF1ZXVlIGZpcnN0XG5cdFx0XHRqUXVlcnkucXVldWUoIHRoaXMsIHR5cGUsIFtdICk7XG5cblx0XHRcdGlmICggaG9va3MgJiYgaG9va3Muc3RvcCApIHtcblx0XHRcdFx0aG9va3Muc3RvcC5jYWxsKCB0aGlzLCB0cnVlICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIExvb2sgZm9yIGFueSBhY3RpdmUgYW5pbWF0aW9ucywgYW5kIGZpbmlzaCB0aGVtXG5cdFx0XHRmb3IgKCBpbmRleCA9IHRpbWVycy5sZW5ndGg7IGluZGV4LS07ICkge1xuXHRcdFx0XHRpZiAoIHRpbWVyc1sgaW5kZXggXS5lbGVtID09PSB0aGlzICYmIHRpbWVyc1sgaW5kZXggXS5xdWV1ZSA9PT0gdHlwZSApIHtcblx0XHRcdFx0XHR0aW1lcnNbIGluZGV4IF0uYW5pbS5zdG9wKCB0cnVlICk7XG5cdFx0XHRcdFx0dGltZXJzLnNwbGljZSggaW5kZXgsIDEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBMb29rIGZvciBhbnkgYW5pbWF0aW9ucyBpbiB0aGUgb2xkIHF1ZXVlIGFuZCBmaW5pc2ggdGhlbVxuXHRcdFx0Zm9yICggaW5kZXggPSAwOyBpbmRleCA8IGxlbmd0aDsgaW5kZXgrKyApIHtcblx0XHRcdFx0aWYgKCBxdWV1ZVsgaW5kZXggXSAmJiBxdWV1ZVsgaW5kZXggXS5maW5pc2ggKSB7XG5cdFx0XHRcdFx0cXVldWVbIGluZGV4IF0uZmluaXNoLmNhbGwoIHRoaXMgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBUdXJuIG9mZiBmaW5pc2hpbmcgZmxhZ1xuXHRcdFx0ZGVsZXRlIGRhdGEuZmluaXNoO1xuXHRcdH0gKTtcblx0fVxufSApO1xuXG5qUXVlcnkuZWFjaCggWyBcInRvZ2dsZVwiLCBcInNob3dcIiwgXCJoaWRlXCIgXSwgZnVuY3Rpb24oIGksIG5hbWUgKSB7XG5cdHZhciBjc3NGbiA9IGpRdWVyeS5mblsgbmFtZSBdO1xuXHRqUXVlcnkuZm5bIG5hbWUgXSA9IGZ1bmN0aW9uKCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIHtcblx0XHRyZXR1cm4gc3BlZWQgPT0gbnVsbCB8fCB0eXBlb2Ygc3BlZWQgPT09IFwiYm9vbGVhblwiID9cblx0XHRcdGNzc0ZuLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSA6XG5cdFx0XHR0aGlzLmFuaW1hdGUoIGdlbkZ4KCBuYW1lLCB0cnVlICksIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICk7XG5cdH07XG59ICk7XG5cbi8vIEdlbmVyYXRlIHNob3J0Y3V0cyBmb3IgY3VzdG9tIGFuaW1hdGlvbnNcbmpRdWVyeS5lYWNoKCB7XG5cdHNsaWRlRG93bjogZ2VuRngoIFwic2hvd1wiICksXG5cdHNsaWRlVXA6IGdlbkZ4KCBcImhpZGVcIiApLFxuXHRzbGlkZVRvZ2dsZTogZ2VuRngoIFwidG9nZ2xlXCIgKSxcblx0ZmFkZUluOiB7IG9wYWNpdHk6IFwic2hvd1wiIH0sXG5cdGZhZGVPdXQ6IHsgb3BhY2l0eTogXCJoaWRlXCIgfSxcblx0ZmFkZVRvZ2dsZTogeyBvcGFjaXR5OiBcInRvZ2dsZVwiIH1cbn0sIGZ1bmN0aW9uKCBuYW1lLCBwcm9wcyApIHtcblx0alF1ZXJ5LmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSB7XG5cdFx0cmV0dXJuIHRoaXMuYW5pbWF0ZSggcHJvcHMsIHNwZWVkLCBlYXNpbmcsIGNhbGxiYWNrICk7XG5cdH07XG59ICk7XG5cbmpRdWVyeS50aW1lcnMgPSBbXTtcbmpRdWVyeS5meC50aWNrID0gZnVuY3Rpb24oKSB7XG5cdHZhciB0aW1lcixcblx0XHRpID0gMCxcblx0XHR0aW1lcnMgPSBqUXVlcnkudGltZXJzO1xuXG5cdGZ4Tm93ID0gRGF0ZS5ub3coKTtcblxuXHRmb3IgKCA7IGkgPCB0aW1lcnMubGVuZ3RoOyBpKysgKSB7XG5cdFx0dGltZXIgPSB0aW1lcnNbIGkgXTtcblxuXHRcdC8vIFJ1biB0aGUgdGltZXIgYW5kIHNhZmVseSByZW1vdmUgaXQgd2hlbiBkb25lIChhbGxvd2luZyBmb3IgZXh0ZXJuYWwgcmVtb3ZhbClcblx0XHRpZiAoICF0aW1lcigpICYmIHRpbWVyc1sgaSBdID09PSB0aW1lciApIHtcblx0XHRcdHRpbWVycy5zcGxpY2UoIGktLSwgMSApO1xuXHRcdH1cblx0fVxuXG5cdGlmICggIXRpbWVycy5sZW5ndGggKSB7XG5cdFx0alF1ZXJ5LmZ4LnN0b3AoKTtcblx0fVxuXHRmeE5vdyA9IHVuZGVmaW5lZDtcbn07XG5cbmpRdWVyeS5meC50aW1lciA9IGZ1bmN0aW9uKCB0aW1lciApIHtcblx0alF1ZXJ5LnRpbWVycy5wdXNoKCB0aW1lciApO1xuXHRqUXVlcnkuZnguc3RhcnQoKTtcbn07XG5cbmpRdWVyeS5meC5pbnRlcnZhbCA9IDEzO1xualF1ZXJ5LmZ4LnN0YXJ0ID0gZnVuY3Rpb24oKSB7XG5cdGlmICggaW5Qcm9ncmVzcyApIHtcblx0XHRyZXR1cm47XG5cdH1cblxuXHRpblByb2dyZXNzID0gdHJ1ZTtcblx0c2NoZWR1bGUoKTtcbn07XG5cbmpRdWVyeS5meC5zdG9wID0gZnVuY3Rpb24oKSB7XG5cdGluUHJvZ3Jlc3MgPSBudWxsO1xufTtcblxualF1ZXJ5LmZ4LnNwZWVkcyA9IHtcblx0c2xvdzogNjAwLFxuXHRmYXN0OiAyMDAsXG5cblx0Ly8gRGVmYXVsdCBzcGVlZFxuXHRfZGVmYXVsdDogNDAwXG59O1xuXG5cbi8vIEJhc2VkIG9mZiBvZiB0aGUgcGx1Z2luIGJ5IENsaW50IEhlbGZlcnMsIHdpdGggcGVybWlzc2lvbi5cbi8vIGh0dHBzOi8vd2ViLmFyY2hpdmUub3JnL3dlYi8yMDEwMDMyNDAxNDc0Ny9odHRwOi8vYmxpbmRzaWduYWxzLmNvbS9pbmRleC5waHAvMjAwOS8wNy9qcXVlcnktZGVsYXkvXG5qUXVlcnkuZm4uZGVsYXkgPSBmdW5jdGlvbiggdGltZSwgdHlwZSApIHtcblx0dGltZSA9IGpRdWVyeS5meCA/IGpRdWVyeS5meC5zcGVlZHNbIHRpbWUgXSB8fCB0aW1lIDogdGltZTtcblx0dHlwZSA9IHR5cGUgfHwgXCJmeFwiO1xuXG5cdHJldHVybiB0aGlzLnF1ZXVlKCB0eXBlLCBmdW5jdGlvbiggbmV4dCwgaG9va3MgKSB7XG5cdFx0dmFyIHRpbWVvdXQgPSB3aW5kb3cuc2V0VGltZW91dCggbmV4dCwgdGltZSApO1xuXHRcdGhvb2tzLnN0b3AgPSBmdW5jdGlvbigpIHtcblx0XHRcdHdpbmRvdy5jbGVhclRpbWVvdXQoIHRpbWVvdXQgKTtcblx0XHR9O1xuXHR9ICk7XG59O1xuXG5cbiggZnVuY3Rpb24oKSB7XG5cdHZhciBpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiaW5wdXRcIiApLFxuXHRcdHNlbGVjdCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwic2VsZWN0XCIgKSxcblx0XHRvcHQgPSBzZWxlY3QuYXBwZW5kQ2hpbGQoIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwib3B0aW9uXCIgKSApO1xuXG5cdGlucHV0LnR5cGUgPSBcImNoZWNrYm94XCI7XG5cblx0Ly8gU3VwcG9ydDogQW5kcm9pZCA8PTQuMyBvbmx5XG5cdC8vIERlZmF1bHQgdmFsdWUgZm9yIGEgY2hlY2tib3ggc2hvdWxkIGJlIFwib25cIlxuXHRzdXBwb3J0LmNoZWNrT24gPSBpbnB1dC52YWx1ZSAhPT0gXCJcIjtcblxuXHQvLyBTdXBwb3J0OiBJRSA8PTExIG9ubHlcblx0Ly8gTXVzdCBhY2Nlc3Mgc2VsZWN0ZWRJbmRleCB0byBtYWtlIGRlZmF1bHQgb3B0aW9ucyBzZWxlY3Rcblx0c3VwcG9ydC5vcHRTZWxlY3RlZCA9IG9wdC5zZWxlY3RlZDtcblxuXHQvLyBTdXBwb3J0OiBJRSA8PTExIG9ubHlcblx0Ly8gQW4gaW5wdXQgbG9zZXMgaXRzIHZhbHVlIGFmdGVyIGJlY29taW5nIGEgcmFkaW9cblx0aW5wdXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImlucHV0XCIgKTtcblx0aW5wdXQudmFsdWUgPSBcInRcIjtcblx0aW5wdXQudHlwZSA9IFwicmFkaW9cIjtcblx0c3VwcG9ydC5yYWRpb1ZhbHVlID0gaW5wdXQudmFsdWUgPT09IFwidFwiO1xufSApKCk7XG5cblxudmFyIGJvb2xIb29rLFxuXHRhdHRySGFuZGxlID0galF1ZXJ5LmV4cHIuYXR0ckhhbmRsZTtcblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHRhdHRyOiBmdW5jdGlvbiggbmFtZSwgdmFsdWUgKSB7XG5cdFx0cmV0dXJuIGFjY2VzcyggdGhpcywgalF1ZXJ5LmF0dHIsIG5hbWUsIHZhbHVlLCBhcmd1bWVudHMubGVuZ3RoID4gMSApO1xuXHR9LFxuXG5cdHJlbW92ZUF0dHI6IGZ1bmN0aW9uKCBuYW1lICkge1xuXHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0alF1ZXJ5LnJlbW92ZUF0dHIoIHRoaXMsIG5hbWUgKTtcblx0XHR9ICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmV4dGVuZCgge1xuXHRhdHRyOiBmdW5jdGlvbiggZWxlbSwgbmFtZSwgdmFsdWUgKSB7XG5cdFx0dmFyIHJldCwgaG9va3MsXG5cdFx0XHRuVHlwZSA9IGVsZW0ubm9kZVR5cGU7XG5cblx0XHQvLyBEb24ndCBnZXQvc2V0IGF0dHJpYnV0ZXMgb24gdGV4dCwgY29tbWVudCBhbmQgYXR0cmlidXRlIG5vZGVzXG5cdFx0aWYgKCBuVHlwZSA9PT0gMyB8fCBuVHlwZSA9PT0gOCB8fCBuVHlwZSA9PT0gMiApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBGYWxsYmFjayB0byBwcm9wIHdoZW4gYXR0cmlidXRlcyBhcmUgbm90IHN1cHBvcnRlZFxuXHRcdGlmICggdHlwZW9mIGVsZW0uZ2V0QXR0cmlidXRlID09PSBcInVuZGVmaW5lZFwiICkge1xuXHRcdFx0cmV0dXJuIGpRdWVyeS5wcm9wKCBlbGVtLCBuYW1lLCB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdC8vIEF0dHJpYnV0ZSBob29rcyBhcmUgZGV0ZXJtaW5lZCBieSB0aGUgbG93ZXJjYXNlIHZlcnNpb25cblx0XHQvLyBHcmFiIG5lY2Vzc2FyeSBob29rIGlmIG9uZSBpcyBkZWZpbmVkXG5cdFx0aWYgKCBuVHlwZSAhPT0gMSB8fCAhalF1ZXJ5LmlzWE1MRG9jKCBlbGVtICkgKSB7XG5cdFx0XHRob29rcyA9IGpRdWVyeS5hdHRySG9va3NbIG5hbWUudG9Mb3dlckNhc2UoKSBdIHx8XG5cdFx0XHRcdCggalF1ZXJ5LmV4cHIubWF0Y2guYm9vbC50ZXN0KCBuYW1lICkgPyBib29sSG9vayA6IHVuZGVmaW5lZCApO1xuXHRcdH1cblxuXHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGlmICggdmFsdWUgPT09IG51bGwgKSB7XG5cdFx0XHRcdGpRdWVyeS5yZW1vdmVBdHRyKCBlbGVtLCBuYW1lICk7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBob29rcyAmJiBcInNldFwiIGluIGhvb2tzICYmXG5cdFx0XHRcdCggcmV0ID0gaG9va3Muc2V0KCBlbGVtLCB2YWx1ZSwgbmFtZSApICkgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0cmV0dXJuIHJldDtcblx0XHRcdH1cblxuXHRcdFx0ZWxlbS5zZXRBdHRyaWJ1dGUoIG5hbWUsIHZhbHVlICsgXCJcIiApO1xuXHRcdFx0cmV0dXJuIHZhbHVlO1xuXHRcdH1cblxuXHRcdGlmICggaG9va3MgJiYgXCJnZXRcIiBpbiBob29rcyAmJiAoIHJldCA9IGhvb2tzLmdldCggZWxlbSwgbmFtZSApICkgIT09IG51bGwgKSB7XG5cdFx0XHRyZXR1cm4gcmV0O1xuXHRcdH1cblxuXHRcdHJldCA9IGpRdWVyeS5maW5kLmF0dHIoIGVsZW0sIG5hbWUgKTtcblxuXHRcdC8vIE5vbi1leGlzdGVudCBhdHRyaWJ1dGVzIHJldHVybiBudWxsLCB3ZSBub3JtYWxpemUgdG8gdW5kZWZpbmVkXG5cdFx0cmV0dXJuIHJldCA9PSBudWxsID8gdW5kZWZpbmVkIDogcmV0O1xuXHR9LFxuXG5cdGF0dHJIb29rczoge1xuXHRcdHR5cGU6IHtcblx0XHRcdHNldDogZnVuY3Rpb24oIGVsZW0sIHZhbHVlICkge1xuXHRcdFx0XHRpZiAoICFzdXBwb3J0LnJhZGlvVmFsdWUgJiYgdmFsdWUgPT09IFwicmFkaW9cIiAmJlxuXHRcdFx0XHRcdG5vZGVOYW1lKCBlbGVtLCBcImlucHV0XCIgKSApIHtcblx0XHRcdFx0XHR2YXIgdmFsID0gZWxlbS52YWx1ZTtcblx0XHRcdFx0XHRlbGVtLnNldEF0dHJpYnV0ZSggXCJ0eXBlXCIsIHZhbHVlICk7XG5cdFx0XHRcdFx0aWYgKCB2YWwgKSB7XG5cdFx0XHRcdFx0XHRlbGVtLnZhbHVlID0gdmFsO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRyZXR1cm4gdmFsdWU7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0cmVtb3ZlQXR0cjogZnVuY3Rpb24oIGVsZW0sIHZhbHVlICkge1xuXHRcdHZhciBuYW1lLFxuXHRcdFx0aSA9IDAsXG5cblx0XHRcdC8vIEF0dHJpYnV0ZSBuYW1lcyBjYW4gY29udGFpbiBub24tSFRNTCB3aGl0ZXNwYWNlIGNoYXJhY3RlcnNcblx0XHRcdC8vIGh0dHBzOi8vaHRtbC5zcGVjLndoYXR3Zy5vcmcvbXVsdGlwYWdlL3N5bnRheC5odG1sI2F0dHJpYnV0ZXMtMlxuXHRcdFx0YXR0ck5hbWVzID0gdmFsdWUgJiYgdmFsdWUubWF0Y2goIHJub3RodG1sd2hpdGUgKTtcblxuXHRcdGlmICggYXR0ck5hbWVzICYmIGVsZW0ubm9kZVR5cGUgPT09IDEgKSB7XG5cdFx0XHR3aGlsZSAoICggbmFtZSA9IGF0dHJOYW1lc1sgaSsrIF0gKSApIHtcblx0XHRcdFx0ZWxlbS5yZW1vdmVBdHRyaWJ1dGUoIG5hbWUgKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn0gKTtcblxuLy8gSG9va3MgZm9yIGJvb2xlYW4gYXR0cmlidXRlc1xuYm9vbEhvb2sgPSB7XG5cdHNldDogZnVuY3Rpb24oIGVsZW0sIHZhbHVlLCBuYW1lICkge1xuXHRcdGlmICggdmFsdWUgPT09IGZhbHNlICkge1xuXG5cdFx0XHQvLyBSZW1vdmUgYm9vbGVhbiBhdHRyaWJ1dGVzIHdoZW4gc2V0IHRvIGZhbHNlXG5cdFx0XHRqUXVlcnkucmVtb3ZlQXR0ciggZWxlbSwgbmFtZSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRlbGVtLnNldEF0dHJpYnV0ZSggbmFtZSwgbmFtZSApO1xuXHRcdH1cblx0XHRyZXR1cm4gbmFtZTtcblx0fVxufTtcblxualF1ZXJ5LmVhY2goIGpRdWVyeS5leHByLm1hdGNoLmJvb2wuc291cmNlLm1hdGNoKCAvXFx3Ky9nICksIGZ1bmN0aW9uKCBpLCBuYW1lICkge1xuXHR2YXIgZ2V0dGVyID0gYXR0ckhhbmRsZVsgbmFtZSBdIHx8IGpRdWVyeS5maW5kLmF0dHI7XG5cblx0YXR0ckhhbmRsZVsgbmFtZSBdID0gZnVuY3Rpb24oIGVsZW0sIG5hbWUsIGlzWE1MICkge1xuXHRcdHZhciByZXQsIGhhbmRsZSxcblx0XHRcdGxvd2VyY2FzZU5hbWUgPSBuYW1lLnRvTG93ZXJDYXNlKCk7XG5cblx0XHRpZiAoICFpc1hNTCApIHtcblxuXHRcdFx0Ly8gQXZvaWQgYW4gaW5maW5pdGUgbG9vcCBieSB0ZW1wb3JhcmlseSByZW1vdmluZyB0aGlzIGZ1bmN0aW9uIGZyb20gdGhlIGdldHRlclxuXHRcdFx0aGFuZGxlID0gYXR0ckhhbmRsZVsgbG93ZXJjYXNlTmFtZSBdO1xuXHRcdFx0YXR0ckhhbmRsZVsgbG93ZXJjYXNlTmFtZSBdID0gcmV0O1xuXHRcdFx0cmV0ID0gZ2V0dGVyKCBlbGVtLCBuYW1lLCBpc1hNTCApICE9IG51bGwgP1xuXHRcdFx0XHRsb3dlcmNhc2VOYW1lIDpcblx0XHRcdFx0bnVsbDtcblx0XHRcdGF0dHJIYW5kbGVbIGxvd2VyY2FzZU5hbWUgXSA9IGhhbmRsZTtcblx0XHR9XG5cdFx0cmV0dXJuIHJldDtcblx0fTtcbn0gKTtcblxuXG5cblxudmFyIHJmb2N1c2FibGUgPSAvXig/OmlucHV0fHNlbGVjdHx0ZXh0YXJlYXxidXR0b24pJC9pLFxuXHRyY2xpY2thYmxlID0gL14oPzphfGFyZWEpJC9pO1xuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdHByb3A6IGZ1bmN0aW9uKCBuYW1lLCB2YWx1ZSApIHtcblx0XHRyZXR1cm4gYWNjZXNzKCB0aGlzLCBqUXVlcnkucHJvcCwgbmFtZSwgdmFsdWUsIGFyZ3VtZW50cy5sZW5ndGggPiAxICk7XG5cdH0sXG5cblx0cmVtb3ZlUHJvcDogZnVuY3Rpb24oIG5hbWUgKSB7XG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRkZWxldGUgdGhpc1sgalF1ZXJ5LnByb3BGaXhbIG5hbWUgXSB8fCBuYW1lIF07XG5cdFx0fSApO1xuXHR9XG59ICk7XG5cbmpRdWVyeS5leHRlbmQoIHtcblx0cHJvcDogZnVuY3Rpb24oIGVsZW0sIG5hbWUsIHZhbHVlICkge1xuXHRcdHZhciByZXQsIGhvb2tzLFxuXHRcdFx0blR5cGUgPSBlbGVtLm5vZGVUeXBlO1xuXG5cdFx0Ly8gRG9uJ3QgZ2V0L3NldCBwcm9wZXJ0aWVzIG9uIHRleHQsIGNvbW1lbnQgYW5kIGF0dHJpYnV0ZSBub2Rlc1xuXHRcdGlmICggblR5cGUgPT09IDMgfHwgblR5cGUgPT09IDggfHwgblR5cGUgPT09IDIgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBuVHlwZSAhPT0gMSB8fCAhalF1ZXJ5LmlzWE1MRG9jKCBlbGVtICkgKSB7XG5cblx0XHRcdC8vIEZpeCBuYW1lIGFuZCBhdHRhY2ggaG9va3Ncblx0XHRcdG5hbWUgPSBqUXVlcnkucHJvcEZpeFsgbmFtZSBdIHx8IG5hbWU7XG5cdFx0XHRob29rcyA9IGpRdWVyeS5wcm9wSG9va3NbIG5hbWUgXTtcblx0XHR9XG5cblx0XHRpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRpZiAoIGhvb2tzICYmIFwic2V0XCIgaW4gaG9va3MgJiZcblx0XHRcdFx0KCByZXQgPSBob29rcy5zZXQoIGVsZW0sIHZhbHVlLCBuYW1lICkgKSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRyZXR1cm4gcmV0O1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gKCBlbGVtWyBuYW1lIF0gPSB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdGlmICggaG9va3MgJiYgXCJnZXRcIiBpbiBob29rcyAmJiAoIHJldCA9IGhvb2tzLmdldCggZWxlbSwgbmFtZSApICkgIT09IG51bGwgKSB7XG5cdFx0XHRyZXR1cm4gcmV0O1xuXHRcdH1cblxuXHRcdHJldHVybiBlbGVtWyBuYW1lIF07XG5cdH0sXG5cblx0cHJvcEhvb2tzOiB7XG5cdFx0dGFiSW5kZXg6IHtcblx0XHRcdGdldDogZnVuY3Rpb24oIGVsZW0gKSB7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgPD05IC0gMTEgb25seVxuXHRcdFx0XHQvLyBlbGVtLnRhYkluZGV4IGRvZXNuJ3QgYWx3YXlzIHJldHVybiB0aGVcblx0XHRcdFx0Ly8gY29ycmVjdCB2YWx1ZSB3aGVuIGl0IGhhc24ndCBiZWVuIGV4cGxpY2l0bHkgc2V0XG5cdFx0XHRcdC8vIGh0dHBzOi8vd2ViLmFyY2hpdmUub3JnL3dlYi8yMDE0MTExNjIzMzM0Ny9odHRwOi8vZmx1aWRwcm9qZWN0Lm9yZy9ibG9nLzIwMDgvMDEvMDkvZ2V0dGluZy1zZXR0aW5nLWFuZC1yZW1vdmluZy10YWJpbmRleC12YWx1ZXMtd2l0aC1qYXZhc2NyaXB0L1xuXHRcdFx0XHQvLyBVc2UgcHJvcGVyIGF0dHJpYnV0ZSByZXRyaWV2YWwoIzEyMDcyKVxuXHRcdFx0XHR2YXIgdGFiaW5kZXggPSBqUXVlcnkuZmluZC5hdHRyKCBlbGVtLCBcInRhYmluZGV4XCIgKTtcblxuXHRcdFx0XHRpZiAoIHRhYmluZGV4ICkge1xuXHRcdFx0XHRcdHJldHVybiBwYXJzZUludCggdGFiaW5kZXgsIDEwICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoXG5cdFx0XHRcdFx0cmZvY3VzYWJsZS50ZXN0KCBlbGVtLm5vZGVOYW1lICkgfHxcblx0XHRcdFx0XHRyY2xpY2thYmxlLnRlc3QoIGVsZW0ubm9kZU5hbWUgKSAmJlxuXHRcdFx0XHRcdGVsZW0uaHJlZlxuXHRcdFx0XHQpIHtcblx0XHRcdFx0XHRyZXR1cm4gMDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiAtMTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0cHJvcEZpeDoge1xuXHRcdFwiZm9yXCI6IFwiaHRtbEZvclwiLFxuXHRcdFwiY2xhc3NcIjogXCJjbGFzc05hbWVcIlxuXHR9XG59ICk7XG5cbi8vIFN1cHBvcnQ6IElFIDw9MTEgb25seVxuLy8gQWNjZXNzaW5nIHRoZSBzZWxlY3RlZEluZGV4IHByb3BlcnR5XG4vLyBmb3JjZXMgdGhlIGJyb3dzZXIgdG8gcmVzcGVjdCBzZXR0aW5nIHNlbGVjdGVkXG4vLyBvbiB0aGUgb3B0aW9uXG4vLyBUaGUgZ2V0dGVyIGVuc3VyZXMgYSBkZWZhdWx0IG9wdGlvbiBpcyBzZWxlY3RlZFxuLy8gd2hlbiBpbiBhbiBvcHRncm91cFxuLy8gZXNsaW50IHJ1bGUgXCJuby11bnVzZWQtZXhwcmVzc2lvbnNcIiBpcyBkaXNhYmxlZCBmb3IgdGhpcyBjb2RlXG4vLyBzaW5jZSBpdCBjb25zaWRlcnMgc3VjaCBhY2Nlc3Npb25zIG5vb3BcbmlmICggIXN1cHBvcnQub3B0U2VsZWN0ZWQgKSB7XG5cdGpRdWVyeS5wcm9wSG9va3Muc2VsZWN0ZWQgPSB7XG5cdFx0Z2V0OiBmdW5jdGlvbiggZWxlbSApIHtcblxuXHRcdFx0LyogZXNsaW50IG5vLXVudXNlZC1leHByZXNzaW9uczogXCJvZmZcIiAqL1xuXG5cdFx0XHR2YXIgcGFyZW50ID0gZWxlbS5wYXJlbnROb2RlO1xuXHRcdFx0aWYgKCBwYXJlbnQgJiYgcGFyZW50LnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdHBhcmVudC5wYXJlbnROb2RlLnNlbGVjdGVkSW5kZXg7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9LFxuXHRcdHNldDogZnVuY3Rpb24oIGVsZW0gKSB7XG5cblx0XHRcdC8qIGVzbGludCBuby11bnVzZWQtZXhwcmVzc2lvbnM6IFwib2ZmXCIgKi9cblxuXHRcdFx0dmFyIHBhcmVudCA9IGVsZW0ucGFyZW50Tm9kZTtcblx0XHRcdGlmICggcGFyZW50ICkge1xuXHRcdFx0XHRwYXJlbnQuc2VsZWN0ZWRJbmRleDtcblxuXHRcdFx0XHRpZiAoIHBhcmVudC5wYXJlbnROb2RlICkge1xuXHRcdFx0XHRcdHBhcmVudC5wYXJlbnROb2RlLnNlbGVjdGVkSW5kZXg7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH07XG59XG5cbmpRdWVyeS5lYWNoKCBbXG5cdFwidGFiSW5kZXhcIixcblx0XCJyZWFkT25seVwiLFxuXHRcIm1heExlbmd0aFwiLFxuXHRcImNlbGxTcGFjaW5nXCIsXG5cdFwiY2VsbFBhZGRpbmdcIixcblx0XCJyb3dTcGFuXCIsXG5cdFwiY29sU3BhblwiLFxuXHRcInVzZU1hcFwiLFxuXHRcImZyYW1lQm9yZGVyXCIsXG5cdFwiY29udGVudEVkaXRhYmxlXCJcbl0sIGZ1bmN0aW9uKCkge1xuXHRqUXVlcnkucHJvcEZpeFsgdGhpcy50b0xvd2VyQ2FzZSgpIF0gPSB0aGlzO1xufSApO1xuXG5cblxuXG5cdC8vIFN0cmlwIGFuZCBjb2xsYXBzZSB3aGl0ZXNwYWNlIGFjY29yZGluZyB0byBIVE1MIHNwZWNcblx0Ly8gaHR0cHM6Ly9pbmZyYS5zcGVjLndoYXR3Zy5vcmcvI3N0cmlwLWFuZC1jb2xsYXBzZS1hc2NpaS13aGl0ZXNwYWNlXG5cdGZ1bmN0aW9uIHN0cmlwQW5kQ29sbGFwc2UoIHZhbHVlICkge1xuXHRcdHZhciB0b2tlbnMgPSB2YWx1ZS5tYXRjaCggcm5vdGh0bWx3aGl0ZSApIHx8IFtdO1xuXHRcdHJldHVybiB0b2tlbnMuam9pbiggXCIgXCIgKTtcblx0fVxuXG5cbmZ1bmN0aW9uIGdldENsYXNzKCBlbGVtICkge1xuXHRyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGUgJiYgZWxlbS5nZXRBdHRyaWJ1dGUoIFwiY2xhc3NcIiApIHx8IFwiXCI7XG59XG5cbmZ1bmN0aW9uIGNsYXNzZXNUb0FycmF5KCB2YWx1ZSApIHtcblx0aWYgKCBBcnJheS5pc0FycmF5KCB2YWx1ZSApICkge1xuXHRcdHJldHVybiB2YWx1ZTtcblx0fVxuXHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRyZXR1cm4gdmFsdWUubWF0Y2goIHJub3RodG1sd2hpdGUgKSB8fCBbXTtcblx0fVxuXHRyZXR1cm4gW107XG59XG5cbmpRdWVyeS5mbi5leHRlbmQoIHtcblx0YWRkQ2xhc3M6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR2YXIgY2xhc3NlcywgZWxlbSwgY3VyLCBjdXJWYWx1ZSwgY2xhenosIGosIGZpbmFsVmFsdWUsXG5cdFx0XHRpID0gMDtcblxuXHRcdGlmICggaXNGdW5jdGlvbiggdmFsdWUgKSApIHtcblx0XHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCBqICkge1xuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS5hZGRDbGFzcyggdmFsdWUuY2FsbCggdGhpcywgaiwgZ2V0Q2xhc3MoIHRoaXMgKSApICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0Y2xhc3NlcyA9IGNsYXNzZXNUb0FycmF5KCB2YWx1ZSApO1xuXG5cdFx0aWYgKCBjbGFzc2VzLmxlbmd0aCApIHtcblx0XHRcdHdoaWxlICggKCBlbGVtID0gdGhpc1sgaSsrIF0gKSApIHtcblx0XHRcdFx0Y3VyVmFsdWUgPSBnZXRDbGFzcyggZWxlbSApO1xuXHRcdFx0XHRjdXIgPSBlbGVtLm5vZGVUeXBlID09PSAxICYmICggXCIgXCIgKyBzdHJpcEFuZENvbGxhcHNlKCBjdXJWYWx1ZSApICsgXCIgXCIgKTtcblxuXHRcdFx0XHRpZiAoIGN1ciApIHtcblx0XHRcdFx0XHRqID0gMDtcblx0XHRcdFx0XHR3aGlsZSAoICggY2xhenogPSBjbGFzc2VzWyBqKysgXSApICkge1xuXHRcdFx0XHRcdFx0aWYgKCBjdXIuaW5kZXhPZiggXCIgXCIgKyBjbGF6eiArIFwiIFwiICkgPCAwICkge1xuXHRcdFx0XHRcdFx0XHRjdXIgKz0gY2xhenogKyBcIiBcIjtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBPbmx5IGFzc2lnbiBpZiBkaWZmZXJlbnQgdG8gYXZvaWQgdW5uZWVkZWQgcmVuZGVyaW5nLlxuXHRcdFx0XHRcdGZpbmFsVmFsdWUgPSBzdHJpcEFuZENvbGxhcHNlKCBjdXIgKTtcblx0XHRcdFx0XHRpZiAoIGN1clZhbHVlICE9PSBmaW5hbFZhbHVlICkge1xuXHRcdFx0XHRcdFx0ZWxlbS5zZXRBdHRyaWJ1dGUoIFwiY2xhc3NcIiwgZmluYWxWYWx1ZSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdHJlbW92ZUNsYXNzOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dmFyIGNsYXNzZXMsIGVsZW0sIGN1ciwgY3VyVmFsdWUsIGNsYXp6LCBqLCBmaW5hbFZhbHVlLFxuXHRcdFx0aSA9IDA7XG5cblx0XHRpZiAoIGlzRnVuY3Rpb24oIHZhbHVlICkgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbiggaiApIHtcblx0XHRcdFx0alF1ZXJ5KCB0aGlzICkucmVtb3ZlQ2xhc3MoIHZhbHVlLmNhbGwoIHRoaXMsIGosIGdldENsYXNzKCB0aGlzICkgKSApO1xuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdGlmICggIWFyZ3VtZW50cy5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5hdHRyKCBcImNsYXNzXCIsIFwiXCIgKTtcblx0XHR9XG5cblx0XHRjbGFzc2VzID0gY2xhc3Nlc1RvQXJyYXkoIHZhbHVlICk7XG5cblx0XHRpZiAoIGNsYXNzZXMubGVuZ3RoICkge1xuXHRcdFx0d2hpbGUgKCAoIGVsZW0gPSB0aGlzWyBpKysgXSApICkge1xuXHRcdFx0XHRjdXJWYWx1ZSA9IGdldENsYXNzKCBlbGVtICk7XG5cblx0XHRcdFx0Ly8gVGhpcyBleHByZXNzaW9uIGlzIGhlcmUgZm9yIGJldHRlciBjb21wcmVzc2liaWxpdHkgKHNlZSBhZGRDbGFzcylcblx0XHRcdFx0Y3VyID0gZWxlbS5ub2RlVHlwZSA9PT0gMSAmJiAoIFwiIFwiICsgc3RyaXBBbmRDb2xsYXBzZSggY3VyVmFsdWUgKSArIFwiIFwiICk7XG5cblx0XHRcdFx0aWYgKCBjdXIgKSB7XG5cdFx0XHRcdFx0aiA9IDA7XG5cdFx0XHRcdFx0d2hpbGUgKCAoIGNsYXp6ID0gY2xhc3Nlc1sgaisrIF0gKSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gUmVtb3ZlICphbGwqIGluc3RhbmNlc1xuXHRcdFx0XHRcdFx0d2hpbGUgKCBjdXIuaW5kZXhPZiggXCIgXCIgKyBjbGF6eiArIFwiIFwiICkgPiAtMSApIHtcblx0XHRcdFx0XHRcdFx0Y3VyID0gY3VyLnJlcGxhY2UoIFwiIFwiICsgY2xhenogKyBcIiBcIiwgXCIgXCIgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBPbmx5IGFzc2lnbiBpZiBkaWZmZXJlbnQgdG8gYXZvaWQgdW5uZWVkZWQgcmVuZGVyaW5nLlxuXHRcdFx0XHRcdGZpbmFsVmFsdWUgPSBzdHJpcEFuZENvbGxhcHNlKCBjdXIgKTtcblx0XHRcdFx0XHRpZiAoIGN1clZhbHVlICE9PSBmaW5hbFZhbHVlICkge1xuXHRcdFx0XHRcdFx0ZWxlbS5zZXRBdHRyaWJ1dGUoIFwiY2xhc3NcIiwgZmluYWxWYWx1ZSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdHRvZ2dsZUNsYXNzOiBmdW5jdGlvbiggdmFsdWUsIHN0YXRlVmFsICkge1xuXHRcdHZhciB0eXBlID0gdHlwZW9mIHZhbHVlLFxuXHRcdFx0aXNWYWxpZFZhbHVlID0gdHlwZSA9PT0gXCJzdHJpbmdcIiB8fCBBcnJheS5pc0FycmF5KCB2YWx1ZSApO1xuXG5cdFx0aWYgKCB0eXBlb2Ygc3RhdGVWYWwgPT09IFwiYm9vbGVhblwiICYmIGlzVmFsaWRWYWx1ZSApIHtcblx0XHRcdHJldHVybiBzdGF0ZVZhbCA/IHRoaXMuYWRkQ2xhc3MoIHZhbHVlICkgOiB0aGlzLnJlbW92ZUNsYXNzKCB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdGlmICggaXNGdW5jdGlvbiggdmFsdWUgKSApIHtcblx0XHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS50b2dnbGVDbGFzcyhcblx0XHRcdFx0XHR2YWx1ZS5jYWxsKCB0aGlzLCBpLCBnZXRDbGFzcyggdGhpcyApLCBzdGF0ZVZhbCApLFxuXHRcdFx0XHRcdHN0YXRlVmFsXG5cdFx0XHRcdCk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgY2xhc3NOYW1lLCBpLCBzZWxmLCBjbGFzc05hbWVzO1xuXG5cdFx0XHRpZiAoIGlzVmFsaWRWYWx1ZSApIHtcblxuXHRcdFx0XHQvLyBUb2dnbGUgaW5kaXZpZHVhbCBjbGFzcyBuYW1lc1xuXHRcdFx0XHRpID0gMDtcblx0XHRcdFx0c2VsZiA9IGpRdWVyeSggdGhpcyApO1xuXHRcdFx0XHRjbGFzc05hbWVzID0gY2xhc3Nlc1RvQXJyYXkoIHZhbHVlICk7XG5cblx0XHRcdFx0d2hpbGUgKCAoIGNsYXNzTmFtZSA9IGNsYXNzTmFtZXNbIGkrKyBdICkgKSB7XG5cblx0XHRcdFx0XHQvLyBDaGVjayBlYWNoIGNsYXNzTmFtZSBnaXZlbiwgc3BhY2Ugc2VwYXJhdGVkIGxpc3Rcblx0XHRcdFx0XHRpZiAoIHNlbGYuaGFzQ2xhc3MoIGNsYXNzTmFtZSApICkge1xuXHRcdFx0XHRcdFx0c2VsZi5yZW1vdmVDbGFzcyggY2xhc3NOYW1lICk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHNlbGYuYWRkQ2xhc3MoIGNsYXNzTmFtZSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHQvLyBUb2dnbGUgd2hvbGUgY2xhc3MgbmFtZVxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgPT09IHVuZGVmaW5lZCB8fCB0eXBlID09PSBcImJvb2xlYW5cIiApIHtcblx0XHRcdFx0Y2xhc3NOYW1lID0gZ2V0Q2xhc3MoIHRoaXMgKTtcblx0XHRcdFx0aWYgKCBjbGFzc05hbWUgKSB7XG5cblx0XHRcdFx0XHQvLyBTdG9yZSBjbGFzc05hbWUgaWYgc2V0XG5cdFx0XHRcdFx0ZGF0YVByaXYuc2V0KCB0aGlzLCBcIl9fY2xhc3NOYW1lX19cIiwgY2xhc3NOYW1lICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBJZiB0aGUgZWxlbWVudCBoYXMgYSBjbGFzcyBuYW1lIG9yIGlmIHdlJ3JlIHBhc3NlZCBgZmFsc2VgLFxuXHRcdFx0XHQvLyB0aGVuIHJlbW92ZSB0aGUgd2hvbGUgY2xhc3NuYW1lIChpZiB0aGVyZSB3YXMgb25lLCB0aGUgYWJvdmUgc2F2ZWQgaXQpLlxuXHRcdFx0XHQvLyBPdGhlcndpc2UgYnJpbmcgYmFjayB3aGF0ZXZlciB3YXMgcHJldmlvdXNseSBzYXZlZCAoaWYgYW55dGhpbmcpLFxuXHRcdFx0XHQvLyBmYWxsaW5nIGJhY2sgdG8gdGhlIGVtcHR5IHN0cmluZyBpZiBub3RoaW5nIHdhcyBzdG9yZWQuXG5cdFx0XHRcdGlmICggdGhpcy5zZXRBdHRyaWJ1dGUgKSB7XG5cdFx0XHRcdFx0dGhpcy5zZXRBdHRyaWJ1dGUoIFwiY2xhc3NcIixcblx0XHRcdFx0XHRcdGNsYXNzTmFtZSB8fCB2YWx1ZSA9PT0gZmFsc2UgP1xuXHRcdFx0XHRcdFx0XCJcIiA6XG5cdFx0XHRcdFx0XHRkYXRhUHJpdi5nZXQoIHRoaXMsIFwiX19jbGFzc05hbWVfX1wiICkgfHwgXCJcIlxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0aGFzQ2xhc3M6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHR2YXIgY2xhc3NOYW1lLCBlbGVtLFxuXHRcdFx0aSA9IDA7XG5cblx0XHRjbGFzc05hbWUgPSBcIiBcIiArIHNlbGVjdG9yICsgXCIgXCI7XG5cdFx0d2hpbGUgKCAoIGVsZW0gPSB0aGlzWyBpKysgXSApICkge1xuXHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSAxICYmXG5cdFx0XHRcdCggXCIgXCIgKyBzdHJpcEFuZENvbGxhcHNlKCBnZXRDbGFzcyggZWxlbSApICkgKyBcIiBcIiApLmluZGV4T2YoIGNsYXNzTmFtZSApID4gLTEgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG59ICk7XG5cblxuXG5cbnZhciBycmV0dXJuID0gL1xcci9nO1xuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdHZhbDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHZhciBob29rcywgcmV0LCB2YWx1ZUlzRnVuY3Rpb24sXG5cdFx0XHRlbGVtID0gdGhpc1sgMCBdO1xuXG5cdFx0aWYgKCAhYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdGlmICggZWxlbSApIHtcblx0XHRcdFx0aG9va3MgPSBqUXVlcnkudmFsSG9va3NbIGVsZW0udHlwZSBdIHx8XG5cdFx0XHRcdFx0alF1ZXJ5LnZhbEhvb2tzWyBlbGVtLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgXTtcblxuXHRcdFx0XHRpZiAoIGhvb2tzICYmXG5cdFx0XHRcdFx0XCJnZXRcIiBpbiBob29rcyAmJlxuXHRcdFx0XHRcdCggcmV0ID0gaG9va3MuZ2V0KCBlbGVtLCBcInZhbHVlXCIgKSApICE9PSB1bmRlZmluZWRcblx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0cmV0dXJuIHJldDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldCA9IGVsZW0udmFsdWU7XG5cblx0XHRcdFx0Ly8gSGFuZGxlIG1vc3QgY29tbW9uIHN0cmluZyBjYXNlc1xuXHRcdFx0XHRpZiAoIHR5cGVvZiByZXQgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHJldC5yZXBsYWNlKCBycmV0dXJuLCBcIlwiICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBIYW5kbGUgY2FzZXMgd2hlcmUgdmFsdWUgaXMgbnVsbC91bmRlZiBvciBudW1iZXJcblx0XHRcdFx0cmV0dXJuIHJldCA9PSBudWxsID8gXCJcIiA6IHJldDtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhbHVlSXNGdW5jdGlvbiA9IGlzRnVuY3Rpb24oIHZhbHVlICk7XG5cblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbiggaSApIHtcblx0XHRcdHZhciB2YWw7XG5cblx0XHRcdGlmICggdGhpcy5ub2RlVHlwZSAhPT0gMSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHZhbHVlSXNGdW5jdGlvbiApIHtcblx0XHRcdFx0dmFsID0gdmFsdWUuY2FsbCggdGhpcywgaSwgalF1ZXJ5KCB0aGlzICkudmFsKCkgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHZhbCA9IHZhbHVlO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBUcmVhdCBudWxsL3VuZGVmaW5lZCBhcyBcIlwiOyBjb252ZXJ0IG51bWJlcnMgdG8gc3RyaW5nXG5cdFx0XHRpZiAoIHZhbCA9PSBudWxsICkge1xuXHRcdFx0XHR2YWwgPSBcIlwiO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCB0eXBlb2YgdmFsID09PSBcIm51bWJlclwiICkge1xuXHRcdFx0XHR2YWwgKz0gXCJcIjtcblxuXHRcdFx0fSBlbHNlIGlmICggQXJyYXkuaXNBcnJheSggdmFsICkgKSB7XG5cdFx0XHRcdHZhbCA9IGpRdWVyeS5tYXAoIHZhbCwgZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdFx0XHRcdHJldHVybiB2YWx1ZSA9PSBudWxsID8gXCJcIiA6IHZhbHVlICsgXCJcIjtcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXG5cdFx0XHRob29rcyA9IGpRdWVyeS52YWxIb29rc1sgdGhpcy50eXBlIF0gfHwgalF1ZXJ5LnZhbEhvb2tzWyB0aGlzLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgXTtcblxuXHRcdFx0Ly8gSWYgc2V0IHJldHVybnMgdW5kZWZpbmVkLCBmYWxsIGJhY2sgdG8gbm9ybWFsIHNldHRpbmdcblx0XHRcdGlmICggIWhvb2tzIHx8ICEoIFwic2V0XCIgaW4gaG9va3MgKSB8fCBob29rcy5zZXQoIHRoaXMsIHZhbCwgXCJ2YWx1ZVwiICkgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0dGhpcy52YWx1ZSA9IHZhbDtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmV4dGVuZCgge1xuXHR2YWxIb29rczoge1xuXHRcdG9wdGlvbjoge1xuXHRcdFx0Z2V0OiBmdW5jdGlvbiggZWxlbSApIHtcblxuXHRcdFx0XHR2YXIgdmFsID0galF1ZXJ5LmZpbmQuYXR0ciggZWxlbSwgXCJ2YWx1ZVwiICk7XG5cdFx0XHRcdHJldHVybiB2YWwgIT0gbnVsbCA/XG5cdFx0XHRcdFx0dmFsIDpcblxuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw9MTAgLSAxMSBvbmx5XG5cdFx0XHRcdFx0Ly8gb3B0aW9uLnRleHQgdGhyb3dzIGV4Y2VwdGlvbnMgKCMxNDY4NiwgIzE0ODU4KVxuXHRcdFx0XHRcdC8vIFN0cmlwIGFuZCBjb2xsYXBzZSB3aGl0ZXNwYWNlXG5cdFx0XHRcdFx0Ly8gaHR0cHM6Ly9odG1sLnNwZWMud2hhdHdnLm9yZy8jc3RyaXAtYW5kLWNvbGxhcHNlLXdoaXRlc3BhY2Vcblx0XHRcdFx0XHRzdHJpcEFuZENvbGxhcHNlKCBqUXVlcnkudGV4dCggZWxlbSApICk7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHRzZWxlY3Q6IHtcblx0XHRcdGdldDogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRcdHZhciB2YWx1ZSwgb3B0aW9uLCBpLFxuXHRcdFx0XHRcdG9wdGlvbnMgPSBlbGVtLm9wdGlvbnMsXG5cdFx0XHRcdFx0aW5kZXggPSBlbGVtLnNlbGVjdGVkSW5kZXgsXG5cdFx0XHRcdFx0b25lID0gZWxlbS50eXBlID09PSBcInNlbGVjdC1vbmVcIixcblx0XHRcdFx0XHR2YWx1ZXMgPSBvbmUgPyBudWxsIDogW10sXG5cdFx0XHRcdFx0bWF4ID0gb25lID8gaW5kZXggKyAxIDogb3B0aW9ucy5sZW5ndGg7XG5cblx0XHRcdFx0aWYgKCBpbmRleCA8IDAgKSB7XG5cdFx0XHRcdFx0aSA9IG1heDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGkgPSBvbmUgPyBpbmRleCA6IDA7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBMb29wIHRocm91Z2ggYWxsIHRoZSBzZWxlY3RlZCBvcHRpb25zXG5cdFx0XHRcdGZvciAoIDsgaSA8IG1heDsgaSsrICkge1xuXHRcdFx0XHRcdG9wdGlvbiA9IG9wdGlvbnNbIGkgXTtcblxuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw9OSBvbmx5XG5cdFx0XHRcdFx0Ly8gSUU4LTkgZG9lc24ndCB1cGRhdGUgc2VsZWN0ZWQgYWZ0ZXIgZm9ybSByZXNldCAoIzI1NTEpXG5cdFx0XHRcdFx0aWYgKCAoIG9wdGlvbi5zZWxlY3RlZCB8fCBpID09PSBpbmRleCApICYmXG5cblx0XHRcdFx0XHRcdFx0Ly8gRG9uJ3QgcmV0dXJuIG9wdGlvbnMgdGhhdCBhcmUgZGlzYWJsZWQgb3IgaW4gYSBkaXNhYmxlZCBvcHRncm91cFxuXHRcdFx0XHRcdFx0XHQhb3B0aW9uLmRpc2FibGVkICYmXG5cdFx0XHRcdFx0XHRcdCggIW9wdGlvbi5wYXJlbnROb2RlLmRpc2FibGVkIHx8XG5cdFx0XHRcdFx0XHRcdFx0IW5vZGVOYW1lKCBvcHRpb24ucGFyZW50Tm9kZSwgXCJvcHRncm91cFwiICkgKSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gR2V0IHRoZSBzcGVjaWZpYyB2YWx1ZSBmb3IgdGhlIG9wdGlvblxuXHRcdFx0XHRcdFx0dmFsdWUgPSBqUXVlcnkoIG9wdGlvbiApLnZhbCgpO1xuXG5cdFx0XHRcdFx0XHQvLyBXZSBkb24ndCBuZWVkIGFuIGFycmF5IGZvciBvbmUgc2VsZWN0c1xuXHRcdFx0XHRcdFx0aWYgKCBvbmUgKSB7XG5cdFx0XHRcdFx0XHRcdHJldHVybiB2YWx1ZTtcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Ly8gTXVsdGktU2VsZWN0cyByZXR1cm4gYW4gYXJyYXlcblx0XHRcdFx0XHRcdHZhbHVlcy5wdXNoKCB2YWx1ZSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiB2YWx1ZXM7XG5cdFx0XHR9LFxuXG5cdFx0XHRzZXQ6IGZ1bmN0aW9uKCBlbGVtLCB2YWx1ZSApIHtcblx0XHRcdFx0dmFyIG9wdGlvblNldCwgb3B0aW9uLFxuXHRcdFx0XHRcdG9wdGlvbnMgPSBlbGVtLm9wdGlvbnMsXG5cdFx0XHRcdFx0dmFsdWVzID0galF1ZXJ5Lm1ha2VBcnJheSggdmFsdWUgKSxcblx0XHRcdFx0XHRpID0gb3B0aW9ucy5sZW5ndGg7XG5cblx0XHRcdFx0d2hpbGUgKCBpLS0gKSB7XG5cdFx0XHRcdFx0b3B0aW9uID0gb3B0aW9uc1sgaSBdO1xuXG5cdFx0XHRcdFx0LyogZXNsaW50LWRpc2FibGUgbm8tY29uZC1hc3NpZ24gKi9cblxuXHRcdFx0XHRcdGlmICggb3B0aW9uLnNlbGVjdGVkID1cblx0XHRcdFx0XHRcdGpRdWVyeS5pbkFycmF5KCBqUXVlcnkudmFsSG9va3Mub3B0aW9uLmdldCggb3B0aW9uICksIHZhbHVlcyApID4gLTFcblx0XHRcdFx0XHQpIHtcblx0XHRcdFx0XHRcdG9wdGlvblNldCA9IHRydWU7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0LyogZXNsaW50LWVuYWJsZSBuby1jb25kLWFzc2lnbiAqL1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gRm9yY2UgYnJvd3NlcnMgdG8gYmVoYXZlIGNvbnNpc3RlbnRseSB3aGVuIG5vbi1tYXRjaGluZyB2YWx1ZSBpcyBzZXRcblx0XHRcdFx0aWYgKCAhb3B0aW9uU2V0ICkge1xuXHRcdFx0XHRcdGVsZW0uc2VsZWN0ZWRJbmRleCA9IC0xO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiB2YWx1ZXM7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG59ICk7XG5cbi8vIFJhZGlvcyBhbmQgY2hlY2tib3hlcyBnZXR0ZXIvc2V0dGVyXG5qUXVlcnkuZWFjaCggWyBcInJhZGlvXCIsIFwiY2hlY2tib3hcIiBdLCBmdW5jdGlvbigpIHtcblx0alF1ZXJ5LnZhbEhvb2tzWyB0aGlzIF0gPSB7XG5cdFx0c2V0OiBmdW5jdGlvbiggZWxlbSwgdmFsdWUgKSB7XG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHZhbHVlICkgKSB7XG5cdFx0XHRcdHJldHVybiAoIGVsZW0uY2hlY2tlZCA9IGpRdWVyeS5pbkFycmF5KCBqUXVlcnkoIGVsZW0gKS52YWwoKSwgdmFsdWUgKSA+IC0xICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xuXHRpZiAoICFzdXBwb3J0LmNoZWNrT24gKSB7XG5cdFx0alF1ZXJ5LnZhbEhvb2tzWyB0aGlzIF0uZ2V0ID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0XHRyZXR1cm4gZWxlbS5nZXRBdHRyaWJ1dGUoIFwidmFsdWVcIiApID09PSBudWxsID8gXCJvblwiIDogZWxlbS52YWx1ZTtcblx0XHR9O1xuXHR9XG59ICk7XG5cblxuXG5cbi8vIFJldHVybiBqUXVlcnkgZm9yIGF0dHJpYnV0ZXMtb25seSBpbmNsdXNpb25cblxuXG5zdXBwb3J0LmZvY3VzaW4gPSBcIm9uZm9jdXNpblwiIGluIHdpbmRvdztcblxuXG52YXIgcmZvY3VzTW9ycGggPSAvXig/OmZvY3VzaW5mb2N1c3xmb2N1c291dGJsdXIpJC8sXG5cdHN0b3BQcm9wYWdhdGlvbkNhbGxiYWNrID0gZnVuY3Rpb24oIGUgKSB7XG5cdFx0ZS5zdG9wUHJvcGFnYXRpb24oKTtcblx0fTtcblxualF1ZXJ5LmV4dGVuZCggalF1ZXJ5LmV2ZW50LCB7XG5cblx0dHJpZ2dlcjogZnVuY3Rpb24oIGV2ZW50LCBkYXRhLCBlbGVtLCBvbmx5SGFuZGxlcnMgKSB7XG5cblx0XHR2YXIgaSwgY3VyLCB0bXAsIGJ1YmJsZVR5cGUsIG9udHlwZSwgaGFuZGxlLCBzcGVjaWFsLCBsYXN0RWxlbWVudCxcblx0XHRcdGV2ZW50UGF0aCA9IFsgZWxlbSB8fCBkb2N1bWVudCBdLFxuXHRcdFx0dHlwZSA9IGhhc093bi5jYWxsKCBldmVudCwgXCJ0eXBlXCIgKSA/IGV2ZW50LnR5cGUgOiBldmVudCxcblx0XHRcdG5hbWVzcGFjZXMgPSBoYXNPd24uY2FsbCggZXZlbnQsIFwibmFtZXNwYWNlXCIgKSA/IGV2ZW50Lm5hbWVzcGFjZS5zcGxpdCggXCIuXCIgKSA6IFtdO1xuXG5cdFx0Y3VyID0gbGFzdEVsZW1lbnQgPSB0bXAgPSBlbGVtID0gZWxlbSB8fCBkb2N1bWVudDtcblxuXHRcdC8vIERvbid0IGRvIGV2ZW50cyBvbiB0ZXh0IGFuZCBjb21tZW50IG5vZGVzXG5cdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSAzIHx8IGVsZW0ubm9kZVR5cGUgPT09IDggKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gZm9jdXMvYmx1ciBtb3JwaHMgdG8gZm9jdXNpbi9vdXQ7IGVuc3VyZSB3ZSdyZSBub3QgZmlyaW5nIHRoZW0gcmlnaHQgbm93XG5cdFx0aWYgKCByZm9jdXNNb3JwaC50ZXN0KCB0eXBlICsgalF1ZXJ5LmV2ZW50LnRyaWdnZXJlZCApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggdHlwZS5pbmRleE9mKCBcIi5cIiApID4gLTEgKSB7XG5cblx0XHRcdC8vIE5hbWVzcGFjZWQgdHJpZ2dlcjsgY3JlYXRlIGEgcmVnZXhwIHRvIG1hdGNoIGV2ZW50IHR5cGUgaW4gaGFuZGxlKClcblx0XHRcdG5hbWVzcGFjZXMgPSB0eXBlLnNwbGl0KCBcIi5cIiApO1xuXHRcdFx0dHlwZSA9IG5hbWVzcGFjZXMuc2hpZnQoKTtcblx0XHRcdG5hbWVzcGFjZXMuc29ydCgpO1xuXHRcdH1cblx0XHRvbnR5cGUgPSB0eXBlLmluZGV4T2YoIFwiOlwiICkgPCAwICYmIFwib25cIiArIHR5cGU7XG5cblx0XHQvLyBDYWxsZXIgY2FuIHBhc3MgaW4gYSBqUXVlcnkuRXZlbnQgb2JqZWN0LCBPYmplY3QsIG9yIGp1c3QgYW4gZXZlbnQgdHlwZSBzdHJpbmdcblx0XHRldmVudCA9IGV2ZW50WyBqUXVlcnkuZXhwYW5kbyBdID9cblx0XHRcdGV2ZW50IDpcblx0XHRcdG5ldyBqUXVlcnkuRXZlbnQoIHR5cGUsIHR5cGVvZiBldmVudCA9PT0gXCJvYmplY3RcIiAmJiBldmVudCApO1xuXG5cdFx0Ly8gVHJpZ2dlciBiaXRtYXNrOiAmIDEgZm9yIG5hdGl2ZSBoYW5kbGVyczsgJiAyIGZvciBqUXVlcnkgKGFsd2F5cyB0cnVlKVxuXHRcdGV2ZW50LmlzVHJpZ2dlciA9IG9ubHlIYW5kbGVycyA/IDIgOiAzO1xuXHRcdGV2ZW50Lm5hbWVzcGFjZSA9IG5hbWVzcGFjZXMuam9pbiggXCIuXCIgKTtcblx0XHRldmVudC5ybmFtZXNwYWNlID0gZXZlbnQubmFtZXNwYWNlID9cblx0XHRcdG5ldyBSZWdFeHAoIFwiKF58XFxcXC4pXCIgKyBuYW1lc3BhY2VzLmpvaW4oIFwiXFxcXC4oPzouKlxcXFwufClcIiApICsgXCIoXFxcXC58JClcIiApIDpcblx0XHRcdG51bGw7XG5cblx0XHQvLyBDbGVhbiB1cCB0aGUgZXZlbnQgaW4gY2FzZSBpdCBpcyBiZWluZyByZXVzZWRcblx0XHRldmVudC5yZXN1bHQgPSB1bmRlZmluZWQ7XG5cdFx0aWYgKCAhZXZlbnQudGFyZ2V0ICkge1xuXHRcdFx0ZXZlbnQudGFyZ2V0ID0gZWxlbTtcblx0XHR9XG5cblx0XHQvLyBDbG9uZSBhbnkgaW5jb21pbmcgZGF0YSBhbmQgcHJlcGVuZCB0aGUgZXZlbnQsIGNyZWF0aW5nIHRoZSBoYW5kbGVyIGFyZyBsaXN0XG5cdFx0ZGF0YSA9IGRhdGEgPT0gbnVsbCA/XG5cdFx0XHRbIGV2ZW50IF0gOlxuXHRcdFx0alF1ZXJ5Lm1ha2VBcnJheSggZGF0YSwgWyBldmVudCBdICk7XG5cblx0XHQvLyBBbGxvdyBzcGVjaWFsIGV2ZW50cyB0byBkcmF3IG91dHNpZGUgdGhlIGxpbmVzXG5cdFx0c3BlY2lhbCA9IGpRdWVyeS5ldmVudC5zcGVjaWFsWyB0eXBlIF0gfHwge307XG5cdFx0aWYgKCAhb25seUhhbmRsZXJzICYmIHNwZWNpYWwudHJpZ2dlciAmJiBzcGVjaWFsLnRyaWdnZXIuYXBwbHkoIGVsZW0sIGRhdGEgKSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gRGV0ZXJtaW5lIGV2ZW50IHByb3BhZ2F0aW9uIHBhdGggaW4gYWR2YW5jZSwgcGVyIFczQyBldmVudHMgc3BlYyAoIzk5NTEpXG5cdFx0Ly8gQnViYmxlIHVwIHRvIGRvY3VtZW50LCB0aGVuIHRvIHdpbmRvdzsgd2F0Y2ggZm9yIGEgZ2xvYmFsIG93bmVyRG9jdW1lbnQgdmFyICgjOTcyNClcblx0XHRpZiAoICFvbmx5SGFuZGxlcnMgJiYgIXNwZWNpYWwubm9CdWJibGUgJiYgIWlzV2luZG93KCBlbGVtICkgKSB7XG5cblx0XHRcdGJ1YmJsZVR5cGUgPSBzcGVjaWFsLmRlbGVnYXRlVHlwZSB8fCB0eXBlO1xuXHRcdFx0aWYgKCAhcmZvY3VzTW9ycGgudGVzdCggYnViYmxlVHlwZSArIHR5cGUgKSApIHtcblx0XHRcdFx0Y3VyID0gY3VyLnBhcmVudE5vZGU7XG5cdFx0XHR9XG5cdFx0XHRmb3IgKCA7IGN1cjsgY3VyID0gY3VyLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdGV2ZW50UGF0aC5wdXNoKCBjdXIgKTtcblx0XHRcdFx0dG1wID0gY3VyO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBPbmx5IGFkZCB3aW5kb3cgaWYgd2UgZ290IHRvIGRvY3VtZW50IChlLmcuLCBub3QgcGxhaW4gb2JqIG9yIGRldGFjaGVkIERPTSlcblx0XHRcdGlmICggdG1wID09PSAoIGVsZW0ub3duZXJEb2N1bWVudCB8fCBkb2N1bWVudCApICkge1xuXHRcdFx0XHRldmVudFBhdGgucHVzaCggdG1wLmRlZmF1bHRWaWV3IHx8IHRtcC5wYXJlbnRXaW5kb3cgfHwgd2luZG93ICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gRmlyZSBoYW5kbGVycyBvbiB0aGUgZXZlbnQgcGF0aFxuXHRcdGkgPSAwO1xuXHRcdHdoaWxlICggKCBjdXIgPSBldmVudFBhdGhbIGkrKyBdICkgJiYgIWV2ZW50LmlzUHJvcGFnYXRpb25TdG9wcGVkKCkgKSB7XG5cdFx0XHRsYXN0RWxlbWVudCA9IGN1cjtcblx0XHRcdGV2ZW50LnR5cGUgPSBpID4gMSA/XG5cdFx0XHRcdGJ1YmJsZVR5cGUgOlxuXHRcdFx0XHRzcGVjaWFsLmJpbmRUeXBlIHx8IHR5cGU7XG5cblx0XHRcdC8vIGpRdWVyeSBoYW5kbGVyXG5cdFx0XHRoYW5kbGUgPSAoIGRhdGFQcml2LmdldCggY3VyLCBcImV2ZW50c1wiICkgfHwge30gKVsgZXZlbnQudHlwZSBdICYmXG5cdFx0XHRcdGRhdGFQcml2LmdldCggY3VyLCBcImhhbmRsZVwiICk7XG5cdFx0XHRpZiAoIGhhbmRsZSApIHtcblx0XHRcdFx0aGFuZGxlLmFwcGx5KCBjdXIsIGRhdGEgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gTmF0aXZlIGhhbmRsZXJcblx0XHRcdGhhbmRsZSA9IG9udHlwZSAmJiBjdXJbIG9udHlwZSBdO1xuXHRcdFx0aWYgKCBoYW5kbGUgJiYgaGFuZGxlLmFwcGx5ICYmIGFjY2VwdERhdGEoIGN1ciApICkge1xuXHRcdFx0XHRldmVudC5yZXN1bHQgPSBoYW5kbGUuYXBwbHkoIGN1ciwgZGF0YSApO1xuXHRcdFx0XHRpZiAoIGV2ZW50LnJlc3VsdCA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRldmVudC50eXBlID0gdHlwZTtcblxuXHRcdC8vIElmIG5vYm9keSBwcmV2ZW50ZWQgdGhlIGRlZmF1bHQgYWN0aW9uLCBkbyBpdCBub3dcblx0XHRpZiAoICFvbmx5SGFuZGxlcnMgJiYgIWV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpICkge1xuXG5cdFx0XHRpZiAoICggIXNwZWNpYWwuX2RlZmF1bHQgfHxcblx0XHRcdFx0c3BlY2lhbC5fZGVmYXVsdC5hcHBseSggZXZlbnRQYXRoLnBvcCgpLCBkYXRhICkgPT09IGZhbHNlICkgJiZcblx0XHRcdFx0YWNjZXB0RGF0YSggZWxlbSApICkge1xuXG5cdFx0XHRcdC8vIENhbGwgYSBuYXRpdmUgRE9NIG1ldGhvZCBvbiB0aGUgdGFyZ2V0IHdpdGggdGhlIHNhbWUgbmFtZSBhcyB0aGUgZXZlbnQuXG5cdFx0XHRcdC8vIERvbid0IGRvIGRlZmF1bHQgYWN0aW9ucyBvbiB3aW5kb3csIHRoYXQncyB3aGVyZSBnbG9iYWwgdmFyaWFibGVzIGJlICgjNjE3MClcblx0XHRcdFx0aWYgKCBvbnR5cGUgJiYgaXNGdW5jdGlvbiggZWxlbVsgdHlwZSBdICkgJiYgIWlzV2luZG93KCBlbGVtICkgKSB7XG5cblx0XHRcdFx0XHQvLyBEb24ndCByZS10cmlnZ2VyIGFuIG9uRk9PIGV2ZW50IHdoZW4gd2UgY2FsbCBpdHMgRk9PKCkgbWV0aG9kXG5cdFx0XHRcdFx0dG1wID0gZWxlbVsgb250eXBlIF07XG5cblx0XHRcdFx0XHRpZiAoIHRtcCApIHtcblx0XHRcdFx0XHRcdGVsZW1bIG9udHlwZSBdID0gbnVsbDtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBQcmV2ZW50IHJlLXRyaWdnZXJpbmcgb2YgdGhlIHNhbWUgZXZlbnQsIHNpbmNlIHdlIGFscmVhZHkgYnViYmxlZCBpdCBhYm92ZVxuXHRcdFx0XHRcdGpRdWVyeS5ldmVudC50cmlnZ2VyZWQgPSB0eXBlO1xuXG5cdFx0XHRcdFx0aWYgKCBldmVudC5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpICkge1xuXHRcdFx0XHRcdFx0bGFzdEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggdHlwZSwgc3RvcFByb3BhZ2F0aW9uQ2FsbGJhY2sgKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRlbGVtWyB0eXBlIF0oKTtcblxuXHRcdFx0XHRcdGlmICggZXZlbnQuaXNQcm9wYWdhdGlvblN0b3BwZWQoKSApIHtcblx0XHRcdFx0XHRcdGxhc3RFbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoIHR5cGUsIHN0b3BQcm9wYWdhdGlvbkNhbGxiYWNrICk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0alF1ZXJ5LmV2ZW50LnRyaWdnZXJlZCA9IHVuZGVmaW5lZDtcblxuXHRcdFx0XHRcdGlmICggdG1wICkge1xuXHRcdFx0XHRcdFx0ZWxlbVsgb250eXBlIF0gPSB0bXA7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGV2ZW50LnJlc3VsdDtcblx0fSxcblxuXHQvLyBQaWdneWJhY2sgb24gYSBkb25vciBldmVudCB0byBzaW11bGF0ZSBhIGRpZmZlcmVudCBvbmVcblx0Ly8gVXNlZCBvbmx5IGZvciBgZm9jdXMoaW4gfCBvdXQpYCBldmVudHNcblx0c2ltdWxhdGU6IGZ1bmN0aW9uKCB0eXBlLCBlbGVtLCBldmVudCApIHtcblx0XHR2YXIgZSA9IGpRdWVyeS5leHRlbmQoXG5cdFx0XHRuZXcgalF1ZXJ5LkV2ZW50KCksXG5cdFx0XHRldmVudCxcblx0XHRcdHtcblx0XHRcdFx0dHlwZTogdHlwZSxcblx0XHRcdFx0aXNTaW11bGF0ZWQ6IHRydWVcblx0XHRcdH1cblx0XHQpO1xuXG5cdFx0alF1ZXJ5LmV2ZW50LnRyaWdnZXIoIGUsIG51bGwsIGVsZW0gKTtcblx0fVxuXG59ICk7XG5cbmpRdWVyeS5mbi5leHRlbmQoIHtcblxuXHR0cmlnZ2VyOiBmdW5jdGlvbiggdHlwZSwgZGF0YSApIHtcblx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdGpRdWVyeS5ldmVudC50cmlnZ2VyKCB0eXBlLCBkYXRhLCB0aGlzICk7XG5cdFx0fSApO1xuXHR9LFxuXHR0cmlnZ2VySGFuZGxlcjogZnVuY3Rpb24oIHR5cGUsIGRhdGEgKSB7XG5cdFx0dmFyIGVsZW0gPSB0aGlzWyAwIF07XG5cdFx0aWYgKCBlbGVtICkge1xuXHRcdFx0cmV0dXJuIGpRdWVyeS5ldmVudC50cmlnZ2VyKCB0eXBlLCBkYXRhLCBlbGVtLCB0cnVlICk7XG5cdFx0fVxuXHR9XG59ICk7XG5cblxuLy8gU3VwcG9ydDogRmlyZWZveCA8PTQ0XG4vLyBGaXJlZm94IGRvZXNuJ3QgaGF2ZSBmb2N1cyhpbiB8IG91dCkgZXZlbnRzXG4vLyBSZWxhdGVkIHRpY2tldCAtIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTY4Nzc4N1xuLy9cbi8vIFN1cHBvcnQ6IENocm9tZSA8PTQ4IC0gNDksIFNhZmFyaSA8PTkuMCAtIDkuMVxuLy8gZm9jdXMoaW4gfCBvdXQpIGV2ZW50cyBmaXJlIGFmdGVyIGZvY3VzICYgYmx1ciBldmVudHMsXG4vLyB3aGljaCBpcyBzcGVjIHZpb2xhdGlvbiAtIGh0dHA6Ly93d3cudzMub3JnL1RSL0RPTS1MZXZlbC0zLUV2ZW50cy8jZXZlbnRzLWZvY3VzZXZlbnQtZXZlbnQtb3JkZXJcbi8vIFJlbGF0ZWQgdGlja2V0IC0gaHR0cHM6Ly9idWdzLmNocm9taXVtLm9yZy9wL2Nocm9taXVtL2lzc3Vlcy9kZXRhaWw/aWQ9NDQ5ODU3XG5pZiAoICFzdXBwb3J0LmZvY3VzaW4gKSB7XG5cdGpRdWVyeS5lYWNoKCB7IGZvY3VzOiBcImZvY3VzaW5cIiwgYmx1cjogXCJmb2N1c291dFwiIH0sIGZ1bmN0aW9uKCBvcmlnLCBmaXggKSB7XG5cblx0XHQvLyBBdHRhY2ggYSBzaW5nbGUgY2FwdHVyaW5nIGhhbmRsZXIgb24gdGhlIGRvY3VtZW50IHdoaWxlIHNvbWVvbmUgd2FudHMgZm9jdXNpbi9mb2N1c291dFxuXHRcdHZhciBoYW5kbGVyID0gZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0alF1ZXJ5LmV2ZW50LnNpbXVsYXRlKCBmaXgsIGV2ZW50LnRhcmdldCwgalF1ZXJ5LmV2ZW50LmZpeCggZXZlbnQgKSApO1xuXHRcdH07XG5cblx0XHRqUXVlcnkuZXZlbnQuc3BlY2lhbFsgZml4IF0gPSB7XG5cdFx0XHRzZXR1cDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBkb2MgPSB0aGlzLm93bmVyRG9jdW1lbnQgfHwgdGhpcyxcblx0XHRcdFx0XHRhdHRhY2hlcyA9IGRhdGFQcml2LmFjY2VzcyggZG9jLCBmaXggKTtcblxuXHRcdFx0XHRpZiAoICFhdHRhY2hlcyApIHtcblx0XHRcdFx0XHRkb2MuYWRkRXZlbnRMaXN0ZW5lciggb3JpZywgaGFuZGxlciwgdHJ1ZSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGRhdGFQcml2LmFjY2VzcyggZG9jLCBmaXgsICggYXR0YWNoZXMgfHwgMCApICsgMSApO1xuXHRcdFx0fSxcblx0XHRcdHRlYXJkb3duOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGRvYyA9IHRoaXMub3duZXJEb2N1bWVudCB8fCB0aGlzLFxuXHRcdFx0XHRcdGF0dGFjaGVzID0gZGF0YVByaXYuYWNjZXNzKCBkb2MsIGZpeCApIC0gMTtcblxuXHRcdFx0XHRpZiAoICFhdHRhY2hlcyApIHtcblx0XHRcdFx0XHRkb2MucmVtb3ZlRXZlbnRMaXN0ZW5lciggb3JpZywgaGFuZGxlciwgdHJ1ZSApO1xuXHRcdFx0XHRcdGRhdGFQcml2LnJlbW92ZSggZG9jLCBmaXggKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGRhdGFQcml2LmFjY2VzcyggZG9jLCBmaXgsIGF0dGFjaGVzICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXHR9ICk7XG59XG52YXIgbG9jYXRpb24gPSB3aW5kb3cubG9jYXRpb247XG5cbnZhciBub25jZSA9IERhdGUubm93KCk7XG5cbnZhciBycXVlcnkgPSAoIC9cXD8vICk7XG5cblxuXG4vLyBDcm9zcy1icm93c2VyIHhtbCBwYXJzaW5nXG5qUXVlcnkucGFyc2VYTUwgPSBmdW5jdGlvbiggZGF0YSApIHtcblx0dmFyIHhtbDtcblx0aWYgKCAhZGF0YSB8fCB0eXBlb2YgZGF0YSAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRyZXR1cm4gbnVsbDtcblx0fVxuXG5cdC8vIFN1cHBvcnQ6IElFIDkgLSAxMSBvbmx5XG5cdC8vIElFIHRocm93cyBvbiBwYXJzZUZyb21TdHJpbmcgd2l0aCBpbnZhbGlkIGlucHV0LlxuXHR0cnkge1xuXHRcdHhtbCA9ICggbmV3IHdpbmRvdy5ET01QYXJzZXIoKSApLnBhcnNlRnJvbVN0cmluZyggZGF0YSwgXCJ0ZXh0L3htbFwiICk7XG5cdH0gY2F0Y2ggKCBlICkge1xuXHRcdHhtbCA9IHVuZGVmaW5lZDtcblx0fVxuXG5cdGlmICggIXhtbCB8fCB4bWwuZ2V0RWxlbWVudHNCeVRhZ05hbWUoIFwicGFyc2VyZXJyb3JcIiApLmxlbmd0aCApIHtcblx0XHRqUXVlcnkuZXJyb3IoIFwiSW52YWxpZCBYTUw6IFwiICsgZGF0YSApO1xuXHR9XG5cdHJldHVybiB4bWw7XG59O1xuXG5cbnZhclxuXHRyYnJhY2tldCA9IC9cXFtcXF0kLyxcblx0ckNSTEYgPSAvXFxyP1xcbi9nLFxuXHRyc3VibWl0dGVyVHlwZXMgPSAvXig/OnN1Ym1pdHxidXR0b258aW1hZ2V8cmVzZXR8ZmlsZSkkL2ksXG5cdHJzdWJtaXR0YWJsZSA9IC9eKD86aW5wdXR8c2VsZWN0fHRleHRhcmVhfGtleWdlbikvaTtcblxuZnVuY3Rpb24gYnVpbGRQYXJhbXMoIHByZWZpeCwgb2JqLCB0cmFkaXRpb25hbCwgYWRkICkge1xuXHR2YXIgbmFtZTtcblxuXHRpZiAoIEFycmF5LmlzQXJyYXkoIG9iaiApICkge1xuXG5cdFx0Ly8gU2VyaWFsaXplIGFycmF5IGl0ZW0uXG5cdFx0alF1ZXJ5LmVhY2goIG9iaiwgZnVuY3Rpb24oIGksIHYgKSB7XG5cdFx0XHRpZiAoIHRyYWRpdGlvbmFsIHx8IHJicmFja2V0LnRlc3QoIHByZWZpeCApICkge1xuXG5cdFx0XHRcdC8vIFRyZWF0IGVhY2ggYXJyYXkgaXRlbSBhcyBhIHNjYWxhci5cblx0XHRcdFx0YWRkKCBwcmVmaXgsIHYgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBJdGVtIGlzIG5vbi1zY2FsYXIgKGFycmF5IG9yIG9iamVjdCksIGVuY29kZSBpdHMgbnVtZXJpYyBpbmRleC5cblx0XHRcdFx0YnVpbGRQYXJhbXMoXG5cdFx0XHRcdFx0cHJlZml4ICsgXCJbXCIgKyAoIHR5cGVvZiB2ID09PSBcIm9iamVjdFwiICYmIHYgIT0gbnVsbCA/IGkgOiBcIlwiICkgKyBcIl1cIixcblx0XHRcdFx0XHR2LFxuXHRcdFx0XHRcdHRyYWRpdGlvbmFsLFxuXHRcdFx0XHRcdGFkZFxuXHRcdFx0XHQpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHR9IGVsc2UgaWYgKCAhdHJhZGl0aW9uYWwgJiYgdG9UeXBlKCBvYmogKSA9PT0gXCJvYmplY3RcIiApIHtcblxuXHRcdC8vIFNlcmlhbGl6ZSBvYmplY3QgaXRlbS5cblx0XHRmb3IgKCBuYW1lIGluIG9iaiApIHtcblx0XHRcdGJ1aWxkUGFyYW1zKCBwcmVmaXggKyBcIltcIiArIG5hbWUgKyBcIl1cIiwgb2JqWyBuYW1lIF0sIHRyYWRpdGlvbmFsLCBhZGQgKTtcblx0XHR9XG5cblx0fSBlbHNlIHtcblxuXHRcdC8vIFNlcmlhbGl6ZSBzY2FsYXIgaXRlbS5cblx0XHRhZGQoIHByZWZpeCwgb2JqICk7XG5cdH1cbn1cblxuLy8gU2VyaWFsaXplIGFuIGFycmF5IG9mIGZvcm0gZWxlbWVudHMgb3IgYSBzZXQgb2Zcbi8vIGtleS92YWx1ZXMgaW50byBhIHF1ZXJ5IHN0cmluZ1xualF1ZXJ5LnBhcmFtID0gZnVuY3Rpb24oIGEsIHRyYWRpdGlvbmFsICkge1xuXHR2YXIgcHJlZml4LFxuXHRcdHMgPSBbXSxcblx0XHRhZGQgPSBmdW5jdGlvbigga2V5LCB2YWx1ZU9yRnVuY3Rpb24gKSB7XG5cblx0XHRcdC8vIElmIHZhbHVlIGlzIGEgZnVuY3Rpb24sIGludm9rZSBpdCBhbmQgdXNlIGl0cyByZXR1cm4gdmFsdWVcblx0XHRcdHZhciB2YWx1ZSA9IGlzRnVuY3Rpb24oIHZhbHVlT3JGdW5jdGlvbiApID9cblx0XHRcdFx0dmFsdWVPckZ1bmN0aW9uKCkgOlxuXHRcdFx0XHR2YWx1ZU9yRnVuY3Rpb247XG5cblx0XHRcdHNbIHMubGVuZ3RoIF0gPSBlbmNvZGVVUklDb21wb25lbnQoIGtleSApICsgXCI9XCIgK1xuXHRcdFx0XHRlbmNvZGVVUklDb21wb25lbnQoIHZhbHVlID09IG51bGwgPyBcIlwiIDogdmFsdWUgKTtcblx0XHR9O1xuXG5cdGlmICggYSA9PSBudWxsICkge1xuXHRcdHJldHVybiBcIlwiO1xuXHR9XG5cblx0Ly8gSWYgYW4gYXJyYXkgd2FzIHBhc3NlZCBpbiwgYXNzdW1lIHRoYXQgaXQgaXMgYW4gYXJyYXkgb2YgZm9ybSBlbGVtZW50cy5cblx0aWYgKCBBcnJheS5pc0FycmF5KCBhICkgfHwgKCBhLmpxdWVyeSAmJiAhalF1ZXJ5LmlzUGxhaW5PYmplY3QoIGEgKSApICkge1xuXG5cdFx0Ly8gU2VyaWFsaXplIHRoZSBmb3JtIGVsZW1lbnRzXG5cdFx0alF1ZXJ5LmVhY2goIGEsIGZ1bmN0aW9uKCkge1xuXHRcdFx0YWRkKCB0aGlzLm5hbWUsIHRoaXMudmFsdWUgKTtcblx0XHR9ICk7XG5cblx0fSBlbHNlIHtcblxuXHRcdC8vIElmIHRyYWRpdGlvbmFsLCBlbmNvZGUgdGhlIFwib2xkXCIgd2F5ICh0aGUgd2F5IDEuMy4yIG9yIG9sZGVyXG5cdFx0Ly8gZGlkIGl0KSwgb3RoZXJ3aXNlIGVuY29kZSBwYXJhbXMgcmVjdXJzaXZlbHkuXG5cdFx0Zm9yICggcHJlZml4IGluIGEgKSB7XG5cdFx0XHRidWlsZFBhcmFtcyggcHJlZml4LCBhWyBwcmVmaXggXSwgdHJhZGl0aW9uYWwsIGFkZCApO1xuXHRcdH1cblx0fVxuXG5cdC8vIFJldHVybiB0aGUgcmVzdWx0aW5nIHNlcmlhbGl6YXRpb25cblx0cmV0dXJuIHMuam9pbiggXCImXCIgKTtcbn07XG5cbmpRdWVyeS5mbi5leHRlbmQoIHtcblx0c2VyaWFsaXplOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4galF1ZXJ5LnBhcmFtKCB0aGlzLnNlcmlhbGl6ZUFycmF5KCkgKTtcblx0fSxcblx0c2VyaWFsaXplQXJyYXk6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLm1hcCggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIENhbiBhZGQgcHJvcEhvb2sgZm9yIFwiZWxlbWVudHNcIiB0byBmaWx0ZXIgb3IgYWRkIGZvcm0gZWxlbWVudHNcblx0XHRcdHZhciBlbGVtZW50cyA9IGpRdWVyeS5wcm9wKCB0aGlzLCBcImVsZW1lbnRzXCIgKTtcblx0XHRcdHJldHVybiBlbGVtZW50cyA/IGpRdWVyeS5tYWtlQXJyYXkoIGVsZW1lbnRzICkgOiB0aGlzO1xuXHRcdH0gKVxuXHRcdC5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHR5cGUgPSB0aGlzLnR5cGU7XG5cblx0XHRcdC8vIFVzZSAuaXMoIFwiOmRpc2FibGVkXCIgKSBzbyB0aGF0IGZpZWxkc2V0W2Rpc2FibGVkXSB3b3Jrc1xuXHRcdFx0cmV0dXJuIHRoaXMubmFtZSAmJiAhalF1ZXJ5KCB0aGlzICkuaXMoIFwiOmRpc2FibGVkXCIgKSAmJlxuXHRcdFx0XHRyc3VibWl0dGFibGUudGVzdCggdGhpcy5ub2RlTmFtZSApICYmICFyc3VibWl0dGVyVHlwZXMudGVzdCggdHlwZSApICYmXG5cdFx0XHRcdCggdGhpcy5jaGVja2VkIHx8ICFyY2hlY2thYmxlVHlwZS50ZXN0KCB0eXBlICkgKTtcblx0XHR9IClcblx0XHQubWFwKCBmdW5jdGlvbiggaSwgZWxlbSApIHtcblx0XHRcdHZhciB2YWwgPSBqUXVlcnkoIHRoaXMgKS52YWwoKTtcblxuXHRcdFx0aWYgKCB2YWwgPT0gbnVsbCApIHtcblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggdmFsICkgKSB7XG5cdFx0XHRcdHJldHVybiBqUXVlcnkubWFwKCB2YWwsIGZ1bmN0aW9uKCB2YWwgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHsgbmFtZTogZWxlbS5uYW1lLCB2YWx1ZTogdmFsLnJlcGxhY2UoIHJDUkxGLCBcIlxcclxcblwiICkgfTtcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4geyBuYW1lOiBlbGVtLm5hbWUsIHZhbHVlOiB2YWwucmVwbGFjZSggckNSTEYsIFwiXFxyXFxuXCIgKSB9O1xuXHRcdH0gKS5nZXQoKTtcblx0fVxufSApO1xuXG5cbnZhclxuXHRyMjAgPSAvJTIwL2csXG5cdHJoYXNoID0gLyMuKiQvLFxuXHRyYW50aUNhY2hlID0gLyhbPyZdKV89W14mXSovLFxuXHRyaGVhZGVycyA9IC9eKC4qPyk6WyBcXHRdKihbXlxcclxcbl0qKSQvbWcsXG5cblx0Ly8gIzc2NTMsICM4MTI1LCAjODE1MjogbG9jYWwgcHJvdG9jb2wgZGV0ZWN0aW9uXG5cdHJsb2NhbFByb3RvY29sID0gL14oPzphYm91dHxhcHB8YXBwLXN0b3JhZ2V8ListZXh0ZW5zaW9ufGZpbGV8cmVzfHdpZGdldCk6JC8sXG5cdHJub0NvbnRlbnQgPSAvXig/OkdFVHxIRUFEKSQvLFxuXHRycHJvdG9jb2wgPSAvXlxcL1xcLy8sXG5cblx0LyogUHJlZmlsdGVyc1xuXHQgKiAxKSBUaGV5IGFyZSB1c2VmdWwgdG8gaW50cm9kdWNlIGN1c3RvbSBkYXRhVHlwZXMgKHNlZSBhamF4L2pzb25wLmpzIGZvciBhbiBleGFtcGxlKVxuXHQgKiAyKSBUaGVzZSBhcmUgY2FsbGVkOlxuXHQgKiAgICAtIEJFRk9SRSBhc2tpbmcgZm9yIGEgdHJhbnNwb3J0XG5cdCAqICAgIC0gQUZURVIgcGFyYW0gc2VyaWFsaXphdGlvbiAocy5kYXRhIGlzIGEgc3RyaW5nIGlmIHMucHJvY2Vzc0RhdGEgaXMgdHJ1ZSlcblx0ICogMykga2V5IGlzIHRoZSBkYXRhVHlwZVxuXHQgKiA0KSB0aGUgY2F0Y2hhbGwgc3ltYm9sIFwiKlwiIGNhbiBiZSB1c2VkXG5cdCAqIDUpIGV4ZWN1dGlvbiB3aWxsIHN0YXJ0IHdpdGggdHJhbnNwb3J0IGRhdGFUeXBlIGFuZCBUSEVOIGNvbnRpbnVlIGRvd24gdG8gXCIqXCIgaWYgbmVlZGVkXG5cdCAqL1xuXHRwcmVmaWx0ZXJzID0ge30sXG5cblx0LyogVHJhbnNwb3J0cyBiaW5kaW5nc1xuXHQgKiAxKSBrZXkgaXMgdGhlIGRhdGFUeXBlXG5cdCAqIDIpIHRoZSBjYXRjaGFsbCBzeW1ib2wgXCIqXCIgY2FuIGJlIHVzZWRcblx0ICogMykgc2VsZWN0aW9uIHdpbGwgc3RhcnQgd2l0aCB0cmFuc3BvcnQgZGF0YVR5cGUgYW5kIFRIRU4gZ28gdG8gXCIqXCIgaWYgbmVlZGVkXG5cdCAqL1xuXHR0cmFuc3BvcnRzID0ge30sXG5cblx0Ly8gQXZvaWQgY29tbWVudC1wcm9sb2cgY2hhciBzZXF1ZW5jZSAoIzEwMDk4KTsgbXVzdCBhcHBlYXNlIGxpbnQgYW5kIGV2YWRlIGNvbXByZXNzaW9uXG5cdGFsbFR5cGVzID0gXCIqL1wiLmNvbmNhdCggXCIqXCIgKSxcblxuXHQvLyBBbmNob3IgdGFnIGZvciBwYXJzaW5nIHRoZSBkb2N1bWVudCBvcmlnaW5cblx0b3JpZ2luQW5jaG9yID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggXCJhXCIgKTtcblx0b3JpZ2luQW5jaG9yLmhyZWYgPSBsb2NhdGlvbi5ocmVmO1xuXG4vLyBCYXNlIFwiY29uc3RydWN0b3JcIiBmb3IgalF1ZXJ5LmFqYXhQcmVmaWx0ZXIgYW5kIGpRdWVyeS5hamF4VHJhbnNwb3J0XG5mdW5jdGlvbiBhZGRUb1ByZWZpbHRlcnNPclRyYW5zcG9ydHMoIHN0cnVjdHVyZSApIHtcblxuXHQvLyBkYXRhVHlwZUV4cHJlc3Npb24gaXMgb3B0aW9uYWwgYW5kIGRlZmF1bHRzIHRvIFwiKlwiXG5cdHJldHVybiBmdW5jdGlvbiggZGF0YVR5cGVFeHByZXNzaW9uLCBmdW5jICkge1xuXG5cdFx0aWYgKCB0eXBlb2YgZGF0YVR5cGVFeHByZXNzaW9uICE9PSBcInN0cmluZ1wiICkge1xuXHRcdFx0ZnVuYyA9IGRhdGFUeXBlRXhwcmVzc2lvbjtcblx0XHRcdGRhdGFUeXBlRXhwcmVzc2lvbiA9IFwiKlwiO1xuXHRcdH1cblxuXHRcdHZhciBkYXRhVHlwZSxcblx0XHRcdGkgPSAwLFxuXHRcdFx0ZGF0YVR5cGVzID0gZGF0YVR5cGVFeHByZXNzaW9uLnRvTG93ZXJDYXNlKCkubWF0Y2goIHJub3RodG1sd2hpdGUgKSB8fCBbXTtcblxuXHRcdGlmICggaXNGdW5jdGlvbiggZnVuYyApICkge1xuXG5cdFx0XHQvLyBGb3IgZWFjaCBkYXRhVHlwZSBpbiB0aGUgZGF0YVR5cGVFeHByZXNzaW9uXG5cdFx0XHR3aGlsZSAoICggZGF0YVR5cGUgPSBkYXRhVHlwZXNbIGkrKyBdICkgKSB7XG5cblx0XHRcdFx0Ly8gUHJlcGVuZCBpZiByZXF1ZXN0ZWRcblx0XHRcdFx0aWYgKCBkYXRhVHlwZVsgMCBdID09PSBcIitcIiApIHtcblx0XHRcdFx0XHRkYXRhVHlwZSA9IGRhdGFUeXBlLnNsaWNlKCAxICkgfHwgXCIqXCI7XG5cdFx0XHRcdFx0KCBzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gPSBzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gfHwgW10gKS51bnNoaWZ0KCBmdW5jICk7XG5cblx0XHRcdFx0Ly8gT3RoZXJ3aXNlIGFwcGVuZFxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdCggc3RydWN0dXJlWyBkYXRhVHlwZSBdID0gc3RydWN0dXJlWyBkYXRhVHlwZSBdIHx8IFtdICkucHVzaCggZnVuYyApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9O1xufVxuXG4vLyBCYXNlIGluc3BlY3Rpb24gZnVuY3Rpb24gZm9yIHByZWZpbHRlcnMgYW5kIHRyYW5zcG9ydHNcbmZ1bmN0aW9uIGluc3BlY3RQcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCBzdHJ1Y3R1cmUsIG9wdGlvbnMsIG9yaWdpbmFsT3B0aW9ucywganFYSFIgKSB7XG5cblx0dmFyIGluc3BlY3RlZCA9IHt9LFxuXHRcdHNlZWtpbmdUcmFuc3BvcnQgPSAoIHN0cnVjdHVyZSA9PT0gdHJhbnNwb3J0cyApO1xuXG5cdGZ1bmN0aW9uIGluc3BlY3QoIGRhdGFUeXBlICkge1xuXHRcdHZhciBzZWxlY3RlZDtcblx0XHRpbnNwZWN0ZWRbIGRhdGFUeXBlIF0gPSB0cnVlO1xuXHRcdGpRdWVyeS5lYWNoKCBzdHJ1Y3R1cmVbIGRhdGFUeXBlIF0gfHwgW10sIGZ1bmN0aW9uKCBfLCBwcmVmaWx0ZXJPckZhY3RvcnkgKSB7XG5cdFx0XHR2YXIgZGF0YVR5cGVPclRyYW5zcG9ydCA9IHByZWZpbHRlck9yRmFjdG9yeSggb3B0aW9ucywgb3JpZ2luYWxPcHRpb25zLCBqcVhIUiApO1xuXHRcdFx0aWYgKCB0eXBlb2YgZGF0YVR5cGVPclRyYW5zcG9ydCA9PT0gXCJzdHJpbmdcIiAmJlxuXHRcdFx0XHQhc2Vla2luZ1RyYW5zcG9ydCAmJiAhaW5zcGVjdGVkWyBkYXRhVHlwZU9yVHJhbnNwb3J0IF0gKSB7XG5cblx0XHRcdFx0b3B0aW9ucy5kYXRhVHlwZXMudW5zaGlmdCggZGF0YVR5cGVPclRyYW5zcG9ydCApO1xuXHRcdFx0XHRpbnNwZWN0KCBkYXRhVHlwZU9yVHJhbnNwb3J0ICk7XG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdH0gZWxzZSBpZiAoIHNlZWtpbmdUcmFuc3BvcnQgKSB7XG5cdFx0XHRcdHJldHVybiAhKCBzZWxlY3RlZCA9IGRhdGFUeXBlT3JUcmFuc3BvcnQgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0cmV0dXJuIHNlbGVjdGVkO1xuXHR9XG5cblx0cmV0dXJuIGluc3BlY3QoIG9wdGlvbnMuZGF0YVR5cGVzWyAwIF0gKSB8fCAhaW5zcGVjdGVkWyBcIipcIiBdICYmIGluc3BlY3QoIFwiKlwiICk7XG59XG5cbi8vIEEgc3BlY2lhbCBleHRlbmQgZm9yIGFqYXggb3B0aW9uc1xuLy8gdGhhdCB0YWtlcyBcImZsYXRcIiBvcHRpb25zIChub3QgdG8gYmUgZGVlcCBleHRlbmRlZClcbi8vIEZpeGVzICM5ODg3XG5mdW5jdGlvbiBhamF4RXh0ZW5kKCB0YXJnZXQsIHNyYyApIHtcblx0dmFyIGtleSwgZGVlcCxcblx0XHRmbGF0T3B0aW9ucyA9IGpRdWVyeS5hamF4U2V0dGluZ3MuZmxhdE9wdGlvbnMgfHwge307XG5cblx0Zm9yICgga2V5IGluIHNyYyApIHtcblx0XHRpZiAoIHNyY1sga2V5IF0gIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdCggZmxhdE9wdGlvbnNbIGtleSBdID8gdGFyZ2V0IDogKCBkZWVwIHx8ICggZGVlcCA9IHt9ICkgKSApWyBrZXkgXSA9IHNyY1sga2V5IF07XG5cdFx0fVxuXHR9XG5cdGlmICggZGVlcCApIHtcblx0XHRqUXVlcnkuZXh0ZW5kKCB0cnVlLCB0YXJnZXQsIGRlZXAgKTtcblx0fVxuXG5cdHJldHVybiB0YXJnZXQ7XG59XG5cbi8qIEhhbmRsZXMgcmVzcG9uc2VzIHRvIGFuIGFqYXggcmVxdWVzdDpcbiAqIC0gZmluZHMgdGhlIHJpZ2h0IGRhdGFUeXBlIChtZWRpYXRlcyBiZXR3ZWVuIGNvbnRlbnQtdHlwZSBhbmQgZXhwZWN0ZWQgZGF0YVR5cGUpXG4gKiAtIHJldHVybnMgdGhlIGNvcnJlc3BvbmRpbmcgcmVzcG9uc2VcbiAqL1xuZnVuY3Rpb24gYWpheEhhbmRsZVJlc3BvbnNlcyggcywganFYSFIsIHJlc3BvbnNlcyApIHtcblxuXHR2YXIgY3QsIHR5cGUsIGZpbmFsRGF0YVR5cGUsIGZpcnN0RGF0YVR5cGUsXG5cdFx0Y29udGVudHMgPSBzLmNvbnRlbnRzLFxuXHRcdGRhdGFUeXBlcyA9IHMuZGF0YVR5cGVzO1xuXG5cdC8vIFJlbW92ZSBhdXRvIGRhdGFUeXBlIGFuZCBnZXQgY29udGVudC10eXBlIGluIHRoZSBwcm9jZXNzXG5cdHdoaWxlICggZGF0YVR5cGVzWyAwIF0gPT09IFwiKlwiICkge1xuXHRcdGRhdGFUeXBlcy5zaGlmdCgpO1xuXHRcdGlmICggY3QgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGN0ID0gcy5taW1lVHlwZSB8fCBqcVhIUi5nZXRSZXNwb25zZUhlYWRlciggXCJDb250ZW50LVR5cGVcIiApO1xuXHRcdH1cblx0fVxuXG5cdC8vIENoZWNrIGlmIHdlJ3JlIGRlYWxpbmcgd2l0aCBhIGtub3duIGNvbnRlbnQtdHlwZVxuXHRpZiAoIGN0ICkge1xuXHRcdGZvciAoIHR5cGUgaW4gY29udGVudHMgKSB7XG5cdFx0XHRpZiAoIGNvbnRlbnRzWyB0eXBlIF0gJiYgY29udGVudHNbIHR5cGUgXS50ZXN0KCBjdCApICkge1xuXHRcdFx0XHRkYXRhVHlwZXMudW5zaGlmdCggdHlwZSApO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLyBDaGVjayB0byBzZWUgaWYgd2UgaGF2ZSBhIHJlc3BvbnNlIGZvciB0aGUgZXhwZWN0ZWQgZGF0YVR5cGVcblx0aWYgKCBkYXRhVHlwZXNbIDAgXSBpbiByZXNwb25zZXMgKSB7XG5cdFx0ZmluYWxEYXRhVHlwZSA9IGRhdGFUeXBlc1sgMCBdO1xuXHR9IGVsc2Uge1xuXG5cdFx0Ly8gVHJ5IGNvbnZlcnRpYmxlIGRhdGFUeXBlc1xuXHRcdGZvciAoIHR5cGUgaW4gcmVzcG9uc2VzICkge1xuXHRcdFx0aWYgKCAhZGF0YVR5cGVzWyAwIF0gfHwgcy5jb252ZXJ0ZXJzWyB0eXBlICsgXCIgXCIgKyBkYXRhVHlwZXNbIDAgXSBdICkge1xuXHRcdFx0XHRmaW5hbERhdGFUeXBlID0gdHlwZTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0XHRpZiAoICFmaXJzdERhdGFUeXBlICkge1xuXHRcdFx0XHRmaXJzdERhdGFUeXBlID0gdHlwZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBPciBqdXN0IHVzZSBmaXJzdCBvbmVcblx0XHRmaW5hbERhdGFUeXBlID0gZmluYWxEYXRhVHlwZSB8fCBmaXJzdERhdGFUeXBlO1xuXHR9XG5cblx0Ly8gSWYgd2UgZm91bmQgYSBkYXRhVHlwZVxuXHQvLyBXZSBhZGQgdGhlIGRhdGFUeXBlIHRvIHRoZSBsaXN0IGlmIG5lZWRlZFxuXHQvLyBhbmQgcmV0dXJuIHRoZSBjb3JyZXNwb25kaW5nIHJlc3BvbnNlXG5cdGlmICggZmluYWxEYXRhVHlwZSApIHtcblx0XHRpZiAoIGZpbmFsRGF0YVR5cGUgIT09IGRhdGFUeXBlc1sgMCBdICkge1xuXHRcdFx0ZGF0YVR5cGVzLnVuc2hpZnQoIGZpbmFsRGF0YVR5cGUgKTtcblx0XHR9XG5cdFx0cmV0dXJuIHJlc3BvbnNlc1sgZmluYWxEYXRhVHlwZSBdO1xuXHR9XG59XG5cbi8qIENoYWluIGNvbnZlcnNpb25zIGdpdmVuIHRoZSByZXF1ZXN0IGFuZCB0aGUgb3JpZ2luYWwgcmVzcG9uc2VcbiAqIEFsc28gc2V0cyB0aGUgcmVzcG9uc2VYWFggZmllbGRzIG9uIHRoZSBqcVhIUiBpbnN0YW5jZVxuICovXG5mdW5jdGlvbiBhamF4Q29udmVydCggcywgcmVzcG9uc2UsIGpxWEhSLCBpc1N1Y2Nlc3MgKSB7XG5cdHZhciBjb252MiwgY3VycmVudCwgY29udiwgdG1wLCBwcmV2LFxuXHRcdGNvbnZlcnRlcnMgPSB7fSxcblxuXHRcdC8vIFdvcmsgd2l0aCBhIGNvcHkgb2YgZGF0YVR5cGVzIGluIGNhc2Ugd2UgbmVlZCB0byBtb2RpZnkgaXQgZm9yIGNvbnZlcnNpb25cblx0XHRkYXRhVHlwZXMgPSBzLmRhdGFUeXBlcy5zbGljZSgpO1xuXG5cdC8vIENyZWF0ZSBjb252ZXJ0ZXJzIG1hcCB3aXRoIGxvd2VyY2FzZWQga2V5c1xuXHRpZiAoIGRhdGFUeXBlc1sgMSBdICkge1xuXHRcdGZvciAoIGNvbnYgaW4gcy5jb252ZXJ0ZXJzICkge1xuXHRcdFx0Y29udmVydGVyc1sgY29udi50b0xvd2VyQ2FzZSgpIF0gPSBzLmNvbnZlcnRlcnNbIGNvbnYgXTtcblx0XHR9XG5cdH1cblxuXHRjdXJyZW50ID0gZGF0YVR5cGVzLnNoaWZ0KCk7XG5cblx0Ly8gQ29udmVydCB0byBlYWNoIHNlcXVlbnRpYWwgZGF0YVR5cGVcblx0d2hpbGUgKCBjdXJyZW50ICkge1xuXG5cdFx0aWYgKCBzLnJlc3BvbnNlRmllbGRzWyBjdXJyZW50IF0gKSB7XG5cdFx0XHRqcVhIUlsgcy5yZXNwb25zZUZpZWxkc1sgY3VycmVudCBdIF0gPSByZXNwb25zZTtcblx0XHR9XG5cblx0XHQvLyBBcHBseSB0aGUgZGF0YUZpbHRlciBpZiBwcm92aWRlZFxuXHRcdGlmICggIXByZXYgJiYgaXNTdWNjZXNzICYmIHMuZGF0YUZpbHRlciApIHtcblx0XHRcdHJlc3BvbnNlID0gcy5kYXRhRmlsdGVyKCByZXNwb25zZSwgcy5kYXRhVHlwZSApO1xuXHRcdH1cblxuXHRcdHByZXYgPSBjdXJyZW50O1xuXHRcdGN1cnJlbnQgPSBkYXRhVHlwZXMuc2hpZnQoKTtcblxuXHRcdGlmICggY3VycmVudCApIHtcblxuXHRcdFx0Ly8gVGhlcmUncyBvbmx5IHdvcmsgdG8gZG8gaWYgY3VycmVudCBkYXRhVHlwZSBpcyBub24tYXV0b1xuXHRcdFx0aWYgKCBjdXJyZW50ID09PSBcIipcIiApIHtcblxuXHRcdFx0XHRjdXJyZW50ID0gcHJldjtcblxuXHRcdFx0Ly8gQ29udmVydCByZXNwb25zZSBpZiBwcmV2IGRhdGFUeXBlIGlzIG5vbi1hdXRvIGFuZCBkaWZmZXJzIGZyb20gY3VycmVudFxuXHRcdFx0fSBlbHNlIGlmICggcHJldiAhPT0gXCIqXCIgJiYgcHJldiAhPT0gY3VycmVudCApIHtcblxuXHRcdFx0XHQvLyBTZWVrIGEgZGlyZWN0IGNvbnZlcnRlclxuXHRcdFx0XHRjb252ID0gY29udmVydGVyc1sgcHJldiArIFwiIFwiICsgY3VycmVudCBdIHx8IGNvbnZlcnRlcnNbIFwiKiBcIiArIGN1cnJlbnQgXTtcblxuXHRcdFx0XHQvLyBJZiBub25lIGZvdW5kLCBzZWVrIGEgcGFpclxuXHRcdFx0XHRpZiAoICFjb252ICkge1xuXHRcdFx0XHRcdGZvciAoIGNvbnYyIGluIGNvbnZlcnRlcnMgKSB7XG5cblx0XHRcdFx0XHRcdC8vIElmIGNvbnYyIG91dHB1dHMgY3VycmVudFxuXHRcdFx0XHRcdFx0dG1wID0gY29udjIuc3BsaXQoIFwiIFwiICk7XG5cdFx0XHRcdFx0XHRpZiAoIHRtcFsgMSBdID09PSBjdXJyZW50ICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIElmIHByZXYgY2FuIGJlIGNvbnZlcnRlZCB0byBhY2NlcHRlZCBpbnB1dFxuXHRcdFx0XHRcdFx0XHRjb252ID0gY29udmVydGVyc1sgcHJldiArIFwiIFwiICsgdG1wWyAwIF0gXSB8fFxuXHRcdFx0XHRcdFx0XHRcdGNvbnZlcnRlcnNbIFwiKiBcIiArIHRtcFsgMCBdIF07XG5cdFx0XHRcdFx0XHRcdGlmICggY29udiApIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIENvbmRlbnNlIGVxdWl2YWxlbmNlIGNvbnZlcnRlcnNcblx0XHRcdFx0XHRcdFx0XHRpZiAoIGNvbnYgPT09IHRydWUgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRjb252ID0gY29udmVydGVyc1sgY29udjIgXTtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIE90aGVyd2lzZSwgaW5zZXJ0IHRoZSBpbnRlcm1lZGlhdGUgZGF0YVR5cGVcblx0XHRcdFx0XHRcdFx0XHR9IGVsc2UgaWYgKCBjb252ZXJ0ZXJzWyBjb252MiBdICE9PSB0cnVlICkge1xuXHRcdFx0XHRcdFx0XHRcdFx0Y3VycmVudCA9IHRtcFsgMCBdO1xuXHRcdFx0XHRcdFx0XHRcdFx0ZGF0YVR5cGVzLnVuc2hpZnQoIHRtcFsgMSBdICk7XG5cdFx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQXBwbHkgY29udmVydGVyIChpZiBub3QgYW4gZXF1aXZhbGVuY2UpXG5cdFx0XHRcdGlmICggY29udiAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdC8vIFVubGVzcyBlcnJvcnMgYXJlIGFsbG93ZWQgdG8gYnViYmxlLCBjYXRjaCBhbmQgcmV0dXJuIHRoZW1cblx0XHRcdFx0XHRpZiAoIGNvbnYgJiYgcy50aHJvd3MgKSB7XG5cdFx0XHRcdFx0XHRyZXNwb25zZSA9IGNvbnYoIHJlc3BvbnNlICk7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRyeSB7XG5cdFx0XHRcdFx0XHRcdHJlc3BvbnNlID0gY29udiggcmVzcG9uc2UgKTtcblx0XHRcdFx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdFx0XHRcdHN0YXRlOiBcInBhcnNlcmVycm9yXCIsXG5cdFx0XHRcdFx0XHRcdFx0ZXJyb3I6IGNvbnYgPyBlIDogXCJObyBjb252ZXJzaW9uIGZyb20gXCIgKyBwcmV2ICsgXCIgdG8gXCIgKyBjdXJyZW50XG5cdFx0XHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHsgc3RhdGU6IFwic3VjY2Vzc1wiLCBkYXRhOiByZXNwb25zZSB9O1xufVxuXG5qUXVlcnkuZXh0ZW5kKCB7XG5cblx0Ly8gQ291bnRlciBmb3IgaG9sZGluZyB0aGUgbnVtYmVyIG9mIGFjdGl2ZSBxdWVyaWVzXG5cdGFjdGl2ZTogMCxcblxuXHQvLyBMYXN0LU1vZGlmaWVkIGhlYWRlciBjYWNoZSBmb3IgbmV4dCByZXF1ZXN0XG5cdGxhc3RNb2RpZmllZDoge30sXG5cdGV0YWc6IHt9LFxuXG5cdGFqYXhTZXR0aW5nczoge1xuXHRcdHVybDogbG9jYXRpb24uaHJlZixcblx0XHR0eXBlOiBcIkdFVFwiLFxuXHRcdGlzTG9jYWw6IHJsb2NhbFByb3RvY29sLnRlc3QoIGxvY2F0aW9uLnByb3RvY29sICksXG5cdFx0Z2xvYmFsOiB0cnVlLFxuXHRcdHByb2Nlc3NEYXRhOiB0cnVlLFxuXHRcdGFzeW5jOiB0cnVlLFxuXHRcdGNvbnRlbnRUeXBlOiBcImFwcGxpY2F0aW9uL3gtd3d3LWZvcm0tdXJsZW5jb2RlZDsgY2hhcnNldD1VVEYtOFwiLFxuXG5cdFx0Lypcblx0XHR0aW1lb3V0OiAwLFxuXHRcdGRhdGE6IG51bGwsXG5cdFx0ZGF0YVR5cGU6IG51bGwsXG5cdFx0dXNlcm5hbWU6IG51bGwsXG5cdFx0cGFzc3dvcmQ6IG51bGwsXG5cdFx0Y2FjaGU6IG51bGwsXG5cdFx0dGhyb3dzOiBmYWxzZSxcblx0XHR0cmFkaXRpb25hbDogZmFsc2UsXG5cdFx0aGVhZGVyczoge30sXG5cdFx0Ki9cblxuXHRcdGFjY2VwdHM6IHtcblx0XHRcdFwiKlwiOiBhbGxUeXBlcyxcblx0XHRcdHRleHQ6IFwidGV4dC9wbGFpblwiLFxuXHRcdFx0aHRtbDogXCJ0ZXh0L2h0bWxcIixcblx0XHRcdHhtbDogXCJhcHBsaWNhdGlvbi94bWwsIHRleHQveG1sXCIsXG5cdFx0XHRqc29uOiBcImFwcGxpY2F0aW9uL2pzb24sIHRleHQvamF2YXNjcmlwdFwiXG5cdFx0fSxcblxuXHRcdGNvbnRlbnRzOiB7XG5cdFx0XHR4bWw6IC9cXGJ4bWxcXGIvLFxuXHRcdFx0aHRtbDogL1xcYmh0bWwvLFxuXHRcdFx0anNvbjogL1xcYmpzb25cXGIvXG5cdFx0fSxcblxuXHRcdHJlc3BvbnNlRmllbGRzOiB7XG5cdFx0XHR4bWw6IFwicmVzcG9uc2VYTUxcIixcblx0XHRcdHRleHQ6IFwicmVzcG9uc2VUZXh0XCIsXG5cdFx0XHRqc29uOiBcInJlc3BvbnNlSlNPTlwiXG5cdFx0fSxcblxuXHRcdC8vIERhdGEgY29udmVydGVyc1xuXHRcdC8vIEtleXMgc2VwYXJhdGUgc291cmNlIChvciBjYXRjaGFsbCBcIipcIikgYW5kIGRlc3RpbmF0aW9uIHR5cGVzIHdpdGggYSBzaW5nbGUgc3BhY2Vcblx0XHRjb252ZXJ0ZXJzOiB7XG5cblx0XHRcdC8vIENvbnZlcnQgYW55dGhpbmcgdG8gdGV4dFxuXHRcdFx0XCIqIHRleHRcIjogU3RyaW5nLFxuXG5cdFx0XHQvLyBUZXh0IHRvIGh0bWwgKHRydWUgPSBubyB0cmFuc2Zvcm1hdGlvbilcblx0XHRcdFwidGV4dCBodG1sXCI6IHRydWUsXG5cblx0XHRcdC8vIEV2YWx1YXRlIHRleHQgYXMgYSBqc29uIGV4cHJlc3Npb25cblx0XHRcdFwidGV4dCBqc29uXCI6IEpTT04ucGFyc2UsXG5cblx0XHRcdC8vIFBhcnNlIHRleHQgYXMgeG1sXG5cdFx0XHRcInRleHQgeG1sXCI6IGpRdWVyeS5wYXJzZVhNTFxuXHRcdH0sXG5cblx0XHQvLyBGb3Igb3B0aW9ucyB0aGF0IHNob3VsZG4ndCBiZSBkZWVwIGV4dGVuZGVkOlxuXHRcdC8vIHlvdSBjYW4gYWRkIHlvdXIgb3duIGN1c3RvbSBvcHRpb25zIGhlcmUgaWZcblx0XHQvLyBhbmQgd2hlbiB5b3UgY3JlYXRlIG9uZSB0aGF0IHNob3VsZG4ndCBiZVxuXHRcdC8vIGRlZXAgZXh0ZW5kZWQgKHNlZSBhamF4RXh0ZW5kKVxuXHRcdGZsYXRPcHRpb25zOiB7XG5cdFx0XHR1cmw6IHRydWUsXG5cdFx0XHRjb250ZXh0OiB0cnVlXG5cdFx0fVxuXHR9LFxuXG5cdC8vIENyZWF0ZXMgYSBmdWxsIGZsZWRnZWQgc2V0dGluZ3Mgb2JqZWN0IGludG8gdGFyZ2V0XG5cdC8vIHdpdGggYm90aCBhamF4U2V0dGluZ3MgYW5kIHNldHRpbmdzIGZpZWxkcy5cblx0Ly8gSWYgdGFyZ2V0IGlzIG9taXR0ZWQsIHdyaXRlcyBpbnRvIGFqYXhTZXR0aW5ncy5cblx0YWpheFNldHVwOiBmdW5jdGlvbiggdGFyZ2V0LCBzZXR0aW5ncyApIHtcblx0XHRyZXR1cm4gc2V0dGluZ3MgP1xuXG5cdFx0XHQvLyBCdWlsZGluZyBhIHNldHRpbmdzIG9iamVjdFxuXHRcdFx0YWpheEV4dGVuZCggYWpheEV4dGVuZCggdGFyZ2V0LCBqUXVlcnkuYWpheFNldHRpbmdzICksIHNldHRpbmdzICkgOlxuXG5cdFx0XHQvLyBFeHRlbmRpbmcgYWpheFNldHRpbmdzXG5cdFx0XHRhamF4RXh0ZW5kKCBqUXVlcnkuYWpheFNldHRpbmdzLCB0YXJnZXQgKTtcblx0fSxcblxuXHRhamF4UHJlZmlsdGVyOiBhZGRUb1ByZWZpbHRlcnNPclRyYW5zcG9ydHMoIHByZWZpbHRlcnMgKSxcblx0YWpheFRyYW5zcG9ydDogYWRkVG9QcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCB0cmFuc3BvcnRzICksXG5cblx0Ly8gTWFpbiBtZXRob2Rcblx0YWpheDogZnVuY3Rpb24oIHVybCwgb3B0aW9ucyApIHtcblxuXHRcdC8vIElmIHVybCBpcyBhbiBvYmplY3QsIHNpbXVsYXRlIHByZS0xLjUgc2lnbmF0dXJlXG5cdFx0aWYgKCB0eXBlb2YgdXJsID09PSBcIm9iamVjdFwiICkge1xuXHRcdFx0b3B0aW9ucyA9IHVybDtcblx0XHRcdHVybCA9IHVuZGVmaW5lZDtcblx0XHR9XG5cblx0XHQvLyBGb3JjZSBvcHRpb25zIHRvIGJlIGFuIG9iamVjdFxuXHRcdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuXG5cdFx0dmFyIHRyYW5zcG9ydCxcblxuXHRcdFx0Ly8gVVJMIHdpdGhvdXQgYW50aS1jYWNoZSBwYXJhbVxuXHRcdFx0Y2FjaGVVUkwsXG5cblx0XHRcdC8vIFJlc3BvbnNlIGhlYWRlcnNcblx0XHRcdHJlc3BvbnNlSGVhZGVyc1N0cmluZyxcblx0XHRcdHJlc3BvbnNlSGVhZGVycyxcblxuXHRcdFx0Ly8gdGltZW91dCBoYW5kbGVcblx0XHRcdHRpbWVvdXRUaW1lcixcblxuXHRcdFx0Ly8gVXJsIGNsZWFudXAgdmFyXG5cdFx0XHR1cmxBbmNob3IsXG5cblx0XHRcdC8vIFJlcXVlc3Qgc3RhdGUgKGJlY29tZXMgZmFsc2UgdXBvbiBzZW5kIGFuZCB0cnVlIHVwb24gY29tcGxldGlvbilcblx0XHRcdGNvbXBsZXRlZCxcblxuXHRcdFx0Ly8gVG8ga25vdyBpZiBnbG9iYWwgZXZlbnRzIGFyZSB0byBiZSBkaXNwYXRjaGVkXG5cdFx0XHRmaXJlR2xvYmFscyxcblxuXHRcdFx0Ly8gTG9vcCB2YXJpYWJsZVxuXHRcdFx0aSxcblxuXHRcdFx0Ly8gdW5jYWNoZWQgcGFydCBvZiB0aGUgdXJsXG5cdFx0XHR1bmNhY2hlZCxcblxuXHRcdFx0Ly8gQ3JlYXRlIHRoZSBmaW5hbCBvcHRpb25zIG9iamVjdFxuXHRcdFx0cyA9IGpRdWVyeS5hamF4U2V0dXAoIHt9LCBvcHRpb25zICksXG5cblx0XHRcdC8vIENhbGxiYWNrcyBjb250ZXh0XG5cdFx0XHRjYWxsYmFja0NvbnRleHQgPSBzLmNvbnRleHQgfHwgcyxcblxuXHRcdFx0Ly8gQ29udGV4dCBmb3IgZ2xvYmFsIGV2ZW50cyBpcyBjYWxsYmFja0NvbnRleHQgaWYgaXQgaXMgYSBET00gbm9kZSBvciBqUXVlcnkgY29sbGVjdGlvblxuXHRcdFx0Z2xvYmFsRXZlbnRDb250ZXh0ID0gcy5jb250ZXh0ICYmXG5cdFx0XHRcdCggY2FsbGJhY2tDb250ZXh0Lm5vZGVUeXBlIHx8IGNhbGxiYWNrQ29udGV4dC5qcXVlcnkgKSA/XG5cdFx0XHRcdFx0alF1ZXJ5KCBjYWxsYmFja0NvbnRleHQgKSA6XG5cdFx0XHRcdFx0alF1ZXJ5LmV2ZW50LFxuXG5cdFx0XHQvLyBEZWZlcnJlZHNcblx0XHRcdGRlZmVycmVkID0galF1ZXJ5LkRlZmVycmVkKCksXG5cdFx0XHRjb21wbGV0ZURlZmVycmVkID0galF1ZXJ5LkNhbGxiYWNrcyggXCJvbmNlIG1lbW9yeVwiICksXG5cblx0XHRcdC8vIFN0YXR1cy1kZXBlbmRlbnQgY2FsbGJhY2tzXG5cdFx0XHRzdGF0dXNDb2RlID0gcy5zdGF0dXNDb2RlIHx8IHt9LFxuXG5cdFx0XHQvLyBIZWFkZXJzICh0aGV5IGFyZSBzZW50IGFsbCBhdCBvbmNlKVxuXHRcdFx0cmVxdWVzdEhlYWRlcnMgPSB7fSxcblx0XHRcdHJlcXVlc3RIZWFkZXJzTmFtZXMgPSB7fSxcblxuXHRcdFx0Ly8gRGVmYXVsdCBhYm9ydCBtZXNzYWdlXG5cdFx0XHRzdHJBYm9ydCA9IFwiY2FuY2VsZWRcIixcblxuXHRcdFx0Ly8gRmFrZSB4aHJcblx0XHRcdGpxWEhSID0ge1xuXHRcdFx0XHRyZWFkeVN0YXRlOiAwLFxuXG5cdFx0XHRcdC8vIEJ1aWxkcyBoZWFkZXJzIGhhc2h0YWJsZSBpZiBuZWVkZWRcblx0XHRcdFx0Z2V0UmVzcG9uc2VIZWFkZXI6IGZ1bmN0aW9uKCBrZXkgKSB7XG5cdFx0XHRcdFx0dmFyIG1hdGNoO1xuXHRcdFx0XHRcdGlmICggY29tcGxldGVkICkge1xuXHRcdFx0XHRcdFx0aWYgKCAhcmVzcG9uc2VIZWFkZXJzICkge1xuXHRcdFx0XHRcdFx0XHRyZXNwb25zZUhlYWRlcnMgPSB7fTtcblx0XHRcdFx0XHRcdFx0d2hpbGUgKCAoIG1hdGNoID0gcmhlYWRlcnMuZXhlYyggcmVzcG9uc2VIZWFkZXJzU3RyaW5nICkgKSApIHtcblx0XHRcdFx0XHRcdFx0XHRyZXNwb25zZUhlYWRlcnNbIG1hdGNoWyAxIF0udG9Mb3dlckNhc2UoKSArIFwiIFwiIF0gPVxuXHRcdFx0XHRcdFx0XHRcdFx0KCByZXNwb25zZUhlYWRlcnNbIG1hdGNoWyAxIF0udG9Mb3dlckNhc2UoKSArIFwiIFwiIF0gfHwgW10gKVxuXHRcdFx0XHRcdFx0XHRcdFx0XHQuY29uY2F0KCBtYXRjaFsgMiBdICk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdG1hdGNoID0gcmVzcG9uc2VIZWFkZXJzWyBrZXkudG9Mb3dlckNhc2UoKSArIFwiIFwiIF07XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiBtYXRjaCA9PSBudWxsID8gbnVsbCA6IG1hdGNoLmpvaW4oIFwiLCBcIiApO1xuXHRcdFx0XHR9LFxuXG5cdFx0XHRcdC8vIFJhdyBzdHJpbmdcblx0XHRcdFx0Z2V0QWxsUmVzcG9uc2VIZWFkZXJzOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRyZXR1cm4gY29tcGxldGVkID8gcmVzcG9uc2VIZWFkZXJzU3RyaW5nIDogbnVsbDtcblx0XHRcdFx0fSxcblxuXHRcdFx0XHQvLyBDYWNoZXMgdGhlIGhlYWRlclxuXHRcdFx0XHRzZXRSZXF1ZXN0SGVhZGVyOiBmdW5jdGlvbiggbmFtZSwgdmFsdWUgKSB7XG5cdFx0XHRcdFx0aWYgKCBjb21wbGV0ZWQgPT0gbnVsbCApIHtcblx0XHRcdFx0XHRcdG5hbWUgPSByZXF1ZXN0SGVhZGVyc05hbWVzWyBuYW1lLnRvTG93ZXJDYXNlKCkgXSA9XG5cdFx0XHRcdFx0XHRcdHJlcXVlc3RIZWFkZXJzTmFtZXNbIG5hbWUudG9Mb3dlckNhc2UoKSBdIHx8IG5hbWU7XG5cdFx0XHRcdFx0XHRyZXF1ZXN0SGVhZGVyc1sgbmFtZSBdID0gdmFsdWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0XHR9LFxuXG5cdFx0XHRcdC8vIE92ZXJyaWRlcyByZXNwb25zZSBjb250ZW50LXR5cGUgaGVhZGVyXG5cdFx0XHRcdG92ZXJyaWRlTWltZVR5cGU6IGZ1bmN0aW9uKCB0eXBlICkge1xuXHRcdFx0XHRcdGlmICggY29tcGxldGVkID09IG51bGwgKSB7XG5cdFx0XHRcdFx0XHRzLm1pbWVUeXBlID0gdHlwZTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHRcdH0sXG5cblx0XHRcdFx0Ly8gU3RhdHVzLWRlcGVuZGVudCBjYWxsYmFja3Ncblx0XHRcdFx0c3RhdHVzQ29kZTogZnVuY3Rpb24oIG1hcCApIHtcblx0XHRcdFx0XHR2YXIgY29kZTtcblx0XHRcdFx0XHRpZiAoIG1hcCApIHtcblx0XHRcdFx0XHRcdGlmICggY29tcGxldGVkICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIEV4ZWN1dGUgdGhlIGFwcHJvcHJpYXRlIGNhbGxiYWNrc1xuXHRcdFx0XHRcdFx0XHRqcVhIUi5hbHdheXMoIG1hcFsganFYSFIuc3RhdHVzIF0gKTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gTGF6eS1hZGQgdGhlIG5ldyBjYWxsYmFja3MgaW4gYSB3YXkgdGhhdCBwcmVzZXJ2ZXMgb2xkIG9uZXNcblx0XHRcdFx0XHRcdFx0Zm9yICggY29kZSBpbiBtYXAgKSB7XG5cdFx0XHRcdFx0XHRcdFx0c3RhdHVzQ29kZVsgY29kZSBdID0gWyBzdGF0dXNDb2RlWyBjb2RlIF0sIG1hcFsgY29kZSBdIF07XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0XHRcdH0sXG5cblx0XHRcdFx0Ly8gQ2FuY2VsIHRoZSByZXF1ZXN0XG5cdFx0XHRcdGFib3J0OiBmdW5jdGlvbiggc3RhdHVzVGV4dCApIHtcblx0XHRcdFx0XHR2YXIgZmluYWxUZXh0ID0gc3RhdHVzVGV4dCB8fCBzdHJBYm9ydDtcblx0XHRcdFx0XHRpZiAoIHRyYW5zcG9ydCApIHtcblx0XHRcdFx0XHRcdHRyYW5zcG9ydC5hYm9ydCggZmluYWxUZXh0ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGRvbmUoIDAsIGZpbmFsVGV4dCApO1xuXHRcdFx0XHRcdHJldHVybiB0aGlzO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXG5cdFx0Ly8gQXR0YWNoIGRlZmVycmVkc1xuXHRcdGRlZmVycmVkLnByb21pc2UoIGpxWEhSICk7XG5cblx0XHQvLyBBZGQgcHJvdG9jb2wgaWYgbm90IHByb3ZpZGVkIChwcmVmaWx0ZXJzIG1pZ2h0IGV4cGVjdCBpdClcblx0XHQvLyBIYW5kbGUgZmFsc3kgdXJsIGluIHRoZSBzZXR0aW5ncyBvYmplY3QgKCMxMDA5MzogY29uc2lzdGVuY3kgd2l0aCBvbGQgc2lnbmF0dXJlKVxuXHRcdC8vIFdlIGFsc28gdXNlIHRoZSB1cmwgcGFyYW1ldGVyIGlmIGF2YWlsYWJsZVxuXHRcdHMudXJsID0gKCAoIHVybCB8fCBzLnVybCB8fCBsb2NhdGlvbi5ocmVmICkgKyBcIlwiIClcblx0XHRcdC5yZXBsYWNlKCBycHJvdG9jb2wsIGxvY2F0aW9uLnByb3RvY29sICsgXCIvL1wiICk7XG5cblx0XHQvLyBBbGlhcyBtZXRob2Qgb3B0aW9uIHRvIHR5cGUgYXMgcGVyIHRpY2tldCAjMTIwMDRcblx0XHRzLnR5cGUgPSBvcHRpb25zLm1ldGhvZCB8fCBvcHRpb25zLnR5cGUgfHwgcy5tZXRob2QgfHwgcy50eXBlO1xuXG5cdFx0Ly8gRXh0cmFjdCBkYXRhVHlwZXMgbGlzdFxuXHRcdHMuZGF0YVR5cGVzID0gKCBzLmRhdGFUeXBlIHx8IFwiKlwiICkudG9Mb3dlckNhc2UoKS5tYXRjaCggcm5vdGh0bWx3aGl0ZSApIHx8IFsgXCJcIiBdO1xuXG5cdFx0Ly8gQSBjcm9zcy1kb21haW4gcmVxdWVzdCBpcyBpbiBvcmRlciB3aGVuIHRoZSBvcmlnaW4gZG9lc24ndCBtYXRjaCB0aGUgY3VycmVudCBvcmlnaW4uXG5cdFx0aWYgKCBzLmNyb3NzRG9tYWluID09IG51bGwgKSB7XG5cdFx0XHR1cmxBbmNob3IgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCBcImFcIiApO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRSA8PTggLSAxMSwgRWRnZSAxMiAtIDE1XG5cdFx0XHQvLyBJRSB0aHJvd3MgZXhjZXB0aW9uIG9uIGFjY2Vzc2luZyB0aGUgaHJlZiBwcm9wZXJ0eSBpZiB1cmwgaXMgbWFsZm9ybWVkLFxuXHRcdFx0Ly8gZS5nLiBodHRwOi8vZXhhbXBsZS5jb206ODB4L1xuXHRcdFx0dHJ5IHtcblx0XHRcdFx0dXJsQW5jaG9yLmhyZWYgPSBzLnVybDtcblxuXHRcdFx0XHQvLyBTdXBwb3J0OiBJRSA8PTggLSAxMSBvbmx5XG5cdFx0XHRcdC8vIEFuY2hvcidzIGhvc3QgcHJvcGVydHkgaXNuJ3QgY29ycmVjdGx5IHNldCB3aGVuIHMudXJsIGlzIHJlbGF0aXZlXG5cdFx0XHRcdHVybEFuY2hvci5ocmVmID0gdXJsQW5jaG9yLmhyZWY7XG5cdFx0XHRcdHMuY3Jvc3NEb21haW4gPSBvcmlnaW5BbmNob3IucHJvdG9jb2wgKyBcIi8vXCIgKyBvcmlnaW5BbmNob3IuaG9zdCAhPT1cblx0XHRcdFx0XHR1cmxBbmNob3IucHJvdG9jb2wgKyBcIi8vXCIgKyB1cmxBbmNob3IuaG9zdDtcblx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXG5cdFx0XHRcdC8vIElmIHRoZXJlIGlzIGFuIGVycm9yIHBhcnNpbmcgdGhlIFVSTCwgYXNzdW1lIGl0IGlzIGNyb3NzRG9tYWluLFxuXHRcdFx0XHQvLyBpdCBjYW4gYmUgcmVqZWN0ZWQgYnkgdGhlIHRyYW5zcG9ydCBpZiBpdCBpcyBpbnZhbGlkXG5cdFx0XHRcdHMuY3Jvc3NEb21haW4gPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIENvbnZlcnQgZGF0YSBpZiBub3QgYWxyZWFkeSBhIHN0cmluZ1xuXHRcdGlmICggcy5kYXRhICYmIHMucHJvY2Vzc0RhdGEgJiYgdHlwZW9mIHMuZGF0YSAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHMuZGF0YSA9IGpRdWVyeS5wYXJhbSggcy5kYXRhLCBzLnRyYWRpdGlvbmFsICk7XG5cdFx0fVxuXG5cdFx0Ly8gQXBwbHkgcHJlZmlsdGVyc1xuXHRcdGluc3BlY3RQcmVmaWx0ZXJzT3JUcmFuc3BvcnRzKCBwcmVmaWx0ZXJzLCBzLCBvcHRpb25zLCBqcVhIUiApO1xuXG5cdFx0Ly8gSWYgcmVxdWVzdCB3YXMgYWJvcnRlZCBpbnNpZGUgYSBwcmVmaWx0ZXIsIHN0b3AgdGhlcmVcblx0XHRpZiAoIGNvbXBsZXRlZCApIHtcblx0XHRcdHJldHVybiBqcVhIUjtcblx0XHR9XG5cblx0XHQvLyBXZSBjYW4gZmlyZSBnbG9iYWwgZXZlbnRzIGFzIG9mIG5vdyBpZiBhc2tlZCB0b1xuXHRcdC8vIERvbid0IGZpcmUgZXZlbnRzIGlmIGpRdWVyeS5ldmVudCBpcyB1bmRlZmluZWQgaW4gYW4gQU1ELXVzYWdlIHNjZW5hcmlvICgjMTUxMTgpXG5cdFx0ZmlyZUdsb2JhbHMgPSBqUXVlcnkuZXZlbnQgJiYgcy5nbG9iYWw7XG5cblx0XHQvLyBXYXRjaCBmb3IgYSBuZXcgc2V0IG9mIHJlcXVlc3RzXG5cdFx0aWYgKCBmaXJlR2xvYmFscyAmJiBqUXVlcnkuYWN0aXZlKysgPT09IDAgKSB7XG5cdFx0XHRqUXVlcnkuZXZlbnQudHJpZ2dlciggXCJhamF4U3RhcnRcIiApO1xuXHRcdH1cblxuXHRcdC8vIFVwcGVyY2FzZSB0aGUgdHlwZVxuXHRcdHMudHlwZSA9IHMudHlwZS50b1VwcGVyQ2FzZSgpO1xuXG5cdFx0Ly8gRGV0ZXJtaW5lIGlmIHJlcXVlc3QgaGFzIGNvbnRlbnRcblx0XHRzLmhhc0NvbnRlbnQgPSAhcm5vQ29udGVudC50ZXN0KCBzLnR5cGUgKTtcblxuXHRcdC8vIFNhdmUgdGhlIFVSTCBpbiBjYXNlIHdlJ3JlIHRveWluZyB3aXRoIHRoZSBJZi1Nb2RpZmllZC1TaW5jZVxuXHRcdC8vIGFuZC9vciBJZi1Ob25lLU1hdGNoIGhlYWRlciBsYXRlciBvblxuXHRcdC8vIFJlbW92ZSBoYXNoIHRvIHNpbXBsaWZ5IHVybCBtYW5pcHVsYXRpb25cblx0XHRjYWNoZVVSTCA9IHMudXJsLnJlcGxhY2UoIHJoYXNoLCBcIlwiICk7XG5cblx0XHQvLyBNb3JlIG9wdGlvbnMgaGFuZGxpbmcgZm9yIHJlcXVlc3RzIHdpdGggbm8gY29udGVudFxuXHRcdGlmICggIXMuaGFzQ29udGVudCApIHtcblxuXHRcdFx0Ly8gUmVtZW1iZXIgdGhlIGhhc2ggc28gd2UgY2FuIHB1dCBpdCBiYWNrXG5cdFx0XHR1bmNhY2hlZCA9IHMudXJsLnNsaWNlKCBjYWNoZVVSTC5sZW5ndGggKTtcblxuXHRcdFx0Ly8gSWYgZGF0YSBpcyBhdmFpbGFibGUgYW5kIHNob3VsZCBiZSBwcm9jZXNzZWQsIGFwcGVuZCBkYXRhIHRvIHVybFxuXHRcdFx0aWYgKCBzLmRhdGEgJiYgKCBzLnByb2Nlc3NEYXRhIHx8IHR5cGVvZiBzLmRhdGEgPT09IFwic3RyaW5nXCIgKSApIHtcblx0XHRcdFx0Y2FjaGVVUkwgKz0gKCBycXVlcnkudGVzdCggY2FjaGVVUkwgKSA/IFwiJlwiIDogXCI/XCIgKSArIHMuZGF0YTtcblxuXHRcdFx0XHQvLyAjOTY4MjogcmVtb3ZlIGRhdGEgc28gdGhhdCBpdCdzIG5vdCB1c2VkIGluIGFuIGV2ZW50dWFsIHJldHJ5XG5cdFx0XHRcdGRlbGV0ZSBzLmRhdGE7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFkZCBvciB1cGRhdGUgYW50aS1jYWNoZSBwYXJhbSBpZiBuZWVkZWRcblx0XHRcdGlmICggcy5jYWNoZSA9PT0gZmFsc2UgKSB7XG5cdFx0XHRcdGNhY2hlVVJMID0gY2FjaGVVUkwucmVwbGFjZSggcmFudGlDYWNoZSwgXCIkMVwiICk7XG5cdFx0XHRcdHVuY2FjaGVkID0gKCBycXVlcnkudGVzdCggY2FjaGVVUkwgKSA/IFwiJlwiIDogXCI/XCIgKSArIFwiXz1cIiArICggbm9uY2UrKyApICsgdW5jYWNoZWQ7XG5cdFx0XHR9XG5cblx0XHRcdC8vIFB1dCBoYXNoIGFuZCBhbnRpLWNhY2hlIG9uIHRoZSBVUkwgdGhhdCB3aWxsIGJlIHJlcXVlc3RlZCAoZ2gtMTczMilcblx0XHRcdHMudXJsID0gY2FjaGVVUkwgKyB1bmNhY2hlZDtcblxuXHRcdC8vIENoYW5nZSAnJTIwJyB0byAnKycgaWYgdGhpcyBpcyBlbmNvZGVkIGZvcm0gYm9keSBjb250ZW50IChnaC0yNjU4KVxuXHRcdH0gZWxzZSBpZiAoIHMuZGF0YSAmJiBzLnByb2Nlc3NEYXRhICYmXG5cdFx0XHQoIHMuY29udGVudFR5cGUgfHwgXCJcIiApLmluZGV4T2YoIFwiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkXCIgKSA9PT0gMCApIHtcblx0XHRcdHMuZGF0YSA9IHMuZGF0YS5yZXBsYWNlKCByMjAsIFwiK1wiICk7XG5cdFx0fVxuXG5cdFx0Ly8gU2V0IHRoZSBJZi1Nb2RpZmllZC1TaW5jZSBhbmQvb3IgSWYtTm9uZS1NYXRjaCBoZWFkZXIsIGlmIGluIGlmTW9kaWZpZWQgbW9kZS5cblx0XHRpZiAoIHMuaWZNb2RpZmllZCApIHtcblx0XHRcdGlmICggalF1ZXJ5Lmxhc3RNb2RpZmllZFsgY2FjaGVVUkwgXSApIHtcblx0XHRcdFx0anFYSFIuc2V0UmVxdWVzdEhlYWRlciggXCJJZi1Nb2RpZmllZC1TaW5jZVwiLCBqUXVlcnkubGFzdE1vZGlmaWVkWyBjYWNoZVVSTCBdICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIGpRdWVyeS5ldGFnWyBjYWNoZVVSTCBdICkge1xuXHRcdFx0XHRqcVhIUi5zZXRSZXF1ZXN0SGVhZGVyKCBcIklmLU5vbmUtTWF0Y2hcIiwgalF1ZXJ5LmV0YWdbIGNhY2hlVVJMIF0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBTZXQgdGhlIGNvcnJlY3QgaGVhZGVyLCBpZiBkYXRhIGlzIGJlaW5nIHNlbnRcblx0XHRpZiAoIHMuZGF0YSAmJiBzLmhhc0NvbnRlbnQgJiYgcy5jb250ZW50VHlwZSAhPT0gZmFsc2UgfHwgb3B0aW9ucy5jb250ZW50VHlwZSApIHtcblx0XHRcdGpxWEhSLnNldFJlcXVlc3RIZWFkZXIoIFwiQ29udGVudC1UeXBlXCIsIHMuY29udGVudFR5cGUgKTtcblx0XHR9XG5cblx0XHQvLyBTZXQgdGhlIEFjY2VwdHMgaGVhZGVyIGZvciB0aGUgc2VydmVyLCBkZXBlbmRpbmcgb24gdGhlIGRhdGFUeXBlXG5cdFx0anFYSFIuc2V0UmVxdWVzdEhlYWRlcihcblx0XHRcdFwiQWNjZXB0XCIsXG5cdFx0XHRzLmRhdGFUeXBlc1sgMCBdICYmIHMuYWNjZXB0c1sgcy5kYXRhVHlwZXNbIDAgXSBdID9cblx0XHRcdFx0cy5hY2NlcHRzWyBzLmRhdGFUeXBlc1sgMCBdIF0gK1xuXHRcdFx0XHRcdCggcy5kYXRhVHlwZXNbIDAgXSAhPT0gXCIqXCIgPyBcIiwgXCIgKyBhbGxUeXBlcyArIFwiOyBxPTAuMDFcIiA6IFwiXCIgKSA6XG5cdFx0XHRcdHMuYWNjZXB0c1sgXCIqXCIgXVxuXHRcdCk7XG5cblx0XHQvLyBDaGVjayBmb3IgaGVhZGVycyBvcHRpb25cblx0XHRmb3IgKCBpIGluIHMuaGVhZGVycyApIHtcblx0XHRcdGpxWEhSLnNldFJlcXVlc3RIZWFkZXIoIGksIHMuaGVhZGVyc1sgaSBdICk7XG5cdFx0fVxuXG5cdFx0Ly8gQWxsb3cgY3VzdG9tIGhlYWRlcnMvbWltZXR5cGVzIGFuZCBlYXJseSBhYm9ydFxuXHRcdGlmICggcy5iZWZvcmVTZW5kICYmXG5cdFx0XHQoIHMuYmVmb3JlU2VuZC5jYWxsKCBjYWxsYmFja0NvbnRleHQsIGpxWEhSLCBzICkgPT09IGZhbHNlIHx8IGNvbXBsZXRlZCApICkge1xuXG5cdFx0XHQvLyBBYm9ydCBpZiBub3QgZG9uZSBhbHJlYWR5IGFuZCByZXR1cm5cblx0XHRcdHJldHVybiBqcVhIUi5hYm9ydCgpO1xuXHRcdH1cblxuXHRcdC8vIEFib3J0aW5nIGlzIG5vIGxvbmdlciBhIGNhbmNlbGxhdGlvblxuXHRcdHN0ckFib3J0ID0gXCJhYm9ydFwiO1xuXG5cdFx0Ly8gSW5zdGFsbCBjYWxsYmFja3Mgb24gZGVmZXJyZWRzXG5cdFx0Y29tcGxldGVEZWZlcnJlZC5hZGQoIHMuY29tcGxldGUgKTtcblx0XHRqcVhIUi5kb25lKCBzLnN1Y2Nlc3MgKTtcblx0XHRqcVhIUi5mYWlsKCBzLmVycm9yICk7XG5cblx0XHQvLyBHZXQgdHJhbnNwb3J0XG5cdFx0dHJhbnNwb3J0ID0gaW5zcGVjdFByZWZpbHRlcnNPclRyYW5zcG9ydHMoIHRyYW5zcG9ydHMsIHMsIG9wdGlvbnMsIGpxWEhSICk7XG5cblx0XHQvLyBJZiBubyB0cmFuc3BvcnQsIHdlIGF1dG8tYWJvcnRcblx0XHRpZiAoICF0cmFuc3BvcnQgKSB7XG5cdFx0XHRkb25lKCAtMSwgXCJObyBUcmFuc3BvcnRcIiApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRqcVhIUi5yZWFkeVN0YXRlID0gMTtcblxuXHRcdFx0Ly8gU2VuZCBnbG9iYWwgZXZlbnRcblx0XHRcdGlmICggZmlyZUdsb2JhbHMgKSB7XG5cdFx0XHRcdGdsb2JhbEV2ZW50Q29udGV4dC50cmlnZ2VyKCBcImFqYXhTZW5kXCIsIFsganFYSFIsIHMgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBJZiByZXF1ZXN0IHdhcyBhYm9ydGVkIGluc2lkZSBhamF4U2VuZCwgc3RvcCB0aGVyZVxuXHRcdFx0aWYgKCBjb21wbGV0ZWQgKSB7XG5cdFx0XHRcdHJldHVybiBqcVhIUjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gVGltZW91dFxuXHRcdFx0aWYgKCBzLmFzeW5jICYmIHMudGltZW91dCA+IDAgKSB7XG5cdFx0XHRcdHRpbWVvdXRUaW1lciA9IHdpbmRvdy5zZXRUaW1lb3V0KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRqcVhIUi5hYm9ydCggXCJ0aW1lb3V0XCIgKTtcblx0XHRcdFx0fSwgcy50aW1lb3V0ICk7XG5cdFx0XHR9XG5cblx0XHRcdHRyeSB7XG5cdFx0XHRcdGNvbXBsZXRlZCA9IGZhbHNlO1xuXHRcdFx0XHR0cmFuc3BvcnQuc2VuZCggcmVxdWVzdEhlYWRlcnMsIGRvbmUgKTtcblx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXG5cdFx0XHRcdC8vIFJldGhyb3cgcG9zdC1jb21wbGV0aW9uIGV4Y2VwdGlvbnNcblx0XHRcdFx0aWYgKCBjb21wbGV0ZWQgKSB7XG5cdFx0XHRcdFx0dGhyb3cgZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFByb3BhZ2F0ZSBvdGhlcnMgYXMgcmVzdWx0c1xuXHRcdFx0XHRkb25lKCAtMSwgZSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIENhbGxiYWNrIGZvciB3aGVuIGV2ZXJ5dGhpbmcgaXMgZG9uZVxuXHRcdGZ1bmN0aW9uIGRvbmUoIHN0YXR1cywgbmF0aXZlU3RhdHVzVGV4dCwgcmVzcG9uc2VzLCBoZWFkZXJzICkge1xuXHRcdFx0dmFyIGlzU3VjY2Vzcywgc3VjY2VzcywgZXJyb3IsIHJlc3BvbnNlLCBtb2RpZmllZCxcblx0XHRcdFx0c3RhdHVzVGV4dCA9IG5hdGl2ZVN0YXR1c1RleHQ7XG5cblx0XHRcdC8vIElnbm9yZSByZXBlYXQgaW52b2NhdGlvbnNcblx0XHRcdGlmICggY29tcGxldGVkICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGNvbXBsZXRlZCA9IHRydWU7XG5cblx0XHRcdC8vIENsZWFyIHRpbWVvdXQgaWYgaXQgZXhpc3RzXG5cdFx0XHRpZiAoIHRpbWVvdXRUaW1lciApIHtcblx0XHRcdFx0d2luZG93LmNsZWFyVGltZW91dCggdGltZW91dFRpbWVyICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIERlcmVmZXJlbmNlIHRyYW5zcG9ydCBmb3IgZWFybHkgZ2FyYmFnZSBjb2xsZWN0aW9uXG5cdFx0XHQvLyAobm8gbWF0dGVyIGhvdyBsb25nIHRoZSBqcVhIUiBvYmplY3Qgd2lsbCBiZSB1c2VkKVxuXHRcdFx0dHJhbnNwb3J0ID0gdW5kZWZpbmVkO1xuXG5cdFx0XHQvLyBDYWNoZSByZXNwb25zZSBoZWFkZXJzXG5cdFx0XHRyZXNwb25zZUhlYWRlcnNTdHJpbmcgPSBoZWFkZXJzIHx8IFwiXCI7XG5cblx0XHRcdC8vIFNldCByZWFkeVN0YXRlXG5cdFx0XHRqcVhIUi5yZWFkeVN0YXRlID0gc3RhdHVzID4gMCA/IDQgOiAwO1xuXG5cdFx0XHQvLyBEZXRlcm1pbmUgaWYgc3VjY2Vzc2Z1bFxuXHRcdFx0aXNTdWNjZXNzID0gc3RhdHVzID49IDIwMCAmJiBzdGF0dXMgPCAzMDAgfHwgc3RhdHVzID09PSAzMDQ7XG5cblx0XHRcdC8vIEdldCByZXNwb25zZSBkYXRhXG5cdFx0XHRpZiAoIHJlc3BvbnNlcyApIHtcblx0XHRcdFx0cmVzcG9uc2UgPSBhamF4SGFuZGxlUmVzcG9uc2VzKCBzLCBqcVhIUiwgcmVzcG9uc2VzICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIENvbnZlcnQgbm8gbWF0dGVyIHdoYXQgKHRoYXQgd2F5IHJlc3BvbnNlWFhYIGZpZWxkcyBhcmUgYWx3YXlzIHNldClcblx0XHRcdHJlc3BvbnNlID0gYWpheENvbnZlcnQoIHMsIHJlc3BvbnNlLCBqcVhIUiwgaXNTdWNjZXNzICk7XG5cblx0XHRcdC8vIElmIHN1Y2Nlc3NmdWwsIGhhbmRsZSB0eXBlIGNoYWluaW5nXG5cdFx0XHRpZiAoIGlzU3VjY2VzcyApIHtcblxuXHRcdFx0XHQvLyBTZXQgdGhlIElmLU1vZGlmaWVkLVNpbmNlIGFuZC9vciBJZi1Ob25lLU1hdGNoIGhlYWRlciwgaWYgaW4gaWZNb2RpZmllZCBtb2RlLlxuXHRcdFx0XHRpZiAoIHMuaWZNb2RpZmllZCApIHtcblx0XHRcdFx0XHRtb2RpZmllZCA9IGpxWEhSLmdldFJlc3BvbnNlSGVhZGVyKCBcIkxhc3QtTW9kaWZpZWRcIiApO1xuXHRcdFx0XHRcdGlmICggbW9kaWZpZWQgKSB7XG5cdFx0XHRcdFx0XHRqUXVlcnkubGFzdE1vZGlmaWVkWyBjYWNoZVVSTCBdID0gbW9kaWZpZWQ7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdG1vZGlmaWVkID0ganFYSFIuZ2V0UmVzcG9uc2VIZWFkZXIoIFwiZXRhZ1wiICk7XG5cdFx0XHRcdFx0aWYgKCBtb2RpZmllZCApIHtcblx0XHRcdFx0XHRcdGpRdWVyeS5ldGFnWyBjYWNoZVVSTCBdID0gbW9kaWZpZWQ7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gaWYgbm8gY29udGVudFxuXHRcdFx0XHRpZiAoIHN0YXR1cyA9PT0gMjA0IHx8IHMudHlwZSA9PT0gXCJIRUFEXCIgKSB7XG5cdFx0XHRcdFx0c3RhdHVzVGV4dCA9IFwibm9jb250ZW50XCI7XG5cblx0XHRcdFx0Ly8gaWYgbm90IG1vZGlmaWVkXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHN0YXR1cyA9PT0gMzA0ICkge1xuXHRcdFx0XHRcdHN0YXR1c1RleHQgPSBcIm5vdG1vZGlmaWVkXCI7XG5cblx0XHRcdFx0Ly8gSWYgd2UgaGF2ZSBkYXRhLCBsZXQncyBjb252ZXJ0IGl0XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0c3RhdHVzVGV4dCA9IHJlc3BvbnNlLnN0YXRlO1xuXHRcdFx0XHRcdHN1Y2Nlc3MgPSByZXNwb25zZS5kYXRhO1xuXHRcdFx0XHRcdGVycm9yID0gcmVzcG9uc2UuZXJyb3I7XG5cdFx0XHRcdFx0aXNTdWNjZXNzID0gIWVycm9yO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIEV4dHJhY3QgZXJyb3IgZnJvbSBzdGF0dXNUZXh0IGFuZCBub3JtYWxpemUgZm9yIG5vbi1hYm9ydHNcblx0XHRcdFx0ZXJyb3IgPSBzdGF0dXNUZXh0O1xuXHRcdFx0XHRpZiAoIHN0YXR1cyB8fCAhc3RhdHVzVGV4dCApIHtcblx0XHRcdFx0XHRzdGF0dXNUZXh0ID0gXCJlcnJvclwiO1xuXHRcdFx0XHRcdGlmICggc3RhdHVzIDwgMCApIHtcblx0XHRcdFx0XHRcdHN0YXR1cyA9IDA7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIFNldCBkYXRhIGZvciB0aGUgZmFrZSB4aHIgb2JqZWN0XG5cdFx0XHRqcVhIUi5zdGF0dXMgPSBzdGF0dXM7XG5cdFx0XHRqcVhIUi5zdGF0dXNUZXh0ID0gKCBuYXRpdmVTdGF0dXNUZXh0IHx8IHN0YXR1c1RleHQgKSArIFwiXCI7XG5cblx0XHRcdC8vIFN1Y2Nlc3MvRXJyb3Jcblx0XHRcdGlmICggaXNTdWNjZXNzICkge1xuXHRcdFx0XHRkZWZlcnJlZC5yZXNvbHZlV2l0aCggY2FsbGJhY2tDb250ZXh0LCBbIHN1Y2Nlc3MsIHN0YXR1c1RleHQsIGpxWEhSIF0gKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGRlZmVycmVkLnJlamVjdFdpdGgoIGNhbGxiYWNrQ29udGV4dCwgWyBqcVhIUiwgc3RhdHVzVGV4dCwgZXJyb3IgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBTdGF0dXMtZGVwZW5kZW50IGNhbGxiYWNrc1xuXHRcdFx0anFYSFIuc3RhdHVzQ29kZSggc3RhdHVzQ29kZSApO1xuXHRcdFx0c3RhdHVzQ29kZSA9IHVuZGVmaW5lZDtcblxuXHRcdFx0aWYgKCBmaXJlR2xvYmFscyApIHtcblx0XHRcdFx0Z2xvYmFsRXZlbnRDb250ZXh0LnRyaWdnZXIoIGlzU3VjY2VzcyA/IFwiYWpheFN1Y2Nlc3NcIiA6IFwiYWpheEVycm9yXCIsXG5cdFx0XHRcdFx0WyBqcVhIUiwgcywgaXNTdWNjZXNzID8gc3VjY2VzcyA6IGVycm9yIF0gKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ29tcGxldGVcblx0XHRcdGNvbXBsZXRlRGVmZXJyZWQuZmlyZVdpdGgoIGNhbGxiYWNrQ29udGV4dCwgWyBqcVhIUiwgc3RhdHVzVGV4dCBdICk7XG5cblx0XHRcdGlmICggZmlyZUdsb2JhbHMgKSB7XG5cdFx0XHRcdGdsb2JhbEV2ZW50Q29udGV4dC50cmlnZ2VyKCBcImFqYXhDb21wbGV0ZVwiLCBbIGpxWEhSLCBzIF0gKTtcblxuXHRcdFx0XHQvLyBIYW5kbGUgdGhlIGdsb2JhbCBBSkFYIGNvdW50ZXJcblx0XHRcdFx0aWYgKCAhKCAtLWpRdWVyeS5hY3RpdmUgKSApIHtcblx0XHRcdFx0XHRqUXVlcnkuZXZlbnQudHJpZ2dlciggXCJhamF4U3RvcFwiICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4ganFYSFI7XG5cdH0sXG5cblx0Z2V0SlNPTjogZnVuY3Rpb24oIHVybCwgZGF0YSwgY2FsbGJhY2sgKSB7XG5cdFx0cmV0dXJuIGpRdWVyeS5nZXQoIHVybCwgZGF0YSwgY2FsbGJhY2ssIFwianNvblwiICk7XG5cdH0sXG5cblx0Z2V0U2NyaXB0OiBmdW5jdGlvbiggdXJsLCBjYWxsYmFjayApIHtcblx0XHRyZXR1cm4galF1ZXJ5LmdldCggdXJsLCB1bmRlZmluZWQsIGNhbGxiYWNrLCBcInNjcmlwdFwiICk7XG5cdH1cbn0gKTtcblxualF1ZXJ5LmVhY2goIFsgXCJnZXRcIiwgXCJwb3N0XCIgXSwgZnVuY3Rpb24oIGksIG1ldGhvZCApIHtcblx0alF1ZXJ5WyBtZXRob2QgXSA9IGZ1bmN0aW9uKCB1cmwsIGRhdGEsIGNhbGxiYWNrLCB0eXBlICkge1xuXG5cdFx0Ly8gU2hpZnQgYXJndW1lbnRzIGlmIGRhdGEgYXJndW1lbnQgd2FzIG9taXR0ZWRcblx0XHRpZiAoIGlzRnVuY3Rpb24oIGRhdGEgKSApIHtcblx0XHRcdHR5cGUgPSB0eXBlIHx8IGNhbGxiYWNrO1xuXHRcdFx0Y2FsbGJhY2sgPSBkYXRhO1xuXHRcdFx0ZGF0YSA9IHVuZGVmaW5lZDtcblx0XHR9XG5cblx0XHQvLyBUaGUgdXJsIGNhbiBiZSBhbiBvcHRpb25zIG9iamVjdCAod2hpY2ggdGhlbiBtdXN0IGhhdmUgLnVybClcblx0XHRyZXR1cm4galF1ZXJ5LmFqYXgoIGpRdWVyeS5leHRlbmQoIHtcblx0XHRcdHVybDogdXJsLFxuXHRcdFx0dHlwZTogbWV0aG9kLFxuXHRcdFx0ZGF0YVR5cGU6IHR5cGUsXG5cdFx0XHRkYXRhOiBkYXRhLFxuXHRcdFx0c3VjY2VzczogY2FsbGJhY2tcblx0XHR9LCBqUXVlcnkuaXNQbGFpbk9iamVjdCggdXJsICkgJiYgdXJsICkgKTtcblx0fTtcbn0gKTtcblxuXG5qUXVlcnkuX2V2YWxVcmwgPSBmdW5jdGlvbiggdXJsLCBvcHRpb25zICkge1xuXHRyZXR1cm4galF1ZXJ5LmFqYXgoIHtcblx0XHR1cmw6IHVybCxcblxuXHRcdC8vIE1ha2UgdGhpcyBleHBsaWNpdCwgc2luY2UgdXNlciBjYW4gb3ZlcnJpZGUgdGhpcyB0aHJvdWdoIGFqYXhTZXR1cCAoIzExMjY0KVxuXHRcdHR5cGU6IFwiR0VUXCIsXG5cdFx0ZGF0YVR5cGU6IFwic2NyaXB0XCIsXG5cdFx0Y2FjaGU6IHRydWUsXG5cdFx0YXN5bmM6IGZhbHNlLFxuXHRcdGdsb2JhbDogZmFsc2UsXG5cblx0XHQvLyBPbmx5IGV2YWx1YXRlIHRoZSByZXNwb25zZSBpZiBpdCBpcyBzdWNjZXNzZnVsIChnaC00MTI2KVxuXHRcdC8vIGRhdGFGaWx0ZXIgaXMgbm90IGludm9rZWQgZm9yIGZhaWx1cmUgcmVzcG9uc2VzLCBzbyB1c2luZyBpdCBpbnN0ZWFkXG5cdFx0Ly8gb2YgdGhlIGRlZmF1bHQgY29udmVydGVyIGlzIGtsdWRneSBidXQgaXQgd29ya3MuXG5cdFx0Y29udmVydGVyczoge1xuXHRcdFx0XCJ0ZXh0IHNjcmlwdFwiOiBmdW5jdGlvbigpIHt9XG5cdFx0fSxcblx0XHRkYXRhRmlsdGVyOiBmdW5jdGlvbiggcmVzcG9uc2UgKSB7XG5cdFx0XHRqUXVlcnkuZ2xvYmFsRXZhbCggcmVzcG9uc2UsIG9wdGlvbnMgKTtcblx0XHR9XG5cdH0gKTtcbn07XG5cblxualF1ZXJ5LmZuLmV4dGVuZCgge1xuXHR3cmFwQWxsOiBmdW5jdGlvbiggaHRtbCApIHtcblx0XHR2YXIgd3JhcDtcblxuXHRcdGlmICggdGhpc1sgMCBdICkge1xuXHRcdFx0aWYgKCBpc0Z1bmN0aW9uKCBodG1sICkgKSB7XG5cdFx0XHRcdGh0bWwgPSBodG1sLmNhbGwoIHRoaXNbIDAgXSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBUaGUgZWxlbWVudHMgdG8gd3JhcCB0aGUgdGFyZ2V0IGFyb3VuZFxuXHRcdFx0d3JhcCA9IGpRdWVyeSggaHRtbCwgdGhpc1sgMCBdLm93bmVyRG9jdW1lbnQgKS5lcSggMCApLmNsb25lKCB0cnVlICk7XG5cblx0XHRcdGlmICggdGhpc1sgMCBdLnBhcmVudE5vZGUgKSB7XG5cdFx0XHRcdHdyYXAuaW5zZXJ0QmVmb3JlKCB0aGlzWyAwIF0gKTtcblx0XHRcdH1cblxuXHRcdFx0d3JhcC5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgZWxlbSA9IHRoaXM7XG5cblx0XHRcdFx0d2hpbGUgKCBlbGVtLmZpcnN0RWxlbWVudENoaWxkICkge1xuXHRcdFx0XHRcdGVsZW0gPSBlbGVtLmZpcnN0RWxlbWVudENoaWxkO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIGVsZW07XG5cdFx0XHR9ICkuYXBwZW5kKCB0aGlzICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0d3JhcElubmVyOiBmdW5jdGlvbiggaHRtbCApIHtcblx0XHRpZiAoIGlzRnVuY3Rpb24oIGh0bWwgKSApIHtcblx0XHRcdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0XHRqUXVlcnkoIHRoaXMgKS53cmFwSW5uZXIoIGh0bWwuY2FsbCggdGhpcywgaSApICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc2VsZiA9IGpRdWVyeSggdGhpcyApLFxuXHRcdFx0XHRjb250ZW50cyA9IHNlbGYuY29udGVudHMoKTtcblxuXHRcdFx0aWYgKCBjb250ZW50cy5sZW5ndGggKSB7XG5cdFx0XHRcdGNvbnRlbnRzLndyYXBBbGwoIGh0bWwgKTtcblxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0c2VsZi5hcHBlbmQoIGh0bWwgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0d3JhcDogZnVuY3Rpb24oIGh0bWwgKSB7XG5cdFx0dmFyIGh0bWxJc0Z1bmN0aW9uID0gaXNGdW5jdGlvbiggaHRtbCApO1xuXG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHRqUXVlcnkoIHRoaXMgKS53cmFwQWxsKCBodG1sSXNGdW5jdGlvbiA/IGh0bWwuY2FsbCggdGhpcywgaSApIDogaHRtbCApO1xuXHRcdH0gKTtcblx0fSxcblxuXHR1bndyYXA6IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHR0aGlzLnBhcmVudCggc2VsZWN0b3IgKS5ub3QoIFwiYm9keVwiICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRqUXVlcnkoIHRoaXMgKS5yZXBsYWNlV2l0aCggdGhpcy5jaGlsZE5vZGVzICk7XG5cdFx0fSApO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG59ICk7XG5cblxualF1ZXJ5LmV4cHIucHNldWRvcy5oaWRkZW4gPSBmdW5jdGlvbiggZWxlbSApIHtcblx0cmV0dXJuICFqUXVlcnkuZXhwci5wc2V1ZG9zLnZpc2libGUoIGVsZW0gKTtcbn07XG5qUXVlcnkuZXhwci5wc2V1ZG9zLnZpc2libGUgPSBmdW5jdGlvbiggZWxlbSApIHtcblx0cmV0dXJuICEhKCBlbGVtLm9mZnNldFdpZHRoIHx8IGVsZW0ub2Zmc2V0SGVpZ2h0IHx8IGVsZW0uZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGggKTtcbn07XG5cblxuXG5cbmpRdWVyeS5hamF4U2V0dGluZ3MueGhyID0gZnVuY3Rpb24oKSB7XG5cdHRyeSB7XG5cdFx0cmV0dXJuIG5ldyB3aW5kb3cuWE1MSHR0cFJlcXVlc3QoKTtcblx0fSBjYXRjaCAoIGUgKSB7fVxufTtcblxudmFyIHhoclN1Y2Nlc3NTdGF0dXMgPSB7XG5cblx0XHQvLyBGaWxlIHByb3RvY29sIGFsd2F5cyB5aWVsZHMgc3RhdHVzIGNvZGUgMCwgYXNzdW1lIDIwMFxuXHRcdDA6IDIwMCxcblxuXHRcdC8vIFN1cHBvcnQ6IElFIDw9OSBvbmx5XG5cdFx0Ly8gIzE0NTA6IHNvbWV0aW1lcyBJRSByZXR1cm5zIDEyMjMgd2hlbiBpdCBzaG91bGQgYmUgMjA0XG5cdFx0MTIyMzogMjA0XG5cdH0sXG5cdHhoclN1cHBvcnRlZCA9IGpRdWVyeS5hamF4U2V0dGluZ3MueGhyKCk7XG5cbnN1cHBvcnQuY29ycyA9ICEheGhyU3VwcG9ydGVkICYmICggXCJ3aXRoQ3JlZGVudGlhbHNcIiBpbiB4aHJTdXBwb3J0ZWQgKTtcbnN1cHBvcnQuYWpheCA9IHhoclN1cHBvcnRlZCA9ICEheGhyU3VwcG9ydGVkO1xuXG5qUXVlcnkuYWpheFRyYW5zcG9ydCggZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdHZhciBjYWxsYmFjaywgZXJyb3JDYWxsYmFjaztcblxuXHQvLyBDcm9zcyBkb21haW4gb25seSBhbGxvd2VkIGlmIHN1cHBvcnRlZCB0aHJvdWdoIFhNTEh0dHBSZXF1ZXN0XG5cdGlmICggc3VwcG9ydC5jb3JzIHx8IHhoclN1cHBvcnRlZCAmJiAhb3B0aW9ucy5jcm9zc0RvbWFpbiApIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0c2VuZDogZnVuY3Rpb24oIGhlYWRlcnMsIGNvbXBsZXRlICkge1xuXHRcdFx0XHR2YXIgaSxcblx0XHRcdFx0XHR4aHIgPSBvcHRpb25zLnhocigpO1xuXG5cdFx0XHRcdHhoci5vcGVuKFxuXHRcdFx0XHRcdG9wdGlvbnMudHlwZSxcblx0XHRcdFx0XHRvcHRpb25zLnVybCxcblx0XHRcdFx0XHRvcHRpb25zLmFzeW5jLFxuXHRcdFx0XHRcdG9wdGlvbnMudXNlcm5hbWUsXG5cdFx0XHRcdFx0b3B0aW9ucy5wYXNzd29yZFxuXHRcdFx0XHQpO1xuXG5cdFx0XHRcdC8vIEFwcGx5IGN1c3RvbSBmaWVsZHMgaWYgcHJvdmlkZWRcblx0XHRcdFx0aWYgKCBvcHRpb25zLnhockZpZWxkcyApIHtcblx0XHRcdFx0XHRmb3IgKCBpIGluIG9wdGlvbnMueGhyRmllbGRzICkge1xuXHRcdFx0XHRcdFx0eGhyWyBpIF0gPSBvcHRpb25zLnhockZpZWxkc1sgaSBdO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIE92ZXJyaWRlIG1pbWUgdHlwZSBpZiBuZWVkZWRcblx0XHRcdFx0aWYgKCBvcHRpb25zLm1pbWVUeXBlICYmIHhoci5vdmVycmlkZU1pbWVUeXBlICkge1xuXHRcdFx0XHRcdHhoci5vdmVycmlkZU1pbWVUeXBlKCBvcHRpb25zLm1pbWVUeXBlICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBYLVJlcXVlc3RlZC1XaXRoIGhlYWRlclxuXHRcdFx0XHQvLyBGb3IgY3Jvc3MtZG9tYWluIHJlcXVlc3RzLCBzZWVpbmcgYXMgY29uZGl0aW9ucyBmb3IgYSBwcmVmbGlnaHQgYXJlXG5cdFx0XHRcdC8vIGFraW4gdG8gYSBqaWdzYXcgcHV6emxlLCB3ZSBzaW1wbHkgbmV2ZXIgc2V0IGl0IHRvIGJlIHN1cmUuXG5cdFx0XHRcdC8vIChpdCBjYW4gYWx3YXlzIGJlIHNldCBvbiBhIHBlci1yZXF1ZXN0IGJhc2lzIG9yIGV2ZW4gdXNpbmcgYWpheFNldHVwKVxuXHRcdFx0XHQvLyBGb3Igc2FtZS1kb21haW4gcmVxdWVzdHMsIHdvbid0IGNoYW5nZSBoZWFkZXIgaWYgYWxyZWFkeSBwcm92aWRlZC5cblx0XHRcdFx0aWYgKCAhb3B0aW9ucy5jcm9zc0RvbWFpbiAmJiAhaGVhZGVyc1sgXCJYLVJlcXVlc3RlZC1XaXRoXCIgXSApIHtcblx0XHRcdFx0XHRoZWFkZXJzWyBcIlgtUmVxdWVzdGVkLVdpdGhcIiBdID0gXCJYTUxIdHRwUmVxdWVzdFwiO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gU2V0IGhlYWRlcnNcblx0XHRcdFx0Zm9yICggaSBpbiBoZWFkZXJzICkge1xuXHRcdFx0XHRcdHhoci5zZXRSZXF1ZXN0SGVhZGVyKCBpLCBoZWFkZXJzWyBpIF0gKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIENhbGxiYWNrXG5cdFx0XHRcdGNhbGxiYWNrID0gZnVuY3Rpb24oIHR5cGUgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0aWYgKCBjYWxsYmFjayApIHtcblx0XHRcdFx0XHRcdFx0Y2FsbGJhY2sgPSBlcnJvckNhbGxiYWNrID0geGhyLm9ubG9hZCA9XG5cdFx0XHRcdFx0XHRcdFx0eGhyLm9uZXJyb3IgPSB4aHIub25hYm9ydCA9IHhoci5vbnRpbWVvdXQgPVxuXHRcdFx0XHRcdFx0XHRcdFx0eGhyLm9ucmVhZHlzdGF0ZWNoYW5nZSA9IG51bGw7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCB0eXBlID09PSBcImFib3J0XCIgKSB7XG5cdFx0XHRcdFx0XHRcdFx0eGhyLmFib3J0KCk7XG5cdFx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIHR5cGUgPT09IFwiZXJyb3JcIiApIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw9OSBvbmx5XG5cdFx0XHRcdFx0XHRcdFx0Ly8gT24gYSBtYW51YWwgbmF0aXZlIGFib3J0LCBJRTkgdGhyb3dzXG5cdFx0XHRcdFx0XHRcdFx0Ly8gZXJyb3JzIG9uIGFueSBwcm9wZXJ0eSBhY2Nlc3MgdGhhdCBpcyBub3QgcmVhZHlTdGF0ZVxuXHRcdFx0XHRcdFx0XHRcdGlmICggdHlwZW9mIHhoci5zdGF0dXMgIT09IFwibnVtYmVyXCIgKSB7XG5cdFx0XHRcdFx0XHRcdFx0XHRjb21wbGV0ZSggMCwgXCJlcnJvclwiICk7XG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRcdGNvbXBsZXRlKFxuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdC8vIEZpbGU6IHByb3RvY29sIGFsd2F5cyB5aWVsZHMgc3RhdHVzIDA7IHNlZSAjODYwNSwgIzE0MjA3XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHhoci5zdGF0dXMsXG5cdFx0XHRcdFx0XHRcdFx0XHRcdHhoci5zdGF0dXNUZXh0XG5cdFx0XHRcdFx0XHRcdFx0XHQpO1xuXHRcdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRjb21wbGV0ZShcblx0XHRcdFx0XHRcdFx0XHRcdHhoclN1Y2Nlc3NTdGF0dXNbIHhoci5zdGF0dXMgXSB8fCB4aHIuc3RhdHVzLFxuXHRcdFx0XHRcdFx0XHRcdFx0eGhyLnN0YXR1c1RleHQsXG5cblx0XHRcdFx0XHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFIDw9OSBvbmx5XG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBJRTkgaGFzIG5vIFhIUjIgYnV0IHRocm93cyBvbiBiaW5hcnkgKHRyYWMtMTE0MjYpXG5cdFx0XHRcdFx0XHRcdFx0XHQvLyBGb3IgWEhSMiBub24tdGV4dCwgbGV0IHRoZSBjYWxsZXIgaGFuZGxlIGl0IChnaC0yNDk4KVxuXHRcdFx0XHRcdFx0XHRcdFx0KCB4aHIucmVzcG9uc2VUeXBlIHx8IFwidGV4dFwiICkgIT09IFwidGV4dFwiICB8fFxuXHRcdFx0XHRcdFx0XHRcdFx0dHlwZW9mIHhoci5yZXNwb25zZVRleHQgIT09IFwic3RyaW5nXCIgP1xuXHRcdFx0XHRcdFx0XHRcdFx0XHR7IGJpbmFyeTogeGhyLnJlc3BvbnNlIH0gOlxuXHRcdFx0XHRcdFx0XHRcdFx0XHR7IHRleHQ6IHhoci5yZXNwb25zZVRleHQgfSxcblx0XHRcdFx0XHRcdFx0XHRcdHhoci5nZXRBbGxSZXNwb25zZUhlYWRlcnMoKVxuXHRcdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9O1xuXHRcdFx0XHR9O1xuXG5cdFx0XHRcdC8vIExpc3RlbiB0byBldmVudHNcblx0XHRcdFx0eGhyLm9ubG9hZCA9IGNhbGxiYWNrKCk7XG5cdFx0XHRcdGVycm9yQ2FsbGJhY2sgPSB4aHIub25lcnJvciA9IHhoci5vbnRpbWVvdXQgPSBjYWxsYmFjayggXCJlcnJvclwiICk7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgOSBvbmx5XG5cdFx0XHRcdC8vIFVzZSBvbnJlYWR5c3RhdGVjaGFuZ2UgdG8gcmVwbGFjZSBvbmFib3J0XG5cdFx0XHRcdC8vIHRvIGhhbmRsZSB1bmNhdWdodCBhYm9ydHNcblx0XHRcdFx0aWYgKCB4aHIub25hYm9ydCAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdHhoci5vbmFib3J0ID0gZXJyb3JDYWxsYmFjaztcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR4aHIub25yZWFkeXN0YXRlY2hhbmdlID0gZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0XHRcdC8vIENoZWNrIHJlYWR5U3RhdGUgYmVmb3JlIHRpbWVvdXQgYXMgaXQgY2hhbmdlc1xuXHRcdFx0XHRcdFx0aWYgKCB4aHIucmVhZHlTdGF0ZSA9PT0gNCApIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBBbGxvdyBvbmVycm9yIHRvIGJlIGNhbGxlZCBmaXJzdCxcblx0XHRcdFx0XHRcdFx0Ly8gYnV0IHRoYXQgd2lsbCBub3QgaGFuZGxlIGEgbmF0aXZlIGFib3J0XG5cdFx0XHRcdFx0XHRcdC8vIEFsc28sIHNhdmUgZXJyb3JDYWxsYmFjayB0byBhIHZhcmlhYmxlXG5cdFx0XHRcdFx0XHRcdC8vIGFzIHhoci5vbmVycm9yIGNhbm5vdCBiZSBhY2Nlc3NlZFxuXHRcdFx0XHRcdFx0XHR3aW5kb3cuc2V0VGltZW91dCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBjYWxsYmFjayApIHtcblx0XHRcdFx0XHRcdFx0XHRcdGVycm9yQ2FsbGJhY2soKTtcblx0XHRcdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9O1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gQ3JlYXRlIHRoZSBhYm9ydCBjYWxsYmFja1xuXHRcdFx0XHRjYWxsYmFjayA9IGNhbGxiYWNrKCBcImFib3J0XCIgKTtcblxuXHRcdFx0XHR0cnkge1xuXG5cdFx0XHRcdFx0Ly8gRG8gc2VuZCB0aGUgcmVxdWVzdCAodGhpcyBtYXkgcmFpc2UgYW4gZXhjZXB0aW9uKVxuXHRcdFx0XHRcdHhoci5zZW5kKCBvcHRpb25zLmhhc0NvbnRlbnQgJiYgb3B0aW9ucy5kYXRhIHx8IG51bGwgKTtcblx0XHRcdFx0fSBjYXRjaCAoIGUgKSB7XG5cblx0XHRcdFx0XHQvLyAjMTQ2ODM6IE9ubHkgcmV0aHJvdyBpZiB0aGlzIGhhc24ndCBiZWVuIG5vdGlmaWVkIGFzIGFuIGVycm9yIHlldFxuXHRcdFx0XHRcdGlmICggY2FsbGJhY2sgKSB7XG5cdFx0XHRcdFx0XHR0aHJvdyBlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSxcblxuXHRcdFx0YWJvcnQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIGNhbGxiYWNrICkge1xuXHRcdFx0XHRcdGNhbGxiYWNrKCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXHR9XG59ICk7XG5cblxuXG5cbi8vIFByZXZlbnQgYXV0by1leGVjdXRpb24gb2Ygc2NyaXB0cyB3aGVuIG5vIGV4cGxpY2l0IGRhdGFUeXBlIHdhcyBwcm92aWRlZCAoU2VlIGdoLTI0MzIpXG5qUXVlcnkuYWpheFByZWZpbHRlciggZnVuY3Rpb24oIHMgKSB7XG5cdGlmICggcy5jcm9zc0RvbWFpbiApIHtcblx0XHRzLmNvbnRlbnRzLnNjcmlwdCA9IGZhbHNlO1xuXHR9XG59ICk7XG5cbi8vIEluc3RhbGwgc2NyaXB0IGRhdGFUeXBlXG5qUXVlcnkuYWpheFNldHVwKCB7XG5cdGFjY2VwdHM6IHtcblx0XHRzY3JpcHQ6IFwidGV4dC9qYXZhc2NyaXB0LCBhcHBsaWNhdGlvbi9qYXZhc2NyaXB0LCBcIiArXG5cdFx0XHRcImFwcGxpY2F0aW9uL2VjbWFzY3JpcHQsIGFwcGxpY2F0aW9uL3gtZWNtYXNjcmlwdFwiXG5cdH0sXG5cdGNvbnRlbnRzOiB7XG5cdFx0c2NyaXB0OiAvXFxiKD86amF2YXxlY21hKXNjcmlwdFxcYi9cblx0fSxcblx0Y29udmVydGVyczoge1xuXHRcdFwidGV4dCBzY3JpcHRcIjogZnVuY3Rpb24oIHRleHQgKSB7XG5cdFx0XHRqUXVlcnkuZ2xvYmFsRXZhbCggdGV4dCApO1xuXHRcdFx0cmV0dXJuIHRleHQ7XG5cdFx0fVxuXHR9XG59ICk7XG5cbi8vIEhhbmRsZSBjYWNoZSdzIHNwZWNpYWwgY2FzZSBhbmQgY3Jvc3NEb21haW5cbmpRdWVyeS5hamF4UHJlZmlsdGVyKCBcInNjcmlwdFwiLCBmdW5jdGlvbiggcyApIHtcblx0aWYgKCBzLmNhY2hlID09PSB1bmRlZmluZWQgKSB7XG5cdFx0cy5jYWNoZSA9IGZhbHNlO1xuXHR9XG5cdGlmICggcy5jcm9zc0RvbWFpbiApIHtcblx0XHRzLnR5cGUgPSBcIkdFVFwiO1xuXHR9XG59ICk7XG5cbi8vIEJpbmQgc2NyaXB0IHRhZyBoYWNrIHRyYW5zcG9ydFxualF1ZXJ5LmFqYXhUcmFuc3BvcnQoIFwic2NyaXB0XCIsIGZ1bmN0aW9uKCBzICkge1xuXG5cdC8vIFRoaXMgdHJhbnNwb3J0IG9ubHkgZGVhbHMgd2l0aCBjcm9zcyBkb21haW4gb3IgZm9yY2VkLWJ5LWF0dHJzIHJlcXVlc3RzXG5cdGlmICggcy5jcm9zc0RvbWFpbiB8fCBzLnNjcmlwdEF0dHJzICkge1xuXHRcdHZhciBzY3JpcHQsIGNhbGxiYWNrO1xuXHRcdHJldHVybiB7XG5cdFx0XHRzZW5kOiBmdW5jdGlvbiggXywgY29tcGxldGUgKSB7XG5cdFx0XHRcdHNjcmlwdCA9IGpRdWVyeSggXCI8c2NyaXB0PlwiIClcblx0XHRcdFx0XHQuYXR0ciggcy5zY3JpcHRBdHRycyB8fCB7fSApXG5cdFx0XHRcdFx0LnByb3AoIHsgY2hhcnNldDogcy5zY3JpcHRDaGFyc2V0LCBzcmM6IHMudXJsIH0gKVxuXHRcdFx0XHRcdC5vbiggXCJsb2FkIGVycm9yXCIsIGNhbGxiYWNrID0gZnVuY3Rpb24oIGV2dCApIHtcblx0XHRcdFx0XHRcdHNjcmlwdC5yZW1vdmUoKTtcblx0XHRcdFx0XHRcdGNhbGxiYWNrID0gbnVsbDtcblx0XHRcdFx0XHRcdGlmICggZXZ0ICkge1xuXHRcdFx0XHRcdFx0XHRjb21wbGV0ZSggZXZ0LnR5cGUgPT09IFwiZXJyb3JcIiA/IDQwNCA6IDIwMCwgZXZ0LnR5cGUgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0Ly8gVXNlIG5hdGl2ZSBET00gbWFuaXB1bGF0aW9uIHRvIGF2b2lkIG91ciBkb21NYW5pcCBBSkFYIHRyaWNrZXJ5XG5cdFx0XHRcdGRvY3VtZW50LmhlYWQuYXBwZW5kQ2hpbGQoIHNjcmlwdFsgMCBdICk7XG5cdFx0XHR9LFxuXHRcdFx0YWJvcnQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIGNhbGxiYWNrICkge1xuXHRcdFx0XHRcdGNhbGxiYWNrKCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXHR9XG59ICk7XG5cblxuXG5cbnZhciBvbGRDYWxsYmFja3MgPSBbXSxcblx0cmpzb25wID0gLyg9KVxcPyg/PSZ8JCl8XFw/XFw/LztcblxuLy8gRGVmYXVsdCBqc29ucCBzZXR0aW5nc1xualF1ZXJ5LmFqYXhTZXR1cCgge1xuXHRqc29ucDogXCJjYWxsYmFja1wiLFxuXHRqc29ucENhbGxiYWNrOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgY2FsbGJhY2sgPSBvbGRDYWxsYmFja3MucG9wKCkgfHwgKCBqUXVlcnkuZXhwYW5kbyArIFwiX1wiICsgKCBub25jZSsrICkgKTtcblx0XHR0aGlzWyBjYWxsYmFjayBdID0gdHJ1ZTtcblx0XHRyZXR1cm4gY2FsbGJhY2s7XG5cdH1cbn0gKTtcblxuLy8gRGV0ZWN0LCBub3JtYWxpemUgb3B0aW9ucyBhbmQgaW5zdGFsbCBjYWxsYmFja3MgZm9yIGpzb25wIHJlcXVlc3RzXG5qUXVlcnkuYWpheFByZWZpbHRlciggXCJqc29uIGpzb25wXCIsIGZ1bmN0aW9uKCBzLCBvcmlnaW5hbFNldHRpbmdzLCBqcVhIUiApIHtcblxuXHR2YXIgY2FsbGJhY2tOYW1lLCBvdmVyd3JpdHRlbiwgcmVzcG9uc2VDb250YWluZXIsXG5cdFx0anNvblByb3AgPSBzLmpzb25wICE9PSBmYWxzZSAmJiAoIHJqc29ucC50ZXN0KCBzLnVybCApID9cblx0XHRcdFwidXJsXCIgOlxuXHRcdFx0dHlwZW9mIHMuZGF0YSA9PT0gXCJzdHJpbmdcIiAmJlxuXHRcdFx0XHQoIHMuY29udGVudFR5cGUgfHwgXCJcIiApXG5cdFx0XHRcdFx0LmluZGV4T2YoIFwiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkXCIgKSA9PT0gMCAmJlxuXHRcdFx0XHRyanNvbnAudGVzdCggcy5kYXRhICkgJiYgXCJkYXRhXCJcblx0XHQpO1xuXG5cdC8vIEhhbmRsZSBpZmYgdGhlIGV4cGVjdGVkIGRhdGEgdHlwZSBpcyBcImpzb25wXCIgb3Igd2UgaGF2ZSBhIHBhcmFtZXRlciB0byBzZXRcblx0aWYgKCBqc29uUHJvcCB8fCBzLmRhdGFUeXBlc1sgMCBdID09PSBcImpzb25wXCIgKSB7XG5cblx0XHQvLyBHZXQgY2FsbGJhY2sgbmFtZSwgcmVtZW1iZXJpbmcgcHJlZXhpc3RpbmcgdmFsdWUgYXNzb2NpYXRlZCB3aXRoIGl0XG5cdFx0Y2FsbGJhY2tOYW1lID0gcy5qc29ucENhbGxiYWNrID0gaXNGdW5jdGlvbiggcy5qc29ucENhbGxiYWNrICkgP1xuXHRcdFx0cy5qc29ucENhbGxiYWNrKCkgOlxuXHRcdFx0cy5qc29ucENhbGxiYWNrO1xuXG5cdFx0Ly8gSW5zZXJ0IGNhbGxiYWNrIGludG8gdXJsIG9yIGZvcm0gZGF0YVxuXHRcdGlmICgganNvblByb3AgKSB7XG5cdFx0XHRzWyBqc29uUHJvcCBdID0gc1sganNvblByb3AgXS5yZXBsYWNlKCByanNvbnAsIFwiJDFcIiArIGNhbGxiYWNrTmFtZSApO1xuXHRcdH0gZWxzZSBpZiAoIHMuanNvbnAgIT09IGZhbHNlICkge1xuXHRcdFx0cy51cmwgKz0gKCBycXVlcnkudGVzdCggcy51cmwgKSA/IFwiJlwiIDogXCI/XCIgKSArIHMuanNvbnAgKyBcIj1cIiArIGNhbGxiYWNrTmFtZTtcblx0XHR9XG5cblx0XHQvLyBVc2UgZGF0YSBjb252ZXJ0ZXIgdG8gcmV0cmlldmUganNvbiBhZnRlciBzY3JpcHQgZXhlY3V0aW9uXG5cdFx0cy5jb252ZXJ0ZXJzWyBcInNjcmlwdCBqc29uXCIgXSA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCAhcmVzcG9uc2VDb250YWluZXIgKSB7XG5cdFx0XHRcdGpRdWVyeS5lcnJvciggY2FsbGJhY2tOYW1lICsgXCIgd2FzIG5vdCBjYWxsZWRcIiApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHJlc3BvbnNlQ29udGFpbmVyWyAwIF07XG5cdFx0fTtcblxuXHRcdC8vIEZvcmNlIGpzb24gZGF0YVR5cGVcblx0XHRzLmRhdGFUeXBlc1sgMCBdID0gXCJqc29uXCI7XG5cblx0XHQvLyBJbnN0YWxsIGNhbGxiYWNrXG5cdFx0b3ZlcndyaXR0ZW4gPSB3aW5kb3dbIGNhbGxiYWNrTmFtZSBdO1xuXHRcdHdpbmRvd1sgY2FsbGJhY2tOYW1lIF0gPSBmdW5jdGlvbigpIHtcblx0XHRcdHJlc3BvbnNlQ29udGFpbmVyID0gYXJndW1lbnRzO1xuXHRcdH07XG5cblx0XHQvLyBDbGVhbi11cCBmdW5jdGlvbiAoZmlyZXMgYWZ0ZXIgY29udmVydGVycylcblx0XHRqcVhIUi5hbHdheXMoIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHQvLyBJZiBwcmV2aW91cyB2YWx1ZSBkaWRuJ3QgZXhpc3QgLSByZW1vdmUgaXRcblx0XHRcdGlmICggb3ZlcndyaXR0ZW4gPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0alF1ZXJ5KCB3aW5kb3cgKS5yZW1vdmVQcm9wKCBjYWxsYmFja05hbWUgKTtcblxuXHRcdFx0Ly8gT3RoZXJ3aXNlIHJlc3RvcmUgcHJlZXhpc3RpbmcgdmFsdWVcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHdpbmRvd1sgY2FsbGJhY2tOYW1lIF0gPSBvdmVyd3JpdHRlbjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gU2F2ZSBiYWNrIGFzIGZyZWVcblx0XHRcdGlmICggc1sgY2FsbGJhY2tOYW1lIF0gKSB7XG5cblx0XHRcdFx0Ly8gTWFrZSBzdXJlIHRoYXQgcmUtdXNpbmcgdGhlIG9wdGlvbnMgZG9lc24ndCBzY3JldyB0aGluZ3MgYXJvdW5kXG5cdFx0XHRcdHMuanNvbnBDYWxsYmFjayA9IG9yaWdpbmFsU2V0dGluZ3MuanNvbnBDYWxsYmFjaztcblxuXHRcdFx0XHQvLyBTYXZlIHRoZSBjYWxsYmFjayBuYW1lIGZvciBmdXR1cmUgdXNlXG5cdFx0XHRcdG9sZENhbGxiYWNrcy5wdXNoKCBjYWxsYmFja05hbWUgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ2FsbCBpZiBpdCB3YXMgYSBmdW5jdGlvbiBhbmQgd2UgaGF2ZSBhIHJlc3BvbnNlXG5cdFx0XHRpZiAoIHJlc3BvbnNlQ29udGFpbmVyICYmIGlzRnVuY3Rpb24oIG92ZXJ3cml0dGVuICkgKSB7XG5cdFx0XHRcdG92ZXJ3cml0dGVuKCByZXNwb25zZUNvbnRhaW5lclsgMCBdICk7XG5cdFx0XHR9XG5cblx0XHRcdHJlc3BvbnNlQ29udGFpbmVyID0gb3ZlcndyaXR0ZW4gPSB1bmRlZmluZWQ7XG5cdFx0fSApO1xuXG5cdFx0Ly8gRGVsZWdhdGUgdG8gc2NyaXB0XG5cdFx0cmV0dXJuIFwic2NyaXB0XCI7XG5cdH1cbn0gKTtcblxuXG5cblxuLy8gU3VwcG9ydDogU2FmYXJpIDggb25seVxuLy8gSW4gU2FmYXJpIDggZG9jdW1lbnRzIGNyZWF0ZWQgdmlhIGRvY3VtZW50LmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudFxuLy8gY29sbGFwc2Ugc2libGluZyBmb3JtczogdGhlIHNlY29uZCBvbmUgYmVjb21lcyBhIGNoaWxkIG9mIHRoZSBmaXJzdCBvbmUuXG4vLyBCZWNhdXNlIG9mIHRoYXQsIHRoaXMgc2VjdXJpdHkgbWVhc3VyZSBoYXMgdG8gYmUgZGlzYWJsZWQgaW4gU2FmYXJpIDguXG4vLyBodHRwczovL2J1Z3Mud2Via2l0Lm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTM3MzM3XG5zdXBwb3J0LmNyZWF0ZUhUTUxEb2N1bWVudCA9ICggZnVuY3Rpb24oKSB7XG5cdHZhciBib2R5ID0gZG9jdW1lbnQuaW1wbGVtZW50YXRpb24uY3JlYXRlSFRNTERvY3VtZW50KCBcIlwiICkuYm9keTtcblx0Ym9keS5pbm5lckhUTUwgPSBcIjxmb3JtPjwvZm9ybT48Zm9ybT48L2Zvcm0+XCI7XG5cdHJldHVybiBib2R5LmNoaWxkTm9kZXMubGVuZ3RoID09PSAyO1xufSApKCk7XG5cblxuLy8gQXJndW1lbnQgXCJkYXRhXCIgc2hvdWxkIGJlIHN0cmluZyBvZiBodG1sXG4vLyBjb250ZXh0IChvcHRpb25hbCk6IElmIHNwZWNpZmllZCwgdGhlIGZyYWdtZW50IHdpbGwgYmUgY3JlYXRlZCBpbiB0aGlzIGNvbnRleHQsXG4vLyBkZWZhdWx0cyB0byBkb2N1bWVudFxuLy8ga2VlcFNjcmlwdHMgKG9wdGlvbmFsKTogSWYgdHJ1ZSwgd2lsbCBpbmNsdWRlIHNjcmlwdHMgcGFzc2VkIGluIHRoZSBodG1sIHN0cmluZ1xualF1ZXJ5LnBhcnNlSFRNTCA9IGZ1bmN0aW9uKCBkYXRhLCBjb250ZXh0LCBrZWVwU2NyaXB0cyApIHtcblx0aWYgKCB0eXBlb2YgZGF0YSAhPT0gXCJzdHJpbmdcIiApIHtcblx0XHRyZXR1cm4gW107XG5cdH1cblx0aWYgKCB0eXBlb2YgY29udGV4dCA9PT0gXCJib29sZWFuXCIgKSB7XG5cdFx0a2VlcFNjcmlwdHMgPSBjb250ZXh0O1xuXHRcdGNvbnRleHQgPSBmYWxzZTtcblx0fVxuXG5cdHZhciBiYXNlLCBwYXJzZWQsIHNjcmlwdHM7XG5cblx0aWYgKCAhY29udGV4dCApIHtcblxuXHRcdC8vIFN0b3Agc2NyaXB0cyBvciBpbmxpbmUgZXZlbnQgaGFuZGxlcnMgZnJvbSBiZWluZyBleGVjdXRlZCBpbW1lZGlhdGVseVxuXHRcdC8vIGJ5IHVzaW5nIGRvY3VtZW50LmltcGxlbWVudGF0aW9uXG5cdFx0aWYgKCBzdXBwb3J0LmNyZWF0ZUhUTUxEb2N1bWVudCApIHtcblx0XHRcdGNvbnRleHQgPSBkb2N1bWVudC5pbXBsZW1lbnRhdGlvbi5jcmVhdGVIVE1MRG9jdW1lbnQoIFwiXCIgKTtcblxuXHRcdFx0Ly8gU2V0IHRoZSBiYXNlIGhyZWYgZm9yIHRoZSBjcmVhdGVkIGRvY3VtZW50XG5cdFx0XHQvLyBzbyBhbnkgcGFyc2VkIGVsZW1lbnRzIHdpdGggVVJMc1xuXHRcdFx0Ly8gYXJlIGJhc2VkIG9uIHRoZSBkb2N1bWVudCdzIFVSTCAoZ2gtMjk2NSlcblx0XHRcdGJhc2UgPSBjb250ZXh0LmNyZWF0ZUVsZW1lbnQoIFwiYmFzZVwiICk7XG5cdFx0XHRiYXNlLmhyZWYgPSBkb2N1bWVudC5sb2NhdGlvbi5ocmVmO1xuXHRcdFx0Y29udGV4dC5oZWFkLmFwcGVuZENoaWxkKCBiYXNlICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGNvbnRleHQgPSBkb2N1bWVudDtcblx0XHR9XG5cdH1cblxuXHRwYXJzZWQgPSByc2luZ2xlVGFnLmV4ZWMoIGRhdGEgKTtcblx0c2NyaXB0cyA9ICFrZWVwU2NyaXB0cyAmJiBbXTtcblxuXHQvLyBTaW5nbGUgdGFnXG5cdGlmICggcGFyc2VkICkge1xuXHRcdHJldHVybiBbIGNvbnRleHQuY3JlYXRlRWxlbWVudCggcGFyc2VkWyAxIF0gKSBdO1xuXHR9XG5cblx0cGFyc2VkID0gYnVpbGRGcmFnbWVudCggWyBkYXRhIF0sIGNvbnRleHQsIHNjcmlwdHMgKTtcblxuXHRpZiAoIHNjcmlwdHMgJiYgc2NyaXB0cy5sZW5ndGggKSB7XG5cdFx0alF1ZXJ5KCBzY3JpcHRzICkucmVtb3ZlKCk7XG5cdH1cblxuXHRyZXR1cm4galF1ZXJ5Lm1lcmdlKCBbXSwgcGFyc2VkLmNoaWxkTm9kZXMgKTtcbn07XG5cblxuLyoqXG4gKiBMb2FkIGEgdXJsIGludG8gYSBwYWdlXG4gKi9cbmpRdWVyeS5mbi5sb2FkID0gZnVuY3Rpb24oIHVybCwgcGFyYW1zLCBjYWxsYmFjayApIHtcblx0dmFyIHNlbGVjdG9yLCB0eXBlLCByZXNwb25zZSxcblx0XHRzZWxmID0gdGhpcyxcblx0XHRvZmYgPSB1cmwuaW5kZXhPZiggXCIgXCIgKTtcblxuXHRpZiAoIG9mZiA+IC0xICkge1xuXHRcdHNlbGVjdG9yID0gc3RyaXBBbmRDb2xsYXBzZSggdXJsLnNsaWNlKCBvZmYgKSApO1xuXHRcdHVybCA9IHVybC5zbGljZSggMCwgb2ZmICk7XG5cdH1cblxuXHQvLyBJZiBpdCdzIGEgZnVuY3Rpb25cblx0aWYgKCBpc0Z1bmN0aW9uKCBwYXJhbXMgKSApIHtcblxuXHRcdC8vIFdlIGFzc3VtZSB0aGF0IGl0J3MgdGhlIGNhbGxiYWNrXG5cdFx0Y2FsbGJhY2sgPSBwYXJhbXM7XG5cdFx0cGFyYW1zID0gdW5kZWZpbmVkO1xuXG5cdC8vIE90aGVyd2lzZSwgYnVpbGQgYSBwYXJhbSBzdHJpbmdcblx0fSBlbHNlIGlmICggcGFyYW1zICYmIHR5cGVvZiBwYXJhbXMgPT09IFwib2JqZWN0XCIgKSB7XG5cdFx0dHlwZSA9IFwiUE9TVFwiO1xuXHR9XG5cblx0Ly8gSWYgd2UgaGF2ZSBlbGVtZW50cyB0byBtb2RpZnksIG1ha2UgdGhlIHJlcXVlc3Rcblx0aWYgKCBzZWxmLmxlbmd0aCA+IDAgKSB7XG5cdFx0alF1ZXJ5LmFqYXgoIHtcblx0XHRcdHVybDogdXJsLFxuXG5cdFx0XHQvLyBJZiBcInR5cGVcIiB2YXJpYWJsZSBpcyB1bmRlZmluZWQsIHRoZW4gXCJHRVRcIiBtZXRob2Qgd2lsbCBiZSB1c2VkLlxuXHRcdFx0Ly8gTWFrZSB2YWx1ZSBvZiB0aGlzIGZpZWxkIGV4cGxpY2l0IHNpbmNlXG5cdFx0XHQvLyB1c2VyIGNhbiBvdmVycmlkZSBpdCB0aHJvdWdoIGFqYXhTZXR1cCBtZXRob2Rcblx0XHRcdHR5cGU6IHR5cGUgfHwgXCJHRVRcIixcblx0XHRcdGRhdGFUeXBlOiBcImh0bWxcIixcblx0XHRcdGRhdGE6IHBhcmFtc1xuXHRcdH0gKS5kb25lKCBmdW5jdGlvbiggcmVzcG9uc2VUZXh0ICkge1xuXG5cdFx0XHQvLyBTYXZlIHJlc3BvbnNlIGZvciB1c2UgaW4gY29tcGxldGUgY2FsbGJhY2tcblx0XHRcdHJlc3BvbnNlID0gYXJndW1lbnRzO1xuXG5cdFx0XHRzZWxmLmh0bWwoIHNlbGVjdG9yID9cblxuXHRcdFx0XHQvLyBJZiBhIHNlbGVjdG9yIHdhcyBzcGVjaWZpZWQsIGxvY2F0ZSB0aGUgcmlnaHQgZWxlbWVudHMgaW4gYSBkdW1teSBkaXZcblx0XHRcdFx0Ly8gRXhjbHVkZSBzY3JpcHRzIHRvIGF2b2lkIElFICdQZXJtaXNzaW9uIERlbmllZCcgZXJyb3JzXG5cdFx0XHRcdGpRdWVyeSggXCI8ZGl2PlwiICkuYXBwZW5kKCBqUXVlcnkucGFyc2VIVE1MKCByZXNwb25zZVRleHQgKSApLmZpbmQoIHNlbGVjdG9yICkgOlxuXG5cdFx0XHRcdC8vIE90aGVyd2lzZSB1c2UgdGhlIGZ1bGwgcmVzdWx0XG5cdFx0XHRcdHJlc3BvbnNlVGV4dCApO1xuXG5cdFx0Ly8gSWYgdGhlIHJlcXVlc3Qgc3VjY2VlZHMsIHRoaXMgZnVuY3Rpb24gZ2V0cyBcImRhdGFcIiwgXCJzdGF0dXNcIiwgXCJqcVhIUlwiXG5cdFx0Ly8gYnV0IHRoZXkgYXJlIGlnbm9yZWQgYmVjYXVzZSByZXNwb25zZSB3YXMgc2V0IGFib3ZlLlxuXHRcdC8vIElmIGl0IGZhaWxzLCB0aGlzIGZ1bmN0aW9uIGdldHMgXCJqcVhIUlwiLCBcInN0YXR1c1wiLCBcImVycm9yXCJcblx0XHR9ICkuYWx3YXlzKCBjYWxsYmFjayAmJiBmdW5jdGlvbigganFYSFIsIHN0YXR1cyApIHtcblx0XHRcdHNlbGYuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGNhbGxiYWNrLmFwcGx5KCB0aGlzLCByZXNwb25zZSB8fCBbIGpxWEhSLnJlc3BvbnNlVGV4dCwgc3RhdHVzLCBqcVhIUiBdICk7XG5cdFx0XHR9ICk7XG5cdFx0fSApO1xuXHR9XG5cblx0cmV0dXJuIHRoaXM7XG59O1xuXG5cblxuXG4vLyBBdHRhY2ggYSBidW5jaCBvZiBmdW5jdGlvbnMgZm9yIGhhbmRsaW5nIGNvbW1vbiBBSkFYIGV2ZW50c1xualF1ZXJ5LmVhY2goIFtcblx0XCJhamF4U3RhcnRcIixcblx0XCJhamF4U3RvcFwiLFxuXHRcImFqYXhDb21wbGV0ZVwiLFxuXHRcImFqYXhFcnJvclwiLFxuXHRcImFqYXhTdWNjZXNzXCIsXG5cdFwiYWpheFNlbmRcIlxuXSwgZnVuY3Rpb24oIGksIHR5cGUgKSB7XG5cdGpRdWVyeS5mblsgdHlwZSBdID0gZnVuY3Rpb24oIGZuICkge1xuXHRcdHJldHVybiB0aGlzLm9uKCB0eXBlLCBmbiApO1xuXHR9O1xufSApO1xuXG5cblxuXG5qUXVlcnkuZXhwci5wc2V1ZG9zLmFuaW1hdGVkID0gZnVuY3Rpb24oIGVsZW0gKSB7XG5cdHJldHVybiBqUXVlcnkuZ3JlcCggalF1ZXJ5LnRpbWVycywgZnVuY3Rpb24oIGZuICkge1xuXHRcdHJldHVybiBlbGVtID09PSBmbi5lbGVtO1xuXHR9ICkubGVuZ3RoO1xufTtcblxuXG5cblxualF1ZXJ5Lm9mZnNldCA9IHtcblx0c2V0T2Zmc2V0OiBmdW5jdGlvbiggZWxlbSwgb3B0aW9ucywgaSApIHtcblx0XHR2YXIgY3VyUG9zaXRpb24sIGN1ckxlZnQsIGN1ckNTU1RvcCwgY3VyVG9wLCBjdXJPZmZzZXQsIGN1ckNTU0xlZnQsIGNhbGN1bGF0ZVBvc2l0aW9uLFxuXHRcdFx0cG9zaXRpb24gPSBqUXVlcnkuY3NzKCBlbGVtLCBcInBvc2l0aW9uXCIgKSxcblx0XHRcdGN1ckVsZW0gPSBqUXVlcnkoIGVsZW0gKSxcblx0XHRcdHByb3BzID0ge307XG5cblx0XHQvLyBTZXQgcG9zaXRpb24gZmlyc3QsIGluLWNhc2UgdG9wL2xlZnQgYXJlIHNldCBldmVuIG9uIHN0YXRpYyBlbGVtXG5cdFx0aWYgKCBwb3NpdGlvbiA9PT0gXCJzdGF0aWNcIiApIHtcblx0XHRcdGVsZW0uc3R5bGUucG9zaXRpb24gPSBcInJlbGF0aXZlXCI7XG5cdFx0fVxuXG5cdFx0Y3VyT2Zmc2V0ID0gY3VyRWxlbS5vZmZzZXQoKTtcblx0XHRjdXJDU1NUb3AgPSBqUXVlcnkuY3NzKCBlbGVtLCBcInRvcFwiICk7XG5cdFx0Y3VyQ1NTTGVmdCA9IGpRdWVyeS5jc3MoIGVsZW0sIFwibGVmdFwiICk7XG5cdFx0Y2FsY3VsYXRlUG9zaXRpb24gPSAoIHBvc2l0aW9uID09PSBcImFic29sdXRlXCIgfHwgcG9zaXRpb24gPT09IFwiZml4ZWRcIiApICYmXG5cdFx0XHQoIGN1ckNTU1RvcCArIGN1ckNTU0xlZnQgKS5pbmRleE9mKCBcImF1dG9cIiApID4gLTE7XG5cblx0XHQvLyBOZWVkIHRvIGJlIGFibGUgdG8gY2FsY3VsYXRlIHBvc2l0aW9uIGlmIGVpdGhlclxuXHRcdC8vIHRvcCBvciBsZWZ0IGlzIGF1dG8gYW5kIHBvc2l0aW9uIGlzIGVpdGhlciBhYnNvbHV0ZSBvciBmaXhlZFxuXHRcdGlmICggY2FsY3VsYXRlUG9zaXRpb24gKSB7XG5cdFx0XHRjdXJQb3NpdGlvbiA9IGN1ckVsZW0ucG9zaXRpb24oKTtcblx0XHRcdGN1clRvcCA9IGN1clBvc2l0aW9uLnRvcDtcblx0XHRcdGN1ckxlZnQgPSBjdXJQb3NpdGlvbi5sZWZ0O1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdGN1clRvcCA9IHBhcnNlRmxvYXQoIGN1ckNTU1RvcCApIHx8IDA7XG5cdFx0XHRjdXJMZWZ0ID0gcGFyc2VGbG9hdCggY3VyQ1NTTGVmdCApIHx8IDA7XG5cdFx0fVxuXG5cdFx0aWYgKCBpc0Z1bmN0aW9uKCBvcHRpb25zICkgKSB7XG5cblx0XHRcdC8vIFVzZSBqUXVlcnkuZXh0ZW5kIGhlcmUgdG8gYWxsb3cgbW9kaWZpY2F0aW9uIG9mIGNvb3JkaW5hdGVzIGFyZ3VtZW50IChnaC0xODQ4KVxuXHRcdFx0b3B0aW9ucyA9IG9wdGlvbnMuY2FsbCggZWxlbSwgaSwgalF1ZXJ5LmV4dGVuZCgge30sIGN1ck9mZnNldCApICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBvcHRpb25zLnRvcCAhPSBudWxsICkge1xuXHRcdFx0cHJvcHMudG9wID0gKCBvcHRpb25zLnRvcCAtIGN1ck9mZnNldC50b3AgKSArIGN1clRvcDtcblx0XHR9XG5cdFx0aWYgKCBvcHRpb25zLmxlZnQgIT0gbnVsbCApIHtcblx0XHRcdHByb3BzLmxlZnQgPSAoIG9wdGlvbnMubGVmdCAtIGN1ck9mZnNldC5sZWZ0ICkgKyBjdXJMZWZ0O1xuXHRcdH1cblxuXHRcdGlmICggXCJ1c2luZ1wiIGluIG9wdGlvbnMgKSB7XG5cdFx0XHRvcHRpb25zLnVzaW5nLmNhbGwoIGVsZW0sIHByb3BzICk7XG5cblx0XHR9IGVsc2Uge1xuXHRcdFx0Y3VyRWxlbS5jc3MoIHByb3BzICk7XG5cdFx0fVxuXHR9XG59O1xuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cblx0Ly8gb2Zmc2V0KCkgcmVsYXRlcyBhbiBlbGVtZW50J3MgYm9yZGVyIGJveCB0byB0aGUgZG9jdW1lbnQgb3JpZ2luXG5cdG9mZnNldDogZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cblx0XHQvLyBQcmVzZXJ2ZSBjaGFpbmluZyBmb3Igc2V0dGVyXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIG9wdGlvbnMgPT09IHVuZGVmaW5lZCA/XG5cdFx0XHRcdHRoaXMgOlxuXHRcdFx0XHR0aGlzLmVhY2goIGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0XHRcdGpRdWVyeS5vZmZzZXQuc2V0T2Zmc2V0KCB0aGlzLCBvcHRpb25zLCBpICk7XG5cdFx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHR2YXIgcmVjdCwgd2luLFxuXHRcdFx0ZWxlbSA9IHRoaXNbIDAgXTtcblxuXHRcdGlmICggIWVsZW0gKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gUmV0dXJuIHplcm9zIGZvciBkaXNjb25uZWN0ZWQgYW5kIGhpZGRlbiAoZGlzcGxheTogbm9uZSkgZWxlbWVudHMgKGdoLTIzMTApXG5cdFx0Ly8gU3VwcG9ydDogSUUgPD0xMSBvbmx5XG5cdFx0Ly8gUnVubmluZyBnZXRCb3VuZGluZ0NsaWVudFJlY3Qgb24gYVxuXHRcdC8vIGRpc2Nvbm5lY3RlZCBub2RlIGluIElFIHRocm93cyBhbiBlcnJvclxuXHRcdGlmICggIWVsZW0uZ2V0Q2xpZW50UmVjdHMoKS5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4geyB0b3A6IDAsIGxlZnQ6IDAgfTtcblx0XHR9XG5cblx0XHQvLyBHZXQgZG9jdW1lbnQtcmVsYXRpdmUgcG9zaXRpb24gYnkgYWRkaW5nIHZpZXdwb3J0IHNjcm9sbCB0byB2aWV3cG9ydC1yZWxhdGl2ZSBnQkNSXG5cdFx0cmVjdCA9IGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cdFx0d2luID0gZWxlbS5vd25lckRvY3VtZW50LmRlZmF1bHRWaWV3O1xuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IHJlY3QudG9wICsgd2luLnBhZ2VZT2Zmc2V0LFxuXHRcdFx0bGVmdDogcmVjdC5sZWZ0ICsgd2luLnBhZ2VYT2Zmc2V0XG5cdFx0fTtcblx0fSxcblxuXHQvLyBwb3NpdGlvbigpIHJlbGF0ZXMgYW4gZWxlbWVudCdzIG1hcmdpbiBib3ggdG8gaXRzIG9mZnNldCBwYXJlbnQncyBwYWRkaW5nIGJveFxuXHQvLyBUaGlzIGNvcnJlc3BvbmRzIHRvIHRoZSBiZWhhdmlvciBvZiBDU1MgYWJzb2x1dGUgcG9zaXRpb25pbmdcblx0cG9zaXRpb246IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggIXRoaXNbIDAgXSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgb2Zmc2V0UGFyZW50LCBvZmZzZXQsIGRvYyxcblx0XHRcdGVsZW0gPSB0aGlzWyAwIF0sXG5cdFx0XHRwYXJlbnRPZmZzZXQgPSB7IHRvcDogMCwgbGVmdDogMCB9O1xuXG5cdFx0Ly8gcG9zaXRpb246Zml4ZWQgZWxlbWVudHMgYXJlIG9mZnNldCBmcm9tIHRoZSB2aWV3cG9ydCwgd2hpY2ggaXRzZWxmIGFsd2F5cyBoYXMgemVybyBvZmZzZXRcblx0XHRpZiAoIGpRdWVyeS5jc3MoIGVsZW0sIFwicG9zaXRpb25cIiApID09PSBcImZpeGVkXCIgKSB7XG5cblx0XHRcdC8vIEFzc3VtZSBwb3NpdGlvbjpmaXhlZCBpbXBsaWVzIGF2YWlsYWJpbGl0eSBvZiBnZXRCb3VuZGluZ0NsaWVudFJlY3Rcblx0XHRcdG9mZnNldCA9IGVsZW0uZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cblx0XHR9IGVsc2Uge1xuXHRcdFx0b2Zmc2V0ID0gdGhpcy5vZmZzZXQoKTtcblxuXHRcdFx0Ly8gQWNjb3VudCBmb3IgdGhlICpyZWFsKiBvZmZzZXQgcGFyZW50LCB3aGljaCBjYW4gYmUgdGhlIGRvY3VtZW50IG9yIGl0cyByb290IGVsZW1lbnRcblx0XHRcdC8vIHdoZW4gYSBzdGF0aWNhbGx5IHBvc2l0aW9uZWQgZWxlbWVudCBpcyBpZGVudGlmaWVkXG5cdFx0XHRkb2MgPSBlbGVtLm93bmVyRG9jdW1lbnQ7XG5cdFx0XHRvZmZzZXRQYXJlbnQgPSBlbGVtLm9mZnNldFBhcmVudCB8fCBkb2MuZG9jdW1lbnRFbGVtZW50O1xuXHRcdFx0d2hpbGUgKCBvZmZzZXRQYXJlbnQgJiZcblx0XHRcdFx0KCBvZmZzZXRQYXJlbnQgPT09IGRvYy5ib2R5IHx8IG9mZnNldFBhcmVudCA9PT0gZG9jLmRvY3VtZW50RWxlbWVudCApICYmXG5cdFx0XHRcdGpRdWVyeS5jc3MoIG9mZnNldFBhcmVudCwgXCJwb3NpdGlvblwiICkgPT09IFwic3RhdGljXCIgKSB7XG5cblx0XHRcdFx0b2Zmc2V0UGFyZW50ID0gb2Zmc2V0UGFyZW50LnBhcmVudE5vZGU7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIG9mZnNldFBhcmVudCAmJiBvZmZzZXRQYXJlbnQgIT09IGVsZW0gJiYgb2Zmc2V0UGFyZW50Lm5vZGVUeXBlID09PSAxICkge1xuXG5cdFx0XHRcdC8vIEluY29ycG9yYXRlIGJvcmRlcnMgaW50byBpdHMgb2Zmc2V0LCBzaW5jZSB0aGV5IGFyZSBvdXRzaWRlIGl0cyBjb250ZW50IG9yaWdpblxuXHRcdFx0XHRwYXJlbnRPZmZzZXQgPSBqUXVlcnkoIG9mZnNldFBhcmVudCApLm9mZnNldCgpO1xuXHRcdFx0XHRwYXJlbnRPZmZzZXQudG9wICs9IGpRdWVyeS5jc3MoIG9mZnNldFBhcmVudCwgXCJib3JkZXJUb3BXaWR0aFwiLCB0cnVlICk7XG5cdFx0XHRcdHBhcmVudE9mZnNldC5sZWZ0ICs9IGpRdWVyeS5jc3MoIG9mZnNldFBhcmVudCwgXCJib3JkZXJMZWZ0V2lkdGhcIiwgdHJ1ZSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIFN1YnRyYWN0IHBhcmVudCBvZmZzZXRzIGFuZCBlbGVtZW50IG1hcmdpbnNcblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiBvZmZzZXQudG9wIC0gcGFyZW50T2Zmc2V0LnRvcCAtIGpRdWVyeS5jc3MoIGVsZW0sIFwibWFyZ2luVG9wXCIsIHRydWUgKSxcblx0XHRcdGxlZnQ6IG9mZnNldC5sZWZ0IC0gcGFyZW50T2Zmc2V0LmxlZnQgLSBqUXVlcnkuY3NzKCBlbGVtLCBcIm1hcmdpbkxlZnRcIiwgdHJ1ZSApXG5cdFx0fTtcblx0fSxcblxuXHQvLyBUaGlzIG1ldGhvZCB3aWxsIHJldHVybiBkb2N1bWVudEVsZW1lbnQgaW4gdGhlIGZvbGxvd2luZyBjYXNlczpcblx0Ly8gMSkgRm9yIHRoZSBlbGVtZW50IGluc2lkZSB0aGUgaWZyYW1lIHdpdGhvdXQgb2Zmc2V0UGFyZW50LCB0aGlzIG1ldGhvZCB3aWxsIHJldHVyblxuXHQvLyAgICBkb2N1bWVudEVsZW1lbnQgb2YgdGhlIHBhcmVudCB3aW5kb3dcblx0Ly8gMikgRm9yIHRoZSBoaWRkZW4gb3IgZGV0YWNoZWQgZWxlbWVudFxuXHQvLyAzKSBGb3IgYm9keSBvciBodG1sIGVsZW1lbnQsIGkuZS4gaW4gY2FzZSBvZiB0aGUgaHRtbCBub2RlIC0gaXQgd2lsbCByZXR1cm4gaXRzZWxmXG5cdC8vXG5cdC8vIGJ1dCB0aG9zZSBleGNlcHRpb25zIHdlcmUgbmV2ZXIgcHJlc2VudGVkIGFzIGEgcmVhbCBsaWZlIHVzZS1jYXNlc1xuXHQvLyBhbmQgbWlnaHQgYmUgY29uc2lkZXJlZCBhcyBtb3JlIHByZWZlcmFibGUgcmVzdWx0cy5cblx0Ly9cblx0Ly8gVGhpcyBsb2dpYywgaG93ZXZlciwgaXMgbm90IGd1YXJhbnRlZWQgYW5kIGNhbiBjaGFuZ2UgYXQgYW55IHBvaW50IGluIHRoZSBmdXR1cmVcblx0b2Zmc2V0UGFyZW50OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIG9mZnNldFBhcmVudCA9IHRoaXMub2Zmc2V0UGFyZW50O1xuXG5cdFx0XHR3aGlsZSAoIG9mZnNldFBhcmVudCAmJiBqUXVlcnkuY3NzKCBvZmZzZXRQYXJlbnQsIFwicG9zaXRpb25cIiApID09PSBcInN0YXRpY1wiICkge1xuXHRcdFx0XHRvZmZzZXRQYXJlbnQgPSBvZmZzZXRQYXJlbnQub2Zmc2V0UGFyZW50O1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gb2Zmc2V0UGFyZW50IHx8IGRvY3VtZW50RWxlbWVudDtcblx0XHR9ICk7XG5cdH1cbn0gKTtcblxuLy8gQ3JlYXRlIHNjcm9sbExlZnQgYW5kIHNjcm9sbFRvcCBtZXRob2RzXG5qUXVlcnkuZWFjaCggeyBzY3JvbGxMZWZ0OiBcInBhZ2VYT2Zmc2V0XCIsIHNjcm9sbFRvcDogXCJwYWdlWU9mZnNldFwiIH0sIGZ1bmN0aW9uKCBtZXRob2QsIHByb3AgKSB7XG5cdHZhciB0b3AgPSBcInBhZ2VZT2Zmc2V0XCIgPT09IHByb3A7XG5cblx0alF1ZXJ5LmZuWyBtZXRob2QgXSA9IGZ1bmN0aW9uKCB2YWwgKSB7XG5cdFx0cmV0dXJuIGFjY2VzcyggdGhpcywgZnVuY3Rpb24oIGVsZW0sIG1ldGhvZCwgdmFsICkge1xuXG5cdFx0XHQvLyBDb2FsZXNjZSBkb2N1bWVudHMgYW5kIHdpbmRvd3Ncblx0XHRcdHZhciB3aW47XG5cdFx0XHRpZiAoIGlzV2luZG93KCBlbGVtICkgKSB7XG5cdFx0XHRcdHdpbiA9IGVsZW07XG5cdFx0XHR9IGVsc2UgaWYgKCBlbGVtLm5vZGVUeXBlID09PSA5ICkge1xuXHRcdFx0XHR3aW4gPSBlbGVtLmRlZmF1bHRWaWV3O1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHZhbCA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRyZXR1cm4gd2luID8gd2luWyBwcm9wIF0gOiBlbGVtWyBtZXRob2QgXTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB3aW4gKSB7XG5cdFx0XHRcdHdpbi5zY3JvbGxUbyhcblx0XHRcdFx0XHQhdG9wID8gdmFsIDogd2luLnBhZ2VYT2Zmc2V0LFxuXHRcdFx0XHRcdHRvcCA/IHZhbCA6IHdpbi5wYWdlWU9mZnNldFxuXHRcdFx0XHQpO1xuXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRlbGVtWyBtZXRob2QgXSA9IHZhbDtcblx0XHRcdH1cblx0XHR9LCBtZXRob2QsIHZhbCwgYXJndW1lbnRzLmxlbmd0aCApO1xuXHR9O1xufSApO1xuXG4vLyBTdXBwb3J0OiBTYWZhcmkgPD03IC0gOS4xLCBDaHJvbWUgPD0zNyAtIDQ5XG4vLyBBZGQgdGhlIHRvcC9sZWZ0IGNzc0hvb2tzIHVzaW5nIGpRdWVyeS5mbi5wb3NpdGlvblxuLy8gV2Via2l0IGJ1ZzogaHR0cHM6Ly9idWdzLndlYmtpdC5vcmcvc2hvd19idWcuY2dpP2lkPTI5MDg0XG4vLyBCbGluayBidWc6IGh0dHBzOi8vYnVncy5jaHJvbWl1bS5vcmcvcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTU4OTM0N1xuLy8gZ2V0Q29tcHV0ZWRTdHlsZSByZXR1cm5zIHBlcmNlbnQgd2hlbiBzcGVjaWZpZWQgZm9yIHRvcC9sZWZ0L2JvdHRvbS9yaWdodDtcbi8vIHJhdGhlciB0aGFuIG1ha2UgdGhlIGNzcyBtb2R1bGUgZGVwZW5kIG9uIHRoZSBvZmZzZXQgbW9kdWxlLCBqdXN0IGNoZWNrIGZvciBpdCBoZXJlXG5qUXVlcnkuZWFjaCggWyBcInRvcFwiLCBcImxlZnRcIiBdLCBmdW5jdGlvbiggaSwgcHJvcCApIHtcblx0alF1ZXJ5LmNzc0hvb2tzWyBwcm9wIF0gPSBhZGRHZXRIb29rSWYoIHN1cHBvcnQucGl4ZWxQb3NpdGlvbixcblx0XHRmdW5jdGlvbiggZWxlbSwgY29tcHV0ZWQgKSB7XG5cdFx0XHRpZiAoIGNvbXB1dGVkICkge1xuXHRcdFx0XHRjb21wdXRlZCA9IGN1ckNTUyggZWxlbSwgcHJvcCApO1xuXG5cdFx0XHRcdC8vIElmIGN1ckNTUyByZXR1cm5zIHBlcmNlbnRhZ2UsIGZhbGxiYWNrIHRvIG9mZnNldFxuXHRcdFx0XHRyZXR1cm4gcm51bW5vbnB4LnRlc3QoIGNvbXB1dGVkICkgP1xuXHRcdFx0XHRcdGpRdWVyeSggZWxlbSApLnBvc2l0aW9uKClbIHByb3AgXSArIFwicHhcIiA6XG5cdFx0XHRcdFx0Y29tcHV0ZWQ7XG5cdFx0XHR9XG5cdFx0fVxuXHQpO1xufSApO1xuXG5cbi8vIENyZWF0ZSBpbm5lckhlaWdodCwgaW5uZXJXaWR0aCwgaGVpZ2h0LCB3aWR0aCwgb3V0ZXJIZWlnaHQgYW5kIG91dGVyV2lkdGggbWV0aG9kc1xualF1ZXJ5LmVhY2goIHsgSGVpZ2h0OiBcImhlaWdodFwiLCBXaWR0aDogXCJ3aWR0aFwiIH0sIGZ1bmN0aW9uKCBuYW1lLCB0eXBlICkge1xuXHRqUXVlcnkuZWFjaCggeyBwYWRkaW5nOiBcImlubmVyXCIgKyBuYW1lLCBjb250ZW50OiB0eXBlLCBcIlwiOiBcIm91dGVyXCIgKyBuYW1lIH0sXG5cdFx0ZnVuY3Rpb24oIGRlZmF1bHRFeHRyYSwgZnVuY05hbWUgKSB7XG5cblx0XHQvLyBNYXJnaW4gaXMgb25seSBmb3Igb3V0ZXJIZWlnaHQsIG91dGVyV2lkdGhcblx0XHRqUXVlcnkuZm5bIGZ1bmNOYW1lIF0gPSBmdW5jdGlvbiggbWFyZ2luLCB2YWx1ZSApIHtcblx0XHRcdHZhciBjaGFpbmFibGUgPSBhcmd1bWVudHMubGVuZ3RoICYmICggZGVmYXVsdEV4dHJhIHx8IHR5cGVvZiBtYXJnaW4gIT09IFwiYm9vbGVhblwiICksXG5cdFx0XHRcdGV4dHJhID0gZGVmYXVsdEV4dHJhIHx8ICggbWFyZ2luID09PSB0cnVlIHx8IHZhbHVlID09PSB0cnVlID8gXCJtYXJnaW5cIiA6IFwiYm9yZGVyXCIgKTtcblxuXHRcdFx0cmV0dXJuIGFjY2VzcyggdGhpcywgZnVuY3Rpb24oIGVsZW0sIHR5cGUsIHZhbHVlICkge1xuXHRcdFx0XHR2YXIgZG9jO1xuXG5cdFx0XHRcdGlmICggaXNXaW5kb3coIGVsZW0gKSApIHtcblxuXHRcdFx0XHRcdC8vICQoIHdpbmRvdyApLm91dGVyV2lkdGgvSGVpZ2h0IHJldHVybiB3L2ggaW5jbHVkaW5nIHNjcm9sbGJhcnMgKGdoLTE3MjkpXG5cdFx0XHRcdFx0cmV0dXJuIGZ1bmNOYW1lLmluZGV4T2YoIFwib3V0ZXJcIiApID09PSAwID9cblx0XHRcdFx0XHRcdGVsZW1bIFwiaW5uZXJcIiArIG5hbWUgXSA6XG5cdFx0XHRcdFx0XHRlbGVtLmRvY3VtZW50LmRvY3VtZW50RWxlbWVudFsgXCJjbGllbnRcIiArIG5hbWUgXTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEdldCBkb2N1bWVudCB3aWR0aCBvciBoZWlnaHRcblx0XHRcdFx0aWYgKCBlbGVtLm5vZGVUeXBlID09PSA5ICkge1xuXHRcdFx0XHRcdGRvYyA9IGVsZW0uZG9jdW1lbnRFbGVtZW50O1xuXG5cdFx0XHRcdFx0Ly8gRWl0aGVyIHNjcm9sbFtXaWR0aC9IZWlnaHRdIG9yIG9mZnNldFtXaWR0aC9IZWlnaHRdIG9yIGNsaWVudFtXaWR0aC9IZWlnaHRdLFxuXHRcdFx0XHRcdC8vIHdoaWNoZXZlciBpcyBncmVhdGVzdFxuXHRcdFx0XHRcdHJldHVybiBNYXRoLm1heChcblx0XHRcdFx0XHRcdGVsZW0uYm9keVsgXCJzY3JvbGxcIiArIG5hbWUgXSwgZG9jWyBcInNjcm9sbFwiICsgbmFtZSBdLFxuXHRcdFx0XHRcdFx0ZWxlbS5ib2R5WyBcIm9mZnNldFwiICsgbmFtZSBdLCBkb2NbIFwib2Zmc2V0XCIgKyBuYW1lIF0sXG5cdFx0XHRcdFx0XHRkb2NbIFwiY2xpZW50XCIgKyBuYW1lIF1cblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIHZhbHVlID09PSB1bmRlZmluZWQgP1xuXG5cdFx0XHRcdFx0Ly8gR2V0IHdpZHRoIG9yIGhlaWdodCBvbiB0aGUgZWxlbWVudCwgcmVxdWVzdGluZyBidXQgbm90IGZvcmNpbmcgcGFyc2VGbG9hdFxuXHRcdFx0XHRcdGpRdWVyeS5jc3MoIGVsZW0sIHR5cGUsIGV4dHJhICkgOlxuXG5cdFx0XHRcdFx0Ly8gU2V0IHdpZHRoIG9yIGhlaWdodCBvbiB0aGUgZWxlbWVudFxuXHRcdFx0XHRcdGpRdWVyeS5zdHlsZSggZWxlbSwgdHlwZSwgdmFsdWUsIGV4dHJhICk7XG5cdFx0XHR9LCB0eXBlLCBjaGFpbmFibGUgPyBtYXJnaW4gOiB1bmRlZmluZWQsIGNoYWluYWJsZSApO1xuXHRcdH07XG5cdH0gKTtcbn0gKTtcblxuXG5qUXVlcnkuZWFjaCggKCBcImJsdXIgZm9jdXMgZm9jdXNpbiBmb2N1c291dCByZXNpemUgc2Nyb2xsIGNsaWNrIGRibGNsaWNrIFwiICtcblx0XCJtb3VzZWRvd24gbW91c2V1cCBtb3VzZW1vdmUgbW91c2VvdmVyIG1vdXNlb3V0IG1vdXNlZW50ZXIgbW91c2VsZWF2ZSBcIiArXG5cdFwiY2hhbmdlIHNlbGVjdCBzdWJtaXQga2V5ZG93biBrZXlwcmVzcyBrZXl1cCBjb250ZXh0bWVudVwiICkuc3BsaXQoIFwiIFwiICksXG5cdGZ1bmN0aW9uKCBpLCBuYW1lICkge1xuXG5cdC8vIEhhbmRsZSBldmVudCBiaW5kaW5nXG5cdGpRdWVyeS5mblsgbmFtZSBdID0gZnVuY3Rpb24oIGRhdGEsIGZuICkge1xuXHRcdHJldHVybiBhcmd1bWVudHMubGVuZ3RoID4gMCA/XG5cdFx0XHR0aGlzLm9uKCBuYW1lLCBudWxsLCBkYXRhLCBmbiApIDpcblx0XHRcdHRoaXMudHJpZ2dlciggbmFtZSApO1xuXHR9O1xufSApO1xuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cdGhvdmVyOiBmdW5jdGlvbiggZm5PdmVyLCBmbk91dCApIHtcblx0XHRyZXR1cm4gdGhpcy5tb3VzZWVudGVyKCBmbk92ZXIgKS5tb3VzZWxlYXZlKCBmbk91dCB8fCBmbk92ZXIgKTtcblx0fVxufSApO1xuXG5cblxuXG5qUXVlcnkuZm4uZXh0ZW5kKCB7XG5cblx0YmluZDogZnVuY3Rpb24oIHR5cGVzLCBkYXRhLCBmbiApIHtcblx0XHRyZXR1cm4gdGhpcy5vbiggdHlwZXMsIG51bGwsIGRhdGEsIGZuICk7XG5cdH0sXG5cdHVuYmluZDogZnVuY3Rpb24oIHR5cGVzLCBmbiApIHtcblx0XHRyZXR1cm4gdGhpcy5vZmYoIHR5cGVzLCBudWxsLCBmbiApO1xuXHR9LFxuXG5cdGRlbGVnYXRlOiBmdW5jdGlvbiggc2VsZWN0b3IsIHR5cGVzLCBkYXRhLCBmbiApIHtcblx0XHRyZXR1cm4gdGhpcy5vbiggdHlwZXMsIHNlbGVjdG9yLCBkYXRhLCBmbiApO1xuXHR9LFxuXHR1bmRlbGVnYXRlOiBmdW5jdGlvbiggc2VsZWN0b3IsIHR5cGVzLCBmbiApIHtcblxuXHRcdC8vICggbmFtZXNwYWNlICkgb3IgKCBzZWxlY3RvciwgdHlwZXMgWywgZm5dIClcblx0XHRyZXR1cm4gYXJndW1lbnRzLmxlbmd0aCA9PT0gMSA/XG5cdFx0XHR0aGlzLm9mZiggc2VsZWN0b3IsIFwiKipcIiApIDpcblx0XHRcdHRoaXMub2ZmKCB0eXBlcywgc2VsZWN0b3IgfHwgXCIqKlwiLCBmbiApO1xuXHR9XG59ICk7XG5cbi8vIEJpbmQgYSBmdW5jdGlvbiB0byBhIGNvbnRleHQsIG9wdGlvbmFsbHkgcGFydGlhbGx5IGFwcGx5aW5nIGFueVxuLy8gYXJndW1lbnRzLlxuLy8galF1ZXJ5LnByb3h5IGlzIGRlcHJlY2F0ZWQgdG8gcHJvbW90ZSBzdGFuZGFyZHMgKHNwZWNpZmljYWxseSBGdW5jdGlvbiNiaW5kKVxuLy8gSG93ZXZlciwgaXQgaXMgbm90IHNsYXRlZCBmb3IgcmVtb3ZhbCBhbnkgdGltZSBzb29uXG5qUXVlcnkucHJveHkgPSBmdW5jdGlvbiggZm4sIGNvbnRleHQgKSB7XG5cdHZhciB0bXAsIGFyZ3MsIHByb3h5O1xuXG5cdGlmICggdHlwZW9mIGNvbnRleHQgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0dG1wID0gZm5bIGNvbnRleHQgXTtcblx0XHRjb250ZXh0ID0gZm47XG5cdFx0Zm4gPSB0bXA7XG5cdH1cblxuXHQvLyBRdWljayBjaGVjayB0byBkZXRlcm1pbmUgaWYgdGFyZ2V0IGlzIGNhbGxhYmxlLCBpbiB0aGUgc3BlY1xuXHQvLyB0aGlzIHRocm93cyBhIFR5cGVFcnJvciwgYnV0IHdlIHdpbGwganVzdCByZXR1cm4gdW5kZWZpbmVkLlxuXHRpZiAoICFpc0Z1bmN0aW9uKCBmbiApICkge1xuXHRcdHJldHVybiB1bmRlZmluZWQ7XG5cdH1cblxuXHQvLyBTaW11bGF0ZWQgYmluZFxuXHRhcmdzID0gc2xpY2UuY2FsbCggYXJndW1lbnRzLCAyICk7XG5cdHByb3h5ID0gZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIGZuLmFwcGx5KCBjb250ZXh0IHx8IHRoaXMsIGFyZ3MuY29uY2F0KCBzbGljZS5jYWxsKCBhcmd1bWVudHMgKSApICk7XG5cdH07XG5cblx0Ly8gU2V0IHRoZSBndWlkIG9mIHVuaXF1ZSBoYW5kbGVyIHRvIHRoZSBzYW1lIG9mIG9yaWdpbmFsIGhhbmRsZXIsIHNvIGl0IGNhbiBiZSByZW1vdmVkXG5cdHByb3h5Lmd1aWQgPSBmbi5ndWlkID0gZm4uZ3VpZCB8fCBqUXVlcnkuZ3VpZCsrO1xuXG5cdHJldHVybiBwcm94eTtcbn07XG5cbmpRdWVyeS5ob2xkUmVhZHkgPSBmdW5jdGlvbiggaG9sZCApIHtcblx0aWYgKCBob2xkICkge1xuXHRcdGpRdWVyeS5yZWFkeVdhaXQrKztcblx0fSBlbHNlIHtcblx0XHRqUXVlcnkucmVhZHkoIHRydWUgKTtcblx0fVxufTtcbmpRdWVyeS5pc0FycmF5ID0gQXJyYXkuaXNBcnJheTtcbmpRdWVyeS5wYXJzZUpTT04gPSBKU09OLnBhcnNlO1xualF1ZXJ5Lm5vZGVOYW1lID0gbm9kZU5hbWU7XG5qUXVlcnkuaXNGdW5jdGlvbiA9IGlzRnVuY3Rpb247XG5qUXVlcnkuaXNXaW5kb3cgPSBpc1dpbmRvdztcbmpRdWVyeS5jYW1lbENhc2UgPSBjYW1lbENhc2U7XG5qUXVlcnkudHlwZSA9IHRvVHlwZTtcblxualF1ZXJ5Lm5vdyA9IERhdGUubm93O1xuXG5qUXVlcnkuaXNOdW1lcmljID0gZnVuY3Rpb24oIG9iaiApIHtcblxuXHQvLyBBcyBvZiBqUXVlcnkgMy4wLCBpc051bWVyaWMgaXMgbGltaXRlZCB0b1xuXHQvLyBzdHJpbmdzIGFuZCBudW1iZXJzIChwcmltaXRpdmVzIG9yIG9iamVjdHMpXG5cdC8vIHRoYXQgY2FuIGJlIGNvZXJjZWQgdG8gZmluaXRlIG51bWJlcnMgKGdoLTI2NjIpXG5cdHZhciB0eXBlID0galF1ZXJ5LnR5cGUoIG9iaiApO1xuXHRyZXR1cm4gKCB0eXBlID09PSBcIm51bWJlclwiIHx8IHR5cGUgPT09IFwic3RyaW5nXCIgKSAmJlxuXG5cdFx0Ly8gcGFyc2VGbG9hdCBOYU5zIG51bWVyaWMtY2FzdCBmYWxzZSBwb3NpdGl2ZXMgKFwiXCIpXG5cdFx0Ly8gLi4uYnV0IG1pc2ludGVycHJldHMgbGVhZGluZy1udW1iZXIgc3RyaW5ncywgcGFydGljdWxhcmx5IGhleCBsaXRlcmFscyAoXCIweC4uLlwiKVxuXHRcdC8vIHN1YnRyYWN0aW9uIGZvcmNlcyBpbmZpbml0aWVzIHRvIE5hTlxuXHRcdCFpc05hTiggb2JqIC0gcGFyc2VGbG9hdCggb2JqICkgKTtcbn07XG5cblxuXG5cbi8vIFJlZ2lzdGVyIGFzIGEgbmFtZWQgQU1EIG1vZHVsZSwgc2luY2UgalF1ZXJ5IGNhbiBiZSBjb25jYXRlbmF0ZWQgd2l0aCBvdGhlclxuLy8gZmlsZXMgdGhhdCBtYXkgdXNlIGRlZmluZSwgYnV0IG5vdCB2aWEgYSBwcm9wZXIgY29uY2F0ZW5hdGlvbiBzY3JpcHQgdGhhdFxuLy8gdW5kZXJzdGFuZHMgYW5vbnltb3VzIEFNRCBtb2R1bGVzLiBBIG5hbWVkIEFNRCBpcyBzYWZlc3QgYW5kIG1vc3Qgcm9idXN0XG4vLyB3YXkgdG8gcmVnaXN0ZXIuIExvd2VyY2FzZSBqcXVlcnkgaXMgdXNlZCBiZWNhdXNlIEFNRCBtb2R1bGUgbmFtZXMgYXJlXG4vLyBkZXJpdmVkIGZyb20gZmlsZSBuYW1lcywgYW5kIGpRdWVyeSBpcyBub3JtYWxseSBkZWxpdmVyZWQgaW4gYSBsb3dlcmNhc2Vcbi8vIGZpbGUgbmFtZS4gRG8gdGhpcyBhZnRlciBjcmVhdGluZyB0aGUgZ2xvYmFsIHNvIHRoYXQgaWYgYW4gQU1EIG1vZHVsZSB3YW50c1xuLy8gdG8gY2FsbCBub0NvbmZsaWN0IHRvIGhpZGUgdGhpcyB2ZXJzaW9uIG9mIGpRdWVyeSwgaXQgd2lsbCB3b3JrLlxuXG4vLyBOb3RlIHRoYXQgZm9yIG1heGltdW0gcG9ydGFiaWxpdHksIGxpYnJhcmllcyB0aGF0IGFyZSBub3QgalF1ZXJ5IHNob3VsZFxuLy8gZGVjbGFyZSB0aGVtc2VsdmVzIGFzIGFub255bW91cyBtb2R1bGVzLCBhbmQgYXZvaWQgc2V0dGluZyBhIGdsb2JhbCBpZiBhblxuLy8gQU1EIGxvYWRlciBpcyBwcmVzZW50LiBqUXVlcnkgaXMgYSBzcGVjaWFsIGNhc2UuIEZvciBtb3JlIGluZm9ybWF0aW9uLCBzZWVcbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9qcmJ1cmtlL3JlcXVpcmVqcy93aWtpL1VwZGF0aW5nLWV4aXN0aW5nLWxpYnJhcmllcyN3aWtpLWFub25cblxuaWYgKCB0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZCApIHtcblx0ZGVmaW5lKCBcImpxdWVyeVwiLCBbXSwgZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIGpRdWVyeTtcblx0fSApO1xufVxuXG5cblxuXG52YXJcblxuXHQvLyBNYXAgb3ZlciBqUXVlcnkgaW4gY2FzZSBvZiBvdmVyd3JpdGVcblx0X2pRdWVyeSA9IHdpbmRvdy5qUXVlcnksXG5cblx0Ly8gTWFwIG92ZXIgdGhlICQgaW4gY2FzZSBvZiBvdmVyd3JpdGVcblx0XyQgPSB3aW5kb3cuJDtcblxualF1ZXJ5Lm5vQ29uZmxpY3QgPSBmdW5jdGlvbiggZGVlcCApIHtcblx0aWYgKCB3aW5kb3cuJCA9PT0galF1ZXJ5ICkge1xuXHRcdHdpbmRvdy4kID0gXyQ7XG5cdH1cblxuXHRpZiAoIGRlZXAgJiYgd2luZG93LmpRdWVyeSA9PT0galF1ZXJ5ICkge1xuXHRcdHdpbmRvdy5qUXVlcnkgPSBfalF1ZXJ5O1xuXHR9XG5cblx0cmV0dXJuIGpRdWVyeTtcbn07XG5cbi8vIEV4cG9zZSBqUXVlcnkgYW5kICQgaWRlbnRpZmllcnMsIGV2ZW4gaW4gQU1EXG4vLyAoIzcxMDIjY29tbWVudDoxMCwgaHR0cHM6Ly9naXRodWIuY29tL2pxdWVyeS9qcXVlcnkvcHVsbC81NTcpXG4vLyBhbmQgQ29tbW9uSlMgZm9yIGJyb3dzZXIgZW11bGF0b3JzICgjMTM1NjYpXG5pZiAoICFub0dsb2JhbCApIHtcblx0d2luZG93LmpRdWVyeSA9IHdpbmRvdy4kID0galF1ZXJ5O1xufVxuXG5cblxuXG5yZXR1cm4galF1ZXJ5O1xufSApO1xuIiwiLyohIGpRdWVyeSBVSSAtIHYxLjEyLjEgLSAyMDE2LTA5LTE0XG4qIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiogSW5jbHVkZXM6IHdpZGdldC5qcywgcG9zaXRpb24uanMsIGRhdGEuanMsIGRpc2FibGUtc2VsZWN0aW9uLmpzLCBlZmZlY3QuanMsIGVmZmVjdHMvZWZmZWN0LWJsaW5kLmpzLCBlZmZlY3RzL2VmZmVjdC1ib3VuY2UuanMsIGVmZmVjdHMvZWZmZWN0LWNsaXAuanMsIGVmZmVjdHMvZWZmZWN0LWRyb3AuanMsIGVmZmVjdHMvZWZmZWN0LWV4cGxvZGUuanMsIGVmZmVjdHMvZWZmZWN0LWZhZGUuanMsIGVmZmVjdHMvZWZmZWN0LWZvbGQuanMsIGVmZmVjdHMvZWZmZWN0LWhpZ2hsaWdodC5qcywgZWZmZWN0cy9lZmZlY3QtcHVmZi5qcywgZWZmZWN0cy9lZmZlY3QtcHVsc2F0ZS5qcywgZWZmZWN0cy9lZmZlY3Qtc2NhbGUuanMsIGVmZmVjdHMvZWZmZWN0LXNoYWtlLmpzLCBlZmZlY3RzL2VmZmVjdC1zaXplLmpzLCBlZmZlY3RzL2VmZmVjdC1zbGlkZS5qcywgZWZmZWN0cy9lZmZlY3QtdHJhbnNmZXIuanMsIGZvY3VzYWJsZS5qcywgZm9ybS1yZXNldC1taXhpbi5qcywganF1ZXJ5LTEtNy5qcywga2V5Y29kZS5qcywgbGFiZWxzLmpzLCBzY3JvbGwtcGFyZW50LmpzLCB0YWJiYWJsZS5qcywgdW5pcXVlLWlkLmpzLCB3aWRnZXRzL2FjY29yZGlvbi5qcywgd2lkZ2V0cy9hdXRvY29tcGxldGUuanMsIHdpZGdldHMvYnV0dG9uLmpzLCB3aWRnZXRzL2NoZWNrYm94cmFkaW8uanMsIHdpZGdldHMvY29udHJvbGdyb3VwLmpzLCB3aWRnZXRzL2RhdGVwaWNrZXIuanMsIHdpZGdldHMvZGlhbG9nLmpzLCB3aWRnZXRzL2RyYWdnYWJsZS5qcywgd2lkZ2V0cy9kcm9wcGFibGUuanMsIHdpZGdldHMvbWVudS5qcywgd2lkZ2V0cy9tb3VzZS5qcywgd2lkZ2V0cy9wcm9ncmVzc2Jhci5qcywgd2lkZ2V0cy9yZXNpemFibGUuanMsIHdpZGdldHMvc2VsZWN0YWJsZS5qcywgd2lkZ2V0cy9zZWxlY3RtZW51LmpzLCB3aWRnZXRzL3NsaWRlci5qcywgd2lkZ2V0cy9zb3J0YWJsZS5qcywgd2lkZ2V0cy9zcGlubmVyLmpzLCB3aWRnZXRzL3RhYnMuanMsIHdpZGdldHMvdG9vbHRpcC5qc1xuKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yczsgTGljZW5zZWQgTUlUICovXG5cbihmdW5jdGlvbiggZmFjdG9yeSApIHtcblx0aWYgKCB0eXBlb2YgZGVmaW5lID09PSBcImZ1bmN0aW9uXCIgJiYgZGVmaW5lLmFtZCApIHtcblxuXHRcdC8vIEFNRC4gUmVnaXN0ZXIgYXMgYW4gYW5vbnltb3VzIG1vZHVsZS5cblx0XHRkZWZpbmUoWyBcImpxdWVyeVwiIF0sIGZhY3RvcnkgKTtcblx0fSBlbHNlIHtcblxuXHRcdC8vIEJyb3dzZXIgZ2xvYmFsc1xuXHRcdGZhY3RvcnkoIGpRdWVyeSApO1xuXHR9XG59KGZ1bmN0aW9uKCAkICkge1xuXG4kLnVpID0gJC51aSB8fCB7fTtcblxudmFyIHZlcnNpb24gPSAkLnVpLnZlcnNpb24gPSBcIjEuMTIuMVwiO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFdpZGdldCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogV2lkZ2V0XG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogUHJvdmlkZXMgYSBmYWN0b3J5IGZvciBjcmVhdGluZyBzdGF0ZWZ1bCB3aWRnZXRzIHdpdGggYSBjb21tb24gQVBJLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2pRdWVyeS53aWRnZXQvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vd2lkZ2V0L1xuXG5cblxudmFyIHdpZGdldFV1aWQgPSAwO1xudmFyIHdpZGdldFNsaWNlID0gQXJyYXkucHJvdG90eXBlLnNsaWNlO1xuXG4kLmNsZWFuRGF0YSA9ICggZnVuY3Rpb24oIG9yaWcgKSB7XG5cdHJldHVybiBmdW5jdGlvbiggZWxlbXMgKSB7XG5cdFx0dmFyIGV2ZW50cywgZWxlbSwgaTtcblx0XHRmb3IgKCBpID0gMDsgKCBlbGVtID0gZWxlbXNbIGkgXSApICE9IG51bGw7IGkrKyApIHtcblx0XHRcdHRyeSB7XG5cblx0XHRcdFx0Ly8gT25seSB0cmlnZ2VyIHJlbW92ZSB3aGVuIG5lY2Vzc2FyeSB0byBzYXZlIHRpbWVcblx0XHRcdFx0ZXZlbnRzID0gJC5fZGF0YSggZWxlbSwgXCJldmVudHNcIiApO1xuXHRcdFx0XHRpZiAoIGV2ZW50cyAmJiBldmVudHMucmVtb3ZlICkge1xuXHRcdFx0XHRcdCQoIGVsZW0gKS50cmlnZ2VySGFuZGxlciggXCJyZW1vdmVcIiApO1xuXHRcdFx0XHR9XG5cblx0XHRcdC8vIEh0dHA6Ly9idWdzLmpxdWVyeS5jb20vdGlja2V0LzgyMzVcblx0XHRcdH0gY2F0Y2ggKCBlICkge31cblx0XHR9XG5cdFx0b3JpZyggZWxlbXMgKTtcblx0fTtcbn0gKSggJC5jbGVhbkRhdGEgKTtcblxuJC53aWRnZXQgPSBmdW5jdGlvbiggbmFtZSwgYmFzZSwgcHJvdG90eXBlICkge1xuXHR2YXIgZXhpc3RpbmdDb25zdHJ1Y3RvciwgY29uc3RydWN0b3IsIGJhc2VQcm90b3R5cGU7XG5cblx0Ly8gUHJveGllZFByb3RvdHlwZSBhbGxvd3MgdGhlIHByb3ZpZGVkIHByb3RvdHlwZSB0byByZW1haW4gdW5tb2RpZmllZFxuXHQvLyBzbyB0aGF0IGl0IGNhbiBiZSB1c2VkIGFzIGEgbWl4aW4gZm9yIG11bHRpcGxlIHdpZGdldHMgKCM4ODc2KVxuXHR2YXIgcHJveGllZFByb3RvdHlwZSA9IHt9O1xuXG5cdHZhciBuYW1lc3BhY2UgPSBuYW1lLnNwbGl0KCBcIi5cIiApWyAwIF07XG5cdG5hbWUgPSBuYW1lLnNwbGl0KCBcIi5cIiApWyAxIF07XG5cdHZhciBmdWxsTmFtZSA9IG5hbWVzcGFjZSArIFwiLVwiICsgbmFtZTtcblxuXHRpZiAoICFwcm90b3R5cGUgKSB7XG5cdFx0cHJvdG90eXBlID0gYmFzZTtcblx0XHRiYXNlID0gJC5XaWRnZXQ7XG5cdH1cblxuXHRpZiAoICQuaXNBcnJheSggcHJvdG90eXBlICkgKSB7XG5cdFx0cHJvdG90eXBlID0gJC5leHRlbmQuYXBwbHkoIG51bGwsIFsge30gXS5jb25jYXQoIHByb3RvdHlwZSApICk7XG5cdH1cblxuXHQvLyBDcmVhdGUgc2VsZWN0b3IgZm9yIHBsdWdpblxuXHQkLmV4cHJbIFwiOlwiIF1bIGZ1bGxOYW1lLnRvTG93ZXJDYXNlKCkgXSA9IGZ1bmN0aW9uKCBlbGVtICkge1xuXHRcdHJldHVybiAhISQuZGF0YSggZWxlbSwgZnVsbE5hbWUgKTtcblx0fTtcblxuXHQkWyBuYW1lc3BhY2UgXSA9ICRbIG5hbWVzcGFjZSBdIHx8IHt9O1xuXHRleGlzdGluZ0NvbnN0cnVjdG9yID0gJFsgbmFtZXNwYWNlIF1bIG5hbWUgXTtcblx0Y29uc3RydWN0b3IgPSAkWyBuYW1lc3BhY2UgXVsgbmFtZSBdID0gZnVuY3Rpb24oIG9wdGlvbnMsIGVsZW1lbnQgKSB7XG5cblx0XHQvLyBBbGxvdyBpbnN0YW50aWF0aW9uIHdpdGhvdXQgXCJuZXdcIiBrZXl3b3JkXG5cdFx0aWYgKCAhdGhpcy5fY3JlYXRlV2lkZ2V0ICkge1xuXHRcdFx0cmV0dXJuIG5ldyBjb25zdHJ1Y3Rvciggb3B0aW9ucywgZWxlbWVudCApO1xuXHRcdH1cblxuXHRcdC8vIEFsbG93IGluc3RhbnRpYXRpb24gd2l0aG91dCBpbml0aWFsaXppbmcgZm9yIHNpbXBsZSBpbmhlcml0YW5jZVxuXHRcdC8vIG11c3QgdXNlIFwibmV3XCIga2V5d29yZCAodGhlIGNvZGUgYWJvdmUgYWx3YXlzIHBhc3NlcyBhcmdzKVxuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdHRoaXMuX2NyZWF0ZVdpZGdldCggb3B0aW9ucywgZWxlbWVudCApO1xuXHRcdH1cblx0fTtcblxuXHQvLyBFeHRlbmQgd2l0aCB0aGUgZXhpc3RpbmcgY29uc3RydWN0b3IgdG8gY2Fycnkgb3ZlciBhbnkgc3RhdGljIHByb3BlcnRpZXNcblx0JC5leHRlbmQoIGNvbnN0cnVjdG9yLCBleGlzdGluZ0NvbnN0cnVjdG9yLCB7XG5cdFx0dmVyc2lvbjogcHJvdG90eXBlLnZlcnNpb24sXG5cblx0XHQvLyBDb3B5IHRoZSBvYmplY3QgdXNlZCB0byBjcmVhdGUgdGhlIHByb3RvdHlwZSBpbiBjYXNlIHdlIG5lZWQgdG9cblx0XHQvLyByZWRlZmluZSB0aGUgd2lkZ2V0IGxhdGVyXG5cdFx0X3Byb3RvOiAkLmV4dGVuZCgge30sIHByb3RvdHlwZSApLFxuXG5cdFx0Ly8gVHJhY2sgd2lkZ2V0cyB0aGF0IGluaGVyaXQgZnJvbSB0aGlzIHdpZGdldCBpbiBjYXNlIHRoaXMgd2lkZ2V0IGlzXG5cdFx0Ly8gcmVkZWZpbmVkIGFmdGVyIGEgd2lkZ2V0IGluaGVyaXRzIGZyb20gaXRcblx0XHRfY2hpbGRDb25zdHJ1Y3RvcnM6IFtdXG5cdH0gKTtcblxuXHRiYXNlUHJvdG90eXBlID0gbmV3IGJhc2UoKTtcblxuXHQvLyBXZSBuZWVkIHRvIG1ha2UgdGhlIG9wdGlvbnMgaGFzaCBhIHByb3BlcnR5IGRpcmVjdGx5IG9uIHRoZSBuZXcgaW5zdGFuY2Vcblx0Ly8gb3RoZXJ3aXNlIHdlJ2xsIG1vZGlmeSB0aGUgb3B0aW9ucyBoYXNoIG9uIHRoZSBwcm90b3R5cGUgdGhhdCB3ZSdyZVxuXHQvLyBpbmhlcml0aW5nIGZyb21cblx0YmFzZVByb3RvdHlwZS5vcHRpb25zID0gJC53aWRnZXQuZXh0ZW5kKCB7fSwgYmFzZVByb3RvdHlwZS5vcHRpb25zICk7XG5cdCQuZWFjaCggcHJvdG90eXBlLCBmdW5jdGlvbiggcHJvcCwgdmFsdWUgKSB7XG5cdFx0aWYgKCAhJC5pc0Z1bmN0aW9uKCB2YWx1ZSApICkge1xuXHRcdFx0cHJveGllZFByb3RvdHlwZVsgcHJvcCBdID0gdmFsdWU7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHByb3hpZWRQcm90b3R5cGVbIHByb3AgXSA9ICggZnVuY3Rpb24oKSB7XG5cdFx0XHRmdW5jdGlvbiBfc3VwZXIoKSB7XG5cdFx0XHRcdHJldHVybiBiYXNlLnByb3RvdHlwZVsgcHJvcCBdLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdH1cblxuXHRcdFx0ZnVuY3Rpb24gX3N1cGVyQXBwbHkoIGFyZ3MgKSB7XG5cdFx0XHRcdHJldHVybiBiYXNlLnByb3RvdHlwZVsgcHJvcCBdLmFwcGx5KCB0aGlzLCBhcmdzICk7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIF9fc3VwZXIgPSB0aGlzLl9zdXBlcjtcblx0XHRcdFx0dmFyIF9fc3VwZXJBcHBseSA9IHRoaXMuX3N1cGVyQXBwbHk7XG5cdFx0XHRcdHZhciByZXR1cm5WYWx1ZTtcblxuXHRcdFx0XHR0aGlzLl9zdXBlciA9IF9zdXBlcjtcblx0XHRcdFx0dGhpcy5fc3VwZXJBcHBseSA9IF9zdXBlckFwcGx5O1xuXG5cdFx0XHRcdHJldHVyblZhbHVlID0gdmFsdWUuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXG5cdFx0XHRcdHRoaXMuX3N1cGVyID0gX19zdXBlcjtcblx0XHRcdFx0dGhpcy5fc3VwZXJBcHBseSA9IF9fc3VwZXJBcHBseTtcblxuXHRcdFx0XHRyZXR1cm4gcmV0dXJuVmFsdWU7XG5cdFx0XHR9O1xuXHRcdH0gKSgpO1xuXHR9ICk7XG5cdGNvbnN0cnVjdG9yLnByb3RvdHlwZSA9ICQud2lkZ2V0LmV4dGVuZCggYmFzZVByb3RvdHlwZSwge1xuXG5cdFx0Ly8gVE9ETzogcmVtb3ZlIHN1cHBvcnQgZm9yIHdpZGdldEV2ZW50UHJlZml4XG5cdFx0Ly8gYWx3YXlzIHVzZSB0aGUgbmFtZSArIGEgY29sb24gYXMgdGhlIHByZWZpeCwgZS5nLiwgZHJhZ2dhYmxlOnN0YXJ0XG5cdFx0Ly8gZG9uJ3QgcHJlZml4IGZvciB3aWRnZXRzIHRoYXQgYXJlbid0IERPTS1iYXNlZFxuXHRcdHdpZGdldEV2ZW50UHJlZml4OiBleGlzdGluZ0NvbnN0cnVjdG9yID8gKCBiYXNlUHJvdG90eXBlLndpZGdldEV2ZW50UHJlZml4IHx8IG5hbWUgKSA6IG5hbWVcblx0fSwgcHJveGllZFByb3RvdHlwZSwge1xuXHRcdGNvbnN0cnVjdG9yOiBjb25zdHJ1Y3Rvcixcblx0XHRuYW1lc3BhY2U6IG5hbWVzcGFjZSxcblx0XHR3aWRnZXROYW1lOiBuYW1lLFxuXHRcdHdpZGdldEZ1bGxOYW1lOiBmdWxsTmFtZVxuXHR9ICk7XG5cblx0Ly8gSWYgdGhpcyB3aWRnZXQgaXMgYmVpbmcgcmVkZWZpbmVkIHRoZW4gd2UgbmVlZCB0byBmaW5kIGFsbCB3aWRnZXRzIHRoYXRcblx0Ly8gYXJlIGluaGVyaXRpbmcgZnJvbSBpdCBhbmQgcmVkZWZpbmUgYWxsIG9mIHRoZW0gc28gdGhhdCB0aGV5IGluaGVyaXQgZnJvbVxuXHQvLyB0aGUgbmV3IHZlcnNpb24gb2YgdGhpcyB3aWRnZXQuIFdlJ3JlIGVzc2VudGlhbGx5IHRyeWluZyB0byByZXBsYWNlIG9uZVxuXHQvLyBsZXZlbCBpbiB0aGUgcHJvdG90eXBlIGNoYWluLlxuXHRpZiAoIGV4aXN0aW5nQ29uc3RydWN0b3IgKSB7XG5cdFx0JC5lYWNoKCBleGlzdGluZ0NvbnN0cnVjdG9yLl9jaGlsZENvbnN0cnVjdG9ycywgZnVuY3Rpb24oIGksIGNoaWxkICkge1xuXHRcdFx0dmFyIGNoaWxkUHJvdG90eXBlID0gY2hpbGQucHJvdG90eXBlO1xuXG5cdFx0XHQvLyBSZWRlZmluZSB0aGUgY2hpbGQgd2lkZ2V0IHVzaW5nIHRoZSBzYW1lIHByb3RvdHlwZSB0aGF0IHdhc1xuXHRcdFx0Ly8gb3JpZ2luYWxseSB1c2VkLCBidXQgaW5oZXJpdCBmcm9tIHRoZSBuZXcgdmVyc2lvbiBvZiB0aGUgYmFzZVxuXHRcdFx0JC53aWRnZXQoIGNoaWxkUHJvdG90eXBlLm5hbWVzcGFjZSArIFwiLlwiICsgY2hpbGRQcm90b3R5cGUud2lkZ2V0TmFtZSwgY29uc3RydWN0b3IsXG5cdFx0XHRcdGNoaWxkLl9wcm90byApO1xuXHRcdH0gKTtcblxuXHRcdC8vIFJlbW92ZSB0aGUgbGlzdCBvZiBleGlzdGluZyBjaGlsZCBjb25zdHJ1Y3RvcnMgZnJvbSB0aGUgb2xkIGNvbnN0cnVjdG9yXG5cdFx0Ly8gc28gdGhlIG9sZCBjaGlsZCBjb25zdHJ1Y3RvcnMgY2FuIGJlIGdhcmJhZ2UgY29sbGVjdGVkXG5cdFx0ZGVsZXRlIGV4aXN0aW5nQ29uc3RydWN0b3IuX2NoaWxkQ29uc3RydWN0b3JzO1xuXHR9IGVsc2Uge1xuXHRcdGJhc2UuX2NoaWxkQ29uc3RydWN0b3JzLnB1c2goIGNvbnN0cnVjdG9yICk7XG5cdH1cblxuXHQkLndpZGdldC5icmlkZ2UoIG5hbWUsIGNvbnN0cnVjdG9yICk7XG5cblx0cmV0dXJuIGNvbnN0cnVjdG9yO1xufTtcblxuJC53aWRnZXQuZXh0ZW5kID0gZnVuY3Rpb24oIHRhcmdldCApIHtcblx0dmFyIGlucHV0ID0gd2lkZ2V0U2xpY2UuY2FsbCggYXJndW1lbnRzLCAxICk7XG5cdHZhciBpbnB1dEluZGV4ID0gMDtcblx0dmFyIGlucHV0TGVuZ3RoID0gaW5wdXQubGVuZ3RoO1xuXHR2YXIga2V5O1xuXHR2YXIgdmFsdWU7XG5cblx0Zm9yICggOyBpbnB1dEluZGV4IDwgaW5wdXRMZW5ndGg7IGlucHV0SW5kZXgrKyApIHtcblx0XHRmb3IgKCBrZXkgaW4gaW5wdXRbIGlucHV0SW5kZXggXSApIHtcblx0XHRcdHZhbHVlID0gaW5wdXRbIGlucHV0SW5kZXggXVsga2V5IF07XG5cdFx0XHRpZiAoIGlucHV0WyBpbnB1dEluZGV4IF0uaGFzT3duUHJvcGVydHkoIGtleSApICYmIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Ly8gQ2xvbmUgb2JqZWN0c1xuXHRcdFx0XHRpZiAoICQuaXNQbGFpbk9iamVjdCggdmFsdWUgKSApIHtcblx0XHRcdFx0XHR0YXJnZXRbIGtleSBdID0gJC5pc1BsYWluT2JqZWN0KCB0YXJnZXRbIGtleSBdICkgP1xuXHRcdFx0XHRcdFx0JC53aWRnZXQuZXh0ZW5kKCB7fSwgdGFyZ2V0WyBrZXkgXSwgdmFsdWUgKSA6XG5cblx0XHRcdFx0XHRcdC8vIERvbid0IGV4dGVuZCBzdHJpbmdzLCBhcnJheXMsIGV0Yy4gd2l0aCBvYmplY3RzXG5cdFx0XHRcdFx0XHQkLndpZGdldC5leHRlbmQoIHt9LCB2YWx1ZSApO1xuXG5cdFx0XHRcdC8vIENvcHkgZXZlcnl0aGluZyBlbHNlIGJ5IHJlZmVyZW5jZVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRhcmdldFsga2V5IF0gPSB2YWx1ZTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fVxuXHRyZXR1cm4gdGFyZ2V0O1xufTtcblxuJC53aWRnZXQuYnJpZGdlID0gZnVuY3Rpb24oIG5hbWUsIG9iamVjdCApIHtcblx0dmFyIGZ1bGxOYW1lID0gb2JqZWN0LnByb3RvdHlwZS53aWRnZXRGdWxsTmFtZSB8fCBuYW1lO1xuXHQkLmZuWyBuYW1lIF0gPSBmdW5jdGlvbiggb3B0aW9ucyApIHtcblx0XHR2YXIgaXNNZXRob2RDYWxsID0gdHlwZW9mIG9wdGlvbnMgPT09IFwic3RyaW5nXCI7XG5cdFx0dmFyIGFyZ3MgPSB3aWRnZXRTbGljZS5jYWxsKCBhcmd1bWVudHMsIDEgKTtcblx0XHR2YXIgcmV0dXJuVmFsdWUgPSB0aGlzO1xuXG5cdFx0aWYgKCBpc01ldGhvZENhbGwgKSB7XG5cblx0XHRcdC8vIElmIHRoaXMgaXMgYW4gZW1wdHkgY29sbGVjdGlvbiwgd2UgbmVlZCB0byBoYXZlIHRoZSBpbnN0YW5jZSBtZXRob2Rcblx0XHRcdC8vIHJldHVybiB1bmRlZmluZWQgaW5zdGVhZCBvZiB0aGUgalF1ZXJ5IGluc3RhbmNlXG5cdFx0XHRpZiAoICF0aGlzLmxlbmd0aCAmJiBvcHRpb25zID09PSBcImluc3RhbmNlXCIgKSB7XG5cdFx0XHRcdHJldHVyblZhbHVlID0gdW5kZWZpbmVkO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR2YXIgbWV0aG9kVmFsdWU7XG5cdFx0XHRcdFx0dmFyIGluc3RhbmNlID0gJC5kYXRhKCB0aGlzLCBmdWxsTmFtZSApO1xuXG5cdFx0XHRcdFx0aWYgKCBvcHRpb25zID09PSBcImluc3RhbmNlXCIgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm5WYWx1ZSA9IGluc3RhbmNlO1xuXHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggIWluc3RhbmNlICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuICQuZXJyb3IoIFwiY2Fubm90IGNhbGwgbWV0aG9kcyBvbiBcIiArIG5hbWUgK1xuXHRcdFx0XHRcdFx0XHRcIiBwcmlvciB0byBpbml0aWFsaXphdGlvbjsgXCIgK1xuXHRcdFx0XHRcdFx0XHRcImF0dGVtcHRlZCB0byBjYWxsIG1ldGhvZCAnXCIgKyBvcHRpb25zICsgXCInXCIgKTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoICEkLmlzRnVuY3Rpb24oIGluc3RhbmNlWyBvcHRpb25zIF0gKSB8fCBvcHRpb25zLmNoYXJBdCggMCApID09PSBcIl9cIiApIHtcblx0XHRcdFx0XHRcdHJldHVybiAkLmVycm9yKCBcIm5vIHN1Y2ggbWV0aG9kICdcIiArIG9wdGlvbnMgKyBcIicgZm9yIFwiICsgbmFtZSArXG5cdFx0XHRcdFx0XHRcdFwiIHdpZGdldCBpbnN0YW5jZVwiICk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0bWV0aG9kVmFsdWUgPSBpbnN0YW5jZVsgb3B0aW9ucyBdLmFwcGx5KCBpbnN0YW5jZSwgYXJncyApO1xuXG5cdFx0XHRcdFx0aWYgKCBtZXRob2RWYWx1ZSAhPT0gaW5zdGFuY2UgJiYgbWV0aG9kVmFsdWUgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRcdHJldHVyblZhbHVlID0gbWV0aG9kVmFsdWUgJiYgbWV0aG9kVmFsdWUuanF1ZXJ5ID9cblx0XHRcdFx0XHRcdFx0cmV0dXJuVmFsdWUucHVzaFN0YWNrKCBtZXRob2RWYWx1ZS5nZXQoKSApIDpcblx0XHRcdFx0XHRcdFx0bWV0aG9kVmFsdWU7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gQWxsb3cgbXVsdGlwbGUgaGFzaGVzIHRvIGJlIHBhc3NlZCBvbiBpbml0XG5cdFx0XHRpZiAoIGFyZ3MubGVuZ3RoICkge1xuXHRcdFx0XHRvcHRpb25zID0gJC53aWRnZXQuZXh0ZW5kLmFwcGx5KCBudWxsLCBbIG9wdGlvbnMgXS5jb25jYXQoIGFyZ3MgKSApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgaW5zdGFuY2UgPSAkLmRhdGEoIHRoaXMsIGZ1bGxOYW1lICk7XG5cdFx0XHRcdGlmICggaW5zdGFuY2UgKSB7XG5cdFx0XHRcdFx0aW5zdGFuY2Uub3B0aW9uKCBvcHRpb25zIHx8IHt9ICk7XG5cdFx0XHRcdFx0aWYgKCBpbnN0YW5jZS5faW5pdCApIHtcblx0XHRcdFx0XHRcdGluc3RhbmNlLl9pbml0KCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdCQuZGF0YSggdGhpcywgZnVsbE5hbWUsIG5ldyBvYmplY3QoIG9wdGlvbnMsIHRoaXMgKSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJldHVyblZhbHVlO1xuXHR9O1xufTtcblxuJC5XaWRnZXQgPSBmdW5jdGlvbiggLyogb3B0aW9ucywgZWxlbWVudCAqLyApIHt9O1xuJC5XaWRnZXQuX2NoaWxkQ29uc3RydWN0b3JzID0gW107XG5cbiQuV2lkZ2V0LnByb3RvdHlwZSA9IHtcblx0d2lkZ2V0TmFtZTogXCJ3aWRnZXRcIixcblx0d2lkZ2V0RXZlbnRQcmVmaXg6IFwiXCIsXG5cdGRlZmF1bHRFbGVtZW50OiBcIjxkaXY+XCIsXG5cblx0b3B0aW9uczoge1xuXHRcdGNsYXNzZXM6IHt9LFxuXHRcdGRpc2FibGVkOiBmYWxzZSxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGNyZWF0ZTogbnVsbFxuXHR9LFxuXG5cdF9jcmVhdGVXaWRnZXQ6IGZ1bmN0aW9uKCBvcHRpb25zLCBlbGVtZW50ICkge1xuXHRcdGVsZW1lbnQgPSAkKCBlbGVtZW50IHx8IHRoaXMuZGVmYXVsdEVsZW1lbnQgfHwgdGhpcyApWyAwIF07XG5cdFx0dGhpcy5lbGVtZW50ID0gJCggZWxlbWVudCApO1xuXHRcdHRoaXMudXVpZCA9IHdpZGdldFV1aWQrKztcblx0XHR0aGlzLmV2ZW50TmFtZXNwYWNlID0gXCIuXCIgKyB0aGlzLndpZGdldE5hbWUgKyB0aGlzLnV1aWQ7XG5cblx0XHR0aGlzLmJpbmRpbmdzID0gJCgpO1xuXHRcdHRoaXMuaG92ZXJhYmxlID0gJCgpO1xuXHRcdHRoaXMuZm9jdXNhYmxlID0gJCgpO1xuXHRcdHRoaXMuY2xhc3Nlc0VsZW1lbnRMb29rdXAgPSB7fTtcblxuXHRcdGlmICggZWxlbWVudCAhPT0gdGhpcyApIHtcblx0XHRcdCQuZGF0YSggZWxlbWVudCwgdGhpcy53aWRnZXRGdWxsTmFtZSwgdGhpcyApO1xuXHRcdFx0dGhpcy5fb24oIHRydWUsIHRoaXMuZWxlbWVudCwge1xuXHRcdFx0XHRyZW1vdmU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0XHRpZiAoIGV2ZW50LnRhcmdldCA9PT0gZWxlbWVudCApIHtcblx0XHRcdFx0XHRcdHRoaXMuZGVzdHJveSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdFx0dGhpcy5kb2N1bWVudCA9ICQoIGVsZW1lbnQuc3R5bGUgP1xuXG5cdFx0XHRcdC8vIEVsZW1lbnQgd2l0aGluIHRoZSBkb2N1bWVudFxuXHRcdFx0XHRlbGVtZW50Lm93bmVyRG9jdW1lbnQgOlxuXG5cdFx0XHRcdC8vIEVsZW1lbnQgaXMgd2luZG93IG9yIGRvY3VtZW50XG5cdFx0XHRcdGVsZW1lbnQuZG9jdW1lbnQgfHwgZWxlbWVudCApO1xuXHRcdFx0dGhpcy53aW5kb3cgPSAkKCB0aGlzLmRvY3VtZW50WyAwIF0uZGVmYXVsdFZpZXcgfHwgdGhpcy5kb2N1bWVudFsgMCBdLnBhcmVudFdpbmRvdyApO1xuXHRcdH1cblxuXHRcdHRoaXMub3B0aW9ucyA9ICQud2lkZ2V0LmV4dGVuZCgge30sXG5cdFx0XHR0aGlzLm9wdGlvbnMsXG5cdFx0XHR0aGlzLl9nZXRDcmVhdGVPcHRpb25zKCksXG5cdFx0XHRvcHRpb25zICk7XG5cblx0XHR0aGlzLl9jcmVhdGUoKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0dGhpcy5fc2V0T3B0aW9uRGlzYWJsZWQoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3RyaWdnZXIoIFwiY3JlYXRlXCIsIG51bGwsIHRoaXMuX2dldENyZWF0ZUV2ZW50RGF0YSgpICk7XG5cdFx0dGhpcy5faW5pdCgpO1xuXHR9LFxuXG5cdF9nZXRDcmVhdGVPcHRpb25zOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4ge307XG5cdH0sXG5cblx0X2dldENyZWF0ZUV2ZW50RGF0YTogJC5ub29wLFxuXG5cdF9jcmVhdGU6ICQubm9vcCxcblxuXHRfaW5pdDogJC5ub29wLFxuXG5cdGRlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdHRoaXMuX2Rlc3Ryb3koKTtcblx0XHQkLmVhY2goIHRoaXMuY2xhc3Nlc0VsZW1lbnRMb29rdXAsIGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHZhbHVlLCBrZXkgKTtcblx0XHR9ICk7XG5cblx0XHQvLyBXZSBjYW4gcHJvYmFibHkgcmVtb3ZlIHRoZSB1bmJpbmQgY2FsbHMgaW4gMi4wXG5cdFx0Ly8gYWxsIGV2ZW50IGJpbmRpbmdzIHNob3VsZCBnbyB0aHJvdWdoIHRoaXMuX29uKClcblx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdC5vZmYoIHRoaXMuZXZlbnROYW1lc3BhY2UgKVxuXHRcdFx0LnJlbW92ZURhdGEoIHRoaXMud2lkZ2V0RnVsbE5hbWUgKTtcblx0XHR0aGlzLndpZGdldCgpXG5cdFx0XHQub2ZmKCB0aGlzLmV2ZW50TmFtZXNwYWNlIClcblx0XHRcdC5yZW1vdmVBdHRyKCBcImFyaWEtZGlzYWJsZWRcIiApO1xuXG5cdFx0Ly8gQ2xlYW4gdXAgZXZlbnRzIGFuZCBzdGF0ZXNcblx0XHR0aGlzLmJpbmRpbmdzLm9mZiggdGhpcy5ldmVudE5hbWVzcGFjZSApO1xuXHR9LFxuXG5cdF9kZXN0cm95OiAkLm5vb3AsXG5cblx0d2lkZ2V0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5lbGVtZW50O1xuXHR9LFxuXG5cdG9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSBrZXk7XG5cdFx0dmFyIHBhcnRzO1xuXHRcdHZhciBjdXJPcHRpb247XG5cdFx0dmFyIGk7XG5cblx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggPT09IDAgKSB7XG5cblx0XHRcdC8vIERvbid0IHJldHVybiBhIHJlZmVyZW5jZSB0byB0aGUgaW50ZXJuYWwgaGFzaFxuXHRcdFx0cmV0dXJuICQud2lkZ2V0LmV4dGVuZCgge30sIHRoaXMub3B0aW9ucyApO1xuXHRcdH1cblxuXHRcdGlmICggdHlwZW9mIGtleSA9PT0gXCJzdHJpbmdcIiApIHtcblxuXHRcdFx0Ly8gSGFuZGxlIG5lc3RlZCBrZXlzLCBlLmcuLCBcImZvby5iYXJcIiA9PiB7IGZvbzogeyBiYXI6IF9fXyB9IH1cblx0XHRcdG9wdGlvbnMgPSB7fTtcblx0XHRcdHBhcnRzID0ga2V5LnNwbGl0KCBcIi5cIiApO1xuXHRcdFx0a2V5ID0gcGFydHMuc2hpZnQoKTtcblx0XHRcdGlmICggcGFydHMubGVuZ3RoICkge1xuXHRcdFx0XHRjdXJPcHRpb24gPSBvcHRpb25zWyBrZXkgXSA9ICQud2lkZ2V0LmV4dGVuZCgge30sIHRoaXMub3B0aW9uc1sga2V5IF0gKTtcblx0XHRcdFx0Zm9yICggaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGggLSAxOyBpKysgKSB7XG5cdFx0XHRcdFx0Y3VyT3B0aW9uWyBwYXJ0c1sgaSBdIF0gPSBjdXJPcHRpb25bIHBhcnRzWyBpIF0gXSB8fCB7fTtcblx0XHRcdFx0XHRjdXJPcHRpb24gPSBjdXJPcHRpb25bIHBhcnRzWyBpIF0gXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRrZXkgPSBwYXJ0cy5wb3AoKTtcblx0XHRcdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID09PSAxICkge1xuXHRcdFx0XHRcdHJldHVybiBjdXJPcHRpb25bIGtleSBdID09PSB1bmRlZmluZWQgPyBudWxsIDogY3VyT3B0aW9uWyBrZXkgXTtcblx0XHRcdFx0fVxuXHRcdFx0XHRjdXJPcHRpb25bIGtleSBdID0gdmFsdWU7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggPT09IDEgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMub3B0aW9uc1sga2V5IF0gPT09IHVuZGVmaW5lZCA/IG51bGwgOiB0aGlzLm9wdGlvbnNbIGtleSBdO1xuXHRcdFx0XHR9XG5cdFx0XHRcdG9wdGlvbnNbIGtleSBdID0gdmFsdWU7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5fc2V0T3B0aW9ucyggb3B0aW9ucyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X3NldE9wdGlvbnM6IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXHRcdHZhciBrZXk7XG5cblx0XHRmb3IgKCBrZXkgaW4gb3B0aW9ucyApIHtcblx0XHRcdHRoaXMuX3NldE9wdGlvbigga2V5LCBvcHRpb25zWyBrZXkgXSApO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdGlmICgga2V5ID09PSBcImNsYXNzZXNcIiApIHtcblx0XHRcdHRoaXMuX3NldE9wdGlvbkNsYXNzZXMoIHZhbHVlICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5vcHRpb25zWyBrZXkgXSA9IHZhbHVlO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiZGlzYWJsZWRcIiApIHtcblx0XHRcdHRoaXMuX3NldE9wdGlvbkRpc2FibGVkKCB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9zZXRPcHRpb25DbGFzc2VzOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dmFyIGNsYXNzS2V5LCBlbGVtZW50cywgY3VycmVudEVsZW1lbnRzO1xuXG5cdFx0Zm9yICggY2xhc3NLZXkgaW4gdmFsdWUgKSB7XG5cdFx0XHRjdXJyZW50RWxlbWVudHMgPSB0aGlzLmNsYXNzZXNFbGVtZW50TG9va3VwWyBjbGFzc0tleSBdO1xuXHRcdFx0aWYgKCB2YWx1ZVsgY2xhc3NLZXkgXSA9PT0gdGhpcy5vcHRpb25zLmNsYXNzZXNbIGNsYXNzS2V5IF0gfHxcblx0XHRcdFx0XHQhY3VycmVudEVsZW1lbnRzIHx8XG5cdFx0XHRcdFx0IWN1cnJlbnRFbGVtZW50cy5sZW5ndGggKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBXZSBhcmUgZG9pbmcgdGhpcyB0byBjcmVhdGUgYSBuZXcgalF1ZXJ5IG9iamVjdCBiZWNhdXNlIHRoZSBfcmVtb3ZlQ2xhc3MoKSBjYWxsXG5cdFx0XHQvLyBvbiB0aGUgbmV4dCBsaW5lIGlzIGdvaW5nIHRvIGRlc3Ryb3kgdGhlIHJlZmVyZW5jZSB0byB0aGUgY3VycmVudCBlbGVtZW50cyBiZWluZ1xuXHRcdFx0Ly8gdHJhY2tlZC4gV2UgbmVlZCB0byBzYXZlIGEgY29weSBvZiB0aGlzIGNvbGxlY3Rpb24gc28gdGhhdCB3ZSBjYW4gYWRkIHRoZSBuZXcgY2xhc3Nlc1xuXHRcdFx0Ly8gYmVsb3cuXG5cdFx0XHRlbGVtZW50cyA9ICQoIGN1cnJlbnRFbGVtZW50cy5nZXQoKSApO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGN1cnJlbnRFbGVtZW50cywgY2xhc3NLZXkgKTtcblxuXHRcdFx0Ly8gV2UgZG9uJ3QgdXNlIF9hZGRDbGFzcygpIGhlcmUsIGJlY2F1c2UgdGhhdCB1c2VzIHRoaXMub3B0aW9ucy5jbGFzc2VzXG5cdFx0XHQvLyBmb3IgZ2VuZXJhdGluZyB0aGUgc3RyaW5nIG9mIGNsYXNzZXMuIFdlIHdhbnQgdG8gdXNlIHRoZSB2YWx1ZSBwYXNzZWQgaW4gZnJvbVxuXHRcdFx0Ly8gX3NldE9wdGlvbigpLCB0aGlzIGlzIHRoZSBuZXcgdmFsdWUgb2YgdGhlIGNsYXNzZXMgb3B0aW9uIHdoaWNoIHdhcyBwYXNzZWQgdG9cblx0XHRcdC8vIF9zZXRPcHRpb24oKS4gV2UgcGFzcyB0aGlzIHZhbHVlIGRpcmVjdGx5IHRvIF9jbGFzc2VzKCkuXG5cdFx0XHRlbGVtZW50cy5hZGRDbGFzcyggdGhpcy5fY2xhc3Nlcygge1xuXHRcdFx0XHRlbGVtZW50OiBlbGVtZW50cyxcblx0XHRcdFx0a2V5czogY2xhc3NLZXksXG5cdFx0XHRcdGNsYXNzZXM6IHZhbHVlLFxuXHRcdFx0XHRhZGQ6IHRydWVcblx0XHRcdH0gKSApO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uRGlzYWJsZWQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR0aGlzLl90b2dnbGVDbGFzcyggdGhpcy53aWRnZXQoKSwgdGhpcy53aWRnZXRGdWxsTmFtZSArIFwiLWRpc2FibGVkXCIsIG51bGwsICEhdmFsdWUgKTtcblxuXHRcdC8vIElmIHRoZSB3aWRnZXQgaXMgYmVjb21pbmcgZGlzYWJsZWQsIHRoZW4gbm90aGluZyBpcyBpbnRlcmFjdGl2ZVxuXHRcdGlmICggdmFsdWUgKSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5ob3ZlcmFibGUsIG51bGwsIFwidWktc3RhdGUtaG92ZXJcIiApO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuZm9jdXNhYmxlLCBudWxsLCBcInVpLXN0YXRlLWZvY3VzXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0ZW5hYmxlOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5fc2V0T3B0aW9ucyggeyBkaXNhYmxlZDogZmFsc2UgfSApO1xuXHR9LFxuXG5cdGRpc2FibGU6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLl9zZXRPcHRpb25zKCB7IGRpc2FibGVkOiB0cnVlIH0gKTtcblx0fSxcblxuXHRfY2xhc3NlczogZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdFx0dmFyIGZ1bGwgPSBbXTtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHRvcHRpb25zID0gJC5leHRlbmQoIHtcblx0XHRcdGVsZW1lbnQ6IHRoaXMuZWxlbWVudCxcblx0XHRcdGNsYXNzZXM6IHRoaXMub3B0aW9ucy5jbGFzc2VzIHx8IHt9XG5cdFx0fSwgb3B0aW9ucyApO1xuXG5cdFx0ZnVuY3Rpb24gcHJvY2Vzc0NsYXNzU3RyaW5nKCBjbGFzc2VzLCBjaGVja09wdGlvbiApIHtcblx0XHRcdHZhciBjdXJyZW50LCBpO1xuXHRcdFx0Zm9yICggaSA9IDA7IGkgPCBjbGFzc2VzLmxlbmd0aDsgaSsrICkge1xuXHRcdFx0XHRjdXJyZW50ID0gdGhhdC5jbGFzc2VzRWxlbWVudExvb2t1cFsgY2xhc3Nlc1sgaSBdIF0gfHwgJCgpO1xuXHRcdFx0XHRpZiAoIG9wdGlvbnMuYWRkICkge1xuXHRcdFx0XHRcdGN1cnJlbnQgPSAkKCAkLnVuaXF1ZSggY3VycmVudC5nZXQoKS5jb25jYXQoIG9wdGlvbnMuZWxlbWVudC5nZXQoKSApICkgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRjdXJyZW50ID0gJCggY3VycmVudC5ub3QoIG9wdGlvbnMuZWxlbWVudCApLmdldCgpICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhhdC5jbGFzc2VzRWxlbWVudExvb2t1cFsgY2xhc3Nlc1sgaSBdIF0gPSBjdXJyZW50O1xuXHRcdFx0XHRmdWxsLnB1c2goIGNsYXNzZXNbIGkgXSApO1xuXHRcdFx0XHRpZiAoIGNoZWNrT3B0aW9uICYmIG9wdGlvbnMuY2xhc3Nlc1sgY2xhc3Nlc1sgaSBdIF0gKSB7XG5cdFx0XHRcdFx0ZnVsbC5wdXNoKCBvcHRpb25zLmNsYXNzZXNbIGNsYXNzZXNbIGkgXSBdICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLl9vbiggb3B0aW9ucy5lbGVtZW50LCB7XG5cdFx0XHRcInJlbW92ZVwiOiBcIl91bnRyYWNrQ2xhc3Nlc0VsZW1lbnRcIlxuXHRcdH0gKTtcblxuXHRcdGlmICggb3B0aW9ucy5rZXlzICkge1xuXHRcdFx0cHJvY2Vzc0NsYXNzU3RyaW5nKCBvcHRpb25zLmtleXMubWF0Y2goIC9cXFMrL2cgKSB8fCBbXSwgdHJ1ZSApO1xuXHRcdH1cblx0XHRpZiAoIG9wdGlvbnMuZXh0cmEgKSB7XG5cdFx0XHRwcm9jZXNzQ2xhc3NTdHJpbmcoIG9wdGlvbnMuZXh0cmEubWF0Y2goIC9cXFMrL2cgKSB8fCBbXSApO1xuXHRcdH1cblxuXHRcdHJldHVybiBmdWxsLmpvaW4oIFwiIFwiICk7XG5cdH0sXG5cblx0X3VudHJhY2tDbGFzc2VzRWxlbWVudDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblx0XHQkLmVhY2goIHRoYXQuY2xhc3Nlc0VsZW1lbnRMb29rdXAsIGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdFx0aWYgKCAkLmluQXJyYXkoIGV2ZW50LnRhcmdldCwgdmFsdWUgKSAhPT0gLTEgKSB7XG5cdFx0XHRcdHRoYXQuY2xhc3Nlc0VsZW1lbnRMb29rdXBbIGtleSBdID0gJCggdmFsdWUubm90KCBldmVudC50YXJnZXQgKS5nZXQoKSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfcmVtb3ZlQ2xhc3M6IGZ1bmN0aW9uKCBlbGVtZW50LCBrZXlzLCBleHRyYSApIHtcblx0XHRyZXR1cm4gdGhpcy5fdG9nZ2xlQ2xhc3MoIGVsZW1lbnQsIGtleXMsIGV4dHJhLCBmYWxzZSApO1xuXHR9LFxuXG5cdF9hZGRDbGFzczogZnVuY3Rpb24oIGVsZW1lbnQsIGtleXMsIGV4dHJhICkge1xuXHRcdHJldHVybiB0aGlzLl90b2dnbGVDbGFzcyggZWxlbWVudCwga2V5cywgZXh0cmEsIHRydWUgKTtcblx0fSxcblxuXHRfdG9nZ2xlQ2xhc3M6IGZ1bmN0aW9uKCBlbGVtZW50LCBrZXlzLCBleHRyYSwgYWRkICkge1xuXHRcdGFkZCA9ICggdHlwZW9mIGFkZCA9PT0gXCJib29sZWFuXCIgKSA/IGFkZCA6IGV4dHJhO1xuXHRcdHZhciBzaGlmdCA9ICggdHlwZW9mIGVsZW1lbnQgPT09IFwic3RyaW5nXCIgfHwgZWxlbWVudCA9PT0gbnVsbCApLFxuXHRcdFx0b3B0aW9ucyA9IHtcblx0XHRcdFx0ZXh0cmE6IHNoaWZ0ID8ga2V5cyA6IGV4dHJhLFxuXHRcdFx0XHRrZXlzOiBzaGlmdCA/IGVsZW1lbnQgOiBrZXlzLFxuXHRcdFx0XHRlbGVtZW50OiBzaGlmdCA/IHRoaXMuZWxlbWVudCA6IGVsZW1lbnQsXG5cdFx0XHRcdGFkZDogYWRkXG5cdFx0XHR9O1xuXHRcdG9wdGlvbnMuZWxlbWVudC50b2dnbGVDbGFzcyggdGhpcy5fY2xhc3Nlcyggb3B0aW9ucyApLCBhZGQgKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRfb246IGZ1bmN0aW9uKCBzdXBwcmVzc0Rpc2FibGVkQ2hlY2ssIGVsZW1lbnQsIGhhbmRsZXJzICkge1xuXHRcdHZhciBkZWxlZ2F0ZUVsZW1lbnQ7XG5cdFx0dmFyIGluc3RhbmNlID0gdGhpcztcblxuXHRcdC8vIE5vIHN1cHByZXNzRGlzYWJsZWRDaGVjayBmbGFnLCBzaHVmZmxlIGFyZ3VtZW50c1xuXHRcdGlmICggdHlwZW9mIHN1cHByZXNzRGlzYWJsZWRDaGVjayAhPT0gXCJib29sZWFuXCIgKSB7XG5cdFx0XHRoYW5kbGVycyA9IGVsZW1lbnQ7XG5cdFx0XHRlbGVtZW50ID0gc3VwcHJlc3NEaXNhYmxlZENoZWNrO1xuXHRcdFx0c3VwcHJlc3NEaXNhYmxlZENoZWNrID0gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly8gTm8gZWxlbWVudCBhcmd1bWVudCwgc2h1ZmZsZSBhbmQgdXNlIHRoaXMuZWxlbWVudFxuXHRcdGlmICggIWhhbmRsZXJzICkge1xuXHRcdFx0aGFuZGxlcnMgPSBlbGVtZW50O1xuXHRcdFx0ZWxlbWVudCA9IHRoaXMuZWxlbWVudDtcblx0XHRcdGRlbGVnYXRlRWxlbWVudCA9IHRoaXMud2lkZ2V0KCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGVsZW1lbnQgPSBkZWxlZ2F0ZUVsZW1lbnQgPSAkKCBlbGVtZW50ICk7XG5cdFx0XHR0aGlzLmJpbmRpbmdzID0gdGhpcy5iaW5kaW5ncy5hZGQoIGVsZW1lbnQgKTtcblx0XHR9XG5cblx0XHQkLmVhY2goIGhhbmRsZXJzLCBmdW5jdGlvbiggZXZlbnQsIGhhbmRsZXIgKSB7XG5cdFx0XHRmdW5jdGlvbiBoYW5kbGVyUHJveHkoKSB7XG5cblx0XHRcdFx0Ly8gQWxsb3cgd2lkZ2V0cyB0byBjdXN0b21pemUgdGhlIGRpc2FibGVkIGhhbmRsaW5nXG5cdFx0XHRcdC8vIC0gZGlzYWJsZWQgYXMgYW4gYXJyYXkgaW5zdGVhZCBvZiBib29sZWFuXG5cdFx0XHRcdC8vIC0gZGlzYWJsZWQgY2xhc3MgYXMgbWV0aG9kIGZvciBkaXNhYmxpbmcgaW5kaXZpZHVhbCBwYXJ0c1xuXHRcdFx0XHRpZiAoICFzdXBwcmVzc0Rpc2FibGVkQ2hlY2sgJiZcblx0XHRcdFx0XHRcdCggaW5zdGFuY2Uub3B0aW9ucy5kaXNhYmxlZCA9PT0gdHJ1ZSB8fFxuXHRcdFx0XHRcdFx0JCggdGhpcyApLmhhc0NsYXNzKCBcInVpLXN0YXRlLWRpc2FibGVkXCIgKSApICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gKCB0eXBlb2YgaGFuZGxlciA9PT0gXCJzdHJpbmdcIiA/IGluc3RhbmNlWyBoYW5kbGVyIF0gOiBoYW5kbGVyIClcblx0XHRcdFx0XHQuYXBwbHkoIGluc3RhbmNlLCBhcmd1bWVudHMgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ29weSB0aGUgZ3VpZCBzbyBkaXJlY3QgdW5iaW5kaW5nIHdvcmtzXG5cdFx0XHRpZiAoIHR5cGVvZiBoYW5kbGVyICE9PSBcInN0cmluZ1wiICkge1xuXHRcdFx0XHRoYW5kbGVyUHJveHkuZ3VpZCA9IGhhbmRsZXIuZ3VpZCA9XG5cdFx0XHRcdFx0aGFuZGxlci5ndWlkIHx8IGhhbmRsZXJQcm94eS5ndWlkIHx8ICQuZ3VpZCsrO1xuXHRcdFx0fVxuXG5cdFx0XHR2YXIgbWF0Y2ggPSBldmVudC5tYXRjaCggL14oW1xcdzotXSopXFxzKiguKikkLyApO1xuXHRcdFx0dmFyIGV2ZW50TmFtZSA9IG1hdGNoWyAxIF0gKyBpbnN0YW5jZS5ldmVudE5hbWVzcGFjZTtcblx0XHRcdHZhciBzZWxlY3RvciA9IG1hdGNoWyAyIF07XG5cblx0XHRcdGlmICggc2VsZWN0b3IgKSB7XG5cdFx0XHRcdGRlbGVnYXRlRWxlbWVudC5vbiggZXZlbnROYW1lLCBzZWxlY3RvciwgaGFuZGxlclByb3h5ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRlbGVtZW50Lm9uKCBldmVudE5hbWUsIGhhbmRsZXJQcm94eSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfb2ZmOiBmdW5jdGlvbiggZWxlbWVudCwgZXZlbnROYW1lICkge1xuXHRcdGV2ZW50TmFtZSA9ICggZXZlbnROYW1lIHx8IFwiXCIgKS5zcGxpdCggXCIgXCIgKS5qb2luKCB0aGlzLmV2ZW50TmFtZXNwYWNlICsgXCIgXCIgKSArXG5cdFx0XHR0aGlzLmV2ZW50TmFtZXNwYWNlO1xuXHRcdGVsZW1lbnQub2ZmKCBldmVudE5hbWUgKS5vZmYoIGV2ZW50TmFtZSApO1xuXG5cdFx0Ly8gQ2xlYXIgdGhlIHN0YWNrIHRvIGF2b2lkIG1lbW9yeSBsZWFrcyAoIzEwMDU2KVxuXHRcdHRoaXMuYmluZGluZ3MgPSAkKCB0aGlzLmJpbmRpbmdzLm5vdCggZWxlbWVudCApLmdldCgpICk7XG5cdFx0dGhpcy5mb2N1c2FibGUgPSAkKCB0aGlzLmZvY3VzYWJsZS5ub3QoIGVsZW1lbnQgKS5nZXQoKSApO1xuXHRcdHRoaXMuaG92ZXJhYmxlID0gJCggdGhpcy5ob3ZlcmFibGUubm90KCBlbGVtZW50ICkuZ2V0KCkgKTtcblx0fSxcblxuXHRfZGVsYXk6IGZ1bmN0aW9uKCBoYW5kbGVyLCBkZWxheSApIHtcblx0XHRmdW5jdGlvbiBoYW5kbGVyUHJveHkoKSB7XG5cdFx0XHRyZXR1cm4gKCB0eXBlb2YgaGFuZGxlciA9PT0gXCJzdHJpbmdcIiA/IGluc3RhbmNlWyBoYW5kbGVyIF0gOiBoYW5kbGVyIClcblx0XHRcdFx0LmFwcGx5KCBpbnN0YW5jZSwgYXJndW1lbnRzICk7XG5cdFx0fVxuXHRcdHZhciBpbnN0YW5jZSA9IHRoaXM7XG5cdFx0cmV0dXJuIHNldFRpbWVvdXQoIGhhbmRsZXJQcm94eSwgZGVsYXkgfHwgMCApO1xuXHR9LFxuXG5cdF9ob3ZlcmFibGU6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHRoaXMuaG92ZXJhYmxlID0gdGhpcy5ob3ZlcmFibGUuYWRkKCBlbGVtZW50ICk7XG5cdFx0dGhpcy5fb24oIGVsZW1lbnQsIHtcblx0XHRcdG1vdXNlZW50ZXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoICQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKSwgbnVsbCwgXCJ1aS1zdGF0ZS1ob3ZlclwiICk7XG5cdFx0XHR9LFxuXHRcdFx0bW91c2VsZWF2ZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggJCggZXZlbnQuY3VycmVudFRhcmdldCApLCBudWxsLCBcInVpLXN0YXRlLWhvdmVyXCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X2ZvY3VzYWJsZTogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0dGhpcy5mb2N1c2FibGUgPSB0aGlzLmZvY3VzYWJsZS5hZGQoIGVsZW1lbnQgKTtcblx0XHR0aGlzLl9vbiggZWxlbWVudCwge1xuXHRcdFx0Zm9jdXNpbjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggJCggZXZlbnQuY3VycmVudFRhcmdldCApLCBudWxsLCBcInVpLXN0YXRlLWZvY3VzXCIgKTtcblx0XHRcdH0sXG5cdFx0XHRmb2N1c291dDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggJCggZXZlbnQuY3VycmVudFRhcmdldCApLCBudWxsLCBcInVpLXN0YXRlLWZvY3VzXCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X3RyaWdnZXI6IGZ1bmN0aW9uKCB0eXBlLCBldmVudCwgZGF0YSApIHtcblx0XHR2YXIgcHJvcCwgb3JpZztcblx0XHR2YXIgY2FsbGJhY2sgPSB0aGlzLm9wdGlvbnNbIHR5cGUgXTtcblxuXHRcdGRhdGEgPSBkYXRhIHx8IHt9O1xuXHRcdGV2ZW50ID0gJC5FdmVudCggZXZlbnQgKTtcblx0XHRldmVudC50eXBlID0gKCB0eXBlID09PSB0aGlzLndpZGdldEV2ZW50UHJlZml4ID9cblx0XHRcdHR5cGUgOlxuXHRcdFx0dGhpcy53aWRnZXRFdmVudFByZWZpeCArIHR5cGUgKS50b0xvd2VyQ2FzZSgpO1xuXG5cdFx0Ly8gVGhlIG9yaWdpbmFsIGV2ZW50IG1heSBjb21lIGZyb20gYW55IGVsZW1lbnRcblx0XHQvLyBzbyB3ZSBuZWVkIHRvIHJlc2V0IHRoZSB0YXJnZXQgb24gdGhlIG5ldyBldmVudFxuXHRcdGV2ZW50LnRhcmdldCA9IHRoaXMuZWxlbWVudFsgMCBdO1xuXG5cdFx0Ly8gQ29weSBvcmlnaW5hbCBldmVudCBwcm9wZXJ0aWVzIG92ZXIgdG8gdGhlIG5ldyBldmVudFxuXHRcdG9yaWcgPSBldmVudC5vcmlnaW5hbEV2ZW50O1xuXHRcdGlmICggb3JpZyApIHtcblx0XHRcdGZvciAoIHByb3AgaW4gb3JpZyApIHtcblx0XHRcdFx0aWYgKCAhKCBwcm9wIGluIGV2ZW50ICkgKSB7XG5cdFx0XHRcdFx0ZXZlbnRbIHByb3AgXSA9IG9yaWdbIHByb3AgXTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuZWxlbWVudC50cmlnZ2VyKCBldmVudCwgZGF0YSApO1xuXHRcdHJldHVybiAhKCAkLmlzRnVuY3Rpb24oIGNhbGxiYWNrICkgJiZcblx0XHRcdGNhbGxiYWNrLmFwcGx5KCB0aGlzLmVsZW1lbnRbIDAgXSwgWyBldmVudCBdLmNvbmNhdCggZGF0YSApICkgPT09IGZhbHNlIHx8XG5cdFx0XHRldmVudC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSApO1xuXHR9XG59O1xuXG4kLmVhY2goIHsgc2hvdzogXCJmYWRlSW5cIiwgaGlkZTogXCJmYWRlT3V0XCIgfSwgZnVuY3Rpb24oIG1ldGhvZCwgZGVmYXVsdEVmZmVjdCApIHtcblx0JC5XaWRnZXQucHJvdG90eXBlWyBcIl9cIiArIG1ldGhvZCBdID0gZnVuY3Rpb24oIGVsZW1lbnQsIG9wdGlvbnMsIGNhbGxiYWNrICkge1xuXHRcdGlmICggdHlwZW9mIG9wdGlvbnMgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRvcHRpb25zID0geyBlZmZlY3Q6IG9wdGlvbnMgfTtcblx0XHR9XG5cblx0XHR2YXIgaGFzT3B0aW9ucztcblx0XHR2YXIgZWZmZWN0TmFtZSA9ICFvcHRpb25zID9cblx0XHRcdG1ldGhvZCA6XG5cdFx0XHRvcHRpb25zID09PSB0cnVlIHx8IHR5cGVvZiBvcHRpb25zID09PSBcIm51bWJlclwiID9cblx0XHRcdFx0ZGVmYXVsdEVmZmVjdCA6XG5cdFx0XHRcdG9wdGlvbnMuZWZmZWN0IHx8IGRlZmF1bHRFZmZlY3Q7XG5cblx0XHRvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcblx0XHRpZiAoIHR5cGVvZiBvcHRpb25zID09PSBcIm51bWJlclwiICkge1xuXHRcdFx0b3B0aW9ucyA9IHsgZHVyYXRpb246IG9wdGlvbnMgfTtcblx0XHR9XG5cblx0XHRoYXNPcHRpb25zID0gISQuaXNFbXB0eU9iamVjdCggb3B0aW9ucyApO1xuXHRcdG9wdGlvbnMuY29tcGxldGUgPSBjYWxsYmFjaztcblxuXHRcdGlmICggb3B0aW9ucy5kZWxheSApIHtcblx0XHRcdGVsZW1lbnQuZGVsYXkoIG9wdGlvbnMuZGVsYXkgKTtcblx0XHR9XG5cblx0XHRpZiAoIGhhc09wdGlvbnMgJiYgJC5lZmZlY3RzICYmICQuZWZmZWN0cy5lZmZlY3RbIGVmZmVjdE5hbWUgXSApIHtcblx0XHRcdGVsZW1lbnRbIG1ldGhvZCBdKCBvcHRpb25zICk7XG5cdFx0fSBlbHNlIGlmICggZWZmZWN0TmFtZSAhPT0gbWV0aG9kICYmIGVsZW1lbnRbIGVmZmVjdE5hbWUgXSApIHtcblx0XHRcdGVsZW1lbnRbIGVmZmVjdE5hbWUgXSggb3B0aW9ucy5kdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcsIGNhbGxiYWNrICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGVsZW1lbnQucXVldWUoIGZ1bmN0aW9uKCBuZXh0ICkge1xuXHRcdFx0XHQkKCB0aGlzIClbIG1ldGhvZCBdKCk7XG5cdFx0XHRcdGlmICggY2FsbGJhY2sgKSB7XG5cdFx0XHRcdFx0Y2FsbGJhY2suY2FsbCggZWxlbWVudFsgMCBdICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0bmV4dCgpO1xuXHRcdFx0fSApO1xuXHRcdH1cblx0fTtcbn0gKTtcblxudmFyIHdpZGdldCA9ICQud2lkZ2V0O1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFBvc2l0aW9uIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKlxuICogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vcG9zaXRpb24vXG4gKi9cblxuLy8+PmxhYmVsOiBQb3NpdGlvblxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IFBvc2l0aW9ucyBlbGVtZW50cyByZWxhdGl2ZSB0byBvdGhlciBlbGVtZW50cy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9wb3NpdGlvbi9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9wb3NpdGlvbi9cblxuXG4oIGZ1bmN0aW9uKCkge1xudmFyIGNhY2hlZFNjcm9sbGJhcldpZHRoLFxuXHRtYXggPSBNYXRoLm1heCxcblx0YWJzID0gTWF0aC5hYnMsXG5cdHJob3Jpem9udGFsID0gL2xlZnR8Y2VudGVyfHJpZ2h0Lyxcblx0cnZlcnRpY2FsID0gL3RvcHxjZW50ZXJ8Ym90dG9tLyxcblx0cm9mZnNldCA9IC9bXFwrXFwtXVxcZCsoXFwuW1xcZF0rKT8lPy8sXG5cdHJwb3NpdGlvbiA9IC9eXFx3Ky8sXG5cdHJwZXJjZW50ID0gLyUkLyxcblx0X3Bvc2l0aW9uID0gJC5mbi5wb3NpdGlvbjtcblxuZnVuY3Rpb24gZ2V0T2Zmc2V0cyggb2Zmc2V0cywgd2lkdGgsIGhlaWdodCApIHtcblx0cmV0dXJuIFtcblx0XHRwYXJzZUZsb2F0KCBvZmZzZXRzWyAwIF0gKSAqICggcnBlcmNlbnQudGVzdCggb2Zmc2V0c1sgMCBdICkgPyB3aWR0aCAvIDEwMCA6IDEgKSxcblx0XHRwYXJzZUZsb2F0KCBvZmZzZXRzWyAxIF0gKSAqICggcnBlcmNlbnQudGVzdCggb2Zmc2V0c1sgMSBdICkgPyBoZWlnaHQgLyAxMDAgOiAxIClcblx0XTtcbn1cblxuZnVuY3Rpb24gcGFyc2VDc3MoIGVsZW1lbnQsIHByb3BlcnR5ICkge1xuXHRyZXR1cm4gcGFyc2VJbnQoICQuY3NzKCBlbGVtZW50LCBwcm9wZXJ0eSApLCAxMCApIHx8IDA7XG59XG5cbmZ1bmN0aW9uIGdldERpbWVuc2lvbnMoIGVsZW0gKSB7XG5cdHZhciByYXcgPSBlbGVtWyAwIF07XG5cdGlmICggcmF3Lm5vZGVUeXBlID09PSA5ICkge1xuXHRcdHJldHVybiB7XG5cdFx0XHR3aWR0aDogZWxlbS53aWR0aCgpLFxuXHRcdFx0aGVpZ2h0OiBlbGVtLmhlaWdodCgpLFxuXHRcdFx0b2Zmc2V0OiB7IHRvcDogMCwgbGVmdDogMCB9XG5cdFx0fTtcblx0fVxuXHRpZiAoICQuaXNXaW5kb3coIHJhdyApICkge1xuXHRcdHJldHVybiB7XG5cdFx0XHR3aWR0aDogZWxlbS53aWR0aCgpLFxuXHRcdFx0aGVpZ2h0OiBlbGVtLmhlaWdodCgpLFxuXHRcdFx0b2Zmc2V0OiB7IHRvcDogZWxlbS5zY3JvbGxUb3AoKSwgbGVmdDogZWxlbS5zY3JvbGxMZWZ0KCkgfVxuXHRcdH07XG5cdH1cblx0aWYgKCByYXcucHJldmVudERlZmF1bHQgKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHdpZHRoOiAwLFxuXHRcdFx0aGVpZ2h0OiAwLFxuXHRcdFx0b2Zmc2V0OiB7IHRvcDogcmF3LnBhZ2VZLCBsZWZ0OiByYXcucGFnZVggfVxuXHRcdH07XG5cdH1cblx0cmV0dXJuIHtcblx0XHR3aWR0aDogZWxlbS5vdXRlcldpZHRoKCksXG5cdFx0aGVpZ2h0OiBlbGVtLm91dGVySGVpZ2h0KCksXG5cdFx0b2Zmc2V0OiBlbGVtLm9mZnNldCgpXG5cdH07XG59XG5cbiQucG9zaXRpb24gPSB7XG5cdHNjcm9sbGJhcldpZHRoOiBmdW5jdGlvbigpIHtcblx0XHRpZiAoIGNhY2hlZFNjcm9sbGJhcldpZHRoICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRyZXR1cm4gY2FjaGVkU2Nyb2xsYmFyV2lkdGg7XG5cdFx0fVxuXHRcdHZhciB3MSwgdzIsXG5cdFx0XHRkaXYgPSAkKCBcIjxkaXYgXCIgK1xuXHRcdFx0XHRcInN0eWxlPSdkaXNwbGF5OmJsb2NrO3Bvc2l0aW9uOmFic29sdXRlO3dpZHRoOjUwcHg7aGVpZ2h0OjUwcHg7b3ZlcmZsb3c6aGlkZGVuOyc+XCIgK1xuXHRcdFx0XHRcIjxkaXYgc3R5bGU9J2hlaWdodDoxMDBweDt3aWR0aDphdXRvOyc+PC9kaXY+PC9kaXY+XCIgKSxcblx0XHRcdGlubmVyRGl2ID0gZGl2LmNoaWxkcmVuKClbIDAgXTtcblxuXHRcdCQoIFwiYm9keVwiICkuYXBwZW5kKCBkaXYgKTtcblx0XHR3MSA9IGlubmVyRGl2Lm9mZnNldFdpZHRoO1xuXHRcdGRpdi5jc3MoIFwib3ZlcmZsb3dcIiwgXCJzY3JvbGxcIiApO1xuXG5cdFx0dzIgPSBpbm5lckRpdi5vZmZzZXRXaWR0aDtcblxuXHRcdGlmICggdzEgPT09IHcyICkge1xuXHRcdFx0dzIgPSBkaXZbIDAgXS5jbGllbnRXaWR0aDtcblx0XHR9XG5cblx0XHRkaXYucmVtb3ZlKCk7XG5cblx0XHRyZXR1cm4gKCBjYWNoZWRTY3JvbGxiYXJXaWR0aCA9IHcxIC0gdzIgKTtcblx0fSxcblx0Z2V0U2Nyb2xsSW5mbzogZnVuY3Rpb24oIHdpdGhpbiApIHtcblx0XHR2YXIgb3ZlcmZsb3dYID0gd2l0aGluLmlzV2luZG93IHx8IHdpdGhpbi5pc0RvY3VtZW50ID8gXCJcIiA6XG5cdFx0XHRcdHdpdGhpbi5lbGVtZW50LmNzcyggXCJvdmVyZmxvdy14XCIgKSxcblx0XHRcdG92ZXJmbG93WSA9IHdpdGhpbi5pc1dpbmRvdyB8fCB3aXRoaW4uaXNEb2N1bWVudCA/IFwiXCIgOlxuXHRcdFx0XHR3aXRoaW4uZWxlbWVudC5jc3MoIFwib3ZlcmZsb3cteVwiICksXG5cdFx0XHRoYXNPdmVyZmxvd1ggPSBvdmVyZmxvd1ggPT09IFwic2Nyb2xsXCIgfHxcblx0XHRcdFx0KCBvdmVyZmxvd1ggPT09IFwiYXV0b1wiICYmIHdpdGhpbi53aWR0aCA8IHdpdGhpbi5lbGVtZW50WyAwIF0uc2Nyb2xsV2lkdGggKSxcblx0XHRcdGhhc092ZXJmbG93WSA9IG92ZXJmbG93WSA9PT0gXCJzY3JvbGxcIiB8fFxuXHRcdFx0XHQoIG92ZXJmbG93WSA9PT0gXCJhdXRvXCIgJiYgd2l0aGluLmhlaWdodCA8IHdpdGhpbi5lbGVtZW50WyAwIF0uc2Nyb2xsSGVpZ2h0ICk7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHdpZHRoOiBoYXNPdmVyZmxvd1kgPyAkLnBvc2l0aW9uLnNjcm9sbGJhcldpZHRoKCkgOiAwLFxuXHRcdFx0aGVpZ2h0OiBoYXNPdmVyZmxvd1ggPyAkLnBvc2l0aW9uLnNjcm9sbGJhcldpZHRoKCkgOiAwXG5cdFx0fTtcblx0fSxcblx0Z2V0V2l0aGluSW5mbzogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0dmFyIHdpdGhpbkVsZW1lbnQgPSAkKCBlbGVtZW50IHx8IHdpbmRvdyApLFxuXHRcdFx0aXNXaW5kb3cgPSAkLmlzV2luZG93KCB3aXRoaW5FbGVtZW50WyAwIF0gKSxcblx0XHRcdGlzRG9jdW1lbnQgPSAhIXdpdGhpbkVsZW1lbnRbIDAgXSAmJiB3aXRoaW5FbGVtZW50WyAwIF0ubm9kZVR5cGUgPT09IDksXG5cdFx0XHRoYXNPZmZzZXQgPSAhaXNXaW5kb3cgJiYgIWlzRG9jdW1lbnQ7XG5cdFx0cmV0dXJuIHtcblx0XHRcdGVsZW1lbnQ6IHdpdGhpbkVsZW1lbnQsXG5cdFx0XHRpc1dpbmRvdzogaXNXaW5kb3csXG5cdFx0XHRpc0RvY3VtZW50OiBpc0RvY3VtZW50LFxuXHRcdFx0b2Zmc2V0OiBoYXNPZmZzZXQgPyAkKCBlbGVtZW50ICkub2Zmc2V0KCkgOiB7IGxlZnQ6IDAsIHRvcDogMCB9LFxuXHRcdFx0c2Nyb2xsTGVmdDogd2l0aGluRWxlbWVudC5zY3JvbGxMZWZ0KCksXG5cdFx0XHRzY3JvbGxUb3A6IHdpdGhpbkVsZW1lbnQuc2Nyb2xsVG9wKCksXG5cdFx0XHR3aWR0aDogd2l0aGluRWxlbWVudC5vdXRlcldpZHRoKCksXG5cdFx0XHRoZWlnaHQ6IHdpdGhpbkVsZW1lbnQub3V0ZXJIZWlnaHQoKVxuXHRcdH07XG5cdH1cbn07XG5cbiQuZm4ucG9zaXRpb24gPSBmdW5jdGlvbiggb3B0aW9ucyApIHtcblx0aWYgKCAhb3B0aW9ucyB8fCAhb3B0aW9ucy5vZiApIHtcblx0XHRyZXR1cm4gX3Bvc2l0aW9uLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0fVxuXG5cdC8vIE1ha2UgYSBjb3B5LCB3ZSBkb24ndCB3YW50IHRvIG1vZGlmeSBhcmd1bWVudHNcblx0b3B0aW9ucyA9ICQuZXh0ZW5kKCB7fSwgb3B0aW9ucyApO1xuXG5cdHZhciBhdE9mZnNldCwgdGFyZ2V0V2lkdGgsIHRhcmdldEhlaWdodCwgdGFyZ2V0T2Zmc2V0LCBiYXNlUG9zaXRpb24sIGRpbWVuc2lvbnMsXG5cdFx0dGFyZ2V0ID0gJCggb3B0aW9ucy5vZiApLFxuXHRcdHdpdGhpbiA9ICQucG9zaXRpb24uZ2V0V2l0aGluSW5mbyggb3B0aW9ucy53aXRoaW4gKSxcblx0XHRzY3JvbGxJbmZvID0gJC5wb3NpdGlvbi5nZXRTY3JvbGxJbmZvKCB3aXRoaW4gKSxcblx0XHRjb2xsaXNpb24gPSAoIG9wdGlvbnMuY29sbGlzaW9uIHx8IFwiZmxpcFwiICkuc3BsaXQoIFwiIFwiICksXG5cdFx0b2Zmc2V0cyA9IHt9O1xuXG5cdGRpbWVuc2lvbnMgPSBnZXREaW1lbnNpb25zKCB0YXJnZXQgKTtcblx0aWYgKCB0YXJnZXRbIDAgXS5wcmV2ZW50RGVmYXVsdCApIHtcblxuXHRcdC8vIEZvcmNlIGxlZnQgdG9wIHRvIGFsbG93IGZsaXBwaW5nXG5cdFx0b3B0aW9ucy5hdCA9IFwibGVmdCB0b3BcIjtcblx0fVxuXHR0YXJnZXRXaWR0aCA9IGRpbWVuc2lvbnMud2lkdGg7XG5cdHRhcmdldEhlaWdodCA9IGRpbWVuc2lvbnMuaGVpZ2h0O1xuXHR0YXJnZXRPZmZzZXQgPSBkaW1lbnNpb25zLm9mZnNldDtcblxuXHQvLyBDbG9uZSB0byByZXVzZSBvcmlnaW5hbCB0YXJnZXRPZmZzZXQgbGF0ZXJcblx0YmFzZVBvc2l0aW9uID0gJC5leHRlbmQoIHt9LCB0YXJnZXRPZmZzZXQgKTtcblxuXHQvLyBGb3JjZSBteSBhbmQgYXQgdG8gaGF2ZSB2YWxpZCBob3Jpem9udGFsIGFuZCB2ZXJ0aWNhbCBwb3NpdGlvbnNcblx0Ly8gaWYgYSB2YWx1ZSBpcyBtaXNzaW5nIG9yIGludmFsaWQsIGl0IHdpbGwgYmUgY29udmVydGVkIHRvIGNlbnRlclxuXHQkLmVhY2goIFsgXCJteVwiLCBcImF0XCIgXSwgZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHBvcyA9ICggb3B0aW9uc1sgdGhpcyBdIHx8IFwiXCIgKS5zcGxpdCggXCIgXCIgKSxcblx0XHRcdGhvcml6b250YWxPZmZzZXQsXG5cdFx0XHR2ZXJ0aWNhbE9mZnNldDtcblxuXHRcdGlmICggcG9zLmxlbmd0aCA9PT0gMSApIHtcblx0XHRcdHBvcyA9IHJob3Jpem9udGFsLnRlc3QoIHBvc1sgMCBdICkgP1xuXHRcdFx0XHRwb3MuY29uY2F0KCBbIFwiY2VudGVyXCIgXSApIDpcblx0XHRcdFx0cnZlcnRpY2FsLnRlc3QoIHBvc1sgMCBdICkgP1xuXHRcdFx0XHRcdFsgXCJjZW50ZXJcIiBdLmNvbmNhdCggcG9zICkgOlxuXHRcdFx0XHRcdFsgXCJjZW50ZXJcIiwgXCJjZW50ZXJcIiBdO1xuXHRcdH1cblx0XHRwb3NbIDAgXSA9IHJob3Jpem9udGFsLnRlc3QoIHBvc1sgMCBdICkgPyBwb3NbIDAgXSA6IFwiY2VudGVyXCI7XG5cdFx0cG9zWyAxIF0gPSBydmVydGljYWwudGVzdCggcG9zWyAxIF0gKSA/IHBvc1sgMSBdIDogXCJjZW50ZXJcIjtcblxuXHRcdC8vIENhbGN1bGF0ZSBvZmZzZXRzXG5cdFx0aG9yaXpvbnRhbE9mZnNldCA9IHJvZmZzZXQuZXhlYyggcG9zWyAwIF0gKTtcblx0XHR2ZXJ0aWNhbE9mZnNldCA9IHJvZmZzZXQuZXhlYyggcG9zWyAxIF0gKTtcblx0XHRvZmZzZXRzWyB0aGlzIF0gPSBbXG5cdFx0XHRob3Jpem9udGFsT2Zmc2V0ID8gaG9yaXpvbnRhbE9mZnNldFsgMCBdIDogMCxcblx0XHRcdHZlcnRpY2FsT2Zmc2V0ID8gdmVydGljYWxPZmZzZXRbIDAgXSA6IDBcblx0XHRdO1xuXG5cdFx0Ly8gUmVkdWNlIHRvIGp1c3QgdGhlIHBvc2l0aW9ucyB3aXRob3V0IHRoZSBvZmZzZXRzXG5cdFx0b3B0aW9uc1sgdGhpcyBdID0gW1xuXHRcdFx0cnBvc2l0aW9uLmV4ZWMoIHBvc1sgMCBdIClbIDAgXSxcblx0XHRcdHJwb3NpdGlvbi5leGVjKCBwb3NbIDEgXSApWyAwIF1cblx0XHRdO1xuXHR9ICk7XG5cblx0Ly8gTm9ybWFsaXplIGNvbGxpc2lvbiBvcHRpb25cblx0aWYgKCBjb2xsaXNpb24ubGVuZ3RoID09PSAxICkge1xuXHRcdGNvbGxpc2lvblsgMSBdID0gY29sbGlzaW9uWyAwIF07XG5cdH1cblxuXHRpZiAoIG9wdGlvbnMuYXRbIDAgXSA9PT0gXCJyaWdodFwiICkge1xuXHRcdGJhc2VQb3NpdGlvbi5sZWZ0ICs9IHRhcmdldFdpZHRoO1xuXHR9IGVsc2UgaWYgKCBvcHRpb25zLmF0WyAwIF0gPT09IFwiY2VudGVyXCIgKSB7XG5cdFx0YmFzZVBvc2l0aW9uLmxlZnQgKz0gdGFyZ2V0V2lkdGggLyAyO1xuXHR9XG5cblx0aWYgKCBvcHRpb25zLmF0WyAxIF0gPT09IFwiYm90dG9tXCIgKSB7XG5cdFx0YmFzZVBvc2l0aW9uLnRvcCArPSB0YXJnZXRIZWlnaHQ7XG5cdH0gZWxzZSBpZiAoIG9wdGlvbnMuYXRbIDEgXSA9PT0gXCJjZW50ZXJcIiApIHtcblx0XHRiYXNlUG9zaXRpb24udG9wICs9IHRhcmdldEhlaWdodCAvIDI7XG5cdH1cblxuXHRhdE9mZnNldCA9IGdldE9mZnNldHMoIG9mZnNldHMuYXQsIHRhcmdldFdpZHRoLCB0YXJnZXRIZWlnaHQgKTtcblx0YmFzZVBvc2l0aW9uLmxlZnQgKz0gYXRPZmZzZXRbIDAgXTtcblx0YmFzZVBvc2l0aW9uLnRvcCArPSBhdE9mZnNldFsgMSBdO1xuXG5cdHJldHVybiB0aGlzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdHZhciBjb2xsaXNpb25Qb3NpdGlvbiwgdXNpbmcsXG5cdFx0XHRlbGVtID0gJCggdGhpcyApLFxuXHRcdFx0ZWxlbVdpZHRoID0gZWxlbS5vdXRlcldpZHRoKCksXG5cdFx0XHRlbGVtSGVpZ2h0ID0gZWxlbS5vdXRlckhlaWdodCgpLFxuXHRcdFx0bWFyZ2luTGVmdCA9IHBhcnNlQ3NzKCB0aGlzLCBcIm1hcmdpbkxlZnRcIiApLFxuXHRcdFx0bWFyZ2luVG9wID0gcGFyc2VDc3MoIHRoaXMsIFwibWFyZ2luVG9wXCIgKSxcblx0XHRcdGNvbGxpc2lvbldpZHRoID0gZWxlbVdpZHRoICsgbWFyZ2luTGVmdCArIHBhcnNlQ3NzKCB0aGlzLCBcIm1hcmdpblJpZ2h0XCIgKSArXG5cdFx0XHRcdHNjcm9sbEluZm8ud2lkdGgsXG5cdFx0XHRjb2xsaXNpb25IZWlnaHQgPSBlbGVtSGVpZ2h0ICsgbWFyZ2luVG9wICsgcGFyc2VDc3MoIHRoaXMsIFwibWFyZ2luQm90dG9tXCIgKSArXG5cdFx0XHRcdHNjcm9sbEluZm8uaGVpZ2h0LFxuXHRcdFx0cG9zaXRpb24gPSAkLmV4dGVuZCgge30sIGJhc2VQb3NpdGlvbiApLFxuXHRcdFx0bXlPZmZzZXQgPSBnZXRPZmZzZXRzKCBvZmZzZXRzLm15LCBlbGVtLm91dGVyV2lkdGgoKSwgZWxlbS5vdXRlckhlaWdodCgpICk7XG5cblx0XHRpZiAoIG9wdGlvbnMubXlbIDAgXSA9PT0gXCJyaWdodFwiICkge1xuXHRcdFx0cG9zaXRpb24ubGVmdCAtPSBlbGVtV2lkdGg7XG5cdFx0fSBlbHNlIGlmICggb3B0aW9ucy5teVsgMCBdID09PSBcImNlbnRlclwiICkge1xuXHRcdFx0cG9zaXRpb24ubGVmdCAtPSBlbGVtV2lkdGggLyAyO1xuXHRcdH1cblxuXHRcdGlmICggb3B0aW9ucy5teVsgMSBdID09PSBcImJvdHRvbVwiICkge1xuXHRcdFx0cG9zaXRpb24udG9wIC09IGVsZW1IZWlnaHQ7XG5cdFx0fSBlbHNlIGlmICggb3B0aW9ucy5teVsgMSBdID09PSBcImNlbnRlclwiICkge1xuXHRcdFx0cG9zaXRpb24udG9wIC09IGVsZW1IZWlnaHQgLyAyO1xuXHRcdH1cblxuXHRcdHBvc2l0aW9uLmxlZnQgKz0gbXlPZmZzZXRbIDAgXTtcblx0XHRwb3NpdGlvbi50b3AgKz0gbXlPZmZzZXRbIDEgXTtcblxuXHRcdGNvbGxpc2lvblBvc2l0aW9uID0ge1xuXHRcdFx0bWFyZ2luTGVmdDogbWFyZ2luTGVmdCxcblx0XHRcdG1hcmdpblRvcDogbWFyZ2luVG9wXG5cdFx0fTtcblxuXHRcdCQuZWFjaCggWyBcImxlZnRcIiwgXCJ0b3BcIiBdLCBmdW5jdGlvbiggaSwgZGlyICkge1xuXHRcdFx0aWYgKCAkLnVpLnBvc2l0aW9uWyBjb2xsaXNpb25bIGkgXSBdICkge1xuXHRcdFx0XHQkLnVpLnBvc2l0aW9uWyBjb2xsaXNpb25bIGkgXSBdWyBkaXIgXSggcG9zaXRpb24sIHtcblx0XHRcdFx0XHR0YXJnZXRXaWR0aDogdGFyZ2V0V2lkdGgsXG5cdFx0XHRcdFx0dGFyZ2V0SGVpZ2h0OiB0YXJnZXRIZWlnaHQsXG5cdFx0XHRcdFx0ZWxlbVdpZHRoOiBlbGVtV2lkdGgsXG5cdFx0XHRcdFx0ZWxlbUhlaWdodDogZWxlbUhlaWdodCxcblx0XHRcdFx0XHRjb2xsaXNpb25Qb3NpdGlvbjogY29sbGlzaW9uUG9zaXRpb24sXG5cdFx0XHRcdFx0Y29sbGlzaW9uV2lkdGg6IGNvbGxpc2lvbldpZHRoLFxuXHRcdFx0XHRcdGNvbGxpc2lvbkhlaWdodDogY29sbGlzaW9uSGVpZ2h0LFxuXHRcdFx0XHRcdG9mZnNldDogWyBhdE9mZnNldFsgMCBdICsgbXlPZmZzZXRbIDAgXSwgYXRPZmZzZXQgWyAxIF0gKyBteU9mZnNldFsgMSBdIF0sXG5cdFx0XHRcdFx0bXk6IG9wdGlvbnMubXksXG5cdFx0XHRcdFx0YXQ6IG9wdGlvbnMuYXQsXG5cdFx0XHRcdFx0d2l0aGluOiB3aXRoaW4sXG5cdFx0XHRcdFx0ZWxlbTogZWxlbVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0aWYgKCBvcHRpb25zLnVzaW5nICkge1xuXG5cdFx0XHQvLyBBZGRzIGZlZWRiYWNrIGFzIHNlY29uZCBhcmd1bWVudCB0byB1c2luZyBjYWxsYmFjaywgaWYgcHJlc2VudFxuXHRcdFx0dXNpbmcgPSBmdW5jdGlvbiggcHJvcHMgKSB7XG5cdFx0XHRcdHZhciBsZWZ0ID0gdGFyZ2V0T2Zmc2V0LmxlZnQgLSBwb3NpdGlvbi5sZWZ0LFxuXHRcdFx0XHRcdHJpZ2h0ID0gbGVmdCArIHRhcmdldFdpZHRoIC0gZWxlbVdpZHRoLFxuXHRcdFx0XHRcdHRvcCA9IHRhcmdldE9mZnNldC50b3AgLSBwb3NpdGlvbi50b3AsXG5cdFx0XHRcdFx0Ym90dG9tID0gdG9wICsgdGFyZ2V0SGVpZ2h0IC0gZWxlbUhlaWdodCxcblx0XHRcdFx0XHRmZWVkYmFjayA9IHtcblx0XHRcdFx0XHRcdHRhcmdldDoge1xuXHRcdFx0XHRcdFx0XHRlbGVtZW50OiB0YXJnZXQsXG5cdFx0XHRcdFx0XHRcdGxlZnQ6IHRhcmdldE9mZnNldC5sZWZ0LFxuXHRcdFx0XHRcdFx0XHR0b3A6IHRhcmdldE9mZnNldC50b3AsXG5cdFx0XHRcdFx0XHRcdHdpZHRoOiB0YXJnZXRXaWR0aCxcblx0XHRcdFx0XHRcdFx0aGVpZ2h0OiB0YXJnZXRIZWlnaHRcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRlbGVtZW50OiB7XG5cdFx0XHRcdFx0XHRcdGVsZW1lbnQ6IGVsZW0sXG5cdFx0XHRcdFx0XHRcdGxlZnQ6IHBvc2l0aW9uLmxlZnQsXG5cdFx0XHRcdFx0XHRcdHRvcDogcG9zaXRpb24udG9wLFxuXHRcdFx0XHRcdFx0XHR3aWR0aDogZWxlbVdpZHRoLFxuXHRcdFx0XHRcdFx0XHRoZWlnaHQ6IGVsZW1IZWlnaHRcblx0XHRcdFx0XHRcdH0sXG5cdFx0XHRcdFx0XHRob3Jpem9udGFsOiByaWdodCA8IDAgPyBcImxlZnRcIiA6IGxlZnQgPiAwID8gXCJyaWdodFwiIDogXCJjZW50ZXJcIixcblx0XHRcdFx0XHRcdHZlcnRpY2FsOiBib3R0b20gPCAwID8gXCJ0b3BcIiA6IHRvcCA+IDAgPyBcImJvdHRvbVwiIDogXCJtaWRkbGVcIlxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdGlmICggdGFyZ2V0V2lkdGggPCBlbGVtV2lkdGggJiYgYWJzKCBsZWZ0ICsgcmlnaHQgKSA8IHRhcmdldFdpZHRoICkge1xuXHRcdFx0XHRcdGZlZWRiYWNrLmhvcml6b250YWwgPSBcImNlbnRlclwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggdGFyZ2V0SGVpZ2h0IDwgZWxlbUhlaWdodCAmJiBhYnMoIHRvcCArIGJvdHRvbSApIDwgdGFyZ2V0SGVpZ2h0ICkge1xuXHRcdFx0XHRcdGZlZWRiYWNrLnZlcnRpY2FsID0gXCJtaWRkbGVcIjtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIG1heCggYWJzKCBsZWZ0ICksIGFicyggcmlnaHQgKSApID4gbWF4KCBhYnMoIHRvcCApLCBhYnMoIGJvdHRvbSApICkgKSB7XG5cdFx0XHRcdFx0ZmVlZGJhY2suaW1wb3J0YW50ID0gXCJob3Jpem9udGFsXCI7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0ZmVlZGJhY2suaW1wb3J0YW50ID0gXCJ2ZXJ0aWNhbFwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdG9wdGlvbnMudXNpbmcuY2FsbCggdGhpcywgcHJvcHMsIGZlZWRiYWNrICk7XG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdGVsZW0ub2Zmc2V0KCAkLmV4dGVuZCggcG9zaXRpb24sIHsgdXNpbmc6IHVzaW5nIH0gKSApO1xuXHR9ICk7XG59O1xuXG4kLnVpLnBvc2l0aW9uID0ge1xuXHRmaXQ6IHtcblx0XHRsZWZ0OiBmdW5jdGlvbiggcG9zaXRpb24sIGRhdGEgKSB7XG5cdFx0XHR2YXIgd2l0aGluID0gZGF0YS53aXRoaW4sXG5cdFx0XHRcdHdpdGhpbk9mZnNldCA9IHdpdGhpbi5pc1dpbmRvdyA/IHdpdGhpbi5zY3JvbGxMZWZ0IDogd2l0aGluLm9mZnNldC5sZWZ0LFxuXHRcdFx0XHRvdXRlcldpZHRoID0gd2l0aGluLndpZHRoLFxuXHRcdFx0XHRjb2xsaXNpb25Qb3NMZWZ0ID0gcG9zaXRpb24ubGVmdCAtIGRhdGEuY29sbGlzaW9uUG9zaXRpb24ubWFyZ2luTGVmdCxcblx0XHRcdFx0b3ZlckxlZnQgPSB3aXRoaW5PZmZzZXQgLSBjb2xsaXNpb25Qb3NMZWZ0LFxuXHRcdFx0XHRvdmVyUmlnaHQgPSBjb2xsaXNpb25Qb3NMZWZ0ICsgZGF0YS5jb2xsaXNpb25XaWR0aCAtIG91dGVyV2lkdGggLSB3aXRoaW5PZmZzZXQsXG5cdFx0XHRcdG5ld092ZXJSaWdodDtcblxuXHRcdFx0Ly8gRWxlbWVudCBpcyB3aWRlciB0aGFuIHdpdGhpblxuXHRcdFx0aWYgKCBkYXRhLmNvbGxpc2lvbldpZHRoID4gb3V0ZXJXaWR0aCApIHtcblxuXHRcdFx0XHQvLyBFbGVtZW50IGlzIGluaXRpYWxseSBvdmVyIHRoZSBsZWZ0IHNpZGUgb2Ygd2l0aGluXG5cdFx0XHRcdGlmICggb3ZlckxlZnQgPiAwICYmIG92ZXJSaWdodCA8PSAwICkge1xuXHRcdFx0XHRcdG5ld092ZXJSaWdodCA9IHBvc2l0aW9uLmxlZnQgKyBvdmVyTGVmdCArIGRhdGEuY29sbGlzaW9uV2lkdGggLSBvdXRlcldpZHRoIC1cblx0XHRcdFx0XHRcdHdpdGhpbk9mZnNldDtcblx0XHRcdFx0XHRwb3NpdGlvbi5sZWZ0ICs9IG92ZXJMZWZ0IC0gbmV3T3ZlclJpZ2h0O1xuXG5cdFx0XHRcdC8vIEVsZW1lbnQgaXMgaW5pdGlhbGx5IG92ZXIgcmlnaHQgc2lkZSBvZiB3aXRoaW5cblx0XHRcdFx0fSBlbHNlIGlmICggb3ZlclJpZ2h0ID4gMCAmJiBvdmVyTGVmdCA8PSAwICkge1xuXHRcdFx0XHRcdHBvc2l0aW9uLmxlZnQgPSB3aXRoaW5PZmZzZXQ7XG5cblx0XHRcdFx0Ly8gRWxlbWVudCBpcyBpbml0aWFsbHkgb3ZlciBib3RoIGxlZnQgYW5kIHJpZ2h0IHNpZGVzIG9mIHdpdGhpblxuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGlmICggb3ZlckxlZnQgPiBvdmVyUmlnaHQgKSB7XG5cdFx0XHRcdFx0XHRwb3NpdGlvbi5sZWZ0ID0gd2l0aGluT2Zmc2V0ICsgb3V0ZXJXaWR0aCAtIGRhdGEuY29sbGlzaW9uV2lkdGg7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHBvc2l0aW9uLmxlZnQgPSB3aXRoaW5PZmZzZXQ7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdC8vIFRvbyBmYXIgbGVmdCAtPiBhbGlnbiB3aXRoIGxlZnQgZWRnZVxuXHRcdFx0fSBlbHNlIGlmICggb3ZlckxlZnQgPiAwICkge1xuXHRcdFx0XHRwb3NpdGlvbi5sZWZ0ICs9IG92ZXJMZWZ0O1xuXG5cdFx0XHQvLyBUb28gZmFyIHJpZ2h0IC0+IGFsaWduIHdpdGggcmlnaHQgZWRnZVxuXHRcdFx0fSBlbHNlIGlmICggb3ZlclJpZ2h0ID4gMCApIHtcblx0XHRcdFx0cG9zaXRpb24ubGVmdCAtPSBvdmVyUmlnaHQ7XG5cblx0XHRcdC8vIEFkanVzdCBiYXNlZCBvbiBwb3NpdGlvbiBhbmQgbWFyZ2luXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRwb3NpdGlvbi5sZWZ0ID0gbWF4KCBwb3NpdGlvbi5sZWZ0IC0gY29sbGlzaW9uUG9zTGVmdCwgcG9zaXRpb24ubGVmdCApO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0dG9wOiBmdW5jdGlvbiggcG9zaXRpb24sIGRhdGEgKSB7XG5cdFx0XHR2YXIgd2l0aGluID0gZGF0YS53aXRoaW4sXG5cdFx0XHRcdHdpdGhpbk9mZnNldCA9IHdpdGhpbi5pc1dpbmRvdyA/IHdpdGhpbi5zY3JvbGxUb3AgOiB3aXRoaW4ub2Zmc2V0LnRvcCxcblx0XHRcdFx0b3V0ZXJIZWlnaHQgPSBkYXRhLndpdGhpbi5oZWlnaHQsXG5cdFx0XHRcdGNvbGxpc2lvblBvc1RvcCA9IHBvc2l0aW9uLnRvcCAtIGRhdGEuY29sbGlzaW9uUG9zaXRpb24ubWFyZ2luVG9wLFxuXHRcdFx0XHRvdmVyVG9wID0gd2l0aGluT2Zmc2V0IC0gY29sbGlzaW9uUG9zVG9wLFxuXHRcdFx0XHRvdmVyQm90dG9tID0gY29sbGlzaW9uUG9zVG9wICsgZGF0YS5jb2xsaXNpb25IZWlnaHQgLSBvdXRlckhlaWdodCAtIHdpdGhpbk9mZnNldCxcblx0XHRcdFx0bmV3T3ZlckJvdHRvbTtcblxuXHRcdFx0Ly8gRWxlbWVudCBpcyB0YWxsZXIgdGhhbiB3aXRoaW5cblx0XHRcdGlmICggZGF0YS5jb2xsaXNpb25IZWlnaHQgPiBvdXRlckhlaWdodCApIHtcblxuXHRcdFx0XHQvLyBFbGVtZW50IGlzIGluaXRpYWxseSBvdmVyIHRoZSB0b3Agb2Ygd2l0aGluXG5cdFx0XHRcdGlmICggb3ZlclRvcCA+IDAgJiYgb3ZlckJvdHRvbSA8PSAwICkge1xuXHRcdFx0XHRcdG5ld092ZXJCb3R0b20gPSBwb3NpdGlvbi50b3AgKyBvdmVyVG9wICsgZGF0YS5jb2xsaXNpb25IZWlnaHQgLSBvdXRlckhlaWdodCAtXG5cdFx0XHRcdFx0XHR3aXRoaW5PZmZzZXQ7XG5cdFx0XHRcdFx0cG9zaXRpb24udG9wICs9IG92ZXJUb3AgLSBuZXdPdmVyQm90dG9tO1xuXG5cdFx0XHRcdC8vIEVsZW1lbnQgaXMgaW5pdGlhbGx5IG92ZXIgYm90dG9tIG9mIHdpdGhpblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvdmVyQm90dG9tID4gMCAmJiBvdmVyVG9wIDw9IDAgKSB7XG5cdFx0XHRcdFx0cG9zaXRpb24udG9wID0gd2l0aGluT2Zmc2V0O1xuXG5cdFx0XHRcdC8vIEVsZW1lbnQgaXMgaW5pdGlhbGx5IG92ZXIgYm90aCB0b3AgYW5kIGJvdHRvbSBvZiB3aXRoaW5cblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRpZiAoIG92ZXJUb3AgPiBvdmVyQm90dG9tICkge1xuXHRcdFx0XHRcdFx0cG9zaXRpb24udG9wID0gd2l0aGluT2Zmc2V0ICsgb3V0ZXJIZWlnaHQgLSBkYXRhLmNvbGxpc2lvbkhlaWdodDtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0cG9zaXRpb24udG9wID0gd2l0aGluT2Zmc2V0O1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHQvLyBUb28gZmFyIHVwIC0+IGFsaWduIHdpdGggdG9wXG5cdFx0XHR9IGVsc2UgaWYgKCBvdmVyVG9wID4gMCApIHtcblx0XHRcdFx0cG9zaXRpb24udG9wICs9IG92ZXJUb3A7XG5cblx0XHRcdC8vIFRvbyBmYXIgZG93biAtPiBhbGlnbiB3aXRoIGJvdHRvbSBlZGdlXG5cdFx0XHR9IGVsc2UgaWYgKCBvdmVyQm90dG9tID4gMCApIHtcblx0XHRcdFx0cG9zaXRpb24udG9wIC09IG92ZXJCb3R0b207XG5cblx0XHRcdC8vIEFkanVzdCBiYXNlZCBvbiBwb3NpdGlvbiBhbmQgbWFyZ2luXG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRwb3NpdGlvbi50b3AgPSBtYXgoIHBvc2l0aW9uLnRvcCAtIGNvbGxpc2lvblBvc1RvcCwgcG9zaXRpb24udG9wICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXHRmbGlwOiB7XG5cdFx0bGVmdDogZnVuY3Rpb24oIHBvc2l0aW9uLCBkYXRhICkge1xuXHRcdFx0dmFyIHdpdGhpbiA9IGRhdGEud2l0aGluLFxuXHRcdFx0XHR3aXRoaW5PZmZzZXQgPSB3aXRoaW4ub2Zmc2V0LmxlZnQgKyB3aXRoaW4uc2Nyb2xsTGVmdCxcblx0XHRcdFx0b3V0ZXJXaWR0aCA9IHdpdGhpbi53aWR0aCxcblx0XHRcdFx0b2Zmc2V0TGVmdCA9IHdpdGhpbi5pc1dpbmRvdyA/IHdpdGhpbi5zY3JvbGxMZWZ0IDogd2l0aGluLm9mZnNldC5sZWZ0LFxuXHRcdFx0XHRjb2xsaXNpb25Qb3NMZWZ0ID0gcG9zaXRpb24ubGVmdCAtIGRhdGEuY29sbGlzaW9uUG9zaXRpb24ubWFyZ2luTGVmdCxcblx0XHRcdFx0b3ZlckxlZnQgPSBjb2xsaXNpb25Qb3NMZWZ0IC0gb2Zmc2V0TGVmdCxcblx0XHRcdFx0b3ZlclJpZ2h0ID0gY29sbGlzaW9uUG9zTGVmdCArIGRhdGEuY29sbGlzaW9uV2lkdGggLSBvdXRlcldpZHRoIC0gb2Zmc2V0TGVmdCxcblx0XHRcdFx0bXlPZmZzZXQgPSBkYXRhLm15WyAwIF0gPT09IFwibGVmdFwiID9cblx0XHRcdFx0XHQtZGF0YS5lbGVtV2lkdGggOlxuXHRcdFx0XHRcdGRhdGEubXlbIDAgXSA9PT0gXCJyaWdodFwiID9cblx0XHRcdFx0XHRcdGRhdGEuZWxlbVdpZHRoIDpcblx0XHRcdFx0XHRcdDAsXG5cdFx0XHRcdGF0T2Zmc2V0ID0gZGF0YS5hdFsgMCBdID09PSBcImxlZnRcIiA/XG5cdFx0XHRcdFx0ZGF0YS50YXJnZXRXaWR0aCA6XG5cdFx0XHRcdFx0ZGF0YS5hdFsgMCBdID09PSBcInJpZ2h0XCIgP1xuXHRcdFx0XHRcdFx0LWRhdGEudGFyZ2V0V2lkdGggOlxuXHRcdFx0XHRcdFx0MCxcblx0XHRcdFx0b2Zmc2V0ID0gLTIgKiBkYXRhLm9mZnNldFsgMCBdLFxuXHRcdFx0XHRuZXdPdmVyUmlnaHQsXG5cdFx0XHRcdG5ld092ZXJMZWZ0O1xuXG5cdFx0XHRpZiAoIG92ZXJMZWZ0IDwgMCApIHtcblx0XHRcdFx0bmV3T3ZlclJpZ2h0ID0gcG9zaXRpb24ubGVmdCArIG15T2Zmc2V0ICsgYXRPZmZzZXQgKyBvZmZzZXQgKyBkYXRhLmNvbGxpc2lvbldpZHRoIC1cblx0XHRcdFx0XHRvdXRlcldpZHRoIC0gd2l0aGluT2Zmc2V0O1xuXHRcdFx0XHRpZiAoIG5ld092ZXJSaWdodCA8IDAgfHwgbmV3T3ZlclJpZ2h0IDwgYWJzKCBvdmVyTGVmdCApICkge1xuXHRcdFx0XHRcdHBvc2l0aW9uLmxlZnQgKz0gbXlPZmZzZXQgKyBhdE9mZnNldCArIG9mZnNldDtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIGlmICggb3ZlclJpZ2h0ID4gMCApIHtcblx0XHRcdFx0bmV3T3ZlckxlZnQgPSBwb3NpdGlvbi5sZWZ0IC0gZGF0YS5jb2xsaXNpb25Qb3NpdGlvbi5tYXJnaW5MZWZ0ICsgbXlPZmZzZXQgK1xuXHRcdFx0XHRcdGF0T2Zmc2V0ICsgb2Zmc2V0IC0gb2Zmc2V0TGVmdDtcblx0XHRcdFx0aWYgKCBuZXdPdmVyTGVmdCA+IDAgfHwgYWJzKCBuZXdPdmVyTGVmdCApIDwgb3ZlclJpZ2h0ICkge1xuXHRcdFx0XHRcdHBvc2l0aW9uLmxlZnQgKz0gbXlPZmZzZXQgKyBhdE9mZnNldCArIG9mZnNldDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sXG5cdFx0dG9wOiBmdW5jdGlvbiggcG9zaXRpb24sIGRhdGEgKSB7XG5cdFx0XHR2YXIgd2l0aGluID0gZGF0YS53aXRoaW4sXG5cdFx0XHRcdHdpdGhpbk9mZnNldCA9IHdpdGhpbi5vZmZzZXQudG9wICsgd2l0aGluLnNjcm9sbFRvcCxcblx0XHRcdFx0b3V0ZXJIZWlnaHQgPSB3aXRoaW4uaGVpZ2h0LFxuXHRcdFx0XHRvZmZzZXRUb3AgPSB3aXRoaW4uaXNXaW5kb3cgPyB3aXRoaW4uc2Nyb2xsVG9wIDogd2l0aGluLm9mZnNldC50b3AsXG5cdFx0XHRcdGNvbGxpc2lvblBvc1RvcCA9IHBvc2l0aW9uLnRvcCAtIGRhdGEuY29sbGlzaW9uUG9zaXRpb24ubWFyZ2luVG9wLFxuXHRcdFx0XHRvdmVyVG9wID0gY29sbGlzaW9uUG9zVG9wIC0gb2Zmc2V0VG9wLFxuXHRcdFx0XHRvdmVyQm90dG9tID0gY29sbGlzaW9uUG9zVG9wICsgZGF0YS5jb2xsaXNpb25IZWlnaHQgLSBvdXRlckhlaWdodCAtIG9mZnNldFRvcCxcblx0XHRcdFx0dG9wID0gZGF0YS5teVsgMSBdID09PSBcInRvcFwiLFxuXHRcdFx0XHRteU9mZnNldCA9IHRvcCA/XG5cdFx0XHRcdFx0LWRhdGEuZWxlbUhlaWdodCA6XG5cdFx0XHRcdFx0ZGF0YS5teVsgMSBdID09PSBcImJvdHRvbVwiID9cblx0XHRcdFx0XHRcdGRhdGEuZWxlbUhlaWdodCA6XG5cdFx0XHRcdFx0XHQwLFxuXHRcdFx0XHRhdE9mZnNldCA9IGRhdGEuYXRbIDEgXSA9PT0gXCJ0b3BcIiA/XG5cdFx0XHRcdFx0ZGF0YS50YXJnZXRIZWlnaHQgOlxuXHRcdFx0XHRcdGRhdGEuYXRbIDEgXSA9PT0gXCJib3R0b21cIiA/XG5cdFx0XHRcdFx0XHQtZGF0YS50YXJnZXRIZWlnaHQgOlxuXHRcdFx0XHRcdFx0MCxcblx0XHRcdFx0b2Zmc2V0ID0gLTIgKiBkYXRhLm9mZnNldFsgMSBdLFxuXHRcdFx0XHRuZXdPdmVyVG9wLFxuXHRcdFx0XHRuZXdPdmVyQm90dG9tO1xuXHRcdFx0aWYgKCBvdmVyVG9wIDwgMCApIHtcblx0XHRcdFx0bmV3T3ZlckJvdHRvbSA9IHBvc2l0aW9uLnRvcCArIG15T2Zmc2V0ICsgYXRPZmZzZXQgKyBvZmZzZXQgKyBkYXRhLmNvbGxpc2lvbkhlaWdodCAtXG5cdFx0XHRcdFx0b3V0ZXJIZWlnaHQgLSB3aXRoaW5PZmZzZXQ7XG5cdFx0XHRcdGlmICggbmV3T3ZlckJvdHRvbSA8IDAgfHwgbmV3T3ZlckJvdHRvbSA8IGFicyggb3ZlclRvcCApICkge1xuXHRcdFx0XHRcdHBvc2l0aW9uLnRvcCArPSBteU9mZnNldCArIGF0T2Zmc2V0ICsgb2Zmc2V0O1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2UgaWYgKCBvdmVyQm90dG9tID4gMCApIHtcblx0XHRcdFx0bmV3T3ZlclRvcCA9IHBvc2l0aW9uLnRvcCAtIGRhdGEuY29sbGlzaW9uUG9zaXRpb24ubWFyZ2luVG9wICsgbXlPZmZzZXQgKyBhdE9mZnNldCArXG5cdFx0XHRcdFx0b2Zmc2V0IC0gb2Zmc2V0VG9wO1xuXHRcdFx0XHRpZiAoIG5ld092ZXJUb3AgPiAwIHx8IGFicyggbmV3T3ZlclRvcCApIDwgb3ZlckJvdHRvbSApIHtcblx0XHRcdFx0XHRwb3NpdGlvbi50b3AgKz0gbXlPZmZzZXQgKyBhdE9mZnNldCArIG9mZnNldDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fSxcblx0ZmxpcGZpdDoge1xuXHRcdGxlZnQ6IGZ1bmN0aW9uKCkge1xuXHRcdFx0JC51aS5wb3NpdGlvbi5mbGlwLmxlZnQuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0JC51aS5wb3NpdGlvbi5maXQubGVmdC5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0fSxcblx0XHR0b3A6IGZ1bmN0aW9uKCkge1xuXHRcdFx0JC51aS5wb3NpdGlvbi5mbGlwLnRvcC5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHQkLnVpLnBvc2l0aW9uLmZpdC50b3AuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdH1cblx0fVxufTtcblxufSApKCk7XG5cbnZhciBwb3NpdGlvbiA9ICQudWkucG9zaXRpb247XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgOmRhdGEgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IDpkYXRhIFNlbGVjdG9yXG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogU2VsZWN0cyBlbGVtZW50cyB3aGljaCBoYXZlIGRhdGEgc3RvcmVkIHVuZGVyIHRoZSBzcGVjaWZpZWQga2V5LlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2RhdGEtc2VsZWN0b3IvXG5cblxudmFyIGRhdGEgPSAkLmV4dGVuZCggJC5leHByWyBcIjpcIiBdLCB7XG5cdGRhdGE6ICQuZXhwci5jcmVhdGVQc2V1ZG8gP1xuXHRcdCQuZXhwci5jcmVhdGVQc2V1ZG8oIGZ1bmN0aW9uKCBkYXRhTmFtZSApIHtcblx0XHRcdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdFx0cmV0dXJuICEhJC5kYXRhKCBlbGVtLCBkYXRhTmFtZSApO1xuXHRcdFx0fTtcblx0XHR9ICkgOlxuXG5cdFx0Ly8gU3VwcG9ydDogalF1ZXJ5IDwxLjhcblx0XHRmdW5jdGlvbiggZWxlbSwgaSwgbWF0Y2ggKSB7XG5cdFx0XHRyZXR1cm4gISEkLmRhdGEoIGVsZW0sIG1hdGNoWyAzIF0gKTtcblx0XHR9XG59ICk7XG5cbi8qIVxuICogalF1ZXJ5IFVJIERpc2FibGUgU2VsZWN0aW9uIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBkaXNhYmxlU2VsZWN0aW9uXG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogRGlzYWJsZSBzZWxlY3Rpb24gb2YgdGV4dCBjb250ZW50IHdpdGhpbiB0aGUgc2V0IG9mIG1hdGNoZWQgZWxlbWVudHMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZGlzYWJsZVNlbGVjdGlvbi9cblxuLy8gVGhpcyBmaWxlIGlzIGRlcHJlY2F0ZWRcblxuXG52YXIgZGlzYWJsZVNlbGVjdGlvbiA9ICQuZm4uZXh0ZW5kKCB7XG5cdGRpc2FibGVTZWxlY3Rpb246ICggZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGV2ZW50VHlwZSA9IFwib25zZWxlY3RzdGFydFwiIGluIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIFwiZGl2XCIgKSA/XG5cdFx0XHRcInNlbGVjdHN0YXJ0XCIgOlxuXHRcdFx0XCJtb3VzZWRvd25cIjtcblxuXHRcdHJldHVybiBmdW5jdGlvbigpIHtcblx0XHRcdHJldHVybiB0aGlzLm9uKCBldmVudFR5cGUgKyBcIi51aS1kaXNhYmxlU2VsZWN0aW9uXCIsIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdH0gKTtcblx0XHR9O1xuXHR9ICkoKSxcblxuXHRlbmFibGVTZWxlY3Rpb246IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLm9mZiggXCIudWktZGlzYWJsZVNlbGVjdGlvblwiICk7XG5cdH1cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBFZmZlY3RzIENvcmVcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8ganNjczpkaXNhYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZGVzY3JpcHRpb246IEV4dGVuZHMgdGhlIGludGVybmFsIGpRdWVyeSBlZmZlY3RzLiBJbmNsdWRlcyBtb3JwaGluZyBhbmQgZWFzaW5nLiBSZXF1aXJlZCBieSBhbGwgb3RoZXIgZWZmZWN0cy5cbi8vIGpzY3M6ZW5hYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vY2F0ZWdvcnkvZWZmZWN0cy1jb3JlL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBkYXRhU3BhY2UgPSBcInVpLWVmZmVjdHMtXCIsXG5cdGRhdGFTcGFjZVN0eWxlID0gXCJ1aS1lZmZlY3RzLXN0eWxlXCIsXG5cdGRhdGFTcGFjZUFuaW1hdGVkID0gXCJ1aS1lZmZlY3RzLWFuaW1hdGVkXCIsXG5cblx0Ly8gQ3JlYXRlIGEgbG9jYWwgalF1ZXJ5IGJlY2F1c2UgalF1ZXJ5IENvbG9yIHJlbGllcyBvbiBpdCBhbmQgdGhlXG5cdC8vIGdsb2JhbCBtYXkgbm90IGV4aXN0IHdpdGggQU1EIGFuZCBhIGN1c3RvbSBidWlsZCAoIzEwMTk5KVxuXHRqUXVlcnkgPSAkO1xuXG4kLmVmZmVjdHMgPSB7XG5cdGVmZmVjdDoge31cbn07XG5cbi8qIVxuICogalF1ZXJ5IENvbG9yIEFuaW1hdGlvbnMgdjIuMS4yXG4gKiBodHRwczovL2dpdGh1Yi5jb20vanF1ZXJ5L2pxdWVyeS1jb2xvclxuICpcbiAqIENvcHlyaWdodCAyMDE0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqXG4gKiBEYXRlOiBXZWQgSmFuIDE2IDA4OjQ3OjA5IDIwMTMgLTA2MDBcbiAqL1xuKCBmdW5jdGlvbiggalF1ZXJ5LCB1bmRlZmluZWQgKSB7XG5cblx0dmFyIHN0ZXBIb29rcyA9IFwiYmFja2dyb3VuZENvbG9yIGJvcmRlckJvdHRvbUNvbG9yIGJvcmRlckxlZnRDb2xvciBib3JkZXJSaWdodENvbG9yIFwiICtcblx0XHRcImJvcmRlclRvcENvbG9yIGNvbG9yIGNvbHVtblJ1bGVDb2xvciBvdXRsaW5lQ29sb3IgdGV4dERlY29yYXRpb25Db2xvciB0ZXh0RW1waGFzaXNDb2xvclwiLFxuXG5cdC8vIFBsdXNlcXVhbHMgdGVzdCBmb3IgKz0gMTAwIC09IDEwMFxuXHRycGx1c2VxdWFscyA9IC9eKFtcXC0rXSk9XFxzKihcXGQrXFwuP1xcZCopLyxcblxuXHQvLyBBIHNldCBvZiBSRSdzIHRoYXQgY2FuIG1hdGNoIHN0cmluZ3MgYW5kIGdlbmVyYXRlIGNvbG9yIHR1cGxlcy5cblx0c3RyaW5nUGFyc2VycyA9IFsge1xuXHRcdFx0cmU6IC9yZ2JhP1xcKFxccyooXFxkezEsM30pXFxzKixcXHMqKFxcZHsxLDN9KVxccyosXFxzKihcXGR7MSwzfSlcXHMqKD86LFxccyooXFxkPyg/OlxcLlxcZCspPylcXHMqKT9cXCkvLFxuXHRcdFx0cGFyc2U6IGZ1bmN0aW9uKCBleGVjUmVzdWx0ICkge1xuXHRcdFx0XHRyZXR1cm4gW1xuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDEgXSxcblx0XHRcdFx0XHRleGVjUmVzdWx0WyAyIF0sXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgMyBdLFxuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDQgXVxuXHRcdFx0XHRdO1xuXHRcdFx0fVxuXHRcdH0sIHtcblx0XHRcdHJlOiAvcmdiYT9cXChcXHMqKFxcZCsoPzpcXC5cXGQrKT8pXFwlXFxzKixcXHMqKFxcZCsoPzpcXC5cXGQrKT8pXFwlXFxzKixcXHMqKFxcZCsoPzpcXC5cXGQrKT8pXFwlXFxzKig/OixcXHMqKFxcZD8oPzpcXC5cXGQrKT8pXFxzKik/XFwpLyxcblx0XHRcdHBhcnNlOiBmdW5jdGlvbiggZXhlY1Jlc3VsdCApIHtcblx0XHRcdFx0cmV0dXJuIFtcblx0XHRcdFx0XHRleGVjUmVzdWx0WyAxIF0gKiAyLjU1LFxuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDIgXSAqIDIuNTUsXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgMyBdICogMi41NSxcblx0XHRcdFx0XHRleGVjUmVzdWx0WyA0IF1cblx0XHRcdFx0XTtcblx0XHRcdH1cblx0XHR9LCB7XG5cblx0XHRcdC8vIFRoaXMgcmVnZXggaWdub3JlcyBBLUYgYmVjYXVzZSBpdCdzIGNvbXBhcmVkIGFnYWluc3QgYW4gYWxyZWFkeSBsb3dlcmNhc2VkIHN0cmluZ1xuXHRcdFx0cmU6IC8jKFthLWYwLTldezJ9KShbYS1mMC05XXsyfSkoW2EtZjAtOV17Mn0pLyxcblx0XHRcdHBhcnNlOiBmdW5jdGlvbiggZXhlY1Jlc3VsdCApIHtcblx0XHRcdFx0cmV0dXJuIFtcblx0XHRcdFx0XHRwYXJzZUludCggZXhlY1Jlc3VsdFsgMSBdLCAxNiApLFxuXHRcdFx0XHRcdHBhcnNlSW50KCBleGVjUmVzdWx0WyAyIF0sIDE2ICksXG5cdFx0XHRcdFx0cGFyc2VJbnQoIGV4ZWNSZXN1bHRbIDMgXSwgMTYgKVxuXHRcdFx0XHRdO1xuXHRcdFx0fVxuXHRcdH0sIHtcblxuXHRcdFx0Ly8gVGhpcyByZWdleCBpZ25vcmVzIEEtRiBiZWNhdXNlIGl0J3MgY29tcGFyZWQgYWdhaW5zdCBhbiBhbHJlYWR5IGxvd2VyY2FzZWQgc3RyaW5nXG5cdFx0XHRyZTogLyMoW2EtZjAtOV0pKFthLWYwLTldKShbYS1mMC05XSkvLFxuXHRcdFx0cGFyc2U6IGZ1bmN0aW9uKCBleGVjUmVzdWx0ICkge1xuXHRcdFx0XHRyZXR1cm4gW1xuXHRcdFx0XHRcdHBhcnNlSW50KCBleGVjUmVzdWx0WyAxIF0gKyBleGVjUmVzdWx0WyAxIF0sIDE2ICksXG5cdFx0XHRcdFx0cGFyc2VJbnQoIGV4ZWNSZXN1bHRbIDIgXSArIGV4ZWNSZXN1bHRbIDIgXSwgMTYgKSxcblx0XHRcdFx0XHRwYXJzZUludCggZXhlY1Jlc3VsdFsgMyBdICsgZXhlY1Jlc3VsdFsgMyBdLCAxNiApXG5cdFx0XHRcdF07XG5cdFx0XHR9XG5cdFx0fSwge1xuXHRcdFx0cmU6IC9oc2xhP1xcKFxccyooXFxkKyg/OlxcLlxcZCspPylcXHMqLFxccyooXFxkKyg/OlxcLlxcZCspPylcXCVcXHMqLFxccyooXFxkKyg/OlxcLlxcZCspPylcXCVcXHMqKD86LFxccyooXFxkPyg/OlxcLlxcZCspPylcXHMqKT9cXCkvLFxuXHRcdFx0c3BhY2U6IFwiaHNsYVwiLFxuXHRcdFx0cGFyc2U6IGZ1bmN0aW9uKCBleGVjUmVzdWx0ICkge1xuXHRcdFx0XHRyZXR1cm4gW1xuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDEgXSxcblx0XHRcdFx0XHRleGVjUmVzdWx0WyAyIF0gLyAxMDAsXG5cdFx0XHRcdFx0ZXhlY1Jlc3VsdFsgMyBdIC8gMTAwLFxuXHRcdFx0XHRcdGV4ZWNSZXN1bHRbIDQgXVxuXHRcdFx0XHRdO1xuXHRcdFx0fVxuXHRcdH0gXSxcblxuXHQvLyBKUXVlcnkuQ29sb3IoIClcblx0Y29sb3IgPSBqUXVlcnkuQ29sb3IgPSBmdW5jdGlvbiggY29sb3IsIGdyZWVuLCBibHVlLCBhbHBoYSApIHtcblx0XHRyZXR1cm4gbmV3IGpRdWVyeS5Db2xvci5mbi5wYXJzZSggY29sb3IsIGdyZWVuLCBibHVlLCBhbHBoYSApO1xuXHR9LFxuXHRzcGFjZXMgPSB7XG5cdFx0cmdiYToge1xuXHRcdFx0cHJvcHM6IHtcblx0XHRcdFx0cmVkOiB7XG5cdFx0XHRcdFx0aWR4OiAwLFxuXHRcdFx0XHRcdHR5cGU6IFwiYnl0ZVwiXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGdyZWVuOiB7XG5cdFx0XHRcdFx0aWR4OiAxLFxuXHRcdFx0XHRcdHR5cGU6IFwiYnl0ZVwiXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGJsdWU6IHtcblx0XHRcdFx0XHRpZHg6IDIsXG5cdFx0XHRcdFx0dHlwZTogXCJieXRlXCJcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0sXG5cblx0XHRoc2xhOiB7XG5cdFx0XHRwcm9wczoge1xuXHRcdFx0XHRodWU6IHtcblx0XHRcdFx0XHRpZHg6IDAsXG5cdFx0XHRcdFx0dHlwZTogXCJkZWdyZWVzXCJcblx0XHRcdFx0fSxcblx0XHRcdFx0c2F0dXJhdGlvbjoge1xuXHRcdFx0XHRcdGlkeDogMSxcblx0XHRcdFx0XHR0eXBlOiBcInBlcmNlbnRcIlxuXHRcdFx0XHR9LFxuXHRcdFx0XHRsaWdodG5lc3M6IHtcblx0XHRcdFx0XHRpZHg6IDIsXG5cdFx0XHRcdFx0dHlwZTogXCJwZXJjZW50XCJcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fSxcblx0cHJvcFR5cGVzID0ge1xuXHRcdFwiYnl0ZVwiOiB7XG5cdFx0XHRmbG9vcjogdHJ1ZSxcblx0XHRcdG1heDogMjU1XG5cdFx0fSxcblx0XHRcInBlcmNlbnRcIjoge1xuXHRcdFx0bWF4OiAxXG5cdFx0fSxcblx0XHRcImRlZ3JlZXNcIjoge1xuXHRcdFx0bW9kOiAzNjAsXG5cdFx0XHRmbG9vcjogdHJ1ZVxuXHRcdH1cblx0fSxcblx0c3VwcG9ydCA9IGNvbG9yLnN1cHBvcnQgPSB7fSxcblxuXHQvLyBFbGVtZW50IGZvciBzdXBwb3J0IHRlc3RzXG5cdHN1cHBvcnRFbGVtID0galF1ZXJ5KCBcIjxwPlwiIClbIDAgXSxcblxuXHQvLyBDb2xvcnMgPSBqUXVlcnkuQ29sb3IubmFtZXNcblx0Y29sb3JzLFxuXG5cdC8vIExvY2FsIGFsaWFzZXMgb2YgZnVuY3Rpb25zIGNhbGxlZCBvZnRlblxuXHRlYWNoID0galF1ZXJ5LmVhY2g7XG5cbi8vIERldGVybWluZSByZ2JhIHN1cHBvcnQgaW1tZWRpYXRlbHlcbnN1cHBvcnRFbGVtLnN0eWxlLmNzc1RleHQgPSBcImJhY2tncm91bmQtY29sb3I6cmdiYSgxLDEsMSwuNSlcIjtcbnN1cHBvcnQucmdiYSA9IHN1cHBvcnRFbGVtLnN0eWxlLmJhY2tncm91bmRDb2xvci5pbmRleE9mKCBcInJnYmFcIiApID4gLTE7XG5cbi8vIERlZmluZSBjYWNoZSBuYW1lIGFuZCBhbHBoYSBwcm9wZXJ0aWVzXG4vLyBmb3IgcmdiYSBhbmQgaHNsYSBzcGFjZXNcbmVhY2goIHNwYWNlcywgZnVuY3Rpb24oIHNwYWNlTmFtZSwgc3BhY2UgKSB7XG5cdHNwYWNlLmNhY2hlID0gXCJfXCIgKyBzcGFjZU5hbWU7XG5cdHNwYWNlLnByb3BzLmFscGhhID0ge1xuXHRcdGlkeDogMyxcblx0XHR0eXBlOiBcInBlcmNlbnRcIixcblx0XHRkZWY6IDFcblx0fTtcbn0gKTtcblxuZnVuY3Rpb24gY2xhbXAoIHZhbHVlLCBwcm9wLCBhbGxvd0VtcHR5ICkge1xuXHR2YXIgdHlwZSA9IHByb3BUeXBlc1sgcHJvcC50eXBlIF0gfHwge307XG5cblx0aWYgKCB2YWx1ZSA9PSBudWxsICkge1xuXHRcdHJldHVybiAoIGFsbG93RW1wdHkgfHwgIXByb3AuZGVmICkgPyBudWxsIDogcHJvcC5kZWY7XG5cdH1cblxuXHQvLyB+fiBpcyBhbiBzaG9ydCB3YXkgb2YgZG9pbmcgZmxvb3IgZm9yIHBvc2l0aXZlIG51bWJlcnNcblx0dmFsdWUgPSB0eXBlLmZsb29yID8gfn52YWx1ZSA6IHBhcnNlRmxvYXQoIHZhbHVlICk7XG5cblx0Ly8gSUUgd2lsbCBwYXNzIGluIGVtcHR5IHN0cmluZ3MgYXMgdmFsdWUgZm9yIGFscGhhLFxuXHQvLyB3aGljaCB3aWxsIGhpdCB0aGlzIGNhc2Vcblx0aWYgKCBpc05hTiggdmFsdWUgKSApIHtcblx0XHRyZXR1cm4gcHJvcC5kZWY7XG5cdH1cblxuXHRpZiAoIHR5cGUubW9kICkge1xuXG5cdFx0Ly8gV2UgYWRkIG1vZCBiZWZvcmUgbW9kZGluZyB0byBtYWtlIHN1cmUgdGhhdCBuZWdhdGl2ZXMgdmFsdWVzXG5cdFx0Ly8gZ2V0IGNvbnZlcnRlZCBwcm9wZXJseTogLTEwIC0+IDM1MFxuXHRcdHJldHVybiAoIHZhbHVlICsgdHlwZS5tb2QgKSAlIHR5cGUubW9kO1xuXHR9XG5cblx0Ly8gRm9yIG5vdyBhbGwgcHJvcGVydHkgdHlwZXMgd2l0aG91dCBtb2QgaGF2ZSBtaW4gYW5kIG1heFxuXHRyZXR1cm4gMCA+IHZhbHVlID8gMCA6IHR5cGUubWF4IDwgdmFsdWUgPyB0eXBlLm1heCA6IHZhbHVlO1xufVxuXG5mdW5jdGlvbiBzdHJpbmdQYXJzZSggc3RyaW5nICkge1xuXHR2YXIgaW5zdCA9IGNvbG9yKCksXG5cdFx0cmdiYSA9IGluc3QuX3JnYmEgPSBbXTtcblxuXHRzdHJpbmcgPSBzdHJpbmcudG9Mb3dlckNhc2UoKTtcblxuXHRlYWNoKCBzdHJpbmdQYXJzZXJzLCBmdW5jdGlvbiggaSwgcGFyc2VyICkge1xuXHRcdHZhciBwYXJzZWQsXG5cdFx0XHRtYXRjaCA9IHBhcnNlci5yZS5leGVjKCBzdHJpbmcgKSxcblx0XHRcdHZhbHVlcyA9IG1hdGNoICYmIHBhcnNlci5wYXJzZSggbWF0Y2ggKSxcblx0XHRcdHNwYWNlTmFtZSA9IHBhcnNlci5zcGFjZSB8fCBcInJnYmFcIjtcblxuXHRcdGlmICggdmFsdWVzICkge1xuXHRcdFx0cGFyc2VkID0gaW5zdFsgc3BhY2VOYW1lIF0oIHZhbHVlcyApO1xuXG5cdFx0XHQvLyBJZiB0aGlzIHdhcyBhbiByZ2JhIHBhcnNlIHRoZSBhc3NpZ25tZW50IG1pZ2h0IGhhcHBlbiB0d2ljZVxuXHRcdFx0Ly8gb2ggd2VsbC4uLi5cblx0XHRcdGluc3RbIHNwYWNlc1sgc3BhY2VOYW1lIF0uY2FjaGUgXSA9IHBhcnNlZFsgc3BhY2VzWyBzcGFjZU5hbWUgXS5jYWNoZSBdO1xuXHRcdFx0cmdiYSA9IGluc3QuX3JnYmEgPSBwYXJzZWQuX3JnYmE7XG5cblx0XHRcdC8vIEV4aXQgZWFjaCggc3RyaW5nUGFyc2VycyApIGhlcmUgYmVjYXVzZSB3ZSBtYXRjaGVkXG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHR9ICk7XG5cblx0Ly8gRm91bmQgYSBzdHJpbmdQYXJzZXIgdGhhdCBoYW5kbGVkIGl0XG5cdGlmICggcmdiYS5sZW5ndGggKSB7XG5cblx0XHQvLyBJZiB0aGlzIGNhbWUgZnJvbSBhIHBhcnNlZCBzdHJpbmcsIGZvcmNlIFwidHJhbnNwYXJlbnRcIiB3aGVuIGFscGhhIGlzIDBcblx0XHQvLyBjaHJvbWUsIChhbmQgbWF5YmUgb3RoZXJzKSByZXR1cm4gXCJ0cmFuc3BhcmVudFwiIGFzIHJnYmEoMCwwLDAsMClcblx0XHRpZiAoIHJnYmEuam9pbigpID09PSBcIjAsMCwwLDBcIiApIHtcblx0XHRcdGpRdWVyeS5leHRlbmQoIHJnYmEsIGNvbG9ycy50cmFuc3BhcmVudCApO1xuXHRcdH1cblx0XHRyZXR1cm4gaW5zdDtcblx0fVxuXG5cdC8vIE5hbWVkIGNvbG9yc1xuXHRyZXR1cm4gY29sb3JzWyBzdHJpbmcgXTtcbn1cblxuY29sb3IuZm4gPSBqUXVlcnkuZXh0ZW5kKCBjb2xvci5wcm90b3R5cGUsIHtcblx0cGFyc2U6IGZ1bmN0aW9uKCByZWQsIGdyZWVuLCBibHVlLCBhbHBoYSApIHtcblx0XHRpZiAoIHJlZCA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0dGhpcy5fcmdiYSA9IFsgbnVsbCwgbnVsbCwgbnVsbCwgbnVsbCBdO1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXHRcdGlmICggcmVkLmpxdWVyeSB8fCByZWQubm9kZVR5cGUgKSB7XG5cdFx0XHRyZWQgPSBqUXVlcnkoIHJlZCApLmNzcyggZ3JlZW4gKTtcblx0XHRcdGdyZWVuID0gdW5kZWZpbmVkO1xuXHRcdH1cblxuXHRcdHZhciBpbnN0ID0gdGhpcyxcblx0XHRcdHR5cGUgPSBqUXVlcnkudHlwZSggcmVkICksXG5cdFx0XHRyZ2JhID0gdGhpcy5fcmdiYSA9IFtdO1xuXG5cdFx0Ly8gTW9yZSB0aGFuIDEgYXJndW1lbnQgc3BlY2lmaWVkIC0gYXNzdW1lICggcmVkLCBncmVlbiwgYmx1ZSwgYWxwaGEgKVxuXHRcdGlmICggZ3JlZW4gIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHJlZCA9IFsgcmVkLCBncmVlbiwgYmx1ZSwgYWxwaGEgXTtcblx0XHRcdHR5cGUgPSBcImFycmF5XCI7XG5cdFx0fVxuXG5cdFx0aWYgKCB0eXBlID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0cmV0dXJuIHRoaXMucGFyc2UoIHN0cmluZ1BhcnNlKCByZWQgKSB8fCBjb2xvcnMuX2RlZmF1bHQgKTtcblx0XHR9XG5cblx0XHRpZiAoIHR5cGUgPT09IFwiYXJyYXlcIiApIHtcblx0XHRcdGVhY2goIHNwYWNlcy5yZ2JhLnByb3BzLCBmdW5jdGlvbigga2V5LCBwcm9wICkge1xuXHRcdFx0XHRyZ2JhWyBwcm9wLmlkeCBdID0gY2xhbXAoIHJlZFsgcHJvcC5pZHggXSwgcHJvcCApO1xuXHRcdFx0fSApO1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cdFx0fVxuXG5cdFx0aWYgKCB0eXBlID09PSBcIm9iamVjdFwiICkge1xuXHRcdFx0aWYgKCByZWQgaW5zdGFuY2VvZiBjb2xvciApIHtcblx0XHRcdFx0ZWFjaCggc3BhY2VzLCBmdW5jdGlvbiggc3BhY2VOYW1lLCBzcGFjZSApIHtcblx0XHRcdFx0XHRpZiAoIHJlZFsgc3BhY2UuY2FjaGUgXSApIHtcblx0XHRcdFx0XHRcdGluc3RbIHNwYWNlLmNhY2hlIF0gPSByZWRbIHNwYWNlLmNhY2hlIF0uc2xpY2UoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGVhY2goIHNwYWNlcywgZnVuY3Rpb24oIHNwYWNlTmFtZSwgc3BhY2UgKSB7XG5cdFx0XHRcdFx0dmFyIGNhY2hlID0gc3BhY2UuY2FjaGU7XG5cdFx0XHRcdFx0ZWFjaCggc3BhY2UucHJvcHMsIGZ1bmN0aW9uKCBrZXksIHByb3AgKSB7XG5cblx0XHRcdFx0XHRcdC8vIElmIHRoZSBjYWNoZSBkb2Vzbid0IGV4aXN0LCBhbmQgd2Uga25vdyBob3cgdG8gY29udmVydFxuXHRcdFx0XHRcdFx0aWYgKCAhaW5zdFsgY2FjaGUgXSAmJiBzcGFjZS50byApIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBJZiB0aGUgdmFsdWUgd2FzIG51bGwsIHdlIGRvbid0IG5lZWQgdG8gY29weSBpdFxuXHRcdFx0XHRcdFx0XHQvLyBpZiB0aGUga2V5IHdhcyBhbHBoYSwgd2UgZG9uJ3QgbmVlZCB0byBjb3B5IGl0IGVpdGhlclxuXHRcdFx0XHRcdFx0XHRpZiAoIGtleSA9PT0gXCJhbHBoYVwiIHx8IHJlZFsga2V5IF0gPT0gbnVsbCApIHtcblx0XHRcdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdFx0aW5zdFsgY2FjaGUgXSA9IHNwYWNlLnRvKCBpbnN0Ll9yZ2JhICk7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIFRoaXMgaXMgdGhlIG9ubHkgY2FzZSB3aGVyZSB3ZSBhbGxvdyBudWxscyBmb3IgQUxMIHByb3BlcnRpZXMuXG5cdFx0XHRcdFx0XHQvLyBjYWxsIGNsYW1wIHdpdGggYWx3YXlzQWxsb3dFbXB0eVxuXHRcdFx0XHRcdFx0aW5zdFsgY2FjaGUgXVsgcHJvcC5pZHggXSA9IGNsYW1wKCByZWRbIGtleSBdLCBwcm9wLCB0cnVlICk7XG5cdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdFx0Ly8gRXZlcnl0aGluZyBkZWZpbmVkIGJ1dCBhbHBoYT9cblx0XHRcdFx0XHRpZiAoIGluc3RbIGNhY2hlIF0gJiZcblx0XHRcdFx0XHRcdFx0alF1ZXJ5LmluQXJyYXkoIG51bGwsIGluc3RbIGNhY2hlIF0uc2xpY2UoIDAsIDMgKSApIDwgMCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gVXNlIHRoZSBkZWZhdWx0IG9mIDFcblx0XHRcdFx0XHRcdGluc3RbIGNhY2hlIF1bIDMgXSA9IDE7XG5cdFx0XHRcdFx0XHRpZiAoIHNwYWNlLmZyb20gKSB7XG5cdFx0XHRcdFx0XHRcdGluc3QuX3JnYmEgPSBzcGFjZS5mcm9tKCBpbnN0WyBjYWNoZSBdICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gdGhpcztcblx0XHR9XG5cdH0sXG5cdGlzOiBmdW5jdGlvbiggY29tcGFyZSApIHtcblx0XHR2YXIgaXMgPSBjb2xvciggY29tcGFyZSApLFxuXHRcdFx0c2FtZSA9IHRydWUsXG5cdFx0XHRpbnN0ID0gdGhpcztcblxuXHRcdGVhY2goIHNwYWNlcywgZnVuY3Rpb24oIF8sIHNwYWNlICkge1xuXHRcdFx0dmFyIGxvY2FsQ2FjaGUsXG5cdFx0XHRcdGlzQ2FjaGUgPSBpc1sgc3BhY2UuY2FjaGUgXTtcblx0XHRcdGlmICggaXNDYWNoZSApIHtcblx0XHRcdFx0bG9jYWxDYWNoZSA9IGluc3RbIHNwYWNlLmNhY2hlIF0gfHwgc3BhY2UudG8gJiYgc3BhY2UudG8oIGluc3QuX3JnYmEgKSB8fCBbXTtcblx0XHRcdFx0ZWFjaCggc3BhY2UucHJvcHMsIGZ1bmN0aW9uKCBfLCBwcm9wICkge1xuXHRcdFx0XHRcdGlmICggaXNDYWNoZVsgcHJvcC5pZHggXSAhPSBudWxsICkge1xuXHRcdFx0XHRcdFx0c2FtZSA9ICggaXNDYWNoZVsgcHJvcC5pZHggXSA9PT0gbG9jYWxDYWNoZVsgcHJvcC5pZHggXSApO1xuXHRcdFx0XHRcdFx0cmV0dXJuIHNhbWU7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gc2FtZTtcblx0XHR9ICk7XG5cdFx0cmV0dXJuIHNhbWU7XG5cdH0sXG5cdF9zcGFjZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHVzZWQgPSBbXSxcblx0XHRcdGluc3QgPSB0aGlzO1xuXHRcdGVhY2goIHNwYWNlcywgZnVuY3Rpb24oIHNwYWNlTmFtZSwgc3BhY2UgKSB7XG5cdFx0XHRpZiAoIGluc3RbIHNwYWNlLmNhY2hlIF0gKSB7XG5cdFx0XHRcdHVzZWQucHVzaCggc3BhY2VOYW1lICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdHJldHVybiB1c2VkLnBvcCgpO1xuXHR9LFxuXHR0cmFuc2l0aW9uOiBmdW5jdGlvbiggb3RoZXIsIGRpc3RhbmNlICkge1xuXHRcdHZhciBlbmQgPSBjb2xvciggb3RoZXIgKSxcblx0XHRcdHNwYWNlTmFtZSA9IGVuZC5fc3BhY2UoKSxcblx0XHRcdHNwYWNlID0gc3BhY2VzWyBzcGFjZU5hbWUgXSxcblx0XHRcdHN0YXJ0Q29sb3IgPSB0aGlzLmFscGhhKCkgPT09IDAgPyBjb2xvciggXCJ0cmFuc3BhcmVudFwiICkgOiB0aGlzLFxuXHRcdFx0c3RhcnQgPSBzdGFydENvbG9yWyBzcGFjZS5jYWNoZSBdIHx8IHNwYWNlLnRvKCBzdGFydENvbG9yLl9yZ2JhICksXG5cdFx0XHRyZXN1bHQgPSBzdGFydC5zbGljZSgpO1xuXG5cdFx0ZW5kID0gZW5kWyBzcGFjZS5jYWNoZSBdO1xuXHRcdGVhY2goIHNwYWNlLnByb3BzLCBmdW5jdGlvbigga2V5LCBwcm9wICkge1xuXHRcdFx0dmFyIGluZGV4ID0gcHJvcC5pZHgsXG5cdFx0XHRcdHN0YXJ0VmFsdWUgPSBzdGFydFsgaW5kZXggXSxcblx0XHRcdFx0ZW5kVmFsdWUgPSBlbmRbIGluZGV4IF0sXG5cdFx0XHRcdHR5cGUgPSBwcm9wVHlwZXNbIHByb3AudHlwZSBdIHx8IHt9O1xuXG5cdFx0XHQvLyBJZiBudWxsLCBkb24ndCBvdmVycmlkZSBzdGFydCB2YWx1ZVxuXHRcdFx0aWYgKCBlbmRWYWx1ZSA9PT0gbnVsbCApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBJZiBudWxsIC0gdXNlIGVuZFxuXHRcdFx0aWYgKCBzdGFydFZhbHVlID09PSBudWxsICkge1xuXHRcdFx0XHRyZXN1bHRbIGluZGV4IF0gPSBlbmRWYWx1ZTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGlmICggdHlwZS5tb2QgKSB7XG5cdFx0XHRcdFx0aWYgKCBlbmRWYWx1ZSAtIHN0YXJ0VmFsdWUgPiB0eXBlLm1vZCAvIDIgKSB7XG5cdFx0XHRcdFx0XHRzdGFydFZhbHVlICs9IHR5cGUubW9kO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoIHN0YXJ0VmFsdWUgLSBlbmRWYWx1ZSA+IHR5cGUubW9kIC8gMiApIHtcblx0XHRcdFx0XHRcdHN0YXJ0VmFsdWUgLT0gdHlwZS5tb2Q7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdHJlc3VsdFsgaW5kZXggXSA9IGNsYW1wKCAoIGVuZFZhbHVlIC0gc3RhcnRWYWx1ZSApICogZGlzdGFuY2UgKyBzdGFydFZhbHVlLCBwcm9wICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHRcdHJldHVybiB0aGlzWyBzcGFjZU5hbWUgXSggcmVzdWx0ICk7XG5cdH0sXG5cdGJsZW5kOiBmdW5jdGlvbiggb3BhcXVlICkge1xuXG5cdFx0Ly8gSWYgd2UgYXJlIGFscmVhZHkgb3BhcXVlIC0gcmV0dXJuIG91cnNlbGZcblx0XHRpZiAoIHRoaXMuX3JnYmFbIDMgXSA9PT0gMSApIHtcblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH1cblxuXHRcdHZhciByZ2IgPSB0aGlzLl9yZ2JhLnNsaWNlKCksXG5cdFx0XHRhID0gcmdiLnBvcCgpLFxuXHRcdFx0YmxlbmQgPSBjb2xvciggb3BhcXVlICkuX3JnYmE7XG5cblx0XHRyZXR1cm4gY29sb3IoIGpRdWVyeS5tYXAoIHJnYiwgZnVuY3Rpb24oIHYsIGkgKSB7XG5cdFx0XHRyZXR1cm4gKCAxIC0gYSApICogYmxlbmRbIGkgXSArIGEgKiB2O1xuXHRcdH0gKSApO1xuXHR9LFxuXHR0b1JnYmFTdHJpbmc6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBwcmVmaXggPSBcInJnYmEoXCIsXG5cdFx0XHRyZ2JhID0galF1ZXJ5Lm1hcCggdGhpcy5fcmdiYSwgZnVuY3Rpb24oIHYsIGkgKSB7XG5cdFx0XHRcdHJldHVybiB2ID09IG51bGwgPyAoIGkgPiAyID8gMSA6IDAgKSA6IHY7XG5cdFx0XHR9ICk7XG5cblx0XHRpZiAoIHJnYmFbIDMgXSA9PT0gMSApIHtcblx0XHRcdHJnYmEucG9wKCk7XG5cdFx0XHRwcmVmaXggPSBcInJnYihcIjtcblx0XHR9XG5cblx0XHRyZXR1cm4gcHJlZml4ICsgcmdiYS5qb2luKCkgKyBcIilcIjtcblx0fSxcblx0dG9Ic2xhU3RyaW5nOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgcHJlZml4ID0gXCJoc2xhKFwiLFxuXHRcdFx0aHNsYSA9IGpRdWVyeS5tYXAoIHRoaXMuaHNsYSgpLCBmdW5jdGlvbiggdiwgaSApIHtcblx0XHRcdFx0aWYgKCB2ID09IG51bGwgKSB7XG5cdFx0XHRcdFx0diA9IGkgPiAyID8gMSA6IDA7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBDYXRjaCAxIGFuZCAyXG5cdFx0XHRcdGlmICggaSAmJiBpIDwgMyApIHtcblx0XHRcdFx0XHR2ID0gTWF0aC5yb3VuZCggdiAqIDEwMCApICsgXCIlXCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIHY7XG5cdFx0XHR9ICk7XG5cblx0XHRpZiAoIGhzbGFbIDMgXSA9PT0gMSApIHtcblx0XHRcdGhzbGEucG9wKCk7XG5cdFx0XHRwcmVmaXggPSBcImhzbChcIjtcblx0XHR9XG5cdFx0cmV0dXJuIHByZWZpeCArIGhzbGEuam9pbigpICsgXCIpXCI7XG5cdH0sXG5cdHRvSGV4U3RyaW5nOiBmdW5jdGlvbiggaW5jbHVkZUFscGhhICkge1xuXHRcdHZhciByZ2JhID0gdGhpcy5fcmdiYS5zbGljZSgpLFxuXHRcdFx0YWxwaGEgPSByZ2JhLnBvcCgpO1xuXG5cdFx0aWYgKCBpbmNsdWRlQWxwaGEgKSB7XG5cdFx0XHRyZ2JhLnB1c2goIH5+KCBhbHBoYSAqIDI1NSApICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIFwiI1wiICsgalF1ZXJ5Lm1hcCggcmdiYSwgZnVuY3Rpb24oIHYgKSB7XG5cblx0XHRcdC8vIERlZmF1bHQgdG8gMCB3aGVuIG51bGxzIGV4aXN0XG5cdFx0XHR2ID0gKCB2IHx8IDAgKS50b1N0cmluZyggMTYgKTtcblx0XHRcdHJldHVybiB2Lmxlbmd0aCA9PT0gMSA/IFwiMFwiICsgdiA6IHY7XG5cdFx0fSApLmpvaW4oIFwiXCIgKTtcblx0fSxcblx0dG9TdHJpbmc6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLl9yZ2JhWyAzIF0gPT09IDAgPyBcInRyYW5zcGFyZW50XCIgOiB0aGlzLnRvUmdiYVN0cmluZygpO1xuXHR9XG59ICk7XG5jb2xvci5mbi5wYXJzZS5wcm90b3R5cGUgPSBjb2xvci5mbjtcblxuLy8gSHNsYSBjb252ZXJzaW9ucyBhZGFwdGVkIGZyb206XG4vLyBodHRwczovL2NvZGUuZ29vZ2xlLmNvbS9wL21hYXNoYWFjay9zb3VyY2UvYnJvd3NlL3BhY2thZ2VzL2dyYXBoaWNzL3RydW5rL3NyYy9ncmFwaGljcy9jb2xvcnMvSFVFMlJHQi5hcz9yPTUwMjFcblxuZnVuY3Rpb24gaHVlMnJnYiggcCwgcSwgaCApIHtcblx0aCA9ICggaCArIDEgKSAlIDE7XG5cdGlmICggaCAqIDYgPCAxICkge1xuXHRcdHJldHVybiBwICsgKCBxIC0gcCApICogaCAqIDY7XG5cdH1cblx0aWYgKCBoICogMiA8IDEgKSB7XG5cdFx0cmV0dXJuIHE7XG5cdH1cblx0aWYgKCBoICogMyA8IDIgKSB7XG5cdFx0cmV0dXJuIHAgKyAoIHEgLSBwICkgKiAoICggMiAvIDMgKSAtIGggKSAqIDY7XG5cdH1cblx0cmV0dXJuIHA7XG59XG5cbnNwYWNlcy5oc2xhLnRvID0gZnVuY3Rpb24oIHJnYmEgKSB7XG5cdGlmICggcmdiYVsgMCBdID09IG51bGwgfHwgcmdiYVsgMSBdID09IG51bGwgfHwgcmdiYVsgMiBdID09IG51bGwgKSB7XG5cdFx0cmV0dXJuIFsgbnVsbCwgbnVsbCwgbnVsbCwgcmdiYVsgMyBdIF07XG5cdH1cblx0dmFyIHIgPSByZ2JhWyAwIF0gLyAyNTUsXG5cdFx0ZyA9IHJnYmFbIDEgXSAvIDI1NSxcblx0XHRiID0gcmdiYVsgMiBdIC8gMjU1LFxuXHRcdGEgPSByZ2JhWyAzIF0sXG5cdFx0bWF4ID0gTWF0aC5tYXgoIHIsIGcsIGIgKSxcblx0XHRtaW4gPSBNYXRoLm1pbiggciwgZywgYiApLFxuXHRcdGRpZmYgPSBtYXggLSBtaW4sXG5cdFx0YWRkID0gbWF4ICsgbWluLFxuXHRcdGwgPSBhZGQgKiAwLjUsXG5cdFx0aCwgcztcblxuXHRpZiAoIG1pbiA9PT0gbWF4ICkge1xuXHRcdGggPSAwO1xuXHR9IGVsc2UgaWYgKCByID09PSBtYXggKSB7XG5cdFx0aCA9ICggNjAgKiAoIGcgLSBiICkgLyBkaWZmICkgKyAzNjA7XG5cdH0gZWxzZSBpZiAoIGcgPT09IG1heCApIHtcblx0XHRoID0gKCA2MCAqICggYiAtIHIgKSAvIGRpZmYgKSArIDEyMDtcblx0fSBlbHNlIHtcblx0XHRoID0gKCA2MCAqICggciAtIGcgKSAvIGRpZmYgKSArIDI0MDtcblx0fVxuXG5cdC8vIENocm9tYSAoZGlmZikgPT0gMCBtZWFucyBncmV5c2NhbGUgd2hpY2gsIGJ5IGRlZmluaXRpb24sIHNhdHVyYXRpb24gPSAwJVxuXHQvLyBvdGhlcndpc2UsIHNhdHVyYXRpb24gaXMgYmFzZWQgb24gdGhlIHJhdGlvIG9mIGNocm9tYSAoZGlmZikgdG8gbGlnaHRuZXNzIChhZGQpXG5cdGlmICggZGlmZiA9PT0gMCApIHtcblx0XHRzID0gMDtcblx0fSBlbHNlIGlmICggbCA8PSAwLjUgKSB7XG5cdFx0cyA9IGRpZmYgLyBhZGQ7XG5cdH0gZWxzZSB7XG5cdFx0cyA9IGRpZmYgLyAoIDIgLSBhZGQgKTtcblx0fVxuXHRyZXR1cm4gWyBNYXRoLnJvdW5kKCBoICkgJSAzNjAsIHMsIGwsIGEgPT0gbnVsbCA/IDEgOiBhIF07XG59O1xuXG5zcGFjZXMuaHNsYS5mcm9tID0gZnVuY3Rpb24oIGhzbGEgKSB7XG5cdGlmICggaHNsYVsgMCBdID09IG51bGwgfHwgaHNsYVsgMSBdID09IG51bGwgfHwgaHNsYVsgMiBdID09IG51bGwgKSB7XG5cdFx0cmV0dXJuIFsgbnVsbCwgbnVsbCwgbnVsbCwgaHNsYVsgMyBdIF07XG5cdH1cblx0dmFyIGggPSBoc2xhWyAwIF0gLyAzNjAsXG5cdFx0cyA9IGhzbGFbIDEgXSxcblx0XHRsID0gaHNsYVsgMiBdLFxuXHRcdGEgPSBoc2xhWyAzIF0sXG5cdFx0cSA9IGwgPD0gMC41ID8gbCAqICggMSArIHMgKSA6IGwgKyBzIC0gbCAqIHMsXG5cdFx0cCA9IDIgKiBsIC0gcTtcblxuXHRyZXR1cm4gW1xuXHRcdE1hdGgucm91bmQoIGh1ZTJyZ2IoIHAsIHEsIGggKyAoIDEgLyAzICkgKSAqIDI1NSApLFxuXHRcdE1hdGgucm91bmQoIGh1ZTJyZ2IoIHAsIHEsIGggKSAqIDI1NSApLFxuXHRcdE1hdGgucm91bmQoIGh1ZTJyZ2IoIHAsIHEsIGggLSAoIDEgLyAzICkgKSAqIDI1NSApLFxuXHRcdGFcblx0XTtcbn07XG5cbmVhY2goIHNwYWNlcywgZnVuY3Rpb24oIHNwYWNlTmFtZSwgc3BhY2UgKSB7XG5cdHZhciBwcm9wcyA9IHNwYWNlLnByb3BzLFxuXHRcdGNhY2hlID0gc3BhY2UuY2FjaGUsXG5cdFx0dG8gPSBzcGFjZS50byxcblx0XHRmcm9tID0gc3BhY2UuZnJvbTtcblxuXHQvLyBNYWtlcyByZ2JhKCkgYW5kIGhzbGEoKVxuXHRjb2xvci5mblsgc3BhY2VOYW1lIF0gPSBmdW5jdGlvbiggdmFsdWUgKSB7XG5cblx0XHQvLyBHZW5lcmF0ZSBhIGNhY2hlIGZvciB0aGlzIHNwYWNlIGlmIGl0IGRvZXNuJ3QgZXhpc3Rcblx0XHRpZiAoIHRvICYmICF0aGlzWyBjYWNoZSBdICkge1xuXHRcdFx0dGhpc1sgY2FjaGUgXSA9IHRvKCB0aGlzLl9yZ2JhICk7XG5cdFx0fVxuXHRcdGlmICggdmFsdWUgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHJldHVybiB0aGlzWyBjYWNoZSBdLnNsaWNlKCk7XG5cdFx0fVxuXG5cdFx0dmFyIHJldCxcblx0XHRcdHR5cGUgPSBqUXVlcnkudHlwZSggdmFsdWUgKSxcblx0XHRcdGFyciA9ICggdHlwZSA9PT0gXCJhcnJheVwiIHx8IHR5cGUgPT09IFwib2JqZWN0XCIgKSA/IHZhbHVlIDogYXJndW1lbnRzLFxuXHRcdFx0bG9jYWwgPSB0aGlzWyBjYWNoZSBdLnNsaWNlKCk7XG5cblx0XHRlYWNoKCBwcm9wcywgZnVuY3Rpb24oIGtleSwgcHJvcCApIHtcblx0XHRcdHZhciB2YWwgPSBhcnJbIHR5cGUgPT09IFwib2JqZWN0XCIgPyBrZXkgOiBwcm9wLmlkeCBdO1xuXHRcdFx0aWYgKCB2YWwgPT0gbnVsbCApIHtcblx0XHRcdFx0dmFsID0gbG9jYWxbIHByb3AuaWR4IF07XG5cdFx0XHR9XG5cdFx0XHRsb2NhbFsgcHJvcC5pZHggXSA9IGNsYW1wKCB2YWwsIHByb3AgKTtcblx0XHR9ICk7XG5cblx0XHRpZiAoIGZyb20gKSB7XG5cdFx0XHRyZXQgPSBjb2xvciggZnJvbSggbG9jYWwgKSApO1xuXHRcdFx0cmV0WyBjYWNoZSBdID0gbG9jYWw7XG5cdFx0XHRyZXR1cm4gcmV0O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gY29sb3IoIGxvY2FsICk7XG5cdFx0fVxuXHR9O1xuXG5cdC8vIE1ha2VzIHJlZCgpIGdyZWVuKCkgYmx1ZSgpIGFscGhhKCkgaHVlKCkgc2F0dXJhdGlvbigpIGxpZ2h0bmVzcygpXG5cdGVhY2goIHByb3BzLCBmdW5jdGlvbigga2V5LCBwcm9wICkge1xuXG5cdFx0Ly8gQWxwaGEgaXMgaW5jbHVkZWQgaW4gbW9yZSB0aGFuIG9uZSBzcGFjZVxuXHRcdGlmICggY29sb3IuZm5bIGtleSBdICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRjb2xvci5mblsga2V5IF0gPSBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0XHR2YXIgdnR5cGUgPSBqUXVlcnkudHlwZSggdmFsdWUgKSxcblx0XHRcdFx0Zm4gPSAoIGtleSA9PT0gXCJhbHBoYVwiID8gKCB0aGlzLl9oc2xhID8gXCJoc2xhXCIgOiBcInJnYmFcIiApIDogc3BhY2VOYW1lICksXG5cdFx0XHRcdGxvY2FsID0gdGhpc1sgZm4gXSgpLFxuXHRcdFx0XHRjdXIgPSBsb2NhbFsgcHJvcC5pZHggXSxcblx0XHRcdFx0bWF0Y2g7XG5cblx0XHRcdGlmICggdnR5cGUgPT09IFwidW5kZWZpbmVkXCIgKSB7XG5cdFx0XHRcdHJldHVybiBjdXI7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggdnR5cGUgPT09IFwiZnVuY3Rpb25cIiApIHtcblx0XHRcdFx0dmFsdWUgPSB2YWx1ZS5jYWxsKCB0aGlzLCBjdXIgKTtcblx0XHRcdFx0dnR5cGUgPSBqUXVlcnkudHlwZSggdmFsdWUgKTtcblx0XHRcdH1cblx0XHRcdGlmICggdmFsdWUgPT0gbnVsbCAmJiBwcm9wLmVtcHR5ICkge1xuXHRcdFx0XHRyZXR1cm4gdGhpcztcblx0XHRcdH1cblx0XHRcdGlmICggdnR5cGUgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdG1hdGNoID0gcnBsdXNlcXVhbHMuZXhlYyggdmFsdWUgKTtcblx0XHRcdFx0aWYgKCBtYXRjaCApIHtcblx0XHRcdFx0XHR2YWx1ZSA9IGN1ciArIHBhcnNlRmxvYXQoIG1hdGNoWyAyIF0gKSAqICggbWF0Y2hbIDEgXSA9PT0gXCIrXCIgPyAxIDogLTEgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0bG9jYWxbIHByb3AuaWR4IF0gPSB2YWx1ZTtcblx0XHRcdHJldHVybiB0aGlzWyBmbiBdKCBsb2NhbCApO1xuXHRcdH07XG5cdH0gKTtcbn0gKTtcblxuLy8gQWRkIGNzc0hvb2sgYW5kIC5meC5zdGVwIGZ1bmN0aW9uIGZvciBlYWNoIG5hbWVkIGhvb2suXG4vLyBhY2NlcHQgYSBzcGFjZSBzZXBhcmF0ZWQgc3RyaW5nIG9mIHByb3BlcnRpZXNcbmNvbG9yLmhvb2sgPSBmdW5jdGlvbiggaG9vayApIHtcblx0dmFyIGhvb2tzID0gaG9vay5zcGxpdCggXCIgXCIgKTtcblx0ZWFjaCggaG9va3MsIGZ1bmN0aW9uKCBpLCBob29rICkge1xuXHRcdGpRdWVyeS5jc3NIb29rc1sgaG9vayBdID0ge1xuXHRcdFx0c2V0OiBmdW5jdGlvbiggZWxlbSwgdmFsdWUgKSB7XG5cdFx0XHRcdHZhciBwYXJzZWQsIGN1ckVsZW0sXG5cdFx0XHRcdFx0YmFja2dyb3VuZENvbG9yID0gXCJcIjtcblxuXHRcdFx0XHRpZiAoIHZhbHVlICE9PSBcInRyYW5zcGFyZW50XCIgJiYgKCBqUXVlcnkudHlwZSggdmFsdWUgKSAhPT0gXCJzdHJpbmdcIiB8fFxuXHRcdFx0XHRcdFx0KCBwYXJzZWQgPSBzdHJpbmdQYXJzZSggdmFsdWUgKSApICkgKSB7XG5cdFx0XHRcdFx0dmFsdWUgPSBjb2xvciggcGFyc2VkIHx8IHZhbHVlICk7XG5cdFx0XHRcdFx0aWYgKCAhc3VwcG9ydC5yZ2JhICYmIHZhbHVlLl9yZ2JhWyAzIF0gIT09IDEgKSB7XG5cdFx0XHRcdFx0XHRjdXJFbGVtID0gaG9vayA9PT0gXCJiYWNrZ3JvdW5kQ29sb3JcIiA/IGVsZW0ucGFyZW50Tm9kZSA6IGVsZW07XG5cdFx0XHRcdFx0XHR3aGlsZSAoXG5cdFx0XHRcdFx0XHRcdCggYmFja2dyb3VuZENvbG9yID09PSBcIlwiIHx8IGJhY2tncm91bmRDb2xvciA9PT0gXCJ0cmFuc3BhcmVudFwiICkgJiZcblx0XHRcdFx0XHRcdFx0Y3VyRWxlbSAmJiBjdXJFbGVtLnN0eWxlXG5cdFx0XHRcdFx0XHQpIHtcblx0XHRcdFx0XHRcdFx0dHJ5IHtcblx0XHRcdFx0XHRcdFx0XHRiYWNrZ3JvdW5kQ29sb3IgPSBqUXVlcnkuY3NzKCBjdXJFbGVtLCBcImJhY2tncm91bmRDb2xvclwiICk7XG5cdFx0XHRcdFx0XHRcdFx0Y3VyRWxlbSA9IGN1ckVsZW0ucGFyZW50Tm9kZTtcblx0XHRcdFx0XHRcdFx0fSBjYXRjaCAoIGUgKSB7XG5cdFx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0dmFsdWUgPSB2YWx1ZS5ibGVuZCggYmFja2dyb3VuZENvbG9yICYmIGJhY2tncm91bmRDb2xvciAhPT0gXCJ0cmFuc3BhcmVudFwiID9cblx0XHRcdFx0XHRcdFx0YmFja2dyb3VuZENvbG9yIDpcblx0XHRcdFx0XHRcdFx0XCJfZGVmYXVsdFwiICk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dmFsdWUgPSB2YWx1ZS50b1JnYmFTdHJpbmcoKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdGVsZW0uc3R5bGVbIGhvb2sgXSA9IHZhbHVlO1xuXHRcdFx0XHR9IGNhdGNoICggZSApIHtcblxuXHRcdFx0XHRcdC8vIFdyYXBwZWQgdG8gcHJldmVudCBJRSBmcm9tIHRocm93aW5nIGVycm9ycyBvbiBcImludmFsaWRcIiB2YWx1ZXMgbGlrZVxuXHRcdFx0XHRcdC8vICdhdXRvJyBvciAnaW5oZXJpdCdcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH07XG5cdFx0alF1ZXJ5LmZ4LnN0ZXBbIGhvb2sgXSA9IGZ1bmN0aW9uKCBmeCApIHtcblx0XHRcdGlmICggIWZ4LmNvbG9ySW5pdCApIHtcblx0XHRcdFx0Znguc3RhcnQgPSBjb2xvciggZnguZWxlbSwgaG9vayApO1xuXHRcdFx0XHRmeC5lbmQgPSBjb2xvciggZnguZW5kICk7XG5cdFx0XHRcdGZ4LmNvbG9ySW5pdCA9IHRydWU7XG5cdFx0XHR9XG5cdFx0XHRqUXVlcnkuY3NzSG9va3NbIGhvb2sgXS5zZXQoIGZ4LmVsZW0sIGZ4LnN0YXJ0LnRyYW5zaXRpb24oIGZ4LmVuZCwgZngucG9zICkgKTtcblx0XHR9O1xuXHR9ICk7XG5cbn07XG5cbmNvbG9yLmhvb2soIHN0ZXBIb29rcyApO1xuXG5qUXVlcnkuY3NzSG9va3MuYm9yZGVyQ29sb3IgPSB7XG5cdGV4cGFuZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHZhciBleHBhbmRlZCA9IHt9O1xuXG5cdFx0ZWFjaCggWyBcIlRvcFwiLCBcIlJpZ2h0XCIsIFwiQm90dG9tXCIsIFwiTGVmdFwiIF0sIGZ1bmN0aW9uKCBpLCBwYXJ0ICkge1xuXHRcdFx0ZXhwYW5kZWRbIFwiYm9yZGVyXCIgKyBwYXJ0ICsgXCJDb2xvclwiIF0gPSB2YWx1ZTtcblx0XHR9ICk7XG5cdFx0cmV0dXJuIGV4cGFuZGVkO1xuXHR9XG59O1xuXG4vLyBCYXNpYyBjb2xvciBuYW1lcyBvbmx5LlxuLy8gVXNhZ2Ugb2YgYW55IG9mIHRoZSBvdGhlciBjb2xvciBuYW1lcyByZXF1aXJlcyBhZGRpbmcgeW91cnNlbGYgb3IgaW5jbHVkaW5nXG4vLyBqcXVlcnkuY29sb3Iuc3ZnLW5hbWVzLmpzLlxuY29sb3JzID0galF1ZXJ5LkNvbG9yLm5hbWVzID0ge1xuXG5cdC8vIDQuMS4gQmFzaWMgY29sb3Iga2V5d29yZHNcblx0YXF1YTogXCIjMDBmZmZmXCIsXG5cdGJsYWNrOiBcIiMwMDAwMDBcIixcblx0Ymx1ZTogXCIjMDAwMGZmXCIsXG5cdGZ1Y2hzaWE6IFwiI2ZmMDBmZlwiLFxuXHRncmF5OiBcIiM4MDgwODBcIixcblx0Z3JlZW46IFwiIzAwODAwMFwiLFxuXHRsaW1lOiBcIiMwMGZmMDBcIixcblx0bWFyb29uOiBcIiM4MDAwMDBcIixcblx0bmF2eTogXCIjMDAwMDgwXCIsXG5cdG9saXZlOiBcIiM4MDgwMDBcIixcblx0cHVycGxlOiBcIiM4MDAwODBcIixcblx0cmVkOiBcIiNmZjAwMDBcIixcblx0c2lsdmVyOiBcIiNjMGMwYzBcIixcblx0dGVhbDogXCIjMDA4MDgwXCIsXG5cdHdoaXRlOiBcIiNmZmZmZmZcIixcblx0eWVsbG93OiBcIiNmZmZmMDBcIixcblxuXHQvLyA0LjIuMy4gXCJ0cmFuc3BhcmVudFwiIGNvbG9yIGtleXdvcmRcblx0dHJhbnNwYXJlbnQ6IFsgbnVsbCwgbnVsbCwgbnVsbCwgMCBdLFxuXG5cdF9kZWZhdWx0OiBcIiNmZmZmZmZcIlxufTtcblxufSApKCBqUXVlcnkgKTtcblxuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogQ0xBU1MgQU5JTUFUSU9OUyAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuKCBmdW5jdGlvbigpIHtcblxudmFyIGNsYXNzQW5pbWF0aW9uQWN0aW9ucyA9IFsgXCJhZGRcIiwgXCJyZW1vdmVcIiwgXCJ0b2dnbGVcIiBdLFxuXHRzaG9ydGhhbmRTdHlsZXMgPSB7XG5cdFx0Ym9yZGVyOiAxLFxuXHRcdGJvcmRlckJvdHRvbTogMSxcblx0XHRib3JkZXJDb2xvcjogMSxcblx0XHRib3JkZXJMZWZ0OiAxLFxuXHRcdGJvcmRlclJpZ2h0OiAxLFxuXHRcdGJvcmRlclRvcDogMSxcblx0XHRib3JkZXJXaWR0aDogMSxcblx0XHRtYXJnaW46IDEsXG5cdFx0cGFkZGluZzogMVxuXHR9O1xuXG4kLmVhY2goXG5cdFsgXCJib3JkZXJMZWZ0U3R5bGVcIiwgXCJib3JkZXJSaWdodFN0eWxlXCIsIFwiYm9yZGVyQm90dG9tU3R5bGVcIiwgXCJib3JkZXJUb3BTdHlsZVwiIF0sXG5cdGZ1bmN0aW9uKCBfLCBwcm9wICkge1xuXHRcdCQuZnguc3RlcFsgcHJvcCBdID0gZnVuY3Rpb24oIGZ4ICkge1xuXHRcdFx0aWYgKCBmeC5lbmQgIT09IFwibm9uZVwiICYmICFmeC5zZXRBdHRyIHx8IGZ4LnBvcyA9PT0gMSAmJiAhZnguc2V0QXR0ciApIHtcblx0XHRcdFx0alF1ZXJ5LnN0eWxlKCBmeC5lbGVtLCBwcm9wLCBmeC5lbmQgKTtcblx0XHRcdFx0Znguc2V0QXR0ciA9IHRydWU7XG5cdFx0XHR9XG5cdFx0fTtcblx0fVxuKTtcblxuZnVuY3Rpb24gZ2V0RWxlbWVudFN0eWxlcyggZWxlbSApIHtcblx0dmFyIGtleSwgbGVuLFxuXHRcdHN0eWxlID0gZWxlbS5vd25lckRvY3VtZW50LmRlZmF1bHRWaWV3ID9cblx0XHRcdGVsZW0ub3duZXJEb2N1bWVudC5kZWZhdWx0Vmlldy5nZXRDb21wdXRlZFN0eWxlKCBlbGVtLCBudWxsICkgOlxuXHRcdFx0ZWxlbS5jdXJyZW50U3R5bGUsXG5cdFx0c3R5bGVzID0ge307XG5cblx0aWYgKCBzdHlsZSAmJiBzdHlsZS5sZW5ndGggJiYgc3R5bGVbIDAgXSAmJiBzdHlsZVsgc3R5bGVbIDAgXSBdICkge1xuXHRcdGxlbiA9IHN0eWxlLmxlbmd0aDtcblx0XHR3aGlsZSAoIGxlbi0tICkge1xuXHRcdFx0a2V5ID0gc3R5bGVbIGxlbiBdO1xuXHRcdFx0aWYgKCB0eXBlb2Ygc3R5bGVbIGtleSBdID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0XHRzdHlsZXNbICQuY2FtZWxDYXNlKCBrZXkgKSBdID0gc3R5bGVbIGtleSBdO1xuXHRcdFx0fVxuXHRcdH1cblxuXHQvLyBTdXBwb3J0OiBPcGVyYSwgSUUgPDlcblx0fSBlbHNlIHtcblx0XHRmb3IgKCBrZXkgaW4gc3R5bGUgKSB7XG5cdFx0XHRpZiAoIHR5cGVvZiBzdHlsZVsga2V5IF0gPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdHN0eWxlc1sga2V5IF0gPSBzdHlsZVsga2V5IF07XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIHN0eWxlcztcbn1cblxuZnVuY3Rpb24gc3R5bGVEaWZmZXJlbmNlKCBvbGRTdHlsZSwgbmV3U3R5bGUgKSB7XG5cdHZhciBkaWZmID0ge30sXG5cdFx0bmFtZSwgdmFsdWU7XG5cblx0Zm9yICggbmFtZSBpbiBuZXdTdHlsZSApIHtcblx0XHR2YWx1ZSA9IG5ld1N0eWxlWyBuYW1lIF07XG5cdFx0aWYgKCBvbGRTdHlsZVsgbmFtZSBdICE9PSB2YWx1ZSApIHtcblx0XHRcdGlmICggIXNob3J0aGFuZFN0eWxlc1sgbmFtZSBdICkge1xuXHRcdFx0XHRpZiAoICQuZnguc3RlcFsgbmFtZSBdIHx8ICFpc05hTiggcGFyc2VGbG9hdCggdmFsdWUgKSApICkge1xuXHRcdFx0XHRcdGRpZmZbIG5hbWUgXSA9IHZhbHVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cblx0cmV0dXJuIGRpZmY7XG59XG5cbi8vIFN1cHBvcnQ6IGpRdWVyeSA8MS44XG5pZiAoICEkLmZuLmFkZEJhY2sgKSB7XG5cdCQuZm4uYWRkQmFjayA9IGZ1bmN0aW9uKCBzZWxlY3RvciApIHtcblx0XHRyZXR1cm4gdGhpcy5hZGQoIHNlbGVjdG9yID09IG51bGwgP1xuXHRcdFx0dGhpcy5wcmV2T2JqZWN0IDogdGhpcy5wcmV2T2JqZWN0LmZpbHRlciggc2VsZWN0b3IgKVxuXHRcdCk7XG5cdH07XG59XG5cbiQuZWZmZWN0cy5hbmltYXRlQ2xhc3MgPSBmdW5jdGlvbiggdmFsdWUsIGR1cmF0aW9uLCBlYXNpbmcsIGNhbGxiYWNrICkge1xuXHR2YXIgbyA9ICQuc3BlZWQoIGR1cmF0aW9uLCBlYXNpbmcsIGNhbGxiYWNrICk7XG5cblx0cmV0dXJuIHRoaXMucXVldWUoIGZ1bmN0aW9uKCkge1xuXHRcdHZhciBhbmltYXRlZCA9ICQoIHRoaXMgKSxcblx0XHRcdGJhc2VDbGFzcyA9IGFuaW1hdGVkLmF0dHIoIFwiY2xhc3NcIiApIHx8IFwiXCIsXG5cdFx0XHRhcHBseUNsYXNzQ2hhbmdlLFxuXHRcdFx0YWxsQW5pbWF0aW9ucyA9IG8uY2hpbGRyZW4gPyBhbmltYXRlZC5maW5kKCBcIipcIiApLmFkZEJhY2soKSA6IGFuaW1hdGVkO1xuXG5cdFx0Ly8gTWFwIHRoZSBhbmltYXRlZCBvYmplY3RzIHRvIHN0b3JlIHRoZSBvcmlnaW5hbCBzdHlsZXMuXG5cdFx0YWxsQW5pbWF0aW9ucyA9IGFsbEFuaW1hdGlvbnMubWFwKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBlbCA9ICQoIHRoaXMgKTtcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdGVsOiBlbCxcblx0XHRcdFx0c3RhcnQ6IGdldEVsZW1lbnRTdHlsZXMoIHRoaXMgKVxuXHRcdFx0fTtcblx0XHR9ICk7XG5cblx0XHQvLyBBcHBseSBjbGFzcyBjaGFuZ2Vcblx0XHRhcHBseUNsYXNzQ2hhbmdlID0gZnVuY3Rpb24oKSB7XG5cdFx0XHQkLmVhY2goIGNsYXNzQW5pbWF0aW9uQWN0aW9ucywgZnVuY3Rpb24oIGksIGFjdGlvbiApIHtcblx0XHRcdFx0aWYgKCB2YWx1ZVsgYWN0aW9uIF0gKSB7XG5cdFx0XHRcdFx0YW5pbWF0ZWRbIGFjdGlvbiArIFwiQ2xhc3NcIiBdKCB2YWx1ZVsgYWN0aW9uIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH07XG5cdFx0YXBwbHlDbGFzc0NoYW5nZSgpO1xuXG5cdFx0Ly8gTWFwIGFsbCBhbmltYXRlZCBvYmplY3RzIGFnYWluIC0gY2FsY3VsYXRlIG5ldyBzdHlsZXMgYW5kIGRpZmZcblx0XHRhbGxBbmltYXRpb25zID0gYWxsQW5pbWF0aW9ucy5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5lbmQgPSBnZXRFbGVtZW50U3R5bGVzKCB0aGlzLmVsWyAwIF0gKTtcblx0XHRcdHRoaXMuZGlmZiA9IHN0eWxlRGlmZmVyZW5jZSggdGhpcy5zdGFydCwgdGhpcy5lbmQgKTtcblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH0gKTtcblxuXHRcdC8vIEFwcGx5IG9yaWdpbmFsIGNsYXNzXG5cdFx0YW5pbWF0ZWQuYXR0ciggXCJjbGFzc1wiLCBiYXNlQ2xhc3MgKTtcblxuXHRcdC8vIE1hcCBhbGwgYW5pbWF0ZWQgb2JqZWN0cyBhZ2FpbiAtIHRoaXMgdGltZSBjb2xsZWN0aW5nIGEgcHJvbWlzZVxuXHRcdGFsbEFuaW1hdGlvbnMgPSBhbGxBbmltYXRpb25zLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgc3R5bGVJbmZvID0gdGhpcyxcblx0XHRcdFx0ZGZkID0gJC5EZWZlcnJlZCgpLFxuXHRcdFx0XHRvcHRzID0gJC5leHRlbmQoIHt9LCBvLCB7XG5cdFx0XHRcdFx0cXVldWU6IGZhbHNlLFxuXHRcdFx0XHRcdGNvbXBsZXRlOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdGRmZC5yZXNvbHZlKCBzdHlsZUluZm8gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblxuXHRcdFx0dGhpcy5lbC5hbmltYXRlKCB0aGlzLmRpZmYsIG9wdHMgKTtcblx0XHRcdHJldHVybiBkZmQucHJvbWlzZSgpO1xuXHRcdH0gKTtcblxuXHRcdC8vIE9uY2UgYWxsIGFuaW1hdGlvbnMgaGF2ZSBjb21wbGV0ZWQ6XG5cdFx0JC53aGVuLmFwcGx5KCAkLCBhbGxBbmltYXRpb25zLmdldCgpICkuZG9uZSggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIFNldCB0aGUgZmluYWwgY2xhc3Ncblx0XHRcdGFwcGx5Q2xhc3NDaGFuZ2UoKTtcblxuXHRcdFx0Ly8gRm9yIGVhY2ggYW5pbWF0ZWQgZWxlbWVudCxcblx0XHRcdC8vIGNsZWFyIGFsbCBjc3MgcHJvcGVydGllcyB0aGF0IHdlcmUgYW5pbWF0ZWRcblx0XHRcdCQuZWFjaCggYXJndW1lbnRzLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGVsID0gdGhpcy5lbDtcblx0XHRcdFx0JC5lYWNoKCB0aGlzLmRpZmYsIGZ1bmN0aW9uKCBrZXkgKSB7XG5cdFx0XHRcdFx0ZWwuY3NzKCBrZXksIFwiXCIgKTtcblx0XHRcdFx0fSApO1xuXHRcdFx0fSApO1xuXG5cdFx0XHQvLyBUaGlzIGlzIGd1YXJudGVlZCB0byBiZSB0aGVyZSBpZiB5b3UgdXNlIGpRdWVyeS5zcGVlZCgpXG5cdFx0XHQvLyBpdCBhbHNvIGhhbmRsZXMgZGVxdWV1aW5nIHRoZSBuZXh0IGFuaW0uLi5cblx0XHRcdG8uY29tcGxldGUuY2FsbCggYW5pbWF0ZWRbIDAgXSApO1xuXHRcdH0gKTtcblx0fSApO1xufTtcblxuJC5mbi5leHRlbmQoIHtcblx0YWRkQ2xhc3M6ICggZnVuY3Rpb24oIG9yaWcgKSB7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCBjbGFzc05hbWVzLCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIHtcblx0XHRcdHJldHVybiBzcGVlZCA/XG5cdFx0XHRcdCQuZWZmZWN0cy5hbmltYXRlQ2xhc3MuY2FsbCggdGhpcyxcblx0XHRcdFx0XHR7IGFkZDogY2xhc3NOYW1lcyB9LCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIDpcblx0XHRcdFx0b3JpZy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0fTtcblx0fSApKCAkLmZuLmFkZENsYXNzICksXG5cblx0cmVtb3ZlQ2xhc3M6ICggZnVuY3Rpb24oIG9yaWcgKSB7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCBjbGFzc05hbWVzLCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIHtcblx0XHRcdHJldHVybiBhcmd1bWVudHMubGVuZ3RoID4gMSA/XG5cdFx0XHRcdCQuZWZmZWN0cy5hbmltYXRlQ2xhc3MuY2FsbCggdGhpcyxcblx0XHRcdFx0XHR7IHJlbW92ZTogY2xhc3NOYW1lcyB9LCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIDpcblx0XHRcdFx0b3JpZy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0fTtcblx0fSApKCAkLmZuLnJlbW92ZUNsYXNzICksXG5cblx0dG9nZ2xlQ2xhc3M6ICggZnVuY3Rpb24oIG9yaWcgKSB7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCBjbGFzc05hbWVzLCBmb3JjZSwgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKSB7XG5cdFx0XHRpZiAoIHR5cGVvZiBmb3JjZSA9PT0gXCJib29sZWFuXCIgfHwgZm9yY2UgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0aWYgKCAhc3BlZWQgKSB7XG5cblx0XHRcdFx0XHQvLyBXaXRob3V0IHNwZWVkIHBhcmFtZXRlclxuXHRcdFx0XHRcdHJldHVybiBvcmlnLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRyZXR1cm4gJC5lZmZlY3RzLmFuaW1hdGVDbGFzcy5jYWxsKCB0aGlzLFxuXHRcdFx0XHRcdFx0KCBmb3JjZSA/IHsgYWRkOiBjbGFzc05hbWVzIH0gOiB7IHJlbW92ZTogY2xhc3NOYW1lcyB9ICksXG5cdFx0XHRcdFx0XHRzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIFdpdGhvdXQgZm9yY2UgcGFyYW1ldGVyXG5cdFx0XHRcdHJldHVybiAkLmVmZmVjdHMuYW5pbWF0ZUNsYXNzLmNhbGwoIHRoaXMsXG5cdFx0XHRcdFx0eyB0b2dnbGU6IGNsYXNzTmFtZXMgfSwgZm9yY2UsIHNwZWVkLCBlYXNpbmcgKTtcblx0XHRcdH1cblx0XHR9O1xuXHR9ICkoICQuZm4udG9nZ2xlQ2xhc3MgKSxcblxuXHRzd2l0Y2hDbGFzczogZnVuY3Rpb24oIHJlbW92ZSwgYWRkLCBzcGVlZCwgZWFzaW5nLCBjYWxsYmFjayApIHtcblx0XHRyZXR1cm4gJC5lZmZlY3RzLmFuaW1hdGVDbGFzcy5jYWxsKCB0aGlzLCB7XG5cdFx0XHRhZGQ6IGFkZCxcblx0XHRcdHJlbW92ZTogcmVtb3ZlXG5cdFx0fSwgc3BlZWQsIGVhc2luZywgY2FsbGJhY2sgKTtcblx0fVxufSApO1xuXG59ICkoKTtcblxuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiBFRkZFQ1RTICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG4oIGZ1bmN0aW9uKCkge1xuXG5pZiAoICQuZXhwciAmJiAkLmV4cHIuZmlsdGVycyAmJiAkLmV4cHIuZmlsdGVycy5hbmltYXRlZCApIHtcblx0JC5leHByLmZpbHRlcnMuYW5pbWF0ZWQgPSAoIGZ1bmN0aW9uKCBvcmlnICkge1xuXHRcdHJldHVybiBmdW5jdGlvbiggZWxlbSApIHtcblx0XHRcdHJldHVybiAhISQoIGVsZW0gKS5kYXRhKCBkYXRhU3BhY2VBbmltYXRlZCApIHx8IG9yaWcoIGVsZW0gKTtcblx0XHR9O1xuXHR9ICkoICQuZXhwci5maWx0ZXJzLmFuaW1hdGVkICk7XG59XG5cbmlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICkge1xuXHQkLmV4dGVuZCggJC5lZmZlY3RzLCB7XG5cblx0XHQvLyBTYXZlcyBhIHNldCBvZiBwcm9wZXJ0aWVzIGluIGEgZGF0YSBzdG9yYWdlXG5cdFx0c2F2ZTogZnVuY3Rpb24oIGVsZW1lbnQsIHNldCApIHtcblx0XHRcdHZhciBpID0gMCwgbGVuZ3RoID0gc2V0Lmxlbmd0aDtcblx0XHRcdGZvciAoIDsgaSA8IGxlbmd0aDsgaSsrICkge1xuXHRcdFx0XHRpZiAoIHNldFsgaSBdICE9PSBudWxsICkge1xuXHRcdFx0XHRcdGVsZW1lbnQuZGF0YSggZGF0YVNwYWNlICsgc2V0WyBpIF0sIGVsZW1lbnRbIDAgXS5zdHlsZVsgc2V0WyBpIF0gXSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSxcblxuXHRcdC8vIFJlc3RvcmVzIGEgc2V0IG9mIHByZXZpb3VzbHkgc2F2ZWQgcHJvcGVydGllcyBmcm9tIGEgZGF0YSBzdG9yYWdlXG5cdFx0cmVzdG9yZTogZnVuY3Rpb24oIGVsZW1lbnQsIHNldCApIHtcblx0XHRcdHZhciB2YWwsIGkgPSAwLCBsZW5ndGggPSBzZXQubGVuZ3RoO1xuXHRcdFx0Zm9yICggOyBpIDwgbGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRcdGlmICggc2V0WyBpIF0gIT09IG51bGwgKSB7XG5cdFx0XHRcdFx0dmFsID0gZWxlbWVudC5kYXRhKCBkYXRhU3BhY2UgKyBzZXRbIGkgXSApO1xuXHRcdFx0XHRcdGVsZW1lbnQuY3NzKCBzZXRbIGkgXSwgdmFsICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9LFxuXG5cdFx0c2V0TW9kZTogZnVuY3Rpb24oIGVsLCBtb2RlICkge1xuXHRcdFx0aWYgKCBtb2RlID09PSBcInRvZ2dsZVwiICkge1xuXHRcdFx0XHRtb2RlID0gZWwuaXMoIFwiOmhpZGRlblwiICkgPyBcInNob3dcIiA6IFwiaGlkZVwiO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIG1vZGU7XG5cdFx0fSxcblxuXHRcdC8vIFdyYXBzIHRoZSBlbGVtZW50IGFyb3VuZCBhIHdyYXBwZXIgdGhhdCBjb3BpZXMgcG9zaXRpb24gcHJvcGVydGllc1xuXHRcdGNyZWF0ZVdyYXBwZXI6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXG5cdFx0XHQvLyBJZiB0aGUgZWxlbWVudCBpcyBhbHJlYWR5IHdyYXBwZWQsIHJldHVybiBpdFxuXHRcdFx0aWYgKCBlbGVtZW50LnBhcmVudCgpLmlzKCBcIi51aS1lZmZlY3RzLXdyYXBwZXJcIiApICkge1xuXHRcdFx0XHRyZXR1cm4gZWxlbWVudC5wYXJlbnQoKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gV3JhcCB0aGUgZWxlbWVudFxuXHRcdFx0dmFyIHByb3BzID0ge1xuXHRcdFx0XHRcdHdpZHRoOiBlbGVtZW50Lm91dGVyV2lkdGgoIHRydWUgKSxcblx0XHRcdFx0XHRoZWlnaHQ6IGVsZW1lbnQub3V0ZXJIZWlnaHQoIHRydWUgKSxcblx0XHRcdFx0XHRcImZsb2F0XCI6IGVsZW1lbnQuY3NzKCBcImZsb2F0XCIgKVxuXHRcdFx0XHR9LFxuXHRcdFx0XHR3cmFwcGVyID0gJCggXCI8ZGl2PjwvZGl2PlwiIClcblx0XHRcdFx0XHQuYWRkQ2xhc3MoIFwidWktZWZmZWN0cy13cmFwcGVyXCIgKVxuXHRcdFx0XHRcdC5jc3MoIHtcblx0XHRcdFx0XHRcdGZvbnRTaXplOiBcIjEwMCVcIixcblx0XHRcdFx0XHRcdGJhY2tncm91bmQ6IFwidHJhbnNwYXJlbnRcIixcblx0XHRcdFx0XHRcdGJvcmRlcjogXCJub25lXCIsXG5cdFx0XHRcdFx0XHRtYXJnaW46IDAsXG5cdFx0XHRcdFx0XHRwYWRkaW5nOiAwXG5cdFx0XHRcdFx0fSApLFxuXG5cdFx0XHRcdC8vIFN0b3JlIHRoZSBzaXplIGluIGNhc2Ugd2lkdGgvaGVpZ2h0IGFyZSBkZWZpbmVkIGluICUgLSBGaXhlcyAjNTI0NVxuXHRcdFx0XHRzaXplID0ge1xuXHRcdFx0XHRcdHdpZHRoOiBlbGVtZW50LndpZHRoKCksXG5cdFx0XHRcdFx0aGVpZ2h0OiBlbGVtZW50LmhlaWdodCgpXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGFjdGl2ZSA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG5cblx0XHRcdC8vIFN1cHBvcnQ6IEZpcmVmb3hcblx0XHRcdC8vIEZpcmVmb3ggaW5jb3JyZWN0bHkgZXhwb3NlcyBhbm9ueW1vdXMgY29udGVudFxuXHRcdFx0Ly8gaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9NTYxNjY0XG5cdFx0XHR0cnkge1xuXHRcdFx0XHRhY3RpdmUuaWQ7XG5cdFx0XHR9IGNhdGNoICggZSApIHtcblx0XHRcdFx0YWN0aXZlID0gZG9jdW1lbnQuYm9keTtcblx0XHRcdH1cblxuXHRcdFx0ZWxlbWVudC53cmFwKCB3cmFwcGVyICk7XG5cblx0XHRcdC8vIEZpeGVzICM3NTk1IC0gRWxlbWVudHMgbG9zZSBmb2N1cyB3aGVuIHdyYXBwZWQuXG5cdFx0XHRpZiAoIGVsZW1lbnRbIDAgXSA9PT0gYWN0aXZlIHx8ICQuY29udGFpbnMoIGVsZW1lbnRbIDAgXSwgYWN0aXZlICkgKSB7XG5cdFx0XHRcdCQoIGFjdGl2ZSApLnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBIb3RmaXggZm9yIGpRdWVyeSAxLjQgc2luY2Ugc29tZSBjaGFuZ2UgaW4gd3JhcCgpIHNlZW1zIHRvIGFjdHVhbGx5XG5cdFx0XHQvLyBsb3NlIHRoZSByZWZlcmVuY2UgdG8gdGhlIHdyYXBwZWQgZWxlbWVudFxuXHRcdFx0d3JhcHBlciA9IGVsZW1lbnQucGFyZW50KCk7XG5cblx0XHRcdC8vIFRyYW5zZmVyIHBvc2l0aW9uaW5nIHByb3BlcnRpZXMgdG8gdGhlIHdyYXBwZXJcblx0XHRcdGlmICggZWxlbWVudC5jc3MoIFwicG9zaXRpb25cIiApID09PSBcInN0YXRpY1wiICkge1xuXHRcdFx0XHR3cmFwcGVyLmNzcyggeyBwb3NpdGlvbjogXCJyZWxhdGl2ZVwiIH0gKTtcblx0XHRcdFx0ZWxlbWVudC5jc3MoIHsgcG9zaXRpb246IFwicmVsYXRpdmVcIiB9ICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQkLmV4dGVuZCggcHJvcHMsIHtcblx0XHRcdFx0XHRwb3NpdGlvbjogZWxlbWVudC5jc3MoIFwicG9zaXRpb25cIiApLFxuXHRcdFx0XHRcdHpJbmRleDogZWxlbWVudC5jc3MoIFwiei1pbmRleFwiIClcblx0XHRcdFx0fSApO1xuXHRcdFx0XHQkLmVhY2goIFsgXCJ0b3BcIiwgXCJsZWZ0XCIsIFwiYm90dG9tXCIsIFwicmlnaHRcIiBdLCBmdW5jdGlvbiggaSwgcG9zICkge1xuXHRcdFx0XHRcdHByb3BzWyBwb3MgXSA9IGVsZW1lbnQuY3NzKCBwb3MgKTtcblx0XHRcdFx0XHRpZiAoIGlzTmFOKCBwYXJzZUludCggcHJvcHNbIHBvcyBdLCAxMCApICkgKSB7XG5cdFx0XHRcdFx0XHRwcm9wc1sgcG9zIF0gPSBcImF1dG9cIjtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdFx0ZWxlbWVudC5jc3MoIHtcblx0XHRcdFx0XHRwb3NpdGlvbjogXCJyZWxhdGl2ZVwiLFxuXHRcdFx0XHRcdHRvcDogMCxcblx0XHRcdFx0XHRsZWZ0OiAwLFxuXHRcdFx0XHRcdHJpZ2h0OiBcImF1dG9cIixcblx0XHRcdFx0XHRib3R0b206IFwiYXV0b1wiXG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHRcdGVsZW1lbnQuY3NzKCBzaXplICk7XG5cblx0XHRcdHJldHVybiB3cmFwcGVyLmNzcyggcHJvcHMgKS5zaG93KCk7XG5cdFx0fSxcblxuXHRcdHJlbW92ZVdyYXBwZXI6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdFx0dmFyIGFjdGl2ZSA9IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG5cblx0XHRcdGlmICggZWxlbWVudC5wYXJlbnQoKS5pcyggXCIudWktZWZmZWN0cy13cmFwcGVyXCIgKSApIHtcblx0XHRcdFx0ZWxlbWVudC5wYXJlbnQoKS5yZXBsYWNlV2l0aCggZWxlbWVudCApO1xuXG5cdFx0XHRcdC8vIEZpeGVzICM3NTk1IC0gRWxlbWVudHMgbG9zZSBmb2N1cyB3aGVuIHdyYXBwZWQuXG5cdFx0XHRcdGlmICggZWxlbWVudFsgMCBdID09PSBhY3RpdmUgfHwgJC5jb250YWlucyggZWxlbWVudFsgMCBdLCBhY3RpdmUgKSApIHtcblx0XHRcdFx0XHQkKCBhY3RpdmUgKS50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZWxlbWVudDtcblx0XHR9XG5cdH0gKTtcbn1cblxuJC5leHRlbmQoICQuZWZmZWN0cywge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXG5cdGRlZmluZTogZnVuY3Rpb24oIG5hbWUsIG1vZGUsIGVmZmVjdCApIHtcblx0XHRpZiAoICFlZmZlY3QgKSB7XG5cdFx0XHRlZmZlY3QgPSBtb2RlO1xuXHRcdFx0bW9kZSA9IFwiZWZmZWN0XCI7XG5cdFx0fVxuXG5cdFx0JC5lZmZlY3RzLmVmZmVjdFsgbmFtZSBdID0gZWZmZWN0O1xuXHRcdCQuZWZmZWN0cy5lZmZlY3RbIG5hbWUgXS5tb2RlID0gbW9kZTtcblxuXHRcdHJldHVybiBlZmZlY3Q7XG5cdH0sXG5cblx0c2NhbGVkRGltZW5zaW9uczogZnVuY3Rpb24oIGVsZW1lbnQsIHBlcmNlbnQsIGRpcmVjdGlvbiApIHtcblx0XHRpZiAoIHBlcmNlbnQgPT09IDAgKSB7XG5cdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRoZWlnaHQ6IDAsXG5cdFx0XHRcdHdpZHRoOiAwLFxuXHRcdFx0XHRvdXRlckhlaWdodDogMCxcblx0XHRcdFx0b3V0ZXJXaWR0aDogMFxuXHRcdFx0fTtcblx0XHR9XG5cblx0XHR2YXIgeCA9IGRpcmVjdGlvbiAhPT0gXCJob3Jpem9udGFsXCIgPyAoICggcGVyY2VudCB8fCAxMDAgKSAvIDEwMCApIDogMSxcblx0XHRcdHkgPSBkaXJlY3Rpb24gIT09IFwidmVydGljYWxcIiA/ICggKCBwZXJjZW50IHx8IDEwMCApIC8gMTAwICkgOiAxO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdGhlaWdodDogZWxlbWVudC5oZWlnaHQoKSAqIHksXG5cdFx0XHR3aWR0aDogZWxlbWVudC53aWR0aCgpICogeCxcblx0XHRcdG91dGVySGVpZ2h0OiBlbGVtZW50Lm91dGVySGVpZ2h0KCkgKiB5LFxuXHRcdFx0b3V0ZXJXaWR0aDogZWxlbWVudC5vdXRlcldpZHRoKCkgKiB4XG5cdFx0fTtcblxuXHR9LFxuXG5cdGNsaXBUb0JveDogZnVuY3Rpb24oIGFuaW1hdGlvbiApIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0d2lkdGg6IGFuaW1hdGlvbi5jbGlwLnJpZ2h0IC0gYW5pbWF0aW9uLmNsaXAubGVmdCxcblx0XHRcdGhlaWdodDogYW5pbWF0aW9uLmNsaXAuYm90dG9tIC0gYW5pbWF0aW9uLmNsaXAudG9wLFxuXHRcdFx0bGVmdDogYW5pbWF0aW9uLmNsaXAubGVmdCxcblx0XHRcdHRvcDogYW5pbWF0aW9uLmNsaXAudG9wXG5cdFx0fTtcblx0fSxcblxuXHQvLyBJbmplY3RzIHJlY2VudGx5IHF1ZXVlZCBmdW5jdGlvbnMgdG8gYmUgZmlyc3QgaW4gbGluZSAoYWZ0ZXIgXCJpbnByb2dyZXNzXCIpXG5cdHVuc2hpZnQ6IGZ1bmN0aW9uKCBlbGVtZW50LCBxdWV1ZUxlbmd0aCwgY291bnQgKSB7XG5cdFx0dmFyIHF1ZXVlID0gZWxlbWVudC5xdWV1ZSgpO1xuXG5cdFx0aWYgKCBxdWV1ZUxlbmd0aCA+IDEgKSB7XG5cdFx0XHRxdWV1ZS5zcGxpY2UuYXBwbHkoIHF1ZXVlLFxuXHRcdFx0XHRbIDEsIDAgXS5jb25jYXQoIHF1ZXVlLnNwbGljZSggcXVldWVMZW5ndGgsIGNvdW50ICkgKSApO1xuXHRcdH1cblx0XHRlbGVtZW50LmRlcXVldWUoKTtcblx0fSxcblxuXHRzYXZlU3R5bGU6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdGVsZW1lbnQuZGF0YSggZGF0YVNwYWNlU3R5bGUsIGVsZW1lbnRbIDAgXS5zdHlsZS5jc3NUZXh0ICk7XG5cdH0sXG5cblx0cmVzdG9yZVN0eWxlOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHRlbGVtZW50WyAwIF0uc3R5bGUuY3NzVGV4dCA9IGVsZW1lbnQuZGF0YSggZGF0YVNwYWNlU3R5bGUgKSB8fCBcIlwiO1xuXHRcdGVsZW1lbnQucmVtb3ZlRGF0YSggZGF0YVNwYWNlU3R5bGUgKTtcblx0fSxcblxuXHRtb2RlOiBmdW5jdGlvbiggZWxlbWVudCwgbW9kZSApIHtcblx0XHR2YXIgaGlkZGVuID0gZWxlbWVudC5pcyggXCI6aGlkZGVuXCIgKTtcblxuXHRcdGlmICggbW9kZSA9PT0gXCJ0b2dnbGVcIiApIHtcblx0XHRcdG1vZGUgPSBoaWRkZW4gPyBcInNob3dcIiA6IFwiaGlkZVwiO1xuXHRcdH1cblx0XHRpZiAoIGhpZGRlbiA/IG1vZGUgPT09IFwiaGlkZVwiIDogbW9kZSA9PT0gXCJzaG93XCIgKSB7XG5cdFx0XHRtb2RlID0gXCJub25lXCI7XG5cdFx0fVxuXHRcdHJldHVybiBtb2RlO1xuXHR9LFxuXG5cdC8vIFRyYW5zbGF0ZXMgYSBbdG9wLGxlZnRdIGFycmF5IGludG8gYSBiYXNlbGluZSB2YWx1ZVxuXHRnZXRCYXNlbGluZTogZnVuY3Rpb24oIG9yaWdpbiwgb3JpZ2luYWwgKSB7XG5cdFx0dmFyIHksIHg7XG5cblx0XHRzd2l0Y2ggKCBvcmlnaW5bIDAgXSApIHtcblx0XHRjYXNlIFwidG9wXCI6XG5cdFx0XHR5ID0gMDtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgXCJtaWRkbGVcIjpcblx0XHRcdHkgPSAwLjU7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIFwiYm90dG9tXCI6XG5cdFx0XHR5ID0gMTtcblx0XHRcdGJyZWFrO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHR5ID0gb3JpZ2luWyAwIF0gLyBvcmlnaW5hbC5oZWlnaHQ7XG5cdFx0fVxuXG5cdFx0c3dpdGNoICggb3JpZ2luWyAxIF0gKSB7XG5cdFx0Y2FzZSBcImxlZnRcIjpcblx0XHRcdHggPSAwO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSBcImNlbnRlclwiOlxuXHRcdFx0eCA9IDAuNTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgXCJyaWdodFwiOlxuXHRcdFx0eCA9IDE7XG5cdFx0XHRicmVhaztcblx0XHRkZWZhdWx0OlxuXHRcdFx0eCA9IG9yaWdpblsgMSBdIC8gb3JpZ2luYWwud2lkdGg7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHg6IHgsXG5cdFx0XHR5OiB5XG5cdFx0fTtcblx0fSxcblxuXHQvLyBDcmVhdGVzIGEgcGxhY2Vob2xkZXIgZWxlbWVudCBzbyB0aGF0IHRoZSBvcmlnaW5hbCBlbGVtZW50IGNhbiBiZSBtYWRlIGFic29sdXRlXG5cdGNyZWF0ZVBsYWNlaG9sZGVyOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHR2YXIgcGxhY2Vob2xkZXIsXG5cdFx0XHRjc3NQb3NpdGlvbiA9IGVsZW1lbnQuY3NzKCBcInBvc2l0aW9uXCIgKSxcblx0XHRcdHBvc2l0aW9uID0gZWxlbWVudC5wb3NpdGlvbigpO1xuXG5cdFx0Ly8gTG9jayBpbiBtYXJnaW5zIGZpcnN0IHRvIGFjY291bnQgZm9yIGZvcm0gZWxlbWVudHMsIHdoaWNoXG5cdFx0Ly8gd2lsbCBjaGFuZ2UgbWFyZ2luIGlmIHlvdSBleHBsaWNpdGx5IHNldCBoZWlnaHRcblx0XHQvLyBzZWU6IGh0dHA6Ly9qc2ZpZGRsZS5uZXQvSlpTTXQvMy8gaHR0cHM6Ly9idWdzLndlYmtpdC5vcmcvc2hvd19idWcuY2dpP2lkPTEwNzM4MFxuXHRcdC8vIFN1cHBvcnQ6IFNhZmFyaVxuXHRcdGVsZW1lbnQuY3NzKCB7XG5cdFx0XHRtYXJnaW5Ub3A6IGVsZW1lbnQuY3NzKCBcIm1hcmdpblRvcFwiICksXG5cdFx0XHRtYXJnaW5Cb3R0b206IGVsZW1lbnQuY3NzKCBcIm1hcmdpbkJvdHRvbVwiICksXG5cdFx0XHRtYXJnaW5MZWZ0OiBlbGVtZW50LmNzcyggXCJtYXJnaW5MZWZ0XCIgKSxcblx0XHRcdG1hcmdpblJpZ2h0OiBlbGVtZW50LmNzcyggXCJtYXJnaW5SaWdodFwiIClcblx0XHR9IClcblx0XHQub3V0ZXJXaWR0aCggZWxlbWVudC5vdXRlcldpZHRoKCkgKVxuXHRcdC5vdXRlckhlaWdodCggZWxlbWVudC5vdXRlckhlaWdodCgpICk7XG5cblx0XHRpZiAoIC9eKHN0YXRpY3xyZWxhdGl2ZSkvLnRlc3QoIGNzc1Bvc2l0aW9uICkgKSB7XG5cdFx0XHRjc3NQb3NpdGlvbiA9IFwiYWJzb2x1dGVcIjtcblxuXHRcdFx0cGxhY2Vob2xkZXIgPSAkKCBcIjxcIiArIGVsZW1lbnRbIDAgXS5ub2RlTmFtZSArIFwiPlwiICkuaW5zZXJ0QWZ0ZXIoIGVsZW1lbnQgKS5jc3MoIHtcblxuXHRcdFx0XHQvLyBDb252ZXJ0IGlubGluZSB0byBpbmxpbmUgYmxvY2sgdG8gYWNjb3VudCBmb3IgaW5saW5lIGVsZW1lbnRzXG5cdFx0XHRcdC8vIHRoYXQgdHVybiB0byBpbmxpbmUgYmxvY2sgYmFzZWQgb24gY29udGVudCAobGlrZSBpbWcpXG5cdFx0XHRcdGRpc3BsYXk6IC9eKGlubGluZXxydWJ5KS8udGVzdCggZWxlbWVudC5jc3MoIFwiZGlzcGxheVwiICkgKSA/XG5cdFx0XHRcdFx0XCJpbmxpbmUtYmxvY2tcIiA6XG5cdFx0XHRcdFx0XCJibG9ja1wiLFxuXHRcdFx0XHR2aXNpYmlsaXR5OiBcImhpZGRlblwiLFxuXG5cdFx0XHRcdC8vIE1hcmdpbnMgbmVlZCB0byBiZSBzZXQgdG8gYWNjb3VudCBmb3IgbWFyZ2luIGNvbGxhcHNlXG5cdFx0XHRcdG1hcmdpblRvcDogZWxlbWVudC5jc3MoIFwibWFyZ2luVG9wXCIgKSxcblx0XHRcdFx0bWFyZ2luQm90dG9tOiBlbGVtZW50LmNzcyggXCJtYXJnaW5Cb3R0b21cIiApLFxuXHRcdFx0XHRtYXJnaW5MZWZ0OiBlbGVtZW50LmNzcyggXCJtYXJnaW5MZWZ0XCIgKSxcblx0XHRcdFx0bWFyZ2luUmlnaHQ6IGVsZW1lbnQuY3NzKCBcIm1hcmdpblJpZ2h0XCIgKSxcblx0XHRcdFx0XCJmbG9hdFwiOiBlbGVtZW50LmNzcyggXCJmbG9hdFwiIClcblx0XHRcdH0gKVxuXHRcdFx0Lm91dGVyV2lkdGgoIGVsZW1lbnQub3V0ZXJXaWR0aCgpIClcblx0XHRcdC5vdXRlckhlaWdodCggZWxlbWVudC5vdXRlckhlaWdodCgpIClcblx0XHRcdC5hZGRDbGFzcyggXCJ1aS1lZmZlY3RzLXBsYWNlaG9sZGVyXCIgKTtcblxuXHRcdFx0ZWxlbWVudC5kYXRhKCBkYXRhU3BhY2UgKyBcInBsYWNlaG9sZGVyXCIsIHBsYWNlaG9sZGVyICk7XG5cdFx0fVxuXG5cdFx0ZWxlbWVudC5jc3MoIHtcblx0XHRcdHBvc2l0aW9uOiBjc3NQb3NpdGlvbixcblx0XHRcdGxlZnQ6IHBvc2l0aW9uLmxlZnQsXG5cdFx0XHR0b3A6IHBvc2l0aW9uLnRvcFxuXHRcdH0gKTtcblxuXHRcdHJldHVybiBwbGFjZWhvbGRlcjtcblx0fSxcblxuXHRyZW1vdmVQbGFjZWhvbGRlcjogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0dmFyIGRhdGFLZXkgPSBkYXRhU3BhY2UgKyBcInBsYWNlaG9sZGVyXCIsXG5cdFx0XHRcdHBsYWNlaG9sZGVyID0gZWxlbWVudC5kYXRhKCBkYXRhS2V5ICk7XG5cblx0XHRpZiAoIHBsYWNlaG9sZGVyICkge1xuXHRcdFx0cGxhY2Vob2xkZXIucmVtb3ZlKCk7XG5cdFx0XHRlbGVtZW50LnJlbW92ZURhdGEoIGRhdGFLZXkgKTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gUmVtb3ZlcyBhIHBsYWNlaG9sZGVyIGlmIGl0IGV4aXN0cyBhbmQgcmVzdG9yZXNcblx0Ly8gcHJvcGVydGllcyB0aGF0IHdlcmUgbW9kaWZpZWQgZHVyaW5nIHBsYWNlaG9sZGVyIGNyZWF0aW9uXG5cdGNsZWFuVXA6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdCQuZWZmZWN0cy5yZXN0b3JlU3R5bGUoIGVsZW1lbnQgKTtcblx0XHQkLmVmZmVjdHMucmVtb3ZlUGxhY2Vob2xkZXIoIGVsZW1lbnQgKTtcblx0fSxcblxuXHRzZXRUcmFuc2l0aW9uOiBmdW5jdGlvbiggZWxlbWVudCwgbGlzdCwgZmFjdG9yLCB2YWx1ZSApIHtcblx0XHR2YWx1ZSA9IHZhbHVlIHx8IHt9O1xuXHRcdCQuZWFjaCggbGlzdCwgZnVuY3Rpb24oIGksIHggKSB7XG5cdFx0XHR2YXIgdW5pdCA9IGVsZW1lbnQuY3NzVW5pdCggeCApO1xuXHRcdFx0aWYgKCB1bml0WyAwIF0gPiAwICkge1xuXHRcdFx0XHR2YWx1ZVsgeCBdID0gdW5pdFsgMCBdICogZmFjdG9yICsgdW5pdFsgMSBdO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XHRyZXR1cm4gdmFsdWU7XG5cdH1cbn0gKTtcblxuLy8gUmV0dXJuIGFuIGVmZmVjdCBvcHRpb25zIG9iamVjdCBmb3IgdGhlIGdpdmVuIHBhcmFtZXRlcnM6XG5mdW5jdGlvbiBfbm9ybWFsaXplQXJndW1lbnRzKCBlZmZlY3QsIG9wdGlvbnMsIHNwZWVkLCBjYWxsYmFjayApIHtcblxuXHQvLyBBbGxvdyBwYXNzaW5nIGFsbCBvcHRpb25zIGFzIHRoZSBmaXJzdCBwYXJhbWV0ZXJcblx0aWYgKCAkLmlzUGxhaW5PYmplY3QoIGVmZmVjdCApICkge1xuXHRcdG9wdGlvbnMgPSBlZmZlY3Q7XG5cdFx0ZWZmZWN0ID0gZWZmZWN0LmVmZmVjdDtcblx0fVxuXG5cdC8vIENvbnZlcnQgdG8gYW4gb2JqZWN0XG5cdGVmZmVjdCA9IHsgZWZmZWN0OiBlZmZlY3QgfTtcblxuXHQvLyBDYXRjaCAoZWZmZWN0LCBudWxsLCAuLi4pXG5cdGlmICggb3B0aW9ucyA9PSBudWxsICkge1xuXHRcdG9wdGlvbnMgPSB7fTtcblx0fVxuXG5cdC8vIENhdGNoIChlZmZlY3QsIGNhbGxiYWNrKVxuXHRpZiAoICQuaXNGdW5jdGlvbiggb3B0aW9ucyApICkge1xuXHRcdGNhbGxiYWNrID0gb3B0aW9ucztcblx0XHRzcGVlZCA9IG51bGw7XG5cdFx0b3B0aW9ucyA9IHt9O1xuXHR9XG5cblx0Ly8gQ2F0Y2ggKGVmZmVjdCwgc3BlZWQsID8pXG5cdGlmICggdHlwZW9mIG9wdGlvbnMgPT09IFwibnVtYmVyXCIgfHwgJC5meC5zcGVlZHNbIG9wdGlvbnMgXSApIHtcblx0XHRjYWxsYmFjayA9IHNwZWVkO1xuXHRcdHNwZWVkID0gb3B0aW9ucztcblx0XHRvcHRpb25zID0ge307XG5cdH1cblxuXHQvLyBDYXRjaCAoZWZmZWN0LCBvcHRpb25zLCBjYWxsYmFjaylcblx0aWYgKCAkLmlzRnVuY3Rpb24oIHNwZWVkICkgKSB7XG5cdFx0Y2FsbGJhY2sgPSBzcGVlZDtcblx0XHRzcGVlZCA9IG51bGw7XG5cdH1cblxuXHQvLyBBZGQgb3B0aW9ucyB0byBlZmZlY3Rcblx0aWYgKCBvcHRpb25zICkge1xuXHRcdCQuZXh0ZW5kKCBlZmZlY3QsIG9wdGlvbnMgKTtcblx0fVxuXG5cdHNwZWVkID0gc3BlZWQgfHwgb3B0aW9ucy5kdXJhdGlvbjtcblx0ZWZmZWN0LmR1cmF0aW9uID0gJC5meC5vZmYgPyAwIDpcblx0XHR0eXBlb2Ygc3BlZWQgPT09IFwibnVtYmVyXCIgPyBzcGVlZCA6XG5cdFx0c3BlZWQgaW4gJC5meC5zcGVlZHMgPyAkLmZ4LnNwZWVkc1sgc3BlZWQgXSA6XG5cdFx0JC5meC5zcGVlZHMuX2RlZmF1bHQ7XG5cblx0ZWZmZWN0LmNvbXBsZXRlID0gY2FsbGJhY2sgfHwgb3B0aW9ucy5jb21wbGV0ZTtcblxuXHRyZXR1cm4gZWZmZWN0O1xufVxuXG5mdW5jdGlvbiBzdGFuZGFyZEFuaW1hdGlvbk9wdGlvbiggb3B0aW9uICkge1xuXG5cdC8vIFZhbGlkIHN0YW5kYXJkIHNwZWVkcyAobm90aGluZywgbnVtYmVyLCBuYW1lZCBzcGVlZClcblx0aWYgKCAhb3B0aW9uIHx8IHR5cGVvZiBvcHRpb24gPT09IFwibnVtYmVyXCIgfHwgJC5meC5zcGVlZHNbIG9wdGlvbiBdICkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cblx0Ly8gSW52YWxpZCBzdHJpbmdzIC0gdHJlYXQgYXMgXCJub3JtYWxcIiBzcGVlZFxuXHRpZiAoIHR5cGVvZiBvcHRpb24gPT09IFwic3RyaW5nXCIgJiYgISQuZWZmZWN0cy5lZmZlY3RbIG9wdGlvbiBdICkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cblx0Ly8gQ29tcGxldGUgY2FsbGJhY2tcblx0aWYgKCAkLmlzRnVuY3Rpb24oIG9wdGlvbiApICkge1xuXHRcdHJldHVybiB0cnVlO1xuXHR9XG5cblx0Ly8gT3B0aW9ucyBoYXNoIChidXQgbm90IG5hbWluZyBhbiBlZmZlY3QpXG5cdGlmICggdHlwZW9mIG9wdGlvbiA9PT0gXCJvYmplY3RcIiAmJiAhb3B0aW9uLmVmZmVjdCApIHtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fVxuXG5cdC8vIERpZG4ndCBtYXRjaCBhbnkgc3RhbmRhcmQgQVBJXG5cdHJldHVybiBmYWxzZTtcbn1cblxuJC5mbi5leHRlbmQoIHtcblx0ZWZmZWN0OiBmdW5jdGlvbiggLyogZWZmZWN0LCBvcHRpb25zLCBzcGVlZCwgY2FsbGJhY2sgKi8gKSB7XG5cdFx0dmFyIGFyZ3MgPSBfbm9ybWFsaXplQXJndW1lbnRzLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSxcblx0XHRcdGVmZmVjdE1ldGhvZCA9ICQuZWZmZWN0cy5lZmZlY3RbIGFyZ3MuZWZmZWN0IF0sXG5cdFx0XHRkZWZhdWx0TW9kZSA9IGVmZmVjdE1ldGhvZC5tb2RlLFxuXHRcdFx0cXVldWUgPSBhcmdzLnF1ZXVlLFxuXHRcdFx0cXVldWVOYW1lID0gcXVldWUgfHwgXCJmeFwiLFxuXHRcdFx0Y29tcGxldGUgPSBhcmdzLmNvbXBsZXRlLFxuXHRcdFx0bW9kZSA9IGFyZ3MubW9kZSxcblx0XHRcdG1vZGVzID0gW10sXG5cdFx0XHRwcmVmaWx0ZXIgPSBmdW5jdGlvbiggbmV4dCApIHtcblx0XHRcdFx0dmFyIGVsID0gJCggdGhpcyApLFxuXHRcdFx0XHRcdG5vcm1hbGl6ZWRNb2RlID0gJC5lZmZlY3RzLm1vZGUoIGVsLCBtb2RlICkgfHwgZGVmYXVsdE1vZGU7XG5cblx0XHRcdFx0Ly8gU2VudGluZWwgZm9yIGR1Y2stcHVuY2hpbmcgdGhlIDphbmltYXRlZCBwc3VlZG8tc2VsZWN0b3Jcblx0XHRcdFx0ZWwuZGF0YSggZGF0YVNwYWNlQW5pbWF0ZWQsIHRydWUgKTtcblxuXHRcdFx0XHQvLyBTYXZlIGVmZmVjdCBtb2RlIGZvciBsYXRlciB1c2UsXG5cdFx0XHRcdC8vIHdlIGNhbid0IGp1c3QgY2FsbCAkLmVmZmVjdHMubW9kZSBhZ2FpbiBsYXRlcixcblx0XHRcdFx0Ly8gYXMgdGhlIC5zaG93KCkgYmVsb3cgZGVzdHJveXMgdGhlIGluaXRpYWwgc3RhdGVcblx0XHRcdFx0bW9kZXMucHVzaCggbm9ybWFsaXplZE1vZGUgKTtcblxuXHRcdFx0XHQvLyBTZWUgJC51aUJhY2tDb21wYXQgaW5zaWRlIG9mIHJ1bigpIGZvciByZW1vdmFsIG9mIGRlZmF1bHRNb2RlIGluIDEuMTNcblx0XHRcdFx0aWYgKCBkZWZhdWx0TW9kZSAmJiAoIG5vcm1hbGl6ZWRNb2RlID09PSBcInNob3dcIiB8fFxuXHRcdFx0XHRcdFx0KCBub3JtYWxpemVkTW9kZSA9PT0gZGVmYXVsdE1vZGUgJiYgbm9ybWFsaXplZE1vZGUgPT09IFwiaGlkZVwiICkgKSApIHtcblx0XHRcdFx0XHRlbC5zaG93KCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoICFkZWZhdWx0TW9kZSB8fCBub3JtYWxpemVkTW9kZSAhPT0gXCJub25lXCIgKSB7XG5cdFx0XHRcdFx0JC5lZmZlY3RzLnNhdmVTdHlsZSggZWwgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggJC5pc0Z1bmN0aW9uKCBuZXh0ICkgKSB7XG5cdFx0XHRcdFx0bmV4dCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXG5cdFx0aWYgKCAkLmZ4Lm9mZiB8fCAhZWZmZWN0TWV0aG9kICkge1xuXG5cdFx0XHQvLyBEZWxlZ2F0ZSB0byB0aGUgb3JpZ2luYWwgbWV0aG9kIChlLmcuLCAuc2hvdygpKSBpZiBwb3NzaWJsZVxuXHRcdFx0aWYgKCBtb2RlICkge1xuXHRcdFx0XHRyZXR1cm4gdGhpc1sgbW9kZSBdKCBhcmdzLmR1cmF0aW9uLCBjb21wbGV0ZSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0aWYgKCBjb21wbGV0ZSApIHtcblx0XHRcdFx0XHRcdGNvbXBsZXRlLmNhbGwoIHRoaXMgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBydW4oIG5leHQgKSB7XG5cdFx0XHR2YXIgZWxlbSA9ICQoIHRoaXMgKTtcblxuXHRcdFx0ZnVuY3Rpb24gY2xlYW51cCgpIHtcblx0XHRcdFx0ZWxlbS5yZW1vdmVEYXRhKCBkYXRhU3BhY2VBbmltYXRlZCApO1xuXG5cdFx0XHRcdCQuZWZmZWN0cy5jbGVhblVwKCBlbGVtICk7XG5cblx0XHRcdFx0aWYgKCBhcmdzLm1vZGUgPT09IFwiaGlkZVwiICkge1xuXHRcdFx0XHRcdGVsZW0uaGlkZSgpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0ZG9uZSgpO1xuXHRcdFx0fVxuXG5cdFx0XHRmdW5jdGlvbiBkb25lKCkge1xuXHRcdFx0XHRpZiAoICQuaXNGdW5jdGlvbiggY29tcGxldGUgKSApIHtcblx0XHRcdFx0XHRjb21wbGV0ZS5jYWxsKCBlbGVtWyAwIF0gKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggJC5pc0Z1bmN0aW9uKCBuZXh0ICkgKSB7XG5cdFx0XHRcdFx0bmV4dCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vIE92ZXJyaWRlIG1vZGUgb3B0aW9uIG9uIGEgcGVyIGVsZW1lbnQgYmFzaXMsXG5cdFx0XHQvLyBhcyB0b2dnbGUgY2FuIGJlIGVpdGhlciBzaG93IG9yIGhpZGUgZGVwZW5kaW5nIG9uIGVsZW1lbnQgc3RhdGVcblx0XHRcdGFyZ3MubW9kZSA9IG1vZGVzLnNoaWZ0KCk7XG5cblx0XHRcdGlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICYmICFkZWZhdWx0TW9kZSApIHtcblx0XHRcdFx0aWYgKCBlbGVtLmlzKCBcIjpoaWRkZW5cIiApID8gbW9kZSA9PT0gXCJoaWRlXCIgOiBtb2RlID09PSBcInNob3dcIiApIHtcblxuXHRcdFx0XHRcdC8vIENhbGwgdGhlIGNvcmUgbWV0aG9kIHRvIHRyYWNrIFwib2xkZGlzcGxheVwiIHByb3Blcmx5XG5cdFx0XHRcdFx0ZWxlbVsgbW9kZSBdKCk7XG5cdFx0XHRcdFx0ZG9uZSgpO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGVmZmVjdE1ldGhvZC5jYWxsKCBlbGVtWyAwIF0sIGFyZ3MsIGRvbmUgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aWYgKCBhcmdzLm1vZGUgPT09IFwibm9uZVwiICkge1xuXG5cdFx0XHRcdFx0Ly8gQ2FsbCB0aGUgY29yZSBtZXRob2QgdG8gdHJhY2sgXCJvbGRkaXNwbGF5XCIgcHJvcGVybHlcblx0XHRcdFx0XHRlbGVtWyBtb2RlIF0oKTtcblx0XHRcdFx0XHRkb25lKCk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0ZWZmZWN0TWV0aG9kLmNhbGwoIGVsZW1bIDAgXSwgYXJncywgY2xlYW51cCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gUnVuIHByZWZpbHRlciBvbiBhbGwgZWxlbWVudHMgZmlyc3QgdG8gZW5zdXJlIHRoYXRcblx0XHQvLyBhbnkgc2hvd2luZyBvciBoaWRpbmcgaGFwcGVucyBiZWZvcmUgcGxhY2Vob2xkZXIgY3JlYXRpb24sXG5cdFx0Ly8gd2hpY2ggZW5zdXJlcyB0aGF0IGFueSBsYXlvdXQgY2hhbmdlcyBhcmUgY29ycmVjdGx5IGNhcHR1cmVkLlxuXHRcdHJldHVybiBxdWV1ZSA9PT0gZmFsc2UgP1xuXHRcdFx0dGhpcy5lYWNoKCBwcmVmaWx0ZXIgKS5lYWNoKCBydW4gKSA6XG5cdFx0XHR0aGlzLnF1ZXVlKCBxdWV1ZU5hbWUsIHByZWZpbHRlciApLnF1ZXVlKCBxdWV1ZU5hbWUsIHJ1biApO1xuXHR9LFxuXG5cdHNob3c6ICggZnVuY3Rpb24oIG9yaWcgKSB7XG5cdFx0cmV0dXJuIGZ1bmN0aW9uKCBvcHRpb24gKSB7XG5cdFx0XHRpZiAoIHN0YW5kYXJkQW5pbWF0aW9uT3B0aW9uKCBvcHRpb24gKSApIHtcblx0XHRcdFx0cmV0dXJuIG9yaWcuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dmFyIGFyZ3MgPSBfbm9ybWFsaXplQXJndW1lbnRzLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdFx0YXJncy5tb2RlID0gXCJzaG93XCI7XG5cdFx0XHRcdHJldHVybiB0aGlzLmVmZmVjdC5jYWxsKCB0aGlzLCBhcmdzICk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fSApKCAkLmZuLnNob3cgKSxcblxuXHRoaWRlOiAoIGZ1bmN0aW9uKCBvcmlnICkge1xuXHRcdHJldHVybiBmdW5jdGlvbiggb3B0aW9uICkge1xuXHRcdFx0aWYgKCBzdGFuZGFyZEFuaW1hdGlvbk9wdGlvbiggb3B0aW9uICkgKSB7XG5cdFx0XHRcdHJldHVybiBvcmlnLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHZhciBhcmdzID0gX25vcm1hbGl6ZUFyZ3VtZW50cy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHRcdGFyZ3MubW9kZSA9IFwiaGlkZVwiO1xuXHRcdFx0XHRyZXR1cm4gdGhpcy5lZmZlY3QuY2FsbCggdGhpcywgYXJncyApO1xuXHRcdFx0fVxuXHRcdH07XG5cdH0gKSggJC5mbi5oaWRlICksXG5cblx0dG9nZ2xlOiAoIGZ1bmN0aW9uKCBvcmlnICkge1xuXHRcdHJldHVybiBmdW5jdGlvbiggb3B0aW9uICkge1xuXHRcdFx0aWYgKCBzdGFuZGFyZEFuaW1hdGlvbk9wdGlvbiggb3B0aW9uICkgfHwgdHlwZW9mIG9wdGlvbiA9PT0gXCJib29sZWFuXCIgKSB7XG5cdFx0XHRcdHJldHVybiBvcmlnLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHZhciBhcmdzID0gX25vcm1hbGl6ZUFyZ3VtZW50cy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHRcdGFyZ3MubW9kZSA9IFwidG9nZ2xlXCI7XG5cdFx0XHRcdHJldHVybiB0aGlzLmVmZmVjdC5jYWxsKCB0aGlzLCBhcmdzICk7XG5cdFx0XHR9XG5cdFx0fTtcblx0fSApKCAkLmZuLnRvZ2dsZSApLFxuXG5cdGNzc1VuaXQ6IGZ1bmN0aW9uKCBrZXkgKSB7XG5cdFx0dmFyIHN0eWxlID0gdGhpcy5jc3MoIGtleSApLFxuXHRcdFx0dmFsID0gW107XG5cblx0XHQkLmVhY2goIFsgXCJlbVwiLCBcInB4XCIsIFwiJVwiLCBcInB0XCIgXSwgZnVuY3Rpb24oIGksIHVuaXQgKSB7XG5cdFx0XHRpZiAoIHN0eWxlLmluZGV4T2YoIHVuaXQgKSA+IDAgKSB7XG5cdFx0XHRcdHZhbCA9IFsgcGFyc2VGbG9hdCggc3R5bGUgKSwgdW5pdCBdO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XHRyZXR1cm4gdmFsO1xuXHR9LFxuXG5cdGNzc0NsaXA6IGZ1bmN0aW9uKCBjbGlwT2JqICkge1xuXHRcdGlmICggY2xpcE9iaiApIHtcblx0XHRcdHJldHVybiB0aGlzLmNzcyggXCJjbGlwXCIsIFwicmVjdChcIiArIGNsaXBPYmoudG9wICsgXCJweCBcIiArIGNsaXBPYmoucmlnaHQgKyBcInB4IFwiICtcblx0XHRcdFx0Y2xpcE9iai5ib3R0b20gKyBcInB4IFwiICsgY2xpcE9iai5sZWZ0ICsgXCJweClcIiApO1xuXHRcdH1cblx0XHRyZXR1cm4gcGFyc2VDbGlwKCB0aGlzLmNzcyggXCJjbGlwXCIgKSwgdGhpcyApO1xuXHR9LFxuXG5cdHRyYW5zZmVyOiBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0XHR2YXIgZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRcdHRhcmdldCA9ICQoIG9wdGlvbnMudG8gKSxcblx0XHRcdHRhcmdldEZpeGVkID0gdGFyZ2V0LmNzcyggXCJwb3NpdGlvblwiICkgPT09IFwiZml4ZWRcIixcblx0XHRcdGJvZHkgPSAkKCBcImJvZHlcIiApLFxuXHRcdFx0Zml4VG9wID0gdGFyZ2V0Rml4ZWQgPyBib2R5LnNjcm9sbFRvcCgpIDogMCxcblx0XHRcdGZpeExlZnQgPSB0YXJnZXRGaXhlZCA/IGJvZHkuc2Nyb2xsTGVmdCgpIDogMCxcblx0XHRcdGVuZFBvc2l0aW9uID0gdGFyZ2V0Lm9mZnNldCgpLFxuXHRcdFx0YW5pbWF0aW9uID0ge1xuXHRcdFx0XHR0b3A6IGVuZFBvc2l0aW9uLnRvcCAtIGZpeFRvcCxcblx0XHRcdFx0bGVmdDogZW5kUG9zaXRpb24ubGVmdCAtIGZpeExlZnQsXG5cdFx0XHRcdGhlaWdodDogdGFyZ2V0LmlubmVySGVpZ2h0KCksXG5cdFx0XHRcdHdpZHRoOiB0YXJnZXQuaW5uZXJXaWR0aCgpXG5cdFx0XHR9LFxuXHRcdFx0c3RhcnRQb3NpdGlvbiA9IGVsZW1lbnQub2Zmc2V0KCksXG5cdFx0XHR0cmFuc2ZlciA9ICQoIFwiPGRpdiBjbGFzcz0ndWktZWZmZWN0cy10cmFuc2Zlcic+PC9kaXY+XCIgKVxuXHRcdFx0XHQuYXBwZW5kVG8oIFwiYm9keVwiIClcblx0XHRcdFx0LmFkZENsYXNzKCBvcHRpb25zLmNsYXNzTmFtZSApXG5cdFx0XHRcdC5jc3MoIHtcblx0XHRcdFx0XHR0b3A6IHN0YXJ0UG9zaXRpb24udG9wIC0gZml4VG9wLFxuXHRcdFx0XHRcdGxlZnQ6IHN0YXJ0UG9zaXRpb24ubGVmdCAtIGZpeExlZnQsXG5cdFx0XHRcdFx0aGVpZ2h0OiBlbGVtZW50LmlubmVySGVpZ2h0KCksXG5cdFx0XHRcdFx0d2lkdGg6IGVsZW1lbnQuaW5uZXJXaWR0aCgpLFxuXHRcdFx0XHRcdHBvc2l0aW9uOiB0YXJnZXRGaXhlZCA/IFwiZml4ZWRcIiA6IFwiYWJzb2x1dGVcIlxuXHRcdFx0XHR9IClcblx0XHRcdFx0LmFuaW1hdGUoIGFuaW1hdGlvbiwgb3B0aW9ucy5kdXJhdGlvbiwgb3B0aW9ucy5lYXNpbmcsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHRyYW5zZmVyLnJlbW92ZSgpO1xuXHRcdFx0XHRcdGlmICggJC5pc0Z1bmN0aW9uKCBkb25lICkgKSB7XG5cdFx0XHRcdFx0XHRkb25lKCk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdH1cbn0gKTtcblxuZnVuY3Rpb24gcGFyc2VDbGlwKCBzdHIsIGVsZW1lbnQgKSB7XG5cdFx0dmFyIG91dGVyV2lkdGggPSBlbGVtZW50Lm91dGVyV2lkdGgoKSxcblx0XHRcdG91dGVySGVpZ2h0ID0gZWxlbWVudC5vdXRlckhlaWdodCgpLFxuXHRcdFx0Y2xpcFJlZ2V4ID0gL15yZWN0XFwoKC0/XFxkKlxcLj9cXGQqcHh8LT9cXGQrJXxhdXRvKSw/XFxzKigtP1xcZCpcXC4/XFxkKnB4fC0/XFxkKyV8YXV0byksP1xccyooLT9cXGQqXFwuP1xcZCpweHwtP1xcZCslfGF1dG8pLD9cXHMqKC0/XFxkKlxcLj9cXGQqcHh8LT9cXGQrJXxhdXRvKVxcKSQvLFxuXHRcdFx0dmFsdWVzID0gY2xpcFJlZ2V4LmV4ZWMoIHN0ciApIHx8IFsgXCJcIiwgMCwgb3V0ZXJXaWR0aCwgb3V0ZXJIZWlnaHQsIDAgXTtcblxuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IHBhcnNlRmxvYXQoIHZhbHVlc1sgMSBdICkgfHwgMCxcblx0XHRcdHJpZ2h0OiB2YWx1ZXNbIDIgXSA9PT0gXCJhdXRvXCIgPyBvdXRlcldpZHRoIDogcGFyc2VGbG9hdCggdmFsdWVzWyAyIF0gKSxcblx0XHRcdGJvdHRvbTogdmFsdWVzWyAzIF0gPT09IFwiYXV0b1wiID8gb3V0ZXJIZWlnaHQgOiBwYXJzZUZsb2F0KCB2YWx1ZXNbIDMgXSApLFxuXHRcdFx0bGVmdDogcGFyc2VGbG9hdCggdmFsdWVzWyA0IF0gKSB8fCAwXG5cdFx0fTtcbn1cblxuJC5meC5zdGVwLmNsaXAgPSBmdW5jdGlvbiggZnggKSB7XG5cdGlmICggIWZ4LmNsaXBJbml0ICkge1xuXHRcdGZ4LnN0YXJ0ID0gJCggZnguZWxlbSApLmNzc0NsaXAoKTtcblx0XHRpZiAoIHR5cGVvZiBmeC5lbmQgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRmeC5lbmQgPSBwYXJzZUNsaXAoIGZ4LmVuZCwgZnguZWxlbSApO1xuXHRcdH1cblx0XHRmeC5jbGlwSW5pdCA9IHRydWU7XG5cdH1cblxuXHQkKCBmeC5lbGVtICkuY3NzQ2xpcCgge1xuXHRcdHRvcDogZngucG9zICogKCBmeC5lbmQudG9wIC0gZnguc3RhcnQudG9wICkgKyBmeC5zdGFydC50b3AsXG5cdFx0cmlnaHQ6IGZ4LnBvcyAqICggZnguZW5kLnJpZ2h0IC0gZnguc3RhcnQucmlnaHQgKSArIGZ4LnN0YXJ0LnJpZ2h0LFxuXHRcdGJvdHRvbTogZngucG9zICogKCBmeC5lbmQuYm90dG9tIC0gZnguc3RhcnQuYm90dG9tICkgKyBmeC5zdGFydC5ib3R0b20sXG5cdFx0bGVmdDogZngucG9zICogKCBmeC5lbmQubGVmdCAtIGZ4LnN0YXJ0LmxlZnQgKSArIGZ4LnN0YXJ0LmxlZnRcblx0fSApO1xufTtcblxufSApKCk7XG5cbi8qKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiovXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKiogRUFTSU5HICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuKCBmdW5jdGlvbigpIHtcblxuLy8gQmFzZWQgb24gZWFzaW5nIGVxdWF0aW9ucyBmcm9tIFJvYmVydCBQZW5uZXIgKGh0dHA6Ly93d3cucm9iZXJ0cGVubmVyLmNvbS9lYXNpbmcpXG5cbnZhciBiYXNlRWFzaW5ncyA9IHt9O1xuXG4kLmVhY2goIFsgXCJRdWFkXCIsIFwiQ3ViaWNcIiwgXCJRdWFydFwiLCBcIlF1aW50XCIsIFwiRXhwb1wiIF0sIGZ1bmN0aW9uKCBpLCBuYW1lICkge1xuXHRiYXNlRWFzaW5nc1sgbmFtZSBdID0gZnVuY3Rpb24oIHAgKSB7XG5cdFx0cmV0dXJuIE1hdGgucG93KCBwLCBpICsgMiApO1xuXHR9O1xufSApO1xuXG4kLmV4dGVuZCggYmFzZUVhc2luZ3MsIHtcblx0U2luZTogZnVuY3Rpb24oIHAgKSB7XG5cdFx0cmV0dXJuIDEgLSBNYXRoLmNvcyggcCAqIE1hdGguUEkgLyAyICk7XG5cdH0sXG5cdENpcmM6IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiAxIC0gTWF0aC5zcXJ0KCAxIC0gcCAqIHAgKTtcblx0fSxcblx0RWxhc3RpYzogZnVuY3Rpb24oIHAgKSB7XG5cdFx0cmV0dXJuIHAgPT09IDAgfHwgcCA9PT0gMSA/IHAgOlxuXHRcdFx0LU1hdGgucG93KCAyLCA4ICogKCBwIC0gMSApICkgKiBNYXRoLnNpbiggKCAoIHAgLSAxICkgKiA4MCAtIDcuNSApICogTWF0aC5QSSAvIDE1ICk7XG5cdH0sXG5cdEJhY2s6IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiBwICogcCAqICggMyAqIHAgLSAyICk7XG5cdH0sXG5cdEJvdW5jZTogZnVuY3Rpb24oIHAgKSB7XG5cdFx0dmFyIHBvdzIsXG5cdFx0XHRib3VuY2UgPSA0O1xuXG5cdFx0d2hpbGUgKCBwIDwgKCAoIHBvdzIgPSBNYXRoLnBvdyggMiwgLS1ib3VuY2UgKSApIC0gMSApIC8gMTEgKSB7fVxuXHRcdHJldHVybiAxIC8gTWF0aC5wb3coIDQsIDMgLSBib3VuY2UgKSAtIDcuNTYyNSAqIE1hdGgucG93KCAoIHBvdzIgKiAzIC0gMiApIC8gMjIgLSBwLCAyICk7XG5cdH1cbn0gKTtcblxuJC5lYWNoKCBiYXNlRWFzaW5ncywgZnVuY3Rpb24oIG5hbWUsIGVhc2VJbiApIHtcblx0JC5lYXNpbmdbIFwiZWFzZUluXCIgKyBuYW1lIF0gPSBlYXNlSW47XG5cdCQuZWFzaW5nWyBcImVhc2VPdXRcIiArIG5hbWUgXSA9IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiAxIC0gZWFzZUluKCAxIC0gcCApO1xuXHR9O1xuXHQkLmVhc2luZ1sgXCJlYXNlSW5PdXRcIiArIG5hbWUgXSA9IGZ1bmN0aW9uKCBwICkge1xuXHRcdHJldHVybiBwIDwgMC41ID9cblx0XHRcdGVhc2VJbiggcCAqIDIgKSAvIDIgOlxuXHRcdFx0MSAtIGVhc2VJbiggcCAqIC0yICsgMiApIC8gMjtcblx0fTtcbn0gKTtcblxufSApKCk7XG5cbnZhciBlZmZlY3QgPSAkLmVmZmVjdHM7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBCbGluZCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogQmxpbmQgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogQmxpbmRzIHRoZSBlbGVtZW50LlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2JsaW5kLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdEJsaW5kID0gJC5lZmZlY3RzLmRlZmluZSggXCJibGluZFwiLCBcImhpZGVcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdHZhciBtYXAgPSB7XG5cdFx0XHR1cDogWyBcImJvdHRvbVwiLCBcInRvcFwiIF0sXG5cdFx0XHR2ZXJ0aWNhbDogWyBcImJvdHRvbVwiLCBcInRvcFwiIF0sXG5cdFx0XHRkb3duOiBbIFwidG9wXCIsIFwiYm90dG9tXCIgXSxcblx0XHRcdGxlZnQ6IFsgXCJyaWdodFwiLCBcImxlZnRcIiBdLFxuXHRcdFx0aG9yaXpvbnRhbDogWyBcInJpZ2h0XCIsIFwibGVmdFwiIF0sXG5cdFx0XHRyaWdodDogWyBcImxlZnRcIiwgXCJyaWdodFwiIF1cblx0XHR9LFxuXHRcdGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0ZGlyZWN0aW9uID0gb3B0aW9ucy5kaXJlY3Rpb24gfHwgXCJ1cFwiLFxuXHRcdHN0YXJ0ID0gZWxlbWVudC5jc3NDbGlwKCksXG5cdFx0YW5pbWF0ZSA9IHsgY2xpcDogJC5leHRlbmQoIHt9LCBzdGFydCApIH0sXG5cdFx0cGxhY2Vob2xkZXIgPSAkLmVmZmVjdHMuY3JlYXRlUGxhY2Vob2xkZXIoIGVsZW1lbnQgKTtcblxuXHRhbmltYXRlLmNsaXBbIG1hcFsgZGlyZWN0aW9uIF1bIDAgXSBdID0gYW5pbWF0ZS5jbGlwWyBtYXBbIGRpcmVjdGlvbiBdWyAxIF0gXTtcblxuXHRpZiAoIG9wdGlvbnMubW9kZSA9PT0gXCJzaG93XCIgKSB7XG5cdFx0ZWxlbWVudC5jc3NDbGlwKCBhbmltYXRlLmNsaXAgKTtcblx0XHRpZiAoIHBsYWNlaG9sZGVyICkge1xuXHRcdFx0cGxhY2Vob2xkZXIuY3NzKCAkLmVmZmVjdHMuY2xpcFRvQm94KCBhbmltYXRlICkgKTtcblx0XHR9XG5cblx0XHRhbmltYXRlLmNsaXAgPSBzdGFydDtcblx0fVxuXG5cdGlmICggcGxhY2Vob2xkZXIgKSB7XG5cdFx0cGxhY2Vob2xkZXIuYW5pbWF0ZSggJC5lZmZlY3RzLmNsaXBUb0JveCggYW5pbWF0ZSApLCBvcHRpb25zLmR1cmF0aW9uLCBvcHRpb25zLmVhc2luZyApO1xuXHR9XG5cblx0ZWxlbWVudC5hbmltYXRlKCBhbmltYXRlLCB7XG5cdFx0cXVldWU6IGZhbHNlLFxuXHRcdGR1cmF0aW9uOiBvcHRpb25zLmR1cmF0aW9uLFxuXHRcdGVhc2luZzogb3B0aW9ucy5lYXNpbmcsXG5cdFx0Y29tcGxldGU6IGRvbmVcblx0fSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgQm91bmNlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBCb3VuY2UgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogQm91bmNlcyBhbiBlbGVtZW50IGhvcml6b250YWxseSBvciB2ZXJ0aWNhbGx5IG4gdGltZXMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vYm91bmNlLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdEJvdW5jZSA9ICQuZWZmZWN0cy5kZWZpbmUoIFwiYm91bmNlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHR2YXIgdXBBbmltLCBkb3duQW5pbSwgcmVmVmFsdWUsXG5cdFx0ZWxlbWVudCA9ICQoIHRoaXMgKSxcblxuXHRcdC8vIERlZmF1bHRzOlxuXHRcdG1vZGUgPSBvcHRpb25zLm1vZGUsXG5cdFx0aGlkZSA9IG1vZGUgPT09IFwiaGlkZVwiLFxuXHRcdHNob3cgPSBtb2RlID09PSBcInNob3dcIixcblx0XHRkaXJlY3Rpb24gPSBvcHRpb25zLmRpcmVjdGlvbiB8fCBcInVwXCIsXG5cdFx0ZGlzdGFuY2UgPSBvcHRpb25zLmRpc3RhbmNlLFxuXHRcdHRpbWVzID0gb3B0aW9ucy50aW1lcyB8fCA1LFxuXG5cdFx0Ly8gTnVtYmVyIG9mIGludGVybmFsIGFuaW1hdGlvbnNcblx0XHRhbmltcyA9IHRpbWVzICogMiArICggc2hvdyB8fCBoaWRlID8gMSA6IDAgKSxcblx0XHRzcGVlZCA9IG9wdGlvbnMuZHVyYXRpb24gLyBhbmltcyxcblx0XHRlYXNpbmcgPSBvcHRpb25zLmVhc2luZyxcblxuXHRcdC8vIFV0aWxpdHk6XG5cdFx0cmVmID0gKCBkaXJlY3Rpb24gPT09IFwidXBcIiB8fCBkaXJlY3Rpb24gPT09IFwiZG93blwiICkgPyBcInRvcFwiIDogXCJsZWZ0XCIsXG5cdFx0bW90aW9uID0gKCBkaXJlY3Rpb24gPT09IFwidXBcIiB8fCBkaXJlY3Rpb24gPT09IFwibGVmdFwiICksXG5cdFx0aSA9IDAsXG5cblx0XHRxdWV1ZWxlbiA9IGVsZW1lbnQucXVldWUoKS5sZW5ndGg7XG5cblx0JC5lZmZlY3RzLmNyZWF0ZVBsYWNlaG9sZGVyKCBlbGVtZW50ICk7XG5cblx0cmVmVmFsdWUgPSBlbGVtZW50LmNzcyggcmVmICk7XG5cblx0Ly8gRGVmYXVsdCBkaXN0YW5jZSBmb3IgdGhlIEJJR0dFU1QgYm91bmNlIGlzIHRoZSBvdXRlciBEaXN0YW5jZSAvIDNcblx0aWYgKCAhZGlzdGFuY2UgKSB7XG5cdFx0ZGlzdGFuY2UgPSBlbGVtZW50WyByZWYgPT09IFwidG9wXCIgPyBcIm91dGVySGVpZ2h0XCIgOiBcIm91dGVyV2lkdGhcIiBdKCkgLyAzO1xuXHR9XG5cblx0aWYgKCBzaG93ICkge1xuXHRcdGRvd25BbmltID0geyBvcGFjaXR5OiAxIH07XG5cdFx0ZG93bkFuaW1bIHJlZiBdID0gcmVmVmFsdWU7XG5cblx0XHQvLyBJZiB3ZSBhcmUgc2hvd2luZywgZm9yY2Ugb3BhY2l0eSAwIGFuZCBzZXQgdGhlIGluaXRpYWwgcG9zaXRpb25cblx0XHQvLyB0aGVuIGRvIHRoZSBcImZpcnN0XCIgYW5pbWF0aW9uXG5cdFx0ZWxlbWVudFxuXHRcdFx0LmNzcyggXCJvcGFjaXR5XCIsIDAgKVxuXHRcdFx0LmNzcyggcmVmLCBtb3Rpb24gPyAtZGlzdGFuY2UgKiAyIDogZGlzdGFuY2UgKiAyIClcblx0XHRcdC5hbmltYXRlKCBkb3duQW5pbSwgc3BlZWQsIGVhc2luZyApO1xuXHR9XG5cblx0Ly8gU3RhcnQgYXQgdGhlIHNtYWxsZXN0IGRpc3RhbmNlIGlmIHdlIGFyZSBoaWRpbmdcblx0aWYgKCBoaWRlICkge1xuXHRcdGRpc3RhbmNlID0gZGlzdGFuY2UgLyBNYXRoLnBvdyggMiwgdGltZXMgLSAxICk7XG5cdH1cblxuXHRkb3duQW5pbSA9IHt9O1xuXHRkb3duQW5pbVsgcmVmIF0gPSByZWZWYWx1ZTtcblxuXHQvLyBCb3VuY2VzIHVwL2Rvd24vbGVmdC9yaWdodCB0aGVuIGJhY2sgdG8gMCAtLSB0aW1lcyAqIDIgYW5pbWF0aW9ucyBoYXBwZW4gaGVyZVxuXHRmb3IgKCA7IGkgPCB0aW1lczsgaSsrICkge1xuXHRcdHVwQW5pbSA9IHt9O1xuXHRcdHVwQW5pbVsgcmVmIF0gPSAoIG1vdGlvbiA/IFwiLT1cIiA6IFwiKz1cIiApICsgZGlzdGFuY2U7XG5cblx0XHRlbGVtZW50XG5cdFx0XHQuYW5pbWF0ZSggdXBBbmltLCBzcGVlZCwgZWFzaW5nIClcblx0XHRcdC5hbmltYXRlKCBkb3duQW5pbSwgc3BlZWQsIGVhc2luZyApO1xuXG5cdFx0ZGlzdGFuY2UgPSBoaWRlID8gZGlzdGFuY2UgKiAyIDogZGlzdGFuY2UgLyAyO1xuXHR9XG5cblx0Ly8gTGFzdCBCb3VuY2Ugd2hlbiBIaWRpbmdcblx0aWYgKCBoaWRlICkge1xuXHRcdHVwQW5pbSA9IHsgb3BhY2l0eTogMCB9O1xuXHRcdHVwQW5pbVsgcmVmIF0gPSAoIG1vdGlvbiA/IFwiLT1cIiA6IFwiKz1cIiApICsgZGlzdGFuY2U7XG5cblx0XHRlbGVtZW50LmFuaW1hdGUoIHVwQW5pbSwgc3BlZWQsIGVhc2luZyApO1xuXHR9XG5cblx0ZWxlbWVudC5xdWV1ZSggZG9uZSApO1xuXG5cdCQuZWZmZWN0cy51bnNoaWZ0KCBlbGVtZW50LCBxdWV1ZWxlbiwgYW5pbXMgKyAxICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBDbGlwIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBDbGlwIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IENsaXBzIHRoZSBlbGVtZW50IG9uIGFuZCBvZmYgbGlrZSBhbiBvbGQgVFYuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vY2xpcC1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RDbGlwID0gJC5lZmZlY3RzLmRlZmluZSggXCJjbGlwXCIsIFwiaGlkZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblx0dmFyIHN0YXJ0LFxuXHRcdGFuaW1hdGUgPSB7fSxcblx0XHRlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdGRpcmVjdGlvbiA9IG9wdGlvbnMuZGlyZWN0aW9uIHx8IFwidmVydGljYWxcIixcblx0XHRib3RoID0gZGlyZWN0aW9uID09PSBcImJvdGhcIixcblx0XHRob3Jpem9udGFsID0gYm90aCB8fCBkaXJlY3Rpb24gPT09IFwiaG9yaXpvbnRhbFwiLFxuXHRcdHZlcnRpY2FsID0gYm90aCB8fCBkaXJlY3Rpb24gPT09IFwidmVydGljYWxcIjtcblxuXHRzdGFydCA9IGVsZW1lbnQuY3NzQ2xpcCgpO1xuXHRhbmltYXRlLmNsaXAgPSB7XG5cdFx0dG9wOiB2ZXJ0aWNhbCA/ICggc3RhcnQuYm90dG9tIC0gc3RhcnQudG9wICkgLyAyIDogc3RhcnQudG9wLFxuXHRcdHJpZ2h0OiBob3Jpem9udGFsID8gKCBzdGFydC5yaWdodCAtIHN0YXJ0LmxlZnQgKSAvIDIgOiBzdGFydC5yaWdodCxcblx0XHRib3R0b206IHZlcnRpY2FsID8gKCBzdGFydC5ib3R0b20gLSBzdGFydC50b3AgKSAvIDIgOiBzdGFydC5ib3R0b20sXG5cdFx0bGVmdDogaG9yaXpvbnRhbCA/ICggc3RhcnQucmlnaHQgLSBzdGFydC5sZWZ0ICkgLyAyIDogc3RhcnQubGVmdFxuXHR9O1xuXG5cdCQuZWZmZWN0cy5jcmVhdGVQbGFjZWhvbGRlciggZWxlbWVudCApO1xuXG5cdGlmICggb3B0aW9ucy5tb2RlID09PSBcInNob3dcIiApIHtcblx0XHRlbGVtZW50LmNzc0NsaXAoIGFuaW1hdGUuY2xpcCApO1xuXHRcdGFuaW1hdGUuY2xpcCA9IHN0YXJ0O1xuXHR9XG5cblx0ZWxlbWVudC5hbmltYXRlKCBhbmltYXRlLCB7XG5cdFx0cXVldWU6IGZhbHNlLFxuXHRcdGR1cmF0aW9uOiBvcHRpb25zLmR1cmF0aW9uLFxuXHRcdGVhc2luZzogb3B0aW9ucy5lYXNpbmcsXG5cdFx0Y29tcGxldGU6IGRvbmVcblx0fSApO1xuXG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBEcm9wIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBEcm9wIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IE1vdmVzIGFuIGVsZW1lbnQgaW4gb25lIGRpcmVjdGlvbiBhbmQgaGlkZXMgaXQgYXQgdGhlIHNhbWUgdGltZS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9kcm9wLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdERyb3AgPSAkLmVmZmVjdHMuZGVmaW5lKCBcImRyb3BcIiwgXCJoaWRlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXG5cdHZhciBkaXN0YW5jZSxcblx0XHRlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdG1vZGUgPSBvcHRpb25zLm1vZGUsXG5cdFx0c2hvdyA9IG1vZGUgPT09IFwic2hvd1wiLFxuXHRcdGRpcmVjdGlvbiA9IG9wdGlvbnMuZGlyZWN0aW9uIHx8IFwibGVmdFwiLFxuXHRcdHJlZiA9ICggZGlyZWN0aW9uID09PSBcInVwXCIgfHwgZGlyZWN0aW9uID09PSBcImRvd25cIiApID8gXCJ0b3BcIiA6IFwibGVmdFwiLFxuXHRcdG1vdGlvbiA9ICggZGlyZWN0aW9uID09PSBcInVwXCIgfHwgZGlyZWN0aW9uID09PSBcImxlZnRcIiApID8gXCItPVwiIDogXCIrPVwiLFxuXHRcdG9wcG9zaXRlTW90aW9uID0gKCBtb3Rpb24gPT09IFwiKz1cIiApID8gXCItPVwiIDogXCIrPVwiLFxuXHRcdGFuaW1hdGlvbiA9IHtcblx0XHRcdG9wYWNpdHk6IDBcblx0XHR9O1xuXG5cdCQuZWZmZWN0cy5jcmVhdGVQbGFjZWhvbGRlciggZWxlbWVudCApO1xuXG5cdGRpc3RhbmNlID0gb3B0aW9ucy5kaXN0YW5jZSB8fFxuXHRcdGVsZW1lbnRbIHJlZiA9PT0gXCJ0b3BcIiA/IFwib3V0ZXJIZWlnaHRcIiA6IFwib3V0ZXJXaWR0aFwiIF0oIHRydWUgKSAvIDI7XG5cblx0YW5pbWF0aW9uWyByZWYgXSA9IG1vdGlvbiArIGRpc3RhbmNlO1xuXG5cdGlmICggc2hvdyApIHtcblx0XHRlbGVtZW50LmNzcyggYW5pbWF0aW9uICk7XG5cblx0XHRhbmltYXRpb25bIHJlZiBdID0gb3Bwb3NpdGVNb3Rpb24gKyBkaXN0YW5jZTtcblx0XHRhbmltYXRpb24ub3BhY2l0eSA9IDE7XG5cdH1cblxuXHQvLyBBbmltYXRlXG5cdGVsZW1lbnQuYW5pbWF0ZSggYW5pbWF0aW9uLCB7XG5cdFx0cXVldWU6IGZhbHNlLFxuXHRcdGR1cmF0aW9uOiBvcHRpb25zLmR1cmF0aW9uLFxuXHRcdGVhc2luZzogb3B0aW9ucy5lYXNpbmcsXG5cdFx0Y29tcGxldGU6IGRvbmVcblx0fSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgRXhwbG9kZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRXhwbG9kZSBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8ganNjczpkaXNhYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZGVzY3JpcHRpb246IEV4cGxvZGVzIGFuIGVsZW1lbnQgaW4gYWxsIGRpcmVjdGlvbnMgaW50byBuIHBpZWNlcy4gSW1wbG9kZXMgYW4gZWxlbWVudCB0byBpdHMgb3JpZ2luYWwgd2hvbGVuZXNzLlxuLy8ganNjczplbmFibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9leHBsb2RlLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdEV4cGxvZGUgPSAkLmVmZmVjdHMuZGVmaW5lKCBcImV4cGxvZGVcIiwgXCJoaWRlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXG5cdHZhciBpLCBqLCBsZWZ0LCB0b3AsIG14LCBteSxcblx0XHRyb3dzID0gb3B0aW9ucy5waWVjZXMgPyBNYXRoLnJvdW5kKCBNYXRoLnNxcnQoIG9wdGlvbnMucGllY2VzICkgKSA6IDMsXG5cdFx0Y2VsbHMgPSByb3dzLFxuXHRcdGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0bW9kZSA9IG9wdGlvbnMubW9kZSxcblx0XHRzaG93ID0gbW9kZSA9PT0gXCJzaG93XCIsXG5cblx0XHQvLyBTaG93IGFuZCB0aGVuIHZpc2liaWxpdHk6aGlkZGVuIHRoZSBlbGVtZW50IGJlZm9yZSBjYWxjdWxhdGluZyBvZmZzZXRcblx0XHRvZmZzZXQgPSBlbGVtZW50LnNob3coKS5jc3MoIFwidmlzaWJpbGl0eVwiLCBcImhpZGRlblwiICkub2Zmc2V0KCksXG5cblx0XHQvLyBXaWR0aCBhbmQgaGVpZ2h0IG9mIGEgcGllY2Vcblx0XHR3aWR0aCA9IE1hdGguY2VpbCggZWxlbWVudC5vdXRlcldpZHRoKCkgLyBjZWxscyApLFxuXHRcdGhlaWdodCA9IE1hdGguY2VpbCggZWxlbWVudC5vdXRlckhlaWdodCgpIC8gcm93cyApLFxuXHRcdHBpZWNlcyA9IFtdO1xuXG5cdC8vIENoaWxkcmVuIGFuaW1hdGUgY29tcGxldGU6XG5cdGZ1bmN0aW9uIGNoaWxkQ29tcGxldGUoKSB7XG5cdFx0cGllY2VzLnB1c2goIHRoaXMgKTtcblx0XHRpZiAoIHBpZWNlcy5sZW5ndGggPT09IHJvd3MgKiBjZWxscyApIHtcblx0XHRcdGFuaW1Db21wbGV0ZSgpO1xuXHRcdH1cblx0fVxuXG5cdC8vIENsb25lIHRoZSBlbGVtZW50IGZvciBlYWNoIHJvdyBhbmQgY2VsbC5cblx0Zm9yICggaSA9IDA7IGkgPCByb3dzOyBpKysgKSB7IC8vID09PT5cblx0XHR0b3AgPSBvZmZzZXQudG9wICsgaSAqIGhlaWdodDtcblx0XHRteSA9IGkgLSAoIHJvd3MgLSAxICkgLyAyO1xuXG5cdFx0Zm9yICggaiA9IDA7IGogPCBjZWxsczsgaisrICkgeyAvLyB8fHxcblx0XHRcdGxlZnQgPSBvZmZzZXQubGVmdCArIGogKiB3aWR0aDtcblx0XHRcdG14ID0gaiAtICggY2VsbHMgLSAxICkgLyAyO1xuXG5cdFx0XHQvLyBDcmVhdGUgYSBjbG9uZSBvZiB0aGUgbm93IGhpZGRlbiBtYWluIGVsZW1lbnQgdGhhdCB3aWxsIGJlIGFic29sdXRlIHBvc2l0aW9uZWRcblx0XHRcdC8vIHdpdGhpbiBhIHdyYXBwZXIgZGl2IG9mZiB0aGUgLWxlZnQgYW5kIC10b3AgZXF1YWwgdG8gc2l6ZSBvZiBvdXIgcGllY2VzXG5cdFx0XHRlbGVtZW50XG5cdFx0XHRcdC5jbG9uZSgpXG5cdFx0XHRcdC5hcHBlbmRUbyggXCJib2R5XCIgKVxuXHRcdFx0XHQud3JhcCggXCI8ZGl2PjwvZGl2PlwiIClcblx0XHRcdFx0LmNzcygge1xuXHRcdFx0XHRcdHBvc2l0aW9uOiBcImFic29sdXRlXCIsXG5cdFx0XHRcdFx0dmlzaWJpbGl0eTogXCJ2aXNpYmxlXCIsXG5cdFx0XHRcdFx0bGVmdDogLWogKiB3aWR0aCxcblx0XHRcdFx0XHR0b3A6IC1pICogaGVpZ2h0XG5cdFx0XHRcdH0gKVxuXG5cdFx0XHRcdC8vIFNlbGVjdCB0aGUgd3JhcHBlciAtIG1ha2UgaXQgb3ZlcmZsb3c6IGhpZGRlbiBhbmQgYWJzb2x1dGUgcG9zaXRpb25lZCBiYXNlZCBvblxuXHRcdFx0XHQvLyB3aGVyZSB0aGUgb3JpZ2luYWwgd2FzIGxvY2F0ZWQgK2xlZnQgYW5kICt0b3AgZXF1YWwgdG8gdGhlIHNpemUgb2YgcGllY2VzXG5cdFx0XHRcdC5wYXJlbnQoKVxuXHRcdFx0XHRcdC5hZGRDbGFzcyggXCJ1aS1lZmZlY3RzLWV4cGxvZGVcIiApXG5cdFx0XHRcdFx0LmNzcygge1xuXHRcdFx0XHRcdFx0cG9zaXRpb246IFwiYWJzb2x1dGVcIixcblx0XHRcdFx0XHRcdG92ZXJmbG93OiBcImhpZGRlblwiLFxuXHRcdFx0XHRcdFx0d2lkdGg6IHdpZHRoLFxuXHRcdFx0XHRcdFx0aGVpZ2h0OiBoZWlnaHQsXG5cdFx0XHRcdFx0XHRsZWZ0OiBsZWZ0ICsgKCBzaG93ID8gbXggKiB3aWR0aCA6IDAgKSxcblx0XHRcdFx0XHRcdHRvcDogdG9wICsgKCBzaG93ID8gbXkgKiBoZWlnaHQgOiAwICksXG5cdFx0XHRcdFx0XHRvcGFjaXR5OiBzaG93ID8gMCA6IDFcblx0XHRcdFx0XHR9IClcblx0XHRcdFx0XHQuYW5pbWF0ZSgge1xuXHRcdFx0XHRcdFx0bGVmdDogbGVmdCArICggc2hvdyA/IDAgOiBteCAqIHdpZHRoICksXG5cdFx0XHRcdFx0XHR0b3A6IHRvcCArICggc2hvdyA/IDAgOiBteSAqIGhlaWdodCApLFxuXHRcdFx0XHRcdFx0b3BhY2l0eTogc2hvdyA/IDEgOiAwXG5cdFx0XHRcdFx0fSwgb3B0aW9ucy5kdXJhdGlvbiB8fCA1MDAsIG9wdGlvbnMuZWFzaW5nLCBjaGlsZENvbXBsZXRlICk7XG5cdFx0fVxuXHR9XG5cblx0ZnVuY3Rpb24gYW5pbUNvbXBsZXRlKCkge1xuXHRcdGVsZW1lbnQuY3NzKCB7XG5cdFx0XHR2aXNpYmlsaXR5OiBcInZpc2libGVcIlxuXHRcdH0gKTtcblx0XHQkKCBwaWVjZXMgKS5yZW1vdmUoKTtcblx0XHRkb25lKCk7XG5cdH1cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIEZhZGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEZhZGUgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogRmFkZXMgdGhlIGVsZW1lbnQuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZmFkZS1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RGYWRlID0gJC5lZmZlY3RzLmRlZmluZSggXCJmYWRlXCIsIFwidG9nZ2xlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHR2YXIgc2hvdyA9IG9wdGlvbnMubW9kZSA9PT0gXCJzaG93XCI7XG5cblx0JCggdGhpcyApXG5cdFx0LmNzcyggXCJvcGFjaXR5XCIsIHNob3cgPyAwIDogMSApXG5cdFx0LmFuaW1hdGUoIHtcblx0XHRcdG9wYWNpdHk6IHNob3cgPyAxIDogMFxuXHRcdH0sIHtcblx0XHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRcdGR1cmF0aW9uOiBvcHRpb25zLmR1cmF0aW9uLFxuXHRcdFx0ZWFzaW5nOiBvcHRpb25zLmVhc2luZyxcblx0XHRcdGNvbXBsZXRlOiBkb25lXG5cdFx0fSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgRm9sZCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRm9sZCBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBGb2xkcyBhbiBlbGVtZW50IGZpcnN0IGhvcml6b250YWxseSBhbmQgdGhlbiB2ZXJ0aWNhbGx5LlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2ZvbGQtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0Rm9sZCA9ICQuZWZmZWN0cy5kZWZpbmUoIFwiZm9sZFwiLCBcImhpZGVcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cblx0Ly8gQ3JlYXRlIGVsZW1lbnRcblx0dmFyIGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0bW9kZSA9IG9wdGlvbnMubW9kZSxcblx0XHRzaG93ID0gbW9kZSA9PT0gXCJzaG93XCIsXG5cdFx0aGlkZSA9IG1vZGUgPT09IFwiaGlkZVwiLFxuXHRcdHNpemUgPSBvcHRpb25zLnNpemUgfHwgMTUsXG5cdFx0cGVyY2VudCA9IC8oWzAtOV0rKSUvLmV4ZWMoIHNpemUgKSxcblx0XHRob3JpekZpcnN0ID0gISFvcHRpb25zLmhvcml6Rmlyc3QsXG5cdFx0cmVmID0gaG9yaXpGaXJzdCA/IFsgXCJyaWdodFwiLCBcImJvdHRvbVwiIF0gOiBbIFwiYm90dG9tXCIsIFwicmlnaHRcIiBdLFxuXHRcdGR1cmF0aW9uID0gb3B0aW9ucy5kdXJhdGlvbiAvIDIsXG5cblx0XHRwbGFjZWhvbGRlciA9ICQuZWZmZWN0cy5jcmVhdGVQbGFjZWhvbGRlciggZWxlbWVudCApLFxuXG5cdFx0c3RhcnQgPSBlbGVtZW50LmNzc0NsaXAoKSxcblx0XHRhbmltYXRpb24xID0geyBjbGlwOiAkLmV4dGVuZCgge30sIHN0YXJ0ICkgfSxcblx0XHRhbmltYXRpb24yID0geyBjbGlwOiAkLmV4dGVuZCgge30sIHN0YXJ0ICkgfSxcblxuXHRcdGRpc3RhbmNlID0gWyBzdGFydFsgcmVmWyAwIF0gXSwgc3RhcnRbIHJlZlsgMSBdIF0gXSxcblxuXHRcdHF1ZXVlbGVuID0gZWxlbWVudC5xdWV1ZSgpLmxlbmd0aDtcblxuXHRpZiAoIHBlcmNlbnQgKSB7XG5cdFx0c2l6ZSA9IHBhcnNlSW50KCBwZXJjZW50WyAxIF0sIDEwICkgLyAxMDAgKiBkaXN0YW5jZVsgaGlkZSA/IDAgOiAxIF07XG5cdH1cblx0YW5pbWF0aW9uMS5jbGlwWyByZWZbIDAgXSBdID0gc2l6ZTtcblx0YW5pbWF0aW9uMi5jbGlwWyByZWZbIDAgXSBdID0gc2l6ZTtcblx0YW5pbWF0aW9uMi5jbGlwWyByZWZbIDEgXSBdID0gMDtcblxuXHRpZiAoIHNob3cgKSB7XG5cdFx0ZWxlbWVudC5jc3NDbGlwKCBhbmltYXRpb24yLmNsaXAgKTtcblx0XHRpZiAoIHBsYWNlaG9sZGVyICkge1xuXHRcdFx0cGxhY2Vob2xkZXIuY3NzKCAkLmVmZmVjdHMuY2xpcFRvQm94KCBhbmltYXRpb24yICkgKTtcblx0XHR9XG5cblx0XHRhbmltYXRpb24yLmNsaXAgPSBzdGFydDtcblx0fVxuXG5cdC8vIEFuaW1hdGVcblx0ZWxlbWVudFxuXHRcdC5xdWV1ZSggZnVuY3Rpb24oIG5leHQgKSB7XG5cdFx0XHRpZiAoIHBsYWNlaG9sZGVyICkge1xuXHRcdFx0XHRwbGFjZWhvbGRlclxuXHRcdFx0XHRcdC5hbmltYXRlKCAkLmVmZmVjdHMuY2xpcFRvQm94KCBhbmltYXRpb24xICksIGR1cmF0aW9uLCBvcHRpb25zLmVhc2luZyApXG5cdFx0XHRcdFx0LmFuaW1hdGUoICQuZWZmZWN0cy5jbGlwVG9Cb3goIGFuaW1hdGlvbjIgKSwgZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nICk7XG5cdFx0XHR9XG5cblx0XHRcdG5leHQoKTtcblx0XHR9IClcblx0XHQuYW5pbWF0ZSggYW5pbWF0aW9uMSwgZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nIClcblx0XHQuYW5pbWF0ZSggYW5pbWF0aW9uMiwgZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nIClcblx0XHQucXVldWUoIGRvbmUgKTtcblxuXHQkLmVmZmVjdHMudW5zaGlmdCggZWxlbWVudCwgcXVldWVsZW4sIDQgKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIEhpZ2hsaWdodCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogSGlnaGxpZ2h0IEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IEhpZ2hsaWdodHMgdGhlIGJhY2tncm91bmQgb2YgYW4gZWxlbWVudCBpbiBhIGRlZmluZWQgY29sb3IgZm9yIGEgY3VzdG9tIGR1cmF0aW9uLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2hpZ2hsaWdodC1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RIaWdobGlnaHQgPSAkLmVmZmVjdHMuZGVmaW5lKCBcImhpZ2hsaWdodFwiLCBcInNob3dcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cdHZhciBlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdGFuaW1hdGlvbiA9IHtcblx0XHRcdGJhY2tncm91bmRDb2xvcjogZWxlbWVudC5jc3MoIFwiYmFja2dyb3VuZENvbG9yXCIgKVxuXHRcdH07XG5cblx0aWYgKCBvcHRpb25zLm1vZGUgPT09IFwiaGlkZVwiICkge1xuXHRcdGFuaW1hdGlvbi5vcGFjaXR5ID0gMDtcblx0fVxuXG5cdCQuZWZmZWN0cy5zYXZlU3R5bGUoIGVsZW1lbnQgKTtcblxuXHRlbGVtZW50XG5cdFx0LmNzcygge1xuXHRcdFx0YmFja2dyb3VuZEltYWdlOiBcIm5vbmVcIixcblx0XHRcdGJhY2tncm91bmRDb2xvcjogb3B0aW9ucy5jb2xvciB8fCBcIiNmZmZmOTlcIlxuXHRcdH0gKVxuXHRcdC5hbmltYXRlKCBhbmltYXRpb24sIHtcblx0XHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRcdGR1cmF0aW9uOiBvcHRpb25zLmR1cmF0aW9uLFxuXHRcdFx0ZWFzaW5nOiBvcHRpb25zLmVhc2luZyxcblx0XHRcdGNvbXBsZXRlOiBkb25lXG5cdFx0fSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgU2l6ZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogU2l6ZSBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBSZXNpemUgYW4gZWxlbWVudCB0byBhIHNwZWNpZmllZCB3aWR0aCBhbmQgaGVpZ2h0LlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3NpemUtZWZmZWN0L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2VmZmVjdC9cblxuXG5cbnZhciBlZmZlY3RzRWZmZWN0U2l6ZSA9ICQuZWZmZWN0cy5kZWZpbmUoIFwic2l6ZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblxuXHQvLyBDcmVhdGUgZWxlbWVudFxuXHR2YXIgYmFzZWxpbmUsIGZhY3RvciwgdGVtcCxcblx0XHRlbGVtZW50ID0gJCggdGhpcyApLFxuXG5cdFx0Ly8gQ29weSBmb3IgY2hpbGRyZW5cblx0XHRjUHJvcHMgPSBbIFwiZm9udFNpemVcIiBdLFxuXHRcdHZQcm9wcyA9IFsgXCJib3JkZXJUb3BXaWR0aFwiLCBcImJvcmRlckJvdHRvbVdpZHRoXCIsIFwicGFkZGluZ1RvcFwiLCBcInBhZGRpbmdCb3R0b21cIiBdLFxuXHRcdGhQcm9wcyA9IFsgXCJib3JkZXJMZWZ0V2lkdGhcIiwgXCJib3JkZXJSaWdodFdpZHRoXCIsIFwicGFkZGluZ0xlZnRcIiwgXCJwYWRkaW5nUmlnaHRcIiBdLFxuXG5cdFx0Ly8gU2V0IG9wdGlvbnNcblx0XHRtb2RlID0gb3B0aW9ucy5tb2RlLFxuXHRcdHJlc3RvcmUgPSBtb2RlICE9PSBcImVmZmVjdFwiLFxuXHRcdHNjYWxlID0gb3B0aW9ucy5zY2FsZSB8fCBcImJvdGhcIixcblx0XHRvcmlnaW4gPSBvcHRpb25zLm9yaWdpbiB8fCBbIFwibWlkZGxlXCIsIFwiY2VudGVyXCIgXSxcblx0XHRwb3NpdGlvbiA9IGVsZW1lbnQuY3NzKCBcInBvc2l0aW9uXCIgKSxcblx0XHRwb3MgPSBlbGVtZW50LnBvc2l0aW9uKCksXG5cdFx0b3JpZ2luYWwgPSAkLmVmZmVjdHMuc2NhbGVkRGltZW5zaW9ucyggZWxlbWVudCApLFxuXHRcdGZyb20gPSBvcHRpb25zLmZyb20gfHwgb3JpZ2luYWwsXG5cdFx0dG8gPSBvcHRpb25zLnRvIHx8ICQuZWZmZWN0cy5zY2FsZWREaW1lbnNpb25zKCBlbGVtZW50LCAwICk7XG5cblx0JC5lZmZlY3RzLmNyZWF0ZVBsYWNlaG9sZGVyKCBlbGVtZW50ICk7XG5cblx0aWYgKCBtb2RlID09PSBcInNob3dcIiApIHtcblx0XHR0ZW1wID0gZnJvbTtcblx0XHRmcm9tID0gdG87XG5cdFx0dG8gPSB0ZW1wO1xuXHR9XG5cblx0Ly8gU2V0IHNjYWxpbmcgZmFjdG9yXG5cdGZhY3RvciA9IHtcblx0XHRmcm9tOiB7XG5cdFx0XHR5OiBmcm9tLmhlaWdodCAvIG9yaWdpbmFsLmhlaWdodCxcblx0XHRcdHg6IGZyb20ud2lkdGggLyBvcmlnaW5hbC53aWR0aFxuXHRcdH0sXG5cdFx0dG86IHtcblx0XHRcdHk6IHRvLmhlaWdodCAvIG9yaWdpbmFsLmhlaWdodCxcblx0XHRcdHg6IHRvLndpZHRoIC8gb3JpZ2luYWwud2lkdGhcblx0XHR9XG5cdH07XG5cblx0Ly8gU2NhbGUgdGhlIGNzcyBib3hcblx0aWYgKCBzY2FsZSA9PT0gXCJib3hcIiB8fCBzY2FsZSA9PT0gXCJib3RoXCIgKSB7XG5cblx0XHQvLyBWZXJ0aWNhbCBwcm9wcyBzY2FsaW5nXG5cdFx0aWYgKCBmYWN0b3IuZnJvbS55ICE9PSBmYWN0b3IudG8ueSApIHtcblx0XHRcdGZyb20gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggZWxlbWVudCwgdlByb3BzLCBmYWN0b3IuZnJvbS55LCBmcm9tICk7XG5cdFx0XHR0byA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBlbGVtZW50LCB2UHJvcHMsIGZhY3Rvci50by55LCB0byApO1xuXHRcdH1cblxuXHRcdC8vIEhvcml6b250YWwgcHJvcHMgc2NhbGluZ1xuXHRcdGlmICggZmFjdG9yLmZyb20ueCAhPT0gZmFjdG9yLnRvLnggKSB7XG5cdFx0XHRmcm9tID0gJC5lZmZlY3RzLnNldFRyYW5zaXRpb24oIGVsZW1lbnQsIGhQcm9wcywgZmFjdG9yLmZyb20ueCwgZnJvbSApO1xuXHRcdFx0dG8gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggZWxlbWVudCwgaFByb3BzLCBmYWN0b3IudG8ueCwgdG8gKTtcblx0XHR9XG5cdH1cblxuXHQvLyBTY2FsZSB0aGUgY29udGVudFxuXHRpZiAoIHNjYWxlID09PSBcImNvbnRlbnRcIiB8fCBzY2FsZSA9PT0gXCJib3RoXCIgKSB7XG5cblx0XHQvLyBWZXJ0aWNhbCBwcm9wcyBzY2FsaW5nXG5cdFx0aWYgKCBmYWN0b3IuZnJvbS55ICE9PSBmYWN0b3IudG8ueSApIHtcblx0XHRcdGZyb20gPSAkLmVmZmVjdHMuc2V0VHJhbnNpdGlvbiggZWxlbWVudCwgY1Byb3BzLCBmYWN0b3IuZnJvbS55LCBmcm9tICk7XG5cdFx0XHR0byA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBlbGVtZW50LCBjUHJvcHMsIGZhY3Rvci50by55LCB0byApO1xuXHRcdH1cblx0fVxuXG5cdC8vIEFkanVzdCB0aGUgcG9zaXRpb24gcHJvcGVydGllcyBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgb3JpZ2luIHBvaW50c1xuXHRpZiAoIG9yaWdpbiApIHtcblx0XHRiYXNlbGluZSA9ICQuZWZmZWN0cy5nZXRCYXNlbGluZSggb3JpZ2luLCBvcmlnaW5hbCApO1xuXHRcdGZyb20udG9wID0gKCBvcmlnaW5hbC5vdXRlckhlaWdodCAtIGZyb20ub3V0ZXJIZWlnaHQgKSAqIGJhc2VsaW5lLnkgKyBwb3MudG9wO1xuXHRcdGZyb20ubGVmdCA9ICggb3JpZ2luYWwub3V0ZXJXaWR0aCAtIGZyb20ub3V0ZXJXaWR0aCApICogYmFzZWxpbmUueCArIHBvcy5sZWZ0O1xuXHRcdHRvLnRvcCA9ICggb3JpZ2luYWwub3V0ZXJIZWlnaHQgLSB0by5vdXRlckhlaWdodCApICogYmFzZWxpbmUueSArIHBvcy50b3A7XG5cdFx0dG8ubGVmdCA9ICggb3JpZ2luYWwub3V0ZXJXaWR0aCAtIHRvLm91dGVyV2lkdGggKSAqIGJhc2VsaW5lLnggKyBwb3MubGVmdDtcblx0fVxuXHRlbGVtZW50LmNzcyggZnJvbSApO1xuXG5cdC8vIEFuaW1hdGUgdGhlIGNoaWxkcmVuIGlmIGRlc2lyZWRcblx0aWYgKCBzY2FsZSA9PT0gXCJjb250ZW50XCIgfHwgc2NhbGUgPT09IFwiYm90aFwiICkge1xuXG5cdFx0dlByb3BzID0gdlByb3BzLmNvbmNhdCggWyBcIm1hcmdpblRvcFwiLCBcIm1hcmdpbkJvdHRvbVwiIF0gKS5jb25jYXQoIGNQcm9wcyApO1xuXHRcdGhQcm9wcyA9IGhQcm9wcy5jb25jYXQoIFsgXCJtYXJnaW5MZWZ0XCIsIFwibWFyZ2luUmlnaHRcIiBdICk7XG5cblx0XHQvLyBPbmx5IGFuaW1hdGUgY2hpbGRyZW4gd2l0aCB3aWR0aCBhdHRyaWJ1dGVzIHNwZWNpZmllZFxuXHRcdC8vIFRPRE86IGlzIHRoaXMgcmlnaHQ/IHNob3VsZCB3ZSBpbmNsdWRlIGFueXRoaW5nIHdpdGggY3NzIHdpZHRoIHNwZWNpZmllZCBhcyB3ZWxsXG5cdFx0ZWxlbWVudC5maW5kKCBcIipbd2lkdGhdXCIgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBjaGlsZCA9ICQoIHRoaXMgKSxcblx0XHRcdFx0Y2hpbGRPcmlnaW5hbCA9ICQuZWZmZWN0cy5zY2FsZWREaW1lbnNpb25zKCBjaGlsZCApLFxuXHRcdFx0XHRjaGlsZEZyb20gPSB7XG5cdFx0XHRcdFx0aGVpZ2h0OiBjaGlsZE9yaWdpbmFsLmhlaWdodCAqIGZhY3Rvci5mcm9tLnksXG5cdFx0XHRcdFx0d2lkdGg6IGNoaWxkT3JpZ2luYWwud2lkdGggKiBmYWN0b3IuZnJvbS54LFxuXHRcdFx0XHRcdG91dGVySGVpZ2h0OiBjaGlsZE9yaWdpbmFsLm91dGVySGVpZ2h0ICogZmFjdG9yLmZyb20ueSxcblx0XHRcdFx0XHRvdXRlcldpZHRoOiBjaGlsZE9yaWdpbmFsLm91dGVyV2lkdGggKiBmYWN0b3IuZnJvbS54XG5cdFx0XHRcdH0sXG5cdFx0XHRcdGNoaWxkVG8gPSB7XG5cdFx0XHRcdFx0aGVpZ2h0OiBjaGlsZE9yaWdpbmFsLmhlaWdodCAqIGZhY3Rvci50by55LFxuXHRcdFx0XHRcdHdpZHRoOiBjaGlsZE9yaWdpbmFsLndpZHRoICogZmFjdG9yLnRvLngsXG5cdFx0XHRcdFx0b3V0ZXJIZWlnaHQ6IGNoaWxkT3JpZ2luYWwuaGVpZ2h0ICogZmFjdG9yLnRvLnksXG5cdFx0XHRcdFx0b3V0ZXJXaWR0aDogY2hpbGRPcmlnaW5hbC53aWR0aCAqIGZhY3Rvci50by54XG5cdFx0XHRcdH07XG5cblx0XHRcdC8vIFZlcnRpY2FsIHByb3BzIHNjYWxpbmdcblx0XHRcdGlmICggZmFjdG9yLmZyb20ueSAhPT0gZmFjdG9yLnRvLnkgKSB7XG5cdFx0XHRcdGNoaWxkRnJvbSA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBjaGlsZCwgdlByb3BzLCBmYWN0b3IuZnJvbS55LCBjaGlsZEZyb20gKTtcblx0XHRcdFx0Y2hpbGRUbyA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBjaGlsZCwgdlByb3BzLCBmYWN0b3IudG8ueSwgY2hpbGRUbyApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBIb3Jpem9udGFsIHByb3BzIHNjYWxpbmdcblx0XHRcdGlmICggZmFjdG9yLmZyb20ueCAhPT0gZmFjdG9yLnRvLnggKSB7XG5cdFx0XHRcdGNoaWxkRnJvbSA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBjaGlsZCwgaFByb3BzLCBmYWN0b3IuZnJvbS54LCBjaGlsZEZyb20gKTtcblx0XHRcdFx0Y2hpbGRUbyA9ICQuZWZmZWN0cy5zZXRUcmFuc2l0aW9uKCBjaGlsZCwgaFByb3BzLCBmYWN0b3IudG8ueCwgY2hpbGRUbyApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHJlc3RvcmUgKSB7XG5cdFx0XHRcdCQuZWZmZWN0cy5zYXZlU3R5bGUoIGNoaWxkICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEFuaW1hdGUgY2hpbGRyZW5cblx0XHRcdGNoaWxkLmNzcyggY2hpbGRGcm9tICk7XG5cdFx0XHRjaGlsZC5hbmltYXRlKCBjaGlsZFRvLCBvcHRpb25zLmR1cmF0aW9uLCBvcHRpb25zLmVhc2luZywgZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0Ly8gUmVzdG9yZSBjaGlsZHJlblxuXHRcdFx0XHRpZiAoIHJlc3RvcmUgKSB7XG5cdFx0XHRcdFx0JC5lZmZlY3RzLnJlc3RvcmVTdHlsZSggY2hpbGQgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0fVxuXG5cdC8vIEFuaW1hdGVcblx0ZWxlbWVudC5hbmltYXRlKCB0bywge1xuXHRcdHF1ZXVlOiBmYWxzZSxcblx0XHRkdXJhdGlvbjogb3B0aW9ucy5kdXJhdGlvbixcblx0XHRlYXNpbmc6IG9wdGlvbnMuZWFzaW5nLFxuXHRcdGNvbXBsZXRlOiBmdW5jdGlvbigpIHtcblxuXHRcdFx0dmFyIG9mZnNldCA9IGVsZW1lbnQub2Zmc2V0KCk7XG5cblx0XHRcdGlmICggdG8ub3BhY2l0eSA9PT0gMCApIHtcblx0XHRcdFx0ZWxlbWVudC5jc3MoIFwib3BhY2l0eVwiLCBmcm9tLm9wYWNpdHkgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCAhcmVzdG9yZSApIHtcblx0XHRcdFx0ZWxlbWVudFxuXHRcdFx0XHRcdC5jc3MoIFwicG9zaXRpb25cIiwgcG9zaXRpb24gPT09IFwic3RhdGljXCIgPyBcInJlbGF0aXZlXCIgOiBwb3NpdGlvbiApXG5cdFx0XHRcdFx0Lm9mZnNldCggb2Zmc2V0ICk7XG5cblx0XHRcdFx0Ly8gTmVlZCB0byBzYXZlIHN0eWxlIGhlcmUgc28gdGhhdCBhdXRvbWF0aWMgc3R5bGUgcmVzdG9yYXRpb25cblx0XHRcdFx0Ly8gZG9lc24ndCByZXN0b3JlIHRvIHRoZSBvcmlnaW5hbCBzdHlsZXMgZnJvbSBiZWZvcmUgdGhlIGFuaW1hdGlvbi5cblx0XHRcdFx0JC5lZmZlY3RzLnNhdmVTdHlsZSggZWxlbWVudCApO1xuXHRcdFx0fVxuXG5cdFx0XHRkb25lKCk7XG5cdFx0fVxuXHR9ICk7XG5cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIFNjYWxlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBTY2FsZSBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBHcm93cyBvciBzaHJpbmtzIGFuIGVsZW1lbnQgYW5kIGl0cyBjb250ZW50LlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3NjYWxlLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdFNjYWxlID0gJC5lZmZlY3RzLmRlZmluZSggXCJzY2FsZVwiLCBmdW5jdGlvbiggb3B0aW9ucywgZG9uZSApIHtcblxuXHQvLyBDcmVhdGUgZWxlbWVudFxuXHR2YXIgZWwgPSAkKCB0aGlzICksXG5cdFx0bW9kZSA9IG9wdGlvbnMubW9kZSxcblx0XHRwZXJjZW50ID0gcGFyc2VJbnQoIG9wdGlvbnMucGVyY2VudCwgMTAgKSB8fFxuXHRcdFx0KCBwYXJzZUludCggb3B0aW9ucy5wZXJjZW50LCAxMCApID09PSAwID8gMCA6ICggbW9kZSAhPT0gXCJlZmZlY3RcIiA/IDAgOiAxMDAgKSApLFxuXG5cdFx0bmV3T3B0aW9ucyA9ICQuZXh0ZW5kKCB0cnVlLCB7XG5cdFx0XHRmcm9tOiAkLmVmZmVjdHMuc2NhbGVkRGltZW5zaW9ucyggZWwgKSxcblx0XHRcdHRvOiAkLmVmZmVjdHMuc2NhbGVkRGltZW5zaW9ucyggZWwsIHBlcmNlbnQsIG9wdGlvbnMuZGlyZWN0aW9uIHx8IFwiYm90aFwiICksXG5cdFx0XHRvcmlnaW46IG9wdGlvbnMub3JpZ2luIHx8IFsgXCJtaWRkbGVcIiwgXCJjZW50ZXJcIiBdXG5cdFx0fSwgb3B0aW9ucyApO1xuXG5cdC8vIEZhZGUgb3B0aW9uIHRvIHN1cHBvcnQgcHVmZlxuXHRpZiAoIG9wdGlvbnMuZmFkZSApIHtcblx0XHRuZXdPcHRpb25zLmZyb20ub3BhY2l0eSA9IDE7XG5cdFx0bmV3T3B0aW9ucy50by5vcGFjaXR5ID0gMDtcblx0fVxuXG5cdCQuZWZmZWN0cy5lZmZlY3Quc2l6ZS5jYWxsKCB0aGlzLCBuZXdPcHRpb25zLCBkb25lICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBQdWZmIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBQdWZmIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IENyZWF0ZXMgYSBwdWZmIGVmZmVjdCBieSBzY2FsaW5nIHRoZSBlbGVtZW50IHVwIGFuZCBoaWRpbmcgaXQgYXQgdGhlIHNhbWUgdGltZS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9wdWZmLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdFB1ZmYgPSAkLmVmZmVjdHMuZGVmaW5lKCBcInB1ZmZcIiwgXCJoaWRlXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHR2YXIgbmV3T3B0aW9ucyA9ICQuZXh0ZW5kKCB0cnVlLCB7fSwgb3B0aW9ucywge1xuXHRcdGZhZGU6IHRydWUsXG5cdFx0cGVyY2VudDogcGFyc2VJbnQoIG9wdGlvbnMucGVyY2VudCwgMTAgKSB8fCAxNTBcblx0fSApO1xuXG5cdCQuZWZmZWN0cy5lZmZlY3Quc2NhbGUuY2FsbCggdGhpcywgbmV3T3B0aW9ucywgZG9uZSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgUHVsc2F0ZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogUHVsc2F0ZSBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBQdWxzYXRlcyBhbiBlbGVtZW50IG4gdGltZXMgYnkgY2hhbmdpbmcgdGhlIG9wYWNpdHkgdG8gemVybyBhbmQgYmFjay5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9wdWxzYXRlLWVmZmVjdC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9lZmZlY3QvXG5cblxuXG52YXIgZWZmZWN0c0VmZmVjdFB1bHNhdGUgPSAkLmVmZmVjdHMuZGVmaW5lKCBcInB1bHNhdGVcIiwgXCJzaG93XCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHR2YXIgZWxlbWVudCA9ICQoIHRoaXMgKSxcblx0XHRtb2RlID0gb3B0aW9ucy5tb2RlLFxuXHRcdHNob3cgPSBtb2RlID09PSBcInNob3dcIixcblx0XHRoaWRlID0gbW9kZSA9PT0gXCJoaWRlXCIsXG5cdFx0c2hvd2hpZGUgPSBzaG93IHx8IGhpZGUsXG5cblx0XHQvLyBTaG93aW5nIG9yIGhpZGluZyBsZWF2ZXMgb2ZmIHRoZSBcImxhc3RcIiBhbmltYXRpb25cblx0XHRhbmltcyA9ICggKCBvcHRpb25zLnRpbWVzIHx8IDUgKSAqIDIgKSArICggc2hvd2hpZGUgPyAxIDogMCApLFxuXHRcdGR1cmF0aW9uID0gb3B0aW9ucy5kdXJhdGlvbiAvIGFuaW1zLFxuXHRcdGFuaW1hdGVUbyA9IDAsXG5cdFx0aSA9IDEsXG5cdFx0cXVldWVsZW4gPSBlbGVtZW50LnF1ZXVlKCkubGVuZ3RoO1xuXG5cdGlmICggc2hvdyB8fCAhZWxlbWVudC5pcyggXCI6dmlzaWJsZVwiICkgKSB7XG5cdFx0ZWxlbWVudC5jc3MoIFwib3BhY2l0eVwiLCAwICkuc2hvdygpO1xuXHRcdGFuaW1hdGVUbyA9IDE7XG5cdH1cblxuXHQvLyBBbmltcyAtIDEgb3BhY2l0eSBcInRvZ2dsZXNcIlxuXHRmb3IgKCA7IGkgPCBhbmltczsgaSsrICkge1xuXHRcdGVsZW1lbnQuYW5pbWF0ZSggeyBvcGFjaXR5OiBhbmltYXRlVG8gfSwgZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nICk7XG5cdFx0YW5pbWF0ZVRvID0gMSAtIGFuaW1hdGVUbztcblx0fVxuXG5cdGVsZW1lbnQuYW5pbWF0ZSggeyBvcGFjaXR5OiBhbmltYXRlVG8gfSwgZHVyYXRpb24sIG9wdGlvbnMuZWFzaW5nICk7XG5cblx0ZWxlbWVudC5xdWV1ZSggZG9uZSApO1xuXG5cdCQuZWZmZWN0cy51bnNoaWZ0KCBlbGVtZW50LCBxdWV1ZWxlbiwgYW5pbXMgKyAxICk7XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgRWZmZWN0cyBTaGFrZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogU2hha2UgRWZmZWN0XG4vLz4+Z3JvdXA6IEVmZmVjdHNcbi8vPj5kZXNjcmlwdGlvbjogU2hha2VzIGFuIGVsZW1lbnQgaG9yaXpvbnRhbGx5IG9yIHZlcnRpY2FsbHkgbiB0aW1lcy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zaGFrZS1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RTaGFrZSA9ICQuZWZmZWN0cy5kZWZpbmUoIFwic2hha2VcIiwgZnVuY3Rpb24oIG9wdGlvbnMsIGRvbmUgKSB7XG5cblx0dmFyIGkgPSAxLFxuXHRcdGVsZW1lbnQgPSAkKCB0aGlzICksXG5cdFx0ZGlyZWN0aW9uID0gb3B0aW9ucy5kaXJlY3Rpb24gfHwgXCJsZWZ0XCIsXG5cdFx0ZGlzdGFuY2UgPSBvcHRpb25zLmRpc3RhbmNlIHx8IDIwLFxuXHRcdHRpbWVzID0gb3B0aW9ucy50aW1lcyB8fCAzLFxuXHRcdGFuaW1zID0gdGltZXMgKiAyICsgMSxcblx0XHRzcGVlZCA9IE1hdGgucm91bmQoIG9wdGlvbnMuZHVyYXRpb24gLyBhbmltcyApLFxuXHRcdHJlZiA9ICggZGlyZWN0aW9uID09PSBcInVwXCIgfHwgZGlyZWN0aW9uID09PSBcImRvd25cIiApID8gXCJ0b3BcIiA6IFwibGVmdFwiLFxuXHRcdHBvc2l0aXZlTW90aW9uID0gKCBkaXJlY3Rpb24gPT09IFwidXBcIiB8fCBkaXJlY3Rpb24gPT09IFwibGVmdFwiICksXG5cdFx0YW5pbWF0aW9uID0ge30sXG5cdFx0YW5pbWF0aW9uMSA9IHt9LFxuXHRcdGFuaW1hdGlvbjIgPSB7fSxcblxuXHRcdHF1ZXVlbGVuID0gZWxlbWVudC5xdWV1ZSgpLmxlbmd0aDtcblxuXHQkLmVmZmVjdHMuY3JlYXRlUGxhY2Vob2xkZXIoIGVsZW1lbnQgKTtcblxuXHQvLyBBbmltYXRpb25cblx0YW5pbWF0aW9uWyByZWYgXSA9ICggcG9zaXRpdmVNb3Rpb24gPyBcIi09XCIgOiBcIis9XCIgKSArIGRpc3RhbmNlO1xuXHRhbmltYXRpb24xWyByZWYgXSA9ICggcG9zaXRpdmVNb3Rpb24gPyBcIis9XCIgOiBcIi09XCIgKSArIGRpc3RhbmNlICogMjtcblx0YW5pbWF0aW9uMlsgcmVmIF0gPSAoIHBvc2l0aXZlTW90aW9uID8gXCItPVwiIDogXCIrPVwiICkgKyBkaXN0YW5jZSAqIDI7XG5cblx0Ly8gQW5pbWF0ZVxuXHRlbGVtZW50LmFuaW1hdGUoIGFuaW1hdGlvbiwgc3BlZWQsIG9wdGlvbnMuZWFzaW5nICk7XG5cblx0Ly8gU2hha2VzXG5cdGZvciAoIDsgaSA8IHRpbWVzOyBpKysgKSB7XG5cdFx0ZWxlbWVudFxuXHRcdFx0LmFuaW1hdGUoIGFuaW1hdGlvbjEsIHNwZWVkLCBvcHRpb25zLmVhc2luZyApXG5cdFx0XHQuYW5pbWF0ZSggYW5pbWF0aW9uMiwgc3BlZWQsIG9wdGlvbnMuZWFzaW5nICk7XG5cdH1cblxuXHRlbGVtZW50XG5cdFx0LmFuaW1hdGUoIGFuaW1hdGlvbjEsIHNwZWVkLCBvcHRpb25zLmVhc2luZyApXG5cdFx0LmFuaW1hdGUoIGFuaW1hdGlvbiwgc3BlZWQgLyAyLCBvcHRpb25zLmVhc2luZyApXG5cdFx0LnF1ZXVlKCBkb25lICk7XG5cblx0JC5lZmZlY3RzLnVuc2hpZnQoIGVsZW1lbnQsIHF1ZXVlbGVuLCBhbmltcyArIDEgKTtcbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBFZmZlY3RzIFNsaWRlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBTbGlkZSBFZmZlY3Rcbi8vPj5ncm91cDogRWZmZWN0c1xuLy8+PmRlc2NyaXB0aW9uOiBTbGlkZXMgYW4gZWxlbWVudCBpbiBhbmQgb3V0IG9mIHRoZSB2aWV3cG9ydC5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zbGlkZS1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdHNFZmZlY3RTbGlkZSA9ICQuZWZmZWN0cy5kZWZpbmUoIFwic2xpZGVcIiwgXCJzaG93XCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHR2YXIgc3RhcnRDbGlwLCBzdGFydFJlZixcblx0XHRlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdG1hcCA9IHtcblx0XHRcdHVwOiBbIFwiYm90dG9tXCIsIFwidG9wXCIgXSxcblx0XHRcdGRvd246IFsgXCJ0b3BcIiwgXCJib3R0b21cIiBdLFxuXHRcdFx0bGVmdDogWyBcInJpZ2h0XCIsIFwibGVmdFwiIF0sXG5cdFx0XHRyaWdodDogWyBcImxlZnRcIiwgXCJyaWdodFwiIF1cblx0XHR9LFxuXHRcdG1vZGUgPSBvcHRpb25zLm1vZGUsXG5cdFx0ZGlyZWN0aW9uID0gb3B0aW9ucy5kaXJlY3Rpb24gfHwgXCJsZWZ0XCIsXG5cdFx0cmVmID0gKCBkaXJlY3Rpb24gPT09IFwidXBcIiB8fCBkaXJlY3Rpb24gPT09IFwiZG93blwiICkgPyBcInRvcFwiIDogXCJsZWZ0XCIsXG5cdFx0cG9zaXRpdmVNb3Rpb24gPSAoIGRpcmVjdGlvbiA9PT0gXCJ1cFwiIHx8IGRpcmVjdGlvbiA9PT0gXCJsZWZ0XCIgKSxcblx0XHRkaXN0YW5jZSA9IG9wdGlvbnMuZGlzdGFuY2UgfHxcblx0XHRcdGVsZW1lbnRbIHJlZiA9PT0gXCJ0b3BcIiA/IFwib3V0ZXJIZWlnaHRcIiA6IFwib3V0ZXJXaWR0aFwiIF0oIHRydWUgKSxcblx0XHRhbmltYXRpb24gPSB7fTtcblxuXHQkLmVmZmVjdHMuY3JlYXRlUGxhY2Vob2xkZXIoIGVsZW1lbnQgKTtcblxuXHRzdGFydENsaXAgPSBlbGVtZW50LmNzc0NsaXAoKTtcblx0c3RhcnRSZWYgPSBlbGVtZW50LnBvc2l0aW9uKClbIHJlZiBdO1xuXG5cdC8vIERlZmluZSBoaWRlIGFuaW1hdGlvblxuXHRhbmltYXRpb25bIHJlZiBdID0gKCBwb3NpdGl2ZU1vdGlvbiA/IC0xIDogMSApICogZGlzdGFuY2UgKyBzdGFydFJlZjtcblx0YW5pbWF0aW9uLmNsaXAgPSBlbGVtZW50LmNzc0NsaXAoKTtcblx0YW5pbWF0aW9uLmNsaXBbIG1hcFsgZGlyZWN0aW9uIF1bIDEgXSBdID0gYW5pbWF0aW9uLmNsaXBbIG1hcFsgZGlyZWN0aW9uIF1bIDAgXSBdO1xuXG5cdC8vIFJldmVyc2UgdGhlIGFuaW1hdGlvbiBpZiB3ZSdyZSBzaG93aW5nXG5cdGlmICggbW9kZSA9PT0gXCJzaG93XCIgKSB7XG5cdFx0ZWxlbWVudC5jc3NDbGlwKCBhbmltYXRpb24uY2xpcCApO1xuXHRcdGVsZW1lbnQuY3NzKCByZWYsIGFuaW1hdGlvblsgcmVmIF0gKTtcblx0XHRhbmltYXRpb24uY2xpcCA9IHN0YXJ0Q2xpcDtcblx0XHRhbmltYXRpb25bIHJlZiBdID0gc3RhcnRSZWY7XG5cdH1cblxuXHQvLyBBY3R1YWxseSBhbmltYXRlXG5cdGVsZW1lbnQuYW5pbWF0ZSggYW5pbWF0aW9uLCB7XG5cdFx0cXVldWU6IGZhbHNlLFxuXHRcdGR1cmF0aW9uOiBvcHRpb25zLmR1cmF0aW9uLFxuXHRcdGVhc2luZzogb3B0aW9ucy5lYXNpbmcsXG5cdFx0Y29tcGxldGU6IGRvbmVcblx0fSApO1xufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEVmZmVjdHMgVHJhbnNmZXIgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IFRyYW5zZmVyIEVmZmVjdFxuLy8+Pmdyb3VwOiBFZmZlY3RzXG4vLz4+ZGVzY3JpcHRpb246IERpc3BsYXlzIGEgdHJhbnNmZXIgZWZmZWN0IGZyb20gb25lIGVsZW1lbnQgdG8gYW5vdGhlci5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS90cmFuc2Zlci1lZmZlY3QvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZWZmZWN0L1xuXG5cblxudmFyIGVmZmVjdDtcbmlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICkge1xuXHRlZmZlY3QgPSAkLmVmZmVjdHMuZGVmaW5lKCBcInRyYW5zZmVyXCIsIGZ1bmN0aW9uKCBvcHRpb25zLCBkb25lICkge1xuXHRcdCQoIHRoaXMgKS50cmFuc2Zlciggb3B0aW9ucywgZG9uZSApO1xuXHR9ICk7XG59XG52YXIgZWZmZWN0c0VmZmVjdFRyYW5zZmVyID0gZWZmZWN0O1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEZvY3VzYWJsZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogOmZvY3VzYWJsZSBTZWxlY3RvclxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IFNlbGVjdHMgZWxlbWVudHMgd2hpY2ggY2FuIGJlIGZvY3VzZWQuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZm9jdXNhYmxlLXNlbGVjdG9yL1xuXG5cblxuLy8gU2VsZWN0b3JzXG4kLnVpLmZvY3VzYWJsZSA9IGZ1bmN0aW9uKCBlbGVtZW50LCBoYXNUYWJpbmRleCApIHtcblx0dmFyIG1hcCwgbWFwTmFtZSwgaW1nLCBmb2N1c2FibGVJZlZpc2libGUsIGZpZWxkc2V0LFxuXHRcdG5vZGVOYW1lID0gZWxlbWVudC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpO1xuXG5cdGlmICggXCJhcmVhXCIgPT09IG5vZGVOYW1lICkge1xuXHRcdG1hcCA9IGVsZW1lbnQucGFyZW50Tm9kZTtcblx0XHRtYXBOYW1lID0gbWFwLm5hbWU7XG5cdFx0aWYgKCAhZWxlbWVudC5ocmVmIHx8ICFtYXBOYW1lIHx8IG1hcC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpICE9PSBcIm1hcFwiICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0XHRpbWcgPSAkKCBcImltZ1t1c2VtYXA9JyNcIiArIG1hcE5hbWUgKyBcIiddXCIgKTtcblx0XHRyZXR1cm4gaW1nLmxlbmd0aCA+IDAgJiYgaW1nLmlzKCBcIjp2aXNpYmxlXCIgKTtcblx0fVxuXG5cdGlmICggL14oaW5wdXR8c2VsZWN0fHRleHRhcmVhfGJ1dHRvbnxvYmplY3QpJC8udGVzdCggbm9kZU5hbWUgKSApIHtcblx0XHRmb2N1c2FibGVJZlZpc2libGUgPSAhZWxlbWVudC5kaXNhYmxlZDtcblxuXHRcdGlmICggZm9jdXNhYmxlSWZWaXNpYmxlICkge1xuXG5cdFx0XHQvLyBGb3JtIGNvbnRyb2xzIHdpdGhpbiBhIGRpc2FibGVkIGZpZWxkc2V0IGFyZSBkaXNhYmxlZC5cblx0XHRcdC8vIEhvd2V2ZXIsIGNvbnRyb2xzIHdpdGhpbiB0aGUgZmllbGRzZXQncyBsZWdlbmQgZG8gbm90IGdldCBkaXNhYmxlZC5cblx0XHRcdC8vIFNpbmNlIGNvbnRyb2xzIGdlbmVyYWxseSBhcmVuJ3QgcGxhY2VkIGluc2lkZSBsZWdlbmRzLCB3ZSBza2lwXG5cdFx0XHQvLyB0aGlzIHBvcnRpb24gb2YgdGhlIGNoZWNrLlxuXHRcdFx0ZmllbGRzZXQgPSAkKCBlbGVtZW50ICkuY2xvc2VzdCggXCJmaWVsZHNldFwiIClbIDAgXTtcblx0XHRcdGlmICggZmllbGRzZXQgKSB7XG5cdFx0XHRcdGZvY3VzYWJsZUlmVmlzaWJsZSA9ICFmaWVsZHNldC5kaXNhYmxlZDtcblx0XHRcdH1cblx0XHR9XG5cdH0gZWxzZSBpZiAoIFwiYVwiID09PSBub2RlTmFtZSApIHtcblx0XHRmb2N1c2FibGVJZlZpc2libGUgPSBlbGVtZW50LmhyZWYgfHwgaGFzVGFiaW5kZXg7XG5cdH0gZWxzZSB7XG5cdFx0Zm9jdXNhYmxlSWZWaXNpYmxlID0gaGFzVGFiaW5kZXg7XG5cdH1cblxuXHRyZXR1cm4gZm9jdXNhYmxlSWZWaXNpYmxlICYmICQoIGVsZW1lbnQgKS5pcyggXCI6dmlzaWJsZVwiICkgJiYgdmlzaWJsZSggJCggZWxlbWVudCApICk7XG59O1xuXG4vLyBTdXBwb3J0OiBJRSA4IG9ubHlcbi8vIElFIDggZG9lc24ndCByZXNvbHZlIGluaGVyaXQgdG8gdmlzaWJsZS9oaWRkZW4gZm9yIGNvbXB1dGVkIHZhbHVlc1xuZnVuY3Rpb24gdmlzaWJsZSggZWxlbWVudCApIHtcblx0dmFyIHZpc2liaWxpdHkgPSBlbGVtZW50LmNzcyggXCJ2aXNpYmlsaXR5XCIgKTtcblx0d2hpbGUgKCB2aXNpYmlsaXR5ID09PSBcImluaGVyaXRcIiApIHtcblx0XHRlbGVtZW50ID0gZWxlbWVudC5wYXJlbnQoKTtcblx0XHR2aXNpYmlsaXR5ID0gZWxlbWVudC5jc3MoIFwidmlzaWJpbGl0eVwiICk7XG5cdH1cblx0cmV0dXJuIHZpc2liaWxpdHkgIT09IFwiaGlkZGVuXCI7XG59XG5cbiQuZXh0ZW5kKCAkLmV4cHJbIFwiOlwiIF0sIHtcblx0Zm9jdXNhYmxlOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHRyZXR1cm4gJC51aS5mb2N1c2FibGUoIGVsZW1lbnQsICQuYXR0ciggZWxlbWVudCwgXCJ0YWJpbmRleFwiICkgIT0gbnVsbCApO1xuXHR9XG59ICk7XG5cbnZhciBmb2N1c2FibGUgPSAkLnVpLmZvY3VzYWJsZTtcblxuXG5cblxuLy8gU3VwcG9ydDogSUU4IE9ubHlcbi8vIElFOCBkb2VzIG5vdCBzdXBwb3J0IHRoZSBmb3JtIGF0dHJpYnV0ZSBhbmQgd2hlbiBpdCBpcyBzdXBwbGllZC4gSXQgb3ZlcndyaXRlcyB0aGUgZm9ybSBwcm9wXG4vLyB3aXRoIGEgc3RyaW5nLCBzbyB3ZSBuZWVkIHRvIGZpbmQgdGhlIHByb3BlciBmb3JtLlxudmFyIGZvcm0gPSAkLmZuLmZvcm0gPSBmdW5jdGlvbigpIHtcblx0cmV0dXJuIHR5cGVvZiB0aGlzWyAwIF0uZm9ybSA9PT0gXCJzdHJpbmdcIiA/IHRoaXMuY2xvc2VzdCggXCJmb3JtXCIgKSA6ICQoIHRoaXNbIDAgXS5mb3JtICk7XG59O1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEZvcm0gUmVzZXQgTWl4aW4gMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IEZvcm0gUmVzZXQgTWl4aW5cbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBSZWZyZXNoIGlucHV0IHdpZGdldHMgd2hlbiB0aGVpciBmb3JtIGlzIHJlc2V0XG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vZm9ybS1yZXNldC1taXhpbi9cblxuXG5cbnZhciBmb3JtUmVzZXRNaXhpbiA9ICQudWkuZm9ybVJlc2V0TWl4aW4gPSB7XG5cdF9mb3JtUmVzZXRIYW5kbGVyOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZm9ybSA9ICQoIHRoaXMgKTtcblxuXHRcdC8vIFdhaXQgZm9yIHRoZSBmb3JtIHJlc2V0IHRvIGFjdHVhbGx5IGhhcHBlbiBiZWZvcmUgcmVmcmVzaGluZ1xuXHRcdHNldFRpbWVvdXQoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGluc3RhbmNlcyA9IGZvcm0uZGF0YSggXCJ1aS1mb3JtLXJlc2V0LWluc3RhbmNlc1wiICk7XG5cdFx0XHQkLmVhY2goIGluc3RhbmNlcywgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMucmVmcmVzaCgpO1xuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0fSxcblxuXHRfYmluZEZvcm1SZXNldEhhbmRsZXI6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuZm9ybSA9IHRoaXMuZWxlbWVudC5mb3JtKCk7XG5cdFx0aWYgKCAhdGhpcy5mb3JtLmxlbmd0aCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgaW5zdGFuY2VzID0gdGhpcy5mb3JtLmRhdGEoIFwidWktZm9ybS1yZXNldC1pbnN0YW5jZXNcIiApIHx8IFtdO1xuXHRcdGlmICggIWluc3RhbmNlcy5sZW5ndGggKSB7XG5cblx0XHRcdC8vIFdlIGRvbid0IHVzZSBfb24oKSBoZXJlIGJlY2F1c2Ugd2UgdXNlIGEgc2luZ2xlIGV2ZW50IGhhbmRsZXIgcGVyIGZvcm1cblx0XHRcdHRoaXMuZm9ybS5vbiggXCJyZXNldC51aS1mb3JtLXJlc2V0XCIsIHRoaXMuX2Zvcm1SZXNldEhhbmRsZXIgKTtcblx0XHR9XG5cdFx0aW5zdGFuY2VzLnB1c2goIHRoaXMgKTtcblx0XHR0aGlzLmZvcm0uZGF0YSggXCJ1aS1mb3JtLXJlc2V0LWluc3RhbmNlc1wiLCBpbnN0YW5jZXMgKTtcblx0fSxcblxuXHRfdW5iaW5kRm9ybVJlc2V0SGFuZGxlcjogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAhdGhpcy5mb3JtLmxlbmd0aCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgaW5zdGFuY2VzID0gdGhpcy5mb3JtLmRhdGEoIFwidWktZm9ybS1yZXNldC1pbnN0YW5jZXNcIiApO1xuXHRcdGluc3RhbmNlcy5zcGxpY2UoICQuaW5BcnJheSggdGhpcywgaW5zdGFuY2VzICksIDEgKTtcblx0XHRpZiAoIGluc3RhbmNlcy5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLmZvcm0uZGF0YSggXCJ1aS1mb3JtLXJlc2V0LWluc3RhbmNlc1wiLCBpbnN0YW5jZXMgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5mb3JtXG5cdFx0XHRcdC5yZW1vdmVEYXRhKCBcInVpLWZvcm0tcmVzZXQtaW5zdGFuY2VzXCIgKVxuXHRcdFx0XHQub2ZmKCBcInJlc2V0LnVpLWZvcm0tcmVzZXRcIiApO1xuXHRcdH1cblx0fVxufTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBTdXBwb3J0IGZvciBqUXVlcnkgY29yZSAxLjcueCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICpcbiAqL1xuXG4vLz4+bGFiZWw6IGpRdWVyeSAxLjcgU3VwcG9ydFxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IFN1cHBvcnQgdmVyc2lvbiAxLjcueCBvZiBqUXVlcnkgY29yZVxuXG5cblxuLy8gU3VwcG9ydDogalF1ZXJ5IDEuNyBvbmx5XG4vLyBOb3QgYSBncmVhdCB3YXkgdG8gY2hlY2sgdmVyc2lvbnMsIGJ1dCBzaW5jZSB3ZSBvbmx5IHN1cHBvcnQgMS43KyBhbmQgb25seVxuLy8gbmVlZCB0byBkZXRlY3QgPDEuOCwgdGhpcyBpcyBhIHNpbXBsZSBjaGVjayB0aGF0IHNob3VsZCBzdWZmaWNlLiBDaGVja2luZ1xuLy8gZm9yIFwiMS43LlwiIHdvdWxkIGJlIGEgYml0IHNhZmVyLCBidXQgdGhlIHZlcnNpb24gc3RyaW5nIGlzIDEuNywgbm90IDEuNy4wXG4vLyBhbmQgd2UnbGwgbmV2ZXIgcmVhY2ggMS43MC4wIChpZiB3ZSBkbywgd2UgY2VydGFpbmx5IHdvbid0IGJlIHN1cHBvcnRpbmdcbi8vIDEuNyBhbnltb3JlKS4gU2VlICMxMTE5NyBmb3Igd2h5IHdlJ3JlIG5vdCB1c2luZyBmZWF0dXJlIGRldGVjdGlvbi5cbmlmICggJC5mbi5qcXVlcnkuc3Vic3RyaW5nKCAwLCAzICkgPT09IFwiMS43XCIgKSB7XG5cblx0Ly8gU2V0dGVycyBmb3IgLmlubmVyV2lkdGgoKSwgLmlubmVySGVpZ2h0KCksIC5vdXRlcldpZHRoKCksIC5vdXRlckhlaWdodCgpXG5cdC8vIFVubGlrZSBqUXVlcnkgQ29yZSAxLjgrLCB0aGVzZSBvbmx5IHN1cHBvcnQgbnVtZXJpYyB2YWx1ZXMgdG8gc2V0IHRoZVxuXHQvLyBkaW1lbnNpb25zIGluIHBpeGVsc1xuXHQkLmVhY2goIFsgXCJXaWR0aFwiLCBcIkhlaWdodFwiIF0sIGZ1bmN0aW9uKCBpLCBuYW1lICkge1xuXHRcdHZhciBzaWRlID0gbmFtZSA9PT0gXCJXaWR0aFwiID8gWyBcIkxlZnRcIiwgXCJSaWdodFwiIF0gOiBbIFwiVG9wXCIsIFwiQm90dG9tXCIgXSxcblx0XHRcdHR5cGUgPSBuYW1lLnRvTG93ZXJDYXNlKCksXG5cdFx0XHRvcmlnID0ge1xuXHRcdFx0XHRpbm5lcldpZHRoOiAkLmZuLmlubmVyV2lkdGgsXG5cdFx0XHRcdGlubmVySGVpZ2h0OiAkLmZuLmlubmVySGVpZ2h0LFxuXHRcdFx0XHRvdXRlcldpZHRoOiAkLmZuLm91dGVyV2lkdGgsXG5cdFx0XHRcdG91dGVySGVpZ2h0OiAkLmZuLm91dGVySGVpZ2h0XG5cdFx0XHR9O1xuXG5cdFx0ZnVuY3Rpb24gcmVkdWNlKCBlbGVtLCBzaXplLCBib3JkZXIsIG1hcmdpbiApIHtcblx0XHRcdCQuZWFjaCggc2lkZSwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHNpemUgLT0gcGFyc2VGbG9hdCggJC5jc3MoIGVsZW0sIFwicGFkZGluZ1wiICsgdGhpcyApICkgfHwgMDtcblx0XHRcdFx0aWYgKCBib3JkZXIgKSB7XG5cdFx0XHRcdFx0c2l6ZSAtPSBwYXJzZUZsb2F0KCAkLmNzcyggZWxlbSwgXCJib3JkZXJcIiArIHRoaXMgKyBcIldpZHRoXCIgKSApIHx8IDA7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBtYXJnaW4gKSB7XG5cdFx0XHRcdFx0c2l6ZSAtPSBwYXJzZUZsb2F0KCAkLmNzcyggZWxlbSwgXCJtYXJnaW5cIiArIHRoaXMgKSApIHx8IDA7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHRcdHJldHVybiBzaXplO1xuXHRcdH1cblxuXHRcdCQuZm5bIFwiaW5uZXJcIiArIG5hbWUgXSA9IGZ1bmN0aW9uKCBzaXplICkge1xuXHRcdFx0aWYgKCBzaXplID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdHJldHVybiBvcmlnWyBcImlubmVyXCIgKyBuYW1lIF0uY2FsbCggdGhpcyApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0JCggdGhpcyApLmNzcyggdHlwZSwgcmVkdWNlKCB0aGlzLCBzaXplICkgKyBcInB4XCIgKTtcblx0XHRcdH0gKTtcblx0XHR9O1xuXG5cdFx0JC5mblsgXCJvdXRlclwiICsgbmFtZSBdID0gZnVuY3Rpb24oIHNpemUsIG1hcmdpbiApIHtcblx0XHRcdGlmICggdHlwZW9mIHNpemUgIT09IFwibnVtYmVyXCIgKSB7XG5cdFx0XHRcdHJldHVybiBvcmlnWyBcIm91dGVyXCIgKyBuYW1lIF0uY2FsbCggdGhpcywgc2l6ZSApO1xuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0JCggdGhpcyApLmNzcyggdHlwZSwgcmVkdWNlKCB0aGlzLCBzaXplLCB0cnVlLCBtYXJnaW4gKSArIFwicHhcIiApO1xuXHRcdFx0fSApO1xuXHRcdH07XG5cdH0gKTtcblxuXHQkLmZuLmFkZEJhY2sgPSBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0cmV0dXJuIHRoaXMuYWRkKCBzZWxlY3RvciA9PSBudWxsID9cblx0XHRcdHRoaXMucHJldk9iamVjdCA6IHRoaXMucHJldk9iamVjdC5maWx0ZXIoIHNlbGVjdG9yIClcblx0XHQpO1xuXHR9O1xufVxuXG47XG4vKiFcbiAqIGpRdWVyeSBVSSBLZXljb2RlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBLZXljb2RlXG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogUHJvdmlkZSBrZXljb2RlcyBhcyBrZXluYW1lc1xuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2pRdWVyeS51aS5rZXlDb2RlL1xuXG5cbnZhciBrZXljb2RlID0gJC51aS5rZXlDb2RlID0ge1xuXHRCQUNLU1BBQ0U6IDgsXG5cdENPTU1BOiAxODgsXG5cdERFTEVURTogNDYsXG5cdERPV046IDQwLFxuXHRFTkQ6IDM1LFxuXHRFTlRFUjogMTMsXG5cdEVTQ0FQRTogMjcsXG5cdEhPTUU6IDM2LFxuXHRMRUZUOiAzNyxcblx0UEFHRV9ET1dOOiAzNCxcblx0UEFHRV9VUDogMzMsXG5cdFBFUklPRDogMTkwLFxuXHRSSUdIVDogMzksXG5cdFNQQUNFOiAzMixcblx0VEFCOiA5LFxuXHRVUDogMzhcbn07XG5cblxuXG5cbi8vIEludGVybmFsIHVzZSBvbmx5XG52YXIgZXNjYXBlU2VsZWN0b3IgPSAkLnVpLmVzY2FwZVNlbGVjdG9yID0gKCBmdW5jdGlvbigpIHtcblx0dmFyIHNlbGVjdG9yRXNjYXBlID0gLyhbIVwiIyQlJicoKSorLC4vOjs8PT4/QFtcXF1eYHt8fX5dKS9nO1xuXHRyZXR1cm4gZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiBzZWxlY3Rvci5yZXBsYWNlKCBzZWxlY3RvckVzY2FwZSwgXCJcXFxcJDFcIiApO1xuXHR9O1xufSApKCk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgTGFiZWxzIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBsYWJlbHNcbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBGaW5kIGFsbCB0aGUgbGFiZWxzIGFzc29jaWF0ZWQgd2l0aCBhIGdpdmVuIGlucHV0XG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vbGFiZWxzL1xuXG5cblxudmFyIGxhYmVscyA9ICQuZm4ubGFiZWxzID0gZnVuY3Rpb24oKSB7XG5cdHZhciBhbmNlc3Rvciwgc2VsZWN0b3IsIGlkLCBsYWJlbHMsIGFuY2VzdG9ycztcblxuXHQvLyBDaGVjayBjb250cm9sLmxhYmVscyBmaXJzdFxuXHRpZiAoIHRoaXNbIDAgXS5sYWJlbHMgJiYgdGhpc1sgMCBdLmxhYmVscy5sZW5ndGggKSB7XG5cdFx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKCB0aGlzWyAwIF0ubGFiZWxzICk7XG5cdH1cblxuXHQvLyBTdXBwb3J0OiBJRSA8PSAxMSwgRkYgPD0gMzcsIEFuZHJvaWQgPD0gMi4zIG9ubHlcblx0Ly8gQWJvdmUgYnJvd3NlcnMgZG8gbm90IHN1cHBvcnQgY29udHJvbC5sYWJlbHMuIEV2ZXJ5dGhpbmcgYmVsb3cgaXMgdG8gc3VwcG9ydCB0aGVtXG5cdC8vIGFzIHdlbGwgYXMgZG9jdW1lbnQgZnJhZ21lbnRzLiBjb250cm9sLmxhYmVscyBkb2VzIG5vdCB3b3JrIG9uIGRvY3VtZW50IGZyYWdtZW50c1xuXHRsYWJlbHMgPSB0aGlzLmVxKCAwICkucGFyZW50cyggXCJsYWJlbFwiICk7XG5cblx0Ly8gTG9vayBmb3IgdGhlIGxhYmVsIGJhc2VkIG9uIHRoZSBpZFxuXHRpZCA9IHRoaXMuYXR0ciggXCJpZFwiICk7XG5cdGlmICggaWQgKSB7XG5cblx0XHQvLyBXZSBkb24ndCBzZWFyY2ggYWdhaW5zdCB0aGUgZG9jdW1lbnQgaW4gY2FzZSB0aGUgZWxlbWVudFxuXHRcdC8vIGlzIGRpc2Nvbm5lY3RlZCBmcm9tIHRoZSBET01cblx0XHRhbmNlc3RvciA9IHRoaXMuZXEoIDAgKS5wYXJlbnRzKCkubGFzdCgpO1xuXG5cdFx0Ly8gR2V0IGEgZnVsbCBzZXQgb2YgdG9wIGxldmVsIGFuY2VzdG9yc1xuXHRcdGFuY2VzdG9ycyA9IGFuY2VzdG9yLmFkZCggYW5jZXN0b3IubGVuZ3RoID8gYW5jZXN0b3Iuc2libGluZ3MoKSA6IHRoaXMuc2libGluZ3MoKSApO1xuXG5cdFx0Ly8gQ3JlYXRlIGEgc2VsZWN0b3IgZm9yIHRoZSBsYWJlbCBiYXNlZCBvbiB0aGUgaWRcblx0XHRzZWxlY3RvciA9IFwibGFiZWxbZm9yPSdcIiArICQudWkuZXNjYXBlU2VsZWN0b3IoIGlkICkgKyBcIiddXCI7XG5cblx0XHRsYWJlbHMgPSBsYWJlbHMuYWRkKCBhbmNlc3RvcnMuZmluZCggc2VsZWN0b3IgKS5hZGRCYWNrKCBzZWxlY3RvciApICk7XG5cblx0fVxuXG5cdC8vIFJldHVybiB3aGF0ZXZlciB3ZSBoYXZlIGZvdW5kIGZvciBsYWJlbHNcblx0cmV0dXJuIHRoaXMucHVzaFN0YWNrKCBsYWJlbHMgKTtcbn07XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgU2Nyb2xsIFBhcmVudCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogc2Nyb2xsUGFyZW50XG4vLz4+Z3JvdXA6IENvcmVcbi8vPj5kZXNjcmlwdGlvbjogR2V0IHRoZSBjbG9zZXN0IGFuY2VzdG9yIGVsZW1lbnQgdGhhdCBpcyBzY3JvbGxhYmxlLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3Njcm9sbFBhcmVudC9cblxuXG5cbnZhciBzY3JvbGxQYXJlbnQgPSAkLmZuLnNjcm9sbFBhcmVudCA9IGZ1bmN0aW9uKCBpbmNsdWRlSGlkZGVuICkge1xuXHR2YXIgcG9zaXRpb24gPSB0aGlzLmNzcyggXCJwb3NpdGlvblwiICksXG5cdFx0ZXhjbHVkZVN0YXRpY1BhcmVudCA9IHBvc2l0aW9uID09PSBcImFic29sdXRlXCIsXG5cdFx0b3ZlcmZsb3dSZWdleCA9IGluY2x1ZGVIaWRkZW4gPyAvKGF1dG98c2Nyb2xsfGhpZGRlbikvIDogLyhhdXRvfHNjcm9sbCkvLFxuXHRcdHNjcm9sbFBhcmVudCA9IHRoaXMucGFyZW50cygpLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgcGFyZW50ID0gJCggdGhpcyApO1xuXHRcdFx0aWYgKCBleGNsdWRlU3RhdGljUGFyZW50ICYmIHBhcmVudC5jc3MoIFwicG9zaXRpb25cIiApID09PSBcInN0YXRpY1wiICkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gb3ZlcmZsb3dSZWdleC50ZXN0KCBwYXJlbnQuY3NzKCBcIm92ZXJmbG93XCIgKSArIHBhcmVudC5jc3MoIFwib3ZlcmZsb3cteVwiICkgK1xuXHRcdFx0XHRwYXJlbnQuY3NzKCBcIm92ZXJmbG93LXhcIiApICk7XG5cdFx0fSApLmVxKCAwICk7XG5cblx0cmV0dXJuIHBvc2l0aW9uID09PSBcImZpeGVkXCIgfHwgIXNjcm9sbFBhcmVudC5sZW5ndGggP1xuXHRcdCQoIHRoaXNbIDAgXS5vd25lckRvY3VtZW50IHx8IGRvY3VtZW50ICkgOlxuXHRcdHNjcm9sbFBhcmVudDtcbn07XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgVGFiYmFibGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IDp0YWJiYWJsZSBTZWxlY3RvclxuLy8+Pmdyb3VwOiBDb3JlXG4vLz4+ZGVzY3JpcHRpb246IFNlbGVjdHMgZWxlbWVudHMgd2hpY2ggY2FuIGJlIHRhYmJlZCB0by5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS90YWJiYWJsZS1zZWxlY3Rvci9cblxuXG5cbnZhciB0YWJiYWJsZSA9ICQuZXh0ZW5kKCAkLmV4cHJbIFwiOlwiIF0sIHtcblx0dGFiYmFibGU6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHZhciB0YWJJbmRleCA9ICQuYXR0ciggZWxlbWVudCwgXCJ0YWJpbmRleFwiICksXG5cdFx0XHRoYXNUYWJpbmRleCA9IHRhYkluZGV4ICE9IG51bGw7XG5cdFx0cmV0dXJuICggIWhhc1RhYmluZGV4IHx8IHRhYkluZGV4ID49IDAgKSAmJiAkLnVpLmZvY3VzYWJsZSggZWxlbWVudCwgaGFzVGFiaW5kZXggKTtcblx0fVxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFVuaXF1ZSBJRCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogdW5pcXVlSWRcbi8vPj5ncm91cDogQ29yZVxuLy8+PmRlc2NyaXB0aW9uOiBGdW5jdGlvbnMgdG8gZ2VuZXJhdGUgYW5kIHJlbW92ZSB1bmlxdWVJZCdzXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vdW5pcXVlSWQvXG5cblxuXG52YXIgdW5pcXVlSWQgPSAkLmZuLmV4dGVuZCgge1xuXHR1bmlxdWVJZDogKCBmdW5jdGlvbigpIHtcblx0XHR2YXIgdXVpZCA9IDA7XG5cblx0XHRyZXR1cm4gZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCAhdGhpcy5pZCApIHtcblx0XHRcdFx0XHR0aGlzLmlkID0gXCJ1aS1pZC1cIiArICggKyt1dWlkICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHR9O1xuXHR9ICkoKSxcblxuXHRyZW1vdmVVbmlxdWVJZDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoIC9edWktaWQtXFxkKyQvLnRlc3QoIHRoaXMuaWQgKSApIHtcblx0XHRcdFx0JCggdGhpcyApLnJlbW92ZUF0dHIoIFwiaWRcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fVxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEFjY29yZGlvbiAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogQWNjb3JkaW9uXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vIGpzY3M6ZGlzYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRlc2NyaXB0aW9uOiBEaXNwbGF5cyBjb2xsYXBzaWJsZSBjb250ZW50IHBhbmVscyBmb3IgcHJlc2VudGluZyBpbmZvcm1hdGlvbiBpbiBhIGxpbWl0ZWQgYW1vdW50IG9mIHNwYWNlLlxuLy8ganNjczplbmFibGUgbWF4aW11bUxpbmVMZW5ndGhcbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9hY2NvcmRpb24vXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vYWNjb3JkaW9uL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvYWNjb3JkaW9uLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG52YXIgd2lkZ2V0c0FjY29yZGlvbiA9ICQud2lkZ2V0KCBcInVpLmFjY29yZGlvblwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRhY3RpdmU6IDAsXG5cdFx0YW5pbWF0ZToge30sXG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS1hY2NvcmRpb24taGVhZGVyXCI6IFwidWktY29ybmVyLXRvcFwiLFxuXHRcdFx0XCJ1aS1hY2NvcmRpb24taGVhZGVyLWNvbGxhcHNlZFwiOiBcInVpLWNvcm5lci1hbGxcIixcblx0XHRcdFwidWktYWNjb3JkaW9uLWNvbnRlbnRcIjogXCJ1aS1jb3JuZXItYm90dG9tXCJcblx0XHR9LFxuXHRcdGNvbGxhcHNpYmxlOiBmYWxzZSxcblx0XHRldmVudDogXCJjbGlja1wiLFxuXHRcdGhlYWRlcjogXCI+IGxpID4gOmZpcnN0LWNoaWxkLCA+IDpub3QobGkpOmV2ZW5cIixcblx0XHRoZWlnaHRTdHlsZTogXCJhdXRvXCIsXG5cdFx0aWNvbnM6IHtcblx0XHRcdGFjdGl2ZUhlYWRlcjogXCJ1aS1pY29uLXRyaWFuZ2xlLTEtc1wiLFxuXHRcdFx0aGVhZGVyOiBcInVpLWljb24tdHJpYW5nbGUtMS1lXCJcblx0XHR9LFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0YWN0aXZhdGU6IG51bGwsXG5cdFx0YmVmb3JlQWN0aXZhdGU6IG51bGxcblx0fSxcblxuXHRoaWRlUHJvcHM6IHtcblx0XHRib3JkZXJUb3BXaWR0aDogXCJoaWRlXCIsXG5cdFx0Ym9yZGVyQm90dG9tV2lkdGg6IFwiaGlkZVwiLFxuXHRcdHBhZGRpbmdUb3A6IFwiaGlkZVwiLFxuXHRcdHBhZGRpbmdCb3R0b206IFwiaGlkZVwiLFxuXHRcdGhlaWdodDogXCJoaWRlXCJcblx0fSxcblxuXHRzaG93UHJvcHM6IHtcblx0XHRib3JkZXJUb3BXaWR0aDogXCJzaG93XCIsXG5cdFx0Ym9yZGVyQm90dG9tV2lkdGg6IFwic2hvd1wiLFxuXHRcdHBhZGRpbmdUb3A6IFwic2hvd1wiLFxuXHRcdHBhZGRpbmdCb3R0b206IFwic2hvd1wiLFxuXHRcdGhlaWdodDogXCJzaG93XCJcblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblxuXHRcdHRoaXMucHJldlNob3cgPSB0aGlzLnByZXZIaWRlID0gJCgpO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWFjY29yZGlvblwiLCBcInVpLXdpZGdldCB1aS1oZWxwZXItcmVzZXRcIiApO1xuXHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcInJvbGVcIiwgXCJ0YWJsaXN0XCIgKTtcblxuXHRcdC8vIERvbid0IGFsbG93IGNvbGxhcHNpYmxlOiBmYWxzZSBhbmQgYWN0aXZlOiBmYWxzZSAvIG51bGxcblx0XHRpZiAoICFvcHRpb25zLmNvbGxhcHNpYmxlICYmICggb3B0aW9ucy5hY3RpdmUgPT09IGZhbHNlIHx8IG9wdGlvbnMuYWN0aXZlID09IG51bGwgKSApIHtcblx0XHRcdG9wdGlvbnMuYWN0aXZlID0gMDtcblx0XHR9XG5cblx0XHR0aGlzLl9wcm9jZXNzUGFuZWxzKCk7XG5cblx0XHQvLyBoYW5kbGUgbmVnYXRpdmUgdmFsdWVzXG5cdFx0aWYgKCBvcHRpb25zLmFjdGl2ZSA8IDAgKSB7XG5cdFx0XHRvcHRpb25zLmFjdGl2ZSArPSB0aGlzLmhlYWRlcnMubGVuZ3RoO1xuXHRcdH1cblx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cdH0sXG5cblx0X2dldENyZWF0ZUV2ZW50RGF0YTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdGhlYWRlcjogdGhpcy5hY3RpdmUsXG5cdFx0XHRwYW5lbDogIXRoaXMuYWN0aXZlLmxlbmd0aCA/ICQoKSA6IHRoaXMuYWN0aXZlLm5leHQoKVxuXHRcdH07XG5cdH0sXG5cblx0X2NyZWF0ZUljb25zOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgaWNvbiwgY2hpbGRyZW4sXG5cdFx0XHRpY29ucyA9IHRoaXMub3B0aW9ucy5pY29ucztcblxuXHRcdGlmICggaWNvbnMgKSB7XG5cdFx0XHRpY29uID0gJCggXCI8c3Bhbj5cIiApO1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIGljb24sIFwidWktYWNjb3JkaW9uLWhlYWRlci1pY29uXCIsIFwidWktaWNvbiBcIiArIGljb25zLmhlYWRlciApO1xuXHRcdFx0aWNvbi5wcmVwZW5kVG8oIHRoaXMuaGVhZGVycyApO1xuXHRcdFx0Y2hpbGRyZW4gPSB0aGlzLmFjdGl2ZS5jaGlsZHJlbiggXCIudWktYWNjb3JkaW9uLWhlYWRlci1pY29uXCIgKTtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBjaGlsZHJlbiwgaWNvbnMuaGVhZGVyIClcblx0XHRcdFx0Ll9hZGRDbGFzcyggY2hpbGRyZW4sIG51bGwsIGljb25zLmFjdGl2ZUhlYWRlciApXG5cdFx0XHRcdC5fYWRkQ2xhc3MoIHRoaXMuaGVhZGVycywgXCJ1aS1hY2NvcmRpb24taWNvbnNcIiApO1xuXHRcdH1cblx0fSxcblxuXHRfZGVzdHJveUljb25zOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5oZWFkZXJzLCBcInVpLWFjY29yZGlvbi1pY29uc1wiICk7XG5cdFx0dGhpcy5oZWFkZXJzLmNoaWxkcmVuKCBcIi51aS1hY2NvcmRpb24taGVhZGVyLWljb25cIiApLnJlbW92ZSgpO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgY29udGVudHM7XG5cblx0XHQvLyBDbGVhbiB1cCBtYWluIGVsZW1lbnRcblx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQXR0ciggXCJyb2xlXCIgKTtcblxuXHRcdC8vIENsZWFuIHVwIGhlYWRlcnNcblx0XHR0aGlzLmhlYWRlcnNcblx0XHRcdC5yZW1vdmVBdHRyKCBcInJvbGUgYXJpYS1leHBhbmRlZCBhcmlhLXNlbGVjdGVkIGFyaWEtY29udHJvbHMgdGFiSW5kZXhcIiApXG5cdFx0XHQucmVtb3ZlVW5pcXVlSWQoKTtcblxuXHRcdHRoaXMuX2Rlc3Ryb3lJY29ucygpO1xuXG5cdFx0Ly8gQ2xlYW4gdXAgY29udGVudCBwYW5lbHNcblx0XHRjb250ZW50cyA9IHRoaXMuaGVhZGVycy5uZXh0KClcblx0XHRcdC5jc3MoIFwiZGlzcGxheVwiLCBcIlwiIClcblx0XHRcdC5yZW1vdmVBdHRyKCBcInJvbGUgYXJpYS1oaWRkZW4gYXJpYS1sYWJlbGxlZGJ5XCIgKVxuXHRcdFx0LnJlbW92ZVVuaXF1ZUlkKCk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5oZWlnaHRTdHlsZSAhPT0gXCJjb250ZW50XCIgKSB7XG5cdFx0XHRjb250ZW50cy5jc3MoIFwiaGVpZ2h0XCIsIFwiXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0aWYgKCBrZXkgPT09IFwiYWN0aXZlXCIgKSB7XG5cblx0XHRcdC8vIF9hY3RpdmF0ZSgpIHdpbGwgaGFuZGxlIGludmFsaWQgdmFsdWVzIGFuZCB1cGRhdGUgdGhpcy5vcHRpb25zXG5cdFx0XHR0aGlzLl9hY3RpdmF0ZSggdmFsdWUgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJldmVudFwiICkge1xuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuX29mZiggdGhpcy5oZWFkZXJzLCB0aGlzLm9wdGlvbnMuZXZlbnQgKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuX3NldHVwRXZlbnRzKCB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHQvLyBTZXR0aW5nIGNvbGxhcHNpYmxlOiBmYWxzZSB3aGlsZSBjb2xsYXBzZWQ7IG9wZW4gZmlyc3QgcGFuZWxcblx0XHRpZiAoIGtleSA9PT0gXCJjb2xsYXBzaWJsZVwiICYmICF2YWx1ZSAmJiB0aGlzLm9wdGlvbnMuYWN0aXZlID09PSBmYWxzZSApIHtcblx0XHRcdHRoaXMuX2FjdGl2YXRlKCAwICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwiaWNvbnNcIiApIHtcblx0XHRcdHRoaXMuX2Rlc3Ryb3lJY29ucygpO1xuXHRcdFx0aWYgKCB2YWx1ZSApIHtcblx0XHRcdFx0dGhpcy5fY3JlYXRlSWNvbnMoKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbkRpc2FibGVkOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIHZhbHVlICk7XG5cblx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJhcmlhLWRpc2FibGVkXCIsIHZhbHVlICk7XG5cblx0XHQvLyBTdXBwb3J0OiBJRTggT25seVxuXHRcdC8vICM1MzMyIC8gIzYwNTkgLSBvcGFjaXR5IGRvZXNuJ3QgY2FzY2FkZSB0byBwb3NpdGlvbmVkIGVsZW1lbnRzIGluIElFXG5cdFx0Ly8gc28gd2UgbmVlZCB0byBhZGQgdGhlIGRpc2FibGVkIGNsYXNzIHRvIHRoZSBoZWFkZXJzIGFuZCBwYW5lbHNcblx0XHR0aGlzLl90b2dnbGVDbGFzcyggbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiLCAhIXZhbHVlICk7XG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIHRoaXMuaGVhZGVycy5hZGQoIHRoaXMuaGVhZGVycy5uZXh0KCkgKSwgbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiLFxuXHRcdFx0ISF2YWx1ZSApO1xuXHR9LFxuXG5cdF9rZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCBldmVudC5hbHRLZXkgfHwgZXZlbnQuY3RybEtleSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIga2V5Q29kZSA9ICQudWkua2V5Q29kZSxcblx0XHRcdGxlbmd0aCA9IHRoaXMuaGVhZGVycy5sZW5ndGgsXG5cdFx0XHRjdXJyZW50SW5kZXggPSB0aGlzLmhlYWRlcnMuaW5kZXgoIGV2ZW50LnRhcmdldCApLFxuXHRcdFx0dG9Gb2N1cyA9IGZhbHNlO1xuXG5cdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRjYXNlIGtleUNvZGUuUklHSFQ6XG5cdFx0Y2FzZSBrZXlDb2RlLkRPV046XG5cdFx0XHR0b0ZvY3VzID0gdGhpcy5oZWFkZXJzWyAoIGN1cnJlbnRJbmRleCArIDEgKSAlIGxlbmd0aCBdO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSBrZXlDb2RlLkxFRlQ6XG5cdFx0Y2FzZSBrZXlDb2RlLlVQOlxuXHRcdFx0dG9Gb2N1cyA9IHRoaXMuaGVhZGVyc1sgKCBjdXJyZW50SW5kZXggLSAxICsgbGVuZ3RoICkgJSBsZW5ndGggXTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2Uga2V5Q29kZS5TUEFDRTpcblx0XHRjYXNlIGtleUNvZGUuRU5URVI6XG5cdFx0XHR0aGlzLl9ldmVudEhhbmRsZXIoIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlIGtleUNvZGUuSE9NRTpcblx0XHRcdHRvRm9jdXMgPSB0aGlzLmhlYWRlcnNbIDAgXTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2Uga2V5Q29kZS5FTkQ6XG5cdFx0XHR0b0ZvY3VzID0gdGhpcy5oZWFkZXJzWyBsZW5ndGggLSAxIF07XG5cdFx0XHRicmVhaztcblx0XHR9XG5cblx0XHRpZiAoIHRvRm9jdXMgKSB7XG5cdFx0XHQkKCBldmVudC50YXJnZXQgKS5hdHRyKCBcInRhYkluZGV4XCIsIC0xICk7XG5cdFx0XHQkKCB0b0ZvY3VzICkuYXR0ciggXCJ0YWJJbmRleFwiLCAwICk7XG5cdFx0XHQkKCB0b0ZvY3VzICkudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdH1cblx0fSxcblxuXHRfcGFuZWxLZXlEb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCBldmVudC5rZXlDb2RlID09PSAkLnVpLmtleUNvZGUuVVAgJiYgZXZlbnQuY3RybEtleSApIHtcblx0XHRcdCQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKS5wcmV2KCkudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0fVxuXHR9LFxuXG5cdHJlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXHRcdHRoaXMuX3Byb2Nlc3NQYW5lbHMoKTtcblxuXHRcdC8vIFdhcyBjb2xsYXBzZWQgb3Igbm8gcGFuZWxcblx0XHRpZiAoICggb3B0aW9ucy5hY3RpdmUgPT09IGZhbHNlICYmIG9wdGlvbnMuY29sbGFwc2libGUgPT09IHRydWUgKSB8fFxuXHRcdFx0XHQhdGhpcy5oZWFkZXJzLmxlbmd0aCApIHtcblx0XHRcdG9wdGlvbnMuYWN0aXZlID0gZmFsc2U7XG5cdFx0XHR0aGlzLmFjdGl2ZSA9ICQoKTtcblxuXHRcdC8vIGFjdGl2ZSBmYWxzZSBvbmx5IHdoZW4gY29sbGFwc2libGUgaXMgdHJ1ZVxuXHRcdH0gZWxzZSBpZiAoIG9wdGlvbnMuYWN0aXZlID09PSBmYWxzZSApIHtcblx0XHRcdHRoaXMuX2FjdGl2YXRlKCAwICk7XG5cblx0XHQvLyB3YXMgYWN0aXZlLCBidXQgYWN0aXZlIHBhbmVsIGlzIGdvbmVcblx0XHR9IGVsc2UgaWYgKCB0aGlzLmFjdGl2ZS5sZW5ndGggJiYgISQuY29udGFpbnMoIHRoaXMuZWxlbWVudFsgMCBdLCB0aGlzLmFjdGl2ZVsgMCBdICkgKSB7XG5cblx0XHRcdC8vIGFsbCByZW1haW5pbmcgcGFuZWwgYXJlIGRpc2FibGVkXG5cdFx0XHRpZiAoIHRoaXMuaGVhZGVycy5sZW5ndGggPT09IHRoaXMuaGVhZGVycy5maW5kKCBcIi51aS1zdGF0ZS1kaXNhYmxlZFwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRvcHRpb25zLmFjdGl2ZSA9IGZhbHNlO1xuXHRcdFx0XHR0aGlzLmFjdGl2ZSA9ICQoKTtcblxuXHRcdFx0Ly8gYWN0aXZhdGUgcHJldmlvdXMgcGFuZWxcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuX2FjdGl2YXRlKCBNYXRoLm1heCggMCwgb3B0aW9ucy5hY3RpdmUgLSAxICkgKTtcblx0XHRcdH1cblxuXHRcdC8vIHdhcyBhY3RpdmUsIGFjdGl2ZSBwYW5lbCBzdGlsbCBleGlzdHNcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBtYWtlIHN1cmUgYWN0aXZlIGluZGV4IGlzIGNvcnJlY3Rcblx0XHRcdG9wdGlvbnMuYWN0aXZlID0gdGhpcy5oZWFkZXJzLmluZGV4KCB0aGlzLmFjdGl2ZSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX2Rlc3Ryb3lJY29ucygpO1xuXG5cdFx0dGhpcy5fcmVmcmVzaCgpO1xuXHR9LFxuXG5cdF9wcm9jZXNzUGFuZWxzOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgcHJldkhlYWRlcnMgPSB0aGlzLmhlYWRlcnMsXG5cdFx0XHRwcmV2UGFuZWxzID0gdGhpcy5wYW5lbHM7XG5cblx0XHR0aGlzLmhlYWRlcnMgPSB0aGlzLmVsZW1lbnQuZmluZCggdGhpcy5vcHRpb25zLmhlYWRlciApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmhlYWRlcnMsIFwidWktYWNjb3JkaW9uLWhlYWRlciB1aS1hY2NvcmRpb24taGVhZGVyLWNvbGxhcHNlZFwiLFxuXHRcdFx0XCJ1aS1zdGF0ZS1kZWZhdWx0XCIgKTtcblxuXHRcdHRoaXMucGFuZWxzID0gdGhpcy5oZWFkZXJzLm5leHQoKS5maWx0ZXIoIFwiOm5vdCgudWktYWNjb3JkaW9uLWNvbnRlbnQtYWN0aXZlKVwiICkuaGlkZSgpO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnBhbmVscywgXCJ1aS1hY2NvcmRpb24tY29udGVudFwiLCBcInVpLWhlbHBlci1yZXNldCB1aS13aWRnZXQtY29udGVudFwiICk7XG5cblx0XHQvLyBBdm9pZCBtZW1vcnkgbGVha3MgKCMxMDA1Nilcblx0XHRpZiAoIHByZXZQYW5lbHMgKSB7XG5cdFx0XHR0aGlzLl9vZmYoIHByZXZIZWFkZXJzLm5vdCggdGhpcy5oZWFkZXJzICkgKTtcblx0XHRcdHRoaXMuX29mZiggcHJldlBhbmVscy5ub3QoIHRoaXMucGFuZWxzICkgKTtcblx0XHR9XG5cdH0sXG5cblx0X3JlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBtYXhIZWlnaHQsXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0aGVpZ2h0U3R5bGUgPSBvcHRpb25zLmhlaWdodFN0eWxlLFxuXHRcdFx0cGFyZW50ID0gdGhpcy5lbGVtZW50LnBhcmVudCgpO1xuXG5cdFx0dGhpcy5hY3RpdmUgPSB0aGlzLl9maW5kQWN0aXZlKCBvcHRpb25zLmFjdGl2ZSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmFjdGl2ZSwgXCJ1aS1hY2NvcmRpb24taGVhZGVyLWFjdGl2ZVwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiIClcblx0XHRcdC5fcmVtb3ZlQ2xhc3MoIHRoaXMuYWN0aXZlLCBcInVpLWFjY29yZGlvbi1oZWFkZXItY29sbGFwc2VkXCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5hY3RpdmUubmV4dCgpLCBcInVpLWFjY29yZGlvbi1jb250ZW50LWFjdGl2ZVwiICk7XG5cdFx0dGhpcy5hY3RpdmUubmV4dCgpLnNob3coKTtcblxuXHRcdHRoaXMuaGVhZGVyc1xuXHRcdFx0LmF0dHIoIFwicm9sZVwiLCBcInRhYlwiIClcblx0XHRcdC5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGhlYWRlciA9ICQoIHRoaXMgKSxcblx0XHRcdFx0XHRoZWFkZXJJZCA9IGhlYWRlci51bmlxdWVJZCgpLmF0dHIoIFwiaWRcIiApLFxuXHRcdFx0XHRcdHBhbmVsID0gaGVhZGVyLm5leHQoKSxcblx0XHRcdFx0XHRwYW5lbElkID0gcGFuZWwudW5pcXVlSWQoKS5hdHRyKCBcImlkXCIgKTtcblx0XHRcdFx0aGVhZGVyLmF0dHIoIFwiYXJpYS1jb250cm9sc1wiLCBwYW5lbElkICk7XG5cdFx0XHRcdHBhbmVsLmF0dHIoIFwiYXJpYS1sYWJlbGxlZGJ5XCIsIGhlYWRlcklkICk7XG5cdFx0XHR9IClcblx0XHRcdC5uZXh0KClcblx0XHRcdFx0LmF0dHIoIFwicm9sZVwiLCBcInRhYnBhbmVsXCIgKTtcblxuXHRcdHRoaXMuaGVhZGVyc1xuXHRcdFx0Lm5vdCggdGhpcy5hY3RpdmUgKVxuXHRcdFx0XHQuYXR0cigge1xuXHRcdFx0XHRcdFwiYXJpYS1zZWxlY3RlZFwiOiBcImZhbHNlXCIsXG5cdFx0XHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwiZmFsc2VcIixcblx0XHRcdFx0XHR0YWJJbmRleDogLTFcblx0XHRcdFx0fSApXG5cdFx0XHRcdC5uZXh0KClcblx0XHRcdFx0XHQuYXR0cigge1xuXHRcdFx0XHRcdFx0XCJhcmlhLWhpZGRlblwiOiBcInRydWVcIlxuXHRcdFx0XHRcdH0gKVxuXHRcdFx0XHRcdC5oaWRlKCk7XG5cblx0XHQvLyBNYWtlIHN1cmUgYXQgbGVhc3Qgb25lIGhlYWRlciBpcyBpbiB0aGUgdGFiIG9yZGVyXG5cdFx0aWYgKCAhdGhpcy5hY3RpdmUubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5oZWFkZXJzLmVxKCAwICkuYXR0ciggXCJ0YWJJbmRleFwiLCAwICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuYWN0aXZlLmF0dHIoIHtcblx0XHRcdFx0XCJhcmlhLXNlbGVjdGVkXCI6IFwidHJ1ZVwiLFxuXHRcdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJ0cnVlXCIsXG5cdFx0XHRcdHRhYkluZGV4OiAwXG5cdFx0XHR9IClcblx0XHRcdFx0Lm5leHQoKVxuXHRcdFx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdFx0XHRcImFyaWEtaGlkZGVuXCI6IFwiZmFsc2VcIlxuXHRcdFx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHR0aGlzLl9jcmVhdGVJY29ucygpO1xuXG5cdFx0dGhpcy5fc2V0dXBFdmVudHMoIG9wdGlvbnMuZXZlbnQgKTtcblxuXHRcdGlmICggaGVpZ2h0U3R5bGUgPT09IFwiZmlsbFwiICkge1xuXHRcdFx0bWF4SGVpZ2h0ID0gcGFyZW50LmhlaWdodCgpO1xuXHRcdFx0dGhpcy5lbGVtZW50LnNpYmxpbmdzKCBcIjp2aXNpYmxlXCIgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGVsZW0gPSAkKCB0aGlzICksXG5cdFx0XHRcdFx0cG9zaXRpb24gPSBlbGVtLmNzcyggXCJwb3NpdGlvblwiICk7XG5cblx0XHRcdFx0aWYgKCBwb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiIHx8IHBvc2l0aW9uID09PSBcImZpeGVkXCIgKSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cdFx0XHRcdG1heEhlaWdodCAtPSBlbGVtLm91dGVySGVpZ2h0KCB0cnVlICk7XG5cdFx0XHR9ICk7XG5cblx0XHRcdHRoaXMuaGVhZGVycy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0bWF4SGVpZ2h0IC09ICQoIHRoaXMgKS5vdXRlckhlaWdodCggdHJ1ZSApO1xuXHRcdFx0fSApO1xuXG5cdFx0XHR0aGlzLmhlYWRlcnMubmV4dCgpXG5cdFx0XHRcdC5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHQkKCB0aGlzICkuaGVpZ2h0KCBNYXRoLm1heCggMCwgbWF4SGVpZ2h0IC1cblx0XHRcdFx0XHRcdCQoIHRoaXMgKS5pbm5lckhlaWdodCgpICsgJCggdGhpcyApLmhlaWdodCgpICkgKTtcblx0XHRcdFx0fSApXG5cdFx0XHRcdC5jc3MoIFwib3ZlcmZsb3dcIiwgXCJhdXRvXCIgKTtcblx0XHR9IGVsc2UgaWYgKCBoZWlnaHRTdHlsZSA9PT0gXCJhdXRvXCIgKSB7XG5cdFx0XHRtYXhIZWlnaHQgPSAwO1xuXHRcdFx0dGhpcy5oZWFkZXJzLm5leHQoKVxuXHRcdFx0XHQuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0dmFyIGlzVmlzaWJsZSA9ICQoIHRoaXMgKS5pcyggXCI6dmlzaWJsZVwiICk7XG5cdFx0XHRcdFx0aWYgKCAhaXNWaXNpYmxlICkge1xuXHRcdFx0XHRcdFx0JCggdGhpcyApLnNob3coKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0bWF4SGVpZ2h0ID0gTWF0aC5tYXgoIG1heEhlaWdodCwgJCggdGhpcyApLmNzcyggXCJoZWlnaHRcIiwgXCJcIiApLmhlaWdodCgpICk7XG5cdFx0XHRcdFx0aWYgKCAhaXNWaXNpYmxlICkge1xuXHRcdFx0XHRcdFx0JCggdGhpcyApLmhpZGUoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKVxuXHRcdFx0XHQuaGVpZ2h0KCBtYXhIZWlnaHQgKTtcblx0XHR9XG5cdH0sXG5cblx0X2FjdGl2YXRlOiBmdW5jdGlvbiggaW5kZXggKSB7XG5cdFx0dmFyIGFjdGl2ZSA9IHRoaXMuX2ZpbmRBY3RpdmUoIGluZGV4IClbIDAgXTtcblxuXHRcdC8vIFRyeWluZyB0byBhY3RpdmF0ZSB0aGUgYWxyZWFkeSBhY3RpdmUgcGFuZWxcblx0XHRpZiAoIGFjdGl2ZSA9PT0gdGhpcy5hY3RpdmVbIDAgXSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBUcnlpbmcgdG8gY29sbGFwc2UsIHNpbXVsYXRlIGEgY2xpY2sgb24gdGhlIGN1cnJlbnRseSBhY3RpdmUgaGVhZGVyXG5cdFx0YWN0aXZlID0gYWN0aXZlIHx8IHRoaXMuYWN0aXZlWyAwIF07XG5cblx0XHR0aGlzLl9ldmVudEhhbmRsZXIoIHtcblx0XHRcdHRhcmdldDogYWN0aXZlLFxuXHRcdFx0Y3VycmVudFRhcmdldDogYWN0aXZlLFxuXHRcdFx0cHJldmVudERlZmF1bHQ6ICQubm9vcFxuXHRcdH0gKTtcblx0fSxcblxuXHRfZmluZEFjdGl2ZTogZnVuY3Rpb24oIHNlbGVjdG9yICkge1xuXHRcdHJldHVybiB0eXBlb2Ygc2VsZWN0b3IgPT09IFwibnVtYmVyXCIgPyB0aGlzLmhlYWRlcnMuZXEoIHNlbGVjdG9yICkgOiAkKCk7XG5cdH0sXG5cblx0X3NldHVwRXZlbnRzOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGV2ZW50cyA9IHtcblx0XHRcdGtleWRvd246IFwiX2tleWRvd25cIlxuXHRcdH07XG5cdFx0aWYgKCBldmVudCApIHtcblx0XHRcdCQuZWFjaCggZXZlbnQuc3BsaXQoIFwiIFwiICksIGZ1bmN0aW9uKCBpbmRleCwgZXZlbnROYW1lICkge1xuXHRcdFx0XHRldmVudHNbIGV2ZW50TmFtZSBdID0gXCJfZXZlbnRIYW5kbGVyXCI7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fb2ZmKCB0aGlzLmhlYWRlcnMuYWRkKCB0aGlzLmhlYWRlcnMubmV4dCgpICkgKTtcblx0XHR0aGlzLl9vbiggdGhpcy5oZWFkZXJzLCBldmVudHMgKTtcblx0XHR0aGlzLl9vbiggdGhpcy5oZWFkZXJzLm5leHQoKSwgeyBrZXlkb3duOiBcIl9wYW5lbEtleURvd25cIiB9ICk7XG5cdFx0dGhpcy5faG92ZXJhYmxlKCB0aGlzLmhlYWRlcnMgKTtcblx0XHR0aGlzLl9mb2N1c2FibGUoIHRoaXMuaGVhZGVycyApO1xuXHR9LFxuXG5cdF9ldmVudEhhbmRsZXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgYWN0aXZlQ2hpbGRyZW4sIGNsaWNrZWRDaGlsZHJlbixcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRhY3RpdmUgPSB0aGlzLmFjdGl2ZSxcblx0XHRcdGNsaWNrZWQgPSAkKCBldmVudC5jdXJyZW50VGFyZ2V0ICksXG5cdFx0XHRjbGlja2VkSXNBY3RpdmUgPSBjbGlja2VkWyAwIF0gPT09IGFjdGl2ZVsgMCBdLFxuXHRcdFx0Y29sbGFwc2luZyA9IGNsaWNrZWRJc0FjdGl2ZSAmJiBvcHRpb25zLmNvbGxhcHNpYmxlLFxuXHRcdFx0dG9TaG93ID0gY29sbGFwc2luZyA/ICQoKSA6IGNsaWNrZWQubmV4dCgpLFxuXHRcdFx0dG9IaWRlID0gYWN0aXZlLm5leHQoKSxcblx0XHRcdGV2ZW50RGF0YSA9IHtcblx0XHRcdFx0b2xkSGVhZGVyOiBhY3RpdmUsXG5cdFx0XHRcdG9sZFBhbmVsOiB0b0hpZGUsXG5cdFx0XHRcdG5ld0hlYWRlcjogY29sbGFwc2luZyA/ICQoKSA6IGNsaWNrZWQsXG5cdFx0XHRcdG5ld1BhbmVsOiB0b1Nob3dcblx0XHRcdH07XG5cblx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0aWYgKFxuXG5cdFx0XHRcdC8vIGNsaWNrIG9uIGFjdGl2ZSBoZWFkZXIsIGJ1dCBub3QgY29sbGFwc2libGVcblx0XHRcdFx0KCBjbGlja2VkSXNBY3RpdmUgJiYgIW9wdGlvbnMuY29sbGFwc2libGUgKSB8fFxuXG5cdFx0XHRcdC8vIGFsbG93IGNhbmNlbGluZyBhY3RpdmF0aW9uXG5cdFx0XHRcdCggdGhpcy5fdHJpZ2dlciggXCJiZWZvcmVBY3RpdmF0ZVwiLCBldmVudCwgZXZlbnREYXRhICkgPT09IGZhbHNlICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0b3B0aW9ucy5hY3RpdmUgPSBjb2xsYXBzaW5nID8gZmFsc2UgOiB0aGlzLmhlYWRlcnMuaW5kZXgoIGNsaWNrZWQgKTtcblxuXHRcdC8vIFdoZW4gdGhlIGNhbGwgdG8gLl90b2dnbGUoKSBjb21lcyBhZnRlciB0aGUgY2xhc3MgY2hhbmdlc1xuXHRcdC8vIGl0IGNhdXNlcyBhIHZlcnkgb2RkIGJ1ZyBpbiBJRSA4IChzZWUgIzY3MjApXG5cdFx0dGhpcy5hY3RpdmUgPSBjbGlja2VkSXNBY3RpdmUgPyAkKCkgOiBjbGlja2VkO1xuXHRcdHRoaXMuX3RvZ2dsZSggZXZlbnREYXRhICk7XG5cblx0XHQvLyBTd2l0Y2ggY2xhc3Nlc1xuXHRcdC8vIGNvcm5lciBjbGFzc2VzIG9uIHRoZSBwcmV2aW91c2x5IGFjdGl2ZSBoZWFkZXIgc3RheSBhZnRlciB0aGUgYW5pbWF0aW9uXG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGFjdGl2ZSwgXCJ1aS1hY2NvcmRpb24taGVhZGVyLWFjdGl2ZVwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0aWYgKCBvcHRpb25zLmljb25zICkge1xuXHRcdFx0YWN0aXZlQ2hpbGRyZW4gPSBhY3RpdmUuY2hpbGRyZW4oIFwiLnVpLWFjY29yZGlvbi1oZWFkZXItaWNvblwiICk7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggYWN0aXZlQ2hpbGRyZW4sIG51bGwsIG9wdGlvbnMuaWNvbnMuYWN0aXZlSGVhZGVyIClcblx0XHRcdFx0Ll9hZGRDbGFzcyggYWN0aXZlQ2hpbGRyZW4sIG51bGwsIG9wdGlvbnMuaWNvbnMuaGVhZGVyICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhY2xpY2tlZElzQWN0aXZlICkge1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGNsaWNrZWQsIFwidWktYWNjb3JkaW9uLWhlYWRlci1jb2xsYXBzZWRcIiApXG5cdFx0XHRcdC5fYWRkQ2xhc3MoIGNsaWNrZWQsIFwidWktYWNjb3JkaW9uLWhlYWRlci1hY3RpdmVcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0aWYgKCBvcHRpb25zLmljb25zICkge1xuXHRcdFx0XHRjbGlja2VkQ2hpbGRyZW4gPSBjbGlja2VkLmNoaWxkcmVuKCBcIi51aS1hY2NvcmRpb24taGVhZGVyLWljb25cIiApO1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggY2xpY2tlZENoaWxkcmVuLCBudWxsLCBvcHRpb25zLmljb25zLmhlYWRlciApXG5cdFx0XHRcdFx0Ll9hZGRDbGFzcyggY2xpY2tlZENoaWxkcmVuLCBudWxsLCBvcHRpb25zLmljb25zLmFjdGl2ZUhlYWRlciApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggY2xpY2tlZC5uZXh0KCksIFwidWktYWNjb3JkaW9uLWNvbnRlbnQtYWN0aXZlXCIgKTtcblx0XHR9XG5cdH0sXG5cblx0X3RvZ2dsZTogZnVuY3Rpb24oIGRhdGEgKSB7XG5cdFx0dmFyIHRvU2hvdyA9IGRhdGEubmV3UGFuZWwsXG5cdFx0XHR0b0hpZGUgPSB0aGlzLnByZXZTaG93Lmxlbmd0aCA/IHRoaXMucHJldlNob3cgOiBkYXRhLm9sZFBhbmVsO1xuXG5cdFx0Ly8gSGFuZGxlIGFjdGl2YXRpbmcgYSBwYW5lbCBkdXJpbmcgdGhlIGFuaW1hdGlvbiBmb3IgYW5vdGhlciBhY3RpdmF0aW9uXG5cdFx0dGhpcy5wcmV2U2hvdy5hZGQoIHRoaXMucHJldkhpZGUgKS5zdG9wKCB0cnVlLCB0cnVlICk7XG5cdFx0dGhpcy5wcmV2U2hvdyA9IHRvU2hvdztcblx0XHR0aGlzLnByZXZIaWRlID0gdG9IaWRlO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuYW5pbWF0ZSApIHtcblx0XHRcdHRoaXMuX2FuaW1hdGUoIHRvU2hvdywgdG9IaWRlLCBkYXRhICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRvSGlkZS5oaWRlKCk7XG5cdFx0XHR0b1Nob3cuc2hvdygpO1xuXHRcdFx0dGhpcy5fdG9nZ2xlQ29tcGxldGUoIGRhdGEgKTtcblx0XHR9XG5cblx0XHR0b0hpZGUuYXR0cigge1xuXHRcdFx0XCJhcmlhLWhpZGRlblwiOiBcInRydWVcIlxuXHRcdH0gKTtcblx0XHR0b0hpZGUucHJldigpLmF0dHIoIHtcblx0XHRcdFwiYXJpYS1zZWxlY3RlZFwiOiBcImZhbHNlXCIsXG5cdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJmYWxzZVwiXG5cdFx0fSApO1xuXG5cdFx0Ly8gaWYgd2UncmUgc3dpdGNoaW5nIHBhbmVscywgcmVtb3ZlIHRoZSBvbGQgaGVhZGVyIGZyb20gdGhlIHRhYiBvcmRlclxuXHRcdC8vIGlmIHdlJ3JlIG9wZW5pbmcgZnJvbSBjb2xsYXBzZWQgc3RhdGUsIHJlbW92ZSB0aGUgcHJldmlvdXMgaGVhZGVyIGZyb20gdGhlIHRhYiBvcmRlclxuXHRcdC8vIGlmIHdlJ3JlIGNvbGxhcHNpbmcsIHRoZW4ga2VlcCB0aGUgY29sbGFwc2luZyBoZWFkZXIgaW4gdGhlIHRhYiBvcmRlclxuXHRcdGlmICggdG9TaG93Lmxlbmd0aCAmJiB0b0hpZGUubGVuZ3RoICkge1xuXHRcdFx0dG9IaWRlLnByZXYoKS5hdHRyKCB7XG5cdFx0XHRcdFwidGFiSW5kZXhcIjogLTEsXG5cdFx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcImZhbHNlXCJcblx0XHRcdH0gKTtcblx0XHR9IGVsc2UgaWYgKCB0b1Nob3cubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5oZWFkZXJzLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiBwYXJzZUludCggJCggdGhpcyApLmF0dHIoIFwidGFiSW5kZXhcIiApLCAxMCApID09PSAwO1xuXHRcdFx0fSApXG5cdFx0XHRcdC5hdHRyKCBcInRhYkluZGV4XCIsIC0xICk7XG5cdFx0fVxuXG5cdFx0dG9TaG93XG5cdFx0XHQuYXR0ciggXCJhcmlhLWhpZGRlblwiLCBcImZhbHNlXCIgKVxuXHRcdFx0LnByZXYoKVxuXHRcdFx0XHQuYXR0cigge1xuXHRcdFx0XHRcdFwiYXJpYS1zZWxlY3RlZFwiOiBcInRydWVcIixcblx0XHRcdFx0XHRcImFyaWEtZXhwYW5kZWRcIjogXCJ0cnVlXCIsXG5cdFx0XHRcdFx0dGFiSW5kZXg6IDBcblx0XHRcdFx0fSApO1xuXHR9LFxuXG5cdF9hbmltYXRlOiBmdW5jdGlvbiggdG9TaG93LCB0b0hpZGUsIGRhdGEgKSB7XG5cdFx0dmFyIHRvdGFsLCBlYXNpbmcsIGR1cmF0aW9uLFxuXHRcdFx0dGhhdCA9IHRoaXMsXG5cdFx0XHRhZGp1c3QgPSAwLFxuXHRcdFx0Ym94U2l6aW5nID0gdG9TaG93LmNzcyggXCJib3gtc2l6aW5nXCIgKSxcblx0XHRcdGRvd24gPSB0b1Nob3cubGVuZ3RoICYmXG5cdFx0XHRcdCggIXRvSGlkZS5sZW5ndGggfHwgKCB0b1Nob3cuaW5kZXgoKSA8IHRvSGlkZS5pbmRleCgpICkgKSxcblx0XHRcdGFuaW1hdGUgPSB0aGlzLm9wdGlvbnMuYW5pbWF0ZSB8fCB7fSxcblx0XHRcdG9wdGlvbnMgPSBkb3duICYmIGFuaW1hdGUuZG93biB8fCBhbmltYXRlLFxuXHRcdFx0Y29tcGxldGUgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhhdC5fdG9nZ2xlQ29tcGxldGUoIGRhdGEgKTtcblx0XHRcdH07XG5cblx0XHRpZiAoIHR5cGVvZiBvcHRpb25zID09PSBcIm51bWJlclwiICkge1xuXHRcdFx0ZHVyYXRpb24gPSBvcHRpb25zO1xuXHRcdH1cblx0XHRpZiAoIHR5cGVvZiBvcHRpb25zID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0ZWFzaW5nID0gb3B0aW9ucztcblx0XHR9XG5cblx0XHQvLyBmYWxsIGJhY2sgZnJvbSBvcHRpb25zIHRvIGFuaW1hdGlvbiBpbiBjYXNlIG9mIHBhcnRpYWwgZG93biBzZXR0aW5nc1xuXHRcdGVhc2luZyA9IGVhc2luZyB8fCBvcHRpb25zLmVhc2luZyB8fCBhbmltYXRlLmVhc2luZztcblx0XHRkdXJhdGlvbiA9IGR1cmF0aW9uIHx8IG9wdGlvbnMuZHVyYXRpb24gfHwgYW5pbWF0ZS5kdXJhdGlvbjtcblxuXHRcdGlmICggIXRvSGlkZS5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4gdG9TaG93LmFuaW1hdGUoIHRoaXMuc2hvd1Byb3BzLCBkdXJhdGlvbiwgZWFzaW5nLCBjb21wbGV0ZSApO1xuXHRcdH1cblx0XHRpZiAoICF0b1Nob3cubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuIHRvSGlkZS5hbmltYXRlKCB0aGlzLmhpZGVQcm9wcywgZHVyYXRpb24sIGVhc2luZywgY29tcGxldGUgKTtcblx0XHR9XG5cblx0XHR0b3RhbCA9IHRvU2hvdy5zaG93KCkub3V0ZXJIZWlnaHQoKTtcblx0XHR0b0hpZGUuYW5pbWF0ZSggdGhpcy5oaWRlUHJvcHMsIHtcblx0XHRcdGR1cmF0aW9uOiBkdXJhdGlvbixcblx0XHRcdGVhc2luZzogZWFzaW5nLFxuXHRcdFx0c3RlcDogZnVuY3Rpb24oIG5vdywgZnggKSB7XG5cdFx0XHRcdGZ4Lm5vdyA9IE1hdGgucm91bmQoIG5vdyApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XHR0b1Nob3dcblx0XHRcdC5oaWRlKClcblx0XHRcdC5hbmltYXRlKCB0aGlzLnNob3dQcm9wcywge1xuXHRcdFx0XHRkdXJhdGlvbjogZHVyYXRpb24sXG5cdFx0XHRcdGVhc2luZzogZWFzaW5nLFxuXHRcdFx0XHRjb21wbGV0ZTogY29tcGxldGUsXG5cdFx0XHRcdHN0ZXA6IGZ1bmN0aW9uKCBub3csIGZ4ICkge1xuXHRcdFx0XHRcdGZ4Lm5vdyA9IE1hdGgucm91bmQoIG5vdyApO1xuXHRcdFx0XHRcdGlmICggZngucHJvcCAhPT0gXCJoZWlnaHRcIiApIHtcblx0XHRcdFx0XHRcdGlmICggYm94U2l6aW5nID09PSBcImNvbnRlbnQtYm94XCIgKSB7XG5cdFx0XHRcdFx0XHRcdGFkanVzdCArPSBmeC5ub3c7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fSBlbHNlIGlmICggdGhhdC5vcHRpb25zLmhlaWdodFN0eWxlICE9PSBcImNvbnRlbnRcIiApIHtcblx0XHRcdFx0XHRcdGZ4Lm5vdyA9IE1hdGgucm91bmQoIHRvdGFsIC0gdG9IaWRlLm91dGVySGVpZ2h0KCkgLSBhZGp1c3QgKTtcblx0XHRcdFx0XHRcdGFkanVzdCA9IDA7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cdH0sXG5cblx0X3RvZ2dsZUNvbXBsZXRlOiBmdW5jdGlvbiggZGF0YSApIHtcblx0XHR2YXIgdG9IaWRlID0gZGF0YS5vbGRQYW5lbCxcblx0XHRcdHByZXYgPSB0b0hpZGUucHJldigpO1xuXG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRvSGlkZSwgXCJ1aS1hY2NvcmRpb24tY29udGVudC1hY3RpdmVcIiApO1xuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBwcmV2LCBcInVpLWFjY29yZGlvbi1oZWFkZXItYWN0aXZlXCIgKVxuXHRcdFx0Ll9hZGRDbGFzcyggcHJldiwgXCJ1aS1hY2NvcmRpb24taGVhZGVyLWNvbGxhcHNlZFwiICk7XG5cblx0XHQvLyBXb3JrIGFyb3VuZCBmb3IgcmVuZGVyaW5nIGJ1ZyBpbiBJRSAoIzU0MjEpXG5cdFx0aWYgKCB0b0hpZGUubGVuZ3RoICkge1xuXHRcdFx0dG9IaWRlLnBhcmVudCgpWyAwIF0uY2xhc3NOYW1lID0gdG9IaWRlLnBhcmVudCgpWyAwIF0uY2xhc3NOYW1lO1xuXHRcdH1cblx0XHR0aGlzLl90cmlnZ2VyKCBcImFjdGl2YXRlXCIsIG51bGwsIGRhdGEgKTtcblx0fVxufSApO1xuXG5cblxudmFyIHNhZmVBY3RpdmVFbGVtZW50ID0gJC51aS5zYWZlQWN0aXZlRWxlbWVudCA9IGZ1bmN0aW9uKCBkb2N1bWVudCApIHtcblx0dmFyIGFjdGl2ZUVsZW1lbnQ7XG5cblx0Ly8gU3VwcG9ydDogSUUgOSBvbmx5XG5cdC8vIElFOSB0aHJvd3MgYW4gXCJVbnNwZWNpZmllZCBlcnJvclwiIGFjY2Vzc2luZyBkb2N1bWVudC5hY3RpdmVFbGVtZW50IGZyb20gYW4gPGlmcmFtZT5cblx0dHJ5IHtcblx0XHRhY3RpdmVFbGVtZW50ID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudDtcblx0fSBjYXRjaCAoIGVycm9yICkge1xuXHRcdGFjdGl2ZUVsZW1lbnQgPSBkb2N1bWVudC5ib2R5O1xuXHR9XG5cblx0Ly8gU3VwcG9ydDogSUUgOSAtIDExIG9ubHlcblx0Ly8gSUUgbWF5IHJldHVybiBudWxsIGluc3RlYWQgb2YgYW4gZWxlbWVudFxuXHQvLyBJbnRlcmVzdGluZ2x5LCB0aGlzIG9ubHkgc2VlbXMgdG8gb2NjdXIgd2hlbiBOT1QgaW4gYW4gaWZyYW1lXG5cdGlmICggIWFjdGl2ZUVsZW1lbnQgKSB7XG5cdFx0YWN0aXZlRWxlbWVudCA9IGRvY3VtZW50LmJvZHk7XG5cdH1cblxuXHQvLyBTdXBwb3J0OiBJRSAxMSBvbmx5XG5cdC8vIElFMTEgcmV0dXJucyBhIHNlZW1pbmdseSBlbXB0eSBvYmplY3QgaW4gc29tZSBjYXNlcyB3aGVuIGFjY2Vzc2luZ1xuXHQvLyBkb2N1bWVudC5hY3RpdmVFbGVtZW50IGZyb20gYW4gPGlmcmFtZT5cblx0aWYgKCAhYWN0aXZlRWxlbWVudC5ub2RlTmFtZSApIHtcblx0XHRhY3RpdmVFbGVtZW50ID0gZG9jdW1lbnQuYm9keTtcblx0fVxuXG5cdHJldHVybiBhY3RpdmVFbGVtZW50O1xufTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBNZW51IDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBNZW51XG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogQ3JlYXRlcyBuZXN0YWJsZSBtZW51cy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9tZW51L1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL21lbnUvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9tZW51LmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG52YXIgd2lkZ2V0c01lbnUgPSAkLndpZGdldCggXCJ1aS5tZW51XCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0ZGVmYXVsdEVsZW1lbnQ6IFwiPHVsPlwiLFxuXHRkZWxheTogMzAwLFxuXHRvcHRpb25zOiB7XG5cdFx0aWNvbnM6IHtcblx0XHRcdHN1Ym1lbnU6IFwidWktaWNvbi1jYXJldC0xLWVcIlxuXHRcdH0sXG5cdFx0aXRlbXM6IFwiPiAqXCIsXG5cdFx0bWVudXM6IFwidWxcIixcblx0XHRwb3NpdGlvbjoge1xuXHRcdFx0bXk6IFwibGVmdCB0b3BcIixcblx0XHRcdGF0OiBcInJpZ2h0IHRvcFwiXG5cdFx0fSxcblx0XHRyb2xlOiBcIm1lbnVcIixcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGJsdXI6IG51bGwsXG5cdFx0Zm9jdXM6IG51bGwsXG5cdFx0c2VsZWN0OiBudWxsXG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5hY3RpdmVNZW51ID0gdGhpcy5lbGVtZW50O1xuXG5cdFx0Ly8gRmxhZyB1c2VkIHRvIHByZXZlbnQgZmlyaW5nIG9mIHRoZSBjbGljayBoYW5kbGVyXG5cdFx0Ly8gYXMgdGhlIGV2ZW50IGJ1YmJsZXMgdXAgdGhyb3VnaCBuZXN0ZWQgbWVudXNcblx0XHR0aGlzLm1vdXNlSGFuZGxlZCA9IGZhbHNlO1xuXHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0LnVuaXF1ZUlkKClcblx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdHJvbGU6IHRoaXMub3B0aW9ucy5yb2xlLFxuXHRcdFx0XHR0YWJJbmRleDogMFxuXHRcdFx0fSApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktbWVudVwiLCBcInVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudFwiICk7XG5cdFx0dGhpcy5fb24oIHtcblxuXHRcdFx0Ly8gUHJldmVudCBmb2N1cyBmcm9tIHN0aWNraW5nIHRvIGxpbmtzIGluc2lkZSBtZW51IGFmdGVyIGNsaWNraW5nXG5cdFx0XHQvLyB0aGVtIChmb2N1cyBzaG91bGQgYWx3YXlzIHN0YXkgb24gVUwgZHVyaW5nIG5hdmlnYXRpb24pLlxuXHRcdFx0XCJtb3VzZWRvd24gLnVpLW1lbnUtaXRlbVwiOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHR9LFxuXHRcdFx0XCJjbGljayAudWktbWVudS1pdGVtXCI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dmFyIHRhcmdldCA9ICQoIGV2ZW50LnRhcmdldCApO1xuXHRcdFx0XHR2YXIgYWN0aXZlID0gJCggJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICkgKTtcblx0XHRcdFx0aWYgKCAhdGhpcy5tb3VzZUhhbmRsZWQgJiYgdGFyZ2V0Lm5vdCggXCIudWktc3RhdGUtZGlzYWJsZWRcIiApLmxlbmd0aCApIHtcblx0XHRcdFx0XHR0aGlzLnNlbGVjdCggZXZlbnQgKTtcblxuXHRcdFx0XHRcdC8vIE9ubHkgc2V0IHRoZSBtb3VzZUhhbmRsZWQgZmxhZyBpZiB0aGUgZXZlbnQgd2lsbCBidWJibGUsIHNlZSAjOTQ2OS5cblx0XHRcdFx0XHRpZiAoICFldmVudC5pc1Byb3BhZ2F0aW9uU3RvcHBlZCgpICkge1xuXHRcdFx0XHRcdFx0dGhpcy5tb3VzZUhhbmRsZWQgPSB0cnVlO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIE9wZW4gc3VibWVudSBvbiBjbGlja1xuXHRcdFx0XHRcdGlmICggdGFyZ2V0LmhhcyggXCIudWktbWVudVwiICkubGVuZ3RoICkge1xuXHRcdFx0XHRcdFx0dGhpcy5leHBhbmQoIGV2ZW50ICk7XG5cdFx0XHRcdFx0fSBlbHNlIGlmICggIXRoaXMuZWxlbWVudC5pcyggXCI6Zm9jdXNcIiApICYmXG5cdFx0XHRcdFx0XHRcdGFjdGl2ZS5jbG9zZXN0KCBcIi51aS1tZW51XCIgKS5sZW5ndGggKSB7XG5cblx0XHRcdFx0XHRcdC8vIFJlZGlyZWN0IGZvY3VzIHRvIHRoZSBtZW51XG5cdFx0XHRcdFx0XHR0aGlzLmVsZW1lbnQudHJpZ2dlciggXCJmb2N1c1wiLCBbIHRydWUgXSApO1xuXG5cdFx0XHRcdFx0XHQvLyBJZiB0aGUgYWN0aXZlIGl0ZW0gaXMgb24gdGhlIHRvcCBsZXZlbCwgbGV0IGl0IHN0YXkgYWN0aXZlLlxuXHRcdFx0XHRcdFx0Ly8gT3RoZXJ3aXNlLCBibHVyIHRoZSBhY3RpdmUgaXRlbSBzaW5jZSBpdCBpcyBubyBsb25nZXIgdmlzaWJsZS5cblx0XHRcdFx0XHRcdGlmICggdGhpcy5hY3RpdmUgJiYgdGhpcy5hY3RpdmUucGFyZW50cyggXCIudWktbWVudVwiICkubGVuZ3RoID09PSAxICkge1xuXHRcdFx0XHRcdFx0XHRjbGVhclRpbWVvdXQoIHRoaXMudGltZXIgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRcIm1vdXNlZW50ZXIgLnVpLW1lbnUtaXRlbVwiOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHRcdFx0Ly8gSWdub3JlIG1vdXNlIGV2ZW50cyB3aGlsZSB0eXBlYWhlYWQgaXMgYWN0aXZlLCBzZWUgIzEwNDU4LlxuXHRcdFx0XHQvLyBQcmV2ZW50cyBmb2N1c2luZyB0aGUgd3JvbmcgaXRlbSB3aGVuIHR5cGVhaGVhZCBjYXVzZXMgYSBzY3JvbGwgd2hpbGUgdGhlIG1vdXNlXG5cdFx0XHRcdC8vIGlzIG92ZXIgYW4gaXRlbSBpbiB0aGUgbWVudVxuXHRcdFx0XHRpZiAoIHRoaXMucHJldmlvdXNGaWx0ZXIgKSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dmFyIGFjdHVhbFRhcmdldCA9ICQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIFwiLnVpLW1lbnUtaXRlbVwiICksXG5cdFx0XHRcdFx0dGFyZ2V0ID0gJCggZXZlbnQuY3VycmVudFRhcmdldCApO1xuXG5cdFx0XHRcdC8vIElnbm9yZSBidWJibGVkIGV2ZW50cyBvbiBwYXJlbnQgaXRlbXMsIHNlZSAjMTE2NDFcblx0XHRcdFx0aWYgKCBhY3R1YWxUYXJnZXRbIDAgXSAhPT0gdGFyZ2V0WyAwIF0gKSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUmVtb3ZlIHVpLXN0YXRlLWFjdGl2ZSBjbGFzcyBmcm9tIHNpYmxpbmdzIG9mIHRoZSBuZXdseSBmb2N1c2VkIG1lbnUgaXRlbVxuXHRcdFx0XHQvLyB0byBhdm9pZCBhIGp1bXAgY2F1c2VkIGJ5IGFkamFjZW50IGVsZW1lbnRzIGJvdGggaGF2aW5nIGEgY2xhc3Mgd2l0aCBhIGJvcmRlclxuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGFyZ2V0LnNpYmxpbmdzKCkuY2hpbGRyZW4oIFwiLnVpLXN0YXRlLWFjdGl2ZVwiICksXG5cdFx0XHRcdFx0bnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0XHR0aGlzLmZvY3VzKCBldmVudCwgdGFyZ2V0ICk7XG5cdFx0XHR9LFxuXHRcdFx0bW91c2VsZWF2ZTogXCJjb2xsYXBzZUFsbFwiLFxuXHRcdFx0XCJtb3VzZWxlYXZlIC51aS1tZW51XCI6IFwiY29sbGFwc2VBbGxcIixcblx0XHRcdGZvY3VzOiBmdW5jdGlvbiggZXZlbnQsIGtlZXBBY3RpdmVJdGVtICkge1xuXG5cdFx0XHRcdC8vIElmIHRoZXJlJ3MgYWxyZWFkeSBhbiBhY3RpdmUgaXRlbSwga2VlcCBpdCBhY3RpdmVcblx0XHRcdFx0Ly8gSWYgbm90LCBhY3RpdmF0ZSB0aGUgZmlyc3QgaXRlbVxuXHRcdFx0XHR2YXIgaXRlbSA9IHRoaXMuYWN0aXZlIHx8IHRoaXMuZWxlbWVudC5maW5kKCB0aGlzLm9wdGlvbnMuaXRlbXMgKS5lcSggMCApO1xuXG5cdFx0XHRcdGlmICggIWtlZXBBY3RpdmVJdGVtICkge1xuXHRcdFx0XHRcdHRoaXMuZm9jdXMoIGV2ZW50LCBpdGVtICk7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRibHVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR2YXIgbm90Q29udGFpbmVkID0gISQuY29udGFpbnMoXG5cdFx0XHRcdFx0XHR0aGlzLmVsZW1lbnRbIDAgXSxcblx0XHRcdFx0XHRcdCQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRpZiAoIG5vdENvbnRhaW5lZCApIHtcblx0XHRcdFx0XHRcdHRoaXMuY29sbGFwc2VBbGwoIGV2ZW50ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9LFxuXHRcdFx0a2V5ZG93bjogXCJfa2V5ZG93blwiXG5cdFx0fSApO1xuXG5cdFx0dGhpcy5yZWZyZXNoKCk7XG5cblx0XHQvLyBDbGlja3Mgb3V0c2lkZSBvZiBhIG1lbnUgY29sbGFwc2UgYW55IG9wZW4gbWVudXNcblx0XHR0aGlzLl9vbiggdGhpcy5kb2N1bWVudCwge1xuXHRcdFx0Y2xpY2s6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCB0aGlzLl9jbG9zZU9uRG9jdW1lbnRDbGljayggZXZlbnQgKSApIHtcblx0XHRcdFx0XHR0aGlzLmNvbGxhcHNlQWxsKCBldmVudCApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUmVzZXQgdGhlIG1vdXNlSGFuZGxlZCBmbGFnXG5cdFx0XHRcdHRoaXMubW91c2VIYW5kbGVkID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgaXRlbXMgPSB0aGlzLmVsZW1lbnQuZmluZCggXCIudWktbWVudS1pdGVtXCIgKVxuXHRcdFx0XHQucmVtb3ZlQXR0ciggXCJyb2xlIGFyaWEtZGlzYWJsZWRcIiApLFxuXHRcdFx0c3VibWVudXMgPSBpdGVtcy5jaGlsZHJlbiggXCIudWktbWVudS1pdGVtLXdyYXBwZXJcIiApXG5cdFx0XHRcdC5yZW1vdmVVbmlxdWVJZCgpXG5cdFx0XHRcdC5yZW1vdmVBdHRyKCBcInRhYkluZGV4IHJvbGUgYXJpYS1oYXNwb3B1cFwiICk7XG5cblx0XHQvLyBEZXN0cm95IChzdWIpbWVudXNcblx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdC5yZW1vdmVBdHRyKCBcImFyaWEtYWN0aXZlZGVzY2VuZGFudFwiIClcblx0XHRcdC5maW5kKCBcIi51aS1tZW51XCIgKS5hZGRCYWNrKClcblx0XHRcdFx0LnJlbW92ZUF0dHIoIFwicm9sZSBhcmlhLWxhYmVsbGVkYnkgYXJpYS1leHBhbmRlZCBhcmlhLWhpZGRlbiBhcmlhLWRpc2FibGVkIFwiICtcblx0XHRcdFx0XHRcInRhYkluZGV4XCIgKVxuXHRcdFx0XHQucmVtb3ZlVW5pcXVlSWQoKVxuXHRcdFx0XHQuc2hvdygpO1xuXG5cdFx0c3VibWVudXMuY2hpbGRyZW4oKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBlbGVtID0gJCggdGhpcyApO1xuXHRcdFx0aWYgKCBlbGVtLmRhdGEoIFwidWktbWVudS1zdWJtZW51LWNhcmV0XCIgKSApIHtcblx0XHRcdFx0ZWxlbS5yZW1vdmUoKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X2tleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgbWF0Y2gsIHByZXYsIGNoYXJhY3Rlciwgc2tpcCxcblx0XHRcdHByZXZlbnREZWZhdWx0ID0gdHJ1ZTtcblxuXHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuUEFHRV9VUDpcblx0XHRcdHRoaXMucHJldmlvdXNQYWdlKCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuUEFHRV9ET1dOOlxuXHRcdFx0dGhpcy5uZXh0UGFnZSggZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkhPTUU6XG5cdFx0XHR0aGlzLl9tb3ZlKCBcImZpcnN0XCIsIFwiZmlyc3RcIiwgZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkVORDpcblx0XHRcdHRoaXMuX21vdmUoIFwibGFzdFwiLCBcImxhc3RcIiwgZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLlVQOlxuXHRcdFx0dGhpcy5wcmV2aW91cyggZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLkRPV046XG5cdFx0XHR0aGlzLm5leHQoIGV2ZW50ICk7XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5MRUZUOlxuXHRcdFx0dGhpcy5jb2xsYXBzZSggZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGNhc2UgJC51aS5rZXlDb2RlLlJJR0hUOlxuXHRcdFx0aWYgKCB0aGlzLmFjdGl2ZSAmJiAhdGhpcy5hY3RpdmUuaXMoIFwiLnVpLXN0YXRlLWRpc2FibGVkXCIgKSApIHtcblx0XHRcdFx0dGhpcy5leHBhbmQoIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0XHRicmVhaztcblx0XHRjYXNlICQudWkua2V5Q29kZS5FTlRFUjpcblx0XHRjYXNlICQudWkua2V5Q29kZS5TUEFDRTpcblx0XHRcdHRoaXMuX2FjdGl2YXRlKCBldmVudCApO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuRVNDQVBFOlxuXHRcdFx0dGhpcy5jb2xsYXBzZSggZXZlbnQgKTtcblx0XHRcdGJyZWFrO1xuXHRcdGRlZmF1bHQ6XG5cdFx0XHRwcmV2ZW50RGVmYXVsdCA9IGZhbHNlO1xuXHRcdFx0cHJldiA9IHRoaXMucHJldmlvdXNGaWx0ZXIgfHwgXCJcIjtcblx0XHRcdHNraXAgPSBmYWxzZTtcblxuXHRcdFx0Ly8gU3VwcG9ydCBudW1iZXIgcGFkIHZhbHVlc1xuXHRcdFx0Y2hhcmFjdGVyID0gZXZlbnQua2V5Q29kZSA+PSA5NiAmJiBldmVudC5rZXlDb2RlIDw9IDEwNSA/XG5cdFx0XHRcdCggZXZlbnQua2V5Q29kZSAtIDk2ICkudG9TdHJpbmcoKSA6IFN0cmluZy5mcm9tQ2hhckNvZGUoIGV2ZW50LmtleUNvZGUgKTtcblxuXHRcdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLmZpbHRlclRpbWVyICk7XG5cblx0XHRcdGlmICggY2hhcmFjdGVyID09PSBwcmV2ICkge1xuXHRcdFx0XHRza2lwID0gdHJ1ZTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGNoYXJhY3RlciA9IHByZXYgKyBjaGFyYWN0ZXI7XG5cdFx0XHR9XG5cblx0XHRcdG1hdGNoID0gdGhpcy5fZmlsdGVyTWVudUl0ZW1zKCBjaGFyYWN0ZXIgKTtcblx0XHRcdG1hdGNoID0gc2tpcCAmJiBtYXRjaC5pbmRleCggdGhpcy5hY3RpdmUubmV4dCgpICkgIT09IC0xID9cblx0XHRcdFx0dGhpcy5hY3RpdmUubmV4dEFsbCggXCIudWktbWVudS1pdGVtXCIgKSA6XG5cdFx0XHRcdG1hdGNoO1xuXG5cdFx0XHQvLyBJZiBubyBtYXRjaGVzIG9uIHRoZSBjdXJyZW50IGZpbHRlciwgcmVzZXQgdG8gdGhlIGxhc3QgY2hhcmFjdGVyIHByZXNzZWRcblx0XHRcdC8vIHRvIG1vdmUgZG93biB0aGUgbWVudSB0byB0aGUgZmlyc3QgaXRlbSB0aGF0IHN0YXJ0cyB3aXRoIHRoYXQgY2hhcmFjdGVyXG5cdFx0XHRpZiAoICFtYXRjaC5sZW5ndGggKSB7XG5cdFx0XHRcdGNoYXJhY3RlciA9IFN0cmluZy5mcm9tQ2hhckNvZGUoIGV2ZW50LmtleUNvZGUgKTtcblx0XHRcdFx0bWF0Y2ggPSB0aGlzLl9maWx0ZXJNZW51SXRlbXMoIGNoYXJhY3RlciApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG1hdGNoLmxlbmd0aCApIHtcblx0XHRcdFx0dGhpcy5mb2N1cyggZXZlbnQsIG1hdGNoICk7XG5cdFx0XHRcdHRoaXMucHJldmlvdXNGaWx0ZXIgPSBjaGFyYWN0ZXI7XG5cdFx0XHRcdHRoaXMuZmlsdGVyVGltZXIgPSB0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0ZGVsZXRlIHRoaXMucHJldmlvdXNGaWx0ZXI7XG5cdFx0XHRcdH0sIDEwMDAgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGRlbGV0ZSB0aGlzLnByZXZpb3VzRmlsdGVyO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggcHJldmVudERlZmF1bHQgKSB7XG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdH1cblx0fSxcblxuXHRfYWN0aXZhdGU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoIHRoaXMuYWN0aXZlICYmICF0aGlzLmFjdGl2ZS5pcyggXCIudWktc3RhdGUtZGlzYWJsZWRcIiApICkge1xuXHRcdFx0aWYgKCB0aGlzLmFjdGl2ZS5jaGlsZHJlbiggXCJbYXJpYS1oYXNwb3B1cD0ndHJ1ZSddXCIgKS5sZW5ndGggKSB7XG5cdFx0XHRcdHRoaXMuZXhwYW5kKCBldmVudCApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5zZWxlY3QoIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdHJlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBtZW51cywgaXRlbXMsIG5ld1N1Ym1lbnVzLCBuZXdJdGVtcywgbmV3V3JhcHBlcnMsXG5cdFx0XHR0aGF0ID0gdGhpcyxcblx0XHRcdGljb24gPSB0aGlzLm9wdGlvbnMuaWNvbnMuc3VibWVudSxcblx0XHRcdHN1Ym1lbnVzID0gdGhpcy5lbGVtZW50LmZpbmQoIHRoaXMub3B0aW9ucy5tZW51cyApO1xuXG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIFwidWktbWVudS1pY29uc1wiLCBudWxsLCAhIXRoaXMuZWxlbWVudC5maW5kKCBcIi51aS1pY29uXCIgKS5sZW5ndGggKTtcblxuXHRcdC8vIEluaXRpYWxpemUgbmVzdGVkIG1lbnVzXG5cdFx0bmV3U3VibWVudXMgPSBzdWJtZW51cy5maWx0ZXIoIFwiOm5vdCgudWktbWVudSlcIiApXG5cdFx0XHQuaGlkZSgpXG5cdFx0XHQuYXR0cigge1xuXHRcdFx0XHRyb2xlOiB0aGlzLm9wdGlvbnMucm9sZSxcblx0XHRcdFx0XCJhcmlhLWhpZGRlblwiOiBcInRydWVcIixcblx0XHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwiZmFsc2VcIlxuXHRcdFx0fSApXG5cdFx0XHQuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBtZW51ID0gJCggdGhpcyApLFxuXHRcdFx0XHRcdGl0ZW0gPSBtZW51LnByZXYoKSxcblx0XHRcdFx0XHRzdWJtZW51Q2FyZXQgPSAkKCBcIjxzcGFuPlwiICkuZGF0YSggXCJ1aS1tZW51LXN1Ym1lbnUtY2FyZXRcIiwgdHJ1ZSApO1xuXG5cdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBzdWJtZW51Q2FyZXQsIFwidWktbWVudS1pY29uXCIsIFwidWktaWNvbiBcIiArIGljb24gKTtcblx0XHRcdFx0aXRlbVxuXHRcdFx0XHRcdC5hdHRyKCBcImFyaWEtaGFzcG9wdXBcIiwgXCJ0cnVlXCIgKVxuXHRcdFx0XHRcdC5wcmVwZW5kKCBzdWJtZW51Q2FyZXQgKTtcblx0XHRcdFx0bWVudS5hdHRyKCBcImFyaWEtbGFiZWxsZWRieVwiLCBpdGVtLmF0dHIoIFwiaWRcIiApICk7XG5cdFx0XHR9ICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggbmV3U3VibWVudXMsIFwidWktbWVudVwiLCBcInVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudCB1aS1mcm9udFwiICk7XG5cblx0XHRtZW51cyA9IHN1Ym1lbnVzLmFkZCggdGhpcy5lbGVtZW50ICk7XG5cdFx0aXRlbXMgPSBtZW51cy5maW5kKCB0aGlzLm9wdGlvbnMuaXRlbXMgKTtcblxuXHRcdC8vIEluaXRpYWxpemUgbWVudS1pdGVtcyBjb250YWluaW5nIHNwYWNlcyBhbmQvb3IgZGFzaGVzIG9ubHkgYXMgZGl2aWRlcnNcblx0XHRpdGVtcy5ub3QoIFwiLnVpLW1lbnUtaXRlbVwiICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgaXRlbSA9ICQoIHRoaXMgKTtcblx0XHRcdGlmICggdGhhdC5faXNEaXZpZGVyKCBpdGVtICkgKSB7XG5cdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBpdGVtLCBcInVpLW1lbnUtZGl2aWRlclwiLCBcInVpLXdpZGdldC1jb250ZW50XCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHQvLyBEb24ndCByZWZyZXNoIGxpc3QgaXRlbXMgdGhhdCBhcmUgYWxyZWFkeSBhZGFwdGVkXG5cdFx0bmV3SXRlbXMgPSBpdGVtcy5ub3QoIFwiLnVpLW1lbnUtaXRlbSwgLnVpLW1lbnUtZGl2aWRlclwiICk7XG5cdFx0bmV3V3JhcHBlcnMgPSBuZXdJdGVtcy5jaGlsZHJlbigpXG5cdFx0XHQubm90KCBcIi51aS1tZW51XCIgKVxuXHRcdFx0XHQudW5pcXVlSWQoKVxuXHRcdFx0XHQuYXR0cigge1xuXHRcdFx0XHRcdHRhYkluZGV4OiAtMSxcblx0XHRcdFx0XHRyb2xlOiB0aGlzLl9pdGVtUm9sZSgpXG5cdFx0XHRcdH0gKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggbmV3SXRlbXMsIFwidWktbWVudS1pdGVtXCIgKVxuXHRcdFx0Ll9hZGRDbGFzcyggbmV3V3JhcHBlcnMsIFwidWktbWVudS1pdGVtLXdyYXBwZXJcIiApO1xuXG5cdFx0Ly8gQWRkIGFyaWEtZGlzYWJsZWQgYXR0cmlidXRlIHRvIGFueSBkaXNhYmxlZCBtZW51IGl0ZW1cblx0XHRpdGVtcy5maWx0ZXIoIFwiLnVpLXN0YXRlLWRpc2FibGVkXCIgKS5hdHRyKCBcImFyaWEtZGlzYWJsZWRcIiwgXCJ0cnVlXCIgKTtcblxuXHRcdC8vIElmIHRoZSBhY3RpdmUgaXRlbSBoYXMgYmVlbiByZW1vdmVkLCBibHVyIHRoZSBtZW51XG5cdFx0aWYgKCB0aGlzLmFjdGl2ZSAmJiAhJC5jb250YWlucyggdGhpcy5lbGVtZW50WyAwIF0sIHRoaXMuYWN0aXZlWyAwIF0gKSApIHtcblx0XHRcdHRoaXMuYmx1cigpO1xuXHRcdH1cblx0fSxcblxuXHRfaXRlbVJvbGU6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB7XG5cdFx0XHRtZW51OiBcIm1lbnVpdGVtXCIsXG5cdFx0XHRsaXN0Ym94OiBcIm9wdGlvblwiXG5cdFx0fVsgdGhpcy5vcHRpb25zLnJvbGUgXTtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRpZiAoIGtleSA9PT0gXCJpY29uc1wiICkge1xuXHRcdFx0dmFyIGljb25zID0gdGhpcy5lbGVtZW50LmZpbmQoIFwiLnVpLW1lbnUtaWNvblwiICk7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggaWNvbnMsIG51bGwsIHRoaXMub3B0aW9ucy5pY29ucy5zdWJtZW51IClcblx0XHRcdFx0Ll9hZGRDbGFzcyggaWNvbnMsIG51bGwsIHZhbHVlLnN1Ym1lbnUgKTtcblx0XHR9XG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uRGlzYWJsZWQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlciggdmFsdWUgKTtcblxuXHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcImFyaWEtZGlzYWJsZWRcIiwgU3RyaW5nKCB2YWx1ZSApICk7XG5cdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiwgISF2YWx1ZSApO1xuXHR9LFxuXG5cdGZvY3VzOiBmdW5jdGlvbiggZXZlbnQsIGl0ZW0gKSB7XG5cdFx0dmFyIG5lc3RlZCwgZm9jdXNlZCwgYWN0aXZlUGFyZW50O1xuXHRcdHRoaXMuYmx1ciggZXZlbnQsIGV2ZW50ICYmIGV2ZW50LnR5cGUgPT09IFwiZm9jdXNcIiApO1xuXG5cdFx0dGhpcy5fc2Nyb2xsSW50b1ZpZXcoIGl0ZW0gKTtcblxuXHRcdHRoaXMuYWN0aXZlID0gaXRlbS5maXJzdCgpO1xuXG5cdFx0Zm9jdXNlZCA9IHRoaXMuYWN0aXZlLmNoaWxkcmVuKCBcIi51aS1tZW51LWl0ZW0td3JhcHBlclwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIGZvY3VzZWQsIG51bGwsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblxuXHRcdC8vIE9ubHkgdXBkYXRlIGFyaWEtYWN0aXZlZGVzY2VuZGFudCBpZiB0aGVyZSdzIGEgcm9sZVxuXHRcdC8vIG90aGVyd2lzZSB3ZSBhc3N1bWUgZm9jdXMgaXMgbWFuYWdlZCBlbHNld2hlcmVcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5yb2xlICkge1xuXHRcdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwiYXJpYS1hY3RpdmVkZXNjZW5kYW50XCIsIGZvY3VzZWQuYXR0ciggXCJpZFwiICkgKTtcblx0XHR9XG5cblx0XHQvLyBIaWdobGlnaHQgYWN0aXZlIHBhcmVudCBtZW51IGl0ZW0sIGlmIGFueVxuXHRcdGFjdGl2ZVBhcmVudCA9IHRoaXMuYWN0aXZlXG5cdFx0XHQucGFyZW50KClcblx0XHRcdFx0LmNsb3Nlc3QoIFwiLnVpLW1lbnUtaXRlbVwiIClcblx0XHRcdFx0XHQuY2hpbGRyZW4oIFwiLnVpLW1lbnUtaXRlbS13cmFwcGVyXCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggYWN0aXZlUGFyZW50LCBudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cblx0XHRpZiAoIGV2ZW50ICYmIGV2ZW50LnR5cGUgPT09IFwia2V5ZG93blwiICkge1xuXHRcdFx0dGhpcy5fY2xvc2UoKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy50aW1lciA9IHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5fY2xvc2UoKTtcblx0XHRcdH0sIHRoaXMuZGVsYXkgKTtcblx0XHR9XG5cblx0XHRuZXN0ZWQgPSBpdGVtLmNoaWxkcmVuKCBcIi51aS1tZW51XCIgKTtcblx0XHRpZiAoIG5lc3RlZC5sZW5ndGggJiYgZXZlbnQgJiYgKCAvXm1vdXNlLy50ZXN0KCBldmVudC50eXBlICkgKSApIHtcblx0XHRcdHRoaXMuX3N0YXJ0T3BlbmluZyggbmVzdGVkICk7XG5cdFx0fVxuXHRcdHRoaXMuYWN0aXZlTWVudSA9IGl0ZW0ucGFyZW50KCk7XG5cblx0XHR0aGlzLl90cmlnZ2VyKCBcImZvY3VzXCIsIGV2ZW50LCB7IGl0ZW06IGl0ZW0gfSApO1xuXHR9LFxuXG5cdF9zY3JvbGxJbnRvVmlldzogZnVuY3Rpb24oIGl0ZW0gKSB7XG5cdFx0dmFyIGJvcmRlclRvcCwgcGFkZGluZ1RvcCwgb2Zmc2V0LCBzY3JvbGwsIGVsZW1lbnRIZWlnaHQsIGl0ZW1IZWlnaHQ7XG5cdFx0aWYgKCB0aGlzLl9oYXNTY3JvbGwoKSApIHtcblx0XHRcdGJvcmRlclRvcCA9IHBhcnNlRmxvYXQoICQuY3NzKCB0aGlzLmFjdGl2ZU1lbnVbIDAgXSwgXCJib3JkZXJUb3BXaWR0aFwiICkgKSB8fCAwO1xuXHRcdFx0cGFkZGluZ1RvcCA9IHBhcnNlRmxvYXQoICQuY3NzKCB0aGlzLmFjdGl2ZU1lbnVbIDAgXSwgXCJwYWRkaW5nVG9wXCIgKSApIHx8IDA7XG5cdFx0XHRvZmZzZXQgPSBpdGVtLm9mZnNldCgpLnRvcCAtIHRoaXMuYWN0aXZlTWVudS5vZmZzZXQoKS50b3AgLSBib3JkZXJUb3AgLSBwYWRkaW5nVG9wO1xuXHRcdFx0c2Nyb2xsID0gdGhpcy5hY3RpdmVNZW51LnNjcm9sbFRvcCgpO1xuXHRcdFx0ZWxlbWVudEhlaWdodCA9IHRoaXMuYWN0aXZlTWVudS5oZWlnaHQoKTtcblx0XHRcdGl0ZW1IZWlnaHQgPSBpdGVtLm91dGVySGVpZ2h0KCk7XG5cblx0XHRcdGlmICggb2Zmc2V0IDwgMCApIHtcblx0XHRcdFx0dGhpcy5hY3RpdmVNZW51LnNjcm9sbFRvcCggc2Nyb2xsICsgb2Zmc2V0ICk7XG5cdFx0XHR9IGVsc2UgaWYgKCBvZmZzZXQgKyBpdGVtSGVpZ2h0ID4gZWxlbWVudEhlaWdodCApIHtcblx0XHRcdFx0dGhpcy5hY3RpdmVNZW51LnNjcm9sbFRvcCggc2Nyb2xsICsgb2Zmc2V0IC0gZWxlbWVudEhlaWdodCArIGl0ZW1IZWlnaHQgKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0Ymx1cjogZnVuY3Rpb24oIGV2ZW50LCBmcm9tRm9jdXMgKSB7XG5cdFx0aWYgKCAhZnJvbUZvY3VzICkge1xuXHRcdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnRpbWVyICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhdGhpcy5hY3RpdmUgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuYWN0aXZlLmNoaWxkcmVuKCBcIi51aS1tZW51LWl0ZW0td3JhcHBlclwiICksXG5cdFx0XHRudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cblx0XHR0aGlzLl90cmlnZ2VyKCBcImJsdXJcIiwgZXZlbnQsIHsgaXRlbTogdGhpcy5hY3RpdmUgfSApO1xuXHRcdHRoaXMuYWN0aXZlID0gbnVsbDtcblx0fSxcblxuXHRfc3RhcnRPcGVuaW5nOiBmdW5jdGlvbiggc3VibWVudSApIHtcblx0XHRjbGVhclRpbWVvdXQoIHRoaXMudGltZXIgKTtcblxuXHRcdC8vIERvbid0IG9wZW4gaWYgYWxyZWFkeSBvcGVuIGZpeGVzIGEgRmlyZWZveCBidWcgdGhhdCBjYXVzZWQgYSAuNSBwaXhlbFxuXHRcdC8vIHNoaWZ0IGluIHRoZSBzdWJtZW51IHBvc2l0aW9uIHdoZW4gbW91c2luZyBvdmVyIHRoZSBjYXJldCBpY29uXG5cdFx0aWYgKCBzdWJtZW51LmF0dHIoIFwiYXJpYS1oaWRkZW5cIiApICE9PSBcInRydWVcIiApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLnRpbWVyID0gdGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5fY2xvc2UoKTtcblx0XHRcdHRoaXMuX29wZW4oIHN1Ym1lbnUgKTtcblx0XHR9LCB0aGlzLmRlbGF5ICk7XG5cdH0sXG5cblx0X29wZW46IGZ1bmN0aW9uKCBzdWJtZW51ICkge1xuXHRcdHZhciBwb3NpdGlvbiA9ICQuZXh0ZW5kKCB7XG5cdFx0XHRvZjogdGhpcy5hY3RpdmVcblx0XHR9LCB0aGlzLm9wdGlvbnMucG9zaXRpb24gKTtcblxuXHRcdGNsZWFyVGltZW91dCggdGhpcy50aW1lciApO1xuXHRcdHRoaXMuZWxlbWVudC5maW5kKCBcIi51aS1tZW51XCIgKS5ub3QoIHN1Ym1lbnUucGFyZW50cyggXCIudWktbWVudVwiICkgKVxuXHRcdFx0LmhpZGUoKVxuXHRcdFx0LmF0dHIoIFwiYXJpYS1oaWRkZW5cIiwgXCJ0cnVlXCIgKTtcblxuXHRcdHN1Ym1lbnVcblx0XHRcdC5zaG93KClcblx0XHRcdC5yZW1vdmVBdHRyKCBcImFyaWEtaGlkZGVuXCIgKVxuXHRcdFx0LmF0dHIoIFwiYXJpYS1leHBhbmRlZFwiLCBcInRydWVcIiApXG5cdFx0XHQucG9zaXRpb24oIHBvc2l0aW9uICk7XG5cdH0sXG5cblx0Y29sbGFwc2VBbGw6IGZ1bmN0aW9uKCBldmVudCwgYWxsICkge1xuXHRcdGNsZWFyVGltZW91dCggdGhpcy50aW1lciApO1xuXHRcdHRoaXMudGltZXIgPSB0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIElmIHdlIHdlcmUgcGFzc2VkIGFuIGV2ZW50LCBsb29rIGZvciB0aGUgc3VibWVudSB0aGF0IGNvbnRhaW5zIHRoZSBldmVudFxuXHRcdFx0dmFyIGN1cnJlbnRNZW51ID0gYWxsID8gdGhpcy5lbGVtZW50IDpcblx0XHRcdFx0JCggZXZlbnQgJiYgZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggdGhpcy5lbGVtZW50LmZpbmQoIFwiLnVpLW1lbnVcIiApICk7XG5cblx0XHRcdC8vIElmIHdlIGZvdW5kIG5vIHZhbGlkIHN1Ym1lbnUgYW5jZXN0b3IsIHVzZSB0aGUgbWFpbiBtZW51IHRvIGNsb3NlIGFsbFxuXHRcdFx0Ly8gc3ViIG1lbnVzIGFueXdheVxuXHRcdFx0aWYgKCAhY3VycmVudE1lbnUubGVuZ3RoICkge1xuXHRcdFx0XHRjdXJyZW50TWVudSA9IHRoaXMuZWxlbWVudDtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fY2xvc2UoIGN1cnJlbnRNZW51ICk7XG5cblx0XHRcdHRoaXMuYmx1ciggZXZlbnQgKTtcblxuXHRcdFx0Ly8gV29yayBhcm91bmQgYWN0aXZlIGl0ZW0gc3RheWluZyBhY3RpdmUgYWZ0ZXIgbWVudSBpcyBibHVycmVkXG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggY3VycmVudE1lbnUuZmluZCggXCIudWktc3RhdGUtYWN0aXZlXCIgKSwgbnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXG5cdFx0XHR0aGlzLmFjdGl2ZU1lbnUgPSBjdXJyZW50TWVudTtcblx0XHR9LCB0aGlzLmRlbGF5ICk7XG5cdH0sXG5cblx0Ly8gV2l0aCBubyBhcmd1bWVudHMsIGNsb3NlcyB0aGUgY3VycmVudGx5IGFjdGl2ZSBtZW51IC0gaWYgbm90aGluZyBpcyBhY3RpdmVcblx0Ly8gaXQgY2xvc2VzIGFsbCBtZW51cy4gIElmIHBhc3NlZCBhbiBhcmd1bWVudCwgaXQgd2lsbCBzZWFyY2ggZm9yIG1lbnVzIEJFTE9XXG5cdF9jbG9zZTogZnVuY3Rpb24oIHN0YXJ0TWVudSApIHtcblx0XHRpZiAoICFzdGFydE1lbnUgKSB7XG5cdFx0XHRzdGFydE1lbnUgPSB0aGlzLmFjdGl2ZSA/IHRoaXMuYWN0aXZlLnBhcmVudCgpIDogdGhpcy5lbGVtZW50O1xuXHRcdH1cblxuXHRcdHN0YXJ0TWVudS5maW5kKCBcIi51aS1tZW51XCIgKVxuXHRcdFx0LmhpZGUoKVxuXHRcdFx0LmF0dHIoIFwiYXJpYS1oaWRkZW5cIiwgXCJ0cnVlXCIgKVxuXHRcdFx0LmF0dHIoIFwiYXJpYS1leHBhbmRlZFwiLCBcImZhbHNlXCIgKTtcblx0fSxcblxuXHRfY2xvc2VPbkRvY3VtZW50Q2xpY2s6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRyZXR1cm4gISQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIFwiLnVpLW1lbnVcIiApLmxlbmd0aDtcblx0fSxcblxuXHRfaXNEaXZpZGVyOiBmdW5jdGlvbiggaXRlbSApIHtcblxuXHRcdC8vIE1hdGNoIGh5cGhlbiwgZW0gZGFzaCwgZW4gZGFzaFxuXHRcdHJldHVybiAhL1teXFwtXFx1MjAxNFxcdTIwMTNcXHNdLy50ZXN0KCBpdGVtLnRleHQoKSApO1xuXHR9LFxuXG5cdGNvbGxhcHNlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIG5ld0l0ZW0gPSB0aGlzLmFjdGl2ZSAmJlxuXHRcdFx0dGhpcy5hY3RpdmUucGFyZW50KCkuY2xvc2VzdCggXCIudWktbWVudS1pdGVtXCIsIHRoaXMuZWxlbWVudCApO1xuXHRcdGlmICggbmV3SXRlbSAmJiBuZXdJdGVtLmxlbmd0aCApIHtcblx0XHRcdHRoaXMuX2Nsb3NlKCk7XG5cdFx0XHR0aGlzLmZvY3VzKCBldmVudCwgbmV3SXRlbSApO1xuXHRcdH1cblx0fSxcblxuXHRleHBhbmQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgbmV3SXRlbSA9IHRoaXMuYWN0aXZlICYmXG5cdFx0XHR0aGlzLmFjdGl2ZVxuXHRcdFx0XHQuY2hpbGRyZW4oIFwiLnVpLW1lbnUgXCIgKVxuXHRcdFx0XHRcdC5maW5kKCB0aGlzLm9wdGlvbnMuaXRlbXMgKVxuXHRcdFx0XHRcdFx0LmZpcnN0KCk7XG5cblx0XHRpZiAoIG5ld0l0ZW0gJiYgbmV3SXRlbS5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLl9vcGVuKCBuZXdJdGVtLnBhcmVudCgpICk7XG5cblx0XHRcdC8vIERlbGF5IHNvIEZpcmVmb3ggd2lsbCBub3QgaGlkZSBhY3RpdmVkZXNjZW5kYW50IGNoYW5nZSBpbiBleHBhbmRpbmcgc3VibWVudSBmcm9tIEFUXG5cdFx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMuZm9jdXMoIGV2ZW50LCBuZXdJdGVtICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdG5leHQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR0aGlzLl9tb3ZlKCBcIm5leHRcIiwgXCJmaXJzdFwiLCBldmVudCApO1xuXHR9LFxuXG5cdHByZXZpb3VzOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dGhpcy5fbW92ZSggXCJwcmV2XCIsIFwibGFzdFwiLCBldmVudCApO1xuXHR9LFxuXG5cdGlzRmlyc3RJdGVtOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5hY3RpdmUgJiYgIXRoaXMuYWN0aXZlLnByZXZBbGwoIFwiLnVpLW1lbnUtaXRlbVwiICkubGVuZ3RoO1xuXHR9LFxuXG5cdGlzTGFzdEl0ZW06IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmFjdGl2ZSAmJiAhdGhpcy5hY3RpdmUubmV4dEFsbCggXCIudWktbWVudS1pdGVtXCIgKS5sZW5ndGg7XG5cdH0sXG5cblx0X21vdmU6IGZ1bmN0aW9uKCBkaXJlY3Rpb24sIGZpbHRlciwgZXZlbnQgKSB7XG5cdFx0dmFyIG5leHQ7XG5cdFx0aWYgKCB0aGlzLmFjdGl2ZSApIHtcblx0XHRcdGlmICggZGlyZWN0aW9uID09PSBcImZpcnN0XCIgfHwgZGlyZWN0aW9uID09PSBcImxhc3RcIiApIHtcblx0XHRcdFx0bmV4dCA9IHRoaXMuYWN0aXZlXG5cdFx0XHRcdFx0WyBkaXJlY3Rpb24gPT09IFwiZmlyc3RcIiA/IFwicHJldkFsbFwiIDogXCJuZXh0QWxsXCIgXSggXCIudWktbWVudS1pdGVtXCIgKVxuXHRcdFx0XHRcdC5lcSggLTEgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdG5leHQgPSB0aGlzLmFjdGl2ZVxuXHRcdFx0XHRcdFsgZGlyZWN0aW9uICsgXCJBbGxcIiBdKCBcIi51aS1tZW51LWl0ZW1cIiApXG5cdFx0XHRcdFx0LmVxKCAwICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGlmICggIW5leHQgfHwgIW5leHQubGVuZ3RoIHx8ICF0aGlzLmFjdGl2ZSApIHtcblx0XHRcdG5leHQgPSB0aGlzLmFjdGl2ZU1lbnUuZmluZCggdGhpcy5vcHRpb25zLml0ZW1zIClbIGZpbHRlciBdKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5mb2N1cyggZXZlbnQsIG5leHQgKTtcblx0fSxcblxuXHRuZXh0UGFnZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBpdGVtLCBiYXNlLCBoZWlnaHQ7XG5cblx0XHRpZiAoICF0aGlzLmFjdGl2ZSApIHtcblx0XHRcdHRoaXMubmV4dCggZXZlbnQgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLmlzTGFzdEl0ZW0oKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLl9oYXNTY3JvbGwoKSApIHtcblx0XHRcdGJhc2UgPSB0aGlzLmFjdGl2ZS5vZmZzZXQoKS50b3A7XG5cdFx0XHRoZWlnaHQgPSB0aGlzLmVsZW1lbnQuaGVpZ2h0KCk7XG5cdFx0XHR0aGlzLmFjdGl2ZS5uZXh0QWxsKCBcIi51aS1tZW51LWl0ZW1cIiApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpdGVtID0gJCggdGhpcyApO1xuXHRcdFx0XHRyZXR1cm4gaXRlbS5vZmZzZXQoKS50b3AgLSBiYXNlIC0gaGVpZ2h0IDwgMDtcblx0XHRcdH0gKTtcblxuXHRcdFx0dGhpcy5mb2N1cyggZXZlbnQsIGl0ZW0gKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5mb2N1cyggZXZlbnQsIHRoaXMuYWN0aXZlTWVudS5maW5kKCB0aGlzLm9wdGlvbnMuaXRlbXMgKVxuXHRcdFx0XHRbICF0aGlzLmFjdGl2ZSA/IFwiZmlyc3RcIiA6IFwibGFzdFwiIF0oKSApO1xuXHRcdH1cblx0fSxcblxuXHRwcmV2aW91c1BhZ2U6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgaXRlbSwgYmFzZSwgaGVpZ2h0O1xuXHRcdGlmICggIXRoaXMuYWN0aXZlICkge1xuXHRcdFx0dGhpcy5uZXh0KCBldmVudCApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuaXNGaXJzdEl0ZW0oKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLl9oYXNTY3JvbGwoKSApIHtcblx0XHRcdGJhc2UgPSB0aGlzLmFjdGl2ZS5vZmZzZXQoKS50b3A7XG5cdFx0XHRoZWlnaHQgPSB0aGlzLmVsZW1lbnQuaGVpZ2h0KCk7XG5cdFx0XHR0aGlzLmFjdGl2ZS5wcmV2QWxsKCBcIi51aS1tZW51LWl0ZW1cIiApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpdGVtID0gJCggdGhpcyApO1xuXHRcdFx0XHRyZXR1cm4gaXRlbS5vZmZzZXQoKS50b3AgLSBiYXNlICsgaGVpZ2h0ID4gMDtcblx0XHRcdH0gKTtcblxuXHRcdFx0dGhpcy5mb2N1cyggZXZlbnQsIGl0ZW0gKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5mb2N1cyggZXZlbnQsIHRoaXMuYWN0aXZlTWVudS5maW5kKCB0aGlzLm9wdGlvbnMuaXRlbXMgKS5maXJzdCgpICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9oYXNTY3JvbGw6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmVsZW1lbnQub3V0ZXJIZWlnaHQoKSA8IHRoaXMuZWxlbWVudC5wcm9wKCBcInNjcm9sbEhlaWdodFwiICk7XG5cdH0sXG5cblx0c2VsZWN0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHQvLyBUT0RPOiBJdCBzaG91bGQgbmV2ZXIgYmUgcG9zc2libGUgdG8gbm90IGhhdmUgYW4gYWN0aXZlIGl0ZW0gYXQgdGhpc1xuXHRcdC8vIHBvaW50LCBidXQgdGhlIHRlc3RzIGRvbid0IHRyaWdnZXIgbW91c2VlbnRlciBiZWZvcmUgY2xpY2suXG5cdFx0dGhpcy5hY3RpdmUgPSB0aGlzLmFjdGl2ZSB8fCAkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCBcIi51aS1tZW51LWl0ZW1cIiApO1xuXHRcdHZhciB1aSA9IHsgaXRlbTogdGhpcy5hY3RpdmUgfTtcblx0XHRpZiAoICF0aGlzLmFjdGl2ZS5oYXMoIFwiLnVpLW1lbnVcIiApLmxlbmd0aCApIHtcblx0XHRcdHRoaXMuY29sbGFwc2VBbGwoIGV2ZW50LCB0cnVlICk7XG5cdFx0fVxuXHRcdHRoaXMuX3RyaWdnZXIoIFwic2VsZWN0XCIsIGV2ZW50LCB1aSApO1xuXHR9LFxuXG5cdF9maWx0ZXJNZW51SXRlbXM6IGZ1bmN0aW9uKCBjaGFyYWN0ZXIgKSB7XG5cdFx0dmFyIGVzY2FwZWRDaGFyYWN0ZXIgPSBjaGFyYWN0ZXIucmVwbGFjZSggL1tcXC1cXFtcXF17fSgpKis/LixcXFxcXFxeJHwjXFxzXS9nLCBcIlxcXFwkJlwiICksXG5cdFx0XHRyZWdleCA9IG5ldyBSZWdFeHAoIFwiXlwiICsgZXNjYXBlZENoYXJhY3RlciwgXCJpXCIgKTtcblxuXHRcdHJldHVybiB0aGlzLmFjdGl2ZU1lbnVcblx0XHRcdC5maW5kKCB0aGlzLm9wdGlvbnMuaXRlbXMgKVxuXG5cdFx0XHRcdC8vIE9ubHkgbWF0Y2ggb24gaXRlbXMsIG5vdCBkaXZpZGVycyBvciBvdGhlciBjb250ZW50ICgjMTA1NzEpXG5cdFx0XHRcdC5maWx0ZXIoIFwiLnVpLW1lbnUtaXRlbVwiIClcblx0XHRcdFx0XHQuZmlsdGVyKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHJldHVybiByZWdleC50ZXN0KFxuXHRcdFx0XHRcdFx0XHQkLnRyaW0oICQoIHRoaXMgKS5jaGlsZHJlbiggXCIudWktbWVudS1pdGVtLXdyYXBwZXJcIiApLnRleHQoKSApICk7XG5cdFx0XHRcdFx0fSApO1xuXHR9XG59ICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgQXV0b2NvbXBsZXRlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBBdXRvY29tcGxldGVcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBMaXN0cyBzdWdnZXN0ZWQgd29yZHMgYXMgdGhlIHVzZXIgaXMgdHlwaW5nLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2F1dG9jb21wbGV0ZS9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9hdXRvY29tcGxldGUvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9hdXRvY29tcGxldGUuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbiQud2lkZ2V0KCBcInVpLmF1dG9jb21wbGV0ZVwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdGRlZmF1bHRFbGVtZW50OiBcIjxpbnB1dD5cIixcblx0b3B0aW9uczoge1xuXHRcdGFwcGVuZFRvOiBudWxsLFxuXHRcdGF1dG9Gb2N1czogZmFsc2UsXG5cdFx0ZGVsYXk6IDMwMCxcblx0XHRtaW5MZW5ndGg6IDEsXG5cdFx0cG9zaXRpb246IHtcblx0XHRcdG15OiBcImxlZnQgdG9wXCIsXG5cdFx0XHRhdDogXCJsZWZ0IGJvdHRvbVwiLFxuXHRcdFx0Y29sbGlzaW9uOiBcIm5vbmVcIlxuXHRcdH0sXG5cdFx0c291cmNlOiBudWxsLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0Y2hhbmdlOiBudWxsLFxuXHRcdGNsb3NlOiBudWxsLFxuXHRcdGZvY3VzOiBudWxsLFxuXHRcdG9wZW46IG51bGwsXG5cdFx0cmVzcG9uc2U6IG51bGwsXG5cdFx0c2VhcmNoOiBudWxsLFxuXHRcdHNlbGVjdDogbnVsbFxuXHR9LFxuXG5cdHJlcXVlc3RJbmRleDogMCxcblx0cGVuZGluZzogMCxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblxuXHRcdC8vIFNvbWUgYnJvd3NlcnMgb25seSByZXBlYXQga2V5ZG93biBldmVudHMsIG5vdCBrZXlwcmVzcyBldmVudHMsXG5cdFx0Ly8gc28gd2UgdXNlIHRoZSBzdXBwcmVzc0tleVByZXNzIGZsYWcgdG8gZGV0ZXJtaW5lIGlmIHdlJ3ZlIGFscmVhZHlcblx0XHQvLyBoYW5kbGVkIHRoZSBrZXlkb3duIGV2ZW50LiAjNzI2OVxuXHRcdC8vIFVuZm9ydHVuYXRlbHkgdGhlIGNvZGUgZm9yICYgaW4ga2V5cHJlc3MgaXMgdGhlIHNhbWUgYXMgdGhlIHVwIGFycm93LFxuXHRcdC8vIHNvIHdlIHVzZSB0aGUgc3VwcHJlc3NLZXlQcmVzc1JlcGVhdCBmbGFnIHRvIGF2b2lkIGhhbmRsaW5nIGtleXByZXNzXG5cdFx0Ly8gZXZlbnRzIHdoZW4gd2Uga25vdyB0aGUga2V5ZG93biBldmVudCB3YXMgdXNlZCB0byBtb2RpZnkgdGhlXG5cdFx0Ly8gc2VhcmNoIHRlcm0uICM3Nzk5XG5cdFx0dmFyIHN1cHByZXNzS2V5UHJlc3MsIHN1cHByZXNzS2V5UHJlc3NSZXBlYXQsIHN1cHByZXNzSW5wdXQsXG5cdFx0XHRub2RlTmFtZSA9IHRoaXMuZWxlbWVudFsgMCBdLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCksXG5cdFx0XHRpc1RleHRhcmVhID0gbm9kZU5hbWUgPT09IFwidGV4dGFyZWFcIixcblx0XHRcdGlzSW5wdXQgPSBub2RlTmFtZSA9PT0gXCJpbnB1dFwiO1xuXG5cdFx0Ly8gVGV4dGFyZWFzIGFyZSBhbHdheXMgbXVsdGktbGluZVxuXHRcdC8vIElucHV0cyBhcmUgYWx3YXlzIHNpbmdsZS1saW5lLCBldmVuIGlmIGluc2lkZSBhIGNvbnRlbnRFZGl0YWJsZSBlbGVtZW50XG5cdFx0Ly8gSUUgYWxzbyB0cmVhdHMgaW5wdXRzIGFzIGNvbnRlbnRFZGl0YWJsZVxuXHRcdC8vIEFsbCBvdGhlciBlbGVtZW50IHR5cGVzIGFyZSBkZXRlcm1pbmVkIGJ5IHdoZXRoZXIgb3Igbm90IHRoZXkncmUgY29udGVudEVkaXRhYmxlXG5cdFx0dGhpcy5pc011bHRpTGluZSA9IGlzVGV4dGFyZWEgfHwgIWlzSW5wdXQgJiYgdGhpcy5faXNDb250ZW50RWRpdGFibGUoIHRoaXMuZWxlbWVudCApO1xuXG5cdFx0dGhpcy52YWx1ZU1ldGhvZCA9IHRoaXMuZWxlbWVudFsgaXNUZXh0YXJlYSB8fCBpc0lucHV0ID8gXCJ2YWxcIiA6IFwidGV4dFwiIF07XG5cdFx0dGhpcy5pc05ld01lbnUgPSB0cnVlO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktYXV0b2NvbXBsZXRlLWlucHV0XCIgKTtcblx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJhdXRvY29tcGxldGVcIiwgXCJvZmZcIiApO1xuXG5cdFx0dGhpcy5fb24oIHRoaXMuZWxlbWVudCwge1xuXHRcdFx0a2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoIHRoaXMuZWxlbWVudC5wcm9wKCBcInJlYWRPbmx5XCIgKSApIHtcblx0XHRcdFx0XHRzdXBwcmVzc0tleVByZXNzID0gdHJ1ZTtcblx0XHRcdFx0XHRzdXBwcmVzc0lucHV0ID0gdHJ1ZTtcblx0XHRcdFx0XHRzdXBwcmVzc0tleVByZXNzUmVwZWF0ID0gdHJ1ZTtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzdXBwcmVzc0tleVByZXNzID0gZmFsc2U7XG5cdFx0XHRcdHN1cHByZXNzSW5wdXQgPSBmYWxzZTtcblx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzc1JlcGVhdCA9IGZhbHNlO1xuXHRcdFx0XHR2YXIga2V5Q29kZSA9ICQudWkua2V5Q29kZTtcblx0XHRcdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLlBBR0VfVVA6XG5cdFx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzcyA9IHRydWU7XG5cdFx0XHRcdFx0dGhpcy5fbW92ZSggXCJwcmV2aW91c1BhZ2VcIiwgZXZlbnQgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLlBBR0VfRE9XTjpcblx0XHRcdFx0XHRzdXBwcmVzc0tleVByZXNzID0gdHJ1ZTtcblx0XHRcdFx0XHR0aGlzLl9tb3ZlKCBcIm5leHRQYWdlXCIsIGV2ZW50ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5VUDpcblx0XHRcdFx0XHRzdXBwcmVzc0tleVByZXNzID0gdHJ1ZTtcblx0XHRcdFx0XHR0aGlzLl9rZXlFdmVudCggXCJwcmV2aW91c1wiLCBldmVudCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuRE9XTjpcblx0XHRcdFx0XHRzdXBwcmVzc0tleVByZXNzID0gdHJ1ZTtcblx0XHRcdFx0XHR0aGlzLl9rZXlFdmVudCggXCJuZXh0XCIsIGV2ZW50ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5FTlRFUjpcblxuXHRcdFx0XHRcdC8vIHdoZW4gbWVudSBpcyBvcGVuIGFuZCBoYXMgZm9jdXNcblx0XHRcdFx0XHRpZiAoIHRoaXMubWVudS5hY3RpdmUgKSB7XG5cblx0XHRcdFx0XHRcdC8vICM2MDU1IC0gT3BlcmEgc3RpbGwgYWxsb3dzIHRoZSBrZXlwcmVzcyB0byBvY2N1clxuXHRcdFx0XHRcdFx0Ly8gd2hpY2ggY2F1c2VzIGZvcm1zIHRvIHN1Ym1pdFxuXHRcdFx0XHRcdFx0c3VwcHJlc3NLZXlQcmVzcyA9IHRydWU7XG5cdFx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdFx0dGhpcy5tZW51LnNlbGVjdCggZXZlbnQgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5UQUI6XG5cdFx0XHRcdFx0aWYgKCB0aGlzLm1lbnUuYWN0aXZlICkge1xuXHRcdFx0XHRcdFx0dGhpcy5tZW51LnNlbGVjdCggZXZlbnQgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5FU0NBUEU6XG5cdFx0XHRcdFx0aWYgKCB0aGlzLm1lbnUuZWxlbWVudC5pcyggXCI6dmlzaWJsZVwiICkgKSB7XG5cdFx0XHRcdFx0XHRpZiAoICF0aGlzLmlzTXVsdGlMaW5lICkge1xuXHRcdFx0XHRcdFx0XHR0aGlzLl92YWx1ZSggdGhpcy50ZXJtICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHR0aGlzLmNsb3NlKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHQvLyBEaWZmZXJlbnQgYnJvd3NlcnMgaGF2ZSBkaWZmZXJlbnQgZGVmYXVsdCBiZWhhdmlvciBmb3IgZXNjYXBlXG5cdFx0XHRcdFx0XHQvLyBTaW5nbGUgcHJlc3MgY2FuIG1lYW4gdW5kbyBvciBjbGVhclxuXHRcdFx0XHRcdFx0Ly8gRG91YmxlIHByZXNzIGluIElFIG1lYW5zIGNsZWFyIHRoZSB3aG9sZSBmb3JtXG5cdFx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRzdXBwcmVzc0tleVByZXNzUmVwZWF0ID0gdHJ1ZTtcblxuXHRcdFx0XHRcdC8vIHNlYXJjaCB0aW1lb3V0IHNob3VsZCBiZSB0cmlnZ2VyZWQgYmVmb3JlIHRoZSBpbnB1dCB2YWx1ZSBpcyBjaGFuZ2VkXG5cdFx0XHRcdFx0dGhpcy5fc2VhcmNoVGltZW91dCggZXZlbnQgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdGtleXByZXNzOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggc3VwcHJlc3NLZXlQcmVzcyApIHtcblx0XHRcdFx0XHRzdXBwcmVzc0tleVByZXNzID0gZmFsc2U7XG5cdFx0XHRcdFx0aWYgKCAhdGhpcy5pc011bHRpTGluZSB8fCB0aGlzLm1lbnUuZWxlbWVudC5pcyggXCI6dmlzaWJsZVwiICkgKSB7XG5cdFx0XHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBzdXBwcmVzc0tleVByZXNzUmVwZWF0ICkge1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFJlcGxpY2F0ZSBzb21lIGtleSBoYW5kbGVycyB0byBhbGxvdyB0aGVtIHRvIHJlcGVhdCBpbiBGaXJlZm94IGFuZCBPcGVyYVxuXHRcdFx0XHR2YXIga2V5Q29kZSA9ICQudWkua2V5Q29kZTtcblx0XHRcdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLlBBR0VfVVA6XG5cdFx0XHRcdFx0dGhpcy5fbW92ZSggXCJwcmV2aW91c1BhZ2VcIiwgZXZlbnQgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSBrZXlDb2RlLlBBR0VfRE9XTjpcblx0XHRcdFx0XHR0aGlzLl9tb3ZlKCBcIm5leHRQYWdlXCIsIGV2ZW50ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2Uga2V5Q29kZS5VUDpcblx0XHRcdFx0XHR0aGlzLl9rZXlFdmVudCggXCJwcmV2aW91c1wiLCBldmVudCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlIGtleUNvZGUuRE9XTjpcblx0XHRcdFx0XHR0aGlzLl9rZXlFdmVudCggXCJuZXh0XCIsIGV2ZW50ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRpbnB1dDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoIHN1cHByZXNzSW5wdXQgKSB7XG5cdFx0XHRcdFx0c3VwcHJlc3NJbnB1dCA9IGZhbHNlO1xuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRoaXMuX3NlYXJjaFRpbWVvdXQoIGV2ZW50ICk7XG5cdFx0XHR9LFxuXHRcdFx0Zm9jdXM6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLnNlbGVjdGVkSXRlbSA9IG51bGw7XG5cdFx0XHRcdHRoaXMucHJldmlvdXMgPSB0aGlzLl92YWx1ZSgpO1xuXHRcdFx0fSxcblx0XHRcdGJsdXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCB0aGlzLmNhbmNlbEJsdXIgKSB7XG5cdFx0XHRcdFx0ZGVsZXRlIHRoaXMuY2FuY2VsQmx1cjtcblx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRjbGVhclRpbWVvdXQoIHRoaXMuc2VhcmNoaW5nICk7XG5cdFx0XHRcdHRoaXMuY2xvc2UoIGV2ZW50ICk7XG5cdFx0XHRcdHRoaXMuX2NoYW5nZSggZXZlbnQgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHR0aGlzLl9pbml0U291cmNlKCk7XG5cdFx0dGhpcy5tZW51ID0gJCggXCI8dWw+XCIgKVxuXHRcdFx0LmFwcGVuZFRvKCB0aGlzLl9hcHBlbmRUbygpIClcblx0XHRcdC5tZW51KCB7XG5cblx0XHRcdFx0Ly8gZGlzYWJsZSBBUklBIHN1cHBvcnQsIHRoZSBsaXZlIHJlZ2lvbiB0YWtlcyBjYXJlIG9mIHRoYXRcblx0XHRcdFx0cm9sZTogbnVsbFxuXHRcdFx0fSApXG5cdFx0XHQuaGlkZSgpXG5cdFx0XHQubWVudSggXCJpbnN0YW5jZVwiICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5tZW51LmVsZW1lbnQsIFwidWktYXV0b2NvbXBsZXRlXCIsIFwidWktZnJvbnRcIiApO1xuXHRcdHRoaXMuX29uKCB0aGlzLm1lbnUuZWxlbWVudCwge1xuXHRcdFx0bW91c2Vkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHRcdFx0Ly8gcHJldmVudCBtb3ZpbmcgZm9jdXMgb3V0IG9mIHRoZSB0ZXh0IGZpZWxkXG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdFx0Ly8gSUUgZG9lc24ndCBwcmV2ZW50IG1vdmluZyBmb2N1cyBldmVuIHdpdGggZXZlbnQucHJldmVudERlZmF1bHQoKVxuXHRcdFx0XHQvLyBzbyB3ZSBzZXQgYSBmbGFnIHRvIGtub3cgd2hlbiB3ZSBzaG91bGQgaWdub3JlIHRoZSBibHVyIGV2ZW50XG5cdFx0XHRcdHRoaXMuY2FuY2VsQmx1ciA9IHRydWU7XG5cdFx0XHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRkZWxldGUgdGhpcy5jYW5jZWxCbHVyO1xuXG5cdFx0XHRcdFx0Ly8gU3VwcG9ydDogSUUgOCBvbmx5XG5cdFx0XHRcdFx0Ly8gUmlnaHQgY2xpY2tpbmcgYSBtZW51IGl0ZW0gb3Igc2VsZWN0aW5nIHRleHQgZnJvbSB0aGUgbWVudSBpdGVtcyB3aWxsXG5cdFx0XHRcdFx0Ly8gcmVzdWx0IGluIGZvY3VzIG1vdmluZyBvdXQgb2YgdGhlIGlucHV0LiBIb3dldmVyLCB3ZSd2ZSBhbHJlYWR5IHJlY2VpdmVkXG5cdFx0XHRcdFx0Ly8gYW5kIGlnbm9yZWQgdGhlIGJsdXIgZXZlbnQgYmVjYXVzZSBvZiB0aGUgY2FuY2VsQmx1ciBmbGFnIHNldCBhYm92ZS4gU29cblx0XHRcdFx0XHQvLyB3ZSByZXN0b3JlIGZvY3VzIHRvIGVuc3VyZSB0aGF0IHRoZSBtZW51IGNsb3NlcyBwcm9wZXJseSBiYXNlZCBvbiB0aGUgdXNlcidzXG5cdFx0XHRcdFx0Ly8gbmV4dCBhY3Rpb25zLlxuXHRcdFx0XHRcdGlmICggdGhpcy5lbGVtZW50WyAwIF0gIT09ICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApICkge1xuXHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50LnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0fSxcblx0XHRcdG1lbnVmb2N1czogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0dmFyIGxhYmVsLCBpdGVtO1xuXG5cdFx0XHRcdC8vIHN1cHBvcnQ6IEZpcmVmb3hcblx0XHRcdFx0Ly8gUHJldmVudCBhY2NpZGVudGFsIGFjdGl2YXRpb24gb2YgbWVudSBpdGVtcyBpbiBGaXJlZm94ICgjNzAyNCAjOTExOClcblx0XHRcdFx0aWYgKCB0aGlzLmlzTmV3TWVudSApIHtcblx0XHRcdFx0XHR0aGlzLmlzTmV3TWVudSA9IGZhbHNlO1xuXHRcdFx0XHRcdGlmICggZXZlbnQub3JpZ2luYWxFdmVudCAmJiAvXm1vdXNlLy50ZXN0KCBldmVudC5vcmlnaW5hbEV2ZW50LnR5cGUgKSApIHtcblx0XHRcdFx0XHRcdHRoaXMubWVudS5ibHVyKCk7XG5cblx0XHRcdFx0XHRcdHRoaXMuZG9jdW1lbnQub25lKCBcIm1vdXNlbW92ZVwiLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdFx0JCggZXZlbnQudGFyZ2V0ICkudHJpZ2dlciggZXZlbnQub3JpZ2luYWxFdmVudCApO1xuXHRcdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aXRlbSA9IHVpLml0ZW0uZGF0YSggXCJ1aS1hdXRvY29tcGxldGUtaXRlbVwiICk7XG5cdFx0XHRcdGlmICggZmFsc2UgIT09IHRoaXMuX3RyaWdnZXIoIFwiZm9jdXNcIiwgZXZlbnQsIHsgaXRlbTogaXRlbSB9ICkgKSB7XG5cblx0XHRcdFx0XHQvLyB1c2UgdmFsdWUgdG8gbWF0Y2ggd2hhdCB3aWxsIGVuZCB1cCBpbiB0aGUgaW5wdXQsIGlmIGl0IHdhcyBhIGtleSBldmVudFxuXHRcdFx0XHRcdGlmICggZXZlbnQub3JpZ2luYWxFdmVudCAmJiAvXmtleS8udGVzdCggZXZlbnQub3JpZ2luYWxFdmVudC50eXBlICkgKSB7XG5cdFx0XHRcdFx0XHR0aGlzLl92YWx1ZSggaXRlbS52YWx1ZSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEFubm91bmNlIHRoZSB2YWx1ZSBpbiB0aGUgbGl2ZVJlZ2lvblxuXHRcdFx0XHRsYWJlbCA9IHVpLml0ZW0uYXR0ciggXCJhcmlhLWxhYmVsXCIgKSB8fCBpdGVtLnZhbHVlO1xuXHRcdFx0XHRpZiAoIGxhYmVsICYmICQudHJpbSggbGFiZWwgKS5sZW5ndGggKSB7XG5cdFx0XHRcdFx0dGhpcy5saXZlUmVnaW9uLmNoaWxkcmVuKCkuaGlkZSgpO1xuXHRcdFx0XHRcdCQoIFwiPGRpdj5cIiApLnRleHQoIGxhYmVsICkuYXBwZW5kVG8oIHRoaXMubGl2ZVJlZ2lvbiApO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0bWVudXNlbGVjdDogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0dmFyIGl0ZW0gPSB1aS5pdGVtLmRhdGEoIFwidWktYXV0b2NvbXBsZXRlLWl0ZW1cIiApLFxuXHRcdFx0XHRcdHByZXZpb3VzID0gdGhpcy5wcmV2aW91cztcblxuXHRcdFx0XHQvLyBPbmx5IHRyaWdnZXIgd2hlbiBmb2N1cyB3YXMgbG9zdCAoY2xpY2sgb24gbWVudSlcblx0XHRcdFx0aWYgKCB0aGlzLmVsZW1lbnRbIDAgXSAhPT0gJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICkgKSB7XG5cdFx0XHRcdFx0dGhpcy5lbGVtZW50LnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0XHRcdHRoaXMucHJldmlvdXMgPSBwcmV2aW91cztcblxuXHRcdFx0XHRcdC8vICM2MTA5IC0gSUUgdHJpZ2dlcnMgdHdvIGZvY3VzIGV2ZW50cyBhbmQgdGhlIHNlY29uZFxuXHRcdFx0XHRcdC8vIGlzIGFzeW5jaHJvbm91cywgc28gd2UgbmVlZCB0byByZXNldCB0aGUgcHJldmlvdXNcblx0XHRcdFx0XHQvLyB0ZXJtIHN5bmNocm9ub3VzbHkgYW5kIGFzeW5jaHJvbm91c2x5IDotKFxuXHRcdFx0XHRcdHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHRoaXMucHJldmlvdXMgPSBwcmV2aW91cztcblx0XHRcdFx0XHRcdHRoaXMuc2VsZWN0ZWRJdGVtID0gaXRlbTtcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGZhbHNlICE9PSB0aGlzLl90cmlnZ2VyKCBcInNlbGVjdFwiLCBldmVudCwgeyBpdGVtOiBpdGVtIH0gKSApIHtcblx0XHRcdFx0XHR0aGlzLl92YWx1ZSggaXRlbS52YWx1ZSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gcmVzZXQgdGhlIHRlcm0gYWZ0ZXIgdGhlIHNlbGVjdCBldmVudFxuXHRcdFx0XHQvLyB0aGlzIGFsbG93cyBjdXN0b20gc2VsZWN0IGhhbmRsaW5nIHRvIHdvcmsgcHJvcGVybHlcblx0XHRcdFx0dGhpcy50ZXJtID0gdGhpcy5fdmFsdWUoKTtcblxuXHRcdFx0XHR0aGlzLmNsb3NlKCBldmVudCApO1xuXHRcdFx0XHR0aGlzLnNlbGVjdGVkSXRlbSA9IGl0ZW07XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0dGhpcy5saXZlUmVnaW9uID0gJCggXCI8ZGl2PlwiLCB7XG5cdFx0XHRyb2xlOiBcInN0YXR1c1wiLFxuXHRcdFx0XCJhcmlhLWxpdmVcIjogXCJhc3NlcnRpdmVcIixcblx0XHRcdFwiYXJpYS1yZWxldmFudFwiOiBcImFkZGl0aW9uc1wiXG5cdFx0fSApXG5cdFx0XHQuYXBwZW5kVG8oIHRoaXMuZG9jdW1lbnRbIDAgXS5ib2R5ICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5saXZlUmVnaW9uLCBudWxsLCBcInVpLWhlbHBlci1oaWRkZW4tYWNjZXNzaWJsZVwiICk7XG5cblx0XHQvLyBUdXJuaW5nIG9mZiBhdXRvY29tcGxldGUgcHJldmVudHMgdGhlIGJyb3dzZXIgZnJvbSByZW1lbWJlcmluZyB0aGVcblx0XHQvLyB2YWx1ZSB3aGVuIG5hdmlnYXRpbmcgdGhyb3VnaCBoaXN0b3J5LCBzbyB3ZSByZS1lbmFibGUgYXV0b2NvbXBsZXRlXG5cdFx0Ly8gaWYgdGhlIHBhZ2UgaXMgdW5sb2FkZWQgYmVmb3JlIHRoZSB3aWRnZXQgaXMgZGVzdHJveWVkLiAjNzc5MFxuXHRcdHRoaXMuX29uKCB0aGlzLndpbmRvdywge1xuXHRcdFx0YmVmb3JldW5sb2FkOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LnJlbW92ZUF0dHIoIFwiYXV0b2NvbXBsZXRlXCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdGNsZWFyVGltZW91dCggdGhpcy5zZWFyY2hpbmcgKTtcblx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQXR0ciggXCJhdXRvY29tcGxldGVcIiApO1xuXHRcdHRoaXMubWVudS5lbGVtZW50LnJlbW92ZSgpO1xuXHRcdHRoaXMubGl2ZVJlZ2lvbi5yZW1vdmUoKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXHRcdGlmICgga2V5ID09PSBcInNvdXJjZVwiICkge1xuXHRcdFx0dGhpcy5faW5pdFNvdXJjZSgpO1xuXHRcdH1cblx0XHRpZiAoIGtleSA9PT0gXCJhcHBlbmRUb1wiICkge1xuXHRcdFx0dGhpcy5tZW51LmVsZW1lbnQuYXBwZW5kVG8oIHRoaXMuX2FwcGVuZFRvKCkgKTtcblx0XHR9XG5cdFx0aWYgKCBrZXkgPT09IFwiZGlzYWJsZWRcIiAmJiB2YWx1ZSAmJiB0aGlzLnhociApIHtcblx0XHRcdHRoaXMueGhyLmFib3J0KCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9pc0V2ZW50VGFyZ2V0SW5XaWRnZXQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgbWVudUVsZW1lbnQgPSB0aGlzLm1lbnUuZWxlbWVudFsgMCBdO1xuXG5cdFx0cmV0dXJuIGV2ZW50LnRhcmdldCA9PT0gdGhpcy5lbGVtZW50WyAwIF0gfHxcblx0XHRcdGV2ZW50LnRhcmdldCA9PT0gbWVudUVsZW1lbnQgfHxcblx0XHRcdCQuY29udGFpbnMoIG1lbnVFbGVtZW50LCBldmVudC50YXJnZXQgKTtcblx0fSxcblxuXHRfY2xvc2VPbkNsaWNrT3V0c2lkZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggIXRoaXMuX2lzRXZlbnRUYXJnZXRJbldpZGdldCggZXZlbnQgKSApIHtcblx0XHRcdHRoaXMuY2xvc2UoKTtcblx0XHR9XG5cdH0sXG5cblx0X2FwcGVuZFRvOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZWxlbWVudCA9IHRoaXMub3B0aW9ucy5hcHBlbmRUbztcblxuXHRcdGlmICggZWxlbWVudCApIHtcblx0XHRcdGVsZW1lbnQgPSBlbGVtZW50LmpxdWVyeSB8fCBlbGVtZW50Lm5vZGVUeXBlID9cblx0XHRcdFx0JCggZWxlbWVudCApIDpcblx0XHRcdFx0dGhpcy5kb2N1bWVudC5maW5kKCBlbGVtZW50ICkuZXEoIDAgKTtcblx0XHR9XG5cblx0XHRpZiAoICFlbGVtZW50IHx8ICFlbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRlbGVtZW50ID0gdGhpcy5lbGVtZW50LmNsb3Nlc3QoIFwiLnVpLWZyb250LCBkaWFsb2dcIiApO1xuXHRcdH1cblxuXHRcdGlmICggIWVsZW1lbnQubGVuZ3RoICkge1xuXHRcdFx0ZWxlbWVudCA9IHRoaXMuZG9jdW1lbnRbIDAgXS5ib2R5O1xuXHRcdH1cblxuXHRcdHJldHVybiBlbGVtZW50O1xuXHR9LFxuXG5cdF9pbml0U291cmNlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgYXJyYXksIHVybCxcblx0XHRcdHRoYXQgPSB0aGlzO1xuXHRcdGlmICggJC5pc0FycmF5KCB0aGlzLm9wdGlvbnMuc291cmNlICkgKSB7XG5cdFx0XHRhcnJheSA9IHRoaXMub3B0aW9ucy5zb3VyY2U7XG5cdFx0XHR0aGlzLnNvdXJjZSA9IGZ1bmN0aW9uKCByZXF1ZXN0LCByZXNwb25zZSApIHtcblx0XHRcdFx0cmVzcG9uc2UoICQudWkuYXV0b2NvbXBsZXRlLmZpbHRlciggYXJyYXksIHJlcXVlc3QudGVybSApICk7XG5cdFx0XHR9O1xuXHRcdH0gZWxzZSBpZiAoIHR5cGVvZiB0aGlzLm9wdGlvbnMuc291cmNlID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0dXJsID0gdGhpcy5vcHRpb25zLnNvdXJjZTtcblx0XHRcdHRoaXMuc291cmNlID0gZnVuY3Rpb24oIHJlcXVlc3QsIHJlc3BvbnNlICkge1xuXHRcdFx0XHRpZiAoIHRoYXQueGhyICkge1xuXHRcdFx0XHRcdHRoYXQueGhyLmFib3J0KCk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhhdC54aHIgPSAkLmFqYXgoIHtcblx0XHRcdFx0XHR1cmw6IHVybCxcblx0XHRcdFx0XHRkYXRhOiByZXF1ZXN0LFxuXHRcdFx0XHRcdGRhdGFUeXBlOiBcImpzb25cIixcblx0XHRcdFx0XHRzdWNjZXNzOiBmdW5jdGlvbiggZGF0YSApIHtcblx0XHRcdFx0XHRcdHJlc3BvbnNlKCBkYXRhICk7XG5cdFx0XHRcdFx0fSxcblx0XHRcdFx0XHRlcnJvcjogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRyZXNwb25zZSggW10gKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gKTtcblx0XHRcdH07XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuc291cmNlID0gdGhpcy5vcHRpb25zLnNvdXJjZTtcblx0XHR9XG5cdH0sXG5cblx0X3NlYXJjaFRpbWVvdXQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRjbGVhclRpbWVvdXQoIHRoaXMuc2VhcmNoaW5nICk7XG5cdFx0dGhpcy5zZWFyY2hpbmcgPSB0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIFNlYXJjaCBpZiB0aGUgdmFsdWUgaGFzIGNoYW5nZWQsIG9yIGlmIHRoZSB1c2VyIHJldHlwZXMgdGhlIHNhbWUgdmFsdWUgKHNlZSAjNzQzNClcblx0XHRcdHZhciBlcXVhbFZhbHVlcyA9IHRoaXMudGVybSA9PT0gdGhpcy5fdmFsdWUoKSxcblx0XHRcdFx0bWVudVZpc2libGUgPSB0aGlzLm1lbnUuZWxlbWVudC5pcyggXCI6dmlzaWJsZVwiICksXG5cdFx0XHRcdG1vZGlmaWVyS2V5ID0gZXZlbnQuYWx0S2V5IHx8IGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSB8fCBldmVudC5zaGlmdEtleTtcblxuXHRcdFx0aWYgKCAhZXF1YWxWYWx1ZXMgfHwgKCBlcXVhbFZhbHVlcyAmJiAhbWVudVZpc2libGUgJiYgIW1vZGlmaWVyS2V5ICkgKSB7XG5cdFx0XHRcdHRoaXMuc2VsZWN0ZWRJdGVtID0gbnVsbDtcblx0XHRcdFx0dGhpcy5zZWFyY2goIG51bGwsIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0fSwgdGhpcy5vcHRpb25zLmRlbGF5ICk7XG5cdH0sXG5cblx0c2VhcmNoOiBmdW5jdGlvbiggdmFsdWUsIGV2ZW50ICkge1xuXHRcdHZhbHVlID0gdmFsdWUgIT0gbnVsbCA/IHZhbHVlIDogdGhpcy5fdmFsdWUoKTtcblxuXHRcdC8vIEFsd2F5cyBzYXZlIHRoZSBhY3R1YWwgdmFsdWUsIG5vdCB0aGUgb25lIHBhc3NlZCBhcyBhbiBhcmd1bWVudFxuXHRcdHRoaXMudGVybSA9IHRoaXMuX3ZhbHVlKCk7XG5cblx0XHRpZiAoIHZhbHVlLmxlbmd0aCA8IHRoaXMub3B0aW9ucy5taW5MZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5jbG9zZSggZXZlbnQgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX3RyaWdnZXIoIFwic2VhcmNoXCIsIGV2ZW50ICkgPT09IGZhbHNlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLl9zZWFyY2goIHZhbHVlICk7XG5cdH0sXG5cblx0X3NlYXJjaDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHRoaXMucGVuZGluZysrO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWF1dG9jb21wbGV0ZS1sb2FkaW5nXCIgKTtcblx0XHR0aGlzLmNhbmNlbFNlYXJjaCA9IGZhbHNlO1xuXG5cdFx0dGhpcy5zb3VyY2UoIHsgdGVybTogdmFsdWUgfSwgdGhpcy5fcmVzcG9uc2UoKSApO1xuXHR9LFxuXG5cdF9yZXNwb25zZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGluZGV4ID0gKyt0aGlzLnJlcXVlc3RJbmRleDtcblxuXHRcdHJldHVybiAkLnByb3h5KCBmdW5jdGlvbiggY29udGVudCApIHtcblx0XHRcdGlmICggaW5kZXggPT09IHRoaXMucmVxdWVzdEluZGV4ICkge1xuXHRcdFx0XHR0aGlzLl9fcmVzcG9uc2UoIGNvbnRlbnQgKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5wZW5kaW5nLS07XG5cdFx0XHRpZiAoICF0aGlzLnBlbmRpbmcgKSB7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBcInVpLWF1dG9jb21wbGV0ZS1sb2FkaW5nXCIgKTtcblx0XHRcdH1cblx0XHR9LCB0aGlzICk7XG5cdH0sXG5cblx0X19yZXNwb25zZTogZnVuY3Rpb24oIGNvbnRlbnQgKSB7XG5cdFx0aWYgKCBjb250ZW50ICkge1xuXHRcdFx0Y29udGVudCA9IHRoaXMuX25vcm1hbGl6ZSggY29udGVudCApO1xuXHRcdH1cblx0XHR0aGlzLl90cmlnZ2VyKCBcInJlc3BvbnNlXCIsIG51bGwsIHsgY29udGVudDogY29udGVudCB9ICk7XG5cdFx0aWYgKCAhdGhpcy5vcHRpb25zLmRpc2FibGVkICYmIGNvbnRlbnQgJiYgY29udGVudC5sZW5ndGggJiYgIXRoaXMuY2FuY2VsU2VhcmNoICkge1xuXHRcdFx0dGhpcy5fc3VnZ2VzdCggY29udGVudCApO1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJvcGVuXCIgKTtcblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyB1c2UgLl9jbG9zZSgpIGluc3RlYWQgb2YgLmNsb3NlKCkgc28gd2UgZG9uJ3QgY2FuY2VsIGZ1dHVyZSBzZWFyY2hlc1xuXHRcdFx0dGhpcy5fY2xvc2UoKTtcblx0XHR9XG5cdH0sXG5cblx0Y2xvc2U6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR0aGlzLmNhbmNlbFNlYXJjaCA9IHRydWU7XG5cdFx0dGhpcy5fY2xvc2UoIGV2ZW50ICk7XG5cdH0sXG5cblx0X2Nsb3NlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHQvLyBSZW1vdmUgdGhlIGhhbmRsZXIgdGhhdCBjbG9zZXMgdGhlIG1lbnUgb24gb3V0c2lkZSBjbGlja3Ncblx0XHR0aGlzLl9vZmYoIHRoaXMuZG9jdW1lbnQsIFwibW91c2Vkb3duXCIgKTtcblxuXHRcdGlmICggdGhpcy5tZW51LmVsZW1lbnQuaXMoIFwiOnZpc2libGVcIiApICkge1xuXHRcdFx0dGhpcy5tZW51LmVsZW1lbnQuaGlkZSgpO1xuXHRcdFx0dGhpcy5tZW51LmJsdXIoKTtcblx0XHRcdHRoaXMuaXNOZXdNZW51ID0gdHJ1ZTtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY2xvc2VcIiwgZXZlbnQgKTtcblx0XHR9XG5cdH0sXG5cblx0X2NoYW5nZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggdGhpcy5wcmV2aW91cyAhPT0gdGhpcy5fdmFsdWUoKSApIHtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY2hhbmdlXCIsIGV2ZW50LCB7IGl0ZW06IHRoaXMuc2VsZWN0ZWRJdGVtIH0gKTtcblx0XHR9XG5cdH0sXG5cblx0X25vcm1hbGl6ZTogZnVuY3Rpb24oIGl0ZW1zICkge1xuXG5cdFx0Ly8gYXNzdW1lIGFsbCBpdGVtcyBoYXZlIHRoZSByaWdodCBmb3JtYXQgd2hlbiB0aGUgZmlyc3QgaXRlbSBpcyBjb21wbGV0ZVxuXHRcdGlmICggaXRlbXMubGVuZ3RoICYmIGl0ZW1zWyAwIF0ubGFiZWwgJiYgaXRlbXNbIDAgXS52YWx1ZSApIHtcblx0XHRcdHJldHVybiBpdGVtcztcblx0XHR9XG5cdFx0cmV0dXJuICQubWFwKCBpdGVtcywgZnVuY3Rpb24oIGl0ZW0gKSB7XG5cdFx0XHRpZiAoIHR5cGVvZiBpdGVtID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdGxhYmVsOiBpdGVtLFxuXHRcdFx0XHRcdHZhbHVlOiBpdGVtXG5cdFx0XHRcdH07XG5cdFx0XHR9XG5cdFx0XHRyZXR1cm4gJC5leHRlbmQoIHt9LCBpdGVtLCB7XG5cdFx0XHRcdGxhYmVsOiBpdGVtLmxhYmVsIHx8IGl0ZW0udmFsdWUsXG5cdFx0XHRcdHZhbHVlOiBpdGVtLnZhbHVlIHx8IGl0ZW0ubGFiZWxcblx0XHRcdH0gKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0X3N1Z2dlc3Q6IGZ1bmN0aW9uKCBpdGVtcyApIHtcblx0XHR2YXIgdWwgPSB0aGlzLm1lbnUuZWxlbWVudC5lbXB0eSgpO1xuXHRcdHRoaXMuX3JlbmRlck1lbnUoIHVsLCBpdGVtcyApO1xuXHRcdHRoaXMuaXNOZXdNZW51ID0gdHJ1ZTtcblx0XHR0aGlzLm1lbnUucmVmcmVzaCgpO1xuXG5cdFx0Ly8gU2l6ZSBhbmQgcG9zaXRpb24gbWVudVxuXHRcdHVsLnNob3coKTtcblx0XHR0aGlzLl9yZXNpemVNZW51KCk7XG5cdFx0dWwucG9zaXRpb24oICQuZXh0ZW5kKCB7XG5cdFx0XHRvZjogdGhpcy5lbGVtZW50XG5cdFx0fSwgdGhpcy5vcHRpb25zLnBvc2l0aW9uICkgKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmF1dG9Gb2N1cyApIHtcblx0XHRcdHRoaXMubWVudS5uZXh0KCk7XG5cdFx0fVxuXG5cdFx0Ly8gTGlzdGVuIGZvciBpbnRlcmFjdGlvbnMgb3V0c2lkZSBvZiB0aGUgd2lkZ2V0ICgjNjY0Milcblx0XHR0aGlzLl9vbiggdGhpcy5kb2N1bWVudCwge1xuXHRcdFx0bW91c2Vkb3duOiBcIl9jbG9zZU9uQ2xpY2tPdXRzaWRlXCJcblx0XHR9ICk7XG5cdH0sXG5cblx0X3Jlc2l6ZU1lbnU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB1bCA9IHRoaXMubWVudS5lbGVtZW50O1xuXHRcdHVsLm91dGVyV2lkdGgoIE1hdGgubWF4KFxuXG5cdFx0XHQvLyBGaXJlZm94IHdyYXBzIGxvbmcgdGV4dCAocG9zc2libHkgYSByb3VuZGluZyBidWcpXG5cdFx0XHQvLyBzbyB3ZSBhZGQgMXB4IHRvIGF2b2lkIHRoZSB3cmFwcGluZyAoIzc1MTMpXG5cdFx0XHR1bC53aWR0aCggXCJcIiApLm91dGVyV2lkdGgoKSArIDEsXG5cdFx0XHR0aGlzLmVsZW1lbnQub3V0ZXJXaWR0aCgpXG5cdFx0KSApO1xuXHR9LFxuXG5cdF9yZW5kZXJNZW51OiBmdW5jdGlvbiggdWwsIGl0ZW1zICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblx0XHQkLmVhY2goIGl0ZW1zLCBmdW5jdGlvbiggaW5kZXgsIGl0ZW0gKSB7XG5cdFx0XHR0aGF0Ll9yZW5kZXJJdGVtRGF0YSggdWwsIGl0ZW0gKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0X3JlbmRlckl0ZW1EYXRhOiBmdW5jdGlvbiggdWwsIGl0ZW0gKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3JlbmRlckl0ZW0oIHVsLCBpdGVtICkuZGF0YSggXCJ1aS1hdXRvY29tcGxldGUtaXRlbVwiLCBpdGVtICk7XG5cdH0sXG5cblx0X3JlbmRlckl0ZW06IGZ1bmN0aW9uKCB1bCwgaXRlbSApIHtcblx0XHRyZXR1cm4gJCggXCI8bGk+XCIgKVxuXHRcdFx0LmFwcGVuZCggJCggXCI8ZGl2PlwiICkudGV4dCggaXRlbS5sYWJlbCApIClcblx0XHRcdC5hcHBlbmRUbyggdWwgKTtcblx0fSxcblxuXHRfbW92ZTogZnVuY3Rpb24oIGRpcmVjdGlvbiwgZXZlbnQgKSB7XG5cdFx0aWYgKCAhdGhpcy5tZW51LmVsZW1lbnQuaXMoIFwiOnZpc2libGVcIiApICkge1xuXHRcdFx0dGhpcy5zZWFyY2goIG51bGwsIGV2ZW50ICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmICggdGhpcy5tZW51LmlzRmlyc3RJdGVtKCkgJiYgL15wcmV2aW91cy8udGVzdCggZGlyZWN0aW9uICkgfHxcblx0XHRcdFx0dGhpcy5tZW51LmlzTGFzdEl0ZW0oKSAmJiAvXm5leHQvLnRlc3QoIGRpcmVjdGlvbiApICkge1xuXG5cdFx0XHRpZiAoICF0aGlzLmlzTXVsdGlMaW5lICkge1xuXHRcdFx0XHR0aGlzLl92YWx1ZSggdGhpcy50ZXJtICk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMubWVudS5ibHVyKCk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMubWVudVsgZGlyZWN0aW9uIF0oIGV2ZW50ICk7XG5cdH0sXG5cblx0d2lkZ2V0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5tZW51LmVsZW1lbnQ7XG5cdH0sXG5cblx0X3ZhbHVlOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy52YWx1ZU1ldGhvZC5hcHBseSggdGhpcy5lbGVtZW50LCBhcmd1bWVudHMgKTtcblx0fSxcblxuXHRfa2V5RXZlbnQ6IGZ1bmN0aW9uKCBrZXlFdmVudCwgZXZlbnQgKSB7XG5cdFx0aWYgKCAhdGhpcy5pc011bHRpTGluZSB8fCB0aGlzLm1lbnUuZWxlbWVudC5pcyggXCI6dmlzaWJsZVwiICkgKSB7XG5cdFx0XHR0aGlzLl9tb3ZlKCBrZXlFdmVudCwgZXZlbnQgKTtcblxuXHRcdFx0Ly8gUHJldmVudHMgbW92aW5nIGN1cnNvciB0byBiZWdpbm5pbmcvZW5kIG9mIHRoZSB0ZXh0IGZpZWxkIGluIHNvbWUgYnJvd3NlcnNcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIFN1cHBvcnQ6IENocm9tZSA8PTUwXG5cdC8vIFdlIHNob3VsZCBiZSBhYmxlIHRvIGp1c3QgdXNlIHRoaXMuZWxlbWVudC5wcm9wKCBcImlzQ29udGVudEVkaXRhYmxlXCIgKVxuXHQvLyBidXQgaGlkZGVuIGVsZW1lbnRzIGFsd2F5cyByZXBvcnQgZmFsc2UgaW4gQ2hyb21lLlxuXHQvLyBodHRwczovL2NvZGUuZ29vZ2xlLmNvbS9wL2Nocm9taXVtL2lzc3Vlcy9kZXRhaWw/aWQ9MzEzMDgyXG5cdF9pc0NvbnRlbnRFZGl0YWJsZTogZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cdFx0aWYgKCAhZWxlbWVudC5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0dmFyIGVkaXRhYmxlID0gZWxlbWVudC5wcm9wKCBcImNvbnRlbnRFZGl0YWJsZVwiICk7XG5cblx0XHRpZiAoIGVkaXRhYmxlID09PSBcImluaGVyaXRcIiApIHtcblx0XHQgIHJldHVybiB0aGlzLl9pc0NvbnRlbnRFZGl0YWJsZSggZWxlbWVudC5wYXJlbnQoKSApO1xuXHRcdH1cblxuXHRcdHJldHVybiBlZGl0YWJsZSA9PT0gXCJ0cnVlXCI7XG5cdH1cbn0gKTtcblxuJC5leHRlbmQoICQudWkuYXV0b2NvbXBsZXRlLCB7XG5cdGVzY2FwZVJlZ2V4OiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0cmV0dXJuIHZhbHVlLnJlcGxhY2UoIC9bXFwtXFxbXFxde30oKSorPy4sXFxcXFxcXiR8I1xcc10vZywgXCJcXFxcJCZcIiApO1xuXHR9LFxuXHRmaWx0ZXI6IGZ1bmN0aW9uKCBhcnJheSwgdGVybSApIHtcblx0XHR2YXIgbWF0Y2hlciA9IG5ldyBSZWdFeHAoICQudWkuYXV0b2NvbXBsZXRlLmVzY2FwZVJlZ2V4KCB0ZXJtICksIFwiaVwiICk7XG5cdFx0cmV0dXJuICQuZ3JlcCggYXJyYXksIGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdHJldHVybiBtYXRjaGVyLnRlc3QoIHZhbHVlLmxhYmVsIHx8IHZhbHVlLnZhbHVlIHx8IHZhbHVlICk7XG5cdFx0fSApO1xuXHR9XG59ICk7XG5cbi8vIExpdmUgcmVnaW9uIGV4dGVuc2lvbiwgYWRkaW5nIGEgYG1lc3NhZ2VzYCBvcHRpb25cbi8vIE5PVEU6IFRoaXMgaXMgYW4gZXhwZXJpbWVudGFsIEFQSS4gV2UgYXJlIHN0aWxsIGludmVzdGlnYXRpbmdcbi8vIGEgZnVsbCBzb2x1dGlvbiBmb3Igc3RyaW5nIG1hbmlwdWxhdGlvbiBhbmQgaW50ZXJuYXRpb25hbGl6YXRpb24uXG4kLndpZGdldCggXCJ1aS5hdXRvY29tcGxldGVcIiwgJC51aS5hdXRvY29tcGxldGUsIHtcblx0b3B0aW9uczoge1xuXHRcdG1lc3NhZ2VzOiB7XG5cdFx0XHRub1Jlc3VsdHM6IFwiTm8gc2VhcmNoIHJlc3VsdHMuXCIsXG5cdFx0XHRyZXN1bHRzOiBmdW5jdGlvbiggYW1vdW50ICkge1xuXHRcdFx0XHRyZXR1cm4gYW1vdW50ICsgKCBhbW91bnQgPiAxID8gXCIgcmVzdWx0cyBhcmVcIiA6IFwiIHJlc3VsdCBpc1wiICkgK1xuXHRcdFx0XHRcdFwiIGF2YWlsYWJsZSwgdXNlIHVwIGFuZCBkb3duIGFycm93IGtleXMgdG8gbmF2aWdhdGUuXCI7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdF9fcmVzcG9uc2U6IGZ1bmN0aW9uKCBjb250ZW50ICkge1xuXHRcdHZhciBtZXNzYWdlO1xuXHRcdHRoaXMuX3N1cGVyQXBwbHkoIGFyZ3VtZW50cyApO1xuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkIHx8IHRoaXMuY2FuY2VsU2VhcmNoICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblx0XHRpZiAoIGNvbnRlbnQgJiYgY29udGVudC5sZW5ndGggKSB7XG5cdFx0XHRtZXNzYWdlID0gdGhpcy5vcHRpb25zLm1lc3NhZ2VzLnJlc3VsdHMoIGNvbnRlbnQubGVuZ3RoICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdG1lc3NhZ2UgPSB0aGlzLm9wdGlvbnMubWVzc2FnZXMubm9SZXN1bHRzO1xuXHRcdH1cblx0XHR0aGlzLmxpdmVSZWdpb24uY2hpbGRyZW4oKS5oaWRlKCk7XG5cdFx0JCggXCI8ZGl2PlwiICkudGV4dCggbWVzc2FnZSApLmFwcGVuZFRvKCB0aGlzLmxpdmVSZWdpb24gKTtcblx0fVxufSApO1xuXG52YXIgd2lkZ2V0c0F1dG9jb21wbGV0ZSA9ICQudWkuYXV0b2NvbXBsZXRlO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIENvbnRyb2xncm91cCAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogQ29udHJvbGdyb3VwXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogVmlzdWFsbHkgZ3JvdXBzIGZvcm0gY29udHJvbCB3aWRnZXRzXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vY29udHJvbGdyb3VwL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2NvbnRyb2xncm91cC9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvbnRyb2xncm91cC5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cbnZhciBjb250cm9sZ3JvdXBDb3JuZXJSZWdleCA9IC91aS1jb3JuZXItKFthLXpdKXsyLDZ9L2c7XG5cbnZhciB3aWRnZXRzQ29udHJvbGdyb3VwID0gJC53aWRnZXQoIFwidWkuY29udHJvbGdyb3VwXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0ZGVmYXVsdEVsZW1lbnQ6IFwiPGRpdj5cIixcblx0b3B0aW9uczoge1xuXHRcdGRpcmVjdGlvbjogXCJob3Jpem9udGFsXCIsXG5cdFx0ZGlzYWJsZWQ6IG51bGwsXG5cdFx0b25seVZpc2libGU6IHRydWUsXG5cdFx0aXRlbXM6IHtcblx0XHRcdFwiYnV0dG9uXCI6IFwiaW5wdXRbdHlwZT1idXR0b25dLCBpbnB1dFt0eXBlPXN1Ym1pdF0sIGlucHV0W3R5cGU9cmVzZXRdLCBidXR0b24sIGFcIixcblx0XHRcdFwiY29udHJvbGdyb3VwTGFiZWxcIjogXCIudWktY29udHJvbGdyb3VwLWxhYmVsXCIsXG5cdFx0XHRcImNoZWNrYm94cmFkaW9cIjogXCJpbnB1dFt0eXBlPSdjaGVja2JveCddLCBpbnB1dFt0eXBlPSdyYWRpbyddXCIsXG5cdFx0XHRcInNlbGVjdG1lbnVcIjogXCJzZWxlY3RcIixcblx0XHRcdFwic3Bpbm5lclwiOiBcIi51aS1zcGlubmVyLWlucHV0XCJcblx0XHR9XG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fZW5oYW5jZSgpO1xuXHR9LFxuXG5cdC8vIFRvIHN1cHBvcnQgdGhlIGVuaGFuY2VkIG9wdGlvbiBpbiBqUXVlcnkgTW9iaWxlLCB3ZSBpc29sYXRlIERPTSBtYW5pcHVsYXRpb25cblx0X2VuaGFuY2U6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcInJvbGVcIiwgXCJ0b29sYmFyXCIgKTtcblx0XHR0aGlzLnJlZnJlc2goKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fY2FsbENoaWxkTWV0aG9kKCBcImRlc3Ryb3lcIiApO1xuXHRcdHRoaXMuY2hpbGRXaWRnZXRzLnJlbW92ZURhdGEoIFwidWktY29udHJvbGdyb3VwLWRhdGFcIiApO1xuXHRcdHRoaXMuZWxlbWVudC5yZW1vdmVBdHRyKCBcInJvbGVcIiApO1xuXHRcdGlmICggdGhpcy5vcHRpb25zLml0ZW1zLmNvbnRyb2xncm91cExhYmVsICkge1xuXHRcdFx0dGhpcy5lbGVtZW50XG5cdFx0XHRcdC5maW5kKCB0aGlzLm9wdGlvbnMuaXRlbXMuY29udHJvbGdyb3VwTGFiZWwgKVxuXHRcdFx0XHQuZmluZCggXCIudWktY29udHJvbGdyb3VwLWxhYmVsLWNvbnRlbnRzXCIgKVxuXHRcdFx0XHQuY29udGVudHMoKS51bndyYXAoKTtcblx0XHR9XG5cdH0sXG5cblx0X2luaXRXaWRnZXRzOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRjaGlsZFdpZGdldHMgPSBbXTtcblxuXHRcdC8vIEZpcnN0IHdlIGl0ZXJhdGUgb3ZlciBlYWNoIG9mIHRoZSBpdGVtcyBvcHRpb25zXG5cdFx0JC5lYWNoKCB0aGlzLm9wdGlvbnMuaXRlbXMsIGZ1bmN0aW9uKCB3aWRnZXQsIHNlbGVjdG9yICkge1xuXHRcdFx0dmFyIGxhYmVscztcblx0XHRcdHZhciBvcHRpb25zID0ge307XG5cblx0XHRcdC8vIE1ha2Ugc3VyZSB0aGUgd2lkZ2V0IGhhcyBhIHNlbGVjdG9yIHNldFxuXHRcdFx0aWYgKCAhc2VsZWN0b3IgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB3aWRnZXQgPT09IFwiY29udHJvbGdyb3VwTGFiZWxcIiApIHtcblx0XHRcdFx0bGFiZWxzID0gdGhhdC5lbGVtZW50LmZpbmQoIHNlbGVjdG9yICk7XG5cdFx0XHRcdGxhYmVscy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR2YXIgZWxlbWVudCA9ICQoIHRoaXMgKTtcblxuXHRcdFx0XHRcdGlmICggZWxlbWVudC5jaGlsZHJlbiggXCIudWktY29udHJvbGdyb3VwLWxhYmVsLWNvbnRlbnRzXCIgKS5sZW5ndGggKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGVsZW1lbnQuY29udGVudHMoKVxuXHRcdFx0XHRcdFx0LndyYXBBbGwoIFwiPHNwYW4gY2xhc3M9J3VpLWNvbnRyb2xncm91cC1sYWJlbC1jb250ZW50cyc+PC9zcGFuPlwiICk7XG5cdFx0XHRcdH0gKTtcblx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIGxhYmVscywgbnVsbCwgXCJ1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnQgdWktc3RhdGUtZGVmYXVsdFwiICk7XG5cdFx0XHRcdGNoaWxkV2lkZ2V0cyA9IGNoaWxkV2lkZ2V0cy5jb25jYXQoIGxhYmVscy5nZXQoKSApO1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdC8vIE1ha2Ugc3VyZSB0aGUgd2lkZ2V0IGFjdHVhbGx5IGV4aXN0c1xuXHRcdFx0aWYgKCAhJC5mblsgd2lkZ2V0IF0gKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0Ly8gV2UgYXNzdW1lIGV2ZXJ5dGhpbmcgaXMgaW4gdGhlIG1pZGRsZSB0byBzdGFydCBiZWNhdXNlIHdlIGNhbid0IGRldGVybWluZVxuXHRcdFx0Ly8gZmlyc3QgLyBsYXN0IGVsZW1lbnRzIHVudGlsIGFsbCBlbmhhbmNtZW50cyBhcmUgZG9uZS5cblx0XHRcdGlmICggdGhhdFsgXCJfXCIgKyB3aWRnZXQgKyBcIk9wdGlvbnNcIiBdICkge1xuXHRcdFx0XHRvcHRpb25zID0gdGhhdFsgXCJfXCIgKyB3aWRnZXQgKyBcIk9wdGlvbnNcIiBdKCBcIm1pZGRsZVwiICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRvcHRpb25zID0geyBjbGFzc2VzOiB7fSB9O1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBGaW5kIGluc3RhbmNlcyBvZiB0aGlzIHdpZGdldCBpbnNpZGUgY29udHJvbGdyb3VwIGFuZCBpbml0IHRoZW1cblx0XHRcdHRoYXQuZWxlbWVudFxuXHRcdFx0XHQuZmluZCggc2VsZWN0b3IgKVxuXHRcdFx0XHQuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0dmFyIGVsZW1lbnQgPSAkKCB0aGlzICk7XG5cdFx0XHRcdFx0dmFyIGluc3RhbmNlID0gZWxlbWVudFsgd2lkZ2V0IF0oIFwiaW5zdGFuY2VcIiApO1xuXG5cdFx0XHRcdFx0Ly8gV2UgbmVlZCB0byBjbG9uZSB0aGUgZGVmYXVsdCBvcHRpb25zIGZvciB0aGlzIHR5cGUgb2Ygd2lkZ2V0IHRvIGF2b2lkXG5cdFx0XHRcdFx0Ly8gcG9sbHV0aW5nIHRoZSB2YXJpYWJsZSBvcHRpb25zIHdoaWNoIGhhcyBhIHdpZGVyIHNjb3BlIHRoYW4gYSBzaW5nbGUgd2lkZ2V0LlxuXHRcdFx0XHRcdHZhciBpbnN0YW5jZU9wdGlvbnMgPSAkLndpZGdldC5leHRlbmQoIHt9LCBvcHRpb25zICk7XG5cblx0XHRcdFx0XHQvLyBJZiB0aGUgYnV0dG9uIGlzIHRoZSBjaGlsZCBvZiBhIHNwaW5uZXIgaWdub3JlIGl0XG5cdFx0XHRcdFx0Ly8gVE9ETzogRmluZCBhIG1vcmUgZ2VuZXJpYyBzb2x1dGlvblxuXHRcdFx0XHRcdGlmICggd2lkZ2V0ID09PSBcImJ1dHRvblwiICYmIGVsZW1lbnQucGFyZW50KCBcIi51aS1zcGlubmVyXCIgKS5sZW5ndGggKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gQ3JlYXRlIHRoZSB3aWRnZXQgaWYgaXQgZG9lc24ndCBleGlzdFxuXHRcdFx0XHRcdGlmICggIWluc3RhbmNlICkge1xuXHRcdFx0XHRcdFx0aW5zdGFuY2UgPSBlbGVtZW50WyB3aWRnZXQgXSgpWyB3aWRnZXQgXSggXCJpbnN0YW5jZVwiICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGlmICggaW5zdGFuY2UgKSB7XG5cdFx0XHRcdFx0XHRpbnN0YW5jZU9wdGlvbnMuY2xhc3NlcyA9XG5cdFx0XHRcdFx0XHRcdHRoYXQuX3Jlc29sdmVDbGFzc2VzVmFsdWVzKCBpbnN0YW5jZU9wdGlvbnMuY2xhc3NlcywgaW5zdGFuY2UgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0ZWxlbWVudFsgd2lkZ2V0IF0oIGluc3RhbmNlT3B0aW9ucyApO1xuXG5cdFx0XHRcdFx0Ly8gU3RvcmUgYW4gaW5zdGFuY2Ugb2YgdGhlIGNvbnRyb2xncm91cCB0byBiZSBhYmxlIHRvIHJlZmVyZW5jZVxuXHRcdFx0XHRcdC8vIGZyb20gdGhlIG91dGVybW9zdCBlbGVtZW50IGZvciBjaGFuZ2luZyBvcHRpb25zIGFuZCByZWZyZXNoXG5cdFx0XHRcdFx0dmFyIHdpZGdldEVsZW1lbnQgPSBlbGVtZW50WyB3aWRnZXQgXSggXCJ3aWRnZXRcIiApO1xuXHRcdFx0XHRcdCQuZGF0YSggd2lkZ2V0RWxlbWVudFsgMCBdLCBcInVpLWNvbnRyb2xncm91cC1kYXRhXCIsXG5cdFx0XHRcdFx0XHRpbnN0YW5jZSA/IGluc3RhbmNlIDogZWxlbWVudFsgd2lkZ2V0IF0oIFwiaW5zdGFuY2VcIiApICk7XG5cblx0XHRcdFx0XHRjaGlsZFdpZGdldHMucHVzaCggd2lkZ2V0RWxlbWVudFsgMCBdICk7XG5cdFx0XHRcdH0gKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLmNoaWxkV2lkZ2V0cyA9ICQoICQudW5pcXVlKCBjaGlsZFdpZGdldHMgKSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmNoaWxkV2lkZ2V0cywgXCJ1aS1jb250cm9sZ3JvdXAtaXRlbVwiICk7XG5cdH0sXG5cblx0X2NhbGxDaGlsZE1ldGhvZDogZnVuY3Rpb24oIG1ldGhvZCApIHtcblx0XHR0aGlzLmNoaWxkV2lkZ2V0cy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBlbGVtZW50ID0gJCggdGhpcyApLFxuXHRcdFx0XHRkYXRhID0gZWxlbWVudC5kYXRhKCBcInVpLWNvbnRyb2xncm91cC1kYXRhXCIgKTtcblx0XHRcdGlmICggZGF0YSAmJiBkYXRhWyBtZXRob2QgXSApIHtcblx0XHRcdFx0ZGF0YVsgbWV0aG9kIF0oKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X3VwZGF0ZUNvcm5lckNsYXNzOiBmdW5jdGlvbiggZWxlbWVudCwgcG9zaXRpb24gKSB7XG5cdFx0dmFyIHJlbW92ZSA9IFwidWktY29ybmVyLXRvcCB1aS1jb3JuZXItYm90dG9tIHVpLWNvcm5lci1sZWZ0IHVpLWNvcm5lci1yaWdodCB1aS1jb3JuZXItYWxsXCI7XG5cdFx0dmFyIGFkZCA9IHRoaXMuX2J1aWxkU2ltcGxlT3B0aW9ucyggcG9zaXRpb24sIFwibGFiZWxcIiApLmNsYXNzZXMubGFiZWw7XG5cblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggZWxlbWVudCwgbnVsbCwgcmVtb3ZlICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIGVsZW1lbnQsIG51bGwsIGFkZCApO1xuXHR9LFxuXG5cdF9idWlsZFNpbXBsZU9wdGlvbnM6IGZ1bmN0aW9uKCBwb3NpdGlvbiwga2V5ICkge1xuXHRcdHZhciBkaXJlY3Rpb24gPSB0aGlzLm9wdGlvbnMuZGlyZWN0aW9uID09PSBcInZlcnRpY2FsXCI7XG5cdFx0dmFyIHJlc3VsdCA9IHtcblx0XHRcdGNsYXNzZXM6IHt9XG5cdFx0fTtcblx0XHRyZXN1bHQuY2xhc3Nlc1sga2V5IF0gPSB7XG5cdFx0XHRcIm1pZGRsZVwiOiBcIlwiLFxuXHRcdFx0XCJmaXJzdFwiOiBcInVpLWNvcm5lci1cIiArICggZGlyZWN0aW9uID8gXCJ0b3BcIiA6IFwibGVmdFwiICksXG5cdFx0XHRcImxhc3RcIjogXCJ1aS1jb3JuZXItXCIgKyAoIGRpcmVjdGlvbiA/IFwiYm90dG9tXCIgOiBcInJpZ2h0XCIgKSxcblx0XHRcdFwib25seVwiOiBcInVpLWNvcm5lci1hbGxcIlxuXHRcdH1bIHBvc2l0aW9uIF07XG5cblx0XHRyZXR1cm4gcmVzdWx0O1xuXHR9LFxuXG5cdF9zcGlubmVyT3B0aW9uczogZnVuY3Rpb24oIHBvc2l0aW9uICkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5fYnVpbGRTaW1wbGVPcHRpb25zKCBwb3NpdGlvbiwgXCJ1aS1zcGlubmVyXCIgKTtcblxuXHRcdG9wdGlvbnMuY2xhc3Nlc1sgXCJ1aS1zcGlubmVyLXVwXCIgXSA9IFwiXCI7XG5cdFx0b3B0aW9ucy5jbGFzc2VzWyBcInVpLXNwaW5uZXItZG93blwiIF0gPSBcIlwiO1xuXG5cdFx0cmV0dXJuIG9wdGlvbnM7XG5cdH0sXG5cblx0X2J1dHRvbk9wdGlvbnM6IGZ1bmN0aW9uKCBwb3NpdGlvbiApIHtcblx0XHRyZXR1cm4gdGhpcy5fYnVpbGRTaW1wbGVPcHRpb25zKCBwb3NpdGlvbiwgXCJ1aS1idXR0b25cIiApO1xuXHR9LFxuXG5cdF9jaGVja2JveHJhZGlvT3B0aW9uczogZnVuY3Rpb24oIHBvc2l0aW9uICkge1xuXHRcdHJldHVybiB0aGlzLl9idWlsZFNpbXBsZU9wdGlvbnMoIHBvc2l0aW9uLCBcInVpLWNoZWNrYm94cmFkaW8tbGFiZWxcIiApO1xuXHR9LFxuXG5cdF9zZWxlY3RtZW51T3B0aW9uczogZnVuY3Rpb24oIHBvc2l0aW9uICkge1xuXHRcdHZhciBkaXJlY3Rpb24gPSB0aGlzLm9wdGlvbnMuZGlyZWN0aW9uID09PSBcInZlcnRpY2FsXCI7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHdpZHRoOiBkaXJlY3Rpb24gPyBcImF1dG9cIiA6IGZhbHNlLFxuXHRcdFx0Y2xhc3Nlczoge1xuXHRcdFx0XHRtaWRkbGU6IHtcblx0XHRcdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLW9wZW5cIjogXCJcIixcblx0XHRcdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLWNsb3NlZFwiOiBcIlwiXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGZpcnN0OiB7XG5cdFx0XHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1vcGVuXCI6IFwidWktY29ybmVyLVwiICsgKCBkaXJlY3Rpb24gPyBcInRvcFwiIDogXCJ0bFwiICksXG5cdFx0XHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1jbG9zZWRcIjogXCJ1aS1jb3JuZXItXCIgKyAoIGRpcmVjdGlvbiA/IFwidG9wXCIgOiBcImxlZnRcIiApXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGxhc3Q6IHtcblx0XHRcdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLW9wZW5cIjogZGlyZWN0aW9uID8gXCJcIiA6IFwidWktY29ybmVyLXRyXCIsXG5cdFx0XHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1jbG9zZWRcIjogXCJ1aS1jb3JuZXItXCIgKyAoIGRpcmVjdGlvbiA/IFwiYm90dG9tXCIgOiBcInJpZ2h0XCIgKVxuXHRcdFx0XHR9LFxuXHRcdFx0XHRvbmx5OiB7XG5cdFx0XHRcdFx0XCJ1aS1zZWxlY3RtZW51LWJ1dHRvbi1vcGVuXCI6IFwidWktY29ybmVyLXRvcFwiLFxuXHRcdFx0XHRcdFwidWktc2VsZWN0bWVudS1idXR0b24tY2xvc2VkXCI6IFwidWktY29ybmVyLWFsbFwiXG5cdFx0XHRcdH1cblxuXHRcdFx0fVsgcG9zaXRpb24gXVxuXHRcdH07XG5cdH0sXG5cblx0X3Jlc29sdmVDbGFzc2VzVmFsdWVzOiBmdW5jdGlvbiggY2xhc3NlcywgaW5zdGFuY2UgKSB7XG5cdFx0dmFyIHJlc3VsdCA9IHt9O1xuXHRcdCQuZWFjaCggY2xhc3NlcywgZnVuY3Rpb24oIGtleSApIHtcblx0XHRcdHZhciBjdXJyZW50ID0gaW5zdGFuY2Uub3B0aW9ucy5jbGFzc2VzWyBrZXkgXSB8fCBcIlwiO1xuXHRcdFx0Y3VycmVudCA9ICQudHJpbSggY3VycmVudC5yZXBsYWNlKCBjb250cm9sZ3JvdXBDb3JuZXJSZWdleCwgXCJcIiApICk7XG5cdFx0XHRyZXN1bHRbIGtleSBdID0gKCBjdXJyZW50ICsgXCIgXCIgKyBjbGFzc2VzWyBrZXkgXSApLnJlcGxhY2UoIC9cXHMrL2csIFwiIFwiICk7XG5cdFx0fSApO1xuXHRcdHJldHVybiByZXN1bHQ7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0aWYgKCBrZXkgPT09IFwiZGlyZWN0aW9uXCIgKSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggXCJ1aS1jb250cm9sZ3JvdXAtXCIgKyB0aGlzLm9wdGlvbnMuZGlyZWN0aW9uICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblx0XHRpZiAoIGtleSA9PT0gXCJkaXNhYmxlZFwiICkge1xuXHRcdFx0dGhpcy5fY2FsbENoaWxkTWV0aG9kKCB2YWx1ZSA/IFwiZGlzYWJsZVwiIDogXCJlbmFibGVcIiApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMucmVmcmVzaCgpO1xuXHR9LFxuXG5cdHJlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBjaGlsZHJlbixcblx0XHRcdHRoYXQgPSB0aGlzO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktY29udHJvbGdyb3VwIHVpLWNvbnRyb2xncm91cC1cIiArIHRoaXMub3B0aW9ucy5kaXJlY3Rpb24gKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpcmVjdGlvbiA9PT0gXCJob3Jpem9udGFsXCIgKSB7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggbnVsbCwgXCJ1aS1oZWxwZXItY2xlYXJmaXhcIiApO1xuXHRcdH1cblx0XHR0aGlzLl9pbml0V2lkZ2V0cygpO1xuXG5cdFx0Y2hpbGRyZW4gPSB0aGlzLmNoaWxkV2lkZ2V0cztcblxuXHRcdC8vIFdlIGZpbHRlciBoZXJlIGJlY2F1c2Ugd2UgbmVlZCB0byB0cmFjayBhbGwgY2hpbGRXaWRnZXRzIG5vdCBqdXN0IHRoZSB2aXNpYmxlIG9uZXNcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5vbmx5VmlzaWJsZSApIHtcblx0XHRcdGNoaWxkcmVuID0gY2hpbGRyZW4uZmlsdGVyKCBcIjp2aXNpYmxlXCIgKTtcblx0XHR9XG5cblx0XHRpZiAoIGNoaWxkcmVuLmxlbmd0aCApIHtcblxuXHRcdFx0Ly8gV2UgZG8gdGhpcyBsYXN0IGJlY2F1c2Ugd2UgbmVlZCB0byBtYWtlIHN1cmUgYWxsIGVuaGFuY21lbnQgaXMgZG9uZVxuXHRcdFx0Ly8gYmVmb3JlIGRldGVybWluaW5nIGZpcnN0IGFuZCBsYXN0XG5cdFx0XHQkLmVhY2goIFsgXCJmaXJzdFwiLCBcImxhc3RcIiBdLCBmdW5jdGlvbiggaW5kZXgsIHZhbHVlICkge1xuXHRcdFx0XHR2YXIgaW5zdGFuY2UgPSBjaGlsZHJlblsgdmFsdWUgXSgpLmRhdGEoIFwidWktY29udHJvbGdyb3VwLWRhdGFcIiApO1xuXG5cdFx0XHRcdGlmICggaW5zdGFuY2UgJiYgdGhhdFsgXCJfXCIgKyBpbnN0YW5jZS53aWRnZXROYW1lICsgXCJPcHRpb25zXCIgXSApIHtcblx0XHRcdFx0XHR2YXIgb3B0aW9ucyA9IHRoYXRbIFwiX1wiICsgaW5zdGFuY2Uud2lkZ2V0TmFtZSArIFwiT3B0aW9uc1wiIF0oXG5cdFx0XHRcdFx0XHRjaGlsZHJlbi5sZW5ndGggPT09IDEgPyBcIm9ubHlcIiA6IHZhbHVlXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRvcHRpb25zLmNsYXNzZXMgPSB0aGF0Ll9yZXNvbHZlQ2xhc3Nlc1ZhbHVlcyggb3B0aW9ucy5jbGFzc2VzLCBpbnN0YW5jZSApO1xuXHRcdFx0XHRcdGluc3RhbmNlLmVsZW1lbnRbIGluc3RhbmNlLndpZGdldE5hbWUgXSggb3B0aW9ucyApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRoYXQuX3VwZGF0ZUNvcm5lckNsYXNzKCBjaGlsZHJlblsgdmFsdWUgXSgpLCB2YWx1ZSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cblx0XHRcdC8vIEZpbmFsbHkgY2FsbCB0aGUgcmVmcmVzaCBtZXRob2Qgb24gZWFjaCBvZiB0aGUgY2hpbGQgd2lkZ2V0cy5cblx0XHRcdHRoaXMuX2NhbGxDaGlsZE1ldGhvZCggXCJyZWZyZXNoXCIgKTtcblx0XHR9XG5cdH1cbn0gKTtcblxuLyohXG4gKiBqUXVlcnkgVUkgQ2hlY2tib3hyYWRpbyAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogQ2hlY2tib3hyYWRpb1xuLy8+Pmdyb3VwOiBXaWRnZXRzXG4vLz4+ZGVzY3JpcHRpb246IEVuaGFuY2VzIGEgZm9ybSB3aXRoIG11bHRpcGxlIHRoZW1lYWJsZSBjaGVja2JveGVzIG9yIHJhZGlvIGJ1dHRvbnMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vY2hlY2tib3hyYWRpby9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9jaGVja2JveHJhZGlvL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvYnV0dG9uLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NoZWNrYm94cmFkaW8uY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbiQud2lkZ2V0KCBcInVpLmNoZWNrYm94cmFkaW9cIiwgWyAkLnVpLmZvcm1SZXNldE1peGluLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRkaXNhYmxlZDogbnVsbCxcblx0XHRsYWJlbDogbnVsbCxcblx0XHRpY29uOiB0cnVlLFxuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktY2hlY2tib3hyYWRpby1sYWJlbFwiOiBcInVpLWNvcm5lci1hbGxcIixcblx0XHRcdFwidWktY2hlY2tib3hyYWRpby1pY29uXCI6IFwidWktY29ybmVyLWFsbFwiXG5cdFx0fVxuXHR9LFxuXG5cdF9nZXRDcmVhdGVPcHRpb25zOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZGlzYWJsZWQsIGxhYmVscztcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLl9zdXBlcigpIHx8IHt9O1xuXG5cdFx0Ly8gV2UgcmVhZCB0aGUgdHlwZSBoZXJlLCBiZWNhdXNlIGl0IG1ha2VzIG1vcmUgc2Vuc2UgdG8gdGhyb3cgYSBlbGVtZW50IHR5cGUgZXJyb3IgZmlyc3QsXG5cdFx0Ly8gcmF0aGVyIHRoZW4gdGhlIGVycm9yIGZvciBsYWNrIG9mIGEgbGFiZWwuIE9mdGVuIGlmIGl0cyB0aGUgd3JvbmcgdHlwZSwgaXRcblx0XHQvLyB3b24ndCBoYXZlIGEgbGFiZWwgKGUuZy4gY2FsbGluZyBvbiBhIGRpdiwgYnRuLCBldGMpXG5cdFx0dGhpcy5fcmVhZFR5cGUoKTtcblxuXHRcdGxhYmVscyA9IHRoaXMuZWxlbWVudC5sYWJlbHMoKTtcblxuXHRcdC8vIElmIHRoZXJlIGFyZSBtdWx0aXBsZSBsYWJlbHMsIHVzZSB0aGUgbGFzdCBvbmVcblx0XHR0aGlzLmxhYmVsID0gJCggbGFiZWxzWyBsYWJlbHMubGVuZ3RoIC0gMSBdICk7XG5cdFx0aWYgKCAhdGhpcy5sYWJlbC5sZW5ndGggKSB7XG5cdFx0XHQkLmVycm9yKCBcIk5vIGxhYmVsIGZvdW5kIGZvciBjaGVja2JveHJhZGlvIHdpZGdldFwiICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5vcmlnaW5hbExhYmVsID0gXCJcIjtcblxuXHRcdC8vIFdlIG5lZWQgdG8gZ2V0IHRoZSBsYWJlbCB0ZXh0IGJ1dCB0aGlzIG1heSBhbHNvIG5lZWQgdG8gbWFrZSBzdXJlIGl0IGRvZXMgbm90IGNvbnRhaW4gdGhlXG5cdFx0Ly8gaW5wdXQgaXRzZWxmLlxuXHRcdHRoaXMubGFiZWwuY29udGVudHMoKS5ub3QoIHRoaXMuZWxlbWVudFsgMCBdICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIFRoZSBsYWJlbCBjb250ZW50cyBjb3VsZCBiZSB0ZXh0LCBodG1sLCBvciBhIG1peC4gV2UgY29uY2F0IGVhY2ggZWxlbWVudCB0byBnZXQgYVxuXHRcdFx0Ly8gc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBsYWJlbCwgd2l0aG91dCB0aGUgaW5wdXQgYXMgcGFydCBvZiBpdC5cblx0XHRcdHRoYXQub3JpZ2luYWxMYWJlbCArPSB0aGlzLm5vZGVUeXBlID09PSAzID8gJCggdGhpcyApLnRleHQoKSA6IHRoaXMub3V0ZXJIVE1MO1xuXHRcdH0gKTtcblxuXHRcdC8vIFNldCB0aGUgbGFiZWwgb3B0aW9uIGlmIHdlIGZvdW5kIGxhYmVsIHRleHRcblx0XHRpZiAoIHRoaXMub3JpZ2luYWxMYWJlbCApIHtcblx0XHRcdG9wdGlvbnMubGFiZWwgPSB0aGlzLm9yaWdpbmFsTGFiZWw7XG5cdFx0fVxuXG5cdFx0ZGlzYWJsZWQgPSB0aGlzLmVsZW1lbnRbIDAgXS5kaXNhYmxlZDtcblx0XHRpZiAoIGRpc2FibGVkICE9IG51bGwgKSB7XG5cdFx0XHRvcHRpb25zLmRpc2FibGVkID0gZGlzYWJsZWQ7XG5cdFx0fVxuXHRcdHJldHVybiBvcHRpb25zO1xuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBjaGVja2VkID0gdGhpcy5lbGVtZW50WyAwIF0uY2hlY2tlZDtcblxuXHRcdHRoaXMuX2JpbmRGb3JtUmVzZXRIYW5kbGVyKCk7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCA9PSBudWxsICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLmRpc2FibGVkID0gdGhpcy5lbGVtZW50WyAwIF0uZGlzYWJsZWQ7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc2V0T3B0aW9uKCBcImRpc2FibGVkXCIsIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWNoZWNrYm94cmFkaW9cIiwgXCJ1aS1oZWxwZXItaGlkZGVuLWFjY2Vzc2libGVcIiApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmxhYmVsLCBcInVpLWNoZWNrYm94cmFkaW8tbGFiZWxcIiwgXCJ1aS1idXR0b24gdWktd2lkZ2V0XCIgKTtcblxuXHRcdGlmICggdGhpcy50eXBlID09PSBcInJhZGlvXCIgKSB7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5sYWJlbCwgXCJ1aS1jaGVja2JveHJhZGlvLXJhZGlvLWxhYmVsXCIgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5sYWJlbCAmJiB0aGlzLm9wdGlvbnMubGFiZWwgIT09IHRoaXMub3JpZ2luYWxMYWJlbCApIHtcblx0XHRcdHRoaXMuX3VwZGF0ZUxhYmVsKCk7XG5cdFx0fSBlbHNlIGlmICggdGhpcy5vcmlnaW5hbExhYmVsICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLmxhYmVsID0gdGhpcy5vcmlnaW5hbExhYmVsO1xuXHRcdH1cblxuXHRcdHRoaXMuX2VuaGFuY2UoKTtcblxuXHRcdGlmICggY2hlY2tlZCApIHtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmxhYmVsLCBcInVpLWNoZWNrYm94cmFkaW8tY2hlY2tlZFwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHRpZiAoIHRoaXMuaWNvbiApIHtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaWNvbiwgbnVsbCwgXCJ1aS1zdGF0ZS1ob3ZlclwiICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5fb24oIHtcblx0XHRcdGNoYW5nZTogXCJfdG9nZ2xlQ2xhc3Nlc1wiLFxuXHRcdFx0Zm9jdXM6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5sYWJlbCwgbnVsbCwgXCJ1aS1zdGF0ZS1mb2N1cyB1aS12aXN1YWwtZm9jdXNcIiApO1xuXHRcdFx0fSxcblx0XHRcdGJsdXI6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5sYWJlbCwgbnVsbCwgXCJ1aS1zdGF0ZS1mb2N1cyB1aS12aXN1YWwtZm9jdXNcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfcmVhZFR5cGU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBub2RlTmFtZSA9IHRoaXMuZWxlbWVudFsgMCBdLm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cdFx0dGhpcy50eXBlID0gdGhpcy5lbGVtZW50WyAwIF0udHlwZTtcblx0XHRpZiAoIG5vZGVOYW1lICE9PSBcImlucHV0XCIgfHwgIS9yYWRpb3xjaGVja2JveC8udGVzdCggdGhpcy50eXBlICkgKSB7XG5cdFx0XHQkLmVycm9yKCBcIkNhbid0IGNyZWF0ZSBjaGVja2JveHJhZGlvIG9uIGVsZW1lbnQubm9kZU5hbWU9XCIgKyBub2RlTmFtZSArXG5cdFx0XHRcdFwiIGFuZCBlbGVtZW50LnR5cGU9XCIgKyB0aGlzLnR5cGUgKTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gU3VwcG9ydCBqUXVlcnkgTW9iaWxlIGVuaGFuY2VkIG9wdGlvblxuXHRfZW5oYW5jZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fdXBkYXRlSWNvbiggdGhpcy5lbGVtZW50WyAwIF0uY2hlY2tlZCApO1xuXHR9LFxuXG5cdHdpZGdldDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMubGFiZWw7XG5cdH0sXG5cblx0X2dldFJhZGlvR3JvdXA6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBncm91cDtcblx0XHR2YXIgbmFtZSA9IHRoaXMuZWxlbWVudFsgMCBdLm5hbWU7XG5cdFx0dmFyIG5hbWVTZWxlY3RvciA9IFwiaW5wdXRbbmFtZT0nXCIgKyAkLnVpLmVzY2FwZVNlbGVjdG9yKCBuYW1lICkgKyBcIiddXCI7XG5cblx0XHRpZiAoICFuYW1lICkge1xuXHRcdFx0cmV0dXJuICQoIFtdICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmZvcm0ubGVuZ3RoICkge1xuXHRcdFx0Z3JvdXAgPSAkKCB0aGlzLmZvcm1bIDAgXS5lbGVtZW50cyApLmZpbHRlciggbmFtZVNlbGVjdG9yICk7XG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gTm90IGluc2lkZSBhIGZvcm0sIGNoZWNrIGFsbCBpbnB1dHMgdGhhdCBhbHNvIGFyZSBub3QgaW5zaWRlIGEgZm9ybVxuXHRcdFx0Z3JvdXAgPSAkKCBuYW1lU2VsZWN0b3IgKS5maWx0ZXIoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gJCggdGhpcyApLmZvcm0oKS5sZW5ndGggPT09IDA7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGdyb3VwLm5vdCggdGhpcy5lbGVtZW50ICk7XG5cdH0sXG5cblx0X3RvZ2dsZUNsYXNzZXM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBjaGVja2VkID0gdGhpcy5lbGVtZW50WyAwIF0uY2hlY2tlZDtcblx0XHR0aGlzLl90b2dnbGVDbGFzcyggdGhpcy5sYWJlbCwgXCJ1aS1jaGVja2JveHJhZGlvLWNoZWNrZWRcIiwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiwgY2hlY2tlZCApO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuaWNvbiAmJiB0aGlzLnR5cGUgPT09IFwiY2hlY2tib3hcIiApIHtcblx0XHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCB0aGlzLmljb24sIG51bGwsIFwidWktaWNvbi1jaGVjayB1aS1zdGF0ZS1jaGVja2VkXCIsIGNoZWNrZWQgKVxuXHRcdFx0XHQuX3RvZ2dsZUNsYXNzKCB0aGlzLmljb24sIG51bGwsIFwidWktaWNvbi1ibGFua1wiLCAhY2hlY2tlZCApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy50eXBlID09PSBcInJhZGlvXCIgKSB7XG5cdFx0XHR0aGlzLl9nZXRSYWRpb0dyb3VwKClcblx0XHRcdFx0LmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdHZhciBpbnN0YW5jZSA9ICQoIHRoaXMgKS5jaGVja2JveHJhZGlvKCBcImluc3RhbmNlXCIgKTtcblxuXHRcdFx0XHRcdGlmICggaW5zdGFuY2UgKSB7XG5cdFx0XHRcdFx0XHRpbnN0YW5jZS5fcmVtb3ZlQ2xhc3MoIGluc3RhbmNlLmxhYmVsLFxuXHRcdFx0XHRcdFx0XHRcInVpLWNoZWNrYm94cmFkaW8tY2hlY2tlZFwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl91bmJpbmRGb3JtUmVzZXRIYW5kbGVyKCk7XG5cblx0XHRpZiAoIHRoaXMuaWNvbiApIHtcblx0XHRcdHRoaXMuaWNvbi5yZW1vdmUoKTtcblx0XHRcdHRoaXMuaWNvblNwYWNlLnJlbW92ZSgpO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblxuXHRcdC8vIFdlIGRvbid0IGFsbG93IHRoZSB2YWx1ZSB0byBiZSBzZXQgdG8gbm90aGluZ1xuXHRcdGlmICgga2V5ID09PSBcImxhYmVsXCIgJiYgIXZhbHVlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJkaXNhYmxlZFwiICkge1xuXHRcdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIHRoaXMubGFiZWwsIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiwgdmFsdWUgKTtcblx0XHRcdHRoaXMuZWxlbWVudFsgMCBdLmRpc2FibGVkID0gdmFsdWU7XG5cblx0XHRcdC8vIERvbid0IHJlZnJlc2ggd2hlbiBzZXR0aW5nIGRpc2FibGVkXG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMucmVmcmVzaCgpO1xuXHR9LFxuXG5cdF91cGRhdGVJY29uOiBmdW5jdGlvbiggY2hlY2tlZCApIHtcblx0XHR2YXIgdG9BZGQgPSBcInVpLWljb24gdWktaWNvbi1iYWNrZ3JvdW5kIFwiO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuaWNvbiApIHtcblx0XHRcdGlmICggIXRoaXMuaWNvbiApIHtcblx0XHRcdFx0dGhpcy5pY29uID0gJCggXCI8c3Bhbj5cIiApO1xuXHRcdFx0XHR0aGlzLmljb25TcGFjZSA9ICQoIFwiPHNwYW4+IDwvc3Bhbj5cIiApO1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5pY29uU3BhY2UsIFwidWktY2hlY2tib3hyYWRpby1pY29uLXNwYWNlXCIgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0aGlzLnR5cGUgPT09IFwiY2hlY2tib3hcIiApIHtcblx0XHRcdFx0dG9BZGQgKz0gY2hlY2tlZCA/IFwidWktaWNvbi1jaGVjayB1aS1zdGF0ZS1jaGVja2VkXCIgOiBcInVpLWljb24tYmxhbmtcIjtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuaWNvbiwgbnVsbCwgY2hlY2tlZCA/IFwidWktaWNvbi1ibGFua1wiIDogXCJ1aS1pY29uLWNoZWNrXCIgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRvQWRkICs9IFwidWktaWNvbi1ibGFua1wiO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaWNvbiwgXCJ1aS1jaGVja2JveHJhZGlvLWljb25cIiwgdG9BZGQgKTtcblx0XHRcdGlmICggIWNoZWNrZWQgKSB7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmljb24sIG51bGwsIFwidWktaWNvbi1jaGVjayB1aS1zdGF0ZS1jaGVja2VkXCIgKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuaWNvbi5wcmVwZW5kVG8oIHRoaXMubGFiZWwgKS5hZnRlciggdGhpcy5pY29uU3BhY2UgKTtcblx0XHR9IGVsc2UgaWYgKCB0aGlzLmljb24gIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuaWNvbi5yZW1vdmUoKTtcblx0XHRcdHRoaXMuaWNvblNwYWNlLnJlbW92ZSgpO1xuXHRcdFx0ZGVsZXRlIHRoaXMuaWNvbjtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZUxhYmVsOiBmdW5jdGlvbigpIHtcblxuXHRcdC8vIFJlbW92ZSB0aGUgY29udGVudHMgb2YgdGhlIGxhYmVsICggbWludXMgdGhlIGljb24sIGljb24gc3BhY2UsIGFuZCBpbnB1dCApXG5cdFx0dmFyIGNvbnRlbnRzID0gdGhpcy5sYWJlbC5jb250ZW50cygpLm5vdCggdGhpcy5lbGVtZW50WyAwIF0gKTtcblx0XHRpZiAoIHRoaXMuaWNvbiApIHtcblx0XHRcdGNvbnRlbnRzID0gY29udGVudHMubm90KCB0aGlzLmljb25bIDAgXSApO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuaWNvblNwYWNlICkge1xuXHRcdFx0Y29udGVudHMgPSBjb250ZW50cy5ub3QoIHRoaXMuaWNvblNwYWNlWyAwIF0gKTtcblx0XHR9XG5cdFx0Y29udGVudHMucmVtb3ZlKCk7XG5cblx0XHR0aGlzLmxhYmVsLmFwcGVuZCggdGhpcy5vcHRpb25zLmxhYmVsICk7XG5cdH0sXG5cblx0cmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGNoZWNrZWQgPSB0aGlzLmVsZW1lbnRbIDAgXS5jaGVja2VkLFxuXHRcdFx0aXNEaXNhYmxlZCA9IHRoaXMuZWxlbWVudFsgMCBdLmRpc2FibGVkO1xuXG5cdFx0dGhpcy5fdXBkYXRlSWNvbiggY2hlY2tlZCApO1xuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCB0aGlzLmxhYmVsLCBcInVpLWNoZWNrYm94cmFkaW8tY2hlY2tlZFwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiLCBjaGVja2VkICk7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMubGFiZWwgIT09IG51bGwgKSB7XG5cdFx0XHR0aGlzLl91cGRhdGVMYWJlbCgpO1xuXHRcdH1cblxuXHRcdGlmICggaXNEaXNhYmxlZCAhPT0gdGhpcy5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0dGhpcy5fc2V0T3B0aW9ucyggeyBcImRpc2FibGVkXCI6IGlzRGlzYWJsZWQgfSApO1xuXHRcdH1cblx0fVxuXG59IF0gKTtcblxudmFyIHdpZGdldHNDaGVja2JveHJhZGlvID0gJC51aS5jaGVja2JveHJhZGlvO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIEJ1dHRvbiAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogQnV0dG9uXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogRW5oYW5jZXMgYSBmb3JtIHdpdGggdGhlbWVhYmxlIGJ1dHRvbnMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vYnV0dG9uL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL2J1dHRvbi9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2J1dHRvbi5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxuJC53aWRnZXQoIFwidWkuYnV0dG9uXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0ZGVmYXVsdEVsZW1lbnQ6IFwiPGJ1dHRvbj5cIixcblx0b3B0aW9uczoge1xuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktYnV0dG9uXCI6IFwidWktY29ybmVyLWFsbFwiXG5cdFx0fSxcblx0XHRkaXNhYmxlZDogbnVsbCxcblx0XHRpY29uOiBudWxsLFxuXHRcdGljb25Qb3NpdGlvbjogXCJiZWdpbm5pbmdcIixcblx0XHRsYWJlbDogbnVsbCxcblx0XHRzaG93TGFiZWw6IHRydWVcblx0fSxcblxuXHRfZ2V0Q3JlYXRlT3B0aW9uczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGRpc2FibGVkLFxuXG5cdFx0XHQvLyBUaGlzIGlzIHRvIHN1cHBvcnQgY2FzZXMgbGlrZSBpbiBqUXVlcnkgTW9iaWxlIHdoZXJlIHRoZSBiYXNlIHdpZGdldCBkb2VzIGhhdmVcblx0XHRcdC8vIGFuIGltcGxlbWVudGF0aW9uIG9mIF9nZXRDcmVhdGVPcHRpb25zXG5cdFx0XHRvcHRpb25zID0gdGhpcy5fc3VwZXIoKSB8fCB7fTtcblxuXHRcdHRoaXMuaXNJbnB1dCA9IHRoaXMuZWxlbWVudC5pcyggXCJpbnB1dFwiICk7XG5cblx0XHRkaXNhYmxlZCA9IHRoaXMuZWxlbWVudFsgMCBdLmRpc2FibGVkO1xuXHRcdGlmICggZGlzYWJsZWQgIT0gbnVsbCApIHtcblx0XHRcdG9wdGlvbnMuZGlzYWJsZWQgPSBkaXNhYmxlZDtcblx0XHR9XG5cblx0XHR0aGlzLm9yaWdpbmFsTGFiZWwgPSB0aGlzLmlzSW5wdXQgPyB0aGlzLmVsZW1lbnQudmFsKCkgOiB0aGlzLmVsZW1lbnQuaHRtbCgpO1xuXHRcdGlmICggdGhpcy5vcmlnaW5hbExhYmVsICkge1xuXHRcdFx0b3B0aW9ucy5sYWJlbCA9IHRoaXMub3JpZ2luYWxMYWJlbDtcblx0XHR9XG5cblx0XHRyZXR1cm4gb3B0aW9ucztcblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHRpZiAoICF0aGlzLm9wdGlvbi5zaG93TGFiZWwgJiAhdGhpcy5vcHRpb25zLmljb24gKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMuc2hvd0xhYmVsID0gdHJ1ZTtcblx0XHR9XG5cblx0XHQvLyBXZSBoYXZlIHRvIGNoZWNrIHRoZSBvcHRpb24gYWdhaW4gaGVyZSBldmVuIHRob3VnaCB3ZSBkaWQgaW4gX2dldENyZWF0ZU9wdGlvbnMsXG5cdFx0Ly8gYmVjYXVzZSBudWxsIG1heSBoYXZlIGJlZW4gcGFzc2VkIG9uIGluaXQgd2hpY2ggd291bGQgb3ZlcnJpZGUgd2hhdCB3YXMgc2V0IGluXG5cdFx0Ly8gX2dldENyZWF0ZU9wdGlvbnNcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5kaXNhYmxlZCA9PSBudWxsICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLmRpc2FibGVkID0gdGhpcy5lbGVtZW50WyAwIF0uZGlzYWJsZWQgfHwgZmFsc2U7XG5cdFx0fVxuXG5cdFx0dGhpcy5oYXNUaXRsZSA9ICEhdGhpcy5lbGVtZW50LmF0dHIoIFwidGl0bGVcIiApO1xuXG5cdFx0Ly8gQ2hlY2sgdG8gc2VlIGlmIHRoZSBsYWJlbCBuZWVkcyB0byBiZSBzZXQgb3IgaWYgaXRzIGFscmVhZHkgY29ycmVjdFxuXHRcdGlmICggdGhpcy5vcHRpb25zLmxhYmVsICYmIHRoaXMub3B0aW9ucy5sYWJlbCAhPT0gdGhpcy5vcmlnaW5hbExhYmVsICkge1xuXHRcdFx0aWYgKCB0aGlzLmlzSW5wdXQgKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC52YWwoIHRoaXMub3B0aW9ucy5sYWJlbCApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50Lmh0bWwoIHRoaXMub3B0aW9ucy5sYWJlbCApO1xuXHRcdFx0fVxuXHRcdH1cblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1idXR0b25cIiwgXCJ1aS13aWRnZXRcIiApO1xuXHRcdHRoaXMuX3NldE9wdGlvbiggXCJkaXNhYmxlZFwiLCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKTtcblx0XHR0aGlzLl9lbmhhbmNlKCk7XG5cblx0XHRpZiAoIHRoaXMuZWxlbWVudC5pcyggXCJhXCIgKSApIHtcblx0XHRcdHRoaXMuX29uKCB7XG5cdFx0XHRcdFwia2V5dXBcIjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRcdGlmICggZXZlbnQua2V5Q29kZSA9PT0gJC51aS5rZXlDb2RlLlNQQUNFICkge1xuXHRcdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuXHRcdFx0XHRcdFx0Ly8gU3VwcG9ydDogUGhhbnRvbUpTIDw9IDEuOSwgSUUgOCBPbmx5XG5cdFx0XHRcdFx0XHQvLyBJZiBhIG5hdGl2ZSBjbGljayBpcyBhdmFpbGFibGUgdXNlIGl0IHNvIHdlIGFjdHVhbGx5IGNhdXNlIG5hdmlnYXRpb25cblx0XHRcdFx0XHRcdC8vIG90aGVyd2lzZSBqdXN0IHRyaWdnZXIgYSBjbGljayBldmVudFxuXHRcdFx0XHRcdFx0aWYgKCB0aGlzLmVsZW1lbnRbIDAgXS5jbGljayApIHtcblx0XHRcdFx0XHRcdFx0dGhpcy5lbGVtZW50WyAwIF0uY2xpY2soKTtcblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRcdHRoaXMuZWxlbWVudC50cmlnZ2VyKCBcImNsaWNrXCIgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHR9XG5cdH0sXG5cblx0X2VuaGFuY2U6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggIXRoaXMuZWxlbWVudC5pcyggXCJidXR0b25cIiApICkge1xuXHRcdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwicm9sZVwiLCBcImJ1dHRvblwiICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuaWNvbiApIHtcblx0XHRcdHRoaXMuX3VwZGF0ZUljb24oIFwiaWNvblwiLCB0aGlzLm9wdGlvbnMuaWNvbiApO1xuXHRcdFx0dGhpcy5fdXBkYXRlVG9vbHRpcCgpO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlVG9vbHRpcDogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy50aXRsZSA9IHRoaXMuZWxlbWVudC5hdHRyKCBcInRpdGxlXCIgKTtcblxuXHRcdGlmICggIXRoaXMub3B0aW9ucy5zaG93TGFiZWwgJiYgIXRoaXMudGl0bGUgKSB7XG5cdFx0XHR0aGlzLmVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiLCB0aGlzLm9wdGlvbnMubGFiZWwgKTtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZUljb246IGZ1bmN0aW9uKCBvcHRpb24sIHZhbHVlICkge1xuXHRcdHZhciBpY29uID0gb3B0aW9uICE9PSBcImljb25Qb3NpdGlvblwiLFxuXHRcdFx0cG9zaXRpb24gPSBpY29uID8gdGhpcy5vcHRpb25zLmljb25Qb3NpdGlvbiA6IHZhbHVlLFxuXHRcdFx0ZGlzcGxheUJsb2NrID0gcG9zaXRpb24gPT09IFwidG9wXCIgfHwgcG9zaXRpb24gPT09IFwiYm90dG9tXCI7XG5cblx0XHQvLyBDcmVhdGUgaWNvblxuXHRcdGlmICggIXRoaXMuaWNvbiApIHtcblx0XHRcdHRoaXMuaWNvbiA9ICQoIFwiPHNwYW4+XCIgKTtcblxuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaWNvbiwgXCJ1aS1idXR0b24taWNvblwiLCBcInVpLWljb25cIiApO1xuXG5cdFx0XHRpZiAoICF0aGlzLm9wdGlvbnMuc2hvd0xhYmVsICkge1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1idXR0b24taWNvbi1vbmx5XCIgKTtcblx0XHRcdH1cblx0XHR9IGVsc2UgaWYgKCBpY29uICkge1xuXG5cdFx0XHQvLyBJZiB3ZSBhcmUgdXBkYXRpbmcgdGhlIGljb24gcmVtb3ZlIHRoZSBvbGQgaWNvbiBjbGFzc1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuaWNvbiwgbnVsbCwgdGhpcy5vcHRpb25zLmljb24gKTtcblx0XHR9XG5cblx0XHQvLyBJZiB3ZSBhcmUgdXBkYXRpbmcgdGhlIGljb24gYWRkIHRoZSBuZXcgaWNvbiBjbGFzc1xuXHRcdGlmICggaWNvbiApIHtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmljb24sIG51bGwsIHZhbHVlICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fYXR0YWNoSWNvbiggcG9zaXRpb24gKTtcblxuXHRcdC8vIElmIHRoZSBpY29uIGlzIG9uIHRvcCBvciBib3R0b20gd2UgbmVlZCB0byBhZGQgdGhlIHVpLXdpZGdldC1pY29uLWJsb2NrIGNsYXNzIGFuZCByZW1vdmVcblx0XHQvLyB0aGUgaWNvblNwYWNlIGlmIHRoZXJlIGlzIG9uZS5cblx0XHRpZiAoIGRpc3BsYXlCbG9jayApIHtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmljb24sIG51bGwsIFwidWktd2lkZ2V0LWljb24tYmxvY2tcIiApO1xuXHRcdFx0aWYgKCB0aGlzLmljb25TcGFjZSApIHtcblx0XHRcdFx0dGhpcy5pY29uU3BhY2UucmVtb3ZlKCk7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gUG9zaXRpb24gaXMgYmVnaW5uaW5nIG9yIGVuZCBzbyByZW1vdmUgdGhlIHVpLXdpZGdldC1pY29uLWJsb2NrIGNsYXNzIGFuZCBhZGQgdGhlXG5cdFx0XHQvLyBzcGFjZSBpZiBpdCBkb2VzIG5vdCBleGlzdFxuXHRcdFx0aWYgKCAhdGhpcy5pY29uU3BhY2UgKSB7XG5cdFx0XHRcdHRoaXMuaWNvblNwYWNlID0gJCggXCI8c3Bhbj4gPC9zcGFuPlwiICk7XG5cdFx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmljb25TcGFjZSwgXCJ1aS1idXR0b24taWNvbi1zcGFjZVwiICk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5pY29uLCBudWxsLCBcInVpLXdpZ2V0LWljb24tYmxvY2tcIiApO1xuXHRcdFx0dGhpcy5fYXR0YWNoSWNvblNwYWNlKCBwb3NpdGlvbiApO1xuXHRcdH1cblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5lbGVtZW50LnJlbW92ZUF0dHIoIFwicm9sZVwiICk7XG5cblx0XHRpZiAoIHRoaXMuaWNvbiApIHtcblx0XHRcdHRoaXMuaWNvbi5yZW1vdmUoKTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLmljb25TcGFjZSApIHtcblx0XHRcdHRoaXMuaWNvblNwYWNlLnJlbW92ZSgpO1xuXHRcdH1cblx0XHRpZiAoICF0aGlzLmhhc1RpdGxlICkge1xuXHRcdFx0dGhpcy5lbGVtZW50LnJlbW92ZUF0dHIoIFwidGl0bGVcIiApO1xuXHRcdH1cblx0fSxcblxuXHRfYXR0YWNoSWNvblNwYWNlOiBmdW5jdGlvbiggaWNvblBvc2l0aW9uICkge1xuXHRcdHRoaXMuaWNvblsgL14oPzplbmR8Ym90dG9tKS8udGVzdCggaWNvblBvc2l0aW9uICkgPyBcImJlZm9yZVwiIDogXCJhZnRlclwiIF0oIHRoaXMuaWNvblNwYWNlICk7XG5cdH0sXG5cblx0X2F0dGFjaEljb246IGZ1bmN0aW9uKCBpY29uUG9zaXRpb24gKSB7XG5cdFx0dGhpcy5lbGVtZW50WyAvXig/OmVuZHxib3R0b20pLy50ZXN0KCBpY29uUG9zaXRpb24gKSA/IFwiYXBwZW5kXCIgOiBcInByZXBlbmRcIiBdKCB0aGlzLmljb24gKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uczogZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdFx0dmFyIG5ld1Nob3dMYWJlbCA9IG9wdGlvbnMuc2hvd0xhYmVsID09PSB1bmRlZmluZWQgP1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMuc2hvd0xhYmVsIDpcblx0XHRcdFx0b3B0aW9ucy5zaG93TGFiZWwsXG5cdFx0XHRuZXdJY29uID0gb3B0aW9ucy5pY29uID09PSB1bmRlZmluZWQgPyB0aGlzLm9wdGlvbnMuaWNvbiA6IG9wdGlvbnMuaWNvbjtcblxuXHRcdGlmICggIW5ld1Nob3dMYWJlbCAmJiAhbmV3SWNvbiApIHtcblx0XHRcdG9wdGlvbnMuc2hvd0xhYmVsID0gdHJ1ZTtcblx0XHR9XG5cdFx0dGhpcy5fc3VwZXIoIG9wdGlvbnMgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRpZiAoIGtleSA9PT0gXCJpY29uXCIgKSB7XG5cdFx0XHRpZiAoIHZhbHVlICkge1xuXHRcdFx0XHR0aGlzLl91cGRhdGVJY29uKCBrZXksIHZhbHVlICk7XG5cdFx0XHR9IGVsc2UgaWYgKCB0aGlzLmljb24gKSB7XG5cdFx0XHRcdHRoaXMuaWNvbi5yZW1vdmUoKTtcblx0XHRcdFx0aWYgKCB0aGlzLmljb25TcGFjZSApIHtcblx0XHRcdFx0XHR0aGlzLmljb25TcGFjZS5yZW1vdmUoKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcImljb25Qb3NpdGlvblwiICkge1xuXHRcdFx0dGhpcy5fdXBkYXRlSWNvbigga2V5LCB2YWx1ZSApO1xuXHRcdH1cblxuXHRcdC8vIE1ha2Ugc3VyZSB3ZSBjYW4ndCBlbmQgdXAgd2l0aCBhIGJ1dHRvbiB0aGF0IGhhcyBuZWl0aGVyIHRleHQgbm9yIGljb25cblx0XHRpZiAoIGtleSA9PT0gXCJzaG93TGFiZWxcIiApIHtcblx0XHRcdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIFwidWktYnV0dG9uLWljb24tb25seVwiLCBudWxsLCAhdmFsdWUgKTtcblx0XHRcdFx0dGhpcy5fdXBkYXRlVG9vbHRpcCgpO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcImxhYmVsXCIgKSB7XG5cdFx0XHRpZiAoIHRoaXMuaXNJbnB1dCApIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LnZhbCggdmFsdWUgKTtcblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gSWYgdGhlcmUgaXMgYW4gaWNvbiwgYXBwZW5kIGl0LCBlbHNlIG5vdGhpbmcgdGhlbiBhcHBlbmQgdGhlIHZhbHVlXG5cdFx0XHRcdC8vIHRoaXMgYXZvaWRzIHJlbW92YWwgb2YgdGhlIGljb24gd2hlbiBzZXR0aW5nIGxhYmVsIHRleHRcblx0XHRcdFx0dGhpcy5lbGVtZW50Lmh0bWwoIHZhbHVlICk7XG5cdFx0XHRcdGlmICggdGhpcy5pY29uICkge1xuXHRcdFx0XHRcdHRoaXMuX2F0dGFjaEljb24oIHRoaXMub3B0aW9ucy5pY29uUG9zaXRpb24gKTtcblx0XHRcdFx0XHR0aGlzLl9hdHRhY2hJY29uU3BhY2UoIHRoaXMub3B0aW9ucy5pY29uUG9zaXRpb24gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJkaXNhYmxlZFwiICkge1xuXHRcdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiwgdmFsdWUgKTtcblx0XHRcdHRoaXMuZWxlbWVudFsgMCBdLmRpc2FibGVkID0gdmFsdWU7XG5cdFx0XHRpZiAoIHZhbHVlICkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQuYmx1cigpO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRyZWZyZXNoOiBmdW5jdGlvbigpIHtcblxuXHRcdC8vIE1ha2Ugc3VyZSB0byBvbmx5IGNoZWNrIGRpc2FibGVkIGlmIGl0cyBhbiBlbGVtZW50IHRoYXQgc3VwcG9ydHMgdGhpcyBvdGhlcndpc2Vcblx0XHQvLyBjaGVjayBmb3IgdGhlIGRpc2FibGVkIGNsYXNzIHRvIGRldGVybWluZSBzdGF0ZVxuXHRcdHZhciBpc0Rpc2FibGVkID0gdGhpcy5lbGVtZW50LmlzKCBcImlucHV0LCBidXR0b25cIiApID9cblx0XHRcdHRoaXMuZWxlbWVudFsgMCBdLmRpc2FibGVkIDogdGhpcy5lbGVtZW50Lmhhc0NsYXNzKCBcInVpLWJ1dHRvbi1kaXNhYmxlZFwiICk7XG5cblx0XHRpZiAoIGlzRGlzYWJsZWQgIT09IHRoaXMub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdHRoaXMuX3NldE9wdGlvbnMoIHsgZGlzYWJsZWQ6IGlzRGlzYWJsZWQgfSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3VwZGF0ZVRvb2x0aXAoKTtcblx0fVxufSApO1xuXG4vLyBERVBSRUNBVEVEXG5pZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSApIHtcblxuXHQvLyBUZXh0IGFuZCBJY29ucyBvcHRpb25zXG5cdCQud2lkZ2V0KCBcInVpLmJ1dHRvblwiLCAkLnVpLmJ1dHRvbiwge1xuXHRcdG9wdGlvbnM6IHtcblx0XHRcdHRleHQ6IHRydWUsXG5cdFx0XHRpY29uczoge1xuXHRcdFx0XHRwcmltYXJ5OiBudWxsLFxuXHRcdFx0XHRzZWNvbmRhcnk6IG51bGxcblx0XHRcdH1cblx0XHR9LFxuXG5cdFx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5zaG93TGFiZWwgJiYgIXRoaXMub3B0aW9ucy50ZXh0ICkge1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMuc2hvd0xhYmVsID0gdGhpcy5vcHRpb25zLnRleHQ7XG5cdFx0XHR9XG5cdFx0XHRpZiAoICF0aGlzLm9wdGlvbnMuc2hvd0xhYmVsICYmIHRoaXMub3B0aW9ucy50ZXh0ICkge1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMudGV4dCA9IHRoaXMub3B0aW9ucy5zaG93TGFiZWw7XG5cdFx0XHR9XG5cdFx0XHRpZiAoICF0aGlzLm9wdGlvbnMuaWNvbiAmJiAoIHRoaXMub3B0aW9ucy5pY29ucy5wcmltYXJ5IHx8XG5cdFx0XHRcdFx0dGhpcy5vcHRpb25zLmljb25zLnNlY29uZGFyeSApICkge1xuXHRcdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5pY29ucy5wcmltYXJ5ICkge1xuXHRcdFx0XHRcdHRoaXMub3B0aW9ucy5pY29uID0gdGhpcy5vcHRpb25zLmljb25zLnByaW1hcnk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5vcHRpb25zLmljb24gPSB0aGlzLm9wdGlvbnMuaWNvbnMuc2Vjb25kYXJ5O1xuXHRcdFx0XHRcdHRoaXMub3B0aW9ucy5pY29uUG9zaXRpb24gPSBcImVuZFwiO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2UgaWYgKCB0aGlzLm9wdGlvbnMuaWNvbiApIHtcblx0XHRcdFx0dGhpcy5vcHRpb25zLmljb25zLnByaW1hcnkgPSB0aGlzLm9wdGlvbnMuaWNvbjtcblx0XHRcdH1cblx0XHRcdHRoaXMuX3N1cGVyKCk7XG5cdFx0fSxcblxuXHRcdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdFx0aWYgKCBrZXkgPT09IFwidGV4dFwiICkge1xuXHRcdFx0XHR0aGlzLl9zdXBlciggXCJzaG93TGFiZWxcIiwgdmFsdWUgKTtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBrZXkgPT09IFwic2hvd0xhYmVsXCIgKSB7XG5cdFx0XHRcdHRoaXMub3B0aW9ucy50ZXh0ID0gdmFsdWU7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIGtleSA9PT0gXCJpY29uXCIgKSB7XG5cdFx0XHRcdHRoaXMub3B0aW9ucy5pY29ucy5wcmltYXJ5ID0gdmFsdWU7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIGtleSA9PT0gXCJpY29uc1wiICkge1xuXHRcdFx0XHRpZiAoIHZhbHVlLnByaW1hcnkgKSB7XG5cdFx0XHRcdFx0dGhpcy5fc3VwZXIoIFwiaWNvblwiLCB2YWx1ZS5wcmltYXJ5ICk7XG5cdFx0XHRcdFx0dGhpcy5fc3VwZXIoIFwiaWNvblBvc2l0aW9uXCIsIFwiYmVnaW5uaW5nXCIgKTtcblx0XHRcdFx0fSBlbHNlIGlmICggdmFsdWUuc2Vjb25kYXJ5ICkge1xuXHRcdFx0XHRcdHRoaXMuX3N1cGVyKCBcImljb25cIiwgdmFsdWUuc2Vjb25kYXJ5ICk7XG5cdFx0XHRcdFx0dGhpcy5fc3VwZXIoIFwiaWNvblBvc2l0aW9uXCIsIFwiZW5kXCIgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0dGhpcy5fc3VwZXJBcHBseSggYXJndW1lbnRzICk7XG5cdFx0fVxuXHR9ICk7XG5cblx0JC5mbi5idXR0b24gPSAoIGZ1bmN0aW9uKCBvcmlnICkge1xuXHRcdHJldHVybiBmdW5jdGlvbigpIHtcblx0XHRcdGlmICggIXRoaXMubGVuZ3RoIHx8ICggdGhpcy5sZW5ndGggJiYgdGhpc1sgMCBdLnRhZ05hbWUgIT09IFwiSU5QVVRcIiApIHx8XG5cdFx0XHRcdFx0KCB0aGlzLmxlbmd0aCAmJiB0aGlzWyAwIF0udGFnTmFtZSA9PT0gXCJJTlBVVFwiICYmIChcblx0XHRcdFx0XHRcdHRoaXMuYXR0ciggXCJ0eXBlXCIgKSAhPT0gXCJjaGVja2JveFwiICYmIHRoaXMuYXR0ciggXCJ0eXBlXCIgKSAhPT0gXCJyYWRpb1wiXG5cdFx0XHRcdFx0KSApICkge1xuXHRcdFx0XHRyZXR1cm4gb3JpZy5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoICEkLnVpLmNoZWNrYm94cmFkaW8gKSB7XG5cdFx0XHRcdCQuZXJyb3IoIFwiQ2hlY2tib3hyYWRpbyB3aWRnZXQgbWlzc2luZ1wiICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggPT09IDAgKSB7XG5cdFx0XHRcdHJldHVybiB0aGlzLmNoZWNrYm94cmFkaW8oIHtcblx0XHRcdFx0XHRcImljb25cIjogZmFsc2Vcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdFx0cmV0dXJuIHRoaXMuY2hlY2tib3hyYWRpby5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0fTtcblx0fSApKCAkLmZuLmJ1dHRvbiApO1xuXG5cdCQuZm4uYnV0dG9uc2V0ID0gZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAhJC51aS5jb250cm9sZ3JvdXAgKSB7XG5cdFx0XHQkLmVycm9yKCBcIkNvbnRyb2xncm91cCB3aWRnZXQgbWlzc2luZ1wiICk7XG5cdFx0fVxuXHRcdGlmICggYXJndW1lbnRzWyAwIF0gPT09IFwib3B0aW9uXCIgJiYgYXJndW1lbnRzWyAxIF0gPT09IFwiaXRlbXNcIiAmJiBhcmd1bWVudHNbIDIgXSApIHtcblx0XHRcdHJldHVybiB0aGlzLmNvbnRyb2xncm91cC5hcHBseSggdGhpcyxcblx0XHRcdFx0WyBhcmd1bWVudHNbIDAgXSwgXCJpdGVtcy5idXR0b25cIiwgYXJndW1lbnRzWyAyIF0gXSApO1xuXHRcdH1cblx0XHRpZiAoIGFyZ3VtZW50c1sgMCBdID09PSBcIm9wdGlvblwiICYmIGFyZ3VtZW50c1sgMSBdID09PSBcIml0ZW1zXCIgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5jb250cm9sZ3JvdXAuYXBwbHkoIHRoaXMsIFsgYXJndW1lbnRzWyAwIF0sIFwiaXRlbXMuYnV0dG9uXCIgXSApO1xuXHRcdH1cblx0XHRpZiAoIHR5cGVvZiBhcmd1bWVudHNbIDAgXSA9PT0gXCJvYmplY3RcIiAmJiBhcmd1bWVudHNbIDAgXS5pdGVtcyApIHtcblx0XHRcdGFyZ3VtZW50c1sgMCBdLml0ZW1zID0ge1xuXHRcdFx0XHRidXR0b246IGFyZ3VtZW50c1sgMCBdLml0ZW1zXG5cdFx0XHR9O1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5jb250cm9sZ3JvdXAuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApO1xuXHR9O1xufVxuXG52YXIgd2lkZ2V0c0J1dHRvbiA9ICQudWkuYnV0dG9uO1xuXG5cbi8vIGpzY3M6ZGlzYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLyoganNjczpkaXNhYmxlIHJlcXVpcmVDYW1lbENhc2VPclVwcGVyQ2FzZUlkZW50aWZpZXJzICovXG4vKiFcbiAqIGpRdWVyeSBVSSBEYXRlcGlja2VyIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBEYXRlcGlja2VyXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogRGlzcGxheXMgYSBjYWxlbmRhciBmcm9tIGFuIGlucHV0IG9yIGlubGluZSBmb3Igc2VsZWN0aW5nIGRhdGVzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2RhdGVwaWNrZXIvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZGF0ZXBpY2tlci9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2RhdGVwaWNrZXIuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbiQuZXh0ZW5kKCAkLnVpLCB7IGRhdGVwaWNrZXI6IHsgdmVyc2lvbjogXCIxLjEyLjFcIiB9IH0gKTtcblxudmFyIGRhdGVwaWNrZXJfaW5zdEFjdGl2ZTtcblxuZnVuY3Rpb24gZGF0ZXBpY2tlcl9nZXRaaW5kZXgoIGVsZW0gKSB7XG5cdHZhciBwb3NpdGlvbiwgdmFsdWU7XG5cdHdoaWxlICggZWxlbS5sZW5ndGggJiYgZWxlbVsgMCBdICE9PSBkb2N1bWVudCApIHtcblxuXHRcdC8vIElnbm9yZSB6LWluZGV4IGlmIHBvc2l0aW9uIGlzIHNldCB0byBhIHZhbHVlIHdoZXJlIHotaW5kZXggaXMgaWdub3JlZCBieSB0aGUgYnJvd3NlclxuXHRcdC8vIFRoaXMgbWFrZXMgYmVoYXZpb3Igb2YgdGhpcyBmdW5jdGlvbiBjb25zaXN0ZW50IGFjcm9zcyBicm93c2Vyc1xuXHRcdC8vIFdlYktpdCBhbHdheXMgcmV0dXJucyBhdXRvIGlmIHRoZSBlbGVtZW50IGlzIHBvc2l0aW9uZWRcblx0XHRwb3NpdGlvbiA9IGVsZW0uY3NzKCBcInBvc2l0aW9uXCIgKTtcblx0XHRpZiAoIHBvc2l0aW9uID09PSBcImFic29sdXRlXCIgfHwgcG9zaXRpb24gPT09IFwicmVsYXRpdmVcIiB8fCBwb3NpdGlvbiA9PT0gXCJmaXhlZFwiICkge1xuXG5cdFx0XHQvLyBJRSByZXR1cm5zIDAgd2hlbiB6SW5kZXggaXMgbm90IHNwZWNpZmllZFxuXHRcdFx0Ly8gb3RoZXIgYnJvd3NlcnMgcmV0dXJuIGEgc3RyaW5nXG5cdFx0XHQvLyB3ZSBpZ25vcmUgdGhlIGNhc2Ugb2YgbmVzdGVkIGVsZW1lbnRzIHdpdGggYW4gZXhwbGljaXQgdmFsdWUgb2YgMFxuXHRcdFx0Ly8gPGRpdiBzdHlsZT1cInotaW5kZXg6IC0xMDtcIj48ZGl2IHN0eWxlPVwiei1pbmRleDogMDtcIj48L2Rpdj48L2Rpdj5cblx0XHRcdHZhbHVlID0gcGFyc2VJbnQoIGVsZW0uY3NzKCBcInpJbmRleFwiICksIDEwICk7XG5cdFx0XHRpZiAoICFpc05hTiggdmFsdWUgKSAmJiB2YWx1ZSAhPT0gMCApIHtcblx0XHRcdFx0cmV0dXJuIHZhbHVlO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRlbGVtID0gZWxlbS5wYXJlbnQoKTtcblx0fVxuXG5cdHJldHVybiAwO1xufVxuLyogRGF0ZSBwaWNrZXIgbWFuYWdlci5cbiAgIFVzZSB0aGUgc2luZ2xldG9uIGluc3RhbmNlIG9mIHRoaXMgY2xhc3MsICQuZGF0ZXBpY2tlciwgdG8gaW50ZXJhY3Qgd2l0aCB0aGUgZGF0ZSBwaWNrZXIuXG4gICBTZXR0aW5ncyBmb3IgKGdyb3VwcyBvZikgZGF0ZSBwaWNrZXJzIGFyZSBtYWludGFpbmVkIGluIGFuIGluc3RhbmNlIG9iamVjdCxcbiAgIGFsbG93aW5nIG11bHRpcGxlIGRpZmZlcmVudCBzZXR0aW5ncyBvbiB0aGUgc2FtZSBwYWdlLiAqL1xuXG5mdW5jdGlvbiBEYXRlcGlja2VyKCkge1xuXHR0aGlzLl9jdXJJbnN0ID0gbnVsbDsgLy8gVGhlIGN1cnJlbnQgaW5zdGFuY2UgaW4gdXNlXG5cdHRoaXMuX2tleUV2ZW50ID0gZmFsc2U7IC8vIElmIHRoZSBsYXN0IGV2ZW50IHdhcyBhIGtleSBldmVudFxuXHR0aGlzLl9kaXNhYmxlZElucHV0cyA9IFtdOyAvLyBMaXN0IG9mIGRhdGUgcGlja2VyIGlucHV0cyB0aGF0IGhhdmUgYmVlbiBkaXNhYmxlZFxuXHR0aGlzLl9kYXRlcGlja2VyU2hvd2luZyA9IGZhbHNlOyAvLyBUcnVlIGlmIHRoZSBwb3B1cCBwaWNrZXIgaXMgc2hvd2luZyAsIGZhbHNlIGlmIG5vdFxuXHR0aGlzLl9pbkRpYWxvZyA9IGZhbHNlOyAvLyBUcnVlIGlmIHNob3dpbmcgd2l0aGluIGEgXCJkaWFsb2dcIiwgZmFsc2UgaWYgbm90XG5cdHRoaXMuX21haW5EaXZJZCA9IFwidWktZGF0ZXBpY2tlci1kaXZcIjsgLy8gVGhlIElEIG9mIHRoZSBtYWluIGRhdGVwaWNrZXIgZGl2aXNpb25cblx0dGhpcy5faW5saW5lQ2xhc3MgPSBcInVpLWRhdGVwaWNrZXItaW5saW5lXCI7IC8vIFRoZSBuYW1lIG9mIHRoZSBpbmxpbmUgbWFya2VyIGNsYXNzXG5cdHRoaXMuX2FwcGVuZENsYXNzID0gXCJ1aS1kYXRlcGlja2VyLWFwcGVuZFwiOyAvLyBUaGUgbmFtZSBvZiB0aGUgYXBwZW5kIG1hcmtlciBjbGFzc1xuXHR0aGlzLl90cmlnZ2VyQ2xhc3MgPSBcInVpLWRhdGVwaWNrZXItdHJpZ2dlclwiOyAvLyBUaGUgbmFtZSBvZiB0aGUgdHJpZ2dlciBtYXJrZXIgY2xhc3Ncblx0dGhpcy5fZGlhbG9nQ2xhc3MgPSBcInVpLWRhdGVwaWNrZXItZGlhbG9nXCI7IC8vIFRoZSBuYW1lIG9mIHRoZSBkaWFsb2cgbWFya2VyIGNsYXNzXG5cdHRoaXMuX2Rpc2FibGVDbGFzcyA9IFwidWktZGF0ZXBpY2tlci1kaXNhYmxlZFwiOyAvLyBUaGUgbmFtZSBvZiB0aGUgZGlzYWJsZWQgY292ZXJpbmcgbWFya2VyIGNsYXNzXG5cdHRoaXMuX3Vuc2VsZWN0YWJsZUNsYXNzID0gXCJ1aS1kYXRlcGlja2VyLXVuc2VsZWN0YWJsZVwiOyAvLyBUaGUgbmFtZSBvZiB0aGUgdW5zZWxlY3RhYmxlIGNlbGwgbWFya2VyIGNsYXNzXG5cdHRoaXMuX2N1cnJlbnRDbGFzcyA9IFwidWktZGF0ZXBpY2tlci1jdXJyZW50LWRheVwiOyAvLyBUaGUgbmFtZSBvZiB0aGUgY3VycmVudCBkYXkgbWFya2VyIGNsYXNzXG5cdHRoaXMuX2RheU92ZXJDbGFzcyA9IFwidWktZGF0ZXBpY2tlci1kYXlzLWNlbGwtb3ZlclwiOyAvLyBUaGUgbmFtZSBvZiB0aGUgZGF5IGhvdmVyIG1hcmtlciBjbGFzc1xuXHR0aGlzLnJlZ2lvbmFsID0gW107IC8vIEF2YWlsYWJsZSByZWdpb25hbCBzZXR0aW5ncywgaW5kZXhlZCBieSBsYW5ndWFnZSBjb2RlXG5cdHRoaXMucmVnaW9uYWxbIFwiXCIgXSA9IHsgLy8gRGVmYXVsdCByZWdpb25hbCBzZXR0aW5nc1xuXHRcdGNsb3NlVGV4dDogXCJEb25lXCIsIC8vIERpc3BsYXkgdGV4dCBmb3IgY2xvc2UgbGlua1xuXHRcdHByZXZUZXh0OiBcIlByZXZcIiwgLy8gRGlzcGxheSB0ZXh0IGZvciBwcmV2aW91cyBtb250aCBsaW5rXG5cdFx0bmV4dFRleHQ6IFwiTmV4dFwiLCAvLyBEaXNwbGF5IHRleHQgZm9yIG5leHQgbW9udGggbGlua1xuXHRcdGN1cnJlbnRUZXh0OiBcIlRvZGF5XCIsIC8vIERpc3BsYXkgdGV4dCBmb3IgY3VycmVudCBtb250aCBsaW5rXG5cdFx0bW9udGhOYW1lczogWyBcIkphbnVhcnlcIixcIkZlYnJ1YXJ5XCIsXCJNYXJjaFwiLFwiQXByaWxcIixcIk1heVwiLFwiSnVuZVwiLFxuXHRcdFx0XCJKdWx5XCIsXCJBdWd1c3RcIixcIlNlcHRlbWJlclwiLFwiT2N0b2JlclwiLFwiTm92ZW1iZXJcIixcIkRlY2VtYmVyXCIgXSwgLy8gTmFtZXMgb2YgbW9udGhzIGZvciBkcm9wLWRvd24gYW5kIGZvcm1hdHRpbmdcblx0XHRtb250aE5hbWVzU2hvcnQ6IFsgXCJKYW5cIiwgXCJGZWJcIiwgXCJNYXJcIiwgXCJBcHJcIiwgXCJNYXlcIiwgXCJKdW5cIiwgXCJKdWxcIiwgXCJBdWdcIiwgXCJTZXBcIiwgXCJPY3RcIiwgXCJOb3ZcIiwgXCJEZWNcIiBdLCAvLyBGb3IgZm9ybWF0dGluZ1xuXHRcdGRheU5hbWVzOiBbIFwiU3VuZGF5XCIsIFwiTW9uZGF5XCIsIFwiVHVlc2RheVwiLCBcIldlZG5lc2RheVwiLCBcIlRodXJzZGF5XCIsIFwiRnJpZGF5XCIsIFwiU2F0dXJkYXlcIiBdLCAvLyBGb3IgZm9ybWF0dGluZ1xuXHRcdGRheU5hbWVzU2hvcnQ6IFsgXCJTdW5cIiwgXCJNb25cIiwgXCJUdWVcIiwgXCJXZWRcIiwgXCJUaHVcIiwgXCJGcmlcIiwgXCJTYXRcIiBdLCAvLyBGb3IgZm9ybWF0dGluZ1xuXHRcdGRheU5hbWVzTWluOiBbIFwiU3VcIixcIk1vXCIsXCJUdVwiLFwiV2VcIixcIlRoXCIsXCJGclwiLFwiU2FcIiBdLCAvLyBDb2x1bW4gaGVhZGluZ3MgZm9yIGRheXMgc3RhcnRpbmcgYXQgU3VuZGF5XG5cdFx0d2Vla0hlYWRlcjogXCJXa1wiLCAvLyBDb2x1bW4gaGVhZGVyIGZvciB3ZWVrIG9mIHRoZSB5ZWFyXG5cdFx0ZGF0ZUZvcm1hdDogXCJtbS9kZC95eVwiLCAvLyBTZWUgZm9ybWF0IG9wdGlvbnMgb24gcGFyc2VEYXRlXG5cdFx0Zmlyc3REYXk6IDAsIC8vIFRoZSBmaXJzdCBkYXkgb2YgdGhlIHdlZWssIFN1biA9IDAsIE1vbiA9IDEsIC4uLlxuXHRcdGlzUlRMOiBmYWxzZSwgLy8gVHJ1ZSBpZiByaWdodC10by1sZWZ0IGxhbmd1YWdlLCBmYWxzZSBpZiBsZWZ0LXRvLXJpZ2h0XG5cdFx0c2hvd01vbnRoQWZ0ZXJZZWFyOiBmYWxzZSwgLy8gVHJ1ZSBpZiB0aGUgeWVhciBzZWxlY3QgcHJlY2VkZXMgbW9udGgsIGZhbHNlIGZvciBtb250aCB0aGVuIHllYXJcblx0XHR5ZWFyU3VmZml4OiBcIlwiIC8vIEFkZGl0aW9uYWwgdGV4dCB0byBhcHBlbmQgdG8gdGhlIHllYXIgaW4gdGhlIG1vbnRoIGhlYWRlcnNcblx0fTtcblx0dGhpcy5fZGVmYXVsdHMgPSB7IC8vIEdsb2JhbCBkZWZhdWx0cyBmb3IgYWxsIHRoZSBkYXRlIHBpY2tlciBpbnN0YW5jZXNcblx0XHRzaG93T246IFwiZm9jdXNcIiwgLy8gXCJmb2N1c1wiIGZvciBwb3B1cCBvbiBmb2N1cyxcblx0XHRcdC8vIFwiYnV0dG9uXCIgZm9yIHRyaWdnZXIgYnV0dG9uLCBvciBcImJvdGhcIiBmb3IgZWl0aGVyXG5cdFx0c2hvd0FuaW06IFwiZmFkZUluXCIsIC8vIE5hbWUgb2YgalF1ZXJ5IGFuaW1hdGlvbiBmb3IgcG9wdXBcblx0XHRzaG93T3B0aW9uczoge30sIC8vIE9wdGlvbnMgZm9yIGVuaGFuY2VkIGFuaW1hdGlvbnNcblx0XHRkZWZhdWx0RGF0ZTogbnVsbCwgLy8gVXNlZCB3aGVuIGZpZWxkIGlzIGJsYW5rOiBhY3R1YWwgZGF0ZSxcblx0XHRcdC8vICsvLW51bWJlciBmb3Igb2Zmc2V0IGZyb20gdG9kYXksIG51bGwgZm9yIHRvZGF5XG5cdFx0YXBwZW5kVGV4dDogXCJcIiwgLy8gRGlzcGxheSB0ZXh0IGZvbGxvd2luZyB0aGUgaW5wdXQgYm94LCBlLmcuIHNob3dpbmcgdGhlIGZvcm1hdFxuXHRcdGJ1dHRvblRleHQ6IFwiLi4uXCIsIC8vIFRleHQgZm9yIHRyaWdnZXIgYnV0dG9uXG5cdFx0YnV0dG9uSW1hZ2U6IFwiXCIsIC8vIFVSTCBmb3IgdHJpZ2dlciBidXR0b24gaW1hZ2Vcblx0XHRidXR0b25JbWFnZU9ubHk6IGZhbHNlLCAvLyBUcnVlIGlmIHRoZSBpbWFnZSBhcHBlYXJzIGFsb25lLCBmYWxzZSBpZiBpdCBhcHBlYXJzIG9uIGEgYnV0dG9uXG5cdFx0aGlkZUlmTm9QcmV2TmV4dDogZmFsc2UsIC8vIFRydWUgdG8gaGlkZSBuZXh0L3ByZXZpb3VzIG1vbnRoIGxpbmtzXG5cdFx0XHQvLyBpZiBub3QgYXBwbGljYWJsZSwgZmFsc2UgdG8ganVzdCBkaXNhYmxlIHRoZW1cblx0XHRuYXZpZ2F0aW9uQXNEYXRlRm9ybWF0OiBmYWxzZSwgLy8gVHJ1ZSBpZiBkYXRlIGZvcm1hdHRpbmcgYXBwbGllZCB0byBwcmV2L3RvZGF5L25leHQgbGlua3Ncblx0XHRnb3RvQ3VycmVudDogZmFsc2UsIC8vIFRydWUgaWYgdG9kYXkgbGluayBnb2VzIGJhY2sgdG8gY3VycmVudCBzZWxlY3Rpb24gaW5zdGVhZFxuXHRcdGNoYW5nZU1vbnRoOiBmYWxzZSwgLy8gVHJ1ZSBpZiBtb250aCBjYW4gYmUgc2VsZWN0ZWQgZGlyZWN0bHksIGZhbHNlIGlmIG9ubHkgcHJldi9uZXh0XG5cdFx0Y2hhbmdlWWVhcjogZmFsc2UsIC8vIFRydWUgaWYgeWVhciBjYW4gYmUgc2VsZWN0ZWQgZGlyZWN0bHksIGZhbHNlIGlmIG9ubHkgcHJldi9uZXh0XG5cdFx0eWVhclJhbmdlOiBcImMtMTA6YysxMFwiLCAvLyBSYW5nZSBvZiB5ZWFycyB0byBkaXNwbGF5IGluIGRyb3AtZG93bixcblx0XHRcdC8vIGVpdGhlciByZWxhdGl2ZSB0byB0b2RheSdzIHllYXIgKC1ubjorbm4pLCByZWxhdGl2ZSB0byBjdXJyZW50bHkgZGlzcGxheWVkIHllYXJcblx0XHRcdC8vIChjLW5uOmMrbm4pLCBhYnNvbHV0ZSAobm5ubjpubm5uKSwgb3IgYSBjb21iaW5hdGlvbiBvZiB0aGUgYWJvdmUgKG5ubm46LW4pXG5cdFx0c2hvd090aGVyTW9udGhzOiBmYWxzZSwgLy8gVHJ1ZSB0byBzaG93IGRhdGVzIGluIG90aGVyIG1vbnRocywgZmFsc2UgdG8gbGVhdmUgYmxhbmtcblx0XHRzZWxlY3RPdGhlck1vbnRoczogZmFsc2UsIC8vIFRydWUgdG8gYWxsb3cgc2VsZWN0aW9uIG9mIGRhdGVzIGluIG90aGVyIG1vbnRocywgZmFsc2UgZm9yIHVuc2VsZWN0YWJsZVxuXHRcdHNob3dXZWVrOiBmYWxzZSwgLy8gVHJ1ZSB0byBzaG93IHdlZWsgb2YgdGhlIHllYXIsIGZhbHNlIHRvIG5vdCBzaG93IGl0XG5cdFx0Y2FsY3VsYXRlV2VlazogdGhpcy5pc284NjAxV2VlaywgLy8gSG93IHRvIGNhbGN1bGF0ZSB0aGUgd2VlayBvZiB0aGUgeWVhcixcblx0XHRcdC8vIHRha2VzIGEgRGF0ZSBhbmQgcmV0dXJucyB0aGUgbnVtYmVyIG9mIHRoZSB3ZWVrIGZvciBpdFxuXHRcdHNob3J0WWVhckN1dG9mZjogXCIrMTBcIiwgLy8gU2hvcnQgeWVhciB2YWx1ZXMgPCB0aGlzIGFyZSBpbiB0aGUgY3VycmVudCBjZW50dXJ5LFxuXHRcdFx0Ly8gPiB0aGlzIGFyZSBpbiB0aGUgcHJldmlvdXMgY2VudHVyeSxcblx0XHRcdC8vIHN0cmluZyB2YWx1ZSBzdGFydGluZyB3aXRoIFwiK1wiIGZvciBjdXJyZW50IHllYXIgKyB2YWx1ZVxuXHRcdG1pbkRhdGU6IG51bGwsIC8vIFRoZSBlYXJsaWVzdCBzZWxlY3RhYmxlIGRhdGUsIG9yIG51bGwgZm9yIG5vIGxpbWl0XG5cdFx0bWF4RGF0ZTogbnVsbCwgLy8gVGhlIGxhdGVzdCBzZWxlY3RhYmxlIGRhdGUsIG9yIG51bGwgZm9yIG5vIGxpbWl0XG5cdFx0ZHVyYXRpb246IFwiZmFzdFwiLCAvLyBEdXJhdGlvbiBvZiBkaXNwbGF5L2Nsb3N1cmVcblx0XHRiZWZvcmVTaG93RGF5OiBudWxsLCAvLyBGdW5jdGlvbiB0aGF0IHRha2VzIGEgZGF0ZSBhbmQgcmV0dXJucyBhbiBhcnJheSB3aXRoXG5cdFx0XHQvLyBbMF0gPSB0cnVlIGlmIHNlbGVjdGFibGUsIGZhbHNlIGlmIG5vdCwgWzFdID0gY3VzdG9tIENTUyBjbGFzcyBuYW1lKHMpIG9yIFwiXCIsXG5cdFx0XHQvLyBbMl0gPSBjZWxsIHRpdGxlIChvcHRpb25hbCksIGUuZy4gJC5kYXRlcGlja2VyLm5vV2Vla2VuZHNcblx0XHRiZWZvcmVTaG93OiBudWxsLCAvLyBGdW5jdGlvbiB0aGF0IHRha2VzIGFuIGlucHV0IGZpZWxkIGFuZFxuXHRcdFx0Ly8gcmV0dXJucyBhIHNldCBvZiBjdXN0b20gc2V0dGluZ3MgZm9yIHRoZSBkYXRlIHBpY2tlclxuXHRcdG9uU2VsZWN0OiBudWxsLCAvLyBEZWZpbmUgYSBjYWxsYmFjayBmdW5jdGlvbiB3aGVuIGEgZGF0ZSBpcyBzZWxlY3RlZFxuXHRcdG9uQ2hhbmdlTW9udGhZZWFyOiBudWxsLCAvLyBEZWZpbmUgYSBjYWxsYmFjayBmdW5jdGlvbiB3aGVuIHRoZSBtb250aCBvciB5ZWFyIGlzIGNoYW5nZWRcblx0XHRvbkNsb3NlOiBudWxsLCAvLyBEZWZpbmUgYSBjYWxsYmFjayBmdW5jdGlvbiB3aGVuIHRoZSBkYXRlcGlja2VyIGlzIGNsb3NlZFxuXHRcdG51bWJlck9mTW9udGhzOiAxLCAvLyBOdW1iZXIgb2YgbW9udGhzIHRvIHNob3cgYXQgYSB0aW1lXG5cdFx0c2hvd0N1cnJlbnRBdFBvczogMCwgLy8gVGhlIHBvc2l0aW9uIGluIG11bHRpcGUgbW9udGhzIGF0IHdoaWNoIHRvIHNob3cgdGhlIGN1cnJlbnQgbW9udGggKHN0YXJ0aW5nIGF0IDApXG5cdFx0c3RlcE1vbnRoczogMSwgLy8gTnVtYmVyIG9mIG1vbnRocyB0byBzdGVwIGJhY2svZm9yd2FyZFxuXHRcdHN0ZXBCaWdNb250aHM6IDEyLCAvLyBOdW1iZXIgb2YgbW9udGhzIHRvIHN0ZXAgYmFjay9mb3J3YXJkIGZvciB0aGUgYmlnIGxpbmtzXG5cdFx0YWx0RmllbGQ6IFwiXCIsIC8vIFNlbGVjdG9yIGZvciBhbiBhbHRlcm5hdGUgZmllbGQgdG8gc3RvcmUgc2VsZWN0ZWQgZGF0ZXMgaW50b1xuXHRcdGFsdEZvcm1hdDogXCJcIiwgLy8gVGhlIGRhdGUgZm9ybWF0IHRvIHVzZSBmb3IgdGhlIGFsdGVybmF0ZSBmaWVsZFxuXHRcdGNvbnN0cmFpbklucHV0OiB0cnVlLCAvLyBUaGUgaW5wdXQgaXMgY29uc3RyYWluZWQgYnkgdGhlIGN1cnJlbnQgZGF0ZSBmb3JtYXRcblx0XHRzaG93QnV0dG9uUGFuZWw6IGZhbHNlLCAvLyBUcnVlIHRvIHNob3cgYnV0dG9uIHBhbmVsLCBmYWxzZSB0byBub3Qgc2hvdyBpdFxuXHRcdGF1dG9TaXplOiBmYWxzZSwgLy8gVHJ1ZSB0byBzaXplIHRoZSBpbnB1dCBmb3IgdGhlIGRhdGUgZm9ybWF0LCBmYWxzZSB0byBsZWF2ZSBhcyBpc1xuXHRcdGRpc2FibGVkOiBmYWxzZSAvLyBUaGUgaW5pdGlhbCBkaXNhYmxlZCBzdGF0ZVxuXHR9O1xuXHQkLmV4dGVuZCggdGhpcy5fZGVmYXVsdHMsIHRoaXMucmVnaW9uYWxbIFwiXCIgXSApO1xuXHR0aGlzLnJlZ2lvbmFsLmVuID0gJC5leHRlbmQoIHRydWUsIHt9LCB0aGlzLnJlZ2lvbmFsWyBcIlwiIF0gKTtcblx0dGhpcy5yZWdpb25hbFsgXCJlbi1VU1wiIF0gPSAkLmV4dGVuZCggdHJ1ZSwge30sIHRoaXMucmVnaW9uYWwuZW4gKTtcblx0dGhpcy5kcERpdiA9IGRhdGVwaWNrZXJfYmluZEhvdmVyKCAkKCBcIjxkaXYgaWQ9J1wiICsgdGhpcy5fbWFpbkRpdklkICsgXCInIGNsYXNzPSd1aS1kYXRlcGlja2VyIHVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudCB1aS1oZWxwZXItY2xlYXJmaXggdWktY29ybmVyLWFsbCc+PC9kaXY+XCIgKSApO1xufVxuXG4kLmV4dGVuZCggRGF0ZXBpY2tlci5wcm90b3R5cGUsIHtcblx0LyogQ2xhc3MgbmFtZSBhZGRlZCB0byBlbGVtZW50cyB0byBpbmRpY2F0ZSBhbHJlYWR5IGNvbmZpZ3VyZWQgd2l0aCBhIGRhdGUgcGlja2VyLiAqL1xuXHRtYXJrZXJDbGFzc05hbWU6IFwiaGFzRGF0ZXBpY2tlclwiLFxuXG5cdC8vS2VlcCB0cmFjayBvZiB0aGUgbWF4aW11bSBudW1iZXIgb2Ygcm93cyBkaXNwbGF5ZWQgKHNlZSAjNzA0Mylcblx0bWF4Um93czogNCxcblxuXHQvLyBUT0RPIHJlbmFtZSB0byBcIndpZGdldFwiIHdoZW4gc3dpdGNoaW5nIHRvIHdpZGdldCBmYWN0b3J5XG5cdF93aWRnZXREYXRlcGlja2VyOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5kcERpdjtcblx0fSxcblxuXHQvKiBPdmVycmlkZSB0aGUgZGVmYXVsdCBzZXR0aW5ncyBmb3IgYWxsIGluc3RhbmNlcyBvZiB0aGUgZGF0ZSBwaWNrZXIuXG5cdCAqIEBwYXJhbSAgc2V0dGluZ3MgIG9iamVjdCAtIHRoZSBuZXcgc2V0dGluZ3MgdG8gdXNlIGFzIGRlZmF1bHRzIChhbm9ueW1vdXMgb2JqZWN0KVxuXHQgKiBAcmV0dXJuIHRoZSBtYW5hZ2VyIG9iamVjdFxuXHQgKi9cblx0c2V0RGVmYXVsdHM6IGZ1bmN0aW9uKCBzZXR0aW5ncyApIHtcblx0XHRkYXRlcGlja2VyX2V4dGVuZFJlbW92ZSggdGhpcy5fZGVmYXVsdHMsIHNldHRpbmdzIHx8IHt9ICk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0LyogQXR0YWNoIHRoZSBkYXRlIHBpY2tlciB0byBhIGpRdWVyeSBzZWxlY3Rpb24uXG5cdCAqIEBwYXJhbSAgdGFyZ2V0XHRlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqIEBwYXJhbSAgc2V0dGluZ3MgIG9iamVjdCAtIHRoZSBuZXcgc2V0dGluZ3MgdG8gdXNlIGZvciB0aGlzIGRhdGUgcGlja2VyIGluc3RhbmNlIChhbm9ueW1vdXMpXG5cdCAqL1xuXHRfYXR0YWNoRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCwgc2V0dGluZ3MgKSB7XG5cdFx0dmFyIG5vZGVOYW1lLCBpbmxpbmUsIGluc3Q7XG5cdFx0bm9kZU5hbWUgPSB0YXJnZXQubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHRpbmxpbmUgPSAoIG5vZGVOYW1lID09PSBcImRpdlwiIHx8IG5vZGVOYW1lID09PSBcInNwYW5cIiApO1xuXHRcdGlmICggIXRhcmdldC5pZCApIHtcblx0XHRcdHRoaXMudXVpZCArPSAxO1xuXHRcdFx0dGFyZ2V0LmlkID0gXCJkcFwiICsgdGhpcy51dWlkO1xuXHRcdH1cblx0XHRpbnN0ID0gdGhpcy5fbmV3SW5zdCggJCggdGFyZ2V0ICksIGlubGluZSApO1xuXHRcdGluc3Quc2V0dGluZ3MgPSAkLmV4dGVuZCgge30sIHNldHRpbmdzIHx8IHt9ICk7XG5cdFx0aWYgKCBub2RlTmFtZSA9PT0gXCJpbnB1dFwiICkge1xuXHRcdFx0dGhpcy5fY29ubmVjdERhdGVwaWNrZXIoIHRhcmdldCwgaW5zdCApO1xuXHRcdH0gZWxzZSBpZiAoIGlubGluZSApIHtcblx0XHRcdHRoaXMuX2lubGluZURhdGVwaWNrZXIoIHRhcmdldCwgaW5zdCApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBDcmVhdGUgYSBuZXcgaW5zdGFuY2Ugb2JqZWN0LiAqL1xuXHRfbmV3SW5zdDogZnVuY3Rpb24oIHRhcmdldCwgaW5saW5lICkge1xuXHRcdHZhciBpZCA9IHRhcmdldFsgMCBdLmlkLnJlcGxhY2UoIC8oW15BLVphLXowLTlfXFwtXSkvZywgXCJcXFxcXFxcXCQxXCIgKTsgLy8gZXNjYXBlIGpRdWVyeSBtZXRhIGNoYXJzXG5cdFx0cmV0dXJuIHsgaWQ6IGlkLCBpbnB1dDogdGFyZ2V0LCAvLyBhc3NvY2lhdGVkIHRhcmdldFxuXHRcdFx0c2VsZWN0ZWREYXk6IDAsIHNlbGVjdGVkTW9udGg6IDAsIHNlbGVjdGVkWWVhcjogMCwgLy8gY3VycmVudCBzZWxlY3Rpb25cblx0XHRcdGRyYXdNb250aDogMCwgZHJhd1llYXI6IDAsIC8vIG1vbnRoIGJlaW5nIGRyYXduXG5cdFx0XHRpbmxpbmU6IGlubGluZSwgLy8gaXMgZGF0ZXBpY2tlciBpbmxpbmUgb3Igbm90XG5cdFx0XHRkcERpdjogKCAhaW5saW5lID8gdGhpcy5kcERpdiA6IC8vIHByZXNlbnRhdGlvbiBkaXZcblx0XHRcdGRhdGVwaWNrZXJfYmluZEhvdmVyKCAkKCBcIjxkaXYgY2xhc3M9J1wiICsgdGhpcy5faW5saW5lQ2xhc3MgKyBcIiB1aS1kYXRlcGlja2VyIHVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudCB1aS1oZWxwZXItY2xlYXJmaXggdWktY29ybmVyLWFsbCc+PC9kaXY+XCIgKSApICkgfTtcblx0fSxcblxuXHQvKiBBdHRhY2ggdGhlIGRhdGUgcGlja2VyIHRvIGFuIGlucHV0IGZpZWxkLiAqL1xuXHRfY29ubmVjdERhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQsIGluc3QgKSB7XG5cdFx0dmFyIGlucHV0ID0gJCggdGFyZ2V0ICk7XG5cdFx0aW5zdC5hcHBlbmQgPSAkKCBbXSApO1xuXHRcdGluc3QudHJpZ2dlciA9ICQoIFtdICk7XG5cdFx0aWYgKCBpbnB1dC5oYXNDbGFzcyggdGhpcy5tYXJrZXJDbGFzc05hbWUgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5fYXR0YWNobWVudHMoIGlucHV0LCBpbnN0ICk7XG5cdFx0aW5wdXQuYWRkQ2xhc3MoIHRoaXMubWFya2VyQ2xhc3NOYW1lICkub24oIFwia2V5ZG93blwiLCB0aGlzLl9kb0tleURvd24gKS5cblx0XHRcdG9uKCBcImtleXByZXNzXCIsIHRoaXMuX2RvS2V5UHJlc3MgKS5vbiggXCJrZXl1cFwiLCB0aGlzLl9kb0tleVVwICk7XG5cdFx0dGhpcy5fYXV0b1NpemUoIGluc3QgKTtcblx0XHQkLmRhdGEoIHRhcmdldCwgXCJkYXRlcGlja2VyXCIsIGluc3QgKTtcblxuXHRcdC8vSWYgZGlzYWJsZWQgb3B0aW9uIGlzIHRydWUsIGRpc2FibGUgdGhlIGRhdGVwaWNrZXIgb25jZSBpdCBoYXMgYmVlbiBhdHRhY2hlZCB0byB0aGUgaW5wdXQgKHNlZSB0aWNrZXQgIzU2NjUpXG5cdFx0aWYgKCBpbnN0LnNldHRpbmdzLmRpc2FibGVkICkge1xuXHRcdFx0dGhpcy5fZGlzYWJsZURhdGVwaWNrZXIoIHRhcmdldCApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBNYWtlIGF0dGFjaG1lbnRzIGJhc2VkIG9uIHNldHRpbmdzLiAqL1xuXHRfYXR0YWNobWVudHM6IGZ1bmN0aW9uKCBpbnB1dCwgaW5zdCApIHtcblx0XHR2YXIgc2hvd09uLCBidXR0b25UZXh0LCBidXR0b25JbWFnZSxcblx0XHRcdGFwcGVuZFRleHQgPSB0aGlzLl9nZXQoIGluc3QsIFwiYXBwZW5kVGV4dFwiICksXG5cdFx0XHRpc1JUTCA9IHRoaXMuX2dldCggaW5zdCwgXCJpc1JUTFwiICk7XG5cblx0XHRpZiAoIGluc3QuYXBwZW5kICkge1xuXHRcdFx0aW5zdC5hcHBlbmQucmVtb3ZlKCk7XG5cdFx0fVxuXHRcdGlmICggYXBwZW5kVGV4dCApIHtcblx0XHRcdGluc3QuYXBwZW5kID0gJCggXCI8c3BhbiBjbGFzcz0nXCIgKyB0aGlzLl9hcHBlbmRDbGFzcyArIFwiJz5cIiArIGFwcGVuZFRleHQgKyBcIjwvc3Bhbj5cIiApO1xuXHRcdFx0aW5wdXRbIGlzUlRMID8gXCJiZWZvcmVcIiA6IFwiYWZ0ZXJcIiBdKCBpbnN0LmFwcGVuZCApO1xuXHRcdH1cblxuXHRcdGlucHV0Lm9mZiggXCJmb2N1c1wiLCB0aGlzLl9zaG93RGF0ZXBpY2tlciApO1xuXG5cdFx0aWYgKCBpbnN0LnRyaWdnZXIgKSB7XG5cdFx0XHRpbnN0LnRyaWdnZXIucmVtb3ZlKCk7XG5cdFx0fVxuXG5cdFx0c2hvd09uID0gdGhpcy5fZ2V0KCBpbnN0LCBcInNob3dPblwiICk7XG5cdFx0aWYgKCBzaG93T24gPT09IFwiZm9jdXNcIiB8fCBzaG93T24gPT09IFwiYm90aFwiICkgeyAvLyBwb3AtdXAgZGF0ZSBwaWNrZXIgd2hlbiBpbiB0aGUgbWFya2VkIGZpZWxkXG5cdFx0XHRpbnB1dC5vbiggXCJmb2N1c1wiLCB0aGlzLl9zaG93RGF0ZXBpY2tlciApO1xuXHRcdH1cblx0XHRpZiAoIHNob3dPbiA9PT0gXCJidXR0b25cIiB8fCBzaG93T24gPT09IFwiYm90aFwiICkgeyAvLyBwb3AtdXAgZGF0ZSBwaWNrZXIgd2hlbiBidXR0b24gY2xpY2tlZFxuXHRcdFx0YnV0dG9uVGV4dCA9IHRoaXMuX2dldCggaW5zdCwgXCJidXR0b25UZXh0XCIgKTtcblx0XHRcdGJ1dHRvbkltYWdlID0gdGhpcy5fZ2V0KCBpbnN0LCBcImJ1dHRvbkltYWdlXCIgKTtcblx0XHRcdGluc3QudHJpZ2dlciA9ICQoIHRoaXMuX2dldCggaW5zdCwgXCJidXR0b25JbWFnZU9ubHlcIiApID9cblx0XHRcdFx0JCggXCI8aW1nLz5cIiApLmFkZENsYXNzKCB0aGlzLl90cmlnZ2VyQ2xhc3MgKS5cblx0XHRcdFx0XHRhdHRyKCB7IHNyYzogYnV0dG9uSW1hZ2UsIGFsdDogYnV0dG9uVGV4dCwgdGl0bGU6IGJ1dHRvblRleHQgfSApIDpcblx0XHRcdFx0JCggXCI8YnV0dG9uIHR5cGU9J2J1dHRvbic+PC9idXR0b24+XCIgKS5hZGRDbGFzcyggdGhpcy5fdHJpZ2dlckNsYXNzICkuXG5cdFx0XHRcdFx0aHRtbCggIWJ1dHRvbkltYWdlID8gYnV0dG9uVGV4dCA6ICQoIFwiPGltZy8+XCIgKS5hdHRyKFxuXHRcdFx0XHRcdHsgc3JjOmJ1dHRvbkltYWdlLCBhbHQ6YnV0dG9uVGV4dCwgdGl0bGU6YnV0dG9uVGV4dCB9ICkgKSApO1xuXHRcdFx0aW5wdXRbIGlzUlRMID8gXCJiZWZvcmVcIiA6IFwiYWZ0ZXJcIiBdKCBpbnN0LnRyaWdnZXIgKTtcblx0XHRcdGluc3QudHJpZ2dlci5vbiggXCJjbGlja1wiLCBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCAkLmRhdGVwaWNrZXIuX2RhdGVwaWNrZXJTaG93aW5nICYmICQuZGF0ZXBpY2tlci5fbGFzdElucHV0ID09PSBpbnB1dFsgMCBdICkge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5faGlkZURhdGVwaWNrZXIoKTtcblx0XHRcdFx0fSBlbHNlIGlmICggJC5kYXRlcGlja2VyLl9kYXRlcGlja2VyU2hvd2luZyAmJiAkLmRhdGVwaWNrZXIuX2xhc3RJbnB1dCAhPT0gaW5wdXRbIDAgXSApIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2hpZGVEYXRlcGlja2VyKCk7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9zaG93RGF0ZXBpY2tlciggaW5wdXRbIDAgXSApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fc2hvd0RhdGVwaWNrZXIoIGlucHV0WyAwIF0gKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIEFwcGx5IHRoZSBtYXhpbXVtIGxlbmd0aCBmb3IgdGhlIGRhdGUgZm9ybWF0LiAqL1xuXHRfYXV0b1NpemU6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdGlmICggdGhpcy5fZ2V0KCBpbnN0LCBcImF1dG9TaXplXCIgKSAmJiAhaW5zdC5pbmxpbmUgKSB7XG5cdFx0XHR2YXIgZmluZE1heCwgbWF4LCBtYXhJLCBpLFxuXHRcdFx0XHRkYXRlID0gbmV3IERhdGUoIDIwMDksIDEyIC0gMSwgMjAgKSwgLy8gRW5zdXJlIGRvdWJsZSBkaWdpdHNcblx0XHRcdFx0ZGF0ZUZvcm1hdCA9IHRoaXMuX2dldCggaW5zdCwgXCJkYXRlRm9ybWF0XCIgKTtcblxuXHRcdFx0aWYgKCBkYXRlRm9ybWF0Lm1hdGNoKCAvW0RNXS8gKSApIHtcblx0XHRcdFx0ZmluZE1heCA9IGZ1bmN0aW9uKCBuYW1lcyApIHtcblx0XHRcdFx0XHRtYXggPSAwO1xuXHRcdFx0XHRcdG1heEkgPSAwO1xuXHRcdFx0XHRcdGZvciAoIGkgPSAwOyBpIDwgbmFtZXMubGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRcdFx0XHRpZiAoIG5hbWVzWyBpIF0ubGVuZ3RoID4gbWF4ICkge1xuXHRcdFx0XHRcdFx0XHRtYXggPSBuYW1lc1sgaSBdLmxlbmd0aDtcblx0XHRcdFx0XHRcdFx0bWF4SSA9IGk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdHJldHVybiBtYXhJO1xuXHRcdFx0XHR9O1xuXHRcdFx0XHRkYXRlLnNldE1vbnRoKCBmaW5kTWF4KCB0aGlzLl9nZXQoIGluc3QsICggZGF0ZUZvcm1hdC5tYXRjaCggL01NLyApID9cblx0XHRcdFx0XHRcIm1vbnRoTmFtZXNcIiA6IFwibW9udGhOYW1lc1Nob3J0XCIgKSApICkgKTtcblx0XHRcdFx0ZGF0ZS5zZXREYXRlKCBmaW5kTWF4KCB0aGlzLl9nZXQoIGluc3QsICggZGF0ZUZvcm1hdC5tYXRjaCggL0RELyApID9cblx0XHRcdFx0XHRcImRheU5hbWVzXCIgOiBcImRheU5hbWVzU2hvcnRcIiApICkgKSArIDIwIC0gZGF0ZS5nZXREYXkoKSApO1xuXHRcdFx0fVxuXHRcdFx0aW5zdC5pbnB1dC5hdHRyKCBcInNpemVcIiwgdGhpcy5fZm9ybWF0RGF0ZSggaW5zdCwgZGF0ZSApLmxlbmd0aCApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBBdHRhY2ggYW4gaW5saW5lIGRhdGUgcGlja2VyIHRvIGEgZGl2LiAqL1xuXHRfaW5saW5lRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCwgaW5zdCApIHtcblx0XHR2YXIgZGl2U3BhbiA9ICQoIHRhcmdldCApO1xuXHRcdGlmICggZGl2U3Bhbi5oYXNDbGFzcyggdGhpcy5tYXJrZXJDbGFzc05hbWUgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0ZGl2U3Bhbi5hZGRDbGFzcyggdGhpcy5tYXJrZXJDbGFzc05hbWUgKS5hcHBlbmQoIGluc3QuZHBEaXYgKTtcblx0XHQkLmRhdGEoIHRhcmdldCwgXCJkYXRlcGlja2VyXCIsIGluc3QgKTtcblx0XHR0aGlzLl9zZXREYXRlKCBpbnN0LCB0aGlzLl9nZXREZWZhdWx0RGF0ZSggaW5zdCApLCB0cnVlICk7XG5cdFx0dGhpcy5fdXBkYXRlRGF0ZXBpY2tlciggaW5zdCApO1xuXHRcdHRoaXMuX3VwZGF0ZUFsdGVybmF0ZSggaW5zdCApO1xuXG5cdFx0Ly9JZiBkaXNhYmxlZCBvcHRpb24gaXMgdHJ1ZSwgZGlzYWJsZSB0aGUgZGF0ZXBpY2tlciBiZWZvcmUgc2hvd2luZyBpdCAoc2VlIHRpY2tldCAjNTY2NSlcblx0XHRpZiAoIGluc3Quc2V0dGluZ3MuZGlzYWJsZWQgKSB7XG5cdFx0XHR0aGlzLl9kaXNhYmxlRGF0ZXBpY2tlciggdGFyZ2V0ICk7XG5cdFx0fVxuXG5cdFx0Ly8gU2V0IGRpc3BsYXk6YmxvY2sgaW4gcGxhY2Ugb2YgaW5zdC5kcERpdi5zaG93KCkgd2hpY2ggd29uJ3Qgd29yayBvbiBkaXNjb25uZWN0ZWQgZWxlbWVudHNcblx0XHQvLyBodHRwOi8vYnVncy5qcXVlcnl1aS5jb20vdGlja2V0Lzc1NTIgLSBBIERhdGVwaWNrZXIgY3JlYXRlZCBvbiBhIGRldGFjaGVkIGRpdiBoYXMgemVybyBoZWlnaHRcblx0XHRpbnN0LmRwRGl2LmNzcyggXCJkaXNwbGF5XCIsIFwiYmxvY2tcIiApO1xuXHR9LFxuXG5cdC8qIFBvcC11cCB0aGUgZGF0ZSBwaWNrZXIgaW4gYSBcImRpYWxvZ1wiIGJveC5cblx0ICogQHBhcmFtICBpbnB1dCBlbGVtZW50IC0gaWdub3JlZFxuXHQgKiBAcGFyYW0gIGRhdGVcdHN0cmluZyBvciBEYXRlIC0gdGhlIGluaXRpYWwgZGF0ZSB0byBkaXNwbGF5XG5cdCAqIEBwYXJhbSAgb25TZWxlY3QgIGZ1bmN0aW9uIC0gdGhlIGZ1bmN0aW9uIHRvIGNhbGwgd2hlbiBhIGRhdGUgaXMgc2VsZWN0ZWRcblx0ICogQHBhcmFtICBzZXR0aW5ncyAgb2JqZWN0IC0gdXBkYXRlIHRoZSBkaWFsb2cgZGF0ZSBwaWNrZXIgaW5zdGFuY2UncyBzZXR0aW5ncyAoYW5vbnltb3VzIG9iamVjdClcblx0ICogQHBhcmFtICBwb3MgaW50WzJdIC0gY29vcmRpbmF0ZXMgZm9yIHRoZSBkaWFsb2cncyBwb3NpdGlvbiB3aXRoaW4gdGhlIHNjcmVlbiBvclxuXHQgKlx0XHRcdFx0XHRldmVudCAtIHdpdGggeC95IGNvb3JkaW5hdGVzIG9yXG5cdCAqXHRcdFx0XHRcdGxlYXZlIGVtcHR5IGZvciBkZWZhdWx0IChzY3JlZW4gY2VudHJlKVxuXHQgKiBAcmV0dXJuIHRoZSBtYW5hZ2VyIG9iamVjdFxuXHQgKi9cblx0X2RpYWxvZ0RhdGVwaWNrZXI6IGZ1bmN0aW9uKCBpbnB1dCwgZGF0ZSwgb25TZWxlY3QsIHNldHRpbmdzLCBwb3MgKSB7XG5cdFx0dmFyIGlkLCBicm93c2VyV2lkdGgsIGJyb3dzZXJIZWlnaHQsIHNjcm9sbFgsIHNjcm9sbFksXG5cdFx0XHRpbnN0ID0gdGhpcy5fZGlhbG9nSW5zdDsgLy8gaW50ZXJuYWwgaW5zdGFuY2VcblxuXHRcdGlmICggIWluc3QgKSB7XG5cdFx0XHR0aGlzLnV1aWQgKz0gMTtcblx0XHRcdGlkID0gXCJkcFwiICsgdGhpcy51dWlkO1xuXHRcdFx0dGhpcy5fZGlhbG9nSW5wdXQgPSAkKCBcIjxpbnB1dCB0eXBlPSd0ZXh0JyBpZD0nXCIgKyBpZCArXG5cdFx0XHRcdFwiJyBzdHlsZT0ncG9zaXRpb246IGFic29sdXRlOyB0b3A6IC0xMDBweDsgd2lkdGg6IDBweDsnLz5cIiApO1xuXHRcdFx0dGhpcy5fZGlhbG9nSW5wdXQub24oIFwia2V5ZG93blwiLCB0aGlzLl9kb0tleURvd24gKTtcblx0XHRcdCQoIFwiYm9keVwiICkuYXBwZW5kKCB0aGlzLl9kaWFsb2dJbnB1dCApO1xuXHRcdFx0aW5zdCA9IHRoaXMuX2RpYWxvZ0luc3QgPSB0aGlzLl9uZXdJbnN0KCB0aGlzLl9kaWFsb2dJbnB1dCwgZmFsc2UgKTtcblx0XHRcdGluc3Quc2V0dGluZ3MgPSB7fTtcblx0XHRcdCQuZGF0YSggdGhpcy5fZGlhbG9nSW5wdXRbIDAgXSwgXCJkYXRlcGlja2VyXCIsIGluc3QgKTtcblx0XHR9XG5cdFx0ZGF0ZXBpY2tlcl9leHRlbmRSZW1vdmUoIGluc3Quc2V0dGluZ3MsIHNldHRpbmdzIHx8IHt9ICk7XG5cdFx0ZGF0ZSA9ICggZGF0ZSAmJiBkYXRlLmNvbnN0cnVjdG9yID09PSBEYXRlID8gdGhpcy5fZm9ybWF0RGF0ZSggaW5zdCwgZGF0ZSApIDogZGF0ZSApO1xuXHRcdHRoaXMuX2RpYWxvZ0lucHV0LnZhbCggZGF0ZSApO1xuXG5cdFx0dGhpcy5fcG9zID0gKCBwb3MgPyAoIHBvcy5sZW5ndGggPyBwb3MgOiBbIHBvcy5wYWdlWCwgcG9zLnBhZ2VZIF0gKSA6IG51bGwgKTtcblx0XHRpZiAoICF0aGlzLl9wb3MgKSB7XG5cdFx0XHRicm93c2VyV2lkdGggPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50V2lkdGg7XG5cdFx0XHRicm93c2VySGVpZ2h0ID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodDtcblx0XHRcdHNjcm9sbFggPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc2Nyb2xsTGVmdCB8fCBkb2N1bWVudC5ib2R5LnNjcm9sbExlZnQ7XG5cdFx0XHRzY3JvbGxZID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnNjcm9sbFRvcCB8fCBkb2N1bWVudC5ib2R5LnNjcm9sbFRvcDtcblx0XHRcdHRoaXMuX3BvcyA9IC8vIHNob3VsZCB1c2UgYWN0dWFsIHdpZHRoL2hlaWdodCBiZWxvd1xuXHRcdFx0XHRbICggYnJvd3NlcldpZHRoIC8gMiApIC0gMTAwICsgc2Nyb2xsWCwgKCBicm93c2VySGVpZ2h0IC8gMiApIC0gMTUwICsgc2Nyb2xsWSBdO1xuXHRcdH1cblxuXHRcdC8vIE1vdmUgaW5wdXQgb24gc2NyZWVuIGZvciBmb2N1cywgYnV0IGhpZGRlbiBiZWhpbmQgZGlhbG9nXG5cdFx0dGhpcy5fZGlhbG9nSW5wdXQuY3NzKCBcImxlZnRcIiwgKCB0aGlzLl9wb3NbIDAgXSArIDIwICkgKyBcInB4XCIgKS5jc3MoIFwidG9wXCIsIHRoaXMuX3Bvc1sgMSBdICsgXCJweFwiICk7XG5cdFx0aW5zdC5zZXR0aW5ncy5vblNlbGVjdCA9IG9uU2VsZWN0O1xuXHRcdHRoaXMuX2luRGlhbG9nID0gdHJ1ZTtcblx0XHR0aGlzLmRwRGl2LmFkZENsYXNzKCB0aGlzLl9kaWFsb2dDbGFzcyApO1xuXHRcdHRoaXMuX3Nob3dEYXRlcGlja2VyKCB0aGlzLl9kaWFsb2dJbnB1dFsgMCBdICk7XG5cdFx0aWYgKCAkLmJsb2NrVUkgKSB7XG5cdFx0XHQkLmJsb2NrVUkoIHRoaXMuZHBEaXYgKTtcblx0XHR9XG5cdFx0JC5kYXRhKCB0aGlzLl9kaWFsb2dJbnB1dFsgMCBdLCBcImRhdGVwaWNrZXJcIiwgaW5zdCApO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8qIERldGFjaCBhIGRhdGVwaWNrZXIgZnJvbSBpdHMgY29udHJvbC5cblx0ICogQHBhcmFtICB0YXJnZXRcdGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICovXG5cdF9kZXN0cm95RGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCApIHtcblx0XHR2YXIgbm9kZU5hbWUsXG5cdFx0XHQkdGFyZ2V0ID0gJCggdGFyZ2V0ICksXG5cdFx0XHRpbnN0ID0gJC5kYXRhKCB0YXJnZXQsIFwiZGF0ZXBpY2tlclwiICk7XG5cblx0XHRpZiAoICEkdGFyZ2V0Lmhhc0NsYXNzKCB0aGlzLm1hcmtlckNsYXNzTmFtZSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdG5vZGVOYW1lID0gdGFyZ2V0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cdFx0JC5yZW1vdmVEYXRhKCB0YXJnZXQsIFwiZGF0ZXBpY2tlclwiICk7XG5cdFx0aWYgKCBub2RlTmFtZSA9PT0gXCJpbnB1dFwiICkge1xuXHRcdFx0aW5zdC5hcHBlbmQucmVtb3ZlKCk7XG5cdFx0XHRpbnN0LnRyaWdnZXIucmVtb3ZlKCk7XG5cdFx0XHQkdGFyZ2V0LnJlbW92ZUNsYXNzKCB0aGlzLm1hcmtlckNsYXNzTmFtZSApLlxuXHRcdFx0XHRvZmYoIFwiZm9jdXNcIiwgdGhpcy5fc2hvd0RhdGVwaWNrZXIgKS5cblx0XHRcdFx0b2ZmKCBcImtleWRvd25cIiwgdGhpcy5fZG9LZXlEb3duICkuXG5cdFx0XHRcdG9mZiggXCJrZXlwcmVzc1wiLCB0aGlzLl9kb0tleVByZXNzICkuXG5cdFx0XHRcdG9mZiggXCJrZXl1cFwiLCB0aGlzLl9kb0tleVVwICk7XG5cdFx0fSBlbHNlIGlmICggbm9kZU5hbWUgPT09IFwiZGl2XCIgfHwgbm9kZU5hbWUgPT09IFwic3BhblwiICkge1xuXHRcdFx0JHRhcmdldC5yZW1vdmVDbGFzcyggdGhpcy5tYXJrZXJDbGFzc05hbWUgKS5lbXB0eSgpO1xuXHRcdH1cblxuXHRcdGlmICggZGF0ZXBpY2tlcl9pbnN0QWN0aXZlID09PSBpbnN0ICkge1xuXHRcdFx0ZGF0ZXBpY2tlcl9pbnN0QWN0aXZlID0gbnVsbDtcblx0XHR9XG5cdH0sXG5cblx0LyogRW5hYmxlIHRoZSBkYXRlIHBpY2tlciB0byBhIGpRdWVyeSBzZWxlY3Rpb24uXG5cdCAqIEBwYXJhbSAgdGFyZ2V0XHRlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqL1xuXHRfZW5hYmxlRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCApIHtcblx0XHR2YXIgbm9kZU5hbWUsIGlubGluZSxcblx0XHRcdCR0YXJnZXQgPSAkKCB0YXJnZXQgKSxcblx0XHRcdGluc3QgPSAkLmRhdGEoIHRhcmdldCwgXCJkYXRlcGlja2VyXCIgKTtcblxuXHRcdGlmICggISR0YXJnZXQuaGFzQ2xhc3MoIHRoaXMubWFya2VyQ2xhc3NOYW1lICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0bm9kZU5hbWUgPSB0YXJnZXQubm9kZU5hbWUudG9Mb3dlckNhc2UoKTtcblx0XHRpZiAoIG5vZGVOYW1lID09PSBcImlucHV0XCIgKSB7XG5cdFx0XHR0YXJnZXQuZGlzYWJsZWQgPSBmYWxzZTtcblx0XHRcdGluc3QudHJpZ2dlci5maWx0ZXIoIFwiYnV0dG9uXCIgKS5cblx0XHRcdFx0ZWFjaCggZnVuY3Rpb24oKSB7IHRoaXMuZGlzYWJsZWQgPSBmYWxzZTsgfSApLmVuZCgpLlxuXHRcdFx0XHRmaWx0ZXIoIFwiaW1nXCIgKS5jc3MoIHsgb3BhY2l0eTogXCIxLjBcIiwgY3Vyc29yOiBcIlwiIH0gKTtcblx0XHR9IGVsc2UgaWYgKCBub2RlTmFtZSA9PT0gXCJkaXZcIiB8fCBub2RlTmFtZSA9PT0gXCJzcGFuXCIgKSB7XG5cdFx0XHRpbmxpbmUgPSAkdGFyZ2V0LmNoaWxkcmVuKCBcIi5cIiArIHRoaXMuX2lubGluZUNsYXNzICk7XG5cdFx0XHRpbmxpbmUuY2hpbGRyZW4oKS5yZW1vdmVDbGFzcyggXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiICk7XG5cdFx0XHRpbmxpbmUuZmluZCggXCJzZWxlY3QudWktZGF0ZXBpY2tlci1tb250aCwgc2VsZWN0LnVpLWRhdGVwaWNrZXIteWVhclwiICkuXG5cdFx0XHRcdHByb3AoIFwiZGlzYWJsZWRcIiwgZmFsc2UgKTtcblx0XHR9XG5cdFx0dGhpcy5fZGlzYWJsZWRJbnB1dHMgPSAkLm1hcCggdGhpcy5fZGlzYWJsZWRJbnB1dHMsXG5cdFx0XHRmdW5jdGlvbiggdmFsdWUgKSB7IHJldHVybiAoIHZhbHVlID09PSB0YXJnZXQgPyBudWxsIDogdmFsdWUgKTsgfSApOyAvLyBkZWxldGUgZW50cnlcblx0fSxcblxuXHQvKiBEaXNhYmxlIHRoZSBkYXRlIHBpY2tlciB0byBhIGpRdWVyeSBzZWxlY3Rpb24uXG5cdCAqIEBwYXJhbSAgdGFyZ2V0XHRlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqL1xuXHRfZGlzYWJsZURhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cdFx0dmFyIG5vZGVOYW1lLCBpbmxpbmUsXG5cdFx0XHQkdGFyZ2V0ID0gJCggdGFyZ2V0ICksXG5cdFx0XHRpbnN0ID0gJC5kYXRhKCB0YXJnZXQsIFwiZGF0ZXBpY2tlclwiICk7XG5cblx0XHRpZiAoICEkdGFyZ2V0Lmhhc0NsYXNzKCB0aGlzLm1hcmtlckNsYXNzTmFtZSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdG5vZGVOYW1lID0gdGFyZ2V0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCk7XG5cdFx0aWYgKCBub2RlTmFtZSA9PT0gXCJpbnB1dFwiICkge1xuXHRcdFx0dGFyZ2V0LmRpc2FibGVkID0gdHJ1ZTtcblx0XHRcdGluc3QudHJpZ2dlci5maWx0ZXIoIFwiYnV0dG9uXCIgKS5cblx0XHRcdFx0ZWFjaCggZnVuY3Rpb24oKSB7IHRoaXMuZGlzYWJsZWQgPSB0cnVlOyB9ICkuZW5kKCkuXG5cdFx0XHRcdGZpbHRlciggXCJpbWdcIiApLmNzcyggeyBvcGFjaXR5OiBcIjAuNVwiLCBjdXJzb3I6IFwiZGVmYXVsdFwiIH0gKTtcblx0XHR9IGVsc2UgaWYgKCBub2RlTmFtZSA9PT0gXCJkaXZcIiB8fCBub2RlTmFtZSA9PT0gXCJzcGFuXCIgKSB7XG5cdFx0XHRpbmxpbmUgPSAkdGFyZ2V0LmNoaWxkcmVuKCBcIi5cIiArIHRoaXMuX2lubGluZUNsYXNzICk7XG5cdFx0XHRpbmxpbmUuY2hpbGRyZW4oKS5hZGRDbGFzcyggXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiICk7XG5cdFx0XHRpbmxpbmUuZmluZCggXCJzZWxlY3QudWktZGF0ZXBpY2tlci1tb250aCwgc2VsZWN0LnVpLWRhdGVwaWNrZXIteWVhclwiICkuXG5cdFx0XHRcdHByb3AoIFwiZGlzYWJsZWRcIiwgdHJ1ZSApO1xuXHRcdH1cblx0XHR0aGlzLl9kaXNhYmxlZElucHV0cyA9ICQubWFwKCB0aGlzLl9kaXNhYmxlZElucHV0cyxcblx0XHRcdGZ1bmN0aW9uKCB2YWx1ZSApIHsgcmV0dXJuICggdmFsdWUgPT09IHRhcmdldCA/IG51bGwgOiB2YWx1ZSApOyB9ICk7IC8vIGRlbGV0ZSBlbnRyeVxuXHRcdHRoaXMuX2Rpc2FibGVkSW5wdXRzWyB0aGlzLl9kaXNhYmxlZElucHV0cy5sZW5ndGggXSA9IHRhcmdldDtcblx0fSxcblxuXHQvKiBJcyB0aGUgZmlyc3QgZmllbGQgaW4gYSBqUXVlcnkgY29sbGVjdGlvbiBkaXNhYmxlZCBhcyBhIGRhdGVwaWNrZXI/XG5cdCAqIEBwYXJhbSAgdGFyZ2V0XHRlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqIEByZXR1cm4gYm9vbGVhbiAtIHRydWUgaWYgZGlzYWJsZWQsIGZhbHNlIGlmIGVuYWJsZWRcblx0ICovXG5cdF9pc0Rpc2FibGVkRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCApIHtcblx0XHRpZiAoICF0YXJnZXQgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHRcdGZvciAoIHZhciBpID0gMDsgaSA8IHRoaXMuX2Rpc2FibGVkSW5wdXRzLmxlbmd0aDsgaSsrICkge1xuXHRcdFx0aWYgKCB0aGlzLl9kaXNhYmxlZElucHV0c1sgaSBdID09PSB0YXJnZXQgKSB7XG5cdFx0XHRcdHJldHVybiB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0sXG5cblx0LyogUmV0cmlldmUgdGhlIGluc3RhbmNlIGRhdGEgZm9yIHRoZSB0YXJnZXQgY29udHJvbC5cblx0ICogQHBhcmFtICB0YXJnZXQgIGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICogQHJldHVybiAgb2JqZWN0IC0gdGhlIGFzc29jaWF0ZWQgaW5zdGFuY2UgZGF0YVxuXHQgKiBAdGhyb3dzICBlcnJvciBpZiBhIGpRdWVyeSBwcm9ibGVtIGdldHRpbmcgZGF0YVxuXHQgKi9cblx0X2dldEluc3Q6IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cdFx0dHJ5IHtcblx0XHRcdHJldHVybiAkLmRhdGEoIHRhcmdldCwgXCJkYXRlcGlja2VyXCIgKTtcblx0XHR9XG5cdFx0Y2F0Y2ggKCBlcnIgKSB7XG5cdFx0XHR0aHJvdyBcIk1pc3NpbmcgaW5zdGFuY2UgZGF0YSBmb3IgdGhpcyBkYXRlcGlja2VyXCI7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIFVwZGF0ZSBvciByZXRyaWV2ZSB0aGUgc2V0dGluZ3MgZm9yIGEgZGF0ZSBwaWNrZXIgYXR0YWNoZWQgdG8gYW4gaW5wdXQgZmllbGQgb3IgZGl2aXNpb24uXG5cdCAqIEBwYXJhbSAgdGFyZ2V0ICBlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqIEBwYXJhbSAgbmFtZVx0b2JqZWN0IC0gdGhlIG5ldyBzZXR0aW5ncyB0byB1cGRhdGUgb3Jcblx0ICpcdFx0XHRcdHN0cmluZyAtIHRoZSBuYW1lIG9mIHRoZSBzZXR0aW5nIHRvIGNoYW5nZSBvciByZXRyaWV2ZSxcblx0ICpcdFx0XHRcdHdoZW4gcmV0cmlldmluZyBhbHNvIFwiYWxsXCIgZm9yIGFsbCBpbnN0YW5jZSBzZXR0aW5ncyBvclxuXHQgKlx0XHRcdFx0XCJkZWZhdWx0c1wiIGZvciBhbGwgZ2xvYmFsIGRlZmF1bHRzXG5cdCAqIEBwYXJhbSAgdmFsdWUgICBhbnkgLSB0aGUgbmV3IHZhbHVlIGZvciB0aGUgc2V0dGluZ1xuXHQgKlx0XHRcdFx0KG9taXQgaWYgYWJvdmUgaXMgYW4gb2JqZWN0IG9yIHRvIHJldHJpZXZlIGEgdmFsdWUpXG5cdCAqL1xuXHRfb3B0aW9uRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCwgbmFtZSwgdmFsdWUgKSB7XG5cdFx0dmFyIHNldHRpbmdzLCBkYXRlLCBtaW5EYXRlLCBtYXhEYXRlLFxuXHRcdFx0aW5zdCA9IHRoaXMuX2dldEluc3QoIHRhcmdldCApO1xuXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID09PSAyICYmIHR5cGVvZiBuYW1lID09PSBcInN0cmluZ1wiICkge1xuXHRcdFx0cmV0dXJuICggbmFtZSA9PT0gXCJkZWZhdWx0c1wiID8gJC5leHRlbmQoIHt9LCAkLmRhdGVwaWNrZXIuX2RlZmF1bHRzICkgOlxuXHRcdFx0XHQoIGluc3QgPyAoIG5hbWUgPT09IFwiYWxsXCIgPyAkLmV4dGVuZCgge30sIGluc3Quc2V0dGluZ3MgKSA6XG5cdFx0XHRcdHRoaXMuX2dldCggaW5zdCwgbmFtZSApICkgOiBudWxsICkgKTtcblx0XHR9XG5cblx0XHRzZXR0aW5ncyA9IG5hbWUgfHwge307XG5cdFx0aWYgKCB0eXBlb2YgbmFtZSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdHNldHRpbmdzID0ge307XG5cdFx0XHRzZXR0aW5nc1sgbmFtZSBdID0gdmFsdWU7XG5cdFx0fVxuXG5cdFx0aWYgKCBpbnN0ICkge1xuXHRcdFx0aWYgKCB0aGlzLl9jdXJJbnN0ID09PSBpbnN0ICkge1xuXHRcdFx0XHR0aGlzLl9oaWRlRGF0ZXBpY2tlcigpO1xuXHRcdFx0fVxuXG5cdFx0XHRkYXRlID0gdGhpcy5fZ2V0RGF0ZURhdGVwaWNrZXIoIHRhcmdldCwgdHJ1ZSApO1xuXHRcdFx0bWluRGF0ZSA9IHRoaXMuX2dldE1pbk1heERhdGUoIGluc3QsIFwibWluXCIgKTtcblx0XHRcdG1heERhdGUgPSB0aGlzLl9nZXRNaW5NYXhEYXRlKCBpbnN0LCBcIm1heFwiICk7XG5cdFx0XHRkYXRlcGlja2VyX2V4dGVuZFJlbW92ZSggaW5zdC5zZXR0aW5ncywgc2V0dGluZ3MgKTtcblxuXHRcdFx0Ly8gcmVmb3JtYXQgdGhlIG9sZCBtaW5EYXRlL21heERhdGUgdmFsdWVzIGlmIGRhdGVGb3JtYXQgY2hhbmdlcyBhbmQgYSBuZXcgbWluRGF0ZS9tYXhEYXRlIGlzbid0IHByb3ZpZGVkXG5cdFx0XHRpZiAoIG1pbkRhdGUgIT09IG51bGwgJiYgc2V0dGluZ3MuZGF0ZUZvcm1hdCAhPT0gdW5kZWZpbmVkICYmIHNldHRpbmdzLm1pbkRhdGUgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0aW5zdC5zZXR0aW5ncy5taW5EYXRlID0gdGhpcy5fZm9ybWF0RGF0ZSggaW5zdCwgbWluRGF0ZSApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBtYXhEYXRlICE9PSBudWxsICYmIHNldHRpbmdzLmRhdGVGb3JtYXQgIT09IHVuZGVmaW5lZCAmJiBzZXR0aW5ncy5tYXhEYXRlID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdGluc3Quc2V0dGluZ3MubWF4RGF0ZSA9IHRoaXMuX2Zvcm1hdERhdGUoIGluc3QsIG1heERhdGUgKTtcblx0XHRcdH1cblx0XHRcdGlmICggXCJkaXNhYmxlZFwiIGluIHNldHRpbmdzICkge1xuXHRcdFx0XHRpZiAoIHNldHRpbmdzLmRpc2FibGVkICkge1xuXHRcdFx0XHRcdHRoaXMuX2Rpc2FibGVEYXRlcGlja2VyKCB0YXJnZXQgKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aGlzLl9lbmFibGVEYXRlcGlja2VyKCB0YXJnZXQgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0dGhpcy5fYXR0YWNobWVudHMoICQoIHRhcmdldCApLCBpbnN0ICk7XG5cdFx0XHR0aGlzLl9hdXRvU2l6ZSggaW5zdCApO1xuXHRcdFx0dGhpcy5fc2V0RGF0ZSggaW5zdCwgZGF0ZSApO1xuXHRcdFx0dGhpcy5fdXBkYXRlQWx0ZXJuYXRlKCBpbnN0ICk7XG5cdFx0XHR0aGlzLl91cGRhdGVEYXRlcGlja2VyKCBpbnN0ICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIENoYW5nZSBtZXRob2QgZGVwcmVjYXRlZFxuXHRfY2hhbmdlRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCwgbmFtZSwgdmFsdWUgKSB7XG5cdFx0dGhpcy5fb3B0aW9uRGF0ZXBpY2tlciggdGFyZ2V0LCBuYW1lLCB2YWx1ZSApO1xuXHR9LFxuXG5cdC8qIFJlZHJhdyB0aGUgZGF0ZSBwaWNrZXIgYXR0YWNoZWQgdG8gYW4gaW5wdXQgZmllbGQgb3IgZGl2aXNpb24uXG5cdCAqIEBwYXJhbSAgdGFyZ2V0ICBlbGVtZW50IC0gdGhlIHRhcmdldCBpbnB1dCBmaWVsZCBvciBkaXZpc2lvbiBvciBzcGFuXG5cdCAqL1xuXHRfcmVmcmVzaERhdGVwaWNrZXI6IGZ1bmN0aW9uKCB0YXJnZXQgKSB7XG5cdFx0dmFyIGluc3QgPSB0aGlzLl9nZXRJbnN0KCB0YXJnZXQgKTtcblx0XHRpZiAoIGluc3QgKSB7XG5cdFx0XHR0aGlzLl91cGRhdGVEYXRlcGlja2VyKCBpbnN0ICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIFNldCB0aGUgZGF0ZXMgZm9yIGEgalF1ZXJ5IHNlbGVjdGlvbi5cblx0ICogQHBhcmFtICB0YXJnZXQgZWxlbWVudCAtIHRoZSB0YXJnZXQgaW5wdXQgZmllbGQgb3IgZGl2aXNpb24gb3Igc3BhblxuXHQgKiBAcGFyYW0gIGRhdGVcdERhdGUgLSB0aGUgbmV3IGRhdGVcblx0ICovXG5cdF9zZXREYXRlRGF0ZXBpY2tlcjogZnVuY3Rpb24oIHRhcmdldCwgZGF0ZSApIHtcblx0XHR2YXIgaW5zdCA9IHRoaXMuX2dldEluc3QoIHRhcmdldCApO1xuXHRcdGlmICggaW5zdCApIHtcblx0XHRcdHRoaXMuX3NldERhdGUoIGluc3QsIGRhdGUgKTtcblx0XHRcdHRoaXMuX3VwZGF0ZURhdGVwaWNrZXIoIGluc3QgKTtcblx0XHRcdHRoaXMuX3VwZGF0ZUFsdGVybmF0ZSggaW5zdCApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBHZXQgdGhlIGRhdGUocykgZm9yIHRoZSBmaXJzdCBlbnRyeSBpbiBhIGpRdWVyeSBzZWxlY3Rpb24uXG5cdCAqIEBwYXJhbSAgdGFyZ2V0IGVsZW1lbnQgLSB0aGUgdGFyZ2V0IGlucHV0IGZpZWxkIG9yIGRpdmlzaW9uIG9yIHNwYW5cblx0ICogQHBhcmFtICBub0RlZmF1bHQgYm9vbGVhbiAtIHRydWUgaWYgbm8gZGVmYXVsdCBkYXRlIGlzIHRvIGJlIHVzZWRcblx0ICogQHJldHVybiBEYXRlIC0gdGhlIGN1cnJlbnQgZGF0ZVxuXHQgKi9cblx0X2dldERhdGVEYXRlcGlja2VyOiBmdW5jdGlvbiggdGFyZ2V0LCBub0RlZmF1bHQgKSB7XG5cdFx0dmFyIGluc3QgPSB0aGlzLl9nZXRJbnN0KCB0YXJnZXQgKTtcblx0XHRpZiAoIGluc3QgJiYgIWluc3QuaW5saW5lICkge1xuXHRcdFx0dGhpcy5fc2V0RGF0ZUZyb21GaWVsZCggaW5zdCwgbm9EZWZhdWx0ICk7XG5cdFx0fVxuXHRcdHJldHVybiAoIGluc3QgPyB0aGlzLl9nZXREYXRlKCBpbnN0ICkgOiBudWxsICk7XG5cdH0sXG5cblx0LyogSGFuZGxlIGtleXN0cm9rZXMuICovXG5cdF9kb0tleURvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgb25TZWxlY3QsIGRhdGVTdHIsIHNlbCxcblx0XHRcdGluc3QgPSAkLmRhdGVwaWNrZXIuX2dldEluc3QoIGV2ZW50LnRhcmdldCApLFxuXHRcdFx0aGFuZGxlZCA9IHRydWUsXG5cdFx0XHRpc1JUTCA9IGluc3QuZHBEaXYuaXMoIFwiLnVpLWRhdGVwaWNrZXItcnRsXCIgKTtcblxuXHRcdGluc3QuX2tleUV2ZW50ID0gdHJ1ZTtcblx0XHRpZiAoICQuZGF0ZXBpY2tlci5fZGF0ZXBpY2tlclNob3dpbmcgKSB7XG5cdFx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdFx0XHRjYXNlIDk6ICQuZGF0ZXBpY2tlci5faGlkZURhdGVwaWNrZXIoKTtcblx0XHRcdFx0XHRcdGhhbmRsZWQgPSBmYWxzZTtcblx0XHRcdFx0XHRcdGJyZWFrOyAvLyBoaWRlIG9uIHRhYiBvdXRcblx0XHRcdFx0Y2FzZSAxMzogc2VsID0gJCggXCJ0ZC5cIiArICQuZGF0ZXBpY2tlci5fZGF5T3ZlckNsYXNzICsgXCI6bm90KC5cIiArXG5cdFx0XHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2N1cnJlbnRDbGFzcyArIFwiKVwiLCBpbnN0LmRwRGl2ICk7XG5cdFx0XHRcdFx0XHRpZiAoIHNlbFsgMCBdICkge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX3NlbGVjdERheSggZXZlbnQudGFyZ2V0LCBpbnN0LnNlbGVjdGVkTW9udGgsIGluc3Quc2VsZWN0ZWRZZWFyLCBzZWxbIDAgXSApO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRvblNlbGVjdCA9ICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcIm9uU2VsZWN0XCIgKTtcblx0XHRcdFx0XHRcdGlmICggb25TZWxlY3QgKSB7XG5cdFx0XHRcdFx0XHRcdGRhdGVTdHIgPSAkLmRhdGVwaWNrZXIuX2Zvcm1hdERhdGUoIGluc3QgKTtcblxuXHRcdFx0XHRcdFx0XHQvLyBUcmlnZ2VyIGN1c3RvbSBjYWxsYmFja1xuXHRcdFx0XHRcdFx0XHRvblNlbGVjdC5hcHBseSggKCBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dFsgMCBdIDogbnVsbCApLCBbIGRhdGVTdHIsIGluc3QgXSApO1xuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9oaWRlRGF0ZXBpY2tlcigpO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7IC8vIGRvbid0IHN1Ym1pdCB0aGUgZm9ybVxuXHRcdFx0XHRjYXNlIDI3OiAkLmRhdGVwaWNrZXIuX2hpZGVEYXRlcGlja2VyKCk7XG5cdFx0XHRcdFx0XHRicmVhazsgLy8gaGlkZSBvbiBlc2NhcGVcblx0XHRcdFx0Y2FzZSAzMzogJC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBldmVudC50YXJnZXQsICggZXZlbnQuY3RybEtleSA/XG5cdFx0XHRcdFx0XHRcdC0kLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzdGVwQmlnTW9udGhzXCIgKSA6XG5cdFx0XHRcdFx0XHRcdC0kLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzdGVwTW9udGhzXCIgKSApLCBcIk1cIiApO1xuXHRcdFx0XHRcdFx0YnJlYWs7IC8vIHByZXZpb3VzIG1vbnRoL3llYXIgb24gcGFnZSB1cC8rIGN0cmxcblx0XHRcdFx0Y2FzZSAzNDogJC5kYXRlcGlja2VyLl9hZGp1c3REYXRlKCBldmVudC50YXJnZXQsICggZXZlbnQuY3RybEtleSA/XG5cdFx0XHRcdFx0XHRcdCskLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzdGVwQmlnTW9udGhzXCIgKSA6XG5cdFx0XHRcdFx0XHRcdCskLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzdGVwTW9udGhzXCIgKSApLCBcIk1cIiApO1xuXHRcdFx0XHRcdFx0YnJlYWs7IC8vIG5leHQgbW9udGgveWVhciBvbiBwYWdlIGRvd24vKyBjdHJsXG5cdFx0XHRcdGNhc2UgMzU6IGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5ICkge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2NsZWFyRGF0ZSggZXZlbnQudGFyZ2V0ICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRoYW5kbGVkID0gZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5O1xuXHRcdFx0XHRcdFx0YnJlYWs7IC8vIGNsZWFyIG9uIGN0cmwgb3IgY29tbWFuZCArZW5kXG5cdFx0XHRcdGNhc2UgMzY6IGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5ICkge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2dvdG9Ub2RheSggZXZlbnQudGFyZ2V0ICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRoYW5kbGVkID0gZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5O1xuXHRcdFx0XHRcdFx0YnJlYWs7IC8vIGN1cnJlbnQgb24gY3RybCBvciBjb21tYW5kICtob21lXG5cdFx0XHRcdGNhc2UgMzc6IGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5ICkge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGV2ZW50LnRhcmdldCwgKCBpc1JUTCA/ICsxIDogLTEgKSwgXCJEXCIgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGhhbmRsZWQgPSBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXk7XG5cblx0XHRcdFx0XHRcdC8vIC0xIGRheSBvbiBjdHJsIG9yIGNvbW1hbmQgK2xlZnRcblx0XHRcdFx0XHRcdGlmICggZXZlbnQub3JpZ2luYWxFdmVudC5hbHRLZXkgKSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggZXZlbnQudGFyZ2V0LCAoIGV2ZW50LmN0cmxLZXkgP1xuXHRcdFx0XHRcdFx0XHRcdC0kLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzdGVwQmlnTW9udGhzXCIgKSA6XG5cdFx0XHRcdFx0XHRcdFx0LSQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcInN0ZXBNb250aHNcIiApICksIFwiTVwiICk7XG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIG5leHQgbW9udGgveWVhciBvbiBhbHQgK2xlZnQgb24gTWFjXG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAzODogaWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgKSB7XG5cdFx0XHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggZXZlbnQudGFyZ2V0LCAtNywgXCJEXCIgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGhhbmRsZWQgPSBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXk7XG5cdFx0XHRcdFx0XHRicmVhazsgLy8gLTEgd2VlayBvbiBjdHJsIG9yIGNvbW1hbmQgK3VwXG5cdFx0XHRcdGNhc2UgMzk6IGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5ICkge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGV2ZW50LnRhcmdldCwgKCBpc1JUTCA/IC0xIDogKzEgKSwgXCJEXCIgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGhhbmRsZWQgPSBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXk7XG5cblx0XHRcdFx0XHRcdC8vICsxIGRheSBvbiBjdHJsIG9yIGNvbW1hbmQgK3JpZ2h0XG5cdFx0XHRcdFx0XHRpZiAoIGV2ZW50Lm9yaWdpbmFsRXZlbnQuYWx0S2V5ICkge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGV2ZW50LnRhcmdldCwgKCBldmVudC5jdHJsS2V5ID9cblx0XHRcdFx0XHRcdFx0XHQrJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic3RlcEJpZ01vbnRoc1wiICkgOlxuXHRcdFx0XHRcdFx0XHRcdCskLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzdGVwTW9udGhzXCIgKSApLCBcIk1cIiApO1xuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHQvLyBuZXh0IG1vbnRoL3llYXIgb24gYWx0ICtyaWdodFxuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdGNhc2UgNDA6IGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5ICkge1xuXHRcdFx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGV2ZW50LnRhcmdldCwgKzcsIFwiRFwiICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRoYW5kbGVkID0gZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5O1xuXHRcdFx0XHRcdFx0YnJlYWs7IC8vICsxIHdlZWsgb24gY3RybCBvciBjb21tYW5kICtkb3duXG5cdFx0XHRcdGRlZmF1bHQ6IGhhbmRsZWQgPSBmYWxzZTtcblx0XHRcdH1cblx0XHR9IGVsc2UgaWYgKCBldmVudC5rZXlDb2RlID09PSAzNiAmJiBldmVudC5jdHJsS2V5ICkgeyAvLyBkaXNwbGF5IHRoZSBkYXRlIHBpY2tlciBvbiBjdHJsK2hvbWVcblx0XHRcdCQuZGF0ZXBpY2tlci5fc2hvd0RhdGVwaWNrZXIoIHRoaXMgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aGFuZGxlZCA9IGZhbHNlO1xuXHRcdH1cblxuXHRcdGlmICggaGFuZGxlZCApIHtcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcblx0XHR9XG5cdH0sXG5cblx0LyogRmlsdGVyIGVudGVyZWQgY2hhcmFjdGVycyAtIGJhc2VkIG9uIGRhdGUgZm9ybWF0LiAqL1xuXHRfZG9LZXlQcmVzczogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBjaGFycywgY2hyLFxuXHRcdFx0aW5zdCA9ICQuZGF0ZXBpY2tlci5fZ2V0SW5zdCggZXZlbnQudGFyZ2V0ICk7XG5cblx0XHRpZiAoICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcImNvbnN0cmFpbklucHV0XCIgKSApIHtcblx0XHRcdGNoYXJzID0gJC5kYXRlcGlja2VyLl9wb3NzaWJsZUNoYXJzKCAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJkYXRlRm9ybWF0XCIgKSApO1xuXHRcdFx0Y2hyID0gU3RyaW5nLmZyb21DaGFyQ29kZSggZXZlbnQuY2hhckNvZGUgPT0gbnVsbCA/IGV2ZW50LmtleUNvZGUgOiBldmVudC5jaGFyQ29kZSApO1xuXHRcdFx0cmV0dXJuIGV2ZW50LmN0cmxLZXkgfHwgZXZlbnQubWV0YUtleSB8fCAoIGNociA8IFwiIFwiIHx8ICFjaGFycyB8fCBjaGFycy5pbmRleE9mKCBjaHIgKSA+IC0xICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIFN5bmNocm9uaXNlIG1hbnVhbCBlbnRyeSBhbmQgZmllbGQvYWx0ZXJuYXRlIGZpZWxkLiAqL1xuXHRfZG9LZXlVcDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBkYXRlLFxuXHRcdFx0aW5zdCA9ICQuZGF0ZXBpY2tlci5fZ2V0SW5zdCggZXZlbnQudGFyZ2V0ICk7XG5cblx0XHRpZiAoIGluc3QuaW5wdXQudmFsKCkgIT09IGluc3QubGFzdFZhbCApIHtcblx0XHRcdHRyeSB7XG5cdFx0XHRcdGRhdGUgPSAkLmRhdGVwaWNrZXIucGFyc2VEYXRlKCAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJkYXRlRm9ybWF0XCIgKSxcblx0XHRcdFx0XHQoIGluc3QuaW5wdXQgPyBpbnN0LmlucHV0LnZhbCgpIDogbnVsbCApLFxuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fZ2V0Rm9ybWF0Q29uZmlnKCBpbnN0ICkgKTtcblxuXHRcdFx0XHRpZiAoIGRhdGUgKSB7IC8vIG9ubHkgaWYgdmFsaWRcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX3NldERhdGVGcm9tRmllbGQoIGluc3QgKTtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX3VwZGF0ZUFsdGVybmF0ZSggaW5zdCApO1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fdXBkYXRlRGF0ZXBpY2tlciggaW5zdCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRjYXRjaCAoIGVyciApIHtcblx0XHRcdH1cblx0XHR9XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0LyogUG9wLXVwIHRoZSBkYXRlIHBpY2tlciBmb3IgYSBnaXZlbiBpbnB1dCBmaWVsZC5cblx0ICogSWYgZmFsc2UgcmV0dXJuZWQgZnJvbSBiZWZvcmVTaG93IGV2ZW50IGhhbmRsZXIgZG8gbm90IHNob3cuXG5cdCAqIEBwYXJhbSAgaW5wdXQgIGVsZW1lbnQgLSB0aGUgaW5wdXQgZmllbGQgYXR0YWNoZWQgdG8gdGhlIGRhdGUgcGlja2VyIG9yXG5cdCAqXHRcdFx0XHRcdGV2ZW50IC0gaWYgdHJpZ2dlcmVkIGJ5IGZvY3VzXG5cdCAqL1xuXHRfc2hvd0RhdGVwaWNrZXI6IGZ1bmN0aW9uKCBpbnB1dCApIHtcblx0XHRpbnB1dCA9IGlucHV0LnRhcmdldCB8fCBpbnB1dDtcblx0XHRpZiAoIGlucHV0Lm5vZGVOYW1lLnRvTG93ZXJDYXNlKCkgIT09IFwiaW5wdXRcIiApIHsgLy8gZmluZCBmcm9tIGJ1dHRvbi9pbWFnZSB0cmlnZ2VyXG5cdFx0XHRpbnB1dCA9ICQoIFwiaW5wdXRcIiwgaW5wdXQucGFyZW50Tm9kZSApWyAwIF07XG5cdFx0fVxuXG5cdFx0aWYgKCAkLmRhdGVwaWNrZXIuX2lzRGlzYWJsZWREYXRlcGlja2VyKCBpbnB1dCApIHx8ICQuZGF0ZXBpY2tlci5fbGFzdElucHV0ID09PSBpbnB1dCApIHsgLy8gYWxyZWFkeSBoZXJlXG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIGluc3QsIGJlZm9yZVNob3csIGJlZm9yZVNob3dTZXR0aW5ncywgaXNGaXhlZCxcblx0XHRcdG9mZnNldCwgc2hvd0FuaW0sIGR1cmF0aW9uO1xuXG5cdFx0aW5zdCA9ICQuZGF0ZXBpY2tlci5fZ2V0SW5zdCggaW5wdXQgKTtcblx0XHRpZiAoICQuZGF0ZXBpY2tlci5fY3VySW5zdCAmJiAkLmRhdGVwaWNrZXIuX2N1ckluc3QgIT09IGluc3QgKSB7XG5cdFx0XHQkLmRhdGVwaWNrZXIuX2N1ckluc3QuZHBEaXYuc3RvcCggdHJ1ZSwgdHJ1ZSApO1xuXHRcdFx0aWYgKCBpbnN0ICYmICQuZGF0ZXBpY2tlci5fZGF0ZXBpY2tlclNob3dpbmcgKSB7XG5cdFx0XHRcdCQuZGF0ZXBpY2tlci5faGlkZURhdGVwaWNrZXIoICQuZGF0ZXBpY2tlci5fY3VySW5zdC5pbnB1dFsgMCBdICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0YmVmb3JlU2hvdyA9ICQuZGF0ZXBpY2tlci5fZ2V0KCBpbnN0LCBcImJlZm9yZVNob3dcIiApO1xuXHRcdGJlZm9yZVNob3dTZXR0aW5ncyA9IGJlZm9yZVNob3cgPyBiZWZvcmVTaG93LmFwcGx5KCBpbnB1dCwgWyBpbnB1dCwgaW5zdCBdICkgOiB7fTtcblx0XHRpZiAoIGJlZm9yZVNob3dTZXR0aW5ncyA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGRhdGVwaWNrZXJfZXh0ZW5kUmVtb3ZlKCBpbnN0LnNldHRpbmdzLCBiZWZvcmVTaG93U2V0dGluZ3MgKTtcblxuXHRcdGluc3QubGFzdFZhbCA9IG51bGw7XG5cdFx0JC5kYXRlcGlja2VyLl9sYXN0SW5wdXQgPSBpbnB1dDtcblx0XHQkLmRhdGVwaWNrZXIuX3NldERhdGVGcm9tRmllbGQoIGluc3QgKTtcblxuXHRcdGlmICggJC5kYXRlcGlja2VyLl9pbkRpYWxvZyApIHsgLy8gaGlkZSBjdXJzb3Jcblx0XHRcdGlucHV0LnZhbHVlID0gXCJcIjtcblx0XHR9XG5cdFx0aWYgKCAhJC5kYXRlcGlja2VyLl9wb3MgKSB7IC8vIHBvc2l0aW9uIGJlbG93IGlucHV0XG5cdFx0XHQkLmRhdGVwaWNrZXIuX3BvcyA9ICQuZGF0ZXBpY2tlci5fZmluZFBvcyggaW5wdXQgKTtcblx0XHRcdCQuZGF0ZXBpY2tlci5fcG9zWyAxIF0gKz0gaW5wdXQub2Zmc2V0SGVpZ2h0OyAvLyBhZGQgdGhlIGhlaWdodFxuXHRcdH1cblxuXHRcdGlzRml4ZWQgPSBmYWxzZTtcblx0XHQkKCBpbnB1dCApLnBhcmVudHMoKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdGlzRml4ZWQgfD0gJCggdGhpcyApLmNzcyggXCJwb3NpdGlvblwiICkgPT09IFwiZml4ZWRcIjtcblx0XHRcdHJldHVybiAhaXNGaXhlZDtcblx0XHR9ICk7XG5cblx0XHRvZmZzZXQgPSB7IGxlZnQ6ICQuZGF0ZXBpY2tlci5fcG9zWyAwIF0sIHRvcDogJC5kYXRlcGlja2VyLl9wb3NbIDEgXSB9O1xuXHRcdCQuZGF0ZXBpY2tlci5fcG9zID0gbnVsbDtcblxuXHRcdC8vdG8gYXZvaWQgZmxhc2hlcyBvbiBGaXJlZm94XG5cdFx0aW5zdC5kcERpdi5lbXB0eSgpO1xuXG5cdFx0Ly8gZGV0ZXJtaW5lIHNpemluZyBvZmZzY3JlZW5cblx0XHRpbnN0LmRwRGl2LmNzcyggeyBwb3NpdGlvbjogXCJhYnNvbHV0ZVwiLCBkaXNwbGF5OiBcImJsb2NrXCIsIHRvcDogXCItMTAwMHB4XCIgfSApO1xuXHRcdCQuZGF0ZXBpY2tlci5fdXBkYXRlRGF0ZXBpY2tlciggaW5zdCApO1xuXG5cdFx0Ly8gZml4IHdpZHRoIGZvciBkeW5hbWljIG51bWJlciBvZiBkYXRlIHBpY2tlcnNcblx0XHQvLyBhbmQgYWRqdXN0IHBvc2l0aW9uIGJlZm9yZSBzaG93aW5nXG5cdFx0b2Zmc2V0ID0gJC5kYXRlcGlja2VyLl9jaGVja09mZnNldCggaW5zdCwgb2Zmc2V0LCBpc0ZpeGVkICk7XG5cdFx0aW5zdC5kcERpdi5jc3MoIHsgcG9zaXRpb246ICggJC5kYXRlcGlja2VyLl9pbkRpYWxvZyAmJiAkLmJsb2NrVUkgP1xuXHRcdFx0XCJzdGF0aWNcIiA6ICggaXNGaXhlZCA/IFwiZml4ZWRcIiA6IFwiYWJzb2x1dGVcIiApICksIGRpc3BsYXk6IFwibm9uZVwiLFxuXHRcdFx0bGVmdDogb2Zmc2V0LmxlZnQgKyBcInB4XCIsIHRvcDogb2Zmc2V0LnRvcCArIFwicHhcIiB9ICk7XG5cblx0XHRpZiAoICFpbnN0LmlubGluZSApIHtcblx0XHRcdHNob3dBbmltID0gJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic2hvd0FuaW1cIiApO1xuXHRcdFx0ZHVyYXRpb24gPSAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJkdXJhdGlvblwiICk7XG5cdFx0XHRpbnN0LmRwRGl2LmNzcyggXCJ6LWluZGV4XCIsIGRhdGVwaWNrZXJfZ2V0WmluZGV4KCAkKCBpbnB1dCApICkgKyAxICk7XG5cdFx0XHQkLmRhdGVwaWNrZXIuX2RhdGVwaWNrZXJTaG93aW5nID0gdHJ1ZTtcblxuXHRcdFx0aWYgKCAkLmVmZmVjdHMgJiYgJC5lZmZlY3RzLmVmZmVjdFsgc2hvd0FuaW0gXSApIHtcblx0XHRcdFx0aW5zdC5kcERpdi5zaG93KCBzaG93QW5pbSwgJC5kYXRlcGlja2VyLl9nZXQoIGluc3QsIFwic2hvd09wdGlvbnNcIiApLCBkdXJhdGlvbiApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aW5zdC5kcERpdlsgc2hvd0FuaW0gfHwgXCJzaG93XCIgXSggc2hvd0FuaW0gPyBkdXJhdGlvbiA6IG51bGwgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCAkLmRhdGVwaWNrZXIuX3Nob3VsZEZvY3VzSW5wdXQoIGluc3QgKSApIHtcblx0XHRcdFx0aW5zdC5pbnB1dC50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdH1cblxuXHRcdFx0JC5kYXRlcGlja2VyLl9jdXJJbnN0ID0gaW5zdDtcblx0XHR9XG5cdH0sXG5cblx0LyogR2VuZXJhdGUgdGhlIGRhdGUgcGlja2VyIGNvbnRlbnQuICovXG5cdF91cGRhdGVEYXRlcGlja2VyOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHR0aGlzLm1heFJvd3MgPSA0OyAvL1Jlc2V0IHRoZSBtYXggbnVtYmVyIG9mIHJvd3MgYmVpbmcgZGlzcGxheWVkIChzZWUgIzcwNDMpXG5cdFx0ZGF0ZXBpY2tlcl9pbnN0QWN0aXZlID0gaW5zdDsgLy8gZm9yIGRlbGVnYXRlIGhvdmVyIGV2ZW50c1xuXHRcdGluc3QuZHBEaXYuZW1wdHkoKS5hcHBlbmQoIHRoaXMuX2dlbmVyYXRlSFRNTCggaW5zdCApICk7XG5cdFx0dGhpcy5fYXR0YWNoSGFuZGxlcnMoIGluc3QgKTtcblxuXHRcdHZhciBvcmlneWVhcnNodG1sLFxuXHRcdFx0bnVtTW9udGhzID0gdGhpcy5fZ2V0TnVtYmVyT2ZNb250aHMoIGluc3QgKSxcblx0XHRcdGNvbHMgPSBudW1Nb250aHNbIDEgXSxcblx0XHRcdHdpZHRoID0gMTcsXG5cdFx0XHRhY3RpdmVDZWxsID0gaW5zdC5kcERpdi5maW5kKCBcIi5cIiArIHRoaXMuX2RheU92ZXJDbGFzcyArIFwiIGFcIiApO1xuXG5cdFx0aWYgKCBhY3RpdmVDZWxsLmxlbmd0aCA+IDAgKSB7XG5cdFx0XHRkYXRlcGlja2VyX2hhbmRsZU1vdXNlb3Zlci5hcHBseSggYWN0aXZlQ2VsbC5nZXQoIDAgKSApO1xuXHRcdH1cblxuXHRcdGluc3QuZHBEaXYucmVtb3ZlQ2xhc3MoIFwidWktZGF0ZXBpY2tlci1tdWx0aS0yIHVpLWRhdGVwaWNrZXItbXVsdGktMyB1aS1kYXRlcGlja2VyLW11bHRpLTRcIiApLndpZHRoKCBcIlwiICk7XG5cdFx0aWYgKCBjb2xzID4gMSApIHtcblx0XHRcdGluc3QuZHBEaXYuYWRkQ2xhc3MoIFwidWktZGF0ZXBpY2tlci1tdWx0aS1cIiArIGNvbHMgKS5jc3MoIFwid2lkdGhcIiwgKCB3aWR0aCAqIGNvbHMgKSArIFwiZW1cIiApO1xuXHRcdH1cblx0XHRpbnN0LmRwRGl2WyAoIG51bU1vbnRoc1sgMCBdICE9PSAxIHx8IG51bU1vbnRoc1sgMSBdICE9PSAxID8gXCJhZGRcIiA6IFwicmVtb3ZlXCIgKSArXG5cdFx0XHRcIkNsYXNzXCIgXSggXCJ1aS1kYXRlcGlja2VyLW11bHRpXCIgKTtcblx0XHRpbnN0LmRwRGl2WyAoIHRoaXMuX2dldCggaW5zdCwgXCJpc1JUTFwiICkgPyBcImFkZFwiIDogXCJyZW1vdmVcIiApICtcblx0XHRcdFwiQ2xhc3NcIiBdKCBcInVpLWRhdGVwaWNrZXItcnRsXCIgKTtcblxuXHRcdGlmICggaW5zdCA9PT0gJC5kYXRlcGlja2VyLl9jdXJJbnN0ICYmICQuZGF0ZXBpY2tlci5fZGF0ZXBpY2tlclNob3dpbmcgJiYgJC5kYXRlcGlja2VyLl9zaG91bGRGb2N1c0lucHV0KCBpbnN0ICkgKSB7XG5cdFx0XHRpbnN0LmlucHV0LnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdH1cblxuXHRcdC8vIERlZmZlcmVkIHJlbmRlciBvZiB0aGUgeWVhcnMgc2VsZWN0ICh0byBhdm9pZCBmbGFzaGVzIG9uIEZpcmVmb3gpXG5cdFx0aWYgKCBpbnN0LnllYXJzaHRtbCApIHtcblx0XHRcdG9yaWd5ZWFyc2h0bWwgPSBpbnN0LnllYXJzaHRtbDtcblx0XHRcdHNldFRpbWVvdXQoIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRcdC8vYXNzdXJlIHRoYXQgaW5zdC55ZWFyc2h0bWwgZGlkbid0IGNoYW5nZS5cblx0XHRcdFx0aWYgKCBvcmlneWVhcnNodG1sID09PSBpbnN0LnllYXJzaHRtbCAmJiBpbnN0LnllYXJzaHRtbCApIHtcblx0XHRcdFx0XHRpbnN0LmRwRGl2LmZpbmQoIFwic2VsZWN0LnVpLWRhdGVwaWNrZXIteWVhcjpmaXJzdFwiICkucmVwbGFjZVdpdGgoIGluc3QueWVhcnNodG1sICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0b3JpZ3llYXJzaHRtbCA9IGluc3QueWVhcnNodG1sID0gbnVsbDtcblx0XHRcdH0sIDAgKTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gIzY2OTQgLSBkb24ndCBmb2N1cyB0aGUgaW5wdXQgaWYgaXQncyBhbHJlYWR5IGZvY3VzZWRcblx0Ly8gdGhpcyBicmVha3MgdGhlIGNoYW5nZSBldmVudCBpbiBJRVxuXHQvLyBTdXBwb3J0OiBJRSBhbmQgalF1ZXJ5IDwxLjlcblx0X3Nob3VsZEZvY3VzSW5wdXQ6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHJldHVybiBpbnN0LmlucHV0ICYmIGluc3QuaW5wdXQuaXMoIFwiOnZpc2libGVcIiApICYmICFpbnN0LmlucHV0LmlzKCBcIjpkaXNhYmxlZFwiICkgJiYgIWluc3QuaW5wdXQuaXMoIFwiOmZvY3VzXCIgKTtcblx0fSxcblxuXHQvKiBDaGVjayBwb3NpdGlvbmluZyB0byByZW1haW4gb24gc2NyZWVuLiAqL1xuXHRfY2hlY2tPZmZzZXQ6IGZ1bmN0aW9uKCBpbnN0LCBvZmZzZXQsIGlzRml4ZWQgKSB7XG5cdFx0dmFyIGRwV2lkdGggPSBpbnN0LmRwRGl2Lm91dGVyV2lkdGgoKSxcblx0XHRcdGRwSGVpZ2h0ID0gaW5zdC5kcERpdi5vdXRlckhlaWdodCgpLFxuXHRcdFx0aW5wdXRXaWR0aCA9IGluc3QuaW5wdXQgPyBpbnN0LmlucHV0Lm91dGVyV2lkdGgoKSA6IDAsXG5cdFx0XHRpbnB1dEhlaWdodCA9IGluc3QuaW5wdXQgPyBpbnN0LmlucHV0Lm91dGVySGVpZ2h0KCkgOiAwLFxuXHRcdFx0dmlld1dpZHRoID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudFdpZHRoICsgKCBpc0ZpeGVkID8gMCA6ICQoIGRvY3VtZW50ICkuc2Nyb2xsTGVmdCgpICksXG5cdFx0XHR2aWV3SGVpZ2h0ID0gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodCArICggaXNGaXhlZCA/IDAgOiAkKCBkb2N1bWVudCApLnNjcm9sbFRvcCgpICk7XG5cblx0XHRvZmZzZXQubGVmdCAtPSAoIHRoaXMuX2dldCggaW5zdCwgXCJpc1JUTFwiICkgPyAoIGRwV2lkdGggLSBpbnB1dFdpZHRoICkgOiAwICk7XG5cdFx0b2Zmc2V0LmxlZnQgLT0gKCBpc0ZpeGVkICYmIG9mZnNldC5sZWZ0ID09PSBpbnN0LmlucHV0Lm9mZnNldCgpLmxlZnQgKSA/ICQoIGRvY3VtZW50ICkuc2Nyb2xsTGVmdCgpIDogMDtcblx0XHRvZmZzZXQudG9wIC09ICggaXNGaXhlZCAmJiBvZmZzZXQudG9wID09PSAoIGluc3QuaW5wdXQub2Zmc2V0KCkudG9wICsgaW5wdXRIZWlnaHQgKSApID8gJCggZG9jdW1lbnQgKS5zY3JvbGxUb3AoKSA6IDA7XG5cblx0XHQvLyBOb3cgY2hlY2sgaWYgZGF0ZXBpY2tlciBpcyBzaG93aW5nIG91dHNpZGUgd2luZG93IHZpZXdwb3J0IC0gbW92ZSB0byBhIGJldHRlciBwbGFjZSBpZiBzby5cblx0XHRvZmZzZXQubGVmdCAtPSBNYXRoLm1pbiggb2Zmc2V0LmxlZnQsICggb2Zmc2V0LmxlZnQgKyBkcFdpZHRoID4gdmlld1dpZHRoICYmIHZpZXdXaWR0aCA+IGRwV2lkdGggKSA/XG5cdFx0XHRNYXRoLmFicyggb2Zmc2V0LmxlZnQgKyBkcFdpZHRoIC0gdmlld1dpZHRoICkgOiAwICk7XG5cdFx0b2Zmc2V0LnRvcCAtPSBNYXRoLm1pbiggb2Zmc2V0LnRvcCwgKCBvZmZzZXQudG9wICsgZHBIZWlnaHQgPiB2aWV3SGVpZ2h0ICYmIHZpZXdIZWlnaHQgPiBkcEhlaWdodCApID9cblx0XHRcdE1hdGguYWJzKCBkcEhlaWdodCArIGlucHV0SGVpZ2h0ICkgOiAwICk7XG5cblx0XHRyZXR1cm4gb2Zmc2V0O1xuXHR9LFxuXG5cdC8qIEZpbmQgYW4gb2JqZWN0J3MgcG9zaXRpb24gb24gdGhlIHNjcmVlbi4gKi9cblx0X2ZpbmRQb3M6IGZ1bmN0aW9uKCBvYmogKSB7XG5cdFx0dmFyIHBvc2l0aW9uLFxuXHRcdFx0aW5zdCA9IHRoaXMuX2dldEluc3QoIG9iaiApLFxuXHRcdFx0aXNSVEwgPSB0aGlzLl9nZXQoIGluc3QsIFwiaXNSVExcIiApO1xuXG5cdFx0d2hpbGUgKCBvYmogJiYgKCBvYmoudHlwZSA9PT0gXCJoaWRkZW5cIiB8fCBvYmoubm9kZVR5cGUgIT09IDEgfHwgJC5leHByLmZpbHRlcnMuaGlkZGVuKCBvYmogKSApICkge1xuXHRcdFx0b2JqID0gb2JqWyBpc1JUTCA/IFwicHJldmlvdXNTaWJsaW5nXCIgOiBcIm5leHRTaWJsaW5nXCIgXTtcblx0XHR9XG5cblx0XHRwb3NpdGlvbiA9ICQoIG9iaiApLm9mZnNldCgpO1xuXHRcdHJldHVybiBbIHBvc2l0aW9uLmxlZnQsIHBvc2l0aW9uLnRvcCBdO1xuXHR9LFxuXG5cdC8qIEhpZGUgdGhlIGRhdGUgcGlja2VyIGZyb20gdmlldy5cblx0ICogQHBhcmFtICBpbnB1dCAgZWxlbWVudCAtIHRoZSBpbnB1dCBmaWVsZCBhdHRhY2hlZCB0byB0aGUgZGF0ZSBwaWNrZXJcblx0ICovXG5cdF9oaWRlRGF0ZXBpY2tlcjogZnVuY3Rpb24oIGlucHV0ICkge1xuXHRcdHZhciBzaG93QW5pbSwgZHVyYXRpb24sIHBvc3RQcm9jZXNzLCBvbkNsb3NlLFxuXHRcdFx0aW5zdCA9IHRoaXMuX2N1ckluc3Q7XG5cblx0XHRpZiAoICFpbnN0IHx8ICggaW5wdXQgJiYgaW5zdCAhPT0gJC5kYXRhKCBpbnB1dCwgXCJkYXRlcGlja2VyXCIgKSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fZGF0ZXBpY2tlclNob3dpbmcgKSB7XG5cdFx0XHRzaG93QW5pbSA9IHRoaXMuX2dldCggaW5zdCwgXCJzaG93QW5pbVwiICk7XG5cdFx0XHRkdXJhdGlvbiA9IHRoaXMuX2dldCggaW5zdCwgXCJkdXJhdGlvblwiICk7XG5cdFx0XHRwb3N0UHJvY2VzcyA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHQkLmRhdGVwaWNrZXIuX3RpZHlEaWFsb2coIGluc3QgKTtcblx0XHRcdH07XG5cblx0XHRcdC8vIERFUFJFQ0FURUQ6IGFmdGVyIEJDIGZvciAxLjgueCAkLmVmZmVjdHNbIHNob3dBbmltIF0gaXMgbm90IG5lZWRlZFxuXHRcdFx0aWYgKCAkLmVmZmVjdHMgJiYgKCAkLmVmZmVjdHMuZWZmZWN0WyBzaG93QW5pbSBdIHx8ICQuZWZmZWN0c1sgc2hvd0FuaW0gXSApICkge1xuXHRcdFx0XHRpbnN0LmRwRGl2LmhpZGUoIHNob3dBbmltLCAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJzaG93T3B0aW9uc1wiICksIGR1cmF0aW9uLCBwb3N0UHJvY2VzcyApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aW5zdC5kcERpdlsgKCBzaG93QW5pbSA9PT0gXCJzbGlkZURvd25cIiA/IFwic2xpZGVVcFwiIDpcblx0XHRcdFx0XHQoIHNob3dBbmltID09PSBcImZhZGVJblwiID8gXCJmYWRlT3V0XCIgOiBcImhpZGVcIiApICkgXSggKCBzaG93QW5pbSA/IGR1cmF0aW9uIDogbnVsbCApLCBwb3N0UHJvY2VzcyApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICFzaG93QW5pbSApIHtcblx0XHRcdFx0cG9zdFByb2Nlc3MoKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuX2RhdGVwaWNrZXJTaG93aW5nID0gZmFsc2U7XG5cblx0XHRcdG9uQ2xvc2UgPSB0aGlzLl9nZXQoIGluc3QsIFwib25DbG9zZVwiICk7XG5cdFx0XHRpZiAoIG9uQ2xvc2UgKSB7XG5cdFx0XHRcdG9uQ2xvc2UuYXBwbHkoICggaW5zdC5pbnB1dCA/IGluc3QuaW5wdXRbIDAgXSA6IG51bGwgKSwgWyAoIGluc3QuaW5wdXQgPyBpbnN0LmlucHV0LnZhbCgpIDogXCJcIiApLCBpbnN0IF0gKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fbGFzdElucHV0ID0gbnVsbDtcblx0XHRcdGlmICggdGhpcy5faW5EaWFsb2cgKSB7XG5cdFx0XHRcdHRoaXMuX2RpYWxvZ0lucHV0LmNzcyggeyBwb3NpdGlvbjogXCJhYnNvbHV0ZVwiLCBsZWZ0OiBcIjBcIiwgdG9wOiBcIi0xMDBweFwiIH0gKTtcblx0XHRcdFx0aWYgKCAkLmJsb2NrVUkgKSB7XG5cdFx0XHRcdFx0JC51bmJsb2NrVUkoKTtcblx0XHRcdFx0XHQkKCBcImJvZHlcIiApLmFwcGVuZCggdGhpcy5kcERpdiApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9pbkRpYWxvZyA9IGZhbHNlO1xuXHRcdH1cblx0fSxcblxuXHQvKiBUaWR5IHVwIGFmdGVyIGEgZGlhbG9nIGRpc3BsYXkuICovXG5cdF90aWR5RGlhbG9nOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHRpbnN0LmRwRGl2LnJlbW92ZUNsYXNzKCB0aGlzLl9kaWFsb2dDbGFzcyApLm9mZiggXCIudWktZGF0ZXBpY2tlci1jYWxlbmRhclwiICk7XG5cdH0sXG5cblx0LyogQ2xvc2UgZGF0ZSBwaWNrZXIgaWYgY2xpY2tlZCBlbHNld2hlcmUuICovXG5cdF9jaGVja0V4dGVybmFsQ2xpY2s6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoICEkLmRhdGVwaWNrZXIuX2N1ckluc3QgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyICR0YXJnZXQgPSAkKCBldmVudC50YXJnZXQgKSxcblx0XHRcdGluc3QgPSAkLmRhdGVwaWNrZXIuX2dldEluc3QoICR0YXJnZXRbIDAgXSApO1xuXG5cdFx0aWYgKCAoICggJHRhcmdldFsgMCBdLmlkICE9PSAkLmRhdGVwaWNrZXIuX21haW5EaXZJZCAmJlxuXHRcdFx0XHQkdGFyZ2V0LnBhcmVudHMoIFwiI1wiICsgJC5kYXRlcGlja2VyLl9tYWluRGl2SWQgKS5sZW5ndGggPT09IDAgJiZcblx0XHRcdFx0ISR0YXJnZXQuaGFzQ2xhc3MoICQuZGF0ZXBpY2tlci5tYXJrZXJDbGFzc05hbWUgKSAmJlxuXHRcdFx0XHQhJHRhcmdldC5jbG9zZXN0KCBcIi5cIiArICQuZGF0ZXBpY2tlci5fdHJpZ2dlckNsYXNzICkubGVuZ3RoICYmXG5cdFx0XHRcdCQuZGF0ZXBpY2tlci5fZGF0ZXBpY2tlclNob3dpbmcgJiYgISggJC5kYXRlcGlja2VyLl9pbkRpYWxvZyAmJiAkLmJsb2NrVUkgKSApICkgfHxcblx0XHRcdCggJHRhcmdldC5oYXNDbGFzcyggJC5kYXRlcGlja2VyLm1hcmtlckNsYXNzTmFtZSApICYmICQuZGF0ZXBpY2tlci5fY3VySW5zdCAhPT0gaW5zdCApICkge1xuXHRcdFx0XHQkLmRhdGVwaWNrZXIuX2hpZGVEYXRlcGlja2VyKCk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIEFkanVzdCBvbmUgb2YgdGhlIGRhdGUgc3ViLWZpZWxkcy4gKi9cblx0X2FkanVzdERhdGU6IGZ1bmN0aW9uKCBpZCwgb2Zmc2V0LCBwZXJpb2QgKSB7XG5cdFx0dmFyIHRhcmdldCA9ICQoIGlkICksXG5cdFx0XHRpbnN0ID0gdGhpcy5fZ2V0SW5zdCggdGFyZ2V0WyAwIF0gKTtcblxuXHRcdGlmICggdGhpcy5faXNEaXNhYmxlZERhdGVwaWNrZXIoIHRhcmdldFsgMCBdICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdHRoaXMuX2FkanVzdEluc3REYXRlKCBpbnN0LCBvZmZzZXQgK1xuXHRcdFx0KCBwZXJpb2QgPT09IFwiTVwiID8gdGhpcy5fZ2V0KCBpbnN0LCBcInNob3dDdXJyZW50QXRQb3NcIiApIDogMCApLCAvLyB1bmRvIHBvc2l0aW9uaW5nXG5cdFx0XHRwZXJpb2QgKTtcblx0XHR0aGlzLl91cGRhdGVEYXRlcGlja2VyKCBpbnN0ICk7XG5cdH0sXG5cblx0LyogQWN0aW9uIGZvciBjdXJyZW50IGxpbmsuICovXG5cdF9nb3RvVG9kYXk6IGZ1bmN0aW9uKCBpZCApIHtcblx0XHR2YXIgZGF0ZSxcblx0XHRcdHRhcmdldCA9ICQoIGlkICksXG5cdFx0XHRpbnN0ID0gdGhpcy5fZ2V0SW5zdCggdGFyZ2V0WyAwIF0gKTtcblxuXHRcdGlmICggdGhpcy5fZ2V0KCBpbnN0LCBcImdvdG9DdXJyZW50XCIgKSAmJiBpbnN0LmN1cnJlbnREYXkgKSB7XG5cdFx0XHRpbnN0LnNlbGVjdGVkRGF5ID0gaW5zdC5jdXJyZW50RGF5O1xuXHRcdFx0aW5zdC5kcmF3TW9udGggPSBpbnN0LnNlbGVjdGVkTW9udGggPSBpbnN0LmN1cnJlbnRNb250aDtcblx0XHRcdGluc3QuZHJhd1llYXIgPSBpbnN0LnNlbGVjdGVkWWVhciA9IGluc3QuY3VycmVudFllYXI7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGRhdGUgPSBuZXcgRGF0ZSgpO1xuXHRcdFx0aW5zdC5zZWxlY3RlZERheSA9IGRhdGUuZ2V0RGF0ZSgpO1xuXHRcdFx0aW5zdC5kcmF3TW9udGggPSBpbnN0LnNlbGVjdGVkTW9udGggPSBkYXRlLmdldE1vbnRoKCk7XG5cdFx0XHRpbnN0LmRyYXdZZWFyID0gaW5zdC5zZWxlY3RlZFllYXIgPSBkYXRlLmdldEZ1bGxZZWFyKCk7XG5cdFx0fVxuXHRcdHRoaXMuX25vdGlmeUNoYW5nZSggaW5zdCApO1xuXHRcdHRoaXMuX2FkanVzdERhdGUoIHRhcmdldCApO1xuXHR9LFxuXG5cdC8qIEFjdGlvbiBmb3Igc2VsZWN0aW5nIGEgbmV3IG1vbnRoL3llYXIuICovXG5cdF9zZWxlY3RNb250aFllYXI6IGZ1bmN0aW9uKCBpZCwgc2VsZWN0LCBwZXJpb2QgKSB7XG5cdFx0dmFyIHRhcmdldCA9ICQoIGlkICksXG5cdFx0XHRpbnN0ID0gdGhpcy5fZ2V0SW5zdCggdGFyZ2V0WyAwIF0gKTtcblxuXHRcdGluc3RbIFwic2VsZWN0ZWRcIiArICggcGVyaW9kID09PSBcIk1cIiA/IFwiTW9udGhcIiA6IFwiWWVhclwiICkgXSA9XG5cdFx0aW5zdFsgXCJkcmF3XCIgKyAoIHBlcmlvZCA9PT0gXCJNXCIgPyBcIk1vbnRoXCIgOiBcIlllYXJcIiApIF0gPVxuXHRcdFx0cGFyc2VJbnQoIHNlbGVjdC5vcHRpb25zWyBzZWxlY3Quc2VsZWN0ZWRJbmRleCBdLnZhbHVlLCAxMCApO1xuXG5cdFx0dGhpcy5fbm90aWZ5Q2hhbmdlKCBpbnN0ICk7XG5cdFx0dGhpcy5fYWRqdXN0RGF0ZSggdGFyZ2V0ICk7XG5cdH0sXG5cblx0LyogQWN0aW9uIGZvciBzZWxlY3RpbmcgYSBkYXkuICovXG5cdF9zZWxlY3REYXk6IGZ1bmN0aW9uKCBpZCwgbW9udGgsIHllYXIsIHRkICkge1xuXHRcdHZhciBpbnN0LFxuXHRcdFx0dGFyZ2V0ID0gJCggaWQgKTtcblxuXHRcdGlmICggJCggdGQgKS5oYXNDbGFzcyggdGhpcy5fdW5zZWxlY3RhYmxlQ2xhc3MgKSB8fCB0aGlzLl9pc0Rpc2FibGVkRGF0ZXBpY2tlciggdGFyZ2V0WyAwIF0gKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpbnN0ID0gdGhpcy5fZ2V0SW5zdCggdGFyZ2V0WyAwIF0gKTtcblx0XHRpbnN0LnNlbGVjdGVkRGF5ID0gaW5zdC5jdXJyZW50RGF5ID0gJCggXCJhXCIsIHRkICkuaHRtbCgpO1xuXHRcdGluc3Quc2VsZWN0ZWRNb250aCA9IGluc3QuY3VycmVudE1vbnRoID0gbW9udGg7XG5cdFx0aW5zdC5zZWxlY3RlZFllYXIgPSBpbnN0LmN1cnJlbnRZZWFyID0geWVhcjtcblx0XHR0aGlzLl9zZWxlY3REYXRlKCBpZCwgdGhpcy5fZm9ybWF0RGF0ZSggaW5zdCxcblx0XHRcdGluc3QuY3VycmVudERheSwgaW5zdC5jdXJyZW50TW9udGgsIGluc3QuY3VycmVudFllYXIgKSApO1xuXHR9LFxuXG5cdC8qIEVyYXNlIHRoZSBpbnB1dCBmaWVsZCBhbmQgaGlkZSB0aGUgZGF0ZSBwaWNrZXIuICovXG5cdF9jbGVhckRhdGU6IGZ1bmN0aW9uKCBpZCApIHtcblx0XHR2YXIgdGFyZ2V0ID0gJCggaWQgKTtcblx0XHR0aGlzLl9zZWxlY3REYXRlKCB0YXJnZXQsIFwiXCIgKTtcblx0fSxcblxuXHQvKiBVcGRhdGUgdGhlIGlucHV0IGZpZWxkIHdpdGggdGhlIHNlbGVjdGVkIGRhdGUuICovXG5cdF9zZWxlY3REYXRlOiBmdW5jdGlvbiggaWQsIGRhdGVTdHIgKSB7XG5cdFx0dmFyIG9uU2VsZWN0LFxuXHRcdFx0dGFyZ2V0ID0gJCggaWQgKSxcblx0XHRcdGluc3QgPSB0aGlzLl9nZXRJbnN0KCB0YXJnZXRbIDAgXSApO1xuXG5cdFx0ZGF0ZVN0ciA9ICggZGF0ZVN0ciAhPSBudWxsID8gZGF0ZVN0ciA6IHRoaXMuX2Zvcm1hdERhdGUoIGluc3QgKSApO1xuXHRcdGlmICggaW5zdC5pbnB1dCApIHtcblx0XHRcdGluc3QuaW5wdXQudmFsKCBkYXRlU3RyICk7XG5cdFx0fVxuXHRcdHRoaXMuX3VwZGF0ZUFsdGVybmF0ZSggaW5zdCApO1xuXG5cdFx0b25TZWxlY3QgPSB0aGlzLl9nZXQoIGluc3QsIFwib25TZWxlY3RcIiApO1xuXHRcdGlmICggb25TZWxlY3QgKSB7XG5cdFx0XHRvblNlbGVjdC5hcHBseSggKCBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dFsgMCBdIDogbnVsbCApLCBbIGRhdGVTdHIsIGluc3QgXSApOyAgLy8gdHJpZ2dlciBjdXN0b20gY2FsbGJhY2tcblx0XHR9IGVsc2UgaWYgKCBpbnN0LmlucHV0ICkge1xuXHRcdFx0aW5zdC5pbnB1dC50cmlnZ2VyKCBcImNoYW5nZVwiICk7IC8vIGZpcmUgdGhlIGNoYW5nZSBldmVudFxuXHRcdH1cblxuXHRcdGlmICggaW5zdC5pbmxpbmUgKSB7XG5cdFx0XHR0aGlzLl91cGRhdGVEYXRlcGlja2VyKCBpbnN0ICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX2hpZGVEYXRlcGlja2VyKCk7XG5cdFx0XHR0aGlzLl9sYXN0SW5wdXQgPSBpbnN0LmlucHV0WyAwIF07XG5cdFx0XHRpZiAoIHR5cGVvZiggaW5zdC5pbnB1dFsgMCBdICkgIT09IFwib2JqZWN0XCIgKSB7XG5cdFx0XHRcdGluc3QuaW5wdXQudHJpZ2dlciggXCJmb2N1c1wiICk7IC8vIHJlc3RvcmUgZm9jdXNcblx0XHRcdH1cblx0XHRcdHRoaXMuX2xhc3RJbnB1dCA9IG51bGw7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIFVwZGF0ZSBhbnkgYWx0ZXJuYXRlIGZpZWxkIHRvIHN5bmNocm9uaXNlIHdpdGggdGhlIG1haW4gZmllbGQuICovXG5cdF91cGRhdGVBbHRlcm5hdGU6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHZhciBhbHRGb3JtYXQsIGRhdGUsIGRhdGVTdHIsXG5cdFx0XHRhbHRGaWVsZCA9IHRoaXMuX2dldCggaW5zdCwgXCJhbHRGaWVsZFwiICk7XG5cblx0XHRpZiAoIGFsdEZpZWxkICkgeyAvLyB1cGRhdGUgYWx0ZXJuYXRlIGZpZWxkIHRvb1xuXHRcdFx0YWx0Rm9ybWF0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcImFsdEZvcm1hdFwiICkgfHwgdGhpcy5fZ2V0KCBpbnN0LCBcImRhdGVGb3JtYXRcIiApO1xuXHRcdFx0ZGF0ZSA9IHRoaXMuX2dldERhdGUoIGluc3QgKTtcblx0XHRcdGRhdGVTdHIgPSB0aGlzLmZvcm1hdERhdGUoIGFsdEZvcm1hdCwgZGF0ZSwgdGhpcy5fZ2V0Rm9ybWF0Q29uZmlnKCBpbnN0ICkgKTtcblx0XHRcdCQoIGFsdEZpZWxkICkudmFsKCBkYXRlU3RyICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIFNldCBhcyBiZWZvcmVTaG93RGF5IGZ1bmN0aW9uIHRvIHByZXZlbnQgc2VsZWN0aW9uIG9mIHdlZWtlbmRzLlxuXHQgKiBAcGFyYW0gIGRhdGUgIERhdGUgLSB0aGUgZGF0ZSB0byBjdXN0b21pc2Vcblx0ICogQHJldHVybiBbYm9vbGVhbiwgc3RyaW5nXSAtIGlzIHRoaXMgZGF0ZSBzZWxlY3RhYmxlPywgd2hhdCBpcyBpdHMgQ1NTIGNsYXNzP1xuXHQgKi9cblx0bm9XZWVrZW5kczogZnVuY3Rpb24oIGRhdGUgKSB7XG5cdFx0dmFyIGRheSA9IGRhdGUuZ2V0RGF5KCk7XG5cdFx0cmV0dXJuIFsgKCBkYXkgPiAwICYmIGRheSA8IDYgKSwgXCJcIiBdO1xuXHR9LFxuXG5cdC8qIFNldCBhcyBjYWxjdWxhdGVXZWVrIHRvIGRldGVybWluZSB0aGUgd2VlayBvZiB0aGUgeWVhciBiYXNlZCBvbiB0aGUgSVNPIDg2MDEgZGVmaW5pdGlvbi5cblx0ICogQHBhcmFtICBkYXRlICBEYXRlIC0gdGhlIGRhdGUgdG8gZ2V0IHRoZSB3ZWVrIGZvclxuXHQgKiBAcmV0dXJuICBudW1iZXIgLSB0aGUgbnVtYmVyIG9mIHRoZSB3ZWVrIHdpdGhpbiB0aGUgeWVhciB0aGF0IGNvbnRhaW5zIHRoaXMgZGF0ZVxuXHQgKi9cblx0aXNvODYwMVdlZWs6IGZ1bmN0aW9uKCBkYXRlICkge1xuXHRcdHZhciB0aW1lLFxuXHRcdFx0Y2hlY2tEYXRlID0gbmV3IERhdGUoIGRhdGUuZ2V0VGltZSgpICk7XG5cblx0XHQvLyBGaW5kIFRodXJzZGF5IG9mIHRoaXMgd2VlayBzdGFydGluZyBvbiBNb25kYXlcblx0XHRjaGVja0RhdGUuc2V0RGF0ZSggY2hlY2tEYXRlLmdldERhdGUoKSArIDQgLSAoIGNoZWNrRGF0ZS5nZXREYXkoKSB8fCA3ICkgKTtcblxuXHRcdHRpbWUgPSBjaGVja0RhdGUuZ2V0VGltZSgpO1xuXHRcdGNoZWNrRGF0ZS5zZXRNb250aCggMCApOyAvLyBDb21wYXJlIHdpdGggSmFuIDFcblx0XHRjaGVja0RhdGUuc2V0RGF0ZSggMSApO1xuXHRcdHJldHVybiBNYXRoLmZsb29yKCBNYXRoLnJvdW5kKCAoIHRpbWUgLSBjaGVja0RhdGUgKSAvIDg2NDAwMDAwICkgLyA3ICkgKyAxO1xuXHR9LFxuXG5cdC8qIFBhcnNlIGEgc3RyaW5nIHZhbHVlIGludG8gYSBkYXRlIG9iamVjdC5cblx0ICogU2VlIGZvcm1hdERhdGUgYmVsb3cgZm9yIHRoZSBwb3NzaWJsZSBmb3JtYXRzLlxuXHQgKlxuXHQgKiBAcGFyYW0gIGZvcm1hdCBzdHJpbmcgLSB0aGUgZXhwZWN0ZWQgZm9ybWF0IG9mIHRoZSBkYXRlXG5cdCAqIEBwYXJhbSAgdmFsdWUgc3RyaW5nIC0gdGhlIGRhdGUgaW4gdGhlIGFib3ZlIGZvcm1hdFxuXHQgKiBAcGFyYW0gIHNldHRpbmdzIE9iamVjdCAtIGF0dHJpYnV0ZXMgaW5jbHVkZTpcblx0ICpcdFx0XHRcdFx0c2hvcnRZZWFyQ3V0b2ZmICBudW1iZXIgLSB0aGUgY3V0b2ZmIHllYXIgZm9yIGRldGVybWluaW5nIHRoZSBjZW50dXJ5IChvcHRpb25hbClcblx0ICpcdFx0XHRcdFx0ZGF5TmFtZXNTaG9ydFx0c3RyaW5nWzddIC0gYWJicmV2aWF0ZWQgbmFtZXMgb2YgdGhlIGRheXMgZnJvbSBTdW5kYXkgKG9wdGlvbmFsKVxuXHQgKlx0XHRcdFx0XHRkYXlOYW1lc1x0XHRzdHJpbmdbN10gLSBuYW1lcyBvZiB0aGUgZGF5cyBmcm9tIFN1bmRheSAob3B0aW9uYWwpXG5cdCAqXHRcdFx0XHRcdG1vbnRoTmFtZXNTaG9ydCBzdHJpbmdbMTJdIC0gYWJicmV2aWF0ZWQgbmFtZXMgb2YgdGhlIG1vbnRocyAob3B0aW9uYWwpXG5cdCAqXHRcdFx0XHRcdG1vbnRoTmFtZXNcdFx0c3RyaW5nWzEyXSAtIG5hbWVzIG9mIHRoZSBtb250aHMgKG9wdGlvbmFsKVxuXHQgKiBAcmV0dXJuICBEYXRlIC0gdGhlIGV4dHJhY3RlZCBkYXRlIHZhbHVlIG9yIG51bGwgaWYgdmFsdWUgaXMgYmxhbmtcblx0ICovXG5cdHBhcnNlRGF0ZTogZnVuY3Rpb24oIGZvcm1hdCwgdmFsdWUsIHNldHRpbmdzICkge1xuXHRcdGlmICggZm9ybWF0ID09IG51bGwgfHwgdmFsdWUgPT0gbnVsbCApIHtcblx0XHRcdHRocm93IFwiSW52YWxpZCBhcmd1bWVudHNcIjtcblx0XHR9XG5cblx0XHR2YWx1ZSA9ICggdHlwZW9mIHZhbHVlID09PSBcIm9iamVjdFwiID8gdmFsdWUudG9TdHJpbmcoKSA6IHZhbHVlICsgXCJcIiApO1xuXHRcdGlmICggdmFsdWUgPT09IFwiXCIgKSB7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblx0XHR9XG5cblx0XHR2YXIgaUZvcm1hdCwgZGltLCBleHRyYSxcblx0XHRcdGlWYWx1ZSA9IDAsXG5cdFx0XHRzaG9ydFllYXJDdXRvZmZUZW1wID0gKCBzZXR0aW5ncyA/IHNldHRpbmdzLnNob3J0WWVhckN1dG9mZiA6IG51bGwgKSB8fCB0aGlzLl9kZWZhdWx0cy5zaG9ydFllYXJDdXRvZmYsXG5cdFx0XHRzaG9ydFllYXJDdXRvZmYgPSAoIHR5cGVvZiBzaG9ydFllYXJDdXRvZmZUZW1wICE9PSBcInN0cmluZ1wiID8gc2hvcnRZZWFyQ3V0b2ZmVGVtcCA6XG5cdFx0XHRcdG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKSAlIDEwMCArIHBhcnNlSW50KCBzaG9ydFllYXJDdXRvZmZUZW1wLCAxMCApICksXG5cdFx0XHRkYXlOYW1lc1Nob3J0ID0gKCBzZXR0aW5ncyA/IHNldHRpbmdzLmRheU5hbWVzU2hvcnQgOiBudWxsICkgfHwgdGhpcy5fZGVmYXVsdHMuZGF5TmFtZXNTaG9ydCxcblx0XHRcdGRheU5hbWVzID0gKCBzZXR0aW5ncyA/IHNldHRpbmdzLmRheU5hbWVzIDogbnVsbCApIHx8IHRoaXMuX2RlZmF1bHRzLmRheU5hbWVzLFxuXHRcdFx0bW9udGhOYW1lc1Nob3J0ID0gKCBzZXR0aW5ncyA/IHNldHRpbmdzLm1vbnRoTmFtZXNTaG9ydCA6IG51bGwgKSB8fCB0aGlzLl9kZWZhdWx0cy5tb250aE5hbWVzU2hvcnQsXG5cdFx0XHRtb250aE5hbWVzID0gKCBzZXR0aW5ncyA/IHNldHRpbmdzLm1vbnRoTmFtZXMgOiBudWxsICkgfHwgdGhpcy5fZGVmYXVsdHMubW9udGhOYW1lcyxcblx0XHRcdHllYXIgPSAtMSxcblx0XHRcdG1vbnRoID0gLTEsXG5cdFx0XHRkYXkgPSAtMSxcblx0XHRcdGRveSA9IC0xLFxuXHRcdFx0bGl0ZXJhbCA9IGZhbHNlLFxuXHRcdFx0ZGF0ZSxcblxuXHRcdFx0Ly8gQ2hlY2sgd2hldGhlciBhIGZvcm1hdCBjaGFyYWN0ZXIgaXMgZG91YmxlZFxuXHRcdFx0bG9va0FoZWFkID0gZnVuY3Rpb24oIG1hdGNoICkge1xuXHRcdFx0XHR2YXIgbWF0Y2hlcyA9ICggaUZvcm1hdCArIDEgPCBmb3JtYXQubGVuZ3RoICYmIGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKyAxICkgPT09IG1hdGNoICk7XG5cdFx0XHRcdGlmICggbWF0Y2hlcyApIHtcblx0XHRcdFx0XHRpRm9ybWF0Kys7XG5cdFx0XHRcdH1cblx0XHRcdFx0cmV0dXJuIG1hdGNoZXM7XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBFeHRyYWN0IGEgbnVtYmVyIGZyb20gdGhlIHN0cmluZyB2YWx1ZVxuXHRcdFx0Z2V0TnVtYmVyID0gZnVuY3Rpb24oIG1hdGNoICkge1xuXHRcdFx0XHR2YXIgaXNEb3VibGVkID0gbG9va0FoZWFkKCBtYXRjaCApLFxuXHRcdFx0XHRcdHNpemUgPSAoIG1hdGNoID09PSBcIkBcIiA/IDE0IDogKCBtYXRjaCA9PT0gXCIhXCIgPyAyMCA6XG5cdFx0XHRcdFx0KCBtYXRjaCA9PT0gXCJ5XCIgJiYgaXNEb3VibGVkID8gNCA6ICggbWF0Y2ggPT09IFwib1wiID8gMyA6IDIgKSApICkgKSxcblx0XHRcdFx0XHRtaW5TaXplID0gKCBtYXRjaCA9PT0gXCJ5XCIgPyBzaXplIDogMSApLFxuXHRcdFx0XHRcdGRpZ2l0cyA9IG5ldyBSZWdFeHAoIFwiXlxcXFxke1wiICsgbWluU2l6ZSArIFwiLFwiICsgc2l6ZSArIFwifVwiICksXG5cdFx0XHRcdFx0bnVtID0gdmFsdWUuc3Vic3RyaW5nKCBpVmFsdWUgKS5tYXRjaCggZGlnaXRzICk7XG5cdFx0XHRcdGlmICggIW51bSApIHtcblx0XHRcdFx0XHR0aHJvdyBcIk1pc3NpbmcgbnVtYmVyIGF0IHBvc2l0aW9uIFwiICsgaVZhbHVlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlWYWx1ZSArPSBudW1bIDAgXS5sZW5ndGg7XG5cdFx0XHRcdHJldHVybiBwYXJzZUludCggbnVtWyAwIF0sIDEwICk7XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBFeHRyYWN0IGEgbmFtZSBmcm9tIHRoZSBzdHJpbmcgdmFsdWUgYW5kIGNvbnZlcnQgdG8gYW4gaW5kZXhcblx0XHRcdGdldE5hbWUgPSBmdW5jdGlvbiggbWF0Y2gsIHNob3J0TmFtZXMsIGxvbmdOYW1lcyApIHtcblx0XHRcdFx0dmFyIGluZGV4ID0gLTEsXG5cdFx0XHRcdFx0bmFtZXMgPSAkLm1hcCggbG9va0FoZWFkKCBtYXRjaCApID8gbG9uZ05hbWVzIDogc2hvcnROYW1lcywgZnVuY3Rpb24oIHYsIGsgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gWyBbIGssIHYgXSBdO1xuXHRcdFx0XHRcdH0gKS5zb3J0KCBmdW5jdGlvbiggYSwgYiApIHtcblx0XHRcdFx0XHRcdHJldHVybiAtKCBhWyAxIF0ubGVuZ3RoIC0gYlsgMSBdLmxlbmd0aCApO1xuXHRcdFx0XHRcdH0gKTtcblxuXHRcdFx0XHQkLmVhY2goIG5hbWVzLCBmdW5jdGlvbiggaSwgcGFpciApIHtcblx0XHRcdFx0XHR2YXIgbmFtZSA9IHBhaXJbIDEgXTtcblx0XHRcdFx0XHRpZiAoIHZhbHVlLnN1YnN0ciggaVZhbHVlLCBuYW1lLmxlbmd0aCApLnRvTG93ZXJDYXNlKCkgPT09IG5hbWUudG9Mb3dlckNhc2UoKSApIHtcblx0XHRcdFx0XHRcdGluZGV4ID0gcGFpclsgMCBdO1xuXHRcdFx0XHRcdFx0aVZhbHVlICs9IG5hbWUubGVuZ3RoO1xuXHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0XHRpZiAoIGluZGV4ICE9PSAtMSApIHtcblx0XHRcdFx0XHRyZXR1cm4gaW5kZXggKyAxO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRocm93IFwiVW5rbm93biBuYW1lIGF0IHBvc2l0aW9uIFwiICsgaVZhbHVlO1xuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXG5cdFx0XHQvLyBDb25maXJtIHRoYXQgYSBsaXRlcmFsIGNoYXJhY3RlciBtYXRjaGVzIHRoZSBzdHJpbmcgdmFsdWVcblx0XHRcdGNoZWNrTGl0ZXJhbCA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIHZhbHVlLmNoYXJBdCggaVZhbHVlICkgIT09IGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKSApIHtcblx0XHRcdFx0XHR0aHJvdyBcIlVuZXhwZWN0ZWQgbGl0ZXJhbCBhdCBwb3NpdGlvbiBcIiArIGlWYWx1ZTtcblx0XHRcdFx0fVxuXHRcdFx0XHRpVmFsdWUrKztcblx0XHRcdH07XG5cblx0XHRmb3IgKCBpRm9ybWF0ID0gMDsgaUZvcm1hdCA8IGZvcm1hdC5sZW5ndGg7IGlGb3JtYXQrKyApIHtcblx0XHRcdGlmICggbGl0ZXJhbCApIHtcblx0XHRcdFx0aWYgKCBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICkgPT09IFwiJ1wiICYmICFsb29rQWhlYWQoIFwiJ1wiICkgKSB7XG5cdFx0XHRcdFx0bGl0ZXJhbCA9IGZhbHNlO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGNoZWNrTGl0ZXJhbCgpO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRzd2l0Y2ggKCBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICkgKSB7XG5cdFx0XHRcdFx0Y2FzZSBcImRcIjpcblx0XHRcdFx0XHRcdGRheSA9IGdldE51bWJlciggXCJkXCIgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgXCJEXCI6XG5cdFx0XHRcdFx0XHRnZXROYW1lKCBcIkRcIiwgZGF5TmFtZXNTaG9ydCwgZGF5TmFtZXMgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgXCJvXCI6XG5cdFx0XHRcdFx0XHRkb3kgPSBnZXROdW1iZXIoIFwib1wiICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlIFwibVwiOlxuXHRcdFx0XHRcdFx0bW9udGggPSBnZXROdW1iZXIoIFwibVwiICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlIFwiTVwiOlxuXHRcdFx0XHRcdFx0bW9udGggPSBnZXROYW1lKCBcIk1cIiwgbW9udGhOYW1lc1Nob3J0LCBtb250aE5hbWVzICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRjYXNlIFwieVwiOlxuXHRcdFx0XHRcdFx0eWVhciA9IGdldE51bWJlciggXCJ5XCIgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgXCJAXCI6XG5cdFx0XHRcdFx0XHRkYXRlID0gbmV3IERhdGUoIGdldE51bWJlciggXCJAXCIgKSApO1xuXHRcdFx0XHRcdFx0eWVhciA9IGRhdGUuZ2V0RnVsbFllYXIoKTtcblx0XHRcdFx0XHRcdG1vbnRoID0gZGF0ZS5nZXRNb250aCgpICsgMTtcblx0XHRcdFx0XHRcdGRheSA9IGRhdGUuZ2V0RGF0ZSgpO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0Y2FzZSBcIiFcIjpcblx0XHRcdFx0XHRcdGRhdGUgPSBuZXcgRGF0ZSggKCBnZXROdW1iZXIoIFwiIVwiICkgLSB0aGlzLl90aWNrc1RvMTk3MCApIC8gMTAwMDAgKTtcblx0XHRcdFx0XHRcdHllYXIgPSBkYXRlLmdldEZ1bGxZZWFyKCk7XG5cdFx0XHRcdFx0XHRtb250aCA9IGRhdGUuZ2V0TW9udGgoKSArIDE7XG5cdFx0XHRcdFx0XHRkYXkgPSBkYXRlLmdldERhdGUoKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGNhc2UgXCInXCI6XG5cdFx0XHRcdFx0XHRpZiAoIGxvb2tBaGVhZCggXCInXCIgKSApIHtcblx0XHRcdFx0XHRcdFx0Y2hlY2tMaXRlcmFsKCk7XG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0XHRsaXRlcmFsID0gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0XHRjaGVja0xpdGVyYWwoKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggaVZhbHVlIDwgdmFsdWUubGVuZ3RoICkge1xuXHRcdFx0ZXh0cmEgPSB2YWx1ZS5zdWJzdHIoIGlWYWx1ZSApO1xuXHRcdFx0aWYgKCAhL15cXHMrLy50ZXN0KCBleHRyYSApICkge1xuXHRcdFx0XHR0aHJvdyBcIkV4dHJhL3VucGFyc2VkIGNoYXJhY3RlcnMgZm91bmQgaW4gZGF0ZTogXCIgKyBleHRyYTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoIHllYXIgPT09IC0xICkge1xuXHRcdFx0eWVhciA9IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKTtcblx0XHR9IGVsc2UgaWYgKCB5ZWFyIDwgMTAwICkge1xuXHRcdFx0eWVhciArPSBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCkgLSBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCkgJSAxMDAgK1xuXHRcdFx0XHQoIHllYXIgPD0gc2hvcnRZZWFyQ3V0b2ZmID8gMCA6IC0xMDAgKTtcblx0XHR9XG5cblx0XHRpZiAoIGRveSA+IC0xICkge1xuXHRcdFx0bW9udGggPSAxO1xuXHRcdFx0ZGF5ID0gZG95O1xuXHRcdFx0ZG8ge1xuXHRcdFx0XHRkaW0gPSB0aGlzLl9nZXREYXlzSW5Nb250aCggeWVhciwgbW9udGggLSAxICk7XG5cdFx0XHRcdGlmICggZGF5IDw9IGRpbSApIHtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0fVxuXHRcdFx0XHRtb250aCsrO1xuXHRcdFx0XHRkYXkgLT0gZGltO1xuXHRcdFx0fSB3aGlsZSAoIHRydWUgKTtcblx0XHR9XG5cblx0XHRkYXRlID0gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCB5ZWFyLCBtb250aCAtIDEsIGRheSApICk7XG5cdFx0aWYgKCBkYXRlLmdldEZ1bGxZZWFyKCkgIT09IHllYXIgfHwgZGF0ZS5nZXRNb250aCgpICsgMSAhPT0gbW9udGggfHwgZGF0ZS5nZXREYXRlKCkgIT09IGRheSApIHtcblx0XHRcdHRocm93IFwiSW52YWxpZCBkYXRlXCI7IC8vIEUuZy4gMzEvMDIvMDBcblx0XHR9XG5cdFx0cmV0dXJuIGRhdGU7XG5cdH0sXG5cblx0LyogU3RhbmRhcmQgZGF0ZSBmb3JtYXRzLiAqL1xuXHRBVE9NOiBcInl5LW1tLWRkXCIsIC8vIFJGQyAzMzM5IChJU08gODYwMSlcblx0Q09PS0lFOiBcIkQsIGRkIE0geXlcIixcblx0SVNPXzg2MDE6IFwieXktbW0tZGRcIixcblx0UkZDXzgyMjogXCJELCBkIE0geVwiLFxuXHRSRkNfODUwOiBcIkRELCBkZC1NLXlcIixcblx0UkZDXzEwMzY6IFwiRCwgZCBNIHlcIixcblx0UkZDXzExMjM6IFwiRCwgZCBNIHl5XCIsXG5cdFJGQ18yODIyOiBcIkQsIGQgTSB5eVwiLFxuXHRSU1M6IFwiRCwgZCBNIHlcIiwgLy8gUkZDIDgyMlxuXHRUSUNLUzogXCIhXCIsXG5cdFRJTUVTVEFNUDogXCJAXCIsXG5cdFczQzogXCJ5eS1tbS1kZFwiLCAvLyBJU08gODYwMVxuXG5cdF90aWNrc1RvMTk3MDogKCAoICggMTk3MCAtIDEgKSAqIDM2NSArIE1hdGguZmxvb3IoIDE5NzAgLyA0ICkgLSBNYXRoLmZsb29yKCAxOTcwIC8gMTAwICkgK1xuXHRcdE1hdGguZmxvb3IoIDE5NzAgLyA0MDAgKSApICogMjQgKiA2MCAqIDYwICogMTAwMDAwMDAgKSxcblxuXHQvKiBGb3JtYXQgYSBkYXRlIG9iamVjdCBpbnRvIGEgc3RyaW5nIHZhbHVlLlxuXHQgKiBUaGUgZm9ybWF0IGNhbiBiZSBjb21iaW5hdGlvbnMgb2YgdGhlIGZvbGxvd2luZzpcblx0ICogZCAgLSBkYXkgb2YgbW9udGggKG5vIGxlYWRpbmcgemVybylcblx0ICogZGQgLSBkYXkgb2YgbW9udGggKHR3byBkaWdpdClcblx0ICogbyAgLSBkYXkgb2YgeWVhciAobm8gbGVhZGluZyB6ZXJvcylcblx0ICogb28gLSBkYXkgb2YgeWVhciAodGhyZWUgZGlnaXQpXG5cdCAqIEQgIC0gZGF5IG5hbWUgc2hvcnRcblx0ICogREQgLSBkYXkgbmFtZSBsb25nXG5cdCAqIG0gIC0gbW9udGggb2YgeWVhciAobm8gbGVhZGluZyB6ZXJvKVxuXHQgKiBtbSAtIG1vbnRoIG9mIHllYXIgKHR3byBkaWdpdClcblx0ICogTSAgLSBtb250aCBuYW1lIHNob3J0XG5cdCAqIE1NIC0gbW9udGggbmFtZSBsb25nXG5cdCAqIHkgIC0geWVhciAodHdvIGRpZ2l0KVxuXHQgKiB5eSAtIHllYXIgKGZvdXIgZGlnaXQpXG5cdCAqIEAgLSBVbml4IHRpbWVzdGFtcCAobXMgc2luY2UgMDEvMDEvMTk3MClcblx0ICogISAtIFdpbmRvd3MgdGlja3MgKDEwMG5zIHNpbmNlIDAxLzAxLzAwMDEpXG5cdCAqIFwiLi4uXCIgLSBsaXRlcmFsIHRleHRcblx0ICogJycgLSBzaW5nbGUgcXVvdGVcblx0ICpcblx0ICogQHBhcmFtICBmb3JtYXQgc3RyaW5nIC0gdGhlIGRlc2lyZWQgZm9ybWF0IG9mIHRoZSBkYXRlXG5cdCAqIEBwYXJhbSAgZGF0ZSBEYXRlIC0gdGhlIGRhdGUgdmFsdWUgdG8gZm9ybWF0XG5cdCAqIEBwYXJhbSAgc2V0dGluZ3MgT2JqZWN0IC0gYXR0cmlidXRlcyBpbmNsdWRlOlxuXHQgKlx0XHRcdFx0XHRkYXlOYW1lc1Nob3J0XHRzdHJpbmdbN10gLSBhYmJyZXZpYXRlZCBuYW1lcyBvZiB0aGUgZGF5cyBmcm9tIFN1bmRheSAob3B0aW9uYWwpXG5cdCAqXHRcdFx0XHRcdGRheU5hbWVzXHRcdHN0cmluZ1s3XSAtIG5hbWVzIG9mIHRoZSBkYXlzIGZyb20gU3VuZGF5IChvcHRpb25hbClcblx0ICpcdFx0XHRcdFx0bW9udGhOYW1lc1Nob3J0IHN0cmluZ1sxMl0gLSBhYmJyZXZpYXRlZCBuYW1lcyBvZiB0aGUgbW9udGhzIChvcHRpb25hbClcblx0ICpcdFx0XHRcdFx0bW9udGhOYW1lc1x0XHRzdHJpbmdbMTJdIC0gbmFtZXMgb2YgdGhlIG1vbnRocyAob3B0aW9uYWwpXG5cdCAqIEByZXR1cm4gIHN0cmluZyAtIHRoZSBkYXRlIGluIHRoZSBhYm92ZSBmb3JtYXRcblx0ICovXG5cdGZvcm1hdERhdGU6IGZ1bmN0aW9uKCBmb3JtYXQsIGRhdGUsIHNldHRpbmdzICkge1xuXHRcdGlmICggIWRhdGUgKSB7XG5cdFx0XHRyZXR1cm4gXCJcIjtcblx0XHR9XG5cblx0XHR2YXIgaUZvcm1hdCxcblx0XHRcdGRheU5hbWVzU2hvcnQgPSAoIHNldHRpbmdzID8gc2V0dGluZ3MuZGF5TmFtZXNTaG9ydCA6IG51bGwgKSB8fCB0aGlzLl9kZWZhdWx0cy5kYXlOYW1lc1Nob3J0LFxuXHRcdFx0ZGF5TmFtZXMgPSAoIHNldHRpbmdzID8gc2V0dGluZ3MuZGF5TmFtZXMgOiBudWxsICkgfHwgdGhpcy5fZGVmYXVsdHMuZGF5TmFtZXMsXG5cdFx0XHRtb250aE5hbWVzU2hvcnQgPSAoIHNldHRpbmdzID8gc2V0dGluZ3MubW9udGhOYW1lc1Nob3J0IDogbnVsbCApIHx8IHRoaXMuX2RlZmF1bHRzLm1vbnRoTmFtZXNTaG9ydCxcblx0XHRcdG1vbnRoTmFtZXMgPSAoIHNldHRpbmdzID8gc2V0dGluZ3MubW9udGhOYW1lcyA6IG51bGwgKSB8fCB0aGlzLl9kZWZhdWx0cy5tb250aE5hbWVzLFxuXG5cdFx0XHQvLyBDaGVjayB3aGV0aGVyIGEgZm9ybWF0IGNoYXJhY3RlciBpcyBkb3VibGVkXG5cdFx0XHRsb29rQWhlYWQgPSBmdW5jdGlvbiggbWF0Y2ggKSB7XG5cdFx0XHRcdHZhciBtYXRjaGVzID0gKCBpRm9ybWF0ICsgMSA8IGZvcm1hdC5sZW5ndGggJiYgZm9ybWF0LmNoYXJBdCggaUZvcm1hdCArIDEgKSA9PT0gbWF0Y2ggKTtcblx0XHRcdFx0aWYgKCBtYXRjaGVzICkge1xuXHRcdFx0XHRcdGlGb3JtYXQrKztcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gbWF0Y2hlcztcblx0XHRcdH0sXG5cblx0XHRcdC8vIEZvcm1hdCBhIG51bWJlciwgd2l0aCBsZWFkaW5nIHplcm8gaWYgbmVjZXNzYXJ5XG5cdFx0XHRmb3JtYXROdW1iZXIgPSBmdW5jdGlvbiggbWF0Y2gsIHZhbHVlLCBsZW4gKSB7XG5cdFx0XHRcdHZhciBudW0gPSBcIlwiICsgdmFsdWU7XG5cdFx0XHRcdGlmICggbG9va0FoZWFkKCBtYXRjaCApICkge1xuXHRcdFx0XHRcdHdoaWxlICggbnVtLmxlbmd0aCA8IGxlbiApIHtcblx0XHRcdFx0XHRcdG51bSA9IFwiMFwiICsgbnVtO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gbnVtO1xuXHRcdFx0fSxcblxuXHRcdFx0Ly8gRm9ybWF0IGEgbmFtZSwgc2hvcnQgb3IgbG9uZyBhcyByZXF1ZXN0ZWRcblx0XHRcdGZvcm1hdE5hbWUgPSBmdW5jdGlvbiggbWF0Y2gsIHZhbHVlLCBzaG9ydE5hbWVzLCBsb25nTmFtZXMgKSB7XG5cdFx0XHRcdHJldHVybiAoIGxvb2tBaGVhZCggbWF0Y2ggKSA/IGxvbmdOYW1lc1sgdmFsdWUgXSA6IHNob3J0TmFtZXNbIHZhbHVlIF0gKTtcblx0XHRcdH0sXG5cdFx0XHRvdXRwdXQgPSBcIlwiLFxuXHRcdFx0bGl0ZXJhbCA9IGZhbHNlO1xuXG5cdFx0aWYgKCBkYXRlICkge1xuXHRcdFx0Zm9yICggaUZvcm1hdCA9IDA7IGlGb3JtYXQgPCBmb3JtYXQubGVuZ3RoOyBpRm9ybWF0KysgKSB7XG5cdFx0XHRcdGlmICggbGl0ZXJhbCApIHtcblx0XHRcdFx0XHRpZiAoIGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKSA9PT0gXCInXCIgJiYgIWxvb2tBaGVhZCggXCInXCIgKSApIHtcblx0XHRcdFx0XHRcdGxpdGVyYWwgPSBmYWxzZTtcblx0XHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdFx0b3V0cHV0ICs9IGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0c3dpdGNoICggZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApICkge1xuXHRcdFx0XHRcdFx0Y2FzZSBcImRcIjpcblx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9IGZvcm1hdE51bWJlciggXCJkXCIsIGRhdGUuZ2V0RGF0ZSgpLCAyICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdFx0Y2FzZSBcIkRcIjpcblx0XHRcdFx0XHRcdFx0b3V0cHV0ICs9IGZvcm1hdE5hbWUoIFwiRFwiLCBkYXRlLmdldERheSgpLCBkYXlOYW1lc1Nob3J0LCBkYXlOYW1lcyApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCJvXCI6XG5cdFx0XHRcdFx0XHRcdG91dHB1dCArPSBmb3JtYXROdW1iZXIoIFwib1wiLFxuXHRcdFx0XHRcdFx0XHRcdE1hdGgucm91bmQoICggbmV3IERhdGUoIGRhdGUuZ2V0RnVsbFllYXIoKSwgZGF0ZS5nZXRNb250aCgpLCBkYXRlLmdldERhdGUoKSApLmdldFRpbWUoKSAtIG5ldyBEYXRlKCBkYXRlLmdldEZ1bGxZZWFyKCksIDAsIDAgKS5nZXRUaW1lKCkgKSAvIDg2NDAwMDAwICksIDMgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwibVwiOlxuXHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gZm9ybWF0TnVtYmVyKCBcIm1cIiwgZGF0ZS5nZXRNb250aCgpICsgMSwgMiApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCJNXCI6XG5cdFx0XHRcdFx0XHRcdG91dHB1dCArPSBmb3JtYXROYW1lKCBcIk1cIiwgZGF0ZS5nZXRNb250aCgpLCBtb250aE5hbWVzU2hvcnQsIG1vbnRoTmFtZXMgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwieVwiOlxuXHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gKCBsb29rQWhlYWQoIFwieVwiICkgPyBkYXRlLmdldEZ1bGxZZWFyKCkgOlxuXHRcdFx0XHRcdFx0XHRcdCggZGF0ZS5nZXRGdWxsWWVhcigpICUgMTAwIDwgMTAgPyBcIjBcIiA6IFwiXCIgKSArIGRhdGUuZ2V0RnVsbFllYXIoKSAlIDEwMCApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCJAXCI6XG5cdFx0XHRcdFx0XHRcdG91dHB1dCArPSBkYXRlLmdldFRpbWUoKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwiIVwiOlxuXHRcdFx0XHRcdFx0XHRvdXRwdXQgKz0gZGF0ZS5nZXRUaW1lKCkgKiAxMDAwMCArIHRoaXMuX3RpY2tzVG8xOTcwO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGNhc2UgXCInXCI6XG5cdFx0XHRcdFx0XHRcdGlmICggbG9va0FoZWFkKCBcIidcIiApICkge1xuXHRcdFx0XHRcdFx0XHRcdG91dHB1dCArPSBcIidcIjtcblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0XHRsaXRlcmFsID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0XHRcdG91dHB1dCArPSBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBvdXRwdXQ7XG5cdH0sXG5cblx0LyogRXh0cmFjdCBhbGwgcG9zc2libGUgY2hhcmFjdGVycyBmcm9tIHRoZSBkYXRlIGZvcm1hdC4gKi9cblx0X3Bvc3NpYmxlQ2hhcnM6IGZ1bmN0aW9uKCBmb3JtYXQgKSB7XG5cdFx0dmFyIGlGb3JtYXQsXG5cdFx0XHRjaGFycyA9IFwiXCIsXG5cdFx0XHRsaXRlcmFsID0gZmFsc2UsXG5cblx0XHRcdC8vIENoZWNrIHdoZXRoZXIgYSBmb3JtYXQgY2hhcmFjdGVyIGlzIGRvdWJsZWRcblx0XHRcdGxvb2tBaGVhZCA9IGZ1bmN0aW9uKCBtYXRjaCApIHtcblx0XHRcdFx0dmFyIG1hdGNoZXMgPSAoIGlGb3JtYXQgKyAxIDwgZm9ybWF0Lmxlbmd0aCAmJiBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICsgMSApID09PSBtYXRjaCApO1xuXHRcdFx0XHRpZiAoIG1hdGNoZXMgKSB7XG5cdFx0XHRcdFx0aUZvcm1hdCsrO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybiBtYXRjaGVzO1xuXHRcdFx0fTtcblxuXHRcdGZvciAoIGlGb3JtYXQgPSAwOyBpRm9ybWF0IDwgZm9ybWF0Lmxlbmd0aDsgaUZvcm1hdCsrICkge1xuXHRcdFx0aWYgKCBsaXRlcmFsICkge1xuXHRcdFx0XHRpZiAoIGZvcm1hdC5jaGFyQXQoIGlGb3JtYXQgKSA9PT0gXCInXCIgJiYgIWxvb2tBaGVhZCggXCInXCIgKSApIHtcblx0XHRcdFx0XHRsaXRlcmFsID0gZmFsc2U7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0Y2hhcnMgKz0gZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRzd2l0Y2ggKCBmb3JtYXQuY2hhckF0KCBpRm9ybWF0ICkgKSB7XG5cdFx0XHRcdFx0Y2FzZSBcImRcIjogY2FzZSBcIm1cIjogY2FzZSBcInlcIjogY2FzZSBcIkBcIjpcblx0XHRcdFx0XHRcdGNoYXJzICs9IFwiMDEyMzQ1Njc4OVwiO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0Y2FzZSBcIkRcIjogY2FzZSBcIk1cIjpcblx0XHRcdFx0XHRcdHJldHVybiBudWxsOyAvLyBBY2NlcHQgYW55dGhpbmdcblx0XHRcdFx0XHRjYXNlIFwiJ1wiOlxuXHRcdFx0XHRcdFx0aWYgKCBsb29rQWhlYWQoIFwiJ1wiICkgKSB7XG5cdFx0XHRcdFx0XHRcdGNoYXJzICs9IFwiJ1wiO1xuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdFx0bGl0ZXJhbCA9IHRydWU7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0Y2hhcnMgKz0gZm9ybWF0LmNoYXJBdCggaUZvcm1hdCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiBjaGFycztcblx0fSxcblxuXHQvKiBHZXQgYSBzZXR0aW5nIHZhbHVlLCBkZWZhdWx0aW5nIGlmIG5lY2Vzc2FyeS4gKi9cblx0X2dldDogZnVuY3Rpb24oIGluc3QsIG5hbWUgKSB7XG5cdFx0cmV0dXJuIGluc3Quc2V0dGluZ3NbIG5hbWUgXSAhPT0gdW5kZWZpbmVkID9cblx0XHRcdGluc3Quc2V0dGluZ3NbIG5hbWUgXSA6IHRoaXMuX2RlZmF1bHRzWyBuYW1lIF07XG5cdH0sXG5cblx0LyogUGFyc2UgZXhpc3RpbmcgZGF0ZSBhbmQgaW5pdGlhbGlzZSBkYXRlIHBpY2tlci4gKi9cblx0X3NldERhdGVGcm9tRmllbGQ6IGZ1bmN0aW9uKCBpbnN0LCBub0RlZmF1bHQgKSB7XG5cdFx0aWYgKCBpbnN0LmlucHV0LnZhbCgpID09PSBpbnN0Lmxhc3RWYWwgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIGRhdGVGb3JtYXQgPSB0aGlzLl9nZXQoIGluc3QsIFwiZGF0ZUZvcm1hdFwiICksXG5cdFx0XHRkYXRlcyA9IGluc3QubGFzdFZhbCA9IGluc3QuaW5wdXQgPyBpbnN0LmlucHV0LnZhbCgpIDogbnVsbCxcblx0XHRcdGRlZmF1bHREYXRlID0gdGhpcy5fZ2V0RGVmYXVsdERhdGUoIGluc3QgKSxcblx0XHRcdGRhdGUgPSBkZWZhdWx0RGF0ZSxcblx0XHRcdHNldHRpbmdzID0gdGhpcy5fZ2V0Rm9ybWF0Q29uZmlnKCBpbnN0ICk7XG5cblx0XHR0cnkge1xuXHRcdFx0ZGF0ZSA9IHRoaXMucGFyc2VEYXRlKCBkYXRlRm9ybWF0LCBkYXRlcywgc2V0dGluZ3MgKSB8fCBkZWZhdWx0RGF0ZTtcblx0XHR9IGNhdGNoICggZXZlbnQgKSB7XG5cdFx0XHRkYXRlcyA9ICggbm9EZWZhdWx0ID8gXCJcIiA6IGRhdGVzICk7XG5cdFx0fVxuXHRcdGluc3Quc2VsZWN0ZWREYXkgPSBkYXRlLmdldERhdGUoKTtcblx0XHRpbnN0LmRyYXdNb250aCA9IGluc3Quc2VsZWN0ZWRNb250aCA9IGRhdGUuZ2V0TW9udGgoKTtcblx0XHRpbnN0LmRyYXdZZWFyID0gaW5zdC5zZWxlY3RlZFllYXIgPSBkYXRlLmdldEZ1bGxZZWFyKCk7XG5cdFx0aW5zdC5jdXJyZW50RGF5ID0gKCBkYXRlcyA/IGRhdGUuZ2V0RGF0ZSgpIDogMCApO1xuXHRcdGluc3QuY3VycmVudE1vbnRoID0gKCBkYXRlcyA/IGRhdGUuZ2V0TW9udGgoKSA6IDAgKTtcblx0XHRpbnN0LmN1cnJlbnRZZWFyID0gKCBkYXRlcyA/IGRhdGUuZ2V0RnVsbFllYXIoKSA6IDAgKTtcblx0XHR0aGlzLl9hZGp1c3RJbnN0RGF0ZSggaW5zdCApO1xuXHR9LFxuXG5cdC8qIFJldHJpZXZlIHRoZSBkZWZhdWx0IGRhdGUgc2hvd24gb24gb3BlbmluZy4gKi9cblx0X2dldERlZmF1bHREYXRlOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHRyZXR1cm4gdGhpcy5fcmVzdHJpY3RNaW5NYXgoIGluc3QsXG5cdFx0XHR0aGlzLl9kZXRlcm1pbmVEYXRlKCBpbnN0LCB0aGlzLl9nZXQoIGluc3QsIFwiZGVmYXVsdERhdGVcIiApLCBuZXcgRGF0ZSgpICkgKTtcblx0fSxcblxuXHQvKiBBIGRhdGUgbWF5IGJlIHNwZWNpZmllZCBhcyBhbiBleGFjdCB2YWx1ZSBvciBhIHJlbGF0aXZlIG9uZS4gKi9cblx0X2RldGVybWluZURhdGU6IGZ1bmN0aW9uKCBpbnN0LCBkYXRlLCBkZWZhdWx0RGF0ZSApIHtcblx0XHR2YXIgb2Zmc2V0TnVtZXJpYyA9IGZ1bmN0aW9uKCBvZmZzZXQgKSB7XG5cdFx0XHRcdHZhciBkYXRlID0gbmV3IERhdGUoKTtcblx0XHRcdFx0ZGF0ZS5zZXREYXRlKCBkYXRlLmdldERhdGUoKSArIG9mZnNldCApO1xuXHRcdFx0XHRyZXR1cm4gZGF0ZTtcblx0XHRcdH0sXG5cdFx0XHRvZmZzZXRTdHJpbmcgPSBmdW5jdGlvbiggb2Zmc2V0ICkge1xuXHRcdFx0XHR0cnkge1xuXHRcdFx0XHRcdHJldHVybiAkLmRhdGVwaWNrZXIucGFyc2VEYXRlKCAkLmRhdGVwaWNrZXIuX2dldCggaW5zdCwgXCJkYXRlRm9ybWF0XCIgKSxcblx0XHRcdFx0XHRcdG9mZnNldCwgJC5kYXRlcGlja2VyLl9nZXRGb3JtYXRDb25maWcoIGluc3QgKSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGNhdGNoICggZSApIHtcblxuXHRcdFx0XHRcdC8vIElnbm9yZVxuXHRcdFx0XHR9XG5cblx0XHRcdFx0dmFyIGRhdGUgPSAoIG9mZnNldC50b0xvd2VyQ2FzZSgpLm1hdGNoKCAvXmMvICkgP1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fZ2V0RGF0ZSggaW5zdCApIDogbnVsbCApIHx8IG5ldyBEYXRlKCksXG5cdFx0XHRcdFx0eWVhciA9IGRhdGUuZ2V0RnVsbFllYXIoKSxcblx0XHRcdFx0XHRtb250aCA9IGRhdGUuZ2V0TW9udGgoKSxcblx0XHRcdFx0XHRkYXkgPSBkYXRlLmdldERhdGUoKSxcblx0XHRcdFx0XHRwYXR0ZXJuID0gLyhbK1xcLV0/WzAtOV0rKVxccyooZHxEfHd8V3xtfE18eXxZKT8vZyxcblx0XHRcdFx0XHRtYXRjaGVzID0gcGF0dGVybi5leGVjKCBvZmZzZXQgKTtcblxuXHRcdFx0XHR3aGlsZSAoIG1hdGNoZXMgKSB7XG5cdFx0XHRcdFx0c3dpdGNoICggbWF0Y2hlc1sgMiBdIHx8IFwiZFwiICkge1xuXHRcdFx0XHRcdFx0Y2FzZSBcImRcIiA6IGNhc2UgXCJEXCIgOlxuXHRcdFx0XHRcdFx0XHRkYXkgKz0gcGFyc2VJbnQoIG1hdGNoZXNbIDEgXSwgMTAgKTsgYnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwid1wiIDogY2FzZSBcIldcIiA6XG5cdFx0XHRcdFx0XHRcdGRheSArPSBwYXJzZUludCggbWF0Y2hlc1sgMSBdLCAxMCApICogNzsgYnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwibVwiIDogY2FzZSBcIk1cIiA6XG5cdFx0XHRcdFx0XHRcdG1vbnRoICs9IHBhcnNlSW50KCBtYXRjaGVzWyAxIF0sIDEwICk7XG5cdFx0XHRcdFx0XHRcdGRheSA9IE1hdGgubWluKCBkYXksICQuZGF0ZXBpY2tlci5fZ2V0RGF5c0luTW9udGgoIHllYXIsIG1vbnRoICkgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdFx0XHRjYXNlIFwieVwiOiBjYXNlIFwiWVwiIDpcblx0XHRcdFx0XHRcdFx0eWVhciArPSBwYXJzZUludCggbWF0Y2hlc1sgMSBdLCAxMCApO1xuXHRcdFx0XHRcdFx0XHRkYXkgPSBNYXRoLm1pbiggZGF5LCAkLmRhdGVwaWNrZXIuX2dldERheXNJbk1vbnRoKCB5ZWFyLCBtb250aCApICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRtYXRjaGVzID0gcGF0dGVybi5leGVjKCBvZmZzZXQgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gbmV3IERhdGUoIHllYXIsIG1vbnRoLCBkYXkgKTtcblx0XHRcdH0sXG5cdFx0XHRuZXdEYXRlID0gKCBkYXRlID09IG51bGwgfHwgZGF0ZSA9PT0gXCJcIiA/IGRlZmF1bHREYXRlIDogKCB0eXBlb2YgZGF0ZSA9PT0gXCJzdHJpbmdcIiA/IG9mZnNldFN0cmluZyggZGF0ZSApIDpcblx0XHRcdFx0KCB0eXBlb2YgZGF0ZSA9PT0gXCJudW1iZXJcIiA/ICggaXNOYU4oIGRhdGUgKSA/IGRlZmF1bHREYXRlIDogb2Zmc2V0TnVtZXJpYyggZGF0ZSApICkgOiBuZXcgRGF0ZSggZGF0ZS5nZXRUaW1lKCkgKSApICkgKTtcblxuXHRcdG5ld0RhdGUgPSAoIG5ld0RhdGUgJiYgbmV3RGF0ZS50b1N0cmluZygpID09PSBcIkludmFsaWQgRGF0ZVwiID8gZGVmYXVsdERhdGUgOiBuZXdEYXRlICk7XG5cdFx0aWYgKCBuZXdEYXRlICkge1xuXHRcdFx0bmV3RGF0ZS5zZXRIb3VycyggMCApO1xuXHRcdFx0bmV3RGF0ZS5zZXRNaW51dGVzKCAwICk7XG5cdFx0XHRuZXdEYXRlLnNldFNlY29uZHMoIDAgKTtcblx0XHRcdG5ld0RhdGUuc2V0TWlsbGlzZWNvbmRzKCAwICk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3RGF0ZSApO1xuXHR9LFxuXG5cdC8qIEhhbmRsZSBzd2l0Y2ggdG8vZnJvbSBkYXlsaWdodCBzYXZpbmcuXG5cdCAqIEhvdXJzIG1heSBiZSBub24temVybyBvbiBkYXlsaWdodCBzYXZpbmcgY3V0LW92ZXI6XG5cdCAqID4gMTIgd2hlbiBtaWRuaWdodCBjaGFuZ2VvdmVyLCBidXQgdGhlbiBjYW5ub3QgZ2VuZXJhdGVcblx0ICogbWlkbmlnaHQgZGF0ZXRpbWUsIHNvIGp1bXAgdG8gMUFNLCBvdGhlcndpc2UgcmVzZXQuXG5cdCAqIEBwYXJhbSAgZGF0ZSAgKERhdGUpIHRoZSBkYXRlIHRvIGNoZWNrXG5cdCAqIEByZXR1cm4gIChEYXRlKSB0aGUgY29ycmVjdGVkIGRhdGVcblx0ICovXG5cdF9kYXlsaWdodFNhdmluZ0FkanVzdDogZnVuY3Rpb24oIGRhdGUgKSB7XG5cdFx0aWYgKCAhZGF0ZSApIHtcblx0XHRcdHJldHVybiBudWxsO1xuXHRcdH1cblx0XHRkYXRlLnNldEhvdXJzKCBkYXRlLmdldEhvdXJzKCkgPiAxMiA/IGRhdGUuZ2V0SG91cnMoKSArIDIgOiAwICk7XG5cdFx0cmV0dXJuIGRhdGU7XG5cdH0sXG5cblx0LyogU2V0IHRoZSBkYXRlKHMpIGRpcmVjdGx5LiAqL1xuXHRfc2V0RGF0ZTogZnVuY3Rpb24oIGluc3QsIGRhdGUsIG5vQ2hhbmdlICkge1xuXHRcdHZhciBjbGVhciA9ICFkYXRlLFxuXHRcdFx0b3JpZ01vbnRoID0gaW5zdC5zZWxlY3RlZE1vbnRoLFxuXHRcdFx0b3JpZ1llYXIgPSBpbnN0LnNlbGVjdGVkWWVhcixcblx0XHRcdG5ld0RhdGUgPSB0aGlzLl9yZXN0cmljdE1pbk1heCggaW5zdCwgdGhpcy5fZGV0ZXJtaW5lRGF0ZSggaW5zdCwgZGF0ZSwgbmV3IERhdGUoKSApICk7XG5cblx0XHRpbnN0LnNlbGVjdGVkRGF5ID0gaW5zdC5jdXJyZW50RGF5ID0gbmV3RGF0ZS5nZXREYXRlKCk7XG5cdFx0aW5zdC5kcmF3TW9udGggPSBpbnN0LnNlbGVjdGVkTW9udGggPSBpbnN0LmN1cnJlbnRNb250aCA9IG5ld0RhdGUuZ2V0TW9udGgoKTtcblx0XHRpbnN0LmRyYXdZZWFyID0gaW5zdC5zZWxlY3RlZFllYXIgPSBpbnN0LmN1cnJlbnRZZWFyID0gbmV3RGF0ZS5nZXRGdWxsWWVhcigpO1xuXHRcdGlmICggKCBvcmlnTW9udGggIT09IGluc3Quc2VsZWN0ZWRNb250aCB8fCBvcmlnWWVhciAhPT0gaW5zdC5zZWxlY3RlZFllYXIgKSAmJiAhbm9DaGFuZ2UgKSB7XG5cdFx0XHR0aGlzLl9ub3RpZnlDaGFuZ2UoIGluc3QgKTtcblx0XHR9XG5cdFx0dGhpcy5fYWRqdXN0SW5zdERhdGUoIGluc3QgKTtcblx0XHRpZiAoIGluc3QuaW5wdXQgKSB7XG5cdFx0XHRpbnN0LmlucHV0LnZhbCggY2xlYXIgPyBcIlwiIDogdGhpcy5fZm9ybWF0RGF0ZSggaW5zdCApICk7XG5cdFx0fVxuXHR9LFxuXG5cdC8qIFJldHJpZXZlIHRoZSBkYXRlKHMpIGRpcmVjdGx5LiAqL1xuXHRfZ2V0RGF0ZTogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0dmFyIHN0YXJ0RGF0ZSA9ICggIWluc3QuY3VycmVudFllYXIgfHwgKCBpbnN0LmlucHV0ICYmIGluc3QuaW5wdXQudmFsKCkgPT09IFwiXCIgKSA/IG51bGwgOlxuXHRcdFx0dGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKFxuXHRcdFx0aW5zdC5jdXJyZW50WWVhciwgaW5zdC5jdXJyZW50TW9udGgsIGluc3QuY3VycmVudERheSApICkgKTtcblx0XHRcdHJldHVybiBzdGFydERhdGU7XG5cdH0sXG5cblx0LyogQXR0YWNoIHRoZSBvbnh4eCBoYW5kbGVycy4gIFRoZXNlIGFyZSBkZWNsYXJlZCBzdGF0aWNhbGx5IHNvXG5cdCAqIHRoZXkgd29yayB3aXRoIHN0YXRpYyBjb2RlIHRyYW5zZm9ybWVycyBsaWtlIENhamEuXG5cdCAqL1xuXHRfYXR0YWNoSGFuZGxlcnM6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHZhciBzdGVwTW9udGhzID0gdGhpcy5fZ2V0KCBpbnN0LCBcInN0ZXBNb250aHNcIiApLFxuXHRcdFx0aWQgPSBcIiNcIiArIGluc3QuaWQucmVwbGFjZSggL1xcXFxcXFxcL2csIFwiXFxcXFwiICk7XG5cdFx0aW5zdC5kcERpdi5maW5kKCBcIltkYXRhLWhhbmRsZXJdXCIgKS5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGhhbmRsZXIgPSB7XG5cdFx0XHRcdHByZXY6IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdCQuZGF0ZXBpY2tlci5fYWRqdXN0RGF0ZSggaWQsIC1zdGVwTW9udGhzLCBcIk1cIiApO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRuZXh0OiBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHQkLmRhdGVwaWNrZXIuX2FkanVzdERhdGUoIGlkLCArc3RlcE1vbnRocywgXCJNXCIgKTtcblx0XHRcdFx0fSxcblx0XHRcdFx0aGlkZTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9oaWRlRGF0ZXBpY2tlcigpO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHR0b2RheTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9nb3RvVG9kYXkoIGlkICk7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdHNlbGVjdERheTogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9zZWxlY3REYXkoIGlkLCArdGhpcy5nZXRBdHRyaWJ1dGUoIFwiZGF0YS1tb250aFwiICksICt0aGlzLmdldEF0dHJpYnV0ZSggXCJkYXRhLXllYXJcIiApLCB0aGlzICk7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9LFxuXHRcdFx0XHRzZWxlY3RNb250aDogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9zZWxlY3RNb250aFllYXIoIGlkLCB0aGlzLCBcIk1cIiApO1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fSxcblx0XHRcdFx0c2VsZWN0WWVhcjogZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0JC5kYXRlcGlja2VyLl9zZWxlY3RNb250aFllYXIoIGlkLCB0aGlzLCBcIllcIiApO1xuXHRcdFx0XHRcdHJldHVybiBmYWxzZTtcblx0XHRcdFx0fVxuXHRcdFx0fTtcblx0XHRcdCQoIHRoaXMgKS5vbiggdGhpcy5nZXRBdHRyaWJ1dGUoIFwiZGF0YS1ldmVudFwiICksIGhhbmRsZXJbIHRoaXMuZ2V0QXR0cmlidXRlKCBcImRhdGEtaGFuZGxlclwiICkgXSApO1xuXHRcdH0gKTtcblx0fSxcblxuXHQvKiBHZW5lcmF0ZSB0aGUgSFRNTCBmb3IgdGhlIGN1cnJlbnQgc3RhdGUgb2YgdGhlIGRhdGUgcGlja2VyLiAqL1xuXHRfZ2VuZXJhdGVIVE1MOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHR2YXIgbWF4RHJhdywgcHJldlRleHQsIHByZXYsIG5leHRUZXh0LCBuZXh0LCBjdXJyZW50VGV4dCwgZ290b0RhdGUsXG5cdFx0XHRjb250cm9scywgYnV0dG9uUGFuZWwsIGZpcnN0RGF5LCBzaG93V2VlaywgZGF5TmFtZXMsIGRheU5hbWVzTWluLFxuXHRcdFx0bW9udGhOYW1lcywgbW9udGhOYW1lc1Nob3J0LCBiZWZvcmVTaG93RGF5LCBzaG93T3RoZXJNb250aHMsXG5cdFx0XHRzZWxlY3RPdGhlck1vbnRocywgZGVmYXVsdERhdGUsIGh0bWwsIGRvdywgcm93LCBncm91cCwgY29sLCBzZWxlY3RlZERhdGUsXG5cdFx0XHRjb3JuZXJDbGFzcywgY2FsZW5kZXIsIHRoZWFkLCBkYXksIGRheXNJbk1vbnRoLCBsZWFkRGF5cywgY3VyUm93cywgbnVtUm93cyxcblx0XHRcdHByaW50RGF0ZSwgZFJvdywgdGJvZHksIGRheVNldHRpbmdzLCBvdGhlck1vbnRoLCB1bnNlbGVjdGFibGUsXG5cdFx0XHR0ZW1wRGF0ZSA9IG5ldyBEYXRlKCksXG5cdFx0XHR0b2RheSA9IHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KFxuXHRcdFx0XHRuZXcgRGF0ZSggdGVtcERhdGUuZ2V0RnVsbFllYXIoKSwgdGVtcERhdGUuZ2V0TW9udGgoKSwgdGVtcERhdGUuZ2V0RGF0ZSgpICkgKSwgLy8gY2xlYXIgdGltZVxuXHRcdFx0aXNSVEwgPSB0aGlzLl9nZXQoIGluc3QsIFwiaXNSVExcIiApLFxuXHRcdFx0c2hvd0J1dHRvblBhbmVsID0gdGhpcy5fZ2V0KCBpbnN0LCBcInNob3dCdXR0b25QYW5lbFwiICksXG5cdFx0XHRoaWRlSWZOb1ByZXZOZXh0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcImhpZGVJZk5vUHJldk5leHRcIiApLFxuXHRcdFx0bmF2aWdhdGlvbkFzRGF0ZUZvcm1hdCA9IHRoaXMuX2dldCggaW5zdCwgXCJuYXZpZ2F0aW9uQXNEYXRlRm9ybWF0XCIgKSxcblx0XHRcdG51bU1vbnRocyA9IHRoaXMuX2dldE51bWJlck9mTW9udGhzKCBpbnN0ICksXG5cdFx0XHRzaG93Q3VycmVudEF0UG9zID0gdGhpcy5fZ2V0KCBpbnN0LCBcInNob3dDdXJyZW50QXRQb3NcIiApLFxuXHRcdFx0c3RlcE1vbnRocyA9IHRoaXMuX2dldCggaW5zdCwgXCJzdGVwTW9udGhzXCIgKSxcblx0XHRcdGlzTXVsdGlNb250aCA9ICggbnVtTW9udGhzWyAwIF0gIT09IDEgfHwgbnVtTW9udGhzWyAxIF0gIT09IDEgKSxcblx0XHRcdGN1cnJlbnREYXRlID0gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoICggIWluc3QuY3VycmVudERheSA/IG5ldyBEYXRlKCA5OTk5LCA5LCA5ICkgOlxuXHRcdFx0XHRuZXcgRGF0ZSggaW5zdC5jdXJyZW50WWVhciwgaW5zdC5jdXJyZW50TW9udGgsIGluc3QuY3VycmVudERheSApICkgKSxcblx0XHRcdG1pbkRhdGUgPSB0aGlzLl9nZXRNaW5NYXhEYXRlKCBpbnN0LCBcIm1pblwiICksXG5cdFx0XHRtYXhEYXRlID0gdGhpcy5fZ2V0TWluTWF4RGF0ZSggaW5zdCwgXCJtYXhcIiApLFxuXHRcdFx0ZHJhd01vbnRoID0gaW5zdC5kcmF3TW9udGggLSBzaG93Q3VycmVudEF0UG9zLFxuXHRcdFx0ZHJhd1llYXIgPSBpbnN0LmRyYXdZZWFyO1xuXG5cdFx0aWYgKCBkcmF3TW9udGggPCAwICkge1xuXHRcdFx0ZHJhd01vbnRoICs9IDEyO1xuXHRcdFx0ZHJhd1llYXItLTtcblx0XHR9XG5cdFx0aWYgKCBtYXhEYXRlICkge1xuXHRcdFx0bWF4RHJhdyA9IHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggbWF4RGF0ZS5nZXRGdWxsWWVhcigpLFxuXHRcdFx0XHRtYXhEYXRlLmdldE1vbnRoKCkgLSAoIG51bU1vbnRoc1sgMCBdICogbnVtTW9udGhzWyAxIF0gKSArIDEsIG1heERhdGUuZ2V0RGF0ZSgpICkgKTtcblx0XHRcdG1heERyYXcgPSAoIG1pbkRhdGUgJiYgbWF4RHJhdyA8IG1pbkRhdGUgPyBtaW5EYXRlIDogbWF4RHJhdyApO1xuXHRcdFx0d2hpbGUgKCB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIGRyYXdZZWFyLCBkcmF3TW9udGgsIDEgKSApID4gbWF4RHJhdyApIHtcblx0XHRcdFx0ZHJhd01vbnRoLS07XG5cdFx0XHRcdGlmICggZHJhd01vbnRoIDwgMCApIHtcblx0XHRcdFx0XHRkcmF3TW9udGggPSAxMTtcblx0XHRcdFx0XHRkcmF3WWVhci0tO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGluc3QuZHJhd01vbnRoID0gZHJhd01vbnRoO1xuXHRcdGluc3QuZHJhd1llYXIgPSBkcmF3WWVhcjtcblxuXHRcdHByZXZUZXh0ID0gdGhpcy5fZ2V0KCBpbnN0LCBcInByZXZUZXh0XCIgKTtcblx0XHRwcmV2VGV4dCA9ICggIW5hdmlnYXRpb25Bc0RhdGVGb3JtYXQgPyBwcmV2VGV4dCA6IHRoaXMuZm9ybWF0RGF0ZSggcHJldlRleHQsXG5cdFx0XHR0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIGRyYXdZZWFyLCBkcmF3TW9udGggLSBzdGVwTW9udGhzLCAxICkgKSxcblx0XHRcdHRoaXMuX2dldEZvcm1hdENvbmZpZyggaW5zdCApICkgKTtcblxuXHRcdHByZXYgPSAoIHRoaXMuX2NhbkFkanVzdE1vbnRoKCBpbnN0LCAtMSwgZHJhd1llYXIsIGRyYXdNb250aCApID9cblx0XHRcdFwiPGEgY2xhc3M9J3VpLWRhdGVwaWNrZXItcHJldiB1aS1jb3JuZXItYWxsJyBkYXRhLWhhbmRsZXI9J3ByZXYnIGRhdGEtZXZlbnQ9J2NsaWNrJ1wiICtcblx0XHRcdFwiIHRpdGxlPSdcIiArIHByZXZUZXh0ICsgXCInPjxzcGFuIGNsYXNzPSd1aS1pY29uIHVpLWljb24tY2lyY2xlLXRyaWFuZ2xlLVwiICsgKCBpc1JUTCA/IFwiZVwiIDogXCJ3XCIgKSArIFwiJz5cIiArIHByZXZUZXh0ICsgXCI8L3NwYW4+PC9hPlwiIDpcblx0XHRcdCggaGlkZUlmTm9QcmV2TmV4dCA/IFwiXCIgOiBcIjxhIGNsYXNzPSd1aS1kYXRlcGlja2VyLXByZXYgdWktY29ybmVyLWFsbCB1aS1zdGF0ZS1kaXNhYmxlZCcgdGl0bGU9J1wiICsgcHJldlRleHQgKyBcIic+PHNwYW4gY2xhc3M9J3VpLWljb24gdWktaWNvbi1jaXJjbGUtdHJpYW5nbGUtXCIgKyAoIGlzUlRMID8gXCJlXCIgOiBcIndcIiApICsgXCInPlwiICsgcHJldlRleHQgKyBcIjwvc3Bhbj48L2E+XCIgKSApO1xuXG5cdFx0bmV4dFRleHQgPSB0aGlzLl9nZXQoIGluc3QsIFwibmV4dFRleHRcIiApO1xuXHRcdG5leHRUZXh0ID0gKCAhbmF2aWdhdGlvbkFzRGF0ZUZvcm1hdCA/IG5leHRUZXh0IDogdGhpcy5mb3JtYXREYXRlKCBuZXh0VGV4dCxcblx0XHRcdHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggZHJhd1llYXIsIGRyYXdNb250aCArIHN0ZXBNb250aHMsIDEgKSApLFxuXHRcdFx0dGhpcy5fZ2V0Rm9ybWF0Q29uZmlnKCBpbnN0ICkgKSApO1xuXG5cdFx0bmV4dCA9ICggdGhpcy5fY2FuQWRqdXN0TW9udGgoIGluc3QsICsxLCBkcmF3WWVhciwgZHJhd01vbnRoICkgP1xuXHRcdFx0XCI8YSBjbGFzcz0ndWktZGF0ZXBpY2tlci1uZXh0IHVpLWNvcm5lci1hbGwnIGRhdGEtaGFuZGxlcj0nbmV4dCcgZGF0YS1ldmVudD0nY2xpY2snXCIgK1xuXHRcdFx0XCIgdGl0bGU9J1wiICsgbmV4dFRleHQgKyBcIic+PHNwYW4gY2xhc3M9J3VpLWljb24gdWktaWNvbi1jaXJjbGUtdHJpYW5nbGUtXCIgKyAoIGlzUlRMID8gXCJ3XCIgOiBcImVcIiApICsgXCInPlwiICsgbmV4dFRleHQgKyBcIjwvc3Bhbj48L2E+XCIgOlxuXHRcdFx0KCBoaWRlSWZOb1ByZXZOZXh0ID8gXCJcIiA6IFwiPGEgY2xhc3M9J3VpLWRhdGVwaWNrZXItbmV4dCB1aS1jb3JuZXItYWxsIHVpLXN0YXRlLWRpc2FibGVkJyB0aXRsZT0nXCIgKyBuZXh0VGV4dCArIFwiJz48c3BhbiBjbGFzcz0ndWktaWNvbiB1aS1pY29uLWNpcmNsZS10cmlhbmdsZS1cIiArICggaXNSVEwgPyBcIndcIiA6IFwiZVwiICkgKyBcIic+XCIgKyBuZXh0VGV4dCArIFwiPC9zcGFuPjwvYT5cIiApICk7XG5cblx0XHRjdXJyZW50VGV4dCA9IHRoaXMuX2dldCggaW5zdCwgXCJjdXJyZW50VGV4dFwiICk7XG5cdFx0Z290b0RhdGUgPSAoIHRoaXMuX2dldCggaW5zdCwgXCJnb3RvQ3VycmVudFwiICkgJiYgaW5zdC5jdXJyZW50RGF5ID8gY3VycmVudERhdGUgOiB0b2RheSApO1xuXHRcdGN1cnJlbnRUZXh0ID0gKCAhbmF2aWdhdGlvbkFzRGF0ZUZvcm1hdCA/IGN1cnJlbnRUZXh0IDpcblx0XHRcdHRoaXMuZm9ybWF0RGF0ZSggY3VycmVudFRleHQsIGdvdG9EYXRlLCB0aGlzLl9nZXRGb3JtYXRDb25maWcoIGluc3QgKSApICk7XG5cblx0XHRjb250cm9scyA9ICggIWluc3QuaW5saW5lID8gXCI8YnV0dG9uIHR5cGU9J2J1dHRvbicgY2xhc3M9J3VpLWRhdGVwaWNrZXItY2xvc2UgdWktc3RhdGUtZGVmYXVsdCB1aS1wcmlvcml0eS1wcmltYXJ5IHVpLWNvcm5lci1hbGwnIGRhdGEtaGFuZGxlcj0naGlkZScgZGF0YS1ldmVudD0nY2xpY2snPlwiICtcblx0XHRcdHRoaXMuX2dldCggaW5zdCwgXCJjbG9zZVRleHRcIiApICsgXCI8L2J1dHRvbj5cIiA6IFwiXCIgKTtcblxuXHRcdGJ1dHRvblBhbmVsID0gKCBzaG93QnV0dG9uUGFuZWwgKSA/IFwiPGRpdiBjbGFzcz0ndWktZGF0ZXBpY2tlci1idXR0b25wYW5lIHVpLXdpZGdldC1jb250ZW50Jz5cIiArICggaXNSVEwgPyBjb250cm9scyA6IFwiXCIgKSArXG5cdFx0XHQoIHRoaXMuX2lzSW5SYW5nZSggaW5zdCwgZ290b0RhdGUgKSA/IFwiPGJ1dHRvbiB0eXBlPSdidXR0b24nIGNsYXNzPSd1aS1kYXRlcGlja2VyLWN1cnJlbnQgdWktc3RhdGUtZGVmYXVsdCB1aS1wcmlvcml0eS1zZWNvbmRhcnkgdWktY29ybmVyLWFsbCcgZGF0YS1oYW5kbGVyPSd0b2RheScgZGF0YS1ldmVudD0nY2xpY2snXCIgK1xuXHRcdFx0XCI+XCIgKyBjdXJyZW50VGV4dCArIFwiPC9idXR0b24+XCIgOiBcIlwiICkgKyAoIGlzUlRMID8gXCJcIiA6IGNvbnRyb2xzICkgKyBcIjwvZGl2PlwiIDogXCJcIjtcblxuXHRcdGZpcnN0RGF5ID0gcGFyc2VJbnQoIHRoaXMuX2dldCggaW5zdCwgXCJmaXJzdERheVwiICksIDEwICk7XG5cdFx0Zmlyc3REYXkgPSAoIGlzTmFOKCBmaXJzdERheSApID8gMCA6IGZpcnN0RGF5ICk7XG5cblx0XHRzaG93V2VlayA9IHRoaXMuX2dldCggaW5zdCwgXCJzaG93V2Vla1wiICk7XG5cdFx0ZGF5TmFtZXMgPSB0aGlzLl9nZXQoIGluc3QsIFwiZGF5TmFtZXNcIiApO1xuXHRcdGRheU5hbWVzTWluID0gdGhpcy5fZ2V0KCBpbnN0LCBcImRheU5hbWVzTWluXCIgKTtcblx0XHRtb250aE5hbWVzID0gdGhpcy5fZ2V0KCBpbnN0LCBcIm1vbnRoTmFtZXNcIiApO1xuXHRcdG1vbnRoTmFtZXNTaG9ydCA9IHRoaXMuX2dldCggaW5zdCwgXCJtb250aE5hbWVzU2hvcnRcIiApO1xuXHRcdGJlZm9yZVNob3dEYXkgPSB0aGlzLl9nZXQoIGluc3QsIFwiYmVmb3JlU2hvd0RheVwiICk7XG5cdFx0c2hvd090aGVyTW9udGhzID0gdGhpcy5fZ2V0KCBpbnN0LCBcInNob3dPdGhlck1vbnRoc1wiICk7XG5cdFx0c2VsZWN0T3RoZXJNb250aHMgPSB0aGlzLl9nZXQoIGluc3QsIFwic2VsZWN0T3RoZXJNb250aHNcIiApO1xuXHRcdGRlZmF1bHREYXRlID0gdGhpcy5fZ2V0RGVmYXVsdERhdGUoIGluc3QgKTtcblx0XHRodG1sID0gXCJcIjtcblxuXHRcdGZvciAoIHJvdyA9IDA7IHJvdyA8IG51bU1vbnRoc1sgMCBdOyByb3crKyApIHtcblx0XHRcdGdyb3VwID0gXCJcIjtcblx0XHRcdHRoaXMubWF4Um93cyA9IDQ7XG5cdFx0XHRmb3IgKCBjb2wgPSAwOyBjb2wgPCBudW1Nb250aHNbIDEgXTsgY29sKysgKSB7XG5cdFx0XHRcdHNlbGVjdGVkRGF0ZSA9IHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBuZXcgRGF0ZSggZHJhd1llYXIsIGRyYXdNb250aCwgaW5zdC5zZWxlY3RlZERheSApICk7XG5cdFx0XHRcdGNvcm5lckNsYXNzID0gXCIgdWktY29ybmVyLWFsbFwiO1xuXHRcdFx0XHRjYWxlbmRlciA9IFwiXCI7XG5cdFx0XHRcdGlmICggaXNNdWx0aU1vbnRoICkge1xuXHRcdFx0XHRcdGNhbGVuZGVyICs9IFwiPGRpdiBjbGFzcz0ndWktZGF0ZXBpY2tlci1ncm91cFwiO1xuXHRcdFx0XHRcdGlmICggbnVtTW9udGhzWyAxIF0gPiAxICkge1xuXHRcdFx0XHRcdFx0c3dpdGNoICggY29sICkge1xuXHRcdFx0XHRcdFx0XHRjYXNlIDA6IGNhbGVuZGVyICs9IFwiIHVpLWRhdGVwaWNrZXItZ3JvdXAtZmlyc3RcIjtcblx0XHRcdFx0XHRcdFx0XHRjb3JuZXJDbGFzcyA9IFwiIHVpLWNvcm5lci1cIiArICggaXNSVEwgPyBcInJpZ2h0XCIgOiBcImxlZnRcIiApOyBicmVhaztcblx0XHRcdFx0XHRcdFx0Y2FzZSBudW1Nb250aHNbIDEgXSAtIDE6IGNhbGVuZGVyICs9IFwiIHVpLWRhdGVwaWNrZXItZ3JvdXAtbGFzdFwiO1xuXHRcdFx0XHRcdFx0XHRcdGNvcm5lckNsYXNzID0gXCIgdWktY29ybmVyLVwiICsgKCBpc1JUTCA/IFwibGVmdFwiIDogXCJyaWdodFwiICk7IGJyZWFrO1xuXHRcdFx0XHRcdFx0XHRkZWZhdWx0OiBjYWxlbmRlciArPSBcIiB1aS1kYXRlcGlja2VyLWdyb3VwLW1pZGRsZVwiOyBjb3JuZXJDbGFzcyA9IFwiXCI7IGJyZWFrO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRjYWxlbmRlciArPSBcIic+XCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0Y2FsZW5kZXIgKz0gXCI8ZGl2IGNsYXNzPSd1aS1kYXRlcGlja2VyLWhlYWRlciB1aS13aWRnZXQtaGVhZGVyIHVpLWhlbHBlci1jbGVhcmZpeFwiICsgY29ybmVyQ2xhc3MgKyBcIic+XCIgK1xuXHRcdFx0XHRcdCggL2FsbHxsZWZ0Ly50ZXN0KCBjb3JuZXJDbGFzcyApICYmIHJvdyA9PT0gMCA/ICggaXNSVEwgPyBuZXh0IDogcHJldiApIDogXCJcIiApICtcblx0XHRcdFx0XHQoIC9hbGx8cmlnaHQvLnRlc3QoIGNvcm5lckNsYXNzICkgJiYgcm93ID09PSAwID8gKCBpc1JUTCA/IHByZXYgOiBuZXh0ICkgOiBcIlwiICkgK1xuXHRcdFx0XHRcdHRoaXMuX2dlbmVyYXRlTW9udGhZZWFySGVhZGVyKCBpbnN0LCBkcmF3TW9udGgsIGRyYXdZZWFyLCBtaW5EYXRlLCBtYXhEYXRlLFxuXHRcdFx0XHRcdHJvdyA+IDAgfHwgY29sID4gMCwgbW9udGhOYW1lcywgbW9udGhOYW1lc1Nob3J0ICkgKyAvLyBkcmF3IG1vbnRoIGhlYWRlcnNcblx0XHRcdFx0XHRcIjwvZGl2Pjx0YWJsZSBjbGFzcz0ndWktZGF0ZXBpY2tlci1jYWxlbmRhcic+PHRoZWFkPlwiICtcblx0XHRcdFx0XHRcIjx0cj5cIjtcblx0XHRcdFx0dGhlYWQgPSAoIHNob3dXZWVrID8gXCI8dGggY2xhc3M9J3VpLWRhdGVwaWNrZXItd2Vlay1jb2wnPlwiICsgdGhpcy5fZ2V0KCBpbnN0LCBcIndlZWtIZWFkZXJcIiApICsgXCI8L3RoPlwiIDogXCJcIiApO1xuXHRcdFx0XHRmb3IgKCBkb3cgPSAwOyBkb3cgPCA3OyBkb3crKyApIHsgLy8gZGF5cyBvZiB0aGUgd2Vla1xuXHRcdFx0XHRcdGRheSA9ICggZG93ICsgZmlyc3REYXkgKSAlIDc7XG5cdFx0XHRcdFx0dGhlYWQgKz0gXCI8dGggc2NvcGU9J2NvbCdcIiArICggKCBkb3cgKyBmaXJzdERheSArIDYgKSAlIDcgPj0gNSA/IFwiIGNsYXNzPSd1aS1kYXRlcGlja2VyLXdlZWstZW5kJ1wiIDogXCJcIiApICsgXCI+XCIgK1xuXHRcdFx0XHRcdFx0XCI8c3BhbiB0aXRsZT0nXCIgKyBkYXlOYW1lc1sgZGF5IF0gKyBcIic+XCIgKyBkYXlOYW1lc01pblsgZGF5IF0gKyBcIjwvc3Bhbj48L3RoPlwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGNhbGVuZGVyICs9IHRoZWFkICsgXCI8L3RyPjwvdGhlYWQ+PHRib2R5PlwiO1xuXHRcdFx0XHRkYXlzSW5Nb250aCA9IHRoaXMuX2dldERheXNJbk1vbnRoKCBkcmF3WWVhciwgZHJhd01vbnRoICk7XG5cdFx0XHRcdGlmICggZHJhd1llYXIgPT09IGluc3Quc2VsZWN0ZWRZZWFyICYmIGRyYXdNb250aCA9PT0gaW5zdC5zZWxlY3RlZE1vbnRoICkge1xuXHRcdFx0XHRcdGluc3Quc2VsZWN0ZWREYXkgPSBNYXRoLm1pbiggaW5zdC5zZWxlY3RlZERheSwgZGF5c0luTW9udGggKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRsZWFkRGF5cyA9ICggdGhpcy5fZ2V0Rmlyc3REYXlPZk1vbnRoKCBkcmF3WWVhciwgZHJhd01vbnRoICkgLSBmaXJzdERheSArIDcgKSAlIDc7XG5cdFx0XHRcdGN1clJvd3MgPSBNYXRoLmNlaWwoICggbGVhZERheXMgKyBkYXlzSW5Nb250aCApIC8gNyApOyAvLyBjYWxjdWxhdGUgdGhlIG51bWJlciBvZiByb3dzIHRvIGdlbmVyYXRlXG5cdFx0XHRcdG51bVJvd3MgPSAoIGlzTXVsdGlNb250aCA/IHRoaXMubWF4Um93cyA+IGN1clJvd3MgPyB0aGlzLm1heFJvd3MgOiBjdXJSb3dzIDogY3VyUm93cyApOyAvL0lmIG11bHRpcGxlIG1vbnRocywgdXNlIHRoZSBoaWdoZXIgbnVtYmVyIG9mIHJvd3MgKHNlZSAjNzA0Mylcblx0XHRcdFx0dGhpcy5tYXhSb3dzID0gbnVtUm93cztcblx0XHRcdFx0cHJpbnREYXRlID0gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCBkcmF3WWVhciwgZHJhd01vbnRoLCAxIC0gbGVhZERheXMgKSApO1xuXHRcdFx0XHRmb3IgKCBkUm93ID0gMDsgZFJvdyA8IG51bVJvd3M7IGRSb3crKyApIHsgLy8gY3JlYXRlIGRhdGUgcGlja2VyIHJvd3Ncblx0XHRcdFx0XHRjYWxlbmRlciArPSBcIjx0cj5cIjtcblx0XHRcdFx0XHR0Ym9keSA9ICggIXNob3dXZWVrID8gXCJcIiA6IFwiPHRkIGNsYXNzPSd1aS1kYXRlcGlja2VyLXdlZWstY29sJz5cIiArXG5cdFx0XHRcdFx0XHR0aGlzLl9nZXQoIGluc3QsIFwiY2FsY3VsYXRlV2Vla1wiICkoIHByaW50RGF0ZSApICsgXCI8L3RkPlwiICk7XG5cdFx0XHRcdFx0Zm9yICggZG93ID0gMDsgZG93IDwgNzsgZG93KysgKSB7IC8vIGNyZWF0ZSBkYXRlIHBpY2tlciBkYXlzXG5cdFx0XHRcdFx0XHRkYXlTZXR0aW5ncyA9ICggYmVmb3JlU2hvd0RheSA/XG5cdFx0XHRcdFx0XHRcdGJlZm9yZVNob3dEYXkuYXBwbHkoICggaW5zdC5pbnB1dCA/IGluc3QuaW5wdXRbIDAgXSA6IG51bGwgKSwgWyBwcmludERhdGUgXSApIDogWyB0cnVlLCBcIlwiIF0gKTtcblx0XHRcdFx0XHRcdG90aGVyTW9udGggPSAoIHByaW50RGF0ZS5nZXRNb250aCgpICE9PSBkcmF3TW9udGggKTtcblx0XHRcdFx0XHRcdHVuc2VsZWN0YWJsZSA9ICggb3RoZXJNb250aCAmJiAhc2VsZWN0T3RoZXJNb250aHMgKSB8fCAhZGF5U2V0dGluZ3NbIDAgXSB8fFxuXHRcdFx0XHRcdFx0XHQoIG1pbkRhdGUgJiYgcHJpbnREYXRlIDwgbWluRGF0ZSApIHx8ICggbWF4RGF0ZSAmJiBwcmludERhdGUgPiBtYXhEYXRlICk7XG5cdFx0XHRcdFx0XHR0Ym9keSArPSBcIjx0ZCBjbGFzcz0nXCIgK1xuXHRcdFx0XHRcdFx0XHQoICggZG93ICsgZmlyc3REYXkgKyA2ICkgJSA3ID49IDUgPyBcIiB1aS1kYXRlcGlja2VyLXdlZWstZW5kXCIgOiBcIlwiICkgKyAvLyBoaWdobGlnaHQgd2Vla2VuZHNcblx0XHRcdFx0XHRcdFx0KCBvdGhlck1vbnRoID8gXCIgdWktZGF0ZXBpY2tlci1vdGhlci1tb250aFwiIDogXCJcIiApICsgLy8gaGlnaGxpZ2h0IGRheXMgZnJvbSBvdGhlciBtb250aHNcblx0XHRcdFx0XHRcdFx0KCAoIHByaW50RGF0ZS5nZXRUaW1lKCkgPT09IHNlbGVjdGVkRGF0ZS5nZXRUaW1lKCkgJiYgZHJhd01vbnRoID09PSBpbnN0LnNlbGVjdGVkTW9udGggJiYgaW5zdC5fa2V5RXZlbnQgKSB8fCAvLyB1c2VyIHByZXNzZWQga2V5XG5cdFx0XHRcdFx0XHRcdCggZGVmYXVsdERhdGUuZ2V0VGltZSgpID09PSBwcmludERhdGUuZ2V0VGltZSgpICYmIGRlZmF1bHREYXRlLmdldFRpbWUoKSA9PT0gc2VsZWN0ZWREYXRlLmdldFRpbWUoKSApID9cblxuXHRcdFx0XHRcdFx0XHQvLyBvciBkZWZhdWx0RGF0ZSBpcyBjdXJyZW50IHByaW50ZWREYXRlIGFuZCBkZWZhdWx0RGF0ZSBpcyBzZWxlY3RlZERhdGVcblx0XHRcdFx0XHRcdFx0XCIgXCIgKyB0aGlzLl9kYXlPdmVyQ2xhc3MgOiBcIlwiICkgKyAvLyBoaWdobGlnaHQgc2VsZWN0ZWQgZGF5XG5cdFx0XHRcdFx0XHRcdCggdW5zZWxlY3RhYmxlID8gXCIgXCIgKyB0aGlzLl91bnNlbGVjdGFibGVDbGFzcyArIFwiIHVpLXN0YXRlLWRpc2FibGVkXCIgOiBcIlwiICkgKyAgLy8gaGlnaGxpZ2h0IHVuc2VsZWN0YWJsZSBkYXlzXG5cdFx0XHRcdFx0XHRcdCggb3RoZXJNb250aCAmJiAhc2hvd090aGVyTW9udGhzID8gXCJcIiA6IFwiIFwiICsgZGF5U2V0dGluZ3NbIDEgXSArIC8vIGhpZ2hsaWdodCBjdXN0b20gZGF0ZXNcblx0XHRcdFx0XHRcdFx0KCBwcmludERhdGUuZ2V0VGltZSgpID09PSBjdXJyZW50RGF0ZS5nZXRUaW1lKCkgPyBcIiBcIiArIHRoaXMuX2N1cnJlbnRDbGFzcyA6IFwiXCIgKSArIC8vIGhpZ2hsaWdodCBzZWxlY3RlZCBkYXlcblx0XHRcdFx0XHRcdFx0KCBwcmludERhdGUuZ2V0VGltZSgpID09PSB0b2RheS5nZXRUaW1lKCkgPyBcIiB1aS1kYXRlcGlja2VyLXRvZGF5XCIgOiBcIlwiICkgKSArIFwiJ1wiICsgLy8gaGlnaGxpZ2h0IHRvZGF5IChpZiBkaWZmZXJlbnQpXG5cdFx0XHRcdFx0XHRcdCggKCAhb3RoZXJNb250aCB8fCBzaG93T3RoZXJNb250aHMgKSAmJiBkYXlTZXR0aW5nc1sgMiBdID8gXCIgdGl0bGU9J1wiICsgZGF5U2V0dGluZ3NbIDIgXS5yZXBsYWNlKCAvJy9nLCBcIiYjMzk7XCIgKSArIFwiJ1wiIDogXCJcIiApICsgLy8gY2VsbCB0aXRsZVxuXHRcdFx0XHRcdFx0XHQoIHVuc2VsZWN0YWJsZSA/IFwiXCIgOiBcIiBkYXRhLWhhbmRsZXI9J3NlbGVjdERheScgZGF0YS1ldmVudD0nY2xpY2snIGRhdGEtbW9udGg9J1wiICsgcHJpbnREYXRlLmdldE1vbnRoKCkgKyBcIicgZGF0YS15ZWFyPSdcIiArIHByaW50RGF0ZS5nZXRGdWxsWWVhcigpICsgXCInXCIgKSArIFwiPlwiICsgLy8gYWN0aW9uc1xuXHRcdFx0XHRcdFx0XHQoIG90aGVyTW9udGggJiYgIXNob3dPdGhlck1vbnRocyA/IFwiJiN4YTA7XCIgOiAvLyBkaXNwbGF5IGZvciBvdGhlciBtb250aHNcblx0XHRcdFx0XHRcdFx0KCB1bnNlbGVjdGFibGUgPyBcIjxzcGFuIGNsYXNzPSd1aS1zdGF0ZS1kZWZhdWx0Jz5cIiArIHByaW50RGF0ZS5nZXREYXRlKCkgKyBcIjwvc3Bhbj5cIiA6IFwiPGEgY2xhc3M9J3VpLXN0YXRlLWRlZmF1bHRcIiArXG5cdFx0XHRcdFx0XHRcdCggcHJpbnREYXRlLmdldFRpbWUoKSA9PT0gdG9kYXkuZ2V0VGltZSgpID8gXCIgdWktc3RhdGUtaGlnaGxpZ2h0XCIgOiBcIlwiICkgK1xuXHRcdFx0XHRcdFx0XHQoIHByaW50RGF0ZS5nZXRUaW1lKCkgPT09IGN1cnJlbnREYXRlLmdldFRpbWUoKSA/IFwiIHVpLXN0YXRlLWFjdGl2ZVwiIDogXCJcIiApICsgLy8gaGlnaGxpZ2h0IHNlbGVjdGVkIGRheVxuXHRcdFx0XHRcdFx0XHQoIG90aGVyTW9udGggPyBcIiB1aS1wcmlvcml0eS1zZWNvbmRhcnlcIiA6IFwiXCIgKSArIC8vIGRpc3Rpbmd1aXNoIGRhdGVzIGZyb20gb3RoZXIgbW9udGhzXG5cdFx0XHRcdFx0XHRcdFwiJyBocmVmPScjJz5cIiArIHByaW50RGF0ZS5nZXREYXRlKCkgKyBcIjwvYT5cIiApICkgKyBcIjwvdGQ+XCI7IC8vIGRpc3BsYXkgc2VsZWN0YWJsZSBkYXRlXG5cdFx0XHRcdFx0XHRwcmludERhdGUuc2V0RGF0ZSggcHJpbnREYXRlLmdldERhdGUoKSArIDEgKTtcblx0XHRcdFx0XHRcdHByaW50RGF0ZSA9IHRoaXMuX2RheWxpZ2h0U2F2aW5nQWRqdXN0KCBwcmludERhdGUgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0Y2FsZW5kZXIgKz0gdGJvZHkgKyBcIjwvdHI+XCI7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZHJhd01vbnRoKys7XG5cdFx0XHRcdGlmICggZHJhd01vbnRoID4gMTEgKSB7XG5cdFx0XHRcdFx0ZHJhd01vbnRoID0gMDtcblx0XHRcdFx0XHRkcmF3WWVhcisrO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGNhbGVuZGVyICs9IFwiPC90Ym9keT48L3RhYmxlPlwiICsgKCBpc011bHRpTW9udGggPyBcIjwvZGl2PlwiICtcblx0XHRcdFx0XHRcdFx0KCAoIG51bU1vbnRoc1sgMCBdID4gMCAmJiBjb2wgPT09IG51bU1vbnRoc1sgMSBdIC0gMSApID8gXCI8ZGl2IGNsYXNzPSd1aS1kYXRlcGlja2VyLXJvdy1icmVhayc+PC9kaXY+XCIgOiBcIlwiICkgOiBcIlwiICk7XG5cdFx0XHRcdGdyb3VwICs9IGNhbGVuZGVyO1xuXHRcdFx0fVxuXHRcdFx0aHRtbCArPSBncm91cDtcblx0XHR9XG5cdFx0aHRtbCArPSBidXR0b25QYW5lbDtcblx0XHRpbnN0Ll9rZXlFdmVudCA9IGZhbHNlO1xuXHRcdHJldHVybiBodG1sO1xuXHR9LFxuXG5cdC8qIEdlbmVyYXRlIHRoZSBtb250aCBhbmQgeWVhciBoZWFkZXIuICovXG5cdF9nZW5lcmF0ZU1vbnRoWWVhckhlYWRlcjogZnVuY3Rpb24oIGluc3QsIGRyYXdNb250aCwgZHJhd1llYXIsIG1pbkRhdGUsIG1heERhdGUsXG5cdFx0XHRzZWNvbmRhcnksIG1vbnRoTmFtZXMsIG1vbnRoTmFtZXNTaG9ydCApIHtcblxuXHRcdHZhciBpbk1pblllYXIsIGluTWF4WWVhciwgbW9udGgsIHllYXJzLCB0aGlzWWVhciwgZGV0ZXJtaW5lWWVhciwgeWVhciwgZW5kWWVhcixcblx0XHRcdGNoYW5nZU1vbnRoID0gdGhpcy5fZ2V0KCBpbnN0LCBcImNoYW5nZU1vbnRoXCIgKSxcblx0XHRcdGNoYW5nZVllYXIgPSB0aGlzLl9nZXQoIGluc3QsIFwiY2hhbmdlWWVhclwiICksXG5cdFx0XHRzaG93TW9udGhBZnRlclllYXIgPSB0aGlzLl9nZXQoIGluc3QsIFwic2hvd01vbnRoQWZ0ZXJZZWFyXCIgKSxcblx0XHRcdGh0bWwgPSBcIjxkaXYgY2xhc3M9J3VpLWRhdGVwaWNrZXItdGl0bGUnPlwiLFxuXHRcdFx0bW9udGhIdG1sID0gXCJcIjtcblxuXHRcdC8vIE1vbnRoIHNlbGVjdGlvblxuXHRcdGlmICggc2Vjb25kYXJ5IHx8ICFjaGFuZ2VNb250aCApIHtcblx0XHRcdG1vbnRoSHRtbCArPSBcIjxzcGFuIGNsYXNzPSd1aS1kYXRlcGlja2VyLW1vbnRoJz5cIiArIG1vbnRoTmFtZXNbIGRyYXdNb250aCBdICsgXCI8L3NwYW4+XCI7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGluTWluWWVhciA9ICggbWluRGF0ZSAmJiBtaW5EYXRlLmdldEZ1bGxZZWFyKCkgPT09IGRyYXdZZWFyICk7XG5cdFx0XHRpbk1heFllYXIgPSAoIG1heERhdGUgJiYgbWF4RGF0ZS5nZXRGdWxsWWVhcigpID09PSBkcmF3WWVhciApO1xuXHRcdFx0bW9udGhIdG1sICs9IFwiPHNlbGVjdCBjbGFzcz0ndWktZGF0ZXBpY2tlci1tb250aCcgZGF0YS1oYW5kbGVyPSdzZWxlY3RNb250aCcgZGF0YS1ldmVudD0nY2hhbmdlJz5cIjtcblx0XHRcdGZvciAoIG1vbnRoID0gMDsgbW9udGggPCAxMjsgbW9udGgrKyApIHtcblx0XHRcdFx0aWYgKCAoICFpbk1pblllYXIgfHwgbW9udGggPj0gbWluRGF0ZS5nZXRNb250aCgpICkgJiYgKCAhaW5NYXhZZWFyIHx8IG1vbnRoIDw9IG1heERhdGUuZ2V0TW9udGgoKSApICkge1xuXHRcdFx0XHRcdG1vbnRoSHRtbCArPSBcIjxvcHRpb24gdmFsdWU9J1wiICsgbW9udGggKyBcIidcIiArXG5cdFx0XHRcdFx0XHQoIG1vbnRoID09PSBkcmF3TW9udGggPyBcIiBzZWxlY3RlZD0nc2VsZWN0ZWQnXCIgOiBcIlwiICkgK1xuXHRcdFx0XHRcdFx0XCI+XCIgKyBtb250aE5hbWVzU2hvcnRbIG1vbnRoIF0gKyBcIjwvb3B0aW9uPlwiO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0XHRtb250aEh0bWwgKz0gXCI8L3NlbGVjdD5cIjtcblx0XHR9XG5cblx0XHRpZiAoICFzaG93TW9udGhBZnRlclllYXIgKSB7XG5cdFx0XHRodG1sICs9IG1vbnRoSHRtbCArICggc2Vjb25kYXJ5IHx8ICEoIGNoYW5nZU1vbnRoICYmIGNoYW5nZVllYXIgKSA/IFwiJiN4YTA7XCIgOiBcIlwiICk7XG5cdFx0fVxuXG5cdFx0Ly8gWWVhciBzZWxlY3Rpb25cblx0XHRpZiAoICFpbnN0LnllYXJzaHRtbCApIHtcblx0XHRcdGluc3QueWVhcnNodG1sID0gXCJcIjtcblx0XHRcdGlmICggc2Vjb25kYXJ5IHx8ICFjaGFuZ2VZZWFyICkge1xuXHRcdFx0XHRodG1sICs9IFwiPHNwYW4gY2xhc3M9J3VpLWRhdGVwaWNrZXIteWVhcic+XCIgKyBkcmF3WWVhciArIFwiPC9zcGFuPlwiO1xuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBkZXRlcm1pbmUgcmFuZ2Ugb2YgeWVhcnMgdG8gZGlzcGxheVxuXHRcdFx0XHR5ZWFycyA9IHRoaXMuX2dldCggaW5zdCwgXCJ5ZWFyUmFuZ2VcIiApLnNwbGl0KCBcIjpcIiApO1xuXHRcdFx0XHR0aGlzWWVhciA9IG5ldyBEYXRlKCkuZ2V0RnVsbFllYXIoKTtcblx0XHRcdFx0ZGV0ZXJtaW5lWWVhciA9IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRcdFx0XHR2YXIgeWVhciA9ICggdmFsdWUubWF0Y2goIC9jWytcXC1dLiovICkgPyBkcmF3WWVhciArIHBhcnNlSW50KCB2YWx1ZS5zdWJzdHJpbmcoIDEgKSwgMTAgKSA6XG5cdFx0XHRcdFx0XHQoIHZhbHVlLm1hdGNoKCAvWytcXC1dLiovICkgPyB0aGlzWWVhciArIHBhcnNlSW50KCB2YWx1ZSwgMTAgKSA6XG5cdFx0XHRcdFx0XHRwYXJzZUludCggdmFsdWUsIDEwICkgKSApO1xuXHRcdFx0XHRcdHJldHVybiAoIGlzTmFOKCB5ZWFyICkgPyB0aGlzWWVhciA6IHllYXIgKTtcblx0XHRcdFx0fTtcblx0XHRcdFx0eWVhciA9IGRldGVybWluZVllYXIoIHllYXJzWyAwIF0gKTtcblx0XHRcdFx0ZW5kWWVhciA9IE1hdGgubWF4KCB5ZWFyLCBkZXRlcm1pbmVZZWFyKCB5ZWFyc1sgMSBdIHx8IFwiXCIgKSApO1xuXHRcdFx0XHR5ZWFyID0gKCBtaW5EYXRlID8gTWF0aC5tYXgoIHllYXIsIG1pbkRhdGUuZ2V0RnVsbFllYXIoKSApIDogeWVhciApO1xuXHRcdFx0XHRlbmRZZWFyID0gKCBtYXhEYXRlID8gTWF0aC5taW4oIGVuZFllYXIsIG1heERhdGUuZ2V0RnVsbFllYXIoKSApIDogZW5kWWVhciApO1xuXHRcdFx0XHRpbnN0LnllYXJzaHRtbCArPSBcIjxzZWxlY3QgY2xhc3M9J3VpLWRhdGVwaWNrZXIteWVhcicgZGF0YS1oYW5kbGVyPSdzZWxlY3RZZWFyJyBkYXRhLWV2ZW50PSdjaGFuZ2UnPlwiO1xuXHRcdFx0XHRmb3IgKCA7IHllYXIgPD0gZW5kWWVhcjsgeWVhcisrICkge1xuXHRcdFx0XHRcdGluc3QueWVhcnNodG1sICs9IFwiPG9wdGlvbiB2YWx1ZT0nXCIgKyB5ZWFyICsgXCInXCIgK1xuXHRcdFx0XHRcdFx0KCB5ZWFyID09PSBkcmF3WWVhciA/IFwiIHNlbGVjdGVkPSdzZWxlY3RlZCdcIiA6IFwiXCIgKSArXG5cdFx0XHRcdFx0XHRcIj5cIiArIHllYXIgKyBcIjwvb3B0aW9uPlwiO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGluc3QueWVhcnNodG1sICs9IFwiPC9zZWxlY3Q+XCI7XG5cblx0XHRcdFx0aHRtbCArPSBpbnN0LnllYXJzaHRtbDtcblx0XHRcdFx0aW5zdC55ZWFyc2h0bWwgPSBudWxsO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGh0bWwgKz0gdGhpcy5fZ2V0KCBpbnN0LCBcInllYXJTdWZmaXhcIiApO1xuXHRcdGlmICggc2hvd01vbnRoQWZ0ZXJZZWFyICkge1xuXHRcdFx0aHRtbCArPSAoIHNlY29uZGFyeSB8fCAhKCBjaGFuZ2VNb250aCAmJiBjaGFuZ2VZZWFyICkgPyBcIiYjeGEwO1wiIDogXCJcIiApICsgbW9udGhIdG1sO1xuXHRcdH1cblx0XHRodG1sICs9IFwiPC9kaXY+XCI7IC8vIENsb3NlIGRhdGVwaWNrZXJfaGVhZGVyXG5cdFx0cmV0dXJuIGh0bWw7XG5cdH0sXG5cblx0LyogQWRqdXN0IG9uZSBvZiB0aGUgZGF0ZSBzdWItZmllbGRzLiAqL1xuXHRfYWRqdXN0SW5zdERhdGU6IGZ1bmN0aW9uKCBpbnN0LCBvZmZzZXQsIHBlcmlvZCApIHtcblx0XHR2YXIgeWVhciA9IGluc3Quc2VsZWN0ZWRZZWFyICsgKCBwZXJpb2QgPT09IFwiWVwiID8gb2Zmc2V0IDogMCApLFxuXHRcdFx0bW9udGggPSBpbnN0LnNlbGVjdGVkTW9udGggKyAoIHBlcmlvZCA9PT0gXCJNXCIgPyBvZmZzZXQgOiAwICksXG5cdFx0XHRkYXkgPSBNYXRoLm1pbiggaW5zdC5zZWxlY3RlZERheSwgdGhpcy5fZ2V0RGF5c0luTW9udGgoIHllYXIsIG1vbnRoICkgKSArICggcGVyaW9kID09PSBcIkRcIiA/IG9mZnNldCA6IDAgKSxcblx0XHRcdGRhdGUgPSB0aGlzLl9yZXN0cmljdE1pbk1heCggaW5zdCwgdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCB5ZWFyLCBtb250aCwgZGF5ICkgKSApO1xuXG5cdFx0aW5zdC5zZWxlY3RlZERheSA9IGRhdGUuZ2V0RGF0ZSgpO1xuXHRcdGluc3QuZHJhd01vbnRoID0gaW5zdC5zZWxlY3RlZE1vbnRoID0gZGF0ZS5nZXRNb250aCgpO1xuXHRcdGluc3QuZHJhd1llYXIgPSBpbnN0LnNlbGVjdGVkWWVhciA9IGRhdGUuZ2V0RnVsbFllYXIoKTtcblx0XHRpZiAoIHBlcmlvZCA9PT0gXCJNXCIgfHwgcGVyaW9kID09PSBcIllcIiApIHtcblx0XHRcdHRoaXMuX25vdGlmeUNoYW5nZSggaW5zdCApO1xuXHRcdH1cblx0fSxcblxuXHQvKiBFbnN1cmUgYSBkYXRlIGlzIHdpdGhpbiBhbnkgbWluL21heCBib3VuZHMuICovXG5cdF9yZXN0cmljdE1pbk1heDogZnVuY3Rpb24oIGluc3QsIGRhdGUgKSB7XG5cdFx0dmFyIG1pbkRhdGUgPSB0aGlzLl9nZXRNaW5NYXhEYXRlKCBpbnN0LCBcIm1pblwiICksXG5cdFx0XHRtYXhEYXRlID0gdGhpcy5fZ2V0TWluTWF4RGF0ZSggaW5zdCwgXCJtYXhcIiApLFxuXHRcdFx0bmV3RGF0ZSA9ICggbWluRGF0ZSAmJiBkYXRlIDwgbWluRGF0ZSA/IG1pbkRhdGUgOiBkYXRlICk7XG5cdFx0cmV0dXJuICggbWF4RGF0ZSAmJiBuZXdEYXRlID4gbWF4RGF0ZSA/IG1heERhdGUgOiBuZXdEYXRlICk7XG5cdH0sXG5cblx0LyogTm90aWZ5IGNoYW5nZSBvZiBtb250aC95ZWFyLiAqL1xuXHRfbm90aWZ5Q2hhbmdlOiBmdW5jdGlvbiggaW5zdCApIHtcblx0XHR2YXIgb25DaGFuZ2UgPSB0aGlzLl9nZXQoIGluc3QsIFwib25DaGFuZ2VNb250aFllYXJcIiApO1xuXHRcdGlmICggb25DaGFuZ2UgKSB7XG5cdFx0XHRvbkNoYW5nZS5hcHBseSggKCBpbnN0LmlucHV0ID8gaW5zdC5pbnB1dFsgMCBdIDogbnVsbCApLFxuXHRcdFx0XHRbIGluc3Quc2VsZWN0ZWRZZWFyLCBpbnN0LnNlbGVjdGVkTW9udGggKyAxLCBpbnN0IF0gKTtcblx0XHR9XG5cdH0sXG5cblx0LyogRGV0ZXJtaW5lIHRoZSBudW1iZXIgb2YgbW9udGhzIHRvIHNob3cuICovXG5cdF9nZXROdW1iZXJPZk1vbnRoczogZnVuY3Rpb24oIGluc3QgKSB7XG5cdFx0dmFyIG51bU1vbnRocyA9IHRoaXMuX2dldCggaW5zdCwgXCJudW1iZXJPZk1vbnRoc1wiICk7XG5cdFx0cmV0dXJuICggbnVtTW9udGhzID09IG51bGwgPyBbIDEsIDEgXSA6ICggdHlwZW9mIG51bU1vbnRocyA9PT0gXCJudW1iZXJcIiA/IFsgMSwgbnVtTW9udGhzIF0gOiBudW1Nb250aHMgKSApO1xuXHR9LFxuXG5cdC8qIERldGVybWluZSB0aGUgY3VycmVudCBtYXhpbXVtIGRhdGUgLSBlbnN1cmUgbm8gdGltZSBjb21wb25lbnRzIGFyZSBzZXQuICovXG5cdF9nZXRNaW5NYXhEYXRlOiBmdW5jdGlvbiggaW5zdCwgbWluTWF4ICkge1xuXHRcdHJldHVybiB0aGlzLl9kZXRlcm1pbmVEYXRlKCBpbnN0LCB0aGlzLl9nZXQoIGluc3QsIG1pbk1heCArIFwiRGF0ZVwiICksIG51bGwgKTtcblx0fSxcblxuXHQvKiBGaW5kIHRoZSBudW1iZXIgb2YgZGF5cyBpbiBhIGdpdmVuIG1vbnRoLiAqL1xuXHRfZ2V0RGF5c0luTW9udGg6IGZ1bmN0aW9uKCB5ZWFyLCBtb250aCApIHtcblx0XHRyZXR1cm4gMzIgLSB0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIHllYXIsIG1vbnRoLCAzMiApICkuZ2V0RGF0ZSgpO1xuXHR9LFxuXG5cdC8qIEZpbmQgdGhlIGRheSBvZiB0aGUgd2VlayBvZiB0aGUgZmlyc3Qgb2YgYSBtb250aC4gKi9cblx0X2dldEZpcnN0RGF5T2ZNb250aDogZnVuY3Rpb24oIHllYXIsIG1vbnRoICkge1xuXHRcdHJldHVybiBuZXcgRGF0ZSggeWVhciwgbW9udGgsIDEgKS5nZXREYXkoKTtcblx0fSxcblxuXHQvKiBEZXRlcm1pbmVzIGlmIHdlIHNob3VsZCBhbGxvdyBhIFwibmV4dC9wcmV2XCIgbW9udGggZGlzcGxheSBjaGFuZ2UuICovXG5cdF9jYW5BZGp1c3RNb250aDogZnVuY3Rpb24oIGluc3QsIG9mZnNldCwgY3VyWWVhciwgY3VyTW9udGggKSB7XG5cdFx0dmFyIG51bU1vbnRocyA9IHRoaXMuX2dldE51bWJlck9mTW9udGhzKCBpbnN0ICksXG5cdFx0XHRkYXRlID0gdGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCBjdXJZZWFyLFxuXHRcdFx0Y3VyTW9udGggKyAoIG9mZnNldCA8IDAgPyBvZmZzZXQgOiBudW1Nb250aHNbIDAgXSAqIG51bU1vbnRoc1sgMSBdICksIDEgKSApO1xuXG5cdFx0aWYgKCBvZmZzZXQgPCAwICkge1xuXHRcdFx0ZGF0ZS5zZXREYXRlKCB0aGlzLl9nZXREYXlzSW5Nb250aCggZGF0ZS5nZXRGdWxsWWVhcigpLCBkYXRlLmdldE1vbnRoKCkgKSApO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcy5faXNJblJhbmdlKCBpbnN0LCBkYXRlICk7XG5cdH0sXG5cblx0LyogSXMgdGhlIGdpdmVuIGRhdGUgaW4gdGhlIGFjY2VwdGVkIHJhbmdlPyAqL1xuXHRfaXNJblJhbmdlOiBmdW5jdGlvbiggaW5zdCwgZGF0ZSApIHtcblx0XHR2YXIgeWVhclNwbGl0LCBjdXJyZW50WWVhcixcblx0XHRcdG1pbkRhdGUgPSB0aGlzLl9nZXRNaW5NYXhEYXRlKCBpbnN0LCBcIm1pblwiICksXG5cdFx0XHRtYXhEYXRlID0gdGhpcy5fZ2V0TWluTWF4RGF0ZSggaW5zdCwgXCJtYXhcIiApLFxuXHRcdFx0bWluWWVhciA9IG51bGwsXG5cdFx0XHRtYXhZZWFyID0gbnVsbCxcblx0XHRcdHllYXJzID0gdGhpcy5fZ2V0KCBpbnN0LCBcInllYXJSYW5nZVwiICk7XG5cdFx0XHRpZiAoIHllYXJzICkge1xuXHRcdFx0XHR5ZWFyU3BsaXQgPSB5ZWFycy5zcGxpdCggXCI6XCIgKTtcblx0XHRcdFx0Y3VycmVudFllYXIgPSBuZXcgRGF0ZSgpLmdldEZ1bGxZZWFyKCk7XG5cdFx0XHRcdG1pblllYXIgPSBwYXJzZUludCggeWVhclNwbGl0WyAwIF0sIDEwICk7XG5cdFx0XHRcdG1heFllYXIgPSBwYXJzZUludCggeWVhclNwbGl0WyAxIF0sIDEwICk7XG5cdFx0XHRcdGlmICggeWVhclNwbGl0WyAwIF0ubWF0Y2goIC9bK1xcLV0uKi8gKSApIHtcblx0XHRcdFx0XHRtaW5ZZWFyICs9IGN1cnJlbnRZZWFyO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggeWVhclNwbGl0WyAxIF0ubWF0Y2goIC9bK1xcLV0uKi8gKSApIHtcblx0XHRcdFx0XHRtYXhZZWFyICs9IGN1cnJlbnRZZWFyO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRyZXR1cm4gKCAoICFtaW5EYXRlIHx8IGRhdGUuZ2V0VGltZSgpID49IG1pbkRhdGUuZ2V0VGltZSgpICkgJiZcblx0XHRcdCggIW1heERhdGUgfHwgZGF0ZS5nZXRUaW1lKCkgPD0gbWF4RGF0ZS5nZXRUaW1lKCkgKSAmJlxuXHRcdFx0KCAhbWluWWVhciB8fCBkYXRlLmdldEZ1bGxZZWFyKCkgPj0gbWluWWVhciApICYmXG5cdFx0XHQoICFtYXhZZWFyIHx8IGRhdGUuZ2V0RnVsbFllYXIoKSA8PSBtYXhZZWFyICkgKTtcblx0fSxcblxuXHQvKiBQcm92aWRlIHRoZSBjb25maWd1cmF0aW9uIHNldHRpbmdzIGZvciBmb3JtYXR0aW5nL3BhcnNpbmcuICovXG5cdF9nZXRGb3JtYXRDb25maWc6IGZ1bmN0aW9uKCBpbnN0ICkge1xuXHRcdHZhciBzaG9ydFllYXJDdXRvZmYgPSB0aGlzLl9nZXQoIGluc3QsIFwic2hvcnRZZWFyQ3V0b2ZmXCIgKTtcblx0XHRzaG9ydFllYXJDdXRvZmYgPSAoIHR5cGVvZiBzaG9ydFllYXJDdXRvZmYgIT09IFwic3RyaW5nXCIgPyBzaG9ydFllYXJDdXRvZmYgOlxuXHRcdFx0bmV3IERhdGUoKS5nZXRGdWxsWWVhcigpICUgMTAwICsgcGFyc2VJbnQoIHNob3J0WWVhckN1dG9mZiwgMTAgKSApO1xuXHRcdHJldHVybiB7IHNob3J0WWVhckN1dG9mZjogc2hvcnRZZWFyQ3V0b2ZmLFxuXHRcdFx0ZGF5TmFtZXNTaG9ydDogdGhpcy5fZ2V0KCBpbnN0LCBcImRheU5hbWVzU2hvcnRcIiApLCBkYXlOYW1lczogdGhpcy5fZ2V0KCBpbnN0LCBcImRheU5hbWVzXCIgKSxcblx0XHRcdG1vbnRoTmFtZXNTaG9ydDogdGhpcy5fZ2V0KCBpbnN0LCBcIm1vbnRoTmFtZXNTaG9ydFwiICksIG1vbnRoTmFtZXM6IHRoaXMuX2dldCggaW5zdCwgXCJtb250aE5hbWVzXCIgKSB9O1xuXHR9LFxuXG5cdC8qIEZvcm1hdCB0aGUgZ2l2ZW4gZGF0ZSBmb3IgZGlzcGxheS4gKi9cblx0X2Zvcm1hdERhdGU6IGZ1bmN0aW9uKCBpbnN0LCBkYXksIG1vbnRoLCB5ZWFyICkge1xuXHRcdGlmICggIWRheSApIHtcblx0XHRcdGluc3QuY3VycmVudERheSA9IGluc3Quc2VsZWN0ZWREYXk7XG5cdFx0XHRpbnN0LmN1cnJlbnRNb250aCA9IGluc3Quc2VsZWN0ZWRNb250aDtcblx0XHRcdGluc3QuY3VycmVudFllYXIgPSBpbnN0LnNlbGVjdGVkWWVhcjtcblx0XHR9XG5cdFx0dmFyIGRhdGUgPSAoIGRheSA/ICggdHlwZW9mIGRheSA9PT0gXCJvYmplY3RcIiA/IGRheSA6XG5cdFx0XHR0aGlzLl9kYXlsaWdodFNhdmluZ0FkanVzdCggbmV3IERhdGUoIHllYXIsIG1vbnRoLCBkYXkgKSApICkgOlxuXHRcdFx0dGhpcy5fZGF5bGlnaHRTYXZpbmdBZGp1c3QoIG5ldyBEYXRlKCBpbnN0LmN1cnJlbnRZZWFyLCBpbnN0LmN1cnJlbnRNb250aCwgaW5zdC5jdXJyZW50RGF5ICkgKSApO1xuXHRcdHJldHVybiB0aGlzLmZvcm1hdERhdGUoIHRoaXMuX2dldCggaW5zdCwgXCJkYXRlRm9ybWF0XCIgKSwgZGF0ZSwgdGhpcy5fZ2V0Rm9ybWF0Q29uZmlnKCBpbnN0ICkgKTtcblx0fVxufSApO1xuXG4vKlxuICogQmluZCBob3ZlciBldmVudHMgZm9yIGRhdGVwaWNrZXIgZWxlbWVudHMuXG4gKiBEb25lIHZpYSBkZWxlZ2F0ZSBzbyB0aGUgYmluZGluZyBvbmx5IG9jY3VycyBvbmNlIGluIHRoZSBsaWZldGltZSBvZiB0aGUgcGFyZW50IGRpdi5cbiAqIEdsb2JhbCBkYXRlcGlja2VyX2luc3RBY3RpdmUsIHNldCBieSBfdXBkYXRlRGF0ZXBpY2tlciBhbGxvd3MgdGhlIGhhbmRsZXJzIHRvIGZpbmQgdGhlaXIgd2F5IGJhY2sgdG8gdGhlIGFjdGl2ZSBwaWNrZXIuXG4gKi9cbmZ1bmN0aW9uIGRhdGVwaWNrZXJfYmluZEhvdmVyKCBkcERpdiApIHtcblx0dmFyIHNlbGVjdG9yID0gXCJidXR0b24sIC51aS1kYXRlcGlja2VyLXByZXYsIC51aS1kYXRlcGlja2VyLW5leHQsIC51aS1kYXRlcGlja2VyLWNhbGVuZGFyIHRkIGFcIjtcblx0cmV0dXJuIGRwRGl2Lm9uKCBcIm1vdXNlb3V0XCIsIHNlbGVjdG9yLCBmdW5jdGlvbigpIHtcblx0XHRcdCQoIHRoaXMgKS5yZW1vdmVDbGFzcyggXCJ1aS1zdGF0ZS1ob3ZlclwiICk7XG5cdFx0XHRpZiAoIHRoaXMuY2xhc3NOYW1lLmluZGV4T2YoIFwidWktZGF0ZXBpY2tlci1wcmV2XCIgKSAhPT0gLTEgKSB7XG5cdFx0XHRcdCQoIHRoaXMgKS5yZW1vdmVDbGFzcyggXCJ1aS1kYXRlcGlja2VyLXByZXYtaG92ZXJcIiApO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCB0aGlzLmNsYXNzTmFtZS5pbmRleE9mKCBcInVpLWRhdGVwaWNrZXItbmV4dFwiICkgIT09IC0xICkge1xuXHRcdFx0XHQkKCB0aGlzICkucmVtb3ZlQ2xhc3MoIFwidWktZGF0ZXBpY2tlci1uZXh0LWhvdmVyXCIgKTtcblx0XHRcdH1cblx0XHR9IClcblx0XHQub24oIFwibW91c2VvdmVyXCIsIHNlbGVjdG9yLCBkYXRlcGlja2VyX2hhbmRsZU1vdXNlb3ZlciApO1xufVxuXG5mdW5jdGlvbiBkYXRlcGlja2VyX2hhbmRsZU1vdXNlb3ZlcigpIHtcblx0aWYgKCAhJC5kYXRlcGlja2VyLl9pc0Rpc2FibGVkRGF0ZXBpY2tlciggZGF0ZXBpY2tlcl9pbnN0QWN0aXZlLmlubGluZSA/IGRhdGVwaWNrZXJfaW5zdEFjdGl2ZS5kcERpdi5wYXJlbnQoKVsgMCBdIDogZGF0ZXBpY2tlcl9pbnN0QWN0aXZlLmlucHV0WyAwIF0gKSApIHtcblx0XHQkKCB0aGlzICkucGFyZW50cyggXCIudWktZGF0ZXBpY2tlci1jYWxlbmRhclwiICkuZmluZCggXCJhXCIgKS5yZW1vdmVDbGFzcyggXCJ1aS1zdGF0ZS1ob3ZlclwiICk7XG5cdFx0JCggdGhpcyApLmFkZENsYXNzKCBcInVpLXN0YXRlLWhvdmVyXCIgKTtcblx0XHRpZiAoIHRoaXMuY2xhc3NOYW1lLmluZGV4T2YoIFwidWktZGF0ZXBpY2tlci1wcmV2XCIgKSAhPT0gLTEgKSB7XG5cdFx0XHQkKCB0aGlzICkuYWRkQ2xhc3MoIFwidWktZGF0ZXBpY2tlci1wcmV2LWhvdmVyXCIgKTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLmNsYXNzTmFtZS5pbmRleE9mKCBcInVpLWRhdGVwaWNrZXItbmV4dFwiICkgIT09IC0xICkge1xuXHRcdFx0JCggdGhpcyApLmFkZENsYXNzKCBcInVpLWRhdGVwaWNrZXItbmV4dC1ob3ZlclwiICk7XG5cdFx0fVxuXHR9XG59XG5cbi8qIGpRdWVyeSBleHRlbmQgbm93IGlnbm9yZXMgbnVsbHMhICovXG5mdW5jdGlvbiBkYXRlcGlja2VyX2V4dGVuZFJlbW92ZSggdGFyZ2V0LCBwcm9wcyApIHtcblx0JC5leHRlbmQoIHRhcmdldCwgcHJvcHMgKTtcblx0Zm9yICggdmFyIG5hbWUgaW4gcHJvcHMgKSB7XG5cdFx0aWYgKCBwcm9wc1sgbmFtZSBdID09IG51bGwgKSB7XG5cdFx0XHR0YXJnZXRbIG5hbWUgXSA9IHByb3BzWyBuYW1lIF07XG5cdFx0fVxuXHR9XG5cdHJldHVybiB0YXJnZXQ7XG59XG5cbi8qIEludm9rZSB0aGUgZGF0ZXBpY2tlciBmdW5jdGlvbmFsaXR5LlxuICAgQHBhcmFtICBvcHRpb25zICBzdHJpbmcgLSBhIGNvbW1hbmQsIG9wdGlvbmFsbHkgZm9sbG93ZWQgYnkgYWRkaXRpb25hbCBwYXJhbWV0ZXJzIG9yXG5cdFx0XHRcdFx0T2JqZWN0IC0gc2V0dGluZ3MgZm9yIGF0dGFjaGluZyBuZXcgZGF0ZXBpY2tlciBmdW5jdGlvbmFsaXR5XG4gICBAcmV0dXJuICBqUXVlcnkgb2JqZWN0ICovXG4kLmZuLmRhdGVwaWNrZXIgPSBmdW5jdGlvbiggb3B0aW9ucyApIHtcblxuXHQvKiBWZXJpZnkgYW4gZW1wdHkgY29sbGVjdGlvbiB3YXNuJ3QgcGFzc2VkIC0gRml4ZXMgIzY5NzYgKi9cblx0aWYgKCAhdGhpcy5sZW5ndGggKSB7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKiBJbml0aWFsaXNlIHRoZSBkYXRlIHBpY2tlci4gKi9cblx0aWYgKCAhJC5kYXRlcGlja2VyLmluaXRpYWxpemVkICkge1xuXHRcdCQoIGRvY3VtZW50ICkub24oIFwibW91c2Vkb3duXCIsICQuZGF0ZXBpY2tlci5fY2hlY2tFeHRlcm5hbENsaWNrICk7XG5cdFx0JC5kYXRlcGlja2VyLmluaXRpYWxpemVkID0gdHJ1ZTtcblx0fVxuXG5cdC8qIEFwcGVuZCBkYXRlcGlja2VyIG1haW4gY29udGFpbmVyIHRvIGJvZHkgaWYgbm90IGV4aXN0LiAqL1xuXHRpZiAoICQoIFwiI1wiICsgJC5kYXRlcGlja2VyLl9tYWluRGl2SWQgKS5sZW5ndGggPT09IDAgKSB7XG5cdFx0JCggXCJib2R5XCIgKS5hcHBlbmQoICQuZGF0ZXBpY2tlci5kcERpdiApO1xuXHR9XG5cblx0dmFyIG90aGVyQXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBhcmd1bWVudHMsIDEgKTtcblx0aWYgKCB0eXBlb2Ygb3B0aW9ucyA9PT0gXCJzdHJpbmdcIiAmJiAoIG9wdGlvbnMgPT09IFwiaXNEaXNhYmxlZFwiIHx8IG9wdGlvbnMgPT09IFwiZ2V0RGF0ZVwiIHx8IG9wdGlvbnMgPT09IFwid2lkZ2V0XCIgKSApIHtcblx0XHRyZXR1cm4gJC5kYXRlcGlja2VyWyBcIl9cIiArIG9wdGlvbnMgKyBcIkRhdGVwaWNrZXJcIiBdLlxuXHRcdFx0YXBwbHkoICQuZGF0ZXBpY2tlciwgWyB0aGlzWyAwIF0gXS5jb25jYXQoIG90aGVyQXJncyApICk7XG5cdH1cblx0aWYgKCBvcHRpb25zID09PSBcIm9wdGlvblwiICYmIGFyZ3VtZW50cy5sZW5ndGggPT09IDIgJiYgdHlwZW9mIGFyZ3VtZW50c1sgMSBdID09PSBcInN0cmluZ1wiICkge1xuXHRcdHJldHVybiAkLmRhdGVwaWNrZXJbIFwiX1wiICsgb3B0aW9ucyArIFwiRGF0ZXBpY2tlclwiIF0uXG5cdFx0XHRhcHBseSggJC5kYXRlcGlja2VyLCBbIHRoaXNbIDAgXSBdLmNvbmNhdCggb3RoZXJBcmdzICkgKTtcblx0fVxuXHRyZXR1cm4gdGhpcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHR0eXBlb2Ygb3B0aW9ucyA9PT0gXCJzdHJpbmdcIiA/XG5cdFx0XHQkLmRhdGVwaWNrZXJbIFwiX1wiICsgb3B0aW9ucyArIFwiRGF0ZXBpY2tlclwiIF0uXG5cdFx0XHRcdGFwcGx5KCAkLmRhdGVwaWNrZXIsIFsgdGhpcyBdLmNvbmNhdCggb3RoZXJBcmdzICkgKSA6XG5cdFx0XHQkLmRhdGVwaWNrZXIuX2F0dGFjaERhdGVwaWNrZXIoIHRoaXMsIG9wdGlvbnMgKTtcblx0fSApO1xufTtcblxuJC5kYXRlcGlja2VyID0gbmV3IERhdGVwaWNrZXIoKTsgLy8gc2luZ2xldG9uIGluc3RhbmNlXG4kLmRhdGVwaWNrZXIuaW5pdGlhbGl6ZWQgPSBmYWxzZTtcbiQuZGF0ZXBpY2tlci51dWlkID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4kLmRhdGVwaWNrZXIudmVyc2lvbiA9IFwiMS4xMi4xXCI7XG5cbnZhciB3aWRnZXRzRGF0ZXBpY2tlciA9ICQuZGF0ZXBpY2tlcjtcblxuXG5cblxuLy8gVGhpcyBmaWxlIGlzIGRlcHJlY2F0ZWRcbnZhciBpZSA9ICQudWkuaWUgPSAhIS9tc2llIFtcXHcuXSsvLmV4ZWMoIG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKSApO1xuXG4vKiFcbiAqIGpRdWVyeSBVSSBNb3VzZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogTW91c2Vcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBBYnN0cmFjdHMgbW91c2UtYmFzZWQgaW50ZXJhY3Rpb25zIHRvIGFzc2lzdCBpbiBjcmVhdGluZyBjZXJ0YWluIHdpZGdldHMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vbW91c2UvXG5cblxuXG52YXIgbW91c2VIYW5kbGVkID0gZmFsc2U7XG4kKCBkb2N1bWVudCApLm9uKCBcIm1vdXNldXBcIiwgZnVuY3Rpb24oKSB7XG5cdG1vdXNlSGFuZGxlZCA9IGZhbHNlO1xufSApO1xuXG52YXIgd2lkZ2V0c01vdXNlID0gJC53aWRnZXQoIFwidWkubW91c2VcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRvcHRpb25zOiB7XG5cdFx0Y2FuY2VsOiBcImlucHV0LCB0ZXh0YXJlYSwgYnV0dG9uLCBzZWxlY3QsIG9wdGlvblwiLFxuXHRcdGRpc3RhbmNlOiAxLFxuXHRcdGRlbGF5OiAwXG5cdH0sXG5cdF9tb3VzZUluaXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdHRoaXMuZWxlbWVudFxuXHRcdFx0Lm9uKCBcIm1vdXNlZG93bi5cIiArIHRoaXMud2lkZ2V0TmFtZSwgZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRyZXR1cm4gdGhhdC5fbW91c2VEb3duKCBldmVudCApO1xuXHRcdFx0fSApXG5cdFx0XHQub24oIFwiY2xpY2suXCIgKyB0aGlzLndpZGdldE5hbWUsIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCB0cnVlID09PSAkLmRhdGEoIGV2ZW50LnRhcmdldCwgdGhhdC53aWRnZXROYW1lICsgXCIucHJldmVudENsaWNrRXZlbnRcIiApICkge1xuXHRcdFx0XHRcdCQucmVtb3ZlRGF0YSggZXZlbnQudGFyZ2V0LCB0aGF0LndpZGdldE5hbWUgKyBcIi5wcmV2ZW50Q2xpY2tFdmVudFwiICk7XG5cdFx0XHRcdFx0ZXZlbnQuc3RvcEltbWVkaWF0ZVByb3BhZ2F0aW9uKCk7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cblx0XHR0aGlzLnN0YXJ0ZWQgPSBmYWxzZTtcblx0fSxcblxuXHQvLyBUT0RPOiBtYWtlIHN1cmUgZGVzdHJveWluZyBvbmUgaW5zdGFuY2Ugb2YgbW91c2UgZG9lc24ndCBtZXNzIHdpdGhcblx0Ly8gb3RoZXIgaW5zdGFuY2VzIG9mIG1vdXNlXG5cdF9tb3VzZURlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuZWxlbWVudC5vZmYoIFwiLlwiICsgdGhpcy53aWRnZXROYW1lICk7XG5cdFx0aWYgKCB0aGlzLl9tb3VzZU1vdmVEZWxlZ2F0ZSApIHtcblx0XHRcdHRoaXMuZG9jdW1lbnRcblx0XHRcdFx0Lm9mZiggXCJtb3VzZW1vdmUuXCIgKyB0aGlzLndpZGdldE5hbWUsIHRoaXMuX21vdXNlTW92ZURlbGVnYXRlIClcblx0XHRcdFx0Lm9mZiggXCJtb3VzZXVwLlwiICsgdGhpcy53aWRnZXROYW1lLCB0aGlzLl9tb3VzZVVwRGVsZWdhdGUgKTtcblx0XHR9XG5cdH0sXG5cblx0X21vdXNlRG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0Ly8gZG9uJ3QgbGV0IG1vcmUgdGhhbiBvbmUgd2lkZ2V0IGhhbmRsZSBtb3VzZVN0YXJ0XG5cdFx0aWYgKCBtb3VzZUhhbmRsZWQgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5fbW91c2VNb3ZlZCA9IGZhbHNlO1xuXG5cdFx0Ly8gV2UgbWF5IGhhdmUgbWlzc2VkIG1vdXNldXAgKG91dCBvZiB3aW5kb3cpXG5cdFx0KCB0aGlzLl9tb3VzZVN0YXJ0ZWQgJiYgdGhpcy5fbW91c2VVcCggZXZlbnQgKSApO1xuXG5cdFx0dGhpcy5fbW91c2VEb3duRXZlbnQgPSBldmVudDtcblxuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdGJ0bklzTGVmdCA9ICggZXZlbnQud2hpY2ggPT09IDEgKSxcblxuXHRcdFx0Ly8gZXZlbnQudGFyZ2V0Lm5vZGVOYW1lIHdvcmtzIGFyb3VuZCBhIGJ1ZyBpbiBJRSA4IHdpdGhcblx0XHRcdC8vIGRpc2FibGVkIGlucHV0cyAoIzc2MjApXG5cdFx0XHRlbElzQ2FuY2VsID0gKCB0eXBlb2YgdGhpcy5vcHRpb25zLmNhbmNlbCA9PT0gXCJzdHJpbmdcIiAmJiBldmVudC50YXJnZXQubm9kZU5hbWUgP1xuXHRcdFx0XHQkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCB0aGlzLm9wdGlvbnMuY2FuY2VsICkubGVuZ3RoIDogZmFsc2UgKTtcblx0XHRpZiAoICFidG5Jc0xlZnQgfHwgZWxJc0NhbmNlbCB8fCAhdGhpcy5fbW91c2VDYXB0dXJlKCBldmVudCApICkge1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0fVxuXG5cdFx0dGhpcy5tb3VzZURlbGF5TWV0ID0gIXRoaXMub3B0aW9ucy5kZWxheTtcblx0XHRpZiAoICF0aGlzLm1vdXNlRGVsYXlNZXQgKSB7XG5cdFx0XHR0aGlzLl9tb3VzZURlbGF5VGltZXIgPSBzZXRUaW1lb3V0KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhhdC5tb3VzZURlbGF5TWV0ID0gdHJ1ZTtcblx0XHRcdH0sIHRoaXMub3B0aW9ucy5kZWxheSApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fbW91c2VEaXN0YW5jZU1ldCggZXZlbnQgKSAmJiB0aGlzLl9tb3VzZURlbGF5TWV0KCBldmVudCApICkge1xuXHRcdFx0dGhpcy5fbW91c2VTdGFydGVkID0gKCB0aGlzLl9tb3VzZVN0YXJ0KCBldmVudCApICE9PSBmYWxzZSApO1xuXHRcdFx0aWYgKCAhdGhpcy5fbW91c2VTdGFydGVkICkge1xuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBDbGljayBldmVudCBtYXkgbmV2ZXIgaGF2ZSBmaXJlZCAoR2Vja28gJiBPcGVyYSlcblx0XHRpZiAoIHRydWUgPT09ICQuZGF0YSggZXZlbnQudGFyZ2V0LCB0aGlzLndpZGdldE5hbWUgKyBcIi5wcmV2ZW50Q2xpY2tFdmVudFwiICkgKSB7XG5cdFx0XHQkLnJlbW92ZURhdGEoIGV2ZW50LnRhcmdldCwgdGhpcy53aWRnZXROYW1lICsgXCIucHJldmVudENsaWNrRXZlbnRcIiApO1xuXHRcdH1cblxuXHRcdC8vIFRoZXNlIGRlbGVnYXRlcyBhcmUgcmVxdWlyZWQgdG8ga2VlcCBjb250ZXh0XG5cdFx0dGhpcy5fbW91c2VNb3ZlRGVsZWdhdGUgPSBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRyZXR1cm4gdGhhdC5fbW91c2VNb3ZlKCBldmVudCApO1xuXHRcdH07XG5cdFx0dGhpcy5fbW91c2VVcERlbGVnYXRlID0gZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0cmV0dXJuIHRoYXQuX21vdXNlVXAoIGV2ZW50ICk7XG5cdFx0fTtcblxuXHRcdHRoaXMuZG9jdW1lbnRcblx0XHRcdC5vbiggXCJtb3VzZW1vdmUuXCIgKyB0aGlzLndpZGdldE5hbWUsIHRoaXMuX21vdXNlTW92ZURlbGVnYXRlIClcblx0XHRcdC5vbiggXCJtb3VzZXVwLlwiICsgdGhpcy53aWRnZXROYW1lLCB0aGlzLl9tb3VzZVVwRGVsZWdhdGUgKTtcblxuXHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRtb3VzZUhhbmRsZWQgPSB0cnVlO1xuXHRcdHJldHVybiB0cnVlO1xuXHR9LFxuXG5cdF9tb3VzZU1vdmU6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdC8vIE9ubHkgY2hlY2sgZm9yIG1vdXNldXBzIG91dHNpZGUgdGhlIGRvY3VtZW50IGlmIHlvdSd2ZSBtb3ZlZCBpbnNpZGUgdGhlIGRvY3VtZW50XG5cdFx0Ly8gYXQgbGVhc3Qgb25jZS4gVGhpcyBwcmV2ZW50cyB0aGUgZmlyaW5nIG9mIG1vdXNldXAgaW4gdGhlIGNhc2Ugb2YgSUU8OSwgd2hpY2ggd2lsbFxuXHRcdC8vIGZpcmUgYSBtb3VzZW1vdmUgZXZlbnQgaWYgY29udGVudCBpcyBwbGFjZWQgdW5kZXIgdGhlIGN1cnNvci4gU2VlICM3Nzc4XG5cdFx0Ly8gU3VwcG9ydDogSUUgPDlcblx0XHRpZiAoIHRoaXMuX21vdXNlTW92ZWQgKSB7XG5cblx0XHRcdC8vIElFIG1vdXNldXAgY2hlY2sgLSBtb3VzZXVwIGhhcHBlbmVkIHdoZW4gbW91c2Ugd2FzIG91dCBvZiB3aW5kb3dcblx0XHRcdGlmICggJC51aS5pZSAmJiAoICFkb2N1bWVudC5kb2N1bWVudE1vZGUgfHwgZG9jdW1lbnQuZG9jdW1lbnRNb2RlIDwgOSApICYmXG5cdFx0XHRcdFx0IWV2ZW50LmJ1dHRvbiApIHtcblx0XHRcdFx0cmV0dXJuIHRoaXMuX21vdXNlVXAoIGV2ZW50ICk7XG5cblx0XHRcdC8vIElmcmFtZSBtb3VzZXVwIGNoZWNrIC0gbW91c2V1cCBvY2N1cnJlZCBpbiBhbm90aGVyIGRvY3VtZW50XG5cdFx0XHR9IGVsc2UgaWYgKCAhZXZlbnQud2hpY2ggKSB7XG5cblx0XHRcdFx0Ly8gU3VwcG9ydDogU2FmYXJpIDw9OCAtIDlcblx0XHRcdFx0Ly8gU2FmYXJpIHNldHMgd2hpY2ggdG8gMCBpZiB5b3UgcHJlc3MgYW55IG9mIHRoZSBmb2xsb3dpbmcga2V5c1xuXHRcdFx0XHQvLyBkdXJpbmcgYSBkcmFnICgjMTQ0NjEpXG5cdFx0XHRcdGlmICggZXZlbnQub3JpZ2luYWxFdmVudC5hbHRLZXkgfHwgZXZlbnQub3JpZ2luYWxFdmVudC5jdHJsS2V5IHx8XG5cdFx0XHRcdFx0XHRldmVudC5vcmlnaW5hbEV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQub3JpZ2luYWxFdmVudC5zaGlmdEtleSApIHtcblx0XHRcdFx0XHR0aGlzLmlnbm9yZU1pc3NpbmdXaGljaCA9IHRydWU7XG5cdFx0XHRcdH0gZWxzZSBpZiAoICF0aGlzLmlnbm9yZU1pc3NpbmdXaGljaCApIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5fbW91c2VVcCggZXZlbnQgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggZXZlbnQud2hpY2ggfHwgZXZlbnQuYnV0dG9uICkge1xuXHRcdFx0dGhpcy5fbW91c2VNb3ZlZCA9IHRydWU7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9tb3VzZVN0YXJ0ZWQgKSB7XG5cdFx0XHR0aGlzLl9tb3VzZURyYWcoIGV2ZW50ICk7XG5cdFx0XHRyZXR1cm4gZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX21vdXNlRGlzdGFuY2VNZXQoIGV2ZW50ICkgJiYgdGhpcy5fbW91c2VEZWxheU1ldCggZXZlbnQgKSApIHtcblx0XHRcdHRoaXMuX21vdXNlU3RhcnRlZCA9XG5cdFx0XHRcdCggdGhpcy5fbW91c2VTdGFydCggdGhpcy5fbW91c2VEb3duRXZlbnQsIGV2ZW50ICkgIT09IGZhbHNlICk7XG5cdFx0XHQoIHRoaXMuX21vdXNlU3RhcnRlZCA/IHRoaXMuX21vdXNlRHJhZyggZXZlbnQgKSA6IHRoaXMuX21vdXNlVXAoIGV2ZW50ICkgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gIXRoaXMuX21vdXNlU3RhcnRlZDtcblx0fSxcblxuXHRfbW91c2VVcDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHRoaXMuZG9jdW1lbnRcblx0XHRcdC5vZmYoIFwibW91c2Vtb3ZlLlwiICsgdGhpcy53aWRnZXROYW1lLCB0aGlzLl9tb3VzZU1vdmVEZWxlZ2F0ZSApXG5cdFx0XHQub2ZmKCBcIm1vdXNldXAuXCIgKyB0aGlzLndpZGdldE5hbWUsIHRoaXMuX21vdXNlVXBEZWxlZ2F0ZSApO1xuXG5cdFx0aWYgKCB0aGlzLl9tb3VzZVN0YXJ0ZWQgKSB7XG5cdFx0XHR0aGlzLl9tb3VzZVN0YXJ0ZWQgPSBmYWxzZTtcblxuXHRcdFx0aWYgKCBldmVudC50YXJnZXQgPT09IHRoaXMuX21vdXNlRG93bkV2ZW50LnRhcmdldCApIHtcblx0XHRcdFx0JC5kYXRhKCBldmVudC50YXJnZXQsIHRoaXMud2lkZ2V0TmFtZSArIFwiLnByZXZlbnRDbGlja0V2ZW50XCIsIHRydWUgKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fbW91c2VTdG9wKCBldmVudCApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fbW91c2VEZWxheVRpbWVyICkge1xuXHRcdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLl9tb3VzZURlbGF5VGltZXIgKTtcblx0XHRcdGRlbGV0ZSB0aGlzLl9tb3VzZURlbGF5VGltZXI7XG5cdFx0fVxuXG5cdFx0dGhpcy5pZ25vcmVNaXNzaW5nV2hpY2ggPSBmYWxzZTtcblx0XHRtb3VzZUhhbmRsZWQgPSBmYWxzZTtcblx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHR9LFxuXG5cdF9tb3VzZURpc3RhbmNlTWV0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0cmV0dXJuICggTWF0aC5tYXgoXG5cdFx0XHRcdE1hdGguYWJzKCB0aGlzLl9tb3VzZURvd25FdmVudC5wYWdlWCAtIGV2ZW50LnBhZ2VYICksXG5cdFx0XHRcdE1hdGguYWJzKCB0aGlzLl9tb3VzZURvd25FdmVudC5wYWdlWSAtIGV2ZW50LnBhZ2VZIClcblx0XHRcdCkgPj0gdGhpcy5vcHRpb25zLmRpc3RhbmNlXG5cdFx0KTtcblx0fSxcblxuXHRfbW91c2VEZWxheU1ldDogZnVuY3Rpb24oIC8qIGV2ZW50ICovICkge1xuXHRcdHJldHVybiB0aGlzLm1vdXNlRGVsYXlNZXQ7XG5cdH0sXG5cblx0Ly8gVGhlc2UgYXJlIHBsYWNlaG9sZGVyIG1ldGhvZHMsIHRvIGJlIG92ZXJyaWRlbiBieSBleHRlbmRpbmcgcGx1Z2luXG5cdF9tb3VzZVN0YXJ0OiBmdW5jdGlvbiggLyogZXZlbnQgKi8gKSB7fSxcblx0X21vdXNlRHJhZzogZnVuY3Rpb24oIC8qIGV2ZW50ICovICkge30sXG5cdF9tb3VzZVN0b3A6IGZ1bmN0aW9uKCAvKiBldmVudCAqLyApIHt9LFxuXHRfbW91c2VDYXB0dXJlOiBmdW5jdGlvbiggLyogZXZlbnQgKi8gKSB7IHJldHVybiB0cnVlOyB9XG59ICk7XG5cblxuXG5cbi8vICQudWkucGx1Z2luIGlzIGRlcHJlY2F0ZWQuIFVzZSAkLndpZGdldCgpIGV4dGVuc2lvbnMgaW5zdGVhZC5cbnZhciBwbHVnaW4gPSAkLnVpLnBsdWdpbiA9IHtcblx0YWRkOiBmdW5jdGlvbiggbW9kdWxlLCBvcHRpb24sIHNldCApIHtcblx0XHR2YXIgaSxcblx0XHRcdHByb3RvID0gJC51aVsgbW9kdWxlIF0ucHJvdG90eXBlO1xuXHRcdGZvciAoIGkgaW4gc2V0ICkge1xuXHRcdFx0cHJvdG8ucGx1Z2luc1sgaSBdID0gcHJvdG8ucGx1Z2luc1sgaSBdIHx8IFtdO1xuXHRcdFx0cHJvdG8ucGx1Z2luc1sgaSBdLnB1c2goIFsgb3B0aW9uLCBzZXRbIGkgXSBdICk7XG5cdFx0fVxuXHR9LFxuXHRjYWxsOiBmdW5jdGlvbiggaW5zdGFuY2UsIG5hbWUsIGFyZ3MsIGFsbG93RGlzY29ubmVjdGVkICkge1xuXHRcdHZhciBpLFxuXHRcdFx0c2V0ID0gaW5zdGFuY2UucGx1Z2luc1sgbmFtZSBdO1xuXG5cdFx0aWYgKCAhc2V0ICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggIWFsbG93RGlzY29ubmVjdGVkICYmICggIWluc3RhbmNlLmVsZW1lbnRbIDAgXS5wYXJlbnROb2RlIHx8XG5cdFx0XHRcdGluc3RhbmNlLmVsZW1lbnRbIDAgXS5wYXJlbnROb2RlLm5vZGVUeXBlID09PSAxMSApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGZvciAoIGkgPSAwOyBpIDwgc2V0Lmxlbmd0aDsgaSsrICkge1xuXHRcdFx0aWYgKCBpbnN0YW5jZS5vcHRpb25zWyBzZXRbIGkgXVsgMCBdIF0gKSB7XG5cdFx0XHRcdHNldFsgaSBdWyAxIF0uYXBwbHkoIGluc3RhbmNlLmVsZW1lbnQsIGFyZ3MgKTtcblx0XHRcdH1cblx0XHR9XG5cdH1cbn07XG5cblxuXG52YXIgc2FmZUJsdXIgPSAkLnVpLnNhZmVCbHVyID0gZnVuY3Rpb24oIGVsZW1lbnQgKSB7XG5cblx0Ly8gU3VwcG9ydDogSUU5IC0gMTAgb25seVxuXHQvLyBJZiB0aGUgPGJvZHk+IGlzIGJsdXJyZWQsIElFIHdpbGwgc3dpdGNoIHdpbmRvd3MsIHNlZSAjOTQyMFxuXHRpZiAoIGVsZW1lbnQgJiYgZWxlbWVudC5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpICE9PSBcImJvZHlcIiApIHtcblx0XHQkKCBlbGVtZW50ICkudHJpZ2dlciggXCJibHVyXCIgKTtcblx0fVxufTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBEcmFnZ2FibGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IERyYWdnYWJsZVxuLy8+Pmdyb3VwOiBJbnRlcmFjdGlvbnNcbi8vPj5kZXNjcmlwdGlvbjogRW5hYmxlcyBkcmFnZ2luZyBmdW5jdGlvbmFsaXR5IGZvciBhbnkgZWxlbWVudC5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9kcmFnZ2FibGUvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZHJhZ2dhYmxlL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2RyYWdnYWJsZS5jc3NcblxuXG5cbiQud2lkZ2V0KCBcInVpLmRyYWdnYWJsZVwiLCAkLnVpLm1vdXNlLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdHdpZGdldEV2ZW50UHJlZml4OiBcImRyYWdcIixcblx0b3B0aW9uczoge1xuXHRcdGFkZENsYXNzZXM6IHRydWUsXG5cdFx0YXBwZW5kVG86IFwicGFyZW50XCIsXG5cdFx0YXhpczogZmFsc2UsXG5cdFx0Y29ubmVjdFRvU29ydGFibGU6IGZhbHNlLFxuXHRcdGNvbnRhaW5tZW50OiBmYWxzZSxcblx0XHRjdXJzb3I6IFwiYXV0b1wiLFxuXHRcdGN1cnNvckF0OiBmYWxzZSxcblx0XHRncmlkOiBmYWxzZSxcblx0XHRoYW5kbGU6IGZhbHNlLFxuXHRcdGhlbHBlcjogXCJvcmlnaW5hbFwiLFxuXHRcdGlmcmFtZUZpeDogZmFsc2UsXG5cdFx0b3BhY2l0eTogZmFsc2UsXG5cdFx0cmVmcmVzaFBvc2l0aW9uczogZmFsc2UsXG5cdFx0cmV2ZXJ0OiBmYWxzZSxcblx0XHRyZXZlcnREdXJhdGlvbjogNTAwLFxuXHRcdHNjb3BlOiBcImRlZmF1bHRcIixcblx0XHRzY3JvbGw6IHRydWUsXG5cdFx0c2Nyb2xsU2Vuc2l0aXZpdHk6IDIwLFxuXHRcdHNjcm9sbFNwZWVkOiAyMCxcblx0XHRzbmFwOiBmYWxzZSxcblx0XHRzbmFwTW9kZTogXCJib3RoXCIsXG5cdFx0c25hcFRvbGVyYW5jZTogMjAsXG5cdFx0c3RhY2s6IGZhbHNlLFxuXHRcdHpJbmRleDogZmFsc2UsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRkcmFnOiBudWxsLFxuXHRcdHN0YXJ0OiBudWxsLFxuXHRcdHN0b3A6IG51bGxcblx0fSxcblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5oZWxwZXIgPT09IFwib3JpZ2luYWxcIiApIHtcblx0XHRcdHRoaXMuX3NldFBvc2l0aW9uUmVsYXRpdmUoKTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuYWRkQ2xhc3NlcyApIHtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLWRyYWdnYWJsZVwiICk7XG5cdFx0fVxuXHRcdHRoaXMuX3NldEhhbmRsZUNsYXNzTmFtZSgpO1xuXG5cdFx0dGhpcy5fbW91c2VJbml0KCk7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblx0XHRpZiAoIGtleSA9PT0gXCJoYW5kbGVcIiApIHtcblx0XHRcdHRoaXMuX3JlbW92ZUhhbmRsZUNsYXNzTmFtZSgpO1xuXHRcdFx0dGhpcy5fc2V0SGFuZGxlQ2xhc3NOYW1lKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHRpZiAoICggdGhpcy5oZWxwZXIgfHwgdGhpcy5lbGVtZW50ICkuaXMoIFwiLnVpLWRyYWdnYWJsZS1kcmFnZ2luZ1wiICkgKSB7XG5cdFx0XHR0aGlzLmRlc3Ryb3lPbkNsZWFyID0gdHJ1ZTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5fcmVtb3ZlSGFuZGxlQ2xhc3NOYW1lKCk7XG5cdFx0dGhpcy5fbW91c2VEZXN0cm95KCk7XG5cdH0sXG5cblx0X21vdXNlQ2FwdHVyZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBvID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0Ly8gQW1vbmcgb3RoZXJzLCBwcmV2ZW50IGEgZHJhZyBvbiBhIHJlc2l6YWJsZS1oYW5kbGVcblx0XHRpZiAoIHRoaXMuaGVscGVyIHx8IG8uZGlzYWJsZWQgfHxcblx0XHRcdFx0JCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggXCIudWktcmVzaXphYmxlLWhhbmRsZVwiICkubGVuZ3RoID4gMCApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHQvL1F1aXQgaWYgd2UncmUgbm90IG9uIGEgdmFsaWQgaGFuZGxlXG5cdFx0dGhpcy5oYW5kbGUgPSB0aGlzLl9nZXRIYW5kbGUoIGV2ZW50ICk7XG5cdFx0aWYgKCAhdGhpcy5oYW5kbGUgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0dGhpcy5fYmx1ckFjdGl2ZUVsZW1lbnQoIGV2ZW50ICk7XG5cblx0XHR0aGlzLl9ibG9ja0ZyYW1lcyggby5pZnJhbWVGaXggPT09IHRydWUgPyBcImlmcmFtZVwiIDogby5pZnJhbWVGaXggKTtcblxuXHRcdHJldHVybiB0cnVlO1xuXG5cdH0sXG5cblx0X2Jsb2NrRnJhbWVzOiBmdW5jdGlvbiggc2VsZWN0b3IgKSB7XG5cdFx0dGhpcy5pZnJhbWVCbG9ja3MgPSB0aGlzLmRvY3VtZW50LmZpbmQoIHNlbGVjdG9yICkubWFwKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBpZnJhbWUgPSAkKCB0aGlzICk7XG5cblx0XHRcdHJldHVybiAkKCBcIjxkaXY+XCIgKVxuXHRcdFx0XHQuY3NzKCBcInBvc2l0aW9uXCIsIFwiYWJzb2x1dGVcIiApXG5cdFx0XHRcdC5hcHBlbmRUbyggaWZyYW1lLnBhcmVudCgpIClcblx0XHRcdFx0Lm91dGVyV2lkdGgoIGlmcmFtZS5vdXRlcldpZHRoKCkgKVxuXHRcdFx0XHQub3V0ZXJIZWlnaHQoIGlmcmFtZS5vdXRlckhlaWdodCgpIClcblx0XHRcdFx0Lm9mZnNldCggaWZyYW1lLm9mZnNldCgpIClbIDAgXTtcblx0XHR9ICk7XG5cdH0sXG5cblx0X3VuYmxvY2tGcmFtZXM6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggdGhpcy5pZnJhbWVCbG9ja3MgKSB7XG5cdFx0XHR0aGlzLmlmcmFtZUJsb2Nrcy5yZW1vdmUoKTtcblx0XHRcdGRlbGV0ZSB0aGlzLmlmcmFtZUJsb2Nrcztcblx0XHR9XG5cdH0sXG5cblx0X2JsdXJBY3RpdmVFbGVtZW50OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGFjdGl2ZUVsZW1lbnQgPSAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKSxcblx0XHRcdHRhcmdldCA9ICQoIGV2ZW50LnRhcmdldCApO1xuXG5cdFx0Ly8gRG9uJ3QgYmx1ciBpZiB0aGUgZXZlbnQgb2NjdXJyZWQgb24gYW4gZWxlbWVudCB0aGF0IGlzIHdpdGhpblxuXHRcdC8vIHRoZSBjdXJyZW50bHkgZm9jdXNlZCBlbGVtZW50XG5cdFx0Ly8gU2VlICMxMDUyNywgIzEyNDcyXG5cdFx0aWYgKCB0YXJnZXQuY2xvc2VzdCggYWN0aXZlRWxlbWVudCApLmxlbmd0aCApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBCbHVyIGFueSBlbGVtZW50IHRoYXQgY3VycmVudGx5IGhhcyBmb2N1cywgc2VlICM0MjYxXG5cdFx0JC51aS5zYWZlQmx1ciggYWN0aXZlRWxlbWVudCApO1xuXHR9LFxuXG5cdF9tb3VzZVN0YXJ0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR2YXIgbyA9IHRoaXMub3B0aW9ucztcblxuXHRcdC8vQ3JlYXRlIGFuZCBhcHBlbmQgdGhlIHZpc2libGUgaGVscGVyXG5cdFx0dGhpcy5oZWxwZXIgPSB0aGlzLl9jcmVhdGVIZWxwZXIoIGV2ZW50ICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5oZWxwZXIsIFwidWktZHJhZ2dhYmxlLWRyYWdnaW5nXCIgKTtcblxuXHRcdC8vQ2FjaGUgdGhlIGhlbHBlciBzaXplXG5cdFx0dGhpcy5fY2FjaGVIZWxwZXJQcm9wb3J0aW9ucygpO1xuXG5cdFx0Ly9JZiBkZG1hbmFnZXIgaXMgdXNlZCBmb3IgZHJvcHBhYmxlcywgc2V0IHRoZSBnbG9iYWwgZHJhZ2dhYmxlXG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLmN1cnJlbnQgPSB0aGlzO1xuXHRcdH1cblxuXHRcdC8qXG5cdFx0ICogLSBQb3NpdGlvbiBnZW5lcmF0aW9uIC1cblx0XHQgKiBUaGlzIGJsb2NrIGdlbmVyYXRlcyBldmVyeXRoaW5nIHBvc2l0aW9uIHJlbGF0ZWQgLSBpdCdzIHRoZSBjb3JlIG9mIGRyYWdnYWJsZXMuXG5cdFx0ICovXG5cblx0XHQvL0NhY2hlIHRoZSBtYXJnaW5zIG9mIHRoZSBvcmlnaW5hbCBlbGVtZW50XG5cdFx0dGhpcy5fY2FjaGVNYXJnaW5zKCk7XG5cblx0XHQvL1N0b3JlIHRoZSBoZWxwZXIncyBjc3MgcG9zaXRpb25cblx0XHR0aGlzLmNzc1Bvc2l0aW9uID0gdGhpcy5oZWxwZXIuY3NzKCBcInBvc2l0aW9uXCIgKTtcblx0XHR0aGlzLnNjcm9sbFBhcmVudCA9IHRoaXMuaGVscGVyLnNjcm9sbFBhcmVudCggdHJ1ZSApO1xuXHRcdHRoaXMub2Zmc2V0UGFyZW50ID0gdGhpcy5oZWxwZXIub2Zmc2V0UGFyZW50KCk7XG5cdFx0dGhpcy5oYXNGaXhlZEFuY2VzdG9yID0gdGhpcy5oZWxwZXIucGFyZW50cygpLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiAkKCB0aGlzICkuY3NzKCBcInBvc2l0aW9uXCIgKSA9PT0gXCJmaXhlZFwiO1xuXHRcdFx0fSApLmxlbmd0aCA+IDA7XG5cblx0XHQvL1RoZSBlbGVtZW50J3MgYWJzb2x1dGUgcG9zaXRpb24gb24gdGhlIHBhZ2UgbWludXMgbWFyZ2luc1xuXHRcdHRoaXMucG9zaXRpb25BYnMgPSB0aGlzLmVsZW1lbnQub2Zmc2V0KCk7XG5cdFx0dGhpcy5fcmVmcmVzaE9mZnNldHMoIGV2ZW50ICk7XG5cblx0XHQvL0dlbmVyYXRlIHRoZSBvcmlnaW5hbCBwb3NpdGlvblxuXHRcdHRoaXMub3JpZ2luYWxQb3NpdGlvbiA9IHRoaXMucG9zaXRpb24gPSB0aGlzLl9nZW5lcmF0ZVBvc2l0aW9uKCBldmVudCwgZmFsc2UgKTtcblx0XHR0aGlzLm9yaWdpbmFsUGFnZVggPSBldmVudC5wYWdlWDtcblx0XHR0aGlzLm9yaWdpbmFsUGFnZVkgPSBldmVudC5wYWdlWTtcblxuXHRcdC8vQWRqdXN0IHRoZSBtb3VzZSBvZmZzZXQgcmVsYXRpdmUgdG8gdGhlIGhlbHBlciBpZiBcImN1cnNvckF0XCIgaXMgc3VwcGxpZWRcblx0XHQoIG8uY3Vyc29yQXQgJiYgdGhpcy5fYWRqdXN0T2Zmc2V0RnJvbUhlbHBlciggby5jdXJzb3JBdCApICk7XG5cblx0XHQvL1NldCBhIGNvbnRhaW5tZW50IGlmIGdpdmVuIGluIHRoZSBvcHRpb25zXG5cdFx0dGhpcy5fc2V0Q29udGFpbm1lbnQoKTtcblxuXHRcdC8vVHJpZ2dlciBldmVudCArIGNhbGxiYWNrc1xuXHRcdGlmICggdGhpcy5fdHJpZ2dlciggXCJzdGFydFwiLCBldmVudCApID09PSBmYWxzZSApIHtcblx0XHRcdHRoaXMuX2NsZWFyKCk7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0Ly9SZWNhY2hlIHRoZSBoZWxwZXIgc2l6ZVxuXHRcdHRoaXMuX2NhY2hlSGVscGVyUHJvcG9ydGlvbnMoKTtcblxuXHRcdC8vUHJlcGFyZSB0aGUgZHJvcHBhYmxlIG9mZnNldHNcblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICYmICFvLmRyb3BCZWhhdmlvdXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5wcmVwYXJlT2Zmc2V0cyggdGhpcywgZXZlbnQgKTtcblx0XHR9XG5cblx0XHQvLyBFeGVjdXRlIHRoZSBkcmFnIG9uY2UgLSB0aGlzIGNhdXNlcyB0aGUgaGVscGVyIG5vdCB0byBiZSB2aXNpYmxlIGJlZm9yZSBnZXR0aW5nIGl0c1xuXHRcdC8vIGNvcnJlY3QgcG9zaXRpb25cblx0XHR0aGlzLl9tb3VzZURyYWcoIGV2ZW50LCB0cnVlICk7XG5cblx0XHQvLyBJZiB0aGUgZGRtYW5hZ2VyIGlzIHVzZWQgZm9yIGRyb3BwYWJsZXMsIGluZm9ybSB0aGUgbWFuYWdlciB0aGF0IGRyYWdnaW5nIGhhcyBzdGFydGVkXG5cdFx0Ly8gKHNlZSAjNTAwMylcblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIuZHJhZ1N0YXJ0KCB0aGlzLCBldmVudCApO1xuXHRcdH1cblxuXHRcdHJldHVybiB0cnVlO1xuXHR9LFxuXG5cdF9yZWZyZXNoT2Zmc2V0czogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHRoaXMub2Zmc2V0ID0ge1xuXHRcdFx0dG9wOiB0aGlzLnBvc2l0aW9uQWJzLnRvcCAtIHRoaXMubWFyZ2lucy50b3AsXG5cdFx0XHRsZWZ0OiB0aGlzLnBvc2l0aW9uQWJzLmxlZnQgLSB0aGlzLm1hcmdpbnMubGVmdCxcblx0XHRcdHNjcm9sbDogZmFsc2UsXG5cdFx0XHRwYXJlbnQ6IHRoaXMuX2dldFBhcmVudE9mZnNldCgpLFxuXHRcdFx0cmVsYXRpdmU6IHRoaXMuX2dldFJlbGF0aXZlT2Zmc2V0KClcblx0XHR9O1xuXG5cdFx0dGhpcy5vZmZzZXQuY2xpY2sgPSB7XG5cdFx0XHRsZWZ0OiBldmVudC5wYWdlWCAtIHRoaXMub2Zmc2V0LmxlZnQsXG5cdFx0XHR0b3A6IGV2ZW50LnBhZ2VZIC0gdGhpcy5vZmZzZXQudG9wXG5cdFx0fTtcblx0fSxcblxuXHRfbW91c2VEcmFnOiBmdW5jdGlvbiggZXZlbnQsIG5vUHJvcGFnYXRpb24gKSB7XG5cblx0XHQvLyByZXNldCBhbnkgbmVjZXNzYXJ5IGNhY2hlZCBwcm9wZXJ0aWVzIChzZWUgIzUwMDkpXG5cdFx0aWYgKCB0aGlzLmhhc0ZpeGVkQW5jZXN0b3IgKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQgPSB0aGlzLl9nZXRQYXJlbnRPZmZzZXQoKTtcblx0XHR9XG5cblx0XHQvL0NvbXB1dGUgdGhlIGhlbHBlcnMgcG9zaXRpb25cblx0XHR0aGlzLnBvc2l0aW9uID0gdGhpcy5fZ2VuZXJhdGVQb3NpdGlvbiggZXZlbnQsIHRydWUgKTtcblx0XHR0aGlzLnBvc2l0aW9uQWJzID0gdGhpcy5fY29udmVydFBvc2l0aW9uVG8oIFwiYWJzb2x1dGVcIiApO1xuXG5cdFx0Ly9DYWxsIHBsdWdpbnMgYW5kIGNhbGxiYWNrcyBhbmQgdXNlIHRoZSByZXN1bHRpbmcgcG9zaXRpb24gaWYgc29tZXRoaW5nIGlzIHJldHVybmVkXG5cdFx0aWYgKCAhbm9Qcm9wYWdhdGlvbiApIHtcblx0XHRcdHZhciB1aSA9IHRoaXMuX3VpSGFzaCgpO1xuXHRcdFx0aWYgKCB0aGlzLl90cmlnZ2VyKCBcImRyYWdcIiwgZXZlbnQsIHVpICkgPT09IGZhbHNlICkge1xuXHRcdFx0XHR0aGlzLl9tb3VzZVVwKCBuZXcgJC5FdmVudCggXCJtb3VzZXVwXCIsIGV2ZW50ICkgKTtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5wb3NpdGlvbiA9IHVpLnBvc2l0aW9uO1xuXHRcdH1cblxuXHRcdHRoaXMuaGVscGVyWyAwIF0uc3R5bGUubGVmdCA9IHRoaXMucG9zaXRpb24ubGVmdCArIFwicHhcIjtcblx0XHR0aGlzLmhlbHBlclsgMCBdLnN0eWxlLnRvcCA9IHRoaXMucG9zaXRpb24udG9wICsgXCJweFwiO1xuXG5cdFx0aWYgKCAkLnVpLmRkbWFuYWdlciApIHtcblx0XHRcdCQudWkuZGRtYW5hZ2VyLmRyYWcoIHRoaXMsIGV2ZW50ICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXG5cdF9tb3VzZVN0b3A6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdC8vSWYgd2UgYXJlIHVzaW5nIGRyb3BwYWJsZXMsIGluZm9ybSB0aGUgbWFuYWdlciBhYm91dCB0aGUgZHJvcFxuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdGRyb3BwZWQgPSBmYWxzZTtcblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICYmICF0aGlzLm9wdGlvbnMuZHJvcEJlaGF2aW91ciApIHtcblx0XHRcdGRyb3BwZWQgPSAkLnVpLmRkbWFuYWdlci5kcm9wKCB0aGlzLCBldmVudCApO1xuXHRcdH1cblxuXHRcdC8vaWYgYSBkcm9wIGNvbWVzIGZyb20gb3V0c2lkZSAoYSBzb3J0YWJsZSlcblx0XHRpZiAoIHRoaXMuZHJvcHBlZCApIHtcblx0XHRcdGRyb3BwZWQgPSB0aGlzLmRyb3BwZWQ7XG5cdFx0XHR0aGlzLmRyb3BwZWQgPSBmYWxzZTtcblx0XHR9XG5cblx0XHRpZiAoICggdGhpcy5vcHRpb25zLnJldmVydCA9PT0gXCJpbnZhbGlkXCIgJiYgIWRyb3BwZWQgKSB8fFxuXHRcdFx0XHQoIHRoaXMub3B0aW9ucy5yZXZlcnQgPT09IFwidmFsaWRcIiAmJiBkcm9wcGVkICkgfHxcblx0XHRcdFx0dGhpcy5vcHRpb25zLnJldmVydCA9PT0gdHJ1ZSB8fCAoICQuaXNGdW5jdGlvbiggdGhpcy5vcHRpb25zLnJldmVydCApICYmXG5cdFx0XHRcdHRoaXMub3B0aW9ucy5yZXZlcnQuY2FsbCggdGhpcy5lbGVtZW50LCBkcm9wcGVkICkgKVxuXHRcdCkge1xuXHRcdFx0JCggdGhpcy5oZWxwZXIgKS5hbmltYXRlKFxuXHRcdFx0XHR0aGlzLm9yaWdpbmFsUG9zaXRpb24sXG5cdFx0XHRcdHBhcnNlSW50KCB0aGlzLm9wdGlvbnMucmV2ZXJ0RHVyYXRpb24sIDEwICksXG5cdFx0XHRcdGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdGlmICggdGhhdC5fdHJpZ2dlciggXCJzdG9wXCIsIGV2ZW50ICkgIT09IGZhbHNlICkge1xuXHRcdFx0XHRcdFx0dGhhdC5fY2xlYXIoKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdH1cblx0XHRcdCk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGlmICggdGhpcy5fdHJpZ2dlciggXCJzdG9wXCIsIGV2ZW50ICkgIT09IGZhbHNlICkge1xuXHRcdFx0XHR0aGlzLl9jbGVhcigpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblxuXHRfbW91c2VVcDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHRoaXMuX3VuYmxvY2tGcmFtZXMoKTtcblxuXHRcdC8vIElmIHRoZSBkZG1hbmFnZXIgaXMgdXNlZCBmb3IgZHJvcHBhYmxlcywgaW5mb3JtIHRoZSBtYW5hZ2VyIHRoYXQgZHJhZ2dpbmcgaGFzIHN0b3BwZWRcblx0XHQvLyAoc2VlICM1MDAzKVxuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5kcmFnU3RvcCggdGhpcywgZXZlbnQgKTtcblx0XHR9XG5cblx0XHQvLyBPbmx5IG5lZWQgdG8gZm9jdXMgaWYgdGhlIGV2ZW50IG9jY3VycmVkIG9uIHRoZSBkcmFnZ2FibGUgaXRzZWxmLCBzZWUgIzEwNTI3XG5cdFx0aWYgKCB0aGlzLmhhbmRsZUVsZW1lbnQuaXMoIGV2ZW50LnRhcmdldCApICkge1xuXG5cdFx0XHQvLyBUaGUgaW50ZXJhY3Rpb24gaXMgb3Zlcjsgd2hldGhlciBvciBub3QgdGhlIGNsaWNrIHJlc3VsdGVkIGluIGEgZHJhZyxcblx0XHRcdC8vIGZvY3VzIHRoZSBlbGVtZW50XG5cdFx0XHR0aGlzLmVsZW1lbnQudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuICQudWkubW91c2UucHJvdG90eXBlLl9tb3VzZVVwLmNhbGwoIHRoaXMsIGV2ZW50ICk7XG5cdH0sXG5cblx0Y2FuY2VsOiBmdW5jdGlvbigpIHtcblxuXHRcdGlmICggdGhpcy5oZWxwZXIuaXMoIFwiLnVpLWRyYWdnYWJsZS1kcmFnZ2luZ1wiICkgKSB7XG5cdFx0XHR0aGlzLl9tb3VzZVVwKCBuZXcgJC5FdmVudCggXCJtb3VzZXVwXCIsIHsgdGFyZ2V0OiB0aGlzLmVsZW1lbnRbIDAgXSB9ICkgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5fY2xlYXIoKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9LFxuXG5cdF9nZXRIYW5kbGU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLmhhbmRsZSA/XG5cdFx0XHQhISQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIHRoaXMuZWxlbWVudC5maW5kKCB0aGlzLm9wdGlvbnMuaGFuZGxlICkgKS5sZW5ndGggOlxuXHRcdFx0dHJ1ZTtcblx0fSxcblxuXHRfc2V0SGFuZGxlQ2xhc3NOYW1lOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmhhbmRsZUVsZW1lbnQgPSB0aGlzLm9wdGlvbnMuaGFuZGxlID9cblx0XHRcdHRoaXMuZWxlbWVudC5maW5kKCB0aGlzLm9wdGlvbnMuaGFuZGxlICkgOiB0aGlzLmVsZW1lbnQ7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaGFuZGxlRWxlbWVudCwgXCJ1aS1kcmFnZ2FibGUtaGFuZGxlXCIgKTtcblx0fSxcblxuXHRfcmVtb3ZlSGFuZGxlQ2xhc3NOYW1lOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5oYW5kbGVFbGVtZW50LCBcInVpLWRyYWdnYWJsZS1oYW5kbGVcIiApO1xuXHR9LFxuXG5cdF9jcmVhdGVIZWxwZXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHZhciBvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0aGVscGVySXNGdW5jdGlvbiA9ICQuaXNGdW5jdGlvbiggby5oZWxwZXIgKSxcblx0XHRcdGhlbHBlciA9IGhlbHBlcklzRnVuY3Rpb24gP1xuXHRcdFx0XHQkKCBvLmhlbHBlci5hcHBseSggdGhpcy5lbGVtZW50WyAwIF0sIFsgZXZlbnQgXSApICkgOlxuXHRcdFx0XHQoIG8uaGVscGVyID09PSBcImNsb25lXCIgP1xuXHRcdFx0XHRcdHRoaXMuZWxlbWVudC5jbG9uZSgpLnJlbW92ZUF0dHIoIFwiaWRcIiApIDpcblx0XHRcdFx0XHR0aGlzLmVsZW1lbnQgKTtcblxuXHRcdGlmICggIWhlbHBlci5wYXJlbnRzKCBcImJvZHlcIiApLmxlbmd0aCApIHtcblx0XHRcdGhlbHBlci5hcHBlbmRUbyggKCBvLmFwcGVuZFRvID09PSBcInBhcmVudFwiID9cblx0XHRcdFx0dGhpcy5lbGVtZW50WyAwIF0ucGFyZW50Tm9kZSA6XG5cdFx0XHRcdG8uYXBwZW5kVG8gKSApO1xuXHRcdH1cblxuXHRcdC8vIEh0dHA6Ly9idWdzLmpxdWVyeXVpLmNvbS90aWNrZXQvOTQ0NlxuXHRcdC8vIGEgaGVscGVyIGZ1bmN0aW9uIGNhbiByZXR1cm4gdGhlIG9yaWdpbmFsIGVsZW1lbnRcblx0XHQvLyB3aGljaCB3b3VsZG4ndCBoYXZlIGJlZW4gc2V0IHRvIHJlbGF0aXZlIGluIF9jcmVhdGVcblx0XHRpZiAoIGhlbHBlcklzRnVuY3Rpb24gJiYgaGVscGVyWyAwIF0gPT09IHRoaXMuZWxlbWVudFsgMCBdICkge1xuXHRcdFx0dGhpcy5fc2V0UG9zaXRpb25SZWxhdGl2ZSgpO1xuXHRcdH1cblxuXHRcdGlmICggaGVscGVyWyAwIF0gIT09IHRoaXMuZWxlbWVudFsgMCBdICYmXG5cdFx0XHRcdCEoIC8oZml4ZWR8YWJzb2x1dGUpLyApLnRlc3QoIGhlbHBlci5jc3MoIFwicG9zaXRpb25cIiApICkgKSB7XG5cdFx0XHRoZWxwZXIuY3NzKCBcInBvc2l0aW9uXCIsIFwiYWJzb2x1dGVcIiApO1xuXHRcdH1cblxuXHRcdHJldHVybiBoZWxwZXI7XG5cblx0fSxcblxuXHRfc2V0UG9zaXRpb25SZWxhdGl2ZTogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAhKCAvXig/OnJ8YXxmKS8gKS50ZXN0KCB0aGlzLmVsZW1lbnQuY3NzKCBcInBvc2l0aW9uXCIgKSApICkge1xuXHRcdFx0dGhpcy5lbGVtZW50WyAwIF0uc3R5bGUucG9zaXRpb24gPSBcInJlbGF0aXZlXCI7XG5cdFx0fVxuXHR9LFxuXG5cdF9hZGp1c3RPZmZzZXRGcm9tSGVscGVyOiBmdW5jdGlvbiggb2JqICkge1xuXHRcdGlmICggdHlwZW9mIG9iaiA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdG9iaiA9IG9iai5zcGxpdCggXCIgXCIgKTtcblx0XHR9XG5cdFx0aWYgKCAkLmlzQXJyYXkoIG9iaiApICkge1xuXHRcdFx0b2JqID0geyBsZWZ0OiArb2JqWyAwIF0sIHRvcDogK29ialsgMSBdIHx8IDAgfTtcblx0XHR9XG5cdFx0aWYgKCBcImxlZnRcIiBpbiBvYmogKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5jbGljay5sZWZ0ID0gb2JqLmxlZnQgKyB0aGlzLm1hcmdpbnMubGVmdDtcblx0XHR9XG5cdFx0aWYgKCBcInJpZ2h0XCIgaW4gb2JqICkge1xuXHRcdFx0dGhpcy5vZmZzZXQuY2xpY2subGVmdCA9IHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLSBvYmoucmlnaHQgKyB0aGlzLm1hcmdpbnMubGVmdDtcblx0XHR9XG5cdFx0aWYgKCBcInRvcFwiIGluIG9iaiApIHtcblx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA9IG9iai50b3AgKyB0aGlzLm1hcmdpbnMudG9wO1xuXHRcdH1cblx0XHRpZiAoIFwiYm90dG9tXCIgaW4gb2JqICkge1xuXHRcdFx0dGhpcy5vZmZzZXQuY2xpY2sudG9wID0gdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLSBvYmouYm90dG9tICsgdGhpcy5tYXJnaW5zLnRvcDtcblx0XHR9XG5cdH0sXG5cblx0X2lzUm9vdE5vZGU6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHJldHVybiAoIC8oaHRtbHxib2R5KS9pICkudGVzdCggZWxlbWVudC50YWdOYW1lICkgfHwgZWxlbWVudCA9PT0gdGhpcy5kb2N1bWVudFsgMCBdO1xuXHR9LFxuXG5cdF9nZXRQYXJlbnRPZmZzZXQ6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly9HZXQgdGhlIG9mZnNldFBhcmVudCBhbmQgY2FjaGUgaXRzIHBvc2l0aW9uXG5cdFx0dmFyIHBvID0gdGhpcy5vZmZzZXRQYXJlbnQub2Zmc2V0KCksXG5cdFx0XHRkb2N1bWVudCA9IHRoaXMuZG9jdW1lbnRbIDAgXTtcblxuXHRcdC8vIFRoaXMgaXMgYSBzcGVjaWFsIGNhc2Ugd2hlcmUgd2UgbmVlZCB0byBtb2RpZnkgYSBvZmZzZXQgY2FsY3VsYXRlZCBvbiBzdGFydCwgc2luY2UgdGhlXG5cdFx0Ly8gZm9sbG93aW5nIGhhcHBlbmVkOlxuXHRcdC8vIDEuIFRoZSBwb3NpdGlvbiBvZiB0aGUgaGVscGVyIGlzIGFic29sdXRlLCBzbyBpdCdzIHBvc2l0aW9uIGlzIGNhbGN1bGF0ZWQgYmFzZWQgb24gdGhlXG5cdFx0Ly8gbmV4dCBwb3NpdGlvbmVkIHBhcmVudFxuXHRcdC8vIDIuIFRoZSBhY3R1YWwgb2Zmc2V0IHBhcmVudCBpcyBhIGNoaWxkIG9mIHRoZSBzY3JvbGwgcGFyZW50LCBhbmQgdGhlIHNjcm9sbCBwYXJlbnQgaXNuJ3Rcblx0XHQvLyB0aGUgZG9jdW1lbnQsIHdoaWNoIG1lYW5zIHRoYXQgdGhlIHNjcm9sbCBpcyBpbmNsdWRlZCBpbiB0aGUgaW5pdGlhbCBjYWxjdWxhdGlvbiBvZiB0aGVcblx0XHQvLyBvZmZzZXQgb2YgdGhlIHBhcmVudCwgYW5kIG5ldmVyIHJlY2FsY3VsYXRlZCB1cG9uIGRyYWdcblx0XHRpZiAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiYWJzb2x1dGVcIiAmJiB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICE9PSBkb2N1bWVudCAmJlxuXHRcdFx0XHQkLmNvbnRhaW5zKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdLCB0aGlzLm9mZnNldFBhcmVudFsgMCBdICkgKSB7XG5cdFx0XHRwby5sZWZ0ICs9IHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbExlZnQoKTtcblx0XHRcdHBvLnRvcCArPSB0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxUb3AoKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX2lzUm9vdE5vZGUoIHRoaXMub2Zmc2V0UGFyZW50WyAwIF0gKSApIHtcblx0XHRcdHBvID0geyB0b3A6IDAsIGxlZnQ6IDAgfTtcblx0XHR9XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiBwby50b3AgKyAoIHBhcnNlSW50KCB0aGlzLm9mZnNldFBhcmVudC5jc3MoIFwiYm9yZGVyVG9wV2lkdGhcIiApLCAxMCApIHx8IDAgKSxcblx0XHRcdGxlZnQ6IHBvLmxlZnQgKyAoIHBhcnNlSW50KCB0aGlzLm9mZnNldFBhcmVudC5jc3MoIFwiYm9yZGVyTGVmdFdpZHRoXCIgKSwgMTAgKSB8fCAwIClcblx0XHR9O1xuXG5cdH0sXG5cblx0X2dldFJlbGF0aXZlT2Zmc2V0OiBmdW5jdGlvbigpIHtcblx0XHRpZiAoIHRoaXMuY3NzUG9zaXRpb24gIT09IFwicmVsYXRpdmVcIiApIHtcblx0XHRcdHJldHVybiB7IHRvcDogMCwgbGVmdDogMCB9O1xuXHRcdH1cblxuXHRcdHZhciBwID0gdGhpcy5lbGVtZW50LnBvc2l0aW9uKCksXG5cdFx0XHRzY3JvbGxJc1Jvb3ROb2RlID0gdGhpcy5faXNSb290Tm9kZSggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSApO1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogcC50b3AgLSAoIHBhcnNlSW50KCB0aGlzLmhlbHBlci5jc3MoIFwidG9wXCIgKSwgMTAgKSB8fCAwICkgK1xuXHRcdFx0XHQoICFzY3JvbGxJc1Jvb3ROb2RlID8gdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsVG9wKCkgOiAwICksXG5cdFx0XHRsZWZ0OiBwLmxlZnQgLSAoIHBhcnNlSW50KCB0aGlzLmhlbHBlci5jc3MoIFwibGVmdFwiICksIDEwICkgfHwgMCApICtcblx0XHRcdFx0KCAhc2Nyb2xsSXNSb290Tm9kZSA/IHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbExlZnQoKSA6IDAgKVxuXHRcdH07XG5cblx0fSxcblxuXHRfY2FjaGVNYXJnaW5zOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLm1hcmdpbnMgPSB7XG5cdFx0XHRsZWZ0OiAoIHBhcnNlSW50KCB0aGlzLmVsZW1lbnQuY3NzKCBcIm1hcmdpbkxlZnRcIiApLCAxMCApIHx8IDAgKSxcblx0XHRcdHRvcDogKCBwYXJzZUludCggdGhpcy5lbGVtZW50LmNzcyggXCJtYXJnaW5Ub3BcIiApLCAxMCApIHx8IDAgKSxcblx0XHRcdHJpZ2h0OiAoIHBhcnNlSW50KCB0aGlzLmVsZW1lbnQuY3NzKCBcIm1hcmdpblJpZ2h0XCIgKSwgMTAgKSB8fCAwICksXG5cdFx0XHRib3R0b206ICggcGFyc2VJbnQoIHRoaXMuZWxlbWVudC5jc3MoIFwibWFyZ2luQm90dG9tXCIgKSwgMTAgKSB8fCAwIClcblx0XHR9O1xuXHR9LFxuXG5cdF9jYWNoZUhlbHBlclByb3BvcnRpb25zOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zID0ge1xuXHRcdFx0d2lkdGg6IHRoaXMuaGVscGVyLm91dGVyV2lkdGgoKSxcblx0XHRcdGhlaWdodDogdGhpcy5oZWxwZXIub3V0ZXJIZWlnaHQoKVxuXHRcdH07XG5cdH0sXG5cblx0X3NldENvbnRhaW5tZW50OiBmdW5jdGlvbigpIHtcblxuXHRcdHZhciBpc1VzZXJTY3JvbGxhYmxlLCBjLCBjZSxcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRkb2N1bWVudCA9IHRoaXMuZG9jdW1lbnRbIDAgXTtcblxuXHRcdHRoaXMucmVsYXRpdmVDb250YWluZXIgPSBudWxsO1xuXG5cdFx0aWYgKCAhby5jb250YWlubWVudCApIHtcblx0XHRcdHRoaXMuY29udGFpbm1lbnQgPSBudWxsO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggby5jb250YWlubWVudCA9PT0gXCJ3aW5kb3dcIiApIHtcblx0XHRcdHRoaXMuY29udGFpbm1lbnQgPSBbXG5cdFx0XHRcdCQoIHdpbmRvdyApLnNjcm9sbExlZnQoKSAtIHRoaXMub2Zmc2V0LnJlbGF0aXZlLmxlZnQgLSB0aGlzLm9mZnNldC5wYXJlbnQubGVmdCxcblx0XHRcdFx0JCggd2luZG93ICkuc2Nyb2xsVG9wKCkgLSB0aGlzLm9mZnNldC5yZWxhdGl2ZS50b3AgLSB0aGlzLm9mZnNldC5wYXJlbnQudG9wLFxuXHRcdFx0XHQkKCB3aW5kb3cgKS5zY3JvbGxMZWZ0KCkgKyAkKCB3aW5kb3cgKS53aWR0aCgpIC1cblx0XHRcdFx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC0gdGhpcy5tYXJnaW5zLmxlZnQsXG5cdFx0XHRcdCQoIHdpbmRvdyApLnNjcm9sbFRvcCgpICtcblx0XHRcdFx0XHQoICQoIHdpbmRvdyApLmhlaWdodCgpIHx8IGRvY3VtZW50LmJvZHkucGFyZW50Tm9kZS5zY3JvbGxIZWlnaHQgKSAtXG5cdFx0XHRcdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLSB0aGlzLm1hcmdpbnMudG9wXG5cdFx0XHRdO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggby5jb250YWlubWVudCA9PT0gXCJkb2N1bWVudFwiICkge1xuXHRcdFx0dGhpcy5jb250YWlubWVudCA9IFtcblx0XHRcdFx0MCxcblx0XHRcdFx0MCxcblx0XHRcdFx0JCggZG9jdW1lbnQgKS53aWR0aCgpIC0gdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAtIHRoaXMubWFyZ2lucy5sZWZ0LFxuXHRcdFx0XHQoICQoIGRvY3VtZW50ICkuaGVpZ2h0KCkgfHwgZG9jdW1lbnQuYm9keS5wYXJlbnROb2RlLnNjcm9sbEhlaWdodCApIC1cblx0XHRcdFx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAtIHRoaXMubWFyZ2lucy50b3Bcblx0XHRcdF07XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBvLmNvbnRhaW5tZW50LmNvbnN0cnVjdG9yID09PSBBcnJheSApIHtcblx0XHRcdHRoaXMuY29udGFpbm1lbnQgPSBvLmNvbnRhaW5tZW50O1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggby5jb250YWlubWVudCA9PT0gXCJwYXJlbnRcIiApIHtcblx0XHRcdG8uY29udGFpbm1lbnQgPSB0aGlzLmhlbHBlclsgMCBdLnBhcmVudE5vZGU7XG5cdFx0fVxuXG5cdFx0YyA9ICQoIG8uY29udGFpbm1lbnQgKTtcblx0XHRjZSA9IGNbIDAgXTtcblxuXHRcdGlmICggIWNlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlzVXNlclNjcm9sbGFibGUgPSAvKHNjcm9sbHxhdXRvKS8udGVzdCggYy5jc3MoIFwib3ZlcmZsb3dcIiApICk7XG5cblx0XHR0aGlzLmNvbnRhaW5tZW50ID0gW1xuXHRcdFx0KCBwYXJzZUludCggYy5jc3MoIFwiYm9yZGVyTGVmdFdpZHRoXCIgKSwgMTAgKSB8fCAwICkgK1xuXHRcdFx0XHQoIHBhcnNlSW50KCBjLmNzcyggXCJwYWRkaW5nTGVmdFwiICksIDEwICkgfHwgMCApLFxuXHRcdFx0KCBwYXJzZUludCggYy5jc3MoIFwiYm9yZGVyVG9wV2lkdGhcIiApLCAxMCApIHx8IDAgKSArXG5cdFx0XHRcdCggcGFyc2VJbnQoIGMuY3NzKCBcInBhZGRpbmdUb3BcIiApLCAxMCApIHx8IDAgKSxcblx0XHRcdCggaXNVc2VyU2Nyb2xsYWJsZSA/IE1hdGgubWF4KCBjZS5zY3JvbGxXaWR0aCwgY2Uub2Zmc2V0V2lkdGggKSA6IGNlLm9mZnNldFdpZHRoICkgLVxuXHRcdFx0XHQoIHBhcnNlSW50KCBjLmNzcyggXCJib3JkZXJSaWdodFdpZHRoXCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHQoIHBhcnNlSW50KCBjLmNzcyggXCJwYWRkaW5nUmlnaHRcIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLVxuXHRcdFx0XHR0aGlzLm1hcmdpbnMubGVmdCAtXG5cdFx0XHRcdHRoaXMubWFyZ2lucy5yaWdodCxcblx0XHRcdCggaXNVc2VyU2Nyb2xsYWJsZSA/IE1hdGgubWF4KCBjZS5zY3JvbGxIZWlnaHQsIGNlLm9mZnNldEhlaWdodCApIDogY2Uub2Zmc2V0SGVpZ2h0ICkgLVxuXHRcdFx0XHQoIHBhcnNlSW50KCBjLmNzcyggXCJib3JkZXJCb3R0b21XaWR0aFwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0KCBwYXJzZUludCggYy5jc3MoIFwicGFkZGluZ0JvdHRvbVwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLVxuXHRcdFx0XHR0aGlzLm1hcmdpbnMudG9wIC1cblx0XHRcdFx0dGhpcy5tYXJnaW5zLmJvdHRvbVxuXHRcdF07XG5cdFx0dGhpcy5yZWxhdGl2ZUNvbnRhaW5lciA9IGM7XG5cdH0sXG5cblx0X2NvbnZlcnRQb3NpdGlvblRvOiBmdW5jdGlvbiggZCwgcG9zICkge1xuXG5cdFx0aWYgKCAhcG9zICkge1xuXHRcdFx0cG9zID0gdGhpcy5wb3NpdGlvbjtcblx0XHR9XG5cblx0XHR2YXIgbW9kID0gZCA9PT0gXCJhYnNvbHV0ZVwiID8gMSA6IC0xLFxuXHRcdFx0c2Nyb2xsSXNSb290Tm9kZSA9IHRoaXMuX2lzUm9vdE5vZGUoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gKTtcblxuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IChcblxuXHRcdFx0XHQvLyBUaGUgYWJzb2x1dGUgbW91c2UgcG9zaXRpb25cblx0XHRcdFx0cG9zLnRvcFx0K1xuXG5cdFx0XHRcdC8vIE9ubHkgZm9yIHJlbGF0aXZlIHBvc2l0aW9uZWQgbm9kZXM6IFJlbGF0aXZlIG9mZnNldCBmcm9tIGVsZW1lbnQgdG8gb2Zmc2V0IHBhcmVudFxuXHRcdFx0XHR0aGlzLm9mZnNldC5yZWxhdGl2ZS50b3AgKiBtb2QgK1xuXG5cdFx0XHRcdC8vIFRoZSBvZmZzZXRQYXJlbnQncyBvZmZzZXQgd2l0aG91dCBib3JkZXJzIChvZmZzZXQgKyBib3JkZXIpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudC50b3AgKiBtb2QgLVxuXHRcdFx0XHQoICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJmaXhlZFwiID9cblx0XHRcdFx0XHQtdGhpcy5vZmZzZXQuc2Nyb2xsLnRvcCA6XG5cdFx0XHRcdFx0KCBzY3JvbGxJc1Jvb3ROb2RlID8gMCA6IHRoaXMub2Zmc2V0LnNjcm9sbC50b3AgKSApICogbW9kIClcblx0XHRcdCksXG5cdFx0XHRsZWZ0OiAoXG5cblx0XHRcdFx0Ly8gVGhlIGFic29sdXRlIG1vdXNlIHBvc2l0aW9uXG5cdFx0XHRcdHBvcy5sZWZ0ICtcblxuXHRcdFx0XHQvLyBPbmx5IGZvciByZWxhdGl2ZSBwb3NpdGlvbmVkIG5vZGVzOiBSZWxhdGl2ZSBvZmZzZXQgZnJvbSBlbGVtZW50IHRvIG9mZnNldCBwYXJlbnRcblx0XHRcdFx0dGhpcy5vZmZzZXQucmVsYXRpdmUubGVmdCAqIG1vZCArXG5cblx0XHRcdFx0Ly8gVGhlIG9mZnNldFBhcmVudCdzIG9mZnNldCB3aXRob3V0IGJvcmRlcnMgKG9mZnNldCArIGJvcmRlcilcblx0XHRcdFx0dGhpcy5vZmZzZXQucGFyZW50LmxlZnQgKiBtb2RcdC1cblx0XHRcdFx0KCAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiZml4ZWRcIiA/XG5cdFx0XHRcdFx0LXRoaXMub2Zmc2V0LnNjcm9sbC5sZWZ0IDpcblx0XHRcdFx0XHQoIHNjcm9sbElzUm9vdE5vZGUgPyAwIDogdGhpcy5vZmZzZXQuc2Nyb2xsLmxlZnQgKSApICogbW9kIClcblx0XHRcdClcblx0XHR9O1xuXG5cdH0sXG5cblx0X2dlbmVyYXRlUG9zaXRpb246IGZ1bmN0aW9uKCBldmVudCwgY29uc3RyYWluUG9zaXRpb24gKSB7XG5cblx0XHR2YXIgY29udGFpbm1lbnQsIGNvLCB0b3AsIGxlZnQsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0c2Nyb2xsSXNSb290Tm9kZSA9IHRoaXMuX2lzUm9vdE5vZGUoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gKSxcblx0XHRcdHBhZ2VYID0gZXZlbnQucGFnZVgsXG5cdFx0XHRwYWdlWSA9IGV2ZW50LnBhZ2VZO1xuXG5cdFx0Ly8gQ2FjaGUgdGhlIHNjcm9sbFxuXHRcdGlmICggIXNjcm9sbElzUm9vdE5vZGUgfHwgIXRoaXMub2Zmc2V0LnNjcm9sbCApIHtcblx0XHRcdHRoaXMub2Zmc2V0LnNjcm9sbCA9IHtcblx0XHRcdFx0dG9wOiB0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxUb3AoKSxcblx0XHRcdFx0bGVmdDogdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCgpXG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdC8qXG5cdFx0ICogLSBQb3NpdGlvbiBjb25zdHJhaW5pbmcgLVxuXHRcdCAqIENvbnN0cmFpbiB0aGUgcG9zaXRpb24gdG8gYSBtaXggb2YgZ3JpZCwgY29udGFpbm1lbnQuXG5cdFx0ICovXG5cblx0XHQvLyBJZiB3ZSBhcmUgbm90IGRyYWdnaW5nIHlldCwgd2Ugd29uJ3QgY2hlY2sgZm9yIG9wdGlvbnNcblx0XHRpZiAoIGNvbnN0cmFpblBvc2l0aW9uICkge1xuXHRcdFx0aWYgKCB0aGlzLmNvbnRhaW5tZW50ICkge1xuXHRcdFx0XHRpZiAoIHRoaXMucmVsYXRpdmVDb250YWluZXIgKSB7XG5cdFx0XHRcdFx0Y28gPSB0aGlzLnJlbGF0aXZlQ29udGFpbmVyLm9mZnNldCgpO1xuXHRcdFx0XHRcdGNvbnRhaW5tZW50ID0gW1xuXHRcdFx0XHRcdFx0dGhpcy5jb250YWlubWVudFsgMCBdICsgY28ubGVmdCxcblx0XHRcdFx0XHRcdHRoaXMuY29udGFpbm1lbnRbIDEgXSArIGNvLnRvcCxcblx0XHRcdFx0XHRcdHRoaXMuY29udGFpbm1lbnRbIDIgXSArIGNvLmxlZnQsXG5cdFx0XHRcdFx0XHR0aGlzLmNvbnRhaW5tZW50WyAzIF0gKyBjby50b3Bcblx0XHRcdFx0XHRdO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdGNvbnRhaW5tZW50ID0gdGhpcy5jb250YWlubWVudDtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVggLSB0aGlzLm9mZnNldC5jbGljay5sZWZ0IDwgY29udGFpbm1lbnRbIDAgXSApIHtcblx0XHRcdFx0XHRwYWdlWCA9IGNvbnRhaW5tZW50WyAwIF0gKyB0aGlzLm9mZnNldC5jbGljay5sZWZ0O1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVkgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPCBjb250YWlubWVudFsgMSBdICkge1xuXHRcdFx0XHRcdHBhZ2VZID0gY29udGFpbm1lbnRbIDEgXSArIHRoaXMub2Zmc2V0LmNsaWNrLnRvcDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VYIC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA+IGNvbnRhaW5tZW50WyAyIF0gKSB7XG5cdFx0XHRcdFx0cGFnZVggPSBjb250YWlubWVudFsgMiBdICsgdGhpcy5vZmZzZXQuY2xpY2subGVmdDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VZIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wID4gY29udGFpbm1lbnRbIDMgXSApIHtcblx0XHRcdFx0XHRwYWdlWSA9IGNvbnRhaW5tZW50WyAzIF0gKyB0aGlzLm9mZnNldC5jbGljay50b3A7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBvLmdyaWQgKSB7XG5cblx0XHRcdFx0Ly9DaGVjayBmb3IgZ3JpZCBlbGVtZW50cyBzZXQgdG8gMCB0byBwcmV2ZW50IGRpdmlkZSBieSAwIGVycm9yIGNhdXNpbmcgaW52YWxpZFxuXHRcdFx0XHQvLyBhcmd1bWVudCBlcnJvcnMgaW4gSUUgKHNlZSB0aWNrZXQgIzY5NTApXG5cdFx0XHRcdHRvcCA9IG8uZ3JpZFsgMSBdID8gdGhpcy5vcmlnaW5hbFBhZ2VZICsgTWF0aC5yb3VuZCggKCBwYWdlWSAtXG5cdFx0XHRcdFx0dGhpcy5vcmlnaW5hbFBhZ2VZICkgLyBvLmdyaWRbIDEgXSApICogby5ncmlkWyAxIF0gOiB0aGlzLm9yaWdpbmFsUGFnZVk7XG5cdFx0XHRcdHBhZ2VZID0gY29udGFpbm1lbnQgPyAoICggdG9wIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wID49IGNvbnRhaW5tZW50WyAxIF0gfHxcblx0XHRcdFx0XHR0b3AgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPiBjb250YWlubWVudFsgMyBdICkgP1xuXHRcdFx0XHRcdFx0dG9wIDpcblx0XHRcdFx0XHRcdCggKCB0b3AgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPj0gY29udGFpbm1lbnRbIDEgXSApID9cblx0XHRcdFx0XHRcdFx0dG9wIC0gby5ncmlkWyAxIF0gOiB0b3AgKyBvLmdyaWRbIDEgXSApICkgOiB0b3A7XG5cblx0XHRcdFx0bGVmdCA9IG8uZ3JpZFsgMCBdID8gdGhpcy5vcmlnaW5hbFBhZ2VYICtcblx0XHRcdFx0XHRNYXRoLnJvdW5kKCAoIHBhZ2VYIC0gdGhpcy5vcmlnaW5hbFBhZ2VYICkgLyBvLmdyaWRbIDAgXSApICogby5ncmlkWyAwIF0gOlxuXHRcdFx0XHRcdHRoaXMub3JpZ2luYWxQYWdlWDtcblx0XHRcdFx0cGFnZVggPSBjb250YWlubWVudCA/ICggKCBsZWZ0IC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA+PSBjb250YWlubWVudFsgMCBdIHx8XG5cdFx0XHRcdFx0bGVmdCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPiBjb250YWlubWVudFsgMiBdICkgP1xuXHRcdFx0XHRcdFx0bGVmdCA6XG5cdFx0XHRcdFx0XHQoICggbGVmdCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPj0gY29udGFpbm1lbnRbIDAgXSApID9cblx0XHRcdFx0XHRcdFx0bGVmdCAtIG8uZ3JpZFsgMCBdIDogbGVmdCArIG8uZ3JpZFsgMCBdICkgKSA6IGxlZnQ7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggby5heGlzID09PSBcInlcIiApIHtcblx0XHRcdFx0cGFnZVggPSB0aGlzLm9yaWdpbmFsUGFnZVg7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggby5heGlzID09PSBcInhcIiApIHtcblx0XHRcdFx0cGFnZVkgPSB0aGlzLm9yaWdpbmFsUGFnZVk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRvcDogKFxuXG5cdFx0XHRcdC8vIFRoZSBhYnNvbHV0ZSBtb3VzZSBwb3NpdGlvblxuXHRcdFx0XHRwYWdlWSAtXG5cblx0XHRcdFx0Ly8gQ2xpY2sgb2Zmc2V0IChyZWxhdGl2ZSB0byB0aGUgZWxlbWVudClcblx0XHRcdFx0dGhpcy5vZmZzZXQuY2xpY2sudG9wIC1cblxuXHRcdFx0XHQvLyBPbmx5IGZvciByZWxhdGl2ZSBwb3NpdGlvbmVkIG5vZGVzOiBSZWxhdGl2ZSBvZmZzZXQgZnJvbSBlbGVtZW50IHRvIG9mZnNldCBwYXJlbnRcblx0XHRcdFx0dGhpcy5vZmZzZXQucmVsYXRpdmUudG9wIC1cblxuXHRcdFx0XHQvLyBUaGUgb2Zmc2V0UGFyZW50J3Mgb2Zmc2V0IHdpdGhvdXQgYm9yZGVycyAob2Zmc2V0ICsgYm9yZGVyKVxuXHRcdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQudG9wICtcblx0XHRcdFx0KCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImZpeGVkXCIgP1xuXHRcdFx0XHRcdC10aGlzLm9mZnNldC5zY3JvbGwudG9wIDpcblx0XHRcdFx0XHQoIHNjcm9sbElzUm9vdE5vZGUgPyAwIDogdGhpcy5vZmZzZXQuc2Nyb2xsLnRvcCApIClcblx0XHRcdCksXG5cdFx0XHRsZWZ0OiAoXG5cblx0XHRcdFx0Ly8gVGhlIGFic29sdXRlIG1vdXNlIHBvc2l0aW9uXG5cdFx0XHRcdHBhZ2VYIC1cblxuXHRcdFx0XHQvLyBDbGljayBvZmZzZXQgKHJlbGF0aXZlIHRvIHRoZSBlbGVtZW50KVxuXHRcdFx0XHR0aGlzLm9mZnNldC5jbGljay5sZWZ0IC1cblxuXHRcdFx0XHQvLyBPbmx5IGZvciByZWxhdGl2ZSBwb3NpdGlvbmVkIG5vZGVzOiBSZWxhdGl2ZSBvZmZzZXQgZnJvbSBlbGVtZW50IHRvIG9mZnNldCBwYXJlbnRcblx0XHRcdFx0dGhpcy5vZmZzZXQucmVsYXRpdmUubGVmdCAtXG5cblx0XHRcdFx0Ly8gVGhlIG9mZnNldFBhcmVudCdzIG9mZnNldCB3aXRob3V0IGJvcmRlcnMgKG9mZnNldCArIGJvcmRlcilcblx0XHRcdFx0dGhpcy5vZmZzZXQucGFyZW50LmxlZnQgK1xuXHRcdFx0XHQoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiZml4ZWRcIiA/XG5cdFx0XHRcdFx0LXRoaXMub2Zmc2V0LnNjcm9sbC5sZWZ0IDpcblx0XHRcdFx0XHQoIHNjcm9sbElzUm9vdE5vZGUgPyAwIDogdGhpcy5vZmZzZXQuc2Nyb2xsLmxlZnQgKSApXG5cdFx0XHQpXG5cdFx0fTtcblxuXHR9LFxuXG5cdF9jbGVhcjogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuaGVscGVyLCBcInVpLWRyYWdnYWJsZS1kcmFnZ2luZ1wiICk7XG5cdFx0aWYgKCB0aGlzLmhlbHBlclsgMCBdICE9PSB0aGlzLmVsZW1lbnRbIDAgXSAmJiAhdGhpcy5jYW5jZWxIZWxwZXJSZW1vdmFsICkge1xuXHRcdFx0dGhpcy5oZWxwZXIucmVtb3ZlKCk7XG5cdFx0fVxuXHRcdHRoaXMuaGVscGVyID0gbnVsbDtcblx0XHR0aGlzLmNhbmNlbEhlbHBlclJlbW92YWwgPSBmYWxzZTtcblx0XHRpZiAoIHRoaXMuZGVzdHJveU9uQ2xlYXIgKSB7XG5cdFx0XHR0aGlzLmRlc3Ryb3koKTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gRnJvbSBub3cgb24gYnVsayBzdHVmZiAtIG1haW5seSBoZWxwZXJzXG5cblx0X3RyaWdnZXI6IGZ1bmN0aW9uKCB0eXBlLCBldmVudCwgdWkgKSB7XG5cdFx0dWkgPSB1aSB8fCB0aGlzLl91aUhhc2goKTtcblx0XHQkLnVpLnBsdWdpbi5jYWxsKCB0aGlzLCB0eXBlLCBbIGV2ZW50LCB1aSwgdGhpcyBdLCB0cnVlICk7XG5cblx0XHQvLyBBYnNvbHV0ZSBwb3NpdGlvbiBhbmQgb2Zmc2V0IChzZWUgIzY4ODQgKSBoYXZlIHRvIGJlIHJlY2FsY3VsYXRlZCBhZnRlciBwbHVnaW5zXG5cdFx0aWYgKCAvXihkcmFnfHN0YXJ0fHN0b3ApLy50ZXN0KCB0eXBlICkgKSB7XG5cdFx0XHR0aGlzLnBvc2l0aW9uQWJzID0gdGhpcy5fY29udmVydFBvc2l0aW9uVG8oIFwiYWJzb2x1dGVcIiApO1xuXHRcdFx0dWkub2Zmc2V0ID0gdGhpcy5wb3NpdGlvbkFicztcblx0XHR9XG5cdFx0cmV0dXJuICQuV2lkZ2V0LnByb3RvdHlwZS5fdHJpZ2dlci5jYWxsKCB0aGlzLCB0eXBlLCBldmVudCwgdWkgKTtcblx0fSxcblxuXHRwbHVnaW5zOiB7fSxcblxuXHRfdWlIYXNoOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0aGVscGVyOiB0aGlzLmhlbHBlcixcblx0XHRcdHBvc2l0aW9uOiB0aGlzLnBvc2l0aW9uLFxuXHRcdFx0b3JpZ2luYWxQb3NpdGlvbjogdGhpcy5vcmlnaW5hbFBvc2l0aW9uLFxuXHRcdFx0b2Zmc2V0OiB0aGlzLnBvc2l0aW9uQWJzXG5cdFx0fTtcblx0fVxuXG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJkcmFnZ2FibGVcIiwgXCJjb25uZWN0VG9Tb3J0YWJsZVwiLCB7XG5cdHN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIHVpLCBkcmFnZ2FibGUgKSB7XG5cdFx0dmFyIHVpU29ydGFibGUgPSAkLmV4dGVuZCgge30sIHVpLCB7XG5cdFx0XHRpdGVtOiBkcmFnZ2FibGUuZWxlbWVudFxuXHRcdH0gKTtcblxuXHRcdGRyYWdnYWJsZS5zb3J0YWJsZXMgPSBbXTtcblx0XHQkKCBkcmFnZ2FibGUub3B0aW9ucy5jb25uZWN0VG9Tb3J0YWJsZSApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHNvcnRhYmxlID0gJCggdGhpcyApLnNvcnRhYmxlKCBcImluc3RhbmNlXCIgKTtcblxuXHRcdFx0aWYgKCBzb3J0YWJsZSAmJiAhc29ydGFibGUub3B0aW9ucy5kaXNhYmxlZCApIHtcblx0XHRcdFx0ZHJhZ2dhYmxlLnNvcnRhYmxlcy5wdXNoKCBzb3J0YWJsZSApO1xuXG5cdFx0XHRcdC8vIFJlZnJlc2hQb3NpdGlvbnMgaXMgY2FsbGVkIGF0IGRyYWcgc3RhcnQgdG8gcmVmcmVzaCB0aGUgY29udGFpbmVyQ2FjaGVcblx0XHRcdFx0Ly8gd2hpY2ggaXMgdXNlZCBpbiBkcmFnLiBUaGlzIGVuc3VyZXMgaXQncyBpbml0aWFsaXplZCBhbmQgc3luY2hyb25pemVkXG5cdFx0XHRcdC8vIHdpdGggYW55IGNoYW5nZXMgdGhhdCBtaWdodCBoYXZlIGhhcHBlbmVkIG9uIHRoZSBwYWdlIHNpbmNlIGluaXRpYWxpemF0aW9uLlxuXHRcdFx0XHRzb3J0YWJsZS5yZWZyZXNoUG9zaXRpb25zKCk7XG5cdFx0XHRcdHNvcnRhYmxlLl90cmlnZ2VyKCBcImFjdGl2YXRlXCIsIGV2ZW50LCB1aVNvcnRhYmxlICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9LFxuXHRzdG9wOiBmdW5jdGlvbiggZXZlbnQsIHVpLCBkcmFnZ2FibGUgKSB7XG5cdFx0dmFyIHVpU29ydGFibGUgPSAkLmV4dGVuZCgge30sIHVpLCB7XG5cdFx0XHRpdGVtOiBkcmFnZ2FibGUuZWxlbWVudFxuXHRcdH0gKTtcblxuXHRcdGRyYWdnYWJsZS5jYW5jZWxIZWxwZXJSZW1vdmFsID0gZmFsc2U7XG5cblx0XHQkLmVhY2goIGRyYWdnYWJsZS5zb3J0YWJsZXMsIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHNvcnRhYmxlID0gdGhpcztcblxuXHRcdFx0aWYgKCBzb3J0YWJsZS5pc092ZXIgKSB7XG5cdFx0XHRcdHNvcnRhYmxlLmlzT3ZlciA9IDA7XG5cblx0XHRcdFx0Ly8gQWxsb3cgdGhpcyBzb3J0YWJsZSB0byBoYW5kbGUgcmVtb3ZpbmcgdGhlIGhlbHBlclxuXHRcdFx0XHRkcmFnZ2FibGUuY2FuY2VsSGVscGVyUmVtb3ZhbCA9IHRydWU7XG5cdFx0XHRcdHNvcnRhYmxlLmNhbmNlbEhlbHBlclJlbW92YWwgPSBmYWxzZTtcblxuXHRcdFx0XHQvLyBVc2UgX3N0b3JlZENTUyBUbyByZXN0b3JlIHByb3BlcnRpZXMgaW4gdGhlIHNvcnRhYmxlLFxuXHRcdFx0XHQvLyBhcyB0aGlzIGFsc28gaGFuZGxlcyByZXZlcnQgKCM5Njc1KSBzaW5jZSB0aGUgZHJhZ2dhYmxlXG5cdFx0XHRcdC8vIG1heSBoYXZlIG1vZGlmaWVkIHRoZW0gaW4gdW5leHBlY3RlZCB3YXlzICgjODgwOSlcblx0XHRcdFx0c29ydGFibGUuX3N0b3JlZENTUyA9IHtcblx0XHRcdFx0XHRwb3NpdGlvbjogc29ydGFibGUucGxhY2Vob2xkZXIuY3NzKCBcInBvc2l0aW9uXCIgKSxcblx0XHRcdFx0XHR0b3A6IHNvcnRhYmxlLnBsYWNlaG9sZGVyLmNzcyggXCJ0b3BcIiApLFxuXHRcdFx0XHRcdGxlZnQ6IHNvcnRhYmxlLnBsYWNlaG9sZGVyLmNzcyggXCJsZWZ0XCIgKVxuXHRcdFx0XHR9O1xuXG5cdFx0XHRcdHNvcnRhYmxlLl9tb3VzZVN0b3AoIGV2ZW50ICk7XG5cblx0XHRcdFx0Ly8gT25jZSBkcmFnIGhhcyBlbmRlZCwgdGhlIHNvcnRhYmxlIHNob3VsZCByZXR1cm4gdG8gdXNpbmdcblx0XHRcdFx0Ly8gaXRzIG9yaWdpbmFsIGhlbHBlciwgbm90IHRoZSBzaGFyZWQgaGVscGVyIGZyb20gZHJhZ2dhYmxlXG5cdFx0XHRcdHNvcnRhYmxlLm9wdGlvbnMuaGVscGVyID0gc29ydGFibGUub3B0aW9ucy5faGVscGVyO1xuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBQcmV2ZW50IHRoaXMgU29ydGFibGUgZnJvbSByZW1vdmluZyB0aGUgaGVscGVyLlxuXHRcdFx0XHQvLyBIb3dldmVyLCBkb24ndCBzZXQgdGhlIGRyYWdnYWJsZSB0byByZW1vdmUgdGhlIGhlbHBlclxuXHRcdFx0XHQvLyBlaXRoZXIgYXMgYW5vdGhlciBjb25uZWN0ZWQgU29ydGFibGUgbWF5IHlldCBoYW5kbGUgdGhlIHJlbW92YWwuXG5cdFx0XHRcdHNvcnRhYmxlLmNhbmNlbEhlbHBlclJlbW92YWwgPSB0cnVlO1xuXG5cdFx0XHRcdHNvcnRhYmxlLl90cmlnZ2VyKCBcImRlYWN0aXZhdGVcIiwgZXZlbnQsIHVpU29ydGFibGUgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cdGRyYWc6IGZ1bmN0aW9uKCBldmVudCwgdWksIGRyYWdnYWJsZSApIHtcblx0XHQkLmVhY2goIGRyYWdnYWJsZS5zb3J0YWJsZXMsIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGlubmVybW9zdEludGVyc2VjdGluZyA9IGZhbHNlLFxuXHRcdFx0XHRzb3J0YWJsZSA9IHRoaXM7XG5cblx0XHRcdC8vIENvcHkgb3ZlciB2YXJpYWJsZXMgdGhhdCBzb3J0YWJsZSdzIF9pbnRlcnNlY3RzV2l0aCB1c2VzXG5cdFx0XHRzb3J0YWJsZS5wb3NpdGlvbkFicyA9IGRyYWdnYWJsZS5wb3NpdGlvbkFicztcblx0XHRcdHNvcnRhYmxlLmhlbHBlclByb3BvcnRpb25zID0gZHJhZ2dhYmxlLmhlbHBlclByb3BvcnRpb25zO1xuXHRcdFx0c29ydGFibGUub2Zmc2V0LmNsaWNrID0gZHJhZ2dhYmxlLm9mZnNldC5jbGljaztcblxuXHRcdFx0aWYgKCBzb3J0YWJsZS5faW50ZXJzZWN0c1dpdGgoIHNvcnRhYmxlLmNvbnRhaW5lckNhY2hlICkgKSB7XG5cdFx0XHRcdGlubmVybW9zdEludGVyc2VjdGluZyA9IHRydWU7XG5cblx0XHRcdFx0JC5lYWNoKCBkcmFnZ2FibGUuc29ydGFibGVzLCBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHRcdC8vIENvcHkgb3ZlciB2YXJpYWJsZXMgdGhhdCBzb3J0YWJsZSdzIF9pbnRlcnNlY3RzV2l0aCB1c2VzXG5cdFx0XHRcdFx0dGhpcy5wb3NpdGlvbkFicyA9IGRyYWdnYWJsZS5wb3NpdGlvbkFicztcblx0XHRcdFx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zID0gZHJhZ2dhYmxlLmhlbHBlclByb3BvcnRpb25zO1xuXHRcdFx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrID0gZHJhZ2dhYmxlLm9mZnNldC5jbGljaztcblxuXHRcdFx0XHRcdGlmICggdGhpcyAhPT0gc29ydGFibGUgJiZcblx0XHRcdFx0XHRcdFx0dGhpcy5faW50ZXJzZWN0c1dpdGgoIHRoaXMuY29udGFpbmVyQ2FjaGUgKSAmJlxuXHRcdFx0XHRcdFx0XHQkLmNvbnRhaW5zKCBzb3J0YWJsZS5lbGVtZW50WyAwIF0sIHRoaXMuZWxlbWVudFsgMCBdICkgKSB7XG5cdFx0XHRcdFx0XHRpbm5lcm1vc3RJbnRlcnNlY3RpbmcgPSBmYWxzZTtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRyZXR1cm4gaW5uZXJtb3N0SW50ZXJzZWN0aW5nO1xuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggaW5uZXJtb3N0SW50ZXJzZWN0aW5nICkge1xuXG5cdFx0XHRcdC8vIElmIGl0IGludGVyc2VjdHMsIHdlIHVzZSBhIGxpdHRsZSBpc092ZXIgdmFyaWFibGUgYW5kIHNldCBpdCBvbmNlLFxuXHRcdFx0XHQvLyBzbyB0aGF0IHRoZSBtb3ZlLWluIHN0dWZmIGdldHMgZmlyZWQgb25seSBvbmNlLlxuXHRcdFx0XHRpZiAoICFzb3J0YWJsZS5pc092ZXIgKSB7XG5cdFx0XHRcdFx0c29ydGFibGUuaXNPdmVyID0gMTtcblxuXHRcdFx0XHRcdC8vIFN0b3JlIGRyYWdnYWJsZSdzIHBhcmVudCBpbiBjYXNlIHdlIG5lZWQgdG8gcmVhcHBlbmQgdG8gaXQgbGF0ZXIuXG5cdFx0XHRcdFx0ZHJhZ2dhYmxlLl9wYXJlbnQgPSB1aS5oZWxwZXIucGFyZW50KCk7XG5cblx0XHRcdFx0XHRzb3J0YWJsZS5jdXJyZW50SXRlbSA9IHVpLmhlbHBlclxuXHRcdFx0XHRcdFx0LmFwcGVuZFRvKCBzb3J0YWJsZS5lbGVtZW50IClcblx0XHRcdFx0XHRcdC5kYXRhKCBcInVpLXNvcnRhYmxlLWl0ZW1cIiwgdHJ1ZSApO1xuXG5cdFx0XHRcdFx0Ly8gU3RvcmUgaGVscGVyIG9wdGlvbiB0byBsYXRlciByZXN0b3JlIGl0XG5cdFx0XHRcdFx0c29ydGFibGUub3B0aW9ucy5faGVscGVyID0gc29ydGFibGUub3B0aW9ucy5oZWxwZXI7XG5cblx0XHRcdFx0XHRzb3J0YWJsZS5vcHRpb25zLmhlbHBlciA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0cmV0dXJuIHVpLmhlbHBlclsgMCBdO1xuXHRcdFx0XHRcdH07XG5cblx0XHRcdFx0XHQvLyBGaXJlIHRoZSBzdGFydCBldmVudHMgb2YgdGhlIHNvcnRhYmxlIHdpdGggb3VyIHBhc3NlZCBicm93c2VyIGV2ZW50LFxuXHRcdFx0XHRcdC8vIGFuZCBvdXIgb3duIGhlbHBlciAoc28gaXQgZG9lc24ndCBjcmVhdGUgYSBuZXcgb25lKVxuXHRcdFx0XHRcdGV2ZW50LnRhcmdldCA9IHNvcnRhYmxlLmN1cnJlbnRJdGVtWyAwIF07XG5cdFx0XHRcdFx0c29ydGFibGUuX21vdXNlQ2FwdHVyZSggZXZlbnQsIHRydWUgKTtcblx0XHRcdFx0XHRzb3J0YWJsZS5fbW91c2VTdGFydCggZXZlbnQsIHRydWUsIHRydWUgKTtcblxuXHRcdFx0XHRcdC8vIEJlY2F1c2UgdGhlIGJyb3dzZXIgZXZlbnQgaXMgd2F5IG9mZiB0aGUgbmV3IGFwcGVuZGVkIHBvcnRsZXQsXG5cdFx0XHRcdFx0Ly8gbW9kaWZ5IG5lY2Vzc2FyeSB2YXJpYWJsZXMgdG8gcmVmbGVjdCB0aGUgY2hhbmdlc1xuXHRcdFx0XHRcdHNvcnRhYmxlLm9mZnNldC5jbGljay50b3AgPSBkcmFnZ2FibGUub2Zmc2V0LmNsaWNrLnRvcDtcblx0XHRcdFx0XHRzb3J0YWJsZS5vZmZzZXQuY2xpY2subGVmdCA9IGRyYWdnYWJsZS5vZmZzZXQuY2xpY2subGVmdDtcblx0XHRcdFx0XHRzb3J0YWJsZS5vZmZzZXQucGFyZW50LmxlZnQgLT0gZHJhZ2dhYmxlLm9mZnNldC5wYXJlbnQubGVmdCAtXG5cdFx0XHRcdFx0XHRzb3J0YWJsZS5vZmZzZXQucGFyZW50LmxlZnQ7XG5cdFx0XHRcdFx0c29ydGFibGUub2Zmc2V0LnBhcmVudC50b3AgLT0gZHJhZ2dhYmxlLm9mZnNldC5wYXJlbnQudG9wIC1cblx0XHRcdFx0XHRcdHNvcnRhYmxlLm9mZnNldC5wYXJlbnQudG9wO1xuXG5cdFx0XHRcdFx0ZHJhZ2dhYmxlLl90cmlnZ2VyKCBcInRvU29ydGFibGVcIiwgZXZlbnQgKTtcblxuXHRcdFx0XHRcdC8vIEluZm9ybSBkcmFnZ2FibGUgdGhhdCB0aGUgaGVscGVyIGlzIGluIGEgdmFsaWQgZHJvcCB6b25lLFxuXHRcdFx0XHRcdC8vIHVzZWQgc29sZWx5IGluIHRoZSByZXZlcnQgb3B0aW9uIHRvIGhhbmRsZSBcInZhbGlkL2ludmFsaWRcIi5cblx0XHRcdFx0XHRkcmFnZ2FibGUuZHJvcHBlZCA9IHNvcnRhYmxlLmVsZW1lbnQ7XG5cblx0XHRcdFx0XHQvLyBOZWVkIHRvIHJlZnJlc2hQb3NpdGlvbnMgb2YgYWxsIHNvcnRhYmxlcyBpbiB0aGUgY2FzZSB0aGF0XG5cdFx0XHRcdFx0Ly8gYWRkaW5nIHRvIG9uZSBzb3J0YWJsZSBjaGFuZ2VzIHRoZSBsb2NhdGlvbiBvZiB0aGUgb3RoZXIgc29ydGFibGVzICgjOTY3NSlcblx0XHRcdFx0XHQkLmVhY2goIGRyYWdnYWJsZS5zb3J0YWJsZXMsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0dGhpcy5yZWZyZXNoUG9zaXRpb25zKCk7XG5cdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdFx0Ly8gSGFjayBzbyByZWNlaXZlL3VwZGF0ZSBjYWxsYmFja3Mgd29yayAobW9zdGx5KVxuXHRcdFx0XHRcdGRyYWdnYWJsZS5jdXJyZW50SXRlbSA9IGRyYWdnYWJsZS5lbGVtZW50O1xuXHRcdFx0XHRcdHNvcnRhYmxlLmZyb21PdXRzaWRlID0gZHJhZ2dhYmxlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBzb3J0YWJsZS5jdXJyZW50SXRlbSApIHtcblx0XHRcdFx0XHRzb3J0YWJsZS5fbW91c2VEcmFnKCBldmVudCApO1xuXG5cdFx0XHRcdFx0Ly8gQ29weSB0aGUgc29ydGFibGUncyBwb3NpdGlvbiBiZWNhdXNlIHRoZSBkcmFnZ2FibGUncyBjYW4gcG90ZW50aWFsbHkgcmVmbGVjdFxuXHRcdFx0XHRcdC8vIGEgcmVsYXRpdmUgcG9zaXRpb24sIHdoaWxlIHNvcnRhYmxlIGlzIGFsd2F5cyBhYnNvbHV0ZSwgd2hpY2ggdGhlIGRyYWdnZWRcblx0XHRcdFx0XHQvLyBlbGVtZW50IGhhcyBub3cgYmVjb21lLiAoIzg4MDkpXG5cdFx0XHRcdFx0dWkucG9zaXRpb24gPSBzb3J0YWJsZS5wb3NpdGlvbjtcblx0XHRcdFx0fVxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBJZiBpdCBkb2Vzbid0IGludGVyc2VjdCB3aXRoIHRoZSBzb3J0YWJsZSwgYW5kIGl0IGludGVyc2VjdGVkIGJlZm9yZSxcblx0XHRcdFx0Ly8gd2UgZmFrZSB0aGUgZHJhZyBzdG9wIG9mIHRoZSBzb3J0YWJsZSwgYnV0IG1ha2Ugc3VyZSBpdCBkb2Vzbid0IHJlbW92ZVxuXHRcdFx0XHQvLyB0aGUgaGVscGVyIGJ5IHVzaW5nIGNhbmNlbEhlbHBlclJlbW92YWwuXG5cdFx0XHRcdGlmICggc29ydGFibGUuaXNPdmVyICkge1xuXG5cdFx0XHRcdFx0c29ydGFibGUuaXNPdmVyID0gMDtcblx0XHRcdFx0XHRzb3J0YWJsZS5jYW5jZWxIZWxwZXJSZW1vdmFsID0gdHJ1ZTtcblxuXHRcdFx0XHRcdC8vIENhbGxpbmcgc29ydGFibGUncyBtb3VzZVN0b3Agd291bGQgdHJpZ2dlciBhIHJldmVydCxcblx0XHRcdFx0XHQvLyBzbyByZXZlcnQgbXVzdCBiZSB0ZW1wb3JhcmlseSBmYWxzZSB1bnRpbCBhZnRlciBtb3VzZVN0b3AgaXMgY2FsbGVkLlxuXHRcdFx0XHRcdHNvcnRhYmxlLm9wdGlvbnMuX3JldmVydCA9IHNvcnRhYmxlLm9wdGlvbnMucmV2ZXJ0O1xuXHRcdFx0XHRcdHNvcnRhYmxlLm9wdGlvbnMucmV2ZXJ0ID0gZmFsc2U7XG5cblx0XHRcdFx0XHRzb3J0YWJsZS5fdHJpZ2dlciggXCJvdXRcIiwgZXZlbnQsIHNvcnRhYmxlLl91aUhhc2goIHNvcnRhYmxlICkgKTtcblx0XHRcdFx0XHRzb3J0YWJsZS5fbW91c2VTdG9wKCBldmVudCwgdHJ1ZSApO1xuXG5cdFx0XHRcdFx0Ly8gUmVzdG9yZSBzb3J0YWJsZSBiZWhhdmlvcnMgdGhhdCB3ZXJlIG1vZGZpZWRcblx0XHRcdFx0XHQvLyB3aGVuIHRoZSBkcmFnZ2FibGUgZW50ZXJlZCB0aGUgc29ydGFibGUgYXJlYSAoIzk0ODEpXG5cdFx0XHRcdFx0c29ydGFibGUub3B0aW9ucy5yZXZlcnQgPSBzb3J0YWJsZS5vcHRpb25zLl9yZXZlcnQ7XG5cdFx0XHRcdFx0c29ydGFibGUub3B0aW9ucy5oZWxwZXIgPSBzb3J0YWJsZS5vcHRpb25zLl9oZWxwZXI7XG5cblx0XHRcdFx0XHRpZiAoIHNvcnRhYmxlLnBsYWNlaG9sZGVyICkge1xuXHRcdFx0XHRcdFx0c29ydGFibGUucGxhY2Vob2xkZXIucmVtb3ZlKCk7XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gUmVzdG9yZSBhbmQgcmVjYWxjdWxhdGUgdGhlIGRyYWdnYWJsZSdzIG9mZnNldCBjb25zaWRlcmluZyB0aGUgc29ydGFibGVcblx0XHRcdFx0XHQvLyBtYXkgaGF2ZSBtb2RpZmllZCB0aGVtIGluIHVuZXhwZWN0ZWQgd2F5cy4gKCM4ODA5LCAjMTA2NjkpXG5cdFx0XHRcdFx0dWkuaGVscGVyLmFwcGVuZFRvKCBkcmFnZ2FibGUuX3BhcmVudCApO1xuXHRcdFx0XHRcdGRyYWdnYWJsZS5fcmVmcmVzaE9mZnNldHMoIGV2ZW50ICk7XG5cdFx0XHRcdFx0dWkucG9zaXRpb24gPSBkcmFnZ2FibGUuX2dlbmVyYXRlUG9zaXRpb24oIGV2ZW50LCB0cnVlICk7XG5cblx0XHRcdFx0XHRkcmFnZ2FibGUuX3RyaWdnZXIoIFwiZnJvbVNvcnRhYmxlXCIsIGV2ZW50ICk7XG5cblx0XHRcdFx0XHQvLyBJbmZvcm0gZHJhZ2dhYmxlIHRoYXQgdGhlIGhlbHBlciBpcyBubyBsb25nZXIgaW4gYSB2YWxpZCBkcm9wIHpvbmVcblx0XHRcdFx0XHRkcmFnZ2FibGUuZHJvcHBlZCA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0Ly8gTmVlZCB0byByZWZyZXNoUG9zaXRpb25zIG9mIGFsbCBzb3J0YWJsZXMganVzdCBpbiBjYXNlIHJlbW92aW5nXG5cdFx0XHRcdFx0Ly8gZnJvbSBvbmUgc29ydGFibGUgY2hhbmdlcyB0aGUgbG9jYXRpb24gb2Ygb3RoZXIgc29ydGFibGVzICgjOTY3NSlcblx0XHRcdFx0XHQkLmVhY2goIGRyYWdnYWJsZS5zb3J0YWJsZXMsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0dGhpcy5yZWZyZXNoUG9zaXRpb25zKCk7XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSApO1xuXHR9XG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJkcmFnZ2FibGVcIiwgXCJjdXJzb3JcIiwge1xuXHRzdGFydDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaW5zdGFuY2UgKSB7XG5cdFx0dmFyIHQgPSAkKCBcImJvZHlcIiApLFxuXHRcdFx0byA9IGluc3RhbmNlLm9wdGlvbnM7XG5cblx0XHRpZiAoIHQuY3NzKCBcImN1cnNvclwiICkgKSB7XG5cdFx0XHRvLl9jdXJzb3IgPSB0LmNzcyggXCJjdXJzb3JcIiApO1xuXHRcdH1cblx0XHR0LmNzcyggXCJjdXJzb3JcIiwgby5jdXJzb3IgKTtcblx0fSxcblx0c3RvcDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaW5zdGFuY2UgKSB7XG5cdFx0dmFyIG8gPSBpbnN0YW5jZS5vcHRpb25zO1xuXHRcdGlmICggby5fY3Vyc29yICkge1xuXHRcdFx0JCggXCJib2R5XCIgKS5jc3MoIFwiY3Vyc29yXCIsIG8uX2N1cnNvciApO1xuXHRcdH1cblx0fVxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwiZHJhZ2dhYmxlXCIsIFwib3BhY2l0eVwiLCB7XG5cdHN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpbnN0YW5jZSApIHtcblx0XHR2YXIgdCA9ICQoIHVpLmhlbHBlciApLFxuXHRcdFx0byA9IGluc3RhbmNlLm9wdGlvbnM7XG5cdFx0aWYgKCB0LmNzcyggXCJvcGFjaXR5XCIgKSApIHtcblx0XHRcdG8uX29wYWNpdHkgPSB0LmNzcyggXCJvcGFjaXR5XCIgKTtcblx0XHR9XG5cdFx0dC5jc3MoIFwib3BhY2l0eVwiLCBvLm9wYWNpdHkgKTtcblx0fSxcblx0c3RvcDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaW5zdGFuY2UgKSB7XG5cdFx0dmFyIG8gPSBpbnN0YW5jZS5vcHRpb25zO1xuXHRcdGlmICggby5fb3BhY2l0eSApIHtcblx0XHRcdCQoIHVpLmhlbHBlciApLmNzcyggXCJvcGFjaXR5XCIsIG8uX29wYWNpdHkgKTtcblx0XHR9XG5cdH1cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcImRyYWdnYWJsZVwiLCBcInNjcm9sbFwiLCB7XG5cdHN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpICkge1xuXHRcdGlmICggIWkuc2Nyb2xsUGFyZW50Tm90SGlkZGVuICkge1xuXHRcdFx0aS5zY3JvbGxQYXJlbnROb3RIaWRkZW4gPSBpLmhlbHBlci5zY3JvbGxQYXJlbnQoIGZhbHNlICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBpLnNjcm9sbFBhcmVudE5vdEhpZGRlblsgMCBdICE9PSBpLmRvY3VtZW50WyAwIF0gJiZcblx0XHRcdFx0aS5zY3JvbGxQYXJlbnROb3RIaWRkZW5bIDAgXS50YWdOYW1lICE9PSBcIkhUTUxcIiApIHtcblx0XHRcdGkub3ZlcmZsb3dPZmZzZXQgPSBpLnNjcm9sbFBhcmVudE5vdEhpZGRlbi5vZmZzZXQoKTtcblx0XHR9XG5cdH0sXG5cdGRyYWc6IGZ1bmN0aW9uKCBldmVudCwgdWksIGkgICkge1xuXG5cdFx0dmFyIG8gPSBpLm9wdGlvbnMsXG5cdFx0XHRzY3JvbGxlZCA9IGZhbHNlLFxuXHRcdFx0c2Nyb2xsUGFyZW50ID0gaS5zY3JvbGxQYXJlbnROb3RIaWRkZW5bIDAgXSxcblx0XHRcdGRvY3VtZW50ID0gaS5kb2N1bWVudFsgMCBdO1xuXG5cdFx0aWYgKCBzY3JvbGxQYXJlbnQgIT09IGRvY3VtZW50ICYmIHNjcm9sbFBhcmVudC50YWdOYW1lICE9PSBcIkhUTUxcIiApIHtcblx0XHRcdGlmICggIW8uYXhpcyB8fCBvLmF4aXMgIT09IFwieFwiICkge1xuXHRcdFx0XHRpZiAoICggaS5vdmVyZmxvd09mZnNldC50b3AgKyBzY3JvbGxQYXJlbnQub2Zmc2V0SGVpZ2h0ICkgLSBldmVudC5wYWdlWSA8XG5cdFx0XHRcdFx0XHRvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbFBhcmVudC5zY3JvbGxUb3AgPSBzY3JvbGxlZCA9IHNjcm9sbFBhcmVudC5zY3JvbGxUb3AgKyBvLnNjcm9sbFNwZWVkO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCBldmVudC5wYWdlWSAtIGkub3ZlcmZsb3dPZmZzZXQudG9wIDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxQYXJlbnQuc2Nyb2xsVG9wID0gc2Nyb2xsZWQgPSBzY3JvbGxQYXJlbnQuc2Nyb2xsVG9wIC0gby5zY3JvbGxTcGVlZDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICFvLmF4aXMgfHwgby5heGlzICE9PSBcInlcIiApIHtcblx0XHRcdFx0aWYgKCAoIGkub3ZlcmZsb3dPZmZzZXQubGVmdCArIHNjcm9sbFBhcmVudC5vZmZzZXRXaWR0aCApIC0gZXZlbnQucGFnZVggPFxuXHRcdFx0XHRcdFx0by5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCA9IHNjcm9sbGVkID0gc2Nyb2xsUGFyZW50LnNjcm9sbExlZnQgKyBvLnNjcm9sbFNwZWVkO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCBldmVudC5wYWdlWCAtIGkub3ZlcmZsb3dPZmZzZXQubGVmdCA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsUGFyZW50LnNjcm9sbExlZnQgPSBzY3JvbGxlZCA9IHNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0IC0gby5zY3JvbGxTcGVlZDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0aWYgKCAhby5heGlzIHx8IG8uYXhpcyAhPT0gXCJ4XCIgKSB7XG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVkgLSAkKCBkb2N1bWVudCApLnNjcm9sbFRvcCgpIDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxlZCA9ICQoIGRvY3VtZW50ICkuc2Nyb2xsVG9wKCAkKCBkb2N1bWVudCApLnNjcm9sbFRvcCgpIC0gby5zY3JvbGxTcGVlZCApO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCAkKCB3aW5kb3cgKS5oZWlnaHQoKSAtICggZXZlbnQucGFnZVkgLSAkKCBkb2N1bWVudCApLnNjcm9sbFRvcCgpICkgPFxuXHRcdFx0XHRcdFx0by5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxlZCA9ICQoIGRvY3VtZW50ICkuc2Nyb2xsVG9wKCAkKCBkb2N1bWVudCApLnNjcm9sbFRvcCgpICsgby5zY3JvbGxTcGVlZCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGlmICggIW8uYXhpcyB8fCBvLmF4aXMgIT09IFwieVwiICkge1xuXHRcdFx0XHRpZiAoIGV2ZW50LnBhZ2VYIC0gJCggZG9jdW1lbnQgKS5zY3JvbGxMZWZ0KCkgPCBvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbGVkID0gJCggZG9jdW1lbnQgKS5zY3JvbGxMZWZ0KFxuXHRcdFx0XHRcdFx0JCggZG9jdW1lbnQgKS5zY3JvbGxMZWZ0KCkgLSBvLnNjcm9sbFNwZWVkXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0fSBlbHNlIGlmICggJCggd2luZG93ICkud2lkdGgoKSAtICggZXZlbnQucGFnZVggLSAkKCBkb2N1bWVudCApLnNjcm9sbExlZnQoKSApIDxcblx0XHRcdFx0XHRcdG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0c2Nyb2xsZWQgPSAkKCBkb2N1bWVudCApLnNjcm9sbExlZnQoXG5cdFx0XHRcdFx0XHQkKCBkb2N1bWVudCApLnNjcm9sbExlZnQoKSArIG8uc2Nyb2xsU3BlZWRcblx0XHRcdFx0XHQpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHNjcm9sbGVkICE9PSBmYWxzZSAmJiAkLnVpLmRkbWFuYWdlciAmJiAhby5kcm9wQmVoYXZpb3VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIucHJlcGFyZU9mZnNldHMoIGksIGV2ZW50ICk7XG5cdFx0fVxuXG5cdH1cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcImRyYWdnYWJsZVwiLCBcInNuYXBcIiwge1xuXHRzdGFydDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaSApIHtcblxuXHRcdHZhciBvID0gaS5vcHRpb25zO1xuXG5cdFx0aS5zbmFwRWxlbWVudHMgPSBbXTtcblxuXHRcdCQoIG8uc25hcC5jb25zdHJ1Y3RvciAhPT0gU3RyaW5nID8gKCBvLnNuYXAuaXRlbXMgfHwgXCI6ZGF0YSh1aS1kcmFnZ2FibGUpXCIgKSA6IG8uc25hcCApXG5cdFx0XHQuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciAkdCA9ICQoIHRoaXMgKSxcblx0XHRcdFx0XHQkbyA9ICR0Lm9mZnNldCgpO1xuXHRcdFx0XHRpZiAoIHRoaXMgIT09IGkuZWxlbWVudFsgMCBdICkge1xuXHRcdFx0XHRcdGkuc25hcEVsZW1lbnRzLnB1c2goIHtcblx0XHRcdFx0XHRcdGl0ZW06IHRoaXMsXG5cdFx0XHRcdFx0XHR3aWR0aDogJHQub3V0ZXJXaWR0aCgpLCBoZWlnaHQ6ICR0Lm91dGVySGVpZ2h0KCksXG5cdFx0XHRcdFx0XHR0b3A6ICRvLnRvcCwgbGVmdDogJG8ubGVmdFxuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXG5cdH0sXG5cdGRyYWc6IGZ1bmN0aW9uKCBldmVudCwgdWksIGluc3QgKSB7XG5cblx0XHR2YXIgdHMsIGJzLCBscywgcnMsIGwsIHIsIHQsIGIsIGksIGZpcnN0LFxuXHRcdFx0byA9IGluc3Qub3B0aW9ucyxcblx0XHRcdGQgPSBvLnNuYXBUb2xlcmFuY2UsXG5cdFx0XHR4MSA9IHVpLm9mZnNldC5sZWZ0LCB4MiA9IHgxICsgaW5zdC5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCxcblx0XHRcdHkxID0gdWkub2Zmc2V0LnRvcCwgeTIgPSB5MSArIGluc3QuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0O1xuXG5cdFx0Zm9yICggaSA9IGluc3Quc25hcEVsZW1lbnRzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXG5cdFx0XHRsID0gaW5zdC5zbmFwRWxlbWVudHNbIGkgXS5sZWZ0IC0gaW5zdC5tYXJnaW5zLmxlZnQ7XG5cdFx0XHRyID0gbCArIGluc3Quc25hcEVsZW1lbnRzWyBpIF0ud2lkdGg7XG5cdFx0XHR0ID0gaW5zdC5zbmFwRWxlbWVudHNbIGkgXS50b3AgLSBpbnN0Lm1hcmdpbnMudG9wO1xuXHRcdFx0YiA9IHQgKyBpbnN0LnNuYXBFbGVtZW50c1sgaSBdLmhlaWdodDtcblxuXHRcdFx0aWYgKCB4MiA8IGwgLSBkIHx8IHgxID4gciArIGQgfHwgeTIgPCB0IC0gZCB8fCB5MSA+IGIgKyBkIHx8XG5cdFx0XHRcdFx0ISQuY29udGFpbnMoIGluc3Quc25hcEVsZW1lbnRzWyBpIF0uaXRlbS5vd25lckRvY3VtZW50LFxuXHRcdFx0XHRcdGluc3Quc25hcEVsZW1lbnRzWyBpIF0uaXRlbSApICkge1xuXHRcdFx0XHRpZiAoIGluc3Quc25hcEVsZW1lbnRzWyBpIF0uc25hcHBpbmcgKSB7XG5cdFx0XHRcdFx0KCBpbnN0Lm9wdGlvbnMuc25hcC5yZWxlYXNlICYmXG5cdFx0XHRcdFx0XHRpbnN0Lm9wdGlvbnMuc25hcC5yZWxlYXNlLmNhbGwoXG5cdFx0XHRcdFx0XHRcdGluc3QuZWxlbWVudCxcblx0XHRcdFx0XHRcdFx0ZXZlbnQsXG5cdFx0XHRcdFx0XHRcdCQuZXh0ZW5kKCBpbnN0Ll91aUhhc2goKSwgeyBzbmFwSXRlbTogaW5zdC5zbmFwRWxlbWVudHNbIGkgXS5pdGVtIH0gKVxuXHRcdFx0XHRcdFx0KSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGluc3Quc25hcEVsZW1lbnRzWyBpIF0uc25hcHBpbmcgPSBmYWxzZTtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggby5zbmFwTW9kZSAhPT0gXCJpbm5lclwiICkge1xuXHRcdFx0XHR0cyA9IE1hdGguYWJzKCB0IC0geTIgKSA8PSBkO1xuXHRcdFx0XHRicyA9IE1hdGguYWJzKCBiIC0geTEgKSA8PSBkO1xuXHRcdFx0XHRscyA9IE1hdGguYWJzKCBsIC0geDIgKSA8PSBkO1xuXHRcdFx0XHRycyA9IE1hdGguYWJzKCByIC0geDEgKSA8PSBkO1xuXHRcdFx0XHRpZiAoIHRzICkge1xuXHRcdFx0XHRcdHVpLnBvc2l0aW9uLnRvcCA9IGluc3QuX2NvbnZlcnRQb3NpdGlvblRvKCBcInJlbGF0aXZlXCIsIHtcblx0XHRcdFx0XHRcdHRvcDogdCAtIGluc3QuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0LFxuXHRcdFx0XHRcdFx0bGVmdDogMFxuXHRcdFx0XHRcdH0gKS50b3A7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBicyApIHtcblx0XHRcdFx0XHR1aS5wb3NpdGlvbi50b3AgPSBpbnN0Ll9jb252ZXJ0UG9zaXRpb25UbyggXCJyZWxhdGl2ZVwiLCB7XG5cdFx0XHRcdFx0XHR0b3A6IGIsXG5cdFx0XHRcdFx0XHRsZWZ0OiAwXG5cdFx0XHRcdFx0fSApLnRvcDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIGxzICkge1xuXHRcdFx0XHRcdHVpLnBvc2l0aW9uLmxlZnQgPSBpbnN0Ll9jb252ZXJ0UG9zaXRpb25UbyggXCJyZWxhdGl2ZVwiLCB7XG5cdFx0XHRcdFx0XHR0b3A6IDAsXG5cdFx0XHRcdFx0XHRsZWZ0OiBsIC0gaW5zdC5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aFxuXHRcdFx0XHRcdH0gKS5sZWZ0O1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggcnMgKSB7XG5cdFx0XHRcdFx0dWkucG9zaXRpb24ubGVmdCA9IGluc3QuX2NvbnZlcnRQb3NpdGlvblRvKCBcInJlbGF0aXZlXCIsIHtcblx0XHRcdFx0XHRcdHRvcDogMCxcblx0XHRcdFx0XHRcdGxlZnQ6IHJcblx0XHRcdFx0XHR9ICkubGVmdDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRmaXJzdCA9ICggdHMgfHwgYnMgfHwgbHMgfHwgcnMgKTtcblxuXHRcdFx0aWYgKCBvLnNuYXBNb2RlICE9PSBcIm91dGVyXCIgKSB7XG5cdFx0XHRcdHRzID0gTWF0aC5hYnMoIHQgLSB5MSApIDw9IGQ7XG5cdFx0XHRcdGJzID0gTWF0aC5hYnMoIGIgLSB5MiApIDw9IGQ7XG5cdFx0XHRcdGxzID0gTWF0aC5hYnMoIGwgLSB4MSApIDw9IGQ7XG5cdFx0XHRcdHJzID0gTWF0aC5hYnMoIHIgLSB4MiApIDw9IGQ7XG5cdFx0XHRcdGlmICggdHMgKSB7XG5cdFx0XHRcdFx0dWkucG9zaXRpb24udG9wID0gaW5zdC5fY29udmVydFBvc2l0aW9uVG8oIFwicmVsYXRpdmVcIiwge1xuXHRcdFx0XHRcdFx0dG9wOiB0LFxuXHRcdFx0XHRcdFx0bGVmdDogMFxuXHRcdFx0XHRcdH0gKS50b3A7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBicyApIHtcblx0XHRcdFx0XHR1aS5wb3NpdGlvbi50b3AgPSBpbnN0Ll9jb252ZXJ0UG9zaXRpb25UbyggXCJyZWxhdGl2ZVwiLCB7XG5cdFx0XHRcdFx0XHR0b3A6IGIgLSBpbnN0LmhlbHBlclByb3BvcnRpb25zLmhlaWdodCxcblx0XHRcdFx0XHRcdGxlZnQ6IDBcblx0XHRcdFx0XHR9ICkudG9wO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggbHMgKSB7XG5cdFx0XHRcdFx0dWkucG9zaXRpb24ubGVmdCA9IGluc3QuX2NvbnZlcnRQb3NpdGlvblRvKCBcInJlbGF0aXZlXCIsIHtcblx0XHRcdFx0XHRcdHRvcDogMCxcblx0XHRcdFx0XHRcdGxlZnQ6IGxcblx0XHRcdFx0XHR9ICkubGVmdDtcblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIHJzICkge1xuXHRcdFx0XHRcdHVpLnBvc2l0aW9uLmxlZnQgPSBpbnN0Ll9jb252ZXJ0UG9zaXRpb25UbyggXCJyZWxhdGl2ZVwiLCB7XG5cdFx0XHRcdFx0XHR0b3A6IDAsXG5cdFx0XHRcdFx0XHRsZWZ0OiByIC0gaW5zdC5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aFxuXHRcdFx0XHRcdH0gKS5sZWZ0O1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdGlmICggIWluc3Quc25hcEVsZW1lbnRzWyBpIF0uc25hcHBpbmcgJiYgKCB0cyB8fCBicyB8fCBscyB8fCBycyB8fCBmaXJzdCApICkge1xuXHRcdFx0XHQoIGluc3Qub3B0aW9ucy5zbmFwLnNuYXAgJiZcblx0XHRcdFx0XHRpbnN0Lm9wdGlvbnMuc25hcC5zbmFwLmNhbGwoXG5cdFx0XHRcdFx0XHRpbnN0LmVsZW1lbnQsXG5cdFx0XHRcdFx0XHRldmVudCxcblx0XHRcdFx0XHRcdCQuZXh0ZW5kKCBpbnN0Ll91aUhhc2goKSwge1xuXHRcdFx0XHRcdFx0XHRzbmFwSXRlbTogaW5zdC5zbmFwRWxlbWVudHNbIGkgXS5pdGVtXG5cdFx0XHRcdFx0XHR9ICkgKSApO1xuXHRcdFx0fVxuXHRcdFx0aW5zdC5zbmFwRWxlbWVudHNbIGkgXS5zbmFwcGluZyA9ICggdHMgfHwgYnMgfHwgbHMgfHwgcnMgfHwgZmlyc3QgKTtcblxuXHRcdH1cblxuXHR9XG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJkcmFnZ2FibGVcIiwgXCJzdGFja1wiLCB7XG5cdHN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpbnN0YW5jZSApIHtcblx0XHR2YXIgbWluLFxuXHRcdFx0byA9IGluc3RhbmNlLm9wdGlvbnMsXG5cdFx0XHRncm91cCA9ICQubWFrZUFycmF5KCAkKCBvLnN0YWNrICkgKS5zb3J0KCBmdW5jdGlvbiggYSwgYiApIHtcblx0XHRcdFx0cmV0dXJuICggcGFyc2VJbnQoICQoIGEgKS5jc3MoIFwiekluZGV4XCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHRcdCggcGFyc2VJbnQoICQoIGIgKS5jc3MoIFwiekluZGV4XCIgKSwgMTAgKSB8fCAwICk7XG5cdFx0XHR9ICk7XG5cblx0XHRpZiAoICFncm91cC5sZW5ndGggKSB7IHJldHVybjsgfVxuXG5cdFx0bWluID0gcGFyc2VJbnQoICQoIGdyb3VwWyAwIF0gKS5jc3MoIFwiekluZGV4XCIgKSwgMTAgKSB8fCAwO1xuXHRcdCQoIGdyb3VwICkuZWFjaCggZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHQkKCB0aGlzICkuY3NzKCBcInpJbmRleFwiLCBtaW4gKyBpICk7XG5cdFx0fSApO1xuXHRcdHRoaXMuY3NzKCBcInpJbmRleFwiLCAoIG1pbiArIGdyb3VwLmxlbmd0aCApICk7XG5cdH1cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcImRyYWdnYWJsZVwiLCBcInpJbmRleFwiLCB7XG5cdHN0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIHVpLCBpbnN0YW5jZSApIHtcblx0XHR2YXIgdCA9ICQoIHVpLmhlbHBlciApLFxuXHRcdFx0byA9IGluc3RhbmNlLm9wdGlvbnM7XG5cblx0XHRpZiAoIHQuY3NzKCBcInpJbmRleFwiICkgKSB7XG5cdFx0XHRvLl96SW5kZXggPSB0LmNzcyggXCJ6SW5kZXhcIiApO1xuXHRcdH1cblx0XHR0LmNzcyggXCJ6SW5kZXhcIiwgby56SW5kZXggKTtcblx0fSxcblx0c3RvcDogZnVuY3Rpb24oIGV2ZW50LCB1aSwgaW5zdGFuY2UgKSB7XG5cdFx0dmFyIG8gPSBpbnN0YW5jZS5vcHRpb25zO1xuXG5cdFx0aWYgKCBvLl96SW5kZXggKSB7XG5cdFx0XHQkKCB1aS5oZWxwZXIgKS5jc3MoIFwiekluZGV4XCIsIG8uX3pJbmRleCApO1xuXHRcdH1cblx0fVxufSApO1xuXG52YXIgd2lkZ2V0c0RyYWdnYWJsZSA9ICQudWkuZHJhZ2dhYmxlO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFJlc2l6YWJsZSAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogUmVzaXphYmxlXG4vLz4+Z3JvdXA6IEludGVyYWN0aW9uc1xuLy8+PmRlc2NyaXB0aW9uOiBFbmFibGVzIHJlc2l6ZSBmdW5jdGlvbmFsaXR5IGZvciBhbnkgZWxlbWVudC5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9yZXNpemFibGUvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vcmVzaXphYmxlL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvcmVzaXphYmxlLmNzc1xuLy8+PmNzcy50aGVtZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGhlbWUuY3NzXG5cblxuXG4kLndpZGdldCggXCJ1aS5yZXNpemFibGVcIiwgJC51aS5tb3VzZSwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHR3aWRnZXRFdmVudFByZWZpeDogXCJyZXNpemVcIixcblx0b3B0aW9uczoge1xuXHRcdGFsc29SZXNpemU6IGZhbHNlLFxuXHRcdGFuaW1hdGU6IGZhbHNlLFxuXHRcdGFuaW1hdGVEdXJhdGlvbjogXCJzbG93XCIsXG5cdFx0YW5pbWF0ZUVhc2luZzogXCJzd2luZ1wiLFxuXHRcdGFzcGVjdFJhdGlvOiBmYWxzZSxcblx0XHRhdXRvSGlkZTogZmFsc2UsXG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS1yZXNpemFibGUtc2VcIjogXCJ1aS1pY29uIHVpLWljb24tZ3JpcHNtYWxsLWRpYWdvbmFsLXNlXCJcblx0XHR9LFxuXHRcdGNvbnRhaW5tZW50OiBmYWxzZSxcblx0XHRnaG9zdDogZmFsc2UsXG5cdFx0Z3JpZDogZmFsc2UsXG5cdFx0aGFuZGxlczogXCJlLHMsc2VcIixcblx0XHRoZWxwZXI6IGZhbHNlLFxuXHRcdG1heEhlaWdodDogbnVsbCxcblx0XHRtYXhXaWR0aDogbnVsbCxcblx0XHRtaW5IZWlnaHQ6IDEwLFxuXHRcdG1pbldpZHRoOiAxMCxcblxuXHRcdC8vIFNlZSAjNzk2MFxuXHRcdHpJbmRleDogOTAsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRyZXNpemU6IG51bGwsXG5cdFx0c3RhcnQ6IG51bGwsXG5cdFx0c3RvcDogbnVsbFxuXHR9LFxuXG5cdF9udW06IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHRyZXR1cm4gcGFyc2VGbG9hdCggdmFsdWUgKSB8fCAwO1xuXHR9LFxuXG5cdF9pc051bWJlcjogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHJldHVybiAhaXNOYU4oIHBhcnNlRmxvYXQoIHZhbHVlICkgKTtcblx0fSxcblxuXHRfaGFzU2Nyb2xsOiBmdW5jdGlvbiggZWwsIGEgKSB7XG5cblx0XHRpZiAoICQoIGVsICkuY3NzKCBcIm92ZXJmbG93XCIgKSA9PT0gXCJoaWRkZW5cIiApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHR2YXIgc2Nyb2xsID0gKCBhICYmIGEgPT09IFwibGVmdFwiICkgPyBcInNjcm9sbExlZnRcIiA6IFwic2Nyb2xsVG9wXCIsXG5cdFx0XHRoYXMgPSBmYWxzZTtcblxuXHRcdGlmICggZWxbIHNjcm9sbCBdID4gMCApIHtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblxuXHRcdC8vIFRPRE86IGRldGVybWluZSB3aGljaCBjYXNlcyBhY3R1YWxseSBjYXVzZSB0aGlzIHRvIGhhcHBlblxuXHRcdC8vIGlmIHRoZSBlbGVtZW50IGRvZXNuJ3QgaGF2ZSB0aGUgc2Nyb2xsIHNldCwgc2VlIGlmIGl0J3MgcG9zc2libGUgdG9cblx0XHQvLyBzZXQgdGhlIHNjcm9sbFxuXHRcdGVsWyBzY3JvbGwgXSA9IDE7XG5cdFx0aGFzID0gKCBlbFsgc2Nyb2xsIF0gPiAwICk7XG5cdFx0ZWxbIHNjcm9sbCBdID0gMDtcblx0XHRyZXR1cm4gaGFzO1xuXHR9LFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0dmFyIG1hcmdpbnMsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0dGhhdCA9IHRoaXM7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktcmVzaXphYmxlXCIgKTtcblxuXHRcdCQuZXh0ZW5kKCB0aGlzLCB7XG5cdFx0XHRfYXNwZWN0UmF0aW86ICEhKCBvLmFzcGVjdFJhdGlvICksXG5cdFx0XHRhc3BlY3RSYXRpbzogby5hc3BlY3RSYXRpbyxcblx0XHRcdG9yaWdpbmFsRWxlbWVudDogdGhpcy5lbGVtZW50LFxuXHRcdFx0X3Byb3BvcnRpb25hbGx5UmVzaXplRWxlbWVudHM6IFtdLFxuXHRcdFx0X2hlbHBlcjogby5oZWxwZXIgfHwgby5naG9zdCB8fCBvLmFuaW1hdGUgPyBvLmhlbHBlciB8fCBcInVpLXJlc2l6YWJsZS1oZWxwZXJcIiA6IG51bGxcblx0XHR9ICk7XG5cblx0XHQvLyBXcmFwIHRoZSBlbGVtZW50IGlmIGl0IGNhbm5vdCBob2xkIGNoaWxkIG5vZGVzXG5cdFx0aWYgKCB0aGlzLmVsZW1lbnRbIDAgXS5ub2RlTmFtZS5tYXRjaCggL14oY2FudmFzfHRleHRhcmVhfGlucHV0fHNlbGVjdHxidXR0b258aW1nKSQvaSApICkge1xuXG5cdFx0XHR0aGlzLmVsZW1lbnQud3JhcChcblx0XHRcdFx0JCggXCI8ZGl2IGNsYXNzPSd1aS13cmFwcGVyJyBzdHlsZT0nb3ZlcmZsb3c6IGhpZGRlbjsnPjwvZGl2PlwiICkuY3NzKCB7XG5cdFx0XHRcdFx0cG9zaXRpb246IHRoaXMuZWxlbWVudC5jc3MoIFwicG9zaXRpb25cIiApLFxuXHRcdFx0XHRcdHdpZHRoOiB0aGlzLmVsZW1lbnQub3V0ZXJXaWR0aCgpLFxuXHRcdFx0XHRcdGhlaWdodDogdGhpcy5lbGVtZW50Lm91dGVySGVpZ2h0KCksXG5cdFx0XHRcdFx0dG9wOiB0aGlzLmVsZW1lbnQuY3NzKCBcInRvcFwiICksXG5cdFx0XHRcdFx0bGVmdDogdGhpcy5lbGVtZW50LmNzcyggXCJsZWZ0XCIgKVxuXHRcdFx0XHR9IClcblx0XHRcdCk7XG5cblx0XHRcdHRoaXMuZWxlbWVudCA9IHRoaXMuZWxlbWVudC5wYXJlbnQoKS5kYXRhKFxuXHRcdFx0XHRcInVpLXJlc2l6YWJsZVwiLCB0aGlzLmVsZW1lbnQucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKVxuXHRcdFx0KTtcblxuXHRcdFx0dGhpcy5lbGVtZW50SXNXcmFwcGVyID0gdHJ1ZTtcblxuXHRcdFx0bWFyZ2lucyA9IHtcblx0XHRcdFx0bWFyZ2luVG9wOiB0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIFwibWFyZ2luVG9wXCIgKSxcblx0XHRcdFx0bWFyZ2luUmlnaHQ6IHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcyggXCJtYXJnaW5SaWdodFwiICksXG5cdFx0XHRcdG1hcmdpbkJvdHRvbTogdGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCBcIm1hcmdpbkJvdHRvbVwiICksXG5cdFx0XHRcdG1hcmdpbkxlZnQ6IHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcyggXCJtYXJnaW5MZWZ0XCIgKVxuXHRcdFx0fTtcblxuXHRcdFx0dGhpcy5lbGVtZW50LmNzcyggbWFyZ2lucyApO1xuXHRcdFx0dGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCBcIm1hcmdpblwiLCAwICk7XG5cblx0XHRcdC8vIHN1cHBvcnQ6IFNhZmFyaVxuXHRcdFx0Ly8gUHJldmVudCBTYWZhcmkgdGV4dGFyZWEgcmVzaXplXG5cdFx0XHR0aGlzLm9yaWdpbmFsUmVzaXplU3R5bGUgPSB0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIFwicmVzaXplXCIgKTtcblx0XHRcdHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcyggXCJyZXNpemVcIiwgXCJub25lXCIgKTtcblxuXHRcdFx0dGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemVFbGVtZW50cy5wdXNoKCB0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIHtcblx0XHRcdFx0cG9zaXRpb246IFwic3RhdGljXCIsXG5cdFx0XHRcdHpvb206IDEsXG5cdFx0XHRcdGRpc3BsYXk6IFwiYmxvY2tcIlxuXHRcdFx0fSApICk7XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFOVxuXHRcdFx0Ly8gYXZvaWQgSUUganVtcCAoaGFyZCBzZXQgdGhlIG1hcmdpbilcblx0XHRcdHRoaXMub3JpZ2luYWxFbGVtZW50LmNzcyggbWFyZ2lucyApO1xuXG5cdFx0XHR0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZSgpO1xuXHRcdH1cblxuXHRcdHRoaXMuX3NldHVwSGFuZGxlcygpO1xuXG5cdFx0aWYgKCBvLmF1dG9IaWRlICkge1xuXHRcdFx0JCggdGhpcy5lbGVtZW50IClcblx0XHRcdFx0Lm9uKCBcIm1vdXNlZW50ZXJcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0aWYgKCBvLmRpc2FibGVkICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggXCJ1aS1yZXNpemFibGUtYXV0b2hpZGVcIiApO1xuXHRcdFx0XHRcdHRoYXQuX2hhbmRsZXMuc2hvdygpO1xuXHRcdFx0XHR9IClcblx0XHRcdFx0Lm9uKCBcIm1vdXNlbGVhdmVcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0aWYgKCBvLmRpc2FibGVkICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRpZiAoICF0aGF0LnJlc2l6aW5nICkge1xuXHRcdFx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIFwidWktcmVzaXphYmxlLWF1dG9oaWRlXCIgKTtcblx0XHRcdFx0XHRcdHRoYXQuX2hhbmRsZXMuaGlkZSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX21vdXNlSW5pdCgpO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblxuXHRcdHRoaXMuX21vdXNlRGVzdHJveSgpO1xuXG5cdFx0dmFyIHdyYXBwZXIsXG5cdFx0XHRfZGVzdHJveSA9IGZ1bmN0aW9uKCBleHAgKSB7XG5cdFx0XHRcdCQoIGV4cCApXG5cdFx0XHRcdFx0LnJlbW92ZURhdGEoIFwicmVzaXphYmxlXCIgKVxuXHRcdFx0XHRcdC5yZW1vdmVEYXRhKCBcInVpLXJlc2l6YWJsZVwiIClcblx0XHRcdFx0XHQub2ZmKCBcIi5yZXNpemFibGVcIiApXG5cdFx0XHRcdFx0LmZpbmQoIFwiLnVpLXJlc2l6YWJsZS1oYW5kbGVcIiApXG5cdFx0XHRcdFx0XHQucmVtb3ZlKCk7XG5cdFx0XHR9O1xuXG5cdFx0Ly8gVE9ETzogVW53cmFwIGF0IHNhbWUgRE9NIHBvc2l0aW9uXG5cdFx0aWYgKCB0aGlzLmVsZW1lbnRJc1dyYXBwZXIgKSB7XG5cdFx0XHRfZGVzdHJveSggdGhpcy5lbGVtZW50ICk7XG5cdFx0XHR3cmFwcGVyID0gdGhpcy5lbGVtZW50O1xuXHRcdFx0dGhpcy5vcmlnaW5hbEVsZW1lbnQuY3NzKCB7XG5cdFx0XHRcdHBvc2l0aW9uOiB3cmFwcGVyLmNzcyggXCJwb3NpdGlvblwiICksXG5cdFx0XHRcdHdpZHRoOiB3cmFwcGVyLm91dGVyV2lkdGgoKSxcblx0XHRcdFx0aGVpZ2h0OiB3cmFwcGVyLm91dGVySGVpZ2h0KCksXG5cdFx0XHRcdHRvcDogd3JhcHBlci5jc3MoIFwidG9wXCIgKSxcblx0XHRcdFx0bGVmdDogd3JhcHBlci5jc3MoIFwibGVmdFwiIClcblx0XHRcdH0gKS5pbnNlcnRBZnRlciggd3JhcHBlciApO1xuXHRcdFx0d3JhcHBlci5yZW1vdmUoKTtcblx0XHR9XG5cblx0XHR0aGlzLm9yaWdpbmFsRWxlbWVudC5jc3MoIFwicmVzaXplXCIsIHRoaXMub3JpZ2luYWxSZXNpemVTdHlsZSApO1xuXHRcdF9kZXN0cm95KCB0aGlzLm9yaWdpbmFsRWxlbWVudCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdHN3aXRjaCAoIGtleSApIHtcblx0XHRjYXNlIFwiaGFuZGxlc1wiOlxuXHRcdFx0dGhpcy5fcmVtb3ZlSGFuZGxlcygpO1xuXHRcdFx0dGhpcy5fc2V0dXBIYW5kbGVzKCk7XG5cdFx0XHRicmVhaztcblx0XHRkZWZhdWx0OlxuXHRcdFx0YnJlYWs7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXR1cEhhbmRsZXM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvID0gdGhpcy5vcHRpb25zLCBoYW5kbGUsIGksIG4sIGhuYW1lLCBheGlzLCB0aGF0ID0gdGhpcztcblx0XHR0aGlzLmhhbmRsZXMgPSBvLmhhbmRsZXMgfHxcblx0XHRcdCggISQoIFwiLnVpLXJlc2l6YWJsZS1oYW5kbGVcIiwgdGhpcy5lbGVtZW50ICkubGVuZ3RoID9cblx0XHRcdFx0XCJlLHMsc2VcIiA6IHtcblx0XHRcdFx0XHRuOiBcIi51aS1yZXNpemFibGUtblwiLFxuXHRcdFx0XHRcdGU6IFwiLnVpLXJlc2l6YWJsZS1lXCIsXG5cdFx0XHRcdFx0czogXCIudWktcmVzaXphYmxlLXNcIixcblx0XHRcdFx0XHR3OiBcIi51aS1yZXNpemFibGUtd1wiLFxuXHRcdFx0XHRcdHNlOiBcIi51aS1yZXNpemFibGUtc2VcIixcblx0XHRcdFx0XHRzdzogXCIudWktcmVzaXphYmxlLXN3XCIsXG5cdFx0XHRcdFx0bmU6IFwiLnVpLXJlc2l6YWJsZS1uZVwiLFxuXHRcdFx0XHRcdG53OiBcIi51aS1yZXNpemFibGUtbndcIlxuXHRcdFx0XHR9ICk7XG5cblx0XHR0aGlzLl9oYW5kbGVzID0gJCgpO1xuXHRcdGlmICggdGhpcy5oYW5kbGVzLmNvbnN0cnVjdG9yID09PSBTdHJpbmcgKSB7XG5cblx0XHRcdGlmICggdGhpcy5oYW5kbGVzID09PSBcImFsbFwiICkge1xuXHRcdFx0XHR0aGlzLmhhbmRsZXMgPSBcIm4sZSxzLHcsc2Usc3csbmUsbndcIjtcblx0XHRcdH1cblxuXHRcdFx0biA9IHRoaXMuaGFuZGxlcy5zcGxpdCggXCIsXCIgKTtcblx0XHRcdHRoaXMuaGFuZGxlcyA9IHt9O1xuXG5cdFx0XHRmb3IgKCBpID0gMDsgaSA8IG4ubGVuZ3RoOyBpKysgKSB7XG5cblx0XHRcdFx0aGFuZGxlID0gJC50cmltKCBuWyBpIF0gKTtcblx0XHRcdFx0aG5hbWUgPSBcInVpLXJlc2l6YWJsZS1cIiArIGhhbmRsZTtcblx0XHRcdFx0YXhpcyA9ICQoIFwiPGRpdj5cIiApO1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggYXhpcywgXCJ1aS1yZXNpemFibGUtaGFuZGxlIFwiICsgaG5hbWUgKTtcblxuXHRcdFx0XHRheGlzLmNzcyggeyB6SW5kZXg6IG8uekluZGV4IH0gKTtcblxuXHRcdFx0XHR0aGlzLmhhbmRsZXNbIGhhbmRsZSBdID0gXCIudWktcmVzaXphYmxlLVwiICsgaGFuZGxlO1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQuYXBwZW5kKCBheGlzICk7XG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHR0aGlzLl9yZW5kZXJBeGlzID0gZnVuY3Rpb24oIHRhcmdldCApIHtcblxuXHRcdFx0dmFyIGksIGF4aXMsIHBhZFBvcywgcGFkV3JhcHBlcjtcblxuXHRcdFx0dGFyZ2V0ID0gdGFyZ2V0IHx8IHRoaXMuZWxlbWVudDtcblxuXHRcdFx0Zm9yICggaSBpbiB0aGlzLmhhbmRsZXMgKSB7XG5cblx0XHRcdFx0aWYgKCB0aGlzLmhhbmRsZXNbIGkgXS5jb25zdHJ1Y3RvciA9PT0gU3RyaW5nICkge1xuXHRcdFx0XHRcdHRoaXMuaGFuZGxlc1sgaSBdID0gdGhpcy5lbGVtZW50LmNoaWxkcmVuKCB0aGlzLmhhbmRsZXNbIGkgXSApLmZpcnN0KCkuc2hvdygpO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCB0aGlzLmhhbmRsZXNbIGkgXS5qcXVlcnkgfHwgdGhpcy5oYW5kbGVzWyBpIF0ubm9kZVR5cGUgKSB7XG5cdFx0XHRcdFx0dGhpcy5oYW5kbGVzWyBpIF0gPSAkKCB0aGlzLmhhbmRsZXNbIGkgXSApO1xuXHRcdFx0XHRcdHRoaXMuX29uKCB0aGlzLmhhbmRsZXNbIGkgXSwgeyBcIm1vdXNlZG93blwiOiB0aGF0Ll9tb3VzZURvd24gfSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCB0aGlzLmVsZW1lbnRJc1dyYXBwZXIgJiZcblx0XHRcdFx0XHRcdHRoaXMub3JpZ2luYWxFbGVtZW50WyAwIF1cblx0XHRcdFx0XHRcdFx0Lm5vZGVOYW1lXG5cdFx0XHRcdFx0XHRcdC5tYXRjaCggL14odGV4dGFyZWF8aW5wdXR8c2VsZWN0fGJ1dHRvbikkL2kgKSApIHtcblx0XHRcdFx0XHRheGlzID0gJCggdGhpcy5oYW5kbGVzWyBpIF0sIHRoaXMuZWxlbWVudCApO1xuXG5cdFx0XHRcdFx0cGFkV3JhcHBlciA9IC9zd3xuZXxud3xzZXxufHMvLnRlc3QoIGkgKSA/XG5cdFx0XHRcdFx0XHRheGlzLm91dGVySGVpZ2h0KCkgOlxuXHRcdFx0XHRcdFx0YXhpcy5vdXRlcldpZHRoKCk7XG5cblx0XHRcdFx0XHRwYWRQb3MgPSBbIFwicGFkZGluZ1wiLFxuXHRcdFx0XHRcdFx0L25lfG53fG4vLnRlc3QoIGkgKSA/IFwiVG9wXCIgOlxuXHRcdFx0XHRcdFx0L3NlfHN3fHMvLnRlc3QoIGkgKSA/IFwiQm90dG9tXCIgOlxuXHRcdFx0XHRcdFx0L15lJC8udGVzdCggaSApID8gXCJSaWdodFwiIDogXCJMZWZ0XCIgXS5qb2luKCBcIlwiICk7XG5cblx0XHRcdFx0XHR0YXJnZXQuY3NzKCBwYWRQb3MsIHBhZFdyYXBwZXIgKTtcblxuXHRcdFx0XHRcdHRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplKCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHR0aGlzLl9oYW5kbGVzID0gdGhpcy5faGFuZGxlcy5hZGQoIHRoaXMuaGFuZGxlc1sgaSBdICk7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdC8vIFRPRE86IG1ha2UgcmVuZGVyQXhpcyBhIHByb3RvdHlwZSBmdW5jdGlvblxuXHRcdHRoaXMuX3JlbmRlckF4aXMoIHRoaXMuZWxlbWVudCApO1xuXG5cdFx0dGhpcy5faGFuZGxlcyA9IHRoaXMuX2hhbmRsZXMuYWRkKCB0aGlzLmVsZW1lbnQuZmluZCggXCIudWktcmVzaXphYmxlLWhhbmRsZVwiICkgKTtcblx0XHR0aGlzLl9oYW5kbGVzLmRpc2FibGVTZWxlY3Rpb24oKTtcblxuXHRcdHRoaXMuX2hhbmRsZXMub24oIFwibW91c2VvdmVyXCIsIGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCAhdGhhdC5yZXNpemluZyApIHtcblx0XHRcdFx0aWYgKCB0aGlzLmNsYXNzTmFtZSApIHtcblx0XHRcdFx0XHRheGlzID0gdGhpcy5jbGFzc05hbWUubWF0Y2goIC91aS1yZXNpemFibGUtKHNlfHN3fG5lfG53fG58ZXxzfHcpL2kgKTtcblx0XHRcdFx0fVxuXHRcdFx0XHR0aGF0LmF4aXMgPSBheGlzICYmIGF4aXNbIDEgXSA/IGF4aXNbIDEgXSA6IFwic2VcIjtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHRpZiAoIG8uYXV0b0hpZGUgKSB7XG5cdFx0XHR0aGlzLl9oYW5kbGVzLmhpZGUoKTtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLXJlc2l6YWJsZS1hdXRvaGlkZVwiICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZW1vdmVIYW5kbGVzOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9oYW5kbGVzLnJlbW92ZSgpO1xuXHR9LFxuXG5cdF9tb3VzZUNhcHR1cmU6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgaSwgaGFuZGxlLFxuXHRcdFx0Y2FwdHVyZSA9IGZhbHNlO1xuXG5cdFx0Zm9yICggaSBpbiB0aGlzLmhhbmRsZXMgKSB7XG5cdFx0XHRoYW5kbGUgPSAkKCB0aGlzLmhhbmRsZXNbIGkgXSApWyAwIF07XG5cdFx0XHRpZiAoIGhhbmRsZSA9PT0gZXZlbnQudGFyZ2V0IHx8ICQuY29udGFpbnMoIGhhbmRsZSwgZXZlbnQudGFyZ2V0ICkgKSB7XG5cdFx0XHRcdGNhcHR1cmUgPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHJldHVybiAhdGhpcy5vcHRpb25zLmRpc2FibGVkICYmIGNhcHR1cmU7XG5cdH0sXG5cblx0X21vdXNlU3RhcnQ6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHZhciBjdXJsZWZ0LCBjdXJ0b3AsIGN1cnNvcixcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRlbCA9IHRoaXMuZWxlbWVudDtcblxuXHRcdHRoaXMucmVzaXppbmcgPSB0cnVlO1xuXG5cdFx0dGhpcy5fcmVuZGVyUHJveHkoKTtcblxuXHRcdGN1cmxlZnQgPSB0aGlzLl9udW0oIHRoaXMuaGVscGVyLmNzcyggXCJsZWZ0XCIgKSApO1xuXHRcdGN1cnRvcCA9IHRoaXMuX251bSggdGhpcy5oZWxwZXIuY3NzKCBcInRvcFwiICkgKTtcblxuXHRcdGlmICggby5jb250YWlubWVudCApIHtcblx0XHRcdGN1cmxlZnQgKz0gJCggby5jb250YWlubWVudCApLnNjcm9sbExlZnQoKSB8fCAwO1xuXHRcdFx0Y3VydG9wICs9ICQoIG8uY29udGFpbm1lbnQgKS5zY3JvbGxUb3AoKSB8fCAwO1xuXHRcdH1cblxuXHRcdHRoaXMub2Zmc2V0ID0gdGhpcy5oZWxwZXIub2Zmc2V0KCk7XG5cdFx0dGhpcy5wb3NpdGlvbiA9IHsgbGVmdDogY3VybGVmdCwgdG9wOiBjdXJ0b3AgfTtcblxuXHRcdHRoaXMuc2l6ZSA9IHRoaXMuX2hlbHBlciA/IHtcblx0XHRcdFx0d2lkdGg6IHRoaXMuaGVscGVyLndpZHRoKCksXG5cdFx0XHRcdGhlaWdodDogdGhpcy5oZWxwZXIuaGVpZ2h0KClcblx0XHRcdH0gOiB7XG5cdFx0XHRcdHdpZHRoOiBlbC53aWR0aCgpLFxuXHRcdFx0XHRoZWlnaHQ6IGVsLmhlaWdodCgpXG5cdFx0XHR9O1xuXG5cdFx0dGhpcy5vcmlnaW5hbFNpemUgPSB0aGlzLl9oZWxwZXIgPyB7XG5cdFx0XHRcdHdpZHRoOiBlbC5vdXRlcldpZHRoKCksXG5cdFx0XHRcdGhlaWdodDogZWwub3V0ZXJIZWlnaHQoKVxuXHRcdFx0fSA6IHtcblx0XHRcdFx0d2lkdGg6IGVsLndpZHRoKCksXG5cdFx0XHRcdGhlaWdodDogZWwuaGVpZ2h0KClcblx0XHRcdH07XG5cblx0XHR0aGlzLnNpemVEaWZmID0ge1xuXHRcdFx0d2lkdGg6IGVsLm91dGVyV2lkdGgoKSAtIGVsLndpZHRoKCksXG5cdFx0XHRoZWlnaHQ6IGVsLm91dGVySGVpZ2h0KCkgLSBlbC5oZWlnaHQoKVxuXHRcdH07XG5cblx0XHR0aGlzLm9yaWdpbmFsUG9zaXRpb24gPSB7IGxlZnQ6IGN1cmxlZnQsIHRvcDogY3VydG9wIH07XG5cdFx0dGhpcy5vcmlnaW5hbE1vdXNlUG9zaXRpb24gPSB7IGxlZnQ6IGV2ZW50LnBhZ2VYLCB0b3A6IGV2ZW50LnBhZ2VZIH07XG5cblx0XHR0aGlzLmFzcGVjdFJhdGlvID0gKCB0eXBlb2Ygby5hc3BlY3RSYXRpbyA9PT0gXCJudW1iZXJcIiApID9cblx0XHRcdG8uYXNwZWN0UmF0aW8gOlxuXHRcdFx0KCAoIHRoaXMub3JpZ2luYWxTaXplLndpZHRoIC8gdGhpcy5vcmlnaW5hbFNpemUuaGVpZ2h0ICkgfHwgMSApO1xuXG5cdFx0Y3Vyc29yID0gJCggXCIudWktcmVzaXphYmxlLVwiICsgdGhpcy5heGlzICkuY3NzKCBcImN1cnNvclwiICk7XG5cdFx0JCggXCJib2R5XCIgKS5jc3MoIFwiY3Vyc29yXCIsIGN1cnNvciA9PT0gXCJhdXRvXCIgPyB0aGlzLmF4aXMgKyBcIi1yZXNpemVcIiA6IGN1cnNvciApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktcmVzaXphYmxlLXJlc2l6aW5nXCIgKTtcblx0XHR0aGlzLl9wcm9wYWdhdGUoIFwic3RhcnRcIiwgZXZlbnQgKTtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHRfbW91c2VEcmFnOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR2YXIgZGF0YSwgcHJvcHMsXG5cdFx0XHRzbXAgPSB0aGlzLm9yaWdpbmFsTW91c2VQb3NpdGlvbixcblx0XHRcdGEgPSB0aGlzLmF4aXMsXG5cdFx0XHRkeCA9ICggZXZlbnQucGFnZVggLSBzbXAubGVmdCApIHx8IDAsXG5cdFx0XHRkeSA9ICggZXZlbnQucGFnZVkgLSBzbXAudG9wICkgfHwgMCxcblx0XHRcdHRyaWdnZXIgPSB0aGlzLl9jaGFuZ2VbIGEgXTtcblxuXHRcdHRoaXMuX3VwZGF0ZVByZXZQcm9wZXJ0aWVzKCk7XG5cblx0XHRpZiAoICF0cmlnZ2VyICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdGRhdGEgPSB0cmlnZ2VyLmFwcGx5KCB0aGlzLCBbIGV2ZW50LCBkeCwgZHkgXSApO1xuXG5cdFx0dGhpcy5fdXBkYXRlVmlydHVhbEJvdW5kYXJpZXMoIGV2ZW50LnNoaWZ0S2V5ICk7XG5cdFx0aWYgKCB0aGlzLl9hc3BlY3RSYXRpbyB8fCBldmVudC5zaGlmdEtleSApIHtcblx0XHRcdGRhdGEgPSB0aGlzLl91cGRhdGVSYXRpbyggZGF0YSwgZXZlbnQgKTtcblx0XHR9XG5cblx0XHRkYXRhID0gdGhpcy5fcmVzcGVjdFNpemUoIGRhdGEsIGV2ZW50ICk7XG5cblx0XHR0aGlzLl91cGRhdGVDYWNoZSggZGF0YSApO1xuXG5cdFx0dGhpcy5fcHJvcGFnYXRlKCBcInJlc2l6ZVwiLCBldmVudCApO1xuXG5cdFx0cHJvcHMgPSB0aGlzLl9hcHBseUNoYW5nZXMoKTtcblxuXHRcdGlmICggIXRoaXMuX2hlbHBlciAmJiB0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZUVsZW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdHRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhJC5pc0VtcHR5T2JqZWN0KCBwcm9wcyApICkge1xuXHRcdFx0dGhpcy5fdXBkYXRlUHJldlByb3BlcnRpZXMoKTtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwicmVzaXplXCIsIGV2ZW50LCB0aGlzLnVpKCkgKTtcblx0XHRcdHRoaXMuX2FwcGx5Q2hhbmdlcygpO1xuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblxuXHRfbW91c2VTdG9wOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR0aGlzLnJlc2l6aW5nID0gZmFsc2U7XG5cdFx0dmFyIHByLCBpc3RhLCBzb2Zmc2V0aCwgc29mZnNldHcsIHMsIGxlZnQsIHRvcCxcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnMsIHRoYXQgPSB0aGlzO1xuXG5cdFx0aWYgKCB0aGlzLl9oZWxwZXIgKSB7XG5cblx0XHRcdHByID0gdGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemVFbGVtZW50cztcblx0XHRcdGlzdGEgPSBwci5sZW5ndGggJiYgKCAvdGV4dGFyZWEvaSApLnRlc3QoIHByWyAwIF0ubm9kZU5hbWUgKTtcblx0XHRcdHNvZmZzZXRoID0gaXN0YSAmJiB0aGlzLl9oYXNTY3JvbGwoIHByWyAwIF0sIFwibGVmdFwiICkgPyAwIDogdGhhdC5zaXplRGlmZi5oZWlnaHQ7XG5cdFx0XHRzb2Zmc2V0dyA9IGlzdGEgPyAwIDogdGhhdC5zaXplRGlmZi53aWR0aDtcblxuXHRcdFx0cyA9IHtcblx0XHRcdFx0d2lkdGg6ICggdGhhdC5oZWxwZXIud2lkdGgoKSAgLSBzb2Zmc2V0dyApLFxuXHRcdFx0XHRoZWlnaHQ6ICggdGhhdC5oZWxwZXIuaGVpZ2h0KCkgLSBzb2Zmc2V0aCApXG5cdFx0XHR9O1xuXHRcdFx0bGVmdCA9ICggcGFyc2VGbG9hdCggdGhhdC5lbGVtZW50LmNzcyggXCJsZWZ0XCIgKSApICtcblx0XHRcdFx0KCB0aGF0LnBvc2l0aW9uLmxlZnQgLSB0aGF0Lm9yaWdpbmFsUG9zaXRpb24ubGVmdCApICkgfHwgbnVsbDtcblx0XHRcdHRvcCA9ICggcGFyc2VGbG9hdCggdGhhdC5lbGVtZW50LmNzcyggXCJ0b3BcIiApICkgK1xuXHRcdFx0XHQoIHRoYXQucG9zaXRpb24udG9wIC0gdGhhdC5vcmlnaW5hbFBvc2l0aW9uLnRvcCApICkgfHwgbnVsbDtcblxuXHRcdFx0aWYgKCAhby5hbmltYXRlICkge1xuXHRcdFx0XHR0aGlzLmVsZW1lbnQuY3NzKCAkLmV4dGVuZCggcywgeyB0b3A6IHRvcCwgbGVmdDogbGVmdCB9ICkgKTtcblx0XHRcdH1cblxuXHRcdFx0dGhhdC5oZWxwZXIuaGVpZ2h0KCB0aGF0LnNpemUuaGVpZ2h0ICk7XG5cdFx0XHR0aGF0LmhlbHBlci53aWR0aCggdGhhdC5zaXplLndpZHRoICk7XG5cblx0XHRcdGlmICggdGhpcy5faGVscGVyICYmICFvLmFuaW1hdGUgKSB7XG5cdFx0XHRcdHRoaXMuX3Byb3BvcnRpb25hbGx5UmVzaXplKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0JCggXCJib2R5XCIgKS5jc3MoIFwiY3Vyc29yXCIsIFwiYXV0b1wiICk7XG5cblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggXCJ1aS1yZXNpemFibGUtcmVzaXppbmdcIiApO1xuXG5cdFx0dGhpcy5fcHJvcGFnYXRlKCBcInN0b3BcIiwgZXZlbnQgKTtcblxuXHRcdGlmICggdGhpcy5faGVscGVyICkge1xuXHRcdFx0dGhpcy5oZWxwZXIucmVtb3ZlKCk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXG5cdH0sXG5cblx0X3VwZGF0ZVByZXZQcm9wZXJ0aWVzOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLnByZXZQb3NpdGlvbiA9IHtcblx0XHRcdHRvcDogdGhpcy5wb3NpdGlvbi50b3AsXG5cdFx0XHRsZWZ0OiB0aGlzLnBvc2l0aW9uLmxlZnRcblx0XHR9O1xuXHRcdHRoaXMucHJldlNpemUgPSB7XG5cdFx0XHR3aWR0aDogdGhpcy5zaXplLndpZHRoLFxuXHRcdFx0aGVpZ2h0OiB0aGlzLnNpemUuaGVpZ2h0XG5cdFx0fTtcblx0fSxcblxuXHRfYXBwbHlDaGFuZ2VzOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgcHJvcHMgPSB7fTtcblxuXHRcdGlmICggdGhpcy5wb3NpdGlvbi50b3AgIT09IHRoaXMucHJldlBvc2l0aW9uLnRvcCApIHtcblx0XHRcdHByb3BzLnRvcCA9IHRoaXMucG9zaXRpb24udG9wICsgXCJweFwiO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMucG9zaXRpb24ubGVmdCAhPT0gdGhpcy5wcmV2UG9zaXRpb24ubGVmdCApIHtcblx0XHRcdHByb3BzLmxlZnQgPSB0aGlzLnBvc2l0aW9uLmxlZnQgKyBcInB4XCI7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5zaXplLndpZHRoICE9PSB0aGlzLnByZXZTaXplLndpZHRoICkge1xuXHRcdFx0cHJvcHMud2lkdGggPSB0aGlzLnNpemUud2lkdGggKyBcInB4XCI7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5zaXplLmhlaWdodCAhPT0gdGhpcy5wcmV2U2l6ZS5oZWlnaHQgKSB7XG5cdFx0XHRwcm9wcy5oZWlnaHQgPSB0aGlzLnNpemUuaGVpZ2h0ICsgXCJweFwiO1xuXHRcdH1cblxuXHRcdHRoaXMuaGVscGVyLmNzcyggcHJvcHMgKTtcblxuXHRcdHJldHVybiBwcm9wcztcblx0fSxcblxuXHRfdXBkYXRlVmlydHVhbEJvdW5kYXJpZXM6IGZ1bmN0aW9uKCBmb3JjZUFzcGVjdFJhdGlvICkge1xuXHRcdHZhciBwTWluV2lkdGgsIHBNYXhXaWR0aCwgcE1pbkhlaWdodCwgcE1heEhlaWdodCwgYixcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnM7XG5cblx0XHRiID0ge1xuXHRcdFx0bWluV2lkdGg6IHRoaXMuX2lzTnVtYmVyKCBvLm1pbldpZHRoICkgPyBvLm1pbldpZHRoIDogMCxcblx0XHRcdG1heFdpZHRoOiB0aGlzLl9pc051bWJlciggby5tYXhXaWR0aCApID8gby5tYXhXaWR0aCA6IEluZmluaXR5LFxuXHRcdFx0bWluSGVpZ2h0OiB0aGlzLl9pc051bWJlciggby5taW5IZWlnaHQgKSA/IG8ubWluSGVpZ2h0IDogMCxcblx0XHRcdG1heEhlaWdodDogdGhpcy5faXNOdW1iZXIoIG8ubWF4SGVpZ2h0ICkgPyBvLm1heEhlaWdodCA6IEluZmluaXR5XG5cdFx0fTtcblxuXHRcdGlmICggdGhpcy5fYXNwZWN0UmF0aW8gfHwgZm9yY2VBc3BlY3RSYXRpbyApIHtcblx0XHRcdHBNaW5XaWR0aCA9IGIubWluSGVpZ2h0ICogdGhpcy5hc3BlY3RSYXRpbztcblx0XHRcdHBNaW5IZWlnaHQgPSBiLm1pbldpZHRoIC8gdGhpcy5hc3BlY3RSYXRpbztcblx0XHRcdHBNYXhXaWR0aCA9IGIubWF4SGVpZ2h0ICogdGhpcy5hc3BlY3RSYXRpbztcblx0XHRcdHBNYXhIZWlnaHQgPSBiLm1heFdpZHRoIC8gdGhpcy5hc3BlY3RSYXRpbztcblxuXHRcdFx0aWYgKCBwTWluV2lkdGggPiBiLm1pbldpZHRoICkge1xuXHRcdFx0XHRiLm1pbldpZHRoID0gcE1pbldpZHRoO1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBwTWluSGVpZ2h0ID4gYi5taW5IZWlnaHQgKSB7XG5cdFx0XHRcdGIubWluSGVpZ2h0ID0gcE1pbkhlaWdodDtcblx0XHRcdH1cblx0XHRcdGlmICggcE1heFdpZHRoIDwgYi5tYXhXaWR0aCApIHtcblx0XHRcdFx0Yi5tYXhXaWR0aCA9IHBNYXhXaWR0aDtcblx0XHRcdH1cblx0XHRcdGlmICggcE1heEhlaWdodCA8IGIubWF4SGVpZ2h0ICkge1xuXHRcdFx0XHRiLm1heEhlaWdodCA9IHBNYXhIZWlnaHQ7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHRoaXMuX3ZCb3VuZGFyaWVzID0gYjtcblx0fSxcblxuXHRfdXBkYXRlQ2FjaGU6IGZ1bmN0aW9uKCBkYXRhICkge1xuXHRcdHRoaXMub2Zmc2V0ID0gdGhpcy5oZWxwZXIub2Zmc2V0KCk7XG5cdFx0aWYgKCB0aGlzLl9pc051bWJlciggZGF0YS5sZWZ0ICkgKSB7XG5cdFx0XHR0aGlzLnBvc2l0aW9uLmxlZnQgPSBkYXRhLmxlZnQ7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5faXNOdW1iZXIoIGRhdGEudG9wICkgKSB7XG5cdFx0XHR0aGlzLnBvc2l0aW9uLnRvcCA9IGRhdGEudG9wO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuX2lzTnVtYmVyKCBkYXRhLmhlaWdodCApICkge1xuXHRcdFx0dGhpcy5zaXplLmhlaWdodCA9IGRhdGEuaGVpZ2h0O1xuXHRcdH1cblx0XHRpZiAoIHRoaXMuX2lzTnVtYmVyKCBkYXRhLndpZHRoICkgKSB7XG5cdFx0XHR0aGlzLnNpemUud2lkdGggPSBkYXRhLndpZHRoO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlUmF0aW86IGZ1bmN0aW9uKCBkYXRhICkge1xuXG5cdFx0dmFyIGNwb3MgPSB0aGlzLnBvc2l0aW9uLFxuXHRcdFx0Y3NpemUgPSB0aGlzLnNpemUsXG5cdFx0XHRhID0gdGhpcy5heGlzO1xuXG5cdFx0aWYgKCB0aGlzLl9pc051bWJlciggZGF0YS5oZWlnaHQgKSApIHtcblx0XHRcdGRhdGEud2lkdGggPSAoIGRhdGEuaGVpZ2h0ICogdGhpcy5hc3BlY3RSYXRpbyApO1xuXHRcdH0gZWxzZSBpZiAoIHRoaXMuX2lzTnVtYmVyKCBkYXRhLndpZHRoICkgKSB7XG5cdFx0XHRkYXRhLmhlaWdodCA9ICggZGF0YS53aWR0aCAvIHRoaXMuYXNwZWN0UmF0aW8gKTtcblx0XHR9XG5cblx0XHRpZiAoIGEgPT09IFwic3dcIiApIHtcblx0XHRcdGRhdGEubGVmdCA9IGNwb3MubGVmdCArICggY3NpemUud2lkdGggLSBkYXRhLndpZHRoICk7XG5cdFx0XHRkYXRhLnRvcCA9IG51bGw7XG5cdFx0fVxuXHRcdGlmICggYSA9PT0gXCJud1wiICkge1xuXHRcdFx0ZGF0YS50b3AgPSBjcG9zLnRvcCArICggY3NpemUuaGVpZ2h0IC0gZGF0YS5oZWlnaHQgKTtcblx0XHRcdGRhdGEubGVmdCA9IGNwb3MubGVmdCArICggY3NpemUud2lkdGggLSBkYXRhLndpZHRoICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGE7XG5cdH0sXG5cblx0X3Jlc3BlY3RTaXplOiBmdW5jdGlvbiggZGF0YSApIHtcblxuXHRcdHZhciBvID0gdGhpcy5fdkJvdW5kYXJpZXMsXG5cdFx0XHRhID0gdGhpcy5heGlzLFxuXHRcdFx0aXNtYXh3ID0gdGhpcy5faXNOdW1iZXIoIGRhdGEud2lkdGggKSAmJiBvLm1heFdpZHRoICYmICggby5tYXhXaWR0aCA8IGRhdGEud2lkdGggKSxcblx0XHRcdGlzbWF4aCA9IHRoaXMuX2lzTnVtYmVyKCBkYXRhLmhlaWdodCApICYmIG8ubWF4SGVpZ2h0ICYmICggby5tYXhIZWlnaHQgPCBkYXRhLmhlaWdodCApLFxuXHRcdFx0aXNtaW53ID0gdGhpcy5faXNOdW1iZXIoIGRhdGEud2lkdGggKSAmJiBvLm1pbldpZHRoICYmICggby5taW5XaWR0aCA+IGRhdGEud2lkdGggKSxcblx0XHRcdGlzbWluaCA9IHRoaXMuX2lzTnVtYmVyKCBkYXRhLmhlaWdodCApICYmIG8ubWluSGVpZ2h0ICYmICggby5taW5IZWlnaHQgPiBkYXRhLmhlaWdodCApLFxuXHRcdFx0ZHcgPSB0aGlzLm9yaWdpbmFsUG9zaXRpb24ubGVmdCArIHRoaXMub3JpZ2luYWxTaXplLndpZHRoLFxuXHRcdFx0ZGggPSB0aGlzLm9yaWdpbmFsUG9zaXRpb24udG9wICsgdGhpcy5vcmlnaW5hbFNpemUuaGVpZ2h0LFxuXHRcdFx0Y3cgPSAvc3d8bnd8dy8udGVzdCggYSApLCBjaCA9IC9ud3xuZXxuLy50ZXN0KCBhICk7XG5cdFx0aWYgKCBpc21pbncgKSB7XG5cdFx0XHRkYXRhLndpZHRoID0gby5taW5XaWR0aDtcblx0XHR9XG5cdFx0aWYgKCBpc21pbmggKSB7XG5cdFx0XHRkYXRhLmhlaWdodCA9IG8ubWluSGVpZ2h0O1xuXHRcdH1cblx0XHRpZiAoIGlzbWF4dyApIHtcblx0XHRcdGRhdGEud2lkdGggPSBvLm1heFdpZHRoO1xuXHRcdH1cblx0XHRpZiAoIGlzbWF4aCApIHtcblx0XHRcdGRhdGEuaGVpZ2h0ID0gby5tYXhIZWlnaHQ7XG5cdFx0fVxuXG5cdFx0aWYgKCBpc21pbncgJiYgY3cgKSB7XG5cdFx0XHRkYXRhLmxlZnQgPSBkdyAtIG8ubWluV2lkdGg7XG5cdFx0fVxuXHRcdGlmICggaXNtYXh3ICYmIGN3ICkge1xuXHRcdFx0ZGF0YS5sZWZ0ID0gZHcgLSBvLm1heFdpZHRoO1xuXHRcdH1cblx0XHRpZiAoIGlzbWluaCAmJiBjaCApIHtcblx0XHRcdGRhdGEudG9wID0gZGggLSBvLm1pbkhlaWdodDtcblx0XHR9XG5cdFx0aWYgKCBpc21heGggJiYgY2ggKSB7XG5cdFx0XHRkYXRhLnRvcCA9IGRoIC0gby5tYXhIZWlnaHQ7XG5cdFx0fVxuXG5cdFx0Ly8gRml4aW5nIGp1bXAgZXJyb3Igb24gdG9wL2xlZnQgLSBidWcgIzIzMzBcblx0XHRpZiAoICFkYXRhLndpZHRoICYmICFkYXRhLmhlaWdodCAmJiAhZGF0YS5sZWZ0ICYmIGRhdGEudG9wICkge1xuXHRcdFx0ZGF0YS50b3AgPSBudWxsO1xuXHRcdH0gZWxzZSBpZiAoICFkYXRhLndpZHRoICYmICFkYXRhLmhlaWdodCAmJiAhZGF0YS50b3AgJiYgZGF0YS5sZWZ0ICkge1xuXHRcdFx0ZGF0YS5sZWZ0ID0gbnVsbDtcblx0XHR9XG5cblx0XHRyZXR1cm4gZGF0YTtcblx0fSxcblxuXHRfZ2V0UGFkZGluZ1BsdXNCb3JkZXJEaW1lbnNpb25zOiBmdW5jdGlvbiggZWxlbWVudCApIHtcblx0XHR2YXIgaSA9IDAsXG5cdFx0XHR3aWR0aHMgPSBbXSxcblx0XHRcdGJvcmRlcnMgPSBbXG5cdFx0XHRcdGVsZW1lbnQuY3NzKCBcImJvcmRlclRvcFdpZHRoXCIgKSxcblx0XHRcdFx0ZWxlbWVudC5jc3MoIFwiYm9yZGVyUmlnaHRXaWR0aFwiICksXG5cdFx0XHRcdGVsZW1lbnQuY3NzKCBcImJvcmRlckJvdHRvbVdpZHRoXCIgKSxcblx0XHRcdFx0ZWxlbWVudC5jc3MoIFwiYm9yZGVyTGVmdFdpZHRoXCIgKVxuXHRcdFx0XSxcblx0XHRcdHBhZGRpbmdzID0gW1xuXHRcdFx0XHRlbGVtZW50LmNzcyggXCJwYWRkaW5nVG9wXCIgKSxcblx0XHRcdFx0ZWxlbWVudC5jc3MoIFwicGFkZGluZ1JpZ2h0XCIgKSxcblx0XHRcdFx0ZWxlbWVudC5jc3MoIFwicGFkZGluZ0JvdHRvbVwiICksXG5cdFx0XHRcdGVsZW1lbnQuY3NzKCBcInBhZGRpbmdMZWZ0XCIgKVxuXHRcdFx0XTtcblxuXHRcdGZvciAoIDsgaSA8IDQ7IGkrKyApIHtcblx0XHRcdHdpZHRoc1sgaSBdID0gKCBwYXJzZUZsb2F0KCBib3JkZXJzWyBpIF0gKSB8fCAwICk7XG5cdFx0XHR3aWR0aHNbIGkgXSArPSAoIHBhcnNlRmxvYXQoIHBhZGRpbmdzWyBpIF0gKSB8fCAwICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHtcblx0XHRcdGhlaWdodDogd2lkdGhzWyAwIF0gKyB3aWR0aHNbIDIgXSxcblx0XHRcdHdpZHRoOiB3aWR0aHNbIDEgXSArIHdpZHRoc1sgMyBdXG5cdFx0fTtcblx0fSxcblxuXHRfcHJvcG9ydGlvbmFsbHlSZXNpemU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0aWYgKCAhdGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemVFbGVtZW50cy5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dmFyIHByZWwsXG5cdFx0XHRpID0gMCxcblx0XHRcdGVsZW1lbnQgPSB0aGlzLmhlbHBlciB8fCB0aGlzLmVsZW1lbnQ7XG5cblx0XHRmb3IgKCA7IGkgPCB0aGlzLl9wcm9wb3J0aW9uYWxseVJlc2l6ZUVsZW1lbnRzLmxlbmd0aDsgaSsrICkge1xuXG5cdFx0XHRwcmVsID0gdGhpcy5fcHJvcG9ydGlvbmFsbHlSZXNpemVFbGVtZW50c1sgaSBdO1xuXG5cdFx0XHQvLyBUT0RPOiBTZWVtcyBsaWtlIGEgYnVnIHRvIGNhY2hlIHRoaXMub3V0ZXJEaW1lbnNpb25zXG5cdFx0XHQvLyBjb25zaWRlcmluZyB0aGF0IHdlIGFyZSBpbiBhIGxvb3AuXG5cdFx0XHRpZiAoICF0aGlzLm91dGVyRGltZW5zaW9ucyApIHtcblx0XHRcdFx0dGhpcy5vdXRlckRpbWVuc2lvbnMgPSB0aGlzLl9nZXRQYWRkaW5nUGx1c0JvcmRlckRpbWVuc2lvbnMoIHByZWwgKTtcblx0XHRcdH1cblxuXHRcdFx0cHJlbC5jc3MoIHtcblx0XHRcdFx0aGVpZ2h0OiAoIGVsZW1lbnQuaGVpZ2h0KCkgLSB0aGlzLm91dGVyRGltZW5zaW9ucy5oZWlnaHQgKSB8fCAwLFxuXHRcdFx0XHR3aWR0aDogKCBlbGVtZW50LndpZHRoKCkgLSB0aGlzLm91dGVyRGltZW5zaW9ucy53aWR0aCApIHx8IDBcblx0XHRcdH0gKTtcblxuXHRcdH1cblxuXHR9LFxuXG5cdF9yZW5kZXJQcm94eTogZnVuY3Rpb24oKSB7XG5cblx0XHR2YXIgZWwgPSB0aGlzLmVsZW1lbnQsIG8gPSB0aGlzLm9wdGlvbnM7XG5cdFx0dGhpcy5lbGVtZW50T2Zmc2V0ID0gZWwub2Zmc2V0KCk7XG5cblx0XHRpZiAoIHRoaXMuX2hlbHBlciApIHtcblxuXHRcdFx0dGhpcy5oZWxwZXIgPSB0aGlzLmhlbHBlciB8fCAkKCBcIjxkaXYgc3R5bGU9J292ZXJmbG93OmhpZGRlbjsnPjwvZGl2PlwiICk7XG5cblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmhlbHBlciwgdGhpcy5faGVscGVyICk7XG5cdFx0XHR0aGlzLmhlbHBlci5jc3MoIHtcblx0XHRcdFx0d2lkdGg6IHRoaXMuZWxlbWVudC5vdXRlcldpZHRoKCksXG5cdFx0XHRcdGhlaWdodDogdGhpcy5lbGVtZW50Lm91dGVySGVpZ2h0KCksXG5cdFx0XHRcdHBvc2l0aW9uOiBcImFic29sdXRlXCIsXG5cdFx0XHRcdGxlZnQ6IHRoaXMuZWxlbWVudE9mZnNldC5sZWZ0ICsgXCJweFwiLFxuXHRcdFx0XHR0b3A6IHRoaXMuZWxlbWVudE9mZnNldC50b3AgKyBcInB4XCIsXG5cdFx0XHRcdHpJbmRleDogKytvLnpJbmRleCAvL1RPRE86IERvbid0IG1vZGlmeSBvcHRpb25cblx0XHRcdH0gKTtcblxuXHRcdFx0dGhpcy5oZWxwZXJcblx0XHRcdFx0LmFwcGVuZFRvKCBcImJvZHlcIiApXG5cdFx0XHRcdC5kaXNhYmxlU2VsZWN0aW9uKCk7XG5cblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5oZWxwZXIgPSB0aGlzLmVsZW1lbnQ7XG5cdFx0fVxuXG5cdH0sXG5cblx0X2NoYW5nZToge1xuXHRcdGU6IGZ1bmN0aW9uKCBldmVudCwgZHggKSB7XG5cdFx0XHRyZXR1cm4geyB3aWR0aDogdGhpcy5vcmlnaW5hbFNpemUud2lkdGggKyBkeCB9O1xuXHRcdH0sXG5cdFx0dzogZnVuY3Rpb24oIGV2ZW50LCBkeCApIHtcblx0XHRcdHZhciBjcyA9IHRoaXMub3JpZ2luYWxTaXplLCBzcCA9IHRoaXMub3JpZ2luYWxQb3NpdGlvbjtcblx0XHRcdHJldHVybiB7IGxlZnQ6IHNwLmxlZnQgKyBkeCwgd2lkdGg6IGNzLndpZHRoIC0gZHggfTtcblx0XHR9LFxuXHRcdG46IGZ1bmN0aW9uKCBldmVudCwgZHgsIGR5ICkge1xuXHRcdFx0dmFyIGNzID0gdGhpcy5vcmlnaW5hbFNpemUsIHNwID0gdGhpcy5vcmlnaW5hbFBvc2l0aW9uO1xuXHRcdFx0cmV0dXJuIHsgdG9wOiBzcC50b3AgKyBkeSwgaGVpZ2h0OiBjcy5oZWlnaHQgLSBkeSB9O1xuXHRcdH0sXG5cdFx0czogZnVuY3Rpb24oIGV2ZW50LCBkeCwgZHkgKSB7XG5cdFx0XHRyZXR1cm4geyBoZWlnaHQ6IHRoaXMub3JpZ2luYWxTaXplLmhlaWdodCArIGR5IH07XG5cdFx0fSxcblx0XHRzZTogZnVuY3Rpb24oIGV2ZW50LCBkeCwgZHkgKSB7XG5cdFx0XHRyZXR1cm4gJC5leHRlbmQoIHRoaXMuX2NoYW5nZS5zLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSxcblx0XHRcdFx0dGhpcy5fY2hhbmdlLmUuYXBwbHkoIHRoaXMsIFsgZXZlbnQsIGR4LCBkeSBdICkgKTtcblx0XHR9LFxuXHRcdHN3OiBmdW5jdGlvbiggZXZlbnQsIGR4LCBkeSApIHtcblx0XHRcdHJldHVybiAkLmV4dGVuZCggdGhpcy5fY2hhbmdlLnMuYXBwbHkoIHRoaXMsIGFyZ3VtZW50cyApLFxuXHRcdFx0XHR0aGlzLl9jaGFuZ2Uudy5hcHBseSggdGhpcywgWyBldmVudCwgZHgsIGR5IF0gKSApO1xuXHRcdH0sXG5cdFx0bmU6IGZ1bmN0aW9uKCBldmVudCwgZHgsIGR5ICkge1xuXHRcdFx0cmV0dXJuICQuZXh0ZW5kKCB0aGlzLl9jaGFuZ2Uubi5hcHBseSggdGhpcywgYXJndW1lbnRzICksXG5cdFx0XHRcdHRoaXMuX2NoYW5nZS5lLmFwcGx5KCB0aGlzLCBbIGV2ZW50LCBkeCwgZHkgXSApICk7XG5cdFx0fSxcblx0XHRudzogZnVuY3Rpb24oIGV2ZW50LCBkeCwgZHkgKSB7XG5cdFx0XHRyZXR1cm4gJC5leHRlbmQoIHRoaXMuX2NoYW5nZS5uLmFwcGx5KCB0aGlzLCBhcmd1bWVudHMgKSxcblx0XHRcdFx0dGhpcy5fY2hhbmdlLncuYXBwbHkoIHRoaXMsIFsgZXZlbnQsIGR4LCBkeSBdICkgKTtcblx0XHR9XG5cdH0sXG5cblx0X3Byb3BhZ2F0ZTogZnVuY3Rpb24oIG4sIGV2ZW50ICkge1xuXHRcdCQudWkucGx1Z2luLmNhbGwoIHRoaXMsIG4sIFsgZXZlbnQsIHRoaXMudWkoKSBdICk7XG5cdFx0KCBuICE9PSBcInJlc2l6ZVwiICYmIHRoaXMuX3RyaWdnZXIoIG4sIGV2ZW50LCB0aGlzLnVpKCkgKSApO1xuXHR9LFxuXG5cdHBsdWdpbnM6IHt9LFxuXG5cdHVpOiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0b3JpZ2luYWxFbGVtZW50OiB0aGlzLm9yaWdpbmFsRWxlbWVudCxcblx0XHRcdGVsZW1lbnQ6IHRoaXMuZWxlbWVudCxcblx0XHRcdGhlbHBlcjogdGhpcy5oZWxwZXIsXG5cdFx0XHRwb3NpdGlvbjogdGhpcy5wb3NpdGlvbixcblx0XHRcdHNpemU6IHRoaXMuc2l6ZSxcblx0XHRcdG9yaWdpbmFsU2l6ZTogdGhpcy5vcmlnaW5hbFNpemUsXG5cdFx0XHRvcmlnaW5hbFBvc2l0aW9uOiB0aGlzLm9yaWdpbmFsUG9zaXRpb25cblx0XHR9O1xuXHR9XG5cbn0gKTtcblxuLypcbiAqIFJlc2l6YWJsZSBFeHRlbnNpb25zXG4gKi9cblxuJC51aS5wbHVnaW4uYWRkKCBcInJlc2l6YWJsZVwiLCBcImFuaW1hdGVcIiwge1xuXG5cdHN0b3A6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgdGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApLFxuXHRcdFx0byA9IHRoYXQub3B0aW9ucyxcblx0XHRcdHByID0gdGhhdC5fcHJvcG9ydGlvbmFsbHlSZXNpemVFbGVtZW50cyxcblx0XHRcdGlzdGEgPSBwci5sZW5ndGggJiYgKCAvdGV4dGFyZWEvaSApLnRlc3QoIHByWyAwIF0ubm9kZU5hbWUgKSxcblx0XHRcdHNvZmZzZXRoID0gaXN0YSAmJiB0aGF0Ll9oYXNTY3JvbGwoIHByWyAwIF0sIFwibGVmdFwiICkgPyAwIDogdGhhdC5zaXplRGlmZi5oZWlnaHQsXG5cdFx0XHRzb2Zmc2V0dyA9IGlzdGEgPyAwIDogdGhhdC5zaXplRGlmZi53aWR0aCxcblx0XHRcdHN0eWxlID0ge1xuXHRcdFx0XHR3aWR0aDogKCB0aGF0LnNpemUud2lkdGggLSBzb2Zmc2V0dyApLFxuXHRcdFx0XHRoZWlnaHQ6ICggdGhhdC5zaXplLmhlaWdodCAtIHNvZmZzZXRoIClcblx0XHRcdH0sXG5cdFx0XHRsZWZ0ID0gKCBwYXJzZUZsb2F0KCB0aGF0LmVsZW1lbnQuY3NzKCBcImxlZnRcIiApICkgK1xuXHRcdFx0XHQoIHRoYXQucG9zaXRpb24ubGVmdCAtIHRoYXQub3JpZ2luYWxQb3NpdGlvbi5sZWZ0ICkgKSB8fCBudWxsLFxuXHRcdFx0dG9wID0gKCBwYXJzZUZsb2F0KCB0aGF0LmVsZW1lbnQuY3NzKCBcInRvcFwiICkgKSArXG5cdFx0XHRcdCggdGhhdC5wb3NpdGlvbi50b3AgLSB0aGF0Lm9yaWdpbmFsUG9zaXRpb24udG9wICkgKSB8fCBudWxsO1xuXG5cdFx0dGhhdC5lbGVtZW50LmFuaW1hdGUoXG5cdFx0XHQkLmV4dGVuZCggc3R5bGUsIHRvcCAmJiBsZWZ0ID8geyB0b3A6IHRvcCwgbGVmdDogbGVmdCB9IDoge30gKSwge1xuXHRcdFx0XHRkdXJhdGlvbjogby5hbmltYXRlRHVyYXRpb24sXG5cdFx0XHRcdGVhc2luZzogby5hbmltYXRlRWFzaW5nLFxuXHRcdFx0XHRzdGVwOiBmdW5jdGlvbigpIHtcblxuXHRcdFx0XHRcdHZhciBkYXRhID0ge1xuXHRcdFx0XHRcdFx0d2lkdGg6IHBhcnNlRmxvYXQoIHRoYXQuZWxlbWVudC5jc3MoIFwid2lkdGhcIiApICksXG5cdFx0XHRcdFx0XHRoZWlnaHQ6IHBhcnNlRmxvYXQoIHRoYXQuZWxlbWVudC5jc3MoIFwiaGVpZ2h0XCIgKSApLFxuXHRcdFx0XHRcdFx0dG9wOiBwYXJzZUZsb2F0KCB0aGF0LmVsZW1lbnQuY3NzKCBcInRvcFwiICkgKSxcblx0XHRcdFx0XHRcdGxlZnQ6IHBhcnNlRmxvYXQoIHRoYXQuZWxlbWVudC5jc3MoIFwibGVmdFwiICkgKVxuXHRcdFx0XHRcdH07XG5cblx0XHRcdFx0XHRpZiAoIHByICYmIHByLmxlbmd0aCApIHtcblx0XHRcdFx0XHRcdCQoIHByWyAwIF0gKS5jc3MoIHsgd2lkdGg6IGRhdGEud2lkdGgsIGhlaWdodDogZGF0YS5oZWlnaHQgfSApO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIFByb3BhZ2F0aW5nIHJlc2l6ZSwgYW5kIHVwZGF0aW5nIHZhbHVlcyBmb3IgZWFjaCBhbmltYXRpb24gc3RlcFxuXHRcdFx0XHRcdHRoYXQuX3VwZGF0ZUNhY2hlKCBkYXRhICk7XG5cdFx0XHRcdFx0dGhhdC5fcHJvcGFnYXRlKCBcInJlc2l6ZVwiLCBldmVudCApO1xuXG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHQpO1xuXHR9XG5cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcInJlc2l6YWJsZVwiLCBcImNvbnRhaW5tZW50XCIsIHtcblxuXHRzdGFydDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGVsZW1lbnQsIHAsIGNvLCBjaCwgY3csIHdpZHRoLCBoZWlnaHQsXG5cdFx0XHR0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICksXG5cdFx0XHRvID0gdGhhdC5vcHRpb25zLFxuXHRcdFx0ZWwgPSB0aGF0LmVsZW1lbnQsXG5cdFx0XHRvYyA9IG8uY29udGFpbm1lbnQsXG5cdFx0XHRjZSA9ICggb2MgaW5zdGFuY2VvZiAkICkgP1xuXHRcdFx0XHRvYy5nZXQoIDAgKSA6XG5cdFx0XHRcdCggL3BhcmVudC8udGVzdCggb2MgKSApID8gZWwucGFyZW50KCkuZ2V0KCAwICkgOiBvYztcblxuXHRcdGlmICggIWNlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoYXQuY29udGFpbmVyRWxlbWVudCA9ICQoIGNlICk7XG5cblx0XHRpZiAoIC9kb2N1bWVudC8udGVzdCggb2MgKSB8fCBvYyA9PT0gZG9jdW1lbnQgKSB7XG5cdFx0XHR0aGF0LmNvbnRhaW5lck9mZnNldCA9IHtcblx0XHRcdFx0bGVmdDogMCxcblx0XHRcdFx0dG9wOiAwXG5cdFx0XHR9O1xuXHRcdFx0dGhhdC5jb250YWluZXJQb3NpdGlvbiA9IHtcblx0XHRcdFx0bGVmdDogMCxcblx0XHRcdFx0dG9wOiAwXG5cdFx0XHR9O1xuXG5cdFx0XHR0aGF0LnBhcmVudERhdGEgPSB7XG5cdFx0XHRcdGVsZW1lbnQ6ICQoIGRvY3VtZW50ICksXG5cdFx0XHRcdGxlZnQ6IDAsXG5cdFx0XHRcdHRvcDogMCxcblx0XHRcdFx0d2lkdGg6ICQoIGRvY3VtZW50ICkud2lkdGgoKSxcblx0XHRcdFx0aGVpZ2h0OiAkKCBkb2N1bWVudCApLmhlaWdodCgpIHx8IGRvY3VtZW50LmJvZHkucGFyZW50Tm9kZS5zY3JvbGxIZWlnaHRcblx0XHRcdH07XG5cdFx0fSBlbHNlIHtcblx0XHRcdGVsZW1lbnQgPSAkKCBjZSApO1xuXHRcdFx0cCA9IFtdO1xuXHRcdFx0JCggWyBcIlRvcFwiLCBcIlJpZ2h0XCIsIFwiTGVmdFwiLCBcIkJvdHRvbVwiIF0gKS5lYWNoKCBmdW5jdGlvbiggaSwgbmFtZSApIHtcblx0XHRcdFx0cFsgaSBdID0gdGhhdC5fbnVtKCBlbGVtZW50LmNzcyggXCJwYWRkaW5nXCIgKyBuYW1lICkgKTtcblx0XHRcdH0gKTtcblxuXHRcdFx0dGhhdC5jb250YWluZXJPZmZzZXQgPSBlbGVtZW50Lm9mZnNldCgpO1xuXHRcdFx0dGhhdC5jb250YWluZXJQb3NpdGlvbiA9IGVsZW1lbnQucG9zaXRpb24oKTtcblx0XHRcdHRoYXQuY29udGFpbmVyU2l6ZSA9IHtcblx0XHRcdFx0aGVpZ2h0OiAoIGVsZW1lbnQuaW5uZXJIZWlnaHQoKSAtIHBbIDMgXSApLFxuXHRcdFx0XHR3aWR0aDogKCBlbGVtZW50LmlubmVyV2lkdGgoKSAtIHBbIDEgXSApXG5cdFx0XHR9O1xuXG5cdFx0XHRjbyA9IHRoYXQuY29udGFpbmVyT2Zmc2V0O1xuXHRcdFx0Y2ggPSB0aGF0LmNvbnRhaW5lclNpemUuaGVpZ2h0O1xuXHRcdFx0Y3cgPSB0aGF0LmNvbnRhaW5lclNpemUud2lkdGg7XG5cdFx0XHR3aWR0aCA9ICggdGhhdC5faGFzU2Nyb2xsICggY2UsIFwibGVmdFwiICkgPyBjZS5zY3JvbGxXaWR0aCA6IGN3ICk7XG5cdFx0XHRoZWlnaHQgPSAoIHRoYXQuX2hhc1Njcm9sbCAoIGNlICkgPyBjZS5zY3JvbGxIZWlnaHQgOiBjaCApIDtcblxuXHRcdFx0dGhhdC5wYXJlbnREYXRhID0ge1xuXHRcdFx0XHRlbGVtZW50OiBjZSxcblx0XHRcdFx0bGVmdDogY28ubGVmdCxcblx0XHRcdFx0dG9wOiBjby50b3AsXG5cdFx0XHRcdHdpZHRoOiB3aWR0aCxcblx0XHRcdFx0aGVpZ2h0OiBoZWlnaHRcblx0XHRcdH07XG5cdFx0fVxuXHR9LFxuXG5cdHJlc2l6ZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciB3b3NldCwgaG9zZXQsIGlzUGFyZW50LCBpc09mZnNldFJlbGF0aXZlLFxuXHRcdFx0dGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApLFxuXHRcdFx0byA9IHRoYXQub3B0aW9ucyxcblx0XHRcdGNvID0gdGhhdC5jb250YWluZXJPZmZzZXQsXG5cdFx0XHRjcCA9IHRoYXQucG9zaXRpb24sXG5cdFx0XHRwUmF0aW8gPSB0aGF0Ll9hc3BlY3RSYXRpbyB8fCBldmVudC5zaGlmdEtleSxcblx0XHRcdGNvcCA9IHtcblx0XHRcdFx0dG9wOiAwLFxuXHRcdFx0XHRsZWZ0OiAwXG5cdFx0XHR9LFxuXHRcdFx0Y2UgPSB0aGF0LmNvbnRhaW5lckVsZW1lbnQsXG5cdFx0XHRjb250aW51ZVJlc2l6ZSA9IHRydWU7XG5cblx0XHRpZiAoIGNlWyAwIF0gIT09IGRvY3VtZW50ICYmICggL3N0YXRpYy8gKS50ZXN0KCBjZS5jc3MoIFwicG9zaXRpb25cIiApICkgKSB7XG5cdFx0XHRjb3AgPSBjbztcblx0XHR9XG5cblx0XHRpZiAoIGNwLmxlZnQgPCAoIHRoYXQuX2hlbHBlciA/IGNvLmxlZnQgOiAwICkgKSB7XG5cdFx0XHR0aGF0LnNpemUud2lkdGggPSB0aGF0LnNpemUud2lkdGggK1xuXHRcdFx0XHQoIHRoYXQuX2hlbHBlciA/XG5cdFx0XHRcdFx0KCB0aGF0LnBvc2l0aW9uLmxlZnQgLSBjby5sZWZ0ICkgOlxuXHRcdFx0XHRcdCggdGhhdC5wb3NpdGlvbi5sZWZ0IC0gY29wLmxlZnQgKSApO1xuXG5cdFx0XHRpZiAoIHBSYXRpbyApIHtcblx0XHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IHRoYXQuc2l6ZS53aWR0aCAvIHRoYXQuYXNwZWN0UmF0aW87XG5cdFx0XHRcdGNvbnRpbnVlUmVzaXplID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHR0aGF0LnBvc2l0aW9uLmxlZnQgPSBvLmhlbHBlciA/IGNvLmxlZnQgOiAwO1xuXHRcdH1cblxuXHRcdGlmICggY3AudG9wIDwgKCB0aGF0Ll9oZWxwZXIgPyBjby50b3AgOiAwICkgKSB7XG5cdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gdGhhdC5zaXplLmhlaWdodCArXG5cdFx0XHRcdCggdGhhdC5faGVscGVyID9cblx0XHRcdFx0XHQoIHRoYXQucG9zaXRpb24udG9wIC0gY28udG9wICkgOlxuXHRcdFx0XHRcdHRoYXQucG9zaXRpb24udG9wICk7XG5cblx0XHRcdGlmICggcFJhdGlvICkge1xuXHRcdFx0XHR0aGF0LnNpemUud2lkdGggPSB0aGF0LnNpemUuaGVpZ2h0ICogdGhhdC5hc3BlY3RSYXRpbztcblx0XHRcdFx0Y29udGludWVSZXNpemUgPSBmYWxzZTtcblx0XHRcdH1cblx0XHRcdHRoYXQucG9zaXRpb24udG9wID0gdGhhdC5faGVscGVyID8gY28udG9wIDogMDtcblx0XHR9XG5cblx0XHRpc1BhcmVudCA9IHRoYXQuY29udGFpbmVyRWxlbWVudC5nZXQoIDAgKSA9PT0gdGhhdC5lbGVtZW50LnBhcmVudCgpLmdldCggMCApO1xuXHRcdGlzT2Zmc2V0UmVsYXRpdmUgPSAvcmVsYXRpdmV8YWJzb2x1dGUvLnRlc3QoIHRoYXQuY29udGFpbmVyRWxlbWVudC5jc3MoIFwicG9zaXRpb25cIiApICk7XG5cblx0XHRpZiAoIGlzUGFyZW50ICYmIGlzT2Zmc2V0UmVsYXRpdmUgKSB7XG5cdFx0XHR0aGF0Lm9mZnNldC5sZWZ0ID0gdGhhdC5wYXJlbnREYXRhLmxlZnQgKyB0aGF0LnBvc2l0aW9uLmxlZnQ7XG5cdFx0XHR0aGF0Lm9mZnNldC50b3AgPSB0aGF0LnBhcmVudERhdGEudG9wICsgdGhhdC5wb3NpdGlvbi50b3A7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoYXQub2Zmc2V0LmxlZnQgPSB0aGF0LmVsZW1lbnQub2Zmc2V0KCkubGVmdDtcblx0XHRcdHRoYXQub2Zmc2V0LnRvcCA9IHRoYXQuZWxlbWVudC5vZmZzZXQoKS50b3A7XG5cdFx0fVxuXG5cdFx0d29zZXQgPSBNYXRoLmFicyggdGhhdC5zaXplRGlmZi53aWR0aCArXG5cdFx0XHQoIHRoYXQuX2hlbHBlciA/XG5cdFx0XHRcdHRoYXQub2Zmc2V0LmxlZnQgLSBjb3AubGVmdCA6XG5cdFx0XHRcdCggdGhhdC5vZmZzZXQubGVmdCAtIGNvLmxlZnQgKSApICk7XG5cblx0XHRob3NldCA9IE1hdGguYWJzKCB0aGF0LnNpemVEaWZmLmhlaWdodCArXG5cdFx0XHQoIHRoYXQuX2hlbHBlciA/XG5cdFx0XHRcdHRoYXQub2Zmc2V0LnRvcCAtIGNvcC50b3AgOlxuXHRcdFx0XHQoIHRoYXQub2Zmc2V0LnRvcCAtIGNvLnRvcCApICkgKTtcblxuXHRcdGlmICggd29zZXQgKyB0aGF0LnNpemUud2lkdGggPj0gdGhhdC5wYXJlbnREYXRhLndpZHRoICkge1xuXHRcdFx0dGhhdC5zaXplLndpZHRoID0gdGhhdC5wYXJlbnREYXRhLndpZHRoIC0gd29zZXQ7XG5cdFx0XHRpZiAoIHBSYXRpbyApIHtcblx0XHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IHRoYXQuc2l6ZS53aWR0aCAvIHRoYXQuYXNwZWN0UmF0aW87XG5cdFx0XHRcdGNvbnRpbnVlUmVzaXplID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBob3NldCArIHRoYXQuc2l6ZS5oZWlnaHQgPj0gdGhhdC5wYXJlbnREYXRhLmhlaWdodCApIHtcblx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSB0aGF0LnBhcmVudERhdGEuaGVpZ2h0IC0gaG9zZXQ7XG5cdFx0XHRpZiAoIHBSYXRpbyApIHtcblx0XHRcdFx0dGhhdC5zaXplLndpZHRoID0gdGhhdC5zaXplLmhlaWdodCAqIHRoYXQuYXNwZWN0UmF0aW87XG5cdFx0XHRcdGNvbnRpbnVlUmVzaXplID0gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCAhY29udGludWVSZXNpemUgKSB7XG5cdFx0XHR0aGF0LnBvc2l0aW9uLmxlZnQgPSB0aGF0LnByZXZQb3NpdGlvbi5sZWZ0O1xuXHRcdFx0dGhhdC5wb3NpdGlvbi50b3AgPSB0aGF0LnByZXZQb3NpdGlvbi50b3A7XG5cdFx0XHR0aGF0LnNpemUud2lkdGggPSB0aGF0LnByZXZTaXplLndpZHRoO1xuXHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IHRoYXQucHJldlNpemUuaGVpZ2h0O1xuXHRcdH1cblx0fSxcblxuXHRzdG9wOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApLFxuXHRcdFx0byA9IHRoYXQub3B0aW9ucyxcblx0XHRcdGNvID0gdGhhdC5jb250YWluZXJPZmZzZXQsXG5cdFx0XHRjb3AgPSB0aGF0LmNvbnRhaW5lclBvc2l0aW9uLFxuXHRcdFx0Y2UgPSB0aGF0LmNvbnRhaW5lckVsZW1lbnQsXG5cdFx0XHRoZWxwZXIgPSAkKCB0aGF0LmhlbHBlciApLFxuXHRcdFx0aG8gPSBoZWxwZXIub2Zmc2V0KCksXG5cdFx0XHR3ID0gaGVscGVyLm91dGVyV2lkdGgoKSAtIHRoYXQuc2l6ZURpZmYud2lkdGgsXG5cdFx0XHRoID0gaGVscGVyLm91dGVySGVpZ2h0KCkgLSB0aGF0LnNpemVEaWZmLmhlaWdodDtcblxuXHRcdGlmICggdGhhdC5faGVscGVyICYmICFvLmFuaW1hdGUgJiYgKCAvcmVsYXRpdmUvICkudGVzdCggY2UuY3NzKCBcInBvc2l0aW9uXCIgKSApICkge1xuXHRcdFx0JCggdGhpcyApLmNzcygge1xuXHRcdFx0XHRsZWZ0OiBoby5sZWZ0IC0gY29wLmxlZnQgLSBjby5sZWZ0LFxuXHRcdFx0XHR3aWR0aDogdyxcblx0XHRcdFx0aGVpZ2h0OiBoXG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGF0Ll9oZWxwZXIgJiYgIW8uYW5pbWF0ZSAmJiAoIC9zdGF0aWMvICkudGVzdCggY2UuY3NzKCBcInBvc2l0aW9uXCIgKSApICkge1xuXHRcdFx0JCggdGhpcyApLmNzcygge1xuXHRcdFx0XHRsZWZ0OiBoby5sZWZ0IC0gY29wLmxlZnQgLSBjby5sZWZ0LFxuXHRcdFx0XHR3aWR0aDogdyxcblx0XHRcdFx0aGVpZ2h0OiBoXG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9XG59ICk7XG5cbiQudWkucGx1Z2luLmFkZCggXCJyZXNpemFibGVcIiwgXCJhbHNvUmVzaXplXCIsIHtcblxuXHRzdGFydDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSAkKCB0aGlzICkucmVzaXphYmxlKCBcImluc3RhbmNlXCIgKSxcblx0XHRcdG8gPSB0aGF0Lm9wdGlvbnM7XG5cblx0XHQkKCBvLmFsc29SZXNpemUgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBlbCA9ICQoIHRoaXMgKTtcblx0XHRcdGVsLmRhdGEoIFwidWktcmVzaXphYmxlLWFsc29yZXNpemVcIiwge1xuXHRcdFx0XHR3aWR0aDogcGFyc2VGbG9hdCggZWwud2lkdGgoKSApLCBoZWlnaHQ6IHBhcnNlRmxvYXQoIGVsLmhlaWdodCgpICksXG5cdFx0XHRcdGxlZnQ6IHBhcnNlRmxvYXQoIGVsLmNzcyggXCJsZWZ0XCIgKSApLCB0b3A6IHBhcnNlRmxvYXQoIGVsLmNzcyggXCJ0b3BcIiApIClcblx0XHRcdH0gKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0cmVzaXplOiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdHZhciB0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICksXG5cdFx0XHRvID0gdGhhdC5vcHRpb25zLFxuXHRcdFx0b3MgPSB0aGF0Lm9yaWdpbmFsU2l6ZSxcblx0XHRcdG9wID0gdGhhdC5vcmlnaW5hbFBvc2l0aW9uLFxuXHRcdFx0ZGVsdGEgPSB7XG5cdFx0XHRcdGhlaWdodDogKCB0aGF0LnNpemUuaGVpZ2h0IC0gb3MuaGVpZ2h0ICkgfHwgMCxcblx0XHRcdFx0d2lkdGg6ICggdGhhdC5zaXplLndpZHRoIC0gb3Mud2lkdGggKSB8fCAwLFxuXHRcdFx0XHR0b3A6ICggdGhhdC5wb3NpdGlvbi50b3AgLSBvcC50b3AgKSB8fCAwLFxuXHRcdFx0XHRsZWZ0OiAoIHRoYXQucG9zaXRpb24ubGVmdCAtIG9wLmxlZnQgKSB8fCAwXG5cdFx0XHR9O1xuXG5cdFx0XHQkKCBvLmFsc29SZXNpemUgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGVsID0gJCggdGhpcyApLCBzdGFydCA9ICQoIHRoaXMgKS5kYXRhKCBcInVpLXJlc2l6YWJsZS1hbHNvcmVzaXplXCIgKSwgc3R5bGUgPSB7fSxcblx0XHRcdFx0XHRjc3MgPSBlbC5wYXJlbnRzKCB1aS5vcmlnaW5hbEVsZW1lbnRbIDAgXSApLmxlbmd0aCA/XG5cdFx0XHRcdFx0XHRcdFsgXCJ3aWR0aFwiLCBcImhlaWdodFwiIF0gOlxuXHRcdFx0XHRcdFx0XHRbIFwid2lkdGhcIiwgXCJoZWlnaHRcIiwgXCJ0b3BcIiwgXCJsZWZ0XCIgXTtcblxuXHRcdFx0XHQkLmVhY2goIGNzcywgZnVuY3Rpb24oIGksIHByb3AgKSB7XG5cdFx0XHRcdFx0dmFyIHN1bSA9ICggc3RhcnRbIHByb3AgXSB8fCAwICkgKyAoIGRlbHRhWyBwcm9wIF0gfHwgMCApO1xuXHRcdFx0XHRcdGlmICggc3VtICYmIHN1bSA+PSAwICkge1xuXHRcdFx0XHRcdFx0c3R5bGVbIHByb3AgXSA9IHN1bSB8fCBudWxsO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdGVsLmNzcyggc3R5bGUgKTtcblx0XHRcdH0gKTtcblx0fSxcblxuXHRzdG9wOiBmdW5jdGlvbigpIHtcblx0XHQkKCB0aGlzICkucmVtb3ZlRGF0YSggXCJ1aS1yZXNpemFibGUtYWxzb3Jlc2l6ZVwiICk7XG5cdH1cbn0gKTtcblxuJC51aS5wbHVnaW4uYWRkKCBcInJlc2l6YWJsZVwiLCBcImdob3N0XCIsIHtcblxuXHRzdGFydDogZnVuY3Rpb24oKSB7XG5cblx0XHR2YXIgdGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApLCBjcyA9IHRoYXQuc2l6ZTtcblxuXHRcdHRoYXQuZ2hvc3QgPSB0aGF0Lm9yaWdpbmFsRWxlbWVudC5jbG9uZSgpO1xuXHRcdHRoYXQuZ2hvc3QuY3NzKCB7XG5cdFx0XHRvcGFjaXR5OiAwLjI1LFxuXHRcdFx0ZGlzcGxheTogXCJibG9ja1wiLFxuXHRcdFx0cG9zaXRpb246IFwicmVsYXRpdmVcIixcblx0XHRcdGhlaWdodDogY3MuaGVpZ2h0LFxuXHRcdFx0d2lkdGg6IGNzLndpZHRoLFxuXHRcdFx0bWFyZ2luOiAwLFxuXHRcdFx0bGVmdDogMCxcblx0XHRcdHRvcDogMFxuXHRcdH0gKTtcblxuXHRcdHRoYXQuX2FkZENsYXNzKCB0aGF0Lmdob3N0LCBcInVpLXJlc2l6YWJsZS1naG9zdFwiICk7XG5cblx0XHQvLyBERVBSRUNBVEVEXG5cdFx0Ly8gVE9ETzogcmVtb3ZlIGFmdGVyIDEuMTJcblx0XHRpZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSAmJiB0eXBlb2YgdGhhdC5vcHRpb25zLmdob3N0ID09PSBcInN0cmluZ1wiICkge1xuXG5cdFx0XHQvLyBHaG9zdCBvcHRpb25cblx0XHRcdHRoYXQuZ2hvc3QuYWRkQ2xhc3MoIHRoaXMub3B0aW9ucy5naG9zdCApO1xuXHRcdH1cblxuXHRcdHRoYXQuZ2hvc3QuYXBwZW5kVG8oIHRoYXQuaGVscGVyICk7XG5cblx0fSxcblxuXHRyZXNpemU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICk7XG5cdFx0aWYgKCB0aGF0Lmdob3N0ICkge1xuXHRcdFx0dGhhdC5naG9zdC5jc3MoIHtcblx0XHRcdFx0cG9zaXRpb246IFwicmVsYXRpdmVcIixcblx0XHRcdFx0aGVpZ2h0OiB0aGF0LnNpemUuaGVpZ2h0LFxuXHRcdFx0XHR3aWR0aDogdGhhdC5zaXplLndpZHRoXG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdHN0b3A6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gJCggdGhpcyApLnJlc2l6YWJsZSggXCJpbnN0YW5jZVwiICk7XG5cdFx0aWYgKCB0aGF0Lmdob3N0ICYmIHRoYXQuaGVscGVyICkge1xuXHRcdFx0dGhhdC5oZWxwZXIuZ2V0KCAwICkucmVtb3ZlQ2hpbGQoIHRoYXQuZ2hvc3QuZ2V0KCAwICkgKTtcblx0XHR9XG5cdH1cblxufSApO1xuXG4kLnVpLnBsdWdpbi5hZGQoIFwicmVzaXphYmxlXCIsIFwiZ3JpZFwiLCB7XG5cblx0cmVzaXplOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3V0ZXJEaW1lbnNpb25zLFxuXHRcdFx0dGhhdCA9ICQoIHRoaXMgKS5yZXNpemFibGUoIFwiaW5zdGFuY2VcIiApLFxuXHRcdFx0byA9IHRoYXQub3B0aW9ucyxcblx0XHRcdGNzID0gdGhhdC5zaXplLFxuXHRcdFx0b3MgPSB0aGF0Lm9yaWdpbmFsU2l6ZSxcblx0XHRcdG9wID0gdGhhdC5vcmlnaW5hbFBvc2l0aW9uLFxuXHRcdFx0YSA9IHRoYXQuYXhpcyxcblx0XHRcdGdyaWQgPSB0eXBlb2Ygby5ncmlkID09PSBcIm51bWJlclwiID8gWyBvLmdyaWQsIG8uZ3JpZCBdIDogby5ncmlkLFxuXHRcdFx0Z3JpZFggPSAoIGdyaWRbIDAgXSB8fCAxICksXG5cdFx0XHRncmlkWSA9ICggZ3JpZFsgMSBdIHx8IDEgKSxcblx0XHRcdG94ID0gTWF0aC5yb3VuZCggKCBjcy53aWR0aCAtIG9zLndpZHRoICkgLyBncmlkWCApICogZ3JpZFgsXG5cdFx0XHRveSA9IE1hdGgucm91bmQoICggY3MuaGVpZ2h0IC0gb3MuaGVpZ2h0ICkgLyBncmlkWSApICogZ3JpZFksXG5cdFx0XHRuZXdXaWR0aCA9IG9zLndpZHRoICsgb3gsXG5cdFx0XHRuZXdIZWlnaHQgPSBvcy5oZWlnaHQgKyBveSxcblx0XHRcdGlzTWF4V2lkdGggPSBvLm1heFdpZHRoICYmICggby5tYXhXaWR0aCA8IG5ld1dpZHRoICksXG5cdFx0XHRpc01heEhlaWdodCA9IG8ubWF4SGVpZ2h0ICYmICggby5tYXhIZWlnaHQgPCBuZXdIZWlnaHQgKSxcblx0XHRcdGlzTWluV2lkdGggPSBvLm1pbldpZHRoICYmICggby5taW5XaWR0aCA+IG5ld1dpZHRoICksXG5cdFx0XHRpc01pbkhlaWdodCA9IG8ubWluSGVpZ2h0ICYmICggby5taW5IZWlnaHQgPiBuZXdIZWlnaHQgKTtcblxuXHRcdG8uZ3JpZCA9IGdyaWQ7XG5cblx0XHRpZiAoIGlzTWluV2lkdGggKSB7XG5cdFx0XHRuZXdXaWR0aCArPSBncmlkWDtcblx0XHR9XG5cdFx0aWYgKCBpc01pbkhlaWdodCApIHtcblx0XHRcdG5ld0hlaWdodCArPSBncmlkWTtcblx0XHR9XG5cdFx0aWYgKCBpc01heFdpZHRoICkge1xuXHRcdFx0bmV3V2lkdGggLT0gZ3JpZFg7XG5cdFx0fVxuXHRcdGlmICggaXNNYXhIZWlnaHQgKSB7XG5cdFx0XHRuZXdIZWlnaHQgLT0gZ3JpZFk7XG5cdFx0fVxuXG5cdFx0aWYgKCAvXihzZXxzfGUpJC8udGVzdCggYSApICkge1xuXHRcdFx0dGhhdC5zaXplLndpZHRoID0gbmV3V2lkdGg7XG5cdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gbmV3SGVpZ2h0O1xuXHRcdH0gZWxzZSBpZiAoIC9eKG5lKSQvLnRlc3QoIGEgKSApIHtcblx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IG5ld1dpZHRoO1xuXHRcdFx0dGhhdC5zaXplLmhlaWdodCA9IG5ld0hlaWdodDtcblx0XHRcdHRoYXQucG9zaXRpb24udG9wID0gb3AudG9wIC0gb3k7XG5cdFx0fSBlbHNlIGlmICggL14oc3cpJC8udGVzdCggYSApICkge1xuXHRcdFx0dGhhdC5zaXplLndpZHRoID0gbmV3V2lkdGg7XG5cdFx0XHR0aGF0LnNpemUuaGVpZ2h0ID0gbmV3SGVpZ2h0O1xuXHRcdFx0dGhhdC5wb3NpdGlvbi5sZWZ0ID0gb3AubGVmdCAtIG94O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRpZiAoIG5ld0hlaWdodCAtIGdyaWRZIDw9IDAgfHwgbmV3V2lkdGggLSBncmlkWCA8PSAwICkge1xuXHRcdFx0XHRvdXRlckRpbWVuc2lvbnMgPSB0aGF0Ll9nZXRQYWRkaW5nUGx1c0JvcmRlckRpbWVuc2lvbnMoIHRoaXMgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBuZXdIZWlnaHQgLSBncmlkWSA+IDAgKSB7XG5cdFx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSBuZXdIZWlnaHQ7XG5cdFx0XHRcdHRoYXQucG9zaXRpb24udG9wID0gb3AudG9wIC0gb3k7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRuZXdIZWlnaHQgPSBncmlkWSAtIG91dGVyRGltZW5zaW9ucy5oZWlnaHQ7XG5cdFx0XHRcdHRoYXQuc2l6ZS5oZWlnaHQgPSBuZXdIZWlnaHQ7XG5cdFx0XHRcdHRoYXQucG9zaXRpb24udG9wID0gb3AudG9wICsgb3MuaGVpZ2h0IC0gbmV3SGVpZ2h0O1xuXHRcdFx0fVxuXHRcdFx0aWYgKCBuZXdXaWR0aCAtIGdyaWRYID4gMCApIHtcblx0XHRcdFx0dGhhdC5zaXplLndpZHRoID0gbmV3V2lkdGg7XG5cdFx0XHRcdHRoYXQucG9zaXRpb24ubGVmdCA9IG9wLmxlZnQgLSBveDtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdG5ld1dpZHRoID0gZ3JpZFggLSBvdXRlckRpbWVuc2lvbnMud2lkdGg7XG5cdFx0XHRcdHRoYXQuc2l6ZS53aWR0aCA9IG5ld1dpZHRoO1xuXHRcdFx0XHR0aGF0LnBvc2l0aW9uLmxlZnQgPSBvcC5sZWZ0ICsgb3Mud2lkdGggLSBuZXdXaWR0aDtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxufSApO1xuXG52YXIgd2lkZ2V0c1Jlc2l6YWJsZSA9ICQudWkucmVzaXphYmxlO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIERpYWxvZyAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogRGlhbG9nXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogRGlzcGxheXMgY3VzdG9taXphYmxlIGRpYWxvZyB3aW5kb3dzLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL2RpYWxvZy9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9kaWFsb2cvXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvY29yZS5jc3Ncbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9kaWFsb2cuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbiQud2lkZ2V0KCBcInVpLmRpYWxvZ1wiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRhcHBlbmRUbzogXCJib2R5XCIsXG5cdFx0YXV0b09wZW46IHRydWUsXG5cdFx0YnV0dG9uczogW10sXG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS1kaWFsb2dcIjogXCJ1aS1jb3JuZXItYWxsXCIsXG5cdFx0XHRcInVpLWRpYWxvZy10aXRsZWJhclwiOiBcInVpLWNvcm5lci1hbGxcIlxuXHRcdH0sXG5cdFx0Y2xvc2VPbkVzY2FwZTogdHJ1ZSxcblx0XHRjbG9zZVRleHQ6IFwiQ2xvc2VcIixcblx0XHRkcmFnZ2FibGU6IHRydWUsXG5cdFx0aGlkZTogbnVsbCxcblx0XHRoZWlnaHQ6IFwiYXV0b1wiLFxuXHRcdG1heEhlaWdodDogbnVsbCxcblx0XHRtYXhXaWR0aDogbnVsbCxcblx0XHRtaW5IZWlnaHQ6IDE1MCxcblx0XHRtaW5XaWR0aDogMTUwLFxuXHRcdG1vZGFsOiBmYWxzZSxcblx0XHRwb3NpdGlvbjoge1xuXHRcdFx0bXk6IFwiY2VudGVyXCIsXG5cdFx0XHRhdDogXCJjZW50ZXJcIixcblx0XHRcdG9mOiB3aW5kb3csXG5cdFx0XHRjb2xsaXNpb246IFwiZml0XCIsXG5cblx0XHRcdC8vIEVuc3VyZSB0aGUgdGl0bGViYXIgaXMgYWx3YXlzIHZpc2libGVcblx0XHRcdHVzaW5nOiBmdW5jdGlvbiggcG9zICkge1xuXHRcdFx0XHR2YXIgdG9wT2Zmc2V0ID0gJCggdGhpcyApLmNzcyggcG9zICkub2Zmc2V0KCkudG9wO1xuXHRcdFx0XHRpZiAoIHRvcE9mZnNldCA8IDAgKSB7XG5cdFx0XHRcdFx0JCggdGhpcyApLmNzcyggXCJ0b3BcIiwgcG9zLnRvcCAtIHRvcE9mZnNldCApO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fSxcblx0XHRyZXNpemFibGU6IHRydWUsXG5cdFx0c2hvdzogbnVsbCxcblx0XHR0aXRsZTogbnVsbCxcblx0XHR3aWR0aDogMzAwLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0YmVmb3JlQ2xvc2U6IG51bGwsXG5cdFx0Y2xvc2U6IG51bGwsXG5cdFx0ZHJhZzogbnVsbCxcblx0XHRkcmFnU3RhcnQ6IG51bGwsXG5cdFx0ZHJhZ1N0b3A6IG51bGwsXG5cdFx0Zm9jdXM6IG51bGwsXG5cdFx0b3BlbjogbnVsbCxcblx0XHRyZXNpemU6IG51bGwsXG5cdFx0cmVzaXplU3RhcnQ6IG51bGwsXG5cdFx0cmVzaXplU3RvcDogbnVsbFxuXHR9LFxuXG5cdHNpemVSZWxhdGVkT3B0aW9uczoge1xuXHRcdGJ1dHRvbnM6IHRydWUsXG5cdFx0aGVpZ2h0OiB0cnVlLFxuXHRcdG1heEhlaWdodDogdHJ1ZSxcblx0XHRtYXhXaWR0aDogdHJ1ZSxcblx0XHRtaW5IZWlnaHQ6IHRydWUsXG5cdFx0bWluV2lkdGg6IHRydWUsXG5cdFx0d2lkdGg6IHRydWVcblx0fSxcblxuXHRyZXNpemFibGVSZWxhdGVkT3B0aW9uczoge1xuXHRcdG1heEhlaWdodDogdHJ1ZSxcblx0XHRtYXhXaWR0aDogdHJ1ZSxcblx0XHRtaW5IZWlnaHQ6IHRydWUsXG5cdFx0bWluV2lkdGg6IHRydWVcblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLm9yaWdpbmFsQ3NzID0ge1xuXHRcdFx0ZGlzcGxheTogdGhpcy5lbGVtZW50WyAwIF0uc3R5bGUuZGlzcGxheSxcblx0XHRcdHdpZHRoOiB0aGlzLmVsZW1lbnRbIDAgXS5zdHlsZS53aWR0aCxcblx0XHRcdG1pbkhlaWdodDogdGhpcy5lbGVtZW50WyAwIF0uc3R5bGUubWluSGVpZ2h0LFxuXHRcdFx0bWF4SGVpZ2h0OiB0aGlzLmVsZW1lbnRbIDAgXS5zdHlsZS5tYXhIZWlnaHQsXG5cdFx0XHRoZWlnaHQ6IHRoaXMuZWxlbWVudFsgMCBdLnN0eWxlLmhlaWdodFxuXHRcdH07XG5cdFx0dGhpcy5vcmlnaW5hbFBvc2l0aW9uID0ge1xuXHRcdFx0cGFyZW50OiB0aGlzLmVsZW1lbnQucGFyZW50KCksXG5cdFx0XHRpbmRleDogdGhpcy5lbGVtZW50LnBhcmVudCgpLmNoaWxkcmVuKCkuaW5kZXgoIHRoaXMuZWxlbWVudCApXG5cdFx0fTtcblx0XHR0aGlzLm9yaWdpbmFsVGl0bGUgPSB0aGlzLmVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiICk7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMudGl0bGUgPT0gbnVsbCAmJiB0aGlzLm9yaWdpbmFsVGl0bGUgIT0gbnVsbCApIHtcblx0XHRcdHRoaXMub3B0aW9ucy50aXRsZSA9IHRoaXMub3JpZ2luYWxUaXRsZTtcblx0XHR9XG5cblx0XHQvLyBEaWFsb2dzIGNhbid0IGJlIGRpc2FibGVkXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHR0aGlzLm9wdGlvbnMuZGlzYWJsZWQgPSBmYWxzZTtcblx0XHR9XG5cblx0XHR0aGlzLl9jcmVhdGVXcmFwcGVyKCk7XG5cblx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdC5zaG93KClcblx0XHRcdC5yZW1vdmVBdHRyKCBcInRpdGxlXCIgKVxuXHRcdFx0LmFwcGVuZFRvKCB0aGlzLnVpRGlhbG9nICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1kaWFsb2ctY29udGVudFwiLCBcInVpLXdpZGdldC1jb250ZW50XCIgKTtcblxuXHRcdHRoaXMuX2NyZWF0ZVRpdGxlYmFyKCk7XG5cdFx0dGhpcy5fY3JlYXRlQnV0dG9uUGFuZSgpO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZHJhZ2dhYmxlICYmICQuZm4uZHJhZ2dhYmxlICkge1xuXHRcdFx0dGhpcy5fbWFrZURyYWdnYWJsZSgpO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5yZXNpemFibGUgJiYgJC5mbi5yZXNpemFibGUgKSB7XG5cdFx0XHR0aGlzLl9tYWtlUmVzaXphYmxlKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5faXNPcGVuID0gZmFsc2U7XG5cblx0XHR0aGlzLl90cmFja0ZvY3VzKCk7XG5cdH0sXG5cblx0X2luaXQ6IGZ1bmN0aW9uKCkge1xuXHRcdGlmICggdGhpcy5vcHRpb25zLmF1dG9PcGVuICkge1xuXHRcdFx0dGhpcy5vcGVuKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9hcHBlbmRUbzogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGVsZW1lbnQgPSB0aGlzLm9wdGlvbnMuYXBwZW5kVG87XG5cdFx0aWYgKCBlbGVtZW50ICYmICggZWxlbWVudC5qcXVlcnkgfHwgZWxlbWVudC5ub2RlVHlwZSApICkge1xuXHRcdFx0cmV0dXJuICQoIGVsZW1lbnQgKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuZG9jdW1lbnQuZmluZCggZWxlbWVudCB8fCBcImJvZHlcIiApLmVxKCAwICk7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBuZXh0LFxuXHRcdFx0b3JpZ2luYWxQb3NpdGlvbiA9IHRoaXMub3JpZ2luYWxQb3NpdGlvbjtcblxuXHRcdHRoaXMuX3VudHJhY2tJbnN0YW5jZSgpO1xuXHRcdHRoaXMuX2Rlc3Ryb3lPdmVybGF5KCk7XG5cblx0XHR0aGlzLmVsZW1lbnRcblx0XHRcdC5yZW1vdmVVbmlxdWVJZCgpXG5cdFx0XHQuY3NzKCB0aGlzLm9yaWdpbmFsQ3NzIClcblxuXHRcdFx0Ly8gV2l0aG91dCBkZXRhY2hpbmcgZmlyc3QsIHRoZSBmb2xsb3dpbmcgYmVjb21lcyByZWFsbHkgc2xvd1xuXHRcdFx0LmRldGFjaCgpO1xuXG5cdFx0dGhpcy51aURpYWxvZy5yZW1vdmUoKTtcblxuXHRcdGlmICggdGhpcy5vcmlnaW5hbFRpdGxlICkge1xuXHRcdFx0dGhpcy5lbGVtZW50LmF0dHIoIFwidGl0bGVcIiwgdGhpcy5vcmlnaW5hbFRpdGxlICk7XG5cdFx0fVxuXG5cdFx0bmV4dCA9IG9yaWdpbmFsUG9zaXRpb24ucGFyZW50LmNoaWxkcmVuKCkuZXEoIG9yaWdpbmFsUG9zaXRpb24uaW5kZXggKTtcblxuXHRcdC8vIERvbid0IHRyeSB0byBwbGFjZSB0aGUgZGlhbG9nIG5leHQgdG8gaXRzZWxmICgjODYxMylcblx0XHRpZiAoIG5leHQubGVuZ3RoICYmIG5leHRbIDAgXSAhPT0gdGhpcy5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRuZXh0LmJlZm9yZSggdGhpcy5lbGVtZW50ICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdG9yaWdpbmFsUG9zaXRpb24ucGFyZW50LmFwcGVuZCggdGhpcy5lbGVtZW50ICk7XG5cdFx0fVxuXHR9LFxuXG5cdHdpZGdldDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMudWlEaWFsb2c7XG5cdH0sXG5cblx0ZGlzYWJsZTogJC5ub29wLFxuXHRlbmFibGU6ICQubm9vcCxcblxuXHRjbG9zZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdGlmICggIXRoaXMuX2lzT3BlbiB8fCB0aGlzLl90cmlnZ2VyKCBcImJlZm9yZUNsb3NlXCIsIGV2ZW50ICkgPT09IGZhbHNlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuX2lzT3BlbiA9IGZhbHNlO1xuXHRcdHRoaXMuX2ZvY3VzZWRFbGVtZW50ID0gbnVsbDtcblx0XHR0aGlzLl9kZXN0cm95T3ZlcmxheSgpO1xuXHRcdHRoaXMuX3VudHJhY2tJbnN0YW5jZSgpO1xuXG5cdFx0aWYgKCAhdGhpcy5vcGVuZXIuZmlsdGVyKCBcIjpmb2N1c2FibGVcIiApLnRyaWdnZXIoIFwiZm9jdXNcIiApLmxlbmd0aCApIHtcblxuXHRcdFx0Ly8gSGlkaW5nIGEgZm9jdXNlZCBlbGVtZW50IGRvZXNuJ3QgdHJpZ2dlciBibHVyIGluIFdlYktpdFxuXHRcdFx0Ly8gc28gaW4gY2FzZSB3ZSBoYXZlIG5vdGhpbmcgdG8gZm9jdXMgb24sIGV4cGxpY2l0bHkgYmx1ciB0aGUgYWN0aXZlIGVsZW1lbnRcblx0XHRcdC8vIGh0dHBzOi8vYnVncy53ZWJraXQub3JnL3Nob3dfYnVnLmNnaT9pZD00NzE4MlxuXHRcdFx0JC51aS5zYWZlQmx1ciggJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICkgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9oaWRlKCB0aGlzLnVpRGlhbG9nLCB0aGlzLm9wdGlvbnMuaGlkZSwgZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGF0Ll90cmlnZ2VyKCBcImNsb3NlXCIsIGV2ZW50ICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdGlzT3BlbjogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2lzT3Blbjtcblx0fSxcblxuXHRtb3ZlVG9Ub3A6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX21vdmVUb1RvcCgpO1xuXHR9LFxuXG5cdF9tb3ZlVG9Ub3A6IGZ1bmN0aW9uKCBldmVudCwgc2lsZW50ICkge1xuXHRcdHZhciBtb3ZlZCA9IGZhbHNlLFxuXHRcdFx0ekluZGljZXMgPSB0aGlzLnVpRGlhbG9nLnNpYmxpbmdzKCBcIi51aS1mcm9udDp2aXNpYmxlXCIgKS5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRyZXR1cm4gKyQoIHRoaXMgKS5jc3MoIFwiei1pbmRleFwiICk7XG5cdFx0XHR9ICkuZ2V0KCksXG5cdFx0XHR6SW5kZXhNYXggPSBNYXRoLm1heC5hcHBseSggbnVsbCwgekluZGljZXMgKTtcblxuXHRcdGlmICggekluZGV4TWF4ID49ICt0aGlzLnVpRGlhbG9nLmNzcyggXCJ6LWluZGV4XCIgKSApIHtcblx0XHRcdHRoaXMudWlEaWFsb2cuY3NzKCBcInotaW5kZXhcIiwgekluZGV4TWF4ICsgMSApO1xuXHRcdFx0bW92ZWQgPSB0cnVlO1xuXHRcdH1cblxuXHRcdGlmICggbW92ZWQgJiYgIXNpbGVudCApIHtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiZm9jdXNcIiwgZXZlbnQgKTtcblx0XHR9XG5cdFx0cmV0dXJuIG1vdmVkO1xuXHR9LFxuXG5cdG9wZW46IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblx0XHRpZiAoIHRoaXMuX2lzT3BlbiApIHtcblx0XHRcdGlmICggdGhpcy5fbW92ZVRvVG9wKCkgKSB7XG5cdFx0XHRcdHRoaXMuX2ZvY3VzVGFiYmFibGUoKTtcblx0XHRcdH1cblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR0aGlzLl9pc09wZW4gPSB0cnVlO1xuXHRcdHRoaXMub3BlbmVyID0gJCggJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICkgKTtcblxuXHRcdHRoaXMuX3NpemUoKTtcblx0XHR0aGlzLl9wb3NpdGlvbigpO1xuXHRcdHRoaXMuX2NyZWF0ZU92ZXJsYXkoKTtcblx0XHR0aGlzLl9tb3ZlVG9Ub3AoIG51bGwsIHRydWUgKTtcblxuXHRcdC8vIEVuc3VyZSB0aGUgb3ZlcmxheSBpcyBtb3ZlZCB0byB0aGUgdG9wIHdpdGggdGhlIGRpYWxvZywgYnV0IG9ubHkgd2hlblxuXHRcdC8vIG9wZW5pbmcuIFRoZSBvdmVybGF5IHNob3VsZG4ndCBtb3ZlIGFmdGVyIHRoZSBkaWFsb2cgaXMgb3BlbiBzbyB0aGF0XG5cdFx0Ly8gbW9kZWxlc3MgZGlhbG9ncyBvcGVuZWQgYWZ0ZXIgdGhlIG1vZGFsIGRpYWxvZyBzdGFjayBwcm9wZXJseS5cblx0XHRpZiAoIHRoaXMub3ZlcmxheSApIHtcblx0XHRcdHRoaXMub3ZlcmxheS5jc3MoIFwiei1pbmRleFwiLCB0aGlzLnVpRGlhbG9nLmNzcyggXCJ6LWluZGV4XCIgKSAtIDEgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9zaG93KCB0aGlzLnVpRGlhbG9nLCB0aGlzLm9wdGlvbnMuc2hvdywgZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGF0Ll9mb2N1c1RhYmJhYmxlKCk7XG5cdFx0XHR0aGF0Ll90cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHR9ICk7XG5cblx0XHQvLyBUcmFjayB0aGUgZGlhbG9nIGltbWVkaWF0ZWx5IHVwb24gb3BlbmVuaW5nIGluIGNhc2UgYSBmb2N1cyBldmVudFxuXHRcdC8vIHNvbWVob3cgb2NjdXJzIG91dHNpZGUgb2YgdGhlIGRpYWxvZyBiZWZvcmUgYW4gZWxlbWVudCBpbnNpZGUgdGhlXG5cdFx0Ly8gZGlhbG9nIGlzIGZvY3VzZWQgKCMxMDE1Milcblx0XHR0aGlzLl9tYWtlRm9jdXNUYXJnZXQoKTtcblxuXHRcdHRoaXMuX3RyaWdnZXIoIFwib3BlblwiICk7XG5cdH0sXG5cblx0X2ZvY3VzVGFiYmFibGU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly8gU2V0IGZvY3VzIHRvIHRoZSBmaXJzdCBtYXRjaDpcblx0XHQvLyAxLiBBbiBlbGVtZW50IHRoYXQgd2FzIGZvY3VzZWQgcHJldmlvdXNseVxuXHRcdC8vIDIuIEZpcnN0IGVsZW1lbnQgaW5zaWRlIHRoZSBkaWFsb2cgbWF0Y2hpbmcgW2F1dG9mb2N1c11cblx0XHQvLyAzLiBUYWJiYWJsZSBlbGVtZW50IGluc2lkZSB0aGUgY29udGVudCBlbGVtZW50XG5cdFx0Ly8gNC4gVGFiYmFibGUgZWxlbWVudCBpbnNpZGUgdGhlIGJ1dHRvbnBhbmVcblx0XHQvLyA1LiBUaGUgY2xvc2UgYnV0dG9uXG5cdFx0Ly8gNi4gVGhlIGRpYWxvZyBpdHNlbGZcblx0XHR2YXIgaGFzRm9jdXMgPSB0aGlzLl9mb2N1c2VkRWxlbWVudDtcblx0XHRpZiAoICFoYXNGb2N1cyApIHtcblx0XHRcdGhhc0ZvY3VzID0gdGhpcy5lbGVtZW50LmZpbmQoIFwiW2F1dG9mb2N1c11cIiApO1xuXHRcdH1cblx0XHRpZiAoICFoYXNGb2N1cy5sZW5ndGggKSB7XG5cdFx0XHRoYXNGb2N1cyA9IHRoaXMuZWxlbWVudC5maW5kKCBcIjp0YWJiYWJsZVwiICk7XG5cdFx0fVxuXHRcdGlmICggIWhhc0ZvY3VzLmxlbmd0aCApIHtcblx0XHRcdGhhc0ZvY3VzID0gdGhpcy51aURpYWxvZ0J1dHRvblBhbmUuZmluZCggXCI6dGFiYmFibGVcIiApO1xuXHRcdH1cblx0XHRpZiAoICFoYXNGb2N1cy5sZW5ndGggKSB7XG5cdFx0XHRoYXNGb2N1cyA9IHRoaXMudWlEaWFsb2dUaXRsZWJhckNsb3NlLmZpbHRlciggXCI6dGFiYmFibGVcIiApO1xuXHRcdH1cblx0XHRpZiAoICFoYXNGb2N1cy5sZW5ndGggKSB7XG5cdFx0XHRoYXNGb2N1cyA9IHRoaXMudWlEaWFsb2c7XG5cdFx0fVxuXHRcdGhhc0ZvY3VzLmVxKCAwICkudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdH0sXG5cblx0X2tlZXBGb2N1czogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGZ1bmN0aW9uIGNoZWNrRm9jdXMoKSB7XG5cdFx0XHR2YXIgYWN0aXZlRWxlbWVudCA9ICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApLFxuXHRcdFx0XHRpc0FjdGl2ZSA9IHRoaXMudWlEaWFsb2dbIDAgXSA9PT0gYWN0aXZlRWxlbWVudCB8fFxuXHRcdFx0XHRcdCQuY29udGFpbnMoIHRoaXMudWlEaWFsb2dbIDAgXSwgYWN0aXZlRWxlbWVudCApO1xuXHRcdFx0aWYgKCAhaXNBY3RpdmUgKSB7XG5cdFx0XHRcdHRoaXMuX2ZvY3VzVGFiYmFibGUoKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRjaGVja0ZvY3VzLmNhbGwoIHRoaXMgKTtcblxuXHRcdC8vIHN1cHBvcnQ6IElFXG5cdFx0Ly8gSUUgPD0gOCBkb2Vzbid0IHByZXZlbnQgbW92aW5nIGZvY3VzIGV2ZW4gd2l0aCBldmVudC5wcmV2ZW50RGVmYXVsdCgpXG5cdFx0Ly8gc28gd2UgY2hlY2sgYWdhaW4gbGF0ZXJcblx0XHR0aGlzLl9kZWxheSggY2hlY2tGb2N1cyApO1xuXHR9LFxuXG5cdF9jcmVhdGVXcmFwcGVyOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLnVpRGlhbG9nID0gJCggXCI8ZGl2PlwiIClcblx0XHRcdC5oaWRlKClcblx0XHRcdC5hdHRyKCB7XG5cblx0XHRcdFx0Ly8gU2V0dGluZyB0YWJJbmRleCBtYWtlcyB0aGUgZGl2IGZvY3VzYWJsZVxuXHRcdFx0XHR0YWJJbmRleDogLTEsXG5cdFx0XHRcdHJvbGU6IFwiZGlhbG9nXCJcblx0XHRcdH0gKVxuXHRcdFx0LmFwcGVuZFRvKCB0aGlzLl9hcHBlbmRUbygpICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy51aURpYWxvZywgXCJ1aS1kaWFsb2dcIiwgXCJ1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnQgdWktZnJvbnRcIiApO1xuXHRcdHRoaXMuX29uKCB0aGlzLnVpRGlhbG9nLCB7XG5cdFx0XHRrZXlkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5vcHRpb25zLmNsb3NlT25Fc2NhcGUgJiYgIWV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpICYmIGV2ZW50LmtleUNvZGUgJiZcblx0XHRcdFx0XHRcdGV2ZW50LmtleUNvZGUgPT09ICQudWkua2V5Q29kZS5FU0NBUEUgKSB7XG5cdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHR0aGlzLmNsb3NlKCBldmVudCApO1xuXHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIFByZXZlbnQgdGFiYmluZyBvdXQgb2YgZGlhbG9nc1xuXHRcdFx0XHRpZiAoIGV2ZW50LmtleUNvZGUgIT09ICQudWkua2V5Q29kZS5UQUIgfHwgZXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkgKSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHZhciB0YWJiYWJsZXMgPSB0aGlzLnVpRGlhbG9nLmZpbmQoIFwiOnRhYmJhYmxlXCIgKSxcblx0XHRcdFx0XHRmaXJzdCA9IHRhYmJhYmxlcy5maWx0ZXIoIFwiOmZpcnN0XCIgKSxcblx0XHRcdFx0XHRsYXN0ID0gdGFiYmFibGVzLmZpbHRlciggXCI6bGFzdFwiICk7XG5cblx0XHRcdFx0aWYgKCAoIGV2ZW50LnRhcmdldCA9PT0gbGFzdFsgMCBdIHx8IGV2ZW50LnRhcmdldCA9PT0gdGhpcy51aURpYWxvZ1sgMCBdICkgJiZcblx0XHRcdFx0XHRcdCFldmVudC5zaGlmdEtleSApIHtcblx0XHRcdFx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0XHRmaXJzdC50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0fSBlbHNlIGlmICggKCBldmVudC50YXJnZXQgPT09IGZpcnN0WyAwIF0gfHxcblx0XHRcdFx0XHRcdGV2ZW50LnRhcmdldCA9PT0gdGhpcy51aURpYWxvZ1sgMCBdICkgJiYgZXZlbnQuc2hpZnRLZXkgKSB7XG5cdFx0XHRcdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0bGFzdC50cmlnZ2VyKCBcImZvY3VzXCIgKTtcblx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0fVxuXHRcdFx0fSxcblx0XHRcdG1vdXNlZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoIHRoaXMuX21vdmVUb1RvcCggZXZlbnQgKSApIHtcblx0XHRcdFx0XHR0aGlzLl9mb2N1c1RhYmJhYmxlKCk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHQvLyBXZSBhc3N1bWUgdGhhdCBhbnkgZXhpc3RpbmcgYXJpYS1kZXNjcmliZWRieSBhdHRyaWJ1dGUgbWVhbnNcblx0XHQvLyB0aGF0IHRoZSBkaWFsb2cgY29udGVudCBpcyBtYXJrZWQgdXAgcHJvcGVybHlcblx0XHQvLyBvdGhlcndpc2Ugd2UgYnJ1dGUgZm9yY2UgdGhlIGNvbnRlbnQgYXMgdGhlIGRlc2NyaXB0aW9uXG5cdFx0aWYgKCAhdGhpcy5lbGVtZW50LmZpbmQoIFwiW2FyaWEtZGVzY3JpYmVkYnldXCIgKS5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLnVpRGlhbG9nLmF0dHIoIHtcblx0XHRcdFx0XCJhcmlhLWRlc2NyaWJlZGJ5XCI6IHRoaXMuZWxlbWVudC51bmlxdWVJZCgpLmF0dHIoIFwiaWRcIiApXG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9jcmVhdGVUaXRsZWJhcjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHVpRGlhbG9nVGl0bGU7XG5cblx0XHR0aGlzLnVpRGlhbG9nVGl0bGViYXIgPSAkKCBcIjxkaXY+XCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy51aURpYWxvZ1RpdGxlYmFyLFxuXHRcdFx0XCJ1aS1kaWFsb2ctdGl0bGViYXJcIiwgXCJ1aS13aWRnZXQtaGVhZGVyIHVpLWhlbHBlci1jbGVhcmZpeFwiICk7XG5cdFx0dGhpcy5fb24oIHRoaXMudWlEaWFsb2dUaXRsZWJhciwge1xuXHRcdFx0bW91c2Vkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHRcdFx0Ly8gRG9uJ3QgcHJldmVudCBjbGljayBvbiBjbG9zZSBidXR0b24gKCM4ODM4KVxuXHRcdFx0XHQvLyBGb2N1c2luZyBhIGRpYWxvZyB0aGF0IGlzIHBhcnRpYWxseSBzY3JvbGxlZCBvdXQgb2Ygdmlld1xuXHRcdFx0XHQvLyBjYXVzZXMgdGhlIGJyb3dzZXIgdG8gc2Nyb2xsIGl0IGludG8gdmlldywgcHJldmVudGluZyB0aGUgY2xpY2sgZXZlbnRcblx0XHRcdFx0aWYgKCAhJCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggXCIudWktZGlhbG9nLXRpdGxlYmFyLWNsb3NlXCIgKSApIHtcblxuXHRcdFx0XHRcdC8vIERpYWxvZyBpc24ndCBnZXR0aW5nIGZvY3VzIHdoZW4gZHJhZ2dpbmcgKCM4MDYzKVxuXHRcdFx0XHRcdHRoaXMudWlEaWFsb2cudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHQvLyBTdXBwb3J0OiBJRVxuXHRcdC8vIFVzZSB0eXBlPVwiYnV0dG9uXCIgdG8gcHJldmVudCBlbnRlciBrZXlwcmVzc2VzIGluIHRleHRib3hlcyBmcm9tIGNsb3NpbmcgdGhlXG5cdFx0Ly8gZGlhbG9nIGluIElFICgjOTMxMilcblx0XHR0aGlzLnVpRGlhbG9nVGl0bGViYXJDbG9zZSA9ICQoIFwiPGJ1dHRvbiB0eXBlPSdidXR0b24nPjwvYnV0dG9uPlwiIClcblx0XHRcdC5idXR0b24oIHtcblx0XHRcdFx0bGFiZWw6ICQoIFwiPGE+XCIgKS50ZXh0KCB0aGlzLm9wdGlvbnMuY2xvc2VUZXh0ICkuaHRtbCgpLFxuXHRcdFx0XHRpY29uOiBcInVpLWljb24tY2xvc2V0aGlja1wiLFxuXHRcdFx0XHRzaG93TGFiZWw6IGZhbHNlXG5cdFx0XHR9IClcblx0XHRcdC5hcHBlbmRUbyggdGhpcy51aURpYWxvZ1RpdGxlYmFyICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy51aURpYWxvZ1RpdGxlYmFyQ2xvc2UsIFwidWktZGlhbG9nLXRpdGxlYmFyLWNsb3NlXCIgKTtcblx0XHR0aGlzLl9vbiggdGhpcy51aURpYWxvZ1RpdGxlYmFyQ2xvc2UsIHtcblx0XHRcdGNsaWNrOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdHRoaXMuY2xvc2UoIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0dWlEaWFsb2dUaXRsZSA9ICQoIFwiPHNwYW4+XCIgKS51bmlxdWVJZCgpLnByZXBlbmRUbyggdGhpcy51aURpYWxvZ1RpdGxlYmFyICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHVpRGlhbG9nVGl0bGUsIFwidWktZGlhbG9nLXRpdGxlXCIgKTtcblx0XHR0aGlzLl90aXRsZSggdWlEaWFsb2dUaXRsZSApO1xuXG5cdFx0dGhpcy51aURpYWxvZ1RpdGxlYmFyLnByZXBlbmRUbyggdGhpcy51aURpYWxvZyApO1xuXG5cdFx0dGhpcy51aURpYWxvZy5hdHRyKCB7XG5cdFx0XHRcImFyaWEtbGFiZWxsZWRieVwiOiB1aURpYWxvZ1RpdGxlLmF0dHIoIFwiaWRcIiApXG5cdFx0fSApO1xuXHR9LFxuXG5cdF90aXRsZTogZnVuY3Rpb24oIHRpdGxlICkge1xuXHRcdGlmICggdGhpcy5vcHRpb25zLnRpdGxlICkge1xuXHRcdFx0dGl0bGUudGV4dCggdGhpcy5vcHRpb25zLnRpdGxlICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRpdGxlLmh0bWwoIFwiJiMxNjA7XCIgKTtcblx0XHR9XG5cdH0sXG5cblx0X2NyZWF0ZUJ1dHRvblBhbmU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMudWlEaWFsb2dCdXR0b25QYW5lID0gJCggXCI8ZGl2PlwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudWlEaWFsb2dCdXR0b25QYW5lLCBcInVpLWRpYWxvZy1idXR0b25wYW5lXCIsXG5cdFx0XHRcInVpLXdpZGdldC1jb250ZW50IHVpLWhlbHBlci1jbGVhcmZpeFwiICk7XG5cblx0XHR0aGlzLnVpQnV0dG9uU2V0ID0gJCggXCI8ZGl2PlwiIClcblx0XHRcdC5hcHBlbmRUbyggdGhpcy51aURpYWxvZ0J1dHRvblBhbmUgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy51aUJ1dHRvblNldCwgXCJ1aS1kaWFsb2ctYnV0dG9uc2V0XCIgKTtcblxuXHRcdHRoaXMuX2NyZWF0ZUJ1dHRvbnMoKTtcblx0fSxcblxuXHRfY3JlYXRlQnV0dG9uczogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0YnV0dG9ucyA9IHRoaXMub3B0aW9ucy5idXR0b25zO1xuXG5cdFx0Ly8gSWYgd2UgYWxyZWFkeSBoYXZlIGEgYnV0dG9uIHBhbmUsIHJlbW92ZSBpdFxuXHRcdHRoaXMudWlEaWFsb2dCdXR0b25QYW5lLnJlbW92ZSgpO1xuXHRcdHRoaXMudWlCdXR0b25TZXQuZW1wdHkoKTtcblxuXHRcdGlmICggJC5pc0VtcHR5T2JqZWN0KCBidXR0b25zICkgfHwgKCAkLmlzQXJyYXkoIGJ1dHRvbnMgKSAmJiAhYnV0dG9ucy5sZW5ndGggKSApIHtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLnVpRGlhbG9nLCBcInVpLWRpYWxvZy1idXR0b25zXCIgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQkLmVhY2goIGJ1dHRvbnMsIGZ1bmN0aW9uKCBuYW1lLCBwcm9wcyApIHtcblx0XHRcdHZhciBjbGljaywgYnV0dG9uT3B0aW9ucztcblx0XHRcdHByb3BzID0gJC5pc0Z1bmN0aW9uKCBwcm9wcyApID9cblx0XHRcdFx0eyBjbGljazogcHJvcHMsIHRleHQ6IG5hbWUgfSA6XG5cdFx0XHRcdHByb3BzO1xuXG5cdFx0XHQvLyBEZWZhdWx0IHRvIGEgbm9uLXN1Ym1pdHRpbmcgYnV0dG9uXG5cdFx0XHRwcm9wcyA9ICQuZXh0ZW5kKCB7IHR5cGU6IFwiYnV0dG9uXCIgfSwgcHJvcHMgKTtcblxuXHRcdFx0Ly8gQ2hhbmdlIHRoZSBjb250ZXh0IGZvciB0aGUgY2xpY2sgY2FsbGJhY2sgdG8gYmUgdGhlIG1haW4gZWxlbWVudFxuXHRcdFx0Y2xpY2sgPSBwcm9wcy5jbGljaztcblx0XHRcdGJ1dHRvbk9wdGlvbnMgPSB7XG5cdFx0XHRcdGljb246IHByb3BzLmljb24sXG5cdFx0XHRcdGljb25Qb3NpdGlvbjogcHJvcHMuaWNvblBvc2l0aW9uLFxuXHRcdFx0XHRzaG93TGFiZWw6IHByb3BzLnNob3dMYWJlbCxcblxuXHRcdFx0XHQvLyBEZXByZWNhdGVkIG9wdGlvbnNcblx0XHRcdFx0aWNvbnM6IHByb3BzLmljb25zLFxuXHRcdFx0XHR0ZXh0OiBwcm9wcy50ZXh0XG5cdFx0XHR9O1xuXG5cdFx0XHRkZWxldGUgcHJvcHMuY2xpY2s7XG5cdFx0XHRkZWxldGUgcHJvcHMuaWNvbjtcblx0XHRcdGRlbGV0ZSBwcm9wcy5pY29uUG9zaXRpb247XG5cdFx0XHRkZWxldGUgcHJvcHMuc2hvd0xhYmVsO1xuXG5cdFx0XHQvLyBEZXByZWNhdGVkIG9wdGlvbnNcblx0XHRcdGRlbGV0ZSBwcm9wcy5pY29ucztcblx0XHRcdGlmICggdHlwZW9mIHByb3BzLnRleHQgPT09IFwiYm9vbGVhblwiICkge1xuXHRcdFx0XHRkZWxldGUgcHJvcHMudGV4dDtcblx0XHRcdH1cblxuXHRcdFx0JCggXCI8YnV0dG9uPjwvYnV0dG9uPlwiLCBwcm9wcyApXG5cdFx0XHRcdC5idXR0b24oIGJ1dHRvbk9wdGlvbnMgKVxuXHRcdFx0XHQuYXBwZW5kVG8oIHRoYXQudWlCdXR0b25TZXQgKVxuXHRcdFx0XHQub24oIFwiY2xpY2tcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRcdFx0Y2xpY2suYXBwbHkoIHRoYXQuZWxlbWVudFsgMCBdLCBhcmd1bWVudHMgKTtcblx0XHRcdFx0fSApO1xuXHRcdH0gKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy51aURpYWxvZywgXCJ1aS1kaWFsb2ctYnV0dG9uc1wiICk7XG5cdFx0dGhpcy51aURpYWxvZ0J1dHRvblBhbmUuYXBwZW5kVG8oIHRoaXMudWlEaWFsb2cgKTtcblx0fSxcblxuXHRfbWFrZURyYWdnYWJsZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblxuXHRcdGZ1bmN0aW9uIGZpbHRlcmVkVWkoIHVpICkge1xuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0cG9zaXRpb246IHVpLnBvc2l0aW9uLFxuXHRcdFx0XHRvZmZzZXQ6IHVpLm9mZnNldFxuXHRcdFx0fTtcblx0XHR9XG5cblx0XHR0aGlzLnVpRGlhbG9nLmRyYWdnYWJsZSgge1xuXHRcdFx0Y2FuY2VsOiBcIi51aS1kaWFsb2ctY29udGVudCwgLnVpLWRpYWxvZy10aXRsZWJhci1jbG9zZVwiLFxuXHRcdFx0aGFuZGxlOiBcIi51aS1kaWFsb2ctdGl0bGViYXJcIixcblx0XHRcdGNvbnRhaW5tZW50OiBcImRvY3VtZW50XCIsXG5cdFx0XHRzdGFydDogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoICQoIHRoaXMgKSwgXCJ1aS1kaWFsb2ctZHJhZ2dpbmdcIiApO1xuXHRcdFx0XHR0aGF0Ll9ibG9ja0ZyYW1lcygpO1xuXHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcImRyYWdTdGFydFwiLCBldmVudCwgZmlsdGVyZWRVaSggdWkgKSApO1xuXHRcdFx0fSxcblx0XHRcdGRyYWc6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwiZHJhZ1wiLCBldmVudCwgZmlsdGVyZWRVaSggdWkgKSApO1xuXHRcdFx0fSxcblx0XHRcdHN0b3A6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdHZhciBsZWZ0ID0gdWkub2Zmc2V0LmxlZnQgLSB0aGF0LmRvY3VtZW50LnNjcm9sbExlZnQoKSxcblx0XHRcdFx0XHR0b3AgPSB1aS5vZmZzZXQudG9wIC0gdGhhdC5kb2N1bWVudC5zY3JvbGxUb3AoKTtcblxuXHRcdFx0XHRvcHRpb25zLnBvc2l0aW9uID0ge1xuXHRcdFx0XHRcdG15OiBcImxlZnQgdG9wXCIsXG5cdFx0XHRcdFx0YXQ6IFwibGVmdFwiICsgKCBsZWZ0ID49IDAgPyBcIitcIiA6IFwiXCIgKSArIGxlZnQgKyBcIiBcIiArXG5cdFx0XHRcdFx0XHRcInRvcFwiICsgKCB0b3AgPj0gMCA/IFwiK1wiIDogXCJcIiApICsgdG9wLFxuXHRcdFx0XHRcdG9mOiB0aGF0LndpbmRvd1xuXHRcdFx0XHR9O1xuXHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggJCggdGhpcyApLCBcInVpLWRpYWxvZy1kcmFnZ2luZ1wiICk7XG5cdFx0XHRcdHRoYXQuX3VuYmxvY2tGcmFtZXMoKTtcblx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJkcmFnU3RvcFwiLCBldmVudCwgZmlsdGVyZWRVaSggdWkgKSApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblxuXHRfbWFrZVJlc2l6YWJsZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGhhbmRsZXMgPSBvcHRpb25zLnJlc2l6YWJsZSxcblxuXHRcdFx0Ly8gLnVpLXJlc2l6YWJsZSBoYXMgcG9zaXRpb246IHJlbGF0aXZlIGRlZmluZWQgaW4gdGhlIHN0eWxlc2hlZXRcblx0XHRcdC8vIGJ1dCBkaWFsb2dzIGhhdmUgdG8gdXNlIGFic29sdXRlIG9yIGZpeGVkIHBvc2l0aW9uaW5nXG5cdFx0XHRwb3NpdGlvbiA9IHRoaXMudWlEaWFsb2cuY3NzKCBcInBvc2l0aW9uXCIgKSxcblx0XHRcdHJlc2l6ZUhhbmRsZXMgPSB0eXBlb2YgaGFuZGxlcyA9PT0gXCJzdHJpbmdcIiA/XG5cdFx0XHRcdGhhbmRsZXMgOlxuXHRcdFx0XHRcIm4sZSxzLHcsc2Usc3csbmUsbndcIjtcblxuXHRcdGZ1bmN0aW9uIGZpbHRlcmVkVWkoIHVpICkge1xuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0b3JpZ2luYWxQb3NpdGlvbjogdWkub3JpZ2luYWxQb3NpdGlvbixcblx0XHRcdFx0b3JpZ2luYWxTaXplOiB1aS5vcmlnaW5hbFNpemUsXG5cdFx0XHRcdHBvc2l0aW9uOiB1aS5wb3NpdGlvbixcblx0XHRcdFx0c2l6ZTogdWkuc2l6ZVxuXHRcdFx0fTtcblx0XHR9XG5cblx0XHR0aGlzLnVpRGlhbG9nLnJlc2l6YWJsZSgge1xuXHRcdFx0Y2FuY2VsOiBcIi51aS1kaWFsb2ctY29udGVudFwiLFxuXHRcdFx0Y29udGFpbm1lbnQ6IFwiZG9jdW1lbnRcIixcblx0XHRcdGFsc29SZXNpemU6IHRoaXMuZWxlbWVudCxcblx0XHRcdG1heFdpZHRoOiBvcHRpb25zLm1heFdpZHRoLFxuXHRcdFx0bWF4SGVpZ2h0OiBvcHRpb25zLm1heEhlaWdodCxcblx0XHRcdG1pbldpZHRoOiBvcHRpb25zLm1pbldpZHRoLFxuXHRcdFx0bWluSGVpZ2h0OiB0aGlzLl9taW5IZWlnaHQoKSxcblx0XHRcdGhhbmRsZXM6IHJlc2l6ZUhhbmRsZXMsXG5cdFx0XHRzdGFydDogZnVuY3Rpb24oIGV2ZW50LCB1aSApIHtcblx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoICQoIHRoaXMgKSwgXCJ1aS1kaWFsb2ctcmVzaXppbmdcIiApO1xuXHRcdFx0XHR0aGF0Ll9ibG9ja0ZyYW1lcygpO1xuXHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInJlc2l6ZVN0YXJ0XCIsIGV2ZW50LCBmaWx0ZXJlZFVpKCB1aSApICk7XG5cdFx0XHR9LFxuXHRcdFx0cmVzaXplOiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInJlc2l6ZVwiLCBldmVudCwgZmlsdGVyZWRVaSggdWkgKSApO1xuXHRcdFx0fSxcblx0XHRcdHN0b3A6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdHZhciBvZmZzZXQgPSB0aGF0LnVpRGlhbG9nLm9mZnNldCgpLFxuXHRcdFx0XHRcdGxlZnQgPSBvZmZzZXQubGVmdCAtIHRoYXQuZG9jdW1lbnQuc2Nyb2xsTGVmdCgpLFxuXHRcdFx0XHRcdHRvcCA9IG9mZnNldC50b3AgLSB0aGF0LmRvY3VtZW50LnNjcm9sbFRvcCgpO1xuXG5cdFx0XHRcdG9wdGlvbnMuaGVpZ2h0ID0gdGhhdC51aURpYWxvZy5oZWlnaHQoKTtcblx0XHRcdFx0b3B0aW9ucy53aWR0aCA9IHRoYXQudWlEaWFsb2cud2lkdGgoKTtcblx0XHRcdFx0b3B0aW9ucy5wb3NpdGlvbiA9IHtcblx0XHRcdFx0XHRteTogXCJsZWZ0IHRvcFwiLFxuXHRcdFx0XHRcdGF0OiBcImxlZnRcIiArICggbGVmdCA+PSAwID8gXCIrXCIgOiBcIlwiICkgKyBsZWZ0ICsgXCIgXCIgK1xuXHRcdFx0XHRcdFx0XCJ0b3BcIiArICggdG9wID49IDAgPyBcIitcIiA6IFwiXCIgKSArIHRvcCxcblx0XHRcdFx0XHRvZjogdGhhdC53aW5kb3dcblx0XHRcdFx0fTtcblx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoICQoIHRoaXMgKSwgXCJ1aS1kaWFsb2ctcmVzaXppbmdcIiApO1xuXHRcdFx0XHR0aGF0Ll91bmJsb2NrRnJhbWVzKCk7XG5cdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwicmVzaXplU3RvcFwiLCBldmVudCwgZmlsdGVyZWRVaSggdWkgKSApO1xuXHRcdFx0fVxuXHRcdH0gKVxuXHRcdFx0LmNzcyggXCJwb3NpdGlvblwiLCBwb3NpdGlvbiApO1xuXHR9LFxuXG5cdF90cmFja0ZvY3VzOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9vbiggdGhpcy53aWRnZXQoKSwge1xuXHRcdFx0Zm9jdXNpbjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHR0aGlzLl9tYWtlRm9jdXNUYXJnZXQoKTtcblx0XHRcdFx0dGhpcy5fZm9jdXNlZEVsZW1lbnQgPSAkKCBldmVudC50YXJnZXQgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X21ha2VGb2N1c1RhcmdldDogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fdW50cmFja0luc3RhbmNlKCk7XG5cdFx0dGhpcy5fdHJhY2tpbmdJbnN0YW5jZXMoKS51bnNoaWZ0KCB0aGlzICk7XG5cdH0sXG5cblx0X3VudHJhY2tJbnN0YW5jZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGluc3RhbmNlcyA9IHRoaXMuX3RyYWNraW5nSW5zdGFuY2VzKCksXG5cdFx0XHRleGlzdHMgPSAkLmluQXJyYXkoIHRoaXMsIGluc3RhbmNlcyApO1xuXHRcdGlmICggZXhpc3RzICE9PSAtMSApIHtcblx0XHRcdGluc3RhbmNlcy5zcGxpY2UoIGV4aXN0cywgMSApO1xuXHRcdH1cblx0fSxcblxuXHRfdHJhY2tpbmdJbnN0YW5jZXM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpbnN0YW5jZXMgPSB0aGlzLmRvY3VtZW50LmRhdGEoIFwidWktZGlhbG9nLWluc3RhbmNlc1wiICk7XG5cdFx0aWYgKCAhaW5zdGFuY2VzICkge1xuXHRcdFx0aW5zdGFuY2VzID0gW107XG5cdFx0XHR0aGlzLmRvY3VtZW50LmRhdGEoIFwidWktZGlhbG9nLWluc3RhbmNlc1wiLCBpbnN0YW5jZXMgKTtcblx0XHR9XG5cdFx0cmV0dXJuIGluc3RhbmNlcztcblx0fSxcblxuXHRfbWluSGVpZ2h0OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblxuXHRcdHJldHVybiBvcHRpb25zLmhlaWdodCA9PT0gXCJhdXRvXCIgP1xuXHRcdFx0b3B0aW9ucy5taW5IZWlnaHQgOlxuXHRcdFx0TWF0aC5taW4oIG9wdGlvbnMubWluSGVpZ2h0LCBvcHRpb25zLmhlaWdodCApO1xuXHR9LFxuXG5cdF9wb3NpdGlvbjogZnVuY3Rpb24oKSB7XG5cblx0XHQvLyBOZWVkIHRvIHNob3cgdGhlIGRpYWxvZyB0byBnZXQgdGhlIGFjdHVhbCBvZmZzZXQgaW4gdGhlIHBvc2l0aW9uIHBsdWdpblxuXHRcdHZhciBpc1Zpc2libGUgPSB0aGlzLnVpRGlhbG9nLmlzKCBcIjp2aXNpYmxlXCIgKTtcblx0XHRpZiAoICFpc1Zpc2libGUgKSB7XG5cdFx0XHR0aGlzLnVpRGlhbG9nLnNob3coKTtcblx0XHR9XG5cdFx0dGhpcy51aURpYWxvZy5wb3NpdGlvbiggdGhpcy5vcHRpb25zLnBvc2l0aW9uICk7XG5cdFx0aWYgKCAhaXNWaXNpYmxlICkge1xuXHRcdFx0dGhpcy51aURpYWxvZy5oaWRlKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb25zOiBmdW5jdGlvbiggb3B0aW9ucyApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRyZXNpemUgPSBmYWxzZSxcblx0XHRcdHJlc2l6YWJsZU9wdGlvbnMgPSB7fTtcblxuXHRcdCQuZWFjaCggb3B0aW9ucywgZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0XHR0aGF0Ll9zZXRPcHRpb24oIGtleSwgdmFsdWUgKTtcblxuXHRcdFx0aWYgKCBrZXkgaW4gdGhhdC5zaXplUmVsYXRlZE9wdGlvbnMgKSB7XG5cdFx0XHRcdHJlc2l6ZSA9IHRydWU7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIGtleSBpbiB0aGF0LnJlc2l6YWJsZVJlbGF0ZWRPcHRpb25zICkge1xuXHRcdFx0XHRyZXNpemFibGVPcHRpb25zWyBrZXkgXSA9IHZhbHVlO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdGlmICggcmVzaXplICkge1xuXHRcdFx0dGhpcy5fc2l6ZSgpO1xuXHRcdFx0dGhpcy5fcG9zaXRpb24oKTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLnVpRGlhbG9nLmlzKCBcIjpkYXRhKHVpLXJlc2l6YWJsZSlcIiApICkge1xuXHRcdFx0dGhpcy51aURpYWxvZy5yZXNpemFibGUoIFwib3B0aW9uXCIsIHJlc2l6YWJsZU9wdGlvbnMgKTtcblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dmFyIGlzRHJhZ2dhYmxlLCBpc1Jlc2l6YWJsZSxcblx0XHRcdHVpRGlhbG9nID0gdGhpcy51aURpYWxvZztcblxuXHRcdGlmICgga2V5ID09PSBcImRpc2FibGVkXCIgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdGlmICgga2V5ID09PSBcImFwcGVuZFRvXCIgKSB7XG5cdFx0XHR0aGlzLnVpRGlhbG9nLmFwcGVuZFRvKCB0aGlzLl9hcHBlbmRUbygpICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwiYnV0dG9uc1wiICkge1xuXHRcdFx0dGhpcy5fY3JlYXRlQnV0dG9ucygpO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcImNsb3NlVGV4dFwiICkge1xuXHRcdFx0dGhpcy51aURpYWxvZ1RpdGxlYmFyQ2xvc2UuYnV0dG9uKCB7XG5cblx0XHRcdFx0Ly8gRW5zdXJlIHRoYXQgd2UgYWx3YXlzIHBhc3MgYSBzdHJpbmdcblx0XHRcdFx0bGFiZWw6ICQoIFwiPGE+XCIgKS50ZXh0KCBcIlwiICsgdGhpcy5vcHRpb25zLmNsb3NlVGV4dCApLmh0bWwoKVxuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcImRyYWdnYWJsZVwiICkge1xuXHRcdFx0aXNEcmFnZ2FibGUgPSB1aURpYWxvZy5pcyggXCI6ZGF0YSh1aS1kcmFnZ2FibGUpXCIgKTtcblx0XHRcdGlmICggaXNEcmFnZ2FibGUgJiYgIXZhbHVlICkge1xuXHRcdFx0XHR1aURpYWxvZy5kcmFnZ2FibGUoIFwiZGVzdHJveVwiICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggIWlzRHJhZ2dhYmxlICYmIHZhbHVlICkge1xuXHRcdFx0XHR0aGlzLl9tYWtlRHJhZ2dhYmxlKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwicG9zaXRpb25cIiApIHtcblx0XHRcdHRoaXMuX3Bvc2l0aW9uKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwicmVzaXphYmxlXCIgKSB7XG5cblx0XHRcdC8vIGN1cnJlbnRseSByZXNpemFibGUsIGJlY29taW5nIG5vbi1yZXNpemFibGVcblx0XHRcdGlzUmVzaXphYmxlID0gdWlEaWFsb2cuaXMoIFwiOmRhdGEodWktcmVzaXphYmxlKVwiICk7XG5cdFx0XHRpZiAoIGlzUmVzaXphYmxlICYmICF2YWx1ZSApIHtcblx0XHRcdFx0dWlEaWFsb2cucmVzaXphYmxlKCBcImRlc3Ryb3lcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDdXJyZW50bHkgcmVzaXphYmxlLCBjaGFuZ2luZyBoYW5kbGVzXG5cdFx0XHRpZiAoIGlzUmVzaXphYmxlICYmIHR5cGVvZiB2YWx1ZSA9PT0gXCJzdHJpbmdcIiApIHtcblx0XHRcdFx0dWlEaWFsb2cucmVzaXphYmxlKCBcIm9wdGlvblwiLCBcImhhbmRsZXNcIiwgdmFsdWUgKTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ3VycmVudGx5IG5vbi1yZXNpemFibGUsIGJlY29taW5nIHJlc2l6YWJsZVxuXHRcdFx0aWYgKCAhaXNSZXNpemFibGUgJiYgdmFsdWUgIT09IGZhbHNlICkge1xuXHRcdFx0XHR0aGlzLl9tYWtlUmVzaXphYmxlKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwidGl0bGVcIiApIHtcblx0XHRcdHRoaXMuX3RpdGxlKCB0aGlzLnVpRGlhbG9nVGl0bGViYXIuZmluZCggXCIudWktZGlhbG9nLXRpdGxlXCIgKSApO1xuXHRcdH1cblx0fSxcblxuXHRfc2l6ZTogZnVuY3Rpb24oKSB7XG5cblx0XHQvLyBJZiB0aGUgdXNlciBoYXMgcmVzaXplZCB0aGUgZGlhbG9nLCB0aGUgLnVpLWRpYWxvZyBhbmQgLnVpLWRpYWxvZy1jb250ZW50XG5cdFx0Ly8gZGl2cyB3aWxsIGJvdGggaGF2ZSB3aWR0aCBhbmQgaGVpZ2h0IHNldCwgc28gd2UgbmVlZCB0byByZXNldCB0aGVtXG5cdFx0dmFyIG5vbkNvbnRlbnRIZWlnaHQsIG1pbkNvbnRlbnRIZWlnaHQsIG1heENvbnRlbnRIZWlnaHQsXG5cdFx0XHRvcHRpb25zID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0Ly8gUmVzZXQgY29udGVudCBzaXppbmdcblx0XHR0aGlzLmVsZW1lbnQuc2hvdygpLmNzcygge1xuXHRcdFx0d2lkdGg6IFwiYXV0b1wiLFxuXHRcdFx0bWluSGVpZ2h0OiAwLFxuXHRcdFx0bWF4SGVpZ2h0OiBcIm5vbmVcIixcblx0XHRcdGhlaWdodDogMFxuXHRcdH0gKTtcblxuXHRcdGlmICggb3B0aW9ucy5taW5XaWR0aCA+IG9wdGlvbnMud2lkdGggKSB7XG5cdFx0XHRvcHRpb25zLndpZHRoID0gb3B0aW9ucy5taW5XaWR0aDtcblx0XHR9XG5cblx0XHQvLyBSZXNldCB3cmFwcGVyIHNpemluZ1xuXHRcdC8vIGRldGVybWluZSB0aGUgaGVpZ2h0IG9mIGFsbCB0aGUgbm9uLWNvbnRlbnQgZWxlbWVudHNcblx0XHRub25Db250ZW50SGVpZ2h0ID0gdGhpcy51aURpYWxvZy5jc3MoIHtcblx0XHRcdGhlaWdodDogXCJhdXRvXCIsXG5cdFx0XHR3aWR0aDogb3B0aW9ucy53aWR0aFxuXHRcdH0gKVxuXHRcdFx0Lm91dGVySGVpZ2h0KCk7XG5cdFx0bWluQ29udGVudEhlaWdodCA9IE1hdGgubWF4KCAwLCBvcHRpb25zLm1pbkhlaWdodCAtIG5vbkNvbnRlbnRIZWlnaHQgKTtcblx0XHRtYXhDb250ZW50SGVpZ2h0ID0gdHlwZW9mIG9wdGlvbnMubWF4SGVpZ2h0ID09PSBcIm51bWJlclwiID9cblx0XHRcdE1hdGgubWF4KCAwLCBvcHRpb25zLm1heEhlaWdodCAtIG5vbkNvbnRlbnRIZWlnaHQgKSA6XG5cdFx0XHRcIm5vbmVcIjtcblxuXHRcdGlmICggb3B0aW9ucy5oZWlnaHQgPT09IFwiYXV0b1wiICkge1xuXHRcdFx0dGhpcy5lbGVtZW50LmNzcygge1xuXHRcdFx0XHRtaW5IZWlnaHQ6IG1pbkNvbnRlbnRIZWlnaHQsXG5cdFx0XHRcdG1heEhlaWdodDogbWF4Q29udGVudEhlaWdodCxcblx0XHRcdFx0aGVpZ2h0OiBcImF1dG9cIlxuXHRcdFx0fSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmVsZW1lbnQuaGVpZ2h0KCBNYXRoLm1heCggMCwgb3B0aW9ucy5oZWlnaHQgLSBub25Db250ZW50SGVpZ2h0ICkgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMudWlEaWFsb2cuaXMoIFwiOmRhdGEodWktcmVzaXphYmxlKVwiICkgKSB7XG5cdFx0XHR0aGlzLnVpRGlhbG9nLnJlc2l6YWJsZSggXCJvcHRpb25cIiwgXCJtaW5IZWlnaHRcIiwgdGhpcy5fbWluSGVpZ2h0KCkgKTtcblx0XHR9XG5cdH0sXG5cblx0X2Jsb2NrRnJhbWVzOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmlmcmFtZUJsb2NrcyA9IHRoaXMuZG9jdW1lbnQuZmluZCggXCJpZnJhbWVcIiApLm1hcCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgaWZyYW1lID0gJCggdGhpcyApO1xuXG5cdFx0XHRyZXR1cm4gJCggXCI8ZGl2PlwiIClcblx0XHRcdFx0LmNzcygge1xuXHRcdFx0XHRcdHBvc2l0aW9uOiBcImFic29sdXRlXCIsXG5cdFx0XHRcdFx0d2lkdGg6IGlmcmFtZS5vdXRlcldpZHRoKCksXG5cdFx0XHRcdFx0aGVpZ2h0OiBpZnJhbWUub3V0ZXJIZWlnaHQoKVxuXHRcdFx0XHR9IClcblx0XHRcdFx0LmFwcGVuZFRvKCBpZnJhbWUucGFyZW50KCkgKVxuXHRcdFx0XHQub2Zmc2V0KCBpZnJhbWUub2Zmc2V0KCkgKVsgMCBdO1xuXHRcdH0gKTtcblx0fSxcblxuXHRfdW5ibG9ja0ZyYW1lczogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCB0aGlzLmlmcmFtZUJsb2NrcyApIHtcblx0XHRcdHRoaXMuaWZyYW1lQmxvY2tzLnJlbW92ZSgpO1xuXHRcdFx0ZGVsZXRlIHRoaXMuaWZyYW1lQmxvY2tzO1xuXHRcdH1cblx0fSxcblxuXHRfYWxsb3dJbnRlcmFjdGlvbjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdGlmICggJCggZXZlbnQudGFyZ2V0ICkuY2xvc2VzdCggXCIudWktZGlhbG9nXCIgKS5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cblx0XHQvLyBUT0RPOiBSZW1vdmUgaGFjayB3aGVuIGRhdGVwaWNrZXIgaW1wbGVtZW50c1xuXHRcdC8vIHRoZSAudWktZnJvbnQgbG9naWMgKCM4OTg5KVxuXHRcdHJldHVybiAhISQoIGV2ZW50LnRhcmdldCApLmNsb3Nlc3QoIFwiLnVpLWRhdGVwaWNrZXJcIiApLmxlbmd0aDtcblx0fSxcblxuXHRfY3JlYXRlT3ZlcmxheTogZnVuY3Rpb24oKSB7XG5cdFx0aWYgKCAhdGhpcy5vcHRpb25zLm1vZGFsICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIFdlIHVzZSBhIGRlbGF5IGluIGNhc2UgdGhlIG92ZXJsYXkgaXMgY3JlYXRlZCBmcm9tIGFuXG5cdFx0Ly8gZXZlbnQgdGhhdCB3ZSdyZSBnb2luZyB0byBiZSBjYW5jZWxsaW5nICgjMjgwNClcblx0XHR2YXIgaXNPcGVuaW5nID0gdHJ1ZTtcblx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRpc09wZW5pbmcgPSBmYWxzZTtcblx0XHR9ICk7XG5cblx0XHRpZiAoICF0aGlzLmRvY3VtZW50LmRhdGEoIFwidWktZGlhbG9nLW92ZXJsYXlzXCIgKSApIHtcblxuXHRcdFx0Ly8gUHJldmVudCB1c2Ugb2YgYW5jaG9ycyBhbmQgaW5wdXRzXG5cdFx0XHQvLyBVc2luZyBfb24oKSBmb3IgYW4gZXZlbnQgaGFuZGxlciBzaGFyZWQgYWNyb3NzIG1hbnkgaW5zdGFuY2VzIGlzXG5cdFx0XHQvLyBzYWZlIGJlY2F1c2UgdGhlIGRpYWxvZ3Mgc3RhY2sgYW5kIG11c3QgYmUgY2xvc2VkIGluIHJldmVyc2Ugb3JkZXJcblx0XHRcdHRoaXMuX29uKCB0aGlzLmRvY3VtZW50LCB7XG5cdFx0XHRcdGZvY3VzaW46IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0XHRpZiAoIGlzT3BlbmluZyApIHtcblx0XHRcdFx0XHRcdHJldHVybjtcblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoICF0aGlzLl9hbGxvd0ludGVyYWN0aW9uKCBldmVudCApICkge1xuXHRcdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0XHRcdHRoaXMuX3RyYWNraW5nSW5zdGFuY2VzKClbIDAgXS5fZm9jdXNUYWJiYWJsZSgpO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdHRoaXMub3ZlcmxheSA9ICQoIFwiPGRpdj5cIiApXG5cdFx0XHQuYXBwZW5kVG8oIHRoaXMuX2FwcGVuZFRvKCkgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLm92ZXJsYXksIG51bGwsIFwidWktd2lkZ2V0LW92ZXJsYXkgdWktZnJvbnRcIiApO1xuXHRcdHRoaXMuX29uKCB0aGlzLm92ZXJsYXksIHtcblx0XHRcdG1vdXNlZG93bjogXCJfa2VlcEZvY3VzXCJcblx0XHR9ICk7XG5cdFx0dGhpcy5kb2N1bWVudC5kYXRhKCBcInVpLWRpYWxvZy1vdmVybGF5c1wiLFxuXHRcdFx0KCB0aGlzLmRvY3VtZW50LmRhdGEoIFwidWktZGlhbG9nLW92ZXJsYXlzXCIgKSB8fCAwICkgKyAxICk7XG5cdH0sXG5cblx0X2Rlc3Ryb3lPdmVybGF5OiBmdW5jdGlvbigpIHtcblx0XHRpZiAoICF0aGlzLm9wdGlvbnMubW9kYWwgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm92ZXJsYXkgKSB7XG5cdFx0XHR2YXIgb3ZlcmxheXMgPSB0aGlzLmRvY3VtZW50LmRhdGEoIFwidWktZGlhbG9nLW92ZXJsYXlzXCIgKSAtIDE7XG5cblx0XHRcdGlmICggIW92ZXJsYXlzICkge1xuXHRcdFx0XHR0aGlzLl9vZmYoIHRoaXMuZG9jdW1lbnQsIFwiZm9jdXNpblwiICk7XG5cdFx0XHRcdHRoaXMuZG9jdW1lbnQucmVtb3ZlRGF0YSggXCJ1aS1kaWFsb2ctb3ZlcmxheXNcIiApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5kb2N1bWVudC5kYXRhKCBcInVpLWRpYWxvZy1vdmVybGF5c1wiLCBvdmVybGF5cyApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLm92ZXJsYXkucmVtb3ZlKCk7XG5cdFx0XHR0aGlzLm92ZXJsYXkgPSBudWxsO1xuXHRcdH1cblx0fVxufSApO1xuXG4vLyBERVBSRUNBVEVEXG4vLyBUT0RPOiBzd2l0Y2ggcmV0dXJuIGJhY2sgdG8gd2lkZ2V0IGRlY2xhcmF0aW9uIGF0IHRvcCBvZiBmaWxlIHdoZW4gdGhpcyBpcyByZW1vdmVkXG5pZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSApIHtcblxuXHQvLyBCYWNrY29tcGF0IGZvciBkaWFsb2dDbGFzcyBvcHRpb25cblx0JC53aWRnZXQoIFwidWkuZGlhbG9nXCIsICQudWkuZGlhbG9nLCB7XG5cdFx0b3B0aW9uczoge1xuXHRcdFx0ZGlhbG9nQ2xhc3M6IFwiXCJcblx0XHR9LFxuXHRcdF9jcmVhdGVXcmFwcGVyOiBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuX3N1cGVyKCk7XG5cdFx0XHR0aGlzLnVpRGlhbG9nLmFkZENsYXNzKCB0aGlzLm9wdGlvbnMuZGlhbG9nQ2xhc3MgKTtcblx0XHR9LFxuXHRcdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdFx0aWYgKCBrZXkgPT09IFwiZGlhbG9nQ2xhc3NcIiApIHtcblx0XHRcdFx0dGhpcy51aURpYWxvZ1xuXHRcdFx0XHRcdC5yZW1vdmVDbGFzcyggdGhpcy5vcHRpb25zLmRpYWxvZ0NsYXNzIClcblx0XHRcdFx0XHQuYWRkQ2xhc3MoIHZhbHVlICk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9zdXBlckFwcGx5KCBhcmd1bWVudHMgKTtcblx0XHR9XG5cdH0gKTtcbn1cblxudmFyIHdpZGdldHNEaWFsb2cgPSAkLnVpLmRpYWxvZztcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBEcm9wcGFibGUgMS4xMi4xXG4gKiBodHRwOi8vanF1ZXJ5dWkuY29tXG4gKlxuICogQ29weXJpZ2h0IGpRdWVyeSBGb3VuZGF0aW9uIGFuZCBvdGhlciBjb250cmlidXRvcnNcbiAqIFJlbGVhc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZS5cbiAqIGh0dHA6Ly9qcXVlcnkub3JnL2xpY2Vuc2VcbiAqL1xuXG4vLz4+bGFiZWw6IERyb3BwYWJsZVxuLy8+Pmdyb3VwOiBJbnRlcmFjdGlvbnNcbi8vPj5kZXNjcmlwdGlvbjogRW5hYmxlcyBkcm9wIHRhcmdldHMgZm9yIGRyYWdnYWJsZSBlbGVtZW50cy5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9kcm9wcGFibGUvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vZHJvcHBhYmxlL1xuXG5cblxuJC53aWRnZXQoIFwidWkuZHJvcHBhYmxlXCIsIHtcblx0dmVyc2lvbjogXCIxLjEyLjFcIixcblx0d2lkZ2V0RXZlbnRQcmVmaXg6IFwiZHJvcFwiLFxuXHRvcHRpb25zOiB7XG5cdFx0YWNjZXB0OiBcIipcIixcblx0XHRhZGRDbGFzc2VzOiB0cnVlLFxuXHRcdGdyZWVkeTogZmFsc2UsXG5cdFx0c2NvcGU6IFwiZGVmYXVsdFwiLFxuXHRcdHRvbGVyYW5jZTogXCJpbnRlcnNlY3RcIixcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGFjdGl2YXRlOiBudWxsLFxuXHRcdGRlYWN0aXZhdGU6IG51bGwsXG5cdFx0ZHJvcDogbnVsbCxcblx0XHRvdXQ6IG51bGwsXG5cdFx0b3ZlcjogbnVsbFxuXHR9LFxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblxuXHRcdHZhciBwcm9wb3J0aW9ucyxcblx0XHRcdG8gPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRhY2NlcHQgPSBvLmFjY2VwdDtcblxuXHRcdHRoaXMuaXNvdmVyID0gZmFsc2U7XG5cdFx0dGhpcy5pc291dCA9IHRydWU7XG5cblx0XHR0aGlzLmFjY2VwdCA9ICQuaXNGdW5jdGlvbiggYWNjZXB0ICkgPyBhY2NlcHQgOiBmdW5jdGlvbiggZCApIHtcblx0XHRcdHJldHVybiBkLmlzKCBhY2NlcHQgKTtcblx0XHR9O1xuXG5cdFx0dGhpcy5wcm9wb3J0aW9ucyA9IGZ1bmN0aW9uKCAvKiB2YWx1ZVRvV3JpdGUgKi8gKSB7XG5cdFx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggKSB7XG5cblx0XHRcdFx0Ly8gU3RvcmUgdGhlIGRyb3BwYWJsZSdzIHByb3BvcnRpb25zXG5cdFx0XHRcdHByb3BvcnRpb25zID0gYXJndW1lbnRzWyAwIF07XG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIFJldHJpZXZlIG9yIGRlcml2ZSB0aGUgZHJvcHBhYmxlJ3MgcHJvcG9ydGlvbnNcblx0XHRcdFx0cmV0dXJuIHByb3BvcnRpb25zID9cblx0XHRcdFx0XHRwcm9wb3J0aW9ucyA6XG5cdFx0XHRcdFx0cHJvcG9ydGlvbnMgPSB7XG5cdFx0XHRcdFx0XHR3aWR0aDogdGhpcy5lbGVtZW50WyAwIF0ub2Zmc2V0V2lkdGgsXG5cdFx0XHRcdFx0XHRoZWlnaHQ6IHRoaXMuZWxlbWVudFsgMCBdLm9mZnNldEhlaWdodFxuXHRcdFx0XHRcdH07XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdHRoaXMuX2FkZFRvTWFuYWdlciggby5zY29wZSApO1xuXG5cdFx0by5hZGRDbGFzc2VzICYmIHRoaXMuX2FkZENsYXNzKCBcInVpLWRyb3BwYWJsZVwiICk7XG5cblx0fSxcblxuXHRfYWRkVG9NYW5hZ2VyOiBmdW5jdGlvbiggc2NvcGUgKSB7XG5cblx0XHQvLyBBZGQgdGhlIHJlZmVyZW5jZSBhbmQgcG9zaXRpb25zIHRvIHRoZSBtYW5hZ2VyXG5cdFx0JC51aS5kZG1hbmFnZXIuZHJvcHBhYmxlc1sgc2NvcGUgXSA9ICQudWkuZGRtYW5hZ2VyLmRyb3BwYWJsZXNbIHNjb3BlIF0gfHwgW107XG5cdFx0JC51aS5kZG1hbmFnZXIuZHJvcHBhYmxlc1sgc2NvcGUgXS5wdXNoKCB0aGlzICk7XG5cdH0sXG5cblx0X3NwbGljZTogZnVuY3Rpb24oIGRyb3AgKSB7XG5cdFx0dmFyIGkgPSAwO1xuXHRcdGZvciAoIDsgaSA8IGRyb3AubGVuZ3RoOyBpKysgKSB7XG5cdFx0XHRpZiAoIGRyb3BbIGkgXSA9PT0gdGhpcyApIHtcblx0XHRcdFx0ZHJvcC5zcGxpY2UoIGksIDEgKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBkcm9wID0gJC51aS5kZG1hbmFnZXIuZHJvcHBhYmxlc1sgdGhpcy5vcHRpb25zLnNjb3BlIF07XG5cblx0XHR0aGlzLl9zcGxpY2UoIGRyb3AgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblxuXHRcdGlmICgga2V5ID09PSBcImFjY2VwdFwiICkge1xuXHRcdFx0dGhpcy5hY2NlcHQgPSAkLmlzRnVuY3Rpb24oIHZhbHVlICkgPyB2YWx1ZSA6IGZ1bmN0aW9uKCBkICkge1xuXHRcdFx0XHRyZXR1cm4gZC5pcyggdmFsdWUgKTtcblx0XHRcdH07XG5cdFx0fSBlbHNlIGlmICgga2V5ID09PSBcInNjb3BlXCIgKSB7XG5cdFx0XHR2YXIgZHJvcCA9ICQudWkuZGRtYW5hZ2VyLmRyb3BwYWJsZXNbIHRoaXMub3B0aW9ucy5zY29wZSBdO1xuXG5cdFx0XHR0aGlzLl9zcGxpY2UoIGRyb3AgKTtcblx0XHRcdHRoaXMuX2FkZFRvTWFuYWdlciggdmFsdWUgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXHR9LFxuXG5cdF9hY3RpdmF0ZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBkcmFnZ2FibGUgPSAkLnVpLmRkbWFuYWdlci5jdXJyZW50O1xuXG5cdFx0dGhpcy5fYWRkQWN0aXZlQ2xhc3MoKTtcblx0XHRpZiAoIGRyYWdnYWJsZSApIHtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiYWN0aXZhdGVcIiwgZXZlbnQsIHRoaXMudWkoIGRyYWdnYWJsZSApICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9kZWFjdGl2YXRlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGRyYWdnYWJsZSA9ICQudWkuZGRtYW5hZ2VyLmN1cnJlbnQ7XG5cblx0XHR0aGlzLl9yZW1vdmVBY3RpdmVDbGFzcygpO1xuXHRcdGlmICggZHJhZ2dhYmxlICkge1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJkZWFjdGl2YXRlXCIsIGV2ZW50LCB0aGlzLnVpKCBkcmFnZ2FibGUgKSApO1xuXHRcdH1cblx0fSxcblxuXHRfb3ZlcjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dmFyIGRyYWdnYWJsZSA9ICQudWkuZGRtYW5hZ2VyLmN1cnJlbnQ7XG5cblx0XHQvLyBCYWlsIGlmIGRyYWdnYWJsZSBhbmQgZHJvcHBhYmxlIGFyZSBzYW1lIGVsZW1lbnRcblx0XHRpZiAoICFkcmFnZ2FibGUgfHwgKCBkcmFnZ2FibGUuY3VycmVudEl0ZW0gfHxcblx0XHRcdFx0ZHJhZ2dhYmxlLmVsZW1lbnQgKVsgMCBdID09PSB0aGlzLmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuYWNjZXB0LmNhbGwoIHRoaXMuZWxlbWVudFsgMCBdLCAoIGRyYWdnYWJsZS5jdXJyZW50SXRlbSB8fFxuXHRcdFx0XHRkcmFnZ2FibGUuZWxlbWVudCApICkgKSB7XG5cdFx0XHR0aGlzLl9hZGRIb3ZlckNsYXNzKCk7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcIm92ZXJcIiwgZXZlbnQsIHRoaXMudWkoIGRyYWdnYWJsZSApICk7XG5cdFx0fVxuXG5cdH0sXG5cblx0X291dDogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dmFyIGRyYWdnYWJsZSA9ICQudWkuZGRtYW5hZ2VyLmN1cnJlbnQ7XG5cblx0XHQvLyBCYWlsIGlmIGRyYWdnYWJsZSBhbmQgZHJvcHBhYmxlIGFyZSBzYW1lIGVsZW1lbnRcblx0XHRpZiAoICFkcmFnZ2FibGUgfHwgKCBkcmFnZ2FibGUuY3VycmVudEl0ZW0gfHxcblx0XHRcdFx0ZHJhZ2dhYmxlLmVsZW1lbnQgKVsgMCBdID09PSB0aGlzLmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuYWNjZXB0LmNhbGwoIHRoaXMuZWxlbWVudFsgMCBdLCAoIGRyYWdnYWJsZS5jdXJyZW50SXRlbSB8fFxuXHRcdFx0XHRkcmFnZ2FibGUuZWxlbWVudCApICkgKSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVIb3ZlckNsYXNzKCk7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcIm91dFwiLCBldmVudCwgdGhpcy51aSggZHJhZ2dhYmxlICkgKTtcblx0XHR9XG5cblx0fSxcblxuXHRfZHJvcDogZnVuY3Rpb24oIGV2ZW50LCBjdXN0b20gKSB7XG5cblx0XHR2YXIgZHJhZ2dhYmxlID0gY3VzdG9tIHx8ICQudWkuZGRtYW5hZ2VyLmN1cnJlbnQsXG5cdFx0XHRjaGlsZHJlbkludGVyc2VjdGlvbiA9IGZhbHNlO1xuXG5cdFx0Ly8gQmFpbCBpZiBkcmFnZ2FibGUgYW5kIGRyb3BwYWJsZSBhcmUgc2FtZSBlbGVtZW50XG5cdFx0aWYgKCAhZHJhZ2dhYmxlIHx8ICggZHJhZ2dhYmxlLmN1cnJlbnRJdGVtIHx8XG5cdFx0XHRcdGRyYWdnYWJsZS5lbGVtZW50IClbIDAgXSA9PT0gdGhpcy5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0dGhpcy5lbGVtZW50XG5cdFx0XHQuZmluZCggXCI6ZGF0YSh1aS1kcm9wcGFibGUpXCIgKVxuXHRcdFx0Lm5vdCggXCIudWktZHJhZ2dhYmxlLWRyYWdnaW5nXCIgKVxuXHRcdFx0LmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR2YXIgaW5zdCA9ICQoIHRoaXMgKS5kcm9wcGFibGUoIFwiaW5zdGFuY2VcIiApO1xuXHRcdFx0XHRpZiAoXG5cdFx0XHRcdFx0aW5zdC5vcHRpb25zLmdyZWVkeSAmJlxuXHRcdFx0XHRcdCFpbnN0Lm9wdGlvbnMuZGlzYWJsZWQgJiZcblx0XHRcdFx0XHRpbnN0Lm9wdGlvbnMuc2NvcGUgPT09IGRyYWdnYWJsZS5vcHRpb25zLnNjb3BlICYmXG5cdFx0XHRcdFx0aW5zdC5hY2NlcHQuY2FsbChcblx0XHRcdFx0XHRcdGluc3QuZWxlbWVudFsgMCBdLCAoIGRyYWdnYWJsZS5jdXJyZW50SXRlbSB8fCBkcmFnZ2FibGUuZWxlbWVudCApXG5cdFx0XHRcdFx0KSAmJlxuXHRcdFx0XHRcdGludGVyc2VjdChcblx0XHRcdFx0XHRcdGRyYWdnYWJsZSxcblx0XHRcdFx0XHRcdCQuZXh0ZW5kKCBpbnN0LCB7IG9mZnNldDogaW5zdC5lbGVtZW50Lm9mZnNldCgpIH0gKSxcblx0XHRcdFx0XHRcdGluc3Qub3B0aW9ucy50b2xlcmFuY2UsIGV2ZW50XG5cdFx0XHRcdFx0KVxuXHRcdFx0XHQpIHtcblx0XHRcdFx0XHRjaGlsZHJlbkludGVyc2VjdGlvbiA9IHRydWU7XG5cdFx0XHRcdFx0cmV0dXJuIGZhbHNlOyB9XG5cdFx0XHR9ICk7XG5cdFx0aWYgKCBjaGlsZHJlbkludGVyc2VjdGlvbiApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuYWNjZXB0LmNhbGwoIHRoaXMuZWxlbWVudFsgMCBdLFxuXHRcdFx0XHQoIGRyYWdnYWJsZS5jdXJyZW50SXRlbSB8fCBkcmFnZ2FibGUuZWxlbWVudCApICkgKSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVBY3RpdmVDbGFzcygpO1xuXHRcdFx0dGhpcy5fcmVtb3ZlSG92ZXJDbGFzcygpO1xuXG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImRyb3BcIiwgZXZlbnQsIHRoaXMudWkoIGRyYWdnYWJsZSApICk7XG5cdFx0XHRyZXR1cm4gdGhpcy5lbGVtZW50O1xuXHRcdH1cblxuXHRcdHJldHVybiBmYWxzZTtcblxuXHR9LFxuXG5cdHVpOiBmdW5jdGlvbiggYyApIHtcblx0XHRyZXR1cm4ge1xuXHRcdFx0ZHJhZ2dhYmxlOiAoIGMuY3VycmVudEl0ZW0gfHwgYy5lbGVtZW50ICksXG5cdFx0XHRoZWxwZXI6IGMuaGVscGVyLFxuXHRcdFx0cG9zaXRpb246IGMucG9zaXRpb24sXG5cdFx0XHRvZmZzZXQ6IGMucG9zaXRpb25BYnNcblx0XHR9O1xuXHR9LFxuXG5cdC8vIEV4dGVuc2lvbiBwb2ludHMganVzdCB0byBtYWtlIGJhY2tjb21wYXQgc2FuZSBhbmQgYXZvaWQgZHVwbGljYXRpbmcgbG9naWNcblx0Ly8gVE9ETzogUmVtb3ZlIGluIDEuMTMgYWxvbmcgd2l0aCBjYWxsIHRvIGl0IGJlbG93XG5cdF9hZGRIb3ZlckNsYXNzOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1kcm9wcGFibGUtaG92ZXJcIiApO1xuXHR9LFxuXG5cdF9yZW1vdmVIb3ZlckNsYXNzOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggXCJ1aS1kcm9wcGFibGUtaG92ZXJcIiApO1xuXHR9LFxuXG5cdF9hZGRBY3RpdmVDbGFzczogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktZHJvcHBhYmxlLWFjdGl2ZVwiICk7XG5cdH0sXG5cblx0X3JlbW92ZUFjdGl2ZUNsYXNzOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggXCJ1aS1kcm9wcGFibGUtYWN0aXZlXCIgKTtcblx0fVxufSApO1xuXG52YXIgaW50ZXJzZWN0ID0gJC51aS5pbnRlcnNlY3QgPSAoIGZ1bmN0aW9uKCkge1xuXHRmdW5jdGlvbiBpc092ZXJBeGlzKCB4LCByZWZlcmVuY2UsIHNpemUgKSB7XG5cdFx0cmV0dXJuICggeCA+PSByZWZlcmVuY2UgKSAmJiAoIHggPCAoIHJlZmVyZW5jZSArIHNpemUgKSApO1xuXHR9XG5cblx0cmV0dXJuIGZ1bmN0aW9uKCBkcmFnZ2FibGUsIGRyb3BwYWJsZSwgdG9sZXJhbmNlTW9kZSwgZXZlbnQgKSB7XG5cblx0XHRpZiAoICFkcm9wcGFibGUub2Zmc2V0ICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHZhciB4MSA9ICggZHJhZ2dhYmxlLnBvc2l0aW9uQWJzIHx8XG5cdFx0XHRcdGRyYWdnYWJsZS5wb3NpdGlvbi5hYnNvbHV0ZSApLmxlZnQgKyBkcmFnZ2FibGUubWFyZ2lucy5sZWZ0LFxuXHRcdFx0eTEgPSAoIGRyYWdnYWJsZS5wb3NpdGlvbkFicyB8fFxuXHRcdFx0XHRkcmFnZ2FibGUucG9zaXRpb24uYWJzb2x1dGUgKS50b3AgKyBkcmFnZ2FibGUubWFyZ2lucy50b3AsXG5cdFx0XHR4MiA9IHgxICsgZHJhZ2dhYmxlLmhlbHBlclByb3BvcnRpb25zLndpZHRoLFxuXHRcdFx0eTIgPSB5MSArIGRyYWdnYWJsZS5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQsXG5cdFx0XHRsID0gZHJvcHBhYmxlLm9mZnNldC5sZWZ0LFxuXHRcdFx0dCA9IGRyb3BwYWJsZS5vZmZzZXQudG9wLFxuXHRcdFx0ciA9IGwgKyBkcm9wcGFibGUucHJvcG9ydGlvbnMoKS53aWR0aCxcblx0XHRcdGIgPSB0ICsgZHJvcHBhYmxlLnByb3BvcnRpb25zKCkuaGVpZ2h0O1xuXG5cdFx0c3dpdGNoICggdG9sZXJhbmNlTW9kZSApIHtcblx0XHRjYXNlIFwiZml0XCI6XG5cdFx0XHRyZXR1cm4gKCBsIDw9IHgxICYmIHgyIDw9IHIgJiYgdCA8PSB5MSAmJiB5MiA8PSBiICk7XG5cdFx0Y2FzZSBcImludGVyc2VjdFwiOlxuXHRcdFx0cmV0dXJuICggbCA8IHgxICsgKCBkcmFnZ2FibGUuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLyAyICkgJiYgLy8gUmlnaHQgSGFsZlxuXHRcdFx0XHR4MiAtICggZHJhZ2dhYmxlLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC8gMiApIDwgciAmJiAvLyBMZWZ0IEhhbGZcblx0XHRcdFx0dCA8IHkxICsgKCBkcmFnZ2FibGUuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC8gMiApICYmIC8vIEJvdHRvbSBIYWxmXG5cdFx0XHRcdHkyIC0gKCBkcmFnZ2FibGUuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC8gMiApIDwgYiApOyAvLyBUb3AgSGFsZlxuXHRcdGNhc2UgXCJwb2ludGVyXCI6XG5cdFx0XHRyZXR1cm4gaXNPdmVyQXhpcyggZXZlbnQucGFnZVksIHQsIGRyb3BwYWJsZS5wcm9wb3J0aW9ucygpLmhlaWdodCApICYmXG5cdFx0XHRcdGlzT3ZlckF4aXMoIGV2ZW50LnBhZ2VYLCBsLCBkcm9wcGFibGUucHJvcG9ydGlvbnMoKS53aWR0aCApO1xuXHRcdGNhc2UgXCJ0b3VjaFwiOlxuXHRcdFx0cmV0dXJuIChcblx0XHRcdFx0KCB5MSA+PSB0ICYmIHkxIDw9IGIgKSB8fCAvLyBUb3AgZWRnZSB0b3VjaGluZ1xuXHRcdFx0XHQoIHkyID49IHQgJiYgeTIgPD0gYiApIHx8IC8vIEJvdHRvbSBlZGdlIHRvdWNoaW5nXG5cdFx0XHRcdCggeTEgPCB0ICYmIHkyID4gYiApIC8vIFN1cnJvdW5kZWQgdmVydGljYWxseVxuXHRcdFx0KSAmJiAoXG5cdFx0XHRcdCggeDEgPj0gbCAmJiB4MSA8PSByICkgfHwgLy8gTGVmdCBlZGdlIHRvdWNoaW5nXG5cdFx0XHRcdCggeDIgPj0gbCAmJiB4MiA8PSByICkgfHwgLy8gUmlnaHQgZWRnZSB0b3VjaGluZ1xuXHRcdFx0XHQoIHgxIDwgbCAmJiB4MiA+IHIgKSAvLyBTdXJyb3VuZGVkIGhvcml6b250YWxseVxuXHRcdFx0KTtcblx0XHRkZWZhdWx0OlxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblx0fTtcbn0gKSgpO1xuXG4vKlxuXHRUaGlzIG1hbmFnZXIgdHJhY2tzIG9mZnNldHMgb2YgZHJhZ2dhYmxlcyBhbmQgZHJvcHBhYmxlc1xuKi9cbiQudWkuZGRtYW5hZ2VyID0ge1xuXHRjdXJyZW50OiBudWxsLFxuXHRkcm9wcGFibGVzOiB7IFwiZGVmYXVsdFwiOiBbXSB9LFxuXHRwcmVwYXJlT2Zmc2V0czogZnVuY3Rpb24oIHQsIGV2ZW50ICkge1xuXG5cdFx0dmFyIGksIGosXG5cdFx0XHRtID0gJC51aS5kZG1hbmFnZXIuZHJvcHBhYmxlc1sgdC5vcHRpb25zLnNjb3BlIF0gfHwgW10sXG5cdFx0XHR0eXBlID0gZXZlbnQgPyBldmVudC50eXBlIDogbnVsbCwgLy8gd29ya2Fyb3VuZCBmb3IgIzIzMTdcblx0XHRcdGxpc3QgPSAoIHQuY3VycmVudEl0ZW0gfHwgdC5lbGVtZW50ICkuZmluZCggXCI6ZGF0YSh1aS1kcm9wcGFibGUpXCIgKS5hZGRCYWNrKCk7XG5cblx0XHRkcm9wcGFibGVzTG9vcDogZm9yICggaSA9IDA7IGkgPCBtLmxlbmd0aDsgaSsrICkge1xuXG5cdFx0XHQvLyBObyBkaXNhYmxlZCBhbmQgbm9uLWFjY2VwdGVkXG5cdFx0XHRpZiAoIG1bIGkgXS5vcHRpb25zLmRpc2FibGVkIHx8ICggdCAmJiAhbVsgaSBdLmFjY2VwdC5jYWxsKCBtWyBpIF0uZWxlbWVudFsgMCBdLFxuXHRcdFx0XHRcdCggdC5jdXJyZW50SXRlbSB8fCB0LmVsZW1lbnQgKSApICkgKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBGaWx0ZXIgb3V0IGVsZW1lbnRzIGluIHRoZSBjdXJyZW50IGRyYWdnZWQgaXRlbVxuXHRcdFx0Zm9yICggaiA9IDA7IGogPCBsaXN0Lmxlbmd0aDsgaisrICkge1xuXHRcdFx0XHRpZiAoIGxpc3RbIGogXSA9PT0gbVsgaSBdLmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdFx0XHRtWyBpIF0ucHJvcG9ydGlvbnMoKS5oZWlnaHQgPSAwO1xuXHRcdFx0XHRcdGNvbnRpbnVlIGRyb3BwYWJsZXNMb29wO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdG1bIGkgXS52aXNpYmxlID0gbVsgaSBdLmVsZW1lbnQuY3NzKCBcImRpc3BsYXlcIiApICE9PSBcIm5vbmVcIjtcblx0XHRcdGlmICggIW1bIGkgXS52aXNpYmxlICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQWN0aXZhdGUgdGhlIGRyb3BwYWJsZSBpZiB1c2VkIGRpcmVjdGx5IGZyb20gZHJhZ2dhYmxlc1xuXHRcdFx0aWYgKCB0eXBlID09PSBcIm1vdXNlZG93blwiICkge1xuXHRcdFx0XHRtWyBpIF0uX2FjdGl2YXRlLmNhbGwoIG1bIGkgXSwgZXZlbnQgKTtcblx0XHRcdH1cblxuXHRcdFx0bVsgaSBdLm9mZnNldCA9IG1bIGkgXS5lbGVtZW50Lm9mZnNldCgpO1xuXHRcdFx0bVsgaSBdLnByb3BvcnRpb25zKCB7XG5cdFx0XHRcdHdpZHRoOiBtWyBpIF0uZWxlbWVudFsgMCBdLm9mZnNldFdpZHRoLFxuXHRcdFx0XHRoZWlnaHQ6IG1bIGkgXS5lbGVtZW50WyAwIF0ub2Zmc2V0SGVpZ2h0XG5cdFx0XHR9ICk7XG5cblx0XHR9XG5cblx0fSxcblx0ZHJvcDogZnVuY3Rpb24oIGRyYWdnYWJsZSwgZXZlbnQgKSB7XG5cblx0XHR2YXIgZHJvcHBlZCA9IGZhbHNlO1xuXG5cdFx0Ly8gQ3JlYXRlIGEgY29weSBvZiB0aGUgZHJvcHBhYmxlcyBpbiBjYXNlIHRoZSBsaXN0IGNoYW5nZXMgZHVyaW5nIHRoZSBkcm9wICgjOTExNilcblx0XHQkLmVhY2goICggJC51aS5kZG1hbmFnZXIuZHJvcHBhYmxlc1sgZHJhZ2dhYmxlLm9wdGlvbnMuc2NvcGUgXSB8fCBbXSApLnNsaWNlKCksIGZ1bmN0aW9uKCkge1xuXG5cdFx0XHRpZiAoICF0aGlzLm9wdGlvbnMgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHRcdGlmICggIXRoaXMub3B0aW9ucy5kaXNhYmxlZCAmJiB0aGlzLnZpc2libGUgJiZcblx0XHRcdFx0XHRpbnRlcnNlY3QoIGRyYWdnYWJsZSwgdGhpcywgdGhpcy5vcHRpb25zLnRvbGVyYW5jZSwgZXZlbnQgKSApIHtcblx0XHRcdFx0ZHJvcHBlZCA9IHRoaXMuX2Ryb3AuY2FsbCggdGhpcywgZXZlbnQgKSB8fCBkcm9wcGVkO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICF0aGlzLm9wdGlvbnMuZGlzYWJsZWQgJiYgdGhpcy52aXNpYmxlICYmIHRoaXMuYWNjZXB0LmNhbGwoIHRoaXMuZWxlbWVudFsgMCBdLFxuXHRcdFx0XHRcdCggZHJhZ2dhYmxlLmN1cnJlbnRJdGVtIHx8IGRyYWdnYWJsZS5lbGVtZW50ICkgKSApIHtcblx0XHRcdFx0dGhpcy5pc291dCA9IHRydWU7XG5cdFx0XHRcdHRoaXMuaXNvdmVyID0gZmFsc2U7XG5cdFx0XHRcdHRoaXMuX2RlYWN0aXZhdGUuY2FsbCggdGhpcywgZXZlbnQgKTtcblx0XHRcdH1cblxuXHRcdH0gKTtcblx0XHRyZXR1cm4gZHJvcHBlZDtcblxuXHR9LFxuXHRkcmFnU3RhcnQ6IGZ1bmN0aW9uKCBkcmFnZ2FibGUsIGV2ZW50ICkge1xuXG5cdFx0Ly8gTGlzdGVuIGZvciBzY3JvbGxpbmcgc28gdGhhdCBpZiB0aGUgZHJhZ2dpbmcgY2F1c2VzIHNjcm9sbGluZyB0aGUgcG9zaXRpb24gb2YgdGhlXG5cdFx0Ly8gZHJvcHBhYmxlcyBjYW4gYmUgcmVjYWxjdWxhdGVkIChzZWUgIzUwMDMpXG5cdFx0ZHJhZ2dhYmxlLmVsZW1lbnQucGFyZW50c1VudGlsKCBcImJvZHlcIiApLm9uKCBcInNjcm9sbC5kcm9wcGFibGVcIiwgZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoICFkcmFnZ2FibGUub3B0aW9ucy5yZWZyZXNoUG9zaXRpb25zICkge1xuXHRcdFx0XHQkLnVpLmRkbWFuYWdlci5wcmVwYXJlT2Zmc2V0cyggZHJhZ2dhYmxlLCBldmVudCApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0fSxcblx0ZHJhZzogZnVuY3Rpb24oIGRyYWdnYWJsZSwgZXZlbnQgKSB7XG5cblx0XHQvLyBJZiB5b3UgaGF2ZSBhIGhpZ2hseSBkeW5hbWljIHBhZ2UsIHlvdSBtaWdodCB0cnkgdGhpcyBvcHRpb24uIEl0IHJlbmRlcnMgcG9zaXRpb25zXG5cdFx0Ly8gZXZlcnkgdGltZSB5b3UgbW92ZSB0aGUgbW91c2UuXG5cdFx0aWYgKCBkcmFnZ2FibGUub3B0aW9ucy5yZWZyZXNoUG9zaXRpb25zICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIucHJlcGFyZU9mZnNldHMoIGRyYWdnYWJsZSwgZXZlbnQgKTtcblx0XHR9XG5cblx0XHQvLyBSdW4gdGhyb3VnaCBhbGwgZHJvcHBhYmxlcyBhbmQgY2hlY2sgdGhlaXIgcG9zaXRpb25zIGJhc2VkIG9uIHNwZWNpZmljIHRvbGVyYW5jZSBvcHRpb25zXG5cdFx0JC5lYWNoKCAkLnVpLmRkbWFuYWdlci5kcm9wcGFibGVzWyBkcmFnZ2FibGUub3B0aW9ucy5zY29wZSBdIHx8IFtdLCBmdW5jdGlvbigpIHtcblxuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgfHwgdGhpcy5ncmVlZHlDaGlsZCB8fCAhdGhpcy52aXNpYmxlICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdHZhciBwYXJlbnRJbnN0YW5jZSwgc2NvcGUsIHBhcmVudCxcblx0XHRcdFx0aW50ZXJzZWN0cyA9IGludGVyc2VjdCggZHJhZ2dhYmxlLCB0aGlzLCB0aGlzLm9wdGlvbnMudG9sZXJhbmNlLCBldmVudCApLFxuXHRcdFx0XHRjID0gIWludGVyc2VjdHMgJiYgdGhpcy5pc292ZXIgP1xuXHRcdFx0XHRcdFwiaXNvdXRcIiA6XG5cdFx0XHRcdFx0KCBpbnRlcnNlY3RzICYmICF0aGlzLmlzb3ZlciA/IFwiaXNvdmVyXCIgOiBudWxsICk7XG5cdFx0XHRpZiAoICFjICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmdyZWVkeSApIHtcblxuXHRcdFx0XHQvLyBmaW5kIGRyb3BwYWJsZSBwYXJlbnRzIHdpdGggc2FtZSBzY29wZVxuXHRcdFx0XHRzY29wZSA9IHRoaXMub3B0aW9ucy5zY29wZTtcblx0XHRcdFx0cGFyZW50ID0gdGhpcy5lbGVtZW50LnBhcmVudHMoIFwiOmRhdGEodWktZHJvcHBhYmxlKVwiICkuZmlsdGVyKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRyZXR1cm4gJCggdGhpcyApLmRyb3BwYWJsZSggXCJpbnN0YW5jZVwiICkub3B0aW9ucy5zY29wZSA9PT0gc2NvcGU7XG5cdFx0XHRcdH0gKTtcblxuXHRcdFx0XHRpZiAoIHBhcmVudC5sZW5ndGggKSB7XG5cdFx0XHRcdFx0cGFyZW50SW5zdGFuY2UgPSAkKCBwYXJlbnRbIDAgXSApLmRyb3BwYWJsZSggXCJpbnN0YW5jZVwiICk7XG5cdFx0XHRcdFx0cGFyZW50SW5zdGFuY2UuZ3JlZWR5Q2hpbGQgPSAoIGMgPT09IFwiaXNvdmVyXCIgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBXZSBqdXN0IG1vdmVkIGludG8gYSBncmVlZHkgY2hpbGRcblx0XHRcdGlmICggcGFyZW50SW5zdGFuY2UgJiYgYyA9PT0gXCJpc292ZXJcIiApIHtcblx0XHRcdFx0cGFyZW50SW5zdGFuY2UuaXNvdmVyID0gZmFsc2U7XG5cdFx0XHRcdHBhcmVudEluc3RhbmNlLmlzb3V0ID0gdHJ1ZTtcblx0XHRcdFx0cGFyZW50SW5zdGFuY2UuX291dC5jYWxsKCBwYXJlbnRJbnN0YW5jZSwgZXZlbnQgKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpc1sgYyBdID0gdHJ1ZTtcblx0XHRcdHRoaXNbIGMgPT09IFwiaXNvdXRcIiA/IFwiaXNvdmVyXCIgOiBcImlzb3V0XCIgXSA9IGZhbHNlO1xuXHRcdFx0dGhpc1sgYyA9PT0gXCJpc292ZXJcIiA/IFwiX292ZXJcIiA6IFwiX291dFwiIF0uY2FsbCggdGhpcywgZXZlbnQgKTtcblxuXHRcdFx0Ly8gV2UganVzdCBtb3ZlZCBvdXQgb2YgYSBncmVlZHkgY2hpbGRcblx0XHRcdGlmICggcGFyZW50SW5zdGFuY2UgJiYgYyA9PT0gXCJpc291dFwiICkge1xuXHRcdFx0XHRwYXJlbnRJbnN0YW5jZS5pc291dCA9IGZhbHNlO1xuXHRcdFx0XHRwYXJlbnRJbnN0YW5jZS5pc292ZXIgPSB0cnVlO1xuXHRcdFx0XHRwYXJlbnRJbnN0YW5jZS5fb3Zlci5jYWxsKCBwYXJlbnRJbnN0YW5jZSwgZXZlbnQgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0fSxcblx0ZHJhZ1N0b3A6IGZ1bmN0aW9uKCBkcmFnZ2FibGUsIGV2ZW50ICkge1xuXHRcdGRyYWdnYWJsZS5lbGVtZW50LnBhcmVudHNVbnRpbCggXCJib2R5XCIgKS5vZmYoIFwic2Nyb2xsLmRyb3BwYWJsZVwiICk7XG5cblx0XHQvLyBDYWxsIHByZXBhcmVPZmZzZXRzIG9uZSBmaW5hbCB0aW1lIHNpbmNlIElFIGRvZXMgbm90IGZpcmUgcmV0dXJuIHNjcm9sbCBldmVudHMgd2hlblxuXHRcdC8vIG92ZXJmbG93IHdhcyBjYXVzZWQgYnkgZHJhZyAoc2VlICM1MDAzKVxuXHRcdGlmICggIWRyYWdnYWJsZS5vcHRpb25zLnJlZnJlc2hQb3NpdGlvbnMgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5wcmVwYXJlT2Zmc2V0cyggZHJhZ2dhYmxlLCBldmVudCApO1xuXHRcdH1cblx0fVxufTtcblxuLy8gREVQUkVDQVRFRFxuLy8gVE9ETzogc3dpdGNoIHJldHVybiBiYWNrIHRvIHdpZGdldCBkZWNsYXJhdGlvbiBhdCB0b3Agb2YgZmlsZSB3aGVuIHRoaXMgaXMgcmVtb3ZlZFxuaWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgKSB7XG5cblx0Ly8gQmFja2NvbXBhdCBmb3IgYWN0aXZlQ2xhc3MgYW5kIGhvdmVyQ2xhc3Mgb3B0aW9uc1xuXHQkLndpZGdldCggXCJ1aS5kcm9wcGFibGVcIiwgJC51aS5kcm9wcGFibGUsIHtcblx0XHRvcHRpb25zOiB7XG5cdFx0XHRob3ZlckNsYXNzOiBmYWxzZSxcblx0XHRcdGFjdGl2ZUNsYXNzOiBmYWxzZVxuXHRcdH0sXG5cdFx0X2FkZEFjdGl2ZUNsYXNzOiBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuX3N1cGVyKCk7XG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5hY3RpdmVDbGFzcyApIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LmFkZENsYXNzKCB0aGlzLm9wdGlvbnMuYWN0aXZlQ2xhc3MgKTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdF9yZW1vdmVBY3RpdmVDbGFzczogZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLl9zdXBlcigpO1xuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuYWN0aXZlQ2xhc3MgKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5yZW1vdmVDbGFzcyggdGhpcy5vcHRpb25zLmFjdGl2ZUNsYXNzICk7XG5cdFx0XHR9XG5cdFx0fSxcblx0XHRfYWRkSG92ZXJDbGFzczogZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGlzLl9zdXBlcigpO1xuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuaG92ZXJDbGFzcyApIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LmFkZENsYXNzKCB0aGlzLm9wdGlvbnMuaG92ZXJDbGFzcyApO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0X3JlbW92ZUhvdmVyQ2xhc3M6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5fc3VwZXIoKTtcblx0XHRcdGlmICggdGhpcy5vcHRpb25zLmhvdmVyQ2xhc3MgKSB7XG5cdFx0XHRcdHRoaXMuZWxlbWVudC5yZW1vdmVDbGFzcyggdGhpcy5vcHRpb25zLmhvdmVyQ2xhc3MgKTtcblx0XHRcdH1cblx0XHR9XG5cdH0gKTtcbn1cblxudmFyIHdpZGdldHNEcm9wcGFibGUgPSAkLnVpLmRyb3BwYWJsZTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBQcm9ncmVzc2JhciAxLjEyLjFcbiAqIGh0dHA6Ly9qcXVlcnl1aS5jb21cbiAqXG4gKiBDb3B5cmlnaHQgalF1ZXJ5IEZvdW5kYXRpb24gYW5kIG90aGVyIGNvbnRyaWJ1dG9yc1xuICogUmVsZWFzZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlLlxuICogaHR0cDovL2pxdWVyeS5vcmcvbGljZW5zZVxuICovXG5cbi8vPj5sYWJlbDogUHJvZ3Jlc3NiYXJcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8ganNjczpkaXNhYmxlIG1heGltdW1MaW5lTGVuZ3RoXG4vLz4+ZGVzY3JpcHRpb246IERpc3BsYXlzIGEgc3RhdHVzIGluZGljYXRvciBmb3IgbG9hZGluZyBzdGF0ZSwgc3RhbmRhcmQgcGVyY2VudGFnZSwgYW5kIG90aGVyIHByb2dyZXNzIGluZGljYXRvcnMuXG4vLyBqc2NzOmVuYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3Byb2dyZXNzYmFyL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3Byb2dyZXNzYmFyL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvcHJvZ3Jlc3NiYXIuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbnZhciB3aWRnZXRzUHJvZ3Jlc3NiYXIgPSAkLndpZGdldCggXCJ1aS5wcm9ncmVzc2JhclwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLXByb2dyZXNzYmFyXCI6IFwidWktY29ybmVyLWFsbFwiLFxuXHRcdFx0XCJ1aS1wcm9ncmVzc2Jhci12YWx1ZVwiOiBcInVpLWNvcm5lci1sZWZ0XCIsXG5cdFx0XHRcInVpLXByb2dyZXNzYmFyLWNvbXBsZXRlXCI6IFwidWktY29ybmVyLXJpZ2h0XCJcblx0XHR9LFxuXHRcdG1heDogMTAwLFxuXHRcdHZhbHVlOiAwLFxuXG5cdFx0Y2hhbmdlOiBudWxsLFxuXHRcdGNvbXBsZXRlOiBudWxsXG5cdH0sXG5cblx0bWluOiAwLFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly8gQ29uc3RyYWluIGluaXRpYWwgdmFsdWVcblx0XHR0aGlzLm9sZFZhbHVlID0gdGhpcy5vcHRpb25zLnZhbHVlID0gdGhpcy5fY29uc3RyYWluZWRWYWx1ZSgpO1xuXG5cdFx0dGhpcy5lbGVtZW50LmF0dHIoIHtcblxuXHRcdFx0Ly8gT25seSBzZXQgc3RhdGljIHZhbHVlczsgYXJpYS12YWx1ZW5vdyBhbmQgYXJpYS12YWx1ZW1heCBhcmVcblx0XHRcdC8vIHNldCBpbnNpZGUgX3JlZnJlc2hWYWx1ZSgpXG5cdFx0XHRyb2xlOiBcInByb2dyZXNzYmFyXCIsXG5cdFx0XHRcImFyaWEtdmFsdWVtaW5cIjogdGhpcy5taW5cblx0XHR9ICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktcHJvZ3Jlc3NiYXJcIiwgXCJ1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXG5cdFx0dGhpcy52YWx1ZURpdiA9ICQoIFwiPGRpdj5cIiApLmFwcGVuZFRvKCB0aGlzLmVsZW1lbnQgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy52YWx1ZURpdiwgXCJ1aS1wcm9ncmVzc2Jhci12YWx1ZVwiLCBcInVpLXdpZGdldC1oZWFkZXJcIiApO1xuXHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmVsZW1lbnQucmVtb3ZlQXR0ciggXCJyb2xlIGFyaWEtdmFsdWVtaW4gYXJpYS12YWx1ZW1heCBhcmlhLXZhbHVlbm93XCIgKTtcblxuXHRcdHRoaXMudmFsdWVEaXYucmVtb3ZlKCk7XG5cdH0sXG5cblx0dmFsdWU6IGZ1bmN0aW9uKCBuZXdWYWx1ZSApIHtcblx0XHRpZiAoIG5ld1ZhbHVlID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLnZhbHVlO1xuXHRcdH1cblxuXHRcdHRoaXMub3B0aW9ucy52YWx1ZSA9IHRoaXMuX2NvbnN0cmFpbmVkVmFsdWUoIG5ld1ZhbHVlICk7XG5cdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdH0sXG5cblx0X2NvbnN0cmFpbmVkVmFsdWU6IGZ1bmN0aW9uKCBuZXdWYWx1ZSApIHtcblx0XHRpZiAoIG5ld1ZhbHVlID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRuZXdWYWx1ZSA9IHRoaXMub3B0aW9ucy52YWx1ZTtcblx0XHR9XG5cblx0XHR0aGlzLmluZGV0ZXJtaW5hdGUgPSBuZXdWYWx1ZSA9PT0gZmFsc2U7XG5cblx0XHQvLyBTYW5pdGl6ZSB2YWx1ZVxuXHRcdGlmICggdHlwZW9mIG5ld1ZhbHVlICE9PSBcIm51bWJlclwiICkge1xuXHRcdFx0bmV3VmFsdWUgPSAwO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmluZGV0ZXJtaW5hdGUgPyBmYWxzZSA6XG5cdFx0XHRNYXRoLm1pbiggdGhpcy5vcHRpb25zLm1heCwgTWF0aC5tYXgoIHRoaXMubWluLCBuZXdWYWx1ZSApICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbnM6IGZ1bmN0aW9uKCBvcHRpb25zICkge1xuXG5cdFx0Ly8gRW5zdXJlIFwidmFsdWVcIiBvcHRpb24gaXMgc2V0IGFmdGVyIG90aGVyIHZhbHVlcyAobGlrZSBtYXgpXG5cdFx0dmFyIHZhbHVlID0gb3B0aW9ucy52YWx1ZTtcblx0XHRkZWxldGUgb3B0aW9ucy52YWx1ZTtcblxuXHRcdHRoaXMuX3N1cGVyKCBvcHRpb25zICk7XG5cblx0XHR0aGlzLm9wdGlvbnMudmFsdWUgPSB0aGlzLl9jb25zdHJhaW5lZFZhbHVlKCB2YWx1ZSApO1xuXHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdGlmICgga2V5ID09PSBcIm1heFwiICkge1xuXG5cdFx0XHQvLyBEb24ndCBhbGxvdyBhIG1heCBsZXNzIHRoYW4gbWluXG5cdFx0XHR2YWx1ZSA9IE1hdGgubWF4KCB0aGlzLm1pbiwgdmFsdWUgKTtcblx0XHR9XG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uRGlzYWJsZWQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlciggdmFsdWUgKTtcblxuXHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcImFyaWEtZGlzYWJsZWRcIiwgdmFsdWUgKTtcblx0XHR0aGlzLl90b2dnbGVDbGFzcyggbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiLCAhIXZhbHVlICk7XG5cdH0sXG5cblx0X3BlcmNlbnRhZ2U6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmluZGV0ZXJtaW5hdGUgP1xuXHRcdFx0MTAwIDpcblx0XHRcdDEwMCAqICggdGhpcy5vcHRpb25zLnZhbHVlIC0gdGhpcy5taW4gKSAvICggdGhpcy5vcHRpb25zLm1heCAtIHRoaXMubWluICk7XG5cdH0sXG5cblx0X3JlZnJlc2hWYWx1ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHZhbHVlID0gdGhpcy5vcHRpb25zLnZhbHVlLFxuXHRcdFx0cGVyY2VudGFnZSA9IHRoaXMuX3BlcmNlbnRhZ2UoKTtcblxuXHRcdHRoaXMudmFsdWVEaXZcblx0XHRcdC50b2dnbGUoIHRoaXMuaW5kZXRlcm1pbmF0ZSB8fCB2YWx1ZSA+IHRoaXMubWluIClcblx0XHRcdC53aWR0aCggcGVyY2VudGFnZS50b0ZpeGVkKCAwICkgKyBcIiVcIiApO1xuXG5cdFx0dGhpc1xuXHRcdFx0Ll90b2dnbGVDbGFzcyggdGhpcy52YWx1ZURpdiwgXCJ1aS1wcm9ncmVzc2Jhci1jb21wbGV0ZVwiLCBudWxsLFxuXHRcdFx0XHR2YWx1ZSA9PT0gdGhpcy5vcHRpb25zLm1heCApXG5cdFx0XHQuX3RvZ2dsZUNsYXNzKCBcInVpLXByb2dyZXNzYmFyLWluZGV0ZXJtaW5hdGVcIiwgbnVsbCwgdGhpcy5pbmRldGVybWluYXRlICk7XG5cblx0XHRpZiAoIHRoaXMuaW5kZXRlcm1pbmF0ZSApIHtcblx0XHRcdHRoaXMuZWxlbWVudC5yZW1vdmVBdHRyKCBcImFyaWEtdmFsdWVub3dcIiApO1xuXHRcdFx0aWYgKCAhdGhpcy5vdmVybGF5RGl2ICkge1xuXHRcdFx0XHR0aGlzLm92ZXJsYXlEaXYgPSAkKCBcIjxkaXY+XCIgKS5hcHBlbmRUbyggdGhpcy52YWx1ZURpdiApO1xuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5vdmVybGF5RGl2LCBcInVpLXByb2dyZXNzYmFyLW92ZXJsYXlcIiApO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmVsZW1lbnQuYXR0cigge1xuXHRcdFx0XHRcImFyaWEtdmFsdWVtYXhcIjogdGhpcy5vcHRpb25zLm1heCxcblx0XHRcdFx0XCJhcmlhLXZhbHVlbm93XCI6IHZhbHVlXG5cdFx0XHR9ICk7XG5cdFx0XHRpZiAoIHRoaXMub3ZlcmxheURpdiApIHtcblx0XHRcdFx0dGhpcy5vdmVybGF5RGl2LnJlbW92ZSgpO1xuXHRcdFx0XHR0aGlzLm92ZXJsYXlEaXYgPSBudWxsO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vbGRWYWx1ZSAhPT0gdmFsdWUgKSB7XG5cdFx0XHR0aGlzLm9sZFZhbHVlID0gdmFsdWU7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNoYW5nZVwiICk7XG5cdFx0fVxuXHRcdGlmICggdmFsdWUgPT09IHRoaXMub3B0aW9ucy5tYXggKSB7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNvbXBsZXRlXCIgKTtcblx0XHR9XG5cdH1cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBTZWxlY3RhYmxlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBTZWxlY3RhYmxlXG4vLz4+Z3JvdXA6IEludGVyYWN0aW9uc1xuLy8+PmRlc2NyaXB0aW9uOiBBbGxvd3MgZ3JvdXBzIG9mIGVsZW1lbnRzIHRvIGJlIHNlbGVjdGVkIHdpdGggdGhlIG1vdXNlLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3NlbGVjdGFibGUvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vc2VsZWN0YWJsZS9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9zZWxlY3RhYmxlLmNzc1xuXG5cblxudmFyIHdpZGdldHNTZWxlY3RhYmxlID0gJC53aWRnZXQoIFwidWkuc2VsZWN0YWJsZVwiLCAkLnVpLm1vdXNlLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRhcHBlbmRUbzogXCJib2R5XCIsXG5cdFx0YXV0b1JlZnJlc2g6IHRydWUsXG5cdFx0ZGlzdGFuY2U6IDAsXG5cdFx0ZmlsdGVyOiBcIipcIixcblx0XHR0b2xlcmFuY2U6IFwidG91Y2hcIixcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdHNlbGVjdGVkOiBudWxsLFxuXHRcdHNlbGVjdGluZzogbnVsbCxcblx0XHRzdGFydDogbnVsbCxcblx0XHRzdG9wOiBudWxsLFxuXHRcdHVuc2VsZWN0ZWQ6IG51bGwsXG5cdFx0dW5zZWxlY3Rpbmc6IG51bGxcblx0fSxcblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktc2VsZWN0YWJsZVwiICk7XG5cblx0XHR0aGlzLmRyYWdnZWQgPSBmYWxzZTtcblxuXHRcdC8vIENhY2hlIHNlbGVjdGVlIGNoaWxkcmVuIGJhc2VkIG9uIGZpbHRlclxuXHRcdHRoaXMucmVmcmVzaCA9IGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhhdC5lbGVtZW50UG9zID0gJCggdGhhdC5lbGVtZW50WyAwIF0gKS5vZmZzZXQoKTtcblx0XHRcdHRoYXQuc2VsZWN0ZWVzID0gJCggdGhhdC5vcHRpb25zLmZpbHRlciwgdGhhdC5lbGVtZW50WyAwIF0gKTtcblx0XHRcdHRoYXQuX2FkZENsYXNzKCB0aGF0LnNlbGVjdGVlcywgXCJ1aS1zZWxlY3RlZVwiICk7XG5cdFx0XHR0aGF0LnNlbGVjdGVlcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyICR0aGlzID0gJCggdGhpcyApLFxuXHRcdFx0XHRcdHNlbGVjdGVlT2Zmc2V0ID0gJHRoaXMub2Zmc2V0KCksXG5cdFx0XHRcdFx0cG9zID0ge1xuXHRcdFx0XHRcdFx0bGVmdDogc2VsZWN0ZWVPZmZzZXQubGVmdCAtIHRoYXQuZWxlbWVudFBvcy5sZWZ0LFxuXHRcdFx0XHRcdFx0dG9wOiBzZWxlY3RlZU9mZnNldC50b3AgLSB0aGF0LmVsZW1lbnRQb3MudG9wXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0JC5kYXRhKCB0aGlzLCBcInNlbGVjdGFibGUtaXRlbVwiLCB7XG5cdFx0XHRcdFx0ZWxlbWVudDogdGhpcyxcblx0XHRcdFx0XHQkZWxlbWVudDogJHRoaXMsXG5cdFx0XHRcdFx0bGVmdDogcG9zLmxlZnQsXG5cdFx0XHRcdFx0dG9wOiBwb3MudG9wLFxuXHRcdFx0XHRcdHJpZ2h0OiBwb3MubGVmdCArICR0aGlzLm91dGVyV2lkdGgoKSxcblx0XHRcdFx0XHRib3R0b206IHBvcy50b3AgKyAkdGhpcy5vdXRlckhlaWdodCgpLFxuXHRcdFx0XHRcdHN0YXJ0c2VsZWN0ZWQ6IGZhbHNlLFxuXHRcdFx0XHRcdHNlbGVjdGVkOiAkdGhpcy5oYXNDbGFzcyggXCJ1aS1zZWxlY3RlZFwiICksXG5cdFx0XHRcdFx0c2VsZWN0aW5nOiAkdGhpcy5oYXNDbGFzcyggXCJ1aS1zZWxlY3RpbmdcIiApLFxuXHRcdFx0XHRcdHVuc2VsZWN0aW5nOiAkdGhpcy5oYXNDbGFzcyggXCJ1aS11bnNlbGVjdGluZ1wiIClcblx0XHRcdFx0fSApO1xuXHRcdFx0fSApO1xuXHRcdH07XG5cdFx0dGhpcy5yZWZyZXNoKCk7XG5cblx0XHR0aGlzLl9tb3VzZUluaXQoKTtcblxuXHRcdHRoaXMuaGVscGVyID0gJCggXCI8ZGl2PlwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMuaGVscGVyLCBcInVpLXNlbGVjdGFibGUtaGVscGVyXCIgKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5zZWxlY3RlZXMucmVtb3ZlRGF0YSggXCJzZWxlY3RhYmxlLWl0ZW1cIiApO1xuXHRcdHRoaXMuX21vdXNlRGVzdHJveSgpO1xuXHR9LFxuXG5cdF9tb3VzZVN0YXJ0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0b3B0aW9ucyA9IHRoaXMub3B0aW9ucztcblxuXHRcdHRoaXMub3BvcyA9IFsgZXZlbnQucGFnZVgsIGV2ZW50LnBhZ2VZIF07XG5cdFx0dGhpcy5lbGVtZW50UG9zID0gJCggdGhpcy5lbGVtZW50WyAwIF0gKS5vZmZzZXQoKTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuc2VsZWN0ZWVzID0gJCggb3B0aW9ucy5maWx0ZXIsIHRoaXMuZWxlbWVudFsgMCBdICk7XG5cblx0XHR0aGlzLl90cmlnZ2VyKCBcInN0YXJ0XCIsIGV2ZW50ICk7XG5cblx0XHQkKCBvcHRpb25zLmFwcGVuZFRvICkuYXBwZW5kKCB0aGlzLmhlbHBlciApO1xuXG5cdFx0Ly8gcG9zaXRpb24gaGVscGVyIChsYXNzbylcblx0XHR0aGlzLmhlbHBlci5jc3MoIHtcblx0XHRcdFwibGVmdFwiOiBldmVudC5wYWdlWCxcblx0XHRcdFwidG9wXCI6IGV2ZW50LnBhZ2VZLFxuXHRcdFx0XCJ3aWR0aFwiOiAwLFxuXHRcdFx0XCJoZWlnaHRcIjogMFxuXHRcdH0gKTtcblxuXHRcdGlmICggb3B0aW9ucy5hdXRvUmVmcmVzaCApIHtcblx0XHRcdHRoaXMucmVmcmVzaCgpO1xuXHRcdH1cblxuXHRcdHRoaXMuc2VsZWN0ZWVzLmZpbHRlciggXCIudWktc2VsZWN0ZWRcIiApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHNlbGVjdGVlID0gJC5kYXRhKCB0aGlzLCBcInNlbGVjdGFibGUtaXRlbVwiICk7XG5cdFx0XHRzZWxlY3RlZS5zdGFydHNlbGVjdGVkID0gdHJ1ZTtcblx0XHRcdGlmICggIWV2ZW50Lm1ldGFLZXkgJiYgIWV2ZW50LmN0cmxLZXkgKSB7XG5cdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS1zZWxlY3RlZFwiICk7XG5cdFx0XHRcdHNlbGVjdGVlLnNlbGVjdGVkID0gZmFsc2U7XG5cdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS11bnNlbGVjdGluZ1wiICk7XG5cdFx0XHRcdHNlbGVjdGVlLnVuc2VsZWN0aW5nID0gdHJ1ZTtcblxuXHRcdFx0XHQvLyBzZWxlY3RhYmxlIFVOU0VMRUNUSU5HIGNhbGxiYWNrXG5cdFx0XHRcdHRoYXQuX3RyaWdnZXIoIFwidW5zZWxlY3RpbmdcIiwgZXZlbnQsIHtcblx0XHRcdFx0XHR1bnNlbGVjdGluZzogc2VsZWN0ZWUuZWxlbWVudFxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0JCggZXZlbnQudGFyZ2V0ICkucGFyZW50cygpLmFkZEJhY2soKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBkb1NlbGVjdCxcblx0XHRcdFx0c2VsZWN0ZWUgPSAkLmRhdGEoIHRoaXMsIFwic2VsZWN0YWJsZS1pdGVtXCIgKTtcblx0XHRcdGlmICggc2VsZWN0ZWUgKSB7XG5cdFx0XHRcdGRvU2VsZWN0ID0gKCAhZXZlbnQubWV0YUtleSAmJiAhZXZlbnQuY3RybEtleSApIHx8XG5cdFx0XHRcdFx0IXNlbGVjdGVlLiRlbGVtZW50Lmhhc0NsYXNzKCBcInVpLXNlbGVjdGVkXCIgKTtcblx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBkb1NlbGVjdCA/IFwidWktdW5zZWxlY3RpbmdcIiA6IFwidWktc2VsZWN0ZWRcIiApXG5cdFx0XHRcdFx0Ll9hZGRDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIGRvU2VsZWN0ID8gXCJ1aS1zZWxlY3RpbmdcIiA6IFwidWktdW5zZWxlY3RpbmdcIiApO1xuXHRcdFx0XHRzZWxlY3RlZS51bnNlbGVjdGluZyA9ICFkb1NlbGVjdDtcblx0XHRcdFx0c2VsZWN0ZWUuc2VsZWN0aW5nID0gZG9TZWxlY3Q7XG5cdFx0XHRcdHNlbGVjdGVlLnNlbGVjdGVkID0gZG9TZWxlY3Q7XG5cblx0XHRcdFx0Ly8gc2VsZWN0YWJsZSAoVU4pU0VMRUNUSU5HIGNhbGxiYWNrXG5cdFx0XHRcdGlmICggZG9TZWxlY3QgKSB7XG5cdFx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJzZWxlY3RpbmdcIiwgZXZlbnQsIHtcblx0XHRcdFx0XHRcdHNlbGVjdGluZzogc2VsZWN0ZWUuZWxlbWVudFxuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInVuc2VsZWN0aW5nXCIsIGV2ZW50LCB7XG5cdFx0XHRcdFx0XHR1bnNlbGVjdGluZzogc2VsZWN0ZWUuZWxlbWVudFxuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0fVxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdH0sXG5cblx0X21vdXNlRHJhZzogZnVuY3Rpb24oIGV2ZW50ICkge1xuXG5cdFx0dGhpcy5kcmFnZ2VkID0gdHJ1ZTtcblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciB0bXAsXG5cdFx0XHR0aGF0ID0gdGhpcyxcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHR4MSA9IHRoaXMub3Bvc1sgMCBdLFxuXHRcdFx0eTEgPSB0aGlzLm9wb3NbIDEgXSxcblx0XHRcdHgyID0gZXZlbnQucGFnZVgsXG5cdFx0XHR5MiA9IGV2ZW50LnBhZ2VZO1xuXG5cdFx0aWYgKCB4MSA+IHgyICkgeyB0bXAgPSB4MjsgeDIgPSB4MTsgeDEgPSB0bXA7IH1cblx0XHRpZiAoIHkxID4geTIgKSB7IHRtcCA9IHkyOyB5MiA9IHkxOyB5MSA9IHRtcDsgfVxuXHRcdHRoaXMuaGVscGVyLmNzcyggeyBsZWZ0OiB4MSwgdG9wOiB5MSwgd2lkdGg6IHgyIC0geDEsIGhlaWdodDogeTIgLSB5MSB9ICk7XG5cblx0XHR0aGlzLnNlbGVjdGVlcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBzZWxlY3RlZSA9ICQuZGF0YSggdGhpcywgXCJzZWxlY3RhYmxlLWl0ZW1cIiApLFxuXHRcdFx0XHRoaXQgPSBmYWxzZSxcblx0XHRcdFx0b2Zmc2V0ID0ge307XG5cblx0XHRcdC8vcHJldmVudCBoZWxwZXIgZnJvbSBiZWluZyBzZWxlY3RlZCBpZiBhcHBlbmRUbzogc2VsZWN0YWJsZVxuXHRcdFx0aWYgKCAhc2VsZWN0ZWUgfHwgc2VsZWN0ZWUuZWxlbWVudCA9PT0gdGhhdC5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0b2Zmc2V0LmxlZnQgICA9IHNlbGVjdGVlLmxlZnQgICArIHRoYXQuZWxlbWVudFBvcy5sZWZ0O1xuXHRcdFx0b2Zmc2V0LnJpZ2h0ICA9IHNlbGVjdGVlLnJpZ2h0ICArIHRoYXQuZWxlbWVudFBvcy5sZWZ0O1xuXHRcdFx0b2Zmc2V0LnRvcCAgICA9IHNlbGVjdGVlLnRvcCAgICArIHRoYXQuZWxlbWVudFBvcy50b3A7XG5cdFx0XHRvZmZzZXQuYm90dG9tID0gc2VsZWN0ZWUuYm90dG9tICsgdGhhdC5lbGVtZW50UG9zLnRvcDtcblxuXHRcdFx0aWYgKCBvcHRpb25zLnRvbGVyYW5jZSA9PT0gXCJ0b3VjaFwiICkge1xuXHRcdFx0XHRoaXQgPSAoICEoIG9mZnNldC5sZWZ0ID4geDIgfHwgb2Zmc2V0LnJpZ2h0IDwgeDEgfHwgb2Zmc2V0LnRvcCA+IHkyIHx8XG4gICAgICAgICAgICAgICAgICAgIG9mZnNldC5ib3R0b20gPCB5MSApICk7XG5cdFx0XHR9IGVsc2UgaWYgKCBvcHRpb25zLnRvbGVyYW5jZSA9PT0gXCJmaXRcIiApIHtcblx0XHRcdFx0aGl0ID0gKCBvZmZzZXQubGVmdCA+IHgxICYmIG9mZnNldC5yaWdodCA8IHgyICYmIG9mZnNldC50b3AgPiB5MSAmJlxuICAgICAgICAgICAgICAgICAgICBvZmZzZXQuYm90dG9tIDwgeTIgKTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBoaXQgKSB7XG5cblx0XHRcdFx0Ly8gU0VMRUNUXG5cdFx0XHRcdGlmICggc2VsZWN0ZWUuc2VsZWN0ZWQgKSB7XG5cdFx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXNlbGVjdGVkXCIgKTtcblx0XHRcdFx0XHRzZWxlY3RlZS5zZWxlY3RlZCA9IGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggc2VsZWN0ZWUudW5zZWxlY3RpbmcgKSB7XG5cdFx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXVuc2VsZWN0aW5nXCIgKTtcblx0XHRcdFx0XHRzZWxlY3RlZS51bnNlbGVjdGluZyA9IGZhbHNlO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggIXNlbGVjdGVlLnNlbGVjdGluZyApIHtcblx0XHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktc2VsZWN0aW5nXCIgKTtcblx0XHRcdFx0XHRzZWxlY3RlZS5zZWxlY3RpbmcgPSB0cnVlO1xuXG5cdFx0XHRcdFx0Ly8gc2VsZWN0YWJsZSBTRUxFQ1RJTkcgY2FsbGJhY2tcblx0XHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcInNlbGVjdGluZ1wiLCBldmVudCwge1xuXHRcdFx0XHRcdFx0c2VsZWN0aW5nOiBzZWxlY3RlZS5lbGVtZW50XG5cdFx0XHRcdFx0fSApO1xuXHRcdFx0XHR9XG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIFVOU0VMRUNUXG5cdFx0XHRcdGlmICggc2VsZWN0ZWUuc2VsZWN0aW5nICkge1xuXHRcdFx0XHRcdGlmICggKCBldmVudC5tZXRhS2V5IHx8IGV2ZW50LmN0cmxLZXkgKSAmJiBzZWxlY3RlZS5zdGFydHNlbGVjdGVkICkge1xuXHRcdFx0XHRcdFx0dGhhdC5fcmVtb3ZlQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXNlbGVjdGluZ1wiICk7XG5cdFx0XHRcdFx0XHRzZWxlY3RlZS5zZWxlY3RpbmcgPSBmYWxzZTtcblx0XHRcdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS1zZWxlY3RlZFwiICk7XG5cdFx0XHRcdFx0XHRzZWxlY3RlZS5zZWxlY3RlZCA9IHRydWU7XG5cdFx0XHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS1zZWxlY3RpbmdcIiApO1xuXHRcdFx0XHRcdFx0c2VsZWN0ZWUuc2VsZWN0aW5nID0gZmFsc2U7XG5cdFx0XHRcdFx0XHRpZiAoIHNlbGVjdGVlLnN0YXJ0c2VsZWN0ZWQgKSB7XG5cdFx0XHRcdFx0XHRcdHRoYXQuX2FkZENsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS11bnNlbGVjdGluZ1wiICk7XG5cdFx0XHRcdFx0XHRcdHNlbGVjdGVlLnVuc2VsZWN0aW5nID0gdHJ1ZTtcblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Ly8gc2VsZWN0YWJsZSBVTlNFTEVDVElORyBjYWxsYmFja1xuXHRcdFx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJ1bnNlbGVjdGluZ1wiLCBldmVudCwge1xuXHRcdFx0XHRcdFx0XHR1bnNlbGVjdGluZzogc2VsZWN0ZWUuZWxlbWVudFxuXHRcdFx0XHRcdFx0fSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0XHRpZiAoIHNlbGVjdGVlLnNlbGVjdGVkICkge1xuXHRcdFx0XHRcdGlmICggIWV2ZW50Lm1ldGFLZXkgJiYgIWV2ZW50LmN0cmxLZXkgJiYgIXNlbGVjdGVlLnN0YXJ0c2VsZWN0ZWQgKSB7XG5cdFx0XHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktc2VsZWN0ZWRcIiApO1xuXHRcdFx0XHRcdFx0c2VsZWN0ZWUuc2VsZWN0ZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIHNlbGVjdGVlLiRlbGVtZW50LCBcInVpLXVuc2VsZWN0aW5nXCIgKTtcblx0XHRcdFx0XHRcdHNlbGVjdGVlLnVuc2VsZWN0aW5nID0gdHJ1ZTtcblxuXHRcdFx0XHRcdFx0Ly8gc2VsZWN0YWJsZSBVTlNFTEVDVElORyBjYWxsYmFja1xuXHRcdFx0XHRcdFx0dGhhdC5fdHJpZ2dlciggXCJ1bnNlbGVjdGluZ1wiLCBldmVudCwge1xuXHRcdFx0XHRcdFx0XHR1bnNlbGVjdGluZzogc2VsZWN0ZWUuZWxlbWVudFxuXHRcdFx0XHRcdFx0fSApO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblxuXHRfbW91c2VTdG9wOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0dGhpcy5kcmFnZ2VkID0gZmFsc2U7XG5cblx0XHQkKCBcIi51aS11bnNlbGVjdGluZ1wiLCB0aGlzLmVsZW1lbnRbIDAgXSApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHNlbGVjdGVlID0gJC5kYXRhKCB0aGlzLCBcInNlbGVjdGFibGUtaXRlbVwiICk7XG5cdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktdW5zZWxlY3RpbmdcIiApO1xuXHRcdFx0c2VsZWN0ZWUudW5zZWxlY3RpbmcgPSBmYWxzZTtcblx0XHRcdHNlbGVjdGVlLnN0YXJ0c2VsZWN0ZWQgPSBmYWxzZTtcblx0XHRcdHRoYXQuX3RyaWdnZXIoIFwidW5zZWxlY3RlZFwiLCBldmVudCwge1xuXHRcdFx0XHR1bnNlbGVjdGVkOiBzZWxlY3RlZS5lbGVtZW50XG5cdFx0XHR9ICk7XG5cdFx0fSApO1xuXHRcdCQoIFwiLnVpLXNlbGVjdGluZ1wiLCB0aGlzLmVsZW1lbnRbIDAgXSApLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHNlbGVjdGVlID0gJC5kYXRhKCB0aGlzLCBcInNlbGVjdGFibGUtaXRlbVwiICk7XG5cdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggc2VsZWN0ZWUuJGVsZW1lbnQsIFwidWktc2VsZWN0aW5nXCIgKVxuXHRcdFx0XHQuX2FkZENsYXNzKCBzZWxlY3RlZS4kZWxlbWVudCwgXCJ1aS1zZWxlY3RlZFwiICk7XG5cdFx0XHRzZWxlY3RlZS5zZWxlY3RpbmcgPSBmYWxzZTtcblx0XHRcdHNlbGVjdGVlLnNlbGVjdGVkID0gdHJ1ZTtcblx0XHRcdHNlbGVjdGVlLnN0YXJ0c2VsZWN0ZWQgPSB0cnVlO1xuXHRcdFx0dGhhdC5fdHJpZ2dlciggXCJzZWxlY3RlZFwiLCBldmVudCwge1xuXHRcdFx0XHRzZWxlY3RlZDogc2VsZWN0ZWUuZWxlbWVudFxuXHRcdFx0fSApO1xuXHRcdH0gKTtcblx0XHR0aGlzLl90cmlnZ2VyKCBcInN0b3BcIiwgZXZlbnQgKTtcblxuXHRcdHRoaXMuaGVscGVyLnJlbW92ZSgpO1xuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG5cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBTZWxlY3RtZW51IDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBTZWxlY3RtZW51XG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vIGpzY3M6ZGlzYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRlc2NyaXB0aW9uOiBEdXBsaWNhdGVzIGFuZCBleHRlbmRzIHRoZSBmdW5jdGlvbmFsaXR5IG9mIGEgbmF0aXZlIEhUTUwgc2VsZWN0IGVsZW1lbnQsIGFsbG93aW5nIGl0IHRvIGJlIGN1c3RvbWl6YWJsZSBpbiBiZWhhdmlvciBhbmQgYXBwZWFyYW5jZSBmYXIgYmV5b25kIHRoZSBsaW1pdGF0aW9ucyBvZiBhIG5hdGl2ZSBzZWxlY3QuXG4vLyBqc2NzOmVuYWJsZSBtYXhpbXVtTGluZUxlbmd0aFxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3NlbGVjdG1lbnUvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vc2VsZWN0bWVudS9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL3NlbGVjdG1lbnUuY3NzLCAuLi8uLi90aGVtZXMvYmFzZS9idXR0b24uY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbnZhciB3aWRnZXRzU2VsZWN0bWVudSA9ICQud2lkZ2V0KCBcInVpLnNlbGVjdG1lbnVcIiwgWyAkLnVpLmZvcm1SZXNldE1peGluLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdGRlZmF1bHRFbGVtZW50OiBcIjxzZWxlY3Q+XCIsXG5cdG9wdGlvbnM6IHtcblx0XHRhcHBlbmRUbzogbnVsbCxcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLW9wZW5cIjogXCJ1aS1jb3JuZXItdG9wXCIsXG5cdFx0XHRcInVpLXNlbGVjdG1lbnUtYnV0dG9uLWNsb3NlZFwiOiBcInVpLWNvcm5lci1hbGxcIlxuXHRcdH0sXG5cdFx0ZGlzYWJsZWQ6IG51bGwsXG5cdFx0aWNvbnM6IHtcblx0XHRcdGJ1dHRvbjogXCJ1aS1pY29uLXRyaWFuZ2xlLTEtc1wiXG5cdFx0fSxcblx0XHRwb3NpdGlvbjoge1xuXHRcdFx0bXk6IFwibGVmdCB0b3BcIixcblx0XHRcdGF0OiBcImxlZnQgYm90dG9tXCIsXG5cdFx0XHRjb2xsaXNpb246IFwibm9uZVwiXG5cdFx0fSxcblx0XHR3aWR0aDogZmFsc2UsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRjaGFuZ2U6IG51bGwsXG5cdFx0Y2xvc2U6IG51bGwsXG5cdFx0Zm9jdXM6IG51bGwsXG5cdFx0b3BlbjogbnVsbCxcblx0XHRzZWxlY3Q6IG51bGxcblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgc2VsZWN0bWVudUlkID0gdGhpcy5lbGVtZW50LnVuaXF1ZUlkKCkuYXR0ciggXCJpZFwiICk7XG5cdFx0dGhpcy5pZHMgPSB7XG5cdFx0XHRlbGVtZW50OiBzZWxlY3RtZW51SWQsXG5cdFx0XHRidXR0b246IHNlbGVjdG1lbnVJZCArIFwiLWJ1dHRvblwiLFxuXHRcdFx0bWVudTogc2VsZWN0bWVudUlkICsgXCItbWVudVwiXG5cdFx0fTtcblxuXHRcdHRoaXMuX2RyYXdCdXR0b24oKTtcblx0XHR0aGlzLl9kcmF3TWVudSgpO1xuXHRcdHRoaXMuX2JpbmRGb3JtUmVzZXRIYW5kbGVyKCk7XG5cblx0XHR0aGlzLl9yZW5kZXJlZCA9IGZhbHNlO1xuXHRcdHRoaXMubWVudUl0ZW1zID0gJCgpO1xuXHR9LFxuXG5cdF9kcmF3QnV0dG9uOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgaWNvbixcblx0XHRcdHRoYXQgPSB0aGlzLFxuXHRcdFx0aXRlbSA9IHRoaXMuX3BhcnNlT3B0aW9uKFxuXHRcdFx0XHR0aGlzLmVsZW1lbnQuZmluZCggXCJvcHRpb246c2VsZWN0ZWRcIiApLFxuXHRcdFx0XHR0aGlzLmVsZW1lbnRbIDAgXS5zZWxlY3RlZEluZGV4XG5cdFx0XHQpO1xuXG5cdFx0Ly8gQXNzb2NpYXRlIGV4aXN0aW5nIGxhYmVsIHdpdGggdGhlIG5ldyBidXR0b25cblx0XHR0aGlzLmxhYmVscyA9IHRoaXMuZWxlbWVudC5sYWJlbHMoKS5hdHRyKCBcImZvclwiLCB0aGlzLmlkcy5idXR0b24gKTtcblx0XHR0aGlzLl9vbiggdGhpcy5sYWJlbHMsIHtcblx0XHRcdGNsaWNrOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdHRoaXMuYnV0dG9uLmZvY3VzKCk7XG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0Ly8gSGlkZSBvcmlnaW5hbCBzZWxlY3QgZWxlbWVudFxuXHRcdHRoaXMuZWxlbWVudC5oaWRlKCk7XG5cblx0XHQvLyBDcmVhdGUgYnV0dG9uXG5cdFx0dGhpcy5idXR0b24gPSAkKCBcIjxzcGFuPlwiLCB7XG5cdFx0XHR0YWJpbmRleDogdGhpcy5vcHRpb25zLmRpc2FibGVkID8gLTEgOiAwLFxuXHRcdFx0aWQ6IHRoaXMuaWRzLmJ1dHRvbixcblx0XHRcdHJvbGU6IFwiY29tYm9ib3hcIixcblx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcImZhbHNlXCIsXG5cdFx0XHRcImFyaWEtYXV0b2NvbXBsZXRlXCI6IFwibGlzdFwiLFxuXHRcdFx0XCJhcmlhLW93bnNcIjogdGhpcy5pZHMubWVudSxcblx0XHRcdFwiYXJpYS1oYXNwb3B1cFwiOiBcInRydWVcIixcblx0XHRcdHRpdGxlOiB0aGlzLmVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiIClcblx0XHR9IClcblx0XHRcdC5pbnNlcnRBZnRlciggdGhpcy5lbGVtZW50ICk7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5idXR0b24sIFwidWktc2VsZWN0bWVudS1idXR0b24gdWktc2VsZWN0bWVudS1idXR0b24tY2xvc2VkXCIsXG5cdFx0XHRcInVpLWJ1dHRvbiB1aS13aWRnZXRcIiApO1xuXG5cdFx0aWNvbiA9ICQoIFwiPHNwYW4+XCIgKS5hcHBlbmRUbyggdGhpcy5idXR0b24gKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggaWNvbiwgXCJ1aS1zZWxlY3RtZW51LWljb25cIiwgXCJ1aS1pY29uIFwiICsgdGhpcy5vcHRpb25zLmljb25zLmJ1dHRvbiApO1xuXHRcdHRoaXMuYnV0dG9uSXRlbSA9IHRoaXMuX3JlbmRlckJ1dHRvbkl0ZW0oIGl0ZW0gKVxuXHRcdFx0LmFwcGVuZFRvKCB0aGlzLmJ1dHRvbiApO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMud2lkdGggIT09IGZhbHNlICkge1xuXHRcdFx0dGhpcy5fcmVzaXplQnV0dG9uKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fb24oIHRoaXMuYnV0dG9uLCB0aGlzLl9idXR0b25FdmVudHMgKTtcblx0XHR0aGlzLmJ1dHRvbi5vbmUoIFwiZm9jdXNpblwiLCBmdW5jdGlvbigpIHtcblxuXHRcdFx0Ly8gRGVsYXkgcmVuZGVyaW5nIHRoZSBtZW51IGl0ZW1zIHVudGlsIHRoZSBidXR0b24gcmVjZWl2ZXMgZm9jdXMuXG5cdFx0XHQvLyBUaGUgbWVudSBtYXkgaGF2ZSBhbHJlYWR5IGJlZW4gcmVuZGVyZWQgdmlhIGEgcHJvZ3JhbW1hdGljIG9wZW4uXG5cdFx0XHRpZiAoICF0aGF0Ll9yZW5kZXJlZCApIHtcblx0XHRcdFx0dGhhdC5fcmVmcmVzaE1lbnUoKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X2RyYXdNZW51OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHQvLyBDcmVhdGUgbWVudVxuXHRcdHRoaXMubWVudSA9ICQoIFwiPHVsPlwiLCB7XG5cdFx0XHRcImFyaWEtaGlkZGVuXCI6IFwidHJ1ZVwiLFxuXHRcdFx0XCJhcmlhLWxhYmVsbGVkYnlcIjogdGhpcy5pZHMuYnV0dG9uLFxuXHRcdFx0aWQ6IHRoaXMuaWRzLm1lbnVcblx0XHR9ICk7XG5cblx0XHQvLyBXcmFwIG1lbnVcblx0XHR0aGlzLm1lbnVXcmFwID0gJCggXCI8ZGl2PlwiICkuYXBwZW5kKCB0aGlzLm1lbnUgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5tZW51V3JhcCwgXCJ1aS1zZWxlY3RtZW51LW1lbnVcIiwgXCJ1aS1mcm9udFwiICk7XG5cdFx0dGhpcy5tZW51V3JhcC5hcHBlbmRUbyggdGhpcy5fYXBwZW5kVG8oKSApO1xuXG5cdFx0Ly8gSW5pdGlhbGl6ZSBtZW51IHdpZGdldFxuXHRcdHRoaXMubWVudUluc3RhbmNlID0gdGhpcy5tZW51XG5cdFx0XHQubWVudSgge1xuXHRcdFx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcdFx0XCJ1aS1tZW51XCI6IFwidWktY29ybmVyLWJvdHRvbVwiXG5cdFx0XHRcdH0sXG5cdFx0XHRcdHJvbGU6IFwibGlzdGJveFwiLFxuXHRcdFx0XHRzZWxlY3Q6IGZ1bmN0aW9uKCBldmVudCwgdWkgKSB7XG5cdFx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuXHRcdFx0XHRcdC8vIFN1cHBvcnQ6IElFOFxuXHRcdFx0XHRcdC8vIElmIHRoZSBpdGVtIHdhcyBzZWxlY3RlZCB2aWEgYSBjbGljaywgdGhlIHRleHQgc2VsZWN0aW9uXG5cdFx0XHRcdFx0Ly8gd2lsbCBiZSBkZXN0cm95ZWQgaW4gSUVcblx0XHRcdFx0XHR0aGF0Ll9zZXRTZWxlY3Rpb24oKTtcblxuXHRcdFx0XHRcdHRoYXQuX3NlbGVjdCggdWkuaXRlbS5kYXRhKCBcInVpLXNlbGVjdG1lbnUtaXRlbVwiICksIGV2ZW50ICk7XG5cdFx0XHRcdH0sXG5cdFx0XHRcdGZvY3VzOiBmdW5jdGlvbiggZXZlbnQsIHVpICkge1xuXHRcdFx0XHRcdHZhciBpdGVtID0gdWkuaXRlbS5kYXRhKCBcInVpLXNlbGVjdG1lbnUtaXRlbVwiICk7XG5cblx0XHRcdFx0XHQvLyBQcmV2ZW50IGluaXRhbCBmb2N1cyBmcm9tIGZpcmluZyBhbmQgY2hlY2sgaWYgaXRzIGEgbmV3bHkgZm9jdXNlZCBpdGVtXG5cdFx0XHRcdFx0aWYgKCB0aGF0LmZvY3VzSW5kZXggIT0gbnVsbCAmJiBpdGVtLmluZGV4ICE9PSB0aGF0LmZvY3VzSW5kZXggKSB7XG5cdFx0XHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcImZvY3VzXCIsIGV2ZW50LCB7IGl0ZW06IGl0ZW0gfSApO1xuXHRcdFx0XHRcdFx0aWYgKCAhdGhhdC5pc09wZW4gKSB7XG5cdFx0XHRcdFx0XHRcdHRoYXQuX3NlbGVjdCggaXRlbSwgZXZlbnQgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0dGhhdC5mb2N1c0luZGV4ID0gaXRlbS5pbmRleDtcblxuXHRcdFx0XHRcdHRoYXQuYnV0dG9uLmF0dHIoIFwiYXJpYS1hY3RpdmVkZXNjZW5kYW50XCIsXG5cdFx0XHRcdFx0XHR0aGF0Lm1lbnVJdGVtcy5lcSggaXRlbS5pbmRleCApLmF0dHIoIFwiaWRcIiApICk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKVxuXHRcdFx0Lm1lbnUoIFwiaW5zdGFuY2VcIiApO1xuXG5cdFx0Ly8gRG9uJ3QgY2xvc2UgdGhlIG1lbnUgb24gbW91c2VsZWF2ZVxuXHRcdHRoaXMubWVudUluc3RhbmNlLl9vZmYoIHRoaXMubWVudSwgXCJtb3VzZWxlYXZlXCIgKTtcblxuXHRcdC8vIENhbmNlbCB0aGUgbWVudSdzIGNvbGxhcHNlQWxsIG9uIGRvY3VtZW50IGNsaWNrXG5cdFx0dGhpcy5tZW51SW5zdGFuY2UuX2Nsb3NlT25Eb2N1bWVudENsaWNrID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fTtcblxuXHRcdC8vIFNlbGVjdHMgb2Z0ZW4gY29udGFpbiBlbXB0eSBpdGVtcywgYnV0IG5ldmVyIGNvbnRhaW4gZGl2aWRlcnNcblx0XHR0aGlzLm1lbnVJbnN0YW5jZS5faXNEaXZpZGVyID0gZnVuY3Rpb24oKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fTtcblx0fSxcblxuXHRyZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9yZWZyZXNoTWVudSgpO1xuXHRcdHRoaXMuYnV0dG9uSXRlbS5yZXBsYWNlV2l0aChcblx0XHRcdHRoaXMuYnV0dG9uSXRlbSA9IHRoaXMuX3JlbmRlckJ1dHRvbkl0ZW0oXG5cblx0XHRcdFx0Ly8gRmFsbCBiYWNrIHRvIGFuIGVtcHR5IG9iamVjdCBpbiBjYXNlIHRoZXJlIGFyZSBubyBvcHRpb25zXG5cdFx0XHRcdHRoaXMuX2dldFNlbGVjdGVkSXRlbSgpLmRhdGEoIFwidWktc2VsZWN0bWVudS1pdGVtXCIgKSB8fCB7fVxuXHRcdFx0KVxuXHRcdCk7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMud2lkdGggPT09IG51bGwgKSB7XG5cdFx0XHR0aGlzLl9yZXNpemVCdXR0b24oKTtcblx0XHR9XG5cdH0sXG5cblx0X3JlZnJlc2hNZW51OiBmdW5jdGlvbigpIHtcblx0XHR2YXIgaXRlbSxcblx0XHRcdG9wdGlvbnMgPSB0aGlzLmVsZW1lbnQuZmluZCggXCJvcHRpb25cIiApO1xuXG5cdFx0dGhpcy5tZW51LmVtcHR5KCk7XG5cblx0XHR0aGlzLl9wYXJzZU9wdGlvbnMoIG9wdGlvbnMgKTtcblx0XHR0aGlzLl9yZW5kZXJNZW51KCB0aGlzLm1lbnUsIHRoaXMuaXRlbXMgKTtcblxuXHRcdHRoaXMubWVudUluc3RhbmNlLnJlZnJlc2goKTtcblx0XHR0aGlzLm1lbnVJdGVtcyA9IHRoaXMubWVudS5maW5kKCBcImxpXCIgKVxuXHRcdFx0Lm5vdCggXCIudWktc2VsZWN0bWVudS1vcHRncm91cFwiIClcblx0XHRcdFx0LmZpbmQoIFwiLnVpLW1lbnUtaXRlbS13cmFwcGVyXCIgKTtcblxuXHRcdHRoaXMuX3JlbmRlcmVkID0gdHJ1ZTtcblxuXHRcdGlmICggIW9wdGlvbnMubGVuZ3RoICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGl0ZW0gPSB0aGlzLl9nZXRTZWxlY3RlZEl0ZW0oKTtcblxuXHRcdC8vIFVwZGF0ZSB0aGUgbWVudSB0byBoYXZlIHRoZSBjb3JyZWN0IGl0ZW0gZm9jdXNlZFxuXHRcdHRoaXMubWVudUluc3RhbmNlLmZvY3VzKCBudWxsLCBpdGVtICk7XG5cdFx0dGhpcy5fc2V0QXJpYSggaXRlbS5kYXRhKCBcInVpLXNlbGVjdG1lbnUtaXRlbVwiICkgKTtcblxuXHRcdC8vIFNldCBkaXNhYmxlZCBzdGF0ZVxuXHRcdHRoaXMuX3NldE9wdGlvbiggXCJkaXNhYmxlZFwiLCB0aGlzLmVsZW1lbnQucHJvcCggXCJkaXNhYmxlZFwiICkgKTtcblx0fSxcblxuXHRvcGVuOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gSWYgdGhpcyBpcyB0aGUgZmlyc3QgdGltZSB0aGUgbWVudSBpcyBiZWluZyBvcGVuZWQsIHJlbmRlciB0aGUgaXRlbXNcblx0XHRpZiAoICF0aGlzLl9yZW5kZXJlZCApIHtcblx0XHRcdHRoaXMuX3JlZnJlc2hNZW51KCk7XG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gTWVudSBjbGVhcnMgZm9jdXMgb24gY2xvc2UsIHJlc2V0IGZvY3VzIHRvIHNlbGVjdGVkIGl0ZW1cblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLm1lbnUuZmluZCggXCIudWktc3RhdGUtYWN0aXZlXCIgKSwgbnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0dGhpcy5tZW51SW5zdGFuY2UuZm9jdXMoIG51bGwsIHRoaXMuX2dldFNlbGVjdGVkSXRlbSgpICk7XG5cdFx0fVxuXG5cdFx0Ly8gSWYgdGhlcmUgYXJlIG5vIG9wdGlvbnMsIGRvbid0IG9wZW4gdGhlIG1lbnVcblx0XHRpZiAoICF0aGlzLm1lbnVJdGVtcy5sZW5ndGggKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5pc09wZW4gPSB0cnVlO1xuXHRcdHRoaXMuX3RvZ2dsZUF0dHIoKTtcblx0XHR0aGlzLl9yZXNpemVNZW51KCk7XG5cdFx0dGhpcy5fcG9zaXRpb24oKTtcblxuXHRcdHRoaXMuX29uKCB0aGlzLmRvY3VtZW50LCB0aGlzLl9kb2N1bWVudENsaWNrICk7XG5cblx0XHR0aGlzLl90cmlnZ2VyKCBcIm9wZW5cIiwgZXZlbnQgKTtcblx0fSxcblxuXHRfcG9zaXRpb246IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMubWVudVdyYXAucG9zaXRpb24oICQuZXh0ZW5kKCB7IG9mOiB0aGlzLmJ1dHRvbiB9LCB0aGlzLm9wdGlvbnMucG9zaXRpb24gKSApO1xuXHR9LFxuXG5cdGNsb3NlOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCAhdGhpcy5pc09wZW4gKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy5pc09wZW4gPSBmYWxzZTtcblx0XHR0aGlzLl90b2dnbGVBdHRyKCk7XG5cblx0XHR0aGlzLnJhbmdlID0gbnVsbDtcblx0XHR0aGlzLl9vZmYoIHRoaXMuZG9jdW1lbnQgKTtcblxuXHRcdHRoaXMuX3RyaWdnZXIoIFwiY2xvc2VcIiwgZXZlbnQgKTtcblx0fSxcblxuXHR3aWRnZXQ6IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLmJ1dHRvbjtcblx0fSxcblxuXHRtZW51V2lkZ2V0OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5tZW51O1xuXHR9LFxuXG5cdF9yZW5kZXJCdXR0b25JdGVtOiBmdW5jdGlvbiggaXRlbSApIHtcblx0XHR2YXIgYnV0dG9uSXRlbSA9ICQoIFwiPHNwYW4+XCIgKTtcblxuXHRcdHRoaXMuX3NldFRleHQoIGJ1dHRvbkl0ZW0sIGl0ZW0ubGFiZWwgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggYnV0dG9uSXRlbSwgXCJ1aS1zZWxlY3RtZW51LXRleHRcIiApO1xuXG5cdFx0cmV0dXJuIGJ1dHRvbkl0ZW07XG5cdH0sXG5cblx0X3JlbmRlck1lbnU6IGZ1bmN0aW9uKCB1bCwgaXRlbXMgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzLFxuXHRcdFx0Y3VycmVudE9wdGdyb3VwID0gXCJcIjtcblxuXHRcdCQuZWFjaCggaXRlbXMsIGZ1bmN0aW9uKCBpbmRleCwgaXRlbSApIHtcblx0XHRcdHZhciBsaTtcblxuXHRcdFx0aWYgKCBpdGVtLm9wdGdyb3VwICE9PSBjdXJyZW50T3B0Z3JvdXAgKSB7XG5cdFx0XHRcdGxpID0gJCggXCI8bGk+XCIsIHtcblx0XHRcdFx0XHR0ZXh0OiBpdGVtLm9wdGdyb3VwXG5cdFx0XHRcdH0gKTtcblx0XHRcdFx0dGhhdC5fYWRkQ2xhc3MoIGxpLCBcInVpLXNlbGVjdG1lbnUtb3B0Z3JvdXBcIiwgXCJ1aS1tZW51LWRpdmlkZXJcIiArXG5cdFx0XHRcdFx0KCBpdGVtLmVsZW1lbnQucGFyZW50KCBcIm9wdGdyb3VwXCIgKS5wcm9wKCBcImRpc2FibGVkXCIgKSA/XG5cdFx0XHRcdFx0XHRcIiB1aS1zdGF0ZS1kaXNhYmxlZFwiIDpcblx0XHRcdFx0XHRcdFwiXCIgKSApO1xuXG5cdFx0XHRcdGxpLmFwcGVuZFRvKCB1bCApO1xuXG5cdFx0XHRcdGN1cnJlbnRPcHRncm91cCA9IGl0ZW0ub3B0Z3JvdXA7XG5cdFx0XHR9XG5cblx0XHRcdHRoYXQuX3JlbmRlckl0ZW1EYXRhKCB1bCwgaXRlbSApO1xuXHRcdH0gKTtcblx0fSxcblxuXHRfcmVuZGVySXRlbURhdGE6IGZ1bmN0aW9uKCB1bCwgaXRlbSApIHtcblx0XHRyZXR1cm4gdGhpcy5fcmVuZGVySXRlbSggdWwsIGl0ZW0gKS5kYXRhKCBcInVpLXNlbGVjdG1lbnUtaXRlbVwiLCBpdGVtICk7XG5cdH0sXG5cblx0X3JlbmRlckl0ZW06IGZ1bmN0aW9uKCB1bCwgaXRlbSApIHtcblx0XHR2YXIgbGkgPSAkKCBcIjxsaT5cIiApLFxuXHRcdFx0d3JhcHBlciA9ICQoIFwiPGRpdj5cIiwge1xuXHRcdFx0XHR0aXRsZTogaXRlbS5lbGVtZW50LmF0dHIoIFwidGl0bGVcIiApXG5cdFx0XHR9ICk7XG5cblx0XHRpZiAoIGl0ZW0uZGlzYWJsZWQgKSB7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggbGksIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiApO1xuXHRcdH1cblx0XHR0aGlzLl9zZXRUZXh0KCB3cmFwcGVyLCBpdGVtLmxhYmVsICk7XG5cblx0XHRyZXR1cm4gbGkuYXBwZW5kKCB3cmFwcGVyICkuYXBwZW5kVG8oIHVsICk7XG5cdH0sXG5cblx0X3NldFRleHQ6IGZ1bmN0aW9uKCBlbGVtZW50LCB2YWx1ZSApIHtcblx0XHRpZiAoIHZhbHVlICkge1xuXHRcdFx0ZWxlbWVudC50ZXh0KCB2YWx1ZSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRlbGVtZW50Lmh0bWwoIFwiJiMxNjA7XCIgKTtcblx0XHR9XG5cdH0sXG5cblx0X21vdmU6IGZ1bmN0aW9uKCBkaXJlY3Rpb24sIGV2ZW50ICkge1xuXHRcdHZhciBpdGVtLCBuZXh0LFxuXHRcdFx0ZmlsdGVyID0gXCIudWktbWVudS1pdGVtXCI7XG5cblx0XHRpZiAoIHRoaXMuaXNPcGVuICkge1xuXHRcdFx0aXRlbSA9IHRoaXMubWVudUl0ZW1zLmVxKCB0aGlzLmZvY3VzSW5kZXggKS5wYXJlbnQoIFwibGlcIiApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRpdGVtID0gdGhpcy5tZW51SXRlbXMuZXEoIHRoaXMuZWxlbWVudFsgMCBdLnNlbGVjdGVkSW5kZXggKS5wYXJlbnQoIFwibGlcIiApO1xuXHRcdFx0ZmlsdGVyICs9IFwiOm5vdCgudWktc3RhdGUtZGlzYWJsZWQpXCI7XG5cdFx0fVxuXG5cdFx0aWYgKCBkaXJlY3Rpb24gPT09IFwiZmlyc3RcIiB8fCBkaXJlY3Rpb24gPT09IFwibGFzdFwiICkge1xuXHRcdFx0bmV4dCA9IGl0ZW1bIGRpcmVjdGlvbiA9PT0gXCJmaXJzdFwiID8gXCJwcmV2QWxsXCIgOiBcIm5leHRBbGxcIiBdKCBmaWx0ZXIgKS5lcSggLTEgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0bmV4dCA9IGl0ZW1bIGRpcmVjdGlvbiArIFwiQWxsXCIgXSggZmlsdGVyICkuZXEoIDAgKTtcblx0XHR9XG5cblx0XHRpZiAoIG5leHQubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5tZW51SW5zdGFuY2UuZm9jdXMoIGV2ZW50LCBuZXh0ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9nZXRTZWxlY3RlZEl0ZW06IGZ1bmN0aW9uKCkge1xuXHRcdHJldHVybiB0aGlzLm1lbnVJdGVtcy5lcSggdGhpcy5lbGVtZW50WyAwIF0uc2VsZWN0ZWRJbmRleCApLnBhcmVudCggXCJsaVwiICk7XG5cdH0sXG5cblx0X3RvZ2dsZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHRoaXNbIHRoaXMuaXNPcGVuID8gXCJjbG9zZVwiIDogXCJvcGVuXCIgXSggZXZlbnQgKTtcblx0fSxcblxuXHRfc2V0U2VsZWN0aW9uOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgc2VsZWN0aW9uO1xuXG5cdFx0aWYgKCAhdGhpcy5yYW5nZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIHdpbmRvdy5nZXRTZWxlY3Rpb24gKSB7XG5cdFx0XHRzZWxlY3Rpb24gPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG5cdFx0XHRzZWxlY3Rpb24ucmVtb3ZlQWxsUmFuZ2VzKCk7XG5cdFx0XHRzZWxlY3Rpb24uYWRkUmFuZ2UoIHRoaXMucmFuZ2UgKTtcblxuXHRcdC8vIFN1cHBvcnQ6IElFOFxuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLnJhbmdlLnNlbGVjdCgpO1xuXHRcdH1cblxuXHRcdC8vIFN1cHBvcnQ6IElFXG5cdFx0Ly8gU2V0dGluZyB0aGUgdGV4dCBzZWxlY3Rpb24ga2lsbHMgdGhlIGJ1dHRvbiBmb2N1cyBpbiBJRSwgYnV0XG5cdFx0Ly8gcmVzdG9yaW5nIHRoZSBmb2N1cyBkb2Vzbid0IGtpbGwgdGhlIHNlbGVjdGlvbi5cblx0XHR0aGlzLmJ1dHRvbi5mb2N1cygpO1xuXHR9LFxuXG5cdF9kb2N1bWVudENsaWNrOiB7XG5cdFx0bW91c2Vkb3duOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRpZiAoICF0aGlzLmlzT3BlbiApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICEkKCBldmVudC50YXJnZXQgKS5jbG9zZXN0KCBcIi51aS1zZWxlY3RtZW51LW1lbnUsICNcIiArXG5cdFx0XHRcdFx0JC51aS5lc2NhcGVTZWxlY3RvciggdGhpcy5pZHMuYnV0dG9uICkgKS5sZW5ndGggKSB7XG5cdFx0XHRcdHRoaXMuY2xvc2UoIGV2ZW50ICk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdF9idXR0b25FdmVudHM6IHtcblxuXHRcdC8vIFByZXZlbnQgdGV4dCBzZWxlY3Rpb24gZnJvbSBiZWluZyByZXNldCB3aGVuIGludGVyYWN0aW5nIHdpdGggdGhlIHNlbGVjdG1lbnUgKCMxMDE0NClcblx0XHRtb3VzZWRvd246IGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHNlbGVjdGlvbjtcblxuXHRcdFx0aWYgKCB3aW5kb3cuZ2V0U2VsZWN0aW9uICkge1xuXHRcdFx0XHRzZWxlY3Rpb24gPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG5cdFx0XHRcdGlmICggc2VsZWN0aW9uLnJhbmdlQ291bnQgKSB7XG5cdFx0XHRcdFx0dGhpcy5yYW5nZSA9IHNlbGVjdGlvbi5nZXRSYW5nZUF0KCAwICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0Ly8gU3VwcG9ydDogSUU4XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLnJhbmdlID0gZG9jdW1lbnQuc2VsZWN0aW9uLmNyZWF0ZVJhbmdlKCk7XG5cdFx0XHR9XG5cdFx0fSxcblxuXHRcdGNsaWNrOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHR0aGlzLl9zZXRTZWxlY3Rpb24oKTtcblx0XHRcdHRoaXMuX3RvZ2dsZSggZXZlbnQgKTtcblx0XHR9LFxuXG5cdFx0a2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0dmFyIHByZXZlbnREZWZhdWx0ID0gdHJ1ZTtcblx0XHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5UQUI6XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5FU0NBUEU6XG5cdFx0XHRcdHRoaXMuY2xvc2UoIGV2ZW50ICk7XG5cdFx0XHRcdHByZXZlbnREZWZhdWx0ID0gZmFsc2U7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuRU5URVI6XG5cdFx0XHRcdGlmICggdGhpcy5pc09wZW4gKSB7XG5cdFx0XHRcdFx0dGhpcy5fc2VsZWN0Rm9jdXNlZEl0ZW0oIGV2ZW50ICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5VUDpcblx0XHRcdFx0aWYgKCBldmVudC5hbHRLZXkgKSB7XG5cdFx0XHRcdFx0dGhpcy5fdG9nZ2xlKCBldmVudCApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRoaXMuX21vdmUoIFwicHJldlwiLCBldmVudCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuRE9XTjpcblx0XHRcdFx0aWYgKCBldmVudC5hbHRLZXkgKSB7XG5cdFx0XHRcdFx0dGhpcy5fdG9nZ2xlKCBldmVudCApO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdHRoaXMuX21vdmUoIFwibmV4dFwiLCBldmVudCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuU1BBQ0U6XG5cdFx0XHRcdGlmICggdGhpcy5pc09wZW4gKSB7XG5cdFx0XHRcdFx0dGhpcy5fc2VsZWN0Rm9jdXNlZEl0ZW0oIGV2ZW50ICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0dGhpcy5fdG9nZ2xlKCBldmVudCApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuTEVGVDpcblx0XHRcdFx0dGhpcy5fbW92ZSggXCJwcmV2XCIsIGV2ZW50ICk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuUklHSFQ6XG5cdFx0XHRcdHRoaXMuX21vdmUoIFwibmV4dFwiLCBldmVudCApO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLkhPTUU6XG5cdFx0XHRjYXNlICQudWkua2V5Q29kZS5QQUdFX1VQOlxuXHRcdFx0XHR0aGlzLl9tb3ZlKCBcImZpcnN0XCIsIGV2ZW50ICk7XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuRU5EOlxuXHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuUEFHRV9ET1dOOlxuXHRcdFx0XHR0aGlzLl9tb3ZlKCBcImxhc3RcIiwgZXZlbnQgKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHR0aGlzLm1lbnUudHJpZ2dlciggZXZlbnQgKTtcblx0XHRcdFx0cHJldmVudERlZmF1bHQgPSBmYWxzZTtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCBwcmV2ZW50RGVmYXVsdCApIHtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X3NlbGVjdEZvY3VzZWRJdGVtOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGl0ZW0gPSB0aGlzLm1lbnVJdGVtcy5lcSggdGhpcy5mb2N1c0luZGV4ICkucGFyZW50KCBcImxpXCIgKTtcblx0XHRpZiAoICFpdGVtLmhhc0NsYXNzKCBcInVpLXN0YXRlLWRpc2FibGVkXCIgKSApIHtcblx0XHRcdHRoaXMuX3NlbGVjdCggaXRlbS5kYXRhKCBcInVpLXNlbGVjdG1lbnUtaXRlbVwiICksIGV2ZW50ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZWxlY3Q6IGZ1bmN0aW9uKCBpdGVtLCBldmVudCApIHtcblx0XHR2YXIgb2xkSW5kZXggPSB0aGlzLmVsZW1lbnRbIDAgXS5zZWxlY3RlZEluZGV4O1xuXG5cdFx0Ly8gQ2hhbmdlIG5hdGl2ZSBzZWxlY3QgZWxlbWVudFxuXHRcdHRoaXMuZWxlbWVudFsgMCBdLnNlbGVjdGVkSW5kZXggPSBpdGVtLmluZGV4O1xuXHRcdHRoaXMuYnV0dG9uSXRlbS5yZXBsYWNlV2l0aCggdGhpcy5idXR0b25JdGVtID0gdGhpcy5fcmVuZGVyQnV0dG9uSXRlbSggaXRlbSApICk7XG5cdFx0dGhpcy5fc2V0QXJpYSggaXRlbSApO1xuXHRcdHRoaXMuX3RyaWdnZXIoIFwic2VsZWN0XCIsIGV2ZW50LCB7IGl0ZW06IGl0ZW0gfSApO1xuXG5cdFx0aWYgKCBpdGVtLmluZGV4ICE9PSBvbGRJbmRleCApIHtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY2hhbmdlXCIsIGV2ZW50LCB7IGl0ZW06IGl0ZW0gfSApO1xuXHRcdH1cblxuXHRcdHRoaXMuY2xvc2UoIGV2ZW50ICk7XG5cdH0sXG5cblx0X3NldEFyaWE6IGZ1bmN0aW9uKCBpdGVtICkge1xuXHRcdHZhciBpZCA9IHRoaXMubWVudUl0ZW1zLmVxKCBpdGVtLmluZGV4ICkuYXR0ciggXCJpZFwiICk7XG5cblx0XHR0aGlzLmJ1dHRvbi5hdHRyKCB7XG5cdFx0XHRcImFyaWEtbGFiZWxsZWRieVwiOiBpZCxcblx0XHRcdFwiYXJpYS1hY3RpdmVkZXNjZW5kYW50XCI6IGlkXG5cdFx0fSApO1xuXHRcdHRoaXMubWVudS5hdHRyKCBcImFyaWEtYWN0aXZlZGVzY2VuZGFudFwiLCBpZCApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdGlmICgga2V5ID09PSBcImljb25zXCIgKSB7XG5cdFx0XHR2YXIgaWNvbiA9IHRoaXMuYnV0dG9uLmZpbmQoIFwic3Bhbi51aS1pY29uXCIgKTtcblx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBpY29uLCBudWxsLCB0aGlzLm9wdGlvbnMuaWNvbnMuYnV0dG9uIClcblx0XHRcdFx0Ll9hZGRDbGFzcyggaWNvbiwgbnVsbCwgdmFsdWUuYnV0dG9uICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3VwZXIoIGtleSwgdmFsdWUgKTtcblxuXHRcdGlmICgga2V5ID09PSBcImFwcGVuZFRvXCIgKSB7XG5cdFx0XHR0aGlzLm1lbnVXcmFwLmFwcGVuZFRvKCB0aGlzLl9hcHBlbmRUbygpICk7XG5cdFx0fVxuXG5cdFx0aWYgKCBrZXkgPT09IFwid2lkdGhcIiApIHtcblx0XHRcdHRoaXMuX3Jlc2l6ZUJ1dHRvbigpO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0T3B0aW9uRGlzYWJsZWQ6IGZ1bmN0aW9uKCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlciggdmFsdWUgKTtcblxuXHRcdHRoaXMubWVudUluc3RhbmNlLm9wdGlvbiggXCJkaXNhYmxlZFwiLCB2YWx1ZSApO1xuXHRcdHRoaXMuYnV0dG9uLmF0dHIoIFwiYXJpYS1kaXNhYmxlZFwiLCB2YWx1ZSApO1xuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCB0aGlzLmJ1dHRvbiwgbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiLCB2YWx1ZSApO1xuXG5cdFx0dGhpcy5lbGVtZW50LnByb3AoIFwiZGlzYWJsZWRcIiwgdmFsdWUgKTtcblx0XHRpZiAoIHZhbHVlICkge1xuXHRcdFx0dGhpcy5idXR0b24uYXR0ciggXCJ0YWJpbmRleFwiLCAtMSApO1xuXHRcdFx0dGhpcy5jbG9zZSgpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLmJ1dHRvbi5hdHRyKCBcInRhYmluZGV4XCIsIDAgKTtcblx0XHR9XG5cdH0sXG5cblx0X2FwcGVuZFRvOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgZWxlbWVudCA9IHRoaXMub3B0aW9ucy5hcHBlbmRUbztcblxuXHRcdGlmICggZWxlbWVudCApIHtcblx0XHRcdGVsZW1lbnQgPSBlbGVtZW50LmpxdWVyeSB8fCBlbGVtZW50Lm5vZGVUeXBlID9cblx0XHRcdFx0JCggZWxlbWVudCApIDpcblx0XHRcdFx0dGhpcy5kb2N1bWVudC5maW5kKCBlbGVtZW50ICkuZXEoIDAgKTtcblx0XHR9XG5cblx0XHRpZiAoICFlbGVtZW50IHx8ICFlbGVtZW50WyAwIF0gKSB7XG5cdFx0XHRlbGVtZW50ID0gdGhpcy5lbGVtZW50LmNsb3Nlc3QoIFwiLnVpLWZyb250LCBkaWFsb2dcIiApO1xuXHRcdH1cblxuXHRcdGlmICggIWVsZW1lbnQubGVuZ3RoICkge1xuXHRcdFx0ZWxlbWVudCA9IHRoaXMuZG9jdW1lbnRbIDAgXS5ib2R5O1xuXHRcdH1cblxuXHRcdHJldHVybiBlbGVtZW50O1xuXHR9LFxuXG5cdF90b2dnbGVBdHRyOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmJ1dHRvbi5hdHRyKCBcImFyaWEtZXhwYW5kZWRcIiwgdGhpcy5pc09wZW4gKTtcblxuXHRcdC8vIFdlIGNhbid0IHVzZSB0d28gX3RvZ2dsZUNsYXNzKCkgY2FsbHMgaGVyZSwgYmVjYXVzZSB3ZSBuZWVkIHRvIG1ha2Ugc3VyZVxuXHRcdC8vIHdlIGFsd2F5cyByZW1vdmUgY2xhc3NlcyBmaXJzdCBhbmQgYWRkIHRoZW0gc2Vjb25kLCBvdGhlcndpc2UgaWYgYm90aCBjbGFzc2VzIGhhdmUgdGhlXG5cdFx0Ly8gc2FtZSB0aGVtZSBjbGFzcywgaXQgd2lsbCBiZSByZW1vdmVkIGFmdGVyIHdlIGFkZCBpdC5cblx0XHR0aGlzLl9yZW1vdmVDbGFzcyggdGhpcy5idXR0b24sIFwidWktc2VsZWN0bWVudS1idXR0b24tXCIgK1xuXHRcdFx0KCB0aGlzLmlzT3BlbiA/IFwiY2xvc2VkXCIgOiBcIm9wZW5cIiApIClcblx0XHRcdC5fYWRkQ2xhc3MoIHRoaXMuYnV0dG9uLCBcInVpLXNlbGVjdG1lbnUtYnV0dG9uLVwiICtcblx0XHRcdFx0KCB0aGlzLmlzT3BlbiA/IFwib3BlblwiIDogXCJjbG9zZWRcIiApIClcblx0XHRcdC5fdG9nZ2xlQ2xhc3MoIHRoaXMubWVudVdyYXAsIFwidWktc2VsZWN0bWVudS1vcGVuXCIsIG51bGwsIHRoaXMuaXNPcGVuICk7XG5cblx0XHR0aGlzLm1lbnUuYXR0ciggXCJhcmlhLWhpZGRlblwiLCAhdGhpcy5pc09wZW4gKTtcblx0fSxcblxuXHRfcmVzaXplQnV0dG9uOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgd2lkdGggPSB0aGlzLm9wdGlvbnMud2lkdGg7XG5cblx0XHQvLyBGb3IgYHdpZHRoOiBmYWxzZWAsIGp1c3QgcmVtb3ZlIGlubGluZSBzdHlsZSBhbmQgc3RvcFxuXHRcdGlmICggd2lkdGggPT09IGZhbHNlICkge1xuXHRcdFx0dGhpcy5idXR0b24uY3NzKCBcIndpZHRoXCIsIFwiXCIgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBGb3IgYHdpZHRoOiBudWxsYCwgbWF0Y2ggdGhlIHdpZHRoIG9mIHRoZSBvcmlnaW5hbCBlbGVtZW50XG5cdFx0aWYgKCB3aWR0aCA9PT0gbnVsbCApIHtcblx0XHRcdHdpZHRoID0gdGhpcy5lbGVtZW50LnNob3coKS5vdXRlcldpZHRoKCk7XG5cdFx0XHR0aGlzLmVsZW1lbnQuaGlkZSgpO1xuXHRcdH1cblxuXHRcdHRoaXMuYnV0dG9uLm91dGVyV2lkdGgoIHdpZHRoICk7XG5cdH0sXG5cblx0X3Jlc2l6ZU1lbnU6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMubWVudS5vdXRlcldpZHRoKCBNYXRoLm1heChcblx0XHRcdHRoaXMuYnV0dG9uLm91dGVyV2lkdGgoKSxcblxuXHRcdFx0Ly8gU3VwcG9ydDogSUUxMFxuXHRcdFx0Ly8gSUUxMCB3cmFwcyBsb25nIHRleHQgKHBvc3NpYmx5IGEgcm91bmRpbmcgYnVnKVxuXHRcdFx0Ly8gc28gd2UgYWRkIDFweCB0byBhdm9pZCB0aGUgd3JhcHBpbmdcblx0XHRcdHRoaXMubWVudS53aWR0aCggXCJcIiApLm91dGVyV2lkdGgoKSArIDFcblx0XHQpICk7XG5cdH0sXG5cblx0X2dldENyZWF0ZU9wdGlvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5fc3VwZXIoKTtcblxuXHRcdG9wdGlvbnMuZGlzYWJsZWQgPSB0aGlzLmVsZW1lbnQucHJvcCggXCJkaXNhYmxlZFwiICk7XG5cblx0XHRyZXR1cm4gb3B0aW9ucztcblx0fSxcblxuXHRfcGFyc2VPcHRpb25zOiBmdW5jdGlvbiggb3B0aW9ucyApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRkYXRhID0gW107XG5cdFx0b3B0aW9ucy5lYWNoKCBmdW5jdGlvbiggaW5kZXgsIGl0ZW0gKSB7XG5cdFx0XHRkYXRhLnB1c2goIHRoYXQuX3BhcnNlT3B0aW9uKCAkKCBpdGVtICksIGluZGV4ICkgKTtcblx0XHR9ICk7XG5cdFx0dGhpcy5pdGVtcyA9IGRhdGE7XG5cdH0sXG5cblx0X3BhcnNlT3B0aW9uOiBmdW5jdGlvbiggb3B0aW9uLCBpbmRleCApIHtcblx0XHR2YXIgb3B0Z3JvdXAgPSBvcHRpb24ucGFyZW50KCBcIm9wdGdyb3VwXCIgKTtcblxuXHRcdHJldHVybiB7XG5cdFx0XHRlbGVtZW50OiBvcHRpb24sXG5cdFx0XHRpbmRleDogaW5kZXgsXG5cdFx0XHR2YWx1ZTogb3B0aW9uLnZhbCgpLFxuXHRcdFx0bGFiZWw6IG9wdGlvbi50ZXh0KCksXG5cdFx0XHRvcHRncm91cDogb3B0Z3JvdXAuYXR0ciggXCJsYWJlbFwiICkgfHwgXCJcIixcblx0XHRcdGRpc2FibGVkOiBvcHRncm91cC5wcm9wKCBcImRpc2FibGVkXCIgKSB8fCBvcHRpb24ucHJvcCggXCJkaXNhYmxlZFwiIClcblx0XHR9O1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl91bmJpbmRGb3JtUmVzZXRIYW5kbGVyKCk7XG5cdFx0dGhpcy5tZW51V3JhcC5yZW1vdmUoKTtcblx0XHR0aGlzLmJ1dHRvbi5yZW1vdmUoKTtcblx0XHR0aGlzLmVsZW1lbnQuc2hvdygpO1xuXHRcdHRoaXMuZWxlbWVudC5yZW1vdmVVbmlxdWVJZCgpO1xuXHRcdHRoaXMubGFiZWxzLmF0dHIoIFwiZm9yXCIsIHRoaXMuaWRzLmVsZW1lbnQgKTtcblx0fVxufSBdICk7XG5cblxuLyohXG4gKiBqUXVlcnkgVUkgU2xpZGVyIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBTbGlkZXJcbi8vPj5ncm91cDogV2lkZ2V0c1xuLy8+PmRlc2NyaXB0aW9uOiBEaXNwbGF5cyBhIGZsZXhpYmxlIHNsaWRlciB3aXRoIHJhbmdlcyBhbmQgYWNjZXNzaWJpbGl0eSB2aWEga2V5Ym9hcmQuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vc2xpZGVyL1xuLy8+PmRlbW9zOiBodHRwOi8vanF1ZXJ5dWkuY29tL3NsaWRlci9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL3NsaWRlci5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxudmFyIHdpZGdldHNTbGlkZXIgPSAkLndpZGdldCggXCJ1aS5zbGlkZXJcIiwgJC51aS5tb3VzZSwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHR3aWRnZXRFdmVudFByZWZpeDogXCJzbGlkZVwiLFxuXG5cdG9wdGlvbnM6IHtcblx0XHRhbmltYXRlOiBmYWxzZSxcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLXNsaWRlclwiOiBcInVpLWNvcm5lci1hbGxcIixcblx0XHRcdFwidWktc2xpZGVyLWhhbmRsZVwiOiBcInVpLWNvcm5lci1hbGxcIixcblxuXHRcdFx0Ly8gTm90ZTogdWktd2lkZ2V0LWhlYWRlciBpc24ndCB0aGUgbW9zdCBmaXR0aW5nbHkgc2VtYW50aWMgZnJhbWV3b3JrIGNsYXNzIGZvciB0aGlzXG5cdFx0XHQvLyBlbGVtZW50LCBidXQgd29ya2VkIGJlc3QgdmlzdWFsbHkgd2l0aCBhIHZhcmlldHkgb2YgdGhlbWVzXG5cdFx0XHRcInVpLXNsaWRlci1yYW5nZVwiOiBcInVpLWNvcm5lci1hbGwgdWktd2lkZ2V0LWhlYWRlclwiXG5cdFx0fSxcblx0XHRkaXN0YW5jZTogMCxcblx0XHRtYXg6IDEwMCxcblx0XHRtaW46IDAsXG5cdFx0b3JpZW50YXRpb246IFwiaG9yaXpvbnRhbFwiLFxuXHRcdHJhbmdlOiBmYWxzZSxcblx0XHRzdGVwOiAxLFxuXHRcdHZhbHVlOiAwLFxuXHRcdHZhbHVlczogbnVsbCxcblxuXHRcdC8vIENhbGxiYWNrc1xuXHRcdGNoYW5nZTogbnVsbCxcblx0XHRzbGlkZTogbnVsbCxcblx0XHRzdGFydDogbnVsbCxcblx0XHRzdG9wOiBudWxsXG5cdH0sXG5cblx0Ly8gTnVtYmVyIG9mIHBhZ2VzIGluIGEgc2xpZGVyXG5cdC8vIChob3cgbWFueSB0aW1lcyBjYW4geW91IHBhZ2UgdXAvZG93biB0byBnbyB0aHJvdWdoIHRoZSB3aG9sZSByYW5nZSlcblx0bnVtUGFnZXM6IDUsXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fa2V5U2xpZGluZyA9IGZhbHNlO1xuXHRcdHRoaXMuX21vdXNlU2xpZGluZyA9IGZhbHNlO1xuXHRcdHRoaXMuX2FuaW1hdGVPZmYgPSB0cnVlO1xuXHRcdHRoaXMuX2hhbmRsZUluZGV4ID0gbnVsbDtcblx0XHR0aGlzLl9kZXRlY3RPcmllbnRhdGlvbigpO1xuXHRcdHRoaXMuX21vdXNlSW5pdCgpO1xuXHRcdHRoaXMuX2NhbGN1bGF0ZU5ld01heCgpO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktc2xpZGVyIHVpLXNsaWRlci1cIiArIHRoaXMub3JpZW50YXRpb24sXG5cdFx0XHRcInVpLXdpZGdldCB1aS13aWRnZXQtY29udGVudFwiICk7XG5cblx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cblx0XHR0aGlzLl9hbmltYXRlT2ZmID0gZmFsc2U7XG5cdH0sXG5cblx0X3JlZnJlc2g6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX2NyZWF0ZVJhbmdlKCk7XG5cdFx0dGhpcy5fY3JlYXRlSGFuZGxlcygpO1xuXHRcdHRoaXMuX3NldHVwRXZlbnRzKCk7XG5cdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdH0sXG5cblx0X2NyZWF0ZUhhbmRsZXM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBpLCBoYW5kbGVDb3VudCxcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRleGlzdGluZ0hhbmRsZXMgPSB0aGlzLmVsZW1lbnQuZmluZCggXCIudWktc2xpZGVyLWhhbmRsZVwiICksXG5cdFx0XHRoYW5kbGUgPSBcIjxzcGFuIHRhYmluZGV4PScwJz48L3NwYW4+XCIsXG5cdFx0XHRoYW5kbGVzID0gW107XG5cblx0XHRoYW5kbGVDb3VudCA9ICggb3B0aW9ucy52YWx1ZXMgJiYgb3B0aW9ucy52YWx1ZXMubGVuZ3RoICkgfHwgMTtcblxuXHRcdGlmICggZXhpc3RpbmdIYW5kbGVzLmxlbmd0aCA+IGhhbmRsZUNvdW50ICkge1xuXHRcdFx0ZXhpc3RpbmdIYW5kbGVzLnNsaWNlKCBoYW5kbGVDb3VudCApLnJlbW92ZSgpO1xuXHRcdFx0ZXhpc3RpbmdIYW5kbGVzID0gZXhpc3RpbmdIYW5kbGVzLnNsaWNlKCAwLCBoYW5kbGVDb3VudCApO1xuXHRcdH1cblxuXHRcdGZvciAoIGkgPSBleGlzdGluZ0hhbmRsZXMubGVuZ3RoOyBpIDwgaGFuZGxlQ291bnQ7IGkrKyApIHtcblx0XHRcdGhhbmRsZXMucHVzaCggaGFuZGxlICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5oYW5kbGVzID0gZXhpc3RpbmdIYW5kbGVzLmFkZCggJCggaGFuZGxlcy5qb2luKCBcIlwiICkgKS5hcHBlbmRUbyggdGhpcy5lbGVtZW50ICkgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmhhbmRsZXMsIFwidWktc2xpZGVyLWhhbmRsZVwiLCBcInVpLXN0YXRlLWRlZmF1bHRcIiApO1xuXG5cdFx0dGhpcy5oYW5kbGUgPSB0aGlzLmhhbmRsZXMuZXEoIDAgKTtcblxuXHRcdHRoaXMuaGFuZGxlcy5lYWNoKCBmdW5jdGlvbiggaSApIHtcblx0XHRcdCQoIHRoaXMgKVxuXHRcdFx0XHQuZGF0YSggXCJ1aS1zbGlkZXItaGFuZGxlLWluZGV4XCIsIGkgKVxuXHRcdFx0XHQuYXR0ciggXCJ0YWJJbmRleFwiLCAwICk7XG5cdFx0fSApO1xuXHR9LFxuXG5cdF9jcmVhdGVSYW5nZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHRpZiAoIG9wdGlvbnMucmFuZ2UgKSB7XG5cdFx0XHRpZiAoIG9wdGlvbnMucmFuZ2UgPT09IHRydWUgKSB7XG5cdFx0XHRcdGlmICggIW9wdGlvbnMudmFsdWVzICkge1xuXHRcdFx0XHRcdG9wdGlvbnMudmFsdWVzID0gWyB0aGlzLl92YWx1ZU1pbigpLCB0aGlzLl92YWx1ZU1pbigpIF07XG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9wdGlvbnMudmFsdWVzLmxlbmd0aCAmJiBvcHRpb25zLnZhbHVlcy5sZW5ndGggIT09IDIgKSB7XG5cdFx0XHRcdFx0b3B0aW9ucy52YWx1ZXMgPSBbIG9wdGlvbnMudmFsdWVzWyAwIF0sIG9wdGlvbnMudmFsdWVzWyAwIF0gXTtcblx0XHRcdFx0fSBlbHNlIGlmICggJC5pc0FycmF5KCBvcHRpb25zLnZhbHVlcyApICkge1xuXHRcdFx0XHRcdG9wdGlvbnMudmFsdWVzID0gb3B0aW9ucy52YWx1ZXMuc2xpY2UoIDAgKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICF0aGlzLnJhbmdlIHx8ICF0aGlzLnJhbmdlLmxlbmd0aCApIHtcblx0XHRcdFx0dGhpcy5yYW5nZSA9ICQoIFwiPGRpdj5cIiApXG5cdFx0XHRcdFx0LmFwcGVuZFRvKCB0aGlzLmVsZW1lbnQgKTtcblxuXHRcdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5yYW5nZSwgXCJ1aS1zbGlkZXItcmFuZ2VcIiApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMucmFuZ2UsIFwidWktc2xpZGVyLXJhbmdlLW1pbiB1aS1zbGlkZXItcmFuZ2UtbWF4XCIgKTtcblxuXHRcdFx0XHQvLyBIYW5kbGUgcmFuZ2Ugc3dpdGNoaW5nIGZyb20gdHJ1ZSB0byBtaW4vbWF4XG5cdFx0XHRcdHRoaXMucmFuZ2UuY3NzKCB7XG5cdFx0XHRcdFx0XCJsZWZ0XCI6IFwiXCIsXG5cdFx0XHRcdFx0XCJib3R0b21cIjogXCJcIlxuXHRcdFx0XHR9ICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIG9wdGlvbnMucmFuZ2UgPT09IFwibWluXCIgfHwgb3B0aW9ucy5yYW5nZSA9PT0gXCJtYXhcIiApIHtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMucmFuZ2UsIFwidWktc2xpZGVyLXJhbmdlLVwiICsgb3B0aW9ucy5yYW5nZSApO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRpZiAoIHRoaXMucmFuZ2UgKSB7XG5cdFx0XHRcdHRoaXMucmFuZ2UucmVtb3ZlKCk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLnJhbmdlID0gbnVsbDtcblx0XHR9XG5cdH0sXG5cblx0X3NldHVwRXZlbnRzOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9vZmYoIHRoaXMuaGFuZGxlcyApO1xuXHRcdHRoaXMuX29uKCB0aGlzLmhhbmRsZXMsIHRoaXMuX2hhbmRsZUV2ZW50cyApO1xuXHRcdHRoaXMuX2hvdmVyYWJsZSggdGhpcy5oYW5kbGVzICk7XG5cdFx0dGhpcy5fZm9jdXNhYmxlKCB0aGlzLmhhbmRsZXMgKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5oYW5kbGVzLnJlbW92ZSgpO1xuXHRcdGlmICggdGhpcy5yYW5nZSApIHtcblx0XHRcdHRoaXMucmFuZ2UucmVtb3ZlKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fbW91c2VEZXN0cm95KCk7XG5cdH0sXG5cblx0X21vdXNlQ2FwdHVyZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBwb3NpdGlvbiwgbm9ybVZhbHVlLCBkaXN0YW5jZSwgY2xvc2VzdEhhbmRsZSwgaW5kZXgsIGFsbG93ZWQsIG9mZnNldCwgbW91c2VPdmVySGFuZGxlLFxuXHRcdFx0dGhhdCA9IHRoaXMsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0aWYgKCBvLmRpc2FibGVkICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHRoaXMuZWxlbWVudFNpemUgPSB7XG5cdFx0XHR3aWR0aDogdGhpcy5lbGVtZW50Lm91dGVyV2lkdGgoKSxcblx0XHRcdGhlaWdodDogdGhpcy5lbGVtZW50Lm91dGVySGVpZ2h0KClcblx0XHR9O1xuXHRcdHRoaXMuZWxlbWVudE9mZnNldCA9IHRoaXMuZWxlbWVudC5vZmZzZXQoKTtcblxuXHRcdHBvc2l0aW9uID0geyB4OiBldmVudC5wYWdlWCwgeTogZXZlbnQucGFnZVkgfTtcblx0XHRub3JtVmFsdWUgPSB0aGlzLl9ub3JtVmFsdWVGcm9tTW91c2UoIHBvc2l0aW9uICk7XG5cdFx0ZGlzdGFuY2UgPSB0aGlzLl92YWx1ZU1heCgpIC0gdGhpcy5fdmFsdWVNaW4oKSArIDE7XG5cdFx0dGhpcy5oYW5kbGVzLmVhY2goIGZ1bmN0aW9uKCBpICkge1xuXHRcdFx0dmFyIHRoaXNEaXN0YW5jZSA9IE1hdGguYWJzKCBub3JtVmFsdWUgLSB0aGF0LnZhbHVlcyggaSApICk7XG5cdFx0XHRpZiAoICggZGlzdGFuY2UgPiB0aGlzRGlzdGFuY2UgKSB8fFxuXHRcdFx0XHQoIGRpc3RhbmNlID09PSB0aGlzRGlzdGFuY2UgJiZcblx0XHRcdFx0XHQoIGkgPT09IHRoYXQuX2xhc3RDaGFuZ2VkVmFsdWUgfHwgdGhhdC52YWx1ZXMoIGkgKSA9PT0gby5taW4gKSApICkge1xuXHRcdFx0XHRkaXN0YW5jZSA9IHRoaXNEaXN0YW5jZTtcblx0XHRcdFx0Y2xvc2VzdEhhbmRsZSA9ICQoIHRoaXMgKTtcblx0XHRcdFx0aW5kZXggPSBpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdGFsbG93ZWQgPSB0aGlzLl9zdGFydCggZXZlbnQsIGluZGV4ICk7XG5cdFx0aWYgKCBhbGxvd2VkID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybiBmYWxzZTtcblx0XHR9XG5cdFx0dGhpcy5fbW91c2VTbGlkaW5nID0gdHJ1ZTtcblxuXHRcdHRoaXMuX2hhbmRsZUluZGV4ID0gaW5kZXg7XG5cblx0XHR0aGlzLl9hZGRDbGFzcyggY2xvc2VzdEhhbmRsZSwgbnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdGNsb3Nlc3RIYW5kbGUudHJpZ2dlciggXCJmb2N1c1wiICk7XG5cblx0XHRvZmZzZXQgPSBjbG9zZXN0SGFuZGxlLm9mZnNldCgpO1xuXHRcdG1vdXNlT3ZlckhhbmRsZSA9ICEkKCBldmVudC50YXJnZXQgKS5wYXJlbnRzKCkuYWRkQmFjaygpLmlzKCBcIi51aS1zbGlkZXItaGFuZGxlXCIgKTtcblx0XHR0aGlzLl9jbGlja09mZnNldCA9IG1vdXNlT3ZlckhhbmRsZSA/IHsgbGVmdDogMCwgdG9wOiAwIH0gOiB7XG5cdFx0XHRsZWZ0OiBldmVudC5wYWdlWCAtIG9mZnNldC5sZWZ0IC0gKCBjbG9zZXN0SGFuZGxlLndpZHRoKCkgLyAyICksXG5cdFx0XHR0b3A6IGV2ZW50LnBhZ2VZIC0gb2Zmc2V0LnRvcCAtXG5cdFx0XHRcdCggY2xvc2VzdEhhbmRsZS5oZWlnaHQoKSAvIDIgKSAtXG5cdFx0XHRcdCggcGFyc2VJbnQoIGNsb3Nlc3RIYW5kbGUuY3NzKCBcImJvcmRlclRvcFdpZHRoXCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHQoIHBhcnNlSW50KCBjbG9zZXN0SGFuZGxlLmNzcyggXCJib3JkZXJCb3R0b21XaWR0aFwiICksIDEwICkgfHwgMCApICtcblx0XHRcdFx0KCBwYXJzZUludCggY2xvc2VzdEhhbmRsZS5jc3MoIFwibWFyZ2luVG9wXCIgKSwgMTAgKSB8fCAwIClcblx0XHR9O1xuXG5cdFx0aWYgKCAhdGhpcy5oYW5kbGVzLmhhc0NsYXNzKCBcInVpLXN0YXRlLWhvdmVyXCIgKSApIHtcblx0XHRcdHRoaXMuX3NsaWRlKCBldmVudCwgaW5kZXgsIG5vcm1WYWx1ZSApO1xuXHRcdH1cblx0XHR0aGlzLl9hbmltYXRlT2ZmID0gdHJ1ZTtcblx0XHRyZXR1cm4gdHJ1ZTtcblx0fSxcblxuXHRfbW91c2VTdGFydDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRydWU7XG5cdH0sXG5cblx0X21vdXNlRHJhZzogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBwb3NpdGlvbiA9IHsgeDogZXZlbnQucGFnZVgsIHk6IGV2ZW50LnBhZ2VZIH0sXG5cdFx0XHRub3JtVmFsdWUgPSB0aGlzLl9ub3JtVmFsdWVGcm9tTW91c2UoIHBvc2l0aW9uICk7XG5cblx0XHR0aGlzLl9zbGlkZSggZXZlbnQsIHRoaXMuX2hhbmRsZUluZGV4LCBub3JtVmFsdWUgKTtcblxuXHRcdHJldHVybiBmYWxzZTtcblx0fSxcblxuXHRfbW91c2VTdG9wOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuaGFuZGxlcywgbnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdHRoaXMuX21vdXNlU2xpZGluZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5fc3RvcCggZXZlbnQsIHRoaXMuX2hhbmRsZUluZGV4ICk7XG5cdFx0dGhpcy5fY2hhbmdlKCBldmVudCwgdGhpcy5faGFuZGxlSW5kZXggKTtcblxuXHRcdHRoaXMuX2hhbmRsZUluZGV4ID0gbnVsbDtcblx0XHR0aGlzLl9jbGlja09mZnNldCA9IG51bGw7XG5cdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IGZhbHNlO1xuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9LFxuXG5cdF9kZXRlY3RPcmllbnRhdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5vcmllbnRhdGlvbiA9ICggdGhpcy5vcHRpb25zLm9yaWVudGF0aW9uID09PSBcInZlcnRpY2FsXCIgKSA/IFwidmVydGljYWxcIiA6IFwiaG9yaXpvbnRhbFwiO1xuXHR9LFxuXG5cdF9ub3JtVmFsdWVGcm9tTW91c2U6IGZ1bmN0aW9uKCBwb3NpdGlvbiApIHtcblx0XHR2YXIgcGl4ZWxUb3RhbCxcblx0XHRcdHBpeGVsTW91c2UsXG5cdFx0XHRwZXJjZW50TW91c2UsXG5cdFx0XHR2YWx1ZVRvdGFsLFxuXHRcdFx0dmFsdWVNb3VzZTtcblxuXHRcdGlmICggdGhpcy5vcmllbnRhdGlvbiA9PT0gXCJob3Jpem9udGFsXCIgKSB7XG5cdFx0XHRwaXhlbFRvdGFsID0gdGhpcy5lbGVtZW50U2l6ZS53aWR0aDtcblx0XHRcdHBpeGVsTW91c2UgPSBwb3NpdGlvbi54IC0gdGhpcy5lbGVtZW50T2Zmc2V0LmxlZnQgLVxuXHRcdFx0XHQoIHRoaXMuX2NsaWNrT2Zmc2V0ID8gdGhpcy5fY2xpY2tPZmZzZXQubGVmdCA6IDAgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0cGl4ZWxUb3RhbCA9IHRoaXMuZWxlbWVudFNpemUuaGVpZ2h0O1xuXHRcdFx0cGl4ZWxNb3VzZSA9IHBvc2l0aW9uLnkgLSB0aGlzLmVsZW1lbnRPZmZzZXQudG9wIC1cblx0XHRcdFx0KCB0aGlzLl9jbGlja09mZnNldCA/IHRoaXMuX2NsaWNrT2Zmc2V0LnRvcCA6IDAgKTtcblx0XHR9XG5cblx0XHRwZXJjZW50TW91c2UgPSAoIHBpeGVsTW91c2UgLyBwaXhlbFRvdGFsICk7XG5cdFx0aWYgKCBwZXJjZW50TW91c2UgPiAxICkge1xuXHRcdFx0cGVyY2VudE1vdXNlID0gMTtcblx0XHR9XG5cdFx0aWYgKCBwZXJjZW50TW91c2UgPCAwICkge1xuXHRcdFx0cGVyY2VudE1vdXNlID0gMDtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLm9yaWVudGF0aW9uID09PSBcInZlcnRpY2FsXCIgKSB7XG5cdFx0XHRwZXJjZW50TW91c2UgPSAxIC0gcGVyY2VudE1vdXNlO1xuXHRcdH1cblxuXHRcdHZhbHVlVG90YWwgPSB0aGlzLl92YWx1ZU1heCgpIC0gdGhpcy5fdmFsdWVNaW4oKTtcblx0XHR2YWx1ZU1vdXNlID0gdGhpcy5fdmFsdWVNaW4oKSArIHBlcmNlbnRNb3VzZSAqIHZhbHVlVG90YWw7XG5cblx0XHRyZXR1cm4gdGhpcy5fdHJpbUFsaWduVmFsdWUoIHZhbHVlTW91c2UgKTtcblx0fSxcblxuXHRfdWlIYXNoOiBmdW5jdGlvbiggaW5kZXgsIHZhbHVlLCB2YWx1ZXMgKSB7XG5cdFx0dmFyIHVpSGFzaCA9IHtcblx0XHRcdGhhbmRsZTogdGhpcy5oYW5kbGVzWyBpbmRleCBdLFxuXHRcdFx0aGFuZGxlSW5kZXg6IGluZGV4LFxuXHRcdFx0dmFsdWU6IHZhbHVlICE9PSB1bmRlZmluZWQgPyB2YWx1ZSA6IHRoaXMudmFsdWUoKVxuXHRcdH07XG5cblx0XHRpZiAoIHRoaXMuX2hhc011bHRpcGxlVmFsdWVzKCkgKSB7XG5cdFx0XHR1aUhhc2gudmFsdWUgPSB2YWx1ZSAhPT0gdW5kZWZpbmVkID8gdmFsdWUgOiB0aGlzLnZhbHVlcyggaW5kZXggKTtcblx0XHRcdHVpSGFzaC52YWx1ZXMgPSB2YWx1ZXMgfHwgdGhpcy52YWx1ZXMoKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdWlIYXNoO1xuXHR9LFxuXG5cdF9oYXNNdWx0aXBsZVZhbHVlczogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy52YWx1ZXMgJiYgdGhpcy5vcHRpb25zLnZhbHVlcy5sZW5ndGg7XG5cdH0sXG5cblx0X3N0YXJ0OiBmdW5jdGlvbiggZXZlbnQsIGluZGV4ICkge1xuXHRcdHJldHVybiB0aGlzLl90cmlnZ2VyKCBcInN0YXJ0XCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIGluZGV4ICkgKTtcblx0fSxcblxuXHRfc2xpZGU6IGZ1bmN0aW9uKCBldmVudCwgaW5kZXgsIG5ld1ZhbCApIHtcblx0XHR2YXIgYWxsb3dlZCwgb3RoZXJWYWwsXG5cdFx0XHRjdXJyZW50VmFsdWUgPSB0aGlzLnZhbHVlKCksXG5cdFx0XHRuZXdWYWx1ZXMgPSB0aGlzLnZhbHVlcygpO1xuXG5cdFx0aWYgKCB0aGlzLl9oYXNNdWx0aXBsZVZhbHVlcygpICkge1xuXHRcdFx0b3RoZXJWYWwgPSB0aGlzLnZhbHVlcyggaW5kZXggPyAwIDogMSApO1xuXHRcdFx0Y3VycmVudFZhbHVlID0gdGhpcy52YWx1ZXMoIGluZGV4ICk7XG5cblx0XHRcdGlmICggdGhpcy5vcHRpb25zLnZhbHVlcy5sZW5ndGggPT09IDIgJiYgdGhpcy5vcHRpb25zLnJhbmdlID09PSB0cnVlICkge1xuXHRcdFx0XHRuZXdWYWwgPSAgaW5kZXggPT09IDAgPyBNYXRoLm1pbiggb3RoZXJWYWwsIG5ld1ZhbCApIDogTWF0aC5tYXgoIG90aGVyVmFsLCBuZXdWYWwgKTtcblx0XHRcdH1cblxuXHRcdFx0bmV3VmFsdWVzWyBpbmRleCBdID0gbmV3VmFsO1xuXHRcdH1cblxuXHRcdGlmICggbmV3VmFsID09PSBjdXJyZW50VmFsdWUgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0YWxsb3dlZCA9IHRoaXMuX3RyaWdnZXIoIFwic2xpZGVcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCggaW5kZXgsIG5ld1ZhbCwgbmV3VmFsdWVzICkgKTtcblxuXHRcdC8vIEEgc2xpZGUgY2FuIGJlIGNhbmNlbGVkIGJ5IHJldHVybmluZyBmYWxzZSBmcm9tIHRoZSBzbGlkZSBjYWxsYmFja1xuXHRcdGlmICggYWxsb3dlZCA9PT0gZmFsc2UgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9oYXNNdWx0aXBsZVZhbHVlcygpICkge1xuXHRcdFx0dGhpcy52YWx1ZXMoIGluZGV4LCBuZXdWYWwgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy52YWx1ZSggbmV3VmFsICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zdG9wOiBmdW5jdGlvbiggZXZlbnQsIGluZGV4ICkge1xuXHRcdHRoaXMuX3RyaWdnZXIoIFwic3RvcFwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCBpbmRleCApICk7XG5cdH0sXG5cblx0X2NoYW5nZTogZnVuY3Rpb24oIGV2ZW50LCBpbmRleCApIHtcblx0XHRpZiAoICF0aGlzLl9rZXlTbGlkaW5nICYmICF0aGlzLl9tb3VzZVNsaWRpbmcgKSB7XG5cblx0XHRcdC8vc3RvcmUgdGhlIGxhc3QgY2hhbmdlZCB2YWx1ZSBpbmRleCBmb3IgcmVmZXJlbmNlIHdoZW4gaGFuZGxlcyBvdmVybGFwXG5cdFx0XHR0aGlzLl9sYXN0Q2hhbmdlZFZhbHVlID0gaW5kZXg7XG5cdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNoYW5nZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCBpbmRleCApICk7XG5cdFx0fVxuXHR9LFxuXG5cdHZhbHVlOiBmdW5jdGlvbiggbmV3VmFsdWUgKSB7XG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLnZhbHVlID0gdGhpcy5fdHJpbUFsaWduVmFsdWUoIG5ld1ZhbHVlICk7XG5cdFx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0XHRcdHRoaXMuX2NoYW5nZSggbnVsbCwgMCApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLl92YWx1ZSgpO1xuXHR9LFxuXG5cdHZhbHVlczogZnVuY3Rpb24oIGluZGV4LCBuZXdWYWx1ZSApIHtcblx0XHR2YXIgdmFscyxcblx0XHRcdG5ld1ZhbHVlcyxcblx0XHRcdGk7XG5cblx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggPiAxICkge1xuXHRcdFx0dGhpcy5vcHRpb25zLnZhbHVlc1sgaW5kZXggXSA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKCBuZXdWYWx1ZSApO1xuXHRcdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdFx0XHR0aGlzLl9jaGFuZ2UoIG51bGwsIGluZGV4ICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoICkge1xuXHRcdFx0aWYgKCAkLmlzQXJyYXkoIGFyZ3VtZW50c1sgMCBdICkgKSB7XG5cdFx0XHRcdHZhbHMgPSB0aGlzLm9wdGlvbnMudmFsdWVzO1xuXHRcdFx0XHRuZXdWYWx1ZXMgPSBhcmd1bWVudHNbIDAgXTtcblx0XHRcdFx0Zm9yICggaSA9IDA7IGkgPCB2YWxzLmxlbmd0aDsgaSArPSAxICkge1xuXHRcdFx0XHRcdHZhbHNbIGkgXSA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKCBuZXdWYWx1ZXNbIGkgXSApO1xuXHRcdFx0XHRcdHRoaXMuX2NoYW5nZSggbnVsbCwgaSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0aWYgKCB0aGlzLl9oYXNNdWx0aXBsZVZhbHVlcygpICkge1xuXHRcdFx0XHRcdHJldHVybiB0aGlzLl92YWx1ZXMoIGluZGV4ICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMudmFsdWUoKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5fdmFsdWVzKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb246IGZ1bmN0aW9uKCBrZXksIHZhbHVlICkge1xuXHRcdHZhciBpLFxuXHRcdFx0dmFsc0xlbmd0aCA9IDA7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJyYW5nZVwiICYmIHRoaXMub3B0aW9ucy5yYW5nZSA9PT0gdHJ1ZSApIHtcblx0XHRcdGlmICggdmFsdWUgPT09IFwibWluXCIgKSB7XG5cdFx0XHRcdHRoaXMub3B0aW9ucy52YWx1ZSA9IHRoaXMuX3ZhbHVlcyggMCApO1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMudmFsdWVzID0gbnVsbDtcblx0XHRcdH0gZWxzZSBpZiAoIHZhbHVlID09PSBcIm1heFwiICkge1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMudmFsdWUgPSB0aGlzLl92YWx1ZXMoIHRoaXMub3B0aW9ucy52YWx1ZXMubGVuZ3RoIC0gMSApO1xuXHRcdFx0XHR0aGlzLm9wdGlvbnMudmFsdWVzID0gbnVsbDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoICQuaXNBcnJheSggdGhpcy5vcHRpb25zLnZhbHVlcyApICkge1xuXHRcdFx0dmFsc0xlbmd0aCA9IHRoaXMub3B0aW9ucy52YWx1ZXMubGVuZ3RoO1xuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHRzd2l0Y2ggKCBrZXkgKSB7XG5cdFx0XHRjYXNlIFwib3JpZW50YXRpb25cIjpcblx0XHRcdFx0dGhpcy5fZGV0ZWN0T3JpZW50YXRpb24oKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIFwidWktc2xpZGVyLWhvcml6b250YWwgdWktc2xpZGVyLXZlcnRpY2FsXCIgKVxuXHRcdFx0XHRcdC5fYWRkQ2xhc3MoIFwidWktc2xpZGVyLVwiICsgdGhpcy5vcmllbnRhdGlvbiApO1xuXHRcdFx0XHR0aGlzLl9yZWZyZXNoVmFsdWUoKTtcblx0XHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMucmFuZ2UgKSB7XG5cdFx0XHRcdFx0dGhpcy5fcmVmcmVzaFJhbmdlKCB2YWx1ZSApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gUmVzZXQgcG9zaXRpb25pbmcgZnJvbSBwcmV2aW91cyBvcmllbnRhdGlvblxuXHRcdFx0XHR0aGlzLmhhbmRsZXMuY3NzKCB2YWx1ZSA9PT0gXCJob3Jpem9udGFsXCIgPyBcImJvdHRvbVwiIDogXCJsZWZ0XCIsIFwiXCIgKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlIFwidmFsdWVcIjpcblx0XHRcdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IHRydWU7XG5cdFx0XHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXHRcdFx0XHR0aGlzLl9jaGFuZ2UoIG51bGwsIDAgKTtcblx0XHRcdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IGZhbHNlO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgXCJ2YWx1ZXNcIjpcblx0XHRcdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IHRydWU7XG5cdFx0XHRcdHRoaXMuX3JlZnJlc2hWYWx1ZSgpO1xuXG5cdFx0XHRcdC8vIFN0YXJ0IGZyb20gdGhlIGxhc3QgaGFuZGxlIHRvIHByZXZlbnQgdW5yZWFjaGFibGUgaGFuZGxlcyAoIzkwNDYpXG5cdFx0XHRcdGZvciAoIGkgPSB2YWxzTGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHRcdFx0dGhpcy5fY2hhbmdlKCBudWxsLCBpICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IGZhbHNlO1xuXHRcdFx0XHRicmVhaztcblx0XHRcdGNhc2UgXCJzdGVwXCI6XG5cdFx0XHRjYXNlIFwibWluXCI6XG5cdFx0XHRjYXNlIFwibWF4XCI6XG5cdFx0XHRcdHRoaXMuX2FuaW1hdGVPZmYgPSB0cnVlO1xuXHRcdFx0XHR0aGlzLl9jYWxjdWxhdGVOZXdNYXgoKTtcblx0XHRcdFx0dGhpcy5fcmVmcmVzaFZhbHVlKCk7XG5cdFx0XHRcdHRoaXMuX2FuaW1hdGVPZmYgPSBmYWxzZTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHRjYXNlIFwicmFuZ2VcIjpcblx0XHRcdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IHRydWU7XG5cdFx0XHRcdHRoaXMuX3JlZnJlc2goKTtcblx0XHRcdFx0dGhpcy5fYW5pbWF0ZU9mZiA9IGZhbHNlO1xuXHRcdFx0XHRicmVhaztcblx0XHR9XG5cdH0sXG5cblx0X3NldE9wdGlvbkRpc2FibGVkOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIHZhbHVlICk7XG5cblx0XHR0aGlzLl90b2dnbGVDbGFzcyggbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiLCAhIXZhbHVlICk7XG5cdH0sXG5cblx0Ly9pbnRlcm5hbCB2YWx1ZSBnZXR0ZXJcblx0Ly8gX3ZhbHVlKCkgcmV0dXJucyB2YWx1ZSB0cmltbWVkIGJ5IG1pbiBhbmQgbWF4LCBhbGlnbmVkIGJ5IHN0ZXBcblx0X3ZhbHVlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdmFsID0gdGhpcy5vcHRpb25zLnZhbHVlO1xuXHRcdHZhbCA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKCB2YWwgKTtcblxuXHRcdHJldHVybiB2YWw7XG5cdH0sXG5cblx0Ly9pbnRlcm5hbCB2YWx1ZXMgZ2V0dGVyXG5cdC8vIF92YWx1ZXMoKSByZXR1cm5zIGFycmF5IG9mIHZhbHVlcyB0cmltbWVkIGJ5IG1pbiBhbmQgbWF4LCBhbGlnbmVkIGJ5IHN0ZXBcblx0Ly8gX3ZhbHVlcyggaW5kZXggKSByZXR1cm5zIHNpbmdsZSB2YWx1ZSB0cmltbWVkIGJ5IG1pbiBhbmQgbWF4LCBhbGlnbmVkIGJ5IHN0ZXBcblx0X3ZhbHVlczogZnVuY3Rpb24oIGluZGV4ICkge1xuXHRcdHZhciB2YWwsXG5cdFx0XHR2YWxzLFxuXHRcdFx0aTtcblxuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdHZhbCA9IHRoaXMub3B0aW9ucy52YWx1ZXNbIGluZGV4IF07XG5cdFx0XHR2YWwgPSB0aGlzLl90cmltQWxpZ25WYWx1ZSggdmFsICk7XG5cblx0XHRcdHJldHVybiB2YWw7XG5cdFx0fSBlbHNlIGlmICggdGhpcy5faGFzTXVsdGlwbGVWYWx1ZXMoKSApIHtcblxuXHRcdFx0Ly8gLnNsaWNlKCkgY3JlYXRlcyBhIGNvcHkgb2YgdGhlIGFycmF5XG5cdFx0XHQvLyB0aGlzIGNvcHkgZ2V0cyB0cmltbWVkIGJ5IG1pbiBhbmQgbWF4IGFuZCB0aGVuIHJldHVybmVkXG5cdFx0XHR2YWxzID0gdGhpcy5vcHRpb25zLnZhbHVlcy5zbGljZSgpO1xuXHRcdFx0Zm9yICggaSA9IDA7IGkgPCB2YWxzLmxlbmd0aDsgaSArPSAxICkge1xuXHRcdFx0XHR2YWxzWyBpIF0gPSB0aGlzLl90cmltQWxpZ25WYWx1ZSggdmFsc1sgaSBdICk7XG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB2YWxzO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRyZXR1cm4gW107XG5cdFx0fVxuXHR9LFxuXG5cdC8vIFJldHVybnMgdGhlIHN0ZXAtYWxpZ25lZCB2YWx1ZSB0aGF0IHZhbCBpcyBjbG9zZXN0IHRvLCBiZXR3ZWVuIChpbmNsdXNpdmUpIG1pbiBhbmQgbWF4XG5cdF90cmltQWxpZ25WYWx1ZTogZnVuY3Rpb24oIHZhbCApIHtcblx0XHRpZiAoIHZhbCA8PSB0aGlzLl92YWx1ZU1pbigpICkge1xuXHRcdFx0cmV0dXJuIHRoaXMuX3ZhbHVlTWluKCk7XG5cdFx0fVxuXHRcdGlmICggdmFsID49IHRoaXMuX3ZhbHVlTWF4KCkgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5fdmFsdWVNYXgoKTtcblx0XHR9XG5cdFx0dmFyIHN0ZXAgPSAoIHRoaXMub3B0aW9ucy5zdGVwID4gMCApID8gdGhpcy5vcHRpb25zLnN0ZXAgOiAxLFxuXHRcdFx0dmFsTW9kU3RlcCA9ICggdmFsIC0gdGhpcy5fdmFsdWVNaW4oKSApICUgc3RlcCxcblx0XHRcdGFsaWduVmFsdWUgPSB2YWwgLSB2YWxNb2RTdGVwO1xuXG5cdFx0aWYgKCBNYXRoLmFicyggdmFsTW9kU3RlcCApICogMiA+PSBzdGVwICkge1xuXHRcdFx0YWxpZ25WYWx1ZSArPSAoIHZhbE1vZFN0ZXAgPiAwICkgPyBzdGVwIDogKCAtc3RlcCApO1xuXHRcdH1cblxuXHRcdC8vIFNpbmNlIEphdmFTY3JpcHQgaGFzIHByb2JsZW1zIHdpdGggbGFyZ2UgZmxvYXRzLCByb3VuZFxuXHRcdC8vIHRoZSBmaW5hbCB2YWx1ZSB0byA1IGRpZ2l0cyBhZnRlciB0aGUgZGVjaW1hbCBwb2ludCAoc2VlICM0MTI0KVxuXHRcdHJldHVybiBwYXJzZUZsb2F0KCBhbGlnblZhbHVlLnRvRml4ZWQoIDUgKSApO1xuXHR9LFxuXG5cdF9jYWxjdWxhdGVOZXdNYXg6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBtYXggPSB0aGlzLm9wdGlvbnMubWF4LFxuXHRcdFx0bWluID0gdGhpcy5fdmFsdWVNaW4oKSxcblx0XHRcdHN0ZXAgPSB0aGlzLm9wdGlvbnMuc3RlcCxcblx0XHRcdGFib3ZlTWluID0gTWF0aC5yb3VuZCggKCBtYXggLSBtaW4gKSAvIHN0ZXAgKSAqIHN0ZXA7XG5cdFx0bWF4ID0gYWJvdmVNaW4gKyBtaW47XG5cdFx0aWYgKCBtYXggPiB0aGlzLm9wdGlvbnMubWF4ICkge1xuXG5cdFx0XHQvL0lmIG1heCBpcyBub3QgZGl2aXNpYmxlIGJ5IHN0ZXAsIHJvdW5kaW5nIG9mZiBtYXkgaW5jcmVhc2UgaXRzIHZhbHVlXG5cdFx0XHRtYXggLT0gc3RlcDtcblx0XHR9XG5cdFx0dGhpcy5tYXggPSBwYXJzZUZsb2F0KCBtYXgudG9GaXhlZCggdGhpcy5fcHJlY2lzaW9uKCkgKSApO1xuXHR9LFxuXG5cdF9wcmVjaXNpb246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBwcmVjaXNpb24gPSB0aGlzLl9wcmVjaXNpb25PZiggdGhpcy5vcHRpb25zLnN0ZXAgKTtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5taW4gIT09IG51bGwgKSB7XG5cdFx0XHRwcmVjaXNpb24gPSBNYXRoLm1heCggcHJlY2lzaW9uLCB0aGlzLl9wcmVjaXNpb25PZiggdGhpcy5vcHRpb25zLm1pbiApICk7XG5cdFx0fVxuXHRcdHJldHVybiBwcmVjaXNpb247XG5cdH0sXG5cblx0X3ByZWNpc2lvbk9mOiBmdW5jdGlvbiggbnVtICkge1xuXHRcdHZhciBzdHIgPSBudW0udG9TdHJpbmcoKSxcblx0XHRcdGRlY2ltYWwgPSBzdHIuaW5kZXhPZiggXCIuXCIgKTtcblx0XHRyZXR1cm4gZGVjaW1hbCA9PT0gLTEgPyAwIDogc3RyLmxlbmd0aCAtIGRlY2ltYWwgLSAxO1xuXHR9LFxuXG5cdF92YWx1ZU1pbjogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5taW47XG5cdH0sXG5cblx0X3ZhbHVlTWF4OiBmdW5jdGlvbigpIHtcblx0XHRyZXR1cm4gdGhpcy5tYXg7XG5cdH0sXG5cblx0X3JlZnJlc2hSYW5nZTogZnVuY3Rpb24oIG9yaWVudGF0aW9uICkge1xuXHRcdGlmICggb3JpZW50YXRpb24gPT09IFwidmVydGljYWxcIiApIHtcblx0XHRcdHRoaXMucmFuZ2UuY3NzKCB7IFwid2lkdGhcIjogXCJcIiwgXCJsZWZ0XCI6IFwiXCIgfSApO1xuXHRcdH1cblx0XHRpZiAoIG9yaWVudGF0aW9uID09PSBcImhvcml6b250YWxcIiApIHtcblx0XHRcdHRoaXMucmFuZ2UuY3NzKCB7IFwiaGVpZ2h0XCI6IFwiXCIsIFwiYm90dG9tXCI6IFwiXCIgfSApO1xuXHRcdH1cblx0fSxcblxuXHRfcmVmcmVzaFZhbHVlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgbGFzdFZhbFBlcmNlbnQsIHZhbFBlcmNlbnQsIHZhbHVlLCB2YWx1ZU1pbiwgdmFsdWVNYXgsXG5cdFx0XHRvUmFuZ2UgPSB0aGlzLm9wdGlvbnMucmFuZ2UsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0dGhhdCA9IHRoaXMsXG5cdFx0XHRhbmltYXRlID0gKCAhdGhpcy5fYW5pbWF0ZU9mZiApID8gby5hbmltYXRlIDogZmFsc2UsXG5cdFx0XHRfc2V0ID0ge307XG5cblx0XHRpZiAoIHRoaXMuX2hhc011bHRpcGxlVmFsdWVzKCkgKSB7XG5cdFx0XHR0aGlzLmhhbmRsZXMuZWFjaCggZnVuY3Rpb24oIGkgKSB7XG5cdFx0XHRcdHZhbFBlcmNlbnQgPSAoIHRoYXQudmFsdWVzKCBpICkgLSB0aGF0Ll92YWx1ZU1pbigpICkgLyAoIHRoYXQuX3ZhbHVlTWF4KCkgLVxuXHRcdFx0XHRcdHRoYXQuX3ZhbHVlTWluKCkgKSAqIDEwMDtcblx0XHRcdFx0X3NldFsgdGhhdC5vcmllbnRhdGlvbiA9PT0gXCJob3Jpem9udGFsXCIgPyBcImxlZnRcIiA6IFwiYm90dG9tXCIgXSA9IHZhbFBlcmNlbnQgKyBcIiVcIjtcblx0XHRcdFx0JCggdGhpcyApLnN0b3AoIDEsIDEgKVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCBfc2V0LCBvLmFuaW1hdGUgKTtcblx0XHRcdFx0aWYgKCB0aGF0Lm9wdGlvbnMucmFuZ2UgPT09IHRydWUgKSB7XG5cdFx0XHRcdFx0aWYgKCB0aGF0Lm9yaWVudGF0aW9uID09PSBcImhvcml6b250YWxcIiApIHtcblx0XHRcdFx0XHRcdGlmICggaSA9PT0gMCApIHtcblx0XHRcdFx0XHRcdFx0dGhhdC5yYW5nZS5zdG9wKCAxLCAxIClbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSgge1xuXHRcdFx0XHRcdFx0XHRcdGxlZnQ6IHZhbFBlcmNlbnQgKyBcIiVcIlxuXHRcdFx0XHRcdFx0XHR9LCBvLmFuaW1hdGUgKTtcblx0XHRcdFx0XHRcdH1cblx0XHRcdFx0XHRcdGlmICggaSA9PT0gMSApIHtcblx0XHRcdFx0XHRcdFx0dGhhdC5yYW5nZVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCB7XG5cdFx0XHRcdFx0XHRcdFx0d2lkdGg6ICggdmFsUGVyY2VudCAtIGxhc3RWYWxQZXJjZW50ICkgKyBcIiVcIlxuXHRcdFx0XHRcdFx0XHR9LCB7XG5cdFx0XHRcdFx0XHRcdFx0cXVldWU6IGZhbHNlLFxuXHRcdFx0XHRcdFx0XHRcdGR1cmF0aW9uOiBvLmFuaW1hdGVcblx0XHRcdFx0XHRcdFx0fSApO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0XHRpZiAoIGkgPT09IDAgKSB7XG5cdFx0XHRcdFx0XHRcdHRoYXQucmFuZ2Uuc3RvcCggMSwgMSApWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIHtcblx0XHRcdFx0XHRcdFx0XHRib3R0b206ICggdmFsUGVyY2VudCApICsgXCIlXCJcblx0XHRcdFx0XHRcdFx0fSwgby5hbmltYXRlICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0XHRpZiAoIGkgPT09IDEgKSB7XG5cdFx0XHRcdFx0XHRcdHRoYXQucmFuZ2VbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSgge1xuXHRcdFx0XHRcdFx0XHRcdGhlaWdodDogKCB2YWxQZXJjZW50IC0gbGFzdFZhbFBlcmNlbnQgKSArIFwiJVwiXG5cdFx0XHRcdFx0XHRcdH0sIHtcblx0XHRcdFx0XHRcdFx0XHRxdWV1ZTogZmFsc2UsXG5cdFx0XHRcdFx0XHRcdFx0ZHVyYXRpb246IG8uYW5pbWF0ZVxuXHRcdFx0XHRcdFx0XHR9ICk7XG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHRcdGxhc3RWYWxQZXJjZW50ID0gdmFsUGVyY2VudDtcblx0XHRcdH0gKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dmFsdWUgPSB0aGlzLnZhbHVlKCk7XG5cdFx0XHR2YWx1ZU1pbiA9IHRoaXMuX3ZhbHVlTWluKCk7XG5cdFx0XHR2YWx1ZU1heCA9IHRoaXMuX3ZhbHVlTWF4KCk7XG5cdFx0XHR2YWxQZXJjZW50ID0gKCB2YWx1ZU1heCAhPT0gdmFsdWVNaW4gKSA/XG5cdFx0XHRcdFx0KCB2YWx1ZSAtIHZhbHVlTWluICkgLyAoIHZhbHVlTWF4IC0gdmFsdWVNaW4gKSAqIDEwMCA6XG5cdFx0XHRcdFx0MDtcblx0XHRcdF9zZXRbIHRoaXMub3JpZW50YXRpb24gPT09IFwiaG9yaXpvbnRhbFwiID8gXCJsZWZ0XCIgOiBcImJvdHRvbVwiIF0gPSB2YWxQZXJjZW50ICsgXCIlXCI7XG5cdFx0XHR0aGlzLmhhbmRsZS5zdG9wKCAxLCAxIClbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSggX3NldCwgby5hbmltYXRlICk7XG5cblx0XHRcdGlmICggb1JhbmdlID09PSBcIm1pblwiICYmIHRoaXMub3JpZW50YXRpb24gPT09IFwiaG9yaXpvbnRhbFwiICkge1xuXHRcdFx0XHR0aGlzLnJhbmdlLnN0b3AoIDEsIDEgKVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCB7XG5cdFx0XHRcdFx0d2lkdGg6IHZhbFBlcmNlbnQgKyBcIiVcIlxuXHRcdFx0XHR9LCBvLmFuaW1hdGUgKTtcblx0XHRcdH1cblx0XHRcdGlmICggb1JhbmdlID09PSBcIm1heFwiICYmIHRoaXMub3JpZW50YXRpb24gPT09IFwiaG9yaXpvbnRhbFwiICkge1xuXHRcdFx0XHR0aGlzLnJhbmdlLnN0b3AoIDEsIDEgKVsgYW5pbWF0ZSA/IFwiYW5pbWF0ZVwiIDogXCJjc3NcIiBdKCB7XG5cdFx0XHRcdFx0d2lkdGg6ICggMTAwIC0gdmFsUGVyY2VudCApICsgXCIlXCJcblx0XHRcdFx0fSwgby5hbmltYXRlICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIG9SYW5nZSA9PT0gXCJtaW5cIiAmJiB0aGlzLm9yaWVudGF0aW9uID09PSBcInZlcnRpY2FsXCIgKSB7XG5cdFx0XHRcdHRoaXMucmFuZ2Uuc3RvcCggMSwgMSApWyBhbmltYXRlID8gXCJhbmltYXRlXCIgOiBcImNzc1wiIF0oIHtcblx0XHRcdFx0XHRoZWlnaHQ6IHZhbFBlcmNlbnQgKyBcIiVcIlxuXHRcdFx0XHR9LCBvLmFuaW1hdGUgKTtcblx0XHRcdH1cblx0XHRcdGlmICggb1JhbmdlID09PSBcIm1heFwiICYmIHRoaXMub3JpZW50YXRpb24gPT09IFwidmVydGljYWxcIiApIHtcblx0XHRcdFx0dGhpcy5yYW5nZS5zdG9wKCAxLCAxIClbIGFuaW1hdGUgPyBcImFuaW1hdGVcIiA6IFwiY3NzXCIgXSgge1xuXHRcdFx0XHRcdGhlaWdodDogKCAxMDAgLSB2YWxQZXJjZW50ICkgKyBcIiVcIlxuXHRcdFx0XHR9LCBvLmFuaW1hdGUgKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X2hhbmRsZUV2ZW50czoge1xuXHRcdGtleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdHZhciBhbGxvd2VkLCBjdXJWYWwsIG5ld1ZhbCwgc3RlcCxcblx0XHRcdFx0aW5kZXggPSAkKCBldmVudC50YXJnZXQgKS5kYXRhKCBcInVpLXNsaWRlci1oYW5kbGUtaW5kZXhcIiApO1xuXG5cdFx0XHRzd2l0Y2ggKCBldmVudC5rZXlDb2RlICkge1xuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5IT01FOlxuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5FTkQ6XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlBBR0VfVVA6XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlBBR0VfRE9XTjpcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuVVA6XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlJJR0hUOlxuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5ET1dOOlxuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5MRUZUOlxuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdFx0aWYgKCAhdGhpcy5fa2V5U2xpZGluZyApIHtcblx0XHRcdFx0XHRcdHRoaXMuX2tleVNsaWRpbmcgPSB0cnVlO1xuXHRcdFx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoICQoIGV2ZW50LnRhcmdldCApLCBudWxsLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHRcdFx0XHRhbGxvd2VkID0gdGhpcy5fc3RhcnQoIGV2ZW50LCBpbmRleCApO1xuXHRcdFx0XHRcdFx0aWYgKCBhbGxvd2VkID09PSBmYWxzZSApIHtcblx0XHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdFx0fVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRicmVhaztcblx0XHRcdH1cblxuXHRcdFx0c3RlcCA9IHRoaXMub3B0aW9ucy5zdGVwO1xuXHRcdFx0aWYgKCB0aGlzLl9oYXNNdWx0aXBsZVZhbHVlcygpICkge1xuXHRcdFx0XHRjdXJWYWwgPSBuZXdWYWwgPSB0aGlzLnZhbHVlcyggaW5kZXggKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGN1clZhbCA9IG5ld1ZhbCA9IHRoaXMudmFsdWUoKTtcblx0XHRcdH1cblxuXHRcdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuSE9NRTpcblx0XHRcdFx0XHRuZXdWYWwgPSB0aGlzLl92YWx1ZU1pbigpO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5FTkQ6XG5cdFx0XHRcdFx0bmV3VmFsID0gdGhpcy5fdmFsdWVNYXgoKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuUEFHRV9VUDpcblx0XHRcdFx0XHRuZXdWYWwgPSB0aGlzLl90cmltQWxpZ25WYWx1ZShcblx0XHRcdFx0XHRcdGN1clZhbCArICggKCB0aGlzLl92YWx1ZU1heCgpIC0gdGhpcy5fdmFsdWVNaW4oKSApIC8gdGhpcy5udW1QYWdlcyApXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuUEFHRV9ET1dOOlxuXHRcdFx0XHRcdG5ld1ZhbCA9IHRoaXMuX3RyaW1BbGlnblZhbHVlKFxuXHRcdFx0XHRcdFx0Y3VyVmFsIC0gKCAoIHRoaXMuX3ZhbHVlTWF4KCkgLSB0aGlzLl92YWx1ZU1pbigpICkgLyB0aGlzLm51bVBhZ2VzICkgKTtcblx0XHRcdFx0XHRicmVhaztcblx0XHRcdFx0Y2FzZSAkLnVpLmtleUNvZGUuVVA6XG5cdFx0XHRcdGNhc2UgJC51aS5rZXlDb2RlLlJJR0hUOlxuXHRcdFx0XHRcdGlmICggY3VyVmFsID09PSB0aGlzLl92YWx1ZU1heCgpICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRuZXdWYWwgPSB0aGlzLl90cmltQWxpZ25WYWx1ZSggY3VyVmFsICsgc3RlcCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5ET1dOOlxuXHRcdFx0XHRjYXNlICQudWkua2V5Q29kZS5MRUZUOlxuXHRcdFx0XHRcdGlmICggY3VyVmFsID09PSB0aGlzLl92YWx1ZU1pbigpICkge1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0XHRuZXdWYWwgPSB0aGlzLl90cmltQWxpZ25WYWx1ZSggY3VyVmFsIC0gc3RlcCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl9zbGlkZSggZXZlbnQsIGluZGV4LCBuZXdWYWwgKTtcblx0XHR9LFxuXHRcdGtleXVwOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHR2YXIgaW5kZXggPSAkKCBldmVudC50YXJnZXQgKS5kYXRhKCBcInVpLXNsaWRlci1oYW5kbGUtaW5kZXhcIiApO1xuXG5cdFx0XHRpZiAoIHRoaXMuX2tleVNsaWRpbmcgKSB7XG5cdFx0XHRcdHRoaXMuX2tleVNsaWRpbmcgPSBmYWxzZTtcblx0XHRcdFx0dGhpcy5fc3RvcCggZXZlbnQsIGluZGV4ICk7XG5cdFx0XHRcdHRoaXMuX2NoYW5nZSggZXZlbnQsIGluZGV4ICk7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCAkKCBldmVudC50YXJnZXQgKSwgbnVsbCwgXCJ1aS1zdGF0ZS1hY3RpdmVcIiApO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufSApO1xuXG5cbi8qIVxuICogalF1ZXJ5IFVJIFNvcnRhYmxlIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBTb3J0YWJsZVxuLy8+Pmdyb3VwOiBJbnRlcmFjdGlvbnNcbi8vPj5kZXNjcmlwdGlvbjogRW5hYmxlcyBpdGVtcyBpbiBhIGxpc3QgdG8gYmUgc29ydGVkIHVzaW5nIHRoZSBtb3VzZS5cbi8vPj5kb2NzOiBodHRwOi8vYXBpLmpxdWVyeXVpLmNvbS9zb3J0YWJsZS9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS9zb3J0YWJsZS9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9zb3J0YWJsZS5jc3NcblxuXG5cbnZhciB3aWRnZXRzU29ydGFibGUgPSAkLndpZGdldCggXCJ1aS5zb3J0YWJsZVwiLCAkLnVpLm1vdXNlLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdHdpZGdldEV2ZW50UHJlZml4OiBcInNvcnRcIixcblx0cmVhZHk6IGZhbHNlLFxuXHRvcHRpb25zOiB7XG5cdFx0YXBwZW5kVG86IFwicGFyZW50XCIsXG5cdFx0YXhpczogZmFsc2UsXG5cdFx0Y29ubmVjdFdpdGg6IGZhbHNlLFxuXHRcdGNvbnRhaW5tZW50OiBmYWxzZSxcblx0XHRjdXJzb3I6IFwiYXV0b1wiLFxuXHRcdGN1cnNvckF0OiBmYWxzZSxcblx0XHRkcm9wT25FbXB0eTogdHJ1ZSxcblx0XHRmb3JjZVBsYWNlaG9sZGVyU2l6ZTogZmFsc2UsXG5cdFx0Zm9yY2VIZWxwZXJTaXplOiBmYWxzZSxcblx0XHRncmlkOiBmYWxzZSxcblx0XHRoYW5kbGU6IGZhbHNlLFxuXHRcdGhlbHBlcjogXCJvcmlnaW5hbFwiLFxuXHRcdGl0ZW1zOiBcIj4gKlwiLFxuXHRcdG9wYWNpdHk6IGZhbHNlLFxuXHRcdHBsYWNlaG9sZGVyOiBmYWxzZSxcblx0XHRyZXZlcnQ6IGZhbHNlLFxuXHRcdHNjcm9sbDogdHJ1ZSxcblx0XHRzY3JvbGxTZW5zaXRpdml0eTogMjAsXG5cdFx0c2Nyb2xsU3BlZWQ6IDIwLFxuXHRcdHNjb3BlOiBcImRlZmF1bHRcIixcblx0XHR0b2xlcmFuY2U6IFwiaW50ZXJzZWN0XCIsXG5cdFx0ekluZGV4OiAxMDAwLFxuXG5cdFx0Ly8gQ2FsbGJhY2tzXG5cdFx0YWN0aXZhdGU6IG51bGwsXG5cdFx0YmVmb3JlU3RvcDogbnVsbCxcblx0XHRjaGFuZ2U6IG51bGwsXG5cdFx0ZGVhY3RpdmF0ZTogbnVsbCxcblx0XHRvdXQ6IG51bGwsXG5cdFx0b3ZlcjogbnVsbCxcblx0XHRyZWNlaXZlOiBudWxsLFxuXHRcdHJlbW92ZTogbnVsbCxcblx0XHRzb3J0OiBudWxsLFxuXHRcdHN0YXJ0OiBudWxsLFxuXHRcdHN0b3A6IG51bGwsXG5cdFx0dXBkYXRlOiBudWxsXG5cdH0sXG5cblx0X2lzT3ZlckF4aXM6IGZ1bmN0aW9uKCB4LCByZWZlcmVuY2UsIHNpemUgKSB7XG5cdFx0cmV0dXJuICggeCA+PSByZWZlcmVuY2UgKSAmJiAoIHggPCAoIHJlZmVyZW5jZSArIHNpemUgKSApO1xuXHR9LFxuXG5cdF9pc0Zsb2F0aW5nOiBmdW5jdGlvbiggaXRlbSApIHtcblx0XHRyZXR1cm4gKCAvbGVmdHxyaWdodC8gKS50ZXN0KCBpdGVtLmNzcyggXCJmbG9hdFwiICkgKSB8fFxuXHRcdFx0KCAvaW5saW5lfHRhYmxlLWNlbGwvICkudGVzdCggaXRlbS5jc3MoIFwiZGlzcGxheVwiICkgKTtcblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmNvbnRhaW5lckNhY2hlID0ge307XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIFwidWktc29ydGFibGVcIiApO1xuXG5cdFx0Ly9HZXQgdGhlIGl0ZW1zXG5cdFx0dGhpcy5yZWZyZXNoKCk7XG5cblx0XHQvL0xldCdzIGRldGVybWluZSB0aGUgcGFyZW50J3Mgb2Zmc2V0XG5cdFx0dGhpcy5vZmZzZXQgPSB0aGlzLmVsZW1lbnQub2Zmc2V0KCk7XG5cblx0XHQvL0luaXRpYWxpemUgbW91c2UgZXZlbnRzIGZvciBpbnRlcmFjdGlvblxuXHRcdHRoaXMuX21vdXNlSW5pdCgpO1xuXG5cdFx0dGhpcy5fc2V0SGFuZGxlQ2xhc3NOYW1lKCk7XG5cblx0XHQvL1dlJ3JlIHJlYWR5IHRvIGdvXG5cdFx0dGhpcy5yZWFkeSA9IHRydWU7XG5cblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiaGFuZGxlXCIgKSB7XG5cdFx0XHR0aGlzLl9zZXRIYW5kbGVDbGFzc05hbWUoKTtcblx0XHR9XG5cdH0sXG5cblx0X3NldEhhbmRsZUNsYXNzTmFtZTogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXHRcdHRoaXMuX3JlbW92ZUNsYXNzKCB0aGlzLmVsZW1lbnQuZmluZCggXCIudWktc29ydGFibGUtaGFuZGxlXCIgKSwgXCJ1aS1zb3J0YWJsZS1oYW5kbGVcIiApO1xuXHRcdCQuZWFjaCggdGhpcy5pdGVtcywgZnVuY3Rpb24oKSB7XG5cdFx0XHR0aGF0Ll9hZGRDbGFzcyhcblx0XHRcdFx0dGhpcy5pbnN0YW5jZS5vcHRpb25zLmhhbmRsZSA/XG5cdFx0XHRcdFx0dGhpcy5pdGVtLmZpbmQoIHRoaXMuaW5zdGFuY2Uub3B0aW9ucy5oYW5kbGUgKSA6XG5cdFx0XHRcdFx0dGhpcy5pdGVtLFxuXHRcdFx0XHRcInVpLXNvcnRhYmxlLWhhbmRsZVwiXG5cdFx0XHQpO1xuXHRcdH0gKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fbW91c2VEZXN0cm95KCk7XG5cblx0XHRmb3IgKCB2YXIgaSA9IHRoaXMuaXRlbXMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHR0aGlzLml0ZW1zWyBpIF0uaXRlbS5yZW1vdmVEYXRhKCB0aGlzLndpZGdldE5hbWUgKyBcIi1pdGVtXCIgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRfbW91c2VDYXB0dXJlOiBmdW5jdGlvbiggZXZlbnQsIG92ZXJyaWRlSGFuZGxlICkge1xuXHRcdHZhciBjdXJyZW50SXRlbSA9IG51bGwsXG5cdFx0XHR2YWxpZEhhbmRsZSA9IGZhbHNlLFxuXHRcdFx0dGhhdCA9IHRoaXM7XG5cblx0XHRpZiAoIHRoaXMucmV2ZXJ0aW5nICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vcHRpb25zLmRpc2FibGVkIHx8IHRoaXMub3B0aW9ucy50eXBlID09PSBcInN0YXRpY1wiICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vV2UgaGF2ZSB0byByZWZyZXNoIHRoZSBpdGVtcyBkYXRhIG9uY2UgZmlyc3Rcblx0XHR0aGlzLl9yZWZyZXNoSXRlbXMoIGV2ZW50ICk7XG5cblx0XHQvL0ZpbmQgb3V0IGlmIHRoZSBjbGlja2VkIG5vZGUgKG9yIG9uZSBvZiBpdHMgcGFyZW50cykgaXMgYSBhY3R1YWwgaXRlbSBpbiB0aGlzLml0ZW1zXG5cdFx0JCggZXZlbnQudGFyZ2V0ICkucGFyZW50cygpLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0aWYgKCAkLmRhdGEoIHRoaXMsIHRoYXQud2lkZ2V0TmFtZSArIFwiLWl0ZW1cIiApID09PSB0aGF0ICkge1xuXHRcdFx0XHRjdXJyZW50SXRlbSA9ICQoIHRoaXMgKTtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XHRpZiAoICQuZGF0YSggZXZlbnQudGFyZ2V0LCB0aGF0LndpZGdldE5hbWUgKyBcIi1pdGVtXCIgKSA9PT0gdGhhdCApIHtcblx0XHRcdGN1cnJlbnRJdGVtID0gJCggZXZlbnQudGFyZ2V0ICk7XG5cdFx0fVxuXG5cdFx0aWYgKCAhY3VycmVudEl0ZW0gKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5vcHRpb25zLmhhbmRsZSAmJiAhb3ZlcnJpZGVIYW5kbGUgKSB7XG5cdFx0XHQkKCB0aGlzLm9wdGlvbnMuaGFuZGxlLCBjdXJyZW50SXRlbSApLmZpbmQoIFwiKlwiICkuYWRkQmFjaygpLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoIHRoaXMgPT09IGV2ZW50LnRhcmdldCApIHtcblx0XHRcdFx0XHR2YWxpZEhhbmRsZSA9IHRydWU7XG5cdFx0XHRcdH1cblx0XHRcdH0gKTtcblx0XHRcdGlmICggIXZhbGlkSGFuZGxlICkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5jdXJyZW50SXRlbSA9IGN1cnJlbnRJdGVtO1xuXHRcdHRoaXMuX3JlbW92ZUN1cnJlbnRzRnJvbUl0ZW1zKCk7XG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fSxcblxuXHRfbW91c2VTdGFydDogZnVuY3Rpb24oIGV2ZW50LCBvdmVycmlkZUhhbmRsZSwgbm9BY3RpdmF0aW9uICkge1xuXG5cdFx0dmFyIGksIGJvZHksXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zO1xuXG5cdFx0dGhpcy5jdXJyZW50Q29udGFpbmVyID0gdGhpcztcblxuXHRcdC8vV2Ugb25seSBuZWVkIHRvIGNhbGwgcmVmcmVzaFBvc2l0aW9ucywgYmVjYXVzZSB0aGUgcmVmcmVzaEl0ZW1zIGNhbGwgaGFzIGJlZW4gbW92ZWQgdG9cblx0XHQvLyBtb3VzZUNhcHR1cmVcblx0XHR0aGlzLnJlZnJlc2hQb3NpdGlvbnMoKTtcblxuXHRcdC8vQ3JlYXRlIGFuZCBhcHBlbmQgdGhlIHZpc2libGUgaGVscGVyXG5cdFx0dGhpcy5oZWxwZXIgPSB0aGlzLl9jcmVhdGVIZWxwZXIoIGV2ZW50ICk7XG5cblx0XHQvL0NhY2hlIHRoZSBoZWxwZXIgc2l6ZVxuXHRcdHRoaXMuX2NhY2hlSGVscGVyUHJvcG9ydGlvbnMoKTtcblxuXHRcdC8qXG5cdFx0ICogLSBQb3NpdGlvbiBnZW5lcmF0aW9uIC1cblx0XHQgKiBUaGlzIGJsb2NrIGdlbmVyYXRlcyBldmVyeXRoaW5nIHBvc2l0aW9uIHJlbGF0ZWQgLSBpdCdzIHRoZSBjb3JlIG9mIGRyYWdnYWJsZXMuXG5cdFx0ICovXG5cblx0XHQvL0NhY2hlIHRoZSBtYXJnaW5zIG9mIHRoZSBvcmlnaW5hbCBlbGVtZW50XG5cdFx0dGhpcy5fY2FjaGVNYXJnaW5zKCk7XG5cblx0XHQvL0dldCB0aGUgbmV4dCBzY3JvbGxpbmcgcGFyZW50XG5cdFx0dGhpcy5zY3JvbGxQYXJlbnQgPSB0aGlzLmhlbHBlci5zY3JvbGxQYXJlbnQoKTtcblxuXHRcdC8vVGhlIGVsZW1lbnQncyBhYnNvbHV0ZSBwb3NpdGlvbiBvbiB0aGUgcGFnZSBtaW51cyBtYXJnaW5zXG5cdFx0dGhpcy5vZmZzZXQgPSB0aGlzLmN1cnJlbnRJdGVtLm9mZnNldCgpO1xuXHRcdHRoaXMub2Zmc2V0ID0ge1xuXHRcdFx0dG9wOiB0aGlzLm9mZnNldC50b3AgLSB0aGlzLm1hcmdpbnMudG9wLFxuXHRcdFx0bGVmdDogdGhpcy5vZmZzZXQubGVmdCAtIHRoaXMubWFyZ2lucy5sZWZ0XG5cdFx0fTtcblxuXHRcdCQuZXh0ZW5kKCB0aGlzLm9mZnNldCwge1xuXHRcdFx0Y2xpY2s6IHsgLy9XaGVyZSB0aGUgY2xpY2sgaGFwcGVuZWQsIHJlbGF0aXZlIHRvIHRoZSBlbGVtZW50XG5cdFx0XHRcdGxlZnQ6IGV2ZW50LnBhZ2VYIC0gdGhpcy5vZmZzZXQubGVmdCxcblx0XHRcdFx0dG9wOiBldmVudC5wYWdlWSAtIHRoaXMub2Zmc2V0LnRvcFxuXHRcdFx0fSxcblx0XHRcdHBhcmVudDogdGhpcy5fZ2V0UGFyZW50T2Zmc2V0KCksXG5cblx0XHRcdC8vIFRoaXMgaXMgYSByZWxhdGl2ZSB0byBhYnNvbHV0ZSBwb3NpdGlvbiBtaW51cyB0aGUgYWN0dWFsIHBvc2l0aW9uIGNhbGN1bGF0aW9uIC1cblx0XHRcdC8vIG9ubHkgdXNlZCBmb3IgcmVsYXRpdmUgcG9zaXRpb25lZCBoZWxwZXJcblx0XHRcdHJlbGF0aXZlOiB0aGlzLl9nZXRSZWxhdGl2ZU9mZnNldCgpXG5cdFx0fSApO1xuXG5cdFx0Ly8gT25seSBhZnRlciB3ZSBnb3QgdGhlIG9mZnNldCwgd2UgY2FuIGNoYW5nZSB0aGUgaGVscGVyJ3MgcG9zaXRpb24gdG8gYWJzb2x1dGVcblx0XHQvLyBUT0RPOiBTdGlsbCBuZWVkIHRvIGZpZ3VyZSBvdXQgYSB3YXkgdG8gbWFrZSByZWxhdGl2ZSBzb3J0aW5nIHBvc3NpYmxlXG5cdFx0dGhpcy5oZWxwZXIuY3NzKCBcInBvc2l0aW9uXCIsIFwiYWJzb2x1dGVcIiApO1xuXHRcdHRoaXMuY3NzUG9zaXRpb24gPSB0aGlzLmhlbHBlci5jc3MoIFwicG9zaXRpb25cIiApO1xuXG5cdFx0Ly9HZW5lcmF0ZSB0aGUgb3JpZ2luYWwgcG9zaXRpb25cblx0XHR0aGlzLm9yaWdpbmFsUG9zaXRpb24gPSB0aGlzLl9nZW5lcmF0ZVBvc2l0aW9uKCBldmVudCApO1xuXHRcdHRoaXMub3JpZ2luYWxQYWdlWCA9IGV2ZW50LnBhZ2VYO1xuXHRcdHRoaXMub3JpZ2luYWxQYWdlWSA9IGV2ZW50LnBhZ2VZO1xuXG5cdFx0Ly9BZGp1c3QgdGhlIG1vdXNlIG9mZnNldCByZWxhdGl2ZSB0byB0aGUgaGVscGVyIGlmIFwiY3Vyc29yQXRcIiBpcyBzdXBwbGllZFxuXHRcdCggby5jdXJzb3JBdCAmJiB0aGlzLl9hZGp1c3RPZmZzZXRGcm9tSGVscGVyKCBvLmN1cnNvckF0ICkgKTtcblxuXHRcdC8vQ2FjaGUgdGhlIGZvcm1lciBET00gcG9zaXRpb25cblx0XHR0aGlzLmRvbVBvc2l0aW9uID0ge1xuXHRcdFx0cHJldjogdGhpcy5jdXJyZW50SXRlbS5wcmV2KClbIDAgXSxcblx0XHRcdHBhcmVudDogdGhpcy5jdXJyZW50SXRlbS5wYXJlbnQoKVsgMCBdXG5cdFx0fTtcblxuXHRcdC8vIElmIHRoZSBoZWxwZXIgaXMgbm90IHRoZSBvcmlnaW5hbCwgaGlkZSB0aGUgb3JpZ2luYWwgc28gaXQncyBub3QgcGxheWluZyBhbnkgcm9sZSBkdXJpbmdcblx0XHQvLyB0aGUgZHJhZywgd29uJ3QgY2F1c2UgYW55dGhpbmcgYmFkIHRoaXMgd2F5XG5cdFx0aWYgKCB0aGlzLmhlbHBlclsgMCBdICE9PSB0aGlzLmN1cnJlbnRJdGVtWyAwIF0gKSB7XG5cdFx0XHR0aGlzLmN1cnJlbnRJdGVtLmhpZGUoKTtcblx0XHR9XG5cblx0XHQvL0NyZWF0ZSB0aGUgcGxhY2Vob2xkZXJcblx0XHR0aGlzLl9jcmVhdGVQbGFjZWhvbGRlcigpO1xuXG5cdFx0Ly9TZXQgYSBjb250YWlubWVudCBpZiBnaXZlbiBpbiB0aGUgb3B0aW9uc1xuXHRcdGlmICggby5jb250YWlubWVudCApIHtcblx0XHRcdHRoaXMuX3NldENvbnRhaW5tZW50KCk7XG5cdFx0fVxuXG5cdFx0aWYgKCBvLmN1cnNvciAmJiBvLmN1cnNvciAhPT0gXCJhdXRvXCIgKSB7IC8vIGN1cnNvciBvcHRpb25cblx0XHRcdGJvZHkgPSB0aGlzLmRvY3VtZW50LmZpbmQoIFwiYm9keVwiICk7XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFXG5cdFx0XHR0aGlzLnN0b3JlZEN1cnNvciA9IGJvZHkuY3NzKCBcImN1cnNvclwiICk7XG5cdFx0XHRib2R5LmNzcyggXCJjdXJzb3JcIiwgby5jdXJzb3IgKTtcblxuXHRcdFx0dGhpcy5zdG9yZWRTdHlsZXNoZWV0ID1cblx0XHRcdFx0JCggXCI8c3R5bGU+KnsgY3Vyc29yOiBcIiArIG8uY3Vyc29yICsgXCIgIWltcG9ydGFudDsgfTwvc3R5bGU+XCIgKS5hcHBlbmRUbyggYm9keSApO1xuXHRcdH1cblxuXHRcdGlmICggby5vcGFjaXR5ICkgeyAvLyBvcGFjaXR5IG9wdGlvblxuXHRcdFx0aWYgKCB0aGlzLmhlbHBlci5jc3MoIFwib3BhY2l0eVwiICkgKSB7XG5cdFx0XHRcdHRoaXMuX3N0b3JlZE9wYWNpdHkgPSB0aGlzLmhlbHBlci5jc3MoIFwib3BhY2l0eVwiICk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLmhlbHBlci5jc3MoIFwib3BhY2l0eVwiLCBvLm9wYWNpdHkgKTtcblx0XHR9XG5cblx0XHRpZiAoIG8uekluZGV4ICkgeyAvLyB6SW5kZXggb3B0aW9uXG5cdFx0XHRpZiAoIHRoaXMuaGVscGVyLmNzcyggXCJ6SW5kZXhcIiApICkge1xuXHRcdFx0XHR0aGlzLl9zdG9yZWRaSW5kZXggPSB0aGlzLmhlbHBlci5jc3MoIFwiekluZGV4XCIgKTtcblx0XHRcdH1cblx0XHRcdHRoaXMuaGVscGVyLmNzcyggXCJ6SW5kZXhcIiwgby56SW5kZXggKTtcblx0XHR9XG5cblx0XHQvL1ByZXBhcmUgc2Nyb2xsaW5nXG5cdFx0aWYgKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICE9PSB0aGlzLmRvY3VtZW50WyAwIF0gJiZcblx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnRbIDAgXS50YWdOYW1lICE9PSBcIkhUTUxcIiApIHtcblx0XHRcdHRoaXMub3ZlcmZsb3dPZmZzZXQgPSB0aGlzLnNjcm9sbFBhcmVudC5vZmZzZXQoKTtcblx0XHR9XG5cblx0XHQvL0NhbGwgY2FsbGJhY2tzXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJzdGFydFwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCkgKTtcblxuXHRcdC8vUmVjYWNoZSB0aGUgaGVscGVyIHNpemVcblx0XHRpZiAoICF0aGlzLl9wcmVzZXJ2ZUhlbHBlclByb3BvcnRpb25zICkge1xuXHRcdFx0dGhpcy5fY2FjaGVIZWxwZXJQcm9wb3J0aW9ucygpO1xuXHRcdH1cblxuXHRcdC8vUG9zdCBcImFjdGl2YXRlXCIgZXZlbnRzIHRvIHBvc3NpYmxlIGNvbnRhaW5lcnNcblx0XHRpZiAoICFub0FjdGl2YXRpb24gKSB7XG5cdFx0XHRmb3IgKCBpID0gdGhpcy5jb250YWluZXJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5fdHJpZ2dlciggXCJhY3RpdmF0ZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCB0aGlzICkgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvL1ByZXBhcmUgcG9zc2libGUgZHJvcHBhYmxlc1xuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5jdXJyZW50ID0gdGhpcztcblx0XHR9XG5cblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICYmICFvLmRyb3BCZWhhdmlvdXIgKSB7XG5cdFx0XHQkLnVpLmRkbWFuYWdlci5wcmVwYXJlT2Zmc2V0cyggdGhpcywgZXZlbnQgKTtcblx0XHR9XG5cblx0XHR0aGlzLmRyYWdnaW5nID0gdHJ1ZTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmhlbHBlciwgXCJ1aS1zb3J0YWJsZS1oZWxwZXJcIiApO1xuXG5cdFx0Ly8gRXhlY3V0ZSB0aGUgZHJhZyBvbmNlIC0gdGhpcyBjYXVzZXMgdGhlIGhlbHBlciBub3QgdG8gYmUgdmlzaWJsZWJlZm9yZSBnZXR0aW5nIGl0c1xuXHRcdC8vIGNvcnJlY3QgcG9zaXRpb25cblx0XHR0aGlzLl9tb3VzZURyYWcoIGV2ZW50ICk7XG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fSxcblxuXHRfbW91c2VEcmFnOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGksIGl0ZW0sIGl0ZW1FbGVtZW50LCBpbnRlcnNlY3Rpb24sXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0c2Nyb2xsZWQgPSBmYWxzZTtcblxuXHRcdC8vQ29tcHV0ZSB0aGUgaGVscGVycyBwb3NpdGlvblxuXHRcdHRoaXMucG9zaXRpb24gPSB0aGlzLl9nZW5lcmF0ZVBvc2l0aW9uKCBldmVudCApO1xuXHRcdHRoaXMucG9zaXRpb25BYnMgPSB0aGlzLl9jb252ZXJ0UG9zaXRpb25UbyggXCJhYnNvbHV0ZVwiICk7XG5cblx0XHRpZiAoICF0aGlzLmxhc3RQb3NpdGlvbkFicyApIHtcblx0XHRcdHRoaXMubGFzdFBvc2l0aW9uQWJzID0gdGhpcy5wb3NpdGlvbkFicztcblx0XHR9XG5cblx0XHQvL0RvIHNjcm9sbGluZ1xuXHRcdGlmICggdGhpcy5vcHRpb25zLnNjcm9sbCApIHtcblx0XHRcdGlmICggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSAhPT0gdGhpcy5kb2N1bWVudFsgMCBdICYmXG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnRbIDAgXS50YWdOYW1lICE9PSBcIkhUTUxcIiApIHtcblxuXHRcdFx0XHRpZiAoICggdGhpcy5vdmVyZmxvd09mZnNldC50b3AgKyB0aGlzLnNjcm9sbFBhcmVudFsgMCBdLm9mZnNldEhlaWdodCApIC1cblx0XHRcdFx0XHRcdGV2ZW50LnBhZ2VZIDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnNjcm9sbFRvcCA9XG5cdFx0XHRcdFx0XHRzY3JvbGxlZCA9IHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0uc2Nyb2xsVG9wICsgby5zY3JvbGxTcGVlZDtcblx0XHRcdFx0fSBlbHNlIGlmICggZXZlbnQucGFnZVkgLSB0aGlzLm92ZXJmbG93T2Zmc2V0LnRvcCA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5zY3JvbGxUb3AgPVxuXHRcdFx0XHRcdFx0c2Nyb2xsZWQgPSB0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnNjcm9sbFRvcCAtIG8uc2Nyb2xsU3BlZWQ7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoICggdGhpcy5vdmVyZmxvd09mZnNldC5sZWZ0ICsgdGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5vZmZzZXRXaWR0aCApIC1cblx0XHRcdFx0XHRcdGV2ZW50LnBhZ2VYIDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnNjcm9sbExlZnQgPSBzY3JvbGxlZCA9XG5cdFx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudFsgMCBdLnNjcm9sbExlZnQgKyBvLnNjcm9sbFNwZWVkO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCBldmVudC5wYWdlWCAtIHRoaXMub3ZlcmZsb3dPZmZzZXQubGVmdCA8IG8uc2Nyb2xsU2Vuc2l0aXZpdHkgKSB7XG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5zY3JvbGxMZWZ0ID0gc2Nyb2xsZWQgPVxuXHRcdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnRbIDAgXS5zY3JvbGxMZWZ0IC0gby5zY3JvbGxTcGVlZDtcblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVkgLSB0aGlzLmRvY3VtZW50LnNjcm9sbFRvcCgpIDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxlZCA9IHRoaXMuZG9jdW1lbnQuc2Nyb2xsVG9wKCB0aGlzLmRvY3VtZW50LnNjcm9sbFRvcCgpIC0gby5zY3JvbGxTcGVlZCApO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCB0aGlzLndpbmRvdy5oZWlnaHQoKSAtICggZXZlbnQucGFnZVkgLSB0aGlzLmRvY3VtZW50LnNjcm9sbFRvcCgpICkgPFxuXHRcdFx0XHRcdFx0by5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxlZCA9IHRoaXMuZG9jdW1lbnQuc2Nyb2xsVG9wKCB0aGlzLmRvY3VtZW50LnNjcm9sbFRvcCgpICsgby5zY3JvbGxTcGVlZCApO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWCAtIHRoaXMuZG9jdW1lbnQuc2Nyb2xsTGVmdCgpIDwgby5zY3JvbGxTZW5zaXRpdml0eSApIHtcblx0XHRcdFx0XHRzY3JvbGxlZCA9IHRoaXMuZG9jdW1lbnQuc2Nyb2xsTGVmdChcblx0XHRcdFx0XHRcdHRoaXMuZG9jdW1lbnQuc2Nyb2xsTGVmdCgpIC0gby5zY3JvbGxTcGVlZFxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH0gZWxzZSBpZiAoIHRoaXMud2luZG93LndpZHRoKCkgLSAoIGV2ZW50LnBhZ2VYIC0gdGhpcy5kb2N1bWVudC5zY3JvbGxMZWZ0KCkgKSA8XG5cdFx0XHRcdFx0XHRvLnNjcm9sbFNlbnNpdGl2aXR5ICkge1xuXHRcdFx0XHRcdHNjcm9sbGVkID0gdGhpcy5kb2N1bWVudC5zY3JvbGxMZWZ0KFxuXHRcdFx0XHRcdFx0dGhpcy5kb2N1bWVudC5zY3JvbGxMZWZ0KCkgKyBvLnNjcm9sbFNwZWVkXG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggc2Nyb2xsZWQgIT09IGZhbHNlICYmICQudWkuZGRtYW5hZ2VyICYmICFvLmRyb3BCZWhhdmlvdXIgKSB7XG5cdFx0XHRcdCQudWkuZGRtYW5hZ2VyLnByZXBhcmVPZmZzZXRzKCB0aGlzLCBldmVudCApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vUmVnZW5lcmF0ZSB0aGUgYWJzb2x1dGUgcG9zaXRpb24gdXNlZCBmb3IgcG9zaXRpb24gY2hlY2tzXG5cdFx0dGhpcy5wb3NpdGlvbkFicyA9IHRoaXMuX2NvbnZlcnRQb3NpdGlvblRvKCBcImFic29sdXRlXCIgKTtcblxuXHRcdC8vU2V0IHRoZSBoZWxwZXIgcG9zaXRpb25cblx0XHRpZiAoICF0aGlzLm9wdGlvbnMuYXhpcyB8fCB0aGlzLm9wdGlvbnMuYXhpcyAhPT0gXCJ5XCIgKSB7XG5cdFx0XHR0aGlzLmhlbHBlclsgMCBdLnN0eWxlLmxlZnQgPSB0aGlzLnBvc2l0aW9uLmxlZnQgKyBcInB4XCI7XG5cdFx0fVxuXHRcdGlmICggIXRoaXMub3B0aW9ucy5heGlzIHx8IHRoaXMub3B0aW9ucy5heGlzICE9PSBcInhcIiApIHtcblx0XHRcdHRoaXMuaGVscGVyWyAwIF0uc3R5bGUudG9wID0gdGhpcy5wb3NpdGlvbi50b3AgKyBcInB4XCI7XG5cdFx0fVxuXG5cdFx0Ly9SZWFycmFuZ2Vcblx0XHRmb3IgKCBpID0gdGhpcy5pdGVtcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblxuXHRcdFx0Ly9DYWNoZSB2YXJpYWJsZXMgYW5kIGludGVyc2VjdGlvbiwgY29udGludWUgaWYgbm8gaW50ZXJzZWN0aW9uXG5cdFx0XHRpdGVtID0gdGhpcy5pdGVtc1sgaSBdO1xuXHRcdFx0aXRlbUVsZW1lbnQgPSBpdGVtLml0ZW1bIDAgXTtcblx0XHRcdGludGVyc2VjdGlvbiA9IHRoaXMuX2ludGVyc2VjdHNXaXRoUG9pbnRlciggaXRlbSApO1xuXHRcdFx0aWYgKCAhaW50ZXJzZWN0aW9uICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gT25seSBwdXQgdGhlIHBsYWNlaG9sZGVyIGluc2lkZSB0aGUgY3VycmVudCBDb250YWluZXIsIHNraXAgYWxsXG5cdFx0XHQvLyBpdGVtcyBmcm9tIG90aGVyIGNvbnRhaW5lcnMuIFRoaXMgd29ya3MgYmVjYXVzZSB3aGVuIG1vdmluZ1xuXHRcdFx0Ly8gYW4gaXRlbSBmcm9tIG9uZSBjb250YWluZXIgdG8gYW5vdGhlciB0aGVcblx0XHRcdC8vIGN1cnJlbnRDb250YWluZXIgaXMgc3dpdGNoZWQgYmVmb3JlIHRoZSBwbGFjZWhvbGRlciBpcyBtb3ZlZC5cblx0XHRcdC8vXG5cdFx0XHQvLyBXaXRob3V0IHRoaXMsIG1vdmluZyBpdGVtcyBpbiBcInN1Yi1zb3J0YWJsZXNcIiBjYW4gY2F1c2Vcblx0XHRcdC8vIHRoZSBwbGFjZWhvbGRlciB0byBqaXR0ZXIgYmV0d2VlbiB0aGUgb3V0ZXIgYW5kIGlubmVyIGNvbnRhaW5lci5cblx0XHRcdGlmICggaXRlbS5pbnN0YW5jZSAhPT0gdGhpcy5jdXJyZW50Q29udGFpbmVyICkge1xuXHRcdFx0XHRjb250aW51ZTtcblx0XHRcdH1cblxuXHRcdFx0Ly8gQ2Fubm90IGludGVyc2VjdCB3aXRoIGl0c2VsZlxuXHRcdFx0Ly8gbm8gdXNlbGVzcyBhY3Rpb25zIHRoYXQgaGF2ZSBiZWVuIGRvbmUgYmVmb3JlXG5cdFx0XHQvLyBubyBhY3Rpb24gaWYgdGhlIGl0ZW0gbW92ZWQgaXMgdGhlIHBhcmVudCBvZiB0aGUgaXRlbSBjaGVja2VkXG5cdFx0XHRpZiAoIGl0ZW1FbGVtZW50ICE9PSB0aGlzLmN1cnJlbnRJdGVtWyAwIF0gJiZcblx0XHRcdFx0dGhpcy5wbGFjZWhvbGRlclsgaW50ZXJzZWN0aW9uID09PSAxID8gXCJuZXh0XCIgOiBcInByZXZcIiBdKClbIDAgXSAhPT0gaXRlbUVsZW1lbnQgJiZcblx0XHRcdFx0ISQuY29udGFpbnMoIHRoaXMucGxhY2Vob2xkZXJbIDAgXSwgaXRlbUVsZW1lbnQgKSAmJlxuXHRcdFx0XHQoIHRoaXMub3B0aW9ucy50eXBlID09PSBcInNlbWktZHluYW1pY1wiID9cblx0XHRcdFx0XHQhJC5jb250YWlucyggdGhpcy5lbGVtZW50WyAwIF0sIGl0ZW1FbGVtZW50ICkgOlxuXHRcdFx0XHRcdHRydWVcblx0XHRcdFx0KVxuXHRcdFx0KSB7XG5cblx0XHRcdFx0dGhpcy5kaXJlY3Rpb24gPSBpbnRlcnNlY3Rpb24gPT09IDEgPyBcImRvd25cIiA6IFwidXBcIjtcblxuXHRcdFx0XHRpZiAoIHRoaXMub3B0aW9ucy50b2xlcmFuY2UgPT09IFwicG9pbnRlclwiIHx8IHRoaXMuX2ludGVyc2VjdHNXaXRoU2lkZXMoIGl0ZW0gKSApIHtcblx0XHRcdFx0XHR0aGlzLl9yZWFycmFuZ2UoIGV2ZW50LCBpdGVtICk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0YnJlYWs7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNoYW5nZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCkgKTtcblx0XHRcdFx0YnJlYWs7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly9Qb3N0IGV2ZW50cyB0byBjb250YWluZXJzXG5cdFx0dGhpcy5fY29udGFjdENvbnRhaW5lcnMoIGV2ZW50ICk7XG5cblx0XHQvL0ludGVyY29ubmVjdCB3aXRoIGRyb3BwYWJsZXNcblx0XHRpZiAoICQudWkuZGRtYW5hZ2VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIuZHJhZyggdGhpcywgZXZlbnQgKTtcblx0XHR9XG5cblx0XHQvL0NhbGwgY2FsbGJhY2tzXG5cdFx0dGhpcy5fdHJpZ2dlciggXCJzb3J0XCIsIGV2ZW50LCB0aGlzLl91aUhhc2goKSApO1xuXG5cdFx0dGhpcy5sYXN0UG9zaXRpb25BYnMgPSB0aGlzLnBvc2l0aW9uQWJzO1xuXHRcdHJldHVybiBmYWxzZTtcblxuXHR9LFxuXG5cdF9tb3VzZVN0b3A6IGZ1bmN0aW9uKCBldmVudCwgbm9Qcm9wYWdhdGlvbiApIHtcblxuXHRcdGlmICggIWV2ZW50ICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vSWYgd2UgYXJlIHVzaW5nIGRyb3BwYWJsZXMsIGluZm9ybSB0aGUgbWFuYWdlciBhYm91dCB0aGUgZHJvcFxuXHRcdGlmICggJC51aS5kZG1hbmFnZXIgJiYgIXRoaXMub3B0aW9ucy5kcm9wQmVoYXZpb3VyICkge1xuXHRcdFx0JC51aS5kZG1hbmFnZXIuZHJvcCggdGhpcywgZXZlbnQgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5yZXZlcnQgKSB7XG5cdFx0XHR2YXIgdGhhdCA9IHRoaXMsXG5cdFx0XHRcdGN1ciA9IHRoaXMucGxhY2Vob2xkZXIub2Zmc2V0KCksXG5cdFx0XHRcdGF4aXMgPSB0aGlzLm9wdGlvbnMuYXhpcyxcblx0XHRcdFx0YW5pbWF0aW9uID0ge307XG5cblx0XHRcdGlmICggIWF4aXMgfHwgYXhpcyA9PT0gXCJ4XCIgKSB7XG5cdFx0XHRcdGFuaW1hdGlvbi5sZWZ0ID0gY3VyLmxlZnQgLSB0aGlzLm9mZnNldC5wYXJlbnQubGVmdCAtIHRoaXMubWFyZ2lucy5sZWZ0ICtcblx0XHRcdFx0XHQoIHRoaXMub2Zmc2V0UGFyZW50WyAwIF0gPT09IHRoaXMuZG9jdW1lbnRbIDAgXS5ib2R5ID9cblx0XHRcdFx0XHRcdDAgOlxuXHRcdFx0XHRcdFx0dGhpcy5vZmZzZXRQYXJlbnRbIDAgXS5zY3JvbGxMZWZ0XG5cdFx0XHRcdFx0KTtcblx0XHRcdH1cblx0XHRcdGlmICggIWF4aXMgfHwgYXhpcyA9PT0gXCJ5XCIgKSB7XG5cdFx0XHRcdGFuaW1hdGlvbi50b3AgPSBjdXIudG9wIC0gdGhpcy5vZmZzZXQucGFyZW50LnRvcCAtIHRoaXMubWFyZ2lucy50b3AgK1xuXHRcdFx0XHRcdCggdGhpcy5vZmZzZXRQYXJlbnRbIDAgXSA9PT0gdGhpcy5kb2N1bWVudFsgMCBdLmJvZHkgP1xuXHRcdFx0XHRcdFx0MCA6XG5cdFx0XHRcdFx0XHR0aGlzLm9mZnNldFBhcmVudFsgMCBdLnNjcm9sbFRvcFxuXHRcdFx0XHRcdCk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLnJldmVydGluZyA9IHRydWU7XG5cdFx0XHQkKCB0aGlzLmhlbHBlciApLmFuaW1hdGUoXG5cdFx0XHRcdGFuaW1hdGlvbixcblx0XHRcdFx0cGFyc2VJbnQoIHRoaXMub3B0aW9ucy5yZXZlcnQsIDEwICkgfHwgNTAwLFxuXHRcdFx0XHRmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR0aGF0Ll9jbGVhciggZXZlbnQgKTtcblx0XHRcdFx0fVxuXHRcdFx0KTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5fY2xlYXIoIGV2ZW50LCBub1Byb3BhZ2F0aW9uICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXG5cdH0sXG5cblx0Y2FuY2VsOiBmdW5jdGlvbigpIHtcblxuXHRcdGlmICggdGhpcy5kcmFnZ2luZyApIHtcblxuXHRcdFx0dGhpcy5fbW91c2VVcCggbmV3ICQuRXZlbnQoIFwibW91c2V1cFwiLCB7IHRhcmdldDogbnVsbCB9ICkgKTtcblxuXHRcdFx0aWYgKCB0aGlzLm9wdGlvbnMuaGVscGVyID09PSBcIm9yaWdpbmFsXCIgKSB7XG5cdFx0XHRcdHRoaXMuY3VycmVudEl0ZW0uY3NzKCB0aGlzLl9zdG9yZWRDU1MgKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuY3VycmVudEl0ZW0sIFwidWktc29ydGFibGUtaGVscGVyXCIgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuY3VycmVudEl0ZW0uc2hvdygpO1xuXHRcdFx0fVxuXG5cdFx0XHQvL1Bvc3QgZGVhY3RpdmF0aW5nIGV2ZW50cyB0byBjb250YWluZXJzXG5cdFx0XHRmb3IgKCB2YXIgaSA9IHRoaXMuY29udGFpbmVycy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uX3RyaWdnZXIoIFwiZGVhY3RpdmF0ZVwiLCBudWxsLCB0aGlzLl91aUhhc2goIHRoaXMgKSApO1xuXHRcdFx0XHRpZiAoIHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLm92ZXIgKSB7XG5cdFx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uX3RyaWdnZXIoIFwib3V0XCIsIG51bGwsIHRoaXMuX3VpSGFzaCggdGhpcyApICk7XG5cdFx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUub3ZlciA9IDA7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5wbGFjZWhvbGRlciApIHtcblxuXHRcdFx0Ly8kKHRoaXMucGxhY2Vob2xkZXJbMF0pLnJlbW92ZSgpOyB3b3VsZCBoYXZlIGJlZW4gdGhlIGpRdWVyeSB3YXkgLSB1bmZvcnR1bmF0ZWx5LFxuXHRcdFx0Ly8gaXQgdW5iaW5kcyBBTEwgZXZlbnRzIGZyb20gdGhlIG9yaWdpbmFsIG5vZGUhXG5cdFx0XHRpZiAoIHRoaXMucGxhY2Vob2xkZXJbIDAgXS5wYXJlbnROb2RlICkge1xuXHRcdFx0XHR0aGlzLnBsYWNlaG9sZGVyWyAwIF0ucGFyZW50Tm9kZS5yZW1vdmVDaGlsZCggdGhpcy5wbGFjZWhvbGRlclsgMCBdICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy5oZWxwZXIgIT09IFwib3JpZ2luYWxcIiAmJiB0aGlzLmhlbHBlciAmJlxuXHRcdFx0XHRcdHRoaXMuaGVscGVyWyAwIF0ucGFyZW50Tm9kZSApIHtcblx0XHRcdFx0dGhpcy5oZWxwZXIucmVtb3ZlKCk7XG5cdFx0XHR9XG5cblx0XHRcdCQuZXh0ZW5kKCB0aGlzLCB7XG5cdFx0XHRcdGhlbHBlcjogbnVsbCxcblx0XHRcdFx0ZHJhZ2dpbmc6IGZhbHNlLFxuXHRcdFx0XHRyZXZlcnRpbmc6IGZhbHNlLFxuXHRcdFx0XHRfbm9GaW5hbFNvcnQ6IG51bGxcblx0XHRcdH0gKTtcblxuXHRcdFx0aWYgKCB0aGlzLmRvbVBvc2l0aW9uLnByZXYgKSB7XG5cdFx0XHRcdCQoIHRoaXMuZG9tUG9zaXRpb24ucHJldiApLmFmdGVyKCB0aGlzLmN1cnJlbnRJdGVtICk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQkKCB0aGlzLmRvbVBvc2l0aW9uLnBhcmVudCApLnByZXBlbmQoIHRoaXMuY3VycmVudEl0ZW0gKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9LFxuXG5cdHNlcmlhbGl6ZTogZnVuY3Rpb24oIG8gKSB7XG5cblx0XHR2YXIgaXRlbXMgPSB0aGlzLl9nZXRJdGVtc0FzalF1ZXJ5KCBvICYmIG8uY29ubmVjdGVkICksXG5cdFx0XHRzdHIgPSBbXTtcblx0XHRvID0gbyB8fCB7fTtcblxuXHRcdCQoIGl0ZW1zICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHR2YXIgcmVzID0gKCAkKCBvLml0ZW0gfHwgdGhpcyApLmF0dHIoIG8uYXR0cmlidXRlIHx8IFwiaWRcIiApIHx8IFwiXCIgKVxuXHRcdFx0XHQubWF0Y2goIG8uZXhwcmVzc2lvbiB8fCAoIC8oLispW1xcLT1fXSguKykvICkgKTtcblx0XHRcdGlmICggcmVzICkge1xuXHRcdFx0XHRzdHIucHVzaChcblx0XHRcdFx0XHQoIG8ua2V5IHx8IHJlc1sgMSBdICsgXCJbXVwiICkgK1xuXHRcdFx0XHRcdFwiPVwiICsgKCBvLmtleSAmJiBvLmV4cHJlc3Npb24gPyByZXNbIDEgXSA6IHJlc1sgMiBdICkgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHRpZiAoICFzdHIubGVuZ3RoICYmIG8ua2V5ICkge1xuXHRcdFx0c3RyLnB1c2goIG8ua2V5ICsgXCI9XCIgKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gc3RyLmpvaW4oIFwiJlwiICk7XG5cblx0fSxcblxuXHR0b0FycmF5OiBmdW5jdGlvbiggbyApIHtcblxuXHRcdHZhciBpdGVtcyA9IHRoaXMuX2dldEl0ZW1zQXNqUXVlcnkoIG8gJiYgby5jb25uZWN0ZWQgKSxcblx0XHRcdHJldCA9IFtdO1xuXG5cdFx0byA9IG8gfHwge307XG5cblx0XHRpdGVtcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHJldC5wdXNoKCAkKCBvLml0ZW0gfHwgdGhpcyApLmF0dHIoIG8uYXR0cmlidXRlIHx8IFwiaWRcIiApIHx8IFwiXCIgKTtcblx0XHR9ICk7XG5cdFx0cmV0dXJuIHJldDtcblxuXHR9LFxuXG5cdC8qIEJlIGNhcmVmdWwgd2l0aCB0aGUgZm9sbG93aW5nIGNvcmUgZnVuY3Rpb25zICovXG5cdF9pbnRlcnNlY3RzV2l0aDogZnVuY3Rpb24oIGl0ZW0gKSB7XG5cblx0XHR2YXIgeDEgPSB0aGlzLnBvc2l0aW9uQWJzLmxlZnQsXG5cdFx0XHR4MiA9IHgxICsgdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCxcblx0XHRcdHkxID0gdGhpcy5wb3NpdGlvbkFicy50b3AsXG5cdFx0XHR5MiA9IHkxICsgdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQsXG5cdFx0XHRsID0gaXRlbS5sZWZ0LFxuXHRcdFx0ciA9IGwgKyBpdGVtLndpZHRoLFxuXHRcdFx0dCA9IGl0ZW0udG9wLFxuXHRcdFx0YiA9IHQgKyBpdGVtLmhlaWdodCxcblx0XHRcdGR5Q2xpY2sgPSB0aGlzLm9mZnNldC5jbGljay50b3AsXG5cdFx0XHRkeENsaWNrID0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCxcblx0XHRcdGlzT3ZlckVsZW1lbnRIZWlnaHQgPSAoIHRoaXMub3B0aW9ucy5heGlzID09PSBcInhcIiApIHx8ICggKCB5MSArIGR5Q2xpY2sgKSA+IHQgJiZcblx0XHRcdFx0KCB5MSArIGR5Q2xpY2sgKSA8IGIgKSxcblx0XHRcdGlzT3ZlckVsZW1lbnRXaWR0aCA9ICggdGhpcy5vcHRpb25zLmF4aXMgPT09IFwieVwiICkgfHwgKCAoIHgxICsgZHhDbGljayApID4gbCAmJlxuXHRcdFx0XHQoIHgxICsgZHhDbGljayApIDwgciApLFxuXHRcdFx0aXNPdmVyRWxlbWVudCA9IGlzT3ZlckVsZW1lbnRIZWlnaHQgJiYgaXNPdmVyRWxlbWVudFdpZHRoO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMudG9sZXJhbmNlID09PSBcInBvaW50ZXJcIiB8fFxuXHRcdFx0dGhpcy5vcHRpb25zLmZvcmNlUG9pbnRlckZvckNvbnRhaW5lcnMgfHxcblx0XHRcdCggdGhpcy5vcHRpb25zLnRvbGVyYW5jZSAhPT0gXCJwb2ludGVyXCIgJiZcblx0XHRcdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9uc1sgdGhpcy5mbG9hdGluZyA/IFwid2lkdGhcIiA6IFwiaGVpZ2h0XCIgXSA+XG5cdFx0XHRcdGl0ZW1bIHRoaXMuZmxvYXRpbmcgPyBcIndpZHRoXCIgOiBcImhlaWdodFwiIF0gKVxuXHRcdCkge1xuXHRcdFx0cmV0dXJuIGlzT3ZlckVsZW1lbnQ7XG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmV0dXJuICggbCA8IHgxICsgKCB0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC8gMiApICYmIC8vIFJpZ2h0IEhhbGZcblx0XHRcdFx0eDIgLSAoIHRoaXMuaGVscGVyUHJvcG9ydGlvbnMud2lkdGggLyAyICkgPCByICYmIC8vIExlZnQgSGFsZlxuXHRcdFx0XHR0IDwgeTEgKyAoIHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC8gMiApICYmIC8vIEJvdHRvbSBIYWxmXG5cdFx0XHRcdHkyIC0gKCB0aGlzLmhlbHBlclByb3BvcnRpb25zLmhlaWdodCAvIDIgKSA8IGIgKTsgLy8gVG9wIEhhbGZcblxuXHRcdH1cblx0fSxcblxuXHRfaW50ZXJzZWN0c1dpdGhQb2ludGVyOiBmdW5jdGlvbiggaXRlbSApIHtcblx0XHR2YXIgdmVydGljYWxEaXJlY3Rpb24sIGhvcml6b250YWxEaXJlY3Rpb24sXG5cdFx0XHRpc092ZXJFbGVtZW50SGVpZ2h0ID0gKCB0aGlzLm9wdGlvbnMuYXhpcyA9PT0gXCJ4XCIgKSB8fFxuXHRcdFx0XHR0aGlzLl9pc092ZXJBeGlzKFxuXHRcdFx0XHRcdHRoaXMucG9zaXRpb25BYnMudG9wICsgdGhpcy5vZmZzZXQuY2xpY2sudG9wLCBpdGVtLnRvcCwgaXRlbS5oZWlnaHQgKSxcblx0XHRcdGlzT3ZlckVsZW1lbnRXaWR0aCA9ICggdGhpcy5vcHRpb25zLmF4aXMgPT09IFwieVwiICkgfHxcblx0XHRcdFx0dGhpcy5faXNPdmVyQXhpcyhcblx0XHRcdFx0XHR0aGlzLnBvc2l0aW9uQWJzLmxlZnQgKyB0aGlzLm9mZnNldC5jbGljay5sZWZ0LCBpdGVtLmxlZnQsIGl0ZW0ud2lkdGggKSxcblx0XHRcdGlzT3ZlckVsZW1lbnQgPSBpc092ZXJFbGVtZW50SGVpZ2h0ICYmIGlzT3ZlckVsZW1lbnRXaWR0aDtcblxuXHRcdGlmICggIWlzT3ZlckVsZW1lbnQgKSB7XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0fVxuXG5cdFx0dmVydGljYWxEaXJlY3Rpb24gPSB0aGlzLl9nZXREcmFnVmVydGljYWxEaXJlY3Rpb24oKTtcblx0XHRob3Jpem9udGFsRGlyZWN0aW9uID0gdGhpcy5fZ2V0RHJhZ0hvcml6b250YWxEaXJlY3Rpb24oKTtcblxuXHRcdHJldHVybiB0aGlzLmZsb2F0aW5nID9cblx0XHRcdCggKCBob3Jpem9udGFsRGlyZWN0aW9uID09PSBcInJpZ2h0XCIgfHwgdmVydGljYWxEaXJlY3Rpb24gPT09IFwiZG93blwiICkgPyAyIDogMSApXG5cdFx0XHQ6ICggdmVydGljYWxEaXJlY3Rpb24gJiYgKCB2ZXJ0aWNhbERpcmVjdGlvbiA9PT0gXCJkb3duXCIgPyAyIDogMSApICk7XG5cblx0fSxcblxuXHRfaW50ZXJzZWN0c1dpdGhTaWRlczogZnVuY3Rpb24oIGl0ZW0gKSB7XG5cblx0XHR2YXIgaXNPdmVyQm90dG9tSGFsZiA9IHRoaXMuX2lzT3ZlckF4aXMoIHRoaXMucG9zaXRpb25BYnMudG9wICtcblx0XHRcdFx0dGhpcy5vZmZzZXQuY2xpY2sudG9wLCBpdGVtLnRvcCArICggaXRlbS5oZWlnaHQgLyAyICksIGl0ZW0uaGVpZ2h0ICksXG5cdFx0XHRpc092ZXJSaWdodEhhbGYgPSB0aGlzLl9pc092ZXJBeGlzKCB0aGlzLnBvc2l0aW9uQWJzLmxlZnQgK1xuXHRcdFx0XHR0aGlzLm9mZnNldC5jbGljay5sZWZ0LCBpdGVtLmxlZnQgKyAoIGl0ZW0ud2lkdGggLyAyICksIGl0ZW0ud2lkdGggKSxcblx0XHRcdHZlcnRpY2FsRGlyZWN0aW9uID0gdGhpcy5fZ2V0RHJhZ1ZlcnRpY2FsRGlyZWN0aW9uKCksXG5cdFx0XHRob3Jpem9udGFsRGlyZWN0aW9uID0gdGhpcy5fZ2V0RHJhZ0hvcml6b250YWxEaXJlY3Rpb24oKTtcblxuXHRcdGlmICggdGhpcy5mbG9hdGluZyAmJiBob3Jpem9udGFsRGlyZWN0aW9uICkge1xuXHRcdFx0cmV0dXJuICggKCBob3Jpem9udGFsRGlyZWN0aW9uID09PSBcInJpZ2h0XCIgJiYgaXNPdmVyUmlnaHRIYWxmICkgfHxcblx0XHRcdFx0KCBob3Jpem9udGFsRGlyZWN0aW9uID09PSBcImxlZnRcIiAmJiAhaXNPdmVyUmlnaHRIYWxmICkgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0cmV0dXJuIHZlcnRpY2FsRGlyZWN0aW9uICYmICggKCB2ZXJ0aWNhbERpcmVjdGlvbiA9PT0gXCJkb3duXCIgJiYgaXNPdmVyQm90dG9tSGFsZiApIHx8XG5cdFx0XHRcdCggdmVydGljYWxEaXJlY3Rpb24gPT09IFwidXBcIiAmJiAhaXNPdmVyQm90dG9tSGFsZiApICk7XG5cdFx0fVxuXG5cdH0sXG5cblx0X2dldERyYWdWZXJ0aWNhbERpcmVjdGlvbjogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIGRlbHRhID0gdGhpcy5wb3NpdGlvbkFicy50b3AgLSB0aGlzLmxhc3RQb3NpdGlvbkFicy50b3A7XG5cdFx0cmV0dXJuIGRlbHRhICE9PSAwICYmICggZGVsdGEgPiAwID8gXCJkb3duXCIgOiBcInVwXCIgKTtcblx0fSxcblxuXHRfZ2V0RHJhZ0hvcml6b250YWxEaXJlY3Rpb246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBkZWx0YSA9IHRoaXMucG9zaXRpb25BYnMubGVmdCAtIHRoaXMubGFzdFBvc2l0aW9uQWJzLmxlZnQ7XG5cdFx0cmV0dXJuIGRlbHRhICE9PSAwICYmICggZGVsdGEgPiAwID8gXCJyaWdodFwiIDogXCJsZWZ0XCIgKTtcblx0fSxcblxuXHRyZWZyZXNoOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dGhpcy5fcmVmcmVzaEl0ZW1zKCBldmVudCApO1xuXHRcdHRoaXMuX3NldEhhbmRsZUNsYXNzTmFtZSgpO1xuXHRcdHRoaXMucmVmcmVzaFBvc2l0aW9ucygpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9jb25uZWN0V2l0aDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cdFx0cmV0dXJuIG9wdGlvbnMuY29ubmVjdFdpdGguY29uc3RydWN0b3IgPT09IFN0cmluZyA/XG5cdFx0XHRbIG9wdGlvbnMuY29ubmVjdFdpdGggXSA6XG5cdFx0XHRvcHRpb25zLmNvbm5lY3RXaXRoO1xuXHR9LFxuXG5cdF9nZXRJdGVtc0FzalF1ZXJ5OiBmdW5jdGlvbiggY29ubmVjdGVkICkge1xuXG5cdFx0dmFyIGksIGosIGN1ciwgaW5zdCxcblx0XHRcdGl0ZW1zID0gW10sXG5cdFx0XHRxdWVyaWVzID0gW10sXG5cdFx0XHRjb25uZWN0V2l0aCA9IHRoaXMuX2Nvbm5lY3RXaXRoKCk7XG5cblx0XHRpZiAoIGNvbm5lY3RXaXRoICYmIGNvbm5lY3RlZCApIHtcblx0XHRcdGZvciAoIGkgPSBjb25uZWN0V2l0aC5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdFx0Y3VyID0gJCggY29ubmVjdFdpdGhbIGkgXSwgdGhpcy5kb2N1bWVudFsgMCBdICk7XG5cdFx0XHRcdGZvciAoIGogPSBjdXIubGVuZ3RoIC0gMTsgaiA+PSAwOyBqLS0gKSB7XG5cdFx0XHRcdFx0aW5zdCA9ICQuZGF0YSggY3VyWyBqIF0sIHRoaXMud2lkZ2V0RnVsbE5hbWUgKTtcblx0XHRcdFx0XHRpZiAoIGluc3QgJiYgaW5zdCAhPT0gdGhpcyAmJiAhaW5zdC5vcHRpb25zLmRpc2FibGVkICkge1xuXHRcdFx0XHRcdFx0cXVlcmllcy5wdXNoKCBbICQuaXNGdW5jdGlvbiggaW5zdC5vcHRpb25zLml0ZW1zICkgP1xuXHRcdFx0XHRcdFx0XHRpbnN0Lm9wdGlvbnMuaXRlbXMuY2FsbCggaW5zdC5lbGVtZW50ICkgOlxuXHRcdFx0XHRcdFx0XHQkKCBpbnN0Lm9wdGlvbnMuaXRlbXMsIGluc3QuZWxlbWVudCApXG5cdFx0XHRcdFx0XHRcdFx0Lm5vdCggXCIudWktc29ydGFibGUtaGVscGVyXCIgKVxuXHRcdFx0XHRcdFx0XHRcdC5ub3QoIFwiLnVpLXNvcnRhYmxlLXBsYWNlaG9sZGVyXCIgKSwgaW5zdCBdICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cXVlcmllcy5wdXNoKCBbICQuaXNGdW5jdGlvbiggdGhpcy5vcHRpb25zLml0ZW1zICkgP1xuXHRcdFx0dGhpcy5vcHRpb25zLml0ZW1zXG5cdFx0XHRcdC5jYWxsKCB0aGlzLmVsZW1lbnQsIG51bGwsIHsgb3B0aW9uczogdGhpcy5vcHRpb25zLCBpdGVtOiB0aGlzLmN1cnJlbnRJdGVtIH0gKSA6XG5cdFx0XHQkKCB0aGlzLm9wdGlvbnMuaXRlbXMsIHRoaXMuZWxlbWVudCApXG5cdFx0XHRcdC5ub3QoIFwiLnVpLXNvcnRhYmxlLWhlbHBlclwiIClcblx0XHRcdFx0Lm5vdCggXCIudWktc29ydGFibGUtcGxhY2Vob2xkZXJcIiApLCB0aGlzIF0gKTtcblxuXHRcdGZ1bmN0aW9uIGFkZEl0ZW1zKCkge1xuXHRcdFx0aXRlbXMucHVzaCggdGhpcyApO1xuXHRcdH1cblx0XHRmb3IgKCBpID0gcXVlcmllcy5sZW5ndGggLSAxOyBpID49IDA7IGktLSApIHtcblx0XHRcdHF1ZXJpZXNbIGkgXVsgMCBdLmVhY2goIGFkZEl0ZW1zICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuICQoIGl0ZW1zICk7XG5cblx0fSxcblxuXHRfcmVtb3ZlQ3VycmVudHNGcm9tSXRlbXM6IGZ1bmN0aW9uKCkge1xuXG5cdFx0dmFyIGxpc3QgPSB0aGlzLmN1cnJlbnRJdGVtLmZpbmQoIFwiOmRhdGEoXCIgKyB0aGlzLndpZGdldE5hbWUgKyBcIi1pdGVtKVwiICk7XG5cblx0XHR0aGlzLml0ZW1zID0gJC5ncmVwKCB0aGlzLml0ZW1zLCBmdW5jdGlvbiggaXRlbSApIHtcblx0XHRcdGZvciAoIHZhciBqID0gMDsgaiA8IGxpc3QubGVuZ3RoOyBqKysgKSB7XG5cdFx0XHRcdGlmICggbGlzdFsgaiBdID09PSBpdGVtLml0ZW1bIDAgXSApIHtcblx0XHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH0gKTtcblxuXHR9LFxuXG5cdF9yZWZyZXNoSXRlbXM6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHRoaXMuaXRlbXMgPSBbXTtcblx0XHR0aGlzLmNvbnRhaW5lcnMgPSBbIHRoaXMgXTtcblxuXHRcdHZhciBpLCBqLCBjdXIsIGluc3QsIHRhcmdldERhdGEsIF9xdWVyaWVzLCBpdGVtLCBxdWVyaWVzTGVuZ3RoLFxuXHRcdFx0aXRlbXMgPSB0aGlzLml0ZW1zLFxuXHRcdFx0cXVlcmllcyA9IFsgWyAkLmlzRnVuY3Rpb24oIHRoaXMub3B0aW9ucy5pdGVtcyApID9cblx0XHRcdFx0dGhpcy5vcHRpb25zLml0ZW1zLmNhbGwoIHRoaXMuZWxlbWVudFsgMCBdLCBldmVudCwgeyBpdGVtOiB0aGlzLmN1cnJlbnRJdGVtIH0gKSA6XG5cdFx0XHRcdCQoIHRoaXMub3B0aW9ucy5pdGVtcywgdGhpcy5lbGVtZW50ICksIHRoaXMgXSBdLFxuXHRcdFx0Y29ubmVjdFdpdGggPSB0aGlzLl9jb25uZWN0V2l0aCgpO1xuXG5cdFx0Ly9TaG91bGRuJ3QgYmUgcnVuIHRoZSBmaXJzdCB0aW1lIHRocm91Z2ggZHVlIHRvIG1hc3NpdmUgc2xvdy1kb3duXG5cdFx0aWYgKCBjb25uZWN0V2l0aCAmJiB0aGlzLnJlYWR5ICkge1xuXHRcdFx0Zm9yICggaSA9IGNvbm5lY3RXaXRoLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0XHRjdXIgPSAkKCBjb25uZWN0V2l0aFsgaSBdLCB0aGlzLmRvY3VtZW50WyAwIF0gKTtcblx0XHRcdFx0Zm9yICggaiA9IGN1ci5sZW5ndGggLSAxOyBqID49IDA7IGotLSApIHtcblx0XHRcdFx0XHRpbnN0ID0gJC5kYXRhKCBjdXJbIGogXSwgdGhpcy53aWRnZXRGdWxsTmFtZSApO1xuXHRcdFx0XHRcdGlmICggaW5zdCAmJiBpbnN0ICE9PSB0aGlzICYmICFpbnN0Lm9wdGlvbnMuZGlzYWJsZWQgKSB7XG5cdFx0XHRcdFx0XHRxdWVyaWVzLnB1c2goIFsgJC5pc0Z1bmN0aW9uKCBpbnN0Lm9wdGlvbnMuaXRlbXMgKSA/XG5cdFx0XHRcdFx0XHRcdGluc3Qub3B0aW9ucy5pdGVtc1xuXHRcdFx0XHRcdFx0XHRcdC5jYWxsKCBpbnN0LmVsZW1lbnRbIDAgXSwgZXZlbnQsIHsgaXRlbTogdGhpcy5jdXJyZW50SXRlbSB9ICkgOlxuXHRcdFx0XHRcdFx0XHQkKCBpbnN0Lm9wdGlvbnMuaXRlbXMsIGluc3QuZWxlbWVudCApLCBpbnN0IF0gKTtcblx0XHRcdFx0XHRcdHRoaXMuY29udGFpbmVycy5wdXNoKCBpbnN0ICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Zm9yICggaSA9IHF1ZXJpZXMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cdFx0XHR0YXJnZXREYXRhID0gcXVlcmllc1sgaSBdWyAxIF07XG5cdFx0XHRfcXVlcmllcyA9IHF1ZXJpZXNbIGkgXVsgMCBdO1xuXG5cdFx0XHRmb3IgKCBqID0gMCwgcXVlcmllc0xlbmd0aCA9IF9xdWVyaWVzLmxlbmd0aDsgaiA8IHF1ZXJpZXNMZW5ndGg7IGorKyApIHtcblx0XHRcdFx0aXRlbSA9ICQoIF9xdWVyaWVzWyBqIF0gKTtcblxuXHRcdFx0XHQvLyBEYXRhIGZvciB0YXJnZXQgY2hlY2tpbmcgKG1vdXNlIG1hbmFnZXIpXG5cdFx0XHRcdGl0ZW0uZGF0YSggdGhpcy53aWRnZXROYW1lICsgXCItaXRlbVwiLCB0YXJnZXREYXRhICk7XG5cblx0XHRcdFx0aXRlbXMucHVzaCgge1xuXHRcdFx0XHRcdGl0ZW06IGl0ZW0sXG5cdFx0XHRcdFx0aW5zdGFuY2U6IHRhcmdldERhdGEsXG5cdFx0XHRcdFx0d2lkdGg6IDAsIGhlaWdodDogMCxcblx0XHRcdFx0XHRsZWZ0OiAwLCB0b3A6IDBcblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHR9LFxuXG5cdHJlZnJlc2hQb3NpdGlvbnM6IGZ1bmN0aW9uKCBmYXN0ICkge1xuXG5cdFx0Ly8gRGV0ZXJtaW5lIHdoZXRoZXIgaXRlbXMgYXJlIGJlaW5nIGRpc3BsYXllZCBob3Jpem9udGFsbHlcblx0XHR0aGlzLmZsb2F0aW5nID0gdGhpcy5pdGVtcy5sZW5ndGggP1xuXHRcdFx0dGhpcy5vcHRpb25zLmF4aXMgPT09IFwieFwiIHx8IHRoaXMuX2lzRmxvYXRpbmcoIHRoaXMuaXRlbXNbIDAgXS5pdGVtICkgOlxuXHRcdFx0ZmFsc2U7XG5cblx0XHQvL1RoaXMgaGFzIHRvIGJlIHJlZG9uZSBiZWNhdXNlIGR1ZSB0byB0aGUgaXRlbSBiZWluZyBtb3ZlZCBvdXQvaW50byB0aGUgb2Zmc2V0UGFyZW50LFxuXHRcdC8vIHRoZSBvZmZzZXRQYXJlbnQncyBwb3NpdGlvbiB3aWxsIGNoYW5nZVxuXHRcdGlmICggdGhpcy5vZmZzZXRQYXJlbnQgJiYgdGhpcy5oZWxwZXIgKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQgPSB0aGlzLl9nZXRQYXJlbnRPZmZzZXQoKTtcblx0XHR9XG5cblx0XHR2YXIgaSwgaXRlbSwgdCwgcDtcblxuXHRcdGZvciAoIGkgPSB0aGlzLml0ZW1zLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0aXRlbSA9IHRoaXMuaXRlbXNbIGkgXTtcblxuXHRcdFx0Ly9XZSBpZ25vcmUgY2FsY3VsYXRpbmcgcG9zaXRpb25zIG9mIGFsbCBjb25uZWN0ZWQgY29udGFpbmVycyB3aGVuIHdlJ3JlIG5vdCBvdmVyIHRoZW1cblx0XHRcdGlmICggaXRlbS5pbnN0YW5jZSAhPT0gdGhpcy5jdXJyZW50Q29udGFpbmVyICYmIHRoaXMuY3VycmVudENvbnRhaW5lciAmJlxuXHRcdFx0XHRcdGl0ZW0uaXRlbVsgMCBdICE9PSB0aGlzLmN1cnJlbnRJdGVtWyAwIF0gKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXG5cdFx0XHR0ID0gdGhpcy5vcHRpb25zLnRvbGVyYW5jZUVsZW1lbnQgP1xuXHRcdFx0XHQkKCB0aGlzLm9wdGlvbnMudG9sZXJhbmNlRWxlbWVudCwgaXRlbS5pdGVtICkgOlxuXHRcdFx0XHRpdGVtLml0ZW07XG5cblx0XHRcdGlmICggIWZhc3QgKSB7XG5cdFx0XHRcdGl0ZW0ud2lkdGggPSB0Lm91dGVyV2lkdGgoKTtcblx0XHRcdFx0aXRlbS5oZWlnaHQgPSB0Lm91dGVySGVpZ2h0KCk7XG5cdFx0XHR9XG5cblx0XHRcdHAgPSB0Lm9mZnNldCgpO1xuXHRcdFx0aXRlbS5sZWZ0ID0gcC5sZWZ0O1xuXHRcdFx0aXRlbS50b3AgPSBwLnRvcDtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMub3B0aW9ucy5jdXN0b20gJiYgdGhpcy5vcHRpb25zLmN1c3RvbS5yZWZyZXNoQ29udGFpbmVycyApIHtcblx0XHRcdHRoaXMub3B0aW9ucy5jdXN0b20ucmVmcmVzaENvbnRhaW5lcnMuY2FsbCggdGhpcyApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRmb3IgKCBpID0gdGhpcy5jb250YWluZXJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0XHRwID0gdGhpcy5jb250YWluZXJzWyBpIF0uZWxlbWVudC5vZmZzZXQoKTtcblx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUubGVmdCA9IHAubGVmdDtcblx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUudG9wID0gcC50b3A7XG5cdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLndpZHRoID1cblx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5lbGVtZW50Lm91dGVyV2lkdGgoKTtcblx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpIF0uY29udGFpbmVyQ2FjaGUuaGVpZ2h0ID1cblx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5lbGVtZW50Lm91dGVySGVpZ2h0KCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X2NyZWF0ZVBsYWNlaG9sZGVyOiBmdW5jdGlvbiggdGhhdCApIHtcblx0XHR0aGF0ID0gdGhhdCB8fCB0aGlzO1xuXHRcdHZhciBjbGFzc05hbWUsXG5cdFx0XHRvID0gdGhhdC5vcHRpb25zO1xuXG5cdFx0aWYgKCAhby5wbGFjZWhvbGRlciB8fCBvLnBsYWNlaG9sZGVyLmNvbnN0cnVjdG9yID09PSBTdHJpbmcgKSB7XG5cdFx0XHRjbGFzc05hbWUgPSBvLnBsYWNlaG9sZGVyO1xuXHRcdFx0by5wbGFjZWhvbGRlciA9IHtcblx0XHRcdFx0ZWxlbWVudDogZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0XHR2YXIgbm9kZU5hbWUgPSB0aGF0LmN1cnJlbnRJdGVtWyAwIF0ubm9kZU5hbWUudG9Mb3dlckNhc2UoKSxcblx0XHRcdFx0XHRcdGVsZW1lbnQgPSAkKCBcIjxcIiArIG5vZGVOYW1lICsgXCI+XCIsIHRoYXQuZG9jdW1lbnRbIDAgXSApO1xuXG5cdFx0XHRcdFx0XHR0aGF0Ll9hZGRDbGFzcyggZWxlbWVudCwgXCJ1aS1zb3J0YWJsZS1wbGFjZWhvbGRlclwiLFxuXHRcdFx0XHRcdFx0XHRcdGNsYXNzTmFtZSB8fCB0aGF0LmN1cnJlbnRJdGVtWyAwIF0uY2xhc3NOYW1lIClcblx0XHRcdFx0XHRcdFx0Ll9yZW1vdmVDbGFzcyggZWxlbWVudCwgXCJ1aS1zb3J0YWJsZS1oZWxwZXJcIiApO1xuXG5cdFx0XHRcdFx0aWYgKCBub2RlTmFtZSA9PT0gXCJ0Ym9keVwiICkge1xuXHRcdFx0XHRcdFx0dGhhdC5fY3JlYXRlVHJQbGFjZWhvbGRlcihcblx0XHRcdFx0XHRcdFx0dGhhdC5jdXJyZW50SXRlbS5maW5kKCBcInRyXCIgKS5lcSggMCApLFxuXHRcdFx0XHRcdFx0XHQkKCBcIjx0cj5cIiwgdGhhdC5kb2N1bWVudFsgMCBdICkuYXBwZW5kVG8oIGVsZW1lbnQgKVxuXHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHR9IGVsc2UgaWYgKCBub2RlTmFtZSA9PT0gXCJ0clwiICkge1xuXHRcdFx0XHRcdFx0dGhhdC5fY3JlYXRlVHJQbGFjZWhvbGRlciggdGhhdC5jdXJyZW50SXRlbSwgZWxlbWVudCApO1xuXHRcdFx0XHRcdH0gZWxzZSBpZiAoIG5vZGVOYW1lID09PSBcImltZ1wiICkge1xuXHRcdFx0XHRcdFx0ZWxlbWVudC5hdHRyKCBcInNyY1wiLCB0aGF0LmN1cnJlbnRJdGVtLmF0dHIoIFwic3JjXCIgKSApO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggIWNsYXNzTmFtZSApIHtcblx0XHRcdFx0XHRcdGVsZW1lbnQuY3NzKCBcInZpc2liaWxpdHlcIiwgXCJoaWRkZW5cIiApO1xuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHJldHVybiBlbGVtZW50O1xuXHRcdFx0XHR9LFxuXHRcdFx0XHR1cGRhdGU6IGZ1bmN0aW9uKCBjb250YWluZXIsIHAgKSB7XG5cblx0XHRcdFx0XHQvLyAxLiBJZiBhIGNsYXNzTmFtZSBpcyBzZXQgYXMgJ3BsYWNlaG9sZGVyIG9wdGlvbiwgd2UgZG9uJ3QgZm9yY2Ugc2l6ZXMgLVxuXHRcdFx0XHRcdC8vIHRoZSBjbGFzcyBpcyByZXNwb25zaWJsZSBmb3IgdGhhdFxuXHRcdFx0XHRcdC8vIDIuIFRoZSBvcHRpb24gJ2ZvcmNlUGxhY2Vob2xkZXJTaXplIGNhbiBiZSBlbmFibGVkIHRvIGZvcmNlIGl0IGV2ZW4gaWYgYVxuXHRcdFx0XHRcdC8vIGNsYXNzIG5hbWUgaXMgc3BlY2lmaWVkXG5cdFx0XHRcdFx0aWYgKCBjbGFzc05hbWUgJiYgIW8uZm9yY2VQbGFjZWhvbGRlclNpemUgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly9JZiB0aGUgZWxlbWVudCBkb2Vzbid0IGhhdmUgYSBhY3R1YWwgaGVpZ2h0IGJ5IGl0c2VsZiAod2l0aG91dCBzdHlsZXMgY29taW5nXG5cdFx0XHRcdFx0Ly8gZnJvbSBhIHN0eWxlc2hlZXQpLCBpdCByZWNlaXZlcyB0aGUgaW5saW5lIGhlaWdodCBmcm9tIHRoZSBkcmFnZ2VkIGl0ZW1cblx0XHRcdFx0XHRpZiAoICFwLmhlaWdodCgpICkge1xuXHRcdFx0XHRcdFx0cC5oZWlnaHQoXG5cdFx0XHRcdFx0XHRcdHRoYXQuY3VycmVudEl0ZW0uaW5uZXJIZWlnaHQoKSAtXG5cdFx0XHRcdFx0XHRcdHBhcnNlSW50KCB0aGF0LmN1cnJlbnRJdGVtLmNzcyggXCJwYWRkaW5nVG9wXCIgKSB8fCAwLCAxMCApIC1cblx0XHRcdFx0XHRcdFx0cGFyc2VJbnQoIHRoYXQuY3VycmVudEl0ZW0uY3NzKCBcInBhZGRpbmdCb3R0b21cIiApIHx8IDAsIDEwICkgKTtcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0aWYgKCAhcC53aWR0aCgpICkge1xuXHRcdFx0XHRcdFx0cC53aWR0aChcblx0XHRcdFx0XHRcdFx0dGhhdC5jdXJyZW50SXRlbS5pbm5lcldpZHRoKCkgLVxuXHRcdFx0XHRcdFx0XHRwYXJzZUludCggdGhhdC5jdXJyZW50SXRlbS5jc3MoIFwicGFkZGluZ0xlZnRcIiApIHx8IDAsIDEwICkgLVxuXHRcdFx0XHRcdFx0XHRwYXJzZUludCggdGhhdC5jdXJyZW50SXRlbS5jc3MoIFwicGFkZGluZ1JpZ2h0XCIgKSB8fCAwLCAxMCApICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9XG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdC8vQ3JlYXRlIHRoZSBwbGFjZWhvbGRlclxuXHRcdHRoYXQucGxhY2Vob2xkZXIgPSAkKCBvLnBsYWNlaG9sZGVyLmVsZW1lbnQuY2FsbCggdGhhdC5lbGVtZW50LCB0aGF0LmN1cnJlbnRJdGVtICkgKTtcblxuXHRcdC8vQXBwZW5kIGl0IGFmdGVyIHRoZSBhY3R1YWwgY3VycmVudCBpdGVtXG5cdFx0dGhhdC5jdXJyZW50SXRlbS5hZnRlciggdGhhdC5wbGFjZWhvbGRlciApO1xuXG5cdFx0Ly9VcGRhdGUgdGhlIHNpemUgb2YgdGhlIHBsYWNlaG9sZGVyIChUT0RPOiBMb2dpYyB0byBmdXp6eSwgc2VlIGxpbmUgMzE2LzMxNylcblx0XHRvLnBsYWNlaG9sZGVyLnVwZGF0ZSggdGhhdCwgdGhhdC5wbGFjZWhvbGRlciApO1xuXG5cdH0sXG5cblx0X2NyZWF0ZVRyUGxhY2Vob2xkZXI6IGZ1bmN0aW9uKCBzb3VyY2VUciwgdGFyZ2V0VHIgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXG5cdFx0c291cmNlVHIuY2hpbGRyZW4oKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdCQoIFwiPHRkPiYjMTYwOzwvdGQ+XCIsIHRoYXQuZG9jdW1lbnRbIDAgXSApXG5cdFx0XHRcdC5hdHRyKCBcImNvbHNwYW5cIiwgJCggdGhpcyApLmF0dHIoIFwiY29sc3BhblwiICkgfHwgMSApXG5cdFx0XHRcdC5hcHBlbmRUbyggdGFyZ2V0VHIgKTtcblx0XHR9ICk7XG5cdH0sXG5cblx0X2NvbnRhY3RDb250YWluZXJzOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0dmFyIGksIGosIGRpc3QsIGl0ZW1XaXRoTGVhc3REaXN0YW5jZSwgcG9zUHJvcGVydHksIHNpemVQcm9wZXJ0eSwgY3VyLCBuZWFyQm90dG9tLFxuXHRcdFx0ZmxvYXRpbmcsIGF4aXMsXG5cdFx0XHRpbm5lcm1vc3RDb250YWluZXIgPSBudWxsLFxuXHRcdFx0aW5uZXJtb3N0SW5kZXggPSBudWxsO1xuXG5cdFx0Ly8gR2V0IGlubmVybW9zdCBjb250YWluZXIgdGhhdCBpbnRlcnNlY3RzIHdpdGggaXRlbVxuXHRcdGZvciAoIGkgPSB0aGlzLmNvbnRhaW5lcnMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0gKSB7XG5cblx0XHRcdC8vIE5ldmVyIGNvbnNpZGVyIGEgY29udGFpbmVyIHRoYXQncyBsb2NhdGVkIHdpdGhpbiB0aGUgaXRlbSBpdHNlbGZcblx0XHRcdGlmICggJC5jb250YWlucyggdGhpcy5jdXJyZW50SXRlbVsgMCBdLCB0aGlzLmNvbnRhaW5lcnNbIGkgXS5lbGVtZW50WyAwIF0gKSApIHtcblx0XHRcdFx0Y29udGludWU7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGhpcy5faW50ZXJzZWN0c1dpdGgoIHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlICkgKSB7XG5cblx0XHRcdFx0Ly8gSWYgd2UndmUgYWxyZWFkeSBmb3VuZCBhIGNvbnRhaW5lciBhbmQgaXQncyBtb3JlIFwiaW5uZXJcIiB0aGFuIHRoaXMsIHRoZW4gY29udGludWVcblx0XHRcdFx0aWYgKCBpbm5lcm1vc3RDb250YWluZXIgJiZcblx0XHRcdFx0XHRcdCQuY29udGFpbnMoXG5cdFx0XHRcdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmVsZW1lbnRbIDAgXSxcblx0XHRcdFx0XHRcdFx0aW5uZXJtb3N0Q29udGFpbmVyLmVsZW1lbnRbIDAgXSApICkge1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aW5uZXJtb3N0Q29udGFpbmVyID0gdGhpcy5jb250YWluZXJzWyBpIF07XG5cdFx0XHRcdGlubmVybW9zdEluZGV4ID0gaTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBjb250YWluZXIgZG9lc24ndCBpbnRlcnNlY3QuIHRyaWdnZXIgXCJvdXRcIiBldmVudCBpZiBuZWNlc3Nhcnlcblx0XHRcdFx0aWYgKCB0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS5vdmVyICkge1xuXHRcdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLl90cmlnZ2VyKCBcIm91dFwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCB0aGlzICkgKTtcblx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGkgXS5jb250YWluZXJDYWNoZS5vdmVyID0gMDtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gSWYgbm8gaW50ZXJzZWN0aW5nIGNvbnRhaW5lcnMgZm91bmQsIHJldHVyblxuXHRcdGlmICggIWlubmVybW9zdENvbnRhaW5lciApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBNb3ZlIHRoZSBpdGVtIGludG8gdGhlIGNvbnRhaW5lciBpZiBpdCdzIG5vdCB0aGVyZSBhbHJlYWR5XG5cdFx0aWYgKCB0aGlzLmNvbnRhaW5lcnMubGVuZ3RoID09PSAxICkge1xuXHRcdFx0aWYgKCAhdGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdLmNvbnRhaW5lckNhY2hlLm92ZXIgKSB7XG5cdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXS5fdHJpZ2dlciggXCJvdmVyXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIHRoaXMgKSApO1xuXHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0uY29udGFpbmVyQ2FjaGUub3ZlciA9IDE7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gV2hlbiBlbnRlcmluZyBhIG5ldyBjb250YWluZXIsIHdlIHdpbGwgZmluZCB0aGUgaXRlbSB3aXRoIHRoZSBsZWFzdCBkaXN0YW5jZSBhbmRcblx0XHRcdC8vIGFwcGVuZCBvdXIgaXRlbSBuZWFyIGl0XG5cdFx0XHRkaXN0ID0gMTAwMDA7XG5cdFx0XHRpdGVtV2l0aExlYXN0RGlzdGFuY2UgPSBudWxsO1xuXHRcdFx0ZmxvYXRpbmcgPSBpbm5lcm1vc3RDb250YWluZXIuZmxvYXRpbmcgfHwgdGhpcy5faXNGbG9hdGluZyggdGhpcy5jdXJyZW50SXRlbSApO1xuXHRcdFx0cG9zUHJvcGVydHkgPSBmbG9hdGluZyA/IFwibGVmdFwiIDogXCJ0b3BcIjtcblx0XHRcdHNpemVQcm9wZXJ0eSA9IGZsb2F0aW5nID8gXCJ3aWR0aFwiIDogXCJoZWlnaHRcIjtcblx0XHRcdGF4aXMgPSBmbG9hdGluZyA/IFwicGFnZVhcIiA6IFwicGFnZVlcIjtcblxuXHRcdFx0Zm9yICggaiA9IHRoaXMuaXRlbXMubGVuZ3RoIC0gMTsgaiA+PSAwOyBqLS0gKSB7XG5cdFx0XHRcdGlmICggISQuY29udGFpbnMoXG5cdFx0XHRcdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0uZWxlbWVudFsgMCBdLCB0aGlzLml0ZW1zWyBqIF0uaXRlbVsgMCBdIClcblx0XHRcdFx0KSB7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCB0aGlzLml0ZW1zWyBqIF0uaXRlbVsgMCBdID09PSB0aGlzLmN1cnJlbnRJdGVtWyAwIF0gKSB7XG5cdFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRjdXIgPSB0aGlzLml0ZW1zWyBqIF0uaXRlbS5vZmZzZXQoKVsgcG9zUHJvcGVydHkgXTtcblx0XHRcdFx0bmVhckJvdHRvbSA9IGZhbHNlO1xuXHRcdFx0XHRpZiAoIGV2ZW50WyBheGlzIF0gLSBjdXIgPiB0aGlzLml0ZW1zWyBqIF1bIHNpemVQcm9wZXJ0eSBdIC8gMiApIHtcblx0XHRcdFx0XHRuZWFyQm90dG9tID0gdHJ1ZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIGV2ZW50WyBheGlzIF0gLSBjdXIgKSA8IGRpc3QgKSB7XG5cdFx0XHRcdFx0ZGlzdCA9IE1hdGguYWJzKCBldmVudFsgYXhpcyBdIC0gY3VyICk7XG5cdFx0XHRcdFx0aXRlbVdpdGhMZWFzdERpc3RhbmNlID0gdGhpcy5pdGVtc1sgaiBdO1xuXHRcdFx0XHRcdHRoaXMuZGlyZWN0aW9uID0gbmVhckJvdHRvbSA/IFwidXBcIiA6IFwiZG93blwiO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdC8vQ2hlY2sgaWYgZHJvcE9uRW1wdHkgaXMgZW5hYmxlZFxuXHRcdFx0aWYgKCAhaXRlbVdpdGhMZWFzdERpc3RhbmNlICYmICF0aGlzLm9wdGlvbnMuZHJvcE9uRW1wdHkgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0aGlzLmN1cnJlbnRDb250YWluZXIgPT09IHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXSApIHtcblx0XHRcdFx0aWYgKCAhdGhpcy5jdXJyZW50Q29udGFpbmVyLmNvbnRhaW5lckNhY2hlLm92ZXIgKSB7XG5cdFx0XHRcdFx0dGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdLl90cmlnZ2VyKCBcIm92ZXJcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCgpICk7XG5cdFx0XHRcdFx0dGhpcy5jdXJyZW50Q29udGFpbmVyLmNvbnRhaW5lckNhY2hlLm92ZXIgPSAxO1xuXHRcdFx0XHR9XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblxuXHRcdFx0aXRlbVdpdGhMZWFzdERpc3RhbmNlID9cblx0XHRcdFx0dGhpcy5fcmVhcnJhbmdlKCBldmVudCwgaXRlbVdpdGhMZWFzdERpc3RhbmNlLCBudWxsLCB0cnVlICkgOlxuXHRcdFx0XHR0aGlzLl9yZWFycmFuZ2UoIGV2ZW50LCBudWxsLCB0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0uZWxlbWVudCwgdHJ1ZSApO1xuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJjaGFuZ2VcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCgpICk7XG5cdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0uX3RyaWdnZXIoIFwiY2hhbmdlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIHRoaXMgKSApO1xuXHRcdFx0dGhpcy5jdXJyZW50Q29udGFpbmVyID0gdGhpcy5jb250YWluZXJzWyBpbm5lcm1vc3RJbmRleCBdO1xuXG5cdFx0XHQvL1VwZGF0ZSB0aGUgcGxhY2Vob2xkZXJcblx0XHRcdHRoaXMub3B0aW9ucy5wbGFjZWhvbGRlci51cGRhdGUoIHRoaXMuY3VycmVudENvbnRhaW5lciwgdGhpcy5wbGFjZWhvbGRlciApO1xuXG5cdFx0XHR0aGlzLmNvbnRhaW5lcnNbIGlubmVybW9zdEluZGV4IF0uX3RyaWdnZXIoIFwib3ZlclwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCB0aGlzICkgKTtcblx0XHRcdHRoaXMuY29udGFpbmVyc1sgaW5uZXJtb3N0SW5kZXggXS5jb250YWluZXJDYWNoZS5vdmVyID0gMTtcblx0XHR9XG5cblx0fSxcblxuXHRfY3JlYXRlSGVscGVyOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cblx0XHR2YXIgbyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGhlbHBlciA9ICQuaXNGdW5jdGlvbiggby5oZWxwZXIgKSA/XG5cdFx0XHRcdCQoIG8uaGVscGVyLmFwcGx5KCB0aGlzLmVsZW1lbnRbIDAgXSwgWyBldmVudCwgdGhpcy5jdXJyZW50SXRlbSBdICkgKSA6XG5cdFx0XHRcdCggby5oZWxwZXIgPT09IFwiY2xvbmVcIiA/IHRoaXMuY3VycmVudEl0ZW0uY2xvbmUoKSA6IHRoaXMuY3VycmVudEl0ZW0gKTtcblxuXHRcdC8vQWRkIHRoZSBoZWxwZXIgdG8gdGhlIERPTSBpZiB0aGF0IGRpZG4ndCBoYXBwZW4gYWxyZWFkeVxuXHRcdGlmICggIWhlbHBlci5wYXJlbnRzKCBcImJvZHlcIiApLmxlbmd0aCApIHtcblx0XHRcdCQoIG8uYXBwZW5kVG8gIT09IFwicGFyZW50XCIgP1xuXHRcdFx0XHRvLmFwcGVuZFRvIDpcblx0XHRcdFx0dGhpcy5jdXJyZW50SXRlbVsgMCBdLnBhcmVudE5vZGUgKVsgMCBdLmFwcGVuZENoaWxkKCBoZWxwZXJbIDAgXSApO1xuXHRcdH1cblxuXHRcdGlmICggaGVscGVyWyAwIF0gPT09IHRoaXMuY3VycmVudEl0ZW1bIDAgXSApIHtcblx0XHRcdHRoaXMuX3N0b3JlZENTUyA9IHtcblx0XHRcdFx0d2lkdGg6IHRoaXMuY3VycmVudEl0ZW1bIDAgXS5zdHlsZS53aWR0aCxcblx0XHRcdFx0aGVpZ2h0OiB0aGlzLmN1cnJlbnRJdGVtWyAwIF0uc3R5bGUuaGVpZ2h0LFxuXHRcdFx0XHRwb3NpdGlvbjogdGhpcy5jdXJyZW50SXRlbS5jc3MoIFwicG9zaXRpb25cIiApLFxuXHRcdFx0XHR0b3A6IHRoaXMuY3VycmVudEl0ZW0uY3NzKCBcInRvcFwiICksXG5cdFx0XHRcdGxlZnQ6IHRoaXMuY3VycmVudEl0ZW0uY3NzKCBcImxlZnRcIiApXG5cdFx0XHR9O1xuXHRcdH1cblxuXHRcdGlmICggIWhlbHBlclsgMCBdLnN0eWxlLndpZHRoIHx8IG8uZm9yY2VIZWxwZXJTaXplICkge1xuXHRcdFx0aGVscGVyLndpZHRoKCB0aGlzLmN1cnJlbnRJdGVtLndpZHRoKCkgKTtcblx0XHR9XG5cdFx0aWYgKCAhaGVscGVyWyAwIF0uc3R5bGUuaGVpZ2h0IHx8IG8uZm9yY2VIZWxwZXJTaXplICkge1xuXHRcdFx0aGVscGVyLmhlaWdodCggdGhpcy5jdXJyZW50SXRlbS5oZWlnaHQoKSApO1xuXHRcdH1cblxuXHRcdHJldHVybiBoZWxwZXI7XG5cblx0fSxcblxuXHRfYWRqdXN0T2Zmc2V0RnJvbUhlbHBlcjogZnVuY3Rpb24oIG9iaiApIHtcblx0XHRpZiAoIHR5cGVvZiBvYmogPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRvYmogPSBvYmouc3BsaXQoIFwiIFwiICk7XG5cdFx0fVxuXHRcdGlmICggJC5pc0FycmF5KCBvYmogKSApIHtcblx0XHRcdG9iaiA9IHsgbGVmdDogK29ialsgMCBdLCB0b3A6ICtvYmpbIDEgXSB8fCAwIH07XG5cdFx0fVxuXHRcdGlmICggXCJsZWZ0XCIgaW4gb2JqICkge1xuXHRcdFx0dGhpcy5vZmZzZXQuY2xpY2subGVmdCA9IG9iai5sZWZ0ICsgdGhpcy5tYXJnaW5zLmxlZnQ7XG5cdFx0fVxuXHRcdGlmICggXCJyaWdodFwiIGluIG9iaiApIHtcblx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPSB0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC0gb2JqLnJpZ2h0ICsgdGhpcy5tYXJnaW5zLmxlZnQ7XG5cdFx0fVxuXHRcdGlmICggXCJ0b3BcIiBpbiBvYmogKSB7XG5cdFx0XHR0aGlzLm9mZnNldC5jbGljay50b3AgPSBvYmoudG9wICsgdGhpcy5tYXJnaW5zLnRvcDtcblx0XHR9XG5cdFx0aWYgKCBcImJvdHRvbVwiIGluIG9iaiApIHtcblx0XHRcdHRoaXMub2Zmc2V0LmNsaWNrLnRvcCA9IHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC0gb2JqLmJvdHRvbSArIHRoaXMubWFyZ2lucy50b3A7XG5cdFx0fVxuXHR9LFxuXG5cdF9nZXRQYXJlbnRPZmZzZXQ6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly9HZXQgdGhlIG9mZnNldFBhcmVudCBhbmQgY2FjaGUgaXRzIHBvc2l0aW9uXG5cdFx0dGhpcy5vZmZzZXRQYXJlbnQgPSB0aGlzLmhlbHBlci5vZmZzZXRQYXJlbnQoKTtcblx0XHR2YXIgcG8gPSB0aGlzLm9mZnNldFBhcmVudC5vZmZzZXQoKTtcblxuXHRcdC8vIFRoaXMgaXMgYSBzcGVjaWFsIGNhc2Ugd2hlcmUgd2UgbmVlZCB0byBtb2RpZnkgYSBvZmZzZXQgY2FsY3VsYXRlZCBvbiBzdGFydCwgc2luY2UgdGhlXG5cdFx0Ly8gZm9sbG93aW5nIGhhcHBlbmVkOlxuXHRcdC8vIDEuIFRoZSBwb3NpdGlvbiBvZiB0aGUgaGVscGVyIGlzIGFic29sdXRlLCBzbyBpdCdzIHBvc2l0aW9uIGlzIGNhbGN1bGF0ZWQgYmFzZWQgb24gdGhlXG5cdFx0Ly8gbmV4dCBwb3NpdGlvbmVkIHBhcmVudFxuXHRcdC8vIDIuIFRoZSBhY3R1YWwgb2Zmc2V0IHBhcmVudCBpcyBhIGNoaWxkIG9mIHRoZSBzY3JvbGwgcGFyZW50LCBhbmQgdGhlIHNjcm9sbCBwYXJlbnQgaXNuJ3Rcblx0XHQvLyB0aGUgZG9jdW1lbnQsIHdoaWNoIG1lYW5zIHRoYXQgdGhlIHNjcm9sbCBpcyBpbmNsdWRlZCBpbiB0aGUgaW5pdGlhbCBjYWxjdWxhdGlvbiBvZiB0aGVcblx0XHQvLyBvZmZzZXQgb2YgdGhlIHBhcmVudCwgYW5kIG5ldmVyIHJlY2FsY3VsYXRlZCB1cG9uIGRyYWdcblx0XHRpZiAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiYWJzb2x1dGVcIiAmJiB0aGlzLnNjcm9sbFBhcmVudFsgMCBdICE9PSB0aGlzLmRvY3VtZW50WyAwIF0gJiZcblx0XHRcdFx0JC5jb250YWlucyggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSwgdGhpcy5vZmZzZXRQYXJlbnRbIDAgXSApICkge1xuXHRcdFx0cG8ubGVmdCArPSB0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0KCk7XG5cdFx0XHRwby50b3AgKz0gdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsVG9wKCk7XG5cdFx0fVxuXG5cdFx0Ly8gVGhpcyBuZWVkcyB0byBiZSBhY3R1YWxseSBkb25lIGZvciBhbGwgYnJvd3NlcnMsIHNpbmNlIHBhZ2VYL3BhZ2VZIGluY2x1ZGVzIHRoaXNcblx0XHQvLyBpbmZvcm1hdGlvbiB3aXRoIGFuIHVnbHkgSUUgZml4XG5cdFx0aWYgKCB0aGlzLm9mZnNldFBhcmVudFsgMCBdID09PSB0aGlzLmRvY3VtZW50WyAwIF0uYm9keSB8fFxuXHRcdFx0XHQoIHRoaXMub2Zmc2V0UGFyZW50WyAwIF0udGFnTmFtZSAmJlxuXHRcdFx0XHR0aGlzLm9mZnNldFBhcmVudFsgMCBdLnRhZ05hbWUudG9Mb3dlckNhc2UoKSA9PT0gXCJodG1sXCIgJiYgJC51aS5pZSApICkge1xuXHRcdFx0cG8gPSB7IHRvcDogMCwgbGVmdDogMCB9O1xuXHRcdH1cblxuXHRcdHJldHVybiB7XG5cdFx0XHR0b3A6IHBvLnRvcCArICggcGFyc2VJbnQoIHRoaXMub2Zmc2V0UGFyZW50LmNzcyggXCJib3JkZXJUb3BXaWR0aFwiICksIDEwICkgfHwgMCApLFxuXHRcdFx0bGVmdDogcG8ubGVmdCArICggcGFyc2VJbnQoIHRoaXMub2Zmc2V0UGFyZW50LmNzcyggXCJib3JkZXJMZWZ0V2lkdGhcIiApLCAxMCApIHx8IDAgKVxuXHRcdH07XG5cblx0fSxcblxuXHRfZ2V0UmVsYXRpdmVPZmZzZXQ6IGZ1bmN0aW9uKCkge1xuXG5cdFx0aWYgKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcInJlbGF0aXZlXCIgKSB7XG5cdFx0XHR2YXIgcCA9IHRoaXMuY3VycmVudEl0ZW0ucG9zaXRpb24oKTtcblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdHRvcDogcC50b3AgLSAoIHBhcnNlSW50KCB0aGlzLmhlbHBlci5jc3MoIFwidG9wXCIgKSwgMTAgKSB8fCAwICkgK1xuXHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbFRvcCgpLFxuXHRcdFx0XHRsZWZ0OiBwLmxlZnQgLSAoIHBhcnNlSW50KCB0aGlzLmhlbHBlci5jc3MoIFwibGVmdFwiICksIDEwICkgfHwgMCApICtcblx0XHRcdFx0XHR0aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0KClcblx0XHRcdH07XG5cdFx0fSBlbHNlIHtcblx0XHRcdHJldHVybiB7IHRvcDogMCwgbGVmdDogMCB9O1xuXHRcdH1cblxuXHR9LFxuXG5cdF9jYWNoZU1hcmdpbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMubWFyZ2lucyA9IHtcblx0XHRcdGxlZnQ6ICggcGFyc2VJbnQoIHRoaXMuY3VycmVudEl0ZW0uY3NzKCBcIm1hcmdpbkxlZnRcIiApLCAxMCApIHx8IDAgKSxcblx0XHRcdHRvcDogKCBwYXJzZUludCggdGhpcy5jdXJyZW50SXRlbS5jc3MoIFwibWFyZ2luVG9wXCIgKSwgMTAgKSB8fCAwIClcblx0XHR9O1xuXHR9LFxuXG5cdF9jYWNoZUhlbHBlclByb3BvcnRpb25zOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLmhlbHBlclByb3BvcnRpb25zID0ge1xuXHRcdFx0d2lkdGg6IHRoaXMuaGVscGVyLm91dGVyV2lkdGgoKSxcblx0XHRcdGhlaWdodDogdGhpcy5oZWxwZXIub3V0ZXJIZWlnaHQoKVxuXHRcdH07XG5cdH0sXG5cblx0X3NldENvbnRhaW5tZW50OiBmdW5jdGlvbigpIHtcblxuXHRcdHZhciBjZSwgY28sIG92ZXIsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zO1xuXHRcdGlmICggby5jb250YWlubWVudCA9PT0gXCJwYXJlbnRcIiApIHtcblx0XHRcdG8uY29udGFpbm1lbnQgPSB0aGlzLmhlbHBlclsgMCBdLnBhcmVudE5vZGU7XG5cdFx0fVxuXHRcdGlmICggby5jb250YWlubWVudCA9PT0gXCJkb2N1bWVudFwiIHx8IG8uY29udGFpbm1lbnQgPT09IFwid2luZG93XCIgKSB7XG5cdFx0XHR0aGlzLmNvbnRhaW5tZW50ID0gW1xuXHRcdFx0XHQwIC0gdGhpcy5vZmZzZXQucmVsYXRpdmUubGVmdCAtIHRoaXMub2Zmc2V0LnBhcmVudC5sZWZ0LFxuXHRcdFx0XHQwIC0gdGhpcy5vZmZzZXQucmVsYXRpdmUudG9wIC0gdGhpcy5vZmZzZXQucGFyZW50LnRvcCxcblx0XHRcdFx0by5jb250YWlubWVudCA9PT0gXCJkb2N1bWVudFwiID9cblx0XHRcdFx0XHR0aGlzLmRvY3VtZW50LndpZHRoKCkgOlxuXHRcdFx0XHRcdHRoaXMud2luZG93LndpZHRoKCkgLSB0aGlzLmhlbHBlclByb3BvcnRpb25zLndpZHRoIC0gdGhpcy5tYXJnaW5zLmxlZnQsXG5cdFx0XHRcdCggby5jb250YWlubWVudCA9PT0gXCJkb2N1bWVudFwiID9cblx0XHRcdFx0XHQoIHRoaXMuZG9jdW1lbnQuaGVpZ2h0KCkgfHwgZG9jdW1lbnQuYm9keS5wYXJlbnROb2RlLnNjcm9sbEhlaWdodCApIDpcblx0XHRcdFx0XHR0aGlzLndpbmRvdy5oZWlnaHQoKSB8fCB0aGlzLmRvY3VtZW50WyAwIF0uYm9keS5wYXJlbnROb2RlLnNjcm9sbEhlaWdodFxuXHRcdFx0XHQpIC0gdGhpcy5oZWxwZXJQcm9wb3J0aW9ucy5oZWlnaHQgLSB0aGlzLm1hcmdpbnMudG9wXG5cdFx0XHRdO1xuXHRcdH1cblxuXHRcdGlmICggISggL14oZG9jdW1lbnR8d2luZG93fHBhcmVudCkkLyApLnRlc3QoIG8uY29udGFpbm1lbnQgKSApIHtcblx0XHRcdGNlID0gJCggby5jb250YWlubWVudCApWyAwIF07XG5cdFx0XHRjbyA9ICQoIG8uY29udGFpbm1lbnQgKS5vZmZzZXQoKTtcblx0XHRcdG92ZXIgPSAoICQoIGNlICkuY3NzKCBcIm92ZXJmbG93XCIgKSAhPT0gXCJoaWRkZW5cIiApO1xuXG5cdFx0XHR0aGlzLmNvbnRhaW5tZW50ID0gW1xuXHRcdFx0XHRjby5sZWZ0ICsgKCBwYXJzZUludCggJCggY2UgKS5jc3MoIFwiYm9yZGVyTGVmdFdpZHRoXCIgKSwgMTAgKSB8fCAwICkgK1xuXHRcdFx0XHRcdCggcGFyc2VJbnQoICQoIGNlICkuY3NzKCBcInBhZGRpbmdMZWZ0XCIgKSwgMTAgKSB8fCAwICkgLSB0aGlzLm1hcmdpbnMubGVmdCxcblx0XHRcdFx0Y28udG9wICsgKCBwYXJzZUludCggJCggY2UgKS5jc3MoIFwiYm9yZGVyVG9wV2lkdGhcIiApLCAxMCApIHx8IDAgKSArXG5cdFx0XHRcdFx0KCBwYXJzZUludCggJCggY2UgKS5jc3MoIFwicGFkZGluZ1RvcFwiICksIDEwICkgfHwgMCApIC0gdGhpcy5tYXJnaW5zLnRvcCxcblx0XHRcdFx0Y28ubGVmdCArICggb3ZlciA/IE1hdGgubWF4KCBjZS5zY3JvbGxXaWR0aCwgY2Uub2Zmc2V0V2lkdGggKSA6IGNlLm9mZnNldFdpZHRoICkgLVxuXHRcdFx0XHRcdCggcGFyc2VJbnQoICQoIGNlICkuY3NzKCBcImJvcmRlckxlZnRXaWR0aFwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0XHQoIHBhcnNlSW50KCAkKCBjZSApLmNzcyggXCJwYWRkaW5nUmlnaHRcIiApLCAxMCApIHx8IDAgKSAtXG5cdFx0XHRcdFx0dGhpcy5oZWxwZXJQcm9wb3J0aW9ucy53aWR0aCAtIHRoaXMubWFyZ2lucy5sZWZ0LFxuXHRcdFx0XHRjby50b3AgKyAoIG92ZXIgPyBNYXRoLm1heCggY2Uuc2Nyb2xsSGVpZ2h0LCBjZS5vZmZzZXRIZWlnaHQgKSA6IGNlLm9mZnNldEhlaWdodCApIC1cblx0XHRcdFx0XHQoIHBhcnNlSW50KCAkKCBjZSApLmNzcyggXCJib3JkZXJUb3BXaWR0aFwiICksIDEwICkgfHwgMCApIC1cblx0XHRcdFx0XHQoIHBhcnNlSW50KCAkKCBjZSApLmNzcyggXCJwYWRkaW5nQm90dG9tXCIgKSwgMTAgKSB8fCAwICkgLVxuXHRcdFx0XHRcdHRoaXMuaGVscGVyUHJvcG9ydGlvbnMuaGVpZ2h0IC0gdGhpcy5tYXJnaW5zLnRvcFxuXHRcdFx0XTtcblx0XHR9XG5cblx0fSxcblxuXHRfY29udmVydFBvc2l0aW9uVG86IGZ1bmN0aW9uKCBkLCBwb3MgKSB7XG5cblx0XHRpZiAoICFwb3MgKSB7XG5cdFx0XHRwb3MgPSB0aGlzLnBvc2l0aW9uO1xuXHRcdH1cblx0XHR2YXIgbW9kID0gZCA9PT0gXCJhYnNvbHV0ZVwiID8gMSA6IC0xLFxuXHRcdFx0c2Nyb2xsID0gdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiICYmXG5cdFx0XHRcdCEoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gIT09IHRoaXMuZG9jdW1lbnRbIDAgXSAmJlxuXHRcdFx0XHQkLmNvbnRhaW5zKCB0aGlzLnNjcm9sbFBhcmVudFsgMCBdLCB0aGlzLm9mZnNldFBhcmVudFsgMCBdICkgKSA/XG5cdFx0XHRcdFx0dGhpcy5vZmZzZXRQYXJlbnQgOlxuXHRcdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50LFxuXHRcdFx0c2Nyb2xsSXNSb290Tm9kZSA9ICggLyhodG1sfGJvZHkpL2kgKS50ZXN0KCBzY3JvbGxbIDAgXS50YWdOYW1lICk7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiAoXG5cblx0XHRcdFx0Ly8gVGhlIGFic29sdXRlIG1vdXNlIHBvc2l0aW9uXG5cdFx0XHRcdHBvcy50b3BcdCtcblxuXHRcdFx0XHQvLyBPbmx5IGZvciByZWxhdGl2ZSBwb3NpdGlvbmVkIG5vZGVzOiBSZWxhdGl2ZSBvZmZzZXQgZnJvbSBlbGVtZW50IHRvIG9mZnNldCBwYXJlbnRcblx0XHRcdFx0dGhpcy5vZmZzZXQucmVsYXRpdmUudG9wICogbW9kICtcblxuXHRcdFx0XHQvLyBUaGUgb2Zmc2V0UGFyZW50J3Mgb2Zmc2V0IHdpdGhvdXQgYm9yZGVycyAob2Zmc2V0ICsgYm9yZGVyKVxuXHRcdFx0XHR0aGlzLm9mZnNldC5wYXJlbnQudG9wICogbW9kIC1cblx0XHRcdFx0KCAoIHRoaXMuY3NzUG9zaXRpb24gPT09IFwiZml4ZWRcIiA/XG5cdFx0XHRcdFx0LXRoaXMuc2Nyb2xsUGFyZW50LnNjcm9sbFRvcCgpIDpcblx0XHRcdFx0XHQoIHNjcm9sbElzUm9vdE5vZGUgPyAwIDogc2Nyb2xsLnNjcm9sbFRvcCgpICkgKSAqIG1vZCApXG5cdFx0XHQpLFxuXHRcdFx0bGVmdDogKFxuXG5cdFx0XHRcdC8vIFRoZSBhYnNvbHV0ZSBtb3VzZSBwb3NpdGlvblxuXHRcdFx0XHRwb3MubGVmdCArXG5cblx0XHRcdFx0Ly8gT25seSBmb3IgcmVsYXRpdmUgcG9zaXRpb25lZCBub2RlczogUmVsYXRpdmUgb2Zmc2V0IGZyb20gZWxlbWVudCB0byBvZmZzZXQgcGFyZW50XG5cdFx0XHRcdHRoaXMub2Zmc2V0LnJlbGF0aXZlLmxlZnQgKiBtb2QgK1xuXG5cdFx0XHRcdC8vIFRoZSBvZmZzZXRQYXJlbnQncyBvZmZzZXQgd2l0aG91dCBib3JkZXJzIChvZmZzZXQgKyBib3JkZXIpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudC5sZWZ0ICogbW9kXHQtXG5cdFx0XHRcdCggKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImZpeGVkXCIgP1xuXHRcdFx0XHRcdC10aGlzLnNjcm9sbFBhcmVudC5zY3JvbGxMZWZ0KCkgOiBzY3JvbGxJc1Jvb3ROb2RlID8gMCA6XG5cdFx0XHRcdFx0c2Nyb2xsLnNjcm9sbExlZnQoKSApICogbW9kIClcblx0XHRcdClcblx0XHR9O1xuXG5cdH0sXG5cblx0X2dlbmVyYXRlUG9zaXRpb246IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdHZhciB0b3AsIGxlZnQsXG5cdFx0XHRvID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0cGFnZVggPSBldmVudC5wYWdlWCxcblx0XHRcdHBhZ2VZID0gZXZlbnQucGFnZVksXG5cdFx0XHRzY3JvbGwgPSB0aGlzLmNzc1Bvc2l0aW9uID09PSBcImFic29sdXRlXCIgJiZcblx0XHRcdFx0ISggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSAhPT0gdGhpcy5kb2N1bWVudFsgMCBdICYmXG5cdFx0XHRcdCQuY29udGFpbnMoIHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0sIHRoaXMub2Zmc2V0UGFyZW50WyAwIF0gKSApID9cblx0XHRcdFx0XHR0aGlzLm9mZnNldFBhcmVudCA6XG5cdFx0XHRcdFx0dGhpcy5zY3JvbGxQYXJlbnQsXG5cdFx0XHRcdHNjcm9sbElzUm9vdE5vZGUgPSAoIC8oaHRtbHxib2R5KS9pICkudGVzdCggc2Nyb2xsWyAwIF0udGFnTmFtZSApO1xuXG5cdFx0Ly8gVGhpcyBpcyBhbm90aGVyIHZlcnkgd2VpcmQgc3BlY2lhbCBjYXNlIHRoYXQgb25seSBoYXBwZW5zIGZvciByZWxhdGl2ZSBlbGVtZW50czpcblx0XHQvLyAxLiBJZiB0aGUgY3NzIHBvc2l0aW9uIGlzIHJlbGF0aXZlXG5cdFx0Ly8gMi4gYW5kIHRoZSBzY3JvbGwgcGFyZW50IGlzIHRoZSBkb2N1bWVudCBvciBzaW1pbGFyIHRvIHRoZSBvZmZzZXQgcGFyZW50XG5cdFx0Ly8gd2UgaGF2ZSB0byByZWZyZXNoIHRoZSByZWxhdGl2ZSBvZmZzZXQgZHVyaW5nIHRoZSBzY3JvbGwgc28gdGhlcmUgYXJlIG5vIGp1bXBzXG5cdFx0aWYgKCB0aGlzLmNzc1Bvc2l0aW9uID09PSBcInJlbGF0aXZlXCIgJiYgISggdGhpcy5zY3JvbGxQYXJlbnRbIDAgXSAhPT0gdGhpcy5kb2N1bWVudFsgMCBdICYmXG5cdFx0XHRcdHRoaXMuc2Nyb2xsUGFyZW50WyAwIF0gIT09IHRoaXMub2Zmc2V0UGFyZW50WyAwIF0gKSApIHtcblx0XHRcdHRoaXMub2Zmc2V0LnJlbGF0aXZlID0gdGhpcy5fZ2V0UmVsYXRpdmVPZmZzZXQoKTtcblx0XHR9XG5cblx0XHQvKlxuXHRcdCAqIC0gUG9zaXRpb24gY29uc3RyYWluaW5nIC1cblx0XHQgKiBDb25zdHJhaW4gdGhlIHBvc2l0aW9uIHRvIGEgbWl4IG9mIGdyaWQsIGNvbnRhaW5tZW50LlxuXHRcdCAqL1xuXG5cdFx0aWYgKCB0aGlzLm9yaWdpbmFsUG9zaXRpb24gKSB7IC8vSWYgd2UgYXJlIG5vdCBkcmFnZ2luZyB5ZXQsIHdlIHdvbid0IGNoZWNrIGZvciBvcHRpb25zXG5cblx0XHRcdGlmICggdGhpcy5jb250YWlubWVudCApIHtcblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPCB0aGlzLmNvbnRhaW5tZW50WyAwIF0gKSB7XG5cdFx0XHRcdFx0cGFnZVggPSB0aGlzLmNvbnRhaW5tZW50WyAwIF0gKyB0aGlzLm9mZnNldC5jbGljay5sZWZ0O1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVkgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPCB0aGlzLmNvbnRhaW5tZW50WyAxIF0gKSB7XG5cdFx0XHRcdFx0cGFnZVkgPSB0aGlzLmNvbnRhaW5tZW50WyAxIF0gKyB0aGlzLm9mZnNldC5jbGljay50b3A7XG5cdFx0XHRcdH1cblx0XHRcdFx0aWYgKCBldmVudC5wYWdlWCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPiB0aGlzLmNvbnRhaW5tZW50WyAyIF0gKSB7XG5cdFx0XHRcdFx0cGFnZVggPSB0aGlzLmNvbnRhaW5tZW50WyAyIF0gKyB0aGlzLm9mZnNldC5jbGljay5sZWZ0O1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggZXZlbnQucGFnZVkgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPiB0aGlzLmNvbnRhaW5tZW50WyAzIF0gKSB7XG5cdFx0XHRcdFx0cGFnZVkgPSB0aGlzLmNvbnRhaW5tZW50WyAzIF0gKyB0aGlzLm9mZnNldC5jbGljay50b3A7XG5cdFx0XHRcdH1cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBvLmdyaWQgKSB7XG5cdFx0XHRcdHRvcCA9IHRoaXMub3JpZ2luYWxQYWdlWSArIE1hdGgucm91bmQoICggcGFnZVkgLSB0aGlzLm9yaWdpbmFsUGFnZVkgKSAvXG5cdFx0XHRcdFx0by5ncmlkWyAxIF0gKSAqIG8uZ3JpZFsgMSBdO1xuXHRcdFx0XHRwYWdlWSA9IHRoaXMuY29udGFpbm1lbnQgP1xuXHRcdFx0XHRcdCggKCB0b3AgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPj0gdGhpcy5jb250YWlubWVudFsgMSBdICYmXG5cdFx0XHRcdFx0XHR0b3AgLSB0aGlzLm9mZnNldC5jbGljay50b3AgPD0gdGhpcy5jb250YWlubWVudFsgMyBdICkgP1xuXHRcdFx0XHRcdFx0XHR0b3AgOlxuXHRcdFx0XHRcdFx0XHQoICggdG9wIC0gdGhpcy5vZmZzZXQuY2xpY2sudG9wID49IHRoaXMuY29udGFpbm1lbnRbIDEgXSApID9cblx0XHRcdFx0XHRcdFx0XHR0b3AgLSBvLmdyaWRbIDEgXSA6IHRvcCArIG8uZ3JpZFsgMSBdICkgKSA6XG5cdFx0XHRcdFx0XHRcdFx0dG9wO1xuXG5cdFx0XHRcdGxlZnQgPSB0aGlzLm9yaWdpbmFsUGFnZVggKyBNYXRoLnJvdW5kKCAoIHBhZ2VYIC0gdGhpcy5vcmlnaW5hbFBhZ2VYICkgL1xuXHRcdFx0XHRcdG8uZ3JpZFsgMCBdICkgKiBvLmdyaWRbIDAgXTtcblx0XHRcdFx0cGFnZVggPSB0aGlzLmNvbnRhaW5tZW50ID9cblx0XHRcdFx0XHQoICggbGVmdCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPj0gdGhpcy5jb250YWlubWVudFsgMCBdICYmXG5cdFx0XHRcdFx0XHRsZWZ0IC0gdGhpcy5vZmZzZXQuY2xpY2subGVmdCA8PSB0aGlzLmNvbnRhaW5tZW50WyAyIF0gKSA/XG5cdFx0XHRcdFx0XHRcdGxlZnQgOlxuXHRcdFx0XHRcdFx0XHQoICggbGVmdCAtIHRoaXMub2Zmc2V0LmNsaWNrLmxlZnQgPj0gdGhpcy5jb250YWlubWVudFsgMCBdICkgP1xuXHRcdFx0XHRcdFx0XHRcdGxlZnQgLSBvLmdyaWRbIDAgXSA6IGxlZnQgKyBvLmdyaWRbIDAgXSApICkgOlxuXHRcdFx0XHRcdFx0XHRcdGxlZnQ7XG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dG9wOiAoXG5cblx0XHRcdFx0Ly8gVGhlIGFic29sdXRlIG1vdXNlIHBvc2l0aW9uXG5cdFx0XHRcdHBhZ2VZIC1cblxuXHRcdFx0XHQvLyBDbGljayBvZmZzZXQgKHJlbGF0aXZlIHRvIHRoZSBlbGVtZW50KVxuXHRcdFx0XHR0aGlzLm9mZnNldC5jbGljay50b3AgLVxuXG5cdFx0XHRcdC8vIE9ubHkgZm9yIHJlbGF0aXZlIHBvc2l0aW9uZWQgbm9kZXM6IFJlbGF0aXZlIG9mZnNldCBmcm9tIGVsZW1lbnQgdG8gb2Zmc2V0IHBhcmVudFxuXHRcdFx0XHR0aGlzLm9mZnNldC5yZWxhdGl2ZS50b3AgLVxuXG5cdFx0XHRcdC8vIFRoZSBvZmZzZXRQYXJlbnQncyBvZmZzZXQgd2l0aG91dCBib3JkZXJzIChvZmZzZXQgKyBib3JkZXIpXG5cdFx0XHRcdHRoaXMub2Zmc2V0LnBhcmVudC50b3AgK1xuXHRcdFx0XHQoICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJmaXhlZFwiID9cblx0XHRcdFx0XHQtdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsVG9wKCkgOlxuXHRcdFx0XHRcdCggc2Nyb2xsSXNSb290Tm9kZSA/IDAgOiBzY3JvbGwuc2Nyb2xsVG9wKCkgKSApIClcblx0XHRcdCksXG5cdFx0XHRsZWZ0OiAoXG5cblx0XHRcdFx0Ly8gVGhlIGFic29sdXRlIG1vdXNlIHBvc2l0aW9uXG5cdFx0XHRcdHBhZ2VYIC1cblxuXHRcdFx0XHQvLyBDbGljayBvZmZzZXQgKHJlbGF0aXZlIHRvIHRoZSBlbGVtZW50KVxuXHRcdFx0XHR0aGlzLm9mZnNldC5jbGljay5sZWZ0IC1cblxuXHRcdFx0XHQvLyBPbmx5IGZvciByZWxhdGl2ZSBwb3NpdGlvbmVkIG5vZGVzOiBSZWxhdGl2ZSBvZmZzZXQgZnJvbSBlbGVtZW50IHRvIG9mZnNldCBwYXJlbnRcblx0XHRcdFx0dGhpcy5vZmZzZXQucmVsYXRpdmUubGVmdCAtXG5cblx0XHRcdFx0Ly8gVGhlIG9mZnNldFBhcmVudCdzIG9mZnNldCB3aXRob3V0IGJvcmRlcnMgKG9mZnNldCArIGJvcmRlcilcblx0XHRcdFx0dGhpcy5vZmZzZXQucGFyZW50LmxlZnQgK1xuXHRcdFx0XHQoICggdGhpcy5jc3NQb3NpdGlvbiA9PT0gXCJmaXhlZFwiID9cblx0XHRcdFx0XHQtdGhpcy5zY3JvbGxQYXJlbnQuc2Nyb2xsTGVmdCgpIDpcblx0XHRcdFx0XHRzY3JvbGxJc1Jvb3ROb2RlID8gMCA6IHNjcm9sbC5zY3JvbGxMZWZ0KCkgKSApXG5cdFx0XHQpXG5cdFx0fTtcblxuXHR9LFxuXG5cdF9yZWFycmFuZ2U6IGZ1bmN0aW9uKCBldmVudCwgaSwgYSwgaGFyZFJlZnJlc2ggKSB7XG5cblx0XHRhID8gYVsgMCBdLmFwcGVuZENoaWxkKCB0aGlzLnBsYWNlaG9sZGVyWyAwIF0gKSA6XG5cdFx0XHRpLml0ZW1bIDAgXS5wYXJlbnROb2RlLmluc2VydEJlZm9yZSggdGhpcy5wbGFjZWhvbGRlclsgMCBdLFxuXHRcdFx0XHQoIHRoaXMuZGlyZWN0aW9uID09PSBcImRvd25cIiA/IGkuaXRlbVsgMCBdIDogaS5pdGVtWyAwIF0ubmV4dFNpYmxpbmcgKSApO1xuXG5cdFx0Ly9WYXJpb3VzIHRoaW5ncyBkb25lIGhlcmUgdG8gaW1wcm92ZSB0aGUgcGVyZm9ybWFuY2U6XG5cdFx0Ly8gMS4gd2UgY3JlYXRlIGEgc2V0VGltZW91dCwgdGhhdCBjYWxscyByZWZyZXNoUG9zaXRpb25zXG5cdFx0Ly8gMi4gb24gdGhlIGluc3RhbmNlLCB3ZSBoYXZlIGEgY291bnRlciB2YXJpYWJsZSwgdGhhdCBnZXQncyBoaWdoZXIgYWZ0ZXIgZXZlcnkgYXBwZW5kXG5cdFx0Ly8gMy4gb24gdGhlIGxvY2FsIHNjb3BlLCB3ZSBjb3B5IHRoZSBjb3VudGVyIHZhcmlhYmxlLCBhbmQgY2hlY2sgaW4gdGhlIHRpbWVvdXQsXG5cdFx0Ly8gaWYgaXQncyBzdGlsbCB0aGUgc2FtZVxuXHRcdC8vIDQuIHRoaXMgbGV0cyBvbmx5IHRoZSBsYXN0IGFkZGl0aW9uIHRvIHRoZSB0aW1lb3V0IHN0YWNrIHRocm91Z2hcblx0XHR0aGlzLmNvdW50ZXIgPSB0aGlzLmNvdW50ZXIgPyArK3RoaXMuY291bnRlciA6IDE7XG5cdFx0dmFyIGNvdW50ZXIgPSB0aGlzLmNvdW50ZXI7XG5cblx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoIGNvdW50ZXIgPT09IHRoaXMuY291bnRlciApIHtcblxuXHRcdFx0XHQvL1ByZWNvbXB1dGUgYWZ0ZXIgZWFjaCBET00gaW5zZXJ0aW9uLCBOT1Qgb24gbW91c2Vtb3ZlXG5cdFx0XHRcdHRoaXMucmVmcmVzaFBvc2l0aW9ucyggIWhhcmRSZWZyZXNoICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdH0sXG5cblx0X2NsZWFyOiBmdW5jdGlvbiggZXZlbnQsIG5vUHJvcGFnYXRpb24gKSB7XG5cblx0XHR0aGlzLnJldmVydGluZyA9IGZhbHNlO1xuXG5cdFx0Ly8gV2UgZGVsYXkgYWxsIGV2ZW50cyB0aGF0IGhhdmUgdG8gYmUgdHJpZ2dlcmVkIHRvIGFmdGVyIHRoZSBwb2ludCB3aGVyZSB0aGUgcGxhY2Vob2xkZXJcblx0XHQvLyBoYXMgYmVlbiByZW1vdmVkIGFuZCBldmVyeXRoaW5nIGVsc2Ugbm9ybWFsaXplZCBhZ2FpblxuXHRcdHZhciBpLFxuXHRcdFx0ZGVsYXllZFRyaWdnZXJzID0gW107XG5cblx0XHQvLyBXZSBmaXJzdCBoYXZlIHRvIHVwZGF0ZSB0aGUgZG9tIHBvc2l0aW9uIG9mIHRoZSBhY3R1YWwgY3VycmVudEl0ZW1cblx0XHQvLyBOb3RlOiBkb24ndCBkbyBpdCBpZiB0aGUgY3VycmVudCBpdGVtIGlzIGFscmVhZHkgcmVtb3ZlZCAoYnkgYSB1c2VyKSwgb3IgaXQgZ2V0c1xuXHRcdC8vIHJlYXBwZW5kZWQgKHNlZSAjNDA4OClcblx0XHRpZiAoICF0aGlzLl9ub0ZpbmFsU29ydCAmJiB0aGlzLmN1cnJlbnRJdGVtLnBhcmVudCgpLmxlbmd0aCApIHtcblx0XHRcdHRoaXMucGxhY2Vob2xkZXIuYmVmb3JlKCB0aGlzLmN1cnJlbnRJdGVtICk7XG5cdFx0fVxuXHRcdHRoaXMuX25vRmluYWxTb3J0ID0gbnVsbDtcblxuXHRcdGlmICggdGhpcy5oZWxwZXJbIDAgXSA9PT0gdGhpcy5jdXJyZW50SXRlbVsgMCBdICkge1xuXHRcdFx0Zm9yICggaSBpbiB0aGlzLl9zdG9yZWRDU1MgKSB7XG5cdFx0XHRcdGlmICggdGhpcy5fc3RvcmVkQ1NTWyBpIF0gPT09IFwiYXV0b1wiIHx8IHRoaXMuX3N0b3JlZENTU1sgaSBdID09PSBcInN0YXRpY1wiICkge1xuXHRcdFx0XHRcdHRoaXMuX3N0b3JlZENTU1sgaSBdID0gXCJcIjtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdFx0dGhpcy5jdXJyZW50SXRlbS5jc3MoIHRoaXMuX3N0b3JlZENTUyApO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuY3VycmVudEl0ZW0sIFwidWktc29ydGFibGUtaGVscGVyXCIgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5jdXJyZW50SXRlbS5zaG93KCk7XG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmZyb21PdXRzaWRlICYmICFub1Byb3BhZ2F0aW9uICkge1xuXHRcdFx0ZGVsYXllZFRyaWdnZXJzLnB1c2goIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dGhpcy5fdHJpZ2dlciggXCJyZWNlaXZlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIHRoaXMuZnJvbU91dHNpZGUgKSApO1xuXHRcdFx0fSApO1xuXHRcdH1cblx0XHRpZiAoICggdGhpcy5mcm9tT3V0c2lkZSB8fFxuXHRcdFx0XHR0aGlzLmRvbVBvc2l0aW9uLnByZXYgIT09XG5cdFx0XHRcdHRoaXMuY3VycmVudEl0ZW0ucHJldigpLm5vdCggXCIudWktc29ydGFibGUtaGVscGVyXCIgKVsgMCBdIHx8XG5cdFx0XHRcdHRoaXMuZG9tUG9zaXRpb24ucGFyZW50ICE9PSB0aGlzLmN1cnJlbnRJdGVtLnBhcmVudCgpWyAwIF0gKSAmJiAhbm9Qcm9wYWdhdGlvbiApIHtcblxuXHRcdFx0Ly8gVHJpZ2dlciB1cGRhdGUgY2FsbGJhY2sgaWYgdGhlIERPTSBwb3NpdGlvbiBoYXMgY2hhbmdlZFxuXHRcdFx0ZGVsYXllZFRyaWdnZXJzLnB1c2goIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0dGhpcy5fdHJpZ2dlciggXCJ1cGRhdGVcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCgpICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXG5cdFx0Ly8gQ2hlY2sgaWYgdGhlIGl0ZW1zIENvbnRhaW5lciBoYXMgQ2hhbmdlZCBhbmQgdHJpZ2dlciBhcHByb3ByaWF0ZVxuXHRcdC8vIGV2ZW50cy5cblx0XHRpZiAoIHRoaXMgIT09IHRoaXMuY3VycmVudENvbnRhaW5lciApIHtcblx0XHRcdGlmICggIW5vUHJvcGFnYXRpb24gKSB7XG5cdFx0XHRcdGRlbGF5ZWRUcmlnZ2Vycy5wdXNoKCBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRcdFx0dGhpcy5fdHJpZ2dlciggXCJyZW1vdmVcIiwgZXZlbnQsIHRoaXMuX3VpSGFzaCgpICk7XG5cdFx0XHRcdH0gKTtcblx0XHRcdFx0ZGVsYXllZFRyaWdnZXJzLnB1c2goICggZnVuY3Rpb24oIGMgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0XHRcdGMuX3RyaWdnZXIoIFwicmVjZWl2ZVwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCB0aGlzICkgKTtcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHR9ICkuY2FsbCggdGhpcywgdGhpcy5jdXJyZW50Q29udGFpbmVyICkgKTtcblx0XHRcdFx0ZGVsYXllZFRyaWdnZXJzLnB1c2goICggZnVuY3Rpb24oIGMgKSB7XG5cdFx0XHRcdFx0cmV0dXJuIGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0XHRcdGMuX3RyaWdnZXIoIFwidXBkYXRlXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goIHRoaXMgKSApO1xuXHRcdFx0XHRcdH07XG5cdFx0XHRcdH0gKS5jYWxsKCB0aGlzLCB0aGlzLmN1cnJlbnRDb250YWluZXIgKSApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vUG9zdCBldmVudHMgdG8gY29udGFpbmVyc1xuXHRcdGZ1bmN0aW9uIGRlbGF5RXZlbnQoIHR5cGUsIGluc3RhbmNlLCBjb250YWluZXIgKSB7XG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRjb250YWluZXIuX3RyaWdnZXIoIHR5cGUsIGV2ZW50LCBpbnN0YW5jZS5fdWlIYXNoKCBpbnN0YW5jZSApICk7XG5cdFx0XHR9O1xuXHRcdH1cblx0XHRmb3IgKCBpID0gdGhpcy5jb250YWluZXJzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tICkge1xuXHRcdFx0aWYgKCAhbm9Qcm9wYWdhdGlvbiApIHtcblx0XHRcdFx0ZGVsYXllZFRyaWdnZXJzLnB1c2goIGRlbGF5RXZlbnQoIFwiZGVhY3RpdmF0ZVwiLCB0aGlzLCB0aGlzLmNvbnRhaW5lcnNbIGkgXSApICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLm92ZXIgKSB7XG5cdFx0XHRcdGRlbGF5ZWRUcmlnZ2Vycy5wdXNoKCBkZWxheUV2ZW50KCBcIm91dFwiLCB0aGlzLCB0aGlzLmNvbnRhaW5lcnNbIGkgXSApICk7XG5cdFx0XHRcdHRoaXMuY29udGFpbmVyc1sgaSBdLmNvbnRhaW5lckNhY2hlLm92ZXIgPSAwO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vRG8gd2hhdCB3YXMgb3JpZ2luYWxseSBpbiBwbHVnaW5zXG5cdFx0aWYgKCB0aGlzLnN0b3JlZEN1cnNvciApIHtcblx0XHRcdHRoaXMuZG9jdW1lbnQuZmluZCggXCJib2R5XCIgKS5jc3MoIFwiY3Vyc29yXCIsIHRoaXMuc3RvcmVkQ3Vyc29yICk7XG5cdFx0XHR0aGlzLnN0b3JlZFN0eWxlc2hlZXQucmVtb3ZlKCk7XG5cdFx0fVxuXHRcdGlmICggdGhpcy5fc3RvcmVkT3BhY2l0eSApIHtcblx0XHRcdHRoaXMuaGVscGVyLmNzcyggXCJvcGFjaXR5XCIsIHRoaXMuX3N0b3JlZE9wYWNpdHkgKTtcblx0XHR9XG5cdFx0aWYgKCB0aGlzLl9zdG9yZWRaSW5kZXggKSB7XG5cdFx0XHR0aGlzLmhlbHBlci5jc3MoIFwiekluZGV4XCIsIHRoaXMuX3N0b3JlZFpJbmRleCA9PT0gXCJhdXRvXCIgPyBcIlwiIDogdGhpcy5fc3RvcmVkWkluZGV4ICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5kcmFnZ2luZyA9IGZhbHNlO1xuXG5cdFx0aWYgKCAhbm9Qcm9wYWdhdGlvbiApIHtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiYmVmb3JlU3RvcFwiLCBldmVudCwgdGhpcy5fdWlIYXNoKCkgKTtcblx0XHR9XG5cblx0XHQvLyQodGhpcy5wbGFjZWhvbGRlclswXSkucmVtb3ZlKCk7IHdvdWxkIGhhdmUgYmVlbiB0aGUgalF1ZXJ5IHdheSAtIHVuZm9ydHVuYXRlbHksXG5cdFx0Ly8gaXQgdW5iaW5kcyBBTEwgZXZlbnRzIGZyb20gdGhlIG9yaWdpbmFsIG5vZGUhXG5cdFx0dGhpcy5wbGFjZWhvbGRlclsgMCBdLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoIHRoaXMucGxhY2Vob2xkZXJbIDAgXSApO1xuXG5cdFx0aWYgKCAhdGhpcy5jYW5jZWxIZWxwZXJSZW1vdmFsICkge1xuXHRcdFx0aWYgKCB0aGlzLmhlbHBlclsgMCBdICE9PSB0aGlzLmN1cnJlbnRJdGVtWyAwIF0gKSB7XG5cdFx0XHRcdHRoaXMuaGVscGVyLnJlbW92ZSgpO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5oZWxwZXIgPSBudWxsO1xuXHRcdH1cblxuXHRcdGlmICggIW5vUHJvcGFnYXRpb24gKSB7XG5cdFx0XHRmb3IgKCBpID0gMDsgaSA8IGRlbGF5ZWRUcmlnZ2Vycy5sZW5ndGg7IGkrKyApIHtcblxuXHRcdFx0XHQvLyBUcmlnZ2VyIGFsbCBkZWxheWVkIGV2ZW50c1xuXHRcdFx0XHRkZWxheWVkVHJpZ2dlcnNbIGkgXS5jYWxsKCB0aGlzLCBldmVudCApO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fdHJpZ2dlciggXCJzdG9wXCIsIGV2ZW50LCB0aGlzLl91aUhhc2goKSApO1xuXHRcdH1cblxuXHRcdHRoaXMuZnJvbU91dHNpZGUgPSBmYWxzZTtcblx0XHRyZXR1cm4gIXRoaXMuY2FuY2VsSGVscGVyUmVtb3ZhbDtcblxuXHR9LFxuXG5cdF90cmlnZ2VyOiBmdW5jdGlvbigpIHtcblx0XHRpZiAoICQuV2lkZ2V0LnByb3RvdHlwZS5fdHJpZ2dlci5hcHBseSggdGhpcywgYXJndW1lbnRzICkgPT09IGZhbHNlICkge1xuXHRcdFx0dGhpcy5jYW5jZWwoKTtcblx0XHR9XG5cdH0sXG5cblx0X3VpSGFzaDogZnVuY3Rpb24oIF9pbnN0ICkge1xuXHRcdHZhciBpbnN0ID0gX2luc3QgfHwgdGhpcztcblx0XHRyZXR1cm4ge1xuXHRcdFx0aGVscGVyOiBpbnN0LmhlbHBlcixcblx0XHRcdHBsYWNlaG9sZGVyOiBpbnN0LnBsYWNlaG9sZGVyIHx8ICQoIFtdICksXG5cdFx0XHRwb3NpdGlvbjogaW5zdC5wb3NpdGlvbixcblx0XHRcdG9yaWdpbmFsUG9zaXRpb246IGluc3Qub3JpZ2luYWxQb3NpdGlvbixcblx0XHRcdG9mZnNldDogaW5zdC5wb3NpdGlvbkFicyxcblx0XHRcdGl0ZW06IGluc3QuY3VycmVudEl0ZW0sXG5cdFx0XHRzZW5kZXI6IF9pbnN0ID8gX2luc3QuZWxlbWVudCA6IG51bGxcblx0XHR9O1xuXHR9XG5cbn0gKTtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBTcGlubmVyIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBTcGlubmVyXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogRGlzcGxheXMgYnV0dG9ucyB0byBlYXNpbHkgaW5wdXQgbnVtYmVycyB2aWEgdGhlIGtleWJvYXJkIG9yIG1vdXNlLlxuLy8+PmRvY3M6IGh0dHA6Ly9hcGkuanF1ZXJ5dWkuY29tL3NwaW5uZXIvXG4vLz4+ZGVtb3M6IGh0dHA6Ly9qcXVlcnl1aS5jb20vc3Bpbm5lci9cbi8vPj5jc3Muc3RydWN0dXJlOiAuLi8uLi90aGVtZXMvYmFzZS9jb3JlLmNzc1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL3NwaW5uZXIuY3NzXG4vLz4+Y3NzLnRoZW1lOiAuLi8uLi90aGVtZXMvYmFzZS90aGVtZS5jc3NcblxuXG5cbmZ1bmN0aW9uIHNwaW5uZXJNb2RpZmVyKCBmbiApIHtcblx0cmV0dXJuIGZ1bmN0aW9uKCkge1xuXHRcdHZhciBwcmV2aW91cyA9IHRoaXMuZWxlbWVudC52YWwoKTtcblx0XHRmbi5hcHBseSggdGhpcywgYXJndW1lbnRzICk7XG5cdFx0dGhpcy5fcmVmcmVzaCgpO1xuXHRcdGlmICggcHJldmlvdXMgIT09IHRoaXMuZWxlbWVudC52YWwoKSApIHtcblx0XHRcdHRoaXMuX3RyaWdnZXIoIFwiY2hhbmdlXCIgKTtcblx0XHR9XG5cdH07XG59XG5cbiQud2lkZ2V0KCBcInVpLnNwaW5uZXJcIiwge1xuXHR2ZXJzaW9uOiBcIjEuMTIuMVwiLFxuXHRkZWZhdWx0RWxlbWVudDogXCI8aW5wdXQ+XCIsXG5cdHdpZGdldEV2ZW50UHJlZml4OiBcInNwaW5cIixcblx0b3B0aW9uczoge1xuXHRcdGNsYXNzZXM6IHtcblx0XHRcdFwidWktc3Bpbm5lclwiOiBcInVpLWNvcm5lci1hbGxcIixcblx0XHRcdFwidWktc3Bpbm5lci1kb3duXCI6IFwidWktY29ybmVyLWJyXCIsXG5cdFx0XHRcInVpLXNwaW5uZXItdXBcIjogXCJ1aS1jb3JuZXItdHJcIlxuXHRcdH0sXG5cdFx0Y3VsdHVyZTogbnVsbCxcblx0XHRpY29uczoge1xuXHRcdFx0ZG93bjogXCJ1aS1pY29uLXRyaWFuZ2xlLTEtc1wiLFxuXHRcdFx0dXA6IFwidWktaWNvbi10cmlhbmdsZS0xLW5cIlxuXHRcdH0sXG5cdFx0aW5jcmVtZW50YWw6IHRydWUsXG5cdFx0bWF4OiBudWxsLFxuXHRcdG1pbjogbnVsbCxcblx0XHRudW1iZXJGb3JtYXQ6IG51bGwsXG5cdFx0cGFnZTogMTAsXG5cdFx0c3RlcDogMSxcblxuXHRcdGNoYW5nZTogbnVsbCxcblx0XHRzcGluOiBudWxsLFxuXHRcdHN0YXJ0OiBudWxsLFxuXHRcdHN0b3A6IG51bGxcblx0fSxcblxuXHRfY3JlYXRlOiBmdW5jdGlvbigpIHtcblxuXHRcdC8vIGhhbmRsZSBzdHJpbmcgdmFsdWVzIHRoYXQgbmVlZCB0byBiZSBwYXJzZWRcblx0XHR0aGlzLl9zZXRPcHRpb24oIFwibWF4XCIsIHRoaXMub3B0aW9ucy5tYXggKTtcblx0XHR0aGlzLl9zZXRPcHRpb24oIFwibWluXCIsIHRoaXMub3B0aW9ucy5taW4gKTtcblx0XHR0aGlzLl9zZXRPcHRpb24oIFwic3RlcFwiLCB0aGlzLm9wdGlvbnMuc3RlcCApO1xuXG5cdFx0Ly8gT25seSBmb3JtYXQgaWYgdGhlcmUgaXMgYSB2YWx1ZSwgcHJldmVudHMgdGhlIGZpZWxkIGZyb20gYmVpbmcgbWFya2VkXG5cdFx0Ly8gYXMgaW52YWxpZCBpbiBGaXJlZm94LCBzZWUgIzk1NzMuXG5cdFx0aWYgKCB0aGlzLnZhbHVlKCkgIT09IFwiXCIgKSB7XG5cblx0XHRcdC8vIEZvcm1hdCB0aGUgdmFsdWUsIGJ1dCBkb24ndCBjb25zdHJhaW4uXG5cdFx0XHR0aGlzLl92YWx1ZSggdGhpcy5lbGVtZW50LnZhbCgpLCB0cnVlICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fZHJhdygpO1xuXHRcdHRoaXMuX29uKCB0aGlzLl9ldmVudHMgKTtcblx0XHR0aGlzLl9yZWZyZXNoKCk7XG5cblx0XHQvLyBUdXJuaW5nIG9mZiBhdXRvY29tcGxldGUgcHJldmVudHMgdGhlIGJyb3dzZXIgZnJvbSByZW1lbWJlcmluZyB0aGVcblx0XHQvLyB2YWx1ZSB3aGVuIG5hdmlnYXRpbmcgdGhyb3VnaCBoaXN0b3J5LCBzbyB3ZSByZS1lbmFibGUgYXV0b2NvbXBsZXRlXG5cdFx0Ly8gaWYgdGhlIHBhZ2UgaXMgdW5sb2FkZWQgYmVmb3JlIHRoZSB3aWRnZXQgaXMgZGVzdHJveWVkLiAjNzc5MFxuXHRcdHRoaXMuX29uKCB0aGlzLndpbmRvdywge1xuXHRcdFx0YmVmb3JldW5sb2FkOiBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5lbGVtZW50LnJlbW92ZUF0dHIoIFwiYXV0b2NvbXBsZXRlXCIgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdH0sXG5cblx0X2dldENyZWF0ZU9wdGlvbnM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5fc3VwZXIoKTtcblx0XHR2YXIgZWxlbWVudCA9IHRoaXMuZWxlbWVudDtcblxuXHRcdCQuZWFjaCggWyBcIm1pblwiLCBcIm1heFwiLCBcInN0ZXBcIiBdLCBmdW5jdGlvbiggaSwgb3B0aW9uICkge1xuXHRcdFx0dmFyIHZhbHVlID0gZWxlbWVudC5hdHRyKCBvcHRpb24gKTtcblx0XHRcdGlmICggdmFsdWUgIT0gbnVsbCAmJiB2YWx1ZS5sZW5ndGggKSB7XG5cdFx0XHRcdG9wdGlvbnNbIG9wdGlvbiBdID0gdmFsdWU7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0cmV0dXJuIG9wdGlvbnM7XG5cdH0sXG5cblx0X2V2ZW50czoge1xuXHRcdGtleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdGlmICggdGhpcy5fc3RhcnQoIGV2ZW50ICkgJiYgdGhpcy5fa2V5ZG93biggZXZlbnQgKSApIHtcblx0XHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdH1cblx0XHR9LFxuXHRcdGtleXVwOiBcIl9zdG9wXCIsXG5cdFx0Zm9jdXM6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5wcmV2aW91cyA9IHRoaXMuZWxlbWVudC52YWwoKTtcblx0XHR9LFxuXHRcdGJsdXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdGlmICggdGhpcy5jYW5jZWxCbHVyICkge1xuXHRcdFx0XHRkZWxldGUgdGhpcy5jYW5jZWxCbHVyO1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX3N0b3AoKTtcblx0XHRcdHRoaXMuX3JlZnJlc2goKTtcblx0XHRcdGlmICggdGhpcy5wcmV2aW91cyAhPT0gdGhpcy5lbGVtZW50LnZhbCgpICkge1xuXHRcdFx0XHR0aGlzLl90cmlnZ2VyKCBcImNoYW5nZVwiLCBldmVudCApO1xuXHRcdFx0fVxuXHRcdH0sXG5cdFx0bW91c2V3aGVlbDogZnVuY3Rpb24oIGV2ZW50LCBkZWx0YSApIHtcblx0XHRcdGlmICggIWRlbHRhICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHRpZiAoICF0aGlzLnNwaW5uaW5nICYmICF0aGlzLl9zdGFydCggZXZlbnQgKSApIHtcblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl9zcGluKCAoIGRlbHRhID4gMCA/IDEgOiAtMSApICogdGhpcy5vcHRpb25zLnN0ZXAsIGV2ZW50ICk7XG5cdFx0XHRjbGVhclRpbWVvdXQoIHRoaXMubW91c2V3aGVlbFRpbWVyICk7XG5cdFx0XHR0aGlzLm1vdXNld2hlZWxUaW1lciA9IHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0aWYgKCB0aGlzLnNwaW5uaW5nICkge1xuXHRcdFx0XHRcdHRoaXMuX3N0b3AoIGV2ZW50ICk7XG5cdFx0XHRcdH1cblx0XHRcdH0sIDEwMCApO1xuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHR9LFxuXHRcdFwibW91c2Vkb3duIC51aS1zcGlubmVyLWJ1dHRvblwiOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0XHR2YXIgcHJldmlvdXM7XG5cblx0XHRcdC8vIFdlIG5ldmVyIHdhbnQgdGhlIGJ1dHRvbnMgdG8gaGF2ZSBmb2N1czsgd2hlbmV2ZXIgdGhlIHVzZXIgaXNcblx0XHRcdC8vIGludGVyYWN0aW5nIHdpdGggdGhlIHNwaW5uZXIsIHRoZSBmb2N1cyBzaG91bGQgYmUgb24gdGhlIGlucHV0LlxuXHRcdFx0Ly8gSWYgdGhlIGlucHV0IGlzIGZvY3VzZWQgdGhlbiB0aGlzLnByZXZpb3VzIGlzIHByb3Blcmx5IHNldCBmcm9tXG5cdFx0XHQvLyB3aGVuIHRoZSBpbnB1dCBmaXJzdCByZWNlaXZlZCBmb2N1cy4gSWYgdGhlIGlucHV0IGlzIG5vdCBmb2N1c2VkXG5cdFx0XHQvLyB0aGVuIHdlIG5lZWQgdG8gc2V0IHRoaXMucHJldmlvdXMgYmFzZWQgb24gdGhlIHZhbHVlIGJlZm9yZSBzcGlubmluZy5cblx0XHRcdHByZXZpb3VzID0gdGhpcy5lbGVtZW50WyAwIF0gPT09ICQudWkuc2FmZUFjdGl2ZUVsZW1lbnQoIHRoaXMuZG9jdW1lbnRbIDAgXSApID9cblx0XHRcdFx0dGhpcy5wcmV2aW91cyA6IHRoaXMuZWxlbWVudC52YWwoKTtcblx0XHRcdGZ1bmN0aW9uIGNoZWNrRm9jdXMoKSB7XG5cdFx0XHRcdHZhciBpc0FjdGl2ZSA9IHRoaXMuZWxlbWVudFsgMCBdID09PSAkLnVpLnNhZmVBY3RpdmVFbGVtZW50KCB0aGlzLmRvY3VtZW50WyAwIF0gKTtcblx0XHRcdFx0aWYgKCAhaXNBY3RpdmUgKSB7XG5cdFx0XHRcdFx0dGhpcy5lbGVtZW50LnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdFx0XHRcdHRoaXMucHJldmlvdXMgPSBwcmV2aW91cztcblxuXHRcdFx0XHRcdC8vIHN1cHBvcnQ6IElFXG5cdFx0XHRcdFx0Ly8gSUUgc2V0cyBmb2N1cyBhc3luY2hyb25vdXNseSwgc28gd2UgbmVlZCB0byBjaGVjayBpZiBmb2N1c1xuXHRcdFx0XHRcdC8vIG1vdmVkIG9mZiBvZiB0aGUgaW5wdXQgYmVjYXVzZSB0aGUgdXNlciBjbGlja2VkIG9uIHRoZSBidXR0b24uXG5cdFx0XHRcdFx0dGhpcy5fZGVsYXkoIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRcdFx0dGhpcy5wcmV2aW91cyA9IHByZXZpb3VzO1xuXHRcdFx0XHRcdH0gKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0XHQvLyBFbnN1cmUgZm9jdXMgaXMgb24gKG9yIHN0YXlzIG9uKSB0aGUgdGV4dCBmaWVsZFxuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdGNoZWNrRm9jdXMuY2FsbCggdGhpcyApO1xuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRVxuXHRcdFx0Ly8gSUUgZG9lc24ndCBwcmV2ZW50IG1vdmluZyBmb2N1cyBldmVuIHdpdGggZXZlbnQucHJldmVudERlZmF1bHQoKVxuXHRcdFx0Ly8gc28gd2Ugc2V0IGEgZmxhZyB0byBrbm93IHdoZW4gd2Ugc2hvdWxkIGlnbm9yZSB0aGUgYmx1ciBldmVudFxuXHRcdFx0Ly8gYW5kIGNoZWNrIChhZ2FpbikgaWYgZm9jdXMgbW92ZWQgb2ZmIG9mIHRoZSBpbnB1dC5cblx0XHRcdHRoaXMuY2FuY2VsQmx1ciA9IHRydWU7XG5cdFx0XHR0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGRlbGV0ZSB0aGlzLmNhbmNlbEJsdXI7XG5cdFx0XHRcdGNoZWNrRm9jdXMuY2FsbCggdGhpcyApO1xuXHRcdFx0fSApO1xuXG5cdFx0XHRpZiAoIHRoaXMuX3N0YXJ0KCBldmVudCApID09PSBmYWxzZSApIHtcblx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl9yZXBlYXQoIG51bGwsICQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKVxuXHRcdFx0XHQuaGFzQ2xhc3MoIFwidWktc3Bpbm5lci11cFwiICkgPyAxIDogLTEsIGV2ZW50ICk7XG5cdFx0fSxcblx0XHRcIm1vdXNldXAgLnVpLXNwaW5uZXItYnV0dG9uXCI6IFwiX3N0b3BcIixcblx0XHRcIm1vdXNlZW50ZXIgLnVpLXNwaW5uZXItYnV0dG9uXCI6IGZ1bmN0aW9uKCBldmVudCApIHtcblxuXHRcdFx0Ly8gYnV0dG9uIHdpbGwgYWRkIHVpLXN0YXRlLWFjdGl2ZSBpZiBtb3VzZSB3YXMgZG93biB3aGlsZSBtb3VzZWxlYXZlIGFuZCBrZXB0IGRvd25cblx0XHRcdGlmICggISQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKS5oYXNDbGFzcyggXCJ1aS1zdGF0ZS1hY3RpdmVcIiApICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGhpcy5fc3RhcnQoIGV2ZW50ICkgPT09IGZhbHNlICkge1xuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl9yZXBlYXQoIG51bGwsICQoIGV2ZW50LmN1cnJlbnRUYXJnZXQgKVxuXHRcdFx0XHQuaGFzQ2xhc3MoIFwidWktc3Bpbm5lci11cFwiICkgPyAxIDogLTEsIGV2ZW50ICk7XG5cdFx0fSxcblxuXHRcdC8vIFRPRE86IGRvIHdlIHJlYWxseSB3YW50IHRvIGNvbnNpZGVyIHRoaXMgYSBzdG9wP1xuXHRcdC8vIHNob3VsZG4ndCB3ZSBqdXN0IHN0b3AgdGhlIHJlcGVhdGVyIGFuZCB3YWl0IHVudGlsIG1vdXNldXAgYmVmb3JlXG5cdFx0Ly8gd2UgdHJpZ2dlciB0aGUgc3RvcCBldmVudD9cblx0XHRcIm1vdXNlbGVhdmUgLnVpLXNwaW5uZXItYnV0dG9uXCI6IFwiX3N0b3BcIlxuXHR9LFxuXG5cdC8vIFN1cHBvcnQgbW9iaWxlIGVuaGFuY2VkIG9wdGlvbiBhbmQgbWFrZSBiYWNrY29tcGF0IG1vcmUgc2FuZVxuXHRfZW5oYW5jZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy51aVNwaW5uZXIgPSB0aGlzLmVsZW1lbnRcblx0XHRcdC5hdHRyKCBcImF1dG9jb21wbGV0ZVwiLCBcIm9mZlwiIClcblx0XHRcdC53cmFwKCBcIjxzcGFuPlwiIClcblx0XHRcdC5wYXJlbnQoKVxuXG5cdFx0XHRcdC8vIEFkZCBidXR0b25zXG5cdFx0XHRcdC5hcHBlbmQoXG5cdFx0XHRcdFx0XCI8YT48L2E+PGE+PC9hPlwiXG5cdFx0XHRcdCk7XG5cdH0sXG5cblx0X2RyYXc6IGZ1bmN0aW9uKCkge1xuXHRcdHRoaXMuX2VuaGFuY2UoKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnVpU3Bpbm5lciwgXCJ1aS1zcGlubmVyXCIsIFwidWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50XCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggXCJ1aS1zcGlubmVyLWlucHV0XCIgKTtcblxuXHRcdHRoaXMuZWxlbWVudC5hdHRyKCBcInJvbGVcIiwgXCJzcGluYnV0dG9uXCIgKTtcblxuXHRcdC8vIEJ1dHRvbiBiaW5kaW5nc1xuXHRcdHRoaXMuYnV0dG9ucyA9IHRoaXMudWlTcGlubmVyLmNoaWxkcmVuKCBcImFcIiApXG5cdFx0XHQuYXR0ciggXCJ0YWJJbmRleFwiLCAtMSApXG5cdFx0XHQuYXR0ciggXCJhcmlhLWhpZGRlblwiLCB0cnVlIClcblx0XHRcdC5idXR0b24oIHtcblx0XHRcdFx0Y2xhc3Nlczoge1xuXHRcdFx0XHRcdFwidWktYnV0dG9uXCI6IFwiXCJcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXG5cdFx0Ly8gVE9ETzogUmlnaHQgbm93IGJ1dHRvbiBkb2VzIG5vdCBzdXBwb3J0IGNsYXNzZXMgdGhpcyBpcyBhbHJlYWR5IHVwZGF0ZWQgaW4gYnV0dG9uIFBSXG5cdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIHRoaXMuYnV0dG9ucywgXCJ1aS1jb3JuZXItYWxsXCIgKTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmJ1dHRvbnMuZmlyc3QoKSwgXCJ1aS1zcGlubmVyLWJ1dHRvbiB1aS1zcGlubmVyLXVwXCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5idXR0b25zLmxhc3QoKSwgXCJ1aS1zcGlubmVyLWJ1dHRvbiB1aS1zcGlubmVyLWRvd25cIiApO1xuXHRcdHRoaXMuYnV0dG9ucy5maXJzdCgpLmJ1dHRvbigge1xuXHRcdFx0XCJpY29uXCI6IHRoaXMub3B0aW9ucy5pY29ucy51cCxcblx0XHRcdFwic2hvd0xhYmVsXCI6IGZhbHNlXG5cdFx0fSApO1xuXHRcdHRoaXMuYnV0dG9ucy5sYXN0KCkuYnV0dG9uKCB7XG5cdFx0XHRcImljb25cIjogdGhpcy5vcHRpb25zLmljb25zLmRvd24sXG5cdFx0XHRcInNob3dMYWJlbFwiOiBmYWxzZVxuXHRcdH0gKTtcblxuXHRcdC8vIElFIDYgZG9lc24ndCB1bmRlcnN0YW5kIGhlaWdodDogNTAlIGZvciB0aGUgYnV0dG9uc1xuXHRcdC8vIHVubGVzcyB0aGUgd3JhcHBlciBoYXMgYW4gZXhwbGljaXQgaGVpZ2h0XG5cdFx0aWYgKCB0aGlzLmJ1dHRvbnMuaGVpZ2h0KCkgPiBNYXRoLmNlaWwoIHRoaXMudWlTcGlubmVyLmhlaWdodCgpICogMC41ICkgJiZcblx0XHRcdFx0dGhpcy51aVNwaW5uZXIuaGVpZ2h0KCkgPiAwICkge1xuXHRcdFx0dGhpcy51aVNwaW5uZXIuaGVpZ2h0KCB0aGlzLnVpU3Bpbm5lci5oZWlnaHQoKSApO1xuXHRcdH1cblx0fSxcblxuXHRfa2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zLFxuXHRcdFx0a2V5Q29kZSA9ICQudWkua2V5Q29kZTtcblxuXHRcdHN3aXRjaCAoIGV2ZW50LmtleUNvZGUgKSB7XG5cdFx0Y2FzZSBrZXlDb2RlLlVQOlxuXHRcdFx0dGhpcy5fcmVwZWF0KCBudWxsLCAxLCBldmVudCApO1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0Y2FzZSBrZXlDb2RlLkRPV046XG5cdFx0XHR0aGlzLl9yZXBlYXQoIG51bGwsIC0xLCBldmVudCApO1xuXHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0Y2FzZSBrZXlDb2RlLlBBR0VfVVA6XG5cdFx0XHR0aGlzLl9yZXBlYXQoIG51bGwsIG9wdGlvbnMucGFnZSwgZXZlbnQgKTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdGNhc2Uga2V5Q29kZS5QQUdFX0RPV046XG5cdFx0XHR0aGlzLl9yZXBlYXQoIG51bGwsIC1vcHRpb25zLnBhZ2UsIGV2ZW50ICk7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0sXG5cblx0X3N0YXJ0OiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCAhdGhpcy5zcGlubmluZyAmJiB0aGlzLl90cmlnZ2VyKCBcInN0YXJ0XCIsIGV2ZW50ICkgPT09IGZhbHNlICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdGlmICggIXRoaXMuY291bnRlciApIHtcblx0XHRcdHRoaXMuY291bnRlciA9IDE7XG5cdFx0fVxuXHRcdHRoaXMuc3Bpbm5pbmcgPSB0cnVlO1xuXHRcdHJldHVybiB0cnVlO1xuXHR9LFxuXG5cdF9yZXBlYXQ6IGZ1bmN0aW9uKCBpLCBzdGVwcywgZXZlbnQgKSB7XG5cdFx0aSA9IGkgfHwgNTAwO1xuXG5cdFx0Y2xlYXJUaW1lb3V0KCB0aGlzLnRpbWVyICk7XG5cdFx0dGhpcy50aW1lciA9IHRoaXMuX2RlbGF5KCBmdW5jdGlvbigpIHtcblx0XHRcdHRoaXMuX3JlcGVhdCggNDAsIHN0ZXBzLCBldmVudCApO1xuXHRcdH0sIGkgKTtcblxuXHRcdHRoaXMuX3NwaW4oIHN0ZXBzICogdGhpcy5vcHRpb25zLnN0ZXAsIGV2ZW50ICk7XG5cdH0sXG5cblx0X3NwaW46IGZ1bmN0aW9uKCBzdGVwLCBldmVudCApIHtcblx0XHR2YXIgdmFsdWUgPSB0aGlzLnZhbHVlKCkgfHwgMDtcblxuXHRcdGlmICggIXRoaXMuY291bnRlciApIHtcblx0XHRcdHRoaXMuY291bnRlciA9IDE7XG5cdFx0fVxuXG5cdFx0dmFsdWUgPSB0aGlzLl9hZGp1c3RWYWx1ZSggdmFsdWUgKyBzdGVwICogdGhpcy5faW5jcmVtZW50KCB0aGlzLmNvdW50ZXIgKSApO1xuXG5cdFx0aWYgKCAhdGhpcy5zcGlubmluZyB8fCB0aGlzLl90cmlnZ2VyKCBcInNwaW5cIiwgZXZlbnQsIHsgdmFsdWU6IHZhbHVlIH0gKSAhPT0gZmFsc2UgKSB7XG5cdFx0XHR0aGlzLl92YWx1ZSggdmFsdWUgKTtcblx0XHRcdHRoaXMuY291bnRlcisrO1xuXHRcdH1cblx0fSxcblxuXHRfaW5jcmVtZW50OiBmdW5jdGlvbiggaSApIHtcblx0XHR2YXIgaW5jcmVtZW50YWwgPSB0aGlzLm9wdGlvbnMuaW5jcmVtZW50YWw7XG5cblx0XHRpZiAoIGluY3JlbWVudGFsICkge1xuXHRcdFx0cmV0dXJuICQuaXNGdW5jdGlvbiggaW5jcmVtZW50YWwgKSA/XG5cdFx0XHRcdGluY3JlbWVudGFsKCBpICkgOlxuXHRcdFx0XHRNYXRoLmZsb29yKCBpICogaSAqIGkgLyA1MDAwMCAtIGkgKiBpIC8gNTAwICsgMTcgKiBpIC8gMjAwICsgMSApO1xuXHRcdH1cblxuXHRcdHJldHVybiAxO1xuXHR9LFxuXG5cdF9wcmVjaXNpb246IGZ1bmN0aW9uKCkge1xuXHRcdHZhciBwcmVjaXNpb24gPSB0aGlzLl9wcmVjaXNpb25PZiggdGhpcy5vcHRpb25zLnN0ZXAgKTtcblx0XHRpZiAoIHRoaXMub3B0aW9ucy5taW4gIT09IG51bGwgKSB7XG5cdFx0XHRwcmVjaXNpb24gPSBNYXRoLm1heCggcHJlY2lzaW9uLCB0aGlzLl9wcmVjaXNpb25PZiggdGhpcy5vcHRpb25zLm1pbiApICk7XG5cdFx0fVxuXHRcdHJldHVybiBwcmVjaXNpb247XG5cdH0sXG5cblx0X3ByZWNpc2lvbk9mOiBmdW5jdGlvbiggbnVtICkge1xuXHRcdHZhciBzdHIgPSBudW0udG9TdHJpbmcoKSxcblx0XHRcdGRlY2ltYWwgPSBzdHIuaW5kZXhPZiggXCIuXCIgKTtcblx0XHRyZXR1cm4gZGVjaW1hbCA9PT0gLTEgPyAwIDogc3RyLmxlbmd0aCAtIGRlY2ltYWwgLSAxO1xuXHR9LFxuXG5cdF9hZGp1c3RWYWx1ZTogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHZhciBiYXNlLCBhYm92ZU1pbixcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHQvLyBNYWtlIHN1cmUgd2UncmUgYXQgYSB2YWxpZCBzdGVwXG5cdFx0Ly8gLSBmaW5kIG91dCB3aGVyZSB3ZSBhcmUgcmVsYXRpdmUgdG8gdGhlIGJhc2UgKG1pbiBvciAwKVxuXHRcdGJhc2UgPSBvcHRpb25zLm1pbiAhPT0gbnVsbCA/IG9wdGlvbnMubWluIDogMDtcblx0XHRhYm92ZU1pbiA9IHZhbHVlIC0gYmFzZTtcblxuXHRcdC8vIC0gcm91bmQgdG8gdGhlIG5lYXJlc3Qgc3RlcFxuXHRcdGFib3ZlTWluID0gTWF0aC5yb3VuZCggYWJvdmVNaW4gLyBvcHRpb25zLnN0ZXAgKSAqIG9wdGlvbnMuc3RlcDtcblxuXHRcdC8vIC0gcm91bmRpbmcgaXMgYmFzZWQgb24gMCwgc28gYWRqdXN0IGJhY2sgdG8gb3VyIGJhc2Vcblx0XHR2YWx1ZSA9IGJhc2UgKyBhYm92ZU1pbjtcblxuXHRcdC8vIEZpeCBwcmVjaXNpb24gZnJvbSBiYWQgSlMgZmxvYXRpbmcgcG9pbnQgbWF0aFxuXHRcdHZhbHVlID0gcGFyc2VGbG9hdCggdmFsdWUudG9GaXhlZCggdGhpcy5fcHJlY2lzaW9uKCkgKSApO1xuXG5cdFx0Ly8gQ2xhbXAgdGhlIHZhbHVlXG5cdFx0aWYgKCBvcHRpb25zLm1heCAhPT0gbnVsbCAmJiB2YWx1ZSA+IG9wdGlvbnMubWF4ICkge1xuXHRcdFx0cmV0dXJuIG9wdGlvbnMubWF4O1xuXHRcdH1cblx0XHRpZiAoIG9wdGlvbnMubWluICE9PSBudWxsICYmIHZhbHVlIDwgb3B0aW9ucy5taW4gKSB7XG5cdFx0XHRyZXR1cm4gb3B0aW9ucy5taW47XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHZhbHVlO1xuXHR9LFxuXG5cdF9zdG9wOiBmdW5jdGlvbiggZXZlbnQgKSB7XG5cdFx0aWYgKCAhdGhpcy5zcGlubmluZyApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRjbGVhclRpbWVvdXQoIHRoaXMudGltZXIgKTtcblx0XHRjbGVhclRpbWVvdXQoIHRoaXMubW91c2V3aGVlbFRpbWVyICk7XG5cdFx0dGhpcy5jb3VudGVyID0gMDtcblx0XHR0aGlzLnNwaW5uaW5nID0gZmFsc2U7XG5cdFx0dGhpcy5fdHJpZ2dlciggXCJzdG9wXCIsIGV2ZW50ICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbjogZnVuY3Rpb24oIGtleSwgdmFsdWUgKSB7XG5cdFx0dmFyIHByZXZWYWx1ZSwgZmlyc3QsIGxhc3Q7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJjdWx0dXJlXCIgfHwga2V5ID09PSBcIm51bWJlckZvcm1hdFwiICkge1xuXHRcdFx0cHJldlZhbHVlID0gdGhpcy5fcGFyc2UoIHRoaXMuZWxlbWVudC52YWwoKSApO1xuXHRcdFx0dGhpcy5vcHRpb25zWyBrZXkgXSA9IHZhbHVlO1xuXHRcdFx0dGhpcy5lbGVtZW50LnZhbCggdGhpcy5fZm9ybWF0KCBwcmV2VmFsdWUgKSApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcIm1heFwiIHx8IGtleSA9PT0gXCJtaW5cIiB8fCBrZXkgPT09IFwic3RlcFwiICkge1xuXHRcdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRcdHZhbHVlID0gdGhpcy5fcGFyc2UoIHZhbHVlICk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGlmICgga2V5ID09PSBcImljb25zXCIgKSB7XG5cdFx0XHRmaXJzdCA9IHRoaXMuYnV0dG9ucy5maXJzdCgpLmZpbmQoIFwiLnVpLWljb25cIiApO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGZpcnN0LCBudWxsLCB0aGlzLm9wdGlvbnMuaWNvbnMudXAgKTtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCBmaXJzdCwgbnVsbCwgdmFsdWUudXAgKTtcblx0XHRcdGxhc3QgPSB0aGlzLmJ1dHRvbnMubGFzdCgpLmZpbmQoIFwiLnVpLWljb25cIiApO1xuXHRcdFx0dGhpcy5fcmVtb3ZlQ2xhc3MoIGxhc3QsIG51bGwsIHRoaXMub3B0aW9ucy5pY29ucy5kb3duICk7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggbGFzdCwgbnVsbCwgdmFsdWUuZG93biApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cdH0sXG5cblx0X3NldE9wdGlvbkRpc2FibGVkOiBmdW5jdGlvbiggdmFsdWUgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIHZhbHVlICk7XG5cblx0XHR0aGlzLl90b2dnbGVDbGFzcyggdGhpcy51aVNwaW5uZXIsIG51bGwsIFwidWktc3RhdGUtZGlzYWJsZWRcIiwgISF2YWx1ZSApO1xuXHRcdHRoaXMuZWxlbWVudC5wcm9wKCBcImRpc2FibGVkXCIsICEhdmFsdWUgKTtcblx0XHR0aGlzLmJ1dHRvbnMuYnV0dG9uKCB2YWx1ZSA/IFwiZGlzYWJsZVwiIDogXCJlbmFibGVcIiApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb25zOiBzcGlubmVyTW9kaWZlciggZnVuY3Rpb24oIG9wdGlvbnMgKSB7XG5cdFx0dGhpcy5fc3VwZXIoIG9wdGlvbnMgKTtcblx0fSApLFxuXG5cdF9wYXJzZTogZnVuY3Rpb24oIHZhbCApIHtcblx0XHRpZiAoIHR5cGVvZiB2YWwgPT09IFwic3RyaW5nXCIgJiYgdmFsICE9PSBcIlwiICkge1xuXHRcdFx0dmFsID0gd2luZG93Lkdsb2JhbGl6ZSAmJiB0aGlzLm9wdGlvbnMubnVtYmVyRm9ybWF0ID9cblx0XHRcdFx0R2xvYmFsaXplLnBhcnNlRmxvYXQoIHZhbCwgMTAsIHRoaXMub3B0aW9ucy5jdWx0dXJlICkgOiArdmFsO1xuXHRcdH1cblx0XHRyZXR1cm4gdmFsID09PSBcIlwiIHx8IGlzTmFOKCB2YWwgKSA/IG51bGwgOiB2YWw7XG5cdH0sXG5cblx0X2Zvcm1hdDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdGlmICggdmFsdWUgPT09IFwiXCIgKSB7XG5cdFx0XHRyZXR1cm4gXCJcIjtcblx0XHR9XG5cdFx0cmV0dXJuIHdpbmRvdy5HbG9iYWxpemUgJiYgdGhpcy5vcHRpb25zLm51bWJlckZvcm1hdCA/XG5cdFx0XHRHbG9iYWxpemUuZm9ybWF0KCB2YWx1ZSwgdGhpcy5vcHRpb25zLm51bWJlckZvcm1hdCwgdGhpcy5vcHRpb25zLmN1bHR1cmUgKSA6XG5cdFx0XHR2YWx1ZTtcblx0fSxcblxuXHRfcmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5lbGVtZW50LmF0dHIoIHtcblx0XHRcdFwiYXJpYS12YWx1ZW1pblwiOiB0aGlzLm9wdGlvbnMubWluLFxuXHRcdFx0XCJhcmlhLXZhbHVlbWF4XCI6IHRoaXMub3B0aW9ucy5tYXgsXG5cblx0XHRcdC8vIFRPRE86IHdoYXQgc2hvdWxkIHdlIGRvIHdpdGggdmFsdWVzIHRoYXQgY2FuJ3QgYmUgcGFyc2VkP1xuXHRcdFx0XCJhcmlhLXZhbHVlbm93XCI6IHRoaXMuX3BhcnNlKCB0aGlzLmVsZW1lbnQudmFsKCkgKVxuXHRcdH0gKTtcblx0fSxcblxuXHRpc1ZhbGlkOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdmFsdWUgPSB0aGlzLnZhbHVlKCk7XG5cblx0XHQvLyBOdWxsIGlzIGludmFsaWRcblx0XHRpZiAoIHZhbHVlID09PSBudWxsICkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdC8vIElmIHZhbHVlIGdldHMgYWRqdXN0ZWQsIGl0J3MgaW52YWxpZFxuXHRcdHJldHVybiB2YWx1ZSA9PT0gdGhpcy5fYWRqdXN0VmFsdWUoIHZhbHVlICk7XG5cdH0sXG5cblx0Ly8gVXBkYXRlIHRoZSB2YWx1ZSB3aXRob3V0IHRyaWdnZXJpbmcgY2hhbmdlXG5cdF92YWx1ZTogZnVuY3Rpb24oIHZhbHVlLCBhbGxvd0FueSApIHtcblx0XHR2YXIgcGFyc2VkO1xuXHRcdGlmICggdmFsdWUgIT09IFwiXCIgKSB7XG5cdFx0XHRwYXJzZWQgPSB0aGlzLl9wYXJzZSggdmFsdWUgKTtcblx0XHRcdGlmICggcGFyc2VkICE9PSBudWxsICkge1xuXHRcdFx0XHRpZiAoICFhbGxvd0FueSApIHtcblx0XHRcdFx0XHRwYXJzZWQgPSB0aGlzLl9hZGp1c3RWYWx1ZSggcGFyc2VkICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0dmFsdWUgPSB0aGlzLl9mb3JtYXQoIHBhcnNlZCApO1xuXHRcdFx0fVxuXHRcdH1cblx0XHR0aGlzLmVsZW1lbnQudmFsKCB2YWx1ZSApO1xuXHRcdHRoaXMuX3JlZnJlc2goKTtcblx0fSxcblxuXHRfZGVzdHJveTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5lbGVtZW50XG5cdFx0XHQucHJvcCggXCJkaXNhYmxlZFwiLCBmYWxzZSApXG5cdFx0XHQucmVtb3ZlQXR0ciggXCJhdXRvY29tcGxldGUgcm9sZSBhcmlhLXZhbHVlbWluIGFyaWEtdmFsdWVtYXggYXJpYS12YWx1ZW5vd1wiICk7XG5cblx0XHR0aGlzLnVpU3Bpbm5lci5yZXBsYWNlV2l0aCggdGhpcy5lbGVtZW50ICk7XG5cdH0sXG5cblx0c3RlcFVwOiBzcGlubmVyTW9kaWZlciggZnVuY3Rpb24oIHN0ZXBzICkge1xuXHRcdHRoaXMuX3N0ZXBVcCggc3RlcHMgKTtcblx0fSApLFxuXHRfc3RlcFVwOiBmdW5jdGlvbiggc3RlcHMgKSB7XG5cdFx0aWYgKCB0aGlzLl9zdGFydCgpICkge1xuXHRcdFx0dGhpcy5fc3BpbiggKCBzdGVwcyB8fCAxICkgKiB0aGlzLm9wdGlvbnMuc3RlcCApO1xuXHRcdFx0dGhpcy5fc3RvcCgpO1xuXHRcdH1cblx0fSxcblxuXHRzdGVwRG93bjogc3Bpbm5lck1vZGlmZXIoIGZ1bmN0aW9uKCBzdGVwcyApIHtcblx0XHR0aGlzLl9zdGVwRG93biggc3RlcHMgKTtcblx0fSApLFxuXHRfc3RlcERvd246IGZ1bmN0aW9uKCBzdGVwcyApIHtcblx0XHRpZiAoIHRoaXMuX3N0YXJ0KCkgKSB7XG5cdFx0XHR0aGlzLl9zcGluKCAoIHN0ZXBzIHx8IDEgKSAqIC10aGlzLm9wdGlvbnMuc3RlcCApO1xuXHRcdFx0dGhpcy5fc3RvcCgpO1xuXHRcdH1cblx0fSxcblxuXHRwYWdlVXA6IHNwaW5uZXJNb2RpZmVyKCBmdW5jdGlvbiggcGFnZXMgKSB7XG5cdFx0dGhpcy5fc3RlcFVwKCAoIHBhZ2VzIHx8IDEgKSAqIHRoaXMub3B0aW9ucy5wYWdlICk7XG5cdH0gKSxcblxuXHRwYWdlRG93bjogc3Bpbm5lck1vZGlmZXIoIGZ1bmN0aW9uKCBwYWdlcyApIHtcblx0XHR0aGlzLl9zdGVwRG93biggKCBwYWdlcyB8fCAxICkgKiB0aGlzLm9wdGlvbnMucGFnZSApO1xuXHR9ICksXG5cblx0dmFsdWU6IGZ1bmN0aW9uKCBuZXdWYWwgKSB7XG5cdFx0aWYgKCAhYXJndW1lbnRzLmxlbmd0aCApIHtcblx0XHRcdHJldHVybiB0aGlzLl9wYXJzZSggdGhpcy5lbGVtZW50LnZhbCgpICk7XG5cdFx0fVxuXHRcdHNwaW5uZXJNb2RpZmVyKCB0aGlzLl92YWx1ZSApLmNhbGwoIHRoaXMsIG5ld1ZhbCApO1xuXHR9LFxuXG5cdHdpZGdldDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMudWlTcGlubmVyO1xuXHR9XG59ICk7XG5cbi8vIERFUFJFQ0FURURcbi8vIFRPRE86IHN3aXRjaCByZXR1cm4gYmFjayB0byB3aWRnZXQgZGVjbGFyYXRpb24gYXQgdG9wIG9mIGZpbGUgd2hlbiB0aGlzIGlzIHJlbW92ZWRcbmlmICggJC51aUJhY2tDb21wYXQgIT09IGZhbHNlICkge1xuXG5cdC8vIEJhY2tjb21wYXQgZm9yIHNwaW5uZXIgaHRtbCBleHRlbnNpb24gcG9pbnRzXG5cdCQud2lkZ2V0KCBcInVpLnNwaW5uZXJcIiwgJC51aS5zcGlubmVyLCB7XG5cdFx0X2VuaGFuY2U6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy51aVNwaW5uZXIgPSB0aGlzLmVsZW1lbnRcblx0XHRcdFx0LmF0dHIoIFwiYXV0b2NvbXBsZXRlXCIsIFwib2ZmXCIgKVxuXHRcdFx0XHQud3JhcCggdGhpcy5fdWlTcGlubmVySHRtbCgpIClcblx0XHRcdFx0LnBhcmVudCgpXG5cblx0XHRcdFx0XHQvLyBBZGQgYnV0dG9uc1xuXHRcdFx0XHRcdC5hcHBlbmQoIHRoaXMuX2J1dHRvbkh0bWwoKSApO1xuXHRcdH0sXG5cdFx0X3VpU3Bpbm5lckh0bWw6IGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuIFwiPHNwYW4+XCI7XG5cdFx0fSxcblxuXHRcdF9idXR0b25IdG1sOiBmdW5jdGlvbigpIHtcblx0XHRcdHJldHVybiBcIjxhPjwvYT48YT48L2E+XCI7XG5cdFx0fVxuXHR9ICk7XG59XG5cbnZhciB3aWRnZXRzU3Bpbm5lciA9ICQudWkuc3Bpbm5lcjtcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBUYWJzIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBUYWJzXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogVHJhbnNmb3JtcyBhIHNldCBvZiBjb250YWluZXIgZWxlbWVudHMgaW50byBhIHRhYiBzdHJ1Y3R1cmUuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vdGFicy9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS90YWJzL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvdGFicy5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxuJC53aWRnZXQoIFwidWkudGFic1wiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdGRlbGF5OiAzMDAsXG5cdG9wdGlvbnM6IHtcblx0XHRhY3RpdmU6IG51bGwsXG5cdFx0Y2xhc3Nlczoge1xuXHRcdFx0XCJ1aS10YWJzXCI6IFwidWktY29ybmVyLWFsbFwiLFxuXHRcdFx0XCJ1aS10YWJzLW5hdlwiOiBcInVpLWNvcm5lci1hbGxcIixcblx0XHRcdFwidWktdGFicy1wYW5lbFwiOiBcInVpLWNvcm5lci1ib3R0b21cIixcblx0XHRcdFwidWktdGFicy10YWJcIjogXCJ1aS1jb3JuZXItdG9wXCJcblx0XHR9LFxuXHRcdGNvbGxhcHNpYmxlOiBmYWxzZSxcblx0XHRldmVudDogXCJjbGlja1wiLFxuXHRcdGhlaWdodFN0eWxlOiBcImNvbnRlbnRcIixcblx0XHRoaWRlOiBudWxsLFxuXHRcdHNob3c6IG51bGwsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRhY3RpdmF0ZTogbnVsbCxcblx0XHRiZWZvcmVBY3RpdmF0ZTogbnVsbCxcblx0XHRiZWZvcmVMb2FkOiBudWxsLFxuXHRcdGxvYWQ6IG51bGxcblx0fSxcblxuXHRfaXNMb2NhbDogKCBmdW5jdGlvbigpIHtcblx0XHR2YXIgcmhhc2ggPSAvIy4qJC87XG5cblx0XHRyZXR1cm4gZnVuY3Rpb24oIGFuY2hvciApIHtcblx0XHRcdHZhciBhbmNob3JVcmwsIGxvY2F0aW9uVXJsO1xuXG5cdFx0XHRhbmNob3JVcmwgPSBhbmNob3IuaHJlZi5yZXBsYWNlKCByaGFzaCwgXCJcIiApO1xuXHRcdFx0bG9jYXRpb25VcmwgPSBsb2NhdGlvbi5ocmVmLnJlcGxhY2UoIHJoYXNoLCBcIlwiICk7XG5cblx0XHRcdC8vIERlY29kaW5nIG1heSB0aHJvdyBhbiBlcnJvciBpZiB0aGUgVVJMIGlzbid0IFVURi04ICgjOTUxOClcblx0XHRcdHRyeSB7XG5cdFx0XHRcdGFuY2hvclVybCA9IGRlY29kZVVSSUNvbXBvbmVudCggYW5jaG9yVXJsICk7XG5cdFx0XHR9IGNhdGNoICggZXJyb3IgKSB7fVxuXHRcdFx0dHJ5IHtcblx0XHRcdFx0bG9jYXRpb25VcmwgPSBkZWNvZGVVUklDb21wb25lbnQoIGxvY2F0aW9uVXJsICk7XG5cdFx0XHR9IGNhdGNoICggZXJyb3IgKSB7fVxuXG5cdFx0XHRyZXR1cm4gYW5jaG9yLmhhc2gubGVuZ3RoID4gMSAmJiBhbmNob3JVcmwgPT09IGxvY2F0aW9uVXJsO1xuXHRcdH07XG5cdH0gKSgpLFxuXG5cdF9jcmVhdGU6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHR0aGlzLnJ1bm5pbmcgPSBmYWxzZTtcblxuXHRcdHRoaXMuX2FkZENsYXNzKCBcInVpLXRhYnNcIiwgXCJ1aS13aWRnZXQgdWktd2lkZ2V0LWNvbnRlbnRcIiApO1xuXHRcdHRoaXMuX3RvZ2dsZUNsYXNzKCBcInVpLXRhYnMtY29sbGFwc2libGVcIiwgbnVsbCwgb3B0aW9ucy5jb2xsYXBzaWJsZSApO1xuXG5cdFx0dGhpcy5fcHJvY2Vzc1RhYnMoKTtcblx0XHRvcHRpb25zLmFjdGl2ZSA9IHRoaXMuX2luaXRpYWxBY3RpdmUoKTtcblxuXHRcdC8vIFRha2UgZGlzYWJsaW5nIHRhYnMgdmlhIGNsYXNzIGF0dHJpYnV0ZSBmcm9tIEhUTUxcblx0XHQvLyBpbnRvIGFjY291bnQgYW5kIHVwZGF0ZSBvcHRpb24gcHJvcGVybHkuXG5cdFx0aWYgKCAkLmlzQXJyYXkoIG9wdGlvbnMuZGlzYWJsZWQgKSApIHtcblx0XHRcdG9wdGlvbnMuZGlzYWJsZWQgPSAkLnVuaXF1ZSggb3B0aW9ucy5kaXNhYmxlZC5jb25jYXQoXG5cdFx0XHRcdCQubWFwKCB0aGlzLnRhYnMuZmlsdGVyKCBcIi51aS1zdGF0ZS1kaXNhYmxlZFwiICksIGZ1bmN0aW9uKCBsaSApIHtcblx0XHRcdFx0XHRyZXR1cm4gdGhhdC50YWJzLmluZGV4KCBsaSApO1xuXHRcdFx0XHR9IClcblx0XHRcdCkgKS5zb3J0KCk7XG5cdFx0fVxuXG5cdFx0Ly8gQ2hlY2sgZm9yIGxlbmd0aCBhdm9pZHMgZXJyb3Igd2hlbiBpbml0aWFsaXppbmcgZW1wdHkgbGlzdFxuXHRcdGlmICggdGhpcy5vcHRpb25zLmFjdGl2ZSAhPT0gZmFsc2UgJiYgdGhpcy5hbmNob3JzLmxlbmd0aCApIHtcblx0XHRcdHRoaXMuYWN0aXZlID0gdGhpcy5fZmluZEFjdGl2ZSggb3B0aW9ucy5hY3RpdmUgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5hY3RpdmUgPSAkKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fcmVmcmVzaCgpO1xuXG5cdFx0aWYgKCB0aGlzLmFjdGl2ZS5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLmxvYWQoIG9wdGlvbnMuYWN0aXZlICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9pbml0aWFsQWN0aXZlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgYWN0aXZlID0gdGhpcy5vcHRpb25zLmFjdGl2ZSxcblx0XHRcdGNvbGxhcHNpYmxlID0gdGhpcy5vcHRpb25zLmNvbGxhcHNpYmxlLFxuXHRcdFx0bG9jYXRpb25IYXNoID0gbG9jYXRpb24uaGFzaC5zdWJzdHJpbmcoIDEgKTtcblxuXHRcdGlmICggYWN0aXZlID09PSBudWxsICkge1xuXG5cdFx0XHQvLyBjaGVjayB0aGUgZnJhZ21lbnQgaWRlbnRpZmllciBpbiB0aGUgVVJMXG5cdFx0XHRpZiAoIGxvY2F0aW9uSGFzaCApIHtcblx0XHRcdFx0dGhpcy50YWJzLmVhY2goIGZ1bmN0aW9uKCBpLCB0YWIgKSB7XG5cdFx0XHRcdFx0aWYgKCAkKCB0YWIgKS5hdHRyKCBcImFyaWEtY29udHJvbHNcIiApID09PSBsb2NhdGlvbkhhc2ggKSB7XG5cdFx0XHRcdFx0XHRhY3RpdmUgPSBpO1xuXHRcdFx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBDaGVjayBmb3IgYSB0YWIgbWFya2VkIGFjdGl2ZSB2aWEgYSBjbGFzc1xuXHRcdFx0aWYgKCBhY3RpdmUgPT09IG51bGwgKSB7XG5cdFx0XHRcdGFjdGl2ZSA9IHRoaXMudGFicy5pbmRleCggdGhpcy50YWJzLmZpbHRlciggXCIudWktdGFicy1hY3RpdmVcIiApICk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIE5vIGFjdGl2ZSB0YWIsIHNldCB0byBmYWxzZVxuXHRcdFx0aWYgKCBhY3RpdmUgPT09IG51bGwgfHwgYWN0aXZlID09PSAtMSApIHtcblx0XHRcdFx0YWN0aXZlID0gdGhpcy50YWJzLmxlbmd0aCA/IDAgOiBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBIYW5kbGUgbnVtYmVyczogbmVnYXRpdmUsIG91dCBvZiByYW5nZVxuXHRcdGlmICggYWN0aXZlICE9PSBmYWxzZSApIHtcblx0XHRcdGFjdGl2ZSA9IHRoaXMudGFicy5pbmRleCggdGhpcy50YWJzLmVxKCBhY3RpdmUgKSApO1xuXHRcdFx0aWYgKCBhY3RpdmUgPT09IC0xICkge1xuXHRcdFx0XHRhY3RpdmUgPSBjb2xsYXBzaWJsZSA/IGZhbHNlIDogMDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBEb24ndCBhbGxvdyBjb2xsYXBzaWJsZTogZmFsc2UgYW5kIGFjdGl2ZTogZmFsc2Vcblx0XHRpZiAoICFjb2xsYXBzaWJsZSAmJiBhY3RpdmUgPT09IGZhbHNlICYmIHRoaXMuYW5jaG9ycy5sZW5ndGggKSB7XG5cdFx0XHRhY3RpdmUgPSAwO1xuXHRcdH1cblxuXHRcdHJldHVybiBhY3RpdmU7XG5cdH0sXG5cblx0X2dldENyZWF0ZUV2ZW50RGF0YTogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHtcblx0XHRcdHRhYjogdGhpcy5hY3RpdmUsXG5cdFx0XHRwYW5lbDogIXRoaXMuYWN0aXZlLmxlbmd0aCA/ICQoKSA6IHRoaXMuX2dldFBhbmVsRm9yVGFiKCB0aGlzLmFjdGl2ZSApXG5cdFx0fTtcblx0fSxcblxuXHRfdGFiS2V5ZG93bjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBmb2N1c2VkVGFiID0gJCggJC51aS5zYWZlQWN0aXZlRWxlbWVudCggdGhpcy5kb2N1bWVudFsgMCBdICkgKS5jbG9zZXN0KCBcImxpXCIgKSxcblx0XHRcdHNlbGVjdGVkSW5kZXggPSB0aGlzLnRhYnMuaW5kZXgoIGZvY3VzZWRUYWIgKSxcblx0XHRcdGdvaW5nRm9yd2FyZCA9IHRydWU7XG5cblx0XHRpZiAoIHRoaXMuX2hhbmRsZVBhZ2VOYXYoIGV2ZW50ICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0c3dpdGNoICggZXZlbnQua2V5Q29kZSApIHtcblx0XHRjYXNlICQudWkua2V5Q29kZS5SSUdIVDpcblx0XHRjYXNlICQudWkua2V5Q29kZS5ET1dOOlxuXHRcdFx0c2VsZWN0ZWRJbmRleCsrO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuVVA6XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuTEVGVDpcblx0XHRcdGdvaW5nRm9yd2FyZCA9IGZhbHNlO1xuXHRcdFx0c2VsZWN0ZWRJbmRleC0tO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuRU5EOlxuXHRcdFx0c2VsZWN0ZWRJbmRleCA9IHRoaXMuYW5jaG9ycy5sZW5ndGggLSAxO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuSE9NRTpcblx0XHRcdHNlbGVjdGVkSW5kZXggPSAwO1xuXHRcdFx0YnJlYWs7XG5cdFx0Y2FzZSAkLnVpLmtleUNvZGUuU1BBQ0U6XG5cblx0XHRcdC8vIEFjdGl2YXRlIG9ubHksIG5vIGNvbGxhcHNpbmdcblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRjbGVhclRpbWVvdXQoIHRoaXMuYWN0aXZhdGluZyApO1xuXHRcdFx0dGhpcy5fYWN0aXZhdGUoIHNlbGVjdGVkSW5kZXggKTtcblx0XHRcdHJldHVybjtcblx0XHRjYXNlICQudWkua2V5Q29kZS5FTlRFUjpcblxuXHRcdFx0Ly8gVG9nZ2xlIChjYW5jZWwgZGVsYXllZCBhY3RpdmF0aW9uLCBhbGxvdyBjb2xsYXBzaW5nKVxuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdGNsZWFyVGltZW91dCggdGhpcy5hY3RpdmF0aW5nICk7XG5cblx0XHRcdC8vIERldGVybWluZSBpZiB3ZSBzaG91bGQgY29sbGFwc2Ugb3IgYWN0aXZhdGVcblx0XHRcdHRoaXMuX2FjdGl2YXRlKCBzZWxlY3RlZEluZGV4ID09PSB0aGlzLm9wdGlvbnMuYWN0aXZlID8gZmFsc2UgOiBzZWxlY3RlZEluZGV4ICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0ZGVmYXVsdDpcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBGb2N1cyB0aGUgYXBwcm9wcmlhdGUgdGFiLCBiYXNlZCBvbiB3aGljaCBrZXkgd2FzIHByZXNzZWRcblx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdGNsZWFyVGltZW91dCggdGhpcy5hY3RpdmF0aW5nICk7XG5cdFx0c2VsZWN0ZWRJbmRleCA9IHRoaXMuX2ZvY3VzTmV4dFRhYiggc2VsZWN0ZWRJbmRleCwgZ29pbmdGb3J3YXJkICk7XG5cblx0XHQvLyBOYXZpZ2F0aW5nIHdpdGggY29udHJvbC9jb21tYW5kIGtleSB3aWxsIHByZXZlbnQgYXV0b21hdGljIGFjdGl2YXRpb25cblx0XHRpZiAoICFldmVudC5jdHJsS2V5ICYmICFldmVudC5tZXRhS2V5ICkge1xuXG5cdFx0XHQvLyBVcGRhdGUgYXJpYS1zZWxlY3RlZCBpbW1lZGlhdGVseSBzbyB0aGF0IEFUIHRoaW5rIHRoZSB0YWIgaXMgYWxyZWFkeSBzZWxlY3RlZC5cblx0XHRcdC8vIE90aGVyd2lzZSBBVCBtYXkgY29uZnVzZSB0aGUgdXNlciBieSBzdGF0aW5nIHRoYXQgdGhleSBuZWVkIHRvIGFjdGl2YXRlIHRoZSB0YWIsXG5cdFx0XHQvLyBidXQgdGhlIHRhYiB3aWxsIGFscmVhZHkgYmUgYWN0aXZhdGVkIGJ5IHRoZSB0aW1lIHRoZSBhbm5vdW5jZW1lbnQgZmluaXNoZXMuXG5cdFx0XHRmb2N1c2VkVGFiLmF0dHIoIFwiYXJpYS1zZWxlY3RlZFwiLCBcImZhbHNlXCIgKTtcblx0XHRcdHRoaXMudGFicy5lcSggc2VsZWN0ZWRJbmRleCApLmF0dHIoIFwiYXJpYS1zZWxlY3RlZFwiLCBcInRydWVcIiApO1xuXG5cdFx0XHR0aGlzLmFjdGl2YXRpbmcgPSB0aGlzLl9kZWxheSggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHRoaXMub3B0aW9uKCBcImFjdGl2ZVwiLCBzZWxlY3RlZEluZGV4ICk7XG5cdFx0XHR9LCB0aGlzLmRlbGF5ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9wYW5lbEtleWRvd246IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoIHRoaXMuX2hhbmRsZVBhZ2VOYXYoIGV2ZW50ICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gQ3RybCt1cCBtb3ZlcyBmb2N1cyB0byB0aGUgY3VycmVudCB0YWJcblx0XHRpZiAoIGV2ZW50LmN0cmxLZXkgJiYgZXZlbnQua2V5Q29kZSA9PT0gJC51aS5rZXlDb2RlLlVQICkge1xuXHRcdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblx0XHRcdHRoaXMuYWN0aXZlLnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdH1cblx0fSxcblxuXHQvLyBBbHQrcGFnZSB1cC9kb3duIG1vdmVzIGZvY3VzIHRvIHRoZSBwcmV2aW91cy9uZXh0IHRhYiAoYW5kIGFjdGl2YXRlcylcblx0X2hhbmRsZVBhZ2VOYXY6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRpZiAoIGV2ZW50LmFsdEtleSAmJiBldmVudC5rZXlDb2RlID09PSAkLnVpLmtleUNvZGUuUEFHRV9VUCApIHtcblx0XHRcdHRoaXMuX2FjdGl2YXRlKCB0aGlzLl9mb2N1c05leHRUYWIoIHRoaXMub3B0aW9ucy5hY3RpdmUgLSAxLCBmYWxzZSApICk7XG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblx0XHR9XG5cdFx0aWYgKCBldmVudC5hbHRLZXkgJiYgZXZlbnQua2V5Q29kZSA9PT0gJC51aS5rZXlDb2RlLlBBR0VfRE9XTiApIHtcblx0XHRcdHRoaXMuX2FjdGl2YXRlKCB0aGlzLl9mb2N1c05leHRUYWIoIHRoaXMub3B0aW9ucy5hY3RpdmUgKyAxLCB0cnVlICkgKTtcblx0XHRcdHJldHVybiB0cnVlO1xuXHRcdH1cblx0fSxcblxuXHRfZmluZE5leHRUYWI6IGZ1bmN0aW9uKCBpbmRleCwgZ29pbmdGb3J3YXJkICkge1xuXHRcdHZhciBsYXN0VGFiSW5kZXggPSB0aGlzLnRhYnMubGVuZ3RoIC0gMTtcblxuXHRcdGZ1bmN0aW9uIGNvbnN0cmFpbigpIHtcblx0XHRcdGlmICggaW5kZXggPiBsYXN0VGFiSW5kZXggKSB7XG5cdFx0XHRcdGluZGV4ID0gMDtcblx0XHRcdH1cblx0XHRcdGlmICggaW5kZXggPCAwICkge1xuXHRcdFx0XHRpbmRleCA9IGxhc3RUYWJJbmRleDtcblx0XHRcdH1cblx0XHRcdHJldHVybiBpbmRleDtcblx0XHR9XG5cblx0XHR3aGlsZSAoICQuaW5BcnJheSggY29uc3RyYWluKCksIHRoaXMub3B0aW9ucy5kaXNhYmxlZCApICE9PSAtMSApIHtcblx0XHRcdGluZGV4ID0gZ29pbmdGb3J3YXJkID8gaW5kZXggKyAxIDogaW5kZXggLSAxO1xuXHRcdH1cblxuXHRcdHJldHVybiBpbmRleDtcblx0fSxcblxuXHRfZm9jdXNOZXh0VGFiOiBmdW5jdGlvbiggaW5kZXgsIGdvaW5nRm9yd2FyZCApIHtcblx0XHRpbmRleCA9IHRoaXMuX2ZpbmROZXh0VGFiKCBpbmRleCwgZ29pbmdGb3J3YXJkICk7XG5cdFx0dGhpcy50YWJzLmVxKCBpbmRleCApLnRyaWdnZXIoIFwiZm9jdXNcIiApO1xuXHRcdHJldHVybiBpbmRleDtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHRpZiAoIGtleSA9PT0gXCJhY3RpdmVcIiApIHtcblxuXHRcdFx0Ly8gX2FjdGl2YXRlKCkgd2lsbCBoYW5kbGUgaW52YWxpZCB2YWx1ZXMgYW5kIHVwZGF0ZSB0aGlzLm9wdGlvbnNcblx0XHRcdHRoaXMuX2FjdGl2YXRlKCB2YWx1ZSApO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuX3N1cGVyKCBrZXksIHZhbHVlICk7XG5cblx0XHRpZiAoIGtleSA9PT0gXCJjb2xsYXBzaWJsZVwiICkge1xuXHRcdFx0dGhpcy5fdG9nZ2xlQ2xhc3MoIFwidWktdGFicy1jb2xsYXBzaWJsZVwiLCBudWxsLCB2YWx1ZSApO1xuXG5cdFx0XHQvLyBTZXR0aW5nIGNvbGxhcHNpYmxlOiBmYWxzZSB3aGlsZSBjb2xsYXBzZWQ7IG9wZW4gZmlyc3QgcGFuZWxcblx0XHRcdGlmICggIXZhbHVlICYmIHRoaXMub3B0aW9ucy5hY3RpdmUgPT09IGZhbHNlICkge1xuXHRcdFx0XHR0aGlzLl9hY3RpdmF0ZSggMCApO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICgga2V5ID09PSBcImV2ZW50XCIgKSB7XG5cdFx0XHR0aGlzLl9zZXR1cEV2ZW50cyggdmFsdWUgKTtcblx0XHR9XG5cblx0XHRpZiAoIGtleSA9PT0gXCJoZWlnaHRTdHlsZVwiICkge1xuXHRcdFx0dGhpcy5fc2V0dXBIZWlnaHRTdHlsZSggdmFsdWUgKTtcblx0XHR9XG5cdH0sXG5cblx0X3Nhbml0aXplU2VsZWN0b3I6IGZ1bmN0aW9uKCBoYXNoICkge1xuXHRcdHJldHVybiBoYXNoID8gaGFzaC5yZXBsYWNlKCAvWyFcIiQlJicoKSorLC5cXC86Ozw9Pj9AXFxbXFxdXFxeYHt8fX5dL2csIFwiXFxcXCQmXCIgKSA6IFwiXCI7XG5cdH0sXG5cblx0cmVmcmVzaDogZnVuY3Rpb24oKSB7XG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXG5cdFx0XHRsaXMgPSB0aGlzLnRhYmxpc3QuY2hpbGRyZW4oIFwiOmhhcyhhW2hyZWZdKVwiICk7XG5cblx0XHQvLyBHZXQgZGlzYWJsZWQgdGFicyBmcm9tIGNsYXNzIGF0dHJpYnV0ZSBmcm9tIEhUTUxcblx0XHQvLyB0aGlzIHdpbGwgZ2V0IGNvbnZlcnRlZCB0byBhIGJvb2xlYW4gaWYgbmVlZGVkIGluIF9yZWZyZXNoKClcblx0XHRvcHRpb25zLmRpc2FibGVkID0gJC5tYXAoIGxpcy5maWx0ZXIoIFwiLnVpLXN0YXRlLWRpc2FibGVkXCIgKSwgZnVuY3Rpb24oIHRhYiApIHtcblx0XHRcdHJldHVybiBsaXMuaW5kZXgoIHRhYiApO1xuXHRcdH0gKTtcblxuXHRcdHRoaXMuX3Byb2Nlc3NUYWJzKCk7XG5cblx0XHQvLyBXYXMgY29sbGFwc2VkIG9yIG5vIHRhYnNcblx0XHRpZiAoIG9wdGlvbnMuYWN0aXZlID09PSBmYWxzZSB8fCAhdGhpcy5hbmNob3JzLmxlbmd0aCApIHtcblx0XHRcdG9wdGlvbnMuYWN0aXZlID0gZmFsc2U7XG5cdFx0XHR0aGlzLmFjdGl2ZSA9ICQoKTtcblxuXHRcdC8vIHdhcyBhY3RpdmUsIGJ1dCBhY3RpdmUgdGFiIGlzIGdvbmVcblx0XHR9IGVsc2UgaWYgKCB0aGlzLmFjdGl2ZS5sZW5ndGggJiYgISQuY29udGFpbnMoIHRoaXMudGFibGlzdFsgMCBdLCB0aGlzLmFjdGl2ZVsgMCBdICkgKSB7XG5cblx0XHRcdC8vIGFsbCByZW1haW5pbmcgdGFicyBhcmUgZGlzYWJsZWRcblx0XHRcdGlmICggdGhpcy50YWJzLmxlbmd0aCA9PT0gb3B0aW9ucy5kaXNhYmxlZC5sZW5ndGggKSB7XG5cdFx0XHRcdG9wdGlvbnMuYWN0aXZlID0gZmFsc2U7XG5cdFx0XHRcdHRoaXMuYWN0aXZlID0gJCgpO1xuXG5cdFx0XHQvLyBhY3RpdmF0ZSBwcmV2aW91cyB0YWJcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRoaXMuX2FjdGl2YXRlKCB0aGlzLl9maW5kTmV4dFRhYiggTWF0aC5tYXgoIDAsIG9wdGlvbnMuYWN0aXZlIC0gMSApLCBmYWxzZSApICk7XG5cdFx0XHR9XG5cblx0XHQvLyB3YXMgYWN0aXZlLCBhY3RpdmUgdGFiIHN0aWxsIGV4aXN0c1xuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIG1ha2Ugc3VyZSBhY3RpdmUgaW5kZXggaXMgY29ycmVjdFxuXHRcdFx0b3B0aW9ucy5hY3RpdmUgPSB0aGlzLnRhYnMuaW5kZXgoIHRoaXMuYWN0aXZlICk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fcmVmcmVzaCgpO1xuXHR9LFxuXG5cdF9yZWZyZXNoOiBmdW5jdGlvbigpIHtcblx0XHR0aGlzLl9zZXRPcHRpb25EaXNhYmxlZCggdGhpcy5vcHRpb25zLmRpc2FibGVkICk7XG5cdFx0dGhpcy5fc2V0dXBFdmVudHMoIHRoaXMub3B0aW9ucy5ldmVudCApO1xuXHRcdHRoaXMuX3NldHVwSGVpZ2h0U3R5bGUoIHRoaXMub3B0aW9ucy5oZWlnaHRTdHlsZSApO1xuXG5cdFx0dGhpcy50YWJzLm5vdCggdGhpcy5hY3RpdmUgKS5hdHRyKCB7XG5cdFx0XHRcImFyaWEtc2VsZWN0ZWRcIjogXCJmYWxzZVwiLFxuXHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwiZmFsc2VcIixcblx0XHRcdHRhYkluZGV4OiAtMVxuXHRcdH0gKTtcblx0XHR0aGlzLnBhbmVscy5ub3QoIHRoaXMuX2dldFBhbmVsRm9yVGFiKCB0aGlzLmFjdGl2ZSApIClcblx0XHRcdC5oaWRlKClcblx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdFwiYXJpYS1oaWRkZW5cIjogXCJ0cnVlXCJcblx0XHRcdH0gKTtcblxuXHRcdC8vIE1ha2Ugc3VyZSBvbmUgdGFiIGlzIGluIHRoZSB0YWIgb3JkZXJcblx0XHRpZiAoICF0aGlzLmFjdGl2ZS5sZW5ndGggKSB7XG5cdFx0XHR0aGlzLnRhYnMuZXEoIDAgKS5hdHRyKCBcInRhYkluZGV4XCIsIDAgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5hY3RpdmVcblx0XHRcdFx0LmF0dHIoIHtcblx0XHRcdFx0XHRcImFyaWEtc2VsZWN0ZWRcIjogXCJ0cnVlXCIsXG5cdFx0XHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwidHJ1ZVwiLFxuXHRcdFx0XHRcdHRhYkluZGV4OiAwXG5cdFx0XHRcdH0gKTtcblx0XHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmFjdGl2ZSwgXCJ1aS10YWJzLWFjdGl2ZVwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHR0aGlzLl9nZXRQYW5lbEZvclRhYiggdGhpcy5hY3RpdmUgKVxuXHRcdFx0XHQuc2hvdygpXG5cdFx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdFx0XCJhcmlhLWhpZGRlblwiOiBcImZhbHNlXCJcblx0XHRcdFx0fSApO1xuXHRcdH1cblx0fSxcblxuXHRfcHJvY2Vzc1RhYnM6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdHByZXZUYWJzID0gdGhpcy50YWJzLFxuXHRcdFx0cHJldkFuY2hvcnMgPSB0aGlzLmFuY2hvcnMsXG5cdFx0XHRwcmV2UGFuZWxzID0gdGhpcy5wYW5lbHM7XG5cblx0XHR0aGlzLnRhYmxpc3QgPSB0aGlzLl9nZXRMaXN0KCkuYXR0ciggXCJyb2xlXCIsIFwidGFibGlzdFwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMudGFibGlzdCwgXCJ1aS10YWJzLW5hdlwiLFxuXHRcdFx0XCJ1aS1oZWxwZXItcmVzZXQgdWktaGVscGVyLWNsZWFyZml4IHVpLXdpZGdldC1oZWFkZXJcIiApO1xuXG5cdFx0Ly8gUHJldmVudCB1c2VycyBmcm9tIGZvY3VzaW5nIGRpc2FibGVkIHRhYnMgdmlhIGNsaWNrXG5cdFx0dGhpcy50YWJsaXN0XG5cdFx0XHQub24oIFwibW91c2Vkb3duXCIgKyB0aGlzLmV2ZW50TmFtZXNwYWNlLCBcIj4gbGlcIiwgZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRpZiAoICQoIHRoaXMgKS5pcyggXCIudWktc3RhdGUtZGlzYWJsZWRcIiApICkge1xuXHRcdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdH1cblx0XHRcdH0gKVxuXG5cdFx0XHQvLyBTdXBwb3J0OiBJRSA8OVxuXHRcdFx0Ly8gUHJldmVudGluZyB0aGUgZGVmYXVsdCBhY3Rpb24gaW4gbW91c2Vkb3duIGRvZXNuJ3QgcHJldmVudCBJRVxuXHRcdFx0Ly8gZnJvbSBmb2N1c2luZyB0aGUgZWxlbWVudCwgc28gaWYgdGhlIGFuY2hvciBnZXRzIGZvY3VzZWQsIGJsdXIuXG5cdFx0XHQvLyBXZSBkb24ndCBoYXZlIHRvIHdvcnJ5IGFib3V0IGZvY3VzaW5nIHRoZSBwcmV2aW91c2x5IGZvY3VzZWRcblx0XHRcdC8vIGVsZW1lbnQgc2luY2UgY2xpY2tpbmcgb24gYSBub24tZm9jdXNhYmxlIGVsZW1lbnQgc2hvdWxkIGZvY3VzXG5cdFx0XHQvLyB0aGUgYm9keSBhbnl3YXkuXG5cdFx0XHQub24oIFwiZm9jdXNcIiArIHRoaXMuZXZlbnROYW1lc3BhY2UsIFwiLnVpLXRhYnMtYW5jaG9yXCIsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHRpZiAoICQoIHRoaXMgKS5jbG9zZXN0KCBcImxpXCIgKS5pcyggXCIudWktc3RhdGUtZGlzYWJsZWRcIiApICkge1xuXHRcdFx0XHRcdHRoaXMuYmx1cigpO1xuXHRcdFx0XHR9XG5cdFx0XHR9ICk7XG5cblx0XHR0aGlzLnRhYnMgPSB0aGlzLnRhYmxpc3QuZmluZCggXCI+IGxpOmhhcyhhW2hyZWZdKVwiIClcblx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdHJvbGU6IFwidGFiXCIsXG5cdFx0XHRcdHRhYkluZGV4OiAtMVxuXHRcdFx0fSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLnRhYnMsIFwidWktdGFicy10YWJcIiwgXCJ1aS1zdGF0ZS1kZWZhdWx0XCIgKTtcblxuXHRcdHRoaXMuYW5jaG9ycyA9IHRoaXMudGFicy5tYXAoIGZ1bmN0aW9uKCkge1xuXHRcdFx0cmV0dXJuICQoIFwiYVwiLCB0aGlzIClbIDAgXTtcblx0XHR9IClcblx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdHJvbGU6IFwicHJlc2VudGF0aW9uXCIsXG5cdFx0XHRcdHRhYkluZGV4OiAtMVxuXHRcdFx0fSApO1xuXHRcdHRoaXMuX2FkZENsYXNzKCB0aGlzLmFuY2hvcnMsIFwidWktdGFicy1hbmNob3JcIiApO1xuXG5cdFx0dGhpcy5wYW5lbHMgPSAkKCk7XG5cblx0XHR0aGlzLmFuY2hvcnMuZWFjaCggZnVuY3Rpb24oIGksIGFuY2hvciApIHtcblx0XHRcdHZhciBzZWxlY3RvciwgcGFuZWwsIHBhbmVsSWQsXG5cdFx0XHRcdGFuY2hvcklkID0gJCggYW5jaG9yICkudW5pcXVlSWQoKS5hdHRyKCBcImlkXCIgKSxcblx0XHRcdFx0dGFiID0gJCggYW5jaG9yICkuY2xvc2VzdCggXCJsaVwiICksXG5cdFx0XHRcdG9yaWdpbmFsQXJpYUNvbnRyb2xzID0gdGFiLmF0dHIoIFwiYXJpYS1jb250cm9sc1wiICk7XG5cblx0XHRcdC8vIElubGluZSB0YWJcblx0XHRcdGlmICggdGhhdC5faXNMb2NhbCggYW5jaG9yICkgKSB7XG5cdFx0XHRcdHNlbGVjdG9yID0gYW5jaG9yLmhhc2g7XG5cdFx0XHRcdHBhbmVsSWQgPSBzZWxlY3Rvci5zdWJzdHJpbmcoIDEgKTtcblx0XHRcdFx0cGFuZWwgPSB0aGF0LmVsZW1lbnQuZmluZCggdGhhdC5fc2FuaXRpemVTZWxlY3Rvciggc2VsZWN0b3IgKSApO1xuXG5cdFx0XHQvLyByZW1vdGUgdGFiXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIElmIHRoZSB0YWIgZG9lc24ndCBhbHJlYWR5IGhhdmUgYXJpYS1jb250cm9scyxcblx0XHRcdFx0Ly8gZ2VuZXJhdGUgYW4gaWQgYnkgdXNpbmcgYSB0aHJvdy1hd2F5IGVsZW1lbnRcblx0XHRcdFx0cGFuZWxJZCA9IHRhYi5hdHRyKCBcImFyaWEtY29udHJvbHNcIiApIHx8ICQoIHt9ICkudW5pcXVlSWQoKVsgMCBdLmlkO1xuXHRcdFx0XHRzZWxlY3RvciA9IFwiI1wiICsgcGFuZWxJZDtcblx0XHRcdFx0cGFuZWwgPSB0aGF0LmVsZW1lbnQuZmluZCggc2VsZWN0b3IgKTtcblx0XHRcdFx0aWYgKCAhcGFuZWwubGVuZ3RoICkge1xuXHRcdFx0XHRcdHBhbmVsID0gdGhhdC5fY3JlYXRlUGFuZWwoIHBhbmVsSWQgKTtcblx0XHRcdFx0XHRwYW5lbC5pbnNlcnRBZnRlciggdGhhdC5wYW5lbHNbIGkgLSAxIF0gfHwgdGhhdC50YWJsaXN0ICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0cGFuZWwuYXR0ciggXCJhcmlhLWxpdmVcIiwgXCJwb2xpdGVcIiApO1xuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHBhbmVsLmxlbmd0aCApIHtcblx0XHRcdFx0dGhhdC5wYW5lbHMgPSB0aGF0LnBhbmVscy5hZGQoIHBhbmVsICk7XG5cdFx0XHR9XG5cdFx0XHRpZiAoIG9yaWdpbmFsQXJpYUNvbnRyb2xzICkge1xuXHRcdFx0XHR0YWIuZGF0YSggXCJ1aS10YWJzLWFyaWEtY29udHJvbHNcIiwgb3JpZ2luYWxBcmlhQ29udHJvbHMgKTtcblx0XHRcdH1cblx0XHRcdHRhYi5hdHRyKCB7XG5cdFx0XHRcdFwiYXJpYS1jb250cm9sc1wiOiBwYW5lbElkLFxuXHRcdFx0XHRcImFyaWEtbGFiZWxsZWRieVwiOiBhbmNob3JJZFxuXHRcdFx0fSApO1xuXHRcdFx0cGFuZWwuYXR0ciggXCJhcmlhLWxhYmVsbGVkYnlcIiwgYW5jaG9ySWQgKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLnBhbmVscy5hdHRyKCBcInJvbGVcIiwgXCJ0YWJwYW5lbFwiICk7XG5cdFx0dGhpcy5fYWRkQ2xhc3MoIHRoaXMucGFuZWxzLCBcInVpLXRhYnMtcGFuZWxcIiwgXCJ1aS13aWRnZXQtY29udGVudFwiICk7XG5cblx0XHQvLyBBdm9pZCBtZW1vcnkgbGVha3MgKCMxMDA1Nilcblx0XHRpZiAoIHByZXZUYWJzICkge1xuXHRcdFx0dGhpcy5fb2ZmKCBwcmV2VGFicy5ub3QoIHRoaXMudGFicyApICk7XG5cdFx0XHR0aGlzLl9vZmYoIHByZXZBbmNob3JzLm5vdCggdGhpcy5hbmNob3JzICkgKTtcblx0XHRcdHRoaXMuX29mZiggcHJldlBhbmVscy5ub3QoIHRoaXMucGFuZWxzICkgKTtcblx0XHR9XG5cdH0sXG5cblx0Ly8gQWxsb3cgb3ZlcnJpZGluZyBob3cgdG8gZmluZCB0aGUgbGlzdCBmb3IgcmFyZSB1c2FnZSBzY2VuYXJpb3MgKCM3NzE1KVxuXHRfZ2V0TGlzdDogZnVuY3Rpb24oKSB7XG5cdFx0cmV0dXJuIHRoaXMudGFibGlzdCB8fCB0aGlzLmVsZW1lbnQuZmluZCggXCJvbCwgdWxcIiApLmVxKCAwICk7XG5cdH0sXG5cblx0X2NyZWF0ZVBhbmVsOiBmdW5jdGlvbiggaWQgKSB7XG5cdFx0cmV0dXJuICQoIFwiPGRpdj5cIiApXG5cdFx0XHQuYXR0ciggXCJpZFwiLCBpZCApXG5cdFx0XHQuZGF0YSggXCJ1aS10YWJzLWRlc3Ryb3lcIiwgdHJ1ZSApO1xuXHR9LFxuXG5cdF9zZXRPcHRpb25EaXNhYmxlZDogZnVuY3Rpb24oIGRpc2FibGVkICkge1xuXHRcdHZhciBjdXJyZW50SXRlbSwgbGksIGk7XG5cblx0XHRpZiAoICQuaXNBcnJheSggZGlzYWJsZWQgKSApIHtcblx0XHRcdGlmICggIWRpc2FibGVkLmxlbmd0aCApIHtcblx0XHRcdFx0ZGlzYWJsZWQgPSBmYWxzZTtcblx0XHRcdH0gZWxzZSBpZiAoIGRpc2FibGVkLmxlbmd0aCA9PT0gdGhpcy5hbmNob3JzLmxlbmd0aCApIHtcblx0XHRcdFx0ZGlzYWJsZWQgPSB0cnVlO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdC8vIERpc2FibGUgdGFic1xuXHRcdGZvciAoIGkgPSAwOyAoIGxpID0gdGhpcy50YWJzWyBpIF0gKTsgaSsrICkge1xuXHRcdFx0Y3VycmVudEl0ZW0gPSAkKCBsaSApO1xuXHRcdFx0aWYgKCBkaXNhYmxlZCA9PT0gdHJ1ZSB8fCAkLmluQXJyYXkoIGksIGRpc2FibGVkICkgIT09IC0xICkge1xuXHRcdFx0XHRjdXJyZW50SXRlbS5hdHRyKCBcImFyaWEtZGlzYWJsZWRcIiwgXCJ0cnVlXCIgKTtcblx0XHRcdFx0dGhpcy5fYWRkQ2xhc3MoIGN1cnJlbnRJdGVtLCBudWxsLCBcInVpLXN0YXRlLWRpc2FibGVkXCIgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGN1cnJlbnRJdGVtLnJlbW92ZUF0dHIoIFwiYXJpYS1kaXNhYmxlZFwiICk7XG5cdFx0XHRcdHRoaXMuX3JlbW92ZUNsYXNzKCBjdXJyZW50SXRlbSwgbnVsbCwgXCJ1aS1zdGF0ZS1kaXNhYmxlZFwiICk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5vcHRpb25zLmRpc2FibGVkID0gZGlzYWJsZWQ7XG5cblx0XHR0aGlzLl90b2dnbGVDbGFzcyggdGhpcy53aWRnZXQoKSwgdGhpcy53aWRnZXRGdWxsTmFtZSArIFwiLWRpc2FibGVkXCIsIG51bGwsXG5cdFx0XHRkaXNhYmxlZCA9PT0gdHJ1ZSApO1xuXHR9LFxuXG5cdF9zZXR1cEV2ZW50czogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciBldmVudHMgPSB7fTtcblx0XHRpZiAoIGV2ZW50ICkge1xuXHRcdFx0JC5lYWNoKCBldmVudC5zcGxpdCggXCIgXCIgKSwgZnVuY3Rpb24oIGluZGV4LCBldmVudE5hbWUgKSB7XG5cdFx0XHRcdGV2ZW50c1sgZXZlbnROYW1lIF0gPSBcIl9ldmVudEhhbmRsZXJcIjtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHR0aGlzLl9vZmYoIHRoaXMuYW5jaG9ycy5hZGQoIHRoaXMudGFicyApLmFkZCggdGhpcy5wYW5lbHMgKSApO1xuXG5cdFx0Ly8gQWx3YXlzIHByZXZlbnQgdGhlIGRlZmF1bHQgYWN0aW9uLCBldmVuIHdoZW4gZGlzYWJsZWRcblx0XHR0aGlzLl9vbiggdHJ1ZSwgdGhpcy5hbmNob3JzLCB7XG5cdFx0XHRjbGljazogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XHR0aGlzLl9vbiggdGhpcy5hbmNob3JzLCBldmVudHMgKTtcblx0XHR0aGlzLl9vbiggdGhpcy50YWJzLCB7IGtleWRvd246IFwiX3RhYktleWRvd25cIiB9ICk7XG5cdFx0dGhpcy5fb24oIHRoaXMucGFuZWxzLCB7IGtleWRvd246IFwiX3BhbmVsS2V5ZG93blwiIH0gKTtcblxuXHRcdHRoaXMuX2ZvY3VzYWJsZSggdGhpcy50YWJzICk7XG5cdFx0dGhpcy5faG92ZXJhYmxlKCB0aGlzLnRhYnMgKTtcblx0fSxcblxuXHRfc2V0dXBIZWlnaHRTdHlsZTogZnVuY3Rpb24oIGhlaWdodFN0eWxlICkge1xuXHRcdHZhciBtYXhIZWlnaHQsXG5cdFx0XHRwYXJlbnQgPSB0aGlzLmVsZW1lbnQucGFyZW50KCk7XG5cblx0XHRpZiAoIGhlaWdodFN0eWxlID09PSBcImZpbGxcIiApIHtcblx0XHRcdG1heEhlaWdodCA9IHBhcmVudC5oZWlnaHQoKTtcblx0XHRcdG1heEhlaWdodCAtPSB0aGlzLmVsZW1lbnQub3V0ZXJIZWlnaHQoKSAtIHRoaXMuZWxlbWVudC5oZWlnaHQoKTtcblxuXHRcdFx0dGhpcy5lbGVtZW50LnNpYmxpbmdzKCBcIjp2aXNpYmxlXCIgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0dmFyIGVsZW0gPSAkKCB0aGlzICksXG5cdFx0XHRcdFx0cG9zaXRpb24gPSBlbGVtLmNzcyggXCJwb3NpdGlvblwiICk7XG5cblx0XHRcdFx0aWYgKCBwb3NpdGlvbiA9PT0gXCJhYnNvbHV0ZVwiIHx8IHBvc2l0aW9uID09PSBcImZpeGVkXCIgKSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cdFx0XHRcdG1heEhlaWdodCAtPSBlbGVtLm91dGVySGVpZ2h0KCB0cnVlICk7XG5cdFx0XHR9ICk7XG5cblx0XHRcdHRoaXMuZWxlbWVudC5jaGlsZHJlbigpLm5vdCggdGhpcy5wYW5lbHMgKS5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0bWF4SGVpZ2h0IC09ICQoIHRoaXMgKS5vdXRlckhlaWdodCggdHJ1ZSApO1xuXHRcdFx0fSApO1xuXG5cdFx0XHR0aGlzLnBhbmVscy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0JCggdGhpcyApLmhlaWdodCggTWF0aC5tYXgoIDAsIG1heEhlaWdodCAtXG5cdFx0XHRcdFx0JCggdGhpcyApLmlubmVySGVpZ2h0KCkgKyAkKCB0aGlzICkuaGVpZ2h0KCkgKSApO1xuXHRcdFx0fSApXG5cdFx0XHRcdC5jc3MoIFwib3ZlcmZsb3dcIiwgXCJhdXRvXCIgKTtcblx0XHR9IGVsc2UgaWYgKCBoZWlnaHRTdHlsZSA9PT0gXCJhdXRvXCIgKSB7XG5cdFx0XHRtYXhIZWlnaHQgPSAwO1xuXHRcdFx0dGhpcy5wYW5lbHMuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdG1heEhlaWdodCA9IE1hdGgubWF4KCBtYXhIZWlnaHQsICQoIHRoaXMgKS5oZWlnaHQoIFwiXCIgKS5oZWlnaHQoKSApO1xuXHRcdFx0fSApLmhlaWdodCggbWF4SGVpZ2h0ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9ldmVudEhhbmRsZXI6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucyxcblx0XHRcdGFjdGl2ZSA9IHRoaXMuYWN0aXZlLFxuXHRcdFx0YW5jaG9yID0gJCggZXZlbnQuY3VycmVudFRhcmdldCApLFxuXHRcdFx0dGFiID0gYW5jaG9yLmNsb3Nlc3QoIFwibGlcIiApLFxuXHRcdFx0Y2xpY2tlZElzQWN0aXZlID0gdGFiWyAwIF0gPT09IGFjdGl2ZVsgMCBdLFxuXHRcdFx0Y29sbGFwc2luZyA9IGNsaWNrZWRJc0FjdGl2ZSAmJiBvcHRpb25zLmNvbGxhcHNpYmxlLFxuXHRcdFx0dG9TaG93ID0gY29sbGFwc2luZyA/ICQoKSA6IHRoaXMuX2dldFBhbmVsRm9yVGFiKCB0YWIgKSxcblx0XHRcdHRvSGlkZSA9ICFhY3RpdmUubGVuZ3RoID8gJCgpIDogdGhpcy5fZ2V0UGFuZWxGb3JUYWIoIGFjdGl2ZSApLFxuXHRcdFx0ZXZlbnREYXRhID0ge1xuXHRcdFx0XHRvbGRUYWI6IGFjdGl2ZSxcblx0XHRcdFx0b2xkUGFuZWw6IHRvSGlkZSxcblx0XHRcdFx0bmV3VGFiOiBjb2xsYXBzaW5nID8gJCgpIDogdGFiLFxuXHRcdFx0XHRuZXdQYW5lbDogdG9TaG93XG5cdFx0XHR9O1xuXG5cdFx0ZXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuXHRcdGlmICggdGFiLmhhc0NsYXNzKCBcInVpLXN0YXRlLWRpc2FibGVkXCIgKSB8fFxuXG5cdFx0XHRcdC8vIHRhYiBpcyBhbHJlYWR5IGxvYWRpbmdcblx0XHRcdFx0dGFiLmhhc0NsYXNzKCBcInVpLXRhYnMtbG9hZGluZ1wiICkgfHxcblxuXHRcdFx0XHQvLyBjYW4ndCBzd2l0Y2ggZHVybmluZyBhbiBhbmltYXRpb25cblx0XHRcdFx0dGhpcy5ydW5uaW5nIHx8XG5cblx0XHRcdFx0Ly8gY2xpY2sgb24gYWN0aXZlIGhlYWRlciwgYnV0IG5vdCBjb2xsYXBzaWJsZVxuXHRcdFx0XHQoIGNsaWNrZWRJc0FjdGl2ZSAmJiAhb3B0aW9ucy5jb2xsYXBzaWJsZSApIHx8XG5cblx0XHRcdFx0Ly8gYWxsb3cgY2FuY2VsaW5nIGFjdGl2YXRpb25cblx0XHRcdFx0KCB0aGlzLl90cmlnZ2VyKCBcImJlZm9yZUFjdGl2YXRlXCIsIGV2ZW50LCBldmVudERhdGEgKSA9PT0gZmFsc2UgKSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRvcHRpb25zLmFjdGl2ZSA9IGNvbGxhcHNpbmcgPyBmYWxzZSA6IHRoaXMudGFicy5pbmRleCggdGFiICk7XG5cblx0XHR0aGlzLmFjdGl2ZSA9IGNsaWNrZWRJc0FjdGl2ZSA/ICQoKSA6IHRhYjtcblx0XHRpZiAoIHRoaXMueGhyICkge1xuXHRcdFx0dGhpcy54aHIuYWJvcnQoKTtcblx0XHR9XG5cblx0XHRpZiAoICF0b0hpZGUubGVuZ3RoICYmICF0b1Nob3cubGVuZ3RoICkge1xuXHRcdFx0JC5lcnJvciggXCJqUXVlcnkgVUkgVGFiczogTWlzbWF0Y2hpbmcgZnJhZ21lbnQgaWRlbnRpZmllci5cIiApO1xuXHRcdH1cblxuXHRcdGlmICggdG9TaG93Lmxlbmd0aCApIHtcblx0XHRcdHRoaXMubG9hZCggdGhpcy50YWJzLmluZGV4KCB0YWIgKSwgZXZlbnQgKTtcblx0XHR9XG5cdFx0dGhpcy5fdG9nZ2xlKCBldmVudCwgZXZlbnREYXRhICk7XG5cdH0sXG5cblx0Ly8gSGFuZGxlcyBzaG93L2hpZGUgZm9yIHNlbGVjdGluZyB0YWJzXG5cdF90b2dnbGU6IGZ1bmN0aW9uKCBldmVudCwgZXZlbnREYXRhICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdHRvU2hvdyA9IGV2ZW50RGF0YS5uZXdQYW5lbCxcblx0XHRcdHRvSGlkZSA9IGV2ZW50RGF0YS5vbGRQYW5lbDtcblxuXHRcdHRoaXMucnVubmluZyA9IHRydWU7XG5cblx0XHRmdW5jdGlvbiBjb21wbGV0ZSgpIHtcblx0XHRcdHRoYXQucnVubmluZyA9IGZhbHNlO1xuXHRcdFx0dGhhdC5fdHJpZ2dlciggXCJhY3RpdmF0ZVwiLCBldmVudCwgZXZlbnREYXRhICk7XG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gc2hvdygpIHtcblx0XHRcdHRoYXQuX2FkZENsYXNzKCBldmVudERhdGEubmV3VGFiLmNsb3Nlc3QoIFwibGlcIiApLCBcInVpLXRhYnMtYWN0aXZlXCIsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblxuXHRcdFx0aWYgKCB0b1Nob3cubGVuZ3RoICYmIHRoYXQub3B0aW9ucy5zaG93ICkge1xuXHRcdFx0XHR0aGF0Ll9zaG93KCB0b1Nob3csIHRoYXQub3B0aW9ucy5zaG93LCBjb21wbGV0ZSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0dG9TaG93LnNob3coKTtcblx0XHRcdFx0Y29tcGxldGUoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBTdGFydCBvdXQgYnkgaGlkaW5nLCB0aGVuIHNob3dpbmcsIHRoZW4gY29tcGxldGluZ1xuXHRcdGlmICggdG9IaWRlLmxlbmd0aCAmJiB0aGlzLm9wdGlvbnMuaGlkZSApIHtcblx0XHRcdHRoaXMuX2hpZGUoIHRvSGlkZSwgdGhpcy5vcHRpb25zLmhpZGUsIGZ1bmN0aW9uKCkge1xuXHRcdFx0XHR0aGF0Ll9yZW1vdmVDbGFzcyggZXZlbnREYXRhLm9sZFRhYi5jbG9zZXN0KCBcImxpXCIgKSxcblx0XHRcdFx0XHRcInVpLXRhYnMtYWN0aXZlXCIsIFwidWktc3RhdGUtYWN0aXZlXCIgKTtcblx0XHRcdFx0c2hvdygpO1xuXHRcdFx0fSApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVDbGFzcyggZXZlbnREYXRhLm9sZFRhYi5jbG9zZXN0KCBcImxpXCIgKSxcblx0XHRcdFx0XCJ1aS10YWJzLWFjdGl2ZVwiLCBcInVpLXN0YXRlLWFjdGl2ZVwiICk7XG5cdFx0XHR0b0hpZGUuaGlkZSgpO1xuXHRcdFx0c2hvdygpO1xuXHRcdH1cblxuXHRcdHRvSGlkZS5hdHRyKCBcImFyaWEtaGlkZGVuXCIsIFwidHJ1ZVwiICk7XG5cdFx0ZXZlbnREYXRhLm9sZFRhYi5hdHRyKCB7XG5cdFx0XHRcImFyaWEtc2VsZWN0ZWRcIjogXCJmYWxzZVwiLFxuXHRcdFx0XCJhcmlhLWV4cGFuZGVkXCI6IFwiZmFsc2VcIlxuXHRcdH0gKTtcblxuXHRcdC8vIElmIHdlJ3JlIHN3aXRjaGluZyB0YWJzLCByZW1vdmUgdGhlIG9sZCB0YWIgZnJvbSB0aGUgdGFiIG9yZGVyLlxuXHRcdC8vIElmIHdlJ3JlIG9wZW5pbmcgZnJvbSBjb2xsYXBzZWQgc3RhdGUsIHJlbW92ZSB0aGUgcHJldmlvdXMgdGFiIGZyb20gdGhlIHRhYiBvcmRlci5cblx0XHQvLyBJZiB3ZSdyZSBjb2xsYXBzaW5nLCB0aGVuIGtlZXAgdGhlIGNvbGxhcHNpbmcgdGFiIGluIHRoZSB0YWIgb3JkZXIuXG5cdFx0aWYgKCB0b1Nob3cubGVuZ3RoICYmIHRvSGlkZS5sZW5ndGggKSB7XG5cdFx0XHRldmVudERhdGEub2xkVGFiLmF0dHIoIFwidGFiSW5kZXhcIiwgLTEgKTtcblx0XHR9IGVsc2UgaWYgKCB0b1Nob3cubGVuZ3RoICkge1xuXHRcdFx0dGhpcy50YWJzLmZpbHRlciggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHJldHVybiAkKCB0aGlzICkuYXR0ciggXCJ0YWJJbmRleFwiICkgPT09IDA7XG5cdFx0XHR9IClcblx0XHRcdFx0LmF0dHIoIFwidGFiSW5kZXhcIiwgLTEgKTtcblx0XHR9XG5cblx0XHR0b1Nob3cuYXR0ciggXCJhcmlhLWhpZGRlblwiLCBcImZhbHNlXCIgKTtcblx0XHRldmVudERhdGEubmV3VGFiLmF0dHIoIHtcblx0XHRcdFwiYXJpYS1zZWxlY3RlZFwiOiBcInRydWVcIixcblx0XHRcdFwiYXJpYS1leHBhbmRlZFwiOiBcInRydWVcIixcblx0XHRcdHRhYkluZGV4OiAwXG5cdFx0fSApO1xuXHR9LFxuXG5cdF9hY3RpdmF0ZTogZnVuY3Rpb24oIGluZGV4ICkge1xuXHRcdHZhciBhbmNob3IsXG5cdFx0XHRhY3RpdmUgPSB0aGlzLl9maW5kQWN0aXZlKCBpbmRleCApO1xuXG5cdFx0Ly8gVHJ5aW5nIHRvIGFjdGl2YXRlIHRoZSBhbHJlYWR5IGFjdGl2ZSBwYW5lbFxuXHRcdGlmICggYWN0aXZlWyAwIF0gPT09IHRoaXMuYWN0aXZlWyAwIF0gKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0Ly8gVHJ5aW5nIHRvIGNvbGxhcHNlLCBzaW11bGF0ZSBhIGNsaWNrIG9uIHRoZSBjdXJyZW50IGFjdGl2ZSBoZWFkZXJcblx0XHRpZiAoICFhY3RpdmUubGVuZ3RoICkge1xuXHRcdFx0YWN0aXZlID0gdGhpcy5hY3RpdmU7XG5cdFx0fVxuXG5cdFx0YW5jaG9yID0gYWN0aXZlLmZpbmQoIFwiLnVpLXRhYnMtYW5jaG9yXCIgKVsgMCBdO1xuXHRcdHRoaXMuX2V2ZW50SGFuZGxlcigge1xuXHRcdFx0dGFyZ2V0OiBhbmNob3IsXG5cdFx0XHRjdXJyZW50VGFyZ2V0OiBhbmNob3IsXG5cdFx0XHRwcmV2ZW50RGVmYXVsdDogJC5ub29wXG5cdFx0fSApO1xuXHR9LFxuXG5cdF9maW5kQWN0aXZlOiBmdW5jdGlvbiggaW5kZXggKSB7XG5cdFx0cmV0dXJuIGluZGV4ID09PSBmYWxzZSA/ICQoKSA6IHRoaXMudGFicy5lcSggaW5kZXggKTtcblx0fSxcblxuXHRfZ2V0SW5kZXg6IGZ1bmN0aW9uKCBpbmRleCApIHtcblxuXHRcdC8vIG1ldGEtZnVuY3Rpb24gdG8gZ2l2ZSB1c2VycyBvcHRpb24gdG8gcHJvdmlkZSBhIGhyZWYgc3RyaW5nIGluc3RlYWQgb2YgYSBudW1lcmljYWwgaW5kZXguXG5cdFx0aWYgKCB0eXBlb2YgaW5kZXggPT09IFwic3RyaW5nXCIgKSB7XG5cdFx0XHRpbmRleCA9IHRoaXMuYW5jaG9ycy5pbmRleCggdGhpcy5hbmNob3JzLmZpbHRlciggXCJbaHJlZiQ9J1wiICtcblx0XHRcdFx0JC51aS5lc2NhcGVTZWxlY3RvciggaW5kZXggKSArIFwiJ11cIiApICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGluZGV4O1xuXHR9LFxuXG5cdF9kZXN0cm95OiBmdW5jdGlvbigpIHtcblx0XHRpZiAoIHRoaXMueGhyICkge1xuXHRcdFx0dGhpcy54aHIuYWJvcnQoKTtcblx0XHR9XG5cblx0XHR0aGlzLnRhYmxpc3Rcblx0XHRcdC5yZW1vdmVBdHRyKCBcInJvbGVcIiApXG5cdFx0XHQub2ZmKCB0aGlzLmV2ZW50TmFtZXNwYWNlICk7XG5cblx0XHR0aGlzLmFuY2hvcnNcblx0XHRcdC5yZW1vdmVBdHRyKCBcInJvbGUgdGFiSW5kZXhcIiApXG5cdFx0XHQucmVtb3ZlVW5pcXVlSWQoKTtcblxuXHRcdHRoaXMudGFicy5hZGQoIHRoaXMucGFuZWxzICkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRpZiAoICQuZGF0YSggdGhpcywgXCJ1aS10YWJzLWRlc3Ryb3lcIiApICkge1xuXHRcdFx0XHQkKCB0aGlzICkucmVtb3ZlKCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHQkKCB0aGlzICkucmVtb3ZlQXR0ciggXCJyb2xlIHRhYkluZGV4IFwiICtcblx0XHRcdFx0XHRcImFyaWEtbGl2ZSBhcmlhLWJ1c3kgYXJpYS1zZWxlY3RlZCBhcmlhLWxhYmVsbGVkYnkgYXJpYS1oaWRkZW4gYXJpYS1leHBhbmRlZFwiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0dGhpcy50YWJzLmVhY2goIGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIGxpID0gJCggdGhpcyApLFxuXHRcdFx0XHRwcmV2ID0gbGkuZGF0YSggXCJ1aS10YWJzLWFyaWEtY29udHJvbHNcIiApO1xuXHRcdFx0aWYgKCBwcmV2ICkge1xuXHRcdFx0XHRsaVxuXHRcdFx0XHRcdC5hdHRyKCBcImFyaWEtY29udHJvbHNcIiwgcHJldiApXG5cdFx0XHRcdFx0LnJlbW92ZURhdGEoIFwidWktdGFicy1hcmlhLWNvbnRyb2xzXCIgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGxpLnJlbW92ZUF0dHIoIFwiYXJpYS1jb250cm9sc1wiICk7XG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0dGhpcy5wYW5lbHMuc2hvdygpO1xuXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMuaGVpZ2h0U3R5bGUgIT09IFwiY29udGVudFwiICkge1xuXHRcdFx0dGhpcy5wYW5lbHMuY3NzKCBcImhlaWdodFwiLCBcIlwiICk7XG5cdFx0fVxuXHR9LFxuXG5cdGVuYWJsZTogZnVuY3Rpb24oIGluZGV4ICkge1xuXHRcdHZhciBkaXNhYmxlZCA9IHRoaXMub3B0aW9ucy5kaXNhYmxlZDtcblx0XHRpZiAoIGRpc2FibGVkID09PSBmYWxzZSApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAoIGluZGV4ID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRkaXNhYmxlZCA9IGZhbHNlO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRpbmRleCA9IHRoaXMuX2dldEluZGV4KCBpbmRleCApO1xuXHRcdFx0aWYgKCAkLmlzQXJyYXkoIGRpc2FibGVkICkgKSB7XG5cdFx0XHRcdGRpc2FibGVkID0gJC5tYXAoIGRpc2FibGVkLCBmdW5jdGlvbiggbnVtICkge1xuXHRcdFx0XHRcdHJldHVybiBudW0gIT09IGluZGV4ID8gbnVtIDogbnVsbDtcblx0XHRcdFx0fSApO1xuXHRcdFx0fSBlbHNlIHtcblx0XHRcdFx0ZGlzYWJsZWQgPSAkLm1hcCggdGhpcy50YWJzLCBmdW5jdGlvbiggbGksIG51bSApIHtcblx0XHRcdFx0XHRyZXR1cm4gbnVtICE9PSBpbmRleCA/IG51bSA6IG51bGw7XG5cdFx0XHRcdH0gKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5fc2V0T3B0aW9uRGlzYWJsZWQoIGRpc2FibGVkICk7XG5cdH0sXG5cblx0ZGlzYWJsZTogZnVuY3Rpb24oIGluZGV4ICkge1xuXHRcdHZhciBkaXNhYmxlZCA9IHRoaXMub3B0aW9ucy5kaXNhYmxlZDtcblx0XHRpZiAoIGRpc2FibGVkID09PSB0cnVlICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggaW5kZXggPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGRpc2FibGVkID0gdHJ1ZTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0aW5kZXggPSB0aGlzLl9nZXRJbmRleCggaW5kZXggKTtcblx0XHRcdGlmICggJC5pbkFycmF5KCBpbmRleCwgZGlzYWJsZWQgKSAhPT0gLTEgKSB7XG5cdFx0XHRcdHJldHVybjtcblx0XHRcdH1cblx0XHRcdGlmICggJC5pc0FycmF5KCBkaXNhYmxlZCApICkge1xuXHRcdFx0XHRkaXNhYmxlZCA9ICQubWVyZ2UoIFsgaW5kZXggXSwgZGlzYWJsZWQgKS5zb3J0KCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRkaXNhYmxlZCA9IFsgaW5kZXggXTtcblx0XHRcdH1cblx0XHR9XG5cdFx0dGhpcy5fc2V0T3B0aW9uRGlzYWJsZWQoIGRpc2FibGVkICk7XG5cdH0sXG5cblx0bG9hZDogZnVuY3Rpb24oIGluZGV4LCBldmVudCApIHtcblx0XHRpbmRleCA9IHRoaXMuX2dldEluZGV4KCBpbmRleCApO1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdHRhYiA9IHRoaXMudGFicy5lcSggaW5kZXggKSxcblx0XHRcdGFuY2hvciA9IHRhYi5maW5kKCBcIi51aS10YWJzLWFuY2hvclwiICksXG5cdFx0XHRwYW5lbCA9IHRoaXMuX2dldFBhbmVsRm9yVGFiKCB0YWIgKSxcblx0XHRcdGV2ZW50RGF0YSA9IHtcblx0XHRcdFx0dGFiOiB0YWIsXG5cdFx0XHRcdHBhbmVsOiBwYW5lbFxuXHRcdFx0fSxcblx0XHRcdGNvbXBsZXRlID0gZnVuY3Rpb24oIGpxWEhSLCBzdGF0dXMgKSB7XG5cdFx0XHRcdGlmICggc3RhdHVzID09PSBcImFib3J0XCIgKSB7XG5cdFx0XHRcdFx0dGhhdC5wYW5lbHMuc3RvcCggZmFsc2UsIHRydWUgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRoYXQuX3JlbW92ZUNsYXNzKCB0YWIsIFwidWktdGFicy1sb2FkaW5nXCIgKTtcblx0XHRcdFx0cGFuZWwucmVtb3ZlQXR0ciggXCJhcmlhLWJ1c3lcIiApO1xuXG5cdFx0XHRcdGlmICgganFYSFIgPT09IHRoYXQueGhyICkge1xuXHRcdFx0XHRcdGRlbGV0ZSB0aGF0Lnhocjtcblx0XHRcdFx0fVxuXHRcdFx0fTtcblxuXHRcdC8vIE5vdCByZW1vdGVcblx0XHRpZiAoIHRoaXMuX2lzTG9jYWwoIGFuY2hvclsgMCBdICkgKSB7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dGhpcy54aHIgPSAkLmFqYXgoIHRoaXMuX2FqYXhTZXR0aW5ncyggYW5jaG9yLCBldmVudCwgZXZlbnREYXRhICkgKTtcblxuXHRcdC8vIFN1cHBvcnQ6IGpRdWVyeSA8MS44XG5cdFx0Ly8galF1ZXJ5IDwxLjggcmV0dXJucyBmYWxzZSBpZiB0aGUgcmVxdWVzdCBpcyBjYW5jZWxlZCBpbiBiZWZvcmVTZW5kLFxuXHRcdC8vIGJ1dCBhcyBvZiAxLjgsICQuYWpheCgpIGFsd2F5cyByZXR1cm5zIGEganFYSFIgb2JqZWN0LlxuXHRcdGlmICggdGhpcy54aHIgJiYgdGhpcy54aHIuc3RhdHVzVGV4dCAhPT0gXCJjYW5jZWxlZFwiICkge1xuXHRcdFx0dGhpcy5fYWRkQ2xhc3MoIHRhYiwgXCJ1aS10YWJzLWxvYWRpbmdcIiApO1xuXHRcdFx0cGFuZWwuYXR0ciggXCJhcmlhLWJ1c3lcIiwgXCJ0cnVlXCIgKTtcblxuXHRcdFx0dGhpcy54aHJcblx0XHRcdFx0LmRvbmUoIGZ1bmN0aW9uKCByZXNwb25zZSwgc3RhdHVzLCBqcVhIUiApIHtcblxuXHRcdFx0XHRcdC8vIHN1cHBvcnQ6IGpRdWVyeSA8MS44XG5cdFx0XHRcdFx0Ly8gaHR0cDovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTE3Nzhcblx0XHRcdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdHBhbmVsLmh0bWwoIHJlc3BvbnNlICk7XG5cdFx0XHRcdFx0XHR0aGF0Ll90cmlnZ2VyKCBcImxvYWRcIiwgZXZlbnQsIGV2ZW50RGF0YSApO1xuXG5cdFx0XHRcdFx0XHRjb21wbGV0ZSgganFYSFIsIHN0YXR1cyApO1xuXHRcdFx0XHRcdH0sIDEgKTtcblx0XHRcdFx0fSApXG5cdFx0XHRcdC5mYWlsKCBmdW5jdGlvbigganFYSFIsIHN0YXR1cyApIHtcblxuXHRcdFx0XHRcdC8vIHN1cHBvcnQ6IGpRdWVyeSA8MS44XG5cdFx0XHRcdFx0Ly8gaHR0cDovL2J1Z3MuanF1ZXJ5LmNvbS90aWNrZXQvMTE3Nzhcblx0XHRcdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHRcdGNvbXBsZXRlKCBqcVhIUiwgc3RhdHVzICk7XG5cdFx0XHRcdFx0fSwgMSApO1xuXHRcdFx0XHR9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9hamF4U2V0dGluZ3M6IGZ1bmN0aW9uKCBhbmNob3IsIGV2ZW50LCBldmVudERhdGEgKSB7XG5cdFx0dmFyIHRoYXQgPSB0aGlzO1xuXHRcdHJldHVybiB7XG5cblx0XHRcdC8vIFN1cHBvcnQ6IElFIDwxMSBvbmx5XG5cdFx0XHQvLyBTdHJpcCBhbnkgaGFzaCB0aGF0IGV4aXN0cyB0byBwcmV2ZW50IGVycm9ycyB3aXRoIHRoZSBBamF4IHJlcXVlc3Rcblx0XHRcdHVybDogYW5jaG9yLmF0dHIoIFwiaHJlZlwiICkucmVwbGFjZSggLyMuKiQvLCBcIlwiICksXG5cdFx0XHRiZWZvcmVTZW5kOiBmdW5jdGlvbigganFYSFIsIHNldHRpbmdzICkge1xuXHRcdFx0XHRyZXR1cm4gdGhhdC5fdHJpZ2dlciggXCJiZWZvcmVMb2FkXCIsIGV2ZW50LFxuXHRcdFx0XHRcdCQuZXh0ZW5kKCB7IGpxWEhSOiBqcVhIUiwgYWpheFNldHRpbmdzOiBzZXR0aW5ncyB9LCBldmVudERhdGEgKSApO1xuXHRcdFx0fVxuXHRcdH07XG5cdH0sXG5cblx0X2dldFBhbmVsRm9yVGFiOiBmdW5jdGlvbiggdGFiICkge1xuXHRcdHZhciBpZCA9ICQoIHRhYiApLmF0dHIoIFwiYXJpYS1jb250cm9sc1wiICk7XG5cdFx0cmV0dXJuIHRoaXMuZWxlbWVudC5maW5kKCB0aGlzLl9zYW5pdGl6ZVNlbGVjdG9yKCBcIiNcIiArIGlkICkgKTtcblx0fVxufSApO1xuXG4vLyBERVBSRUNBVEVEXG4vLyBUT0RPOiBTd2l0Y2ggcmV0dXJuIGJhY2sgdG8gd2lkZ2V0IGRlY2xhcmF0aW9uIGF0IHRvcCBvZiBmaWxlIHdoZW4gdGhpcyBpcyByZW1vdmVkXG5pZiAoICQudWlCYWNrQ29tcGF0ICE9PSBmYWxzZSApIHtcblxuXHQvLyBCYWNrY29tcGF0IGZvciB1aS10YWIgY2xhc3MgKG5vdyB1aS10YWJzLXRhYilcblx0JC53aWRnZXQoIFwidWkudGFic1wiLCAkLnVpLnRhYnMsIHtcblx0XHRfcHJvY2Vzc1RhYnM6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dGhpcy5fc3VwZXJBcHBseSggYXJndW1lbnRzICk7XG5cdFx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy50YWJzLCBcInVpLXRhYlwiICk7XG5cdFx0fVxuXHR9ICk7XG59XG5cbnZhciB3aWRnZXRzVGFicyA9ICQudWkudGFicztcblxuXG4vKiFcbiAqIGpRdWVyeSBVSSBUb29sdGlwIDEuMTIuMVxuICogaHR0cDovL2pxdWVyeXVpLmNvbVxuICpcbiAqIENvcHlyaWdodCBqUXVlcnkgRm91bmRhdGlvbiBhbmQgb3RoZXIgY29udHJpYnV0b3JzXG4gKiBSZWxlYXNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2UuXG4gKiBodHRwOi8vanF1ZXJ5Lm9yZy9saWNlbnNlXG4gKi9cblxuLy8+PmxhYmVsOiBUb29sdGlwXG4vLz4+Z3JvdXA6IFdpZGdldHNcbi8vPj5kZXNjcmlwdGlvbjogU2hvd3MgYWRkaXRpb25hbCBpbmZvcm1hdGlvbiBmb3IgYW55IGVsZW1lbnQgb24gaG92ZXIgb3IgZm9jdXMuXG4vLz4+ZG9jczogaHR0cDovL2FwaS5qcXVlcnl1aS5jb20vdG9vbHRpcC9cbi8vPj5kZW1vczogaHR0cDovL2pxdWVyeXVpLmNvbS90b29sdGlwL1xuLy8+PmNzcy5zdHJ1Y3R1cmU6IC4uLy4uL3RoZW1lcy9iYXNlL2NvcmUuY3NzXG4vLz4+Y3NzLnN0cnVjdHVyZTogLi4vLi4vdGhlbWVzL2Jhc2UvdG9vbHRpcC5jc3Ncbi8vPj5jc3MudGhlbWU6IC4uLy4uL3RoZW1lcy9iYXNlL3RoZW1lLmNzc1xuXG5cblxuJC53aWRnZXQoIFwidWkudG9vbHRpcFwiLCB7XG5cdHZlcnNpb246IFwiMS4xMi4xXCIsXG5cdG9wdGlvbnM6IHtcblx0XHRjbGFzc2VzOiB7XG5cdFx0XHRcInVpLXRvb2x0aXBcIjogXCJ1aS1jb3JuZXItYWxsIHVpLXdpZGdldC1zaGFkb3dcIlxuXHRcdH0sXG5cdFx0Y29udGVudDogZnVuY3Rpb24oKSB7XG5cblx0XHRcdC8vIHN1cHBvcnQ6IElFPDksIE9wZXJhIGluIGpRdWVyeSA8MS43XG5cdFx0XHQvLyAudGV4dCgpIGNhbid0IGFjY2VwdCB1bmRlZmluZWQsIHNvIGNvZXJjZSB0byBhIHN0cmluZ1xuXHRcdFx0dmFyIHRpdGxlID0gJCggdGhpcyApLmF0dHIoIFwidGl0bGVcIiApIHx8IFwiXCI7XG5cblx0XHRcdC8vIEVzY2FwZSB0aXRsZSwgc2luY2Ugd2UncmUgZ29pbmcgZnJvbSBhbiBhdHRyaWJ1dGUgdG8gcmF3IEhUTUxcblx0XHRcdHJldHVybiAkKCBcIjxhPlwiICkudGV4dCggdGl0bGUgKS5odG1sKCk7XG5cdFx0fSxcblx0XHRoaWRlOiB0cnVlLFxuXG5cdFx0Ly8gRGlzYWJsZWQgZWxlbWVudHMgaGF2ZSBpbmNvbnNpc3RlbnQgYmVoYXZpb3IgYWNyb3NzIGJyb3dzZXJzICgjODY2MSlcblx0XHRpdGVtczogXCJbdGl0bGVdOm5vdChbZGlzYWJsZWRdKVwiLFxuXHRcdHBvc2l0aW9uOiB7XG5cdFx0XHRteTogXCJsZWZ0IHRvcCsxNVwiLFxuXHRcdFx0YXQ6IFwibGVmdCBib3R0b21cIixcblx0XHRcdGNvbGxpc2lvbjogXCJmbGlwZml0IGZsaXBcIlxuXHRcdH0sXG5cdFx0c2hvdzogdHJ1ZSxcblx0XHR0cmFjazogZmFsc2UsXG5cblx0XHQvLyBDYWxsYmFja3Ncblx0XHRjbG9zZTogbnVsbCxcblx0XHRvcGVuOiBudWxsXG5cdH0sXG5cblx0X2FkZERlc2NyaWJlZEJ5OiBmdW5jdGlvbiggZWxlbSwgaWQgKSB7XG5cdFx0dmFyIGRlc2NyaWJlZGJ5ID0gKCBlbGVtLmF0dHIoIFwiYXJpYS1kZXNjcmliZWRieVwiICkgfHwgXCJcIiApLnNwbGl0KCAvXFxzKy8gKTtcblx0XHRkZXNjcmliZWRieS5wdXNoKCBpZCApO1xuXHRcdGVsZW1cblx0XHRcdC5kYXRhKCBcInVpLXRvb2x0aXAtaWRcIiwgaWQgKVxuXHRcdFx0LmF0dHIoIFwiYXJpYS1kZXNjcmliZWRieVwiLCAkLnRyaW0oIGRlc2NyaWJlZGJ5LmpvaW4oIFwiIFwiICkgKSApO1xuXHR9LFxuXG5cdF9yZW1vdmVEZXNjcmliZWRCeTogZnVuY3Rpb24oIGVsZW0gKSB7XG5cdFx0dmFyIGlkID0gZWxlbS5kYXRhKCBcInVpLXRvb2x0aXAtaWRcIiApLFxuXHRcdFx0ZGVzY3JpYmVkYnkgPSAoIGVsZW0uYXR0ciggXCJhcmlhLWRlc2NyaWJlZGJ5XCIgKSB8fCBcIlwiICkuc3BsaXQoIC9cXHMrLyApLFxuXHRcdFx0aW5kZXggPSAkLmluQXJyYXkoIGlkLCBkZXNjcmliZWRieSApO1xuXG5cdFx0aWYgKCBpbmRleCAhPT0gLTEgKSB7XG5cdFx0XHRkZXNjcmliZWRieS5zcGxpY2UoIGluZGV4LCAxICk7XG5cdFx0fVxuXG5cdFx0ZWxlbS5yZW1vdmVEYXRhKCBcInVpLXRvb2x0aXAtaWRcIiApO1xuXHRcdGRlc2NyaWJlZGJ5ID0gJC50cmltKCBkZXNjcmliZWRieS5qb2luKCBcIiBcIiApICk7XG5cdFx0aWYgKCBkZXNjcmliZWRieSApIHtcblx0XHRcdGVsZW0uYXR0ciggXCJhcmlhLWRlc2NyaWJlZGJ5XCIsIGRlc2NyaWJlZGJ5ICk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGVsZW0ucmVtb3ZlQXR0ciggXCJhcmlhLWRlc2NyaWJlZGJ5XCIgKTtcblx0XHR9XG5cdH0sXG5cblx0X2NyZWF0ZTogZnVuY3Rpb24oKSB7XG5cdFx0dGhpcy5fb24oIHtcblx0XHRcdG1vdXNlb3ZlcjogXCJvcGVuXCIsXG5cdFx0XHRmb2N1c2luOiBcIm9wZW5cIlxuXHRcdH0gKTtcblxuXHRcdC8vIElEcyBvZiBnZW5lcmF0ZWQgdG9vbHRpcHMsIG5lZWRlZCBmb3IgZGVzdHJveVxuXHRcdHRoaXMudG9vbHRpcHMgPSB7fTtcblxuXHRcdC8vIElEcyBvZiBwYXJlbnQgdG9vbHRpcHMgd2hlcmUgd2UgcmVtb3ZlZCB0aGUgdGl0bGUgYXR0cmlidXRlXG5cdFx0dGhpcy5wYXJlbnRzID0ge307XG5cblx0XHQvLyBBcHBlbmQgdGhlIGFyaWEtbGl2ZSByZWdpb24gc28gdG9vbHRpcHMgYW5ub3VuY2UgY29ycmVjdGx5XG5cdFx0dGhpcy5saXZlUmVnaW9uID0gJCggXCI8ZGl2PlwiIClcblx0XHRcdC5hdHRyKCB7XG5cdFx0XHRcdHJvbGU6IFwibG9nXCIsXG5cdFx0XHRcdFwiYXJpYS1saXZlXCI6IFwiYXNzZXJ0aXZlXCIsXG5cdFx0XHRcdFwiYXJpYS1yZWxldmFudFwiOiBcImFkZGl0aW9uc1wiXG5cdFx0XHR9IClcblx0XHRcdC5hcHBlbmRUbyggdGhpcy5kb2N1bWVudFsgMCBdLmJvZHkgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdGhpcy5saXZlUmVnaW9uLCBudWxsLCBcInVpLWhlbHBlci1oaWRkZW4tYWNjZXNzaWJsZVwiICk7XG5cblx0XHR0aGlzLmRpc2FibGVkVGl0bGVzID0gJCggW10gKTtcblx0fSxcblxuXHRfc2V0T3B0aW9uOiBmdW5jdGlvbigga2V5LCB2YWx1ZSApIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHR0aGlzLl9zdXBlcigga2V5LCB2YWx1ZSApO1xuXG5cdFx0aWYgKCBrZXkgPT09IFwiY29udGVudFwiICkge1xuXHRcdFx0JC5lYWNoKCB0aGlzLnRvb2x0aXBzLCBmdW5jdGlvbiggaWQsIHRvb2x0aXBEYXRhICkge1xuXHRcdFx0XHR0aGF0Ll91cGRhdGVDb250ZW50KCB0b29sdGlwRGF0YS5lbGVtZW50ICk7XG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRPcHRpb25EaXNhYmxlZDogZnVuY3Rpb24oIHZhbHVlICkge1xuXHRcdHRoaXNbIHZhbHVlID8gXCJfZGlzYWJsZVwiIDogXCJfZW5hYmxlXCIgXSgpO1xuXHR9LFxuXG5cdF9kaXNhYmxlOiBmdW5jdGlvbigpIHtcblx0XHR2YXIgdGhhdCA9IHRoaXM7XG5cblx0XHQvLyBDbG9zZSBvcGVuIHRvb2x0aXBzXG5cdFx0JC5lYWNoKCB0aGlzLnRvb2x0aXBzLCBmdW5jdGlvbiggaWQsIHRvb2x0aXBEYXRhICkge1xuXHRcdFx0dmFyIGV2ZW50ID0gJC5FdmVudCggXCJibHVyXCIgKTtcblx0XHRcdGV2ZW50LnRhcmdldCA9IGV2ZW50LmN1cnJlbnRUYXJnZXQgPSB0b29sdGlwRGF0YS5lbGVtZW50WyAwIF07XG5cdFx0XHR0aGF0LmNsb3NlKCBldmVudCwgdHJ1ZSApO1xuXHRcdH0gKTtcblxuXHRcdC8vIFJlbW92ZSB0aXRsZSBhdHRyaWJ1dGVzIHRvIHByZXZlbnQgbmF0aXZlIHRvb2x0aXBzXG5cdFx0dGhpcy5kaXNhYmxlZFRpdGxlcyA9IHRoaXMuZGlzYWJsZWRUaXRsZXMuYWRkKFxuXHRcdFx0dGhpcy5lbGVtZW50LmZpbmQoIHRoaXMub3B0aW9ucy5pdGVtcyApLmFkZEJhY2soKVxuXHRcdFx0XHQuZmlsdGVyKCBmdW5jdGlvbigpIHtcblx0XHRcdFx0XHR2YXIgZWxlbWVudCA9ICQoIHRoaXMgKTtcblx0XHRcdFx0XHRpZiAoIGVsZW1lbnQuaXMoIFwiW3RpdGxlXVwiICkgKSB7XG5cdFx0XHRcdFx0XHRyZXR1cm4gZWxlbWVudFxuXHRcdFx0XHRcdFx0XHQuZGF0YSggXCJ1aS10b29sdGlwLXRpdGxlXCIsIGVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiICkgKVxuXHRcdFx0XHRcdFx0XHQucmVtb3ZlQXR0ciggXCJ0aXRsZVwiICk7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHR9IClcblx0XHQpO1xuXHR9LFxuXG5cdF9lbmFibGU6IGZ1bmN0aW9uKCkge1xuXG5cdFx0Ly8gcmVzdG9yZSB0aXRsZSBhdHRyaWJ1dGVzXG5cdFx0dGhpcy5kaXNhYmxlZFRpdGxlcy5lYWNoKCBmdW5jdGlvbigpIHtcblx0XHRcdHZhciBlbGVtZW50ID0gJCggdGhpcyApO1xuXHRcdFx0aWYgKCBlbGVtZW50LmRhdGEoIFwidWktdG9vbHRpcC10aXRsZVwiICkgKSB7XG5cdFx0XHRcdGVsZW1lbnQuYXR0ciggXCJ0aXRsZVwiLCBlbGVtZW50LmRhdGEoIFwidWktdG9vbHRpcC10aXRsZVwiICkgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cdFx0dGhpcy5kaXNhYmxlZFRpdGxlcyA9ICQoIFtdICk7XG5cdH0sXG5cblx0b3BlbjogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciB0aGF0ID0gdGhpcyxcblx0XHRcdHRhcmdldCA9ICQoIGV2ZW50ID8gZXZlbnQudGFyZ2V0IDogdGhpcy5lbGVtZW50IClcblxuXHRcdFx0XHQvLyB3ZSBuZWVkIGNsb3Nlc3QgaGVyZSBkdWUgdG8gbW91c2VvdmVyIGJ1YmJsaW5nLFxuXHRcdFx0XHQvLyBidXQgYWx3YXlzIHBvaW50aW5nIGF0IHRoZSBzYW1lIGV2ZW50IHRhcmdldFxuXHRcdFx0XHQuY2xvc2VzdCggdGhpcy5vcHRpb25zLml0ZW1zICk7XG5cblx0XHQvLyBObyBlbGVtZW50IHRvIHNob3cgYSB0b29sdGlwIGZvciBvciB0aGUgdG9vbHRpcCBpcyBhbHJlYWR5IG9wZW5cblx0XHRpZiAoICF0YXJnZXQubGVuZ3RoIHx8IHRhcmdldC5kYXRhKCBcInVpLXRvb2x0aXAtaWRcIiApICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICggdGFyZ2V0LmF0dHIoIFwidGl0bGVcIiApICkge1xuXHRcdFx0dGFyZ2V0LmRhdGEoIFwidWktdG9vbHRpcC10aXRsZVwiLCB0YXJnZXQuYXR0ciggXCJ0aXRsZVwiICkgKTtcblx0XHR9XG5cblx0XHR0YXJnZXQuZGF0YSggXCJ1aS10b29sdGlwLW9wZW5cIiwgdHJ1ZSApO1xuXG5cdFx0Ly8gS2lsbCBwYXJlbnQgdG9vbHRpcHMsIGN1c3RvbSBvciBuYXRpdmUsIGZvciBob3ZlclxuXHRcdGlmICggZXZlbnQgJiYgZXZlbnQudHlwZSA9PT0gXCJtb3VzZW92ZXJcIiApIHtcblx0XHRcdHRhcmdldC5wYXJlbnRzKCkuZWFjaCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdHZhciBwYXJlbnQgPSAkKCB0aGlzICksXG5cdFx0XHRcdFx0Ymx1ckV2ZW50O1xuXHRcdFx0XHRpZiAoIHBhcmVudC5kYXRhKCBcInVpLXRvb2x0aXAtb3BlblwiICkgKSB7XG5cdFx0XHRcdFx0Ymx1ckV2ZW50ID0gJC5FdmVudCggXCJibHVyXCIgKTtcblx0XHRcdFx0XHRibHVyRXZlbnQudGFyZ2V0ID0gYmx1ckV2ZW50LmN1cnJlbnRUYXJnZXQgPSB0aGlzO1xuXHRcdFx0XHRcdHRoYXQuY2xvc2UoIGJsdXJFdmVudCwgdHJ1ZSApO1xuXHRcdFx0XHR9XG5cdFx0XHRcdGlmICggcGFyZW50LmF0dHIoIFwidGl0bGVcIiApICkge1xuXHRcdFx0XHRcdHBhcmVudC51bmlxdWVJZCgpO1xuXHRcdFx0XHRcdHRoYXQucGFyZW50c1sgdGhpcy5pZCBdID0ge1xuXHRcdFx0XHRcdFx0ZWxlbWVudDogdGhpcyxcblx0XHRcdFx0XHRcdHRpdGxlOiBwYXJlbnQuYXR0ciggXCJ0aXRsZVwiIClcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdHBhcmVudC5hdHRyKCBcInRpdGxlXCIsIFwiXCIgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3JlZ2lzdGVyQ2xvc2VIYW5kbGVycyggZXZlbnQsIHRhcmdldCApO1xuXHRcdHRoaXMuX3VwZGF0ZUNvbnRlbnQoIHRhcmdldCwgZXZlbnQgKTtcblx0fSxcblxuXHRfdXBkYXRlQ29udGVudDogZnVuY3Rpb24oIHRhcmdldCwgZXZlbnQgKSB7XG5cdFx0dmFyIGNvbnRlbnQsXG5cdFx0XHRjb250ZW50T3B0aW9uID0gdGhpcy5vcHRpb25zLmNvbnRlbnQsXG5cdFx0XHR0aGF0ID0gdGhpcyxcblx0XHRcdGV2ZW50VHlwZSA9IGV2ZW50ID8gZXZlbnQudHlwZSA6IG51bGw7XG5cblx0XHRpZiAoIHR5cGVvZiBjb250ZW50T3B0aW9uID09PSBcInN0cmluZ1wiIHx8IGNvbnRlbnRPcHRpb24ubm9kZVR5cGUgfHxcblx0XHRcdFx0Y29udGVudE9wdGlvbi5qcXVlcnkgKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5fb3BlbiggZXZlbnQsIHRhcmdldCwgY29udGVudE9wdGlvbiApO1xuXHRcdH1cblxuXHRcdGNvbnRlbnQgPSBjb250ZW50T3B0aW9uLmNhbGwoIHRhcmdldFsgMCBdLCBmdW5jdGlvbiggcmVzcG9uc2UgKSB7XG5cblx0XHRcdC8vIElFIG1heSBpbnN0YW50bHkgc2VydmUgYSBjYWNoZWQgcmVzcG9uc2UgZm9yIGFqYXggcmVxdWVzdHNcblx0XHRcdC8vIGRlbGF5IHRoaXMgY2FsbCB0byBfb3BlbiBzbyB0aGUgb3RoZXIgY2FsbCB0byBfb3BlbiBydW5zIGZpcnN0XG5cdFx0XHR0aGF0Ll9kZWxheSggZnVuY3Rpb24oKSB7XG5cblx0XHRcdFx0Ly8gSWdub3JlIGFzeW5jIHJlc3BvbnNlIGlmIHRvb2x0aXAgd2FzIGNsb3NlZCBhbHJlYWR5XG5cdFx0XHRcdGlmICggIXRhcmdldC5kYXRhKCBcInVpLXRvb2x0aXAtb3BlblwiICkgKSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gSlF1ZXJ5IGNyZWF0ZXMgYSBzcGVjaWFsIGV2ZW50IGZvciBmb2N1c2luIHdoZW4gaXQgZG9lc24ndFxuXHRcdFx0XHQvLyBleGlzdCBuYXRpdmVseS4gVG8gaW1wcm92ZSBwZXJmb3JtYW5jZSwgdGhlIG5hdGl2ZSBldmVudFxuXHRcdFx0XHQvLyBvYmplY3QgaXMgcmV1c2VkIGFuZCB0aGUgdHlwZSBpcyBjaGFuZ2VkLiBUaGVyZWZvcmUsIHdlIGNhbid0XG5cdFx0XHRcdC8vIHJlbHkgb24gdGhlIHR5cGUgYmVpbmcgY29ycmVjdCBhZnRlciB0aGUgZXZlbnQgZmluaXNoZWRcblx0XHRcdFx0Ly8gYnViYmxpbmcsIHNvIHdlIHNldCBpdCBiYWNrIHRvIHRoZSBwcmV2aW91cyB2YWx1ZS4gKCM4NzQwKVxuXHRcdFx0XHRpZiAoIGV2ZW50ICkge1xuXHRcdFx0XHRcdGV2ZW50LnR5cGUgPSBldmVudFR5cGU7XG5cdFx0XHRcdH1cblx0XHRcdFx0dGhpcy5fb3BlbiggZXZlbnQsIHRhcmdldCwgcmVzcG9uc2UgKTtcblx0XHRcdH0gKTtcblx0XHR9ICk7XG5cdFx0aWYgKCBjb250ZW50ICkge1xuXHRcdFx0dGhpcy5fb3BlbiggZXZlbnQsIHRhcmdldCwgY29udGVudCApO1xuXHRcdH1cblx0fSxcblxuXHRfb3BlbjogZnVuY3Rpb24oIGV2ZW50LCB0YXJnZXQsIGNvbnRlbnQgKSB7XG5cdFx0dmFyIHRvb2x0aXBEYXRhLCB0b29sdGlwLCBkZWxheWVkU2hvdywgYTExeUNvbnRlbnQsXG5cdFx0XHRwb3NpdGlvbk9wdGlvbiA9ICQuZXh0ZW5kKCB7fSwgdGhpcy5vcHRpb25zLnBvc2l0aW9uICk7XG5cblx0XHRpZiAoICFjb250ZW50ICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIENvbnRlbnQgY2FuIGJlIHVwZGF0ZWQgbXVsdGlwbGUgdGltZXMuIElmIHRoZSB0b29sdGlwIGFscmVhZHlcblx0XHQvLyBleGlzdHMsIHRoZW4ganVzdCB1cGRhdGUgdGhlIGNvbnRlbnQgYW5kIGJhaWwuXG5cdFx0dG9vbHRpcERhdGEgPSB0aGlzLl9maW5kKCB0YXJnZXQgKTtcblx0XHRpZiAoIHRvb2x0aXBEYXRhICkge1xuXHRcdFx0dG9vbHRpcERhdGEudG9vbHRpcC5maW5kKCBcIi51aS10b29sdGlwLWNvbnRlbnRcIiApLmh0bWwoIGNvbnRlbnQgKTtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHQvLyBJZiB3ZSBoYXZlIGEgdGl0bGUsIGNsZWFyIGl0IHRvIHByZXZlbnQgdGhlIG5hdGl2ZSB0b29sdGlwXG5cdFx0Ly8gd2UgaGF2ZSB0byBjaGVjayBmaXJzdCB0byBhdm9pZCBkZWZpbmluZyBhIHRpdGxlIGlmIG5vbmUgZXhpc3RzXG5cdFx0Ly8gKHdlIGRvbid0IHdhbnQgdG8gY2F1c2UgYW4gZWxlbWVudCB0byBzdGFydCBtYXRjaGluZyBbdGl0bGVdKVxuXHRcdC8vXG5cdFx0Ly8gV2UgdXNlIHJlbW92ZUF0dHIgb25seSBmb3Iga2V5IGV2ZW50cywgdG8gYWxsb3cgSUUgdG8gZXhwb3J0IHRoZSBjb3JyZWN0XG5cdFx0Ly8gYWNjZXNzaWJsZSBhdHRyaWJ1dGVzLiBGb3IgbW91c2UgZXZlbnRzLCBzZXQgdG8gZW1wdHkgc3RyaW5nIHRvIGF2b2lkXG5cdFx0Ly8gbmF0aXZlIHRvb2x0aXAgc2hvd2luZyB1cCAoaGFwcGVucyBvbmx5IHdoZW4gcmVtb3ZpbmcgaW5zaWRlIG1vdXNlb3ZlcikuXG5cdFx0aWYgKCB0YXJnZXQuaXMoIFwiW3RpdGxlXVwiICkgKSB7XG5cdFx0XHRpZiAoIGV2ZW50ICYmIGV2ZW50LnR5cGUgPT09IFwibW91c2VvdmVyXCIgKSB7XG5cdFx0XHRcdHRhcmdldC5hdHRyKCBcInRpdGxlXCIsIFwiXCIgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHRhcmdldC5yZW1vdmVBdHRyKCBcInRpdGxlXCIgKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0b29sdGlwRGF0YSA9IHRoaXMuX3Rvb2x0aXAoIHRhcmdldCApO1xuXHRcdHRvb2x0aXAgPSB0b29sdGlwRGF0YS50b29sdGlwO1xuXHRcdHRoaXMuX2FkZERlc2NyaWJlZEJ5KCB0YXJnZXQsIHRvb2x0aXAuYXR0ciggXCJpZFwiICkgKTtcblx0XHR0b29sdGlwLmZpbmQoIFwiLnVpLXRvb2x0aXAtY29udGVudFwiICkuaHRtbCggY29udGVudCApO1xuXG5cdFx0Ly8gU3VwcG9ydDogVm9pY2VvdmVyIG9uIE9TIFgsIEpBV1Mgb24gSUUgPD0gOVxuXHRcdC8vIEpBV1MgYW5ub3VuY2VzIGRlbGV0aW9ucyBldmVuIHdoZW4gYXJpYS1yZWxldmFudD1cImFkZGl0aW9uc1wiXG5cdFx0Ly8gVm9pY2VvdmVyIHdpbGwgc29tZXRpbWVzIHJlLXJlYWQgdGhlIGVudGlyZSBsb2cgcmVnaW9uJ3MgY29udGVudHMgZnJvbSB0aGUgYmVnaW5uaW5nXG5cdFx0dGhpcy5saXZlUmVnaW9uLmNoaWxkcmVuKCkuaGlkZSgpO1xuXHRcdGExMXlDb250ZW50ID0gJCggXCI8ZGl2PlwiICkuaHRtbCggdG9vbHRpcC5maW5kKCBcIi51aS10b29sdGlwLWNvbnRlbnRcIiApLmh0bWwoKSApO1xuXHRcdGExMXlDb250ZW50LnJlbW92ZUF0dHIoIFwibmFtZVwiICkuZmluZCggXCJbbmFtZV1cIiApLnJlbW92ZUF0dHIoIFwibmFtZVwiICk7XG5cdFx0YTExeUNvbnRlbnQucmVtb3ZlQXR0ciggXCJpZFwiICkuZmluZCggXCJbaWRdXCIgKS5yZW1vdmVBdHRyKCBcImlkXCIgKTtcblx0XHRhMTF5Q29udGVudC5hcHBlbmRUbyggdGhpcy5saXZlUmVnaW9uICk7XG5cblx0XHRmdW5jdGlvbiBwb3NpdGlvbiggZXZlbnQgKSB7XG5cdFx0XHRwb3NpdGlvbk9wdGlvbi5vZiA9IGV2ZW50O1xuXHRcdFx0aWYgKCB0b29sdGlwLmlzKCBcIjpoaWRkZW5cIiApICkge1xuXHRcdFx0XHRyZXR1cm47XG5cdFx0XHR9XG5cdFx0XHR0b29sdGlwLnBvc2l0aW9uKCBwb3NpdGlvbk9wdGlvbiApO1xuXHRcdH1cblx0XHRpZiAoIHRoaXMub3B0aW9ucy50cmFjayAmJiBldmVudCAmJiAvXm1vdXNlLy50ZXN0KCBldmVudC50eXBlICkgKSB7XG5cdFx0XHR0aGlzLl9vbiggdGhpcy5kb2N1bWVudCwge1xuXHRcdFx0XHRtb3VzZW1vdmU6IHBvc2l0aW9uXG5cdFx0XHR9ICk7XG5cblx0XHRcdC8vIHRyaWdnZXIgb25jZSB0byBvdmVycmlkZSBlbGVtZW50LXJlbGF0aXZlIHBvc2l0aW9uaW5nXG5cdFx0XHRwb3NpdGlvbiggZXZlbnQgKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dG9vbHRpcC5wb3NpdGlvbiggJC5leHRlbmQoIHtcblx0XHRcdFx0b2Y6IHRhcmdldFxuXHRcdFx0fSwgdGhpcy5vcHRpb25zLnBvc2l0aW9uICkgKTtcblx0XHR9XG5cblx0XHR0b29sdGlwLmhpZGUoKTtcblxuXHRcdHRoaXMuX3Nob3coIHRvb2x0aXAsIHRoaXMub3B0aW9ucy5zaG93ICk7XG5cblx0XHQvLyBIYW5kbGUgdHJhY2tpbmcgdG9vbHRpcHMgdGhhdCBhcmUgc2hvd24gd2l0aCBhIGRlbGF5ICgjODY0NCkuIEFzIHNvb25cblx0XHQvLyBhcyB0aGUgdG9vbHRpcCBpcyB2aXNpYmxlLCBwb3NpdGlvbiB0aGUgdG9vbHRpcCB1c2luZyB0aGUgbW9zdCByZWNlbnRcblx0XHQvLyBldmVudC5cblx0XHQvLyBBZGRzIHRoZSBjaGVjayB0byBhZGQgdGhlIHRpbWVycyBvbmx5IHdoZW4gYm90aCBkZWxheSBhbmQgdHJhY2sgb3B0aW9ucyBhcmUgc2V0ICgjMTQ2ODIpXG5cdFx0aWYgKCB0aGlzLm9wdGlvbnMudHJhY2sgJiYgdGhpcy5vcHRpb25zLnNob3cgJiYgdGhpcy5vcHRpb25zLnNob3cuZGVsYXkgKSB7XG5cdFx0XHRkZWxheWVkU2hvdyA9IHRoaXMuZGVsYXllZFNob3cgPSBzZXRJbnRlcnZhbCggZnVuY3Rpb24oKSB7XG5cdFx0XHRcdGlmICggdG9vbHRpcC5pcyggXCI6dmlzaWJsZVwiICkgKSB7XG5cdFx0XHRcdFx0cG9zaXRpb24oIHBvc2l0aW9uT3B0aW9uLm9mICk7XG5cdFx0XHRcdFx0Y2xlYXJJbnRlcnZhbCggZGVsYXllZFNob3cgKTtcblx0XHRcdFx0fVxuXHRcdFx0fSwgJC5meC5pbnRlcnZhbCApO1xuXHRcdH1cblxuXHRcdHRoaXMuX3RyaWdnZXIoIFwib3BlblwiLCBldmVudCwgeyB0b29sdGlwOiB0b29sdGlwIH0gKTtcblx0fSxcblxuXHRfcmVnaXN0ZXJDbG9zZUhhbmRsZXJzOiBmdW5jdGlvbiggZXZlbnQsIHRhcmdldCApIHtcblx0XHR2YXIgZXZlbnRzID0ge1xuXHRcdFx0a2V5dXA6IGZ1bmN0aW9uKCBldmVudCApIHtcblx0XHRcdFx0aWYgKCBldmVudC5rZXlDb2RlID09PSAkLnVpLmtleUNvZGUuRVNDQVBFICkge1xuXHRcdFx0XHRcdHZhciBmYWtlRXZlbnQgPSAkLkV2ZW50KCBldmVudCApO1xuXHRcdFx0XHRcdGZha2VFdmVudC5jdXJyZW50VGFyZ2V0ID0gdGFyZ2V0WyAwIF07XG5cdFx0XHRcdFx0dGhpcy5jbG9zZSggZmFrZUV2ZW50LCB0cnVlICk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0Ly8gT25seSBiaW5kIHJlbW92ZSBoYW5kbGVyIGZvciBkZWxlZ2F0ZWQgdGFyZ2V0cy4gTm9uLWRlbGVnYXRlZFxuXHRcdC8vIHRvb2x0aXBzIHdpbGwgaGFuZGxlIHRoaXMgaW4gZGVzdHJveS5cblx0XHRpZiAoIHRhcmdldFsgMCBdICE9PSB0aGlzLmVsZW1lbnRbIDAgXSApIHtcblx0XHRcdGV2ZW50cy5yZW1vdmUgPSBmdW5jdGlvbigpIHtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlVG9vbHRpcCggdGhpcy5fZmluZCggdGFyZ2V0ICkudG9vbHRpcCApO1xuXHRcdFx0fTtcblx0XHR9XG5cblx0XHRpZiAoICFldmVudCB8fCBldmVudC50eXBlID09PSBcIm1vdXNlb3ZlclwiICkge1xuXHRcdFx0ZXZlbnRzLm1vdXNlbGVhdmUgPSBcImNsb3NlXCI7XG5cdFx0fVxuXHRcdGlmICggIWV2ZW50IHx8IGV2ZW50LnR5cGUgPT09IFwiZm9jdXNpblwiICkge1xuXHRcdFx0ZXZlbnRzLmZvY3Vzb3V0ID0gXCJjbG9zZVwiO1xuXHRcdH1cblx0XHR0aGlzLl9vbiggdHJ1ZSwgdGFyZ2V0LCBldmVudHMgKTtcblx0fSxcblxuXHRjbG9zZTogZnVuY3Rpb24oIGV2ZW50ICkge1xuXHRcdHZhciB0b29sdGlwLFxuXHRcdFx0dGhhdCA9IHRoaXMsXG5cdFx0XHR0YXJnZXQgPSAkKCBldmVudCA/IGV2ZW50LmN1cnJlbnRUYXJnZXQgOiB0aGlzLmVsZW1lbnQgKSxcblx0XHRcdHRvb2x0aXBEYXRhID0gdGhpcy5fZmluZCggdGFyZ2V0ICk7XG5cblx0XHQvLyBUaGUgdG9vbHRpcCBtYXkgYWxyZWFkeSBiZSBjbG9zZWRcblx0XHRpZiAoICF0b29sdGlwRGF0YSApIHtcblxuXHRcdFx0Ly8gV2Ugc2V0IHVpLXRvb2x0aXAtb3BlbiBpbW1lZGlhdGVseSB1cG9uIG9wZW4gKGluIG9wZW4oKSksIGJ1dCBvbmx5IHNldCB0aGVcblx0XHRcdC8vIGFkZGl0aW9uYWwgZGF0YSBvbmNlIHRoZXJlJ3MgYWN0dWFsbHkgY29udGVudCB0byBzaG93IChpbiBfb3BlbigpKS4gU28gZXZlbiBpZiB0aGVcblx0XHRcdC8vIHRvb2x0aXAgZG9lc24ndCBoYXZlIGZ1bGwgZGF0YSwgd2UgYWx3YXlzIHJlbW92ZSB1aS10b29sdGlwLW9wZW4gaW4gY2FzZSB3ZSdyZSBpblxuXHRcdFx0Ly8gdGhlIHBlcmlvZCBiZXR3ZWVuIG9wZW4oKSBhbmQgX29wZW4oKS5cblx0XHRcdHRhcmdldC5yZW1vdmVEYXRhKCBcInVpLXRvb2x0aXAtb3BlblwiICk7XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXG5cdFx0dG9vbHRpcCA9IHRvb2x0aXBEYXRhLnRvb2x0aXA7XG5cblx0XHQvLyBEaXNhYmxpbmcgY2xvc2VzIHRoZSB0b29sdGlwLCBzbyB3ZSBuZWVkIHRvIHRyYWNrIHdoZW4gd2UncmUgY2xvc2luZ1xuXHRcdC8vIHRvIGF2b2lkIGFuIGluZmluaXRlIGxvb3AgaW4gY2FzZSB0aGUgdG9vbHRpcCBiZWNvbWVzIGRpc2FibGVkIG9uIGNsb3NlXG5cdFx0aWYgKCB0b29sdGlwRGF0YS5jbG9zaW5nICkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdC8vIENsZWFyIHRoZSBpbnRlcnZhbCBmb3IgZGVsYXllZCB0cmFja2luZyB0b29sdGlwc1xuXHRcdGNsZWFySW50ZXJ2YWwoIHRoaXMuZGVsYXllZFNob3cgKTtcblxuXHRcdC8vIE9ubHkgc2V0IHRpdGxlIGlmIHdlIGhhZCBvbmUgYmVmb3JlIChzZWUgY29tbWVudCBpbiBfb3BlbigpKVxuXHRcdC8vIElmIHRoZSB0aXRsZSBhdHRyaWJ1dGUgaGFzIGNoYW5nZWQgc2luY2Ugb3BlbigpLCBkb24ndCByZXN0b3JlXG5cdFx0aWYgKCB0YXJnZXQuZGF0YSggXCJ1aS10b29sdGlwLXRpdGxlXCIgKSAmJiAhdGFyZ2V0LmF0dHIoIFwidGl0bGVcIiApICkge1xuXHRcdFx0dGFyZ2V0LmF0dHIoIFwidGl0bGVcIiwgdGFyZ2V0LmRhdGEoIFwidWktdG9vbHRpcC10aXRsZVwiICkgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9yZW1vdmVEZXNjcmliZWRCeSggdGFyZ2V0ICk7XG5cblx0XHR0b29sdGlwRGF0YS5oaWRpbmcgPSB0cnVlO1xuXHRcdHRvb2x0aXAuc3RvcCggdHJ1ZSApO1xuXHRcdHRoaXMuX2hpZGUoIHRvb2x0aXAsIHRoaXMub3B0aW9ucy5oaWRlLCBmdW5jdGlvbigpIHtcblx0XHRcdHRoYXQuX3JlbW92ZVRvb2x0aXAoICQoIHRoaXMgKSApO1xuXHRcdH0gKTtcblxuXHRcdHRhcmdldC5yZW1vdmVEYXRhKCBcInVpLXRvb2x0aXAtb3BlblwiICk7XG5cdFx0dGhpcy5fb2ZmKCB0YXJnZXQsIFwibW91c2VsZWF2ZSBmb2N1c291dCBrZXl1cFwiICk7XG5cblx0XHQvLyBSZW1vdmUgJ3JlbW92ZScgYmluZGluZyBvbmx5IG9uIGRlbGVnYXRlZCB0YXJnZXRzXG5cdFx0aWYgKCB0YXJnZXRbIDAgXSAhPT0gdGhpcy5lbGVtZW50WyAwIF0gKSB7XG5cdFx0XHR0aGlzLl9vZmYoIHRhcmdldCwgXCJyZW1vdmVcIiApO1xuXHRcdH1cblx0XHR0aGlzLl9vZmYoIHRoaXMuZG9jdW1lbnQsIFwibW91c2Vtb3ZlXCIgKTtcblxuXHRcdGlmICggZXZlbnQgJiYgZXZlbnQudHlwZSA9PT0gXCJtb3VzZWxlYXZlXCIgKSB7XG5cdFx0XHQkLmVhY2goIHRoaXMucGFyZW50cywgZnVuY3Rpb24oIGlkLCBwYXJlbnQgKSB7XG5cdFx0XHRcdCQoIHBhcmVudC5lbGVtZW50ICkuYXR0ciggXCJ0aXRsZVwiLCBwYXJlbnQudGl0bGUgKTtcblx0XHRcdFx0ZGVsZXRlIHRoYXQucGFyZW50c1sgaWQgXTtcblx0XHRcdH0gKTtcblx0XHR9XG5cblx0XHR0b29sdGlwRGF0YS5jbG9zaW5nID0gdHJ1ZTtcblx0XHR0aGlzLl90cmlnZ2VyKCBcImNsb3NlXCIsIGV2ZW50LCB7IHRvb2x0aXA6IHRvb2x0aXAgfSApO1xuXHRcdGlmICggIXRvb2x0aXBEYXRhLmhpZGluZyApIHtcblx0XHRcdHRvb2x0aXBEYXRhLmNsb3NpbmcgPSBmYWxzZTtcblx0XHR9XG5cdH0sXG5cblx0X3Rvb2x0aXA6IGZ1bmN0aW9uKCBlbGVtZW50ICkge1xuXHRcdHZhciB0b29sdGlwID0gJCggXCI8ZGl2PlwiICkuYXR0ciggXCJyb2xlXCIsIFwidG9vbHRpcFwiICksXG5cdFx0XHRjb250ZW50ID0gJCggXCI8ZGl2PlwiICkuYXBwZW5kVG8oIHRvb2x0aXAgKSxcblx0XHRcdGlkID0gdG9vbHRpcC51bmlxdWVJZCgpLmF0dHIoIFwiaWRcIiApO1xuXG5cdFx0dGhpcy5fYWRkQ2xhc3MoIGNvbnRlbnQsIFwidWktdG9vbHRpcC1jb250ZW50XCIgKTtcblx0XHR0aGlzLl9hZGRDbGFzcyggdG9vbHRpcCwgXCJ1aS10b29sdGlwXCIsIFwidWktd2lkZ2V0IHVpLXdpZGdldC1jb250ZW50XCIgKTtcblxuXHRcdHRvb2x0aXAuYXBwZW5kVG8oIHRoaXMuX2FwcGVuZFRvKCBlbGVtZW50ICkgKTtcblxuXHRcdHJldHVybiB0aGlzLnRvb2x0aXBzWyBpZCBdID0ge1xuXHRcdFx0ZWxlbWVudDogZWxlbWVudCxcblx0XHRcdHRvb2x0aXA6IHRvb2x0aXBcblx0XHR9O1xuXHR9LFxuXG5cdF9maW5kOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHZhciBpZCA9IHRhcmdldC5kYXRhKCBcInVpLXRvb2x0aXAtaWRcIiApO1xuXHRcdHJldHVybiBpZCA/IHRoaXMudG9vbHRpcHNbIGlkIF0gOiBudWxsO1xuXHR9LFxuXG5cdF9yZW1vdmVUb29sdGlwOiBmdW5jdGlvbiggdG9vbHRpcCApIHtcblx0XHR0b29sdGlwLnJlbW92ZSgpO1xuXHRcdGRlbGV0ZSB0aGlzLnRvb2x0aXBzWyB0b29sdGlwLmF0dHIoIFwiaWRcIiApIF07XG5cdH0sXG5cblx0X2FwcGVuZFRvOiBmdW5jdGlvbiggdGFyZ2V0ICkge1xuXHRcdHZhciBlbGVtZW50ID0gdGFyZ2V0LmNsb3Nlc3QoIFwiLnVpLWZyb250LCBkaWFsb2dcIiApO1xuXG5cdFx0aWYgKCAhZWxlbWVudC5sZW5ndGggKSB7XG5cdFx0XHRlbGVtZW50ID0gdGhpcy5kb2N1bWVudFsgMCBdLmJvZHk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGVsZW1lbnQ7XG5cdH0sXG5cblx0X2Rlc3Ryb3k6IGZ1bmN0aW9uKCkge1xuXHRcdHZhciB0aGF0ID0gdGhpcztcblxuXHRcdC8vIENsb3NlIG9wZW4gdG9vbHRpcHNcblx0XHQkLmVhY2goIHRoaXMudG9vbHRpcHMsIGZ1bmN0aW9uKCBpZCwgdG9vbHRpcERhdGEgKSB7XG5cblx0XHRcdC8vIERlbGVnYXRlIHRvIGNsb3NlIG1ldGhvZCB0byBoYW5kbGUgY29tbW9uIGNsZWFudXBcblx0XHRcdHZhciBldmVudCA9ICQuRXZlbnQoIFwiYmx1clwiICksXG5cdFx0XHRcdGVsZW1lbnQgPSB0b29sdGlwRGF0YS5lbGVtZW50O1xuXHRcdFx0ZXZlbnQudGFyZ2V0ID0gZXZlbnQuY3VycmVudFRhcmdldCA9IGVsZW1lbnRbIDAgXTtcblx0XHRcdHRoYXQuY2xvc2UoIGV2ZW50LCB0cnVlICk7XG5cblx0XHRcdC8vIFJlbW92ZSBpbW1lZGlhdGVseTsgZGVzdHJveWluZyBhbiBvcGVuIHRvb2x0aXAgZG9lc24ndCB1c2UgdGhlXG5cdFx0XHQvLyBoaWRlIGFuaW1hdGlvblxuXHRcdFx0JCggXCIjXCIgKyBpZCApLnJlbW92ZSgpO1xuXG5cdFx0XHQvLyBSZXN0b3JlIHRoZSB0aXRsZVxuXHRcdFx0aWYgKCBlbGVtZW50LmRhdGEoIFwidWktdG9vbHRpcC10aXRsZVwiICkgKSB7XG5cblx0XHRcdFx0Ly8gSWYgdGhlIHRpdGxlIGF0dHJpYnV0ZSBoYXMgY2hhbmdlZCBzaW5jZSBvcGVuKCksIGRvbid0IHJlc3RvcmVcblx0XHRcdFx0aWYgKCAhZWxlbWVudC5hdHRyKCBcInRpdGxlXCIgKSApIHtcblx0XHRcdFx0XHRlbGVtZW50LmF0dHIoIFwidGl0bGVcIiwgZWxlbWVudC5kYXRhKCBcInVpLXRvb2x0aXAtdGl0bGVcIiApICk7XG5cdFx0XHRcdH1cblx0XHRcdFx0ZWxlbWVudC5yZW1vdmVEYXRhKCBcInVpLXRvb2x0aXAtdGl0bGVcIiApO1xuXHRcdFx0fVxuXHRcdH0gKTtcblx0XHR0aGlzLmxpdmVSZWdpb24ucmVtb3ZlKCk7XG5cdH1cbn0gKTtcblxuLy8gREVQUkVDQVRFRFxuLy8gVE9ETzogU3dpdGNoIHJldHVybiBiYWNrIHRvIHdpZGdldCBkZWNsYXJhdGlvbiBhdCB0b3Agb2YgZmlsZSB3aGVuIHRoaXMgaXMgcmVtb3ZlZFxuaWYgKCAkLnVpQmFja0NvbXBhdCAhPT0gZmFsc2UgKSB7XG5cblx0Ly8gQmFja2NvbXBhdCBmb3IgdG9vbHRpcENsYXNzIG9wdGlvblxuXHQkLndpZGdldCggXCJ1aS50b29sdGlwXCIsICQudWkudG9vbHRpcCwge1xuXHRcdG9wdGlvbnM6IHtcblx0XHRcdHRvb2x0aXBDbGFzczogbnVsbFxuXHRcdH0sXG5cdFx0X3Rvb2x0aXA6IGZ1bmN0aW9uKCkge1xuXHRcdFx0dmFyIHRvb2x0aXBEYXRhID0gdGhpcy5fc3VwZXJBcHBseSggYXJndW1lbnRzICk7XG5cdFx0XHRpZiAoIHRoaXMub3B0aW9ucy50b29sdGlwQ2xhc3MgKSB7XG5cdFx0XHRcdHRvb2x0aXBEYXRhLnRvb2x0aXAuYWRkQ2xhc3MoIHRoaXMub3B0aW9ucy50b29sdGlwQ2xhc3MgKTtcblx0XHRcdH1cblx0XHRcdHJldHVybiB0b29sdGlwRGF0YTtcblx0XHR9XG5cdH0gKTtcbn1cblxudmFyIHdpZGdldHNUb29sdGlwID0gJC51aS50b29sdGlwO1xuXG5cblxuXG59KSk7IiwiKGZ1bmN0aW9uIGRlZmluZU11c3RhY2hlKGdsb2JhbCxmYWN0b3J5KXtpZih0eXBlb2YgZXhwb3J0cz09PVwib2JqZWN0XCImJmV4cG9ydHMmJnR5cGVvZiBleHBvcnRzLm5vZGVOYW1lIT09XCJzdHJpbmdcIil7ZmFjdG9yeShleHBvcnRzKX1lbHNlIGlmKHR5cGVvZiBkZWZpbmU9PT1cImZ1bmN0aW9uXCImJmRlZmluZS5hbWQpe2RlZmluZShbXCJleHBvcnRzXCJdLGZhY3RvcnkpfWVsc2V7Z2xvYmFsLk11c3RhY2hlPXt9O2ZhY3RvcnkoZ2xvYmFsLk11c3RhY2hlKX19KSh0aGlzLGZ1bmN0aW9uIG11c3RhY2hlRmFjdG9yeShtdXN0YWNoZSl7dmFyIG9iamVjdFRvU3RyaW5nPU9iamVjdC5wcm90b3R5cGUudG9TdHJpbmc7dmFyIGlzQXJyYXk9QXJyYXkuaXNBcnJheXx8ZnVuY3Rpb24gaXNBcnJheVBvbHlmaWxsKG9iamVjdCl7cmV0dXJuIG9iamVjdFRvU3RyaW5nLmNhbGwob2JqZWN0KT09PVwiW29iamVjdCBBcnJheV1cIn07ZnVuY3Rpb24gaXNGdW5jdGlvbihvYmplY3Qpe3JldHVybiB0eXBlb2Ygb2JqZWN0PT09XCJmdW5jdGlvblwifWZ1bmN0aW9uIHR5cGVTdHIob2JqKXtyZXR1cm4gaXNBcnJheShvYmopP1wiYXJyYXlcIjp0eXBlb2Ygb2JqfWZ1bmN0aW9uIGVzY2FwZVJlZ0V4cChzdHJpbmcpe3JldHVybiBzdHJpbmcucmVwbGFjZSgvW1xcLVxcW1xcXXt9KCkqKz8uLFxcXFxcXF4kfCNcXHNdL2csXCJcXFxcJCZcIil9ZnVuY3Rpb24gaGFzUHJvcGVydHkob2JqLHByb3BOYW1lKXtyZXR1cm4gb2JqIT1udWxsJiZ0eXBlb2Ygb2JqPT09XCJvYmplY3RcIiYmcHJvcE5hbWUgaW4gb2JqfXZhciByZWdFeHBUZXN0PVJlZ0V4cC5wcm90b3R5cGUudGVzdDtmdW5jdGlvbiB0ZXN0UmVnRXhwKHJlLHN0cmluZyl7cmV0dXJuIHJlZ0V4cFRlc3QuY2FsbChyZSxzdHJpbmcpfXZhciBub25TcGFjZVJlPS9cXFMvO2Z1bmN0aW9uIGlzV2hpdGVzcGFjZShzdHJpbmcpe3JldHVybiF0ZXN0UmVnRXhwKG5vblNwYWNlUmUsc3RyaW5nKX12YXIgZW50aXR5TWFwPXtcIiZcIjpcIiZhbXA7XCIsXCI8XCI6XCImbHQ7XCIsXCI+XCI6XCImZ3Q7XCIsJ1wiJzpcIiZxdW90O1wiLFwiJ1wiOlwiJiMzOTtcIixcIi9cIjpcIiYjeDJGO1wiLFwiYFwiOlwiJiN4NjA7XCIsXCI9XCI6XCImI3gzRDtcIn07ZnVuY3Rpb24gZXNjYXBlSHRtbChzdHJpbmcpe3JldHVybiBTdHJpbmcoc3RyaW5nKS5yZXBsYWNlKC9bJjw+XCInYD1cXC9dL2csZnVuY3Rpb24gZnJvbUVudGl0eU1hcChzKXtyZXR1cm4gZW50aXR5TWFwW3NdfSl9dmFyIHdoaXRlUmU9L1xccyovO3ZhciBzcGFjZVJlPS9cXHMrLzt2YXIgZXF1YWxzUmU9L1xccyo9Lzt2YXIgY3VybHlSZT0vXFxzKlxcfS87dmFyIHRhZ1JlPS8jfFxcXnxcXC98PnxcXHt8Jnw9fCEvO2Z1bmN0aW9uIHBhcnNlVGVtcGxhdGUodGVtcGxhdGUsdGFncyl7aWYoIXRlbXBsYXRlKXJldHVybltdO3ZhciBzZWN0aW9ucz1bXTt2YXIgdG9rZW5zPVtdO3ZhciBzcGFjZXM9W107dmFyIGhhc1RhZz1mYWxzZTt2YXIgbm9uU3BhY2U9ZmFsc2U7ZnVuY3Rpb24gc3RyaXBTcGFjZSgpe2lmKGhhc1RhZyYmIW5vblNwYWNlKXt3aGlsZShzcGFjZXMubGVuZ3RoKWRlbGV0ZSB0b2tlbnNbc3BhY2VzLnBvcCgpXX1lbHNle3NwYWNlcz1bXX1oYXNUYWc9ZmFsc2U7bm9uU3BhY2U9ZmFsc2V9dmFyIG9wZW5pbmdUYWdSZSxjbG9zaW5nVGFnUmUsY2xvc2luZ0N1cmx5UmU7ZnVuY3Rpb24gY29tcGlsZVRhZ3ModGFnc1RvQ29tcGlsZSl7aWYodHlwZW9mIHRhZ3NUb0NvbXBpbGU9PT1cInN0cmluZ1wiKXRhZ3NUb0NvbXBpbGU9dGFnc1RvQ29tcGlsZS5zcGxpdChzcGFjZVJlLDIpO2lmKCFpc0FycmF5KHRhZ3NUb0NvbXBpbGUpfHx0YWdzVG9Db21waWxlLmxlbmd0aCE9PTIpdGhyb3cgbmV3IEVycm9yKFwiSW52YWxpZCB0YWdzOiBcIit0YWdzVG9Db21waWxlKTtvcGVuaW5nVGFnUmU9bmV3IFJlZ0V4cChlc2NhcGVSZWdFeHAodGFnc1RvQ29tcGlsZVswXSkrXCJcXFxccypcIik7Y2xvc2luZ1RhZ1JlPW5ldyBSZWdFeHAoXCJcXFxccypcIitlc2NhcGVSZWdFeHAodGFnc1RvQ29tcGlsZVsxXSkpO2Nsb3NpbmdDdXJseVJlPW5ldyBSZWdFeHAoXCJcXFxccypcIitlc2NhcGVSZWdFeHAoXCJ9XCIrdGFnc1RvQ29tcGlsZVsxXSkpfWNvbXBpbGVUYWdzKHRhZ3N8fG11c3RhY2hlLnRhZ3MpO3ZhciBzY2FubmVyPW5ldyBTY2FubmVyKHRlbXBsYXRlKTt2YXIgc3RhcnQsdHlwZSx2YWx1ZSxjaHIsdG9rZW4sb3BlblNlY3Rpb247d2hpbGUoIXNjYW5uZXIuZW9zKCkpe3N0YXJ0PXNjYW5uZXIucG9zO3ZhbHVlPXNjYW5uZXIuc2NhblVudGlsKG9wZW5pbmdUYWdSZSk7aWYodmFsdWUpe2Zvcih2YXIgaT0wLHZhbHVlTGVuZ3RoPXZhbHVlLmxlbmd0aDtpPHZhbHVlTGVuZ3RoOysraSl7Y2hyPXZhbHVlLmNoYXJBdChpKTtpZihpc1doaXRlc3BhY2UoY2hyKSl7c3BhY2VzLnB1c2godG9rZW5zLmxlbmd0aCl9ZWxzZXtub25TcGFjZT10cnVlfXRva2Vucy5wdXNoKFtcInRleHRcIixjaHIsc3RhcnQsc3RhcnQrMV0pO3N0YXJ0Kz0xO2lmKGNocj09PVwiXFxuXCIpc3RyaXBTcGFjZSgpfX1pZighc2Nhbm5lci5zY2FuKG9wZW5pbmdUYWdSZSkpYnJlYWs7aGFzVGFnPXRydWU7dHlwZT1zY2FubmVyLnNjYW4odGFnUmUpfHxcIm5hbWVcIjtzY2FubmVyLnNjYW4od2hpdGVSZSk7aWYodHlwZT09PVwiPVwiKXt2YWx1ZT1zY2FubmVyLnNjYW5VbnRpbChlcXVhbHNSZSk7c2Nhbm5lci5zY2FuKGVxdWFsc1JlKTtzY2FubmVyLnNjYW5VbnRpbChjbG9zaW5nVGFnUmUpfWVsc2UgaWYodHlwZT09PVwie1wiKXt2YWx1ZT1zY2FubmVyLnNjYW5VbnRpbChjbG9zaW5nQ3VybHlSZSk7c2Nhbm5lci5zY2FuKGN1cmx5UmUpO3NjYW5uZXIuc2NhblVudGlsKGNsb3NpbmdUYWdSZSk7dHlwZT1cIiZcIn1lbHNle3ZhbHVlPXNjYW5uZXIuc2NhblVudGlsKGNsb3NpbmdUYWdSZSl9aWYoIXNjYW5uZXIuc2NhbihjbG9zaW5nVGFnUmUpKXRocm93IG5ldyBFcnJvcihcIlVuY2xvc2VkIHRhZyBhdCBcIitzY2FubmVyLnBvcyk7dG9rZW49W3R5cGUsdmFsdWUsc3RhcnQsc2Nhbm5lci5wb3NdO3Rva2Vucy5wdXNoKHRva2VuKTtpZih0eXBlPT09XCIjXCJ8fHR5cGU9PT1cIl5cIil7c2VjdGlvbnMucHVzaCh0b2tlbil9ZWxzZSBpZih0eXBlPT09XCIvXCIpe29wZW5TZWN0aW9uPXNlY3Rpb25zLnBvcCgpO2lmKCFvcGVuU2VjdGlvbil0aHJvdyBuZXcgRXJyb3IoJ1Vub3BlbmVkIHNlY3Rpb24gXCInK3ZhbHVlKydcIiBhdCAnK3N0YXJ0KTtpZihvcGVuU2VjdGlvblsxXSE9PXZhbHVlKXRocm93IG5ldyBFcnJvcignVW5jbG9zZWQgc2VjdGlvbiBcIicrb3BlblNlY3Rpb25bMV0rJ1wiIGF0ICcrc3RhcnQpfWVsc2UgaWYodHlwZT09PVwibmFtZVwifHx0eXBlPT09XCJ7XCJ8fHR5cGU9PT1cIiZcIil7bm9uU3BhY2U9dHJ1ZX1lbHNlIGlmKHR5cGU9PT1cIj1cIil7Y29tcGlsZVRhZ3ModmFsdWUpfX1vcGVuU2VjdGlvbj1zZWN0aW9ucy5wb3AoKTtpZihvcGVuU2VjdGlvbil0aHJvdyBuZXcgRXJyb3IoJ1VuY2xvc2VkIHNlY3Rpb24gXCInK29wZW5TZWN0aW9uWzFdKydcIiBhdCAnK3NjYW5uZXIucG9zKTtyZXR1cm4gbmVzdFRva2VucyhzcXVhc2hUb2tlbnModG9rZW5zKSl9ZnVuY3Rpb24gc3F1YXNoVG9rZW5zKHRva2Vucyl7dmFyIHNxdWFzaGVkVG9rZW5zPVtdO3ZhciB0b2tlbixsYXN0VG9rZW47Zm9yKHZhciBpPTAsbnVtVG9rZW5zPXRva2Vucy5sZW5ndGg7aTxudW1Ub2tlbnM7KytpKXt0b2tlbj10b2tlbnNbaV07aWYodG9rZW4pe2lmKHRva2VuWzBdPT09XCJ0ZXh0XCImJmxhc3RUb2tlbiYmbGFzdFRva2VuWzBdPT09XCJ0ZXh0XCIpe2xhc3RUb2tlblsxXSs9dG9rZW5bMV07bGFzdFRva2VuWzNdPXRva2VuWzNdfWVsc2V7c3F1YXNoZWRUb2tlbnMucHVzaCh0b2tlbik7bGFzdFRva2VuPXRva2VufX19cmV0dXJuIHNxdWFzaGVkVG9rZW5zfWZ1bmN0aW9uIG5lc3RUb2tlbnModG9rZW5zKXt2YXIgbmVzdGVkVG9rZW5zPVtdO3ZhciBjb2xsZWN0b3I9bmVzdGVkVG9rZW5zO3ZhciBzZWN0aW9ucz1bXTt2YXIgdG9rZW4sc2VjdGlvbjtmb3IodmFyIGk9MCxudW1Ub2tlbnM9dG9rZW5zLmxlbmd0aDtpPG51bVRva2VuczsrK2kpe3Rva2VuPXRva2Vuc1tpXTtzd2l0Y2godG9rZW5bMF0pe2Nhc2VcIiNcIjpjYXNlXCJeXCI6Y29sbGVjdG9yLnB1c2godG9rZW4pO3NlY3Rpb25zLnB1c2godG9rZW4pO2NvbGxlY3Rvcj10b2tlbls0XT1bXTticmVhaztjYXNlXCIvXCI6c2VjdGlvbj1zZWN0aW9ucy5wb3AoKTtzZWN0aW9uWzVdPXRva2VuWzJdO2NvbGxlY3Rvcj1zZWN0aW9ucy5sZW5ndGg+MD9zZWN0aW9uc1tzZWN0aW9ucy5sZW5ndGgtMV1bNF06bmVzdGVkVG9rZW5zO2JyZWFrO2RlZmF1bHQ6Y29sbGVjdG9yLnB1c2godG9rZW4pfX1yZXR1cm4gbmVzdGVkVG9rZW5zfWZ1bmN0aW9uIFNjYW5uZXIoc3RyaW5nKXt0aGlzLnN0cmluZz1zdHJpbmc7dGhpcy50YWlsPXN0cmluZzt0aGlzLnBvcz0wfVNjYW5uZXIucHJvdG90eXBlLmVvcz1mdW5jdGlvbiBlb3MoKXtyZXR1cm4gdGhpcy50YWlsPT09XCJcIn07U2Nhbm5lci5wcm90b3R5cGUuc2Nhbj1mdW5jdGlvbiBzY2FuKHJlKXt2YXIgbWF0Y2g9dGhpcy50YWlsLm1hdGNoKHJlKTtpZighbWF0Y2h8fG1hdGNoLmluZGV4IT09MClyZXR1cm5cIlwiO3ZhciBzdHJpbmc9bWF0Y2hbMF07dGhpcy50YWlsPXRoaXMudGFpbC5zdWJzdHJpbmcoc3RyaW5nLmxlbmd0aCk7dGhpcy5wb3MrPXN0cmluZy5sZW5ndGg7cmV0dXJuIHN0cmluZ307U2Nhbm5lci5wcm90b3R5cGUuc2NhblVudGlsPWZ1bmN0aW9uIHNjYW5VbnRpbChyZSl7dmFyIGluZGV4PXRoaXMudGFpbC5zZWFyY2gocmUpLG1hdGNoO3N3aXRjaChpbmRleCl7Y2FzZS0xOm1hdGNoPXRoaXMudGFpbDt0aGlzLnRhaWw9XCJcIjticmVhaztjYXNlIDA6bWF0Y2g9XCJcIjticmVhaztkZWZhdWx0Om1hdGNoPXRoaXMudGFpbC5zdWJzdHJpbmcoMCxpbmRleCk7dGhpcy50YWlsPXRoaXMudGFpbC5zdWJzdHJpbmcoaW5kZXgpfXRoaXMucG9zKz1tYXRjaC5sZW5ndGg7cmV0dXJuIG1hdGNofTtmdW5jdGlvbiBDb250ZXh0KHZpZXcscGFyZW50Q29udGV4dCl7dGhpcy52aWV3PXZpZXc7dGhpcy5jYWNoZT17XCIuXCI6dGhpcy52aWV3fTt0aGlzLnBhcmVudD1wYXJlbnRDb250ZXh0fUNvbnRleHQucHJvdG90eXBlLnB1c2g9ZnVuY3Rpb24gcHVzaCh2aWV3KXtyZXR1cm4gbmV3IENvbnRleHQodmlldyx0aGlzKX07Q29udGV4dC5wcm90b3R5cGUubG9va3VwPWZ1bmN0aW9uIGxvb2t1cChuYW1lKXt2YXIgY2FjaGU9dGhpcy5jYWNoZTt2YXIgdmFsdWU7aWYoY2FjaGUuaGFzT3duUHJvcGVydHkobmFtZSkpe3ZhbHVlPWNhY2hlW25hbWVdfWVsc2V7dmFyIGNvbnRleHQ9dGhpcyxuYW1lcyxpbmRleCxsb29rdXBIaXQ9ZmFsc2U7d2hpbGUoY29udGV4dCl7aWYobmFtZS5pbmRleE9mKFwiLlwiKT4wKXt2YWx1ZT1jb250ZXh0LnZpZXc7bmFtZXM9bmFtZS5zcGxpdChcIi5cIik7aW5kZXg9MDt3aGlsZSh2YWx1ZSE9bnVsbCYmaW5kZXg8bmFtZXMubGVuZ3RoKXtpZihpbmRleD09PW5hbWVzLmxlbmd0aC0xKWxvb2t1cEhpdD1oYXNQcm9wZXJ0eSh2YWx1ZSxuYW1lc1tpbmRleF0pO3ZhbHVlPXZhbHVlW25hbWVzW2luZGV4KytdXX19ZWxzZXt2YWx1ZT1jb250ZXh0LnZpZXdbbmFtZV07bG9va3VwSGl0PWhhc1Byb3BlcnR5KGNvbnRleHQudmlldyxuYW1lKX1pZihsb29rdXBIaXQpYnJlYWs7Y29udGV4dD1jb250ZXh0LnBhcmVudH1jYWNoZVtuYW1lXT12YWx1ZX1pZihpc0Z1bmN0aW9uKHZhbHVlKSl2YWx1ZT12YWx1ZS5jYWxsKHRoaXMudmlldyk7cmV0dXJuIHZhbHVlfTtmdW5jdGlvbiBXcml0ZXIoKXt0aGlzLmNhY2hlPXt9fVdyaXRlci5wcm90b3R5cGUuY2xlYXJDYWNoZT1mdW5jdGlvbiBjbGVhckNhY2hlKCl7dGhpcy5jYWNoZT17fX07V3JpdGVyLnByb3RvdHlwZS5wYXJzZT1mdW5jdGlvbiBwYXJzZSh0ZW1wbGF0ZSx0YWdzKXt2YXIgY2FjaGU9dGhpcy5jYWNoZTt2YXIgdG9rZW5zPWNhY2hlW3RlbXBsYXRlXTtpZih0b2tlbnM9PW51bGwpdG9rZW5zPWNhY2hlW3RlbXBsYXRlXT1wYXJzZVRlbXBsYXRlKHRlbXBsYXRlLHRhZ3MpO3JldHVybiB0b2tlbnN9O1dyaXRlci5wcm90b3R5cGUucmVuZGVyPWZ1bmN0aW9uIHJlbmRlcih0ZW1wbGF0ZSx2aWV3LHBhcnRpYWxzKXt2YXIgdG9rZW5zPXRoaXMucGFyc2UodGVtcGxhdGUpO3ZhciBjb250ZXh0PXZpZXcgaW5zdGFuY2VvZiBDb250ZXh0P3ZpZXc6bmV3IENvbnRleHQodmlldyk7cmV0dXJuIHRoaXMucmVuZGVyVG9rZW5zKHRva2Vucyxjb250ZXh0LHBhcnRpYWxzLHRlbXBsYXRlKX07V3JpdGVyLnByb3RvdHlwZS5yZW5kZXJUb2tlbnM9ZnVuY3Rpb24gcmVuZGVyVG9rZW5zKHRva2Vucyxjb250ZXh0LHBhcnRpYWxzLG9yaWdpbmFsVGVtcGxhdGUpe3ZhciBidWZmZXI9XCJcIjt2YXIgdG9rZW4sc3ltYm9sLHZhbHVlO2Zvcih2YXIgaT0wLG51bVRva2Vucz10b2tlbnMubGVuZ3RoO2k8bnVtVG9rZW5zOysraSl7dmFsdWU9dW5kZWZpbmVkO3Rva2VuPXRva2Vuc1tpXTtzeW1ib2w9dG9rZW5bMF07aWYoc3ltYm9sPT09XCIjXCIpdmFsdWU9dGhpcy5yZW5kZXJTZWN0aW9uKHRva2VuLGNvbnRleHQscGFydGlhbHMsb3JpZ2luYWxUZW1wbGF0ZSk7ZWxzZSBpZihzeW1ib2w9PT1cIl5cIil2YWx1ZT10aGlzLnJlbmRlckludmVydGVkKHRva2VuLGNvbnRleHQscGFydGlhbHMsb3JpZ2luYWxUZW1wbGF0ZSk7ZWxzZSBpZihzeW1ib2w9PT1cIj5cIil2YWx1ZT10aGlzLnJlbmRlclBhcnRpYWwodG9rZW4sY29udGV4dCxwYXJ0aWFscyxvcmlnaW5hbFRlbXBsYXRlKTtlbHNlIGlmKHN5bWJvbD09PVwiJlwiKXZhbHVlPXRoaXMudW5lc2NhcGVkVmFsdWUodG9rZW4sY29udGV4dCk7ZWxzZSBpZihzeW1ib2w9PT1cIm5hbWVcIil2YWx1ZT10aGlzLmVzY2FwZWRWYWx1ZSh0b2tlbixjb250ZXh0KTtlbHNlIGlmKHN5bWJvbD09PVwidGV4dFwiKXZhbHVlPXRoaXMucmF3VmFsdWUodG9rZW4pO2lmKHZhbHVlIT09dW5kZWZpbmVkKWJ1ZmZlcis9dmFsdWV9cmV0dXJuIGJ1ZmZlcn07V3JpdGVyLnByb3RvdHlwZS5yZW5kZXJTZWN0aW9uPWZ1bmN0aW9uIHJlbmRlclNlY3Rpb24odG9rZW4sY29udGV4dCxwYXJ0aWFscyxvcmlnaW5hbFRlbXBsYXRlKXt2YXIgc2VsZj10aGlzO3ZhciBidWZmZXI9XCJcIjt2YXIgdmFsdWU9Y29udGV4dC5sb29rdXAodG9rZW5bMV0pO2Z1bmN0aW9uIHN1YlJlbmRlcih0ZW1wbGF0ZSl7cmV0dXJuIHNlbGYucmVuZGVyKHRlbXBsYXRlLGNvbnRleHQscGFydGlhbHMpfWlmKCF2YWx1ZSlyZXR1cm47aWYoaXNBcnJheSh2YWx1ZSkpe2Zvcih2YXIgaj0wLHZhbHVlTGVuZ3RoPXZhbHVlLmxlbmd0aDtqPHZhbHVlTGVuZ3RoOysrail7YnVmZmVyKz10aGlzLnJlbmRlclRva2Vucyh0b2tlbls0XSxjb250ZXh0LnB1c2godmFsdWVbal0pLHBhcnRpYWxzLG9yaWdpbmFsVGVtcGxhdGUpfX1lbHNlIGlmKHR5cGVvZiB2YWx1ZT09PVwib2JqZWN0XCJ8fHR5cGVvZiB2YWx1ZT09PVwic3RyaW5nXCJ8fHR5cGVvZiB2YWx1ZT09PVwibnVtYmVyXCIpe2J1ZmZlcis9dGhpcy5yZW5kZXJUb2tlbnModG9rZW5bNF0sY29udGV4dC5wdXNoKHZhbHVlKSxwYXJ0aWFscyxvcmlnaW5hbFRlbXBsYXRlKX1lbHNlIGlmKGlzRnVuY3Rpb24odmFsdWUpKXtpZih0eXBlb2Ygb3JpZ2luYWxUZW1wbGF0ZSE9PVwic3RyaW5nXCIpdGhyb3cgbmV3IEVycm9yKFwiQ2Fubm90IHVzZSBoaWdoZXItb3JkZXIgc2VjdGlvbnMgd2l0aG91dCB0aGUgb3JpZ2luYWwgdGVtcGxhdGVcIik7dmFsdWU9dmFsdWUuY2FsbChjb250ZXh0LnZpZXcsb3JpZ2luYWxUZW1wbGF0ZS5zbGljZSh0b2tlblszXSx0b2tlbls1XSksc3ViUmVuZGVyKTtpZih2YWx1ZSE9bnVsbClidWZmZXIrPXZhbHVlfWVsc2V7YnVmZmVyKz10aGlzLnJlbmRlclRva2Vucyh0b2tlbls0XSxjb250ZXh0LHBhcnRpYWxzLG9yaWdpbmFsVGVtcGxhdGUpfXJldHVybiBidWZmZXJ9O1dyaXRlci5wcm90b3R5cGUucmVuZGVySW52ZXJ0ZWQ9ZnVuY3Rpb24gcmVuZGVySW52ZXJ0ZWQodG9rZW4sY29udGV4dCxwYXJ0aWFscyxvcmlnaW5hbFRlbXBsYXRlKXt2YXIgdmFsdWU9Y29udGV4dC5sb29rdXAodG9rZW5bMV0pO2lmKCF2YWx1ZXx8aXNBcnJheSh2YWx1ZSkmJnZhbHVlLmxlbmd0aD09PTApcmV0dXJuIHRoaXMucmVuZGVyVG9rZW5zKHRva2VuWzRdLGNvbnRleHQscGFydGlhbHMsb3JpZ2luYWxUZW1wbGF0ZSl9O1dyaXRlci5wcm90b3R5cGUucmVuZGVyUGFydGlhbD1mdW5jdGlvbiByZW5kZXJQYXJ0aWFsKHRva2VuLGNvbnRleHQscGFydGlhbHMpe2lmKCFwYXJ0aWFscylyZXR1cm47dmFyIHZhbHVlPWlzRnVuY3Rpb24ocGFydGlhbHMpP3BhcnRpYWxzKHRva2VuWzFdKTpwYXJ0aWFsc1t0b2tlblsxXV07aWYodmFsdWUhPW51bGwpcmV0dXJuIHRoaXMucmVuZGVyVG9rZW5zKHRoaXMucGFyc2UodmFsdWUpLGNvbnRleHQscGFydGlhbHMsdmFsdWUpfTtXcml0ZXIucHJvdG90eXBlLnVuZXNjYXBlZFZhbHVlPWZ1bmN0aW9uIHVuZXNjYXBlZFZhbHVlKHRva2VuLGNvbnRleHQpe3ZhciB2YWx1ZT1jb250ZXh0Lmxvb2t1cCh0b2tlblsxXSk7aWYodmFsdWUhPW51bGwpcmV0dXJuIHZhbHVlfTtXcml0ZXIucHJvdG90eXBlLmVzY2FwZWRWYWx1ZT1mdW5jdGlvbiBlc2NhcGVkVmFsdWUodG9rZW4sY29udGV4dCl7dmFyIHZhbHVlPWNvbnRleHQubG9va3VwKHRva2VuWzFdKTtpZih2YWx1ZSE9bnVsbClyZXR1cm4gbXVzdGFjaGUuZXNjYXBlKHZhbHVlKX07V3JpdGVyLnByb3RvdHlwZS5yYXdWYWx1ZT1mdW5jdGlvbiByYXdWYWx1ZSh0b2tlbil7cmV0dXJuIHRva2VuWzFdfTttdXN0YWNoZS5uYW1lPVwibXVzdGFjaGUuanNcIjttdXN0YWNoZS52ZXJzaW9uPVwiMi4zLjJcIjttdXN0YWNoZS50YWdzPVtcInt7XCIsXCJ9fVwiXTt2YXIgZGVmYXVsdFdyaXRlcj1uZXcgV3JpdGVyO211c3RhY2hlLmNsZWFyQ2FjaGU9ZnVuY3Rpb24gY2xlYXJDYWNoZSgpe3JldHVybiBkZWZhdWx0V3JpdGVyLmNsZWFyQ2FjaGUoKX07bXVzdGFjaGUucGFyc2U9ZnVuY3Rpb24gcGFyc2UodGVtcGxhdGUsdGFncyl7cmV0dXJuIGRlZmF1bHRXcml0ZXIucGFyc2UodGVtcGxhdGUsdGFncyl9O211c3RhY2hlLnJlbmRlcj1mdW5jdGlvbiByZW5kZXIodGVtcGxhdGUsdmlldyxwYXJ0aWFscyl7aWYodHlwZW9mIHRlbXBsYXRlIT09XCJzdHJpbmdcIil7dGhyb3cgbmV3IFR5cGVFcnJvcignSW52YWxpZCB0ZW1wbGF0ZSEgVGVtcGxhdGUgc2hvdWxkIGJlIGEgXCJzdHJpbmdcIiAnKydidXQgXCInK3R5cGVTdHIodGVtcGxhdGUpKydcIiB3YXMgZ2l2ZW4gYXMgdGhlIGZpcnN0ICcrXCJhcmd1bWVudCBmb3IgbXVzdGFjaGUjcmVuZGVyKHRlbXBsYXRlLCB2aWV3LCBwYXJ0aWFscylcIil9cmV0dXJuIGRlZmF1bHRXcml0ZXIucmVuZGVyKHRlbXBsYXRlLHZpZXcscGFydGlhbHMpfTttdXN0YWNoZS50b19odG1sPWZ1bmN0aW9uIHRvX2h0bWwodGVtcGxhdGUsdmlldyxwYXJ0aWFscyxzZW5kKXt2YXIgcmVzdWx0PW11c3RhY2hlLnJlbmRlcih0ZW1wbGF0ZSx2aWV3LHBhcnRpYWxzKTtpZihpc0Z1bmN0aW9uKHNlbmQpKXtzZW5kKHJlc3VsdCl9ZWxzZXtyZXR1cm4gcmVzdWx0fX07bXVzdGFjaGUuZXNjYXBlPWVzY2FwZUh0bWw7bXVzdGFjaGUuU2Nhbm5lcj1TY2FubmVyO211c3RhY2hlLkNvbnRleHQ9Q29udGV4dDttdXN0YWNoZS5Xcml0ZXI9V3JpdGVyO3JldHVybiBtdXN0YWNoZX0pO1xuIiwiLyogZ2xvYmFscyBqUXVlcnkgKi9cblxuKGZ1bmN0aW9uKCQpIHtcbiAgLy8gU2VsZWN0b3IgdG8gc2VsZWN0IG9ubHkgbm90IGFscmVhZHkgcHJvY2Vzc2VkIGVsZW1lbnRzXG4gICQuZXhwcltcIjpcIl0ubm90bWRwcm9jID0gZnVuY3Rpb24ob2JqKXtcbiAgICBpZiAoJChvYmopLmRhdGEoXCJtZHByb2NcIikpIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICB9O1xuXG4gIGZ1bmN0aW9uIF9pc0NoYXIoZXZ0KSB7XG4gICAgaWYgKHR5cGVvZiBldnQud2hpY2ggPT0gXCJ1bmRlZmluZWRcIikge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgZXZ0LndoaWNoID09IFwibnVtYmVyXCIgJiYgZXZ0LndoaWNoID4gMCkge1xuICAgICAgcmV0dXJuICFldnQuY3RybEtleSAmJiAhZXZ0Lm1ldGFLZXkgJiYgIWV2dC5hbHRLZXkgJiYgZXZ0LndoaWNoICE9IDggJiYgZXZ0LndoaWNoICE9IDk7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBcbiAgZnVuY3Rpb24gX2FkZEZvcm1Hcm91cEZvY3VzKGVsZW1lbnQpe1xuICAgICQoZWxlbWVudCkuY2xvc2VzdChcIi5mb3JtLWdyb3VwXCIpLmFkZENsYXNzKFwiaXMtZm9jdXNlZFwiKTtcbiAgfVxuICBcbiAgZnVuY3Rpb24gX3JlbW92ZUZvcm1Hcm91cEZvY3VzKGVsZW1lbnQpe1xuICAgICQoZWxlbWVudCkuY2xvc2VzdChcIi5mb3JtLWdyb3VwXCIpLnJlbW92ZUNsYXNzKFwiaXMtZm9jdXNlZFwiKTsgLy8gcmVtb3ZlIGNsYXNzIGZyb20gZm9ybS1ncm91cFxuICB9XG5cbiAgJC5tYXRlcmlhbCA9ICB7XG4gICAgXCJvcHRpb25zXCI6IHtcbiAgICAgIC8vIFRoZXNlIG9wdGlvbnMgc2V0IHdoYXQgd2lsbCBiZSBzdGFydGVkIGJ5ICQubWF0ZXJpYWwuaW5pdCgpXG4gICAgICBcImlucHV0XCI6IHRydWUsXG4gICAgICBcInJpcHBsZXNcIjogdHJ1ZSxcbiAgICAgIFwiY2hlY2tib3hcIjogdHJ1ZSxcbiAgICAgIFwidG9nZ2xlYnV0dG9uXCI6IHRydWUsXG4gICAgICBcInJhZGlvXCI6IHRydWUsXG4gICAgICBcImFycml2ZVwiOiB0cnVlLFxuICAgICAgXCJhdXRvZmlsbFwiOiBmYWxzZSxcblxuICAgICAgXCJ3aXRoUmlwcGxlc1wiOiBbXG4gICAgICAgIFwiLmJ0bjpub3QoLmJ0bi1saW5rKVwiLFxuICAgICAgICBcIi5jYXJkLWltYWdlXCIsXG4gICAgICAgIFwiLm5hdmJhciBhOm5vdCgud2l0aG91dHJpcHBsZSlcIixcbiAgICAgICAgXCIuZHJvcGRvd24tbWVudSBhXCIsXG4gICAgICAgIFwiLm5hdi10YWJzIGE6bm90KC53aXRob3V0cmlwcGxlKVwiLFxuICAgICAgICBcIi53aXRocmlwcGxlXCIsXG4gICAgICAgIFwiLnBhZ2luYXRpb24gbGk6bm90KC5hY3RpdmUpOm5vdCguZGlzYWJsZWQpIGE6bm90KC53aXRob3V0cmlwcGxlKVwiXG4gICAgICBdLmpvaW4oXCIsXCIpLFxuICAgICAgXCJpbnB1dEVsZW1lbnRzXCI6IFwiaW5wdXQuZm9ybS1jb250cm9sLCB0ZXh0YXJlYS5mb3JtLWNvbnRyb2wsIHNlbGVjdC5mb3JtLWNvbnRyb2xcIixcbiAgICAgIFwiY2hlY2tib3hFbGVtZW50c1wiOiBcIi5jaGVja2JveCA+IGxhYmVsID4gaW5wdXRbdHlwZT1jaGVja2JveF1cIixcbiAgICAgIFwidG9nZ2xlYnV0dG9uRWxlbWVudHNcIjogXCIudG9nZ2xlYnV0dG9uID4gbGFiZWwgPiBpbnB1dFt0eXBlPWNoZWNrYm94XVwiLFxuICAgICAgXCJyYWRpb0VsZW1lbnRzXCI6IFwiLnJhZGlvID4gbGFiZWwgPiBpbnB1dFt0eXBlPXJhZGlvXVwiXG4gICAgfSxcbiAgICBcImNoZWNrYm94XCI6IGZ1bmN0aW9uKHNlbGVjdG9yKSB7XG4gICAgICAvLyBBZGQgZmFrZS1jaGVja2JveCB0byBtYXRlcmlhbCBjaGVja2JveGVzXG4gICAgICAkKChzZWxlY3RvcikgPyBzZWxlY3RvciA6IHRoaXMub3B0aW9ucy5jaGVja2JveEVsZW1lbnRzKVxuICAgICAgLmZpbHRlcihcIjpub3RtZHByb2NcIilcbiAgICAgIC5kYXRhKFwibWRwcm9jXCIsIHRydWUpXG4gICAgICAuYWZ0ZXIoXCI8c3BhbiBjbGFzcz0nY2hlY2tib3gtbWF0ZXJpYWwnPjxzcGFuIGNsYXNzPSdjaGVjayc+PC9zcGFuPjwvc3Bhbj5cIik7XG4gICAgfSxcbiAgICBcInRvZ2dsZWJ1dHRvblwiOiBmdW5jdGlvbihzZWxlY3Rvcikge1xuICAgICAgLy8gQWRkIGZha2UtY2hlY2tib3ggdG8gbWF0ZXJpYWwgY2hlY2tib3hlc1xuICAgICAgJCgoc2VsZWN0b3IpID8gc2VsZWN0b3IgOiB0aGlzLm9wdGlvbnMudG9nZ2xlYnV0dG9uRWxlbWVudHMpXG4gICAgICAuZmlsdGVyKFwiOm5vdG1kcHJvY1wiKVxuICAgICAgLmRhdGEoXCJtZHByb2NcIiwgdHJ1ZSlcbiAgICAgIC5hZnRlcihcIjxzcGFuIGNsYXNzPSd0b2dnbGUnPjwvc3Bhbj5cIik7XG4gICAgfSxcbiAgICBcInJhZGlvXCI6IGZ1bmN0aW9uKHNlbGVjdG9yKSB7XG4gICAgICAvLyBBZGQgZmFrZS1yYWRpbyB0byBtYXRlcmlhbCByYWRpb3NcbiAgICAgICQoKHNlbGVjdG9yKSA/IHNlbGVjdG9yIDogdGhpcy5vcHRpb25zLnJhZGlvRWxlbWVudHMpXG4gICAgICAuZmlsdGVyKFwiOm5vdG1kcHJvY1wiKVxuICAgICAgLmRhdGEoXCJtZHByb2NcIiwgdHJ1ZSlcbiAgICAgIC5hZnRlcihcIjxzcGFuIGNsYXNzPSdjaXJjbGUnPjwvc3Bhbj48c3BhbiBjbGFzcz0nY2hlY2snPjwvc3Bhbj5cIik7XG4gICAgfSxcbiAgICBcImlucHV0XCI6IGZ1bmN0aW9uKHNlbGVjdG9yKSB7XG4gICAgICAkKChzZWxlY3RvcikgPyBzZWxlY3RvciA6IHRoaXMub3B0aW9ucy5pbnB1dEVsZW1lbnRzKVxuICAgICAgLmZpbHRlcihcIjpub3RtZHByb2NcIilcbiAgICAgIC5kYXRhKFwibWRwcm9jXCIsIHRydWUpXG4gICAgICAuZWFjaCggZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciAkaW5wdXQgPSAkKHRoaXMpO1xuXG4gICAgICAgIC8vIFJlcXVpcmVzIGZvcm0tZ3JvdXAgc3RhbmRhcmQgbWFya3VwICh3aWxsIGFkZCBpdCBpZiBuZWNlc3NhcnkpXG4gICAgICAgIHZhciAkZm9ybUdyb3VwID0gJGlucHV0LmNsb3Nlc3QoXCIuZm9ybS1ncm91cFwiKTsgLy8gbm90ZSB0aGF0IGZvcm0tZ3JvdXAgbWF5IGJlIGdyYW5kcGFyZW50IGluIHRoZSBjYXNlIG9mIGFuIGlucHV0LWdyb3VwXG4gICAgICAgIGlmKCRmb3JtR3JvdXAubGVuZ3RoID09PSAwKXtcbiAgICAgICAgICAkaW5wdXQud3JhcChcIjxkaXYgY2xhc3M9J2Zvcm0tZ3JvdXAnPjwvZGl2PlwiKTtcbiAgICAgICAgICAkZm9ybUdyb3VwID0gJGlucHV0LmNsb3Nlc3QoXCIuZm9ybS1ncm91cFwiKTsgLy8gZmluZCBub2RlIGFmdGVyIGF0dGFjaGVkIChvdGhlcndpc2UgYWRkaXRpb25hbCBhdHRhY2htZW50cyBkb24ndCB3b3JrKVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gTGVnYWN5IC0gQWRkIGhpbnQgbGFiZWwgaWYgdXNpbmcgdGhlIG9sZCBzaG9ydGhhbmQgZGF0YS1oaW50IGF0dHJpYnV0ZSBvbiB0aGUgaW5wdXRcbiAgICAgICAgaWYgKCRpbnB1dC5hdHRyKFwiZGF0YS1oaW50XCIpKSB7XG4gICAgICAgICAgJGlucHV0LmFmdGVyKFwiPHAgY2xhc3M9J2hlbHAtYmxvY2snPlwiICsgJGlucHV0LmF0dHIoXCJkYXRhLWhpbnRcIikgKyBcIjwvcD5cIik7XG4gICAgICAgICAgJGlucHV0LnJlbW92ZUF0dHIoXCJkYXRhLWhpbnRcIik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBMZWdhY3kgLSBDaGFuZ2UgaW5wdXQtc20vbGcgdG8gZm9ybS1ncm91cC1zbS9sZyBpbnN0ZWFkIChwcmVmZXJyZWQgc3RhbmRhcmQgYW5kIHNpbXBsZXIgY3NzL2xlc3MgdmFyaWFudHMpXG4gICAgICAgIHZhciBsZWdhY3lTaXplcyA9IHtcbiAgICAgICAgICBcImlucHV0LWxnXCI6IFwiZm9ybS1ncm91cC1sZ1wiLFxuICAgICAgICAgIFwiaW5wdXQtc21cIjogXCJmb3JtLWdyb3VwLXNtXCJcbiAgICAgICAgfTtcbiAgICAgICAgJC5lYWNoKCBsZWdhY3lTaXplcywgZnVuY3Rpb24oIGxlZ2FjeVNpemUsIHN0YW5kYXJkU2l6ZSApIHtcbiAgICAgICAgICBpZiAoJGlucHV0Lmhhc0NsYXNzKGxlZ2FjeVNpemUpKSB7XG4gICAgICAgICAgICAkaW5wdXQucmVtb3ZlQ2xhc3MobGVnYWN5U2l6ZSk7XG4gICAgICAgICAgICAkZm9ybUdyb3VwLmFkZENsYXNzKHN0YW5kYXJkU2l6ZSk7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBMZWdhY3kgLSBBZGQgbGFiZWwtZmxvYXRpbmcgaWYgdXNpbmcgb2xkIHNob3J0aGFuZCA8aW5wdXQgY2xhc3M9XCJmbG9hdGluZy1sYWJlbFwiIHBsYWNlaG9sZGVyPVwiZm9vXCI+XG4gICAgICAgIGlmICgkaW5wdXQuaGFzQ2xhc3MoXCJmbG9hdGluZy1sYWJlbFwiKSkge1xuICAgICAgICAgIHZhciBwbGFjZWhvbGRlciA9ICRpbnB1dC5hdHRyKFwicGxhY2Vob2xkZXJcIik7XG4gICAgICAgICAgJGlucHV0LmF0dHIoXCJwbGFjZWhvbGRlclwiLCBudWxsKS5yZW1vdmVDbGFzcyhcImZsb2F0aW5nLWxhYmVsXCIpO1xuICAgICAgICAgIHZhciBpZCA9ICRpbnB1dC5hdHRyKFwiaWRcIik7XG4gICAgICAgICAgdmFyIGZvckF0dHJpYnV0ZSA9IFwiXCI7XG4gICAgICAgICAgaWYoaWQpIHtcbiAgICAgICAgICAgIGZvckF0dHJpYnV0ZSA9IFwiZm9yPSdcIiArIGlkICsgXCInXCI7XG4gICAgICAgICAgfVxuICAgICAgICAgICRmb3JtR3JvdXAuYWRkQ2xhc3MoXCJsYWJlbC1mbG9hdGluZ1wiKTtcbiAgICAgICAgICAkaW5wdXQuYWZ0ZXIoXCI8bGFiZWwgXCIgKyBmb3JBdHRyaWJ1dGUgKyBcImNsYXNzPSdjb250cm9sLWxhYmVsJz5cIiArIHBsYWNlaG9sZGVyICsgXCI8L2xhYmVsPlwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFNldCBhcyBlbXB0eSBpZiBpcyBlbXB0eSAoZGFtbiBJIG11c3QgaW1wcm92ZSB0aGlzLi4uKVxuICAgICAgICBpZiAoJGlucHV0LnZhbCgpID09PSBudWxsIHx8ICRpbnB1dC52YWwoKSA9PSBcInVuZGVmaW5lZFwiIHx8ICRpbnB1dC52YWwoKSA9PT0gXCJcIikge1xuICAgICAgICAgICRmb3JtR3JvdXAuYWRkQ2xhc3MoXCJpcy1lbXB0eVwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgICAgLy8gQWRkIGF0IHRoZSBlbmQgb2YgdGhlIGZvcm0tZ3JvdXBcbiAgICAgICAgJGZvcm1Hcm91cC5hcHBlbmQoXCI8c3BhbiBjbGFzcz0nbWF0ZXJpYWwtaW5wdXQnPjwvc3Bhbj5cIik7XG5cbiAgICAgICAgLy8gU3VwcG9ydCBmb3IgZmlsZSBpbnB1dFxuICAgICAgICBpZiAoJGZvcm1Hcm91cC5maW5kKFwiaW5wdXRbdHlwZT1maWxlXVwiKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgJGZvcm1Hcm91cC5hZGRDbGFzcyhcImlzLWZpbGVpbnB1dFwiKTtcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfSxcbiAgICBcImF0dGFjaElucHV0RXZlbnRIYW5kbGVyc1wiOiBmdW5jdGlvbigpIHtcblxuICAgICAgLy8gY2hlY2tib3hlcyBkaWRuJ3QgYXBwZWFyIHRvIGJ1YmJsZSB0byB0aGUgZG9jdW1lbnQsIHNvIHdlJ2xsIGJpbmQgdGhlc2UgZGlyZWN0bHlcbiAgICAgICQoXCIuZm9ybS1ncm91cCAuY2hlY2tib3ggbGFiZWxcIikuaG92ZXIoZnVuY3Rpb24oKSB7XG4gICAgICAgIF9hZGRGb3JtR3JvdXBGb2N1cyh0aGlzKTtcbiAgICAgIH0sIGZ1bmN0aW9uKCkge1xuICAgICAgICBfcmVtb3ZlRm9ybUdyb3VwRm9jdXModGhpcyk7XG4gICAgICB9KTtcblxuICAgICAgJChkb2N1bWVudClcbiAgICAgIC5vbihcImNoYW5nZVwiLCBcIi5jaGVja2JveCBpbnB1dFt0eXBlPWNoZWNrYm94XVwiLCBmdW5jdGlvbigpIHsgJCh0aGlzKS5ibHVyKCk7IH0pXG4gICAgICAub24oXCJrZXlkb3duIHBhc3RlXCIsIFwiLmZvcm0tY29udHJvbFwiLCBmdW5jdGlvbihlKSB7XG4gICAgICAgIGlmKF9pc0NoYXIoZSkpIHtcbiAgICAgICAgICAkKHRoaXMpLmNsb3Nlc3QoXCIuZm9ybS1ncm91cFwiKS5yZW1vdmVDbGFzcyhcImlzLWVtcHR5XCIpO1xuICAgICAgICB9XG4gICAgICB9KVxuICAgICAgLm9uKFwia2V5dXAgY2hhbmdlXCIsIFwiLmZvcm0tY29udHJvbFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyICRpbnB1dCA9ICQodGhpcyk7XG4gICAgICAgIHZhciAkZm9ybUdyb3VwID0gJGlucHV0LmNsb3Nlc3QoXCIuZm9ybS1ncm91cFwiKTtcbiAgICAgICAgdmFyIGlzVmFsaWQgPSAodHlwZW9mICRpbnB1dFswXS5jaGVja1ZhbGlkaXR5ID09PSBcInVuZGVmaW5lZFwiIHx8ICRpbnB1dFswXS5jaGVja1ZhbGlkaXR5KCkpO1xuXG4gICAgICAgIGlmICgkaW5wdXQudmFsKCkgPT09IFwiXCIgJiYgaXNWYWxpZCkge1xuICAgICAgICAgICRmb3JtR3JvdXAuYWRkQ2xhc3MoXCJpcy1lbXB0eVwiKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAkZm9ybUdyb3VwLnJlbW92ZUNsYXNzKFwiaXMtZW1wdHlcIik7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBWYWxpZGF0aW9uIGV2ZW50cyBkbyBub3QgYnViYmxlLCBzbyB0aGV5IG11c3QgYmUgYXR0YWNoZWQgZGlyZWN0bHkgdG8gdGhlIGlucHV0OiBodHRwOi8vanNmaWRkbGUubmV0L1BFcFJNLzEvXG4gICAgICAgIC8vICBGdXJ0aGVyLCBldmVuIHRoZSBiaW5kIG1ldGhvZCBpcyBiZWluZyBjYXVnaHQsIGJ1dCBzaW5jZSB3ZSBhcmUgYWxyZWFkeSBjYWxsaW5nICNjaGVja1ZhbGlkaXR5IGhlcmUsIGp1c3QgYWx0ZXJcbiAgICAgICAgLy8gIHRoZSBmb3JtLWdyb3VwIG9uIGNoYW5nZS5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gTk9URTogSSdtIG5vdCBzdXJlIHdlIHNob3VsZCBiZSBpbnRlcnZlbmluZyByZWdhcmRpbmcgdmFsaWRhdGlvbiwgdGhpcyBzZWVtcyBiZXR0ZXIgYXMgYSBSRUFETUUgYW5kIHNuaXBwZXQgb2YgY29kZS5cbiAgICAgICAgLy8gICAgICAgIEJVVCwgSSd2ZSBsZWZ0IGl0IGhlcmUgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5LlxuICAgICAgICBpZihpc1ZhbGlkKXtcbiAgICAgICAgICAkZm9ybUdyb3VwLnJlbW92ZUNsYXNzKFwiaGFzLWVycm9yXCIpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2V7XG4gICAgICAgICAgJGZvcm1Hcm91cC5hZGRDbGFzcyhcImhhcy1lcnJvclwiKTtcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICAgIC5vbihcImZvY3VzXCIsIFwiLmZvcm0tY29udHJvbCwgLmZvcm0tZ3JvdXAuaXMtZmlsZWlucHV0XCIsIGZ1bmN0aW9uKCkge1xuICAgICAgICBfYWRkRm9ybUdyb3VwRm9jdXModGhpcyk7XG4gICAgICB9KVxuICAgICAgLm9uKFwiYmx1clwiLCBcIi5mb3JtLWNvbnRyb2wsIC5mb3JtLWdyb3VwLmlzLWZpbGVpbnB1dFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgX3JlbW92ZUZvcm1Hcm91cEZvY3VzKHRoaXMpO1xuICAgICAgfSlcbiAgICAgIC8vIG1ha2Ugc3VyZSBlbXB0eSBpcyBhZGRlZCBiYWNrIHdoZW4gdGhlcmUgaXMgYSBwcm9ncmFtbWF0aWMgdmFsdWUgY2hhbmdlLlxuICAgICAgLy8gIE5PVEU6IHByb2dyYW1tYXRpYyBjaGFuZ2luZyBvZiB2YWx1ZSB1c2luZyAkLnZhbCgpIG11c3QgdHJpZ2dlciB0aGUgY2hhbmdlIGV2ZW50IGkuZS4gJC52YWwoJ3gnKS50cmlnZ2VyKCdjaGFuZ2UnKVxuICAgICAgLm9uKFwiY2hhbmdlXCIsIFwiLmZvcm0tZ3JvdXAgaW5wdXRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciAkaW5wdXQgPSAkKHRoaXMpO1xuICAgICAgICBpZigkaW5wdXQuYXR0cihcInR5cGVcIikgPT0gXCJmaWxlXCIpIHtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgJGZvcm1Hcm91cCA9ICRpbnB1dC5jbG9zZXN0KFwiLmZvcm0tZ3JvdXBcIik7XG4gICAgICAgIHZhciB2YWx1ZSA9ICRpbnB1dC52YWwoKTtcbiAgICAgICAgaWYgKHZhbHVlKSB7XG4gICAgICAgICAgJGZvcm1Hcm91cC5yZW1vdmVDbGFzcyhcImlzLWVtcHR5XCIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICRmb3JtR3JvdXAuYWRkQ2xhc3MoXCJpcy1lbXB0eVwiKTtcbiAgICAgICAgfVxuICAgICAgfSlcbiAgICAgIC8vIHNldCB0aGUgZmlsZWlucHV0IHJlYWRvbmx5IGZpZWxkIHdpdGggdGhlIG5hbWUgb2YgdGhlIGZpbGVcbiAgICAgIC5vbihcImNoYW5nZVwiLCBcIi5mb3JtLWdyb3VwLmlzLWZpbGVpbnB1dCBpbnB1dFt0eXBlPSdmaWxlJ11cIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciAkaW5wdXQgPSAkKHRoaXMpO1xuICAgICAgICB2YXIgJGZvcm1Hcm91cCA9ICRpbnB1dC5jbG9zZXN0KFwiLmZvcm0tZ3JvdXBcIik7XG4gICAgICAgIHZhciB2YWx1ZSA9IFwiXCI7XG4gICAgICAgICQuZWFjaCh0aGlzLmZpbGVzLCBmdW5jdGlvbihpLCBmaWxlKSB7XG4gICAgICAgICAgdmFsdWUgKz0gZmlsZS5uYW1lICsgXCIsIFwiO1xuICAgICAgICB9KTtcbiAgICAgICAgdmFsdWUgPSB2YWx1ZS5zdWJzdHJpbmcoMCwgdmFsdWUubGVuZ3RoIC0gMik7XG4gICAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICAgICRmb3JtR3JvdXAucmVtb3ZlQ2xhc3MoXCJpcy1lbXB0eVwiKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAkZm9ybUdyb3VwLmFkZENsYXNzKFwiaXMtZW1wdHlcIik7XG4gICAgICAgIH1cbiAgICAgICAgJGZvcm1Hcm91cC5maW5kKFwiaW5wdXQuZm9ybS1jb250cm9sW3JlYWRvbmx5XVwiKS52YWwodmFsdWUpO1xuICAgICAgfSk7XG4gICAgfSxcbiAgICBcInJpcHBsZXNcIjogZnVuY3Rpb24oc2VsZWN0b3IpIHtcbiAgICAgICQoKHNlbGVjdG9yKSA/IHNlbGVjdG9yIDogdGhpcy5vcHRpb25zLndpdGhSaXBwbGVzKS5yaXBwbGVzKCk7XG4gICAgfSxcbiAgICBcImF1dG9maWxsXCI6IGZ1bmN0aW9uKCkge1xuICAgICAgLy8gVGhpcyBwYXJ0IG9mIGNvZGUgd2lsbCBkZXRlY3QgYXV0b2ZpbGwgd2hlbiB0aGUgcGFnZSBpcyBsb2FkaW5nICh1c2VybmFtZSBhbmQgcGFzc3dvcmQgaW5wdXRzIGZvciBleGFtcGxlKVxuICAgICAgdmFyIGxvYWRpbmcgPSBzZXRJbnRlcnZhbChmdW5jdGlvbigpIHtcbiAgICAgICAgJChcImlucHV0W3R5cGUhPWNoZWNrYm94XVwiKS5lYWNoKGZ1bmN0aW9uKCkge1xuICAgICAgICAgIHZhciAkdGhpcyA9ICQodGhpcyk7XG4gICAgICAgICAgaWYgKCR0aGlzLnZhbCgpICYmICR0aGlzLnZhbCgpICE9PSAkdGhpcy5hdHRyKFwidmFsdWVcIikpIHtcbiAgICAgICAgICAgICR0aGlzLnRyaWdnZXIoXCJjaGFuZ2VcIik7XG4gICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgIH0sIDEwMCk7XG5cbiAgICAgIC8vIEFmdGVyIDEwIHNlY29uZHMgd2UgYXJlIHF1aXRlIHN1cmUgYWxsIHRoZSBuZWVkZWQgaW5wdXRzIGFyZSBhdXRvZmlsbGVkIHRoZW4gd2UgY2FuIHN0b3AgY2hlY2tpbmcgdGhlbVxuICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbChsb2FkaW5nKTtcbiAgICAgIH0sIDEwMDAwKTtcbiAgICB9LFxuICAgIFwiYXR0YWNoQXV0b2ZpbGxFdmVudEhhbmRsZXJzXCI6IGZ1bmN0aW9uKCkge1xuICAgICAgLy8gTGlzdGVuIG9uIGlucHV0cyBvZiB0aGUgZm9jdXNlZCBmb3JtIChiZWNhdXNlIHVzZXIgY2FuIHNlbGVjdCBmcm9tIHRoZSBhdXRvZmlsbCBkcm9wZG93biBvbmx5IHdoZW4gdGhlIGlucHV0IGhhcyBmb2N1cylcbiAgICAgIHZhciBmb2N1c2VkO1xuICAgICAgJChkb2N1bWVudClcbiAgICAgIC5vbihcImZvY3VzXCIsIFwiaW5wdXRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciAkaW5wdXRzID0gJCh0aGlzKS5wYXJlbnRzKFwiZm9ybVwiKS5maW5kKFwiaW5wdXRcIikubm90KFwiW3R5cGU9ZmlsZV1cIik7XG4gICAgICAgIGZvY3VzZWQgPSBzZXRJbnRlcnZhbChmdW5jdGlvbigpIHtcbiAgICAgICAgICAkaW5wdXRzLmVhY2goZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgJHRoaXMgPSAkKHRoaXMpO1xuICAgICAgICAgICAgaWYgKCR0aGlzLnZhbCgpICE9PSAkdGhpcy5hdHRyKFwidmFsdWVcIikpIHtcbiAgICAgICAgICAgICAgJHRoaXMudHJpZ2dlcihcImNoYW5nZVwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9KTtcbiAgICAgICAgfSwgMTAwKTtcbiAgICAgIH0pXG4gICAgICAub24oXCJibHVyXCIsIFwiLmZvcm0tZ3JvdXAgaW5wdXRcIiwgZnVuY3Rpb24oKSB7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwoZm9jdXNlZCk7XG4gICAgICB9KTtcbiAgICB9LFxuICAgIFwiaW5pdFwiOiBmdW5jdGlvbigpIHtcbiAgICAgIHZhciAkZG9jdW1lbnQgPSAkKGRvY3VtZW50KTtcblxuICAgICAgaWYgKCQuZm4ucmlwcGxlcyAmJiB0aGlzLm9wdGlvbnMucmlwcGxlcykge1xuICAgICAgICB0aGlzLnJpcHBsZXMoKTtcbiAgICAgIH1cbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuaW5wdXQpIHtcbiAgICAgICAgdGhpcy5pbnB1dCgpO1xuICAgICAgICB0aGlzLmF0dGFjaElucHV0RXZlbnRIYW5kbGVycygpO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5jaGVja2JveCkge1xuICAgICAgICB0aGlzLmNoZWNrYm94KCk7XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5vcHRpb25zLnRvZ2dsZWJ1dHRvbikge1xuICAgICAgICB0aGlzLnRvZ2dsZWJ1dHRvbigpO1xuICAgICAgfVxuICAgICAgaWYgKHRoaXMub3B0aW9ucy5yYWRpbykge1xuICAgICAgICB0aGlzLnJhZGlvKCk7XG4gICAgICB9XG4gICAgICBpZiAodGhpcy5vcHRpb25zLmF1dG9maWxsKSB7XG4gICAgICAgIHRoaXMuYXV0b2ZpbGwoKTtcbiAgICAgICAgdGhpcy5hdHRhY2hBdXRvZmlsbEV2ZW50SGFuZGxlcnMoKTtcbiAgICAgIH1cblxuICAgICAgaWYgKGRvY3VtZW50LmFycml2ZSAmJiB0aGlzLm9wdGlvbnMuYXJyaXZlKSB7XG4gICAgICAgIGlmICgkLmZuLnJpcHBsZXMgJiYgdGhpcy5vcHRpb25zLnJpcHBsZXMpIHtcbiAgICAgICAgICAkZG9jdW1lbnQuYXJyaXZlKHRoaXMub3B0aW9ucy53aXRoUmlwcGxlcywgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAkLm1hdGVyaWFsLnJpcHBsZXMoJCh0aGlzKSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5pbnB1dCkge1xuICAgICAgICAgICRkb2N1bWVudC5hcnJpdmUodGhpcy5vcHRpb25zLmlucHV0RWxlbWVudHMsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgJC5tYXRlcmlhbC5pbnB1dCgkKHRoaXMpKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLmNoZWNrYm94KSB7XG4gICAgICAgICAgJGRvY3VtZW50LmFycml2ZSh0aGlzLm9wdGlvbnMuY2hlY2tib3hFbGVtZW50cywgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAkLm1hdGVyaWFsLmNoZWNrYm94KCQodGhpcykpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMucmFkaW8pIHtcbiAgICAgICAgICAkZG9jdW1lbnQuYXJyaXZlKHRoaXMub3B0aW9ucy5yYWRpb0VsZW1lbnRzLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICQubWF0ZXJpYWwucmFkaW8oJCh0aGlzKSk7XG4gICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy50b2dnbGVidXR0b24pIHtcbiAgICAgICAgICAkZG9jdW1lbnQuYXJyaXZlKHRoaXMub3B0aW9ucy50b2dnbGVidXR0b25FbGVtZW50cywgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAkLm1hdGVyaWFsLnRvZ2dsZWJ1dHRvbigkKHRoaXMpKTtcbiAgICAgICAgICB9KTtcbiAgICAgICAgfVxuXG4gICAgICB9XG4gICAgfVxuICB9O1xuXG59KShqUXVlcnkpO1xuIiwiLyogQ29weXJpZ2h0IDIwMTQrLCBGZWRlcmljbyBaaXZvbG8sIExJQ0VOU0UgYXQgaHR0cHM6Ly9naXRodWIuY29tL0ZlelZyYXN0YS9ib290c3RyYXAtbWF0ZXJpYWwtZGVzaWduL2Jsb2IvbWFzdGVyL0xJQ0VOU0UubWQgKi9cbi8qIGdsb2JhbHMgalF1ZXJ5LCBuYXZpZ2F0b3IgKi9cblxuKGZ1bmN0aW9uKCQsIHdpbmRvdywgZG9jdW1lbnQsIHVuZGVmaW5lZCkge1xuXG4gIFwidXNlIHN0cmljdFwiO1xuXG4gIC8qKlxuICAgKiBEZWZpbmUgdGhlIG5hbWUgb2YgdGhlIHBsdWdpblxuICAgKi9cbiAgdmFyIHJpcHBsZXMgPSBcInJpcHBsZXNcIjtcblxuXG4gIC8qKlxuICAgKiBHZXQgYW4gaW5zdGFuY2Ugb2YgdGhlIHBsdWdpblxuICAgKi9cbiAgdmFyIHNlbGYgPSBudWxsO1xuXG5cbiAgLyoqXG4gICAqIERlZmluZSB0aGUgZGVmYXVsdHMgb2YgdGhlIHBsdWdpblxuICAgKi9cbiAgdmFyIGRlZmF1bHRzID0ge307XG5cblxuICAvKipcbiAgICogQ3JlYXRlIHRoZSBtYWluIHBsdWdpbiBmdW5jdGlvblxuICAgKi9cbiAgZnVuY3Rpb24gUmlwcGxlcyhlbGVtZW50LCBvcHRpb25zKSB7XG4gICAgc2VsZiA9IHRoaXM7XG5cbiAgICB0aGlzLmVsZW1lbnQgPSAkKGVsZW1lbnQpO1xuXG4gICAgdGhpcy5vcHRpb25zID0gJC5leHRlbmQoe30sIGRlZmF1bHRzLCBvcHRpb25zKTtcblxuICAgIHRoaXMuX2RlZmF1bHRzID0gZGVmYXVsdHM7XG4gICAgdGhpcy5fbmFtZSA9IHJpcHBsZXM7XG5cbiAgICB0aGlzLmluaXQoKTtcbiAgfVxuXG5cbiAgLyoqXG4gICAqIEluaXRpYWxpemUgdGhlIHBsdWdpblxuICAgKi9cbiAgUmlwcGxlcy5wcm90b3R5cGUuaW5pdCA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciAkZWxlbWVudCAgPSB0aGlzLmVsZW1lbnQ7XG5cbiAgICAkZWxlbWVudC5vbihcIm1vdXNlZG93biB0b3VjaHN0YXJ0XCIsIGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICAvKipcbiAgICAgICAqIFZlcmlmeSBpZiB0aGUgdXNlciBpcyBqdXN0IHRvdWNoaW5nIG9uIGEgZGV2aWNlIGFuZCByZXR1cm4gaWYgc29cbiAgICAgICAqL1xuICAgICAgaWYoc2VsZi5pc1RvdWNoKCkgJiYgZXZlbnQudHlwZSA9PT0gXCJtb3VzZWRvd25cIikge1xuICAgICAgICByZXR1cm47XG4gICAgICB9XG5cblxuICAgICAgLyoqXG4gICAgICAgKiBWZXJpZnkgaWYgdGhlIGN1cnJlbnQgZWxlbWVudCBhbHJlYWR5IGhhcyBhIHJpcHBsZSB3cmFwcGVyIGVsZW1lbnQgYW5kXG4gICAgICAgKiBjcmVhdGVzIGlmIGl0IGRvZXNuJ3RcbiAgICAgICAqL1xuICAgICAgaWYoISgkZWxlbWVudC5maW5kKFwiLnJpcHBsZS1jb250YWluZXJcIikubGVuZ3RoKSkge1xuICAgICAgICAkZWxlbWVudC5hcHBlbmQoXCI8ZGl2IGNsYXNzPVxcXCJyaXBwbGUtY29udGFpbmVyXFxcIj48L2Rpdj5cIik7XG4gICAgICB9XG5cblxuICAgICAgLyoqXG4gICAgICAgKiBGaW5kIHRoZSByaXBwbGUgd3JhcHBlclxuICAgICAgICovXG4gICAgICB2YXIgJHdyYXBwZXIgPSAkZWxlbWVudC5jaGlsZHJlbihcIi5yaXBwbGUtY29udGFpbmVyXCIpO1xuXG5cbiAgICAgIC8qKlxuICAgICAgICogR2V0IHJlbFkgYW5kIHJlbFggcG9zaXRpb25zXG4gICAgICAgKi9cbiAgICAgIHZhciByZWxZID0gc2VsZi5nZXRSZWxZKCR3cmFwcGVyLCBldmVudCk7XG4gICAgICB2YXIgcmVsWCA9IHNlbGYuZ2V0UmVsWCgkd3JhcHBlciwgZXZlbnQpO1xuXG5cbiAgICAgIC8qKlxuICAgICAgICogSWYgcmVsWSBhbmQvb3IgcmVsWCBhcmUgZmFsc2UsIHJldHVybiB0aGUgZXZlbnRcbiAgICAgICAqL1xuICAgICAgaWYoIXJlbFkgJiYgIXJlbFgpIHtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG5cbiAgICAgIC8qKlxuICAgICAgICogR2V0IHRoZSByaXBwbGUgY29sb3JcbiAgICAgICAqL1xuICAgICAgdmFyIHJpcHBsZUNvbG9yID0gc2VsZi5nZXRSaXBwbGVzQ29sb3IoJGVsZW1lbnQpO1xuXG5cbiAgICAgIC8qKlxuICAgICAgICogQ3JlYXRlIHRoZSByaXBwbGUgZWxlbWVudFxuICAgICAgICovXG4gICAgICB2YXIgJHJpcHBsZSA9ICQoXCI8ZGl2PjwvZGl2PlwiKTtcblxuICAgICAgJHJpcHBsZVxuICAgICAgLmFkZENsYXNzKFwicmlwcGxlXCIpXG4gICAgICAuY3NzKHtcbiAgICAgICAgXCJsZWZ0XCI6IHJlbFgsXG4gICAgICAgIFwidG9wXCI6IHJlbFksXG4gICAgICAgIFwiYmFja2dyb3VuZC1jb2xvclwiOiByaXBwbGVDb2xvclxuICAgICAgfSk7XG5cblxuICAgICAgLyoqXG4gICAgICAgKiBBcHBlbmQgdGhlIHJpcHBsZSB0byB0aGUgd3JhcHBlclxuICAgICAgICovXG4gICAgICAkd3JhcHBlci5hcHBlbmQoJHJpcHBsZSk7XG5cblxuICAgICAgLyoqXG4gICAgICAgKiBNYWtlIHN1cmUgdGhlIHJpcHBsZSBoYXMgdGhlIHN0eWxlcyBhcHBsaWVkICh1Z2x5IGhhY2sgYnV0IGl0IHdvcmtzKVxuICAgICAgICovXG4gICAgICAoZnVuY3Rpb24oKSB7IHJldHVybiB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSgkcmlwcGxlWzBdKS5vcGFjaXR5OyB9KSgpO1xuXG5cbiAgICAgIC8qKlxuICAgICAgICogVHVybiBvbiB0aGUgcmlwcGxlIGFuaW1hdGlvblxuICAgICAgICovXG4gICAgICBzZWxmLnJpcHBsZU9uKCRlbGVtZW50LCAkcmlwcGxlKTtcblxuXG4gICAgICAvKipcbiAgICAgICAqIENhbGwgdGhlIHJpcHBsZUVuZCBmdW5jdGlvbiB3aGVuIHRoZSB0cmFuc2l0aW9uIFwib25cIiBlbmRzXG4gICAgICAgKi9cbiAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgIHNlbGYucmlwcGxlRW5kKCRyaXBwbGUpO1xuICAgICAgfSwgNTAwKTtcblxuXG4gICAgICAvKipcbiAgICAgICAqIERldGVjdCB3aGVuIHRoZSB1c2VyIGxlYXZlcyB0aGUgZWxlbWVudFxuICAgICAgICovXG4gICAgICAkZWxlbWVudC5vbihcIm1vdXNldXAgbW91c2VsZWF2ZSB0b3VjaGVuZFwiLCBmdW5jdGlvbigpIHtcbiAgICAgICAgJHJpcHBsZS5kYXRhKFwibW91c2Vkb3duXCIsIFwib2ZmXCIpO1xuXG4gICAgICAgIGlmKCRyaXBwbGUuZGF0YShcImFuaW1hdGluZ1wiKSA9PT0gXCJvZmZcIikge1xuICAgICAgICAgIHNlbGYucmlwcGxlT3V0KCRyaXBwbGUpO1xuICAgICAgICB9XG4gICAgICB9KTtcblxuICAgIH0pO1xuICB9O1xuXG5cbiAgLyoqXG4gICAqIEdldCB0aGUgbmV3IHNpemUgYmFzZWQgb24gdGhlIGVsZW1lbnQgaGVpZ2h0L3dpZHRoIGFuZCB0aGUgcmlwcGxlIHdpZHRoXG4gICAqL1xuICBSaXBwbGVzLnByb3RvdHlwZS5nZXROZXdTaXplID0gZnVuY3Rpb24oJGVsZW1lbnQsICRyaXBwbGUpIHtcblxuICAgIHJldHVybiAoTWF0aC5tYXgoJGVsZW1lbnQub3V0ZXJXaWR0aCgpLCAkZWxlbWVudC5vdXRlckhlaWdodCgpKSAvICRyaXBwbGUub3V0ZXJXaWR0aCgpKSAqIDIuNTtcbiAgfTtcblxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHJlbFhcbiAgICovXG4gIFJpcHBsZXMucHJvdG90eXBlLmdldFJlbFggPSBmdW5jdGlvbigkd3JhcHBlciwgIGV2ZW50KSB7XG4gICAgdmFyIHdyYXBwZXJPZmZzZXQgPSAkd3JhcHBlci5vZmZzZXQoKTtcblxuICAgIGlmKCFzZWxmLmlzVG91Y2goKSkge1xuICAgICAgLyoqXG4gICAgICAgKiBHZXQgdGhlIG1vdXNlIHBvc2l0aW9uIHJlbGF0aXZlIHRvIHRoZSByaXBwbGUgd3JhcHBlclxuICAgICAgICovXG4gICAgICByZXR1cm4gZXZlbnQucGFnZVggLSB3cmFwcGVyT2Zmc2V0LmxlZnQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIC8qKlxuICAgICAgICogTWFrZSBzdXJlIHRoZSB1c2VyIGlzIHVzaW5nIG9ubHkgb25lIGZpbmdlciBhbmQgdGhlbiBnZXQgdGhlIHRvdWNoXG4gICAgICAgKiBwb3NpdGlvbiByZWxhdGl2ZSB0byB0aGUgcmlwcGxlIHdyYXBwZXJcbiAgICAgICAqL1xuICAgICAgZXZlbnQgPSBldmVudC5vcmlnaW5hbEV2ZW50O1xuXG4gICAgICBpZihldmVudC50b3VjaGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICByZXR1cm4gZXZlbnQudG91Y2hlc1swXS5wYWdlWCAtIHdyYXBwZXJPZmZzZXQubGVmdDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfTtcblxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHJlbFlcbiAgICovXG4gIFJpcHBsZXMucHJvdG90eXBlLmdldFJlbFkgPSBmdW5jdGlvbigkd3JhcHBlciwgZXZlbnQpIHtcbiAgICB2YXIgd3JhcHBlck9mZnNldCA9ICR3cmFwcGVyLm9mZnNldCgpO1xuXG4gICAgaWYoIXNlbGYuaXNUb3VjaCgpKSB7XG4gICAgICAvKipcbiAgICAgICAqIEdldCB0aGUgbW91c2UgcG9zaXRpb24gcmVsYXRpdmUgdG8gdGhlIHJpcHBsZSB3cmFwcGVyXG4gICAgICAgKi9cbiAgICAgIHJldHVybiBldmVudC5wYWdlWSAtIHdyYXBwZXJPZmZzZXQudG9wO1xuICAgIH0gZWxzZSB7XG4gICAgICAvKipcbiAgICAgICAqIE1ha2Ugc3VyZSB0aGUgdXNlciBpcyB1c2luZyBvbmx5IG9uZSBmaW5nZXIgYW5kIHRoZW4gZ2V0IHRoZSB0b3VjaFxuICAgICAgICogcG9zaXRpb24gcmVsYXRpdmUgdG8gdGhlIHJpcHBsZSB3cmFwcGVyXG4gICAgICAgKi9cbiAgICAgIGV2ZW50ID0gZXZlbnQub3JpZ2luYWxFdmVudDtcblxuICAgICAgaWYoZXZlbnQudG91Y2hlcy5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgcmV0dXJuIGV2ZW50LnRvdWNoZXNbMF0ucGFnZVkgLSB3cmFwcGVyT2Zmc2V0LnRvcDtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgfTtcblxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIHJpcHBsZSBjb2xvclxuICAgKi9cbiAgUmlwcGxlcy5wcm90b3R5cGUuZ2V0UmlwcGxlc0NvbG9yID0gZnVuY3Rpb24oJGVsZW1lbnQpIHtcblxuICAgIHZhciBjb2xvciA9ICRlbGVtZW50LmRhdGEoXCJyaXBwbGUtY29sb3JcIikgPyAkZWxlbWVudC5kYXRhKFwicmlwcGxlLWNvbG9yXCIpIDogd2luZG93LmdldENvbXB1dGVkU3R5bGUoJGVsZW1lbnRbMF0pLmNvbG9yO1xuXG4gICAgcmV0dXJuIGNvbG9yO1xuICB9O1xuXG5cbiAgLyoqXG4gICAqIFZlcmlmeSBpZiB0aGUgY2xpZW50IGJyb3dzZXIgaGFzIHRyYW5zaXN0aW9uIHN1cHBvcnRcbiAgICovXG4gIFJpcHBsZXMucHJvdG90eXBlLmhhc1RyYW5zaXRpb25TdXBwb3J0ID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIHRoaXNCb2R5ICA9IGRvY3VtZW50LmJvZHkgfHwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50O1xuICAgIHZhciB0aGlzU3R5bGUgPSB0aGlzQm9keS5zdHlsZTtcblxuICAgIHZhciBzdXBwb3J0ID0gKFxuICAgICAgdGhpc1N0eWxlLnRyYW5zaXRpb24gIT09IHVuZGVmaW5lZCB8fFxuICAgICAgdGhpc1N0eWxlLldlYmtpdFRyYW5zaXRpb24gIT09IHVuZGVmaW5lZCB8fFxuICAgICAgdGhpc1N0eWxlLk1velRyYW5zaXRpb24gIT09IHVuZGVmaW5lZCB8fFxuICAgICAgdGhpc1N0eWxlLk1zVHJhbnNpdGlvbiAhPT0gdW5kZWZpbmVkIHx8XG4gICAgICB0aGlzU3R5bGUuT1RyYW5zaXRpb24gIT09IHVuZGVmaW5lZFxuICAgICk7XG5cbiAgICByZXR1cm4gc3VwcG9ydDtcbiAgfTtcblxuXG4gIC8qKlxuICAgKiBWZXJpZnkgaWYgdGhlIGNsaWVudCBpcyB1c2luZyBhIG1vYmlsZSBkZXZpY2VcbiAgICovXG4gIFJpcHBsZXMucHJvdG90eXBlLmlzVG91Y2ggPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gL0FuZHJvaWR8d2ViT1N8aVBob25lfGlQYWR8aVBvZHxCbGFja0JlcnJ5fElFTW9iaWxlfE9wZXJhIE1pbmkvaS50ZXN0KG5hdmlnYXRvci51c2VyQWdlbnQpO1xuICB9O1xuXG5cbiAgLyoqXG4gICAqIEVuZCB0aGUgYW5pbWF0aW9uIG9mIHRoZSByaXBwbGVcbiAgICovXG4gIFJpcHBsZXMucHJvdG90eXBlLnJpcHBsZUVuZCA9IGZ1bmN0aW9uKCRyaXBwbGUpIHtcbiAgICAkcmlwcGxlLmRhdGEoXCJhbmltYXRpbmdcIiwgXCJvZmZcIik7XG5cbiAgICBpZigkcmlwcGxlLmRhdGEoXCJtb3VzZWRvd25cIikgPT09IFwib2ZmXCIpIHtcbiAgICAgIHNlbGYucmlwcGxlT3V0KCRyaXBwbGUpO1xuICAgIH1cbiAgfTtcblxuXG4gIC8qKlxuICAgKiBUdXJuIG9mZiB0aGUgcmlwcGxlIGVmZmVjdFxuICAgKi9cbiAgUmlwcGxlcy5wcm90b3R5cGUucmlwcGxlT3V0ID0gZnVuY3Rpb24oJHJpcHBsZSkge1xuICAgICRyaXBwbGUub2ZmKCk7XG5cbiAgICBpZihzZWxmLmhhc1RyYW5zaXRpb25TdXBwb3J0KCkpIHtcbiAgICAgICRyaXBwbGUuYWRkQ2xhc3MoXCJyaXBwbGUtb3V0XCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICAkcmlwcGxlLmFuaW1hdGUoe1wib3BhY2l0eVwiOiAwfSwgMTAwLCBmdW5jdGlvbigpIHtcbiAgICAgICAgJHJpcHBsZS50cmlnZ2VyKFwidHJhbnNpdGlvbmVuZFwiKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgICRyaXBwbGUub24oXCJ0cmFuc2l0aW9uZW5kIHdlYmtpdFRyYW5zaXRpb25FbmQgb1RyYW5zaXRpb25FbmQgTVNUcmFuc2l0aW9uRW5kXCIsIGZ1bmN0aW9uKCkge1xuICAgICAgJHJpcHBsZS5yZW1vdmUoKTtcbiAgICB9KTtcbiAgfTtcblxuXG4gIC8qKlxuICAgKiBUdXJuIG9uIHRoZSByaXBwbGUgZWZmZWN0XG4gICAqL1xuICBSaXBwbGVzLnByb3RvdHlwZS5yaXBwbGVPbiA9IGZ1bmN0aW9uKCRlbGVtZW50LCAkcmlwcGxlKSB7XG4gICAgdmFyIHNpemUgPSBzZWxmLmdldE5ld1NpemUoJGVsZW1lbnQsICRyaXBwbGUpO1xuXG4gICAgaWYoc2VsZi5oYXNUcmFuc2l0aW9uU3VwcG9ydCgpKSB7XG4gICAgICAkcmlwcGxlXG4gICAgICAuY3NzKHtcbiAgICAgICAgXCItbXMtdHJhbnNmb3JtXCI6IFwic2NhbGUoXCIgKyBzaXplICsgXCIpXCIsXG4gICAgICAgIFwiLW1vei10cmFuc2Zvcm1cIjogXCJzY2FsZShcIiArIHNpemUgKyBcIilcIixcbiAgICAgICAgXCItd2Via2l0LXRyYW5zZm9ybVwiOiBcInNjYWxlKFwiICsgc2l6ZSArIFwiKVwiLFxuICAgICAgICBcInRyYW5zZm9ybVwiOiBcInNjYWxlKFwiICsgc2l6ZSArIFwiKVwiXG4gICAgICB9KVxuICAgICAgLmFkZENsYXNzKFwicmlwcGxlLW9uXCIpXG4gICAgICAuZGF0YShcImFuaW1hdGluZ1wiLCBcIm9uXCIpXG4gICAgICAuZGF0YShcIm1vdXNlZG93blwiLCBcIm9uXCIpO1xuICAgIH0gZWxzZSB7XG4gICAgICAkcmlwcGxlLmFuaW1hdGUoe1xuICAgICAgICBcIndpZHRoXCI6IE1hdGgubWF4KCRlbGVtZW50Lm91dGVyV2lkdGgoKSwgJGVsZW1lbnQub3V0ZXJIZWlnaHQoKSkgKiAyLFxuICAgICAgICBcImhlaWdodFwiOiBNYXRoLm1heCgkZWxlbWVudC5vdXRlcldpZHRoKCksICRlbGVtZW50Lm91dGVySGVpZ2h0KCkpICogMixcbiAgICAgICAgXCJtYXJnaW4tbGVmdFwiOiBNYXRoLm1heCgkZWxlbWVudC5vdXRlcldpZHRoKCksICRlbGVtZW50Lm91dGVySGVpZ2h0KCkpICogKC0xKSxcbiAgICAgICAgXCJtYXJnaW4tdG9wXCI6IE1hdGgubWF4KCRlbGVtZW50Lm91dGVyV2lkdGgoKSwgJGVsZW1lbnQub3V0ZXJIZWlnaHQoKSkgKiAoLTEpLFxuICAgICAgICBcIm9wYWNpdHlcIjogMC4yXG4gICAgICB9LCA1MDAsIGZ1bmN0aW9uKCkge1xuICAgICAgICAkcmlwcGxlLnRyaWdnZXIoXCJ0cmFuc2l0aW9uZW5kXCIpO1xuICAgICAgfSk7XG4gICAgfVxuICB9O1xuXG5cbiAgLyoqXG4gICAqIENyZWF0ZSB0aGUganF1ZXJ5IHBsdWdpbiBmdW5jdGlvblxuICAgKi9cbiAgJC5mbi5yaXBwbGVzID0gZnVuY3Rpb24ob3B0aW9ucykge1xuICAgIHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24oKSB7XG4gICAgICBpZighJC5kYXRhKHRoaXMsIFwicGx1Z2luX1wiICsgcmlwcGxlcykpIHtcbiAgICAgICAgJC5kYXRhKHRoaXMsIFwicGx1Z2luX1wiICsgcmlwcGxlcywgbmV3IFJpcHBsZXModGhpcywgb3B0aW9ucykpO1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG59KShqUXVlcnksIHdpbmRvdywgZG9jdW1lbnQpO1xuIiwiLyohXG4gKiBCb290c3RyYXAgdjMuNC4xIChodHRwczovL2dldGJvb3RzdHJhcC5jb20vKVxuICogQ29weXJpZ2h0IDIwMTEtMjAxOSBUd2l0dGVyLCBJbmMuXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2VcbiAqL1xuXG5pZiAodHlwZW9mIGpRdWVyeSA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgdGhyb3cgbmV3IEVycm9yKCdCb290c3RyYXBcXCdzIEphdmFTY3JpcHQgcmVxdWlyZXMgalF1ZXJ5Jylcbn1cblxuK2Z1bmN0aW9uICgkKSB7XG4gICd1c2Ugc3RyaWN0JztcbiAgdmFyIHZlcnNpb24gPSAkLmZuLmpxdWVyeS5zcGxpdCgnICcpWzBdLnNwbGl0KCcuJylcbiAgaWYgKCh2ZXJzaW9uWzBdIDwgMiAmJiB2ZXJzaW9uWzFdIDwgOSkgfHwgKHZlcnNpb25bMF0gPT0gMSAmJiB2ZXJzaW9uWzFdID09IDkgJiYgdmVyc2lvblsyXSA8IDEpIHx8ICh2ZXJzaW9uWzBdID4gMykpIHtcbiAgICB0aHJvdyBuZXcgRXJyb3IoJ0Jvb3RzdHJhcFxcJ3MgSmF2YVNjcmlwdCByZXF1aXJlcyBqUXVlcnkgdmVyc2lvbiAxLjkuMSBvciBoaWdoZXIsIGJ1dCBsb3dlciB0aGFuIHZlcnNpb24gNCcpXG4gIH1cbn0oalF1ZXJ5KTtcblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBCb290c3RyYXA6IHRyYW5zaXRpb24uanMgdjMuNC4xXG4gKiBodHRwczovL2dldGJvb3RzdHJhcC5jb20vZG9jcy8zLjQvamF2YXNjcmlwdC8jdHJhbnNpdGlvbnNcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29weXJpZ2h0IDIwMTEtMjAxOSBUd2l0dGVyLCBJbmMuXG4gKiBMaWNlbnNlZCB1bmRlciBNSVQgKGh0dHBzOi8vZ2l0aHViLmNvbS90d2JzL2Jvb3RzdHJhcC9ibG9iL21hc3Rlci9MSUNFTlNFKVxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cblxuK2Z1bmN0aW9uICgkKSB7XG4gICd1c2Ugc3RyaWN0JztcblxuICAvLyBDU1MgVFJBTlNJVElPTiBTVVBQT1JUIChTaG91dG91dDogaHR0cHM6Ly9tb2Rlcm5penIuY29tLylcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgZnVuY3Rpb24gdHJhbnNpdGlvbkVuZCgpIHtcbiAgICB2YXIgZWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdib290c3RyYXAnKVxuXG4gICAgdmFyIHRyYW5zRW5kRXZlbnROYW1lcyA9IHtcbiAgICAgIFdlYmtpdFRyYW5zaXRpb24gOiAnd2Via2l0VHJhbnNpdGlvbkVuZCcsXG4gICAgICBNb3pUcmFuc2l0aW9uICAgIDogJ3RyYW5zaXRpb25lbmQnLFxuICAgICAgT1RyYW5zaXRpb24gICAgICA6ICdvVHJhbnNpdGlvbkVuZCBvdHJhbnNpdGlvbmVuZCcsXG4gICAgICB0cmFuc2l0aW9uICAgICAgIDogJ3RyYW5zaXRpb25lbmQnXG4gICAgfVxuXG4gICAgZm9yICh2YXIgbmFtZSBpbiB0cmFuc0VuZEV2ZW50TmFtZXMpIHtcbiAgICAgIGlmIChlbC5zdHlsZVtuYW1lXSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgIHJldHVybiB7IGVuZDogdHJhbnNFbmRFdmVudE5hbWVzW25hbWVdIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2UgLy8gZXhwbGljaXQgZm9yIGllOCAoICAuXy4pXG4gIH1cblxuICAvLyBodHRwczovL2Jsb2cuYWxleG1hY2Nhdy5jb20vY3NzLXRyYW5zaXRpb25zXG4gICQuZm4uZW11bGF0ZVRyYW5zaXRpb25FbmQgPSBmdW5jdGlvbiAoZHVyYXRpb24pIHtcbiAgICB2YXIgY2FsbGVkID0gZmFsc2VcbiAgICB2YXIgJGVsID0gdGhpc1xuICAgICQodGhpcykub25lKCdic1RyYW5zaXRpb25FbmQnLCBmdW5jdGlvbiAoKSB7IGNhbGxlZCA9IHRydWUgfSlcbiAgICB2YXIgY2FsbGJhY2sgPSBmdW5jdGlvbiAoKSB7IGlmICghY2FsbGVkKSAkKCRlbCkudHJpZ2dlcigkLnN1cHBvcnQudHJhbnNpdGlvbi5lbmQpIH1cbiAgICBzZXRUaW1lb3V0KGNhbGxiYWNrLCBkdXJhdGlvbilcbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgJChmdW5jdGlvbiAoKSB7XG4gICAgJC5zdXBwb3J0LnRyYW5zaXRpb24gPSB0cmFuc2l0aW9uRW5kKClcblxuICAgIGlmICghJC5zdXBwb3J0LnRyYW5zaXRpb24pIHJldHVyblxuXG4gICAgJC5ldmVudC5zcGVjaWFsLmJzVHJhbnNpdGlvbkVuZCA9IHtcbiAgICAgIGJpbmRUeXBlOiAkLnN1cHBvcnQudHJhbnNpdGlvbi5lbmQsXG4gICAgICBkZWxlZ2F0ZVR5cGU6ICQuc3VwcG9ydC50cmFuc2l0aW9uLmVuZCxcbiAgICAgIGhhbmRsZTogZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgaWYgKCQoZS50YXJnZXQpLmlzKHRoaXMpKSByZXR1cm4gZS5oYW5kbGVPYmouaGFuZGxlci5hcHBseSh0aGlzLCBhcmd1bWVudHMpXG4gICAgICB9XG4gICAgfVxuICB9KVxuXG59KGpRdWVyeSk7XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQm9vdHN0cmFwOiBhbGVydC5qcyB2My40LjFcbiAqIGh0dHBzOi8vZ2V0Ym9vdHN0cmFwLmNvbS9kb2NzLzMuNC9qYXZhc2NyaXB0LyNhbGVydHNcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29weXJpZ2h0IDIwMTEtMjAxOSBUd2l0dGVyLCBJbmMuXG4gKiBMaWNlbnNlZCB1bmRlciBNSVQgKGh0dHBzOi8vZ2l0aHViLmNvbS90d2JzL2Jvb3RzdHJhcC9ibG9iL21hc3Rlci9MSUNFTlNFKVxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cblxuK2Z1bmN0aW9uICgkKSB7XG4gICd1c2Ugc3RyaWN0JztcblxuICAvLyBBTEVSVCBDTEFTUyBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT1cblxuICB2YXIgZGlzbWlzcyA9ICdbZGF0YS1kaXNtaXNzPVwiYWxlcnRcIl0nXG4gIHZhciBBbGVydCAgID0gZnVuY3Rpb24gKGVsKSB7XG4gICAgJChlbCkub24oJ2NsaWNrJywgZGlzbWlzcywgdGhpcy5jbG9zZSlcbiAgfVxuXG4gIEFsZXJ0LlZFUlNJT04gPSAnMy40LjEnXG5cbiAgQWxlcnQuVFJBTlNJVElPTl9EVVJBVElPTiA9IDE1MFxuXG4gIEFsZXJ0LnByb3RvdHlwZS5jbG9zZSA9IGZ1bmN0aW9uIChlKSB7XG4gICAgdmFyICR0aGlzICAgID0gJCh0aGlzKVxuICAgIHZhciBzZWxlY3RvciA9ICR0aGlzLmF0dHIoJ2RhdGEtdGFyZ2V0JylcblxuICAgIGlmICghc2VsZWN0b3IpIHtcbiAgICAgIHNlbGVjdG9yID0gJHRoaXMuYXR0cignaHJlZicpXG4gICAgICBzZWxlY3RvciA9IHNlbGVjdG9yICYmIHNlbGVjdG9yLnJlcGxhY2UoLy4qKD89I1teXFxzXSokKS8sICcnKSAvLyBzdHJpcCBmb3IgaWU3XG4gICAgfVxuXG4gICAgc2VsZWN0b3IgICAgPSBzZWxlY3RvciA9PT0gJyMnID8gW10gOiBzZWxlY3RvclxuICAgIHZhciAkcGFyZW50ID0gJChkb2N1bWVudCkuZmluZChzZWxlY3RvcilcblxuICAgIGlmIChlKSBlLnByZXZlbnREZWZhdWx0KClcblxuICAgIGlmICghJHBhcmVudC5sZW5ndGgpIHtcbiAgICAgICRwYXJlbnQgPSAkdGhpcy5jbG9zZXN0KCcuYWxlcnQnKVxuICAgIH1cblxuICAgICRwYXJlbnQudHJpZ2dlcihlID0gJC5FdmVudCgnY2xvc2UuYnMuYWxlcnQnKSlcblxuICAgIGlmIChlLmlzRGVmYXVsdFByZXZlbnRlZCgpKSByZXR1cm5cblxuICAgICRwYXJlbnQucmVtb3ZlQ2xhc3MoJ2luJylcblxuICAgIGZ1bmN0aW9uIHJlbW92ZUVsZW1lbnQoKSB7XG4gICAgICAvLyBkZXRhY2ggZnJvbSBwYXJlbnQsIGZpcmUgZXZlbnQgdGhlbiBjbGVhbiB1cCBkYXRhXG4gICAgICAkcGFyZW50LmRldGFjaCgpLnRyaWdnZXIoJ2Nsb3NlZC5icy5hbGVydCcpLnJlbW92ZSgpXG4gICAgfVxuXG4gICAgJC5zdXBwb3J0LnRyYW5zaXRpb24gJiYgJHBhcmVudC5oYXNDbGFzcygnZmFkZScpID9cbiAgICAgICRwYXJlbnRcbiAgICAgICAgLm9uZSgnYnNUcmFuc2l0aW9uRW5kJywgcmVtb3ZlRWxlbWVudClcbiAgICAgICAgLmVtdWxhdGVUcmFuc2l0aW9uRW5kKEFsZXJ0LlRSQU5TSVRJT05fRFVSQVRJT04pIDpcbiAgICAgIHJlbW92ZUVsZW1lbnQoKVxuICB9XG5cblxuICAvLyBBTEVSVCBQTFVHSU4gREVGSU5JVElPTlxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIGZ1bmN0aW9uIFBsdWdpbihvcHRpb24pIHtcbiAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkdGhpcyA9ICQodGhpcylcbiAgICAgIHZhciBkYXRhICA9ICR0aGlzLmRhdGEoJ2JzLmFsZXJ0JylcblxuICAgICAgaWYgKCFkYXRhKSAkdGhpcy5kYXRhKCdicy5hbGVydCcsIChkYXRhID0gbmV3IEFsZXJ0KHRoaXMpKSlcbiAgICAgIGlmICh0eXBlb2Ygb3B0aW9uID09ICdzdHJpbmcnKSBkYXRhW29wdGlvbl0uY2FsbCgkdGhpcylcbiAgICB9KVxuICB9XG5cbiAgdmFyIG9sZCA9ICQuZm4uYWxlcnRcblxuICAkLmZuLmFsZXJ0ICAgICAgICAgICAgID0gUGx1Z2luXG4gICQuZm4uYWxlcnQuQ29uc3RydWN0b3IgPSBBbGVydFxuXG5cbiAgLy8gQUxFUlQgTk8gQ09ORkxJQ1RcbiAgLy8gPT09PT09PT09PT09PT09PT1cblxuICAkLmZuLmFsZXJ0Lm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJC5mbi5hbGVydCA9IG9sZFxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuXG4gIC8vIEFMRVJUIERBVEEtQVBJXG4gIC8vID09PT09PT09PT09PT09XG5cbiAgJChkb2N1bWVudCkub24oJ2NsaWNrLmJzLmFsZXJ0LmRhdGEtYXBpJywgZGlzbWlzcywgQWxlcnQucHJvdG90eXBlLmNsb3NlKVxuXG59KGpRdWVyeSk7XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQm9vdHN0cmFwOiBidXR0b24uanMgdjMuNC4xXG4gKiBodHRwczovL2dldGJvb3RzdHJhcC5jb20vZG9jcy8zLjQvamF2YXNjcmlwdC8jYnV0dG9uc1xuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb3B5cmlnaHQgMjAxMS0yMDE5IFR3aXR0ZXIsIEluYy5cbiAqIExpY2Vuc2VkIHVuZGVyIE1JVCAoaHR0cHM6Ly9naXRodWIuY29tL3R3YnMvYm9vdHN0cmFwL2Jsb2IvbWFzdGVyL0xJQ0VOU0UpXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuXG4rZnVuY3Rpb24gKCQpIHtcbiAgJ3VzZSBzdHJpY3QnO1xuXG4gIC8vIEJVVFRPTiBQVUJMSUMgQ0xBU1MgREVGSU5JVElPTlxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICB2YXIgQnV0dG9uID0gZnVuY3Rpb24gKGVsZW1lbnQsIG9wdGlvbnMpIHtcbiAgICB0aGlzLiRlbGVtZW50ICA9ICQoZWxlbWVudClcbiAgICB0aGlzLm9wdGlvbnMgICA9ICQuZXh0ZW5kKHt9LCBCdXR0b24uREVGQVVMVFMsIG9wdGlvbnMpXG4gICAgdGhpcy5pc0xvYWRpbmcgPSBmYWxzZVxuICB9XG5cbiAgQnV0dG9uLlZFUlNJT04gID0gJzMuNC4xJ1xuXG4gIEJ1dHRvbi5ERUZBVUxUUyA9IHtcbiAgICBsb2FkaW5nVGV4dDogJ2xvYWRpbmcuLi4nXG4gIH1cblxuICBCdXR0b24ucHJvdG90eXBlLnNldFN0YXRlID0gZnVuY3Rpb24gKHN0YXRlKSB7XG4gICAgdmFyIGQgICAgPSAnZGlzYWJsZWQnXG4gICAgdmFyICRlbCAgPSB0aGlzLiRlbGVtZW50XG4gICAgdmFyIHZhbCAgPSAkZWwuaXMoJ2lucHV0JykgPyAndmFsJyA6ICdodG1sJ1xuICAgIHZhciBkYXRhID0gJGVsLmRhdGEoKVxuXG4gICAgc3RhdGUgKz0gJ1RleHQnXG5cbiAgICBpZiAoZGF0YS5yZXNldFRleHQgPT0gbnVsbCkgJGVsLmRhdGEoJ3Jlc2V0VGV4dCcsICRlbFt2YWxdKCkpXG5cbiAgICAvLyBwdXNoIHRvIGV2ZW50IGxvb3AgdG8gYWxsb3cgZm9ybXMgdG8gc3VibWl0XG4gICAgc2V0VGltZW91dCgkLnByb3h5KGZ1bmN0aW9uICgpIHtcbiAgICAgICRlbFt2YWxdKGRhdGFbc3RhdGVdID09IG51bGwgPyB0aGlzLm9wdGlvbnNbc3RhdGVdIDogZGF0YVtzdGF0ZV0pXG5cbiAgICAgIGlmIChzdGF0ZSA9PSAnbG9hZGluZ1RleHQnKSB7XG4gICAgICAgIHRoaXMuaXNMb2FkaW5nID0gdHJ1ZVxuICAgICAgICAkZWwuYWRkQ2xhc3MoZCkuYXR0cihkLCBkKS5wcm9wKGQsIHRydWUpXG4gICAgICB9IGVsc2UgaWYgKHRoaXMuaXNMb2FkaW5nKSB7XG4gICAgICAgIHRoaXMuaXNMb2FkaW5nID0gZmFsc2VcbiAgICAgICAgJGVsLnJlbW92ZUNsYXNzKGQpLnJlbW92ZUF0dHIoZCkucHJvcChkLCBmYWxzZSlcbiAgICAgIH1cbiAgICB9LCB0aGlzKSwgMClcbiAgfVxuXG4gIEJ1dHRvbi5wcm90b3R5cGUudG9nZ2xlID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBjaGFuZ2VkID0gdHJ1ZVxuICAgIHZhciAkcGFyZW50ID0gdGhpcy4kZWxlbWVudC5jbG9zZXN0KCdbZGF0YS10b2dnbGU9XCJidXR0b25zXCJdJylcblxuICAgIGlmICgkcGFyZW50Lmxlbmd0aCkge1xuICAgICAgdmFyICRpbnB1dCA9IHRoaXMuJGVsZW1lbnQuZmluZCgnaW5wdXQnKVxuICAgICAgaWYgKCRpbnB1dC5wcm9wKCd0eXBlJykgPT0gJ3JhZGlvJykge1xuICAgICAgICBpZiAoJGlucHV0LnByb3AoJ2NoZWNrZWQnKSkgY2hhbmdlZCA9IGZhbHNlXG4gICAgICAgICRwYXJlbnQuZmluZCgnLmFjdGl2ZScpLnJlbW92ZUNsYXNzKCdhY3RpdmUnKVxuICAgICAgICB0aGlzLiRlbGVtZW50LmFkZENsYXNzKCdhY3RpdmUnKVxuICAgICAgfSBlbHNlIGlmICgkaW5wdXQucHJvcCgndHlwZScpID09ICdjaGVja2JveCcpIHtcbiAgICAgICAgaWYgKCgkaW5wdXQucHJvcCgnY2hlY2tlZCcpKSAhPT0gdGhpcy4kZWxlbWVudC5oYXNDbGFzcygnYWN0aXZlJykpIGNoYW5nZWQgPSBmYWxzZVxuICAgICAgICB0aGlzLiRlbGVtZW50LnRvZ2dsZUNsYXNzKCdhY3RpdmUnKVxuICAgICAgfVxuICAgICAgJGlucHV0LnByb3AoJ2NoZWNrZWQnLCB0aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCdhY3RpdmUnKSlcbiAgICAgIGlmIChjaGFuZ2VkKSAkaW5wdXQudHJpZ2dlcignY2hhbmdlJylcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy4kZWxlbWVudC5hdHRyKCdhcmlhLXByZXNzZWQnLCAhdGhpcy4kZWxlbWVudC5oYXNDbGFzcygnYWN0aXZlJykpXG4gICAgICB0aGlzLiRlbGVtZW50LnRvZ2dsZUNsYXNzKCdhY3RpdmUnKVxuICAgIH1cbiAgfVxuXG5cbiAgLy8gQlVUVE9OIFBMVUdJTiBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIGZ1bmN0aW9uIFBsdWdpbihvcHRpb24pIHtcbiAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkdGhpcyAgID0gJCh0aGlzKVxuICAgICAgdmFyIGRhdGEgICAgPSAkdGhpcy5kYXRhKCdicy5idXR0b24nKVxuICAgICAgdmFyIG9wdGlvbnMgPSB0eXBlb2Ygb3B0aW9uID09ICdvYmplY3QnICYmIG9wdGlvblxuXG4gICAgICBpZiAoIWRhdGEpICR0aGlzLmRhdGEoJ2JzLmJ1dHRvbicsIChkYXRhID0gbmV3IEJ1dHRvbih0aGlzLCBvcHRpb25zKSkpXG5cbiAgICAgIGlmIChvcHRpb24gPT0gJ3RvZ2dsZScpIGRhdGEudG9nZ2xlKClcbiAgICAgIGVsc2UgaWYgKG9wdGlvbikgZGF0YS5zZXRTdGF0ZShvcHRpb24pXG4gICAgfSlcbiAgfVxuXG4gIHZhciBvbGQgPSAkLmZuLmJ1dHRvblxuXG4gICQuZm4uYnV0dG9uICAgICAgICAgICAgID0gUGx1Z2luXG4gICQuZm4uYnV0dG9uLkNvbnN0cnVjdG9yID0gQnV0dG9uXG5cblxuICAvLyBCVVRUT04gTk8gQ09ORkxJQ1RcbiAgLy8gPT09PT09PT09PT09PT09PT09XG5cbiAgJC5mbi5idXR0b24ubm9Db25mbGljdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAkLmZuLmJ1dHRvbiA9IG9sZFxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuXG4gIC8vIEJVVFRPTiBEQVRBLUFQSVxuICAvLyA9PT09PT09PT09PT09PT1cblxuICAkKGRvY3VtZW50KVxuICAgIC5vbignY2xpY2suYnMuYnV0dG9uLmRhdGEtYXBpJywgJ1tkYXRhLXRvZ2dsZV49XCJidXR0b25cIl0nLCBmdW5jdGlvbiAoZSkge1xuICAgICAgdmFyICRidG4gPSAkKGUudGFyZ2V0KS5jbG9zZXN0KCcuYnRuJylcbiAgICAgIFBsdWdpbi5jYWxsKCRidG4sICd0b2dnbGUnKVxuICAgICAgaWYgKCEoJChlLnRhcmdldCkuaXMoJ2lucHV0W3R5cGU9XCJyYWRpb1wiXSwgaW5wdXRbdHlwZT1cImNoZWNrYm94XCJdJykpKSB7XG4gICAgICAgIC8vIFByZXZlbnQgZG91YmxlIGNsaWNrIG9uIHJhZGlvcywgYW5kIHRoZSBkb3VibGUgc2VsZWN0aW9ucyAoc28gY2FuY2VsbGF0aW9uKSBvbiBjaGVja2JveGVzXG4gICAgICAgIGUucHJldmVudERlZmF1bHQoKVxuICAgICAgICAvLyBUaGUgdGFyZ2V0IGNvbXBvbmVudCBzdGlsbCByZWNlaXZlIHRoZSBmb2N1c1xuICAgICAgICBpZiAoJGJ0bi5pcygnaW5wdXQsYnV0dG9uJykpICRidG4udHJpZ2dlcignZm9jdXMnKVxuICAgICAgICBlbHNlICRidG4uZmluZCgnaW5wdXQ6dmlzaWJsZSxidXR0b246dmlzaWJsZScpLmZpcnN0KCkudHJpZ2dlcignZm9jdXMnKVxuICAgICAgfVxuICAgIH0pXG4gICAgLm9uKCdmb2N1cy5icy5idXR0b24uZGF0YS1hcGkgYmx1ci5icy5idXR0b24uZGF0YS1hcGknLCAnW2RhdGEtdG9nZ2xlXj1cImJ1dHRvblwiXScsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAkKGUudGFyZ2V0KS5jbG9zZXN0KCcuYnRuJykudG9nZ2xlQ2xhc3MoJ2ZvY3VzJywgL15mb2N1cyhpbik/JC8udGVzdChlLnR5cGUpKVxuICAgIH0pXG5cbn0oalF1ZXJ5KTtcblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBCb290c3RyYXA6IGNhcm91c2VsLmpzIHYzLjQuMVxuICogaHR0cHM6Ly9nZXRib290c3RyYXAuY29tL2RvY3MvMy40L2phdmFzY3JpcHQvI2Nhcm91c2VsXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvcHlyaWdodCAyMDExLTIwMTkgVHdpdHRlciwgSW5jLlxuICogTGljZW5zZWQgdW5kZXIgTUlUIChodHRwczovL2dpdGh1Yi5jb20vdHdicy9ib290c3RyYXAvYmxvYi9tYXN0ZXIvTElDRU5TRSlcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuXG5cbitmdW5jdGlvbiAoJCkge1xuICAndXNlIHN0cmljdCc7XG5cbiAgLy8gQ0FST1VTRUwgQ0xBU1MgREVGSU5JVElPTlxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgdmFyIENhcm91c2VsID0gZnVuY3Rpb24gKGVsZW1lbnQsIG9wdGlvbnMpIHtcbiAgICB0aGlzLiRlbGVtZW50ICAgID0gJChlbGVtZW50KVxuICAgIHRoaXMuJGluZGljYXRvcnMgPSB0aGlzLiRlbGVtZW50LmZpbmQoJy5jYXJvdXNlbC1pbmRpY2F0b3JzJylcbiAgICB0aGlzLm9wdGlvbnMgICAgID0gb3B0aW9uc1xuICAgIHRoaXMucGF1c2VkICAgICAgPSBudWxsXG4gICAgdGhpcy5zbGlkaW5nICAgICA9IG51bGxcbiAgICB0aGlzLmludGVydmFsICAgID0gbnVsbFxuICAgIHRoaXMuJGFjdGl2ZSAgICAgPSBudWxsXG4gICAgdGhpcy4kaXRlbXMgICAgICA9IG51bGxcblxuICAgIHRoaXMub3B0aW9ucy5rZXlib2FyZCAmJiB0aGlzLiRlbGVtZW50Lm9uKCdrZXlkb3duLmJzLmNhcm91c2VsJywgJC5wcm94eSh0aGlzLmtleWRvd24sIHRoaXMpKVxuXG4gICAgdGhpcy5vcHRpb25zLnBhdXNlID09ICdob3ZlcicgJiYgISgnb250b3VjaHN0YXJ0JyBpbiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQpICYmIHRoaXMuJGVsZW1lbnRcbiAgICAgIC5vbignbW91c2VlbnRlci5icy5jYXJvdXNlbCcsICQucHJveHkodGhpcy5wYXVzZSwgdGhpcykpXG4gICAgICAub24oJ21vdXNlbGVhdmUuYnMuY2Fyb3VzZWwnLCAkLnByb3h5KHRoaXMuY3ljbGUsIHRoaXMpKVxuICB9XG5cbiAgQ2Fyb3VzZWwuVkVSU0lPTiAgPSAnMy40LjEnXG5cbiAgQ2Fyb3VzZWwuVFJBTlNJVElPTl9EVVJBVElPTiA9IDYwMFxuXG4gIENhcm91c2VsLkRFRkFVTFRTID0ge1xuICAgIGludGVydmFsOiA1MDAwLFxuICAgIHBhdXNlOiAnaG92ZXInLFxuICAgIHdyYXA6IHRydWUsXG4gICAga2V5Ym9hcmQ6IHRydWVcbiAgfVxuXG4gIENhcm91c2VsLnByb3RvdHlwZS5rZXlkb3duID0gZnVuY3Rpb24gKGUpIHtcbiAgICBpZiAoL2lucHV0fHRleHRhcmVhL2kudGVzdChlLnRhcmdldC50YWdOYW1lKSkgcmV0dXJuXG4gICAgc3dpdGNoIChlLndoaWNoKSB7XG4gICAgICBjYXNlIDM3OiB0aGlzLnByZXYoKTsgYnJlYWtcbiAgICAgIGNhc2UgMzk6IHRoaXMubmV4dCgpOyBicmVha1xuICAgICAgZGVmYXVsdDogcmV0dXJuXG4gICAgfVxuXG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpXG4gIH1cblxuICBDYXJvdXNlbC5wcm90b3R5cGUuY3ljbGUgPSBmdW5jdGlvbiAoZSkge1xuICAgIGUgfHwgKHRoaXMucGF1c2VkID0gZmFsc2UpXG5cbiAgICB0aGlzLmludGVydmFsICYmIGNsZWFySW50ZXJ2YWwodGhpcy5pbnRlcnZhbClcblxuICAgIHRoaXMub3B0aW9ucy5pbnRlcnZhbFxuICAgICAgJiYgIXRoaXMucGF1c2VkXG4gICAgICAmJiAodGhpcy5pbnRlcnZhbCA9IHNldEludGVydmFsKCQucHJveHkodGhpcy5uZXh0LCB0aGlzKSwgdGhpcy5vcHRpb25zLmludGVydmFsKSlcblxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICBDYXJvdXNlbC5wcm90b3R5cGUuZ2V0SXRlbUluZGV4ID0gZnVuY3Rpb24gKGl0ZW0pIHtcbiAgICB0aGlzLiRpdGVtcyA9IGl0ZW0ucGFyZW50KCkuY2hpbGRyZW4oJy5pdGVtJylcbiAgICByZXR1cm4gdGhpcy4kaXRlbXMuaW5kZXgoaXRlbSB8fCB0aGlzLiRhY3RpdmUpXG4gIH1cblxuICBDYXJvdXNlbC5wcm90b3R5cGUuZ2V0SXRlbUZvckRpcmVjdGlvbiA9IGZ1bmN0aW9uIChkaXJlY3Rpb24sIGFjdGl2ZSkge1xuICAgIHZhciBhY3RpdmVJbmRleCA9IHRoaXMuZ2V0SXRlbUluZGV4KGFjdGl2ZSlcbiAgICB2YXIgd2lsbFdyYXAgPSAoZGlyZWN0aW9uID09ICdwcmV2JyAmJiBhY3RpdmVJbmRleCA9PT0gMClcbiAgICAgICAgICAgICAgICB8fCAoZGlyZWN0aW9uID09ICduZXh0JyAmJiBhY3RpdmVJbmRleCA9PSAodGhpcy4kaXRlbXMubGVuZ3RoIC0gMSkpXG4gICAgaWYgKHdpbGxXcmFwICYmICF0aGlzLm9wdGlvbnMud3JhcCkgcmV0dXJuIGFjdGl2ZVxuICAgIHZhciBkZWx0YSA9IGRpcmVjdGlvbiA9PSAncHJldicgPyAtMSA6IDFcbiAgICB2YXIgaXRlbUluZGV4ID0gKGFjdGl2ZUluZGV4ICsgZGVsdGEpICUgdGhpcy4kaXRlbXMubGVuZ3RoXG4gICAgcmV0dXJuIHRoaXMuJGl0ZW1zLmVxKGl0ZW1JbmRleClcbiAgfVxuXG4gIENhcm91c2VsLnByb3RvdHlwZS50byA9IGZ1bmN0aW9uIChwb3MpIHtcbiAgICB2YXIgdGhhdCAgICAgICAgPSB0aGlzXG4gICAgdmFyIGFjdGl2ZUluZGV4ID0gdGhpcy5nZXRJdGVtSW5kZXgodGhpcy4kYWN0aXZlID0gdGhpcy4kZWxlbWVudC5maW5kKCcuaXRlbS5hY3RpdmUnKSlcblxuICAgIGlmIChwb3MgPiAodGhpcy4kaXRlbXMubGVuZ3RoIC0gMSkgfHwgcG9zIDwgMCkgcmV0dXJuXG5cbiAgICBpZiAodGhpcy5zbGlkaW5nKSAgICAgICByZXR1cm4gdGhpcy4kZWxlbWVudC5vbmUoJ3NsaWQuYnMuY2Fyb3VzZWwnLCBmdW5jdGlvbiAoKSB7IHRoYXQudG8ocG9zKSB9KSAvLyB5ZXMsIFwic2xpZFwiXG4gICAgaWYgKGFjdGl2ZUluZGV4ID09IHBvcykgcmV0dXJuIHRoaXMucGF1c2UoKS5jeWNsZSgpXG5cbiAgICByZXR1cm4gdGhpcy5zbGlkZShwb3MgPiBhY3RpdmVJbmRleCA/ICduZXh0JyA6ICdwcmV2JywgdGhpcy4kaXRlbXMuZXEocG9zKSlcbiAgfVxuXG4gIENhcm91c2VsLnByb3RvdHlwZS5wYXVzZSA9IGZ1bmN0aW9uIChlKSB7XG4gICAgZSB8fCAodGhpcy5wYXVzZWQgPSB0cnVlKVxuXG4gICAgaWYgKHRoaXMuJGVsZW1lbnQuZmluZCgnLm5leHQsIC5wcmV2JykubGVuZ3RoICYmICQuc3VwcG9ydC50cmFuc2l0aW9uKSB7XG4gICAgICB0aGlzLiRlbGVtZW50LnRyaWdnZXIoJC5zdXBwb3J0LnRyYW5zaXRpb24uZW5kKVxuICAgICAgdGhpcy5jeWNsZSh0cnVlKVxuICAgIH1cblxuICAgIHRoaXMuaW50ZXJ2YWwgPSBjbGVhckludGVydmFsKHRoaXMuaW50ZXJ2YWwpXG5cbiAgICByZXR1cm4gdGhpc1xuICB9XG5cbiAgQ2Fyb3VzZWwucHJvdG90eXBlLm5leHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuc2xpZGluZykgcmV0dXJuXG4gICAgcmV0dXJuIHRoaXMuc2xpZGUoJ25leHQnKVxuICB9XG5cbiAgQ2Fyb3VzZWwucHJvdG90eXBlLnByZXYgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuc2xpZGluZykgcmV0dXJuXG4gICAgcmV0dXJuIHRoaXMuc2xpZGUoJ3ByZXYnKVxuICB9XG5cbiAgQ2Fyb3VzZWwucHJvdG90eXBlLnNsaWRlID0gZnVuY3Rpb24gKHR5cGUsIG5leHQpIHtcbiAgICB2YXIgJGFjdGl2ZSAgID0gdGhpcy4kZWxlbWVudC5maW5kKCcuaXRlbS5hY3RpdmUnKVxuICAgIHZhciAkbmV4dCAgICAgPSBuZXh0IHx8IHRoaXMuZ2V0SXRlbUZvckRpcmVjdGlvbih0eXBlLCAkYWN0aXZlKVxuICAgIHZhciBpc0N5Y2xpbmcgPSB0aGlzLmludGVydmFsXG4gICAgdmFyIGRpcmVjdGlvbiA9IHR5cGUgPT0gJ25leHQnID8gJ2xlZnQnIDogJ3JpZ2h0J1xuICAgIHZhciB0aGF0ICAgICAgPSB0aGlzXG5cbiAgICBpZiAoJG5leHQuaGFzQ2xhc3MoJ2FjdGl2ZScpKSByZXR1cm4gKHRoaXMuc2xpZGluZyA9IGZhbHNlKVxuXG4gICAgdmFyIHJlbGF0ZWRUYXJnZXQgPSAkbmV4dFswXVxuICAgIHZhciBzbGlkZUV2ZW50ID0gJC5FdmVudCgnc2xpZGUuYnMuY2Fyb3VzZWwnLCB7XG4gICAgICByZWxhdGVkVGFyZ2V0OiByZWxhdGVkVGFyZ2V0LFxuICAgICAgZGlyZWN0aW9uOiBkaXJlY3Rpb25cbiAgICB9KVxuICAgIHRoaXMuJGVsZW1lbnQudHJpZ2dlcihzbGlkZUV2ZW50KVxuICAgIGlmIChzbGlkZUV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpKSByZXR1cm5cblxuICAgIHRoaXMuc2xpZGluZyA9IHRydWVcblxuICAgIGlzQ3ljbGluZyAmJiB0aGlzLnBhdXNlKClcblxuICAgIGlmICh0aGlzLiRpbmRpY2F0b3JzLmxlbmd0aCkge1xuICAgICAgdGhpcy4kaW5kaWNhdG9ycy5maW5kKCcuYWN0aXZlJykucmVtb3ZlQ2xhc3MoJ2FjdGl2ZScpXG4gICAgICB2YXIgJG5leHRJbmRpY2F0b3IgPSAkKHRoaXMuJGluZGljYXRvcnMuY2hpbGRyZW4oKVt0aGlzLmdldEl0ZW1JbmRleCgkbmV4dCldKVxuICAgICAgJG5leHRJbmRpY2F0b3IgJiYgJG5leHRJbmRpY2F0b3IuYWRkQ2xhc3MoJ2FjdGl2ZScpXG4gICAgfVxuXG4gICAgdmFyIHNsaWRFdmVudCA9ICQuRXZlbnQoJ3NsaWQuYnMuY2Fyb3VzZWwnLCB7IHJlbGF0ZWRUYXJnZXQ6IHJlbGF0ZWRUYXJnZXQsIGRpcmVjdGlvbjogZGlyZWN0aW9uIH0pIC8vIHllcywgXCJzbGlkXCJcbiAgICBpZiAoJC5zdXBwb3J0LnRyYW5zaXRpb24gJiYgdGhpcy4kZWxlbWVudC5oYXNDbGFzcygnc2xpZGUnKSkge1xuICAgICAgJG5leHQuYWRkQ2xhc3ModHlwZSlcbiAgICAgIGlmICh0eXBlb2YgJG5leHQgPT09ICdvYmplY3QnICYmICRuZXh0Lmxlbmd0aCkge1xuICAgICAgICAkbmV4dFswXS5vZmZzZXRXaWR0aCAvLyBmb3JjZSByZWZsb3dcbiAgICAgIH1cbiAgICAgICRhY3RpdmUuYWRkQ2xhc3MoZGlyZWN0aW9uKVxuICAgICAgJG5leHQuYWRkQ2xhc3MoZGlyZWN0aW9uKVxuICAgICAgJGFjdGl2ZVxuICAgICAgICAub25lKCdic1RyYW5zaXRpb25FbmQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgJG5leHQucmVtb3ZlQ2xhc3MoW3R5cGUsIGRpcmVjdGlvbl0uam9pbignICcpKS5hZGRDbGFzcygnYWN0aXZlJylcbiAgICAgICAgICAkYWN0aXZlLnJlbW92ZUNsYXNzKFsnYWN0aXZlJywgZGlyZWN0aW9uXS5qb2luKCcgJykpXG4gICAgICAgICAgdGhhdC5zbGlkaW5nID0gZmFsc2VcbiAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoYXQuJGVsZW1lbnQudHJpZ2dlcihzbGlkRXZlbnQpXG4gICAgICAgICAgfSwgMClcbiAgICAgICAgfSlcbiAgICAgICAgLmVtdWxhdGVUcmFuc2l0aW9uRW5kKENhcm91c2VsLlRSQU5TSVRJT05fRFVSQVRJT04pXG4gICAgfSBlbHNlIHtcbiAgICAgICRhY3RpdmUucmVtb3ZlQ2xhc3MoJ2FjdGl2ZScpXG4gICAgICAkbmV4dC5hZGRDbGFzcygnYWN0aXZlJylcbiAgICAgIHRoaXMuc2xpZGluZyA9IGZhbHNlXG4gICAgICB0aGlzLiRlbGVtZW50LnRyaWdnZXIoc2xpZEV2ZW50KVxuICAgIH1cblxuICAgIGlzQ3ljbGluZyAmJiB0aGlzLmN5Y2xlKClcblxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuXG4gIC8vIENBUk9VU0VMIFBMVUdJTiBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgZnVuY3Rpb24gUGx1Z2luKG9wdGlvbikge1xuICAgIHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgdmFyICR0aGlzICAgPSAkKHRoaXMpXG4gICAgICB2YXIgZGF0YSAgICA9ICR0aGlzLmRhdGEoJ2JzLmNhcm91c2VsJylcbiAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIENhcm91c2VsLkRFRkFVTFRTLCAkdGhpcy5kYXRhKCksIHR5cGVvZiBvcHRpb24gPT0gJ29iamVjdCcgJiYgb3B0aW9uKVxuICAgICAgdmFyIGFjdGlvbiAgPSB0eXBlb2Ygb3B0aW9uID09ICdzdHJpbmcnID8gb3B0aW9uIDogb3B0aW9ucy5zbGlkZVxuXG4gICAgICBpZiAoIWRhdGEpICR0aGlzLmRhdGEoJ2JzLmNhcm91c2VsJywgKGRhdGEgPSBuZXcgQ2Fyb3VzZWwodGhpcywgb3B0aW9ucykpKVxuICAgICAgaWYgKHR5cGVvZiBvcHRpb24gPT0gJ251bWJlcicpIGRhdGEudG8ob3B0aW9uKVxuICAgICAgZWxzZSBpZiAoYWN0aW9uKSBkYXRhW2FjdGlvbl0oKVxuICAgICAgZWxzZSBpZiAob3B0aW9ucy5pbnRlcnZhbCkgZGF0YS5wYXVzZSgpLmN5Y2xlKClcbiAgICB9KVxuICB9XG5cbiAgdmFyIG9sZCA9ICQuZm4uY2Fyb3VzZWxcblxuICAkLmZuLmNhcm91c2VsICAgICAgICAgICAgID0gUGx1Z2luXG4gICQuZm4uY2Fyb3VzZWwuQ29uc3RydWN0b3IgPSBDYXJvdXNlbFxuXG5cbiAgLy8gQ0FST1VTRUwgTk8gQ09ORkxJQ1RcbiAgLy8gPT09PT09PT09PT09PT09PT09PT1cblxuICAkLmZuLmNhcm91c2VsLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJC5mbi5jYXJvdXNlbCA9IG9sZFxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuXG4gIC8vIENBUk9VU0VMIERBVEEtQVBJXG4gIC8vID09PT09PT09PT09PT09PT09XG5cbiAgdmFyIGNsaWNrSGFuZGxlciA9IGZ1bmN0aW9uIChlKSB7XG4gICAgdmFyICR0aGlzICAgPSAkKHRoaXMpXG4gICAgdmFyIGhyZWYgICAgPSAkdGhpcy5hdHRyKCdocmVmJylcbiAgICBpZiAoaHJlZikge1xuICAgICAgaHJlZiA9IGhyZWYucmVwbGFjZSgvLiooPz0jW15cXHNdKyQpLywgJycpIC8vIHN0cmlwIGZvciBpZTdcbiAgICB9XG5cbiAgICB2YXIgdGFyZ2V0ICA9ICR0aGlzLmF0dHIoJ2RhdGEtdGFyZ2V0JykgfHwgaHJlZlxuICAgIHZhciAkdGFyZ2V0ID0gJChkb2N1bWVudCkuZmluZCh0YXJnZXQpXG5cbiAgICBpZiAoISR0YXJnZXQuaGFzQ2xhc3MoJ2Nhcm91c2VsJykpIHJldHVyblxuXG4gICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgJHRhcmdldC5kYXRhKCksICR0aGlzLmRhdGEoKSlcbiAgICB2YXIgc2xpZGVJbmRleCA9ICR0aGlzLmF0dHIoJ2RhdGEtc2xpZGUtdG8nKVxuICAgIGlmIChzbGlkZUluZGV4KSBvcHRpb25zLmludGVydmFsID0gZmFsc2VcblxuICAgIFBsdWdpbi5jYWxsKCR0YXJnZXQsIG9wdGlvbnMpXG5cbiAgICBpZiAoc2xpZGVJbmRleCkge1xuICAgICAgJHRhcmdldC5kYXRhKCdicy5jYXJvdXNlbCcpLnRvKHNsaWRlSW5kZXgpXG4gICAgfVxuXG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpXG4gIH1cblxuICAkKGRvY3VtZW50KVxuICAgIC5vbignY2xpY2suYnMuY2Fyb3VzZWwuZGF0YS1hcGknLCAnW2RhdGEtc2xpZGVdJywgY2xpY2tIYW5kbGVyKVxuICAgIC5vbignY2xpY2suYnMuY2Fyb3VzZWwuZGF0YS1hcGknLCAnW2RhdGEtc2xpZGUtdG9dJywgY2xpY2tIYW5kbGVyKVxuXG4gICQod2luZG93KS5vbignbG9hZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAkKCdbZGF0YS1yaWRlPVwiY2Fyb3VzZWxcIl0nKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkY2Fyb3VzZWwgPSAkKHRoaXMpXG4gICAgICBQbHVnaW4uY2FsbCgkY2Fyb3VzZWwsICRjYXJvdXNlbC5kYXRhKCkpXG4gICAgfSlcbiAgfSlcblxufShqUXVlcnkpO1xuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEJvb3RzdHJhcDogY29sbGFwc2UuanMgdjMuNC4xXG4gKiBodHRwczovL2dldGJvb3RzdHJhcC5jb20vZG9jcy8zLjQvamF2YXNjcmlwdC8jY29sbGFwc2VcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29weXJpZ2h0IDIwMTEtMjAxOSBUd2l0dGVyLCBJbmMuXG4gKiBMaWNlbnNlZCB1bmRlciBNSVQgKGh0dHBzOi8vZ2l0aHViLmNvbS90d2JzL2Jvb3RzdHJhcC9ibG9iL21hc3Rlci9MSUNFTlNFKVxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cbi8qIGpzaGludCBsYXRlZGVmOiBmYWxzZSAqL1xuXG4rZnVuY3Rpb24gKCQpIHtcbiAgJ3VzZSBzdHJpY3QnO1xuXG4gIC8vIENPTExBUFNFIFBVQkxJQyBDTEFTUyBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgdmFyIENvbGxhcHNlID0gZnVuY3Rpb24gKGVsZW1lbnQsIG9wdGlvbnMpIHtcbiAgICB0aGlzLiRlbGVtZW50ICAgICAgPSAkKGVsZW1lbnQpXG4gICAgdGhpcy5vcHRpb25zICAgICAgID0gJC5leHRlbmQoe30sIENvbGxhcHNlLkRFRkFVTFRTLCBvcHRpb25zKVxuICAgIHRoaXMuJHRyaWdnZXIgICAgICA9ICQoJ1tkYXRhLXRvZ2dsZT1cImNvbGxhcHNlXCJdW2hyZWY9XCIjJyArIGVsZW1lbnQuaWQgKyAnXCJdLCcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1tkYXRhLXRvZ2dsZT1cImNvbGxhcHNlXCJdW2RhdGEtdGFyZ2V0PVwiIycgKyBlbGVtZW50LmlkICsgJ1wiXScpXG4gICAgdGhpcy50cmFuc2l0aW9uaW5nID0gbnVsbFxuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5wYXJlbnQpIHtcbiAgICAgIHRoaXMuJHBhcmVudCA9IHRoaXMuZ2V0UGFyZW50KClcbiAgICB9IGVsc2Uge1xuICAgICAgdGhpcy5hZGRBcmlhQW5kQ29sbGFwc2VkQ2xhc3ModGhpcy4kZWxlbWVudCwgdGhpcy4kdHJpZ2dlcilcbiAgICB9XG5cbiAgICBpZiAodGhpcy5vcHRpb25zLnRvZ2dsZSkgdGhpcy50b2dnbGUoKVxuICB9XG5cbiAgQ29sbGFwc2UuVkVSU0lPTiAgPSAnMy40LjEnXG5cbiAgQ29sbGFwc2UuVFJBTlNJVElPTl9EVVJBVElPTiA9IDM1MFxuXG4gIENvbGxhcHNlLkRFRkFVTFRTID0ge1xuICAgIHRvZ2dsZTogdHJ1ZVxuICB9XG5cbiAgQ29sbGFwc2UucHJvdG90eXBlLmRpbWVuc2lvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgaGFzV2lkdGggPSB0aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCd3aWR0aCcpXG4gICAgcmV0dXJuIGhhc1dpZHRoID8gJ3dpZHRoJyA6ICdoZWlnaHQnXG4gIH1cblxuICBDb2xsYXBzZS5wcm90b3R5cGUuc2hvdyA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy50cmFuc2l0aW9uaW5nIHx8IHRoaXMuJGVsZW1lbnQuaGFzQ2xhc3MoJ2luJykpIHJldHVyblxuXG4gICAgdmFyIGFjdGl2ZXNEYXRhXG4gICAgdmFyIGFjdGl2ZXMgPSB0aGlzLiRwYXJlbnQgJiYgdGhpcy4kcGFyZW50LmNoaWxkcmVuKCcucGFuZWwnKS5jaGlsZHJlbignLmluLCAuY29sbGFwc2luZycpXG5cbiAgICBpZiAoYWN0aXZlcyAmJiBhY3RpdmVzLmxlbmd0aCkge1xuICAgICAgYWN0aXZlc0RhdGEgPSBhY3RpdmVzLmRhdGEoJ2JzLmNvbGxhcHNlJylcbiAgICAgIGlmIChhY3RpdmVzRGF0YSAmJiBhY3RpdmVzRGF0YS50cmFuc2l0aW9uaW5nKSByZXR1cm5cbiAgICB9XG5cbiAgICB2YXIgc3RhcnRFdmVudCA9ICQuRXZlbnQoJ3Nob3cuYnMuY29sbGFwc2UnKVxuICAgIHRoaXMuJGVsZW1lbnQudHJpZ2dlcihzdGFydEV2ZW50KVxuICAgIGlmIChzdGFydEV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpKSByZXR1cm5cblxuICAgIGlmIChhY3RpdmVzICYmIGFjdGl2ZXMubGVuZ3RoKSB7XG4gICAgICBQbHVnaW4uY2FsbChhY3RpdmVzLCAnaGlkZScpXG4gICAgICBhY3RpdmVzRGF0YSB8fCBhY3RpdmVzLmRhdGEoJ2JzLmNvbGxhcHNlJywgbnVsbClcbiAgICB9XG5cbiAgICB2YXIgZGltZW5zaW9uID0gdGhpcy5kaW1lbnNpb24oKVxuXG4gICAgdGhpcy4kZWxlbWVudFxuICAgICAgLnJlbW92ZUNsYXNzKCdjb2xsYXBzZScpXG4gICAgICAuYWRkQ2xhc3MoJ2NvbGxhcHNpbmcnKVtkaW1lbnNpb25dKDApXG4gICAgICAuYXR0cignYXJpYS1leHBhbmRlZCcsIHRydWUpXG5cbiAgICB0aGlzLiR0cmlnZ2VyXG4gICAgICAucmVtb3ZlQ2xhc3MoJ2NvbGxhcHNlZCcpXG4gICAgICAuYXR0cignYXJpYS1leHBhbmRlZCcsIHRydWUpXG5cbiAgICB0aGlzLnRyYW5zaXRpb25pbmcgPSAxXG5cbiAgICB2YXIgY29tcGxldGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICB0aGlzLiRlbGVtZW50XG4gICAgICAgIC5yZW1vdmVDbGFzcygnY29sbGFwc2luZycpXG4gICAgICAgIC5hZGRDbGFzcygnY29sbGFwc2UgaW4nKVtkaW1lbnNpb25dKCcnKVxuICAgICAgdGhpcy50cmFuc2l0aW9uaW5nID0gMFxuICAgICAgdGhpcy4kZWxlbWVudFxuICAgICAgICAudHJpZ2dlcignc2hvd24uYnMuY29sbGFwc2UnKVxuICAgIH1cblxuICAgIGlmICghJC5zdXBwb3J0LnRyYW5zaXRpb24pIHJldHVybiBjb21wbGV0ZS5jYWxsKHRoaXMpXG5cbiAgICB2YXIgc2Nyb2xsU2l6ZSA9ICQuY2FtZWxDYXNlKFsnc2Nyb2xsJywgZGltZW5zaW9uXS5qb2luKCctJykpXG5cbiAgICB0aGlzLiRlbGVtZW50XG4gICAgICAub25lKCdic1RyYW5zaXRpb25FbmQnLCAkLnByb3h5KGNvbXBsZXRlLCB0aGlzKSlcbiAgICAgIC5lbXVsYXRlVHJhbnNpdGlvbkVuZChDb2xsYXBzZS5UUkFOU0lUSU9OX0RVUkFUSU9OKVtkaW1lbnNpb25dKHRoaXMuJGVsZW1lbnRbMF1bc2Nyb2xsU2l6ZV0pXG4gIH1cblxuICBDb2xsYXBzZS5wcm90b3R5cGUuaGlkZSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy50cmFuc2l0aW9uaW5nIHx8ICF0aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCdpbicpKSByZXR1cm5cblxuICAgIHZhciBzdGFydEV2ZW50ID0gJC5FdmVudCgnaGlkZS5icy5jb2xsYXBzZScpXG4gICAgdGhpcy4kZWxlbWVudC50cmlnZ2VyKHN0YXJ0RXZlbnQpXG4gICAgaWYgKHN0YXJ0RXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkpIHJldHVyblxuXG4gICAgdmFyIGRpbWVuc2lvbiA9IHRoaXMuZGltZW5zaW9uKClcblxuICAgIHRoaXMuJGVsZW1lbnRbZGltZW5zaW9uXSh0aGlzLiRlbGVtZW50W2RpbWVuc2lvbl0oKSlbMF0ub2Zmc2V0SGVpZ2h0XG5cbiAgICB0aGlzLiRlbGVtZW50XG4gICAgICAuYWRkQ2xhc3MoJ2NvbGxhcHNpbmcnKVxuICAgICAgLnJlbW92ZUNsYXNzKCdjb2xsYXBzZSBpbicpXG4gICAgICAuYXR0cignYXJpYS1leHBhbmRlZCcsIGZhbHNlKVxuXG4gICAgdGhpcy4kdHJpZ2dlclxuICAgICAgLmFkZENsYXNzKCdjb2xsYXBzZWQnKVxuICAgICAgLmF0dHIoJ2FyaWEtZXhwYW5kZWQnLCBmYWxzZSlcblxuICAgIHRoaXMudHJhbnNpdGlvbmluZyA9IDFcblxuICAgIHZhciBjb21wbGV0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHRoaXMudHJhbnNpdGlvbmluZyA9IDBcbiAgICAgIHRoaXMuJGVsZW1lbnRcbiAgICAgICAgLnJlbW92ZUNsYXNzKCdjb2xsYXBzaW5nJylcbiAgICAgICAgLmFkZENsYXNzKCdjb2xsYXBzZScpXG4gICAgICAgIC50cmlnZ2VyKCdoaWRkZW4uYnMuY29sbGFwc2UnKVxuICAgIH1cblxuICAgIGlmICghJC5zdXBwb3J0LnRyYW5zaXRpb24pIHJldHVybiBjb21wbGV0ZS5jYWxsKHRoaXMpXG5cbiAgICB0aGlzLiRlbGVtZW50XG4gICAgICBbZGltZW5zaW9uXSgwKVxuICAgICAgLm9uZSgnYnNUcmFuc2l0aW9uRW5kJywgJC5wcm94eShjb21wbGV0ZSwgdGhpcykpXG4gICAgICAuZW11bGF0ZVRyYW5zaXRpb25FbmQoQ29sbGFwc2UuVFJBTlNJVElPTl9EVVJBVElPTilcbiAgfVxuXG4gIENvbGxhcHNlLnByb3RvdHlwZS50b2dnbGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpc1t0aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCdpbicpID8gJ2hpZGUnIDogJ3Nob3cnXSgpXG4gIH1cblxuICBDb2xsYXBzZS5wcm90b3R5cGUuZ2V0UGFyZW50ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiAkKGRvY3VtZW50KS5maW5kKHRoaXMub3B0aW9ucy5wYXJlbnQpXG4gICAgICAuZmluZCgnW2RhdGEtdG9nZ2xlPVwiY29sbGFwc2VcIl1bZGF0YS1wYXJlbnQ9XCInICsgdGhpcy5vcHRpb25zLnBhcmVudCArICdcIl0nKVxuICAgICAgLmVhY2goJC5wcm94eShmdW5jdGlvbiAoaSwgZWxlbWVudCkge1xuICAgICAgICB2YXIgJGVsZW1lbnQgPSAkKGVsZW1lbnQpXG4gICAgICAgIHRoaXMuYWRkQXJpYUFuZENvbGxhcHNlZENsYXNzKGdldFRhcmdldEZyb21UcmlnZ2VyKCRlbGVtZW50KSwgJGVsZW1lbnQpXG4gICAgICB9LCB0aGlzKSlcbiAgICAgIC5lbmQoKVxuICB9XG5cbiAgQ29sbGFwc2UucHJvdG90eXBlLmFkZEFyaWFBbmRDb2xsYXBzZWRDbGFzcyA9IGZ1bmN0aW9uICgkZWxlbWVudCwgJHRyaWdnZXIpIHtcbiAgICB2YXIgaXNPcGVuID0gJGVsZW1lbnQuaGFzQ2xhc3MoJ2luJylcblxuICAgICRlbGVtZW50LmF0dHIoJ2FyaWEtZXhwYW5kZWQnLCBpc09wZW4pXG4gICAgJHRyaWdnZXJcbiAgICAgIC50b2dnbGVDbGFzcygnY29sbGFwc2VkJywgIWlzT3BlbilcbiAgICAgIC5hdHRyKCdhcmlhLWV4cGFuZGVkJywgaXNPcGVuKVxuICB9XG5cbiAgZnVuY3Rpb24gZ2V0VGFyZ2V0RnJvbVRyaWdnZXIoJHRyaWdnZXIpIHtcbiAgICB2YXIgaHJlZlxuICAgIHZhciB0YXJnZXQgPSAkdHJpZ2dlci5hdHRyKCdkYXRhLXRhcmdldCcpXG4gICAgICB8fCAoaHJlZiA9ICR0cmlnZ2VyLmF0dHIoJ2hyZWYnKSkgJiYgaHJlZi5yZXBsYWNlKC8uKig/PSNbXlxcc10rJCkvLCAnJykgLy8gc3RyaXAgZm9yIGllN1xuXG4gICAgcmV0dXJuICQoZG9jdW1lbnQpLmZpbmQodGFyZ2V0KVxuICB9XG5cblxuICAvLyBDT0xMQVBTRSBQTFVHSU4gREVGSU5JVElPTlxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIGZ1bmN0aW9uIFBsdWdpbihvcHRpb24pIHtcbiAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkdGhpcyAgID0gJCh0aGlzKVxuICAgICAgdmFyIGRhdGEgICAgPSAkdGhpcy5kYXRhKCdicy5jb2xsYXBzZScpXG4gICAgICB2YXIgb3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBDb2xsYXBzZS5ERUZBVUxUUywgJHRoaXMuZGF0YSgpLCB0eXBlb2Ygb3B0aW9uID09ICdvYmplY3QnICYmIG9wdGlvbilcblxuICAgICAgaWYgKCFkYXRhICYmIG9wdGlvbnMudG9nZ2xlICYmIC9zaG93fGhpZGUvLnRlc3Qob3B0aW9uKSkgb3B0aW9ucy50b2dnbGUgPSBmYWxzZVxuICAgICAgaWYgKCFkYXRhKSAkdGhpcy5kYXRhKCdicy5jb2xsYXBzZScsIChkYXRhID0gbmV3IENvbGxhcHNlKHRoaXMsIG9wdGlvbnMpKSlcbiAgICAgIGlmICh0eXBlb2Ygb3B0aW9uID09ICdzdHJpbmcnKSBkYXRhW29wdGlvbl0oKVxuICAgIH0pXG4gIH1cblxuICB2YXIgb2xkID0gJC5mbi5jb2xsYXBzZVxuXG4gICQuZm4uY29sbGFwc2UgICAgICAgICAgICAgPSBQbHVnaW5cbiAgJC5mbi5jb2xsYXBzZS5Db25zdHJ1Y3RvciA9IENvbGxhcHNlXG5cblxuICAvLyBDT0xMQVBTRSBOTyBDT05GTElDVFxuICAvLyA9PT09PT09PT09PT09PT09PT09PVxuXG4gICQuZm4uY29sbGFwc2Uubm9Db25mbGljdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAkLmZuLmNvbGxhcHNlID0gb2xkXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG5cbiAgLy8gQ09MTEFQU0UgREFUQS1BUElcbiAgLy8gPT09PT09PT09PT09PT09PT1cblxuICAkKGRvY3VtZW50KS5vbignY2xpY2suYnMuY29sbGFwc2UuZGF0YS1hcGknLCAnW2RhdGEtdG9nZ2xlPVwiY29sbGFwc2VcIl0nLCBmdW5jdGlvbiAoZSkge1xuICAgIHZhciAkdGhpcyAgID0gJCh0aGlzKVxuXG4gICAgaWYgKCEkdGhpcy5hdHRyKCdkYXRhLXRhcmdldCcpKSBlLnByZXZlbnREZWZhdWx0KClcblxuICAgIHZhciAkdGFyZ2V0ID0gZ2V0VGFyZ2V0RnJvbVRyaWdnZXIoJHRoaXMpXG4gICAgdmFyIGRhdGEgICAgPSAkdGFyZ2V0LmRhdGEoJ2JzLmNvbGxhcHNlJylcbiAgICB2YXIgb3B0aW9uICA9IGRhdGEgPyAndG9nZ2xlJyA6ICR0aGlzLmRhdGEoKVxuXG4gICAgUGx1Z2luLmNhbGwoJHRhcmdldCwgb3B0aW9uKVxuICB9KVxuXG59KGpRdWVyeSk7XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQm9vdHN0cmFwOiBkcm9wZG93bi5qcyB2My40LjFcbiAqIGh0dHBzOi8vZ2V0Ym9vdHN0cmFwLmNvbS9kb2NzLzMuNC9qYXZhc2NyaXB0LyNkcm9wZG93bnNcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29weXJpZ2h0IDIwMTEtMjAxOSBUd2l0dGVyLCBJbmMuXG4gKiBMaWNlbnNlZCB1bmRlciBNSVQgKGh0dHBzOi8vZ2l0aHViLmNvbS90d2JzL2Jvb3RzdHJhcC9ibG9iL21hc3Rlci9MSUNFTlNFKVxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cblxuK2Z1bmN0aW9uICgkKSB7XG4gICd1c2Ugc3RyaWN0JztcblxuICAvLyBEUk9QRE9XTiBDTEFTUyBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICB2YXIgYmFja2Ryb3AgPSAnLmRyb3Bkb3duLWJhY2tkcm9wJ1xuICB2YXIgdG9nZ2xlICAgPSAnW2RhdGEtdG9nZ2xlPVwiZHJvcGRvd25cIl0nXG4gIHZhciBEcm9wZG93biA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gICAgJChlbGVtZW50KS5vbignY2xpY2suYnMuZHJvcGRvd24nLCB0aGlzLnRvZ2dsZSlcbiAgfVxuXG4gIERyb3Bkb3duLlZFUlNJT04gPSAnMy40LjEnXG5cbiAgZnVuY3Rpb24gZ2V0UGFyZW50KCR0aGlzKSB7XG4gICAgdmFyIHNlbGVjdG9yID0gJHRoaXMuYXR0cignZGF0YS10YXJnZXQnKVxuXG4gICAgaWYgKCFzZWxlY3Rvcikge1xuICAgICAgc2VsZWN0b3IgPSAkdGhpcy5hdHRyKCdocmVmJylcbiAgICAgIHNlbGVjdG9yID0gc2VsZWN0b3IgJiYgLyNbQS1aYS16XS8udGVzdChzZWxlY3RvcikgJiYgc2VsZWN0b3IucmVwbGFjZSgvLiooPz0jW15cXHNdKiQpLywgJycpIC8vIHN0cmlwIGZvciBpZTdcbiAgICB9XG5cbiAgICB2YXIgJHBhcmVudCA9IHNlbGVjdG9yICE9PSAnIycgPyAkKGRvY3VtZW50KS5maW5kKHNlbGVjdG9yKSA6IG51bGxcblxuICAgIHJldHVybiAkcGFyZW50ICYmICRwYXJlbnQubGVuZ3RoID8gJHBhcmVudCA6ICR0aGlzLnBhcmVudCgpXG4gIH1cblxuICBmdW5jdGlvbiBjbGVhck1lbnVzKGUpIHtcbiAgICBpZiAoZSAmJiBlLndoaWNoID09PSAzKSByZXR1cm5cbiAgICAkKGJhY2tkcm9wKS5yZW1vdmUoKVxuICAgICQodG9nZ2xlKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkdGhpcyAgICAgICAgID0gJCh0aGlzKVxuICAgICAgdmFyICRwYXJlbnQgICAgICAgPSBnZXRQYXJlbnQoJHRoaXMpXG4gICAgICB2YXIgcmVsYXRlZFRhcmdldCA9IHsgcmVsYXRlZFRhcmdldDogdGhpcyB9XG5cbiAgICAgIGlmICghJHBhcmVudC5oYXNDbGFzcygnb3BlbicpKSByZXR1cm5cblxuICAgICAgaWYgKGUgJiYgZS50eXBlID09ICdjbGljaycgJiYgL2lucHV0fHRleHRhcmVhL2kudGVzdChlLnRhcmdldC50YWdOYW1lKSAmJiAkLmNvbnRhaW5zKCRwYXJlbnRbMF0sIGUudGFyZ2V0KSkgcmV0dXJuXG5cbiAgICAgICRwYXJlbnQudHJpZ2dlcihlID0gJC5FdmVudCgnaGlkZS5icy5kcm9wZG93bicsIHJlbGF0ZWRUYXJnZXQpKVxuXG4gICAgICBpZiAoZS5pc0RlZmF1bHRQcmV2ZW50ZWQoKSkgcmV0dXJuXG5cbiAgICAgICR0aGlzLmF0dHIoJ2FyaWEtZXhwYW5kZWQnLCAnZmFsc2UnKVxuICAgICAgJHBhcmVudC5yZW1vdmVDbGFzcygnb3BlbicpLnRyaWdnZXIoJC5FdmVudCgnaGlkZGVuLmJzLmRyb3Bkb3duJywgcmVsYXRlZFRhcmdldCkpXG4gICAgfSlcbiAgfVxuXG4gIERyb3Bkb3duLnByb3RvdHlwZS50b2dnbGUgPSBmdW5jdGlvbiAoZSkge1xuICAgIHZhciAkdGhpcyA9ICQodGhpcylcblxuICAgIGlmICgkdGhpcy5pcygnLmRpc2FibGVkLCA6ZGlzYWJsZWQnKSkgcmV0dXJuXG5cbiAgICB2YXIgJHBhcmVudCAgPSBnZXRQYXJlbnQoJHRoaXMpXG4gICAgdmFyIGlzQWN0aXZlID0gJHBhcmVudC5oYXNDbGFzcygnb3BlbicpXG5cbiAgICBjbGVhck1lbnVzKClcblxuICAgIGlmICghaXNBY3RpdmUpIHtcbiAgICAgIGlmICgnb250b3VjaHN0YXJ0JyBpbiBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgJiYgISRwYXJlbnQuY2xvc2VzdCgnLm5hdmJhci1uYXYnKS5sZW5ndGgpIHtcbiAgICAgICAgLy8gaWYgbW9iaWxlIHdlIHVzZSBhIGJhY2tkcm9wIGJlY2F1c2UgY2xpY2sgZXZlbnRzIGRvbid0IGRlbGVnYXRlXG4gICAgICAgICQoZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2JykpXG4gICAgICAgICAgLmFkZENsYXNzKCdkcm9wZG93bi1iYWNrZHJvcCcpXG4gICAgICAgICAgLmluc2VydEFmdGVyKCQodGhpcykpXG4gICAgICAgICAgLm9uKCdjbGljaycsIGNsZWFyTWVudXMpXG4gICAgICB9XG5cbiAgICAgIHZhciByZWxhdGVkVGFyZ2V0ID0geyByZWxhdGVkVGFyZ2V0OiB0aGlzIH1cbiAgICAgICRwYXJlbnQudHJpZ2dlcihlID0gJC5FdmVudCgnc2hvdy5icy5kcm9wZG93bicsIHJlbGF0ZWRUYXJnZXQpKVxuXG4gICAgICBpZiAoZS5pc0RlZmF1bHRQcmV2ZW50ZWQoKSkgcmV0dXJuXG5cbiAgICAgICR0aGlzXG4gICAgICAgIC50cmlnZ2VyKCdmb2N1cycpXG4gICAgICAgIC5hdHRyKCdhcmlhLWV4cGFuZGVkJywgJ3RydWUnKVxuXG4gICAgICAkcGFyZW50XG4gICAgICAgIC50b2dnbGVDbGFzcygnb3BlbicpXG4gICAgICAgIC50cmlnZ2VyKCQuRXZlbnQoJ3Nob3duLmJzLmRyb3Bkb3duJywgcmVsYXRlZFRhcmdldCkpXG4gICAgfVxuXG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cblxuICBEcm9wZG93bi5wcm90b3R5cGUua2V5ZG93biA9IGZ1bmN0aW9uIChlKSB7XG4gICAgaWYgKCEvKDM4fDQwfDI3fDMyKS8udGVzdChlLndoaWNoKSB8fCAvaW5wdXR8dGV4dGFyZWEvaS50ZXN0KGUudGFyZ2V0LnRhZ05hbWUpKSByZXR1cm5cblxuICAgIHZhciAkdGhpcyA9ICQodGhpcylcblxuICAgIGUucHJldmVudERlZmF1bHQoKVxuICAgIGUuc3RvcFByb3BhZ2F0aW9uKClcblxuICAgIGlmICgkdGhpcy5pcygnLmRpc2FibGVkLCA6ZGlzYWJsZWQnKSkgcmV0dXJuXG5cbiAgICB2YXIgJHBhcmVudCAgPSBnZXRQYXJlbnQoJHRoaXMpXG4gICAgdmFyIGlzQWN0aXZlID0gJHBhcmVudC5oYXNDbGFzcygnb3BlbicpXG5cbiAgICBpZiAoIWlzQWN0aXZlICYmIGUud2hpY2ggIT0gMjcgfHwgaXNBY3RpdmUgJiYgZS53aGljaCA9PSAyNykge1xuICAgICAgaWYgKGUud2hpY2ggPT0gMjcpICRwYXJlbnQuZmluZCh0b2dnbGUpLnRyaWdnZXIoJ2ZvY3VzJylcbiAgICAgIHJldHVybiAkdGhpcy50cmlnZ2VyKCdjbGljaycpXG4gICAgfVxuXG4gICAgdmFyIGRlc2MgPSAnIGxpOm5vdCguZGlzYWJsZWQpOnZpc2libGUgYSdcbiAgICB2YXIgJGl0ZW1zID0gJHBhcmVudC5maW5kKCcuZHJvcGRvd24tbWVudScgKyBkZXNjKVxuXG4gICAgaWYgKCEkaXRlbXMubGVuZ3RoKSByZXR1cm5cblxuICAgIHZhciBpbmRleCA9ICRpdGVtcy5pbmRleChlLnRhcmdldClcblxuICAgIGlmIChlLndoaWNoID09IDM4ICYmIGluZGV4ID4gMCkgICAgICAgICAgICAgICAgIGluZGV4LS0gICAgICAgICAvLyB1cFxuICAgIGlmIChlLndoaWNoID09IDQwICYmIGluZGV4IDwgJGl0ZW1zLmxlbmd0aCAtIDEpIGluZGV4KysgICAgICAgICAvLyBkb3duXG4gICAgaWYgKCF+aW5kZXgpICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaW5kZXggPSAwXG5cbiAgICAkaXRlbXMuZXEoaW5kZXgpLnRyaWdnZXIoJ2ZvY3VzJylcbiAgfVxuXG5cbiAgLy8gRFJPUERPV04gUExVR0lOIERFRklOSVRJT05cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICBmdW5jdGlvbiBQbHVnaW4ob3B0aW9uKSB7XG4gICAgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgJHRoaXMgPSAkKHRoaXMpXG4gICAgICB2YXIgZGF0YSAgPSAkdGhpcy5kYXRhKCdicy5kcm9wZG93bicpXG5cbiAgICAgIGlmICghZGF0YSkgJHRoaXMuZGF0YSgnYnMuZHJvcGRvd24nLCAoZGF0YSA9IG5ldyBEcm9wZG93bih0aGlzKSkpXG4gICAgICBpZiAodHlwZW9mIG9wdGlvbiA9PSAnc3RyaW5nJykgZGF0YVtvcHRpb25dLmNhbGwoJHRoaXMpXG4gICAgfSlcbiAgfVxuXG4gIHZhciBvbGQgPSAkLmZuLmRyb3Bkb3duXG5cbiAgJC5mbi5kcm9wZG93biAgICAgICAgICAgICA9IFBsdWdpblxuICAkLmZuLmRyb3Bkb3duLkNvbnN0cnVjdG9yID0gRHJvcGRvd25cblxuXG4gIC8vIERST1BET1dOIE5PIENPTkZMSUNUXG4gIC8vID09PT09PT09PT09PT09PT09PT09XG5cbiAgJC5mbi5kcm9wZG93bi5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICQuZm4uZHJvcGRvd24gPSBvbGRcbiAgICByZXR1cm4gdGhpc1xuICB9XG5cblxuICAvLyBBUFBMWSBUTyBTVEFOREFSRCBEUk9QRE9XTiBFTEVNRU5UU1xuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gICQoZG9jdW1lbnQpXG4gICAgLm9uKCdjbGljay5icy5kcm9wZG93bi5kYXRhLWFwaScsIGNsZWFyTWVudXMpXG4gICAgLm9uKCdjbGljay5icy5kcm9wZG93bi5kYXRhLWFwaScsICcuZHJvcGRvd24gZm9ybScsIGZ1bmN0aW9uIChlKSB7IGUuc3RvcFByb3BhZ2F0aW9uKCkgfSlcbiAgICAub24oJ2NsaWNrLmJzLmRyb3Bkb3duLmRhdGEtYXBpJywgdG9nZ2xlLCBEcm9wZG93bi5wcm90b3R5cGUudG9nZ2xlKVxuICAgIC5vbigna2V5ZG93bi5icy5kcm9wZG93bi5kYXRhLWFwaScsIHRvZ2dsZSwgRHJvcGRvd24ucHJvdG90eXBlLmtleWRvd24pXG4gICAgLm9uKCdrZXlkb3duLmJzLmRyb3Bkb3duLmRhdGEtYXBpJywgJy5kcm9wZG93bi1tZW51JywgRHJvcGRvd24ucHJvdG90eXBlLmtleWRvd24pXG5cbn0oalF1ZXJ5KTtcblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBCb290c3RyYXA6IG1vZGFsLmpzIHYzLjQuMVxuICogaHR0cHM6Ly9nZXRib290c3RyYXAuY29tL2RvY3MvMy40L2phdmFzY3JpcHQvI21vZGFsc1xuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb3B5cmlnaHQgMjAxMS0yMDE5IFR3aXR0ZXIsIEluYy5cbiAqIExpY2Vuc2VkIHVuZGVyIE1JVCAoaHR0cHM6Ly9naXRodWIuY29tL3R3YnMvYm9vdHN0cmFwL2Jsb2IvbWFzdGVyL0xJQ0VOU0UpXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuXG4rZnVuY3Rpb24gKCQpIHtcbiAgJ3VzZSBzdHJpY3QnO1xuXG4gIC8vIE1PREFMIENMQVNTIERFRklOSVRJT05cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PVxuXG4gIHZhciBNb2RhbCA9IGZ1bmN0aW9uIChlbGVtZW50LCBvcHRpb25zKSB7XG4gICAgdGhpcy5vcHRpb25zID0gb3B0aW9uc1xuICAgIHRoaXMuJGJvZHkgPSAkKGRvY3VtZW50LmJvZHkpXG4gICAgdGhpcy4kZWxlbWVudCA9ICQoZWxlbWVudClcbiAgICB0aGlzLiRkaWFsb2cgPSB0aGlzLiRlbGVtZW50LmZpbmQoJy5tb2RhbC1kaWFsb2cnKVxuICAgIHRoaXMuJGJhY2tkcm9wID0gbnVsbFxuICAgIHRoaXMuaXNTaG93biA9IG51bGxcbiAgICB0aGlzLm9yaWdpbmFsQm9keVBhZCA9IG51bGxcbiAgICB0aGlzLnNjcm9sbGJhcldpZHRoID0gMFxuICAgIHRoaXMuaWdub3JlQmFja2Ryb3BDbGljayA9IGZhbHNlXG4gICAgdGhpcy5maXhlZENvbnRlbnQgPSAnLm5hdmJhci1maXhlZC10b3AsIC5uYXZiYXItZml4ZWQtYm90dG9tJ1xuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5yZW1vdGUpIHtcbiAgICAgIHRoaXMuJGVsZW1lbnRcbiAgICAgICAgLmZpbmQoJy5tb2RhbC1jb250ZW50JylcbiAgICAgICAgLmxvYWQodGhpcy5vcHRpb25zLnJlbW90ZSwgJC5wcm94eShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgdGhpcy4kZWxlbWVudC50cmlnZ2VyKCdsb2FkZWQuYnMubW9kYWwnKVxuICAgICAgICB9LCB0aGlzKSlcbiAgICB9XG4gIH1cblxuICBNb2RhbC5WRVJTSU9OID0gJzMuNC4xJ1xuXG4gIE1vZGFsLlRSQU5TSVRJT05fRFVSQVRJT04gPSAzMDBcbiAgTW9kYWwuQkFDS0RST1BfVFJBTlNJVElPTl9EVVJBVElPTiA9IDE1MFxuXG4gIE1vZGFsLkRFRkFVTFRTID0ge1xuICAgIGJhY2tkcm9wOiB0cnVlLFxuICAgIGtleWJvYXJkOiB0cnVlLFxuICAgIHNob3c6IHRydWVcbiAgfVxuXG4gIE1vZGFsLnByb3RvdHlwZS50b2dnbGUgPSBmdW5jdGlvbiAoX3JlbGF0ZWRUYXJnZXQpIHtcbiAgICByZXR1cm4gdGhpcy5pc1Nob3duID8gdGhpcy5oaWRlKCkgOiB0aGlzLnNob3coX3JlbGF0ZWRUYXJnZXQpXG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUuc2hvdyA9IGZ1bmN0aW9uIChfcmVsYXRlZFRhcmdldCkge1xuICAgIHZhciB0aGF0ID0gdGhpc1xuICAgIHZhciBlID0gJC5FdmVudCgnc2hvdy5icy5tb2RhbCcsIHsgcmVsYXRlZFRhcmdldDogX3JlbGF0ZWRUYXJnZXQgfSlcblxuICAgIHRoaXMuJGVsZW1lbnQudHJpZ2dlcihlKVxuXG4gICAgaWYgKHRoaXMuaXNTaG93biB8fCBlLmlzRGVmYXVsdFByZXZlbnRlZCgpKSByZXR1cm5cblxuICAgIHRoaXMuaXNTaG93biA9IHRydWVcblxuICAgIHRoaXMuY2hlY2tTY3JvbGxiYXIoKVxuICAgIHRoaXMuc2V0U2Nyb2xsYmFyKClcbiAgICB0aGlzLiRib2R5LmFkZENsYXNzKCdtb2RhbC1vcGVuJylcblxuICAgIHRoaXMuZXNjYXBlKClcbiAgICB0aGlzLnJlc2l6ZSgpXG5cbiAgICB0aGlzLiRlbGVtZW50Lm9uKCdjbGljay5kaXNtaXNzLmJzLm1vZGFsJywgJ1tkYXRhLWRpc21pc3M9XCJtb2RhbFwiXScsICQucHJveHkodGhpcy5oaWRlLCB0aGlzKSlcblxuICAgIHRoaXMuJGRpYWxvZy5vbignbW91c2Vkb3duLmRpc21pc3MuYnMubW9kYWwnLCBmdW5jdGlvbiAoKSB7XG4gICAgICB0aGF0LiRlbGVtZW50Lm9uZSgnbW91c2V1cC5kaXNtaXNzLmJzLm1vZGFsJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgaWYgKCQoZS50YXJnZXQpLmlzKHRoYXQuJGVsZW1lbnQpKSB0aGF0Lmlnbm9yZUJhY2tkcm9wQ2xpY2sgPSB0cnVlXG4gICAgICB9KVxuICAgIH0pXG5cbiAgICB0aGlzLmJhY2tkcm9wKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciB0cmFuc2l0aW9uID0gJC5zdXBwb3J0LnRyYW5zaXRpb24gJiYgdGhhdC4kZWxlbWVudC5oYXNDbGFzcygnZmFkZScpXG5cbiAgICAgIGlmICghdGhhdC4kZWxlbWVudC5wYXJlbnQoKS5sZW5ndGgpIHtcbiAgICAgICAgdGhhdC4kZWxlbWVudC5hcHBlbmRUbyh0aGF0LiRib2R5KSAvLyBkb24ndCBtb3ZlIG1vZGFscyBkb20gcG9zaXRpb25cbiAgICAgIH1cblxuICAgICAgdGhhdC4kZWxlbWVudFxuICAgICAgICAuc2hvdygpXG4gICAgICAgIC5zY3JvbGxUb3AoMClcblxuICAgICAgdGhhdC5hZGp1c3REaWFsb2coKVxuXG4gICAgICBpZiAodHJhbnNpdGlvbikge1xuICAgICAgICB0aGF0LiRlbGVtZW50WzBdLm9mZnNldFdpZHRoIC8vIGZvcmNlIHJlZmxvd1xuICAgICAgfVxuXG4gICAgICB0aGF0LiRlbGVtZW50LmFkZENsYXNzKCdpbicpXG5cbiAgICAgIHRoYXQuZW5mb3JjZUZvY3VzKClcblxuICAgICAgdmFyIGUgPSAkLkV2ZW50KCdzaG93bi5icy5tb2RhbCcsIHsgcmVsYXRlZFRhcmdldDogX3JlbGF0ZWRUYXJnZXQgfSlcblxuICAgICAgdHJhbnNpdGlvbiA/XG4gICAgICAgIHRoYXQuJGRpYWxvZyAvLyB3YWl0IGZvciBtb2RhbCB0byBzbGlkZSBpblxuICAgICAgICAgIC5vbmUoJ2JzVHJhbnNpdGlvbkVuZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHRoYXQuJGVsZW1lbnQudHJpZ2dlcignZm9jdXMnKS50cmlnZ2VyKGUpXG4gICAgICAgICAgfSlcbiAgICAgICAgICAuZW11bGF0ZVRyYW5zaXRpb25FbmQoTW9kYWwuVFJBTlNJVElPTl9EVVJBVElPTikgOlxuICAgICAgICB0aGF0LiRlbGVtZW50LnRyaWdnZXIoJ2ZvY3VzJykudHJpZ2dlcihlKVxuICAgIH0pXG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUuaGlkZSA9IGZ1bmN0aW9uIChlKSB7XG4gICAgaWYgKGUpIGUucHJldmVudERlZmF1bHQoKVxuXG4gICAgZSA9ICQuRXZlbnQoJ2hpZGUuYnMubW9kYWwnKVxuXG4gICAgdGhpcy4kZWxlbWVudC50cmlnZ2VyKGUpXG5cbiAgICBpZiAoIXRoaXMuaXNTaG93biB8fCBlLmlzRGVmYXVsdFByZXZlbnRlZCgpKSByZXR1cm5cblxuICAgIHRoaXMuaXNTaG93biA9IGZhbHNlXG5cbiAgICB0aGlzLmVzY2FwZSgpXG4gICAgdGhpcy5yZXNpemUoKVxuXG4gICAgJChkb2N1bWVudCkub2ZmKCdmb2N1c2luLmJzLm1vZGFsJylcblxuICAgIHRoaXMuJGVsZW1lbnRcbiAgICAgIC5yZW1vdmVDbGFzcygnaW4nKVxuICAgICAgLm9mZignY2xpY2suZGlzbWlzcy5icy5tb2RhbCcpXG4gICAgICAub2ZmKCdtb3VzZXVwLmRpc21pc3MuYnMubW9kYWwnKVxuXG4gICAgdGhpcy4kZGlhbG9nLm9mZignbW91c2Vkb3duLmRpc21pc3MuYnMubW9kYWwnKVxuXG4gICAgJC5zdXBwb3J0LnRyYW5zaXRpb24gJiYgdGhpcy4kZWxlbWVudC5oYXNDbGFzcygnZmFkZScpID9cbiAgICAgIHRoaXMuJGVsZW1lbnRcbiAgICAgICAgLm9uZSgnYnNUcmFuc2l0aW9uRW5kJywgJC5wcm94eSh0aGlzLmhpZGVNb2RhbCwgdGhpcykpXG4gICAgICAgIC5lbXVsYXRlVHJhbnNpdGlvbkVuZChNb2RhbC5UUkFOU0lUSU9OX0RVUkFUSU9OKSA6XG4gICAgICB0aGlzLmhpZGVNb2RhbCgpXG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUuZW5mb3JjZUZvY3VzID0gZnVuY3Rpb24gKCkge1xuICAgICQoZG9jdW1lbnQpXG4gICAgICAub2ZmKCdmb2N1c2luLmJzLm1vZGFsJykgLy8gZ3VhcmQgYWdhaW5zdCBpbmZpbml0ZSBmb2N1cyBsb29wXG4gICAgICAub24oJ2ZvY3VzaW4uYnMubW9kYWwnLCAkLnByb3h5KGZ1bmN0aW9uIChlKSB7XG4gICAgICAgIGlmIChkb2N1bWVudCAhPT0gZS50YXJnZXQgJiZcbiAgICAgICAgICB0aGlzLiRlbGVtZW50WzBdICE9PSBlLnRhcmdldCAmJlxuICAgICAgICAgICF0aGlzLiRlbGVtZW50LmhhcyhlLnRhcmdldCkubGVuZ3RoKSB7XG4gICAgICAgICAgdGhpcy4kZWxlbWVudC50cmlnZ2VyKCdmb2N1cycpXG4gICAgICAgIH1cbiAgICAgIH0sIHRoaXMpKVxuICB9XG5cbiAgTW9kYWwucHJvdG90eXBlLmVzY2FwZSA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5pc1Nob3duICYmIHRoaXMub3B0aW9ucy5rZXlib2FyZCkge1xuICAgICAgdGhpcy4kZWxlbWVudC5vbigna2V5ZG93bi5kaXNtaXNzLmJzLm1vZGFsJywgJC5wcm94eShmdW5jdGlvbiAoZSkge1xuICAgICAgICBlLndoaWNoID09IDI3ICYmIHRoaXMuaGlkZSgpXG4gICAgICB9LCB0aGlzKSlcbiAgICB9IGVsc2UgaWYgKCF0aGlzLmlzU2hvd24pIHtcbiAgICAgIHRoaXMuJGVsZW1lbnQub2ZmKCdrZXlkb3duLmRpc21pc3MuYnMubW9kYWwnKVxuICAgIH1cbiAgfVxuXG4gIE1vZGFsLnByb3RvdHlwZS5yZXNpemUgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuaXNTaG93bikge1xuICAgICAgJCh3aW5kb3cpLm9uKCdyZXNpemUuYnMubW9kYWwnLCAkLnByb3h5KHRoaXMuaGFuZGxlVXBkYXRlLCB0aGlzKSlcbiAgICB9IGVsc2Uge1xuICAgICAgJCh3aW5kb3cpLm9mZigncmVzaXplLmJzLm1vZGFsJylcbiAgICB9XG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUuaGlkZU1vZGFsID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciB0aGF0ID0gdGhpc1xuICAgIHRoaXMuJGVsZW1lbnQuaGlkZSgpXG4gICAgdGhpcy5iYWNrZHJvcChmdW5jdGlvbiAoKSB7XG4gICAgICB0aGF0LiRib2R5LnJlbW92ZUNsYXNzKCdtb2RhbC1vcGVuJylcbiAgICAgIHRoYXQucmVzZXRBZGp1c3RtZW50cygpXG4gICAgICB0aGF0LnJlc2V0U2Nyb2xsYmFyKClcbiAgICAgIHRoYXQuJGVsZW1lbnQudHJpZ2dlcignaGlkZGVuLmJzLm1vZGFsJylcbiAgICB9KVxuICB9XG5cbiAgTW9kYWwucHJvdG90eXBlLnJlbW92ZUJhY2tkcm9wID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuJGJhY2tkcm9wICYmIHRoaXMuJGJhY2tkcm9wLnJlbW92ZSgpXG4gICAgdGhpcy4kYmFja2Ryb3AgPSBudWxsXG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUuYmFja2Ryb3AgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB2YXIgdGhhdCA9IHRoaXNcbiAgICB2YXIgYW5pbWF0ZSA9IHRoaXMuJGVsZW1lbnQuaGFzQ2xhc3MoJ2ZhZGUnKSA/ICdmYWRlJyA6ICcnXG5cbiAgICBpZiAodGhpcy5pc1Nob3duICYmIHRoaXMub3B0aW9ucy5iYWNrZHJvcCkge1xuICAgICAgdmFyIGRvQW5pbWF0ZSA9ICQuc3VwcG9ydC50cmFuc2l0aW9uICYmIGFuaW1hdGVcblxuICAgICAgdGhpcy4kYmFja2Ryb3AgPSAkKGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpKVxuICAgICAgICAuYWRkQ2xhc3MoJ21vZGFsLWJhY2tkcm9wICcgKyBhbmltYXRlKVxuICAgICAgICAuYXBwZW5kVG8odGhpcy4kYm9keSlcblxuICAgICAgdGhpcy4kZWxlbWVudC5vbignY2xpY2suZGlzbWlzcy5icy5tb2RhbCcsICQucHJveHkoZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgaWYgKHRoaXMuaWdub3JlQmFja2Ryb3BDbGljaykge1xuICAgICAgICAgIHRoaXMuaWdub3JlQmFja2Ryb3BDbGljayA9IGZhbHNlXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgaWYgKGUudGFyZ2V0ICE9PSBlLmN1cnJlbnRUYXJnZXQpIHJldHVyblxuICAgICAgICB0aGlzLm9wdGlvbnMuYmFja2Ryb3AgPT0gJ3N0YXRpYydcbiAgICAgICAgICA/IHRoaXMuJGVsZW1lbnRbMF0uZm9jdXMoKVxuICAgICAgICAgIDogdGhpcy5oaWRlKClcbiAgICAgIH0sIHRoaXMpKVxuXG4gICAgICBpZiAoZG9BbmltYXRlKSB0aGlzLiRiYWNrZHJvcFswXS5vZmZzZXRXaWR0aCAvLyBmb3JjZSByZWZsb3dcblxuICAgICAgdGhpcy4kYmFja2Ryb3AuYWRkQ2xhc3MoJ2luJylcblxuICAgICAgaWYgKCFjYWxsYmFjaykgcmV0dXJuXG5cbiAgICAgIGRvQW5pbWF0ZSA/XG4gICAgICAgIHRoaXMuJGJhY2tkcm9wXG4gICAgICAgICAgLm9uZSgnYnNUcmFuc2l0aW9uRW5kJywgY2FsbGJhY2spXG4gICAgICAgICAgLmVtdWxhdGVUcmFuc2l0aW9uRW5kKE1vZGFsLkJBQ0tEUk9QX1RSQU5TSVRJT05fRFVSQVRJT04pIDpcbiAgICAgICAgY2FsbGJhY2soKVxuXG4gICAgfSBlbHNlIGlmICghdGhpcy5pc1Nob3duICYmIHRoaXMuJGJhY2tkcm9wKSB7XG4gICAgICB0aGlzLiRiYWNrZHJvcC5yZW1vdmVDbGFzcygnaW4nKVxuXG4gICAgICB2YXIgY2FsbGJhY2tSZW1vdmUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoYXQucmVtb3ZlQmFja2Ryb3AoKVxuICAgICAgICBjYWxsYmFjayAmJiBjYWxsYmFjaygpXG4gICAgICB9XG4gICAgICAkLnN1cHBvcnQudHJhbnNpdGlvbiAmJiB0aGlzLiRlbGVtZW50Lmhhc0NsYXNzKCdmYWRlJykgP1xuICAgICAgICB0aGlzLiRiYWNrZHJvcFxuICAgICAgICAgIC5vbmUoJ2JzVHJhbnNpdGlvbkVuZCcsIGNhbGxiYWNrUmVtb3ZlKVxuICAgICAgICAgIC5lbXVsYXRlVHJhbnNpdGlvbkVuZChNb2RhbC5CQUNLRFJPUF9UUkFOU0lUSU9OX0RVUkFUSU9OKSA6XG4gICAgICAgIGNhbGxiYWNrUmVtb3ZlKClcblxuICAgIH0gZWxzZSBpZiAoY2FsbGJhY2spIHtcbiAgICAgIGNhbGxiYWNrKClcbiAgICB9XG4gIH1cblxuICAvLyB0aGVzZSBmb2xsb3dpbmcgbWV0aG9kcyBhcmUgdXNlZCB0byBoYW5kbGUgb3ZlcmZsb3dpbmcgbW9kYWxzXG5cbiAgTW9kYWwucHJvdG90eXBlLmhhbmRsZVVwZGF0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmFkanVzdERpYWxvZygpXG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUuYWRqdXN0RGlhbG9nID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBtb2RhbElzT3ZlcmZsb3dpbmcgPSB0aGlzLiRlbGVtZW50WzBdLnNjcm9sbEhlaWdodCA+IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5jbGllbnRIZWlnaHRcblxuICAgIHRoaXMuJGVsZW1lbnQuY3NzKHtcbiAgICAgIHBhZGRpbmdMZWZ0OiAhdGhpcy5ib2R5SXNPdmVyZmxvd2luZyAmJiBtb2RhbElzT3ZlcmZsb3dpbmcgPyB0aGlzLnNjcm9sbGJhcldpZHRoIDogJycsXG4gICAgICBwYWRkaW5nUmlnaHQ6IHRoaXMuYm9keUlzT3ZlcmZsb3dpbmcgJiYgIW1vZGFsSXNPdmVyZmxvd2luZyA/IHRoaXMuc2Nyb2xsYmFyV2lkdGggOiAnJ1xuICAgIH0pXG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUucmVzZXRBZGp1c3RtZW50cyA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLiRlbGVtZW50LmNzcyh7XG4gICAgICBwYWRkaW5nTGVmdDogJycsXG4gICAgICBwYWRkaW5nUmlnaHQ6ICcnXG4gICAgfSlcbiAgfVxuXG4gIE1vZGFsLnByb3RvdHlwZS5jaGVja1Njcm9sbGJhciA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZnVsbFdpbmRvd1dpZHRoID0gd2luZG93LmlubmVyV2lkdGhcbiAgICBpZiAoIWZ1bGxXaW5kb3dXaWR0aCkgeyAvLyB3b3JrYXJvdW5kIGZvciBtaXNzaW5nIHdpbmRvdy5pbm5lcldpZHRoIGluIElFOFxuICAgICAgdmFyIGRvY3VtZW50RWxlbWVudFJlY3QgPSBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KClcbiAgICAgIGZ1bGxXaW5kb3dXaWR0aCA9IGRvY3VtZW50RWxlbWVudFJlY3QucmlnaHQgLSBNYXRoLmFicyhkb2N1bWVudEVsZW1lbnRSZWN0LmxlZnQpXG4gICAgfVxuICAgIHRoaXMuYm9keUlzT3ZlcmZsb3dpbmcgPSBkb2N1bWVudC5ib2R5LmNsaWVudFdpZHRoIDwgZnVsbFdpbmRvd1dpZHRoXG4gICAgdGhpcy5zY3JvbGxiYXJXaWR0aCA9IHRoaXMubWVhc3VyZVNjcm9sbGJhcigpXG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUuc2V0U2Nyb2xsYmFyID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBib2R5UGFkID0gcGFyc2VJbnQoKHRoaXMuJGJvZHkuY3NzKCdwYWRkaW5nLXJpZ2h0JykgfHwgMCksIDEwKVxuICAgIHRoaXMub3JpZ2luYWxCb2R5UGFkID0gZG9jdW1lbnQuYm9keS5zdHlsZS5wYWRkaW5nUmlnaHQgfHwgJydcbiAgICB2YXIgc2Nyb2xsYmFyV2lkdGggPSB0aGlzLnNjcm9sbGJhcldpZHRoXG4gICAgaWYgKHRoaXMuYm9keUlzT3ZlcmZsb3dpbmcpIHtcbiAgICAgIHRoaXMuJGJvZHkuY3NzKCdwYWRkaW5nLXJpZ2h0JywgYm9keVBhZCArIHNjcm9sbGJhcldpZHRoKVxuICAgICAgJCh0aGlzLmZpeGVkQ29udGVudCkuZWFjaChmdW5jdGlvbiAoaW5kZXgsIGVsZW1lbnQpIHtcbiAgICAgICAgdmFyIGFjdHVhbFBhZGRpbmcgPSBlbGVtZW50LnN0eWxlLnBhZGRpbmdSaWdodFxuICAgICAgICB2YXIgY2FsY3VsYXRlZFBhZGRpbmcgPSAkKGVsZW1lbnQpLmNzcygncGFkZGluZy1yaWdodCcpXG4gICAgICAgICQoZWxlbWVudClcbiAgICAgICAgICAuZGF0YSgncGFkZGluZy1yaWdodCcsIGFjdHVhbFBhZGRpbmcpXG4gICAgICAgICAgLmNzcygncGFkZGluZy1yaWdodCcsIHBhcnNlRmxvYXQoY2FsY3VsYXRlZFBhZGRpbmcpICsgc2Nyb2xsYmFyV2lkdGggKyAncHgnKVxuICAgICAgfSlcbiAgICB9XG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUucmVzZXRTY3JvbGxiYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy4kYm9keS5jc3MoJ3BhZGRpbmctcmlnaHQnLCB0aGlzLm9yaWdpbmFsQm9keVBhZClcbiAgICAkKHRoaXMuZml4ZWRDb250ZW50KS5lYWNoKGZ1bmN0aW9uIChpbmRleCwgZWxlbWVudCkge1xuICAgICAgdmFyIHBhZGRpbmcgPSAkKGVsZW1lbnQpLmRhdGEoJ3BhZGRpbmctcmlnaHQnKVxuICAgICAgJChlbGVtZW50KS5yZW1vdmVEYXRhKCdwYWRkaW5nLXJpZ2h0JylcbiAgICAgIGVsZW1lbnQuc3R5bGUucGFkZGluZ1JpZ2h0ID0gcGFkZGluZyA/IHBhZGRpbmcgOiAnJ1xuICAgIH0pXG4gIH1cblxuICBNb2RhbC5wcm90b3R5cGUubWVhc3VyZVNjcm9sbGJhciA9IGZ1bmN0aW9uICgpIHsgLy8gdGh4IHdhbHNoXG4gICAgdmFyIHNjcm9sbERpdiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpXG4gICAgc2Nyb2xsRGl2LmNsYXNzTmFtZSA9ICdtb2RhbC1zY3JvbGxiYXItbWVhc3VyZSdcbiAgICB0aGlzLiRib2R5LmFwcGVuZChzY3JvbGxEaXYpXG4gICAgdmFyIHNjcm9sbGJhcldpZHRoID0gc2Nyb2xsRGl2Lm9mZnNldFdpZHRoIC0gc2Nyb2xsRGl2LmNsaWVudFdpZHRoXG4gICAgdGhpcy4kYm9keVswXS5yZW1vdmVDaGlsZChzY3JvbGxEaXYpXG4gICAgcmV0dXJuIHNjcm9sbGJhcldpZHRoXG4gIH1cblxuXG4gIC8vIE1PREFMIFBMVUdJTiBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgZnVuY3Rpb24gUGx1Z2luKG9wdGlvbiwgX3JlbGF0ZWRUYXJnZXQpIHtcbiAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkdGhpcyA9ICQodGhpcylcbiAgICAgIHZhciBkYXRhID0gJHRoaXMuZGF0YSgnYnMubW9kYWwnKVxuICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgTW9kYWwuREVGQVVMVFMsICR0aGlzLmRhdGEoKSwgdHlwZW9mIG9wdGlvbiA9PSAnb2JqZWN0JyAmJiBvcHRpb24pXG5cbiAgICAgIGlmICghZGF0YSkgJHRoaXMuZGF0YSgnYnMubW9kYWwnLCAoZGF0YSA9IG5ldyBNb2RhbCh0aGlzLCBvcHRpb25zKSkpXG4gICAgICBpZiAodHlwZW9mIG9wdGlvbiA9PSAnc3RyaW5nJykgZGF0YVtvcHRpb25dKF9yZWxhdGVkVGFyZ2V0KVxuICAgICAgZWxzZSBpZiAob3B0aW9ucy5zaG93KSBkYXRhLnNob3coX3JlbGF0ZWRUYXJnZXQpXG4gICAgfSlcbiAgfVxuXG4gIHZhciBvbGQgPSAkLmZuLm1vZGFsXG5cbiAgJC5mbi5tb2RhbCA9IFBsdWdpblxuICAkLmZuLm1vZGFsLkNvbnN0cnVjdG9yID0gTW9kYWxcblxuXG4gIC8vIE1PREFMIE5PIENPTkZMSUNUXG4gIC8vID09PT09PT09PT09PT09PT09XG5cbiAgJC5mbi5tb2RhbC5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICQuZm4ubW9kYWwgPSBvbGRcbiAgICByZXR1cm4gdGhpc1xuICB9XG5cblxuICAvLyBNT0RBTCBEQVRBLUFQSVxuICAvLyA9PT09PT09PT09PT09PVxuXG4gICQoZG9jdW1lbnQpLm9uKCdjbGljay5icy5tb2RhbC5kYXRhLWFwaScsICdbZGF0YS10b2dnbGU9XCJtb2RhbFwiXScsIGZ1bmN0aW9uIChlKSB7XG4gICAgdmFyICR0aGlzID0gJCh0aGlzKVxuICAgIHZhciBocmVmID0gJHRoaXMuYXR0cignaHJlZicpXG4gICAgdmFyIHRhcmdldCA9ICR0aGlzLmF0dHIoJ2RhdGEtdGFyZ2V0JykgfHxcbiAgICAgIChocmVmICYmIGhyZWYucmVwbGFjZSgvLiooPz0jW15cXHNdKyQpLywgJycpKSAvLyBzdHJpcCBmb3IgaWU3XG5cbiAgICB2YXIgJHRhcmdldCA9ICQoZG9jdW1lbnQpLmZpbmQodGFyZ2V0KVxuICAgIHZhciBvcHRpb24gPSAkdGFyZ2V0LmRhdGEoJ2JzLm1vZGFsJykgPyAndG9nZ2xlJyA6ICQuZXh0ZW5kKHsgcmVtb3RlOiAhLyMvLnRlc3QoaHJlZikgJiYgaHJlZiB9LCAkdGFyZ2V0LmRhdGEoKSwgJHRoaXMuZGF0YSgpKVxuXG4gICAgaWYgKCR0aGlzLmlzKCdhJykpIGUucHJldmVudERlZmF1bHQoKVxuXG4gICAgJHRhcmdldC5vbmUoJ3Nob3cuYnMubW9kYWwnLCBmdW5jdGlvbiAoc2hvd0V2ZW50KSB7XG4gICAgICBpZiAoc2hvd0V2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpKSByZXR1cm4gLy8gb25seSByZWdpc3RlciBmb2N1cyByZXN0b3JlciBpZiBtb2RhbCB3aWxsIGFjdHVhbGx5IGdldCBzaG93blxuICAgICAgJHRhcmdldC5vbmUoJ2hpZGRlbi5icy5tb2RhbCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJHRoaXMuaXMoJzp2aXNpYmxlJykgJiYgJHRoaXMudHJpZ2dlcignZm9jdXMnKVxuICAgICAgfSlcbiAgICB9KVxuICAgIFBsdWdpbi5jYWxsKCR0YXJnZXQsIG9wdGlvbiwgdGhpcylcbiAgfSlcblxufShqUXVlcnkpO1xuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEJvb3RzdHJhcDogdG9vbHRpcC5qcyB2My40LjFcbiAqIGh0dHBzOi8vZ2V0Ym9vdHN0cmFwLmNvbS9kb2NzLzMuNC9qYXZhc2NyaXB0LyN0b29sdGlwXG4gKiBJbnNwaXJlZCBieSB0aGUgb3JpZ2luYWwgalF1ZXJ5LnRpcHN5IGJ5IEphc29uIEZyYW1lXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvcHlyaWdodCAyMDExLTIwMTkgVHdpdHRlciwgSW5jLlxuICogTGljZW5zZWQgdW5kZXIgTUlUIChodHRwczovL2dpdGh1Yi5jb20vdHdicy9ib290c3RyYXAvYmxvYi9tYXN0ZXIvTElDRU5TRSlcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuXG4rZnVuY3Rpb24gKCQpIHtcbiAgJ3VzZSBzdHJpY3QnO1xuXG4gIHZhciBESVNBTExPV0VEX0FUVFJJQlVURVMgPSBbJ3Nhbml0aXplJywgJ3doaXRlTGlzdCcsICdzYW5pdGl6ZUZuJ11cblxuICB2YXIgdXJpQXR0cnMgPSBbXG4gICAgJ2JhY2tncm91bmQnLFxuICAgICdjaXRlJyxcbiAgICAnaHJlZicsXG4gICAgJ2l0ZW10eXBlJyxcbiAgICAnbG9uZ2Rlc2MnLFxuICAgICdwb3N0ZXInLFxuICAgICdzcmMnLFxuICAgICd4bGluazpocmVmJ1xuICBdXG5cbiAgdmFyIEFSSUFfQVRUUklCVVRFX1BBVFRFUk4gPSAvXmFyaWEtW1xcdy1dKiQvaVxuXG4gIHZhciBEZWZhdWx0V2hpdGVsaXN0ID0ge1xuICAgIC8vIEdsb2JhbCBhdHRyaWJ1dGVzIGFsbG93ZWQgb24gYW55IHN1cHBsaWVkIGVsZW1lbnQgYmVsb3cuXG4gICAgJyonOiBbJ2NsYXNzJywgJ2RpcicsICdpZCcsICdsYW5nJywgJ3JvbGUnLCBBUklBX0FUVFJJQlVURV9QQVRURVJOXSxcbiAgICBhOiBbJ3RhcmdldCcsICdocmVmJywgJ3RpdGxlJywgJ3JlbCddLFxuICAgIGFyZWE6IFtdLFxuICAgIGI6IFtdLFxuICAgIGJyOiBbXSxcbiAgICBjb2w6IFtdLFxuICAgIGNvZGU6IFtdLFxuICAgIGRpdjogW10sXG4gICAgZW06IFtdLFxuICAgIGhyOiBbXSxcbiAgICBoMTogW10sXG4gICAgaDI6IFtdLFxuICAgIGgzOiBbXSxcbiAgICBoNDogW10sXG4gICAgaDU6IFtdLFxuICAgIGg2OiBbXSxcbiAgICBpOiBbXSxcbiAgICBpbWc6IFsnc3JjJywgJ2FsdCcsICd0aXRsZScsICd3aWR0aCcsICdoZWlnaHQnXSxcbiAgICBsaTogW10sXG4gICAgb2w6IFtdLFxuICAgIHA6IFtdLFxuICAgIHByZTogW10sXG4gICAgczogW10sXG4gICAgc21hbGw6IFtdLFxuICAgIHNwYW46IFtdLFxuICAgIHN1YjogW10sXG4gICAgc3VwOiBbXSxcbiAgICBzdHJvbmc6IFtdLFxuICAgIHU6IFtdLFxuICAgIHVsOiBbXVxuICB9XG5cbiAgLyoqXG4gICAqIEEgcGF0dGVybiB0aGF0IHJlY29nbml6ZXMgYSBjb21tb25seSB1c2VmdWwgc3Vic2V0IG9mIFVSTHMgdGhhdCBhcmUgc2FmZS5cbiAgICpcbiAgICogU2hvdXRvdXQgdG8gQW5ndWxhciA3IGh0dHBzOi8vZ2l0aHViLmNvbS9hbmd1bGFyL2FuZ3VsYXIvYmxvYi83LjIuNC9wYWNrYWdlcy9jb3JlL3NyYy9zYW5pdGl6YXRpb24vdXJsX3Nhbml0aXplci50c1xuICAgKi9cbiAgdmFyIFNBRkVfVVJMX1BBVFRFUk4gPSAvXig/Oig/Omh0dHBzP3xtYWlsdG98ZnRwfHRlbHxmaWxlKTp8W14mOi8/I10qKD86Wy8/I118JCkpL2dpXG5cbiAgLyoqXG4gICAqIEEgcGF0dGVybiB0aGF0IG1hdGNoZXMgc2FmZSBkYXRhIFVSTHMuIE9ubHkgbWF0Y2hlcyBpbWFnZSwgdmlkZW8gYW5kIGF1ZGlvIHR5cGVzLlxuICAgKlxuICAgKiBTaG91dG91dCB0byBBbmd1bGFyIDcgaHR0cHM6Ly9naXRodWIuY29tL2FuZ3VsYXIvYW5ndWxhci9ibG9iLzcuMi40L3BhY2thZ2VzL2NvcmUvc3JjL3Nhbml0aXphdGlvbi91cmxfc2FuaXRpemVyLnRzXG4gICAqL1xuICB2YXIgREFUQV9VUkxfUEFUVEVSTiA9IC9eZGF0YTooPzppbWFnZVxcLyg/OmJtcHxnaWZ8anBlZ3xqcGd8cG5nfHRpZmZ8d2VicCl8dmlkZW9cXC8oPzptcGVnfG1wNHxvZ2d8d2VibSl8YXVkaW9cXC8oPzptcDN8b2dhfG9nZ3xvcHVzKSk7YmFzZTY0LFthLXowLTkrL10rPSokL2lcblxuICBmdW5jdGlvbiBhbGxvd2VkQXR0cmlidXRlKGF0dHIsIGFsbG93ZWRBdHRyaWJ1dGVMaXN0KSB7XG4gICAgdmFyIGF0dHJOYW1lID0gYXR0ci5ub2RlTmFtZS50b0xvd2VyQ2FzZSgpXG5cbiAgICBpZiAoJC5pbkFycmF5KGF0dHJOYW1lLCBhbGxvd2VkQXR0cmlidXRlTGlzdCkgIT09IC0xKSB7XG4gICAgICBpZiAoJC5pbkFycmF5KGF0dHJOYW1lLCB1cmlBdHRycykgIT09IC0xKSB7XG4gICAgICAgIHJldHVybiBCb29sZWFuKGF0dHIubm9kZVZhbHVlLm1hdGNoKFNBRkVfVVJMX1BBVFRFUk4pIHx8IGF0dHIubm9kZVZhbHVlLm1hdGNoKERBVEFfVVJMX1BBVFRFUk4pKVxuICAgICAgfVxuXG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH1cblxuICAgIHZhciByZWdFeHAgPSAkKGFsbG93ZWRBdHRyaWJ1dGVMaXN0KS5maWx0ZXIoZnVuY3Rpb24gKGluZGV4LCB2YWx1ZSkge1xuICAgICAgcmV0dXJuIHZhbHVlIGluc3RhbmNlb2YgUmVnRXhwXG4gICAgfSlcblxuICAgIC8vIENoZWNrIGlmIGEgcmVndWxhciBleHByZXNzaW9uIHZhbGlkYXRlcyB0aGUgYXR0cmlidXRlLlxuICAgIGZvciAodmFyIGkgPSAwLCBsID0gcmVnRXhwLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgaWYgKGF0dHJOYW1lLm1hdGNoKHJlZ0V4cFtpXSkpIHtcbiAgICAgICAgcmV0dXJuIHRydWVcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIGZ1bmN0aW9uIHNhbml0aXplSHRtbCh1bnNhZmVIdG1sLCB3aGl0ZUxpc3QsIHNhbml0aXplRm4pIHtcbiAgICBpZiAodW5zYWZlSHRtbC5sZW5ndGggPT09IDApIHtcbiAgICAgIHJldHVybiB1bnNhZmVIdG1sXG4gICAgfVxuXG4gICAgaWYgKHNhbml0aXplRm4gJiYgdHlwZW9mIHNhbml0aXplRm4gPT09ICdmdW5jdGlvbicpIHtcbiAgICAgIHJldHVybiBzYW5pdGl6ZUZuKHVuc2FmZUh0bWwpXG4gICAgfVxuXG4gICAgLy8gSUUgOCBhbmQgYmVsb3cgZG9uJ3Qgc3VwcG9ydCBjcmVhdGVIVE1MRG9jdW1lbnRcbiAgICBpZiAoIWRvY3VtZW50LmltcGxlbWVudGF0aW9uIHx8ICFkb2N1bWVudC5pbXBsZW1lbnRhdGlvbi5jcmVhdGVIVE1MRG9jdW1lbnQpIHtcbiAgICAgIHJldHVybiB1bnNhZmVIdG1sXG4gICAgfVxuXG4gICAgdmFyIGNyZWF0ZWREb2N1bWVudCA9IGRvY3VtZW50LmltcGxlbWVudGF0aW9uLmNyZWF0ZUhUTUxEb2N1bWVudCgnc2FuaXRpemF0aW9uJylcbiAgICBjcmVhdGVkRG9jdW1lbnQuYm9keS5pbm5lckhUTUwgPSB1bnNhZmVIdG1sXG5cbiAgICB2YXIgd2hpdGVsaXN0S2V5cyA9ICQubWFwKHdoaXRlTGlzdCwgZnVuY3Rpb24gKGVsLCBpKSB7IHJldHVybiBpIH0pXG4gICAgdmFyIGVsZW1lbnRzID0gJChjcmVhdGVkRG9jdW1lbnQuYm9keSkuZmluZCgnKicpXG5cbiAgICBmb3IgKHZhciBpID0gMCwgbGVuID0gZWxlbWVudHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIHZhciBlbCA9IGVsZW1lbnRzW2ldXG4gICAgICB2YXIgZWxOYW1lID0gZWwubm9kZU5hbWUudG9Mb3dlckNhc2UoKVxuXG4gICAgICBpZiAoJC5pbkFycmF5KGVsTmFtZSwgd2hpdGVsaXN0S2V5cykgPT09IC0xKSB7XG4gICAgICAgIGVsLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoZWwpXG5cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cblxuICAgICAgdmFyIGF0dHJpYnV0ZUxpc3QgPSAkLm1hcChlbC5hdHRyaWJ1dGVzLCBmdW5jdGlvbiAoZWwpIHsgcmV0dXJuIGVsIH0pXG4gICAgICB2YXIgd2hpdGVsaXN0ZWRBdHRyaWJ1dGVzID0gW10uY29uY2F0KHdoaXRlTGlzdFsnKiddIHx8IFtdLCB3aGl0ZUxpc3RbZWxOYW1lXSB8fCBbXSlcblxuICAgICAgZm9yICh2YXIgaiA9IDAsIGxlbjIgPSBhdHRyaWJ1dGVMaXN0Lmxlbmd0aDsgaiA8IGxlbjI7IGorKykge1xuICAgICAgICBpZiAoIWFsbG93ZWRBdHRyaWJ1dGUoYXR0cmlidXRlTGlzdFtqXSwgd2hpdGVsaXN0ZWRBdHRyaWJ1dGVzKSkge1xuICAgICAgICAgIGVsLnJlbW92ZUF0dHJpYnV0ZShhdHRyaWJ1dGVMaXN0W2pdLm5vZGVOYW1lKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGNyZWF0ZWREb2N1bWVudC5ib2R5LmlubmVySFRNTFxuICB9XG5cbiAgLy8gVE9PTFRJUCBQVUJMSUMgQ0xBU1MgREVGSU5JVElPTlxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgdmFyIFRvb2x0aXAgPSBmdW5jdGlvbiAoZWxlbWVudCwgb3B0aW9ucykge1xuICAgIHRoaXMudHlwZSAgICAgICA9IG51bGxcbiAgICB0aGlzLm9wdGlvbnMgICAgPSBudWxsXG4gICAgdGhpcy5lbmFibGVkICAgID0gbnVsbFxuICAgIHRoaXMudGltZW91dCAgICA9IG51bGxcbiAgICB0aGlzLmhvdmVyU3RhdGUgPSBudWxsXG4gICAgdGhpcy4kZWxlbWVudCAgID0gbnVsbFxuICAgIHRoaXMuaW5TdGF0ZSAgICA9IG51bGxcblxuICAgIHRoaXMuaW5pdCgndG9vbHRpcCcsIGVsZW1lbnQsIG9wdGlvbnMpXG4gIH1cblxuICBUb29sdGlwLlZFUlNJT04gID0gJzMuNC4xJ1xuXG4gIFRvb2x0aXAuVFJBTlNJVElPTl9EVVJBVElPTiA9IDE1MFxuXG4gIFRvb2x0aXAuREVGQVVMVFMgPSB7XG4gICAgYW5pbWF0aW9uOiB0cnVlLFxuICAgIHBsYWNlbWVudDogJ3RvcCcsXG4gICAgc2VsZWN0b3I6IGZhbHNlLFxuICAgIHRlbXBsYXRlOiAnPGRpdiBjbGFzcz1cInRvb2x0aXBcIiByb2xlPVwidG9vbHRpcFwiPjxkaXYgY2xhc3M9XCJ0b29sdGlwLWFycm93XCI+PC9kaXY+PGRpdiBjbGFzcz1cInRvb2x0aXAtaW5uZXJcIj48L2Rpdj48L2Rpdj4nLFxuICAgIHRyaWdnZXI6ICdob3ZlciBmb2N1cycsXG4gICAgdGl0bGU6ICcnLFxuICAgIGRlbGF5OiAwLFxuICAgIGh0bWw6IGZhbHNlLFxuICAgIGNvbnRhaW5lcjogZmFsc2UsXG4gICAgdmlld3BvcnQ6IHtcbiAgICAgIHNlbGVjdG9yOiAnYm9keScsXG4gICAgICBwYWRkaW5nOiAwXG4gICAgfSxcbiAgICBzYW5pdGl6ZSA6IHRydWUsXG4gICAgc2FuaXRpemVGbiA6IG51bGwsXG4gICAgd2hpdGVMaXN0IDogRGVmYXVsdFdoaXRlbGlzdFxuICB9XG5cbiAgVG9vbHRpcC5wcm90b3R5cGUuaW5pdCA9IGZ1bmN0aW9uICh0eXBlLCBlbGVtZW50LCBvcHRpb25zKSB7XG4gICAgdGhpcy5lbmFibGVkICAgPSB0cnVlXG4gICAgdGhpcy50eXBlICAgICAgPSB0eXBlXG4gICAgdGhpcy4kZWxlbWVudCAgPSAkKGVsZW1lbnQpXG4gICAgdGhpcy5vcHRpb25zICAgPSB0aGlzLmdldE9wdGlvbnMob3B0aW9ucylcbiAgICB0aGlzLiR2aWV3cG9ydCA9IHRoaXMub3B0aW9ucy52aWV3cG9ydCAmJiAkKGRvY3VtZW50KS5maW5kKCQuaXNGdW5jdGlvbih0aGlzLm9wdGlvbnMudmlld3BvcnQpID8gdGhpcy5vcHRpb25zLnZpZXdwb3J0LmNhbGwodGhpcywgdGhpcy4kZWxlbWVudCkgOiAodGhpcy5vcHRpb25zLnZpZXdwb3J0LnNlbGVjdG9yIHx8IHRoaXMub3B0aW9ucy52aWV3cG9ydCkpXG4gICAgdGhpcy5pblN0YXRlICAgPSB7IGNsaWNrOiBmYWxzZSwgaG92ZXI6IGZhbHNlLCBmb2N1czogZmFsc2UgfVxuXG4gICAgaWYgKHRoaXMuJGVsZW1lbnRbMF0gaW5zdGFuY2VvZiBkb2N1bWVudC5jb25zdHJ1Y3RvciAmJiAhdGhpcy5vcHRpb25zLnNlbGVjdG9yKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ2BzZWxlY3RvcmAgb3B0aW9uIG11c3QgYmUgc3BlY2lmaWVkIHdoZW4gaW5pdGlhbGl6aW5nICcgKyB0aGlzLnR5cGUgKyAnIG9uIHRoZSB3aW5kb3cuZG9jdW1lbnQgb2JqZWN0IScpXG4gICAgfVxuXG4gICAgdmFyIHRyaWdnZXJzID0gdGhpcy5vcHRpb25zLnRyaWdnZXIuc3BsaXQoJyAnKVxuXG4gICAgZm9yICh2YXIgaSA9IHRyaWdnZXJzLmxlbmd0aDsgaS0tOykge1xuICAgICAgdmFyIHRyaWdnZXIgPSB0cmlnZ2Vyc1tpXVxuXG4gICAgICBpZiAodHJpZ2dlciA9PSAnY2xpY2snKSB7XG4gICAgICAgIHRoaXMuJGVsZW1lbnQub24oJ2NsaWNrLicgKyB0aGlzLnR5cGUsIHRoaXMub3B0aW9ucy5zZWxlY3RvciwgJC5wcm94eSh0aGlzLnRvZ2dsZSwgdGhpcykpXG4gICAgICB9IGVsc2UgaWYgKHRyaWdnZXIgIT0gJ21hbnVhbCcpIHtcbiAgICAgICAgdmFyIGV2ZW50SW4gID0gdHJpZ2dlciA9PSAnaG92ZXInID8gJ21vdXNlZW50ZXInIDogJ2ZvY3VzaW4nXG4gICAgICAgIHZhciBldmVudE91dCA9IHRyaWdnZXIgPT0gJ2hvdmVyJyA/ICdtb3VzZWxlYXZlJyA6ICdmb2N1c291dCdcblxuICAgICAgICB0aGlzLiRlbGVtZW50Lm9uKGV2ZW50SW4gICsgJy4nICsgdGhpcy50eXBlLCB0aGlzLm9wdGlvbnMuc2VsZWN0b3IsICQucHJveHkodGhpcy5lbnRlciwgdGhpcykpXG4gICAgICAgIHRoaXMuJGVsZW1lbnQub24oZXZlbnRPdXQgKyAnLicgKyB0aGlzLnR5cGUsIHRoaXMub3B0aW9ucy5zZWxlY3RvciwgJC5wcm94eSh0aGlzLmxlYXZlLCB0aGlzKSlcbiAgICAgIH1cbiAgICB9XG5cbiAgICB0aGlzLm9wdGlvbnMuc2VsZWN0b3IgP1xuICAgICAgKHRoaXMuX29wdGlvbnMgPSAkLmV4dGVuZCh7fSwgdGhpcy5vcHRpb25zLCB7IHRyaWdnZXI6ICdtYW51YWwnLCBzZWxlY3RvcjogJycgfSkpIDpcbiAgICAgIHRoaXMuZml4VGl0bGUoKVxuICB9XG5cbiAgVG9vbHRpcC5wcm90b3R5cGUuZ2V0RGVmYXVsdHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIFRvb2x0aXAuREVGQVVMVFNcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLmdldE9wdGlvbnMgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgIHZhciBkYXRhQXR0cmlidXRlcyA9IHRoaXMuJGVsZW1lbnQuZGF0YSgpXG5cbiAgICBmb3IgKHZhciBkYXRhQXR0ciBpbiBkYXRhQXR0cmlidXRlcykge1xuICAgICAgaWYgKGRhdGFBdHRyaWJ1dGVzLmhhc093blByb3BlcnR5KGRhdGFBdHRyKSAmJiAkLmluQXJyYXkoZGF0YUF0dHIsIERJU0FMTE9XRURfQVRUUklCVVRFUykgIT09IC0xKSB7XG4gICAgICAgIGRlbGV0ZSBkYXRhQXR0cmlidXRlc1tkYXRhQXR0cl1cbiAgICAgIH1cbiAgICB9XG5cbiAgICBvcHRpb25zID0gJC5leHRlbmQoe30sIHRoaXMuZ2V0RGVmYXVsdHMoKSwgZGF0YUF0dHJpYnV0ZXMsIG9wdGlvbnMpXG5cbiAgICBpZiAob3B0aW9ucy5kZWxheSAmJiB0eXBlb2Ygb3B0aW9ucy5kZWxheSA9PSAnbnVtYmVyJykge1xuICAgICAgb3B0aW9ucy5kZWxheSA9IHtcbiAgICAgICAgc2hvdzogb3B0aW9ucy5kZWxheSxcbiAgICAgICAgaGlkZTogb3B0aW9ucy5kZWxheVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChvcHRpb25zLnNhbml0aXplKSB7XG4gICAgICBvcHRpb25zLnRlbXBsYXRlID0gc2FuaXRpemVIdG1sKG9wdGlvbnMudGVtcGxhdGUsIG9wdGlvbnMud2hpdGVMaXN0LCBvcHRpb25zLnNhbml0aXplRm4pXG4gICAgfVxuXG4gICAgcmV0dXJuIG9wdGlvbnNcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLmdldERlbGVnYXRlT3B0aW9ucyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgb3B0aW9ucyAgPSB7fVxuICAgIHZhciBkZWZhdWx0cyA9IHRoaXMuZ2V0RGVmYXVsdHMoKVxuXG4gICAgdGhpcy5fb3B0aW9ucyAmJiAkLmVhY2godGhpcy5fb3B0aW9ucywgZnVuY3Rpb24gKGtleSwgdmFsdWUpIHtcbiAgICAgIGlmIChkZWZhdWx0c1trZXldICE9IHZhbHVlKSBvcHRpb25zW2tleV0gPSB2YWx1ZVxuICAgIH0pXG5cbiAgICByZXR1cm4gb3B0aW9uc1xuICB9XG5cbiAgVG9vbHRpcC5wcm90b3R5cGUuZW50ZXIgPSBmdW5jdGlvbiAob2JqKSB7XG4gICAgdmFyIHNlbGYgPSBvYmogaW5zdGFuY2VvZiB0aGlzLmNvbnN0cnVjdG9yID9cbiAgICAgIG9iaiA6ICQob2JqLmN1cnJlbnRUYXJnZXQpLmRhdGEoJ2JzLicgKyB0aGlzLnR5cGUpXG5cbiAgICBpZiAoIXNlbGYpIHtcbiAgICAgIHNlbGYgPSBuZXcgdGhpcy5jb25zdHJ1Y3RvcihvYmouY3VycmVudFRhcmdldCwgdGhpcy5nZXREZWxlZ2F0ZU9wdGlvbnMoKSlcbiAgICAgICQob2JqLmN1cnJlbnRUYXJnZXQpLmRhdGEoJ2JzLicgKyB0aGlzLnR5cGUsIHNlbGYpXG4gICAgfVxuXG4gICAgaWYgKG9iaiBpbnN0YW5jZW9mICQuRXZlbnQpIHtcbiAgICAgIHNlbGYuaW5TdGF0ZVtvYmoudHlwZSA9PSAnZm9jdXNpbicgPyAnZm9jdXMnIDogJ2hvdmVyJ10gPSB0cnVlXG4gICAgfVxuXG4gICAgaWYgKHNlbGYudGlwKCkuaGFzQ2xhc3MoJ2luJykgfHwgc2VsZi5ob3ZlclN0YXRlID09ICdpbicpIHtcbiAgICAgIHNlbGYuaG92ZXJTdGF0ZSA9ICdpbidcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIGNsZWFyVGltZW91dChzZWxmLnRpbWVvdXQpXG5cbiAgICBzZWxmLmhvdmVyU3RhdGUgPSAnaW4nXG5cbiAgICBpZiAoIXNlbGYub3B0aW9ucy5kZWxheSB8fCAhc2VsZi5vcHRpb25zLmRlbGF5LnNob3cpIHJldHVybiBzZWxmLnNob3coKVxuXG4gICAgc2VsZi50aW1lb3V0ID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICBpZiAoc2VsZi5ob3ZlclN0YXRlID09ICdpbicpIHNlbGYuc2hvdygpXG4gICAgfSwgc2VsZi5vcHRpb25zLmRlbGF5LnNob3cpXG4gIH1cblxuICBUb29sdGlwLnByb3RvdHlwZS5pc0luU3RhdGVUcnVlID0gZnVuY3Rpb24gKCkge1xuICAgIGZvciAodmFyIGtleSBpbiB0aGlzLmluU3RhdGUpIHtcbiAgICAgIGlmICh0aGlzLmluU3RhdGVba2V5XSkgcmV0dXJuIHRydWVcbiAgICB9XG5cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLmxlYXZlID0gZnVuY3Rpb24gKG9iaikge1xuICAgIHZhciBzZWxmID0gb2JqIGluc3RhbmNlb2YgdGhpcy5jb25zdHJ1Y3RvciA/XG4gICAgICBvYmogOiAkKG9iai5jdXJyZW50VGFyZ2V0KS5kYXRhKCdicy4nICsgdGhpcy50eXBlKVxuXG4gICAgaWYgKCFzZWxmKSB7XG4gICAgICBzZWxmID0gbmV3IHRoaXMuY29uc3RydWN0b3Iob2JqLmN1cnJlbnRUYXJnZXQsIHRoaXMuZ2V0RGVsZWdhdGVPcHRpb25zKCkpXG4gICAgICAkKG9iai5jdXJyZW50VGFyZ2V0KS5kYXRhKCdicy4nICsgdGhpcy50eXBlLCBzZWxmKVxuICAgIH1cblxuICAgIGlmIChvYmogaW5zdGFuY2VvZiAkLkV2ZW50KSB7XG4gICAgICBzZWxmLmluU3RhdGVbb2JqLnR5cGUgPT0gJ2ZvY3Vzb3V0JyA/ICdmb2N1cycgOiAnaG92ZXInXSA9IGZhbHNlXG4gICAgfVxuXG4gICAgaWYgKHNlbGYuaXNJblN0YXRlVHJ1ZSgpKSByZXR1cm5cblxuICAgIGNsZWFyVGltZW91dChzZWxmLnRpbWVvdXQpXG5cbiAgICBzZWxmLmhvdmVyU3RhdGUgPSAnb3V0J1xuXG4gICAgaWYgKCFzZWxmLm9wdGlvbnMuZGVsYXkgfHwgIXNlbGYub3B0aW9ucy5kZWxheS5oaWRlKSByZXR1cm4gc2VsZi5oaWRlKClcblxuICAgIHNlbGYudGltZW91dCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgaWYgKHNlbGYuaG92ZXJTdGF0ZSA9PSAnb3V0Jykgc2VsZi5oaWRlKClcbiAgICB9LCBzZWxmLm9wdGlvbnMuZGVsYXkuaGlkZSlcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLnNob3cgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGUgPSAkLkV2ZW50KCdzaG93LmJzLicgKyB0aGlzLnR5cGUpXG5cbiAgICBpZiAodGhpcy5oYXNDb250ZW50KCkgJiYgdGhpcy5lbmFibGVkKSB7XG4gICAgICB0aGlzLiRlbGVtZW50LnRyaWdnZXIoZSlcblxuICAgICAgdmFyIGluRG9tID0gJC5jb250YWlucyh0aGlzLiRlbGVtZW50WzBdLm93bmVyRG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LCB0aGlzLiRlbGVtZW50WzBdKVxuICAgICAgaWYgKGUuaXNEZWZhdWx0UHJldmVudGVkKCkgfHwgIWluRG9tKSByZXR1cm5cbiAgICAgIHZhciB0aGF0ID0gdGhpc1xuXG4gICAgICB2YXIgJHRpcCA9IHRoaXMudGlwKClcblxuICAgICAgdmFyIHRpcElkID0gdGhpcy5nZXRVSUQodGhpcy50eXBlKVxuXG4gICAgICB0aGlzLnNldENvbnRlbnQoKVxuICAgICAgJHRpcC5hdHRyKCdpZCcsIHRpcElkKVxuICAgICAgdGhpcy4kZWxlbWVudC5hdHRyKCdhcmlhLWRlc2NyaWJlZGJ5JywgdGlwSWQpXG5cbiAgICAgIGlmICh0aGlzLm9wdGlvbnMuYW5pbWF0aW9uKSAkdGlwLmFkZENsYXNzKCdmYWRlJylcblxuICAgICAgdmFyIHBsYWNlbWVudCA9IHR5cGVvZiB0aGlzLm9wdGlvbnMucGxhY2VtZW50ID09ICdmdW5jdGlvbicgP1xuICAgICAgICB0aGlzLm9wdGlvbnMucGxhY2VtZW50LmNhbGwodGhpcywgJHRpcFswXSwgdGhpcy4kZWxlbWVudFswXSkgOlxuICAgICAgICB0aGlzLm9wdGlvbnMucGxhY2VtZW50XG5cbiAgICAgIHZhciBhdXRvVG9rZW4gPSAvXFxzP2F1dG8/XFxzPy9pXG4gICAgICB2YXIgYXV0b1BsYWNlID0gYXV0b1Rva2VuLnRlc3QocGxhY2VtZW50KVxuICAgICAgaWYgKGF1dG9QbGFjZSkgcGxhY2VtZW50ID0gcGxhY2VtZW50LnJlcGxhY2UoYXV0b1Rva2VuLCAnJykgfHwgJ3RvcCdcblxuICAgICAgJHRpcFxuICAgICAgICAuZGV0YWNoKClcbiAgICAgICAgLmNzcyh7IHRvcDogMCwgbGVmdDogMCwgZGlzcGxheTogJ2Jsb2NrJyB9KVxuICAgICAgICAuYWRkQ2xhc3MocGxhY2VtZW50KVxuICAgICAgICAuZGF0YSgnYnMuJyArIHRoaXMudHlwZSwgdGhpcylcblxuICAgICAgdGhpcy5vcHRpb25zLmNvbnRhaW5lciA/ICR0aXAuYXBwZW5kVG8oJChkb2N1bWVudCkuZmluZCh0aGlzLm9wdGlvbnMuY29udGFpbmVyKSkgOiAkdGlwLmluc2VydEFmdGVyKHRoaXMuJGVsZW1lbnQpXG4gICAgICB0aGlzLiRlbGVtZW50LnRyaWdnZXIoJ2luc2VydGVkLmJzLicgKyB0aGlzLnR5cGUpXG5cbiAgICAgIHZhciBwb3MgICAgICAgICAgPSB0aGlzLmdldFBvc2l0aW9uKClcbiAgICAgIHZhciBhY3R1YWxXaWR0aCAgPSAkdGlwWzBdLm9mZnNldFdpZHRoXG4gICAgICB2YXIgYWN0dWFsSGVpZ2h0ID0gJHRpcFswXS5vZmZzZXRIZWlnaHRcblxuICAgICAgaWYgKGF1dG9QbGFjZSkge1xuICAgICAgICB2YXIgb3JnUGxhY2VtZW50ID0gcGxhY2VtZW50XG4gICAgICAgIHZhciB2aWV3cG9ydERpbSA9IHRoaXMuZ2V0UG9zaXRpb24odGhpcy4kdmlld3BvcnQpXG5cbiAgICAgICAgcGxhY2VtZW50ID0gcGxhY2VtZW50ID09ICdib3R0b20nICYmIHBvcy5ib3R0b20gKyBhY3R1YWxIZWlnaHQgPiB2aWV3cG9ydERpbS5ib3R0b20gPyAndG9wJyAgICA6XG4gICAgICAgICAgICAgICAgICAgIHBsYWNlbWVudCA9PSAndG9wJyAgICAmJiBwb3MudG9wICAgIC0gYWN0dWFsSGVpZ2h0IDwgdmlld3BvcnREaW0udG9wICAgID8gJ2JvdHRvbScgOlxuICAgICAgICAgICAgICAgICAgICBwbGFjZW1lbnQgPT0gJ3JpZ2h0JyAgJiYgcG9zLnJpZ2h0ICArIGFjdHVhbFdpZHRoICA+IHZpZXdwb3J0RGltLndpZHRoICA/ICdsZWZ0JyAgIDpcbiAgICAgICAgICAgICAgICAgICAgcGxhY2VtZW50ID09ICdsZWZ0JyAgICYmIHBvcy5sZWZ0ICAgLSBhY3R1YWxXaWR0aCAgPCB2aWV3cG9ydERpbS5sZWZ0ICAgPyAncmlnaHQnICA6XG4gICAgICAgICAgICAgICAgICAgIHBsYWNlbWVudFxuXG4gICAgICAgICR0aXBcbiAgICAgICAgICAucmVtb3ZlQ2xhc3Mob3JnUGxhY2VtZW50KVxuICAgICAgICAgIC5hZGRDbGFzcyhwbGFjZW1lbnQpXG4gICAgICB9XG5cbiAgICAgIHZhciBjYWxjdWxhdGVkT2Zmc2V0ID0gdGhpcy5nZXRDYWxjdWxhdGVkT2Zmc2V0KHBsYWNlbWVudCwgcG9zLCBhY3R1YWxXaWR0aCwgYWN0dWFsSGVpZ2h0KVxuXG4gICAgICB0aGlzLmFwcGx5UGxhY2VtZW50KGNhbGN1bGF0ZWRPZmZzZXQsIHBsYWNlbWVudClcblxuICAgICAgdmFyIGNvbXBsZXRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgcHJldkhvdmVyU3RhdGUgPSB0aGF0LmhvdmVyU3RhdGVcbiAgICAgICAgdGhhdC4kZWxlbWVudC50cmlnZ2VyKCdzaG93bi5icy4nICsgdGhhdC50eXBlKVxuICAgICAgICB0aGF0LmhvdmVyU3RhdGUgPSBudWxsXG5cbiAgICAgICAgaWYgKHByZXZIb3ZlclN0YXRlID09ICdvdXQnKSB0aGF0LmxlYXZlKHRoYXQpXG4gICAgICB9XG5cbiAgICAgICQuc3VwcG9ydC50cmFuc2l0aW9uICYmIHRoaXMuJHRpcC5oYXNDbGFzcygnZmFkZScpID9cbiAgICAgICAgJHRpcFxuICAgICAgICAgIC5vbmUoJ2JzVHJhbnNpdGlvbkVuZCcsIGNvbXBsZXRlKVxuICAgICAgICAgIC5lbXVsYXRlVHJhbnNpdGlvbkVuZChUb29sdGlwLlRSQU5TSVRJT05fRFVSQVRJT04pIDpcbiAgICAgICAgY29tcGxldGUoKVxuICAgIH1cbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLmFwcGx5UGxhY2VtZW50ID0gZnVuY3Rpb24gKG9mZnNldCwgcGxhY2VtZW50KSB7XG4gICAgdmFyICR0aXAgICA9IHRoaXMudGlwKClcbiAgICB2YXIgd2lkdGggID0gJHRpcFswXS5vZmZzZXRXaWR0aFxuICAgIHZhciBoZWlnaHQgPSAkdGlwWzBdLm9mZnNldEhlaWdodFxuXG4gICAgLy8gbWFudWFsbHkgcmVhZCBtYXJnaW5zIGJlY2F1c2UgZ2V0Qm91bmRpbmdDbGllbnRSZWN0IGluY2x1ZGVzIGRpZmZlcmVuY2VcbiAgICB2YXIgbWFyZ2luVG9wID0gcGFyc2VJbnQoJHRpcC5jc3MoJ21hcmdpbi10b3AnKSwgMTApXG4gICAgdmFyIG1hcmdpbkxlZnQgPSBwYXJzZUludCgkdGlwLmNzcygnbWFyZ2luLWxlZnQnKSwgMTApXG5cbiAgICAvLyB3ZSBtdXN0IGNoZWNrIGZvciBOYU4gZm9yIGllIDgvOVxuICAgIGlmIChpc05hTihtYXJnaW5Ub3ApKSAgbWFyZ2luVG9wICA9IDBcbiAgICBpZiAoaXNOYU4obWFyZ2luTGVmdCkpIG1hcmdpbkxlZnQgPSAwXG5cbiAgICBvZmZzZXQudG9wICArPSBtYXJnaW5Ub3BcbiAgICBvZmZzZXQubGVmdCArPSBtYXJnaW5MZWZ0XG5cbiAgICAvLyAkLmZuLm9mZnNldCBkb2Vzbid0IHJvdW5kIHBpeGVsIHZhbHVlc1xuICAgIC8vIHNvIHdlIHVzZSBzZXRPZmZzZXQgZGlyZWN0bHkgd2l0aCBvdXIgb3duIGZ1bmN0aW9uIEItMFxuICAgICQub2Zmc2V0LnNldE9mZnNldCgkdGlwWzBdLCAkLmV4dGVuZCh7XG4gICAgICB1c2luZzogZnVuY3Rpb24gKHByb3BzKSB7XG4gICAgICAgICR0aXAuY3NzKHtcbiAgICAgICAgICB0b3A6IE1hdGgucm91bmQocHJvcHMudG9wKSxcbiAgICAgICAgICBsZWZ0OiBNYXRoLnJvdW5kKHByb3BzLmxlZnQpXG4gICAgICAgIH0pXG4gICAgICB9XG4gICAgfSwgb2Zmc2V0KSwgMClcblxuICAgICR0aXAuYWRkQ2xhc3MoJ2luJylcblxuICAgIC8vIGNoZWNrIHRvIHNlZSBpZiBwbGFjaW5nIHRpcCBpbiBuZXcgb2Zmc2V0IGNhdXNlZCB0aGUgdGlwIHRvIHJlc2l6ZSBpdHNlbGZcbiAgICB2YXIgYWN0dWFsV2lkdGggID0gJHRpcFswXS5vZmZzZXRXaWR0aFxuICAgIHZhciBhY3R1YWxIZWlnaHQgPSAkdGlwWzBdLm9mZnNldEhlaWdodFxuXG4gICAgaWYgKHBsYWNlbWVudCA9PSAndG9wJyAmJiBhY3R1YWxIZWlnaHQgIT0gaGVpZ2h0KSB7XG4gICAgICBvZmZzZXQudG9wID0gb2Zmc2V0LnRvcCArIGhlaWdodCAtIGFjdHVhbEhlaWdodFxuICAgIH1cblxuICAgIHZhciBkZWx0YSA9IHRoaXMuZ2V0Vmlld3BvcnRBZGp1c3RlZERlbHRhKHBsYWNlbWVudCwgb2Zmc2V0LCBhY3R1YWxXaWR0aCwgYWN0dWFsSGVpZ2h0KVxuXG4gICAgaWYgKGRlbHRhLmxlZnQpIG9mZnNldC5sZWZ0ICs9IGRlbHRhLmxlZnRcbiAgICBlbHNlIG9mZnNldC50b3AgKz0gZGVsdGEudG9wXG5cbiAgICB2YXIgaXNWZXJ0aWNhbCAgICAgICAgICA9IC90b3B8Ym90dG9tLy50ZXN0KHBsYWNlbWVudClcbiAgICB2YXIgYXJyb3dEZWx0YSAgICAgICAgICA9IGlzVmVydGljYWwgPyBkZWx0YS5sZWZ0ICogMiAtIHdpZHRoICsgYWN0dWFsV2lkdGggOiBkZWx0YS50b3AgKiAyIC0gaGVpZ2h0ICsgYWN0dWFsSGVpZ2h0XG4gICAgdmFyIGFycm93T2Zmc2V0UG9zaXRpb24gPSBpc1ZlcnRpY2FsID8gJ29mZnNldFdpZHRoJyA6ICdvZmZzZXRIZWlnaHQnXG5cbiAgICAkdGlwLm9mZnNldChvZmZzZXQpXG4gICAgdGhpcy5yZXBsYWNlQXJyb3coYXJyb3dEZWx0YSwgJHRpcFswXVthcnJvd09mZnNldFBvc2l0aW9uXSwgaXNWZXJ0aWNhbClcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLnJlcGxhY2VBcnJvdyA9IGZ1bmN0aW9uIChkZWx0YSwgZGltZW5zaW9uLCBpc1ZlcnRpY2FsKSB7XG4gICAgdGhpcy5hcnJvdygpXG4gICAgICAuY3NzKGlzVmVydGljYWwgPyAnbGVmdCcgOiAndG9wJywgNTAgKiAoMSAtIGRlbHRhIC8gZGltZW5zaW9uKSArICclJylcbiAgICAgIC5jc3MoaXNWZXJ0aWNhbCA/ICd0b3AnIDogJ2xlZnQnLCAnJylcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLnNldENvbnRlbnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyICR0aXAgID0gdGhpcy50aXAoKVxuICAgIHZhciB0aXRsZSA9IHRoaXMuZ2V0VGl0bGUoKVxuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5odG1sKSB7XG4gICAgICBpZiAodGhpcy5vcHRpb25zLnNhbml0aXplKSB7XG4gICAgICAgIHRpdGxlID0gc2FuaXRpemVIdG1sKHRpdGxlLCB0aGlzLm9wdGlvbnMud2hpdGVMaXN0LCB0aGlzLm9wdGlvbnMuc2FuaXRpemVGbilcbiAgICAgIH1cblxuICAgICAgJHRpcC5maW5kKCcudG9vbHRpcC1pbm5lcicpLmh0bWwodGl0bGUpXG4gICAgfSBlbHNlIHtcbiAgICAgICR0aXAuZmluZCgnLnRvb2x0aXAtaW5uZXInKS50ZXh0KHRpdGxlKVxuICAgIH1cblxuICAgICR0aXAucmVtb3ZlQ2xhc3MoJ2ZhZGUgaW4gdG9wIGJvdHRvbSBsZWZ0IHJpZ2h0JylcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLmhpZGUgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB2YXIgdGhhdCA9IHRoaXNcbiAgICB2YXIgJHRpcCA9ICQodGhpcy4kdGlwKVxuICAgIHZhciBlICAgID0gJC5FdmVudCgnaGlkZS5icy4nICsgdGhpcy50eXBlKVxuXG4gICAgZnVuY3Rpb24gY29tcGxldGUoKSB7XG4gICAgICBpZiAodGhhdC5ob3ZlclN0YXRlICE9ICdpbicpICR0aXAuZGV0YWNoKClcbiAgICAgIGlmICh0aGF0LiRlbGVtZW50KSB7IC8vIFRPRE86IENoZWNrIHdoZXRoZXIgZ3VhcmRpbmcgdGhpcyBjb2RlIHdpdGggdGhpcyBgaWZgIGlzIHJlYWxseSBuZWNlc3NhcnkuXG4gICAgICAgIHRoYXQuJGVsZW1lbnRcbiAgICAgICAgICAucmVtb3ZlQXR0cignYXJpYS1kZXNjcmliZWRieScpXG4gICAgICAgICAgLnRyaWdnZXIoJ2hpZGRlbi5icy4nICsgdGhhdC50eXBlKVxuICAgICAgfVxuICAgICAgY2FsbGJhY2sgJiYgY2FsbGJhY2soKVxuICAgIH1cblxuICAgIHRoaXMuJGVsZW1lbnQudHJpZ2dlcihlKVxuXG4gICAgaWYgKGUuaXNEZWZhdWx0UHJldmVudGVkKCkpIHJldHVyblxuXG4gICAgJHRpcC5yZW1vdmVDbGFzcygnaW4nKVxuXG4gICAgJC5zdXBwb3J0LnRyYW5zaXRpb24gJiYgJHRpcC5oYXNDbGFzcygnZmFkZScpID9cbiAgICAgICR0aXBcbiAgICAgICAgLm9uZSgnYnNUcmFuc2l0aW9uRW5kJywgY29tcGxldGUpXG4gICAgICAgIC5lbXVsYXRlVHJhbnNpdGlvbkVuZChUb29sdGlwLlRSQU5TSVRJT05fRFVSQVRJT04pIDpcbiAgICAgIGNvbXBsZXRlKClcblxuICAgIHRoaXMuaG92ZXJTdGF0ZSA9IG51bGxcblxuICAgIHJldHVybiB0aGlzXG4gIH1cblxuICBUb29sdGlwLnByb3RvdHlwZS5maXhUaXRsZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgJGUgPSB0aGlzLiRlbGVtZW50XG4gICAgaWYgKCRlLmF0dHIoJ3RpdGxlJykgfHwgdHlwZW9mICRlLmF0dHIoJ2RhdGEtb3JpZ2luYWwtdGl0bGUnKSAhPSAnc3RyaW5nJykge1xuICAgICAgJGUuYXR0cignZGF0YS1vcmlnaW5hbC10aXRsZScsICRlLmF0dHIoJ3RpdGxlJykgfHwgJycpLmF0dHIoJ3RpdGxlJywgJycpXG4gICAgfVxuICB9XG5cbiAgVG9vbHRpcC5wcm90b3R5cGUuaGFzQ29udGVudCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRUaXRsZSgpXG4gIH1cblxuICBUb29sdGlwLnByb3RvdHlwZS5nZXRQb3NpdGlvbiA9IGZ1bmN0aW9uICgkZWxlbWVudCkge1xuICAgICRlbGVtZW50ICAgPSAkZWxlbWVudCB8fCB0aGlzLiRlbGVtZW50XG5cbiAgICB2YXIgZWwgICAgID0gJGVsZW1lbnRbMF1cbiAgICB2YXIgaXNCb2R5ID0gZWwudGFnTmFtZSA9PSAnQk9EWSdcblxuICAgIHZhciBlbFJlY3QgICAgPSBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKVxuICAgIGlmIChlbFJlY3Qud2lkdGggPT0gbnVsbCkge1xuICAgICAgLy8gd2lkdGggYW5kIGhlaWdodCBhcmUgbWlzc2luZyBpbiBJRTgsIHNvIGNvbXB1dGUgdGhlbSBtYW51YWxseTsgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS90d2JzL2Jvb3RzdHJhcC9pc3N1ZXMvMTQwOTNcbiAgICAgIGVsUmVjdCA9ICQuZXh0ZW5kKHt9LCBlbFJlY3QsIHsgd2lkdGg6IGVsUmVjdC5yaWdodCAtIGVsUmVjdC5sZWZ0LCBoZWlnaHQ6IGVsUmVjdC5ib3R0b20gLSBlbFJlY3QudG9wIH0pXG4gICAgfVxuICAgIHZhciBpc1N2ZyA9IHdpbmRvdy5TVkdFbGVtZW50ICYmIGVsIGluc3RhbmNlb2Ygd2luZG93LlNWR0VsZW1lbnRcbiAgICAvLyBBdm9pZCB1c2luZyAkLm9mZnNldCgpIG9uIFNWR3Mgc2luY2UgaXQgZ2l2ZXMgaW5jb3JyZWN0IHJlc3VsdHMgaW4galF1ZXJ5IDMuXG4gICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS90d2JzL2Jvb3RzdHJhcC9pc3N1ZXMvMjAyODBcbiAgICB2YXIgZWxPZmZzZXQgID0gaXNCb2R5ID8geyB0b3A6IDAsIGxlZnQ6IDAgfSA6IChpc1N2ZyA/IG51bGwgOiAkZWxlbWVudC5vZmZzZXQoKSlcbiAgICB2YXIgc2Nyb2xsICAgID0geyBzY3JvbGw6IGlzQm9keSA/IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxUb3AgfHwgZG9jdW1lbnQuYm9keS5zY3JvbGxUb3AgOiAkZWxlbWVudC5zY3JvbGxUb3AoKSB9XG4gICAgdmFyIG91dGVyRGltcyA9IGlzQm9keSA/IHsgd2lkdGg6ICQod2luZG93KS53aWR0aCgpLCBoZWlnaHQ6ICQod2luZG93KS5oZWlnaHQoKSB9IDogbnVsbFxuXG4gICAgcmV0dXJuICQuZXh0ZW5kKHt9LCBlbFJlY3QsIHNjcm9sbCwgb3V0ZXJEaW1zLCBlbE9mZnNldClcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLmdldENhbGN1bGF0ZWRPZmZzZXQgPSBmdW5jdGlvbiAocGxhY2VtZW50LCBwb3MsIGFjdHVhbFdpZHRoLCBhY3R1YWxIZWlnaHQpIHtcbiAgICByZXR1cm4gcGxhY2VtZW50ID09ICdib3R0b20nID8geyB0b3A6IHBvcy50b3AgKyBwb3MuaGVpZ2h0LCAgIGxlZnQ6IHBvcy5sZWZ0ICsgcG9zLndpZHRoIC8gMiAtIGFjdHVhbFdpZHRoIC8gMiB9IDpcbiAgICAgICAgICAgcGxhY2VtZW50ID09ICd0b3AnICAgID8geyB0b3A6IHBvcy50b3AgLSBhY3R1YWxIZWlnaHQsIGxlZnQ6IHBvcy5sZWZ0ICsgcG9zLndpZHRoIC8gMiAtIGFjdHVhbFdpZHRoIC8gMiB9IDpcbiAgICAgICAgICAgcGxhY2VtZW50ID09ICdsZWZ0JyAgID8geyB0b3A6IHBvcy50b3AgKyBwb3MuaGVpZ2h0IC8gMiAtIGFjdHVhbEhlaWdodCAvIDIsIGxlZnQ6IHBvcy5sZWZ0IC0gYWN0dWFsV2lkdGggfSA6XG4gICAgICAgIC8qIHBsYWNlbWVudCA9PSAncmlnaHQnICovIHsgdG9wOiBwb3MudG9wICsgcG9zLmhlaWdodCAvIDIgLSBhY3R1YWxIZWlnaHQgLyAyLCBsZWZ0OiBwb3MubGVmdCArIHBvcy53aWR0aCB9XG5cbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLmdldFZpZXdwb3J0QWRqdXN0ZWREZWx0YSA9IGZ1bmN0aW9uIChwbGFjZW1lbnQsIHBvcywgYWN0dWFsV2lkdGgsIGFjdHVhbEhlaWdodCkge1xuICAgIHZhciBkZWx0YSA9IHsgdG9wOiAwLCBsZWZ0OiAwIH1cbiAgICBpZiAoIXRoaXMuJHZpZXdwb3J0KSByZXR1cm4gZGVsdGFcblxuICAgIHZhciB2aWV3cG9ydFBhZGRpbmcgPSB0aGlzLm9wdGlvbnMudmlld3BvcnQgJiYgdGhpcy5vcHRpb25zLnZpZXdwb3J0LnBhZGRpbmcgfHwgMFxuICAgIHZhciB2aWV3cG9ydERpbWVuc2lvbnMgPSB0aGlzLmdldFBvc2l0aW9uKHRoaXMuJHZpZXdwb3J0KVxuXG4gICAgaWYgKC9yaWdodHxsZWZ0Ly50ZXN0KHBsYWNlbWVudCkpIHtcbiAgICAgIHZhciB0b3BFZGdlT2Zmc2V0ICAgID0gcG9zLnRvcCAtIHZpZXdwb3J0UGFkZGluZyAtIHZpZXdwb3J0RGltZW5zaW9ucy5zY3JvbGxcbiAgICAgIHZhciBib3R0b21FZGdlT2Zmc2V0ID0gcG9zLnRvcCArIHZpZXdwb3J0UGFkZGluZyAtIHZpZXdwb3J0RGltZW5zaW9ucy5zY3JvbGwgKyBhY3R1YWxIZWlnaHRcbiAgICAgIGlmICh0b3BFZGdlT2Zmc2V0IDwgdmlld3BvcnREaW1lbnNpb25zLnRvcCkgeyAvLyB0b3Agb3ZlcmZsb3dcbiAgICAgICAgZGVsdGEudG9wID0gdmlld3BvcnREaW1lbnNpb25zLnRvcCAtIHRvcEVkZ2VPZmZzZXRcbiAgICAgIH0gZWxzZSBpZiAoYm90dG9tRWRnZU9mZnNldCA+IHZpZXdwb3J0RGltZW5zaW9ucy50b3AgKyB2aWV3cG9ydERpbWVuc2lvbnMuaGVpZ2h0KSB7IC8vIGJvdHRvbSBvdmVyZmxvd1xuICAgICAgICBkZWx0YS50b3AgPSB2aWV3cG9ydERpbWVuc2lvbnMudG9wICsgdmlld3BvcnREaW1lbnNpb25zLmhlaWdodCAtIGJvdHRvbUVkZ2VPZmZzZXRcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGxlZnRFZGdlT2Zmc2V0ICA9IHBvcy5sZWZ0IC0gdmlld3BvcnRQYWRkaW5nXG4gICAgICB2YXIgcmlnaHRFZGdlT2Zmc2V0ID0gcG9zLmxlZnQgKyB2aWV3cG9ydFBhZGRpbmcgKyBhY3R1YWxXaWR0aFxuICAgICAgaWYgKGxlZnRFZGdlT2Zmc2V0IDwgdmlld3BvcnREaW1lbnNpb25zLmxlZnQpIHsgLy8gbGVmdCBvdmVyZmxvd1xuICAgICAgICBkZWx0YS5sZWZ0ID0gdmlld3BvcnREaW1lbnNpb25zLmxlZnQgLSBsZWZ0RWRnZU9mZnNldFxuICAgICAgfSBlbHNlIGlmIChyaWdodEVkZ2VPZmZzZXQgPiB2aWV3cG9ydERpbWVuc2lvbnMucmlnaHQpIHsgLy8gcmlnaHQgb3ZlcmZsb3dcbiAgICAgICAgZGVsdGEubGVmdCA9IHZpZXdwb3J0RGltZW5zaW9ucy5sZWZ0ICsgdmlld3BvcnREaW1lbnNpb25zLndpZHRoIC0gcmlnaHRFZGdlT2Zmc2V0XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlbHRhXG4gIH1cblxuICBUb29sdGlwLnByb3RvdHlwZS5nZXRUaXRsZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgdGl0bGVcbiAgICB2YXIgJGUgPSB0aGlzLiRlbGVtZW50XG4gICAgdmFyIG8gID0gdGhpcy5vcHRpb25zXG5cbiAgICB0aXRsZSA9ICRlLmF0dHIoJ2RhdGEtb3JpZ2luYWwtdGl0bGUnKVxuICAgICAgfHwgKHR5cGVvZiBvLnRpdGxlID09ICdmdW5jdGlvbicgPyBvLnRpdGxlLmNhbGwoJGVbMF0pIDogIG8udGl0bGUpXG5cbiAgICByZXR1cm4gdGl0bGVcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLmdldFVJRCA9IGZ1bmN0aW9uIChwcmVmaXgpIHtcbiAgICBkbyBwcmVmaXggKz0gfn4oTWF0aC5yYW5kb20oKSAqIDEwMDAwMDApXG4gICAgd2hpbGUgKGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHByZWZpeCkpXG4gICAgcmV0dXJuIHByZWZpeFxuICB9XG5cbiAgVG9vbHRpcC5wcm90b3R5cGUudGlwID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICghdGhpcy4kdGlwKSB7XG4gICAgICB0aGlzLiR0aXAgPSAkKHRoaXMub3B0aW9ucy50ZW1wbGF0ZSlcbiAgICAgIGlmICh0aGlzLiR0aXAubGVuZ3RoICE9IDEpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKHRoaXMudHlwZSArICcgYHRlbXBsYXRlYCBvcHRpb24gbXVzdCBjb25zaXN0IG9mIGV4YWN0bHkgMSB0b3AtbGV2ZWwgZWxlbWVudCEnKVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdGhpcy4kdGlwXG4gIH1cblxuICBUb29sdGlwLnByb3RvdHlwZS5hcnJvdyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gKHRoaXMuJGFycm93ID0gdGhpcy4kYXJyb3cgfHwgdGhpcy50aXAoKS5maW5kKCcudG9vbHRpcC1hcnJvdycpKVxuICB9XG5cbiAgVG9vbHRpcC5wcm90b3R5cGUuZW5hYmxlID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZW5hYmxlZCA9IHRydWVcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLmRpc2FibGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5lbmFibGVkID0gZmFsc2VcbiAgfVxuXG4gIFRvb2x0aXAucHJvdG90eXBlLnRvZ2dsZUVuYWJsZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5lbmFibGVkID0gIXRoaXMuZW5hYmxlZFxuICB9XG5cbiAgVG9vbHRpcC5wcm90b3R5cGUudG9nZ2xlID0gZnVuY3Rpb24gKGUpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXNcbiAgICBpZiAoZSkge1xuICAgICAgc2VsZiA9ICQoZS5jdXJyZW50VGFyZ2V0KS5kYXRhKCdicy4nICsgdGhpcy50eXBlKVxuICAgICAgaWYgKCFzZWxmKSB7XG4gICAgICAgIHNlbGYgPSBuZXcgdGhpcy5jb25zdHJ1Y3RvcihlLmN1cnJlbnRUYXJnZXQsIHRoaXMuZ2V0RGVsZWdhdGVPcHRpb25zKCkpXG4gICAgICAgICQoZS5jdXJyZW50VGFyZ2V0KS5kYXRhKCdicy4nICsgdGhpcy50eXBlLCBzZWxmKVxuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChlKSB7XG4gICAgICBzZWxmLmluU3RhdGUuY2xpY2sgPSAhc2VsZi5pblN0YXRlLmNsaWNrXG4gICAgICBpZiAoc2VsZi5pc0luU3RhdGVUcnVlKCkpIHNlbGYuZW50ZXIoc2VsZilcbiAgICAgIGVsc2Ugc2VsZi5sZWF2ZShzZWxmKVxuICAgIH0gZWxzZSB7XG4gICAgICBzZWxmLnRpcCgpLmhhc0NsYXNzKCdpbicpID8gc2VsZi5sZWF2ZShzZWxmKSA6IHNlbGYuZW50ZXIoc2VsZilcbiAgICB9XG4gIH1cblxuICBUb29sdGlwLnByb3RvdHlwZS5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciB0aGF0ID0gdGhpc1xuICAgIGNsZWFyVGltZW91dCh0aGlzLnRpbWVvdXQpXG4gICAgdGhpcy5oaWRlKGZ1bmN0aW9uICgpIHtcbiAgICAgIHRoYXQuJGVsZW1lbnQub2ZmKCcuJyArIHRoYXQudHlwZSkucmVtb3ZlRGF0YSgnYnMuJyArIHRoYXQudHlwZSlcbiAgICAgIGlmICh0aGF0LiR0aXApIHtcbiAgICAgICAgdGhhdC4kdGlwLmRldGFjaCgpXG4gICAgICB9XG4gICAgICB0aGF0LiR0aXAgPSBudWxsXG4gICAgICB0aGF0LiRhcnJvdyA9IG51bGxcbiAgICAgIHRoYXQuJHZpZXdwb3J0ID0gbnVsbFxuICAgICAgdGhhdC4kZWxlbWVudCA9IG51bGxcbiAgICB9KVxuICB9XG5cbiAgVG9vbHRpcC5wcm90b3R5cGUuc2FuaXRpemVIdG1sID0gZnVuY3Rpb24gKHVuc2FmZUh0bWwpIHtcbiAgICByZXR1cm4gc2FuaXRpemVIdG1sKHVuc2FmZUh0bWwsIHRoaXMub3B0aW9ucy53aGl0ZUxpc3QsIHRoaXMub3B0aW9ucy5zYW5pdGl6ZUZuKVxuICB9XG5cbiAgLy8gVE9PTFRJUCBQTFVHSU4gREVGSU5JVElPTlxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgZnVuY3Rpb24gUGx1Z2luKG9wdGlvbikge1xuICAgIHJldHVybiB0aGlzLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgdmFyICR0aGlzICAgPSAkKHRoaXMpXG4gICAgICB2YXIgZGF0YSAgICA9ICR0aGlzLmRhdGEoJ2JzLnRvb2x0aXAnKVxuICAgICAgdmFyIG9wdGlvbnMgPSB0eXBlb2Ygb3B0aW9uID09ICdvYmplY3QnICYmIG9wdGlvblxuXG4gICAgICBpZiAoIWRhdGEgJiYgL2Rlc3Ryb3l8aGlkZS8udGVzdChvcHRpb24pKSByZXR1cm5cbiAgICAgIGlmICghZGF0YSkgJHRoaXMuZGF0YSgnYnMudG9vbHRpcCcsIChkYXRhID0gbmV3IFRvb2x0aXAodGhpcywgb3B0aW9ucykpKVxuICAgICAgaWYgKHR5cGVvZiBvcHRpb24gPT0gJ3N0cmluZycpIGRhdGFbb3B0aW9uXSgpXG4gICAgfSlcbiAgfVxuXG4gIHZhciBvbGQgPSAkLmZuLnRvb2x0aXBcblxuICAkLmZuLnRvb2x0aXAgICAgICAgICAgICAgPSBQbHVnaW5cbiAgJC5mbi50b29sdGlwLkNvbnN0cnVjdG9yID0gVG9vbHRpcFxuXG5cbiAgLy8gVE9PTFRJUCBOTyBDT05GTElDVFxuICAvLyA9PT09PT09PT09PT09PT09PT09XG5cbiAgJC5mbi50b29sdGlwLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJC5mbi50b29sdGlwID0gb2xkXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG59KGpRdWVyeSk7XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQm9vdHN0cmFwOiBwb3BvdmVyLmpzIHYzLjQuMVxuICogaHR0cHM6Ly9nZXRib290c3RyYXAuY29tL2RvY3MvMy40L2phdmFzY3JpcHQvI3BvcG92ZXJzXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvcHlyaWdodCAyMDExLTIwMTkgVHdpdHRlciwgSW5jLlxuICogTGljZW5zZWQgdW5kZXIgTUlUIChodHRwczovL2dpdGh1Yi5jb20vdHdicy9ib290c3RyYXAvYmxvYi9tYXN0ZXIvTElDRU5TRSlcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuXG5cbitmdW5jdGlvbiAoJCkge1xuICAndXNlIHN0cmljdCc7XG5cbiAgLy8gUE9QT1ZFUiBQVUJMSUMgQ0xBU1MgREVGSU5JVElPTlxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgdmFyIFBvcG92ZXIgPSBmdW5jdGlvbiAoZWxlbWVudCwgb3B0aW9ucykge1xuICAgIHRoaXMuaW5pdCgncG9wb3ZlcicsIGVsZW1lbnQsIG9wdGlvbnMpXG4gIH1cblxuICBpZiAoISQuZm4udG9vbHRpcCkgdGhyb3cgbmV3IEVycm9yKCdQb3BvdmVyIHJlcXVpcmVzIHRvb2x0aXAuanMnKVxuXG4gIFBvcG92ZXIuVkVSU0lPTiAgPSAnMy40LjEnXG5cbiAgUG9wb3Zlci5ERUZBVUxUUyA9ICQuZXh0ZW5kKHt9LCAkLmZuLnRvb2x0aXAuQ29uc3RydWN0b3IuREVGQVVMVFMsIHtcbiAgICBwbGFjZW1lbnQ6ICdyaWdodCcsXG4gICAgdHJpZ2dlcjogJ2NsaWNrJyxcbiAgICBjb250ZW50OiAnJyxcbiAgICB0ZW1wbGF0ZTogJzxkaXYgY2xhc3M9XCJwb3BvdmVyXCIgcm9sZT1cInRvb2x0aXBcIj48ZGl2IGNsYXNzPVwiYXJyb3dcIj48L2Rpdj48aDMgY2xhc3M9XCJwb3BvdmVyLXRpdGxlXCI+PC9oMz48ZGl2IGNsYXNzPVwicG9wb3Zlci1jb250ZW50XCI+PC9kaXY+PC9kaXY+J1xuICB9KVxuXG5cbiAgLy8gTk9URTogUE9QT1ZFUiBFWFRFTkRTIHRvb2x0aXAuanNcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICBQb3BvdmVyLnByb3RvdHlwZSA9ICQuZXh0ZW5kKHt9LCAkLmZuLnRvb2x0aXAuQ29uc3RydWN0b3IucHJvdG90eXBlKVxuXG4gIFBvcG92ZXIucHJvdG90eXBlLmNvbnN0cnVjdG9yID0gUG9wb3ZlclxuXG4gIFBvcG92ZXIucHJvdG90eXBlLmdldERlZmF1bHRzID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiBQb3BvdmVyLkRFRkFVTFRTXG4gIH1cblxuICBQb3BvdmVyLnByb3RvdHlwZS5zZXRDb250ZW50ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciAkdGlwICAgID0gdGhpcy50aXAoKVxuICAgIHZhciB0aXRsZSAgID0gdGhpcy5nZXRUaXRsZSgpXG4gICAgdmFyIGNvbnRlbnQgPSB0aGlzLmdldENvbnRlbnQoKVxuXG4gICAgaWYgKHRoaXMub3B0aW9ucy5odG1sKSB7XG4gICAgICB2YXIgdHlwZUNvbnRlbnQgPSB0eXBlb2YgY29udGVudFxuXG4gICAgICBpZiAodGhpcy5vcHRpb25zLnNhbml0aXplKSB7XG4gICAgICAgIHRpdGxlID0gdGhpcy5zYW5pdGl6ZUh0bWwodGl0bGUpXG5cbiAgICAgICAgaWYgKHR5cGVDb250ZW50ID09PSAnc3RyaW5nJykge1xuICAgICAgICAgIGNvbnRlbnQgPSB0aGlzLnNhbml0aXplSHRtbChjb250ZW50KVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgICR0aXAuZmluZCgnLnBvcG92ZXItdGl0bGUnKS5odG1sKHRpdGxlKVxuICAgICAgJHRpcC5maW5kKCcucG9wb3Zlci1jb250ZW50JykuY2hpbGRyZW4oKS5kZXRhY2goKS5lbmQoKVtcbiAgICAgICAgdHlwZUNvbnRlbnQgPT09ICdzdHJpbmcnID8gJ2h0bWwnIDogJ2FwcGVuZCdcbiAgICAgIF0oY29udGVudClcbiAgICB9IGVsc2Uge1xuICAgICAgJHRpcC5maW5kKCcucG9wb3Zlci10aXRsZScpLnRleHQodGl0bGUpXG4gICAgICAkdGlwLmZpbmQoJy5wb3BvdmVyLWNvbnRlbnQnKS5jaGlsZHJlbigpLmRldGFjaCgpLmVuZCgpLnRleHQoY29udGVudClcbiAgICB9XG5cbiAgICAkdGlwLnJlbW92ZUNsYXNzKCdmYWRlIHRvcCBib3R0b20gbGVmdCByaWdodCBpbicpXG5cbiAgICAvLyBJRTggZG9lc24ndCBhY2NlcHQgaGlkaW5nIHZpYSB0aGUgYDplbXB0eWAgcHNldWRvIHNlbGVjdG9yLCB3ZSBoYXZlIHRvIGRvXG4gICAgLy8gdGhpcyBtYW51YWxseSBieSBjaGVja2luZyB0aGUgY29udGVudHMuXG4gICAgaWYgKCEkdGlwLmZpbmQoJy5wb3BvdmVyLXRpdGxlJykuaHRtbCgpKSAkdGlwLmZpbmQoJy5wb3BvdmVyLXRpdGxlJykuaGlkZSgpXG4gIH1cblxuICBQb3BvdmVyLnByb3RvdHlwZS5oYXNDb250ZW50ID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLmdldFRpdGxlKCkgfHwgdGhpcy5nZXRDb250ZW50KClcbiAgfVxuXG4gIFBvcG92ZXIucHJvdG90eXBlLmdldENvbnRlbnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyICRlID0gdGhpcy4kZWxlbWVudFxuICAgIHZhciBvICA9IHRoaXMub3B0aW9uc1xuXG4gICAgcmV0dXJuICRlLmF0dHIoJ2RhdGEtY29udGVudCcpXG4gICAgICB8fCAodHlwZW9mIG8uY29udGVudCA9PSAnZnVuY3Rpb24nID9cbiAgICAgICAgby5jb250ZW50LmNhbGwoJGVbMF0pIDpcbiAgICAgICAgby5jb250ZW50KVxuICB9XG5cbiAgUG9wb3Zlci5wcm90b3R5cGUuYXJyb3cgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICh0aGlzLiRhcnJvdyA9IHRoaXMuJGFycm93IHx8IHRoaXMudGlwKCkuZmluZCgnLmFycm93JykpXG4gIH1cblxuXG4gIC8vIFBPUE9WRVIgUExVR0lOIERFRklOSVRJT05cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIGZ1bmN0aW9uIFBsdWdpbihvcHRpb24pIHtcbiAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkdGhpcyAgID0gJCh0aGlzKVxuICAgICAgdmFyIGRhdGEgICAgPSAkdGhpcy5kYXRhKCdicy5wb3BvdmVyJylcbiAgICAgIHZhciBvcHRpb25zID0gdHlwZW9mIG9wdGlvbiA9PSAnb2JqZWN0JyAmJiBvcHRpb25cblxuICAgICAgaWYgKCFkYXRhICYmIC9kZXN0cm95fGhpZGUvLnRlc3Qob3B0aW9uKSkgcmV0dXJuXG4gICAgICBpZiAoIWRhdGEpICR0aGlzLmRhdGEoJ2JzLnBvcG92ZXInLCAoZGF0YSA9IG5ldyBQb3BvdmVyKHRoaXMsIG9wdGlvbnMpKSlcbiAgICAgIGlmICh0eXBlb2Ygb3B0aW9uID09ICdzdHJpbmcnKSBkYXRhW29wdGlvbl0oKVxuICAgIH0pXG4gIH1cblxuICB2YXIgb2xkID0gJC5mbi5wb3BvdmVyXG5cbiAgJC5mbi5wb3BvdmVyICAgICAgICAgICAgID0gUGx1Z2luXG4gICQuZm4ucG9wb3Zlci5Db25zdHJ1Y3RvciA9IFBvcG92ZXJcblxuXG4gIC8vIFBPUE9WRVIgTk8gQ09ORkxJQ1RcbiAgLy8gPT09PT09PT09PT09PT09PT09PVxuXG4gICQuZm4ucG9wb3Zlci5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICQuZm4ucG9wb3ZlciA9IG9sZFxuICAgIHJldHVybiB0aGlzXG4gIH1cblxufShqUXVlcnkpO1xuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEJvb3RzdHJhcDogc2Nyb2xsc3B5LmpzIHYzLjQuMVxuICogaHR0cHM6Ly9nZXRib290c3RyYXAuY29tL2RvY3MvMy40L2phdmFzY3JpcHQvI3Njcm9sbHNweVxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb3B5cmlnaHQgMjAxMS0yMDE5IFR3aXR0ZXIsIEluYy5cbiAqIExpY2Vuc2VkIHVuZGVyIE1JVCAoaHR0cHM6Ly9naXRodWIuY29tL3R3YnMvYm9vdHN0cmFwL2Jsb2IvbWFzdGVyL0xJQ0VOU0UpXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0gKi9cblxuXG4rZnVuY3Rpb24gKCQpIHtcbiAgJ3VzZSBzdHJpY3QnO1xuXG4gIC8vIFNDUk9MTFNQWSBDTEFTUyBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgZnVuY3Rpb24gU2Nyb2xsU3B5KGVsZW1lbnQsIG9wdGlvbnMpIHtcbiAgICB0aGlzLiRib2R5ICAgICAgICAgID0gJChkb2N1bWVudC5ib2R5KVxuICAgIHRoaXMuJHNjcm9sbEVsZW1lbnQgPSAkKGVsZW1lbnQpLmlzKGRvY3VtZW50LmJvZHkpID8gJCh3aW5kb3cpIDogJChlbGVtZW50KVxuICAgIHRoaXMub3B0aW9ucyAgICAgICAgPSAkLmV4dGVuZCh7fSwgU2Nyb2xsU3B5LkRFRkFVTFRTLCBvcHRpb25zKVxuICAgIHRoaXMuc2VsZWN0b3IgICAgICAgPSAodGhpcy5vcHRpb25zLnRhcmdldCB8fCAnJykgKyAnIC5uYXYgbGkgPiBhJ1xuICAgIHRoaXMub2Zmc2V0cyAgICAgICAgPSBbXVxuICAgIHRoaXMudGFyZ2V0cyAgICAgICAgPSBbXVxuICAgIHRoaXMuYWN0aXZlVGFyZ2V0ICAgPSBudWxsXG4gICAgdGhpcy5zY3JvbGxIZWlnaHQgICA9IDBcblxuICAgIHRoaXMuJHNjcm9sbEVsZW1lbnQub24oJ3Njcm9sbC5icy5zY3JvbGxzcHknLCAkLnByb3h5KHRoaXMucHJvY2VzcywgdGhpcykpXG4gICAgdGhpcy5yZWZyZXNoKClcbiAgICB0aGlzLnByb2Nlc3MoKVxuICB9XG5cbiAgU2Nyb2xsU3B5LlZFUlNJT04gID0gJzMuNC4xJ1xuXG4gIFNjcm9sbFNweS5ERUZBVUxUUyA9IHtcbiAgICBvZmZzZXQ6IDEwXG4gIH1cblxuICBTY3JvbGxTcHkucHJvdG90eXBlLmdldFNjcm9sbEhlaWdodCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy4kc2Nyb2xsRWxlbWVudFswXS5zY3JvbGxIZWlnaHQgfHwgTWF0aC5tYXgodGhpcy4kYm9keVswXS5zY3JvbGxIZWlnaHQsIGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zY3JvbGxIZWlnaHQpXG4gIH1cblxuICBTY3JvbGxTcHkucHJvdG90eXBlLnJlZnJlc2ggPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHRoYXQgICAgICAgICAgPSB0aGlzXG4gICAgdmFyIG9mZnNldE1ldGhvZCAgPSAnb2Zmc2V0J1xuICAgIHZhciBvZmZzZXRCYXNlICAgID0gMFxuXG4gICAgdGhpcy5vZmZzZXRzICAgICAgPSBbXVxuICAgIHRoaXMudGFyZ2V0cyAgICAgID0gW11cbiAgICB0aGlzLnNjcm9sbEhlaWdodCA9IHRoaXMuZ2V0U2Nyb2xsSGVpZ2h0KClcblxuICAgIGlmICghJC5pc1dpbmRvdyh0aGlzLiRzY3JvbGxFbGVtZW50WzBdKSkge1xuICAgICAgb2Zmc2V0TWV0aG9kID0gJ3Bvc2l0aW9uJ1xuICAgICAgb2Zmc2V0QmFzZSAgID0gdGhpcy4kc2Nyb2xsRWxlbWVudC5zY3JvbGxUb3AoKVxuICAgIH1cblxuICAgIHRoaXMuJGJvZHlcbiAgICAgIC5maW5kKHRoaXMuc2VsZWN0b3IpXG4gICAgICAubWFwKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyICRlbCAgID0gJCh0aGlzKVxuICAgICAgICB2YXIgaHJlZiAgPSAkZWwuZGF0YSgndGFyZ2V0JykgfHwgJGVsLmF0dHIoJ2hyZWYnKVxuICAgICAgICB2YXIgJGhyZWYgPSAvXiMuLy50ZXN0KGhyZWYpICYmICQoaHJlZilcblxuICAgICAgICByZXR1cm4gKCRocmVmXG4gICAgICAgICAgJiYgJGhyZWYubGVuZ3RoXG4gICAgICAgICAgJiYgJGhyZWYuaXMoJzp2aXNpYmxlJylcbiAgICAgICAgICAmJiBbWyRocmVmW29mZnNldE1ldGhvZF0oKS50b3AgKyBvZmZzZXRCYXNlLCBocmVmXV0pIHx8IG51bGxcbiAgICAgIH0pXG4gICAgICAuc29ydChmdW5jdGlvbiAoYSwgYikgeyByZXR1cm4gYVswXSAtIGJbMF0gfSlcbiAgICAgIC5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhhdC5vZmZzZXRzLnB1c2godGhpc1swXSlcbiAgICAgICAgdGhhdC50YXJnZXRzLnB1c2godGhpc1sxXSlcbiAgICAgIH0pXG4gIH1cblxuICBTY3JvbGxTcHkucHJvdG90eXBlLnByb2Nlc3MgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHNjcm9sbFRvcCAgICA9IHRoaXMuJHNjcm9sbEVsZW1lbnQuc2Nyb2xsVG9wKCkgKyB0aGlzLm9wdGlvbnMub2Zmc2V0XG4gICAgdmFyIHNjcm9sbEhlaWdodCA9IHRoaXMuZ2V0U2Nyb2xsSGVpZ2h0KClcbiAgICB2YXIgbWF4U2Nyb2xsICAgID0gdGhpcy5vcHRpb25zLm9mZnNldCArIHNjcm9sbEhlaWdodCAtIHRoaXMuJHNjcm9sbEVsZW1lbnQuaGVpZ2h0KClcbiAgICB2YXIgb2Zmc2V0cyAgICAgID0gdGhpcy5vZmZzZXRzXG4gICAgdmFyIHRhcmdldHMgICAgICA9IHRoaXMudGFyZ2V0c1xuICAgIHZhciBhY3RpdmVUYXJnZXQgPSB0aGlzLmFjdGl2ZVRhcmdldFxuICAgIHZhciBpXG5cbiAgICBpZiAodGhpcy5zY3JvbGxIZWlnaHQgIT0gc2Nyb2xsSGVpZ2h0KSB7XG4gICAgICB0aGlzLnJlZnJlc2goKVxuICAgIH1cblxuICAgIGlmIChzY3JvbGxUb3AgPj0gbWF4U2Nyb2xsKSB7XG4gICAgICByZXR1cm4gYWN0aXZlVGFyZ2V0ICE9IChpID0gdGFyZ2V0c1t0YXJnZXRzLmxlbmd0aCAtIDFdKSAmJiB0aGlzLmFjdGl2YXRlKGkpXG4gICAgfVxuXG4gICAgaWYgKGFjdGl2ZVRhcmdldCAmJiBzY3JvbGxUb3AgPCBvZmZzZXRzWzBdKSB7XG4gICAgICB0aGlzLmFjdGl2ZVRhcmdldCA9IG51bGxcbiAgICAgIHJldHVybiB0aGlzLmNsZWFyKClcbiAgICB9XG5cbiAgICBmb3IgKGkgPSBvZmZzZXRzLmxlbmd0aDsgaS0tOykge1xuICAgICAgYWN0aXZlVGFyZ2V0ICE9IHRhcmdldHNbaV1cbiAgICAgICAgJiYgc2Nyb2xsVG9wID49IG9mZnNldHNbaV1cbiAgICAgICAgJiYgKG9mZnNldHNbaSArIDFdID09PSB1bmRlZmluZWQgfHwgc2Nyb2xsVG9wIDwgb2Zmc2V0c1tpICsgMV0pXG4gICAgICAgICYmIHRoaXMuYWN0aXZhdGUodGFyZ2V0c1tpXSlcbiAgICB9XG4gIH1cblxuICBTY3JvbGxTcHkucHJvdG90eXBlLmFjdGl2YXRlID0gZnVuY3Rpb24gKHRhcmdldCkge1xuICAgIHRoaXMuYWN0aXZlVGFyZ2V0ID0gdGFyZ2V0XG5cbiAgICB0aGlzLmNsZWFyKClcblxuICAgIHZhciBzZWxlY3RvciA9IHRoaXMuc2VsZWN0b3IgK1xuICAgICAgJ1tkYXRhLXRhcmdldD1cIicgKyB0YXJnZXQgKyAnXCJdLCcgK1xuICAgICAgdGhpcy5zZWxlY3RvciArICdbaHJlZj1cIicgKyB0YXJnZXQgKyAnXCJdJ1xuXG4gICAgdmFyIGFjdGl2ZSA9ICQoc2VsZWN0b3IpXG4gICAgICAucGFyZW50cygnbGknKVxuICAgICAgLmFkZENsYXNzKCdhY3RpdmUnKVxuXG4gICAgaWYgKGFjdGl2ZS5wYXJlbnQoJy5kcm9wZG93bi1tZW51JykubGVuZ3RoKSB7XG4gICAgICBhY3RpdmUgPSBhY3RpdmVcbiAgICAgICAgLmNsb3Nlc3QoJ2xpLmRyb3Bkb3duJylcbiAgICAgICAgLmFkZENsYXNzKCdhY3RpdmUnKVxuICAgIH1cblxuICAgIGFjdGl2ZS50cmlnZ2VyKCdhY3RpdmF0ZS5icy5zY3JvbGxzcHknKVxuICB9XG5cbiAgU2Nyb2xsU3B5LnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHtcbiAgICAkKHRoaXMuc2VsZWN0b3IpXG4gICAgICAucGFyZW50c1VudGlsKHRoaXMub3B0aW9ucy50YXJnZXQsICcuYWN0aXZlJylcbiAgICAgIC5yZW1vdmVDbGFzcygnYWN0aXZlJylcbiAgfVxuXG5cbiAgLy8gU0NST0xMU1BZIFBMVUdJTiBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIGZ1bmN0aW9uIFBsdWdpbihvcHRpb24pIHtcbiAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkdGhpcyAgID0gJCh0aGlzKVxuICAgICAgdmFyIGRhdGEgICAgPSAkdGhpcy5kYXRhKCdicy5zY3JvbGxzcHknKVxuICAgICAgdmFyIG9wdGlvbnMgPSB0eXBlb2Ygb3B0aW9uID09ICdvYmplY3QnICYmIG9wdGlvblxuXG4gICAgICBpZiAoIWRhdGEpICR0aGlzLmRhdGEoJ2JzLnNjcm9sbHNweScsIChkYXRhID0gbmV3IFNjcm9sbFNweSh0aGlzLCBvcHRpb25zKSkpXG4gICAgICBpZiAodHlwZW9mIG9wdGlvbiA9PSAnc3RyaW5nJykgZGF0YVtvcHRpb25dKClcbiAgICB9KVxuICB9XG5cbiAgdmFyIG9sZCA9ICQuZm4uc2Nyb2xsc3B5XG5cbiAgJC5mbi5zY3JvbGxzcHkgICAgICAgICAgICAgPSBQbHVnaW5cbiAgJC5mbi5zY3JvbGxzcHkuQ29uc3RydWN0b3IgPSBTY3JvbGxTcHlcblxuXG4gIC8vIFNDUk9MTFNQWSBOTyBDT05GTElDVFxuICAvLyA9PT09PT09PT09PT09PT09PT09PT1cblxuICAkLmZuLnNjcm9sbHNweS5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICQuZm4uc2Nyb2xsc3B5ID0gb2xkXG4gICAgcmV0dXJuIHRoaXNcbiAgfVxuXG5cbiAgLy8gU0NST0xMU1BZIERBVEEtQVBJXG4gIC8vID09PT09PT09PT09PT09PT09PVxuXG4gICQod2luZG93KS5vbignbG9hZC5icy5zY3JvbGxzcHkuZGF0YS1hcGknLCBmdW5jdGlvbiAoKSB7XG4gICAgJCgnW2RhdGEtc3B5PVwic2Nyb2xsXCJdJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgJHNweSA9ICQodGhpcylcbiAgICAgIFBsdWdpbi5jYWxsKCRzcHksICRzcHkuZGF0YSgpKVxuICAgIH0pXG4gIH0pXG5cbn0oalF1ZXJ5KTtcblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBCb290c3RyYXA6IHRhYi5qcyB2My40LjFcbiAqIGh0dHBzOi8vZ2V0Ym9vdHN0cmFwLmNvbS9kb2NzLzMuNC9qYXZhc2NyaXB0LyN0YWJzXG4gKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvcHlyaWdodCAyMDExLTIwMTkgVHdpdHRlciwgSW5jLlxuICogTGljZW5zZWQgdW5kZXIgTUlUIChodHRwczovL2dpdGh1Yi5jb20vdHdicy9ib290c3RyYXAvYmxvYi9tYXN0ZXIvTElDRU5TRSlcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSAqL1xuXG5cbitmdW5jdGlvbiAoJCkge1xuICAndXNlIHN0cmljdCc7XG5cbiAgLy8gVEFCIENMQVNTIERFRklOSVRJT05cbiAgLy8gPT09PT09PT09PT09PT09PT09PT1cblxuICB2YXIgVGFiID0gZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgICAvLyBqc2NzOmRpc2FibGUgcmVxdWlyZURvbGxhckJlZm9yZWpRdWVyeUFzc2lnbm1lbnRcbiAgICB0aGlzLmVsZW1lbnQgPSAkKGVsZW1lbnQpXG4gICAgLy8ganNjczplbmFibGUgcmVxdWlyZURvbGxhckJlZm9yZWpRdWVyeUFzc2lnbm1lbnRcbiAgfVxuXG4gIFRhYi5WRVJTSU9OID0gJzMuNC4xJ1xuXG4gIFRhYi5UUkFOU0lUSU9OX0RVUkFUSU9OID0gMTUwXG5cbiAgVGFiLnByb3RvdHlwZS5zaG93ID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciAkdGhpcyAgICA9IHRoaXMuZWxlbWVudFxuICAgIHZhciAkdWwgICAgICA9ICR0aGlzLmNsb3Nlc3QoJ3VsOm5vdCguZHJvcGRvd24tbWVudSknKVxuICAgIHZhciBzZWxlY3RvciA9ICR0aGlzLmRhdGEoJ3RhcmdldCcpXG5cbiAgICBpZiAoIXNlbGVjdG9yKSB7XG4gICAgICBzZWxlY3RvciA9ICR0aGlzLmF0dHIoJ2hyZWYnKVxuICAgICAgc2VsZWN0b3IgPSBzZWxlY3RvciAmJiBzZWxlY3Rvci5yZXBsYWNlKC8uKig/PSNbXlxcc10qJCkvLCAnJykgLy8gc3RyaXAgZm9yIGllN1xuICAgIH1cblxuICAgIGlmICgkdGhpcy5wYXJlbnQoJ2xpJykuaGFzQ2xhc3MoJ2FjdGl2ZScpKSByZXR1cm5cblxuICAgIHZhciAkcHJldmlvdXMgPSAkdWwuZmluZCgnLmFjdGl2ZTpsYXN0IGEnKVxuICAgIHZhciBoaWRlRXZlbnQgPSAkLkV2ZW50KCdoaWRlLmJzLnRhYicsIHtcbiAgICAgIHJlbGF0ZWRUYXJnZXQ6ICR0aGlzWzBdXG4gICAgfSlcbiAgICB2YXIgc2hvd0V2ZW50ID0gJC5FdmVudCgnc2hvdy5icy50YWInLCB7XG4gICAgICByZWxhdGVkVGFyZ2V0OiAkcHJldmlvdXNbMF1cbiAgICB9KVxuXG4gICAgJHByZXZpb3VzLnRyaWdnZXIoaGlkZUV2ZW50KVxuICAgICR0aGlzLnRyaWdnZXIoc2hvd0V2ZW50KVxuXG4gICAgaWYgKHNob3dFdmVudC5pc0RlZmF1bHRQcmV2ZW50ZWQoKSB8fCBoaWRlRXZlbnQuaXNEZWZhdWx0UHJldmVudGVkKCkpIHJldHVyblxuXG4gICAgdmFyICR0YXJnZXQgPSAkKGRvY3VtZW50KS5maW5kKHNlbGVjdG9yKVxuXG4gICAgdGhpcy5hY3RpdmF0ZSgkdGhpcy5jbG9zZXN0KCdsaScpLCAkdWwpXG4gICAgdGhpcy5hY3RpdmF0ZSgkdGFyZ2V0LCAkdGFyZ2V0LnBhcmVudCgpLCBmdW5jdGlvbiAoKSB7XG4gICAgICAkcHJldmlvdXMudHJpZ2dlcih7XG4gICAgICAgIHR5cGU6ICdoaWRkZW4uYnMudGFiJyxcbiAgICAgICAgcmVsYXRlZFRhcmdldDogJHRoaXNbMF1cbiAgICAgIH0pXG4gICAgICAkdGhpcy50cmlnZ2VyKHtcbiAgICAgICAgdHlwZTogJ3Nob3duLmJzLnRhYicsXG4gICAgICAgIHJlbGF0ZWRUYXJnZXQ6ICRwcmV2aW91c1swXVxuICAgICAgfSlcbiAgICB9KVxuICB9XG5cbiAgVGFiLnByb3RvdHlwZS5hY3RpdmF0ZSA9IGZ1bmN0aW9uIChlbGVtZW50LCBjb250YWluZXIsIGNhbGxiYWNrKSB7XG4gICAgdmFyICRhY3RpdmUgICAgPSBjb250YWluZXIuZmluZCgnPiAuYWN0aXZlJylcbiAgICB2YXIgdHJhbnNpdGlvbiA9IGNhbGxiYWNrXG4gICAgICAmJiAkLnN1cHBvcnQudHJhbnNpdGlvblxuICAgICAgJiYgKCRhY3RpdmUubGVuZ3RoICYmICRhY3RpdmUuaGFzQ2xhc3MoJ2ZhZGUnKSB8fCAhIWNvbnRhaW5lci5maW5kKCc+IC5mYWRlJykubGVuZ3RoKVxuXG4gICAgZnVuY3Rpb24gbmV4dCgpIHtcbiAgICAgICRhY3RpdmVcbiAgICAgICAgLnJlbW92ZUNsYXNzKCdhY3RpdmUnKVxuICAgICAgICAuZmluZCgnPiAuZHJvcGRvd24tbWVudSA+IC5hY3RpdmUnKVxuICAgICAgICAucmVtb3ZlQ2xhc3MoJ2FjdGl2ZScpXG4gICAgICAgIC5lbmQoKVxuICAgICAgICAuZmluZCgnW2RhdGEtdG9nZ2xlPVwidGFiXCJdJylcbiAgICAgICAgLmF0dHIoJ2FyaWEtZXhwYW5kZWQnLCBmYWxzZSlcblxuICAgICAgZWxlbWVudFxuICAgICAgICAuYWRkQ2xhc3MoJ2FjdGl2ZScpXG4gICAgICAgIC5maW5kKCdbZGF0YS10b2dnbGU9XCJ0YWJcIl0nKVxuICAgICAgICAuYXR0cignYXJpYS1leHBhbmRlZCcsIHRydWUpXG5cbiAgICAgIGlmICh0cmFuc2l0aW9uKSB7XG4gICAgICAgIGVsZW1lbnRbMF0ub2Zmc2V0V2lkdGggLy8gcmVmbG93IGZvciB0cmFuc2l0aW9uXG4gICAgICAgIGVsZW1lbnQuYWRkQ2xhc3MoJ2luJylcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGVsZW1lbnQucmVtb3ZlQ2xhc3MoJ2ZhZGUnKVxuICAgICAgfVxuXG4gICAgICBpZiAoZWxlbWVudC5wYXJlbnQoJy5kcm9wZG93bi1tZW51JykubGVuZ3RoKSB7XG4gICAgICAgIGVsZW1lbnRcbiAgICAgICAgICAuY2xvc2VzdCgnbGkuZHJvcGRvd24nKVxuICAgICAgICAgIC5hZGRDbGFzcygnYWN0aXZlJylcbiAgICAgICAgICAuZW5kKClcbiAgICAgICAgICAuZmluZCgnW2RhdGEtdG9nZ2xlPVwidGFiXCJdJylcbiAgICAgICAgICAuYXR0cignYXJpYS1leHBhbmRlZCcsIHRydWUpXG4gICAgICB9XG5cbiAgICAgIGNhbGxiYWNrICYmIGNhbGxiYWNrKClcbiAgICB9XG5cbiAgICAkYWN0aXZlLmxlbmd0aCAmJiB0cmFuc2l0aW9uID9cbiAgICAgICRhY3RpdmVcbiAgICAgICAgLm9uZSgnYnNUcmFuc2l0aW9uRW5kJywgbmV4dClcbiAgICAgICAgLmVtdWxhdGVUcmFuc2l0aW9uRW5kKFRhYi5UUkFOU0lUSU9OX0RVUkFUSU9OKSA6XG4gICAgICBuZXh0KClcblxuICAgICRhY3RpdmUucmVtb3ZlQ2xhc3MoJ2luJylcbiAgfVxuXG5cbiAgLy8gVEFCIFBMVUdJTiBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PVxuXG4gIGZ1bmN0aW9uIFBsdWdpbihvcHRpb24pIHtcbiAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciAkdGhpcyA9ICQodGhpcylcbiAgICAgIHZhciBkYXRhICA9ICR0aGlzLmRhdGEoJ2JzLnRhYicpXG5cbiAgICAgIGlmICghZGF0YSkgJHRoaXMuZGF0YSgnYnMudGFiJywgKGRhdGEgPSBuZXcgVGFiKHRoaXMpKSlcbiAgICAgIGlmICh0eXBlb2Ygb3B0aW9uID09ICdzdHJpbmcnKSBkYXRhW29wdGlvbl0oKVxuICAgIH0pXG4gIH1cblxuICB2YXIgb2xkID0gJC5mbi50YWJcblxuICAkLmZuLnRhYiAgICAgICAgICAgICA9IFBsdWdpblxuICAkLmZuLnRhYi5Db25zdHJ1Y3RvciA9IFRhYlxuXG5cbiAgLy8gVEFCIE5PIENPTkZMSUNUXG4gIC8vID09PT09PT09PT09PT09PVxuXG4gICQuZm4udGFiLm5vQ29uZmxpY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgJC5mbi50YWIgPSBvbGRcbiAgICByZXR1cm4gdGhpc1xuICB9XG5cblxuICAvLyBUQUIgREFUQS1BUElcbiAgLy8gPT09PT09PT09PT09XG5cbiAgdmFyIGNsaWNrSGFuZGxlciA9IGZ1bmN0aW9uIChlKSB7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpXG4gICAgUGx1Z2luLmNhbGwoJCh0aGlzKSwgJ3Nob3cnKVxuICB9XG5cbiAgJChkb2N1bWVudClcbiAgICAub24oJ2NsaWNrLmJzLnRhYi5kYXRhLWFwaScsICdbZGF0YS10b2dnbGU9XCJ0YWJcIl0nLCBjbGlja0hhbmRsZXIpXG4gICAgLm9uKCdjbGljay5icy50YWIuZGF0YS1hcGknLCAnW2RhdGEtdG9nZ2xlPVwicGlsbFwiXScsIGNsaWNrSGFuZGxlcilcblxufShqUXVlcnkpO1xuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEJvb3RzdHJhcDogYWZmaXguanMgdjMuNC4xXG4gKiBodHRwczovL2dldGJvb3RzdHJhcC5jb20vZG9jcy8zLjQvamF2YXNjcmlwdC8jYWZmaXhcbiAqID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29weXJpZ2h0IDIwMTEtMjAxOSBUd2l0dGVyLCBJbmMuXG4gKiBMaWNlbnNlZCB1bmRlciBNSVQgKGh0dHBzOi8vZ2l0aHViLmNvbS90d2JzL2Jvb3RzdHJhcC9ibG9iL21hc3Rlci9MSUNFTlNFKVxuICogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09ICovXG5cblxuK2Z1bmN0aW9uICgkKSB7XG4gICd1c2Ugc3RyaWN0JztcblxuICAvLyBBRkZJWCBDTEFTUyBERUZJTklUSU9OXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT1cblxuICB2YXIgQWZmaXggPSBmdW5jdGlvbiAoZWxlbWVudCwgb3B0aW9ucykge1xuICAgIHRoaXMub3B0aW9ucyA9ICQuZXh0ZW5kKHt9LCBBZmZpeC5ERUZBVUxUUywgb3B0aW9ucylcblxuICAgIHZhciB0YXJnZXQgPSB0aGlzLm9wdGlvbnMudGFyZ2V0ID09PSBBZmZpeC5ERUZBVUxUUy50YXJnZXQgPyAkKHRoaXMub3B0aW9ucy50YXJnZXQpIDogJChkb2N1bWVudCkuZmluZCh0aGlzLm9wdGlvbnMudGFyZ2V0KVxuXG4gICAgdGhpcy4kdGFyZ2V0ID0gdGFyZ2V0XG4gICAgICAub24oJ3Njcm9sbC5icy5hZmZpeC5kYXRhLWFwaScsICQucHJveHkodGhpcy5jaGVja1Bvc2l0aW9uLCB0aGlzKSlcbiAgICAgIC5vbignY2xpY2suYnMuYWZmaXguZGF0YS1hcGknLCAgJC5wcm94eSh0aGlzLmNoZWNrUG9zaXRpb25XaXRoRXZlbnRMb29wLCB0aGlzKSlcblxuICAgIHRoaXMuJGVsZW1lbnQgICAgID0gJChlbGVtZW50KVxuICAgIHRoaXMuYWZmaXhlZCAgICAgID0gbnVsbFxuICAgIHRoaXMudW5waW4gICAgICAgID0gbnVsbFxuICAgIHRoaXMucGlubmVkT2Zmc2V0ID0gbnVsbFxuXG4gICAgdGhpcy5jaGVja1Bvc2l0aW9uKClcbiAgfVxuXG4gIEFmZml4LlZFUlNJT04gID0gJzMuNC4xJ1xuXG4gIEFmZml4LlJFU0VUICAgID0gJ2FmZml4IGFmZml4LXRvcCBhZmZpeC1ib3R0b20nXG5cbiAgQWZmaXguREVGQVVMVFMgPSB7XG4gICAgb2Zmc2V0OiAwLFxuICAgIHRhcmdldDogd2luZG93XG4gIH1cblxuICBBZmZpeC5wcm90b3R5cGUuZ2V0U3RhdGUgPSBmdW5jdGlvbiAoc2Nyb2xsSGVpZ2h0LCBoZWlnaHQsIG9mZnNldFRvcCwgb2Zmc2V0Qm90dG9tKSB7XG4gICAgdmFyIHNjcm9sbFRvcCAgICA9IHRoaXMuJHRhcmdldC5zY3JvbGxUb3AoKVxuICAgIHZhciBwb3NpdGlvbiAgICAgPSB0aGlzLiRlbGVtZW50Lm9mZnNldCgpXG4gICAgdmFyIHRhcmdldEhlaWdodCA9IHRoaXMuJHRhcmdldC5oZWlnaHQoKVxuXG4gICAgaWYgKG9mZnNldFRvcCAhPSBudWxsICYmIHRoaXMuYWZmaXhlZCA9PSAndG9wJykgcmV0dXJuIHNjcm9sbFRvcCA8IG9mZnNldFRvcCA/ICd0b3AnIDogZmFsc2VcblxuICAgIGlmICh0aGlzLmFmZml4ZWQgPT0gJ2JvdHRvbScpIHtcbiAgICAgIGlmIChvZmZzZXRUb3AgIT0gbnVsbCkgcmV0dXJuIChzY3JvbGxUb3AgKyB0aGlzLnVucGluIDw9IHBvc2l0aW9uLnRvcCkgPyBmYWxzZSA6ICdib3R0b20nXG4gICAgICByZXR1cm4gKHNjcm9sbFRvcCArIHRhcmdldEhlaWdodCA8PSBzY3JvbGxIZWlnaHQgLSBvZmZzZXRCb3R0b20pID8gZmFsc2UgOiAnYm90dG9tJ1xuICAgIH1cblxuICAgIHZhciBpbml0aWFsaXppbmcgICA9IHRoaXMuYWZmaXhlZCA9PSBudWxsXG4gICAgdmFyIGNvbGxpZGVyVG9wICAgID0gaW5pdGlhbGl6aW5nID8gc2Nyb2xsVG9wIDogcG9zaXRpb24udG9wXG4gICAgdmFyIGNvbGxpZGVySGVpZ2h0ID0gaW5pdGlhbGl6aW5nID8gdGFyZ2V0SGVpZ2h0IDogaGVpZ2h0XG5cbiAgICBpZiAob2Zmc2V0VG9wICE9IG51bGwgJiYgc2Nyb2xsVG9wIDw9IG9mZnNldFRvcCkgcmV0dXJuICd0b3AnXG4gICAgaWYgKG9mZnNldEJvdHRvbSAhPSBudWxsICYmIChjb2xsaWRlclRvcCArIGNvbGxpZGVySGVpZ2h0ID49IHNjcm9sbEhlaWdodCAtIG9mZnNldEJvdHRvbSkpIHJldHVybiAnYm90dG9tJ1xuXG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cblxuICBBZmZpeC5wcm90b3R5cGUuZ2V0UGlubmVkT2Zmc2V0ID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLnBpbm5lZE9mZnNldCkgcmV0dXJuIHRoaXMucGlubmVkT2Zmc2V0XG4gICAgdGhpcy4kZWxlbWVudC5yZW1vdmVDbGFzcyhBZmZpeC5SRVNFVCkuYWRkQ2xhc3MoJ2FmZml4JylcbiAgICB2YXIgc2Nyb2xsVG9wID0gdGhpcy4kdGFyZ2V0LnNjcm9sbFRvcCgpXG4gICAgdmFyIHBvc2l0aW9uICA9IHRoaXMuJGVsZW1lbnQub2Zmc2V0KClcbiAgICByZXR1cm4gKHRoaXMucGlubmVkT2Zmc2V0ID0gcG9zaXRpb24udG9wIC0gc2Nyb2xsVG9wKVxuICB9XG5cbiAgQWZmaXgucHJvdG90eXBlLmNoZWNrUG9zaXRpb25XaXRoRXZlbnRMb29wID0gZnVuY3Rpb24gKCkge1xuICAgIHNldFRpbWVvdXQoJC5wcm94eSh0aGlzLmNoZWNrUG9zaXRpb24sIHRoaXMpLCAxKVxuICB9XG5cbiAgQWZmaXgucHJvdG90eXBlLmNoZWNrUG9zaXRpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKCF0aGlzLiRlbGVtZW50LmlzKCc6dmlzaWJsZScpKSByZXR1cm5cblxuICAgIHZhciBoZWlnaHQgICAgICAgPSB0aGlzLiRlbGVtZW50LmhlaWdodCgpXG4gICAgdmFyIG9mZnNldCAgICAgICA9IHRoaXMub3B0aW9ucy5vZmZzZXRcbiAgICB2YXIgb2Zmc2V0VG9wICAgID0gb2Zmc2V0LnRvcFxuICAgIHZhciBvZmZzZXRCb3R0b20gPSBvZmZzZXQuYm90dG9tXG4gICAgdmFyIHNjcm9sbEhlaWdodCA9IE1hdGgubWF4KCQoZG9jdW1lbnQpLmhlaWdodCgpLCAkKGRvY3VtZW50LmJvZHkpLmhlaWdodCgpKVxuXG4gICAgaWYgKHR5cGVvZiBvZmZzZXQgIT0gJ29iamVjdCcpICAgICAgICAgb2Zmc2V0Qm90dG9tID0gb2Zmc2V0VG9wID0gb2Zmc2V0XG4gICAgaWYgKHR5cGVvZiBvZmZzZXRUb3AgPT0gJ2Z1bmN0aW9uJykgICAgb2Zmc2V0VG9wICAgID0gb2Zmc2V0LnRvcCh0aGlzLiRlbGVtZW50KVxuICAgIGlmICh0eXBlb2Ygb2Zmc2V0Qm90dG9tID09ICdmdW5jdGlvbicpIG9mZnNldEJvdHRvbSA9IG9mZnNldC5ib3R0b20odGhpcy4kZWxlbWVudClcblxuICAgIHZhciBhZmZpeCA9IHRoaXMuZ2V0U3RhdGUoc2Nyb2xsSGVpZ2h0LCBoZWlnaHQsIG9mZnNldFRvcCwgb2Zmc2V0Qm90dG9tKVxuXG4gICAgaWYgKHRoaXMuYWZmaXhlZCAhPSBhZmZpeCkge1xuICAgICAgaWYgKHRoaXMudW5waW4gIT0gbnVsbCkgdGhpcy4kZWxlbWVudC5jc3MoJ3RvcCcsICcnKVxuXG4gICAgICB2YXIgYWZmaXhUeXBlID0gJ2FmZml4JyArIChhZmZpeCA/ICctJyArIGFmZml4IDogJycpXG4gICAgICB2YXIgZSAgICAgICAgID0gJC5FdmVudChhZmZpeFR5cGUgKyAnLmJzLmFmZml4JylcblxuICAgICAgdGhpcy4kZWxlbWVudC50cmlnZ2VyKGUpXG5cbiAgICAgIGlmIChlLmlzRGVmYXVsdFByZXZlbnRlZCgpKSByZXR1cm5cblxuICAgICAgdGhpcy5hZmZpeGVkID0gYWZmaXhcbiAgICAgIHRoaXMudW5waW4gPSBhZmZpeCA9PSAnYm90dG9tJyA/IHRoaXMuZ2V0UGlubmVkT2Zmc2V0KCkgOiBudWxsXG5cbiAgICAgIHRoaXMuJGVsZW1lbnRcbiAgICAgICAgLnJlbW92ZUNsYXNzKEFmZml4LlJFU0VUKVxuICAgICAgICAuYWRkQ2xhc3MoYWZmaXhUeXBlKVxuICAgICAgICAudHJpZ2dlcihhZmZpeFR5cGUucmVwbGFjZSgnYWZmaXgnLCAnYWZmaXhlZCcpICsgJy5icy5hZmZpeCcpXG4gICAgfVxuXG4gICAgaWYgKGFmZml4ID09ICdib3R0b20nKSB7XG4gICAgICB0aGlzLiRlbGVtZW50Lm9mZnNldCh7XG4gICAgICAgIHRvcDogc2Nyb2xsSGVpZ2h0IC0gaGVpZ2h0IC0gb2Zmc2V0Qm90dG9tXG4gICAgICB9KVxuICAgIH1cbiAgfVxuXG5cbiAgLy8gQUZGSVggUExVR0lOIERFRklOSVRJT05cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT1cblxuICBmdW5jdGlvbiBQbHVnaW4ob3B0aW9uKSB7XG4gICAgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgJHRoaXMgICA9ICQodGhpcylcbiAgICAgIHZhciBkYXRhICAgID0gJHRoaXMuZGF0YSgnYnMuYWZmaXgnKVxuICAgICAgdmFyIG9wdGlvbnMgPSB0eXBlb2Ygb3B0aW9uID09ICdvYmplY3QnICYmIG9wdGlvblxuXG4gICAgICBpZiAoIWRhdGEpICR0aGlzLmRhdGEoJ2JzLmFmZml4JywgKGRhdGEgPSBuZXcgQWZmaXgodGhpcywgb3B0aW9ucykpKVxuICAgICAgaWYgKHR5cGVvZiBvcHRpb24gPT0gJ3N0cmluZycpIGRhdGFbb3B0aW9uXSgpXG4gICAgfSlcbiAgfVxuXG4gIHZhciBvbGQgPSAkLmZuLmFmZml4XG5cbiAgJC5mbi5hZmZpeCAgICAgICAgICAgICA9IFBsdWdpblxuICAkLmZuLmFmZml4LkNvbnN0cnVjdG9yID0gQWZmaXhcblxuXG4gIC8vIEFGRklYIE5PIENPTkZMSUNUXG4gIC8vID09PT09PT09PT09PT09PT09XG5cbiAgJC5mbi5hZmZpeC5ub0NvbmZsaWN0ID0gZnVuY3Rpb24gKCkge1xuICAgICQuZm4uYWZmaXggPSBvbGRcbiAgICByZXR1cm4gdGhpc1xuICB9XG5cblxuICAvLyBBRkZJWCBEQVRBLUFQSVxuICAvLyA9PT09PT09PT09PT09PVxuXG4gICQod2luZG93KS5vbignbG9hZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAkKCdbZGF0YS1zcHk9XCJhZmZpeFwiXScpLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgdmFyICRzcHkgPSAkKHRoaXMpXG4gICAgICB2YXIgZGF0YSA9ICRzcHkuZGF0YSgpXG5cbiAgICAgIGRhdGEub2Zmc2V0ID0gZGF0YS5vZmZzZXQgfHwge31cblxuICAgICAgaWYgKGRhdGEub2Zmc2V0Qm90dG9tICE9IG51bGwpIGRhdGEub2Zmc2V0LmJvdHRvbSA9IGRhdGEub2Zmc2V0Qm90dG9tXG4gICAgICBpZiAoZGF0YS5vZmZzZXRUb3AgICAgIT0gbnVsbCkgZGF0YS5vZmZzZXQudG9wICAgID0gZGF0YS5vZmZzZXRUb3BcblxuICAgICAgUGx1Z2luLmNhbGwoJHNweSwgZGF0YSlcbiAgICB9KVxuICB9KVxuXG59KGpRdWVyeSk7XG4iLCIvKlxuICogalF1ZXJ5IElmcmFtZSBUcmFuc3BvcnQgUGx1Z2luXG4gKiBodHRwczovL2dpdGh1Yi5jb20vYmx1ZWltcC9qUXVlcnktRmlsZS1VcGxvYWRcbiAqXG4gKiBDb3B5cmlnaHQgMjAxMSwgU2ViYXN0aWFuIFRzY2hhblxuICogaHR0cHM6Ly9ibHVlaW1wLm5ldFxuICpcbiAqIExpY2Vuc2VkIHVuZGVyIHRoZSBNSVQgbGljZW5zZTpcbiAqIGh0dHBzOi8vb3BlbnNvdXJjZS5vcmcvbGljZW5zZXMvTUlUXG4gKi9cblxuLyogZ2xvYmFsIGRlZmluZSwgcmVxdWlyZSwgd2luZG93LCBkb2N1bWVudCwgSlNPTiAqL1xuXG47KGZ1bmN0aW9uIChmYWN0b3J5KSB7XG4gICAgJ3VzZSBzdHJpY3QnO1xuICAgIGlmICh0eXBlb2YgZGVmaW5lID09PSAnZnVuY3Rpb24nICYmIGRlZmluZS5hbWQpIHtcbiAgICAgICAgLy8gUmVnaXN0ZXIgYXMgYW4gYW5vbnltb3VzIEFNRCBtb2R1bGU6XG4gICAgICAgIGRlZmluZShbJ2pxdWVyeSddLCBmYWN0b3J5KTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBleHBvcnRzID09PSAnb2JqZWN0Jykge1xuICAgICAgICAvLyBOb2RlL0NvbW1vbkpTOlxuICAgICAgICBmYWN0b3J5KHJlcXVpcmUoJ2pxdWVyeScpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICAvLyBCcm93c2VyIGdsb2JhbHM6XG4gICAgICAgIGZhY3Rvcnkod2luZG93LmpRdWVyeSk7XG4gICAgfVxufShmdW5jdGlvbiAoJCkge1xuICAgICd1c2Ugc3RyaWN0JztcblxuICAgIC8vIEhlbHBlciB2YXJpYWJsZSB0byBjcmVhdGUgdW5pcXVlIG5hbWVzIGZvciB0aGUgdHJhbnNwb3J0IGlmcmFtZXM6XG4gICAgdmFyIGNvdW50ZXIgPSAwLFxuICAgICAgICBqc29uQVBJID0gJCxcbiAgICAgICAganNvblBhcnNlID0gJ3BhcnNlSlNPTic7XG5cbiAgICBpZiAoJ0pTT04nIGluIHdpbmRvdyAmJiAncGFyc2UnIGluIEpTT04pIHtcbiAgICAgIGpzb25BUEkgPSBKU09OO1xuICAgICAganNvblBhcnNlID0gJ3BhcnNlJztcbiAgICB9XG5cbiAgICAvLyBUaGUgaWZyYW1lIHRyYW5zcG9ydCBhY2NlcHRzIGZvdXIgYWRkaXRpb25hbCBvcHRpb25zOlxuICAgIC8vIG9wdGlvbnMuZmlsZUlucHV0OiBhIGpRdWVyeSBjb2xsZWN0aW9uIG9mIGZpbGUgaW5wdXQgZmllbGRzXG4gICAgLy8gb3B0aW9ucy5wYXJhbU5hbWU6IHRoZSBwYXJhbWV0ZXIgbmFtZSBmb3IgdGhlIGZpbGUgZm9ybSBkYXRhLFxuICAgIC8vICBvdmVycmlkZXMgdGhlIG5hbWUgcHJvcGVydHkgb2YgdGhlIGZpbGUgaW5wdXQgZmllbGQocyksXG4gICAgLy8gIGNhbiBiZSBhIHN0cmluZyBvciBhbiBhcnJheSBvZiBzdHJpbmdzLlxuICAgIC8vIG9wdGlvbnMuZm9ybURhdGE6IGFuIGFycmF5IG9mIG9iamVjdHMgd2l0aCBuYW1lIGFuZCB2YWx1ZSBwcm9wZXJ0aWVzLFxuICAgIC8vICBlcXVpdmFsZW50IHRvIHRoZSByZXR1cm4gZGF0YSBvZiAuc2VyaWFsaXplQXJyYXkoKSwgZS5nLjpcbiAgICAvLyAgW3tuYW1lOiAnYScsIHZhbHVlOiAxfSwge25hbWU6ICdiJywgdmFsdWU6IDJ9XVxuICAgIC8vIG9wdGlvbnMuaW5pdGlhbElmcmFtZVNyYzogdGhlIFVSTCBvZiB0aGUgaW5pdGlhbCBpZnJhbWUgc3JjLFxuICAgIC8vICBieSBkZWZhdWx0IHNldCB0byBcImphdmFzY3JpcHQ6ZmFsc2U7XCJcbiAgICAkLmFqYXhUcmFuc3BvcnQoJ2lmcmFtZScsIGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgIGlmIChvcHRpb25zLmFzeW5jKSB7XG4gICAgICAgICAgICAvLyBqYXZhc2NyaXB0OmZhbHNlIGFzIGluaXRpYWwgaWZyYW1lIHNyY1xuICAgICAgICAgICAgLy8gcHJldmVudHMgd2FybmluZyBwb3B1cHMgb24gSFRUUFMgaW4gSUU2OlxuICAgICAgICAgICAgLypqc2hpbnQgc2NyaXB0dXJsOiB0cnVlICovXG4gICAgICAgICAgICB2YXIgaW5pdGlhbElmcmFtZVNyYyA9IG9wdGlvbnMuaW5pdGlhbElmcmFtZVNyYyB8fCAnamF2YXNjcmlwdDpmYWxzZTsnLFxuICAgICAgICAgICAgLypqc2hpbnQgc2NyaXB0dXJsOiBmYWxzZSAqL1xuICAgICAgICAgICAgICAgIGZvcm0sXG4gICAgICAgICAgICAgICAgaWZyYW1lLFxuICAgICAgICAgICAgICAgIGFkZFBhcmFtQ2hhcjtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgc2VuZDogZnVuY3Rpb24gKF8sIGNvbXBsZXRlQ2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgZm9ybSA9ICQoJzxmb3JtIHN0eWxlPVwiZGlzcGxheTpub25lO1wiPjwvZm9ybT4nKTtcbiAgICAgICAgICAgICAgICAgICAgZm9ybS5hdHRyKCdhY2NlcHQtY2hhcnNldCcsIG9wdGlvbnMuZm9ybUFjY2VwdENoYXJzZXQpO1xuICAgICAgICAgICAgICAgICAgICBhZGRQYXJhbUNoYXIgPSAvXFw/Ly50ZXN0KG9wdGlvbnMudXJsKSA/ICcmJyA6ICc/JztcbiAgICAgICAgICAgICAgICAgICAgLy8gWERvbWFpblJlcXVlc3Qgb25seSBzdXBwb3J0cyBHRVQgYW5kIFBPU1Q6XG4gICAgICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLnR5cGUgPT09ICdERUxFVEUnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IG9wdGlvbnMudXJsICsgYWRkUGFyYW1DaGFyICsgJ19tZXRob2Q9REVMRVRFJztcbiAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMudHlwZSA9ICdQT1NUJztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zLnR5cGUgPT09ICdQVVQnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnVybCA9IG9wdGlvbnMudXJsICsgYWRkUGFyYW1DaGFyICsgJ19tZXRob2Q9UFVUJztcbiAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMudHlwZSA9ICdQT1NUJztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmIChvcHRpb25zLnR5cGUgPT09ICdQQVRDSCcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMudXJsID0gb3B0aW9ucy51cmwgKyBhZGRQYXJhbUNoYXIgKyAnX21ldGhvZD1QQVRDSCc7XG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnR5cGUgPSAnUE9TVCc7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLy8gSUUgdmVyc2lvbnMgYmVsb3cgSUU4IGNhbm5vdCBzZXQgdGhlIG5hbWUgcHJvcGVydHkgb2ZcbiAgICAgICAgICAgICAgICAgICAgLy8gZWxlbWVudHMgdGhhdCBoYXZlIGFscmVhZHkgYmVlbiBhZGRlZCB0byB0aGUgRE9NLFxuICAgICAgICAgICAgICAgICAgICAvLyBzbyB3ZSBzZXQgdGhlIG5hbWUgYWxvbmcgd2l0aCB0aGUgaWZyYW1lIEhUTUwgbWFya3VwOlxuICAgICAgICAgICAgICAgICAgICBjb3VudGVyICs9IDE7XG4gICAgICAgICAgICAgICAgICAgIGlmcmFtZSA9ICQoXG4gICAgICAgICAgICAgICAgICAgICAgICAnPGlmcmFtZSBzcmM9XCInICsgaW5pdGlhbElmcmFtZVNyYyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ1wiIG5hbWU9XCJpZnJhbWUtdHJhbnNwb3J0LScgKyBjb3VudGVyICsgJ1wiPjwvaWZyYW1lPidcbiAgICAgICAgICAgICAgICAgICAgKS5iaW5kKCdsb2FkJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZpbGVJbnB1dENsb25lcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBwYXJhbU5hbWVzID0gJC5pc0FycmF5KG9wdGlvbnMucGFyYW1OYW1lKSA/XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnBhcmFtTmFtZSA6IFtvcHRpb25zLnBhcmFtTmFtZV07XG4gICAgICAgICAgICAgICAgICAgICAgICBpZnJhbWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAudW5iaW5kKCdsb2FkJylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAuYmluZCgnbG9hZCcsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlc3BvbnNlO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBXcmFwIGluIGEgdHJ5L2NhdGNoIGJsb2NrIHRvIGNhdGNoIGV4Y2VwdGlvbnMgdGhyb3duXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHdoZW4gdHJ5aW5nIHRvIGFjY2VzcyBjcm9zcy1kb21haW4gaWZyYW1lIGNvbnRlbnRzOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2UgPSBpZnJhbWUuY29udGVudHMoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIEdvb2dsZSBDaHJvbWUgYW5kIEZpcmVmb3ggZG8gbm90IHRocm93IGFuXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBleGNlcHRpb24gd2hlbiBjYWxsaW5nIGlmcmFtZS5jb250ZW50cygpIG9uXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjcm9zcy1kb21haW4gcmVxdWVzdHMsIHNvIHdlIHVuaWZ5IHRoZSByZXNwb25zZTpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghcmVzcG9uc2UubGVuZ3RoIHx8ICFyZXNwb25zZVswXS5maXJzdENoaWxkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbnNlID0gdW5kZWZpbmVkO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSBjb21wbGV0ZSBjYWxsYmFjayByZXR1cm5zIHRoZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBpZnJhbWUgY29udGVudCBkb2N1bWVudCBhcyByZXNwb25zZSBvYmplY3Q6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbXBsZXRlQ2FsbGJhY2soXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAyMDAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnc3VjY2VzcycsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7J2lmcmFtZSc6IHJlc3BvbnNlfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGaXggZm9yIElFIGVuZGxlc3MgcHJvZ3Jlc3MgYmFyIGFjdGl2aXR5IGJ1Z1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyAoaGFwcGVucyBvbiBmb3JtIHN1Ym1pdHMgdG8gaWZyYW1lIHRhcmdldHMpOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAkKCc8aWZyYW1lIHNyYz1cIicgKyBpbml0aWFsSWZyYW1lU3JjICsgJ1wiPjwvaWZyYW1lPicpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuYXBwZW5kVG8oZm9ybSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlbW92aW5nIHRoZSBmb3JtIGluIGEgc2V0VGltZW91dCBjYWxsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBhbGxvd3MgQ2hyb21lJ3MgZGV2ZWxvcGVyIHRvb2xzIHRvIGRpc3BsYXlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHRoZSByZXNwb25zZSByZXN1bHRcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm0ucmVtb3ZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sIDApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9ybVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5wcm9wKCd0YXJnZXQnLCBpZnJhbWUucHJvcCgnbmFtZScpKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5wcm9wKCdhY3Rpb24nLCBvcHRpb25zLnVybClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAucHJvcCgnbWV0aG9kJywgb3B0aW9ucy50eXBlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmZvcm1EYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKG9wdGlvbnMuZm9ybURhdGEsIGZ1bmN0aW9uIChpbmRleCwgZmllbGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJCgnPGlucHV0IHR5cGU9XCJoaWRkZW5cIi8+JylcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5wcm9wKCduYW1lJywgZmllbGQubmFtZSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC52YWwoZmllbGQudmFsdWUpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAuYXBwZW5kVG8oZm9ybSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5maWxlSW5wdXQgJiYgb3B0aW9ucy5maWxlSW5wdXQubGVuZ3RoICYmXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMudHlwZSA9PT0gJ1BPU1QnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZUlucHV0Q2xvbmVzID0gb3B0aW9ucy5maWxlSW5wdXQuY2xvbmUoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBJbnNlcnQgYSBjbG9uZSBmb3IgZWFjaCBmaWxlIGlucHV0IGZpZWxkOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsZUlucHV0LmFmdGVyKGZ1bmN0aW9uIChpbmRleCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmlsZUlucHV0Q2xvbmVzW2luZGV4XTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5wYXJhbU5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5maWxlSW5wdXQuZWFjaChmdW5jdGlvbiAoaW5kZXgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQodGhpcykucHJvcChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAnbmFtZScsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lc1tpbmRleF0gfHwgb3B0aW9ucy5wYXJhbU5hbWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBBcHBlbmRpbmcgdGhlIGZpbGUgaW5wdXQgZmllbGRzIHRvIHRoZSBoaWRkZW4gZm9ybVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIHJlbW92ZXMgdGhlbSBmcm9tIHRoZWlyIG9yaWdpbmFsIGxvY2F0aW9uOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLmFwcGVuZChvcHRpb25zLmZpbGVJbnB1dClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnByb3AoJ2VuY3R5cGUnLCAnbXVsdGlwYXJ0L2Zvcm0tZGF0YScpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGVuY3R5cGUgbXVzdCBiZSBzZXQgYXMgZW5jb2RpbmcgZm9yIElFOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucHJvcCgnZW5jb2RpbmcnLCAnbXVsdGlwYXJ0L2Zvcm0tZGF0YScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFJlbW92ZSB0aGUgSFRNTDUgZm9ybSBhdHRyaWJ1dGUgZnJvbSB0aGUgaW5wdXQocyk6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5maWxlSW5wdXQucmVtb3ZlQXR0cignZm9ybScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZm9ybS5zdWJtaXQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEluc2VydCB0aGUgZmlsZSBpbnB1dCBmaWVsZHMgYXQgdGhlaXIgb3JpZ2luYWwgbG9jYXRpb25cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJ5IHJlcGxhY2luZyB0aGUgY2xvbmVzIHdpdGggdGhlIG9yaWdpbmFsczpcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChmaWxlSW5wdXRDbG9uZXMgJiYgZmlsZUlucHV0Q2xvbmVzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsZUlucHV0LmVhY2goZnVuY3Rpb24gKGluZGV4LCBpbnB1dCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgY2xvbmUgPSAkKGZpbGVJbnB1dENsb25lc1tpbmRleF0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBSZXN0b3JlIHRoZSBvcmlnaW5hbCBuYW1lIGFuZCBmb3JtIHByb3BlcnRpZXM6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoaW5wdXQpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAucHJvcCgnbmFtZScsIGNsb25lLnByb3AoJ25hbWUnKSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5hdHRyKCdmb3JtJywgY2xvbmUuYXR0cignZm9ybScpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xvbmUucmVwbGFjZVdpdGgoaW5wdXQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZm9ybS5hcHBlbmQoaWZyYW1lKS5hcHBlbmRUbyhkb2N1bWVudC5ib2R5KTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGFib3J0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChpZnJhbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGphdmFzY3JpcHQ6ZmFsc2UgYXMgaWZyYW1lIHNyYyBhYm9ydHMgdGhlIHJlcXVlc3RcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFuZCBwcmV2ZW50cyB3YXJuaW5nIHBvcHVwcyBvbiBIVFRQUyBpbiBJRTYuXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBjb25jYXQgaXMgdXNlZCB0byBhdm9pZCB0aGUgXCJTY3JpcHQgVVJMXCIgSlNMaW50IGVycm9yOlxuICAgICAgICAgICAgICAgICAgICAgICAgaWZyYW1lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnVuYmluZCgnbG9hZCcpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnByb3AoJ3NyYycsIGluaXRpYWxJZnJhbWVTcmMpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChmb3JtKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3JtLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgLy8gVGhlIGlmcmFtZSB0cmFuc3BvcnQgcmV0dXJucyB0aGUgaWZyYW1lIGNvbnRlbnQgZG9jdW1lbnQgYXMgcmVzcG9uc2UuXG4gICAgLy8gVGhlIGZvbGxvd2luZyBhZGRzIGNvbnZlcnRlcnMgZnJvbSBpZnJhbWUgdG8gdGV4dCwganNvbiwgaHRtbCwgeG1sXG4gICAgLy8gYW5kIHNjcmlwdC5cbiAgICAvLyBQbGVhc2Ugbm90ZSB0aGF0IHRoZSBDb250ZW50LVR5cGUgZm9yIEpTT04gcmVzcG9uc2VzIGhhcyB0byBiZSB0ZXh0L3BsYWluXG4gICAgLy8gb3IgdGV4dC9odG1sLCBpZiB0aGUgYnJvd3NlciBkb2Vzbid0IGluY2x1ZGUgYXBwbGljYXRpb24vanNvbiBpbiB0aGVcbiAgICAvLyBBY2NlcHQgaGVhZGVyLCBlbHNlIElFIHdpbGwgc2hvdyBhIGRvd25sb2FkIGRpYWxvZy5cbiAgICAvLyBUaGUgQ29udGVudC1UeXBlIGZvciBYTUwgcmVzcG9uc2VzIG9uIHRoZSBvdGhlciBoYW5kIGhhcyB0byBiZSBhbHdheXNcbiAgICAvLyBhcHBsaWNhdGlvbi94bWwgb3IgdGV4dC94bWwsIHNvIElFIHByb3Blcmx5IHBhcnNlcyB0aGUgWE1MIHJlc3BvbnNlLlxuICAgIC8vIFNlZSBhbHNvXG4gICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2JsdWVpbXAvalF1ZXJ5LUZpbGUtVXBsb2FkL3dpa2kvU2V0dXAjY29udGVudC10eXBlLW5lZ290aWF0aW9uXG4gICAgJC5hamF4U2V0dXAoe1xuICAgICAgICBjb252ZXJ0ZXJzOiB7XG4gICAgICAgICAgICAnaWZyYW1lIHRleHQnOiBmdW5jdGlvbiAoaWZyYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGlmcmFtZSAmJiAkKGlmcmFtZVswXS5ib2R5KS50ZXh0KCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgJ2lmcmFtZSBqc29uJzogZnVuY3Rpb24gKGlmcmFtZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpZnJhbWUgJiYganNvbkFQSVtqc29uUGFyc2VdKCQoaWZyYW1lWzBdLmJvZHkpLnRleHQoKSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgJ2lmcmFtZSBodG1sJzogZnVuY3Rpb24gKGlmcmFtZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBpZnJhbWUgJiYgJChpZnJhbWVbMF0uYm9keSkuaHRtbCgpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICdpZnJhbWUgeG1sJzogZnVuY3Rpb24gKGlmcmFtZSkge1xuICAgICAgICAgICAgICAgIHZhciB4bWxEb2MgPSBpZnJhbWUgJiYgaWZyYW1lWzBdO1xuICAgICAgICAgICAgICAgIHJldHVybiB4bWxEb2MgJiYgJC5pc1hNTERvYyh4bWxEb2MpID8geG1sRG9jIDpcbiAgICAgICAgICAgICAgICAgICAgICAgICQucGFyc2VYTUwoKHhtbERvYy5YTUxEb2N1bWVudCAmJiB4bWxEb2MuWE1MRG9jdW1lbnQueG1sKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoeG1sRG9jLmJvZHkpLmh0bWwoKSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgJ2lmcmFtZSBzY3JpcHQnOiBmdW5jdGlvbiAoaWZyYW1lKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGlmcmFtZSAmJiAkLmdsb2JhbEV2YWwoJChpZnJhbWVbMF0uYm9keSkudGV4dCgpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0pO1xuXG59KSk7XG4iLCIvKlxuICogalF1ZXJ5IEZpbGUgVXBsb2FkIFBsdWdpblxuICogaHR0cHM6Ly9naXRodWIuY29tL2JsdWVpbXAvalF1ZXJ5LUZpbGUtVXBsb2FkXG4gKlxuICogQ29weXJpZ2h0IDIwMTAsIFNlYmFzdGlhbiBUc2NoYW5cbiAqIGh0dHBzOi8vYmx1ZWltcC5uZXRcbiAqXG4gKiBMaWNlbnNlZCB1bmRlciB0aGUgTUlUIGxpY2Vuc2U6XG4gKiBodHRwczovL29wZW5zb3VyY2Uub3JnL2xpY2Vuc2VzL01JVFxuICovXG5cbi8qIGpzaGludCBub21lbjpmYWxzZSAqL1xuLyogZ2xvYmFsIGRlZmluZSwgcmVxdWlyZSwgd2luZG93LCBkb2N1bWVudCwgbG9jYXRpb24sIEJsb2IsIEZvcm1EYXRhICovXG5cbjsoZnVuY3Rpb24gKGZhY3RvcnkpIHtcbiAgICAndXNlIHN0cmljdCc7XG4gICAgaWYgKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xuICAgICAgICAvLyBSZWdpc3RlciBhcyBhbiBhbm9ueW1vdXMgQU1EIG1vZHVsZTpcbiAgICAgICAgZGVmaW5lKFtcbiAgICAgICAgICAgICdqcXVlcnknLFxuICAgICAgICAgICAgJ2pxdWVyeS11aS91aS93aWRnZXQnXG4gICAgICAgIF0sIGZhY3RvcnkpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIGV4cG9ydHMgPT09ICdvYmplY3QnKSB7XG4gICAgICAgIC8vIE5vZGUvQ29tbW9uSlM6XG4gICAgICAgIGZhY3RvcnkoXG4gICAgICAgICAgICByZXF1aXJlKCdqcXVlcnknKSxcbiAgICAgICAgICAgIHJlcXVpcmUoJy4vdmVuZG9yL2pxdWVyeS51aS53aWRnZXQnKVxuICAgICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIC8vIEJyb3dzZXIgZ2xvYmFsczpcbiAgICAgICAgZmFjdG9yeSh3aW5kb3cualF1ZXJ5KTtcbiAgICB9XG59KGZ1bmN0aW9uICgkKSB7XG4gICAgJ3VzZSBzdHJpY3QnO1xuXG4gICAgLy8gRGV0ZWN0IGZpbGUgaW5wdXQgc3VwcG9ydCwgYmFzZWQgb25cbiAgICAvLyBodHRwOi8vdmlsamFtaXMuY29tL2Jsb2cvMjAxMi9maWxlLXVwbG9hZC1zdXBwb3J0LW9uLW1vYmlsZS9cbiAgICAkLnN1cHBvcnQuZmlsZUlucHV0ID0gIShuZXcgUmVnRXhwKFxuICAgICAgICAvLyBIYW5kbGUgZGV2aWNlcyB3aGljaCBnaXZlIGZhbHNlIHBvc2l0aXZlcyBmb3IgdGhlIGZlYXR1cmUgZGV0ZWN0aW9uOlxuICAgICAgICAnKEFuZHJvaWQgKDFcXFxcLlswMTU2XXwyXFxcXC5bMDFdKSknICtcbiAgICAgICAgICAgICd8KFdpbmRvd3MgUGhvbmUgKE9TIDd8OFxcXFwuMCkpfChYQkxXUCl8KFp1bmVXUCl8KFdQRGVza3RvcCknICtcbiAgICAgICAgICAgICd8KHcoZWIpP09TQnJvd3Nlcil8KHdlYk9TKScgK1xuICAgICAgICAgICAgJ3woS2luZGxlLygxXFxcXC4wfDJcXFxcLlswNV18M1xcXFwuMCkpJ1xuICAgICkudGVzdCh3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudCkgfHxcbiAgICAgICAgLy8gRmVhdHVyZSBkZXRlY3Rpb24gZm9yIGFsbCBvdGhlciBkZXZpY2VzOlxuICAgICAgICAkKCc8aW5wdXQgdHlwZT1cImZpbGVcIi8+JykucHJvcCgnZGlzYWJsZWQnKSk7XG5cbiAgICAvLyBUaGUgRmlsZVJlYWRlciBBUEkgaXMgbm90IGFjdHVhbGx5IHVzZWQsIGJ1dCB3b3JrcyBhcyBmZWF0dXJlIGRldGVjdGlvbixcbiAgICAvLyBhcyBzb21lIFNhZmFyaSB2ZXJzaW9ucyAoNT8pIHN1cHBvcnQgWEhSIGZpbGUgdXBsb2FkcyB2aWEgdGhlIEZvcm1EYXRhIEFQSSxcbiAgICAvLyBidXQgbm90IG5vbi1tdWx0aXBhcnQgWEhSIGZpbGUgdXBsb2Fkcy5cbiAgICAvLyB3aW5kb3cuWE1MSHR0cFJlcXVlc3RVcGxvYWQgaXMgbm90IGF2YWlsYWJsZSBvbiBJRTEwLCBzbyB3ZSBjaGVjayBmb3JcbiAgICAvLyB3aW5kb3cuUHJvZ3Jlc3NFdmVudCBpbnN0ZWFkIHRvIGRldGVjdCBYSFIyIGZpbGUgdXBsb2FkIGNhcGFiaWxpdHk6XG4gICAgJC5zdXBwb3J0LnhockZpbGVVcGxvYWQgPSAhISh3aW5kb3cuUHJvZ3Jlc3NFdmVudCAmJiB3aW5kb3cuRmlsZVJlYWRlcik7XG4gICAgJC5zdXBwb3J0LnhockZvcm1EYXRhRmlsZVVwbG9hZCA9ICEhd2luZG93LkZvcm1EYXRhO1xuXG4gICAgLy8gRGV0ZWN0IHN1cHBvcnQgZm9yIEJsb2Igc2xpY2luZyAocmVxdWlyZWQgZm9yIGNodW5rZWQgdXBsb2Fkcyk6XG4gICAgJC5zdXBwb3J0LmJsb2JTbGljZSA9IHdpbmRvdy5CbG9iICYmIChCbG9iLnByb3RvdHlwZS5zbGljZSB8fFxuICAgICAgICBCbG9iLnByb3RvdHlwZS53ZWJraXRTbGljZSB8fCBCbG9iLnByb3RvdHlwZS5tb3pTbGljZSk7XG5cbiAgICAvLyBIZWxwZXIgZnVuY3Rpb24gdG8gY3JlYXRlIGRyYWcgaGFuZGxlcnMgZm9yIGRyYWdvdmVyL2RyYWdlbnRlci9kcmFnbGVhdmU6XG4gICAgZnVuY3Rpb24gZ2V0RHJhZ0hhbmRsZXIodHlwZSkge1xuICAgICAgICB2YXIgaXNEcmFnT3ZlciA9IHR5cGUgPT09ICdkcmFnb3Zlcic7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgZS5kYXRhVHJhbnNmZXIgPSBlLm9yaWdpbmFsRXZlbnQgJiYgZS5vcmlnaW5hbEV2ZW50LmRhdGFUcmFuc2ZlcjtcbiAgICAgICAgICAgIHZhciBkYXRhVHJhbnNmZXIgPSBlLmRhdGFUcmFuc2ZlcjtcbiAgICAgICAgICAgIGlmIChkYXRhVHJhbnNmZXIgJiYgJC5pbkFycmF5KCdGaWxlcycsIGRhdGFUcmFuc2Zlci50eXBlcykgIT09IC0xICYmXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3RyaWdnZXIoXG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlLFxuICAgICAgICAgICAgICAgICAgICAgICAgJC5FdmVudCh0eXBlLCB7ZGVsZWdhdGVkRXZlbnQ6IGV9KVxuICAgICAgICAgICAgICAgICAgICApICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICBpZiAoaXNEcmFnT3Zlcikge1xuICAgICAgICAgICAgICAgICAgICBkYXRhVHJhbnNmZXIuZHJvcEVmZmVjdCA9ICdjb3B5JztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gVGhlIGZpbGV1cGxvYWQgd2lkZ2V0IGxpc3RlbnMgZm9yIGNoYW5nZSBldmVudHMgb24gZmlsZSBpbnB1dCBmaWVsZHMgZGVmaW5lZFxuICAgIC8vIHZpYSBmaWxlSW5wdXQgc2V0dGluZyBhbmQgcGFzdGUgb3IgZHJvcCBldmVudHMgb2YgdGhlIGdpdmVuIGRyb3Bab25lLlxuICAgIC8vIEluIGFkZGl0aW9uIHRvIHRoZSBkZWZhdWx0IGpRdWVyeSBXaWRnZXQgbWV0aG9kcywgdGhlIGZpbGV1cGxvYWQgd2lkZ2V0XG4gICAgLy8gZXhwb3NlcyB0aGUgXCJhZGRcIiBhbmQgXCJzZW5kXCIgbWV0aG9kcywgdG8gYWRkIG9yIGRpcmVjdGx5IHNlbmQgZmlsZXMgdXNpbmdcbiAgICAvLyB0aGUgZmlsZXVwbG9hZCBBUEkuXG4gICAgLy8gQnkgZGVmYXVsdCwgZmlsZXMgYWRkZWQgdmlhIGZpbGUgaW5wdXQgc2VsZWN0aW9uLCBwYXN0ZSwgZHJhZyAmIGRyb3Agb3JcbiAgICAvLyBcImFkZFwiIG1ldGhvZCBhcmUgdXBsb2FkZWQgaW1tZWRpYXRlbHksIGJ1dCBpdCBpcyBwb3NzaWJsZSB0byBvdmVycmlkZVxuICAgIC8vIHRoZSBcImFkZFwiIGNhbGxiYWNrIG9wdGlvbiB0byBxdWV1ZSBmaWxlIHVwbG9hZHMuXG4gICAgJC53aWRnZXQoJ2JsdWVpbXAuZmlsZXVwbG9hZCcsIHtcblxuICAgICAgICBvcHRpb25zOiB7XG4gICAgICAgICAgICAvLyBUaGUgZHJvcCB0YXJnZXQgZWxlbWVudChzKSwgYnkgdGhlIGRlZmF1bHQgdGhlIGNvbXBsZXRlIGRvY3VtZW50LlxuICAgICAgICAgICAgLy8gU2V0IHRvIG51bGwgdG8gZGlzYWJsZSBkcmFnICYgZHJvcCBzdXBwb3J0OlxuICAgICAgICAgICAgZHJvcFpvbmU6ICQoZG9jdW1lbnQpLFxuICAgICAgICAgICAgLy8gVGhlIHBhc3RlIHRhcmdldCBlbGVtZW50KHMpLCBieSB0aGUgZGVmYXVsdCB1bmRlZmluZWQuXG4gICAgICAgICAgICAvLyBTZXQgdG8gYSBET00gbm9kZSBvciBqUXVlcnkgb2JqZWN0IHRvIGVuYWJsZSBmaWxlIHBhc3Rpbmc6XG4gICAgICAgICAgICBwYXN0ZVpvbmU6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIC8vIFRoZSBmaWxlIGlucHV0IGZpZWxkKHMpLCB0aGF0IGFyZSBsaXN0ZW5lZCB0byBmb3IgY2hhbmdlIGV2ZW50cy5cbiAgICAgICAgICAgIC8vIElmIHVuZGVmaW5lZCwgaXQgaXMgc2V0IHRvIHRoZSBmaWxlIGlucHV0IGZpZWxkcyBpbnNpZGVcbiAgICAgICAgICAgIC8vIG9mIHRoZSB3aWRnZXQgZWxlbWVudCBvbiBwbHVnaW4gaW5pdGlhbGl6YXRpb24uXG4gICAgICAgICAgICAvLyBTZXQgdG8gbnVsbCB0byBkaXNhYmxlIHRoZSBjaGFuZ2UgbGlzdGVuZXIuXG4gICAgICAgICAgICBmaWxlSW5wdXQ6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIC8vIEJ5IGRlZmF1bHQsIHRoZSBmaWxlIGlucHV0IGZpZWxkIGlzIHJlcGxhY2VkIHdpdGggYSBjbG9uZSBhZnRlclxuICAgICAgICAgICAgLy8gZWFjaCBpbnB1dCBmaWVsZCBjaGFuZ2UgZXZlbnQuIFRoaXMgaXMgcmVxdWlyZWQgZm9yIGlmcmFtZSB0cmFuc3BvcnRcbiAgICAgICAgICAgIC8vIHF1ZXVlcyBhbmQgYWxsb3dzIGNoYW5nZSBldmVudHMgdG8gYmUgZmlyZWQgZm9yIHRoZSBzYW1lIGZpbGVcbiAgICAgICAgICAgIC8vIHNlbGVjdGlvbiwgYnV0IGNhbiBiZSBkaXNhYmxlZCBieSBzZXR0aW5nIHRoZSBmb2xsb3dpbmcgb3B0aW9uIHRvIGZhbHNlOlxuICAgICAgICAgICAgcmVwbGFjZUZpbGVJbnB1dDogdHJ1ZSxcbiAgICAgICAgICAgIC8vIFRoZSBwYXJhbWV0ZXIgbmFtZSBmb3IgdGhlIGZpbGUgZm9ybSBkYXRhICh0aGUgcmVxdWVzdCBhcmd1bWVudCBuYW1lKS5cbiAgICAgICAgICAgIC8vIElmIHVuZGVmaW5lZCBvciBlbXB0eSwgdGhlIG5hbWUgcHJvcGVydHkgb2YgdGhlIGZpbGUgaW5wdXQgZmllbGQgaXNcbiAgICAgICAgICAgIC8vIHVzZWQsIG9yIFwiZmlsZXNbXVwiIGlmIHRoZSBmaWxlIGlucHV0IG5hbWUgcHJvcGVydHkgaXMgYWxzbyBlbXB0eSxcbiAgICAgICAgICAgIC8vIGNhbiBiZSBhIHN0cmluZyBvciBhbiBhcnJheSBvZiBzdHJpbmdzOlxuICAgICAgICAgICAgcGFyYW1OYW1lOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAvLyBCeSBkZWZhdWx0LCBlYWNoIGZpbGUgb2YgYSBzZWxlY3Rpb24gaXMgdXBsb2FkZWQgdXNpbmcgYW4gaW5kaXZpZHVhbFxuICAgICAgICAgICAgLy8gcmVxdWVzdCBmb3IgWEhSIHR5cGUgdXBsb2Fkcy4gU2V0IHRvIGZhbHNlIHRvIHVwbG9hZCBmaWxlXG4gICAgICAgICAgICAvLyBzZWxlY3Rpb25zIGluIG9uZSByZXF1ZXN0IGVhY2g6XG4gICAgICAgICAgICBzaW5nbGVGaWxlVXBsb2FkczogdHJ1ZSxcbiAgICAgICAgICAgIC8vIFRvIGxpbWl0IHRoZSBudW1iZXIgb2YgZmlsZXMgdXBsb2FkZWQgd2l0aCBvbmUgWEhSIHJlcXVlc3QsXG4gICAgICAgICAgICAvLyBzZXQgdGhlIGZvbGxvd2luZyBvcHRpb24gdG8gYW4gaW50ZWdlciBncmVhdGVyIHRoYW4gMDpcbiAgICAgICAgICAgIGxpbWl0TXVsdGlGaWxlVXBsb2FkczogdW5kZWZpbmVkLFxuICAgICAgICAgICAgLy8gVGhlIGZvbGxvd2luZyBvcHRpb24gbGltaXRzIHRoZSBudW1iZXIgb2YgZmlsZXMgdXBsb2FkZWQgd2l0aCBvbmVcbiAgICAgICAgICAgIC8vIFhIUiByZXF1ZXN0IHRvIGtlZXAgdGhlIHJlcXVlc3Qgc2l6ZSB1bmRlciBvciBlcXVhbCB0byB0aGUgZGVmaW5lZFxuICAgICAgICAgICAgLy8gbGltaXQgaW4gYnl0ZXM6XG4gICAgICAgICAgICBsaW1pdE11bHRpRmlsZVVwbG9hZFNpemU6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIC8vIE11bHRpcGFydCBmaWxlIHVwbG9hZHMgYWRkIGEgbnVtYmVyIG9mIGJ5dGVzIHRvIGVhY2ggdXBsb2FkZWQgZmlsZSxcbiAgICAgICAgICAgIC8vIHRoZXJlZm9yZSB0aGUgZm9sbG93aW5nIG9wdGlvbiBhZGRzIGFuIG92ZXJoZWFkIGZvciBlYWNoIGZpbGUgdXNlZFxuICAgICAgICAgICAgLy8gaW4gdGhlIGxpbWl0TXVsdGlGaWxlVXBsb2FkU2l6ZSBjb25maWd1cmF0aW9uOlxuICAgICAgICAgICAgbGltaXRNdWx0aUZpbGVVcGxvYWRTaXplT3ZlcmhlYWQ6IDUxMixcbiAgICAgICAgICAgIC8vIFNldCB0aGUgZm9sbG93aW5nIG9wdGlvbiB0byB0cnVlIHRvIGlzc3VlIGFsbCBmaWxlIHVwbG9hZCByZXF1ZXN0c1xuICAgICAgICAgICAgLy8gaW4gYSBzZXF1ZW50aWFsIG9yZGVyOlxuICAgICAgICAgICAgc2VxdWVudGlhbFVwbG9hZHM6IGZhbHNlLFxuICAgICAgICAgICAgLy8gVG8gbGltaXQgdGhlIG51bWJlciBvZiBjb25jdXJyZW50IHVwbG9hZHMsXG4gICAgICAgICAgICAvLyBzZXQgdGhlIGZvbGxvd2luZyBvcHRpb24gdG8gYW4gaW50ZWdlciBncmVhdGVyIHRoYW4gMDpcbiAgICAgICAgICAgIGxpbWl0Q29uY3VycmVudFVwbG9hZHM6IHVuZGVmaW5lZCxcbiAgICAgICAgICAgIC8vIFNldCB0aGUgZm9sbG93aW5nIG9wdGlvbiB0byB0cnVlIHRvIGZvcmNlIGlmcmFtZSB0cmFuc3BvcnQgdXBsb2FkczpcbiAgICAgICAgICAgIGZvcmNlSWZyYW1lVHJhbnNwb3J0OiBmYWxzZSxcbiAgICAgICAgICAgIC8vIFNldCB0aGUgZm9sbG93aW5nIG9wdGlvbiB0byB0aGUgbG9jYXRpb24gb2YgYSByZWRpcmVjdCB1cmwgb24gdGhlXG4gICAgICAgICAgICAvLyBvcmlnaW4gc2VydmVyLCBmb3IgY3Jvc3MtZG9tYWluIGlmcmFtZSB0cmFuc3BvcnQgdXBsb2FkczpcbiAgICAgICAgICAgIHJlZGlyZWN0OiB1bmRlZmluZWQsXG4gICAgICAgICAgICAvLyBUaGUgcGFyYW1ldGVyIG5hbWUgZm9yIHRoZSByZWRpcmVjdCB1cmwsIHNlbnQgYXMgcGFydCBvZiB0aGUgZm9ybVxuICAgICAgICAgICAgLy8gZGF0YSBhbmQgc2V0IHRvICdyZWRpcmVjdCcgaWYgdGhpcyBvcHRpb24gaXMgZW1wdHk6XG4gICAgICAgICAgICByZWRpcmVjdFBhcmFtTmFtZTogdW5kZWZpbmVkLFxuICAgICAgICAgICAgLy8gU2V0IHRoZSBmb2xsb3dpbmcgb3B0aW9uIHRvIHRoZSBsb2NhdGlvbiBvZiBhIHBvc3RNZXNzYWdlIHdpbmRvdyxcbiAgICAgICAgICAgIC8vIHRvIGVuYWJsZSBwb3N0TWVzc2FnZSB0cmFuc3BvcnQgdXBsb2FkczpcbiAgICAgICAgICAgIHBvc3RNZXNzYWdlOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAvLyBCeSBkZWZhdWx0LCBYSFIgZmlsZSB1cGxvYWRzIGFyZSBzZW50IGFzIG11bHRpcGFydC9mb3JtLWRhdGEuXG4gICAgICAgICAgICAvLyBUaGUgaWZyYW1lIHRyYW5zcG9ydCBpcyBhbHdheXMgdXNpbmcgbXVsdGlwYXJ0L2Zvcm0tZGF0YS5cbiAgICAgICAgICAgIC8vIFNldCB0byBmYWxzZSB0byBlbmFibGUgbm9uLW11bHRpcGFydCBYSFIgdXBsb2FkczpcbiAgICAgICAgICAgIG11bHRpcGFydDogdHJ1ZSxcbiAgICAgICAgICAgIC8vIFRvIHVwbG9hZCBsYXJnZSBmaWxlcyBpbiBzbWFsbGVyIGNodW5rcywgc2V0IHRoZSBmb2xsb3dpbmcgb3B0aW9uXG4gICAgICAgICAgICAvLyB0byBhIHByZWZlcnJlZCBtYXhpbXVtIGNodW5rIHNpemUuIElmIHNldCB0byAwLCBudWxsIG9yIHVuZGVmaW5lZCxcbiAgICAgICAgICAgIC8vIG9yIHRoZSBicm93c2VyIGRvZXMgbm90IHN1cHBvcnQgdGhlIHJlcXVpcmVkIEJsb2IgQVBJLCBmaWxlcyB3aWxsXG4gICAgICAgICAgICAvLyBiZSB1cGxvYWRlZCBhcyBhIHdob2xlLlxuICAgICAgICAgICAgbWF4Q2h1bmtTaXplOiB1bmRlZmluZWQsXG4gICAgICAgICAgICAvLyBXaGVuIGEgbm9uLW11bHRpcGFydCB1cGxvYWQgb3IgYSBjaHVua2VkIG11bHRpcGFydCB1cGxvYWQgaGFzIGJlZW5cbiAgICAgICAgICAgIC8vIGFib3J0ZWQsIHRoaXMgb3B0aW9uIGNhbiBiZSB1c2VkIHRvIHJlc3VtZSB0aGUgdXBsb2FkIGJ5IHNldHRpbmdcbiAgICAgICAgICAgIC8vIGl0IHRvIHRoZSBzaXplIG9mIHRoZSBhbHJlYWR5IHVwbG9hZGVkIGJ5dGVzLiBUaGlzIG9wdGlvbiBpcyBtb3N0XG4gICAgICAgICAgICAvLyB1c2VmdWwgd2hlbiBtb2RpZnlpbmcgdGhlIG9wdGlvbnMgb2JqZWN0IGluc2lkZSBvZiB0aGUgXCJhZGRcIiBvclxuICAgICAgICAgICAgLy8gXCJzZW5kXCIgY2FsbGJhY2tzLCBhcyB0aGUgb3B0aW9ucyBhcmUgY2xvbmVkIGZvciBlYWNoIGZpbGUgdXBsb2FkLlxuICAgICAgICAgICAgdXBsb2FkZWRCeXRlczogdW5kZWZpbmVkLFxuICAgICAgICAgICAgLy8gQnkgZGVmYXVsdCwgZmFpbGVkIChhYm9ydCBvciBlcnJvcikgZmlsZSB1cGxvYWRzIGFyZSByZW1vdmVkIGZyb20gdGhlXG4gICAgICAgICAgICAvLyBnbG9iYWwgcHJvZ3Jlc3MgY2FsY3VsYXRpb24uIFNldCB0aGUgZm9sbG93aW5nIG9wdGlvbiB0byBmYWxzZSB0b1xuICAgICAgICAgICAgLy8gcHJldmVudCByZWNhbGN1bGF0aW5nIHRoZSBnbG9iYWwgcHJvZ3Jlc3MgZGF0YTpcbiAgICAgICAgICAgIHJlY2FsY3VsYXRlUHJvZ3Jlc3M6IHRydWUsXG4gICAgICAgICAgICAvLyBJbnRlcnZhbCBpbiBtaWxsaXNlY29uZHMgdG8gY2FsY3VsYXRlIGFuZCB0cmlnZ2VyIHByb2dyZXNzIGV2ZW50czpcbiAgICAgICAgICAgIHByb2dyZXNzSW50ZXJ2YWw6IDEwMCxcbiAgICAgICAgICAgIC8vIEludGVydmFsIGluIG1pbGxpc2Vjb25kcyB0byBjYWxjdWxhdGUgcHJvZ3Jlc3MgYml0cmF0ZTpcbiAgICAgICAgICAgIGJpdHJhdGVJbnRlcnZhbDogNTAwLFxuICAgICAgICAgICAgLy8gQnkgZGVmYXVsdCwgdXBsb2FkcyBhcmUgc3RhcnRlZCBhdXRvbWF0aWNhbGx5IHdoZW4gYWRkaW5nIGZpbGVzOlxuICAgICAgICAgICAgYXV0b1VwbG9hZDogdHJ1ZSxcblxuICAgICAgICAgICAgLy8gRXJyb3IgYW5kIGluZm8gbWVzc2FnZXM6XG4gICAgICAgICAgICBtZXNzYWdlczoge1xuICAgICAgICAgICAgICAgIHVwbG9hZGVkQnl0ZXM6ICdVcGxvYWRlZCBieXRlcyBleGNlZWQgZmlsZSBzaXplJ1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgLy8gVHJhbnNsYXRpb24gZnVuY3Rpb24sIGdldHMgdGhlIG1lc3NhZ2Uga2V5IHRvIGJlIHRyYW5zbGF0ZWRcbiAgICAgICAgICAgIC8vIGFuZCBhbiBvYmplY3Qgd2l0aCBjb250ZXh0IHNwZWNpZmljIGRhdGEgYXMgYXJndW1lbnRzOlxuICAgICAgICAgICAgaTE4bjogZnVuY3Rpb24gKG1lc3NhZ2UsIGNvbnRleHQpIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlID0gdGhpcy5tZXNzYWdlc1ttZXNzYWdlXSB8fCBtZXNzYWdlLnRvU3RyaW5nKCk7XG4gICAgICAgICAgICAgICAgaWYgKGNvbnRleHQpIHtcbiAgICAgICAgICAgICAgICAgICAgJC5lYWNoKGNvbnRleHQsIGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtZXNzYWdlID0gbWVzc2FnZS5yZXBsYWNlKCd7JyArIGtleSArICd9JywgdmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIG1lc3NhZ2U7XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICAvLyBBZGRpdGlvbmFsIGZvcm0gZGF0YSB0byBiZSBzZW50IGFsb25nIHdpdGggdGhlIGZpbGUgdXBsb2FkcyBjYW4gYmUgc2V0XG4gICAgICAgICAgICAvLyB1c2luZyB0aGlzIG9wdGlvbiwgd2hpY2ggYWNjZXB0cyBhbiBhcnJheSBvZiBvYmplY3RzIHdpdGggbmFtZSBhbmRcbiAgICAgICAgICAgIC8vIHZhbHVlIHByb3BlcnRpZXMsIGEgZnVuY3Rpb24gcmV0dXJuaW5nIHN1Y2ggYW4gYXJyYXksIGEgRm9ybURhdGFcbiAgICAgICAgICAgIC8vIG9iamVjdCAoZm9yIFhIUiBmaWxlIHVwbG9hZHMpLCBvciBhIHNpbXBsZSBvYmplY3QuXG4gICAgICAgICAgICAvLyBUaGUgZm9ybSBvZiB0aGUgZmlyc3QgZmlsZUlucHV0IGlzIGdpdmVuIGFzIHBhcmFtZXRlciB0byB0aGUgZnVuY3Rpb246XG4gICAgICAgICAgICBmb3JtRGF0YTogZnVuY3Rpb24gKGZvcm0pIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZm9ybS5zZXJpYWxpemVBcnJheSgpO1xuICAgICAgICAgICAgfSxcblxuICAgICAgICAgICAgLy8gVGhlIGFkZCBjYWxsYmFjayBpcyBpbnZva2VkIGFzIHNvb24gYXMgZmlsZXMgYXJlIGFkZGVkIHRvIHRoZSBmaWxldXBsb2FkXG4gICAgICAgICAgICAvLyB3aWRnZXQgKHZpYSBmaWxlIGlucHV0IHNlbGVjdGlvbiwgZHJhZyAmIGRyb3AsIHBhc3RlIG9yIGFkZCBBUEkgY2FsbCkuXG4gICAgICAgICAgICAvLyBJZiB0aGUgc2luZ2xlRmlsZVVwbG9hZHMgb3B0aW9uIGlzIGVuYWJsZWQsIHRoaXMgY2FsbGJhY2sgd2lsbCBiZVxuICAgICAgICAgICAgLy8gY2FsbGVkIG9uY2UgZm9yIGVhY2ggZmlsZSBpbiB0aGUgc2VsZWN0aW9uIGZvciBYSFIgZmlsZSB1cGxvYWRzLCBlbHNlXG4gICAgICAgICAgICAvLyBvbmNlIGZvciBlYWNoIGZpbGUgc2VsZWN0aW9uLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIFRoZSB1cGxvYWQgc3RhcnRzIHdoZW4gdGhlIHN1Ym1pdCBtZXRob2QgaXMgaW52b2tlZCBvbiB0aGUgZGF0YSBwYXJhbWV0ZXIuXG4gICAgICAgICAgICAvLyBUaGUgZGF0YSBvYmplY3QgY29udGFpbnMgYSBmaWxlcyBwcm9wZXJ0eSBob2xkaW5nIHRoZSBhZGRlZCBmaWxlc1xuICAgICAgICAgICAgLy8gYW5kIGFsbG93cyB5b3UgdG8gb3ZlcnJpZGUgcGx1Z2luIG9wdGlvbnMgYXMgd2VsbCBhcyBkZWZpbmUgYWpheCBzZXR0aW5ncy5cbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyBMaXN0ZW5lcnMgZm9yIHRoaXMgY2FsbGJhY2sgY2FuIGFsc28gYmUgYm91bmQgdGhlIGZvbGxvd2luZyB3YXk6XG4gICAgICAgICAgICAvLyAuYmluZCgnZmlsZXVwbG9hZGFkZCcsIGZ1bmMpO1xuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIGRhdGEuc3VibWl0KCkgcmV0dXJucyBhIFByb21pc2Ugb2JqZWN0IGFuZCBhbGxvd3MgdG8gYXR0YWNoIGFkZGl0aW9uYWxcbiAgICAgICAgICAgIC8vIGhhbmRsZXJzIHVzaW5nIGpRdWVyeSdzIERlZmVycmVkIGNhbGxiYWNrczpcbiAgICAgICAgICAgIC8vIGRhdGEuc3VibWl0KCkuZG9uZShmdW5jKS5mYWlsKGZ1bmMpLmFsd2F5cyhmdW5jKTtcbiAgICAgICAgICAgIGFkZDogZnVuY3Rpb24gKGUsIGRhdGEpIHtcbiAgICAgICAgICAgICAgICBpZiAoZS5pc0RlZmF1bHRQcmV2ZW50ZWQoKSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChkYXRhLmF1dG9VcGxvYWQgfHwgKGRhdGEuYXV0b1VwbG9hZCAhPT0gZmFsc2UgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICQodGhpcykuZmlsZXVwbG9hZCgnb3B0aW9uJywgJ2F1dG9VcGxvYWQnKSkpIHtcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5wcm9jZXNzKCkuZG9uZShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhLnN1Ym1pdCgpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuXG4gICAgICAgICAgICAvLyBPdGhlciBjYWxsYmFja3M6XG5cbiAgICAgICAgICAgIC8vIENhbGxiYWNrIGZvciB0aGUgc3VibWl0IGV2ZW50IG9mIGVhY2ggZmlsZSB1cGxvYWQ6XG4gICAgICAgICAgICAvLyBzdWJtaXQ6IGZ1bmN0aW9uIChlLCBkYXRhKSB7fSwgLy8gLmJpbmQoJ2ZpbGV1cGxvYWRzdWJtaXQnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gQ2FsbGJhY2sgZm9yIHRoZSBzdGFydCBvZiBlYWNoIGZpbGUgdXBsb2FkIHJlcXVlc3Q6XG4gICAgICAgICAgICAvLyBzZW5kOiBmdW5jdGlvbiAoZSwgZGF0YSkge30sIC8vIC5iaW5kKCdmaWxldXBsb2Fkc2VuZCcsIGZ1bmMpO1xuXG4gICAgICAgICAgICAvLyBDYWxsYmFjayBmb3Igc3VjY2Vzc2Z1bCB1cGxvYWRzOlxuICAgICAgICAgICAgLy8gZG9uZTogZnVuY3Rpb24gKGUsIGRhdGEpIHt9LCAvLyAuYmluZCgnZmlsZXVwbG9hZGRvbmUnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gQ2FsbGJhY2sgZm9yIGZhaWxlZCAoYWJvcnQgb3IgZXJyb3IpIHVwbG9hZHM6XG4gICAgICAgICAgICAvLyBmYWlsOiBmdW5jdGlvbiAoZSwgZGF0YSkge30sIC8vIC5iaW5kKCdmaWxldXBsb2FkZmFpbCcsIGZ1bmMpO1xuXG4gICAgICAgICAgICAvLyBDYWxsYmFjayBmb3IgY29tcGxldGVkIChzdWNjZXNzLCBhYm9ydCBvciBlcnJvcikgcmVxdWVzdHM6XG4gICAgICAgICAgICAvLyBhbHdheXM6IGZ1bmN0aW9uIChlLCBkYXRhKSB7fSwgLy8gLmJpbmQoJ2ZpbGV1cGxvYWRhbHdheXMnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gQ2FsbGJhY2sgZm9yIHVwbG9hZCBwcm9ncmVzcyBldmVudHM6XG4gICAgICAgICAgICAvLyBwcm9ncmVzczogZnVuY3Rpb24gKGUsIGRhdGEpIHt9LCAvLyAuYmluZCgnZmlsZXVwbG9hZHByb2dyZXNzJywgZnVuYyk7XG5cbiAgICAgICAgICAgIC8vIENhbGxiYWNrIGZvciBnbG9iYWwgdXBsb2FkIHByb2dyZXNzIGV2ZW50czpcbiAgICAgICAgICAgIC8vIHByb2dyZXNzYWxsOiBmdW5jdGlvbiAoZSwgZGF0YSkge30sIC8vIC5iaW5kKCdmaWxldXBsb2FkcHJvZ3Jlc3NhbGwnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gQ2FsbGJhY2sgZm9yIHVwbG9hZHMgc3RhcnQsIGVxdWl2YWxlbnQgdG8gdGhlIGdsb2JhbCBhamF4U3RhcnQgZXZlbnQ6XG4gICAgICAgICAgICAvLyBzdGFydDogZnVuY3Rpb24gKGUpIHt9LCAvLyAuYmluZCgnZmlsZXVwbG9hZHN0YXJ0JywgZnVuYyk7XG5cbiAgICAgICAgICAgIC8vIENhbGxiYWNrIGZvciB1cGxvYWRzIHN0b3AsIGVxdWl2YWxlbnQgdG8gdGhlIGdsb2JhbCBhamF4U3RvcCBldmVudDpcbiAgICAgICAgICAgIC8vIHN0b3A6IGZ1bmN0aW9uIChlKSB7fSwgLy8gLmJpbmQoJ2ZpbGV1cGxvYWRzdG9wJywgZnVuYyk7XG5cbiAgICAgICAgICAgIC8vIENhbGxiYWNrIGZvciBjaGFuZ2UgZXZlbnRzIG9mIHRoZSBmaWxlSW5wdXQocyk6XG4gICAgICAgICAgICAvLyBjaGFuZ2U6IGZ1bmN0aW9uIChlLCBkYXRhKSB7fSwgLy8gLmJpbmQoJ2ZpbGV1cGxvYWRjaGFuZ2UnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gQ2FsbGJhY2sgZm9yIHBhc3RlIGV2ZW50cyB0byB0aGUgcGFzdGVab25lKHMpOlxuICAgICAgICAgICAgLy8gcGFzdGU6IGZ1bmN0aW9uIChlLCBkYXRhKSB7fSwgLy8gLmJpbmQoJ2ZpbGV1cGxvYWRwYXN0ZScsIGZ1bmMpO1xuXG4gICAgICAgICAgICAvLyBDYWxsYmFjayBmb3IgZHJvcCBldmVudHMgb2YgdGhlIGRyb3Bab25lKHMpOlxuICAgICAgICAgICAgLy8gZHJvcDogZnVuY3Rpb24gKGUsIGRhdGEpIHt9LCAvLyAuYmluZCgnZmlsZXVwbG9hZGRyb3AnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gQ2FsbGJhY2sgZm9yIGRyYWdvdmVyIGV2ZW50cyBvZiB0aGUgZHJvcFpvbmUocyk6XG4gICAgICAgICAgICAvLyBkcmFnb3ZlcjogZnVuY3Rpb24gKGUpIHt9LCAvLyAuYmluZCgnZmlsZXVwbG9hZGRyYWdvdmVyJywgZnVuYyk7XG5cbiAgICAgICAgICAgIC8vIENhbGxiYWNrIGJlZm9yZSB0aGUgc3RhcnQgb2YgZWFjaCBjaHVuayB1cGxvYWQgcmVxdWVzdCAoYmVmb3JlIGZvcm0gZGF0YSBpbml0aWFsaXphdGlvbik6XG4gICAgICAgICAgICAvLyBjaHVua2JlZm9yZXNlbmQ6IGZ1bmN0aW9uIChlLCBkYXRhKSB7fSwgLy8gLmJpbmQoJ2ZpbGV1cGxvYWRjaHVua2JlZm9yZXNlbmQnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gQ2FsbGJhY2sgZm9yIHRoZSBzdGFydCBvZiBlYWNoIGNodW5rIHVwbG9hZCByZXF1ZXN0OlxuICAgICAgICAgICAgLy8gY2h1bmtzZW5kOiBmdW5jdGlvbiAoZSwgZGF0YSkge30sIC8vIC5iaW5kKCdmaWxldXBsb2FkY2h1bmtzZW5kJywgZnVuYyk7XG5cbiAgICAgICAgICAgIC8vIENhbGxiYWNrIGZvciBzdWNjZXNzZnVsIGNodW5rIHVwbG9hZHM6XG4gICAgICAgICAgICAvLyBjaHVua2RvbmU6IGZ1bmN0aW9uIChlLCBkYXRhKSB7fSwgLy8gLmJpbmQoJ2ZpbGV1cGxvYWRjaHVua2RvbmUnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gQ2FsbGJhY2sgZm9yIGZhaWxlZCAoYWJvcnQgb3IgZXJyb3IpIGNodW5rIHVwbG9hZHM6XG4gICAgICAgICAgICAvLyBjaHVua2ZhaWw6IGZ1bmN0aW9uIChlLCBkYXRhKSB7fSwgLy8gLmJpbmQoJ2ZpbGV1cGxvYWRjaHVua2ZhaWwnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gQ2FsbGJhY2sgZm9yIGNvbXBsZXRlZCAoc3VjY2VzcywgYWJvcnQgb3IgZXJyb3IpIGNodW5rIHVwbG9hZCByZXF1ZXN0czpcbiAgICAgICAgICAgIC8vIGNodW5rYWx3YXlzOiBmdW5jdGlvbiAoZSwgZGF0YSkge30sIC8vIC5iaW5kKCdmaWxldXBsb2FkY2h1bmthbHdheXMnLCBmdW5jKTtcblxuICAgICAgICAgICAgLy8gVGhlIHBsdWdpbiBvcHRpb25zIGFyZSB1c2VkIGFzIHNldHRpbmdzIG9iamVjdCBmb3IgdGhlIGFqYXggY2FsbHMuXG4gICAgICAgICAgICAvLyBUaGUgZm9sbG93aW5nIGFyZSBqUXVlcnkgYWpheCBzZXR0aW5ncyByZXF1aXJlZCBmb3IgdGhlIGZpbGUgdXBsb2FkczpcbiAgICAgICAgICAgIHByb2Nlc3NEYXRhOiBmYWxzZSxcbiAgICAgICAgICAgIGNvbnRlbnRUeXBlOiBmYWxzZSxcbiAgICAgICAgICAgIGNhY2hlOiBmYWxzZSxcbiAgICAgICAgICAgIHRpbWVvdXQ6IDBcbiAgICAgICAgfSxcblxuICAgICAgICAvLyBBIGxpc3Qgb2Ygb3B0aW9ucyB0aGF0IHJlcXVpcmUgcmVpbml0aWFsaXppbmcgZXZlbnQgbGlzdGVuZXJzIGFuZC9vclxuICAgICAgICAvLyBzcGVjaWFsIGluaXRpYWxpemF0aW9uIGNvZGU6XG4gICAgICAgIF9zcGVjaWFsT3B0aW9uczogW1xuICAgICAgICAgICAgJ2ZpbGVJbnB1dCcsXG4gICAgICAgICAgICAnZHJvcFpvbmUnLFxuICAgICAgICAgICAgJ3Bhc3RlWm9uZScsXG4gICAgICAgICAgICAnbXVsdGlwYXJ0JyxcbiAgICAgICAgICAgICdmb3JjZUlmcmFtZVRyYW5zcG9ydCdcbiAgICAgICAgXSxcblxuICAgICAgICBfYmxvYlNsaWNlOiAkLnN1cHBvcnQuYmxvYlNsaWNlICYmIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBzbGljZSA9IHRoaXMuc2xpY2UgfHwgdGhpcy53ZWJraXRTbGljZSB8fCB0aGlzLm1velNsaWNlO1xuICAgICAgICAgICAgcmV0dXJuIHNsaWNlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgX0JpdHJhdGVUaW1lcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdGhpcy50aW1lc3RhbXAgPSAoKERhdGUubm93KSA/IERhdGUubm93KCkgOiAobmV3IERhdGUoKSkuZ2V0VGltZSgpKTtcbiAgICAgICAgICAgIHRoaXMubG9hZGVkID0gMDtcbiAgICAgICAgICAgIHRoaXMuYml0cmF0ZSA9IDA7XG4gICAgICAgICAgICB0aGlzLmdldEJpdHJhdGUgPSBmdW5jdGlvbiAobm93LCBsb2FkZWQsIGludGVydmFsKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRpbWVEaWZmID0gbm93IC0gdGhpcy50aW1lc3RhbXA7XG4gICAgICAgICAgICAgICAgaWYgKCF0aGlzLmJpdHJhdGUgfHwgIWludGVydmFsIHx8IHRpbWVEaWZmID4gaW50ZXJ2YWwpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5iaXRyYXRlID0gKGxvYWRlZCAtIHRoaXMubG9hZGVkKSAqICgxMDAwIC8gdGltZURpZmYpICogODtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5sb2FkZWQgPSBsb2FkZWQ7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudGltZXN0YW1wID0gbm93O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5iaXRyYXRlO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfSxcblxuICAgICAgICBfaXNYSFJVcGxvYWQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gIW9wdGlvbnMuZm9yY2VJZnJhbWVUcmFuc3BvcnQgJiZcbiAgICAgICAgICAgICAgICAoKCFvcHRpb25zLm11bHRpcGFydCAmJiAkLnN1cHBvcnQueGhyRmlsZVVwbG9hZCkgfHxcbiAgICAgICAgICAgICAgICAkLnN1cHBvcnQueGhyRm9ybURhdGFGaWxlVXBsb2FkKTtcbiAgICAgICAgfSxcblxuICAgICAgICBfZ2V0Rm9ybURhdGE6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZm9ybURhdGE7XG4gICAgICAgICAgICBpZiAoJC50eXBlKG9wdGlvbnMuZm9ybURhdGEpID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG9wdGlvbnMuZm9ybURhdGEob3B0aW9ucy5mb3JtKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICgkLmlzQXJyYXkob3B0aW9ucy5mb3JtRGF0YSkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gb3B0aW9ucy5mb3JtRGF0YTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICgkLnR5cGUob3B0aW9ucy5mb3JtRGF0YSkgPT09ICdvYmplY3QnKSB7XG4gICAgICAgICAgICAgICAgZm9ybURhdGEgPSBbXTtcbiAgICAgICAgICAgICAgICAkLmVhY2gob3B0aW9ucy5mb3JtRGF0YSwgZnVuY3Rpb24gKG5hbWUsIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvcm1EYXRhLnB1c2goe25hbWU6IG5hbWUsIHZhbHVlOiB2YWx1ZX0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHJldHVybiBmb3JtRGF0YTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBbXTtcbiAgICAgICAgfSxcblxuICAgICAgICBfZ2V0VG90YWw6IGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgdmFyIHRvdGFsID0gMDtcbiAgICAgICAgICAgICQuZWFjaChmaWxlcywgZnVuY3Rpb24gKGluZGV4LCBmaWxlKSB7XG4gICAgICAgICAgICAgICAgdG90YWwgKz0gZmlsZS5zaXplIHx8IDE7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiB0b3RhbDtcbiAgICAgICAgfSxcblxuICAgICAgICBfaW5pdFByb2dyZXNzT2JqZWN0OiBmdW5jdGlvbiAob2JqKSB7XG4gICAgICAgICAgICB2YXIgcHJvZ3Jlc3MgPSB7XG4gICAgICAgICAgICAgICAgbG9hZGVkOiAwLFxuICAgICAgICAgICAgICAgIHRvdGFsOiAwLFxuICAgICAgICAgICAgICAgIGJpdHJhdGU6IDBcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAob2JqLl9wcm9ncmVzcykge1xuICAgICAgICAgICAgICAgICQuZXh0ZW5kKG9iai5fcHJvZ3Jlc3MsIHByb2dyZXNzKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgb2JqLl9wcm9ncmVzcyA9IHByb2dyZXNzO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIF9pbml0UmVzcG9uc2VPYmplY3Q6IGZ1bmN0aW9uIChvYmopIHtcbiAgICAgICAgICAgIHZhciBwcm9wO1xuICAgICAgICAgICAgaWYgKG9iai5fcmVzcG9uc2UpIHtcbiAgICAgICAgICAgICAgICBmb3IgKHByb3AgaW4gb2JqLl9yZXNwb25zZSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAob2JqLl9yZXNwb25zZS5oYXNPd25Qcm9wZXJ0eShwcm9wKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIG9iai5fcmVzcG9uc2VbcHJvcF07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG9iai5fcmVzcG9uc2UgPSB7fTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBfb25Qcm9ncmVzczogZnVuY3Rpb24gKGUsIGRhdGEpIHtcbiAgICAgICAgICAgIGlmIChlLmxlbmd0aENvbXB1dGFibGUpIHtcbiAgICAgICAgICAgICAgICB2YXIgbm93ID0gKChEYXRlLm5vdykgPyBEYXRlLm5vdygpIDogKG5ldyBEYXRlKCkpLmdldFRpbWUoKSksXG4gICAgICAgICAgICAgICAgICAgIGxvYWRlZDtcbiAgICAgICAgICAgICAgICBpZiAoZGF0YS5fdGltZSAmJiBkYXRhLnByb2dyZXNzSW50ZXJ2YWwgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgIChub3cgLSBkYXRhLl90aW1lIDwgZGF0YS5wcm9ncmVzc0ludGVydmFsKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgZS5sb2FkZWQgIT09IGUudG90YWwpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBkYXRhLl90aW1lID0gbm93O1xuICAgICAgICAgICAgICAgIGxvYWRlZCA9IE1hdGguZmxvb3IoXG4gICAgICAgICAgICAgICAgICAgIGUubG9hZGVkIC8gZS50b3RhbCAqIChkYXRhLmNodW5rU2l6ZSB8fCBkYXRhLl9wcm9ncmVzcy50b3RhbClcbiAgICAgICAgICAgICAgICApICsgKGRhdGEudXBsb2FkZWRCeXRlcyB8fCAwKTtcbiAgICAgICAgICAgICAgICAvLyBBZGQgdGhlIGRpZmZlcmVuY2UgZnJvbSB0aGUgcHJldmlvdXNseSBsb2FkZWQgc3RhdGVcbiAgICAgICAgICAgICAgICAvLyB0byB0aGUgZ2xvYmFsIGxvYWRlZCBjb3VudGVyOlxuICAgICAgICAgICAgICAgIHRoaXMuX3Byb2dyZXNzLmxvYWRlZCArPSAobG9hZGVkIC0gZGF0YS5fcHJvZ3Jlc3MubG9hZGVkKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9wcm9ncmVzcy5iaXRyYXRlID0gdGhpcy5fYml0cmF0ZVRpbWVyLmdldEJpdHJhdGUoXG4gICAgICAgICAgICAgICAgICAgIG5vdyxcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fcHJvZ3Jlc3MubG9hZGVkLFxuICAgICAgICAgICAgICAgICAgICBkYXRhLmJpdHJhdGVJbnRlcnZhbFxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgZGF0YS5fcHJvZ3Jlc3MubG9hZGVkID0gZGF0YS5sb2FkZWQgPSBsb2FkZWQ7XG4gICAgICAgICAgICAgICAgZGF0YS5fcHJvZ3Jlc3MuYml0cmF0ZSA9IGRhdGEuYml0cmF0ZSA9IGRhdGEuX2JpdHJhdGVUaW1lci5nZXRCaXRyYXRlKFxuICAgICAgICAgICAgICAgICAgICBub3csXG4gICAgICAgICAgICAgICAgICAgIGxvYWRlZCxcbiAgICAgICAgICAgICAgICAgICAgZGF0YS5iaXRyYXRlSW50ZXJ2YWxcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIC8vIFRyaWdnZXIgYSBjdXN0b20gcHJvZ3Jlc3MgZXZlbnQgd2l0aCBhIHRvdGFsIGRhdGEgcHJvcGVydHkgc2V0XG4gICAgICAgICAgICAgICAgLy8gdG8gdGhlIGZpbGUgc2l6ZShzKSBvZiB0aGUgY3VycmVudCB1cGxvYWQgYW5kIGEgbG9hZGVkIGRhdGFcbiAgICAgICAgICAgICAgICAvLyBwcm9wZXJ0eSBjYWxjdWxhdGVkIGFjY29yZGluZ2x5OlxuICAgICAgICAgICAgICAgIHRoaXMuX3RyaWdnZXIoXG4gICAgICAgICAgICAgICAgICAgICdwcm9ncmVzcycsXG4gICAgICAgICAgICAgICAgICAgICQuRXZlbnQoJ3Byb2dyZXNzJywge2RlbGVnYXRlZEV2ZW50OiBlfSksXG4gICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIC8vIFRyaWdnZXIgYSBnbG9iYWwgcHJvZ3Jlc3MgZXZlbnQgZm9yIGFsbCBjdXJyZW50IGZpbGUgdXBsb2FkcyxcbiAgICAgICAgICAgICAgICAvLyBpbmNsdWRpbmcgYWpheCBjYWxscyBxdWV1ZWQgZm9yIHNlcXVlbnRpYWwgZmlsZSB1cGxvYWRzOlxuICAgICAgICAgICAgICAgIHRoaXMuX3RyaWdnZXIoXG4gICAgICAgICAgICAgICAgICAgICdwcm9ncmVzc2FsbCcsXG4gICAgICAgICAgICAgICAgICAgICQuRXZlbnQoJ3Byb2dyZXNzYWxsJywge2RlbGVnYXRlZEV2ZW50OiBlfSksXG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3Byb2dyZXNzXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBfaW5pdFByb2dyZXNzTGlzdGVuZXI6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgdGhhdCA9IHRoaXMsXG4gICAgICAgICAgICAgICAgeGhyID0gb3B0aW9ucy54aHIgPyBvcHRpb25zLnhocigpIDogJC5hamF4U2V0dGluZ3MueGhyKCk7XG4gICAgICAgICAgICAvLyBBY2Nlc3NzIHRvIHRoZSBuYXRpdmUgWEhSIG9iamVjdCBpcyByZXF1aXJlZCB0byBhZGQgZXZlbnQgbGlzdGVuZXJzXG4gICAgICAgICAgICAvLyBmb3IgdGhlIHVwbG9hZCBwcm9ncmVzcyBldmVudDpcbiAgICAgICAgICAgIGlmICh4aHIudXBsb2FkKSB7XG4gICAgICAgICAgICAgICAgJCh4aHIudXBsb2FkKS5iaW5kKCdwcm9ncmVzcycsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvZSA9IGUub3JpZ2luYWxFdmVudDtcbiAgICAgICAgICAgICAgICAgICAgLy8gTWFrZSBzdXJlIHRoZSBwcm9ncmVzcyBldmVudCBwcm9wZXJ0aWVzIGdldCBjb3BpZWQgb3ZlcjpcbiAgICAgICAgICAgICAgICAgICAgZS5sZW5ndGhDb21wdXRhYmxlID0gb2UubGVuZ3RoQ29tcHV0YWJsZTtcbiAgICAgICAgICAgICAgICAgICAgZS5sb2FkZWQgPSBvZS5sb2FkZWQ7XG4gICAgICAgICAgICAgICAgICAgIGUudG90YWwgPSBvZS50b3RhbDtcbiAgICAgICAgICAgICAgICAgICAgdGhhdC5fb25Qcm9ncmVzcyhlLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBvcHRpb25zLnhociA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHhocjtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIF9kZWluaXRQcm9ncmVzc0xpc3RlbmVyOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHhociA9IG9wdGlvbnMueGhyID8gb3B0aW9ucy54aHIoKSA6ICQuYWpheFNldHRpbmdzLnhocigpO1xuICAgICAgICAgICAgaWYgKHhoci51cGxvYWQpIHtcbiAgICAgICAgICAgICAgICAkKHhoci51cGxvYWQpLnVuYmluZCgncHJvZ3Jlc3MnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBfaXNJbnN0YW5jZU9mOiBmdW5jdGlvbiAodHlwZSwgb2JqKSB7XG4gICAgICAgICAgICAvLyBDcm9zcy1mcmFtZSBpbnN0YW5jZW9mIGNoZWNrXG4gICAgICAgICAgICByZXR1cm4gT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iaikgPT09ICdbb2JqZWN0ICcgKyB0eXBlICsgJ10nO1xuICAgICAgICB9LFxuXG4gICAgICAgIF9pbml0WEhSRGF0YTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciB0aGF0ID0gdGhpcyxcbiAgICAgICAgICAgICAgICBmb3JtRGF0YSxcbiAgICAgICAgICAgICAgICBmaWxlID0gb3B0aW9ucy5maWxlc1swXSxcbiAgICAgICAgICAgICAgICAvLyBJZ25vcmUgbm9uLW11bHRpcGFydCBzZXR0aW5nIGlmIG5vdCBzdXBwb3J0ZWQ6XG4gICAgICAgICAgICAgICAgbXVsdGlwYXJ0ID0gb3B0aW9ucy5tdWx0aXBhcnQgfHwgISQuc3VwcG9ydC54aHJGaWxlVXBsb2FkLFxuICAgICAgICAgICAgICAgIHBhcmFtTmFtZSA9ICQudHlwZShvcHRpb25zLnBhcmFtTmFtZSkgPT09ICdhcnJheScgP1xuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnBhcmFtTmFtZVswXSA6IG9wdGlvbnMucGFyYW1OYW1lO1xuICAgICAgICAgICAgb3B0aW9ucy5oZWFkZXJzID0gJC5leHRlbmQoe30sIG9wdGlvbnMuaGVhZGVycyk7XG4gICAgICAgICAgICBpZiAob3B0aW9ucy5jb250ZW50UmFuZ2UpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmhlYWRlcnNbJ0NvbnRlbnQtUmFuZ2UnXSA9IG9wdGlvbnMuY29udGVudFJhbmdlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCFtdWx0aXBhcnQgfHwgb3B0aW9ucy5ibG9iIHx8ICF0aGlzLl9pc0luc3RhbmNlT2YoJ0ZpbGUnLCBmaWxlKSkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuaGVhZGVyc1snQ29udGVudC1EaXNwb3NpdGlvbiddID0gJ2F0dGFjaG1lbnQ7IGZpbGVuYW1lPVwiJyArXG4gICAgICAgICAgICAgICAgICAgIGVuY29kZVVSSShmaWxlLnVwbG9hZE5hbWUgfHwgZmlsZS5uYW1lKSArICdcIic7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIW11bHRpcGFydCkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuY29udGVudFR5cGUgPSBmaWxlLnR5cGUgfHwgJ2FwcGxpY2F0aW9uL29jdGV0LXN0cmVhbSc7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5kYXRhID0gb3B0aW9ucy5ibG9iIHx8IGZpbGU7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCQuc3VwcG9ydC54aHJGb3JtRGF0YUZpbGVVcGxvYWQpIHtcbiAgICAgICAgICAgICAgICBpZiAob3B0aW9ucy5wb3N0TWVzc2FnZSkge1xuICAgICAgICAgICAgICAgICAgICAvLyB3aW5kb3cucG9zdE1lc3NhZ2UgZG9lcyBub3QgYWxsb3cgc2VuZGluZyBGb3JtRGF0YVxuICAgICAgICAgICAgICAgICAgICAvLyBvYmplY3RzLCBzbyB3ZSBqdXN0IGFkZCB0aGUgRmlsZS9CbG9iIG9iamVjdHMgdG9cbiAgICAgICAgICAgICAgICAgICAgLy8gdGhlIGZvcm1EYXRhIGFycmF5IGFuZCBsZXQgdGhlIHBvc3RNZXNzYWdlIHdpbmRvd1xuICAgICAgICAgICAgICAgICAgICAvLyBjcmVhdGUgdGhlIEZvcm1EYXRhIG9iamVjdCBvdXQgb2YgdGhpcyBhcnJheTpcbiAgICAgICAgICAgICAgICAgICAgZm9ybURhdGEgPSB0aGlzLl9nZXRGb3JtRGF0YShvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuYmxvYikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9ybURhdGEucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmFtZTogcGFyYW1OYW1lLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiBvcHRpb25zLmJsb2JcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgJC5lYWNoKG9wdGlvbnMuZmlsZXMsIGZ1bmN0aW9uIChpbmRleCwgZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1EYXRhLnB1c2goe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiAoJC50eXBlKG9wdGlvbnMucGFyYW1OYW1lKSA9PT0gJ2FycmF5JyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5wYXJhbU5hbWVbaW5kZXhdKSB8fCBwYXJhbU5hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlOiBmaWxlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGF0Ll9pc0luc3RhbmNlT2YoJ0Zvcm1EYXRhJywgb3B0aW9ucy5mb3JtRGF0YSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1EYXRhID0gb3B0aW9ucy5mb3JtRGF0YTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1EYXRhID0gbmV3IEZvcm1EYXRhKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAkLmVhY2godGhpcy5fZ2V0Rm9ybURhdGEob3B0aW9ucyksIGZ1bmN0aW9uIChpbmRleCwgZmllbGQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmb3JtRGF0YS5hcHBlbmQoZmllbGQubmFtZSwgZmllbGQudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMuYmxvYikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZm9ybURhdGEuYXBwZW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmJsb2IsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZmlsZS51cGxvYWROYW1lIHx8IGZpbGUubmFtZVxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChvcHRpb25zLmZpbGVzLCBmdW5jdGlvbiAoaW5kZXgsIGZpbGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGNoZWNrIGFsbG93cyB0aGUgdGVzdHMgdG8gcnVuIHdpdGhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBkdW1teSBvYmplY3RzOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGF0Ll9pc0luc3RhbmNlT2YoJ0ZpbGUnLCBmaWxlKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhhdC5faXNJbnN0YW5jZU9mKCdCbG9iJywgZmlsZSkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZm9ybURhdGEuYXBwZW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKCQudHlwZShvcHRpb25zLnBhcmFtTmFtZSkgPT09ICdhcnJheScgJiZcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnBhcmFtTmFtZVtpbmRleF0pIHx8IHBhcmFtTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZpbGUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnVwbG9hZE5hbWUgfHwgZmlsZS5uYW1lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5kYXRhID0gZm9ybURhdGE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBCbG9iIHJlZmVyZW5jZSBpcyBub3QgbmVlZGVkIGFueW1vcmUsIGZyZWUgbWVtb3J5OlxuICAgICAgICAgICAgb3B0aW9ucy5ibG9iID0gbnVsbDtcbiAgICAgICAgfSxcblxuICAgICAgICBfaW5pdElmcmFtZVNldHRpbmdzOiBmdW5jdGlvbiAob3B0aW9ucykge1xuICAgICAgICAgICAgdmFyIHRhcmdldEhvc3QgPSAkKCc8YT48L2E+JykucHJvcCgnaHJlZicsIG9wdGlvbnMudXJsKS5wcm9wKCdob3N0Jyk7XG4gICAgICAgICAgICAvLyBTZXR0aW5nIHRoZSBkYXRhVHlwZSB0byBpZnJhbWUgZW5hYmxlcyB0aGUgaWZyYW1lIHRyYW5zcG9ydDpcbiAgICAgICAgICAgIG9wdGlvbnMuZGF0YVR5cGUgPSAnaWZyYW1lICcgKyAob3B0aW9ucy5kYXRhVHlwZSB8fCAnJyk7XG4gICAgICAgICAgICAvLyBUaGUgaWZyYW1lIHRyYW5zcG9ydCBhY2NlcHRzIGEgc2VyaWFsaXplZCBhcnJheSBhcyBmb3JtIGRhdGE6XG4gICAgICAgICAgICBvcHRpb25zLmZvcm1EYXRhID0gdGhpcy5fZ2V0Rm9ybURhdGEob3B0aW9ucyk7XG4gICAgICAgICAgICAvLyBBZGQgcmVkaXJlY3QgdXJsIHRvIGZvcm0gZGF0YSBvbiBjcm9zcy1kb21haW4gdXBsb2FkczpcbiAgICAgICAgICAgIGlmIChvcHRpb25zLnJlZGlyZWN0ICYmIHRhcmdldEhvc3QgJiYgdGFyZ2V0SG9zdCAhPT0gbG9jYXRpb24uaG9zdCkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZm9ybURhdGEucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIG5hbWU6IG9wdGlvbnMucmVkaXJlY3RQYXJhbU5hbWUgfHwgJ3JlZGlyZWN0JyxcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IG9wdGlvbnMucmVkaXJlY3RcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBfaW5pdERhdGFTZXR0aW5nczogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLl9pc1hIUlVwbG9hZChvcHRpb25zKSkge1xuICAgICAgICAgICAgICAgIGlmICghdGhpcy5fY2h1bmtlZFVwbG9hZChvcHRpb25zLCB0cnVlKSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIW9wdGlvbnMuZGF0YSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5faW5pdFhIUkRhdGEob3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5faW5pdFByb2dyZXNzTGlzdGVuZXIob3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLnBvc3RNZXNzYWdlKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNldHRpbmcgdGhlIGRhdGFUeXBlIHRvIHBvc3RtZXNzYWdlIGVuYWJsZXMgdGhlXG4gICAgICAgICAgICAgICAgICAgIC8vIHBvc3RNZXNzYWdlIHRyYW5zcG9ydDpcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5kYXRhVHlwZSA9ICdwb3N0bWVzc2FnZSAnICsgKG9wdGlvbnMuZGF0YVR5cGUgfHwgJycpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5faW5pdElmcmFtZVNldHRpbmdzKG9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIF9nZXRQYXJhbU5hbWU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgZmlsZUlucHV0ID0gJChvcHRpb25zLmZpbGVJbnB1dCksXG4gICAgICAgICAgICAgICAgcGFyYW1OYW1lID0gb3B0aW9ucy5wYXJhbU5hbWU7XG4gICAgICAgICAgICBpZiAoIXBhcmFtTmFtZSkge1xuICAgICAgICAgICAgICAgIHBhcmFtTmFtZSA9IFtdO1xuICAgICAgICAgICAgICAgIGZpbGVJbnB1dC5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGlucHV0ID0gJCh0aGlzKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWUgPSBpbnB1dC5wcm9wKCduYW1lJykgfHwgJ2ZpbGVzW10nLFxuICAgICAgICAgICAgICAgICAgICAgICAgaSA9IChpbnB1dC5wcm9wKCdmaWxlcycpIHx8IFsxXSkubGVuZ3RoO1xuICAgICAgICAgICAgICAgICAgICB3aGlsZSAoaSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lLnB1c2gobmFtZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpIC09IDE7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBpZiAoIXBhcmFtTmFtZS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lID0gW2ZpbGVJbnB1dC5wcm9wKCduYW1lJykgfHwgJ2ZpbGVzW10nXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCEkLmlzQXJyYXkocGFyYW1OYW1lKSkge1xuICAgICAgICAgICAgICAgIHBhcmFtTmFtZSA9IFtwYXJhbU5hbWVdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHBhcmFtTmFtZTtcbiAgICAgICAgfSxcblxuICAgICAgICBfaW5pdEZvcm1TZXR0aW5nczogZnVuY3Rpb24gKG9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vIFJldHJpZXZlIG1pc3Npbmcgb3B0aW9ucyBmcm9tIHRoZSBpbnB1dCBmaWVsZCBhbmQgdGhlXG4gICAgICAgICAgICAvLyBhc3NvY2lhdGVkIGZvcm0sIGlmIGF2YWlsYWJsZTpcbiAgICAgICAgICAgIGlmICghb3B0aW9ucy5mb3JtIHx8ICFvcHRpb25zLmZvcm0ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5mb3JtID0gJChvcHRpb25zLmZpbGVJbnB1dC5wcm9wKCdmb3JtJykpO1xuICAgICAgICAgICAgICAgIC8vIElmIHRoZSBnaXZlbiBmaWxlIGlucHV0IGRvZXNuJ3QgaGF2ZSBhbiBhc3NvY2lhdGVkIGZvcm0sXG4gICAgICAgICAgICAgICAgLy8gdXNlIHRoZSBkZWZhdWx0IHdpZGdldCBmaWxlIGlucHV0J3MgZm9ybTpcbiAgICAgICAgICAgICAgICBpZiAoIW9wdGlvbnMuZm9ybS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5mb3JtID0gJCh0aGlzLm9wdGlvbnMuZmlsZUlucHV0LnByb3AoJ2Zvcm0nKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgb3B0aW9ucy5wYXJhbU5hbWUgPSB0aGlzLl9nZXRQYXJhbU5hbWUob3B0aW9ucyk7XG4gICAgICAgICAgICBpZiAoIW9wdGlvbnMudXJsKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy51cmwgPSBvcHRpb25zLmZvcm0ucHJvcCgnYWN0aW9uJykgfHwgbG9jYXRpb24uaHJlZjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFRoZSBIVFRQIHJlcXVlc3QgbWV0aG9kIG11c3QgYmUgXCJQT1NUXCIgb3IgXCJQVVRcIjpcbiAgICAgICAgICAgIG9wdGlvbnMudHlwZSA9IChvcHRpb25zLnR5cGUgfHxcbiAgICAgICAgICAgICAgICAoJC50eXBlKG9wdGlvbnMuZm9ybS5wcm9wKCdtZXRob2QnKSkgPT09ICdzdHJpbmcnICYmXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuZm9ybS5wcm9wKCdtZXRob2QnKSkgfHwgJydcbiAgICAgICAgICAgICAgICApLnRvVXBwZXJDYXNlKCk7XG4gICAgICAgICAgICBpZiAob3B0aW9ucy50eXBlICE9PSAnUE9TVCcgJiYgb3B0aW9ucy50eXBlICE9PSAnUFVUJyAmJlxuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLnR5cGUgIT09ICdQQVRDSCcpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLnR5cGUgPSAnUE9TVCc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIW9wdGlvbnMuZm9ybUFjY2VwdENoYXJzZXQpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmZvcm1BY2NlcHRDaGFyc2V0ID0gb3B0aW9ucy5mb3JtLmF0dHIoJ2FjY2VwdC1jaGFyc2V0Jyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgX2dldEFKQVhTZXR0aW5nczogZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgICAgIHZhciBvcHRpb25zID0gJC5leHRlbmQoe30sIHRoaXMub3B0aW9ucywgZGF0YSk7XG4gICAgICAgICAgICB0aGlzLl9pbml0Rm9ybVNldHRpbmdzKG9wdGlvbnMpO1xuICAgICAgICAgICAgdGhpcy5faW5pdERhdGFTZXR0aW5ncyhvcHRpb25zKTtcbiAgICAgICAgICAgIHJldHVybiBvcHRpb25zO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8vIGpRdWVyeSAxLjYgZG9lc24ndCBwcm92aWRlIC5zdGF0ZSgpLFxuICAgICAgICAvLyB3aGlsZSBqUXVlcnkgMS44KyByZW1vdmVkIC5pc1JlamVjdGVkKCkgYW5kIC5pc1Jlc29sdmVkKCk6XG4gICAgICAgIF9nZXREZWZlcnJlZFN0YXRlOiBmdW5jdGlvbiAoZGVmZXJyZWQpIHtcbiAgICAgICAgICAgIGlmIChkZWZlcnJlZC5zdGF0ZSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBkZWZlcnJlZC5zdGF0ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZmVycmVkLmlzUmVzb2x2ZWQoKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAncmVzb2x2ZWQnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGRlZmVycmVkLmlzUmVqZWN0ZWQoKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiAncmVqZWN0ZWQnO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuICdwZW5kaW5nJztcbiAgICAgICAgfSxcblxuICAgICAgICAvLyBNYXBzIGpxWEhSIGNhbGxiYWNrcyB0byB0aGUgZXF1aXZhbGVudFxuICAgICAgICAvLyBtZXRob2RzIG9mIHRoZSBnaXZlbiBQcm9taXNlIG9iamVjdDpcbiAgICAgICAgX2VuaGFuY2VQcm9taXNlOiBmdW5jdGlvbiAocHJvbWlzZSkge1xuICAgICAgICAgICAgcHJvbWlzZS5zdWNjZXNzID0gcHJvbWlzZS5kb25lO1xuICAgICAgICAgICAgcHJvbWlzZS5lcnJvciA9IHByb21pc2UuZmFpbDtcbiAgICAgICAgICAgIHByb21pc2UuY29tcGxldGUgPSBwcm9taXNlLmFsd2F5cztcbiAgICAgICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8vIENyZWF0ZXMgYW5kIHJldHVybnMgYSBQcm9taXNlIG9iamVjdCBlbmhhbmNlZCB3aXRoXG4gICAgICAgIC8vIHRoZSBqcVhIUiBtZXRob2RzIGFib3J0LCBzdWNjZXNzLCBlcnJvciBhbmQgY29tcGxldGU6XG4gICAgICAgIF9nZXRYSFJQcm9taXNlOiBmdW5jdGlvbiAocmVzb2x2ZU9yUmVqZWN0LCBjb250ZXh0LCBhcmdzKSB7XG4gICAgICAgICAgICB2YXIgZGZkID0gJC5EZWZlcnJlZCgpLFxuICAgICAgICAgICAgICAgIHByb21pc2UgPSBkZmQucHJvbWlzZSgpO1xuICAgICAgICAgICAgY29udGV4dCA9IGNvbnRleHQgfHwgdGhpcy5vcHRpb25zLmNvbnRleHQgfHwgcHJvbWlzZTtcbiAgICAgICAgICAgIGlmIChyZXNvbHZlT3JSZWplY3QgPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICBkZmQucmVzb2x2ZVdpdGgoY29udGV4dCwgYXJncyk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHJlc29sdmVPclJlamVjdCA9PT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICBkZmQucmVqZWN0V2l0aChjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHByb21pc2UuYWJvcnQgPSBkZmQucHJvbWlzZTtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9lbmhhbmNlUHJvbWlzZShwcm9taXNlKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvLyBBZGRzIGNvbnZlbmllbmNlIG1ldGhvZHMgdG8gdGhlIGRhdGEgY2FsbGJhY2sgYXJndW1lbnQ6XG4gICAgICAgIF9hZGRDb252ZW5pZW5jZU1ldGhvZHM6IGZ1bmN0aW9uIChlLCBkYXRhKSB7XG4gICAgICAgICAgICB2YXIgdGhhdCA9IHRoaXMsXG4gICAgICAgICAgICAgICAgZ2V0UHJvbWlzZSA9IGZ1bmN0aW9uIChhcmdzKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZVdpdGgodGhhdCwgYXJncykucHJvbWlzZSgpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICBkYXRhLnByb2Nlc3MgPSBmdW5jdGlvbiAocmVzb2x2ZUZ1bmMsIHJlamVjdEZ1bmMpIHtcbiAgICAgICAgICAgICAgICBpZiAocmVzb2x2ZUZ1bmMgfHwgcmVqZWN0RnVuYykge1xuICAgICAgICAgICAgICAgICAgICBkYXRhLl9wcm9jZXNzUXVldWUgPSB0aGlzLl9wcm9jZXNzUXVldWUgPVxuICAgICAgICAgICAgICAgICAgICAgICAgKHRoaXMuX3Byb2Nlc3NRdWV1ZSB8fCBnZXRQcm9taXNlKFt0aGlzXSkpLnRoZW4oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZGF0YS5lcnJvclRocm93bikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuICQuRGVmZXJyZWQoKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC5yZWplY3RXaXRoKHRoYXQsIFtkYXRhXSkucHJvbWlzZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBnZXRQcm9taXNlKGFyZ3VtZW50cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgKS50aGVuKHJlc29sdmVGdW5jLCByZWplY3RGdW5jKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuX3Byb2Nlc3NRdWV1ZSB8fCBnZXRQcm9taXNlKFt0aGlzXSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgZGF0YS5zdWJtaXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuc3RhdGUoKSAhPT0gJ3BlbmRpbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuanFYSFIgPSB0aGlzLmpxWEhSID1cbiAgICAgICAgICAgICAgICAgICAgICAgICh0aGF0Ll90cmlnZ2VyKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdzdWJtaXQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQuRXZlbnQoJ3N1Ym1pdCcsIHtkZWxlZ2F0ZWRFdmVudDogZX0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoaXNcbiAgICAgICAgICAgICAgICAgICAgICAgICkgIT09IGZhbHNlKSAmJiB0aGF0Ll9vblNlbmQoZSwgdGhpcyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmpxWEhSIHx8IHRoYXQuX2dldFhIUlByb21pc2UoKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBkYXRhLmFib3J0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmpxWEhSKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmpxWEhSLmFib3J0KCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMuZXJyb3JUaHJvd24gPSAnYWJvcnQnO1xuICAgICAgICAgICAgICAgIHRoYXQuX3RyaWdnZXIoJ2ZhaWwnLCBudWxsLCB0aGlzKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhhdC5fZ2V0WEhSUHJvbWlzZShmYWxzZSk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgZGF0YS5zdGF0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5qcVhIUikge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhhdC5fZ2V0RGVmZXJyZWRTdGF0ZSh0aGlzLmpxWEhSKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuX3Byb2Nlc3NRdWV1ZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhhdC5fZ2V0RGVmZXJyZWRTdGF0ZSh0aGlzLl9wcm9jZXNzUXVldWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBkYXRhLnByb2Nlc3NpbmcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICF0aGlzLmpxWEhSICYmIHRoaXMuX3Byb2Nlc3NRdWV1ZSAmJiB0aGF0XG4gICAgICAgICAgICAgICAgICAgIC5fZ2V0RGVmZXJyZWRTdGF0ZSh0aGlzLl9wcm9jZXNzUXVldWUpID09PSAncGVuZGluZyc7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgZGF0YS5wcm9ncmVzcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcHJvZ3Jlc3M7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgZGF0YS5yZXNwb25zZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fcmVzcG9uc2U7XG4gICAgICAgICAgICB9O1xuICAgICAgICB9LFxuXG4gICAgICAgIC8vIFBhcnNlcyB0aGUgUmFuZ2UgaGVhZGVyIGZyb20gdGhlIHNlcnZlciByZXNwb25zZVxuICAgICAgICAvLyBhbmQgcmV0dXJucyB0aGUgdXBsb2FkZWQgYnl0ZXM6XG4gICAgICAgIF9nZXRVcGxvYWRlZEJ5dGVzOiBmdW5jdGlvbiAoanFYSFIpIHtcbiAgICAgICAgICAgIHZhciByYW5nZSA9IGpxWEhSLmdldFJlc3BvbnNlSGVhZGVyKCdSYW5nZScpLFxuICAgICAgICAgICAgICAgIHBhcnRzID0gcmFuZ2UgJiYgcmFuZ2Uuc3BsaXQoJy0nKSxcbiAgICAgICAgICAgICAgICB1cHBlckJ5dGVzUG9zID0gcGFydHMgJiYgcGFydHMubGVuZ3RoID4gMSAmJlxuICAgICAgICAgICAgICAgICAgICBwYXJzZUludChwYXJ0c1sxXSwgMTApO1xuICAgICAgICAgICAgcmV0dXJuIHVwcGVyQnl0ZXNQb3MgJiYgdXBwZXJCeXRlc1BvcyArIDE7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLy8gVXBsb2FkcyBhIGZpbGUgaW4gbXVsdGlwbGUsIHNlcXVlbnRpYWwgcmVxdWVzdHNcbiAgICAgICAgLy8gYnkgc3BsaXR0aW5nIHRoZSBmaWxlIHVwIGluIG11bHRpcGxlIGJsb2IgY2h1bmtzLlxuICAgICAgICAvLyBJZiB0aGUgc2Vjb25kIHBhcmFtZXRlciBpcyB0cnVlLCBvbmx5IHRlc3RzIGlmIHRoZSBmaWxlXG4gICAgICAgIC8vIHNob3VsZCBiZSB1cGxvYWRlZCBpbiBjaHVua3MsIGJ1dCBkb2VzIG5vdCBpbnZva2UgYW55XG4gICAgICAgIC8vIHVwbG9hZCByZXF1ZXN0czpcbiAgICAgICAgX2NodW5rZWRVcGxvYWQ6IGZ1bmN0aW9uIChvcHRpb25zLCB0ZXN0T25seSkge1xuICAgICAgICAgICAgb3B0aW9ucy51cGxvYWRlZEJ5dGVzID0gb3B0aW9ucy51cGxvYWRlZEJ5dGVzIHx8IDA7XG4gICAgICAgICAgICB2YXIgdGhhdCA9IHRoaXMsXG4gICAgICAgICAgICAgICAgZmlsZSA9IG9wdGlvbnMuZmlsZXNbMF0sXG4gICAgICAgICAgICAgICAgZnMgPSBmaWxlLnNpemUsXG4gICAgICAgICAgICAgICAgdWIgPSBvcHRpb25zLnVwbG9hZGVkQnl0ZXMsXG4gICAgICAgICAgICAgICAgbWNzID0gb3B0aW9ucy5tYXhDaHVua1NpemUgfHwgZnMsXG4gICAgICAgICAgICAgICAgc2xpY2UgPSB0aGlzLl9ibG9iU2xpY2UsXG4gICAgICAgICAgICAgICAgZGZkID0gJC5EZWZlcnJlZCgpLFxuICAgICAgICAgICAgICAgIHByb21pc2UgPSBkZmQucHJvbWlzZSgpLFxuICAgICAgICAgICAgICAgIGpxWEhSLFxuICAgICAgICAgICAgICAgIHVwbG9hZDtcbiAgICAgICAgICAgIGlmICghKHRoaXMuX2lzWEhSVXBsb2FkKG9wdGlvbnMpICYmIHNsaWNlICYmICh1YiB8fCAoJC50eXBlKG1jcykgPT09ICdmdW5jdGlvbicgPyBtY3Mob3B0aW9ucykgOiBtY3MpIDwgZnMpKSB8fFxuICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmRhdGEpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAodGVzdE9ubHkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh1YiA+PSBmcykge1xuICAgICAgICAgICAgICAgIGZpbGUuZXJyb3IgPSBvcHRpb25zLmkxOG4oJ3VwbG9hZGVkQnl0ZXMnKTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fZ2V0WEhSUHJvbWlzZShcbiAgICAgICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuY29udGV4dCxcbiAgICAgICAgICAgICAgICAgICAgW251bGwsICdlcnJvcicsIGZpbGUuZXJyb3JdXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIFRoZSBjaHVuayB1cGxvYWQgbWV0aG9kOlxuICAgICAgICAgICAgdXBsb2FkID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIC8vIENsb25lIHRoZSBvcHRpb25zIG9iamVjdCBmb3IgZWFjaCBjaHVuayB1cGxvYWQ6XG4gICAgICAgICAgICAgICAgdmFyIG8gPSAkLmV4dGVuZCh7fSwgb3B0aW9ucyksXG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRMb2FkZWQgPSBvLl9wcm9ncmVzcy5sb2FkZWQ7XG4gICAgICAgICAgICAgICAgby5ibG9iID0gc2xpY2UuY2FsbChcbiAgICAgICAgICAgICAgICAgICAgZmlsZSxcbiAgICAgICAgICAgICAgICAgICAgdWIsXG4gICAgICAgICAgICAgICAgICAgIHViICsgKCQudHlwZShtY3MpID09PSAnZnVuY3Rpb24nID8gbWNzKG8pIDogbWNzKSxcbiAgICAgICAgICAgICAgICAgICAgZmlsZS50eXBlXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAvLyBTdG9yZSB0aGUgY3VycmVudCBjaHVuayBzaXplLCBhcyB0aGUgYmxvYiBpdHNlbGZcbiAgICAgICAgICAgICAgICAvLyB3aWxsIGJlIGRlcmVmZXJlbmNlZCBhZnRlciBkYXRhIHByb2Nlc3Npbmc6XG4gICAgICAgICAgICAgICAgby5jaHVua1NpemUgPSBvLmJsb2Iuc2l6ZTtcbiAgICAgICAgICAgICAgICAvLyBFeHBvc2UgdGhlIGNodW5rIGJ5dGVzIHBvc2l0aW9uIHJhbmdlOlxuICAgICAgICAgICAgICAgIG8uY29udGVudFJhbmdlID0gJ2J5dGVzICcgKyB1YiArICctJyArXG4gICAgICAgICAgICAgICAgICAgICh1YiArIG8uY2h1bmtTaXplIC0gMSkgKyAnLycgKyBmcztcbiAgICAgICAgICAgICAgICAvLyBUcmlnZ2VyIGNodW5rYmVmb3Jlc2VuZCB0byBhbGxvdyBmb3JtIGRhdGEgdG8gYmUgdXBkYXRlZCBmb3IgdGhpcyBjaHVua1xuICAgICAgICAgICAgICAgIHRoYXQuX3RyaWdnZXIoJ2NodW5rYmVmb3Jlc2VuZCcsIG51bGwsIG8pO1xuICAgICAgICAgICAgICAgIC8vIFByb2Nlc3MgdGhlIHVwbG9hZCBkYXRhICh0aGUgYmxvYiBhbmQgcG90ZW50aWFsIGZvcm0gZGF0YSk6XG4gICAgICAgICAgICAgICAgdGhhdC5faW5pdFhIUkRhdGEobyk7XG4gICAgICAgICAgICAgICAgLy8gQWRkIHByb2dyZXNzIGxpc3RlbmVycyBmb3IgdGhpcyBjaHVuayB1cGxvYWQ6XG4gICAgICAgICAgICAgICAgdGhhdC5faW5pdFByb2dyZXNzTGlzdGVuZXIobyk7XG4gICAgICAgICAgICAgICAganFYSFIgPSAoKHRoYXQuX3RyaWdnZXIoJ2NodW5rc2VuZCcsIG51bGwsIG8pICE9PSBmYWxzZSAmJiAkLmFqYXgobykpIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGF0Ll9nZXRYSFJQcm9taXNlKGZhbHNlLCBvLmNvbnRleHQpKVxuICAgICAgICAgICAgICAgICAgICAuZG9uZShmdW5jdGlvbiAocmVzdWx0LCB0ZXh0U3RhdHVzLCBqcVhIUikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdWIgPSB0aGF0Ll9nZXRVcGxvYWRlZEJ5dGVzKGpxWEhSKSB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICh1YiArIG8uY2h1bmtTaXplKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENyZWF0ZSBhIHByb2dyZXNzIGV2ZW50IGlmIG5vIGZpbmFsIHByb2dyZXNzIGV2ZW50XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyB3aXRoIGxvYWRlZCBlcXVhbGluZyB0b3RhbCBoYXMgYmVlbiB0cmlnZ2VyZWRcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGZvciB0aGlzIGNodW5rOlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGN1cnJlbnRMb2FkZWQgKyBvLmNodW5rU2l6ZSAtIG8uX3Byb2dyZXNzLmxvYWRlZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQuX29uUHJvZ3Jlc3MoJC5FdmVudCgncHJvZ3Jlc3MnLCB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxlbmd0aENvbXB1dGFibGU6IHRydWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvYWRlZDogdWIgLSBvLnVwbG9hZGVkQnl0ZXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvdGFsOiB1YiAtIG8udXBsb2FkZWRCeXRlc1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pLCBvKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnMudXBsb2FkZWRCeXRlcyA9IG8udXBsb2FkZWRCeXRlcyA9IHViO1xuICAgICAgICAgICAgICAgICAgICAgICAgby5yZXN1bHQgPSByZXN1bHQ7XG4gICAgICAgICAgICAgICAgICAgICAgICBvLnRleHRTdGF0dXMgPSB0ZXh0U3RhdHVzO1xuICAgICAgICAgICAgICAgICAgICAgICAgby5qcVhIUiA9IGpxWEhSO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhhdC5fdHJpZ2dlcignY2h1bmtkb25lJywgbnVsbCwgbyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGF0Ll90cmlnZ2VyKCdjaHVua2Fsd2F5cycsIG51bGwsIG8pO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHViIDwgZnMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBGaWxlIHVwbG9hZCBub3QgeWV0IGNvbXBsZXRlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNvbnRpbnVlIHdpdGggdGhlIG5leHQgY2h1bms6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBsb2FkKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmZC5yZXNvbHZlV2l0aChcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgby5jb250ZXh0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBbcmVzdWx0LCB0ZXh0U3RhdHVzLCBqcVhIUl1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAuZmFpbChmdW5jdGlvbiAoanFYSFIsIHRleHRTdGF0dXMsIGVycm9yVGhyb3duKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvLmpxWEhSID0ganFYSFI7XG4gICAgICAgICAgICAgICAgICAgICAgICBvLnRleHRTdGF0dXMgPSB0ZXh0U3RhdHVzO1xuICAgICAgICAgICAgICAgICAgICAgICAgby5lcnJvclRocm93biA9IGVycm9yVGhyb3duO1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhhdC5fdHJpZ2dlcignY2h1bmtmYWlsJywgbnVsbCwgbyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGF0Ll90cmlnZ2VyKCdjaHVua2Fsd2F5cycsIG51bGwsIG8pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZGZkLnJlamVjdFdpdGgoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgby5jb250ZXh0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtqcVhIUiwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd25dXG4gICAgICAgICAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgICAgICAuYWx3YXlzKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQuX2RlaW5pdFByb2dyZXNzTGlzdGVuZXIobyk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHRoaXMuX2VuaGFuY2VQcm9taXNlKHByb21pc2UpO1xuICAgICAgICAgICAgcHJvbWlzZS5hYm9ydCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4ganFYSFIuYWJvcnQoKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICB1cGxvYWQoKTtcbiAgICAgICAgICAgIHJldHVybiBwcm9taXNlO1xuICAgICAgICB9LFxuXG4gICAgICAgIF9iZWZvcmVTZW5kOiBmdW5jdGlvbiAoZSwgZGF0YSkge1xuICAgICAgICAgICAgaWYgKHRoaXMuX2FjdGl2ZSA9PT0gMCkge1xuICAgICAgICAgICAgICAgIC8vIHRoZSBzdGFydCBjYWxsYmFjayBpcyB0cmlnZ2VyZWQgd2hlbiBhbiB1cGxvYWQgc3RhcnRzXG4gICAgICAgICAgICAgICAgLy8gYW5kIG5vIG90aGVyIHVwbG9hZHMgYXJlIGN1cnJlbnRseSBydW5uaW5nLFxuICAgICAgICAgICAgICAgIC8vIGVxdWl2YWxlbnQgdG8gdGhlIGdsb2JhbCBhamF4U3RhcnQgZXZlbnQ6XG4gICAgICAgICAgICAgICAgdGhpcy5fdHJpZ2dlcignc3RhcnQnKTtcbiAgICAgICAgICAgICAgICAvLyBTZXQgdGltZXIgZm9yIGdsb2JhbCBiaXRyYXRlIHByb2dyZXNzIGNhbGN1bGF0aW9uOlxuICAgICAgICAgICAgICAgIHRoaXMuX2JpdHJhdGVUaW1lciA9IG5ldyB0aGlzLl9CaXRyYXRlVGltZXIoKTtcbiAgICAgICAgICAgICAgICAvLyBSZXNldCB0aGUgZ2xvYmFsIHByb2dyZXNzIHZhbHVlczpcbiAgICAgICAgICAgICAgICB0aGlzLl9wcm9ncmVzcy5sb2FkZWQgPSB0aGlzLl9wcm9ncmVzcy50b3RhbCA9IDA7XG4gICAgICAgICAgICAgICAgdGhpcy5fcHJvZ3Jlc3MuYml0cmF0ZSA9IDA7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBNYWtlIHN1cmUgdGhlIGNvbnRhaW5lciBvYmplY3RzIGZvciB0aGUgLnJlc3BvbnNlKCkgYW5kXG4gICAgICAgICAgICAvLyAucHJvZ3Jlc3MoKSBtZXRob2RzIG9uIHRoZSBkYXRhIG9iamVjdCBhcmUgYXZhaWxhYmxlXG4gICAgICAgICAgICAvLyBhbmQgcmVzZXQgdG8gdGhlaXIgaW5pdGlhbCBzdGF0ZTpcbiAgICAgICAgICAgIHRoaXMuX2luaXRSZXNwb25zZU9iamVjdChkYXRhKTtcbiAgICAgICAgICAgIHRoaXMuX2luaXRQcm9ncmVzc09iamVjdChkYXRhKTtcbiAgICAgICAgICAgIGRhdGEuX3Byb2dyZXNzLmxvYWRlZCA9IGRhdGEubG9hZGVkID0gZGF0YS51cGxvYWRlZEJ5dGVzIHx8IDA7XG4gICAgICAgICAgICBkYXRhLl9wcm9ncmVzcy50b3RhbCA9IGRhdGEudG90YWwgPSB0aGlzLl9nZXRUb3RhbChkYXRhLmZpbGVzKSB8fCAxO1xuICAgICAgICAgICAgZGF0YS5fcHJvZ3Jlc3MuYml0cmF0ZSA9IGRhdGEuYml0cmF0ZSA9IDA7XG4gICAgICAgICAgICB0aGlzLl9hY3RpdmUgKz0gMTtcbiAgICAgICAgICAgIC8vIEluaXRpYWxpemUgdGhlIGdsb2JhbCBwcm9ncmVzcyB2YWx1ZXM6XG4gICAgICAgICAgICB0aGlzLl9wcm9ncmVzcy5sb2FkZWQgKz0gZGF0YS5sb2FkZWQ7XG4gICAgICAgICAgICB0aGlzLl9wcm9ncmVzcy50b3RhbCArPSBkYXRhLnRvdGFsO1xuICAgICAgICB9LFxuXG4gICAgICAgIF9vbkRvbmU6IGZ1bmN0aW9uIChyZXN1bHQsIHRleHRTdGF0dXMsIGpxWEhSLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgdG90YWwgPSBvcHRpb25zLl9wcm9ncmVzcy50b3RhbCxcbiAgICAgICAgICAgICAgICByZXNwb25zZSA9IG9wdGlvbnMuX3Jlc3BvbnNlO1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMuX3Byb2dyZXNzLmxvYWRlZCA8IHRvdGFsKSB7XG4gICAgICAgICAgICAgICAgLy8gQ3JlYXRlIGEgcHJvZ3Jlc3MgZXZlbnQgaWYgbm8gZmluYWwgcHJvZ3Jlc3MgZXZlbnRcbiAgICAgICAgICAgICAgICAvLyB3aXRoIGxvYWRlZCBlcXVhbGluZyB0b3RhbCBoYXMgYmVlbiB0cmlnZ2VyZWQ6XG4gICAgICAgICAgICAgICAgdGhpcy5fb25Qcm9ncmVzcygkLkV2ZW50KCdwcm9ncmVzcycsIHtcbiAgICAgICAgICAgICAgICAgICAgbGVuZ3RoQ29tcHV0YWJsZTogdHJ1ZSxcbiAgICAgICAgICAgICAgICAgICAgbG9hZGVkOiB0b3RhbCxcbiAgICAgICAgICAgICAgICAgICAgdG90YWw6IHRvdGFsXG4gICAgICAgICAgICAgICAgfSksIG9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmVzcG9uc2UucmVzdWx0ID0gb3B0aW9ucy5yZXN1bHQgPSByZXN1bHQ7XG4gICAgICAgICAgICByZXNwb25zZS50ZXh0U3RhdHVzID0gb3B0aW9ucy50ZXh0U3RhdHVzID0gdGV4dFN0YXR1cztcbiAgICAgICAgICAgIHJlc3BvbnNlLmpxWEhSID0gb3B0aW9ucy5qcVhIUiA9IGpxWEhSO1xuICAgICAgICAgICAgdGhpcy5fdHJpZ2dlcignZG9uZScsIG51bGwsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIF9vbkZhaWw6IGZ1bmN0aW9uIChqcVhIUiwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd24sIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciByZXNwb25zZSA9IG9wdGlvbnMuX3Jlc3BvbnNlO1xuICAgICAgICAgICAgaWYgKG9wdGlvbnMucmVjYWxjdWxhdGVQcm9ncmVzcykge1xuICAgICAgICAgICAgICAgIC8vIFJlbW92ZSB0aGUgZmFpbGVkIChlcnJvciBvciBhYm9ydCkgZmlsZSB1cGxvYWQgZnJvbVxuICAgICAgICAgICAgICAgIC8vIHRoZSBnbG9iYWwgcHJvZ3Jlc3MgY2FsY3VsYXRpb246XG4gICAgICAgICAgICAgICAgdGhpcy5fcHJvZ3Jlc3MubG9hZGVkIC09IG9wdGlvbnMuX3Byb2dyZXNzLmxvYWRlZDtcbiAgICAgICAgICAgICAgICB0aGlzLl9wcm9ncmVzcy50b3RhbCAtPSBvcHRpb25zLl9wcm9ncmVzcy50b3RhbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJlc3BvbnNlLmpxWEhSID0gb3B0aW9ucy5qcVhIUiA9IGpxWEhSO1xuICAgICAgICAgICAgcmVzcG9uc2UudGV4dFN0YXR1cyA9IG9wdGlvbnMudGV4dFN0YXR1cyA9IHRleHRTdGF0dXM7XG4gICAgICAgICAgICByZXNwb25zZS5lcnJvclRocm93biA9IG9wdGlvbnMuZXJyb3JUaHJvd24gPSBlcnJvclRocm93bjtcbiAgICAgICAgICAgIHRoaXMuX3RyaWdnZXIoJ2ZhaWwnLCBudWxsLCBvcHRpb25zKTtcbiAgICAgICAgfSxcblxuICAgICAgICBfb25BbHdheXM6IGZ1bmN0aW9uIChqcVhIUm9yUmVzdWx0LCB0ZXh0U3RhdHVzLCBqcVhIUm9yRXJyb3IsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIC8vIGpxWEhSb3JSZXN1bHQsIHRleHRTdGF0dXMgYW5kIGpxWEhSb3JFcnJvciBhcmUgYWRkZWQgdG8gdGhlXG4gICAgICAgICAgICAvLyBvcHRpb25zIG9iamVjdCB2aWEgZG9uZSBhbmQgZmFpbCBjYWxsYmFja3NcbiAgICAgICAgICAgIHRoaXMuX3RyaWdnZXIoJ2Fsd2F5cycsIG51bGwsIG9wdGlvbnMpO1xuICAgICAgICB9LFxuXG4gICAgICAgIF9vblNlbmQ6IGZ1bmN0aW9uIChlLCBkYXRhKSB7XG4gICAgICAgICAgICBpZiAoIWRhdGEuc3VibWl0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fYWRkQ29udmVuaWVuY2VNZXRob2RzKGUsIGRhdGEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHRoYXQgPSB0aGlzLFxuICAgICAgICAgICAgICAgIGpxWEhSLFxuICAgICAgICAgICAgICAgIGFib3J0ZWQsXG4gICAgICAgICAgICAgICAgc2xvdCxcbiAgICAgICAgICAgICAgICBwaXBlLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB0aGF0Ll9nZXRBSkFYU2V0dGluZ3MoZGF0YSksXG4gICAgICAgICAgICAgICAgc2VuZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhhdC5fc2VuZGluZyArPSAxO1xuICAgICAgICAgICAgICAgICAgICAvLyBTZXQgdGltZXIgZm9yIGJpdHJhdGUgcHJvZ3Jlc3MgY2FsY3VsYXRpb246XG4gICAgICAgICAgICAgICAgICAgIG9wdGlvbnMuX2JpdHJhdGVUaW1lciA9IG5ldyB0aGF0Ll9CaXRyYXRlVGltZXIoKTtcbiAgICAgICAgICAgICAgICAgICAganFYSFIgPSBqcVhIUiB8fCAoXG4gICAgICAgICAgICAgICAgICAgICAgICAoKGFib3J0ZWQgfHwgdGhhdC5fdHJpZ2dlcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnc2VuZCcsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5FdmVudCgnc2VuZCcsIHtkZWxlZ2F0ZWRFdmVudDogZX0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnNcbiAgICAgICAgICAgICAgICAgICAgICAgICkgPT09IGZhbHNlKSAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgdGhhdC5fZ2V0WEhSUHJvbWlzZShmYWxzZSwgb3B0aW9ucy5jb250ZXh0LCBhYm9ydGVkKSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQuX2NodW5rZWRVcGxvYWQob3B0aW9ucykgfHwgJC5hamF4KG9wdGlvbnMpXG4gICAgICAgICAgICAgICAgICAgICkuZG9uZShmdW5jdGlvbiAocmVzdWx0LCB0ZXh0U3RhdHVzLCBqcVhIUikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhhdC5fb25Eb25lKHJlc3VsdCwgdGV4dFN0YXR1cywganFYSFIsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KS5mYWlsKGZ1bmN0aW9uIChqcVhIUiwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQuX29uRmFpbChqcVhIUiwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd24sIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICB9KS5hbHdheXMoZnVuY3Rpb24gKGpxWEhSb3JSZXN1bHQsIHRleHRTdGF0dXMsIGpxWEhSb3JFcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhhdC5fZGVpbml0UHJvZ3Jlc3NMaXN0ZW5lcihvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQuX29uQWx3YXlzKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGpxWEhSb3JSZXN1bHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdGV4dFN0YXR1cyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBqcVhIUm9yRXJyb3IsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgb3B0aW9uc1xuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQuX3NlbmRpbmcgLT0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQuX2FjdGl2ZSAtPSAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG9wdGlvbnMubGltaXRDb25jdXJyZW50VXBsb2FkcyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmxpbWl0Q29uY3VycmVudFVwbG9hZHMgPiB0aGF0Ll9zZW5kaW5nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3RhcnQgdGhlIG5leHQgcXVldWVkIHVwbG9hZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyB0aGF0IGhhcyBub3QgYmVlbiBhYm9ydGVkOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBuZXh0U2xvdCA9IHRoYXQuX3Nsb3RzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKG5leHRTbG90KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGF0Ll9nZXREZWZlcnJlZFN0YXRlKG5leHRTbG90KSA9PT0gJ3BlbmRpbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXh0U2xvdC5yZXNvbHZlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBuZXh0U2xvdCA9IHRoYXQuX3Nsb3RzLnNoaWZ0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoYXQuX2FjdGl2ZSA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFRoZSBzdG9wIGNhbGxiYWNrIGlzIHRyaWdnZXJlZCB3aGVuIGFsbCB1cGxvYWRzIGhhdmVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBiZWVuIGNvbXBsZXRlZCwgZXF1aXZhbGVudCB0byB0aGUgZ2xvYmFsIGFqYXhTdG9wIGV2ZW50OlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQuX3RyaWdnZXIoJ3N0b3AnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBqcVhIUjtcbiAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgdGhpcy5fYmVmb3JlU2VuZChlLCBvcHRpb25zKTtcbiAgICAgICAgICAgIGlmICh0aGlzLm9wdGlvbnMuc2VxdWVudGlhbFVwbG9hZHMgfHxcbiAgICAgICAgICAgICAgICAgICAgKHRoaXMub3B0aW9ucy5saW1pdENvbmN1cnJlbnRVcGxvYWRzICYmXG4gICAgICAgICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5saW1pdENvbmN1cnJlbnRVcGxvYWRzIDw9IHRoaXMuX3NlbmRpbmcpKSB7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5saW1pdENvbmN1cnJlbnRVcGxvYWRzID4gMSkge1xuICAgICAgICAgICAgICAgICAgICBzbG90ID0gJC5EZWZlcnJlZCgpO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9zbG90cy5wdXNoKHNsb3QpO1xuICAgICAgICAgICAgICAgICAgICBwaXBlID0gc2xvdC50aGVuKHNlbmQpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuX3NlcXVlbmNlID0gdGhpcy5fc2VxdWVuY2UudGhlbihzZW5kLCBzZW5kKTtcbiAgICAgICAgICAgICAgICAgICAgcGlwZSA9IHRoaXMuX3NlcXVlbmNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBSZXR1cm4gdGhlIHBpcGVkIFByb21pc2Ugb2JqZWN0LCBlbmhhbmNlZCB3aXRoIGFuIGFib3J0IG1ldGhvZCxcbiAgICAgICAgICAgICAgICAvLyB3aGljaCBpcyBkZWxlZ2F0ZWQgdG8gdGhlIGpxWEhSIG9iamVjdCBvZiB0aGUgY3VycmVudCB1cGxvYWQsXG4gICAgICAgICAgICAgICAgLy8gYW5kIGpxWEhSIGNhbGxiYWNrcyBtYXBwZWQgdG8gdGhlIGVxdWl2YWxlbnQgUHJvbWlzZSBtZXRob2RzOlxuICAgICAgICAgICAgICAgIHBpcGUuYWJvcnQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIGFib3J0ZWQgPSBbdW5kZWZpbmVkLCAnYWJvcnQnLCAnYWJvcnQnXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFqcVhIUikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHNsb3QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzbG90LnJlamVjdFdpdGgob3B0aW9ucy5jb250ZXh0LCBhYm9ydGVkKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBzZW5kKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGpxWEhSLmFib3J0KCk7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fZW5oYW5jZVByb21pc2UocGlwZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gc2VuZCgpO1xuICAgICAgICB9LFxuXG4gICAgICAgIF9vbkFkZDogZnVuY3Rpb24gKGUsIGRhdGEpIHtcbiAgICAgICAgICAgIHZhciB0aGF0ID0gdGhpcyxcbiAgICAgICAgICAgICAgICByZXN1bHQgPSB0cnVlLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgdGhpcy5vcHRpb25zLCBkYXRhKSxcbiAgICAgICAgICAgICAgICBmaWxlcyA9IGRhdGEuZmlsZXMsXG4gICAgICAgICAgICAgICAgZmlsZXNMZW5ndGggPSBmaWxlcy5sZW5ndGgsXG4gICAgICAgICAgICAgICAgbGltaXQgPSBvcHRpb25zLmxpbWl0TXVsdGlGaWxlVXBsb2FkcyxcbiAgICAgICAgICAgICAgICBsaW1pdFNpemUgPSBvcHRpb25zLmxpbWl0TXVsdGlGaWxlVXBsb2FkU2l6ZSxcbiAgICAgICAgICAgICAgICBvdmVyaGVhZCA9IG9wdGlvbnMubGltaXRNdWx0aUZpbGVVcGxvYWRTaXplT3ZlcmhlYWQsXG4gICAgICAgICAgICAgICAgYmF0Y2hTaXplID0gMCxcbiAgICAgICAgICAgICAgICBwYXJhbU5hbWUgPSB0aGlzLl9nZXRQYXJhbU5hbWUob3B0aW9ucyksXG4gICAgICAgICAgICAgICAgcGFyYW1OYW1lU2V0LFxuICAgICAgICAgICAgICAgIHBhcmFtTmFtZVNsaWNlLFxuICAgICAgICAgICAgICAgIGZpbGVTZXQsXG4gICAgICAgICAgICAgICAgaSxcbiAgICAgICAgICAgICAgICBqID0gMDtcbiAgICAgICAgICAgIGlmICghZmlsZXNMZW5ndGgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobGltaXRTaXplICYmIGZpbGVzWzBdLnNpemUgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGxpbWl0U2l6ZSA9IHVuZGVmaW5lZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghKG9wdGlvbnMuc2luZ2xlRmlsZVVwbG9hZHMgfHwgbGltaXQgfHwgbGltaXRTaXplKSB8fFxuICAgICAgICAgICAgICAgICAgICAhdGhpcy5faXNYSFJVcGxvYWQob3B0aW9ucykpIHtcbiAgICAgICAgICAgICAgICBmaWxlU2V0ID0gW2ZpbGVzXTtcbiAgICAgICAgICAgICAgICBwYXJhbU5hbWVTZXQgPSBbcGFyYW1OYW1lXTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoIShvcHRpb25zLnNpbmdsZUZpbGVVcGxvYWRzIHx8IGxpbWl0U2l6ZSkgJiYgbGltaXQpIHtcbiAgICAgICAgICAgICAgICBmaWxlU2V0ID0gW107XG4gICAgICAgICAgICAgICAgcGFyYW1OYW1lU2V0ID0gW107XG4gICAgICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IGZpbGVzTGVuZ3RoOyBpICs9IGxpbWl0KSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbGVTZXQucHVzaChmaWxlcy5zbGljZShpLCBpICsgbGltaXQpKTtcbiAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lU2xpY2UgPSBwYXJhbU5hbWUuc2xpY2UoaSwgaSArIGxpbWl0KTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFwYXJhbU5hbWVTbGljZS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtTmFtZVNsaWNlID0gcGFyYW1OYW1lO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHBhcmFtTmFtZVNldC5wdXNoKHBhcmFtTmFtZVNsaWNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCFvcHRpb25zLnNpbmdsZUZpbGVVcGxvYWRzICYmIGxpbWl0U2l6ZSkge1xuICAgICAgICAgICAgICAgIGZpbGVTZXQgPSBbXTtcbiAgICAgICAgICAgICAgICBwYXJhbU5hbWVTZXQgPSBbXTtcbiAgICAgICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgZmlsZXNMZW5ndGg7IGkgPSBpICsgMSkge1xuICAgICAgICAgICAgICAgICAgICBiYXRjaFNpemUgKz0gZmlsZXNbaV0uc2l6ZSArIG92ZXJoZWFkO1xuICAgICAgICAgICAgICAgICAgICBpZiAoaSArIDEgPT09IGZpbGVzTGVuZ3RoIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgKChiYXRjaFNpemUgKyBmaWxlc1tpICsgMV0uc2l6ZSArIG92ZXJoZWFkKSA+IGxpbWl0U2l6ZSkgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAobGltaXQgJiYgaSArIDEgLSBqID49IGxpbWl0KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZmlsZVNldC5wdXNoKGZpbGVzLnNsaWNlKGosIGkgKyAxKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBwYXJhbU5hbWVTbGljZSA9IHBhcmFtTmFtZS5zbGljZShqLCBpICsgMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXBhcmFtTmFtZVNsaWNlLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhcmFtTmFtZVNsaWNlID0gcGFyYW1OYW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgcGFyYW1OYW1lU2V0LnB1c2gocGFyYW1OYW1lU2xpY2UpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaiA9IGkgKyAxO1xuICAgICAgICAgICAgICAgICAgICAgICAgYmF0Y2hTaXplID0gMDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcGFyYW1OYW1lU2V0ID0gcGFyYW1OYW1lO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGF0YS5vcmlnaW5hbEZpbGVzID0gZmlsZXM7XG4gICAgICAgICAgICAkLmVhY2goZmlsZVNldCB8fCBmaWxlcywgZnVuY3Rpb24gKGluZGV4LCBlbGVtZW50KSB7XG4gICAgICAgICAgICAgICAgdmFyIG5ld0RhdGEgPSAkLmV4dGVuZCh7fSwgZGF0YSk7XG4gICAgICAgICAgICAgICAgbmV3RGF0YS5maWxlcyA9IGZpbGVTZXQgPyBlbGVtZW50IDogW2VsZW1lbnRdO1xuICAgICAgICAgICAgICAgIG5ld0RhdGEucGFyYW1OYW1lID0gcGFyYW1OYW1lU2V0W2luZGV4XTtcbiAgICAgICAgICAgICAgICB0aGF0Ll9pbml0UmVzcG9uc2VPYmplY3QobmV3RGF0YSk7XG4gICAgICAgICAgICAgICAgdGhhdC5faW5pdFByb2dyZXNzT2JqZWN0KG5ld0RhdGEpO1xuICAgICAgICAgICAgICAgIHRoYXQuX2FkZENvbnZlbmllbmNlTWV0aG9kcyhlLCBuZXdEYXRhKTtcbiAgICAgICAgICAgICAgICByZXN1bHQgPSB0aGF0Ll90cmlnZ2VyKFxuICAgICAgICAgICAgICAgICAgICAnYWRkJyxcbiAgICAgICAgICAgICAgICAgICAgJC5FdmVudCgnYWRkJywge2RlbGVnYXRlZEV2ZW50OiBlfSksXG4gICAgICAgICAgICAgICAgICAgIG5ld0RhdGFcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiByZXN1bHQ7XG4gICAgICAgIH0sXG5cbiAgICAgICAgX3JlcGxhY2VGaWxlSW5wdXQ6IGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgICAgICB2YXIgaW5wdXQgPSBkYXRhLmZpbGVJbnB1dCxcbiAgICAgICAgICAgICAgICBpbnB1dENsb25lID0gaW5wdXQuY2xvbmUodHJ1ZSksXG4gICAgICAgICAgICAgICAgcmVzdG9yZUZvY3VzID0gaW5wdXQuaXMoZG9jdW1lbnQuYWN0aXZlRWxlbWVudCk7XG4gICAgICAgICAgICAvLyBBZGQgYSByZWZlcmVuY2UgZm9yIHRoZSBuZXcgY2xvbmVkIGZpbGUgaW5wdXQgdG8gdGhlIGRhdGEgYXJndW1lbnQ6XG4gICAgICAgICAgICBkYXRhLmZpbGVJbnB1dENsb25lID0gaW5wdXRDbG9uZTtcbiAgICAgICAgICAgICQoJzxmb3JtPjwvZm9ybT4nKS5hcHBlbmQoaW5wdXRDbG9uZSlbMF0ucmVzZXQoKTtcbiAgICAgICAgICAgIC8vIERldGFjaGluZyBhbGxvd3MgdG8gaW5zZXJ0IHRoZSBmaWxlSW5wdXQgb24gYW5vdGhlciBmb3JtXG4gICAgICAgICAgICAvLyB3aXRob3V0IGxvb3NpbmcgdGhlIGZpbGUgaW5wdXQgdmFsdWU6XG4gICAgICAgICAgICBpbnB1dC5hZnRlcihpbnB1dENsb25lKS5kZXRhY2goKTtcbiAgICAgICAgICAgIC8vIElmIHRoZSBmaWxlSW5wdXQgaGFkIGZvY3VzIGJlZm9yZSBpdCB3YXMgZGV0YWNoZWQsXG4gICAgICAgICAgICAvLyByZXN0b3JlIGZvY3VzIHRvIHRoZSBpbnB1dENsb25lLlxuICAgICAgICAgICAgaWYgKHJlc3RvcmVGb2N1cykge1xuICAgICAgICAgICAgICAgIGlucHV0Q2xvbmUuZm9jdXMoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIC8vIEF2b2lkIG1lbW9yeSBsZWFrcyB3aXRoIHRoZSBkZXRhY2hlZCBmaWxlIGlucHV0OlxuICAgICAgICAgICAgJC5jbGVhbkRhdGEoaW5wdXQudW5iaW5kKCdyZW1vdmUnKSk7XG4gICAgICAgICAgICAvLyBSZXBsYWNlIHRoZSBvcmlnaW5hbCBmaWxlIGlucHV0IGVsZW1lbnQgaW4gdGhlIGZpbGVJbnB1dFxuICAgICAgICAgICAgLy8gZWxlbWVudHMgc2V0IHdpdGggdGhlIGNsb25lLCB3aGljaCBoYXMgYmVlbiBjb3BpZWQgaW5jbHVkaW5nXG4gICAgICAgICAgICAvLyBldmVudCBoYW5kbGVyczpcbiAgICAgICAgICAgIHRoaXMub3B0aW9ucy5maWxlSW5wdXQgPSB0aGlzLm9wdGlvbnMuZmlsZUlucHV0Lm1hcChmdW5jdGlvbiAoaSwgZWwpIHtcbiAgICAgICAgICAgICAgICBpZiAoZWwgPT09IGlucHV0WzBdKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBpbnB1dENsb25lWzBdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gZWw7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIC8vIElmIHRoZSB3aWRnZXQgaGFzIGJlZW4gaW5pdGlhbGl6ZWQgb24gdGhlIGZpbGUgaW5wdXQgaXRzZWxmLFxuICAgICAgICAgICAgLy8gb3ZlcnJpZGUgdGhpcy5lbGVtZW50IHdpdGggdGhlIGZpbGUgaW5wdXQgY2xvbmU6XG4gICAgICAgICAgICBpZiAoaW5wdXRbMF0gPT09IHRoaXMuZWxlbWVudFswXSkge1xuICAgICAgICAgICAgICAgIHRoaXMuZWxlbWVudCA9IGlucHV0Q2xvbmU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgX2hhbmRsZUZpbGVUcmVlRW50cnk6IGZ1bmN0aW9uIChlbnRyeSwgcGF0aCkge1xuICAgICAgICAgICAgdmFyIHRoYXQgPSB0aGlzLFxuICAgICAgICAgICAgICAgIGRmZCA9ICQuRGVmZXJyZWQoKSxcbiAgICAgICAgICAgICAgICBlbnRyaWVzID0gW10sXG4gICAgICAgICAgICAgICAgZGlyUmVhZGVyLFxuICAgICAgICAgICAgICAgIGVycm9ySGFuZGxlciA9IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChlICYmICFlLmVudHJ5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlLmVudHJ5ID0gZW50cnk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgLy8gU2luY2UgJC53aGVuIHJldHVybnMgaW1tZWRpYXRlbHkgaWYgb25lXG4gICAgICAgICAgICAgICAgICAgIC8vIERlZmVycmVkIGlzIHJlamVjdGVkLCB3ZSB1c2UgcmVzb2x2ZSBpbnN0ZWFkLlxuICAgICAgICAgICAgICAgICAgICAvLyBUaGlzIGFsbG93cyB2YWxpZCBmaWxlcyBhbmQgaW52YWxpZCBpdGVtc1xuICAgICAgICAgICAgICAgICAgICAvLyB0byBiZSByZXR1cm5lZCB0b2dldGhlciBpbiBvbmUgc2V0OlxuICAgICAgICAgICAgICAgICAgICBkZmQucmVzb2x2ZShbZV0pO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgc3VjY2Vzc0hhbmRsZXIgPSBmdW5jdGlvbiAoZW50cmllcykge1xuICAgICAgICAgICAgICAgICAgICB0aGF0Ll9oYW5kbGVGaWxlVHJlZUVudHJpZXMoXG4gICAgICAgICAgICAgICAgICAgICAgICBlbnRyaWVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgcGF0aCArIGVudHJ5Lm5hbWUgKyAnLydcbiAgICAgICAgICAgICAgICAgICAgKS5kb25lKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGZkLnJlc29sdmUoZmlsZXMpO1xuICAgICAgICAgICAgICAgICAgICB9KS5mYWlsKGVycm9ySGFuZGxlcik7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICByZWFkRW50cmllcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgZGlyUmVhZGVyLnJlYWRFbnRyaWVzKGZ1bmN0aW9uIChyZXN1bHRzKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXJlc3VsdHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3VjY2Vzc0hhbmRsZXIoZW50cmllcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudHJpZXMgPSBlbnRyaWVzLmNvbmNhdChyZXN1bHRzKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWFkRW50cmllcygpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9LCBlcnJvckhhbmRsZXIpO1xuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICBwYXRoID0gcGF0aCB8fCAnJztcbiAgICAgICAgICAgIGlmIChlbnRyeS5pc0ZpbGUpIHtcbiAgICAgICAgICAgICAgICBpZiAoZW50cnkuX2ZpbGUpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gV29ya2Fyb3VuZCBmb3IgQ2hyb21lIGJ1ZyAjMTQ5NzM1XG4gICAgICAgICAgICAgICAgICAgIGVudHJ5Ll9maWxlLnJlbGF0aXZlUGF0aCA9IHBhdGg7XG4gICAgICAgICAgICAgICAgICAgIGRmZC5yZXNvbHZlKGVudHJ5Ll9maWxlKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBlbnRyeS5maWxlKGZ1bmN0aW9uIChmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmaWxlLnJlbGF0aXZlUGF0aCA9IHBhdGg7XG4gICAgICAgICAgICAgICAgICAgICAgICBkZmQucmVzb2x2ZShmaWxlKTtcbiAgICAgICAgICAgICAgICAgICAgfSwgZXJyb3JIYW5kbGVyKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGVudHJ5LmlzRGlyZWN0b3J5KSB7XG4gICAgICAgICAgICAgICAgZGlyUmVhZGVyID0gZW50cnkuY3JlYXRlUmVhZGVyKCk7XG4gICAgICAgICAgICAgICAgcmVhZEVudHJpZXMoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gUmV0dXJuIGFuIGVtcHR5IGxpc3QgZm9yIGZpbGUgc3lzdGVtIGl0ZW1zXG4gICAgICAgICAgICAgICAgLy8gb3RoZXIgdGhhbiBmaWxlcyBvciBkaXJlY3RvcmllczpcbiAgICAgICAgICAgICAgICBkZmQucmVzb2x2ZShbXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gZGZkLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICBfaGFuZGxlRmlsZVRyZWVFbnRyaWVzOiBmdW5jdGlvbiAoZW50cmllcywgcGF0aCkge1xuICAgICAgICAgICAgdmFyIHRoYXQgPSB0aGlzO1xuICAgICAgICAgICAgcmV0dXJuICQud2hlbi5hcHBseShcbiAgICAgICAgICAgICAgICAkLFxuICAgICAgICAgICAgICAgICQubWFwKGVudHJpZXMsIGZ1bmN0aW9uIChlbnRyeSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhhdC5faGFuZGxlRmlsZVRyZWVFbnRyeShlbnRyeSwgcGF0aCk7XG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICkudGhlbihmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIEFycmF5LnByb3RvdHlwZS5jb25jYXQuYXBwbHkoXG4gICAgICAgICAgICAgICAgICAgIFtdLFxuICAgICAgICAgICAgICAgICAgICBhcmd1bWVudHNcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgX2dldERyb3BwZWRGaWxlczogZnVuY3Rpb24gKGRhdGFUcmFuc2Zlcikge1xuICAgICAgICAgICAgZGF0YVRyYW5zZmVyID0gZGF0YVRyYW5zZmVyIHx8IHt9O1xuICAgICAgICAgICAgdmFyIGl0ZW1zID0gZGF0YVRyYW5zZmVyLml0ZW1zO1xuICAgICAgICAgICAgaWYgKGl0ZW1zICYmIGl0ZW1zLmxlbmd0aCAmJiAoaXRlbXNbMF0ud2Via2l0R2V0QXNFbnRyeSB8fFxuICAgICAgICAgICAgICAgICAgICBpdGVtc1swXS5nZXRBc0VudHJ5KSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9oYW5kbGVGaWxlVHJlZUVudHJpZXMoXG4gICAgICAgICAgICAgICAgICAgICQubWFwKGl0ZW1zLCBmdW5jdGlvbiAoaXRlbSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGVudHJ5O1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0ud2Via2l0R2V0QXNFbnRyeSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVudHJ5ID0gaXRlbS53ZWJraXRHZXRBc0VudHJ5KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVudHJ5KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFdvcmthcm91bmQgZm9yIENocm9tZSBidWcgIzE0OTczNTpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW50cnkuX2ZpbGUgPSBpdGVtLmdldEFzRmlsZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZW50cnk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gaXRlbS5nZXRBc0VudHJ5KCk7XG4gICAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAkLkRlZmVycmVkKCkucmVzb2x2ZShcbiAgICAgICAgICAgICAgICAkLm1ha2VBcnJheShkYXRhVHJhbnNmZXIuZmlsZXMpXG4gICAgICAgICAgICApLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICBfZ2V0U2luZ2xlRmlsZUlucHV0RmlsZXM6IGZ1bmN0aW9uIChmaWxlSW5wdXQpIHtcbiAgICAgICAgICAgIGZpbGVJbnB1dCA9ICQoZmlsZUlucHV0KTtcbiAgICAgICAgICAgIHZhciBlbnRyaWVzID0gZmlsZUlucHV0LnByb3AoJ3dlYmtpdEVudHJpZXMnKSB8fFxuICAgICAgICAgICAgICAgICAgICBmaWxlSW5wdXQucHJvcCgnZW50cmllcycpLFxuICAgICAgICAgICAgICAgIGZpbGVzLFxuICAgICAgICAgICAgICAgIHZhbHVlO1xuICAgICAgICAgICAgaWYgKGVudHJpZXMgJiYgZW50cmllcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5faGFuZGxlRmlsZVRyZWVFbnRyaWVzKGVudHJpZXMpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZmlsZXMgPSAkLm1ha2VBcnJheShmaWxlSW5wdXQucHJvcCgnZmlsZXMnKSk7XG4gICAgICAgICAgICBpZiAoIWZpbGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhbHVlID0gZmlsZUlucHV0LnByb3AoJ3ZhbHVlJyk7XG4gICAgICAgICAgICAgICAgaWYgKCF2YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoW10pLnByb21pc2UoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gSWYgdGhlIGZpbGVzIHByb3BlcnR5IGlzIG5vdCBhdmFpbGFibGUsIHRoZSBicm93c2VyIGRvZXMgbm90XG4gICAgICAgICAgICAgICAgLy8gc3VwcG9ydCB0aGUgRmlsZSBBUEkgYW5kIHdlIGFkZCBhIHBzZXVkbyBGaWxlIG9iamVjdCB3aXRoXG4gICAgICAgICAgICAgICAgLy8gdGhlIGlucHV0IHZhbHVlIGFzIG5hbWUgd2l0aCBwYXRoIGluZm9ybWF0aW9uIHJlbW92ZWQ6XG4gICAgICAgICAgICAgICAgZmlsZXMgPSBbe25hbWU6IHZhbHVlLnJlcGxhY2UoL14uKlxcXFwvLCAnJyl9XTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoZmlsZXNbMF0ubmFtZSA9PT0gdW5kZWZpbmVkICYmIGZpbGVzWzBdLmZpbGVOYW1lKSB7XG4gICAgICAgICAgICAgICAgLy8gRmlsZSBub3JtYWxpemF0aW9uIGZvciBTYWZhcmkgNCBhbmQgRmlyZWZveCAzOlxuICAgICAgICAgICAgICAgICQuZWFjaChmaWxlcywgZnVuY3Rpb24gKGluZGV4LCBmaWxlKSB7XG4gICAgICAgICAgICAgICAgICAgIGZpbGUubmFtZSA9IGZpbGUuZmlsZU5hbWU7XG4gICAgICAgICAgICAgICAgICAgIGZpbGUuc2l6ZSA9IGZpbGUuZmlsZVNpemU7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gJC5EZWZlcnJlZCgpLnJlc29sdmUoZmlsZXMpLnByb21pc2UoKTtcbiAgICAgICAgfSxcblxuICAgICAgICBfZ2V0RmlsZUlucHV0RmlsZXM6IGZ1bmN0aW9uIChmaWxlSW5wdXQpIHtcbiAgICAgICAgICAgIGlmICghKGZpbGVJbnB1dCBpbnN0YW5jZW9mICQpIHx8IGZpbGVJbnB1dC5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fZ2V0U2luZ2xlRmlsZUlucHV0RmlsZXMoZmlsZUlucHV0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiAkLndoZW4uYXBwbHkoXG4gICAgICAgICAgICAgICAgJCxcbiAgICAgICAgICAgICAgICAkLm1hcChmaWxlSW5wdXQsIHRoaXMuX2dldFNpbmdsZUZpbGVJbnB1dEZpbGVzKVxuICAgICAgICAgICAgKS50aGVuKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gQXJyYXkucHJvdG90eXBlLmNvbmNhdC5hcHBseShcbiAgICAgICAgICAgICAgICAgICAgW10sXG4gICAgICAgICAgICAgICAgICAgIGFyZ3VtZW50c1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcblxuICAgICAgICBfb25DaGFuZ2U6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICB2YXIgdGhhdCA9IHRoaXMsXG4gICAgICAgICAgICAgICAgZGF0YSA9IHtcbiAgICAgICAgICAgICAgICAgICAgZmlsZUlucHV0OiAkKGUudGFyZ2V0KSxcbiAgICAgICAgICAgICAgICAgICAgZm9ybTogJChlLnRhcmdldC5mb3JtKVxuICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICB0aGlzLl9nZXRGaWxlSW5wdXRGaWxlcyhkYXRhLmZpbGVJbnB1dCkuYWx3YXlzKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgIGRhdGEuZmlsZXMgPSBmaWxlcztcbiAgICAgICAgICAgICAgICBpZiAodGhhdC5vcHRpb25zLnJlcGxhY2VGaWxlSW5wdXQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhhdC5fcmVwbGFjZUZpbGVJbnB1dChkYXRhKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHRoYXQuX3RyaWdnZXIoXG4gICAgICAgICAgICAgICAgICAgICAgICAnY2hhbmdlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICQuRXZlbnQoJ2NoYW5nZScsIHtkZWxlZ2F0ZWRFdmVudDogZX0pLFxuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVxuICAgICAgICAgICAgICAgICAgICApICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGF0Ll9vbkFkZChlLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcblxuICAgICAgICBfb25QYXN0ZTogZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIHZhciBpdGVtcyA9IGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQuY2xpcGJvYXJkRGF0YSAmJlxuICAgICAgICAgICAgICAgICAgICBlLm9yaWdpbmFsRXZlbnQuY2xpcGJvYXJkRGF0YS5pdGVtcyxcbiAgICAgICAgICAgICAgICBkYXRhID0ge2ZpbGVzOiBbXX07XG4gICAgICAgICAgICBpZiAoaXRlbXMgJiYgaXRlbXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgJC5lYWNoKGl0ZW1zLCBmdW5jdGlvbiAoaW5kZXgsIGl0ZW0pIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGZpbGUgPSBpdGVtLmdldEFzRmlsZSAmJiBpdGVtLmdldEFzRmlsZSgpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZmlsZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGF0YS5maWxlcy5wdXNoKGZpbGUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuX3RyaWdnZXIoXG4gICAgICAgICAgICAgICAgICAgICAgICAncGFzdGUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgJC5FdmVudCgncGFzdGUnLCB7ZGVsZWdhdGVkRXZlbnQ6IGV9KSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGFcbiAgICAgICAgICAgICAgICAgICAgKSAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fb25BZGQoZSwgZGF0YSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIF9vbkRyb3A6IGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICBlLmRhdGFUcmFuc2ZlciA9IGUub3JpZ2luYWxFdmVudCAmJiBlLm9yaWdpbmFsRXZlbnQuZGF0YVRyYW5zZmVyO1xuICAgICAgICAgICAgdmFyIHRoYXQgPSB0aGlzLFxuICAgICAgICAgICAgICAgIGRhdGFUcmFuc2ZlciA9IGUuZGF0YVRyYW5zZmVyLFxuICAgICAgICAgICAgICAgIGRhdGEgPSB7fTtcbiAgICAgICAgICAgIGlmIChkYXRhVHJhbnNmZXIgJiYgZGF0YVRyYW5zZmVyLmZpbGVzICYmIGRhdGFUcmFuc2Zlci5maWxlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgdGhpcy5fZ2V0RHJvcHBlZEZpbGVzKGRhdGFUcmFuc2ZlcikuYWx3YXlzKGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICBkYXRhLmZpbGVzID0gZmlsZXM7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGF0Ll90cmlnZ2VyKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdkcm9wJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAkLkV2ZW50KCdkcm9wJywge2RlbGVnYXRlZEV2ZW50OiBlfSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZGF0YVxuICAgICAgICAgICAgICAgICAgICAgICAgKSAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoYXQuX29uQWRkKGUsIGRhdGEpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgX29uRHJhZ092ZXI6IGdldERyYWdIYW5kbGVyKCdkcmFnb3ZlcicpLFxuXG4gICAgICAgIF9vbkRyYWdFbnRlcjogZ2V0RHJhZ0hhbmRsZXIoJ2RyYWdlbnRlcicpLFxuXG4gICAgICAgIF9vbkRyYWdMZWF2ZTogZ2V0RHJhZ0hhbmRsZXIoJ2RyYWdsZWF2ZScpLFxuXG4gICAgICAgIF9pbml0RXZlbnRIYW5kbGVyczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgaWYgKHRoaXMuX2lzWEhSVXBsb2FkKHRoaXMub3B0aW9ucykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9vbih0aGlzLm9wdGlvbnMuZHJvcFpvbmUsIHtcbiAgICAgICAgICAgICAgICAgICAgZHJhZ292ZXI6IHRoaXMuX29uRHJhZ092ZXIsXG4gICAgICAgICAgICAgICAgICAgIGRyb3A6IHRoaXMuX29uRHJvcCxcbiAgICAgICAgICAgICAgICAgICAgLy8gZXZlbnQucHJldmVudERlZmF1bHQoKSBvbiBkcmFnZW50ZXIgaXMgcmVxdWlyZWQgZm9yIElFMTArOlxuICAgICAgICAgICAgICAgICAgICBkcmFnZW50ZXI6IHRoaXMuX29uRHJhZ0VudGVyLFxuICAgICAgICAgICAgICAgICAgICAvLyBkcmFnbGVhdmUgaXMgbm90IHJlcXVpcmVkLCBidXQgYWRkZWQgZm9yIGNvbXBsZXRlbmVzczpcbiAgICAgICAgICAgICAgICAgICAgZHJhZ2xlYXZlOiB0aGlzLl9vbkRyYWdMZWF2ZVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIHRoaXMuX29uKHRoaXMub3B0aW9ucy5wYXN0ZVpvbmUsIHtcbiAgICAgICAgICAgICAgICAgICAgcGFzdGU6IHRoaXMuX29uUGFzdGVcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICgkLnN1cHBvcnQuZmlsZUlucHV0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5fb24odGhpcy5vcHRpb25zLmZpbGVJbnB1dCwge1xuICAgICAgICAgICAgICAgICAgICBjaGFuZ2U6IHRoaXMuX29uQ2hhbmdlXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG5cbiAgICAgICAgX2Rlc3Ryb3lFdmVudEhhbmRsZXJzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLl9vZmYodGhpcy5vcHRpb25zLmRyb3Bab25lLCAnZHJhZ2VudGVyIGRyYWdsZWF2ZSBkcmFnb3ZlciBkcm9wJyk7XG4gICAgICAgICAgICB0aGlzLl9vZmYodGhpcy5vcHRpb25zLnBhc3RlWm9uZSwgJ3Bhc3RlJyk7XG4gICAgICAgICAgICB0aGlzLl9vZmYodGhpcy5vcHRpb25zLmZpbGVJbnB1dCwgJ2NoYW5nZScpO1xuICAgICAgICB9LFxuXG4gICAgICAgIF9kZXN0cm95OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLl9kZXN0cm95RXZlbnRIYW5kbGVycygpO1xuICAgICAgICB9LFxuXG4gICAgICAgIF9zZXRPcHRpb246IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICB2YXIgcmVpbml0ID0gJC5pbkFycmF5KGtleSwgdGhpcy5fc3BlY2lhbE9wdGlvbnMpICE9PSAtMTtcbiAgICAgICAgICAgIGlmIChyZWluaXQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLl9kZXN0cm95RXZlbnRIYW5kbGVycygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5fc3VwZXIoa2V5LCB2YWx1ZSk7XG4gICAgICAgICAgICBpZiAocmVpbml0KSB7XG4gICAgICAgICAgICAgICAgdGhpcy5faW5pdFNwZWNpYWxPcHRpb25zKCk7XG4gICAgICAgICAgICAgICAgdGhpcy5faW5pdEV2ZW50SGFuZGxlcnMoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICBfaW5pdFNwZWNpYWxPcHRpb25zOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcbiAgICAgICAgICAgIGlmIChvcHRpb25zLmZpbGVJbnB1dCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5maWxlSW5wdXQgPSB0aGlzLmVsZW1lbnQuaXMoJ2lucHV0W3R5cGU9XCJmaWxlXCJdJykgP1xuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5lbGVtZW50IDogdGhpcy5lbGVtZW50LmZpbmQoJ2lucHV0W3R5cGU9XCJmaWxlXCJdJyk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCEob3B0aW9ucy5maWxlSW5wdXQgaW5zdGFuY2VvZiAkKSkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuZmlsZUlucHV0ID0gJChvcHRpb25zLmZpbGVJbnB1dCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoIShvcHRpb25zLmRyb3Bab25lIGluc3RhbmNlb2YgJCkpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLmRyb3Bab25lID0gJChvcHRpb25zLmRyb3Bab25lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICghKG9wdGlvbnMucGFzdGVab25lIGluc3RhbmNlb2YgJCkpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zLnBhc3RlWm9uZSA9ICQob3B0aW9ucy5wYXN0ZVpvbmUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuXG4gICAgICAgIF9nZXRSZWdFeHA6IGZ1bmN0aW9uIChzdHIpIHtcbiAgICAgICAgICAgIHZhciBwYXJ0cyA9IHN0ci5zcGxpdCgnLycpLFxuICAgICAgICAgICAgICAgIG1vZGlmaWVycyA9IHBhcnRzLnBvcCgpO1xuICAgICAgICAgICAgcGFydHMuc2hpZnQoKTtcbiAgICAgICAgICAgIHJldHVybiBuZXcgUmVnRXhwKHBhcnRzLmpvaW4oJy8nKSwgbW9kaWZpZXJzKTtcbiAgICAgICAgfSxcblxuICAgICAgICBfaXNSZWdFeHBPcHRpb246IGZ1bmN0aW9uIChrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICByZXR1cm4ga2V5ICE9PSAndXJsJyAmJiAkLnR5cGUodmFsdWUpID09PSAnc3RyaW5nJyAmJlxuICAgICAgICAgICAgICAgIC9eXFwvLipcXC9baWdtXXswLDN9JC8udGVzdCh2YWx1ZSk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgX2luaXREYXRhQXR0cmlidXRlczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHRoYXQgPSB0aGlzLFxuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnMsXG4gICAgICAgICAgICAgICAgZGF0YSA9IHRoaXMuZWxlbWVudC5kYXRhKCk7XG4gICAgICAgICAgICAvLyBJbml0aWFsaXplIG9wdGlvbnMgc2V0IHZpYSBIVE1MNSBkYXRhLWF0dHJpYnV0ZXM6XG4gICAgICAgICAgICAkLmVhY2goXG4gICAgICAgICAgICAgICAgdGhpcy5lbGVtZW50WzBdLmF0dHJpYnV0ZXMsXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKGluZGV4LCBhdHRyKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBrZXkgPSBhdHRyLm5hbWUudG9Mb3dlckNhc2UoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlO1xuICAgICAgICAgICAgICAgICAgICBpZiAoL15kYXRhLS8udGVzdChrZXkpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDb252ZXJ0IGh5cGhlbi1hdGVkIGtleSB0byBjYW1lbENhc2U6XG4gICAgICAgICAgICAgICAgICAgICAgICBrZXkgPSBrZXkuc2xpY2UoNSkucmVwbGFjZSgvLVthLXpdL2csIGZ1bmN0aW9uIChzdHIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gc3RyLmNoYXJBdCgxKS50b1VwcGVyQ2FzZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGRhdGFba2V5XTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGF0Ll9pc1JlZ0V4cE9wdGlvbihrZXksIHZhbHVlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdGhhdC5fZ2V0UmVnRXhwKHZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIG9wdGlvbnNba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSxcblxuICAgICAgICBfY3JlYXRlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLl9pbml0RGF0YUF0dHJpYnV0ZXMoKTtcbiAgICAgICAgICAgIHRoaXMuX2luaXRTcGVjaWFsT3B0aW9ucygpO1xuICAgICAgICAgICAgdGhpcy5fc2xvdHMgPSBbXTtcbiAgICAgICAgICAgIHRoaXMuX3NlcXVlbmNlID0gdGhpcy5fZ2V0WEhSUHJvbWlzZSh0cnVlKTtcbiAgICAgICAgICAgIHRoaXMuX3NlbmRpbmcgPSB0aGlzLl9hY3RpdmUgPSAwO1xuICAgICAgICAgICAgdGhpcy5faW5pdFByb2dyZXNzT2JqZWN0KHRoaXMpO1xuICAgICAgICAgICAgdGhpcy5faW5pdEV2ZW50SGFuZGxlcnMoKTtcbiAgICAgICAgfSxcblxuICAgICAgICAvLyBUaGlzIG1ldGhvZCBpcyBleHBvc2VkIHRvIHRoZSB3aWRnZXQgQVBJIGFuZCBhbGxvd3MgdG8gcXVlcnlcbiAgICAgICAgLy8gdGhlIG51bWJlciBvZiBhY3RpdmUgdXBsb2FkczpcbiAgICAgICAgYWN0aXZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fYWN0aXZlO1xuICAgICAgICB9LFxuXG4gICAgICAgIC8vIFRoaXMgbWV0aG9kIGlzIGV4cG9zZWQgdG8gdGhlIHdpZGdldCBBUEkgYW5kIGFsbG93cyB0byBxdWVyeVxuICAgICAgICAvLyB0aGUgd2lkZ2V0IHVwbG9hZCBwcm9ncmVzcy5cbiAgICAgICAgLy8gSXQgcmV0dXJucyBhbiBvYmplY3Qgd2l0aCBsb2FkZWQsIHRvdGFsIGFuZCBiaXRyYXRlIHByb3BlcnRpZXNcbiAgICAgICAgLy8gZm9yIHRoZSBydW5uaW5nIHVwbG9hZHM6XG4gICAgICAgIHByb2dyZXNzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fcHJvZ3Jlc3M7XG4gICAgICAgIH0sXG5cbiAgICAgICAgLy8gVGhpcyBtZXRob2QgaXMgZXhwb3NlZCB0byB0aGUgd2lkZ2V0IEFQSSBhbmQgYWxsb3dzIGFkZGluZyBmaWxlc1xuICAgICAgICAvLyB1c2luZyB0aGUgZmlsZXVwbG9hZCBBUEkuIFRoZSBkYXRhIHBhcmFtZXRlciBhY2NlcHRzIGFuIG9iamVjdCB3aGljaFxuICAgICAgICAvLyBtdXN0IGhhdmUgYSBmaWxlcyBwcm9wZXJ0eSBhbmQgY2FuIGNvbnRhaW4gYWRkaXRpb25hbCBvcHRpb25zOlxuICAgICAgICAvLyAuZmlsZXVwbG9hZCgnYWRkJywge2ZpbGVzOiBmaWxlc0xpc3R9KTtcbiAgICAgICAgYWRkOiBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAgICAgICAgdmFyIHRoYXQgPSB0aGlzO1xuICAgICAgICAgICAgaWYgKCFkYXRhIHx8IHRoaXMub3B0aW9ucy5kaXNhYmxlZCkge1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChkYXRhLmZpbGVJbnB1dCAmJiAhZGF0YS5maWxlcykge1xuICAgICAgICAgICAgICAgIHRoaXMuX2dldEZpbGVJbnB1dEZpbGVzKGRhdGEuZmlsZUlucHV0KS5hbHdheXMoZnVuY3Rpb24gKGZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEuZmlsZXMgPSBmaWxlcztcbiAgICAgICAgICAgICAgICAgICAgdGhhdC5fb25BZGQobnVsbCwgZGF0YSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGRhdGEuZmlsZXMgPSAkLm1ha2VBcnJheShkYXRhLmZpbGVzKTtcbiAgICAgICAgICAgICAgICB0aGlzLl9vbkFkZChudWxsLCBkYXRhKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcblxuICAgICAgICAvLyBUaGlzIG1ldGhvZCBpcyBleHBvc2VkIHRvIHRoZSB3aWRnZXQgQVBJIGFuZCBhbGxvd3Mgc2VuZGluZyBmaWxlc1xuICAgICAgICAvLyB1c2luZyB0aGUgZmlsZXVwbG9hZCBBUEkuIFRoZSBkYXRhIHBhcmFtZXRlciBhY2NlcHRzIGFuIG9iamVjdCB3aGljaFxuICAgICAgICAvLyBtdXN0IGhhdmUgYSBmaWxlcyBvciBmaWxlSW5wdXQgcHJvcGVydHkgYW5kIGNhbiBjb250YWluIGFkZGl0aW9uYWwgb3B0aW9uczpcbiAgICAgICAgLy8gLmZpbGV1cGxvYWQoJ3NlbmQnLCB7ZmlsZXM6IGZpbGVzTGlzdH0pO1xuICAgICAgICAvLyBUaGUgbWV0aG9kIHJldHVybnMgYSBQcm9taXNlIG9iamVjdCBmb3IgdGhlIGZpbGUgdXBsb2FkIGNhbGwuXG4gICAgICAgIHNlbmQ6IGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgICAgICBpZiAoZGF0YSAmJiAhdGhpcy5vcHRpb25zLmRpc2FibGVkKSB7XG4gICAgICAgICAgICAgICAgaWYgKGRhdGEuZmlsZUlucHV0ICYmICFkYXRhLmZpbGVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB0aGF0ID0gdGhpcyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRmZCA9ICQuRGVmZXJyZWQoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHByb21pc2UgPSBkZmQucHJvbWlzZSgpLFxuICAgICAgICAgICAgICAgICAgICAgICAganFYSFIsXG4gICAgICAgICAgICAgICAgICAgICAgICBhYm9ydGVkO1xuICAgICAgICAgICAgICAgICAgICBwcm9taXNlLmFib3J0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWJvcnRlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoanFYSFIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ganFYSFIuYWJvcnQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGRmZC5yZWplY3QobnVsbCwgJ2Fib3J0JywgJ2Fib3J0Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gcHJvbWlzZTtcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fZ2V0RmlsZUlucHV0RmlsZXMoZGF0YS5maWxlSW5wdXQpLmFsd2F5cyhcbiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChmaWxlcykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChhYm9ydGVkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFmaWxlcy5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZkLnJlamVjdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEuZmlsZXMgPSBmaWxlcztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBqcVhIUiA9IHRoYXQuX29uU2VuZChudWxsLCBkYXRhKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBqcVhIUi50aGVuKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAocmVzdWx0LCB0ZXh0U3RhdHVzLCBqcVhIUikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZkLnJlc29sdmUocmVzdWx0LCB0ZXh0U3RhdHVzLCBqcVhIUik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChqcVhIUiwgdGV4dFN0YXR1cywgZXJyb3JUaHJvd24pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmZC5yZWplY3QoanFYSFIsIHRleHRTdGF0dXMsIGVycm9yVGhyb3duKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLl9lbmhhbmNlUHJvbWlzZShwcm9taXNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZGF0YS5maWxlcyA9ICQubWFrZUFycmF5KGRhdGEuZmlsZXMpO1xuICAgICAgICAgICAgICAgIGlmIChkYXRhLmZpbGVzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5fb25TZW5kKG51bGwsIGRhdGEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9nZXRYSFJQcm9taXNlKGZhbHNlLCBkYXRhICYmIGRhdGEuY29udGV4dCk7XG4gICAgICAgIH1cblxuICAgIH0pO1xuXG59KSk7XG4iLCIvLyBTcGVjdHJ1bSBDb2xvcnBpY2tlciB2MS44LjBcbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9iZ3JpbnMvc3BlY3RydW1cbi8vIEF1dGhvcjogQnJpYW4gR3JpbnN0ZWFkXG4vLyBMaWNlbnNlOiBNSVRcblxuKGZ1bmN0aW9uIChmYWN0b3J5KSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG5cbiAgICBpZiAodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKSB7IC8vIEFNRFxuICAgICAgICBkZWZpbmUoWydqcXVlcnknXSwgZmFjdG9yeSk7XG4gICAgfVxuICAgIGVsc2UgaWYgKHR5cGVvZiBleHBvcnRzID09IFwib2JqZWN0XCIgJiYgdHlwZW9mIG1vZHVsZSA9PSBcIm9iamVjdFwiKSB7IC8vIENvbW1vbkpTXG4gICAgICAgIG1vZHVsZS5leHBvcnRzID0gZmFjdG9yeShyZXF1aXJlKCdqcXVlcnknKSk7XG4gICAgfVxuICAgIGVsc2UgeyAvLyBCcm93c2VyXG4gICAgICAgIGZhY3RvcnkoalF1ZXJ5KTtcbiAgICB9XG59KShmdW5jdGlvbigkLCB1bmRlZmluZWQpIHtcbiAgICBcInVzZSBzdHJpY3RcIjtcblxuICAgIHZhciBkZWZhdWx0T3B0cyA9IHtcblxuICAgICAgICAvLyBDYWxsYmFja3NcbiAgICAgICAgYmVmb3JlU2hvdzogbm9vcCxcbiAgICAgICAgbW92ZTogbm9vcCxcbiAgICAgICAgY2hhbmdlOiBub29wLFxuICAgICAgICBzaG93OiBub29wLFxuICAgICAgICBoaWRlOiBub29wLFxuXG4gICAgICAgIC8vIE9wdGlvbnNcbiAgICAgICAgY29sb3I6IGZhbHNlLFxuICAgICAgICBmbGF0OiBmYWxzZSxcbiAgICAgICAgc2hvd0lucHV0OiBmYWxzZSxcbiAgICAgICAgYWxsb3dFbXB0eTogZmFsc2UsXG4gICAgICAgIHNob3dCdXR0b25zOiB0cnVlLFxuICAgICAgICBjbGlja291dEZpcmVzQ2hhbmdlOiB0cnVlLFxuICAgICAgICBzaG93SW5pdGlhbDogZmFsc2UsXG4gICAgICAgIHNob3dQYWxldHRlOiBmYWxzZSxcbiAgICAgICAgc2hvd1BhbGV0dGVPbmx5OiBmYWxzZSxcbiAgICAgICAgaGlkZUFmdGVyUGFsZXR0ZVNlbGVjdDogZmFsc2UsXG4gICAgICAgIHRvZ2dsZVBhbGV0dGVPbmx5OiBmYWxzZSxcbiAgICAgICAgc2hvd1NlbGVjdGlvblBhbGV0dGU6IHRydWUsXG4gICAgICAgIGxvY2FsU3RvcmFnZUtleTogZmFsc2UsXG4gICAgICAgIGFwcGVuZFRvOiBcImJvZHlcIixcbiAgICAgICAgbWF4U2VsZWN0aW9uU2l6ZTogNyxcbiAgICAgICAgY2FuY2VsVGV4dDogXCJjYW5jZWxcIixcbiAgICAgICAgY2hvb3NlVGV4dDogXCJjaG9vc2VcIixcbiAgICAgICAgdG9nZ2xlUGFsZXR0ZU1vcmVUZXh0OiBcIm1vcmVcIixcbiAgICAgICAgdG9nZ2xlUGFsZXR0ZUxlc3NUZXh0OiBcImxlc3NcIixcbiAgICAgICAgY2xlYXJUZXh0OiBcIkNsZWFyIENvbG9yIFNlbGVjdGlvblwiLFxuICAgICAgICBub0NvbG9yU2VsZWN0ZWRUZXh0OiBcIk5vIENvbG9yIFNlbGVjdGVkXCIsXG4gICAgICAgIHByZWZlcnJlZEZvcm1hdDogZmFsc2UsXG4gICAgICAgIGNsYXNzTmFtZTogXCJcIiwgLy8gRGVwcmVjYXRlZCAtIHVzZSBjb250YWluZXJDbGFzc05hbWUgYW5kIHJlcGxhY2VyQ2xhc3NOYW1lIGluc3RlYWQuXG4gICAgICAgIGNvbnRhaW5lckNsYXNzTmFtZTogXCJcIixcbiAgICAgICAgcmVwbGFjZXJDbGFzc05hbWU6IFwiXCIsXG4gICAgICAgIHNob3dBbHBoYTogZmFsc2UsXG4gICAgICAgIHRoZW1lOiBcInNwLWxpZ2h0XCIsXG4gICAgICAgIHBhbGV0dGU6IFtbXCIjZmZmZmZmXCIsIFwiIzAwMDAwMFwiLCBcIiNmZjAwMDBcIiwgXCIjZmY4MDAwXCIsIFwiI2ZmZmYwMFwiLCBcIiMwMDgwMDBcIiwgXCIjMDAwMGZmXCIsIFwiIzRiMDA4MlwiLCBcIiM5NDAwZDNcIl1dLFxuICAgICAgICBzZWxlY3Rpb25QYWxldHRlOiBbXSxcbiAgICAgICAgZGlzYWJsZWQ6IGZhbHNlLFxuICAgICAgICBvZmZzZXQ6IG51bGxcbiAgICB9LFxuICAgIHNwZWN0cnVtcyA9IFtdLFxuICAgIElFID0gISEvbXNpZS9pLmV4ZWMoIHdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50ICksXG4gICAgcmdiYVN1cHBvcnQgPSAoZnVuY3Rpb24oKSB7XG4gICAgICAgIGZ1bmN0aW9uIGNvbnRhaW5zKCBzdHIsIHN1YnN0ciApIHtcbiAgICAgICAgICAgIHJldHVybiAhIX4oJycgKyBzdHIpLmluZGV4T2Yoc3Vic3RyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBlbGVtID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICAgIHZhciBzdHlsZSA9IGVsZW0uc3R5bGU7XG4gICAgICAgIHN0eWxlLmNzc1RleHQgPSAnYmFja2dyb3VuZC1jb2xvcjpyZ2JhKDAsMCwwLC41KSc7XG4gICAgICAgIHJldHVybiBjb250YWlucyhzdHlsZS5iYWNrZ3JvdW5kQ29sb3IsICdyZ2JhJykgfHwgY29udGFpbnMoc3R5bGUuYmFja2dyb3VuZENvbG9yLCAnaHNsYScpO1xuICAgIH0pKCksXG4gICAgcmVwbGFjZUlucHV0ID0gW1xuICAgICAgICBcIjxkaXYgY2xhc3M9J3NwLXJlcGxhY2VyJz5cIixcbiAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3AtcHJldmlldyc+PGRpdiBjbGFzcz0nc3AtcHJldmlldy1pbm5lcic+PC9kaXY+PC9kaXY+XCIsXG4gICAgICAgICAgICBcIjxkaXYgY2xhc3M9J3NwLWRkJz4mIzk2NjA7PC9kaXY+XCIsXG4gICAgICAgIFwiPC9kaXY+XCJcbiAgICBdLmpvaW4oJycpLFxuICAgIG1hcmt1cCA9IChmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgLy8gSUUgZG9lcyBub3Qgc3VwcG9ydCBncmFkaWVudHMgd2l0aCBtdWx0aXBsZSBzdG9wcywgc28gd2UgbmVlZCB0byBzaW11bGF0ZVxuICAgICAgICAvLyAgdGhhdCBmb3IgdGhlIHJhaW5ib3cgc2xpZGVyIHdpdGggOCBkaXZzIHRoYXQgZWFjaCBoYXZlIGEgc2luZ2xlIGdyYWRpZW50XG4gICAgICAgIHZhciBncmFkaWVudEZpeCA9IFwiXCI7XG4gICAgICAgIGlmIChJRSkge1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDE7IGkgPD0gNjsgaSsrKSB7XG4gICAgICAgICAgICAgICAgZ3JhZGllbnRGaXggKz0gXCI8ZGl2IGNsYXNzPSdzcC1cIiArIGkgKyBcIic+PC9kaXY+XCI7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gW1xuICAgICAgICAgICAgXCI8ZGl2IGNsYXNzPSdzcC1jb250YWluZXIgc3AtaGlkZGVuJz5cIixcbiAgICAgICAgICAgICAgICBcIjxkaXYgY2xhc3M9J3NwLXBhbGV0dGUtY29udGFpbmVyJz5cIixcbiAgICAgICAgICAgICAgICAgICAgXCI8ZGl2IGNsYXNzPSdzcC1wYWxldHRlIHNwLXRodW1iIHNwLWNmJz48L2Rpdj5cIixcbiAgICAgICAgICAgICAgICAgICAgXCI8ZGl2IGNsYXNzPSdzcC1wYWxldHRlLWJ1dHRvbi1jb250YWluZXIgc3AtY2YnPlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCI8YnV0dG9uIHR5cGU9J2J1dHRvbicgY2xhc3M9J3NwLXBhbGV0dGUtdG9nZ2xlJz48L2J1dHRvbj5cIixcbiAgICAgICAgICAgICAgICAgICAgXCI8L2Rpdj5cIixcbiAgICAgICAgICAgICAgICBcIjwvZGl2PlwiLFxuICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3AtcGlja2VyLWNvbnRhaW5lcic+XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3AtdG9wIHNwLWNmJz5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3AtZmlsbCc+PC9kaXY+XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcIjxkaXYgY2xhc3M9J3NwLXRvcC1pbm5lcic+XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCI8ZGl2IGNsYXNzPSdzcC1jb2xvcic+XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3Atc2F0Jz5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3AtdmFsJz5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIjxkaXYgY2xhc3M9J3NwLWRyYWdnZXInPjwvZGl2PlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCI8L2Rpdj5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgXCI8L2Rpdj5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIjwvZGl2PlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3AtY2xlYXIgc3AtY2xlYXItZGlzcGxheSc+XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCI8L2Rpdj5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIjxkaXYgY2xhc3M9J3NwLWh1ZSc+XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3Atc2xpZGVyJz48L2Rpdj5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZ3JhZGllbnRGaXgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCI8L2Rpdj5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiPC9kaXY+XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcIjxkaXYgY2xhc3M9J3NwLWFscGhhJz48ZGl2IGNsYXNzPSdzcC1hbHBoYS1pbm5lcic+PGRpdiBjbGFzcz0nc3AtYWxwaGEtaGFuZGxlJz48L2Rpdj48L2Rpdj48L2Rpdj5cIixcbiAgICAgICAgICAgICAgICAgICAgXCI8L2Rpdj5cIixcbiAgICAgICAgICAgICAgICAgICAgXCI8ZGl2IGNsYXNzPSdzcC1pbnB1dC1jb250YWluZXIgc3AtY2YnPlwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgXCI8aW5wdXQgY2xhc3M9J3NwLWlucHV0JyB0eXBlPSd0ZXh0JyBzcGVsbGNoZWNrPSdmYWxzZScgIC8+XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiPC9kaXY+XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3AtaW5pdGlhbCBzcC10aHVtYiBzcC1jZic+PC9kaXY+XCIsXG4gICAgICAgICAgICAgICAgICAgIFwiPGRpdiBjbGFzcz0nc3AtYnV0dG9uLWNvbnRhaW5lciBzcC1jZic+XCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBcIjxhIGNsYXNzPSdzcC1jYW5jZWwnIGhyZWY9JyMnPjwvYT5cIixcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiPGJ1dHRvbiB0eXBlPSdidXR0b24nIGNsYXNzPSdzcC1jaG9vc2UnPjwvYnV0dG9uPlwiLFxuICAgICAgICAgICAgICAgICAgICBcIjwvZGl2PlwiLFxuICAgICAgICAgICAgICAgIFwiPC9kaXY+XCIsXG4gICAgICAgICAgICBcIjwvZGl2PlwiXG4gICAgICAgIF0uam9pbihcIlwiKTtcbiAgICB9KSgpO1xuXG4gICAgZnVuY3Rpb24gcGFsZXR0ZVRlbXBsYXRlIChwLCBjb2xvciwgY2xhc3NOYW1lLCBvcHRzKSB7XG4gICAgICAgIHZhciBodG1sID0gW107XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIGN1cnJlbnQgPSBwW2ldO1xuICAgICAgICAgICAgaWYoY3VycmVudCkge1xuICAgICAgICAgICAgICAgIHZhciB0aW55ID0gdGlueWNvbG9yKGN1cnJlbnQpO1xuICAgICAgICAgICAgICAgIHZhciBjID0gdGlueS50b0hzbCgpLmwgPCAwLjUgPyBcInNwLXRodW1iLWVsIHNwLXRodW1iLWRhcmtcIiA6IFwic3AtdGh1bWItZWwgc3AtdGh1bWItbGlnaHRcIjtcbiAgICAgICAgICAgICAgICBjICs9ICh0aW55Y29sb3IuZXF1YWxzKGNvbG9yLCBjdXJyZW50KSkgPyBcIiBzcC10aHVtYi1hY3RpdmVcIiA6IFwiXCI7XG4gICAgICAgICAgICAgICAgdmFyIGZvcm1hdHRlZFN0cmluZyA9IHRpbnkudG9TdHJpbmcob3B0cy5wcmVmZXJyZWRGb3JtYXQgfHwgXCJyZ2JcIik7XG4gICAgICAgICAgICAgICAgdmFyIHN3YXRjaFN0eWxlID0gcmdiYVN1cHBvcnQgPyAoXCJiYWNrZ3JvdW5kLWNvbG9yOlwiICsgdGlueS50b1JnYlN0cmluZygpKSA6IFwiZmlsdGVyOlwiICsgdGlueS50b0ZpbHRlcigpO1xuICAgICAgICAgICAgICAgIGh0bWwucHVzaCgnPHNwYW4gdGl0bGU9XCInICsgZm9ybWF0dGVkU3RyaW5nICsgJ1wiIGRhdGEtY29sb3I9XCInICsgdGlueS50b1JnYlN0cmluZygpICsgJ1wiIGNsYXNzPVwiJyArIGMgKyAnXCI+PHNwYW4gY2xhc3M9XCJzcC10aHVtYi1pbm5lclwiIHN0eWxlPVwiJyArIHN3YXRjaFN0eWxlICsgJztcIiAvPjwvc3Bhbj4nKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFyIGNscyA9ICdzcC1jbGVhci1kaXNwbGF5JztcbiAgICAgICAgICAgICAgICBodG1sLnB1c2goJCgnPGRpdiAvPicpXG4gICAgICAgICAgICAgICAgICAgIC5hcHBlbmQoJCgnPHNwYW4gZGF0YS1jb2xvcj1cIlwiIHN0eWxlPVwiYmFja2dyb3VuZC1jb2xvcjp0cmFuc3BhcmVudDtcIiBjbGFzcz1cIicgKyBjbHMgKyAnXCI+PC9zcGFuPicpXG4gICAgICAgICAgICAgICAgICAgICAgICAuYXR0cigndGl0bGUnLCBvcHRzLm5vQ29sb3JTZWxlY3RlZFRleHQpXG4gICAgICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICAgICAgLmh0bWwoKVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFwiPGRpdiBjbGFzcz0nc3AtY2YgXCIgKyBjbGFzc05hbWUgKyBcIic+XCIgKyBodG1sLmpvaW4oJycpICsgXCI8L2Rpdj5cIjtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBoaWRlQWxsKCkge1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNwZWN0cnVtcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKHNwZWN0cnVtc1tpXSkge1xuICAgICAgICAgICAgICAgIHNwZWN0cnVtc1tpXS5oaWRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpbnN0YW5jZU9wdGlvbnMobywgY2FsbGJhY2tDb250ZXh0KSB7XG4gICAgICAgIHZhciBvcHRzID0gJC5leHRlbmQoe30sIGRlZmF1bHRPcHRzLCBvKTtcbiAgICAgICAgb3B0cy5jYWxsYmFja3MgPSB7XG4gICAgICAgICAgICAnbW92ZSc6IGJpbmQob3B0cy5tb3ZlLCBjYWxsYmFja0NvbnRleHQpLFxuICAgICAgICAgICAgJ2NoYW5nZSc6IGJpbmQob3B0cy5jaGFuZ2UsIGNhbGxiYWNrQ29udGV4dCksXG4gICAgICAgICAgICAnc2hvdyc6IGJpbmQob3B0cy5zaG93LCBjYWxsYmFja0NvbnRleHQpLFxuICAgICAgICAgICAgJ2hpZGUnOiBiaW5kKG9wdHMuaGlkZSwgY2FsbGJhY2tDb250ZXh0KSxcbiAgICAgICAgICAgICdiZWZvcmVTaG93JzogYmluZChvcHRzLmJlZm9yZVNob3csIGNhbGxiYWNrQ29udGV4dClcbiAgICAgICAgfTtcblxuICAgICAgICByZXR1cm4gb3B0cztcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzcGVjdHJ1bShlbGVtZW50LCBvKSB7XG5cbiAgICAgICAgdmFyIG9wdHMgPSBpbnN0YW5jZU9wdGlvbnMobywgZWxlbWVudCksXG4gICAgICAgICAgICBmbGF0ID0gb3B0cy5mbGF0LFxuICAgICAgICAgICAgc2hvd1NlbGVjdGlvblBhbGV0dGUgPSBvcHRzLnNob3dTZWxlY3Rpb25QYWxldHRlLFxuICAgICAgICAgICAgbG9jYWxTdG9yYWdlS2V5ID0gb3B0cy5sb2NhbFN0b3JhZ2VLZXksXG4gICAgICAgICAgICB0aGVtZSA9IG9wdHMudGhlbWUsXG4gICAgICAgICAgICBjYWxsYmFja3MgPSBvcHRzLmNhbGxiYWNrcyxcbiAgICAgICAgICAgIHJlc2l6ZSA9IHRocm90dGxlKHJlZmxvdywgMTApLFxuICAgICAgICAgICAgdmlzaWJsZSA9IGZhbHNlLFxuICAgICAgICAgICAgaXNEcmFnZ2luZyA9IGZhbHNlLFxuICAgICAgICAgICAgZHJhZ1dpZHRoID0gMCxcbiAgICAgICAgICAgIGRyYWdIZWlnaHQgPSAwLFxuICAgICAgICAgICAgZHJhZ0hlbHBlckhlaWdodCA9IDAsXG4gICAgICAgICAgICBzbGlkZUhlaWdodCA9IDAsXG4gICAgICAgICAgICBzbGlkZVdpZHRoID0gMCxcbiAgICAgICAgICAgIGFscGhhV2lkdGggPSAwLFxuICAgICAgICAgICAgYWxwaGFTbGlkZUhlbHBlcldpZHRoID0gMCxcbiAgICAgICAgICAgIHNsaWRlSGVscGVySGVpZ2h0ID0gMCxcbiAgICAgICAgICAgIGN1cnJlbnRIdWUgPSAwLFxuICAgICAgICAgICAgY3VycmVudFNhdHVyYXRpb24gPSAwLFxuICAgICAgICAgICAgY3VycmVudFZhbHVlID0gMCxcbiAgICAgICAgICAgIGN1cnJlbnRBbHBoYSA9IDEsXG4gICAgICAgICAgICBwYWxldHRlID0gW10sXG4gICAgICAgICAgICBwYWxldHRlQXJyYXkgPSBbXSxcbiAgICAgICAgICAgIHBhbGV0dGVMb29rdXAgPSB7fSxcbiAgICAgICAgICAgIHNlbGVjdGlvblBhbGV0dGUgPSBvcHRzLnNlbGVjdGlvblBhbGV0dGUuc2xpY2UoMCksXG4gICAgICAgICAgICBtYXhTZWxlY3Rpb25TaXplID0gb3B0cy5tYXhTZWxlY3Rpb25TaXplLFxuICAgICAgICAgICAgZHJhZ2dpbmdDbGFzcyA9IFwic3AtZHJhZ2dpbmdcIixcbiAgICAgICAgICAgIHNoaWZ0TW92ZW1lbnREaXJlY3Rpb24gPSBudWxsO1xuXG4gICAgICAgIHZhciBkb2MgPSBlbGVtZW50Lm93bmVyRG9jdW1lbnQsXG4gICAgICAgICAgICBib2R5ID0gZG9jLmJvZHksXG4gICAgICAgICAgICBib3VuZEVsZW1lbnQgPSAkKGVsZW1lbnQpLFxuICAgICAgICAgICAgZGlzYWJsZWQgPSBmYWxzZSxcbiAgICAgICAgICAgIGNvbnRhaW5lciA9ICQobWFya3VwLCBkb2MpLmFkZENsYXNzKHRoZW1lKSxcbiAgICAgICAgICAgIHBpY2tlckNvbnRhaW5lciA9IGNvbnRhaW5lci5maW5kKFwiLnNwLXBpY2tlci1jb250YWluZXJcIiksXG4gICAgICAgICAgICBkcmFnZ2VyID0gY29udGFpbmVyLmZpbmQoXCIuc3AtY29sb3JcIiksXG4gICAgICAgICAgICBkcmFnSGVscGVyID0gY29udGFpbmVyLmZpbmQoXCIuc3AtZHJhZ2dlclwiKSxcbiAgICAgICAgICAgIHNsaWRlciA9IGNvbnRhaW5lci5maW5kKFwiLnNwLWh1ZVwiKSxcbiAgICAgICAgICAgIHNsaWRlSGVscGVyID0gY29udGFpbmVyLmZpbmQoXCIuc3Atc2xpZGVyXCIpLFxuICAgICAgICAgICAgYWxwaGFTbGlkZXJJbm5lciA9IGNvbnRhaW5lci5maW5kKFwiLnNwLWFscGhhLWlubmVyXCIpLFxuICAgICAgICAgICAgYWxwaGFTbGlkZXIgPSBjb250YWluZXIuZmluZChcIi5zcC1hbHBoYVwiKSxcbiAgICAgICAgICAgIGFscGhhU2xpZGVIZWxwZXIgPSBjb250YWluZXIuZmluZChcIi5zcC1hbHBoYS1oYW5kbGVcIiksXG4gICAgICAgICAgICB0ZXh0SW5wdXQgPSBjb250YWluZXIuZmluZChcIi5zcC1pbnB1dFwiKSxcbiAgICAgICAgICAgIHBhbGV0dGVDb250YWluZXIgPSBjb250YWluZXIuZmluZChcIi5zcC1wYWxldHRlXCIpLFxuICAgICAgICAgICAgaW5pdGlhbENvbG9yQ29udGFpbmVyID0gY29udGFpbmVyLmZpbmQoXCIuc3AtaW5pdGlhbFwiKSxcbiAgICAgICAgICAgIGNhbmNlbEJ1dHRvbiA9IGNvbnRhaW5lci5maW5kKFwiLnNwLWNhbmNlbFwiKSxcbiAgICAgICAgICAgIGNsZWFyQnV0dG9uID0gY29udGFpbmVyLmZpbmQoXCIuc3AtY2xlYXJcIiksXG4gICAgICAgICAgICBjaG9vc2VCdXR0b24gPSBjb250YWluZXIuZmluZChcIi5zcC1jaG9vc2VcIiksXG4gICAgICAgICAgICB0b2dnbGVCdXR0b24gPSBjb250YWluZXIuZmluZChcIi5zcC1wYWxldHRlLXRvZ2dsZVwiKSxcbiAgICAgICAgICAgIGlzSW5wdXQgPSBib3VuZEVsZW1lbnQuaXMoXCJpbnB1dFwiKSxcbiAgICAgICAgICAgIGlzSW5wdXRUeXBlQ29sb3IgPSBpc0lucHV0ICYmIGJvdW5kRWxlbWVudC5hdHRyKFwidHlwZVwiKSA9PT0gXCJjb2xvclwiICYmIGlucHV0VHlwZUNvbG9yU3VwcG9ydCgpLFxuICAgICAgICAgICAgc2hvdWxkUmVwbGFjZSA9IGlzSW5wdXQgJiYgIWZsYXQsXG4gICAgICAgICAgICByZXBsYWNlciA9IChzaG91bGRSZXBsYWNlKSA/ICQocmVwbGFjZUlucHV0KS5hZGRDbGFzcyh0aGVtZSkuYWRkQ2xhc3Mob3B0cy5jbGFzc05hbWUpLmFkZENsYXNzKG9wdHMucmVwbGFjZXJDbGFzc05hbWUpIDogJChbXSksXG4gICAgICAgICAgICBvZmZzZXRFbGVtZW50ID0gKHNob3VsZFJlcGxhY2UpID8gcmVwbGFjZXIgOiBib3VuZEVsZW1lbnQsXG4gICAgICAgICAgICBwcmV2aWV3RWxlbWVudCA9IHJlcGxhY2VyLmZpbmQoXCIuc3AtcHJldmlldy1pbm5lclwiKSxcbiAgICAgICAgICAgIGluaXRpYWxDb2xvciA9IG9wdHMuY29sb3IgfHwgKGlzSW5wdXQgJiYgYm91bmRFbGVtZW50LnZhbCgpKSxcbiAgICAgICAgICAgIGNvbG9yT25TaG93ID0gZmFsc2UsXG4gICAgICAgICAgICBjdXJyZW50UHJlZmVycmVkRm9ybWF0ID0gb3B0cy5wcmVmZXJyZWRGb3JtYXQsXG4gICAgICAgICAgICBjbGlja291dEZpcmVzQ2hhbmdlID0gIW9wdHMuc2hvd0J1dHRvbnMgfHwgb3B0cy5jbGlja291dEZpcmVzQ2hhbmdlLFxuICAgICAgICAgICAgaXNFbXB0eSA9ICFpbml0aWFsQ29sb3IsXG4gICAgICAgICAgICBhbGxvd0VtcHR5ID0gb3B0cy5hbGxvd0VtcHR5ICYmICFpc0lucHV0VHlwZUNvbG9yO1xuXG4gICAgICAgIGZ1bmN0aW9uIGFwcGx5T3B0aW9ucygpIHtcblxuICAgICAgICAgICAgaWYgKG9wdHMuc2hvd1BhbGV0dGVPbmx5KSB7XG4gICAgICAgICAgICAgICAgb3B0cy5zaG93UGFsZXR0ZSA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRvZ2dsZUJ1dHRvbi50ZXh0KG9wdHMuc2hvd1BhbGV0dGVPbmx5ID8gb3B0cy50b2dnbGVQYWxldHRlTW9yZVRleHQgOiBvcHRzLnRvZ2dsZVBhbGV0dGVMZXNzVGV4dCk7XG5cbiAgICAgICAgICAgIGlmIChvcHRzLnBhbGV0dGUpIHtcbiAgICAgICAgICAgICAgICBwYWxldHRlID0gb3B0cy5wYWxldHRlLnNsaWNlKDApO1xuICAgICAgICAgICAgICAgIHBhbGV0dGVBcnJheSA9ICQuaXNBcnJheShwYWxldHRlWzBdKSA/IHBhbGV0dGUgOiBbcGFsZXR0ZV07XG4gICAgICAgICAgICAgICAgcGFsZXR0ZUxvb2t1cCA9IHt9O1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcGFsZXR0ZUFycmF5Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgcGFsZXR0ZUFycmF5W2ldLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmdiID0gdGlueWNvbG9yKHBhbGV0dGVBcnJheVtpXVtqXSkudG9SZ2JTdHJpbmcoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhbGV0dGVMb29rdXBbcmdiXSA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNvbnRhaW5lci50b2dnbGVDbGFzcyhcInNwLWZsYXRcIiwgZmxhdCk7XG4gICAgICAgICAgICBjb250YWluZXIudG9nZ2xlQ2xhc3MoXCJzcC1pbnB1dC1kaXNhYmxlZFwiLCAhb3B0cy5zaG93SW5wdXQpO1xuICAgICAgICAgICAgY29udGFpbmVyLnRvZ2dsZUNsYXNzKFwic3AtYWxwaGEtZW5hYmxlZFwiLCBvcHRzLnNob3dBbHBoYSk7XG4gICAgICAgICAgICBjb250YWluZXIudG9nZ2xlQ2xhc3MoXCJzcC1jbGVhci1lbmFibGVkXCIsIGFsbG93RW1wdHkpO1xuICAgICAgICAgICAgY29udGFpbmVyLnRvZ2dsZUNsYXNzKFwic3AtYnV0dG9ucy1kaXNhYmxlZFwiLCAhb3B0cy5zaG93QnV0dG9ucyk7XG4gICAgICAgICAgICBjb250YWluZXIudG9nZ2xlQ2xhc3MoXCJzcC1wYWxldHRlLWJ1dHRvbnMtZGlzYWJsZWRcIiwgIW9wdHMudG9nZ2xlUGFsZXR0ZU9ubHkpO1xuICAgICAgICAgICAgY29udGFpbmVyLnRvZ2dsZUNsYXNzKFwic3AtcGFsZXR0ZS1kaXNhYmxlZFwiLCAhb3B0cy5zaG93UGFsZXR0ZSk7XG4gICAgICAgICAgICBjb250YWluZXIudG9nZ2xlQ2xhc3MoXCJzcC1wYWxldHRlLW9ubHlcIiwgb3B0cy5zaG93UGFsZXR0ZU9ubHkpO1xuICAgICAgICAgICAgY29udGFpbmVyLnRvZ2dsZUNsYXNzKFwic3AtaW5pdGlhbC1kaXNhYmxlZFwiLCAhb3B0cy5zaG93SW5pdGlhbCk7XG4gICAgICAgICAgICBjb250YWluZXIuYWRkQ2xhc3Mob3B0cy5jbGFzc05hbWUpLmFkZENsYXNzKG9wdHMuY29udGFpbmVyQ2xhc3NOYW1lKTtcblxuICAgICAgICAgICAgcmVmbG93KCk7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBpbml0aWFsaXplKCkge1xuXG4gICAgICAgICAgICBpZiAoSUUpIHtcbiAgICAgICAgICAgICAgICBjb250YWluZXIuZmluZChcIio6bm90KGlucHV0KVwiKS5hdHRyKFwidW5zZWxlY3RhYmxlXCIsIFwib25cIik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGFwcGx5T3B0aW9ucygpO1xuXG4gICAgICAgICAgICBpZiAoc2hvdWxkUmVwbGFjZSkge1xuICAgICAgICAgICAgICAgIGJvdW5kRWxlbWVudC5hZnRlcihyZXBsYWNlcikuaGlkZSgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoIWFsbG93RW1wdHkpIHtcbiAgICAgICAgICAgICAgICBjbGVhckJ1dHRvbi5oaWRlKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChmbGF0KSB7XG4gICAgICAgICAgICAgICAgYm91bmRFbGVtZW50LmFmdGVyKGNvbnRhaW5lcikuaGlkZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG5cbiAgICAgICAgICAgICAgICB2YXIgYXBwZW5kVG8gPSBvcHRzLmFwcGVuZFRvID09PSBcInBhcmVudFwiID8gYm91bmRFbGVtZW50LnBhcmVudCgpIDogJChvcHRzLmFwcGVuZFRvKTtcbiAgICAgICAgICAgICAgICBpZiAoYXBwZW5kVG8ubGVuZ3RoICE9PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGFwcGVuZFRvID0gJChcImJvZHlcIik7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgYXBwZW5kVG8uYXBwZW5kKGNvbnRhaW5lcik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHVwZGF0ZVNlbGVjdGlvblBhbGV0dGVGcm9tU3RvcmFnZSgpO1xuXG4gICAgICAgICAgICBvZmZzZXRFbGVtZW50LmJpbmQoXCJjbGljay5zcGVjdHJ1bSB0b3VjaHN0YXJ0LnNwZWN0cnVtXCIsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFkaXNhYmxlZCkge1xuICAgICAgICAgICAgICAgICAgICB0b2dnbGUoKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuXG4gICAgICAgICAgICAgICAgaWYgKCEkKGUudGFyZ2V0KS5pcyhcImlucHV0XCIpKSB7XG4gICAgICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYoYm91bmRFbGVtZW50LmlzKFwiOmRpc2FibGVkXCIpIHx8IChvcHRzLmRpc2FibGVkID09PSB0cnVlKSkge1xuICAgICAgICAgICAgICAgIGRpc2FibGUoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gUHJldmVudCBjbGlja3MgZnJvbSBidWJibGluZyB1cCB0byBkb2N1bWVudC4gIFRoaXMgd291bGQgY2F1c2UgaXQgdG8gYmUgaGlkZGVuLlxuICAgICAgICAgICAgY29udGFpbmVyLmNsaWNrKHN0b3BQcm9wYWdhdGlvbik7XG5cbiAgICAgICAgICAgIC8vIEhhbmRsZSB1c2VyIHR5cGVkIGlucHV0XG4gICAgICAgICAgICB0ZXh0SW5wdXQuY2hhbmdlKHNldEZyb21UZXh0SW5wdXQpO1xuICAgICAgICAgICAgdGV4dElucHV0LmJpbmQoXCJwYXN0ZVwiLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgc2V0VGltZW91dChzZXRGcm9tVGV4dElucHV0LCAxKTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgdGV4dElucHV0LmtleWRvd24oZnVuY3Rpb24gKGUpIHsgaWYgKGUua2V5Q29kZSA9PSAxMykgeyBzZXRGcm9tVGV4dElucHV0KCk7IH0gfSk7XG5cbiAgICAgICAgICAgIGNhbmNlbEJ1dHRvbi50ZXh0KG9wdHMuY2FuY2VsVGV4dCk7XG4gICAgICAgICAgICBjYW5jZWxCdXR0b24uYmluZChcImNsaWNrLnNwZWN0cnVtXCIsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgcmV2ZXJ0KCk7XG4gICAgICAgICAgICAgICAgaGlkZSgpO1xuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNsZWFyQnV0dG9uLmF0dHIoXCJ0aXRsZVwiLCBvcHRzLmNsZWFyVGV4dCk7XG4gICAgICAgICAgICBjbGVhckJ1dHRvbi5iaW5kKFwiY2xpY2suc3BlY3RydW1cIiwgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICBpc0VtcHR5ID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBtb3ZlKCk7XG5cbiAgICAgICAgICAgICAgICBpZihmbGF0KSB7XG4gICAgICAgICAgICAgICAgICAgIC8vZm9yIHRoZSBmbGF0IHN0eWxlLCB0aGlzIGlzIGEgY2hhbmdlIGV2ZW50XG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZU9yaWdpbmFsSW5wdXQodHJ1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGNob29zZUJ1dHRvbi50ZXh0KG9wdHMuY2hvb3NlVGV4dCk7XG4gICAgICAgICAgICBjaG9vc2VCdXR0b24uYmluZChcImNsaWNrLnNwZWN0cnVtXCIsIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgZS5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG5cbiAgICAgICAgICAgICAgICBpZiAoSUUgJiYgdGV4dElucHV0LmlzKFwiOmZvY3VzXCIpKSB7XG4gICAgICAgICAgICAgICAgICAgIHRleHRJbnB1dC50cmlnZ2VyKCdjaGFuZ2UnKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAoaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHVwZGF0ZU9yaWdpbmFsSW5wdXQodHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIGhpZGUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdG9nZ2xlQnV0dG9uLnRleHQob3B0cy5zaG93UGFsZXR0ZU9ubHkgPyBvcHRzLnRvZ2dsZVBhbGV0dGVNb3JlVGV4dCA6IG9wdHMudG9nZ2xlUGFsZXR0ZUxlc3NUZXh0KTtcbiAgICAgICAgICAgIHRvZ2dsZUJ1dHRvbi5iaW5kKFwiY2xpY2suc3BlY3RydW1cIiwgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICAgICAgICAgIG9wdHMuc2hvd1BhbGV0dGVPbmx5ID0gIW9wdHMuc2hvd1BhbGV0dGVPbmx5O1xuXG4gICAgICAgICAgICAgICAgLy8gVG8gbWFrZSBzdXJlIHRoZSBQaWNrZXIgYXJlYSBpcyBkcmF3biBvbiB0aGUgcmlnaHQsIG5leHQgdG8gdGhlXG4gICAgICAgICAgICAgICAgLy8gUGFsZXR0ZSBhcmVhIChhbmQgbm90IGJlbG93IHRoZSBwYWxldHRlKSwgZmlyc3QgbW92ZSB0aGUgUGFsZXR0ZVxuICAgICAgICAgICAgICAgIC8vIHRvIHRoZSBsZWZ0IHRvIG1ha2Ugc3BhY2UgZm9yIHRoZSBwaWNrZXIsIHBsdXMgNXB4IGV4dHJhLlxuICAgICAgICAgICAgICAgIC8vIFRoZSAnYXBwbHlPcHRpb25zJyBmdW5jdGlvbiBwdXRzIHRoZSB3aG9sZSBjb250YWluZXIgYmFjayBpbnRvIHBsYWNlXG4gICAgICAgICAgICAgICAgLy8gYW5kIHRha2VzIGNhcmUgb2YgdGhlIGJ1dHRvbi10ZXh0IGFuZCB0aGUgc3AtcGFsZXR0ZS1vbmx5IENTUyBjbGFzcy5cbiAgICAgICAgICAgICAgICBpZiAoIW9wdHMuc2hvd1BhbGV0dGVPbmx5ICYmICFmbGF0KSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lci5jc3MoJ2xlZnQnLCAnLT0nICsgKHBpY2tlckNvbnRhaW5lci5vdXRlcldpZHRoKHRydWUpICsgNSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBhcHBseU9wdGlvbnMoKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICBkcmFnZ2FibGUoYWxwaGFTbGlkZXIsIGZ1bmN0aW9uIChkcmFnWCwgZHJhZ1ksIGUpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50QWxwaGEgPSAoZHJhZ1ggLyBhbHBoYVdpZHRoKTtcbiAgICAgICAgICAgICAgICBpc0VtcHR5ID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgaWYgKGUuc2hpZnRLZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudEFscGhhID0gTWF0aC5yb3VuZChjdXJyZW50QWxwaGEgKiAxMCkgLyAxMDtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBtb3ZlKCk7XG4gICAgICAgICAgICB9LCBkcmFnU3RhcnQsIGRyYWdTdG9wKTtcblxuICAgICAgICAgICAgZHJhZ2dhYmxlKHNsaWRlciwgZnVuY3Rpb24gKGRyYWdYLCBkcmFnWSkge1xuICAgICAgICAgICAgICAgIGN1cnJlbnRIdWUgPSBwYXJzZUZsb2F0KGRyYWdZIC8gc2xpZGVIZWlnaHQpO1xuICAgICAgICAgICAgICAgIGlzRW1wdHkgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBpZiAoIW9wdHMuc2hvd0FscGhhKSB7XG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRBbHBoYSA9IDE7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIG1vdmUoKTtcbiAgICAgICAgICAgIH0sIGRyYWdTdGFydCwgZHJhZ1N0b3ApO1xuXG4gICAgICAgICAgICBkcmFnZ2FibGUoZHJhZ2dlciwgZnVuY3Rpb24gKGRyYWdYLCBkcmFnWSwgZSkge1xuXG4gICAgICAgICAgICAgICAgLy8gc2hpZnQrZHJhZyBzaG91bGQgc25hcCB0aGUgbW92ZW1lbnQgdG8gZWl0aGVyIHRoZSB4IG9yIHkgYXhpcy5cbiAgICAgICAgICAgICAgICBpZiAoIWUuc2hpZnRLZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgc2hpZnRNb3ZlbWVudERpcmVjdGlvbiA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKCFzaGlmdE1vdmVtZW50RGlyZWN0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGREcmFnWCA9IGN1cnJlbnRTYXR1cmF0aW9uICogZHJhZ1dpZHRoO1xuICAgICAgICAgICAgICAgICAgICB2YXIgb2xkRHJhZ1kgPSBkcmFnSGVpZ2h0IC0gKGN1cnJlbnRWYWx1ZSAqIGRyYWdIZWlnaHQpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZnVydGhlckZyb21YID0gTWF0aC5hYnMoZHJhZ1ggLSBvbGREcmFnWCkgPiBNYXRoLmFicyhkcmFnWSAtIG9sZERyYWdZKTtcblxuICAgICAgICAgICAgICAgICAgICBzaGlmdE1vdmVtZW50RGlyZWN0aW9uID0gZnVydGhlckZyb21YID8gXCJ4XCIgOiBcInlcIjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgc2V0U2F0dXJhdGlvbiA9ICFzaGlmdE1vdmVtZW50RGlyZWN0aW9uIHx8IHNoaWZ0TW92ZW1lbnREaXJlY3Rpb24gPT09IFwieFwiO1xuICAgICAgICAgICAgICAgIHZhciBzZXRWYWx1ZSA9ICFzaGlmdE1vdmVtZW50RGlyZWN0aW9uIHx8IHNoaWZ0TW92ZW1lbnREaXJlY3Rpb24gPT09IFwieVwiO1xuXG4gICAgICAgICAgICAgICAgaWYgKHNldFNhdHVyYXRpb24pIHtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudFNhdHVyYXRpb24gPSBwYXJzZUZsb2F0KGRyYWdYIC8gZHJhZ1dpZHRoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKHNldFZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnRWYWx1ZSA9IHBhcnNlRmxvYXQoKGRyYWdIZWlnaHQgLSBkcmFnWSkgLyBkcmFnSGVpZ2h0KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpc0VtcHR5ID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgaWYgKCFvcHRzLnNob3dBbHBoYSkge1xuICAgICAgICAgICAgICAgICAgICBjdXJyZW50QWxwaGEgPSAxO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG1vdmUoKTtcblxuICAgICAgICAgICAgfSwgZHJhZ1N0YXJ0LCBkcmFnU3RvcCk7XG5cbiAgICAgICAgICAgIGlmICghIWluaXRpYWxDb2xvcikge1xuICAgICAgICAgICAgICAgIHNldChpbml0aWFsQ29sb3IpO1xuXG4gICAgICAgICAgICAgICAgLy8gSW4gY2FzZSBjb2xvciB3YXMgYmxhY2sgLSB1cGRhdGUgdGhlIHByZXZpZXcgVUkgYW5kIHNldCB0aGUgZm9ybWF0XG4gICAgICAgICAgICAgICAgLy8gc2luY2UgdGhlIHNldCBmdW5jdGlvbiB3aWxsIG5vdCBydW4gKGRlZmF1bHQgY29sb3IgaXMgYmxhY2spLlxuICAgICAgICAgICAgICAgIHVwZGF0ZVVJKCk7XG4gICAgICAgICAgICAgICAgY3VycmVudFByZWZlcnJlZEZvcm1hdCA9IG9wdHMucHJlZmVycmVkRm9ybWF0IHx8IHRpbnljb2xvcihpbml0aWFsQ29sb3IpLmZvcm1hdDtcblxuICAgICAgICAgICAgICAgIGFkZENvbG9yVG9TZWxlY3Rpb25QYWxldHRlKGluaXRpYWxDb2xvcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB1cGRhdGVVSSgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoZmxhdCkge1xuICAgICAgICAgICAgICAgIHNob3coKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZnVuY3Rpb24gcGFsZXR0ZUVsZW1lbnRDbGljayhlKSB7XG4gICAgICAgICAgICAgICAgaWYgKGUuZGF0YSAmJiBlLmRhdGEuaWdub3JlKSB7XG4gICAgICAgICAgICAgICAgICAgIHNldCgkKGUudGFyZ2V0KS5jbG9zZXN0KFwiLnNwLXRodW1iLWVsXCIpLmRhdGEoXCJjb2xvclwiKSk7XG4gICAgICAgICAgICAgICAgICAgIG1vdmUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHNldCgkKGUudGFyZ2V0KS5jbG9zZXN0KFwiLnNwLXRodW1iLWVsXCIpLmRhdGEoXCJjb2xvclwiKSk7XG4gICAgICAgICAgICAgICAgICAgIG1vdmUoKTtcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlT3JpZ2luYWxJbnB1dCh0cnVlKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdHMuaGlkZUFmdGVyUGFsZXR0ZVNlbGVjdCkge1xuICAgICAgICAgICAgICAgICAgICAgIGhpZGUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHBhbGV0dGVFdmVudCA9IElFID8gXCJtb3VzZWRvd24uc3BlY3RydW1cIiA6IFwiY2xpY2suc3BlY3RydW0gdG91Y2hzdGFydC5zcGVjdHJ1bVwiO1xuICAgICAgICAgICAgcGFsZXR0ZUNvbnRhaW5lci5kZWxlZ2F0ZShcIi5zcC10aHVtYi1lbFwiLCBwYWxldHRlRXZlbnQsIHBhbGV0dGVFbGVtZW50Q2xpY2spO1xuICAgICAgICAgICAgaW5pdGlhbENvbG9yQ29udGFpbmVyLmRlbGVnYXRlKFwiLnNwLXRodW1iLWVsOm50aC1jaGlsZCgxKVwiLCBwYWxldHRlRXZlbnQsIHsgaWdub3JlOiB0cnVlIH0sIHBhbGV0dGVFbGVtZW50Q2xpY2spO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gdXBkYXRlU2VsZWN0aW9uUGFsZXR0ZUZyb21TdG9yYWdlKCkge1xuXG4gICAgICAgICAgICBpZiAobG9jYWxTdG9yYWdlS2V5ICYmIHdpbmRvdy5sb2NhbFN0b3JhZ2UpIHtcblxuICAgICAgICAgICAgICAgIC8vIE1pZ3JhdGUgb2xkIHBhbGV0dGVzIG92ZXIgdG8gbmV3IGZvcm1hdC4gIE1heSB3YW50IHRvIHJlbW92ZSB0aGlzIGV2ZW50dWFsbHkuXG4gICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG9sZFBhbGV0dGUgPSB3aW5kb3cubG9jYWxTdG9yYWdlW2xvY2FsU3RvcmFnZUtleV0uc3BsaXQoXCIsI1wiKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG9sZFBhbGV0dGUubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHdpbmRvdy5sb2NhbFN0b3JhZ2VbbG9jYWxTdG9yYWdlS2V5XTtcbiAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChvbGRQYWxldHRlLCBmdW5jdGlvbihpLCBjKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFkZENvbG9yVG9TZWxlY3Rpb25QYWxldHRlKGMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2F0Y2goZSkgeyB9XG5cbiAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICBzZWxlY3Rpb25QYWxldHRlID0gd2luZG93LmxvY2FsU3RvcmFnZVtsb2NhbFN0b3JhZ2VLZXldLnNwbGl0KFwiO1wiKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgY2F0Y2ggKGUpIHsgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gYWRkQ29sb3JUb1NlbGVjdGlvblBhbGV0dGUoY29sb3IpIHtcbiAgICAgICAgICAgIGlmIChzaG93U2VsZWN0aW9uUGFsZXR0ZSkge1xuICAgICAgICAgICAgICAgIHZhciByZ2IgPSB0aW55Y29sb3IoY29sb3IpLnRvUmdiU3RyaW5nKCk7XG4gICAgICAgICAgICAgICAgaWYgKCFwYWxldHRlTG9va3VwW3JnYl0gJiYgJC5pbkFycmF5KHJnYiwgc2VsZWN0aW9uUGFsZXR0ZSkgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlbGVjdGlvblBhbGV0dGUucHVzaChyZ2IpO1xuICAgICAgICAgICAgICAgICAgICB3aGlsZShzZWxlY3Rpb25QYWxldHRlLmxlbmd0aCA+IG1heFNlbGVjdGlvblNpemUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdGlvblBhbGV0dGUuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmIChsb2NhbFN0b3JhZ2VLZXkgJiYgd2luZG93LmxvY2FsU3RvcmFnZSkge1xuICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZVtsb2NhbFN0b3JhZ2VLZXldID0gc2VsZWN0aW9uUGFsZXR0ZS5qb2luKFwiO1wiKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjYXRjaChlKSB7IH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBnZXRVbmlxdWVTZWxlY3Rpb25QYWxldHRlKCkge1xuICAgICAgICAgICAgdmFyIHVuaXF1ZSA9IFtdO1xuICAgICAgICAgICAgaWYgKG9wdHMuc2hvd1BhbGV0dGUpIHtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGVjdGlvblBhbGV0dGUubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHJnYiA9IHRpbnljb2xvcihzZWxlY3Rpb25QYWxldHRlW2ldKS50b1JnYlN0cmluZygpO1xuXG4gICAgICAgICAgICAgICAgICAgIGlmICghcGFsZXR0ZUxvb2t1cFtyZ2JdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB1bmlxdWUucHVzaChzZWxlY3Rpb25QYWxldHRlW2ldKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIHVuaXF1ZS5yZXZlcnNlKCkuc2xpY2UoMCwgb3B0cy5tYXhTZWxlY3Rpb25TaXplKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGRyYXdQYWxldHRlKCkge1xuXG4gICAgICAgICAgICB2YXIgY3VycmVudENvbG9yID0gZ2V0KCk7XG5cbiAgICAgICAgICAgIHZhciBodG1sID0gJC5tYXAocGFsZXR0ZUFycmF5LCBmdW5jdGlvbiAocGFsZXR0ZSwgaSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBwYWxldHRlVGVtcGxhdGUocGFsZXR0ZSwgY3VycmVudENvbG9yLCBcInNwLXBhbGV0dGUtcm93IHNwLXBhbGV0dGUtcm93LVwiICsgaSwgb3B0cyk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdXBkYXRlU2VsZWN0aW9uUGFsZXR0ZUZyb21TdG9yYWdlKCk7XG5cbiAgICAgICAgICAgIGlmIChzZWxlY3Rpb25QYWxldHRlKSB7XG4gICAgICAgICAgICAgICAgaHRtbC5wdXNoKHBhbGV0dGVUZW1wbGF0ZShnZXRVbmlxdWVTZWxlY3Rpb25QYWxldHRlKCksIGN1cnJlbnRDb2xvciwgXCJzcC1wYWxldHRlLXJvdyBzcC1wYWxldHRlLXJvdy1zZWxlY3Rpb25cIiwgb3B0cykpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBwYWxldHRlQ29udGFpbmVyLmh0bWwoaHRtbC5qb2luKFwiXCIpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGRyYXdJbml0aWFsKCkge1xuICAgICAgICAgICAgaWYgKG9wdHMuc2hvd0luaXRpYWwpIHtcbiAgICAgICAgICAgICAgICB2YXIgaW5pdGlhbCA9IGNvbG9yT25TaG93O1xuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50ID0gZ2V0KCk7XG4gICAgICAgICAgICAgICAgaW5pdGlhbENvbG9yQ29udGFpbmVyLmh0bWwocGFsZXR0ZVRlbXBsYXRlKFtpbml0aWFsLCBjdXJyZW50XSwgY3VycmVudCwgXCJzcC1wYWxldHRlLXJvdy1pbml0aWFsXCIsIG9wdHMpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGRyYWdTdGFydCgpIHtcbiAgICAgICAgICAgIGlmIChkcmFnSGVpZ2h0IDw9IDAgfHwgZHJhZ1dpZHRoIDw9IDAgfHwgc2xpZGVIZWlnaHQgPD0gMCkge1xuICAgICAgICAgICAgICAgIHJlZmxvdygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaXNEcmFnZ2luZyA9IHRydWU7XG4gICAgICAgICAgICBjb250YWluZXIuYWRkQ2xhc3MoZHJhZ2dpbmdDbGFzcyk7XG4gICAgICAgICAgICBzaGlmdE1vdmVtZW50RGlyZWN0aW9uID0gbnVsbDtcbiAgICAgICAgICAgIGJvdW5kRWxlbWVudC50cmlnZ2VyKCdkcmFnc3RhcnQuc3BlY3RydW0nLCBbIGdldCgpIF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gZHJhZ1N0b3AoKSB7XG4gICAgICAgICAgICBpc0RyYWdnaW5nID0gZmFsc2U7XG4gICAgICAgICAgICBjb250YWluZXIucmVtb3ZlQ2xhc3MoZHJhZ2dpbmdDbGFzcyk7XG4gICAgICAgICAgICBib3VuZEVsZW1lbnQudHJpZ2dlcignZHJhZ3N0b3Auc3BlY3RydW0nLCBbIGdldCgpIF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gc2V0RnJvbVRleHRJbnB1dCgpIHtcblxuICAgICAgICAgICAgdmFyIHZhbHVlID0gdGV4dElucHV0LnZhbCgpO1xuXG4gICAgICAgICAgICBpZiAoKHZhbHVlID09PSBudWxsIHx8IHZhbHVlID09PSBcIlwiKSAmJiBhbGxvd0VtcHR5KSB7XG4gICAgICAgICAgICAgICAgc2V0KG51bGwpO1xuICAgICAgICAgICAgICAgIHVwZGF0ZU9yaWdpbmFsSW5wdXQodHJ1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgdGlueSA9IHRpbnljb2xvcih2YWx1ZSk7XG4gICAgICAgICAgICAgICAgaWYgKHRpbnkuaXNWYWxpZCgpKSB7XG4gICAgICAgICAgICAgICAgICAgIHNldCh0aW55KTtcbiAgICAgICAgICAgICAgICAgICAgdXBkYXRlT3JpZ2luYWxJbnB1dCh0cnVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRleHRJbnB1dC5hZGRDbGFzcyhcInNwLXZhbGlkYXRpb24tZXJyb3JcIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gdG9nZ2xlKCkge1xuICAgICAgICAgICAgaWYgKHZpc2libGUpIHtcbiAgICAgICAgICAgICAgICBoaWRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBzaG93KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBzaG93KCkge1xuICAgICAgICAgICAgdmFyIGV2ZW50ID0gJC5FdmVudCgnYmVmb3JlU2hvdy5zcGVjdHJ1bScpO1xuXG4gICAgICAgICAgICBpZiAodmlzaWJsZSkge1xuICAgICAgICAgICAgICAgIHJlZmxvdygpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgYm91bmRFbGVtZW50LnRyaWdnZXIoZXZlbnQsIFsgZ2V0KCkgXSk7XG5cbiAgICAgICAgICAgIGlmIChjYWxsYmFja3MuYmVmb3JlU2hvdyhnZXQoKSkgPT09IGZhbHNlIHx8IGV2ZW50LmlzRGVmYXVsdFByZXZlbnRlZCgpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBoaWRlQWxsKCk7XG4gICAgICAgICAgICB2aXNpYmxlID0gdHJ1ZTtcblxuICAgICAgICAgICAgJChkb2MpLmJpbmQoXCJrZXlkb3duLnNwZWN0cnVtXCIsIG9ua2V5ZG93bik7XG4gICAgICAgICAgICAkKGRvYykuYmluZChcImNsaWNrLnNwZWN0cnVtXCIsIGNsaWNrb3V0KTtcbiAgICAgICAgICAgICQod2luZG93KS5iaW5kKFwicmVzaXplLnNwZWN0cnVtXCIsIHJlc2l6ZSk7XG4gICAgICAgICAgICByZXBsYWNlci5hZGRDbGFzcyhcInNwLWFjdGl2ZVwiKTtcbiAgICAgICAgICAgIGNvbnRhaW5lci5yZW1vdmVDbGFzcyhcInNwLWhpZGRlblwiKTtcblxuICAgICAgICAgICAgcmVmbG93KCk7XG4gICAgICAgICAgICB1cGRhdGVVSSgpO1xuXG4gICAgICAgICAgICBjb2xvck9uU2hvdyA9IGdldCgpO1xuXG4gICAgICAgICAgICBkcmF3SW5pdGlhbCgpO1xuICAgICAgICAgICAgY2FsbGJhY2tzLnNob3coY29sb3JPblNob3cpO1xuICAgICAgICAgICAgYm91bmRFbGVtZW50LnRyaWdnZXIoJ3Nob3cuc3BlY3RydW0nLCBbIGNvbG9yT25TaG93IF0pO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gb25rZXlkb3duKGUpIHtcbiAgICAgICAgICAgIC8vIENsb3NlIG9uIEVTQ1xuICAgICAgICAgICAgaWYgKGUua2V5Q29kZSA9PT0gMjcpIHtcbiAgICAgICAgICAgICAgICBoaWRlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBjbGlja291dChlKSB7XG4gICAgICAgICAgICAvLyBSZXR1cm4gb24gcmlnaHQgY2xpY2suXG4gICAgICAgICAgICBpZiAoZS5idXR0b24gPT0gMikgeyByZXR1cm47IH1cblxuICAgICAgICAgICAgLy8gSWYgYSBkcmFnIGV2ZW50IHdhcyBoYXBwZW5pbmcgZHVyaW5nIHRoZSBtb3VzZXVwLCBkb24ndCBoaWRlXG4gICAgICAgICAgICAvLyBvbiBjbGljay5cbiAgICAgICAgICAgIGlmIChpc0RyYWdnaW5nKSB7IHJldHVybjsgfVxuXG4gICAgICAgICAgICBpZiAoY2xpY2tvdXRGaXJlc0NoYW5nZSkge1xuICAgICAgICAgICAgICAgIHVwZGF0ZU9yaWdpbmFsSW5wdXQodHJ1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXZlcnQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGhpZGUoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGhpZGUoKSB7XG4gICAgICAgICAgICAvLyBSZXR1cm4gaWYgaGlkaW5nIGlzIHVubmVjZXNzYXJ5XG4gICAgICAgICAgICBpZiAoIXZpc2libGUgfHwgZmxhdCkgeyByZXR1cm47IH1cbiAgICAgICAgICAgIHZpc2libGUgPSBmYWxzZTtcblxuICAgICAgICAgICAgJChkb2MpLnVuYmluZChcImtleWRvd24uc3BlY3RydW1cIiwgb25rZXlkb3duKTtcbiAgICAgICAgICAgICQoZG9jKS51bmJpbmQoXCJjbGljay5zcGVjdHJ1bVwiLCBjbGlja291dCk7XG4gICAgICAgICAgICAkKHdpbmRvdykudW5iaW5kKFwicmVzaXplLnNwZWN0cnVtXCIsIHJlc2l6ZSk7XG5cbiAgICAgICAgICAgIHJlcGxhY2VyLnJlbW92ZUNsYXNzKFwic3AtYWN0aXZlXCIpO1xuICAgICAgICAgICAgY29udGFpbmVyLmFkZENsYXNzKFwic3AtaGlkZGVuXCIpO1xuXG4gICAgICAgICAgICBjYWxsYmFja3MuaGlkZShnZXQoKSk7XG4gICAgICAgICAgICBib3VuZEVsZW1lbnQudHJpZ2dlcignaGlkZS5zcGVjdHJ1bScsIFsgZ2V0KCkgXSk7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiByZXZlcnQoKSB7XG4gICAgICAgICAgICBzZXQoY29sb3JPblNob3csIHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gc2V0KGNvbG9yLCBpZ25vcmVGb3JtYXRDaGFuZ2UpIHtcbiAgICAgICAgICAgIGlmICh0aW55Y29sb3IuZXF1YWxzKGNvbG9yLCBnZXQoKSkpIHtcbiAgICAgICAgICAgICAgICAvLyBVcGRhdGUgVUkganVzdCBpbiBjYXNlIGEgdmFsaWRhdGlvbiBlcnJvciBuZWVkc1xuICAgICAgICAgICAgICAgIC8vIHRvIGJlIGNsZWFyZWQuXG4gICAgICAgICAgICAgICAgdXBkYXRlVUkoKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBuZXdDb2xvciwgbmV3SHN2O1xuICAgICAgICAgICAgaWYgKCFjb2xvciAmJiBhbGxvd0VtcHR5KSB7XG4gICAgICAgICAgICAgICAgaXNFbXB0eSA9IHRydWU7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlzRW1wdHkgPSBmYWxzZTtcbiAgICAgICAgICAgICAgICBuZXdDb2xvciA9IHRpbnljb2xvcihjb2xvcik7XG4gICAgICAgICAgICAgICAgbmV3SHN2ID0gbmV3Q29sb3IudG9Ic3YoKTtcblxuICAgICAgICAgICAgICAgIGN1cnJlbnRIdWUgPSAobmV3SHN2LmggJSAzNjApIC8gMzYwO1xuICAgICAgICAgICAgICAgIGN1cnJlbnRTYXR1cmF0aW9uID0gbmV3SHN2LnM7XG4gICAgICAgICAgICAgICAgY3VycmVudFZhbHVlID0gbmV3SHN2LnY7XG4gICAgICAgICAgICAgICAgY3VycmVudEFscGhhID0gbmV3SHN2LmE7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB1cGRhdGVVSSgpO1xuXG4gICAgICAgICAgICBpZiAobmV3Q29sb3IgJiYgbmV3Q29sb3IuaXNWYWxpZCgpICYmICFpZ25vcmVGb3JtYXRDaGFuZ2UpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50UHJlZmVycmVkRm9ybWF0ID0gb3B0cy5wcmVmZXJyZWRGb3JtYXQgfHwgbmV3Q29sb3IuZ2V0Rm9ybWF0KCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBnZXQob3B0cykge1xuICAgICAgICAgICAgb3B0cyA9IG9wdHMgfHwgeyB9O1xuXG4gICAgICAgICAgICBpZiAoYWxsb3dFbXB0eSAmJiBpc0VtcHR5KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHJldHVybiB0aW55Y29sb3IuZnJvbVJhdGlvKHtcbiAgICAgICAgICAgICAgICBoOiBjdXJyZW50SHVlLFxuICAgICAgICAgICAgICAgIHM6IGN1cnJlbnRTYXR1cmF0aW9uLFxuICAgICAgICAgICAgICAgIHY6IGN1cnJlbnRWYWx1ZSxcbiAgICAgICAgICAgICAgICBhOiBNYXRoLnJvdW5kKGN1cnJlbnRBbHBoYSAqIDEwMCkgLyAxMDBcbiAgICAgICAgICAgIH0sIHsgZm9ybWF0OiBvcHRzLmZvcm1hdCB8fCBjdXJyZW50UHJlZmVycmVkRm9ybWF0IH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gaXNWYWxpZCgpIHtcbiAgICAgICAgICAgIHJldHVybiAhdGV4dElucHV0Lmhhc0NsYXNzKFwic3AtdmFsaWRhdGlvbi1lcnJvclwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIG1vdmUoKSB7XG4gICAgICAgICAgICB1cGRhdGVVSSgpO1xuXG4gICAgICAgICAgICBjYWxsYmFja3MubW92ZShnZXQoKSk7XG4gICAgICAgICAgICBib3VuZEVsZW1lbnQudHJpZ2dlcignbW92ZS5zcGVjdHJ1bScsIFsgZ2V0KCkgXSk7XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiB1cGRhdGVVSSgpIHtcblxuICAgICAgICAgICAgdGV4dElucHV0LnJlbW92ZUNsYXNzKFwic3AtdmFsaWRhdGlvbi1lcnJvclwiKTtcblxuICAgICAgICAgICAgdXBkYXRlSGVscGVyTG9jYXRpb25zKCk7XG5cbiAgICAgICAgICAgIC8vIFVwZGF0ZSBkcmFnZ2VyIGJhY2tncm91bmQgY29sb3IgKGdyYWRpZW50cyB0YWtlIGNhcmUgb2Ygc2F0dXJhdGlvbiBhbmQgdmFsdWUpLlxuICAgICAgICAgICAgdmFyIGZsYXRDb2xvciA9IHRpbnljb2xvci5mcm9tUmF0aW8oeyBoOiBjdXJyZW50SHVlLCBzOiAxLCB2OiAxIH0pO1xuICAgICAgICAgICAgZHJhZ2dlci5jc3MoXCJiYWNrZ3JvdW5kLWNvbG9yXCIsIGZsYXRDb2xvci50b0hleFN0cmluZygpKTtcblxuICAgICAgICAgICAgLy8gR2V0IGEgZm9ybWF0IHRoYXQgYWxwaGEgd2lsbCBiZSBpbmNsdWRlZCBpbiAoaGV4IGFuZCBuYW1lcyBpZ25vcmUgYWxwaGEpXG4gICAgICAgICAgICB2YXIgZm9ybWF0ID0gY3VycmVudFByZWZlcnJlZEZvcm1hdDtcbiAgICAgICAgICAgIGlmIChjdXJyZW50QWxwaGEgPCAxICYmICEoY3VycmVudEFscGhhID09PSAwICYmIGZvcm1hdCA9PT0gXCJuYW1lXCIpKSB7XG4gICAgICAgICAgICAgICAgaWYgKGZvcm1hdCA9PT0gXCJoZXhcIiB8fCBmb3JtYXQgPT09IFwiaGV4M1wiIHx8IGZvcm1hdCA9PT0gXCJoZXg2XCIgfHwgZm9ybWF0ID09PSBcIm5hbWVcIikge1xuICAgICAgICAgICAgICAgICAgICBmb3JtYXQgPSBcInJnYlwiO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJlYWxDb2xvciA9IGdldCh7IGZvcm1hdDogZm9ybWF0IH0pLFxuICAgICAgICAgICAgICAgIGRpc3BsYXlDb2xvciA9ICcnO1xuXG4gICAgICAgICAgICAgLy9yZXNldCBiYWNrZ3JvdW5kIGluZm8gZm9yIHByZXZpZXcgZWxlbWVudFxuICAgICAgICAgICAgcHJldmlld0VsZW1lbnQucmVtb3ZlQ2xhc3MoXCJzcC1jbGVhci1kaXNwbGF5XCIpO1xuICAgICAgICAgICAgcHJldmlld0VsZW1lbnQuY3NzKCdiYWNrZ3JvdW5kLWNvbG9yJywgJ3RyYW5zcGFyZW50Jyk7XG5cbiAgICAgICAgICAgIGlmICghcmVhbENvbG9yICYmIGFsbG93RW1wdHkpIHtcbiAgICAgICAgICAgICAgICAvLyBVcGRhdGUgdGhlIHJlcGxhY2VkIGVsZW1lbnRzIGJhY2tncm91bmQgd2l0aCBpY29uIGluZGljYXRpbmcgbm8gY29sb3Igc2VsZWN0aW9uXG4gICAgICAgICAgICAgICAgcHJldmlld0VsZW1lbnQuYWRkQ2xhc3MoXCJzcC1jbGVhci1kaXNwbGF5XCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlYWxIZXggPSByZWFsQ29sb3IudG9IZXhTdHJpbmcoKSxcbiAgICAgICAgICAgICAgICAgICAgcmVhbFJnYiA9IHJlYWxDb2xvci50b1JnYlN0cmluZygpO1xuXG4gICAgICAgICAgICAgICAgLy8gVXBkYXRlIHRoZSByZXBsYWNlZCBlbGVtZW50cyBiYWNrZ3JvdW5kIGNvbG9yICh3aXRoIGFjdHVhbCBzZWxlY3RlZCBjb2xvcilcbiAgICAgICAgICAgICAgICBpZiAocmdiYVN1cHBvcnQgfHwgcmVhbENvbG9yLmFscGhhID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIHByZXZpZXdFbGVtZW50LmNzcyhcImJhY2tncm91bmQtY29sb3JcIiwgcmVhbFJnYik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBwcmV2aWV3RWxlbWVudC5jc3MoXCJiYWNrZ3JvdW5kLWNvbG9yXCIsIFwidHJhbnNwYXJlbnRcIik7XG4gICAgICAgICAgICAgICAgICAgIHByZXZpZXdFbGVtZW50LmNzcyhcImZpbHRlclwiLCByZWFsQ29sb3IudG9GaWx0ZXIoKSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYgKG9wdHMuc2hvd0FscGhhKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciByZ2IgPSByZWFsQ29sb3IudG9SZ2IoKTtcbiAgICAgICAgICAgICAgICAgICAgcmdiLmEgPSAwO1xuICAgICAgICAgICAgICAgICAgICB2YXIgcmVhbEFscGhhID0gdGlueWNvbG9yKHJnYikudG9SZ2JTdHJpbmcoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGdyYWRpZW50ID0gXCJsaW5lYXItZ3JhZGllbnQobGVmdCwgXCIgKyByZWFsQWxwaGEgKyBcIiwgXCIgKyByZWFsSGV4ICsgXCIpXCI7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKElFKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhbHBoYVNsaWRlcklubmVyLmNzcyhcImZpbHRlclwiLCB0aW55Y29sb3IocmVhbEFscGhhKS50b0ZpbHRlcih7IGdyYWRpZW50VHlwZTogMSB9LCByZWFsSGV4KSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhbHBoYVNsaWRlcklubmVyLmNzcyhcImJhY2tncm91bmRcIiwgXCItd2Via2l0LVwiICsgZ3JhZGllbnQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGFTbGlkZXJJbm5lci5jc3MoXCJiYWNrZ3JvdW5kXCIsIFwiLW1vei1cIiArIGdyYWRpZW50KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFscGhhU2xpZGVySW5uZXIuY3NzKFwiYmFja2dyb3VuZFwiLCBcIi1tcy1cIiArIGdyYWRpZW50KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVzZSBjdXJyZW50IHN5bnRheCBncmFkaWVudCBvbiB1bnByZWZpeGVkIHByb3BlcnR5LlxuICAgICAgICAgICAgICAgICAgICAgICAgYWxwaGFTbGlkZXJJbm5lci5jc3MoXCJiYWNrZ3JvdW5kXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgXCJsaW5lYXItZ3JhZGllbnQodG8gcmlnaHQsIFwiICsgcmVhbEFscGhhICsgXCIsIFwiICsgcmVhbEhleCArIFwiKVwiKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGRpc3BsYXlDb2xvciA9IHJlYWxDb2xvci50b1N0cmluZyhmb3JtYXQpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBVcGRhdGUgdGhlIHRleHQgZW50cnkgaW5wdXQgYXMgaXQgY2hhbmdlcyBoYXBwZW5cbiAgICAgICAgICAgIGlmIChvcHRzLnNob3dJbnB1dCkge1xuICAgICAgICAgICAgICAgIHRleHRJbnB1dC52YWwoZGlzcGxheUNvbG9yKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKG9wdHMuc2hvd1BhbGV0dGUpIHtcbiAgICAgICAgICAgICAgICBkcmF3UGFsZXR0ZSgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBkcmF3SW5pdGlhbCgpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gdXBkYXRlSGVscGVyTG9jYXRpb25zKCkge1xuICAgICAgICAgICAgdmFyIHMgPSBjdXJyZW50U2F0dXJhdGlvbjtcbiAgICAgICAgICAgIHZhciB2ID0gY3VycmVudFZhbHVlO1xuXG4gICAgICAgICAgICBpZihhbGxvd0VtcHR5ICYmIGlzRW1wdHkpIHtcbiAgICAgICAgICAgICAgICAvL2lmIHNlbGVjdGVkIGNvbG9yIGlzIGVtcHR5LCBoaWRlIHRoZSBoZWxwZXJzXG4gICAgICAgICAgICAgICAgYWxwaGFTbGlkZUhlbHBlci5oaWRlKCk7XG4gICAgICAgICAgICAgICAgc2xpZGVIZWxwZXIuaGlkZSgpO1xuICAgICAgICAgICAgICAgIGRyYWdIZWxwZXIuaGlkZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgLy9tYWtlIHN1cmUgaGVscGVycyBhcmUgdmlzaWJsZVxuICAgICAgICAgICAgICAgIGFscGhhU2xpZGVIZWxwZXIuc2hvdygpO1xuICAgICAgICAgICAgICAgIHNsaWRlSGVscGVyLnNob3coKTtcbiAgICAgICAgICAgICAgICBkcmFnSGVscGVyLnNob3coKTtcblxuICAgICAgICAgICAgICAgIC8vIFdoZXJlIHRvIHNob3cgdGhlIGxpdHRsZSBjaXJjbGUgaW4gdGhhdCBkaXNwbGF5cyB5b3VyIGN1cnJlbnQgc2VsZWN0ZWQgY29sb3JcbiAgICAgICAgICAgICAgICB2YXIgZHJhZ1ggPSBzICogZHJhZ1dpZHRoO1xuICAgICAgICAgICAgICAgIHZhciBkcmFnWSA9IGRyYWdIZWlnaHQgLSAodiAqIGRyYWdIZWlnaHQpO1xuICAgICAgICAgICAgICAgIGRyYWdYID0gTWF0aC5tYXgoXG4gICAgICAgICAgICAgICAgICAgIC1kcmFnSGVscGVySGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICBNYXRoLm1pbihkcmFnV2lkdGggLSBkcmFnSGVscGVySGVpZ2h0LCBkcmFnWCAtIGRyYWdIZWxwZXJIZWlnaHQpXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICBkcmFnWSA9IE1hdGgubWF4KFxuICAgICAgICAgICAgICAgICAgICAtZHJhZ0hlbHBlckhlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgTWF0aC5taW4oZHJhZ0hlaWdodCAtIGRyYWdIZWxwZXJIZWlnaHQsIGRyYWdZIC0gZHJhZ0hlbHBlckhlaWdodClcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIGRyYWdIZWxwZXIuY3NzKHtcbiAgICAgICAgICAgICAgICAgICAgXCJ0b3BcIjogZHJhZ1kgKyBcInB4XCIsXG4gICAgICAgICAgICAgICAgICAgIFwibGVmdFwiOiBkcmFnWCArIFwicHhcIlxuICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgdmFyIGFscGhhWCA9IGN1cnJlbnRBbHBoYSAqIGFscGhhV2lkdGg7XG4gICAgICAgICAgICAgICAgYWxwaGFTbGlkZUhlbHBlci5jc3Moe1xuICAgICAgICAgICAgICAgICAgICBcImxlZnRcIjogKGFscGhhWCAtIChhbHBoYVNsaWRlSGVscGVyV2lkdGggLyAyKSkgKyBcInB4XCJcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIC8vIFdoZXJlIHRvIHNob3cgdGhlIGJhciB0aGF0IGRpc3BsYXlzIHlvdXIgY3VycmVudCBzZWxlY3RlZCBodWVcbiAgICAgICAgICAgICAgICB2YXIgc2xpZGVZID0gKGN1cnJlbnRIdWUpICogc2xpZGVIZWlnaHQ7XG4gICAgICAgICAgICAgICAgc2xpZGVIZWxwZXIuY3NzKHtcbiAgICAgICAgICAgICAgICAgICAgXCJ0b3BcIjogKHNsaWRlWSAtIHNsaWRlSGVscGVySGVpZ2h0KSArIFwicHhcIlxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gdXBkYXRlT3JpZ2luYWxJbnB1dChmaXJlQ2FsbGJhY2spIHtcbiAgICAgICAgICAgIHZhciBjb2xvciA9IGdldCgpLFxuICAgICAgICAgICAgICAgIGRpc3BsYXlDb2xvciA9ICcnLFxuICAgICAgICAgICAgICAgIGhhc0NoYW5nZWQgPSAhdGlueWNvbG9yLmVxdWFscyhjb2xvciwgY29sb3JPblNob3cpO1xuXG4gICAgICAgICAgICBpZiAoY29sb3IpIHtcbiAgICAgICAgICAgICAgICBkaXNwbGF5Q29sb3IgPSBjb2xvci50b1N0cmluZyhjdXJyZW50UHJlZmVycmVkRm9ybWF0KTtcbiAgICAgICAgICAgICAgICAvLyBVcGRhdGUgdGhlIHNlbGVjdGlvbiBwYWxldHRlIHdpdGggdGhlIGN1cnJlbnQgY29sb3JcbiAgICAgICAgICAgICAgICBhZGRDb2xvclRvU2VsZWN0aW9uUGFsZXR0ZShjb2xvcik7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChpc0lucHV0KSB7XG4gICAgICAgICAgICAgICAgYm91bmRFbGVtZW50LnZhbChkaXNwbGF5Q29sb3IpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoZmlyZUNhbGxiYWNrICYmIGhhc0NoYW5nZWQpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFja3MuY2hhbmdlKGNvbG9yKTtcbiAgICAgICAgICAgICAgICBib3VuZEVsZW1lbnQudHJpZ2dlcignY2hhbmdlJywgWyBjb2xvciBdKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIHJlZmxvdygpIHtcbiAgICAgICAgICAgIGlmICghdmlzaWJsZSkge1xuICAgICAgICAgICAgICAgIHJldHVybjsgLy8gQ2FsY3VsYXRpb25zIHdvdWxkIGJlIHVzZWxlc3MgYW5kIHdvdWxkbid0IGJlIHJlbGlhYmxlIGFueXdheXNcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGRyYWdXaWR0aCA9IGRyYWdnZXIud2lkdGgoKTtcbiAgICAgICAgICAgIGRyYWdIZWlnaHQgPSBkcmFnZ2VyLmhlaWdodCgpO1xuICAgICAgICAgICAgZHJhZ0hlbHBlckhlaWdodCA9IGRyYWdIZWxwZXIuaGVpZ2h0KCk7XG4gICAgICAgICAgICBzbGlkZVdpZHRoID0gc2xpZGVyLndpZHRoKCk7XG4gICAgICAgICAgICBzbGlkZUhlaWdodCA9IHNsaWRlci5oZWlnaHQoKTtcbiAgICAgICAgICAgIHNsaWRlSGVscGVySGVpZ2h0ID0gc2xpZGVIZWxwZXIuaGVpZ2h0KCk7XG4gICAgICAgICAgICBhbHBoYVdpZHRoID0gYWxwaGFTbGlkZXIud2lkdGgoKTtcbiAgICAgICAgICAgIGFscGhhU2xpZGVIZWxwZXJXaWR0aCA9IGFscGhhU2xpZGVIZWxwZXIud2lkdGgoKTtcblxuICAgICAgICAgICAgaWYgKCFmbGF0KSB7XG4gICAgICAgICAgICAgICAgY29udGFpbmVyLmNzcyhcInBvc2l0aW9uXCIsIFwiYWJzb2x1dGVcIik7XG4gICAgICAgICAgICAgICAgaWYgKG9wdHMub2Zmc2V0KSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lci5vZmZzZXQob3B0cy5vZmZzZXQpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnRhaW5lci5vZmZzZXQoZ2V0T2Zmc2V0KGNvbnRhaW5lciwgb2Zmc2V0RWxlbWVudCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdXBkYXRlSGVscGVyTG9jYXRpb25zKCk7XG5cbiAgICAgICAgICAgIGlmIChvcHRzLnNob3dQYWxldHRlKSB7XG4gICAgICAgICAgICAgICAgZHJhd1BhbGV0dGUoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgYm91bmRFbGVtZW50LnRyaWdnZXIoJ3JlZmxvdy5zcGVjdHJ1bScpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gZGVzdHJveSgpIHtcbiAgICAgICAgICAgIGJvdW5kRWxlbWVudC5zaG93KCk7XG4gICAgICAgICAgICBvZmZzZXRFbGVtZW50LnVuYmluZChcImNsaWNrLnNwZWN0cnVtIHRvdWNoc3RhcnQuc3BlY3RydW1cIik7XG4gICAgICAgICAgICBjb250YWluZXIucmVtb3ZlKCk7XG4gICAgICAgICAgICByZXBsYWNlci5yZW1vdmUoKTtcbiAgICAgICAgICAgIHNwZWN0cnVtc1tzcGVjdC5pZF0gPSBudWxsO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gb3B0aW9uKG9wdGlvbk5hbWUsIG9wdGlvblZhbHVlKSB7XG4gICAgICAgICAgICBpZiAob3B0aW9uTmFtZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuICQuZXh0ZW5kKHt9LCBvcHRzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChvcHRpb25WYWx1ZSA9PT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIG9wdHNbb3B0aW9uTmFtZV07XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIG9wdHNbb3B0aW9uTmFtZV0gPSBvcHRpb25WYWx1ZTtcblxuICAgICAgICAgICAgaWYgKG9wdGlvbk5hbWUgPT09IFwicHJlZmVycmVkRm9ybWF0XCIpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50UHJlZmVycmVkRm9ybWF0ID0gb3B0cy5wcmVmZXJyZWRGb3JtYXQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBhcHBseU9wdGlvbnMoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGVuYWJsZSgpIHtcbiAgICAgICAgICAgIGRpc2FibGVkID0gZmFsc2U7XG4gICAgICAgICAgICBib3VuZEVsZW1lbnQuYXR0cihcImRpc2FibGVkXCIsIGZhbHNlKTtcbiAgICAgICAgICAgIG9mZnNldEVsZW1lbnQucmVtb3ZlQ2xhc3MoXCJzcC1kaXNhYmxlZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIGRpc2FibGUoKSB7XG4gICAgICAgICAgICBoaWRlKCk7XG4gICAgICAgICAgICBkaXNhYmxlZCA9IHRydWU7XG4gICAgICAgICAgICBib3VuZEVsZW1lbnQuYXR0cihcImRpc2FibGVkXCIsIHRydWUpO1xuICAgICAgICAgICAgb2Zmc2V0RWxlbWVudC5hZGRDbGFzcyhcInNwLWRpc2FibGVkXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gc2V0T2Zmc2V0KGNvb3JkKSB7XG4gICAgICAgICAgICBvcHRzLm9mZnNldCA9IGNvb3JkO1xuICAgICAgICAgICAgcmVmbG93KCk7XG4gICAgICAgIH1cblxuICAgICAgICBpbml0aWFsaXplKCk7XG5cbiAgICAgICAgdmFyIHNwZWN0ID0ge1xuICAgICAgICAgICAgc2hvdzogc2hvdyxcbiAgICAgICAgICAgIGhpZGU6IGhpZGUsXG4gICAgICAgICAgICB0b2dnbGU6IHRvZ2dsZSxcbiAgICAgICAgICAgIHJlZmxvdzogcmVmbG93LFxuICAgICAgICAgICAgb3B0aW9uOiBvcHRpb24sXG4gICAgICAgICAgICBlbmFibGU6IGVuYWJsZSxcbiAgICAgICAgICAgIGRpc2FibGU6IGRpc2FibGUsXG4gICAgICAgICAgICBvZmZzZXQ6IHNldE9mZnNldCxcbiAgICAgICAgICAgIHNldDogZnVuY3Rpb24gKGMpIHtcbiAgICAgICAgICAgICAgICBzZXQoYyk7XG4gICAgICAgICAgICAgICAgdXBkYXRlT3JpZ2luYWxJbnB1dCgpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGdldDogZ2V0LFxuICAgICAgICAgICAgZGVzdHJveTogZGVzdHJveSxcbiAgICAgICAgICAgIGNvbnRhaW5lcjogY29udGFpbmVyXG4gICAgICAgIH07XG5cbiAgICAgICAgc3BlY3QuaWQgPSBzcGVjdHJ1bXMucHVzaChzcGVjdCkgLSAxO1xuXG4gICAgICAgIHJldHVybiBzcGVjdDtcbiAgICB9XG5cbiAgICAvKipcbiAgICAqIGNoZWNrT2Zmc2V0IC0gZ2V0IHRoZSBvZmZzZXQgYmVsb3cvYWJvdmUgYW5kIGxlZnQvcmlnaHQgZWxlbWVudCBkZXBlbmRpbmcgb24gc2NyZWVuIHBvc2l0aW9uXG4gICAgKiBUaGFua3MgaHR0cHM6Ly9naXRodWIuY29tL2pxdWVyeS9qcXVlcnktdWkvYmxvYi9tYXN0ZXIvdWkvanF1ZXJ5LnVpLmRhdGVwaWNrZXIuanNcbiAgICAqL1xuICAgIGZ1bmN0aW9uIGdldE9mZnNldChwaWNrZXIsIGlucHV0KSB7XG4gICAgICAgIHZhciBleHRyYVkgPSAwO1xuICAgICAgICB2YXIgZHBXaWR0aCA9IHBpY2tlci5vdXRlcldpZHRoKCk7XG4gICAgICAgIHZhciBkcEhlaWdodCA9IHBpY2tlci5vdXRlckhlaWdodCgpO1xuICAgICAgICB2YXIgaW5wdXRIZWlnaHQgPSBpbnB1dC5vdXRlckhlaWdodCgpO1xuICAgICAgICB2YXIgZG9jID0gcGlja2VyWzBdLm93bmVyRG9jdW1lbnQ7XG4gICAgICAgIHZhciBkb2NFbGVtID0gZG9jLmRvY3VtZW50RWxlbWVudDtcbiAgICAgICAgdmFyIHZpZXdXaWR0aCA9IGRvY0VsZW0uY2xpZW50V2lkdGggKyAkKGRvYykuc2Nyb2xsTGVmdCgpO1xuICAgICAgICB2YXIgdmlld0hlaWdodCA9IGRvY0VsZW0uY2xpZW50SGVpZ2h0ICsgJChkb2MpLnNjcm9sbFRvcCgpO1xuICAgICAgICB2YXIgb2Zmc2V0ID0gaW5wdXQub2Zmc2V0KCk7XG4gICAgICAgIG9mZnNldC50b3AgKz0gaW5wdXRIZWlnaHQ7XG5cbiAgICAgICAgb2Zmc2V0LmxlZnQgLT1cbiAgICAgICAgICAgIE1hdGgubWluKG9mZnNldC5sZWZ0LCAob2Zmc2V0LmxlZnQgKyBkcFdpZHRoID4gdmlld1dpZHRoICYmIHZpZXdXaWR0aCA+IGRwV2lkdGgpID9cbiAgICAgICAgICAgIE1hdGguYWJzKG9mZnNldC5sZWZ0ICsgZHBXaWR0aCAtIHZpZXdXaWR0aCkgOiAwKTtcblxuICAgICAgICBvZmZzZXQudG9wIC09XG4gICAgICAgICAgICBNYXRoLm1pbihvZmZzZXQudG9wLCAoKG9mZnNldC50b3AgKyBkcEhlaWdodCA+IHZpZXdIZWlnaHQgJiYgdmlld0hlaWdodCA+IGRwSGVpZ2h0KSA/XG4gICAgICAgICAgICBNYXRoLmFicyhkcEhlaWdodCArIGlucHV0SGVpZ2h0IC0gZXh0cmFZKSA6IGV4dHJhWSkpO1xuXG4gICAgICAgIHJldHVybiBvZmZzZXQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgKiBub29wIC0gZG8gbm90aGluZ1xuICAgICovXG4gICAgZnVuY3Rpb24gbm9vcCgpIHtcblxuICAgIH1cblxuICAgIC8qKlxuICAgICogc3RvcFByb3BhZ2F0aW9uIC0gbWFrZXMgdGhlIGNvZGUgb25seSBkb2luZyB0aGlzIGEgbGl0dGxlIGVhc2llciB0byByZWFkIGluIGxpbmVcbiAgICAqL1xuICAgIGZ1bmN0aW9uIHN0b3BQcm9wYWdhdGlvbihlKSB7XG4gICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgKiBDcmVhdGUgYSBmdW5jdGlvbiBib3VuZCB0byBhIGdpdmVuIG9iamVjdFxuICAgICogVGhhbmtzIHRvIHVuZGVyc2NvcmUuanNcbiAgICAqL1xuICAgIGZ1bmN0aW9uIGJpbmQoZnVuYywgb2JqKSB7XG4gICAgICAgIHZhciBzbGljZSA9IEFycmF5LnByb3RvdHlwZS5zbGljZTtcbiAgICAgICAgdmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMik7XG4gICAgICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICByZXR1cm4gZnVuYy5hcHBseShvYmosIGFyZ3MuY29uY2F0KHNsaWNlLmNhbGwoYXJndW1lbnRzKSkpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8qKlxuICAgICogTGlnaHR3ZWlnaHQgZHJhZyBoZWxwZXIuICBIYW5kbGVzIGNvbnRhaW5tZW50IHdpdGhpbiB0aGUgZWxlbWVudCwgc28gdGhhdFxuICAgICogd2hlbiBkcmFnZ2luZywgdGhlIHggaXMgd2l0aGluIFswLGVsZW1lbnQud2lkdGhdIGFuZCB5IGlzIHdpdGhpbiBbMCxlbGVtZW50LmhlaWdodF1cbiAgICAqL1xuICAgIGZ1bmN0aW9uIGRyYWdnYWJsZShlbGVtZW50LCBvbm1vdmUsIG9uc3RhcnQsIG9uc3RvcCkge1xuICAgICAgICBvbm1vdmUgPSBvbm1vdmUgfHwgZnVuY3Rpb24gKCkgeyB9O1xuICAgICAgICBvbnN0YXJ0ID0gb25zdGFydCB8fCBmdW5jdGlvbiAoKSB7IH07XG4gICAgICAgIG9uc3RvcCA9IG9uc3RvcCB8fCBmdW5jdGlvbiAoKSB7IH07XG4gICAgICAgIHZhciBkb2MgPSBkb2N1bWVudDtcbiAgICAgICAgdmFyIGRyYWdnaW5nID0gZmFsc2U7XG4gICAgICAgIHZhciBvZmZzZXQgPSB7fTtcbiAgICAgICAgdmFyIG1heEhlaWdodCA9IDA7XG4gICAgICAgIHZhciBtYXhXaWR0aCA9IDA7XG4gICAgICAgIHZhciBoYXNUb3VjaCA9ICgnb250b3VjaHN0YXJ0JyBpbiB3aW5kb3cpO1xuXG4gICAgICAgIHZhciBkdXJpbmdEcmFnRXZlbnRzID0ge307XG4gICAgICAgIGR1cmluZ0RyYWdFdmVudHNbXCJzZWxlY3RzdGFydFwiXSA9IHByZXZlbnQ7XG4gICAgICAgIGR1cmluZ0RyYWdFdmVudHNbXCJkcmFnc3RhcnRcIl0gPSBwcmV2ZW50O1xuICAgICAgICBkdXJpbmdEcmFnRXZlbnRzW1widG91Y2htb3ZlIG1vdXNlbW92ZVwiXSA9IG1vdmU7XG4gICAgICAgIGR1cmluZ0RyYWdFdmVudHNbXCJ0b3VjaGVuZCBtb3VzZXVwXCJdID0gc3RvcDtcblxuICAgICAgICBmdW5jdGlvbiBwcmV2ZW50KGUpIHtcbiAgICAgICAgICAgIGlmIChlLnN0b3BQcm9wYWdhdGlvbikge1xuICAgICAgICAgICAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZS5wcmV2ZW50RGVmYXVsdCkge1xuICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGUucmV0dXJuVmFsdWUgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZ1bmN0aW9uIG1vdmUoZSkge1xuICAgICAgICAgICAgaWYgKGRyYWdnaW5nKSB7XG4gICAgICAgICAgICAgICAgLy8gTW91c2V1cCBoYXBwZW5lZCBvdXRzaWRlIG9mIHdpbmRvd1xuICAgICAgICAgICAgICAgIGlmIChJRSAmJiBkb2MuZG9jdW1lbnRNb2RlIDwgOSAmJiAhZS5idXR0b24pIHtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHN0b3AoKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgdDAgPSBlLm9yaWdpbmFsRXZlbnQgJiYgZS5vcmlnaW5hbEV2ZW50LnRvdWNoZXMgJiYgZS5vcmlnaW5hbEV2ZW50LnRvdWNoZXNbMF07XG4gICAgICAgICAgICAgICAgdmFyIHBhZ2VYID0gdDAgJiYgdDAucGFnZVggfHwgZS5wYWdlWDtcbiAgICAgICAgICAgICAgICB2YXIgcGFnZVkgPSB0MCAmJiB0MC5wYWdlWSB8fCBlLnBhZ2VZO1xuXG4gICAgICAgICAgICAgICAgdmFyIGRyYWdYID0gTWF0aC5tYXgoMCwgTWF0aC5taW4ocGFnZVggLSBvZmZzZXQubGVmdCwgbWF4V2lkdGgpKTtcbiAgICAgICAgICAgICAgICB2YXIgZHJhZ1kgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihwYWdlWSAtIG9mZnNldC50b3AsIG1heEhlaWdodCkpO1xuXG4gICAgICAgICAgICAgICAgaWYgKGhhc1RvdWNoKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIFN0b3Agc2Nyb2xsaW5nIGluIGlPU1xuICAgICAgICAgICAgICAgICAgICBwcmV2ZW50KGUpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIG9ubW92ZS5hcHBseShlbGVtZW50LCBbZHJhZ1gsIGRyYWdZLCBlXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBmdW5jdGlvbiBzdGFydChlKSB7XG4gICAgICAgICAgICB2YXIgcmlnaHRjbGljayA9IChlLndoaWNoKSA/IChlLndoaWNoID09IDMpIDogKGUuYnV0dG9uID09IDIpO1xuXG4gICAgICAgICAgICBpZiAoIXJpZ2h0Y2xpY2sgJiYgIWRyYWdnaW5nKSB7XG4gICAgICAgICAgICAgICAgaWYgKG9uc3RhcnQuYXBwbHkoZWxlbWVudCwgYXJndW1lbnRzKSAhPT0gZmFsc2UpIHtcbiAgICAgICAgICAgICAgICAgICAgZHJhZ2dpbmcgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBtYXhIZWlnaHQgPSAkKGVsZW1lbnQpLmhlaWdodCgpO1xuICAgICAgICAgICAgICAgICAgICBtYXhXaWR0aCA9ICQoZWxlbWVudCkud2lkdGgoKTtcbiAgICAgICAgICAgICAgICAgICAgb2Zmc2V0ID0gJChlbGVtZW50KS5vZmZzZXQoKTtcblxuICAgICAgICAgICAgICAgICAgICAkKGRvYykuYmluZChkdXJpbmdEcmFnRXZlbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgJChkb2MuYm9keSkuYWRkQ2xhc3MoXCJzcC1kcmFnZ2luZ1wiKTtcblxuICAgICAgICAgICAgICAgICAgICBtb3ZlKGUpO1xuXG4gICAgICAgICAgICAgICAgICAgIHByZXZlbnQoZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgZnVuY3Rpb24gc3RvcCgpIHtcbiAgICAgICAgICAgIGlmIChkcmFnZ2luZykge1xuICAgICAgICAgICAgICAgICQoZG9jKS51bmJpbmQoZHVyaW5nRHJhZ0V2ZW50cyk7XG4gICAgICAgICAgICAgICAgJChkb2MuYm9keSkucmVtb3ZlQ2xhc3MoXCJzcC1kcmFnZ2luZ1wiKTtcblxuICAgICAgICAgICAgICAgIC8vIFdhaXQgYSB0aWNrIGJlZm9yZSBub3RpZnlpbmcgb2JzZXJ2ZXJzIHRvIGFsbG93IHRoZSBjbGljayBldmVudFxuICAgICAgICAgICAgICAgIC8vIHRvIGZpcmUgaW4gQ2hyb21lLlxuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgIG9uc3RvcC5hcHBseShlbGVtZW50LCBhcmd1bWVudHMpO1xuICAgICAgICAgICAgICAgIH0sIDApO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZHJhZ2dpbmcgPSBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgICQoZWxlbWVudCkuYmluZChcInRvdWNoc3RhcnQgbW91c2Vkb3duXCIsIHN0YXJ0KTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiB0aHJvdHRsZShmdW5jLCB3YWl0LCBkZWJvdW5jZSkge1xuICAgICAgICB2YXIgdGltZW91dDtcbiAgICAgICAgcmV0dXJuIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBjb250ZXh0ID0gdGhpcywgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgICAgICAgIHZhciB0aHJvdHRsZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgdGltZW91dCA9IG51bGw7XG4gICAgICAgICAgICAgICAgZnVuYy5hcHBseShjb250ZXh0LCBhcmdzKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBpZiAoZGVib3VuY2UpIGNsZWFyVGltZW91dCh0aW1lb3V0KTtcbiAgICAgICAgICAgIGlmIChkZWJvdW5jZSB8fCAhdGltZW91dCkgdGltZW91dCA9IHNldFRpbWVvdXQodGhyb3R0bGVyLCB3YWl0KTtcbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBpbnB1dFR5cGVDb2xvclN1cHBvcnQoKSB7XG4gICAgICAgIHJldHVybiAkLmZuLnNwZWN0cnVtLmlucHV0VHlwZUNvbG9yU3VwcG9ydCgpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICogRGVmaW5lIGEgalF1ZXJ5IHBsdWdpblxuICAgICovXG4gICAgdmFyIGRhdGFJRCA9IFwic3BlY3RydW0uaWRcIjtcbiAgICAkLmZuLnNwZWN0cnVtID0gZnVuY3Rpb24gKG9wdHMsIGV4dHJhKSB7XG5cbiAgICAgICAgaWYgKHR5cGVvZiBvcHRzID09IFwic3RyaW5nXCIpIHtcblxuICAgICAgICAgICAgdmFyIHJldHVyblZhbHVlID0gdGhpcztcbiAgICAgICAgICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoIGFyZ3VtZW50cywgMSApO1xuXG4gICAgICAgICAgICB0aGlzLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHZhciBzcGVjdCA9IHNwZWN0cnVtc1skKHRoaXMpLmRhdGEoZGF0YUlEKV07XG4gICAgICAgICAgICAgICAgaWYgKHNwZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBtZXRob2QgPSBzcGVjdFtvcHRzXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFtZXRob2QpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93IG5ldyBFcnJvciggXCJTcGVjdHJ1bTogbm8gc3VjaCBtZXRob2Q6ICdcIiArIG9wdHMgKyBcIidcIiApO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKG9wdHMgPT0gXCJnZXRcIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuVmFsdWUgPSBzcGVjdC5nZXQoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChvcHRzID09IFwiY29udGFpbmVyXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJldHVyblZhbHVlID0gc3BlY3QuY29udGFpbmVyO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKG9wdHMgPT0gXCJvcHRpb25cIikge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuVmFsdWUgPSBzcGVjdC5vcHRpb24uYXBwbHkoc3BlY3QsIGFyZ3MpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2UgaWYgKG9wdHMgPT0gXCJkZXN0cm95XCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNwZWN0LmRlc3Ryb3koKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICQodGhpcykucmVtb3ZlRGF0YShkYXRhSUQpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWV0aG9kLmFwcGx5KHNwZWN0LCBhcmdzKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICByZXR1cm4gcmV0dXJuVmFsdWU7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBJbml0aWFsaXppbmcgYSBuZXcgaW5zdGFuY2Ugb2Ygc3BlY3RydW1cbiAgICAgICAgcmV0dXJuIHRoaXMuc3BlY3RydW0oXCJkZXN0cm95XCIpLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIG9wdGlvbnMgPSAkLmV4dGVuZCh7fSwgb3B0cywgJCh0aGlzKS5kYXRhKCkpO1xuICAgICAgICAgICAgdmFyIHNwZWN0ID0gc3BlY3RydW0odGhpcywgb3B0aW9ucyk7XG4gICAgICAgICAgICAkKHRoaXMpLmRhdGEoZGF0YUlELCBzcGVjdC5pZCk7XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAkLmZuLnNwZWN0cnVtLmxvYWQgPSB0cnVlO1xuICAgICQuZm4uc3BlY3RydW0ubG9hZE9wdHMgPSB7fTtcbiAgICAkLmZuLnNwZWN0cnVtLmRyYWdnYWJsZSA9IGRyYWdnYWJsZTtcbiAgICAkLmZuLnNwZWN0cnVtLmRlZmF1bHRzID0gZGVmYXVsdE9wdHM7XG4gICAgJC5mbi5zcGVjdHJ1bS5pbnB1dFR5cGVDb2xvclN1cHBvcnQgPSBmdW5jdGlvbiBpbnB1dFR5cGVDb2xvclN1cHBvcnQoKSB7XG4gICAgICAgIGlmICh0eXBlb2YgaW5wdXRUeXBlQ29sb3JTdXBwb3J0Ll9jYWNoZWRSZXN1bHQgPT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICAgICAgICAgIHZhciBjb2xvcklucHV0ID0gJChcIjxpbnB1dCB0eXBlPSdjb2xvcicvPlwiKVswXTsgLy8gaWYgY29sb3IgZWxlbWVudCBpcyBzdXBwb3J0ZWQsIHZhbHVlIHdpbGwgZGVmYXVsdCB0byBub3QgbnVsbFxuICAgICAgICAgICAgaW5wdXRUeXBlQ29sb3JTdXBwb3J0Ll9jYWNoZWRSZXN1bHQgPSBjb2xvcklucHV0LnR5cGUgPT09IFwiY29sb3JcIiAmJiBjb2xvcklucHV0LnZhbHVlICE9PSBcIlwiO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBpbnB1dFR5cGVDb2xvclN1cHBvcnQuX2NhY2hlZFJlc3VsdDtcbiAgICB9O1xuXG4gICAgJC5zcGVjdHJ1bSA9IHsgfTtcbiAgICAkLnNwZWN0cnVtLmxvY2FsaXphdGlvbiA9IHsgfTtcbiAgICAkLnNwZWN0cnVtLnBhbGV0dGVzID0geyB9O1xuXG4gICAgJC5mbi5zcGVjdHJ1bS5wcm9jZXNzTmF0aXZlQ29sb3JJbnB1dHMgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBjb2xvcklucHV0cyA9ICQoXCJpbnB1dFt0eXBlPWNvbG9yXVwiKTtcbiAgICAgICAgaWYgKGNvbG9ySW5wdXRzLmxlbmd0aCAmJiAhaW5wdXRUeXBlQ29sb3JTdXBwb3J0KCkpIHtcbiAgICAgICAgICAgIGNvbG9ySW5wdXRzLnNwZWN0cnVtKHtcbiAgICAgICAgICAgICAgICBwcmVmZXJyZWRGb3JtYXQ6IFwiaGV4NlwiXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBUaW55Q29sb3IgdjEuMS4yXG4gICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2Jncmlucy9UaW55Q29sb3JcbiAgICAvLyBCcmlhbiBHcmluc3RlYWQsIE1JVCBMaWNlbnNlXG5cbiAgICAoZnVuY3Rpb24oKSB7XG5cbiAgICB2YXIgdHJpbUxlZnQgPSAvXltcXHMsI10rLyxcbiAgICAgICAgdHJpbVJpZ2h0ID0gL1xccyskLyxcbiAgICAgICAgdGlueUNvdW50ZXIgPSAwLFxuICAgICAgICBtYXRoID0gTWF0aCxcbiAgICAgICAgbWF0aFJvdW5kID0gbWF0aC5yb3VuZCxcbiAgICAgICAgbWF0aE1pbiA9IG1hdGgubWluLFxuICAgICAgICBtYXRoTWF4ID0gbWF0aC5tYXgsXG4gICAgICAgIG1hdGhSYW5kb20gPSBtYXRoLnJhbmRvbTtcblxuICAgIHZhciB0aW55Y29sb3IgPSBmdW5jdGlvbihjb2xvciwgb3B0cykge1xuXG4gICAgICAgIGNvbG9yID0gKGNvbG9yKSA/IGNvbG9yIDogJyc7XG4gICAgICAgIG9wdHMgPSBvcHRzIHx8IHsgfTtcblxuICAgICAgICAvLyBJZiBpbnB1dCBpcyBhbHJlYWR5IGEgdGlueWNvbG9yLCByZXR1cm4gaXRzZWxmXG4gICAgICAgIGlmIChjb2xvciBpbnN0YW5jZW9mIHRpbnljb2xvcikge1xuICAgICAgICAgICByZXR1cm4gY29sb3I7XG4gICAgICAgIH1cbiAgICAgICAgLy8gSWYgd2UgYXJlIGNhbGxlZCBhcyBhIGZ1bmN0aW9uLCBjYWxsIHVzaW5nIG5ldyBpbnN0ZWFkXG4gICAgICAgIGlmICghKHRoaXMgaW5zdGFuY2VvZiB0aW55Y29sb3IpKSB7XG4gICAgICAgICAgICByZXR1cm4gbmV3IHRpbnljb2xvcihjb2xvciwgb3B0cyk7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgcmdiID0gaW5wdXRUb1JHQihjb2xvcik7XG4gICAgICAgIHRoaXMuX29yaWdpbmFsSW5wdXQgPSBjb2xvcixcbiAgICAgICAgdGhpcy5fciA9IHJnYi5yLFxuICAgICAgICB0aGlzLl9nID0gcmdiLmcsXG4gICAgICAgIHRoaXMuX2IgPSByZ2IuYixcbiAgICAgICAgdGhpcy5fYSA9IHJnYi5hLFxuICAgICAgICB0aGlzLl9yb3VuZEEgPSBtYXRoUm91bmQoMTAwKnRoaXMuX2EpIC8gMTAwLFxuICAgICAgICB0aGlzLl9mb3JtYXQgPSBvcHRzLmZvcm1hdCB8fCByZ2IuZm9ybWF0O1xuICAgICAgICB0aGlzLl9ncmFkaWVudFR5cGUgPSBvcHRzLmdyYWRpZW50VHlwZTtcblxuICAgICAgICAvLyBEb24ndCBsZXQgdGhlIHJhbmdlIG9mIFswLDI1NV0gY29tZSBiYWNrIGluIFswLDFdLlxuICAgICAgICAvLyBQb3RlbnRpYWxseSBsb3NlIGEgbGl0dGxlIGJpdCBvZiBwcmVjaXNpb24gaGVyZSwgYnV0IHdpbGwgZml4IGlzc3VlcyB3aGVyZVxuICAgICAgICAvLyAuNSBnZXRzIGludGVycHJldGVkIGFzIGhhbGYgb2YgdGhlIHRvdGFsLCBpbnN0ZWFkIG9mIGhhbGYgb2YgMVxuICAgICAgICAvLyBJZiBpdCB3YXMgc3VwcG9zZWQgdG8gYmUgMTI4LCB0aGlzIHdhcyBhbHJlYWR5IHRha2VuIGNhcmUgb2YgYnkgYGlucHV0VG9SZ2JgXG4gICAgICAgIGlmICh0aGlzLl9yIDwgMSkgeyB0aGlzLl9yID0gbWF0aFJvdW5kKHRoaXMuX3IpOyB9XG4gICAgICAgIGlmICh0aGlzLl9nIDwgMSkgeyB0aGlzLl9nID0gbWF0aFJvdW5kKHRoaXMuX2cpOyB9XG4gICAgICAgIGlmICh0aGlzLl9iIDwgMSkgeyB0aGlzLl9iID0gbWF0aFJvdW5kKHRoaXMuX2IpOyB9XG5cbiAgICAgICAgdGhpcy5fb2sgPSByZ2Iub2s7XG4gICAgICAgIHRoaXMuX3RjX2lkID0gdGlueUNvdW50ZXIrKztcbiAgICB9O1xuXG4gICAgdGlueWNvbG9yLnByb3RvdHlwZSA9IHtcbiAgICAgICAgaXNEYXJrOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEJyaWdodG5lc3MoKSA8IDEyODtcbiAgICAgICAgfSxcbiAgICAgICAgaXNMaWdodDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gIXRoaXMuaXNEYXJrKCk7XG4gICAgICAgIH0sXG4gICAgICAgIGlzVmFsaWQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX29rO1xuICAgICAgICB9LFxuICAgICAgICBnZXRPcmlnaW5hbElucHV0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICByZXR1cm4gdGhpcy5fb3JpZ2luYWxJbnB1dDtcbiAgICAgICAgfSxcbiAgICAgICAgZ2V0Rm9ybWF0OiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9mb3JtYXQ7XG4gICAgICAgIH0sXG4gICAgICAgIGdldEFscGhhOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9hO1xuICAgICAgICB9LFxuICAgICAgICBnZXRCcmlnaHRuZXNzOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciByZ2IgPSB0aGlzLnRvUmdiKCk7XG4gICAgICAgICAgICByZXR1cm4gKHJnYi5yICogMjk5ICsgcmdiLmcgKiA1ODcgKyByZ2IuYiAqIDExNCkgLyAxMDAwO1xuICAgICAgICB9LFxuICAgICAgICBzZXRBbHBoYTogZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgICAgICAgIHRoaXMuX2EgPSBib3VuZEFscGhhKHZhbHVlKTtcbiAgICAgICAgICAgIHRoaXMuX3JvdW5kQSA9IG1hdGhSb3VuZCgxMDAqdGhpcy5fYSkgLyAxMDA7XG4gICAgICAgICAgICByZXR1cm4gdGhpcztcbiAgICAgICAgfSxcbiAgICAgICAgdG9Ic3Y6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGhzdiA9IHJnYlRvSHN2KHRoaXMuX3IsIHRoaXMuX2csIHRoaXMuX2IpO1xuICAgICAgICAgICAgcmV0dXJuIHsgaDogaHN2LmggKiAzNjAsIHM6IGhzdi5zLCB2OiBoc3YudiwgYTogdGhpcy5fYSB9O1xuICAgICAgICB9LFxuICAgICAgICB0b0hzdlN0cmluZzogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgaHN2ID0gcmdiVG9Ic3YodGhpcy5fciwgdGhpcy5fZywgdGhpcy5fYik7XG4gICAgICAgICAgICB2YXIgaCA9IG1hdGhSb3VuZChoc3YuaCAqIDM2MCksIHMgPSBtYXRoUm91bmQoaHN2LnMgKiAxMDApLCB2ID0gbWF0aFJvdW5kKGhzdi52ICogMTAwKTtcbiAgICAgICAgICAgIHJldHVybiAodGhpcy5fYSA9PSAxKSA/XG4gICAgICAgICAgICAgIFwiaHN2KFwiICArIGggKyBcIiwgXCIgKyBzICsgXCIlLCBcIiArIHYgKyBcIiUpXCIgOlxuICAgICAgICAgICAgICBcImhzdmEoXCIgKyBoICsgXCIsIFwiICsgcyArIFwiJSwgXCIgKyB2ICsgXCIlLCBcIisgdGhpcy5fcm91bmRBICsgXCIpXCI7XG4gICAgICAgIH0sXG4gICAgICAgIHRvSHNsOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHZhciBoc2wgPSByZ2JUb0hzbCh0aGlzLl9yLCB0aGlzLl9nLCB0aGlzLl9iKTtcbiAgICAgICAgICAgIHJldHVybiB7IGg6IGhzbC5oICogMzYwLCBzOiBoc2wucywgbDogaHNsLmwsIGE6IHRoaXMuX2EgfTtcbiAgICAgICAgfSxcbiAgICAgICAgdG9Ic2xTdHJpbmc6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIGhzbCA9IHJnYlRvSHNsKHRoaXMuX3IsIHRoaXMuX2csIHRoaXMuX2IpO1xuICAgICAgICAgICAgdmFyIGggPSBtYXRoUm91bmQoaHNsLmggKiAzNjApLCBzID0gbWF0aFJvdW5kKGhzbC5zICogMTAwKSwgbCA9IG1hdGhSb3VuZChoc2wubCAqIDEwMCk7XG4gICAgICAgICAgICByZXR1cm4gKHRoaXMuX2EgPT0gMSkgP1xuICAgICAgICAgICAgICBcImhzbChcIiAgKyBoICsgXCIsIFwiICsgcyArIFwiJSwgXCIgKyBsICsgXCIlKVwiIDpcbiAgICAgICAgICAgICAgXCJoc2xhKFwiICsgaCArIFwiLCBcIiArIHMgKyBcIiUsIFwiICsgbCArIFwiJSwgXCIrIHRoaXMuX3JvdW5kQSArIFwiKVwiO1xuICAgICAgICB9LFxuICAgICAgICB0b0hleDogZnVuY3Rpb24oYWxsb3czQ2hhcikge1xuICAgICAgICAgICAgcmV0dXJuIHJnYlRvSGV4KHRoaXMuX3IsIHRoaXMuX2csIHRoaXMuX2IsIGFsbG93M0NoYXIpO1xuICAgICAgICB9LFxuICAgICAgICB0b0hleFN0cmluZzogZnVuY3Rpb24oYWxsb3czQ2hhcikge1xuICAgICAgICAgICAgcmV0dXJuICcjJyArIHRoaXMudG9IZXgoYWxsb3czQ2hhcik7XG4gICAgICAgIH0sXG4gICAgICAgIHRvSGV4ODogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gcmdiYVRvSGV4KHRoaXMuX3IsIHRoaXMuX2csIHRoaXMuX2IsIHRoaXMuX2EpO1xuICAgICAgICB9LFxuICAgICAgICB0b0hleDhTdHJpbmc6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuICcjJyArIHRoaXMudG9IZXg4KCk7XG4gICAgICAgIH0sXG4gICAgICAgIHRvUmdiOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHI6IG1hdGhSb3VuZCh0aGlzLl9yKSwgZzogbWF0aFJvdW5kKHRoaXMuX2cpLCBiOiBtYXRoUm91bmQodGhpcy5fYiksIGE6IHRoaXMuX2EgfTtcbiAgICAgICAgfSxcbiAgICAgICAgdG9SZ2JTdHJpbmc6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuICh0aGlzLl9hID09IDEpID9cbiAgICAgICAgICAgICAgXCJyZ2IoXCIgICsgbWF0aFJvdW5kKHRoaXMuX3IpICsgXCIsIFwiICsgbWF0aFJvdW5kKHRoaXMuX2cpICsgXCIsIFwiICsgbWF0aFJvdW5kKHRoaXMuX2IpICsgXCIpXCIgOlxuICAgICAgICAgICAgICBcInJnYmEoXCIgKyBtYXRoUm91bmQodGhpcy5fcikgKyBcIiwgXCIgKyBtYXRoUm91bmQodGhpcy5fZykgKyBcIiwgXCIgKyBtYXRoUm91bmQodGhpcy5fYikgKyBcIiwgXCIgKyB0aGlzLl9yb3VuZEEgKyBcIilcIjtcbiAgICAgICAgfSxcbiAgICAgICAgdG9QZXJjZW50YWdlUmdiOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB7IHI6IG1hdGhSb3VuZChib3VuZDAxKHRoaXMuX3IsIDI1NSkgKiAxMDApICsgXCIlXCIsIGc6IG1hdGhSb3VuZChib3VuZDAxKHRoaXMuX2csIDI1NSkgKiAxMDApICsgXCIlXCIsIGI6IG1hdGhSb3VuZChib3VuZDAxKHRoaXMuX2IsIDI1NSkgKiAxMDApICsgXCIlXCIsIGE6IHRoaXMuX2EgfTtcbiAgICAgICAgfSxcbiAgICAgICAgdG9QZXJjZW50YWdlUmdiU3RyaW5nOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiAodGhpcy5fYSA9PSAxKSA/XG4gICAgICAgICAgICAgIFwicmdiKFwiICArIG1hdGhSb3VuZChib3VuZDAxKHRoaXMuX3IsIDI1NSkgKiAxMDApICsgXCIlLCBcIiArIG1hdGhSb3VuZChib3VuZDAxKHRoaXMuX2csIDI1NSkgKiAxMDApICsgXCIlLCBcIiArIG1hdGhSb3VuZChib3VuZDAxKHRoaXMuX2IsIDI1NSkgKiAxMDApICsgXCIlKVwiIDpcbiAgICAgICAgICAgICAgXCJyZ2JhKFwiICsgbWF0aFJvdW5kKGJvdW5kMDEodGhpcy5fciwgMjU1KSAqIDEwMCkgKyBcIiUsIFwiICsgbWF0aFJvdW5kKGJvdW5kMDEodGhpcy5fZywgMjU1KSAqIDEwMCkgKyBcIiUsIFwiICsgbWF0aFJvdW5kKGJvdW5kMDEodGhpcy5fYiwgMjU1KSAqIDEwMCkgKyBcIiUsIFwiICsgdGhpcy5fcm91bmRBICsgXCIpXCI7XG4gICAgICAgIH0sXG4gICAgICAgIHRvTmFtZTogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5fYSA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBcInRyYW5zcGFyZW50XCI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLl9hIDwgMSkge1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuIGhleE5hbWVzW3JnYlRvSGV4KHRoaXMuX3IsIHRoaXMuX2csIHRoaXMuX2IsIHRydWUpXSB8fCBmYWxzZTtcbiAgICAgICAgfSxcbiAgICAgICAgdG9GaWx0ZXI6IGZ1bmN0aW9uKHNlY29uZENvbG9yKSB7XG4gICAgICAgICAgICB2YXIgaGV4OFN0cmluZyA9ICcjJyArIHJnYmFUb0hleCh0aGlzLl9yLCB0aGlzLl9nLCB0aGlzLl9iLCB0aGlzLl9hKTtcbiAgICAgICAgICAgIHZhciBzZWNvbmRIZXg4U3RyaW5nID0gaGV4OFN0cmluZztcbiAgICAgICAgICAgIHZhciBncmFkaWVudFR5cGUgPSB0aGlzLl9ncmFkaWVudFR5cGUgPyBcIkdyYWRpZW50VHlwZSA9IDEsIFwiIDogXCJcIjtcblxuICAgICAgICAgICAgaWYgKHNlY29uZENvbG9yKSB7XG4gICAgICAgICAgICAgICAgdmFyIHMgPSB0aW55Y29sb3Ioc2Vjb25kQ29sb3IpO1xuICAgICAgICAgICAgICAgIHNlY29uZEhleDhTdHJpbmcgPSBzLnRvSGV4OFN0cmluZygpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gXCJwcm9naWQ6RFhJbWFnZVRyYW5zZm9ybS5NaWNyb3NvZnQuZ3JhZGllbnQoXCIrZ3JhZGllbnRUeXBlK1wic3RhcnRDb2xvcnN0cj1cIitoZXg4U3RyaW5nK1wiLGVuZENvbG9yc3RyPVwiK3NlY29uZEhleDhTdHJpbmcrXCIpXCI7XG4gICAgICAgIH0sXG4gICAgICAgIHRvU3RyaW5nOiBmdW5jdGlvbihmb3JtYXQpIHtcbiAgICAgICAgICAgIHZhciBmb3JtYXRTZXQgPSAhIWZvcm1hdDtcbiAgICAgICAgICAgIGZvcm1hdCA9IGZvcm1hdCB8fCB0aGlzLl9mb3JtYXQ7XG5cbiAgICAgICAgICAgIHZhciBmb3JtYXR0ZWRTdHJpbmcgPSBmYWxzZTtcbiAgICAgICAgICAgIHZhciBoYXNBbHBoYSA9IHRoaXMuX2EgPCAxICYmIHRoaXMuX2EgPj0gMDtcbiAgICAgICAgICAgIHZhciBuZWVkc0FscGhhRm9ybWF0ID0gIWZvcm1hdFNldCAmJiBoYXNBbHBoYSAmJiAoZm9ybWF0ID09PSBcImhleFwiIHx8IGZvcm1hdCA9PT0gXCJoZXg2XCIgfHwgZm9ybWF0ID09PSBcImhleDNcIiB8fCBmb3JtYXQgPT09IFwibmFtZVwiKTtcblxuICAgICAgICAgICAgaWYgKG5lZWRzQWxwaGFGb3JtYXQpIHtcbiAgICAgICAgICAgICAgICAvLyBTcGVjaWFsIGNhc2UgZm9yIFwidHJhbnNwYXJlbnRcIiwgYWxsIG90aGVyIG5vbi1hbHBoYSBmb3JtYXRzXG4gICAgICAgICAgICAgICAgLy8gd2lsbCByZXR1cm4gcmdiYSB3aGVuIHRoZXJlIGlzIHRyYW5zcGFyZW5jeS5cbiAgICAgICAgICAgICAgICBpZiAoZm9ybWF0ID09PSBcIm5hbWVcIiAmJiB0aGlzLl9hID09PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnRvTmFtZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy50b1JnYlN0cmluZygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGZvcm1hdCA9PT0gXCJyZ2JcIikge1xuICAgICAgICAgICAgICAgIGZvcm1hdHRlZFN0cmluZyA9IHRoaXMudG9SZ2JTdHJpbmcoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChmb3JtYXQgPT09IFwicHJnYlwiKSB7XG4gICAgICAgICAgICAgICAgZm9ybWF0dGVkU3RyaW5nID0gdGhpcy50b1BlcmNlbnRhZ2VSZ2JTdHJpbmcoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChmb3JtYXQgPT09IFwiaGV4XCIgfHwgZm9ybWF0ID09PSBcImhleDZcIikge1xuICAgICAgICAgICAgICAgIGZvcm1hdHRlZFN0cmluZyA9IHRoaXMudG9IZXhTdHJpbmcoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChmb3JtYXQgPT09IFwiaGV4M1wiKSB7XG4gICAgICAgICAgICAgICAgZm9ybWF0dGVkU3RyaW5nID0gdGhpcy50b0hleFN0cmluZyh0cnVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChmb3JtYXQgPT09IFwiaGV4OFwiKSB7XG4gICAgICAgICAgICAgICAgZm9ybWF0dGVkU3RyaW5nID0gdGhpcy50b0hleDhTdHJpbmcoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChmb3JtYXQgPT09IFwibmFtZVwiKSB7XG4gICAgICAgICAgICAgICAgZm9ybWF0dGVkU3RyaW5nID0gdGhpcy50b05hbWUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChmb3JtYXQgPT09IFwiaHNsXCIpIHtcbiAgICAgICAgICAgICAgICBmb3JtYXR0ZWRTdHJpbmcgPSB0aGlzLnRvSHNsU3RyaW5nKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZm9ybWF0ID09PSBcImhzdlwiKSB7XG4gICAgICAgICAgICAgICAgZm9ybWF0dGVkU3RyaW5nID0gdGhpcy50b0hzdlN0cmluZygpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gZm9ybWF0dGVkU3RyaW5nIHx8IHRoaXMudG9IZXhTdHJpbmcoKTtcbiAgICAgICAgfSxcblxuICAgICAgICBfYXBwbHlNb2RpZmljYXRpb246IGZ1bmN0aW9uKGZuLCBhcmdzKSB7XG4gICAgICAgICAgICB2YXIgY29sb3IgPSBmbi5hcHBseShudWxsLCBbdGhpc10uY29uY2F0KFtdLnNsaWNlLmNhbGwoYXJncykpKTtcbiAgICAgICAgICAgIHRoaXMuX3IgPSBjb2xvci5fcjtcbiAgICAgICAgICAgIHRoaXMuX2cgPSBjb2xvci5fZztcbiAgICAgICAgICAgIHRoaXMuX2IgPSBjb2xvci5fYjtcbiAgICAgICAgICAgIHRoaXMuc2V0QWxwaGEoY29sb3IuX2EpO1xuICAgICAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgICAgIH0sXG4gICAgICAgIGxpZ2h0ZW46IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2FwcGx5TW9kaWZpY2F0aW9uKGxpZ2h0ZW4sIGFyZ3VtZW50cyk7XG4gICAgICAgIH0sXG4gICAgICAgIGJyaWdodGVuOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9hcHBseU1vZGlmaWNhdGlvbihicmlnaHRlbiwgYXJndW1lbnRzKTtcbiAgICAgICAgfSxcbiAgICAgICAgZGFya2VuOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9hcHBseU1vZGlmaWNhdGlvbihkYXJrZW4sIGFyZ3VtZW50cyk7XG4gICAgICAgIH0sXG4gICAgICAgIGRlc2F0dXJhdGU6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2FwcGx5TW9kaWZpY2F0aW9uKGRlc2F0dXJhdGUsIGFyZ3VtZW50cyk7XG4gICAgICAgIH0sXG4gICAgICAgIHNhdHVyYXRlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9hcHBseU1vZGlmaWNhdGlvbihzYXR1cmF0ZSwgYXJndW1lbnRzKTtcbiAgICAgICAgfSxcbiAgICAgICAgZ3JleXNjYWxlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9hcHBseU1vZGlmaWNhdGlvbihncmV5c2NhbGUsIGFyZ3VtZW50cyk7XG4gICAgICAgIH0sXG4gICAgICAgIHNwaW46IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2FwcGx5TW9kaWZpY2F0aW9uKHNwaW4sIGFyZ3VtZW50cyk7XG4gICAgICAgIH0sXG5cbiAgICAgICAgX2FwcGx5Q29tYmluYXRpb246IGZ1bmN0aW9uKGZuLCBhcmdzKSB7XG4gICAgICAgICAgICByZXR1cm4gZm4uYXBwbHkobnVsbCwgW3RoaXNdLmNvbmNhdChbXS5zbGljZS5jYWxsKGFyZ3MpKSk7XG4gICAgICAgIH0sXG4gICAgICAgIGFuYWxvZ291czogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fYXBwbHlDb21iaW5hdGlvbihhbmFsb2dvdXMsIGFyZ3VtZW50cyk7XG4gICAgICAgIH0sXG4gICAgICAgIGNvbXBsZW1lbnQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2FwcGx5Q29tYmluYXRpb24oY29tcGxlbWVudCwgYXJndW1lbnRzKTtcbiAgICAgICAgfSxcbiAgICAgICAgbW9ub2Nocm9tYXRpYzogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fYXBwbHlDb21iaW5hdGlvbihtb25vY2hyb21hdGljLCBhcmd1bWVudHMpO1xuICAgICAgICB9LFxuICAgICAgICBzcGxpdGNvbXBsZW1lbnQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuX2FwcGx5Q29tYmluYXRpb24oc3BsaXRjb21wbGVtZW50LCBhcmd1bWVudHMpO1xuICAgICAgICB9LFxuICAgICAgICB0cmlhZDogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fYXBwbHlDb21iaW5hdGlvbih0cmlhZCwgYXJndW1lbnRzKTtcbiAgICAgICAgfSxcbiAgICAgICAgdGV0cmFkOiBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLl9hcHBseUNvbWJpbmF0aW9uKHRldHJhZCwgYXJndW1lbnRzKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvLyBJZiBpbnB1dCBpcyBhbiBvYmplY3QsIGZvcmNlIDEgaW50byBcIjEuMFwiIHRvIGhhbmRsZSByYXRpb3MgcHJvcGVybHlcbiAgICAvLyBTdHJpbmcgaW5wdXQgcmVxdWlyZXMgXCIxLjBcIiBhcyBpbnB1dCwgc28gMSB3aWxsIGJlIHRyZWF0ZWQgYXMgMVxuICAgIHRpbnljb2xvci5mcm9tUmF0aW8gPSBmdW5jdGlvbihjb2xvciwgb3B0cykge1xuICAgICAgICBpZiAodHlwZW9mIGNvbG9yID09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgICAgIHZhciBuZXdDb2xvciA9IHt9O1xuICAgICAgICAgICAgZm9yICh2YXIgaSBpbiBjb2xvcikge1xuICAgICAgICAgICAgICAgIGlmIChjb2xvci5oYXNPd25Qcm9wZXJ0eShpKSkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoaSA9PT0gXCJhXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5ld0NvbG9yW2ldID0gY29sb3JbaV07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBuZXdDb2xvcltpXSA9IGNvbnZlcnRUb1BlcmNlbnRhZ2UoY29sb3JbaV0pO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29sb3IgPSBuZXdDb2xvcjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiB0aW55Y29sb3IoY29sb3IsIG9wdHMpO1xuICAgIH07XG5cbiAgICAvLyBHaXZlbiBhIHN0cmluZyBvciBvYmplY3QsIGNvbnZlcnQgdGhhdCBpbnB1dCB0byBSR0JcbiAgICAvLyBQb3NzaWJsZSBzdHJpbmcgaW5wdXRzOlxuICAgIC8vXG4gICAgLy8gICAgIFwicmVkXCJcbiAgICAvLyAgICAgXCIjZjAwXCIgb3IgXCJmMDBcIlxuICAgIC8vICAgICBcIiNmZjAwMDBcIiBvciBcImZmMDAwMFwiXG4gICAgLy8gICAgIFwiI2ZmMDAwMDAwXCIgb3IgXCJmZjAwMDAwMFwiXG4gICAgLy8gICAgIFwicmdiIDI1NSAwIDBcIiBvciBcInJnYiAoMjU1LCAwLCAwKVwiXG4gICAgLy8gICAgIFwicmdiIDEuMCAwIDBcIiBvciBcInJnYiAoMSwgMCwgMClcIlxuICAgIC8vICAgICBcInJnYmEgKDI1NSwgMCwgMCwgMSlcIiBvciBcInJnYmEgMjU1LCAwLCAwLCAxXCJcbiAgICAvLyAgICAgXCJyZ2JhICgxLjAsIDAsIDAsIDEpXCIgb3IgXCJyZ2JhIDEuMCwgMCwgMCwgMVwiXG4gICAgLy8gICAgIFwiaHNsKDAsIDEwMCUsIDUwJSlcIiBvciBcImhzbCAwIDEwMCUgNTAlXCJcbiAgICAvLyAgICAgXCJoc2xhKDAsIDEwMCUsIDUwJSwgMSlcIiBvciBcImhzbGEgMCAxMDAlIDUwJSwgMVwiXG4gICAgLy8gICAgIFwiaHN2KDAsIDEwMCUsIDEwMCUpXCIgb3IgXCJoc3YgMCAxMDAlIDEwMCVcIlxuICAgIC8vXG4gICAgZnVuY3Rpb24gaW5wdXRUb1JHQihjb2xvcikge1xuXG4gICAgICAgIHZhciByZ2IgPSB7IHI6IDAsIGc6IDAsIGI6IDAgfTtcbiAgICAgICAgdmFyIGEgPSAxO1xuICAgICAgICB2YXIgb2sgPSBmYWxzZTtcbiAgICAgICAgdmFyIGZvcm1hdCA9IGZhbHNlO1xuXG4gICAgICAgIGlmICh0eXBlb2YgY29sb3IgPT0gXCJzdHJpbmdcIikge1xuICAgICAgICAgICAgY29sb3IgPSBzdHJpbmdJbnB1dFRvT2JqZWN0KGNvbG9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0eXBlb2YgY29sb3IgPT0gXCJvYmplY3RcIikge1xuICAgICAgICAgICAgaWYgKGNvbG9yLmhhc093blByb3BlcnR5KFwiclwiKSAmJiBjb2xvci5oYXNPd25Qcm9wZXJ0eShcImdcIikgJiYgY29sb3IuaGFzT3duUHJvcGVydHkoXCJiXCIpKSB7XG4gICAgICAgICAgICAgICAgcmdiID0gcmdiVG9SZ2IoY29sb3IuciwgY29sb3IuZywgY29sb3IuYik7XG4gICAgICAgICAgICAgICAgb2sgPSB0cnVlO1xuICAgICAgICAgICAgICAgIGZvcm1hdCA9IFN0cmluZyhjb2xvci5yKS5zdWJzdHIoLTEpID09PSBcIiVcIiA/IFwicHJnYlwiIDogXCJyZ2JcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKGNvbG9yLmhhc093blByb3BlcnR5KFwiaFwiKSAmJiBjb2xvci5oYXNPd25Qcm9wZXJ0eShcInNcIikgJiYgY29sb3IuaGFzT3duUHJvcGVydHkoXCJ2XCIpKSB7XG4gICAgICAgICAgICAgICAgY29sb3IucyA9IGNvbnZlcnRUb1BlcmNlbnRhZ2UoY29sb3Iucyk7XG4gICAgICAgICAgICAgICAgY29sb3IudiA9IGNvbnZlcnRUb1BlcmNlbnRhZ2UoY29sb3Iudik7XG4gICAgICAgICAgICAgICAgcmdiID0gaHN2VG9SZ2IoY29sb3IuaCwgY29sb3IucywgY29sb3Iudik7XG4gICAgICAgICAgICAgICAgb2sgPSB0cnVlO1xuICAgICAgICAgICAgICAgIGZvcm1hdCA9IFwiaHN2XCI7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIGlmIChjb2xvci5oYXNPd25Qcm9wZXJ0eShcImhcIikgJiYgY29sb3IuaGFzT3duUHJvcGVydHkoXCJzXCIpICYmIGNvbG9yLmhhc093blByb3BlcnR5KFwibFwiKSkge1xuICAgICAgICAgICAgICAgIGNvbG9yLnMgPSBjb252ZXJ0VG9QZXJjZW50YWdlKGNvbG9yLnMpO1xuICAgICAgICAgICAgICAgIGNvbG9yLmwgPSBjb252ZXJ0VG9QZXJjZW50YWdlKGNvbG9yLmwpO1xuICAgICAgICAgICAgICAgIHJnYiA9IGhzbFRvUmdiKGNvbG9yLmgsIGNvbG9yLnMsIGNvbG9yLmwpO1xuICAgICAgICAgICAgICAgIG9rID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBmb3JtYXQgPSBcImhzbFwiO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoY29sb3IuaGFzT3duUHJvcGVydHkoXCJhXCIpKSB7XG4gICAgICAgICAgICAgICAgYSA9IGNvbG9yLmE7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBhID0gYm91bmRBbHBoYShhKTtcblxuICAgICAgICByZXR1cm4ge1xuICAgICAgICAgICAgb2s6IG9rLFxuICAgICAgICAgICAgZm9ybWF0OiBjb2xvci5mb3JtYXQgfHwgZm9ybWF0LFxuICAgICAgICAgICAgcjogbWF0aE1pbigyNTUsIG1hdGhNYXgocmdiLnIsIDApKSxcbiAgICAgICAgICAgIGc6IG1hdGhNaW4oMjU1LCBtYXRoTWF4KHJnYi5nLCAwKSksXG4gICAgICAgICAgICBiOiBtYXRoTWluKDI1NSwgbWF0aE1heChyZ2IuYiwgMCkpLFxuICAgICAgICAgICAgYTogYVxuICAgICAgICB9O1xuICAgIH1cblxuXG4gICAgLy8gQ29udmVyc2lvbiBGdW5jdGlvbnNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gICAgLy8gYHJnYlRvSHNsYCwgYHJnYlRvSHN2YCwgYGhzbFRvUmdiYCwgYGhzdlRvUmdiYCBtb2RpZmllZCBmcm9tOlxuICAgIC8vIDxodHRwOi8vbWppamFja3Nvbi5jb20vMjAwOC8wMi9yZ2ItdG8taHNsLWFuZC1yZ2ItdG8taHN2LWNvbG9yLW1vZGVsLWNvbnZlcnNpb24tYWxnb3JpdGhtcy1pbi1qYXZhc2NyaXB0PlxuXG4gICAgLy8gYHJnYlRvUmdiYFxuICAgIC8vIEhhbmRsZSBib3VuZHMgLyBwZXJjZW50YWdlIGNoZWNraW5nIHRvIGNvbmZvcm0gdG8gQ1NTIGNvbG9yIHNwZWNcbiAgICAvLyA8aHR0cDovL3d3dy53My5vcmcvVFIvY3NzMy1jb2xvci8+XG4gICAgLy8gKkFzc3VtZXM6KiByLCBnLCBiIGluIFswLCAyNTVdIG9yIFswLCAxXVxuICAgIC8vICpSZXR1cm5zOiogeyByLCBnLCBiIH0gaW4gWzAsIDI1NV1cbiAgICBmdW5jdGlvbiByZ2JUb1JnYihyLCBnLCBiKXtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHI6IGJvdW5kMDEociwgMjU1KSAqIDI1NSxcbiAgICAgICAgICAgIGc6IGJvdW5kMDEoZywgMjU1KSAqIDI1NSxcbiAgICAgICAgICAgIGI6IGJvdW5kMDEoYiwgMjU1KSAqIDI1NVxuICAgICAgICB9O1xuICAgIH1cblxuICAgIC8vIGByZ2JUb0hzbGBcbiAgICAvLyBDb252ZXJ0cyBhbiBSR0IgY29sb3IgdmFsdWUgdG8gSFNMLlxuICAgIC8vICpBc3N1bWVzOiogciwgZywgYW5kIGIgYXJlIGNvbnRhaW5lZCBpbiBbMCwgMjU1XSBvciBbMCwgMV1cbiAgICAvLyAqUmV0dXJuczoqIHsgaCwgcywgbCB9IGluIFswLDFdXG4gICAgZnVuY3Rpb24gcmdiVG9Ic2wociwgZywgYikge1xuXG4gICAgICAgIHIgPSBib3VuZDAxKHIsIDI1NSk7XG4gICAgICAgIGcgPSBib3VuZDAxKGcsIDI1NSk7XG4gICAgICAgIGIgPSBib3VuZDAxKGIsIDI1NSk7XG5cbiAgICAgICAgdmFyIG1heCA9IG1hdGhNYXgociwgZywgYiksIG1pbiA9IG1hdGhNaW4ociwgZywgYik7XG4gICAgICAgIHZhciBoLCBzLCBsID0gKG1heCArIG1pbikgLyAyO1xuXG4gICAgICAgIGlmKG1heCA9PSBtaW4pIHtcbiAgICAgICAgICAgIGggPSBzID0gMDsgLy8gYWNocm9tYXRpY1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIGQgPSBtYXggLSBtaW47XG4gICAgICAgICAgICBzID0gbCA+IDAuNSA/IGQgLyAoMiAtIG1heCAtIG1pbikgOiBkIC8gKG1heCArIG1pbik7XG4gICAgICAgICAgICBzd2l0Y2gobWF4KSB7XG4gICAgICAgICAgICAgICAgY2FzZSByOiBoID0gKGcgLSBiKSAvIGQgKyAoZyA8IGIgPyA2IDogMCk7IGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgZzogaCA9IChiIC0gcikgLyBkICsgMjsgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSBiOiBoID0gKHIgLSBnKSAvIGQgKyA0OyBicmVhaztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaCAvPSA2O1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHsgaDogaCwgczogcywgbDogbCB9O1xuICAgIH1cblxuICAgIC8vIGBoc2xUb1JnYmBcbiAgICAvLyBDb252ZXJ0cyBhbiBIU0wgY29sb3IgdmFsdWUgdG8gUkdCLlxuICAgIC8vICpBc3N1bWVzOiogaCBpcyBjb250YWluZWQgaW4gWzAsIDFdIG9yIFswLCAzNjBdIGFuZCBzIGFuZCBsIGFyZSBjb250YWluZWQgWzAsIDFdIG9yIFswLCAxMDBdXG4gICAgLy8gKlJldHVybnM6KiB7IHIsIGcsIGIgfSBpbiB0aGUgc2V0IFswLCAyNTVdXG4gICAgZnVuY3Rpb24gaHNsVG9SZ2IoaCwgcywgbCkge1xuICAgICAgICB2YXIgciwgZywgYjtcblxuICAgICAgICBoID0gYm91bmQwMShoLCAzNjApO1xuICAgICAgICBzID0gYm91bmQwMShzLCAxMDApO1xuICAgICAgICBsID0gYm91bmQwMShsLCAxMDApO1xuXG4gICAgICAgIGZ1bmN0aW9uIGh1ZTJyZ2IocCwgcSwgdCkge1xuICAgICAgICAgICAgaWYodCA8IDApIHQgKz0gMTtcbiAgICAgICAgICAgIGlmKHQgPiAxKSB0IC09IDE7XG4gICAgICAgICAgICBpZih0IDwgMS82KSByZXR1cm4gcCArIChxIC0gcCkgKiA2ICogdDtcbiAgICAgICAgICAgIGlmKHQgPCAxLzIpIHJldHVybiBxO1xuICAgICAgICAgICAgaWYodCA8IDIvMykgcmV0dXJuIHAgKyAocSAtIHApICogKDIvMyAtIHQpICogNjtcbiAgICAgICAgICAgIHJldHVybiBwO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYocyA9PT0gMCkge1xuICAgICAgICAgICAgciA9IGcgPSBiID0gbDsgLy8gYWNocm9tYXRpY1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgdmFyIHEgPSBsIDwgMC41ID8gbCAqICgxICsgcykgOiBsICsgcyAtIGwgKiBzO1xuICAgICAgICAgICAgdmFyIHAgPSAyICogbCAtIHE7XG4gICAgICAgICAgICByID0gaHVlMnJnYihwLCBxLCBoICsgMS8zKTtcbiAgICAgICAgICAgIGcgPSBodWUycmdiKHAsIHEsIGgpO1xuICAgICAgICAgICAgYiA9IGh1ZTJyZ2IocCwgcSwgaCAtIDEvMyk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4geyByOiByICogMjU1LCBnOiBnICogMjU1LCBiOiBiICogMjU1IH07XG4gICAgfVxuXG4gICAgLy8gYHJnYlRvSHN2YFxuICAgIC8vIENvbnZlcnRzIGFuIFJHQiBjb2xvciB2YWx1ZSB0byBIU1ZcbiAgICAvLyAqQXNzdW1lczoqIHIsIGcsIGFuZCBiIGFyZSBjb250YWluZWQgaW4gdGhlIHNldCBbMCwgMjU1XSBvciBbMCwgMV1cbiAgICAvLyAqUmV0dXJuczoqIHsgaCwgcywgdiB9IGluIFswLDFdXG4gICAgZnVuY3Rpb24gcmdiVG9Ic3YociwgZywgYikge1xuXG4gICAgICAgIHIgPSBib3VuZDAxKHIsIDI1NSk7XG4gICAgICAgIGcgPSBib3VuZDAxKGcsIDI1NSk7XG4gICAgICAgIGIgPSBib3VuZDAxKGIsIDI1NSk7XG5cbiAgICAgICAgdmFyIG1heCA9IG1hdGhNYXgociwgZywgYiksIG1pbiA9IG1hdGhNaW4ociwgZywgYik7XG4gICAgICAgIHZhciBoLCBzLCB2ID0gbWF4O1xuXG4gICAgICAgIHZhciBkID0gbWF4IC0gbWluO1xuICAgICAgICBzID0gbWF4ID09PSAwID8gMCA6IGQgLyBtYXg7XG5cbiAgICAgICAgaWYobWF4ID09IG1pbikge1xuICAgICAgICAgICAgaCA9IDA7IC8vIGFjaHJvbWF0aWNcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgIHN3aXRjaChtYXgpIHtcbiAgICAgICAgICAgICAgICBjYXNlIHI6IGggPSAoZyAtIGIpIC8gZCArIChnIDwgYiA/IDYgOiAwKTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSBnOiBoID0gKGIgLSByKSAvIGQgKyAyOyBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlIGI6IGggPSAociAtIGcpIC8gZCArIDQ7IGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaCAvPSA2O1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB7IGg6IGgsIHM6IHMsIHY6IHYgfTtcbiAgICB9XG5cbiAgICAvLyBgaHN2VG9SZ2JgXG4gICAgLy8gQ29udmVydHMgYW4gSFNWIGNvbG9yIHZhbHVlIHRvIFJHQi5cbiAgICAvLyAqQXNzdW1lczoqIGggaXMgY29udGFpbmVkIGluIFswLCAxXSBvciBbMCwgMzYwXSBhbmQgcyBhbmQgdiBhcmUgY29udGFpbmVkIGluIFswLCAxXSBvciBbMCwgMTAwXVxuICAgIC8vICpSZXR1cm5zOiogeyByLCBnLCBiIH0gaW4gdGhlIHNldCBbMCwgMjU1XVxuICAgICBmdW5jdGlvbiBoc3ZUb1JnYihoLCBzLCB2KSB7XG5cbiAgICAgICAgaCA9IGJvdW5kMDEoaCwgMzYwKSAqIDY7XG4gICAgICAgIHMgPSBib3VuZDAxKHMsIDEwMCk7XG4gICAgICAgIHYgPSBib3VuZDAxKHYsIDEwMCk7XG5cbiAgICAgICAgdmFyIGkgPSBtYXRoLmZsb29yKGgpLFxuICAgICAgICAgICAgZiA9IGggLSBpLFxuICAgICAgICAgICAgcCA9IHYgKiAoMSAtIHMpLFxuICAgICAgICAgICAgcSA9IHYgKiAoMSAtIGYgKiBzKSxcbiAgICAgICAgICAgIHQgPSB2ICogKDEgLSAoMSAtIGYpICogcyksXG4gICAgICAgICAgICBtb2QgPSBpICUgNixcbiAgICAgICAgICAgIHIgPSBbdiwgcSwgcCwgcCwgdCwgdl1bbW9kXSxcbiAgICAgICAgICAgIGcgPSBbdCwgdiwgdiwgcSwgcCwgcF1bbW9kXSxcbiAgICAgICAgICAgIGIgPSBbcCwgcCwgdCwgdiwgdiwgcV1bbW9kXTtcblxuICAgICAgICByZXR1cm4geyByOiByICogMjU1LCBnOiBnICogMjU1LCBiOiBiICogMjU1IH07XG4gICAgfVxuXG4gICAgLy8gYHJnYlRvSGV4YFxuICAgIC8vIENvbnZlcnRzIGFuIFJHQiBjb2xvciB0byBoZXhcbiAgICAvLyBBc3N1bWVzIHIsIGcsIGFuZCBiIGFyZSBjb250YWluZWQgaW4gdGhlIHNldCBbMCwgMjU1XVxuICAgIC8vIFJldHVybnMgYSAzIG9yIDYgY2hhcmFjdGVyIGhleFxuICAgIGZ1bmN0aW9uIHJnYlRvSGV4KHIsIGcsIGIsIGFsbG93M0NoYXIpIHtcblxuICAgICAgICB2YXIgaGV4ID0gW1xuICAgICAgICAgICAgcGFkMihtYXRoUm91bmQocikudG9TdHJpbmcoMTYpKSxcbiAgICAgICAgICAgIHBhZDIobWF0aFJvdW5kKGcpLnRvU3RyaW5nKDE2KSksXG4gICAgICAgICAgICBwYWQyKG1hdGhSb3VuZChiKS50b1N0cmluZygxNikpXG4gICAgICAgIF07XG5cbiAgICAgICAgLy8gUmV0dXJuIGEgMyBjaGFyYWN0ZXIgaGV4IGlmIHBvc3NpYmxlXG4gICAgICAgIGlmIChhbGxvdzNDaGFyICYmIGhleFswXS5jaGFyQXQoMCkgPT0gaGV4WzBdLmNoYXJBdCgxKSAmJiBoZXhbMV0uY2hhckF0KDApID09IGhleFsxXS5jaGFyQXQoMSkgJiYgaGV4WzJdLmNoYXJBdCgwKSA9PSBoZXhbMl0uY2hhckF0KDEpKSB7XG4gICAgICAgICAgICByZXR1cm4gaGV4WzBdLmNoYXJBdCgwKSArIGhleFsxXS5jaGFyQXQoMCkgKyBoZXhbMl0uY2hhckF0KDApO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGhleC5qb2luKFwiXCIpO1xuICAgIH1cbiAgICAgICAgLy8gYHJnYmFUb0hleGBcbiAgICAgICAgLy8gQ29udmVydHMgYW4gUkdCQSBjb2xvciBwbHVzIGFscGhhIHRyYW5zcGFyZW5jeSB0byBoZXhcbiAgICAgICAgLy8gQXNzdW1lcyByLCBnLCBiIGFuZCBhIGFyZSBjb250YWluZWQgaW4gdGhlIHNldCBbMCwgMjU1XVxuICAgICAgICAvLyBSZXR1cm5zIGFuIDggY2hhcmFjdGVyIGhleFxuICAgICAgICBmdW5jdGlvbiByZ2JhVG9IZXgociwgZywgYiwgYSkge1xuXG4gICAgICAgICAgICB2YXIgaGV4ID0gW1xuICAgICAgICAgICAgICAgIHBhZDIoY29udmVydERlY2ltYWxUb0hleChhKSksXG4gICAgICAgICAgICAgICAgcGFkMihtYXRoUm91bmQocikudG9TdHJpbmcoMTYpKSxcbiAgICAgICAgICAgICAgICBwYWQyKG1hdGhSb3VuZChnKS50b1N0cmluZygxNikpLFxuICAgICAgICAgICAgICAgIHBhZDIobWF0aFJvdW5kKGIpLnRvU3RyaW5nKDE2KSlcbiAgICAgICAgICAgIF07XG5cbiAgICAgICAgICAgIHJldHVybiBoZXguam9pbihcIlwiKTtcbiAgICAgICAgfVxuXG4gICAgLy8gYGVxdWFsc2BcbiAgICAvLyBDYW4gYmUgY2FsbGVkIHdpdGggYW55IHRpbnljb2xvciBpbnB1dFxuICAgIHRpbnljb2xvci5lcXVhbHMgPSBmdW5jdGlvbiAoY29sb3IxLCBjb2xvcjIpIHtcbiAgICAgICAgaWYgKCFjb2xvcjEgfHwgIWNvbG9yMikgeyByZXR1cm4gZmFsc2U7IH1cbiAgICAgICAgcmV0dXJuIHRpbnljb2xvcihjb2xvcjEpLnRvUmdiU3RyaW5nKCkgPT0gdGlueWNvbG9yKGNvbG9yMikudG9SZ2JTdHJpbmcoKTtcbiAgICB9O1xuICAgIHRpbnljb2xvci5yYW5kb20gPSBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRpbnljb2xvci5mcm9tUmF0aW8oe1xuICAgICAgICAgICAgcjogbWF0aFJhbmRvbSgpLFxuICAgICAgICAgICAgZzogbWF0aFJhbmRvbSgpLFxuICAgICAgICAgICAgYjogbWF0aFJhbmRvbSgpXG4gICAgICAgIH0pO1xuICAgIH07XG5cblxuICAgIC8vIE1vZGlmaWNhdGlvbiBGdW5jdGlvbnNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gVGhhbmtzIHRvIGxlc3MuanMgZm9yIHNvbWUgb2YgdGhlIGJhc2ljcyBoZXJlXG4gICAgLy8gPGh0dHBzOi8vZ2l0aHViLmNvbS9jbG91ZGhlYWQvbGVzcy5qcy9ibG9iL21hc3Rlci9saWIvbGVzcy9mdW5jdGlvbnMuanM+XG5cbiAgICBmdW5jdGlvbiBkZXNhdHVyYXRlKGNvbG9yLCBhbW91bnQpIHtcbiAgICAgICAgYW1vdW50ID0gKGFtb3VudCA9PT0gMCkgPyAwIDogKGFtb3VudCB8fCAxMCk7XG4gICAgICAgIHZhciBoc2wgPSB0aW55Y29sb3IoY29sb3IpLnRvSHNsKCk7XG4gICAgICAgIGhzbC5zIC09IGFtb3VudCAvIDEwMDtcbiAgICAgICAgaHNsLnMgPSBjbGFtcDAxKGhzbC5zKTtcbiAgICAgICAgcmV0dXJuIHRpbnljb2xvcihoc2wpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIHNhdHVyYXRlKGNvbG9yLCBhbW91bnQpIHtcbiAgICAgICAgYW1vdW50ID0gKGFtb3VudCA9PT0gMCkgPyAwIDogKGFtb3VudCB8fCAxMCk7XG4gICAgICAgIHZhciBoc2wgPSB0aW55Y29sb3IoY29sb3IpLnRvSHNsKCk7XG4gICAgICAgIGhzbC5zICs9IGFtb3VudCAvIDEwMDtcbiAgICAgICAgaHNsLnMgPSBjbGFtcDAxKGhzbC5zKTtcbiAgICAgICAgcmV0dXJuIHRpbnljb2xvcihoc2wpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGdyZXlzY2FsZShjb2xvcikge1xuICAgICAgICByZXR1cm4gdGlueWNvbG9yKGNvbG9yKS5kZXNhdHVyYXRlKDEwMCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbGlnaHRlbiAoY29sb3IsIGFtb3VudCkge1xuICAgICAgICBhbW91bnQgPSAoYW1vdW50ID09PSAwKSA/IDAgOiAoYW1vdW50IHx8IDEwKTtcbiAgICAgICAgdmFyIGhzbCA9IHRpbnljb2xvcihjb2xvcikudG9Ic2woKTtcbiAgICAgICAgaHNsLmwgKz0gYW1vdW50IC8gMTAwO1xuICAgICAgICBoc2wubCA9IGNsYW1wMDEoaHNsLmwpO1xuICAgICAgICByZXR1cm4gdGlueWNvbG9yKGhzbCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYnJpZ2h0ZW4oY29sb3IsIGFtb3VudCkge1xuICAgICAgICBhbW91bnQgPSAoYW1vdW50ID09PSAwKSA/IDAgOiAoYW1vdW50IHx8IDEwKTtcbiAgICAgICAgdmFyIHJnYiA9IHRpbnljb2xvcihjb2xvcikudG9SZ2IoKTtcbiAgICAgICAgcmdiLnIgPSBtYXRoTWF4KDAsIG1hdGhNaW4oMjU1LCByZ2IuciAtIG1hdGhSb3VuZCgyNTUgKiAtIChhbW91bnQgLyAxMDApKSkpO1xuICAgICAgICByZ2IuZyA9IG1hdGhNYXgoMCwgbWF0aE1pbigyNTUsIHJnYi5nIC0gbWF0aFJvdW5kKDI1NSAqIC0gKGFtb3VudCAvIDEwMCkpKSk7XG4gICAgICAgIHJnYi5iID0gbWF0aE1heCgwLCBtYXRoTWluKDI1NSwgcmdiLmIgLSBtYXRoUm91bmQoMjU1ICogLSAoYW1vdW50IC8gMTAwKSkpKTtcbiAgICAgICAgcmV0dXJuIHRpbnljb2xvcihyZ2IpO1xuICAgIH1cblxuICAgIGZ1bmN0aW9uIGRhcmtlbiAoY29sb3IsIGFtb3VudCkge1xuICAgICAgICBhbW91bnQgPSAoYW1vdW50ID09PSAwKSA/IDAgOiAoYW1vdW50IHx8IDEwKTtcbiAgICAgICAgdmFyIGhzbCA9IHRpbnljb2xvcihjb2xvcikudG9Ic2woKTtcbiAgICAgICAgaHNsLmwgLT0gYW1vdW50IC8gMTAwO1xuICAgICAgICBoc2wubCA9IGNsYW1wMDEoaHNsLmwpO1xuICAgICAgICByZXR1cm4gdGlueWNvbG9yKGhzbCk7XG4gICAgfVxuXG4gICAgLy8gU3BpbiB0YWtlcyBhIHBvc2l0aXZlIG9yIG5lZ2F0aXZlIGFtb3VudCB3aXRoaW4gWy0zNjAsIDM2MF0gaW5kaWNhdGluZyB0aGUgY2hhbmdlIG9mIGh1ZS5cbiAgICAvLyBWYWx1ZXMgb3V0c2lkZSBvZiB0aGlzIHJhbmdlIHdpbGwgYmUgd3JhcHBlZCBpbnRvIHRoaXMgcmFuZ2UuXG4gICAgZnVuY3Rpb24gc3Bpbihjb2xvciwgYW1vdW50KSB7XG4gICAgICAgIHZhciBoc2wgPSB0aW55Y29sb3IoY29sb3IpLnRvSHNsKCk7XG4gICAgICAgIHZhciBodWUgPSAobWF0aFJvdW5kKGhzbC5oKSArIGFtb3VudCkgJSAzNjA7XG4gICAgICAgIGhzbC5oID0gaHVlIDwgMCA/IDM2MCArIGh1ZSA6IGh1ZTtcbiAgICAgICAgcmV0dXJuIHRpbnljb2xvcihoc2wpO1xuICAgIH1cblxuICAgIC8vIENvbWJpbmF0aW9uIEZ1bmN0aW9uc1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuICAgIC8vIFRoYW5rcyB0byBqUXVlcnkgeENvbG9yIGZvciBzb21lIG9mIHRoZSBpZGVhcyBiZWhpbmQgdGhlc2VcbiAgICAvLyA8aHR0cHM6Ly9naXRodWIuY29tL2luZnVzaW9uL2pRdWVyeS14Y29sb3IvYmxvYi9tYXN0ZXIvanF1ZXJ5Lnhjb2xvci5qcz5cblxuICAgIGZ1bmN0aW9uIGNvbXBsZW1lbnQoY29sb3IpIHtcbiAgICAgICAgdmFyIGhzbCA9IHRpbnljb2xvcihjb2xvcikudG9Ic2woKTtcbiAgICAgICAgaHNsLmggPSAoaHNsLmggKyAxODApICUgMzYwO1xuICAgICAgICByZXR1cm4gdGlueWNvbG9yKGhzbCk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdHJpYWQoY29sb3IpIHtcbiAgICAgICAgdmFyIGhzbCA9IHRpbnljb2xvcihjb2xvcikudG9Ic2woKTtcbiAgICAgICAgdmFyIGggPSBoc2wuaDtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIHRpbnljb2xvcihjb2xvciksXG4gICAgICAgICAgICB0aW55Y29sb3IoeyBoOiAoaCArIDEyMCkgJSAzNjAsIHM6IGhzbC5zLCBsOiBoc2wubCB9KSxcbiAgICAgICAgICAgIHRpbnljb2xvcih7IGg6IChoICsgMjQwKSAlIDM2MCwgczogaHNsLnMsIGw6IGhzbC5sIH0pXG4gICAgICAgIF07XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gdGV0cmFkKGNvbG9yKSB7XG4gICAgICAgIHZhciBoc2wgPSB0aW55Y29sb3IoY29sb3IpLnRvSHNsKCk7XG4gICAgICAgIHZhciBoID0gaHNsLmg7XG4gICAgICAgIHJldHVybiBbXG4gICAgICAgICAgICB0aW55Y29sb3IoY29sb3IpLFxuICAgICAgICAgICAgdGlueWNvbG9yKHsgaDogKGggKyA5MCkgJSAzNjAsIHM6IGhzbC5zLCBsOiBoc2wubCB9KSxcbiAgICAgICAgICAgIHRpbnljb2xvcih7IGg6IChoICsgMTgwKSAlIDM2MCwgczogaHNsLnMsIGw6IGhzbC5sIH0pLFxuICAgICAgICAgICAgdGlueWNvbG9yKHsgaDogKGggKyAyNzApICUgMzYwLCBzOiBoc2wucywgbDogaHNsLmwgfSlcbiAgICAgICAgXTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzcGxpdGNvbXBsZW1lbnQoY29sb3IpIHtcbiAgICAgICAgdmFyIGhzbCA9IHRpbnljb2xvcihjb2xvcikudG9Ic2woKTtcbiAgICAgICAgdmFyIGggPSBoc2wuaDtcbiAgICAgICAgcmV0dXJuIFtcbiAgICAgICAgICAgIHRpbnljb2xvcihjb2xvciksXG4gICAgICAgICAgICB0aW55Y29sb3IoeyBoOiAoaCArIDcyKSAlIDM2MCwgczogaHNsLnMsIGw6IGhzbC5sfSksXG4gICAgICAgICAgICB0aW55Y29sb3IoeyBoOiAoaCArIDIxNikgJSAzNjAsIHM6IGhzbC5zLCBsOiBoc2wubH0pXG4gICAgICAgIF07XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gYW5hbG9nb3VzKGNvbG9yLCByZXN1bHRzLCBzbGljZXMpIHtcbiAgICAgICAgcmVzdWx0cyA9IHJlc3VsdHMgfHwgNjtcbiAgICAgICAgc2xpY2VzID0gc2xpY2VzIHx8IDMwO1xuXG4gICAgICAgIHZhciBoc2wgPSB0aW55Y29sb3IoY29sb3IpLnRvSHNsKCk7XG4gICAgICAgIHZhciBwYXJ0ID0gMzYwIC8gc2xpY2VzO1xuICAgICAgICB2YXIgcmV0ID0gW3Rpbnljb2xvcihjb2xvcildO1xuXG4gICAgICAgIGZvciAoaHNsLmggPSAoKGhzbC5oIC0gKHBhcnQgKiByZXN1bHRzID4+IDEpKSArIDcyMCkgJSAzNjA7IC0tcmVzdWx0czsgKSB7XG4gICAgICAgICAgICBoc2wuaCA9IChoc2wuaCArIHBhcnQpICUgMzYwO1xuICAgICAgICAgICAgcmV0LnB1c2godGlueWNvbG9yKGhzbCkpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiByZXQ7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gbW9ub2Nocm9tYXRpYyhjb2xvciwgcmVzdWx0cykge1xuICAgICAgICByZXN1bHRzID0gcmVzdWx0cyB8fCA2O1xuICAgICAgICB2YXIgaHN2ID0gdGlueWNvbG9yKGNvbG9yKS50b0hzdigpO1xuICAgICAgICB2YXIgaCA9IGhzdi5oLCBzID0gaHN2LnMsIHYgPSBoc3YudjtcbiAgICAgICAgdmFyIHJldCA9IFtdO1xuICAgICAgICB2YXIgbW9kaWZpY2F0aW9uID0gMSAvIHJlc3VsdHM7XG5cbiAgICAgICAgd2hpbGUgKHJlc3VsdHMtLSkge1xuICAgICAgICAgICAgcmV0LnB1c2godGlueWNvbG9yKHsgaDogaCwgczogcywgdjogdn0pKTtcbiAgICAgICAgICAgIHYgPSAodiArIG1vZGlmaWNhdGlvbikgJSAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHJldDtcbiAgICB9XG5cbiAgICAvLyBVdGlsaXR5IEZ1bmN0aW9uc1xuICAgIC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4gICAgdGlueWNvbG9yLm1peCA9IGZ1bmN0aW9uKGNvbG9yMSwgY29sb3IyLCBhbW91bnQpIHtcbiAgICAgICAgYW1vdW50ID0gKGFtb3VudCA9PT0gMCkgPyAwIDogKGFtb3VudCB8fCA1MCk7XG5cbiAgICAgICAgdmFyIHJnYjEgPSB0aW55Y29sb3IoY29sb3IxKS50b1JnYigpO1xuICAgICAgICB2YXIgcmdiMiA9IHRpbnljb2xvcihjb2xvcjIpLnRvUmdiKCk7XG5cbiAgICAgICAgdmFyIHAgPSBhbW91bnQgLyAxMDA7XG4gICAgICAgIHZhciB3ID0gcCAqIDIgLSAxO1xuICAgICAgICB2YXIgYSA9IHJnYjIuYSAtIHJnYjEuYTtcblxuICAgICAgICB2YXIgdzE7XG5cbiAgICAgICAgaWYgKHcgKiBhID09IC0xKSB7XG4gICAgICAgICAgICB3MSA9IHc7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB3MSA9ICh3ICsgYSkgLyAoMSArIHcgKiBhKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHcxID0gKHcxICsgMSkgLyAyO1xuXG4gICAgICAgIHZhciB3MiA9IDEgLSB3MTtcblxuICAgICAgICB2YXIgcmdiYSA9IHtcbiAgICAgICAgICAgIHI6IHJnYjIuciAqIHcxICsgcmdiMS5yICogdzIsXG4gICAgICAgICAgICBnOiByZ2IyLmcgKiB3MSArIHJnYjEuZyAqIHcyLFxuICAgICAgICAgICAgYjogcmdiMi5iICogdzEgKyByZ2IxLmIgKiB3MixcbiAgICAgICAgICAgIGE6IHJnYjIuYSAqIHAgICsgcmdiMS5hICogKDEgLSBwKVxuICAgICAgICB9O1xuXG4gICAgICAgIHJldHVybiB0aW55Y29sb3IocmdiYSk7XG4gICAgfTtcblxuXG4gICAgLy8gUmVhZGFiaWxpdHkgRnVuY3Rpb25zXG4gICAgLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4gICAgLy8gPGh0dHA6Ly93d3cudzMub3JnL1RSL0FFUlQjY29sb3ItY29udHJhc3Q+XG5cbiAgICAvLyBgcmVhZGFiaWxpdHlgXG4gICAgLy8gQW5hbHl6ZSB0aGUgMiBjb2xvcnMgYW5kIHJldHVybnMgYW4gb2JqZWN0IHdpdGggdGhlIGZvbGxvd2luZyBwcm9wZXJ0aWVzOlxuICAgIC8vICAgIGBicmlnaHRuZXNzYDogZGlmZmVyZW5jZSBpbiBicmlnaHRuZXNzIGJldHdlZW4gdGhlIHR3byBjb2xvcnNcbiAgICAvLyAgICBgY29sb3JgOiBkaWZmZXJlbmNlIGluIGNvbG9yL2h1ZSBiZXR3ZWVuIHRoZSB0d28gY29sb3JzXG4gICAgdGlueWNvbG9yLnJlYWRhYmlsaXR5ID0gZnVuY3Rpb24oY29sb3IxLCBjb2xvcjIpIHtcbiAgICAgICAgdmFyIGMxID0gdGlueWNvbG9yKGNvbG9yMSk7XG4gICAgICAgIHZhciBjMiA9IHRpbnljb2xvcihjb2xvcjIpO1xuICAgICAgICB2YXIgcmdiMSA9IGMxLnRvUmdiKCk7XG4gICAgICAgIHZhciByZ2IyID0gYzIudG9SZ2IoKTtcbiAgICAgICAgdmFyIGJyaWdodG5lc3NBID0gYzEuZ2V0QnJpZ2h0bmVzcygpO1xuICAgICAgICB2YXIgYnJpZ2h0bmVzc0IgPSBjMi5nZXRCcmlnaHRuZXNzKCk7XG4gICAgICAgIHZhciBjb2xvckRpZmYgPSAoXG4gICAgICAgICAgICBNYXRoLm1heChyZ2IxLnIsIHJnYjIucikgLSBNYXRoLm1pbihyZ2IxLnIsIHJnYjIucikgK1xuICAgICAgICAgICAgTWF0aC5tYXgocmdiMS5nLCByZ2IyLmcpIC0gTWF0aC5taW4ocmdiMS5nLCByZ2IyLmcpICtcbiAgICAgICAgICAgIE1hdGgubWF4KHJnYjEuYiwgcmdiMi5iKSAtIE1hdGgubWluKHJnYjEuYiwgcmdiMi5iKVxuICAgICAgICApO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBicmlnaHRuZXNzOiBNYXRoLmFicyhicmlnaHRuZXNzQSAtIGJyaWdodG5lc3NCKSxcbiAgICAgICAgICAgIGNvbG9yOiBjb2xvckRpZmZcbiAgICAgICAgfTtcbiAgICB9O1xuXG4gICAgLy8gYHJlYWRhYmxlYFxuICAgIC8vIGh0dHA6Ly93d3cudzMub3JnL1RSL0FFUlQjY29sb3ItY29udHJhc3RcbiAgICAvLyBFbnN1cmUgdGhhdCBmb3JlZ3JvdW5kIGFuZCBiYWNrZ3JvdW5kIGNvbG9yIGNvbWJpbmF0aW9ucyBwcm92aWRlIHN1ZmZpY2llbnQgY29udHJhc3QuXG4gICAgLy8gKkV4YW1wbGUqXG4gICAgLy8gICAgdGlueWNvbG9yLmlzUmVhZGFibGUoXCIjMDAwXCIsIFwiIzExMVwiKSA9PiBmYWxzZVxuICAgIHRpbnljb2xvci5pc1JlYWRhYmxlID0gZnVuY3Rpb24oY29sb3IxLCBjb2xvcjIpIHtcbiAgICAgICAgdmFyIHJlYWRhYmlsaXR5ID0gdGlueWNvbG9yLnJlYWRhYmlsaXR5KGNvbG9yMSwgY29sb3IyKTtcbiAgICAgICAgcmV0dXJuIHJlYWRhYmlsaXR5LmJyaWdodG5lc3MgPiAxMjUgJiYgcmVhZGFiaWxpdHkuY29sb3IgPiA1MDA7XG4gICAgfTtcblxuICAgIC8vIGBtb3N0UmVhZGFibGVgXG4gICAgLy8gR2l2ZW4gYSBiYXNlIGNvbG9yIGFuZCBhIGxpc3Qgb2YgcG9zc2libGUgZm9yZWdyb3VuZCBvciBiYWNrZ3JvdW5kXG4gICAgLy8gY29sb3JzIGZvciB0aGF0IGJhc2UsIHJldHVybnMgdGhlIG1vc3QgcmVhZGFibGUgY29sb3IuXG4gICAgLy8gKkV4YW1wbGUqXG4gICAgLy8gICAgdGlueWNvbG9yLm1vc3RSZWFkYWJsZShcIiMxMjNcIiwgW1wiI2ZmZlwiLCBcIiMwMDBcIl0pID0+IFwiIzAwMFwiXG4gICAgdGlueWNvbG9yLm1vc3RSZWFkYWJsZSA9IGZ1bmN0aW9uKGJhc2VDb2xvciwgY29sb3JMaXN0KSB7XG4gICAgICAgIHZhciBiZXN0Q29sb3IgPSBudWxsO1xuICAgICAgICB2YXIgYmVzdFNjb3JlID0gMDtcbiAgICAgICAgdmFyIGJlc3RJc1JlYWRhYmxlID0gZmFsc2U7XG4gICAgICAgIGZvciAodmFyIGk9MDsgaSA8IGNvbG9yTGlzdC5sZW5ndGg7IGkrKykge1xuXG4gICAgICAgICAgICAvLyBXZSBub3JtYWxpemUgYm90aCBhcm91bmQgdGhlIFwiYWNjZXB0YWJsZVwiIGJyZWFraW5nIHBvaW50LFxuICAgICAgICAgICAgLy8gYnV0IHJhbmsgYnJpZ2h0bmVzcyBjb25zdHJhc3QgaGlnaGVyIHRoYW4gaHVlLlxuXG4gICAgICAgICAgICB2YXIgcmVhZGFiaWxpdHkgPSB0aW55Y29sb3IucmVhZGFiaWxpdHkoYmFzZUNvbG9yLCBjb2xvckxpc3RbaV0pO1xuICAgICAgICAgICAgdmFyIHJlYWRhYmxlID0gcmVhZGFiaWxpdHkuYnJpZ2h0bmVzcyA+IDEyNSAmJiByZWFkYWJpbGl0eS5jb2xvciA+IDUwMDtcbiAgICAgICAgICAgIHZhciBzY29yZSA9IDMgKiAocmVhZGFiaWxpdHkuYnJpZ2h0bmVzcyAvIDEyNSkgKyAocmVhZGFiaWxpdHkuY29sb3IgLyA1MDApO1xuXG4gICAgICAgICAgICBpZiAoKHJlYWRhYmxlICYmICEgYmVzdElzUmVhZGFibGUpIHx8XG4gICAgICAgICAgICAgICAgKHJlYWRhYmxlICYmIGJlc3RJc1JlYWRhYmxlICYmIHNjb3JlID4gYmVzdFNjb3JlKSB8fFxuICAgICAgICAgICAgICAgICgoISByZWFkYWJsZSkgJiYgKCEgYmVzdElzUmVhZGFibGUpICYmIHNjb3JlID4gYmVzdFNjb3JlKSkge1xuICAgICAgICAgICAgICAgIGJlc3RJc1JlYWRhYmxlID0gcmVhZGFibGU7XG4gICAgICAgICAgICAgICAgYmVzdFNjb3JlID0gc2NvcmU7XG4gICAgICAgICAgICAgICAgYmVzdENvbG9yID0gdGlueWNvbG9yKGNvbG9yTGlzdFtpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGJlc3RDb2xvcjtcbiAgICB9O1xuXG5cbiAgICAvLyBCaWcgTGlzdCBvZiBDb2xvcnNcbiAgICAvLyAtLS0tLS0tLS0tLS0tLS0tLS1cbiAgICAvLyA8aHR0cDovL3d3dy53My5vcmcvVFIvY3NzMy1jb2xvci8jc3ZnLWNvbG9yPlxuICAgIHZhciBuYW1lcyA9IHRpbnljb2xvci5uYW1lcyA9IHtcbiAgICAgICAgYWxpY2VibHVlOiBcImYwZjhmZlwiLFxuICAgICAgICBhbnRpcXVld2hpdGU6IFwiZmFlYmQ3XCIsXG4gICAgICAgIGFxdWE6IFwiMGZmXCIsXG4gICAgICAgIGFxdWFtYXJpbmU6IFwiN2ZmZmQ0XCIsXG4gICAgICAgIGF6dXJlOiBcImYwZmZmZlwiLFxuICAgICAgICBiZWlnZTogXCJmNWY1ZGNcIixcbiAgICAgICAgYmlzcXVlOiBcImZmZTRjNFwiLFxuICAgICAgICBibGFjazogXCIwMDBcIixcbiAgICAgICAgYmxhbmNoZWRhbG1vbmQ6IFwiZmZlYmNkXCIsXG4gICAgICAgIGJsdWU6IFwiMDBmXCIsXG4gICAgICAgIGJsdWV2aW9sZXQ6IFwiOGEyYmUyXCIsXG4gICAgICAgIGJyb3duOiBcImE1MmEyYVwiLFxuICAgICAgICBidXJseXdvb2Q6IFwiZGViODg3XCIsXG4gICAgICAgIGJ1cm50c2llbm5hOiBcImVhN2U1ZFwiLFxuICAgICAgICBjYWRldGJsdWU6IFwiNWY5ZWEwXCIsXG4gICAgICAgIGNoYXJ0cmV1c2U6IFwiN2ZmZjAwXCIsXG4gICAgICAgIGNob2NvbGF0ZTogXCJkMjY5MWVcIixcbiAgICAgICAgY29yYWw6IFwiZmY3ZjUwXCIsXG4gICAgICAgIGNvcm5mbG93ZXJibHVlOiBcIjY0OTVlZFwiLFxuICAgICAgICBjb3Juc2lsazogXCJmZmY4ZGNcIixcbiAgICAgICAgY3JpbXNvbjogXCJkYzE0M2NcIixcbiAgICAgICAgY3lhbjogXCIwZmZcIixcbiAgICAgICAgZGFya2JsdWU6IFwiMDAwMDhiXCIsXG4gICAgICAgIGRhcmtjeWFuOiBcIjAwOGI4YlwiLFxuICAgICAgICBkYXJrZ29sZGVucm9kOiBcImI4ODYwYlwiLFxuICAgICAgICBkYXJrZ3JheTogXCJhOWE5YTlcIixcbiAgICAgICAgZGFya2dyZWVuOiBcIjAwNjQwMFwiLFxuICAgICAgICBkYXJrZ3JleTogXCJhOWE5YTlcIixcbiAgICAgICAgZGFya2toYWtpOiBcImJkYjc2YlwiLFxuICAgICAgICBkYXJrbWFnZW50YTogXCI4YjAwOGJcIixcbiAgICAgICAgZGFya29saXZlZ3JlZW46IFwiNTU2YjJmXCIsXG4gICAgICAgIGRhcmtvcmFuZ2U6IFwiZmY4YzAwXCIsXG4gICAgICAgIGRhcmtvcmNoaWQ6IFwiOTkzMmNjXCIsXG4gICAgICAgIGRhcmtyZWQ6IFwiOGIwMDAwXCIsXG4gICAgICAgIGRhcmtzYWxtb246IFwiZTk5NjdhXCIsXG4gICAgICAgIGRhcmtzZWFncmVlbjogXCI4ZmJjOGZcIixcbiAgICAgICAgZGFya3NsYXRlYmx1ZTogXCI0ODNkOGJcIixcbiAgICAgICAgZGFya3NsYXRlZ3JheTogXCIyZjRmNGZcIixcbiAgICAgICAgZGFya3NsYXRlZ3JleTogXCIyZjRmNGZcIixcbiAgICAgICAgZGFya3R1cnF1b2lzZTogXCIwMGNlZDFcIixcbiAgICAgICAgZGFya3Zpb2xldDogXCI5NDAwZDNcIixcbiAgICAgICAgZGVlcHBpbms6IFwiZmYxNDkzXCIsXG4gICAgICAgIGRlZXBza3libHVlOiBcIjAwYmZmZlwiLFxuICAgICAgICBkaW1ncmF5OiBcIjY5Njk2OVwiLFxuICAgICAgICBkaW1ncmV5OiBcIjY5Njk2OVwiLFxuICAgICAgICBkb2RnZXJibHVlOiBcIjFlOTBmZlwiLFxuICAgICAgICBmaXJlYnJpY2s6IFwiYjIyMjIyXCIsXG4gICAgICAgIGZsb3JhbHdoaXRlOiBcImZmZmFmMFwiLFxuICAgICAgICBmb3Jlc3RncmVlbjogXCIyMjhiMjJcIixcbiAgICAgICAgZnVjaHNpYTogXCJmMGZcIixcbiAgICAgICAgZ2FpbnNib3JvOiBcImRjZGNkY1wiLFxuICAgICAgICBnaG9zdHdoaXRlOiBcImY4ZjhmZlwiLFxuICAgICAgICBnb2xkOiBcImZmZDcwMFwiLFxuICAgICAgICBnb2xkZW5yb2Q6IFwiZGFhNTIwXCIsXG4gICAgICAgIGdyYXk6IFwiODA4MDgwXCIsXG4gICAgICAgIGdyZWVuOiBcIjAwODAwMFwiLFxuICAgICAgICBncmVlbnllbGxvdzogXCJhZGZmMmZcIixcbiAgICAgICAgZ3JleTogXCI4MDgwODBcIixcbiAgICAgICAgaG9uZXlkZXc6IFwiZjBmZmYwXCIsXG4gICAgICAgIGhvdHBpbms6IFwiZmY2OWI0XCIsXG4gICAgICAgIGluZGlhbnJlZDogXCJjZDVjNWNcIixcbiAgICAgICAgaW5kaWdvOiBcIjRiMDA4MlwiLFxuICAgICAgICBpdm9yeTogXCJmZmZmZjBcIixcbiAgICAgICAga2hha2k6IFwiZjBlNjhjXCIsXG4gICAgICAgIGxhdmVuZGVyOiBcImU2ZTZmYVwiLFxuICAgICAgICBsYXZlbmRlcmJsdXNoOiBcImZmZjBmNVwiLFxuICAgICAgICBsYXduZ3JlZW46IFwiN2NmYzAwXCIsXG4gICAgICAgIGxlbW9uY2hpZmZvbjogXCJmZmZhY2RcIixcbiAgICAgICAgbGlnaHRibHVlOiBcImFkZDhlNlwiLFxuICAgICAgICBsaWdodGNvcmFsOiBcImYwODA4MFwiLFxuICAgICAgICBsaWdodGN5YW46IFwiZTBmZmZmXCIsXG4gICAgICAgIGxpZ2h0Z29sZGVucm9keWVsbG93OiBcImZhZmFkMlwiLFxuICAgICAgICBsaWdodGdyYXk6IFwiZDNkM2QzXCIsXG4gICAgICAgIGxpZ2h0Z3JlZW46IFwiOTBlZTkwXCIsXG4gICAgICAgIGxpZ2h0Z3JleTogXCJkM2QzZDNcIixcbiAgICAgICAgbGlnaHRwaW5rOiBcImZmYjZjMVwiLFxuICAgICAgICBsaWdodHNhbG1vbjogXCJmZmEwN2FcIixcbiAgICAgICAgbGlnaHRzZWFncmVlbjogXCIyMGIyYWFcIixcbiAgICAgICAgbGlnaHRza3libHVlOiBcIjg3Y2VmYVwiLFxuICAgICAgICBsaWdodHNsYXRlZ3JheTogXCI3ODlcIixcbiAgICAgICAgbGlnaHRzbGF0ZWdyZXk6IFwiNzg5XCIsXG4gICAgICAgIGxpZ2h0c3RlZWxibHVlOiBcImIwYzRkZVwiLFxuICAgICAgICBsaWdodHllbGxvdzogXCJmZmZmZTBcIixcbiAgICAgICAgbGltZTogXCIwZjBcIixcbiAgICAgICAgbGltZWdyZWVuOiBcIjMyY2QzMlwiLFxuICAgICAgICBsaW5lbjogXCJmYWYwZTZcIixcbiAgICAgICAgbWFnZW50YTogXCJmMGZcIixcbiAgICAgICAgbWFyb29uOiBcIjgwMDAwMFwiLFxuICAgICAgICBtZWRpdW1hcXVhbWFyaW5lOiBcIjY2Y2RhYVwiLFxuICAgICAgICBtZWRpdW1ibHVlOiBcIjAwMDBjZFwiLFxuICAgICAgICBtZWRpdW1vcmNoaWQ6IFwiYmE1NWQzXCIsXG4gICAgICAgIG1lZGl1bXB1cnBsZTogXCI5MzcwZGJcIixcbiAgICAgICAgbWVkaXVtc2VhZ3JlZW46IFwiM2NiMzcxXCIsXG4gICAgICAgIG1lZGl1bXNsYXRlYmx1ZTogXCI3YjY4ZWVcIixcbiAgICAgICAgbWVkaXVtc3ByaW5nZ3JlZW46IFwiMDBmYTlhXCIsXG4gICAgICAgIG1lZGl1bXR1cnF1b2lzZTogXCI0OGQxY2NcIixcbiAgICAgICAgbWVkaXVtdmlvbGV0cmVkOiBcImM3MTU4NVwiLFxuICAgICAgICBtaWRuaWdodGJsdWU6IFwiMTkxOTcwXCIsXG4gICAgICAgIG1pbnRjcmVhbTogXCJmNWZmZmFcIixcbiAgICAgICAgbWlzdHlyb3NlOiBcImZmZTRlMVwiLFxuICAgICAgICBtb2NjYXNpbjogXCJmZmU0YjVcIixcbiAgICAgICAgbmF2YWpvd2hpdGU6IFwiZmZkZWFkXCIsXG4gICAgICAgIG5hdnk6IFwiMDAwMDgwXCIsXG4gICAgICAgIG9sZGxhY2U6IFwiZmRmNWU2XCIsXG4gICAgICAgIG9saXZlOiBcIjgwODAwMFwiLFxuICAgICAgICBvbGl2ZWRyYWI6IFwiNmI4ZTIzXCIsXG4gICAgICAgIG9yYW5nZTogXCJmZmE1MDBcIixcbiAgICAgICAgb3JhbmdlcmVkOiBcImZmNDUwMFwiLFxuICAgICAgICBvcmNoaWQ6IFwiZGE3MGQ2XCIsXG4gICAgICAgIHBhbGVnb2xkZW5yb2Q6IFwiZWVlOGFhXCIsXG4gICAgICAgIHBhbGVncmVlbjogXCI5OGZiOThcIixcbiAgICAgICAgcGFsZXR1cnF1b2lzZTogXCJhZmVlZWVcIixcbiAgICAgICAgcGFsZXZpb2xldHJlZDogXCJkYjcwOTNcIixcbiAgICAgICAgcGFwYXlhd2hpcDogXCJmZmVmZDVcIixcbiAgICAgICAgcGVhY2hwdWZmOiBcImZmZGFiOVwiLFxuICAgICAgICBwZXJ1OiBcImNkODUzZlwiLFxuICAgICAgICBwaW5rOiBcImZmYzBjYlwiLFxuICAgICAgICBwbHVtOiBcImRkYTBkZFwiLFxuICAgICAgICBwb3dkZXJibHVlOiBcImIwZTBlNlwiLFxuICAgICAgICBwdXJwbGU6IFwiODAwMDgwXCIsXG4gICAgICAgIHJlYmVjY2FwdXJwbGU6IFwiNjYzMzk5XCIsXG4gICAgICAgIHJlZDogXCJmMDBcIixcbiAgICAgICAgcm9zeWJyb3duOiBcImJjOGY4ZlwiLFxuICAgICAgICByb3lhbGJsdWU6IFwiNDE2OWUxXCIsXG4gICAgICAgIHNhZGRsZWJyb3duOiBcIjhiNDUxM1wiLFxuICAgICAgICBzYWxtb246IFwiZmE4MDcyXCIsXG4gICAgICAgIHNhbmR5YnJvd246IFwiZjRhNDYwXCIsXG4gICAgICAgIHNlYWdyZWVuOiBcIjJlOGI1N1wiLFxuICAgICAgICBzZWFzaGVsbDogXCJmZmY1ZWVcIixcbiAgICAgICAgc2llbm5hOiBcImEwNTIyZFwiLFxuICAgICAgICBzaWx2ZXI6IFwiYzBjMGMwXCIsXG4gICAgICAgIHNreWJsdWU6IFwiODdjZWViXCIsXG4gICAgICAgIHNsYXRlYmx1ZTogXCI2YTVhY2RcIixcbiAgICAgICAgc2xhdGVncmF5OiBcIjcwODA5MFwiLFxuICAgICAgICBzbGF0ZWdyZXk6IFwiNzA4MDkwXCIsXG4gICAgICAgIHNub3c6IFwiZmZmYWZhXCIsXG4gICAgICAgIHNwcmluZ2dyZWVuOiBcIjAwZmY3ZlwiLFxuICAgICAgICBzdGVlbGJsdWU6IFwiNDY4MmI0XCIsXG4gICAgICAgIHRhbjogXCJkMmI0OGNcIixcbiAgICAgICAgdGVhbDogXCIwMDgwODBcIixcbiAgICAgICAgdGhpc3RsZTogXCJkOGJmZDhcIixcbiAgICAgICAgdG9tYXRvOiBcImZmNjM0N1wiLFxuICAgICAgICB0dXJxdW9pc2U6IFwiNDBlMGQwXCIsXG4gICAgICAgIHZpb2xldDogXCJlZTgyZWVcIixcbiAgICAgICAgd2hlYXQ6IFwiZjVkZWIzXCIsXG4gICAgICAgIHdoaXRlOiBcImZmZlwiLFxuICAgICAgICB3aGl0ZXNtb2tlOiBcImY1ZjVmNVwiLFxuICAgICAgICB5ZWxsb3c6IFwiZmYwXCIsXG4gICAgICAgIHllbGxvd2dyZWVuOiBcIjlhY2QzMlwiXG4gICAgfTtcblxuICAgIC8vIE1ha2UgaXQgZWFzeSB0byBhY2Nlc3MgY29sb3JzIHZpYSBgaGV4TmFtZXNbaGV4XWBcbiAgICB2YXIgaGV4TmFtZXMgPSB0aW55Y29sb3IuaGV4TmFtZXMgPSBmbGlwKG5hbWVzKTtcblxuXG4gICAgLy8gVXRpbGl0aWVzXG4gICAgLy8gLS0tLS0tLS0tXG5cbiAgICAvLyBgeyAnbmFtZTEnOiAndmFsMScgfWAgYmVjb21lcyBgeyAndmFsMSc6ICduYW1lMScgfWBcbiAgICBmdW5jdGlvbiBmbGlwKG8pIHtcbiAgICAgICAgdmFyIGZsaXBwZWQgPSB7IH07XG4gICAgICAgIGZvciAodmFyIGkgaW4gbykge1xuICAgICAgICAgICAgaWYgKG8uaGFzT3duUHJvcGVydHkoaSkpIHtcbiAgICAgICAgICAgICAgICBmbGlwcGVkW29baV1dID0gaTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmxpcHBlZDtcbiAgICB9XG5cbiAgICAvLyBSZXR1cm4gYSB2YWxpZCBhbHBoYSB2YWx1ZSBbMCwxXSB3aXRoIGFsbCBpbnZhbGlkIHZhbHVlcyBiZWluZyBzZXQgdG8gMVxuICAgIGZ1bmN0aW9uIGJvdW5kQWxwaGEoYSkge1xuICAgICAgICBhID0gcGFyc2VGbG9hdChhKTtcblxuICAgICAgICBpZiAoaXNOYU4oYSkgfHwgYSA8IDAgfHwgYSA+IDEpIHtcbiAgICAgICAgICAgIGEgPSAxO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIGE7XG4gICAgfVxuXG4gICAgLy8gVGFrZSBpbnB1dCBmcm9tIFswLCBuXSBhbmQgcmV0dXJuIGl0IGFzIFswLCAxXVxuICAgIGZ1bmN0aW9uIGJvdW5kMDEobiwgbWF4KSB7XG4gICAgICAgIGlmIChpc09uZVBvaW50WmVybyhuKSkgeyBuID0gXCIxMDAlXCI7IH1cblxuICAgICAgICB2YXIgcHJvY2Vzc1BlcmNlbnQgPSBpc1BlcmNlbnRhZ2Uobik7XG4gICAgICAgIG4gPSBtYXRoTWluKG1heCwgbWF0aE1heCgwLCBwYXJzZUZsb2F0KG4pKSk7XG5cbiAgICAgICAgLy8gQXV0b21hdGljYWxseSBjb252ZXJ0IHBlcmNlbnRhZ2UgaW50byBudW1iZXJcbiAgICAgICAgaWYgKHByb2Nlc3NQZXJjZW50KSB7XG4gICAgICAgICAgICBuID0gcGFyc2VJbnQobiAqIG1heCwgMTApIC8gMTAwO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSGFuZGxlIGZsb2F0aW5nIHBvaW50IHJvdW5kaW5nIGVycm9yc1xuICAgICAgICBpZiAoKG1hdGguYWJzKG4gLSBtYXgpIDwgMC4wMDAwMDEpKSB7XG4gICAgICAgICAgICByZXR1cm4gMTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIENvbnZlcnQgaW50byBbMCwgMV0gcmFuZ2UgaWYgaXQgaXNuJ3QgYWxyZWFkeVxuICAgICAgICByZXR1cm4gKG4gJSBtYXgpIC8gcGFyc2VGbG9hdChtYXgpO1xuICAgIH1cblxuICAgIC8vIEZvcmNlIGEgbnVtYmVyIGJldHdlZW4gMCBhbmQgMVxuICAgIGZ1bmN0aW9uIGNsYW1wMDEodmFsKSB7XG4gICAgICAgIHJldHVybiBtYXRoTWluKDEsIG1hdGhNYXgoMCwgdmFsKSk7XG4gICAgfVxuXG4gICAgLy8gUGFyc2UgYSBiYXNlLTE2IGhleCB2YWx1ZSBpbnRvIGEgYmFzZS0xMCBpbnRlZ2VyXG4gICAgZnVuY3Rpb24gcGFyc2VJbnRGcm9tSGV4KHZhbCkge1xuICAgICAgICByZXR1cm4gcGFyc2VJbnQodmFsLCAxNik7XG4gICAgfVxuXG4gICAgLy8gTmVlZCB0byBoYW5kbGUgMS4wIGFzIDEwMCUsIHNpbmNlIG9uY2UgaXQgaXMgYSBudW1iZXIsIHRoZXJlIGlzIG5vIGRpZmZlcmVuY2UgYmV0d2VlbiBpdCBhbmQgMVxuICAgIC8vIDxodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzc0MjIwNzIvamF2YXNjcmlwdC1ob3ctdG8tZGV0ZWN0LW51bWJlci1hcy1hLWRlY2ltYWwtaW5jbHVkaW5nLTEtMD5cbiAgICBmdW5jdGlvbiBpc09uZVBvaW50WmVybyhuKSB7XG4gICAgICAgIHJldHVybiB0eXBlb2YgbiA9PSBcInN0cmluZ1wiICYmIG4uaW5kZXhPZignLicpICE9IC0xICYmIHBhcnNlRmxvYXQobikgPT09IDE7XG4gICAgfVxuXG4gICAgLy8gQ2hlY2sgdG8gc2VlIGlmIHN0cmluZyBwYXNzZWQgaW4gaXMgYSBwZXJjZW50YWdlXG4gICAgZnVuY3Rpb24gaXNQZXJjZW50YWdlKG4pIHtcbiAgICAgICAgcmV0dXJuIHR5cGVvZiBuID09PSBcInN0cmluZ1wiICYmIG4uaW5kZXhPZignJScpICE9IC0xO1xuICAgIH1cblxuICAgIC8vIEZvcmNlIGEgaGV4IHZhbHVlIHRvIGhhdmUgMiBjaGFyYWN0ZXJzXG4gICAgZnVuY3Rpb24gcGFkMihjKSB7XG4gICAgICAgIHJldHVybiBjLmxlbmd0aCA9PSAxID8gJzAnICsgYyA6ICcnICsgYztcbiAgICB9XG5cbiAgICAvLyBSZXBsYWNlIGEgZGVjaW1hbCB3aXRoIGl0J3MgcGVyY2VudGFnZSB2YWx1ZVxuICAgIGZ1bmN0aW9uIGNvbnZlcnRUb1BlcmNlbnRhZ2Uobikge1xuICAgICAgICBpZiAobiA8PSAxKSB7XG4gICAgICAgICAgICBuID0gKG4gKiAxMDApICsgXCIlXCI7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gbjtcbiAgICB9XG5cbiAgICAvLyBDb252ZXJ0cyBhIGRlY2ltYWwgdG8gYSBoZXggdmFsdWVcbiAgICBmdW5jdGlvbiBjb252ZXJ0RGVjaW1hbFRvSGV4KGQpIHtcbiAgICAgICAgcmV0dXJuIE1hdGgucm91bmQocGFyc2VGbG9hdChkKSAqIDI1NSkudG9TdHJpbmcoMTYpO1xuICAgIH1cbiAgICAvLyBDb252ZXJ0cyBhIGhleCB2YWx1ZSB0byBhIGRlY2ltYWxcbiAgICBmdW5jdGlvbiBjb252ZXJ0SGV4VG9EZWNpbWFsKGgpIHtcbiAgICAgICAgcmV0dXJuIChwYXJzZUludEZyb21IZXgoaCkgLyAyNTUpO1xuICAgIH1cblxuICAgIHZhciBtYXRjaGVycyA9IChmdW5jdGlvbigpIHtcblxuICAgICAgICAvLyA8aHR0cDovL3d3dy53My5vcmcvVFIvY3NzMy12YWx1ZXMvI2ludGVnZXJzPlxuICAgICAgICB2YXIgQ1NTX0lOVEVHRVIgPSBcIlstXFxcXCtdP1xcXFxkKyU/XCI7XG5cbiAgICAgICAgLy8gPGh0dHA6Ly93d3cudzMub3JnL1RSL2NzczMtdmFsdWVzLyNudW1iZXItdmFsdWU+XG4gICAgICAgIHZhciBDU1NfTlVNQkVSID0gXCJbLVxcXFwrXT9cXFxcZCpcXFxcLlxcXFxkKyU/XCI7XG5cbiAgICAgICAgLy8gQWxsb3cgcG9zaXRpdmUvbmVnYXRpdmUgaW50ZWdlci9udW1iZXIuICBEb24ndCBjYXB0dXJlIHRoZSBlaXRoZXIvb3IsIGp1c3QgdGhlIGVudGlyZSBvdXRjb21lLlxuICAgICAgICB2YXIgQ1NTX1VOSVQgPSBcIig/OlwiICsgQ1NTX05VTUJFUiArIFwiKXwoPzpcIiArIENTU19JTlRFR0VSICsgXCIpXCI7XG5cbiAgICAgICAgLy8gQWN0dWFsIG1hdGNoaW5nLlxuICAgICAgICAvLyBQYXJlbnRoZXNlcyBhbmQgY29tbWFzIGFyZSBvcHRpb25hbCwgYnV0IG5vdCByZXF1aXJlZC5cbiAgICAgICAgLy8gV2hpdGVzcGFjZSBjYW4gdGFrZSB0aGUgcGxhY2Ugb2YgY29tbWFzIG9yIG9wZW5pbmcgcGFyZW5cbiAgICAgICAgdmFyIFBFUk1JU1NJVkVfTUFUQ0gzID0gXCJbXFxcXHN8XFxcXChdKyhcIiArIENTU19VTklUICsgXCIpWyx8XFxcXHNdKyhcIiArIENTU19VTklUICsgXCIpWyx8XFxcXHNdKyhcIiArIENTU19VTklUICsgXCIpXFxcXHMqXFxcXCk/XCI7XG4gICAgICAgIHZhciBQRVJNSVNTSVZFX01BVENINCA9IFwiW1xcXFxzfFxcXFwoXSsoXCIgKyBDU1NfVU5JVCArIFwiKVssfFxcXFxzXSsoXCIgKyBDU1NfVU5JVCArIFwiKVssfFxcXFxzXSsoXCIgKyBDU1NfVU5JVCArIFwiKVssfFxcXFxzXSsoXCIgKyBDU1NfVU5JVCArIFwiKVxcXFxzKlxcXFwpP1wiO1xuXG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICByZ2I6IG5ldyBSZWdFeHAoXCJyZ2JcIiArIFBFUk1JU1NJVkVfTUFUQ0gzKSxcbiAgICAgICAgICAgIHJnYmE6IG5ldyBSZWdFeHAoXCJyZ2JhXCIgKyBQRVJNSVNTSVZFX01BVENINCksXG4gICAgICAgICAgICBoc2w6IG5ldyBSZWdFeHAoXCJoc2xcIiArIFBFUk1JU1NJVkVfTUFUQ0gzKSxcbiAgICAgICAgICAgIGhzbGE6IG5ldyBSZWdFeHAoXCJoc2xhXCIgKyBQRVJNSVNTSVZFX01BVENINCksXG4gICAgICAgICAgICBoc3Y6IG5ldyBSZWdFeHAoXCJoc3ZcIiArIFBFUk1JU1NJVkVfTUFUQ0gzKSxcbiAgICAgICAgICAgIGhzdmE6IG5ldyBSZWdFeHAoXCJoc3ZhXCIgKyBQRVJNSVNTSVZFX01BVENINCksXG4gICAgICAgICAgICBoZXgzOiAvXihbMC05YS1mQS1GXXsxfSkoWzAtOWEtZkEtRl17MX0pKFswLTlhLWZBLUZdezF9KSQvLFxuICAgICAgICAgICAgaGV4NjogL14oWzAtOWEtZkEtRl17Mn0pKFswLTlhLWZBLUZdezJ9KShbMC05YS1mQS1GXXsyfSkkLyxcbiAgICAgICAgICAgIGhleDg6IC9eKFswLTlhLWZBLUZdezJ9KShbMC05YS1mQS1GXXsyfSkoWzAtOWEtZkEtRl17Mn0pKFswLTlhLWZBLUZdezJ9KSQvXG4gICAgICAgIH07XG4gICAgfSkoKTtcblxuICAgIC8vIGBzdHJpbmdJbnB1dFRvT2JqZWN0YFxuICAgIC8vIFBlcm1pc3NpdmUgc3RyaW5nIHBhcnNpbmcuICBUYWtlIGluIGEgbnVtYmVyIG9mIGZvcm1hdHMsIGFuZCBvdXRwdXQgYW4gb2JqZWN0XG4gICAgLy8gYmFzZWQgb24gZGV0ZWN0ZWQgZm9ybWF0LiAgUmV0dXJucyBgeyByLCBnLCBiIH1gIG9yIGB7IGgsIHMsIGwgfWAgb3IgYHsgaCwgcywgdn1gXG4gICAgZnVuY3Rpb24gc3RyaW5nSW5wdXRUb09iamVjdChjb2xvcikge1xuXG4gICAgICAgIGNvbG9yID0gY29sb3IucmVwbGFjZSh0cmltTGVmdCwnJykucmVwbGFjZSh0cmltUmlnaHQsICcnKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgbmFtZWQgPSBmYWxzZTtcbiAgICAgICAgaWYgKG5hbWVzW2NvbG9yXSkge1xuICAgICAgICAgICAgY29sb3IgPSBuYW1lc1tjb2xvcl07XG4gICAgICAgICAgICBuYW1lZCA9IHRydWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoY29sb3IgPT0gJ3RyYW5zcGFyZW50Jykge1xuICAgICAgICAgICAgcmV0dXJuIHsgcjogMCwgZzogMCwgYjogMCwgYTogMCwgZm9ybWF0OiBcIm5hbWVcIiB9O1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gVHJ5IHRvIG1hdGNoIHN0cmluZyBpbnB1dCB1c2luZyByZWd1bGFyIGV4cHJlc3Npb25zLlxuICAgICAgICAvLyBLZWVwIG1vc3Qgb2YgdGhlIG51bWJlciBib3VuZGluZyBvdXQgb2YgdGhpcyBmdW5jdGlvbiAtIGRvbid0IHdvcnJ5IGFib3V0IFswLDFdIG9yIFswLDEwMF0gb3IgWzAsMzYwXVxuICAgICAgICAvLyBKdXN0IHJldHVybiBhbiBvYmplY3QgYW5kIGxldCB0aGUgY29udmVyc2lvbiBmdW5jdGlvbnMgaGFuZGxlIHRoYXQuXG4gICAgICAgIC8vIFRoaXMgd2F5IHRoZSByZXN1bHQgd2lsbCBiZSB0aGUgc2FtZSB3aGV0aGVyIHRoZSB0aW55Y29sb3IgaXMgaW5pdGlhbGl6ZWQgd2l0aCBzdHJpbmcgb3Igb2JqZWN0LlxuICAgICAgICB2YXIgbWF0Y2g7XG4gICAgICAgIGlmICgobWF0Y2ggPSBtYXRjaGVycy5yZ2IuZXhlYyhjb2xvcikpKSB7XG4gICAgICAgICAgICByZXR1cm4geyByOiBtYXRjaFsxXSwgZzogbWF0Y2hbMl0sIGI6IG1hdGNoWzNdIH07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKChtYXRjaCA9IG1hdGNoZXJzLnJnYmEuZXhlYyhjb2xvcikpKSB7XG4gICAgICAgICAgICByZXR1cm4geyByOiBtYXRjaFsxXSwgZzogbWF0Y2hbMl0sIGI6IG1hdGNoWzNdLCBhOiBtYXRjaFs0XSB9O1xuICAgICAgICB9XG4gICAgICAgIGlmICgobWF0Y2ggPSBtYXRjaGVycy5oc2wuZXhlYyhjb2xvcikpKSB7XG4gICAgICAgICAgICByZXR1cm4geyBoOiBtYXRjaFsxXSwgczogbWF0Y2hbMl0sIGw6IG1hdGNoWzNdIH07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKChtYXRjaCA9IG1hdGNoZXJzLmhzbGEuZXhlYyhjb2xvcikpKSB7XG4gICAgICAgICAgICByZXR1cm4geyBoOiBtYXRjaFsxXSwgczogbWF0Y2hbMl0sIGw6IG1hdGNoWzNdLCBhOiBtYXRjaFs0XSB9O1xuICAgICAgICB9XG4gICAgICAgIGlmICgobWF0Y2ggPSBtYXRjaGVycy5oc3YuZXhlYyhjb2xvcikpKSB7XG4gICAgICAgICAgICByZXR1cm4geyBoOiBtYXRjaFsxXSwgczogbWF0Y2hbMl0sIHY6IG1hdGNoWzNdIH07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKChtYXRjaCA9IG1hdGNoZXJzLmhzdmEuZXhlYyhjb2xvcikpKSB7XG4gICAgICAgICAgICByZXR1cm4geyBoOiBtYXRjaFsxXSwgczogbWF0Y2hbMl0sIHY6IG1hdGNoWzNdLCBhOiBtYXRjaFs0XSB9O1xuICAgICAgICB9XG4gICAgICAgIGlmICgobWF0Y2ggPSBtYXRjaGVycy5oZXg4LmV4ZWMoY29sb3IpKSkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICBhOiBjb252ZXJ0SGV4VG9EZWNpbWFsKG1hdGNoWzFdKSxcbiAgICAgICAgICAgICAgICByOiBwYXJzZUludEZyb21IZXgobWF0Y2hbMl0pLFxuICAgICAgICAgICAgICAgIGc6IHBhcnNlSW50RnJvbUhleChtYXRjaFszXSksXG4gICAgICAgICAgICAgICAgYjogcGFyc2VJbnRGcm9tSGV4KG1hdGNoWzRdKSxcbiAgICAgICAgICAgICAgICBmb3JtYXQ6IG5hbWVkID8gXCJuYW1lXCIgOiBcImhleDhcIlxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoKG1hdGNoID0gbWF0Y2hlcnMuaGV4Ni5leGVjKGNvbG9yKSkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcjogcGFyc2VJbnRGcm9tSGV4KG1hdGNoWzFdKSxcbiAgICAgICAgICAgICAgICBnOiBwYXJzZUludEZyb21IZXgobWF0Y2hbMl0pLFxuICAgICAgICAgICAgICAgIGI6IHBhcnNlSW50RnJvbUhleChtYXRjaFszXSksXG4gICAgICAgICAgICAgICAgZm9ybWF0OiBuYW1lZCA/IFwibmFtZVwiIDogXCJoZXhcIlxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoKG1hdGNoID0gbWF0Y2hlcnMuaGV4My5leGVjKGNvbG9yKSkpIHtcbiAgICAgICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICAgICAgcjogcGFyc2VJbnRGcm9tSGV4KG1hdGNoWzFdICsgJycgKyBtYXRjaFsxXSksXG4gICAgICAgICAgICAgICAgZzogcGFyc2VJbnRGcm9tSGV4KG1hdGNoWzJdICsgJycgKyBtYXRjaFsyXSksXG4gICAgICAgICAgICAgICAgYjogcGFyc2VJbnRGcm9tSGV4KG1hdGNoWzNdICsgJycgKyBtYXRjaFszXSksXG4gICAgICAgICAgICAgICAgZm9ybWF0OiBuYW1lZCA/IFwibmFtZVwiIDogXCJoZXhcIlxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICB3aW5kb3cudGlueWNvbG9yID0gdGlueWNvbG9yO1xuICAgIH0pKCk7XG5cbiAgICAkKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCQuZm4uc3BlY3RydW0ubG9hZCkge1xuICAgICAgICAgICAgJC5mbi5zcGVjdHJ1bS5wcm9jZXNzTmF0aXZlQ29sb3JJbnB1dHMoKTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG59KTtcbiIsIi8qIHBlcmZlY3Qtc2Nyb2xsYmFyIHYwLjcuMSAqL1xuKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkoezE6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgcHMgPSByZXF1aXJlKCcuLi9tYWluJyk7XG52YXIgcHNJbnN0YW5jZXMgPSByZXF1aXJlKCcuLi9wbHVnaW4vaW5zdGFuY2VzJyk7XG5cbmZ1bmN0aW9uIG1vdW50SlF1ZXJ5KGpRdWVyeSkge1xuICBqUXVlcnkuZm4ucGVyZmVjdFNjcm9sbGJhciA9IGZ1bmN0aW9uIChzZXR0aW5nT3JDb21tYW5kKSB7XG4gICAgcmV0dXJuIHRoaXMuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICBpZiAodHlwZW9mIHNldHRpbmdPckNvbW1hbmQgPT09ICdvYmplY3QnIHx8XG4gICAgICAgICAgdHlwZW9mIHNldHRpbmdPckNvbW1hbmQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIC8vIElmIGl0J3MgYW4gb2JqZWN0IG9yIG5vbmUsIGluaXRpYWxpemUuXG4gICAgICAgIHZhciBzZXR0aW5ncyA9IHNldHRpbmdPckNvbW1hbmQ7XG5cbiAgICAgICAgaWYgKCFwc0luc3RhbmNlcy5nZXQodGhpcykpIHtcbiAgICAgICAgICBwcy5pbml0aWFsaXplKHRoaXMsIHNldHRpbmdzKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gVW5sZXNzLCBpdCBtYXkgYmUgYSBjb21tYW5kLlxuICAgICAgICB2YXIgY29tbWFuZCA9IHNldHRpbmdPckNvbW1hbmQ7XG5cbiAgICAgICAgaWYgKGNvbW1hbmQgPT09ICd1cGRhdGUnKSB7XG4gICAgICAgICAgcHMudXBkYXRlKHRoaXMpO1xuICAgICAgICB9IGVsc2UgaWYgKGNvbW1hbmQgPT09ICdkZXN0cm95Jykge1xuICAgICAgICAgIHBzLmRlc3Ryb3kodGhpcyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfTtcbn1cblxuaWYgKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xuICAvLyBBTUQuIFJlZ2lzdGVyIGFzIGFuIGFub255bW91cyBtb2R1bGUuXG4gIGRlZmluZShbJ2pxdWVyeSddLCBtb3VudEpRdWVyeSk7XG59IGVsc2Uge1xuICB2YXIganEgPSB3aW5kb3cualF1ZXJ5ID8gd2luZG93LmpRdWVyeSA6IHdpbmRvdy4kO1xuICBpZiAodHlwZW9mIGpxICE9PSAndW5kZWZpbmVkJykge1xuICAgIG1vdW50SlF1ZXJ5KGpxKTtcbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IG1vdW50SlF1ZXJ5O1xuXG59LHtcIi4uL21haW5cIjo3LFwiLi4vcGx1Z2luL2luc3RhbmNlc1wiOjE4fV0sMjpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIG9sZEFkZChlbGVtZW50LCBjbGFzc05hbWUpIHtcbiAgdmFyIGNsYXNzZXMgPSBlbGVtZW50LmNsYXNzTmFtZS5zcGxpdCgnICcpO1xuICBpZiAoY2xhc3Nlcy5pbmRleE9mKGNsYXNzTmFtZSkgPCAwKSB7XG4gICAgY2xhc3Nlcy5wdXNoKGNsYXNzTmFtZSk7XG4gIH1cbiAgZWxlbWVudC5jbGFzc05hbWUgPSBjbGFzc2VzLmpvaW4oJyAnKTtcbn1cblxuZnVuY3Rpb24gb2xkUmVtb3ZlKGVsZW1lbnQsIGNsYXNzTmFtZSkge1xuICB2YXIgY2xhc3NlcyA9IGVsZW1lbnQuY2xhc3NOYW1lLnNwbGl0KCcgJyk7XG4gIHZhciBpZHggPSBjbGFzc2VzLmluZGV4T2YoY2xhc3NOYW1lKTtcbiAgaWYgKGlkeCA+PSAwKSB7XG4gICAgY2xhc3Nlcy5zcGxpY2UoaWR4LCAxKTtcbiAgfVxuICBlbGVtZW50LmNsYXNzTmFtZSA9IGNsYXNzZXMuam9pbignICcpO1xufVxuXG5leHBvcnRzLmFkZCA9IGZ1bmN0aW9uIChlbGVtZW50LCBjbGFzc05hbWUpIHtcbiAgaWYgKGVsZW1lbnQuY2xhc3NMaXN0KSB7XG4gICAgZWxlbWVudC5jbGFzc0xpc3QuYWRkKGNsYXNzTmFtZSk7XG4gIH0gZWxzZSB7XG4gICAgb2xkQWRkKGVsZW1lbnQsIGNsYXNzTmFtZSk7XG4gIH1cbn07XG5cbmV4cG9ydHMucmVtb3ZlID0gZnVuY3Rpb24gKGVsZW1lbnQsIGNsYXNzTmFtZSkge1xuICBpZiAoZWxlbWVudC5jbGFzc0xpc3QpIHtcbiAgICBlbGVtZW50LmNsYXNzTGlzdC5yZW1vdmUoY2xhc3NOYW1lKTtcbiAgfSBlbHNlIHtcbiAgICBvbGRSZW1vdmUoZWxlbWVudCwgY2xhc3NOYW1lKTtcbiAgfVxufTtcblxuZXhwb3J0cy5saXN0ID0gZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgaWYgKGVsZW1lbnQuY2xhc3NMaXN0KSB7XG4gICAgcmV0dXJuIEFycmF5LnByb3RvdHlwZS5zbGljZS5hcHBseShlbGVtZW50LmNsYXNzTGlzdCk7XG4gIH0gZWxzZSB7XG4gICAgcmV0dXJuIGVsZW1lbnQuY2xhc3NOYW1lLnNwbGl0KCcgJyk7XG4gIH1cbn07XG5cbn0se31dLDM6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgRE9NID0ge307XG5cbkRPTS5lID0gZnVuY3Rpb24gKHRhZ05hbWUsIGNsYXNzTmFtZSkge1xuICB2YXIgZWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGFnTmFtZSk7XG4gIGVsZW1lbnQuY2xhc3NOYW1lID0gY2xhc3NOYW1lO1xuICByZXR1cm4gZWxlbWVudDtcbn07XG5cbkRPTS5hcHBlbmRUbyA9IGZ1bmN0aW9uIChjaGlsZCwgcGFyZW50KSB7XG4gIHBhcmVudC5hcHBlbmRDaGlsZChjaGlsZCk7XG4gIHJldHVybiBjaGlsZDtcbn07XG5cbmZ1bmN0aW9uIGNzc0dldChlbGVtZW50LCBzdHlsZU5hbWUpIHtcbiAgcmV0dXJuIHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGVsZW1lbnQpW3N0eWxlTmFtZV07XG59XG5cbmZ1bmN0aW9uIGNzc1NldChlbGVtZW50LCBzdHlsZU5hbWUsIHN0eWxlVmFsdWUpIHtcbiAgaWYgKHR5cGVvZiBzdHlsZVZhbHVlID09PSAnbnVtYmVyJykge1xuICAgIHN0eWxlVmFsdWUgPSBzdHlsZVZhbHVlLnRvU3RyaW5nKCkgKyAncHgnO1xuICB9XG4gIGVsZW1lbnQuc3R5bGVbc3R5bGVOYW1lXSA9IHN0eWxlVmFsdWU7XG4gIHJldHVybiBlbGVtZW50O1xufVxuXG5mdW5jdGlvbiBjc3NNdWx0aVNldChlbGVtZW50LCBvYmopIHtcbiAgZm9yICh2YXIga2V5IGluIG9iaikge1xuICAgIHZhciB2YWwgPSBvYmpba2V5XTtcbiAgICBpZiAodHlwZW9mIHZhbCA9PT0gJ251bWJlcicpIHtcbiAgICAgIHZhbCA9IHZhbC50b1N0cmluZygpICsgJ3B4JztcbiAgICB9XG4gICAgZWxlbWVudC5zdHlsZVtrZXldID0gdmFsO1xuICB9XG4gIHJldHVybiBlbGVtZW50O1xufVxuXG5ET00uY3NzID0gZnVuY3Rpb24gKGVsZW1lbnQsIHN0eWxlTmFtZU9yT2JqZWN0LCBzdHlsZVZhbHVlKSB7XG4gIGlmICh0eXBlb2Ygc3R5bGVOYW1lT3JPYmplY3QgPT09ICdvYmplY3QnKSB7XG4gICAgLy8gbXVsdGlwbGUgc2V0IHdpdGggb2JqZWN0XG4gICAgcmV0dXJuIGNzc011bHRpU2V0KGVsZW1lbnQsIHN0eWxlTmFtZU9yT2JqZWN0KTtcbiAgfSBlbHNlIHtcbiAgICBpZiAodHlwZW9mIHN0eWxlVmFsdWUgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gY3NzR2V0KGVsZW1lbnQsIHN0eWxlTmFtZU9yT2JqZWN0KTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGNzc1NldChlbGVtZW50LCBzdHlsZU5hbWVPck9iamVjdCwgc3R5bGVWYWx1ZSk7XG4gICAgfVxuICB9XG59O1xuXG5ET00ubWF0Y2hlcyA9IGZ1bmN0aW9uIChlbGVtZW50LCBxdWVyeSkge1xuICBpZiAodHlwZW9mIGVsZW1lbnQubWF0Y2hlcyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICByZXR1cm4gZWxlbWVudC5tYXRjaGVzKHF1ZXJ5KTtcbiAgfSBlbHNlIHtcbiAgICBpZiAodHlwZW9mIGVsZW1lbnQubWF0Y2hlc1NlbGVjdG9yICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuIGVsZW1lbnQubWF0Y2hlc1NlbGVjdG9yKHF1ZXJ5KTtcbiAgICB9IGVsc2UgaWYgKHR5cGVvZiBlbGVtZW50LndlYmtpdE1hdGNoZXNTZWxlY3RvciAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgIHJldHVybiBlbGVtZW50LndlYmtpdE1hdGNoZXNTZWxlY3RvcihxdWVyeSk7XG4gICAgfSBlbHNlIGlmICh0eXBlb2YgZWxlbWVudC5tb3pNYXRjaGVzU2VsZWN0b3IgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gZWxlbWVudC5tb3pNYXRjaGVzU2VsZWN0b3IocXVlcnkpO1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIGVsZW1lbnQubXNNYXRjaGVzU2VsZWN0b3IgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICByZXR1cm4gZWxlbWVudC5tc01hdGNoZXNTZWxlY3RvcihxdWVyeSk7XG4gICAgfVxuICB9XG59O1xuXG5ET00ucmVtb3ZlID0gZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgaWYgKHR5cGVvZiBlbGVtZW50LnJlbW92ZSAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICBlbGVtZW50LnJlbW92ZSgpO1xuICB9IGVsc2Uge1xuICAgIGlmIChlbGVtZW50LnBhcmVudE5vZGUpIHtcbiAgICAgIGVsZW1lbnQucGFyZW50Tm9kZS5yZW1vdmVDaGlsZChlbGVtZW50KTtcbiAgICB9XG4gIH1cbn07XG5cbkRPTS5xdWVyeUNoaWxkcmVuID0gZnVuY3Rpb24gKGVsZW1lbnQsIHNlbGVjdG9yKSB7XG4gIHJldHVybiBBcnJheS5wcm90b3R5cGUuZmlsdGVyLmNhbGwoZWxlbWVudC5jaGlsZE5vZGVzLCBmdW5jdGlvbiAoY2hpbGQpIHtcbiAgICByZXR1cm4gRE9NLm1hdGNoZXMoY2hpbGQsIHNlbGVjdG9yKTtcbiAgfSk7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IERPTTtcblxufSx7fV0sNDpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbnZhciBFdmVudEVsZW1lbnQgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICB0aGlzLmVsZW1lbnQgPSBlbGVtZW50O1xuICB0aGlzLmV2ZW50cyA9IHt9O1xufTtcblxuRXZlbnRFbGVtZW50LnByb3RvdHlwZS5iaW5kID0gZnVuY3Rpb24gKGV2ZW50TmFtZSwgaGFuZGxlcikge1xuICBpZiAodHlwZW9mIHRoaXMuZXZlbnRzW2V2ZW50TmFtZV0gPT09ICd1bmRlZmluZWQnKSB7XG4gICAgdGhpcy5ldmVudHNbZXZlbnROYW1lXSA9IFtdO1xuICB9XG4gIHRoaXMuZXZlbnRzW2V2ZW50TmFtZV0ucHVzaChoYW5kbGVyKTtcbiAgdGhpcy5lbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBoYW5kbGVyLCBmYWxzZSk7XG59O1xuXG5FdmVudEVsZW1lbnQucHJvdG90eXBlLnVuYmluZCA9IGZ1bmN0aW9uIChldmVudE5hbWUsIGhhbmRsZXIpIHtcbiAgdmFyIGlzSGFuZGxlclByb3ZpZGVkID0gKHR5cGVvZiBoYW5kbGVyICE9PSAndW5kZWZpbmVkJyk7XG4gIHRoaXMuZXZlbnRzW2V2ZW50TmFtZV0gPSB0aGlzLmV2ZW50c1tldmVudE5hbWVdLmZpbHRlcihmdW5jdGlvbiAoaGRscikge1xuICAgIGlmIChpc0hhbmRsZXJQcm92aWRlZCAmJiBoZGxyICE9PSBoYW5kbGVyKSB7XG4gICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG4gICAgdGhpcy5lbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoZXZlbnROYW1lLCBoZGxyLCBmYWxzZSk7XG4gICAgcmV0dXJuIGZhbHNlO1xuICB9LCB0aGlzKTtcbn07XG5cbkV2ZW50RWxlbWVudC5wcm90b3R5cGUudW5iaW5kQWxsID0gZnVuY3Rpb24gKCkge1xuICBmb3IgKHZhciBuYW1lIGluIHRoaXMuZXZlbnRzKSB7XG4gICAgdGhpcy51bmJpbmQobmFtZSk7XG4gIH1cbn07XG5cbnZhciBFdmVudE1hbmFnZXIgPSBmdW5jdGlvbiAoKSB7XG4gIHRoaXMuZXZlbnRFbGVtZW50cyA9IFtdO1xufTtcblxuRXZlbnRNYW5hZ2VyLnByb3RvdHlwZS5ldmVudEVsZW1lbnQgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICB2YXIgZWUgPSB0aGlzLmV2ZW50RWxlbWVudHMuZmlsdGVyKGZ1bmN0aW9uIChldmVudEVsZW1lbnQpIHtcbiAgICByZXR1cm4gZXZlbnRFbGVtZW50LmVsZW1lbnQgPT09IGVsZW1lbnQ7XG4gIH0pWzBdO1xuICBpZiAodHlwZW9mIGVlID09PSAndW5kZWZpbmVkJykge1xuICAgIGVlID0gbmV3IEV2ZW50RWxlbWVudChlbGVtZW50KTtcbiAgICB0aGlzLmV2ZW50RWxlbWVudHMucHVzaChlZSk7XG4gIH1cbiAgcmV0dXJuIGVlO1xufTtcblxuRXZlbnRNYW5hZ2VyLnByb3RvdHlwZS5iaW5kID0gZnVuY3Rpb24gKGVsZW1lbnQsIGV2ZW50TmFtZSwgaGFuZGxlcikge1xuICB0aGlzLmV2ZW50RWxlbWVudChlbGVtZW50KS5iaW5kKGV2ZW50TmFtZSwgaGFuZGxlcik7XG59O1xuXG5FdmVudE1hbmFnZXIucHJvdG90eXBlLnVuYmluZCA9IGZ1bmN0aW9uIChlbGVtZW50LCBldmVudE5hbWUsIGhhbmRsZXIpIHtcbiAgdGhpcy5ldmVudEVsZW1lbnQoZWxlbWVudCkudW5iaW5kKGV2ZW50TmFtZSwgaGFuZGxlcik7XG59O1xuXG5FdmVudE1hbmFnZXIucHJvdG90eXBlLnVuYmluZEFsbCA9IGZ1bmN0aW9uICgpIHtcbiAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmV2ZW50RWxlbWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICB0aGlzLmV2ZW50RWxlbWVudHNbaV0udW5iaW5kQWxsKCk7XG4gIH1cbn07XG5cbkV2ZW50TWFuYWdlci5wcm90b3R5cGUub25jZSA9IGZ1bmN0aW9uIChlbGVtZW50LCBldmVudE5hbWUsIGhhbmRsZXIpIHtcbiAgdmFyIGVlID0gdGhpcy5ldmVudEVsZW1lbnQoZWxlbWVudCk7XG4gIHZhciBvbmNlSGFuZGxlciA9IGZ1bmN0aW9uIChlKSB7XG4gICAgZWUudW5iaW5kKGV2ZW50TmFtZSwgb25jZUhhbmRsZXIpO1xuICAgIGhhbmRsZXIoZSk7XG4gIH07XG4gIGVlLmJpbmQoZXZlbnROYW1lLCBvbmNlSGFuZGxlcik7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV2ZW50TWFuYWdlcjtcblxufSx7fV0sNTpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbm1vZHVsZS5leHBvcnRzID0gKGZ1bmN0aW9uICgpIHtcbiAgZnVuY3Rpb24gczQoKSB7XG4gICAgcmV0dXJuIE1hdGguZmxvb3IoKDEgKyBNYXRoLnJhbmRvbSgpKSAqIDB4MTAwMDApXG4gICAgICAgICAgICAgICAudG9TdHJpbmcoMTYpXG4gICAgICAgICAgICAgICAuc3Vic3RyaW5nKDEpO1xuICB9XG4gIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHM0KCkgKyBzNCgpICsgJy0nICsgczQoKSArICctJyArIHM0KCkgKyAnLScgK1xuICAgICAgICAgICBzNCgpICsgJy0nICsgczQoKSArIHM0KCkgKyBzNCgpO1xuICB9O1xufSkoKTtcblxufSx7fV0sNjpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbnZhciBjbHMgPSByZXF1aXJlKCcuL2NsYXNzJyk7XG52YXIgZG9tID0gcmVxdWlyZSgnLi9kb20nKTtcblxudmFyIHRvSW50ID0gZXhwb3J0cy50b0ludCA9IGZ1bmN0aW9uICh4KSB7XG4gIHJldHVybiBwYXJzZUludCh4LCAxMCkgfHwgMDtcbn07XG5cbnZhciBjbG9uZSA9IGV4cG9ydHMuY2xvbmUgPSBmdW5jdGlvbiAob2JqKSB7XG4gIGlmICghb2JqKSB7XG4gICAgcmV0dXJuIG51bGw7XG4gIH0gZWxzZSBpZiAoQXJyYXkuaXNBcnJheShvYmopKSB7XG4gICAgcmV0dXJuIG9iai5tYXAoY2xvbmUpO1xuICB9IGVsc2UgaWYgKHR5cGVvZiBvYmogPT09ICdvYmplY3QnKSB7XG4gICAgdmFyIHJlc3VsdCA9IHt9O1xuICAgIGZvciAodmFyIGtleSBpbiBvYmopIHtcbiAgICAgIHJlc3VsdFtrZXldID0gY2xvbmUob2JqW2tleV0pO1xuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0O1xuICB9IGVsc2Uge1xuICAgIHJldHVybiBvYmo7XG4gIH1cbn07XG5cbmV4cG9ydHMuZXh0ZW5kID0gZnVuY3Rpb24gKG9yaWdpbmFsLCBzb3VyY2UpIHtcbiAgdmFyIHJlc3VsdCA9IGNsb25lKG9yaWdpbmFsKTtcbiAgZm9yICh2YXIga2V5IGluIHNvdXJjZSkge1xuICAgIHJlc3VsdFtrZXldID0gY2xvbmUoc291cmNlW2tleV0pO1xuICB9XG4gIHJldHVybiByZXN1bHQ7XG59O1xuXG5leHBvcnRzLmlzRWRpdGFibGUgPSBmdW5jdGlvbiAoZWwpIHtcbiAgcmV0dXJuIGRvbS5tYXRjaGVzKGVsLCBcImlucHV0LFtjb250ZW50ZWRpdGFibGVdXCIpIHx8XG4gICAgICAgICBkb20ubWF0Y2hlcyhlbCwgXCJzZWxlY3QsW2NvbnRlbnRlZGl0YWJsZV1cIikgfHxcbiAgICAgICAgIGRvbS5tYXRjaGVzKGVsLCBcInRleHRhcmVhLFtjb250ZW50ZWRpdGFibGVdXCIpIHx8XG4gICAgICAgICBkb20ubWF0Y2hlcyhlbCwgXCJidXR0b24sW2NvbnRlbnRlZGl0YWJsZV1cIik7XG59O1xuXG5leHBvcnRzLnJlbW92ZVBzQ2xhc3NlcyA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gIHZhciBjbHNMaXN0ID0gY2xzLmxpc3QoZWxlbWVudCk7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgY2xzTGlzdC5sZW5ndGg7IGkrKykge1xuICAgIHZhciBjbGFzc05hbWUgPSBjbHNMaXN0W2ldO1xuICAgIGlmIChjbGFzc05hbWUuaW5kZXhPZigncHMtJykgPT09IDApIHtcbiAgICAgIGNscy5yZW1vdmUoZWxlbWVudCwgY2xhc3NOYW1lKTtcbiAgICB9XG4gIH1cbn07XG5cbmV4cG9ydHMub3V0ZXJXaWR0aCA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gIHJldHVybiB0b0ludChkb20uY3NzKGVsZW1lbnQsICd3aWR0aCcpKSArXG4gICAgICAgICB0b0ludChkb20uY3NzKGVsZW1lbnQsICdwYWRkaW5nTGVmdCcpKSArXG4gICAgICAgICB0b0ludChkb20uY3NzKGVsZW1lbnQsICdwYWRkaW5nUmlnaHQnKSkgK1xuICAgICAgICAgdG9JbnQoZG9tLmNzcyhlbGVtZW50LCAnYm9yZGVyTGVmdFdpZHRoJykpICtcbiAgICAgICAgIHRvSW50KGRvbS5jc3MoZWxlbWVudCwgJ2JvcmRlclJpZ2h0V2lkdGgnKSk7XG59O1xuXG5mdW5jdGlvbiB0b2dnbGVTY3JvbGxpbmcoaGFuZGxlcikge1xuICByZXR1cm4gZnVuY3Rpb24gKGVsZW1lbnQsIGF4aXMpIHtcbiAgICBoYW5kbGVyKGVsZW1lbnQsICdwcy0taW4tc2Nyb2xsaW5nJyk7XG4gICAgaWYgKHR5cGVvZiBheGlzICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgaGFuZGxlcihlbGVtZW50LCAncHMtLScgKyBheGlzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgaGFuZGxlcihlbGVtZW50LCAncHMtLXgnKTtcbiAgICAgIGhhbmRsZXIoZWxlbWVudCwgJ3BzLS15Jyk7XG4gICAgfVxuICB9O1xufVxuXG5leHBvcnRzLnN0YXJ0U2Nyb2xsaW5nID0gdG9nZ2xlU2Nyb2xsaW5nKGNscy5hZGQpO1xuXG5leHBvcnRzLnN0b3BTY3JvbGxpbmcgPSB0b2dnbGVTY3JvbGxpbmcoY2xzLnJlbW92ZSk7XG5cbmV4cG9ydHMuZW52ID0ge1xuICBpc1dlYktpdDogdHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJyAmJiAnV2Via2l0QXBwZWFyYW5jZScgaW4gZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LnN0eWxlLFxuICBzdXBwb3J0c1RvdWNoOiB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiAoKCdvbnRvdWNoc3RhcnQnIGluIHdpbmRvdykgfHwgd2luZG93LkRvY3VtZW50VG91Y2ggJiYgZG9jdW1lbnQgaW5zdGFuY2VvZiB3aW5kb3cuRG9jdW1lbnRUb3VjaCksXG4gIHN1cHBvcnRzSWVQb2ludGVyOiB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyAmJiB3aW5kb3cubmF2aWdhdG9yLm1zTWF4VG91Y2hQb2ludHMgIT09IG51bGxcbn07XG5cbn0se1wiLi9jbGFzc1wiOjIsXCIuL2RvbVwiOjN9XSw3OltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxudmFyIGRlc3Ryb3kgPSByZXF1aXJlKCcuL3BsdWdpbi9kZXN0cm95Jyk7XG52YXIgaW5pdGlhbGl6ZSA9IHJlcXVpcmUoJy4vcGx1Z2luL2luaXRpYWxpemUnKTtcbnZhciB1cGRhdGUgPSByZXF1aXJlKCcuL3BsdWdpbi91cGRhdGUnKTtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGluaXRpYWxpemU6IGluaXRpYWxpemUsXG4gIHVwZGF0ZTogdXBkYXRlLFxuICBkZXN0cm95OiBkZXN0cm95XG59O1xuXG59LHtcIi4vcGx1Z2luL2Rlc3Ryb3lcIjo5LFwiLi9wbHVnaW4vaW5pdGlhbGl6ZVwiOjE3LFwiLi9wbHVnaW4vdXBkYXRlXCI6MjF9XSw4OltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gIGhhbmRsZXJzOiBbJ2NsaWNrLXJhaWwnLCAnZHJhZy1zY3JvbGxiYXInLCAna2V5Ym9hcmQnLCAnd2hlZWwnLCAndG91Y2gnXSxcbiAgbWF4U2Nyb2xsYmFyTGVuZ3RoOiBudWxsLFxuICBtaW5TY3JvbGxiYXJMZW5ndGg6IG51bGwsXG4gIHNjcm9sbFhNYXJnaW5PZmZzZXQ6IDAsXG4gIHNjcm9sbFlNYXJnaW5PZmZzZXQ6IDAsXG4gIHN1cHByZXNzU2Nyb2xsWDogZmFsc2UsXG4gIHN1cHByZXNzU2Nyb2xsWTogZmFsc2UsXG4gIHN3aXBlUHJvcGFnYXRpb246IHRydWUsXG4gIHN3aXBlRWFzaW5nOiB0cnVlLFxuICB1c2VCb3RoV2hlZWxBeGVzOiBmYWxzZSxcbiAgd2hlZWxQcm9wYWdhdGlvbjogZmFsc2UsXG4gIHdoZWVsU3BlZWQ6IDEsXG4gIHRoZW1lOiAnZGVmYXVsdCdcbn07XG5cbn0se31dLDk6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgXyA9IHJlcXVpcmUoJy4uL2xpYi9oZWxwZXInKTtcbnZhciBkb20gPSByZXF1aXJlKCcuLi9saWIvZG9tJyk7XG52YXIgaW5zdGFuY2VzID0gcmVxdWlyZSgnLi9pbnN0YW5jZXMnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICB2YXIgaSA9IGluc3RhbmNlcy5nZXQoZWxlbWVudCk7XG5cbiAgaWYgKCFpKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgaS5ldmVudC51bmJpbmRBbGwoKTtcbiAgZG9tLnJlbW92ZShpLnNjcm9sbGJhclgpO1xuICBkb20ucmVtb3ZlKGkuc2Nyb2xsYmFyWSk7XG4gIGRvbS5yZW1vdmUoaS5zY3JvbGxiYXJYUmFpbCk7XG4gIGRvbS5yZW1vdmUoaS5zY3JvbGxiYXJZUmFpbCk7XG4gIF8ucmVtb3ZlUHNDbGFzc2VzKGVsZW1lbnQpO1xuXG4gIGluc3RhbmNlcy5yZW1vdmUoZWxlbWVudCk7XG59O1xuXG59LHtcIi4uL2xpYi9kb21cIjozLFwiLi4vbGliL2hlbHBlclwiOjYsXCIuL2luc3RhbmNlc1wiOjE4fV0sMTA6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5zdGFuY2VzID0gcmVxdWlyZSgnLi4vaW5zdGFuY2VzJyk7XG52YXIgdXBkYXRlR2VvbWV0cnkgPSByZXF1aXJlKCcuLi91cGRhdGUtZ2VvbWV0cnknKTtcbnZhciB1cGRhdGVTY3JvbGwgPSByZXF1aXJlKCcuLi91cGRhdGUtc2Nyb2xsJyk7XG5cbmZ1bmN0aW9uIGJpbmRDbGlja1JhaWxIYW5kbGVyKGVsZW1lbnQsIGkpIHtcbiAgZnVuY3Rpb24gcGFnZU9mZnNldChlbCkge1xuICAgIHJldHVybiBlbC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgfVxuICB2YXIgc3RvcFByb3BhZ2F0aW9uID0gZnVuY3Rpb24gKGUpIHsgZS5zdG9wUHJvcGFnYXRpb24oKTsgfTtcblxuICBpLmV2ZW50LmJpbmQoaS5zY3JvbGxiYXJZLCAnY2xpY2snLCBzdG9wUHJvcGFnYXRpb24pO1xuICBpLmV2ZW50LmJpbmQoaS5zY3JvbGxiYXJZUmFpbCwgJ2NsaWNrJywgZnVuY3Rpb24gKGUpIHtcbiAgICB2YXIgcG9zaXRpb25Ub3AgPSBlLnBhZ2VZIC0gd2luZG93LnBhZ2VZT2Zmc2V0IC0gcGFnZU9mZnNldChpLnNjcm9sbGJhcllSYWlsKS50b3A7XG4gICAgdmFyIGRpcmVjdGlvbiA9IHBvc2l0aW9uVG9wID4gaS5zY3JvbGxiYXJZVG9wID8gMSA6IC0xO1xuXG4gICAgdXBkYXRlU2Nyb2xsKGVsZW1lbnQsICd0b3AnLCBlbGVtZW50LnNjcm9sbFRvcCArIGRpcmVjdGlvbiAqIGkuY29udGFpbmVySGVpZ2h0KTtcbiAgICB1cGRhdGVHZW9tZXRyeShlbGVtZW50KTtcblxuICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gIH0pO1xuXG4gIGkuZXZlbnQuYmluZChpLnNjcm9sbGJhclgsICdjbGljaycsIHN0b3BQcm9wYWdhdGlvbik7XG4gIGkuZXZlbnQuYmluZChpLnNjcm9sbGJhclhSYWlsLCAnY2xpY2snLCBmdW5jdGlvbiAoZSkge1xuICAgIHZhciBwb3NpdGlvbkxlZnQgPSBlLnBhZ2VYIC0gd2luZG93LnBhZ2VYT2Zmc2V0IC0gcGFnZU9mZnNldChpLnNjcm9sbGJhclhSYWlsKS5sZWZ0O1xuICAgIHZhciBkaXJlY3Rpb24gPSBwb3NpdGlvbkxlZnQgPiBpLnNjcm9sbGJhclhMZWZ0ID8gMSA6IC0xO1xuXG4gICAgdXBkYXRlU2Nyb2xsKGVsZW1lbnQsICdsZWZ0JywgZWxlbWVudC5zY3JvbGxMZWZ0ICsgZGlyZWN0aW9uICogaS5jb250YWluZXJXaWR0aCk7XG4gICAgdXBkYXRlR2VvbWV0cnkoZWxlbWVudCk7XG5cbiAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICB9KTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICB2YXIgaSA9IGluc3RhbmNlcy5nZXQoZWxlbWVudCk7XG4gIGJpbmRDbGlja1JhaWxIYW5kbGVyKGVsZW1lbnQsIGkpO1xufTtcblxufSx7XCIuLi9pbnN0YW5jZXNcIjoxOCxcIi4uL3VwZGF0ZS1nZW9tZXRyeVwiOjE5LFwiLi4vdXBkYXRlLXNjcm9sbFwiOjIwfV0sMTE6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgXyA9IHJlcXVpcmUoJy4uLy4uL2xpYi9oZWxwZXInKTtcbnZhciBkb20gPSByZXF1aXJlKCcuLi8uLi9saWIvZG9tJyk7XG52YXIgaW5zdGFuY2VzID0gcmVxdWlyZSgnLi4vaW5zdGFuY2VzJyk7XG52YXIgdXBkYXRlR2VvbWV0cnkgPSByZXF1aXJlKCcuLi91cGRhdGUtZ2VvbWV0cnknKTtcbnZhciB1cGRhdGVTY3JvbGwgPSByZXF1aXJlKCcuLi91cGRhdGUtc2Nyb2xsJyk7XG5cbmZ1bmN0aW9uIGJpbmRNb3VzZVNjcm9sbFhIYW5kbGVyKGVsZW1lbnQsIGkpIHtcbiAgdmFyIGN1cnJlbnRMZWZ0ID0gbnVsbDtcbiAgdmFyIGN1cnJlbnRQYWdlWCA9IG51bGw7XG5cbiAgZnVuY3Rpb24gdXBkYXRlU2Nyb2xsTGVmdChkZWx0YVgpIHtcbiAgICB2YXIgbmV3TGVmdCA9IGN1cnJlbnRMZWZ0ICsgKGRlbHRhWCAqIGkucmFpbFhSYXRpbyk7XG4gICAgdmFyIG1heExlZnQgPSBNYXRoLm1heCgwLCBpLnNjcm9sbGJhclhSYWlsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQpICsgKGkucmFpbFhSYXRpbyAqIChpLnJhaWxYV2lkdGggLSBpLnNjcm9sbGJhclhXaWR0aCkpO1xuXG4gICAgaWYgKG5ld0xlZnQgPCAwKSB7XG4gICAgICBpLnNjcm9sbGJhclhMZWZ0ID0gMDtcbiAgICB9IGVsc2UgaWYgKG5ld0xlZnQgPiBtYXhMZWZ0KSB7XG4gICAgICBpLnNjcm9sbGJhclhMZWZ0ID0gbWF4TGVmdDtcbiAgICB9IGVsc2Uge1xuICAgICAgaS5zY3JvbGxiYXJYTGVmdCA9IG5ld0xlZnQ7XG4gICAgfVxuXG4gICAgdmFyIHNjcm9sbExlZnQgPSBfLnRvSW50KGkuc2Nyb2xsYmFyWExlZnQgKiAoaS5jb250ZW50V2lkdGggLSBpLmNvbnRhaW5lcldpZHRoKSAvIChpLmNvbnRhaW5lcldpZHRoIC0gKGkucmFpbFhSYXRpbyAqIGkuc2Nyb2xsYmFyWFdpZHRoKSkpIC0gaS5uZWdhdGl2ZVNjcm9sbEFkanVzdG1lbnQ7XG4gICAgdXBkYXRlU2Nyb2xsKGVsZW1lbnQsICdsZWZ0Jywgc2Nyb2xsTGVmdCk7XG4gIH1cblxuICB2YXIgbW91c2VNb3ZlSGFuZGxlciA9IGZ1bmN0aW9uIChlKSB7XG4gICAgdXBkYXRlU2Nyb2xsTGVmdChlLnBhZ2VYIC0gY3VycmVudFBhZ2VYKTtcbiAgICB1cGRhdGVHZW9tZXRyeShlbGVtZW50KTtcbiAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgfTtcblxuICB2YXIgbW91c2VVcEhhbmRsZXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgXy5zdG9wU2Nyb2xsaW5nKGVsZW1lbnQsICd4Jyk7XG4gICAgaS5ldmVudC51bmJpbmQoaS5vd25lckRvY3VtZW50LCAnbW91c2Vtb3ZlJywgbW91c2VNb3ZlSGFuZGxlcik7XG4gIH07XG5cbiAgaS5ldmVudC5iaW5kKGkuc2Nyb2xsYmFyWCwgJ21vdXNlZG93bicsIGZ1bmN0aW9uIChlKSB7XG4gICAgY3VycmVudFBhZ2VYID0gZS5wYWdlWDtcbiAgICBjdXJyZW50TGVmdCA9IF8udG9JbnQoZG9tLmNzcyhpLnNjcm9sbGJhclgsICdsZWZ0JykpICogaS5yYWlsWFJhdGlvO1xuICAgIF8uc3RhcnRTY3JvbGxpbmcoZWxlbWVudCwgJ3gnKTtcblxuICAgIGkuZXZlbnQuYmluZChpLm93bmVyRG9jdW1lbnQsICdtb3VzZW1vdmUnLCBtb3VzZU1vdmVIYW5kbGVyKTtcbiAgICBpLmV2ZW50Lm9uY2UoaS5vd25lckRvY3VtZW50LCAnbW91c2V1cCcsIG1vdXNlVXBIYW5kbGVyKTtcblxuICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICB9KTtcbn1cblxuZnVuY3Rpb24gYmluZE1vdXNlU2Nyb2xsWUhhbmRsZXIoZWxlbWVudCwgaSkge1xuICB2YXIgY3VycmVudFRvcCA9IG51bGw7XG4gIHZhciBjdXJyZW50UGFnZVkgPSBudWxsO1xuXG4gIGZ1bmN0aW9uIHVwZGF0ZVNjcm9sbFRvcChkZWx0YVkpIHtcbiAgICB2YXIgbmV3VG9wID0gY3VycmVudFRvcCArIChkZWx0YVkgKiBpLnJhaWxZUmF0aW8pO1xuICAgIHZhciBtYXhUb3AgPSBNYXRoLm1heCgwLCBpLnNjcm9sbGJhcllSYWlsLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnRvcCkgKyAoaS5yYWlsWVJhdGlvICogKGkucmFpbFlIZWlnaHQgLSBpLnNjcm9sbGJhcllIZWlnaHQpKTtcblxuICAgIGlmIChuZXdUb3AgPCAwKSB7XG4gICAgICBpLnNjcm9sbGJhcllUb3AgPSAwO1xuICAgIH0gZWxzZSBpZiAobmV3VG9wID4gbWF4VG9wKSB7XG4gICAgICBpLnNjcm9sbGJhcllUb3AgPSBtYXhUb3A7XG4gICAgfSBlbHNlIHtcbiAgICAgIGkuc2Nyb2xsYmFyWVRvcCA9IG5ld1RvcDtcbiAgICB9XG5cbiAgICB2YXIgc2Nyb2xsVG9wID0gXy50b0ludChpLnNjcm9sbGJhcllUb3AgKiAoaS5jb250ZW50SGVpZ2h0IC0gaS5jb250YWluZXJIZWlnaHQpIC8gKGkuY29udGFpbmVySGVpZ2h0IC0gKGkucmFpbFlSYXRpbyAqIGkuc2Nyb2xsYmFyWUhlaWdodCkpKTtcbiAgICB1cGRhdGVTY3JvbGwoZWxlbWVudCwgJ3RvcCcsIHNjcm9sbFRvcCk7XG4gIH1cblxuICB2YXIgbW91c2VNb3ZlSGFuZGxlciA9IGZ1bmN0aW9uIChlKSB7XG4gICAgdXBkYXRlU2Nyb2xsVG9wKGUucGFnZVkgLSBjdXJyZW50UGFnZVkpO1xuICAgIHVwZGF0ZUdlb21ldHJ5KGVsZW1lbnQpO1xuICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICB9O1xuXG4gIHZhciBtb3VzZVVwSGFuZGxlciA9IGZ1bmN0aW9uICgpIHtcbiAgICBfLnN0b3BTY3JvbGxpbmcoZWxlbWVudCwgJ3knKTtcbiAgICBpLmV2ZW50LnVuYmluZChpLm93bmVyRG9jdW1lbnQsICdtb3VzZW1vdmUnLCBtb3VzZU1vdmVIYW5kbGVyKTtcbiAgfTtcblxuICBpLmV2ZW50LmJpbmQoaS5zY3JvbGxiYXJZLCAnbW91c2Vkb3duJywgZnVuY3Rpb24gKGUpIHtcbiAgICBjdXJyZW50UGFnZVkgPSBlLnBhZ2VZO1xuICAgIGN1cnJlbnRUb3AgPSBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJZLCAndG9wJykpICogaS5yYWlsWVJhdGlvO1xuICAgIF8uc3RhcnRTY3JvbGxpbmcoZWxlbWVudCwgJ3knKTtcblxuICAgIGkuZXZlbnQuYmluZChpLm93bmVyRG9jdW1lbnQsICdtb3VzZW1vdmUnLCBtb3VzZU1vdmVIYW5kbGVyKTtcbiAgICBpLmV2ZW50Lm9uY2UoaS5vd25lckRvY3VtZW50LCAnbW91c2V1cCcsIG1vdXNlVXBIYW5kbGVyKTtcblxuICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICB9KTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICB2YXIgaSA9IGluc3RhbmNlcy5nZXQoZWxlbWVudCk7XG4gIGJpbmRNb3VzZVNjcm9sbFhIYW5kbGVyKGVsZW1lbnQsIGkpO1xuICBiaW5kTW91c2VTY3JvbGxZSGFuZGxlcihlbGVtZW50LCBpKTtcbn07XG5cbn0se1wiLi4vLi4vbGliL2RvbVwiOjMsXCIuLi8uLi9saWIvaGVscGVyXCI6NixcIi4uL2luc3RhbmNlc1wiOjE4LFwiLi4vdXBkYXRlLWdlb21ldHJ5XCI6MTksXCIuLi91cGRhdGUtc2Nyb2xsXCI6MjB9XSwxMjpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbnZhciBfID0gcmVxdWlyZSgnLi4vLi4vbGliL2hlbHBlcicpO1xudmFyIGRvbSA9IHJlcXVpcmUoJy4uLy4uL2xpYi9kb20nKTtcbnZhciBpbnN0YW5jZXMgPSByZXF1aXJlKCcuLi9pbnN0YW5jZXMnKTtcbnZhciB1cGRhdGVHZW9tZXRyeSA9IHJlcXVpcmUoJy4uL3VwZGF0ZS1nZW9tZXRyeScpO1xudmFyIHVwZGF0ZVNjcm9sbCA9IHJlcXVpcmUoJy4uL3VwZGF0ZS1zY3JvbGwnKTtcblxuZnVuY3Rpb24gYmluZEtleWJvYXJkSGFuZGxlcihlbGVtZW50LCBpKSB7XG4gIHZhciBob3ZlcmVkID0gZmFsc2U7XG4gIGkuZXZlbnQuYmluZChlbGVtZW50LCAnbW91c2VlbnRlcicsIGZ1bmN0aW9uICgpIHtcbiAgICBob3ZlcmVkID0gdHJ1ZTtcbiAgfSk7XG4gIGkuZXZlbnQuYmluZChlbGVtZW50LCAnbW91c2VsZWF2ZScsIGZ1bmN0aW9uICgpIHtcbiAgICBob3ZlcmVkID0gZmFsc2U7XG4gIH0pO1xuXG4gIHZhciBzaG91bGRQcmV2ZW50ID0gZmFsc2U7XG4gIGZ1bmN0aW9uIHNob3VsZFByZXZlbnREZWZhdWx0KGRlbHRhWCwgZGVsdGFZKSB7XG4gICAgdmFyIHNjcm9sbFRvcCA9IGVsZW1lbnQuc2Nyb2xsVG9wO1xuICAgIGlmIChkZWx0YVggPT09IDApIHtcbiAgICAgIGlmICghaS5zY3JvbGxiYXJZQWN0aXZlKSB7XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH1cbiAgICAgIGlmICgoc2Nyb2xsVG9wID09PSAwICYmIGRlbHRhWSA+IDApIHx8IChzY3JvbGxUb3AgPj0gaS5jb250ZW50SGVpZ2h0IC0gaS5jb250YWluZXJIZWlnaHQgJiYgZGVsdGFZIDwgMCkpIHtcbiAgICAgICAgcmV0dXJuICFpLnNldHRpbmdzLndoZWVsUHJvcGFnYXRpb247XG4gICAgICB9XG4gICAgfVxuXG4gICAgdmFyIHNjcm9sbExlZnQgPSBlbGVtZW50LnNjcm9sbExlZnQ7XG4gICAgaWYgKGRlbHRhWSA9PT0gMCkge1xuICAgICAgaWYgKCFpLnNjcm9sbGJhclhBY3RpdmUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgaWYgKChzY3JvbGxMZWZ0ID09PSAwICYmIGRlbHRhWCA8IDApIHx8IChzY3JvbGxMZWZ0ID49IGkuY29udGVudFdpZHRoIC0gaS5jb250YWluZXJXaWR0aCAmJiBkZWx0YVggPiAwKSkge1xuICAgICAgICByZXR1cm4gIWkuc2V0dGluZ3Mud2hlZWxQcm9wYWdhdGlvbjtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRydWU7XG4gIH1cblxuICBpLmV2ZW50LmJpbmQoaS5vd25lckRvY3VtZW50LCAna2V5ZG93bicsIGZ1bmN0aW9uIChlKSB7XG4gICAgaWYgKChlLmlzRGVmYXVsdFByZXZlbnRlZCAmJiBlLmlzRGVmYXVsdFByZXZlbnRlZCgpKSB8fCBlLmRlZmF1bHRQcmV2ZW50ZWQpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgZm9jdXNlZCA9IGRvbS5tYXRjaGVzKGkuc2Nyb2xsYmFyWCwgJzpmb2N1cycpIHx8XG4gICAgICAgICAgICAgICAgICBkb20ubWF0Y2hlcyhpLnNjcm9sbGJhclksICc6Zm9jdXMnKTtcblxuICAgIGlmICghaG92ZXJlZCAmJiAhZm9jdXNlZCkge1xuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBhY3RpdmVFbGVtZW50ID0gZG9jdW1lbnQuYWN0aXZlRWxlbWVudCA/IGRvY3VtZW50LmFjdGl2ZUVsZW1lbnQgOiBpLm93bmVyRG9jdW1lbnQuYWN0aXZlRWxlbWVudDtcbiAgICBpZiAoYWN0aXZlRWxlbWVudCkge1xuICAgICAgaWYgKGFjdGl2ZUVsZW1lbnQudGFnTmFtZSA9PT0gJ0lGUkFNRScpIHtcbiAgICAgICAgYWN0aXZlRWxlbWVudCA9IGFjdGl2ZUVsZW1lbnQuY29udGVudERvY3VtZW50LmFjdGl2ZUVsZW1lbnQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBnbyBkZWVwZXIgaWYgZWxlbWVudCBpcyBhIHdlYmNvbXBvbmVudFxuICAgICAgICB3aGlsZSAoYWN0aXZlRWxlbWVudC5zaGFkb3dSb290KSB7XG4gICAgICAgICAgYWN0aXZlRWxlbWVudCA9IGFjdGl2ZUVsZW1lbnQuc2hhZG93Um9vdC5hY3RpdmVFbGVtZW50O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoXy5pc0VkaXRhYmxlKGFjdGl2ZUVsZW1lbnQpKSB7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgZGVsdGFYID0gMDtcbiAgICB2YXIgZGVsdGFZID0gMDtcblxuICAgIHN3aXRjaCAoZS53aGljaCkge1xuICAgIGNhc2UgMzc6IC8vIGxlZnRcbiAgICAgIGlmIChlLm1ldGFLZXkpIHtcbiAgICAgICAgZGVsdGFYID0gLWkuY29udGVudFdpZHRoO1xuICAgICAgfSBlbHNlIGlmIChlLmFsdEtleSkge1xuICAgICAgICBkZWx0YVggPSAtaS5jb250YWluZXJXaWR0aDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRlbHRhWCA9IC0zMDtcbiAgICAgIH1cbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgMzg6IC8vIHVwXG4gICAgICBpZiAoZS5tZXRhS2V5KSB7XG4gICAgICAgIGRlbHRhWSA9IGkuY29udGVudEhlaWdodDtcbiAgICAgIH0gZWxzZSBpZiAoZS5hbHRLZXkpIHtcbiAgICAgICAgZGVsdGFZID0gaS5jb250YWluZXJIZWlnaHQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkZWx0YVkgPSAzMDtcbiAgICAgIH1cbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgMzk6IC8vIHJpZ2h0XG4gICAgICBpZiAoZS5tZXRhS2V5KSB7XG4gICAgICAgIGRlbHRhWCA9IGkuY29udGVudFdpZHRoO1xuICAgICAgfSBlbHNlIGlmIChlLmFsdEtleSkge1xuICAgICAgICBkZWx0YVggPSBpLmNvbnRhaW5lcldpZHRoO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGVsdGFYID0gMzA7XG4gICAgICB9XG4gICAgICBicmVhaztcbiAgICBjYXNlIDQwOiAvLyBkb3duXG4gICAgICBpZiAoZS5tZXRhS2V5KSB7XG4gICAgICAgIGRlbHRhWSA9IC1pLmNvbnRlbnRIZWlnaHQ7XG4gICAgICB9IGVsc2UgaWYgKGUuYWx0S2V5KSB7XG4gICAgICAgIGRlbHRhWSA9IC1pLmNvbnRhaW5lckhlaWdodDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRlbHRhWSA9IC0zMDtcbiAgICAgIH1cbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgMzM6IC8vIHBhZ2UgdXBcbiAgICAgIGRlbHRhWSA9IDkwO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAzMjogLy8gc3BhY2UgYmFyXG4gICAgICBpZiAoZS5zaGlmdEtleSkge1xuICAgICAgICBkZWx0YVkgPSA5MDtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGRlbHRhWSA9IC05MDtcbiAgICAgIH1cbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgMzQ6IC8vIHBhZ2UgZG93blxuICAgICAgZGVsdGFZID0gLTkwO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSAzNTogLy8gZW5kXG4gICAgICBpZiAoZS5jdHJsS2V5KSB7XG4gICAgICAgIGRlbHRhWSA9IC1pLmNvbnRlbnRIZWlnaHQ7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkZWx0YVkgPSAtaS5jb250YWluZXJIZWlnaHQ7XG4gICAgICB9XG4gICAgICBicmVhaztcbiAgICBjYXNlIDM2OiAvLyBob21lXG4gICAgICBpZiAoZS5jdHJsS2V5KSB7XG4gICAgICAgIGRlbHRhWSA9IGVsZW1lbnQuc2Nyb2xsVG9wO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGVsdGFZID0gaS5jb250YWluZXJIZWlnaHQ7XG4gICAgICB9XG4gICAgICBicmVhaztcbiAgICBkZWZhdWx0OlxuICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHVwZGF0ZVNjcm9sbChlbGVtZW50LCAndG9wJywgZWxlbWVudC5zY3JvbGxUb3AgLSBkZWx0YVkpO1xuICAgIHVwZGF0ZVNjcm9sbChlbGVtZW50LCAnbGVmdCcsIGVsZW1lbnQuc2Nyb2xsTGVmdCArIGRlbHRhWCk7XG4gICAgdXBkYXRlR2VvbWV0cnkoZWxlbWVudCk7XG5cbiAgICBzaG91bGRQcmV2ZW50ID0gc2hvdWxkUHJldmVudERlZmF1bHQoZGVsdGFYLCBkZWx0YVkpO1xuICAgIGlmIChzaG91bGRQcmV2ZW50KSB7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuICB9KTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICB2YXIgaSA9IGluc3RhbmNlcy5nZXQoZWxlbWVudCk7XG4gIGJpbmRLZXlib2FyZEhhbmRsZXIoZWxlbWVudCwgaSk7XG59O1xuXG59LHtcIi4uLy4uL2xpYi9kb21cIjozLFwiLi4vLi4vbGliL2hlbHBlclwiOjYsXCIuLi9pbnN0YW5jZXNcIjoxOCxcIi4uL3VwZGF0ZS1nZW9tZXRyeVwiOjE5LFwiLi4vdXBkYXRlLXNjcm9sbFwiOjIwfV0sMTM6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5zdGFuY2VzID0gcmVxdWlyZSgnLi4vaW5zdGFuY2VzJyk7XG52YXIgdXBkYXRlR2VvbWV0cnkgPSByZXF1aXJlKCcuLi91cGRhdGUtZ2VvbWV0cnknKTtcbnZhciB1cGRhdGVTY3JvbGwgPSByZXF1aXJlKCcuLi91cGRhdGUtc2Nyb2xsJyk7XG5cbmZ1bmN0aW9uIGJpbmRNb3VzZVdoZWVsSGFuZGxlcihlbGVtZW50LCBpKSB7XG4gIHZhciBzaG91bGRQcmV2ZW50ID0gZmFsc2U7XG5cbiAgZnVuY3Rpb24gc2hvdWxkUHJldmVudERlZmF1bHQoZGVsdGFYLCBkZWx0YVkpIHtcbiAgICB2YXIgc2Nyb2xsVG9wID0gZWxlbWVudC5zY3JvbGxUb3A7XG4gICAgaWYgKGRlbHRhWCA9PT0gMCkge1xuICAgICAgaWYgKCFpLnNjcm9sbGJhcllBY3RpdmUpIHtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgfVxuICAgICAgaWYgKChzY3JvbGxUb3AgPT09IDAgJiYgZGVsdGFZID4gMCkgfHwgKHNjcm9sbFRvcCA+PSBpLmNvbnRlbnRIZWlnaHQgLSBpLmNvbnRhaW5lckhlaWdodCAmJiBkZWx0YVkgPCAwKSkge1xuICAgICAgICByZXR1cm4gIWkuc2V0dGluZ3Mud2hlZWxQcm9wYWdhdGlvbjtcbiAgICAgIH1cbiAgICB9XG5cbiAgICB2YXIgc2Nyb2xsTGVmdCA9IGVsZW1lbnQuc2Nyb2xsTGVmdDtcbiAgICBpZiAoZGVsdGFZID09PSAwKSB7XG4gICAgICBpZiAoIWkuc2Nyb2xsYmFyWEFjdGl2ZSkge1xuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG4gICAgICBpZiAoKHNjcm9sbExlZnQgPT09IDAgJiYgZGVsdGFYIDwgMCkgfHwgKHNjcm9sbExlZnQgPj0gaS5jb250ZW50V2lkdGggLSBpLmNvbnRhaW5lcldpZHRoICYmIGRlbHRhWCA+IDApKSB7XG4gICAgICAgIHJldHVybiAhaS5zZXR0aW5ncy53aGVlbFByb3BhZ2F0aW9uO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gdHJ1ZTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGdldERlbHRhRnJvbUV2ZW50KGUpIHtcbiAgICB2YXIgZGVsdGFYID0gZS5kZWx0YVg7XG4gICAgdmFyIGRlbHRhWSA9IC0xICogZS5kZWx0YVk7XG5cbiAgICBpZiAodHlwZW9mIGRlbHRhWCA9PT0gXCJ1bmRlZmluZWRcIiB8fCB0eXBlb2YgZGVsdGFZID09PSBcInVuZGVmaW5lZFwiKSB7XG4gICAgICAvLyBPUyBYIFNhZmFyaVxuICAgICAgZGVsdGFYID0gLTEgKiBlLndoZWVsRGVsdGFYIC8gNjtcbiAgICAgIGRlbHRhWSA9IGUud2hlZWxEZWx0YVkgLyA2O1xuICAgIH1cblxuICAgIGlmIChlLmRlbHRhTW9kZSAmJiBlLmRlbHRhTW9kZSA9PT0gMSkge1xuICAgICAgLy8gRmlyZWZveCBpbiBkZWx0YU1vZGUgMTogTGluZSBzY3JvbGxpbmdcbiAgICAgIGRlbHRhWCAqPSAxMDtcbiAgICAgIGRlbHRhWSAqPSAxMDtcbiAgICB9XG5cbiAgICBpZiAoZGVsdGFYICE9PSBkZWx0YVggJiYgZGVsdGFZICE9PSBkZWx0YVkvKiBOYU4gY2hlY2tzICovKSB7XG4gICAgICAvLyBJRSBpbiBzb21lIG1vdXNlIGRyaXZlcnNcbiAgICAgIGRlbHRhWCA9IDA7XG4gICAgICBkZWx0YVkgPSBlLndoZWVsRGVsdGE7XG4gICAgfVxuXG4gICAgaWYgKGUuc2hpZnRLZXkpIHtcbiAgICAgIC8vIHJldmVyc2UgYXhpcyB3aXRoIHNoaWZ0IGtleVxuICAgICAgcmV0dXJuIFstZGVsdGFZLCAtZGVsdGFYXTtcbiAgICB9XG4gICAgcmV0dXJuIFtkZWx0YVgsIGRlbHRhWV07XG4gIH1cblxuICBmdW5jdGlvbiBzaG91bGRCZUNvbnN1bWVkQnlDaGlsZChkZWx0YVgsIGRlbHRhWSkge1xuICAgIHZhciBjaGlsZCA9IGVsZW1lbnQucXVlcnlTZWxlY3RvcigndGV4dGFyZWE6aG92ZXIsIHNlbGVjdFttdWx0aXBsZV06aG92ZXIsIC5wcy1jaGlsZDpob3ZlcicpO1xuICAgIGlmIChjaGlsZCkge1xuICAgICAgdmFyIHN0eWxlID0gd2luZG93LmdldENvbXB1dGVkU3R5bGUoY2hpbGQpO1xuICAgICAgdmFyIG92ZXJmbG93ID0gW1xuICAgICAgICBzdHlsZS5vdmVyZmxvdyxcbiAgICAgICAgc3R5bGUub3ZlcmZsb3dYLFxuICAgICAgICBzdHlsZS5vdmVyZmxvd1lcbiAgICAgIF0uam9pbignJyk7XG5cbiAgICAgIGlmICghb3ZlcmZsb3cubWF0Y2goLyhzY3JvbGx8YXV0bykvKSkge1xuICAgICAgICAvLyBpZiBub3Qgc2Nyb2xsYWJsZVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICB9XG5cbiAgICAgIHZhciBtYXhTY3JvbGxUb3AgPSBjaGlsZC5zY3JvbGxIZWlnaHQgLSBjaGlsZC5jbGllbnRIZWlnaHQ7XG4gICAgICBpZiAobWF4U2Nyb2xsVG9wID4gMCkge1xuICAgICAgICBpZiAoIShjaGlsZC5zY3JvbGxUb3AgPT09IDAgJiYgZGVsdGFZID4gMCkgJiYgIShjaGlsZC5zY3JvbGxUb3AgPT09IG1heFNjcm9sbFRvcCAmJiBkZWx0YVkgPCAwKSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICB2YXIgbWF4U2Nyb2xsTGVmdCA9IGNoaWxkLnNjcm9sbExlZnQgLSBjaGlsZC5jbGllbnRXaWR0aDtcbiAgICAgIGlmIChtYXhTY3JvbGxMZWZ0ID4gMCkge1xuICAgICAgICBpZiAoIShjaGlsZC5zY3JvbGxMZWZ0ID09PSAwICYmIGRlbHRhWCA8IDApICYmICEoY2hpbGQuc2Nyb2xsTGVmdCA9PT0gbWF4U2Nyb2xsTGVmdCAmJiBkZWx0YVggPiAwKSkge1xuICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG1vdXNld2hlZWxIYW5kbGVyKGUpIHtcbiAgICB2YXIgZGVsdGEgPSBnZXREZWx0YUZyb21FdmVudChlKTtcblxuICAgIHZhciBkZWx0YVggPSBkZWx0YVswXTtcbiAgICB2YXIgZGVsdGFZID0gZGVsdGFbMV07XG5cbiAgICBpZiAoc2hvdWxkQmVDb25zdW1lZEJ5Q2hpbGQoZGVsdGFYLCBkZWx0YVkpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgc2hvdWxkUHJldmVudCA9IGZhbHNlO1xuICAgIGlmICghaS5zZXR0aW5ncy51c2VCb3RoV2hlZWxBeGVzKSB7XG4gICAgICAvLyBkZWx0YVggd2lsbCBvbmx5IGJlIHVzZWQgZm9yIGhvcml6b250YWwgc2Nyb2xsaW5nIGFuZCBkZWx0YVkgd2lsbFxuICAgICAgLy8gb25seSBiZSB1c2VkIGZvciB2ZXJ0aWNhbCBzY3JvbGxpbmcgLSB0aGlzIGlzIHRoZSBkZWZhdWx0XG4gICAgICB1cGRhdGVTY3JvbGwoZWxlbWVudCwgJ3RvcCcsIGVsZW1lbnQuc2Nyb2xsVG9wIC0gKGRlbHRhWSAqIGkuc2V0dGluZ3Mud2hlZWxTcGVlZCkpO1xuICAgICAgdXBkYXRlU2Nyb2xsKGVsZW1lbnQsICdsZWZ0JywgZWxlbWVudC5zY3JvbGxMZWZ0ICsgKGRlbHRhWCAqIGkuc2V0dGluZ3Mud2hlZWxTcGVlZCkpO1xuICAgIH0gZWxzZSBpZiAoaS5zY3JvbGxiYXJZQWN0aXZlICYmICFpLnNjcm9sbGJhclhBY3RpdmUpIHtcbiAgICAgIC8vIG9ubHkgdmVydGljYWwgc2Nyb2xsYmFyIGlzIGFjdGl2ZSBhbmQgdXNlQm90aFdoZWVsQXhlcyBvcHRpb24gaXNcbiAgICAgIC8vIGFjdGl2ZSwgc28gbGV0J3Mgc2Nyb2xsIHZlcnRpY2FsIGJhciB1c2luZyBib3RoIG1vdXNlIHdoZWVsIGF4ZXNcbiAgICAgIGlmIChkZWx0YVkpIHtcbiAgICAgICAgdXBkYXRlU2Nyb2xsKGVsZW1lbnQsICd0b3AnLCBlbGVtZW50LnNjcm9sbFRvcCAtIChkZWx0YVkgKiBpLnNldHRpbmdzLndoZWVsU3BlZWQpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHVwZGF0ZVNjcm9sbChlbGVtZW50LCAndG9wJywgZWxlbWVudC5zY3JvbGxUb3AgKyAoZGVsdGFYICogaS5zZXR0aW5ncy53aGVlbFNwZWVkKSk7XG4gICAgICB9XG4gICAgICBzaG91bGRQcmV2ZW50ID0gdHJ1ZTtcbiAgICB9IGVsc2UgaWYgKGkuc2Nyb2xsYmFyWEFjdGl2ZSAmJiAhaS5zY3JvbGxiYXJZQWN0aXZlKSB7XG4gICAgICAvLyB1c2VCb3RoV2hlZWxBeGVzIGFuZCBvbmx5IGhvcml6b250YWwgYmFyIGlzIGFjdGl2ZSwgc28gdXNlIGJvdGhcbiAgICAgIC8vIHdoZWVsIGF4ZXMgZm9yIGhvcml6b250YWwgYmFyXG4gICAgICBpZiAoZGVsdGFYKSB7XG4gICAgICAgIHVwZGF0ZVNjcm9sbChlbGVtZW50LCAnbGVmdCcsIGVsZW1lbnQuc2Nyb2xsTGVmdCArIChkZWx0YVggKiBpLnNldHRpbmdzLndoZWVsU3BlZWQpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHVwZGF0ZVNjcm9sbChlbGVtZW50LCAnbGVmdCcsIGVsZW1lbnQuc2Nyb2xsTGVmdCAtIChkZWx0YVkgKiBpLnNldHRpbmdzLndoZWVsU3BlZWQpKTtcbiAgICAgIH1cbiAgICAgIHNob3VsZFByZXZlbnQgPSB0cnVlO1xuICAgIH1cblxuICAgIHVwZGF0ZUdlb21ldHJ5KGVsZW1lbnQpO1xuXG4gICAgc2hvdWxkUHJldmVudCA9IChzaG91bGRQcmV2ZW50IHx8IHNob3VsZFByZXZlbnREZWZhdWx0KGRlbHRhWCwgZGVsdGFZKSk7XG4gICAgaWYgKHNob3VsZFByZXZlbnQpIHtcbiAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgfVxuICB9XG5cbiAgaWYgKHR5cGVvZiB3aW5kb3cub253aGVlbCAhPT0gXCJ1bmRlZmluZWRcIikge1xuICAgIGkuZXZlbnQuYmluZChlbGVtZW50LCAnd2hlZWwnLCBtb3VzZXdoZWVsSGFuZGxlcik7XG4gIH0gZWxzZSBpZiAodHlwZW9mIHdpbmRvdy5vbm1vdXNld2hlZWwgIT09IFwidW5kZWZpbmVkXCIpIHtcbiAgICBpLmV2ZW50LmJpbmQoZWxlbWVudCwgJ21vdXNld2hlZWwnLCBtb3VzZXdoZWVsSGFuZGxlcik7XG4gIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICB2YXIgaSA9IGluc3RhbmNlcy5nZXQoZWxlbWVudCk7XG4gIGJpbmRNb3VzZVdoZWVsSGFuZGxlcihlbGVtZW50LCBpKTtcbn07XG5cbn0se1wiLi4vaW5zdGFuY2VzXCI6MTgsXCIuLi91cGRhdGUtZ2VvbWV0cnlcIjoxOSxcIi4uL3VwZGF0ZS1zY3JvbGxcIjoyMH1dLDE0OltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxudmFyIGluc3RhbmNlcyA9IHJlcXVpcmUoJy4uL2luc3RhbmNlcycpO1xudmFyIHVwZGF0ZUdlb21ldHJ5ID0gcmVxdWlyZSgnLi4vdXBkYXRlLWdlb21ldHJ5Jyk7XG5cbmZ1bmN0aW9uIGJpbmROYXRpdmVTY3JvbGxIYW5kbGVyKGVsZW1lbnQsIGkpIHtcbiAgaS5ldmVudC5iaW5kKGVsZW1lbnQsICdzY3JvbGwnLCBmdW5jdGlvbiAoKSB7XG4gICAgdXBkYXRlR2VvbWV0cnkoZWxlbWVudCk7XG4gIH0pO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gIHZhciBpID0gaW5zdGFuY2VzLmdldChlbGVtZW50KTtcbiAgYmluZE5hdGl2ZVNjcm9sbEhhbmRsZXIoZWxlbWVudCwgaSk7XG59O1xuXG59LHtcIi4uL2luc3RhbmNlc1wiOjE4LFwiLi4vdXBkYXRlLWdlb21ldHJ5XCI6MTl9XSwxNTpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbnZhciBfID0gcmVxdWlyZSgnLi4vLi4vbGliL2hlbHBlcicpO1xudmFyIGluc3RhbmNlcyA9IHJlcXVpcmUoJy4uL2luc3RhbmNlcycpO1xudmFyIHVwZGF0ZUdlb21ldHJ5ID0gcmVxdWlyZSgnLi4vdXBkYXRlLWdlb21ldHJ5Jyk7XG52YXIgdXBkYXRlU2Nyb2xsID0gcmVxdWlyZSgnLi4vdXBkYXRlLXNjcm9sbCcpO1xuXG5mdW5jdGlvbiBiaW5kU2VsZWN0aW9uSGFuZGxlcihlbGVtZW50LCBpKSB7XG4gIGZ1bmN0aW9uIGdldFJhbmdlTm9kZSgpIHtcbiAgICB2YXIgc2VsZWN0aW9uID0gd2luZG93LmdldFNlbGVjdGlvbiA/IHdpbmRvdy5nZXRTZWxlY3Rpb24oKSA6XG4gICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldFNlbGVjdGlvbiA/IGRvY3VtZW50LmdldFNlbGVjdGlvbigpIDogJyc7XG4gICAgaWYgKHNlbGVjdGlvbi50b1N0cmluZygpLmxlbmd0aCA9PT0gMCkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBzZWxlY3Rpb24uZ2V0UmFuZ2VBdCgwKS5jb21tb25BbmNlc3RvckNvbnRhaW5lcjtcbiAgICB9XG4gIH1cblxuICB2YXIgc2Nyb2xsaW5nTG9vcCA9IG51bGw7XG4gIHZhciBzY3JvbGxEaWZmID0ge3RvcDogMCwgbGVmdDogMH07XG4gIGZ1bmN0aW9uIHN0YXJ0U2Nyb2xsaW5nKCkge1xuICAgIGlmICghc2Nyb2xsaW5nTG9vcCkge1xuICAgICAgc2Nyb2xsaW5nTG9vcCA9IHNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCFpbnN0YW5jZXMuZ2V0KGVsZW1lbnQpKSB7XG4gICAgICAgICAgY2xlYXJJbnRlcnZhbChzY3JvbGxpbmdMb29wKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB1cGRhdGVTY3JvbGwoZWxlbWVudCwgJ3RvcCcsIGVsZW1lbnQuc2Nyb2xsVG9wICsgc2Nyb2xsRGlmZi50b3ApO1xuICAgICAgICB1cGRhdGVTY3JvbGwoZWxlbWVudCwgJ2xlZnQnLCBlbGVtZW50LnNjcm9sbExlZnQgKyBzY3JvbGxEaWZmLmxlZnQpO1xuICAgICAgICB1cGRhdGVHZW9tZXRyeShlbGVtZW50KTtcbiAgICAgIH0sIDUwKTsgLy8gZXZlcnkgLjEgc2VjXG4gICAgfVxuICB9XG4gIGZ1bmN0aW9uIHN0b3BTY3JvbGxpbmcoKSB7XG4gICAgaWYgKHNjcm9sbGluZ0xvb3ApIHtcbiAgICAgIGNsZWFySW50ZXJ2YWwoc2Nyb2xsaW5nTG9vcCk7XG4gICAgICBzY3JvbGxpbmdMb29wID0gbnVsbDtcbiAgICB9XG4gICAgXy5zdG9wU2Nyb2xsaW5nKGVsZW1lbnQpO1xuICB9XG5cbiAgdmFyIGlzU2VsZWN0ZWQgPSBmYWxzZTtcbiAgaS5ldmVudC5iaW5kKGkub3duZXJEb2N1bWVudCwgJ3NlbGVjdGlvbmNoYW5nZScsIGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoZWxlbWVudC5jb250YWlucyhnZXRSYW5nZU5vZGUoKSkpIHtcbiAgICAgIGlzU2VsZWN0ZWQgPSB0cnVlO1xuICAgIH0gZWxzZSB7XG4gICAgICBpc1NlbGVjdGVkID0gZmFsc2U7XG4gICAgICBzdG9wU2Nyb2xsaW5nKCk7XG4gICAgfVxuICB9KTtcbiAgaS5ldmVudC5iaW5kKHdpbmRvdywgJ21vdXNldXAnLCBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKGlzU2VsZWN0ZWQpIHtcbiAgICAgIGlzU2VsZWN0ZWQgPSBmYWxzZTtcbiAgICAgIHN0b3BTY3JvbGxpbmcoKTtcbiAgICB9XG4gIH0pO1xuICBpLmV2ZW50LmJpbmQod2luZG93LCAna2V5dXAnLCBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKGlzU2VsZWN0ZWQpIHtcbiAgICAgIGlzU2VsZWN0ZWQgPSBmYWxzZTtcbiAgICAgIHN0b3BTY3JvbGxpbmcoKTtcbiAgICB9XG4gIH0pO1xuXG4gIGkuZXZlbnQuYmluZCh3aW5kb3csICdtb3VzZW1vdmUnLCBmdW5jdGlvbiAoZSkge1xuICAgIGlmIChpc1NlbGVjdGVkKSB7XG4gICAgICB2YXIgbW91c2VQb3NpdGlvbiA9IHt4OiBlLnBhZ2VYLCB5OiBlLnBhZ2VZfTtcbiAgICAgIHZhciBjb250YWluZXJHZW9tZXRyeSA9IHtcbiAgICAgICAgbGVmdDogZWxlbWVudC5vZmZzZXRMZWZ0LFxuICAgICAgICByaWdodDogZWxlbWVudC5vZmZzZXRMZWZ0ICsgZWxlbWVudC5vZmZzZXRXaWR0aCxcbiAgICAgICAgdG9wOiBlbGVtZW50Lm9mZnNldFRvcCxcbiAgICAgICAgYm90dG9tOiBlbGVtZW50Lm9mZnNldFRvcCArIGVsZW1lbnQub2Zmc2V0SGVpZ2h0XG4gICAgICB9O1xuXG4gICAgICBpZiAobW91c2VQb3NpdGlvbi54IDwgY29udGFpbmVyR2VvbWV0cnkubGVmdCArIDMpIHtcbiAgICAgICAgc2Nyb2xsRGlmZi5sZWZ0ID0gLTU7XG4gICAgICAgIF8uc3RhcnRTY3JvbGxpbmcoZWxlbWVudCwgJ3gnKTtcbiAgICAgIH0gZWxzZSBpZiAobW91c2VQb3NpdGlvbi54ID4gY29udGFpbmVyR2VvbWV0cnkucmlnaHQgLSAzKSB7XG4gICAgICAgIHNjcm9sbERpZmYubGVmdCA9IDU7XG4gICAgICAgIF8uc3RhcnRTY3JvbGxpbmcoZWxlbWVudCwgJ3gnKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNjcm9sbERpZmYubGVmdCA9IDA7XG4gICAgICB9XG5cbiAgICAgIGlmIChtb3VzZVBvc2l0aW9uLnkgPCBjb250YWluZXJHZW9tZXRyeS50b3AgKyAzKSB7XG4gICAgICAgIGlmIChjb250YWluZXJHZW9tZXRyeS50b3AgKyAzIC0gbW91c2VQb3NpdGlvbi55IDwgNSkge1xuICAgICAgICAgIHNjcm9sbERpZmYudG9wID0gLTU7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgc2Nyb2xsRGlmZi50b3AgPSAtMjA7XG4gICAgICAgIH1cbiAgICAgICAgXy5zdGFydFNjcm9sbGluZyhlbGVtZW50LCAneScpO1xuICAgICAgfSBlbHNlIGlmIChtb3VzZVBvc2l0aW9uLnkgPiBjb250YWluZXJHZW9tZXRyeS5ib3R0b20gLSAzKSB7XG4gICAgICAgIGlmIChtb3VzZVBvc2l0aW9uLnkgLSBjb250YWluZXJHZW9tZXRyeS5ib3R0b20gKyAzIDwgNSkge1xuICAgICAgICAgIHNjcm9sbERpZmYudG9wID0gNTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzY3JvbGxEaWZmLnRvcCA9IDIwO1xuICAgICAgICB9XG4gICAgICAgIF8uc3RhcnRTY3JvbGxpbmcoZWxlbWVudCwgJ3knKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNjcm9sbERpZmYudG9wID0gMDtcbiAgICAgIH1cblxuICAgICAgaWYgKHNjcm9sbERpZmYudG9wID09PSAwICYmIHNjcm9sbERpZmYubGVmdCA9PT0gMCkge1xuICAgICAgICBzdG9wU2Nyb2xsaW5nKCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBzdGFydFNjcm9sbGluZygpO1xuICAgICAgfVxuICAgIH1cbiAgfSk7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgdmFyIGkgPSBpbnN0YW5jZXMuZ2V0KGVsZW1lbnQpO1xuICBiaW5kU2VsZWN0aW9uSGFuZGxlcihlbGVtZW50LCBpKTtcbn07XG5cbn0se1wiLi4vLi4vbGliL2hlbHBlclwiOjYsXCIuLi9pbnN0YW5jZXNcIjoxOCxcIi4uL3VwZGF0ZS1nZW9tZXRyeVwiOjE5LFwiLi4vdXBkYXRlLXNjcm9sbFwiOjIwfV0sMTY6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgXyA9IHJlcXVpcmUoJy4uLy4uL2xpYi9oZWxwZXInKTtcbnZhciBpbnN0YW5jZXMgPSByZXF1aXJlKCcuLi9pbnN0YW5jZXMnKTtcbnZhciB1cGRhdGVHZW9tZXRyeSA9IHJlcXVpcmUoJy4uL3VwZGF0ZS1nZW9tZXRyeScpO1xudmFyIHVwZGF0ZVNjcm9sbCA9IHJlcXVpcmUoJy4uL3VwZGF0ZS1zY3JvbGwnKTtcblxuZnVuY3Rpb24gYmluZFRvdWNoSGFuZGxlcihlbGVtZW50LCBpLCBzdXBwb3J0c1RvdWNoLCBzdXBwb3J0c0llUG9pbnRlcikge1xuICBmdW5jdGlvbiBzaG91bGRQcmV2ZW50RGVmYXVsdChkZWx0YVgsIGRlbHRhWSkge1xuICAgIHZhciBzY3JvbGxUb3AgPSBlbGVtZW50LnNjcm9sbFRvcDtcbiAgICB2YXIgc2Nyb2xsTGVmdCA9IGVsZW1lbnQuc2Nyb2xsTGVmdDtcbiAgICB2YXIgbWFnbml0dWRlWCA9IE1hdGguYWJzKGRlbHRhWCk7XG4gICAgdmFyIG1hZ25pdHVkZVkgPSBNYXRoLmFicyhkZWx0YVkpO1xuXG4gICAgaWYgKG1hZ25pdHVkZVkgPiBtYWduaXR1ZGVYKSB7XG4gICAgICAvLyB1c2VyIGlzIHBlcmhhcHMgdHJ5aW5nIHRvIHN3aXBlIHVwL2Rvd24gdGhlIHBhZ2VcblxuICAgICAgaWYgKCgoZGVsdGFZIDwgMCkgJiYgKHNjcm9sbFRvcCA9PT0gaS5jb250ZW50SGVpZ2h0IC0gaS5jb250YWluZXJIZWlnaHQpKSB8fFxuICAgICAgICAgICgoZGVsdGFZID4gMCkgJiYgKHNjcm9sbFRvcCA9PT0gMCkpKSB7XG4gICAgICAgIHJldHVybiAhaS5zZXR0aW5ncy5zd2lwZVByb3BhZ2F0aW9uO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAobWFnbml0dWRlWCA+IG1hZ25pdHVkZVkpIHtcbiAgICAgIC8vIHVzZXIgaXMgcGVyaGFwcyB0cnlpbmcgdG8gc3dpcGUgbGVmdC9yaWdodCBhY3Jvc3MgdGhlIHBhZ2VcblxuICAgICAgaWYgKCgoZGVsdGFYIDwgMCkgJiYgKHNjcm9sbExlZnQgPT09IGkuY29udGVudFdpZHRoIC0gaS5jb250YWluZXJXaWR0aCkpIHx8XG4gICAgICAgICAgKChkZWx0YVggPiAwKSAmJiAoc2Nyb2xsTGVmdCA9PT0gMCkpKSB7XG4gICAgICAgIHJldHVybiAhaS5zZXR0aW5ncy5zd2lwZVByb3BhZ2F0aW9uO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgZnVuY3Rpb24gYXBwbHlUb3VjaE1vdmUoZGlmZmVyZW5jZVgsIGRpZmZlcmVuY2VZKSB7XG4gICAgdXBkYXRlU2Nyb2xsKGVsZW1lbnQsICd0b3AnLCBlbGVtZW50LnNjcm9sbFRvcCAtIGRpZmZlcmVuY2VZKTtcbiAgICB1cGRhdGVTY3JvbGwoZWxlbWVudCwgJ2xlZnQnLCBlbGVtZW50LnNjcm9sbExlZnQgLSBkaWZmZXJlbmNlWCk7XG5cbiAgICB1cGRhdGVHZW9tZXRyeShlbGVtZW50KTtcbiAgfVxuXG4gIHZhciBzdGFydE9mZnNldCA9IHt9O1xuICB2YXIgc3RhcnRUaW1lID0gMDtcbiAgdmFyIHNwZWVkID0ge307XG4gIHZhciBlYXNpbmdMb29wID0gbnVsbDtcbiAgdmFyIGluR2xvYmFsVG91Y2ggPSBmYWxzZTtcbiAgdmFyIGluTG9jYWxUb3VjaCA9IGZhbHNlO1xuXG4gIGZ1bmN0aW9uIGdsb2JhbFRvdWNoU3RhcnQoKSB7XG4gICAgaW5HbG9iYWxUb3VjaCA9IHRydWU7XG4gIH1cbiAgZnVuY3Rpb24gZ2xvYmFsVG91Y2hFbmQoKSB7XG4gICAgaW5HbG9iYWxUb3VjaCA9IGZhbHNlO1xuICB9XG5cbiAgZnVuY3Rpb24gZ2V0VG91Y2goZSkge1xuICAgIGlmIChlLnRhcmdldFRvdWNoZXMpIHtcbiAgICAgIHJldHVybiBlLnRhcmdldFRvdWNoZXNbMF07XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIE1heWJlIElFIHBvaW50ZXJcbiAgICAgIHJldHVybiBlO1xuICAgIH1cbiAgfVxuICBmdW5jdGlvbiBzaG91bGRIYW5kbGUoZSkge1xuICAgIGlmIChlLnRhcmdldFRvdWNoZXMgJiYgZS50YXJnZXRUb3VjaGVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIGlmIChlLnBvaW50ZXJUeXBlICYmIGUucG9pbnRlclR5cGUgIT09ICdtb3VzZScgJiYgZS5wb2ludGVyVHlwZSAhPT0gZS5NU1BPSU5URVJfVFlQRV9NT1VTRSkge1xuICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuICBmdW5jdGlvbiB0b3VjaFN0YXJ0KGUpIHtcbiAgICBpZiAoc2hvdWxkSGFuZGxlKGUpKSB7XG4gICAgICBpbkxvY2FsVG91Y2ggPSB0cnVlO1xuXG4gICAgICB2YXIgdG91Y2ggPSBnZXRUb3VjaChlKTtcblxuICAgICAgc3RhcnRPZmZzZXQucGFnZVggPSB0b3VjaC5wYWdlWDtcbiAgICAgIHN0YXJ0T2Zmc2V0LnBhZ2VZID0gdG91Y2gucGFnZVk7XG5cbiAgICAgIHN0YXJ0VGltZSA9IChuZXcgRGF0ZSgpKS5nZXRUaW1lKCk7XG5cbiAgICAgIGlmIChlYXNpbmdMb29wICE9PSBudWxsKSB7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwoZWFzaW5nTG9vcCk7XG4gICAgICB9XG5cbiAgICAgIGUuc3RvcFByb3BhZ2F0aW9uKCk7XG4gICAgfVxuICB9XG4gIGZ1bmN0aW9uIHRvdWNoTW92ZShlKSB7XG4gICAgaWYgKCFpbkxvY2FsVG91Y2ggJiYgaS5zZXR0aW5ncy5zd2lwZVByb3BhZ2F0aW9uKSB7XG4gICAgICB0b3VjaFN0YXJ0KGUpO1xuICAgIH1cbiAgICBpZiAoIWluR2xvYmFsVG91Y2ggJiYgaW5Mb2NhbFRvdWNoICYmIHNob3VsZEhhbmRsZShlKSkge1xuICAgICAgdmFyIHRvdWNoID0gZ2V0VG91Y2goZSk7XG5cbiAgICAgIHZhciBjdXJyZW50T2Zmc2V0ID0ge3BhZ2VYOiB0b3VjaC5wYWdlWCwgcGFnZVk6IHRvdWNoLnBhZ2VZfTtcblxuICAgICAgdmFyIGRpZmZlcmVuY2VYID0gY3VycmVudE9mZnNldC5wYWdlWCAtIHN0YXJ0T2Zmc2V0LnBhZ2VYO1xuICAgICAgdmFyIGRpZmZlcmVuY2VZID0gY3VycmVudE9mZnNldC5wYWdlWSAtIHN0YXJ0T2Zmc2V0LnBhZ2VZO1xuXG4gICAgICBhcHBseVRvdWNoTW92ZShkaWZmZXJlbmNlWCwgZGlmZmVyZW5jZVkpO1xuICAgICAgc3RhcnRPZmZzZXQgPSBjdXJyZW50T2Zmc2V0O1xuXG4gICAgICB2YXIgY3VycmVudFRpbWUgPSAobmV3IERhdGUoKSkuZ2V0VGltZSgpO1xuXG4gICAgICB2YXIgdGltZUdhcCA9IGN1cnJlbnRUaW1lIC0gc3RhcnRUaW1lO1xuICAgICAgaWYgKHRpbWVHYXAgPiAwKSB7XG4gICAgICAgIHNwZWVkLnggPSBkaWZmZXJlbmNlWCAvIHRpbWVHYXA7XG4gICAgICAgIHNwZWVkLnkgPSBkaWZmZXJlbmNlWSAvIHRpbWVHYXA7XG4gICAgICAgIHN0YXJ0VGltZSA9IGN1cnJlbnRUaW1lO1xuICAgICAgfVxuXG4gICAgICBpZiAoc2hvdWxkUHJldmVudERlZmF1bHQoZGlmZmVyZW5jZVgsIGRpZmZlcmVuY2VZKSkge1xuICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICB9XG4gICAgfVxuICB9XG4gIGZ1bmN0aW9uIHRvdWNoRW5kKCkge1xuICAgIGlmICghaW5HbG9iYWxUb3VjaCAmJiBpbkxvY2FsVG91Y2gpIHtcbiAgICAgIGluTG9jYWxUb3VjaCA9IGZhbHNlO1xuXG4gICAgICBpZiAoaS5zZXR0aW5ncy5zd2lwZUVhc2luZykge1xuICAgICAgICBjbGVhckludGVydmFsKGVhc2luZ0xvb3ApO1xuICAgICAgICBlYXNpbmdMb29wID0gc2V0SW50ZXJ2YWwoZnVuY3Rpb24gKCkge1xuICAgICAgICAgIGlmICghaW5zdGFuY2VzLmdldChlbGVtZW50KSkge1xuICAgICAgICAgICAgY2xlYXJJbnRlcnZhbChlYXNpbmdMb29wKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBpZiAoIXNwZWVkLnggJiYgIXNwZWVkLnkpIHtcbiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwoZWFzaW5nTG9vcCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgaWYgKE1hdGguYWJzKHNwZWVkLngpIDwgMC4wMSAmJiBNYXRoLmFicyhzcGVlZC55KSA8IDAuMDEpIHtcbiAgICAgICAgICAgIGNsZWFySW50ZXJ2YWwoZWFzaW5nTG9vcCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgfVxuXG4gICAgICAgICAgYXBwbHlUb3VjaE1vdmUoc3BlZWQueCAqIDMwLCBzcGVlZC55ICogMzApO1xuXG4gICAgICAgICAgc3BlZWQueCAqPSAwLjg7XG4gICAgICAgICAgc3BlZWQueSAqPSAwLjg7XG4gICAgICAgIH0sIDEwKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBpZiAoc3VwcG9ydHNUb3VjaCkge1xuICAgIGkuZXZlbnQuYmluZCh3aW5kb3csICd0b3VjaHN0YXJ0JywgZ2xvYmFsVG91Y2hTdGFydCk7XG4gICAgaS5ldmVudC5iaW5kKHdpbmRvdywgJ3RvdWNoZW5kJywgZ2xvYmFsVG91Y2hFbmQpO1xuICAgIGkuZXZlbnQuYmluZChlbGVtZW50LCAndG91Y2hzdGFydCcsIHRvdWNoU3RhcnQpO1xuICAgIGkuZXZlbnQuYmluZChlbGVtZW50LCAndG91Y2htb3ZlJywgdG91Y2hNb3ZlKTtcbiAgICBpLmV2ZW50LmJpbmQoZWxlbWVudCwgJ3RvdWNoZW5kJywgdG91Y2hFbmQpO1xuICB9IGVsc2UgaWYgKHN1cHBvcnRzSWVQb2ludGVyKSB7XG4gICAgaWYgKHdpbmRvdy5Qb2ludGVyRXZlbnQpIHtcbiAgICAgIGkuZXZlbnQuYmluZCh3aW5kb3csICdwb2ludGVyZG93bicsIGdsb2JhbFRvdWNoU3RhcnQpO1xuICAgICAgaS5ldmVudC5iaW5kKHdpbmRvdywgJ3BvaW50ZXJ1cCcsIGdsb2JhbFRvdWNoRW5kKTtcbiAgICAgIGkuZXZlbnQuYmluZChlbGVtZW50LCAncG9pbnRlcmRvd24nLCB0b3VjaFN0YXJ0KTtcbiAgICAgIGkuZXZlbnQuYmluZChlbGVtZW50LCAncG9pbnRlcm1vdmUnLCB0b3VjaE1vdmUpO1xuICAgICAgaS5ldmVudC5iaW5kKGVsZW1lbnQsICdwb2ludGVydXAnLCB0b3VjaEVuZCk7XG4gICAgfSBlbHNlIGlmICh3aW5kb3cuTVNQb2ludGVyRXZlbnQpIHtcbiAgICAgIGkuZXZlbnQuYmluZCh3aW5kb3csICdNU1BvaW50ZXJEb3duJywgZ2xvYmFsVG91Y2hTdGFydCk7XG4gICAgICBpLmV2ZW50LmJpbmQod2luZG93LCAnTVNQb2ludGVyVXAnLCBnbG9iYWxUb3VjaEVuZCk7XG4gICAgICBpLmV2ZW50LmJpbmQoZWxlbWVudCwgJ01TUG9pbnRlckRvd24nLCB0b3VjaFN0YXJ0KTtcbiAgICAgIGkuZXZlbnQuYmluZChlbGVtZW50LCAnTVNQb2ludGVyTW92ZScsIHRvdWNoTW92ZSk7XG4gICAgICBpLmV2ZW50LmJpbmQoZWxlbWVudCwgJ01TUG9pbnRlclVwJywgdG91Y2hFbmQpO1xuICAgIH1cbiAgfVxufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gIGlmICghXy5lbnYuc3VwcG9ydHNUb3VjaCAmJiAhXy5lbnYuc3VwcG9ydHNJZVBvaW50ZXIpIHtcbiAgICByZXR1cm47XG4gIH1cblxuICB2YXIgaSA9IGluc3RhbmNlcy5nZXQoZWxlbWVudCk7XG4gIGJpbmRUb3VjaEhhbmRsZXIoZWxlbWVudCwgaSwgXy5lbnYuc3VwcG9ydHNUb3VjaCwgXy5lbnYuc3VwcG9ydHNJZVBvaW50ZXIpO1xufTtcblxufSx7XCIuLi8uLi9saWIvaGVscGVyXCI6NixcIi4uL2luc3RhbmNlc1wiOjE4LFwiLi4vdXBkYXRlLWdlb21ldHJ5XCI6MTksXCIuLi91cGRhdGUtc2Nyb2xsXCI6MjB9XSwxNzpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbnZhciBfID0gcmVxdWlyZSgnLi4vbGliL2hlbHBlcicpO1xudmFyIGNscyA9IHJlcXVpcmUoJy4uL2xpYi9jbGFzcycpO1xudmFyIGluc3RhbmNlcyA9IHJlcXVpcmUoJy4vaW5zdGFuY2VzJyk7XG52YXIgdXBkYXRlR2VvbWV0cnkgPSByZXF1aXJlKCcuL3VwZGF0ZS1nZW9tZXRyeScpO1xuXG4vLyBIYW5kbGVyc1xudmFyIGhhbmRsZXJzID0ge1xuICAnY2xpY2stcmFpbCc6IHJlcXVpcmUoJy4vaGFuZGxlci9jbGljay1yYWlsJyksXG4gICdkcmFnLXNjcm9sbGJhcic6IHJlcXVpcmUoJy4vaGFuZGxlci9kcmFnLXNjcm9sbGJhcicpLFxuICAna2V5Ym9hcmQnOiByZXF1aXJlKCcuL2hhbmRsZXIva2V5Ym9hcmQnKSxcbiAgJ3doZWVsJzogcmVxdWlyZSgnLi9oYW5kbGVyL21vdXNlLXdoZWVsJyksXG4gICd0b3VjaCc6IHJlcXVpcmUoJy4vaGFuZGxlci90b3VjaCcpLFxuICAnc2VsZWN0aW9uJzogcmVxdWlyZSgnLi9oYW5kbGVyL3NlbGVjdGlvbicpXG59O1xudmFyIG5hdGl2ZVNjcm9sbEhhbmRsZXIgPSByZXF1aXJlKCcuL2hhbmRsZXIvbmF0aXZlLXNjcm9sbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChlbGVtZW50LCB1c2VyU2V0dGluZ3MpIHtcbiAgdXNlclNldHRpbmdzID0gdHlwZW9mIHVzZXJTZXR0aW5ncyA9PT0gJ29iamVjdCcgPyB1c2VyU2V0dGluZ3MgOiB7fTtcblxuICBjbHMuYWRkKGVsZW1lbnQsICdwcycpO1xuXG4gIC8vIENyZWF0ZSBhIHBsdWdpbiBpbnN0YW5jZS5cbiAgdmFyIGkgPSBpbnN0YW5jZXMuYWRkKGVsZW1lbnQpO1xuXG4gIGkuc2V0dGluZ3MgPSBfLmV4dGVuZChpLnNldHRpbmdzLCB1c2VyU2V0dGluZ3MpO1xuICBjbHMuYWRkKGVsZW1lbnQsICdwcy0tdGhlbWVfJyArIGkuc2V0dGluZ3MudGhlbWUpO1xuXG4gIGkuc2V0dGluZ3MuaGFuZGxlcnMuZm9yRWFjaChmdW5jdGlvbiAoaGFuZGxlck5hbWUpIHtcbiAgICBoYW5kbGVyc1toYW5kbGVyTmFtZV0oZWxlbWVudCk7XG4gIH0pO1xuXG4gIG5hdGl2ZVNjcm9sbEhhbmRsZXIoZWxlbWVudCk7XG5cbiAgdXBkYXRlR2VvbWV0cnkoZWxlbWVudCk7XG59O1xuXG59LHtcIi4uL2xpYi9jbGFzc1wiOjIsXCIuLi9saWIvaGVscGVyXCI6NixcIi4vaGFuZGxlci9jbGljay1yYWlsXCI6MTAsXCIuL2hhbmRsZXIvZHJhZy1zY3JvbGxiYXJcIjoxMSxcIi4vaGFuZGxlci9rZXlib2FyZFwiOjEyLFwiLi9oYW5kbGVyL21vdXNlLXdoZWVsXCI6MTMsXCIuL2hhbmRsZXIvbmF0aXZlLXNjcm9sbFwiOjE0LFwiLi9oYW5kbGVyL3NlbGVjdGlvblwiOjE1LFwiLi9oYW5kbGVyL3RvdWNoXCI6MTYsXCIuL2luc3RhbmNlc1wiOjE4LFwiLi91cGRhdGUtZ2VvbWV0cnlcIjoxOX1dLDE4OltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxudmFyIF8gPSByZXF1aXJlKCcuLi9saWIvaGVscGVyJyk7XG52YXIgY2xzID0gcmVxdWlyZSgnLi4vbGliL2NsYXNzJyk7XG52YXIgZGVmYXVsdFNldHRpbmdzID0gcmVxdWlyZSgnLi9kZWZhdWx0LXNldHRpbmcnKTtcbnZhciBkb20gPSByZXF1aXJlKCcuLi9saWIvZG9tJyk7XG52YXIgRXZlbnRNYW5hZ2VyID0gcmVxdWlyZSgnLi4vbGliL2V2ZW50LW1hbmFnZXInKTtcbnZhciBndWlkID0gcmVxdWlyZSgnLi4vbGliL2d1aWQnKTtcblxudmFyIGluc3RhbmNlcyA9IHt9O1xuXG5mdW5jdGlvbiBJbnN0YW5jZShlbGVtZW50KSB7XG4gIHZhciBpID0gdGhpcztcblxuICBpLnNldHRpbmdzID0gXy5jbG9uZShkZWZhdWx0U2V0dGluZ3MpO1xuICBpLmNvbnRhaW5lcldpZHRoID0gbnVsbDtcbiAgaS5jb250YWluZXJIZWlnaHQgPSBudWxsO1xuICBpLmNvbnRlbnRXaWR0aCA9IG51bGw7XG4gIGkuY29udGVudEhlaWdodCA9IG51bGw7XG5cbiAgaS5pc1J0bCA9IGRvbS5jc3MoZWxlbWVudCwgJ2RpcmVjdGlvbicpID09PSBcInJ0bFwiO1xuICBpLmlzTmVnYXRpdmVTY3JvbGwgPSAoZnVuY3Rpb24gKCkge1xuICAgIHZhciBvcmlnaW5hbFNjcm9sbExlZnQgPSBlbGVtZW50LnNjcm9sbExlZnQ7XG4gICAgdmFyIHJlc3VsdCA9IG51bGw7XG4gICAgZWxlbWVudC5zY3JvbGxMZWZ0ID0gLTE7XG4gICAgcmVzdWx0ID0gZWxlbWVudC5zY3JvbGxMZWZ0IDwgMDtcbiAgICBlbGVtZW50LnNjcm9sbExlZnQgPSBvcmlnaW5hbFNjcm9sbExlZnQ7XG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfSkoKTtcbiAgaS5uZWdhdGl2ZVNjcm9sbEFkanVzdG1lbnQgPSBpLmlzTmVnYXRpdmVTY3JvbGwgPyBlbGVtZW50LnNjcm9sbFdpZHRoIC0gZWxlbWVudC5jbGllbnRXaWR0aCA6IDA7XG4gIGkuZXZlbnQgPSBuZXcgRXZlbnRNYW5hZ2VyKCk7XG4gIGkub3duZXJEb2N1bWVudCA9IGVsZW1lbnQub3duZXJEb2N1bWVudCB8fCBkb2N1bWVudDtcblxuICBmdW5jdGlvbiBmb2N1cygpIHtcbiAgICBjbHMuYWRkKGVsZW1lbnQsICdwcy0tZm9jdXMnKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGJsdXIoKSB7XG4gICAgY2xzLnJlbW92ZShlbGVtZW50LCAncHMtLWZvY3VzJyk7XG4gIH1cblxuICBpLnNjcm9sbGJhclhSYWlsID0gZG9tLmFwcGVuZFRvKGRvbS5lKCdkaXYnLCAncHNfX3Njcm9sbGJhci14LXJhaWwnKSwgZWxlbWVudCk7XG4gIGkuc2Nyb2xsYmFyWCA9IGRvbS5hcHBlbmRUbyhkb20uZSgnZGl2JywgJ3BzX19zY3JvbGxiYXIteCcpLCBpLnNjcm9sbGJhclhSYWlsKTtcbiAgaS5zY3JvbGxiYXJYLnNldEF0dHJpYnV0ZSgndGFiaW5kZXgnLCAwKTtcbiAgaS5ldmVudC5iaW5kKGkuc2Nyb2xsYmFyWCwgJ2ZvY3VzJywgZm9jdXMpO1xuICBpLmV2ZW50LmJpbmQoaS5zY3JvbGxiYXJYLCAnYmx1cicsIGJsdXIpO1xuICBpLnNjcm9sbGJhclhBY3RpdmUgPSBudWxsO1xuICBpLnNjcm9sbGJhclhXaWR0aCA9IG51bGw7XG4gIGkuc2Nyb2xsYmFyWExlZnQgPSBudWxsO1xuICBpLnNjcm9sbGJhclhCb3R0b20gPSBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ2JvdHRvbScpKTtcbiAgaS5pc1Njcm9sbGJhclhVc2luZ0JvdHRvbSA9IGkuc2Nyb2xsYmFyWEJvdHRvbSA9PT0gaS5zY3JvbGxiYXJYQm90dG9tOyAvLyAhaXNOYU5cbiAgaS5zY3JvbGxiYXJYVG9wID0gaS5pc1Njcm9sbGJhclhVc2luZ0JvdHRvbSA/IG51bGwgOiBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ3RvcCcpKTtcbiAgaS5yYWlsQm9yZGVyWFdpZHRoID0gXy50b0ludChkb20uY3NzKGkuc2Nyb2xsYmFyWFJhaWwsICdib3JkZXJMZWZ0V2lkdGgnKSkgKyBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ2JvcmRlclJpZ2h0V2lkdGgnKSk7XG4gIC8vIFNldCByYWlsIHRvIGRpc3BsYXk6YmxvY2sgdG8gY2FsY3VsYXRlIG1hcmdpbnNcbiAgZG9tLmNzcyhpLnNjcm9sbGJhclhSYWlsLCAnZGlzcGxheScsICdibG9jaycpO1xuICBpLnJhaWxYTWFyZ2luV2lkdGggPSBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ21hcmdpbkxlZnQnKSkgKyBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ21hcmdpblJpZ2h0JykpO1xuICBkb20uY3NzKGkuc2Nyb2xsYmFyWFJhaWwsICdkaXNwbGF5JywgJycpO1xuICBpLnJhaWxYV2lkdGggPSBudWxsO1xuICBpLnJhaWxYUmF0aW8gPSBudWxsO1xuXG4gIGkuc2Nyb2xsYmFyWVJhaWwgPSBkb20uYXBwZW5kVG8oZG9tLmUoJ2RpdicsICdwc19fc2Nyb2xsYmFyLXktcmFpbCcpLCBlbGVtZW50KTtcbiAgaS5zY3JvbGxiYXJZID0gZG9tLmFwcGVuZFRvKGRvbS5lKCdkaXYnLCAncHNfX3Njcm9sbGJhci15JyksIGkuc2Nyb2xsYmFyWVJhaWwpO1xuICBpLnNjcm9sbGJhclkuc2V0QXR0cmlidXRlKCd0YWJpbmRleCcsIDApO1xuICBpLmV2ZW50LmJpbmQoaS5zY3JvbGxiYXJZLCAnZm9jdXMnLCBmb2N1cyk7XG4gIGkuZXZlbnQuYmluZChpLnNjcm9sbGJhclksICdibHVyJywgYmx1cik7XG4gIGkuc2Nyb2xsYmFyWUFjdGl2ZSA9IG51bGw7XG4gIGkuc2Nyb2xsYmFyWUhlaWdodCA9IG51bGw7XG4gIGkuc2Nyb2xsYmFyWVRvcCA9IG51bGw7XG4gIGkuc2Nyb2xsYmFyWVJpZ2h0ID0gXy50b0ludChkb20uY3NzKGkuc2Nyb2xsYmFyWVJhaWwsICdyaWdodCcpKTtcbiAgaS5pc1Njcm9sbGJhcllVc2luZ1JpZ2h0ID0gaS5zY3JvbGxiYXJZUmlnaHQgPT09IGkuc2Nyb2xsYmFyWVJpZ2h0OyAvLyAhaXNOYU5cbiAgaS5zY3JvbGxiYXJZTGVmdCA9IGkuaXNTY3JvbGxiYXJZVXNpbmdSaWdodCA/IG51bGwgOiBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJZUmFpbCwgJ2xlZnQnKSk7XG4gIGkuc2Nyb2xsYmFyWU91dGVyV2lkdGggPSBpLmlzUnRsID8gXy5vdXRlcldpZHRoKGkuc2Nyb2xsYmFyWSkgOiBudWxsO1xuICBpLnJhaWxCb3JkZXJZV2lkdGggPSBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJZUmFpbCwgJ2JvcmRlclRvcFdpZHRoJykpICsgXy50b0ludChkb20uY3NzKGkuc2Nyb2xsYmFyWVJhaWwsICdib3JkZXJCb3R0b21XaWR0aCcpKTtcbiAgZG9tLmNzcyhpLnNjcm9sbGJhcllSYWlsLCAnZGlzcGxheScsICdibG9jaycpO1xuICBpLnJhaWxZTWFyZ2luSGVpZ2h0ID0gXy50b0ludChkb20uY3NzKGkuc2Nyb2xsYmFyWVJhaWwsICdtYXJnaW5Ub3AnKSkgKyBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJZUmFpbCwgJ21hcmdpbkJvdHRvbScpKTtcbiAgZG9tLmNzcyhpLnNjcm9sbGJhcllSYWlsLCAnZGlzcGxheScsICcnKTtcbiAgaS5yYWlsWUhlaWdodCA9IG51bGw7XG4gIGkucmFpbFlSYXRpbyA9IG51bGw7XG59XG5cbmZ1bmN0aW9uIGdldElkKGVsZW1lbnQpIHtcbiAgcmV0dXJuIGVsZW1lbnQuZ2V0QXR0cmlidXRlKCdkYXRhLXBzLWlkJyk7XG59XG5cbmZ1bmN0aW9uIHNldElkKGVsZW1lbnQsIGlkKSB7XG4gIGVsZW1lbnQuc2V0QXR0cmlidXRlKCdkYXRhLXBzLWlkJywgaWQpO1xufVxuXG5mdW5jdGlvbiByZW1vdmVJZChlbGVtZW50KSB7XG4gIGVsZW1lbnQucmVtb3ZlQXR0cmlidXRlKCdkYXRhLXBzLWlkJyk7XG59XG5cbmV4cG9ydHMuYWRkID0gZnVuY3Rpb24gKGVsZW1lbnQpIHtcbiAgdmFyIG5ld0lkID0gZ3VpZCgpO1xuICBzZXRJZChlbGVtZW50LCBuZXdJZCk7XG4gIGluc3RhbmNlc1tuZXdJZF0gPSBuZXcgSW5zdGFuY2UoZWxlbWVudCk7XG4gIHJldHVybiBpbnN0YW5jZXNbbmV3SWRdO1xufTtcblxuZXhwb3J0cy5yZW1vdmUgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICBkZWxldGUgaW5zdGFuY2VzW2dldElkKGVsZW1lbnQpXTtcbiAgcmVtb3ZlSWQoZWxlbWVudCk7XG59O1xuXG5leHBvcnRzLmdldCA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gIHJldHVybiBpbnN0YW5jZXNbZ2V0SWQoZWxlbWVudCldO1xufTtcblxufSx7XCIuLi9saWIvY2xhc3NcIjoyLFwiLi4vbGliL2RvbVwiOjMsXCIuLi9saWIvZXZlbnQtbWFuYWdlclwiOjQsXCIuLi9saWIvZ3VpZFwiOjUsXCIuLi9saWIvaGVscGVyXCI6NixcIi4vZGVmYXVsdC1zZXR0aW5nXCI6OH1dLDE5OltmdW5jdGlvbihyZXF1aXJlLG1vZHVsZSxleHBvcnRzKXtcbid1c2Ugc3RyaWN0JztcblxudmFyIF8gPSByZXF1aXJlKCcuLi9saWIvaGVscGVyJyk7XG52YXIgY2xzID0gcmVxdWlyZSgnLi4vbGliL2NsYXNzJyk7XG52YXIgZG9tID0gcmVxdWlyZSgnLi4vbGliL2RvbScpO1xudmFyIGluc3RhbmNlcyA9IHJlcXVpcmUoJy4vaW5zdGFuY2VzJyk7XG52YXIgdXBkYXRlU2Nyb2xsID0gcmVxdWlyZSgnLi91cGRhdGUtc2Nyb2xsJyk7XG5cbmZ1bmN0aW9uIGdldFRodW1iU2l6ZShpLCB0aHVtYlNpemUpIHtcbiAgaWYgKGkuc2V0dGluZ3MubWluU2Nyb2xsYmFyTGVuZ3RoKSB7XG4gICAgdGh1bWJTaXplID0gTWF0aC5tYXgodGh1bWJTaXplLCBpLnNldHRpbmdzLm1pblNjcm9sbGJhckxlbmd0aCk7XG4gIH1cbiAgaWYgKGkuc2V0dGluZ3MubWF4U2Nyb2xsYmFyTGVuZ3RoKSB7XG4gICAgdGh1bWJTaXplID0gTWF0aC5taW4odGh1bWJTaXplLCBpLnNldHRpbmdzLm1heFNjcm9sbGJhckxlbmd0aCk7XG4gIH1cbiAgcmV0dXJuIHRodW1iU2l6ZTtcbn1cblxuZnVuY3Rpb24gdXBkYXRlQ3NzKGVsZW1lbnQsIGkpIHtcbiAgdmFyIHhSYWlsT2Zmc2V0ID0ge3dpZHRoOiBpLnJhaWxYV2lkdGh9O1xuICBpZiAoaS5pc1J0bCkge1xuICAgIHhSYWlsT2Zmc2V0LmxlZnQgPSBpLm5lZ2F0aXZlU2Nyb2xsQWRqdXN0bWVudCArIGVsZW1lbnQuc2Nyb2xsTGVmdCArIGkuY29udGFpbmVyV2lkdGggLSBpLmNvbnRlbnRXaWR0aDtcbiAgfSBlbHNlIHtcbiAgICB4UmFpbE9mZnNldC5sZWZ0ID0gZWxlbWVudC5zY3JvbGxMZWZ0O1xuICB9XG4gIGlmIChpLmlzU2Nyb2xsYmFyWFVzaW5nQm90dG9tKSB7XG4gICAgeFJhaWxPZmZzZXQuYm90dG9tID0gaS5zY3JvbGxiYXJYQm90dG9tIC0gZWxlbWVudC5zY3JvbGxUb3A7XG4gIH0gZWxzZSB7XG4gICAgeFJhaWxPZmZzZXQudG9wID0gaS5zY3JvbGxiYXJYVG9wICsgZWxlbWVudC5zY3JvbGxUb3A7XG4gIH1cbiAgZG9tLmNzcyhpLnNjcm9sbGJhclhSYWlsLCB4UmFpbE9mZnNldCk7XG5cbiAgdmFyIHlSYWlsT2Zmc2V0ID0ge3RvcDogZWxlbWVudC5zY3JvbGxUb3AsIGhlaWdodDogaS5yYWlsWUhlaWdodH07XG4gIGlmIChpLmlzU2Nyb2xsYmFyWVVzaW5nUmlnaHQpIHtcbiAgICBpZiAoaS5pc1J0bCkge1xuICAgICAgeVJhaWxPZmZzZXQucmlnaHQgPSBpLmNvbnRlbnRXaWR0aCAtIChpLm5lZ2F0aXZlU2Nyb2xsQWRqdXN0bWVudCArIGVsZW1lbnQuc2Nyb2xsTGVmdCkgLSBpLnNjcm9sbGJhcllSaWdodCAtIGkuc2Nyb2xsYmFyWU91dGVyV2lkdGg7XG4gICAgfSBlbHNlIHtcbiAgICAgIHlSYWlsT2Zmc2V0LnJpZ2h0ID0gaS5zY3JvbGxiYXJZUmlnaHQgLSBlbGVtZW50LnNjcm9sbExlZnQ7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGlmIChpLmlzUnRsKSB7XG4gICAgICB5UmFpbE9mZnNldC5sZWZ0ID0gaS5uZWdhdGl2ZVNjcm9sbEFkanVzdG1lbnQgKyBlbGVtZW50LnNjcm9sbExlZnQgKyBpLmNvbnRhaW5lcldpZHRoICogMiAtIGkuY29udGVudFdpZHRoIC0gaS5zY3JvbGxiYXJZTGVmdCAtIGkuc2Nyb2xsYmFyWU91dGVyV2lkdGg7XG4gICAgfSBlbHNlIHtcbiAgICAgIHlSYWlsT2Zmc2V0LmxlZnQgPSBpLnNjcm9sbGJhcllMZWZ0ICsgZWxlbWVudC5zY3JvbGxMZWZ0O1xuICAgIH1cbiAgfVxuICBkb20uY3NzKGkuc2Nyb2xsYmFyWVJhaWwsIHlSYWlsT2Zmc2V0KTtcblxuICBkb20uY3NzKGkuc2Nyb2xsYmFyWCwge2xlZnQ6IGkuc2Nyb2xsYmFyWExlZnQsIHdpZHRoOiBpLnNjcm9sbGJhclhXaWR0aCAtIGkucmFpbEJvcmRlclhXaWR0aH0pO1xuICBkb20uY3NzKGkuc2Nyb2xsYmFyWSwge3RvcDogaS5zY3JvbGxiYXJZVG9wLCBoZWlnaHQ6IGkuc2Nyb2xsYmFyWUhlaWdodCAtIGkucmFpbEJvcmRlcllXaWR0aH0pO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChlbGVtZW50KSB7XG4gIHZhciBpID0gaW5zdGFuY2VzLmdldChlbGVtZW50KTtcblxuICBpLmNvbnRhaW5lcldpZHRoID0gZWxlbWVudC5jbGllbnRXaWR0aDtcbiAgaS5jb250YWluZXJIZWlnaHQgPSBlbGVtZW50LmNsaWVudEhlaWdodDtcbiAgaS5jb250ZW50V2lkdGggPSBlbGVtZW50LnNjcm9sbFdpZHRoO1xuICBpLmNvbnRlbnRIZWlnaHQgPSBlbGVtZW50LnNjcm9sbEhlaWdodDtcblxuICB2YXIgZXhpc3RpbmdSYWlscztcbiAgaWYgKCFlbGVtZW50LmNvbnRhaW5zKGkuc2Nyb2xsYmFyWFJhaWwpKSB7XG4gICAgZXhpc3RpbmdSYWlscyA9IGRvbS5xdWVyeUNoaWxkcmVuKGVsZW1lbnQsICcucHNfX3Njcm9sbGJhci14LXJhaWwnKTtcbiAgICBpZiAoZXhpc3RpbmdSYWlscy5sZW5ndGggPiAwKSB7XG4gICAgICBleGlzdGluZ1JhaWxzLmZvckVhY2goZnVuY3Rpb24gKHJhaWwpIHtcbiAgICAgICAgZG9tLnJlbW92ZShyYWlsKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgICBkb20uYXBwZW5kVG8oaS5zY3JvbGxiYXJYUmFpbCwgZWxlbWVudCk7XG4gIH1cbiAgaWYgKCFlbGVtZW50LmNvbnRhaW5zKGkuc2Nyb2xsYmFyWVJhaWwpKSB7XG4gICAgZXhpc3RpbmdSYWlscyA9IGRvbS5xdWVyeUNoaWxkcmVuKGVsZW1lbnQsICcucHNfX3Njcm9sbGJhci15LXJhaWwnKTtcbiAgICBpZiAoZXhpc3RpbmdSYWlscy5sZW5ndGggPiAwKSB7XG4gICAgICBleGlzdGluZ1JhaWxzLmZvckVhY2goZnVuY3Rpb24gKHJhaWwpIHtcbiAgICAgICAgZG9tLnJlbW92ZShyYWlsKTtcbiAgICAgIH0pO1xuICAgIH1cbiAgICBkb20uYXBwZW5kVG8oaS5zY3JvbGxiYXJZUmFpbCwgZWxlbWVudCk7XG4gIH1cblxuICBpZiAoIWkuc2V0dGluZ3Muc3VwcHJlc3NTY3JvbGxYICYmIGkuY29udGFpbmVyV2lkdGggKyBpLnNldHRpbmdzLnNjcm9sbFhNYXJnaW5PZmZzZXQgPCBpLmNvbnRlbnRXaWR0aCkge1xuICAgIGkuc2Nyb2xsYmFyWEFjdGl2ZSA9IHRydWU7XG4gICAgaS5yYWlsWFdpZHRoID0gaS5jb250YWluZXJXaWR0aCAtIGkucmFpbFhNYXJnaW5XaWR0aDtcbiAgICBpLnJhaWxYUmF0aW8gPSBpLmNvbnRhaW5lcldpZHRoIC8gaS5yYWlsWFdpZHRoO1xuICAgIGkuc2Nyb2xsYmFyWFdpZHRoID0gZ2V0VGh1bWJTaXplKGksIF8udG9JbnQoaS5yYWlsWFdpZHRoICogaS5jb250YWluZXJXaWR0aCAvIGkuY29udGVudFdpZHRoKSk7XG4gICAgaS5zY3JvbGxiYXJYTGVmdCA9IF8udG9JbnQoKGkubmVnYXRpdmVTY3JvbGxBZGp1c3RtZW50ICsgZWxlbWVudC5zY3JvbGxMZWZ0KSAqIChpLnJhaWxYV2lkdGggLSBpLnNjcm9sbGJhclhXaWR0aCkgLyAoaS5jb250ZW50V2lkdGggLSBpLmNvbnRhaW5lcldpZHRoKSk7XG4gIH0gZWxzZSB7XG4gICAgaS5zY3JvbGxiYXJYQWN0aXZlID0gZmFsc2U7XG4gIH1cblxuICBpZiAoIWkuc2V0dGluZ3Muc3VwcHJlc3NTY3JvbGxZICYmIGkuY29udGFpbmVySGVpZ2h0ICsgaS5zZXR0aW5ncy5zY3JvbGxZTWFyZ2luT2Zmc2V0IDwgaS5jb250ZW50SGVpZ2h0KSB7XG4gICAgaS5zY3JvbGxiYXJZQWN0aXZlID0gdHJ1ZTtcbiAgICBpLnJhaWxZSGVpZ2h0ID0gaS5jb250YWluZXJIZWlnaHQgLSBpLnJhaWxZTWFyZ2luSGVpZ2h0O1xuICAgIGkucmFpbFlSYXRpbyA9IGkuY29udGFpbmVySGVpZ2h0IC8gaS5yYWlsWUhlaWdodDtcbiAgICBpLnNjcm9sbGJhcllIZWlnaHQgPSBnZXRUaHVtYlNpemUoaSwgXy50b0ludChpLnJhaWxZSGVpZ2h0ICogaS5jb250YWluZXJIZWlnaHQgLyBpLmNvbnRlbnRIZWlnaHQpKTtcbiAgICBpLnNjcm9sbGJhcllUb3AgPSBfLnRvSW50KGVsZW1lbnQuc2Nyb2xsVG9wICogKGkucmFpbFlIZWlnaHQgLSBpLnNjcm9sbGJhcllIZWlnaHQpIC8gKGkuY29udGVudEhlaWdodCAtIGkuY29udGFpbmVySGVpZ2h0KSk7XG4gIH0gZWxzZSB7XG4gICAgaS5zY3JvbGxiYXJZQWN0aXZlID0gZmFsc2U7XG4gIH1cblxuICBpZiAoaS5zY3JvbGxiYXJYTGVmdCA+PSBpLnJhaWxYV2lkdGggLSBpLnNjcm9sbGJhclhXaWR0aCkge1xuICAgIGkuc2Nyb2xsYmFyWExlZnQgPSBpLnJhaWxYV2lkdGggLSBpLnNjcm9sbGJhclhXaWR0aDtcbiAgfVxuICBpZiAoaS5zY3JvbGxiYXJZVG9wID49IGkucmFpbFlIZWlnaHQgLSBpLnNjcm9sbGJhcllIZWlnaHQpIHtcbiAgICBpLnNjcm9sbGJhcllUb3AgPSBpLnJhaWxZSGVpZ2h0IC0gaS5zY3JvbGxiYXJZSGVpZ2h0O1xuICB9XG5cbiAgdXBkYXRlQ3NzKGVsZW1lbnQsIGkpO1xuXG4gIGlmIChpLnNjcm9sbGJhclhBY3RpdmUpIHtcbiAgICBjbHMuYWRkKGVsZW1lbnQsICdwcy0tYWN0aXZlLXgnKTtcbiAgfSBlbHNlIHtcbiAgICBjbHMucmVtb3ZlKGVsZW1lbnQsICdwcy0tYWN0aXZlLXgnKTtcbiAgICBpLnNjcm9sbGJhclhXaWR0aCA9IDA7XG4gICAgaS5zY3JvbGxiYXJYTGVmdCA9IDA7XG4gICAgdXBkYXRlU2Nyb2xsKGVsZW1lbnQsICdsZWZ0JywgMCk7XG4gIH1cbiAgaWYgKGkuc2Nyb2xsYmFyWUFjdGl2ZSkge1xuICAgIGNscy5hZGQoZWxlbWVudCwgJ3BzLS1hY3RpdmUteScpO1xuICB9IGVsc2Uge1xuICAgIGNscy5yZW1vdmUoZWxlbWVudCwgJ3BzLS1hY3RpdmUteScpO1xuICAgIGkuc2Nyb2xsYmFyWUhlaWdodCA9IDA7XG4gICAgaS5zY3JvbGxiYXJZVG9wID0gMDtcbiAgICB1cGRhdGVTY3JvbGwoZWxlbWVudCwgJ3RvcCcsIDApO1xuICB9XG59O1xuXG59LHtcIi4uL2xpYi9jbGFzc1wiOjIsXCIuLi9saWIvZG9tXCI6MyxcIi4uL2xpYi9oZWxwZXJcIjo2LFwiLi9pbnN0YW5jZXNcIjoxOCxcIi4vdXBkYXRlLXNjcm9sbFwiOjIwfV0sMjA6W2Z1bmN0aW9uKHJlcXVpcmUsbW9kdWxlLGV4cG9ydHMpe1xuJ3VzZSBzdHJpY3QnO1xuXG52YXIgaW5zdGFuY2VzID0gcmVxdWlyZSgnLi9pbnN0YW5jZXMnKTtcblxudmFyIGNyZWF0ZURPTUV2ZW50ID0gZnVuY3Rpb24gKG5hbWUpIHtcbiAgdmFyIGV2ZW50ID0gZG9jdW1lbnQuY3JlYXRlRXZlbnQoXCJFdmVudFwiKTtcbiAgZXZlbnQuaW5pdEV2ZW50KG5hbWUsIHRydWUsIHRydWUpO1xuICByZXR1cm4gZXZlbnQ7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIChlbGVtZW50LCBheGlzLCB2YWx1ZSkge1xuICBpZiAodHlwZW9mIGVsZW1lbnQgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgdGhyb3cgJ1lvdSBtdXN0IHByb3ZpZGUgYW4gZWxlbWVudCB0byB0aGUgdXBkYXRlLXNjcm9sbCBmdW5jdGlvbic7XG4gIH1cblxuICBpZiAodHlwZW9mIGF4aXMgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgdGhyb3cgJ1lvdSBtdXN0IHByb3ZpZGUgYW4gYXhpcyB0byB0aGUgdXBkYXRlLXNjcm9sbCBmdW5jdGlvbic7XG4gIH1cblxuICBpZiAodHlwZW9mIHZhbHVlID09PSAndW5kZWZpbmVkJykge1xuICAgIHRocm93ICdZb3UgbXVzdCBwcm92aWRlIGEgdmFsdWUgdG8gdGhlIHVwZGF0ZS1zY3JvbGwgZnVuY3Rpb24nO1xuICB9XG5cbiAgaWYgKGF4aXMgPT09ICd0b3AnICYmIHZhbHVlIDw9IDApIHtcbiAgICBlbGVtZW50LnNjcm9sbFRvcCA9IHZhbHVlID0gMDsgLy8gZG9uJ3QgYWxsb3cgbmVnYXRpdmUgc2Nyb2xsXG4gICAgZWxlbWVudC5kaXNwYXRjaEV2ZW50KGNyZWF0ZURPTUV2ZW50KCdwcy15LXJlYWNoLXN0YXJ0JykpO1xuICB9XG5cbiAgaWYgKGF4aXMgPT09ICdsZWZ0JyAmJiB2YWx1ZSA8PSAwKSB7XG4gICAgZWxlbWVudC5zY3JvbGxMZWZ0ID0gdmFsdWUgPSAwOyAvLyBkb24ndCBhbGxvdyBuZWdhdGl2ZSBzY3JvbGxcbiAgICBlbGVtZW50LmRpc3BhdGNoRXZlbnQoY3JlYXRlRE9NRXZlbnQoJ3BzLXgtcmVhY2gtc3RhcnQnKSk7XG4gIH1cblxuICB2YXIgaSA9IGluc3RhbmNlcy5nZXQoZWxlbWVudCk7XG5cbiAgaWYgKGF4aXMgPT09ICd0b3AnICYmIHZhbHVlID49IGkuY29udGVudEhlaWdodCAtIGkuY29udGFpbmVySGVpZ2h0KSB7XG4gICAgLy8gZG9uJ3QgYWxsb3cgc2Nyb2xsIHBhc3QgY29udGFpbmVyXG4gICAgdmFsdWUgPSBpLmNvbnRlbnRIZWlnaHQgLSBpLmNvbnRhaW5lckhlaWdodDtcbiAgICBpZiAodmFsdWUgLSBlbGVtZW50LnNjcm9sbFRvcCA8PSAxKSB7XG4gICAgICAvLyBtaXRpZ2F0ZXMgcm91bmRpbmcgZXJyb3JzIG9uIG5vbi1zdWJwaXhlbCBzY3JvbGwgdmFsdWVzXG4gICAgICB2YWx1ZSA9IGVsZW1lbnQuc2Nyb2xsVG9wO1xuICAgIH0gZWxzZSB7XG4gICAgICBlbGVtZW50LnNjcm9sbFRvcCA9IHZhbHVlO1xuICAgIH1cbiAgICBlbGVtZW50LmRpc3BhdGNoRXZlbnQoY3JlYXRlRE9NRXZlbnQoJ3BzLXktcmVhY2gtZW5kJykpO1xuICB9XG5cbiAgaWYgKGF4aXMgPT09ICdsZWZ0JyAmJiB2YWx1ZSA+PSBpLmNvbnRlbnRXaWR0aCAtIGkuY29udGFpbmVyV2lkdGgpIHtcbiAgICAvLyBkb24ndCBhbGxvdyBzY3JvbGwgcGFzdCBjb250YWluZXJcbiAgICB2YWx1ZSA9IGkuY29udGVudFdpZHRoIC0gaS5jb250YWluZXJXaWR0aDtcbiAgICBpZiAodmFsdWUgLSBlbGVtZW50LnNjcm9sbExlZnQgPD0gMSkge1xuICAgICAgLy8gbWl0aWdhdGVzIHJvdW5kaW5nIGVycm9ycyBvbiBub24tc3VicGl4ZWwgc2Nyb2xsIHZhbHVlc1xuICAgICAgdmFsdWUgPSBlbGVtZW50LnNjcm9sbExlZnQ7XG4gICAgfSBlbHNlIHtcbiAgICAgIGVsZW1lbnQuc2Nyb2xsTGVmdCA9IHZhbHVlO1xuICAgIH1cbiAgICBlbGVtZW50LmRpc3BhdGNoRXZlbnQoY3JlYXRlRE9NRXZlbnQoJ3BzLXgtcmVhY2gtZW5kJykpO1xuICB9XG5cbiAgaWYgKGkubGFzdFRvcCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgaS5sYXN0VG9wID0gZWxlbWVudC5zY3JvbGxUb3A7XG4gIH1cblxuICBpZiAoaS5sYXN0TGVmdCA9PT0gdW5kZWZpbmVkKSB7XG4gICAgaS5sYXN0TGVmdCA9IGVsZW1lbnQuc2Nyb2xsTGVmdDtcbiAgfVxuXG4gIGlmIChheGlzID09PSAndG9wJyAmJiB2YWx1ZSA8IGkubGFzdFRvcCkge1xuICAgIGVsZW1lbnQuZGlzcGF0Y2hFdmVudChjcmVhdGVET01FdmVudCgncHMtc2Nyb2xsLXVwJykpO1xuICB9XG5cbiAgaWYgKGF4aXMgPT09ICd0b3AnICYmIHZhbHVlID4gaS5sYXN0VG9wKSB7XG4gICAgZWxlbWVudC5kaXNwYXRjaEV2ZW50KGNyZWF0ZURPTUV2ZW50KCdwcy1zY3JvbGwtZG93bicpKTtcbiAgfVxuXG4gIGlmIChheGlzID09PSAnbGVmdCcgJiYgdmFsdWUgPCBpLmxhc3RMZWZ0KSB7XG4gICAgZWxlbWVudC5kaXNwYXRjaEV2ZW50KGNyZWF0ZURPTUV2ZW50KCdwcy1zY3JvbGwtbGVmdCcpKTtcbiAgfVxuXG4gIGlmIChheGlzID09PSAnbGVmdCcgJiYgdmFsdWUgPiBpLmxhc3RMZWZ0KSB7XG4gICAgZWxlbWVudC5kaXNwYXRjaEV2ZW50KGNyZWF0ZURPTUV2ZW50KCdwcy1zY3JvbGwtcmlnaHQnKSk7XG4gIH1cblxuICBpZiAoYXhpcyA9PT0gJ3RvcCcgJiYgdmFsdWUgIT09IGkubGFzdFRvcCkge1xuICAgIGVsZW1lbnQuc2Nyb2xsVG9wID0gaS5sYXN0VG9wID0gdmFsdWU7XG4gICAgZWxlbWVudC5kaXNwYXRjaEV2ZW50KGNyZWF0ZURPTUV2ZW50KCdwcy1zY3JvbGwteScpKTtcbiAgfVxuXG4gIGlmIChheGlzID09PSAnbGVmdCcgJiYgdmFsdWUgIT09IGkubGFzdExlZnQpIHtcbiAgICBlbGVtZW50LnNjcm9sbExlZnQgPSBpLmxhc3RMZWZ0ID0gdmFsdWU7XG4gICAgZWxlbWVudC5kaXNwYXRjaEV2ZW50KGNyZWF0ZURPTUV2ZW50KCdwcy1zY3JvbGwteCcpKTtcbiAgfVxuXG59O1xuXG59LHtcIi4vaW5zdGFuY2VzXCI6MTh9XSwyMTpbZnVuY3Rpb24ocmVxdWlyZSxtb2R1bGUsZXhwb3J0cyl7XG4ndXNlIHN0cmljdCc7XG5cbnZhciBfID0gcmVxdWlyZSgnLi4vbGliL2hlbHBlcicpO1xudmFyIGRvbSA9IHJlcXVpcmUoJy4uL2xpYi9kb20nKTtcbnZhciBpbnN0YW5jZXMgPSByZXF1aXJlKCcuL2luc3RhbmNlcycpO1xudmFyIHVwZGF0ZUdlb21ldHJ5ID0gcmVxdWlyZSgnLi91cGRhdGUtZ2VvbWV0cnknKTtcbnZhciB1cGRhdGVTY3JvbGwgPSByZXF1aXJlKCcuL3VwZGF0ZS1zY3JvbGwnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICB2YXIgaSA9IGluc3RhbmNlcy5nZXQoZWxlbWVudCk7XG5cbiAgaWYgKCFpKSB7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gUmVjYWxjdWF0ZSBuZWdhdGl2ZSBzY3JvbGxMZWZ0IGFkanVzdG1lbnRcbiAgaS5uZWdhdGl2ZVNjcm9sbEFkanVzdG1lbnQgPSBpLmlzTmVnYXRpdmVTY3JvbGwgPyBlbGVtZW50LnNjcm9sbFdpZHRoIC0gZWxlbWVudC5jbGllbnRXaWR0aCA6IDA7XG5cbiAgLy8gUmVjYWxjdWxhdGUgcmFpbCBtYXJnaW5zXG4gIGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ2Rpc3BsYXknLCAnYmxvY2snKTtcbiAgZG9tLmNzcyhpLnNjcm9sbGJhcllSYWlsLCAnZGlzcGxheScsICdibG9jaycpO1xuICBpLnJhaWxYTWFyZ2luV2lkdGggPSBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ21hcmdpbkxlZnQnKSkgKyBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ21hcmdpblJpZ2h0JykpO1xuICBpLnJhaWxZTWFyZ2luSGVpZ2h0ID0gXy50b0ludChkb20uY3NzKGkuc2Nyb2xsYmFyWVJhaWwsICdtYXJnaW5Ub3AnKSkgKyBfLnRvSW50KGRvbS5jc3MoaS5zY3JvbGxiYXJZUmFpbCwgJ21hcmdpbkJvdHRvbScpKTtcblxuICAvLyBIaWRlIHNjcm9sbGJhcnMgbm90IHRvIGFmZmVjdCBzY3JvbGxXaWR0aCBhbmQgc2Nyb2xsSGVpZ2h0XG4gIGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ2Rpc3BsYXknLCAnbm9uZScpO1xuICBkb20uY3NzKGkuc2Nyb2xsYmFyWVJhaWwsICdkaXNwbGF5JywgJ25vbmUnKTtcblxuICB1cGRhdGVHZW9tZXRyeShlbGVtZW50KTtcblxuICAvLyBVcGRhdGUgdG9wL2xlZnQgc2Nyb2xsIHRvIHRyaWdnZXIgZXZlbnRzXG4gIHVwZGF0ZVNjcm9sbChlbGVtZW50LCAndG9wJywgZWxlbWVudC5zY3JvbGxUb3ApO1xuICB1cGRhdGVTY3JvbGwoZWxlbWVudCwgJ2xlZnQnLCBlbGVtZW50LnNjcm9sbExlZnQpO1xuXG4gIGRvbS5jc3MoaS5zY3JvbGxiYXJYUmFpbCwgJ2Rpc3BsYXknLCAnJyk7XG4gIGRvbS5jc3MoaS5zY3JvbGxiYXJZUmFpbCwgJ2Rpc3BsYXknLCAnJyk7XG59O1xuXG59LHtcIi4uL2xpYi9kb21cIjozLFwiLi4vbGliL2hlbHBlclwiOjYsXCIuL2luc3RhbmNlc1wiOjE4LFwiLi91cGRhdGUtZ2VvbWV0cnlcIjoxOSxcIi4vdXBkYXRlLXNjcm9sbFwiOjIwfV19LHt9LFsxXSk7XG4iLCIvLyBDb2RlTWlycm9yLCBjb3B5cmlnaHQgKGMpIGJ5IE1hcmlqbiBIYXZlcmJla2UgYW5kIG90aGVyc1xuLy8gRGlzdHJpYnV0ZWQgdW5kZXIgYW4gTUlUIGxpY2Vuc2U6IGh0dHBzOi8vY29kZW1pcnJvci5uZXQvTElDRU5TRVxuXG4vLyBUaGlzIGlzIENvZGVNaXJyb3IgKGh0dHBzOi8vY29kZW1pcnJvci5uZXQpLCBhIGNvZGUgZWRpdG9yXG4vLyBpbXBsZW1lbnRlZCBpbiBKYXZhU2NyaXB0IG9uIHRvcCBvZiB0aGUgYnJvd3NlcidzIERPTS5cbi8vXG4vLyBZb3UgY2FuIGZpbmQgc29tZSB0ZWNobmljYWwgYmFja2dyb3VuZCBmb3Igc29tZSBvZiB0aGUgY29kZSBiZWxvd1xuLy8gYXQgaHR0cDovL21hcmlqbmhhdmVyYmVrZS5ubC9ibG9nLyNjbS1pbnRlcm5hbHMgLlxuXG4oZnVuY3Rpb24gKGdsb2JhbCwgZmFjdG9yeSkge1xuICB0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcgJiYgdHlwZW9mIG1vZHVsZSAhPT0gJ3VuZGVmaW5lZCcgPyBtb2R1bGUuZXhwb3J0cyA9IGZhY3RvcnkoKSA6XG4gIHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCA/IGRlZmluZShmYWN0b3J5KSA6XG4gIChnbG9iYWwuQ29kZU1pcnJvciA9IGZhY3RvcnkoKSk7XG59KHRoaXMsIChmdW5jdGlvbiAoKSB7ICd1c2Ugc3RyaWN0JztcblxuICAvLyBLbHVkZ2VzIGZvciBidWdzIGFuZCBiZWhhdmlvciBkaWZmZXJlbmNlcyB0aGF0IGNhbid0IGJlIGZlYXR1cmVcbiAgLy8gZGV0ZWN0ZWQgYXJlIGVuYWJsZWQgYmFzZWQgb24gdXNlckFnZW50IGV0YyBzbmlmZmluZy5cbiAgdmFyIHVzZXJBZ2VudCA9IG5hdmlnYXRvci51c2VyQWdlbnQ7XG4gIHZhciBwbGF0Zm9ybSA9IG5hdmlnYXRvci5wbGF0Zm9ybTtcblxuICB2YXIgZ2Vja28gPSAvZ2Vja29cXC9cXGQvaS50ZXN0KHVzZXJBZ2VudCk7XG4gIHZhciBpZV91cHRvMTAgPSAvTVNJRSBcXGQvLnRlc3QodXNlckFnZW50KTtcbiAgdmFyIGllXzExdXAgPSAvVHJpZGVudFxcLyg/Ols3LTldfFxcZHsyLH0pXFwuLipydjooXFxkKykvLmV4ZWModXNlckFnZW50KTtcbiAgdmFyIGVkZ2UgPSAvRWRnZVxcLyhcXGQrKS8uZXhlYyh1c2VyQWdlbnQpO1xuICB2YXIgaWUgPSBpZV91cHRvMTAgfHwgaWVfMTF1cCB8fCBlZGdlO1xuICB2YXIgaWVfdmVyc2lvbiA9IGllICYmIChpZV91cHRvMTAgPyBkb2N1bWVudC5kb2N1bWVudE1vZGUgfHwgNiA6ICsoZWRnZSB8fCBpZV8xMXVwKVsxXSk7XG4gIHZhciB3ZWJraXQgPSAhZWRnZSAmJiAvV2ViS2l0XFwvLy50ZXN0KHVzZXJBZ2VudCk7XG4gIHZhciBxdHdlYmtpdCA9IHdlYmtpdCAmJiAvUXRcXC9cXGQrXFwuXFxkKy8udGVzdCh1c2VyQWdlbnQpO1xuICB2YXIgY2hyb21lID0gIWVkZ2UgJiYgL0Nocm9tZVxcLy8udGVzdCh1c2VyQWdlbnQpO1xuICB2YXIgcHJlc3RvID0gL09wZXJhXFwvLy50ZXN0KHVzZXJBZ2VudCk7XG4gIHZhciBzYWZhcmkgPSAvQXBwbGUgQ29tcHV0ZXIvLnRlc3QobmF2aWdhdG9yLnZlbmRvcik7XG4gIHZhciBtYWNfZ2VNb3VudGFpbkxpb24gPSAvTWFjIE9TIFggMVxcZFxcRChbOC05XXxcXGRcXGQpXFxELy50ZXN0KHVzZXJBZ2VudCk7XG4gIHZhciBwaGFudG9tID0gL1BoYW50b21KUy8udGVzdCh1c2VyQWdlbnQpO1xuXG4gIHZhciBpb3MgPSAhZWRnZSAmJiAvQXBwbGVXZWJLaXQvLnRlc3QodXNlckFnZW50KSAmJiAvTW9iaWxlXFwvXFx3Ky8udGVzdCh1c2VyQWdlbnQpO1xuICB2YXIgYW5kcm9pZCA9IC9BbmRyb2lkLy50ZXN0KHVzZXJBZ2VudCk7XG4gIC8vIFRoaXMgaXMgd29lZnVsbHkgaW5jb21wbGV0ZS4gU3VnZ2VzdGlvbnMgZm9yIGFsdGVybmF0aXZlIG1ldGhvZHMgd2VsY29tZS5cbiAgdmFyIG1vYmlsZSA9IGlvcyB8fCBhbmRyb2lkIHx8IC93ZWJPU3xCbGFja0JlcnJ5fE9wZXJhIE1pbml8T3BlcmEgTW9iaXxJRU1vYmlsZS9pLnRlc3QodXNlckFnZW50KTtcbiAgdmFyIG1hYyA9IGlvcyB8fCAvTWFjLy50ZXN0KHBsYXRmb3JtKTtcbiAgdmFyIGNocm9tZU9TID0gL1xcYkNyT1NcXGIvLnRlc3QodXNlckFnZW50KTtcbiAgdmFyIHdpbmRvd3MgPSAvd2luL2kudGVzdChwbGF0Zm9ybSk7XG5cbiAgdmFyIHByZXN0b192ZXJzaW9uID0gcHJlc3RvICYmIHVzZXJBZ2VudC5tYXRjaCgvVmVyc2lvblxcLyhcXGQqXFwuXFxkKikvKTtcbiAgaWYgKHByZXN0b192ZXJzaW9uKSB7IHByZXN0b192ZXJzaW9uID0gTnVtYmVyKHByZXN0b192ZXJzaW9uWzFdKTsgfVxuICBpZiAocHJlc3RvX3ZlcnNpb24gJiYgcHJlc3RvX3ZlcnNpb24gPj0gMTUpIHsgcHJlc3RvID0gZmFsc2U7IHdlYmtpdCA9IHRydWU7IH1cbiAgLy8gU29tZSBicm93c2VycyB1c2UgdGhlIHdyb25nIGV2ZW50IHByb3BlcnRpZXMgdG8gc2lnbmFsIGNtZC9jdHJsIG9uIE9TIFhcbiAgdmFyIGZsaXBDdHJsQ21kID0gbWFjICYmIChxdHdlYmtpdCB8fCBwcmVzdG8gJiYgKHByZXN0b192ZXJzaW9uID09IG51bGwgfHwgcHJlc3RvX3ZlcnNpb24gPCAxMi4xMSkpO1xuICB2YXIgY2FwdHVyZVJpZ2h0Q2xpY2sgPSBnZWNrbyB8fCAoaWUgJiYgaWVfdmVyc2lvbiA+PSA5KTtcblxuICBmdW5jdGlvbiBjbGFzc1Rlc3QoY2xzKSB7IHJldHVybiBuZXcgUmVnRXhwKFwiKF58XFxcXHMpXCIgKyBjbHMgKyBcIig/OiR8XFxcXHMpXFxcXHMqXCIpIH1cblxuICB2YXIgcm1DbGFzcyA9IGZ1bmN0aW9uKG5vZGUsIGNscykge1xuICAgIHZhciBjdXJyZW50ID0gbm9kZS5jbGFzc05hbWU7XG4gICAgdmFyIG1hdGNoID0gY2xhc3NUZXN0KGNscykuZXhlYyhjdXJyZW50KTtcbiAgICBpZiAobWF0Y2gpIHtcbiAgICAgIHZhciBhZnRlciA9IGN1cnJlbnQuc2xpY2UobWF0Y2guaW5kZXggKyBtYXRjaFswXS5sZW5ndGgpO1xuICAgICAgbm9kZS5jbGFzc05hbWUgPSBjdXJyZW50LnNsaWNlKDAsIG1hdGNoLmluZGV4KSArIChhZnRlciA/IG1hdGNoWzFdICsgYWZ0ZXIgOiBcIlwiKTtcbiAgICB9XG4gIH07XG5cbiAgZnVuY3Rpb24gcmVtb3ZlQ2hpbGRyZW4oZSkge1xuICAgIGZvciAodmFyIGNvdW50ID0gZS5jaGlsZE5vZGVzLmxlbmd0aDsgY291bnQgPiAwOyAtLWNvdW50KVxuICAgICAgeyBlLnJlbW92ZUNoaWxkKGUuZmlyc3RDaGlsZCk7IH1cbiAgICByZXR1cm4gZVxuICB9XG5cbiAgZnVuY3Rpb24gcmVtb3ZlQ2hpbGRyZW5BbmRBZGQocGFyZW50LCBlKSB7XG4gICAgcmV0dXJuIHJlbW92ZUNoaWxkcmVuKHBhcmVudCkuYXBwZW5kQ2hpbGQoZSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGVsdCh0YWcsIGNvbnRlbnQsIGNsYXNzTmFtZSwgc3R5bGUpIHtcbiAgICB2YXIgZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQodGFnKTtcbiAgICBpZiAoY2xhc3NOYW1lKSB7IGUuY2xhc3NOYW1lID0gY2xhc3NOYW1lOyB9XG4gICAgaWYgKHN0eWxlKSB7IGUuc3R5bGUuY3NzVGV4dCA9IHN0eWxlOyB9XG4gICAgaWYgKHR5cGVvZiBjb250ZW50ID09IFwic3RyaW5nXCIpIHsgZS5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShjb250ZW50KSk7IH1cbiAgICBlbHNlIGlmIChjb250ZW50KSB7IGZvciAodmFyIGkgPSAwOyBpIDwgY29udGVudC5sZW5ndGg7ICsraSkgeyBlLmFwcGVuZENoaWxkKGNvbnRlbnRbaV0pOyB9IH1cbiAgICByZXR1cm4gZVxuICB9XG4gIC8vIHdyYXBwZXIgZm9yIGVsdCwgd2hpY2ggcmVtb3ZlcyB0aGUgZWx0IGZyb20gdGhlIGFjY2Vzc2liaWxpdHkgdHJlZVxuICBmdW5jdGlvbiBlbHRQKHRhZywgY29udGVudCwgY2xhc3NOYW1lLCBzdHlsZSkge1xuICAgIHZhciBlID0gZWx0KHRhZywgY29udGVudCwgY2xhc3NOYW1lLCBzdHlsZSk7XG4gICAgZS5zZXRBdHRyaWJ1dGUoXCJyb2xlXCIsIFwicHJlc2VudGF0aW9uXCIpO1xuICAgIHJldHVybiBlXG4gIH1cblxuICB2YXIgcmFuZ2U7XG4gIGlmIChkb2N1bWVudC5jcmVhdGVSYW5nZSkgeyByYW5nZSA9IGZ1bmN0aW9uKG5vZGUsIHN0YXJ0LCBlbmQsIGVuZE5vZGUpIHtcbiAgICB2YXIgciA9IGRvY3VtZW50LmNyZWF0ZVJhbmdlKCk7XG4gICAgci5zZXRFbmQoZW5kTm9kZSB8fCBub2RlLCBlbmQpO1xuICAgIHIuc2V0U3RhcnQobm9kZSwgc3RhcnQpO1xuICAgIHJldHVybiByXG4gIH07IH1cbiAgZWxzZSB7IHJhbmdlID0gZnVuY3Rpb24obm9kZSwgc3RhcnQsIGVuZCkge1xuICAgIHZhciByID0gZG9jdW1lbnQuYm9keS5jcmVhdGVUZXh0UmFuZ2UoKTtcbiAgICB0cnkgeyByLm1vdmVUb0VsZW1lbnRUZXh0KG5vZGUucGFyZW50Tm9kZSk7IH1cbiAgICBjYXRjaChlKSB7IHJldHVybiByIH1cbiAgICByLmNvbGxhcHNlKHRydWUpO1xuICAgIHIubW92ZUVuZChcImNoYXJhY3RlclwiLCBlbmQpO1xuICAgIHIubW92ZVN0YXJ0KFwiY2hhcmFjdGVyXCIsIHN0YXJ0KTtcbiAgICByZXR1cm4gclxuICB9OyB9XG5cbiAgZnVuY3Rpb24gY29udGFpbnMocGFyZW50LCBjaGlsZCkge1xuICAgIGlmIChjaGlsZC5ub2RlVHlwZSA9PSAzKSAvLyBBbmRyb2lkIGJyb3dzZXIgYWx3YXlzIHJldHVybnMgZmFsc2Ugd2hlbiBjaGlsZCBpcyBhIHRleHRub2RlXG4gICAgICB7IGNoaWxkID0gY2hpbGQucGFyZW50Tm9kZTsgfVxuICAgIGlmIChwYXJlbnQuY29udGFpbnMpXG4gICAgICB7IHJldHVybiBwYXJlbnQuY29udGFpbnMoY2hpbGQpIH1cbiAgICBkbyB7XG4gICAgICBpZiAoY2hpbGQubm9kZVR5cGUgPT0gMTEpIHsgY2hpbGQgPSBjaGlsZC5ob3N0OyB9XG4gICAgICBpZiAoY2hpbGQgPT0gcGFyZW50KSB7IHJldHVybiB0cnVlIH1cbiAgICB9IHdoaWxlIChjaGlsZCA9IGNoaWxkLnBhcmVudE5vZGUpXG4gIH1cblxuICBmdW5jdGlvbiBhY3RpdmVFbHQoKSB7XG4gICAgLy8gSUUgYW5kIEVkZ2UgbWF5IHRocm93IGFuIFwiVW5zcGVjaWZpZWQgRXJyb3JcIiB3aGVuIGFjY2Vzc2luZyBkb2N1bWVudC5hY3RpdmVFbGVtZW50LlxuICAgIC8vIElFIDwgMTAgd2lsbCB0aHJvdyB3aGVuIGFjY2Vzc2VkIHdoaWxlIHRoZSBwYWdlIGlzIGxvYWRpbmcgb3IgaW4gYW4gaWZyYW1lLlxuICAgIC8vIElFID4gOSBhbmQgRWRnZSB3aWxsIHRocm93IHdoZW4gYWNjZXNzZWQgaW4gYW4gaWZyYW1lIGlmIGRvY3VtZW50LmJvZHkgaXMgdW5hdmFpbGFibGUuXG4gICAgdmFyIGFjdGl2ZUVsZW1lbnQ7XG4gICAgdHJ5IHtcbiAgICAgIGFjdGl2ZUVsZW1lbnQgPSBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuICAgIH0gY2F0Y2goZSkge1xuICAgICAgYWN0aXZlRWxlbWVudCA9IGRvY3VtZW50LmJvZHkgfHwgbnVsbDtcbiAgICB9XG4gICAgd2hpbGUgKGFjdGl2ZUVsZW1lbnQgJiYgYWN0aXZlRWxlbWVudC5zaGFkb3dSb290ICYmIGFjdGl2ZUVsZW1lbnQuc2hhZG93Um9vdC5hY3RpdmVFbGVtZW50KVxuICAgICAgeyBhY3RpdmVFbGVtZW50ID0gYWN0aXZlRWxlbWVudC5zaGFkb3dSb290LmFjdGl2ZUVsZW1lbnQ7IH1cbiAgICByZXR1cm4gYWN0aXZlRWxlbWVudFxuICB9XG5cbiAgZnVuY3Rpb24gYWRkQ2xhc3Mobm9kZSwgY2xzKSB7XG4gICAgdmFyIGN1cnJlbnQgPSBub2RlLmNsYXNzTmFtZTtcbiAgICBpZiAoIWNsYXNzVGVzdChjbHMpLnRlc3QoY3VycmVudCkpIHsgbm9kZS5jbGFzc05hbWUgKz0gKGN1cnJlbnQgPyBcIiBcIiA6IFwiXCIpICsgY2xzOyB9XG4gIH1cbiAgZnVuY3Rpb24gam9pbkNsYXNzZXMoYSwgYikge1xuICAgIHZhciBhcyA9IGEuc3BsaXQoXCIgXCIpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYXMubGVuZ3RoOyBpKyspXG4gICAgICB7IGlmIChhc1tpXSAmJiAhY2xhc3NUZXN0KGFzW2ldKS50ZXN0KGIpKSB7IGIgKz0gXCIgXCIgKyBhc1tpXTsgfSB9XG4gICAgcmV0dXJuIGJcbiAgfVxuXG4gIHZhciBzZWxlY3RJbnB1dCA9IGZ1bmN0aW9uKG5vZGUpIHsgbm9kZS5zZWxlY3QoKTsgfTtcbiAgaWYgKGlvcykgLy8gTW9iaWxlIFNhZmFyaSBhcHBhcmVudGx5IGhhcyBhIGJ1ZyB3aGVyZSBzZWxlY3QoKSBpcyBicm9rZW4uXG4gICAgeyBzZWxlY3RJbnB1dCA9IGZ1bmN0aW9uKG5vZGUpIHsgbm9kZS5zZWxlY3Rpb25TdGFydCA9IDA7IG5vZGUuc2VsZWN0aW9uRW5kID0gbm9kZS52YWx1ZS5sZW5ndGg7IH07IH1cbiAgZWxzZSBpZiAoaWUpIC8vIFN1cHByZXNzIG15c3RlcmlvdXMgSUUxMCBlcnJvcnNcbiAgICB7IHNlbGVjdElucHV0ID0gZnVuY3Rpb24obm9kZSkgeyB0cnkgeyBub2RlLnNlbGVjdCgpOyB9IGNhdGNoKF9lKSB7fSB9OyB9XG5cbiAgZnVuY3Rpb24gYmluZChmKSB7XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDEpO1xuICAgIHJldHVybiBmdW5jdGlvbigpe3JldHVybiBmLmFwcGx5KG51bGwsIGFyZ3MpfVxuICB9XG5cbiAgZnVuY3Rpb24gY29weU9iaihvYmosIHRhcmdldCwgb3ZlcndyaXRlKSB7XG4gICAgaWYgKCF0YXJnZXQpIHsgdGFyZ2V0ID0ge307IH1cbiAgICBmb3IgKHZhciBwcm9wIGluIG9iailcbiAgICAgIHsgaWYgKG9iai5oYXNPd25Qcm9wZXJ0eShwcm9wKSAmJiAob3ZlcndyaXRlICE9PSBmYWxzZSB8fCAhdGFyZ2V0Lmhhc093blByb3BlcnR5KHByb3ApKSlcbiAgICAgICAgeyB0YXJnZXRbcHJvcF0gPSBvYmpbcHJvcF07IH0gfVxuICAgIHJldHVybiB0YXJnZXRcbiAgfVxuXG4gIC8vIENvdW50cyB0aGUgY29sdW1uIG9mZnNldCBpbiBhIHN0cmluZywgdGFraW5nIHRhYnMgaW50byBhY2NvdW50LlxuICAvLyBVc2VkIG1vc3RseSB0byBmaW5kIGluZGVudGF0aW9uLlxuICBmdW5jdGlvbiBjb3VudENvbHVtbihzdHJpbmcsIGVuZCwgdGFiU2l6ZSwgc3RhcnRJbmRleCwgc3RhcnRWYWx1ZSkge1xuICAgIGlmIChlbmQgPT0gbnVsbCkge1xuICAgICAgZW5kID0gc3RyaW5nLnNlYXJjaCgvW15cXHNcXHUwMGEwXS8pO1xuICAgICAgaWYgKGVuZCA9PSAtMSkgeyBlbmQgPSBzdHJpbmcubGVuZ3RoOyB9XG4gICAgfVxuICAgIGZvciAodmFyIGkgPSBzdGFydEluZGV4IHx8IDAsIG4gPSBzdGFydFZhbHVlIHx8IDA7Oykge1xuICAgICAgdmFyIG5leHRUYWIgPSBzdHJpbmcuaW5kZXhPZihcIlxcdFwiLCBpKTtcbiAgICAgIGlmIChuZXh0VGFiIDwgMCB8fCBuZXh0VGFiID49IGVuZClcbiAgICAgICAgeyByZXR1cm4gbiArIChlbmQgLSBpKSB9XG4gICAgICBuICs9IG5leHRUYWIgLSBpO1xuICAgICAgbiArPSB0YWJTaXplIC0gKG4gJSB0YWJTaXplKTtcbiAgICAgIGkgPSBuZXh0VGFiICsgMTtcbiAgICB9XG4gIH1cblxuICB2YXIgRGVsYXllZCA9IGZ1bmN0aW9uKCkge3RoaXMuaWQgPSBudWxsO307XG4gIERlbGF5ZWQucHJvdG90eXBlLnNldCA9IGZ1bmN0aW9uIChtcywgZikge1xuICAgIGNsZWFyVGltZW91dCh0aGlzLmlkKTtcbiAgICB0aGlzLmlkID0gc2V0VGltZW91dChmLCBtcyk7XG4gIH07XG5cbiAgZnVuY3Rpb24gaW5kZXhPZihhcnJheSwgZWx0KSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7ICsraSlcbiAgICAgIHsgaWYgKGFycmF5W2ldID09IGVsdCkgeyByZXR1cm4gaSB9IH1cbiAgICByZXR1cm4gLTFcbiAgfVxuXG4gIC8vIE51bWJlciBvZiBwaXhlbHMgYWRkZWQgdG8gc2Nyb2xsZXIgYW5kIHNpemVyIHRvIGhpZGUgc2Nyb2xsYmFyXG4gIHZhciBzY3JvbGxlckdhcCA9IDMwO1xuXG4gIC8vIFJldHVybmVkIG9yIHRocm93biBieSB2YXJpb3VzIHByb3RvY29scyB0byBzaWduYWwgJ0knbSBub3RcbiAgLy8gaGFuZGxpbmcgdGhpcycuXG4gIHZhciBQYXNzID0ge3RvU3RyaW5nOiBmdW5jdGlvbigpe3JldHVybiBcIkNvZGVNaXJyb3IuUGFzc1wifX07XG5cbiAgLy8gUmV1c2VkIG9wdGlvbiBvYmplY3RzIGZvciBzZXRTZWxlY3Rpb24gJiBmcmllbmRzXG4gIHZhciBzZWxfZG9udFNjcm9sbCA9IHtzY3JvbGw6IGZhbHNlfSwgc2VsX21vdXNlID0ge29yaWdpbjogXCIqbW91c2VcIn0sIHNlbF9tb3ZlID0ge29yaWdpbjogXCIrbW92ZVwifTtcblxuICAvLyBUaGUgaW52ZXJzZSBvZiBjb3VudENvbHVtbiAtLSBmaW5kIHRoZSBvZmZzZXQgdGhhdCBjb3JyZXNwb25kcyB0b1xuICAvLyBhIHBhcnRpY3VsYXIgY29sdW1uLlxuICBmdW5jdGlvbiBmaW5kQ29sdW1uKHN0cmluZywgZ29hbCwgdGFiU2l6ZSkge1xuICAgIGZvciAodmFyIHBvcyA9IDAsIGNvbCA9IDA7Oykge1xuICAgICAgdmFyIG5leHRUYWIgPSBzdHJpbmcuaW5kZXhPZihcIlxcdFwiLCBwb3MpO1xuICAgICAgaWYgKG5leHRUYWIgPT0gLTEpIHsgbmV4dFRhYiA9IHN0cmluZy5sZW5ndGg7IH1cbiAgICAgIHZhciBza2lwcGVkID0gbmV4dFRhYiAtIHBvcztcbiAgICAgIGlmIChuZXh0VGFiID09IHN0cmluZy5sZW5ndGggfHwgY29sICsgc2tpcHBlZCA+PSBnb2FsKVxuICAgICAgICB7IHJldHVybiBwb3MgKyBNYXRoLm1pbihza2lwcGVkLCBnb2FsIC0gY29sKSB9XG4gICAgICBjb2wgKz0gbmV4dFRhYiAtIHBvcztcbiAgICAgIGNvbCArPSB0YWJTaXplIC0gKGNvbCAlIHRhYlNpemUpO1xuICAgICAgcG9zID0gbmV4dFRhYiArIDE7XG4gICAgICBpZiAoY29sID49IGdvYWwpIHsgcmV0dXJuIHBvcyB9XG4gICAgfVxuICB9XG5cbiAgdmFyIHNwYWNlU3RycyA9IFtcIlwiXTtcbiAgZnVuY3Rpb24gc3BhY2VTdHIobikge1xuICAgIHdoaWxlIChzcGFjZVN0cnMubGVuZ3RoIDw9IG4pXG4gICAgICB7IHNwYWNlU3Rycy5wdXNoKGxzdChzcGFjZVN0cnMpICsgXCIgXCIpOyB9XG4gICAgcmV0dXJuIHNwYWNlU3Ryc1tuXVxuICB9XG5cbiAgZnVuY3Rpb24gbHN0KGFycikgeyByZXR1cm4gYXJyW2Fyci5sZW5ndGgtMV0gfVxuXG4gIGZ1bmN0aW9uIG1hcChhcnJheSwgZikge1xuICAgIHZhciBvdXQgPSBbXTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgaSsrKSB7IG91dFtpXSA9IGYoYXJyYXlbaV0sIGkpOyB9XG4gICAgcmV0dXJuIG91dFxuICB9XG5cbiAgZnVuY3Rpb24gaW5zZXJ0U29ydGVkKGFycmF5LCB2YWx1ZSwgc2NvcmUpIHtcbiAgICB2YXIgcG9zID0gMCwgcHJpb3JpdHkgPSBzY29yZSh2YWx1ZSk7XG4gICAgd2hpbGUgKHBvcyA8IGFycmF5Lmxlbmd0aCAmJiBzY29yZShhcnJheVtwb3NdKSA8PSBwcmlvcml0eSkgeyBwb3MrKzsgfVxuICAgIGFycmF5LnNwbGljZShwb3MsIDAsIHZhbHVlKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG5vdGhpbmcoKSB7fVxuXG4gIGZ1bmN0aW9uIGNyZWF0ZU9iaihiYXNlLCBwcm9wcykge1xuICAgIHZhciBpbnN0O1xuICAgIGlmIChPYmplY3QuY3JlYXRlKSB7XG4gICAgICBpbnN0ID0gT2JqZWN0LmNyZWF0ZShiYXNlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgbm90aGluZy5wcm90b3R5cGUgPSBiYXNlO1xuICAgICAgaW5zdCA9IG5ldyBub3RoaW5nKCk7XG4gICAgfVxuICAgIGlmIChwcm9wcykgeyBjb3B5T2JqKHByb3BzLCBpbnN0KTsgfVxuICAgIHJldHVybiBpbnN0XG4gIH1cblxuICB2YXIgbm9uQVNDSUlTaW5nbGVDYXNlV29yZENoYXIgPSAvW1xcdTAwZGZcXHUwNTg3XFx1MDU5MC1cXHUwNWY0XFx1MDYwMC1cXHUwNmZmXFx1MzA0MC1cXHUzMDlmXFx1MzBhMC1cXHUzMGZmXFx1MzQwMC1cXHU0ZGI1XFx1NGUwMC1cXHU5ZmNjXFx1YWMwMC1cXHVkN2FmXS87XG4gIGZ1bmN0aW9uIGlzV29yZENoYXJCYXNpYyhjaCkge1xuICAgIHJldHVybiAvXFx3Ly50ZXN0KGNoKSB8fCBjaCA+IFwiXFx4ODBcIiAmJlxuICAgICAgKGNoLnRvVXBwZXJDYXNlKCkgIT0gY2gudG9Mb3dlckNhc2UoKSB8fCBub25BU0NJSVNpbmdsZUNhc2VXb3JkQ2hhci50ZXN0KGNoKSlcbiAgfVxuICBmdW5jdGlvbiBpc1dvcmRDaGFyKGNoLCBoZWxwZXIpIHtcbiAgICBpZiAoIWhlbHBlcikgeyByZXR1cm4gaXNXb3JkQ2hhckJhc2ljKGNoKSB9XG4gICAgaWYgKGhlbHBlci5zb3VyY2UuaW5kZXhPZihcIlxcXFx3XCIpID4gLTEgJiYgaXNXb3JkQ2hhckJhc2ljKGNoKSkgeyByZXR1cm4gdHJ1ZSB9XG4gICAgcmV0dXJuIGhlbHBlci50ZXN0KGNoKVxuICB9XG5cbiAgZnVuY3Rpb24gaXNFbXB0eShvYmopIHtcbiAgICBmb3IgKHZhciBuIGluIG9iaikgeyBpZiAob2JqLmhhc093blByb3BlcnR5KG4pICYmIG9ialtuXSkgeyByZXR1cm4gZmFsc2UgfSB9XG4gICAgcmV0dXJuIHRydWVcbiAgfVxuXG4gIC8vIEV4dGVuZGluZyB1bmljb2RlIGNoYXJhY3RlcnMuIEEgc2VyaWVzIG9mIGEgbm9uLWV4dGVuZGluZyBjaGFyICtcbiAgLy8gYW55IG51bWJlciBvZiBleHRlbmRpbmcgY2hhcnMgaXMgdHJlYXRlZCBhcyBhIHNpbmdsZSB1bml0IGFzIGZhclxuICAvLyBhcyBlZGl0aW5nIGFuZCBtZWFzdXJpbmcgaXMgY29uY2VybmVkLiBUaGlzIGlzIG5vdCBmdWxseSBjb3JyZWN0LFxuICAvLyBzaW5jZSBzb21lIHNjcmlwdHMvZm9udHMvYnJvd3NlcnMgYWxzbyB0cmVhdCBvdGhlciBjb25maWd1cmF0aW9uc1xuICAvLyBvZiBjb2RlIHBvaW50cyBhcyBhIGdyb3VwLlxuICB2YXIgZXh0ZW5kaW5nQ2hhcnMgPSAvW1xcdTAzMDAtXFx1MDM2ZlxcdTA0ODMtXFx1MDQ4OVxcdTA1OTEtXFx1MDViZFxcdTA1YmZcXHUwNWMxXFx1MDVjMlxcdTA1YzRcXHUwNWM1XFx1MDVjN1xcdTA2MTAtXFx1MDYxYVxcdTA2NGItXFx1MDY1ZVxcdTA2NzBcXHUwNmQ2LVxcdTA2ZGNcXHUwNmRlLVxcdTA2ZTRcXHUwNmU3XFx1MDZlOFxcdTA2ZWEtXFx1MDZlZFxcdTA3MTFcXHUwNzMwLVxcdTA3NGFcXHUwN2E2LVxcdTA3YjBcXHUwN2ViLVxcdTA3ZjNcXHUwODE2LVxcdTA4MTlcXHUwODFiLVxcdTA4MjNcXHUwODI1LVxcdTA4MjdcXHUwODI5LVxcdTA4MmRcXHUwOTAwLVxcdTA5MDJcXHUwOTNjXFx1MDk0MS1cXHUwOTQ4XFx1MDk0ZFxcdTA5NTEtXFx1MDk1NVxcdTA5NjJcXHUwOTYzXFx1MDk4MVxcdTA5YmNcXHUwOWJlXFx1MDljMS1cXHUwOWM0XFx1MDljZFxcdTA5ZDdcXHUwOWUyXFx1MDllM1xcdTBhMDFcXHUwYTAyXFx1MGEzY1xcdTBhNDFcXHUwYTQyXFx1MGE0N1xcdTBhNDhcXHUwYTRiLVxcdTBhNGRcXHUwYTUxXFx1MGE3MFxcdTBhNzFcXHUwYTc1XFx1MGE4MVxcdTBhODJcXHUwYWJjXFx1MGFjMS1cXHUwYWM1XFx1MGFjN1xcdTBhYzhcXHUwYWNkXFx1MGFlMlxcdTBhZTNcXHUwYjAxXFx1MGIzY1xcdTBiM2VcXHUwYjNmXFx1MGI0MS1cXHUwYjQ0XFx1MGI0ZFxcdTBiNTZcXHUwYjU3XFx1MGI2MlxcdTBiNjNcXHUwYjgyXFx1MGJiZVxcdTBiYzBcXHUwYmNkXFx1MGJkN1xcdTBjM2UtXFx1MGM0MFxcdTBjNDYtXFx1MGM0OFxcdTBjNGEtXFx1MGM0ZFxcdTBjNTVcXHUwYzU2XFx1MGM2MlxcdTBjNjNcXHUwY2JjXFx1MGNiZlxcdTBjYzJcXHUwY2M2XFx1MGNjY1xcdTBjY2RcXHUwY2Q1XFx1MGNkNlxcdTBjZTJcXHUwY2UzXFx1MGQzZVxcdTBkNDEtXFx1MGQ0NFxcdTBkNGRcXHUwZDU3XFx1MGQ2MlxcdTBkNjNcXHUwZGNhXFx1MGRjZlxcdTBkZDItXFx1MGRkNFxcdTBkZDZcXHUwZGRmXFx1MGUzMVxcdTBlMzQtXFx1MGUzYVxcdTBlNDctXFx1MGU0ZVxcdTBlYjFcXHUwZWI0LVxcdTBlYjlcXHUwZWJiXFx1MGViY1xcdTBlYzgtXFx1MGVjZFxcdTBmMThcXHUwZjE5XFx1MGYzNVxcdTBmMzdcXHUwZjM5XFx1MGY3MS1cXHUwZjdlXFx1MGY4MC1cXHUwZjg0XFx1MGY4NlxcdTBmODdcXHUwZjkwLVxcdTBmOTdcXHUwZjk5LVxcdTBmYmNcXHUwZmM2XFx1MTAyZC1cXHUxMDMwXFx1MTAzMi1cXHUxMDM3XFx1MTAzOVxcdTEwM2FcXHUxMDNkXFx1MTAzZVxcdTEwNThcXHUxMDU5XFx1MTA1ZS1cXHUxMDYwXFx1MTA3MS1cXHUxMDc0XFx1MTA4MlxcdTEwODVcXHUxMDg2XFx1MTA4ZFxcdTEwOWRcXHUxMzVmXFx1MTcxMi1cXHUxNzE0XFx1MTczMi1cXHUxNzM0XFx1MTc1MlxcdTE3NTNcXHUxNzcyXFx1MTc3M1xcdTE3YjctXFx1MTdiZFxcdTE3YzZcXHUxN2M5LVxcdTE3ZDNcXHUxN2RkXFx1MTgwYi1cXHUxODBkXFx1MThhOVxcdTE5MjAtXFx1MTkyMlxcdTE5MjdcXHUxOTI4XFx1MTkzMlxcdTE5MzktXFx1MTkzYlxcdTFhMTdcXHUxYTE4XFx1MWE1NlxcdTFhNTgtXFx1MWE1ZVxcdTFhNjBcXHUxYTYyXFx1MWE2NS1cXHUxYTZjXFx1MWE3My1cXHUxYTdjXFx1MWE3ZlxcdTFiMDAtXFx1MWIwM1xcdTFiMzRcXHUxYjM2LVxcdTFiM2FcXHUxYjNjXFx1MWI0MlxcdTFiNmItXFx1MWI3M1xcdTFiODBcXHUxYjgxXFx1MWJhMi1cXHUxYmE1XFx1MWJhOFxcdTFiYTlcXHUxYzJjLVxcdTFjMzNcXHUxYzM2XFx1MWMzN1xcdTFjZDAtXFx1MWNkMlxcdTFjZDQtXFx1MWNlMFxcdTFjZTItXFx1MWNlOFxcdTFjZWRcXHUxZGMwLVxcdTFkZTZcXHUxZGZkLVxcdTFkZmZcXHUyMDBjXFx1MjAwZFxcdTIwZDAtXFx1MjBmMFxcdTJjZWYtXFx1MmNmMVxcdTJkZTAtXFx1MmRmZlxcdTMwMmEtXFx1MzAyZlxcdTMwOTlcXHUzMDlhXFx1YTY2Zi1cXHVhNjcyXFx1YTY3Y1xcdWE2N2RcXHVhNmYwXFx1YTZmMVxcdWE4MDJcXHVhODA2XFx1YTgwYlxcdWE4MjVcXHVhODI2XFx1YThjNFxcdWE4ZTAtXFx1YThmMVxcdWE5MjYtXFx1YTkyZFxcdWE5NDctXFx1YTk1MVxcdWE5ODAtXFx1YTk4MlxcdWE5YjNcXHVhOWI2LVxcdWE5YjlcXHVhOWJjXFx1YWEyOS1cXHVhYTJlXFx1YWEzMVxcdWFhMzJcXHVhYTM1XFx1YWEzNlxcdWFhNDNcXHVhYTRjXFx1YWFiMFxcdWFhYjItXFx1YWFiNFxcdWFhYjdcXHVhYWI4XFx1YWFiZVxcdWFhYmZcXHVhYWMxXFx1YWJlNVxcdWFiZThcXHVhYmVkXFx1ZGMwMC1cXHVkZmZmXFx1ZmIxZVxcdWZlMDAtXFx1ZmUwZlxcdWZlMjAtXFx1ZmUyNlxcdWZmOWVcXHVmZjlmXS87XG4gIGZ1bmN0aW9uIGlzRXh0ZW5kaW5nQ2hhcihjaCkgeyByZXR1cm4gY2guY2hhckNvZGVBdCgwKSA+PSA3NjggJiYgZXh0ZW5kaW5nQ2hhcnMudGVzdChjaCkgfVxuXG4gIC8vIFJldHVybnMgYSBudW1iZXIgZnJvbSB0aGUgcmFuZ2UgW2AwYDsgYHN0ci5sZW5ndGhgXSB1bmxlc3MgYHBvc2AgaXMgb3V0c2lkZSB0aGF0IHJhbmdlLlxuICBmdW5jdGlvbiBza2lwRXh0ZW5kaW5nQ2hhcnMoc3RyLCBwb3MsIGRpcikge1xuICAgIHdoaWxlICgoZGlyIDwgMCA/IHBvcyA+IDAgOiBwb3MgPCBzdHIubGVuZ3RoKSAmJiBpc0V4dGVuZGluZ0NoYXIoc3RyLmNoYXJBdChwb3MpKSkgeyBwb3MgKz0gZGlyOyB9XG4gICAgcmV0dXJuIHBvc1xuICB9XG5cbiAgLy8gUmV0dXJucyB0aGUgdmFsdWUgZnJvbSB0aGUgcmFuZ2UgW2Bmcm9tYDsgYHRvYF0gdGhhdCBzYXRpc2ZpZXNcbiAgLy8gYHByZWRgIGFuZCBpcyBjbG9zZXN0IHRvIGBmcm9tYC4gQXNzdW1lcyB0aGF0IGF0IGxlYXN0IGB0b2BcbiAgLy8gc2F0aXNmaWVzIGBwcmVkYC4gU3VwcG9ydHMgYGZyb21gIGJlaW5nIGdyZWF0ZXIgdGhhbiBgdG9gLlxuICBmdW5jdGlvbiBmaW5kRmlyc3QocHJlZCwgZnJvbSwgdG8pIHtcbiAgICAvLyBBdCBhbnkgcG9pbnQgd2UgYXJlIGNlcnRhaW4gYHRvYCBzYXRpc2ZpZXMgYHByZWRgLCBkb24ndCBrbm93XG4gICAgLy8gd2hldGhlciBgZnJvbWAgZG9lcy5cbiAgICB2YXIgZGlyID0gZnJvbSA+IHRvID8gLTEgOiAxO1xuICAgIGZvciAoOzspIHtcbiAgICAgIGlmIChmcm9tID09IHRvKSB7IHJldHVybiBmcm9tIH1cbiAgICAgIHZhciBtaWRGID0gKGZyb20gKyB0bykgLyAyLCBtaWQgPSBkaXIgPCAwID8gTWF0aC5jZWlsKG1pZEYpIDogTWF0aC5mbG9vcihtaWRGKTtcbiAgICAgIGlmIChtaWQgPT0gZnJvbSkgeyByZXR1cm4gcHJlZChtaWQpID8gZnJvbSA6IHRvIH1cbiAgICAgIGlmIChwcmVkKG1pZCkpIHsgdG8gPSBtaWQ7IH1cbiAgICAgIGVsc2UgeyBmcm9tID0gbWlkICsgZGlyOyB9XG4gICAgfVxuICB9XG5cbiAgLy8gVGhlIGRpc3BsYXkgaGFuZGxlcyB0aGUgRE9NIGludGVncmF0aW9uLCBib3RoIGZvciBpbnB1dCByZWFkaW5nXG4gIC8vIGFuZCBjb250ZW50IGRyYXdpbmcuIEl0IGhvbGRzIHJlZmVyZW5jZXMgdG8gRE9NIG5vZGVzIGFuZFxuICAvLyBkaXNwbGF5LXJlbGF0ZWQgc3RhdGUuXG5cbiAgZnVuY3Rpb24gRGlzcGxheShwbGFjZSwgZG9jLCBpbnB1dCkge1xuICAgIHZhciBkID0gdGhpcztcbiAgICB0aGlzLmlucHV0ID0gaW5wdXQ7XG5cbiAgICAvLyBDb3ZlcnMgYm90dG9tLXJpZ2h0IHNxdWFyZSB3aGVuIGJvdGggc2Nyb2xsYmFycyBhcmUgcHJlc2VudC5cbiAgICBkLnNjcm9sbGJhckZpbGxlciA9IGVsdChcImRpdlwiLCBudWxsLCBcIkNvZGVNaXJyb3Itc2Nyb2xsYmFyLWZpbGxlclwiKTtcbiAgICBkLnNjcm9sbGJhckZpbGxlci5zZXRBdHRyaWJ1dGUoXCJjbS1ub3QtY29udGVudFwiLCBcInRydWVcIik7XG4gICAgLy8gQ292ZXJzIGJvdHRvbSBvZiBndXR0ZXIgd2hlbiBjb3Zlckd1dHRlck5leHRUb1Njcm9sbGJhciBpcyBvblxuICAgIC8vIGFuZCBoIHNjcm9sbGJhciBpcyBwcmVzZW50LlxuICAgIGQuZ3V0dGVyRmlsbGVyID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1ndXR0ZXItZmlsbGVyXCIpO1xuICAgIGQuZ3V0dGVyRmlsbGVyLnNldEF0dHJpYnV0ZShcImNtLW5vdC1jb250ZW50XCIsIFwidHJ1ZVwiKTtcbiAgICAvLyBXaWxsIGNvbnRhaW4gdGhlIGFjdHVhbCBjb2RlLCBwb3NpdGlvbmVkIHRvIGNvdmVyIHRoZSB2aWV3cG9ydC5cbiAgICBkLmxpbmVEaXYgPSBlbHRQKFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1jb2RlXCIpO1xuICAgIC8vIEVsZW1lbnRzIGFyZSBhZGRlZCB0byB0aGVzZSB0byByZXByZXNlbnQgc2VsZWN0aW9uIGFuZCBjdXJzb3JzLlxuICAgIGQuc2VsZWN0aW9uRGl2ID0gZWx0KFwiZGl2XCIsIG51bGwsIG51bGwsIFwicG9zaXRpb246IHJlbGF0aXZlOyB6LWluZGV4OiAxXCIpO1xuICAgIGQuY3Vyc29yRGl2ID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1jdXJzb3JzXCIpO1xuICAgIC8vIEEgdmlzaWJpbGl0eTogaGlkZGVuIGVsZW1lbnQgdXNlZCB0byBmaW5kIHRoZSBzaXplIG9mIHRoaW5ncy5cbiAgICBkLm1lYXN1cmUgPSBlbHQoXCJkaXZcIiwgbnVsbCwgXCJDb2RlTWlycm9yLW1lYXN1cmVcIik7XG4gICAgLy8gV2hlbiBsaW5lcyBvdXRzaWRlIG9mIHRoZSB2aWV3cG9ydCBhcmUgbWVhc3VyZWQsIHRoZXkgYXJlIGRyYXduIGluIHRoaXMuXG4gICAgZC5saW5lTWVhc3VyZSA9IGVsdChcImRpdlwiLCBudWxsLCBcIkNvZGVNaXJyb3ItbWVhc3VyZVwiKTtcbiAgICAvLyBXcmFwcyBldmVyeXRoaW5nIHRoYXQgbmVlZHMgdG8gZXhpc3QgaW5zaWRlIHRoZSB2ZXJ0aWNhbGx5LXBhZGRlZCBjb29yZGluYXRlIHN5c3RlbVxuICAgIGQubGluZVNwYWNlID0gZWx0UChcImRpdlwiLCBbZC5tZWFzdXJlLCBkLmxpbmVNZWFzdXJlLCBkLnNlbGVjdGlvbkRpdiwgZC5jdXJzb3JEaXYsIGQubGluZURpdl0sXG4gICAgICAgICAgICAgICAgICAgICAgbnVsbCwgXCJwb3NpdGlvbjogcmVsYXRpdmU7IG91dGxpbmU6IG5vbmVcIik7XG4gICAgdmFyIGxpbmVzID0gZWx0UChcImRpdlwiLCBbZC5saW5lU3BhY2VdLCBcIkNvZGVNaXJyb3ItbGluZXNcIik7XG4gICAgLy8gTW92ZWQgYXJvdW5kIGl0cyBwYXJlbnQgdG8gY292ZXIgdmlzaWJsZSB2aWV3LlxuICAgIGQubW92ZXIgPSBlbHQoXCJkaXZcIiwgW2xpbmVzXSwgbnVsbCwgXCJwb3NpdGlvbjogcmVsYXRpdmVcIik7XG4gICAgLy8gU2V0IHRvIHRoZSBoZWlnaHQgb2YgdGhlIGRvY3VtZW50LCBhbGxvd2luZyBzY3JvbGxpbmcuXG4gICAgZC5zaXplciA9IGVsdChcImRpdlwiLCBbZC5tb3Zlcl0sIFwiQ29kZU1pcnJvci1zaXplclwiKTtcbiAgICBkLnNpemVyV2lkdGggPSBudWxsO1xuICAgIC8vIEJlaGF2aW9yIG9mIGVsdHMgd2l0aCBvdmVyZmxvdzogYXV0byBhbmQgcGFkZGluZyBpc1xuICAgIC8vIGluY29uc2lzdGVudCBhY3Jvc3MgYnJvd3NlcnMuIFRoaXMgaXMgdXNlZCB0byBlbnN1cmUgdGhlXG4gICAgLy8gc2Nyb2xsYWJsZSBhcmVhIGlzIGJpZyBlbm91Z2guXG4gICAgZC5oZWlnaHRGb3JjZXIgPSBlbHQoXCJkaXZcIiwgbnVsbCwgbnVsbCwgXCJwb3NpdGlvbjogYWJzb2x1dGU7IGhlaWdodDogXCIgKyBzY3JvbGxlckdhcCArIFwicHg7IHdpZHRoOiAxcHg7XCIpO1xuICAgIC8vIFdpbGwgY29udGFpbiB0aGUgZ3V0dGVycywgaWYgYW55LlxuICAgIGQuZ3V0dGVycyA9IGVsdChcImRpdlwiLCBudWxsLCBcIkNvZGVNaXJyb3ItZ3V0dGVyc1wiKTtcbiAgICBkLmxpbmVHdXR0ZXIgPSBudWxsO1xuICAgIC8vIEFjdHVhbCBzY3JvbGxhYmxlIGVsZW1lbnQuXG4gICAgZC5zY3JvbGxlciA9IGVsdChcImRpdlwiLCBbZC5zaXplciwgZC5oZWlnaHRGb3JjZXIsIGQuZ3V0dGVyc10sIFwiQ29kZU1pcnJvci1zY3JvbGxcIik7XG4gICAgZC5zY3JvbGxlci5zZXRBdHRyaWJ1dGUoXCJ0YWJJbmRleFwiLCBcIi0xXCIpO1xuICAgIC8vIFRoZSBlbGVtZW50IGluIHdoaWNoIHRoZSBlZGl0b3IgbGl2ZXMuXG4gICAgZC53cmFwcGVyID0gZWx0KFwiZGl2XCIsIFtkLnNjcm9sbGJhckZpbGxlciwgZC5ndXR0ZXJGaWxsZXIsIGQuc2Nyb2xsZXJdLCBcIkNvZGVNaXJyb3JcIik7XG5cbiAgICAvLyBXb3JrIGFyb3VuZCBJRTcgei1pbmRleCBidWcgKG5vdCBwZXJmZWN0LCBoZW5jZSBJRTcgbm90IHJlYWxseSBiZWluZyBzdXBwb3J0ZWQpXG4gICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCA4KSB7IGQuZ3V0dGVycy5zdHlsZS56SW5kZXggPSAtMTsgZC5zY3JvbGxlci5zdHlsZS5wYWRkaW5nUmlnaHQgPSAwOyB9XG4gICAgaWYgKCF3ZWJraXQgJiYgIShnZWNrbyAmJiBtb2JpbGUpKSB7IGQuc2Nyb2xsZXIuZHJhZ2dhYmxlID0gdHJ1ZTsgfVxuXG4gICAgaWYgKHBsYWNlKSB7XG4gICAgICBpZiAocGxhY2UuYXBwZW5kQ2hpbGQpIHsgcGxhY2UuYXBwZW5kQ2hpbGQoZC53cmFwcGVyKTsgfVxuICAgICAgZWxzZSB7IHBsYWNlKGQud3JhcHBlcik7IH1cbiAgICB9XG5cbiAgICAvLyBDdXJyZW50IHJlbmRlcmVkIHJhbmdlIChtYXkgYmUgYmlnZ2VyIHRoYW4gdGhlIHZpZXcgd2luZG93KS5cbiAgICBkLnZpZXdGcm9tID0gZC52aWV3VG8gPSBkb2MuZmlyc3Q7XG4gICAgZC5yZXBvcnRlZFZpZXdGcm9tID0gZC5yZXBvcnRlZFZpZXdUbyA9IGRvYy5maXJzdDtcbiAgICAvLyBJbmZvcm1hdGlvbiBhYm91dCB0aGUgcmVuZGVyZWQgbGluZXMuXG4gICAgZC52aWV3ID0gW107XG4gICAgZC5yZW5kZXJlZFZpZXcgPSBudWxsO1xuICAgIC8vIEhvbGRzIGluZm8gYWJvdXQgYSBzaW5nbGUgcmVuZGVyZWQgbGluZSB3aGVuIGl0IHdhcyByZW5kZXJlZFxuICAgIC8vIGZvciBtZWFzdXJlbWVudCwgd2hpbGUgbm90IGluIHZpZXcuXG4gICAgZC5leHRlcm5hbE1lYXN1cmVkID0gbnVsbDtcbiAgICAvLyBFbXB0eSBzcGFjZSAoaW4gcGl4ZWxzKSBhYm92ZSB0aGUgdmlld1xuICAgIGQudmlld09mZnNldCA9IDA7XG4gICAgZC5sYXN0V3JhcEhlaWdodCA9IGQubGFzdFdyYXBXaWR0aCA9IDA7XG4gICAgZC51cGRhdGVMaW5lTnVtYmVycyA9IG51bGw7XG5cbiAgICBkLm5hdGl2ZUJhcldpZHRoID0gZC5iYXJIZWlnaHQgPSBkLmJhcldpZHRoID0gMDtcbiAgICBkLnNjcm9sbGJhcnNDbGlwcGVkID0gZmFsc2U7XG5cbiAgICAvLyBVc2VkIHRvIG9ubHkgcmVzaXplIHRoZSBsaW5lIG51bWJlciBndXR0ZXIgd2hlbiBuZWNlc3NhcnkgKHdoZW5cbiAgICAvLyB0aGUgYW1vdW50IG9mIGxpbmVzIGNyb3NzZXMgYSBib3VuZGFyeSB0aGF0IG1ha2VzIGl0cyB3aWR0aCBjaGFuZ2UpXG4gICAgZC5saW5lTnVtV2lkdGggPSBkLmxpbmVOdW1Jbm5lcldpZHRoID0gZC5saW5lTnVtQ2hhcnMgPSBudWxsO1xuICAgIC8vIFNldCB0byB0cnVlIHdoZW4gYSBub24taG9yaXpvbnRhbC1zY3JvbGxpbmcgbGluZSB3aWRnZXQgaXNcbiAgICAvLyBhZGRlZC4gQXMgYW4gb3B0aW1pemF0aW9uLCBsaW5lIHdpZGdldCBhbGlnbmluZyBpcyBza2lwcGVkIHdoZW5cbiAgICAvLyB0aGlzIGlzIGZhbHNlLlxuICAgIGQuYWxpZ25XaWRnZXRzID0gZmFsc2U7XG5cbiAgICBkLmNhY2hlZENoYXJXaWR0aCA9IGQuY2FjaGVkVGV4dEhlaWdodCA9IGQuY2FjaGVkUGFkZGluZ0ggPSBudWxsO1xuXG4gICAgLy8gVHJhY2tzIHRoZSBtYXhpbXVtIGxpbmUgbGVuZ3RoIHNvIHRoYXQgdGhlIGhvcml6b250YWwgc2Nyb2xsYmFyXG4gICAgLy8gY2FuIGJlIGtlcHQgc3RhdGljIHdoZW4gc2Nyb2xsaW5nLlxuICAgIGQubWF4TGluZSA9IG51bGw7XG4gICAgZC5tYXhMaW5lTGVuZ3RoID0gMDtcbiAgICBkLm1heExpbmVDaGFuZ2VkID0gZmFsc2U7XG5cbiAgICAvLyBVc2VkIGZvciBtZWFzdXJpbmcgd2hlZWwgc2Nyb2xsaW5nIGdyYW51bGFyaXR5XG4gICAgZC53aGVlbERYID0gZC53aGVlbERZID0gZC53aGVlbFN0YXJ0WCA9IGQud2hlZWxTdGFydFkgPSBudWxsO1xuXG4gICAgLy8gVHJ1ZSB3aGVuIHNoaWZ0IGlzIGhlbGQgZG93bi5cbiAgICBkLnNoaWZ0ID0gZmFsc2U7XG5cbiAgICAvLyBVc2VkIHRvIHRyYWNrIHdoZXRoZXIgYW55dGhpbmcgaGFwcGVuZWQgc2luY2UgdGhlIGNvbnRleHQgbWVudVxuICAgIC8vIHdhcyBvcGVuZWQuXG4gICAgZC5zZWxGb3JDb250ZXh0TWVudSA9IG51bGw7XG5cbiAgICBkLmFjdGl2ZVRvdWNoID0gbnVsbDtcblxuICAgIGlucHV0LmluaXQoZCk7XG4gIH1cblxuICAvLyBGaW5kIHRoZSBsaW5lIG9iamVjdCBjb3JyZXNwb25kaW5nIHRvIHRoZSBnaXZlbiBsaW5lIG51bWJlci5cbiAgZnVuY3Rpb24gZ2V0TGluZShkb2MsIG4pIHtcbiAgICBuIC09IGRvYy5maXJzdDtcbiAgICBpZiAobiA8IDAgfHwgbiA+PSBkb2Muc2l6ZSkgeyB0aHJvdyBuZXcgRXJyb3IoXCJUaGVyZSBpcyBubyBsaW5lIFwiICsgKG4gKyBkb2MuZmlyc3QpICsgXCIgaW4gdGhlIGRvY3VtZW50LlwiKSB9XG4gICAgdmFyIGNodW5rID0gZG9jO1xuICAgIHdoaWxlICghY2h1bmsubGluZXMpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOzsgKytpKSB7XG4gICAgICAgIHZhciBjaGlsZCA9IGNodW5rLmNoaWxkcmVuW2ldLCBzeiA9IGNoaWxkLmNodW5rU2l6ZSgpO1xuICAgICAgICBpZiAobiA8IHN6KSB7IGNodW5rID0gY2hpbGQ7IGJyZWFrIH1cbiAgICAgICAgbiAtPSBzejtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGNodW5rLmxpbmVzW25dXG4gIH1cblxuICAvLyBHZXQgdGhlIHBhcnQgb2YgYSBkb2N1bWVudCBiZXR3ZWVuIHR3byBwb3NpdGlvbnMsIGFzIGFuIGFycmF5IG9mXG4gIC8vIHN0cmluZ3MuXG4gIGZ1bmN0aW9uIGdldEJldHdlZW4oZG9jLCBzdGFydCwgZW5kKSB7XG4gICAgdmFyIG91dCA9IFtdLCBuID0gc3RhcnQubGluZTtcbiAgICBkb2MuaXRlcihzdGFydC5saW5lLCBlbmQubGluZSArIDEsIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICB2YXIgdGV4dCA9IGxpbmUudGV4dDtcbiAgICAgIGlmIChuID09IGVuZC5saW5lKSB7IHRleHQgPSB0ZXh0LnNsaWNlKDAsIGVuZC5jaCk7IH1cbiAgICAgIGlmIChuID09IHN0YXJ0LmxpbmUpIHsgdGV4dCA9IHRleHQuc2xpY2Uoc3RhcnQuY2gpOyB9XG4gICAgICBvdXQucHVzaCh0ZXh0KTtcbiAgICAgICsrbjtcbiAgICB9KTtcbiAgICByZXR1cm4gb3V0XG4gIH1cbiAgLy8gR2V0IHRoZSBsaW5lcyBiZXR3ZWVuIGZyb20gYW5kIHRvLCBhcyBhcnJheSBvZiBzdHJpbmdzLlxuICBmdW5jdGlvbiBnZXRMaW5lcyhkb2MsIGZyb20sIHRvKSB7XG4gICAgdmFyIG91dCA9IFtdO1xuICAgIGRvYy5pdGVyKGZyb20sIHRvLCBmdW5jdGlvbiAobGluZSkgeyBvdXQucHVzaChsaW5lLnRleHQpOyB9KTsgLy8gaXRlciBhYm9ydHMgd2hlbiBjYWxsYmFjayByZXR1cm5zIHRydXRoeSB2YWx1ZVxuICAgIHJldHVybiBvdXRcbiAgfVxuXG4gIC8vIFVwZGF0ZSB0aGUgaGVpZ2h0IG9mIGEgbGluZSwgcHJvcGFnYXRpbmcgdGhlIGhlaWdodCBjaGFuZ2VcbiAgLy8gdXB3YXJkcyB0byBwYXJlbnQgbm9kZXMuXG4gIGZ1bmN0aW9uIHVwZGF0ZUxpbmVIZWlnaHQobGluZSwgaGVpZ2h0KSB7XG4gICAgdmFyIGRpZmYgPSBoZWlnaHQgLSBsaW5lLmhlaWdodDtcbiAgICBpZiAoZGlmZikgeyBmb3IgKHZhciBuID0gbGluZTsgbjsgbiA9IG4ucGFyZW50KSB7IG4uaGVpZ2h0ICs9IGRpZmY7IH0gfVxuICB9XG5cbiAgLy8gR2l2ZW4gYSBsaW5lIG9iamVjdCwgZmluZCBpdHMgbGluZSBudW1iZXIgYnkgd2Fsa2luZyB1cCB0aHJvdWdoXG4gIC8vIGl0cyBwYXJlbnQgbGlua3MuXG4gIGZ1bmN0aW9uIGxpbmVObyhsaW5lKSB7XG4gICAgaWYgKGxpbmUucGFyZW50ID09IG51bGwpIHsgcmV0dXJuIG51bGwgfVxuICAgIHZhciBjdXIgPSBsaW5lLnBhcmVudCwgbm8gPSBpbmRleE9mKGN1ci5saW5lcywgbGluZSk7XG4gICAgZm9yICh2YXIgY2h1bmsgPSBjdXIucGFyZW50OyBjaHVuazsgY3VyID0gY2h1bmssIGNodW5rID0gY2h1bmsucGFyZW50KSB7XG4gICAgICBmb3IgKHZhciBpID0gMDs7ICsraSkge1xuICAgICAgICBpZiAoY2h1bmsuY2hpbGRyZW5baV0gPT0gY3VyKSB7IGJyZWFrIH1cbiAgICAgICAgbm8gKz0gY2h1bmsuY2hpbGRyZW5baV0uY2h1bmtTaXplKCk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBubyArIGN1ci5maXJzdFxuICB9XG5cbiAgLy8gRmluZCB0aGUgbGluZSBhdCB0aGUgZ2l2ZW4gdmVydGljYWwgcG9zaXRpb24sIHVzaW5nIHRoZSBoZWlnaHRcbiAgLy8gaW5mb3JtYXRpb24gaW4gdGhlIGRvY3VtZW50IHRyZWUuXG4gIGZ1bmN0aW9uIGxpbmVBdEhlaWdodChjaHVuaywgaCkge1xuICAgIHZhciBuID0gY2h1bmsuZmlyc3Q7XG4gICAgb3V0ZXI6IGRvIHtcbiAgICAgIGZvciAodmFyIGkkMSA9IDA7IGkkMSA8IGNodW5rLmNoaWxkcmVuLmxlbmd0aDsgKytpJDEpIHtcbiAgICAgICAgdmFyIGNoaWxkID0gY2h1bmsuY2hpbGRyZW5baSQxXSwgY2ggPSBjaGlsZC5oZWlnaHQ7XG4gICAgICAgIGlmIChoIDwgY2gpIHsgY2h1bmsgPSBjaGlsZDsgY29udGludWUgb3V0ZXIgfVxuICAgICAgICBoIC09IGNoO1xuICAgICAgICBuICs9IGNoaWxkLmNodW5rU2l6ZSgpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIG5cbiAgICB9IHdoaWxlICghY2h1bmsubGluZXMpXG4gICAgdmFyIGkgPSAwO1xuICAgIGZvciAoOyBpIDwgY2h1bmsubGluZXMubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBsaW5lID0gY2h1bmsubGluZXNbaV0sIGxoID0gbGluZS5oZWlnaHQ7XG4gICAgICBpZiAoaCA8IGxoKSB7IGJyZWFrIH1cbiAgICAgIGggLT0gbGg7XG4gICAgfVxuICAgIHJldHVybiBuICsgaVxuICB9XG5cbiAgZnVuY3Rpb24gaXNMaW5lKGRvYywgbCkge3JldHVybiBsID49IGRvYy5maXJzdCAmJiBsIDwgZG9jLmZpcnN0ICsgZG9jLnNpemV9XG5cbiAgZnVuY3Rpb24gbGluZU51bWJlckZvcihvcHRpb25zLCBpKSB7XG4gICAgcmV0dXJuIFN0cmluZyhvcHRpb25zLmxpbmVOdW1iZXJGb3JtYXR0ZXIoaSArIG9wdGlvbnMuZmlyc3RMaW5lTnVtYmVyKSlcbiAgfVxuXG4gIC8vIEEgUG9zIGluc3RhbmNlIHJlcHJlc2VudHMgYSBwb3NpdGlvbiB3aXRoaW4gdGhlIHRleHQuXG4gIGZ1bmN0aW9uIFBvcyhsaW5lLCBjaCwgc3RpY2t5KSB7XG4gICAgaWYgKCBzdGlja3kgPT09IHZvaWQgMCApIHN0aWNreSA9IG51bGw7XG5cbiAgICBpZiAoISh0aGlzIGluc3RhbmNlb2YgUG9zKSkgeyByZXR1cm4gbmV3IFBvcyhsaW5lLCBjaCwgc3RpY2t5KSB9XG4gICAgdGhpcy5saW5lID0gbGluZTtcbiAgICB0aGlzLmNoID0gY2g7XG4gICAgdGhpcy5zdGlja3kgPSBzdGlja3k7XG4gIH1cblxuICAvLyBDb21wYXJlIHR3byBwb3NpdGlvbnMsIHJldHVybiAwIGlmIHRoZXkgYXJlIHRoZSBzYW1lLCBhIG5lZ2F0aXZlXG4gIC8vIG51bWJlciB3aGVuIGEgaXMgbGVzcywgYW5kIGEgcG9zaXRpdmUgbnVtYmVyIG90aGVyd2lzZS5cbiAgZnVuY3Rpb24gY21wKGEsIGIpIHsgcmV0dXJuIGEubGluZSAtIGIubGluZSB8fCBhLmNoIC0gYi5jaCB9XG5cbiAgZnVuY3Rpb24gZXF1YWxDdXJzb3JQb3MoYSwgYikgeyByZXR1cm4gYS5zdGlja3kgPT0gYi5zdGlja3kgJiYgY21wKGEsIGIpID09IDAgfVxuXG4gIGZ1bmN0aW9uIGNvcHlQb3MoeCkge3JldHVybiBQb3MoeC5saW5lLCB4LmNoKX1cbiAgZnVuY3Rpb24gbWF4UG9zKGEsIGIpIHsgcmV0dXJuIGNtcChhLCBiKSA8IDAgPyBiIDogYSB9XG4gIGZ1bmN0aW9uIG1pblBvcyhhLCBiKSB7IHJldHVybiBjbXAoYSwgYikgPCAwID8gYSA6IGIgfVxuXG4gIC8vIE1vc3Qgb2YgdGhlIGV4dGVybmFsIEFQSSBjbGlwcyBnaXZlbiBwb3NpdGlvbnMgdG8gbWFrZSBzdXJlIHRoZXlcbiAgLy8gYWN0dWFsbHkgZXhpc3Qgd2l0aGluIHRoZSBkb2N1bWVudC5cbiAgZnVuY3Rpb24gY2xpcExpbmUoZG9jLCBuKSB7cmV0dXJuIE1hdGgubWF4KGRvYy5maXJzdCwgTWF0aC5taW4obiwgZG9jLmZpcnN0ICsgZG9jLnNpemUgLSAxKSl9XG4gIGZ1bmN0aW9uIGNsaXBQb3MoZG9jLCBwb3MpIHtcbiAgICBpZiAocG9zLmxpbmUgPCBkb2MuZmlyc3QpIHsgcmV0dXJuIFBvcyhkb2MuZmlyc3QsIDApIH1cbiAgICB2YXIgbGFzdCA9IGRvYy5maXJzdCArIGRvYy5zaXplIC0gMTtcbiAgICBpZiAocG9zLmxpbmUgPiBsYXN0KSB7IHJldHVybiBQb3MobGFzdCwgZ2V0TGluZShkb2MsIGxhc3QpLnRleHQubGVuZ3RoKSB9XG4gICAgcmV0dXJuIGNsaXBUb0xlbihwb3MsIGdldExpbmUoZG9jLCBwb3MubGluZSkudGV4dC5sZW5ndGgpXG4gIH1cbiAgZnVuY3Rpb24gY2xpcFRvTGVuKHBvcywgbGluZWxlbikge1xuICAgIHZhciBjaCA9IHBvcy5jaDtcbiAgICBpZiAoY2ggPT0gbnVsbCB8fCBjaCA+IGxpbmVsZW4pIHsgcmV0dXJuIFBvcyhwb3MubGluZSwgbGluZWxlbikgfVxuICAgIGVsc2UgaWYgKGNoIDwgMCkgeyByZXR1cm4gUG9zKHBvcy5saW5lLCAwKSB9XG4gICAgZWxzZSB7IHJldHVybiBwb3MgfVxuICB9XG4gIGZ1bmN0aW9uIGNsaXBQb3NBcnJheShkb2MsIGFycmF5KSB7XG4gICAgdmFyIG91dCA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgYXJyYXkubGVuZ3RoOyBpKyspIHsgb3V0W2ldID0gY2xpcFBvcyhkb2MsIGFycmF5W2ldKTsgfVxuICAgIHJldHVybiBvdXRcbiAgfVxuXG4gIC8vIE9wdGltaXplIHNvbWUgY29kZSB3aGVuIHRoZXNlIGZlYXR1cmVzIGFyZSBub3QgdXNlZC5cbiAgdmFyIHNhd1JlYWRPbmx5U3BhbnMgPSBmYWxzZSwgc2F3Q29sbGFwc2VkU3BhbnMgPSBmYWxzZTtcblxuICBmdW5jdGlvbiBzZWVSZWFkT25seVNwYW5zKCkge1xuICAgIHNhd1JlYWRPbmx5U3BhbnMgPSB0cnVlO1xuICB9XG5cbiAgZnVuY3Rpb24gc2VlQ29sbGFwc2VkU3BhbnMoKSB7XG4gICAgc2F3Q29sbGFwc2VkU3BhbnMgPSB0cnVlO1xuICB9XG5cbiAgLy8gVEVYVE1BUktFUiBTUEFOU1xuXG4gIGZ1bmN0aW9uIE1hcmtlZFNwYW4obWFya2VyLCBmcm9tLCB0bykge1xuICAgIHRoaXMubWFya2VyID0gbWFya2VyO1xuICAgIHRoaXMuZnJvbSA9IGZyb207IHRoaXMudG8gPSB0bztcbiAgfVxuXG4gIC8vIFNlYXJjaCBhbiBhcnJheSBvZiBzcGFucyBmb3IgYSBzcGFuIG1hdGNoaW5nIHRoZSBnaXZlbiBtYXJrZXIuXG4gIGZ1bmN0aW9uIGdldE1hcmtlZFNwYW5Gb3Ioc3BhbnMsIG1hcmtlcikge1xuICAgIGlmIChzcGFucykgeyBmb3IgKHZhciBpID0gMDsgaSA8IHNwYW5zLmxlbmd0aDsgKytpKSB7XG4gICAgICB2YXIgc3BhbiA9IHNwYW5zW2ldO1xuICAgICAgaWYgKHNwYW4ubWFya2VyID09IG1hcmtlcikgeyByZXR1cm4gc3BhbiB9XG4gICAgfSB9XG4gIH1cbiAgLy8gUmVtb3ZlIGEgc3BhbiBmcm9tIGFuIGFycmF5LCByZXR1cm5pbmcgdW5kZWZpbmVkIGlmIG5vIHNwYW5zIGFyZVxuICAvLyBsZWZ0ICh3ZSBkb24ndCBzdG9yZSBhcnJheXMgZm9yIGxpbmVzIHdpdGhvdXQgc3BhbnMpLlxuICBmdW5jdGlvbiByZW1vdmVNYXJrZWRTcGFuKHNwYW5zLCBzcGFuKSB7XG4gICAgdmFyIHI7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzcGFucy5sZW5ndGg7ICsraSlcbiAgICAgIHsgaWYgKHNwYW5zW2ldICE9IHNwYW4pIHsgKHIgfHwgKHIgPSBbXSkpLnB1c2goc3BhbnNbaV0pOyB9IH1cbiAgICByZXR1cm4gclxuICB9XG4gIC8vIEFkZCBhIHNwYW4gdG8gYSBsaW5lLlxuICBmdW5jdGlvbiBhZGRNYXJrZWRTcGFuKGxpbmUsIHNwYW4pIHtcbiAgICBsaW5lLm1hcmtlZFNwYW5zID0gbGluZS5tYXJrZWRTcGFucyA/IGxpbmUubWFya2VkU3BhbnMuY29uY2F0KFtzcGFuXSkgOiBbc3Bhbl07XG4gICAgc3Bhbi5tYXJrZXIuYXR0YWNoTGluZShsaW5lKTtcbiAgfVxuXG4gIC8vIFVzZWQgZm9yIHRoZSBhbGdvcml0aG0gdGhhdCBhZGp1c3RzIG1hcmtlcnMgZm9yIGEgY2hhbmdlIGluIHRoZVxuICAvLyBkb2N1bWVudC4gVGhlc2UgZnVuY3Rpb25zIGN1dCBhbiBhcnJheSBvZiBzcGFucyBhdCBhIGdpdmVuXG4gIC8vIGNoYXJhY3RlciBwb3NpdGlvbiwgcmV0dXJuaW5nIGFuIGFycmF5IG9mIHJlbWFpbmluZyBjaHVua3MgKG9yXG4gIC8vIHVuZGVmaW5lZCBpZiBub3RoaW5nIHJlbWFpbnMpLlxuICBmdW5jdGlvbiBtYXJrZWRTcGFuc0JlZm9yZShvbGQsIHN0YXJ0Q2gsIGlzSW5zZXJ0KSB7XG4gICAgdmFyIG53O1xuICAgIGlmIChvbGQpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBvbGQubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBzcGFuID0gb2xkW2ldLCBtYXJrZXIgPSBzcGFuLm1hcmtlcjtcbiAgICAgIHZhciBzdGFydHNCZWZvcmUgPSBzcGFuLmZyb20gPT0gbnVsbCB8fCAobWFya2VyLmluY2x1c2l2ZUxlZnQgPyBzcGFuLmZyb20gPD0gc3RhcnRDaCA6IHNwYW4uZnJvbSA8IHN0YXJ0Q2gpO1xuICAgICAgaWYgKHN0YXJ0c0JlZm9yZSB8fCBzcGFuLmZyb20gPT0gc3RhcnRDaCAmJiBtYXJrZXIudHlwZSA9PSBcImJvb2ttYXJrXCIgJiYgKCFpc0luc2VydCB8fCAhc3Bhbi5tYXJrZXIuaW5zZXJ0TGVmdCkpIHtcbiAgICAgICAgdmFyIGVuZHNBZnRlciA9IHNwYW4udG8gPT0gbnVsbCB8fCAobWFya2VyLmluY2x1c2l2ZVJpZ2h0ID8gc3Bhbi50byA+PSBzdGFydENoIDogc3Bhbi50byA+IHN0YXJ0Q2gpXG4gICAgICAgIDsobncgfHwgKG53ID0gW10pKS5wdXNoKG5ldyBNYXJrZWRTcGFuKG1hcmtlciwgc3Bhbi5mcm9tLCBlbmRzQWZ0ZXIgPyBudWxsIDogc3Bhbi50bykpO1xuICAgICAgfVxuICAgIH0gfVxuICAgIHJldHVybiBud1xuICB9XG4gIGZ1bmN0aW9uIG1hcmtlZFNwYW5zQWZ0ZXIob2xkLCBlbmRDaCwgaXNJbnNlcnQpIHtcbiAgICB2YXIgbnc7XG4gICAgaWYgKG9sZCkgeyBmb3IgKHZhciBpID0gMDsgaSA8IG9sZC5sZW5ndGg7ICsraSkge1xuICAgICAgdmFyIHNwYW4gPSBvbGRbaV0sIG1hcmtlciA9IHNwYW4ubWFya2VyO1xuICAgICAgdmFyIGVuZHNBZnRlciA9IHNwYW4udG8gPT0gbnVsbCB8fCAobWFya2VyLmluY2x1c2l2ZVJpZ2h0ID8gc3Bhbi50byA+PSBlbmRDaCA6IHNwYW4udG8gPiBlbmRDaCk7XG4gICAgICBpZiAoZW5kc0FmdGVyIHx8IHNwYW4uZnJvbSA9PSBlbmRDaCAmJiBtYXJrZXIudHlwZSA9PSBcImJvb2ttYXJrXCIgJiYgKCFpc0luc2VydCB8fCBzcGFuLm1hcmtlci5pbnNlcnRMZWZ0KSkge1xuICAgICAgICB2YXIgc3RhcnRzQmVmb3JlID0gc3Bhbi5mcm9tID09IG51bGwgfHwgKG1hcmtlci5pbmNsdXNpdmVMZWZ0ID8gc3Bhbi5mcm9tIDw9IGVuZENoIDogc3Bhbi5mcm9tIDwgZW5kQ2gpXG4gICAgICAgIDsobncgfHwgKG53ID0gW10pKS5wdXNoKG5ldyBNYXJrZWRTcGFuKG1hcmtlciwgc3RhcnRzQmVmb3JlID8gbnVsbCA6IHNwYW4uZnJvbSAtIGVuZENoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNwYW4udG8gPT0gbnVsbCA/IG51bGwgOiBzcGFuLnRvIC0gZW5kQ2gpKTtcbiAgICAgIH1cbiAgICB9IH1cbiAgICByZXR1cm4gbndcbiAgfVxuXG4gIC8vIEdpdmVuIGEgY2hhbmdlIG9iamVjdCwgY29tcHV0ZSB0aGUgbmV3IHNldCBvZiBtYXJrZXIgc3BhbnMgdGhhdFxuICAvLyBjb3ZlciB0aGUgbGluZSBpbiB3aGljaCB0aGUgY2hhbmdlIHRvb2sgcGxhY2UuIFJlbW92ZXMgc3BhbnNcbiAgLy8gZW50aXJlbHkgd2l0aGluIHRoZSBjaGFuZ2UsIHJlY29ubmVjdHMgc3BhbnMgYmVsb25naW5nIHRvIHRoZVxuICAvLyBzYW1lIG1hcmtlciB0aGF0IGFwcGVhciBvbiBib3RoIHNpZGVzIG9mIHRoZSBjaGFuZ2UsIGFuZCBjdXRzIG9mZlxuICAvLyBzcGFucyBwYXJ0aWFsbHkgd2l0aGluIHRoZSBjaGFuZ2UuIFJldHVybnMgYW4gYXJyYXkgb2Ygc3BhblxuICAvLyBhcnJheXMgd2l0aCBvbmUgZWxlbWVudCBmb3IgZWFjaCBsaW5lIGluIChhZnRlcikgdGhlIGNoYW5nZS5cbiAgZnVuY3Rpb24gc3RyZXRjaFNwYW5zT3ZlckNoYW5nZShkb2MsIGNoYW5nZSkge1xuICAgIGlmIChjaGFuZ2UuZnVsbCkgeyByZXR1cm4gbnVsbCB9XG4gICAgdmFyIG9sZEZpcnN0ID0gaXNMaW5lKGRvYywgY2hhbmdlLmZyb20ubGluZSkgJiYgZ2V0TGluZShkb2MsIGNoYW5nZS5mcm9tLmxpbmUpLm1hcmtlZFNwYW5zO1xuICAgIHZhciBvbGRMYXN0ID0gaXNMaW5lKGRvYywgY2hhbmdlLnRvLmxpbmUpICYmIGdldExpbmUoZG9jLCBjaGFuZ2UudG8ubGluZSkubWFya2VkU3BhbnM7XG4gICAgaWYgKCFvbGRGaXJzdCAmJiAhb2xkTGFzdCkgeyByZXR1cm4gbnVsbCB9XG5cbiAgICB2YXIgc3RhcnRDaCA9IGNoYW5nZS5mcm9tLmNoLCBlbmRDaCA9IGNoYW5nZS50by5jaCwgaXNJbnNlcnQgPSBjbXAoY2hhbmdlLmZyb20sIGNoYW5nZS50bykgPT0gMDtcbiAgICAvLyBHZXQgdGhlIHNwYW5zIHRoYXQgJ3N0aWNrIG91dCcgb24gYm90aCBzaWRlc1xuICAgIHZhciBmaXJzdCA9IG1hcmtlZFNwYW5zQmVmb3JlKG9sZEZpcnN0LCBzdGFydENoLCBpc0luc2VydCk7XG4gICAgdmFyIGxhc3QgPSBtYXJrZWRTcGFuc0FmdGVyKG9sZExhc3QsIGVuZENoLCBpc0luc2VydCk7XG5cbiAgICAvLyBOZXh0LCBtZXJnZSB0aG9zZSB0d28gZW5kc1xuICAgIHZhciBzYW1lTGluZSA9IGNoYW5nZS50ZXh0Lmxlbmd0aCA9PSAxLCBvZmZzZXQgPSBsc3QoY2hhbmdlLnRleHQpLmxlbmd0aCArIChzYW1lTGluZSA/IHN0YXJ0Q2ggOiAwKTtcbiAgICBpZiAoZmlyc3QpIHtcbiAgICAgIC8vIEZpeCB1cCAudG8gcHJvcGVydGllcyBvZiBmaXJzdFxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBmaXJzdC5sZW5ndGg7ICsraSkge1xuICAgICAgICB2YXIgc3BhbiA9IGZpcnN0W2ldO1xuICAgICAgICBpZiAoc3Bhbi50byA9PSBudWxsKSB7XG4gICAgICAgICAgdmFyIGZvdW5kID0gZ2V0TWFya2VkU3BhbkZvcihsYXN0LCBzcGFuLm1hcmtlcik7XG4gICAgICAgICAgaWYgKCFmb3VuZCkgeyBzcGFuLnRvID0gc3RhcnRDaDsgfVxuICAgICAgICAgIGVsc2UgaWYgKHNhbWVMaW5lKSB7IHNwYW4udG8gPSBmb3VuZC50byA9PSBudWxsID8gbnVsbCA6IGZvdW5kLnRvICsgb2Zmc2V0OyB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGxhc3QpIHtcbiAgICAgIC8vIEZpeCB1cCAuZnJvbSBpbiBsYXN0IChvciBtb3ZlIHRoZW0gaW50byBmaXJzdCBpbiBjYXNlIG9mIHNhbWVMaW5lKVxuICAgICAgZm9yICh2YXIgaSQxID0gMDsgaSQxIDwgbGFzdC5sZW5ndGg7ICsraSQxKSB7XG4gICAgICAgIHZhciBzcGFuJDEgPSBsYXN0W2kkMV07XG4gICAgICAgIGlmIChzcGFuJDEudG8gIT0gbnVsbCkgeyBzcGFuJDEudG8gKz0gb2Zmc2V0OyB9XG4gICAgICAgIGlmIChzcGFuJDEuZnJvbSA9PSBudWxsKSB7XG4gICAgICAgICAgdmFyIGZvdW5kJDEgPSBnZXRNYXJrZWRTcGFuRm9yKGZpcnN0LCBzcGFuJDEubWFya2VyKTtcbiAgICAgICAgICBpZiAoIWZvdW5kJDEpIHtcbiAgICAgICAgICAgIHNwYW4kMS5mcm9tID0gb2Zmc2V0O1xuICAgICAgICAgICAgaWYgKHNhbWVMaW5lKSB7IChmaXJzdCB8fCAoZmlyc3QgPSBbXSkpLnB1c2goc3BhbiQxKTsgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzcGFuJDEuZnJvbSArPSBvZmZzZXQ7XG4gICAgICAgICAgaWYgKHNhbWVMaW5lKSB7IChmaXJzdCB8fCAoZmlyc3QgPSBbXSkpLnB1c2goc3BhbiQxKTsgfVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIC8vIE1ha2Ugc3VyZSB3ZSBkaWRuJ3QgY3JlYXRlIGFueSB6ZXJvLWxlbmd0aCBzcGFuc1xuICAgIGlmIChmaXJzdCkgeyBmaXJzdCA9IGNsZWFyRW1wdHlTcGFucyhmaXJzdCk7IH1cbiAgICBpZiAobGFzdCAmJiBsYXN0ICE9IGZpcnN0KSB7IGxhc3QgPSBjbGVhckVtcHR5U3BhbnMobGFzdCk7IH1cblxuICAgIHZhciBuZXdNYXJrZXJzID0gW2ZpcnN0XTtcbiAgICBpZiAoIXNhbWVMaW5lKSB7XG4gICAgICAvLyBGaWxsIGdhcCB3aXRoIHdob2xlLWxpbmUtc3BhbnNcbiAgICAgIHZhciBnYXAgPSBjaGFuZ2UudGV4dC5sZW5ndGggLSAyLCBnYXBNYXJrZXJzO1xuICAgICAgaWYgKGdhcCA+IDAgJiYgZmlyc3QpXG4gICAgICAgIHsgZm9yICh2YXIgaSQyID0gMDsgaSQyIDwgZmlyc3QubGVuZ3RoOyArK2kkMilcbiAgICAgICAgICB7IGlmIChmaXJzdFtpJDJdLnRvID09IG51bGwpXG4gICAgICAgICAgICB7IChnYXBNYXJrZXJzIHx8IChnYXBNYXJrZXJzID0gW10pKS5wdXNoKG5ldyBNYXJrZWRTcGFuKGZpcnN0W2kkMl0ubWFya2VyLCBudWxsLCBudWxsKSk7IH0gfSB9XG4gICAgICBmb3IgKHZhciBpJDMgPSAwOyBpJDMgPCBnYXA7ICsraSQzKVxuICAgICAgICB7IG5ld01hcmtlcnMucHVzaChnYXBNYXJrZXJzKTsgfVxuICAgICAgbmV3TWFya2Vycy5wdXNoKGxhc3QpO1xuICAgIH1cbiAgICByZXR1cm4gbmV3TWFya2Vyc1xuICB9XG5cbiAgLy8gUmVtb3ZlIHNwYW5zIHRoYXQgYXJlIGVtcHR5IGFuZCBkb24ndCBoYXZlIGEgY2xlYXJXaGVuRW1wdHlcbiAgLy8gb3B0aW9uIG9mIGZhbHNlLlxuICBmdW5jdGlvbiBjbGVhckVtcHR5U3BhbnMoc3BhbnMpIHtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNwYW5zLmxlbmd0aDsgKytpKSB7XG4gICAgICB2YXIgc3BhbiA9IHNwYW5zW2ldO1xuICAgICAgaWYgKHNwYW4uZnJvbSAhPSBudWxsICYmIHNwYW4uZnJvbSA9PSBzcGFuLnRvICYmIHNwYW4ubWFya2VyLmNsZWFyV2hlbkVtcHR5ICE9PSBmYWxzZSlcbiAgICAgICAgeyBzcGFucy5zcGxpY2UoaS0tLCAxKTsgfVxuICAgIH1cbiAgICBpZiAoIXNwYW5zLmxlbmd0aCkgeyByZXR1cm4gbnVsbCB9XG4gICAgcmV0dXJuIHNwYW5zXG4gIH1cblxuICAvLyBVc2VkIHRvICdjbGlwJyBvdXQgcmVhZE9ubHkgcmFuZ2VzIHdoZW4gbWFraW5nIGEgY2hhbmdlLlxuICBmdW5jdGlvbiByZW1vdmVSZWFkT25seVJhbmdlcyhkb2MsIGZyb20sIHRvKSB7XG4gICAgdmFyIG1hcmtlcnMgPSBudWxsO1xuICAgIGRvYy5pdGVyKGZyb20ubGluZSwgdG8ubGluZSArIDEsIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICBpZiAobGluZS5tYXJrZWRTcGFucykgeyBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmUubWFya2VkU3BhbnMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdmFyIG1hcmsgPSBsaW5lLm1hcmtlZFNwYW5zW2ldLm1hcmtlcjtcbiAgICAgICAgaWYgKG1hcmsucmVhZE9ubHkgJiYgKCFtYXJrZXJzIHx8IGluZGV4T2YobWFya2VycywgbWFyaykgPT0gLTEpKVxuICAgICAgICAgIHsgKG1hcmtlcnMgfHwgKG1hcmtlcnMgPSBbXSkpLnB1c2gobWFyayk7IH1cbiAgICAgIH0gfVxuICAgIH0pO1xuICAgIGlmICghbWFya2VycykgeyByZXR1cm4gbnVsbCB9XG4gICAgdmFyIHBhcnRzID0gW3tmcm9tOiBmcm9tLCB0bzogdG99XTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IG1hcmtlcnMubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBtayA9IG1hcmtlcnNbaV0sIG0gPSBtay5maW5kKDApO1xuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBwYXJ0cy5sZW5ndGg7ICsraikge1xuICAgICAgICB2YXIgcCA9IHBhcnRzW2pdO1xuICAgICAgICBpZiAoY21wKHAudG8sIG0uZnJvbSkgPCAwIHx8IGNtcChwLmZyb20sIG0udG8pID4gMCkgeyBjb250aW51ZSB9XG4gICAgICAgIHZhciBuZXdQYXJ0cyA9IFtqLCAxXSwgZGZyb20gPSBjbXAocC5mcm9tLCBtLmZyb20pLCBkdG8gPSBjbXAocC50bywgbS50byk7XG4gICAgICAgIGlmIChkZnJvbSA8IDAgfHwgIW1rLmluY2x1c2l2ZUxlZnQgJiYgIWRmcm9tKVxuICAgICAgICAgIHsgbmV3UGFydHMucHVzaCh7ZnJvbTogcC5mcm9tLCB0bzogbS5mcm9tfSk7IH1cbiAgICAgICAgaWYgKGR0byA+IDAgfHwgIW1rLmluY2x1c2l2ZVJpZ2h0ICYmICFkdG8pXG4gICAgICAgICAgeyBuZXdQYXJ0cy5wdXNoKHtmcm9tOiBtLnRvLCB0bzogcC50b30pOyB9XG4gICAgICAgIHBhcnRzLnNwbGljZS5hcHBseShwYXJ0cywgbmV3UGFydHMpO1xuICAgICAgICBqICs9IG5ld1BhcnRzLmxlbmd0aCAtIDM7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBwYXJ0c1xuICB9XG5cbiAgLy8gQ29ubmVjdCBvciBkaXNjb25uZWN0IHNwYW5zIGZyb20gYSBsaW5lLlxuICBmdW5jdGlvbiBkZXRhY2hNYXJrZWRTcGFucyhsaW5lKSB7XG4gICAgdmFyIHNwYW5zID0gbGluZS5tYXJrZWRTcGFucztcbiAgICBpZiAoIXNwYW5zKSB7IHJldHVybiB9XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzcGFucy5sZW5ndGg7ICsraSlcbiAgICAgIHsgc3BhbnNbaV0ubWFya2VyLmRldGFjaExpbmUobGluZSk7IH1cbiAgICBsaW5lLm1hcmtlZFNwYW5zID0gbnVsbDtcbiAgfVxuICBmdW5jdGlvbiBhdHRhY2hNYXJrZWRTcGFucyhsaW5lLCBzcGFucykge1xuICAgIGlmICghc3BhbnMpIHsgcmV0dXJuIH1cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNwYW5zLmxlbmd0aDsgKytpKVxuICAgICAgeyBzcGFuc1tpXS5tYXJrZXIuYXR0YWNoTGluZShsaW5lKTsgfVxuICAgIGxpbmUubWFya2VkU3BhbnMgPSBzcGFucztcbiAgfVxuXG4gIC8vIEhlbHBlcnMgdXNlZCB3aGVuIGNvbXB1dGluZyB3aGljaCBvdmVybGFwcGluZyBjb2xsYXBzZWQgc3BhblxuICAvLyBjb3VudHMgYXMgdGhlIGxhcmdlciBvbmUuXG4gIGZ1bmN0aW9uIGV4dHJhTGVmdChtYXJrZXIpIHsgcmV0dXJuIG1hcmtlci5pbmNsdXNpdmVMZWZ0ID8gLTEgOiAwIH1cbiAgZnVuY3Rpb24gZXh0cmFSaWdodChtYXJrZXIpIHsgcmV0dXJuIG1hcmtlci5pbmNsdXNpdmVSaWdodCA/IDEgOiAwIH1cblxuICAvLyBSZXR1cm5zIGEgbnVtYmVyIGluZGljYXRpbmcgd2hpY2ggb2YgdHdvIG92ZXJsYXBwaW5nIGNvbGxhcHNlZFxuICAvLyBzcGFucyBpcyBsYXJnZXIgKGFuZCB0aHVzIGluY2x1ZGVzIHRoZSBvdGhlcikuIEZhbGxzIGJhY2sgdG9cbiAgLy8gY29tcGFyaW5nIGlkcyB3aGVuIHRoZSBzcGFucyBjb3ZlciBleGFjdGx5IHRoZSBzYW1lIHJhbmdlLlxuICBmdW5jdGlvbiBjb21wYXJlQ29sbGFwc2VkTWFya2VycyhhLCBiKSB7XG4gICAgdmFyIGxlbkRpZmYgPSBhLmxpbmVzLmxlbmd0aCAtIGIubGluZXMubGVuZ3RoO1xuICAgIGlmIChsZW5EaWZmICE9IDApIHsgcmV0dXJuIGxlbkRpZmYgfVxuICAgIHZhciBhUG9zID0gYS5maW5kKCksIGJQb3MgPSBiLmZpbmQoKTtcbiAgICB2YXIgZnJvbUNtcCA9IGNtcChhUG9zLmZyb20sIGJQb3MuZnJvbSkgfHwgZXh0cmFMZWZ0KGEpIC0gZXh0cmFMZWZ0KGIpO1xuICAgIGlmIChmcm9tQ21wKSB7IHJldHVybiAtZnJvbUNtcCB9XG4gICAgdmFyIHRvQ21wID0gY21wKGFQb3MudG8sIGJQb3MudG8pIHx8IGV4dHJhUmlnaHQoYSkgLSBleHRyYVJpZ2h0KGIpO1xuICAgIGlmICh0b0NtcCkgeyByZXR1cm4gdG9DbXAgfVxuICAgIHJldHVybiBiLmlkIC0gYS5pZFxuICB9XG5cbiAgLy8gRmluZCBvdXQgd2hldGhlciBhIGxpbmUgZW5kcyBvciBzdGFydHMgaW4gYSBjb2xsYXBzZWQgc3Bhbi4gSWZcbiAgLy8gc28sIHJldHVybiB0aGUgbWFya2VyIGZvciB0aGF0IHNwYW4uXG4gIGZ1bmN0aW9uIGNvbGxhcHNlZFNwYW5BdFNpZGUobGluZSwgc3RhcnQpIHtcbiAgICB2YXIgc3BzID0gc2F3Q29sbGFwc2VkU3BhbnMgJiYgbGluZS5tYXJrZWRTcGFucywgZm91bmQ7XG4gICAgaWYgKHNwcykgeyBmb3IgKHZhciBzcCA9ICh2b2lkIDApLCBpID0gMDsgaSA8IHNwcy5sZW5ndGg7ICsraSkge1xuICAgICAgc3AgPSBzcHNbaV07XG4gICAgICBpZiAoc3AubWFya2VyLmNvbGxhcHNlZCAmJiAoc3RhcnQgPyBzcC5mcm9tIDogc3AudG8pID09IG51bGwgJiZcbiAgICAgICAgICAoIWZvdW5kIHx8IGNvbXBhcmVDb2xsYXBzZWRNYXJrZXJzKGZvdW5kLCBzcC5tYXJrZXIpIDwgMCkpXG4gICAgICAgIHsgZm91bmQgPSBzcC5tYXJrZXI7IH1cbiAgICB9IH1cbiAgICByZXR1cm4gZm91bmRcbiAgfVxuICBmdW5jdGlvbiBjb2xsYXBzZWRTcGFuQXRTdGFydChsaW5lKSB7IHJldHVybiBjb2xsYXBzZWRTcGFuQXRTaWRlKGxpbmUsIHRydWUpIH1cbiAgZnVuY3Rpb24gY29sbGFwc2VkU3BhbkF0RW5kKGxpbmUpIHsgcmV0dXJuIGNvbGxhcHNlZFNwYW5BdFNpZGUobGluZSwgZmFsc2UpIH1cblxuICBmdW5jdGlvbiBjb2xsYXBzZWRTcGFuQXJvdW5kKGxpbmUsIGNoKSB7XG4gICAgdmFyIHNwcyA9IHNhd0NvbGxhcHNlZFNwYW5zICYmIGxpbmUubWFya2VkU3BhbnMsIGZvdW5kO1xuICAgIGlmIChzcHMpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBzcHMubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBzcCA9IHNwc1tpXTtcbiAgICAgIGlmIChzcC5tYXJrZXIuY29sbGFwc2VkICYmIChzcC5mcm9tID09IG51bGwgfHwgc3AuZnJvbSA8IGNoKSAmJiAoc3AudG8gPT0gbnVsbCB8fCBzcC50byA+IGNoKSAmJlxuICAgICAgICAgICghZm91bmQgfHwgY29tcGFyZUNvbGxhcHNlZE1hcmtlcnMoZm91bmQsIHNwLm1hcmtlcikgPCAwKSkgeyBmb3VuZCA9IHNwLm1hcmtlcjsgfVxuICAgIH0gfVxuICAgIHJldHVybiBmb3VuZFxuICB9XG5cbiAgLy8gVGVzdCB3aGV0aGVyIHRoZXJlIGV4aXN0cyBhIGNvbGxhcHNlZCBzcGFuIHRoYXQgcGFydGlhbGx5XG4gIC8vIG92ZXJsYXBzIChjb3ZlcnMgdGhlIHN0YXJ0IG9yIGVuZCwgYnV0IG5vdCBib3RoKSBvZiBhIG5ldyBzcGFuLlxuICAvLyBTdWNoIG92ZXJsYXAgaXMgbm90IGFsbG93ZWQuXG4gIGZ1bmN0aW9uIGNvbmZsaWN0aW5nQ29sbGFwc2VkUmFuZ2UoZG9jLCBsaW5lTm8kJDEsIGZyb20sIHRvLCBtYXJrZXIpIHtcbiAgICB2YXIgbGluZSA9IGdldExpbmUoZG9jLCBsaW5lTm8kJDEpO1xuICAgIHZhciBzcHMgPSBzYXdDb2xsYXBzZWRTcGFucyAmJiBsaW5lLm1hcmtlZFNwYW5zO1xuICAgIGlmIChzcHMpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBzcHMubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBzcCA9IHNwc1tpXTtcbiAgICAgIGlmICghc3AubWFya2VyLmNvbGxhcHNlZCkgeyBjb250aW51ZSB9XG4gICAgICB2YXIgZm91bmQgPSBzcC5tYXJrZXIuZmluZCgwKTtcbiAgICAgIHZhciBmcm9tQ21wID0gY21wKGZvdW5kLmZyb20sIGZyb20pIHx8IGV4dHJhTGVmdChzcC5tYXJrZXIpIC0gZXh0cmFMZWZ0KG1hcmtlcik7XG4gICAgICB2YXIgdG9DbXAgPSBjbXAoZm91bmQudG8sIHRvKSB8fCBleHRyYVJpZ2h0KHNwLm1hcmtlcikgLSBleHRyYVJpZ2h0KG1hcmtlcik7XG4gICAgICBpZiAoZnJvbUNtcCA+PSAwICYmIHRvQ21wIDw9IDAgfHwgZnJvbUNtcCA8PSAwICYmIHRvQ21wID49IDApIHsgY29udGludWUgfVxuICAgICAgaWYgKGZyb21DbXAgPD0gMCAmJiAoc3AubWFya2VyLmluY2x1c2l2ZVJpZ2h0ICYmIG1hcmtlci5pbmNsdXNpdmVMZWZ0ID8gY21wKGZvdW5kLnRvLCBmcm9tKSA+PSAwIDogY21wKGZvdW5kLnRvLCBmcm9tKSA+IDApIHx8XG4gICAgICAgICAgZnJvbUNtcCA+PSAwICYmIChzcC5tYXJrZXIuaW5jbHVzaXZlUmlnaHQgJiYgbWFya2VyLmluY2x1c2l2ZUxlZnQgPyBjbXAoZm91bmQuZnJvbSwgdG8pIDw9IDAgOiBjbXAoZm91bmQuZnJvbSwgdG8pIDwgMCkpXG4gICAgICAgIHsgcmV0dXJuIHRydWUgfVxuICAgIH0gfVxuICB9XG5cbiAgLy8gQSB2aXN1YWwgbGluZSBpcyBhIGxpbmUgYXMgZHJhd24gb24gdGhlIHNjcmVlbi4gRm9sZGluZywgZm9yXG4gIC8vIGV4YW1wbGUsIGNhbiBjYXVzZSBtdWx0aXBsZSBsb2dpY2FsIGxpbmVzIHRvIGFwcGVhciBvbiB0aGUgc2FtZVxuICAvLyB2aXN1YWwgbGluZS4gVGhpcyBmaW5kcyB0aGUgc3RhcnQgb2YgdGhlIHZpc3VhbCBsaW5lIHRoYXQgdGhlXG4gIC8vIGdpdmVuIGxpbmUgaXMgcGFydCBvZiAodXN1YWxseSB0aGF0IGlzIHRoZSBsaW5lIGl0c2VsZikuXG4gIGZ1bmN0aW9uIHZpc3VhbExpbmUobGluZSkge1xuICAgIHZhciBtZXJnZWQ7XG4gICAgd2hpbGUgKG1lcmdlZCA9IGNvbGxhcHNlZFNwYW5BdFN0YXJ0KGxpbmUpKVxuICAgICAgeyBsaW5lID0gbWVyZ2VkLmZpbmQoLTEsIHRydWUpLmxpbmU7IH1cbiAgICByZXR1cm4gbGluZVxuICB9XG5cbiAgZnVuY3Rpb24gdmlzdWFsTGluZUVuZChsaW5lKSB7XG4gICAgdmFyIG1lcmdlZDtcbiAgICB3aGlsZSAobWVyZ2VkID0gY29sbGFwc2VkU3BhbkF0RW5kKGxpbmUpKVxuICAgICAgeyBsaW5lID0gbWVyZ2VkLmZpbmQoMSwgdHJ1ZSkubGluZTsgfVxuICAgIHJldHVybiBsaW5lXG4gIH1cblxuICAvLyBSZXR1cm5zIGFuIGFycmF5IG9mIGxvZ2ljYWwgbGluZXMgdGhhdCBjb250aW51ZSB0aGUgdmlzdWFsIGxpbmVcbiAgLy8gc3RhcnRlZCBieSB0aGUgYXJndW1lbnQsIG9yIHVuZGVmaW5lZCBpZiB0aGVyZSBhcmUgbm8gc3VjaCBsaW5lcy5cbiAgZnVuY3Rpb24gdmlzdWFsTGluZUNvbnRpbnVlZChsaW5lKSB7XG4gICAgdmFyIG1lcmdlZCwgbGluZXM7XG4gICAgd2hpbGUgKG1lcmdlZCA9IGNvbGxhcHNlZFNwYW5BdEVuZChsaW5lKSkge1xuICAgICAgbGluZSA9IG1lcmdlZC5maW5kKDEsIHRydWUpLmxpbmVcbiAgICAgIDsobGluZXMgfHwgKGxpbmVzID0gW10pKS5wdXNoKGxpbmUpO1xuICAgIH1cbiAgICByZXR1cm4gbGluZXNcbiAgfVxuXG4gIC8vIEdldCB0aGUgbGluZSBudW1iZXIgb2YgdGhlIHN0YXJ0IG9mIHRoZSB2aXN1YWwgbGluZSB0aGF0IHRoZVxuICAvLyBnaXZlbiBsaW5lIG51bWJlciBpcyBwYXJ0IG9mLlxuICBmdW5jdGlvbiB2aXN1YWxMaW5lTm8oZG9jLCBsaW5lTikge1xuICAgIHZhciBsaW5lID0gZ2V0TGluZShkb2MsIGxpbmVOKSwgdmlzID0gdmlzdWFsTGluZShsaW5lKTtcbiAgICBpZiAobGluZSA9PSB2aXMpIHsgcmV0dXJuIGxpbmVOIH1cbiAgICByZXR1cm4gbGluZU5vKHZpcylcbiAgfVxuXG4gIC8vIEdldCB0aGUgbGluZSBudW1iZXIgb2YgdGhlIHN0YXJ0IG9mIHRoZSBuZXh0IHZpc3VhbCBsaW5lIGFmdGVyXG4gIC8vIHRoZSBnaXZlbiBsaW5lLlxuICBmdW5jdGlvbiB2aXN1YWxMaW5lRW5kTm8oZG9jLCBsaW5lTikge1xuICAgIGlmIChsaW5lTiA+IGRvYy5sYXN0TGluZSgpKSB7IHJldHVybiBsaW5lTiB9XG4gICAgdmFyIGxpbmUgPSBnZXRMaW5lKGRvYywgbGluZU4pLCBtZXJnZWQ7XG4gICAgaWYgKCFsaW5lSXNIaWRkZW4oZG9jLCBsaW5lKSkgeyByZXR1cm4gbGluZU4gfVxuICAgIHdoaWxlIChtZXJnZWQgPSBjb2xsYXBzZWRTcGFuQXRFbmQobGluZSkpXG4gICAgICB7IGxpbmUgPSBtZXJnZWQuZmluZCgxLCB0cnVlKS5saW5lOyB9XG4gICAgcmV0dXJuIGxpbmVObyhsaW5lKSArIDFcbiAgfVxuXG4gIC8vIENvbXB1dGUgd2hldGhlciBhIGxpbmUgaXMgaGlkZGVuLiBMaW5lcyBjb3VudCBhcyBoaWRkZW4gd2hlbiB0aGV5XG4gIC8vIGFyZSBwYXJ0IG9mIGEgdmlzdWFsIGxpbmUgdGhhdCBzdGFydHMgd2l0aCBhbm90aGVyIGxpbmUsIG9yIHdoZW5cbiAgLy8gdGhleSBhcmUgZW50aXJlbHkgY292ZXJlZCBieSBjb2xsYXBzZWQsIG5vbi13aWRnZXQgc3Bhbi5cbiAgZnVuY3Rpb24gbGluZUlzSGlkZGVuKGRvYywgbGluZSkge1xuICAgIHZhciBzcHMgPSBzYXdDb2xsYXBzZWRTcGFucyAmJiBsaW5lLm1hcmtlZFNwYW5zO1xuICAgIGlmIChzcHMpIHsgZm9yICh2YXIgc3AgPSAodm9pZCAwKSwgaSA9IDA7IGkgPCBzcHMubGVuZ3RoOyArK2kpIHtcbiAgICAgIHNwID0gc3BzW2ldO1xuICAgICAgaWYgKCFzcC5tYXJrZXIuY29sbGFwc2VkKSB7IGNvbnRpbnVlIH1cbiAgICAgIGlmIChzcC5mcm9tID09IG51bGwpIHsgcmV0dXJuIHRydWUgfVxuICAgICAgaWYgKHNwLm1hcmtlci53aWRnZXROb2RlKSB7IGNvbnRpbnVlIH1cbiAgICAgIGlmIChzcC5mcm9tID09IDAgJiYgc3AubWFya2VyLmluY2x1c2l2ZUxlZnQgJiYgbGluZUlzSGlkZGVuSW5uZXIoZG9jLCBsaW5lLCBzcCkpXG4gICAgICAgIHsgcmV0dXJuIHRydWUgfVxuICAgIH0gfVxuICB9XG4gIGZ1bmN0aW9uIGxpbmVJc0hpZGRlbklubmVyKGRvYywgbGluZSwgc3Bhbikge1xuICAgIGlmIChzcGFuLnRvID09IG51bGwpIHtcbiAgICAgIHZhciBlbmQgPSBzcGFuLm1hcmtlci5maW5kKDEsIHRydWUpO1xuICAgICAgcmV0dXJuIGxpbmVJc0hpZGRlbklubmVyKGRvYywgZW5kLmxpbmUsIGdldE1hcmtlZFNwYW5Gb3IoZW5kLmxpbmUubWFya2VkU3BhbnMsIHNwYW4ubWFya2VyKSlcbiAgICB9XG4gICAgaWYgKHNwYW4ubWFya2VyLmluY2x1c2l2ZVJpZ2h0ICYmIHNwYW4udG8gPT0gbGluZS50ZXh0Lmxlbmd0aClcbiAgICAgIHsgcmV0dXJuIHRydWUgfVxuICAgIGZvciAodmFyIHNwID0gKHZvaWQgMCksIGkgPSAwOyBpIDwgbGluZS5tYXJrZWRTcGFucy5sZW5ndGg7ICsraSkge1xuICAgICAgc3AgPSBsaW5lLm1hcmtlZFNwYW5zW2ldO1xuICAgICAgaWYgKHNwLm1hcmtlci5jb2xsYXBzZWQgJiYgIXNwLm1hcmtlci53aWRnZXROb2RlICYmIHNwLmZyb20gPT0gc3Bhbi50byAmJlxuICAgICAgICAgIChzcC50byA9PSBudWxsIHx8IHNwLnRvICE9IHNwYW4uZnJvbSkgJiZcbiAgICAgICAgICAoc3AubWFya2VyLmluY2x1c2l2ZUxlZnQgfHwgc3Bhbi5tYXJrZXIuaW5jbHVzaXZlUmlnaHQpICYmXG4gICAgICAgICAgbGluZUlzSGlkZGVuSW5uZXIoZG9jLCBsaW5lLCBzcCkpIHsgcmV0dXJuIHRydWUgfVxuICAgIH1cbiAgfVxuXG4gIC8vIEZpbmQgdGhlIGhlaWdodCBhYm92ZSB0aGUgZ2l2ZW4gbGluZS5cbiAgZnVuY3Rpb24gaGVpZ2h0QXRMaW5lKGxpbmVPYmopIHtcbiAgICBsaW5lT2JqID0gdmlzdWFsTGluZShsaW5lT2JqKTtcblxuICAgIHZhciBoID0gMCwgY2h1bmsgPSBsaW5lT2JqLnBhcmVudDtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNodW5rLmxpbmVzLmxlbmd0aDsgKytpKSB7XG4gICAgICB2YXIgbGluZSA9IGNodW5rLmxpbmVzW2ldO1xuICAgICAgaWYgKGxpbmUgPT0gbGluZU9iaikgeyBicmVhayB9XG4gICAgICBlbHNlIHsgaCArPSBsaW5lLmhlaWdodDsgfVxuICAgIH1cbiAgICBmb3IgKHZhciBwID0gY2h1bmsucGFyZW50OyBwOyBjaHVuayA9IHAsIHAgPSBjaHVuay5wYXJlbnQpIHtcbiAgICAgIGZvciAodmFyIGkkMSA9IDA7IGkkMSA8IHAuY2hpbGRyZW4ubGVuZ3RoOyArK2kkMSkge1xuICAgICAgICB2YXIgY3VyID0gcC5jaGlsZHJlbltpJDFdO1xuICAgICAgICBpZiAoY3VyID09IGNodW5rKSB7IGJyZWFrIH1cbiAgICAgICAgZWxzZSB7IGggKz0gY3VyLmhlaWdodDsgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gaFxuICB9XG5cbiAgLy8gQ29tcHV0ZSB0aGUgY2hhcmFjdGVyIGxlbmd0aCBvZiBhIGxpbmUsIHRha2luZyBpbnRvIGFjY291bnRcbiAgLy8gY29sbGFwc2VkIHJhbmdlcyAoc2VlIG1hcmtUZXh0KSB0aGF0IG1pZ2h0IGhpZGUgcGFydHMsIGFuZCBqb2luXG4gIC8vIG90aGVyIGxpbmVzIG9udG8gaXQuXG4gIGZ1bmN0aW9uIGxpbmVMZW5ndGgobGluZSkge1xuICAgIGlmIChsaW5lLmhlaWdodCA9PSAwKSB7IHJldHVybiAwIH1cbiAgICB2YXIgbGVuID0gbGluZS50ZXh0Lmxlbmd0aCwgbWVyZ2VkLCBjdXIgPSBsaW5lO1xuICAgIHdoaWxlIChtZXJnZWQgPSBjb2xsYXBzZWRTcGFuQXRTdGFydChjdXIpKSB7XG4gICAgICB2YXIgZm91bmQgPSBtZXJnZWQuZmluZCgwLCB0cnVlKTtcbiAgICAgIGN1ciA9IGZvdW5kLmZyb20ubGluZTtcbiAgICAgIGxlbiArPSBmb3VuZC5mcm9tLmNoIC0gZm91bmQudG8uY2g7XG4gICAgfVxuICAgIGN1ciA9IGxpbmU7XG4gICAgd2hpbGUgKG1lcmdlZCA9IGNvbGxhcHNlZFNwYW5BdEVuZChjdXIpKSB7XG4gICAgICB2YXIgZm91bmQkMSA9IG1lcmdlZC5maW5kKDAsIHRydWUpO1xuICAgICAgbGVuIC09IGN1ci50ZXh0Lmxlbmd0aCAtIGZvdW5kJDEuZnJvbS5jaDtcbiAgICAgIGN1ciA9IGZvdW5kJDEudG8ubGluZTtcbiAgICAgIGxlbiArPSBjdXIudGV4dC5sZW5ndGggLSBmb3VuZCQxLnRvLmNoO1xuICAgIH1cbiAgICByZXR1cm4gbGVuXG4gIH1cblxuICAvLyBGaW5kIHRoZSBsb25nZXN0IGxpbmUgaW4gdGhlIGRvY3VtZW50LlxuICBmdW5jdGlvbiBmaW5kTWF4TGluZShjbSkge1xuICAgIHZhciBkID0gY20uZGlzcGxheSwgZG9jID0gY20uZG9jO1xuICAgIGQubWF4TGluZSA9IGdldExpbmUoZG9jLCBkb2MuZmlyc3QpO1xuICAgIGQubWF4TGluZUxlbmd0aCA9IGxpbmVMZW5ndGgoZC5tYXhMaW5lKTtcbiAgICBkLm1heExpbmVDaGFuZ2VkID0gdHJ1ZTtcbiAgICBkb2MuaXRlcihmdW5jdGlvbiAobGluZSkge1xuICAgICAgdmFyIGxlbiA9IGxpbmVMZW5ndGgobGluZSk7XG4gICAgICBpZiAobGVuID4gZC5tYXhMaW5lTGVuZ3RoKSB7XG4gICAgICAgIGQubWF4TGluZUxlbmd0aCA9IGxlbjtcbiAgICAgICAgZC5tYXhMaW5lID0gbGluZTtcbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIC8vIEJJREkgSEVMUEVSU1xuXG4gIGZ1bmN0aW9uIGl0ZXJhdGVCaWRpU2VjdGlvbnMob3JkZXIsIGZyb20sIHRvLCBmKSB7XG4gICAgaWYgKCFvcmRlcikgeyByZXR1cm4gZihmcm9tLCB0bywgXCJsdHJcIiwgMCkgfVxuICAgIHZhciBmb3VuZCA9IGZhbHNlO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb3JkZXIubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBwYXJ0ID0gb3JkZXJbaV07XG4gICAgICBpZiAocGFydC5mcm9tIDwgdG8gJiYgcGFydC50byA+IGZyb20gfHwgZnJvbSA9PSB0byAmJiBwYXJ0LnRvID09IGZyb20pIHtcbiAgICAgICAgZihNYXRoLm1heChwYXJ0LmZyb20sIGZyb20pLCBNYXRoLm1pbihwYXJ0LnRvLCB0byksIHBhcnQubGV2ZWwgPT0gMSA/IFwicnRsXCIgOiBcImx0clwiLCBpKTtcbiAgICAgICAgZm91bmQgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIWZvdW5kKSB7IGYoZnJvbSwgdG8sIFwibHRyXCIpOyB9XG4gIH1cblxuICB2YXIgYmlkaU90aGVyID0gbnVsbDtcbiAgZnVuY3Rpb24gZ2V0QmlkaVBhcnRBdChvcmRlciwgY2gsIHN0aWNreSkge1xuICAgIHZhciBmb3VuZDtcbiAgICBiaWRpT3RoZXIgPSBudWxsO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb3JkZXIubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBjdXIgPSBvcmRlcltpXTtcbiAgICAgIGlmIChjdXIuZnJvbSA8IGNoICYmIGN1ci50byA+IGNoKSB7IHJldHVybiBpIH1cbiAgICAgIGlmIChjdXIudG8gPT0gY2gpIHtcbiAgICAgICAgaWYgKGN1ci5mcm9tICE9IGN1ci50byAmJiBzdGlja3kgPT0gXCJiZWZvcmVcIikgeyBmb3VuZCA9IGk7IH1cbiAgICAgICAgZWxzZSB7IGJpZGlPdGhlciA9IGk7IH1cbiAgICAgIH1cbiAgICAgIGlmIChjdXIuZnJvbSA9PSBjaCkge1xuICAgICAgICBpZiAoY3VyLmZyb20gIT0gY3VyLnRvICYmIHN0aWNreSAhPSBcImJlZm9yZVwiKSB7IGZvdW5kID0gaTsgfVxuICAgICAgICBlbHNlIHsgYmlkaU90aGVyID0gaTsgfVxuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gZm91bmQgIT0gbnVsbCA/IGZvdW5kIDogYmlkaU90aGVyXG4gIH1cblxuICAvLyBCaWRpcmVjdGlvbmFsIG9yZGVyaW5nIGFsZ29yaXRobVxuICAvLyBTZWUgaHR0cDovL3VuaWNvZGUub3JnL3JlcG9ydHMvdHI5L3RyOS0xMy5odG1sIGZvciB0aGUgYWxnb3JpdGhtXG4gIC8vIHRoYXQgdGhpcyAocGFydGlhbGx5KSBpbXBsZW1lbnRzLlxuXG4gIC8vIE9uZS1jaGFyIGNvZGVzIHVzZWQgZm9yIGNoYXJhY3RlciB0eXBlczpcbiAgLy8gTCAoTCk6ICAgTGVmdC10by1SaWdodFxuICAvLyBSIChSKTogICBSaWdodC10by1MZWZ0XG4gIC8vIHIgKEFMKTogIFJpZ2h0LXRvLUxlZnQgQXJhYmljXG4gIC8vIDEgKEVOKTogIEV1cm9wZWFuIE51bWJlclxuICAvLyArIChFUyk6ICBFdXJvcGVhbiBOdW1iZXIgU2VwYXJhdG9yXG4gIC8vICUgKEVUKTogIEV1cm9wZWFuIE51bWJlciBUZXJtaW5hdG9yXG4gIC8vIG4gKEFOKTogIEFyYWJpYyBOdW1iZXJcbiAgLy8gLCAoQ1MpOiAgQ29tbW9uIE51bWJlciBTZXBhcmF0b3JcbiAgLy8gbSAoTlNNKTogTm9uLVNwYWNpbmcgTWFya1xuICAvLyBiIChCTik6ICBCb3VuZGFyeSBOZXV0cmFsXG4gIC8vIHMgKEIpOiAgIFBhcmFncmFwaCBTZXBhcmF0b3JcbiAgLy8gdCAoUyk6ICAgU2VnbWVudCBTZXBhcmF0b3JcbiAgLy8gdyAoV1MpOiAgV2hpdGVzcGFjZVxuICAvLyBOIChPTik6ICBPdGhlciBOZXV0cmFsc1xuXG4gIC8vIFJldHVybnMgbnVsbCBpZiBjaGFyYWN0ZXJzIGFyZSBvcmRlcmVkIGFzIHRoZXkgYXBwZWFyXG4gIC8vIChsZWZ0LXRvLXJpZ2h0KSwgb3IgYW4gYXJyYXkgb2Ygc2VjdGlvbnMgKHtmcm9tLCB0bywgbGV2ZWx9XG4gIC8vIG9iamVjdHMpIGluIHRoZSBvcmRlciBpbiB3aGljaCB0aGV5IG9jY3VyIHZpc3VhbGx5LlxuICB2YXIgYmlkaU9yZGVyaW5nID0gKGZ1bmN0aW9uKCkge1xuICAgIC8vIENoYXJhY3RlciB0eXBlcyBmb3IgY29kZXBvaW50cyAwIHRvIDB4ZmZcbiAgICB2YXIgbG93VHlwZXMgPSBcImJiYmJiYmJiYnRzdHdzYmJiYmJiYmJiYmJiYmJzc3N0d05OJSUlTk5OTk5OLE4sTjExMTExMTExMTFOTk5OTk5OTExMTExMTExMTExMTExMTExMTExMTExMTExOTk5OTk5MTExMTExMTExMTExMTExMTExMTExMTExMTE5OTk5iYmJiYmJzYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmJiYmIsTiUlJSVOTk5OTE5OTk5OJSUxMU5MTk5OMUxOTk5OTkxMTExMTExMTExMTExMTExMTExMTExMTkxMTExMTExMTExMTExMTExMTExMTExMTExMTExMTExOXCI7XG4gICAgLy8gQ2hhcmFjdGVyIHR5cGVzIGZvciBjb2RlcG9pbnRzIDB4NjAwIHRvIDB4NmY5XG4gICAgdmFyIGFyYWJpY1R5cGVzID0gXCJubm5ubm5OTnIlJXIsck5ObW1tbW1tbW1tbW1ycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJtbW1tbW1tbW1tbW1tbW1tbW1tbW1ubm5ubm5ubm5uJW5ucnJybXJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJycnJybW1tbW1tbW5ObW1tbW1tcnJtbU5tbW1tcnIxMTExMTExMTExXCI7XG4gICAgZnVuY3Rpb24gY2hhclR5cGUoY29kZSkge1xuICAgICAgaWYgKGNvZGUgPD0gMHhmNykgeyByZXR1cm4gbG93VHlwZXMuY2hhckF0KGNvZGUpIH1cbiAgICAgIGVsc2UgaWYgKDB4NTkwIDw9IGNvZGUgJiYgY29kZSA8PSAweDVmNCkgeyByZXR1cm4gXCJSXCIgfVxuICAgICAgZWxzZSBpZiAoMHg2MDAgPD0gY29kZSAmJiBjb2RlIDw9IDB4NmY5KSB7IHJldHVybiBhcmFiaWNUeXBlcy5jaGFyQXQoY29kZSAtIDB4NjAwKSB9XG4gICAgICBlbHNlIGlmICgweDZlZSA8PSBjb2RlICYmIGNvZGUgPD0gMHg4YWMpIHsgcmV0dXJuIFwiclwiIH1cbiAgICAgIGVsc2UgaWYgKDB4MjAwMCA8PSBjb2RlICYmIGNvZGUgPD0gMHgyMDBiKSB7IHJldHVybiBcIndcIiB9XG4gICAgICBlbHNlIGlmIChjb2RlID09IDB4MjAwYykgeyByZXR1cm4gXCJiXCIgfVxuICAgICAgZWxzZSB7IHJldHVybiBcIkxcIiB9XG4gICAgfVxuXG4gICAgdmFyIGJpZGlSRSA9IC9bXFx1MDU5MC1cXHUwNWY0XFx1MDYwMC1cXHUwNmZmXFx1MDcwMC1cXHUwOGFjXS87XG4gICAgdmFyIGlzTmV1dHJhbCA9IC9bc3R3Tl0vLCBpc1N0cm9uZyA9IC9bTFJyXS8sIGNvdW50c0FzTGVmdCA9IC9bTGIxbl0vLCBjb3VudHNBc051bSA9IC9bMW5dLztcblxuICAgIGZ1bmN0aW9uIEJpZGlTcGFuKGxldmVsLCBmcm9tLCB0bykge1xuICAgICAgdGhpcy5sZXZlbCA9IGxldmVsO1xuICAgICAgdGhpcy5mcm9tID0gZnJvbTsgdGhpcy50byA9IHRvO1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbihzdHIsIGRpcmVjdGlvbikge1xuICAgICAgdmFyIG91dGVyVHlwZSA9IGRpcmVjdGlvbiA9PSBcImx0clwiID8gXCJMXCIgOiBcIlJcIjtcblxuICAgICAgaWYgKHN0ci5sZW5ndGggPT0gMCB8fCBkaXJlY3Rpb24gPT0gXCJsdHJcIiAmJiAhYmlkaVJFLnRlc3Qoc3RyKSkgeyByZXR1cm4gZmFsc2UgfVxuICAgICAgdmFyIGxlbiA9IHN0ci5sZW5ndGgsIHR5cGVzID0gW107XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbjsgKytpKVxuICAgICAgICB7IHR5cGVzLnB1c2goY2hhclR5cGUoc3RyLmNoYXJDb2RlQXQoaSkpKTsgfVxuXG4gICAgICAvLyBXMS4gRXhhbWluZSBlYWNoIG5vbi1zcGFjaW5nIG1hcmsgKE5TTSkgaW4gdGhlIGxldmVsIHJ1biwgYW5kXG4gICAgICAvLyBjaGFuZ2UgdGhlIHR5cGUgb2YgdGhlIE5TTSB0byB0aGUgdHlwZSBvZiB0aGUgcHJldmlvdXNcbiAgICAgIC8vIGNoYXJhY3Rlci4gSWYgdGhlIE5TTSBpcyBhdCB0aGUgc3RhcnQgb2YgdGhlIGxldmVsIHJ1biwgaXQgd2lsbFxuICAgICAgLy8gZ2V0IHRoZSB0eXBlIG9mIHNvci5cbiAgICAgIGZvciAodmFyIGkkMSA9IDAsIHByZXYgPSBvdXRlclR5cGU7IGkkMSA8IGxlbjsgKytpJDEpIHtcbiAgICAgICAgdmFyIHR5cGUgPSB0eXBlc1tpJDFdO1xuICAgICAgICBpZiAodHlwZSA9PSBcIm1cIikgeyB0eXBlc1tpJDFdID0gcHJldjsgfVxuICAgICAgICBlbHNlIHsgcHJldiA9IHR5cGU7IH1cbiAgICAgIH1cblxuICAgICAgLy8gVzIuIFNlYXJjaCBiYWNrd2FyZHMgZnJvbSBlYWNoIGluc3RhbmNlIG9mIGEgRXVyb3BlYW4gbnVtYmVyXG4gICAgICAvLyB1bnRpbCB0aGUgZmlyc3Qgc3Ryb25nIHR5cGUgKFIsIEwsIEFMLCBvciBzb3IpIGlzIGZvdW5kLiBJZiBhblxuICAgICAgLy8gQUwgaXMgZm91bmQsIGNoYW5nZSB0aGUgdHlwZSBvZiB0aGUgRXVyb3BlYW4gbnVtYmVyIHRvIEFyYWJpY1xuICAgICAgLy8gbnVtYmVyLlxuICAgICAgLy8gVzMuIENoYW5nZSBhbGwgQUxzIHRvIFIuXG4gICAgICBmb3IgKHZhciBpJDIgPSAwLCBjdXIgPSBvdXRlclR5cGU7IGkkMiA8IGxlbjsgKytpJDIpIHtcbiAgICAgICAgdmFyIHR5cGUkMSA9IHR5cGVzW2kkMl07XG4gICAgICAgIGlmICh0eXBlJDEgPT0gXCIxXCIgJiYgY3VyID09IFwiclwiKSB7IHR5cGVzW2kkMl0gPSBcIm5cIjsgfVxuICAgICAgICBlbHNlIGlmIChpc1N0cm9uZy50ZXN0KHR5cGUkMSkpIHsgY3VyID0gdHlwZSQxOyBpZiAodHlwZSQxID09IFwiclwiKSB7IHR5cGVzW2kkMl0gPSBcIlJcIjsgfSB9XG4gICAgICB9XG5cbiAgICAgIC8vIFc0LiBBIHNpbmdsZSBFdXJvcGVhbiBzZXBhcmF0b3IgYmV0d2VlbiB0d28gRXVyb3BlYW4gbnVtYmVyc1xuICAgICAgLy8gY2hhbmdlcyB0byBhIEV1cm9wZWFuIG51bWJlci4gQSBzaW5nbGUgY29tbW9uIHNlcGFyYXRvciBiZXR3ZWVuXG4gICAgICAvLyB0d28gbnVtYmVycyBvZiB0aGUgc2FtZSB0eXBlIGNoYW5nZXMgdG8gdGhhdCB0eXBlLlxuICAgICAgZm9yICh2YXIgaSQzID0gMSwgcHJldiQxID0gdHlwZXNbMF07IGkkMyA8IGxlbiAtIDE7ICsraSQzKSB7XG4gICAgICAgIHZhciB0eXBlJDIgPSB0eXBlc1tpJDNdO1xuICAgICAgICBpZiAodHlwZSQyID09IFwiK1wiICYmIHByZXYkMSA9PSBcIjFcIiAmJiB0eXBlc1tpJDMrMV0gPT0gXCIxXCIpIHsgdHlwZXNbaSQzXSA9IFwiMVwiOyB9XG4gICAgICAgIGVsc2UgaWYgKHR5cGUkMiA9PSBcIixcIiAmJiBwcmV2JDEgPT0gdHlwZXNbaSQzKzFdICYmXG4gICAgICAgICAgICAgICAgIChwcmV2JDEgPT0gXCIxXCIgfHwgcHJldiQxID09IFwiblwiKSkgeyB0eXBlc1tpJDNdID0gcHJldiQxOyB9XG4gICAgICAgIHByZXYkMSA9IHR5cGUkMjtcbiAgICAgIH1cblxuICAgICAgLy8gVzUuIEEgc2VxdWVuY2Ugb2YgRXVyb3BlYW4gdGVybWluYXRvcnMgYWRqYWNlbnQgdG8gRXVyb3BlYW5cbiAgICAgIC8vIG51bWJlcnMgY2hhbmdlcyB0byBhbGwgRXVyb3BlYW4gbnVtYmVycy5cbiAgICAgIC8vIFc2LiBPdGhlcndpc2UsIHNlcGFyYXRvcnMgYW5kIHRlcm1pbmF0b3JzIGNoYW5nZSB0byBPdGhlclxuICAgICAgLy8gTmV1dHJhbC5cbiAgICAgIGZvciAodmFyIGkkNCA9IDA7IGkkNCA8IGxlbjsgKytpJDQpIHtcbiAgICAgICAgdmFyIHR5cGUkMyA9IHR5cGVzW2kkNF07XG4gICAgICAgIGlmICh0eXBlJDMgPT0gXCIsXCIpIHsgdHlwZXNbaSQ0XSA9IFwiTlwiOyB9XG4gICAgICAgIGVsc2UgaWYgKHR5cGUkMyA9PSBcIiVcIikge1xuICAgICAgICAgIHZhciBlbmQgPSAodm9pZCAwKTtcbiAgICAgICAgICBmb3IgKGVuZCA9IGkkNCArIDE7IGVuZCA8IGxlbiAmJiB0eXBlc1tlbmRdID09IFwiJVwiOyArK2VuZCkge31cbiAgICAgICAgICB2YXIgcmVwbGFjZSA9IChpJDQgJiYgdHlwZXNbaSQ0LTFdID09IFwiIVwiKSB8fCAoZW5kIDwgbGVuICYmIHR5cGVzW2VuZF0gPT0gXCIxXCIpID8gXCIxXCIgOiBcIk5cIjtcbiAgICAgICAgICBmb3IgKHZhciBqID0gaSQ0OyBqIDwgZW5kOyArK2opIHsgdHlwZXNbal0gPSByZXBsYWNlOyB9XG4gICAgICAgICAgaSQ0ID0gZW5kIC0gMTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBXNy4gU2VhcmNoIGJhY2t3YXJkcyBmcm9tIGVhY2ggaW5zdGFuY2Ugb2YgYSBFdXJvcGVhbiBudW1iZXJcbiAgICAgIC8vIHVudGlsIHRoZSBmaXJzdCBzdHJvbmcgdHlwZSAoUiwgTCwgb3Igc29yKSBpcyBmb3VuZC4gSWYgYW4gTCBpc1xuICAgICAgLy8gZm91bmQsIHRoZW4gY2hhbmdlIHRoZSB0eXBlIG9mIHRoZSBFdXJvcGVhbiBudW1iZXIgdG8gTC5cbiAgICAgIGZvciAodmFyIGkkNSA9IDAsIGN1ciQxID0gb3V0ZXJUeXBlOyBpJDUgPCBsZW47ICsraSQ1KSB7XG4gICAgICAgIHZhciB0eXBlJDQgPSB0eXBlc1tpJDVdO1xuICAgICAgICBpZiAoY3VyJDEgPT0gXCJMXCIgJiYgdHlwZSQ0ID09IFwiMVwiKSB7IHR5cGVzW2kkNV0gPSBcIkxcIjsgfVxuICAgICAgICBlbHNlIGlmIChpc1N0cm9uZy50ZXN0KHR5cGUkNCkpIHsgY3VyJDEgPSB0eXBlJDQ7IH1cbiAgICAgIH1cblxuICAgICAgLy8gTjEuIEEgc2VxdWVuY2Ugb2YgbmV1dHJhbHMgdGFrZXMgdGhlIGRpcmVjdGlvbiBvZiB0aGVcbiAgICAgIC8vIHN1cnJvdW5kaW5nIHN0cm9uZyB0ZXh0IGlmIHRoZSB0ZXh0IG9uIGJvdGggc2lkZXMgaGFzIHRoZSBzYW1lXG4gICAgICAvLyBkaXJlY3Rpb24uIEV1cm9wZWFuIGFuZCBBcmFiaWMgbnVtYmVycyBhY3QgYXMgaWYgdGhleSB3ZXJlIFIgaW5cbiAgICAgIC8vIHRlcm1zIG9mIHRoZWlyIGluZmx1ZW5jZSBvbiBuZXV0cmFscy4gU3RhcnQtb2YtbGV2ZWwtcnVuIChzb3IpXG4gICAgICAvLyBhbmQgZW5kLW9mLWxldmVsLXJ1biAoZW9yKSBhcmUgdXNlZCBhdCBsZXZlbCBydW4gYm91bmRhcmllcy5cbiAgICAgIC8vIE4yLiBBbnkgcmVtYWluaW5nIG5ldXRyYWxzIHRha2UgdGhlIGVtYmVkZGluZyBkaXJlY3Rpb24uXG4gICAgICBmb3IgKHZhciBpJDYgPSAwOyBpJDYgPCBsZW47ICsraSQ2KSB7XG4gICAgICAgIGlmIChpc05ldXRyYWwudGVzdCh0eXBlc1tpJDZdKSkge1xuICAgICAgICAgIHZhciBlbmQkMSA9ICh2b2lkIDApO1xuICAgICAgICAgIGZvciAoZW5kJDEgPSBpJDYgKyAxOyBlbmQkMSA8IGxlbiAmJiBpc05ldXRyYWwudGVzdCh0eXBlc1tlbmQkMV0pOyArK2VuZCQxKSB7fVxuICAgICAgICAgIHZhciBiZWZvcmUgPSAoaSQ2ID8gdHlwZXNbaSQ2LTFdIDogb3V0ZXJUeXBlKSA9PSBcIkxcIjtcbiAgICAgICAgICB2YXIgYWZ0ZXIgPSAoZW5kJDEgPCBsZW4gPyB0eXBlc1tlbmQkMV0gOiBvdXRlclR5cGUpID09IFwiTFwiO1xuICAgICAgICAgIHZhciByZXBsYWNlJDEgPSBiZWZvcmUgPT0gYWZ0ZXIgPyAoYmVmb3JlID8gXCJMXCIgOiBcIlJcIikgOiBvdXRlclR5cGU7XG4gICAgICAgICAgZm9yICh2YXIgaiQxID0gaSQ2OyBqJDEgPCBlbmQkMTsgKytqJDEpIHsgdHlwZXNbaiQxXSA9IHJlcGxhY2UkMTsgfVxuICAgICAgICAgIGkkNiA9IGVuZCQxIC0gMTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICAvLyBIZXJlIHdlIGRlcGFydCBmcm9tIHRoZSBkb2N1bWVudGVkIGFsZ29yaXRobSwgaW4gb3JkZXIgdG8gYXZvaWRcbiAgICAgIC8vIGJ1aWxkaW5nIHVwIGFuIGFjdHVhbCBsZXZlbHMgYXJyYXkuIFNpbmNlIHRoZXJlIGFyZSBvbmx5IHRocmVlXG4gICAgICAvLyBsZXZlbHMgKDAsIDEsIDIpIGluIGFuIGltcGxlbWVudGF0aW9uIHRoYXQgZG9lc24ndCB0YWtlXG4gICAgICAvLyBleHBsaWNpdCBlbWJlZGRpbmcgaW50byBhY2NvdW50LCB3ZSBjYW4gYnVpbGQgdXAgdGhlIG9yZGVyIG9uXG4gICAgICAvLyB0aGUgZmx5LCB3aXRob3V0IGZvbGxvd2luZyB0aGUgbGV2ZWwtYmFzZWQgYWxnb3JpdGhtLlxuICAgICAgdmFyIG9yZGVyID0gW10sIG07XG4gICAgICBmb3IgKHZhciBpJDcgPSAwOyBpJDcgPCBsZW47KSB7XG4gICAgICAgIGlmIChjb3VudHNBc0xlZnQudGVzdCh0eXBlc1tpJDddKSkge1xuICAgICAgICAgIHZhciBzdGFydCA9IGkkNztcbiAgICAgICAgICBmb3IgKCsraSQ3OyBpJDcgPCBsZW4gJiYgY291bnRzQXNMZWZ0LnRlc3QodHlwZXNbaSQ3XSk7ICsraSQ3KSB7fVxuICAgICAgICAgIG9yZGVyLnB1c2gobmV3IEJpZGlTcGFuKDAsIHN0YXJ0LCBpJDcpKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICB2YXIgcG9zID0gaSQ3LCBhdCA9IG9yZGVyLmxlbmd0aDtcbiAgICAgICAgICBmb3IgKCsraSQ3OyBpJDcgPCBsZW4gJiYgdHlwZXNbaSQ3XSAhPSBcIkxcIjsgKytpJDcpIHt9XG4gICAgICAgICAgZm9yICh2YXIgaiQyID0gcG9zOyBqJDIgPCBpJDc7KSB7XG4gICAgICAgICAgICBpZiAoY291bnRzQXNOdW0udGVzdCh0eXBlc1tqJDJdKSkge1xuICAgICAgICAgICAgICBpZiAocG9zIDwgaiQyKSB7IG9yZGVyLnNwbGljZShhdCwgMCwgbmV3IEJpZGlTcGFuKDEsIHBvcywgaiQyKSk7IH1cbiAgICAgICAgICAgICAgdmFyIG5zdGFydCA9IGokMjtcbiAgICAgICAgICAgICAgZm9yICgrK2okMjsgaiQyIDwgaSQ3ICYmIGNvdW50c0FzTnVtLnRlc3QodHlwZXNbaiQyXSk7ICsraiQyKSB7fVxuICAgICAgICAgICAgICBvcmRlci5zcGxpY2UoYXQsIDAsIG5ldyBCaWRpU3BhbigyLCBuc3RhcnQsIGokMikpO1xuICAgICAgICAgICAgICBwb3MgPSBqJDI7XG4gICAgICAgICAgICB9IGVsc2UgeyArK2okMjsgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAocG9zIDwgaSQ3KSB7IG9yZGVyLnNwbGljZShhdCwgMCwgbmV3IEJpZGlTcGFuKDEsIHBvcywgaSQ3KSk7IH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGRpcmVjdGlvbiA9PSBcImx0clwiKSB7XG4gICAgICAgIGlmIChvcmRlclswXS5sZXZlbCA9PSAxICYmIChtID0gc3RyLm1hdGNoKC9eXFxzKy8pKSkge1xuICAgICAgICAgIG9yZGVyWzBdLmZyb20gPSBtWzBdLmxlbmd0aDtcbiAgICAgICAgICBvcmRlci51bnNoaWZ0KG5ldyBCaWRpU3BhbigwLCAwLCBtWzBdLmxlbmd0aCkpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChsc3Qob3JkZXIpLmxldmVsID09IDEgJiYgKG0gPSBzdHIubWF0Y2goL1xccyskLykpKSB7XG4gICAgICAgICAgbHN0KG9yZGVyKS50byAtPSBtWzBdLmxlbmd0aDtcbiAgICAgICAgICBvcmRlci5wdXNoKG5ldyBCaWRpU3BhbigwLCBsZW4gLSBtWzBdLmxlbmd0aCwgbGVuKSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgcmV0dXJuIGRpcmVjdGlvbiA9PSBcInJ0bFwiID8gb3JkZXIucmV2ZXJzZSgpIDogb3JkZXJcbiAgICB9XG4gIH0pKCk7XG5cbiAgLy8gR2V0IHRoZSBiaWRpIG9yZGVyaW5nIGZvciB0aGUgZ2l2ZW4gbGluZSAoYW5kIGNhY2hlIGl0KS4gUmV0dXJuc1xuICAvLyBmYWxzZSBmb3IgbGluZXMgdGhhdCBhcmUgZnVsbHkgbGVmdC10by1yaWdodCwgYW5kIGFuIGFycmF5IG9mXG4gIC8vIEJpZGlTcGFuIG9iamVjdHMgb3RoZXJ3aXNlLlxuICBmdW5jdGlvbiBnZXRPcmRlcihsaW5lLCBkaXJlY3Rpb24pIHtcbiAgICB2YXIgb3JkZXIgPSBsaW5lLm9yZGVyO1xuICAgIGlmIChvcmRlciA9PSBudWxsKSB7IG9yZGVyID0gbGluZS5vcmRlciA9IGJpZGlPcmRlcmluZyhsaW5lLnRleHQsIGRpcmVjdGlvbik7IH1cbiAgICByZXR1cm4gb3JkZXJcbiAgfVxuXG4gIC8vIEVWRU5UIEhBTkRMSU5HXG5cbiAgLy8gTGlnaHR3ZWlnaHQgZXZlbnQgZnJhbWV3b3JrLiBvbi9vZmYgYWxzbyB3b3JrIG9uIERPTSBub2RlcyxcbiAgLy8gcmVnaXN0ZXJpbmcgbmF0aXZlIERPTSBoYW5kbGVycy5cblxuICB2YXIgbm9IYW5kbGVycyA9IFtdO1xuXG4gIHZhciBvbiA9IGZ1bmN0aW9uKGVtaXR0ZXIsIHR5cGUsIGYpIHtcbiAgICBpZiAoZW1pdHRlci5hZGRFdmVudExpc3RlbmVyKSB7XG4gICAgICBlbWl0dGVyLmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgZiwgZmFsc2UpO1xuICAgIH0gZWxzZSBpZiAoZW1pdHRlci5hdHRhY2hFdmVudCkge1xuICAgICAgZW1pdHRlci5hdHRhY2hFdmVudChcIm9uXCIgKyB0eXBlLCBmKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIG1hcCQkMSA9IGVtaXR0ZXIuX2hhbmRsZXJzIHx8IChlbWl0dGVyLl9oYW5kbGVycyA9IHt9KTtcbiAgICAgIG1hcCQkMVt0eXBlXSA9IChtYXAkJDFbdHlwZV0gfHwgbm9IYW5kbGVycykuY29uY2F0KGYpO1xuICAgIH1cbiAgfTtcblxuICBmdW5jdGlvbiBnZXRIYW5kbGVycyhlbWl0dGVyLCB0eXBlKSB7XG4gICAgcmV0dXJuIGVtaXR0ZXIuX2hhbmRsZXJzICYmIGVtaXR0ZXIuX2hhbmRsZXJzW3R5cGVdIHx8IG5vSGFuZGxlcnNcbiAgfVxuXG4gIGZ1bmN0aW9uIG9mZihlbWl0dGVyLCB0eXBlLCBmKSB7XG4gICAgaWYgKGVtaXR0ZXIucmVtb3ZlRXZlbnRMaXN0ZW5lcikge1xuICAgICAgZW1pdHRlci5yZW1vdmVFdmVudExpc3RlbmVyKHR5cGUsIGYsIGZhbHNlKTtcbiAgICB9IGVsc2UgaWYgKGVtaXR0ZXIuZGV0YWNoRXZlbnQpIHtcbiAgICAgIGVtaXR0ZXIuZGV0YWNoRXZlbnQoXCJvblwiICsgdHlwZSwgZik7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBtYXAkJDEgPSBlbWl0dGVyLl9oYW5kbGVycywgYXJyID0gbWFwJCQxICYmIG1hcCQkMVt0eXBlXTtcbiAgICAgIGlmIChhcnIpIHtcbiAgICAgICAgdmFyIGluZGV4ID0gaW5kZXhPZihhcnIsIGYpO1xuICAgICAgICBpZiAoaW5kZXggPiAtMSlcbiAgICAgICAgICB7IG1hcCQkMVt0eXBlXSA9IGFyci5zbGljZSgwLCBpbmRleCkuY29uY2F0KGFyci5zbGljZShpbmRleCArIDEpKTsgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHNpZ25hbChlbWl0dGVyLCB0eXBlIC8qLCB2YWx1ZXMuLi4qLykge1xuICAgIHZhciBoYW5kbGVycyA9IGdldEhhbmRsZXJzKGVtaXR0ZXIsIHR5cGUpO1xuICAgIGlmICghaGFuZGxlcnMubGVuZ3RoKSB7IHJldHVybiB9XG4gICAgdmFyIGFyZ3MgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaGFuZGxlcnMubGVuZ3RoOyArK2kpIHsgaGFuZGxlcnNbaV0uYXBwbHkobnVsbCwgYXJncyk7IH1cbiAgfVxuXG4gIC8vIFRoZSBET00gZXZlbnRzIHRoYXQgQ29kZU1pcnJvciBoYW5kbGVzIGNhbiBiZSBvdmVycmlkZGVuIGJ5XG4gIC8vIHJlZ2lzdGVyaW5nIGEgKG5vbi1ET00pIGhhbmRsZXIgb24gdGhlIGVkaXRvciBmb3IgdGhlIGV2ZW50IG5hbWUsXG4gIC8vIGFuZCBwcmV2ZW50RGVmYXVsdC1pbmcgdGhlIGV2ZW50IGluIHRoYXQgaGFuZGxlci5cbiAgZnVuY3Rpb24gc2lnbmFsRE9NRXZlbnQoY20sIGUsIG92ZXJyaWRlKSB7XG4gICAgaWYgKHR5cGVvZiBlID09IFwic3RyaW5nXCIpXG4gICAgICB7IGUgPSB7dHlwZTogZSwgcHJldmVudERlZmF1bHQ6IGZ1bmN0aW9uKCkgeyB0aGlzLmRlZmF1bHRQcmV2ZW50ZWQgPSB0cnVlOyB9fTsgfVxuICAgIHNpZ25hbChjbSwgb3ZlcnJpZGUgfHwgZS50eXBlLCBjbSwgZSk7XG4gICAgcmV0dXJuIGVfZGVmYXVsdFByZXZlbnRlZChlKSB8fCBlLmNvZGVtaXJyb3JJZ25vcmVcbiAgfVxuXG4gIGZ1bmN0aW9uIHNpZ25hbEN1cnNvckFjdGl2aXR5KGNtKSB7XG4gICAgdmFyIGFyciA9IGNtLl9oYW5kbGVycyAmJiBjbS5faGFuZGxlcnMuY3Vyc29yQWN0aXZpdHk7XG4gICAgaWYgKCFhcnIpIHsgcmV0dXJuIH1cbiAgICB2YXIgc2V0ID0gY20uY3VyT3AuY3Vyc29yQWN0aXZpdHlIYW5kbGVycyB8fCAoY20uY3VyT3AuY3Vyc29yQWN0aXZpdHlIYW5kbGVycyA9IFtdKTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGFyci5sZW5ndGg7ICsraSkgeyBpZiAoaW5kZXhPZihzZXQsIGFycltpXSkgPT0gLTEpXG4gICAgICB7IHNldC5wdXNoKGFycltpXSk7IH0gfVxuICB9XG5cbiAgZnVuY3Rpb24gaGFzSGFuZGxlcihlbWl0dGVyLCB0eXBlKSB7XG4gICAgcmV0dXJuIGdldEhhbmRsZXJzKGVtaXR0ZXIsIHR5cGUpLmxlbmd0aCA+IDBcbiAgfVxuXG4gIC8vIEFkZCBvbiBhbmQgb2ZmIG1ldGhvZHMgdG8gYSBjb25zdHJ1Y3RvcidzIHByb3RvdHlwZSwgdG8gbWFrZVxuICAvLyByZWdpc3RlcmluZyBldmVudHMgb24gc3VjaCBvYmplY3RzIG1vcmUgY29udmVuaWVudC5cbiAgZnVuY3Rpb24gZXZlbnRNaXhpbihjdG9yKSB7XG4gICAgY3Rvci5wcm90b3R5cGUub24gPSBmdW5jdGlvbih0eXBlLCBmKSB7b24odGhpcywgdHlwZSwgZik7fTtcbiAgICBjdG9yLnByb3RvdHlwZS5vZmYgPSBmdW5jdGlvbih0eXBlLCBmKSB7b2ZmKHRoaXMsIHR5cGUsIGYpO307XG4gIH1cblxuICAvLyBEdWUgdG8gdGhlIGZhY3QgdGhhdCB3ZSBzdGlsbCBzdXBwb3J0IGp1cmFzc2ljIElFIHZlcnNpb25zLCBzb21lXG4gIC8vIGNvbXBhdGliaWxpdHkgd3JhcHBlcnMgYXJlIG5lZWRlZC5cblxuICBmdW5jdGlvbiBlX3ByZXZlbnREZWZhdWx0KGUpIHtcbiAgICBpZiAoZS5wcmV2ZW50RGVmYXVsdCkgeyBlLnByZXZlbnREZWZhdWx0KCk7IH1cbiAgICBlbHNlIHsgZS5yZXR1cm5WYWx1ZSA9IGZhbHNlOyB9XG4gIH1cbiAgZnVuY3Rpb24gZV9zdG9wUHJvcGFnYXRpb24oZSkge1xuICAgIGlmIChlLnN0b3BQcm9wYWdhdGlvbikgeyBlLnN0b3BQcm9wYWdhdGlvbigpOyB9XG4gICAgZWxzZSB7IGUuY2FuY2VsQnViYmxlID0gdHJ1ZTsgfVxuICB9XG4gIGZ1bmN0aW9uIGVfZGVmYXVsdFByZXZlbnRlZChlKSB7XG4gICAgcmV0dXJuIGUuZGVmYXVsdFByZXZlbnRlZCAhPSBudWxsID8gZS5kZWZhdWx0UHJldmVudGVkIDogZS5yZXR1cm5WYWx1ZSA9PSBmYWxzZVxuICB9XG4gIGZ1bmN0aW9uIGVfc3RvcChlKSB7ZV9wcmV2ZW50RGVmYXVsdChlKTsgZV9zdG9wUHJvcGFnYXRpb24oZSk7fVxuXG4gIGZ1bmN0aW9uIGVfdGFyZ2V0KGUpIHtyZXR1cm4gZS50YXJnZXQgfHwgZS5zcmNFbGVtZW50fVxuICBmdW5jdGlvbiBlX2J1dHRvbihlKSB7XG4gICAgdmFyIGIgPSBlLndoaWNoO1xuICAgIGlmIChiID09IG51bGwpIHtcbiAgICAgIGlmIChlLmJ1dHRvbiAmIDEpIHsgYiA9IDE7IH1cbiAgICAgIGVsc2UgaWYgKGUuYnV0dG9uICYgMikgeyBiID0gMzsgfVxuICAgICAgZWxzZSBpZiAoZS5idXR0b24gJiA0KSB7IGIgPSAyOyB9XG4gICAgfVxuICAgIGlmIChtYWMgJiYgZS5jdHJsS2V5ICYmIGIgPT0gMSkgeyBiID0gMzsgfVxuICAgIHJldHVybiBiXG4gIH1cblxuICAvLyBEZXRlY3QgZHJhZy1hbmQtZHJvcFxuICB2YXIgZHJhZ0FuZERyb3AgPSBmdW5jdGlvbigpIHtcbiAgICAvLyBUaGVyZSBpcyAqc29tZSoga2luZCBvZiBkcmFnLWFuZC1kcm9wIHN1cHBvcnQgaW4gSUU2LTgsIGJ1dCBJXG4gICAgLy8gY291bGRuJ3QgZ2V0IGl0IHRvIHdvcmsgeWV0LlxuICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgOSkgeyByZXR1cm4gZmFsc2UgfVxuICAgIHZhciBkaXYgPSBlbHQoJ2RpdicpO1xuICAgIHJldHVybiBcImRyYWdnYWJsZVwiIGluIGRpdiB8fCBcImRyYWdEcm9wXCIgaW4gZGl2XG4gIH0oKTtcblxuICB2YXIgendzcFN1cHBvcnRlZDtcbiAgZnVuY3Rpb24gemVyb1dpZHRoRWxlbWVudChtZWFzdXJlKSB7XG4gICAgaWYgKHp3c3BTdXBwb3J0ZWQgPT0gbnVsbCkge1xuICAgICAgdmFyIHRlc3QgPSBlbHQoXCJzcGFuXCIsIFwiXFx1MjAwYlwiKTtcbiAgICAgIHJlbW92ZUNoaWxkcmVuQW5kQWRkKG1lYXN1cmUsIGVsdChcInNwYW5cIiwgW3Rlc3QsIGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKFwieFwiKV0pKTtcbiAgICAgIGlmIChtZWFzdXJlLmZpcnN0Q2hpbGQub2Zmc2V0SGVpZ2h0ICE9IDApXG4gICAgICAgIHsgendzcFN1cHBvcnRlZCA9IHRlc3Qub2Zmc2V0V2lkdGggPD0gMSAmJiB0ZXN0Lm9mZnNldEhlaWdodCA+IDIgJiYgIShpZSAmJiBpZV92ZXJzaW9uIDwgOCk7IH1cbiAgICB9XG4gICAgdmFyIG5vZGUgPSB6d3NwU3VwcG9ydGVkID8gZWx0KFwic3BhblwiLCBcIlxcdTIwMGJcIikgOlxuICAgICAgZWx0KFwic3BhblwiLCBcIlxcdTAwYTBcIiwgbnVsbCwgXCJkaXNwbGF5OiBpbmxpbmUtYmxvY2s7IHdpZHRoOiAxcHg7IG1hcmdpbi1yaWdodDogLTFweFwiKTtcbiAgICBub2RlLnNldEF0dHJpYnV0ZShcImNtLXRleHRcIiwgXCJcIik7XG4gICAgcmV0dXJuIG5vZGVcbiAgfVxuXG4gIC8vIEZlYXR1cmUtZGV0ZWN0IElFJ3MgY3J1bW15IGNsaWVudCByZWN0IHJlcG9ydGluZyBmb3IgYmlkaSB0ZXh0XG4gIHZhciBiYWRCaWRpUmVjdHM7XG4gIGZ1bmN0aW9uIGhhc0JhZEJpZGlSZWN0cyhtZWFzdXJlKSB7XG4gICAgaWYgKGJhZEJpZGlSZWN0cyAhPSBudWxsKSB7IHJldHVybiBiYWRCaWRpUmVjdHMgfVxuICAgIHZhciB0eHQgPSByZW1vdmVDaGlsZHJlbkFuZEFkZChtZWFzdXJlLCBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcIkFcXHUwNjJlQVwiKSk7XG4gICAgdmFyIHIwID0gcmFuZ2UodHh0LCAwLCAxKS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICB2YXIgcjEgPSByYW5nZSh0eHQsIDEsIDIpLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIHJlbW92ZUNoaWxkcmVuKG1lYXN1cmUpO1xuICAgIGlmICghcjAgfHwgcjAubGVmdCA9PSByMC5yaWdodCkgeyByZXR1cm4gZmFsc2UgfSAvLyBTYWZhcmkgcmV0dXJucyBudWxsIGluIHNvbWUgY2FzZXMgKCMyNzgwKVxuICAgIHJldHVybiBiYWRCaWRpUmVjdHMgPSAocjEucmlnaHQgLSByMC5yaWdodCA8IDMpXG4gIH1cblxuICAvLyBTZWUgaWYgXCJcIi5zcGxpdCBpcyB0aGUgYnJva2VuIElFIHZlcnNpb24sIGlmIHNvLCBwcm92aWRlIGFuXG4gIC8vIGFsdGVybmF0aXZlIHdheSB0byBzcGxpdCBsaW5lcy5cbiAgdmFyIHNwbGl0TGluZXNBdXRvID0gXCJcXG5cXG5iXCIuc3BsaXQoL1xcbi8pLmxlbmd0aCAhPSAzID8gZnVuY3Rpb24gKHN0cmluZykge1xuICAgIHZhciBwb3MgPSAwLCByZXN1bHQgPSBbXSwgbCA9IHN0cmluZy5sZW5ndGg7XG4gICAgd2hpbGUgKHBvcyA8PSBsKSB7XG4gICAgICB2YXIgbmwgPSBzdHJpbmcuaW5kZXhPZihcIlxcblwiLCBwb3MpO1xuICAgICAgaWYgKG5sID09IC0xKSB7IG5sID0gc3RyaW5nLmxlbmd0aDsgfVxuICAgICAgdmFyIGxpbmUgPSBzdHJpbmcuc2xpY2UocG9zLCBzdHJpbmcuY2hhckF0KG5sIC0gMSkgPT0gXCJcXHJcIiA/IG5sIC0gMSA6IG5sKTtcbiAgICAgIHZhciBydCA9IGxpbmUuaW5kZXhPZihcIlxcclwiKTtcbiAgICAgIGlmIChydCAhPSAtMSkge1xuICAgICAgICByZXN1bHQucHVzaChsaW5lLnNsaWNlKDAsIHJ0KSk7XG4gICAgICAgIHBvcyArPSBydCArIDE7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHQucHVzaChsaW5lKTtcbiAgICAgICAgcG9zID0gbmwgKyAxO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0XG4gIH0gOiBmdW5jdGlvbiAoc3RyaW5nKSB7IHJldHVybiBzdHJpbmcuc3BsaXQoL1xcclxcbj98XFxuLyk7IH07XG5cbiAgdmFyIGhhc1NlbGVjdGlvbiA9IHdpbmRvdy5nZXRTZWxlY3Rpb24gPyBmdW5jdGlvbiAodGUpIHtcbiAgICB0cnkgeyByZXR1cm4gdGUuc2VsZWN0aW9uU3RhcnQgIT0gdGUuc2VsZWN0aW9uRW5kIH1cbiAgICBjYXRjaChlKSB7IHJldHVybiBmYWxzZSB9XG4gIH0gOiBmdW5jdGlvbiAodGUpIHtcbiAgICB2YXIgcmFuZ2UkJDE7XG4gICAgdHJ5IHtyYW5nZSQkMSA9IHRlLm93bmVyRG9jdW1lbnQuc2VsZWN0aW9uLmNyZWF0ZVJhbmdlKCk7fVxuICAgIGNhdGNoKGUpIHt9XG4gICAgaWYgKCFyYW5nZSQkMSB8fCByYW5nZSQkMS5wYXJlbnRFbGVtZW50KCkgIT0gdGUpIHsgcmV0dXJuIGZhbHNlIH1cbiAgICByZXR1cm4gcmFuZ2UkJDEuY29tcGFyZUVuZFBvaW50cyhcIlN0YXJ0VG9FbmRcIiwgcmFuZ2UkJDEpICE9IDBcbiAgfTtcblxuICB2YXIgaGFzQ29weUV2ZW50ID0gKGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgZSA9IGVsdChcImRpdlwiKTtcbiAgICBpZiAoXCJvbmNvcHlcIiBpbiBlKSB7IHJldHVybiB0cnVlIH1cbiAgICBlLnNldEF0dHJpYnV0ZShcIm9uY29weVwiLCBcInJldHVybjtcIik7XG4gICAgcmV0dXJuIHR5cGVvZiBlLm9uY29weSA9PSBcImZ1bmN0aW9uXCJcbiAgfSkoKTtcblxuICB2YXIgYmFkWm9vbWVkUmVjdHMgPSBudWxsO1xuICBmdW5jdGlvbiBoYXNCYWRab29tZWRSZWN0cyhtZWFzdXJlKSB7XG4gICAgaWYgKGJhZFpvb21lZFJlY3RzICE9IG51bGwpIHsgcmV0dXJuIGJhZFpvb21lZFJlY3RzIH1cbiAgICB2YXIgbm9kZSA9IHJlbW92ZUNoaWxkcmVuQW5kQWRkKG1lYXN1cmUsIGVsdChcInNwYW5cIiwgXCJ4XCIpKTtcbiAgICB2YXIgbm9ybWFsID0gbm9kZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICB2YXIgZnJvbVJhbmdlID0gcmFuZ2Uobm9kZSwgMCwgMSkuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgcmV0dXJuIGJhZFpvb21lZFJlY3RzID0gTWF0aC5hYnMobm9ybWFsLmxlZnQgLSBmcm9tUmFuZ2UubGVmdCkgPiAxXG4gIH1cblxuICAvLyBLbm93biBtb2RlcywgYnkgbmFtZSBhbmQgYnkgTUlNRVxuICB2YXIgbW9kZXMgPSB7fSwgbWltZU1vZGVzID0ge307XG5cbiAgLy8gRXh0cmEgYXJndW1lbnRzIGFyZSBzdG9yZWQgYXMgdGhlIG1vZGUncyBkZXBlbmRlbmNpZXMsIHdoaWNoIGlzXG4gIC8vIHVzZWQgYnkgKGxlZ2FjeSkgbWVjaGFuaXNtcyBsaWtlIGxvYWRtb2RlLmpzIHRvIGF1dG9tYXRpY2FsbHlcbiAgLy8gbG9hZCBhIG1vZGUuIChQcmVmZXJyZWQgbWVjaGFuaXNtIGlzIHRoZSByZXF1aXJlL2RlZmluZSBjYWxscy4pXG4gIGZ1bmN0aW9uIGRlZmluZU1vZGUobmFtZSwgbW9kZSkge1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID4gMilcbiAgICAgIHsgbW9kZS5kZXBlbmRlbmNpZXMgPSBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbChhcmd1bWVudHMsIDIpOyB9XG4gICAgbW9kZXNbbmFtZV0gPSBtb2RlO1xuICB9XG5cbiAgZnVuY3Rpb24gZGVmaW5lTUlNRShtaW1lLCBzcGVjKSB7XG4gICAgbWltZU1vZGVzW21pbWVdID0gc3BlYztcbiAgfVxuXG4gIC8vIEdpdmVuIGEgTUlNRSB0eXBlLCBhIHtuYW1lLCAuLi5vcHRpb25zfSBjb25maWcgb2JqZWN0LCBvciBhIG5hbWVcbiAgLy8gc3RyaW5nLCByZXR1cm4gYSBtb2RlIGNvbmZpZyBvYmplY3QuXG4gIGZ1bmN0aW9uIHJlc29sdmVNb2RlKHNwZWMpIHtcbiAgICBpZiAodHlwZW9mIHNwZWMgPT0gXCJzdHJpbmdcIiAmJiBtaW1lTW9kZXMuaGFzT3duUHJvcGVydHkoc3BlYykpIHtcbiAgICAgIHNwZWMgPSBtaW1lTW9kZXNbc3BlY107XG4gICAgfSBlbHNlIGlmIChzcGVjICYmIHR5cGVvZiBzcGVjLm5hbWUgPT0gXCJzdHJpbmdcIiAmJiBtaW1lTW9kZXMuaGFzT3duUHJvcGVydHkoc3BlYy5uYW1lKSkge1xuICAgICAgdmFyIGZvdW5kID0gbWltZU1vZGVzW3NwZWMubmFtZV07XG4gICAgICBpZiAodHlwZW9mIGZvdW5kID09IFwic3RyaW5nXCIpIHsgZm91bmQgPSB7bmFtZTogZm91bmR9OyB9XG4gICAgICBzcGVjID0gY3JlYXRlT2JqKGZvdW5kLCBzcGVjKTtcbiAgICAgIHNwZWMubmFtZSA9IGZvdW5kLm5hbWU7XG4gICAgfSBlbHNlIGlmICh0eXBlb2Ygc3BlYyA9PSBcInN0cmluZ1wiICYmIC9eW1xcd1xcLV0rXFwvW1xcd1xcLV0rXFwreG1sJC8udGVzdChzcGVjKSkge1xuICAgICAgcmV0dXJuIHJlc29sdmVNb2RlKFwiYXBwbGljYXRpb24veG1sXCIpXG4gICAgfSBlbHNlIGlmICh0eXBlb2Ygc3BlYyA9PSBcInN0cmluZ1wiICYmIC9eW1xcd1xcLV0rXFwvW1xcd1xcLV0rXFwranNvbiQvLnRlc3Qoc3BlYykpIHtcbiAgICAgIHJldHVybiByZXNvbHZlTW9kZShcImFwcGxpY2F0aW9uL2pzb25cIilcbiAgICB9XG4gICAgaWYgKHR5cGVvZiBzcGVjID09IFwic3RyaW5nXCIpIHsgcmV0dXJuIHtuYW1lOiBzcGVjfSB9XG4gICAgZWxzZSB7IHJldHVybiBzcGVjIHx8IHtuYW1lOiBcIm51bGxcIn0gfVxuICB9XG5cbiAgLy8gR2l2ZW4gYSBtb2RlIHNwZWMgKGFueXRoaW5nIHRoYXQgcmVzb2x2ZU1vZGUgYWNjZXB0cyksIGZpbmQgYW5kXG4gIC8vIGluaXRpYWxpemUgYW4gYWN0dWFsIG1vZGUgb2JqZWN0LlxuICBmdW5jdGlvbiBnZXRNb2RlKG9wdGlvbnMsIHNwZWMpIHtcbiAgICBzcGVjID0gcmVzb2x2ZU1vZGUoc3BlYyk7XG4gICAgdmFyIG1mYWN0b3J5ID0gbW9kZXNbc3BlYy5uYW1lXTtcbiAgICBpZiAoIW1mYWN0b3J5KSB7IHJldHVybiBnZXRNb2RlKG9wdGlvbnMsIFwidGV4dC9wbGFpblwiKSB9XG4gICAgdmFyIG1vZGVPYmogPSBtZmFjdG9yeShvcHRpb25zLCBzcGVjKTtcbiAgICBpZiAobW9kZUV4dGVuc2lvbnMuaGFzT3duUHJvcGVydHkoc3BlYy5uYW1lKSkge1xuICAgICAgdmFyIGV4dHMgPSBtb2RlRXh0ZW5zaW9uc1tzcGVjLm5hbWVdO1xuICAgICAgZm9yICh2YXIgcHJvcCBpbiBleHRzKSB7XG4gICAgICAgIGlmICghZXh0cy5oYXNPd25Qcm9wZXJ0eShwcm9wKSkgeyBjb250aW51ZSB9XG4gICAgICAgIGlmIChtb2RlT2JqLmhhc093blByb3BlcnR5KHByb3ApKSB7IG1vZGVPYmpbXCJfXCIgKyBwcm9wXSA9IG1vZGVPYmpbcHJvcF07IH1cbiAgICAgICAgbW9kZU9ialtwcm9wXSA9IGV4dHNbcHJvcF07XG4gICAgICB9XG4gICAgfVxuICAgIG1vZGVPYmoubmFtZSA9IHNwZWMubmFtZTtcbiAgICBpZiAoc3BlYy5oZWxwZXJUeXBlKSB7IG1vZGVPYmouaGVscGVyVHlwZSA9IHNwZWMuaGVscGVyVHlwZTsgfVxuICAgIGlmIChzcGVjLm1vZGVQcm9wcykgeyBmb3IgKHZhciBwcm9wJDEgaW4gc3BlYy5tb2RlUHJvcHMpXG4gICAgICB7IG1vZGVPYmpbcHJvcCQxXSA9IHNwZWMubW9kZVByb3BzW3Byb3AkMV07IH0gfVxuXG4gICAgcmV0dXJuIG1vZGVPYmpcbiAgfVxuXG4gIC8vIFRoaXMgY2FuIGJlIHVzZWQgdG8gYXR0YWNoIHByb3BlcnRpZXMgdG8gbW9kZSBvYmplY3RzIGZyb21cbiAgLy8gb3V0c2lkZSB0aGUgYWN0dWFsIG1vZGUgZGVmaW5pdGlvbi5cbiAgdmFyIG1vZGVFeHRlbnNpb25zID0ge307XG4gIGZ1bmN0aW9uIGV4dGVuZE1vZGUobW9kZSwgcHJvcGVydGllcykge1xuICAgIHZhciBleHRzID0gbW9kZUV4dGVuc2lvbnMuaGFzT3duUHJvcGVydHkobW9kZSkgPyBtb2RlRXh0ZW5zaW9uc1ttb2RlXSA6IChtb2RlRXh0ZW5zaW9uc1ttb2RlXSA9IHt9KTtcbiAgICBjb3B5T2JqKHByb3BlcnRpZXMsIGV4dHMpO1xuICB9XG5cbiAgZnVuY3Rpb24gY29weVN0YXRlKG1vZGUsIHN0YXRlKSB7XG4gICAgaWYgKHN0YXRlID09PSB0cnVlKSB7IHJldHVybiBzdGF0ZSB9XG4gICAgaWYgKG1vZGUuY29weVN0YXRlKSB7IHJldHVybiBtb2RlLmNvcHlTdGF0ZShzdGF0ZSkgfVxuICAgIHZhciBuc3RhdGUgPSB7fTtcbiAgICBmb3IgKHZhciBuIGluIHN0YXRlKSB7XG4gICAgICB2YXIgdmFsID0gc3RhdGVbbl07XG4gICAgICBpZiAodmFsIGluc3RhbmNlb2YgQXJyYXkpIHsgdmFsID0gdmFsLmNvbmNhdChbXSk7IH1cbiAgICAgIG5zdGF0ZVtuXSA9IHZhbDtcbiAgICB9XG4gICAgcmV0dXJuIG5zdGF0ZVxuICB9XG5cbiAgLy8gR2l2ZW4gYSBtb2RlIGFuZCBhIHN0YXRlIChmb3IgdGhhdCBtb2RlKSwgZmluZCB0aGUgaW5uZXIgbW9kZSBhbmRcbiAgLy8gc3RhdGUgYXQgdGhlIHBvc2l0aW9uIHRoYXQgdGhlIHN0YXRlIHJlZmVycyB0by5cbiAgZnVuY3Rpb24gaW5uZXJNb2RlKG1vZGUsIHN0YXRlKSB7XG4gICAgdmFyIGluZm87XG4gICAgd2hpbGUgKG1vZGUuaW5uZXJNb2RlKSB7XG4gICAgICBpbmZvID0gbW9kZS5pbm5lck1vZGUoc3RhdGUpO1xuICAgICAgaWYgKCFpbmZvIHx8IGluZm8ubW9kZSA9PSBtb2RlKSB7IGJyZWFrIH1cbiAgICAgIHN0YXRlID0gaW5mby5zdGF0ZTtcbiAgICAgIG1vZGUgPSBpbmZvLm1vZGU7XG4gICAgfVxuICAgIHJldHVybiBpbmZvIHx8IHttb2RlOiBtb2RlLCBzdGF0ZTogc3RhdGV9XG4gIH1cblxuICBmdW5jdGlvbiBzdGFydFN0YXRlKG1vZGUsIGExLCBhMikge1xuICAgIHJldHVybiBtb2RlLnN0YXJ0U3RhdGUgPyBtb2RlLnN0YXJ0U3RhdGUoYTEsIGEyKSA6IHRydWVcbiAgfVxuXG4gIC8vIFNUUklORyBTVFJFQU1cblxuICAvLyBGZWQgdG8gdGhlIG1vZGUgcGFyc2VycywgcHJvdmlkZXMgaGVscGVyIGZ1bmN0aW9ucyB0byBtYWtlXG4gIC8vIHBhcnNlcnMgbW9yZSBzdWNjaW5jdC5cblxuICB2YXIgU3RyaW5nU3RyZWFtID0gZnVuY3Rpb24oc3RyaW5nLCB0YWJTaXplLCBsaW5lT3JhY2xlKSB7XG4gICAgdGhpcy5wb3MgPSB0aGlzLnN0YXJ0ID0gMDtcbiAgICB0aGlzLnN0cmluZyA9IHN0cmluZztcbiAgICB0aGlzLnRhYlNpemUgPSB0YWJTaXplIHx8IDg7XG4gICAgdGhpcy5sYXN0Q29sdW1uUG9zID0gdGhpcy5sYXN0Q29sdW1uVmFsdWUgPSAwO1xuICAgIHRoaXMubGluZVN0YXJ0ID0gMDtcbiAgICB0aGlzLmxpbmVPcmFjbGUgPSBsaW5lT3JhY2xlO1xuICB9O1xuXG4gIFN0cmluZ1N0cmVhbS5wcm90b3R5cGUuZW9sID0gZnVuY3Rpb24gKCkge3JldHVybiB0aGlzLnBvcyA+PSB0aGlzLnN0cmluZy5sZW5ndGh9O1xuICBTdHJpbmdTdHJlYW0ucHJvdG90eXBlLnNvbCA9IGZ1bmN0aW9uICgpIHtyZXR1cm4gdGhpcy5wb3MgPT0gdGhpcy5saW5lU3RhcnR9O1xuICBTdHJpbmdTdHJlYW0ucHJvdG90eXBlLnBlZWsgPSBmdW5jdGlvbiAoKSB7cmV0dXJuIHRoaXMuc3RyaW5nLmNoYXJBdCh0aGlzLnBvcykgfHwgdW5kZWZpbmVkfTtcbiAgU3RyaW5nU3RyZWFtLnByb3RvdHlwZS5uZXh0ID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLnBvcyA8IHRoaXMuc3RyaW5nLmxlbmd0aClcbiAgICAgIHsgcmV0dXJuIHRoaXMuc3RyaW5nLmNoYXJBdCh0aGlzLnBvcysrKSB9XG4gIH07XG4gIFN0cmluZ1N0cmVhbS5wcm90b3R5cGUuZWF0ID0gZnVuY3Rpb24gKG1hdGNoKSB7XG4gICAgdmFyIGNoID0gdGhpcy5zdHJpbmcuY2hhckF0KHRoaXMucG9zKTtcbiAgICB2YXIgb2s7XG4gICAgaWYgKHR5cGVvZiBtYXRjaCA9PSBcInN0cmluZ1wiKSB7IG9rID0gY2ggPT0gbWF0Y2g7IH1cbiAgICBlbHNlIHsgb2sgPSBjaCAmJiAobWF0Y2gudGVzdCA/IG1hdGNoLnRlc3QoY2gpIDogbWF0Y2goY2gpKTsgfVxuICAgIGlmIChvaykgeysrdGhpcy5wb3M7IHJldHVybiBjaH1cbiAgfTtcbiAgU3RyaW5nU3RyZWFtLnByb3RvdHlwZS5lYXRXaGlsZSA9IGZ1bmN0aW9uIChtYXRjaCkge1xuICAgIHZhciBzdGFydCA9IHRoaXMucG9zO1xuICAgIHdoaWxlICh0aGlzLmVhdChtYXRjaCkpe31cbiAgICByZXR1cm4gdGhpcy5wb3MgPiBzdGFydFxuICB9O1xuICBTdHJpbmdTdHJlYW0ucHJvdG90eXBlLmVhdFNwYWNlID0gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICB2YXIgc3RhcnQgPSB0aGlzLnBvcztcbiAgICB3aGlsZSAoL1tcXHNcXHUwMGEwXS8udGVzdCh0aGlzLnN0cmluZy5jaGFyQXQodGhpcy5wb3MpKSkgeyArK3RoaXMkMS5wb3M7IH1cbiAgICByZXR1cm4gdGhpcy5wb3MgPiBzdGFydFxuICB9O1xuICBTdHJpbmdTdHJlYW0ucHJvdG90eXBlLnNraXBUb0VuZCA9IGZ1bmN0aW9uICgpIHt0aGlzLnBvcyA9IHRoaXMuc3RyaW5nLmxlbmd0aDt9O1xuICBTdHJpbmdTdHJlYW0ucHJvdG90eXBlLnNraXBUbyA9IGZ1bmN0aW9uIChjaCkge1xuICAgIHZhciBmb3VuZCA9IHRoaXMuc3RyaW5nLmluZGV4T2YoY2gsIHRoaXMucG9zKTtcbiAgICBpZiAoZm91bmQgPiAtMSkge3RoaXMucG9zID0gZm91bmQ7IHJldHVybiB0cnVlfVxuICB9O1xuICBTdHJpbmdTdHJlYW0ucHJvdG90eXBlLmJhY2tVcCA9IGZ1bmN0aW9uIChuKSB7dGhpcy5wb3MgLT0gbjt9O1xuICBTdHJpbmdTdHJlYW0ucHJvdG90eXBlLmNvbHVtbiA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5sYXN0Q29sdW1uUG9zIDwgdGhpcy5zdGFydCkge1xuICAgICAgdGhpcy5sYXN0Q29sdW1uVmFsdWUgPSBjb3VudENvbHVtbih0aGlzLnN0cmluZywgdGhpcy5zdGFydCwgdGhpcy50YWJTaXplLCB0aGlzLmxhc3RDb2x1bW5Qb3MsIHRoaXMubGFzdENvbHVtblZhbHVlKTtcbiAgICAgIHRoaXMubGFzdENvbHVtblBvcyA9IHRoaXMuc3RhcnQ7XG4gICAgfVxuICAgIHJldHVybiB0aGlzLmxhc3RDb2x1bW5WYWx1ZSAtICh0aGlzLmxpbmVTdGFydCA/IGNvdW50Q29sdW1uKHRoaXMuc3RyaW5nLCB0aGlzLmxpbmVTdGFydCwgdGhpcy50YWJTaXplKSA6IDApXG4gIH07XG4gIFN0cmluZ1N0cmVhbS5wcm90b3R5cGUuaW5kZW50YXRpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIGNvdW50Q29sdW1uKHRoaXMuc3RyaW5nLCBudWxsLCB0aGlzLnRhYlNpemUpIC1cbiAgICAgICh0aGlzLmxpbmVTdGFydCA/IGNvdW50Q29sdW1uKHRoaXMuc3RyaW5nLCB0aGlzLmxpbmVTdGFydCwgdGhpcy50YWJTaXplKSA6IDApXG4gIH07XG4gIFN0cmluZ1N0cmVhbS5wcm90b3R5cGUubWF0Y2ggPSBmdW5jdGlvbiAocGF0dGVybiwgY29uc3VtZSwgY2FzZUluc2Vuc2l0aXZlKSB7XG4gICAgaWYgKHR5cGVvZiBwYXR0ZXJuID09IFwic3RyaW5nXCIpIHtcbiAgICAgIHZhciBjYXNlZCA9IGZ1bmN0aW9uIChzdHIpIHsgcmV0dXJuIGNhc2VJbnNlbnNpdGl2ZSA/IHN0ci50b0xvd2VyQ2FzZSgpIDogc3RyOyB9O1xuICAgICAgdmFyIHN1YnN0ciA9IHRoaXMuc3RyaW5nLnN1YnN0cih0aGlzLnBvcywgcGF0dGVybi5sZW5ndGgpO1xuICAgICAgaWYgKGNhc2VkKHN1YnN0cikgPT0gY2FzZWQocGF0dGVybikpIHtcbiAgICAgICAgaWYgKGNvbnN1bWUgIT09IGZhbHNlKSB7IHRoaXMucG9zICs9IHBhdHRlcm4ubGVuZ3RoOyB9XG4gICAgICAgIHJldHVybiB0cnVlXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBtYXRjaCA9IHRoaXMuc3RyaW5nLnNsaWNlKHRoaXMucG9zKS5tYXRjaChwYXR0ZXJuKTtcbiAgICAgIGlmIChtYXRjaCAmJiBtYXRjaC5pbmRleCA+IDApIHsgcmV0dXJuIG51bGwgfVxuICAgICAgaWYgKG1hdGNoICYmIGNvbnN1bWUgIT09IGZhbHNlKSB7IHRoaXMucG9zICs9IG1hdGNoWzBdLmxlbmd0aDsgfVxuICAgICAgcmV0dXJuIG1hdGNoXG4gICAgfVxuICB9O1xuICBTdHJpbmdTdHJlYW0ucHJvdG90eXBlLmN1cnJlbnQgPSBmdW5jdGlvbiAoKXtyZXR1cm4gdGhpcy5zdHJpbmcuc2xpY2UodGhpcy5zdGFydCwgdGhpcy5wb3MpfTtcbiAgU3RyaW5nU3RyZWFtLnByb3RvdHlwZS5oaWRlRmlyc3RDaGFycyA9IGZ1bmN0aW9uIChuLCBpbm5lcikge1xuICAgIHRoaXMubGluZVN0YXJ0ICs9IG47XG4gICAgdHJ5IHsgcmV0dXJuIGlubmVyKCkgfVxuICAgIGZpbmFsbHkgeyB0aGlzLmxpbmVTdGFydCAtPSBuOyB9XG4gIH07XG4gIFN0cmluZ1N0cmVhbS5wcm90b3R5cGUubG9va0FoZWFkID0gZnVuY3Rpb24gKG4pIHtcbiAgICB2YXIgb3JhY2xlID0gdGhpcy5saW5lT3JhY2xlO1xuICAgIHJldHVybiBvcmFjbGUgJiYgb3JhY2xlLmxvb2tBaGVhZChuKVxuICB9O1xuICBTdHJpbmdTdHJlYW0ucHJvdG90eXBlLmJhc2VUb2tlbiA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgb3JhY2xlID0gdGhpcy5saW5lT3JhY2xlO1xuICAgIHJldHVybiBvcmFjbGUgJiYgb3JhY2xlLmJhc2VUb2tlbih0aGlzLnBvcylcbiAgfTtcblxuICB2YXIgU2F2ZWRDb250ZXh0ID0gZnVuY3Rpb24oc3RhdGUsIGxvb2tBaGVhZCkge1xuICAgIHRoaXMuc3RhdGUgPSBzdGF0ZTtcbiAgICB0aGlzLmxvb2tBaGVhZCA9IGxvb2tBaGVhZDtcbiAgfTtcblxuICB2YXIgQ29udGV4dCA9IGZ1bmN0aW9uKGRvYywgc3RhdGUsIGxpbmUsIGxvb2tBaGVhZCkge1xuICAgIHRoaXMuc3RhdGUgPSBzdGF0ZTtcbiAgICB0aGlzLmRvYyA9IGRvYztcbiAgICB0aGlzLmxpbmUgPSBsaW5lO1xuICAgIHRoaXMubWF4TG9va0FoZWFkID0gbG9va0FoZWFkIHx8IDA7XG4gICAgdGhpcy5iYXNlVG9rZW5zID0gbnVsbDtcbiAgICB0aGlzLmJhc2VUb2tlblBvcyA9IDE7XG4gIH07XG5cbiAgQ29udGV4dC5wcm90b3R5cGUubG9va0FoZWFkID0gZnVuY3Rpb24gKG4pIHtcbiAgICB2YXIgbGluZSA9IHRoaXMuZG9jLmdldExpbmUodGhpcy5saW5lICsgbik7XG4gICAgaWYgKGxpbmUgIT0gbnVsbCAmJiBuID4gdGhpcy5tYXhMb29rQWhlYWQpIHsgdGhpcy5tYXhMb29rQWhlYWQgPSBuOyB9XG4gICAgcmV0dXJuIGxpbmVcbiAgfTtcblxuICBDb250ZXh0LnByb3RvdHlwZS5iYXNlVG9rZW4gPSBmdW5jdGlvbiAobikge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICBpZiAoIXRoaXMuYmFzZVRva2VucykgeyByZXR1cm4gbnVsbCB9XG4gICAgd2hpbGUgKHRoaXMuYmFzZVRva2Vuc1t0aGlzLmJhc2VUb2tlblBvc10gPD0gbilcbiAgICAgIHsgdGhpcyQxLmJhc2VUb2tlblBvcyArPSAyOyB9XG4gICAgdmFyIHR5cGUgPSB0aGlzLmJhc2VUb2tlbnNbdGhpcy5iYXNlVG9rZW5Qb3MgKyAxXTtcbiAgICByZXR1cm4ge3R5cGU6IHR5cGUgJiYgdHlwZS5yZXBsYWNlKC8oIHxeKW92ZXJsYXkgLiovLCBcIlwiKSxcbiAgICAgICAgICAgIHNpemU6IHRoaXMuYmFzZVRva2Vuc1t0aGlzLmJhc2VUb2tlblBvc10gLSBufVxuICB9O1xuXG4gIENvbnRleHQucHJvdG90eXBlLm5leHRMaW5lID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMubGluZSsrO1xuICAgIGlmICh0aGlzLm1heExvb2tBaGVhZCA+IDApIHsgdGhpcy5tYXhMb29rQWhlYWQtLTsgfVxuICB9O1xuXG4gIENvbnRleHQuZnJvbVNhdmVkID0gZnVuY3Rpb24gKGRvYywgc2F2ZWQsIGxpbmUpIHtcbiAgICBpZiAoc2F2ZWQgaW5zdGFuY2VvZiBTYXZlZENvbnRleHQpXG4gICAgICB7IHJldHVybiBuZXcgQ29udGV4dChkb2MsIGNvcHlTdGF0ZShkb2MubW9kZSwgc2F2ZWQuc3RhdGUpLCBsaW5lLCBzYXZlZC5sb29rQWhlYWQpIH1cbiAgICBlbHNlXG4gICAgICB7IHJldHVybiBuZXcgQ29udGV4dChkb2MsIGNvcHlTdGF0ZShkb2MubW9kZSwgc2F2ZWQpLCBsaW5lKSB9XG4gIH07XG5cbiAgQ29udGV4dC5wcm90b3R5cGUuc2F2ZSA9IGZ1bmN0aW9uIChjb3B5KSB7XG4gICAgdmFyIHN0YXRlID0gY29weSAhPT0gZmFsc2UgPyBjb3B5U3RhdGUodGhpcy5kb2MubW9kZSwgdGhpcy5zdGF0ZSkgOiB0aGlzLnN0YXRlO1xuICAgIHJldHVybiB0aGlzLm1heExvb2tBaGVhZCA+IDAgPyBuZXcgU2F2ZWRDb250ZXh0KHN0YXRlLCB0aGlzLm1heExvb2tBaGVhZCkgOiBzdGF0ZVxuICB9O1xuXG5cbiAgLy8gQ29tcHV0ZSBhIHN0eWxlIGFycmF5IChhbiBhcnJheSBzdGFydGluZyB3aXRoIGEgbW9kZSBnZW5lcmF0aW9uXG4gIC8vIC0tIGZvciBpbnZhbGlkYXRpb24gLS0gZm9sbG93ZWQgYnkgcGFpcnMgb2YgZW5kIHBvc2l0aW9ucyBhbmRcbiAgLy8gc3R5bGUgc3RyaW5ncyksIHdoaWNoIGlzIHVzZWQgdG8gaGlnaGxpZ2h0IHRoZSB0b2tlbnMgb24gdGhlXG4gIC8vIGxpbmUuXG4gIGZ1bmN0aW9uIGhpZ2hsaWdodExpbmUoY20sIGxpbmUsIGNvbnRleHQsIGZvcmNlVG9FbmQpIHtcbiAgICAvLyBBIHN0eWxlcyBhcnJheSBhbHdheXMgc3RhcnRzIHdpdGggYSBudW1iZXIgaWRlbnRpZnlpbmcgdGhlXG4gICAgLy8gbW9kZS9vdmVybGF5cyB0aGF0IGl0IGlzIGJhc2VkIG9uIChmb3IgZWFzeSBpbnZhbGlkYXRpb24pLlxuICAgIHZhciBzdCA9IFtjbS5zdGF0ZS5tb2RlR2VuXSwgbGluZUNsYXNzZXMgPSB7fTtcbiAgICAvLyBDb21wdXRlIHRoZSBiYXNlIGFycmF5IG9mIHN0eWxlc1xuICAgIHJ1bk1vZGUoY20sIGxpbmUudGV4dCwgY20uZG9jLm1vZGUsIGNvbnRleHQsIGZ1bmN0aW9uIChlbmQsIHN0eWxlKSB7IHJldHVybiBzdC5wdXNoKGVuZCwgc3R5bGUpOyB9LFxuICAgICAgICAgICAgbGluZUNsYXNzZXMsIGZvcmNlVG9FbmQpO1xuICAgIHZhciBzdGF0ZSA9IGNvbnRleHQuc3RhdGU7XG5cbiAgICAvLyBSdW4gb3ZlcmxheXMsIGFkanVzdCBzdHlsZSBhcnJheS5cbiAgICB2YXIgbG9vcCA9IGZ1bmN0aW9uICggbyApIHtcbiAgICAgIGNvbnRleHQuYmFzZVRva2VucyA9IHN0O1xuICAgICAgdmFyIG92ZXJsYXkgPSBjbS5zdGF0ZS5vdmVybGF5c1tvXSwgaSA9IDEsIGF0ID0gMDtcbiAgICAgIGNvbnRleHQuc3RhdGUgPSB0cnVlO1xuICAgICAgcnVuTW9kZShjbSwgbGluZS50ZXh0LCBvdmVybGF5Lm1vZGUsIGNvbnRleHQsIGZ1bmN0aW9uIChlbmQsIHN0eWxlKSB7XG4gICAgICAgIHZhciBzdGFydCA9IGk7XG4gICAgICAgIC8vIEVuc3VyZSB0aGVyZSdzIGEgdG9rZW4gZW5kIGF0IHRoZSBjdXJyZW50IHBvc2l0aW9uLCBhbmQgdGhhdCBpIHBvaW50cyBhdCBpdFxuICAgICAgICB3aGlsZSAoYXQgPCBlbmQpIHtcbiAgICAgICAgICB2YXIgaV9lbmQgPSBzdFtpXTtcbiAgICAgICAgICBpZiAoaV9lbmQgPiBlbmQpXG4gICAgICAgICAgICB7IHN0LnNwbGljZShpLCAxLCBlbmQsIHN0W2krMV0sIGlfZW5kKTsgfVxuICAgICAgICAgIGkgKz0gMjtcbiAgICAgICAgICBhdCA9IE1hdGgubWluKGVuZCwgaV9lbmQpO1xuICAgICAgICB9XG4gICAgICAgIGlmICghc3R5bGUpIHsgcmV0dXJuIH1cbiAgICAgICAgaWYgKG92ZXJsYXkub3BhcXVlKSB7XG4gICAgICAgICAgc3Quc3BsaWNlKHN0YXJ0LCBpIC0gc3RhcnQsIGVuZCwgXCJvdmVybGF5IFwiICsgc3R5bGUpO1xuICAgICAgICAgIGkgPSBzdGFydCArIDI7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZm9yICg7IHN0YXJ0IDwgaTsgc3RhcnQgKz0gMikge1xuICAgICAgICAgICAgdmFyIGN1ciA9IHN0W3N0YXJ0KzFdO1xuICAgICAgICAgICAgc3Rbc3RhcnQrMV0gPSAoY3VyID8gY3VyICsgXCIgXCIgOiBcIlwiKSArIFwib3ZlcmxheSBcIiArIHN0eWxlO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSwgbGluZUNsYXNzZXMpO1xuICAgICAgY29udGV4dC5zdGF0ZSA9IHN0YXRlO1xuICAgICAgY29udGV4dC5iYXNlVG9rZW5zID0gbnVsbDtcbiAgICAgIGNvbnRleHQuYmFzZVRva2VuUG9zID0gMTtcbiAgICB9O1xuXG4gICAgZm9yICh2YXIgbyA9IDA7IG8gPCBjbS5zdGF0ZS5vdmVybGF5cy5sZW5ndGg7ICsrbykgbG9vcCggbyApO1xuXG4gICAgcmV0dXJuIHtzdHlsZXM6IHN0LCBjbGFzc2VzOiBsaW5lQ2xhc3Nlcy5iZ0NsYXNzIHx8IGxpbmVDbGFzc2VzLnRleHRDbGFzcyA/IGxpbmVDbGFzc2VzIDogbnVsbH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGdldExpbmVTdHlsZXMoY20sIGxpbmUsIHVwZGF0ZUZyb250aWVyKSB7XG4gICAgaWYgKCFsaW5lLnN0eWxlcyB8fCBsaW5lLnN0eWxlc1swXSAhPSBjbS5zdGF0ZS5tb2RlR2VuKSB7XG4gICAgICB2YXIgY29udGV4dCA9IGdldENvbnRleHRCZWZvcmUoY20sIGxpbmVObyhsaW5lKSk7XG4gICAgICB2YXIgcmVzZXRTdGF0ZSA9IGxpbmUudGV4dC5sZW5ndGggPiBjbS5vcHRpb25zLm1heEhpZ2hsaWdodExlbmd0aCAmJiBjb3B5U3RhdGUoY20uZG9jLm1vZGUsIGNvbnRleHQuc3RhdGUpO1xuICAgICAgdmFyIHJlc3VsdCA9IGhpZ2hsaWdodExpbmUoY20sIGxpbmUsIGNvbnRleHQpO1xuICAgICAgaWYgKHJlc2V0U3RhdGUpIHsgY29udGV4dC5zdGF0ZSA9IHJlc2V0U3RhdGU7IH1cbiAgICAgIGxpbmUuc3RhdGVBZnRlciA9IGNvbnRleHQuc2F2ZSghcmVzZXRTdGF0ZSk7XG4gICAgICBsaW5lLnN0eWxlcyA9IHJlc3VsdC5zdHlsZXM7XG4gICAgICBpZiAocmVzdWx0LmNsYXNzZXMpIHsgbGluZS5zdHlsZUNsYXNzZXMgPSByZXN1bHQuY2xhc3NlczsgfVxuICAgICAgZWxzZSBpZiAobGluZS5zdHlsZUNsYXNzZXMpIHsgbGluZS5zdHlsZUNsYXNzZXMgPSBudWxsOyB9XG4gICAgICBpZiAodXBkYXRlRnJvbnRpZXIgPT09IGNtLmRvYy5oaWdobGlnaHRGcm9udGllcilcbiAgICAgICAgeyBjbS5kb2MubW9kZUZyb250aWVyID0gTWF0aC5tYXgoY20uZG9jLm1vZGVGcm9udGllciwgKytjbS5kb2MuaGlnaGxpZ2h0RnJvbnRpZXIpOyB9XG4gICAgfVxuICAgIHJldHVybiBsaW5lLnN0eWxlc1xuICB9XG5cbiAgZnVuY3Rpb24gZ2V0Q29udGV4dEJlZm9yZShjbSwgbiwgcHJlY2lzZSkge1xuICAgIHZhciBkb2MgPSBjbS5kb2MsIGRpc3BsYXkgPSBjbS5kaXNwbGF5O1xuICAgIGlmICghZG9jLm1vZGUuc3RhcnRTdGF0ZSkgeyByZXR1cm4gbmV3IENvbnRleHQoZG9jLCB0cnVlLCBuKSB9XG4gICAgdmFyIHN0YXJ0ID0gZmluZFN0YXJ0TGluZShjbSwgbiwgcHJlY2lzZSk7XG4gICAgdmFyIHNhdmVkID0gc3RhcnQgPiBkb2MuZmlyc3QgJiYgZ2V0TGluZShkb2MsIHN0YXJ0IC0gMSkuc3RhdGVBZnRlcjtcbiAgICB2YXIgY29udGV4dCA9IHNhdmVkID8gQ29udGV4dC5mcm9tU2F2ZWQoZG9jLCBzYXZlZCwgc3RhcnQpIDogbmV3IENvbnRleHQoZG9jLCBzdGFydFN0YXRlKGRvYy5tb2RlKSwgc3RhcnQpO1xuXG4gICAgZG9jLml0ZXIoc3RhcnQsIG4sIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICBwcm9jZXNzTGluZShjbSwgbGluZS50ZXh0LCBjb250ZXh0KTtcbiAgICAgIHZhciBwb3MgPSBjb250ZXh0LmxpbmU7XG4gICAgICBsaW5lLnN0YXRlQWZ0ZXIgPSBwb3MgPT0gbiAtIDEgfHwgcG9zICUgNSA9PSAwIHx8IHBvcyA+PSBkaXNwbGF5LnZpZXdGcm9tICYmIHBvcyA8IGRpc3BsYXkudmlld1RvID8gY29udGV4dC5zYXZlKCkgOiBudWxsO1xuICAgICAgY29udGV4dC5uZXh0TGluZSgpO1xuICAgIH0pO1xuICAgIGlmIChwcmVjaXNlKSB7IGRvYy5tb2RlRnJvbnRpZXIgPSBjb250ZXh0LmxpbmU7IH1cbiAgICByZXR1cm4gY29udGV4dFxuICB9XG5cbiAgLy8gTGlnaHR3ZWlnaHQgZm9ybSBvZiBoaWdobGlnaHQgLS0gcHJvY2VlZCBvdmVyIHRoaXMgbGluZSBhbmRcbiAgLy8gdXBkYXRlIHN0YXRlLCBidXQgZG9uJ3Qgc2F2ZSBhIHN0eWxlIGFycmF5LiBVc2VkIGZvciBsaW5lcyB0aGF0XG4gIC8vIGFyZW4ndCBjdXJyZW50bHkgdmlzaWJsZS5cbiAgZnVuY3Rpb24gcHJvY2Vzc0xpbmUoY20sIHRleHQsIGNvbnRleHQsIHN0YXJ0QXQpIHtcbiAgICB2YXIgbW9kZSA9IGNtLmRvYy5tb2RlO1xuICAgIHZhciBzdHJlYW0gPSBuZXcgU3RyaW5nU3RyZWFtKHRleHQsIGNtLm9wdGlvbnMudGFiU2l6ZSwgY29udGV4dCk7XG4gICAgc3RyZWFtLnN0YXJ0ID0gc3RyZWFtLnBvcyA9IHN0YXJ0QXQgfHwgMDtcbiAgICBpZiAodGV4dCA9PSBcIlwiKSB7IGNhbGxCbGFua0xpbmUobW9kZSwgY29udGV4dC5zdGF0ZSk7IH1cbiAgICB3aGlsZSAoIXN0cmVhbS5lb2woKSkge1xuICAgICAgcmVhZFRva2VuKG1vZGUsIHN0cmVhbSwgY29udGV4dC5zdGF0ZSk7XG4gICAgICBzdHJlYW0uc3RhcnQgPSBzdHJlYW0ucG9zO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGNhbGxCbGFua0xpbmUobW9kZSwgc3RhdGUpIHtcbiAgICBpZiAobW9kZS5ibGFua0xpbmUpIHsgcmV0dXJuIG1vZGUuYmxhbmtMaW5lKHN0YXRlKSB9XG4gICAgaWYgKCFtb2RlLmlubmVyTW9kZSkgeyByZXR1cm4gfVxuICAgIHZhciBpbm5lciA9IGlubmVyTW9kZShtb2RlLCBzdGF0ZSk7XG4gICAgaWYgKGlubmVyLm1vZGUuYmxhbmtMaW5lKSB7IHJldHVybiBpbm5lci5tb2RlLmJsYW5rTGluZShpbm5lci5zdGF0ZSkgfVxuICB9XG5cbiAgZnVuY3Rpb24gcmVhZFRva2VuKG1vZGUsIHN0cmVhbSwgc3RhdGUsIGlubmVyKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCAxMDsgaSsrKSB7XG4gICAgICBpZiAoaW5uZXIpIHsgaW5uZXJbMF0gPSBpbm5lck1vZGUobW9kZSwgc3RhdGUpLm1vZGU7IH1cbiAgICAgIHZhciBzdHlsZSA9IG1vZGUudG9rZW4oc3RyZWFtLCBzdGF0ZSk7XG4gICAgICBpZiAoc3RyZWFtLnBvcyA+IHN0cmVhbS5zdGFydCkgeyByZXR1cm4gc3R5bGUgfVxuICAgIH1cbiAgICB0aHJvdyBuZXcgRXJyb3IoXCJNb2RlIFwiICsgbW9kZS5uYW1lICsgXCIgZmFpbGVkIHRvIGFkdmFuY2Ugc3RyZWFtLlwiKVxuICB9XG5cbiAgdmFyIFRva2VuID0gZnVuY3Rpb24oc3RyZWFtLCB0eXBlLCBzdGF0ZSkge1xuICAgIHRoaXMuc3RhcnQgPSBzdHJlYW0uc3RhcnQ7IHRoaXMuZW5kID0gc3RyZWFtLnBvcztcbiAgICB0aGlzLnN0cmluZyA9IHN0cmVhbS5jdXJyZW50KCk7XG4gICAgdGhpcy50eXBlID0gdHlwZSB8fCBudWxsO1xuICAgIHRoaXMuc3RhdGUgPSBzdGF0ZTtcbiAgfTtcblxuICAvLyBVdGlsaXR5IGZvciBnZXRUb2tlbkF0IGFuZCBnZXRMaW5lVG9rZW5zXG4gIGZ1bmN0aW9uIHRha2VUb2tlbihjbSwgcG9zLCBwcmVjaXNlLCBhc0FycmF5KSB7XG4gICAgdmFyIGRvYyA9IGNtLmRvYywgbW9kZSA9IGRvYy5tb2RlLCBzdHlsZTtcbiAgICBwb3MgPSBjbGlwUG9zKGRvYywgcG9zKTtcbiAgICB2YXIgbGluZSA9IGdldExpbmUoZG9jLCBwb3MubGluZSksIGNvbnRleHQgPSBnZXRDb250ZXh0QmVmb3JlKGNtLCBwb3MubGluZSwgcHJlY2lzZSk7XG4gICAgdmFyIHN0cmVhbSA9IG5ldyBTdHJpbmdTdHJlYW0obGluZS50ZXh0LCBjbS5vcHRpb25zLnRhYlNpemUsIGNvbnRleHQpLCB0b2tlbnM7XG4gICAgaWYgKGFzQXJyYXkpIHsgdG9rZW5zID0gW107IH1cbiAgICB3aGlsZSAoKGFzQXJyYXkgfHwgc3RyZWFtLnBvcyA8IHBvcy5jaCkgJiYgIXN0cmVhbS5lb2woKSkge1xuICAgICAgc3RyZWFtLnN0YXJ0ID0gc3RyZWFtLnBvcztcbiAgICAgIHN0eWxlID0gcmVhZFRva2VuKG1vZGUsIHN0cmVhbSwgY29udGV4dC5zdGF0ZSk7XG4gICAgICBpZiAoYXNBcnJheSkgeyB0b2tlbnMucHVzaChuZXcgVG9rZW4oc3RyZWFtLCBzdHlsZSwgY29weVN0YXRlKGRvYy5tb2RlLCBjb250ZXh0LnN0YXRlKSkpOyB9XG4gICAgfVxuICAgIHJldHVybiBhc0FycmF5ID8gdG9rZW5zIDogbmV3IFRva2VuKHN0cmVhbSwgc3R5bGUsIGNvbnRleHQuc3RhdGUpXG4gIH1cblxuICBmdW5jdGlvbiBleHRyYWN0TGluZUNsYXNzZXModHlwZSwgb3V0cHV0KSB7XG4gICAgaWYgKHR5cGUpIHsgZm9yICg7Oykge1xuICAgICAgdmFyIGxpbmVDbGFzcyA9IHR5cGUubWF0Y2goLyg/Ol58XFxzKylsaW5lLShiYWNrZ3JvdW5kLSk/KFxcUyspLyk7XG4gICAgICBpZiAoIWxpbmVDbGFzcykgeyBicmVhayB9XG4gICAgICB0eXBlID0gdHlwZS5zbGljZSgwLCBsaW5lQ2xhc3MuaW5kZXgpICsgdHlwZS5zbGljZShsaW5lQ2xhc3MuaW5kZXggKyBsaW5lQ2xhc3NbMF0ubGVuZ3RoKTtcbiAgICAgIHZhciBwcm9wID0gbGluZUNsYXNzWzFdID8gXCJiZ0NsYXNzXCIgOiBcInRleHRDbGFzc1wiO1xuICAgICAgaWYgKG91dHB1dFtwcm9wXSA9PSBudWxsKVxuICAgICAgICB7IG91dHB1dFtwcm9wXSA9IGxpbmVDbGFzc1syXTsgfVxuICAgICAgZWxzZSBpZiAoIShuZXcgUmVnRXhwKFwiKD86XnxcXHMpXCIgKyBsaW5lQ2xhc3NbMl0gKyBcIig/OiR8XFxzKVwiKSkudGVzdChvdXRwdXRbcHJvcF0pKVxuICAgICAgICB7IG91dHB1dFtwcm9wXSArPSBcIiBcIiArIGxpbmVDbGFzc1syXTsgfVxuICAgIH0gfVxuICAgIHJldHVybiB0eXBlXG4gIH1cblxuICAvLyBSdW4gdGhlIGdpdmVuIG1vZGUncyBwYXJzZXIgb3ZlciBhIGxpbmUsIGNhbGxpbmcgZiBmb3IgZWFjaCB0b2tlbi5cbiAgZnVuY3Rpb24gcnVuTW9kZShjbSwgdGV4dCwgbW9kZSwgY29udGV4dCwgZiwgbGluZUNsYXNzZXMsIGZvcmNlVG9FbmQpIHtcbiAgICB2YXIgZmxhdHRlblNwYW5zID0gbW9kZS5mbGF0dGVuU3BhbnM7XG4gICAgaWYgKGZsYXR0ZW5TcGFucyA9PSBudWxsKSB7IGZsYXR0ZW5TcGFucyA9IGNtLm9wdGlvbnMuZmxhdHRlblNwYW5zOyB9XG4gICAgdmFyIGN1clN0YXJ0ID0gMCwgY3VyU3R5bGUgPSBudWxsO1xuICAgIHZhciBzdHJlYW0gPSBuZXcgU3RyaW5nU3RyZWFtKHRleHQsIGNtLm9wdGlvbnMudGFiU2l6ZSwgY29udGV4dCksIHN0eWxlO1xuICAgIHZhciBpbm5lciA9IGNtLm9wdGlvbnMuYWRkTW9kZUNsYXNzICYmIFtudWxsXTtcbiAgICBpZiAodGV4dCA9PSBcIlwiKSB7IGV4dHJhY3RMaW5lQ2xhc3NlcyhjYWxsQmxhbmtMaW5lKG1vZGUsIGNvbnRleHQuc3RhdGUpLCBsaW5lQ2xhc3Nlcyk7IH1cbiAgICB3aGlsZSAoIXN0cmVhbS5lb2woKSkge1xuICAgICAgaWYgKHN0cmVhbS5wb3MgPiBjbS5vcHRpb25zLm1heEhpZ2hsaWdodExlbmd0aCkge1xuICAgICAgICBmbGF0dGVuU3BhbnMgPSBmYWxzZTtcbiAgICAgICAgaWYgKGZvcmNlVG9FbmQpIHsgcHJvY2Vzc0xpbmUoY20sIHRleHQsIGNvbnRleHQsIHN0cmVhbS5wb3MpOyB9XG4gICAgICAgIHN0cmVhbS5wb3MgPSB0ZXh0Lmxlbmd0aDtcbiAgICAgICAgc3R5bGUgPSBudWxsO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3R5bGUgPSBleHRyYWN0TGluZUNsYXNzZXMocmVhZFRva2VuKG1vZGUsIHN0cmVhbSwgY29udGV4dC5zdGF0ZSwgaW5uZXIpLCBsaW5lQ2xhc3Nlcyk7XG4gICAgICB9XG4gICAgICBpZiAoaW5uZXIpIHtcbiAgICAgICAgdmFyIG1OYW1lID0gaW5uZXJbMF0ubmFtZTtcbiAgICAgICAgaWYgKG1OYW1lKSB7IHN0eWxlID0gXCJtLVwiICsgKHN0eWxlID8gbU5hbWUgKyBcIiBcIiArIHN0eWxlIDogbU5hbWUpOyB9XG4gICAgICB9XG4gICAgICBpZiAoIWZsYXR0ZW5TcGFucyB8fCBjdXJTdHlsZSAhPSBzdHlsZSkge1xuICAgICAgICB3aGlsZSAoY3VyU3RhcnQgPCBzdHJlYW0uc3RhcnQpIHtcbiAgICAgICAgICBjdXJTdGFydCA9IE1hdGgubWluKHN0cmVhbS5zdGFydCwgY3VyU3RhcnQgKyA1MDAwKTtcbiAgICAgICAgICBmKGN1clN0YXJ0LCBjdXJTdHlsZSk7XG4gICAgICAgIH1cbiAgICAgICAgY3VyU3R5bGUgPSBzdHlsZTtcbiAgICAgIH1cbiAgICAgIHN0cmVhbS5zdGFydCA9IHN0cmVhbS5wb3M7XG4gICAgfVxuICAgIHdoaWxlIChjdXJTdGFydCA8IHN0cmVhbS5wb3MpIHtcbiAgICAgIC8vIFdlYmtpdCBzZWVtcyB0byByZWZ1c2UgdG8gcmVuZGVyIHRleHQgbm9kZXMgbG9uZ2VyIHRoYW4gNTc0NDRcbiAgICAgIC8vIGNoYXJhY3RlcnMsIGFuZCByZXR1cm5zIGluYWNjdXJhdGUgbWVhc3VyZW1lbnRzIGluIG5vZGVzXG4gICAgICAvLyBzdGFydGluZyBhcm91bmQgNTAwMCBjaGFycy5cbiAgICAgIHZhciBwb3MgPSBNYXRoLm1pbihzdHJlYW0ucG9zLCBjdXJTdGFydCArIDUwMDApO1xuICAgICAgZihwb3MsIGN1clN0eWxlKTtcbiAgICAgIGN1clN0YXJ0ID0gcG9zO1xuICAgIH1cbiAgfVxuXG4gIC8vIEZpbmRzIHRoZSBsaW5lIHRvIHN0YXJ0IHdpdGggd2hlbiBzdGFydGluZyBhIHBhcnNlLiBUcmllcyB0b1xuICAvLyBmaW5kIGEgbGluZSB3aXRoIGEgc3RhdGVBZnRlciwgc28gdGhhdCBpdCBjYW4gc3RhcnQgd2l0aCBhXG4gIC8vIHZhbGlkIHN0YXRlLiBJZiB0aGF0IGZhaWxzLCBpdCByZXR1cm5zIHRoZSBsaW5lIHdpdGggdGhlXG4gIC8vIHNtYWxsZXN0IGluZGVudGF0aW9uLCB3aGljaCB0ZW5kcyB0byBuZWVkIHRoZSBsZWFzdCBjb250ZXh0IHRvXG4gIC8vIHBhcnNlIGNvcnJlY3RseS5cbiAgZnVuY3Rpb24gZmluZFN0YXJ0TGluZShjbSwgbiwgcHJlY2lzZSkge1xuICAgIHZhciBtaW5pbmRlbnQsIG1pbmxpbmUsIGRvYyA9IGNtLmRvYztcbiAgICB2YXIgbGltID0gcHJlY2lzZSA/IC0xIDogbiAtIChjbS5kb2MubW9kZS5pbm5lck1vZGUgPyAxMDAwIDogMTAwKTtcbiAgICBmb3IgKHZhciBzZWFyY2ggPSBuOyBzZWFyY2ggPiBsaW07IC0tc2VhcmNoKSB7XG4gICAgICBpZiAoc2VhcmNoIDw9IGRvYy5maXJzdCkgeyByZXR1cm4gZG9jLmZpcnN0IH1cbiAgICAgIHZhciBsaW5lID0gZ2V0TGluZShkb2MsIHNlYXJjaCAtIDEpLCBhZnRlciA9IGxpbmUuc3RhdGVBZnRlcjtcbiAgICAgIGlmIChhZnRlciAmJiAoIXByZWNpc2UgfHwgc2VhcmNoICsgKGFmdGVyIGluc3RhbmNlb2YgU2F2ZWRDb250ZXh0ID8gYWZ0ZXIubG9va0FoZWFkIDogMCkgPD0gZG9jLm1vZGVGcm9udGllcikpXG4gICAgICAgIHsgcmV0dXJuIHNlYXJjaCB9XG4gICAgICB2YXIgaW5kZW50ZWQgPSBjb3VudENvbHVtbihsaW5lLnRleHQsIG51bGwsIGNtLm9wdGlvbnMudGFiU2l6ZSk7XG4gICAgICBpZiAobWlubGluZSA9PSBudWxsIHx8IG1pbmluZGVudCA+IGluZGVudGVkKSB7XG4gICAgICAgIG1pbmxpbmUgPSBzZWFyY2ggLSAxO1xuICAgICAgICBtaW5pbmRlbnQgPSBpbmRlbnRlZDtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG1pbmxpbmVcbiAgfVxuXG4gIGZ1bmN0aW9uIHJldHJlYXRGcm9udGllcihkb2MsIG4pIHtcbiAgICBkb2MubW9kZUZyb250aWVyID0gTWF0aC5taW4oZG9jLm1vZGVGcm9udGllciwgbik7XG4gICAgaWYgKGRvYy5oaWdobGlnaHRGcm9udGllciA8IG4gLSAxMCkgeyByZXR1cm4gfVxuICAgIHZhciBzdGFydCA9IGRvYy5maXJzdDtcbiAgICBmb3IgKHZhciBsaW5lID0gbiAtIDE7IGxpbmUgPiBzdGFydDsgbGluZS0tKSB7XG4gICAgICB2YXIgc2F2ZWQgPSBnZXRMaW5lKGRvYywgbGluZSkuc3RhdGVBZnRlcjtcbiAgICAgIC8vIGNoYW5nZSBpcyBvbiAzXG4gICAgICAvLyBzdGF0ZSBvbiBsaW5lIDEgbG9va2VkIGFoZWFkIDIgLS0gc28gc2F3IDNcbiAgICAgIC8vIHRlc3QgMSArIDIgPCAzIHNob3VsZCBjb3ZlciB0aGlzXG4gICAgICBpZiAoc2F2ZWQgJiYgKCEoc2F2ZWQgaW5zdGFuY2VvZiBTYXZlZENvbnRleHQpIHx8IGxpbmUgKyBzYXZlZC5sb29rQWhlYWQgPCBuKSkge1xuICAgICAgICBzdGFydCA9IGxpbmUgKyAxO1xuICAgICAgICBicmVha1xuICAgICAgfVxuICAgIH1cbiAgICBkb2MuaGlnaGxpZ2h0RnJvbnRpZXIgPSBNYXRoLm1pbihkb2MuaGlnaGxpZ2h0RnJvbnRpZXIsIHN0YXJ0KTtcbiAgfVxuXG4gIC8vIExJTkUgREFUQSBTVFJVQ1RVUkVcblxuICAvLyBMaW5lIG9iamVjdHMuIFRoZXNlIGhvbGQgc3RhdGUgcmVsYXRlZCB0byBhIGxpbmUsIGluY2x1ZGluZ1xuICAvLyBoaWdobGlnaHRpbmcgaW5mbyAodGhlIHN0eWxlcyBhcnJheSkuXG4gIHZhciBMaW5lID0gZnVuY3Rpb24odGV4dCwgbWFya2VkU3BhbnMsIGVzdGltYXRlSGVpZ2h0KSB7XG4gICAgdGhpcy50ZXh0ID0gdGV4dDtcbiAgICBhdHRhY2hNYXJrZWRTcGFucyh0aGlzLCBtYXJrZWRTcGFucyk7XG4gICAgdGhpcy5oZWlnaHQgPSBlc3RpbWF0ZUhlaWdodCA/IGVzdGltYXRlSGVpZ2h0KHRoaXMpIDogMTtcbiAgfTtcblxuICBMaW5lLnByb3RvdHlwZS5saW5lTm8gPSBmdW5jdGlvbiAoKSB7IHJldHVybiBsaW5lTm8odGhpcykgfTtcbiAgZXZlbnRNaXhpbihMaW5lKTtcblxuICAvLyBDaGFuZ2UgdGhlIGNvbnRlbnQgKHRleHQsIG1hcmtlcnMpIG9mIGEgbGluZS4gQXV0b21hdGljYWxseVxuICAvLyBpbnZhbGlkYXRlcyBjYWNoZWQgaW5mb3JtYXRpb24gYW5kIHRyaWVzIHRvIHJlLWVzdGltYXRlIHRoZVxuICAvLyBsaW5lJ3MgaGVpZ2h0LlxuICBmdW5jdGlvbiB1cGRhdGVMaW5lKGxpbmUsIHRleHQsIG1hcmtlZFNwYW5zLCBlc3RpbWF0ZUhlaWdodCkge1xuICAgIGxpbmUudGV4dCA9IHRleHQ7XG4gICAgaWYgKGxpbmUuc3RhdGVBZnRlcikgeyBsaW5lLnN0YXRlQWZ0ZXIgPSBudWxsOyB9XG4gICAgaWYgKGxpbmUuc3R5bGVzKSB7IGxpbmUuc3R5bGVzID0gbnVsbDsgfVxuICAgIGlmIChsaW5lLm9yZGVyICE9IG51bGwpIHsgbGluZS5vcmRlciA9IG51bGw7IH1cbiAgICBkZXRhY2hNYXJrZWRTcGFucyhsaW5lKTtcbiAgICBhdHRhY2hNYXJrZWRTcGFucyhsaW5lLCBtYXJrZWRTcGFucyk7XG4gICAgdmFyIGVzdEhlaWdodCA9IGVzdGltYXRlSGVpZ2h0ID8gZXN0aW1hdGVIZWlnaHQobGluZSkgOiAxO1xuICAgIGlmIChlc3RIZWlnaHQgIT0gbGluZS5oZWlnaHQpIHsgdXBkYXRlTGluZUhlaWdodChsaW5lLCBlc3RIZWlnaHQpOyB9XG4gIH1cblxuICAvLyBEZXRhY2ggYSBsaW5lIGZyb20gdGhlIGRvY3VtZW50IHRyZWUgYW5kIGl0cyBtYXJrZXJzLlxuICBmdW5jdGlvbiBjbGVhblVwTGluZShsaW5lKSB7XG4gICAgbGluZS5wYXJlbnQgPSBudWxsO1xuICAgIGRldGFjaE1hcmtlZFNwYW5zKGxpbmUpO1xuICB9XG5cbiAgLy8gQ29udmVydCBhIHN0eWxlIGFzIHJldHVybmVkIGJ5IGEgbW9kZSAoZWl0aGVyIG51bGwsIG9yIGEgc3RyaW5nXG4gIC8vIGNvbnRhaW5pbmcgb25lIG9yIG1vcmUgc3R5bGVzKSB0byBhIENTUyBzdHlsZS4gVGhpcyBpcyBjYWNoZWQsXG4gIC8vIGFuZCBhbHNvIGxvb2tzIGZvciBsaW5lLXdpZGUgc3R5bGVzLlxuICB2YXIgc3R5bGVUb0NsYXNzQ2FjaGUgPSB7fSwgc3R5bGVUb0NsYXNzQ2FjaGVXaXRoTW9kZSA9IHt9O1xuICBmdW5jdGlvbiBpbnRlcnByZXRUb2tlblN0eWxlKHN0eWxlLCBvcHRpb25zKSB7XG4gICAgaWYgKCFzdHlsZSB8fCAvXlxccyokLy50ZXN0KHN0eWxlKSkgeyByZXR1cm4gbnVsbCB9XG4gICAgdmFyIGNhY2hlID0gb3B0aW9ucy5hZGRNb2RlQ2xhc3MgPyBzdHlsZVRvQ2xhc3NDYWNoZVdpdGhNb2RlIDogc3R5bGVUb0NsYXNzQ2FjaGU7XG4gICAgcmV0dXJuIGNhY2hlW3N0eWxlXSB8fFxuICAgICAgKGNhY2hlW3N0eWxlXSA9IHN0eWxlLnJlcGxhY2UoL1xcUysvZywgXCJjbS0kJlwiKSlcbiAgfVxuXG4gIC8vIFJlbmRlciB0aGUgRE9NIHJlcHJlc2VudGF0aW9uIG9mIHRoZSB0ZXh0IG9mIGEgbGluZS4gQWxzbyBidWlsZHNcbiAgLy8gdXAgYSAnbGluZSBtYXAnLCB3aGljaCBwb2ludHMgYXQgdGhlIERPTSBub2RlcyB0aGF0IHJlcHJlc2VudFxuICAvLyBzcGVjaWZpYyBzdHJldGNoZXMgb2YgdGV4dCwgYW5kIGlzIHVzZWQgYnkgdGhlIG1lYXN1cmluZyBjb2RlLlxuICAvLyBUaGUgcmV0dXJuZWQgb2JqZWN0IGNvbnRhaW5zIHRoZSBET00gbm9kZSwgdGhpcyBtYXAsIGFuZFxuICAvLyBpbmZvcm1hdGlvbiBhYm91dCBsaW5lLXdpZGUgc3R5bGVzIHRoYXQgd2VyZSBzZXQgYnkgdGhlIG1vZGUuXG4gIGZ1bmN0aW9uIGJ1aWxkTGluZUNvbnRlbnQoY20sIGxpbmVWaWV3KSB7XG4gICAgLy8gVGhlIHBhZGRpbmctcmlnaHQgZm9yY2VzIHRoZSBlbGVtZW50IHRvIGhhdmUgYSAnYm9yZGVyJywgd2hpY2hcbiAgICAvLyBpcyBuZWVkZWQgb24gV2Via2l0IHRvIGJlIGFibGUgdG8gZ2V0IGxpbmUtbGV2ZWwgYm91bmRpbmdcbiAgICAvLyByZWN0YW5nbGVzIGZvciBpdCAoaW4gbWVhc3VyZUNoYXIpLlxuICAgIHZhciBjb250ZW50ID0gZWx0UChcInNwYW5cIiwgbnVsbCwgbnVsbCwgd2Via2l0ID8gXCJwYWRkaW5nLXJpZ2h0OiAuMXB4XCIgOiBudWxsKTtcbiAgICB2YXIgYnVpbGRlciA9IHtwcmU6IGVsdFAoXCJwcmVcIiwgW2NvbnRlbnRdLCBcIkNvZGVNaXJyb3ItbGluZVwiKSwgY29udGVudDogY29udGVudCxcbiAgICAgICAgICAgICAgICAgICBjb2w6IDAsIHBvczogMCwgY206IGNtLFxuICAgICAgICAgICAgICAgICAgIHRyYWlsaW5nU3BhY2U6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgIHNwbGl0U3BhY2VzOiBjbS5nZXRPcHRpb24oXCJsaW5lV3JhcHBpbmdcIil9O1xuICAgIGxpbmVWaWV3Lm1lYXN1cmUgPSB7fTtcblxuICAgIC8vIEl0ZXJhdGUgb3ZlciB0aGUgbG9naWNhbCBsaW5lcyB0aGF0IG1ha2UgdXAgdGhpcyB2aXN1YWwgbGluZS5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8PSAobGluZVZpZXcucmVzdCA/IGxpbmVWaWV3LnJlc3QubGVuZ3RoIDogMCk7IGkrKykge1xuICAgICAgdmFyIGxpbmUgPSBpID8gbGluZVZpZXcucmVzdFtpIC0gMV0gOiBsaW5lVmlldy5saW5lLCBvcmRlciA9ICh2b2lkIDApO1xuICAgICAgYnVpbGRlci5wb3MgPSAwO1xuICAgICAgYnVpbGRlci5hZGRUb2tlbiA9IGJ1aWxkVG9rZW47XG4gICAgICAvLyBPcHRpb25hbGx5IHdpcmUgaW4gc29tZSBoYWNrcyBpbnRvIHRoZSB0b2tlbi1yZW5kZXJpbmdcbiAgICAgIC8vIGFsZ29yaXRobSwgdG8gZGVhbCB3aXRoIGJyb3dzZXIgcXVpcmtzLlxuICAgICAgaWYgKGhhc0JhZEJpZGlSZWN0cyhjbS5kaXNwbGF5Lm1lYXN1cmUpICYmIChvcmRlciA9IGdldE9yZGVyKGxpbmUsIGNtLmRvYy5kaXJlY3Rpb24pKSlcbiAgICAgICAgeyBidWlsZGVyLmFkZFRva2VuID0gYnVpbGRUb2tlbkJhZEJpZGkoYnVpbGRlci5hZGRUb2tlbiwgb3JkZXIpOyB9XG4gICAgICBidWlsZGVyLm1hcCA9IFtdO1xuICAgICAgdmFyIGFsbG93RnJvbnRpZXJVcGRhdGUgPSBsaW5lVmlldyAhPSBjbS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQgJiYgbGluZU5vKGxpbmUpO1xuICAgICAgaW5zZXJ0TGluZUNvbnRlbnQobGluZSwgYnVpbGRlciwgZ2V0TGluZVN0eWxlcyhjbSwgbGluZSwgYWxsb3dGcm9udGllclVwZGF0ZSkpO1xuICAgICAgaWYgKGxpbmUuc3R5bGVDbGFzc2VzKSB7XG4gICAgICAgIGlmIChsaW5lLnN0eWxlQ2xhc3Nlcy5iZ0NsYXNzKVxuICAgICAgICAgIHsgYnVpbGRlci5iZ0NsYXNzID0gam9pbkNsYXNzZXMobGluZS5zdHlsZUNsYXNzZXMuYmdDbGFzcywgYnVpbGRlci5iZ0NsYXNzIHx8IFwiXCIpOyB9XG4gICAgICAgIGlmIChsaW5lLnN0eWxlQ2xhc3Nlcy50ZXh0Q2xhc3MpXG4gICAgICAgICAgeyBidWlsZGVyLnRleHRDbGFzcyA9IGpvaW5DbGFzc2VzKGxpbmUuc3R5bGVDbGFzc2VzLnRleHRDbGFzcywgYnVpbGRlci50ZXh0Q2xhc3MgfHwgXCJcIik7IH1cbiAgICAgIH1cblxuICAgICAgLy8gRW5zdXJlIGF0IGxlYXN0IGEgc2luZ2xlIG5vZGUgaXMgcHJlc2VudCwgZm9yIG1lYXN1cmluZy5cbiAgICAgIGlmIChidWlsZGVyLm1hcC5sZW5ndGggPT0gMClcbiAgICAgICAgeyBidWlsZGVyLm1hcC5wdXNoKDAsIDAsIGJ1aWxkZXIuY29udGVudC5hcHBlbmRDaGlsZCh6ZXJvV2lkdGhFbGVtZW50KGNtLmRpc3BsYXkubWVhc3VyZSkpKTsgfVxuXG4gICAgICAvLyBTdG9yZSB0aGUgbWFwIGFuZCBhIGNhY2hlIG9iamVjdCBmb3IgdGhlIGN1cnJlbnQgbG9naWNhbCBsaW5lXG4gICAgICBpZiAoaSA9PSAwKSB7XG4gICAgICAgIGxpbmVWaWV3Lm1lYXN1cmUubWFwID0gYnVpbGRlci5tYXA7XG4gICAgICAgIGxpbmVWaWV3Lm1lYXN1cmUuY2FjaGUgPSB7fTtcbiAgICAgIH0gZWxzZSB7XG4gIChsaW5lVmlldy5tZWFzdXJlLm1hcHMgfHwgKGxpbmVWaWV3Lm1lYXN1cmUubWFwcyA9IFtdKSkucHVzaChidWlsZGVyLm1hcClcbiAgICAgICAgOyhsaW5lVmlldy5tZWFzdXJlLmNhY2hlcyB8fCAobGluZVZpZXcubWVhc3VyZS5jYWNoZXMgPSBbXSkpLnB1c2goe30pO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFNlZSBpc3N1ZSAjMjkwMVxuICAgIGlmICh3ZWJraXQpIHtcbiAgICAgIHZhciBsYXN0ID0gYnVpbGRlci5jb250ZW50Lmxhc3RDaGlsZDtcbiAgICAgIGlmICgvXFxiY20tdGFiXFxiLy50ZXN0KGxhc3QuY2xhc3NOYW1lKSB8fCAobGFzdC5xdWVyeVNlbGVjdG9yICYmIGxhc3QucXVlcnlTZWxlY3RvcihcIi5jbS10YWJcIikpKVxuICAgICAgICB7IGJ1aWxkZXIuY29udGVudC5jbGFzc05hbWUgPSBcImNtLXRhYi13cmFwLWhhY2tcIjsgfVxuICAgIH1cblxuICAgIHNpZ25hbChjbSwgXCJyZW5kZXJMaW5lXCIsIGNtLCBsaW5lVmlldy5saW5lLCBidWlsZGVyLnByZSk7XG4gICAgaWYgKGJ1aWxkZXIucHJlLmNsYXNzTmFtZSlcbiAgICAgIHsgYnVpbGRlci50ZXh0Q2xhc3MgPSBqb2luQ2xhc3NlcyhidWlsZGVyLnByZS5jbGFzc05hbWUsIGJ1aWxkZXIudGV4dENsYXNzIHx8IFwiXCIpOyB9XG5cbiAgICByZXR1cm4gYnVpbGRlclxuICB9XG5cbiAgZnVuY3Rpb24gZGVmYXVsdFNwZWNpYWxDaGFyUGxhY2Vob2xkZXIoY2gpIHtcbiAgICB2YXIgdG9rZW4gPSBlbHQoXCJzcGFuXCIsIFwiXFx1MjAyMlwiLCBcImNtLWludmFsaWRjaGFyXCIpO1xuICAgIHRva2VuLnRpdGxlID0gXCJcXFxcdVwiICsgY2guY2hhckNvZGVBdCgwKS50b1N0cmluZygxNik7XG4gICAgdG9rZW4uc2V0QXR0cmlidXRlKFwiYXJpYS1sYWJlbFwiLCB0b2tlbi50aXRsZSk7XG4gICAgcmV0dXJuIHRva2VuXG4gIH1cblxuICAvLyBCdWlsZCB1cCB0aGUgRE9NIHJlcHJlc2VudGF0aW9uIGZvciBhIHNpbmdsZSB0b2tlbiwgYW5kIGFkZCBpdCB0b1xuICAvLyB0aGUgbGluZSBtYXAuIFRha2VzIGNhcmUgdG8gcmVuZGVyIHNwZWNpYWwgY2hhcmFjdGVycyBzZXBhcmF0ZWx5LlxuICBmdW5jdGlvbiBidWlsZFRva2VuKGJ1aWxkZXIsIHRleHQsIHN0eWxlLCBzdGFydFN0eWxlLCBlbmRTdHlsZSwgY3NzLCBhdHRyaWJ1dGVzKSB7XG4gICAgaWYgKCF0ZXh0KSB7IHJldHVybiB9XG4gICAgdmFyIGRpc3BsYXlUZXh0ID0gYnVpbGRlci5zcGxpdFNwYWNlcyA/IHNwbGl0U3BhY2VzKHRleHQsIGJ1aWxkZXIudHJhaWxpbmdTcGFjZSkgOiB0ZXh0O1xuICAgIHZhciBzcGVjaWFsID0gYnVpbGRlci5jbS5zdGF0ZS5zcGVjaWFsQ2hhcnMsIG11c3RXcmFwID0gZmFsc2U7XG4gICAgdmFyIGNvbnRlbnQ7XG4gICAgaWYgKCFzcGVjaWFsLnRlc3QodGV4dCkpIHtcbiAgICAgIGJ1aWxkZXIuY29sICs9IHRleHQubGVuZ3RoO1xuICAgICAgY29udGVudCA9IGRvY3VtZW50LmNyZWF0ZVRleHROb2RlKGRpc3BsYXlUZXh0KTtcbiAgICAgIGJ1aWxkZXIubWFwLnB1c2goYnVpbGRlci5wb3MsIGJ1aWxkZXIucG9zICsgdGV4dC5sZW5ndGgsIGNvbnRlbnQpO1xuICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCA5KSB7IG11c3RXcmFwID0gdHJ1ZTsgfVxuICAgICAgYnVpbGRlci5wb3MgKz0gdGV4dC5sZW5ndGg7XG4gICAgfSBlbHNlIHtcbiAgICAgIGNvbnRlbnQgPSBkb2N1bWVudC5jcmVhdGVEb2N1bWVudEZyYWdtZW50KCk7XG4gICAgICB2YXIgcG9zID0gMDtcbiAgICAgIHdoaWxlICh0cnVlKSB7XG4gICAgICAgIHNwZWNpYWwubGFzdEluZGV4ID0gcG9zO1xuICAgICAgICB2YXIgbSA9IHNwZWNpYWwuZXhlYyh0ZXh0KTtcbiAgICAgICAgdmFyIHNraXBwZWQgPSBtID8gbS5pbmRleCAtIHBvcyA6IHRleHQubGVuZ3RoIC0gcG9zO1xuICAgICAgICBpZiAoc2tpcHBlZCkge1xuICAgICAgICAgIHZhciB0eHQgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShkaXNwbGF5VGV4dC5zbGljZShwb3MsIHBvcyArIHNraXBwZWQpKTtcbiAgICAgICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDkpIHsgY29udGVudC5hcHBlbmRDaGlsZChlbHQoXCJzcGFuXCIsIFt0eHRdKSk7IH1cbiAgICAgICAgICBlbHNlIHsgY29udGVudC5hcHBlbmRDaGlsZCh0eHQpOyB9XG4gICAgICAgICAgYnVpbGRlci5tYXAucHVzaChidWlsZGVyLnBvcywgYnVpbGRlci5wb3MgKyBza2lwcGVkLCB0eHQpO1xuICAgICAgICAgIGJ1aWxkZXIuY29sICs9IHNraXBwZWQ7XG4gICAgICAgICAgYnVpbGRlci5wb3MgKz0gc2tpcHBlZDtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIW0pIHsgYnJlYWsgfVxuICAgICAgICBwb3MgKz0gc2tpcHBlZCArIDE7XG4gICAgICAgIHZhciB0eHQkMSA9ICh2b2lkIDApO1xuICAgICAgICBpZiAobVswXSA9PSBcIlxcdFwiKSB7XG4gICAgICAgICAgdmFyIHRhYlNpemUgPSBidWlsZGVyLmNtLm9wdGlvbnMudGFiU2l6ZSwgdGFiV2lkdGggPSB0YWJTaXplIC0gYnVpbGRlci5jb2wgJSB0YWJTaXplO1xuICAgICAgICAgIHR4dCQxID0gY29udGVudC5hcHBlbmRDaGlsZChlbHQoXCJzcGFuXCIsIHNwYWNlU3RyKHRhYldpZHRoKSwgXCJjbS10YWJcIikpO1xuICAgICAgICAgIHR4dCQxLnNldEF0dHJpYnV0ZShcInJvbGVcIiwgXCJwcmVzZW50YXRpb25cIik7XG4gICAgICAgICAgdHh0JDEuc2V0QXR0cmlidXRlKFwiY20tdGV4dFwiLCBcIlxcdFwiKTtcbiAgICAgICAgICBidWlsZGVyLmNvbCArPSB0YWJXaWR0aDtcbiAgICAgICAgfSBlbHNlIGlmIChtWzBdID09IFwiXFxyXCIgfHwgbVswXSA9PSBcIlxcblwiKSB7XG4gICAgICAgICAgdHh0JDEgPSBjb250ZW50LmFwcGVuZENoaWxkKGVsdChcInNwYW5cIiwgbVswXSA9PSBcIlxcclwiID8gXCJcXHUyNDBkXCIgOiBcIlxcdTI0MjRcIiwgXCJjbS1pbnZhbGlkY2hhclwiKSk7XG4gICAgICAgICAgdHh0JDEuc2V0QXR0cmlidXRlKFwiY20tdGV4dFwiLCBtWzBdKTtcbiAgICAgICAgICBidWlsZGVyLmNvbCArPSAxO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHR4dCQxID0gYnVpbGRlci5jbS5vcHRpb25zLnNwZWNpYWxDaGFyUGxhY2Vob2xkZXIobVswXSk7XG4gICAgICAgICAgdHh0JDEuc2V0QXR0cmlidXRlKFwiY20tdGV4dFwiLCBtWzBdKTtcbiAgICAgICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDkpIHsgY29udGVudC5hcHBlbmRDaGlsZChlbHQoXCJzcGFuXCIsIFt0eHQkMV0pKTsgfVxuICAgICAgICAgIGVsc2UgeyBjb250ZW50LmFwcGVuZENoaWxkKHR4dCQxKTsgfVxuICAgICAgICAgIGJ1aWxkZXIuY29sICs9IDE7XG4gICAgICAgIH1cbiAgICAgICAgYnVpbGRlci5tYXAucHVzaChidWlsZGVyLnBvcywgYnVpbGRlci5wb3MgKyAxLCB0eHQkMSk7XG4gICAgICAgIGJ1aWxkZXIucG9zKys7XG4gICAgICB9XG4gICAgfVxuICAgIGJ1aWxkZXIudHJhaWxpbmdTcGFjZSA9IGRpc3BsYXlUZXh0LmNoYXJDb2RlQXQodGV4dC5sZW5ndGggLSAxKSA9PSAzMjtcbiAgICBpZiAoc3R5bGUgfHwgc3RhcnRTdHlsZSB8fCBlbmRTdHlsZSB8fCBtdXN0V3JhcCB8fCBjc3MpIHtcbiAgICAgIHZhciBmdWxsU3R5bGUgPSBzdHlsZSB8fCBcIlwiO1xuICAgICAgaWYgKHN0YXJ0U3R5bGUpIHsgZnVsbFN0eWxlICs9IHN0YXJ0U3R5bGU7IH1cbiAgICAgIGlmIChlbmRTdHlsZSkgeyBmdWxsU3R5bGUgKz0gZW5kU3R5bGU7IH1cbiAgICAgIHZhciB0b2tlbiA9IGVsdChcInNwYW5cIiwgW2NvbnRlbnRdLCBmdWxsU3R5bGUsIGNzcyk7XG4gICAgICBpZiAoYXR0cmlidXRlcykge1xuICAgICAgICBmb3IgKHZhciBhdHRyIGluIGF0dHJpYnV0ZXMpIHsgaWYgKGF0dHJpYnV0ZXMuaGFzT3duUHJvcGVydHkoYXR0cikgJiYgYXR0ciAhPSBcInN0eWxlXCIgJiYgYXR0ciAhPSBcImNsYXNzXCIpXG4gICAgICAgICAgeyB0b2tlbi5zZXRBdHRyaWJ1dGUoYXR0ciwgYXR0cmlidXRlc1thdHRyXSk7IH0gfVxuICAgICAgfVxuICAgICAgcmV0dXJuIGJ1aWxkZXIuY29udGVudC5hcHBlbmRDaGlsZCh0b2tlbilcbiAgICB9XG4gICAgYnVpbGRlci5jb250ZW50LmFwcGVuZENoaWxkKGNvbnRlbnQpO1xuICB9XG5cbiAgLy8gQ2hhbmdlIHNvbWUgc3BhY2VzIHRvIE5CU1AgdG8gcHJldmVudCB0aGUgYnJvd3NlciBmcm9tIGNvbGxhcHNpbmdcbiAgLy8gdHJhaWxpbmcgc3BhY2VzIGF0IHRoZSBlbmQgb2YgYSBsaW5lIHdoZW4gcmVuZGVyaW5nIHRleHQgKGlzc3VlICMxMzYyKS5cbiAgZnVuY3Rpb24gc3BsaXRTcGFjZXModGV4dCwgdHJhaWxpbmdCZWZvcmUpIHtcbiAgICBpZiAodGV4dC5sZW5ndGggPiAxICYmICEvICAvLnRlc3QodGV4dCkpIHsgcmV0dXJuIHRleHQgfVxuICAgIHZhciBzcGFjZUJlZm9yZSA9IHRyYWlsaW5nQmVmb3JlLCByZXN1bHQgPSBcIlwiO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGV4dC5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGNoID0gdGV4dC5jaGFyQXQoaSk7XG4gICAgICBpZiAoY2ggPT0gXCIgXCIgJiYgc3BhY2VCZWZvcmUgJiYgKGkgPT0gdGV4dC5sZW5ndGggLSAxIHx8IHRleHQuY2hhckNvZGVBdChpICsgMSkgPT0gMzIpKVxuICAgICAgICB7IGNoID0gXCJcXHUwMGEwXCI7IH1cbiAgICAgIHJlc3VsdCArPSBjaDtcbiAgICAgIHNwYWNlQmVmb3JlID0gY2ggPT0gXCIgXCI7XG4gICAgfVxuICAgIHJldHVybiByZXN1bHRcbiAgfVxuXG4gIC8vIFdvcmsgYXJvdW5kIG5vbnNlbnNlIGRpbWVuc2lvbnMgYmVpbmcgcmVwb3J0ZWQgZm9yIHN0cmV0Y2hlcyBvZlxuICAvLyByaWdodC10by1sZWZ0IHRleHQuXG4gIGZ1bmN0aW9uIGJ1aWxkVG9rZW5CYWRCaWRpKGlubmVyLCBvcmRlcikge1xuICAgIHJldHVybiBmdW5jdGlvbiAoYnVpbGRlciwgdGV4dCwgc3R5bGUsIHN0YXJ0U3R5bGUsIGVuZFN0eWxlLCBjc3MsIGF0dHJpYnV0ZXMpIHtcbiAgICAgIHN0eWxlID0gc3R5bGUgPyBzdHlsZSArIFwiIGNtLWZvcmNlLWJvcmRlclwiIDogXCJjbS1mb3JjZS1ib3JkZXJcIjtcbiAgICAgIHZhciBzdGFydCA9IGJ1aWxkZXIucG9zLCBlbmQgPSBzdGFydCArIHRleHQubGVuZ3RoO1xuICAgICAgZm9yICg7Oykge1xuICAgICAgICAvLyBGaW5kIHRoZSBwYXJ0IHRoYXQgb3ZlcmxhcHMgd2l0aCB0aGUgc3RhcnQgb2YgdGhpcyB0ZXh0XG4gICAgICAgIHZhciBwYXJ0ID0gKHZvaWQgMCk7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgb3JkZXIubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICBwYXJ0ID0gb3JkZXJbaV07XG4gICAgICAgICAgaWYgKHBhcnQudG8gPiBzdGFydCAmJiBwYXJ0LmZyb20gPD0gc3RhcnQpIHsgYnJlYWsgfVxuICAgICAgICB9XG4gICAgICAgIGlmIChwYXJ0LnRvID49IGVuZCkgeyByZXR1cm4gaW5uZXIoYnVpbGRlciwgdGV4dCwgc3R5bGUsIHN0YXJ0U3R5bGUsIGVuZFN0eWxlLCBjc3MsIGF0dHJpYnV0ZXMpIH1cbiAgICAgICAgaW5uZXIoYnVpbGRlciwgdGV4dC5zbGljZSgwLCBwYXJ0LnRvIC0gc3RhcnQpLCBzdHlsZSwgc3RhcnRTdHlsZSwgbnVsbCwgY3NzLCBhdHRyaWJ1dGVzKTtcbiAgICAgICAgc3RhcnRTdHlsZSA9IG51bGw7XG4gICAgICAgIHRleHQgPSB0ZXh0LnNsaWNlKHBhcnQudG8gLSBzdGFydCk7XG4gICAgICAgIHN0YXJ0ID0gcGFydC50bztcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBidWlsZENvbGxhcHNlZFNwYW4oYnVpbGRlciwgc2l6ZSwgbWFya2VyLCBpZ25vcmVXaWRnZXQpIHtcbiAgICB2YXIgd2lkZ2V0ID0gIWlnbm9yZVdpZGdldCAmJiBtYXJrZXIud2lkZ2V0Tm9kZTtcbiAgICBpZiAod2lkZ2V0KSB7IGJ1aWxkZXIubWFwLnB1c2goYnVpbGRlci5wb3MsIGJ1aWxkZXIucG9zICsgc2l6ZSwgd2lkZ2V0KTsgfVxuICAgIGlmICghaWdub3JlV2lkZ2V0ICYmIGJ1aWxkZXIuY20uZGlzcGxheS5pbnB1dC5uZWVkc0NvbnRlbnRBdHRyaWJ1dGUpIHtcbiAgICAgIGlmICghd2lkZ2V0KVxuICAgICAgICB7IHdpZGdldCA9IGJ1aWxkZXIuY29udGVudC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVFbGVtZW50KFwic3BhblwiKSk7IH1cbiAgICAgIHdpZGdldC5zZXRBdHRyaWJ1dGUoXCJjbS1tYXJrZXJcIiwgbWFya2VyLmlkKTtcbiAgICB9XG4gICAgaWYgKHdpZGdldCkge1xuICAgICAgYnVpbGRlci5jbS5kaXNwbGF5LmlucHV0LnNldFVuZWRpdGFibGUod2lkZ2V0KTtcbiAgICAgIGJ1aWxkZXIuY29udGVudC5hcHBlbmRDaGlsZCh3aWRnZXQpO1xuICAgIH1cbiAgICBidWlsZGVyLnBvcyArPSBzaXplO1xuICAgIGJ1aWxkZXIudHJhaWxpbmdTcGFjZSA9IGZhbHNlO1xuICB9XG5cbiAgLy8gT3V0cHV0cyBhIG51bWJlciBvZiBzcGFucyB0byBtYWtlIHVwIGEgbGluZSwgdGFraW5nIGhpZ2hsaWdodGluZ1xuICAvLyBhbmQgbWFya2VkIHRleHQgaW50byBhY2NvdW50LlxuICBmdW5jdGlvbiBpbnNlcnRMaW5lQ29udGVudChsaW5lLCBidWlsZGVyLCBzdHlsZXMpIHtcbiAgICB2YXIgc3BhbnMgPSBsaW5lLm1hcmtlZFNwYW5zLCBhbGxUZXh0ID0gbGluZS50ZXh0LCBhdCA9IDA7XG4gICAgaWYgKCFzcGFucykge1xuICAgICAgZm9yICh2YXIgaSQxID0gMTsgaSQxIDwgc3R5bGVzLmxlbmd0aDsgaSQxKz0yKVxuICAgICAgICB7IGJ1aWxkZXIuYWRkVG9rZW4oYnVpbGRlciwgYWxsVGV4dC5zbGljZShhdCwgYXQgPSBzdHlsZXNbaSQxXSksIGludGVycHJldFRva2VuU3R5bGUoc3R5bGVzW2kkMSsxXSwgYnVpbGRlci5jbS5vcHRpb25zKSk7IH1cbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHZhciBsZW4gPSBhbGxUZXh0Lmxlbmd0aCwgcG9zID0gMCwgaSA9IDEsIHRleHQgPSBcIlwiLCBzdHlsZSwgY3NzO1xuICAgIHZhciBuZXh0Q2hhbmdlID0gMCwgc3BhblN0eWxlLCBzcGFuRW5kU3R5bGUsIHNwYW5TdGFydFN0eWxlLCBjb2xsYXBzZWQsIGF0dHJpYnV0ZXM7XG4gICAgZm9yICg7Oykge1xuICAgICAgaWYgKG5leHRDaGFuZ2UgPT0gcG9zKSB7IC8vIFVwZGF0ZSBjdXJyZW50IG1hcmtlciBzZXRcbiAgICAgICAgc3BhblN0eWxlID0gc3BhbkVuZFN0eWxlID0gc3BhblN0YXJ0U3R5bGUgPSBjc3MgPSBcIlwiO1xuICAgICAgICBhdHRyaWJ1dGVzID0gbnVsbDtcbiAgICAgICAgY29sbGFwc2VkID0gbnVsbDsgbmV4dENoYW5nZSA9IEluZmluaXR5O1xuICAgICAgICB2YXIgZm91bmRCb29rbWFya3MgPSBbXSwgZW5kU3R5bGVzID0gKHZvaWQgMCk7XG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgc3BhbnMubGVuZ3RoOyArK2opIHtcbiAgICAgICAgICB2YXIgc3AgPSBzcGFuc1tqXSwgbSA9IHNwLm1hcmtlcjtcbiAgICAgICAgICBpZiAobS50eXBlID09IFwiYm9va21hcmtcIiAmJiBzcC5mcm9tID09IHBvcyAmJiBtLndpZGdldE5vZGUpIHtcbiAgICAgICAgICAgIGZvdW5kQm9va21hcmtzLnB1c2gobSk7XG4gICAgICAgICAgfSBlbHNlIGlmIChzcC5mcm9tIDw9IHBvcyAmJiAoc3AudG8gPT0gbnVsbCB8fCBzcC50byA+IHBvcyB8fCBtLmNvbGxhcHNlZCAmJiBzcC50byA9PSBwb3MgJiYgc3AuZnJvbSA9PSBwb3MpKSB7XG4gICAgICAgICAgICBpZiAoc3AudG8gIT0gbnVsbCAmJiBzcC50byAhPSBwb3MgJiYgbmV4dENoYW5nZSA+IHNwLnRvKSB7XG4gICAgICAgICAgICAgIG5leHRDaGFuZ2UgPSBzcC50bztcbiAgICAgICAgICAgICAgc3BhbkVuZFN0eWxlID0gXCJcIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChtLmNsYXNzTmFtZSkgeyBzcGFuU3R5bGUgKz0gXCIgXCIgKyBtLmNsYXNzTmFtZTsgfVxuICAgICAgICAgICAgaWYgKG0uY3NzKSB7IGNzcyA9IChjc3MgPyBjc3MgKyBcIjtcIiA6IFwiXCIpICsgbS5jc3M7IH1cbiAgICAgICAgICAgIGlmIChtLnN0YXJ0U3R5bGUgJiYgc3AuZnJvbSA9PSBwb3MpIHsgc3BhblN0YXJ0U3R5bGUgKz0gXCIgXCIgKyBtLnN0YXJ0U3R5bGU7IH1cbiAgICAgICAgICAgIGlmIChtLmVuZFN0eWxlICYmIHNwLnRvID09IG5leHRDaGFuZ2UpIHsgKGVuZFN0eWxlcyB8fCAoZW5kU3R5bGVzID0gW10pKS5wdXNoKG0uZW5kU3R5bGUsIHNwLnRvKTsgfVxuICAgICAgICAgICAgLy8gc3VwcG9ydCBmb3IgdGhlIG9sZCB0aXRsZSBwcm9wZXJ0eVxuICAgICAgICAgICAgLy8gaHR0cHM6Ly9naXRodWIuY29tL2NvZGVtaXJyb3IvQ29kZU1pcnJvci9wdWxsLzU2NzNcbiAgICAgICAgICAgIGlmIChtLnRpdGxlKSB7IChhdHRyaWJ1dGVzIHx8IChhdHRyaWJ1dGVzID0ge30pKS50aXRsZSA9IG0udGl0bGU7IH1cbiAgICAgICAgICAgIGlmIChtLmF0dHJpYnV0ZXMpIHtcbiAgICAgICAgICAgICAgZm9yICh2YXIgYXR0ciBpbiBtLmF0dHJpYnV0ZXMpXG4gICAgICAgICAgICAgICAgeyAoYXR0cmlidXRlcyB8fCAoYXR0cmlidXRlcyA9IHt9KSlbYXR0cl0gPSBtLmF0dHJpYnV0ZXNbYXR0cl07IH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChtLmNvbGxhcHNlZCAmJiAoIWNvbGxhcHNlZCB8fCBjb21wYXJlQ29sbGFwc2VkTWFya2Vycyhjb2xsYXBzZWQubWFya2VyLCBtKSA8IDApKVxuICAgICAgICAgICAgICB7IGNvbGxhcHNlZCA9IHNwOyB9XG4gICAgICAgICAgfSBlbHNlIGlmIChzcC5mcm9tID4gcG9zICYmIG5leHRDaGFuZ2UgPiBzcC5mcm9tKSB7XG4gICAgICAgICAgICBuZXh0Q2hhbmdlID0gc3AuZnJvbTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGVuZFN0eWxlcykgeyBmb3IgKHZhciBqJDEgPSAwOyBqJDEgPCBlbmRTdHlsZXMubGVuZ3RoOyBqJDEgKz0gMilcbiAgICAgICAgICB7IGlmIChlbmRTdHlsZXNbaiQxICsgMV0gPT0gbmV4dENoYW5nZSkgeyBzcGFuRW5kU3R5bGUgKz0gXCIgXCIgKyBlbmRTdHlsZXNbaiQxXTsgfSB9IH1cblxuICAgICAgICBpZiAoIWNvbGxhcHNlZCB8fCBjb2xsYXBzZWQuZnJvbSA9PSBwb3MpIHsgZm9yICh2YXIgaiQyID0gMDsgaiQyIDwgZm91bmRCb29rbWFya3MubGVuZ3RoOyArK2okMilcbiAgICAgICAgICB7IGJ1aWxkQ29sbGFwc2VkU3BhbihidWlsZGVyLCAwLCBmb3VuZEJvb2ttYXJrc1tqJDJdKTsgfSB9XG4gICAgICAgIGlmIChjb2xsYXBzZWQgJiYgKGNvbGxhcHNlZC5mcm9tIHx8IDApID09IHBvcykge1xuICAgICAgICAgIGJ1aWxkQ29sbGFwc2VkU3BhbihidWlsZGVyLCAoY29sbGFwc2VkLnRvID09IG51bGwgPyBsZW4gKyAxIDogY29sbGFwc2VkLnRvKSAtIHBvcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY29sbGFwc2VkLm1hcmtlciwgY29sbGFwc2VkLmZyb20gPT0gbnVsbCk7XG4gICAgICAgICAgaWYgKGNvbGxhcHNlZC50byA9PSBudWxsKSB7IHJldHVybiB9XG4gICAgICAgICAgaWYgKGNvbGxhcHNlZC50byA9PSBwb3MpIHsgY29sbGFwc2VkID0gZmFsc2U7IH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKHBvcyA+PSBsZW4pIHsgYnJlYWsgfVxuXG4gICAgICB2YXIgdXB0byA9IE1hdGgubWluKGxlbiwgbmV4dENoYW5nZSk7XG4gICAgICB3aGlsZSAodHJ1ZSkge1xuICAgICAgICBpZiAodGV4dCkge1xuICAgICAgICAgIHZhciBlbmQgPSBwb3MgKyB0ZXh0Lmxlbmd0aDtcbiAgICAgICAgICBpZiAoIWNvbGxhcHNlZCkge1xuICAgICAgICAgICAgdmFyIHRva2VuVGV4dCA9IGVuZCA+IHVwdG8gPyB0ZXh0LnNsaWNlKDAsIHVwdG8gLSBwb3MpIDogdGV4dDtcbiAgICAgICAgICAgIGJ1aWxkZXIuYWRkVG9rZW4oYnVpbGRlciwgdG9rZW5UZXh0LCBzdHlsZSA/IHN0eWxlICsgc3BhblN0eWxlIDogc3BhblN0eWxlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzcGFuU3RhcnRTdHlsZSwgcG9zICsgdG9rZW5UZXh0Lmxlbmd0aCA9PSBuZXh0Q2hhbmdlID8gc3BhbkVuZFN0eWxlIDogXCJcIiwgY3NzLCBhdHRyaWJ1dGVzKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGVuZCA+PSB1cHRvKSB7dGV4dCA9IHRleHQuc2xpY2UodXB0byAtIHBvcyk7IHBvcyA9IHVwdG87IGJyZWFrfVxuICAgICAgICAgIHBvcyA9IGVuZDtcbiAgICAgICAgICBzcGFuU3RhcnRTdHlsZSA9IFwiXCI7XG4gICAgICAgIH1cbiAgICAgICAgdGV4dCA9IGFsbFRleHQuc2xpY2UoYXQsIGF0ID0gc3R5bGVzW2krK10pO1xuICAgICAgICBzdHlsZSA9IGludGVycHJldFRva2VuU3R5bGUoc3R5bGVzW2krK10sIGJ1aWxkZXIuY20ub3B0aW9ucyk7XG4gICAgICB9XG4gICAgfVxuICB9XG5cblxuICAvLyBUaGVzZSBvYmplY3RzIGFyZSB1c2VkIHRvIHJlcHJlc2VudCB0aGUgdmlzaWJsZSAoY3VycmVudGx5IGRyYXduKVxuICAvLyBwYXJ0IG9mIHRoZSBkb2N1bWVudC4gQSBMaW5lVmlldyBtYXkgY29ycmVzcG9uZCB0byBtdWx0aXBsZVxuICAvLyBsb2dpY2FsIGxpbmVzLCBpZiB0aG9zZSBhcmUgY29ubmVjdGVkIGJ5IGNvbGxhcHNlZCByYW5nZXMuXG4gIGZ1bmN0aW9uIExpbmVWaWV3KGRvYywgbGluZSwgbGluZU4pIHtcbiAgICAvLyBUaGUgc3RhcnRpbmcgbGluZVxuICAgIHRoaXMubGluZSA9IGxpbmU7XG4gICAgLy8gQ29udGludWluZyBsaW5lcywgaWYgYW55XG4gICAgdGhpcy5yZXN0ID0gdmlzdWFsTGluZUNvbnRpbnVlZChsaW5lKTtcbiAgICAvLyBOdW1iZXIgb2YgbG9naWNhbCBsaW5lcyBpbiB0aGlzIHZpc3VhbCBsaW5lXG4gICAgdGhpcy5zaXplID0gdGhpcy5yZXN0ID8gbGluZU5vKGxzdCh0aGlzLnJlc3QpKSAtIGxpbmVOICsgMSA6IDE7XG4gICAgdGhpcy5ub2RlID0gdGhpcy50ZXh0ID0gbnVsbDtcbiAgICB0aGlzLmhpZGRlbiA9IGxpbmVJc0hpZGRlbihkb2MsIGxpbmUpO1xuICB9XG5cbiAgLy8gQ3JlYXRlIGEgcmFuZ2Ugb2YgTGluZVZpZXcgb2JqZWN0cyBmb3IgdGhlIGdpdmVuIGxpbmVzLlxuICBmdW5jdGlvbiBidWlsZFZpZXdBcnJheShjbSwgZnJvbSwgdG8pIHtcbiAgICB2YXIgYXJyYXkgPSBbXSwgbmV4dFBvcztcbiAgICBmb3IgKHZhciBwb3MgPSBmcm9tOyBwb3MgPCB0bzsgcG9zID0gbmV4dFBvcykge1xuICAgICAgdmFyIHZpZXcgPSBuZXcgTGluZVZpZXcoY20uZG9jLCBnZXRMaW5lKGNtLmRvYywgcG9zKSwgcG9zKTtcbiAgICAgIG5leHRQb3MgPSBwb3MgKyB2aWV3LnNpemU7XG4gICAgICBhcnJheS5wdXNoKHZpZXcpO1xuICAgIH1cbiAgICByZXR1cm4gYXJyYXlcbiAgfVxuXG4gIHZhciBvcGVyYXRpb25Hcm91cCA9IG51bGw7XG5cbiAgZnVuY3Rpb24gcHVzaE9wZXJhdGlvbihvcCkge1xuICAgIGlmIChvcGVyYXRpb25Hcm91cCkge1xuICAgICAgb3BlcmF0aW9uR3JvdXAub3BzLnB1c2gob3ApO1xuICAgIH0gZWxzZSB7XG4gICAgICBvcC5vd25zR3JvdXAgPSBvcGVyYXRpb25Hcm91cCA9IHtcbiAgICAgICAgb3BzOiBbb3BdLFxuICAgICAgICBkZWxheWVkQ2FsbGJhY2tzOiBbXVxuICAgICAgfTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBmaXJlQ2FsbGJhY2tzRm9yT3BzKGdyb3VwKSB7XG4gICAgLy8gQ2FsbHMgZGVsYXllZCBjYWxsYmFja3MgYW5kIGN1cnNvckFjdGl2aXR5IGhhbmRsZXJzIHVudGlsIG5vXG4gICAgLy8gbmV3IG9uZXMgYXBwZWFyXG4gICAgdmFyIGNhbGxiYWNrcyA9IGdyb3VwLmRlbGF5ZWRDYWxsYmFja3MsIGkgPSAwO1xuICAgIGRvIHtcbiAgICAgIGZvciAoOyBpIDwgY2FsbGJhY2tzLmxlbmd0aDsgaSsrKVxuICAgICAgICB7IGNhbGxiYWNrc1tpXS5jYWxsKG51bGwpOyB9XG4gICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGdyb3VwLm9wcy5sZW5ndGg7IGorKykge1xuICAgICAgICB2YXIgb3AgPSBncm91cC5vcHNbal07XG4gICAgICAgIGlmIChvcC5jdXJzb3JBY3Rpdml0eUhhbmRsZXJzKVxuICAgICAgICAgIHsgd2hpbGUgKG9wLmN1cnNvckFjdGl2aXR5Q2FsbGVkIDwgb3AuY3Vyc29yQWN0aXZpdHlIYW5kbGVycy5sZW5ndGgpXG4gICAgICAgICAgICB7IG9wLmN1cnNvckFjdGl2aXR5SGFuZGxlcnNbb3AuY3Vyc29yQWN0aXZpdHlDYWxsZWQrK10uY2FsbChudWxsLCBvcC5jbSk7IH0gfVxuICAgICAgfVxuICAgIH0gd2hpbGUgKGkgPCBjYWxsYmFja3MubGVuZ3RoKVxuICB9XG5cbiAgZnVuY3Rpb24gZmluaXNoT3BlcmF0aW9uKG9wLCBlbmRDYikge1xuICAgIHZhciBncm91cCA9IG9wLm93bnNHcm91cDtcbiAgICBpZiAoIWdyb3VwKSB7IHJldHVybiB9XG5cbiAgICB0cnkgeyBmaXJlQ2FsbGJhY2tzRm9yT3BzKGdyb3VwKTsgfVxuICAgIGZpbmFsbHkge1xuICAgICAgb3BlcmF0aW9uR3JvdXAgPSBudWxsO1xuICAgICAgZW5kQ2IoZ3JvdXApO1xuICAgIH1cbiAgfVxuXG4gIHZhciBvcnBoYW5EZWxheWVkQ2FsbGJhY2tzID0gbnVsbDtcblxuICAvLyBPZnRlbiwgd2Ugd2FudCB0byBzaWduYWwgZXZlbnRzIGF0IGEgcG9pbnQgd2hlcmUgd2UgYXJlIGluIHRoZVxuICAvLyBtaWRkbGUgb2Ygc29tZSB3b3JrLCBidXQgZG9uJ3Qgd2FudCB0aGUgaGFuZGxlciB0byBzdGFydCBjYWxsaW5nXG4gIC8vIG90aGVyIG1ldGhvZHMgb24gdGhlIGVkaXRvciwgd2hpY2ggbWlnaHQgYmUgaW4gYW4gaW5jb25zaXN0ZW50XG4gIC8vIHN0YXRlIG9yIHNpbXBseSBub3QgZXhwZWN0IGFueSBvdGhlciBldmVudHMgdG8gaGFwcGVuLlxuICAvLyBzaWduYWxMYXRlciBsb29rcyB3aGV0aGVyIHRoZXJlIGFyZSBhbnkgaGFuZGxlcnMsIGFuZCBzY2hlZHVsZXNcbiAgLy8gdGhlbSB0byBiZSBleGVjdXRlZCB3aGVuIHRoZSBsYXN0IG9wZXJhdGlvbiBlbmRzLCBvciwgaWYgbm9cbiAgLy8gb3BlcmF0aW9uIGlzIGFjdGl2ZSwgd2hlbiBhIHRpbWVvdXQgZmlyZXMuXG4gIGZ1bmN0aW9uIHNpZ25hbExhdGVyKGVtaXR0ZXIsIHR5cGUgLyosIHZhbHVlcy4uLiovKSB7XG4gICAgdmFyIGFyciA9IGdldEhhbmRsZXJzKGVtaXR0ZXIsIHR5cGUpO1xuICAgIGlmICghYXJyLmxlbmd0aCkgeyByZXR1cm4gfVxuICAgIHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAyKSwgbGlzdDtcbiAgICBpZiAob3BlcmF0aW9uR3JvdXApIHtcbiAgICAgIGxpc3QgPSBvcGVyYXRpb25Hcm91cC5kZWxheWVkQ2FsbGJhY2tzO1xuICAgIH0gZWxzZSBpZiAob3JwaGFuRGVsYXllZENhbGxiYWNrcykge1xuICAgICAgbGlzdCA9IG9ycGhhbkRlbGF5ZWRDYWxsYmFja3M7XG4gICAgfSBlbHNlIHtcbiAgICAgIGxpc3QgPSBvcnBoYW5EZWxheWVkQ2FsbGJhY2tzID0gW107XG4gICAgICBzZXRUaW1lb3V0KGZpcmVPcnBoYW5EZWxheWVkLCAwKTtcbiAgICB9XG4gICAgdmFyIGxvb3AgPSBmdW5jdGlvbiAoIGkgKSB7XG4gICAgICBsaXN0LnB1c2goZnVuY3Rpb24gKCkgeyByZXR1cm4gYXJyW2ldLmFwcGx5KG51bGwsIGFyZ3MpOyB9KTtcbiAgICB9O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcnIubGVuZ3RoOyArK2kpXG4gICAgICBsb29wKCBpICk7XG4gIH1cblxuICBmdW5jdGlvbiBmaXJlT3JwaGFuRGVsYXllZCgpIHtcbiAgICB2YXIgZGVsYXllZCA9IG9ycGhhbkRlbGF5ZWRDYWxsYmFja3M7XG4gICAgb3JwaGFuRGVsYXllZENhbGxiYWNrcyA9IG51bGw7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkZWxheWVkLmxlbmd0aDsgKytpKSB7IGRlbGF5ZWRbaV0oKTsgfVxuICB9XG5cbiAgLy8gV2hlbiBhbiBhc3BlY3Qgb2YgYSBsaW5lIGNoYW5nZXMsIGEgc3RyaW5nIGlzIGFkZGVkIHRvXG4gIC8vIGxpbmVWaWV3LmNoYW5nZXMuIFRoaXMgdXBkYXRlcyB0aGUgcmVsZXZhbnQgcGFydCBvZiB0aGUgbGluZSdzXG4gIC8vIERPTSBzdHJ1Y3R1cmUuXG4gIGZ1bmN0aW9uIHVwZGF0ZUxpbmVGb3JDaGFuZ2VzKGNtLCBsaW5lVmlldywgbGluZU4sIGRpbXMpIHtcbiAgICBmb3IgKHZhciBqID0gMDsgaiA8IGxpbmVWaWV3LmNoYW5nZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgIHZhciB0eXBlID0gbGluZVZpZXcuY2hhbmdlc1tqXTtcbiAgICAgIGlmICh0eXBlID09IFwidGV4dFwiKSB7IHVwZGF0ZUxpbmVUZXh0KGNtLCBsaW5lVmlldyk7IH1cbiAgICAgIGVsc2UgaWYgKHR5cGUgPT0gXCJndXR0ZXJcIikgeyB1cGRhdGVMaW5lR3V0dGVyKGNtLCBsaW5lVmlldywgbGluZU4sIGRpbXMpOyB9XG4gICAgICBlbHNlIGlmICh0eXBlID09IFwiY2xhc3NcIikgeyB1cGRhdGVMaW5lQ2xhc3NlcyhjbSwgbGluZVZpZXcpOyB9XG4gICAgICBlbHNlIGlmICh0eXBlID09IFwid2lkZ2V0XCIpIHsgdXBkYXRlTGluZVdpZGdldHMoY20sIGxpbmVWaWV3LCBkaW1zKTsgfVxuICAgIH1cbiAgICBsaW5lVmlldy5jaGFuZ2VzID0gbnVsbDtcbiAgfVxuXG4gIC8vIExpbmVzIHdpdGggZ3V0dGVyIGVsZW1lbnRzLCB3aWRnZXRzIG9yIGEgYmFja2dyb3VuZCBjbGFzcyBuZWVkIHRvXG4gIC8vIGJlIHdyYXBwZWQsIGFuZCBoYXZlIHRoZSBleHRyYSBlbGVtZW50cyBhZGRlZCB0byB0aGUgd3JhcHBlciBkaXZcbiAgZnVuY3Rpb24gZW5zdXJlTGluZVdyYXBwZWQobGluZVZpZXcpIHtcbiAgICBpZiAobGluZVZpZXcubm9kZSA9PSBsaW5lVmlldy50ZXh0KSB7XG4gICAgICBsaW5lVmlldy5ub2RlID0gZWx0KFwiZGl2XCIsIG51bGwsIG51bGwsIFwicG9zaXRpb246IHJlbGF0aXZlXCIpO1xuICAgICAgaWYgKGxpbmVWaWV3LnRleHQucGFyZW50Tm9kZSlcbiAgICAgICAgeyBsaW5lVmlldy50ZXh0LnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGxpbmVWaWV3Lm5vZGUsIGxpbmVWaWV3LnRleHQpOyB9XG4gICAgICBsaW5lVmlldy5ub2RlLmFwcGVuZENoaWxkKGxpbmVWaWV3LnRleHQpO1xuICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCA4KSB7IGxpbmVWaWV3Lm5vZGUuc3R5bGUuekluZGV4ID0gMjsgfVxuICAgIH1cbiAgICByZXR1cm4gbGluZVZpZXcubm9kZVxuICB9XG5cbiAgZnVuY3Rpb24gdXBkYXRlTGluZUJhY2tncm91bmQoY20sIGxpbmVWaWV3KSB7XG4gICAgdmFyIGNscyA9IGxpbmVWaWV3LmJnQ2xhc3MgPyBsaW5lVmlldy5iZ0NsYXNzICsgXCIgXCIgKyAobGluZVZpZXcubGluZS5iZ0NsYXNzIHx8IFwiXCIpIDogbGluZVZpZXcubGluZS5iZ0NsYXNzO1xuICAgIGlmIChjbHMpIHsgY2xzICs9IFwiIENvZGVNaXJyb3ItbGluZWJhY2tncm91bmRcIjsgfVxuICAgIGlmIChsaW5lVmlldy5iYWNrZ3JvdW5kKSB7XG4gICAgICBpZiAoY2xzKSB7IGxpbmVWaWV3LmJhY2tncm91bmQuY2xhc3NOYW1lID0gY2xzOyB9XG4gICAgICBlbHNlIHsgbGluZVZpZXcuYmFja2dyb3VuZC5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGxpbmVWaWV3LmJhY2tncm91bmQpOyBsaW5lVmlldy5iYWNrZ3JvdW5kID0gbnVsbDsgfVxuICAgIH0gZWxzZSBpZiAoY2xzKSB7XG4gICAgICB2YXIgd3JhcCA9IGVuc3VyZUxpbmVXcmFwcGVkKGxpbmVWaWV3KTtcbiAgICAgIGxpbmVWaWV3LmJhY2tncm91bmQgPSB3cmFwLmluc2VydEJlZm9yZShlbHQoXCJkaXZcIiwgbnVsbCwgY2xzKSwgd3JhcC5maXJzdENoaWxkKTtcbiAgICAgIGNtLmRpc3BsYXkuaW5wdXQuc2V0VW5lZGl0YWJsZShsaW5lVmlldy5iYWNrZ3JvdW5kKTtcbiAgICB9XG4gIH1cblxuICAvLyBXcmFwcGVyIGFyb3VuZCBidWlsZExpbmVDb250ZW50IHdoaWNoIHdpbGwgcmV1c2UgdGhlIHN0cnVjdHVyZVxuICAvLyBpbiBkaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQgd2hlbiBwb3NzaWJsZS5cbiAgZnVuY3Rpb24gZ2V0TGluZUNvbnRlbnQoY20sIGxpbmVWaWV3KSB7XG4gICAgdmFyIGV4dCA9IGNtLmRpc3BsYXkuZXh0ZXJuYWxNZWFzdXJlZDtcbiAgICBpZiAoZXh0ICYmIGV4dC5saW5lID09IGxpbmVWaWV3LmxpbmUpIHtcbiAgICAgIGNtLmRpc3BsYXkuZXh0ZXJuYWxNZWFzdXJlZCA9IG51bGw7XG4gICAgICBsaW5lVmlldy5tZWFzdXJlID0gZXh0Lm1lYXN1cmU7XG4gICAgICByZXR1cm4gZXh0LmJ1aWx0XG4gICAgfVxuICAgIHJldHVybiBidWlsZExpbmVDb250ZW50KGNtLCBsaW5lVmlldylcbiAgfVxuXG4gIC8vIFJlZHJhdyB0aGUgbGluZSdzIHRleHQuIEludGVyYWN0cyB3aXRoIHRoZSBiYWNrZ3JvdW5kIGFuZCB0ZXh0XG4gIC8vIGNsYXNzZXMgYmVjYXVzZSB0aGUgbW9kZSBtYXkgb3V0cHV0IHRva2VucyB0aGF0IGluZmx1ZW5jZSB0aGVzZVxuICAvLyBjbGFzc2VzLlxuICBmdW5jdGlvbiB1cGRhdGVMaW5lVGV4dChjbSwgbGluZVZpZXcpIHtcbiAgICB2YXIgY2xzID0gbGluZVZpZXcudGV4dC5jbGFzc05hbWU7XG4gICAgdmFyIGJ1aWx0ID0gZ2V0TGluZUNvbnRlbnQoY20sIGxpbmVWaWV3KTtcbiAgICBpZiAobGluZVZpZXcudGV4dCA9PSBsaW5lVmlldy5ub2RlKSB7IGxpbmVWaWV3Lm5vZGUgPSBidWlsdC5wcmU7IH1cbiAgICBsaW5lVmlldy50ZXh0LnBhcmVudE5vZGUucmVwbGFjZUNoaWxkKGJ1aWx0LnByZSwgbGluZVZpZXcudGV4dCk7XG4gICAgbGluZVZpZXcudGV4dCA9IGJ1aWx0LnByZTtcbiAgICBpZiAoYnVpbHQuYmdDbGFzcyAhPSBsaW5lVmlldy5iZ0NsYXNzIHx8IGJ1aWx0LnRleHRDbGFzcyAhPSBsaW5lVmlldy50ZXh0Q2xhc3MpIHtcbiAgICAgIGxpbmVWaWV3LmJnQ2xhc3MgPSBidWlsdC5iZ0NsYXNzO1xuICAgICAgbGluZVZpZXcudGV4dENsYXNzID0gYnVpbHQudGV4dENsYXNzO1xuICAgICAgdXBkYXRlTGluZUNsYXNzZXMoY20sIGxpbmVWaWV3KTtcbiAgICB9IGVsc2UgaWYgKGNscykge1xuICAgICAgbGluZVZpZXcudGV4dC5jbGFzc05hbWUgPSBjbHM7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gdXBkYXRlTGluZUNsYXNzZXMoY20sIGxpbmVWaWV3KSB7XG4gICAgdXBkYXRlTGluZUJhY2tncm91bmQoY20sIGxpbmVWaWV3KTtcbiAgICBpZiAobGluZVZpZXcubGluZS53cmFwQ2xhc3MpXG4gICAgICB7IGVuc3VyZUxpbmVXcmFwcGVkKGxpbmVWaWV3KS5jbGFzc05hbWUgPSBsaW5lVmlldy5saW5lLndyYXBDbGFzczsgfVxuICAgIGVsc2UgaWYgKGxpbmVWaWV3Lm5vZGUgIT0gbGluZVZpZXcudGV4dClcbiAgICAgIHsgbGluZVZpZXcubm9kZS5jbGFzc05hbWUgPSBcIlwiOyB9XG4gICAgdmFyIHRleHRDbGFzcyA9IGxpbmVWaWV3LnRleHRDbGFzcyA/IGxpbmVWaWV3LnRleHRDbGFzcyArIFwiIFwiICsgKGxpbmVWaWV3LmxpbmUudGV4dENsYXNzIHx8IFwiXCIpIDogbGluZVZpZXcubGluZS50ZXh0Q2xhc3M7XG4gICAgbGluZVZpZXcudGV4dC5jbGFzc05hbWUgPSB0ZXh0Q2xhc3MgfHwgXCJcIjtcbiAgfVxuXG4gIGZ1bmN0aW9uIHVwZGF0ZUxpbmVHdXR0ZXIoY20sIGxpbmVWaWV3LCBsaW5lTiwgZGltcykge1xuICAgIGlmIChsaW5lVmlldy5ndXR0ZXIpIHtcbiAgICAgIGxpbmVWaWV3Lm5vZGUucmVtb3ZlQ2hpbGQobGluZVZpZXcuZ3V0dGVyKTtcbiAgICAgIGxpbmVWaWV3Lmd1dHRlciA9IG51bGw7XG4gICAgfVxuICAgIGlmIChsaW5lVmlldy5ndXR0ZXJCYWNrZ3JvdW5kKSB7XG4gICAgICBsaW5lVmlldy5ub2RlLnJlbW92ZUNoaWxkKGxpbmVWaWV3Lmd1dHRlckJhY2tncm91bmQpO1xuICAgICAgbGluZVZpZXcuZ3V0dGVyQmFja2dyb3VuZCA9IG51bGw7XG4gICAgfVxuICAgIGlmIChsaW5lVmlldy5saW5lLmd1dHRlckNsYXNzKSB7XG4gICAgICB2YXIgd3JhcCA9IGVuc3VyZUxpbmVXcmFwcGVkKGxpbmVWaWV3KTtcbiAgICAgIGxpbmVWaWV3Lmd1dHRlckJhY2tncm91bmQgPSBlbHQoXCJkaXZcIiwgbnVsbCwgXCJDb2RlTWlycm9yLWd1dHRlci1iYWNrZ3JvdW5kIFwiICsgbGluZVZpZXcubGluZS5ndXR0ZXJDbGFzcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKFwibGVmdDogXCIgKyAoY20ub3B0aW9ucy5maXhlZEd1dHRlciA/IGRpbXMuZml4ZWRQb3MgOiAtZGltcy5ndXR0ZXJUb3RhbFdpZHRoKSArIFwicHg7IHdpZHRoOiBcIiArIChkaW1zLmd1dHRlclRvdGFsV2lkdGgpICsgXCJweFwiKSk7XG4gICAgICBjbS5kaXNwbGF5LmlucHV0LnNldFVuZWRpdGFibGUobGluZVZpZXcuZ3V0dGVyQmFja2dyb3VuZCk7XG4gICAgICB3cmFwLmluc2VydEJlZm9yZShsaW5lVmlldy5ndXR0ZXJCYWNrZ3JvdW5kLCBsaW5lVmlldy50ZXh0KTtcbiAgICB9XG4gICAgdmFyIG1hcmtlcnMgPSBsaW5lVmlldy5saW5lLmd1dHRlck1hcmtlcnM7XG4gICAgaWYgKGNtLm9wdGlvbnMubGluZU51bWJlcnMgfHwgbWFya2Vycykge1xuICAgICAgdmFyIHdyYXAkMSA9IGVuc3VyZUxpbmVXcmFwcGVkKGxpbmVWaWV3KTtcbiAgICAgIHZhciBndXR0ZXJXcmFwID0gbGluZVZpZXcuZ3V0dGVyID0gZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1ndXR0ZXItd3JhcHBlclwiLCAoXCJsZWZ0OiBcIiArIChjbS5vcHRpb25zLmZpeGVkR3V0dGVyID8gZGltcy5maXhlZFBvcyA6IC1kaW1zLmd1dHRlclRvdGFsV2lkdGgpICsgXCJweFwiKSk7XG4gICAgICBjbS5kaXNwbGF5LmlucHV0LnNldFVuZWRpdGFibGUoZ3V0dGVyV3JhcCk7XG4gICAgICB3cmFwJDEuaW5zZXJ0QmVmb3JlKGd1dHRlcldyYXAsIGxpbmVWaWV3LnRleHQpO1xuICAgICAgaWYgKGxpbmVWaWV3LmxpbmUuZ3V0dGVyQ2xhc3MpXG4gICAgICAgIHsgZ3V0dGVyV3JhcC5jbGFzc05hbWUgKz0gXCIgXCIgKyBsaW5lVmlldy5saW5lLmd1dHRlckNsYXNzOyB9XG4gICAgICBpZiAoY20ub3B0aW9ucy5saW5lTnVtYmVycyAmJiAoIW1hcmtlcnMgfHwgIW1hcmtlcnNbXCJDb2RlTWlycm9yLWxpbmVudW1iZXJzXCJdKSlcbiAgICAgICAgeyBsaW5lVmlldy5saW5lTnVtYmVyID0gZ3V0dGVyV3JhcC5hcHBlbmRDaGlsZChcbiAgICAgICAgICBlbHQoXCJkaXZcIiwgbGluZU51bWJlckZvcihjbS5vcHRpb25zLCBsaW5lTiksXG4gICAgICAgICAgICAgIFwiQ29kZU1pcnJvci1saW5lbnVtYmVyIENvZGVNaXJyb3ItZ3V0dGVyLWVsdFwiLFxuICAgICAgICAgICAgICAoXCJsZWZ0OiBcIiArIChkaW1zLmd1dHRlckxlZnRbXCJDb2RlTWlycm9yLWxpbmVudW1iZXJzXCJdKSArIFwicHg7IHdpZHRoOiBcIiArIChjbS5kaXNwbGF5LmxpbmVOdW1Jbm5lcldpZHRoKSArIFwicHhcIikpKTsgfVxuICAgICAgaWYgKG1hcmtlcnMpIHsgZm9yICh2YXIgayA9IDA7IGsgPCBjbS5vcHRpb25zLmd1dHRlcnMubGVuZ3RoOyArK2spIHtcbiAgICAgICAgdmFyIGlkID0gY20ub3B0aW9ucy5ndXR0ZXJzW2tdLCBmb3VuZCA9IG1hcmtlcnMuaGFzT3duUHJvcGVydHkoaWQpICYmIG1hcmtlcnNbaWRdO1xuICAgICAgICBpZiAoZm91bmQpXG4gICAgICAgICAgeyBndXR0ZXJXcmFwLmFwcGVuZENoaWxkKGVsdChcImRpdlwiLCBbZm91bmRdLCBcIkNvZGVNaXJyb3ItZ3V0dGVyLWVsdFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChcImxlZnQ6IFwiICsgKGRpbXMuZ3V0dGVyTGVmdFtpZF0pICsgXCJweDsgd2lkdGg6IFwiICsgKGRpbXMuZ3V0dGVyV2lkdGhbaWRdKSArIFwicHhcIikpKTsgfVxuICAgICAgfSB9XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gdXBkYXRlTGluZVdpZGdldHMoY20sIGxpbmVWaWV3LCBkaW1zKSB7XG4gICAgaWYgKGxpbmVWaWV3LmFsaWduYWJsZSkgeyBsaW5lVmlldy5hbGlnbmFibGUgPSBudWxsOyB9XG4gICAgZm9yICh2YXIgbm9kZSA9IGxpbmVWaWV3Lm5vZGUuZmlyc3RDaGlsZCwgbmV4dCA9ICh2b2lkIDApOyBub2RlOyBub2RlID0gbmV4dCkge1xuICAgICAgbmV4dCA9IG5vZGUubmV4dFNpYmxpbmc7XG4gICAgICBpZiAobm9kZS5jbGFzc05hbWUgPT0gXCJDb2RlTWlycm9yLWxpbmV3aWRnZXRcIilcbiAgICAgICAgeyBsaW5lVmlldy5ub2RlLnJlbW92ZUNoaWxkKG5vZGUpOyB9XG4gICAgfVxuICAgIGluc2VydExpbmVXaWRnZXRzKGNtLCBsaW5lVmlldywgZGltcyk7XG4gIH1cblxuICAvLyBCdWlsZCBhIGxpbmUncyBET00gcmVwcmVzZW50YXRpb24gZnJvbSBzY3JhdGNoXG4gIGZ1bmN0aW9uIGJ1aWxkTGluZUVsZW1lbnQoY20sIGxpbmVWaWV3LCBsaW5lTiwgZGltcykge1xuICAgIHZhciBidWlsdCA9IGdldExpbmVDb250ZW50KGNtLCBsaW5lVmlldyk7XG4gICAgbGluZVZpZXcudGV4dCA9IGxpbmVWaWV3Lm5vZGUgPSBidWlsdC5wcmU7XG4gICAgaWYgKGJ1aWx0LmJnQ2xhc3MpIHsgbGluZVZpZXcuYmdDbGFzcyA9IGJ1aWx0LmJnQ2xhc3M7IH1cbiAgICBpZiAoYnVpbHQudGV4dENsYXNzKSB7IGxpbmVWaWV3LnRleHRDbGFzcyA9IGJ1aWx0LnRleHRDbGFzczsgfVxuXG4gICAgdXBkYXRlTGluZUNsYXNzZXMoY20sIGxpbmVWaWV3KTtcbiAgICB1cGRhdGVMaW5lR3V0dGVyKGNtLCBsaW5lVmlldywgbGluZU4sIGRpbXMpO1xuICAgIGluc2VydExpbmVXaWRnZXRzKGNtLCBsaW5lVmlldywgZGltcyk7XG4gICAgcmV0dXJuIGxpbmVWaWV3Lm5vZGVcbiAgfVxuXG4gIC8vIEEgbGluZVZpZXcgbWF5IGNvbnRhaW4gbXVsdGlwbGUgbG9naWNhbCBsaW5lcyAod2hlbiBtZXJnZWQgYnlcbiAgLy8gY29sbGFwc2VkIHNwYW5zKS4gVGhlIHdpZGdldHMgZm9yIGFsbCBvZiB0aGVtIG5lZWQgdG8gYmUgZHJhd24uXG4gIGZ1bmN0aW9uIGluc2VydExpbmVXaWRnZXRzKGNtLCBsaW5lVmlldywgZGltcykge1xuICAgIGluc2VydExpbmVXaWRnZXRzRm9yKGNtLCBsaW5lVmlldy5saW5lLCBsaW5lVmlldywgZGltcywgdHJ1ZSk7XG4gICAgaWYgKGxpbmVWaWV3LnJlc3QpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lVmlldy5yZXN0Lmxlbmd0aDsgaSsrKVxuICAgICAgeyBpbnNlcnRMaW5lV2lkZ2V0c0ZvcihjbSwgbGluZVZpZXcucmVzdFtpXSwgbGluZVZpZXcsIGRpbXMsIGZhbHNlKTsgfSB9XG4gIH1cblxuICBmdW5jdGlvbiBpbnNlcnRMaW5lV2lkZ2V0c0ZvcihjbSwgbGluZSwgbGluZVZpZXcsIGRpbXMsIGFsbG93QWJvdmUpIHtcbiAgICBpZiAoIWxpbmUud2lkZ2V0cykgeyByZXR1cm4gfVxuICAgIHZhciB3cmFwID0gZW5zdXJlTGluZVdyYXBwZWQobGluZVZpZXcpO1xuICAgIGZvciAodmFyIGkgPSAwLCB3cyA9IGxpbmUud2lkZ2V0czsgaSA8IHdzLmxlbmd0aDsgKytpKSB7XG4gICAgICB2YXIgd2lkZ2V0ID0gd3NbaV0sIG5vZGUgPSBlbHQoXCJkaXZcIiwgW3dpZGdldC5ub2RlXSwgXCJDb2RlTWlycm9yLWxpbmV3aWRnZXRcIik7XG4gICAgICBpZiAoIXdpZGdldC5oYW5kbGVNb3VzZUV2ZW50cykgeyBub2RlLnNldEF0dHJpYnV0ZShcImNtLWlnbm9yZS1ldmVudHNcIiwgXCJ0cnVlXCIpOyB9XG4gICAgICBwb3NpdGlvbkxpbmVXaWRnZXQod2lkZ2V0LCBub2RlLCBsaW5lVmlldywgZGltcyk7XG4gICAgICBjbS5kaXNwbGF5LmlucHV0LnNldFVuZWRpdGFibGUobm9kZSk7XG4gICAgICBpZiAoYWxsb3dBYm92ZSAmJiB3aWRnZXQuYWJvdmUpXG4gICAgICAgIHsgd3JhcC5pbnNlcnRCZWZvcmUobm9kZSwgbGluZVZpZXcuZ3V0dGVyIHx8IGxpbmVWaWV3LnRleHQpOyB9XG4gICAgICBlbHNlXG4gICAgICAgIHsgd3JhcC5hcHBlbmRDaGlsZChub2RlKTsgfVxuICAgICAgc2lnbmFsTGF0ZXIod2lkZ2V0LCBcInJlZHJhd1wiKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBwb3NpdGlvbkxpbmVXaWRnZXQod2lkZ2V0LCBub2RlLCBsaW5lVmlldywgZGltcykge1xuICAgIGlmICh3aWRnZXQubm9IU2Nyb2xsKSB7XG4gIChsaW5lVmlldy5hbGlnbmFibGUgfHwgKGxpbmVWaWV3LmFsaWduYWJsZSA9IFtdKSkucHVzaChub2RlKTtcbiAgICAgIHZhciB3aWR0aCA9IGRpbXMud3JhcHBlcldpZHRoO1xuICAgICAgbm9kZS5zdHlsZS5sZWZ0ID0gZGltcy5maXhlZFBvcyArIFwicHhcIjtcbiAgICAgIGlmICghd2lkZ2V0LmNvdmVyR3V0dGVyKSB7XG4gICAgICAgIHdpZHRoIC09IGRpbXMuZ3V0dGVyVG90YWxXaWR0aDtcbiAgICAgICAgbm9kZS5zdHlsZS5wYWRkaW5nTGVmdCA9IGRpbXMuZ3V0dGVyVG90YWxXaWR0aCArIFwicHhcIjtcbiAgICAgIH1cbiAgICAgIG5vZGUuc3R5bGUud2lkdGggPSB3aWR0aCArIFwicHhcIjtcbiAgICB9XG4gICAgaWYgKHdpZGdldC5jb3Zlckd1dHRlcikge1xuICAgICAgbm9kZS5zdHlsZS56SW5kZXggPSA1O1xuICAgICAgbm9kZS5zdHlsZS5wb3NpdGlvbiA9IFwicmVsYXRpdmVcIjtcbiAgICAgIGlmICghd2lkZ2V0Lm5vSFNjcm9sbCkgeyBub2RlLnN0eWxlLm1hcmdpbkxlZnQgPSAtZGltcy5ndXR0ZXJUb3RhbFdpZHRoICsgXCJweFwiOyB9XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gd2lkZ2V0SGVpZ2h0KHdpZGdldCkge1xuICAgIGlmICh3aWRnZXQuaGVpZ2h0ICE9IG51bGwpIHsgcmV0dXJuIHdpZGdldC5oZWlnaHQgfVxuICAgIHZhciBjbSA9IHdpZGdldC5kb2MuY207XG4gICAgaWYgKCFjbSkgeyByZXR1cm4gMCB9XG4gICAgaWYgKCFjb250YWlucyhkb2N1bWVudC5ib2R5LCB3aWRnZXQubm9kZSkpIHtcbiAgICAgIHZhciBwYXJlbnRTdHlsZSA9IFwicG9zaXRpb246IHJlbGF0aXZlO1wiO1xuICAgICAgaWYgKHdpZGdldC5jb3Zlckd1dHRlcilcbiAgICAgICAgeyBwYXJlbnRTdHlsZSArPSBcIm1hcmdpbi1sZWZ0OiAtXCIgKyBjbS5kaXNwbGF5Lmd1dHRlcnMub2Zmc2V0V2lkdGggKyBcInB4O1wiOyB9XG4gICAgICBpZiAod2lkZ2V0Lm5vSFNjcm9sbClcbiAgICAgICAgeyBwYXJlbnRTdHlsZSArPSBcIndpZHRoOiBcIiArIGNtLmRpc3BsYXkud3JhcHBlci5jbGllbnRXaWR0aCArIFwicHg7XCI7IH1cbiAgICAgIHJlbW92ZUNoaWxkcmVuQW5kQWRkKGNtLmRpc3BsYXkubWVhc3VyZSwgZWx0KFwiZGl2XCIsIFt3aWRnZXQubm9kZV0sIG51bGwsIHBhcmVudFN0eWxlKSk7XG4gICAgfVxuICAgIHJldHVybiB3aWRnZXQuaGVpZ2h0ID0gd2lkZ2V0Lm5vZGUucGFyZW50Tm9kZS5vZmZzZXRIZWlnaHRcbiAgfVxuXG4gIC8vIFJldHVybiB0cnVlIHdoZW4gdGhlIGdpdmVuIG1vdXNlIGV2ZW50IGhhcHBlbmVkIGluIGEgd2lkZ2V0XG4gIGZ1bmN0aW9uIGV2ZW50SW5XaWRnZXQoZGlzcGxheSwgZSkge1xuICAgIGZvciAodmFyIG4gPSBlX3RhcmdldChlKTsgbiAhPSBkaXNwbGF5LndyYXBwZXI7IG4gPSBuLnBhcmVudE5vZGUpIHtcbiAgICAgIGlmICghbiB8fCAobi5ub2RlVHlwZSA9PSAxICYmIG4uZ2V0QXR0cmlidXRlKFwiY20taWdub3JlLWV2ZW50c1wiKSA9PSBcInRydWVcIikgfHxcbiAgICAgICAgICAobi5wYXJlbnROb2RlID09IGRpc3BsYXkuc2l6ZXIgJiYgbiAhPSBkaXNwbGF5Lm1vdmVyKSlcbiAgICAgICAgeyByZXR1cm4gdHJ1ZSB9XG4gICAgfVxuICB9XG5cbiAgLy8gUE9TSVRJT04gTUVBU1VSRU1FTlRcblxuICBmdW5jdGlvbiBwYWRkaW5nVG9wKGRpc3BsYXkpIHtyZXR1cm4gZGlzcGxheS5saW5lU3BhY2Uub2Zmc2V0VG9wfVxuICBmdW5jdGlvbiBwYWRkaW5nVmVydChkaXNwbGF5KSB7cmV0dXJuIGRpc3BsYXkubW92ZXIub2Zmc2V0SGVpZ2h0IC0gZGlzcGxheS5saW5lU3BhY2Uub2Zmc2V0SGVpZ2h0fVxuICBmdW5jdGlvbiBwYWRkaW5nSChkaXNwbGF5KSB7XG4gICAgaWYgKGRpc3BsYXkuY2FjaGVkUGFkZGluZ0gpIHsgcmV0dXJuIGRpc3BsYXkuY2FjaGVkUGFkZGluZ0ggfVxuICAgIHZhciBlID0gcmVtb3ZlQ2hpbGRyZW5BbmRBZGQoZGlzcGxheS5tZWFzdXJlLCBlbHQoXCJwcmVcIiwgXCJ4XCIpKTtcbiAgICB2YXIgc3R5bGUgPSB3aW5kb3cuZ2V0Q29tcHV0ZWRTdHlsZSA/IHdpbmRvdy5nZXRDb21wdXRlZFN0eWxlKGUpIDogZS5jdXJyZW50U3R5bGU7XG4gICAgdmFyIGRhdGEgPSB7bGVmdDogcGFyc2VJbnQoc3R5bGUucGFkZGluZ0xlZnQpLCByaWdodDogcGFyc2VJbnQoc3R5bGUucGFkZGluZ1JpZ2h0KX07XG4gICAgaWYgKCFpc05hTihkYXRhLmxlZnQpICYmICFpc05hTihkYXRhLnJpZ2h0KSkgeyBkaXNwbGF5LmNhY2hlZFBhZGRpbmdIID0gZGF0YTsgfVxuICAgIHJldHVybiBkYXRhXG4gIH1cblxuICBmdW5jdGlvbiBzY3JvbGxHYXAoY20pIHsgcmV0dXJuIHNjcm9sbGVyR2FwIC0gY20uZGlzcGxheS5uYXRpdmVCYXJXaWR0aCB9XG4gIGZ1bmN0aW9uIGRpc3BsYXlXaWR0aChjbSkge1xuICAgIHJldHVybiBjbS5kaXNwbGF5LnNjcm9sbGVyLmNsaWVudFdpZHRoIC0gc2Nyb2xsR2FwKGNtKSAtIGNtLmRpc3BsYXkuYmFyV2lkdGhcbiAgfVxuICBmdW5jdGlvbiBkaXNwbGF5SGVpZ2h0KGNtKSB7XG4gICAgcmV0dXJuIGNtLmRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50SGVpZ2h0IC0gc2Nyb2xsR2FwKGNtKSAtIGNtLmRpc3BsYXkuYmFySGVpZ2h0XG4gIH1cblxuICAvLyBFbnN1cmUgdGhlIGxpbmVWaWV3LndyYXBwaW5nLmhlaWdodHMgYXJyYXkgaXMgcG9wdWxhdGVkLiBUaGlzIGlzXG4gIC8vIGFuIGFycmF5IG9mIGJvdHRvbSBvZmZzZXRzIGZvciB0aGUgbGluZXMgdGhhdCBtYWtlIHVwIGEgZHJhd25cbiAgLy8gbGluZS4gV2hlbiBsaW5lV3JhcHBpbmcgaXMgb24sIHRoZXJlIG1pZ2h0IGJlIG1vcmUgdGhhbiBvbmVcbiAgLy8gaGVpZ2h0LlxuICBmdW5jdGlvbiBlbnN1cmVMaW5lSGVpZ2h0cyhjbSwgbGluZVZpZXcsIHJlY3QpIHtcbiAgICB2YXIgd3JhcHBpbmcgPSBjbS5vcHRpb25zLmxpbmVXcmFwcGluZztcbiAgICB2YXIgY3VyV2lkdGggPSB3cmFwcGluZyAmJiBkaXNwbGF5V2lkdGgoY20pO1xuICAgIGlmICghbGluZVZpZXcubWVhc3VyZS5oZWlnaHRzIHx8IHdyYXBwaW5nICYmIGxpbmVWaWV3Lm1lYXN1cmUud2lkdGggIT0gY3VyV2lkdGgpIHtcbiAgICAgIHZhciBoZWlnaHRzID0gbGluZVZpZXcubWVhc3VyZS5oZWlnaHRzID0gW107XG4gICAgICBpZiAod3JhcHBpbmcpIHtcbiAgICAgICAgbGluZVZpZXcubWVhc3VyZS53aWR0aCA9IGN1cldpZHRoO1xuICAgICAgICB2YXIgcmVjdHMgPSBsaW5lVmlldy50ZXh0LmZpcnN0Q2hpbGQuZ2V0Q2xpZW50UmVjdHMoKTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZWN0cy5sZW5ndGggLSAxOyBpKyspIHtcbiAgICAgICAgICB2YXIgY3VyID0gcmVjdHNbaV0sIG5leHQgPSByZWN0c1tpICsgMV07XG4gICAgICAgICAgaWYgKE1hdGguYWJzKGN1ci5ib3R0b20gLSBuZXh0LmJvdHRvbSkgPiAyKVxuICAgICAgICAgICAgeyBoZWlnaHRzLnB1c2goKGN1ci5ib3R0b20gKyBuZXh0LnRvcCkgLyAyIC0gcmVjdC50b3ApOyB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGhlaWdodHMucHVzaChyZWN0LmJvdHRvbSAtIHJlY3QudG9wKTtcbiAgICB9XG4gIH1cblxuICAvLyBGaW5kIGEgbGluZSBtYXAgKG1hcHBpbmcgY2hhcmFjdGVyIG9mZnNldHMgdG8gdGV4dCBub2RlcykgYW5kIGFcbiAgLy8gbWVhc3VyZW1lbnQgY2FjaGUgZm9yIHRoZSBnaXZlbiBsaW5lIG51bWJlci4gKEEgbGluZSB2aWV3IG1pZ2h0XG4gIC8vIGNvbnRhaW4gbXVsdGlwbGUgbGluZXMgd2hlbiBjb2xsYXBzZWQgcmFuZ2VzIGFyZSBwcmVzZW50LilcbiAgZnVuY3Rpb24gbWFwRnJvbUxpbmVWaWV3KGxpbmVWaWV3LCBsaW5lLCBsaW5lTikge1xuICAgIGlmIChsaW5lVmlldy5saW5lID09IGxpbmUpXG4gICAgICB7IHJldHVybiB7bWFwOiBsaW5lVmlldy5tZWFzdXJlLm1hcCwgY2FjaGU6IGxpbmVWaWV3Lm1lYXN1cmUuY2FjaGV9IH1cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVWaWV3LnJlc3QubGVuZ3RoOyBpKyspXG4gICAgICB7IGlmIChsaW5lVmlldy5yZXN0W2ldID09IGxpbmUpXG4gICAgICAgIHsgcmV0dXJuIHttYXA6IGxpbmVWaWV3Lm1lYXN1cmUubWFwc1tpXSwgY2FjaGU6IGxpbmVWaWV3Lm1lYXN1cmUuY2FjaGVzW2ldfSB9IH1cbiAgICBmb3IgKHZhciBpJDEgPSAwOyBpJDEgPCBsaW5lVmlldy5yZXN0Lmxlbmd0aDsgaSQxKyspXG4gICAgICB7IGlmIChsaW5lTm8obGluZVZpZXcucmVzdFtpJDFdKSA+IGxpbmVOKVxuICAgICAgICB7IHJldHVybiB7bWFwOiBsaW5lVmlldy5tZWFzdXJlLm1hcHNbaSQxXSwgY2FjaGU6IGxpbmVWaWV3Lm1lYXN1cmUuY2FjaGVzW2kkMV0sIGJlZm9yZTogdHJ1ZX0gfSB9XG4gIH1cblxuICAvLyBSZW5kZXIgYSBsaW5lIGludG8gdGhlIGhpZGRlbiBub2RlIGRpc3BsYXkuZXh0ZXJuYWxNZWFzdXJlZC4gVXNlZFxuICAvLyB3aGVuIG1lYXN1cmVtZW50IGlzIG5lZWRlZCBmb3IgYSBsaW5lIHRoYXQncyBub3QgaW4gdGhlIHZpZXdwb3J0LlxuICBmdW5jdGlvbiB1cGRhdGVFeHRlcm5hbE1lYXN1cmVtZW50KGNtLCBsaW5lKSB7XG4gICAgbGluZSA9IHZpc3VhbExpbmUobGluZSk7XG4gICAgdmFyIGxpbmVOID0gbGluZU5vKGxpbmUpO1xuICAgIHZhciB2aWV3ID0gY20uZGlzcGxheS5leHRlcm5hbE1lYXN1cmVkID0gbmV3IExpbmVWaWV3KGNtLmRvYywgbGluZSwgbGluZU4pO1xuICAgIHZpZXcubGluZU4gPSBsaW5lTjtcbiAgICB2YXIgYnVpbHQgPSB2aWV3LmJ1aWx0ID0gYnVpbGRMaW5lQ29udGVudChjbSwgdmlldyk7XG4gICAgdmlldy50ZXh0ID0gYnVpbHQucHJlO1xuICAgIHJlbW92ZUNoaWxkcmVuQW5kQWRkKGNtLmRpc3BsYXkubGluZU1lYXN1cmUsIGJ1aWx0LnByZSk7XG4gICAgcmV0dXJuIHZpZXdcbiAgfVxuXG4gIC8vIEdldCBhIHt0b3AsIGJvdHRvbSwgbGVmdCwgcmlnaHR9IGJveCAoaW4gbGluZS1sb2NhbCBjb29yZGluYXRlcylcbiAgLy8gZm9yIGEgZ2l2ZW4gY2hhcmFjdGVyLlxuICBmdW5jdGlvbiBtZWFzdXJlQ2hhcihjbSwgbGluZSwgY2gsIGJpYXMpIHtcbiAgICByZXR1cm4gbWVhc3VyZUNoYXJQcmVwYXJlZChjbSwgcHJlcGFyZU1lYXN1cmVGb3JMaW5lKGNtLCBsaW5lKSwgY2gsIGJpYXMpXG4gIH1cblxuICAvLyBGaW5kIGEgbGluZSB2aWV3IHRoYXQgY29ycmVzcG9uZHMgdG8gdGhlIGdpdmVuIGxpbmUgbnVtYmVyLlxuICBmdW5jdGlvbiBmaW5kVmlld0ZvckxpbmUoY20sIGxpbmVOKSB7XG4gICAgaWYgKGxpbmVOID49IGNtLmRpc3BsYXkudmlld0Zyb20gJiYgbGluZU4gPCBjbS5kaXNwbGF5LnZpZXdUbylcbiAgICAgIHsgcmV0dXJuIGNtLmRpc3BsYXkudmlld1tmaW5kVmlld0luZGV4KGNtLCBsaW5lTildIH1cbiAgICB2YXIgZXh0ID0gY20uZGlzcGxheS5leHRlcm5hbE1lYXN1cmVkO1xuICAgIGlmIChleHQgJiYgbGluZU4gPj0gZXh0LmxpbmVOICYmIGxpbmVOIDwgZXh0LmxpbmVOICsgZXh0LnNpemUpXG4gICAgICB7IHJldHVybiBleHQgfVxuICB9XG5cbiAgLy8gTWVhc3VyZW1lbnQgY2FuIGJlIHNwbGl0IGluIHR3byBzdGVwcywgdGhlIHNldC11cCB3b3JrIHRoYXRcbiAgLy8gYXBwbGllcyB0byB0aGUgd2hvbGUgbGluZSwgYW5kIHRoZSBtZWFzdXJlbWVudCBvZiB0aGUgYWN0dWFsXG4gIC8vIGNoYXJhY3Rlci4gRnVuY3Rpb25zIGxpa2UgY29vcmRzQ2hhciwgdGhhdCBuZWVkIHRvIGRvIGEgbG90IG9mXG4gIC8vIG1lYXN1cmVtZW50cyBpbiBhIHJvdywgY2FuIHRodXMgZW5zdXJlIHRoYXQgdGhlIHNldC11cCB3b3JrIGlzXG4gIC8vIG9ubHkgZG9uZSBvbmNlLlxuICBmdW5jdGlvbiBwcmVwYXJlTWVhc3VyZUZvckxpbmUoY20sIGxpbmUpIHtcbiAgICB2YXIgbGluZU4gPSBsaW5lTm8obGluZSk7XG4gICAgdmFyIHZpZXcgPSBmaW5kVmlld0ZvckxpbmUoY20sIGxpbmVOKTtcbiAgICBpZiAodmlldyAmJiAhdmlldy50ZXh0KSB7XG4gICAgICB2aWV3ID0gbnVsbDtcbiAgICB9IGVsc2UgaWYgKHZpZXcgJiYgdmlldy5jaGFuZ2VzKSB7XG4gICAgICB1cGRhdGVMaW5lRm9yQ2hhbmdlcyhjbSwgdmlldywgbGluZU4sIGdldERpbWVuc2lvbnMoY20pKTtcbiAgICAgIGNtLmN1ck9wLmZvcmNlVXBkYXRlID0gdHJ1ZTtcbiAgICB9XG4gICAgaWYgKCF2aWV3KVxuICAgICAgeyB2aWV3ID0gdXBkYXRlRXh0ZXJuYWxNZWFzdXJlbWVudChjbSwgbGluZSk7IH1cblxuICAgIHZhciBpbmZvID0gbWFwRnJvbUxpbmVWaWV3KHZpZXcsIGxpbmUsIGxpbmVOKTtcbiAgICByZXR1cm4ge1xuICAgICAgbGluZTogbGluZSwgdmlldzogdmlldywgcmVjdDogbnVsbCxcbiAgICAgIG1hcDogaW5mby5tYXAsIGNhY2hlOiBpbmZvLmNhY2hlLCBiZWZvcmU6IGluZm8uYmVmb3JlLFxuICAgICAgaGFzSGVpZ2h0czogZmFsc2VcbiAgICB9XG4gIH1cblxuICAvLyBHaXZlbiBhIHByZXBhcmVkIG1lYXN1cmVtZW50IG9iamVjdCwgbWVhc3VyZXMgdGhlIHBvc2l0aW9uIG9mIGFuXG4gIC8vIGFjdHVhbCBjaGFyYWN0ZXIgKG9yIGZldGNoZXMgaXQgZnJvbSB0aGUgY2FjaGUpLlxuICBmdW5jdGlvbiBtZWFzdXJlQ2hhclByZXBhcmVkKGNtLCBwcmVwYXJlZCwgY2gsIGJpYXMsIHZhckhlaWdodCkge1xuICAgIGlmIChwcmVwYXJlZC5iZWZvcmUpIHsgY2ggPSAtMTsgfVxuICAgIHZhciBrZXkgPSBjaCArIChiaWFzIHx8IFwiXCIpLCBmb3VuZDtcbiAgICBpZiAocHJlcGFyZWQuY2FjaGUuaGFzT3duUHJvcGVydHkoa2V5KSkge1xuICAgICAgZm91bmQgPSBwcmVwYXJlZC5jYWNoZVtrZXldO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoIXByZXBhcmVkLnJlY3QpXG4gICAgICAgIHsgcHJlcGFyZWQucmVjdCA9IHByZXBhcmVkLnZpZXcudGV4dC5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTsgfVxuICAgICAgaWYgKCFwcmVwYXJlZC5oYXNIZWlnaHRzKSB7XG4gICAgICAgIGVuc3VyZUxpbmVIZWlnaHRzKGNtLCBwcmVwYXJlZC52aWV3LCBwcmVwYXJlZC5yZWN0KTtcbiAgICAgICAgcHJlcGFyZWQuaGFzSGVpZ2h0cyA9IHRydWU7XG4gICAgICB9XG4gICAgICBmb3VuZCA9IG1lYXN1cmVDaGFySW5uZXIoY20sIHByZXBhcmVkLCBjaCwgYmlhcyk7XG4gICAgICBpZiAoIWZvdW5kLmJvZ3VzKSB7IHByZXBhcmVkLmNhY2hlW2tleV0gPSBmb3VuZDsgfVxuICAgIH1cbiAgICByZXR1cm4ge2xlZnQ6IGZvdW5kLmxlZnQsIHJpZ2h0OiBmb3VuZC5yaWdodCxcbiAgICAgICAgICAgIHRvcDogdmFySGVpZ2h0ID8gZm91bmQucnRvcCA6IGZvdW5kLnRvcCxcbiAgICAgICAgICAgIGJvdHRvbTogdmFySGVpZ2h0ID8gZm91bmQucmJvdHRvbSA6IGZvdW5kLmJvdHRvbX1cbiAgfVxuXG4gIHZhciBudWxsUmVjdCA9IHtsZWZ0OiAwLCByaWdodDogMCwgdG9wOiAwLCBib3R0b206IDB9O1xuXG4gIGZ1bmN0aW9uIG5vZGVBbmRPZmZzZXRJbkxpbmVNYXAobWFwJCQxLCBjaCwgYmlhcykge1xuICAgIHZhciBub2RlLCBzdGFydCwgZW5kLCBjb2xsYXBzZSwgbVN0YXJ0LCBtRW5kO1xuICAgIC8vIEZpcnN0LCBzZWFyY2ggdGhlIGxpbmUgbWFwIGZvciB0aGUgdGV4dCBub2RlIGNvcnJlc3BvbmRpbmcgdG8sXG4gICAgLy8gb3IgY2xvc2VzdCB0bywgdGhlIHRhcmdldCBjaGFyYWN0ZXIuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtYXAkJDEubGVuZ3RoOyBpICs9IDMpIHtcbiAgICAgIG1TdGFydCA9IG1hcCQkMVtpXTtcbiAgICAgIG1FbmQgPSBtYXAkJDFbaSArIDFdO1xuICAgICAgaWYgKGNoIDwgbVN0YXJ0KSB7XG4gICAgICAgIHN0YXJ0ID0gMDsgZW5kID0gMTtcbiAgICAgICAgY29sbGFwc2UgPSBcImxlZnRcIjtcbiAgICAgIH0gZWxzZSBpZiAoY2ggPCBtRW5kKSB7XG4gICAgICAgIHN0YXJ0ID0gY2ggLSBtU3RhcnQ7XG4gICAgICAgIGVuZCA9IHN0YXJ0ICsgMTtcbiAgICAgIH0gZWxzZSBpZiAoaSA9PSBtYXAkJDEubGVuZ3RoIC0gMyB8fCBjaCA9PSBtRW5kICYmIG1hcCQkMVtpICsgM10gPiBjaCkge1xuICAgICAgICBlbmQgPSBtRW5kIC0gbVN0YXJ0O1xuICAgICAgICBzdGFydCA9IGVuZCAtIDE7XG4gICAgICAgIGlmIChjaCA+PSBtRW5kKSB7IGNvbGxhcHNlID0gXCJyaWdodFwiOyB9XG4gICAgICB9XG4gICAgICBpZiAoc3RhcnQgIT0gbnVsbCkge1xuICAgICAgICBub2RlID0gbWFwJCQxW2kgKyAyXTtcbiAgICAgICAgaWYgKG1TdGFydCA9PSBtRW5kICYmIGJpYXMgPT0gKG5vZGUuaW5zZXJ0TGVmdCA/IFwibGVmdFwiIDogXCJyaWdodFwiKSlcbiAgICAgICAgICB7IGNvbGxhcHNlID0gYmlhczsgfVxuICAgICAgICBpZiAoYmlhcyA9PSBcImxlZnRcIiAmJiBzdGFydCA9PSAwKVxuICAgICAgICAgIHsgd2hpbGUgKGkgJiYgbWFwJCQxW2kgLSAyXSA9PSBtYXAkJDFbaSAtIDNdICYmIG1hcCQkMVtpIC0gMV0uaW5zZXJ0TGVmdCkge1xuICAgICAgICAgICAgbm9kZSA9IG1hcCQkMVsoaSAtPSAzKSArIDJdO1xuICAgICAgICAgICAgY29sbGFwc2UgPSBcImxlZnRcIjtcbiAgICAgICAgICB9IH1cbiAgICAgICAgaWYgKGJpYXMgPT0gXCJyaWdodFwiICYmIHN0YXJ0ID09IG1FbmQgLSBtU3RhcnQpXG4gICAgICAgICAgeyB3aGlsZSAoaSA8IG1hcCQkMS5sZW5ndGggLSAzICYmIG1hcCQkMVtpICsgM10gPT0gbWFwJCQxW2kgKyA0XSAmJiAhbWFwJCQxW2kgKyA1XS5pbnNlcnRMZWZ0KSB7XG4gICAgICAgICAgICBub2RlID0gbWFwJCQxWyhpICs9IDMpICsgMl07XG4gICAgICAgICAgICBjb2xsYXBzZSA9IFwicmlnaHRcIjtcbiAgICAgICAgICB9IH1cbiAgICAgICAgYnJlYWtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHtub2RlOiBub2RlLCBzdGFydDogc3RhcnQsIGVuZDogZW5kLCBjb2xsYXBzZTogY29sbGFwc2UsIGNvdmVyU3RhcnQ6IG1TdGFydCwgY292ZXJFbmQ6IG1FbmR9XG4gIH1cblxuICBmdW5jdGlvbiBnZXRVc2VmdWxSZWN0KHJlY3RzLCBiaWFzKSB7XG4gICAgdmFyIHJlY3QgPSBudWxsUmVjdDtcbiAgICBpZiAoYmlhcyA9PSBcImxlZnRcIikgeyBmb3IgKHZhciBpID0gMDsgaSA8IHJlY3RzLmxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoKHJlY3QgPSByZWN0c1tpXSkubGVmdCAhPSByZWN0LnJpZ2h0KSB7IGJyZWFrIH1cbiAgICB9IH0gZWxzZSB7IGZvciAodmFyIGkkMSA9IHJlY3RzLmxlbmd0aCAtIDE7IGkkMSA+PSAwOyBpJDEtLSkge1xuICAgICAgaWYgKChyZWN0ID0gcmVjdHNbaSQxXSkubGVmdCAhPSByZWN0LnJpZ2h0KSB7IGJyZWFrIH1cbiAgICB9IH1cbiAgICByZXR1cm4gcmVjdFxuICB9XG5cbiAgZnVuY3Rpb24gbWVhc3VyZUNoYXJJbm5lcihjbSwgcHJlcGFyZWQsIGNoLCBiaWFzKSB7XG4gICAgdmFyIHBsYWNlID0gbm9kZUFuZE9mZnNldEluTGluZU1hcChwcmVwYXJlZC5tYXAsIGNoLCBiaWFzKTtcbiAgICB2YXIgbm9kZSA9IHBsYWNlLm5vZGUsIHN0YXJ0ID0gcGxhY2Uuc3RhcnQsIGVuZCA9IHBsYWNlLmVuZCwgY29sbGFwc2UgPSBwbGFjZS5jb2xsYXBzZTtcblxuICAgIHZhciByZWN0O1xuICAgIGlmIChub2RlLm5vZGVUeXBlID09IDMpIHsgLy8gSWYgaXQgaXMgYSB0ZXh0IG5vZGUsIHVzZSBhIHJhbmdlIHRvIHJldHJpZXZlIHRoZSBjb29yZGluYXRlcy5cbiAgICAgIGZvciAodmFyIGkkMSA9IDA7IGkkMSA8IDQ7IGkkMSsrKSB7IC8vIFJldHJ5IGEgbWF4aW11bSBvZiA0IHRpbWVzIHdoZW4gbm9uc2Vuc2UgcmVjdGFuZ2xlcyBhcmUgcmV0dXJuZWRcbiAgICAgICAgd2hpbGUgKHN0YXJ0ICYmIGlzRXh0ZW5kaW5nQ2hhcihwcmVwYXJlZC5saW5lLnRleHQuY2hhckF0KHBsYWNlLmNvdmVyU3RhcnQgKyBzdGFydCkpKSB7IC0tc3RhcnQ7IH1cbiAgICAgICAgd2hpbGUgKHBsYWNlLmNvdmVyU3RhcnQgKyBlbmQgPCBwbGFjZS5jb3ZlckVuZCAmJiBpc0V4dGVuZGluZ0NoYXIocHJlcGFyZWQubGluZS50ZXh0LmNoYXJBdChwbGFjZS5jb3ZlclN0YXJ0ICsgZW5kKSkpIHsgKytlbmQ7IH1cbiAgICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCA5ICYmIHN0YXJ0ID09IDAgJiYgZW5kID09IHBsYWNlLmNvdmVyRW5kIC0gcGxhY2UuY292ZXJTdGFydClcbiAgICAgICAgICB7IHJlY3QgPSBub2RlLnBhcmVudE5vZGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7IH1cbiAgICAgICAgZWxzZVxuICAgICAgICAgIHsgcmVjdCA9IGdldFVzZWZ1bFJlY3QocmFuZ2Uobm9kZSwgc3RhcnQsIGVuZCkuZ2V0Q2xpZW50UmVjdHMoKSwgYmlhcyk7IH1cbiAgICAgICAgaWYgKHJlY3QubGVmdCB8fCByZWN0LnJpZ2h0IHx8IHN0YXJ0ID09IDApIHsgYnJlYWsgfVxuICAgICAgICBlbmQgPSBzdGFydDtcbiAgICAgICAgc3RhcnQgPSBzdGFydCAtIDE7XG4gICAgICAgIGNvbGxhcHNlID0gXCJyaWdodFwiO1xuICAgICAgfVxuICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCAxMSkgeyByZWN0ID0gbWF5YmVVcGRhdGVSZWN0Rm9yWm9vbWluZyhjbS5kaXNwbGF5Lm1lYXN1cmUsIHJlY3QpOyB9XG4gICAgfSBlbHNlIHsgLy8gSWYgaXQgaXMgYSB3aWRnZXQsIHNpbXBseSBnZXQgdGhlIGJveCBmb3IgdGhlIHdob2xlIHdpZGdldC5cbiAgICAgIGlmIChzdGFydCA+IDApIHsgY29sbGFwc2UgPSBiaWFzID0gXCJyaWdodFwiOyB9XG4gICAgICB2YXIgcmVjdHM7XG4gICAgICBpZiAoY20ub3B0aW9ucy5saW5lV3JhcHBpbmcgJiYgKHJlY3RzID0gbm9kZS5nZXRDbGllbnRSZWN0cygpKS5sZW5ndGggPiAxKVxuICAgICAgICB7IHJlY3QgPSByZWN0c1tiaWFzID09IFwicmlnaHRcIiA/IHJlY3RzLmxlbmd0aCAtIDEgOiAwXTsgfVxuICAgICAgZWxzZVxuICAgICAgICB7IHJlY3QgPSBub2RlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpOyB9XG4gICAgfVxuICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgOSAmJiAhc3RhcnQgJiYgKCFyZWN0IHx8ICFyZWN0LmxlZnQgJiYgIXJlY3QucmlnaHQpKSB7XG4gICAgICB2YXIgclNwYW4gPSBub2RlLnBhcmVudE5vZGUuZ2V0Q2xpZW50UmVjdHMoKVswXTtcbiAgICAgIGlmIChyU3BhbilcbiAgICAgICAgeyByZWN0ID0ge2xlZnQ6IHJTcGFuLmxlZnQsIHJpZ2h0OiByU3Bhbi5sZWZ0ICsgY2hhcldpZHRoKGNtLmRpc3BsYXkpLCB0b3A6IHJTcGFuLnRvcCwgYm90dG9tOiByU3Bhbi5ib3R0b219OyB9XG4gICAgICBlbHNlXG4gICAgICAgIHsgcmVjdCA9IG51bGxSZWN0OyB9XG4gICAgfVxuXG4gICAgdmFyIHJ0b3AgPSByZWN0LnRvcCAtIHByZXBhcmVkLnJlY3QudG9wLCByYm90ID0gcmVjdC5ib3R0b20gLSBwcmVwYXJlZC5yZWN0LnRvcDtcbiAgICB2YXIgbWlkID0gKHJ0b3AgKyByYm90KSAvIDI7XG4gICAgdmFyIGhlaWdodHMgPSBwcmVwYXJlZC52aWV3Lm1lYXN1cmUuaGVpZ2h0cztcbiAgICB2YXIgaSA9IDA7XG4gICAgZm9yICg7IGkgPCBoZWlnaHRzLmxlbmd0aCAtIDE7IGkrKylcbiAgICAgIHsgaWYgKG1pZCA8IGhlaWdodHNbaV0pIHsgYnJlYWsgfSB9XG4gICAgdmFyIHRvcCA9IGkgPyBoZWlnaHRzW2kgLSAxXSA6IDAsIGJvdCA9IGhlaWdodHNbaV07XG4gICAgdmFyIHJlc3VsdCA9IHtsZWZ0OiAoY29sbGFwc2UgPT0gXCJyaWdodFwiID8gcmVjdC5yaWdodCA6IHJlY3QubGVmdCkgLSBwcmVwYXJlZC5yZWN0LmxlZnQsXG4gICAgICAgICAgICAgICAgICByaWdodDogKGNvbGxhcHNlID09IFwibGVmdFwiID8gcmVjdC5sZWZ0IDogcmVjdC5yaWdodCkgLSBwcmVwYXJlZC5yZWN0LmxlZnQsXG4gICAgICAgICAgICAgICAgICB0b3A6IHRvcCwgYm90dG9tOiBib3R9O1xuICAgIGlmICghcmVjdC5sZWZ0ICYmICFyZWN0LnJpZ2h0KSB7IHJlc3VsdC5ib2d1cyA9IHRydWU7IH1cbiAgICBpZiAoIWNtLm9wdGlvbnMuc2luZ2xlQ3Vyc29ySGVpZ2h0UGVyTGluZSkgeyByZXN1bHQucnRvcCA9IHJ0b3A7IHJlc3VsdC5yYm90dG9tID0gcmJvdDsgfVxuXG4gICAgcmV0dXJuIHJlc3VsdFxuICB9XG5cbiAgLy8gV29yayBhcm91bmQgcHJvYmxlbSB3aXRoIGJvdW5kaW5nIGNsaWVudCByZWN0cyBvbiByYW5nZXMgYmVpbmdcbiAgLy8gcmV0dXJuZWQgaW5jb3JyZWN0bHkgd2hlbiB6b29tZWQgb24gSUUxMCBhbmQgYmVsb3cuXG4gIGZ1bmN0aW9uIG1heWJlVXBkYXRlUmVjdEZvclpvb21pbmcobWVhc3VyZSwgcmVjdCkge1xuICAgIGlmICghd2luZG93LnNjcmVlbiB8fCBzY3JlZW4ubG9naWNhbFhEUEkgPT0gbnVsbCB8fFxuICAgICAgICBzY3JlZW4ubG9naWNhbFhEUEkgPT0gc2NyZWVuLmRldmljZVhEUEkgfHwgIWhhc0JhZFpvb21lZFJlY3RzKG1lYXN1cmUpKVxuICAgICAgeyByZXR1cm4gcmVjdCB9XG4gICAgdmFyIHNjYWxlWCA9IHNjcmVlbi5sb2dpY2FsWERQSSAvIHNjcmVlbi5kZXZpY2VYRFBJO1xuICAgIHZhciBzY2FsZVkgPSBzY3JlZW4ubG9naWNhbFlEUEkgLyBzY3JlZW4uZGV2aWNlWURQSTtcbiAgICByZXR1cm4ge2xlZnQ6IHJlY3QubGVmdCAqIHNjYWxlWCwgcmlnaHQ6IHJlY3QucmlnaHQgKiBzY2FsZVgsXG4gICAgICAgICAgICB0b3A6IHJlY3QudG9wICogc2NhbGVZLCBib3R0b206IHJlY3QuYm90dG9tICogc2NhbGVZfVxuICB9XG5cbiAgZnVuY3Rpb24gY2xlYXJMaW5lTWVhc3VyZW1lbnRDYWNoZUZvcihsaW5lVmlldykge1xuICAgIGlmIChsaW5lVmlldy5tZWFzdXJlKSB7XG4gICAgICBsaW5lVmlldy5tZWFzdXJlLmNhY2hlID0ge307XG4gICAgICBsaW5lVmlldy5tZWFzdXJlLmhlaWdodHMgPSBudWxsO1xuICAgICAgaWYgKGxpbmVWaWV3LnJlc3QpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lVmlldy5yZXN0Lmxlbmd0aDsgaSsrKVxuICAgICAgICB7IGxpbmVWaWV3Lm1lYXN1cmUuY2FjaGVzW2ldID0ge307IH0gfVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGNsZWFyTGluZU1lYXN1cmVtZW50Q2FjaGUoY20pIHtcbiAgICBjbS5kaXNwbGF5LmV4dGVybmFsTWVhc3VyZSA9IG51bGw7XG4gICAgcmVtb3ZlQ2hpbGRyZW4oY20uZGlzcGxheS5saW5lTWVhc3VyZSk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjbS5kaXNwbGF5LnZpZXcubGVuZ3RoOyBpKyspXG4gICAgICB7IGNsZWFyTGluZU1lYXN1cmVtZW50Q2FjaGVGb3IoY20uZGlzcGxheS52aWV3W2ldKTsgfVxuICB9XG5cbiAgZnVuY3Rpb24gY2xlYXJDYWNoZXMoY20pIHtcbiAgICBjbGVhckxpbmVNZWFzdXJlbWVudENhY2hlKGNtKTtcbiAgICBjbS5kaXNwbGF5LmNhY2hlZENoYXJXaWR0aCA9IGNtLmRpc3BsYXkuY2FjaGVkVGV4dEhlaWdodCA9IGNtLmRpc3BsYXkuY2FjaGVkUGFkZGluZ0ggPSBudWxsO1xuICAgIGlmICghY20ub3B0aW9ucy5saW5lV3JhcHBpbmcpIHsgY20uZGlzcGxheS5tYXhMaW5lQ2hhbmdlZCA9IHRydWU7IH1cbiAgICBjbS5kaXNwbGF5LmxpbmVOdW1DaGFycyA9IG51bGw7XG4gIH1cblxuICBmdW5jdGlvbiBwYWdlU2Nyb2xsWCgpIHtcbiAgICAvLyBXb3JrIGFyb3VuZCBodHRwczovL2J1Z3MuY2hyb21pdW0ub3JnL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD00ODkyMDZcbiAgICAvLyB3aGljaCBjYXVzZXMgcGFnZV9PZmZzZXQgYW5kIGJvdW5kaW5nIGNsaWVudCByZWN0cyB0byB1c2VcbiAgICAvLyBkaWZmZXJlbnQgcmVmZXJlbmNlIHZpZXdwb3J0cyBhbmQgaW52YWxpZGF0ZSBvdXIgY2FsY3VsYXRpb25zLlxuICAgIGlmIChjaHJvbWUgJiYgYW5kcm9pZCkgeyByZXR1cm4gLShkb2N1bWVudC5ib2R5LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLmxlZnQgLSBwYXJzZUludChnZXRDb21wdXRlZFN0eWxlKGRvY3VtZW50LmJvZHkpLm1hcmdpbkxlZnQpKSB9XG4gICAgcmV0dXJuIHdpbmRvdy5wYWdlWE9mZnNldCB8fCAoZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50IHx8IGRvY3VtZW50LmJvZHkpLnNjcm9sbExlZnRcbiAgfVxuICBmdW5jdGlvbiBwYWdlU2Nyb2xsWSgpIHtcbiAgICBpZiAoY2hyb21lICYmIGFuZHJvaWQpIHsgcmV0dXJuIC0oZG9jdW1lbnQuYm9keS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS50b3AgLSBwYXJzZUludChnZXRDb21wdXRlZFN0eWxlKGRvY3VtZW50LmJvZHkpLm1hcmdpblRvcCkpIH1cbiAgICByZXR1cm4gd2luZG93LnBhZ2VZT2Zmc2V0IHx8IChkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQgfHwgZG9jdW1lbnQuYm9keSkuc2Nyb2xsVG9wXG4gIH1cblxuICBmdW5jdGlvbiB3aWRnZXRUb3BIZWlnaHQobGluZU9iaikge1xuICAgIHZhciBoZWlnaHQgPSAwO1xuICAgIGlmIChsaW5lT2JqLndpZGdldHMpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lT2JqLndpZGdldHMubGVuZ3RoOyArK2kpIHsgaWYgKGxpbmVPYmoud2lkZ2V0c1tpXS5hYm92ZSlcbiAgICAgIHsgaGVpZ2h0ICs9IHdpZGdldEhlaWdodChsaW5lT2JqLndpZGdldHNbaV0pOyB9IH0gfVxuICAgIHJldHVybiBoZWlnaHRcbiAgfVxuXG4gIC8vIENvbnZlcnRzIGEge3RvcCwgYm90dG9tLCBsZWZ0LCByaWdodH0gYm94IGZyb20gbGluZS1sb2NhbFxuICAvLyBjb29yZGluYXRlcyBpbnRvIGFub3RoZXIgY29vcmRpbmF0ZSBzeXN0ZW0uIENvbnRleHQgbWF5IGJlIG9uZSBvZlxuICAvLyBcImxpbmVcIiwgXCJkaXZcIiAoZGlzcGxheS5saW5lRGl2KSwgXCJsb2NhbFwiLi9udWxsIChlZGl0b3IpLCBcIndpbmRvd1wiLFxuICAvLyBvciBcInBhZ2VcIi5cbiAgZnVuY3Rpb24gaW50b0Nvb3JkU3lzdGVtKGNtLCBsaW5lT2JqLCByZWN0LCBjb250ZXh0LCBpbmNsdWRlV2lkZ2V0cykge1xuICAgIGlmICghaW5jbHVkZVdpZGdldHMpIHtcbiAgICAgIHZhciBoZWlnaHQgPSB3aWRnZXRUb3BIZWlnaHQobGluZU9iaik7XG4gICAgICByZWN0LnRvcCArPSBoZWlnaHQ7IHJlY3QuYm90dG9tICs9IGhlaWdodDtcbiAgICB9XG4gICAgaWYgKGNvbnRleHQgPT0gXCJsaW5lXCIpIHsgcmV0dXJuIHJlY3QgfVxuICAgIGlmICghY29udGV4dCkgeyBjb250ZXh0ID0gXCJsb2NhbFwiOyB9XG4gICAgdmFyIHlPZmYgPSBoZWlnaHRBdExpbmUobGluZU9iaik7XG4gICAgaWYgKGNvbnRleHQgPT0gXCJsb2NhbFwiKSB7IHlPZmYgKz0gcGFkZGluZ1RvcChjbS5kaXNwbGF5KTsgfVxuICAgIGVsc2UgeyB5T2ZmIC09IGNtLmRpc3BsYXkudmlld09mZnNldDsgfVxuICAgIGlmIChjb250ZXh0ID09IFwicGFnZVwiIHx8IGNvbnRleHQgPT0gXCJ3aW5kb3dcIikge1xuICAgICAgdmFyIGxPZmYgPSBjbS5kaXNwbGF5LmxpbmVTcGFjZS5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKTtcbiAgICAgIHlPZmYgKz0gbE9mZi50b3AgKyAoY29udGV4dCA9PSBcIndpbmRvd1wiID8gMCA6IHBhZ2VTY3JvbGxZKCkpO1xuICAgICAgdmFyIHhPZmYgPSBsT2ZmLmxlZnQgKyAoY29udGV4dCA9PSBcIndpbmRvd1wiID8gMCA6IHBhZ2VTY3JvbGxYKCkpO1xuICAgICAgcmVjdC5sZWZ0ICs9IHhPZmY7IHJlY3QucmlnaHQgKz0geE9mZjtcbiAgICB9XG4gICAgcmVjdC50b3AgKz0geU9mZjsgcmVjdC5ib3R0b20gKz0geU9mZjtcbiAgICByZXR1cm4gcmVjdFxuICB9XG5cbiAgLy8gQ292ZXJ0cyBhIGJveCBmcm9tIFwiZGl2XCIgY29vcmRzIHRvIGFub3RoZXIgY29vcmRpbmF0ZSBzeXN0ZW0uXG4gIC8vIENvbnRleHQgbWF5IGJlIFwid2luZG93XCIsIFwicGFnZVwiLCBcImRpdlwiLCBvciBcImxvY2FsXCIuL251bGwuXG4gIGZ1bmN0aW9uIGZyb21Db29yZFN5c3RlbShjbSwgY29vcmRzLCBjb250ZXh0KSB7XG4gICAgaWYgKGNvbnRleHQgPT0gXCJkaXZcIikgeyByZXR1cm4gY29vcmRzIH1cbiAgICB2YXIgbGVmdCA9IGNvb3Jkcy5sZWZ0LCB0b3AgPSBjb29yZHMudG9wO1xuICAgIC8vIEZpcnN0IG1vdmUgaW50byBcInBhZ2VcIiBjb29yZGluYXRlIHN5c3RlbVxuICAgIGlmIChjb250ZXh0ID09IFwicGFnZVwiKSB7XG4gICAgICBsZWZ0IC09IHBhZ2VTY3JvbGxYKCk7XG4gICAgICB0b3AgLT0gcGFnZVNjcm9sbFkoKTtcbiAgICB9IGVsc2UgaWYgKGNvbnRleHQgPT0gXCJsb2NhbFwiIHx8ICFjb250ZXh0KSB7XG4gICAgICB2YXIgbG9jYWxCb3ggPSBjbS5kaXNwbGF5LnNpemVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgbGVmdCArPSBsb2NhbEJveC5sZWZ0O1xuICAgICAgdG9wICs9IGxvY2FsQm94LnRvcDtcbiAgICB9XG5cbiAgICB2YXIgbGluZVNwYWNlQm94ID0gY20uZGlzcGxheS5saW5lU3BhY2UuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgcmV0dXJuIHtsZWZ0OiBsZWZ0IC0gbGluZVNwYWNlQm94LmxlZnQsIHRvcDogdG9wIC0gbGluZVNwYWNlQm94LnRvcH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGNoYXJDb29yZHMoY20sIHBvcywgY29udGV4dCwgbGluZU9iaiwgYmlhcykge1xuICAgIGlmICghbGluZU9iaikgeyBsaW5lT2JqID0gZ2V0TGluZShjbS5kb2MsIHBvcy5saW5lKTsgfVxuICAgIHJldHVybiBpbnRvQ29vcmRTeXN0ZW0oY20sIGxpbmVPYmosIG1lYXN1cmVDaGFyKGNtLCBsaW5lT2JqLCBwb3MuY2gsIGJpYXMpLCBjb250ZXh0KVxuICB9XG5cbiAgLy8gUmV0dXJucyBhIGJveCBmb3IgYSBnaXZlbiBjdXJzb3IgcG9zaXRpb24sIHdoaWNoIG1heSBoYXZlIGFuXG4gIC8vICdvdGhlcicgcHJvcGVydHkgY29udGFpbmluZyB0aGUgcG9zaXRpb24gb2YgdGhlIHNlY29uZGFyeSBjdXJzb3JcbiAgLy8gb24gYSBiaWRpIGJvdW5kYXJ5LlxuICAvLyBBIGN1cnNvciBQb3MobGluZSwgY2hhciwgXCJiZWZvcmVcIikgaXMgb24gdGhlIHNhbWUgdmlzdWFsIGxpbmUgYXMgYGNoYXIgLSAxYFxuICAvLyBhbmQgYWZ0ZXIgYGNoYXIgLSAxYCBpbiB3cml0aW5nIG9yZGVyIG9mIGBjaGFyIC0gMWBcbiAgLy8gQSBjdXJzb3IgUG9zKGxpbmUsIGNoYXIsIFwiYWZ0ZXJcIikgaXMgb24gdGhlIHNhbWUgdmlzdWFsIGxpbmUgYXMgYGNoYXJgXG4gIC8vIGFuZCBiZWZvcmUgYGNoYXJgIGluIHdyaXRpbmcgb3JkZXIgb2YgYGNoYXJgXG4gIC8vIEV4YW1wbGVzICh1cHBlci1jYXNlIGxldHRlcnMgYXJlIFJUTCwgbG93ZXItY2FzZSBhcmUgTFRSKTpcbiAgLy8gICAgIFBvcygwLCAxLCAuLi4pXG4gIC8vICAgICBiZWZvcmUgICBhZnRlclxuICAvLyBhYiAgICAgYXxiICAgICBhfGJcbiAgLy8gYUIgICAgIGF8QiAgICAgYUJ8XG4gIC8vIEFiICAgICB8QWIgICAgIEF8YlxuICAvLyBBQiAgICAgQnxBICAgICBCfEFcbiAgLy8gRXZlcnkgcG9zaXRpb24gYWZ0ZXIgdGhlIGxhc3QgY2hhcmFjdGVyIG9uIGEgbGluZSBpcyBjb25zaWRlcmVkIHRvIHN0aWNrXG4gIC8vIHRvIHRoZSBsYXN0IGNoYXJhY3RlciBvbiB0aGUgbGluZS5cbiAgZnVuY3Rpb24gY3Vyc29yQ29vcmRzKGNtLCBwb3MsIGNvbnRleHQsIGxpbmVPYmosIHByZXBhcmVkTWVhc3VyZSwgdmFySGVpZ2h0KSB7XG4gICAgbGluZU9iaiA9IGxpbmVPYmogfHwgZ2V0TGluZShjbS5kb2MsIHBvcy5saW5lKTtcbiAgICBpZiAoIXByZXBhcmVkTWVhc3VyZSkgeyBwcmVwYXJlZE1lYXN1cmUgPSBwcmVwYXJlTWVhc3VyZUZvckxpbmUoY20sIGxpbmVPYmopOyB9XG4gICAgZnVuY3Rpb24gZ2V0KGNoLCByaWdodCkge1xuICAgICAgdmFyIG0gPSBtZWFzdXJlQ2hhclByZXBhcmVkKGNtLCBwcmVwYXJlZE1lYXN1cmUsIGNoLCByaWdodCA/IFwicmlnaHRcIiA6IFwibGVmdFwiLCB2YXJIZWlnaHQpO1xuICAgICAgaWYgKHJpZ2h0KSB7IG0ubGVmdCA9IG0ucmlnaHQ7IH0gZWxzZSB7IG0ucmlnaHQgPSBtLmxlZnQ7IH1cbiAgICAgIHJldHVybiBpbnRvQ29vcmRTeXN0ZW0oY20sIGxpbmVPYmosIG0sIGNvbnRleHQpXG4gICAgfVxuICAgIHZhciBvcmRlciA9IGdldE9yZGVyKGxpbmVPYmosIGNtLmRvYy5kaXJlY3Rpb24pLCBjaCA9IHBvcy5jaCwgc3RpY2t5ID0gcG9zLnN0aWNreTtcbiAgICBpZiAoY2ggPj0gbGluZU9iai50ZXh0Lmxlbmd0aCkge1xuICAgICAgY2ggPSBsaW5lT2JqLnRleHQubGVuZ3RoO1xuICAgICAgc3RpY2t5ID0gXCJiZWZvcmVcIjtcbiAgICB9IGVsc2UgaWYgKGNoIDw9IDApIHtcbiAgICAgIGNoID0gMDtcbiAgICAgIHN0aWNreSA9IFwiYWZ0ZXJcIjtcbiAgICB9XG4gICAgaWYgKCFvcmRlcikgeyByZXR1cm4gZ2V0KHN0aWNreSA9PSBcImJlZm9yZVwiID8gY2ggLSAxIDogY2gsIHN0aWNreSA9PSBcImJlZm9yZVwiKSB9XG5cbiAgICBmdW5jdGlvbiBnZXRCaWRpKGNoLCBwYXJ0UG9zLCBpbnZlcnQpIHtcbiAgICAgIHZhciBwYXJ0ID0gb3JkZXJbcGFydFBvc10sIHJpZ2h0ID0gcGFydC5sZXZlbCA9PSAxO1xuICAgICAgcmV0dXJuIGdldChpbnZlcnQgPyBjaCAtIDEgOiBjaCwgcmlnaHQgIT0gaW52ZXJ0KVxuICAgIH1cbiAgICB2YXIgcGFydFBvcyA9IGdldEJpZGlQYXJ0QXQob3JkZXIsIGNoLCBzdGlja3kpO1xuICAgIHZhciBvdGhlciA9IGJpZGlPdGhlcjtcbiAgICB2YXIgdmFsID0gZ2V0QmlkaShjaCwgcGFydFBvcywgc3RpY2t5ID09IFwiYmVmb3JlXCIpO1xuICAgIGlmIChvdGhlciAhPSBudWxsKSB7IHZhbC5vdGhlciA9IGdldEJpZGkoY2gsIG90aGVyLCBzdGlja3kgIT0gXCJiZWZvcmVcIik7IH1cbiAgICByZXR1cm4gdmFsXG4gIH1cblxuICAvLyBVc2VkIHRvIGNoZWFwbHkgZXN0aW1hdGUgdGhlIGNvb3JkaW5hdGVzIGZvciBhIHBvc2l0aW9uLiBVc2VkIGZvclxuICAvLyBpbnRlcm1lZGlhdGUgc2Nyb2xsIHVwZGF0ZXMuXG4gIGZ1bmN0aW9uIGVzdGltYXRlQ29vcmRzKGNtLCBwb3MpIHtcbiAgICB2YXIgbGVmdCA9IDA7XG4gICAgcG9zID0gY2xpcFBvcyhjbS5kb2MsIHBvcyk7XG4gICAgaWYgKCFjbS5vcHRpb25zLmxpbmVXcmFwcGluZykgeyBsZWZ0ID0gY2hhcldpZHRoKGNtLmRpc3BsYXkpICogcG9zLmNoOyB9XG4gICAgdmFyIGxpbmVPYmogPSBnZXRMaW5lKGNtLmRvYywgcG9zLmxpbmUpO1xuICAgIHZhciB0b3AgPSBoZWlnaHRBdExpbmUobGluZU9iaikgKyBwYWRkaW5nVG9wKGNtLmRpc3BsYXkpO1xuICAgIHJldHVybiB7bGVmdDogbGVmdCwgcmlnaHQ6IGxlZnQsIHRvcDogdG9wLCBib3R0b206IHRvcCArIGxpbmVPYmouaGVpZ2h0fVxuICB9XG5cbiAgLy8gUG9zaXRpb25zIHJldHVybmVkIGJ5IGNvb3Jkc0NoYXIgY29udGFpbiBzb21lIGV4dHJhIGluZm9ybWF0aW9uLlxuICAvLyB4UmVsIGlzIHRoZSByZWxhdGl2ZSB4IHBvc2l0aW9uIG9mIHRoZSBpbnB1dCBjb29yZGluYXRlcyBjb21wYXJlZFxuICAvLyB0byB0aGUgZm91bmQgcG9zaXRpb24gKHNvIHhSZWwgPiAwIG1lYW5zIHRoZSBjb29yZGluYXRlcyBhcmUgdG9cbiAgLy8gdGhlIHJpZ2h0IG9mIHRoZSBjaGFyYWN0ZXIgcG9zaXRpb24sIGZvciBleGFtcGxlKS4gV2hlbiBvdXRzaWRlXG4gIC8vIGlzIHRydWUsIHRoYXQgbWVhbnMgdGhlIGNvb3JkaW5hdGVzIGxpZSBvdXRzaWRlIHRoZSBsaW5lJ3NcbiAgLy8gdmVydGljYWwgcmFuZ2UuXG4gIGZ1bmN0aW9uIFBvc1dpdGhJbmZvKGxpbmUsIGNoLCBzdGlja3ksIG91dHNpZGUsIHhSZWwpIHtcbiAgICB2YXIgcG9zID0gUG9zKGxpbmUsIGNoLCBzdGlja3kpO1xuICAgIHBvcy54UmVsID0geFJlbDtcbiAgICBpZiAob3V0c2lkZSkgeyBwb3Mub3V0c2lkZSA9IHRydWU7IH1cbiAgICByZXR1cm4gcG9zXG4gIH1cblxuICAvLyBDb21wdXRlIHRoZSBjaGFyYWN0ZXIgcG9zaXRpb24gY2xvc2VzdCB0byB0aGUgZ2l2ZW4gY29vcmRpbmF0ZXMuXG4gIC8vIElucHV0IG11c3QgYmUgbGluZVNwYWNlLWxvY2FsIChcImRpdlwiIGNvb3JkaW5hdGUgc3lzdGVtKS5cbiAgZnVuY3Rpb24gY29vcmRzQ2hhcihjbSwgeCwgeSkge1xuICAgIHZhciBkb2MgPSBjbS5kb2M7XG4gICAgeSArPSBjbS5kaXNwbGF5LnZpZXdPZmZzZXQ7XG4gICAgaWYgKHkgPCAwKSB7IHJldHVybiBQb3NXaXRoSW5mbyhkb2MuZmlyc3QsIDAsIG51bGwsIHRydWUsIC0xKSB9XG4gICAgdmFyIGxpbmVOID0gbGluZUF0SGVpZ2h0KGRvYywgeSksIGxhc3QgPSBkb2MuZmlyc3QgKyBkb2Muc2l6ZSAtIDE7XG4gICAgaWYgKGxpbmVOID4gbGFzdClcbiAgICAgIHsgcmV0dXJuIFBvc1dpdGhJbmZvKGRvYy5maXJzdCArIGRvYy5zaXplIC0gMSwgZ2V0TGluZShkb2MsIGxhc3QpLnRleHQubGVuZ3RoLCBudWxsLCB0cnVlLCAxKSB9XG4gICAgaWYgKHggPCAwKSB7IHggPSAwOyB9XG5cbiAgICB2YXIgbGluZU9iaiA9IGdldExpbmUoZG9jLCBsaW5lTik7XG4gICAgZm9yICg7Oykge1xuICAgICAgdmFyIGZvdW5kID0gY29vcmRzQ2hhcklubmVyKGNtLCBsaW5lT2JqLCBsaW5lTiwgeCwgeSk7XG4gICAgICB2YXIgY29sbGFwc2VkID0gY29sbGFwc2VkU3BhbkFyb3VuZChsaW5lT2JqLCBmb3VuZC5jaCArIChmb3VuZC54UmVsID4gMCA/IDEgOiAwKSk7XG4gICAgICBpZiAoIWNvbGxhcHNlZCkgeyByZXR1cm4gZm91bmQgfVxuICAgICAgdmFyIHJhbmdlRW5kID0gY29sbGFwc2VkLmZpbmQoMSk7XG4gICAgICBpZiAocmFuZ2VFbmQubGluZSA9PSBsaW5lTikgeyByZXR1cm4gcmFuZ2VFbmQgfVxuICAgICAgbGluZU9iaiA9IGdldExpbmUoZG9jLCBsaW5lTiA9IHJhbmdlRW5kLmxpbmUpO1xuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHdyYXBwZWRMaW5lRXh0ZW50KGNtLCBsaW5lT2JqLCBwcmVwYXJlZE1lYXN1cmUsIHkpIHtcbiAgICB5IC09IHdpZGdldFRvcEhlaWdodChsaW5lT2JqKTtcbiAgICB2YXIgZW5kID0gbGluZU9iai50ZXh0Lmxlbmd0aDtcbiAgICB2YXIgYmVnaW4gPSBmaW5kRmlyc3QoZnVuY3Rpb24gKGNoKSB7IHJldHVybiBtZWFzdXJlQ2hhclByZXBhcmVkKGNtLCBwcmVwYXJlZE1lYXN1cmUsIGNoIC0gMSkuYm90dG9tIDw9IHk7IH0sIGVuZCwgMCk7XG4gICAgZW5kID0gZmluZEZpcnN0KGZ1bmN0aW9uIChjaCkgeyByZXR1cm4gbWVhc3VyZUNoYXJQcmVwYXJlZChjbSwgcHJlcGFyZWRNZWFzdXJlLCBjaCkudG9wID4geTsgfSwgYmVnaW4sIGVuZCk7XG4gICAgcmV0dXJuIHtiZWdpbjogYmVnaW4sIGVuZDogZW5kfVxuICB9XG5cbiAgZnVuY3Rpb24gd3JhcHBlZExpbmVFeHRlbnRDaGFyKGNtLCBsaW5lT2JqLCBwcmVwYXJlZE1lYXN1cmUsIHRhcmdldCkge1xuICAgIGlmICghcHJlcGFyZWRNZWFzdXJlKSB7IHByZXBhcmVkTWVhc3VyZSA9IHByZXBhcmVNZWFzdXJlRm9yTGluZShjbSwgbGluZU9iaik7IH1cbiAgICB2YXIgdGFyZ2V0VG9wID0gaW50b0Nvb3JkU3lzdGVtKGNtLCBsaW5lT2JqLCBtZWFzdXJlQ2hhclByZXBhcmVkKGNtLCBwcmVwYXJlZE1lYXN1cmUsIHRhcmdldCksIFwibGluZVwiKS50b3A7XG4gICAgcmV0dXJuIHdyYXBwZWRMaW5lRXh0ZW50KGNtLCBsaW5lT2JqLCBwcmVwYXJlZE1lYXN1cmUsIHRhcmdldFRvcClcbiAgfVxuXG4gIC8vIFJldHVybnMgdHJ1ZSBpZiB0aGUgZ2l2ZW4gc2lkZSBvZiBhIGJveCBpcyBhZnRlciB0aGUgZ2l2ZW5cbiAgLy8gY29vcmRpbmF0ZXMsIGluIHRvcC10by1ib3R0b20sIGxlZnQtdG8tcmlnaHQgb3JkZXIuXG4gIGZ1bmN0aW9uIGJveElzQWZ0ZXIoYm94LCB4LCB5LCBsZWZ0KSB7XG4gICAgcmV0dXJuIGJveC5ib3R0b20gPD0geSA/IGZhbHNlIDogYm94LnRvcCA+IHkgPyB0cnVlIDogKGxlZnQgPyBib3gubGVmdCA6IGJveC5yaWdodCkgPiB4XG4gIH1cblxuICBmdW5jdGlvbiBjb29yZHNDaGFySW5uZXIoY20sIGxpbmVPYmosIGxpbmVObyQkMSwgeCwgeSkge1xuICAgIC8vIE1vdmUgeSBpbnRvIGxpbmUtbG9jYWwgY29vcmRpbmF0ZSBzcGFjZVxuICAgIHkgLT0gaGVpZ2h0QXRMaW5lKGxpbmVPYmopO1xuICAgIHZhciBwcmVwYXJlZE1lYXN1cmUgPSBwcmVwYXJlTWVhc3VyZUZvckxpbmUoY20sIGxpbmVPYmopO1xuICAgIC8vIFdoZW4gZGlyZWN0bHkgY2FsbGluZyBgbWVhc3VyZUNoYXJQcmVwYXJlZGAsIHdlIGhhdmUgdG8gYWRqdXN0XG4gICAgLy8gZm9yIHRoZSB3aWRnZXRzIGF0IHRoaXMgbGluZS5cbiAgICB2YXIgd2lkZ2V0SGVpZ2h0JCQxID0gd2lkZ2V0VG9wSGVpZ2h0KGxpbmVPYmopO1xuICAgIHZhciBiZWdpbiA9IDAsIGVuZCA9IGxpbmVPYmoudGV4dC5sZW5ndGgsIGx0ciA9IHRydWU7XG5cbiAgICB2YXIgb3JkZXIgPSBnZXRPcmRlcihsaW5lT2JqLCBjbS5kb2MuZGlyZWN0aW9uKTtcbiAgICAvLyBJZiB0aGUgbGluZSBpc24ndCBwbGFpbiBsZWZ0LXRvLXJpZ2h0IHRleHQsIGZpcnN0IGZpZ3VyZSBvdXRcbiAgICAvLyB3aGljaCBiaWRpIHNlY3Rpb24gdGhlIGNvb3JkaW5hdGVzIGZhbGwgaW50by5cbiAgICBpZiAob3JkZXIpIHtcbiAgICAgIHZhciBwYXJ0ID0gKGNtLm9wdGlvbnMubGluZVdyYXBwaW5nID8gY29vcmRzQmlkaVBhcnRXcmFwcGVkIDogY29vcmRzQmlkaVBhcnQpXG4gICAgICAgICAgICAgICAgICAgKGNtLCBsaW5lT2JqLCBsaW5lTm8kJDEsIHByZXBhcmVkTWVhc3VyZSwgb3JkZXIsIHgsIHkpO1xuICAgICAgbHRyID0gcGFydC5sZXZlbCAhPSAxO1xuICAgICAgLy8gVGhlIGF3a3dhcmQgLTEgb2Zmc2V0cyBhcmUgbmVlZGVkIGJlY2F1c2UgZmluZEZpcnN0IChjYWxsZWRcbiAgICAgIC8vIG9uIHRoZXNlIGJlbG93KSB3aWxsIHRyZWF0IGl0cyBmaXJzdCBib3VuZCBhcyBpbmNsdXNpdmUsXG4gICAgICAvLyBzZWNvbmQgYXMgZXhjbHVzaXZlLCBidXQgd2Ugd2FudCB0byBhY3R1YWxseSBhZGRyZXNzIHRoZVxuICAgICAgLy8gY2hhcmFjdGVycyBpbiB0aGUgcGFydCdzIHJhbmdlXG4gICAgICBiZWdpbiA9IGx0ciA/IHBhcnQuZnJvbSA6IHBhcnQudG8gLSAxO1xuICAgICAgZW5kID0gbHRyID8gcGFydC50byA6IHBhcnQuZnJvbSAtIDE7XG4gICAgfVxuXG4gICAgLy8gQSBiaW5hcnkgc2VhcmNoIHRvIGZpbmQgdGhlIGZpcnN0IGNoYXJhY3RlciB3aG9zZSBib3VuZGluZyBib3hcbiAgICAvLyBzdGFydHMgYWZ0ZXIgdGhlIGNvb3JkaW5hdGVzLiBJZiB3ZSBydW4gYWNyb3NzIGFueSB3aG9zZSBib3ggd3JhcFxuICAgIC8vIHRoZSBjb29yZGluYXRlcywgc3RvcmUgdGhhdC5cbiAgICB2YXIgY2hBcm91bmQgPSBudWxsLCBib3hBcm91bmQgPSBudWxsO1xuICAgIHZhciBjaCA9IGZpbmRGaXJzdChmdW5jdGlvbiAoY2gpIHtcbiAgICAgIHZhciBib3ggPSBtZWFzdXJlQ2hhclByZXBhcmVkKGNtLCBwcmVwYXJlZE1lYXN1cmUsIGNoKTtcbiAgICAgIGJveC50b3AgKz0gd2lkZ2V0SGVpZ2h0JCQxOyBib3guYm90dG9tICs9IHdpZGdldEhlaWdodCQkMTtcbiAgICAgIGlmICghYm94SXNBZnRlcihib3gsIHgsIHksIGZhbHNlKSkgeyByZXR1cm4gZmFsc2UgfVxuICAgICAgaWYgKGJveC50b3AgPD0geSAmJiBib3gubGVmdCA8PSB4KSB7XG4gICAgICAgIGNoQXJvdW5kID0gY2g7XG4gICAgICAgIGJveEFyb3VuZCA9IGJveDtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlXG4gICAgfSwgYmVnaW4sIGVuZCk7XG5cbiAgICB2YXIgYmFzZVgsIHN0aWNreSwgb3V0c2lkZSA9IGZhbHNlO1xuICAgIC8vIElmIGEgYm94IGFyb3VuZCB0aGUgY29vcmRpbmF0ZXMgd2FzIGZvdW5kLCB1c2UgdGhhdFxuICAgIGlmIChib3hBcm91bmQpIHtcbiAgICAgIC8vIERpc3Rpbmd1aXNoIGNvb3JkaW5hdGVzIG5lYXJlciB0byB0aGUgbGVmdCBvciByaWdodCBzaWRlIG9mIHRoZSBib3hcbiAgICAgIHZhciBhdExlZnQgPSB4IC0gYm94QXJvdW5kLmxlZnQgPCBib3hBcm91bmQucmlnaHQgLSB4LCBhdFN0YXJ0ID0gYXRMZWZ0ID09IGx0cjtcbiAgICAgIGNoID0gY2hBcm91bmQgKyAoYXRTdGFydCA/IDAgOiAxKTtcbiAgICAgIHN0aWNreSA9IGF0U3RhcnQgPyBcImFmdGVyXCIgOiBcImJlZm9yZVwiO1xuICAgICAgYmFzZVggPSBhdExlZnQgPyBib3hBcm91bmQubGVmdCA6IGJveEFyb3VuZC5yaWdodDtcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gKEFkanVzdCBmb3IgZXh0ZW5kZWQgYm91bmQsIGlmIG5lY2Vzc2FyeS4pXG4gICAgICBpZiAoIWx0ciAmJiAoY2ggPT0gZW5kIHx8IGNoID09IGJlZ2luKSkgeyBjaCsrOyB9XG4gICAgICAvLyBUbyBkZXRlcm1pbmUgd2hpY2ggc2lkZSB0byBhc3NvY2lhdGUgd2l0aCwgZ2V0IHRoZSBib3ggdG8gdGhlXG4gICAgICAvLyBsZWZ0IG9mIHRoZSBjaGFyYWN0ZXIgYW5kIGNvbXBhcmUgaXQncyB2ZXJ0aWNhbCBwb3NpdGlvbiB0byB0aGVcbiAgICAgIC8vIGNvb3JkaW5hdGVzXG4gICAgICBzdGlja3kgPSBjaCA9PSAwID8gXCJhZnRlclwiIDogY2ggPT0gbGluZU9iai50ZXh0Lmxlbmd0aCA/IFwiYmVmb3JlXCIgOlxuICAgICAgICAobWVhc3VyZUNoYXJQcmVwYXJlZChjbSwgcHJlcGFyZWRNZWFzdXJlLCBjaCAtIChsdHIgPyAxIDogMCkpLmJvdHRvbSArIHdpZGdldEhlaWdodCQkMSA8PSB5KSA9PSBsdHIgP1xuICAgICAgICBcImFmdGVyXCIgOiBcImJlZm9yZVwiO1xuICAgICAgLy8gTm93IGdldCBhY2N1cmF0ZSBjb29yZGluYXRlcyBmb3IgdGhpcyBwbGFjZSwgaW4gb3JkZXIgdG8gZ2V0IGFcbiAgICAgIC8vIGJhc2UgWCBwb3NpdGlvblxuICAgICAgdmFyIGNvb3JkcyA9IGN1cnNvckNvb3JkcyhjbSwgUG9zKGxpbmVObyQkMSwgY2gsIHN0aWNreSksIFwibGluZVwiLCBsaW5lT2JqLCBwcmVwYXJlZE1lYXN1cmUpO1xuICAgICAgYmFzZVggPSBjb29yZHMubGVmdDtcbiAgICAgIG91dHNpZGUgPSB5IDwgY29vcmRzLnRvcCB8fCB5ID49IGNvb3Jkcy5ib3R0b207XG4gICAgfVxuXG4gICAgY2ggPSBza2lwRXh0ZW5kaW5nQ2hhcnMobGluZU9iai50ZXh0LCBjaCwgMSk7XG4gICAgcmV0dXJuIFBvc1dpdGhJbmZvKGxpbmVObyQkMSwgY2gsIHN0aWNreSwgb3V0c2lkZSwgeCAtIGJhc2VYKVxuICB9XG5cbiAgZnVuY3Rpb24gY29vcmRzQmlkaVBhcnQoY20sIGxpbmVPYmosIGxpbmVObyQkMSwgcHJlcGFyZWRNZWFzdXJlLCBvcmRlciwgeCwgeSkge1xuICAgIC8vIEJpZGkgcGFydHMgYXJlIHNvcnRlZCBsZWZ0LXRvLXJpZ2h0LCBhbmQgaW4gYSBub24tbGluZS13cmFwcGluZ1xuICAgIC8vIHNpdHVhdGlvbiwgd2UgY2FuIHRha2UgdGhpcyBvcmRlcmluZyB0byBjb3JyZXNwb25kIHRvIHRoZSB2aXN1YWxcbiAgICAvLyBvcmRlcmluZy4gVGhpcyBmaW5kcyB0aGUgZmlyc3QgcGFydCB3aG9zZSBlbmQgaXMgYWZ0ZXIgdGhlIGdpdmVuXG4gICAgLy8gY29vcmRpbmF0ZXMuXG4gICAgdmFyIGluZGV4ID0gZmluZEZpcnN0KGZ1bmN0aW9uIChpKSB7XG4gICAgICB2YXIgcGFydCA9IG9yZGVyW2ldLCBsdHIgPSBwYXJ0LmxldmVsICE9IDE7XG4gICAgICByZXR1cm4gYm94SXNBZnRlcihjdXJzb3JDb29yZHMoY20sIFBvcyhsaW5lTm8kJDEsIGx0ciA/IHBhcnQudG8gOiBwYXJ0LmZyb20sIGx0ciA/IFwiYmVmb3JlXCIgOiBcImFmdGVyXCIpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwibGluZVwiLCBsaW5lT2JqLCBwcmVwYXJlZE1lYXN1cmUpLCB4LCB5LCB0cnVlKVxuICAgIH0sIDAsIG9yZGVyLmxlbmd0aCAtIDEpO1xuICAgIHZhciBwYXJ0ID0gb3JkZXJbaW5kZXhdO1xuICAgIC8vIElmIHRoaXMgaXNuJ3QgdGhlIGZpcnN0IHBhcnQsIHRoZSBwYXJ0J3Mgc3RhcnQgaXMgYWxzbyBhZnRlclxuICAgIC8vIHRoZSBjb29yZGluYXRlcywgYW5kIHRoZSBjb29yZGluYXRlcyBhcmVuJ3Qgb24gdGhlIHNhbWUgbGluZSBhc1xuICAgIC8vIHRoYXQgc3RhcnQsIG1vdmUgb25lIHBhcnQgYmFjay5cbiAgICBpZiAoaW5kZXggPiAwKSB7XG4gICAgICB2YXIgbHRyID0gcGFydC5sZXZlbCAhPSAxO1xuICAgICAgdmFyIHN0YXJ0ID0gY3Vyc29yQ29vcmRzKGNtLCBQb3MobGluZU5vJCQxLCBsdHIgPyBwYXJ0LmZyb20gOiBwYXJ0LnRvLCBsdHIgPyBcImFmdGVyXCIgOiBcImJlZm9yZVwiKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBcImxpbmVcIiwgbGluZU9iaiwgcHJlcGFyZWRNZWFzdXJlKTtcbiAgICAgIGlmIChib3hJc0FmdGVyKHN0YXJ0LCB4LCB5LCB0cnVlKSAmJiBzdGFydC50b3AgPiB5KVxuICAgICAgICB7IHBhcnQgPSBvcmRlcltpbmRleCAtIDFdOyB9XG4gICAgfVxuICAgIHJldHVybiBwYXJ0XG4gIH1cblxuICBmdW5jdGlvbiBjb29yZHNCaWRpUGFydFdyYXBwZWQoY20sIGxpbmVPYmosIF9saW5lTm8sIHByZXBhcmVkTWVhc3VyZSwgb3JkZXIsIHgsIHkpIHtcbiAgICAvLyBJbiBhIHdyYXBwZWQgbGluZSwgcnRsIHRleHQgb24gd3JhcHBpbmcgYm91bmRhcmllcyBjYW4gZG8gdGhpbmdzXG4gICAgLy8gdGhhdCBkb24ndCBjb3JyZXNwb25kIHRvIHRoZSBvcmRlcmluZyBpbiBvdXIgYG9yZGVyYCBhcnJheSBhdFxuICAgIC8vIGFsbCwgc28gYSBiaW5hcnkgc2VhcmNoIGRvZXNuJ3Qgd29yaywgYW5kIHdlIHdhbnQgdG8gcmV0dXJuIGFcbiAgICAvLyBwYXJ0IHRoYXQgb25seSBzcGFucyBvbmUgbGluZSBzbyB0aGF0IHRoZSBiaW5hcnkgc2VhcmNoIGluXG4gICAgLy8gY29vcmRzQ2hhcklubmVyIGlzIHNhZmUuIEFzIHN1Y2gsIHdlIGZpcnN0IGZpbmQgdGhlIGV4dGVudCBvZiB0aGVcbiAgICAvLyB3cmFwcGVkIGxpbmUsIGFuZCB0aGVuIGRvIGEgZmxhdCBzZWFyY2ggaW4gd2hpY2ggd2UgZGlzY2FyZCBhbnlcbiAgICAvLyBzcGFucyB0aGF0IGFyZW4ndCBvbiB0aGUgbGluZS5cbiAgICB2YXIgcmVmID0gd3JhcHBlZExpbmVFeHRlbnQoY20sIGxpbmVPYmosIHByZXBhcmVkTWVhc3VyZSwgeSk7XG4gICAgdmFyIGJlZ2luID0gcmVmLmJlZ2luO1xuICAgIHZhciBlbmQgPSByZWYuZW5kO1xuICAgIGlmICgvXFxzLy50ZXN0KGxpbmVPYmoudGV4dC5jaGFyQXQoZW5kIC0gMSkpKSB7IGVuZC0tOyB9XG4gICAgdmFyIHBhcnQgPSBudWxsLCBjbG9zZXN0RGlzdCA9IG51bGw7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcmRlci5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIHAgPSBvcmRlcltpXTtcbiAgICAgIGlmIChwLmZyb20gPj0gZW5kIHx8IHAudG8gPD0gYmVnaW4pIHsgY29udGludWUgfVxuICAgICAgdmFyIGx0ciA9IHAubGV2ZWwgIT0gMTtcbiAgICAgIHZhciBlbmRYID0gbWVhc3VyZUNoYXJQcmVwYXJlZChjbSwgcHJlcGFyZWRNZWFzdXJlLCBsdHIgPyBNYXRoLm1pbihlbmQsIHAudG8pIC0gMSA6IE1hdGgubWF4KGJlZ2luLCBwLmZyb20pKS5yaWdodDtcbiAgICAgIC8vIFdlaWdoIGFnYWluc3Qgc3BhbnMgZW5kaW5nIGJlZm9yZSB0aGlzLCBzbyB0aGF0IHRoZXkgYXJlIG9ubHlcbiAgICAgIC8vIHBpY2tlZCBpZiBub3RoaW5nIGVuZHMgYWZ0ZXJcbiAgICAgIHZhciBkaXN0ID0gZW5kWCA8IHggPyB4IC0gZW5kWCArIDFlOSA6IGVuZFggLSB4O1xuICAgICAgaWYgKCFwYXJ0IHx8IGNsb3Nlc3REaXN0ID4gZGlzdCkge1xuICAgICAgICBwYXJ0ID0gcDtcbiAgICAgICAgY2xvc2VzdERpc3QgPSBkaXN0O1xuICAgICAgfVxuICAgIH1cbiAgICBpZiAoIXBhcnQpIHsgcGFydCA9IG9yZGVyW29yZGVyLmxlbmd0aCAtIDFdOyB9XG4gICAgLy8gQ2xpcCB0aGUgcGFydCB0byB0aGUgd3JhcHBlZCBsaW5lLlxuICAgIGlmIChwYXJ0LmZyb20gPCBiZWdpbikgeyBwYXJ0ID0ge2Zyb206IGJlZ2luLCB0bzogcGFydC50bywgbGV2ZWw6IHBhcnQubGV2ZWx9OyB9XG4gICAgaWYgKHBhcnQudG8gPiBlbmQpIHsgcGFydCA9IHtmcm9tOiBwYXJ0LmZyb20sIHRvOiBlbmQsIGxldmVsOiBwYXJ0LmxldmVsfTsgfVxuICAgIHJldHVybiBwYXJ0XG4gIH1cblxuICB2YXIgbWVhc3VyZVRleHQ7XG4gIC8vIENvbXB1dGUgdGhlIGRlZmF1bHQgdGV4dCBoZWlnaHQuXG4gIGZ1bmN0aW9uIHRleHRIZWlnaHQoZGlzcGxheSkge1xuICAgIGlmIChkaXNwbGF5LmNhY2hlZFRleHRIZWlnaHQgIT0gbnVsbCkgeyByZXR1cm4gZGlzcGxheS5jYWNoZWRUZXh0SGVpZ2h0IH1cbiAgICBpZiAobWVhc3VyZVRleHQgPT0gbnVsbCkge1xuICAgICAgbWVhc3VyZVRleHQgPSBlbHQoXCJwcmVcIik7XG4gICAgICAvLyBNZWFzdXJlIGEgYnVuY2ggb2YgbGluZXMsIGZvciBicm93c2VycyB0aGF0IGNvbXB1dGVcbiAgICAgIC8vIGZyYWN0aW9uYWwgaGVpZ2h0cy5cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgNDk7ICsraSkge1xuICAgICAgICBtZWFzdXJlVGV4dC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcInhcIikpO1xuICAgICAgICBtZWFzdXJlVGV4dC5hcHBlbmRDaGlsZChlbHQoXCJiclwiKSk7XG4gICAgICB9XG4gICAgICBtZWFzdXJlVGV4dC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShcInhcIikpO1xuICAgIH1cbiAgICByZW1vdmVDaGlsZHJlbkFuZEFkZChkaXNwbGF5Lm1lYXN1cmUsIG1lYXN1cmVUZXh0KTtcbiAgICB2YXIgaGVpZ2h0ID0gbWVhc3VyZVRleHQub2Zmc2V0SGVpZ2h0IC8gNTA7XG4gICAgaWYgKGhlaWdodCA+IDMpIHsgZGlzcGxheS5jYWNoZWRUZXh0SGVpZ2h0ID0gaGVpZ2h0OyB9XG4gICAgcmVtb3ZlQ2hpbGRyZW4oZGlzcGxheS5tZWFzdXJlKTtcbiAgICByZXR1cm4gaGVpZ2h0IHx8IDFcbiAgfVxuXG4gIC8vIENvbXB1dGUgdGhlIGRlZmF1bHQgY2hhcmFjdGVyIHdpZHRoLlxuICBmdW5jdGlvbiBjaGFyV2lkdGgoZGlzcGxheSkge1xuICAgIGlmIChkaXNwbGF5LmNhY2hlZENoYXJXaWR0aCAhPSBudWxsKSB7IHJldHVybiBkaXNwbGF5LmNhY2hlZENoYXJXaWR0aCB9XG4gICAgdmFyIGFuY2hvciA9IGVsdChcInNwYW5cIiwgXCJ4eHh4eHh4eHh4XCIpO1xuICAgIHZhciBwcmUgPSBlbHQoXCJwcmVcIiwgW2FuY2hvcl0pO1xuICAgIHJlbW92ZUNoaWxkcmVuQW5kQWRkKGRpc3BsYXkubWVhc3VyZSwgcHJlKTtcbiAgICB2YXIgcmVjdCA9IGFuY2hvci5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKSwgd2lkdGggPSAocmVjdC5yaWdodCAtIHJlY3QubGVmdCkgLyAxMDtcbiAgICBpZiAod2lkdGggPiAyKSB7IGRpc3BsYXkuY2FjaGVkQ2hhcldpZHRoID0gd2lkdGg7IH1cbiAgICByZXR1cm4gd2lkdGggfHwgMTBcbiAgfVxuXG4gIC8vIERvIGEgYnVsay1yZWFkIG9mIHRoZSBET00gcG9zaXRpb25zIGFuZCBzaXplcyBuZWVkZWQgdG8gZHJhdyB0aGVcbiAgLy8gdmlldywgc28gdGhhdCB3ZSBkb24ndCBpbnRlcmxlYXZlIHJlYWRpbmcgYW5kIHdyaXRpbmcgdG8gdGhlIERPTS5cbiAgZnVuY3Rpb24gZ2V0RGltZW5zaW9ucyhjbSkge1xuICAgIHZhciBkID0gY20uZGlzcGxheSwgbGVmdCA9IHt9LCB3aWR0aCA9IHt9O1xuICAgIHZhciBndXR0ZXJMZWZ0ID0gZC5ndXR0ZXJzLmNsaWVudExlZnQ7XG4gICAgZm9yICh2YXIgbiA9IGQuZ3V0dGVycy5maXJzdENoaWxkLCBpID0gMDsgbjsgbiA9IG4ubmV4dFNpYmxpbmcsICsraSkge1xuICAgICAgbGVmdFtjbS5vcHRpb25zLmd1dHRlcnNbaV1dID0gbi5vZmZzZXRMZWZ0ICsgbi5jbGllbnRMZWZ0ICsgZ3V0dGVyTGVmdDtcbiAgICAgIHdpZHRoW2NtLm9wdGlvbnMuZ3V0dGVyc1tpXV0gPSBuLmNsaWVudFdpZHRoO1xuICAgIH1cbiAgICByZXR1cm4ge2ZpeGVkUG9zOiBjb21wZW5zYXRlRm9ySFNjcm9sbChkKSxcbiAgICAgICAgICAgIGd1dHRlclRvdGFsV2lkdGg6IGQuZ3V0dGVycy5vZmZzZXRXaWR0aCxcbiAgICAgICAgICAgIGd1dHRlckxlZnQ6IGxlZnQsXG4gICAgICAgICAgICBndXR0ZXJXaWR0aDogd2lkdGgsXG4gICAgICAgICAgICB3cmFwcGVyV2lkdGg6IGQud3JhcHBlci5jbGllbnRXaWR0aH1cbiAgfVxuXG4gIC8vIENvbXB1dGVzIGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsTGVmdCArIGRpc3BsYXkuZ3V0dGVycy5vZmZzZXRXaWR0aCxcbiAgLy8gYnV0IHVzaW5nIGdldEJvdW5kaW5nQ2xpZW50UmVjdCB0byBnZXQgYSBzdWItcGl4ZWwtYWNjdXJhdGVcbiAgLy8gcmVzdWx0LlxuICBmdW5jdGlvbiBjb21wZW5zYXRlRm9ySFNjcm9sbChkaXNwbGF5KSB7XG4gICAgcmV0dXJuIGRpc3BsYXkuc2Nyb2xsZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdCAtIGRpc3BsYXkuc2l6ZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkubGVmdFxuICB9XG5cbiAgLy8gUmV0dXJucyBhIGZ1bmN0aW9uIHRoYXQgZXN0aW1hdGVzIHRoZSBoZWlnaHQgb2YgYSBsaW5lLCB0byB1c2UgYXNcbiAgLy8gZmlyc3QgYXBwcm94aW1hdGlvbiB1bnRpbCB0aGUgbGluZSBiZWNvbWVzIHZpc2libGUgKGFuZCBpcyB0aHVzXG4gIC8vIHByb3Blcmx5IG1lYXN1cmFibGUpLlxuICBmdW5jdGlvbiBlc3RpbWF0ZUhlaWdodChjbSkge1xuICAgIHZhciB0aCA9IHRleHRIZWlnaHQoY20uZGlzcGxheSksIHdyYXBwaW5nID0gY20ub3B0aW9ucy5saW5lV3JhcHBpbmc7XG4gICAgdmFyIHBlckxpbmUgPSB3cmFwcGluZyAmJiBNYXRoLm1heCg1LCBjbS5kaXNwbGF5LnNjcm9sbGVyLmNsaWVudFdpZHRoIC8gY2hhcldpZHRoKGNtLmRpc3BsYXkpIC0gMyk7XG4gICAgcmV0dXJuIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICBpZiAobGluZUlzSGlkZGVuKGNtLmRvYywgbGluZSkpIHsgcmV0dXJuIDAgfVxuXG4gICAgICB2YXIgd2lkZ2V0c0hlaWdodCA9IDA7XG4gICAgICBpZiAobGluZS53aWRnZXRzKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgbGluZS53aWRnZXRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChsaW5lLndpZGdldHNbaV0uaGVpZ2h0KSB7IHdpZGdldHNIZWlnaHQgKz0gbGluZS53aWRnZXRzW2ldLmhlaWdodDsgfVxuICAgICAgfSB9XG5cbiAgICAgIGlmICh3cmFwcGluZylcbiAgICAgICAgeyByZXR1cm4gd2lkZ2V0c0hlaWdodCArIChNYXRoLmNlaWwobGluZS50ZXh0Lmxlbmd0aCAvIHBlckxpbmUpIHx8IDEpICogdGggfVxuICAgICAgZWxzZVxuICAgICAgICB7IHJldHVybiB3aWRnZXRzSGVpZ2h0ICsgdGggfVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGVzdGltYXRlTGluZUhlaWdodHMoY20pIHtcbiAgICB2YXIgZG9jID0gY20uZG9jLCBlc3QgPSBlc3RpbWF0ZUhlaWdodChjbSk7XG4gICAgZG9jLml0ZXIoZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgIHZhciBlc3RIZWlnaHQgPSBlc3QobGluZSk7XG4gICAgICBpZiAoZXN0SGVpZ2h0ICE9IGxpbmUuaGVpZ2h0KSB7IHVwZGF0ZUxpbmVIZWlnaHQobGluZSwgZXN0SGVpZ2h0KTsgfVxuICAgIH0pO1xuICB9XG5cbiAgLy8gR2l2ZW4gYSBtb3VzZSBldmVudCwgZmluZCB0aGUgY29ycmVzcG9uZGluZyBwb3NpdGlvbi4gSWYgbGliZXJhbFxuICAvLyBpcyBmYWxzZSwgaXQgY2hlY2tzIHdoZXRoZXIgYSBndXR0ZXIgb3Igc2Nyb2xsYmFyIHdhcyBjbGlja2VkLFxuICAvLyBhbmQgcmV0dXJucyBudWxsIGlmIGl0IHdhcy4gZm9yUmVjdCBpcyB1c2VkIGJ5IHJlY3Rhbmd1bGFyXG4gIC8vIHNlbGVjdGlvbnMsIGFuZCB0cmllcyB0byBlc3RpbWF0ZSBhIGNoYXJhY3RlciBwb3NpdGlvbiBldmVuIGZvclxuICAvLyBjb29yZGluYXRlcyBiZXlvbmQgdGhlIHJpZ2h0IG9mIHRoZSB0ZXh0LlxuICBmdW5jdGlvbiBwb3NGcm9tTW91c2UoY20sIGUsIGxpYmVyYWwsIGZvclJlY3QpIHtcbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXk7XG4gICAgaWYgKCFsaWJlcmFsICYmIGVfdGFyZ2V0KGUpLmdldEF0dHJpYnV0ZShcImNtLW5vdC1jb250ZW50XCIpID09IFwidHJ1ZVwiKSB7IHJldHVybiBudWxsIH1cblxuICAgIHZhciB4LCB5LCBzcGFjZSA9IGRpc3BsYXkubGluZVNwYWNlLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIC8vIEZhaWxzIHVucHJlZGljdGFibHkgb24gSUVbNjddIHdoZW4gbW91c2UgaXMgZHJhZ2dlZCBhcm91bmQgcXVpY2tseS5cbiAgICB0cnkgeyB4ID0gZS5jbGllbnRYIC0gc3BhY2UubGVmdDsgeSA9IGUuY2xpZW50WSAtIHNwYWNlLnRvcDsgfVxuICAgIGNhdGNoIChlKSB7IHJldHVybiBudWxsIH1cbiAgICB2YXIgY29vcmRzID0gY29vcmRzQ2hhcihjbSwgeCwgeSksIGxpbmU7XG4gICAgaWYgKGZvclJlY3QgJiYgY29vcmRzLnhSZWwgPT0gMSAmJiAobGluZSA9IGdldExpbmUoY20uZG9jLCBjb29yZHMubGluZSkudGV4dCkubGVuZ3RoID09IGNvb3Jkcy5jaCkge1xuICAgICAgdmFyIGNvbERpZmYgPSBjb3VudENvbHVtbihsaW5lLCBsaW5lLmxlbmd0aCwgY20ub3B0aW9ucy50YWJTaXplKSAtIGxpbmUubGVuZ3RoO1xuICAgICAgY29vcmRzID0gUG9zKGNvb3Jkcy5saW5lLCBNYXRoLm1heCgwLCBNYXRoLnJvdW5kKCh4IC0gcGFkZGluZ0goY20uZGlzcGxheSkubGVmdCkgLyBjaGFyV2lkdGgoY20uZGlzcGxheSkpIC0gY29sRGlmZikpO1xuICAgIH1cbiAgICByZXR1cm4gY29vcmRzXG4gIH1cblxuICAvLyBGaW5kIHRoZSB2aWV3IGVsZW1lbnQgY29ycmVzcG9uZGluZyB0byBhIGdpdmVuIGxpbmUuIFJldHVybiBudWxsXG4gIC8vIHdoZW4gdGhlIGxpbmUgaXNuJ3QgdmlzaWJsZS5cbiAgZnVuY3Rpb24gZmluZFZpZXdJbmRleChjbSwgbikge1xuICAgIGlmIChuID49IGNtLmRpc3BsYXkudmlld1RvKSB7IHJldHVybiBudWxsIH1cbiAgICBuIC09IGNtLmRpc3BsYXkudmlld0Zyb207XG4gICAgaWYgKG4gPCAwKSB7IHJldHVybiBudWxsIH1cbiAgICB2YXIgdmlldyA9IGNtLmRpc3BsYXkudmlldztcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZpZXcubGVuZ3RoOyBpKyspIHtcbiAgICAgIG4gLT0gdmlld1tpXS5zaXplO1xuICAgICAgaWYgKG4gPCAwKSB7IHJldHVybiBpIH1cbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiB1cGRhdGVTZWxlY3Rpb24oY20pIHtcbiAgICBjbS5kaXNwbGF5LmlucHV0LnNob3dTZWxlY3Rpb24oY20uZGlzcGxheS5pbnB1dC5wcmVwYXJlU2VsZWN0aW9uKCkpO1xuICB9XG5cbiAgZnVuY3Rpb24gcHJlcGFyZVNlbGVjdGlvbihjbSwgcHJpbWFyeSkge1xuICAgIGlmICggcHJpbWFyeSA9PT0gdm9pZCAwICkgcHJpbWFyeSA9IHRydWU7XG5cbiAgICB2YXIgZG9jID0gY20uZG9jLCByZXN1bHQgPSB7fTtcbiAgICB2YXIgY3VyRnJhZ21lbnQgPSByZXN1bHQuY3Vyc29ycyA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcbiAgICB2YXIgc2VsRnJhZ21lbnQgPSByZXN1bHQuc2VsZWN0aW9uID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkb2Muc2VsLnJhbmdlcy5sZW5ndGg7IGkrKykge1xuICAgICAgaWYgKCFwcmltYXJ5ICYmIGkgPT0gZG9jLnNlbC5wcmltSW5kZXgpIHsgY29udGludWUgfVxuICAgICAgdmFyIHJhbmdlJCQxID0gZG9jLnNlbC5yYW5nZXNbaV07XG4gICAgICBpZiAocmFuZ2UkJDEuZnJvbSgpLmxpbmUgPj0gY20uZGlzcGxheS52aWV3VG8gfHwgcmFuZ2UkJDEudG8oKS5saW5lIDwgY20uZGlzcGxheS52aWV3RnJvbSkgeyBjb250aW51ZSB9XG4gICAgICB2YXIgY29sbGFwc2VkID0gcmFuZ2UkJDEuZW1wdHkoKTtcbiAgICAgIGlmIChjb2xsYXBzZWQgfHwgY20ub3B0aW9ucy5zaG93Q3Vyc29yV2hlblNlbGVjdGluZylcbiAgICAgICAgeyBkcmF3U2VsZWN0aW9uQ3Vyc29yKGNtLCByYW5nZSQkMS5oZWFkLCBjdXJGcmFnbWVudCk7IH1cbiAgICAgIGlmICghY29sbGFwc2VkKVxuICAgICAgICB7IGRyYXdTZWxlY3Rpb25SYW5nZShjbSwgcmFuZ2UkJDEsIHNlbEZyYWdtZW50KTsgfVxuICAgIH1cbiAgICByZXR1cm4gcmVzdWx0XG4gIH1cblxuICAvLyBEcmF3cyBhIGN1cnNvciBmb3IgdGhlIGdpdmVuIHJhbmdlXG4gIGZ1bmN0aW9uIGRyYXdTZWxlY3Rpb25DdXJzb3IoY20sIGhlYWQsIG91dHB1dCkge1xuICAgIHZhciBwb3MgPSBjdXJzb3JDb29yZHMoY20sIGhlYWQsIFwiZGl2XCIsIG51bGwsIG51bGwsICFjbS5vcHRpb25zLnNpbmdsZUN1cnNvckhlaWdodFBlckxpbmUpO1xuXG4gICAgdmFyIGN1cnNvciA9IG91dHB1dC5hcHBlbmRDaGlsZChlbHQoXCJkaXZcIiwgXCJcXHUwMGEwXCIsIFwiQ29kZU1pcnJvci1jdXJzb3JcIikpO1xuICAgIGN1cnNvci5zdHlsZS5sZWZ0ID0gcG9zLmxlZnQgKyBcInB4XCI7XG4gICAgY3Vyc29yLnN0eWxlLnRvcCA9IHBvcy50b3AgKyBcInB4XCI7XG4gICAgY3Vyc29yLnN0eWxlLmhlaWdodCA9IE1hdGgubWF4KDAsIHBvcy5ib3R0b20gLSBwb3MudG9wKSAqIGNtLm9wdGlvbnMuY3Vyc29ySGVpZ2h0ICsgXCJweFwiO1xuXG4gICAgaWYgKHBvcy5vdGhlcikge1xuICAgICAgLy8gU2Vjb25kYXJ5IGN1cnNvciwgc2hvd24gd2hlbiBvbiBhICdqdW1wJyBpbiBiaS1kaXJlY3Rpb25hbCB0ZXh0XG4gICAgICB2YXIgb3RoZXJDdXJzb3IgPSBvdXRwdXQuYXBwZW5kQ2hpbGQoZWx0KFwiZGl2XCIsIFwiXFx1MDBhMFwiLCBcIkNvZGVNaXJyb3ItY3Vyc29yIENvZGVNaXJyb3Itc2Vjb25kYXJ5Y3Vyc29yXCIpKTtcbiAgICAgIG90aGVyQ3Vyc29yLnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xuICAgICAgb3RoZXJDdXJzb3Iuc3R5bGUubGVmdCA9IHBvcy5vdGhlci5sZWZ0ICsgXCJweFwiO1xuICAgICAgb3RoZXJDdXJzb3Iuc3R5bGUudG9wID0gcG9zLm90aGVyLnRvcCArIFwicHhcIjtcbiAgICAgIG90aGVyQ3Vyc29yLnN0eWxlLmhlaWdodCA9IChwb3Mub3RoZXIuYm90dG9tIC0gcG9zLm90aGVyLnRvcCkgKiAuODUgKyBcInB4XCI7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gY21wQ29vcmRzKGEsIGIpIHsgcmV0dXJuIGEudG9wIC0gYi50b3AgfHwgYS5sZWZ0IC0gYi5sZWZ0IH1cblxuICAvLyBEcmF3cyB0aGUgZ2l2ZW4gcmFuZ2UgYXMgYSBoaWdobGlnaHRlZCBzZWxlY3Rpb25cbiAgZnVuY3Rpb24gZHJhd1NlbGVjdGlvblJhbmdlKGNtLCByYW5nZSQkMSwgb3V0cHV0KSB7XG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBkb2MgPSBjbS5kb2M7XG4gICAgdmFyIGZyYWdtZW50ID0gZG9jdW1lbnQuY3JlYXRlRG9jdW1lbnRGcmFnbWVudCgpO1xuICAgIHZhciBwYWRkaW5nID0gcGFkZGluZ0goY20uZGlzcGxheSksIGxlZnRTaWRlID0gcGFkZGluZy5sZWZ0O1xuICAgIHZhciByaWdodFNpZGUgPSBNYXRoLm1heChkaXNwbGF5LnNpemVyV2lkdGgsIGRpc3BsYXlXaWR0aChjbSkgLSBkaXNwbGF5LnNpemVyLm9mZnNldExlZnQpIC0gcGFkZGluZy5yaWdodDtcbiAgICB2YXIgZG9jTFRSID0gZG9jLmRpcmVjdGlvbiA9PSBcImx0clwiO1xuXG4gICAgZnVuY3Rpb24gYWRkKGxlZnQsIHRvcCwgd2lkdGgsIGJvdHRvbSkge1xuICAgICAgaWYgKHRvcCA8IDApIHsgdG9wID0gMDsgfVxuICAgICAgdG9wID0gTWF0aC5yb3VuZCh0b3ApO1xuICAgICAgYm90dG9tID0gTWF0aC5yb3VuZChib3R0b20pO1xuICAgICAgZnJhZ21lbnQuYXBwZW5kQ2hpbGQoZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1zZWxlY3RlZFwiLCAoXCJwb3NpdGlvbjogYWJzb2x1dGU7IGxlZnQ6IFwiICsgbGVmdCArIFwicHg7XFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0b3A6IFwiICsgdG9wICsgXCJweDsgd2lkdGg6IFwiICsgKHdpZHRoID09IG51bGwgPyByaWdodFNpZGUgLSBsZWZ0IDogd2lkdGgpICsgXCJweDtcXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodDogXCIgKyAoYm90dG9tIC0gdG9wKSArIFwicHhcIikpKTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBkcmF3Rm9yTGluZShsaW5lLCBmcm9tQXJnLCB0b0FyZykge1xuICAgICAgdmFyIGxpbmVPYmogPSBnZXRMaW5lKGRvYywgbGluZSk7XG4gICAgICB2YXIgbGluZUxlbiA9IGxpbmVPYmoudGV4dC5sZW5ndGg7XG4gICAgICB2YXIgc3RhcnQsIGVuZDtcbiAgICAgIGZ1bmN0aW9uIGNvb3JkcyhjaCwgYmlhcykge1xuICAgICAgICByZXR1cm4gY2hhckNvb3JkcyhjbSwgUG9zKGxpbmUsIGNoKSwgXCJkaXZcIiwgbGluZU9iaiwgYmlhcylcbiAgICAgIH1cblxuICAgICAgZnVuY3Rpb24gd3JhcFgocG9zLCBkaXIsIHNpZGUpIHtcbiAgICAgICAgdmFyIGV4dGVudCA9IHdyYXBwZWRMaW5lRXh0ZW50Q2hhcihjbSwgbGluZU9iaiwgbnVsbCwgcG9zKTtcbiAgICAgICAgdmFyIHByb3AgPSAoZGlyID09IFwibHRyXCIpID09IChzaWRlID09IFwiYWZ0ZXJcIikgPyBcImxlZnRcIiA6IFwicmlnaHRcIjtcbiAgICAgICAgdmFyIGNoID0gc2lkZSA9PSBcImFmdGVyXCIgPyBleHRlbnQuYmVnaW4gOiBleHRlbnQuZW5kIC0gKC9cXHMvLnRlc3QobGluZU9iai50ZXh0LmNoYXJBdChleHRlbnQuZW5kIC0gMSkpID8gMiA6IDEpO1xuICAgICAgICByZXR1cm4gY29vcmRzKGNoLCBwcm9wKVtwcm9wXVxuICAgICAgfVxuXG4gICAgICB2YXIgb3JkZXIgPSBnZXRPcmRlcihsaW5lT2JqLCBkb2MuZGlyZWN0aW9uKTtcbiAgICAgIGl0ZXJhdGVCaWRpU2VjdGlvbnMob3JkZXIsIGZyb21BcmcgfHwgMCwgdG9BcmcgPT0gbnVsbCA/IGxpbmVMZW4gOiB0b0FyZywgZnVuY3Rpb24gKGZyb20sIHRvLCBkaXIsIGkpIHtcbiAgICAgICAgdmFyIGx0ciA9IGRpciA9PSBcImx0clwiO1xuICAgICAgICB2YXIgZnJvbVBvcyA9IGNvb3Jkcyhmcm9tLCBsdHIgPyBcImxlZnRcIiA6IFwicmlnaHRcIik7XG4gICAgICAgIHZhciB0b1BvcyA9IGNvb3Jkcyh0byAtIDEsIGx0ciA/IFwicmlnaHRcIiA6IFwibGVmdFwiKTtcblxuICAgICAgICB2YXIgb3BlblN0YXJ0ID0gZnJvbUFyZyA9PSBudWxsICYmIGZyb20gPT0gMCwgb3BlbkVuZCA9IHRvQXJnID09IG51bGwgJiYgdG8gPT0gbGluZUxlbjtcbiAgICAgICAgdmFyIGZpcnN0ID0gaSA9PSAwLCBsYXN0ID0gIW9yZGVyIHx8IGkgPT0gb3JkZXIubGVuZ3RoIC0gMTtcbiAgICAgICAgaWYgKHRvUG9zLnRvcCAtIGZyb21Qb3MudG9wIDw9IDMpIHsgLy8gU2luZ2xlIGxpbmVcbiAgICAgICAgICB2YXIgb3BlbkxlZnQgPSAoZG9jTFRSID8gb3BlblN0YXJ0IDogb3BlbkVuZCkgJiYgZmlyc3Q7XG4gICAgICAgICAgdmFyIG9wZW5SaWdodCA9IChkb2NMVFIgPyBvcGVuRW5kIDogb3BlblN0YXJ0KSAmJiBsYXN0O1xuICAgICAgICAgIHZhciBsZWZ0ID0gb3BlbkxlZnQgPyBsZWZ0U2lkZSA6IChsdHIgPyBmcm9tUG9zIDogdG9Qb3MpLmxlZnQ7XG4gICAgICAgICAgdmFyIHJpZ2h0ID0gb3BlblJpZ2h0ID8gcmlnaHRTaWRlIDogKGx0ciA/IHRvUG9zIDogZnJvbVBvcykucmlnaHQ7XG4gICAgICAgICAgYWRkKGxlZnQsIGZyb21Qb3MudG9wLCByaWdodCAtIGxlZnQsIGZyb21Qb3MuYm90dG9tKTtcbiAgICAgICAgfSBlbHNlIHsgLy8gTXVsdGlwbGUgbGluZXNcbiAgICAgICAgICB2YXIgdG9wTGVmdCwgdG9wUmlnaHQsIGJvdExlZnQsIGJvdFJpZ2h0O1xuICAgICAgICAgIGlmIChsdHIpIHtcbiAgICAgICAgICAgIHRvcExlZnQgPSBkb2NMVFIgJiYgb3BlblN0YXJ0ICYmIGZpcnN0ID8gbGVmdFNpZGUgOiBmcm9tUG9zLmxlZnQ7XG4gICAgICAgICAgICB0b3BSaWdodCA9IGRvY0xUUiA/IHJpZ2h0U2lkZSA6IHdyYXBYKGZyb20sIGRpciwgXCJiZWZvcmVcIik7XG4gICAgICAgICAgICBib3RMZWZ0ID0gZG9jTFRSID8gbGVmdFNpZGUgOiB3cmFwWCh0bywgZGlyLCBcImFmdGVyXCIpO1xuICAgICAgICAgICAgYm90UmlnaHQgPSBkb2NMVFIgJiYgb3BlbkVuZCAmJiBsYXN0ID8gcmlnaHRTaWRlIDogdG9Qb3MucmlnaHQ7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRvcExlZnQgPSAhZG9jTFRSID8gbGVmdFNpZGUgOiB3cmFwWChmcm9tLCBkaXIsIFwiYmVmb3JlXCIpO1xuICAgICAgICAgICAgdG9wUmlnaHQgPSAhZG9jTFRSICYmIG9wZW5TdGFydCAmJiBmaXJzdCA/IHJpZ2h0U2lkZSA6IGZyb21Qb3MucmlnaHQ7XG4gICAgICAgICAgICBib3RMZWZ0ID0gIWRvY0xUUiAmJiBvcGVuRW5kICYmIGxhc3QgPyBsZWZ0U2lkZSA6IHRvUG9zLmxlZnQ7XG4gICAgICAgICAgICBib3RSaWdodCA9ICFkb2NMVFIgPyByaWdodFNpZGUgOiB3cmFwWCh0bywgZGlyLCBcImFmdGVyXCIpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBhZGQodG9wTGVmdCwgZnJvbVBvcy50b3AsIHRvcFJpZ2h0IC0gdG9wTGVmdCwgZnJvbVBvcy5ib3R0b20pO1xuICAgICAgICAgIGlmIChmcm9tUG9zLmJvdHRvbSA8IHRvUG9zLnRvcCkgeyBhZGQobGVmdFNpZGUsIGZyb21Qb3MuYm90dG9tLCBudWxsLCB0b1Bvcy50b3ApOyB9XG4gICAgICAgICAgYWRkKGJvdExlZnQsIHRvUG9zLnRvcCwgYm90UmlnaHQgLSBib3RMZWZ0LCB0b1Bvcy5ib3R0b20pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFzdGFydCB8fCBjbXBDb29yZHMoZnJvbVBvcywgc3RhcnQpIDwgMCkgeyBzdGFydCA9IGZyb21Qb3M7IH1cbiAgICAgICAgaWYgKGNtcENvb3Jkcyh0b1Bvcywgc3RhcnQpIDwgMCkgeyBzdGFydCA9IHRvUG9zOyB9XG4gICAgICAgIGlmICghZW5kIHx8IGNtcENvb3Jkcyhmcm9tUG9zLCBlbmQpIDwgMCkgeyBlbmQgPSBmcm9tUG9zOyB9XG4gICAgICAgIGlmIChjbXBDb29yZHModG9Qb3MsIGVuZCkgPCAwKSB7IGVuZCA9IHRvUG9zOyB9XG4gICAgICB9KTtcbiAgICAgIHJldHVybiB7c3RhcnQ6IHN0YXJ0LCBlbmQ6IGVuZH1cbiAgICB9XG5cbiAgICB2YXIgc0Zyb20gPSByYW5nZSQkMS5mcm9tKCksIHNUbyA9IHJhbmdlJCQxLnRvKCk7XG4gICAgaWYgKHNGcm9tLmxpbmUgPT0gc1RvLmxpbmUpIHtcbiAgICAgIGRyYXdGb3JMaW5lKHNGcm9tLmxpbmUsIHNGcm9tLmNoLCBzVG8uY2gpO1xuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgZnJvbUxpbmUgPSBnZXRMaW5lKGRvYywgc0Zyb20ubGluZSksIHRvTGluZSA9IGdldExpbmUoZG9jLCBzVG8ubGluZSk7XG4gICAgICB2YXIgc2luZ2xlVkxpbmUgPSB2aXN1YWxMaW5lKGZyb21MaW5lKSA9PSB2aXN1YWxMaW5lKHRvTGluZSk7XG4gICAgICB2YXIgbGVmdEVuZCA9IGRyYXdGb3JMaW5lKHNGcm9tLmxpbmUsIHNGcm9tLmNoLCBzaW5nbGVWTGluZSA/IGZyb21MaW5lLnRleHQubGVuZ3RoICsgMSA6IG51bGwpLmVuZDtcbiAgICAgIHZhciByaWdodFN0YXJ0ID0gZHJhd0ZvckxpbmUoc1RvLmxpbmUsIHNpbmdsZVZMaW5lID8gMCA6IG51bGwsIHNUby5jaCkuc3RhcnQ7XG4gICAgICBpZiAoc2luZ2xlVkxpbmUpIHtcbiAgICAgICAgaWYgKGxlZnRFbmQudG9wIDwgcmlnaHRTdGFydC50b3AgLSAyKSB7XG4gICAgICAgICAgYWRkKGxlZnRFbmQucmlnaHQsIGxlZnRFbmQudG9wLCBudWxsLCBsZWZ0RW5kLmJvdHRvbSk7XG4gICAgICAgICAgYWRkKGxlZnRTaWRlLCByaWdodFN0YXJ0LnRvcCwgcmlnaHRTdGFydC5sZWZ0LCByaWdodFN0YXJ0LmJvdHRvbSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgYWRkKGxlZnRFbmQucmlnaHQsIGxlZnRFbmQudG9wLCByaWdodFN0YXJ0LmxlZnQgLSBsZWZ0RW5kLnJpZ2h0LCBsZWZ0RW5kLmJvdHRvbSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGlmIChsZWZ0RW5kLmJvdHRvbSA8IHJpZ2h0U3RhcnQudG9wKVxuICAgICAgICB7IGFkZChsZWZ0U2lkZSwgbGVmdEVuZC5ib3R0b20sIG51bGwsIHJpZ2h0U3RhcnQudG9wKTsgfVxuICAgIH1cblxuICAgIG91dHB1dC5hcHBlbmRDaGlsZChmcmFnbWVudCk7XG4gIH1cblxuICAvLyBDdXJzb3ItYmxpbmtpbmdcbiAgZnVuY3Rpb24gcmVzdGFydEJsaW5rKGNtKSB7XG4gICAgaWYgKCFjbS5zdGF0ZS5mb2N1c2VkKSB7IHJldHVybiB9XG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5O1xuICAgIGNsZWFySW50ZXJ2YWwoZGlzcGxheS5ibGlua2VyKTtcbiAgICB2YXIgb24gPSB0cnVlO1xuICAgIGRpc3BsYXkuY3Vyc29yRGl2LnN0eWxlLnZpc2liaWxpdHkgPSBcIlwiO1xuICAgIGlmIChjbS5vcHRpb25zLmN1cnNvckJsaW5rUmF0ZSA+IDApXG4gICAgICB7IGRpc3BsYXkuYmxpbmtlciA9IHNldEludGVydmFsKGZ1bmN0aW9uICgpIHsgcmV0dXJuIGRpc3BsYXkuY3Vyc29yRGl2LnN0eWxlLnZpc2liaWxpdHkgPSAob24gPSAhb24pID8gXCJcIiA6IFwiaGlkZGVuXCI7IH0sXG4gICAgICAgIGNtLm9wdGlvbnMuY3Vyc29yQmxpbmtSYXRlKTsgfVxuICAgIGVsc2UgaWYgKGNtLm9wdGlvbnMuY3Vyc29yQmxpbmtSYXRlIDwgMClcbiAgICAgIHsgZGlzcGxheS5jdXJzb3JEaXYuc3R5bGUudmlzaWJpbGl0eSA9IFwiaGlkZGVuXCI7IH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGVuc3VyZUZvY3VzKGNtKSB7XG4gICAgaWYgKCFjbS5zdGF0ZS5mb2N1c2VkKSB7IGNtLmRpc3BsYXkuaW5wdXQuZm9jdXMoKTsgb25Gb2N1cyhjbSk7IH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGRlbGF5Qmx1ckV2ZW50KGNtKSB7XG4gICAgY20uc3RhdGUuZGVsYXlpbmdCbHVyRXZlbnQgPSB0cnVlO1xuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyBpZiAoY20uc3RhdGUuZGVsYXlpbmdCbHVyRXZlbnQpIHtcbiAgICAgIGNtLnN0YXRlLmRlbGF5aW5nQmx1ckV2ZW50ID0gZmFsc2U7XG4gICAgICBvbkJsdXIoY20pO1xuICAgIH0gfSwgMTAwKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG9uRm9jdXMoY20sIGUpIHtcbiAgICBpZiAoY20uc3RhdGUuZGVsYXlpbmdCbHVyRXZlbnQpIHsgY20uc3RhdGUuZGVsYXlpbmdCbHVyRXZlbnQgPSBmYWxzZTsgfVxuXG4gICAgaWYgKGNtLm9wdGlvbnMucmVhZE9ubHkgPT0gXCJub2N1cnNvclwiKSB7IHJldHVybiB9XG4gICAgaWYgKCFjbS5zdGF0ZS5mb2N1c2VkKSB7XG4gICAgICBzaWduYWwoY20sIFwiZm9jdXNcIiwgY20sIGUpO1xuICAgICAgY20uc3RhdGUuZm9jdXNlZCA9IHRydWU7XG4gICAgICBhZGRDbGFzcyhjbS5kaXNwbGF5LndyYXBwZXIsIFwiQ29kZU1pcnJvci1mb2N1c2VkXCIpO1xuICAgICAgLy8gVGhpcyB0ZXN0IHByZXZlbnRzIHRoaXMgZnJvbSBmaXJpbmcgd2hlbiBhIGNvbnRleHRcbiAgICAgIC8vIG1lbnUgaXMgY2xvc2VkIChzaW5jZSB0aGUgaW5wdXQgcmVzZXQgd291bGQga2lsbCB0aGVcbiAgICAgIC8vIHNlbGVjdC1hbGwgZGV0ZWN0aW9uIGhhY2spXG4gICAgICBpZiAoIWNtLmN1ck9wICYmIGNtLmRpc3BsYXkuc2VsRm9yQ29udGV4dE1lbnUgIT0gY20uZG9jLnNlbCkge1xuICAgICAgICBjbS5kaXNwbGF5LmlucHV0LnJlc2V0KCk7XG4gICAgICAgIGlmICh3ZWJraXQpIHsgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7IHJldHVybiBjbS5kaXNwbGF5LmlucHV0LnJlc2V0KHRydWUpOyB9LCAyMCk7IH0gLy8gSXNzdWUgIzE3MzBcbiAgICAgIH1cbiAgICAgIGNtLmRpc3BsYXkuaW5wdXQucmVjZWl2ZWRGb2N1cygpO1xuICAgIH1cbiAgICByZXN0YXJ0QmxpbmsoY20pO1xuICB9XG4gIGZ1bmN0aW9uIG9uQmx1cihjbSwgZSkge1xuICAgIGlmIChjbS5zdGF0ZS5kZWxheWluZ0JsdXJFdmVudCkgeyByZXR1cm4gfVxuXG4gICAgaWYgKGNtLnN0YXRlLmZvY3VzZWQpIHtcbiAgICAgIHNpZ25hbChjbSwgXCJibHVyXCIsIGNtLCBlKTtcbiAgICAgIGNtLnN0YXRlLmZvY3VzZWQgPSBmYWxzZTtcbiAgICAgIHJtQ2xhc3MoY20uZGlzcGxheS53cmFwcGVyLCBcIkNvZGVNaXJyb3ItZm9jdXNlZFwiKTtcbiAgICB9XG4gICAgY2xlYXJJbnRlcnZhbChjbS5kaXNwbGF5LmJsaW5rZXIpO1xuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyBpZiAoIWNtLnN0YXRlLmZvY3VzZWQpIHsgY20uZGlzcGxheS5zaGlmdCA9IGZhbHNlOyB9IH0sIDE1MCk7XG4gIH1cblxuICAvLyBSZWFkIHRoZSBhY3R1YWwgaGVpZ2h0cyBvZiB0aGUgcmVuZGVyZWQgbGluZXMsIGFuZCB1cGRhdGUgdGhlaXJcbiAgLy8gc3RvcmVkIGhlaWdodHMgdG8gbWF0Y2guXG4gIGZ1bmN0aW9uIHVwZGF0ZUhlaWdodHNJblZpZXdwb3J0KGNtKSB7XG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5O1xuICAgIHZhciBwcmV2Qm90dG9tID0gZGlzcGxheS5saW5lRGl2Lm9mZnNldFRvcDtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGRpc3BsYXkudmlldy5sZW5ndGg7IGkrKykge1xuICAgICAgdmFyIGN1ciA9IGRpc3BsYXkudmlld1tpXSwgd3JhcHBpbmcgPSBjbS5vcHRpb25zLmxpbmVXcmFwcGluZztcbiAgICAgIHZhciBoZWlnaHQgPSAodm9pZCAwKSwgd2lkdGggPSAwO1xuICAgICAgaWYgKGN1ci5oaWRkZW4pIHsgY29udGludWUgfVxuICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCA4KSB7XG4gICAgICAgIHZhciBib3QgPSBjdXIubm9kZS5vZmZzZXRUb3AgKyBjdXIubm9kZS5vZmZzZXRIZWlnaHQ7XG4gICAgICAgIGhlaWdodCA9IGJvdCAtIHByZXZCb3R0b207XG4gICAgICAgIHByZXZCb3R0b20gPSBib3Q7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgYm94ID0gY3VyLm5vZGUuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICAgIGhlaWdodCA9IGJveC5ib3R0b20gLSBib3gudG9wO1xuICAgICAgICAvLyBDaGVjayB0aGF0IGxpbmVzIGRvbid0IGV4dGVuZCBwYXN0IHRoZSByaWdodCBvZiB0aGUgY3VycmVudFxuICAgICAgICAvLyBlZGl0b3Igd2lkdGhcbiAgICAgICAgaWYgKCF3cmFwcGluZyAmJiBjdXIudGV4dC5maXJzdENoaWxkKVxuICAgICAgICAgIHsgd2lkdGggPSBjdXIudGV4dC5maXJzdENoaWxkLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLnJpZ2h0IC0gYm94LmxlZnQgLSAxOyB9XG4gICAgICB9XG4gICAgICB2YXIgZGlmZiA9IGN1ci5saW5lLmhlaWdodCAtIGhlaWdodDtcbiAgICAgIGlmIChoZWlnaHQgPCAyKSB7IGhlaWdodCA9IHRleHRIZWlnaHQoZGlzcGxheSk7IH1cbiAgICAgIGlmIChkaWZmID4gLjAwNSB8fCBkaWZmIDwgLS4wMDUpIHtcbiAgICAgICAgdXBkYXRlTGluZUhlaWdodChjdXIubGluZSwgaGVpZ2h0KTtcbiAgICAgICAgdXBkYXRlV2lkZ2V0SGVpZ2h0KGN1ci5saW5lKTtcbiAgICAgICAgaWYgKGN1ci5yZXN0KSB7IGZvciAodmFyIGogPSAwOyBqIDwgY3VyLnJlc3QubGVuZ3RoOyBqKyspXG4gICAgICAgICAgeyB1cGRhdGVXaWRnZXRIZWlnaHQoY3VyLnJlc3Rbal0pOyB9IH1cbiAgICAgIH1cbiAgICAgIGlmICh3aWR0aCA+IGNtLmRpc3BsYXkuc2l6ZXJXaWR0aCkge1xuICAgICAgICB2YXIgY2hXaWR0aCA9IE1hdGguY2VpbCh3aWR0aCAvIGNoYXJXaWR0aChjbS5kaXNwbGF5KSk7XG4gICAgICAgIGlmIChjaFdpZHRoID4gY20uZGlzcGxheS5tYXhMaW5lTGVuZ3RoKSB7XG4gICAgICAgICAgY20uZGlzcGxheS5tYXhMaW5lTGVuZ3RoID0gY2hXaWR0aDtcbiAgICAgICAgICBjbS5kaXNwbGF5Lm1heExpbmUgPSBjdXIubGluZTtcbiAgICAgICAgICBjbS5kaXNwbGF5Lm1heExpbmVDaGFuZ2VkID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFJlYWQgYW5kIHN0b3JlIHRoZSBoZWlnaHQgb2YgbGluZSB3aWRnZXRzIGFzc29jaWF0ZWQgd2l0aCB0aGVcbiAgLy8gZ2l2ZW4gbGluZS5cbiAgZnVuY3Rpb24gdXBkYXRlV2lkZ2V0SGVpZ2h0KGxpbmUpIHtcbiAgICBpZiAobGluZS53aWRnZXRzKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgbGluZS53aWRnZXRzLmxlbmd0aDsgKytpKSB7XG4gICAgICB2YXIgdyA9IGxpbmUud2lkZ2V0c1tpXSwgcGFyZW50ID0gdy5ub2RlLnBhcmVudE5vZGU7XG4gICAgICBpZiAocGFyZW50KSB7IHcuaGVpZ2h0ID0gcGFyZW50Lm9mZnNldEhlaWdodDsgfVxuICAgIH0gfVxuICB9XG5cbiAgLy8gQ29tcHV0ZSB0aGUgbGluZXMgdGhhdCBhcmUgdmlzaWJsZSBpbiBhIGdpdmVuIHZpZXdwb3J0IChkZWZhdWx0c1xuICAvLyB0aGUgdGhlIGN1cnJlbnQgc2Nyb2xsIHBvc2l0aW9uKS4gdmlld3BvcnQgbWF5IGNvbnRhaW4gdG9wLFxuICAvLyBoZWlnaHQsIGFuZCBlbnN1cmUgKHNlZSBvcC5zY3JvbGxUb1BvcykgcHJvcGVydGllcy5cbiAgZnVuY3Rpb24gdmlzaWJsZUxpbmVzKGRpc3BsYXksIGRvYywgdmlld3BvcnQpIHtcbiAgICB2YXIgdG9wID0gdmlld3BvcnQgJiYgdmlld3BvcnQudG9wICE9IG51bGwgPyBNYXRoLm1heCgwLCB2aWV3cG9ydC50b3ApIDogZGlzcGxheS5zY3JvbGxlci5zY3JvbGxUb3A7XG4gICAgdG9wID0gTWF0aC5mbG9vcih0b3AgLSBwYWRkaW5nVG9wKGRpc3BsYXkpKTtcbiAgICB2YXIgYm90dG9tID0gdmlld3BvcnQgJiYgdmlld3BvcnQuYm90dG9tICE9IG51bGwgPyB2aWV3cG9ydC5ib3R0b20gOiB0b3AgKyBkaXNwbGF5LndyYXBwZXIuY2xpZW50SGVpZ2h0O1xuXG4gICAgdmFyIGZyb20gPSBsaW5lQXRIZWlnaHQoZG9jLCB0b3ApLCB0byA9IGxpbmVBdEhlaWdodChkb2MsIGJvdHRvbSk7XG4gICAgLy8gRW5zdXJlIGlzIGEge2Zyb206IHtsaW5lLCBjaH0sIHRvOiB7bGluZSwgY2h9fSBvYmplY3QsIGFuZFxuICAgIC8vIGZvcmNlcyB0aG9zZSBsaW5lcyBpbnRvIHRoZSB2aWV3cG9ydCAoaWYgcG9zc2libGUpLlxuICAgIGlmICh2aWV3cG9ydCAmJiB2aWV3cG9ydC5lbnN1cmUpIHtcbiAgICAgIHZhciBlbnN1cmVGcm9tID0gdmlld3BvcnQuZW5zdXJlLmZyb20ubGluZSwgZW5zdXJlVG8gPSB2aWV3cG9ydC5lbnN1cmUudG8ubGluZTtcbiAgICAgIGlmIChlbnN1cmVGcm9tIDwgZnJvbSkge1xuICAgICAgICBmcm9tID0gZW5zdXJlRnJvbTtcbiAgICAgICAgdG8gPSBsaW5lQXRIZWlnaHQoZG9jLCBoZWlnaHRBdExpbmUoZ2V0TGluZShkb2MsIGVuc3VyZUZyb20pKSArIGRpc3BsYXkud3JhcHBlci5jbGllbnRIZWlnaHQpO1xuICAgICAgfSBlbHNlIGlmIChNYXRoLm1pbihlbnN1cmVUbywgZG9jLmxhc3RMaW5lKCkpID49IHRvKSB7XG4gICAgICAgIGZyb20gPSBsaW5lQXRIZWlnaHQoZG9jLCBoZWlnaHRBdExpbmUoZ2V0TGluZShkb2MsIGVuc3VyZVRvKSkgLSBkaXNwbGF5LndyYXBwZXIuY2xpZW50SGVpZ2h0KTtcbiAgICAgICAgdG8gPSBlbnN1cmVUbztcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHtmcm9tOiBmcm9tLCB0bzogTWF0aC5tYXgodG8sIGZyb20gKyAxKX1cbiAgfVxuXG4gIC8vIFJlLWFsaWduIGxpbmUgbnVtYmVycyBhbmQgZ3V0dGVyIG1hcmtzIHRvIGNvbXBlbnNhdGUgZm9yXG4gIC8vIGhvcml6b250YWwgc2Nyb2xsaW5nLlxuICBmdW5jdGlvbiBhbGlnbkhvcml6b250YWxseShjbSkge1xuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheSwgdmlldyA9IGRpc3BsYXkudmlldztcbiAgICBpZiAoIWRpc3BsYXkuYWxpZ25XaWRnZXRzICYmICghZGlzcGxheS5ndXR0ZXJzLmZpcnN0Q2hpbGQgfHwgIWNtLm9wdGlvbnMuZml4ZWRHdXR0ZXIpKSB7IHJldHVybiB9XG4gICAgdmFyIGNvbXAgPSBjb21wZW5zYXRlRm9ySFNjcm9sbChkaXNwbGF5KSAtIGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsTGVmdCArIGNtLmRvYy5zY3JvbGxMZWZ0O1xuICAgIHZhciBndXR0ZXJXID0gZGlzcGxheS5ndXR0ZXJzLm9mZnNldFdpZHRoLCBsZWZ0ID0gY29tcCArIFwicHhcIjtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHZpZXcubGVuZ3RoOyBpKyspIHsgaWYgKCF2aWV3W2ldLmhpZGRlbikge1xuICAgICAgaWYgKGNtLm9wdGlvbnMuZml4ZWRHdXR0ZXIpIHtcbiAgICAgICAgaWYgKHZpZXdbaV0uZ3V0dGVyKVxuICAgICAgICAgIHsgdmlld1tpXS5ndXR0ZXIuc3R5bGUubGVmdCA9IGxlZnQ7IH1cbiAgICAgICAgaWYgKHZpZXdbaV0uZ3V0dGVyQmFja2dyb3VuZClcbiAgICAgICAgICB7IHZpZXdbaV0uZ3V0dGVyQmFja2dyb3VuZC5zdHlsZS5sZWZ0ID0gbGVmdDsgfVxuICAgICAgfVxuICAgICAgdmFyIGFsaWduID0gdmlld1tpXS5hbGlnbmFibGU7XG4gICAgICBpZiAoYWxpZ24pIHsgZm9yICh2YXIgaiA9IDA7IGogPCBhbGlnbi5sZW5ndGg7IGorKylcbiAgICAgICAgeyBhbGlnbltqXS5zdHlsZS5sZWZ0ID0gbGVmdDsgfSB9XG4gICAgfSB9XG4gICAgaWYgKGNtLm9wdGlvbnMuZml4ZWRHdXR0ZXIpXG4gICAgICB7IGRpc3BsYXkuZ3V0dGVycy5zdHlsZS5sZWZ0ID0gKGNvbXAgKyBndXR0ZXJXKSArIFwicHhcIjsgfVxuICB9XG5cbiAgLy8gVXNlZCB0byBlbnN1cmUgdGhhdCB0aGUgbGluZSBudW1iZXIgZ3V0dGVyIGlzIHN0aWxsIHRoZSByaWdodFxuICAvLyBzaXplIGZvciB0aGUgY3VycmVudCBkb2N1bWVudCBzaXplLiBSZXR1cm5zIHRydWUgd2hlbiBhbiB1cGRhdGVcbiAgLy8gaXMgbmVlZGVkLlxuICBmdW5jdGlvbiBtYXliZVVwZGF0ZUxpbmVOdW1iZXJXaWR0aChjbSkge1xuICAgIGlmICghY20ub3B0aW9ucy5saW5lTnVtYmVycykgeyByZXR1cm4gZmFsc2UgfVxuICAgIHZhciBkb2MgPSBjbS5kb2MsIGxhc3QgPSBsaW5lTnVtYmVyRm9yKGNtLm9wdGlvbnMsIGRvYy5maXJzdCArIGRvYy5zaXplIC0gMSksIGRpc3BsYXkgPSBjbS5kaXNwbGF5O1xuICAgIGlmIChsYXN0Lmxlbmd0aCAhPSBkaXNwbGF5LmxpbmVOdW1DaGFycykge1xuICAgICAgdmFyIHRlc3QgPSBkaXNwbGF5Lm1lYXN1cmUuYXBwZW5kQ2hpbGQoZWx0KFwiZGl2XCIsIFtlbHQoXCJkaXZcIiwgbGFzdCldLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiQ29kZU1pcnJvci1saW5lbnVtYmVyIENvZGVNaXJyb3ItZ3V0dGVyLWVsdFwiKSk7XG4gICAgICB2YXIgaW5uZXJXID0gdGVzdC5maXJzdENoaWxkLm9mZnNldFdpZHRoLCBwYWRkaW5nID0gdGVzdC5vZmZzZXRXaWR0aCAtIGlubmVyVztcbiAgICAgIGRpc3BsYXkubGluZUd1dHRlci5zdHlsZS53aWR0aCA9IFwiXCI7XG4gICAgICBkaXNwbGF5LmxpbmVOdW1Jbm5lcldpZHRoID0gTWF0aC5tYXgoaW5uZXJXLCBkaXNwbGF5LmxpbmVHdXR0ZXIub2Zmc2V0V2lkdGggLSBwYWRkaW5nKSArIDE7XG4gICAgICBkaXNwbGF5LmxpbmVOdW1XaWR0aCA9IGRpc3BsYXkubGluZU51bUlubmVyV2lkdGggKyBwYWRkaW5nO1xuICAgICAgZGlzcGxheS5saW5lTnVtQ2hhcnMgPSBkaXNwbGF5LmxpbmVOdW1Jbm5lcldpZHRoID8gbGFzdC5sZW5ndGggOiAtMTtcbiAgICAgIGRpc3BsYXkubGluZUd1dHRlci5zdHlsZS53aWR0aCA9IGRpc3BsYXkubGluZU51bVdpZHRoICsgXCJweFwiO1xuICAgICAgdXBkYXRlR3V0dGVyU3BhY2UoY20pO1xuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG4gICAgcmV0dXJuIGZhbHNlXG4gIH1cblxuICAvLyBTQ1JPTExJTkcgVEhJTkdTIElOVE8gVklFV1xuXG4gIC8vIElmIGFuIGVkaXRvciBzaXRzIG9uIHRoZSB0b3Agb3IgYm90dG9tIG9mIHRoZSB3aW5kb3csIHBhcnRpYWxseVxuICAvLyBzY3JvbGxlZCBvdXQgb2YgdmlldywgdGhpcyBlbnN1cmVzIHRoYXQgdGhlIGN1cnNvciBpcyB2aXNpYmxlLlxuICBmdW5jdGlvbiBtYXliZVNjcm9sbFdpbmRvdyhjbSwgcmVjdCkge1xuICAgIGlmIChzaWduYWxET01FdmVudChjbSwgXCJzY3JvbGxDdXJzb3JJbnRvVmlld1wiKSkgeyByZXR1cm4gfVxuXG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBib3ggPSBkaXNwbGF5LnNpemVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpLCBkb1Njcm9sbCA9IG51bGw7XG4gICAgaWYgKHJlY3QudG9wICsgYm94LnRvcCA8IDApIHsgZG9TY3JvbGwgPSB0cnVlOyB9XG4gICAgZWxzZSBpZiAocmVjdC5ib3R0b20gKyBib3gudG9wID4gKHdpbmRvdy5pbm5lckhlaWdodCB8fCBkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuY2xpZW50SGVpZ2h0KSkgeyBkb1Njcm9sbCA9IGZhbHNlOyB9XG4gICAgaWYgKGRvU2Nyb2xsICE9IG51bGwgJiYgIXBoYW50b20pIHtcbiAgICAgIHZhciBzY3JvbGxOb2RlID0gZWx0KFwiZGl2XCIsIFwiXFx1MjAwYlwiLCBudWxsLCAoXCJwb3NpdGlvbjogYWJzb2x1dGU7XFxuICAgICAgICAgICAgICAgICAgICAgICAgIHRvcDogXCIgKyAocmVjdC50b3AgLSBkaXNwbGF5LnZpZXdPZmZzZXQgLSBwYWRkaW5nVG9wKGNtLmRpc3BsYXkpKSArIFwicHg7XFxuICAgICAgICAgICAgICAgICAgICAgICAgIGhlaWdodDogXCIgKyAocmVjdC5ib3R0b20gLSByZWN0LnRvcCArIHNjcm9sbEdhcChjbSkgKyBkaXNwbGF5LmJhckhlaWdodCkgKyBcInB4O1xcbiAgICAgICAgICAgICAgICAgICAgICAgICBsZWZ0OiBcIiArIChyZWN0LmxlZnQpICsgXCJweDsgd2lkdGg6IFwiICsgKE1hdGgubWF4KDIsIHJlY3QucmlnaHQgLSByZWN0LmxlZnQpKSArIFwicHg7XCIpKTtcbiAgICAgIGNtLmRpc3BsYXkubGluZVNwYWNlLmFwcGVuZENoaWxkKHNjcm9sbE5vZGUpO1xuICAgICAgc2Nyb2xsTm9kZS5zY3JvbGxJbnRvVmlldyhkb1Njcm9sbCk7XG4gICAgICBjbS5kaXNwbGF5LmxpbmVTcGFjZS5yZW1vdmVDaGlsZChzY3JvbGxOb2RlKTtcbiAgICB9XG4gIH1cblxuICAvLyBTY3JvbGwgYSBnaXZlbiBwb3NpdGlvbiBpbnRvIHZpZXcgKGltbWVkaWF0ZWx5KSwgdmVyaWZ5aW5nIHRoYXRcbiAgLy8gaXQgYWN0dWFsbHkgYmVjYW1lIHZpc2libGUgKGFzIGxpbmUgaGVpZ2h0cyBhcmUgYWNjdXJhdGVseVxuICAvLyBtZWFzdXJlZCwgdGhlIHBvc2l0aW9uIG9mIHNvbWV0aGluZyBtYXkgJ2RyaWZ0JyBkdXJpbmcgZHJhd2luZykuXG4gIGZ1bmN0aW9uIHNjcm9sbFBvc0ludG9WaWV3KGNtLCBwb3MsIGVuZCwgbWFyZ2luKSB7XG4gICAgaWYgKG1hcmdpbiA9PSBudWxsKSB7IG1hcmdpbiA9IDA7IH1cbiAgICB2YXIgcmVjdDtcbiAgICBpZiAoIWNtLm9wdGlvbnMubGluZVdyYXBwaW5nICYmIHBvcyA9PSBlbmQpIHtcbiAgICAgIC8vIFNldCBwb3MgYW5kIGVuZCB0byB0aGUgY3Vyc29yIHBvc2l0aW9ucyBhcm91bmQgdGhlIGNoYXJhY3RlciBwb3Mgc3RpY2tzIHRvXG4gICAgICAvLyBJZiBwb3Muc3RpY2t5ID09IFwiYmVmb3JlXCIsIHRoYXQgaXMgYXJvdW5kIHBvcy5jaCAtIDEsIG90aGVyd2lzZSBhcm91bmQgcG9zLmNoXG4gICAgICAvLyBJZiBwb3MgPT0gUG9zKF8sIDAsIFwiYmVmb3JlXCIpLCBwb3MgYW5kIGVuZCBhcmUgdW5jaGFuZ2VkXG4gICAgICBwb3MgPSBwb3MuY2ggPyBQb3MocG9zLmxpbmUsIHBvcy5zdGlja3kgPT0gXCJiZWZvcmVcIiA/IHBvcy5jaCAtIDEgOiBwb3MuY2gsIFwiYWZ0ZXJcIikgOiBwb3M7XG4gICAgICBlbmQgPSBwb3Muc3RpY2t5ID09IFwiYmVmb3JlXCIgPyBQb3MocG9zLmxpbmUsIHBvcy5jaCArIDEsIFwiYmVmb3JlXCIpIDogcG9zO1xuICAgIH1cbiAgICBmb3IgKHZhciBsaW1pdCA9IDA7IGxpbWl0IDwgNTsgbGltaXQrKykge1xuICAgICAgdmFyIGNoYW5nZWQgPSBmYWxzZTtcbiAgICAgIHZhciBjb29yZHMgPSBjdXJzb3JDb29yZHMoY20sIHBvcyk7XG4gICAgICB2YXIgZW5kQ29vcmRzID0gIWVuZCB8fCBlbmQgPT0gcG9zID8gY29vcmRzIDogY3Vyc29yQ29vcmRzKGNtLCBlbmQpO1xuICAgICAgcmVjdCA9IHtsZWZ0OiBNYXRoLm1pbihjb29yZHMubGVmdCwgZW5kQ29vcmRzLmxlZnQpLFxuICAgICAgICAgICAgICB0b3A6IE1hdGgubWluKGNvb3Jkcy50b3AsIGVuZENvb3Jkcy50b3ApIC0gbWFyZ2luLFxuICAgICAgICAgICAgICByaWdodDogTWF0aC5tYXgoY29vcmRzLmxlZnQsIGVuZENvb3Jkcy5sZWZ0KSxcbiAgICAgICAgICAgICAgYm90dG9tOiBNYXRoLm1heChjb29yZHMuYm90dG9tLCBlbmRDb29yZHMuYm90dG9tKSArIG1hcmdpbn07XG4gICAgICB2YXIgc2Nyb2xsUG9zID0gY2FsY3VsYXRlU2Nyb2xsUG9zKGNtLCByZWN0KTtcbiAgICAgIHZhciBzdGFydFRvcCA9IGNtLmRvYy5zY3JvbGxUb3AsIHN0YXJ0TGVmdCA9IGNtLmRvYy5zY3JvbGxMZWZ0O1xuICAgICAgaWYgKHNjcm9sbFBvcy5zY3JvbGxUb3AgIT0gbnVsbCkge1xuICAgICAgICB1cGRhdGVTY3JvbGxUb3AoY20sIHNjcm9sbFBvcy5zY3JvbGxUb3ApO1xuICAgICAgICBpZiAoTWF0aC5hYnMoY20uZG9jLnNjcm9sbFRvcCAtIHN0YXJ0VG9wKSA+IDEpIHsgY2hhbmdlZCA9IHRydWU7IH1cbiAgICAgIH1cbiAgICAgIGlmIChzY3JvbGxQb3Muc2Nyb2xsTGVmdCAhPSBudWxsKSB7XG4gICAgICAgIHNldFNjcm9sbExlZnQoY20sIHNjcm9sbFBvcy5zY3JvbGxMZWZ0KTtcbiAgICAgICAgaWYgKE1hdGguYWJzKGNtLmRvYy5zY3JvbGxMZWZ0IC0gc3RhcnRMZWZ0KSA+IDEpIHsgY2hhbmdlZCA9IHRydWU7IH1cbiAgICAgIH1cbiAgICAgIGlmICghY2hhbmdlZCkgeyBicmVhayB9XG4gICAgfVxuICAgIHJldHVybiByZWN0XG4gIH1cblxuICAvLyBTY3JvbGwgYSBnaXZlbiBzZXQgb2YgY29vcmRpbmF0ZXMgaW50byB2aWV3IChpbW1lZGlhdGVseSkuXG4gIGZ1bmN0aW9uIHNjcm9sbEludG9WaWV3KGNtLCByZWN0KSB7XG4gICAgdmFyIHNjcm9sbFBvcyA9IGNhbGN1bGF0ZVNjcm9sbFBvcyhjbSwgcmVjdCk7XG4gICAgaWYgKHNjcm9sbFBvcy5zY3JvbGxUb3AgIT0gbnVsbCkgeyB1cGRhdGVTY3JvbGxUb3AoY20sIHNjcm9sbFBvcy5zY3JvbGxUb3ApOyB9XG4gICAgaWYgKHNjcm9sbFBvcy5zY3JvbGxMZWZ0ICE9IG51bGwpIHsgc2V0U2Nyb2xsTGVmdChjbSwgc2Nyb2xsUG9zLnNjcm9sbExlZnQpOyB9XG4gIH1cblxuICAvLyBDYWxjdWxhdGUgYSBuZXcgc2Nyb2xsIHBvc2l0aW9uIG5lZWRlZCB0byBzY3JvbGwgdGhlIGdpdmVuXG4gIC8vIHJlY3RhbmdsZSBpbnRvIHZpZXcuIFJldHVybnMgYW4gb2JqZWN0IHdpdGggc2Nyb2xsVG9wIGFuZFxuICAvLyBzY3JvbGxMZWZ0IHByb3BlcnRpZXMuIFdoZW4gdGhlc2UgYXJlIHVuZGVmaW5lZCwgdGhlXG4gIC8vIHZlcnRpY2FsL2hvcml6b250YWwgcG9zaXRpb24gZG9lcyBub3QgbmVlZCB0byBiZSBhZGp1c3RlZC5cbiAgZnVuY3Rpb24gY2FsY3VsYXRlU2Nyb2xsUG9zKGNtLCByZWN0KSB7XG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBzbmFwTWFyZ2luID0gdGV4dEhlaWdodChjbS5kaXNwbGF5KTtcbiAgICBpZiAocmVjdC50b3AgPCAwKSB7IHJlY3QudG9wID0gMDsgfVxuICAgIHZhciBzY3JlZW50b3AgPSBjbS5jdXJPcCAmJiBjbS5jdXJPcC5zY3JvbGxUb3AgIT0gbnVsbCA/IGNtLmN1ck9wLnNjcm9sbFRvcCA6IGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wO1xuICAgIHZhciBzY3JlZW4gPSBkaXNwbGF5SGVpZ2h0KGNtKSwgcmVzdWx0ID0ge307XG4gICAgaWYgKHJlY3QuYm90dG9tIC0gcmVjdC50b3AgPiBzY3JlZW4pIHsgcmVjdC5ib3R0b20gPSByZWN0LnRvcCArIHNjcmVlbjsgfVxuICAgIHZhciBkb2NCb3R0b20gPSBjbS5kb2MuaGVpZ2h0ICsgcGFkZGluZ1ZlcnQoZGlzcGxheSk7XG4gICAgdmFyIGF0VG9wID0gcmVjdC50b3AgPCBzbmFwTWFyZ2luLCBhdEJvdHRvbSA9IHJlY3QuYm90dG9tID4gZG9jQm90dG9tIC0gc25hcE1hcmdpbjtcbiAgICBpZiAocmVjdC50b3AgPCBzY3JlZW50b3ApIHtcbiAgICAgIHJlc3VsdC5zY3JvbGxUb3AgPSBhdFRvcCA/IDAgOiByZWN0LnRvcDtcbiAgICB9IGVsc2UgaWYgKHJlY3QuYm90dG9tID4gc2NyZWVudG9wICsgc2NyZWVuKSB7XG4gICAgICB2YXIgbmV3VG9wID0gTWF0aC5taW4ocmVjdC50b3AsIChhdEJvdHRvbSA/IGRvY0JvdHRvbSA6IHJlY3QuYm90dG9tKSAtIHNjcmVlbik7XG4gICAgICBpZiAobmV3VG9wICE9IHNjcmVlbnRvcCkgeyByZXN1bHQuc2Nyb2xsVG9wID0gbmV3VG9wOyB9XG4gICAgfVxuXG4gICAgdmFyIHNjcmVlbmxlZnQgPSBjbS5jdXJPcCAmJiBjbS5jdXJPcC5zY3JvbGxMZWZ0ICE9IG51bGwgPyBjbS5jdXJPcC5zY3JvbGxMZWZ0IDogZGlzcGxheS5zY3JvbGxlci5zY3JvbGxMZWZ0O1xuICAgIHZhciBzY3JlZW53ID0gZGlzcGxheVdpZHRoKGNtKSAtIChjbS5vcHRpb25zLmZpeGVkR3V0dGVyID8gZGlzcGxheS5ndXR0ZXJzLm9mZnNldFdpZHRoIDogMCk7XG4gICAgdmFyIHRvb1dpZGUgPSByZWN0LnJpZ2h0IC0gcmVjdC5sZWZ0ID4gc2NyZWVudztcbiAgICBpZiAodG9vV2lkZSkgeyByZWN0LnJpZ2h0ID0gcmVjdC5sZWZ0ICsgc2NyZWVudzsgfVxuICAgIGlmIChyZWN0LmxlZnQgPCAxMClcbiAgICAgIHsgcmVzdWx0LnNjcm9sbExlZnQgPSAwOyB9XG4gICAgZWxzZSBpZiAocmVjdC5sZWZ0IDwgc2NyZWVubGVmdClcbiAgICAgIHsgcmVzdWx0LnNjcm9sbExlZnQgPSBNYXRoLm1heCgwLCByZWN0LmxlZnQgLSAodG9vV2lkZSA/IDAgOiAxMCkpOyB9XG4gICAgZWxzZSBpZiAocmVjdC5yaWdodCA+IHNjcmVlbncgKyBzY3JlZW5sZWZ0IC0gMylcbiAgICAgIHsgcmVzdWx0LnNjcm9sbExlZnQgPSByZWN0LnJpZ2h0ICsgKHRvb1dpZGUgPyAwIDogMTApIC0gc2NyZWVudzsgfVxuICAgIHJldHVybiByZXN1bHRcbiAgfVxuXG4gIC8vIFN0b3JlIGEgcmVsYXRpdmUgYWRqdXN0bWVudCB0byB0aGUgc2Nyb2xsIHBvc2l0aW9uIGluIHRoZSBjdXJyZW50XG4gIC8vIG9wZXJhdGlvbiAodG8gYmUgYXBwbGllZCB3aGVuIHRoZSBvcGVyYXRpb24gZmluaXNoZXMpLlxuICBmdW5jdGlvbiBhZGRUb1Njcm9sbFRvcChjbSwgdG9wKSB7XG4gICAgaWYgKHRvcCA9PSBudWxsKSB7IHJldHVybiB9XG4gICAgcmVzb2x2ZVNjcm9sbFRvUG9zKGNtKTtcbiAgICBjbS5jdXJPcC5zY3JvbGxUb3AgPSAoY20uY3VyT3Auc2Nyb2xsVG9wID09IG51bGwgPyBjbS5kb2Muc2Nyb2xsVG9wIDogY20uY3VyT3Auc2Nyb2xsVG9wKSArIHRvcDtcbiAgfVxuXG4gIC8vIE1ha2Ugc3VyZSB0aGF0IGF0IHRoZSBlbmQgb2YgdGhlIG9wZXJhdGlvbiB0aGUgY3VycmVudCBjdXJzb3IgaXNcbiAgLy8gc2hvd24uXG4gIGZ1bmN0aW9uIGVuc3VyZUN1cnNvclZpc2libGUoY20pIHtcbiAgICByZXNvbHZlU2Nyb2xsVG9Qb3MoY20pO1xuICAgIHZhciBjdXIgPSBjbS5nZXRDdXJzb3IoKTtcbiAgICBjbS5jdXJPcC5zY3JvbGxUb1BvcyA9IHtmcm9tOiBjdXIsIHRvOiBjdXIsIG1hcmdpbjogY20ub3B0aW9ucy5jdXJzb3JTY3JvbGxNYXJnaW59O1xuICB9XG5cbiAgZnVuY3Rpb24gc2Nyb2xsVG9Db29yZHMoY20sIHgsIHkpIHtcbiAgICBpZiAoeCAhPSBudWxsIHx8IHkgIT0gbnVsbCkgeyByZXNvbHZlU2Nyb2xsVG9Qb3MoY20pOyB9XG4gICAgaWYgKHggIT0gbnVsbCkgeyBjbS5jdXJPcC5zY3JvbGxMZWZ0ID0geDsgfVxuICAgIGlmICh5ICE9IG51bGwpIHsgY20uY3VyT3Auc2Nyb2xsVG9wID0geTsgfVxuICB9XG5cbiAgZnVuY3Rpb24gc2Nyb2xsVG9SYW5nZShjbSwgcmFuZ2UkJDEpIHtcbiAgICByZXNvbHZlU2Nyb2xsVG9Qb3MoY20pO1xuICAgIGNtLmN1ck9wLnNjcm9sbFRvUG9zID0gcmFuZ2UkJDE7XG4gIH1cblxuICAvLyBXaGVuIGFuIG9wZXJhdGlvbiBoYXMgaXRzIHNjcm9sbFRvUG9zIHByb3BlcnR5IHNldCwgYW5kIGFub3RoZXJcbiAgLy8gc2Nyb2xsIGFjdGlvbiBpcyBhcHBsaWVkIGJlZm9yZSB0aGUgZW5kIG9mIHRoZSBvcGVyYXRpb24sIHRoaXNcbiAgLy8gJ3NpbXVsYXRlcycgc2Nyb2xsaW5nIHRoYXQgcG9zaXRpb24gaW50byB2aWV3IGluIGEgY2hlYXAgd2F5LCBzb1xuICAvLyB0aGF0IHRoZSBlZmZlY3Qgb2YgaW50ZXJtZWRpYXRlIHNjcm9sbCBjb21tYW5kcyBpcyBub3QgaWdub3JlZC5cbiAgZnVuY3Rpb24gcmVzb2x2ZVNjcm9sbFRvUG9zKGNtKSB7XG4gICAgdmFyIHJhbmdlJCQxID0gY20uY3VyT3Auc2Nyb2xsVG9Qb3M7XG4gICAgaWYgKHJhbmdlJCQxKSB7XG4gICAgICBjbS5jdXJPcC5zY3JvbGxUb1BvcyA9IG51bGw7XG4gICAgICB2YXIgZnJvbSA9IGVzdGltYXRlQ29vcmRzKGNtLCByYW5nZSQkMS5mcm9tKSwgdG8gPSBlc3RpbWF0ZUNvb3JkcyhjbSwgcmFuZ2UkJDEudG8pO1xuICAgICAgc2Nyb2xsVG9Db29yZHNSYW5nZShjbSwgZnJvbSwgdG8sIHJhbmdlJCQxLm1hcmdpbik7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gc2Nyb2xsVG9Db29yZHNSYW5nZShjbSwgZnJvbSwgdG8sIG1hcmdpbikge1xuICAgIHZhciBzUG9zID0gY2FsY3VsYXRlU2Nyb2xsUG9zKGNtLCB7XG4gICAgICBsZWZ0OiBNYXRoLm1pbihmcm9tLmxlZnQsIHRvLmxlZnQpLFxuICAgICAgdG9wOiBNYXRoLm1pbihmcm9tLnRvcCwgdG8udG9wKSAtIG1hcmdpbixcbiAgICAgIHJpZ2h0OiBNYXRoLm1heChmcm9tLnJpZ2h0LCB0by5yaWdodCksXG4gICAgICBib3R0b206IE1hdGgubWF4KGZyb20uYm90dG9tLCB0by5ib3R0b20pICsgbWFyZ2luXG4gICAgfSk7XG4gICAgc2Nyb2xsVG9Db29yZHMoY20sIHNQb3Muc2Nyb2xsTGVmdCwgc1Bvcy5zY3JvbGxUb3ApO1xuICB9XG5cbiAgLy8gU3luYyB0aGUgc2Nyb2xsYWJsZSBhcmVhIGFuZCBzY3JvbGxiYXJzLCBlbnN1cmUgdGhlIHZpZXdwb3J0XG4gIC8vIGNvdmVycyB0aGUgdmlzaWJsZSBhcmVhLlxuICBmdW5jdGlvbiB1cGRhdGVTY3JvbGxUb3AoY20sIHZhbCkge1xuICAgIGlmIChNYXRoLmFicyhjbS5kb2Muc2Nyb2xsVG9wIC0gdmFsKSA8IDIpIHsgcmV0dXJuIH1cbiAgICBpZiAoIWdlY2tvKSB7IHVwZGF0ZURpc3BsYXlTaW1wbGUoY20sIHt0b3A6IHZhbH0pOyB9XG4gICAgc2V0U2Nyb2xsVG9wKGNtLCB2YWwsIHRydWUpO1xuICAgIGlmIChnZWNrbykgeyB1cGRhdGVEaXNwbGF5U2ltcGxlKGNtKTsgfVxuICAgIHN0YXJ0V29ya2VyKGNtLCAxMDApO1xuICB9XG5cbiAgZnVuY3Rpb24gc2V0U2Nyb2xsVG9wKGNtLCB2YWwsIGZvcmNlU2Nyb2xsKSB7XG4gICAgdmFsID0gTWF0aC5taW4oY20uZGlzcGxheS5zY3JvbGxlci5zY3JvbGxIZWlnaHQgLSBjbS5kaXNwbGF5LnNjcm9sbGVyLmNsaWVudEhlaWdodCwgdmFsKTtcbiAgICBpZiAoY20uZGlzcGxheS5zY3JvbGxlci5zY3JvbGxUb3AgPT0gdmFsICYmICFmb3JjZVNjcm9sbCkgeyByZXR1cm4gfVxuICAgIGNtLmRvYy5zY3JvbGxUb3AgPSB2YWw7XG4gICAgY20uZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbFRvcCh2YWwpO1xuICAgIGlmIChjbS5kaXNwbGF5LnNjcm9sbGVyLnNjcm9sbFRvcCAhPSB2YWwpIHsgY20uZGlzcGxheS5zY3JvbGxlci5zY3JvbGxUb3AgPSB2YWw7IH1cbiAgfVxuXG4gIC8vIFN5bmMgc2Nyb2xsZXIgYW5kIHNjcm9sbGJhciwgZW5zdXJlIHRoZSBndXR0ZXIgZWxlbWVudHMgYXJlXG4gIC8vIGFsaWduZWQuXG4gIGZ1bmN0aW9uIHNldFNjcm9sbExlZnQoY20sIHZhbCwgaXNTY3JvbGxlciwgZm9yY2VTY3JvbGwpIHtcbiAgICB2YWwgPSBNYXRoLm1pbih2YWwsIGNtLmRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsV2lkdGggLSBjbS5kaXNwbGF5LnNjcm9sbGVyLmNsaWVudFdpZHRoKTtcbiAgICBpZiAoKGlzU2Nyb2xsZXIgPyB2YWwgPT0gY20uZG9jLnNjcm9sbExlZnQgOiBNYXRoLmFicyhjbS5kb2Muc2Nyb2xsTGVmdCAtIHZhbCkgPCAyKSAmJiAhZm9yY2VTY3JvbGwpIHsgcmV0dXJuIH1cbiAgICBjbS5kb2Muc2Nyb2xsTGVmdCA9IHZhbDtcbiAgICBhbGlnbkhvcml6b250YWxseShjbSk7XG4gICAgaWYgKGNtLmRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsTGVmdCAhPSB2YWwpIHsgY20uZGlzcGxheS5zY3JvbGxlci5zY3JvbGxMZWZ0ID0gdmFsOyB9XG4gICAgY20uZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbExlZnQodmFsKTtcbiAgfVxuXG4gIC8vIFNDUk9MTEJBUlNcblxuICAvLyBQcmVwYXJlIERPTSByZWFkcyBuZWVkZWQgdG8gdXBkYXRlIHRoZSBzY3JvbGxiYXJzLiBEb25lIGluIG9uZVxuICAvLyBzaG90IHRvIG1pbmltaXplIHVwZGF0ZS9tZWFzdXJlIHJvdW5kdHJpcHMuXG4gIGZ1bmN0aW9uIG1lYXN1cmVGb3JTY3JvbGxiYXJzKGNtKSB7XG4gICAgdmFyIGQgPSBjbS5kaXNwbGF5LCBndXR0ZXJXID0gZC5ndXR0ZXJzLm9mZnNldFdpZHRoO1xuICAgIHZhciBkb2NIID0gTWF0aC5yb3VuZChjbS5kb2MuaGVpZ2h0ICsgcGFkZGluZ1ZlcnQoY20uZGlzcGxheSkpO1xuICAgIHJldHVybiB7XG4gICAgICBjbGllbnRIZWlnaHQ6IGQuc2Nyb2xsZXIuY2xpZW50SGVpZ2h0LFxuICAgICAgdmlld0hlaWdodDogZC53cmFwcGVyLmNsaWVudEhlaWdodCxcbiAgICAgIHNjcm9sbFdpZHRoOiBkLnNjcm9sbGVyLnNjcm9sbFdpZHRoLCBjbGllbnRXaWR0aDogZC5zY3JvbGxlci5jbGllbnRXaWR0aCxcbiAgICAgIHZpZXdXaWR0aDogZC53cmFwcGVyLmNsaWVudFdpZHRoLFxuICAgICAgYmFyTGVmdDogY20ub3B0aW9ucy5maXhlZEd1dHRlciA/IGd1dHRlclcgOiAwLFxuICAgICAgZG9jSGVpZ2h0OiBkb2NILFxuICAgICAgc2Nyb2xsSGVpZ2h0OiBkb2NIICsgc2Nyb2xsR2FwKGNtKSArIGQuYmFySGVpZ2h0LFxuICAgICAgbmF0aXZlQmFyV2lkdGg6IGQubmF0aXZlQmFyV2lkdGgsXG4gICAgICBndXR0ZXJXaWR0aDogZ3V0dGVyV1xuICAgIH1cbiAgfVxuXG4gIHZhciBOYXRpdmVTY3JvbGxiYXJzID0gZnVuY3Rpb24ocGxhY2UsIHNjcm9sbCwgY20pIHtcbiAgICB0aGlzLmNtID0gY207XG4gICAgdmFyIHZlcnQgPSB0aGlzLnZlcnQgPSBlbHQoXCJkaXZcIiwgW2VsdChcImRpdlwiLCBudWxsLCBudWxsLCBcIm1pbi13aWR0aDogMXB4XCIpXSwgXCJDb2RlTWlycm9yLXZzY3JvbGxiYXJcIik7XG4gICAgdmFyIGhvcml6ID0gdGhpcy5ob3JpeiA9IGVsdChcImRpdlwiLCBbZWx0KFwiZGl2XCIsIG51bGwsIG51bGwsIFwiaGVpZ2h0OiAxMDAlOyBtaW4taGVpZ2h0OiAxcHhcIildLCBcIkNvZGVNaXJyb3ItaHNjcm9sbGJhclwiKTtcbiAgICB2ZXJ0LnRhYkluZGV4ID0gaG9yaXoudGFiSW5kZXggPSAtMTtcbiAgICBwbGFjZSh2ZXJ0KTsgcGxhY2UoaG9yaXopO1xuXG4gICAgb24odmVydCwgXCJzY3JvbGxcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgaWYgKHZlcnQuY2xpZW50SGVpZ2h0KSB7IHNjcm9sbCh2ZXJ0LnNjcm9sbFRvcCwgXCJ2ZXJ0aWNhbFwiKTsgfVxuICAgIH0pO1xuICAgIG9uKGhvcml6LCBcInNjcm9sbFwiLCBmdW5jdGlvbiAoKSB7XG4gICAgICBpZiAoaG9yaXouY2xpZW50V2lkdGgpIHsgc2Nyb2xsKGhvcml6LnNjcm9sbExlZnQsIFwiaG9yaXpvbnRhbFwiKTsgfVxuICAgIH0pO1xuXG4gICAgdGhpcy5jaGVja2VkWmVyb1dpZHRoID0gZmFsc2U7XG4gICAgLy8gTmVlZCB0byBzZXQgYSBtaW5pbXVtIHdpZHRoIHRvIHNlZSB0aGUgc2Nyb2xsYmFyIG9uIElFNyAoYnV0IG11c3Qgbm90IHNldCBpdCBvbiBJRTgpLlxuICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uIDwgOCkgeyB0aGlzLmhvcml6LnN0eWxlLm1pbkhlaWdodCA9IHRoaXMudmVydC5zdHlsZS5taW5XaWR0aCA9IFwiMThweFwiOyB9XG4gIH07XG5cbiAgTmF0aXZlU2Nyb2xsYmFycy5wcm90b3R5cGUudXBkYXRlID0gZnVuY3Rpb24gKG1lYXN1cmUpIHtcbiAgICB2YXIgbmVlZHNIID0gbWVhc3VyZS5zY3JvbGxXaWR0aCA+IG1lYXN1cmUuY2xpZW50V2lkdGggKyAxO1xuICAgIHZhciBuZWVkc1YgPSBtZWFzdXJlLnNjcm9sbEhlaWdodCA+IG1lYXN1cmUuY2xpZW50SGVpZ2h0ICsgMTtcbiAgICB2YXIgc1dpZHRoID0gbWVhc3VyZS5uYXRpdmVCYXJXaWR0aDtcblxuICAgIGlmIChuZWVkc1YpIHtcbiAgICAgIHRoaXMudmVydC5zdHlsZS5kaXNwbGF5ID0gXCJibG9ja1wiO1xuICAgICAgdGhpcy52ZXJ0LnN0eWxlLmJvdHRvbSA9IG5lZWRzSCA/IHNXaWR0aCArIFwicHhcIiA6IFwiMFwiO1xuICAgICAgdmFyIHRvdGFsSGVpZ2h0ID0gbWVhc3VyZS52aWV3SGVpZ2h0IC0gKG5lZWRzSCA/IHNXaWR0aCA6IDApO1xuICAgICAgLy8gQSBidWcgaW4gSUU4IGNhbiBjYXVzZSB0aGlzIHZhbHVlIHRvIGJlIG5lZ2F0aXZlLCBzbyBndWFyZCBpdC5cbiAgICAgIHRoaXMudmVydC5maXJzdENoaWxkLnN0eWxlLmhlaWdodCA9XG4gICAgICAgIE1hdGgubWF4KDAsIG1lYXN1cmUuc2Nyb2xsSGVpZ2h0IC0gbWVhc3VyZS5jbGllbnRIZWlnaHQgKyB0b3RhbEhlaWdodCkgKyBcInB4XCI7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMudmVydC5zdHlsZS5kaXNwbGF5ID0gXCJcIjtcbiAgICAgIHRoaXMudmVydC5maXJzdENoaWxkLnN0eWxlLmhlaWdodCA9IFwiMFwiO1xuICAgIH1cblxuICAgIGlmIChuZWVkc0gpIHtcbiAgICAgIHRoaXMuaG9yaXouc3R5bGUuZGlzcGxheSA9IFwiYmxvY2tcIjtcbiAgICAgIHRoaXMuaG9yaXouc3R5bGUucmlnaHQgPSBuZWVkc1YgPyBzV2lkdGggKyBcInB4XCIgOiBcIjBcIjtcbiAgICAgIHRoaXMuaG9yaXouc3R5bGUubGVmdCA9IG1lYXN1cmUuYmFyTGVmdCArIFwicHhcIjtcbiAgICAgIHZhciB0b3RhbFdpZHRoID0gbWVhc3VyZS52aWV3V2lkdGggLSBtZWFzdXJlLmJhckxlZnQgLSAobmVlZHNWID8gc1dpZHRoIDogMCk7XG4gICAgICB0aGlzLmhvcml6LmZpcnN0Q2hpbGQuc3R5bGUud2lkdGggPVxuICAgICAgICBNYXRoLm1heCgwLCBtZWFzdXJlLnNjcm9sbFdpZHRoIC0gbWVhc3VyZS5jbGllbnRXaWR0aCArIHRvdGFsV2lkdGgpICsgXCJweFwiO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLmhvcml6LnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xuICAgICAgdGhpcy5ob3Jpei5maXJzdENoaWxkLnN0eWxlLndpZHRoID0gXCIwXCI7XG4gICAgfVxuXG4gICAgaWYgKCF0aGlzLmNoZWNrZWRaZXJvV2lkdGggJiYgbWVhc3VyZS5jbGllbnRIZWlnaHQgPiAwKSB7XG4gICAgICBpZiAoc1dpZHRoID09IDApIHsgdGhpcy56ZXJvV2lkdGhIYWNrKCk7IH1cbiAgICAgIHRoaXMuY2hlY2tlZFplcm9XaWR0aCA9IHRydWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtyaWdodDogbmVlZHNWID8gc1dpZHRoIDogMCwgYm90dG9tOiBuZWVkc0ggPyBzV2lkdGggOiAwfVxuICB9O1xuXG4gIE5hdGl2ZVNjcm9sbGJhcnMucHJvdG90eXBlLnNldFNjcm9sbExlZnQgPSBmdW5jdGlvbiAocG9zKSB7XG4gICAgaWYgKHRoaXMuaG9yaXouc2Nyb2xsTGVmdCAhPSBwb3MpIHsgdGhpcy5ob3Jpei5zY3JvbGxMZWZ0ID0gcG9zOyB9XG4gICAgaWYgKHRoaXMuZGlzYWJsZUhvcml6KSB7IHRoaXMuZW5hYmxlWmVyb1dpZHRoQmFyKHRoaXMuaG9yaXosIHRoaXMuZGlzYWJsZUhvcml6LCBcImhvcml6XCIpOyB9XG4gIH07XG5cbiAgTmF0aXZlU2Nyb2xsYmFycy5wcm90b3R5cGUuc2V0U2Nyb2xsVG9wID0gZnVuY3Rpb24gKHBvcykge1xuICAgIGlmICh0aGlzLnZlcnQuc2Nyb2xsVG9wICE9IHBvcykgeyB0aGlzLnZlcnQuc2Nyb2xsVG9wID0gcG9zOyB9XG4gICAgaWYgKHRoaXMuZGlzYWJsZVZlcnQpIHsgdGhpcy5lbmFibGVaZXJvV2lkdGhCYXIodGhpcy52ZXJ0LCB0aGlzLmRpc2FibGVWZXJ0LCBcInZlcnRcIik7IH1cbiAgfTtcblxuICBOYXRpdmVTY3JvbGxiYXJzLnByb3RvdHlwZS56ZXJvV2lkdGhIYWNrID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciB3ID0gbWFjICYmICFtYWNfZ2VNb3VudGFpbkxpb24gPyBcIjEycHhcIiA6IFwiMThweFwiO1xuICAgIHRoaXMuaG9yaXouc3R5bGUuaGVpZ2h0ID0gdGhpcy52ZXJ0LnN0eWxlLndpZHRoID0gdztcbiAgICB0aGlzLmhvcml6LnN0eWxlLnBvaW50ZXJFdmVudHMgPSB0aGlzLnZlcnQuc3R5bGUucG9pbnRlckV2ZW50cyA9IFwibm9uZVwiO1xuICAgIHRoaXMuZGlzYWJsZUhvcml6ID0gbmV3IERlbGF5ZWQ7XG4gICAgdGhpcy5kaXNhYmxlVmVydCA9IG5ldyBEZWxheWVkO1xuICB9O1xuXG4gIE5hdGl2ZVNjcm9sbGJhcnMucHJvdG90eXBlLmVuYWJsZVplcm9XaWR0aEJhciA9IGZ1bmN0aW9uIChiYXIsIGRlbGF5LCB0eXBlKSB7XG4gICAgYmFyLnN0eWxlLnBvaW50ZXJFdmVudHMgPSBcImF1dG9cIjtcbiAgICBmdW5jdGlvbiBtYXliZURpc2FibGUoKSB7XG4gICAgICAvLyBUbyBmaW5kIG91dCB3aGV0aGVyIHRoZSBzY3JvbGxiYXIgaXMgc3RpbGwgdmlzaWJsZSwgd2VcbiAgICAgIC8vIGNoZWNrIHdoZXRoZXIgdGhlIGVsZW1lbnQgdW5kZXIgdGhlIHBpeGVsIGluIHRoZSBib3R0b21cbiAgICAgIC8vIHJpZ2h0IGNvcm5lciBvZiB0aGUgc2Nyb2xsYmFyIGJveCBpcyB0aGUgc2Nyb2xsYmFyIGJveFxuICAgICAgLy8gaXRzZWxmICh3aGVuIHRoZSBiYXIgaXMgc3RpbGwgdmlzaWJsZSkgb3IgaXRzIGZpbGxlciBjaGlsZFxuICAgICAgLy8gKHdoZW4gdGhlIGJhciBpcyBoaWRkZW4pLiBJZiBpdCBpcyBzdGlsbCB2aXNpYmxlLCB3ZSBrZWVwXG4gICAgICAvLyBpdCBlbmFibGVkLCBpZiBpdCdzIGhpZGRlbiwgd2UgZGlzYWJsZSBwb2ludGVyIGV2ZW50cy5cbiAgICAgIHZhciBib3ggPSBiYXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICB2YXIgZWx0JCQxID0gdHlwZSA9PSBcInZlcnRcIiA/IGRvY3VtZW50LmVsZW1lbnRGcm9tUG9pbnQoYm94LnJpZ2h0IC0gMSwgKGJveC50b3AgKyBib3guYm90dG9tKSAvIDIpXG4gICAgICAgICAgOiBkb2N1bWVudC5lbGVtZW50RnJvbVBvaW50KChib3gucmlnaHQgKyBib3gubGVmdCkgLyAyLCBib3guYm90dG9tIC0gMSk7XG4gICAgICBpZiAoZWx0JCQxICE9IGJhcikgeyBiYXIuc3R5bGUucG9pbnRlckV2ZW50cyA9IFwibm9uZVwiOyB9XG4gICAgICBlbHNlIHsgZGVsYXkuc2V0KDEwMDAsIG1heWJlRGlzYWJsZSk7IH1cbiAgICB9XG4gICAgZGVsYXkuc2V0KDEwMDAsIG1heWJlRGlzYWJsZSk7XG4gIH07XG5cbiAgTmF0aXZlU2Nyb2xsYmFycy5wcm90b3R5cGUuY2xlYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHBhcmVudCA9IHRoaXMuaG9yaXoucGFyZW50Tm9kZTtcbiAgICBwYXJlbnQucmVtb3ZlQ2hpbGQodGhpcy5ob3Jpeik7XG4gICAgcGFyZW50LnJlbW92ZUNoaWxkKHRoaXMudmVydCk7XG4gIH07XG5cbiAgdmFyIE51bGxTY3JvbGxiYXJzID0gZnVuY3Rpb24gKCkge307XG5cbiAgTnVsbFNjcm9sbGJhcnMucHJvdG90eXBlLnVwZGF0ZSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHtib3R0b206IDAsIHJpZ2h0OiAwfSB9O1xuICBOdWxsU2Nyb2xsYmFycy5wcm90b3R5cGUuc2V0U2Nyb2xsTGVmdCA9IGZ1bmN0aW9uICgpIHt9O1xuICBOdWxsU2Nyb2xsYmFycy5wcm90b3R5cGUuc2V0U2Nyb2xsVG9wID0gZnVuY3Rpb24gKCkge307XG4gIE51bGxTY3JvbGxiYXJzLnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHt9O1xuXG4gIGZ1bmN0aW9uIHVwZGF0ZVNjcm9sbGJhcnMoY20sIG1lYXN1cmUpIHtcbiAgICBpZiAoIW1lYXN1cmUpIHsgbWVhc3VyZSA9IG1lYXN1cmVGb3JTY3JvbGxiYXJzKGNtKTsgfVxuICAgIHZhciBzdGFydFdpZHRoID0gY20uZGlzcGxheS5iYXJXaWR0aCwgc3RhcnRIZWlnaHQgPSBjbS5kaXNwbGF5LmJhckhlaWdodDtcbiAgICB1cGRhdGVTY3JvbGxiYXJzSW5uZXIoY20sIG1lYXN1cmUpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgNCAmJiBzdGFydFdpZHRoICE9IGNtLmRpc3BsYXkuYmFyV2lkdGggfHwgc3RhcnRIZWlnaHQgIT0gY20uZGlzcGxheS5iYXJIZWlnaHQ7IGkrKykge1xuICAgICAgaWYgKHN0YXJ0V2lkdGggIT0gY20uZGlzcGxheS5iYXJXaWR0aCAmJiBjbS5vcHRpb25zLmxpbmVXcmFwcGluZylcbiAgICAgICAgeyB1cGRhdGVIZWlnaHRzSW5WaWV3cG9ydChjbSk7IH1cbiAgICAgIHVwZGF0ZVNjcm9sbGJhcnNJbm5lcihjbSwgbWVhc3VyZUZvclNjcm9sbGJhcnMoY20pKTtcbiAgICAgIHN0YXJ0V2lkdGggPSBjbS5kaXNwbGF5LmJhcldpZHRoOyBzdGFydEhlaWdodCA9IGNtLmRpc3BsYXkuYmFySGVpZ2h0O1xuICAgIH1cbiAgfVxuXG4gIC8vIFJlLXN5bmNocm9uaXplIHRoZSBmYWtlIHNjcm9sbGJhcnMgd2l0aCB0aGUgYWN0dWFsIHNpemUgb2YgdGhlXG4gIC8vIGNvbnRlbnQuXG4gIGZ1bmN0aW9uIHVwZGF0ZVNjcm9sbGJhcnNJbm5lcihjbSwgbWVhc3VyZSkge1xuICAgIHZhciBkID0gY20uZGlzcGxheTtcbiAgICB2YXIgc2l6ZXMgPSBkLnNjcm9sbGJhcnMudXBkYXRlKG1lYXN1cmUpO1xuXG4gICAgZC5zaXplci5zdHlsZS5wYWRkaW5nUmlnaHQgPSAoZC5iYXJXaWR0aCA9IHNpemVzLnJpZ2h0KSArIFwicHhcIjtcbiAgICBkLnNpemVyLnN0eWxlLnBhZGRpbmdCb3R0b20gPSAoZC5iYXJIZWlnaHQgPSBzaXplcy5ib3R0b20pICsgXCJweFwiO1xuICAgIGQuaGVpZ2h0Rm9yY2VyLnN0eWxlLmJvcmRlckJvdHRvbSA9IHNpemVzLmJvdHRvbSArIFwicHggc29saWQgdHJhbnNwYXJlbnRcIjtcblxuICAgIGlmIChzaXplcy5yaWdodCAmJiBzaXplcy5ib3R0b20pIHtcbiAgICAgIGQuc2Nyb2xsYmFyRmlsbGVyLnN0eWxlLmRpc3BsYXkgPSBcImJsb2NrXCI7XG4gICAgICBkLnNjcm9sbGJhckZpbGxlci5zdHlsZS5oZWlnaHQgPSBzaXplcy5ib3R0b20gKyBcInB4XCI7XG4gICAgICBkLnNjcm9sbGJhckZpbGxlci5zdHlsZS53aWR0aCA9IHNpemVzLnJpZ2h0ICsgXCJweFwiO1xuICAgIH0gZWxzZSB7IGQuc2Nyb2xsYmFyRmlsbGVyLnN0eWxlLmRpc3BsYXkgPSBcIlwiOyB9XG4gICAgaWYgKHNpemVzLmJvdHRvbSAmJiBjbS5vcHRpb25zLmNvdmVyR3V0dGVyTmV4dFRvU2Nyb2xsYmFyICYmIGNtLm9wdGlvbnMuZml4ZWRHdXR0ZXIpIHtcbiAgICAgIGQuZ3V0dGVyRmlsbGVyLnN0eWxlLmRpc3BsYXkgPSBcImJsb2NrXCI7XG4gICAgICBkLmd1dHRlckZpbGxlci5zdHlsZS5oZWlnaHQgPSBzaXplcy5ib3R0b20gKyBcInB4XCI7XG4gICAgICBkLmd1dHRlckZpbGxlci5zdHlsZS53aWR0aCA9IG1lYXN1cmUuZ3V0dGVyV2lkdGggKyBcInB4XCI7XG4gICAgfSBlbHNlIHsgZC5ndXR0ZXJGaWxsZXIuc3R5bGUuZGlzcGxheSA9IFwiXCI7IH1cbiAgfVxuXG4gIHZhciBzY3JvbGxiYXJNb2RlbCA9IHtcIm5hdGl2ZVwiOiBOYXRpdmVTY3JvbGxiYXJzLCBcIm51bGxcIjogTnVsbFNjcm9sbGJhcnN9O1xuXG4gIGZ1bmN0aW9uIGluaXRTY3JvbGxiYXJzKGNtKSB7XG4gICAgaWYgKGNtLmRpc3BsYXkuc2Nyb2xsYmFycykge1xuICAgICAgY20uZGlzcGxheS5zY3JvbGxiYXJzLmNsZWFyKCk7XG4gICAgICBpZiAoY20uZGlzcGxheS5zY3JvbGxiYXJzLmFkZENsYXNzKVxuICAgICAgICB7IHJtQ2xhc3MoY20uZGlzcGxheS53cmFwcGVyLCBjbS5kaXNwbGF5LnNjcm9sbGJhcnMuYWRkQ2xhc3MpOyB9XG4gICAgfVxuXG4gICAgY20uZGlzcGxheS5zY3JvbGxiYXJzID0gbmV3IHNjcm9sbGJhck1vZGVsW2NtLm9wdGlvbnMuc2Nyb2xsYmFyU3R5bGVdKGZ1bmN0aW9uIChub2RlKSB7XG4gICAgICBjbS5kaXNwbGF5LndyYXBwZXIuaW5zZXJ0QmVmb3JlKG5vZGUsIGNtLmRpc3BsYXkuc2Nyb2xsYmFyRmlsbGVyKTtcbiAgICAgIC8vIFByZXZlbnQgY2xpY2tzIGluIHRoZSBzY3JvbGxiYXJzIGZyb20ga2lsbGluZyBmb2N1c1xuICAgICAgb24obm9kZSwgXCJtb3VzZWRvd25cIiwgZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoY20uc3RhdGUuZm9jdXNlZCkgeyBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHsgcmV0dXJuIGNtLmRpc3BsYXkuaW5wdXQuZm9jdXMoKTsgfSwgMCk7IH1cbiAgICAgIH0pO1xuICAgICAgbm9kZS5zZXRBdHRyaWJ1dGUoXCJjbS1ub3QtY29udGVudFwiLCBcInRydWVcIik7XG4gICAgfSwgZnVuY3Rpb24gKHBvcywgYXhpcykge1xuICAgICAgaWYgKGF4aXMgPT0gXCJob3Jpem9udGFsXCIpIHsgc2V0U2Nyb2xsTGVmdChjbSwgcG9zKTsgfVxuICAgICAgZWxzZSB7IHVwZGF0ZVNjcm9sbFRvcChjbSwgcG9zKTsgfVxuICAgIH0sIGNtKTtcbiAgICBpZiAoY20uZGlzcGxheS5zY3JvbGxiYXJzLmFkZENsYXNzKVxuICAgICAgeyBhZGRDbGFzcyhjbS5kaXNwbGF5LndyYXBwZXIsIGNtLmRpc3BsYXkuc2Nyb2xsYmFycy5hZGRDbGFzcyk7IH1cbiAgfVxuXG4gIC8vIE9wZXJhdGlvbnMgYXJlIHVzZWQgdG8gd3JhcCBhIHNlcmllcyBvZiBjaGFuZ2VzIHRvIHRoZSBlZGl0b3JcbiAgLy8gc3RhdGUgaW4gc3VjaCBhIHdheSB0aGF0IGVhY2ggY2hhbmdlIHdvbid0IGhhdmUgdG8gdXBkYXRlIHRoZVxuICAvLyBjdXJzb3IgYW5kIGRpc3BsYXkgKHdoaWNoIHdvdWxkIGJlIGF3a3dhcmQsIHNsb3csIGFuZFxuICAvLyBlcnJvci1wcm9uZSkuIEluc3RlYWQsIGRpc3BsYXkgdXBkYXRlcyBhcmUgYmF0Y2hlZCBhbmQgdGhlbiBhbGxcbiAgLy8gY29tYmluZWQgYW5kIGV4ZWN1dGVkIGF0IG9uY2UuXG5cbiAgdmFyIG5leHRPcElkID0gMDtcbiAgLy8gU3RhcnQgYSBuZXcgb3BlcmF0aW9uLlxuICBmdW5jdGlvbiBzdGFydE9wZXJhdGlvbihjbSkge1xuICAgIGNtLmN1ck9wID0ge1xuICAgICAgY206IGNtLFxuICAgICAgdmlld0NoYW5nZWQ6IGZhbHNlLCAgICAgIC8vIEZsYWcgdGhhdCBpbmRpY2F0ZXMgdGhhdCBsaW5lcyBtaWdodCBuZWVkIHRvIGJlIHJlZHJhd25cbiAgICAgIHN0YXJ0SGVpZ2h0OiBjbS5kb2MuaGVpZ2h0LCAvLyBVc2VkIHRvIGRldGVjdCBuZWVkIHRvIHVwZGF0ZSBzY3JvbGxiYXJcbiAgICAgIGZvcmNlVXBkYXRlOiBmYWxzZSwgICAgICAvLyBVc2VkIHRvIGZvcmNlIGEgcmVkcmF3XG4gICAgICB1cGRhdGVJbnB1dDogMCwgICAgICAgLy8gV2hldGhlciB0byByZXNldCB0aGUgaW5wdXQgdGV4dGFyZWFcbiAgICAgIHR5cGluZzogZmFsc2UsICAgICAgICAgICAvLyBXaGV0aGVyIHRoaXMgcmVzZXQgc2hvdWxkIGJlIGNhcmVmdWwgdG8gbGVhdmUgZXhpc3RpbmcgdGV4dCAoZm9yIGNvbXBvc2l0aW5nKVxuICAgICAgY2hhbmdlT2JqczogbnVsbCwgICAgICAgIC8vIEFjY3VtdWxhdGVkIGNoYW5nZXMsIGZvciBmaXJpbmcgY2hhbmdlIGV2ZW50c1xuICAgICAgY3Vyc29yQWN0aXZpdHlIYW5kbGVyczogbnVsbCwgLy8gU2V0IG9mIGhhbmRsZXJzIHRvIGZpcmUgY3Vyc29yQWN0aXZpdHkgb25cbiAgICAgIGN1cnNvckFjdGl2aXR5Q2FsbGVkOiAwLCAvLyBUcmFja3Mgd2hpY2ggY3Vyc29yQWN0aXZpdHkgaGFuZGxlcnMgaGF2ZSBiZWVuIGNhbGxlZCBhbHJlYWR5XG4gICAgICBzZWxlY3Rpb25DaGFuZ2VkOiBmYWxzZSwgLy8gV2hldGhlciB0aGUgc2VsZWN0aW9uIG5lZWRzIHRvIGJlIHJlZHJhd25cbiAgICAgIHVwZGF0ZU1heExpbmU6IGZhbHNlLCAgICAvLyBTZXQgd2hlbiB0aGUgd2lkZXN0IGxpbmUgbmVlZHMgdG8gYmUgZGV0ZXJtaW5lZCBhbmV3XG4gICAgICBzY3JvbGxMZWZ0OiBudWxsLCBzY3JvbGxUb3A6IG51bGwsIC8vIEludGVybWVkaWF0ZSBzY3JvbGwgcG9zaXRpb24sIG5vdCBwdXNoZWQgdG8gRE9NIHlldFxuICAgICAgc2Nyb2xsVG9Qb3M6IG51bGwsICAgICAgIC8vIFVzZWQgdG8gc2Nyb2xsIHRvIGEgc3BlY2lmaWMgcG9zaXRpb25cbiAgICAgIGZvY3VzOiBmYWxzZSxcbiAgICAgIGlkOiArK25leHRPcElkICAgICAgICAgICAvLyBVbmlxdWUgSURcbiAgICB9O1xuICAgIHB1c2hPcGVyYXRpb24oY20uY3VyT3ApO1xuICB9XG5cbiAgLy8gRmluaXNoIGFuIG9wZXJhdGlvbiwgdXBkYXRpbmcgdGhlIGRpc3BsYXkgYW5kIHNpZ25hbGxpbmcgZGVsYXllZCBldmVudHNcbiAgZnVuY3Rpb24gZW5kT3BlcmF0aW9uKGNtKSB7XG4gICAgdmFyIG9wID0gY20uY3VyT3A7XG4gICAgaWYgKG9wKSB7IGZpbmlzaE9wZXJhdGlvbihvcCwgZnVuY3Rpb24gKGdyb3VwKSB7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGdyb3VwLm9wcy5sZW5ndGg7IGkrKylcbiAgICAgICAgeyBncm91cC5vcHNbaV0uY20uY3VyT3AgPSBudWxsOyB9XG4gICAgICBlbmRPcGVyYXRpb25zKGdyb3VwKTtcbiAgICB9KTsgfVxuICB9XG5cbiAgLy8gVGhlIERPTSB1cGRhdGVzIGRvbmUgd2hlbiBhbiBvcGVyYXRpb24gZmluaXNoZXMgYXJlIGJhdGNoZWQgc29cbiAgLy8gdGhhdCB0aGUgbWluaW11bSBudW1iZXIgb2YgcmVsYXlvdXRzIGFyZSByZXF1aXJlZC5cbiAgZnVuY3Rpb24gZW5kT3BlcmF0aW9ucyhncm91cCkge1xuICAgIHZhciBvcHMgPSBncm91cC5vcHM7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvcHMubGVuZ3RoOyBpKyspIC8vIFJlYWQgRE9NXG4gICAgICB7IGVuZE9wZXJhdGlvbl9SMShvcHNbaV0pOyB9XG4gICAgZm9yICh2YXIgaSQxID0gMDsgaSQxIDwgb3BzLmxlbmd0aDsgaSQxKyspIC8vIFdyaXRlIERPTSAobWF5YmUpXG4gICAgICB7IGVuZE9wZXJhdGlvbl9XMShvcHNbaSQxXSk7IH1cbiAgICBmb3IgKHZhciBpJDIgPSAwOyBpJDIgPCBvcHMubGVuZ3RoOyBpJDIrKykgLy8gUmVhZCBET01cbiAgICAgIHsgZW5kT3BlcmF0aW9uX1IyKG9wc1tpJDJdKTsgfVxuICAgIGZvciAodmFyIGkkMyA9IDA7IGkkMyA8IG9wcy5sZW5ndGg7IGkkMysrKSAvLyBXcml0ZSBET00gKG1heWJlKVxuICAgICAgeyBlbmRPcGVyYXRpb25fVzIob3BzW2kkM10pOyB9XG4gICAgZm9yICh2YXIgaSQ0ID0gMDsgaSQ0IDwgb3BzLmxlbmd0aDsgaSQ0KyspIC8vIFJlYWQgRE9NXG4gICAgICB7IGVuZE9wZXJhdGlvbl9maW5pc2gob3BzW2kkNF0pOyB9XG4gIH1cblxuICBmdW5jdGlvbiBlbmRPcGVyYXRpb25fUjEob3ApIHtcbiAgICB2YXIgY20gPSBvcC5jbSwgZGlzcGxheSA9IGNtLmRpc3BsYXk7XG4gICAgbWF5YmVDbGlwU2Nyb2xsYmFycyhjbSk7XG4gICAgaWYgKG9wLnVwZGF0ZU1heExpbmUpIHsgZmluZE1heExpbmUoY20pOyB9XG5cbiAgICBvcC5tdXN0VXBkYXRlID0gb3Audmlld0NoYW5nZWQgfHwgb3AuZm9yY2VVcGRhdGUgfHwgb3Auc2Nyb2xsVG9wICE9IG51bGwgfHxcbiAgICAgIG9wLnNjcm9sbFRvUG9zICYmIChvcC5zY3JvbGxUb1Bvcy5mcm9tLmxpbmUgPCBkaXNwbGF5LnZpZXdGcm9tIHx8XG4gICAgICAgICAgICAgICAgICAgICAgICAgb3Auc2Nyb2xsVG9Qb3MudG8ubGluZSA+PSBkaXNwbGF5LnZpZXdUbykgfHxcbiAgICAgIGRpc3BsYXkubWF4TGluZUNoYW5nZWQgJiYgY20ub3B0aW9ucy5saW5lV3JhcHBpbmc7XG4gICAgb3AudXBkYXRlID0gb3AubXVzdFVwZGF0ZSAmJlxuICAgICAgbmV3IERpc3BsYXlVcGRhdGUoY20sIG9wLm11c3RVcGRhdGUgJiYge3RvcDogb3Auc2Nyb2xsVG9wLCBlbnN1cmU6IG9wLnNjcm9sbFRvUG9zfSwgb3AuZm9yY2VVcGRhdGUpO1xuICB9XG5cbiAgZnVuY3Rpb24gZW5kT3BlcmF0aW9uX1cxKG9wKSB7XG4gICAgb3AudXBkYXRlZERpc3BsYXkgPSBvcC5tdXN0VXBkYXRlICYmIHVwZGF0ZURpc3BsYXlJZk5lZWRlZChvcC5jbSwgb3AudXBkYXRlKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGVuZE9wZXJhdGlvbl9SMihvcCkge1xuICAgIHZhciBjbSA9IG9wLmNtLCBkaXNwbGF5ID0gY20uZGlzcGxheTtcbiAgICBpZiAob3AudXBkYXRlZERpc3BsYXkpIHsgdXBkYXRlSGVpZ2h0c0luVmlld3BvcnQoY20pOyB9XG5cbiAgICBvcC5iYXJNZWFzdXJlID0gbWVhc3VyZUZvclNjcm9sbGJhcnMoY20pO1xuXG4gICAgLy8gSWYgdGhlIG1heCBsaW5lIGNoYW5nZWQgc2luY2UgaXQgd2FzIGxhc3QgbWVhc3VyZWQsIG1lYXN1cmUgaXQsXG4gICAgLy8gYW5kIGVuc3VyZSB0aGUgZG9jdW1lbnQncyB3aWR0aCBtYXRjaGVzIGl0LlxuICAgIC8vIHVwZGF0ZURpc3BsYXlfVzIgd2lsbCB1c2UgdGhlc2UgcHJvcGVydGllcyB0byBkbyB0aGUgYWN0dWFsIHJlc2l6aW5nXG4gICAgaWYgKGRpc3BsYXkubWF4TGluZUNoYW5nZWQgJiYgIWNtLm9wdGlvbnMubGluZVdyYXBwaW5nKSB7XG4gICAgICBvcC5hZGp1c3RXaWR0aFRvID0gbWVhc3VyZUNoYXIoY20sIGRpc3BsYXkubWF4TGluZSwgZGlzcGxheS5tYXhMaW5lLnRleHQubGVuZ3RoKS5sZWZ0ICsgMztcbiAgICAgIGNtLmRpc3BsYXkuc2l6ZXJXaWR0aCA9IG9wLmFkanVzdFdpZHRoVG87XG4gICAgICBvcC5iYXJNZWFzdXJlLnNjcm9sbFdpZHRoID1cbiAgICAgICAgTWF0aC5tYXgoZGlzcGxheS5zY3JvbGxlci5jbGllbnRXaWR0aCwgZGlzcGxheS5zaXplci5vZmZzZXRMZWZ0ICsgb3AuYWRqdXN0V2lkdGhUbyArIHNjcm9sbEdhcChjbSkgKyBjbS5kaXNwbGF5LmJhcldpZHRoKTtcbiAgICAgIG9wLm1heFNjcm9sbExlZnQgPSBNYXRoLm1heCgwLCBkaXNwbGF5LnNpemVyLm9mZnNldExlZnQgKyBvcC5hZGp1c3RXaWR0aFRvIC0gZGlzcGxheVdpZHRoKGNtKSk7XG4gICAgfVxuXG4gICAgaWYgKG9wLnVwZGF0ZWREaXNwbGF5IHx8IG9wLnNlbGVjdGlvbkNoYW5nZWQpXG4gICAgICB7IG9wLnByZXBhcmVkU2VsZWN0aW9uID0gZGlzcGxheS5pbnB1dC5wcmVwYXJlU2VsZWN0aW9uKCk7IH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGVuZE9wZXJhdGlvbl9XMihvcCkge1xuICAgIHZhciBjbSA9IG9wLmNtO1xuXG4gICAgaWYgKG9wLmFkanVzdFdpZHRoVG8gIT0gbnVsbCkge1xuICAgICAgY20uZGlzcGxheS5zaXplci5zdHlsZS5taW5XaWR0aCA9IG9wLmFkanVzdFdpZHRoVG8gKyBcInB4XCI7XG4gICAgICBpZiAob3AubWF4U2Nyb2xsTGVmdCA8IGNtLmRvYy5zY3JvbGxMZWZ0KVxuICAgICAgICB7IHNldFNjcm9sbExlZnQoY20sIE1hdGgubWluKGNtLmRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsTGVmdCwgb3AubWF4U2Nyb2xsTGVmdCksIHRydWUpOyB9XG4gICAgICBjbS5kaXNwbGF5Lm1heExpbmVDaGFuZ2VkID0gZmFsc2U7XG4gICAgfVxuXG4gICAgdmFyIHRha2VGb2N1cyA9IG9wLmZvY3VzICYmIG9wLmZvY3VzID09IGFjdGl2ZUVsdCgpO1xuICAgIGlmIChvcC5wcmVwYXJlZFNlbGVjdGlvbilcbiAgICAgIHsgY20uZGlzcGxheS5pbnB1dC5zaG93U2VsZWN0aW9uKG9wLnByZXBhcmVkU2VsZWN0aW9uLCB0YWtlRm9jdXMpOyB9XG4gICAgaWYgKG9wLnVwZGF0ZWREaXNwbGF5IHx8IG9wLnN0YXJ0SGVpZ2h0ICE9IGNtLmRvYy5oZWlnaHQpXG4gICAgICB7IHVwZGF0ZVNjcm9sbGJhcnMoY20sIG9wLmJhck1lYXN1cmUpOyB9XG4gICAgaWYgKG9wLnVwZGF0ZWREaXNwbGF5KVxuICAgICAgeyBzZXREb2N1bWVudEhlaWdodChjbSwgb3AuYmFyTWVhc3VyZSk7IH1cblxuICAgIGlmIChvcC5zZWxlY3Rpb25DaGFuZ2VkKSB7IHJlc3RhcnRCbGluayhjbSk7IH1cblxuICAgIGlmIChjbS5zdGF0ZS5mb2N1c2VkICYmIG9wLnVwZGF0ZUlucHV0KVxuICAgICAgeyBjbS5kaXNwbGF5LmlucHV0LnJlc2V0KG9wLnR5cGluZyk7IH1cbiAgICBpZiAodGFrZUZvY3VzKSB7IGVuc3VyZUZvY3VzKG9wLmNtKTsgfVxuICB9XG5cbiAgZnVuY3Rpb24gZW5kT3BlcmF0aW9uX2ZpbmlzaChvcCkge1xuICAgIHZhciBjbSA9IG9wLmNtLCBkaXNwbGF5ID0gY20uZGlzcGxheSwgZG9jID0gY20uZG9jO1xuXG4gICAgaWYgKG9wLnVwZGF0ZWREaXNwbGF5KSB7IHBvc3RVcGRhdGVEaXNwbGF5KGNtLCBvcC51cGRhdGUpOyB9XG5cbiAgICAvLyBBYm9ydCBtb3VzZSB3aGVlbCBkZWx0YSBtZWFzdXJlbWVudCwgd2hlbiBzY3JvbGxpbmcgZXhwbGljaXRseVxuICAgIGlmIChkaXNwbGF5LndoZWVsU3RhcnRYICE9IG51bGwgJiYgKG9wLnNjcm9sbFRvcCAhPSBudWxsIHx8IG9wLnNjcm9sbExlZnQgIT0gbnVsbCB8fCBvcC5zY3JvbGxUb1BvcykpXG4gICAgICB7IGRpc3BsYXkud2hlZWxTdGFydFggPSBkaXNwbGF5LndoZWVsU3RhcnRZID0gbnVsbDsgfVxuXG4gICAgLy8gUHJvcGFnYXRlIHRoZSBzY3JvbGwgcG9zaXRpb24gdG8gdGhlIGFjdHVhbCBET00gc2Nyb2xsZXJcbiAgICBpZiAob3Auc2Nyb2xsVG9wICE9IG51bGwpIHsgc2V0U2Nyb2xsVG9wKGNtLCBvcC5zY3JvbGxUb3AsIG9wLmZvcmNlU2Nyb2xsKTsgfVxuXG4gICAgaWYgKG9wLnNjcm9sbExlZnQgIT0gbnVsbCkgeyBzZXRTY3JvbGxMZWZ0KGNtLCBvcC5zY3JvbGxMZWZ0LCB0cnVlLCB0cnVlKTsgfVxuICAgIC8vIElmIHdlIG5lZWQgdG8gc2Nyb2xsIGEgc3BlY2lmaWMgcG9zaXRpb24gaW50byB2aWV3LCBkbyBzby5cbiAgICBpZiAob3Auc2Nyb2xsVG9Qb3MpIHtcbiAgICAgIHZhciByZWN0ID0gc2Nyb2xsUG9zSW50b1ZpZXcoY20sIGNsaXBQb3MoZG9jLCBvcC5zY3JvbGxUb1Bvcy5mcm9tKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpcFBvcyhkb2MsIG9wLnNjcm9sbFRvUG9zLnRvKSwgb3Auc2Nyb2xsVG9Qb3MubWFyZ2luKTtcbiAgICAgIG1heWJlU2Nyb2xsV2luZG93KGNtLCByZWN0KTtcbiAgICB9XG5cbiAgICAvLyBGaXJlIGV2ZW50cyBmb3IgbWFya2VycyB0aGF0IGFyZSBoaWRkZW4vdW5pZGRlbiBieSBlZGl0aW5nIG9yXG4gICAgLy8gdW5kb2luZ1xuICAgIHZhciBoaWRkZW4gPSBvcC5tYXliZUhpZGRlbk1hcmtlcnMsIHVuaGlkZGVuID0gb3AubWF5YmVVbmhpZGRlbk1hcmtlcnM7XG4gICAgaWYgKGhpZGRlbikgeyBmb3IgKHZhciBpID0gMDsgaSA8IGhpZGRlbi5sZW5ndGg7ICsraSlcbiAgICAgIHsgaWYgKCFoaWRkZW5baV0ubGluZXMubGVuZ3RoKSB7IHNpZ25hbChoaWRkZW5baV0sIFwiaGlkZVwiKTsgfSB9IH1cbiAgICBpZiAodW5oaWRkZW4pIHsgZm9yICh2YXIgaSQxID0gMDsgaSQxIDwgdW5oaWRkZW4ubGVuZ3RoOyArK2kkMSlcbiAgICAgIHsgaWYgKHVuaGlkZGVuW2kkMV0ubGluZXMubGVuZ3RoKSB7IHNpZ25hbCh1bmhpZGRlbltpJDFdLCBcInVuaGlkZVwiKTsgfSB9IH1cblxuICAgIGlmIChkaXNwbGF5LndyYXBwZXIub2Zmc2V0SGVpZ2h0KVxuICAgICAgeyBkb2Muc2Nyb2xsVG9wID0gY20uZGlzcGxheS5zY3JvbGxlci5zY3JvbGxUb3A7IH1cblxuICAgIC8vIEZpcmUgY2hhbmdlIGV2ZW50cywgYW5kIGRlbGF5ZWQgZXZlbnQgaGFuZGxlcnNcbiAgICBpZiAob3AuY2hhbmdlT2JqcylcbiAgICAgIHsgc2lnbmFsKGNtLCBcImNoYW5nZXNcIiwgY20sIG9wLmNoYW5nZU9ianMpOyB9XG4gICAgaWYgKG9wLnVwZGF0ZSlcbiAgICAgIHsgb3AudXBkYXRlLmZpbmlzaCgpOyB9XG4gIH1cblxuICAvLyBSdW4gdGhlIGdpdmVuIGZ1bmN0aW9uIGluIGFuIG9wZXJhdGlvblxuICBmdW5jdGlvbiBydW5Jbk9wKGNtLCBmKSB7XG4gICAgaWYgKGNtLmN1ck9wKSB7IHJldHVybiBmKCkgfVxuICAgIHN0YXJ0T3BlcmF0aW9uKGNtKTtcbiAgICB0cnkgeyByZXR1cm4gZigpIH1cbiAgICBmaW5hbGx5IHsgZW5kT3BlcmF0aW9uKGNtKTsgfVxuICB9XG4gIC8vIFdyYXBzIGEgZnVuY3Rpb24gaW4gYW4gb3BlcmF0aW9uLiBSZXR1cm5zIHRoZSB3cmFwcGVkIGZ1bmN0aW9uLlxuICBmdW5jdGlvbiBvcGVyYXRpb24oY20sIGYpIHtcbiAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICBpZiAoY20uY3VyT3ApIHsgcmV0dXJuIGYuYXBwbHkoY20sIGFyZ3VtZW50cykgfVxuICAgICAgc3RhcnRPcGVyYXRpb24oY20pO1xuICAgICAgdHJ5IHsgcmV0dXJuIGYuYXBwbHkoY20sIGFyZ3VtZW50cykgfVxuICAgICAgZmluYWxseSB7IGVuZE9wZXJhdGlvbihjbSk7IH1cbiAgICB9XG4gIH1cbiAgLy8gVXNlZCB0byBhZGQgbWV0aG9kcyB0byBlZGl0b3IgYW5kIGRvYyBpbnN0YW5jZXMsIHdyYXBwaW5nIHRoZW0gaW5cbiAgLy8gb3BlcmF0aW9ucy5cbiAgZnVuY3Rpb24gbWV0aG9kT3AoZikge1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIGlmICh0aGlzLmN1ck9wKSB7IHJldHVybiBmLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfVxuICAgICAgc3RhcnRPcGVyYXRpb24odGhpcyk7XG4gICAgICB0cnkgeyByZXR1cm4gZi5hcHBseSh0aGlzLCBhcmd1bWVudHMpIH1cbiAgICAgIGZpbmFsbHkgeyBlbmRPcGVyYXRpb24odGhpcyk7IH1cbiAgICB9XG4gIH1cbiAgZnVuY3Rpb24gZG9jTWV0aG9kT3AoZikge1xuICAgIHJldHVybiBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBjbSA9IHRoaXMuY207XG4gICAgICBpZiAoIWNtIHx8IGNtLmN1ck9wKSB7IHJldHVybiBmLmFwcGx5KHRoaXMsIGFyZ3VtZW50cykgfVxuICAgICAgc3RhcnRPcGVyYXRpb24oY20pO1xuICAgICAgdHJ5IHsgcmV0dXJuIGYuYXBwbHkodGhpcywgYXJndW1lbnRzKSB9XG4gICAgICBmaW5hbGx5IHsgZW5kT3BlcmF0aW9uKGNtKTsgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFVwZGF0ZXMgdGhlIGRpc3BsYXkudmlldyBkYXRhIHN0cnVjdHVyZSBmb3IgYSBnaXZlbiBjaGFuZ2UgdG8gdGhlXG4gIC8vIGRvY3VtZW50LiBGcm9tIGFuZCB0byBhcmUgaW4gcHJlLWNoYW5nZSBjb29yZGluYXRlcy4gTGVuZGlmZiBpc1xuICAvLyB0aGUgYW1vdW50IG9mIGxpbmVzIGFkZGVkIG9yIHN1YnRyYWN0ZWQgYnkgdGhlIGNoYW5nZS4gVGhpcyBpc1xuICAvLyB1c2VkIGZvciBjaGFuZ2VzIHRoYXQgc3BhbiBtdWx0aXBsZSBsaW5lcywgb3IgY2hhbmdlIHRoZSB3YXlcbiAgLy8gbGluZXMgYXJlIGRpdmlkZWQgaW50byB2aXN1YWwgbGluZXMuIHJlZ0xpbmVDaGFuZ2UgKGJlbG93KVxuICAvLyByZWdpc3RlcnMgc2luZ2xlLWxpbmUgY2hhbmdlcy5cbiAgZnVuY3Rpb24gcmVnQ2hhbmdlKGNtLCBmcm9tLCB0bywgbGVuZGlmZikge1xuICAgIGlmIChmcm9tID09IG51bGwpIHsgZnJvbSA9IGNtLmRvYy5maXJzdDsgfVxuICAgIGlmICh0byA9PSBudWxsKSB7IHRvID0gY20uZG9jLmZpcnN0ICsgY20uZG9jLnNpemU7IH1cbiAgICBpZiAoIWxlbmRpZmYpIHsgbGVuZGlmZiA9IDA7IH1cblxuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheTtcbiAgICBpZiAobGVuZGlmZiAmJiB0byA8IGRpc3BsYXkudmlld1RvICYmXG4gICAgICAgIChkaXNwbGF5LnVwZGF0ZUxpbmVOdW1iZXJzID09IG51bGwgfHwgZGlzcGxheS51cGRhdGVMaW5lTnVtYmVycyA+IGZyb20pKVxuICAgICAgeyBkaXNwbGF5LnVwZGF0ZUxpbmVOdW1iZXJzID0gZnJvbTsgfVxuXG4gICAgY20uY3VyT3Audmlld0NoYW5nZWQgPSB0cnVlO1xuXG4gICAgaWYgKGZyb20gPj0gZGlzcGxheS52aWV3VG8pIHsgLy8gQ2hhbmdlIGFmdGVyXG4gICAgICBpZiAoc2F3Q29sbGFwc2VkU3BhbnMgJiYgdmlzdWFsTGluZU5vKGNtLmRvYywgZnJvbSkgPCBkaXNwbGF5LnZpZXdUbylcbiAgICAgICAgeyByZXNldFZpZXcoY20pOyB9XG4gICAgfSBlbHNlIGlmICh0byA8PSBkaXNwbGF5LnZpZXdGcm9tKSB7IC8vIENoYW5nZSBiZWZvcmVcbiAgICAgIGlmIChzYXdDb2xsYXBzZWRTcGFucyAmJiB2aXN1YWxMaW5lRW5kTm8oY20uZG9jLCB0byArIGxlbmRpZmYpID4gZGlzcGxheS52aWV3RnJvbSkge1xuICAgICAgICByZXNldFZpZXcoY20pO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGlzcGxheS52aWV3RnJvbSArPSBsZW5kaWZmO1xuICAgICAgICBkaXNwbGF5LnZpZXdUbyArPSBsZW5kaWZmO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoZnJvbSA8PSBkaXNwbGF5LnZpZXdGcm9tICYmIHRvID49IGRpc3BsYXkudmlld1RvKSB7IC8vIEZ1bGwgb3ZlcmxhcFxuICAgICAgcmVzZXRWaWV3KGNtKTtcbiAgICB9IGVsc2UgaWYgKGZyb20gPD0gZGlzcGxheS52aWV3RnJvbSkgeyAvLyBUb3Agb3ZlcmxhcFxuICAgICAgdmFyIGN1dCA9IHZpZXdDdXR0aW5nUG9pbnQoY20sIHRvLCB0byArIGxlbmRpZmYsIDEpO1xuICAgICAgaWYgKGN1dCkge1xuICAgICAgICBkaXNwbGF5LnZpZXcgPSBkaXNwbGF5LnZpZXcuc2xpY2UoY3V0LmluZGV4KTtcbiAgICAgICAgZGlzcGxheS52aWV3RnJvbSA9IGN1dC5saW5lTjtcbiAgICAgICAgZGlzcGxheS52aWV3VG8gKz0gbGVuZGlmZjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJlc2V0VmlldyhjbSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0byA+PSBkaXNwbGF5LnZpZXdUbykgeyAvLyBCb3R0b20gb3ZlcmxhcFxuICAgICAgdmFyIGN1dCQxID0gdmlld0N1dHRpbmdQb2ludChjbSwgZnJvbSwgZnJvbSwgLTEpO1xuICAgICAgaWYgKGN1dCQxKSB7XG4gICAgICAgIGRpc3BsYXkudmlldyA9IGRpc3BsYXkudmlldy5zbGljZSgwLCBjdXQkMS5pbmRleCk7XG4gICAgICAgIGRpc3BsYXkudmlld1RvID0gY3V0JDEubGluZU47XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXNldFZpZXcoY20pO1xuICAgICAgfVxuICAgIH0gZWxzZSB7IC8vIEdhcCBpbiB0aGUgbWlkZGxlXG4gICAgICB2YXIgY3V0VG9wID0gdmlld0N1dHRpbmdQb2ludChjbSwgZnJvbSwgZnJvbSwgLTEpO1xuICAgICAgdmFyIGN1dEJvdCA9IHZpZXdDdXR0aW5nUG9pbnQoY20sIHRvLCB0byArIGxlbmRpZmYsIDEpO1xuICAgICAgaWYgKGN1dFRvcCAmJiBjdXRCb3QpIHtcbiAgICAgICAgZGlzcGxheS52aWV3ID0gZGlzcGxheS52aWV3LnNsaWNlKDAsIGN1dFRvcC5pbmRleClcbiAgICAgICAgICAuY29uY2F0KGJ1aWxkVmlld0FycmF5KGNtLCBjdXRUb3AubGluZU4sIGN1dEJvdC5saW5lTikpXG4gICAgICAgICAgLmNvbmNhdChkaXNwbGF5LnZpZXcuc2xpY2UoY3V0Qm90LmluZGV4KSk7XG4gICAgICAgIGRpc3BsYXkudmlld1RvICs9IGxlbmRpZmY7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXNldFZpZXcoY20pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBleHQgPSBkaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQ7XG4gICAgaWYgKGV4dCkge1xuICAgICAgaWYgKHRvIDwgZXh0LmxpbmVOKVxuICAgICAgICB7IGV4dC5saW5lTiArPSBsZW5kaWZmOyB9XG4gICAgICBlbHNlIGlmIChmcm9tIDwgZXh0LmxpbmVOICsgZXh0LnNpemUpXG4gICAgICAgIHsgZGlzcGxheS5leHRlcm5hbE1lYXN1cmVkID0gbnVsbDsgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFJlZ2lzdGVyIGEgY2hhbmdlIHRvIGEgc2luZ2xlIGxpbmUuIFR5cGUgbXVzdCBiZSBvbmUgb2YgXCJ0ZXh0XCIsXG4gIC8vIFwiZ3V0dGVyXCIsIFwiY2xhc3NcIiwgXCJ3aWRnZXRcIlxuICBmdW5jdGlvbiByZWdMaW5lQ2hhbmdlKGNtLCBsaW5lLCB0eXBlKSB7XG4gICAgY20uY3VyT3Audmlld0NoYW5nZWQgPSB0cnVlO1xuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheSwgZXh0ID0gY20uZGlzcGxheS5leHRlcm5hbE1lYXN1cmVkO1xuICAgIGlmIChleHQgJiYgbGluZSA+PSBleHQubGluZU4gJiYgbGluZSA8IGV4dC5saW5lTiArIGV4dC5zaXplKVxuICAgICAgeyBkaXNwbGF5LmV4dGVybmFsTWVhc3VyZWQgPSBudWxsOyB9XG5cbiAgICBpZiAobGluZSA8IGRpc3BsYXkudmlld0Zyb20gfHwgbGluZSA+PSBkaXNwbGF5LnZpZXdUbykgeyByZXR1cm4gfVxuICAgIHZhciBsaW5lVmlldyA9IGRpc3BsYXkudmlld1tmaW5kVmlld0luZGV4KGNtLCBsaW5lKV07XG4gICAgaWYgKGxpbmVWaWV3Lm5vZGUgPT0gbnVsbCkgeyByZXR1cm4gfVxuICAgIHZhciBhcnIgPSBsaW5lVmlldy5jaGFuZ2VzIHx8IChsaW5lVmlldy5jaGFuZ2VzID0gW10pO1xuICAgIGlmIChpbmRleE9mKGFyciwgdHlwZSkgPT0gLTEpIHsgYXJyLnB1c2godHlwZSk7IH1cbiAgfVxuXG4gIC8vIENsZWFyIHRoZSB2aWV3LlxuICBmdW5jdGlvbiByZXNldFZpZXcoY20pIHtcbiAgICBjbS5kaXNwbGF5LnZpZXdGcm9tID0gY20uZGlzcGxheS52aWV3VG8gPSBjbS5kb2MuZmlyc3Q7XG4gICAgY20uZGlzcGxheS52aWV3ID0gW107XG4gICAgY20uZGlzcGxheS52aWV3T2Zmc2V0ID0gMDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHZpZXdDdXR0aW5nUG9pbnQoY20sIG9sZE4sIG5ld04sIGRpcikge1xuICAgIHZhciBpbmRleCA9IGZpbmRWaWV3SW5kZXgoY20sIG9sZE4pLCBkaWZmLCB2aWV3ID0gY20uZGlzcGxheS52aWV3O1xuICAgIGlmICghc2F3Q29sbGFwc2VkU3BhbnMgfHwgbmV3TiA9PSBjbS5kb2MuZmlyc3QgKyBjbS5kb2Muc2l6ZSlcbiAgICAgIHsgcmV0dXJuIHtpbmRleDogaW5kZXgsIGxpbmVOOiBuZXdOfSB9XG4gICAgdmFyIG4gPSBjbS5kaXNwbGF5LnZpZXdGcm9tO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgaW5kZXg7IGkrKylcbiAgICAgIHsgbiArPSB2aWV3W2ldLnNpemU7IH1cbiAgICBpZiAobiAhPSBvbGROKSB7XG4gICAgICBpZiAoZGlyID4gMCkge1xuICAgICAgICBpZiAoaW5kZXggPT0gdmlldy5sZW5ndGggLSAxKSB7IHJldHVybiBudWxsIH1cbiAgICAgICAgZGlmZiA9IChuICsgdmlld1tpbmRleF0uc2l6ZSkgLSBvbGROO1xuICAgICAgICBpbmRleCsrO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgZGlmZiA9IG4gLSBvbGROO1xuICAgICAgfVxuICAgICAgb2xkTiArPSBkaWZmOyBuZXdOICs9IGRpZmY7XG4gICAgfVxuICAgIHdoaWxlICh2aXN1YWxMaW5lTm8oY20uZG9jLCBuZXdOKSAhPSBuZXdOKSB7XG4gICAgICBpZiAoaW5kZXggPT0gKGRpciA8IDAgPyAwIDogdmlldy5sZW5ndGggLSAxKSkgeyByZXR1cm4gbnVsbCB9XG4gICAgICBuZXdOICs9IGRpciAqIHZpZXdbaW5kZXggLSAoZGlyIDwgMCA/IDEgOiAwKV0uc2l6ZTtcbiAgICAgIGluZGV4ICs9IGRpcjtcbiAgICB9XG4gICAgcmV0dXJuIHtpbmRleDogaW5kZXgsIGxpbmVOOiBuZXdOfVxuICB9XG5cbiAgLy8gRm9yY2UgdGhlIHZpZXcgdG8gY292ZXIgYSBnaXZlbiByYW5nZSwgYWRkaW5nIGVtcHR5IHZpZXcgZWxlbWVudFxuICAvLyBvciBjbGlwcGluZyBvZmYgZXhpc3Rpbmcgb25lcyBhcyBuZWVkZWQuXG4gIGZ1bmN0aW9uIGFkanVzdFZpZXcoY20sIGZyb20sIHRvKSB7XG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCB2aWV3ID0gZGlzcGxheS52aWV3O1xuICAgIGlmICh2aWV3Lmxlbmd0aCA9PSAwIHx8IGZyb20gPj0gZGlzcGxheS52aWV3VG8gfHwgdG8gPD0gZGlzcGxheS52aWV3RnJvbSkge1xuICAgICAgZGlzcGxheS52aWV3ID0gYnVpbGRWaWV3QXJyYXkoY20sIGZyb20sIHRvKTtcbiAgICAgIGRpc3BsYXkudmlld0Zyb20gPSBmcm9tO1xuICAgIH0gZWxzZSB7XG4gICAgICBpZiAoZGlzcGxheS52aWV3RnJvbSA+IGZyb20pXG4gICAgICAgIHsgZGlzcGxheS52aWV3ID0gYnVpbGRWaWV3QXJyYXkoY20sIGZyb20sIGRpc3BsYXkudmlld0Zyb20pLmNvbmNhdChkaXNwbGF5LnZpZXcpOyB9XG4gICAgICBlbHNlIGlmIChkaXNwbGF5LnZpZXdGcm9tIDwgZnJvbSlcbiAgICAgICAgeyBkaXNwbGF5LnZpZXcgPSBkaXNwbGF5LnZpZXcuc2xpY2UoZmluZFZpZXdJbmRleChjbSwgZnJvbSkpOyB9XG4gICAgICBkaXNwbGF5LnZpZXdGcm9tID0gZnJvbTtcbiAgICAgIGlmIChkaXNwbGF5LnZpZXdUbyA8IHRvKVxuICAgICAgICB7IGRpc3BsYXkudmlldyA9IGRpc3BsYXkudmlldy5jb25jYXQoYnVpbGRWaWV3QXJyYXkoY20sIGRpc3BsYXkudmlld1RvLCB0bykpOyB9XG4gICAgICBlbHNlIGlmIChkaXNwbGF5LnZpZXdUbyA+IHRvKVxuICAgICAgICB7IGRpc3BsYXkudmlldyA9IGRpc3BsYXkudmlldy5zbGljZSgwLCBmaW5kVmlld0luZGV4KGNtLCB0bykpOyB9XG4gICAgfVxuICAgIGRpc3BsYXkudmlld1RvID0gdG87XG4gIH1cblxuICAvLyBDb3VudCB0aGUgbnVtYmVyIG9mIGxpbmVzIGluIHRoZSB2aWV3IHdob3NlIERPTSByZXByZXNlbnRhdGlvbiBpc1xuICAvLyBvdXQgb2YgZGF0ZSAob3Igbm9uZXhpc3RlbnQpLlxuICBmdW5jdGlvbiBjb3VudERpcnR5VmlldyhjbSkge1xuICAgIHZhciB2aWV3ID0gY20uZGlzcGxheS52aWV3LCBkaXJ0eSA9IDA7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB2aWV3Lmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgbGluZVZpZXcgPSB2aWV3W2ldO1xuICAgICAgaWYgKCFsaW5lVmlldy5oaWRkZW4gJiYgKCFsaW5lVmlldy5ub2RlIHx8IGxpbmVWaWV3LmNoYW5nZXMpKSB7ICsrZGlydHk7IH1cbiAgICB9XG4gICAgcmV0dXJuIGRpcnR5XG4gIH1cblxuICAvLyBISUdITElHSFQgV09SS0VSXG5cbiAgZnVuY3Rpb24gc3RhcnRXb3JrZXIoY20sIHRpbWUpIHtcbiAgICBpZiAoY20uZG9jLmhpZ2hsaWdodEZyb250aWVyIDwgY20uZGlzcGxheS52aWV3VG8pXG4gICAgICB7IGNtLnN0YXRlLmhpZ2hsaWdodC5zZXQodGltZSwgYmluZChoaWdobGlnaHRXb3JrZXIsIGNtKSk7IH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGhpZ2hsaWdodFdvcmtlcihjbSkge1xuICAgIHZhciBkb2MgPSBjbS5kb2M7XG4gICAgaWYgKGRvYy5oaWdobGlnaHRGcm9udGllciA+PSBjbS5kaXNwbGF5LnZpZXdUbykgeyByZXR1cm4gfVxuICAgIHZhciBlbmQgPSArbmV3IERhdGUgKyBjbS5vcHRpb25zLndvcmtUaW1lO1xuICAgIHZhciBjb250ZXh0ID0gZ2V0Q29udGV4dEJlZm9yZShjbSwgZG9jLmhpZ2hsaWdodEZyb250aWVyKTtcbiAgICB2YXIgY2hhbmdlZExpbmVzID0gW107XG5cbiAgICBkb2MuaXRlcihjb250ZXh0LmxpbmUsIE1hdGgubWluKGRvYy5maXJzdCArIGRvYy5zaXplLCBjbS5kaXNwbGF5LnZpZXdUbyArIDUwMCksIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICBpZiAoY29udGV4dC5saW5lID49IGNtLmRpc3BsYXkudmlld0Zyb20pIHsgLy8gVmlzaWJsZVxuICAgICAgICB2YXIgb2xkU3R5bGVzID0gbGluZS5zdHlsZXM7XG4gICAgICAgIHZhciByZXNldFN0YXRlID0gbGluZS50ZXh0Lmxlbmd0aCA+IGNtLm9wdGlvbnMubWF4SGlnaGxpZ2h0TGVuZ3RoID8gY29weVN0YXRlKGRvYy5tb2RlLCBjb250ZXh0LnN0YXRlKSA6IG51bGw7XG4gICAgICAgIHZhciBoaWdobGlnaHRlZCA9IGhpZ2hsaWdodExpbmUoY20sIGxpbmUsIGNvbnRleHQsIHRydWUpO1xuICAgICAgICBpZiAocmVzZXRTdGF0ZSkgeyBjb250ZXh0LnN0YXRlID0gcmVzZXRTdGF0ZTsgfVxuICAgICAgICBsaW5lLnN0eWxlcyA9IGhpZ2hsaWdodGVkLnN0eWxlcztcbiAgICAgICAgdmFyIG9sZENscyA9IGxpbmUuc3R5bGVDbGFzc2VzLCBuZXdDbHMgPSBoaWdobGlnaHRlZC5jbGFzc2VzO1xuICAgICAgICBpZiAobmV3Q2xzKSB7IGxpbmUuc3R5bGVDbGFzc2VzID0gbmV3Q2xzOyB9XG4gICAgICAgIGVsc2UgaWYgKG9sZENscykgeyBsaW5lLnN0eWxlQ2xhc3NlcyA9IG51bGw7IH1cbiAgICAgICAgdmFyIGlzY2hhbmdlID0gIW9sZFN0eWxlcyB8fCBvbGRTdHlsZXMubGVuZ3RoICE9IGxpbmUuc3R5bGVzLmxlbmd0aCB8fFxuICAgICAgICAgIG9sZENscyAhPSBuZXdDbHMgJiYgKCFvbGRDbHMgfHwgIW5ld0NscyB8fCBvbGRDbHMuYmdDbGFzcyAhPSBuZXdDbHMuYmdDbGFzcyB8fCBvbGRDbHMudGV4dENsYXNzICE9IG5ld0Nscy50ZXh0Q2xhc3MpO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgIWlzY2hhbmdlICYmIGkgPCBvbGRTdHlsZXMubGVuZ3RoOyArK2kpIHsgaXNjaGFuZ2UgPSBvbGRTdHlsZXNbaV0gIT0gbGluZS5zdHlsZXNbaV07IH1cbiAgICAgICAgaWYgKGlzY2hhbmdlKSB7IGNoYW5nZWRMaW5lcy5wdXNoKGNvbnRleHQubGluZSk7IH1cbiAgICAgICAgbGluZS5zdGF0ZUFmdGVyID0gY29udGV4dC5zYXZlKCk7XG4gICAgICAgIGNvbnRleHQubmV4dExpbmUoKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIGlmIChsaW5lLnRleHQubGVuZ3RoIDw9IGNtLm9wdGlvbnMubWF4SGlnaGxpZ2h0TGVuZ3RoKVxuICAgICAgICAgIHsgcHJvY2Vzc0xpbmUoY20sIGxpbmUudGV4dCwgY29udGV4dCk7IH1cbiAgICAgICAgbGluZS5zdGF0ZUFmdGVyID0gY29udGV4dC5saW5lICUgNSA9PSAwID8gY29udGV4dC5zYXZlKCkgOiBudWxsO1xuICAgICAgICBjb250ZXh0Lm5leHRMaW5lKCk7XG4gICAgICB9XG4gICAgICBpZiAoK25ldyBEYXRlID4gZW5kKSB7XG4gICAgICAgIHN0YXJ0V29ya2VyKGNtLCBjbS5vcHRpb25zLndvcmtEZWxheSk7XG4gICAgICAgIHJldHVybiB0cnVlXG4gICAgICB9XG4gICAgfSk7XG4gICAgZG9jLmhpZ2hsaWdodEZyb250aWVyID0gY29udGV4dC5saW5lO1xuICAgIGRvYy5tb2RlRnJvbnRpZXIgPSBNYXRoLm1heChkb2MubW9kZUZyb250aWVyLCBjb250ZXh0LmxpbmUpO1xuICAgIGlmIChjaGFuZ2VkTGluZXMubGVuZ3RoKSB7IHJ1bkluT3AoY20sIGZ1bmN0aW9uICgpIHtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2hhbmdlZExpbmVzLmxlbmd0aDsgaSsrKVxuICAgICAgICB7IHJlZ0xpbmVDaGFuZ2UoY20sIGNoYW5nZWRMaW5lc1tpXSwgXCJ0ZXh0XCIpOyB9XG4gICAgfSk7IH1cbiAgfVxuXG4gIC8vIERJU1BMQVkgRFJBV0lOR1xuXG4gIHZhciBEaXNwbGF5VXBkYXRlID0gZnVuY3Rpb24oY20sIHZpZXdwb3J0LCBmb3JjZSkge1xuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheTtcblxuICAgIHRoaXMudmlld3BvcnQgPSB2aWV3cG9ydDtcbiAgICAvLyBTdG9yZSBzb21lIHZhbHVlcyB0aGF0IHdlJ2xsIG5lZWQgbGF0ZXIgKGJ1dCBkb24ndCB3YW50IHRvIGZvcmNlIGEgcmVsYXlvdXQgZm9yKVxuICAgIHRoaXMudmlzaWJsZSA9IHZpc2libGVMaW5lcyhkaXNwbGF5LCBjbS5kb2MsIHZpZXdwb3J0KTtcbiAgICB0aGlzLmVkaXRvcklzSGlkZGVuID0gIWRpc3BsYXkud3JhcHBlci5vZmZzZXRXaWR0aDtcbiAgICB0aGlzLndyYXBwZXJIZWlnaHQgPSBkaXNwbGF5LndyYXBwZXIuY2xpZW50SGVpZ2h0O1xuICAgIHRoaXMud3JhcHBlcldpZHRoID0gZGlzcGxheS53cmFwcGVyLmNsaWVudFdpZHRoO1xuICAgIHRoaXMub2xkRGlzcGxheVdpZHRoID0gZGlzcGxheVdpZHRoKGNtKTtcbiAgICB0aGlzLmZvcmNlID0gZm9yY2U7XG4gICAgdGhpcy5kaW1zID0gZ2V0RGltZW5zaW9ucyhjbSk7XG4gICAgdGhpcy5ldmVudHMgPSBbXTtcbiAgfTtcblxuICBEaXNwbGF5VXBkYXRlLnByb3RvdHlwZS5zaWduYWwgPSBmdW5jdGlvbiAoZW1pdHRlciwgdHlwZSkge1xuICAgIGlmIChoYXNIYW5kbGVyKGVtaXR0ZXIsIHR5cGUpKVxuICAgICAgeyB0aGlzLmV2ZW50cy5wdXNoKGFyZ3VtZW50cyk7IH1cbiAgfTtcbiAgRGlzcGxheVVwZGF0ZS5wcm90b3R5cGUuZmluaXNoID0gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuZXZlbnRzLmxlbmd0aDsgaSsrKVxuICAgICAgeyBzaWduYWwuYXBwbHkobnVsbCwgdGhpcyQxLmV2ZW50c1tpXSk7IH1cbiAgfTtcblxuICBmdW5jdGlvbiBtYXliZUNsaXBTY3JvbGxiYXJzKGNtKSB7XG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5O1xuICAgIGlmICghZGlzcGxheS5zY3JvbGxiYXJzQ2xpcHBlZCAmJiBkaXNwbGF5LnNjcm9sbGVyLm9mZnNldFdpZHRoKSB7XG4gICAgICBkaXNwbGF5Lm5hdGl2ZUJhcldpZHRoID0gZGlzcGxheS5zY3JvbGxlci5vZmZzZXRXaWR0aCAtIGRpc3BsYXkuc2Nyb2xsZXIuY2xpZW50V2lkdGg7XG4gICAgICBkaXNwbGF5LmhlaWdodEZvcmNlci5zdHlsZS5oZWlnaHQgPSBzY3JvbGxHYXAoY20pICsgXCJweFwiO1xuICAgICAgZGlzcGxheS5zaXplci5zdHlsZS5tYXJnaW5Cb3R0b20gPSAtZGlzcGxheS5uYXRpdmVCYXJXaWR0aCArIFwicHhcIjtcbiAgICAgIGRpc3BsYXkuc2l6ZXIuc3R5bGUuYm9yZGVyUmlnaHRXaWR0aCA9IHNjcm9sbEdhcChjbSkgKyBcInB4XCI7XG4gICAgICBkaXNwbGF5LnNjcm9sbGJhcnNDbGlwcGVkID0gdHJ1ZTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBzZWxlY3Rpb25TbmFwc2hvdChjbSkge1xuICAgIGlmIChjbS5oYXNGb2N1cygpKSB7IHJldHVybiBudWxsIH1cbiAgICB2YXIgYWN0aXZlID0gYWN0aXZlRWx0KCk7XG4gICAgaWYgKCFhY3RpdmUgfHwgIWNvbnRhaW5zKGNtLmRpc3BsYXkubGluZURpdiwgYWN0aXZlKSkgeyByZXR1cm4gbnVsbCB9XG4gICAgdmFyIHJlc3VsdCA9IHthY3RpdmVFbHQ6IGFjdGl2ZX07XG4gICAgaWYgKHdpbmRvdy5nZXRTZWxlY3Rpb24pIHtcbiAgICAgIHZhciBzZWwgPSB3aW5kb3cuZ2V0U2VsZWN0aW9uKCk7XG4gICAgICBpZiAoc2VsLmFuY2hvck5vZGUgJiYgc2VsLmV4dGVuZCAmJiBjb250YWlucyhjbS5kaXNwbGF5LmxpbmVEaXYsIHNlbC5hbmNob3JOb2RlKSkge1xuICAgICAgICByZXN1bHQuYW5jaG9yTm9kZSA9IHNlbC5hbmNob3JOb2RlO1xuICAgICAgICByZXN1bHQuYW5jaG9yT2Zmc2V0ID0gc2VsLmFuY2hvck9mZnNldDtcbiAgICAgICAgcmVzdWx0LmZvY3VzTm9kZSA9IHNlbC5mb2N1c05vZGU7XG4gICAgICAgIHJlc3VsdC5mb2N1c09mZnNldCA9IHNlbC5mb2N1c09mZnNldDtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHJlc3VsdFxuICB9XG5cbiAgZnVuY3Rpb24gcmVzdG9yZVNlbGVjdGlvbihzbmFwc2hvdCkge1xuICAgIGlmICghc25hcHNob3QgfHwgIXNuYXBzaG90LmFjdGl2ZUVsdCB8fCBzbmFwc2hvdC5hY3RpdmVFbHQgPT0gYWN0aXZlRWx0KCkpIHsgcmV0dXJuIH1cbiAgICBzbmFwc2hvdC5hY3RpdmVFbHQuZm9jdXMoKTtcbiAgICBpZiAoc25hcHNob3QuYW5jaG9yTm9kZSAmJiBjb250YWlucyhkb2N1bWVudC5ib2R5LCBzbmFwc2hvdC5hbmNob3JOb2RlKSAmJiBjb250YWlucyhkb2N1bWVudC5ib2R5LCBzbmFwc2hvdC5mb2N1c05vZGUpKSB7XG4gICAgICB2YXIgc2VsID0gd2luZG93LmdldFNlbGVjdGlvbigpLCByYW5nZSQkMSA9IGRvY3VtZW50LmNyZWF0ZVJhbmdlKCk7XG4gICAgICByYW5nZSQkMS5zZXRFbmQoc25hcHNob3QuYW5jaG9yTm9kZSwgc25hcHNob3QuYW5jaG9yT2Zmc2V0KTtcbiAgICAgIHJhbmdlJCQxLmNvbGxhcHNlKGZhbHNlKTtcbiAgICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICAgIHNlbC5hZGRSYW5nZShyYW5nZSQkMSk7XG4gICAgICBzZWwuZXh0ZW5kKHNuYXBzaG90LmZvY3VzTm9kZSwgc25hcHNob3QuZm9jdXNPZmZzZXQpO1xuICAgIH1cbiAgfVxuXG4gIC8vIERvZXMgdGhlIGFjdHVhbCB1cGRhdGluZyBvZiB0aGUgbGluZSBkaXNwbGF5LiBCYWlscyBvdXRcbiAgLy8gKHJldHVybmluZyBmYWxzZSkgd2hlbiB0aGVyZSBpcyBub3RoaW5nIHRvIGJlIGRvbmUgYW5kIGZvcmNlZCBpc1xuICAvLyBmYWxzZS5cbiAgZnVuY3Rpb24gdXBkYXRlRGlzcGxheUlmTmVlZGVkKGNtLCB1cGRhdGUpIHtcbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXksIGRvYyA9IGNtLmRvYztcblxuICAgIGlmICh1cGRhdGUuZWRpdG9ySXNIaWRkZW4pIHtcbiAgICAgIHJlc2V0VmlldyhjbSk7XG4gICAgICByZXR1cm4gZmFsc2VcbiAgICB9XG5cbiAgICAvLyBCYWlsIG91dCBpZiB0aGUgdmlzaWJsZSBhcmVhIGlzIGFscmVhZHkgcmVuZGVyZWQgYW5kIG5vdGhpbmcgY2hhbmdlZC5cbiAgICBpZiAoIXVwZGF0ZS5mb3JjZSAmJlxuICAgICAgICB1cGRhdGUudmlzaWJsZS5mcm9tID49IGRpc3BsYXkudmlld0Zyb20gJiYgdXBkYXRlLnZpc2libGUudG8gPD0gZGlzcGxheS52aWV3VG8gJiZcbiAgICAgICAgKGRpc3BsYXkudXBkYXRlTGluZU51bWJlcnMgPT0gbnVsbCB8fCBkaXNwbGF5LnVwZGF0ZUxpbmVOdW1iZXJzID49IGRpc3BsYXkudmlld1RvKSAmJlxuICAgICAgICBkaXNwbGF5LnJlbmRlcmVkVmlldyA9PSBkaXNwbGF5LnZpZXcgJiYgY291bnREaXJ0eVZpZXcoY20pID09IDApXG4gICAgICB7IHJldHVybiBmYWxzZSB9XG5cbiAgICBpZiAobWF5YmVVcGRhdGVMaW5lTnVtYmVyV2lkdGgoY20pKSB7XG4gICAgICByZXNldFZpZXcoY20pO1xuICAgICAgdXBkYXRlLmRpbXMgPSBnZXREaW1lbnNpb25zKGNtKTtcbiAgICB9XG5cbiAgICAvLyBDb21wdXRlIGEgc3VpdGFibGUgbmV3IHZpZXdwb3J0IChmcm9tICYgdG8pXG4gICAgdmFyIGVuZCA9IGRvYy5maXJzdCArIGRvYy5zaXplO1xuICAgIHZhciBmcm9tID0gTWF0aC5tYXgodXBkYXRlLnZpc2libGUuZnJvbSAtIGNtLm9wdGlvbnMudmlld3BvcnRNYXJnaW4sIGRvYy5maXJzdCk7XG4gICAgdmFyIHRvID0gTWF0aC5taW4oZW5kLCB1cGRhdGUudmlzaWJsZS50byArIGNtLm9wdGlvbnMudmlld3BvcnRNYXJnaW4pO1xuICAgIGlmIChkaXNwbGF5LnZpZXdGcm9tIDwgZnJvbSAmJiBmcm9tIC0gZGlzcGxheS52aWV3RnJvbSA8IDIwKSB7IGZyb20gPSBNYXRoLm1heChkb2MuZmlyc3QsIGRpc3BsYXkudmlld0Zyb20pOyB9XG4gICAgaWYgKGRpc3BsYXkudmlld1RvID4gdG8gJiYgZGlzcGxheS52aWV3VG8gLSB0byA8IDIwKSB7IHRvID0gTWF0aC5taW4oZW5kLCBkaXNwbGF5LnZpZXdUbyk7IH1cbiAgICBpZiAoc2F3Q29sbGFwc2VkU3BhbnMpIHtcbiAgICAgIGZyb20gPSB2aXN1YWxMaW5lTm8oY20uZG9jLCBmcm9tKTtcbiAgICAgIHRvID0gdmlzdWFsTGluZUVuZE5vKGNtLmRvYywgdG8pO1xuICAgIH1cblxuICAgIHZhciBkaWZmZXJlbnQgPSBmcm9tICE9IGRpc3BsYXkudmlld0Zyb20gfHwgdG8gIT0gZGlzcGxheS52aWV3VG8gfHxcbiAgICAgIGRpc3BsYXkubGFzdFdyYXBIZWlnaHQgIT0gdXBkYXRlLndyYXBwZXJIZWlnaHQgfHwgZGlzcGxheS5sYXN0V3JhcFdpZHRoICE9IHVwZGF0ZS53cmFwcGVyV2lkdGg7XG4gICAgYWRqdXN0VmlldyhjbSwgZnJvbSwgdG8pO1xuXG4gICAgZGlzcGxheS52aWV3T2Zmc2V0ID0gaGVpZ2h0QXRMaW5lKGdldExpbmUoY20uZG9jLCBkaXNwbGF5LnZpZXdGcm9tKSk7XG4gICAgLy8gUG9zaXRpb24gdGhlIG1vdmVyIGRpdiB0byBhbGlnbiB3aXRoIHRoZSBjdXJyZW50IHNjcm9sbCBwb3NpdGlvblxuICAgIGNtLmRpc3BsYXkubW92ZXIuc3R5bGUudG9wID0gZGlzcGxheS52aWV3T2Zmc2V0ICsgXCJweFwiO1xuXG4gICAgdmFyIHRvVXBkYXRlID0gY291bnREaXJ0eVZpZXcoY20pO1xuICAgIGlmICghZGlmZmVyZW50ICYmIHRvVXBkYXRlID09IDAgJiYgIXVwZGF0ZS5mb3JjZSAmJiBkaXNwbGF5LnJlbmRlcmVkVmlldyA9PSBkaXNwbGF5LnZpZXcgJiZcbiAgICAgICAgKGRpc3BsYXkudXBkYXRlTGluZU51bWJlcnMgPT0gbnVsbCB8fCBkaXNwbGF5LnVwZGF0ZUxpbmVOdW1iZXJzID49IGRpc3BsYXkudmlld1RvKSlcbiAgICAgIHsgcmV0dXJuIGZhbHNlIH1cblxuICAgIC8vIEZvciBiaWcgY2hhbmdlcywgd2UgaGlkZSB0aGUgZW5jbG9zaW5nIGVsZW1lbnQgZHVyaW5nIHRoZVxuICAgIC8vIHVwZGF0ZSwgc2luY2UgdGhhdCBzcGVlZHMgdXAgdGhlIG9wZXJhdGlvbnMgb24gbW9zdCBicm93c2Vycy5cbiAgICB2YXIgc2VsU25hcHNob3QgPSBzZWxlY3Rpb25TbmFwc2hvdChjbSk7XG4gICAgaWYgKHRvVXBkYXRlID4gNCkgeyBkaXNwbGF5LmxpbmVEaXYuc3R5bGUuZGlzcGxheSA9IFwibm9uZVwiOyB9XG4gICAgcGF0Y2hEaXNwbGF5KGNtLCBkaXNwbGF5LnVwZGF0ZUxpbmVOdW1iZXJzLCB1cGRhdGUuZGltcyk7XG4gICAgaWYgKHRvVXBkYXRlID4gNCkgeyBkaXNwbGF5LmxpbmVEaXYuc3R5bGUuZGlzcGxheSA9IFwiXCI7IH1cbiAgICBkaXNwbGF5LnJlbmRlcmVkVmlldyA9IGRpc3BsYXkudmlldztcbiAgICAvLyBUaGVyZSBtaWdodCBoYXZlIGJlZW4gYSB3aWRnZXQgd2l0aCBhIGZvY3VzZWQgZWxlbWVudCB0aGF0IGdvdFxuICAgIC8vIGhpZGRlbiBvciB1cGRhdGVkLCBpZiBzbyByZS1mb2N1cyBpdC5cbiAgICByZXN0b3JlU2VsZWN0aW9uKHNlbFNuYXBzaG90KTtcblxuICAgIC8vIFByZXZlbnQgc2VsZWN0aW9uIGFuZCBjdXJzb3JzIGZyb20gaW50ZXJmZXJpbmcgd2l0aCB0aGUgc2Nyb2xsXG4gICAgLy8gd2lkdGggYW5kIGhlaWdodC5cbiAgICByZW1vdmVDaGlsZHJlbihkaXNwbGF5LmN1cnNvckRpdik7XG4gICAgcmVtb3ZlQ2hpbGRyZW4oZGlzcGxheS5zZWxlY3Rpb25EaXYpO1xuICAgIGRpc3BsYXkuZ3V0dGVycy5zdHlsZS5oZWlnaHQgPSBkaXNwbGF5LnNpemVyLnN0eWxlLm1pbkhlaWdodCA9IDA7XG5cbiAgICBpZiAoZGlmZmVyZW50KSB7XG4gICAgICBkaXNwbGF5Lmxhc3RXcmFwSGVpZ2h0ID0gdXBkYXRlLndyYXBwZXJIZWlnaHQ7XG4gICAgICBkaXNwbGF5Lmxhc3RXcmFwV2lkdGggPSB1cGRhdGUud3JhcHBlcldpZHRoO1xuICAgICAgc3RhcnRXb3JrZXIoY20sIDQwMCk7XG4gICAgfVxuXG4gICAgZGlzcGxheS51cGRhdGVMaW5lTnVtYmVycyA9IG51bGw7XG5cbiAgICByZXR1cm4gdHJ1ZVxuICB9XG5cbiAgZnVuY3Rpb24gcG9zdFVwZGF0ZURpc3BsYXkoY20sIHVwZGF0ZSkge1xuICAgIHZhciB2aWV3cG9ydCA9IHVwZGF0ZS52aWV3cG9ydDtcblxuICAgIGZvciAodmFyIGZpcnN0ID0gdHJ1ZTs7IGZpcnN0ID0gZmFsc2UpIHtcbiAgICAgIGlmICghZmlyc3QgfHwgIWNtLm9wdGlvbnMubGluZVdyYXBwaW5nIHx8IHVwZGF0ZS5vbGREaXNwbGF5V2lkdGggPT0gZGlzcGxheVdpZHRoKGNtKSkge1xuICAgICAgICAvLyBDbGlwIGZvcmNlZCB2aWV3cG9ydCB0byBhY3R1YWwgc2Nyb2xsYWJsZSBhcmVhLlxuICAgICAgICBpZiAodmlld3BvcnQgJiYgdmlld3BvcnQudG9wICE9IG51bGwpXG4gICAgICAgICAgeyB2aWV3cG9ydCA9IHt0b3A6IE1hdGgubWluKGNtLmRvYy5oZWlnaHQgKyBwYWRkaW5nVmVydChjbS5kaXNwbGF5KSAtIGRpc3BsYXlIZWlnaHQoY20pLCB2aWV3cG9ydC50b3ApfTsgfVxuICAgICAgICAvLyBVcGRhdGVkIGxpbmUgaGVpZ2h0cyBtaWdodCByZXN1bHQgaW4gdGhlIGRyYXduIGFyZWEgbm90XG4gICAgICAgIC8vIGFjdHVhbGx5IGNvdmVyaW5nIHRoZSB2aWV3cG9ydC4gS2VlcCBsb29waW5nIHVudGlsIGl0IGRvZXMuXG4gICAgICAgIHVwZGF0ZS52aXNpYmxlID0gdmlzaWJsZUxpbmVzKGNtLmRpc3BsYXksIGNtLmRvYywgdmlld3BvcnQpO1xuICAgICAgICBpZiAodXBkYXRlLnZpc2libGUuZnJvbSA+PSBjbS5kaXNwbGF5LnZpZXdGcm9tICYmIHVwZGF0ZS52aXNpYmxlLnRvIDw9IGNtLmRpc3BsYXkudmlld1RvKVxuICAgICAgICAgIHsgYnJlYWsgfVxuICAgICAgfVxuICAgICAgaWYgKCF1cGRhdGVEaXNwbGF5SWZOZWVkZWQoY20sIHVwZGF0ZSkpIHsgYnJlYWsgfVxuICAgICAgdXBkYXRlSGVpZ2h0c0luVmlld3BvcnQoY20pO1xuICAgICAgdmFyIGJhck1lYXN1cmUgPSBtZWFzdXJlRm9yU2Nyb2xsYmFycyhjbSk7XG4gICAgICB1cGRhdGVTZWxlY3Rpb24oY20pO1xuICAgICAgdXBkYXRlU2Nyb2xsYmFycyhjbSwgYmFyTWVhc3VyZSk7XG4gICAgICBzZXREb2N1bWVudEhlaWdodChjbSwgYmFyTWVhc3VyZSk7XG4gICAgICB1cGRhdGUuZm9yY2UgPSBmYWxzZTtcbiAgICB9XG5cbiAgICB1cGRhdGUuc2lnbmFsKGNtLCBcInVwZGF0ZVwiLCBjbSk7XG4gICAgaWYgKGNtLmRpc3BsYXkudmlld0Zyb20gIT0gY20uZGlzcGxheS5yZXBvcnRlZFZpZXdGcm9tIHx8IGNtLmRpc3BsYXkudmlld1RvICE9IGNtLmRpc3BsYXkucmVwb3J0ZWRWaWV3VG8pIHtcbiAgICAgIHVwZGF0ZS5zaWduYWwoY20sIFwidmlld3BvcnRDaGFuZ2VcIiwgY20sIGNtLmRpc3BsYXkudmlld0Zyb20sIGNtLmRpc3BsYXkudmlld1RvKTtcbiAgICAgIGNtLmRpc3BsYXkucmVwb3J0ZWRWaWV3RnJvbSA9IGNtLmRpc3BsYXkudmlld0Zyb207IGNtLmRpc3BsYXkucmVwb3J0ZWRWaWV3VG8gPSBjbS5kaXNwbGF5LnZpZXdUbztcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiB1cGRhdGVEaXNwbGF5U2ltcGxlKGNtLCB2aWV3cG9ydCkge1xuICAgIHZhciB1cGRhdGUgPSBuZXcgRGlzcGxheVVwZGF0ZShjbSwgdmlld3BvcnQpO1xuICAgIGlmICh1cGRhdGVEaXNwbGF5SWZOZWVkZWQoY20sIHVwZGF0ZSkpIHtcbiAgICAgIHVwZGF0ZUhlaWdodHNJblZpZXdwb3J0KGNtKTtcbiAgICAgIHBvc3RVcGRhdGVEaXNwbGF5KGNtLCB1cGRhdGUpO1xuICAgICAgdmFyIGJhck1lYXN1cmUgPSBtZWFzdXJlRm9yU2Nyb2xsYmFycyhjbSk7XG4gICAgICB1cGRhdGVTZWxlY3Rpb24oY20pO1xuICAgICAgdXBkYXRlU2Nyb2xsYmFycyhjbSwgYmFyTWVhc3VyZSk7XG4gICAgICBzZXREb2N1bWVudEhlaWdodChjbSwgYmFyTWVhc3VyZSk7XG4gICAgICB1cGRhdGUuZmluaXNoKCk7XG4gICAgfVxuICB9XG5cbiAgLy8gU3luYyB0aGUgYWN0dWFsIGRpc3BsYXkgRE9NIHN0cnVjdHVyZSB3aXRoIGRpc3BsYXkudmlldywgcmVtb3ZpbmdcbiAgLy8gbm9kZXMgZm9yIGxpbmVzIHRoYXQgYXJlIG5vIGxvbmdlciBpbiB2aWV3LCBhbmQgY3JlYXRpbmcgdGhlIG9uZXNcbiAgLy8gdGhhdCBhcmUgbm90IHRoZXJlIHlldCwgYW5kIHVwZGF0aW5nIHRoZSBvbmVzIHRoYXQgYXJlIG91dCBvZlxuICAvLyBkYXRlLlxuICBmdW5jdGlvbiBwYXRjaERpc3BsYXkoY20sIHVwZGF0ZU51bWJlcnNGcm9tLCBkaW1zKSB7XG4gICAgdmFyIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBsaW5lTnVtYmVycyA9IGNtLm9wdGlvbnMubGluZU51bWJlcnM7XG4gICAgdmFyIGNvbnRhaW5lciA9IGRpc3BsYXkubGluZURpdiwgY3VyID0gY29udGFpbmVyLmZpcnN0Q2hpbGQ7XG5cbiAgICBmdW5jdGlvbiBybShub2RlKSB7XG4gICAgICB2YXIgbmV4dCA9IG5vZGUubmV4dFNpYmxpbmc7XG4gICAgICAvLyBXb3JrcyBhcm91bmQgYSB0aHJvdy1zY3JvbGwgYnVnIGluIE9TIFggV2Via2l0XG4gICAgICBpZiAod2Via2l0ICYmIG1hYyAmJiBjbS5kaXNwbGF5LmN1cnJlbnRXaGVlbFRhcmdldCA9PSBub2RlKVxuICAgICAgICB7IG5vZGUuc3R5bGUuZGlzcGxheSA9IFwibm9uZVwiOyB9XG4gICAgICBlbHNlXG4gICAgICAgIHsgbm9kZS5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKG5vZGUpOyB9XG4gICAgICByZXR1cm4gbmV4dFxuICAgIH1cblxuICAgIHZhciB2aWV3ID0gZGlzcGxheS52aWV3LCBsaW5lTiA9IGRpc3BsYXkudmlld0Zyb207XG4gICAgLy8gTG9vcCBvdmVyIHRoZSBlbGVtZW50cyBpbiB0aGUgdmlldywgc3luY2luZyBjdXIgKHRoZSBET00gbm9kZXNcbiAgICAvLyBpbiBkaXNwbGF5LmxpbmVEaXYpIHdpdGggdGhlIHZpZXcgYXMgd2UgZ28uXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB2aWV3Lmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgbGluZVZpZXcgPSB2aWV3W2ldO1xuICAgICAgaWYgKGxpbmVWaWV3LmhpZGRlbikgOyBlbHNlIGlmICghbGluZVZpZXcubm9kZSB8fCBsaW5lVmlldy5ub2RlLnBhcmVudE5vZGUgIT0gY29udGFpbmVyKSB7IC8vIE5vdCBkcmF3biB5ZXRcbiAgICAgICAgdmFyIG5vZGUgPSBidWlsZExpbmVFbGVtZW50KGNtLCBsaW5lVmlldywgbGluZU4sIGRpbXMpO1xuICAgICAgICBjb250YWluZXIuaW5zZXJ0QmVmb3JlKG5vZGUsIGN1cik7XG4gICAgICB9IGVsc2UgeyAvLyBBbHJlYWR5IGRyYXduXG4gICAgICAgIHdoaWxlIChjdXIgIT0gbGluZVZpZXcubm9kZSkgeyBjdXIgPSBybShjdXIpOyB9XG4gICAgICAgIHZhciB1cGRhdGVOdW1iZXIgPSBsaW5lTnVtYmVycyAmJiB1cGRhdGVOdW1iZXJzRnJvbSAhPSBudWxsICYmXG4gICAgICAgICAgdXBkYXRlTnVtYmVyc0Zyb20gPD0gbGluZU4gJiYgbGluZVZpZXcubGluZU51bWJlcjtcbiAgICAgICAgaWYgKGxpbmVWaWV3LmNoYW5nZXMpIHtcbiAgICAgICAgICBpZiAoaW5kZXhPZihsaW5lVmlldy5jaGFuZ2VzLCBcImd1dHRlclwiKSA+IC0xKSB7IHVwZGF0ZU51bWJlciA9IGZhbHNlOyB9XG4gICAgICAgICAgdXBkYXRlTGluZUZvckNoYW5nZXMoY20sIGxpbmVWaWV3LCBsaW5lTiwgZGltcyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHVwZGF0ZU51bWJlcikge1xuICAgICAgICAgIHJlbW92ZUNoaWxkcmVuKGxpbmVWaWV3LmxpbmVOdW1iZXIpO1xuICAgICAgICAgIGxpbmVWaWV3LmxpbmVOdW1iZXIuYXBwZW5kQ2hpbGQoZG9jdW1lbnQuY3JlYXRlVGV4dE5vZGUobGluZU51bWJlckZvcihjbS5vcHRpb25zLCBsaW5lTikpKTtcbiAgICAgICAgfVxuICAgICAgICBjdXIgPSBsaW5lVmlldy5ub2RlLm5leHRTaWJsaW5nO1xuICAgICAgfVxuICAgICAgbGluZU4gKz0gbGluZVZpZXcuc2l6ZTtcbiAgICB9XG4gICAgd2hpbGUgKGN1cikgeyBjdXIgPSBybShjdXIpOyB9XG4gIH1cblxuICBmdW5jdGlvbiB1cGRhdGVHdXR0ZXJTcGFjZShjbSkge1xuICAgIHZhciB3aWR0aCA9IGNtLmRpc3BsYXkuZ3V0dGVycy5vZmZzZXRXaWR0aDtcbiAgICBjbS5kaXNwbGF5LnNpemVyLnN0eWxlLm1hcmdpbkxlZnQgPSB3aWR0aCArIFwicHhcIjtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNldERvY3VtZW50SGVpZ2h0KGNtLCBtZWFzdXJlKSB7XG4gICAgY20uZGlzcGxheS5zaXplci5zdHlsZS5taW5IZWlnaHQgPSBtZWFzdXJlLmRvY0hlaWdodCArIFwicHhcIjtcbiAgICBjbS5kaXNwbGF5LmhlaWdodEZvcmNlci5zdHlsZS50b3AgPSBtZWFzdXJlLmRvY0hlaWdodCArIFwicHhcIjtcbiAgICBjbS5kaXNwbGF5Lmd1dHRlcnMuc3R5bGUuaGVpZ2h0ID0gKG1lYXN1cmUuZG9jSGVpZ2h0ICsgY20uZGlzcGxheS5iYXJIZWlnaHQgKyBzY3JvbGxHYXAoY20pKSArIFwicHhcIjtcbiAgfVxuXG4gIC8vIFJlYnVpbGQgdGhlIGd1dHRlciBlbGVtZW50cywgZW5zdXJlIHRoZSBtYXJnaW4gdG8gdGhlIGxlZnQgb2YgdGhlXG4gIC8vIGNvZGUgbWF0Y2hlcyB0aGVpciB3aWR0aC5cbiAgZnVuY3Rpb24gdXBkYXRlR3V0dGVycyhjbSkge1xuICAgIHZhciBndXR0ZXJzID0gY20uZGlzcGxheS5ndXR0ZXJzLCBzcGVjcyA9IGNtLm9wdGlvbnMuZ3V0dGVycztcbiAgICByZW1vdmVDaGlsZHJlbihndXR0ZXJzKTtcbiAgICB2YXIgaSA9IDA7XG4gICAgZm9yICg7IGkgPCBzcGVjcy5sZW5ndGg7ICsraSkge1xuICAgICAgdmFyIGd1dHRlckNsYXNzID0gc3BlY3NbaV07XG4gICAgICB2YXIgZ0VsdCA9IGd1dHRlcnMuYXBwZW5kQ2hpbGQoZWx0KFwiZGl2XCIsIG51bGwsIFwiQ29kZU1pcnJvci1ndXR0ZXIgXCIgKyBndXR0ZXJDbGFzcykpO1xuICAgICAgaWYgKGd1dHRlckNsYXNzID09IFwiQ29kZU1pcnJvci1saW5lbnVtYmVyc1wiKSB7XG4gICAgICAgIGNtLmRpc3BsYXkubGluZUd1dHRlciA9IGdFbHQ7XG4gICAgICAgIGdFbHQuc3R5bGUud2lkdGggPSAoY20uZGlzcGxheS5saW5lTnVtV2lkdGggfHwgMSkgKyBcInB4XCI7XG4gICAgICB9XG4gICAgfVxuICAgIGd1dHRlcnMuc3R5bGUuZGlzcGxheSA9IGkgPyBcIlwiIDogXCJub25lXCI7XG4gICAgdXBkYXRlR3V0dGVyU3BhY2UoY20pO1xuICB9XG5cbiAgLy8gTWFrZSBzdXJlIHRoZSBndXR0ZXJzIG9wdGlvbnMgY29udGFpbnMgdGhlIGVsZW1lbnRcbiAgLy8gXCJDb2RlTWlycm9yLWxpbmVudW1iZXJzXCIgd2hlbiB0aGUgbGluZU51bWJlcnMgb3B0aW9uIGlzIHRydWUuXG4gIGZ1bmN0aW9uIHNldEd1dHRlcnNGb3JMaW5lTnVtYmVycyhvcHRpb25zKSB7XG4gICAgdmFyIGZvdW5kID0gaW5kZXhPZihvcHRpb25zLmd1dHRlcnMsIFwiQ29kZU1pcnJvci1saW5lbnVtYmVyc1wiKTtcbiAgICBpZiAoZm91bmQgPT0gLTEgJiYgb3B0aW9ucy5saW5lTnVtYmVycykge1xuICAgICAgb3B0aW9ucy5ndXR0ZXJzID0gb3B0aW9ucy5ndXR0ZXJzLmNvbmNhdChbXCJDb2RlTWlycm9yLWxpbmVudW1iZXJzXCJdKTtcbiAgICB9IGVsc2UgaWYgKGZvdW5kID4gLTEgJiYgIW9wdGlvbnMubGluZU51bWJlcnMpIHtcbiAgICAgIG9wdGlvbnMuZ3V0dGVycyA9IG9wdGlvbnMuZ3V0dGVycy5zbGljZSgwKTtcbiAgICAgIG9wdGlvbnMuZ3V0dGVycy5zcGxpY2UoZm91bmQsIDEpO1xuICAgIH1cbiAgfVxuXG4gIC8vIFNpbmNlIHRoZSBkZWx0YSB2YWx1ZXMgcmVwb3J0ZWQgb24gbW91c2Ugd2hlZWwgZXZlbnRzIGFyZVxuICAvLyB1bnN0YW5kYXJkaXplZCBiZXR3ZWVuIGJyb3dzZXJzIGFuZCBldmVuIGJyb3dzZXIgdmVyc2lvbnMsIGFuZFxuICAvLyBnZW5lcmFsbHkgaG9ycmlibHkgdW5wcmVkaWN0YWJsZSwgdGhpcyBjb2RlIHN0YXJ0cyBieSBtZWFzdXJpbmdcbiAgLy8gdGhlIHNjcm9sbCBlZmZlY3QgdGhhdCB0aGUgZmlyc3QgZmV3IG1vdXNlIHdoZWVsIGV2ZW50cyBoYXZlLFxuICAvLyBhbmQsIGZyb20gdGhhdCwgZGV0ZWN0cyB0aGUgd2F5IGl0IGNhbiBjb252ZXJ0IGRlbHRhcyB0byBwaXhlbFxuICAvLyBvZmZzZXRzIGFmdGVyd2FyZHMuXG4gIC8vXG4gIC8vIFRoZSByZWFzb24gd2Ugd2FudCB0byBrbm93IHRoZSBhbW91bnQgYSB3aGVlbCBldmVudCB3aWxsIHNjcm9sbFxuICAvLyBpcyB0aGF0IGl0IGdpdmVzIHVzIGEgY2hhbmNlIHRvIHVwZGF0ZSB0aGUgZGlzcGxheSBiZWZvcmUgdGhlXG4gIC8vIGFjdHVhbCBzY3JvbGxpbmcgaGFwcGVucywgcmVkdWNpbmcgZmxpY2tlcmluZy5cblxuICB2YXIgd2hlZWxTYW1wbGVzID0gMCwgd2hlZWxQaXhlbHNQZXJVbml0ID0gbnVsbDtcbiAgLy8gRmlsbCBpbiBhIGJyb3dzZXItZGV0ZWN0ZWQgc3RhcnRpbmcgdmFsdWUgb24gYnJvd3NlcnMgd2hlcmUgd2VcbiAgLy8ga25vdyBvbmUuIFRoZXNlIGRvbid0IGhhdmUgdG8gYmUgYWNjdXJhdGUgLS0gdGhlIHJlc3VsdCBvZiB0aGVtXG4gIC8vIGJlaW5nIHdyb25nIHdvdWxkIGp1c3QgYmUgYSBzbGlnaHQgZmxpY2tlciBvbiB0aGUgZmlyc3Qgd2hlZWxcbiAgLy8gc2Nyb2xsIChpZiBpdCBpcyBsYXJnZSBlbm91Z2gpLlxuICBpZiAoaWUpIHsgd2hlZWxQaXhlbHNQZXJVbml0ID0gLS41MzsgfVxuICBlbHNlIGlmIChnZWNrbykgeyB3aGVlbFBpeGVsc1BlclVuaXQgPSAxNTsgfVxuICBlbHNlIGlmIChjaHJvbWUpIHsgd2hlZWxQaXhlbHNQZXJVbml0ID0gLS43OyB9XG4gIGVsc2UgaWYgKHNhZmFyaSkgeyB3aGVlbFBpeGVsc1BlclVuaXQgPSAtMS8zOyB9XG5cbiAgZnVuY3Rpb24gd2hlZWxFdmVudERlbHRhKGUpIHtcbiAgICB2YXIgZHggPSBlLndoZWVsRGVsdGFYLCBkeSA9IGUud2hlZWxEZWx0YVk7XG4gICAgaWYgKGR4ID09IG51bGwgJiYgZS5kZXRhaWwgJiYgZS5heGlzID09IGUuSE9SSVpPTlRBTF9BWElTKSB7IGR4ID0gZS5kZXRhaWw7IH1cbiAgICBpZiAoZHkgPT0gbnVsbCAmJiBlLmRldGFpbCAmJiBlLmF4aXMgPT0gZS5WRVJUSUNBTF9BWElTKSB7IGR5ID0gZS5kZXRhaWw7IH1cbiAgICBlbHNlIGlmIChkeSA9PSBudWxsKSB7IGR5ID0gZS53aGVlbERlbHRhOyB9XG4gICAgcmV0dXJuIHt4OiBkeCwgeTogZHl9XG4gIH1cbiAgZnVuY3Rpb24gd2hlZWxFdmVudFBpeGVscyhlKSB7XG4gICAgdmFyIGRlbHRhID0gd2hlZWxFdmVudERlbHRhKGUpO1xuICAgIGRlbHRhLnggKj0gd2hlZWxQaXhlbHNQZXJVbml0O1xuICAgIGRlbHRhLnkgKj0gd2hlZWxQaXhlbHNQZXJVbml0O1xuICAgIHJldHVybiBkZWx0YVxuICB9XG5cbiAgZnVuY3Rpb24gb25TY3JvbGxXaGVlbChjbSwgZSkge1xuICAgIHZhciBkZWx0YSA9IHdoZWVsRXZlbnREZWx0YShlKSwgZHggPSBkZWx0YS54LCBkeSA9IGRlbHRhLnk7XG5cbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXksIHNjcm9sbCA9IGRpc3BsYXkuc2Nyb2xsZXI7XG4gICAgLy8gUXVpdCBpZiB0aGVyZSdzIG5vdGhpbmcgdG8gc2Nyb2xsIGhlcmVcbiAgICB2YXIgY2FuU2Nyb2xsWCA9IHNjcm9sbC5zY3JvbGxXaWR0aCA+IHNjcm9sbC5jbGllbnRXaWR0aDtcbiAgICB2YXIgY2FuU2Nyb2xsWSA9IHNjcm9sbC5zY3JvbGxIZWlnaHQgPiBzY3JvbGwuY2xpZW50SGVpZ2h0O1xuICAgIGlmICghKGR4ICYmIGNhblNjcm9sbFggfHwgZHkgJiYgY2FuU2Nyb2xsWSkpIHsgcmV0dXJuIH1cblxuICAgIC8vIFdlYmtpdCBicm93c2VycyBvbiBPUyBYIGFib3J0IG1vbWVudHVtIHNjcm9sbHMgd2hlbiB0aGUgdGFyZ2V0XG4gICAgLy8gb2YgdGhlIHNjcm9sbCBldmVudCBpcyByZW1vdmVkIGZyb20gdGhlIHNjcm9sbGFibGUgZWxlbWVudC5cbiAgICAvLyBUaGlzIGhhY2sgKHNlZSByZWxhdGVkIGNvZGUgaW4gcGF0Y2hEaXNwbGF5KSBtYWtlcyBzdXJlIHRoZVxuICAgIC8vIGVsZW1lbnQgaXMga2VwdCBhcm91bmQuXG4gICAgaWYgKGR5ICYmIG1hYyAmJiB3ZWJraXQpIHtcbiAgICAgIG91dGVyOiBmb3IgKHZhciBjdXIgPSBlLnRhcmdldCwgdmlldyA9IGRpc3BsYXkudmlldzsgY3VyICE9IHNjcm9sbDsgY3VyID0gY3VyLnBhcmVudE5vZGUpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB2aWV3Lmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgaWYgKHZpZXdbaV0ubm9kZSA9PSBjdXIpIHtcbiAgICAgICAgICAgIGNtLmRpc3BsYXkuY3VycmVudFdoZWVsVGFyZ2V0ID0gY3VyO1xuICAgICAgICAgICAgYnJlYWsgb3V0ZXJcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBPbiBzb21lIGJyb3dzZXJzLCBob3Jpem9udGFsIHNjcm9sbGluZyB3aWxsIGNhdXNlIHJlZHJhd3MgdG9cbiAgICAvLyBoYXBwZW4gYmVmb3JlIHRoZSBndXR0ZXIgaGFzIGJlZW4gcmVhbGlnbmVkLCBjYXVzaW5nIGl0IHRvXG4gICAgLy8gd3JpZ2dsZSBhcm91bmQgaW4gYSBtb3N0IHVuc2VlbWx5IHdheS4gV2hlbiB3ZSBoYXZlIGFuXG4gICAgLy8gZXN0aW1hdGVkIHBpeGVscy9kZWx0YSB2YWx1ZSwgd2UganVzdCBoYW5kbGUgaG9yaXpvbnRhbFxuICAgIC8vIHNjcm9sbGluZyBlbnRpcmVseSBoZXJlLiBJdCdsbCBiZSBzbGlnaHRseSBvZmYgZnJvbSBuYXRpdmUsIGJ1dFxuICAgIC8vIGJldHRlciB0aGFuIGdsaXRjaGluZyBvdXQuXG4gICAgaWYgKGR4ICYmICFnZWNrbyAmJiAhcHJlc3RvICYmIHdoZWVsUGl4ZWxzUGVyVW5pdCAhPSBudWxsKSB7XG4gICAgICBpZiAoZHkgJiYgY2FuU2Nyb2xsWSlcbiAgICAgICAgeyB1cGRhdGVTY3JvbGxUb3AoY20sIE1hdGgubWF4KDAsIHNjcm9sbC5zY3JvbGxUb3AgKyBkeSAqIHdoZWVsUGl4ZWxzUGVyVW5pdCkpOyB9XG4gICAgICBzZXRTY3JvbGxMZWZ0KGNtLCBNYXRoLm1heCgwLCBzY3JvbGwuc2Nyb2xsTGVmdCArIGR4ICogd2hlZWxQaXhlbHNQZXJVbml0KSk7XG4gICAgICAvLyBPbmx5IHByZXZlbnQgZGVmYXVsdCBzY3JvbGxpbmcgaWYgdmVydGljYWwgc2Nyb2xsaW5nIGlzXG4gICAgICAvLyBhY3R1YWxseSBwb3NzaWJsZS4gT3RoZXJ3aXNlLCBpdCBjYXVzZXMgdmVydGljYWwgc2Nyb2xsXG4gICAgICAvLyBqaXR0ZXIgb24gT1NYIHRyYWNrcGFkcyB3aGVuIGRlbHRhWCBpcyBzbWFsbCBhbmQgZGVsdGFZXG4gICAgICAvLyBpcyBsYXJnZSAoaXNzdWUgIzM1NzkpXG4gICAgICBpZiAoIWR5IHx8IChkeSAmJiBjYW5TY3JvbGxZKSlcbiAgICAgICAgeyBlX3ByZXZlbnREZWZhdWx0KGUpOyB9XG4gICAgICBkaXNwbGF5LndoZWVsU3RhcnRYID0gbnVsbDsgLy8gQWJvcnQgbWVhc3VyZW1lbnQsIGlmIGluIHByb2dyZXNzXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICAvLyAnUHJvamVjdCcgdGhlIHZpc2libGUgdmlld3BvcnQgdG8gY292ZXIgdGhlIGFyZWEgdGhhdCBpcyBiZWluZ1xuICAgIC8vIHNjcm9sbGVkIGludG8gdmlldyAoaWYgd2Uga25vdyBlbm91Z2ggdG8gZXN0aW1hdGUgaXQpLlxuICAgIGlmIChkeSAmJiB3aGVlbFBpeGVsc1BlclVuaXQgIT0gbnVsbCkge1xuICAgICAgdmFyIHBpeGVscyA9IGR5ICogd2hlZWxQaXhlbHNQZXJVbml0O1xuICAgICAgdmFyIHRvcCA9IGNtLmRvYy5zY3JvbGxUb3AsIGJvdCA9IHRvcCArIGRpc3BsYXkud3JhcHBlci5jbGllbnRIZWlnaHQ7XG4gICAgICBpZiAocGl4ZWxzIDwgMCkgeyB0b3AgPSBNYXRoLm1heCgwLCB0b3AgKyBwaXhlbHMgLSA1MCk7IH1cbiAgICAgIGVsc2UgeyBib3QgPSBNYXRoLm1pbihjbS5kb2MuaGVpZ2h0LCBib3QgKyBwaXhlbHMgKyA1MCk7IH1cbiAgICAgIHVwZGF0ZURpc3BsYXlTaW1wbGUoY20sIHt0b3A6IHRvcCwgYm90dG9tOiBib3R9KTtcbiAgICB9XG5cbiAgICBpZiAod2hlZWxTYW1wbGVzIDwgMjApIHtcbiAgICAgIGlmIChkaXNwbGF5LndoZWVsU3RhcnRYID09IG51bGwpIHtcbiAgICAgICAgZGlzcGxheS53aGVlbFN0YXJ0WCA9IHNjcm9sbC5zY3JvbGxMZWZ0OyBkaXNwbGF5LndoZWVsU3RhcnRZID0gc2Nyb2xsLnNjcm9sbFRvcDtcbiAgICAgICAgZGlzcGxheS53aGVlbERYID0gZHg7IGRpc3BsYXkud2hlZWxEWSA9IGR5O1xuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBpZiAoZGlzcGxheS53aGVlbFN0YXJ0WCA9PSBudWxsKSB7IHJldHVybiB9XG4gICAgICAgICAgdmFyIG1vdmVkWCA9IHNjcm9sbC5zY3JvbGxMZWZ0IC0gZGlzcGxheS53aGVlbFN0YXJ0WDtcbiAgICAgICAgICB2YXIgbW92ZWRZID0gc2Nyb2xsLnNjcm9sbFRvcCAtIGRpc3BsYXkud2hlZWxTdGFydFk7XG4gICAgICAgICAgdmFyIHNhbXBsZSA9IChtb3ZlZFkgJiYgZGlzcGxheS53aGVlbERZICYmIG1vdmVkWSAvIGRpc3BsYXkud2hlZWxEWSkgfHxcbiAgICAgICAgICAgIChtb3ZlZFggJiYgZGlzcGxheS53aGVlbERYICYmIG1vdmVkWCAvIGRpc3BsYXkud2hlZWxEWCk7XG4gICAgICAgICAgZGlzcGxheS53aGVlbFN0YXJ0WCA9IGRpc3BsYXkud2hlZWxTdGFydFkgPSBudWxsO1xuICAgICAgICAgIGlmICghc2FtcGxlKSB7IHJldHVybiB9XG4gICAgICAgICAgd2hlZWxQaXhlbHNQZXJVbml0ID0gKHdoZWVsUGl4ZWxzUGVyVW5pdCAqIHdoZWVsU2FtcGxlcyArIHNhbXBsZSkgLyAod2hlZWxTYW1wbGVzICsgMSk7XG4gICAgICAgICAgKyt3aGVlbFNhbXBsZXM7XG4gICAgICAgIH0sIDIwMCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBkaXNwbGF5LndoZWVsRFggKz0gZHg7IGRpc3BsYXkud2hlZWxEWSArPSBkeTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyBTZWxlY3Rpb24gb2JqZWN0cyBhcmUgaW1tdXRhYmxlLiBBIG5ldyBvbmUgaXMgY3JlYXRlZCBldmVyeSB0aW1lXG4gIC8vIHRoZSBzZWxlY3Rpb24gY2hhbmdlcy4gQSBzZWxlY3Rpb24gaXMgb25lIG9yIG1vcmUgbm9uLW92ZXJsYXBwaW5nXG4gIC8vIChhbmQgbm9uLXRvdWNoaW5nKSByYW5nZXMsIHNvcnRlZCwgYW5kIGFuIGludGVnZXIgdGhhdCBpbmRpY2F0ZXNcbiAgLy8gd2hpY2ggb25lIGlzIHRoZSBwcmltYXJ5IHNlbGVjdGlvbiAodGhlIG9uZSB0aGF0J3Mgc2Nyb2xsZWQgaW50b1xuICAvLyB2aWV3LCB0aGF0IGdldEN1cnNvciByZXR1cm5zLCBldGMpLlxuICB2YXIgU2VsZWN0aW9uID0gZnVuY3Rpb24ocmFuZ2VzLCBwcmltSW5kZXgpIHtcbiAgICB0aGlzLnJhbmdlcyA9IHJhbmdlcztcbiAgICB0aGlzLnByaW1JbmRleCA9IHByaW1JbmRleDtcbiAgfTtcblxuICBTZWxlY3Rpb24ucHJvdG90eXBlLnByaW1hcnkgPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLnJhbmdlc1t0aGlzLnByaW1JbmRleF0gfTtcblxuICBTZWxlY3Rpb24ucHJvdG90eXBlLmVxdWFscyA9IGZ1bmN0aW9uIChvdGhlcikge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICBpZiAob3RoZXIgPT0gdGhpcykgeyByZXR1cm4gdHJ1ZSB9XG4gICAgaWYgKG90aGVyLnByaW1JbmRleCAhPSB0aGlzLnByaW1JbmRleCB8fCBvdGhlci5yYW5nZXMubGVuZ3RoICE9IHRoaXMucmFuZ2VzLmxlbmd0aCkgeyByZXR1cm4gZmFsc2UgfVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5yYW5nZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBoZXJlID0gdGhpcyQxLnJhbmdlc1tpXSwgdGhlcmUgPSBvdGhlci5yYW5nZXNbaV07XG4gICAgICBpZiAoIWVxdWFsQ3Vyc29yUG9zKGhlcmUuYW5jaG9yLCB0aGVyZS5hbmNob3IpIHx8ICFlcXVhbEN1cnNvclBvcyhoZXJlLmhlYWQsIHRoZXJlLmhlYWQpKSB7IHJldHVybiBmYWxzZSB9XG4gICAgfVxuICAgIHJldHVybiB0cnVlXG4gIH07XG5cbiAgU2VsZWN0aW9uLnByb3RvdHlwZS5kZWVwQ29weSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgdmFyIG91dCA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5yYW5nZXMubGVuZ3RoOyBpKyspXG4gICAgICB7IG91dFtpXSA9IG5ldyBSYW5nZShjb3B5UG9zKHRoaXMkMS5yYW5nZXNbaV0uYW5jaG9yKSwgY29weVBvcyh0aGlzJDEucmFuZ2VzW2ldLmhlYWQpKTsgfVxuICAgIHJldHVybiBuZXcgU2VsZWN0aW9uKG91dCwgdGhpcy5wcmltSW5kZXgpXG4gIH07XG5cbiAgU2VsZWN0aW9uLnByb3RvdHlwZS5zb21ldGhpbmdTZWxlY3RlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLnJhbmdlcy5sZW5ndGg7IGkrKylcbiAgICAgIHsgaWYgKCF0aGlzJDEucmFuZ2VzW2ldLmVtcHR5KCkpIHsgcmV0dXJuIHRydWUgfSB9XG4gICAgcmV0dXJuIGZhbHNlXG4gIH07XG5cbiAgU2VsZWN0aW9uLnByb3RvdHlwZS5jb250YWlucyA9IGZ1bmN0aW9uIChwb3MsIGVuZCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICBpZiAoIWVuZCkgeyBlbmQgPSBwb3M7IH1cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMucmFuZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgcmFuZ2UgPSB0aGlzJDEucmFuZ2VzW2ldO1xuICAgICAgaWYgKGNtcChlbmQsIHJhbmdlLmZyb20oKSkgPj0gMCAmJiBjbXAocG9zLCByYW5nZS50bygpKSA8PSAwKVxuICAgICAgICB7IHJldHVybiBpIH1cbiAgICB9XG4gICAgcmV0dXJuIC0xXG4gIH07XG5cbiAgdmFyIFJhbmdlID0gZnVuY3Rpb24oYW5jaG9yLCBoZWFkKSB7XG4gICAgdGhpcy5hbmNob3IgPSBhbmNob3I7IHRoaXMuaGVhZCA9IGhlYWQ7XG4gIH07XG5cbiAgUmFuZ2UucHJvdG90eXBlLmZyb20gPSBmdW5jdGlvbiAoKSB7IHJldHVybiBtaW5Qb3ModGhpcy5hbmNob3IsIHRoaXMuaGVhZCkgfTtcbiAgUmFuZ2UucHJvdG90eXBlLnRvID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gbWF4UG9zKHRoaXMuYW5jaG9yLCB0aGlzLmhlYWQpIH07XG4gIFJhbmdlLnByb3RvdHlwZS5lbXB0eSA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMuaGVhZC5saW5lID09IHRoaXMuYW5jaG9yLmxpbmUgJiYgdGhpcy5oZWFkLmNoID09IHRoaXMuYW5jaG9yLmNoIH07XG5cbiAgLy8gVGFrZSBhbiB1bnNvcnRlZCwgcG90ZW50aWFsbHkgb3ZlcmxhcHBpbmcgc2V0IG9mIHJhbmdlcywgYW5kXG4gIC8vIGJ1aWxkIGEgc2VsZWN0aW9uIG91dCBvZiBpdC4gJ0NvbnN1bWVzJyByYW5nZXMgYXJyYXkgKG1vZGlmeWluZ1xuICAvLyBpdCkuXG4gIGZ1bmN0aW9uIG5vcm1hbGl6ZVNlbGVjdGlvbihjbSwgcmFuZ2VzLCBwcmltSW5kZXgpIHtcbiAgICB2YXIgbWF5VG91Y2ggPSBjbSAmJiBjbS5vcHRpb25zLnNlbGVjdGlvbnNNYXlUb3VjaDtcbiAgICB2YXIgcHJpbSA9IHJhbmdlc1twcmltSW5kZXhdO1xuICAgIHJhbmdlcy5zb3J0KGZ1bmN0aW9uIChhLCBiKSB7IHJldHVybiBjbXAoYS5mcm9tKCksIGIuZnJvbSgpKTsgfSk7XG4gICAgcHJpbUluZGV4ID0gaW5kZXhPZihyYW5nZXMsIHByaW0pO1xuICAgIGZvciAodmFyIGkgPSAxOyBpIDwgcmFuZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgY3VyID0gcmFuZ2VzW2ldLCBwcmV2ID0gcmFuZ2VzW2kgLSAxXTtcbiAgICAgIHZhciBkaWZmID0gY21wKHByZXYudG8oKSwgY3VyLmZyb20oKSk7XG4gICAgICBpZiAobWF5VG91Y2ggJiYgIWN1ci5lbXB0eSgpID8gZGlmZiA+IDAgOiBkaWZmID49IDApIHtcbiAgICAgICAgdmFyIGZyb20gPSBtaW5Qb3MocHJldi5mcm9tKCksIGN1ci5mcm9tKCkpLCB0byA9IG1heFBvcyhwcmV2LnRvKCksIGN1ci50bygpKTtcbiAgICAgICAgdmFyIGludiA9IHByZXYuZW1wdHkoKSA/IGN1ci5mcm9tKCkgPT0gY3VyLmhlYWQgOiBwcmV2LmZyb20oKSA9PSBwcmV2LmhlYWQ7XG4gICAgICAgIGlmIChpIDw9IHByaW1JbmRleCkgeyAtLXByaW1JbmRleDsgfVxuICAgICAgICByYW5nZXMuc3BsaWNlKC0taSwgMiwgbmV3IFJhbmdlKGludiA/IHRvIDogZnJvbSwgaW52ID8gZnJvbSA6IHRvKSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuZXcgU2VsZWN0aW9uKHJhbmdlcywgcHJpbUluZGV4KVxuICB9XG5cbiAgZnVuY3Rpb24gc2ltcGxlU2VsZWN0aW9uKGFuY2hvciwgaGVhZCkge1xuICAgIHJldHVybiBuZXcgU2VsZWN0aW9uKFtuZXcgUmFuZ2UoYW5jaG9yLCBoZWFkIHx8IGFuY2hvcildLCAwKVxuICB9XG5cbiAgLy8gQ29tcHV0ZSB0aGUgcG9zaXRpb24gb2YgdGhlIGVuZCBvZiBhIGNoYW5nZSAoaXRzICd0bycgcHJvcGVydHlcbiAgLy8gcmVmZXJzIHRvIHRoZSBwcmUtY2hhbmdlIGVuZCkuXG4gIGZ1bmN0aW9uIGNoYW5nZUVuZChjaGFuZ2UpIHtcbiAgICBpZiAoIWNoYW5nZS50ZXh0KSB7IHJldHVybiBjaGFuZ2UudG8gfVxuICAgIHJldHVybiBQb3MoY2hhbmdlLmZyb20ubGluZSArIGNoYW5nZS50ZXh0Lmxlbmd0aCAtIDEsXG4gICAgICAgICAgICAgICBsc3QoY2hhbmdlLnRleHQpLmxlbmd0aCArIChjaGFuZ2UudGV4dC5sZW5ndGggPT0gMSA/IGNoYW5nZS5mcm9tLmNoIDogMCkpXG4gIH1cblxuICAvLyBBZGp1c3QgYSBwb3NpdGlvbiB0byByZWZlciB0byB0aGUgcG9zdC1jaGFuZ2UgcG9zaXRpb24gb2YgdGhlXG4gIC8vIHNhbWUgdGV4dCwgb3IgdGhlIGVuZCBvZiB0aGUgY2hhbmdlIGlmIHRoZSBjaGFuZ2UgY292ZXJzIGl0LlxuICBmdW5jdGlvbiBhZGp1c3RGb3JDaGFuZ2UocG9zLCBjaGFuZ2UpIHtcbiAgICBpZiAoY21wKHBvcywgY2hhbmdlLmZyb20pIDwgMCkgeyByZXR1cm4gcG9zIH1cbiAgICBpZiAoY21wKHBvcywgY2hhbmdlLnRvKSA8PSAwKSB7IHJldHVybiBjaGFuZ2VFbmQoY2hhbmdlKSB9XG5cbiAgICB2YXIgbGluZSA9IHBvcy5saW5lICsgY2hhbmdlLnRleHQubGVuZ3RoIC0gKGNoYW5nZS50by5saW5lIC0gY2hhbmdlLmZyb20ubGluZSkgLSAxLCBjaCA9IHBvcy5jaDtcbiAgICBpZiAocG9zLmxpbmUgPT0gY2hhbmdlLnRvLmxpbmUpIHsgY2ggKz0gY2hhbmdlRW5kKGNoYW5nZSkuY2ggLSBjaGFuZ2UudG8uY2g7IH1cbiAgICByZXR1cm4gUG9zKGxpbmUsIGNoKVxuICB9XG5cbiAgZnVuY3Rpb24gY29tcHV0ZVNlbEFmdGVyQ2hhbmdlKGRvYywgY2hhbmdlKSB7XG4gICAgdmFyIG91dCA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZG9jLnNlbC5yYW5nZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciByYW5nZSA9IGRvYy5zZWwucmFuZ2VzW2ldO1xuICAgICAgb3V0LnB1c2gobmV3IFJhbmdlKGFkanVzdEZvckNoYW5nZShyYW5nZS5hbmNob3IsIGNoYW5nZSksXG4gICAgICAgICAgICAgICAgICAgICAgICAgYWRqdXN0Rm9yQ2hhbmdlKHJhbmdlLmhlYWQsIGNoYW5nZSkpKTtcbiAgICB9XG4gICAgcmV0dXJuIG5vcm1hbGl6ZVNlbGVjdGlvbihkb2MuY20sIG91dCwgZG9jLnNlbC5wcmltSW5kZXgpXG4gIH1cblxuICBmdW5jdGlvbiBvZmZzZXRQb3MocG9zLCBvbGQsIG53KSB7XG4gICAgaWYgKHBvcy5saW5lID09IG9sZC5saW5lKVxuICAgICAgeyByZXR1cm4gUG9zKG53LmxpbmUsIHBvcy5jaCAtIG9sZC5jaCArIG53LmNoKSB9XG4gICAgZWxzZVxuICAgICAgeyByZXR1cm4gUG9zKG53LmxpbmUgKyAocG9zLmxpbmUgLSBvbGQubGluZSksIHBvcy5jaCkgfVxuICB9XG5cbiAgLy8gVXNlZCBieSByZXBsYWNlU2VsZWN0aW9ucyB0byBhbGxvdyBtb3ZpbmcgdGhlIHNlbGVjdGlvbiB0byB0aGVcbiAgLy8gc3RhcnQgb3IgYXJvdW5kIHRoZSByZXBsYWNlZCB0ZXN0LiBIaW50IG1heSBiZSBcInN0YXJ0XCIgb3IgXCJhcm91bmRcIi5cbiAgZnVuY3Rpb24gY29tcHV0ZVJlcGxhY2VkU2VsKGRvYywgY2hhbmdlcywgaGludCkge1xuICAgIHZhciBvdXQgPSBbXTtcbiAgICB2YXIgb2xkUHJldiA9IFBvcyhkb2MuZmlyc3QsIDApLCBuZXdQcmV2ID0gb2xkUHJldjtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNoYW5nZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBjaGFuZ2UgPSBjaGFuZ2VzW2ldO1xuICAgICAgdmFyIGZyb20gPSBvZmZzZXRQb3MoY2hhbmdlLmZyb20sIG9sZFByZXYsIG5ld1ByZXYpO1xuICAgICAgdmFyIHRvID0gb2Zmc2V0UG9zKGNoYW5nZUVuZChjaGFuZ2UpLCBvbGRQcmV2LCBuZXdQcmV2KTtcbiAgICAgIG9sZFByZXYgPSBjaGFuZ2UudG87XG4gICAgICBuZXdQcmV2ID0gdG87XG4gICAgICBpZiAoaGludCA9PSBcImFyb3VuZFwiKSB7XG4gICAgICAgIHZhciByYW5nZSA9IGRvYy5zZWwucmFuZ2VzW2ldLCBpbnYgPSBjbXAocmFuZ2UuaGVhZCwgcmFuZ2UuYW5jaG9yKSA8IDA7XG4gICAgICAgIG91dFtpXSA9IG5ldyBSYW5nZShpbnYgPyB0byA6IGZyb20sIGludiA/IGZyb20gOiB0byk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICBvdXRbaV0gPSBuZXcgUmFuZ2UoZnJvbSwgZnJvbSk7XG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuZXcgU2VsZWN0aW9uKG91dCwgZG9jLnNlbC5wcmltSW5kZXgpXG4gIH1cblxuICAvLyBVc2VkIHRvIGdldCB0aGUgZWRpdG9yIGludG8gYSBjb25zaXN0ZW50IHN0YXRlIGFnYWluIHdoZW4gb3B0aW9ucyBjaGFuZ2UuXG5cbiAgZnVuY3Rpb24gbG9hZE1vZGUoY20pIHtcbiAgICBjbS5kb2MubW9kZSA9IGdldE1vZGUoY20ub3B0aW9ucywgY20uZG9jLm1vZGVPcHRpb24pO1xuICAgIHJlc2V0TW9kZVN0YXRlKGNtKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHJlc2V0TW9kZVN0YXRlKGNtKSB7XG4gICAgY20uZG9jLml0ZXIoZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgIGlmIChsaW5lLnN0YXRlQWZ0ZXIpIHsgbGluZS5zdGF0ZUFmdGVyID0gbnVsbDsgfVxuICAgICAgaWYgKGxpbmUuc3R5bGVzKSB7IGxpbmUuc3R5bGVzID0gbnVsbDsgfVxuICAgIH0pO1xuICAgIGNtLmRvYy5tb2RlRnJvbnRpZXIgPSBjbS5kb2MuaGlnaGxpZ2h0RnJvbnRpZXIgPSBjbS5kb2MuZmlyc3Q7XG4gICAgc3RhcnRXb3JrZXIoY20sIDEwMCk7XG4gICAgY20uc3RhdGUubW9kZUdlbisrO1xuICAgIGlmIChjbS5jdXJPcCkgeyByZWdDaGFuZ2UoY20pOyB9XG4gIH1cblxuICAvLyBET0NVTUVOVCBEQVRBIFNUUlVDVFVSRVxuXG4gIC8vIEJ5IGRlZmF1bHQsIHVwZGF0ZXMgdGhhdCBzdGFydCBhbmQgZW5kIGF0IHRoZSBiZWdpbm5pbmcgb2YgYSBsaW5lXG4gIC8vIGFyZSB0cmVhdGVkIHNwZWNpYWxseSwgaW4gb3JkZXIgdG8gbWFrZSB0aGUgYXNzb2NpYXRpb24gb2YgbGluZVxuICAvLyB3aWRnZXRzIGFuZCBtYXJrZXIgZWxlbWVudHMgd2l0aCB0aGUgdGV4dCBiZWhhdmUgbW9yZSBpbnR1aXRpdmUuXG4gIGZ1bmN0aW9uIGlzV2hvbGVMaW5lVXBkYXRlKGRvYywgY2hhbmdlKSB7XG4gICAgcmV0dXJuIGNoYW5nZS5mcm9tLmNoID09IDAgJiYgY2hhbmdlLnRvLmNoID09IDAgJiYgbHN0KGNoYW5nZS50ZXh0KSA9PSBcIlwiICYmXG4gICAgICAoIWRvYy5jbSB8fCBkb2MuY20ub3B0aW9ucy53aG9sZUxpbmVVcGRhdGVCZWZvcmUpXG4gIH1cblxuICAvLyBQZXJmb3JtIGEgY2hhbmdlIG9uIHRoZSBkb2N1bWVudCBkYXRhIHN0cnVjdHVyZS5cbiAgZnVuY3Rpb24gdXBkYXRlRG9jKGRvYywgY2hhbmdlLCBtYXJrZWRTcGFucywgZXN0aW1hdGVIZWlnaHQkJDEpIHtcbiAgICBmdW5jdGlvbiBzcGFuc0ZvcihuKSB7cmV0dXJuIG1hcmtlZFNwYW5zID8gbWFya2VkU3BhbnNbbl0gOiBudWxsfVxuICAgIGZ1bmN0aW9uIHVwZGF0ZShsaW5lLCB0ZXh0LCBzcGFucykge1xuICAgICAgdXBkYXRlTGluZShsaW5lLCB0ZXh0LCBzcGFucywgZXN0aW1hdGVIZWlnaHQkJDEpO1xuICAgICAgc2lnbmFsTGF0ZXIobGluZSwgXCJjaGFuZ2VcIiwgbGluZSwgY2hhbmdlKTtcbiAgICB9XG4gICAgZnVuY3Rpb24gbGluZXNGb3Ioc3RhcnQsIGVuZCkge1xuICAgICAgdmFyIHJlc3VsdCA9IFtdO1xuICAgICAgZm9yICh2YXIgaSA9IHN0YXJ0OyBpIDwgZW5kOyArK2kpXG4gICAgICAgIHsgcmVzdWx0LnB1c2gobmV3IExpbmUodGV4dFtpXSwgc3BhbnNGb3IoaSksIGVzdGltYXRlSGVpZ2h0JCQxKSk7IH1cbiAgICAgIHJldHVybiByZXN1bHRcbiAgICB9XG5cbiAgICB2YXIgZnJvbSA9IGNoYW5nZS5mcm9tLCB0byA9IGNoYW5nZS50bywgdGV4dCA9IGNoYW5nZS50ZXh0O1xuICAgIHZhciBmaXJzdExpbmUgPSBnZXRMaW5lKGRvYywgZnJvbS5saW5lKSwgbGFzdExpbmUgPSBnZXRMaW5lKGRvYywgdG8ubGluZSk7XG4gICAgdmFyIGxhc3RUZXh0ID0gbHN0KHRleHQpLCBsYXN0U3BhbnMgPSBzcGFuc0Zvcih0ZXh0Lmxlbmd0aCAtIDEpLCBubGluZXMgPSB0by5saW5lIC0gZnJvbS5saW5lO1xuXG4gICAgLy8gQWRqdXN0IHRoZSBsaW5lIHN0cnVjdHVyZVxuICAgIGlmIChjaGFuZ2UuZnVsbCkge1xuICAgICAgZG9jLmluc2VydCgwLCBsaW5lc0ZvcigwLCB0ZXh0Lmxlbmd0aCkpO1xuICAgICAgZG9jLnJlbW92ZSh0ZXh0Lmxlbmd0aCwgZG9jLnNpemUgLSB0ZXh0Lmxlbmd0aCk7XG4gICAgfSBlbHNlIGlmIChpc1dob2xlTGluZVVwZGF0ZShkb2MsIGNoYW5nZSkpIHtcbiAgICAgIC8vIFRoaXMgaXMgYSB3aG9sZS1saW5lIHJlcGxhY2UuIFRyZWF0ZWQgc3BlY2lhbGx5IHRvIG1ha2VcbiAgICAgIC8vIHN1cmUgbGluZSBvYmplY3RzIG1vdmUgdGhlIHdheSB0aGV5IGFyZSBzdXBwb3NlZCB0by5cbiAgICAgIHZhciBhZGRlZCA9IGxpbmVzRm9yKDAsIHRleHQubGVuZ3RoIC0gMSk7XG4gICAgICB1cGRhdGUobGFzdExpbmUsIGxhc3RMaW5lLnRleHQsIGxhc3RTcGFucyk7XG4gICAgICBpZiAobmxpbmVzKSB7IGRvYy5yZW1vdmUoZnJvbS5saW5lLCBubGluZXMpOyB9XG4gICAgICBpZiAoYWRkZWQubGVuZ3RoKSB7IGRvYy5pbnNlcnQoZnJvbS5saW5lLCBhZGRlZCk7IH1cbiAgICB9IGVsc2UgaWYgKGZpcnN0TGluZSA9PSBsYXN0TGluZSkge1xuICAgICAgaWYgKHRleHQubGVuZ3RoID09IDEpIHtcbiAgICAgICAgdXBkYXRlKGZpcnN0TGluZSwgZmlyc3RMaW5lLnRleHQuc2xpY2UoMCwgZnJvbS5jaCkgKyBsYXN0VGV4dCArIGZpcnN0TGluZS50ZXh0LnNsaWNlKHRvLmNoKSwgbGFzdFNwYW5zKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBhZGRlZCQxID0gbGluZXNGb3IoMSwgdGV4dC5sZW5ndGggLSAxKTtcbiAgICAgICAgYWRkZWQkMS5wdXNoKG5ldyBMaW5lKGxhc3RUZXh0ICsgZmlyc3RMaW5lLnRleHQuc2xpY2UodG8uY2gpLCBsYXN0U3BhbnMsIGVzdGltYXRlSGVpZ2h0JCQxKSk7XG4gICAgICAgIHVwZGF0ZShmaXJzdExpbmUsIGZpcnN0TGluZS50ZXh0LnNsaWNlKDAsIGZyb20uY2gpICsgdGV4dFswXSwgc3BhbnNGb3IoMCkpO1xuICAgICAgICBkb2MuaW5zZXJ0KGZyb20ubGluZSArIDEsIGFkZGVkJDEpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodGV4dC5sZW5ndGggPT0gMSkge1xuICAgICAgdXBkYXRlKGZpcnN0TGluZSwgZmlyc3RMaW5lLnRleHQuc2xpY2UoMCwgZnJvbS5jaCkgKyB0ZXh0WzBdICsgbGFzdExpbmUudGV4dC5zbGljZSh0by5jaCksIHNwYW5zRm9yKDApKTtcbiAgICAgIGRvYy5yZW1vdmUoZnJvbS5saW5lICsgMSwgbmxpbmVzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdXBkYXRlKGZpcnN0TGluZSwgZmlyc3RMaW5lLnRleHQuc2xpY2UoMCwgZnJvbS5jaCkgKyB0ZXh0WzBdLCBzcGFuc0ZvcigwKSk7XG4gICAgICB1cGRhdGUobGFzdExpbmUsIGxhc3RUZXh0ICsgbGFzdExpbmUudGV4dC5zbGljZSh0by5jaCksIGxhc3RTcGFucyk7XG4gICAgICB2YXIgYWRkZWQkMiA9IGxpbmVzRm9yKDEsIHRleHQubGVuZ3RoIC0gMSk7XG4gICAgICBpZiAobmxpbmVzID4gMSkgeyBkb2MucmVtb3ZlKGZyb20ubGluZSArIDEsIG5saW5lcyAtIDEpOyB9XG4gICAgICBkb2MuaW5zZXJ0KGZyb20ubGluZSArIDEsIGFkZGVkJDIpO1xuICAgIH1cblxuICAgIHNpZ25hbExhdGVyKGRvYywgXCJjaGFuZ2VcIiwgZG9jLCBjaGFuZ2UpO1xuICB9XG5cbiAgLy8gQ2FsbCBmIGZvciBhbGwgbGlua2VkIGRvY3VtZW50cy5cbiAgZnVuY3Rpb24gbGlua2VkRG9jcyhkb2MsIGYsIHNoYXJlZEhpc3RPbmx5KSB7XG4gICAgZnVuY3Rpb24gcHJvcGFnYXRlKGRvYywgc2tpcCwgc2hhcmVkSGlzdCkge1xuICAgICAgaWYgKGRvYy5saW5rZWQpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBkb2MubGlua2VkLmxlbmd0aDsgKytpKSB7XG4gICAgICAgIHZhciByZWwgPSBkb2MubGlua2VkW2ldO1xuICAgICAgICBpZiAocmVsLmRvYyA9PSBza2lwKSB7IGNvbnRpbnVlIH1cbiAgICAgICAgdmFyIHNoYXJlZCA9IHNoYXJlZEhpc3QgJiYgcmVsLnNoYXJlZEhpc3Q7XG4gICAgICAgIGlmIChzaGFyZWRIaXN0T25seSAmJiAhc2hhcmVkKSB7IGNvbnRpbnVlIH1cbiAgICAgICAgZihyZWwuZG9jLCBzaGFyZWQpO1xuICAgICAgICBwcm9wYWdhdGUocmVsLmRvYywgZG9jLCBzaGFyZWQpO1xuICAgICAgfSB9XG4gICAgfVxuICAgIHByb3BhZ2F0ZShkb2MsIG51bGwsIHRydWUpO1xuICB9XG5cbiAgLy8gQXR0YWNoIGEgZG9jdW1lbnQgdG8gYW4gZWRpdG9yLlxuICBmdW5jdGlvbiBhdHRhY2hEb2MoY20sIGRvYykge1xuICAgIGlmIChkb2MuY20pIHsgdGhyb3cgbmV3IEVycm9yKFwiVGhpcyBkb2N1bWVudCBpcyBhbHJlYWR5IGluIHVzZS5cIikgfVxuICAgIGNtLmRvYyA9IGRvYztcbiAgICBkb2MuY20gPSBjbTtcbiAgICBlc3RpbWF0ZUxpbmVIZWlnaHRzKGNtKTtcbiAgICBsb2FkTW9kZShjbSk7XG4gICAgc2V0RGlyZWN0aW9uQ2xhc3MoY20pO1xuICAgIGlmICghY20ub3B0aW9ucy5saW5lV3JhcHBpbmcpIHsgZmluZE1heExpbmUoY20pOyB9XG4gICAgY20ub3B0aW9ucy5tb2RlID0gZG9jLm1vZGVPcHRpb247XG4gICAgcmVnQ2hhbmdlKGNtKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHNldERpcmVjdGlvbkNsYXNzKGNtKSB7XG4gIChjbS5kb2MuZGlyZWN0aW9uID09IFwicnRsXCIgPyBhZGRDbGFzcyA6IHJtQ2xhc3MpKGNtLmRpc3BsYXkubGluZURpdiwgXCJDb2RlTWlycm9yLXJ0bFwiKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGRpcmVjdGlvbkNoYW5nZWQoY20pIHtcbiAgICBydW5Jbk9wKGNtLCBmdW5jdGlvbiAoKSB7XG4gICAgICBzZXREaXJlY3Rpb25DbGFzcyhjbSk7XG4gICAgICByZWdDaGFuZ2UoY20pO1xuICAgIH0pO1xuICB9XG5cbiAgZnVuY3Rpb24gSGlzdG9yeShzdGFydEdlbikge1xuICAgIC8vIEFycmF5cyBvZiBjaGFuZ2UgZXZlbnRzIGFuZCBzZWxlY3Rpb25zLiBEb2luZyBzb21ldGhpbmcgYWRkcyBhblxuICAgIC8vIGV2ZW50IHRvIGRvbmUgYW5kIGNsZWFycyB1bmRvLiBVbmRvaW5nIG1vdmVzIGV2ZW50cyBmcm9tIGRvbmVcbiAgICAvLyB0byB1bmRvbmUsIHJlZG9pbmcgbW92ZXMgdGhlbSBpbiB0aGUgb3RoZXIgZGlyZWN0aW9uLlxuICAgIHRoaXMuZG9uZSA9IFtdOyB0aGlzLnVuZG9uZSA9IFtdO1xuICAgIHRoaXMudW5kb0RlcHRoID0gSW5maW5pdHk7XG4gICAgLy8gVXNlZCB0byB0cmFjayB3aGVuIGNoYW5nZXMgY2FuIGJlIG1lcmdlZCBpbnRvIGEgc2luZ2xlIHVuZG9cbiAgICAvLyBldmVudFxuICAgIHRoaXMubGFzdE1vZFRpbWUgPSB0aGlzLmxhc3RTZWxUaW1lID0gMDtcbiAgICB0aGlzLmxhc3RPcCA9IHRoaXMubGFzdFNlbE9wID0gbnVsbDtcbiAgICB0aGlzLmxhc3RPcmlnaW4gPSB0aGlzLmxhc3RTZWxPcmlnaW4gPSBudWxsO1xuICAgIC8vIFVzZWQgYnkgdGhlIGlzQ2xlYW4oKSBtZXRob2RcbiAgICB0aGlzLmdlbmVyYXRpb24gPSB0aGlzLm1heEdlbmVyYXRpb24gPSBzdGFydEdlbiB8fCAxO1xuICB9XG5cbiAgLy8gQ3JlYXRlIGEgaGlzdG9yeSBjaGFuZ2UgZXZlbnQgZnJvbSBhbiB1cGRhdGVEb2Mtc3R5bGUgY2hhbmdlXG4gIC8vIG9iamVjdC5cbiAgZnVuY3Rpb24gaGlzdG9yeUNoYW5nZUZyb21DaGFuZ2UoZG9jLCBjaGFuZ2UpIHtcbiAgICB2YXIgaGlzdENoYW5nZSA9IHtmcm9tOiBjb3B5UG9zKGNoYW5nZS5mcm9tKSwgdG86IGNoYW5nZUVuZChjaGFuZ2UpLCB0ZXh0OiBnZXRCZXR3ZWVuKGRvYywgY2hhbmdlLmZyb20sIGNoYW5nZS50byl9O1xuICAgIGF0dGFjaExvY2FsU3BhbnMoZG9jLCBoaXN0Q2hhbmdlLCBjaGFuZ2UuZnJvbS5saW5lLCBjaGFuZ2UudG8ubGluZSArIDEpO1xuICAgIGxpbmtlZERvY3MoZG9jLCBmdW5jdGlvbiAoZG9jKSB7IHJldHVybiBhdHRhY2hMb2NhbFNwYW5zKGRvYywgaGlzdENoYW5nZSwgY2hhbmdlLmZyb20ubGluZSwgY2hhbmdlLnRvLmxpbmUgKyAxKTsgfSwgdHJ1ZSk7XG4gICAgcmV0dXJuIGhpc3RDaGFuZ2VcbiAgfVxuXG4gIC8vIFBvcCBhbGwgc2VsZWN0aW9uIGV2ZW50cyBvZmYgdGhlIGVuZCBvZiBhIGhpc3RvcnkgYXJyYXkuIFN0b3AgYXRcbiAgLy8gYSBjaGFuZ2UgZXZlbnQuXG4gIGZ1bmN0aW9uIGNsZWFyU2VsZWN0aW9uRXZlbnRzKGFycmF5KSB7XG4gICAgd2hpbGUgKGFycmF5Lmxlbmd0aCkge1xuICAgICAgdmFyIGxhc3QgPSBsc3QoYXJyYXkpO1xuICAgICAgaWYgKGxhc3QucmFuZ2VzKSB7IGFycmF5LnBvcCgpOyB9XG4gICAgICBlbHNlIHsgYnJlYWsgfVxuICAgIH1cbiAgfVxuXG4gIC8vIEZpbmQgdGhlIHRvcCBjaGFuZ2UgZXZlbnQgaW4gdGhlIGhpc3RvcnkuIFBvcCBvZmYgc2VsZWN0aW9uXG4gIC8vIGV2ZW50cyB0aGF0IGFyZSBpbiB0aGUgd2F5LlxuICBmdW5jdGlvbiBsYXN0Q2hhbmdlRXZlbnQoaGlzdCwgZm9yY2UpIHtcbiAgICBpZiAoZm9yY2UpIHtcbiAgICAgIGNsZWFyU2VsZWN0aW9uRXZlbnRzKGhpc3QuZG9uZSk7XG4gICAgICByZXR1cm4gbHN0KGhpc3QuZG9uZSlcbiAgICB9IGVsc2UgaWYgKGhpc3QuZG9uZS5sZW5ndGggJiYgIWxzdChoaXN0LmRvbmUpLnJhbmdlcykge1xuICAgICAgcmV0dXJuIGxzdChoaXN0LmRvbmUpXG4gICAgfSBlbHNlIGlmIChoaXN0LmRvbmUubGVuZ3RoID4gMSAmJiAhaGlzdC5kb25lW2hpc3QuZG9uZS5sZW5ndGggLSAyXS5yYW5nZXMpIHtcbiAgICAgIGhpc3QuZG9uZS5wb3AoKTtcbiAgICAgIHJldHVybiBsc3QoaGlzdC5kb25lKVxuICAgIH1cbiAgfVxuXG4gIC8vIFJlZ2lzdGVyIGEgY2hhbmdlIGluIHRoZSBoaXN0b3J5LiBNZXJnZXMgY2hhbmdlcyB0aGF0IGFyZSB3aXRoaW5cbiAgLy8gYSBzaW5nbGUgb3BlcmF0aW9uLCBvciBhcmUgY2xvc2UgdG9nZXRoZXIgd2l0aCBhbiBvcmlnaW4gdGhhdFxuICAvLyBhbGxvd3MgbWVyZ2luZyAoc3RhcnRpbmcgd2l0aCBcIitcIikgaW50byBhIHNpbmdsZSBldmVudC5cbiAgZnVuY3Rpb24gYWRkQ2hhbmdlVG9IaXN0b3J5KGRvYywgY2hhbmdlLCBzZWxBZnRlciwgb3BJZCkge1xuICAgIHZhciBoaXN0ID0gZG9jLmhpc3Rvcnk7XG4gICAgaGlzdC51bmRvbmUubGVuZ3RoID0gMDtcbiAgICB2YXIgdGltZSA9ICtuZXcgRGF0ZSwgY3VyO1xuICAgIHZhciBsYXN0O1xuXG4gICAgaWYgKChoaXN0Lmxhc3RPcCA9PSBvcElkIHx8XG4gICAgICAgICBoaXN0Lmxhc3RPcmlnaW4gPT0gY2hhbmdlLm9yaWdpbiAmJiBjaGFuZ2Uub3JpZ2luICYmXG4gICAgICAgICAoKGNoYW5nZS5vcmlnaW4uY2hhckF0KDApID09IFwiK1wiICYmIGhpc3QubGFzdE1vZFRpbWUgPiB0aW1lIC0gKGRvYy5jbSA/IGRvYy5jbS5vcHRpb25zLmhpc3RvcnlFdmVudERlbGF5IDogNTAwKSkgfHxcbiAgICAgICAgICBjaGFuZ2Uub3JpZ2luLmNoYXJBdCgwKSA9PSBcIipcIikpICYmXG4gICAgICAgIChjdXIgPSBsYXN0Q2hhbmdlRXZlbnQoaGlzdCwgaGlzdC5sYXN0T3AgPT0gb3BJZCkpKSB7XG4gICAgICAvLyBNZXJnZSB0aGlzIGNoYW5nZSBpbnRvIHRoZSBsYXN0IGV2ZW50XG4gICAgICBsYXN0ID0gbHN0KGN1ci5jaGFuZ2VzKTtcbiAgICAgIGlmIChjbXAoY2hhbmdlLmZyb20sIGNoYW5nZS50bykgPT0gMCAmJiBjbXAoY2hhbmdlLmZyb20sIGxhc3QudG8pID09IDApIHtcbiAgICAgICAgLy8gT3B0aW1pemVkIGNhc2UgZm9yIHNpbXBsZSBpbnNlcnRpb24gLS0gZG9uJ3Qgd2FudCB0byBhZGRcbiAgICAgICAgLy8gbmV3IGNoYW5nZXNldHMgZm9yIGV2ZXJ5IGNoYXJhY3RlciB0eXBlZFxuICAgICAgICBsYXN0LnRvID0gY2hhbmdlRW5kKGNoYW5nZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICAvLyBBZGQgbmV3IHN1Yi1ldmVudFxuICAgICAgICBjdXIuY2hhbmdlcy5wdXNoKGhpc3RvcnlDaGFuZ2VGcm9tQ2hhbmdlKGRvYywgY2hhbmdlKSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8vIENhbiBub3QgYmUgbWVyZ2VkLCBzdGFydCBhIG5ldyBldmVudC5cbiAgICAgIHZhciBiZWZvcmUgPSBsc3QoaGlzdC5kb25lKTtcbiAgICAgIGlmICghYmVmb3JlIHx8ICFiZWZvcmUucmFuZ2VzKVxuICAgICAgICB7IHB1c2hTZWxlY3Rpb25Ub0hpc3RvcnkoZG9jLnNlbCwgaGlzdC5kb25lKTsgfVxuICAgICAgY3VyID0ge2NoYW5nZXM6IFtoaXN0b3J5Q2hhbmdlRnJvbUNoYW5nZShkb2MsIGNoYW5nZSldLFxuICAgICAgICAgICAgIGdlbmVyYXRpb246IGhpc3QuZ2VuZXJhdGlvbn07XG4gICAgICBoaXN0LmRvbmUucHVzaChjdXIpO1xuICAgICAgd2hpbGUgKGhpc3QuZG9uZS5sZW5ndGggPiBoaXN0LnVuZG9EZXB0aCkge1xuICAgICAgICBoaXN0LmRvbmUuc2hpZnQoKTtcbiAgICAgICAgaWYgKCFoaXN0LmRvbmVbMF0ucmFuZ2VzKSB7IGhpc3QuZG9uZS5zaGlmdCgpOyB9XG4gICAgICB9XG4gICAgfVxuICAgIGhpc3QuZG9uZS5wdXNoKHNlbEFmdGVyKTtcbiAgICBoaXN0LmdlbmVyYXRpb24gPSArK2hpc3QubWF4R2VuZXJhdGlvbjtcbiAgICBoaXN0Lmxhc3RNb2RUaW1lID0gaGlzdC5sYXN0U2VsVGltZSA9IHRpbWU7XG4gICAgaGlzdC5sYXN0T3AgPSBoaXN0Lmxhc3RTZWxPcCA9IG9wSWQ7XG4gICAgaGlzdC5sYXN0T3JpZ2luID0gaGlzdC5sYXN0U2VsT3JpZ2luID0gY2hhbmdlLm9yaWdpbjtcblxuICAgIGlmICghbGFzdCkgeyBzaWduYWwoZG9jLCBcImhpc3RvcnlBZGRlZFwiKTsgfVxuICB9XG5cbiAgZnVuY3Rpb24gc2VsZWN0aW9uRXZlbnRDYW5CZU1lcmdlZChkb2MsIG9yaWdpbiwgcHJldiwgc2VsKSB7XG4gICAgdmFyIGNoID0gb3JpZ2luLmNoYXJBdCgwKTtcbiAgICByZXR1cm4gY2ggPT0gXCIqXCIgfHxcbiAgICAgIGNoID09IFwiK1wiICYmXG4gICAgICBwcmV2LnJhbmdlcy5sZW5ndGggPT0gc2VsLnJhbmdlcy5sZW5ndGggJiZcbiAgICAgIHByZXYuc29tZXRoaW5nU2VsZWN0ZWQoKSA9PSBzZWwuc29tZXRoaW5nU2VsZWN0ZWQoKSAmJlxuICAgICAgbmV3IERhdGUgLSBkb2MuaGlzdG9yeS5sYXN0U2VsVGltZSA8PSAoZG9jLmNtID8gZG9jLmNtLm9wdGlvbnMuaGlzdG9yeUV2ZW50RGVsYXkgOiA1MDApXG4gIH1cblxuICAvLyBDYWxsZWQgd2hlbmV2ZXIgdGhlIHNlbGVjdGlvbiBjaGFuZ2VzLCBzZXRzIHRoZSBuZXcgc2VsZWN0aW9uIGFzXG4gIC8vIHRoZSBwZW5kaW5nIHNlbGVjdGlvbiBpbiB0aGUgaGlzdG9yeSwgYW5kIHB1c2hlcyB0aGUgb2xkIHBlbmRpbmdcbiAgLy8gc2VsZWN0aW9uIGludG8gdGhlICdkb25lJyBhcnJheSB3aGVuIGl0IHdhcyBzaWduaWZpY2FudGx5XG4gIC8vIGRpZmZlcmVudCAoaW4gbnVtYmVyIG9mIHNlbGVjdGVkIHJhbmdlcywgZW1wdGluZXNzLCBvciB0aW1lKS5cbiAgZnVuY3Rpb24gYWRkU2VsZWN0aW9uVG9IaXN0b3J5KGRvYywgc2VsLCBvcElkLCBvcHRpb25zKSB7XG4gICAgdmFyIGhpc3QgPSBkb2MuaGlzdG9yeSwgb3JpZ2luID0gb3B0aW9ucyAmJiBvcHRpb25zLm9yaWdpbjtcblxuICAgIC8vIEEgbmV3IGV2ZW50IGlzIHN0YXJ0ZWQgd2hlbiB0aGUgcHJldmlvdXMgb3JpZ2luIGRvZXMgbm90IG1hdGNoXG4gICAgLy8gdGhlIGN1cnJlbnQsIG9yIHRoZSBvcmlnaW5zIGRvbid0IGFsbG93IG1hdGNoaW5nLiBPcmlnaW5zXG4gICAgLy8gc3RhcnRpbmcgd2l0aCAqIGFyZSBhbHdheXMgbWVyZ2VkLCB0aG9zZSBzdGFydGluZyB3aXRoICsgYXJlXG4gICAgLy8gbWVyZ2VkIHdoZW4gc2ltaWxhciBhbmQgY2xvc2UgdG9nZXRoZXIgaW4gdGltZS5cbiAgICBpZiAob3BJZCA9PSBoaXN0Lmxhc3RTZWxPcCB8fFxuICAgICAgICAob3JpZ2luICYmIGhpc3QubGFzdFNlbE9yaWdpbiA9PSBvcmlnaW4gJiZcbiAgICAgICAgIChoaXN0Lmxhc3RNb2RUaW1lID09IGhpc3QubGFzdFNlbFRpbWUgJiYgaGlzdC5sYXN0T3JpZ2luID09IG9yaWdpbiB8fFxuICAgICAgICAgIHNlbGVjdGlvbkV2ZW50Q2FuQmVNZXJnZWQoZG9jLCBvcmlnaW4sIGxzdChoaXN0LmRvbmUpLCBzZWwpKSkpXG4gICAgICB7IGhpc3QuZG9uZVtoaXN0LmRvbmUubGVuZ3RoIC0gMV0gPSBzZWw7IH1cbiAgICBlbHNlXG4gICAgICB7IHB1c2hTZWxlY3Rpb25Ub0hpc3Rvcnkoc2VsLCBoaXN0LmRvbmUpOyB9XG5cbiAgICBoaXN0Lmxhc3RTZWxUaW1lID0gK25ldyBEYXRlO1xuICAgIGhpc3QubGFzdFNlbE9yaWdpbiA9IG9yaWdpbjtcbiAgICBoaXN0Lmxhc3RTZWxPcCA9IG9wSWQ7XG4gICAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5jbGVhclJlZG8gIT09IGZhbHNlKVxuICAgICAgeyBjbGVhclNlbGVjdGlvbkV2ZW50cyhoaXN0LnVuZG9uZSk7IH1cbiAgfVxuXG4gIGZ1bmN0aW9uIHB1c2hTZWxlY3Rpb25Ub0hpc3Rvcnkoc2VsLCBkZXN0KSB7XG4gICAgdmFyIHRvcCA9IGxzdChkZXN0KTtcbiAgICBpZiAoISh0b3AgJiYgdG9wLnJhbmdlcyAmJiB0b3AuZXF1YWxzKHNlbCkpKVxuICAgICAgeyBkZXN0LnB1c2goc2VsKTsgfVxuICB9XG5cbiAgLy8gVXNlZCB0byBzdG9yZSBtYXJrZWQgc3BhbiBpbmZvcm1hdGlvbiBpbiB0aGUgaGlzdG9yeS5cbiAgZnVuY3Rpb24gYXR0YWNoTG9jYWxTcGFucyhkb2MsIGNoYW5nZSwgZnJvbSwgdG8pIHtcbiAgICB2YXIgZXhpc3RpbmcgPSBjaGFuZ2VbXCJzcGFuc19cIiArIGRvYy5pZF0sIG4gPSAwO1xuICAgIGRvYy5pdGVyKE1hdGgubWF4KGRvYy5maXJzdCwgZnJvbSksIE1hdGgubWluKGRvYy5maXJzdCArIGRvYy5zaXplLCB0byksIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICBpZiAobGluZS5tYXJrZWRTcGFucylcbiAgICAgICAgeyAoZXhpc3RpbmcgfHwgKGV4aXN0aW5nID0gY2hhbmdlW1wic3BhbnNfXCIgKyBkb2MuaWRdID0ge30pKVtuXSA9IGxpbmUubWFya2VkU3BhbnM7IH1cbiAgICAgICsrbjtcbiAgICB9KTtcbiAgfVxuXG4gIC8vIFdoZW4gdW4vcmUtZG9pbmcgcmVzdG9yZXMgdGV4dCBjb250YWluaW5nIG1hcmtlZCBzcGFucywgdGhvc2VcbiAgLy8gdGhhdCBoYXZlIGJlZW4gZXhwbGljaXRseSBjbGVhcmVkIHNob3VsZCBub3QgYmUgcmVzdG9yZWQuXG4gIGZ1bmN0aW9uIHJlbW92ZUNsZWFyZWRTcGFucyhzcGFucykge1xuICAgIGlmICghc3BhbnMpIHsgcmV0dXJuIG51bGwgfVxuICAgIHZhciBvdXQ7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzcGFucy5sZW5ndGg7ICsraSkge1xuICAgICAgaWYgKHNwYW5zW2ldLm1hcmtlci5leHBsaWNpdGx5Q2xlYXJlZCkgeyBpZiAoIW91dCkgeyBvdXQgPSBzcGFucy5zbGljZSgwLCBpKTsgfSB9XG4gICAgICBlbHNlIGlmIChvdXQpIHsgb3V0LnB1c2goc3BhbnNbaV0pOyB9XG4gICAgfVxuICAgIHJldHVybiAhb3V0ID8gc3BhbnMgOiBvdXQubGVuZ3RoID8gb3V0IDogbnVsbFxuICB9XG5cbiAgLy8gUmV0cmlldmUgYW5kIGZpbHRlciB0aGUgb2xkIG1hcmtlZCBzcGFucyBzdG9yZWQgaW4gYSBjaGFuZ2UgZXZlbnQuXG4gIGZ1bmN0aW9uIGdldE9sZFNwYW5zKGRvYywgY2hhbmdlKSB7XG4gICAgdmFyIGZvdW5kID0gY2hhbmdlW1wic3BhbnNfXCIgKyBkb2MuaWRdO1xuICAgIGlmICghZm91bmQpIHsgcmV0dXJuIG51bGwgfVxuICAgIHZhciBudyA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2hhbmdlLnRleHQubGVuZ3RoOyArK2kpXG4gICAgICB7IG53LnB1c2gocmVtb3ZlQ2xlYXJlZFNwYW5zKGZvdW5kW2ldKSk7IH1cbiAgICByZXR1cm4gbndcbiAgfVxuXG4gIC8vIFVzZWQgZm9yIHVuL3JlLWRvaW5nIGNoYW5nZXMgZnJvbSB0aGUgaGlzdG9yeS4gQ29tYmluZXMgdGhlXG4gIC8vIHJlc3VsdCBvZiBjb21wdXRpbmcgdGhlIGV4aXN0aW5nIHNwYW5zIHdpdGggdGhlIHNldCBvZiBzcGFucyB0aGF0XG4gIC8vIGV4aXN0ZWQgaW4gdGhlIGhpc3RvcnkgKHNvIHRoYXQgZGVsZXRpbmcgYXJvdW5kIGEgc3BhbiBhbmQgdGhlblxuICAvLyB1bmRvaW5nIGJyaW5ncyBiYWNrIHRoZSBzcGFuKS5cbiAgZnVuY3Rpb24gbWVyZ2VPbGRTcGFucyhkb2MsIGNoYW5nZSkge1xuICAgIHZhciBvbGQgPSBnZXRPbGRTcGFucyhkb2MsIGNoYW5nZSk7XG4gICAgdmFyIHN0cmV0Y2hlZCA9IHN0cmV0Y2hTcGFuc092ZXJDaGFuZ2UoZG9jLCBjaGFuZ2UpO1xuICAgIGlmICghb2xkKSB7IHJldHVybiBzdHJldGNoZWQgfVxuICAgIGlmICghc3RyZXRjaGVkKSB7IHJldHVybiBvbGQgfVxuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvbGQubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBvbGRDdXIgPSBvbGRbaV0sIHN0cmV0Y2hDdXIgPSBzdHJldGNoZWRbaV07XG4gICAgICBpZiAob2xkQ3VyICYmIHN0cmV0Y2hDdXIpIHtcbiAgICAgICAgc3BhbnM6IGZvciAodmFyIGogPSAwOyBqIDwgc3RyZXRjaEN1ci5sZW5ndGg7ICsraikge1xuICAgICAgICAgIHZhciBzcGFuID0gc3RyZXRjaEN1cltqXTtcbiAgICAgICAgICBmb3IgKHZhciBrID0gMDsgayA8IG9sZEN1ci5sZW5ndGg7ICsraylcbiAgICAgICAgICAgIHsgaWYgKG9sZEN1cltrXS5tYXJrZXIgPT0gc3Bhbi5tYXJrZXIpIHsgY29udGludWUgc3BhbnMgfSB9XG4gICAgICAgICAgb2xkQ3VyLnB1c2goc3Bhbik7XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAoc3RyZXRjaEN1cikge1xuICAgICAgICBvbGRbaV0gPSBzdHJldGNoQ3VyO1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gb2xkXG4gIH1cblxuICAvLyBVc2VkIGJvdGggdG8gcHJvdmlkZSBhIEpTT04tc2FmZSBvYmplY3QgaW4gLmdldEhpc3RvcnksIGFuZCwgd2hlblxuICAvLyBkZXRhY2hpbmcgYSBkb2N1bWVudCwgdG8gc3BsaXQgdGhlIGhpc3RvcnkgaW4gdHdvXG4gIGZ1bmN0aW9uIGNvcHlIaXN0b3J5QXJyYXkoZXZlbnRzLCBuZXdHcm91cCwgaW5zdGFudGlhdGVTZWwpIHtcbiAgICB2YXIgY29weSA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgZXZlbnRzLmxlbmd0aDsgKytpKSB7XG4gICAgICB2YXIgZXZlbnQgPSBldmVudHNbaV07XG4gICAgICBpZiAoZXZlbnQucmFuZ2VzKSB7XG4gICAgICAgIGNvcHkucHVzaChpbnN0YW50aWF0ZVNlbCA/IFNlbGVjdGlvbi5wcm90b3R5cGUuZGVlcENvcHkuY2FsbChldmVudCkgOiBldmVudCk7XG4gICAgICAgIGNvbnRpbnVlXG4gICAgICB9XG4gICAgICB2YXIgY2hhbmdlcyA9IGV2ZW50LmNoYW5nZXMsIG5ld0NoYW5nZXMgPSBbXTtcbiAgICAgIGNvcHkucHVzaCh7Y2hhbmdlczogbmV3Q2hhbmdlc30pO1xuICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBjaGFuZ2VzLmxlbmd0aDsgKytqKSB7XG4gICAgICAgIHZhciBjaGFuZ2UgPSBjaGFuZ2VzW2pdLCBtID0gKHZvaWQgMCk7XG4gICAgICAgIG5ld0NoYW5nZXMucHVzaCh7ZnJvbTogY2hhbmdlLmZyb20sIHRvOiBjaGFuZ2UudG8sIHRleHQ6IGNoYW5nZS50ZXh0fSk7XG4gICAgICAgIGlmIChuZXdHcm91cCkgeyBmb3IgKHZhciBwcm9wIGluIGNoYW5nZSkgeyBpZiAobSA9IHByb3AubWF0Y2goL15zcGFuc18oXFxkKykkLykpIHtcbiAgICAgICAgICBpZiAoaW5kZXhPZihuZXdHcm91cCwgTnVtYmVyKG1bMV0pKSA+IC0xKSB7XG4gICAgICAgICAgICBsc3QobmV3Q2hhbmdlcylbcHJvcF0gPSBjaGFuZ2VbcHJvcF07XG4gICAgICAgICAgICBkZWxldGUgY2hhbmdlW3Byb3BdO1xuICAgICAgICAgIH1cbiAgICAgICAgfSB9IH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGNvcHlcbiAgfVxuXG4gIC8vIFRoZSAnc2Nyb2xsJyBwYXJhbWV0ZXIgZ2l2ZW4gdG8gbWFueSBvZiB0aGVzZSBpbmRpY2F0ZWQgd2hldGhlclxuICAvLyB0aGUgbmV3IGN1cnNvciBwb3NpdGlvbiBzaG91bGQgYmUgc2Nyb2xsZWQgaW50byB2aWV3IGFmdGVyXG4gIC8vIG1vZGlmeWluZyB0aGUgc2VsZWN0aW9uLlxuXG4gIC8vIElmIHNoaWZ0IGlzIGhlbGQgb3IgdGhlIGV4dGVuZCBmbGFnIGlzIHNldCwgZXh0ZW5kcyBhIHJhbmdlIHRvXG4gIC8vIGluY2x1ZGUgYSBnaXZlbiBwb3NpdGlvbiAoYW5kIG9wdGlvbmFsbHkgYSBzZWNvbmQgcG9zaXRpb24pLlxuICAvLyBPdGhlcndpc2UsIHNpbXBseSByZXR1cm5zIHRoZSByYW5nZSBiZXR3ZWVuIHRoZSBnaXZlbiBwb3NpdGlvbnMuXG4gIC8vIFVzZWQgZm9yIGN1cnNvciBtb3Rpb24gYW5kIHN1Y2guXG4gIGZ1bmN0aW9uIGV4dGVuZFJhbmdlKHJhbmdlLCBoZWFkLCBvdGhlciwgZXh0ZW5kKSB7XG4gICAgaWYgKGV4dGVuZCkge1xuICAgICAgdmFyIGFuY2hvciA9IHJhbmdlLmFuY2hvcjtcbiAgICAgIGlmIChvdGhlcikge1xuICAgICAgICB2YXIgcG9zQmVmb3JlID0gY21wKGhlYWQsIGFuY2hvcikgPCAwO1xuICAgICAgICBpZiAocG9zQmVmb3JlICE9IChjbXAob3RoZXIsIGFuY2hvcikgPCAwKSkge1xuICAgICAgICAgIGFuY2hvciA9IGhlYWQ7XG4gICAgICAgICAgaGVhZCA9IG90aGVyO1xuICAgICAgICB9IGVsc2UgaWYgKHBvc0JlZm9yZSAhPSAoY21wKGhlYWQsIG90aGVyKSA8IDApKSB7XG4gICAgICAgICAgaGVhZCA9IG90aGVyO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gbmV3IFJhbmdlKGFuY2hvciwgaGVhZClcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIG5ldyBSYW5nZShvdGhlciB8fCBoZWFkLCBoZWFkKVxuICAgIH1cbiAgfVxuXG4gIC8vIEV4dGVuZCB0aGUgcHJpbWFyeSBzZWxlY3Rpb24gcmFuZ2UsIGRpc2NhcmQgdGhlIHJlc3QuXG4gIGZ1bmN0aW9uIGV4dGVuZFNlbGVjdGlvbihkb2MsIGhlYWQsIG90aGVyLCBvcHRpb25zLCBleHRlbmQpIHtcbiAgICBpZiAoZXh0ZW5kID09IG51bGwpIHsgZXh0ZW5kID0gZG9jLmNtICYmIChkb2MuY20uZGlzcGxheS5zaGlmdCB8fCBkb2MuZXh0ZW5kKTsgfVxuICAgIHNldFNlbGVjdGlvbihkb2MsIG5ldyBTZWxlY3Rpb24oW2V4dGVuZFJhbmdlKGRvYy5zZWwucHJpbWFyeSgpLCBoZWFkLCBvdGhlciwgZXh0ZW5kKV0sIDApLCBvcHRpb25zKTtcbiAgfVxuXG4gIC8vIEV4dGVuZCBhbGwgc2VsZWN0aW9ucyAocG9zIGlzIGFuIGFycmF5IG9mIHNlbGVjdGlvbnMgd2l0aCBsZW5ndGhcbiAgLy8gZXF1YWwgdGhlIG51bWJlciBvZiBzZWxlY3Rpb25zKVxuICBmdW5jdGlvbiBleHRlbmRTZWxlY3Rpb25zKGRvYywgaGVhZHMsIG9wdGlvbnMpIHtcbiAgICB2YXIgb3V0ID0gW107XG4gICAgdmFyIGV4dGVuZCA9IGRvYy5jbSAmJiAoZG9jLmNtLmRpc3BsYXkuc2hpZnQgfHwgZG9jLmV4dGVuZCk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBkb2Muc2VsLnJhbmdlcy5sZW5ndGg7IGkrKylcbiAgICAgIHsgb3V0W2ldID0gZXh0ZW5kUmFuZ2UoZG9jLnNlbC5yYW5nZXNbaV0sIGhlYWRzW2ldLCBudWxsLCBleHRlbmQpOyB9XG4gICAgdmFyIG5ld1NlbCA9IG5vcm1hbGl6ZVNlbGVjdGlvbihkb2MuY20sIG91dCwgZG9jLnNlbC5wcmltSW5kZXgpO1xuICAgIHNldFNlbGVjdGlvbihkb2MsIG5ld1NlbCwgb3B0aW9ucyk7XG4gIH1cblxuICAvLyBVcGRhdGVzIGEgc2luZ2xlIHJhbmdlIGluIHRoZSBzZWxlY3Rpb24uXG4gIGZ1bmN0aW9uIHJlcGxhY2VPbmVTZWxlY3Rpb24oZG9jLCBpLCByYW5nZSwgb3B0aW9ucykge1xuICAgIHZhciByYW5nZXMgPSBkb2Muc2VsLnJhbmdlcy5zbGljZSgwKTtcbiAgICByYW5nZXNbaV0gPSByYW5nZTtcbiAgICBzZXRTZWxlY3Rpb24oZG9jLCBub3JtYWxpemVTZWxlY3Rpb24oZG9jLmNtLCByYW5nZXMsIGRvYy5zZWwucHJpbUluZGV4KSwgb3B0aW9ucyk7XG4gIH1cblxuICAvLyBSZXNldCB0aGUgc2VsZWN0aW9uIHRvIGEgc2luZ2xlIHJhbmdlLlxuICBmdW5jdGlvbiBzZXRTaW1wbGVTZWxlY3Rpb24oZG9jLCBhbmNob3IsIGhlYWQsIG9wdGlvbnMpIHtcbiAgICBzZXRTZWxlY3Rpb24oZG9jLCBzaW1wbGVTZWxlY3Rpb24oYW5jaG9yLCBoZWFkKSwgb3B0aW9ucyk7XG4gIH1cblxuICAvLyBHaXZlIGJlZm9yZVNlbGVjdGlvbkNoYW5nZSBoYW5kbGVycyBhIGNoYW5nZSB0byBpbmZsdWVuY2UgYVxuICAvLyBzZWxlY3Rpb24gdXBkYXRlLlxuICBmdW5jdGlvbiBmaWx0ZXJTZWxlY3Rpb25DaGFuZ2UoZG9jLCBzZWwsIG9wdGlvbnMpIHtcbiAgICB2YXIgb2JqID0ge1xuICAgICAgcmFuZ2VzOiBzZWwucmFuZ2VzLFxuICAgICAgdXBkYXRlOiBmdW5jdGlvbihyYW5nZXMpIHtcbiAgICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICAgICAgdGhpcy5yYW5nZXMgPSBbXTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByYW5nZXMubGVuZ3RoOyBpKyspXG4gICAgICAgICAgeyB0aGlzJDEucmFuZ2VzW2ldID0gbmV3IFJhbmdlKGNsaXBQb3MoZG9jLCByYW5nZXNbaV0uYW5jaG9yKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGlwUG9zKGRvYywgcmFuZ2VzW2ldLmhlYWQpKTsgfVxuICAgICAgfSxcbiAgICAgIG9yaWdpbjogb3B0aW9ucyAmJiBvcHRpb25zLm9yaWdpblxuICAgIH07XG4gICAgc2lnbmFsKGRvYywgXCJiZWZvcmVTZWxlY3Rpb25DaGFuZ2VcIiwgZG9jLCBvYmopO1xuICAgIGlmIChkb2MuY20pIHsgc2lnbmFsKGRvYy5jbSwgXCJiZWZvcmVTZWxlY3Rpb25DaGFuZ2VcIiwgZG9jLmNtLCBvYmopOyB9XG4gICAgaWYgKG9iai5yYW5nZXMgIT0gc2VsLnJhbmdlcykgeyByZXR1cm4gbm9ybWFsaXplU2VsZWN0aW9uKGRvYy5jbSwgb2JqLnJhbmdlcywgb2JqLnJhbmdlcy5sZW5ndGggLSAxKSB9XG4gICAgZWxzZSB7IHJldHVybiBzZWwgfVxuICB9XG5cbiAgZnVuY3Rpb24gc2V0U2VsZWN0aW9uUmVwbGFjZUhpc3RvcnkoZG9jLCBzZWwsIG9wdGlvbnMpIHtcbiAgICB2YXIgZG9uZSA9IGRvYy5oaXN0b3J5LmRvbmUsIGxhc3QgPSBsc3QoZG9uZSk7XG4gICAgaWYgKGxhc3QgJiYgbGFzdC5yYW5nZXMpIHtcbiAgICAgIGRvbmVbZG9uZS5sZW5ndGggLSAxXSA9IHNlbDtcbiAgICAgIHNldFNlbGVjdGlvbk5vVW5kbyhkb2MsIHNlbCwgb3B0aW9ucyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHNldFNlbGVjdGlvbihkb2MsIHNlbCwgb3B0aW9ucyk7XG4gICAgfVxuICB9XG5cbiAgLy8gU2V0IGEgbmV3IHNlbGVjdGlvbi5cbiAgZnVuY3Rpb24gc2V0U2VsZWN0aW9uKGRvYywgc2VsLCBvcHRpb25zKSB7XG4gICAgc2V0U2VsZWN0aW9uTm9VbmRvKGRvYywgc2VsLCBvcHRpb25zKTtcbiAgICBhZGRTZWxlY3Rpb25Ub0hpc3RvcnkoZG9jLCBkb2Muc2VsLCBkb2MuY20gPyBkb2MuY20uY3VyT3AuaWQgOiBOYU4sIG9wdGlvbnMpO1xuICB9XG5cbiAgZnVuY3Rpb24gc2V0U2VsZWN0aW9uTm9VbmRvKGRvYywgc2VsLCBvcHRpb25zKSB7XG4gICAgaWYgKGhhc0hhbmRsZXIoZG9jLCBcImJlZm9yZVNlbGVjdGlvbkNoYW5nZVwiKSB8fCBkb2MuY20gJiYgaGFzSGFuZGxlcihkb2MuY20sIFwiYmVmb3JlU2VsZWN0aW9uQ2hhbmdlXCIpKVxuICAgICAgeyBzZWwgPSBmaWx0ZXJTZWxlY3Rpb25DaGFuZ2UoZG9jLCBzZWwsIG9wdGlvbnMpOyB9XG5cbiAgICB2YXIgYmlhcyA9IG9wdGlvbnMgJiYgb3B0aW9ucy5iaWFzIHx8XG4gICAgICAoY21wKHNlbC5wcmltYXJ5KCkuaGVhZCwgZG9jLnNlbC5wcmltYXJ5KCkuaGVhZCkgPCAwID8gLTEgOiAxKTtcbiAgICBzZXRTZWxlY3Rpb25Jbm5lcihkb2MsIHNraXBBdG9taWNJblNlbGVjdGlvbihkb2MsIHNlbCwgYmlhcywgdHJ1ZSkpO1xuXG4gICAgaWYgKCEob3B0aW9ucyAmJiBvcHRpb25zLnNjcm9sbCA9PT0gZmFsc2UpICYmIGRvYy5jbSlcbiAgICAgIHsgZW5zdXJlQ3Vyc29yVmlzaWJsZShkb2MuY20pOyB9XG4gIH1cblxuICBmdW5jdGlvbiBzZXRTZWxlY3Rpb25Jbm5lcihkb2MsIHNlbCkge1xuICAgIGlmIChzZWwuZXF1YWxzKGRvYy5zZWwpKSB7IHJldHVybiB9XG5cbiAgICBkb2Muc2VsID0gc2VsO1xuXG4gICAgaWYgKGRvYy5jbSkge1xuICAgICAgZG9jLmNtLmN1ck9wLnVwZGF0ZUlucHV0ID0gMTtcbiAgICAgIGRvYy5jbS5jdXJPcC5zZWxlY3Rpb25DaGFuZ2VkID0gdHJ1ZTtcbiAgICAgIHNpZ25hbEN1cnNvckFjdGl2aXR5KGRvYy5jbSk7XG4gICAgfVxuICAgIHNpZ25hbExhdGVyKGRvYywgXCJjdXJzb3JBY3Rpdml0eVwiLCBkb2MpO1xuICB9XG5cbiAgLy8gVmVyaWZ5IHRoYXQgdGhlIHNlbGVjdGlvbiBkb2VzIG5vdCBwYXJ0aWFsbHkgc2VsZWN0IGFueSBhdG9taWNcbiAgLy8gbWFya2VkIHJhbmdlcy5cbiAgZnVuY3Rpb24gcmVDaGVja1NlbGVjdGlvbihkb2MpIHtcbiAgICBzZXRTZWxlY3Rpb25Jbm5lcihkb2MsIHNraXBBdG9taWNJblNlbGVjdGlvbihkb2MsIGRvYy5zZWwsIG51bGwsIGZhbHNlKSk7XG4gIH1cblxuICAvLyBSZXR1cm4gYSBzZWxlY3Rpb24gdGhhdCBkb2VzIG5vdCBwYXJ0aWFsbHkgc2VsZWN0IGFueSBhdG9taWNcbiAgLy8gcmFuZ2VzLlxuICBmdW5jdGlvbiBza2lwQXRvbWljSW5TZWxlY3Rpb24oZG9jLCBzZWwsIGJpYXMsIG1heUNsZWFyKSB7XG4gICAgdmFyIG91dDtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbC5yYW5nZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciByYW5nZSA9IHNlbC5yYW5nZXNbaV07XG4gICAgICB2YXIgb2xkID0gc2VsLnJhbmdlcy5sZW5ndGggPT0gZG9jLnNlbC5yYW5nZXMubGVuZ3RoICYmIGRvYy5zZWwucmFuZ2VzW2ldO1xuICAgICAgdmFyIG5ld0FuY2hvciA9IHNraXBBdG9taWMoZG9jLCByYW5nZS5hbmNob3IsIG9sZCAmJiBvbGQuYW5jaG9yLCBiaWFzLCBtYXlDbGVhcik7XG4gICAgICB2YXIgbmV3SGVhZCA9IHNraXBBdG9taWMoZG9jLCByYW5nZS5oZWFkLCBvbGQgJiYgb2xkLmhlYWQsIGJpYXMsIG1heUNsZWFyKTtcbiAgICAgIGlmIChvdXQgfHwgbmV3QW5jaG9yICE9IHJhbmdlLmFuY2hvciB8fCBuZXdIZWFkICE9IHJhbmdlLmhlYWQpIHtcbiAgICAgICAgaWYgKCFvdXQpIHsgb3V0ID0gc2VsLnJhbmdlcy5zbGljZSgwLCBpKTsgfVxuICAgICAgICBvdXRbaV0gPSBuZXcgUmFuZ2UobmV3QW5jaG9yLCBuZXdIZWFkKTtcbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIG91dCA/IG5vcm1hbGl6ZVNlbGVjdGlvbihkb2MuY20sIG91dCwgc2VsLnByaW1JbmRleCkgOiBzZWxcbiAgfVxuXG4gIGZ1bmN0aW9uIHNraXBBdG9taWNJbm5lcihkb2MsIHBvcywgb2xkUG9zLCBkaXIsIG1heUNsZWFyKSB7XG4gICAgdmFyIGxpbmUgPSBnZXRMaW5lKGRvYywgcG9zLmxpbmUpO1xuICAgIGlmIChsaW5lLm1hcmtlZFNwYW5zKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgbGluZS5tYXJrZWRTcGFucy5sZW5ndGg7ICsraSkge1xuICAgICAgdmFyIHNwID0gbGluZS5tYXJrZWRTcGFuc1tpXSwgbSA9IHNwLm1hcmtlcjtcbiAgICAgIGlmICgoc3AuZnJvbSA9PSBudWxsIHx8IChtLmluY2x1c2l2ZUxlZnQgPyBzcC5mcm9tIDw9IHBvcy5jaCA6IHNwLmZyb20gPCBwb3MuY2gpKSAmJlxuICAgICAgICAgIChzcC50byA9PSBudWxsIHx8IChtLmluY2x1c2l2ZVJpZ2h0ID8gc3AudG8gPj0gcG9zLmNoIDogc3AudG8gPiBwb3MuY2gpKSkge1xuICAgICAgICBpZiAobWF5Q2xlYXIpIHtcbiAgICAgICAgICBzaWduYWwobSwgXCJiZWZvcmVDdXJzb3JFbnRlclwiKTtcbiAgICAgICAgICBpZiAobS5leHBsaWNpdGx5Q2xlYXJlZCkge1xuICAgICAgICAgICAgaWYgKCFsaW5lLm1hcmtlZFNwYW5zKSB7IGJyZWFrIH1cbiAgICAgICAgICAgIGVsc2Ugey0taTsgY29udGludWV9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGlmICghbS5hdG9taWMpIHsgY29udGludWUgfVxuXG4gICAgICAgIGlmIChvbGRQb3MpIHtcbiAgICAgICAgICB2YXIgbmVhciA9IG0uZmluZChkaXIgPCAwID8gMSA6IC0xKSwgZGlmZiA9ICh2b2lkIDApO1xuICAgICAgICAgIGlmIChkaXIgPCAwID8gbS5pbmNsdXNpdmVSaWdodCA6IG0uaW5jbHVzaXZlTGVmdClcbiAgICAgICAgICAgIHsgbmVhciA9IG1vdmVQb3MoZG9jLCBuZWFyLCAtZGlyLCBuZWFyICYmIG5lYXIubGluZSA9PSBwb3MubGluZSA/IGxpbmUgOiBudWxsKTsgfVxuICAgICAgICAgIGlmIChuZWFyICYmIG5lYXIubGluZSA9PSBwb3MubGluZSAmJiAoZGlmZiA9IGNtcChuZWFyLCBvbGRQb3MpKSAmJiAoZGlyIDwgMCA/IGRpZmYgPCAwIDogZGlmZiA+IDApKVxuICAgICAgICAgICAgeyByZXR1cm4gc2tpcEF0b21pY0lubmVyKGRvYywgbmVhciwgcG9zLCBkaXIsIG1heUNsZWFyKSB9XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZmFyID0gbS5maW5kKGRpciA8IDAgPyAtMSA6IDEpO1xuICAgICAgICBpZiAoZGlyIDwgMCA/IG0uaW5jbHVzaXZlTGVmdCA6IG0uaW5jbHVzaXZlUmlnaHQpXG4gICAgICAgICAgeyBmYXIgPSBtb3ZlUG9zKGRvYywgZmFyLCBkaXIsIGZhci5saW5lID09IHBvcy5saW5lID8gbGluZSA6IG51bGwpOyB9XG4gICAgICAgIHJldHVybiBmYXIgPyBza2lwQXRvbWljSW5uZXIoZG9jLCBmYXIsIHBvcywgZGlyLCBtYXlDbGVhcikgOiBudWxsXG4gICAgICB9XG4gICAgfSB9XG4gICAgcmV0dXJuIHBvc1xuICB9XG5cbiAgLy8gRW5zdXJlIGEgZ2l2ZW4gcG9zaXRpb24gaXMgbm90IGluc2lkZSBhbiBhdG9taWMgcmFuZ2UuXG4gIGZ1bmN0aW9uIHNraXBBdG9taWMoZG9jLCBwb3MsIG9sZFBvcywgYmlhcywgbWF5Q2xlYXIpIHtcbiAgICB2YXIgZGlyID0gYmlhcyB8fCAxO1xuICAgIHZhciBmb3VuZCA9IHNraXBBdG9taWNJbm5lcihkb2MsIHBvcywgb2xkUG9zLCBkaXIsIG1heUNsZWFyKSB8fFxuICAgICAgICAoIW1heUNsZWFyICYmIHNraXBBdG9taWNJbm5lcihkb2MsIHBvcywgb2xkUG9zLCBkaXIsIHRydWUpKSB8fFxuICAgICAgICBza2lwQXRvbWljSW5uZXIoZG9jLCBwb3MsIG9sZFBvcywgLWRpciwgbWF5Q2xlYXIpIHx8XG4gICAgICAgICghbWF5Q2xlYXIgJiYgc2tpcEF0b21pY0lubmVyKGRvYywgcG9zLCBvbGRQb3MsIC1kaXIsIHRydWUpKTtcbiAgICBpZiAoIWZvdW5kKSB7XG4gICAgICBkb2MuY2FudEVkaXQgPSB0cnVlO1xuICAgICAgcmV0dXJuIFBvcyhkb2MuZmlyc3QsIDApXG4gICAgfVxuICAgIHJldHVybiBmb3VuZFxuICB9XG5cbiAgZnVuY3Rpb24gbW92ZVBvcyhkb2MsIHBvcywgZGlyLCBsaW5lKSB7XG4gICAgaWYgKGRpciA8IDAgJiYgcG9zLmNoID09IDApIHtcbiAgICAgIGlmIChwb3MubGluZSA+IGRvYy5maXJzdCkgeyByZXR1cm4gY2xpcFBvcyhkb2MsIFBvcyhwb3MubGluZSAtIDEpKSB9XG4gICAgICBlbHNlIHsgcmV0dXJuIG51bGwgfVxuICAgIH0gZWxzZSBpZiAoZGlyID4gMCAmJiBwb3MuY2ggPT0gKGxpbmUgfHwgZ2V0TGluZShkb2MsIHBvcy5saW5lKSkudGV4dC5sZW5ndGgpIHtcbiAgICAgIGlmIChwb3MubGluZSA8IGRvYy5maXJzdCArIGRvYy5zaXplIC0gMSkgeyByZXR1cm4gUG9zKHBvcy5saW5lICsgMSwgMCkgfVxuICAgICAgZWxzZSB7IHJldHVybiBudWxsIH1cbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIG5ldyBQb3MocG9zLmxpbmUsIHBvcy5jaCArIGRpcilcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBzZWxlY3RBbGwoY20pIHtcbiAgICBjbS5zZXRTZWxlY3Rpb24oUG9zKGNtLmZpcnN0TGluZSgpLCAwKSwgUG9zKGNtLmxhc3RMaW5lKCkpLCBzZWxfZG9udFNjcm9sbCk7XG4gIH1cblxuICAvLyBVUERBVElOR1xuXG4gIC8vIEFsbG93IFwiYmVmb3JlQ2hhbmdlXCIgZXZlbnQgaGFuZGxlcnMgdG8gaW5mbHVlbmNlIGEgY2hhbmdlXG4gIGZ1bmN0aW9uIGZpbHRlckNoYW5nZShkb2MsIGNoYW5nZSwgdXBkYXRlKSB7XG4gICAgdmFyIG9iaiA9IHtcbiAgICAgIGNhbmNlbGVkOiBmYWxzZSxcbiAgICAgIGZyb206IGNoYW5nZS5mcm9tLFxuICAgICAgdG86IGNoYW5nZS50byxcbiAgICAgIHRleHQ6IGNoYW5nZS50ZXh0LFxuICAgICAgb3JpZ2luOiBjaGFuZ2Uub3JpZ2luLFxuICAgICAgY2FuY2VsOiBmdW5jdGlvbiAoKSB7IHJldHVybiBvYmouY2FuY2VsZWQgPSB0cnVlOyB9XG4gICAgfTtcbiAgICBpZiAodXBkYXRlKSB7IG9iai51cGRhdGUgPSBmdW5jdGlvbiAoZnJvbSwgdG8sIHRleHQsIG9yaWdpbikge1xuICAgICAgaWYgKGZyb20pIHsgb2JqLmZyb20gPSBjbGlwUG9zKGRvYywgZnJvbSk7IH1cbiAgICAgIGlmICh0bykgeyBvYmoudG8gPSBjbGlwUG9zKGRvYywgdG8pOyB9XG4gICAgICBpZiAodGV4dCkgeyBvYmoudGV4dCA9IHRleHQ7IH1cbiAgICAgIGlmIChvcmlnaW4gIT09IHVuZGVmaW5lZCkgeyBvYmoub3JpZ2luID0gb3JpZ2luOyB9XG4gICAgfTsgfVxuICAgIHNpZ25hbChkb2MsIFwiYmVmb3JlQ2hhbmdlXCIsIGRvYywgb2JqKTtcbiAgICBpZiAoZG9jLmNtKSB7IHNpZ25hbChkb2MuY20sIFwiYmVmb3JlQ2hhbmdlXCIsIGRvYy5jbSwgb2JqKTsgfVxuXG4gICAgaWYgKG9iai5jYW5jZWxlZCkge1xuICAgICAgaWYgKGRvYy5jbSkgeyBkb2MuY20uY3VyT3AudXBkYXRlSW5wdXQgPSAyOyB9XG4gICAgICByZXR1cm4gbnVsbFxuICAgIH1cbiAgICByZXR1cm4ge2Zyb206IG9iai5mcm9tLCB0bzogb2JqLnRvLCB0ZXh0OiBvYmoudGV4dCwgb3JpZ2luOiBvYmoub3JpZ2lufVxuICB9XG5cbiAgLy8gQXBwbHkgYSBjaGFuZ2UgdG8gYSBkb2N1bWVudCwgYW5kIGFkZCBpdCB0byB0aGUgZG9jdW1lbnQnc1xuICAvLyBoaXN0b3J5LCBhbmQgcHJvcGFnYXRpbmcgaXQgdG8gYWxsIGxpbmtlZCBkb2N1bWVudHMuXG4gIGZ1bmN0aW9uIG1ha2VDaGFuZ2UoZG9jLCBjaGFuZ2UsIGlnbm9yZVJlYWRPbmx5KSB7XG4gICAgaWYgKGRvYy5jbSkge1xuICAgICAgaWYgKCFkb2MuY20uY3VyT3ApIHsgcmV0dXJuIG9wZXJhdGlvbihkb2MuY20sIG1ha2VDaGFuZ2UpKGRvYywgY2hhbmdlLCBpZ25vcmVSZWFkT25seSkgfVxuICAgICAgaWYgKGRvYy5jbS5zdGF0ZS5zdXBwcmVzc0VkaXRzKSB7IHJldHVybiB9XG4gICAgfVxuXG4gICAgaWYgKGhhc0hhbmRsZXIoZG9jLCBcImJlZm9yZUNoYW5nZVwiKSB8fCBkb2MuY20gJiYgaGFzSGFuZGxlcihkb2MuY20sIFwiYmVmb3JlQ2hhbmdlXCIpKSB7XG4gICAgICBjaGFuZ2UgPSBmaWx0ZXJDaGFuZ2UoZG9jLCBjaGFuZ2UsIHRydWUpO1xuICAgICAgaWYgKCFjaGFuZ2UpIHsgcmV0dXJuIH1cbiAgICB9XG5cbiAgICAvLyBQb3NzaWJseSBzcGxpdCBvciBzdXBwcmVzcyB0aGUgdXBkYXRlIGJhc2VkIG9uIHRoZSBwcmVzZW5jZVxuICAgIC8vIG9mIHJlYWQtb25seSBzcGFucyBpbiBpdHMgcmFuZ2UuXG4gICAgdmFyIHNwbGl0ID0gc2F3UmVhZE9ubHlTcGFucyAmJiAhaWdub3JlUmVhZE9ubHkgJiYgcmVtb3ZlUmVhZE9ubHlSYW5nZXMoZG9jLCBjaGFuZ2UuZnJvbSwgY2hhbmdlLnRvKTtcbiAgICBpZiAoc3BsaXQpIHtcbiAgICAgIGZvciAodmFyIGkgPSBzcGxpdC5sZW5ndGggLSAxOyBpID49IDA7IC0taSlcbiAgICAgICAgeyBtYWtlQ2hhbmdlSW5uZXIoZG9jLCB7ZnJvbTogc3BsaXRbaV0uZnJvbSwgdG86IHNwbGl0W2ldLnRvLCB0ZXh0OiBpID8gW1wiXCJdIDogY2hhbmdlLnRleHQsIG9yaWdpbjogY2hhbmdlLm9yaWdpbn0pOyB9XG4gICAgfSBlbHNlIHtcbiAgICAgIG1ha2VDaGFuZ2VJbm5lcihkb2MsIGNoYW5nZSk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gbWFrZUNoYW5nZUlubmVyKGRvYywgY2hhbmdlKSB7XG4gICAgaWYgKGNoYW5nZS50ZXh0Lmxlbmd0aCA9PSAxICYmIGNoYW5nZS50ZXh0WzBdID09IFwiXCIgJiYgY21wKGNoYW5nZS5mcm9tLCBjaGFuZ2UudG8pID09IDApIHsgcmV0dXJuIH1cbiAgICB2YXIgc2VsQWZ0ZXIgPSBjb21wdXRlU2VsQWZ0ZXJDaGFuZ2UoZG9jLCBjaGFuZ2UpO1xuICAgIGFkZENoYW5nZVRvSGlzdG9yeShkb2MsIGNoYW5nZSwgc2VsQWZ0ZXIsIGRvYy5jbSA/IGRvYy5jbS5jdXJPcC5pZCA6IE5hTik7XG5cbiAgICBtYWtlQ2hhbmdlU2luZ2xlRG9jKGRvYywgY2hhbmdlLCBzZWxBZnRlciwgc3RyZXRjaFNwYW5zT3ZlckNoYW5nZShkb2MsIGNoYW5nZSkpO1xuICAgIHZhciByZWJhc2VkID0gW107XG5cbiAgICBsaW5rZWREb2NzKGRvYywgZnVuY3Rpb24gKGRvYywgc2hhcmVkSGlzdCkge1xuICAgICAgaWYgKCFzaGFyZWRIaXN0ICYmIGluZGV4T2YocmViYXNlZCwgZG9jLmhpc3RvcnkpID09IC0xKSB7XG4gICAgICAgIHJlYmFzZUhpc3QoZG9jLmhpc3RvcnksIGNoYW5nZSk7XG4gICAgICAgIHJlYmFzZWQucHVzaChkb2MuaGlzdG9yeSk7XG4gICAgICB9XG4gICAgICBtYWtlQ2hhbmdlU2luZ2xlRG9jKGRvYywgY2hhbmdlLCBudWxsLCBzdHJldGNoU3BhbnNPdmVyQ2hhbmdlKGRvYywgY2hhbmdlKSk7XG4gICAgfSk7XG4gIH1cblxuICAvLyBSZXZlcnQgYSBjaGFuZ2Ugc3RvcmVkIGluIGEgZG9jdW1lbnQncyBoaXN0b3J5LlxuICBmdW5jdGlvbiBtYWtlQ2hhbmdlRnJvbUhpc3RvcnkoZG9jLCB0eXBlLCBhbGxvd1NlbGVjdGlvbk9ubHkpIHtcbiAgICB2YXIgc3VwcHJlc3MgPSBkb2MuY20gJiYgZG9jLmNtLnN0YXRlLnN1cHByZXNzRWRpdHM7XG4gICAgaWYgKHN1cHByZXNzICYmICFhbGxvd1NlbGVjdGlvbk9ubHkpIHsgcmV0dXJuIH1cblxuICAgIHZhciBoaXN0ID0gZG9jLmhpc3RvcnksIGV2ZW50LCBzZWxBZnRlciA9IGRvYy5zZWw7XG4gICAgdmFyIHNvdXJjZSA9IHR5cGUgPT0gXCJ1bmRvXCIgPyBoaXN0LmRvbmUgOiBoaXN0LnVuZG9uZSwgZGVzdCA9IHR5cGUgPT0gXCJ1bmRvXCIgPyBoaXN0LnVuZG9uZSA6IGhpc3QuZG9uZTtcblxuICAgIC8vIFZlcmlmeSB0aGF0IHRoZXJlIGlzIGEgdXNlYWJsZSBldmVudCAoc28gdGhhdCBjdHJsLXogd29uJ3RcbiAgICAvLyBuZWVkbGVzc2x5IGNsZWFyIHNlbGVjdGlvbiBldmVudHMpXG4gICAgdmFyIGkgPSAwO1xuICAgIGZvciAoOyBpIDwgc291cmNlLmxlbmd0aDsgaSsrKSB7XG4gICAgICBldmVudCA9IHNvdXJjZVtpXTtcbiAgICAgIGlmIChhbGxvd1NlbGVjdGlvbk9ubHkgPyBldmVudC5yYW5nZXMgJiYgIWV2ZW50LmVxdWFscyhkb2Muc2VsKSA6ICFldmVudC5yYW5nZXMpXG4gICAgICAgIHsgYnJlYWsgfVxuICAgIH1cbiAgICBpZiAoaSA9PSBzb3VyY2UubGVuZ3RoKSB7IHJldHVybiB9XG4gICAgaGlzdC5sYXN0T3JpZ2luID0gaGlzdC5sYXN0U2VsT3JpZ2luID0gbnVsbDtcblxuICAgIGZvciAoOzspIHtcbiAgICAgIGV2ZW50ID0gc291cmNlLnBvcCgpO1xuICAgICAgaWYgKGV2ZW50LnJhbmdlcykge1xuICAgICAgICBwdXNoU2VsZWN0aW9uVG9IaXN0b3J5KGV2ZW50LCBkZXN0KTtcbiAgICAgICAgaWYgKGFsbG93U2VsZWN0aW9uT25seSAmJiAhZXZlbnQuZXF1YWxzKGRvYy5zZWwpKSB7XG4gICAgICAgICAgc2V0U2VsZWN0aW9uKGRvYywgZXZlbnQsIHtjbGVhclJlZG86IGZhbHNlfSk7XG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgc2VsQWZ0ZXIgPSBldmVudDtcbiAgICAgIH0gZWxzZSBpZiAoc3VwcHJlc3MpIHtcbiAgICAgICAgc291cmNlLnB1c2goZXZlbnQpO1xuICAgICAgICByZXR1cm5cbiAgICAgIH0gZWxzZSB7IGJyZWFrIH1cbiAgICB9XG5cbiAgICAvLyBCdWlsZCB1cCBhIHJldmVyc2UgY2hhbmdlIG9iamVjdCB0byBhZGQgdG8gdGhlIG9wcG9zaXRlIGhpc3RvcnlcbiAgICAvLyBzdGFjayAocmVkbyB3aGVuIHVuZG9pbmcsIGFuZCB2aWNlIHZlcnNhKS5cbiAgICB2YXIgYW50aUNoYW5nZXMgPSBbXTtcbiAgICBwdXNoU2VsZWN0aW9uVG9IaXN0b3J5KHNlbEFmdGVyLCBkZXN0KTtcbiAgICBkZXN0LnB1c2goe2NoYW5nZXM6IGFudGlDaGFuZ2VzLCBnZW5lcmF0aW9uOiBoaXN0LmdlbmVyYXRpb259KTtcbiAgICBoaXN0LmdlbmVyYXRpb24gPSBldmVudC5nZW5lcmF0aW9uIHx8ICsraGlzdC5tYXhHZW5lcmF0aW9uO1xuXG4gICAgdmFyIGZpbHRlciA9IGhhc0hhbmRsZXIoZG9jLCBcImJlZm9yZUNoYW5nZVwiKSB8fCBkb2MuY20gJiYgaGFzSGFuZGxlcihkb2MuY20sIFwiYmVmb3JlQ2hhbmdlXCIpO1xuXG4gICAgdmFyIGxvb3AgPSBmdW5jdGlvbiAoIGkgKSB7XG4gICAgICB2YXIgY2hhbmdlID0gZXZlbnQuY2hhbmdlc1tpXTtcbiAgICAgIGNoYW5nZS5vcmlnaW4gPSB0eXBlO1xuICAgICAgaWYgKGZpbHRlciAmJiAhZmlsdGVyQ2hhbmdlKGRvYywgY2hhbmdlLCBmYWxzZSkpIHtcbiAgICAgICAgc291cmNlLmxlbmd0aCA9IDA7XG4gICAgICAgIHJldHVybiB7fVxuICAgICAgfVxuXG4gICAgICBhbnRpQ2hhbmdlcy5wdXNoKGhpc3RvcnlDaGFuZ2VGcm9tQ2hhbmdlKGRvYywgY2hhbmdlKSk7XG5cbiAgICAgIHZhciBhZnRlciA9IGkgPyBjb21wdXRlU2VsQWZ0ZXJDaGFuZ2UoZG9jLCBjaGFuZ2UpIDogbHN0KHNvdXJjZSk7XG4gICAgICBtYWtlQ2hhbmdlU2luZ2xlRG9jKGRvYywgY2hhbmdlLCBhZnRlciwgbWVyZ2VPbGRTcGFucyhkb2MsIGNoYW5nZSkpO1xuICAgICAgaWYgKCFpICYmIGRvYy5jbSkgeyBkb2MuY20uc2Nyb2xsSW50b1ZpZXcoe2Zyb206IGNoYW5nZS5mcm9tLCB0bzogY2hhbmdlRW5kKGNoYW5nZSl9KTsgfVxuICAgICAgdmFyIHJlYmFzZWQgPSBbXTtcblxuICAgICAgLy8gUHJvcGFnYXRlIHRvIHRoZSBsaW5rZWQgZG9jdW1lbnRzXG4gICAgICBsaW5rZWREb2NzKGRvYywgZnVuY3Rpb24gKGRvYywgc2hhcmVkSGlzdCkge1xuICAgICAgICBpZiAoIXNoYXJlZEhpc3QgJiYgaW5kZXhPZihyZWJhc2VkLCBkb2MuaGlzdG9yeSkgPT0gLTEpIHtcbiAgICAgICAgICByZWJhc2VIaXN0KGRvYy5oaXN0b3J5LCBjaGFuZ2UpO1xuICAgICAgICAgIHJlYmFzZWQucHVzaChkb2MuaGlzdG9yeSk7XG4gICAgICAgIH1cbiAgICAgICAgbWFrZUNoYW5nZVNpbmdsZURvYyhkb2MsIGNoYW5nZSwgbnVsbCwgbWVyZ2VPbGRTcGFucyhkb2MsIGNoYW5nZSkpO1xuICAgICAgfSk7XG4gICAgfTtcblxuICAgIGZvciAodmFyIGkkMSA9IGV2ZW50LmNoYW5nZXMubGVuZ3RoIC0gMTsgaSQxID49IDA7IC0taSQxKSB7XG4gICAgICB2YXIgcmV0dXJuZWQgPSBsb29wKCBpJDEgKTtcblxuICAgICAgaWYgKCByZXR1cm5lZCApIHJldHVybiByZXR1cm5lZC52O1xuICAgIH1cbiAgfVxuXG4gIC8vIFN1Yi12aWV3cyBuZWVkIHRoZWlyIGxpbmUgbnVtYmVycyBzaGlmdGVkIHdoZW4gdGV4dCBpcyBhZGRlZFxuICAvLyBhYm92ZSBvciBiZWxvdyB0aGVtIGluIHRoZSBwYXJlbnQgZG9jdW1lbnQuXG4gIGZ1bmN0aW9uIHNoaWZ0RG9jKGRvYywgZGlzdGFuY2UpIHtcbiAgICBpZiAoZGlzdGFuY2UgPT0gMCkgeyByZXR1cm4gfVxuICAgIGRvYy5maXJzdCArPSBkaXN0YW5jZTtcbiAgICBkb2Muc2VsID0gbmV3IFNlbGVjdGlvbihtYXAoZG9jLnNlbC5yYW5nZXMsIGZ1bmN0aW9uIChyYW5nZSkgeyByZXR1cm4gbmV3IFJhbmdlKFxuICAgICAgUG9zKHJhbmdlLmFuY2hvci5saW5lICsgZGlzdGFuY2UsIHJhbmdlLmFuY2hvci5jaCksXG4gICAgICBQb3MocmFuZ2UuaGVhZC5saW5lICsgZGlzdGFuY2UsIHJhbmdlLmhlYWQuY2gpXG4gICAgKTsgfSksIGRvYy5zZWwucHJpbUluZGV4KTtcbiAgICBpZiAoZG9jLmNtKSB7XG4gICAgICByZWdDaGFuZ2UoZG9jLmNtLCBkb2MuZmlyc3QsIGRvYy5maXJzdCAtIGRpc3RhbmNlLCBkaXN0YW5jZSk7XG4gICAgICBmb3IgKHZhciBkID0gZG9jLmNtLmRpc3BsYXksIGwgPSBkLnZpZXdGcm9tOyBsIDwgZC52aWV3VG87IGwrKylcbiAgICAgICAgeyByZWdMaW5lQ2hhbmdlKGRvYy5jbSwgbCwgXCJndXR0ZXJcIik7IH1cbiAgICB9XG4gIH1cblxuICAvLyBNb3JlIGxvd2VyLWxldmVsIGNoYW5nZSBmdW5jdGlvbiwgaGFuZGxpbmcgb25seSBhIHNpbmdsZSBkb2N1bWVudFxuICAvLyAobm90IGxpbmtlZCBvbmVzKS5cbiAgZnVuY3Rpb24gbWFrZUNoYW5nZVNpbmdsZURvYyhkb2MsIGNoYW5nZSwgc2VsQWZ0ZXIsIHNwYW5zKSB7XG4gICAgaWYgKGRvYy5jbSAmJiAhZG9jLmNtLmN1ck9wKVxuICAgICAgeyByZXR1cm4gb3BlcmF0aW9uKGRvYy5jbSwgbWFrZUNoYW5nZVNpbmdsZURvYykoZG9jLCBjaGFuZ2UsIHNlbEFmdGVyLCBzcGFucykgfVxuXG4gICAgaWYgKGNoYW5nZS50by5saW5lIDwgZG9jLmZpcnN0KSB7XG4gICAgICBzaGlmdERvYyhkb2MsIGNoYW5nZS50ZXh0Lmxlbmd0aCAtIDEgLSAoY2hhbmdlLnRvLmxpbmUgLSBjaGFuZ2UuZnJvbS5saW5lKSk7XG4gICAgICByZXR1cm5cbiAgICB9XG4gICAgaWYgKGNoYW5nZS5mcm9tLmxpbmUgPiBkb2MubGFzdExpbmUoKSkgeyByZXR1cm4gfVxuXG4gICAgLy8gQ2xpcCB0aGUgY2hhbmdlIHRvIHRoZSBzaXplIG9mIHRoaXMgZG9jXG4gICAgaWYgKGNoYW5nZS5mcm9tLmxpbmUgPCBkb2MuZmlyc3QpIHtcbiAgICAgIHZhciBzaGlmdCA9IGNoYW5nZS50ZXh0Lmxlbmd0aCAtIDEgLSAoZG9jLmZpcnN0IC0gY2hhbmdlLmZyb20ubGluZSk7XG4gICAgICBzaGlmdERvYyhkb2MsIHNoaWZ0KTtcbiAgICAgIGNoYW5nZSA9IHtmcm9tOiBQb3MoZG9jLmZpcnN0LCAwKSwgdG86IFBvcyhjaGFuZ2UudG8ubGluZSArIHNoaWZ0LCBjaGFuZ2UudG8uY2gpLFxuICAgICAgICAgICAgICAgIHRleHQ6IFtsc3QoY2hhbmdlLnRleHQpXSwgb3JpZ2luOiBjaGFuZ2Uub3JpZ2lufTtcbiAgICB9XG4gICAgdmFyIGxhc3QgPSBkb2MubGFzdExpbmUoKTtcbiAgICBpZiAoY2hhbmdlLnRvLmxpbmUgPiBsYXN0KSB7XG4gICAgICBjaGFuZ2UgPSB7ZnJvbTogY2hhbmdlLmZyb20sIHRvOiBQb3MobGFzdCwgZ2V0TGluZShkb2MsIGxhc3QpLnRleHQubGVuZ3RoKSxcbiAgICAgICAgICAgICAgICB0ZXh0OiBbY2hhbmdlLnRleHRbMF1dLCBvcmlnaW46IGNoYW5nZS5vcmlnaW59O1xuICAgIH1cblxuICAgIGNoYW5nZS5yZW1vdmVkID0gZ2V0QmV0d2Vlbihkb2MsIGNoYW5nZS5mcm9tLCBjaGFuZ2UudG8pO1xuXG4gICAgaWYgKCFzZWxBZnRlcikgeyBzZWxBZnRlciA9IGNvbXB1dGVTZWxBZnRlckNoYW5nZShkb2MsIGNoYW5nZSk7IH1cbiAgICBpZiAoZG9jLmNtKSB7IG1ha2VDaGFuZ2VTaW5nbGVEb2NJbkVkaXRvcihkb2MuY20sIGNoYW5nZSwgc3BhbnMpOyB9XG4gICAgZWxzZSB7IHVwZGF0ZURvYyhkb2MsIGNoYW5nZSwgc3BhbnMpOyB9XG4gICAgc2V0U2VsZWN0aW9uTm9VbmRvKGRvYywgc2VsQWZ0ZXIsIHNlbF9kb250U2Nyb2xsKTtcbiAgfVxuXG4gIC8vIEhhbmRsZSB0aGUgaW50ZXJhY3Rpb24gb2YgYSBjaGFuZ2UgdG8gYSBkb2N1bWVudCB3aXRoIHRoZSBlZGl0b3JcbiAgLy8gdGhhdCB0aGlzIGRvY3VtZW50IGlzIHBhcnQgb2YuXG4gIGZ1bmN0aW9uIG1ha2VDaGFuZ2VTaW5nbGVEb2NJbkVkaXRvcihjbSwgY2hhbmdlLCBzcGFucykge1xuICAgIHZhciBkb2MgPSBjbS5kb2MsIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCBmcm9tID0gY2hhbmdlLmZyb20sIHRvID0gY2hhbmdlLnRvO1xuXG4gICAgdmFyIHJlY29tcHV0ZU1heExlbmd0aCA9IGZhbHNlLCBjaGVja1dpZHRoU3RhcnQgPSBmcm9tLmxpbmU7XG4gICAgaWYgKCFjbS5vcHRpb25zLmxpbmVXcmFwcGluZykge1xuICAgICAgY2hlY2tXaWR0aFN0YXJ0ID0gbGluZU5vKHZpc3VhbExpbmUoZ2V0TGluZShkb2MsIGZyb20ubGluZSkpKTtcbiAgICAgIGRvYy5pdGVyKGNoZWNrV2lkdGhTdGFydCwgdG8ubGluZSArIDEsIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIGlmIChsaW5lID09IGRpc3BsYXkubWF4TGluZSkge1xuICAgICAgICAgIHJlY29tcHV0ZU1heExlbmd0aCA9IHRydWU7XG4gICAgICAgICAgcmV0dXJuIHRydWVcbiAgICAgICAgfVxuICAgICAgfSk7XG4gICAgfVxuXG4gICAgaWYgKGRvYy5zZWwuY29udGFpbnMoY2hhbmdlLmZyb20sIGNoYW5nZS50bykgPiAtMSlcbiAgICAgIHsgc2lnbmFsQ3Vyc29yQWN0aXZpdHkoY20pOyB9XG5cbiAgICB1cGRhdGVEb2MoZG9jLCBjaGFuZ2UsIHNwYW5zLCBlc3RpbWF0ZUhlaWdodChjbSkpO1xuXG4gICAgaWYgKCFjbS5vcHRpb25zLmxpbmVXcmFwcGluZykge1xuICAgICAgZG9jLml0ZXIoY2hlY2tXaWR0aFN0YXJ0LCBmcm9tLmxpbmUgKyBjaGFuZ2UudGV4dC5sZW5ndGgsIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHZhciBsZW4gPSBsaW5lTGVuZ3RoKGxpbmUpO1xuICAgICAgICBpZiAobGVuID4gZGlzcGxheS5tYXhMaW5lTGVuZ3RoKSB7XG4gICAgICAgICAgZGlzcGxheS5tYXhMaW5lID0gbGluZTtcbiAgICAgICAgICBkaXNwbGF5Lm1heExpbmVMZW5ndGggPSBsZW47XG4gICAgICAgICAgZGlzcGxheS5tYXhMaW5lQ2hhbmdlZCA9IHRydWU7XG4gICAgICAgICAgcmVjb21wdXRlTWF4TGVuZ3RoID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICAgIH0pO1xuICAgICAgaWYgKHJlY29tcHV0ZU1heExlbmd0aCkgeyBjbS5jdXJPcC51cGRhdGVNYXhMaW5lID0gdHJ1ZTsgfVxuICAgIH1cblxuICAgIHJldHJlYXRGcm9udGllcihkb2MsIGZyb20ubGluZSk7XG4gICAgc3RhcnRXb3JrZXIoY20sIDQwMCk7XG5cbiAgICB2YXIgbGVuZGlmZiA9IGNoYW5nZS50ZXh0Lmxlbmd0aCAtICh0by5saW5lIC0gZnJvbS5saW5lKSAtIDE7XG4gICAgLy8gUmVtZW1iZXIgdGhhdCB0aGVzZSBsaW5lcyBjaGFuZ2VkLCBmb3IgdXBkYXRpbmcgdGhlIGRpc3BsYXlcbiAgICBpZiAoY2hhbmdlLmZ1bGwpXG4gICAgICB7IHJlZ0NoYW5nZShjbSk7IH1cbiAgICBlbHNlIGlmIChmcm9tLmxpbmUgPT0gdG8ubGluZSAmJiBjaGFuZ2UudGV4dC5sZW5ndGggPT0gMSAmJiAhaXNXaG9sZUxpbmVVcGRhdGUoY20uZG9jLCBjaGFuZ2UpKVxuICAgICAgeyByZWdMaW5lQ2hhbmdlKGNtLCBmcm9tLmxpbmUsIFwidGV4dFwiKTsgfVxuICAgIGVsc2VcbiAgICAgIHsgcmVnQ2hhbmdlKGNtLCBmcm9tLmxpbmUsIHRvLmxpbmUgKyAxLCBsZW5kaWZmKTsgfVxuXG4gICAgdmFyIGNoYW5nZXNIYW5kbGVyID0gaGFzSGFuZGxlcihjbSwgXCJjaGFuZ2VzXCIpLCBjaGFuZ2VIYW5kbGVyID0gaGFzSGFuZGxlcihjbSwgXCJjaGFuZ2VcIik7XG4gICAgaWYgKGNoYW5nZUhhbmRsZXIgfHwgY2hhbmdlc0hhbmRsZXIpIHtcbiAgICAgIHZhciBvYmogPSB7XG4gICAgICAgIGZyb206IGZyb20sIHRvOiB0byxcbiAgICAgICAgdGV4dDogY2hhbmdlLnRleHQsXG4gICAgICAgIHJlbW92ZWQ6IGNoYW5nZS5yZW1vdmVkLFxuICAgICAgICBvcmlnaW46IGNoYW5nZS5vcmlnaW5cbiAgICAgIH07XG4gICAgICBpZiAoY2hhbmdlSGFuZGxlcikgeyBzaWduYWxMYXRlcihjbSwgXCJjaGFuZ2VcIiwgY20sIG9iaik7IH1cbiAgICAgIGlmIChjaGFuZ2VzSGFuZGxlcikgeyAoY20uY3VyT3AuY2hhbmdlT2JqcyB8fCAoY20uY3VyT3AuY2hhbmdlT2JqcyA9IFtdKSkucHVzaChvYmopOyB9XG4gICAgfVxuICAgIGNtLmRpc3BsYXkuc2VsRm9yQ29udGV4dE1lbnUgPSBudWxsO1xuICB9XG5cbiAgZnVuY3Rpb24gcmVwbGFjZVJhbmdlKGRvYywgY29kZSwgZnJvbSwgdG8sIG9yaWdpbikge1xuICAgIHZhciBhc3NpZ247XG5cbiAgICBpZiAoIXRvKSB7IHRvID0gZnJvbTsgfVxuICAgIGlmIChjbXAodG8sIGZyb20pIDwgMCkgeyAoYXNzaWduID0gW3RvLCBmcm9tXSwgZnJvbSA9IGFzc2lnblswXSwgdG8gPSBhc3NpZ25bMV0pOyB9XG4gICAgaWYgKHR5cGVvZiBjb2RlID09IFwic3RyaW5nXCIpIHsgY29kZSA9IGRvYy5zcGxpdExpbmVzKGNvZGUpOyB9XG4gICAgbWFrZUNoYW5nZShkb2MsIHtmcm9tOiBmcm9tLCB0bzogdG8sIHRleHQ6IGNvZGUsIG9yaWdpbjogb3JpZ2lufSk7XG4gIH1cblxuICAvLyBSZWJhc2luZy9yZXNldHRpbmcgaGlzdG9yeSB0byBkZWFsIHdpdGggZXh0ZXJuYWxseS1zb3VyY2VkIGNoYW5nZXNcblxuICBmdW5jdGlvbiByZWJhc2VIaXN0U2VsU2luZ2xlKHBvcywgZnJvbSwgdG8sIGRpZmYpIHtcbiAgICBpZiAodG8gPCBwb3MubGluZSkge1xuICAgICAgcG9zLmxpbmUgKz0gZGlmZjtcbiAgICB9IGVsc2UgaWYgKGZyb20gPCBwb3MubGluZSkge1xuICAgICAgcG9zLmxpbmUgPSBmcm9tO1xuICAgICAgcG9zLmNoID0gMDtcbiAgICB9XG4gIH1cblxuICAvLyBUcmllcyB0byByZWJhc2UgYW4gYXJyYXkgb2YgaGlzdG9yeSBldmVudHMgZ2l2ZW4gYSBjaGFuZ2UgaW4gdGhlXG4gIC8vIGRvY3VtZW50LiBJZiB0aGUgY2hhbmdlIHRvdWNoZXMgdGhlIHNhbWUgbGluZXMgYXMgdGhlIGV2ZW50LCB0aGVcbiAgLy8gZXZlbnQsIGFuZCBldmVyeXRoaW5nICdiZWhpbmQnIGl0LCBpcyBkaXNjYXJkZWQuIElmIHRoZSBjaGFuZ2UgaXNcbiAgLy8gYmVmb3JlIHRoZSBldmVudCwgdGhlIGV2ZW50J3MgcG9zaXRpb25zIGFyZSB1cGRhdGVkLiBVc2VzIGFcbiAgLy8gY29weS1vbi13cml0ZSBzY2hlbWUgZm9yIHRoZSBwb3NpdGlvbnMsIHRvIGF2b2lkIGhhdmluZyB0b1xuICAvLyByZWFsbG9jYXRlIHRoZW0gYWxsIG9uIGV2ZXJ5IHJlYmFzZSwgYnV0IGFsc28gYXZvaWQgcHJvYmxlbXMgd2l0aFxuICAvLyBzaGFyZWQgcG9zaXRpb24gb2JqZWN0cyBiZWluZyB1bnNhZmVseSB1cGRhdGVkLlxuICBmdW5jdGlvbiByZWJhc2VIaXN0QXJyYXkoYXJyYXksIGZyb20sIHRvLCBkaWZmKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7ICsraSkge1xuICAgICAgdmFyIHN1YiA9IGFycmF5W2ldLCBvayA9IHRydWU7XG4gICAgICBpZiAoc3ViLnJhbmdlcykge1xuICAgICAgICBpZiAoIXN1Yi5jb3BpZWQpIHsgc3ViID0gYXJyYXlbaV0gPSBzdWIuZGVlcENvcHkoKTsgc3ViLmNvcGllZCA9IHRydWU7IH1cbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBzdWIucmFuZ2VzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgcmViYXNlSGlzdFNlbFNpbmdsZShzdWIucmFuZ2VzW2pdLmFuY2hvciwgZnJvbSwgdG8sIGRpZmYpO1xuICAgICAgICAgIHJlYmFzZUhpc3RTZWxTaW5nbGUoc3ViLnJhbmdlc1tqXS5oZWFkLCBmcm9tLCB0bywgZGlmZik7XG4gICAgICAgIH1cbiAgICAgICAgY29udGludWVcbiAgICAgIH1cbiAgICAgIGZvciAodmFyIGokMSA9IDA7IGokMSA8IHN1Yi5jaGFuZ2VzLmxlbmd0aDsgKytqJDEpIHtcbiAgICAgICAgdmFyIGN1ciA9IHN1Yi5jaGFuZ2VzW2okMV07XG4gICAgICAgIGlmICh0byA8IGN1ci5mcm9tLmxpbmUpIHtcbiAgICAgICAgICBjdXIuZnJvbSA9IFBvcyhjdXIuZnJvbS5saW5lICsgZGlmZiwgY3VyLmZyb20uY2gpO1xuICAgICAgICAgIGN1ci50byA9IFBvcyhjdXIudG8ubGluZSArIGRpZmYsIGN1ci50by5jaCk7XG4gICAgICAgIH0gZWxzZSBpZiAoZnJvbSA8PSBjdXIudG8ubGluZSkge1xuICAgICAgICAgIG9rID0gZmFsc2U7XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKCFvaykge1xuICAgICAgICBhcnJheS5zcGxpY2UoMCwgaSArIDEpO1xuICAgICAgICBpID0gMDtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiByZWJhc2VIaXN0KGhpc3QsIGNoYW5nZSkge1xuICAgIHZhciBmcm9tID0gY2hhbmdlLmZyb20ubGluZSwgdG8gPSBjaGFuZ2UudG8ubGluZSwgZGlmZiA9IGNoYW5nZS50ZXh0Lmxlbmd0aCAtICh0byAtIGZyb20pIC0gMTtcbiAgICByZWJhc2VIaXN0QXJyYXkoaGlzdC5kb25lLCBmcm9tLCB0bywgZGlmZik7XG4gICAgcmViYXNlSGlzdEFycmF5KGhpc3QudW5kb25lLCBmcm9tLCB0bywgZGlmZik7XG4gIH1cblxuICAvLyBVdGlsaXR5IGZvciBhcHBseWluZyBhIGNoYW5nZSB0byBhIGxpbmUgYnkgaGFuZGxlIG9yIG51bWJlcixcbiAgLy8gcmV0dXJuaW5nIHRoZSBudW1iZXIgYW5kIG9wdGlvbmFsbHkgcmVnaXN0ZXJpbmcgdGhlIGxpbmUgYXNcbiAgLy8gY2hhbmdlZC5cbiAgZnVuY3Rpb24gY2hhbmdlTGluZShkb2MsIGhhbmRsZSwgY2hhbmdlVHlwZSwgb3ApIHtcbiAgICB2YXIgbm8gPSBoYW5kbGUsIGxpbmUgPSBoYW5kbGU7XG4gICAgaWYgKHR5cGVvZiBoYW5kbGUgPT0gXCJudW1iZXJcIikgeyBsaW5lID0gZ2V0TGluZShkb2MsIGNsaXBMaW5lKGRvYywgaGFuZGxlKSk7IH1cbiAgICBlbHNlIHsgbm8gPSBsaW5lTm8oaGFuZGxlKTsgfVxuICAgIGlmIChubyA9PSBudWxsKSB7IHJldHVybiBudWxsIH1cbiAgICBpZiAob3AobGluZSwgbm8pICYmIGRvYy5jbSkgeyByZWdMaW5lQ2hhbmdlKGRvYy5jbSwgbm8sIGNoYW5nZVR5cGUpOyB9XG4gICAgcmV0dXJuIGxpbmVcbiAgfVxuXG4gIC8vIFRoZSBkb2N1bWVudCBpcyByZXByZXNlbnRlZCBhcyBhIEJUcmVlIGNvbnNpc3Rpbmcgb2YgbGVhdmVzLCB3aXRoXG4gIC8vIGNodW5rIG9mIGxpbmVzIGluIHRoZW0sIGFuZCBicmFuY2hlcywgd2l0aCB1cCB0byB0ZW4gbGVhdmVzIG9yXG4gIC8vIG90aGVyIGJyYW5jaCBub2RlcyBiZWxvdyB0aGVtLiBUaGUgdG9wIG5vZGUgaXMgYWx3YXlzIGEgYnJhbmNoXG4gIC8vIG5vZGUsIGFuZCBpcyB0aGUgZG9jdW1lbnQgb2JqZWN0IGl0c2VsZiAobWVhbmluZyBpdCBoYXNcbiAgLy8gYWRkaXRpb25hbCBtZXRob2RzIGFuZCBwcm9wZXJ0aWVzKS5cbiAgLy9cbiAgLy8gQWxsIG5vZGVzIGhhdmUgcGFyZW50IGxpbmtzLiBUaGUgdHJlZSBpcyB1c2VkIGJvdGggdG8gZ28gZnJvbVxuICAvLyBsaW5lIG51bWJlcnMgdG8gbGluZSBvYmplY3RzLCBhbmQgdG8gZ28gZnJvbSBvYmplY3RzIHRvIG51bWJlcnMuXG4gIC8vIEl0IGFsc28gaW5kZXhlcyBieSBoZWlnaHQsIGFuZCBpcyB1c2VkIHRvIGNvbnZlcnQgYmV0d2VlbiBoZWlnaHRcbiAgLy8gYW5kIGxpbmUgb2JqZWN0LCBhbmQgdG8gZmluZCB0aGUgdG90YWwgaGVpZ2h0IG9mIHRoZSBkb2N1bWVudC5cbiAgLy9cbiAgLy8gU2VlIGFsc28gaHR0cDovL21hcmlqbmhhdmVyYmVrZS5ubC9ibG9nL2NvZGVtaXJyb3ItbGluZS10cmVlLmh0bWxcblxuICBmdW5jdGlvbiBMZWFmQ2h1bmsobGluZXMpIHtcbiAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgIHRoaXMubGluZXMgPSBsaW5lcztcbiAgICB0aGlzLnBhcmVudCA9IG51bGw7XG4gICAgdmFyIGhlaWdodCA9IDA7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7ICsraSkge1xuICAgICAgbGluZXNbaV0ucGFyZW50ID0gdGhpcyQxO1xuICAgICAgaGVpZ2h0ICs9IGxpbmVzW2ldLmhlaWdodDtcbiAgICB9XG4gICAgdGhpcy5oZWlnaHQgPSBoZWlnaHQ7XG4gIH1cblxuICBMZWFmQ2h1bmsucHJvdG90eXBlID0ge1xuICAgIGNodW5rU2l6ZTogZnVuY3Rpb24oKSB7IHJldHVybiB0aGlzLmxpbmVzLmxlbmd0aCB9LFxuXG4gICAgLy8gUmVtb3ZlIHRoZSBuIGxpbmVzIGF0IG9mZnNldCAnYXQnLlxuICAgIHJlbW92ZUlubmVyOiBmdW5jdGlvbihhdCwgbikge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICAgIGZvciAodmFyIGkgPSBhdCwgZSA9IGF0ICsgbjsgaSA8IGU7ICsraSkge1xuICAgICAgICB2YXIgbGluZSA9IHRoaXMkMS5saW5lc1tpXTtcbiAgICAgICAgdGhpcyQxLmhlaWdodCAtPSBsaW5lLmhlaWdodDtcbiAgICAgICAgY2xlYW5VcExpbmUobGluZSk7XG4gICAgICAgIHNpZ25hbExhdGVyKGxpbmUsIFwiZGVsZXRlXCIpO1xuICAgICAgfVxuICAgICAgdGhpcy5saW5lcy5zcGxpY2UoYXQsIG4pO1xuICAgIH0sXG5cbiAgICAvLyBIZWxwZXIgdXNlZCB0byBjb2xsYXBzZSBhIHNtYWxsIGJyYW5jaCBpbnRvIGEgc2luZ2xlIGxlYWYuXG4gICAgY29sbGFwc2U6IGZ1bmN0aW9uKGxpbmVzKSB7XG4gICAgICBsaW5lcy5wdXNoLmFwcGx5KGxpbmVzLCB0aGlzLmxpbmVzKTtcbiAgICB9LFxuXG4gICAgLy8gSW5zZXJ0IHRoZSBnaXZlbiBhcnJheSBvZiBsaW5lcyBhdCBvZmZzZXQgJ2F0JywgY291bnQgdGhlbSBhc1xuICAgIC8vIGhhdmluZyB0aGUgZ2l2ZW4gaGVpZ2h0LlxuICAgIGluc2VydElubmVyOiBmdW5jdGlvbihhdCwgbGluZXMsIGhlaWdodCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICAgIHRoaXMuaGVpZ2h0ICs9IGhlaWdodDtcbiAgICAgIHRoaXMubGluZXMgPSB0aGlzLmxpbmVzLnNsaWNlKDAsIGF0KS5jb25jYXQobGluZXMpLmNvbmNhdCh0aGlzLmxpbmVzLnNsaWNlKGF0KSk7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgKytpKSB7IGxpbmVzW2ldLnBhcmVudCA9IHRoaXMkMTsgfVxuICAgIH0sXG5cbiAgICAvLyBVc2VkIHRvIGl0ZXJhdGUgb3ZlciBhIHBhcnQgb2YgdGhlIHRyZWUuXG4gICAgaXRlck46IGZ1bmN0aW9uKGF0LCBuLCBvcCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICAgIGZvciAodmFyIGUgPSBhdCArIG47IGF0IDwgZTsgKythdClcbiAgICAgICAgeyBpZiAob3AodGhpcyQxLmxpbmVzW2F0XSkpIHsgcmV0dXJuIHRydWUgfSB9XG4gICAgfVxuICB9O1xuXG4gIGZ1bmN0aW9uIEJyYW5jaENodW5rKGNoaWxkcmVuKSB7XG4gICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICB0aGlzLmNoaWxkcmVuID0gY2hpbGRyZW47XG4gICAgdmFyIHNpemUgPSAwLCBoZWlnaHQgPSAwO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2hpbGRyZW4ubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBjaCA9IGNoaWxkcmVuW2ldO1xuICAgICAgc2l6ZSArPSBjaC5jaHVua1NpemUoKTsgaGVpZ2h0ICs9IGNoLmhlaWdodDtcbiAgICAgIGNoLnBhcmVudCA9IHRoaXMkMTtcbiAgICB9XG4gICAgdGhpcy5zaXplID0gc2l6ZTtcbiAgICB0aGlzLmhlaWdodCA9IGhlaWdodDtcbiAgICB0aGlzLnBhcmVudCA9IG51bGw7XG4gIH1cblxuICBCcmFuY2hDaHVuay5wcm90b3R5cGUgPSB7XG4gICAgY2h1bmtTaXplOiBmdW5jdGlvbigpIHsgcmV0dXJuIHRoaXMuc2l6ZSB9LFxuXG4gICAgcmVtb3ZlSW5uZXI6IGZ1bmN0aW9uKGF0LCBuKSB7XG4gICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgICAgdGhpcy5zaXplIC09IG47XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdmFyIGNoaWxkID0gdGhpcyQxLmNoaWxkcmVuW2ldLCBzeiA9IGNoaWxkLmNodW5rU2l6ZSgpO1xuICAgICAgICBpZiAoYXQgPCBzeikge1xuICAgICAgICAgIHZhciBybSA9IE1hdGgubWluKG4sIHN6IC0gYXQpLCBvbGRIZWlnaHQgPSBjaGlsZC5oZWlnaHQ7XG4gICAgICAgICAgY2hpbGQucmVtb3ZlSW5uZXIoYXQsIHJtKTtcbiAgICAgICAgICB0aGlzJDEuaGVpZ2h0IC09IG9sZEhlaWdodCAtIGNoaWxkLmhlaWdodDtcbiAgICAgICAgICBpZiAoc3ogPT0gcm0pIHsgdGhpcyQxLmNoaWxkcmVuLnNwbGljZShpLS0sIDEpOyBjaGlsZC5wYXJlbnQgPSBudWxsOyB9XG4gICAgICAgICAgaWYgKChuIC09IHJtKSA9PSAwKSB7IGJyZWFrIH1cbiAgICAgICAgICBhdCA9IDA7XG4gICAgICAgIH0gZWxzZSB7IGF0IC09IHN6OyB9XG4gICAgICB9XG4gICAgICAvLyBJZiB0aGUgcmVzdWx0IGlzIHNtYWxsZXIgdGhhbiAyNSBsaW5lcywgZW5zdXJlIHRoYXQgaXQgaXMgYVxuICAgICAgLy8gc2luZ2xlIGxlYWYgbm9kZS5cbiAgICAgIGlmICh0aGlzLnNpemUgLSBuIDwgMjUgJiZcbiAgICAgICAgICAodGhpcy5jaGlsZHJlbi5sZW5ndGggPiAxIHx8ICEodGhpcy5jaGlsZHJlblswXSBpbnN0YW5jZW9mIExlYWZDaHVuaykpKSB7XG4gICAgICAgIHZhciBsaW5lcyA9IFtdO1xuICAgICAgICB0aGlzLmNvbGxhcHNlKGxpbmVzKTtcbiAgICAgICAgdGhpcy5jaGlsZHJlbiA9IFtuZXcgTGVhZkNodW5rKGxpbmVzKV07XG4gICAgICAgIHRoaXMuY2hpbGRyZW5bMF0ucGFyZW50ID0gdGhpcztcbiAgICAgIH1cbiAgICB9LFxuXG4gICAgY29sbGFwc2U6IGZ1bmN0aW9uKGxpbmVzKSB7XG4gICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgKytpKSB7IHRoaXMkMS5jaGlsZHJlbltpXS5jb2xsYXBzZShsaW5lcyk7IH1cbiAgICB9LFxuXG4gICAgaW5zZXJ0SW5uZXI6IGZ1bmN0aW9uKGF0LCBsaW5lcywgaGVpZ2h0KSB7XG4gICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgICAgdGhpcy5zaXplICs9IGxpbmVzLmxlbmd0aDtcbiAgICAgIHRoaXMuaGVpZ2h0ICs9IGhlaWdodDtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5jaGlsZHJlbi5sZW5ndGg7ICsraSkge1xuICAgICAgICB2YXIgY2hpbGQgPSB0aGlzJDEuY2hpbGRyZW5baV0sIHN6ID0gY2hpbGQuY2h1bmtTaXplKCk7XG4gICAgICAgIGlmIChhdCA8PSBzeikge1xuICAgICAgICAgIGNoaWxkLmluc2VydElubmVyKGF0LCBsaW5lcywgaGVpZ2h0KTtcbiAgICAgICAgICBpZiAoY2hpbGQubGluZXMgJiYgY2hpbGQubGluZXMubGVuZ3RoID4gNTApIHtcbiAgICAgICAgICAgIC8vIFRvIGF2b2lkIG1lbW9yeSB0aHJhc2hpbmcgd2hlbiBjaGlsZC5saW5lcyBpcyBodWdlIChlLmcuIGZpcnN0IHZpZXcgb2YgYSBsYXJnZSBmaWxlKSwgaXQncyBuZXZlciBzcGxpY2VkLlxuICAgICAgICAgICAgLy8gSW5zdGVhZCwgc21hbGwgc2xpY2VzIGFyZSB0YWtlbi4gVGhleSdyZSB0YWtlbiBpbiBvcmRlciBiZWNhdXNlIHNlcXVlbnRpYWwgbWVtb3J5IGFjY2Vzc2VzIGFyZSBmYXN0ZXN0LlxuICAgICAgICAgICAgdmFyIHJlbWFpbmluZyA9IGNoaWxkLmxpbmVzLmxlbmd0aCAlIDI1ICsgMjU7XG4gICAgICAgICAgICBmb3IgKHZhciBwb3MgPSByZW1haW5pbmc7IHBvcyA8IGNoaWxkLmxpbmVzLmxlbmd0aDspIHtcbiAgICAgICAgICAgICAgdmFyIGxlYWYgPSBuZXcgTGVhZkNodW5rKGNoaWxkLmxpbmVzLnNsaWNlKHBvcywgcG9zICs9IDI1KSk7XG4gICAgICAgICAgICAgIGNoaWxkLmhlaWdodCAtPSBsZWFmLmhlaWdodDtcbiAgICAgICAgICAgICAgdGhpcyQxLmNoaWxkcmVuLnNwbGljZSgrK2ksIDAsIGxlYWYpO1xuICAgICAgICAgICAgICBsZWFmLnBhcmVudCA9IHRoaXMkMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNoaWxkLmxpbmVzID0gY2hpbGQubGluZXMuc2xpY2UoMCwgcmVtYWluaW5nKTtcbiAgICAgICAgICAgIHRoaXMkMS5tYXliZVNwaWxsKCk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrXG4gICAgICAgIH1cbiAgICAgICAgYXQgLT0gc3o7XG4gICAgICB9XG4gICAgfSxcblxuICAgIC8vIFdoZW4gYSBub2RlIGhhcyBncm93biwgY2hlY2sgd2hldGhlciBpdCBzaG91bGQgYmUgc3BsaXQuXG4gICAgbWF5YmVTcGlsbDogZnVuY3Rpb24oKSB7XG4gICAgICBpZiAodGhpcy5jaGlsZHJlbi5sZW5ndGggPD0gMTApIHsgcmV0dXJuIH1cbiAgICAgIHZhciBtZSA9IHRoaXM7XG4gICAgICBkbyB7XG4gICAgICAgIHZhciBzcGlsbGVkID0gbWUuY2hpbGRyZW4uc3BsaWNlKG1lLmNoaWxkcmVuLmxlbmd0aCAtIDUsIDUpO1xuICAgICAgICB2YXIgc2libGluZyA9IG5ldyBCcmFuY2hDaHVuayhzcGlsbGVkKTtcbiAgICAgICAgaWYgKCFtZS5wYXJlbnQpIHsgLy8gQmVjb21lIHRoZSBwYXJlbnQgbm9kZVxuICAgICAgICAgIHZhciBjb3B5ID0gbmV3IEJyYW5jaENodW5rKG1lLmNoaWxkcmVuKTtcbiAgICAgICAgICBjb3B5LnBhcmVudCA9IG1lO1xuICAgICAgICAgIG1lLmNoaWxkcmVuID0gW2NvcHksIHNpYmxpbmddO1xuICAgICAgICAgIG1lID0gY29weTtcbiAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG1lLnNpemUgLT0gc2libGluZy5zaXplO1xuICAgICAgICAgIG1lLmhlaWdodCAtPSBzaWJsaW5nLmhlaWdodDtcbiAgICAgICAgICB2YXIgbXlJbmRleCA9IGluZGV4T2YobWUucGFyZW50LmNoaWxkcmVuLCBtZSk7XG4gICAgICAgICAgbWUucGFyZW50LmNoaWxkcmVuLnNwbGljZShteUluZGV4ICsgMSwgMCwgc2libGluZyk7XG4gICAgICAgIH1cbiAgICAgICAgc2libGluZy5wYXJlbnQgPSBtZS5wYXJlbnQ7XG4gICAgICB9IHdoaWxlIChtZS5jaGlsZHJlbi5sZW5ndGggPiAxMClcbiAgICAgIG1lLnBhcmVudC5tYXliZVNwaWxsKCk7XG4gICAgfSxcblxuICAgIGl0ZXJOOiBmdW5jdGlvbihhdCwgbiwgb3ApIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdmFyIGNoaWxkID0gdGhpcyQxLmNoaWxkcmVuW2ldLCBzeiA9IGNoaWxkLmNodW5rU2l6ZSgpO1xuICAgICAgICBpZiAoYXQgPCBzeikge1xuICAgICAgICAgIHZhciB1c2VkID0gTWF0aC5taW4obiwgc3ogLSBhdCk7XG4gICAgICAgICAgaWYgKGNoaWxkLml0ZXJOKGF0LCB1c2VkLCBvcCkpIHsgcmV0dXJuIHRydWUgfVxuICAgICAgICAgIGlmICgobiAtPSB1c2VkKSA9PSAwKSB7IGJyZWFrIH1cbiAgICAgICAgICBhdCA9IDA7XG4gICAgICAgIH0gZWxzZSB7IGF0IC09IHN6OyB9XG4gICAgICB9XG4gICAgfVxuICB9O1xuXG4gIC8vIExpbmUgd2lkZ2V0cyBhcmUgYmxvY2sgZWxlbWVudHMgZGlzcGxheWVkIGFib3ZlIG9yIGJlbG93IGEgbGluZS5cblxuICB2YXIgTGluZVdpZGdldCA9IGZ1bmN0aW9uKGRvYywgbm9kZSwgb3B0aW9ucykge1xuICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgaWYgKG9wdGlvbnMpIHsgZm9yICh2YXIgb3B0IGluIG9wdGlvbnMpIHsgaWYgKG9wdGlvbnMuaGFzT3duUHJvcGVydHkob3B0KSlcbiAgICAgIHsgdGhpcyQxW29wdF0gPSBvcHRpb25zW29wdF07IH0gfSB9XG4gICAgdGhpcy5kb2MgPSBkb2M7XG4gICAgdGhpcy5ub2RlID0gbm9kZTtcbiAgfTtcblxuICBMaW5lV2lkZ2V0LnByb3RvdHlwZS5jbGVhciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgdmFyIGNtID0gdGhpcy5kb2MuY20sIHdzID0gdGhpcy5saW5lLndpZGdldHMsIGxpbmUgPSB0aGlzLmxpbmUsIG5vID0gbGluZU5vKGxpbmUpO1xuICAgIGlmIChubyA9PSBudWxsIHx8ICF3cykgeyByZXR1cm4gfVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgd3MubGVuZ3RoOyArK2kpIHsgaWYgKHdzW2ldID09IHRoaXMkMSkgeyB3cy5zcGxpY2UoaS0tLCAxKTsgfSB9XG4gICAgaWYgKCF3cy5sZW5ndGgpIHsgbGluZS53aWRnZXRzID0gbnVsbDsgfVxuICAgIHZhciBoZWlnaHQgPSB3aWRnZXRIZWlnaHQodGhpcyk7XG4gICAgdXBkYXRlTGluZUhlaWdodChsaW5lLCBNYXRoLm1heCgwLCBsaW5lLmhlaWdodCAtIGhlaWdodCkpO1xuICAgIGlmIChjbSkge1xuICAgICAgcnVuSW5PcChjbSwgZnVuY3Rpb24gKCkge1xuICAgICAgICBhZGp1c3RTY3JvbGxXaGVuQWJvdmVWaXNpYmxlKGNtLCBsaW5lLCAtaGVpZ2h0KTtcbiAgICAgICAgcmVnTGluZUNoYW5nZShjbSwgbm8sIFwid2lkZ2V0XCIpO1xuICAgICAgfSk7XG4gICAgICBzaWduYWxMYXRlcihjbSwgXCJsaW5lV2lkZ2V0Q2xlYXJlZFwiLCBjbSwgdGhpcywgbm8pO1xuICAgIH1cbiAgfTtcblxuICBMaW5lV2lkZ2V0LnByb3RvdHlwZS5jaGFuZ2VkID0gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICB2YXIgb2xkSCA9IHRoaXMuaGVpZ2h0LCBjbSA9IHRoaXMuZG9jLmNtLCBsaW5lID0gdGhpcy5saW5lO1xuICAgIHRoaXMuaGVpZ2h0ID0gbnVsbDtcbiAgICB2YXIgZGlmZiA9IHdpZGdldEhlaWdodCh0aGlzKSAtIG9sZEg7XG4gICAgaWYgKCFkaWZmKSB7IHJldHVybiB9XG4gICAgaWYgKCFsaW5lSXNIaWRkZW4odGhpcy5kb2MsIGxpbmUpKSB7IHVwZGF0ZUxpbmVIZWlnaHQobGluZSwgbGluZS5oZWlnaHQgKyBkaWZmKTsgfVxuICAgIGlmIChjbSkge1xuICAgICAgcnVuSW5PcChjbSwgZnVuY3Rpb24gKCkge1xuICAgICAgICBjbS5jdXJPcC5mb3JjZVVwZGF0ZSA9IHRydWU7XG4gICAgICAgIGFkanVzdFNjcm9sbFdoZW5BYm92ZVZpc2libGUoY20sIGxpbmUsIGRpZmYpO1xuICAgICAgICBzaWduYWxMYXRlcihjbSwgXCJsaW5lV2lkZ2V0Q2hhbmdlZFwiLCBjbSwgdGhpcyQxLCBsaW5lTm8obGluZSkpO1xuICAgICAgfSk7XG4gICAgfVxuICB9O1xuICBldmVudE1peGluKExpbmVXaWRnZXQpO1xuXG4gIGZ1bmN0aW9uIGFkanVzdFNjcm9sbFdoZW5BYm92ZVZpc2libGUoY20sIGxpbmUsIGRpZmYpIHtcbiAgICBpZiAoaGVpZ2h0QXRMaW5lKGxpbmUpIDwgKChjbS5jdXJPcCAmJiBjbS5jdXJPcC5zY3JvbGxUb3ApIHx8IGNtLmRvYy5zY3JvbGxUb3ApKVxuICAgICAgeyBhZGRUb1Njcm9sbFRvcChjbSwgZGlmZik7IH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGFkZExpbmVXaWRnZXQoZG9jLCBoYW5kbGUsIG5vZGUsIG9wdGlvbnMpIHtcbiAgICB2YXIgd2lkZ2V0ID0gbmV3IExpbmVXaWRnZXQoZG9jLCBub2RlLCBvcHRpb25zKTtcbiAgICB2YXIgY20gPSBkb2MuY207XG4gICAgaWYgKGNtICYmIHdpZGdldC5ub0hTY3JvbGwpIHsgY20uZGlzcGxheS5hbGlnbldpZGdldHMgPSB0cnVlOyB9XG4gICAgY2hhbmdlTGluZShkb2MsIGhhbmRsZSwgXCJ3aWRnZXRcIiwgZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgIHZhciB3aWRnZXRzID0gbGluZS53aWRnZXRzIHx8IChsaW5lLndpZGdldHMgPSBbXSk7XG4gICAgICBpZiAod2lkZ2V0Lmluc2VydEF0ID09IG51bGwpIHsgd2lkZ2V0cy5wdXNoKHdpZGdldCk7IH1cbiAgICAgIGVsc2UgeyB3aWRnZXRzLnNwbGljZShNYXRoLm1pbih3aWRnZXRzLmxlbmd0aCAtIDEsIE1hdGgubWF4KDAsIHdpZGdldC5pbnNlcnRBdCkpLCAwLCB3aWRnZXQpOyB9XG4gICAgICB3aWRnZXQubGluZSA9IGxpbmU7XG4gICAgICBpZiAoY20gJiYgIWxpbmVJc0hpZGRlbihkb2MsIGxpbmUpKSB7XG4gICAgICAgIHZhciBhYm92ZVZpc2libGUgPSBoZWlnaHRBdExpbmUobGluZSkgPCBkb2Muc2Nyb2xsVG9wO1xuICAgICAgICB1cGRhdGVMaW5lSGVpZ2h0KGxpbmUsIGxpbmUuaGVpZ2h0ICsgd2lkZ2V0SGVpZ2h0KHdpZGdldCkpO1xuICAgICAgICBpZiAoYWJvdmVWaXNpYmxlKSB7IGFkZFRvU2Nyb2xsVG9wKGNtLCB3aWRnZXQuaGVpZ2h0KTsgfVxuICAgICAgICBjbS5jdXJPcC5mb3JjZVVwZGF0ZSA9IHRydWU7XG4gICAgICB9XG4gICAgICByZXR1cm4gdHJ1ZVxuICAgIH0pO1xuICAgIGlmIChjbSkgeyBzaWduYWxMYXRlcihjbSwgXCJsaW5lV2lkZ2V0QWRkZWRcIiwgY20sIHdpZGdldCwgdHlwZW9mIGhhbmRsZSA9PSBcIm51bWJlclwiID8gaGFuZGxlIDogbGluZU5vKGhhbmRsZSkpOyB9XG4gICAgcmV0dXJuIHdpZGdldFxuICB9XG5cbiAgLy8gVEVYVE1BUktFUlNcblxuICAvLyBDcmVhdGVkIHdpdGggbWFya1RleHQgYW5kIHNldEJvb2ttYXJrIG1ldGhvZHMuIEEgVGV4dE1hcmtlciBpcyBhXG4gIC8vIGhhbmRsZSB0aGF0IGNhbiBiZSB1c2VkIHRvIGNsZWFyIG9yIGZpbmQgYSBtYXJrZWQgcG9zaXRpb24gaW4gdGhlXG4gIC8vIGRvY3VtZW50LiBMaW5lIG9iamVjdHMgaG9sZCBhcnJheXMgKG1hcmtlZFNwYW5zKSBjb250YWluaW5nXG4gIC8vIHtmcm9tLCB0bywgbWFya2VyfSBvYmplY3QgcG9pbnRpbmcgdG8gc3VjaCBtYXJrZXIgb2JqZWN0cywgYW5kXG4gIC8vIGluZGljYXRpbmcgdGhhdCBzdWNoIGEgbWFya2VyIGlzIHByZXNlbnQgb24gdGhhdCBsaW5lLiBNdWx0aXBsZVxuICAvLyBsaW5lcyBtYXkgcG9pbnQgdG8gdGhlIHNhbWUgbWFya2VyIHdoZW4gaXQgc3BhbnMgYWNyb3NzIGxpbmVzLlxuICAvLyBUaGUgc3BhbnMgd2lsbCBoYXZlIG51bGwgZm9yIHRoZWlyIGZyb20vdG8gcHJvcGVydGllcyB3aGVuIHRoZVxuICAvLyBtYXJrZXIgY29udGludWVzIGJleW9uZCB0aGUgc3RhcnQvZW5kIG9mIHRoZSBsaW5lLiBNYXJrZXJzIGhhdmVcbiAgLy8gbGlua3MgYmFjayB0byB0aGUgbGluZXMgdGhleSBjdXJyZW50bHkgdG91Y2guXG5cbiAgLy8gQ29sbGFwc2VkIG1hcmtlcnMgaGF2ZSB1bmlxdWUgaWRzLCBpbiBvcmRlciB0byBiZSBhYmxlIHRvIG9yZGVyXG4gIC8vIHRoZW0sIHdoaWNoIGlzIG5lZWRlZCBmb3IgdW5pcXVlbHkgZGV0ZXJtaW5pbmcgYW4gb3V0ZXIgbWFya2VyXG4gIC8vIHdoZW4gdGhleSBvdmVybGFwICh0aGV5IG1heSBuZXN0LCBidXQgbm90IHBhcnRpYWxseSBvdmVybGFwKS5cbiAgdmFyIG5leHRNYXJrZXJJZCA9IDA7XG5cbiAgdmFyIFRleHRNYXJrZXIgPSBmdW5jdGlvbihkb2MsIHR5cGUpIHtcbiAgICB0aGlzLmxpbmVzID0gW107XG4gICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICB0aGlzLmRvYyA9IGRvYztcbiAgICB0aGlzLmlkID0gKytuZXh0TWFya2VySWQ7XG4gIH07XG5cbiAgLy8gQ2xlYXIgdGhlIG1hcmtlci5cbiAgVGV4dE1hcmtlci5wcm90b3R5cGUuY2xlYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgIGlmICh0aGlzLmV4cGxpY2l0bHlDbGVhcmVkKSB7IHJldHVybiB9XG4gICAgdmFyIGNtID0gdGhpcy5kb2MuY20sIHdpdGhPcCA9IGNtICYmICFjbS5jdXJPcDtcbiAgICBpZiAod2l0aE9wKSB7IHN0YXJ0T3BlcmF0aW9uKGNtKTsgfVxuICAgIGlmIChoYXNIYW5kbGVyKHRoaXMsIFwiY2xlYXJcIikpIHtcbiAgICAgIHZhciBmb3VuZCA9IHRoaXMuZmluZCgpO1xuICAgICAgaWYgKGZvdW5kKSB7IHNpZ25hbExhdGVyKHRoaXMsIFwiY2xlYXJcIiwgZm91bmQuZnJvbSwgZm91bmQudG8pOyB9XG4gICAgfVxuICAgIHZhciBtaW4gPSBudWxsLCBtYXggPSBudWxsO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5saW5lcy5sZW5ndGg7ICsraSkge1xuICAgICAgdmFyIGxpbmUgPSB0aGlzJDEubGluZXNbaV07XG4gICAgICB2YXIgc3BhbiA9IGdldE1hcmtlZFNwYW5Gb3IobGluZS5tYXJrZWRTcGFucywgdGhpcyQxKTtcbiAgICAgIGlmIChjbSAmJiAhdGhpcyQxLmNvbGxhcHNlZCkgeyByZWdMaW5lQ2hhbmdlKGNtLCBsaW5lTm8obGluZSksIFwidGV4dFwiKTsgfVxuICAgICAgZWxzZSBpZiAoY20pIHtcbiAgICAgICAgaWYgKHNwYW4udG8gIT0gbnVsbCkgeyBtYXggPSBsaW5lTm8obGluZSk7IH1cbiAgICAgICAgaWYgKHNwYW4uZnJvbSAhPSBudWxsKSB7IG1pbiA9IGxpbmVObyhsaW5lKTsgfVxuICAgICAgfVxuICAgICAgbGluZS5tYXJrZWRTcGFucyA9IHJlbW92ZU1hcmtlZFNwYW4obGluZS5tYXJrZWRTcGFucywgc3Bhbik7XG4gICAgICBpZiAoc3Bhbi5mcm9tID09IG51bGwgJiYgdGhpcyQxLmNvbGxhcHNlZCAmJiAhbGluZUlzSGlkZGVuKHRoaXMkMS5kb2MsIGxpbmUpICYmIGNtKVxuICAgICAgICB7IHVwZGF0ZUxpbmVIZWlnaHQobGluZSwgdGV4dEhlaWdodChjbS5kaXNwbGF5KSk7IH1cbiAgICB9XG4gICAgaWYgKGNtICYmIHRoaXMuY29sbGFwc2VkICYmICFjbS5vcHRpb25zLmxpbmVXcmFwcGluZykgeyBmb3IgKHZhciBpJDEgPSAwOyBpJDEgPCB0aGlzLmxpbmVzLmxlbmd0aDsgKytpJDEpIHtcbiAgICAgIHZhciB2aXN1YWwgPSB2aXN1YWxMaW5lKHRoaXMkMS5saW5lc1tpJDFdKSwgbGVuID0gbGluZUxlbmd0aCh2aXN1YWwpO1xuICAgICAgaWYgKGxlbiA+IGNtLmRpc3BsYXkubWF4TGluZUxlbmd0aCkge1xuICAgICAgICBjbS5kaXNwbGF5Lm1heExpbmUgPSB2aXN1YWw7XG4gICAgICAgIGNtLmRpc3BsYXkubWF4TGluZUxlbmd0aCA9IGxlbjtcbiAgICAgICAgY20uZGlzcGxheS5tYXhMaW5lQ2hhbmdlZCA9IHRydWU7XG4gICAgICB9XG4gICAgfSB9XG5cbiAgICBpZiAobWluICE9IG51bGwgJiYgY20gJiYgdGhpcy5jb2xsYXBzZWQpIHsgcmVnQ2hhbmdlKGNtLCBtaW4sIG1heCArIDEpOyB9XG4gICAgdGhpcy5saW5lcy5sZW5ndGggPSAwO1xuICAgIHRoaXMuZXhwbGljaXRseUNsZWFyZWQgPSB0cnVlO1xuICAgIGlmICh0aGlzLmF0b21pYyAmJiB0aGlzLmRvYy5jYW50RWRpdCkge1xuICAgICAgdGhpcy5kb2MuY2FudEVkaXQgPSBmYWxzZTtcbiAgICAgIGlmIChjbSkgeyByZUNoZWNrU2VsZWN0aW9uKGNtLmRvYyk7IH1cbiAgICB9XG4gICAgaWYgKGNtKSB7IHNpZ25hbExhdGVyKGNtLCBcIm1hcmtlckNsZWFyZWRcIiwgY20sIHRoaXMsIG1pbiwgbWF4KTsgfVxuICAgIGlmICh3aXRoT3ApIHsgZW5kT3BlcmF0aW9uKGNtKTsgfVxuICAgIGlmICh0aGlzLnBhcmVudCkgeyB0aGlzLnBhcmVudC5jbGVhcigpOyB9XG4gIH07XG5cbiAgLy8gRmluZCB0aGUgcG9zaXRpb24gb2YgdGhlIG1hcmtlciBpbiB0aGUgZG9jdW1lbnQuIFJldHVybnMgYSB7ZnJvbSxcbiAgLy8gdG99IG9iamVjdCBieSBkZWZhdWx0LiBTaWRlIGNhbiBiZSBwYXNzZWQgdG8gZ2V0IGEgc3BlY2lmaWMgc2lkZVxuICAvLyAtLSAwIChib3RoKSwgLTEgKGxlZnQpLCBvciAxIChyaWdodCkuIFdoZW4gbGluZU9iaiBpcyB0cnVlLCB0aGVcbiAgLy8gUG9zIG9iamVjdHMgcmV0dXJuZWQgY29udGFpbiBhIGxpbmUgb2JqZWN0LCByYXRoZXIgdGhhbiBhIGxpbmVcbiAgLy8gbnVtYmVyICh1c2VkIHRvIHByZXZlbnQgbG9va2luZyB1cCB0aGUgc2FtZSBsaW5lIHR3aWNlKS5cbiAgVGV4dE1hcmtlci5wcm90b3R5cGUuZmluZCA9IGZ1bmN0aW9uIChzaWRlLCBsaW5lT2JqKSB7XG4gICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgIGlmIChzaWRlID09IG51bGwgJiYgdGhpcy50eXBlID09IFwiYm9va21hcmtcIikgeyBzaWRlID0gMTsgfVxuICAgIHZhciBmcm9tLCB0bztcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubGluZXMubGVuZ3RoOyArK2kpIHtcbiAgICAgIHZhciBsaW5lID0gdGhpcyQxLmxpbmVzW2ldO1xuICAgICAgdmFyIHNwYW4gPSBnZXRNYXJrZWRTcGFuRm9yKGxpbmUubWFya2VkU3BhbnMsIHRoaXMkMSk7XG4gICAgICBpZiAoc3Bhbi5mcm9tICE9IG51bGwpIHtcbiAgICAgICAgZnJvbSA9IFBvcyhsaW5lT2JqID8gbGluZSA6IGxpbmVObyhsaW5lKSwgc3Bhbi5mcm9tKTtcbiAgICAgICAgaWYgKHNpZGUgPT0gLTEpIHsgcmV0dXJuIGZyb20gfVxuICAgICAgfVxuICAgICAgaWYgKHNwYW4udG8gIT0gbnVsbCkge1xuICAgICAgICB0byA9IFBvcyhsaW5lT2JqID8gbGluZSA6IGxpbmVObyhsaW5lKSwgc3Bhbi50byk7XG4gICAgICAgIGlmIChzaWRlID09IDEpIHsgcmV0dXJuIHRvIH1cbiAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIGZyb20gJiYge2Zyb206IGZyb20sIHRvOiB0b31cbiAgfTtcblxuICAvLyBTaWduYWxzIHRoYXQgdGhlIG1hcmtlcidzIHdpZGdldCBjaGFuZ2VkLCBhbmQgc3Vycm91bmRpbmcgbGF5b3V0XG4gIC8vIHNob3VsZCBiZSByZWNvbXB1dGVkLlxuICBUZXh0TWFya2VyLnByb3RvdHlwZS5jaGFuZ2VkID0gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICB2YXIgcG9zID0gdGhpcy5maW5kKC0xLCB0cnVlKSwgd2lkZ2V0ID0gdGhpcywgY20gPSB0aGlzLmRvYy5jbTtcbiAgICBpZiAoIXBvcyB8fCAhY20pIHsgcmV0dXJuIH1cbiAgICBydW5Jbk9wKGNtLCBmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgbGluZSA9IHBvcy5saW5lLCBsaW5lTiA9IGxpbmVObyhwb3MubGluZSk7XG4gICAgICB2YXIgdmlldyA9IGZpbmRWaWV3Rm9yTGluZShjbSwgbGluZU4pO1xuICAgICAgaWYgKHZpZXcpIHtcbiAgICAgICAgY2xlYXJMaW5lTWVhc3VyZW1lbnRDYWNoZUZvcih2aWV3KTtcbiAgICAgICAgY20uY3VyT3Auc2VsZWN0aW9uQ2hhbmdlZCA9IGNtLmN1ck9wLmZvcmNlVXBkYXRlID0gdHJ1ZTtcbiAgICAgIH1cbiAgICAgIGNtLmN1ck9wLnVwZGF0ZU1heExpbmUgPSB0cnVlO1xuICAgICAgaWYgKCFsaW5lSXNIaWRkZW4od2lkZ2V0LmRvYywgbGluZSkgJiYgd2lkZ2V0LmhlaWdodCAhPSBudWxsKSB7XG4gICAgICAgIHZhciBvbGRIZWlnaHQgPSB3aWRnZXQuaGVpZ2h0O1xuICAgICAgICB3aWRnZXQuaGVpZ2h0ID0gbnVsbDtcbiAgICAgICAgdmFyIGRIZWlnaHQgPSB3aWRnZXRIZWlnaHQod2lkZ2V0KSAtIG9sZEhlaWdodDtcbiAgICAgICAgaWYgKGRIZWlnaHQpXG4gICAgICAgICAgeyB1cGRhdGVMaW5lSGVpZ2h0KGxpbmUsIGxpbmUuaGVpZ2h0ICsgZEhlaWdodCk7IH1cbiAgICAgIH1cbiAgICAgIHNpZ25hbExhdGVyKGNtLCBcIm1hcmtlckNoYW5nZWRcIiwgY20sIHRoaXMkMSk7XG4gICAgfSk7XG4gIH07XG5cbiAgVGV4dE1hcmtlci5wcm90b3R5cGUuYXR0YWNoTGluZSA9IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgaWYgKCF0aGlzLmxpbmVzLmxlbmd0aCAmJiB0aGlzLmRvYy5jbSkge1xuICAgICAgdmFyIG9wID0gdGhpcy5kb2MuY20uY3VyT3A7XG4gICAgICBpZiAoIW9wLm1heWJlSGlkZGVuTWFya2VycyB8fCBpbmRleE9mKG9wLm1heWJlSGlkZGVuTWFya2VycywgdGhpcykgPT0gLTEpXG4gICAgICAgIHsgKG9wLm1heWJlVW5oaWRkZW5NYXJrZXJzIHx8IChvcC5tYXliZVVuaGlkZGVuTWFya2VycyA9IFtdKSkucHVzaCh0aGlzKTsgfVxuICAgIH1cbiAgICB0aGlzLmxpbmVzLnB1c2gobGluZSk7XG4gIH07XG5cbiAgVGV4dE1hcmtlci5wcm90b3R5cGUuZGV0YWNoTGluZSA9IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgdGhpcy5saW5lcy5zcGxpY2UoaW5kZXhPZih0aGlzLmxpbmVzLCBsaW5lKSwgMSk7XG4gICAgaWYgKCF0aGlzLmxpbmVzLmxlbmd0aCAmJiB0aGlzLmRvYy5jbSkge1xuICAgICAgdmFyIG9wID0gdGhpcy5kb2MuY20uY3VyT3BcbiAgICAgIDsob3AubWF5YmVIaWRkZW5NYXJrZXJzIHx8IChvcC5tYXliZUhpZGRlbk1hcmtlcnMgPSBbXSkpLnB1c2godGhpcyk7XG4gICAgfVxuICB9O1xuICBldmVudE1peGluKFRleHRNYXJrZXIpO1xuXG4gIC8vIENyZWF0ZSBhIG1hcmtlciwgd2lyZSBpdCB1cCB0byB0aGUgcmlnaHQgbGluZXMsIGFuZFxuICBmdW5jdGlvbiBtYXJrVGV4dChkb2MsIGZyb20sIHRvLCBvcHRpb25zLCB0eXBlKSB7XG4gICAgLy8gU2hhcmVkIG1hcmtlcnMgKGFjcm9zcyBsaW5rZWQgZG9jdW1lbnRzKSBhcmUgaGFuZGxlZCBzZXBhcmF0ZWx5XG4gICAgLy8gKG1hcmtUZXh0U2hhcmVkIHdpbGwgY2FsbCBvdXQgdG8gdGhpcyBhZ2Fpbiwgb25jZSBwZXJcbiAgICAvLyBkb2N1bWVudCkuXG4gICAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5zaGFyZWQpIHsgcmV0dXJuIG1hcmtUZXh0U2hhcmVkKGRvYywgZnJvbSwgdG8sIG9wdGlvbnMsIHR5cGUpIH1cbiAgICAvLyBFbnN1cmUgd2UgYXJlIGluIGFuIG9wZXJhdGlvbi5cbiAgICBpZiAoZG9jLmNtICYmICFkb2MuY20uY3VyT3ApIHsgcmV0dXJuIG9wZXJhdGlvbihkb2MuY20sIG1hcmtUZXh0KShkb2MsIGZyb20sIHRvLCBvcHRpb25zLCB0eXBlKSB9XG5cbiAgICB2YXIgbWFya2VyID0gbmV3IFRleHRNYXJrZXIoZG9jLCB0eXBlKSwgZGlmZiA9IGNtcChmcm9tLCB0byk7XG4gICAgaWYgKG9wdGlvbnMpIHsgY29weU9iaihvcHRpb25zLCBtYXJrZXIsIGZhbHNlKTsgfVxuICAgIC8vIERvbid0IGNvbm5lY3QgZW1wdHkgbWFya2VycyB1bmxlc3MgY2xlYXJXaGVuRW1wdHkgaXMgZmFsc2VcbiAgICBpZiAoZGlmZiA+IDAgfHwgZGlmZiA9PSAwICYmIG1hcmtlci5jbGVhcldoZW5FbXB0eSAhPT0gZmFsc2UpXG4gICAgICB7IHJldHVybiBtYXJrZXIgfVxuICAgIGlmIChtYXJrZXIucmVwbGFjZWRXaXRoKSB7XG4gICAgICAvLyBTaG93aW5nIHVwIGFzIGEgd2lkZ2V0IGltcGxpZXMgY29sbGFwc2VkICh3aWRnZXQgcmVwbGFjZXMgdGV4dClcbiAgICAgIG1hcmtlci5jb2xsYXBzZWQgPSB0cnVlO1xuICAgICAgbWFya2VyLndpZGdldE5vZGUgPSBlbHRQKFwic3BhblwiLCBbbWFya2VyLnJlcGxhY2VkV2l0aF0sIFwiQ29kZU1pcnJvci13aWRnZXRcIik7XG4gICAgICBpZiAoIW9wdGlvbnMuaGFuZGxlTW91c2VFdmVudHMpIHsgbWFya2VyLndpZGdldE5vZGUuc2V0QXR0cmlidXRlKFwiY20taWdub3JlLWV2ZW50c1wiLCBcInRydWVcIik7IH1cbiAgICAgIGlmIChvcHRpb25zLmluc2VydExlZnQpIHsgbWFya2VyLndpZGdldE5vZGUuaW5zZXJ0TGVmdCA9IHRydWU7IH1cbiAgICB9XG4gICAgaWYgKG1hcmtlci5jb2xsYXBzZWQpIHtcbiAgICAgIGlmIChjb25mbGljdGluZ0NvbGxhcHNlZFJhbmdlKGRvYywgZnJvbS5saW5lLCBmcm9tLCB0bywgbWFya2VyKSB8fFxuICAgICAgICAgIGZyb20ubGluZSAhPSB0by5saW5lICYmIGNvbmZsaWN0aW5nQ29sbGFwc2VkUmFuZ2UoZG9jLCB0by5saW5lLCBmcm9tLCB0bywgbWFya2VyKSlcbiAgICAgICAgeyB0aHJvdyBuZXcgRXJyb3IoXCJJbnNlcnRpbmcgY29sbGFwc2VkIG1hcmtlciBwYXJ0aWFsbHkgb3ZlcmxhcHBpbmcgYW4gZXhpc3Rpbmcgb25lXCIpIH1cbiAgICAgIHNlZUNvbGxhcHNlZFNwYW5zKCk7XG4gICAgfVxuXG4gICAgaWYgKG1hcmtlci5hZGRUb0hpc3RvcnkpXG4gICAgICB7IGFkZENoYW5nZVRvSGlzdG9yeShkb2MsIHtmcm9tOiBmcm9tLCB0bzogdG8sIG9yaWdpbjogXCJtYXJrVGV4dFwifSwgZG9jLnNlbCwgTmFOKTsgfVxuXG4gICAgdmFyIGN1ckxpbmUgPSBmcm9tLmxpbmUsIGNtID0gZG9jLmNtLCB1cGRhdGVNYXhMaW5lO1xuICAgIGRvYy5pdGVyKGN1ckxpbmUsIHRvLmxpbmUgKyAxLCBmdW5jdGlvbiAobGluZSkge1xuICAgICAgaWYgKGNtICYmIG1hcmtlci5jb2xsYXBzZWQgJiYgIWNtLm9wdGlvbnMubGluZVdyYXBwaW5nICYmIHZpc3VhbExpbmUobGluZSkgPT0gY20uZGlzcGxheS5tYXhMaW5lKVxuICAgICAgICB7IHVwZGF0ZU1heExpbmUgPSB0cnVlOyB9XG4gICAgICBpZiAobWFya2VyLmNvbGxhcHNlZCAmJiBjdXJMaW5lICE9IGZyb20ubGluZSkgeyB1cGRhdGVMaW5lSGVpZ2h0KGxpbmUsIDApOyB9XG4gICAgICBhZGRNYXJrZWRTcGFuKGxpbmUsIG5ldyBNYXJrZWRTcGFuKG1hcmtlcixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyTGluZSA9PSBmcm9tLmxpbmUgPyBmcm9tLmNoIDogbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY3VyTGluZSA9PSB0by5saW5lID8gdG8uY2ggOiBudWxsKSk7XG4gICAgICArK2N1ckxpbmU7XG4gICAgfSk7XG4gICAgLy8gbGluZUlzSGlkZGVuIGRlcGVuZHMgb24gdGhlIHByZXNlbmNlIG9mIHRoZSBzcGFucywgc28gbmVlZHMgYSBzZWNvbmQgcGFzc1xuICAgIGlmIChtYXJrZXIuY29sbGFwc2VkKSB7IGRvYy5pdGVyKGZyb20ubGluZSwgdG8ubGluZSArIDEsIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICBpZiAobGluZUlzSGlkZGVuKGRvYywgbGluZSkpIHsgdXBkYXRlTGluZUhlaWdodChsaW5lLCAwKTsgfVxuICAgIH0pOyB9XG5cbiAgICBpZiAobWFya2VyLmNsZWFyT25FbnRlcikgeyBvbihtYXJrZXIsIFwiYmVmb3JlQ3Vyc29yRW50ZXJcIiwgZnVuY3Rpb24gKCkgeyByZXR1cm4gbWFya2VyLmNsZWFyKCk7IH0pOyB9XG5cbiAgICBpZiAobWFya2VyLnJlYWRPbmx5KSB7XG4gICAgICBzZWVSZWFkT25seVNwYW5zKCk7XG4gICAgICBpZiAoZG9jLmhpc3RvcnkuZG9uZS5sZW5ndGggfHwgZG9jLmhpc3RvcnkudW5kb25lLmxlbmd0aClcbiAgICAgICAgeyBkb2MuY2xlYXJIaXN0b3J5KCk7IH1cbiAgICB9XG4gICAgaWYgKG1hcmtlci5jb2xsYXBzZWQpIHtcbiAgICAgIG1hcmtlci5pZCA9ICsrbmV4dE1hcmtlcklkO1xuICAgICAgbWFya2VyLmF0b21pYyA9IHRydWU7XG4gICAgfVxuICAgIGlmIChjbSkge1xuICAgICAgLy8gU3luYyBlZGl0b3Igc3RhdGVcbiAgICAgIGlmICh1cGRhdGVNYXhMaW5lKSB7IGNtLmN1ck9wLnVwZGF0ZU1heExpbmUgPSB0cnVlOyB9XG4gICAgICBpZiAobWFya2VyLmNvbGxhcHNlZClcbiAgICAgICAgeyByZWdDaGFuZ2UoY20sIGZyb20ubGluZSwgdG8ubGluZSArIDEpOyB9XG4gICAgICBlbHNlIGlmIChtYXJrZXIuY2xhc3NOYW1lIHx8IG1hcmtlci5zdGFydFN0eWxlIHx8IG1hcmtlci5lbmRTdHlsZSB8fCBtYXJrZXIuY3NzIHx8XG4gICAgICAgICAgICAgICBtYXJrZXIuYXR0cmlidXRlcyB8fCBtYXJrZXIudGl0bGUpXG4gICAgICAgIHsgZm9yICh2YXIgaSA9IGZyb20ubGluZTsgaSA8PSB0by5saW5lOyBpKyspIHsgcmVnTGluZUNoYW5nZShjbSwgaSwgXCJ0ZXh0XCIpOyB9IH1cbiAgICAgIGlmIChtYXJrZXIuYXRvbWljKSB7IHJlQ2hlY2tTZWxlY3Rpb24oY20uZG9jKTsgfVxuICAgICAgc2lnbmFsTGF0ZXIoY20sIFwibWFya2VyQWRkZWRcIiwgY20sIG1hcmtlcik7XG4gICAgfVxuICAgIHJldHVybiBtYXJrZXJcbiAgfVxuXG4gIC8vIFNIQVJFRCBURVhUTUFSS0VSU1xuXG4gIC8vIEEgc2hhcmVkIG1hcmtlciBzcGFucyBtdWx0aXBsZSBsaW5rZWQgZG9jdW1lbnRzLiBJdCBpc1xuICAvLyBpbXBsZW1lbnRlZCBhcyBhIG1ldGEtbWFya2VyLW9iamVjdCBjb250cm9sbGluZyBtdWx0aXBsZSBub3JtYWxcbiAgLy8gbWFya2Vycy5cbiAgdmFyIFNoYXJlZFRleHRNYXJrZXIgPSBmdW5jdGlvbihtYXJrZXJzLCBwcmltYXJ5KSB7XG4gICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICB0aGlzLm1hcmtlcnMgPSBtYXJrZXJzO1xuICAgIHRoaXMucHJpbWFyeSA9IHByaW1hcnk7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtYXJrZXJzLmxlbmd0aDsgKytpKVxuICAgICAgeyBtYXJrZXJzW2ldLnBhcmVudCA9IHRoaXMkMTsgfVxuICB9O1xuXG4gIFNoYXJlZFRleHRNYXJrZXIucHJvdG90eXBlLmNsZWFyID0gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICBpZiAodGhpcy5leHBsaWNpdGx5Q2xlYXJlZCkgeyByZXR1cm4gfVxuICAgIHRoaXMuZXhwbGljaXRseUNsZWFyZWQgPSB0cnVlO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5tYXJrZXJzLmxlbmd0aDsgKytpKVxuICAgICAgeyB0aGlzJDEubWFya2Vyc1tpXS5jbGVhcigpOyB9XG4gICAgc2lnbmFsTGF0ZXIodGhpcywgXCJjbGVhclwiKTtcbiAgfTtcblxuICBTaGFyZWRUZXh0TWFya2VyLnByb3RvdHlwZS5maW5kID0gZnVuY3Rpb24gKHNpZGUsIGxpbmVPYmopIHtcbiAgICByZXR1cm4gdGhpcy5wcmltYXJ5LmZpbmQoc2lkZSwgbGluZU9iailcbiAgfTtcbiAgZXZlbnRNaXhpbihTaGFyZWRUZXh0TWFya2VyKTtcblxuICBmdW5jdGlvbiBtYXJrVGV4dFNoYXJlZChkb2MsIGZyb20sIHRvLCBvcHRpb25zLCB0eXBlKSB7XG4gICAgb3B0aW9ucyA9IGNvcHlPYmoob3B0aW9ucyk7XG4gICAgb3B0aW9ucy5zaGFyZWQgPSBmYWxzZTtcbiAgICB2YXIgbWFya2VycyA9IFttYXJrVGV4dChkb2MsIGZyb20sIHRvLCBvcHRpb25zLCB0eXBlKV0sIHByaW1hcnkgPSBtYXJrZXJzWzBdO1xuICAgIHZhciB3aWRnZXQgPSBvcHRpb25zLndpZGdldE5vZGU7XG4gICAgbGlua2VkRG9jcyhkb2MsIGZ1bmN0aW9uIChkb2MpIHtcbiAgICAgIGlmICh3aWRnZXQpIHsgb3B0aW9ucy53aWRnZXROb2RlID0gd2lkZ2V0LmNsb25lTm9kZSh0cnVlKTsgfVxuICAgICAgbWFya2Vycy5wdXNoKG1hcmtUZXh0KGRvYywgY2xpcFBvcyhkb2MsIGZyb20pLCBjbGlwUG9zKGRvYywgdG8pLCBvcHRpb25zLCB0eXBlKSk7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGRvYy5saW5rZWQubGVuZ3RoOyArK2kpXG4gICAgICAgIHsgaWYgKGRvYy5saW5rZWRbaV0uaXNQYXJlbnQpIHsgcmV0dXJuIH0gfVxuICAgICAgcHJpbWFyeSA9IGxzdChtYXJrZXJzKTtcbiAgICB9KTtcbiAgICByZXR1cm4gbmV3IFNoYXJlZFRleHRNYXJrZXIobWFya2VycywgcHJpbWFyeSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGZpbmRTaGFyZWRNYXJrZXJzKGRvYykge1xuICAgIHJldHVybiBkb2MuZmluZE1hcmtzKFBvcyhkb2MuZmlyc3QsIDApLCBkb2MuY2xpcFBvcyhQb3MoZG9jLmxhc3RMaW5lKCkpKSwgZnVuY3Rpb24gKG0pIHsgcmV0dXJuIG0ucGFyZW50OyB9KVxuICB9XG5cbiAgZnVuY3Rpb24gY29weVNoYXJlZE1hcmtlcnMoZG9jLCBtYXJrZXJzKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtYXJrZXJzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgbWFya2VyID0gbWFya2Vyc1tpXSwgcG9zID0gbWFya2VyLmZpbmQoKTtcbiAgICAgIHZhciBtRnJvbSA9IGRvYy5jbGlwUG9zKHBvcy5mcm9tKSwgbVRvID0gZG9jLmNsaXBQb3MocG9zLnRvKTtcbiAgICAgIGlmIChjbXAobUZyb20sIG1UbykpIHtcbiAgICAgICAgdmFyIHN1Yk1hcmsgPSBtYXJrVGV4dChkb2MsIG1Gcm9tLCBtVG8sIG1hcmtlci5wcmltYXJ5LCBtYXJrZXIucHJpbWFyeS50eXBlKTtcbiAgICAgICAgbWFya2VyLm1hcmtlcnMucHVzaChzdWJNYXJrKTtcbiAgICAgICAgc3ViTWFyay5wYXJlbnQgPSBtYXJrZXI7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gZGV0YWNoU2hhcmVkTWFya2VycyhtYXJrZXJzKSB7XG4gICAgdmFyIGxvb3AgPSBmdW5jdGlvbiAoIGkgKSB7XG4gICAgICB2YXIgbWFya2VyID0gbWFya2Vyc1tpXSwgbGlua2VkID0gW21hcmtlci5wcmltYXJ5LmRvY107XG4gICAgICBsaW5rZWREb2NzKG1hcmtlci5wcmltYXJ5LmRvYywgZnVuY3Rpb24gKGQpIHsgcmV0dXJuIGxpbmtlZC5wdXNoKGQpOyB9KTtcbiAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbWFya2VyLm1hcmtlcnMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgdmFyIHN1Yk1hcmtlciA9IG1hcmtlci5tYXJrZXJzW2pdO1xuICAgICAgICBpZiAoaW5kZXhPZihsaW5rZWQsIHN1Yk1hcmtlci5kb2MpID09IC0xKSB7XG4gICAgICAgICAgc3ViTWFya2VyLnBhcmVudCA9IG51bGw7XG4gICAgICAgICAgbWFya2VyLm1hcmtlcnMuc3BsaWNlKGotLSwgMSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBtYXJrZXJzLmxlbmd0aDsgaSsrKSBsb29wKCBpICk7XG4gIH1cblxuICB2YXIgbmV4dERvY0lkID0gMDtcbiAgdmFyIERvYyA9IGZ1bmN0aW9uKHRleHQsIG1vZGUsIGZpcnN0TGluZSwgbGluZVNlcCwgZGlyZWN0aW9uKSB7XG4gICAgaWYgKCEodGhpcyBpbnN0YW5jZW9mIERvYykpIHsgcmV0dXJuIG5ldyBEb2ModGV4dCwgbW9kZSwgZmlyc3RMaW5lLCBsaW5lU2VwLCBkaXJlY3Rpb24pIH1cbiAgICBpZiAoZmlyc3RMaW5lID09IG51bGwpIHsgZmlyc3RMaW5lID0gMDsgfVxuXG4gICAgQnJhbmNoQ2h1bmsuY2FsbCh0aGlzLCBbbmV3IExlYWZDaHVuayhbbmV3IExpbmUoXCJcIiwgbnVsbCldKV0pO1xuICAgIHRoaXMuZmlyc3QgPSBmaXJzdExpbmU7XG4gICAgdGhpcy5zY3JvbGxUb3AgPSB0aGlzLnNjcm9sbExlZnQgPSAwO1xuICAgIHRoaXMuY2FudEVkaXQgPSBmYWxzZTtcbiAgICB0aGlzLmNsZWFuR2VuZXJhdGlvbiA9IDE7XG4gICAgdGhpcy5tb2RlRnJvbnRpZXIgPSB0aGlzLmhpZ2hsaWdodEZyb250aWVyID0gZmlyc3RMaW5lO1xuICAgIHZhciBzdGFydCA9IFBvcyhmaXJzdExpbmUsIDApO1xuICAgIHRoaXMuc2VsID0gc2ltcGxlU2VsZWN0aW9uKHN0YXJ0KTtcbiAgICB0aGlzLmhpc3RvcnkgPSBuZXcgSGlzdG9yeShudWxsKTtcbiAgICB0aGlzLmlkID0gKytuZXh0RG9jSWQ7XG4gICAgdGhpcy5tb2RlT3B0aW9uID0gbW9kZTtcbiAgICB0aGlzLmxpbmVTZXAgPSBsaW5lU2VwO1xuICAgIHRoaXMuZGlyZWN0aW9uID0gKGRpcmVjdGlvbiA9PSBcInJ0bFwiKSA/IFwicnRsXCIgOiBcImx0clwiO1xuICAgIHRoaXMuZXh0ZW5kID0gZmFsc2U7XG5cbiAgICBpZiAodHlwZW9mIHRleHQgPT0gXCJzdHJpbmdcIikgeyB0ZXh0ID0gdGhpcy5zcGxpdExpbmVzKHRleHQpOyB9XG4gICAgdXBkYXRlRG9jKHRoaXMsIHtmcm9tOiBzdGFydCwgdG86IHN0YXJ0LCB0ZXh0OiB0ZXh0fSk7XG4gICAgc2V0U2VsZWN0aW9uKHRoaXMsIHNpbXBsZVNlbGVjdGlvbihzdGFydCksIHNlbF9kb250U2Nyb2xsKTtcbiAgfTtcblxuICBEb2MucHJvdG90eXBlID0gY3JlYXRlT2JqKEJyYW5jaENodW5rLnByb3RvdHlwZSwge1xuICAgIGNvbnN0cnVjdG9yOiBEb2MsXG4gICAgLy8gSXRlcmF0ZSBvdmVyIHRoZSBkb2N1bWVudC4gU3VwcG9ydHMgdHdvIGZvcm1zIC0tIHdpdGggb25seSBvbmVcbiAgICAvLyBhcmd1bWVudCwgaXQgY2FsbHMgdGhhdCBmb3IgZWFjaCBsaW5lIGluIHRoZSBkb2N1bWVudC4gV2l0aFxuICAgIC8vIHRocmVlLCBpdCBpdGVyYXRlcyBvdmVyIHRoZSByYW5nZSBnaXZlbiBieSB0aGUgZmlyc3QgdHdvICh3aXRoXG4gICAgLy8gdGhlIHNlY29uZCBiZWluZyBub24taW5jbHVzaXZlKS5cbiAgICBpdGVyOiBmdW5jdGlvbihmcm9tLCB0bywgb3ApIHtcbiAgICAgIGlmIChvcCkgeyB0aGlzLml0ZXJOKGZyb20gLSB0aGlzLmZpcnN0LCB0byAtIGZyb20sIG9wKTsgfVxuICAgICAgZWxzZSB7IHRoaXMuaXRlck4odGhpcy5maXJzdCwgdGhpcy5maXJzdCArIHRoaXMuc2l6ZSwgZnJvbSk7IH1cbiAgICB9LFxuXG4gICAgLy8gTm9uLXB1YmxpYyBpbnRlcmZhY2UgZm9yIGFkZGluZyBhbmQgcmVtb3ZpbmcgbGluZXMuXG4gICAgaW5zZXJ0OiBmdW5jdGlvbihhdCwgbGluZXMpIHtcbiAgICAgIHZhciBoZWlnaHQgPSAwO1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7ICsraSkgeyBoZWlnaHQgKz0gbGluZXNbaV0uaGVpZ2h0OyB9XG4gICAgICB0aGlzLmluc2VydElubmVyKGF0IC0gdGhpcy5maXJzdCwgbGluZXMsIGhlaWdodCk7XG4gICAgfSxcbiAgICByZW1vdmU6IGZ1bmN0aW9uKGF0LCBuKSB7IHRoaXMucmVtb3ZlSW5uZXIoYXQgLSB0aGlzLmZpcnN0LCBuKTsgfSxcblxuICAgIC8vIEZyb20gaGVyZSwgdGhlIG1ldGhvZHMgYXJlIHBhcnQgb2YgdGhlIHB1YmxpYyBpbnRlcmZhY2UuIE1vc3RcbiAgICAvLyBhcmUgYWxzbyBhdmFpbGFibGUgZnJvbSBDb2RlTWlycm9yIChlZGl0b3IpIGluc3RhbmNlcy5cblxuICAgIGdldFZhbHVlOiBmdW5jdGlvbihsaW5lU2VwKSB7XG4gICAgICB2YXIgbGluZXMgPSBnZXRMaW5lcyh0aGlzLCB0aGlzLmZpcnN0LCB0aGlzLmZpcnN0ICsgdGhpcy5zaXplKTtcbiAgICAgIGlmIChsaW5lU2VwID09PSBmYWxzZSkgeyByZXR1cm4gbGluZXMgfVxuICAgICAgcmV0dXJuIGxpbmVzLmpvaW4obGluZVNlcCB8fCB0aGlzLmxpbmVTZXBhcmF0b3IoKSlcbiAgICB9LFxuICAgIHNldFZhbHVlOiBkb2NNZXRob2RPcChmdW5jdGlvbihjb2RlKSB7XG4gICAgICB2YXIgdG9wID0gUG9zKHRoaXMuZmlyc3QsIDApLCBsYXN0ID0gdGhpcy5maXJzdCArIHRoaXMuc2l6ZSAtIDE7XG4gICAgICBtYWtlQ2hhbmdlKHRoaXMsIHtmcm9tOiB0b3AsIHRvOiBQb3MobGFzdCwgZ2V0TGluZSh0aGlzLCBsYXN0KS50ZXh0Lmxlbmd0aCksXG4gICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiB0aGlzLnNwbGl0TGluZXMoY29kZSksIG9yaWdpbjogXCJzZXRWYWx1ZVwiLCBmdWxsOiB0cnVlfSwgdHJ1ZSk7XG4gICAgICBpZiAodGhpcy5jbSkgeyBzY3JvbGxUb0Nvb3Jkcyh0aGlzLmNtLCAwLCAwKTsgfVxuICAgICAgc2V0U2VsZWN0aW9uKHRoaXMsIHNpbXBsZVNlbGVjdGlvbih0b3ApLCBzZWxfZG9udFNjcm9sbCk7XG4gICAgfSksXG4gICAgcmVwbGFjZVJhbmdlOiBmdW5jdGlvbihjb2RlLCBmcm9tLCB0bywgb3JpZ2luKSB7XG4gICAgICBmcm9tID0gY2xpcFBvcyh0aGlzLCBmcm9tKTtcbiAgICAgIHRvID0gdG8gPyBjbGlwUG9zKHRoaXMsIHRvKSA6IGZyb207XG4gICAgICByZXBsYWNlUmFuZ2UodGhpcywgY29kZSwgZnJvbSwgdG8sIG9yaWdpbik7XG4gICAgfSxcbiAgICBnZXRSYW5nZTogZnVuY3Rpb24oZnJvbSwgdG8sIGxpbmVTZXApIHtcbiAgICAgIHZhciBsaW5lcyA9IGdldEJldHdlZW4odGhpcywgY2xpcFBvcyh0aGlzLCBmcm9tKSwgY2xpcFBvcyh0aGlzLCB0bykpO1xuICAgICAgaWYgKGxpbmVTZXAgPT09IGZhbHNlKSB7IHJldHVybiBsaW5lcyB9XG4gICAgICByZXR1cm4gbGluZXMuam9pbihsaW5lU2VwIHx8IHRoaXMubGluZVNlcGFyYXRvcigpKVxuICAgIH0sXG5cbiAgICBnZXRMaW5lOiBmdW5jdGlvbihsaW5lKSB7dmFyIGwgPSB0aGlzLmdldExpbmVIYW5kbGUobGluZSk7IHJldHVybiBsICYmIGwudGV4dH0sXG5cbiAgICBnZXRMaW5lSGFuZGxlOiBmdW5jdGlvbihsaW5lKSB7aWYgKGlzTGluZSh0aGlzLCBsaW5lKSkgeyByZXR1cm4gZ2V0TGluZSh0aGlzLCBsaW5lKSB9fSxcbiAgICBnZXRMaW5lTnVtYmVyOiBmdW5jdGlvbihsaW5lKSB7cmV0dXJuIGxpbmVObyhsaW5lKX0sXG5cbiAgICBnZXRMaW5lSGFuZGxlVmlzdWFsU3RhcnQ6IGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgIGlmICh0eXBlb2YgbGluZSA9PSBcIm51bWJlclwiKSB7IGxpbmUgPSBnZXRMaW5lKHRoaXMsIGxpbmUpOyB9XG4gICAgICByZXR1cm4gdmlzdWFsTGluZShsaW5lKVxuICAgIH0sXG5cbiAgICBsaW5lQ291bnQ6IGZ1bmN0aW9uKCkge3JldHVybiB0aGlzLnNpemV9LFxuICAgIGZpcnN0TGluZTogZnVuY3Rpb24oKSB7cmV0dXJuIHRoaXMuZmlyc3R9LFxuICAgIGxhc3RMaW5lOiBmdW5jdGlvbigpIHtyZXR1cm4gdGhpcy5maXJzdCArIHRoaXMuc2l6ZSAtIDF9LFxuXG4gICAgY2xpcFBvczogZnVuY3Rpb24ocG9zKSB7cmV0dXJuIGNsaXBQb3ModGhpcywgcG9zKX0sXG5cbiAgICBnZXRDdXJzb3I6IGZ1bmN0aW9uKHN0YXJ0KSB7XG4gICAgICB2YXIgcmFuZ2UkJDEgPSB0aGlzLnNlbC5wcmltYXJ5KCksIHBvcztcbiAgICAgIGlmIChzdGFydCA9PSBudWxsIHx8IHN0YXJ0ID09IFwiaGVhZFwiKSB7IHBvcyA9IHJhbmdlJCQxLmhlYWQ7IH1cbiAgICAgIGVsc2UgaWYgKHN0YXJ0ID09IFwiYW5jaG9yXCIpIHsgcG9zID0gcmFuZ2UkJDEuYW5jaG9yOyB9XG4gICAgICBlbHNlIGlmIChzdGFydCA9PSBcImVuZFwiIHx8IHN0YXJ0ID09IFwidG9cIiB8fCBzdGFydCA9PT0gZmFsc2UpIHsgcG9zID0gcmFuZ2UkJDEudG8oKTsgfVxuICAgICAgZWxzZSB7IHBvcyA9IHJhbmdlJCQxLmZyb20oKTsgfVxuICAgICAgcmV0dXJuIHBvc1xuICAgIH0sXG4gICAgbGlzdFNlbGVjdGlvbnM6IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5zZWwucmFuZ2VzIH0sXG4gICAgc29tZXRoaW5nU2VsZWN0ZWQ6IGZ1bmN0aW9uKCkge3JldHVybiB0aGlzLnNlbC5zb21ldGhpbmdTZWxlY3RlZCgpfSxcblxuICAgIHNldEN1cnNvcjogZG9jTWV0aG9kT3AoZnVuY3Rpb24obGluZSwgY2gsIG9wdGlvbnMpIHtcbiAgICAgIHNldFNpbXBsZVNlbGVjdGlvbih0aGlzLCBjbGlwUG9zKHRoaXMsIHR5cGVvZiBsaW5lID09IFwibnVtYmVyXCIgPyBQb3MobGluZSwgY2ggfHwgMCkgOiBsaW5lKSwgbnVsbCwgb3B0aW9ucyk7XG4gICAgfSksXG4gICAgc2V0U2VsZWN0aW9uOiBkb2NNZXRob2RPcChmdW5jdGlvbihhbmNob3IsIGhlYWQsIG9wdGlvbnMpIHtcbiAgICAgIHNldFNpbXBsZVNlbGVjdGlvbih0aGlzLCBjbGlwUG9zKHRoaXMsIGFuY2hvciksIGNsaXBQb3ModGhpcywgaGVhZCB8fCBhbmNob3IpLCBvcHRpb25zKTtcbiAgICB9KSxcbiAgICBleHRlbmRTZWxlY3Rpb246IGRvY01ldGhvZE9wKGZ1bmN0aW9uKGhlYWQsIG90aGVyLCBvcHRpb25zKSB7XG4gICAgICBleHRlbmRTZWxlY3Rpb24odGhpcywgY2xpcFBvcyh0aGlzLCBoZWFkKSwgb3RoZXIgJiYgY2xpcFBvcyh0aGlzLCBvdGhlciksIG9wdGlvbnMpO1xuICAgIH0pLFxuICAgIGV4dGVuZFNlbGVjdGlvbnM6IGRvY01ldGhvZE9wKGZ1bmN0aW9uKGhlYWRzLCBvcHRpb25zKSB7XG4gICAgICBleHRlbmRTZWxlY3Rpb25zKHRoaXMsIGNsaXBQb3NBcnJheSh0aGlzLCBoZWFkcyksIG9wdGlvbnMpO1xuICAgIH0pLFxuICAgIGV4dGVuZFNlbGVjdGlvbnNCeTogZG9jTWV0aG9kT3AoZnVuY3Rpb24oZiwgb3B0aW9ucykge1xuICAgICAgdmFyIGhlYWRzID0gbWFwKHRoaXMuc2VsLnJhbmdlcywgZik7XG4gICAgICBleHRlbmRTZWxlY3Rpb25zKHRoaXMsIGNsaXBQb3NBcnJheSh0aGlzLCBoZWFkcyksIG9wdGlvbnMpO1xuICAgIH0pLFxuICAgIHNldFNlbGVjdGlvbnM6IGRvY01ldGhvZE9wKGZ1bmN0aW9uKHJhbmdlcywgcHJpbWFyeSwgb3B0aW9ucykge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICAgIGlmICghcmFuZ2VzLmxlbmd0aCkgeyByZXR1cm4gfVxuICAgICAgdmFyIG91dCA9IFtdO1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByYW5nZXMubGVuZ3RoOyBpKyspXG4gICAgICAgIHsgb3V0W2ldID0gbmV3IFJhbmdlKGNsaXBQb3ModGhpcyQxLCByYW5nZXNbaV0uYW5jaG9yKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgIGNsaXBQb3ModGhpcyQxLCByYW5nZXNbaV0uaGVhZCkpOyB9XG4gICAgICBpZiAocHJpbWFyeSA9PSBudWxsKSB7IHByaW1hcnkgPSBNYXRoLm1pbihyYW5nZXMubGVuZ3RoIC0gMSwgdGhpcy5zZWwucHJpbUluZGV4KTsgfVxuICAgICAgc2V0U2VsZWN0aW9uKHRoaXMsIG5vcm1hbGl6ZVNlbGVjdGlvbih0aGlzLmNtLCBvdXQsIHByaW1hcnkpLCBvcHRpb25zKTtcbiAgICB9KSxcbiAgICBhZGRTZWxlY3Rpb246IGRvY01ldGhvZE9wKGZ1bmN0aW9uKGFuY2hvciwgaGVhZCwgb3B0aW9ucykge1xuICAgICAgdmFyIHJhbmdlcyA9IHRoaXMuc2VsLnJhbmdlcy5zbGljZSgwKTtcbiAgICAgIHJhbmdlcy5wdXNoKG5ldyBSYW5nZShjbGlwUG9zKHRoaXMsIGFuY2hvciksIGNsaXBQb3ModGhpcywgaGVhZCB8fCBhbmNob3IpKSk7XG4gICAgICBzZXRTZWxlY3Rpb24odGhpcywgbm9ybWFsaXplU2VsZWN0aW9uKHRoaXMuY20sIHJhbmdlcywgcmFuZ2VzLmxlbmd0aCAtIDEpLCBvcHRpb25zKTtcbiAgICB9KSxcblxuICAgIGdldFNlbGVjdGlvbjogZnVuY3Rpb24obGluZVNlcCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICAgIHZhciByYW5nZXMgPSB0aGlzLnNlbC5yYW5nZXMsIGxpbmVzO1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByYW5nZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHNlbCA9IGdldEJldHdlZW4odGhpcyQxLCByYW5nZXNbaV0uZnJvbSgpLCByYW5nZXNbaV0udG8oKSk7XG4gICAgICAgIGxpbmVzID0gbGluZXMgPyBsaW5lcy5jb25jYXQoc2VsKSA6IHNlbDtcbiAgICAgIH1cbiAgICAgIGlmIChsaW5lU2VwID09PSBmYWxzZSkgeyByZXR1cm4gbGluZXMgfVxuICAgICAgZWxzZSB7IHJldHVybiBsaW5lcy5qb2luKGxpbmVTZXAgfHwgdGhpcy5saW5lU2VwYXJhdG9yKCkpIH1cbiAgICB9LFxuICAgIGdldFNlbGVjdGlvbnM6IGZ1bmN0aW9uKGxpbmVTZXApIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgICB2YXIgcGFydHMgPSBbXSwgcmFuZ2VzID0gdGhpcy5zZWwucmFuZ2VzO1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByYW5nZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHNlbCA9IGdldEJldHdlZW4odGhpcyQxLCByYW5nZXNbaV0uZnJvbSgpLCByYW5nZXNbaV0udG8oKSk7XG4gICAgICAgIGlmIChsaW5lU2VwICE9PSBmYWxzZSkgeyBzZWwgPSBzZWwuam9pbihsaW5lU2VwIHx8IHRoaXMkMS5saW5lU2VwYXJhdG9yKCkpOyB9XG4gICAgICAgIHBhcnRzW2ldID0gc2VsO1xuICAgICAgfVxuICAgICAgcmV0dXJuIHBhcnRzXG4gICAgfSxcbiAgICByZXBsYWNlU2VsZWN0aW9uOiBmdW5jdGlvbihjb2RlLCBjb2xsYXBzZSwgb3JpZ2luKSB7XG4gICAgICB2YXIgZHVwID0gW107XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuc2VsLnJhbmdlcy5sZW5ndGg7IGkrKylcbiAgICAgICAgeyBkdXBbaV0gPSBjb2RlOyB9XG4gICAgICB0aGlzLnJlcGxhY2VTZWxlY3Rpb25zKGR1cCwgY29sbGFwc2UsIG9yaWdpbiB8fCBcIitpbnB1dFwiKTtcbiAgICB9LFxuICAgIHJlcGxhY2VTZWxlY3Rpb25zOiBkb2NNZXRob2RPcChmdW5jdGlvbihjb2RlLCBjb2xsYXBzZSwgb3JpZ2luKSB7XG4gICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgICAgdmFyIGNoYW5nZXMgPSBbXSwgc2VsID0gdGhpcy5zZWw7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbC5yYW5nZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHJhbmdlJCQxID0gc2VsLnJhbmdlc1tpXTtcbiAgICAgICAgY2hhbmdlc1tpXSA9IHtmcm9tOiByYW5nZSQkMS5mcm9tKCksIHRvOiByYW5nZSQkMS50bygpLCB0ZXh0OiB0aGlzJDEuc3BsaXRMaW5lcyhjb2RlW2ldKSwgb3JpZ2luOiBvcmlnaW59O1xuICAgICAgfVxuICAgICAgdmFyIG5ld1NlbCA9IGNvbGxhcHNlICYmIGNvbGxhcHNlICE9IFwiZW5kXCIgJiYgY29tcHV0ZVJlcGxhY2VkU2VsKHRoaXMsIGNoYW5nZXMsIGNvbGxhcHNlKTtcbiAgICAgIGZvciAodmFyIGkkMSA9IGNoYW5nZXMubGVuZ3RoIC0gMTsgaSQxID49IDA7IGkkMS0tKVxuICAgICAgICB7IG1ha2VDaGFuZ2UodGhpcyQxLCBjaGFuZ2VzW2kkMV0pOyB9XG4gICAgICBpZiAobmV3U2VsKSB7IHNldFNlbGVjdGlvblJlcGxhY2VIaXN0b3J5KHRoaXMsIG5ld1NlbCk7IH1cbiAgICAgIGVsc2UgaWYgKHRoaXMuY20pIHsgZW5zdXJlQ3Vyc29yVmlzaWJsZSh0aGlzLmNtKTsgfVxuICAgIH0pLFxuICAgIHVuZG86IGRvY01ldGhvZE9wKGZ1bmN0aW9uKCkge21ha2VDaGFuZ2VGcm9tSGlzdG9yeSh0aGlzLCBcInVuZG9cIik7fSksXG4gICAgcmVkbzogZG9jTWV0aG9kT3AoZnVuY3Rpb24oKSB7bWFrZUNoYW5nZUZyb21IaXN0b3J5KHRoaXMsIFwicmVkb1wiKTt9KSxcbiAgICB1bmRvU2VsZWN0aW9uOiBkb2NNZXRob2RPcChmdW5jdGlvbigpIHttYWtlQ2hhbmdlRnJvbUhpc3RvcnkodGhpcywgXCJ1bmRvXCIsIHRydWUpO30pLFxuICAgIHJlZG9TZWxlY3Rpb246IGRvY01ldGhvZE9wKGZ1bmN0aW9uKCkge21ha2VDaGFuZ2VGcm9tSGlzdG9yeSh0aGlzLCBcInJlZG9cIiwgdHJ1ZSk7fSksXG5cbiAgICBzZXRFeHRlbmRpbmc6IGZ1bmN0aW9uKHZhbCkge3RoaXMuZXh0ZW5kID0gdmFsO30sXG4gICAgZ2V0RXh0ZW5kaW5nOiBmdW5jdGlvbigpIHtyZXR1cm4gdGhpcy5leHRlbmR9LFxuXG4gICAgaGlzdG9yeVNpemU6IGZ1bmN0aW9uKCkge1xuICAgICAgdmFyIGhpc3QgPSB0aGlzLmhpc3RvcnksIGRvbmUgPSAwLCB1bmRvbmUgPSAwO1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBoaXN0LmRvbmUubGVuZ3RoOyBpKyspIHsgaWYgKCFoaXN0LmRvbmVbaV0ucmFuZ2VzKSB7ICsrZG9uZTsgfSB9XG4gICAgICBmb3IgKHZhciBpJDEgPSAwOyBpJDEgPCBoaXN0LnVuZG9uZS5sZW5ndGg7IGkkMSsrKSB7IGlmICghaGlzdC51bmRvbmVbaSQxXS5yYW5nZXMpIHsgKyt1bmRvbmU7IH0gfVxuICAgICAgcmV0dXJuIHt1bmRvOiBkb25lLCByZWRvOiB1bmRvbmV9XG4gICAgfSxcbiAgICBjbGVhckhpc3Rvcnk6IGZ1bmN0aW9uKCkge3RoaXMuaGlzdG9yeSA9IG5ldyBIaXN0b3J5KHRoaXMuaGlzdG9yeS5tYXhHZW5lcmF0aW9uKTt9LFxuXG4gICAgbWFya0NsZWFuOiBmdW5jdGlvbigpIHtcbiAgICAgIHRoaXMuY2xlYW5HZW5lcmF0aW9uID0gdGhpcy5jaGFuZ2VHZW5lcmF0aW9uKHRydWUpO1xuICAgIH0sXG4gICAgY2hhbmdlR2VuZXJhdGlvbjogZnVuY3Rpb24oZm9yY2VTcGxpdCkge1xuICAgICAgaWYgKGZvcmNlU3BsaXQpXG4gICAgICAgIHsgdGhpcy5oaXN0b3J5Lmxhc3RPcCA9IHRoaXMuaGlzdG9yeS5sYXN0U2VsT3AgPSB0aGlzLmhpc3RvcnkubGFzdE9yaWdpbiA9IG51bGw7IH1cbiAgICAgIHJldHVybiB0aGlzLmhpc3RvcnkuZ2VuZXJhdGlvblxuICAgIH0sXG4gICAgaXNDbGVhbjogZnVuY3Rpb24gKGdlbikge1xuICAgICAgcmV0dXJuIHRoaXMuaGlzdG9yeS5nZW5lcmF0aW9uID09IChnZW4gfHwgdGhpcy5jbGVhbkdlbmVyYXRpb24pXG4gICAgfSxcblxuICAgIGdldEhpc3Rvcnk6IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHtkb25lOiBjb3B5SGlzdG9yeUFycmF5KHRoaXMuaGlzdG9yeS5kb25lKSxcbiAgICAgICAgICAgICAgdW5kb25lOiBjb3B5SGlzdG9yeUFycmF5KHRoaXMuaGlzdG9yeS51bmRvbmUpfVxuICAgIH0sXG4gICAgc2V0SGlzdG9yeTogZnVuY3Rpb24oaGlzdERhdGEpIHtcbiAgICAgIHZhciBoaXN0ID0gdGhpcy5oaXN0b3J5ID0gbmV3IEhpc3RvcnkodGhpcy5oaXN0b3J5Lm1heEdlbmVyYXRpb24pO1xuICAgICAgaGlzdC5kb25lID0gY29weUhpc3RvcnlBcnJheShoaXN0RGF0YS5kb25lLnNsaWNlKDApLCBudWxsLCB0cnVlKTtcbiAgICAgIGhpc3QudW5kb25lID0gY29weUhpc3RvcnlBcnJheShoaXN0RGF0YS51bmRvbmUuc2xpY2UoMCksIG51bGwsIHRydWUpO1xuICAgIH0sXG5cbiAgICBzZXRHdXR0ZXJNYXJrZXI6IGRvY01ldGhvZE9wKGZ1bmN0aW9uKGxpbmUsIGd1dHRlcklELCB2YWx1ZSkge1xuICAgICAgcmV0dXJuIGNoYW5nZUxpbmUodGhpcywgbGluZSwgXCJndXR0ZXJcIiwgZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIG1hcmtlcnMgPSBsaW5lLmd1dHRlck1hcmtlcnMgfHwgKGxpbmUuZ3V0dGVyTWFya2VycyA9IHt9KTtcbiAgICAgICAgbWFya2Vyc1tndXR0ZXJJRF0gPSB2YWx1ZTtcbiAgICAgICAgaWYgKCF2YWx1ZSAmJiBpc0VtcHR5KG1hcmtlcnMpKSB7IGxpbmUuZ3V0dGVyTWFya2VycyA9IG51bGw7IH1cbiAgICAgICAgcmV0dXJuIHRydWVcbiAgICAgIH0pXG4gICAgfSksXG5cbiAgICBjbGVhckd1dHRlcjogZG9jTWV0aG9kT3AoZnVuY3Rpb24oZ3V0dGVySUQpIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgICB0aGlzLml0ZXIoZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgaWYgKGxpbmUuZ3V0dGVyTWFya2VycyAmJiBsaW5lLmd1dHRlck1hcmtlcnNbZ3V0dGVySURdKSB7XG4gICAgICAgICAgY2hhbmdlTGluZSh0aGlzJDEsIGxpbmUsIFwiZ3V0dGVyXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGxpbmUuZ3V0dGVyTWFya2Vyc1tndXR0ZXJJRF0gPSBudWxsO1xuICAgICAgICAgICAgaWYgKGlzRW1wdHkobGluZS5ndXR0ZXJNYXJrZXJzKSkgeyBsaW5lLmd1dHRlck1hcmtlcnMgPSBudWxsOyB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZVxuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9KTtcbiAgICB9KSxcblxuICAgIGxpbmVJbmZvOiBmdW5jdGlvbihsaW5lKSB7XG4gICAgICB2YXIgbjtcbiAgICAgIGlmICh0eXBlb2YgbGluZSA9PSBcIm51bWJlclwiKSB7XG4gICAgICAgIGlmICghaXNMaW5lKHRoaXMsIGxpbmUpKSB7IHJldHVybiBudWxsIH1cbiAgICAgICAgbiA9IGxpbmU7XG4gICAgICAgIGxpbmUgPSBnZXRMaW5lKHRoaXMsIGxpbmUpO1xuICAgICAgICBpZiAoIWxpbmUpIHsgcmV0dXJuIG51bGwgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbiA9IGxpbmVObyhsaW5lKTtcbiAgICAgICAgaWYgKG4gPT0gbnVsbCkgeyByZXR1cm4gbnVsbCB9XG4gICAgICB9XG4gICAgICByZXR1cm4ge2xpbmU6IG4sIGhhbmRsZTogbGluZSwgdGV4dDogbGluZS50ZXh0LCBndXR0ZXJNYXJrZXJzOiBsaW5lLmd1dHRlck1hcmtlcnMsXG4gICAgICAgICAgICAgIHRleHRDbGFzczogbGluZS50ZXh0Q2xhc3MsIGJnQ2xhc3M6IGxpbmUuYmdDbGFzcywgd3JhcENsYXNzOiBsaW5lLndyYXBDbGFzcyxcbiAgICAgICAgICAgICAgd2lkZ2V0czogbGluZS53aWRnZXRzfVxuICAgIH0sXG5cbiAgICBhZGRMaW5lQ2xhc3M6IGRvY01ldGhvZE9wKGZ1bmN0aW9uKGhhbmRsZSwgd2hlcmUsIGNscykge1xuICAgICAgcmV0dXJuIGNoYW5nZUxpbmUodGhpcywgaGFuZGxlLCB3aGVyZSA9PSBcImd1dHRlclwiID8gXCJndXR0ZXJcIiA6IFwiY2xhc3NcIiwgZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIHByb3AgPSB3aGVyZSA9PSBcInRleHRcIiA/IFwidGV4dENsYXNzXCJcbiAgICAgICAgICAgICAgICAgOiB3aGVyZSA9PSBcImJhY2tncm91bmRcIiA/IFwiYmdDbGFzc1wiXG4gICAgICAgICAgICAgICAgIDogd2hlcmUgPT0gXCJndXR0ZXJcIiA/IFwiZ3V0dGVyQ2xhc3NcIiA6IFwid3JhcENsYXNzXCI7XG4gICAgICAgIGlmICghbGluZVtwcm9wXSkgeyBsaW5lW3Byb3BdID0gY2xzOyB9XG4gICAgICAgIGVsc2UgaWYgKGNsYXNzVGVzdChjbHMpLnRlc3QobGluZVtwcm9wXSkpIHsgcmV0dXJuIGZhbHNlIH1cbiAgICAgICAgZWxzZSB7IGxpbmVbcHJvcF0gKz0gXCIgXCIgKyBjbHM7IH1cbiAgICAgICAgcmV0dXJuIHRydWVcbiAgICAgIH0pXG4gICAgfSksXG4gICAgcmVtb3ZlTGluZUNsYXNzOiBkb2NNZXRob2RPcChmdW5jdGlvbihoYW5kbGUsIHdoZXJlLCBjbHMpIHtcbiAgICAgIHJldHVybiBjaGFuZ2VMaW5lKHRoaXMsIGhhbmRsZSwgd2hlcmUgPT0gXCJndXR0ZXJcIiA/IFwiZ3V0dGVyXCIgOiBcImNsYXNzXCIsIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHZhciBwcm9wID0gd2hlcmUgPT0gXCJ0ZXh0XCIgPyBcInRleHRDbGFzc1wiXG4gICAgICAgICAgICAgICAgIDogd2hlcmUgPT0gXCJiYWNrZ3JvdW5kXCIgPyBcImJnQ2xhc3NcIlxuICAgICAgICAgICAgICAgICA6IHdoZXJlID09IFwiZ3V0dGVyXCIgPyBcImd1dHRlckNsYXNzXCIgOiBcIndyYXBDbGFzc1wiO1xuICAgICAgICB2YXIgY3VyID0gbGluZVtwcm9wXTtcbiAgICAgICAgaWYgKCFjdXIpIHsgcmV0dXJuIGZhbHNlIH1cbiAgICAgICAgZWxzZSBpZiAoY2xzID09IG51bGwpIHsgbGluZVtwcm9wXSA9IG51bGw7IH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgdmFyIGZvdW5kID0gY3VyLm1hdGNoKGNsYXNzVGVzdChjbHMpKTtcbiAgICAgICAgICBpZiAoIWZvdW5kKSB7IHJldHVybiBmYWxzZSB9XG4gICAgICAgICAgdmFyIGVuZCA9IGZvdW5kLmluZGV4ICsgZm91bmRbMF0ubGVuZ3RoO1xuICAgICAgICAgIGxpbmVbcHJvcF0gPSBjdXIuc2xpY2UoMCwgZm91bmQuaW5kZXgpICsgKCFmb3VuZC5pbmRleCB8fCBlbmQgPT0gY3VyLmxlbmd0aCA/IFwiXCIgOiBcIiBcIikgKyBjdXIuc2xpY2UoZW5kKSB8fCBudWxsO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiB0cnVlXG4gICAgICB9KVxuICAgIH0pLFxuXG4gICAgYWRkTGluZVdpZGdldDogZG9jTWV0aG9kT3AoZnVuY3Rpb24oaGFuZGxlLCBub2RlLCBvcHRpb25zKSB7XG4gICAgICByZXR1cm4gYWRkTGluZVdpZGdldCh0aGlzLCBoYW5kbGUsIG5vZGUsIG9wdGlvbnMpXG4gICAgfSksXG4gICAgcmVtb3ZlTGluZVdpZGdldDogZnVuY3Rpb24od2lkZ2V0KSB7IHdpZGdldC5jbGVhcigpOyB9LFxuXG4gICAgbWFya1RleHQ6IGZ1bmN0aW9uKGZyb20sIHRvLCBvcHRpb25zKSB7XG4gICAgICByZXR1cm4gbWFya1RleHQodGhpcywgY2xpcFBvcyh0aGlzLCBmcm9tKSwgY2xpcFBvcyh0aGlzLCB0byksIG9wdGlvbnMsIG9wdGlvbnMgJiYgb3B0aW9ucy50eXBlIHx8IFwicmFuZ2VcIilcbiAgICB9LFxuICAgIHNldEJvb2ttYXJrOiBmdW5jdGlvbihwb3MsIG9wdGlvbnMpIHtcbiAgICAgIHZhciByZWFsT3B0cyA9IHtyZXBsYWNlZFdpdGg6IG9wdGlvbnMgJiYgKG9wdGlvbnMubm9kZVR5cGUgPT0gbnVsbCA/IG9wdGlvbnMud2lkZ2V0IDogb3B0aW9ucyksXG4gICAgICAgICAgICAgICAgICAgICAgaW5zZXJ0TGVmdDogb3B0aW9ucyAmJiBvcHRpb25zLmluc2VydExlZnQsXG4gICAgICAgICAgICAgICAgICAgICAgY2xlYXJXaGVuRW1wdHk6IGZhbHNlLCBzaGFyZWQ6IG9wdGlvbnMgJiYgb3B0aW9ucy5zaGFyZWQsXG4gICAgICAgICAgICAgICAgICAgICAgaGFuZGxlTW91c2VFdmVudHM6IG9wdGlvbnMgJiYgb3B0aW9ucy5oYW5kbGVNb3VzZUV2ZW50c307XG4gICAgICBwb3MgPSBjbGlwUG9zKHRoaXMsIHBvcyk7XG4gICAgICByZXR1cm4gbWFya1RleHQodGhpcywgcG9zLCBwb3MsIHJlYWxPcHRzLCBcImJvb2ttYXJrXCIpXG4gICAgfSxcbiAgICBmaW5kTWFya3NBdDogZnVuY3Rpb24ocG9zKSB7XG4gICAgICBwb3MgPSBjbGlwUG9zKHRoaXMsIHBvcyk7XG4gICAgICB2YXIgbWFya2VycyA9IFtdLCBzcGFucyA9IGdldExpbmUodGhpcywgcG9zLmxpbmUpLm1hcmtlZFNwYW5zO1xuICAgICAgaWYgKHNwYW5zKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgc3BhbnMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdmFyIHNwYW4gPSBzcGFuc1tpXTtcbiAgICAgICAgaWYgKChzcGFuLmZyb20gPT0gbnVsbCB8fCBzcGFuLmZyb20gPD0gcG9zLmNoKSAmJlxuICAgICAgICAgICAgKHNwYW4udG8gPT0gbnVsbCB8fCBzcGFuLnRvID49IHBvcy5jaCkpXG4gICAgICAgICAgeyBtYXJrZXJzLnB1c2goc3Bhbi5tYXJrZXIucGFyZW50IHx8IHNwYW4ubWFya2VyKTsgfVxuICAgICAgfSB9XG4gICAgICByZXR1cm4gbWFya2Vyc1xuICAgIH0sXG4gICAgZmluZE1hcmtzOiBmdW5jdGlvbihmcm9tLCB0bywgZmlsdGVyKSB7XG4gICAgICBmcm9tID0gY2xpcFBvcyh0aGlzLCBmcm9tKTsgdG8gPSBjbGlwUG9zKHRoaXMsIHRvKTtcbiAgICAgIHZhciBmb3VuZCA9IFtdLCBsaW5lTm8kJDEgPSBmcm9tLmxpbmU7XG4gICAgICB0aGlzLml0ZXIoZnJvbS5saW5lLCB0by5saW5lICsgMSwgZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIHNwYW5zID0gbGluZS5tYXJrZWRTcGFucztcbiAgICAgICAgaWYgKHNwYW5zKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgc3BhbnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgc3BhbiA9IHNwYW5zW2ldO1xuICAgICAgICAgIGlmICghKHNwYW4udG8gIT0gbnVsbCAmJiBsaW5lTm8kJDEgPT0gZnJvbS5saW5lICYmIGZyb20uY2ggPj0gc3Bhbi50byB8fFxuICAgICAgICAgICAgICAgIHNwYW4uZnJvbSA9PSBudWxsICYmIGxpbmVObyQkMSAhPSBmcm9tLmxpbmUgfHxcbiAgICAgICAgICAgICAgICBzcGFuLmZyb20gIT0gbnVsbCAmJiBsaW5lTm8kJDEgPT0gdG8ubGluZSAmJiBzcGFuLmZyb20gPj0gdG8uY2gpICYmXG4gICAgICAgICAgICAgICghZmlsdGVyIHx8IGZpbHRlcihzcGFuLm1hcmtlcikpKVxuICAgICAgICAgICAgeyBmb3VuZC5wdXNoKHNwYW4ubWFya2VyLnBhcmVudCB8fCBzcGFuLm1hcmtlcik7IH1cbiAgICAgICAgfSB9XG4gICAgICAgICsrbGluZU5vJCQxO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gZm91bmRcbiAgICB9LFxuICAgIGdldEFsbE1hcmtzOiBmdW5jdGlvbigpIHtcbiAgICAgIHZhciBtYXJrZXJzID0gW107XG4gICAgICB0aGlzLml0ZXIoZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIHNwcyA9IGxpbmUubWFya2VkU3BhbnM7XG4gICAgICAgIGlmIChzcHMpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCBzcHMubGVuZ3RoOyArK2kpXG4gICAgICAgICAgeyBpZiAoc3BzW2ldLmZyb20gIT0gbnVsbCkgeyBtYXJrZXJzLnB1c2goc3BzW2ldLm1hcmtlcik7IH0gfSB9XG4gICAgICB9KTtcbiAgICAgIHJldHVybiBtYXJrZXJzXG4gICAgfSxcblxuICAgIHBvc0Zyb21JbmRleDogZnVuY3Rpb24ob2ZmKSB7XG4gICAgICB2YXIgY2gsIGxpbmVObyQkMSA9IHRoaXMuZmlyc3QsIHNlcFNpemUgPSB0aGlzLmxpbmVTZXBhcmF0b3IoKS5sZW5ndGg7XG4gICAgICB0aGlzLml0ZXIoZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIHN6ID0gbGluZS50ZXh0Lmxlbmd0aCArIHNlcFNpemU7XG4gICAgICAgIGlmIChzeiA+IG9mZikgeyBjaCA9IG9mZjsgcmV0dXJuIHRydWUgfVxuICAgICAgICBvZmYgLT0gc3o7XG4gICAgICAgICsrbGluZU5vJCQxO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gY2xpcFBvcyh0aGlzLCBQb3MobGluZU5vJCQxLCBjaCkpXG4gICAgfSxcbiAgICBpbmRleEZyb21Qb3M6IGZ1bmN0aW9uIChjb29yZHMpIHtcbiAgICAgIGNvb3JkcyA9IGNsaXBQb3ModGhpcywgY29vcmRzKTtcbiAgICAgIHZhciBpbmRleCA9IGNvb3Jkcy5jaDtcbiAgICAgIGlmIChjb29yZHMubGluZSA8IHRoaXMuZmlyc3QgfHwgY29vcmRzLmNoIDwgMCkgeyByZXR1cm4gMCB9XG4gICAgICB2YXIgc2VwU2l6ZSA9IHRoaXMubGluZVNlcGFyYXRvcigpLmxlbmd0aDtcbiAgICAgIHRoaXMuaXRlcih0aGlzLmZpcnN0LCBjb29yZHMubGluZSwgZnVuY3Rpb24gKGxpbmUpIHsgLy8gaXRlciBhYm9ydHMgd2hlbiBjYWxsYmFjayByZXR1cm5zIGEgdHJ1dGh5IHZhbHVlXG4gICAgICAgIGluZGV4ICs9IGxpbmUudGV4dC5sZW5ndGggKyBzZXBTaXplO1xuICAgICAgfSk7XG4gICAgICByZXR1cm4gaW5kZXhcbiAgICB9LFxuXG4gICAgY29weTogZnVuY3Rpb24oY29weUhpc3RvcnkpIHtcbiAgICAgIHZhciBkb2MgPSBuZXcgRG9jKGdldExpbmVzKHRoaXMsIHRoaXMuZmlyc3QsIHRoaXMuZmlyc3QgKyB0aGlzLnNpemUpLFxuICAgICAgICAgICAgICAgICAgICAgICAgdGhpcy5tb2RlT3B0aW9uLCB0aGlzLmZpcnN0LCB0aGlzLmxpbmVTZXAsIHRoaXMuZGlyZWN0aW9uKTtcbiAgICAgIGRvYy5zY3JvbGxUb3AgPSB0aGlzLnNjcm9sbFRvcDsgZG9jLnNjcm9sbExlZnQgPSB0aGlzLnNjcm9sbExlZnQ7XG4gICAgICBkb2Muc2VsID0gdGhpcy5zZWw7XG4gICAgICBkb2MuZXh0ZW5kID0gZmFsc2U7XG4gICAgICBpZiAoY29weUhpc3RvcnkpIHtcbiAgICAgICAgZG9jLmhpc3RvcnkudW5kb0RlcHRoID0gdGhpcy5oaXN0b3J5LnVuZG9EZXB0aDtcbiAgICAgICAgZG9jLnNldEhpc3RvcnkodGhpcy5nZXRIaXN0b3J5KCkpO1xuICAgICAgfVxuICAgICAgcmV0dXJuIGRvY1xuICAgIH0sXG5cbiAgICBsaW5rZWREb2M6IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICAgIGlmICghb3B0aW9ucykgeyBvcHRpb25zID0ge307IH1cbiAgICAgIHZhciBmcm9tID0gdGhpcy5maXJzdCwgdG8gPSB0aGlzLmZpcnN0ICsgdGhpcy5zaXplO1xuICAgICAgaWYgKG9wdGlvbnMuZnJvbSAhPSBudWxsICYmIG9wdGlvbnMuZnJvbSA+IGZyb20pIHsgZnJvbSA9IG9wdGlvbnMuZnJvbTsgfVxuICAgICAgaWYgKG9wdGlvbnMudG8gIT0gbnVsbCAmJiBvcHRpb25zLnRvIDwgdG8pIHsgdG8gPSBvcHRpb25zLnRvOyB9XG4gICAgICB2YXIgY29weSA9IG5ldyBEb2MoZ2V0TGluZXModGhpcywgZnJvbSwgdG8pLCBvcHRpb25zLm1vZGUgfHwgdGhpcy5tb2RlT3B0aW9uLCBmcm9tLCB0aGlzLmxpbmVTZXAsIHRoaXMuZGlyZWN0aW9uKTtcbiAgICAgIGlmIChvcHRpb25zLnNoYXJlZEhpc3QpIHsgY29weS5oaXN0b3J5ID0gdGhpcy5oaXN0b3J5XG4gICAgICA7IH0odGhpcy5saW5rZWQgfHwgKHRoaXMubGlua2VkID0gW10pKS5wdXNoKHtkb2M6IGNvcHksIHNoYXJlZEhpc3Q6IG9wdGlvbnMuc2hhcmVkSGlzdH0pO1xuICAgICAgY29weS5saW5rZWQgPSBbe2RvYzogdGhpcywgaXNQYXJlbnQ6IHRydWUsIHNoYXJlZEhpc3Q6IG9wdGlvbnMuc2hhcmVkSGlzdH1dO1xuICAgICAgY29weVNoYXJlZE1hcmtlcnMoY29weSwgZmluZFNoYXJlZE1hcmtlcnModGhpcykpO1xuICAgICAgcmV0dXJuIGNvcHlcbiAgICB9LFxuICAgIHVubGlua0RvYzogZnVuY3Rpb24ob3RoZXIpIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgICBpZiAob3RoZXIgaW5zdGFuY2VvZiBDb2RlTWlycm9yKSB7IG90aGVyID0gb3RoZXIuZG9jOyB9XG4gICAgICBpZiAodGhpcy5saW5rZWQpIHsgZm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLmxpbmtlZC5sZW5ndGg7ICsraSkge1xuICAgICAgICB2YXIgbGluayA9IHRoaXMkMS5saW5rZWRbaV07XG4gICAgICAgIGlmIChsaW5rLmRvYyAhPSBvdGhlcikgeyBjb250aW51ZSB9XG4gICAgICAgIHRoaXMkMS5saW5rZWQuc3BsaWNlKGksIDEpO1xuICAgICAgICBvdGhlci51bmxpbmtEb2ModGhpcyQxKTtcbiAgICAgICAgZGV0YWNoU2hhcmVkTWFya2VycyhmaW5kU2hhcmVkTWFya2Vycyh0aGlzJDEpKTtcbiAgICAgICAgYnJlYWtcbiAgICAgIH0gfVxuICAgICAgLy8gSWYgdGhlIGhpc3RvcmllcyB3ZXJlIHNoYXJlZCwgc3BsaXQgdGhlbSBhZ2FpblxuICAgICAgaWYgKG90aGVyLmhpc3RvcnkgPT0gdGhpcy5oaXN0b3J5KSB7XG4gICAgICAgIHZhciBzcGxpdElkcyA9IFtvdGhlci5pZF07XG4gICAgICAgIGxpbmtlZERvY3Mob3RoZXIsIGZ1bmN0aW9uIChkb2MpIHsgcmV0dXJuIHNwbGl0SWRzLnB1c2goZG9jLmlkKTsgfSwgdHJ1ZSk7XG4gICAgICAgIG90aGVyLmhpc3RvcnkgPSBuZXcgSGlzdG9yeShudWxsKTtcbiAgICAgICAgb3RoZXIuaGlzdG9yeS5kb25lID0gY29weUhpc3RvcnlBcnJheSh0aGlzLmhpc3RvcnkuZG9uZSwgc3BsaXRJZHMpO1xuICAgICAgICBvdGhlci5oaXN0b3J5LnVuZG9uZSA9IGNvcHlIaXN0b3J5QXJyYXkodGhpcy5oaXN0b3J5LnVuZG9uZSwgc3BsaXRJZHMpO1xuICAgICAgfVxuICAgIH0sXG4gICAgaXRlckxpbmtlZERvY3M6IGZ1bmN0aW9uKGYpIHtsaW5rZWREb2NzKHRoaXMsIGYpO30sXG5cbiAgICBnZXRNb2RlOiBmdW5jdGlvbigpIHtyZXR1cm4gdGhpcy5tb2RlfSxcbiAgICBnZXRFZGl0b3I6IGZ1bmN0aW9uKCkge3JldHVybiB0aGlzLmNtfSxcblxuICAgIHNwbGl0TGluZXM6IGZ1bmN0aW9uKHN0cikge1xuICAgICAgaWYgKHRoaXMubGluZVNlcCkgeyByZXR1cm4gc3RyLnNwbGl0KHRoaXMubGluZVNlcCkgfVxuICAgICAgcmV0dXJuIHNwbGl0TGluZXNBdXRvKHN0cilcbiAgICB9LFxuICAgIGxpbmVTZXBhcmF0b3I6IGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5saW5lU2VwIHx8IFwiXFxuXCIgfSxcblxuICAgIHNldERpcmVjdGlvbjogZG9jTWV0aG9kT3AoZnVuY3Rpb24gKGRpcikge1xuICAgICAgaWYgKGRpciAhPSBcInJ0bFwiKSB7IGRpciA9IFwibHRyXCI7IH1cbiAgICAgIGlmIChkaXIgPT0gdGhpcy5kaXJlY3Rpb24pIHsgcmV0dXJuIH1cbiAgICAgIHRoaXMuZGlyZWN0aW9uID0gZGlyO1xuICAgICAgdGhpcy5pdGVyKGZ1bmN0aW9uIChsaW5lKSB7IHJldHVybiBsaW5lLm9yZGVyID0gbnVsbDsgfSk7XG4gICAgICBpZiAodGhpcy5jbSkgeyBkaXJlY3Rpb25DaGFuZ2VkKHRoaXMuY20pOyB9XG4gICAgfSlcbiAgfSk7XG5cbiAgLy8gUHVibGljIGFsaWFzLlxuICBEb2MucHJvdG90eXBlLmVhY2hMaW5lID0gRG9jLnByb3RvdHlwZS5pdGVyO1xuXG4gIC8vIEtsdWRnZSB0byB3b3JrIGFyb3VuZCBzdHJhbmdlIElFIGJlaGF2aW9yIHdoZXJlIGl0J2xsIHNvbWV0aW1lc1xuICAvLyByZS1maXJlIGEgc2VyaWVzIG9mIGRyYWctcmVsYXRlZCBldmVudHMgcmlnaHQgYWZ0ZXIgdGhlIGRyb3AgKCMxNTUxKVxuICB2YXIgbGFzdERyb3AgPSAwO1xuXG4gIGZ1bmN0aW9uIG9uRHJvcChlKSB7XG4gICAgdmFyIGNtID0gdGhpcztcbiAgICBjbGVhckRyYWdDdXJzb3IoY20pO1xuICAgIGlmIChzaWduYWxET01FdmVudChjbSwgZSkgfHwgZXZlbnRJbldpZGdldChjbS5kaXNwbGF5LCBlKSlcbiAgICAgIHsgcmV0dXJuIH1cbiAgICBlX3ByZXZlbnREZWZhdWx0KGUpO1xuICAgIGlmIChpZSkgeyBsYXN0RHJvcCA9ICtuZXcgRGF0ZTsgfVxuICAgIHZhciBwb3MgPSBwb3NGcm9tTW91c2UoY20sIGUsIHRydWUpLCBmaWxlcyA9IGUuZGF0YVRyYW5zZmVyLmZpbGVzO1xuICAgIGlmICghcG9zIHx8IGNtLmlzUmVhZE9ubHkoKSkgeyByZXR1cm4gfVxuICAgIC8vIE1pZ2h0IGJlIGEgZmlsZSBkcm9wLCBpbiB3aGljaCBjYXNlIHdlIHNpbXBseSBleHRyYWN0IHRoZSB0ZXh0XG4gICAgLy8gYW5kIGluc2VydCBpdC5cbiAgICBpZiAoZmlsZXMgJiYgZmlsZXMubGVuZ3RoICYmIHdpbmRvdy5GaWxlUmVhZGVyICYmIHdpbmRvdy5GaWxlKSB7XG4gICAgICB2YXIgbiA9IGZpbGVzLmxlbmd0aCwgdGV4dCA9IEFycmF5KG4pLCByZWFkID0gMDtcbiAgICAgIHZhciBsb2FkRmlsZSA9IGZ1bmN0aW9uIChmaWxlLCBpKSB7XG4gICAgICAgIGlmIChjbS5vcHRpb25zLmFsbG93RHJvcEZpbGVUeXBlcyAmJlxuICAgICAgICAgICAgaW5kZXhPZihjbS5vcHRpb25zLmFsbG93RHJvcEZpbGVUeXBlcywgZmlsZS50eXBlKSA9PSAtMSlcbiAgICAgICAgICB7IHJldHVybiB9XG5cbiAgICAgICAgdmFyIHJlYWRlciA9IG5ldyBGaWxlUmVhZGVyO1xuICAgICAgICByZWFkZXIub25sb2FkID0gb3BlcmF0aW9uKGNtLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgdmFyIGNvbnRlbnQgPSByZWFkZXIucmVzdWx0O1xuICAgICAgICAgIGlmICgvW1xceDAwLVxceDA4XFx4MGUtXFx4MWZdezJ9Ly50ZXN0KGNvbnRlbnQpKSB7IGNvbnRlbnQgPSBcIlwiOyB9XG4gICAgICAgICAgdGV4dFtpXSA9IGNvbnRlbnQ7XG4gICAgICAgICAgaWYgKCsrcmVhZCA9PSBuKSB7XG4gICAgICAgICAgICBwb3MgPSBjbGlwUG9zKGNtLmRvYywgcG9zKTtcbiAgICAgICAgICAgIHZhciBjaGFuZ2UgPSB7ZnJvbTogcG9zLCB0bzogcG9zLFxuICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0OiBjbS5kb2Muc3BsaXRMaW5lcyh0ZXh0LmpvaW4oY20uZG9jLmxpbmVTZXBhcmF0b3IoKSkpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICBvcmlnaW46IFwicGFzdGVcIn07XG4gICAgICAgICAgICBtYWtlQ2hhbmdlKGNtLmRvYywgY2hhbmdlKTtcbiAgICAgICAgICAgIHNldFNlbGVjdGlvblJlcGxhY2VIaXN0b3J5KGNtLmRvYywgc2ltcGxlU2VsZWN0aW9uKHBvcywgY2hhbmdlRW5kKGNoYW5nZSkpKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZWFkZXIucmVhZEFzVGV4dChmaWxlKTtcbiAgICAgIH07XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG47ICsraSkgeyBsb2FkRmlsZShmaWxlc1tpXSwgaSk7IH1cbiAgICB9IGVsc2UgeyAvLyBOb3JtYWwgZHJvcFxuICAgICAgLy8gRG9uJ3QgZG8gYSByZXBsYWNlIGlmIHRoZSBkcm9wIGhhcHBlbmVkIGluc2lkZSBvZiB0aGUgc2VsZWN0ZWQgdGV4dC5cbiAgICAgIGlmIChjbS5zdGF0ZS5kcmFnZ2luZ1RleHQgJiYgY20uZG9jLnNlbC5jb250YWlucyhwb3MpID4gLTEpIHtcbiAgICAgICAgY20uc3RhdGUuZHJhZ2dpbmdUZXh0KGUpO1xuICAgICAgICAvLyBFbnN1cmUgdGhlIGVkaXRvciBpcyByZS1mb2N1c2VkXG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyByZXR1cm4gY20uZGlzcGxheS5pbnB1dC5mb2N1cygpOyB9LCAyMCk7XG4gICAgICAgIHJldHVyblxuICAgICAgfVxuICAgICAgdHJ5IHtcbiAgICAgICAgdmFyIHRleHQkMSA9IGUuZGF0YVRyYW5zZmVyLmdldERhdGEoXCJUZXh0XCIpO1xuICAgICAgICBpZiAodGV4dCQxKSB7XG4gICAgICAgICAgdmFyIHNlbGVjdGVkO1xuICAgICAgICAgIGlmIChjbS5zdGF0ZS5kcmFnZ2luZ1RleHQgJiYgIWNtLnN0YXRlLmRyYWdnaW5nVGV4dC5jb3B5KVxuICAgICAgICAgICAgeyBzZWxlY3RlZCA9IGNtLmxpc3RTZWxlY3Rpb25zKCk7IH1cbiAgICAgICAgICBzZXRTZWxlY3Rpb25Ob1VuZG8oY20uZG9jLCBzaW1wbGVTZWxlY3Rpb24ocG9zLCBwb3MpKTtcbiAgICAgICAgICBpZiAoc2VsZWN0ZWQpIHsgZm9yICh2YXIgaSQxID0gMDsgaSQxIDwgc2VsZWN0ZWQubGVuZ3RoOyArK2kkMSlcbiAgICAgICAgICAgIHsgcmVwbGFjZVJhbmdlKGNtLmRvYywgXCJcIiwgc2VsZWN0ZWRbaSQxXS5hbmNob3IsIHNlbGVjdGVkW2kkMV0uaGVhZCwgXCJkcmFnXCIpOyB9IH1cbiAgICAgICAgICBjbS5yZXBsYWNlU2VsZWN0aW9uKHRleHQkMSwgXCJhcm91bmRcIiwgXCJwYXN0ZVwiKTtcbiAgICAgICAgICBjbS5kaXNwbGF5LmlucHV0LmZvY3VzKCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGNhdGNoKGUpe31cbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBvbkRyYWdTdGFydChjbSwgZSkge1xuICAgIGlmIChpZSAmJiAoIWNtLnN0YXRlLmRyYWdnaW5nVGV4dCB8fCArbmV3IERhdGUgLSBsYXN0RHJvcCA8IDEwMCkpIHsgZV9zdG9wKGUpOyByZXR1cm4gfVxuICAgIGlmIChzaWduYWxET01FdmVudChjbSwgZSkgfHwgZXZlbnRJbldpZGdldChjbS5kaXNwbGF5LCBlKSkgeyByZXR1cm4gfVxuXG4gICAgZS5kYXRhVHJhbnNmZXIuc2V0RGF0YShcIlRleHRcIiwgY20uZ2V0U2VsZWN0aW9uKCkpO1xuICAgIGUuZGF0YVRyYW5zZmVyLmVmZmVjdEFsbG93ZWQgPSBcImNvcHlNb3ZlXCI7XG5cbiAgICAvLyBVc2UgZHVtbXkgaW1hZ2UgaW5zdGVhZCBvZiBkZWZhdWx0IGJyb3dzZXJzIGltYWdlLlxuICAgIC8vIFJlY2VudCBTYWZhcmkgKH42LjAuMikgaGF2ZSBhIHRlbmRlbmN5IHRvIHNlZ2ZhdWx0IHdoZW4gdGhpcyBoYXBwZW5zLCBzbyB3ZSBkb24ndCBkbyBpdCB0aGVyZS5cbiAgICBpZiAoZS5kYXRhVHJhbnNmZXIuc2V0RHJhZ0ltYWdlICYmICFzYWZhcmkpIHtcbiAgICAgIHZhciBpbWcgPSBlbHQoXCJpbWdcIiwgbnVsbCwgbnVsbCwgXCJwb3NpdGlvbjogZml4ZWQ7IGxlZnQ6IDA7IHRvcDogMDtcIik7XG4gICAgICBpbWcuc3JjID0gXCJkYXRhOmltYWdlL2dpZjtiYXNlNjQsUjBsR09EbGhBUUFCQUFBQUFDSDVCQUVLQUFFQUxBQUFBQUFCQUFFQUFBSUNUQUVBT3c9PVwiO1xuICAgICAgaWYgKHByZXN0bykge1xuICAgICAgICBpbWcud2lkdGggPSBpbWcuaGVpZ2h0ID0gMTtcbiAgICAgICAgY20uZGlzcGxheS53cmFwcGVyLmFwcGVuZENoaWxkKGltZyk7XG4gICAgICAgIC8vIEZvcmNlIGEgcmVsYXlvdXQsIG9yIE9wZXJhIHdvbid0IHVzZSBvdXIgaW1hZ2UgZm9yIHNvbWUgb2JzY3VyZSByZWFzb25cbiAgICAgICAgaW1nLl90b3AgPSBpbWcub2Zmc2V0VG9wO1xuICAgICAgfVxuICAgICAgZS5kYXRhVHJhbnNmZXIuc2V0RHJhZ0ltYWdlKGltZywgMCwgMCk7XG4gICAgICBpZiAocHJlc3RvKSB7IGltZy5wYXJlbnROb2RlLnJlbW92ZUNoaWxkKGltZyk7IH1cbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBvbkRyYWdPdmVyKGNtLCBlKSB7XG4gICAgdmFyIHBvcyA9IHBvc0Zyb21Nb3VzZShjbSwgZSk7XG4gICAgaWYgKCFwb3MpIHsgcmV0dXJuIH1cbiAgICB2YXIgZnJhZyA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcbiAgICBkcmF3U2VsZWN0aW9uQ3Vyc29yKGNtLCBwb3MsIGZyYWcpO1xuICAgIGlmICghY20uZGlzcGxheS5kcmFnQ3Vyc29yKSB7XG4gICAgICBjbS5kaXNwbGF5LmRyYWdDdXJzb3IgPSBlbHQoXCJkaXZcIiwgbnVsbCwgXCJDb2RlTWlycm9yLWN1cnNvcnMgQ29kZU1pcnJvci1kcmFnY3Vyc29yc1wiKTtcbiAgICAgIGNtLmRpc3BsYXkubGluZVNwYWNlLmluc2VydEJlZm9yZShjbS5kaXNwbGF5LmRyYWdDdXJzb3IsIGNtLmRpc3BsYXkuY3Vyc29yRGl2KTtcbiAgICB9XG4gICAgcmVtb3ZlQ2hpbGRyZW5BbmRBZGQoY20uZGlzcGxheS5kcmFnQ3Vyc29yLCBmcmFnKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGNsZWFyRHJhZ0N1cnNvcihjbSkge1xuICAgIGlmIChjbS5kaXNwbGF5LmRyYWdDdXJzb3IpIHtcbiAgICAgIGNtLmRpc3BsYXkubGluZVNwYWNlLnJlbW92ZUNoaWxkKGNtLmRpc3BsYXkuZHJhZ0N1cnNvcik7XG4gICAgICBjbS5kaXNwbGF5LmRyYWdDdXJzb3IgPSBudWxsO1xuICAgIH1cbiAgfVxuXG4gIC8vIFRoZXNlIG11c3QgYmUgaGFuZGxlZCBjYXJlZnVsbHksIGJlY2F1c2UgbmFpdmVseSByZWdpc3RlcmluZyBhXG4gIC8vIGhhbmRsZXIgZm9yIGVhY2ggZWRpdG9yIHdpbGwgY2F1c2UgdGhlIGVkaXRvcnMgdG8gbmV2ZXIgYmVcbiAgLy8gZ2FyYmFnZSBjb2xsZWN0ZWQuXG5cbiAgZnVuY3Rpb24gZm9yRWFjaENvZGVNaXJyb3IoZikge1xuICAgIGlmICghZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZSkgeyByZXR1cm4gfVxuICAgIHZhciBieUNsYXNzID0gZG9jdW1lbnQuZ2V0RWxlbWVudHNCeUNsYXNzTmFtZShcIkNvZGVNaXJyb3JcIiksIGVkaXRvcnMgPSBbXTtcbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGJ5Q2xhc3MubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBjbSA9IGJ5Q2xhc3NbaV0uQ29kZU1pcnJvcjtcbiAgICAgIGlmIChjbSkgeyBlZGl0b3JzLnB1c2goY20pOyB9XG4gICAgfVxuICAgIGlmIChlZGl0b3JzLmxlbmd0aCkgeyBlZGl0b3JzWzBdLm9wZXJhdGlvbihmdW5jdGlvbiAoKSB7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGVkaXRvcnMubGVuZ3RoOyBpKyspIHsgZihlZGl0b3JzW2ldKTsgfVxuICAgIH0pOyB9XG4gIH1cblxuICB2YXIgZ2xvYmFsc1JlZ2lzdGVyZWQgPSBmYWxzZTtcbiAgZnVuY3Rpb24gZW5zdXJlR2xvYmFsSGFuZGxlcnMoKSB7XG4gICAgaWYgKGdsb2JhbHNSZWdpc3RlcmVkKSB7IHJldHVybiB9XG4gICAgcmVnaXN0ZXJHbG9iYWxIYW5kbGVycygpO1xuICAgIGdsb2JhbHNSZWdpc3RlcmVkID0gdHJ1ZTtcbiAgfVxuICBmdW5jdGlvbiByZWdpc3Rlckdsb2JhbEhhbmRsZXJzKCkge1xuICAgIC8vIFdoZW4gdGhlIHdpbmRvdyByZXNpemVzLCB3ZSBuZWVkIHRvIHJlZnJlc2ggYWN0aXZlIGVkaXRvcnMuXG4gICAgdmFyIHJlc2l6ZVRpbWVyO1xuICAgIG9uKHdpbmRvdywgXCJyZXNpemVcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgaWYgKHJlc2l6ZVRpbWVyID09IG51bGwpIHsgcmVzaXplVGltZXIgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmVzaXplVGltZXIgPSBudWxsO1xuICAgICAgICBmb3JFYWNoQ29kZU1pcnJvcihvblJlc2l6ZSk7XG4gICAgICB9LCAxMDApOyB9XG4gICAgfSk7XG4gICAgLy8gV2hlbiB0aGUgd2luZG93IGxvc2VzIGZvY3VzLCB3ZSB3YW50IHRvIHNob3cgdGhlIGVkaXRvciBhcyBibHVycmVkXG4gICAgb24od2luZG93LCBcImJsdXJcIiwgZnVuY3Rpb24gKCkgeyByZXR1cm4gZm9yRWFjaENvZGVNaXJyb3Iob25CbHVyKTsgfSk7XG4gIH1cbiAgLy8gQ2FsbGVkIHdoZW4gdGhlIHdpbmRvdyByZXNpemVzXG4gIGZ1bmN0aW9uIG9uUmVzaXplKGNtKSB7XG4gICAgdmFyIGQgPSBjbS5kaXNwbGF5O1xuICAgIC8vIE1pZ2h0IGJlIGEgdGV4dCBzY2FsaW5nIG9wZXJhdGlvbiwgY2xlYXIgc2l6ZSBjYWNoZXMuXG4gICAgZC5jYWNoZWRDaGFyV2lkdGggPSBkLmNhY2hlZFRleHRIZWlnaHQgPSBkLmNhY2hlZFBhZGRpbmdIID0gbnVsbDtcbiAgICBkLnNjcm9sbGJhcnNDbGlwcGVkID0gZmFsc2U7XG4gICAgY20uc2V0U2l6ZSgpO1xuICB9XG5cbiAgdmFyIGtleU5hbWVzID0ge1xuICAgIDM6IFwiUGF1c2VcIiwgODogXCJCYWNrc3BhY2VcIiwgOTogXCJUYWJcIiwgMTM6IFwiRW50ZXJcIiwgMTY6IFwiU2hpZnRcIiwgMTc6IFwiQ3RybFwiLCAxODogXCJBbHRcIixcbiAgICAxOTogXCJQYXVzZVwiLCAyMDogXCJDYXBzTG9ja1wiLCAyNzogXCJFc2NcIiwgMzI6IFwiU3BhY2VcIiwgMzM6IFwiUGFnZVVwXCIsIDM0OiBcIlBhZ2VEb3duXCIsIDM1OiBcIkVuZFwiLFxuICAgIDM2OiBcIkhvbWVcIiwgMzc6IFwiTGVmdFwiLCAzODogXCJVcFwiLCAzOTogXCJSaWdodFwiLCA0MDogXCJEb3duXCIsIDQ0OiBcIlByaW50U2NyblwiLCA0NTogXCJJbnNlcnRcIixcbiAgICA0NjogXCJEZWxldGVcIiwgNTk6IFwiO1wiLCA2MTogXCI9XCIsIDkxOiBcIk1vZFwiLCA5MjogXCJNb2RcIiwgOTM6IFwiTW9kXCIsXG4gICAgMTA2OiBcIipcIiwgMTA3OiBcIj1cIiwgMTA5OiBcIi1cIiwgMTEwOiBcIi5cIiwgMTExOiBcIi9cIiwgMTI3OiBcIkRlbGV0ZVwiLCAxNDU6IFwiU2Nyb2xsTG9ja1wiLFxuICAgIDE3MzogXCItXCIsIDE4NjogXCI7XCIsIDE4NzogXCI9XCIsIDE4ODogXCIsXCIsIDE4OTogXCItXCIsIDE5MDogXCIuXCIsIDE5MTogXCIvXCIsIDE5MjogXCJgXCIsIDIxOTogXCJbXCIsIDIyMDogXCJcXFxcXCIsXG4gICAgMjIxOiBcIl1cIiwgMjIyOiBcIidcIiwgNjMyMzI6IFwiVXBcIiwgNjMyMzM6IFwiRG93blwiLCA2MzIzNDogXCJMZWZ0XCIsIDYzMjM1OiBcIlJpZ2h0XCIsIDYzMjcyOiBcIkRlbGV0ZVwiLFxuICAgIDYzMjczOiBcIkhvbWVcIiwgNjMyNzU6IFwiRW5kXCIsIDYzMjc2OiBcIlBhZ2VVcFwiLCA2MzI3NzogXCJQYWdlRG93blwiLCA2MzMwMjogXCJJbnNlcnRcIlxuICB9O1xuXG4gIC8vIE51bWJlciBrZXlzXG4gIGZvciAodmFyIGkgPSAwOyBpIDwgMTA7IGkrKykgeyBrZXlOYW1lc1tpICsgNDhdID0ga2V5TmFtZXNbaSArIDk2XSA9IFN0cmluZyhpKTsgfVxuICAvLyBBbHBoYWJldGljIGtleXNcbiAgZm9yICh2YXIgaSQxID0gNjU7IGkkMSA8PSA5MDsgaSQxKyspIHsga2V5TmFtZXNbaSQxXSA9IFN0cmluZy5mcm9tQ2hhckNvZGUoaSQxKTsgfVxuICAvLyBGdW5jdGlvbiBrZXlzXG4gIGZvciAodmFyIGkkMiA9IDE7IGkkMiA8PSAxMjsgaSQyKyspIHsga2V5TmFtZXNbaSQyICsgMTExXSA9IGtleU5hbWVzW2kkMiArIDYzMjM1XSA9IFwiRlwiICsgaSQyOyB9XG5cbiAgdmFyIGtleU1hcCA9IHt9O1xuXG4gIGtleU1hcC5iYXNpYyA9IHtcbiAgICBcIkxlZnRcIjogXCJnb0NoYXJMZWZ0XCIsIFwiUmlnaHRcIjogXCJnb0NoYXJSaWdodFwiLCBcIlVwXCI6IFwiZ29MaW5lVXBcIiwgXCJEb3duXCI6IFwiZ29MaW5lRG93blwiLFxuICAgIFwiRW5kXCI6IFwiZ29MaW5lRW5kXCIsIFwiSG9tZVwiOiBcImdvTGluZVN0YXJ0U21hcnRcIiwgXCJQYWdlVXBcIjogXCJnb1BhZ2VVcFwiLCBcIlBhZ2VEb3duXCI6IFwiZ29QYWdlRG93blwiLFxuICAgIFwiRGVsZXRlXCI6IFwiZGVsQ2hhckFmdGVyXCIsIFwiQmFja3NwYWNlXCI6IFwiZGVsQ2hhckJlZm9yZVwiLCBcIlNoaWZ0LUJhY2tzcGFjZVwiOiBcImRlbENoYXJCZWZvcmVcIixcbiAgICBcIlRhYlwiOiBcImRlZmF1bHRUYWJcIiwgXCJTaGlmdC1UYWJcIjogXCJpbmRlbnRBdXRvXCIsXG4gICAgXCJFbnRlclwiOiBcIm5ld2xpbmVBbmRJbmRlbnRcIiwgXCJJbnNlcnRcIjogXCJ0b2dnbGVPdmVyd3JpdGVcIixcbiAgICBcIkVzY1wiOiBcInNpbmdsZVNlbGVjdGlvblwiXG4gIH07XG4gIC8vIE5vdGUgdGhhdCB0aGUgc2F2ZSBhbmQgZmluZC1yZWxhdGVkIGNvbW1hbmRzIGFyZW4ndCBkZWZpbmVkIGJ5XG4gIC8vIGRlZmF1bHQuIFVzZXIgY29kZSBvciBhZGRvbnMgY2FuIGRlZmluZSB0aGVtLiBVbmtub3duIGNvbW1hbmRzXG4gIC8vIGFyZSBzaW1wbHkgaWdub3JlZC5cbiAga2V5TWFwLnBjRGVmYXVsdCA9IHtcbiAgICBcIkN0cmwtQVwiOiBcInNlbGVjdEFsbFwiLCBcIkN0cmwtRFwiOiBcImRlbGV0ZUxpbmVcIiwgXCJDdHJsLVpcIjogXCJ1bmRvXCIsIFwiU2hpZnQtQ3RybC1aXCI6IFwicmVkb1wiLCBcIkN0cmwtWVwiOiBcInJlZG9cIixcbiAgICBcIkN0cmwtSG9tZVwiOiBcImdvRG9jU3RhcnRcIiwgXCJDdHJsLUVuZFwiOiBcImdvRG9jRW5kXCIsIFwiQ3RybC1VcFwiOiBcImdvTGluZVVwXCIsIFwiQ3RybC1Eb3duXCI6IFwiZ29MaW5lRG93blwiLFxuICAgIFwiQ3RybC1MZWZ0XCI6IFwiZ29Hcm91cExlZnRcIiwgXCJDdHJsLVJpZ2h0XCI6IFwiZ29Hcm91cFJpZ2h0XCIsIFwiQWx0LUxlZnRcIjogXCJnb0xpbmVTdGFydFwiLCBcIkFsdC1SaWdodFwiOiBcImdvTGluZUVuZFwiLFxuICAgIFwiQ3RybC1CYWNrc3BhY2VcIjogXCJkZWxHcm91cEJlZm9yZVwiLCBcIkN0cmwtRGVsZXRlXCI6IFwiZGVsR3JvdXBBZnRlclwiLCBcIkN0cmwtU1wiOiBcInNhdmVcIiwgXCJDdHJsLUZcIjogXCJmaW5kXCIsXG4gICAgXCJDdHJsLUdcIjogXCJmaW5kTmV4dFwiLCBcIlNoaWZ0LUN0cmwtR1wiOiBcImZpbmRQcmV2XCIsIFwiU2hpZnQtQ3RybC1GXCI6IFwicmVwbGFjZVwiLCBcIlNoaWZ0LUN0cmwtUlwiOiBcInJlcGxhY2VBbGxcIixcbiAgICBcIkN0cmwtW1wiOiBcImluZGVudExlc3NcIiwgXCJDdHJsLV1cIjogXCJpbmRlbnRNb3JlXCIsXG4gICAgXCJDdHJsLVVcIjogXCJ1bmRvU2VsZWN0aW9uXCIsIFwiU2hpZnQtQ3RybC1VXCI6IFwicmVkb1NlbGVjdGlvblwiLCBcIkFsdC1VXCI6IFwicmVkb1NlbGVjdGlvblwiLFxuICAgIFwiZmFsbHRocm91Z2hcIjogXCJiYXNpY1wiXG4gIH07XG4gIC8vIFZlcnkgYmFzaWMgcmVhZGxpbmUvZW1hY3Mtc3R5bGUgYmluZGluZ3MsIHdoaWNoIGFyZSBzdGFuZGFyZCBvbiBNYWMuXG4gIGtleU1hcC5lbWFjc3kgPSB7XG4gICAgXCJDdHJsLUZcIjogXCJnb0NoYXJSaWdodFwiLCBcIkN0cmwtQlwiOiBcImdvQ2hhckxlZnRcIiwgXCJDdHJsLVBcIjogXCJnb0xpbmVVcFwiLCBcIkN0cmwtTlwiOiBcImdvTGluZURvd25cIixcbiAgICBcIkFsdC1GXCI6IFwiZ29Xb3JkUmlnaHRcIiwgXCJBbHQtQlwiOiBcImdvV29yZExlZnRcIiwgXCJDdHJsLUFcIjogXCJnb0xpbmVTdGFydFwiLCBcIkN0cmwtRVwiOiBcImdvTGluZUVuZFwiLFxuICAgIFwiQ3RybC1WXCI6IFwiZ29QYWdlRG93blwiLCBcIlNoaWZ0LUN0cmwtVlwiOiBcImdvUGFnZVVwXCIsIFwiQ3RybC1EXCI6IFwiZGVsQ2hhckFmdGVyXCIsIFwiQ3RybC1IXCI6IFwiZGVsQ2hhckJlZm9yZVwiLFxuICAgIFwiQWx0LURcIjogXCJkZWxXb3JkQWZ0ZXJcIiwgXCJBbHQtQmFja3NwYWNlXCI6IFwiZGVsV29yZEJlZm9yZVwiLCBcIkN0cmwtS1wiOiBcImtpbGxMaW5lXCIsIFwiQ3RybC1UXCI6IFwidHJhbnNwb3NlQ2hhcnNcIixcbiAgICBcIkN0cmwtT1wiOiBcIm9wZW5MaW5lXCJcbiAgfTtcbiAga2V5TWFwLm1hY0RlZmF1bHQgPSB7XG4gICAgXCJDbWQtQVwiOiBcInNlbGVjdEFsbFwiLCBcIkNtZC1EXCI6IFwiZGVsZXRlTGluZVwiLCBcIkNtZC1aXCI6IFwidW5kb1wiLCBcIlNoaWZ0LUNtZC1aXCI6IFwicmVkb1wiLCBcIkNtZC1ZXCI6IFwicmVkb1wiLFxuICAgIFwiQ21kLUhvbWVcIjogXCJnb0RvY1N0YXJ0XCIsIFwiQ21kLVVwXCI6IFwiZ29Eb2NTdGFydFwiLCBcIkNtZC1FbmRcIjogXCJnb0RvY0VuZFwiLCBcIkNtZC1Eb3duXCI6IFwiZ29Eb2NFbmRcIiwgXCJBbHQtTGVmdFwiOiBcImdvR3JvdXBMZWZ0XCIsXG4gICAgXCJBbHQtUmlnaHRcIjogXCJnb0dyb3VwUmlnaHRcIiwgXCJDbWQtTGVmdFwiOiBcImdvTGluZUxlZnRcIiwgXCJDbWQtUmlnaHRcIjogXCJnb0xpbmVSaWdodFwiLCBcIkFsdC1CYWNrc3BhY2VcIjogXCJkZWxHcm91cEJlZm9yZVwiLFxuICAgIFwiQ3RybC1BbHQtQmFja3NwYWNlXCI6IFwiZGVsR3JvdXBBZnRlclwiLCBcIkFsdC1EZWxldGVcIjogXCJkZWxHcm91cEFmdGVyXCIsIFwiQ21kLVNcIjogXCJzYXZlXCIsIFwiQ21kLUZcIjogXCJmaW5kXCIsXG4gICAgXCJDbWQtR1wiOiBcImZpbmROZXh0XCIsIFwiU2hpZnQtQ21kLUdcIjogXCJmaW5kUHJldlwiLCBcIkNtZC1BbHQtRlwiOiBcInJlcGxhY2VcIiwgXCJTaGlmdC1DbWQtQWx0LUZcIjogXCJyZXBsYWNlQWxsXCIsXG4gICAgXCJDbWQtW1wiOiBcImluZGVudExlc3NcIiwgXCJDbWQtXVwiOiBcImluZGVudE1vcmVcIiwgXCJDbWQtQmFja3NwYWNlXCI6IFwiZGVsV3JhcHBlZExpbmVMZWZ0XCIsIFwiQ21kLURlbGV0ZVwiOiBcImRlbFdyYXBwZWRMaW5lUmlnaHRcIixcbiAgICBcIkNtZC1VXCI6IFwidW5kb1NlbGVjdGlvblwiLCBcIlNoaWZ0LUNtZC1VXCI6IFwicmVkb1NlbGVjdGlvblwiLCBcIkN0cmwtVXBcIjogXCJnb0RvY1N0YXJ0XCIsIFwiQ3RybC1Eb3duXCI6IFwiZ29Eb2NFbmRcIixcbiAgICBcImZhbGx0aHJvdWdoXCI6IFtcImJhc2ljXCIsIFwiZW1hY3N5XCJdXG4gIH07XG4gIGtleU1hcFtcImRlZmF1bHRcIl0gPSBtYWMgPyBrZXlNYXAubWFjRGVmYXVsdCA6IGtleU1hcC5wY0RlZmF1bHQ7XG5cbiAgLy8gS0VZTUFQIERJU1BBVENIXG5cbiAgZnVuY3Rpb24gbm9ybWFsaXplS2V5TmFtZShuYW1lKSB7XG4gICAgdmFyIHBhcnRzID0gbmFtZS5zcGxpdCgvLSg/ISQpLyk7XG4gICAgbmFtZSA9IHBhcnRzW3BhcnRzLmxlbmd0aCAtIDFdO1xuICAgIHZhciBhbHQsIGN0cmwsIHNoaWZ0LCBjbWQ7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwYXJ0cy5sZW5ndGggLSAxOyBpKyspIHtcbiAgICAgIHZhciBtb2QgPSBwYXJ0c1tpXTtcbiAgICAgIGlmICgvXihjbWR8bWV0YXxtKSQvaS50ZXN0KG1vZCkpIHsgY21kID0gdHJ1ZTsgfVxuICAgICAgZWxzZSBpZiAoL15hKGx0KT8kL2kudGVzdChtb2QpKSB7IGFsdCA9IHRydWU7IH1cbiAgICAgIGVsc2UgaWYgKC9eKGN8Y3RybHxjb250cm9sKSQvaS50ZXN0KG1vZCkpIHsgY3RybCA9IHRydWU7IH1cbiAgICAgIGVsc2UgaWYgKC9ecyhoaWZ0KT8kL2kudGVzdChtb2QpKSB7IHNoaWZ0ID0gdHJ1ZTsgfVxuICAgICAgZWxzZSB7IHRocm93IG5ldyBFcnJvcihcIlVucmVjb2duaXplZCBtb2RpZmllciBuYW1lOiBcIiArIG1vZCkgfVxuICAgIH1cbiAgICBpZiAoYWx0KSB7IG5hbWUgPSBcIkFsdC1cIiArIG5hbWU7IH1cbiAgICBpZiAoY3RybCkgeyBuYW1lID0gXCJDdHJsLVwiICsgbmFtZTsgfVxuICAgIGlmIChjbWQpIHsgbmFtZSA9IFwiQ21kLVwiICsgbmFtZTsgfVxuICAgIGlmIChzaGlmdCkgeyBuYW1lID0gXCJTaGlmdC1cIiArIG5hbWU7IH1cbiAgICByZXR1cm4gbmFtZVxuICB9XG5cbiAgLy8gVGhpcyBpcyBhIGtsdWRnZSB0byBrZWVwIGtleW1hcHMgbW9zdGx5IHdvcmtpbmcgYXMgcmF3IG9iamVjdHNcbiAgLy8gKGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5KSB3aGlsZSBhdCB0aGUgc2FtZSB0aW1lIHN1cHBvcnQgZmVhdHVyZXNcbiAgLy8gbGlrZSBub3JtYWxpemF0aW9uIGFuZCBtdWx0aS1zdHJva2Uga2V5IGJpbmRpbmdzLiBJdCBjb21waWxlcyBhXG4gIC8vIG5ldyBub3JtYWxpemVkIGtleW1hcCwgYW5kIHRoZW4gdXBkYXRlcyB0aGUgb2xkIG9iamVjdCB0byByZWZsZWN0XG4gIC8vIHRoaXMuXG4gIGZ1bmN0aW9uIG5vcm1hbGl6ZUtleU1hcChrZXltYXApIHtcbiAgICB2YXIgY29weSA9IHt9O1xuICAgIGZvciAodmFyIGtleW5hbWUgaW4ga2V5bWFwKSB7IGlmIChrZXltYXAuaGFzT3duUHJvcGVydHkoa2V5bmFtZSkpIHtcbiAgICAgIHZhciB2YWx1ZSA9IGtleW1hcFtrZXluYW1lXTtcbiAgICAgIGlmICgvXihuYW1lfGZhbGx0aHJvdWdofChkZXxhdCl0YWNoKSQvLnRlc3Qoa2V5bmFtZSkpIHsgY29udGludWUgfVxuICAgICAgaWYgKHZhbHVlID09IFwiLi4uXCIpIHsgZGVsZXRlIGtleW1hcFtrZXluYW1lXTsgY29udGludWUgfVxuXG4gICAgICB2YXIga2V5cyA9IG1hcChrZXluYW1lLnNwbGl0KFwiIFwiKSwgbm9ybWFsaXplS2V5TmFtZSk7XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGtleXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHZhbCA9ICh2b2lkIDApLCBuYW1lID0gKHZvaWQgMCk7XG4gICAgICAgIGlmIChpID09IGtleXMubGVuZ3RoIC0gMSkge1xuICAgICAgICAgIG5hbWUgPSBrZXlzLmpvaW4oXCIgXCIpO1xuICAgICAgICAgIHZhbCA9IHZhbHVlO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIG5hbWUgPSBrZXlzLnNsaWNlKDAsIGkgKyAxKS5qb2luKFwiIFwiKTtcbiAgICAgICAgICB2YWwgPSBcIi4uLlwiO1xuICAgICAgICB9XG4gICAgICAgIHZhciBwcmV2ID0gY29weVtuYW1lXTtcbiAgICAgICAgaWYgKCFwcmV2KSB7IGNvcHlbbmFtZV0gPSB2YWw7IH1cbiAgICAgICAgZWxzZSBpZiAocHJldiAhPSB2YWwpIHsgdGhyb3cgbmV3IEVycm9yKFwiSW5jb25zaXN0ZW50IGJpbmRpbmdzIGZvciBcIiArIG5hbWUpIH1cbiAgICAgIH1cbiAgICAgIGRlbGV0ZSBrZXltYXBba2V5bmFtZV07XG4gICAgfSB9XG4gICAgZm9yICh2YXIgcHJvcCBpbiBjb3B5KSB7IGtleW1hcFtwcm9wXSA9IGNvcHlbcHJvcF07IH1cbiAgICByZXR1cm4ga2V5bWFwXG4gIH1cblxuICBmdW5jdGlvbiBsb29rdXBLZXkoa2V5LCBtYXAkJDEsIGhhbmRsZSwgY29udGV4dCkge1xuICAgIG1hcCQkMSA9IGdldEtleU1hcChtYXAkJDEpO1xuICAgIHZhciBmb3VuZCA9IG1hcCQkMS5jYWxsID8gbWFwJCQxLmNhbGwoa2V5LCBjb250ZXh0KSA6IG1hcCQkMVtrZXldO1xuICAgIGlmIChmb3VuZCA9PT0gZmFsc2UpIHsgcmV0dXJuIFwibm90aGluZ1wiIH1cbiAgICBpZiAoZm91bmQgPT09IFwiLi4uXCIpIHsgcmV0dXJuIFwibXVsdGlcIiB9XG4gICAgaWYgKGZvdW5kICE9IG51bGwgJiYgaGFuZGxlKGZvdW5kKSkgeyByZXR1cm4gXCJoYW5kbGVkXCIgfVxuXG4gICAgaWYgKG1hcCQkMS5mYWxsdGhyb3VnaCkge1xuICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbChtYXAkJDEuZmFsbHRocm91Z2gpICE9IFwiW29iamVjdCBBcnJheV1cIilcbiAgICAgICAgeyByZXR1cm4gbG9va3VwS2V5KGtleSwgbWFwJCQxLmZhbGx0aHJvdWdoLCBoYW5kbGUsIGNvbnRleHQpIH1cbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbWFwJCQxLmZhbGx0aHJvdWdoLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciByZXN1bHQgPSBsb29rdXBLZXkoa2V5LCBtYXAkJDEuZmFsbHRocm91Z2hbaV0sIGhhbmRsZSwgY29udGV4dCk7XG4gICAgICAgIGlmIChyZXN1bHQpIHsgcmV0dXJuIHJlc3VsdCB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLy8gTW9kaWZpZXIga2V5IHByZXNzZXMgZG9uJ3QgY291bnQgYXMgJ3JlYWwnIGtleSBwcmVzc2VzIGZvciB0aGVcbiAgLy8gcHVycG9zZSBvZiBrZXltYXAgZmFsbHRocm91Z2guXG4gIGZ1bmN0aW9uIGlzTW9kaWZpZXJLZXkodmFsdWUpIHtcbiAgICB2YXIgbmFtZSA9IHR5cGVvZiB2YWx1ZSA9PSBcInN0cmluZ1wiID8gdmFsdWUgOiBrZXlOYW1lc1t2YWx1ZS5rZXlDb2RlXTtcbiAgICByZXR1cm4gbmFtZSA9PSBcIkN0cmxcIiB8fCBuYW1lID09IFwiQWx0XCIgfHwgbmFtZSA9PSBcIlNoaWZ0XCIgfHwgbmFtZSA9PSBcIk1vZFwiXG4gIH1cblxuICBmdW5jdGlvbiBhZGRNb2RpZmllck5hbWVzKG5hbWUsIGV2ZW50LCBub1NoaWZ0KSB7XG4gICAgdmFyIGJhc2UgPSBuYW1lO1xuICAgIGlmIChldmVudC5hbHRLZXkgJiYgYmFzZSAhPSBcIkFsdFwiKSB7IG5hbWUgPSBcIkFsdC1cIiArIG5hbWU7IH1cbiAgICBpZiAoKGZsaXBDdHJsQ21kID8gZXZlbnQubWV0YUtleSA6IGV2ZW50LmN0cmxLZXkpICYmIGJhc2UgIT0gXCJDdHJsXCIpIHsgbmFtZSA9IFwiQ3RybC1cIiArIG5hbWU7IH1cbiAgICBpZiAoKGZsaXBDdHJsQ21kID8gZXZlbnQuY3RybEtleSA6IGV2ZW50Lm1ldGFLZXkpICYmIGJhc2UgIT0gXCJDbWRcIikgeyBuYW1lID0gXCJDbWQtXCIgKyBuYW1lOyB9XG4gICAgaWYgKCFub1NoaWZ0ICYmIGV2ZW50LnNoaWZ0S2V5ICYmIGJhc2UgIT0gXCJTaGlmdFwiKSB7IG5hbWUgPSBcIlNoaWZ0LVwiICsgbmFtZTsgfVxuICAgIHJldHVybiBuYW1lXG4gIH1cblxuICAvLyBMb29rIHVwIHRoZSBuYW1lIG9mIGEga2V5IGFzIGluZGljYXRlZCBieSBhbiBldmVudCBvYmplY3QuXG4gIGZ1bmN0aW9uIGtleU5hbWUoZXZlbnQsIG5vU2hpZnQpIHtcbiAgICBpZiAocHJlc3RvICYmIGV2ZW50LmtleUNvZGUgPT0gMzQgJiYgZXZlbnRbXCJjaGFyXCJdKSB7IHJldHVybiBmYWxzZSB9XG4gICAgdmFyIG5hbWUgPSBrZXlOYW1lc1tldmVudC5rZXlDb2RlXTtcbiAgICBpZiAobmFtZSA9PSBudWxsIHx8IGV2ZW50LmFsdEdyYXBoS2V5KSB7IHJldHVybiBmYWxzZSB9XG4gICAgLy8gQ3RybC1TY3JvbGxMb2NrIGhhcyBrZXlDb2RlIDMsIHNhbWUgYXMgQ3RybC1QYXVzZSxcbiAgICAvLyBzbyB3ZSdsbCB1c2UgZXZlbnQuY29kZSB3aGVuIGF2YWlsYWJsZSAoQ2hyb21lIDQ4KywgRkYgMzgrLCBTYWZhcmkgMTAuMSspXG4gICAgaWYgKGV2ZW50LmtleUNvZGUgPT0gMyAmJiBldmVudC5jb2RlKSB7IG5hbWUgPSBldmVudC5jb2RlOyB9XG4gICAgcmV0dXJuIGFkZE1vZGlmaWVyTmFtZXMobmFtZSwgZXZlbnQsIG5vU2hpZnQpXG4gIH1cblxuICBmdW5jdGlvbiBnZXRLZXlNYXAodmFsKSB7XG4gICAgcmV0dXJuIHR5cGVvZiB2YWwgPT0gXCJzdHJpbmdcIiA/IGtleU1hcFt2YWxdIDogdmFsXG4gIH1cblxuICAvLyBIZWxwZXIgZm9yIGRlbGV0aW5nIHRleHQgbmVhciB0aGUgc2VsZWN0aW9uKHMpLCB1c2VkIHRvIGltcGxlbWVudFxuICAvLyBiYWNrc3BhY2UsIGRlbGV0ZSwgYW5kIHNpbWlsYXIgZnVuY3Rpb25hbGl0eS5cbiAgZnVuY3Rpb24gZGVsZXRlTmVhclNlbGVjdGlvbihjbSwgY29tcHV0ZSkge1xuICAgIHZhciByYW5nZXMgPSBjbS5kb2Muc2VsLnJhbmdlcywga2lsbCA9IFtdO1xuICAgIC8vIEJ1aWxkIHVwIGEgc2V0IG9mIHJhbmdlcyB0byBraWxsIGZpcnN0LCBtZXJnaW5nIG92ZXJsYXBwaW5nXG4gICAgLy8gcmFuZ2VzLlxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmFuZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgdG9LaWxsID0gY29tcHV0ZShyYW5nZXNbaV0pO1xuICAgICAgd2hpbGUgKGtpbGwubGVuZ3RoICYmIGNtcCh0b0tpbGwuZnJvbSwgbHN0KGtpbGwpLnRvKSA8PSAwKSB7XG4gICAgICAgIHZhciByZXBsYWNlZCA9IGtpbGwucG9wKCk7XG4gICAgICAgIGlmIChjbXAocmVwbGFjZWQuZnJvbSwgdG9LaWxsLmZyb20pIDwgMCkge1xuICAgICAgICAgIHRvS2lsbC5mcm9tID0gcmVwbGFjZWQuZnJvbTtcbiAgICAgICAgICBicmVha1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBraWxsLnB1c2godG9LaWxsKTtcbiAgICB9XG4gICAgLy8gTmV4dCwgcmVtb3ZlIHRob3NlIGFjdHVhbCByYW5nZXMuXG4gICAgcnVuSW5PcChjbSwgZnVuY3Rpb24gKCkge1xuICAgICAgZm9yICh2YXIgaSA9IGtpbGwubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pXG4gICAgICAgIHsgcmVwbGFjZVJhbmdlKGNtLmRvYywgXCJcIiwga2lsbFtpXS5mcm9tLCBraWxsW2ldLnRvLCBcIitkZWxldGVcIik7IH1cbiAgICAgIGVuc3VyZUN1cnNvclZpc2libGUoY20pO1xuICAgIH0pO1xuICB9XG5cbiAgZnVuY3Rpb24gbW92ZUNoYXJMb2dpY2FsbHkobGluZSwgY2gsIGRpcikge1xuICAgIHZhciB0YXJnZXQgPSBza2lwRXh0ZW5kaW5nQ2hhcnMobGluZS50ZXh0LCBjaCArIGRpciwgZGlyKTtcbiAgICByZXR1cm4gdGFyZ2V0IDwgMCB8fCB0YXJnZXQgPiBsaW5lLnRleHQubGVuZ3RoID8gbnVsbCA6IHRhcmdldFxuICB9XG5cbiAgZnVuY3Rpb24gbW92ZUxvZ2ljYWxseShsaW5lLCBzdGFydCwgZGlyKSB7XG4gICAgdmFyIGNoID0gbW92ZUNoYXJMb2dpY2FsbHkobGluZSwgc3RhcnQuY2gsIGRpcik7XG4gICAgcmV0dXJuIGNoID09IG51bGwgPyBudWxsIDogbmV3IFBvcyhzdGFydC5saW5lLCBjaCwgZGlyIDwgMCA/IFwiYWZ0ZXJcIiA6IFwiYmVmb3JlXCIpXG4gIH1cblxuICBmdW5jdGlvbiBlbmRPZkxpbmUodmlzdWFsbHksIGNtLCBsaW5lT2JqLCBsaW5lTm8sIGRpcikge1xuICAgIGlmICh2aXN1YWxseSkge1xuICAgICAgdmFyIG9yZGVyID0gZ2V0T3JkZXIobGluZU9iaiwgY20uZG9jLmRpcmVjdGlvbik7XG4gICAgICBpZiAob3JkZXIpIHtcbiAgICAgICAgdmFyIHBhcnQgPSBkaXIgPCAwID8gbHN0KG9yZGVyKSA6IG9yZGVyWzBdO1xuICAgICAgICB2YXIgbW92ZUluU3RvcmFnZU9yZGVyID0gKGRpciA8IDApID09IChwYXJ0LmxldmVsID09IDEpO1xuICAgICAgICB2YXIgc3RpY2t5ID0gbW92ZUluU3RvcmFnZU9yZGVyID8gXCJhZnRlclwiIDogXCJiZWZvcmVcIjtcbiAgICAgICAgdmFyIGNoO1xuICAgICAgICAvLyBXaXRoIGEgd3JhcHBlZCBydGwgY2h1bmsgKHBvc3NpYmx5IHNwYW5uaW5nIG11bHRpcGxlIGJpZGkgcGFydHMpLFxuICAgICAgICAvLyBpdCBjb3VsZCBiZSB0aGF0IHRoZSBsYXN0IGJpZGkgcGFydCBpcyBub3Qgb24gdGhlIGxhc3QgdmlzdWFsIGxpbmUsXG4gICAgICAgIC8vIHNpbmNlIHZpc3VhbCBsaW5lcyBjb250YWluIGNvbnRlbnQgb3JkZXItY29uc2VjdXRpdmUgY2h1bmtzLlxuICAgICAgICAvLyBUaHVzLCBpbiBydGwsIHdlIGFyZSBsb29raW5nIGZvciB0aGUgZmlyc3QgKGNvbnRlbnQtb3JkZXIpIGNoYXJhY3RlclxuICAgICAgICAvLyBpbiB0aGUgcnRsIGNodW5rIHRoYXQgaXMgb24gdGhlIGxhc3QgbGluZSAodGhhdCBpcywgdGhlIHNhbWUgbGluZVxuICAgICAgICAvLyBhcyB0aGUgbGFzdCAoY29udGVudC1vcmRlcikgY2hhcmFjdGVyKS5cbiAgICAgICAgaWYgKHBhcnQubGV2ZWwgPiAwIHx8IGNtLmRvYy5kaXJlY3Rpb24gPT0gXCJydGxcIikge1xuICAgICAgICAgIHZhciBwcmVwID0gcHJlcGFyZU1lYXN1cmVGb3JMaW5lKGNtLCBsaW5lT2JqKTtcbiAgICAgICAgICBjaCA9IGRpciA8IDAgPyBsaW5lT2JqLnRleHQubGVuZ3RoIC0gMSA6IDA7XG4gICAgICAgICAgdmFyIHRhcmdldFRvcCA9IG1lYXN1cmVDaGFyUHJlcGFyZWQoY20sIHByZXAsIGNoKS50b3A7XG4gICAgICAgICAgY2ggPSBmaW5kRmlyc3QoZnVuY3Rpb24gKGNoKSB7IHJldHVybiBtZWFzdXJlQ2hhclByZXBhcmVkKGNtLCBwcmVwLCBjaCkudG9wID09IHRhcmdldFRvcDsgfSwgKGRpciA8IDApID09IChwYXJ0LmxldmVsID09IDEpID8gcGFydC5mcm9tIDogcGFydC50byAtIDEsIGNoKTtcbiAgICAgICAgICBpZiAoc3RpY2t5ID09IFwiYmVmb3JlXCIpIHsgY2ggPSBtb3ZlQ2hhckxvZ2ljYWxseShsaW5lT2JqLCBjaCwgMSk7IH1cbiAgICAgICAgfSBlbHNlIHsgY2ggPSBkaXIgPCAwID8gcGFydC50byA6IHBhcnQuZnJvbTsgfVxuICAgICAgICByZXR1cm4gbmV3IFBvcyhsaW5lTm8sIGNoLCBzdGlja3kpXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBuZXcgUG9zKGxpbmVObywgZGlyIDwgMCA/IGxpbmVPYmoudGV4dC5sZW5ndGggOiAwLCBkaXIgPCAwID8gXCJiZWZvcmVcIiA6IFwiYWZ0ZXJcIilcbiAgfVxuXG4gIGZ1bmN0aW9uIG1vdmVWaXN1YWxseShjbSwgbGluZSwgc3RhcnQsIGRpcikge1xuICAgIHZhciBiaWRpID0gZ2V0T3JkZXIobGluZSwgY20uZG9jLmRpcmVjdGlvbik7XG4gICAgaWYgKCFiaWRpKSB7IHJldHVybiBtb3ZlTG9naWNhbGx5KGxpbmUsIHN0YXJ0LCBkaXIpIH1cbiAgICBpZiAoc3RhcnQuY2ggPj0gbGluZS50ZXh0Lmxlbmd0aCkge1xuICAgICAgc3RhcnQuY2ggPSBsaW5lLnRleHQubGVuZ3RoO1xuICAgICAgc3RhcnQuc3RpY2t5ID0gXCJiZWZvcmVcIjtcbiAgICB9IGVsc2UgaWYgKHN0YXJ0LmNoIDw9IDApIHtcbiAgICAgIHN0YXJ0LmNoID0gMDtcbiAgICAgIHN0YXJ0LnN0aWNreSA9IFwiYWZ0ZXJcIjtcbiAgICB9XG4gICAgdmFyIHBhcnRQb3MgPSBnZXRCaWRpUGFydEF0KGJpZGksIHN0YXJ0LmNoLCBzdGFydC5zdGlja3kpLCBwYXJ0ID0gYmlkaVtwYXJ0UG9zXTtcbiAgICBpZiAoY20uZG9jLmRpcmVjdGlvbiA9PSBcImx0clwiICYmIHBhcnQubGV2ZWwgJSAyID09IDAgJiYgKGRpciA+IDAgPyBwYXJ0LnRvID4gc3RhcnQuY2ggOiBwYXJ0LmZyb20gPCBzdGFydC5jaCkpIHtcbiAgICAgIC8vIENhc2UgMTogV2UgbW92ZSB3aXRoaW4gYW4gbHRyIHBhcnQgaW4gYW4gbHRyIGVkaXRvci4gRXZlbiB3aXRoIHdyYXBwZWQgbGluZXMsXG4gICAgICAvLyBub3RoaW5nIGludGVyZXN0aW5nIGhhcHBlbnMuXG4gICAgICByZXR1cm4gbW92ZUxvZ2ljYWxseShsaW5lLCBzdGFydCwgZGlyKVxuICAgIH1cblxuICAgIHZhciBtdiA9IGZ1bmN0aW9uIChwb3MsIGRpcikgeyByZXR1cm4gbW92ZUNoYXJMb2dpY2FsbHkobGluZSwgcG9zIGluc3RhbmNlb2YgUG9zID8gcG9zLmNoIDogcG9zLCBkaXIpOyB9O1xuICAgIHZhciBwcmVwO1xuICAgIHZhciBnZXRXcmFwcGVkTGluZUV4dGVudCA9IGZ1bmN0aW9uIChjaCkge1xuICAgICAgaWYgKCFjbS5vcHRpb25zLmxpbmVXcmFwcGluZykgeyByZXR1cm4ge2JlZ2luOiAwLCBlbmQ6IGxpbmUudGV4dC5sZW5ndGh9IH1cbiAgICAgIHByZXAgPSBwcmVwIHx8IHByZXBhcmVNZWFzdXJlRm9yTGluZShjbSwgbGluZSk7XG4gICAgICByZXR1cm4gd3JhcHBlZExpbmVFeHRlbnRDaGFyKGNtLCBsaW5lLCBwcmVwLCBjaClcbiAgICB9O1xuICAgIHZhciB3cmFwcGVkTGluZUV4dGVudCA9IGdldFdyYXBwZWRMaW5lRXh0ZW50KHN0YXJ0LnN0aWNreSA9PSBcImJlZm9yZVwiID8gbXYoc3RhcnQsIC0xKSA6IHN0YXJ0LmNoKTtcblxuICAgIGlmIChjbS5kb2MuZGlyZWN0aW9uID09IFwicnRsXCIgfHwgcGFydC5sZXZlbCA9PSAxKSB7XG4gICAgICB2YXIgbW92ZUluU3RvcmFnZU9yZGVyID0gKHBhcnQubGV2ZWwgPT0gMSkgPT0gKGRpciA8IDApO1xuICAgICAgdmFyIGNoID0gbXYoc3RhcnQsIG1vdmVJblN0b3JhZ2VPcmRlciA/IDEgOiAtMSk7XG4gICAgICBpZiAoY2ggIT0gbnVsbCAmJiAoIW1vdmVJblN0b3JhZ2VPcmRlciA/IGNoID49IHBhcnQuZnJvbSAmJiBjaCA+PSB3cmFwcGVkTGluZUV4dGVudC5iZWdpbiA6IGNoIDw9IHBhcnQudG8gJiYgY2ggPD0gd3JhcHBlZExpbmVFeHRlbnQuZW5kKSkge1xuICAgICAgICAvLyBDYXNlIDI6IFdlIG1vdmUgd2l0aGluIGFuIHJ0bCBwYXJ0IG9yIGluIGFuIHJ0bCBlZGl0b3Igb24gdGhlIHNhbWUgdmlzdWFsIGxpbmVcbiAgICAgICAgdmFyIHN0aWNreSA9IG1vdmVJblN0b3JhZ2VPcmRlciA/IFwiYmVmb3JlXCIgOiBcImFmdGVyXCI7XG4gICAgICAgIHJldHVybiBuZXcgUG9zKHN0YXJ0LmxpbmUsIGNoLCBzdGlja3kpXG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQ2FzZSAzOiBDb3VsZCBub3QgbW92ZSB3aXRoaW4gdGhpcyBiaWRpIHBhcnQgaW4gdGhpcyB2aXN1YWwgbGluZSwgc28gbGVhdmVcbiAgICAvLyB0aGUgY3VycmVudCBiaWRpIHBhcnRcblxuICAgIHZhciBzZWFyY2hJblZpc3VhbExpbmUgPSBmdW5jdGlvbiAocGFydFBvcywgZGlyLCB3cmFwcGVkTGluZUV4dGVudCkge1xuICAgICAgdmFyIGdldFJlcyA9IGZ1bmN0aW9uIChjaCwgbW92ZUluU3RvcmFnZU9yZGVyKSB7IHJldHVybiBtb3ZlSW5TdG9yYWdlT3JkZXJcbiAgICAgICAgPyBuZXcgUG9zKHN0YXJ0LmxpbmUsIG12KGNoLCAxKSwgXCJiZWZvcmVcIilcbiAgICAgICAgOiBuZXcgUG9zKHN0YXJ0LmxpbmUsIGNoLCBcImFmdGVyXCIpOyB9O1xuXG4gICAgICBmb3IgKDsgcGFydFBvcyA+PSAwICYmIHBhcnRQb3MgPCBiaWRpLmxlbmd0aDsgcGFydFBvcyArPSBkaXIpIHtcbiAgICAgICAgdmFyIHBhcnQgPSBiaWRpW3BhcnRQb3NdO1xuICAgICAgICB2YXIgbW92ZUluU3RvcmFnZU9yZGVyID0gKGRpciA+IDApID09IChwYXJ0LmxldmVsICE9IDEpO1xuICAgICAgICB2YXIgY2ggPSBtb3ZlSW5TdG9yYWdlT3JkZXIgPyB3cmFwcGVkTGluZUV4dGVudC5iZWdpbiA6IG12KHdyYXBwZWRMaW5lRXh0ZW50LmVuZCwgLTEpO1xuICAgICAgICBpZiAocGFydC5mcm9tIDw9IGNoICYmIGNoIDwgcGFydC50bykgeyByZXR1cm4gZ2V0UmVzKGNoLCBtb3ZlSW5TdG9yYWdlT3JkZXIpIH1cbiAgICAgICAgY2ggPSBtb3ZlSW5TdG9yYWdlT3JkZXIgPyBwYXJ0LmZyb20gOiBtdihwYXJ0LnRvLCAtMSk7XG4gICAgICAgIGlmICh3cmFwcGVkTGluZUV4dGVudC5iZWdpbiA8PSBjaCAmJiBjaCA8IHdyYXBwZWRMaW5lRXh0ZW50LmVuZCkgeyByZXR1cm4gZ2V0UmVzKGNoLCBtb3ZlSW5TdG9yYWdlT3JkZXIpIH1cbiAgICAgIH1cbiAgICB9O1xuXG4gICAgLy8gQ2FzZSAzYTogTG9vayBmb3Igb3RoZXIgYmlkaSBwYXJ0cyBvbiB0aGUgc2FtZSB2aXN1YWwgbGluZVxuICAgIHZhciByZXMgPSBzZWFyY2hJblZpc3VhbExpbmUocGFydFBvcyArIGRpciwgZGlyLCB3cmFwcGVkTGluZUV4dGVudCk7XG4gICAgaWYgKHJlcykgeyByZXR1cm4gcmVzIH1cblxuICAgIC8vIENhc2UgM2I6IExvb2sgZm9yIG90aGVyIGJpZGkgcGFydHMgb24gdGhlIG5leHQgdmlzdWFsIGxpbmVcbiAgICB2YXIgbmV4dENoID0gZGlyID4gMCA/IHdyYXBwZWRMaW5lRXh0ZW50LmVuZCA6IG12KHdyYXBwZWRMaW5lRXh0ZW50LmJlZ2luLCAtMSk7XG4gICAgaWYgKG5leHRDaCAhPSBudWxsICYmICEoZGlyID4gMCAmJiBuZXh0Q2ggPT0gbGluZS50ZXh0Lmxlbmd0aCkpIHtcbiAgICAgIHJlcyA9IHNlYXJjaEluVmlzdWFsTGluZShkaXIgPiAwID8gMCA6IGJpZGkubGVuZ3RoIC0gMSwgZGlyLCBnZXRXcmFwcGVkTGluZUV4dGVudChuZXh0Q2gpKTtcbiAgICAgIGlmIChyZXMpIHsgcmV0dXJuIHJlcyB9XG4gICAgfVxuXG4gICAgLy8gQ2FzZSA0OiBOb3doZXJlIHRvIG1vdmVcbiAgICByZXR1cm4gbnVsbFxuICB9XG5cbiAgLy8gQ29tbWFuZHMgYXJlIHBhcmFtZXRlci1sZXNzIGFjdGlvbnMgdGhhdCBjYW4gYmUgcGVyZm9ybWVkIG9uIGFuXG4gIC8vIGVkaXRvciwgbW9zdGx5IHVzZWQgZm9yIGtleWJpbmRpbmdzLlxuICB2YXIgY29tbWFuZHMgPSB7XG4gICAgc2VsZWN0QWxsOiBzZWxlY3RBbGwsXG4gICAgc2luZ2xlU2VsZWN0aW9uOiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLnNldFNlbGVjdGlvbihjbS5nZXRDdXJzb3IoXCJhbmNob3JcIiksIGNtLmdldEN1cnNvcihcImhlYWRcIiksIHNlbF9kb250U2Nyb2xsKTsgfSxcbiAgICBraWxsTGluZTogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBkZWxldGVOZWFyU2VsZWN0aW9uKGNtLCBmdW5jdGlvbiAocmFuZ2UpIHtcbiAgICAgIGlmIChyYW5nZS5lbXB0eSgpKSB7XG4gICAgICAgIHZhciBsZW4gPSBnZXRMaW5lKGNtLmRvYywgcmFuZ2UuaGVhZC5saW5lKS50ZXh0Lmxlbmd0aDtcbiAgICAgICAgaWYgKHJhbmdlLmhlYWQuY2ggPT0gbGVuICYmIHJhbmdlLmhlYWQubGluZSA8IGNtLmxhc3RMaW5lKCkpXG4gICAgICAgICAgeyByZXR1cm4ge2Zyb206IHJhbmdlLmhlYWQsIHRvOiBQb3MocmFuZ2UuaGVhZC5saW5lICsgMSwgMCl9IH1cbiAgICAgICAgZWxzZVxuICAgICAgICAgIHsgcmV0dXJuIHtmcm9tOiByYW5nZS5oZWFkLCB0bzogUG9zKHJhbmdlLmhlYWQubGluZSwgbGVuKX0gfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmV0dXJuIHtmcm9tOiByYW5nZS5mcm9tKCksIHRvOiByYW5nZS50bygpfVxuICAgICAgfVxuICAgIH0pOyB9LFxuICAgIGRlbGV0ZUxpbmU6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gZGVsZXRlTmVhclNlbGVjdGlvbihjbSwgZnVuY3Rpb24gKHJhbmdlKSB7IHJldHVybiAoe1xuICAgICAgZnJvbTogUG9zKHJhbmdlLmZyb20oKS5saW5lLCAwKSxcbiAgICAgIHRvOiBjbGlwUG9zKGNtLmRvYywgUG9zKHJhbmdlLnRvKCkubGluZSArIDEsIDApKVxuICAgIH0pOyB9KTsgfSxcbiAgICBkZWxMaW5lTGVmdDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBkZWxldGVOZWFyU2VsZWN0aW9uKGNtLCBmdW5jdGlvbiAocmFuZ2UpIHsgcmV0dXJuICh7XG4gICAgICBmcm9tOiBQb3MocmFuZ2UuZnJvbSgpLmxpbmUsIDApLCB0bzogcmFuZ2UuZnJvbSgpXG4gICAgfSk7IH0pOyB9LFxuICAgIGRlbFdyYXBwZWRMaW5lTGVmdDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBkZWxldGVOZWFyU2VsZWN0aW9uKGNtLCBmdW5jdGlvbiAocmFuZ2UpIHtcbiAgICAgIHZhciB0b3AgPSBjbS5jaGFyQ29vcmRzKHJhbmdlLmhlYWQsIFwiZGl2XCIpLnRvcCArIDU7XG4gICAgICB2YXIgbGVmdFBvcyA9IGNtLmNvb3Jkc0NoYXIoe2xlZnQ6IDAsIHRvcDogdG9wfSwgXCJkaXZcIik7XG4gICAgICByZXR1cm4ge2Zyb206IGxlZnRQb3MsIHRvOiByYW5nZS5mcm9tKCl9XG4gICAgfSk7IH0sXG4gICAgZGVsV3JhcHBlZExpbmVSaWdodDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBkZWxldGVOZWFyU2VsZWN0aW9uKGNtLCBmdW5jdGlvbiAocmFuZ2UpIHtcbiAgICAgIHZhciB0b3AgPSBjbS5jaGFyQ29vcmRzKHJhbmdlLmhlYWQsIFwiZGl2XCIpLnRvcCArIDU7XG4gICAgICB2YXIgcmlnaHRQb3MgPSBjbS5jb29yZHNDaGFyKHtsZWZ0OiBjbS5kaXNwbGF5LmxpbmVEaXYub2Zmc2V0V2lkdGggKyAxMDAsIHRvcDogdG9wfSwgXCJkaXZcIik7XG4gICAgICByZXR1cm4ge2Zyb206IHJhbmdlLmZyb20oKSwgdG86IHJpZ2h0UG9zIH1cbiAgICB9KTsgfSxcbiAgICB1bmRvOiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLnVuZG8oKTsgfSxcbiAgICByZWRvOiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLnJlZG8oKTsgfSxcbiAgICB1bmRvU2VsZWN0aW9uOiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLnVuZG9TZWxlY3Rpb24oKTsgfSxcbiAgICByZWRvU2VsZWN0aW9uOiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLnJlZG9TZWxlY3Rpb24oKTsgfSxcbiAgICBnb0RvY1N0YXJ0OiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLmV4dGVuZFNlbGVjdGlvbihQb3MoY20uZmlyc3RMaW5lKCksIDApKTsgfSxcbiAgICBnb0RvY0VuZDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5leHRlbmRTZWxlY3Rpb24oUG9zKGNtLmxhc3RMaW5lKCkpKTsgfSxcbiAgICBnb0xpbmVTdGFydDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24gKHJhbmdlKSB7IHJldHVybiBsaW5lU3RhcnQoY20sIHJhbmdlLmhlYWQubGluZSk7IH0sXG4gICAgICB7b3JpZ2luOiBcIittb3ZlXCIsIGJpYXM6IDF9XG4gICAgKTsgfSxcbiAgICBnb0xpbmVTdGFydFNtYXJ0OiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLmV4dGVuZFNlbGVjdGlvbnNCeShmdW5jdGlvbiAocmFuZ2UpIHsgcmV0dXJuIGxpbmVTdGFydFNtYXJ0KGNtLCByYW5nZS5oZWFkKTsgfSxcbiAgICAgIHtvcmlnaW46IFwiK21vdmVcIiwgYmlhczogMX1cbiAgICApOyB9LFxuICAgIGdvTGluZUVuZDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24gKHJhbmdlKSB7IHJldHVybiBsaW5lRW5kKGNtLCByYW5nZS5oZWFkLmxpbmUpOyB9LFxuICAgICAge29yaWdpbjogXCIrbW92ZVwiLCBiaWFzOiAtMX1cbiAgICApOyB9LFxuICAgIGdvTGluZVJpZ2h0OiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLmV4dGVuZFNlbGVjdGlvbnNCeShmdW5jdGlvbiAocmFuZ2UpIHtcbiAgICAgIHZhciB0b3AgPSBjbS5jdXJzb3JDb29yZHMocmFuZ2UuaGVhZCwgXCJkaXZcIikudG9wICsgNTtcbiAgICAgIHJldHVybiBjbS5jb29yZHNDaGFyKHtsZWZ0OiBjbS5kaXNwbGF5LmxpbmVEaXYub2Zmc2V0V2lkdGggKyAxMDAsIHRvcDogdG9wfSwgXCJkaXZcIilcbiAgICB9LCBzZWxfbW92ZSk7IH0sXG4gICAgZ29MaW5lTGVmdDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5leHRlbmRTZWxlY3Rpb25zQnkoZnVuY3Rpb24gKHJhbmdlKSB7XG4gICAgICB2YXIgdG9wID0gY20uY3Vyc29yQ29vcmRzKHJhbmdlLmhlYWQsIFwiZGl2XCIpLnRvcCArIDU7XG4gICAgICByZXR1cm4gY20uY29vcmRzQ2hhcih7bGVmdDogMCwgdG9wOiB0b3B9LCBcImRpdlwiKVxuICAgIH0sIHNlbF9tb3ZlKTsgfSxcbiAgICBnb0xpbmVMZWZ0U21hcnQ6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20uZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uIChyYW5nZSkge1xuICAgICAgdmFyIHRvcCA9IGNtLmN1cnNvckNvb3JkcyhyYW5nZS5oZWFkLCBcImRpdlwiKS50b3AgKyA1O1xuICAgICAgdmFyIHBvcyA9IGNtLmNvb3Jkc0NoYXIoe2xlZnQ6IDAsIHRvcDogdG9wfSwgXCJkaXZcIik7XG4gICAgICBpZiAocG9zLmNoIDwgY20uZ2V0TGluZShwb3MubGluZSkuc2VhcmNoKC9cXFMvKSkgeyByZXR1cm4gbGluZVN0YXJ0U21hcnQoY20sIHJhbmdlLmhlYWQpIH1cbiAgICAgIHJldHVybiBwb3NcbiAgICB9LCBzZWxfbW92ZSk7IH0sXG4gICAgZ29MaW5lVXA6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20ubW92ZVYoLTEsIFwibGluZVwiKTsgfSxcbiAgICBnb0xpbmVEb3duOiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLm1vdmVWKDEsIFwibGluZVwiKTsgfSxcbiAgICBnb1BhZ2VVcDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5tb3ZlVigtMSwgXCJwYWdlXCIpOyB9LFxuICAgIGdvUGFnZURvd246IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20ubW92ZVYoMSwgXCJwYWdlXCIpOyB9LFxuICAgIGdvQ2hhckxlZnQ6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20ubW92ZUgoLTEsIFwiY2hhclwiKTsgfSxcbiAgICBnb0NoYXJSaWdodDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5tb3ZlSCgxLCBcImNoYXJcIik7IH0sXG4gICAgZ29Db2x1bW5MZWZ0OiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLm1vdmVIKC0xLCBcImNvbHVtblwiKTsgfSxcbiAgICBnb0NvbHVtblJpZ2h0OiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLm1vdmVIKDEsIFwiY29sdW1uXCIpOyB9LFxuICAgIGdvV29yZExlZnQ6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20ubW92ZUgoLTEsIFwid29yZFwiKTsgfSxcbiAgICBnb0dyb3VwUmlnaHQ6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20ubW92ZUgoMSwgXCJncm91cFwiKTsgfSxcbiAgICBnb0dyb3VwTGVmdDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5tb3ZlSCgtMSwgXCJncm91cFwiKTsgfSxcbiAgICBnb1dvcmRSaWdodDogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5tb3ZlSCgxLCBcIndvcmRcIik7IH0sXG4gICAgZGVsQ2hhckJlZm9yZTogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5kZWxldGVIKC0xLCBcImNoYXJcIik7IH0sXG4gICAgZGVsQ2hhckFmdGVyOiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLmRlbGV0ZUgoMSwgXCJjaGFyXCIpOyB9LFxuICAgIGRlbFdvcmRCZWZvcmU6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20uZGVsZXRlSCgtMSwgXCJ3b3JkXCIpOyB9LFxuICAgIGRlbFdvcmRBZnRlcjogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5kZWxldGVIKDEsIFwid29yZFwiKTsgfSxcbiAgICBkZWxHcm91cEJlZm9yZTogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5kZWxldGVIKC0xLCBcImdyb3VwXCIpOyB9LFxuICAgIGRlbEdyb3VwQWZ0ZXI6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20uZGVsZXRlSCgxLCBcImdyb3VwXCIpOyB9LFxuICAgIGluZGVudEF1dG86IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20uaW5kZW50U2VsZWN0aW9uKFwic21hcnRcIik7IH0sXG4gICAgaW5kZW50TW9yZTogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5pbmRlbnRTZWxlY3Rpb24oXCJhZGRcIik7IH0sXG4gICAgaW5kZW50TGVzczogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5pbmRlbnRTZWxlY3Rpb24oXCJzdWJ0cmFjdFwiKTsgfSxcbiAgICBpbnNlcnRUYWI6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20ucmVwbGFjZVNlbGVjdGlvbihcIlxcdFwiKTsgfSxcbiAgICBpbnNlcnRTb2Z0VGFiOiBmdW5jdGlvbiAoY20pIHtcbiAgICAgIHZhciBzcGFjZXMgPSBbXSwgcmFuZ2VzID0gY20ubGlzdFNlbGVjdGlvbnMoKSwgdGFiU2l6ZSA9IGNtLm9wdGlvbnMudGFiU2l6ZTtcbiAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmFuZ2VzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIHZhciBwb3MgPSByYW5nZXNbaV0uZnJvbSgpO1xuICAgICAgICB2YXIgY29sID0gY291bnRDb2x1bW4oY20uZ2V0TGluZShwb3MubGluZSksIHBvcy5jaCwgdGFiU2l6ZSk7XG4gICAgICAgIHNwYWNlcy5wdXNoKHNwYWNlU3RyKHRhYlNpemUgLSBjb2wgJSB0YWJTaXplKSk7XG4gICAgICB9XG4gICAgICBjbS5yZXBsYWNlU2VsZWN0aW9ucyhzcGFjZXMpO1xuICAgIH0sXG4gICAgZGVmYXVsdFRhYjogZnVuY3Rpb24gKGNtKSB7XG4gICAgICBpZiAoY20uc29tZXRoaW5nU2VsZWN0ZWQoKSkgeyBjbS5pbmRlbnRTZWxlY3Rpb24oXCJhZGRcIik7IH1cbiAgICAgIGVsc2UgeyBjbS5leGVjQ29tbWFuZChcImluc2VydFRhYlwiKTsgfVxuICAgIH0sXG4gICAgLy8gU3dhcCB0aGUgdHdvIGNoYXJzIGxlZnQgYW5kIHJpZ2h0IG9mIGVhY2ggc2VsZWN0aW9uJ3MgaGVhZC5cbiAgICAvLyBNb3ZlIGN1cnNvciBiZWhpbmQgdGhlIHR3byBzd2FwcGVkIGNoYXJhY3RlcnMgYWZ0ZXJ3YXJkcy5cbiAgICAvL1xuICAgIC8vIERvZXNuJ3QgY29uc2lkZXIgbGluZSBmZWVkcyBhIGNoYXJhY3Rlci5cbiAgICAvLyBEb2Vzbid0IHNjYW4gbW9yZSB0aGFuIG9uZSBsaW5lIGFib3ZlIHRvIGZpbmQgYSBjaGFyYWN0ZXIuXG4gICAgLy8gRG9lc24ndCBkbyBhbnl0aGluZyBvbiBhbiBlbXB0eSBsaW5lLlxuICAgIC8vIERvZXNuJ3QgZG8gYW55dGhpbmcgd2l0aCBub24tZW1wdHkgc2VsZWN0aW9ucy5cbiAgICB0cmFuc3Bvc2VDaGFyczogZnVuY3Rpb24gKGNtKSB7IHJldHVybiBydW5Jbk9wKGNtLCBmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgcmFuZ2VzID0gY20ubGlzdFNlbGVjdGlvbnMoKSwgbmV3U2VsID0gW107XG4gICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHJhbmdlcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoIXJhbmdlc1tpXS5lbXB0eSgpKSB7IGNvbnRpbnVlIH1cbiAgICAgICAgdmFyIGN1ciA9IHJhbmdlc1tpXS5oZWFkLCBsaW5lID0gZ2V0TGluZShjbS5kb2MsIGN1ci5saW5lKS50ZXh0O1xuICAgICAgICBpZiAobGluZSkge1xuICAgICAgICAgIGlmIChjdXIuY2ggPT0gbGluZS5sZW5ndGgpIHsgY3VyID0gbmV3IFBvcyhjdXIubGluZSwgY3VyLmNoIC0gMSk7IH1cbiAgICAgICAgICBpZiAoY3VyLmNoID4gMCkge1xuICAgICAgICAgICAgY3VyID0gbmV3IFBvcyhjdXIubGluZSwgY3VyLmNoICsgMSk7XG4gICAgICAgICAgICBjbS5yZXBsYWNlUmFuZ2UobGluZS5jaGFyQXQoY3VyLmNoIC0gMSkgKyBsaW5lLmNoYXJBdChjdXIuY2ggLSAyKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBQb3MoY3VyLmxpbmUsIGN1ci5jaCAtIDIpLCBjdXIsIFwiK3RyYW5zcG9zZVwiKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGN1ci5saW5lID4gY20uZG9jLmZpcnN0KSB7XG4gICAgICAgICAgICB2YXIgcHJldiA9IGdldExpbmUoY20uZG9jLCBjdXIubGluZSAtIDEpLnRleHQ7XG4gICAgICAgICAgICBpZiAocHJldikge1xuICAgICAgICAgICAgICBjdXIgPSBuZXcgUG9zKGN1ci5saW5lLCAxKTtcbiAgICAgICAgICAgICAgY20ucmVwbGFjZVJhbmdlKGxpbmUuY2hhckF0KDApICsgY20uZG9jLmxpbmVTZXBhcmF0b3IoKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2LmNoYXJBdChwcmV2Lmxlbmd0aCAtIDEpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgUG9zKGN1ci5saW5lIC0gMSwgcHJldi5sZW5ndGggLSAxKSwgY3VyLCBcIit0cmFuc3Bvc2VcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIG5ld1NlbC5wdXNoKG5ldyBSYW5nZShjdXIsIGN1cikpO1xuICAgICAgfVxuICAgICAgY20uc2V0U2VsZWN0aW9ucyhuZXdTZWwpO1xuICAgIH0pOyB9LFxuICAgIG5ld2xpbmVBbmRJbmRlbnQ6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gcnVuSW5PcChjbSwgZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIHNlbHMgPSBjbS5saXN0U2VsZWN0aW9ucygpO1xuICAgICAgZm9yICh2YXIgaSA9IHNlbHMubGVuZ3RoIC0gMTsgaSA+PSAwOyBpLS0pXG4gICAgICAgIHsgY20ucmVwbGFjZVJhbmdlKGNtLmRvYy5saW5lU2VwYXJhdG9yKCksIHNlbHNbaV0uYW5jaG9yLCBzZWxzW2ldLmhlYWQsIFwiK2lucHV0XCIpOyB9XG4gICAgICBzZWxzID0gY20ubGlzdFNlbGVjdGlvbnMoKTtcbiAgICAgIGZvciAodmFyIGkkMSA9IDA7IGkkMSA8IHNlbHMubGVuZ3RoOyBpJDErKylcbiAgICAgICAgeyBjbS5pbmRlbnRMaW5lKHNlbHNbaSQxXS5mcm9tKCkubGluZSwgbnVsbCwgdHJ1ZSk7IH1cbiAgICAgIGVuc3VyZUN1cnNvclZpc2libGUoY20pO1xuICAgIH0pOyB9LFxuICAgIG9wZW5MaW5lOiBmdW5jdGlvbiAoY20pIHsgcmV0dXJuIGNtLnJlcGxhY2VTZWxlY3Rpb24oXCJcXG5cIiwgXCJzdGFydFwiKTsgfSxcbiAgICB0b2dnbGVPdmVyd3JpdGU6IGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20udG9nZ2xlT3ZlcndyaXRlKCk7IH1cbiAgfTtcblxuXG4gIGZ1bmN0aW9uIGxpbmVTdGFydChjbSwgbGluZU4pIHtcbiAgICB2YXIgbGluZSA9IGdldExpbmUoY20uZG9jLCBsaW5lTik7XG4gICAgdmFyIHZpc3VhbCA9IHZpc3VhbExpbmUobGluZSk7XG4gICAgaWYgKHZpc3VhbCAhPSBsaW5lKSB7IGxpbmVOID0gbGluZU5vKHZpc3VhbCk7IH1cbiAgICByZXR1cm4gZW5kT2ZMaW5lKHRydWUsIGNtLCB2aXN1YWwsIGxpbmVOLCAxKVxuICB9XG4gIGZ1bmN0aW9uIGxpbmVFbmQoY20sIGxpbmVOKSB7XG4gICAgdmFyIGxpbmUgPSBnZXRMaW5lKGNtLmRvYywgbGluZU4pO1xuICAgIHZhciB2aXN1YWwgPSB2aXN1YWxMaW5lRW5kKGxpbmUpO1xuICAgIGlmICh2aXN1YWwgIT0gbGluZSkgeyBsaW5lTiA9IGxpbmVObyh2aXN1YWwpOyB9XG4gICAgcmV0dXJuIGVuZE9mTGluZSh0cnVlLCBjbSwgbGluZSwgbGluZU4sIC0xKVxuICB9XG4gIGZ1bmN0aW9uIGxpbmVTdGFydFNtYXJ0KGNtLCBwb3MpIHtcbiAgICB2YXIgc3RhcnQgPSBsaW5lU3RhcnQoY20sIHBvcy5saW5lKTtcbiAgICB2YXIgbGluZSA9IGdldExpbmUoY20uZG9jLCBzdGFydC5saW5lKTtcbiAgICB2YXIgb3JkZXIgPSBnZXRPcmRlcihsaW5lLCBjbS5kb2MuZGlyZWN0aW9uKTtcbiAgICBpZiAoIW9yZGVyIHx8IG9yZGVyWzBdLmxldmVsID09IDApIHtcbiAgICAgIHZhciBmaXJzdE5vbldTID0gTWF0aC5tYXgoMCwgbGluZS50ZXh0LnNlYXJjaCgvXFxTLykpO1xuICAgICAgdmFyIGluV1MgPSBwb3MubGluZSA9PSBzdGFydC5saW5lICYmIHBvcy5jaCA8PSBmaXJzdE5vbldTICYmIHBvcy5jaDtcbiAgICAgIHJldHVybiBQb3Moc3RhcnQubGluZSwgaW5XUyA/IDAgOiBmaXJzdE5vbldTLCBzdGFydC5zdGlja3kpXG4gICAgfVxuICAgIHJldHVybiBzdGFydFxuICB9XG5cbiAgLy8gUnVuIGEgaGFuZGxlciB0aGF0IHdhcyBib3VuZCB0byBhIGtleS5cbiAgZnVuY3Rpb24gZG9IYW5kbGVCaW5kaW5nKGNtLCBib3VuZCwgZHJvcFNoaWZ0KSB7XG4gICAgaWYgKHR5cGVvZiBib3VuZCA9PSBcInN0cmluZ1wiKSB7XG4gICAgICBib3VuZCA9IGNvbW1hbmRzW2JvdW5kXTtcbiAgICAgIGlmICghYm91bmQpIHsgcmV0dXJuIGZhbHNlIH1cbiAgICB9XG4gICAgLy8gRW5zdXJlIHByZXZpb3VzIGlucHV0IGhhcyBiZWVuIHJlYWQsIHNvIHRoYXQgdGhlIGhhbmRsZXIgc2VlcyBhXG4gICAgLy8gY29uc2lzdGVudCB2aWV3IG9mIHRoZSBkb2N1bWVudFxuICAgIGNtLmRpc3BsYXkuaW5wdXQuZW5zdXJlUG9sbGVkKCk7XG4gICAgdmFyIHByZXZTaGlmdCA9IGNtLmRpc3BsYXkuc2hpZnQsIGRvbmUgPSBmYWxzZTtcbiAgICB0cnkge1xuICAgICAgaWYgKGNtLmlzUmVhZE9ubHkoKSkgeyBjbS5zdGF0ZS5zdXBwcmVzc0VkaXRzID0gdHJ1ZTsgfVxuICAgICAgaWYgKGRyb3BTaGlmdCkgeyBjbS5kaXNwbGF5LnNoaWZ0ID0gZmFsc2U7IH1cbiAgICAgIGRvbmUgPSBib3VuZChjbSkgIT0gUGFzcztcbiAgICB9IGZpbmFsbHkge1xuICAgICAgY20uZGlzcGxheS5zaGlmdCA9IHByZXZTaGlmdDtcbiAgICAgIGNtLnN0YXRlLnN1cHByZXNzRWRpdHMgPSBmYWxzZTtcbiAgICB9XG4gICAgcmV0dXJuIGRvbmVcbiAgfVxuXG4gIGZ1bmN0aW9uIGxvb2t1cEtleUZvckVkaXRvcihjbSwgbmFtZSwgaGFuZGxlKSB7XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjbS5zdGF0ZS5rZXlNYXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgcmVzdWx0ID0gbG9va3VwS2V5KG5hbWUsIGNtLnN0YXRlLmtleU1hcHNbaV0sIGhhbmRsZSwgY20pO1xuICAgICAgaWYgKHJlc3VsdCkgeyByZXR1cm4gcmVzdWx0IH1cbiAgICB9XG4gICAgcmV0dXJuIChjbS5vcHRpb25zLmV4dHJhS2V5cyAmJiBsb29rdXBLZXkobmFtZSwgY20ub3B0aW9ucy5leHRyYUtleXMsIGhhbmRsZSwgY20pKVxuICAgICAgfHwgbG9va3VwS2V5KG5hbWUsIGNtLm9wdGlvbnMua2V5TWFwLCBoYW5kbGUsIGNtKVxuICB9XG5cbiAgLy8gTm90ZSB0aGF0LCBkZXNwaXRlIHRoZSBuYW1lLCB0aGlzIGZ1bmN0aW9uIGlzIGFsc28gdXNlZCB0byBjaGVja1xuICAvLyBmb3IgYm91bmQgbW91c2UgY2xpY2tzLlxuXG4gIHZhciBzdG9wU2VxID0gbmV3IERlbGF5ZWQ7XG5cbiAgZnVuY3Rpb24gZGlzcGF0Y2hLZXkoY20sIG5hbWUsIGUsIGhhbmRsZSkge1xuICAgIHZhciBzZXEgPSBjbS5zdGF0ZS5rZXlTZXE7XG4gICAgaWYgKHNlcSkge1xuICAgICAgaWYgKGlzTW9kaWZpZXJLZXkobmFtZSkpIHsgcmV0dXJuIFwiaGFuZGxlZFwiIH1cbiAgICAgIGlmICgvXFwnJC8udGVzdChuYW1lKSlcbiAgICAgICAgeyBjbS5zdGF0ZS5rZXlTZXEgPSBudWxsOyB9XG4gICAgICBlbHNlXG4gICAgICAgIHsgc3RvcFNlcS5zZXQoNTAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBpZiAoY20uc3RhdGUua2V5U2VxID09IHNlcSkge1xuICAgICAgICAgICAgY20uc3RhdGUua2V5U2VxID0gbnVsbDtcbiAgICAgICAgICAgIGNtLmRpc3BsYXkuaW5wdXQucmVzZXQoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0pOyB9XG4gICAgICBpZiAoZGlzcGF0Y2hLZXlJbm5lcihjbSwgc2VxICsgXCIgXCIgKyBuYW1lLCBlLCBoYW5kbGUpKSB7IHJldHVybiB0cnVlIH1cbiAgICB9XG4gICAgcmV0dXJuIGRpc3BhdGNoS2V5SW5uZXIoY20sIG5hbWUsIGUsIGhhbmRsZSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGRpc3BhdGNoS2V5SW5uZXIoY20sIG5hbWUsIGUsIGhhbmRsZSkge1xuICAgIHZhciByZXN1bHQgPSBsb29rdXBLZXlGb3JFZGl0b3IoY20sIG5hbWUsIGhhbmRsZSk7XG5cbiAgICBpZiAocmVzdWx0ID09IFwibXVsdGlcIilcbiAgICAgIHsgY20uc3RhdGUua2V5U2VxID0gbmFtZTsgfVxuICAgIGlmIChyZXN1bHQgPT0gXCJoYW5kbGVkXCIpXG4gICAgICB7IHNpZ25hbExhdGVyKGNtLCBcImtleUhhbmRsZWRcIiwgY20sIG5hbWUsIGUpOyB9XG5cbiAgICBpZiAocmVzdWx0ID09IFwiaGFuZGxlZFwiIHx8IHJlc3VsdCA9PSBcIm11bHRpXCIpIHtcbiAgICAgIGVfcHJldmVudERlZmF1bHQoZSk7XG4gICAgICByZXN0YXJ0QmxpbmsoY20pO1xuICAgIH1cblxuICAgIHJldHVybiAhIXJlc3VsdFxuICB9XG5cbiAgLy8gSGFuZGxlIGEga2V5IGZyb20gdGhlIGtleWRvd24gZXZlbnQuXG4gIGZ1bmN0aW9uIGhhbmRsZUtleUJpbmRpbmcoY20sIGUpIHtcbiAgICB2YXIgbmFtZSA9IGtleU5hbWUoZSwgdHJ1ZSk7XG4gICAgaWYgKCFuYW1lKSB7IHJldHVybiBmYWxzZSB9XG5cbiAgICBpZiAoZS5zaGlmdEtleSAmJiAhY20uc3RhdGUua2V5U2VxKSB7XG4gICAgICAvLyBGaXJzdCB0cnkgdG8gcmVzb2x2ZSBmdWxsIG5hbWUgKGluY2x1ZGluZyAnU2hpZnQtJykuIEZhaWxpbmdcbiAgICAgIC8vIHRoYXQsIHNlZSBpZiB0aGVyZSBpcyBhIGN1cnNvci1tb3Rpb24gY29tbWFuZCAoc3RhcnRpbmcgd2l0aFxuICAgICAgLy8gJ2dvJykgYm91bmQgdG8gdGhlIGtleW5hbWUgd2l0aG91dCAnU2hpZnQtJy5cbiAgICAgIHJldHVybiBkaXNwYXRjaEtleShjbSwgXCJTaGlmdC1cIiArIG5hbWUsIGUsIGZ1bmN0aW9uIChiKSB7IHJldHVybiBkb0hhbmRsZUJpbmRpbmcoY20sIGIsIHRydWUpOyB9KVxuICAgICAgICAgIHx8IGRpc3BhdGNoS2V5KGNtLCBuYW1lLCBlLCBmdW5jdGlvbiAoYikge1xuICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBiID09IFwic3RyaW5nXCIgPyAvXmdvW0EtWl0vLnRlc3QoYikgOiBiLm1vdGlvbilcbiAgICAgICAgICAgICAgICAgeyByZXR1cm4gZG9IYW5kbGVCaW5kaW5nKGNtLCBiKSB9XG4gICAgICAgICAgICAgfSlcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIGRpc3BhdGNoS2V5KGNtLCBuYW1lLCBlLCBmdW5jdGlvbiAoYikgeyByZXR1cm4gZG9IYW5kbGVCaW5kaW5nKGNtLCBiKTsgfSlcbiAgICB9XG4gIH1cblxuICAvLyBIYW5kbGUgYSBrZXkgZnJvbSB0aGUga2V5cHJlc3MgZXZlbnRcbiAgZnVuY3Rpb24gaGFuZGxlQ2hhckJpbmRpbmcoY20sIGUsIGNoKSB7XG4gICAgcmV0dXJuIGRpc3BhdGNoS2V5KGNtLCBcIidcIiArIGNoICsgXCInXCIsIGUsIGZ1bmN0aW9uIChiKSB7IHJldHVybiBkb0hhbmRsZUJpbmRpbmcoY20sIGIsIHRydWUpOyB9KVxuICB9XG5cbiAgdmFyIGxhc3RTdG9wcGVkS2V5ID0gbnVsbDtcbiAgZnVuY3Rpb24gb25LZXlEb3duKGUpIHtcbiAgICB2YXIgY20gPSB0aGlzO1xuICAgIGNtLmN1ck9wLmZvY3VzID0gYWN0aXZlRWx0KCk7XG4gICAgaWYgKHNpZ25hbERPTUV2ZW50KGNtLCBlKSkgeyByZXR1cm4gfVxuICAgIC8vIElFIGRvZXMgc3RyYW5nZSB0aGluZ3Mgd2l0aCBlc2NhcGUuXG4gICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCAxMSAmJiBlLmtleUNvZGUgPT0gMjcpIHsgZS5yZXR1cm5WYWx1ZSA9IGZhbHNlOyB9XG4gICAgdmFyIGNvZGUgPSBlLmtleUNvZGU7XG4gICAgY20uZGlzcGxheS5zaGlmdCA9IGNvZGUgPT0gMTYgfHwgZS5zaGlmdEtleTtcbiAgICB2YXIgaGFuZGxlZCA9IGhhbmRsZUtleUJpbmRpbmcoY20sIGUpO1xuICAgIGlmIChwcmVzdG8pIHtcbiAgICAgIGxhc3RTdG9wcGVkS2V5ID0gaGFuZGxlZCA/IGNvZGUgOiBudWxsO1xuICAgICAgLy8gT3BlcmEgaGFzIG5vIGN1dCBldmVudC4uLiB3ZSB0cnkgdG8gYXQgbGVhc3QgY2F0Y2ggdGhlIGtleSBjb21ib1xuICAgICAgaWYgKCFoYW5kbGVkICYmIGNvZGUgPT0gODggJiYgIWhhc0NvcHlFdmVudCAmJiAobWFjID8gZS5tZXRhS2V5IDogZS5jdHJsS2V5KSlcbiAgICAgICAgeyBjbS5yZXBsYWNlU2VsZWN0aW9uKFwiXCIsIG51bGwsIFwiY3V0XCIpOyB9XG4gICAgfVxuXG4gICAgLy8gVHVybiBtb3VzZSBpbnRvIGNyb3NzaGFpciB3aGVuIEFsdCBpcyBoZWxkIG9uIE1hYy5cbiAgICBpZiAoY29kZSA9PSAxOCAmJiAhL1xcYkNvZGVNaXJyb3ItY3Jvc3NoYWlyXFxiLy50ZXN0KGNtLmRpc3BsYXkubGluZURpdi5jbGFzc05hbWUpKVxuICAgICAgeyBzaG93Q3Jvc3NIYWlyKGNtKTsgfVxuICB9XG5cbiAgZnVuY3Rpb24gc2hvd0Nyb3NzSGFpcihjbSkge1xuICAgIHZhciBsaW5lRGl2ID0gY20uZGlzcGxheS5saW5lRGl2O1xuICAgIGFkZENsYXNzKGxpbmVEaXYsIFwiQ29kZU1pcnJvci1jcm9zc2hhaXJcIik7XG5cbiAgICBmdW5jdGlvbiB1cChlKSB7XG4gICAgICBpZiAoZS5rZXlDb2RlID09IDE4IHx8ICFlLmFsdEtleSkge1xuICAgICAgICBybUNsYXNzKGxpbmVEaXYsIFwiQ29kZU1pcnJvci1jcm9zc2hhaXJcIik7XG4gICAgICAgIG9mZihkb2N1bWVudCwgXCJrZXl1cFwiLCB1cCk7XG4gICAgICAgIG9mZihkb2N1bWVudCwgXCJtb3VzZW92ZXJcIiwgdXApO1xuICAgICAgfVxuICAgIH1cbiAgICBvbihkb2N1bWVudCwgXCJrZXl1cFwiLCB1cCk7XG4gICAgb24oZG9jdW1lbnQsIFwibW91c2VvdmVyXCIsIHVwKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG9uS2V5VXAoZSkge1xuICAgIGlmIChlLmtleUNvZGUgPT0gMTYpIHsgdGhpcy5kb2Muc2VsLnNoaWZ0ID0gZmFsc2U7IH1cbiAgICBzaWduYWxET01FdmVudCh0aGlzLCBlKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIG9uS2V5UHJlc3MoZSkge1xuICAgIHZhciBjbSA9IHRoaXM7XG4gICAgaWYgKGV2ZW50SW5XaWRnZXQoY20uZGlzcGxheSwgZSkgfHwgc2lnbmFsRE9NRXZlbnQoY20sIGUpIHx8IGUuY3RybEtleSAmJiAhZS5hbHRLZXkgfHwgbWFjICYmIGUubWV0YUtleSkgeyByZXR1cm4gfVxuICAgIHZhciBrZXlDb2RlID0gZS5rZXlDb2RlLCBjaGFyQ29kZSA9IGUuY2hhckNvZGU7XG4gICAgaWYgKHByZXN0byAmJiBrZXlDb2RlID09IGxhc3RTdG9wcGVkS2V5KSB7bGFzdFN0b3BwZWRLZXkgPSBudWxsOyBlX3ByZXZlbnREZWZhdWx0KGUpOyByZXR1cm59XG4gICAgaWYgKChwcmVzdG8gJiYgKCFlLndoaWNoIHx8IGUud2hpY2ggPCAxMCkpICYmIGhhbmRsZUtleUJpbmRpbmcoY20sIGUpKSB7IHJldHVybiB9XG4gICAgdmFyIGNoID0gU3RyaW5nLmZyb21DaGFyQ29kZShjaGFyQ29kZSA9PSBudWxsID8ga2V5Q29kZSA6IGNoYXJDb2RlKTtcbiAgICAvLyBTb21lIGJyb3dzZXJzIGZpcmUga2V5cHJlc3MgZXZlbnRzIGZvciBiYWNrc3BhY2VcbiAgICBpZiAoY2ggPT0gXCJcXHgwOFwiKSB7IHJldHVybiB9XG4gICAgaWYgKGhhbmRsZUNoYXJCaW5kaW5nKGNtLCBlLCBjaCkpIHsgcmV0dXJuIH1cbiAgICBjbS5kaXNwbGF5LmlucHV0Lm9uS2V5UHJlc3MoZSk7XG4gIH1cblxuICB2YXIgRE9VQkxFQ0xJQ0tfREVMQVkgPSA0MDA7XG5cbiAgdmFyIFBhc3RDbGljayA9IGZ1bmN0aW9uKHRpbWUsIHBvcywgYnV0dG9uKSB7XG4gICAgdGhpcy50aW1lID0gdGltZTtcbiAgICB0aGlzLnBvcyA9IHBvcztcbiAgICB0aGlzLmJ1dHRvbiA9IGJ1dHRvbjtcbiAgfTtcblxuICBQYXN0Q2xpY2sucHJvdG90eXBlLmNvbXBhcmUgPSBmdW5jdGlvbiAodGltZSwgcG9zLCBidXR0b24pIHtcbiAgICByZXR1cm4gdGhpcy50aW1lICsgRE9VQkxFQ0xJQ0tfREVMQVkgPiB0aW1lICYmXG4gICAgICBjbXAocG9zLCB0aGlzLnBvcykgPT0gMCAmJiBidXR0b24gPT0gdGhpcy5idXR0b25cbiAgfTtcblxuICB2YXIgbGFzdENsaWNrLCBsYXN0RG91YmxlQ2xpY2s7XG4gIGZ1bmN0aW9uIGNsaWNrUmVwZWF0KHBvcywgYnV0dG9uKSB7XG4gICAgdmFyIG5vdyA9ICtuZXcgRGF0ZTtcbiAgICBpZiAobGFzdERvdWJsZUNsaWNrICYmIGxhc3REb3VibGVDbGljay5jb21wYXJlKG5vdywgcG9zLCBidXR0b24pKSB7XG4gICAgICBsYXN0Q2xpY2sgPSBsYXN0RG91YmxlQ2xpY2sgPSBudWxsO1xuICAgICAgcmV0dXJuIFwidHJpcGxlXCJcbiAgICB9IGVsc2UgaWYgKGxhc3RDbGljayAmJiBsYXN0Q2xpY2suY29tcGFyZShub3csIHBvcywgYnV0dG9uKSkge1xuICAgICAgbGFzdERvdWJsZUNsaWNrID0gbmV3IFBhc3RDbGljayhub3csIHBvcywgYnV0dG9uKTtcbiAgICAgIGxhc3RDbGljayA9IG51bGw7XG4gICAgICByZXR1cm4gXCJkb3VibGVcIlxuICAgIH0gZWxzZSB7XG4gICAgICBsYXN0Q2xpY2sgPSBuZXcgUGFzdENsaWNrKG5vdywgcG9zLCBidXR0b24pO1xuICAgICAgbGFzdERvdWJsZUNsaWNrID0gbnVsbDtcbiAgICAgIHJldHVybiBcInNpbmdsZVwiXG4gICAgfVxuICB9XG5cbiAgLy8gQSBtb3VzZSBkb3duIGNhbiBiZSBhIHNpbmdsZSBjbGljaywgZG91YmxlIGNsaWNrLCB0cmlwbGUgY2xpY2ssXG4gIC8vIHN0YXJ0IG9mIHNlbGVjdGlvbiBkcmFnLCBzdGFydCBvZiB0ZXh0IGRyYWcsIG5ldyBjdXJzb3JcbiAgLy8gKGN0cmwtY2xpY2spLCByZWN0YW5nbGUgZHJhZyAoYWx0LWRyYWcpLCBvciB4d2luXG4gIC8vIG1pZGRsZS1jbGljay1wYXN0ZS4gT3IgaXQgbWlnaHQgYmUgYSBjbGljayBvbiBzb21ldGhpbmcgd2Ugc2hvdWxkXG4gIC8vIG5vdCBpbnRlcmZlcmUgd2l0aCwgc3VjaCBhcyBhIHNjcm9sbGJhciBvciB3aWRnZXQuXG4gIGZ1bmN0aW9uIG9uTW91c2VEb3duKGUpIHtcbiAgICB2YXIgY20gPSB0aGlzLCBkaXNwbGF5ID0gY20uZGlzcGxheTtcbiAgICBpZiAoc2lnbmFsRE9NRXZlbnQoY20sIGUpIHx8IGRpc3BsYXkuYWN0aXZlVG91Y2ggJiYgZGlzcGxheS5pbnB1dC5zdXBwb3J0c1RvdWNoKCkpIHsgcmV0dXJuIH1cbiAgICBkaXNwbGF5LmlucHV0LmVuc3VyZVBvbGxlZCgpO1xuICAgIGRpc3BsYXkuc2hpZnQgPSBlLnNoaWZ0S2V5O1xuXG4gICAgaWYgKGV2ZW50SW5XaWRnZXQoZGlzcGxheSwgZSkpIHtcbiAgICAgIGlmICghd2Via2l0KSB7XG4gICAgICAgIC8vIEJyaWVmbHkgdHVybiBvZmYgZHJhZ2dhYmlsaXR5LCB0byBhbGxvdyB3aWRnZXRzIHRvIGRvXG4gICAgICAgIC8vIG5vcm1hbCBkcmFnZ2luZyB0aGluZ3MuXG4gICAgICAgIGRpc3BsYXkuc2Nyb2xsZXIuZHJhZ2dhYmxlID0gZmFsc2U7XG4gICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyByZXR1cm4gZGlzcGxheS5zY3JvbGxlci5kcmFnZ2FibGUgPSB0cnVlOyB9LCAxMDApO1xuICAgICAgfVxuICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGlmIChjbGlja0luR3V0dGVyKGNtLCBlKSkgeyByZXR1cm4gfVxuICAgIHZhciBwb3MgPSBwb3NGcm9tTW91c2UoY20sIGUpLCBidXR0b24gPSBlX2J1dHRvbihlKSwgcmVwZWF0ID0gcG9zID8gY2xpY2tSZXBlYXQocG9zLCBidXR0b24pIDogXCJzaW5nbGVcIjtcbiAgICB3aW5kb3cuZm9jdXMoKTtcblxuICAgIC8vICMzMjYxOiBtYWtlIHN1cmUsIHRoYXQgd2UncmUgbm90IHN0YXJ0aW5nIGEgc2Vjb25kIHNlbGVjdGlvblxuICAgIGlmIChidXR0b24gPT0gMSAmJiBjbS5zdGF0ZS5zZWxlY3RpbmdUZXh0KVxuICAgICAgeyBjbS5zdGF0ZS5zZWxlY3RpbmdUZXh0KGUpOyB9XG5cbiAgICBpZiAocG9zICYmIGhhbmRsZU1hcHBlZEJ1dHRvbihjbSwgYnV0dG9uLCBwb3MsIHJlcGVhdCwgZSkpIHsgcmV0dXJuIH1cblxuICAgIGlmIChidXR0b24gPT0gMSkge1xuICAgICAgaWYgKHBvcykgeyBsZWZ0QnV0dG9uRG93bihjbSwgcG9zLCByZXBlYXQsIGUpOyB9XG4gICAgICBlbHNlIGlmIChlX3RhcmdldChlKSA9PSBkaXNwbGF5LnNjcm9sbGVyKSB7IGVfcHJldmVudERlZmF1bHQoZSk7IH1cbiAgICB9IGVsc2UgaWYgKGJ1dHRvbiA9PSAyKSB7XG4gICAgICBpZiAocG9zKSB7IGV4dGVuZFNlbGVjdGlvbihjbS5kb2MsIHBvcyk7IH1cbiAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyByZXR1cm4gZGlzcGxheS5pbnB1dC5mb2N1cygpOyB9LCAyMCk7XG4gICAgfSBlbHNlIGlmIChidXR0b24gPT0gMykge1xuICAgICAgaWYgKGNhcHR1cmVSaWdodENsaWNrKSB7IGNtLmRpc3BsYXkuaW5wdXQub25Db250ZXh0TWVudShlKTsgfVxuICAgICAgZWxzZSB7IGRlbGF5Qmx1ckV2ZW50KGNtKTsgfVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGhhbmRsZU1hcHBlZEJ1dHRvbihjbSwgYnV0dG9uLCBwb3MsIHJlcGVhdCwgZXZlbnQpIHtcbiAgICB2YXIgbmFtZSA9IFwiQ2xpY2tcIjtcbiAgICBpZiAocmVwZWF0ID09IFwiZG91YmxlXCIpIHsgbmFtZSA9IFwiRG91YmxlXCIgKyBuYW1lOyB9XG4gICAgZWxzZSBpZiAocmVwZWF0ID09IFwidHJpcGxlXCIpIHsgbmFtZSA9IFwiVHJpcGxlXCIgKyBuYW1lOyB9XG4gICAgbmFtZSA9IChidXR0b24gPT0gMSA/IFwiTGVmdFwiIDogYnV0dG9uID09IDIgPyBcIk1pZGRsZVwiIDogXCJSaWdodFwiKSArIG5hbWU7XG5cbiAgICByZXR1cm4gZGlzcGF0Y2hLZXkoY20sICBhZGRNb2RpZmllck5hbWVzKG5hbWUsIGV2ZW50KSwgZXZlbnQsIGZ1bmN0aW9uIChib3VuZCkge1xuICAgICAgaWYgKHR5cGVvZiBib3VuZCA9PSBcInN0cmluZ1wiKSB7IGJvdW5kID0gY29tbWFuZHNbYm91bmRdOyB9XG4gICAgICBpZiAoIWJvdW5kKSB7IHJldHVybiBmYWxzZSB9XG4gICAgICB2YXIgZG9uZSA9IGZhbHNlO1xuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKGNtLmlzUmVhZE9ubHkoKSkgeyBjbS5zdGF0ZS5zdXBwcmVzc0VkaXRzID0gdHJ1ZTsgfVxuICAgICAgICBkb25lID0gYm91bmQoY20sIHBvcykgIT0gUGFzcztcbiAgICAgIH0gZmluYWxseSB7XG4gICAgICAgIGNtLnN0YXRlLnN1cHByZXNzRWRpdHMgPSBmYWxzZTtcbiAgICAgIH1cbiAgICAgIHJldHVybiBkb25lXG4gICAgfSlcbiAgfVxuXG4gIGZ1bmN0aW9uIGNvbmZpZ3VyZU1vdXNlKGNtLCByZXBlYXQsIGV2ZW50KSB7XG4gICAgdmFyIG9wdGlvbiA9IGNtLmdldE9wdGlvbihcImNvbmZpZ3VyZU1vdXNlXCIpO1xuICAgIHZhciB2YWx1ZSA9IG9wdGlvbiA/IG9wdGlvbihjbSwgcmVwZWF0LCBldmVudCkgOiB7fTtcbiAgICBpZiAodmFsdWUudW5pdCA9PSBudWxsKSB7XG4gICAgICB2YXIgcmVjdCA9IGNocm9tZU9TID8gZXZlbnQuc2hpZnRLZXkgJiYgZXZlbnQubWV0YUtleSA6IGV2ZW50LmFsdEtleTtcbiAgICAgIHZhbHVlLnVuaXQgPSByZWN0ID8gXCJyZWN0YW5nbGVcIiA6IHJlcGVhdCA9PSBcInNpbmdsZVwiID8gXCJjaGFyXCIgOiByZXBlYXQgPT0gXCJkb3VibGVcIiA/IFwid29yZFwiIDogXCJsaW5lXCI7XG4gICAgfVxuICAgIGlmICh2YWx1ZS5leHRlbmQgPT0gbnVsbCB8fCBjbS5kb2MuZXh0ZW5kKSB7IHZhbHVlLmV4dGVuZCA9IGNtLmRvYy5leHRlbmQgfHwgZXZlbnQuc2hpZnRLZXk7IH1cbiAgICBpZiAodmFsdWUuYWRkTmV3ID09IG51bGwpIHsgdmFsdWUuYWRkTmV3ID0gbWFjID8gZXZlbnQubWV0YUtleSA6IGV2ZW50LmN0cmxLZXk7IH1cbiAgICBpZiAodmFsdWUubW92ZU9uRHJhZyA9PSBudWxsKSB7IHZhbHVlLm1vdmVPbkRyYWcgPSAhKG1hYyA/IGV2ZW50LmFsdEtleSA6IGV2ZW50LmN0cmxLZXkpOyB9XG4gICAgcmV0dXJuIHZhbHVlXG4gIH1cblxuICBmdW5jdGlvbiBsZWZ0QnV0dG9uRG93bihjbSwgcG9zLCByZXBlYXQsIGV2ZW50KSB7XG4gICAgaWYgKGllKSB7IHNldFRpbWVvdXQoYmluZChlbnN1cmVGb2N1cywgY20pLCAwKTsgfVxuICAgIGVsc2UgeyBjbS5jdXJPcC5mb2N1cyA9IGFjdGl2ZUVsdCgpOyB9XG5cbiAgICB2YXIgYmVoYXZpb3IgPSBjb25maWd1cmVNb3VzZShjbSwgcmVwZWF0LCBldmVudCk7XG5cbiAgICB2YXIgc2VsID0gY20uZG9jLnNlbCwgY29udGFpbmVkO1xuICAgIGlmIChjbS5vcHRpb25zLmRyYWdEcm9wICYmIGRyYWdBbmREcm9wICYmICFjbS5pc1JlYWRPbmx5KCkgJiZcbiAgICAgICAgcmVwZWF0ID09IFwic2luZ2xlXCIgJiYgKGNvbnRhaW5lZCA9IHNlbC5jb250YWlucyhwb3MpKSA+IC0xICYmXG4gICAgICAgIChjbXAoKGNvbnRhaW5lZCA9IHNlbC5yYW5nZXNbY29udGFpbmVkXSkuZnJvbSgpLCBwb3MpIDwgMCB8fCBwb3MueFJlbCA+IDApICYmXG4gICAgICAgIChjbXAoY29udGFpbmVkLnRvKCksIHBvcykgPiAwIHx8IHBvcy54UmVsIDwgMCkpXG4gICAgICB7IGxlZnRCdXR0b25TdGFydERyYWcoY20sIGV2ZW50LCBwb3MsIGJlaGF2aW9yKTsgfVxuICAgIGVsc2VcbiAgICAgIHsgbGVmdEJ1dHRvblNlbGVjdChjbSwgZXZlbnQsIHBvcywgYmVoYXZpb3IpOyB9XG4gIH1cblxuICAvLyBTdGFydCBhIHRleHQgZHJhZy4gV2hlbiBpdCBlbmRzLCBzZWUgaWYgYW55IGRyYWdnaW5nIGFjdHVhbGx5XG4gIC8vIGhhcHBlbiwgYW5kIHRyZWF0IGFzIGEgY2xpY2sgaWYgaXQgZGlkbid0LlxuICBmdW5jdGlvbiBsZWZ0QnV0dG9uU3RhcnREcmFnKGNtLCBldmVudCwgcG9zLCBiZWhhdmlvcikge1xuICAgIHZhciBkaXNwbGF5ID0gY20uZGlzcGxheSwgbW92ZWQgPSBmYWxzZTtcbiAgICB2YXIgZHJhZ0VuZCA9IG9wZXJhdGlvbihjbSwgZnVuY3Rpb24gKGUpIHtcbiAgICAgIGlmICh3ZWJraXQpIHsgZGlzcGxheS5zY3JvbGxlci5kcmFnZ2FibGUgPSBmYWxzZTsgfVxuICAgICAgY20uc3RhdGUuZHJhZ2dpbmdUZXh0ID0gZmFsc2U7XG4gICAgICBvZmYoZGlzcGxheS53cmFwcGVyLm93bmVyRG9jdW1lbnQsIFwibW91c2V1cFwiLCBkcmFnRW5kKTtcbiAgICAgIG9mZihkaXNwbGF5LndyYXBwZXIub3duZXJEb2N1bWVudCwgXCJtb3VzZW1vdmVcIiwgbW91c2VNb3ZlKTtcbiAgICAgIG9mZihkaXNwbGF5LnNjcm9sbGVyLCBcImRyYWdzdGFydFwiLCBkcmFnU3RhcnQpO1xuICAgICAgb2ZmKGRpc3BsYXkuc2Nyb2xsZXIsIFwiZHJvcFwiLCBkcmFnRW5kKTtcbiAgICAgIGlmICghbW92ZWQpIHtcbiAgICAgICAgZV9wcmV2ZW50RGVmYXVsdChlKTtcbiAgICAgICAgaWYgKCFiZWhhdmlvci5hZGROZXcpXG4gICAgICAgICAgeyBleHRlbmRTZWxlY3Rpb24oY20uZG9jLCBwb3MsIG51bGwsIG51bGwsIGJlaGF2aW9yLmV4dGVuZCk7IH1cbiAgICAgICAgLy8gV29yayBhcm91bmQgdW5leHBsYWluYWJsZSBmb2N1cyBwcm9ibGVtIGluIElFOSAoIzIxMjcpIGFuZCBDaHJvbWUgKCMzMDgxKVxuICAgICAgICBpZiAod2Via2l0IHx8IGllICYmIGllX3ZlcnNpb24gPT0gOSlcbiAgICAgICAgICB7IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge2Rpc3BsYXkud3JhcHBlci5vd25lckRvY3VtZW50LmJvZHkuZm9jdXMoKTsgZGlzcGxheS5pbnB1dC5mb2N1cygpO30sIDIwKTsgfVxuICAgICAgICBlbHNlXG4gICAgICAgICAgeyBkaXNwbGF5LmlucHV0LmZvY3VzKCk7IH1cbiAgICAgIH1cbiAgICB9KTtcbiAgICB2YXIgbW91c2VNb3ZlID0gZnVuY3Rpb24oZTIpIHtcbiAgICAgIG1vdmVkID0gbW92ZWQgfHwgTWF0aC5hYnMoZXZlbnQuY2xpZW50WCAtIGUyLmNsaWVudFgpICsgTWF0aC5hYnMoZXZlbnQuY2xpZW50WSAtIGUyLmNsaWVudFkpID49IDEwO1xuICAgIH07XG4gICAgdmFyIGRyYWdTdGFydCA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIG1vdmVkID0gdHJ1ZTsgfTtcbiAgICAvLyBMZXQgdGhlIGRyYWcgaGFuZGxlciBoYW5kbGUgdGhpcy5cbiAgICBpZiAod2Via2l0KSB7IGRpc3BsYXkuc2Nyb2xsZXIuZHJhZ2dhYmxlID0gdHJ1ZTsgfVxuICAgIGNtLnN0YXRlLmRyYWdnaW5nVGV4dCA9IGRyYWdFbmQ7XG4gICAgZHJhZ0VuZC5jb3B5ID0gIWJlaGF2aW9yLm1vdmVPbkRyYWc7XG4gICAgLy8gSUUncyBhcHByb2FjaCB0byBkcmFnZ2FibGVcbiAgICBpZiAoZGlzcGxheS5zY3JvbGxlci5kcmFnRHJvcCkgeyBkaXNwbGF5LnNjcm9sbGVyLmRyYWdEcm9wKCk7IH1cbiAgICBvbihkaXNwbGF5LndyYXBwZXIub3duZXJEb2N1bWVudCwgXCJtb3VzZXVwXCIsIGRyYWdFbmQpO1xuICAgIG9uKGRpc3BsYXkud3JhcHBlci5vd25lckRvY3VtZW50LCBcIm1vdXNlbW92ZVwiLCBtb3VzZU1vdmUpO1xuICAgIG9uKGRpc3BsYXkuc2Nyb2xsZXIsIFwiZHJhZ3N0YXJ0XCIsIGRyYWdTdGFydCk7XG4gICAgb24oZGlzcGxheS5zY3JvbGxlciwgXCJkcm9wXCIsIGRyYWdFbmQpO1xuXG4gICAgZGVsYXlCbHVyRXZlbnQoY20pO1xuICAgIHNldFRpbWVvdXQoZnVuY3Rpb24gKCkgeyByZXR1cm4gZGlzcGxheS5pbnB1dC5mb2N1cygpOyB9LCAyMCk7XG4gIH1cblxuICBmdW5jdGlvbiByYW5nZUZvclVuaXQoY20sIHBvcywgdW5pdCkge1xuICAgIGlmICh1bml0ID09IFwiY2hhclwiKSB7IHJldHVybiBuZXcgUmFuZ2UocG9zLCBwb3MpIH1cbiAgICBpZiAodW5pdCA9PSBcIndvcmRcIikgeyByZXR1cm4gY20uZmluZFdvcmRBdChwb3MpIH1cbiAgICBpZiAodW5pdCA9PSBcImxpbmVcIikgeyByZXR1cm4gbmV3IFJhbmdlKFBvcyhwb3MubGluZSwgMCksIGNsaXBQb3MoY20uZG9jLCBQb3MocG9zLmxpbmUgKyAxLCAwKSkpIH1cbiAgICB2YXIgcmVzdWx0ID0gdW5pdChjbSwgcG9zKTtcbiAgICByZXR1cm4gbmV3IFJhbmdlKHJlc3VsdC5mcm9tLCByZXN1bHQudG8pXG4gIH1cblxuICAvLyBOb3JtYWwgc2VsZWN0aW9uLCBhcyBvcHBvc2VkIHRvIHRleHQgZHJhZ2dpbmcuXG4gIGZ1bmN0aW9uIGxlZnRCdXR0b25TZWxlY3QoY20sIGV2ZW50LCBzdGFydCwgYmVoYXZpb3IpIHtcbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXksIGRvYyA9IGNtLmRvYztcbiAgICBlX3ByZXZlbnREZWZhdWx0KGV2ZW50KTtcblxuICAgIHZhciBvdXJSYW5nZSwgb3VySW5kZXgsIHN0YXJ0U2VsID0gZG9jLnNlbCwgcmFuZ2VzID0gc3RhcnRTZWwucmFuZ2VzO1xuICAgIGlmIChiZWhhdmlvci5hZGROZXcgJiYgIWJlaGF2aW9yLmV4dGVuZCkge1xuICAgICAgb3VySW5kZXggPSBkb2Muc2VsLmNvbnRhaW5zKHN0YXJ0KTtcbiAgICAgIGlmIChvdXJJbmRleCA+IC0xKVxuICAgICAgICB7IG91clJhbmdlID0gcmFuZ2VzW291ckluZGV4XTsgfVxuICAgICAgZWxzZVxuICAgICAgICB7IG91clJhbmdlID0gbmV3IFJhbmdlKHN0YXJ0LCBzdGFydCk7IH1cbiAgICB9IGVsc2Uge1xuICAgICAgb3VyUmFuZ2UgPSBkb2Muc2VsLnByaW1hcnkoKTtcbiAgICAgIG91ckluZGV4ID0gZG9jLnNlbC5wcmltSW5kZXg7XG4gICAgfVxuXG4gICAgaWYgKGJlaGF2aW9yLnVuaXQgPT0gXCJyZWN0YW5nbGVcIikge1xuICAgICAgaWYgKCFiZWhhdmlvci5hZGROZXcpIHsgb3VyUmFuZ2UgPSBuZXcgUmFuZ2Uoc3RhcnQsIHN0YXJ0KTsgfVxuICAgICAgc3RhcnQgPSBwb3NGcm9tTW91c2UoY20sIGV2ZW50LCB0cnVlLCB0cnVlKTtcbiAgICAgIG91ckluZGV4ID0gLTE7XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciByYW5nZSQkMSA9IHJhbmdlRm9yVW5pdChjbSwgc3RhcnQsIGJlaGF2aW9yLnVuaXQpO1xuICAgICAgaWYgKGJlaGF2aW9yLmV4dGVuZClcbiAgICAgICAgeyBvdXJSYW5nZSA9IGV4dGVuZFJhbmdlKG91clJhbmdlLCByYW5nZSQkMS5hbmNob3IsIHJhbmdlJCQxLmhlYWQsIGJlaGF2aW9yLmV4dGVuZCk7IH1cbiAgICAgIGVsc2VcbiAgICAgICAgeyBvdXJSYW5nZSA9IHJhbmdlJCQxOyB9XG4gICAgfVxuXG4gICAgaWYgKCFiZWhhdmlvci5hZGROZXcpIHtcbiAgICAgIG91ckluZGV4ID0gMDtcbiAgICAgIHNldFNlbGVjdGlvbihkb2MsIG5ldyBTZWxlY3Rpb24oW291clJhbmdlXSwgMCksIHNlbF9tb3VzZSk7XG4gICAgICBzdGFydFNlbCA9IGRvYy5zZWw7XG4gICAgfSBlbHNlIGlmIChvdXJJbmRleCA9PSAtMSkge1xuICAgICAgb3VySW5kZXggPSByYW5nZXMubGVuZ3RoO1xuICAgICAgc2V0U2VsZWN0aW9uKGRvYywgbm9ybWFsaXplU2VsZWN0aW9uKGNtLCByYW5nZXMuY29uY2F0KFtvdXJSYW5nZV0pLCBvdXJJbmRleCksXG4gICAgICAgICAgICAgICAgICAge3Njcm9sbDogZmFsc2UsIG9yaWdpbjogXCIqbW91c2VcIn0pO1xuICAgIH0gZWxzZSBpZiAocmFuZ2VzLmxlbmd0aCA+IDEgJiYgcmFuZ2VzW291ckluZGV4XS5lbXB0eSgpICYmIGJlaGF2aW9yLnVuaXQgPT0gXCJjaGFyXCIgJiYgIWJlaGF2aW9yLmV4dGVuZCkge1xuICAgICAgc2V0U2VsZWN0aW9uKGRvYywgbm9ybWFsaXplU2VsZWN0aW9uKGNtLCByYW5nZXMuc2xpY2UoMCwgb3VySW5kZXgpLmNvbmNhdChyYW5nZXMuc2xpY2Uob3VySW5kZXggKyAxKSksIDApLFxuICAgICAgICAgICAgICAgICAgIHtzY3JvbGw6IGZhbHNlLCBvcmlnaW46IFwiKm1vdXNlXCJ9KTtcbiAgICAgIHN0YXJ0U2VsID0gZG9jLnNlbDtcbiAgICB9IGVsc2Uge1xuICAgICAgcmVwbGFjZU9uZVNlbGVjdGlvbihkb2MsIG91ckluZGV4LCBvdXJSYW5nZSwgc2VsX21vdXNlKTtcbiAgICB9XG5cbiAgICB2YXIgbGFzdFBvcyA9IHN0YXJ0O1xuICAgIGZ1bmN0aW9uIGV4dGVuZFRvKHBvcykge1xuICAgICAgaWYgKGNtcChsYXN0UG9zLCBwb3MpID09IDApIHsgcmV0dXJuIH1cbiAgICAgIGxhc3RQb3MgPSBwb3M7XG5cbiAgICAgIGlmIChiZWhhdmlvci51bml0ID09IFwicmVjdGFuZ2xlXCIpIHtcbiAgICAgICAgdmFyIHJhbmdlcyA9IFtdLCB0YWJTaXplID0gY20ub3B0aW9ucy50YWJTaXplO1xuICAgICAgICB2YXIgc3RhcnRDb2wgPSBjb3VudENvbHVtbihnZXRMaW5lKGRvYywgc3RhcnQubGluZSkudGV4dCwgc3RhcnQuY2gsIHRhYlNpemUpO1xuICAgICAgICB2YXIgcG9zQ29sID0gY291bnRDb2x1bW4oZ2V0TGluZShkb2MsIHBvcy5saW5lKS50ZXh0LCBwb3MuY2gsIHRhYlNpemUpO1xuICAgICAgICB2YXIgbGVmdCA9IE1hdGgubWluKHN0YXJ0Q29sLCBwb3NDb2wpLCByaWdodCA9IE1hdGgubWF4KHN0YXJ0Q29sLCBwb3NDb2wpO1xuICAgICAgICBmb3IgKHZhciBsaW5lID0gTWF0aC5taW4oc3RhcnQubGluZSwgcG9zLmxpbmUpLCBlbmQgPSBNYXRoLm1pbihjbS5sYXN0TGluZSgpLCBNYXRoLm1heChzdGFydC5saW5lLCBwb3MubGluZSkpO1xuICAgICAgICAgICAgIGxpbmUgPD0gZW5kOyBsaW5lKyspIHtcbiAgICAgICAgICB2YXIgdGV4dCA9IGdldExpbmUoZG9jLCBsaW5lKS50ZXh0LCBsZWZ0UG9zID0gZmluZENvbHVtbih0ZXh0LCBsZWZ0LCB0YWJTaXplKTtcbiAgICAgICAgICBpZiAobGVmdCA9PSByaWdodClcbiAgICAgICAgICAgIHsgcmFuZ2VzLnB1c2gobmV3IFJhbmdlKFBvcyhsaW5lLCBsZWZ0UG9zKSwgUG9zKGxpbmUsIGxlZnRQb3MpKSk7IH1cbiAgICAgICAgICBlbHNlIGlmICh0ZXh0Lmxlbmd0aCA+IGxlZnRQb3MpXG4gICAgICAgICAgICB7IHJhbmdlcy5wdXNoKG5ldyBSYW5nZShQb3MobGluZSwgbGVmdFBvcyksIFBvcyhsaW5lLCBmaW5kQ29sdW1uKHRleHQsIHJpZ2h0LCB0YWJTaXplKSkpKTsgfVxuICAgICAgICB9XG4gICAgICAgIGlmICghcmFuZ2VzLmxlbmd0aCkgeyByYW5nZXMucHVzaChuZXcgUmFuZ2Uoc3RhcnQsIHN0YXJ0KSk7IH1cbiAgICAgICAgc2V0U2VsZWN0aW9uKGRvYywgbm9ybWFsaXplU2VsZWN0aW9uKGNtLCBzdGFydFNlbC5yYW5nZXMuc2xpY2UoMCwgb3VySW5kZXgpLmNvbmNhdChyYW5nZXMpLCBvdXJJbmRleCksXG4gICAgICAgICAgICAgICAgICAgICB7b3JpZ2luOiBcIiptb3VzZVwiLCBzY3JvbGw6IGZhbHNlfSk7XG4gICAgICAgIGNtLnNjcm9sbEludG9WaWV3KHBvcyk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgb2xkUmFuZ2UgPSBvdXJSYW5nZTtcbiAgICAgICAgdmFyIHJhbmdlJCQxID0gcmFuZ2VGb3JVbml0KGNtLCBwb3MsIGJlaGF2aW9yLnVuaXQpO1xuICAgICAgICB2YXIgYW5jaG9yID0gb2xkUmFuZ2UuYW5jaG9yLCBoZWFkO1xuICAgICAgICBpZiAoY21wKHJhbmdlJCQxLmFuY2hvciwgYW5jaG9yKSA+IDApIHtcbiAgICAgICAgICBoZWFkID0gcmFuZ2UkJDEuaGVhZDtcbiAgICAgICAgICBhbmNob3IgPSBtaW5Qb3Mob2xkUmFuZ2UuZnJvbSgpLCByYW5nZSQkMS5hbmNob3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGhlYWQgPSByYW5nZSQkMS5hbmNob3I7XG4gICAgICAgICAgYW5jaG9yID0gbWF4UG9zKG9sZFJhbmdlLnRvKCksIHJhbmdlJCQxLmhlYWQpO1xuICAgICAgICB9XG4gICAgICAgIHZhciByYW5nZXMkMSA9IHN0YXJ0U2VsLnJhbmdlcy5zbGljZSgwKTtcbiAgICAgICAgcmFuZ2VzJDFbb3VySW5kZXhdID0gYmlkaVNpbXBsaWZ5KGNtLCBuZXcgUmFuZ2UoY2xpcFBvcyhkb2MsIGFuY2hvciksIGhlYWQpKTtcbiAgICAgICAgc2V0U2VsZWN0aW9uKGRvYywgbm9ybWFsaXplU2VsZWN0aW9uKGNtLCByYW5nZXMkMSwgb3VySW5kZXgpLCBzZWxfbW91c2UpO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciBlZGl0b3JTaXplID0gZGlzcGxheS53cmFwcGVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgIC8vIFVzZWQgdG8gZW5zdXJlIHRpbWVvdXQgcmUtdHJpZXMgZG9uJ3QgZmlyZSB3aGVuIGFub3RoZXIgZXh0ZW5kXG4gICAgLy8gaGFwcGVuZWQgaW4gdGhlIG1lYW50aW1lIChjbGVhclRpbWVvdXQgaXNuJ3QgcmVsaWFibGUgLS0gYXRcbiAgICAvLyBsZWFzdCBvbiBDaHJvbWUsIHRoZSB0aW1lb3V0cyBzdGlsbCBoYXBwZW4gZXZlbiB3aGVuIGNsZWFyZWQsXG4gICAgLy8gaWYgdGhlIGNsZWFyIGhhcHBlbnMgYWZ0ZXIgdGhlaXIgc2NoZWR1bGVkIGZpcmluZyB0aW1lKS5cbiAgICB2YXIgY291bnRlciA9IDA7XG5cbiAgICBmdW5jdGlvbiBleHRlbmQoZSkge1xuICAgICAgdmFyIGN1ckNvdW50ID0gKytjb3VudGVyO1xuICAgICAgdmFyIGN1ciA9IHBvc0Zyb21Nb3VzZShjbSwgZSwgdHJ1ZSwgYmVoYXZpb3IudW5pdCA9PSBcInJlY3RhbmdsZVwiKTtcbiAgICAgIGlmICghY3VyKSB7IHJldHVybiB9XG4gICAgICBpZiAoY21wKGN1ciwgbGFzdFBvcykgIT0gMCkge1xuICAgICAgICBjbS5jdXJPcC5mb2N1cyA9IGFjdGl2ZUVsdCgpO1xuICAgICAgICBleHRlbmRUbyhjdXIpO1xuICAgICAgICB2YXIgdmlzaWJsZSA9IHZpc2libGVMaW5lcyhkaXNwbGF5LCBkb2MpO1xuICAgICAgICBpZiAoY3VyLmxpbmUgPj0gdmlzaWJsZS50byB8fCBjdXIubGluZSA8IHZpc2libGUuZnJvbSlcbiAgICAgICAgICB7IHNldFRpbWVvdXQob3BlcmF0aW9uKGNtLCBmdW5jdGlvbiAoKSB7aWYgKGNvdW50ZXIgPT0gY3VyQ291bnQpIHsgZXh0ZW5kKGUpOyB9fSksIDE1MCk7IH1cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciBvdXRzaWRlID0gZS5jbGllbnRZIDwgZWRpdG9yU2l6ZS50b3AgPyAtMjAgOiBlLmNsaWVudFkgPiBlZGl0b3JTaXplLmJvdHRvbSA/IDIwIDogMDtcbiAgICAgICAgaWYgKG91dHNpZGUpIHsgc2V0VGltZW91dChvcGVyYXRpb24oY20sIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICBpZiAoY291bnRlciAhPSBjdXJDb3VudCkgeyByZXR1cm4gfVxuICAgICAgICAgIGRpc3BsYXkuc2Nyb2xsZXIuc2Nyb2xsVG9wICs9IG91dHNpZGU7XG4gICAgICAgICAgZXh0ZW5kKGUpO1xuICAgICAgICB9KSwgNTApOyB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gZG9uZShlKSB7XG4gICAgICBjbS5zdGF0ZS5zZWxlY3RpbmdUZXh0ID0gZmFsc2U7XG4gICAgICBjb3VudGVyID0gSW5maW5pdHk7XG4gICAgICBlX3ByZXZlbnREZWZhdWx0KGUpO1xuICAgICAgZGlzcGxheS5pbnB1dC5mb2N1cygpO1xuICAgICAgb2ZmKGRpc3BsYXkud3JhcHBlci5vd25lckRvY3VtZW50LCBcIm1vdXNlbW92ZVwiLCBtb3ZlKTtcbiAgICAgIG9mZihkaXNwbGF5LndyYXBwZXIub3duZXJEb2N1bWVudCwgXCJtb3VzZXVwXCIsIHVwKTtcbiAgICAgIGRvYy5oaXN0b3J5Lmxhc3RTZWxPcmlnaW4gPSBudWxsO1xuICAgIH1cblxuICAgIHZhciBtb3ZlID0gb3BlcmF0aW9uKGNtLCBmdW5jdGlvbiAoZSkge1xuICAgICAgaWYgKGUuYnV0dG9ucyA9PT0gMCB8fCAhZV9idXR0b24oZSkpIHsgZG9uZShlKTsgfVxuICAgICAgZWxzZSB7IGV4dGVuZChlKTsgfVxuICAgIH0pO1xuICAgIHZhciB1cCA9IG9wZXJhdGlvbihjbSwgZG9uZSk7XG4gICAgY20uc3RhdGUuc2VsZWN0aW5nVGV4dCA9IHVwO1xuICAgIG9uKGRpc3BsYXkud3JhcHBlci5vd25lckRvY3VtZW50LCBcIm1vdXNlbW92ZVwiLCBtb3ZlKTtcbiAgICBvbihkaXNwbGF5LndyYXBwZXIub3duZXJEb2N1bWVudCwgXCJtb3VzZXVwXCIsIHVwKTtcbiAgfVxuXG4gIC8vIFVzZWQgd2hlbiBtb3VzZS1zZWxlY3RpbmcgdG8gYWRqdXN0IHRoZSBhbmNob3IgdG8gdGhlIHByb3BlciBzaWRlXG4gIC8vIG9mIGEgYmlkaSBqdW1wIGRlcGVuZGluZyBvbiB0aGUgdmlzdWFsIHBvc2l0aW9uIG9mIHRoZSBoZWFkLlxuICBmdW5jdGlvbiBiaWRpU2ltcGxpZnkoY20sIHJhbmdlJCQxKSB7XG4gICAgdmFyIGFuY2hvciA9IHJhbmdlJCQxLmFuY2hvcjtcbiAgICB2YXIgaGVhZCA9IHJhbmdlJCQxLmhlYWQ7XG4gICAgdmFyIGFuY2hvckxpbmUgPSBnZXRMaW5lKGNtLmRvYywgYW5jaG9yLmxpbmUpO1xuICAgIGlmIChjbXAoYW5jaG9yLCBoZWFkKSA9PSAwICYmIGFuY2hvci5zdGlja3kgPT0gaGVhZC5zdGlja3kpIHsgcmV0dXJuIHJhbmdlJCQxIH1cbiAgICB2YXIgb3JkZXIgPSBnZXRPcmRlcihhbmNob3JMaW5lKTtcbiAgICBpZiAoIW9yZGVyKSB7IHJldHVybiByYW5nZSQkMSB9XG4gICAgdmFyIGluZGV4ID0gZ2V0QmlkaVBhcnRBdChvcmRlciwgYW5jaG9yLmNoLCBhbmNob3Iuc3RpY2t5KSwgcGFydCA9IG9yZGVyW2luZGV4XTtcbiAgICBpZiAocGFydC5mcm9tICE9IGFuY2hvci5jaCAmJiBwYXJ0LnRvICE9IGFuY2hvci5jaCkgeyByZXR1cm4gcmFuZ2UkJDEgfVxuICAgIHZhciBib3VuZGFyeSA9IGluZGV4ICsgKChwYXJ0LmZyb20gPT0gYW5jaG9yLmNoKSA9PSAocGFydC5sZXZlbCAhPSAxKSA/IDAgOiAxKTtcbiAgICBpZiAoYm91bmRhcnkgPT0gMCB8fCBib3VuZGFyeSA9PSBvcmRlci5sZW5ndGgpIHsgcmV0dXJuIHJhbmdlJCQxIH1cblxuICAgIC8vIENvbXB1dGUgdGhlIHJlbGF0aXZlIHZpc3VhbCBwb3NpdGlvbiBvZiB0aGUgaGVhZCBjb21wYXJlZCB0byB0aGVcbiAgICAvLyBhbmNob3IgKDwwIGlzIHRvIHRoZSBsZWZ0LCA+MCB0byB0aGUgcmlnaHQpXG4gICAgdmFyIGxlZnRTaWRlO1xuICAgIGlmIChoZWFkLmxpbmUgIT0gYW5jaG9yLmxpbmUpIHtcbiAgICAgIGxlZnRTaWRlID0gKGhlYWQubGluZSAtIGFuY2hvci5saW5lKSAqIChjbS5kb2MuZGlyZWN0aW9uID09IFwibHRyXCIgPyAxIDogLTEpID4gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgdmFyIGhlYWRJbmRleCA9IGdldEJpZGlQYXJ0QXQob3JkZXIsIGhlYWQuY2gsIGhlYWQuc3RpY2t5KTtcbiAgICAgIHZhciBkaXIgPSBoZWFkSW5kZXggLSBpbmRleCB8fCAoaGVhZC5jaCAtIGFuY2hvci5jaCkgKiAocGFydC5sZXZlbCA9PSAxID8gLTEgOiAxKTtcbiAgICAgIGlmIChoZWFkSW5kZXggPT0gYm91bmRhcnkgLSAxIHx8IGhlYWRJbmRleCA9PSBib3VuZGFyeSlcbiAgICAgICAgeyBsZWZ0U2lkZSA9IGRpciA8IDA7IH1cbiAgICAgIGVsc2VcbiAgICAgICAgeyBsZWZ0U2lkZSA9IGRpciA+IDA7IH1cbiAgICB9XG5cbiAgICB2YXIgdXNlUGFydCA9IG9yZGVyW2JvdW5kYXJ5ICsgKGxlZnRTaWRlID8gLTEgOiAwKV07XG4gICAgdmFyIGZyb20gPSBsZWZ0U2lkZSA9PSAodXNlUGFydC5sZXZlbCA9PSAxKTtcbiAgICB2YXIgY2ggPSBmcm9tID8gdXNlUGFydC5mcm9tIDogdXNlUGFydC50bywgc3RpY2t5ID0gZnJvbSA/IFwiYWZ0ZXJcIiA6IFwiYmVmb3JlXCI7XG4gICAgcmV0dXJuIGFuY2hvci5jaCA9PSBjaCAmJiBhbmNob3Iuc3RpY2t5ID09IHN0aWNreSA/IHJhbmdlJCQxIDogbmV3IFJhbmdlKG5ldyBQb3MoYW5jaG9yLmxpbmUsIGNoLCBzdGlja3kpLCBoZWFkKVxuICB9XG5cblxuICAvLyBEZXRlcm1pbmVzIHdoZXRoZXIgYW4gZXZlbnQgaGFwcGVuZWQgaW4gdGhlIGd1dHRlciwgYW5kIGZpcmVzIHRoZVxuICAvLyBoYW5kbGVycyBmb3IgdGhlIGNvcnJlc3BvbmRpbmcgZXZlbnQuXG4gIGZ1bmN0aW9uIGd1dHRlckV2ZW50KGNtLCBlLCB0eXBlLCBwcmV2ZW50KSB7XG4gICAgdmFyIG1YLCBtWTtcbiAgICBpZiAoZS50b3VjaGVzKSB7XG4gICAgICBtWCA9IGUudG91Y2hlc1swXS5jbGllbnRYO1xuICAgICAgbVkgPSBlLnRvdWNoZXNbMF0uY2xpZW50WTtcbiAgICB9IGVsc2Uge1xuICAgICAgdHJ5IHsgbVggPSBlLmNsaWVudFg7IG1ZID0gZS5jbGllbnRZOyB9XG4gICAgICBjYXRjaChlKSB7IHJldHVybiBmYWxzZSB9XG4gICAgfVxuICAgIGlmIChtWCA+PSBNYXRoLmZsb29yKGNtLmRpc3BsYXkuZ3V0dGVycy5nZXRCb3VuZGluZ0NsaWVudFJlY3QoKS5yaWdodCkpIHsgcmV0dXJuIGZhbHNlIH1cbiAgICBpZiAocHJldmVudCkgeyBlX3ByZXZlbnREZWZhdWx0KGUpOyB9XG5cbiAgICB2YXIgZGlzcGxheSA9IGNtLmRpc3BsYXk7XG4gICAgdmFyIGxpbmVCb3ggPSBkaXNwbGF5LmxpbmVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG5cbiAgICBpZiAobVkgPiBsaW5lQm94LmJvdHRvbSB8fCAhaGFzSGFuZGxlcihjbSwgdHlwZSkpIHsgcmV0dXJuIGVfZGVmYXVsdFByZXZlbnRlZChlKSB9XG4gICAgbVkgLT0gbGluZUJveC50b3AgLSBkaXNwbGF5LnZpZXdPZmZzZXQ7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNtLm9wdGlvbnMuZ3V0dGVycy5sZW5ndGg7ICsraSkge1xuICAgICAgdmFyIGcgPSBkaXNwbGF5Lmd1dHRlcnMuY2hpbGROb2Rlc1tpXTtcbiAgICAgIGlmIChnICYmIGcuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCkucmlnaHQgPj0gbVgpIHtcbiAgICAgICAgdmFyIGxpbmUgPSBsaW5lQXRIZWlnaHQoY20uZG9jLCBtWSk7XG4gICAgICAgIHZhciBndXR0ZXIgPSBjbS5vcHRpb25zLmd1dHRlcnNbaV07XG4gICAgICAgIHNpZ25hbChjbSwgdHlwZSwgY20sIGxpbmUsIGd1dHRlciwgZSk7XG4gICAgICAgIHJldHVybiBlX2RlZmF1bHRQcmV2ZW50ZWQoZSlcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBjbGlja0luR3V0dGVyKGNtLCBlKSB7XG4gICAgcmV0dXJuIGd1dHRlckV2ZW50KGNtLCBlLCBcImd1dHRlckNsaWNrXCIsIHRydWUpXG4gIH1cblxuICAvLyBDT05URVhUIE1FTlUgSEFORExJTkdcblxuICAvLyBUbyBtYWtlIHRoZSBjb250ZXh0IG1lbnUgd29yaywgd2UgbmVlZCB0byBicmllZmx5IHVuaGlkZSB0aGVcbiAgLy8gdGV4dGFyZWEgKG1ha2luZyBpdCBhcyB1bm9idHJ1c2l2ZSBhcyBwb3NzaWJsZSkgdG8gbGV0IHRoZVxuICAvLyByaWdodC1jbGljayB0YWtlIGVmZmVjdCBvbiBpdC5cbiAgZnVuY3Rpb24gb25Db250ZXh0TWVudShjbSwgZSkge1xuICAgIGlmIChldmVudEluV2lkZ2V0KGNtLmRpc3BsYXksIGUpIHx8IGNvbnRleHRNZW51SW5HdXR0ZXIoY20sIGUpKSB7IHJldHVybiB9XG4gICAgaWYgKHNpZ25hbERPTUV2ZW50KGNtLCBlLCBcImNvbnRleHRtZW51XCIpKSB7IHJldHVybiB9XG4gICAgaWYgKCFjYXB0dXJlUmlnaHRDbGljaykgeyBjbS5kaXNwbGF5LmlucHV0Lm9uQ29udGV4dE1lbnUoZSk7IH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGNvbnRleHRNZW51SW5HdXR0ZXIoY20sIGUpIHtcbiAgICBpZiAoIWhhc0hhbmRsZXIoY20sIFwiZ3V0dGVyQ29udGV4dE1lbnVcIikpIHsgcmV0dXJuIGZhbHNlIH1cbiAgICByZXR1cm4gZ3V0dGVyRXZlbnQoY20sIGUsIFwiZ3V0dGVyQ29udGV4dE1lbnVcIiwgZmFsc2UpXG4gIH1cblxuICBmdW5jdGlvbiB0aGVtZUNoYW5nZWQoY20pIHtcbiAgICBjbS5kaXNwbGF5LndyYXBwZXIuY2xhc3NOYW1lID0gY20uZGlzcGxheS53cmFwcGVyLmNsYXNzTmFtZS5yZXBsYWNlKC9cXHMqY20tcy1cXFMrL2csIFwiXCIpICtcbiAgICAgIGNtLm9wdGlvbnMudGhlbWUucmVwbGFjZSgvKF58XFxzKVxccyovZywgXCIgY20tcy1cIik7XG4gICAgY2xlYXJDYWNoZXMoY20pO1xuICB9XG5cbiAgdmFyIEluaXQgPSB7dG9TdHJpbmc6IGZ1bmN0aW9uKCl7cmV0dXJuIFwiQ29kZU1pcnJvci5Jbml0XCJ9fTtcblxuICB2YXIgZGVmYXVsdHMgPSB7fTtcbiAgdmFyIG9wdGlvbkhhbmRsZXJzID0ge307XG5cbiAgZnVuY3Rpb24gZGVmaW5lT3B0aW9ucyhDb2RlTWlycm9yKSB7XG4gICAgdmFyIG9wdGlvbkhhbmRsZXJzID0gQ29kZU1pcnJvci5vcHRpb25IYW5kbGVycztcblxuICAgIGZ1bmN0aW9uIG9wdGlvbihuYW1lLCBkZWZsdCwgaGFuZGxlLCBub3RPbkluaXQpIHtcbiAgICAgIENvZGVNaXJyb3IuZGVmYXVsdHNbbmFtZV0gPSBkZWZsdDtcbiAgICAgIGlmIChoYW5kbGUpIHsgb3B0aW9uSGFuZGxlcnNbbmFtZV0gPVxuICAgICAgICBub3RPbkluaXQgPyBmdW5jdGlvbiAoY20sIHZhbCwgb2xkKSB7aWYgKG9sZCAhPSBJbml0KSB7IGhhbmRsZShjbSwgdmFsLCBvbGQpOyB9fSA6IGhhbmRsZTsgfVxuICAgIH1cblxuICAgIENvZGVNaXJyb3IuZGVmaW5lT3B0aW9uID0gb3B0aW9uO1xuXG4gICAgLy8gUGFzc2VkIHRvIG9wdGlvbiBoYW5kbGVycyB3aGVuIHRoZXJlIGlzIG5vIG9sZCB2YWx1ZS5cbiAgICBDb2RlTWlycm9yLkluaXQgPSBJbml0O1xuXG4gICAgLy8gVGhlc2UgdHdvIGFyZSwgb24gaW5pdCwgY2FsbGVkIGZyb20gdGhlIGNvbnN0cnVjdG9yIGJlY2F1c2UgdGhleVxuICAgIC8vIGhhdmUgdG8gYmUgaW5pdGlhbGl6ZWQgYmVmb3JlIHRoZSBlZGl0b3IgY2FuIHN0YXJ0IGF0IGFsbC5cbiAgICBvcHRpb24oXCJ2YWx1ZVwiLCBcIlwiLCBmdW5jdGlvbiAoY20sIHZhbCkgeyByZXR1cm4gY20uc2V0VmFsdWUodmFsKTsgfSwgdHJ1ZSk7XG4gICAgb3B0aW9uKFwibW9kZVwiLCBudWxsLCBmdW5jdGlvbiAoY20sIHZhbCkge1xuICAgICAgY20uZG9jLm1vZGVPcHRpb24gPSB2YWw7XG4gICAgICBsb2FkTW9kZShjbSk7XG4gICAgfSwgdHJ1ZSk7XG5cbiAgICBvcHRpb24oXCJpbmRlbnRVbml0XCIsIDIsIGxvYWRNb2RlLCB0cnVlKTtcbiAgICBvcHRpb24oXCJpbmRlbnRXaXRoVGFic1wiLCBmYWxzZSk7XG4gICAgb3B0aW9uKFwic21hcnRJbmRlbnRcIiwgdHJ1ZSk7XG4gICAgb3B0aW9uKFwidGFiU2l6ZVwiLCA0LCBmdW5jdGlvbiAoY20pIHtcbiAgICAgIHJlc2V0TW9kZVN0YXRlKGNtKTtcbiAgICAgIGNsZWFyQ2FjaGVzKGNtKTtcbiAgICAgIHJlZ0NoYW5nZShjbSk7XG4gICAgfSwgdHJ1ZSk7XG5cbiAgICBvcHRpb24oXCJsaW5lU2VwYXJhdG9yXCIsIG51bGwsIGZ1bmN0aW9uIChjbSwgdmFsKSB7XG4gICAgICBjbS5kb2MubGluZVNlcCA9IHZhbDtcbiAgICAgIGlmICghdmFsKSB7IHJldHVybiB9XG4gICAgICB2YXIgbmV3QnJlYWtzID0gW10sIGxpbmVObyA9IGNtLmRvYy5maXJzdDtcbiAgICAgIGNtLmRvYy5pdGVyKGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIGZvciAodmFyIHBvcyA9IDA7Oykge1xuICAgICAgICAgIHZhciBmb3VuZCA9IGxpbmUudGV4dC5pbmRleE9mKHZhbCwgcG9zKTtcbiAgICAgICAgICBpZiAoZm91bmQgPT0gLTEpIHsgYnJlYWsgfVxuICAgICAgICAgIHBvcyA9IGZvdW5kICsgdmFsLmxlbmd0aDtcbiAgICAgICAgICBuZXdCcmVha3MucHVzaChQb3MobGluZU5vLCBmb3VuZCkpO1xuICAgICAgICB9XG4gICAgICAgIGxpbmVObysrO1xuICAgICAgfSk7XG4gICAgICBmb3IgKHZhciBpID0gbmV3QnJlYWtzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKVxuICAgICAgICB7IHJlcGxhY2VSYW5nZShjbS5kb2MsIHZhbCwgbmV3QnJlYWtzW2ldLCBQb3MobmV3QnJlYWtzW2ldLmxpbmUsIG5ld0JyZWFrc1tpXS5jaCArIHZhbC5sZW5ndGgpKTsgfVxuICAgIH0pO1xuICAgIG9wdGlvbihcInNwZWNpYWxDaGFyc1wiLCAvW1xcdTAwMDAtXFx1MDAxZlxcdTAwN2YtXFx1MDA5ZlxcdTAwYWRcXHUwNjFjXFx1MjAwYi1cXHUyMDBmXFx1MjAyOFxcdTIwMjlcXHVmZWZmXS9nLCBmdW5jdGlvbiAoY20sIHZhbCwgb2xkKSB7XG4gICAgICBjbS5zdGF0ZS5zcGVjaWFsQ2hhcnMgPSBuZXcgUmVnRXhwKHZhbC5zb3VyY2UgKyAodmFsLnRlc3QoXCJcXHRcIikgPyBcIlwiIDogXCJ8XFx0XCIpLCBcImdcIik7XG4gICAgICBpZiAob2xkICE9IEluaXQpIHsgY20ucmVmcmVzaCgpOyB9XG4gICAgfSk7XG4gICAgb3B0aW9uKFwic3BlY2lhbENoYXJQbGFjZWhvbGRlclwiLCBkZWZhdWx0U3BlY2lhbENoYXJQbGFjZWhvbGRlciwgZnVuY3Rpb24gKGNtKSB7IHJldHVybiBjbS5yZWZyZXNoKCk7IH0sIHRydWUpO1xuICAgIG9wdGlvbihcImVsZWN0cmljQ2hhcnNcIiwgdHJ1ZSk7XG4gICAgb3B0aW9uKFwiaW5wdXRTdHlsZVwiLCBtb2JpbGUgPyBcImNvbnRlbnRlZGl0YWJsZVwiIDogXCJ0ZXh0YXJlYVwiLCBmdW5jdGlvbiAoKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbnB1dFN0eWxlIGNhbiBub3QgKHlldCkgYmUgY2hhbmdlZCBpbiBhIHJ1bm5pbmcgZWRpdG9yXCIpIC8vIEZJWE1FXG4gICAgfSwgdHJ1ZSk7XG4gICAgb3B0aW9uKFwic3BlbGxjaGVja1wiLCBmYWxzZSwgZnVuY3Rpb24gKGNtLCB2YWwpIHsgcmV0dXJuIGNtLmdldElucHV0RmllbGQoKS5zcGVsbGNoZWNrID0gdmFsOyB9LCB0cnVlKTtcbiAgICBvcHRpb24oXCJydGxNb3ZlVmlzdWFsbHlcIiwgIXdpbmRvd3MpO1xuICAgIG9wdGlvbihcIndob2xlTGluZVVwZGF0ZUJlZm9yZVwiLCB0cnVlKTtcblxuICAgIG9wdGlvbihcInRoZW1lXCIsIFwiZGVmYXVsdFwiLCBmdW5jdGlvbiAoY20pIHtcbiAgICAgIHRoZW1lQ2hhbmdlZChjbSk7XG4gICAgICBndXR0ZXJzQ2hhbmdlZChjbSk7XG4gICAgfSwgdHJ1ZSk7XG4gICAgb3B0aW9uKFwia2V5TWFwXCIsIFwiZGVmYXVsdFwiLCBmdW5jdGlvbiAoY20sIHZhbCwgb2xkKSB7XG4gICAgICB2YXIgbmV4dCA9IGdldEtleU1hcCh2YWwpO1xuICAgICAgdmFyIHByZXYgPSBvbGQgIT0gSW5pdCAmJiBnZXRLZXlNYXAob2xkKTtcbiAgICAgIGlmIChwcmV2ICYmIHByZXYuZGV0YWNoKSB7IHByZXYuZGV0YWNoKGNtLCBuZXh0KTsgfVxuICAgICAgaWYgKG5leHQuYXR0YWNoKSB7IG5leHQuYXR0YWNoKGNtLCBwcmV2IHx8IG51bGwpOyB9XG4gICAgfSk7XG4gICAgb3B0aW9uKFwiZXh0cmFLZXlzXCIsIG51bGwpO1xuICAgIG9wdGlvbihcImNvbmZpZ3VyZU1vdXNlXCIsIG51bGwpO1xuXG4gICAgb3B0aW9uKFwibGluZVdyYXBwaW5nXCIsIGZhbHNlLCB3cmFwcGluZ0NoYW5nZWQsIHRydWUpO1xuICAgIG9wdGlvbihcImd1dHRlcnNcIiwgW10sIGZ1bmN0aW9uIChjbSkge1xuICAgICAgc2V0R3V0dGVyc0ZvckxpbmVOdW1iZXJzKGNtLm9wdGlvbnMpO1xuICAgICAgZ3V0dGVyc0NoYW5nZWQoY20pO1xuICAgIH0sIHRydWUpO1xuICAgIG9wdGlvbihcImZpeGVkR3V0dGVyXCIsIHRydWUsIGZ1bmN0aW9uIChjbSwgdmFsKSB7XG4gICAgICBjbS5kaXNwbGF5Lmd1dHRlcnMuc3R5bGUubGVmdCA9IHZhbCA/IGNvbXBlbnNhdGVGb3JIU2Nyb2xsKGNtLmRpc3BsYXkpICsgXCJweFwiIDogXCIwXCI7XG4gICAgICBjbS5yZWZyZXNoKCk7XG4gICAgfSwgdHJ1ZSk7XG4gICAgb3B0aW9uKFwiY292ZXJHdXR0ZXJOZXh0VG9TY3JvbGxiYXJcIiwgZmFsc2UsIGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gdXBkYXRlU2Nyb2xsYmFycyhjbSk7IH0sIHRydWUpO1xuICAgIG9wdGlvbihcInNjcm9sbGJhclN0eWxlXCIsIFwibmF0aXZlXCIsIGZ1bmN0aW9uIChjbSkge1xuICAgICAgaW5pdFNjcm9sbGJhcnMoY20pO1xuICAgICAgdXBkYXRlU2Nyb2xsYmFycyhjbSk7XG4gICAgICBjbS5kaXNwbGF5LnNjcm9sbGJhcnMuc2V0U2Nyb2xsVG9wKGNtLmRvYy5zY3JvbGxUb3ApO1xuICAgICAgY20uZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbExlZnQoY20uZG9jLnNjcm9sbExlZnQpO1xuICAgIH0sIHRydWUpO1xuICAgIG9wdGlvbihcImxpbmVOdW1iZXJzXCIsIGZhbHNlLCBmdW5jdGlvbiAoY20pIHtcbiAgICAgIHNldEd1dHRlcnNGb3JMaW5lTnVtYmVycyhjbS5vcHRpb25zKTtcbiAgICAgIGd1dHRlcnNDaGFuZ2VkKGNtKTtcbiAgICB9LCB0cnVlKTtcbiAgICBvcHRpb24oXCJmaXJzdExpbmVOdW1iZXJcIiwgMSwgZ3V0dGVyc0NoYW5nZWQsIHRydWUpO1xuICAgIG9wdGlvbihcImxpbmVOdW1iZXJGb3JtYXR0ZXJcIiwgZnVuY3Rpb24gKGludGVnZXIpIHsgcmV0dXJuIGludGVnZXI7IH0sIGd1dHRlcnNDaGFuZ2VkLCB0cnVlKTtcbiAgICBvcHRpb24oXCJzaG93Q3Vyc29yV2hlblNlbGVjdGluZ1wiLCBmYWxzZSwgdXBkYXRlU2VsZWN0aW9uLCB0cnVlKTtcblxuICAgIG9wdGlvbihcInJlc2V0U2VsZWN0aW9uT25Db250ZXh0TWVudVwiLCB0cnVlKTtcbiAgICBvcHRpb24oXCJsaW5lV2lzZUNvcHlDdXRcIiwgdHJ1ZSk7XG4gICAgb3B0aW9uKFwicGFzdGVMaW5lc1BlclNlbGVjdGlvblwiLCB0cnVlKTtcbiAgICBvcHRpb24oXCJzZWxlY3Rpb25zTWF5VG91Y2hcIiwgZmFsc2UpO1xuXG4gICAgb3B0aW9uKFwicmVhZE9ubHlcIiwgZmFsc2UsIGZ1bmN0aW9uIChjbSwgdmFsKSB7XG4gICAgICBpZiAodmFsID09IFwibm9jdXJzb3JcIikge1xuICAgICAgICBvbkJsdXIoY20pO1xuICAgICAgICBjbS5kaXNwbGF5LmlucHV0LmJsdXIoKTtcbiAgICAgIH1cbiAgICAgIGNtLmRpc3BsYXkuaW5wdXQucmVhZE9ubHlDaGFuZ2VkKHZhbCk7XG4gICAgfSk7XG4gICAgb3B0aW9uKFwiZGlzYWJsZUlucHV0XCIsIGZhbHNlLCBmdW5jdGlvbiAoY20sIHZhbCkge2lmICghdmFsKSB7IGNtLmRpc3BsYXkuaW5wdXQucmVzZXQoKTsgfX0sIHRydWUpO1xuICAgIG9wdGlvbihcImRyYWdEcm9wXCIsIHRydWUsIGRyYWdEcm9wQ2hhbmdlZCk7XG4gICAgb3B0aW9uKFwiYWxsb3dEcm9wRmlsZVR5cGVzXCIsIG51bGwpO1xuXG4gICAgb3B0aW9uKFwiY3Vyc29yQmxpbmtSYXRlXCIsIDUzMCk7XG4gICAgb3B0aW9uKFwiY3Vyc29yU2Nyb2xsTWFyZ2luXCIsIDApO1xuICAgIG9wdGlvbihcImN1cnNvckhlaWdodFwiLCAxLCB1cGRhdGVTZWxlY3Rpb24sIHRydWUpO1xuICAgIG9wdGlvbihcInNpbmdsZUN1cnNvckhlaWdodFBlckxpbmVcIiwgdHJ1ZSwgdXBkYXRlU2VsZWN0aW9uLCB0cnVlKTtcbiAgICBvcHRpb24oXCJ3b3JrVGltZVwiLCAxMDApO1xuICAgIG9wdGlvbihcIndvcmtEZWxheVwiLCAxMDApO1xuICAgIG9wdGlvbihcImZsYXR0ZW5TcGFuc1wiLCB0cnVlLCByZXNldE1vZGVTdGF0ZSwgdHJ1ZSk7XG4gICAgb3B0aW9uKFwiYWRkTW9kZUNsYXNzXCIsIGZhbHNlLCByZXNldE1vZGVTdGF0ZSwgdHJ1ZSk7XG4gICAgb3B0aW9uKFwicG9sbEludGVydmFsXCIsIDEwMCk7XG4gICAgb3B0aW9uKFwidW5kb0RlcHRoXCIsIDIwMCwgZnVuY3Rpb24gKGNtLCB2YWwpIHsgcmV0dXJuIGNtLmRvYy5oaXN0b3J5LnVuZG9EZXB0aCA9IHZhbDsgfSk7XG4gICAgb3B0aW9uKFwiaGlzdG9yeUV2ZW50RGVsYXlcIiwgMTI1MCk7XG4gICAgb3B0aW9uKFwidmlld3BvcnRNYXJnaW5cIiwgMTAsIGZ1bmN0aW9uIChjbSkgeyByZXR1cm4gY20ucmVmcmVzaCgpOyB9LCB0cnVlKTtcbiAgICBvcHRpb24oXCJtYXhIaWdobGlnaHRMZW5ndGhcIiwgMTAwMDAsIHJlc2V0TW9kZVN0YXRlLCB0cnVlKTtcbiAgICBvcHRpb24oXCJtb3ZlSW5wdXRXaXRoQ3Vyc29yXCIsIHRydWUsIGZ1bmN0aW9uIChjbSwgdmFsKSB7XG4gICAgICBpZiAoIXZhbCkgeyBjbS5kaXNwbGF5LmlucHV0LnJlc2V0UG9zaXRpb24oKTsgfVxuICAgIH0pO1xuXG4gICAgb3B0aW9uKFwidGFiaW5kZXhcIiwgbnVsbCwgZnVuY3Rpb24gKGNtLCB2YWwpIHsgcmV0dXJuIGNtLmRpc3BsYXkuaW5wdXQuZ2V0RmllbGQoKS50YWJJbmRleCA9IHZhbCB8fCBcIlwiOyB9KTtcbiAgICBvcHRpb24oXCJhdXRvZm9jdXNcIiwgbnVsbCk7XG4gICAgb3B0aW9uKFwiZGlyZWN0aW9uXCIsIFwibHRyXCIsIGZ1bmN0aW9uIChjbSwgdmFsKSB7IHJldHVybiBjbS5kb2Muc2V0RGlyZWN0aW9uKHZhbCk7IH0sIHRydWUpO1xuICAgIG9wdGlvbihcInBocmFzZXNcIiwgbnVsbCk7XG4gIH1cblxuICBmdW5jdGlvbiBndXR0ZXJzQ2hhbmdlZChjbSkge1xuICAgIHVwZGF0ZUd1dHRlcnMoY20pO1xuICAgIHJlZ0NoYW5nZShjbSk7XG4gICAgYWxpZ25Ib3Jpem9udGFsbHkoY20pO1xuICB9XG5cbiAgZnVuY3Rpb24gZHJhZ0Ryb3BDaGFuZ2VkKGNtLCB2YWx1ZSwgb2xkKSB7XG4gICAgdmFyIHdhc09uID0gb2xkICYmIG9sZCAhPSBJbml0O1xuICAgIGlmICghdmFsdWUgIT0gIXdhc09uKSB7XG4gICAgICB2YXIgZnVuY3MgPSBjbS5kaXNwbGF5LmRyYWdGdW5jdGlvbnM7XG4gICAgICB2YXIgdG9nZ2xlID0gdmFsdWUgPyBvbiA6IG9mZjtcbiAgICAgIHRvZ2dsZShjbS5kaXNwbGF5LnNjcm9sbGVyLCBcImRyYWdzdGFydFwiLCBmdW5jcy5zdGFydCk7XG4gICAgICB0b2dnbGUoY20uZGlzcGxheS5zY3JvbGxlciwgXCJkcmFnZW50ZXJcIiwgZnVuY3MuZW50ZXIpO1xuICAgICAgdG9nZ2xlKGNtLmRpc3BsYXkuc2Nyb2xsZXIsIFwiZHJhZ292ZXJcIiwgZnVuY3Mub3Zlcik7XG4gICAgICB0b2dnbGUoY20uZGlzcGxheS5zY3JvbGxlciwgXCJkcmFnbGVhdmVcIiwgZnVuY3MubGVhdmUpO1xuICAgICAgdG9nZ2xlKGNtLmRpc3BsYXkuc2Nyb2xsZXIsIFwiZHJvcFwiLCBmdW5jcy5kcm9wKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiB3cmFwcGluZ0NoYW5nZWQoY20pIHtcbiAgICBpZiAoY20ub3B0aW9ucy5saW5lV3JhcHBpbmcpIHtcbiAgICAgIGFkZENsYXNzKGNtLmRpc3BsYXkud3JhcHBlciwgXCJDb2RlTWlycm9yLXdyYXBcIik7XG4gICAgICBjbS5kaXNwbGF5LnNpemVyLnN0eWxlLm1pbldpZHRoID0gXCJcIjtcbiAgICAgIGNtLmRpc3BsYXkuc2l6ZXJXaWR0aCA9IG51bGw7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJtQ2xhc3MoY20uZGlzcGxheS53cmFwcGVyLCBcIkNvZGVNaXJyb3Itd3JhcFwiKTtcbiAgICAgIGZpbmRNYXhMaW5lKGNtKTtcbiAgICB9XG4gICAgZXN0aW1hdGVMaW5lSGVpZ2h0cyhjbSk7XG4gICAgcmVnQ2hhbmdlKGNtKTtcbiAgICBjbGVhckNhY2hlcyhjbSk7XG4gICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7IHJldHVybiB1cGRhdGVTY3JvbGxiYXJzKGNtKTsgfSwgMTAwKTtcbiAgfVxuXG4gIC8vIEEgQ29kZU1pcnJvciBpbnN0YW5jZSByZXByZXNlbnRzIGFuIGVkaXRvci4gVGhpcyBpcyB0aGUgb2JqZWN0XG4gIC8vIHRoYXQgdXNlciBjb2RlIGlzIHVzdWFsbHkgZGVhbGluZyB3aXRoLlxuXG4gIGZ1bmN0aW9uIENvZGVNaXJyb3IocGxhY2UsIG9wdGlvbnMpIHtcbiAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgIGlmICghKHRoaXMgaW5zdGFuY2VvZiBDb2RlTWlycm9yKSkgeyByZXR1cm4gbmV3IENvZGVNaXJyb3IocGxhY2UsIG9wdGlvbnMpIH1cblxuICAgIHRoaXMub3B0aW9ucyA9IG9wdGlvbnMgPSBvcHRpb25zID8gY29weU9iaihvcHRpb25zKSA6IHt9O1xuICAgIC8vIERldGVybWluZSBlZmZlY3RpdmUgb3B0aW9ucyBiYXNlZCBvbiBnaXZlbiB2YWx1ZXMgYW5kIGRlZmF1bHRzLlxuICAgIGNvcHlPYmooZGVmYXVsdHMsIG9wdGlvbnMsIGZhbHNlKTtcbiAgICBzZXRHdXR0ZXJzRm9yTGluZU51bWJlcnMob3B0aW9ucyk7XG5cbiAgICB2YXIgZG9jID0gb3B0aW9ucy52YWx1ZTtcbiAgICBpZiAodHlwZW9mIGRvYyA9PSBcInN0cmluZ1wiKSB7IGRvYyA9IG5ldyBEb2MoZG9jLCBvcHRpb25zLm1vZGUsIG51bGwsIG9wdGlvbnMubGluZVNlcGFyYXRvciwgb3B0aW9ucy5kaXJlY3Rpb24pOyB9XG4gICAgZWxzZSBpZiAob3B0aW9ucy5tb2RlKSB7IGRvYy5tb2RlT3B0aW9uID0gb3B0aW9ucy5tb2RlOyB9XG4gICAgdGhpcy5kb2MgPSBkb2M7XG5cbiAgICB2YXIgaW5wdXQgPSBuZXcgQ29kZU1pcnJvci5pbnB1dFN0eWxlc1tvcHRpb25zLmlucHV0U3R5bGVdKHRoaXMpO1xuICAgIHZhciBkaXNwbGF5ID0gdGhpcy5kaXNwbGF5ID0gbmV3IERpc3BsYXkocGxhY2UsIGRvYywgaW5wdXQpO1xuICAgIGRpc3BsYXkud3JhcHBlci5Db2RlTWlycm9yID0gdGhpcztcbiAgICB1cGRhdGVHdXR0ZXJzKHRoaXMpO1xuICAgIHRoZW1lQ2hhbmdlZCh0aGlzKTtcbiAgICBpZiAob3B0aW9ucy5saW5lV3JhcHBpbmcpXG4gICAgICB7IHRoaXMuZGlzcGxheS53cmFwcGVyLmNsYXNzTmFtZSArPSBcIiBDb2RlTWlycm9yLXdyYXBcIjsgfVxuICAgIGluaXRTY3JvbGxiYXJzKHRoaXMpO1xuXG4gICAgdGhpcy5zdGF0ZSA9IHtcbiAgICAgIGtleU1hcHM6IFtdLCAgLy8gc3RvcmVzIG1hcHMgYWRkZWQgYnkgYWRkS2V5TWFwXG4gICAgICBvdmVybGF5czogW10sIC8vIGhpZ2hsaWdodGluZyBvdmVybGF5cywgYXMgYWRkZWQgYnkgYWRkT3ZlcmxheVxuICAgICAgbW9kZUdlbjogMCwgICAvLyBidW1wZWQgd2hlbiBtb2RlL292ZXJsYXkgY2hhbmdlcywgdXNlZCB0byBpbnZhbGlkYXRlIGhpZ2hsaWdodGluZyBpbmZvXG4gICAgICBvdmVyd3JpdGU6IGZhbHNlLFxuICAgICAgZGVsYXlpbmdCbHVyRXZlbnQ6IGZhbHNlLFxuICAgICAgZm9jdXNlZDogZmFsc2UsXG4gICAgICBzdXBwcmVzc0VkaXRzOiBmYWxzZSwgLy8gdXNlZCB0byBkaXNhYmxlIGVkaXRpbmcgZHVyaW5nIGtleSBoYW5kbGVycyB3aGVuIGluIHJlYWRPbmx5IG1vZGVcbiAgICAgIHBhc3RlSW5jb21pbmc6IGZhbHNlLCBjdXRJbmNvbWluZzogZmFsc2UsIC8vIGhlbHAgcmVjb2duaXplIHBhc3RlL2N1dCBlZGl0cyBpbiBpbnB1dC5wb2xsXG4gICAgICBzZWxlY3RpbmdUZXh0OiBmYWxzZSxcbiAgICAgIGRyYWdnaW5nVGV4dDogZmFsc2UsXG4gICAgICBoaWdobGlnaHQ6IG5ldyBEZWxheWVkKCksIC8vIHN0b3JlcyBoaWdobGlnaHQgd29ya2VyIHRpbWVvdXRcbiAgICAgIGtleVNlcTogbnVsbCwgIC8vIFVuZmluaXNoZWQga2V5IHNlcXVlbmNlXG4gICAgICBzcGVjaWFsQ2hhcnM6IG51bGxcbiAgICB9O1xuXG4gICAgaWYgKG9wdGlvbnMuYXV0b2ZvY3VzICYmICFtb2JpbGUpIHsgZGlzcGxheS5pbnB1dC5mb2N1cygpOyB9XG5cbiAgICAvLyBPdmVycmlkZSBtYWdpYyB0ZXh0YXJlYSBjb250ZW50IHJlc3RvcmUgdGhhdCBJRSBzb21ldGltZXMgZG9lc1xuICAgIC8vIG9uIG91ciBoaWRkZW4gdGV4dGFyZWEgb24gcmVsb2FkXG4gICAgaWYgKGllICYmIGllX3ZlcnNpb24gPCAxMSkgeyBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMkMS5kaXNwbGF5LmlucHV0LnJlc2V0KHRydWUpOyB9LCAyMCk7IH1cblxuICAgIHJlZ2lzdGVyRXZlbnRIYW5kbGVycyh0aGlzKTtcbiAgICBlbnN1cmVHbG9iYWxIYW5kbGVycygpO1xuXG4gICAgc3RhcnRPcGVyYXRpb24odGhpcyk7XG4gICAgdGhpcy5jdXJPcC5mb3JjZVVwZGF0ZSA9IHRydWU7XG4gICAgYXR0YWNoRG9jKHRoaXMsIGRvYyk7XG5cbiAgICBpZiAoKG9wdGlvbnMuYXV0b2ZvY3VzICYmICFtb2JpbGUpIHx8IHRoaXMuaGFzRm9jdXMoKSlcbiAgICAgIHsgc2V0VGltZW91dChiaW5kKG9uRm9jdXMsIHRoaXMpLCAyMCk7IH1cbiAgICBlbHNlXG4gICAgICB7IG9uQmx1cih0aGlzKTsgfVxuXG4gICAgZm9yICh2YXIgb3B0IGluIG9wdGlvbkhhbmRsZXJzKSB7IGlmIChvcHRpb25IYW5kbGVycy5oYXNPd25Qcm9wZXJ0eShvcHQpKVxuICAgICAgeyBvcHRpb25IYW5kbGVyc1tvcHRdKHRoaXMkMSwgb3B0aW9uc1tvcHRdLCBJbml0KTsgfSB9XG4gICAgbWF5YmVVcGRhdGVMaW5lTnVtYmVyV2lkdGgodGhpcyk7XG4gICAgaWYgKG9wdGlvbnMuZmluaXNoSW5pdCkgeyBvcHRpb25zLmZpbmlzaEluaXQodGhpcyk7IH1cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGluaXRIb29rcy5sZW5ndGg7ICsraSkgeyBpbml0SG9va3NbaV0odGhpcyQxKTsgfVxuICAgIGVuZE9wZXJhdGlvbih0aGlzKTtcbiAgICAvLyBTdXBwcmVzcyBvcHRpbWl6ZWxlZ2liaWxpdHkgaW4gV2Via2l0LCBzaW5jZSBpdCBicmVha3MgdGV4dFxuICAgIC8vIG1lYXN1cmluZyBvbiBsaW5lIHdyYXBwaW5nIGJvdW5kYXJpZXMuXG4gICAgaWYgKHdlYmtpdCAmJiBvcHRpb25zLmxpbmVXcmFwcGluZyAmJlxuICAgICAgICBnZXRDb21wdXRlZFN0eWxlKGRpc3BsYXkubGluZURpdikudGV4dFJlbmRlcmluZyA9PSBcIm9wdGltaXplbGVnaWJpbGl0eVwiKVxuICAgICAgeyBkaXNwbGF5LmxpbmVEaXYuc3R5bGUudGV4dFJlbmRlcmluZyA9IFwiYXV0b1wiOyB9XG4gIH1cblxuICAvLyBUaGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIG9wdGlvbnMuXG4gIENvZGVNaXJyb3IuZGVmYXVsdHMgPSBkZWZhdWx0cztcbiAgLy8gRnVuY3Rpb25zIHRvIHJ1biB3aGVuIG9wdGlvbnMgYXJlIGNoYW5nZWQuXG4gIENvZGVNaXJyb3Iub3B0aW9uSGFuZGxlcnMgPSBvcHRpb25IYW5kbGVycztcblxuICAvLyBBdHRhY2ggdGhlIG5lY2Vzc2FyeSBldmVudCBoYW5kbGVycyB3aGVuIGluaXRpYWxpemluZyB0aGUgZWRpdG9yXG4gIGZ1bmN0aW9uIHJlZ2lzdGVyRXZlbnRIYW5kbGVycyhjbSkge1xuICAgIHZhciBkID0gY20uZGlzcGxheTtcbiAgICBvbihkLnNjcm9sbGVyLCBcIm1vdXNlZG93blwiLCBvcGVyYXRpb24oY20sIG9uTW91c2VEb3duKSk7XG4gICAgLy8gT2xkZXIgSUUncyB3aWxsIG5vdCBmaXJlIGEgc2Vjb25kIG1vdXNlZG93biBmb3IgYSBkb3VibGUgY2xpY2tcbiAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDExKVxuICAgICAgeyBvbihkLnNjcm9sbGVyLCBcImRibGNsaWNrXCIsIG9wZXJhdGlvbihjbSwgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgaWYgKHNpZ25hbERPTUV2ZW50KGNtLCBlKSkgeyByZXR1cm4gfVxuICAgICAgICB2YXIgcG9zID0gcG9zRnJvbU1vdXNlKGNtLCBlKTtcbiAgICAgICAgaWYgKCFwb3MgfHwgY2xpY2tJbkd1dHRlcihjbSwgZSkgfHwgZXZlbnRJbldpZGdldChjbS5kaXNwbGF5LCBlKSkgeyByZXR1cm4gfVxuICAgICAgICBlX3ByZXZlbnREZWZhdWx0KGUpO1xuICAgICAgICB2YXIgd29yZCA9IGNtLmZpbmRXb3JkQXQocG9zKTtcbiAgICAgICAgZXh0ZW5kU2VsZWN0aW9uKGNtLmRvYywgd29yZC5hbmNob3IsIHdvcmQuaGVhZCk7XG4gICAgICB9KSk7IH1cbiAgICBlbHNlXG4gICAgICB7IG9uKGQuc2Nyb2xsZXIsIFwiZGJsY2xpY2tcIiwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIHNpZ25hbERPTUV2ZW50KGNtLCBlKSB8fCBlX3ByZXZlbnREZWZhdWx0KGUpOyB9KTsgfVxuICAgIC8vIFNvbWUgYnJvd3NlcnMgZmlyZSBjb250ZXh0bWVudSAqYWZ0ZXIqIG9wZW5pbmcgdGhlIG1lbnUsIGF0XG4gICAgLy8gd2hpY2ggcG9pbnQgd2UgY2FuJ3QgbWVzcyB3aXRoIGl0IGFueW1vcmUuIENvbnRleHQgbWVudSBpc1xuICAgIC8vIGhhbmRsZWQgaW4gb25Nb3VzZURvd24gZm9yIHRoZXNlIGJyb3dzZXJzLlxuICAgIG9uKGQuc2Nyb2xsZXIsIFwiY29udGV4dG1lbnVcIiwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG9uQ29udGV4dE1lbnUoY20sIGUpOyB9KTtcblxuICAgIC8vIFVzZWQgdG8gc3VwcHJlc3MgbW91c2UgZXZlbnQgaGFuZGxpbmcgd2hlbiBhIHRvdWNoIGhhcHBlbnNcbiAgICB2YXIgdG91Y2hGaW5pc2hlZCwgcHJldlRvdWNoID0ge2VuZDogMH07XG4gICAgZnVuY3Rpb24gZmluaXNoVG91Y2goKSB7XG4gICAgICBpZiAoZC5hY3RpdmVUb3VjaCkge1xuICAgICAgICB0b3VjaEZpbmlzaGVkID0gc2V0VGltZW91dChmdW5jdGlvbiAoKSB7IHJldHVybiBkLmFjdGl2ZVRvdWNoID0gbnVsbDsgfSwgMTAwMCk7XG4gICAgICAgIHByZXZUb3VjaCA9IGQuYWN0aXZlVG91Y2g7XG4gICAgICAgIHByZXZUb3VjaC5lbmQgPSArbmV3IERhdGU7XG4gICAgICB9XG4gICAgfVxuICAgIGZ1bmN0aW9uIGlzTW91c2VMaWtlVG91Y2hFdmVudChlKSB7XG4gICAgICBpZiAoZS50b3VjaGVzLmxlbmd0aCAhPSAxKSB7IHJldHVybiBmYWxzZSB9XG4gICAgICB2YXIgdG91Y2ggPSBlLnRvdWNoZXNbMF07XG4gICAgICByZXR1cm4gdG91Y2gucmFkaXVzWCA8PSAxICYmIHRvdWNoLnJhZGl1c1kgPD0gMVxuICAgIH1cbiAgICBmdW5jdGlvbiBmYXJBd2F5KHRvdWNoLCBvdGhlcikge1xuICAgICAgaWYgKG90aGVyLmxlZnQgPT0gbnVsbCkgeyByZXR1cm4gdHJ1ZSB9XG4gICAgICB2YXIgZHggPSBvdGhlci5sZWZ0IC0gdG91Y2gubGVmdCwgZHkgPSBvdGhlci50b3AgLSB0b3VjaC50b3A7XG4gICAgICByZXR1cm4gZHggKiBkeCArIGR5ICogZHkgPiAyMCAqIDIwXG4gICAgfVxuICAgIG9uKGQuc2Nyb2xsZXIsIFwidG91Y2hzdGFydFwiLCBmdW5jdGlvbiAoZSkge1xuICAgICAgaWYgKCFzaWduYWxET01FdmVudChjbSwgZSkgJiYgIWlzTW91c2VMaWtlVG91Y2hFdmVudChlKSAmJiAhY2xpY2tJbkd1dHRlcihjbSwgZSkpIHtcbiAgICAgICAgZC5pbnB1dC5lbnN1cmVQb2xsZWQoKTtcbiAgICAgICAgY2xlYXJUaW1lb3V0KHRvdWNoRmluaXNoZWQpO1xuICAgICAgICB2YXIgbm93ID0gK25ldyBEYXRlO1xuICAgICAgICBkLmFjdGl2ZVRvdWNoID0ge3N0YXJ0OiBub3csIG1vdmVkOiBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgICAgICBwcmV2OiBub3cgLSBwcmV2VG91Y2guZW5kIDw9IDMwMCA/IHByZXZUb3VjaCA6IG51bGx9O1xuICAgICAgICBpZiAoZS50b3VjaGVzLmxlbmd0aCA9PSAxKSB7XG4gICAgICAgICAgZC5hY3RpdmVUb3VjaC5sZWZ0ID0gZS50b3VjaGVzWzBdLnBhZ2VYO1xuICAgICAgICAgIGQuYWN0aXZlVG91Y2gudG9wID0gZS50b3VjaGVzWzBdLnBhZ2VZO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfSk7XG4gICAgb24oZC5zY3JvbGxlciwgXCJ0b3VjaG1vdmVcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgaWYgKGQuYWN0aXZlVG91Y2gpIHsgZC5hY3RpdmVUb3VjaC5tb3ZlZCA9IHRydWU7IH1cbiAgICB9KTtcbiAgICBvbihkLnNjcm9sbGVyLCBcInRvdWNoZW5kXCIsIGZ1bmN0aW9uIChlKSB7XG4gICAgICB2YXIgdG91Y2ggPSBkLmFjdGl2ZVRvdWNoO1xuICAgICAgaWYgKHRvdWNoICYmICFldmVudEluV2lkZ2V0KGQsIGUpICYmIHRvdWNoLmxlZnQgIT0gbnVsbCAmJlxuICAgICAgICAgICF0b3VjaC5tb3ZlZCAmJiBuZXcgRGF0ZSAtIHRvdWNoLnN0YXJ0IDwgMzAwKSB7XG4gICAgICAgIHZhciBwb3MgPSBjbS5jb29yZHNDaGFyKGQuYWN0aXZlVG91Y2gsIFwicGFnZVwiKSwgcmFuZ2U7XG4gICAgICAgIGlmICghdG91Y2gucHJldiB8fCBmYXJBd2F5KHRvdWNoLCB0b3VjaC5wcmV2KSkgLy8gU2luZ2xlIHRhcFxuICAgICAgICAgIHsgcmFuZ2UgPSBuZXcgUmFuZ2UocG9zLCBwb3MpOyB9XG4gICAgICAgIGVsc2UgaWYgKCF0b3VjaC5wcmV2LnByZXYgfHwgZmFyQXdheSh0b3VjaCwgdG91Y2gucHJldi5wcmV2KSkgLy8gRG91YmxlIHRhcFxuICAgICAgICAgIHsgcmFuZ2UgPSBjbS5maW5kV29yZEF0KHBvcyk7IH1cbiAgICAgICAgZWxzZSAvLyBUcmlwbGUgdGFwXG4gICAgICAgICAgeyByYW5nZSA9IG5ldyBSYW5nZShQb3MocG9zLmxpbmUsIDApLCBjbGlwUG9zKGNtLmRvYywgUG9zKHBvcy5saW5lICsgMSwgMCkpKTsgfVxuICAgICAgICBjbS5zZXRTZWxlY3Rpb24ocmFuZ2UuYW5jaG9yLCByYW5nZS5oZWFkKTtcbiAgICAgICAgY20uZm9jdXMoKTtcbiAgICAgICAgZV9wcmV2ZW50RGVmYXVsdChlKTtcbiAgICAgIH1cbiAgICAgIGZpbmlzaFRvdWNoKCk7XG4gICAgfSk7XG4gICAgb24oZC5zY3JvbGxlciwgXCJ0b3VjaGNhbmNlbFwiLCBmaW5pc2hUb3VjaCk7XG5cbiAgICAvLyBTeW5jIHNjcm9sbGluZyBiZXR3ZWVuIGZha2Ugc2Nyb2xsYmFycyBhbmQgcmVhbCBzY3JvbGxhYmxlXG4gICAgLy8gYXJlYSwgZW5zdXJlIHZpZXdwb3J0IGlzIHVwZGF0ZWQgd2hlbiBzY3JvbGxpbmcuXG4gICAgb24oZC5zY3JvbGxlciwgXCJzY3JvbGxcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgaWYgKGQuc2Nyb2xsZXIuY2xpZW50SGVpZ2h0KSB7XG4gICAgICAgIHVwZGF0ZVNjcm9sbFRvcChjbSwgZC5zY3JvbGxlci5zY3JvbGxUb3ApO1xuICAgICAgICBzZXRTY3JvbGxMZWZ0KGNtLCBkLnNjcm9sbGVyLnNjcm9sbExlZnQsIHRydWUpO1xuICAgICAgICBzaWduYWwoY20sIFwic2Nyb2xsXCIsIGNtKTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIC8vIExpc3RlbiB0byB3aGVlbCBldmVudHMgaW4gb3JkZXIgdG8gdHJ5IGFuZCB1cGRhdGUgdGhlIHZpZXdwb3J0IG9uIHRpbWUuXG4gICAgb24oZC5zY3JvbGxlciwgXCJtb3VzZXdoZWVsXCIsIGZ1bmN0aW9uIChlKSB7IHJldHVybiBvblNjcm9sbFdoZWVsKGNtLCBlKTsgfSk7XG4gICAgb24oZC5zY3JvbGxlciwgXCJET01Nb3VzZVNjcm9sbFwiLCBmdW5jdGlvbiAoZSkgeyByZXR1cm4gb25TY3JvbGxXaGVlbChjbSwgZSk7IH0pO1xuXG4gICAgLy8gUHJldmVudCB3cmFwcGVyIGZyb20gZXZlciBzY3JvbGxpbmdcbiAgICBvbihkLndyYXBwZXIsIFwic2Nyb2xsXCIsIGZ1bmN0aW9uICgpIHsgcmV0dXJuIGQud3JhcHBlci5zY3JvbGxUb3AgPSBkLndyYXBwZXIuc2Nyb2xsTGVmdCA9IDA7IH0pO1xuXG4gICAgZC5kcmFnRnVuY3Rpb25zID0ge1xuICAgICAgZW50ZXI6IGZ1bmN0aW9uIChlKSB7aWYgKCFzaWduYWxET01FdmVudChjbSwgZSkpIHsgZV9zdG9wKGUpOyB9fSxcbiAgICAgIG92ZXI6IGZ1bmN0aW9uIChlKSB7aWYgKCFzaWduYWxET01FdmVudChjbSwgZSkpIHsgb25EcmFnT3ZlcihjbSwgZSk7IGVfc3RvcChlKTsgfX0sXG4gICAgICBzdGFydDogZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG9uRHJhZ1N0YXJ0KGNtLCBlKTsgfSxcbiAgICAgIGRyb3A6IG9wZXJhdGlvbihjbSwgb25Ecm9wKSxcbiAgICAgIGxlYXZlOiBmdW5jdGlvbiAoZSkge2lmICghc2lnbmFsRE9NRXZlbnQoY20sIGUpKSB7IGNsZWFyRHJhZ0N1cnNvcihjbSk7IH19XG4gICAgfTtcblxuICAgIHZhciBpbnAgPSBkLmlucHV0LmdldEZpZWxkKCk7XG4gICAgb24oaW5wLCBcImtleXVwXCIsIGZ1bmN0aW9uIChlKSB7IHJldHVybiBvbktleVVwLmNhbGwoY20sIGUpOyB9KTtcbiAgICBvbihpbnAsIFwia2V5ZG93blwiLCBvcGVyYXRpb24oY20sIG9uS2V5RG93bikpO1xuICAgIG9uKGlucCwgXCJrZXlwcmVzc1wiLCBvcGVyYXRpb24oY20sIG9uS2V5UHJlc3MpKTtcbiAgICBvbihpbnAsIFwiZm9jdXNcIiwgZnVuY3Rpb24gKGUpIHsgcmV0dXJuIG9uRm9jdXMoY20sIGUpOyB9KTtcbiAgICBvbihpbnAsIFwiYmx1clwiLCBmdW5jdGlvbiAoZSkgeyByZXR1cm4gb25CbHVyKGNtLCBlKTsgfSk7XG4gIH1cblxuICB2YXIgaW5pdEhvb2tzID0gW107XG4gIENvZGVNaXJyb3IuZGVmaW5lSW5pdEhvb2sgPSBmdW5jdGlvbiAoZikgeyByZXR1cm4gaW5pdEhvb2tzLnB1c2goZik7IH07XG5cbiAgLy8gSW5kZW50IHRoZSBnaXZlbiBsaW5lLiBUaGUgaG93IHBhcmFtZXRlciBjYW4gYmUgXCJzbWFydFwiLFxuICAvLyBcImFkZFwiL251bGwsIFwic3VidHJhY3RcIiwgb3IgXCJwcmV2XCIuIFdoZW4gYWdncmVzc2l2ZSBpcyBmYWxzZVxuICAvLyAodHlwaWNhbGx5IHNldCB0byB0cnVlIGZvciBmb3JjZWQgc2luZ2xlLWxpbmUgaW5kZW50cyksIGVtcHR5XG4gIC8vIGxpbmVzIGFyZSBub3QgaW5kZW50ZWQsIGFuZCBwbGFjZXMgd2hlcmUgdGhlIG1vZGUgcmV0dXJucyBQYXNzXG4gIC8vIGFyZSBsZWZ0IGFsb25lLlxuICBmdW5jdGlvbiBpbmRlbnRMaW5lKGNtLCBuLCBob3csIGFnZ3Jlc3NpdmUpIHtcbiAgICB2YXIgZG9jID0gY20uZG9jLCBzdGF0ZTtcbiAgICBpZiAoaG93ID09IG51bGwpIHsgaG93ID0gXCJhZGRcIjsgfVxuICAgIGlmIChob3cgPT0gXCJzbWFydFwiKSB7XG4gICAgICAvLyBGYWxsIGJhY2sgdG8gXCJwcmV2XCIgd2hlbiB0aGUgbW9kZSBkb2Vzbid0IGhhdmUgYW4gaW5kZW50YXRpb25cbiAgICAgIC8vIG1ldGhvZC5cbiAgICAgIGlmICghZG9jLm1vZGUuaW5kZW50KSB7IGhvdyA9IFwicHJldlwiOyB9XG4gICAgICBlbHNlIHsgc3RhdGUgPSBnZXRDb250ZXh0QmVmb3JlKGNtLCBuKS5zdGF0ZTsgfVxuICAgIH1cblxuICAgIHZhciB0YWJTaXplID0gY20ub3B0aW9ucy50YWJTaXplO1xuICAgIHZhciBsaW5lID0gZ2V0TGluZShkb2MsIG4pLCBjdXJTcGFjZSA9IGNvdW50Q29sdW1uKGxpbmUudGV4dCwgbnVsbCwgdGFiU2l6ZSk7XG4gICAgaWYgKGxpbmUuc3RhdGVBZnRlcikgeyBsaW5lLnN0YXRlQWZ0ZXIgPSBudWxsOyB9XG4gICAgdmFyIGN1clNwYWNlU3RyaW5nID0gbGluZS50ZXh0Lm1hdGNoKC9eXFxzKi8pWzBdLCBpbmRlbnRhdGlvbjtcbiAgICBpZiAoIWFnZ3Jlc3NpdmUgJiYgIS9cXFMvLnRlc3QobGluZS50ZXh0KSkge1xuICAgICAgaW5kZW50YXRpb24gPSAwO1xuICAgICAgaG93ID0gXCJub3RcIjtcbiAgICB9IGVsc2UgaWYgKGhvdyA9PSBcInNtYXJ0XCIpIHtcbiAgICAgIGluZGVudGF0aW9uID0gZG9jLm1vZGUuaW5kZW50KHN0YXRlLCBsaW5lLnRleHQuc2xpY2UoY3VyU3BhY2VTdHJpbmcubGVuZ3RoKSwgbGluZS50ZXh0KTtcbiAgICAgIGlmIChpbmRlbnRhdGlvbiA9PSBQYXNzIHx8IGluZGVudGF0aW9uID4gMTUwKSB7XG4gICAgICAgIGlmICghYWdncmVzc2l2ZSkgeyByZXR1cm4gfVxuICAgICAgICBob3cgPSBcInByZXZcIjtcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGhvdyA9PSBcInByZXZcIikge1xuICAgICAgaWYgKG4gPiBkb2MuZmlyc3QpIHsgaW5kZW50YXRpb24gPSBjb3VudENvbHVtbihnZXRMaW5lKGRvYywgbi0xKS50ZXh0LCBudWxsLCB0YWJTaXplKTsgfVxuICAgICAgZWxzZSB7IGluZGVudGF0aW9uID0gMDsgfVxuICAgIH0gZWxzZSBpZiAoaG93ID09IFwiYWRkXCIpIHtcbiAgICAgIGluZGVudGF0aW9uID0gY3VyU3BhY2UgKyBjbS5vcHRpb25zLmluZGVudFVuaXQ7XG4gICAgfSBlbHNlIGlmIChob3cgPT0gXCJzdWJ0cmFjdFwiKSB7XG4gICAgICBpbmRlbnRhdGlvbiA9IGN1clNwYWNlIC0gY20ub3B0aW9ucy5pbmRlbnRVbml0O1xuICAgIH0gZWxzZSBpZiAodHlwZW9mIGhvdyA9PSBcIm51bWJlclwiKSB7XG4gICAgICBpbmRlbnRhdGlvbiA9IGN1clNwYWNlICsgaG93O1xuICAgIH1cbiAgICBpbmRlbnRhdGlvbiA9IE1hdGgubWF4KDAsIGluZGVudGF0aW9uKTtcblxuICAgIHZhciBpbmRlbnRTdHJpbmcgPSBcIlwiLCBwb3MgPSAwO1xuICAgIGlmIChjbS5vcHRpb25zLmluZGVudFdpdGhUYWJzKVxuICAgICAgeyBmb3IgKHZhciBpID0gTWF0aC5mbG9vcihpbmRlbnRhdGlvbiAvIHRhYlNpemUpOyBpOyAtLWkpIHtwb3MgKz0gdGFiU2l6ZTsgaW5kZW50U3RyaW5nICs9IFwiXFx0XCI7fSB9XG4gICAgaWYgKHBvcyA8IGluZGVudGF0aW9uKSB7IGluZGVudFN0cmluZyArPSBzcGFjZVN0cihpbmRlbnRhdGlvbiAtIHBvcyk7IH1cblxuICAgIGlmIChpbmRlbnRTdHJpbmcgIT0gY3VyU3BhY2VTdHJpbmcpIHtcbiAgICAgIHJlcGxhY2VSYW5nZShkb2MsIGluZGVudFN0cmluZywgUG9zKG4sIDApLCBQb3MobiwgY3VyU3BhY2VTdHJpbmcubGVuZ3RoKSwgXCIraW5wdXRcIik7XG4gICAgICBsaW5lLnN0YXRlQWZ0ZXIgPSBudWxsO1xuICAgICAgcmV0dXJuIHRydWVcbiAgICB9IGVsc2Uge1xuICAgICAgLy8gRW5zdXJlIHRoYXQsIGlmIHRoZSBjdXJzb3Igd2FzIGluIHRoZSB3aGl0ZXNwYWNlIGF0IHRoZSBzdGFydFxuICAgICAgLy8gb2YgdGhlIGxpbmUsIGl0IGlzIG1vdmVkIHRvIHRoZSBlbmQgb2YgdGhhdCBzcGFjZS5cbiAgICAgIGZvciAodmFyIGkkMSA9IDA7IGkkMSA8IGRvYy5zZWwucmFuZ2VzLmxlbmd0aDsgaSQxKyspIHtcbiAgICAgICAgdmFyIHJhbmdlID0gZG9jLnNlbC5yYW5nZXNbaSQxXTtcbiAgICAgICAgaWYgKHJhbmdlLmhlYWQubGluZSA9PSBuICYmIHJhbmdlLmhlYWQuY2ggPCBjdXJTcGFjZVN0cmluZy5sZW5ndGgpIHtcbiAgICAgICAgICB2YXIgcG9zJDEgPSBQb3MobiwgY3VyU3BhY2VTdHJpbmcubGVuZ3RoKTtcbiAgICAgICAgICByZXBsYWNlT25lU2VsZWN0aW9uKGRvYywgaSQxLCBuZXcgUmFuZ2UocG9zJDEsIHBvcyQxKSk7XG4gICAgICAgICAgYnJlYWtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIC8vIFRoaXMgd2lsbCBiZSBzZXQgdG8gYSB7bGluZVdpc2U6IGJvb2wsIHRleHQ6IFtzdHJpbmddfSBvYmplY3QsIHNvXG4gIC8vIHRoYXQsIHdoZW4gcGFzdGluZywgd2Uga25vdyB3aGF0IGtpbmQgb2Ygc2VsZWN0aW9ucyB0aGUgY29waWVkXG4gIC8vIHRleHQgd2FzIG1hZGUgb3V0IG9mLlxuICB2YXIgbGFzdENvcGllZCA9IG51bGw7XG5cbiAgZnVuY3Rpb24gc2V0TGFzdENvcGllZChuZXdMYXN0Q29waWVkKSB7XG4gICAgbGFzdENvcGllZCA9IG5ld0xhc3RDb3BpZWQ7XG4gIH1cblxuICBmdW5jdGlvbiBhcHBseVRleHRJbnB1dChjbSwgaW5zZXJ0ZWQsIGRlbGV0ZWQsIHNlbCwgb3JpZ2luKSB7XG4gICAgdmFyIGRvYyA9IGNtLmRvYztcbiAgICBjbS5kaXNwbGF5LnNoaWZ0ID0gZmFsc2U7XG4gICAgaWYgKCFzZWwpIHsgc2VsID0gZG9jLnNlbDsgfVxuXG4gICAgdmFyIHBhc3RlID0gY20uc3RhdGUucGFzdGVJbmNvbWluZyB8fCBvcmlnaW4gPT0gXCJwYXN0ZVwiO1xuICAgIHZhciB0ZXh0TGluZXMgPSBzcGxpdExpbmVzQXV0byhpbnNlcnRlZCksIG11bHRpUGFzdGUgPSBudWxsO1xuICAgIC8vIFdoZW4gcGFzdGluZyBOIGxpbmVzIGludG8gTiBzZWxlY3Rpb25zLCBpbnNlcnQgb25lIGxpbmUgcGVyIHNlbGVjdGlvblxuICAgIGlmIChwYXN0ZSAmJiBzZWwucmFuZ2VzLmxlbmd0aCA+IDEpIHtcbiAgICAgIGlmIChsYXN0Q29waWVkICYmIGxhc3RDb3BpZWQudGV4dC5qb2luKFwiXFxuXCIpID09IGluc2VydGVkKSB7XG4gICAgICAgIGlmIChzZWwucmFuZ2VzLmxlbmd0aCAlIGxhc3RDb3BpZWQudGV4dC5sZW5ndGggPT0gMCkge1xuICAgICAgICAgIG11bHRpUGFzdGUgPSBbXTtcbiAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxhc3RDb3BpZWQudGV4dC5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIHsgbXVsdGlQYXN0ZS5wdXNoKGRvYy5zcGxpdExpbmVzKGxhc3RDb3BpZWQudGV4dFtpXSkpOyB9XG4gICAgICAgIH1cbiAgICAgIH0gZWxzZSBpZiAodGV4dExpbmVzLmxlbmd0aCA9PSBzZWwucmFuZ2VzLmxlbmd0aCAmJiBjbS5vcHRpb25zLnBhc3RlTGluZXNQZXJTZWxlY3Rpb24pIHtcbiAgICAgICAgbXVsdGlQYXN0ZSA9IG1hcCh0ZXh0TGluZXMsIGZ1bmN0aW9uIChsKSB7IHJldHVybiBbbF07IH0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIHZhciB1cGRhdGVJbnB1dCA9IGNtLmN1ck9wLnVwZGF0ZUlucHV0O1xuICAgIC8vIE5vcm1hbCBiZWhhdmlvciBpcyB0byBpbnNlcnQgdGhlIG5ldyB0ZXh0IGludG8gZXZlcnkgc2VsZWN0aW9uXG4gICAgZm9yICh2YXIgaSQxID0gc2VsLnJhbmdlcy5sZW5ndGggLSAxOyBpJDEgPj0gMDsgaSQxLS0pIHtcbiAgICAgIHZhciByYW5nZSQkMSA9IHNlbC5yYW5nZXNbaSQxXTtcbiAgICAgIHZhciBmcm9tID0gcmFuZ2UkJDEuZnJvbSgpLCB0byA9IHJhbmdlJCQxLnRvKCk7XG4gICAgICBpZiAocmFuZ2UkJDEuZW1wdHkoKSkge1xuICAgICAgICBpZiAoZGVsZXRlZCAmJiBkZWxldGVkID4gMCkgLy8gSGFuZGxlIGRlbGV0aW9uXG4gICAgICAgICAgeyBmcm9tID0gUG9zKGZyb20ubGluZSwgZnJvbS5jaCAtIGRlbGV0ZWQpOyB9XG4gICAgICAgIGVsc2UgaWYgKGNtLnN0YXRlLm92ZXJ3cml0ZSAmJiAhcGFzdGUpIC8vIEhhbmRsZSBvdmVyd3JpdGVcbiAgICAgICAgICB7IHRvID0gUG9zKHRvLmxpbmUsIE1hdGgubWluKGdldExpbmUoZG9jLCB0by5saW5lKS50ZXh0Lmxlbmd0aCwgdG8uY2ggKyBsc3QodGV4dExpbmVzKS5sZW5ndGgpKTsgfVxuICAgICAgICBlbHNlIGlmIChwYXN0ZSAmJiBsYXN0Q29waWVkICYmIGxhc3RDb3BpZWQubGluZVdpc2UgJiYgbGFzdENvcGllZC50ZXh0LmpvaW4oXCJcXG5cIikgPT0gaW5zZXJ0ZWQpXG4gICAgICAgICAgeyBmcm9tID0gdG8gPSBQb3MoZnJvbS5saW5lLCAwKTsgfVxuICAgICAgfVxuICAgICAgdmFyIGNoYW5nZUV2ZW50ID0ge2Zyb206IGZyb20sIHRvOiB0bywgdGV4dDogbXVsdGlQYXN0ZSA/IG11bHRpUGFzdGVbaSQxICUgbXVsdGlQYXN0ZS5sZW5ndGhdIDogdGV4dExpbmVzLFxuICAgICAgICAgICAgICAgICAgICAgICAgIG9yaWdpbjogb3JpZ2luIHx8IChwYXN0ZSA/IFwicGFzdGVcIiA6IGNtLnN0YXRlLmN1dEluY29taW5nID8gXCJjdXRcIiA6IFwiK2lucHV0XCIpfTtcbiAgICAgIG1ha2VDaGFuZ2UoY20uZG9jLCBjaGFuZ2VFdmVudCk7XG4gICAgICBzaWduYWxMYXRlcihjbSwgXCJpbnB1dFJlYWRcIiwgY20sIGNoYW5nZUV2ZW50KTtcbiAgICB9XG4gICAgaWYgKGluc2VydGVkICYmICFwYXN0ZSlcbiAgICAgIHsgdHJpZ2dlckVsZWN0cmljKGNtLCBpbnNlcnRlZCk7IH1cblxuICAgIGVuc3VyZUN1cnNvclZpc2libGUoY20pO1xuICAgIGlmIChjbS5jdXJPcC51cGRhdGVJbnB1dCA8IDIpIHsgY20uY3VyT3AudXBkYXRlSW5wdXQgPSB1cGRhdGVJbnB1dDsgfVxuICAgIGNtLmN1ck9wLnR5cGluZyA9IHRydWU7XG4gICAgY20uc3RhdGUucGFzdGVJbmNvbWluZyA9IGNtLnN0YXRlLmN1dEluY29taW5nID0gZmFsc2U7XG4gIH1cblxuICBmdW5jdGlvbiBoYW5kbGVQYXN0ZShlLCBjbSkge1xuICAgIHZhciBwYXN0ZWQgPSBlLmNsaXBib2FyZERhdGEgJiYgZS5jbGlwYm9hcmREYXRhLmdldERhdGEoXCJUZXh0XCIpO1xuICAgIGlmIChwYXN0ZWQpIHtcbiAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgIGlmICghY20uaXNSZWFkT25seSgpICYmICFjbS5vcHRpb25zLmRpc2FibGVJbnB1dClcbiAgICAgICAgeyBydW5Jbk9wKGNtLCBmdW5jdGlvbiAoKSB7IHJldHVybiBhcHBseVRleHRJbnB1dChjbSwgcGFzdGVkLCAwLCBudWxsLCBcInBhc3RlXCIpOyB9KTsgfVxuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiB0cmlnZ2VyRWxlY3RyaWMoY20sIGluc2VydGVkKSB7XG4gICAgLy8gV2hlbiBhbiAnZWxlY3RyaWMnIGNoYXJhY3RlciBpcyBpbnNlcnRlZCwgaW1tZWRpYXRlbHkgdHJpZ2dlciBhIHJlaW5kZW50XG4gICAgaWYgKCFjbS5vcHRpb25zLmVsZWN0cmljQ2hhcnMgfHwgIWNtLm9wdGlvbnMuc21hcnRJbmRlbnQpIHsgcmV0dXJuIH1cbiAgICB2YXIgc2VsID0gY20uZG9jLnNlbDtcblxuICAgIGZvciAodmFyIGkgPSBzZWwucmFuZ2VzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICB2YXIgcmFuZ2UkJDEgPSBzZWwucmFuZ2VzW2ldO1xuICAgICAgaWYgKHJhbmdlJCQxLmhlYWQuY2ggPiAxMDAgfHwgKGkgJiYgc2VsLnJhbmdlc1tpIC0gMV0uaGVhZC5saW5lID09IHJhbmdlJCQxLmhlYWQubGluZSkpIHsgY29udGludWUgfVxuICAgICAgdmFyIG1vZGUgPSBjbS5nZXRNb2RlQXQocmFuZ2UkJDEuaGVhZCk7XG4gICAgICB2YXIgaW5kZW50ZWQgPSBmYWxzZTtcbiAgICAgIGlmIChtb2RlLmVsZWN0cmljQ2hhcnMpIHtcbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBtb2RlLmVsZWN0cmljQ2hhcnMubGVuZ3RoOyBqKyspXG4gICAgICAgICAgeyBpZiAoaW5zZXJ0ZWQuaW5kZXhPZihtb2RlLmVsZWN0cmljQ2hhcnMuY2hhckF0KGopKSA+IC0xKSB7XG4gICAgICAgICAgICBpbmRlbnRlZCA9IGluZGVudExpbmUoY20sIHJhbmdlJCQxLmhlYWQubGluZSwgXCJzbWFydFwiKTtcbiAgICAgICAgICAgIGJyZWFrXG4gICAgICAgICAgfSB9XG4gICAgICB9IGVsc2UgaWYgKG1vZGUuZWxlY3RyaWNJbnB1dCkge1xuICAgICAgICBpZiAobW9kZS5lbGVjdHJpY0lucHV0LnRlc3QoZ2V0TGluZShjbS5kb2MsIHJhbmdlJCQxLmhlYWQubGluZSkudGV4dC5zbGljZSgwLCByYW5nZSQkMS5oZWFkLmNoKSkpXG4gICAgICAgICAgeyBpbmRlbnRlZCA9IGluZGVudExpbmUoY20sIHJhbmdlJCQxLmhlYWQubGluZSwgXCJzbWFydFwiKTsgfVxuICAgICAgfVxuICAgICAgaWYgKGluZGVudGVkKSB7IHNpZ25hbExhdGVyKGNtLCBcImVsZWN0cmljSW5wdXRcIiwgY20sIHJhbmdlJCQxLmhlYWQubGluZSk7IH1cbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBjb3B5YWJsZVJhbmdlcyhjbSkge1xuICAgIHZhciB0ZXh0ID0gW10sIHJhbmdlcyA9IFtdO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY20uZG9jLnNlbC5yYW5nZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgIHZhciBsaW5lID0gY20uZG9jLnNlbC5yYW5nZXNbaV0uaGVhZC5saW5lO1xuICAgICAgdmFyIGxpbmVSYW5nZSA9IHthbmNob3I6IFBvcyhsaW5lLCAwKSwgaGVhZDogUG9zKGxpbmUgKyAxLCAwKX07XG4gICAgICByYW5nZXMucHVzaChsaW5lUmFuZ2UpO1xuICAgICAgdGV4dC5wdXNoKGNtLmdldFJhbmdlKGxpbmVSYW5nZS5hbmNob3IsIGxpbmVSYW5nZS5oZWFkKSk7XG4gICAgfVxuICAgIHJldHVybiB7dGV4dDogdGV4dCwgcmFuZ2VzOiByYW5nZXN9XG4gIH1cblxuICBmdW5jdGlvbiBkaXNhYmxlQnJvd3Nlck1hZ2ljKGZpZWxkLCBzcGVsbGNoZWNrKSB7XG4gICAgZmllbGQuc2V0QXR0cmlidXRlKFwiYXV0b2NvcnJlY3RcIiwgXCJvZmZcIik7XG4gICAgZmllbGQuc2V0QXR0cmlidXRlKFwiYXV0b2NhcGl0YWxpemVcIiwgXCJvZmZcIik7XG4gICAgZmllbGQuc2V0QXR0cmlidXRlKFwic3BlbGxjaGVja1wiLCAhIXNwZWxsY2hlY2spO1xuICB9XG5cbiAgZnVuY3Rpb24gaGlkZGVuVGV4dGFyZWEoKSB7XG4gICAgdmFyIHRlID0gZWx0KFwidGV4dGFyZWFcIiwgbnVsbCwgbnVsbCwgXCJwb3NpdGlvbjogYWJzb2x1dGU7IGJvdHRvbTogLTFlbTsgcGFkZGluZzogMDsgd2lkdGg6IDFweDsgaGVpZ2h0OiAxZW07IG91dGxpbmU6IG5vbmVcIik7XG4gICAgdmFyIGRpdiA9IGVsdChcImRpdlwiLCBbdGVdLCBudWxsLCBcIm92ZXJmbG93OiBoaWRkZW47IHBvc2l0aW9uOiByZWxhdGl2ZTsgd2lkdGg6IDNweDsgaGVpZ2h0OiAwcHg7XCIpO1xuICAgIC8vIFRoZSB0ZXh0YXJlYSBpcyBrZXB0IHBvc2l0aW9uZWQgbmVhciB0aGUgY3Vyc29yIHRvIHByZXZlbnQgdGhlXG4gICAgLy8gZmFjdCB0aGF0IGl0J2xsIGJlIHNjcm9sbGVkIGludG8gdmlldyBvbiBpbnB1dCBmcm9tIHNjcm9sbGluZ1xuICAgIC8vIG91ciBmYWtlIGN1cnNvciBvdXQgb2Ygdmlldy4gT24gd2Via2l0LCB3aGVuIHdyYXA9b2ZmLCBwYXN0ZSBpc1xuICAgIC8vIHZlcnkgc2xvdy4gU28gbWFrZSB0aGUgYXJlYSB3aWRlIGluc3RlYWQuXG4gICAgaWYgKHdlYmtpdCkgeyB0ZS5zdHlsZS53aWR0aCA9IFwiMTAwMHB4XCI7IH1cbiAgICBlbHNlIHsgdGUuc2V0QXR0cmlidXRlKFwid3JhcFwiLCBcIm9mZlwiKTsgfVxuICAgIC8vIElmIGJvcmRlcjogMDsgLS0gaU9TIGZhaWxzIHRvIG9wZW4ga2V5Ym9hcmQgKGlzc3VlICMxMjg3KVxuICAgIGlmIChpb3MpIHsgdGUuc3R5bGUuYm9yZGVyID0gXCIxcHggc29saWQgYmxhY2tcIjsgfVxuICAgIGRpc2FibGVCcm93c2VyTWFnaWModGUpO1xuICAgIHJldHVybiBkaXZcbiAgfVxuXG4gIC8vIFRoZSBwdWJsaWNseSB2aXNpYmxlIEFQSS4gTm90ZSB0aGF0IG1ldGhvZE9wKGYpIG1lYW5zXG4gIC8vICd3cmFwIGYgaW4gYW4gb3BlcmF0aW9uLCBwZXJmb3JtZWQgb24gaXRzIGB0aGlzYCBwYXJhbWV0ZXInLlxuXG4gIC8vIFRoaXMgaXMgbm90IHRoZSBjb21wbGV0ZSBzZXQgb2YgZWRpdG9yIG1ldGhvZHMuIE1vc3Qgb2YgdGhlXG4gIC8vIG1ldGhvZHMgZGVmaW5lZCBvbiB0aGUgRG9jIHR5cGUgYXJlIGFsc28gaW5qZWN0ZWQgaW50b1xuICAvLyBDb2RlTWlycm9yLnByb3RvdHlwZSwgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IGFuZFxuICAvLyBjb252ZW5pZW5jZS5cblxuICBmdW5jdGlvbiBhZGRFZGl0b3JNZXRob2RzKENvZGVNaXJyb3IpIHtcbiAgICB2YXIgb3B0aW9uSGFuZGxlcnMgPSBDb2RlTWlycm9yLm9wdGlvbkhhbmRsZXJzO1xuXG4gICAgdmFyIGhlbHBlcnMgPSBDb2RlTWlycm9yLmhlbHBlcnMgPSB7fTtcblxuICAgIENvZGVNaXJyb3IucHJvdG90eXBlID0ge1xuICAgICAgY29uc3RydWN0b3I6IENvZGVNaXJyb3IsXG4gICAgICBmb2N1czogZnVuY3Rpb24oKXt3aW5kb3cuZm9jdXMoKTsgdGhpcy5kaXNwbGF5LmlucHV0LmZvY3VzKCk7fSxcblxuICAgICAgc2V0T3B0aW9uOiBmdW5jdGlvbihvcHRpb24sIHZhbHVlKSB7XG4gICAgICAgIHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zLCBvbGQgPSBvcHRpb25zW29wdGlvbl07XG4gICAgICAgIGlmIChvcHRpb25zW29wdGlvbl0gPT0gdmFsdWUgJiYgb3B0aW9uICE9IFwibW9kZVwiKSB7IHJldHVybiB9XG4gICAgICAgIG9wdGlvbnNbb3B0aW9uXSA9IHZhbHVlO1xuICAgICAgICBpZiAob3B0aW9uSGFuZGxlcnMuaGFzT3duUHJvcGVydHkob3B0aW9uKSlcbiAgICAgICAgICB7IG9wZXJhdGlvbih0aGlzLCBvcHRpb25IYW5kbGVyc1tvcHRpb25dKSh0aGlzLCB2YWx1ZSwgb2xkKTsgfVxuICAgICAgICBzaWduYWwodGhpcywgXCJvcHRpb25DaGFuZ2VcIiwgdGhpcywgb3B0aW9uKTtcbiAgICAgIH0sXG5cbiAgICAgIGdldE9wdGlvbjogZnVuY3Rpb24ob3B0aW9uKSB7cmV0dXJuIHRoaXMub3B0aW9uc1tvcHRpb25dfSxcbiAgICAgIGdldERvYzogZnVuY3Rpb24oKSB7cmV0dXJuIHRoaXMuZG9jfSxcblxuICAgICAgYWRkS2V5TWFwOiBmdW5jdGlvbihtYXAkJDEsIGJvdHRvbSkge1xuICAgICAgICB0aGlzLnN0YXRlLmtleU1hcHNbYm90dG9tID8gXCJwdXNoXCIgOiBcInVuc2hpZnRcIl0oZ2V0S2V5TWFwKG1hcCQkMSkpO1xuICAgICAgfSxcbiAgICAgIHJlbW92ZUtleU1hcDogZnVuY3Rpb24obWFwJCQxKSB7XG4gICAgICAgIHZhciBtYXBzID0gdGhpcy5zdGF0ZS5rZXlNYXBzO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG1hcHMubGVuZ3RoOyArK2kpXG4gICAgICAgICAgeyBpZiAobWFwc1tpXSA9PSBtYXAkJDEgfHwgbWFwc1tpXS5uYW1lID09IG1hcCQkMSkge1xuICAgICAgICAgICAgbWFwcy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZVxuICAgICAgICAgIH0gfVxuICAgICAgfSxcblxuICAgICAgYWRkT3ZlcmxheTogbWV0aG9kT3AoZnVuY3Rpb24oc3BlYywgb3B0aW9ucykge1xuICAgICAgICB2YXIgbW9kZSA9IHNwZWMudG9rZW4gPyBzcGVjIDogQ29kZU1pcnJvci5nZXRNb2RlKHRoaXMub3B0aW9ucywgc3BlYyk7XG4gICAgICAgIGlmIChtb2RlLnN0YXJ0U3RhdGUpIHsgdGhyb3cgbmV3IEVycm9yKFwiT3ZlcmxheXMgbWF5IG5vdCBiZSBzdGF0ZWZ1bC5cIikgfVxuICAgICAgICBpbnNlcnRTb3J0ZWQodGhpcy5zdGF0ZS5vdmVybGF5cyxcbiAgICAgICAgICAgICAgICAgICAgIHttb2RlOiBtb2RlLCBtb2RlU3BlYzogc3BlYywgb3BhcXVlOiBvcHRpb25zICYmIG9wdGlvbnMub3BhcXVlLFxuICAgICAgICAgICAgICAgICAgICAgIHByaW9yaXR5OiAob3B0aW9ucyAmJiBvcHRpb25zLnByaW9yaXR5KSB8fCAwfSxcbiAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChvdmVybGF5KSB7IHJldHVybiBvdmVybGF5LnByaW9yaXR5OyB9KTtcbiAgICAgICAgdGhpcy5zdGF0ZS5tb2RlR2VuKys7XG4gICAgICAgIHJlZ0NoYW5nZSh0aGlzKTtcbiAgICAgIH0pLFxuICAgICAgcmVtb3ZlT3ZlcmxheTogbWV0aG9kT3AoZnVuY3Rpb24oc3BlYykge1xuICAgICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgICAgICB2YXIgb3ZlcmxheXMgPSB0aGlzLnN0YXRlLm92ZXJsYXlzO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG92ZXJsYXlzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgdmFyIGN1ciA9IG92ZXJsYXlzW2ldLm1vZGVTcGVjO1xuICAgICAgICAgIGlmIChjdXIgPT0gc3BlYyB8fCB0eXBlb2Ygc3BlYyA9PSBcInN0cmluZ1wiICYmIGN1ci5uYW1lID09IHNwZWMpIHtcbiAgICAgICAgICAgIG92ZXJsYXlzLnNwbGljZShpLCAxKTtcbiAgICAgICAgICAgIHRoaXMkMS5zdGF0ZS5tb2RlR2VuKys7XG4gICAgICAgICAgICByZWdDaGFuZ2UodGhpcyQxKTtcbiAgICAgICAgICAgIHJldHVyblxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfSksXG5cbiAgICAgIGluZGVudExpbmU6IG1ldGhvZE9wKGZ1bmN0aW9uKG4sIGRpciwgYWdncmVzc2l2ZSkge1xuICAgICAgICBpZiAodHlwZW9mIGRpciAhPSBcInN0cmluZ1wiICYmIHR5cGVvZiBkaXIgIT0gXCJudW1iZXJcIikge1xuICAgICAgICAgIGlmIChkaXIgPT0gbnVsbCkgeyBkaXIgPSB0aGlzLm9wdGlvbnMuc21hcnRJbmRlbnQgPyBcInNtYXJ0XCIgOiBcInByZXZcIjsgfVxuICAgICAgICAgIGVsc2UgeyBkaXIgPSBkaXIgPyBcImFkZFwiIDogXCJzdWJ0cmFjdFwiOyB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGlzTGluZSh0aGlzLmRvYywgbikpIHsgaW5kZW50TGluZSh0aGlzLCBuLCBkaXIsIGFnZ3Jlc3NpdmUpOyB9XG4gICAgICB9KSxcbiAgICAgIGluZGVudFNlbGVjdGlvbjogbWV0aG9kT3AoZnVuY3Rpb24oaG93KSB7XG4gICAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgICAgIHZhciByYW5nZXMgPSB0aGlzLmRvYy5zZWwucmFuZ2VzLCBlbmQgPSAtMTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByYW5nZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICB2YXIgcmFuZ2UkJDEgPSByYW5nZXNbaV07XG4gICAgICAgICAgaWYgKCFyYW5nZSQkMS5lbXB0eSgpKSB7XG4gICAgICAgICAgICB2YXIgZnJvbSA9IHJhbmdlJCQxLmZyb20oKSwgdG8gPSByYW5nZSQkMS50bygpO1xuICAgICAgICAgICAgdmFyIHN0YXJ0ID0gTWF0aC5tYXgoZW5kLCBmcm9tLmxpbmUpO1xuICAgICAgICAgICAgZW5kID0gTWF0aC5taW4odGhpcyQxLmxhc3RMaW5lKCksIHRvLmxpbmUgLSAodG8uY2ggPyAwIDogMSkpICsgMTtcbiAgICAgICAgICAgIGZvciAodmFyIGogPSBzdGFydDsgaiA8IGVuZDsgKytqKVxuICAgICAgICAgICAgICB7IGluZGVudExpbmUodGhpcyQxLCBqLCBob3cpOyB9XG4gICAgICAgICAgICB2YXIgbmV3UmFuZ2VzID0gdGhpcyQxLmRvYy5zZWwucmFuZ2VzO1xuICAgICAgICAgICAgaWYgKGZyb20uY2ggPT0gMCAmJiByYW5nZXMubGVuZ3RoID09IG5ld1Jhbmdlcy5sZW5ndGggJiYgbmV3UmFuZ2VzW2ldLmZyb20oKS5jaCA+IDApXG4gICAgICAgICAgICAgIHsgcmVwbGFjZU9uZVNlbGVjdGlvbih0aGlzJDEuZG9jLCBpLCBuZXcgUmFuZ2UoZnJvbSwgbmV3UmFuZ2VzW2ldLnRvKCkpLCBzZWxfZG9udFNjcm9sbCk7IH1cbiAgICAgICAgICB9IGVsc2UgaWYgKHJhbmdlJCQxLmhlYWQubGluZSA+IGVuZCkge1xuICAgICAgICAgICAgaW5kZW50TGluZSh0aGlzJDEsIHJhbmdlJCQxLmhlYWQubGluZSwgaG93LCB0cnVlKTtcbiAgICAgICAgICAgIGVuZCA9IHJhbmdlJCQxLmhlYWQubGluZTtcbiAgICAgICAgICAgIGlmIChpID09IHRoaXMkMS5kb2Muc2VsLnByaW1JbmRleCkgeyBlbnN1cmVDdXJzb3JWaXNpYmxlKHRoaXMkMSk7IH1cbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgIH0pLFxuXG4gICAgICAvLyBGZXRjaCB0aGUgcGFyc2VyIHRva2VuIGZvciBhIGdpdmVuIGNoYXJhY3Rlci4gVXNlZnVsIGZvciBoYWNrc1xuICAgICAgLy8gdGhhdCB3YW50IHRvIGluc3BlY3QgdGhlIG1vZGUgc3RhdGUgKHNheSwgZm9yIGNvbXBsZXRpb24pLlxuICAgICAgZ2V0VG9rZW5BdDogZnVuY3Rpb24ocG9zLCBwcmVjaXNlKSB7XG4gICAgICAgIHJldHVybiB0YWtlVG9rZW4odGhpcywgcG9zLCBwcmVjaXNlKVxuICAgICAgfSxcblxuICAgICAgZ2V0TGluZVRva2VuczogZnVuY3Rpb24obGluZSwgcHJlY2lzZSkge1xuICAgICAgICByZXR1cm4gdGFrZVRva2VuKHRoaXMsIFBvcyhsaW5lKSwgcHJlY2lzZSwgdHJ1ZSlcbiAgICAgIH0sXG5cbiAgICAgIGdldFRva2VuVHlwZUF0OiBmdW5jdGlvbihwb3MpIHtcbiAgICAgICAgcG9zID0gY2xpcFBvcyh0aGlzLmRvYywgcG9zKTtcbiAgICAgICAgdmFyIHN0eWxlcyA9IGdldExpbmVTdHlsZXModGhpcywgZ2V0TGluZSh0aGlzLmRvYywgcG9zLmxpbmUpKTtcbiAgICAgICAgdmFyIGJlZm9yZSA9IDAsIGFmdGVyID0gKHN0eWxlcy5sZW5ndGggLSAxKSAvIDIsIGNoID0gcG9zLmNoO1xuICAgICAgICB2YXIgdHlwZTtcbiAgICAgICAgaWYgKGNoID09IDApIHsgdHlwZSA9IHN0eWxlc1syXTsgfVxuICAgICAgICBlbHNlIHsgZm9yICg7Oykge1xuICAgICAgICAgIHZhciBtaWQgPSAoYmVmb3JlICsgYWZ0ZXIpID4+IDE7XG4gICAgICAgICAgaWYgKChtaWQgPyBzdHlsZXNbbWlkICogMiAtIDFdIDogMCkgPj0gY2gpIHsgYWZ0ZXIgPSBtaWQ7IH1cbiAgICAgICAgICBlbHNlIGlmIChzdHlsZXNbbWlkICogMiArIDFdIDwgY2gpIHsgYmVmb3JlID0gbWlkICsgMTsgfVxuICAgICAgICAgIGVsc2UgeyB0eXBlID0gc3R5bGVzW21pZCAqIDIgKyAyXTsgYnJlYWsgfVxuICAgICAgICB9IH1cbiAgICAgICAgdmFyIGN1dCA9IHR5cGUgPyB0eXBlLmluZGV4T2YoXCJvdmVybGF5IFwiKSA6IC0xO1xuICAgICAgICByZXR1cm4gY3V0IDwgMCA/IHR5cGUgOiBjdXQgPT0gMCA/IG51bGwgOiB0eXBlLnNsaWNlKDAsIGN1dCAtIDEpXG4gICAgICB9LFxuXG4gICAgICBnZXRNb2RlQXQ6IGZ1bmN0aW9uKHBvcykge1xuICAgICAgICB2YXIgbW9kZSA9IHRoaXMuZG9jLm1vZGU7XG4gICAgICAgIGlmICghbW9kZS5pbm5lck1vZGUpIHsgcmV0dXJuIG1vZGUgfVxuICAgICAgICByZXR1cm4gQ29kZU1pcnJvci5pbm5lck1vZGUobW9kZSwgdGhpcy5nZXRUb2tlbkF0KHBvcykuc3RhdGUpLm1vZGVcbiAgICAgIH0sXG5cbiAgICAgIGdldEhlbHBlcjogZnVuY3Rpb24ocG9zLCB0eXBlKSB7XG4gICAgICAgIHJldHVybiB0aGlzLmdldEhlbHBlcnMocG9zLCB0eXBlKVswXVxuICAgICAgfSxcblxuICAgICAgZ2V0SGVscGVyczogZnVuY3Rpb24ocG9zLCB0eXBlKSB7XG4gICAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgICAgIHZhciBmb3VuZCA9IFtdO1xuICAgICAgICBpZiAoIWhlbHBlcnMuaGFzT3duUHJvcGVydHkodHlwZSkpIHsgcmV0dXJuIGZvdW5kIH1cbiAgICAgICAgdmFyIGhlbHAgPSBoZWxwZXJzW3R5cGVdLCBtb2RlID0gdGhpcy5nZXRNb2RlQXQocG9zKTtcbiAgICAgICAgaWYgKHR5cGVvZiBtb2RlW3R5cGVdID09IFwic3RyaW5nXCIpIHtcbiAgICAgICAgICBpZiAoaGVscFttb2RlW3R5cGVdXSkgeyBmb3VuZC5wdXNoKGhlbHBbbW9kZVt0eXBlXV0pOyB9XG4gICAgICAgIH0gZWxzZSBpZiAobW9kZVt0eXBlXSkge1xuICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbW9kZVt0eXBlXS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgdmFyIHZhbCA9IGhlbHBbbW9kZVt0eXBlXVtpXV07XG4gICAgICAgICAgICBpZiAodmFsKSB7IGZvdW5kLnB1c2godmFsKTsgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIGlmIChtb2RlLmhlbHBlclR5cGUgJiYgaGVscFttb2RlLmhlbHBlclR5cGVdKSB7XG4gICAgICAgICAgZm91bmQucHVzaChoZWxwW21vZGUuaGVscGVyVHlwZV0pO1xuICAgICAgICB9IGVsc2UgaWYgKGhlbHBbbW9kZS5uYW1lXSkge1xuICAgICAgICAgIGZvdW5kLnB1c2goaGVscFttb2RlLm5hbWVdKTtcbiAgICAgICAgfVxuICAgICAgICBmb3IgKHZhciBpJDEgPSAwOyBpJDEgPCBoZWxwLl9nbG9iYWwubGVuZ3RoOyBpJDErKykge1xuICAgICAgICAgIHZhciBjdXIgPSBoZWxwLl9nbG9iYWxbaSQxXTtcbiAgICAgICAgICBpZiAoY3VyLnByZWQobW9kZSwgdGhpcyQxKSAmJiBpbmRleE9mKGZvdW5kLCBjdXIudmFsKSA9PSAtMSlcbiAgICAgICAgICAgIHsgZm91bmQucHVzaChjdXIudmFsKTsgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmb3VuZFxuICAgICAgfSxcblxuICAgICAgZ2V0U3RhdGVBZnRlcjogZnVuY3Rpb24obGluZSwgcHJlY2lzZSkge1xuICAgICAgICB2YXIgZG9jID0gdGhpcy5kb2M7XG4gICAgICAgIGxpbmUgPSBjbGlwTGluZShkb2MsIGxpbmUgPT0gbnVsbCA/IGRvYy5maXJzdCArIGRvYy5zaXplIC0gMTogbGluZSk7XG4gICAgICAgIHJldHVybiBnZXRDb250ZXh0QmVmb3JlKHRoaXMsIGxpbmUgKyAxLCBwcmVjaXNlKS5zdGF0ZVxuICAgICAgfSxcblxuICAgICAgY3Vyc29yQ29vcmRzOiBmdW5jdGlvbihzdGFydCwgbW9kZSkge1xuICAgICAgICB2YXIgcG9zLCByYW5nZSQkMSA9IHRoaXMuZG9jLnNlbC5wcmltYXJ5KCk7XG4gICAgICAgIGlmIChzdGFydCA9PSBudWxsKSB7IHBvcyA9IHJhbmdlJCQxLmhlYWQ7IH1cbiAgICAgICAgZWxzZSBpZiAodHlwZW9mIHN0YXJ0ID09IFwib2JqZWN0XCIpIHsgcG9zID0gY2xpcFBvcyh0aGlzLmRvYywgc3RhcnQpOyB9XG4gICAgICAgIGVsc2UgeyBwb3MgPSBzdGFydCA/IHJhbmdlJCQxLmZyb20oKSA6IHJhbmdlJCQxLnRvKCk7IH1cbiAgICAgICAgcmV0dXJuIGN1cnNvckNvb3Jkcyh0aGlzLCBwb3MsIG1vZGUgfHwgXCJwYWdlXCIpXG4gICAgICB9LFxuXG4gICAgICBjaGFyQ29vcmRzOiBmdW5jdGlvbihwb3MsIG1vZGUpIHtcbiAgICAgICAgcmV0dXJuIGNoYXJDb29yZHModGhpcywgY2xpcFBvcyh0aGlzLmRvYywgcG9zKSwgbW9kZSB8fCBcInBhZ2VcIilcbiAgICAgIH0sXG5cbiAgICAgIGNvb3Jkc0NoYXI6IGZ1bmN0aW9uKGNvb3JkcywgbW9kZSkge1xuICAgICAgICBjb29yZHMgPSBmcm9tQ29vcmRTeXN0ZW0odGhpcywgY29vcmRzLCBtb2RlIHx8IFwicGFnZVwiKTtcbiAgICAgICAgcmV0dXJuIGNvb3Jkc0NoYXIodGhpcywgY29vcmRzLmxlZnQsIGNvb3Jkcy50b3ApXG4gICAgICB9LFxuXG4gICAgICBsaW5lQXRIZWlnaHQ6IGZ1bmN0aW9uKGhlaWdodCwgbW9kZSkge1xuICAgICAgICBoZWlnaHQgPSBmcm9tQ29vcmRTeXN0ZW0odGhpcywge3RvcDogaGVpZ2h0LCBsZWZ0OiAwfSwgbW9kZSB8fCBcInBhZ2VcIikudG9wO1xuICAgICAgICByZXR1cm4gbGluZUF0SGVpZ2h0KHRoaXMuZG9jLCBoZWlnaHQgKyB0aGlzLmRpc3BsYXkudmlld09mZnNldClcbiAgICAgIH0sXG4gICAgICBoZWlnaHRBdExpbmU6IGZ1bmN0aW9uKGxpbmUsIG1vZGUsIGluY2x1ZGVXaWRnZXRzKSB7XG4gICAgICAgIHZhciBlbmQgPSBmYWxzZSwgbGluZU9iajtcbiAgICAgICAgaWYgKHR5cGVvZiBsaW5lID09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICB2YXIgbGFzdCA9IHRoaXMuZG9jLmZpcnN0ICsgdGhpcy5kb2Muc2l6ZSAtIDE7XG4gICAgICAgICAgaWYgKGxpbmUgPCB0aGlzLmRvYy5maXJzdCkgeyBsaW5lID0gdGhpcy5kb2MuZmlyc3Q7IH1cbiAgICAgICAgICBlbHNlIGlmIChsaW5lID4gbGFzdCkgeyBsaW5lID0gbGFzdDsgZW5kID0gdHJ1ZTsgfVxuICAgICAgICAgIGxpbmVPYmogPSBnZXRMaW5lKHRoaXMuZG9jLCBsaW5lKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBsaW5lT2JqID0gbGluZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaW50b0Nvb3JkU3lzdGVtKHRoaXMsIGxpbmVPYmosIHt0b3A6IDAsIGxlZnQ6IDB9LCBtb2RlIHx8IFwicGFnZVwiLCBpbmNsdWRlV2lkZ2V0cyB8fCBlbmQpLnRvcCArXG4gICAgICAgICAgKGVuZCA/IHRoaXMuZG9jLmhlaWdodCAtIGhlaWdodEF0TGluZShsaW5lT2JqKSA6IDApXG4gICAgICB9LFxuXG4gICAgICBkZWZhdWx0VGV4dEhlaWdodDogZnVuY3Rpb24oKSB7IHJldHVybiB0ZXh0SGVpZ2h0KHRoaXMuZGlzcGxheSkgfSxcbiAgICAgIGRlZmF1bHRDaGFyV2lkdGg6IGZ1bmN0aW9uKCkgeyByZXR1cm4gY2hhcldpZHRoKHRoaXMuZGlzcGxheSkgfSxcblxuICAgICAgZ2V0Vmlld3BvcnQ6IGZ1bmN0aW9uKCkgeyByZXR1cm4ge2Zyb206IHRoaXMuZGlzcGxheS52aWV3RnJvbSwgdG86IHRoaXMuZGlzcGxheS52aWV3VG99fSxcblxuICAgICAgYWRkV2lkZ2V0OiBmdW5jdGlvbihwb3MsIG5vZGUsIHNjcm9sbCwgdmVydCwgaG9yaXopIHtcbiAgICAgICAgdmFyIGRpc3BsYXkgPSB0aGlzLmRpc3BsYXk7XG4gICAgICAgIHBvcyA9IGN1cnNvckNvb3Jkcyh0aGlzLCBjbGlwUG9zKHRoaXMuZG9jLCBwb3MpKTtcbiAgICAgICAgdmFyIHRvcCA9IHBvcy5ib3R0b20sIGxlZnQgPSBwb3MubGVmdDtcbiAgICAgICAgbm9kZS5zdHlsZS5wb3NpdGlvbiA9IFwiYWJzb2x1dGVcIjtcbiAgICAgICAgbm9kZS5zZXRBdHRyaWJ1dGUoXCJjbS1pZ25vcmUtZXZlbnRzXCIsIFwidHJ1ZVwiKTtcbiAgICAgICAgdGhpcy5kaXNwbGF5LmlucHV0LnNldFVuZWRpdGFibGUobm9kZSk7XG4gICAgICAgIGRpc3BsYXkuc2l6ZXIuYXBwZW5kQ2hpbGQobm9kZSk7XG4gICAgICAgIGlmICh2ZXJ0ID09IFwib3ZlclwiKSB7XG4gICAgICAgICAgdG9wID0gcG9zLnRvcDtcbiAgICAgICAgfSBlbHNlIGlmICh2ZXJ0ID09IFwiYWJvdmVcIiB8fCB2ZXJ0ID09IFwibmVhclwiKSB7XG4gICAgICAgICAgdmFyIHZzcGFjZSA9IE1hdGgubWF4KGRpc3BsYXkud3JhcHBlci5jbGllbnRIZWlnaHQsIHRoaXMuZG9jLmhlaWdodCksXG4gICAgICAgICAgaHNwYWNlID0gTWF0aC5tYXgoZGlzcGxheS5zaXplci5jbGllbnRXaWR0aCwgZGlzcGxheS5saW5lU3BhY2UuY2xpZW50V2lkdGgpO1xuICAgICAgICAgIC8vIERlZmF1bHQgdG8gcG9zaXRpb25pbmcgYWJvdmUgKGlmIHNwZWNpZmllZCBhbmQgcG9zc2libGUpOyBvdGhlcndpc2UgZGVmYXVsdCB0byBwb3NpdGlvbmluZyBiZWxvd1xuICAgICAgICAgIGlmICgodmVydCA9PSAnYWJvdmUnIHx8IHBvcy5ib3R0b20gKyBub2RlLm9mZnNldEhlaWdodCA+IHZzcGFjZSkgJiYgcG9zLnRvcCA+IG5vZGUub2Zmc2V0SGVpZ2h0KVxuICAgICAgICAgICAgeyB0b3AgPSBwb3MudG9wIC0gbm9kZS5vZmZzZXRIZWlnaHQ7IH1cbiAgICAgICAgICBlbHNlIGlmIChwb3MuYm90dG9tICsgbm9kZS5vZmZzZXRIZWlnaHQgPD0gdnNwYWNlKVxuICAgICAgICAgICAgeyB0b3AgPSBwb3MuYm90dG9tOyB9XG4gICAgICAgICAgaWYgKGxlZnQgKyBub2RlLm9mZnNldFdpZHRoID4gaHNwYWNlKVxuICAgICAgICAgICAgeyBsZWZ0ID0gaHNwYWNlIC0gbm9kZS5vZmZzZXRXaWR0aDsgfVxuICAgICAgICB9XG4gICAgICAgIG5vZGUuc3R5bGUudG9wID0gdG9wICsgXCJweFwiO1xuICAgICAgICBub2RlLnN0eWxlLmxlZnQgPSBub2RlLnN0eWxlLnJpZ2h0ID0gXCJcIjtcbiAgICAgICAgaWYgKGhvcml6ID09IFwicmlnaHRcIikge1xuICAgICAgICAgIGxlZnQgPSBkaXNwbGF5LnNpemVyLmNsaWVudFdpZHRoIC0gbm9kZS5vZmZzZXRXaWR0aDtcbiAgICAgICAgICBub2RlLnN0eWxlLnJpZ2h0ID0gXCIwcHhcIjtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBpZiAoaG9yaXogPT0gXCJsZWZ0XCIpIHsgbGVmdCA9IDA7IH1cbiAgICAgICAgICBlbHNlIGlmIChob3JpeiA9PSBcIm1pZGRsZVwiKSB7IGxlZnQgPSAoZGlzcGxheS5zaXplci5jbGllbnRXaWR0aCAtIG5vZGUub2Zmc2V0V2lkdGgpIC8gMjsgfVxuICAgICAgICAgIG5vZGUuc3R5bGUubGVmdCA9IGxlZnQgKyBcInB4XCI7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHNjcm9sbClcbiAgICAgICAgICB7IHNjcm9sbEludG9WaWV3KHRoaXMsIHtsZWZ0OiBsZWZ0LCB0b3A6IHRvcCwgcmlnaHQ6IGxlZnQgKyBub2RlLm9mZnNldFdpZHRoLCBib3R0b206IHRvcCArIG5vZGUub2Zmc2V0SGVpZ2h0fSk7IH1cbiAgICAgIH0sXG5cbiAgICAgIHRyaWdnZXJPbktleURvd246IG1ldGhvZE9wKG9uS2V5RG93biksXG4gICAgICB0cmlnZ2VyT25LZXlQcmVzczogbWV0aG9kT3Aob25LZXlQcmVzcyksXG4gICAgICB0cmlnZ2VyT25LZXlVcDogb25LZXlVcCxcbiAgICAgIHRyaWdnZXJPbk1vdXNlRG93bjogbWV0aG9kT3Aob25Nb3VzZURvd24pLFxuXG4gICAgICBleGVjQ29tbWFuZDogZnVuY3Rpb24oY21kKSB7XG4gICAgICAgIGlmIChjb21tYW5kcy5oYXNPd25Qcm9wZXJ0eShjbWQpKVxuICAgICAgICAgIHsgcmV0dXJuIGNvbW1hbmRzW2NtZF0uY2FsbChudWxsLCB0aGlzKSB9XG4gICAgICB9LFxuXG4gICAgICB0cmlnZ2VyRWxlY3RyaWM6IG1ldGhvZE9wKGZ1bmN0aW9uKHRleHQpIHsgdHJpZ2dlckVsZWN0cmljKHRoaXMsIHRleHQpOyB9KSxcblxuICAgICAgZmluZFBvc0g6IGZ1bmN0aW9uKGZyb20sIGFtb3VudCwgdW5pdCwgdmlzdWFsbHkpIHtcbiAgICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICAgICAgdmFyIGRpciA9IDE7XG4gICAgICAgIGlmIChhbW91bnQgPCAwKSB7IGRpciA9IC0xOyBhbW91bnQgPSAtYW1vdW50OyB9XG4gICAgICAgIHZhciBjdXIgPSBjbGlwUG9zKHRoaXMuZG9jLCBmcm9tKTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhbW91bnQ7ICsraSkge1xuICAgICAgICAgIGN1ciA9IGZpbmRQb3NIKHRoaXMkMS5kb2MsIGN1ciwgZGlyLCB1bml0LCB2aXN1YWxseSk7XG4gICAgICAgICAgaWYgKGN1ci5oaXRTaWRlKSB7IGJyZWFrIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gY3VyXG4gICAgICB9LFxuXG4gICAgICBtb3ZlSDogbWV0aG9kT3AoZnVuY3Rpb24oZGlyLCB1bml0KSB7XG4gICAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgICAgIHRoaXMuZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uIChyYW5nZSQkMSkge1xuICAgICAgICAgIGlmICh0aGlzJDEuZGlzcGxheS5zaGlmdCB8fCB0aGlzJDEuZG9jLmV4dGVuZCB8fCByYW5nZSQkMS5lbXB0eSgpKVxuICAgICAgICAgICAgeyByZXR1cm4gZmluZFBvc0godGhpcyQxLmRvYywgcmFuZ2UkJDEuaGVhZCwgZGlyLCB1bml0LCB0aGlzJDEub3B0aW9ucy5ydGxNb3ZlVmlzdWFsbHkpIH1cbiAgICAgICAgICBlbHNlXG4gICAgICAgICAgICB7IHJldHVybiBkaXIgPCAwID8gcmFuZ2UkJDEuZnJvbSgpIDogcmFuZ2UkJDEudG8oKSB9XG4gICAgICAgIH0sIHNlbF9tb3ZlKTtcbiAgICAgIH0pLFxuXG4gICAgICBkZWxldGVIOiBtZXRob2RPcChmdW5jdGlvbihkaXIsIHVuaXQpIHtcbiAgICAgICAgdmFyIHNlbCA9IHRoaXMuZG9jLnNlbCwgZG9jID0gdGhpcy5kb2M7XG4gICAgICAgIGlmIChzZWwuc29tZXRoaW5nU2VsZWN0ZWQoKSlcbiAgICAgICAgICB7IGRvYy5yZXBsYWNlU2VsZWN0aW9uKFwiXCIsIG51bGwsIFwiK2RlbGV0ZVwiKTsgfVxuICAgICAgICBlbHNlXG4gICAgICAgICAgeyBkZWxldGVOZWFyU2VsZWN0aW9uKHRoaXMsIGZ1bmN0aW9uIChyYW5nZSQkMSkge1xuICAgICAgICAgICAgdmFyIG90aGVyID0gZmluZFBvc0goZG9jLCByYW5nZSQkMS5oZWFkLCBkaXIsIHVuaXQsIGZhbHNlKTtcbiAgICAgICAgICAgIHJldHVybiBkaXIgPCAwID8ge2Zyb206IG90aGVyLCB0bzogcmFuZ2UkJDEuaGVhZH0gOiB7ZnJvbTogcmFuZ2UkJDEuaGVhZCwgdG86IG90aGVyfVxuICAgICAgICAgIH0pOyB9XG4gICAgICB9KSxcblxuICAgICAgZmluZFBvc1Y6IGZ1bmN0aW9uKGZyb20sIGFtb3VudCwgdW5pdCwgZ29hbENvbHVtbikge1xuICAgICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgICAgICB2YXIgZGlyID0gMSwgeCA9IGdvYWxDb2x1bW47XG4gICAgICAgIGlmIChhbW91bnQgPCAwKSB7IGRpciA9IC0xOyBhbW91bnQgPSAtYW1vdW50OyB9XG4gICAgICAgIHZhciBjdXIgPSBjbGlwUG9zKHRoaXMuZG9jLCBmcm9tKTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhbW91bnQ7ICsraSkge1xuICAgICAgICAgIHZhciBjb29yZHMgPSBjdXJzb3JDb29yZHModGhpcyQxLCBjdXIsIFwiZGl2XCIpO1xuICAgICAgICAgIGlmICh4ID09IG51bGwpIHsgeCA9IGNvb3Jkcy5sZWZ0OyB9XG4gICAgICAgICAgZWxzZSB7IGNvb3Jkcy5sZWZ0ID0geDsgfVxuICAgICAgICAgIGN1ciA9IGZpbmRQb3NWKHRoaXMkMSwgY29vcmRzLCBkaXIsIHVuaXQpO1xuICAgICAgICAgIGlmIChjdXIuaGl0U2lkZSkgeyBicmVhayB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGN1clxuICAgICAgfSxcblxuICAgICAgbW92ZVY6IG1ldGhvZE9wKGZ1bmN0aW9uKGRpciwgdW5pdCkge1xuICAgICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgICAgICB2YXIgZG9jID0gdGhpcy5kb2MsIGdvYWxzID0gW107XG4gICAgICAgIHZhciBjb2xsYXBzZSA9ICF0aGlzLmRpc3BsYXkuc2hpZnQgJiYgIWRvYy5leHRlbmQgJiYgZG9jLnNlbC5zb21ldGhpbmdTZWxlY3RlZCgpO1xuICAgICAgICBkb2MuZXh0ZW5kU2VsZWN0aW9uc0J5KGZ1bmN0aW9uIChyYW5nZSQkMSkge1xuICAgICAgICAgIGlmIChjb2xsYXBzZSlcbiAgICAgICAgICAgIHsgcmV0dXJuIGRpciA8IDAgPyByYW5nZSQkMS5mcm9tKCkgOiByYW5nZSQkMS50bygpIH1cbiAgICAgICAgICB2YXIgaGVhZFBvcyA9IGN1cnNvckNvb3Jkcyh0aGlzJDEsIHJhbmdlJCQxLmhlYWQsIFwiZGl2XCIpO1xuICAgICAgICAgIGlmIChyYW5nZSQkMS5nb2FsQ29sdW1uICE9IG51bGwpIHsgaGVhZFBvcy5sZWZ0ID0gcmFuZ2UkJDEuZ29hbENvbHVtbjsgfVxuICAgICAgICAgIGdvYWxzLnB1c2goaGVhZFBvcy5sZWZ0KTtcbiAgICAgICAgICB2YXIgcG9zID0gZmluZFBvc1YodGhpcyQxLCBoZWFkUG9zLCBkaXIsIHVuaXQpO1xuICAgICAgICAgIGlmICh1bml0ID09IFwicGFnZVwiICYmIHJhbmdlJCQxID09IGRvYy5zZWwucHJpbWFyeSgpKVxuICAgICAgICAgICAgeyBhZGRUb1Njcm9sbFRvcCh0aGlzJDEsIGNoYXJDb29yZHModGhpcyQxLCBwb3MsIFwiZGl2XCIpLnRvcCAtIGhlYWRQb3MudG9wKTsgfVxuICAgICAgICAgIHJldHVybiBwb3NcbiAgICAgICAgfSwgc2VsX21vdmUpO1xuICAgICAgICBpZiAoZ29hbHMubGVuZ3RoKSB7IGZvciAodmFyIGkgPSAwOyBpIDwgZG9jLnNlbC5yYW5nZXMubGVuZ3RoOyBpKyspXG4gICAgICAgICAgeyBkb2Muc2VsLnJhbmdlc1tpXS5nb2FsQ29sdW1uID0gZ29hbHNbaV07IH0gfVxuICAgICAgfSksXG5cbiAgICAgIC8vIEZpbmQgdGhlIHdvcmQgYXQgdGhlIGdpdmVuIHBvc2l0aW9uIChhcyByZXR1cm5lZCBieSBjb29yZHNDaGFyKS5cbiAgICAgIGZpbmRXb3JkQXQ6IGZ1bmN0aW9uKHBvcykge1xuICAgICAgICB2YXIgZG9jID0gdGhpcy5kb2MsIGxpbmUgPSBnZXRMaW5lKGRvYywgcG9zLmxpbmUpLnRleHQ7XG4gICAgICAgIHZhciBzdGFydCA9IHBvcy5jaCwgZW5kID0gcG9zLmNoO1xuICAgICAgICBpZiAobGluZSkge1xuICAgICAgICAgIHZhciBoZWxwZXIgPSB0aGlzLmdldEhlbHBlcihwb3MsIFwid29yZENoYXJzXCIpO1xuICAgICAgICAgIGlmICgocG9zLnN0aWNreSA9PSBcImJlZm9yZVwiIHx8IGVuZCA9PSBsaW5lLmxlbmd0aCkgJiYgc3RhcnQpIHsgLS1zdGFydDsgfSBlbHNlIHsgKytlbmQ7IH1cbiAgICAgICAgICB2YXIgc3RhcnRDaGFyID0gbGluZS5jaGFyQXQoc3RhcnQpO1xuICAgICAgICAgIHZhciBjaGVjayA9IGlzV29yZENoYXIoc3RhcnRDaGFyLCBoZWxwZXIpXG4gICAgICAgICAgICA/IGZ1bmN0aW9uIChjaCkgeyByZXR1cm4gaXNXb3JkQ2hhcihjaCwgaGVscGVyKTsgfVxuICAgICAgICAgICAgOiAvXFxzLy50ZXN0KHN0YXJ0Q2hhcikgPyBmdW5jdGlvbiAoY2gpIHsgcmV0dXJuIC9cXHMvLnRlc3QoY2gpOyB9XG4gICAgICAgICAgICA6IGZ1bmN0aW9uIChjaCkgeyByZXR1cm4gKCEvXFxzLy50ZXN0KGNoKSAmJiAhaXNXb3JkQ2hhcihjaCkpOyB9O1xuICAgICAgICAgIHdoaWxlIChzdGFydCA+IDAgJiYgY2hlY2sobGluZS5jaGFyQXQoc3RhcnQgLSAxKSkpIHsgLS1zdGFydDsgfVxuICAgICAgICAgIHdoaWxlIChlbmQgPCBsaW5lLmxlbmd0aCAmJiBjaGVjayhsaW5lLmNoYXJBdChlbmQpKSkgeyArK2VuZDsgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZXcgUmFuZ2UoUG9zKHBvcy5saW5lLCBzdGFydCksIFBvcyhwb3MubGluZSwgZW5kKSlcbiAgICAgIH0sXG5cbiAgICAgIHRvZ2dsZU92ZXJ3cml0ZTogZnVuY3Rpb24odmFsdWUpIHtcbiAgICAgICAgaWYgKHZhbHVlICE9IG51bGwgJiYgdmFsdWUgPT0gdGhpcy5zdGF0ZS5vdmVyd3JpdGUpIHsgcmV0dXJuIH1cbiAgICAgICAgaWYgKHRoaXMuc3RhdGUub3ZlcndyaXRlID0gIXRoaXMuc3RhdGUub3ZlcndyaXRlKVxuICAgICAgICAgIHsgYWRkQ2xhc3ModGhpcy5kaXNwbGF5LmN1cnNvckRpdiwgXCJDb2RlTWlycm9yLW92ZXJ3cml0ZVwiKTsgfVxuICAgICAgICBlbHNlXG4gICAgICAgICAgeyBybUNsYXNzKHRoaXMuZGlzcGxheS5jdXJzb3JEaXYsIFwiQ29kZU1pcnJvci1vdmVyd3JpdGVcIik7IH1cblxuICAgICAgICBzaWduYWwodGhpcywgXCJvdmVyd3JpdGVUb2dnbGVcIiwgdGhpcywgdGhpcy5zdGF0ZS5vdmVyd3JpdGUpO1xuICAgICAgfSxcbiAgICAgIGhhc0ZvY3VzOiBmdW5jdGlvbigpIHsgcmV0dXJuIHRoaXMuZGlzcGxheS5pbnB1dC5nZXRGaWVsZCgpID09IGFjdGl2ZUVsdCgpIH0sXG4gICAgICBpc1JlYWRPbmx5OiBmdW5jdGlvbigpIHsgcmV0dXJuICEhKHRoaXMub3B0aW9ucy5yZWFkT25seSB8fCB0aGlzLmRvYy5jYW50RWRpdCkgfSxcblxuICAgICAgc2Nyb2xsVG86IG1ldGhvZE9wKGZ1bmN0aW9uICh4LCB5KSB7IHNjcm9sbFRvQ29vcmRzKHRoaXMsIHgsIHkpOyB9KSxcbiAgICAgIGdldFNjcm9sbEluZm86IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgc2Nyb2xsZXIgPSB0aGlzLmRpc3BsYXkuc2Nyb2xsZXI7XG4gICAgICAgIHJldHVybiB7bGVmdDogc2Nyb2xsZXIuc2Nyb2xsTGVmdCwgdG9wOiBzY3JvbGxlci5zY3JvbGxUb3AsXG4gICAgICAgICAgICAgICAgaGVpZ2h0OiBzY3JvbGxlci5zY3JvbGxIZWlnaHQgLSBzY3JvbGxHYXAodGhpcykgLSB0aGlzLmRpc3BsYXkuYmFySGVpZ2h0LFxuICAgICAgICAgICAgICAgIHdpZHRoOiBzY3JvbGxlci5zY3JvbGxXaWR0aCAtIHNjcm9sbEdhcCh0aGlzKSAtIHRoaXMuZGlzcGxheS5iYXJXaWR0aCxcbiAgICAgICAgICAgICAgICBjbGllbnRIZWlnaHQ6IGRpc3BsYXlIZWlnaHQodGhpcyksIGNsaWVudFdpZHRoOiBkaXNwbGF5V2lkdGgodGhpcyl9XG4gICAgICB9LFxuXG4gICAgICBzY3JvbGxJbnRvVmlldzogbWV0aG9kT3AoZnVuY3Rpb24ocmFuZ2UkJDEsIG1hcmdpbikge1xuICAgICAgICBpZiAocmFuZ2UkJDEgPT0gbnVsbCkge1xuICAgICAgICAgIHJhbmdlJCQxID0ge2Zyb206IHRoaXMuZG9jLnNlbC5wcmltYXJ5KCkuaGVhZCwgdG86IG51bGx9O1xuICAgICAgICAgIGlmIChtYXJnaW4gPT0gbnVsbCkgeyBtYXJnaW4gPSB0aGlzLm9wdGlvbnMuY3Vyc29yU2Nyb2xsTWFyZ2luOyB9XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHJhbmdlJCQxID09IFwibnVtYmVyXCIpIHtcbiAgICAgICAgICByYW5nZSQkMSA9IHtmcm9tOiBQb3MocmFuZ2UkJDEsIDApLCB0bzogbnVsbH07XG4gICAgICAgIH0gZWxzZSBpZiAocmFuZ2UkJDEuZnJvbSA9PSBudWxsKSB7XG4gICAgICAgICAgcmFuZ2UkJDEgPSB7ZnJvbTogcmFuZ2UkJDEsIHRvOiBudWxsfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXJhbmdlJCQxLnRvKSB7IHJhbmdlJCQxLnRvID0gcmFuZ2UkJDEuZnJvbTsgfVxuICAgICAgICByYW5nZSQkMS5tYXJnaW4gPSBtYXJnaW4gfHwgMDtcblxuICAgICAgICBpZiAocmFuZ2UkJDEuZnJvbS5saW5lICE9IG51bGwpIHtcbiAgICAgICAgICBzY3JvbGxUb1JhbmdlKHRoaXMsIHJhbmdlJCQxKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICBzY3JvbGxUb0Nvb3Jkc1JhbmdlKHRoaXMsIHJhbmdlJCQxLmZyb20sIHJhbmdlJCQxLnRvLCByYW5nZSQkMS5tYXJnaW4pO1xuICAgICAgICB9XG4gICAgICB9KSxcblxuICAgICAgc2V0U2l6ZTogbWV0aG9kT3AoZnVuY3Rpb24od2lkdGgsIGhlaWdodCkge1xuICAgICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgICAgICB2YXIgaW50ZXJwcmV0ID0gZnVuY3Rpb24gKHZhbCkgeyByZXR1cm4gdHlwZW9mIHZhbCA9PSBcIm51bWJlclwiIHx8IC9eXFxkKyQvLnRlc3QoU3RyaW5nKHZhbCkpID8gdmFsICsgXCJweFwiIDogdmFsOyB9O1xuICAgICAgICBpZiAod2lkdGggIT0gbnVsbCkgeyB0aGlzLmRpc3BsYXkud3JhcHBlci5zdHlsZS53aWR0aCA9IGludGVycHJldCh3aWR0aCk7IH1cbiAgICAgICAgaWYgKGhlaWdodCAhPSBudWxsKSB7IHRoaXMuZGlzcGxheS53cmFwcGVyLnN0eWxlLmhlaWdodCA9IGludGVycHJldChoZWlnaHQpOyB9XG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMubGluZVdyYXBwaW5nKSB7IGNsZWFyTGluZU1lYXN1cmVtZW50Q2FjaGUodGhpcyk7IH1cbiAgICAgICAgdmFyIGxpbmVObyQkMSA9IHRoaXMuZGlzcGxheS52aWV3RnJvbTtcbiAgICAgICAgdGhpcy5kb2MuaXRlcihsaW5lTm8kJDEsIHRoaXMuZGlzcGxheS52aWV3VG8sIGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgICAgaWYgKGxpbmUud2lkZ2V0cykgeyBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmUud2lkZ2V0cy5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIHsgaWYgKGxpbmUud2lkZ2V0c1tpXS5ub0hTY3JvbGwpIHsgcmVnTGluZUNoYW5nZSh0aGlzJDEsIGxpbmVObyQkMSwgXCJ3aWRnZXRcIik7IGJyZWFrIH0gfSB9XG4gICAgICAgICAgKytsaW5lTm8kJDE7XG4gICAgICAgIH0pO1xuICAgICAgICB0aGlzLmN1ck9wLmZvcmNlVXBkYXRlID0gdHJ1ZTtcbiAgICAgICAgc2lnbmFsKHRoaXMsIFwicmVmcmVzaFwiLCB0aGlzKTtcbiAgICAgIH0pLFxuXG4gICAgICBvcGVyYXRpb246IGZ1bmN0aW9uKGYpe3JldHVybiBydW5Jbk9wKHRoaXMsIGYpfSxcbiAgICAgIHN0YXJ0T3BlcmF0aW9uOiBmdW5jdGlvbigpe3JldHVybiBzdGFydE9wZXJhdGlvbih0aGlzKX0sXG4gICAgICBlbmRPcGVyYXRpb246IGZ1bmN0aW9uKCl7cmV0dXJuIGVuZE9wZXJhdGlvbih0aGlzKX0sXG5cbiAgICAgIHJlZnJlc2g6IG1ldGhvZE9wKGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgb2xkSGVpZ2h0ID0gdGhpcy5kaXNwbGF5LmNhY2hlZFRleHRIZWlnaHQ7XG4gICAgICAgIHJlZ0NoYW5nZSh0aGlzKTtcbiAgICAgICAgdGhpcy5jdXJPcC5mb3JjZVVwZGF0ZSA9IHRydWU7XG4gICAgICAgIGNsZWFyQ2FjaGVzKHRoaXMpO1xuICAgICAgICBzY3JvbGxUb0Nvb3Jkcyh0aGlzLCB0aGlzLmRvYy5zY3JvbGxMZWZ0LCB0aGlzLmRvYy5zY3JvbGxUb3ApO1xuICAgICAgICB1cGRhdGVHdXR0ZXJTcGFjZSh0aGlzKTtcbiAgICAgICAgaWYgKG9sZEhlaWdodCA9PSBudWxsIHx8IE1hdGguYWJzKG9sZEhlaWdodCAtIHRleHRIZWlnaHQodGhpcy5kaXNwbGF5KSkgPiAuNSlcbiAgICAgICAgICB7IGVzdGltYXRlTGluZUhlaWdodHModGhpcyk7IH1cbiAgICAgICAgc2lnbmFsKHRoaXMsIFwicmVmcmVzaFwiLCB0aGlzKTtcbiAgICAgIH0pLFxuXG4gICAgICBzd2FwRG9jOiBtZXRob2RPcChmdW5jdGlvbihkb2MpIHtcbiAgICAgICAgdmFyIG9sZCA9IHRoaXMuZG9jO1xuICAgICAgICBvbGQuY20gPSBudWxsO1xuICAgICAgICBhdHRhY2hEb2ModGhpcywgZG9jKTtcbiAgICAgICAgY2xlYXJDYWNoZXModGhpcyk7XG4gICAgICAgIHRoaXMuZGlzcGxheS5pbnB1dC5yZXNldCgpO1xuICAgICAgICBzY3JvbGxUb0Nvb3Jkcyh0aGlzLCBkb2Muc2Nyb2xsTGVmdCwgZG9jLnNjcm9sbFRvcCk7XG4gICAgICAgIHRoaXMuY3VyT3AuZm9yY2VTY3JvbGwgPSB0cnVlO1xuICAgICAgICBzaWduYWxMYXRlcih0aGlzLCBcInN3YXBEb2NcIiwgdGhpcywgb2xkKTtcbiAgICAgICAgcmV0dXJuIG9sZFxuICAgICAgfSksXG5cbiAgICAgIHBocmFzZTogZnVuY3Rpb24ocGhyYXNlVGV4dCkge1xuICAgICAgICB2YXIgcGhyYXNlcyA9IHRoaXMub3B0aW9ucy5waHJhc2VzO1xuICAgICAgICByZXR1cm4gcGhyYXNlcyAmJiBPYmplY3QucHJvdG90eXBlLmhhc093blByb3BlcnR5LmNhbGwocGhyYXNlcywgcGhyYXNlVGV4dCkgPyBwaHJhc2VzW3BocmFzZVRleHRdIDogcGhyYXNlVGV4dFxuICAgICAgfSxcblxuICAgICAgZ2V0SW5wdXRGaWVsZDogZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kaXNwbGF5LmlucHV0LmdldEZpZWxkKCl9LFxuICAgICAgZ2V0V3JhcHBlckVsZW1lbnQ6IGZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZGlzcGxheS53cmFwcGVyfSxcbiAgICAgIGdldFNjcm9sbGVyRWxlbWVudDogZnVuY3Rpb24oKXtyZXR1cm4gdGhpcy5kaXNwbGF5LnNjcm9sbGVyfSxcbiAgICAgIGdldEd1dHRlckVsZW1lbnQ6IGZ1bmN0aW9uKCl7cmV0dXJuIHRoaXMuZGlzcGxheS5ndXR0ZXJzfVxuICAgIH07XG4gICAgZXZlbnRNaXhpbihDb2RlTWlycm9yKTtcblxuICAgIENvZGVNaXJyb3IucmVnaXN0ZXJIZWxwZXIgPSBmdW5jdGlvbih0eXBlLCBuYW1lLCB2YWx1ZSkge1xuICAgICAgaWYgKCFoZWxwZXJzLmhhc093blByb3BlcnR5KHR5cGUpKSB7IGhlbHBlcnNbdHlwZV0gPSBDb2RlTWlycm9yW3R5cGVdID0ge19nbG9iYWw6IFtdfTsgfVxuICAgICAgaGVscGVyc1t0eXBlXVtuYW1lXSA9IHZhbHVlO1xuICAgIH07XG4gICAgQ29kZU1pcnJvci5yZWdpc3Rlckdsb2JhbEhlbHBlciA9IGZ1bmN0aW9uKHR5cGUsIG5hbWUsIHByZWRpY2F0ZSwgdmFsdWUpIHtcbiAgICAgIENvZGVNaXJyb3IucmVnaXN0ZXJIZWxwZXIodHlwZSwgbmFtZSwgdmFsdWUpO1xuICAgICAgaGVscGVyc1t0eXBlXS5fZ2xvYmFsLnB1c2goe3ByZWQ6IHByZWRpY2F0ZSwgdmFsOiB2YWx1ZX0pO1xuICAgIH07XG4gIH1cblxuICAvLyBVc2VkIGZvciBob3Jpem9udGFsIHJlbGF0aXZlIG1vdGlvbi4gRGlyIGlzIC0xIG9yIDEgKGxlZnQgb3JcbiAgLy8gcmlnaHQpLCB1bml0IGNhbiBiZSBcImNoYXJcIiwgXCJjb2x1bW5cIiAobGlrZSBjaGFyLCBidXQgZG9lc24ndFxuICAvLyBjcm9zcyBsaW5lIGJvdW5kYXJpZXMpLCBcIndvcmRcIiAoYWNyb3NzIG5leHQgd29yZCksIG9yIFwiZ3JvdXBcIiAodG9cbiAgLy8gdGhlIHN0YXJ0IG9mIG5leHQgZ3JvdXAgb2Ygd29yZCBvciBub24td29yZC1ub24td2hpdGVzcGFjZVxuICAvLyBjaGFycykuIFRoZSB2aXN1YWxseSBwYXJhbSBjb250cm9scyB3aGV0aGVyLCBpbiByaWdodC10by1sZWZ0XG4gIC8vIHRleHQsIGRpcmVjdGlvbiAxIG1lYW5zIHRvIG1vdmUgdG93YXJkcyB0aGUgbmV4dCBpbmRleCBpbiB0aGVcbiAgLy8gc3RyaW5nLCBvciB0b3dhcmRzIHRoZSBjaGFyYWN0ZXIgdG8gdGhlIHJpZ2h0IG9mIHRoZSBjdXJyZW50XG4gIC8vIHBvc2l0aW9uLiBUaGUgcmVzdWx0aW5nIHBvc2l0aW9uIHdpbGwgaGF2ZSBhIGhpdFNpZGU9dHJ1ZVxuICAvLyBwcm9wZXJ0eSBpZiBpdCByZWFjaGVkIHRoZSBlbmQgb2YgdGhlIGRvY3VtZW50LlxuICBmdW5jdGlvbiBmaW5kUG9zSChkb2MsIHBvcywgZGlyLCB1bml0LCB2aXN1YWxseSkge1xuICAgIHZhciBvbGRQb3MgPSBwb3M7XG4gICAgdmFyIG9yaWdEaXIgPSBkaXI7XG4gICAgdmFyIGxpbmVPYmogPSBnZXRMaW5lKGRvYywgcG9zLmxpbmUpO1xuICAgIGZ1bmN0aW9uIGZpbmROZXh0TGluZSgpIHtcbiAgICAgIHZhciBsID0gcG9zLmxpbmUgKyBkaXI7XG4gICAgICBpZiAobCA8IGRvYy5maXJzdCB8fCBsID49IGRvYy5maXJzdCArIGRvYy5zaXplKSB7IHJldHVybiBmYWxzZSB9XG4gICAgICBwb3MgPSBuZXcgUG9zKGwsIHBvcy5jaCwgcG9zLnN0aWNreSk7XG4gICAgICByZXR1cm4gbGluZU9iaiA9IGdldExpbmUoZG9jLCBsKVxuICAgIH1cbiAgICBmdW5jdGlvbiBtb3ZlT25jZShib3VuZFRvTGluZSkge1xuICAgICAgdmFyIG5leHQ7XG4gICAgICBpZiAodmlzdWFsbHkpIHtcbiAgICAgICAgbmV4dCA9IG1vdmVWaXN1YWxseShkb2MuY20sIGxpbmVPYmosIHBvcywgZGlyKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG5leHQgPSBtb3ZlTG9naWNhbGx5KGxpbmVPYmosIHBvcywgZGlyKTtcbiAgICAgIH1cbiAgICAgIGlmIChuZXh0ID09IG51bGwpIHtcbiAgICAgICAgaWYgKCFib3VuZFRvTGluZSAmJiBmaW5kTmV4dExpbmUoKSlcbiAgICAgICAgICB7IHBvcyA9IGVuZE9mTGluZSh2aXN1YWxseSwgZG9jLmNtLCBsaW5lT2JqLCBwb3MubGluZSwgZGlyKTsgfVxuICAgICAgICBlbHNlXG4gICAgICAgICAgeyByZXR1cm4gZmFsc2UgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcG9zID0gbmV4dDtcbiAgICAgIH1cbiAgICAgIHJldHVybiB0cnVlXG4gICAgfVxuXG4gICAgaWYgKHVuaXQgPT0gXCJjaGFyXCIpIHtcbiAgICAgIG1vdmVPbmNlKCk7XG4gICAgfSBlbHNlIGlmICh1bml0ID09IFwiY29sdW1uXCIpIHtcbiAgICAgIG1vdmVPbmNlKHRydWUpO1xuICAgIH0gZWxzZSBpZiAodW5pdCA9PSBcIndvcmRcIiB8fCB1bml0ID09IFwiZ3JvdXBcIikge1xuICAgICAgdmFyIHNhd1R5cGUgPSBudWxsLCBncm91cCA9IHVuaXQgPT0gXCJncm91cFwiO1xuICAgICAgdmFyIGhlbHBlciA9IGRvYy5jbSAmJiBkb2MuY20uZ2V0SGVscGVyKHBvcywgXCJ3b3JkQ2hhcnNcIik7XG4gICAgICBmb3IgKHZhciBmaXJzdCA9IHRydWU7OyBmaXJzdCA9IGZhbHNlKSB7XG4gICAgICAgIGlmIChkaXIgPCAwICYmICFtb3ZlT25jZSghZmlyc3QpKSB7IGJyZWFrIH1cbiAgICAgICAgdmFyIGN1ciA9IGxpbmVPYmoudGV4dC5jaGFyQXQocG9zLmNoKSB8fCBcIlxcblwiO1xuICAgICAgICB2YXIgdHlwZSA9IGlzV29yZENoYXIoY3VyLCBoZWxwZXIpID8gXCJ3XCJcbiAgICAgICAgICA6IGdyb3VwICYmIGN1ciA9PSBcIlxcblwiID8gXCJuXCJcbiAgICAgICAgICA6ICFncm91cCB8fCAvXFxzLy50ZXN0KGN1cikgPyBudWxsXG4gICAgICAgICAgOiBcInBcIjtcbiAgICAgICAgaWYgKGdyb3VwICYmICFmaXJzdCAmJiAhdHlwZSkgeyB0eXBlID0gXCJzXCI7IH1cbiAgICAgICAgaWYgKHNhd1R5cGUgJiYgc2F3VHlwZSAhPSB0eXBlKSB7XG4gICAgICAgICAgaWYgKGRpciA8IDApIHtkaXIgPSAxOyBtb3ZlT25jZSgpOyBwb3Muc3RpY2t5ID0gXCJhZnRlclwiO31cbiAgICAgICAgICBicmVha1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHR5cGUpIHsgc2F3VHlwZSA9IHR5cGU7IH1cbiAgICAgICAgaWYgKGRpciA+IDAgJiYgIW1vdmVPbmNlKCFmaXJzdCkpIHsgYnJlYWsgfVxuICAgICAgfVxuICAgIH1cbiAgICB2YXIgcmVzdWx0ID0gc2tpcEF0b21pYyhkb2MsIHBvcywgb2xkUG9zLCBvcmlnRGlyLCB0cnVlKTtcbiAgICBpZiAoZXF1YWxDdXJzb3JQb3Mob2xkUG9zLCByZXN1bHQpKSB7IHJlc3VsdC5oaXRTaWRlID0gdHJ1ZTsgfVxuICAgIHJldHVybiByZXN1bHRcbiAgfVxuXG4gIC8vIEZvciByZWxhdGl2ZSB2ZXJ0aWNhbCBtb3ZlbWVudC4gRGlyIG1heSBiZSAtMSBvciAxLiBVbml0IGNhbiBiZVxuICAvLyBcInBhZ2VcIiBvciBcImxpbmVcIi4gVGhlIHJlc3VsdGluZyBwb3NpdGlvbiB3aWxsIGhhdmUgYSBoaXRTaWRlPXRydWVcbiAgLy8gcHJvcGVydHkgaWYgaXQgcmVhY2hlZCB0aGUgZW5kIG9mIHRoZSBkb2N1bWVudC5cbiAgZnVuY3Rpb24gZmluZFBvc1YoY20sIHBvcywgZGlyLCB1bml0KSB7XG4gICAgdmFyIGRvYyA9IGNtLmRvYywgeCA9IHBvcy5sZWZ0LCB5O1xuICAgIGlmICh1bml0ID09IFwicGFnZVwiKSB7XG4gICAgICB2YXIgcGFnZVNpemUgPSBNYXRoLm1pbihjbS5kaXNwbGF5LndyYXBwZXIuY2xpZW50SGVpZ2h0LCB3aW5kb3cuaW5uZXJIZWlnaHQgfHwgZG9jdW1lbnQuZG9jdW1lbnRFbGVtZW50LmNsaWVudEhlaWdodCk7XG4gICAgICB2YXIgbW92ZUFtb3VudCA9IE1hdGgubWF4KHBhZ2VTaXplIC0gLjUgKiB0ZXh0SGVpZ2h0KGNtLmRpc3BsYXkpLCAzKTtcbiAgICAgIHkgPSAoZGlyID4gMCA/IHBvcy5ib3R0b20gOiBwb3MudG9wKSArIGRpciAqIG1vdmVBbW91bnQ7XG5cbiAgICB9IGVsc2UgaWYgKHVuaXQgPT0gXCJsaW5lXCIpIHtcbiAgICAgIHkgPSBkaXIgPiAwID8gcG9zLmJvdHRvbSArIDMgOiBwb3MudG9wIC0gMztcbiAgICB9XG4gICAgdmFyIHRhcmdldDtcbiAgICBmb3IgKDs7KSB7XG4gICAgICB0YXJnZXQgPSBjb29yZHNDaGFyKGNtLCB4LCB5KTtcbiAgICAgIGlmICghdGFyZ2V0Lm91dHNpZGUpIHsgYnJlYWsgfVxuICAgICAgaWYgKGRpciA8IDAgPyB5IDw9IDAgOiB5ID49IGRvYy5oZWlnaHQpIHsgdGFyZ2V0LmhpdFNpZGUgPSB0cnVlOyBicmVhayB9XG4gICAgICB5ICs9IGRpciAqIDU7XG4gICAgfVxuICAgIHJldHVybiB0YXJnZXRcbiAgfVxuXG4gIC8vIENPTlRFTlRFRElUQUJMRSBJTlBVVCBTVFlMRVxuXG4gIHZhciBDb250ZW50RWRpdGFibGVJbnB1dCA9IGZ1bmN0aW9uKGNtKSB7XG4gICAgdGhpcy5jbSA9IGNtO1xuICAgIHRoaXMubGFzdEFuY2hvck5vZGUgPSB0aGlzLmxhc3RBbmNob3JPZmZzZXQgPSB0aGlzLmxhc3RGb2N1c05vZGUgPSB0aGlzLmxhc3RGb2N1c09mZnNldCA9IG51bGw7XG4gICAgdGhpcy5wb2xsaW5nID0gbmV3IERlbGF5ZWQoKTtcbiAgICB0aGlzLmNvbXBvc2luZyA9IG51bGw7XG4gICAgdGhpcy5ncmFjZVBlcmlvZCA9IGZhbHNlO1xuICAgIHRoaXMucmVhZERPTVRpbWVvdXQgPSBudWxsO1xuICB9O1xuXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZS5pbml0ID0gZnVuY3Rpb24gKGRpc3BsYXkpIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgdmFyIGlucHV0ID0gdGhpcywgY20gPSBpbnB1dC5jbTtcbiAgICB2YXIgZGl2ID0gaW5wdXQuZGl2ID0gZGlzcGxheS5saW5lRGl2O1xuICAgIGRpc2FibGVCcm93c2VyTWFnaWMoZGl2LCBjbS5vcHRpb25zLnNwZWxsY2hlY2spO1xuXG4gICAgb24oZGl2LCBcInBhc3RlXCIsIGZ1bmN0aW9uIChlKSB7XG4gICAgICBpZiAoc2lnbmFsRE9NRXZlbnQoY20sIGUpIHx8IGhhbmRsZVBhc3RlKGUsIGNtKSkgeyByZXR1cm4gfVxuICAgICAgLy8gSUUgZG9lc24ndCBmaXJlIGlucHV0IGV2ZW50cywgc28gd2Ugc2NoZWR1bGUgYSByZWFkIGZvciB0aGUgcGFzdGVkIGNvbnRlbnQgaW4gdGhpcyB3YXlcbiAgICAgIGlmIChpZV92ZXJzaW9uIDw9IDExKSB7IHNldFRpbWVvdXQob3BlcmF0aW9uKGNtLCBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzJDEudXBkYXRlRnJvbURPTSgpOyB9KSwgMjApOyB9XG4gICAgfSk7XG5cbiAgICBvbihkaXYsIFwiY29tcG9zaXRpb25zdGFydFwiLCBmdW5jdGlvbiAoZSkge1xuICAgICAgdGhpcyQxLmNvbXBvc2luZyA9IHtkYXRhOiBlLmRhdGEsIGRvbmU6IGZhbHNlfTtcbiAgICB9KTtcbiAgICBvbihkaXYsIFwiY29tcG9zaXRpb251cGRhdGVcIiwgZnVuY3Rpb24gKGUpIHtcbiAgICAgIGlmICghdGhpcyQxLmNvbXBvc2luZykgeyB0aGlzJDEuY29tcG9zaW5nID0ge2RhdGE6IGUuZGF0YSwgZG9uZTogZmFsc2V9OyB9XG4gICAgfSk7XG4gICAgb24oZGl2LCBcImNvbXBvc2l0aW9uZW5kXCIsIGZ1bmN0aW9uIChlKSB7XG4gICAgICBpZiAodGhpcyQxLmNvbXBvc2luZykge1xuICAgICAgICBpZiAoZS5kYXRhICE9IHRoaXMkMS5jb21wb3NpbmcuZGF0YSkgeyB0aGlzJDEucmVhZEZyb21ET01Tb29uKCk7IH1cbiAgICAgICAgdGhpcyQxLmNvbXBvc2luZy5kb25lID0gdHJ1ZTtcbiAgICAgIH1cbiAgICB9KTtcblxuICAgIG9uKGRpdiwgXCJ0b3VjaHN0YXJ0XCIsIGZ1bmN0aW9uICgpIHsgcmV0dXJuIGlucHV0LmZvcmNlQ29tcG9zaXRpb25FbmQoKTsgfSk7XG5cbiAgICBvbihkaXYsIFwiaW5wdXRcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgaWYgKCF0aGlzJDEuY29tcG9zaW5nKSB7IHRoaXMkMS5yZWFkRnJvbURPTVNvb24oKTsgfVxuICAgIH0pO1xuXG4gICAgZnVuY3Rpb24gb25Db3B5Q3V0KGUpIHtcbiAgICAgIGlmIChzaWduYWxET01FdmVudChjbSwgZSkpIHsgcmV0dXJuIH1cbiAgICAgIGlmIChjbS5zb21ldGhpbmdTZWxlY3RlZCgpKSB7XG4gICAgICAgIHNldExhc3RDb3BpZWQoe2xpbmVXaXNlOiBmYWxzZSwgdGV4dDogY20uZ2V0U2VsZWN0aW9ucygpfSk7XG4gICAgICAgIGlmIChlLnR5cGUgPT0gXCJjdXRcIikgeyBjbS5yZXBsYWNlU2VsZWN0aW9uKFwiXCIsIG51bGwsIFwiY3V0XCIpOyB9XG4gICAgICB9IGVsc2UgaWYgKCFjbS5vcHRpb25zLmxpbmVXaXNlQ29weUN1dCkge1xuICAgICAgICByZXR1cm5cbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHZhciByYW5nZXMgPSBjb3B5YWJsZVJhbmdlcyhjbSk7XG4gICAgICAgIHNldExhc3RDb3BpZWQoe2xpbmVXaXNlOiB0cnVlLCB0ZXh0OiByYW5nZXMudGV4dH0pO1xuICAgICAgICBpZiAoZS50eXBlID09IFwiY3V0XCIpIHtcbiAgICAgICAgICBjbS5vcGVyYXRpb24oZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgY20uc2V0U2VsZWN0aW9ucyhyYW5nZXMucmFuZ2VzLCAwLCBzZWxfZG9udFNjcm9sbCk7XG4gICAgICAgICAgICBjbS5yZXBsYWNlU2VsZWN0aW9uKFwiXCIsIG51bGwsIFwiY3V0XCIpO1xuICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoZS5jbGlwYm9hcmREYXRhKSB7XG4gICAgICAgIGUuY2xpcGJvYXJkRGF0YS5jbGVhckRhdGEoKTtcbiAgICAgICAgdmFyIGNvbnRlbnQgPSBsYXN0Q29waWVkLnRleHQuam9pbihcIlxcblwiKTtcbiAgICAgICAgLy8gaU9TIGV4cG9zZXMgdGhlIGNsaXBib2FyZCBBUEksIGJ1dCBzZWVtcyB0byBkaXNjYXJkIGNvbnRlbnQgaW5zZXJ0ZWQgaW50byBpdFxuICAgICAgICBlLmNsaXBib2FyZERhdGEuc2V0RGF0YShcIlRleHRcIiwgY29udGVudCk7XG4gICAgICAgIGlmIChlLmNsaXBib2FyZERhdGEuZ2V0RGF0YShcIlRleHRcIikgPT0gY29udGVudCkge1xuICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gT2xkLWZhc2hpb25lZCBicmllZmx5LWZvY3VzLWEtdGV4dGFyZWEgaGFja1xuICAgICAgdmFyIGtsdWRnZSA9IGhpZGRlblRleHRhcmVhKCksIHRlID0ga2x1ZGdlLmZpcnN0Q2hpbGQ7XG4gICAgICBjbS5kaXNwbGF5LmxpbmVTcGFjZS5pbnNlcnRCZWZvcmUoa2x1ZGdlLCBjbS5kaXNwbGF5LmxpbmVTcGFjZS5maXJzdENoaWxkKTtcbiAgICAgIHRlLnZhbHVlID0gbGFzdENvcGllZC50ZXh0LmpvaW4oXCJcXG5cIik7XG4gICAgICB2YXIgaGFkRm9jdXMgPSBkb2N1bWVudC5hY3RpdmVFbGVtZW50O1xuICAgICAgc2VsZWN0SW5wdXQodGUpO1xuICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNtLmRpc3BsYXkubGluZVNwYWNlLnJlbW92ZUNoaWxkKGtsdWRnZSk7XG4gICAgICAgIGhhZEZvY3VzLmZvY3VzKCk7XG4gICAgICAgIGlmIChoYWRGb2N1cyA9PSBkaXYpIHsgaW5wdXQuc2hvd1ByaW1hcnlTZWxlY3Rpb24oKTsgfVxuICAgICAgfSwgNTApO1xuICAgIH1cbiAgICBvbihkaXYsIFwiY29weVwiLCBvbkNvcHlDdXQpO1xuICAgIG9uKGRpdiwgXCJjdXRcIiwgb25Db3B5Q3V0KTtcbiAgfTtcblxuICBDb250ZW50RWRpdGFibGVJbnB1dC5wcm90b3R5cGUucHJlcGFyZVNlbGVjdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgcmVzdWx0ID0gcHJlcGFyZVNlbGVjdGlvbih0aGlzLmNtLCBmYWxzZSk7XG4gICAgcmVzdWx0LmZvY3VzID0gdGhpcy5jbS5zdGF0ZS5mb2N1c2VkO1xuICAgIHJldHVybiByZXN1bHRcbiAgfTtcblxuICBDb250ZW50RWRpdGFibGVJbnB1dC5wcm90b3R5cGUuc2hvd1NlbGVjdGlvbiA9IGZ1bmN0aW9uIChpbmZvLCB0YWtlRm9jdXMpIHtcbiAgICBpZiAoIWluZm8gfHwgIXRoaXMuY20uZGlzcGxheS52aWV3Lmxlbmd0aCkgeyByZXR1cm4gfVxuICAgIGlmIChpbmZvLmZvY3VzIHx8IHRha2VGb2N1cykgeyB0aGlzLnNob3dQcmltYXJ5U2VsZWN0aW9uKCk7IH1cbiAgICB0aGlzLnNob3dNdWx0aXBsZVNlbGVjdGlvbnMoaW5mbyk7XG4gIH07XG5cbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLmdldFNlbGVjdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gdGhpcy5jbS5kaXNwbGF5LndyYXBwZXIub3duZXJEb2N1bWVudC5nZXRTZWxlY3Rpb24oKVxuICB9O1xuXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZS5zaG93UHJpbWFyeVNlbGVjdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2VsID0gdGhpcy5nZXRTZWxlY3Rpb24oKSwgY20gPSB0aGlzLmNtLCBwcmltID0gY20uZG9jLnNlbC5wcmltYXJ5KCk7XG4gICAgdmFyIGZyb20gPSBwcmltLmZyb20oKSwgdG8gPSBwcmltLnRvKCk7XG5cbiAgICBpZiAoY20uZGlzcGxheS52aWV3VG8gPT0gY20uZGlzcGxheS52aWV3RnJvbSB8fCBmcm9tLmxpbmUgPj0gY20uZGlzcGxheS52aWV3VG8gfHwgdG8ubGluZSA8IGNtLmRpc3BsYXkudmlld0Zyb20pIHtcbiAgICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHZhciBjdXJBbmNob3IgPSBkb21Ub1BvcyhjbSwgc2VsLmFuY2hvck5vZGUsIHNlbC5hbmNob3JPZmZzZXQpO1xuICAgIHZhciBjdXJGb2N1cyA9IGRvbVRvUG9zKGNtLCBzZWwuZm9jdXNOb2RlLCBzZWwuZm9jdXNPZmZzZXQpO1xuICAgIGlmIChjdXJBbmNob3IgJiYgIWN1ckFuY2hvci5iYWQgJiYgY3VyRm9jdXMgJiYgIWN1ckZvY3VzLmJhZCAmJlxuICAgICAgICBjbXAobWluUG9zKGN1ckFuY2hvciwgY3VyRm9jdXMpLCBmcm9tKSA9PSAwICYmXG4gICAgICAgIGNtcChtYXhQb3MoY3VyQW5jaG9yLCBjdXJGb2N1cyksIHRvKSA9PSAwKVxuICAgICAgeyByZXR1cm4gfVxuXG4gICAgdmFyIHZpZXcgPSBjbS5kaXNwbGF5LnZpZXc7XG4gICAgdmFyIHN0YXJ0ID0gKGZyb20ubGluZSA+PSBjbS5kaXNwbGF5LnZpZXdGcm9tICYmIHBvc1RvRE9NKGNtLCBmcm9tKSkgfHxcbiAgICAgICAge25vZGU6IHZpZXdbMF0ubWVhc3VyZS5tYXBbMl0sIG9mZnNldDogMH07XG4gICAgdmFyIGVuZCA9IHRvLmxpbmUgPCBjbS5kaXNwbGF5LnZpZXdUbyAmJiBwb3NUb0RPTShjbSwgdG8pO1xuICAgIGlmICghZW5kKSB7XG4gICAgICB2YXIgbWVhc3VyZSA9IHZpZXdbdmlldy5sZW5ndGggLSAxXS5tZWFzdXJlO1xuICAgICAgdmFyIG1hcCQkMSA9IG1lYXN1cmUubWFwcyA/IG1lYXN1cmUubWFwc1ttZWFzdXJlLm1hcHMubGVuZ3RoIC0gMV0gOiBtZWFzdXJlLm1hcDtcbiAgICAgIGVuZCA9IHtub2RlOiBtYXAkJDFbbWFwJCQxLmxlbmd0aCAtIDFdLCBvZmZzZXQ6IG1hcCQkMVttYXAkJDEubGVuZ3RoIC0gMl0gLSBtYXAkJDFbbWFwJCQxLmxlbmd0aCAtIDNdfTtcbiAgICB9XG5cbiAgICBpZiAoIXN0YXJ0IHx8ICFlbmQpIHtcbiAgICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICAgIHJldHVyblxuICAgIH1cblxuICAgIHZhciBvbGQgPSBzZWwucmFuZ2VDb3VudCAmJiBzZWwuZ2V0UmFuZ2VBdCgwKSwgcm5nO1xuICAgIHRyeSB7IHJuZyA9IHJhbmdlKHN0YXJ0Lm5vZGUsIHN0YXJ0Lm9mZnNldCwgZW5kLm9mZnNldCwgZW5kLm5vZGUpOyB9XG4gICAgY2F0Y2goZSkge30gLy8gT3VyIG1vZGVsIG9mIHRoZSBET00gbWlnaHQgYmUgb3V0ZGF0ZWQsIGluIHdoaWNoIGNhc2UgdGhlIHJhbmdlIHdlIHRyeSB0byBzZXQgY2FuIGJlIGltcG9zc2libGVcbiAgICBpZiAocm5nKSB7XG4gICAgICBpZiAoIWdlY2tvICYmIGNtLnN0YXRlLmZvY3VzZWQpIHtcbiAgICAgICAgc2VsLmNvbGxhcHNlKHN0YXJ0Lm5vZGUsIHN0YXJ0Lm9mZnNldCk7XG4gICAgICAgIGlmICghcm5nLmNvbGxhcHNlZCkge1xuICAgICAgICAgIHNlbC5yZW1vdmVBbGxSYW5nZXMoKTtcbiAgICAgICAgICBzZWwuYWRkUmFuZ2Uocm5nKTtcbiAgICAgICAgfVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc2VsLnJlbW92ZUFsbFJhbmdlcygpO1xuICAgICAgICBzZWwuYWRkUmFuZ2Uocm5nKTtcbiAgICAgIH1cbiAgICAgIGlmIChvbGQgJiYgc2VsLmFuY2hvck5vZGUgPT0gbnVsbCkgeyBzZWwuYWRkUmFuZ2Uob2xkKTsgfVxuICAgICAgZWxzZSBpZiAoZ2Vja28pIHsgdGhpcy5zdGFydEdyYWNlUGVyaW9kKCk7IH1cbiAgICB9XG4gICAgdGhpcy5yZW1lbWJlclNlbGVjdGlvbigpO1xuICB9O1xuXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZS5zdGFydEdyYWNlUGVyaW9kID0gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICBjbGVhclRpbWVvdXQodGhpcy5ncmFjZVBlcmlvZCk7XG4gICAgdGhpcy5ncmFjZVBlcmlvZCA9IHNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgdGhpcyQxLmdyYWNlUGVyaW9kID0gZmFsc2U7XG4gICAgICBpZiAodGhpcyQxLnNlbGVjdGlvbkNoYW5nZWQoKSlcbiAgICAgICAgeyB0aGlzJDEuY20ub3BlcmF0aW9uKGZ1bmN0aW9uICgpIHsgcmV0dXJuIHRoaXMkMS5jbS5jdXJPcC5zZWxlY3Rpb25DaGFuZ2VkID0gdHJ1ZTsgfSk7IH1cbiAgICB9LCAyMCk7XG4gIH07XG5cbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLnNob3dNdWx0aXBsZVNlbGVjdGlvbnMgPSBmdW5jdGlvbiAoaW5mbykge1xuICAgIHJlbW92ZUNoaWxkcmVuQW5kQWRkKHRoaXMuY20uZGlzcGxheS5jdXJzb3JEaXYsIGluZm8uY3Vyc29ycyk7XG4gICAgcmVtb3ZlQ2hpbGRyZW5BbmRBZGQodGhpcy5jbS5kaXNwbGF5LnNlbGVjdGlvbkRpdiwgaW5mby5zZWxlY3Rpb24pO1xuICB9O1xuXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZS5yZW1lbWJlclNlbGVjdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgc2VsID0gdGhpcy5nZXRTZWxlY3Rpb24oKTtcbiAgICB0aGlzLmxhc3RBbmNob3JOb2RlID0gc2VsLmFuY2hvck5vZGU7IHRoaXMubGFzdEFuY2hvck9mZnNldCA9IHNlbC5hbmNob3JPZmZzZXQ7XG4gICAgdGhpcy5sYXN0Rm9jdXNOb2RlID0gc2VsLmZvY3VzTm9kZTsgdGhpcy5sYXN0Rm9jdXNPZmZzZXQgPSBzZWwuZm9jdXNPZmZzZXQ7XG4gIH07XG5cbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLnNlbGVjdGlvbkluRWRpdG9yID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBzZWwgPSB0aGlzLmdldFNlbGVjdGlvbigpO1xuICAgIGlmICghc2VsLnJhbmdlQ291bnQpIHsgcmV0dXJuIGZhbHNlIH1cbiAgICB2YXIgbm9kZSA9IHNlbC5nZXRSYW5nZUF0KDApLmNvbW1vbkFuY2VzdG9yQ29udGFpbmVyO1xuICAgIHJldHVybiBjb250YWlucyh0aGlzLmRpdiwgbm9kZSlcbiAgfTtcblxuICBDb250ZW50RWRpdGFibGVJbnB1dC5wcm90b3R5cGUuZm9jdXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuY20ub3B0aW9ucy5yZWFkT25seSAhPSBcIm5vY3Vyc29yXCIpIHtcbiAgICAgIGlmICghdGhpcy5zZWxlY3Rpb25JbkVkaXRvcigpKVxuICAgICAgICB7IHRoaXMuc2hvd1NlbGVjdGlvbih0aGlzLnByZXBhcmVTZWxlY3Rpb24oKSwgdHJ1ZSk7IH1cbiAgICAgIHRoaXMuZGl2LmZvY3VzKCk7XG4gICAgfVxuICB9O1xuICBDb250ZW50RWRpdGFibGVJbnB1dC5wcm90b3R5cGUuYmx1ciA9IGZ1bmN0aW9uICgpIHsgdGhpcy5kaXYuYmx1cigpOyB9O1xuICBDb250ZW50RWRpdGFibGVJbnB1dC5wcm90b3R5cGUuZ2V0RmllbGQgPSBmdW5jdGlvbiAoKSB7IHJldHVybiB0aGlzLmRpdiB9O1xuXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZS5zdXBwb3J0c1RvdWNoID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gdHJ1ZSB9O1xuXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZS5yZWNlaXZlZEZvY3VzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBpbnB1dCA9IHRoaXM7XG4gICAgaWYgKHRoaXMuc2VsZWN0aW9uSW5FZGl0b3IoKSlcbiAgICAgIHsgdGhpcy5wb2xsU2VsZWN0aW9uKCk7IH1cbiAgICBlbHNlXG4gICAgICB7IHJ1bkluT3AodGhpcy5jbSwgZnVuY3Rpb24gKCkgeyByZXR1cm4gaW5wdXQuY20uY3VyT3Auc2VsZWN0aW9uQ2hhbmdlZCA9IHRydWU7IH0pOyB9XG5cbiAgICBmdW5jdGlvbiBwb2xsKCkge1xuICAgICAgaWYgKGlucHV0LmNtLnN0YXRlLmZvY3VzZWQpIHtcbiAgICAgICAgaW5wdXQucG9sbFNlbGVjdGlvbigpO1xuICAgICAgICBpbnB1dC5wb2xsaW5nLnNldChpbnB1dC5jbS5vcHRpb25zLnBvbGxJbnRlcnZhbCwgcG9sbCk7XG4gICAgICB9XG4gICAgfVxuICAgIHRoaXMucG9sbGluZy5zZXQodGhpcy5jbS5vcHRpb25zLnBvbGxJbnRlcnZhbCwgcG9sbCk7XG4gIH07XG5cbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLnNlbGVjdGlvbkNoYW5nZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHNlbCA9IHRoaXMuZ2V0U2VsZWN0aW9uKCk7XG4gICAgcmV0dXJuIHNlbC5hbmNob3JOb2RlICE9IHRoaXMubGFzdEFuY2hvck5vZGUgfHwgc2VsLmFuY2hvck9mZnNldCAhPSB0aGlzLmxhc3RBbmNob3JPZmZzZXQgfHxcbiAgICAgIHNlbC5mb2N1c05vZGUgIT0gdGhpcy5sYXN0Rm9jdXNOb2RlIHx8IHNlbC5mb2N1c09mZnNldCAhPSB0aGlzLmxhc3RGb2N1c09mZnNldFxuICB9O1xuXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZS5wb2xsU2VsZWN0aW9uID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLnJlYWRET01UaW1lb3V0ICE9IG51bGwgfHwgdGhpcy5ncmFjZVBlcmlvZCB8fCAhdGhpcy5zZWxlY3Rpb25DaGFuZ2VkKCkpIHsgcmV0dXJuIH1cbiAgICB2YXIgc2VsID0gdGhpcy5nZXRTZWxlY3Rpb24oKSwgY20gPSB0aGlzLmNtO1xuICAgIC8vIE9uIEFuZHJvaWQgQ2hyb21lICh2ZXJzaW9uIDU2LCBhdCBsZWFzdCksIGJhY2tzcGFjaW5nIGludG8gYW5cbiAgICAvLyB1bmVkaXRhYmxlIGJsb2NrIGVsZW1lbnQgd2lsbCBwdXQgdGhlIGN1cnNvciBpbiB0aGF0IGVsZW1lbnQsXG4gICAgLy8gYW5kIHRoZW4sIGJlY2F1c2UgaXQncyBub3QgZWRpdGFibGUsIGhpZGUgdGhlIHZpcnR1YWwga2V5Ym9hcmQuXG4gICAgLy8gQmVjYXVzZSBBbmRyb2lkIGRvZXNuJ3QgYWxsb3cgdXMgdG8gYWN0dWFsbHkgZGV0ZWN0IGJhY2tzcGFjZVxuICAgIC8vIHByZXNzZXMgaW4gYSBzYW5lIHdheSwgdGhpcyBjb2RlIGNoZWNrcyBmb3Igd2hlbiB0aGF0IGhhcHBlbnNcbiAgICAvLyBhbmQgc2ltdWxhdGVzIGEgYmFja3NwYWNlIHByZXNzIGluIHRoaXMgY2FzZS5cbiAgICBpZiAoYW5kcm9pZCAmJiBjaHJvbWUgJiYgdGhpcy5jbS5vcHRpb25zLmd1dHRlcnMubGVuZ3RoICYmIGlzSW5HdXR0ZXIoc2VsLmFuY2hvck5vZGUpKSB7XG4gICAgICB0aGlzLmNtLnRyaWdnZXJPbktleURvd24oe3R5cGU6IFwia2V5ZG93blwiLCBrZXlDb2RlOiA4LCBwcmV2ZW50RGVmYXVsdDogTWF0aC5hYnN9KTtcbiAgICAgIHRoaXMuYmx1cigpO1xuICAgICAgdGhpcy5mb2N1cygpO1xuICAgICAgcmV0dXJuXG4gICAgfVxuICAgIGlmICh0aGlzLmNvbXBvc2luZykgeyByZXR1cm4gfVxuICAgIHRoaXMucmVtZW1iZXJTZWxlY3Rpb24oKTtcbiAgICB2YXIgYW5jaG9yID0gZG9tVG9Qb3MoY20sIHNlbC5hbmNob3JOb2RlLCBzZWwuYW5jaG9yT2Zmc2V0KTtcbiAgICB2YXIgaGVhZCA9IGRvbVRvUG9zKGNtLCBzZWwuZm9jdXNOb2RlLCBzZWwuZm9jdXNPZmZzZXQpO1xuICAgIGlmIChhbmNob3IgJiYgaGVhZCkgeyBydW5Jbk9wKGNtLCBmdW5jdGlvbiAoKSB7XG4gICAgICBzZXRTZWxlY3Rpb24oY20uZG9jLCBzaW1wbGVTZWxlY3Rpb24oYW5jaG9yLCBoZWFkKSwgc2VsX2RvbnRTY3JvbGwpO1xuICAgICAgaWYgKGFuY2hvci5iYWQgfHwgaGVhZC5iYWQpIHsgY20uY3VyT3Auc2VsZWN0aW9uQ2hhbmdlZCA9IHRydWU7IH1cbiAgICB9KTsgfVxuICB9O1xuXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZS5wb2xsQ29udGVudCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5yZWFkRE9NVGltZW91dCAhPSBudWxsKSB7XG4gICAgICBjbGVhclRpbWVvdXQodGhpcy5yZWFkRE9NVGltZW91dCk7XG4gICAgICB0aGlzLnJlYWRET01UaW1lb3V0ID0gbnVsbDtcbiAgICB9XG5cbiAgICB2YXIgY20gPSB0aGlzLmNtLCBkaXNwbGF5ID0gY20uZGlzcGxheSwgc2VsID0gY20uZG9jLnNlbC5wcmltYXJ5KCk7XG4gICAgdmFyIGZyb20gPSBzZWwuZnJvbSgpLCB0byA9IHNlbC50bygpO1xuICAgIGlmIChmcm9tLmNoID09IDAgJiYgZnJvbS5saW5lID4gY20uZmlyc3RMaW5lKCkpXG4gICAgICB7IGZyb20gPSBQb3MoZnJvbS5saW5lIC0gMSwgZ2V0TGluZShjbS5kb2MsIGZyb20ubGluZSAtIDEpLmxlbmd0aCk7IH1cbiAgICBpZiAodG8uY2ggPT0gZ2V0TGluZShjbS5kb2MsIHRvLmxpbmUpLnRleHQubGVuZ3RoICYmIHRvLmxpbmUgPCBjbS5sYXN0TGluZSgpKVxuICAgICAgeyB0byA9IFBvcyh0by5saW5lICsgMSwgMCk7IH1cbiAgICBpZiAoZnJvbS5saW5lIDwgZGlzcGxheS52aWV3RnJvbSB8fCB0by5saW5lID4gZGlzcGxheS52aWV3VG8gLSAxKSB7IHJldHVybiBmYWxzZSB9XG5cbiAgICB2YXIgZnJvbUluZGV4LCBmcm9tTGluZSwgZnJvbU5vZGU7XG4gICAgaWYgKGZyb20ubGluZSA9PSBkaXNwbGF5LnZpZXdGcm9tIHx8IChmcm9tSW5kZXggPSBmaW5kVmlld0luZGV4KGNtLCBmcm9tLmxpbmUpKSA9PSAwKSB7XG4gICAgICBmcm9tTGluZSA9IGxpbmVObyhkaXNwbGF5LnZpZXdbMF0ubGluZSk7XG4gICAgICBmcm9tTm9kZSA9IGRpc3BsYXkudmlld1swXS5ub2RlO1xuICAgIH0gZWxzZSB7XG4gICAgICBmcm9tTGluZSA9IGxpbmVObyhkaXNwbGF5LnZpZXdbZnJvbUluZGV4XS5saW5lKTtcbiAgICAgIGZyb21Ob2RlID0gZGlzcGxheS52aWV3W2Zyb21JbmRleCAtIDFdLm5vZGUubmV4dFNpYmxpbmc7XG4gICAgfVxuICAgIHZhciB0b0luZGV4ID0gZmluZFZpZXdJbmRleChjbSwgdG8ubGluZSk7XG4gICAgdmFyIHRvTGluZSwgdG9Ob2RlO1xuICAgIGlmICh0b0luZGV4ID09IGRpc3BsYXkudmlldy5sZW5ndGggLSAxKSB7XG4gICAgICB0b0xpbmUgPSBkaXNwbGF5LnZpZXdUbyAtIDE7XG4gICAgICB0b05vZGUgPSBkaXNwbGF5LmxpbmVEaXYubGFzdENoaWxkO1xuICAgIH0gZWxzZSB7XG4gICAgICB0b0xpbmUgPSBsaW5lTm8oZGlzcGxheS52aWV3W3RvSW5kZXggKyAxXS5saW5lKSAtIDE7XG4gICAgICB0b05vZGUgPSBkaXNwbGF5LnZpZXdbdG9JbmRleCArIDFdLm5vZGUucHJldmlvdXNTaWJsaW5nO1xuICAgIH1cblxuICAgIGlmICghZnJvbU5vZGUpIHsgcmV0dXJuIGZhbHNlIH1cbiAgICB2YXIgbmV3VGV4dCA9IGNtLmRvYy5zcGxpdExpbmVzKGRvbVRleHRCZXR3ZWVuKGNtLCBmcm9tTm9kZSwgdG9Ob2RlLCBmcm9tTGluZSwgdG9MaW5lKSk7XG4gICAgdmFyIG9sZFRleHQgPSBnZXRCZXR3ZWVuKGNtLmRvYywgUG9zKGZyb21MaW5lLCAwKSwgUG9zKHRvTGluZSwgZ2V0TGluZShjbS5kb2MsIHRvTGluZSkudGV4dC5sZW5ndGgpKTtcbiAgICB3aGlsZSAobmV3VGV4dC5sZW5ndGggPiAxICYmIG9sZFRleHQubGVuZ3RoID4gMSkge1xuICAgICAgaWYgKGxzdChuZXdUZXh0KSA9PSBsc3Qob2xkVGV4dCkpIHsgbmV3VGV4dC5wb3AoKTsgb2xkVGV4dC5wb3AoKTsgdG9MaW5lLS07IH1cbiAgICAgIGVsc2UgaWYgKG5ld1RleHRbMF0gPT0gb2xkVGV4dFswXSkgeyBuZXdUZXh0LnNoaWZ0KCk7IG9sZFRleHQuc2hpZnQoKTsgZnJvbUxpbmUrKzsgfVxuICAgICAgZWxzZSB7IGJyZWFrIH1cbiAgICB9XG5cbiAgICB2YXIgY3V0RnJvbnQgPSAwLCBjdXRFbmQgPSAwO1xuICAgIHZhciBuZXdUb3AgPSBuZXdUZXh0WzBdLCBvbGRUb3AgPSBvbGRUZXh0WzBdLCBtYXhDdXRGcm9udCA9IE1hdGgubWluKG5ld1RvcC5sZW5ndGgsIG9sZFRvcC5sZW5ndGgpO1xuICAgIHdoaWxlIChjdXRGcm9udCA8IG1heEN1dEZyb250ICYmIG5ld1RvcC5jaGFyQ29kZUF0KGN1dEZyb250KSA9PSBvbGRUb3AuY2hhckNvZGVBdChjdXRGcm9udCkpXG4gICAgICB7ICsrY3V0RnJvbnQ7IH1cbiAgICB2YXIgbmV3Qm90ID0gbHN0KG5ld1RleHQpLCBvbGRCb3QgPSBsc3Qob2xkVGV4dCk7XG4gICAgdmFyIG1heEN1dEVuZCA9IE1hdGgubWluKG5ld0JvdC5sZW5ndGggLSAobmV3VGV4dC5sZW5ndGggPT0gMSA/IGN1dEZyb250IDogMCksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZEJvdC5sZW5ndGggLSAob2xkVGV4dC5sZW5ndGggPT0gMSA/IGN1dEZyb250IDogMCkpO1xuICAgIHdoaWxlIChjdXRFbmQgPCBtYXhDdXRFbmQgJiZcbiAgICAgICAgICAgbmV3Qm90LmNoYXJDb2RlQXQobmV3Qm90Lmxlbmd0aCAtIGN1dEVuZCAtIDEpID09IG9sZEJvdC5jaGFyQ29kZUF0KG9sZEJvdC5sZW5ndGggLSBjdXRFbmQgLSAxKSlcbiAgICAgIHsgKytjdXRFbmQ7IH1cbiAgICAvLyBUcnkgdG8gbW92ZSBzdGFydCBvZiBjaGFuZ2UgdG8gc3RhcnQgb2Ygc2VsZWN0aW9uIGlmIGFtYmlndW91c1xuICAgIGlmIChuZXdUZXh0Lmxlbmd0aCA9PSAxICYmIG9sZFRleHQubGVuZ3RoID09IDEgJiYgZnJvbUxpbmUgPT0gZnJvbS5saW5lKSB7XG4gICAgICB3aGlsZSAoY3V0RnJvbnQgJiYgY3V0RnJvbnQgPiBmcm9tLmNoICYmXG4gICAgICAgICAgICAgbmV3Qm90LmNoYXJDb2RlQXQobmV3Qm90Lmxlbmd0aCAtIGN1dEVuZCAtIDEpID09IG9sZEJvdC5jaGFyQ29kZUF0KG9sZEJvdC5sZW5ndGggLSBjdXRFbmQgLSAxKSkge1xuICAgICAgICBjdXRGcm9udC0tO1xuICAgICAgICBjdXRFbmQrKztcbiAgICAgIH1cbiAgICB9XG5cbiAgICBuZXdUZXh0W25ld1RleHQubGVuZ3RoIC0gMV0gPSBuZXdCb3Quc2xpY2UoMCwgbmV3Qm90Lmxlbmd0aCAtIGN1dEVuZCkucmVwbGFjZSgvXlxcdTIwMGIrLywgXCJcIik7XG4gICAgbmV3VGV4dFswXSA9IG5ld1RleHRbMF0uc2xpY2UoY3V0RnJvbnQpLnJlcGxhY2UoL1xcdTIwMGIrJC8sIFwiXCIpO1xuXG4gICAgdmFyIGNoRnJvbSA9IFBvcyhmcm9tTGluZSwgY3V0RnJvbnQpO1xuICAgIHZhciBjaFRvID0gUG9zKHRvTGluZSwgb2xkVGV4dC5sZW5ndGggPyBsc3Qob2xkVGV4dCkubGVuZ3RoIC0gY3V0RW5kIDogMCk7XG4gICAgaWYgKG5ld1RleHQubGVuZ3RoID4gMSB8fCBuZXdUZXh0WzBdIHx8IGNtcChjaEZyb20sIGNoVG8pKSB7XG4gICAgICByZXBsYWNlUmFuZ2UoY20uZG9jLCBuZXdUZXh0LCBjaEZyb20sIGNoVG8sIFwiK2lucHV0XCIpO1xuICAgICAgcmV0dXJuIHRydWVcbiAgICB9XG4gIH07XG5cbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLmVuc3VyZVBvbGxlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLmZvcmNlQ29tcG9zaXRpb25FbmQoKTtcbiAgfTtcbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLnJlc2V0ID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZm9yY2VDb21wb3NpdGlvbkVuZCgpO1xuICB9O1xuICBDb250ZW50RWRpdGFibGVJbnB1dC5wcm90b3R5cGUuZm9yY2VDb21wb3NpdGlvbkVuZCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMuY29tcG9zaW5nKSB7IHJldHVybiB9XG4gICAgY2xlYXJUaW1lb3V0KHRoaXMucmVhZERPTVRpbWVvdXQpO1xuICAgIHRoaXMuY29tcG9zaW5nID0gbnVsbDtcbiAgICB0aGlzLnVwZGF0ZUZyb21ET00oKTtcbiAgICB0aGlzLmRpdi5ibHVyKCk7XG4gICAgdGhpcy5kaXYuZm9jdXMoKTtcbiAgfTtcbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLnJlYWRGcm9tRE9NU29vbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgaWYgKHRoaXMucmVhZERPTVRpbWVvdXQgIT0gbnVsbCkgeyByZXR1cm4gfVxuICAgIHRoaXMucmVhZERPTVRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgIHRoaXMkMS5yZWFkRE9NVGltZW91dCA9IG51bGw7XG4gICAgICBpZiAodGhpcyQxLmNvbXBvc2luZykge1xuICAgICAgICBpZiAodGhpcyQxLmNvbXBvc2luZy5kb25lKSB7IHRoaXMkMS5jb21wb3NpbmcgPSBudWxsOyB9XG4gICAgICAgIGVsc2UgeyByZXR1cm4gfVxuICAgICAgfVxuICAgICAgdGhpcyQxLnVwZGF0ZUZyb21ET00oKTtcbiAgICB9LCA4MCk7XG4gIH07XG5cbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLnVwZGF0ZUZyb21ET00gPSBmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgIGlmICh0aGlzLmNtLmlzUmVhZE9ubHkoKSB8fCAhdGhpcy5wb2xsQ29udGVudCgpKVxuICAgICAgeyBydW5Jbk9wKHRoaXMuY20sIGZ1bmN0aW9uICgpIHsgcmV0dXJuIHJlZ0NoYW5nZSh0aGlzJDEuY20pOyB9KTsgfVxuICB9O1xuXG4gIENvbnRlbnRFZGl0YWJsZUlucHV0LnByb3RvdHlwZS5zZXRVbmVkaXRhYmxlID0gZnVuY3Rpb24gKG5vZGUpIHtcbiAgICBub2RlLmNvbnRlbnRFZGl0YWJsZSA9IFwiZmFsc2VcIjtcbiAgfTtcblxuICBDb250ZW50RWRpdGFibGVJbnB1dC5wcm90b3R5cGUub25LZXlQcmVzcyA9IGZ1bmN0aW9uIChlKSB7XG4gICAgaWYgKGUuY2hhckNvZGUgPT0gMCB8fCB0aGlzLmNvbXBvc2luZykgeyByZXR1cm4gfVxuICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICBpZiAoIXRoaXMuY20uaXNSZWFkT25seSgpKVxuICAgICAgeyBvcGVyYXRpb24odGhpcy5jbSwgYXBwbHlUZXh0SW5wdXQpKHRoaXMuY20sIFN0cmluZy5mcm9tQ2hhckNvZGUoZS5jaGFyQ29kZSA9PSBudWxsID8gZS5rZXlDb2RlIDogZS5jaGFyQ29kZSksIDApOyB9XG4gIH07XG5cbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLnJlYWRPbmx5Q2hhbmdlZCA9IGZ1bmN0aW9uICh2YWwpIHtcbiAgICB0aGlzLmRpdi5jb250ZW50RWRpdGFibGUgPSBTdHJpbmcodmFsICE9IFwibm9jdXJzb3JcIik7XG4gIH07XG5cbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLm9uQ29udGV4dE1lbnUgPSBmdW5jdGlvbiAoKSB7fTtcbiAgQ29udGVudEVkaXRhYmxlSW5wdXQucHJvdG90eXBlLnJlc2V0UG9zaXRpb24gPSBmdW5jdGlvbiAoKSB7fTtcblxuICBDb250ZW50RWRpdGFibGVJbnB1dC5wcm90b3R5cGUubmVlZHNDb250ZW50QXR0cmlidXRlID0gdHJ1ZTtcblxuICBmdW5jdGlvbiBwb3NUb0RPTShjbSwgcG9zKSB7XG4gICAgdmFyIHZpZXcgPSBmaW5kVmlld0ZvckxpbmUoY20sIHBvcy5saW5lKTtcbiAgICBpZiAoIXZpZXcgfHwgdmlldy5oaWRkZW4pIHsgcmV0dXJuIG51bGwgfVxuICAgIHZhciBsaW5lID0gZ2V0TGluZShjbS5kb2MsIHBvcy5saW5lKTtcbiAgICB2YXIgaW5mbyA9IG1hcEZyb21MaW5lVmlldyh2aWV3LCBsaW5lLCBwb3MubGluZSk7XG5cbiAgICB2YXIgb3JkZXIgPSBnZXRPcmRlcihsaW5lLCBjbS5kb2MuZGlyZWN0aW9uKSwgc2lkZSA9IFwibGVmdFwiO1xuICAgIGlmIChvcmRlcikge1xuICAgICAgdmFyIHBhcnRQb3MgPSBnZXRCaWRpUGFydEF0KG9yZGVyLCBwb3MuY2gpO1xuICAgICAgc2lkZSA9IHBhcnRQb3MgJSAyID8gXCJyaWdodFwiIDogXCJsZWZ0XCI7XG4gICAgfVxuICAgIHZhciByZXN1bHQgPSBub2RlQW5kT2Zmc2V0SW5MaW5lTWFwKGluZm8ubWFwLCBwb3MuY2gsIHNpZGUpO1xuICAgIHJlc3VsdC5vZmZzZXQgPSByZXN1bHQuY29sbGFwc2UgPT0gXCJyaWdodFwiID8gcmVzdWx0LmVuZCA6IHJlc3VsdC5zdGFydDtcbiAgICByZXR1cm4gcmVzdWx0XG4gIH1cblxuICBmdW5jdGlvbiBpc0luR3V0dGVyKG5vZGUpIHtcbiAgICBmb3IgKHZhciBzY2FuID0gbm9kZTsgc2Nhbjsgc2NhbiA9IHNjYW4ucGFyZW50Tm9kZSlcbiAgICAgIHsgaWYgKC9Db2RlTWlycm9yLWd1dHRlci13cmFwcGVyLy50ZXN0KHNjYW4uY2xhc3NOYW1lKSkgeyByZXR1cm4gdHJ1ZSB9IH1cbiAgICByZXR1cm4gZmFsc2VcbiAgfVxuXG4gIGZ1bmN0aW9uIGJhZFBvcyhwb3MsIGJhZCkgeyBpZiAoYmFkKSB7IHBvcy5iYWQgPSB0cnVlOyB9IHJldHVybiBwb3MgfVxuXG4gIGZ1bmN0aW9uIGRvbVRleHRCZXR3ZWVuKGNtLCBmcm9tLCB0bywgZnJvbUxpbmUsIHRvTGluZSkge1xuICAgIHZhciB0ZXh0ID0gXCJcIiwgY2xvc2luZyA9IGZhbHNlLCBsaW5lU2VwID0gY20uZG9jLmxpbmVTZXBhcmF0b3IoKSwgZXh0cmFMaW5lYnJlYWsgPSBmYWxzZTtcbiAgICBmdW5jdGlvbiByZWNvZ25pemVNYXJrZXIoaWQpIHsgcmV0dXJuIGZ1bmN0aW9uIChtYXJrZXIpIHsgcmV0dXJuIG1hcmtlci5pZCA9PSBpZDsgfSB9XG4gICAgZnVuY3Rpb24gY2xvc2UoKSB7XG4gICAgICBpZiAoY2xvc2luZykge1xuICAgICAgICB0ZXh0ICs9IGxpbmVTZXA7XG4gICAgICAgIGlmIChleHRyYUxpbmVicmVhaykgeyB0ZXh0ICs9IGxpbmVTZXA7IH1cbiAgICAgICAgY2xvc2luZyA9IGV4dHJhTGluZWJyZWFrID0gZmFsc2U7XG4gICAgICB9XG4gICAgfVxuICAgIGZ1bmN0aW9uIGFkZFRleHQoc3RyKSB7XG4gICAgICBpZiAoc3RyKSB7XG4gICAgICAgIGNsb3NlKCk7XG4gICAgICAgIHRleHQgKz0gc3RyO1xuICAgICAgfVxuICAgIH1cbiAgICBmdW5jdGlvbiB3YWxrKG5vZGUpIHtcbiAgICAgIGlmIChub2RlLm5vZGVUeXBlID09IDEpIHtcbiAgICAgICAgdmFyIGNtVGV4dCA9IG5vZGUuZ2V0QXR0cmlidXRlKFwiY20tdGV4dFwiKTtcbiAgICAgICAgaWYgKGNtVGV4dCkge1xuICAgICAgICAgIGFkZFRleHQoY21UZXh0KTtcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICB2YXIgbWFya2VySUQgPSBub2RlLmdldEF0dHJpYnV0ZShcImNtLW1hcmtlclwiKSwgcmFuZ2UkJDE7XG4gICAgICAgIGlmIChtYXJrZXJJRCkge1xuICAgICAgICAgIHZhciBmb3VuZCA9IGNtLmZpbmRNYXJrcyhQb3MoZnJvbUxpbmUsIDApLCBQb3ModG9MaW5lICsgMSwgMCksIHJlY29nbml6ZU1hcmtlcigrbWFya2VySUQpKTtcbiAgICAgICAgICBpZiAoZm91bmQubGVuZ3RoICYmIChyYW5nZSQkMSA9IGZvdW5kWzBdLmZpbmQoMCkpKVxuICAgICAgICAgICAgeyBhZGRUZXh0KGdldEJldHdlZW4oY20uZG9jLCByYW5nZSQkMS5mcm9tLCByYW5nZSQkMS50bykuam9pbihsaW5lU2VwKSk7IH1cbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBpZiAobm9kZS5nZXRBdHRyaWJ1dGUoXCJjb250ZW50ZWRpdGFibGVcIikgPT0gXCJmYWxzZVwiKSB7IHJldHVybiB9XG4gICAgICAgIHZhciBpc0Jsb2NrID0gL14ocHJlfGRpdnxwfGxpfHRhYmxlfGJyKSQvaS50ZXN0KG5vZGUubm9kZU5hbWUpO1xuICAgICAgICBpZiAoIS9eYnIkL2kudGVzdChub2RlLm5vZGVOYW1lKSAmJiBub2RlLnRleHRDb250ZW50Lmxlbmd0aCA9PSAwKSB7IHJldHVybiB9XG5cbiAgICAgICAgaWYgKGlzQmxvY2spIHsgY2xvc2UoKTsgfVxuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IG5vZGUuY2hpbGROb2Rlcy5sZW5ndGg7IGkrKylcbiAgICAgICAgICB7IHdhbGsobm9kZS5jaGlsZE5vZGVzW2ldKTsgfVxuXG4gICAgICAgIGlmICgvXihwcmV8cCkkL2kudGVzdChub2RlLm5vZGVOYW1lKSkgeyBleHRyYUxpbmVicmVhayA9IHRydWU7IH1cbiAgICAgICAgaWYgKGlzQmxvY2spIHsgY2xvc2luZyA9IHRydWU7IH1cbiAgICAgIH0gZWxzZSBpZiAobm9kZS5ub2RlVHlwZSA9PSAzKSB7XG4gICAgICAgIGFkZFRleHQobm9kZS5ub2RlVmFsdWUucmVwbGFjZSgvXFx1MjAwYi9nLCBcIlwiKS5yZXBsYWNlKC9cXHUwMGEwL2csIFwiIFwiKSk7XG4gICAgICB9XG4gICAgfVxuICAgIGZvciAoOzspIHtcbiAgICAgIHdhbGsoZnJvbSk7XG4gICAgICBpZiAoZnJvbSA9PSB0bykgeyBicmVhayB9XG4gICAgICBmcm9tID0gZnJvbS5uZXh0U2libGluZztcbiAgICAgIGV4dHJhTGluZWJyZWFrID0gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0ZXh0XG4gIH1cblxuICBmdW5jdGlvbiBkb21Ub1BvcyhjbSwgbm9kZSwgb2Zmc2V0KSB7XG4gICAgdmFyIGxpbmVOb2RlO1xuICAgIGlmIChub2RlID09IGNtLmRpc3BsYXkubGluZURpdikge1xuICAgICAgbGluZU5vZGUgPSBjbS5kaXNwbGF5LmxpbmVEaXYuY2hpbGROb2Rlc1tvZmZzZXRdO1xuICAgICAgaWYgKCFsaW5lTm9kZSkgeyByZXR1cm4gYmFkUG9zKGNtLmNsaXBQb3MoUG9zKGNtLmRpc3BsYXkudmlld1RvIC0gMSkpLCB0cnVlKSB9XG4gICAgICBub2RlID0gbnVsbDsgb2Zmc2V0ID0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgZm9yIChsaW5lTm9kZSA9IG5vZGU7OyBsaW5lTm9kZSA9IGxpbmVOb2RlLnBhcmVudE5vZGUpIHtcbiAgICAgICAgaWYgKCFsaW5lTm9kZSB8fCBsaW5lTm9kZSA9PSBjbS5kaXNwbGF5LmxpbmVEaXYpIHsgcmV0dXJuIG51bGwgfVxuICAgICAgICBpZiAobGluZU5vZGUucGFyZW50Tm9kZSAmJiBsaW5lTm9kZS5wYXJlbnROb2RlID09IGNtLmRpc3BsYXkubGluZURpdikgeyBicmVhayB9XG4gICAgICB9XG4gICAgfVxuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY20uZGlzcGxheS52aWV3Lmxlbmd0aDsgaSsrKSB7XG4gICAgICB2YXIgbGluZVZpZXcgPSBjbS5kaXNwbGF5LnZpZXdbaV07XG4gICAgICBpZiAobGluZVZpZXcubm9kZSA9PSBsaW5lTm9kZSlcbiAgICAgICAgeyByZXR1cm4gbG9jYXRlTm9kZUluTGluZVZpZXcobGluZVZpZXcsIG5vZGUsIG9mZnNldCkgfVxuICAgIH1cbiAgfVxuXG4gIGZ1bmN0aW9uIGxvY2F0ZU5vZGVJbkxpbmVWaWV3KGxpbmVWaWV3LCBub2RlLCBvZmZzZXQpIHtcbiAgICB2YXIgd3JhcHBlciA9IGxpbmVWaWV3LnRleHQuZmlyc3RDaGlsZCwgYmFkID0gZmFsc2U7XG4gICAgaWYgKCFub2RlIHx8ICFjb250YWlucyh3cmFwcGVyLCBub2RlKSkgeyByZXR1cm4gYmFkUG9zKFBvcyhsaW5lTm8obGluZVZpZXcubGluZSksIDApLCB0cnVlKSB9XG4gICAgaWYgKG5vZGUgPT0gd3JhcHBlcikge1xuICAgICAgYmFkID0gdHJ1ZTtcbiAgICAgIG5vZGUgPSB3cmFwcGVyLmNoaWxkTm9kZXNbb2Zmc2V0XTtcbiAgICAgIG9mZnNldCA9IDA7XG4gICAgICBpZiAoIW5vZGUpIHtcbiAgICAgICAgdmFyIGxpbmUgPSBsaW5lVmlldy5yZXN0ID8gbHN0KGxpbmVWaWV3LnJlc3QpIDogbGluZVZpZXcubGluZTtcbiAgICAgICAgcmV0dXJuIGJhZFBvcyhQb3MobGluZU5vKGxpbmUpLCBsaW5lLnRleHQubGVuZ3RoKSwgYmFkKVxuICAgICAgfVxuICAgIH1cblxuICAgIHZhciB0ZXh0Tm9kZSA9IG5vZGUubm9kZVR5cGUgPT0gMyA/IG5vZGUgOiBudWxsLCB0b3BOb2RlID0gbm9kZTtcbiAgICBpZiAoIXRleHROb2RlICYmIG5vZGUuY2hpbGROb2Rlcy5sZW5ndGggPT0gMSAmJiBub2RlLmZpcnN0Q2hpbGQubm9kZVR5cGUgPT0gMykge1xuICAgICAgdGV4dE5vZGUgPSBub2RlLmZpcnN0Q2hpbGQ7XG4gICAgICBpZiAob2Zmc2V0KSB7IG9mZnNldCA9IHRleHROb2RlLm5vZGVWYWx1ZS5sZW5ndGg7IH1cbiAgICB9XG4gICAgd2hpbGUgKHRvcE5vZGUucGFyZW50Tm9kZSAhPSB3cmFwcGVyKSB7IHRvcE5vZGUgPSB0b3BOb2RlLnBhcmVudE5vZGU7IH1cbiAgICB2YXIgbWVhc3VyZSA9IGxpbmVWaWV3Lm1lYXN1cmUsIG1hcHMgPSBtZWFzdXJlLm1hcHM7XG5cbiAgICBmdW5jdGlvbiBmaW5kKHRleHROb2RlLCB0b3BOb2RlLCBvZmZzZXQpIHtcbiAgICAgIGZvciAodmFyIGkgPSAtMTsgaSA8IChtYXBzID8gbWFwcy5sZW5ndGggOiAwKTsgaSsrKSB7XG4gICAgICAgIHZhciBtYXAkJDEgPSBpIDwgMCA/IG1lYXN1cmUubWFwIDogbWFwc1tpXTtcbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBtYXAkJDEubGVuZ3RoOyBqICs9IDMpIHtcbiAgICAgICAgICB2YXIgY3VyTm9kZSA9IG1hcCQkMVtqICsgMl07XG4gICAgICAgICAgaWYgKGN1ck5vZGUgPT0gdGV4dE5vZGUgfHwgY3VyTm9kZSA9PSB0b3BOb2RlKSB7XG4gICAgICAgICAgICB2YXIgbGluZSA9IGxpbmVObyhpIDwgMCA/IGxpbmVWaWV3LmxpbmUgOiBsaW5lVmlldy5yZXN0W2ldKTtcbiAgICAgICAgICAgIHZhciBjaCA9IG1hcCQkMVtqXSArIG9mZnNldDtcbiAgICAgICAgICAgIGlmIChvZmZzZXQgPCAwIHx8IGN1ck5vZGUgIT0gdGV4dE5vZGUpIHsgY2ggPSBtYXAkJDFbaiArIChvZmZzZXQgPyAxIDogMCldOyB9XG4gICAgICAgICAgICByZXR1cm4gUG9zKGxpbmUsIGNoKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cbiAgICB2YXIgZm91bmQgPSBmaW5kKHRleHROb2RlLCB0b3BOb2RlLCBvZmZzZXQpO1xuICAgIGlmIChmb3VuZCkgeyByZXR1cm4gYmFkUG9zKGZvdW5kLCBiYWQpIH1cblxuICAgIC8vIEZJWE1FIHRoaXMgaXMgYWxsIHJlYWxseSBzaGFreS4gbWlnaHQgaGFuZGxlIHRoZSBmZXcgY2FzZXMgaXQgbmVlZHMgdG8gaGFuZGxlLCBidXQgbGlrZWx5IHRvIGNhdXNlIHByb2JsZW1zXG4gICAgZm9yICh2YXIgYWZ0ZXIgPSB0b3BOb2RlLm5leHRTaWJsaW5nLCBkaXN0ID0gdGV4dE5vZGUgPyB0ZXh0Tm9kZS5ub2RlVmFsdWUubGVuZ3RoIC0gb2Zmc2V0IDogMDsgYWZ0ZXI7IGFmdGVyID0gYWZ0ZXIubmV4dFNpYmxpbmcpIHtcbiAgICAgIGZvdW5kID0gZmluZChhZnRlciwgYWZ0ZXIuZmlyc3RDaGlsZCwgMCk7XG4gICAgICBpZiAoZm91bmQpXG4gICAgICAgIHsgcmV0dXJuIGJhZFBvcyhQb3MoZm91bmQubGluZSwgZm91bmQuY2ggLSBkaXN0KSwgYmFkKSB9XG4gICAgICBlbHNlXG4gICAgICAgIHsgZGlzdCArPSBhZnRlci50ZXh0Q29udGVudC5sZW5ndGg7IH1cbiAgICB9XG4gICAgZm9yICh2YXIgYmVmb3JlID0gdG9wTm9kZS5wcmV2aW91c1NpYmxpbmcsIGRpc3QkMSA9IG9mZnNldDsgYmVmb3JlOyBiZWZvcmUgPSBiZWZvcmUucHJldmlvdXNTaWJsaW5nKSB7XG4gICAgICBmb3VuZCA9IGZpbmQoYmVmb3JlLCBiZWZvcmUuZmlyc3RDaGlsZCwgLTEpO1xuICAgICAgaWYgKGZvdW5kKVxuICAgICAgICB7IHJldHVybiBiYWRQb3MoUG9zKGZvdW5kLmxpbmUsIGZvdW5kLmNoICsgZGlzdCQxKSwgYmFkKSB9XG4gICAgICBlbHNlXG4gICAgICAgIHsgZGlzdCQxICs9IGJlZm9yZS50ZXh0Q29udGVudC5sZW5ndGg7IH1cbiAgICB9XG4gIH1cblxuICAvLyBURVhUQVJFQSBJTlBVVCBTVFlMRVxuXG4gIHZhciBUZXh0YXJlYUlucHV0ID0gZnVuY3Rpb24oY20pIHtcbiAgICB0aGlzLmNtID0gY207XG4gICAgLy8gU2VlIGlucHV0LnBvbGwgYW5kIGlucHV0LnJlc2V0XG4gICAgdGhpcy5wcmV2SW5wdXQgPSBcIlwiO1xuXG4gICAgLy8gRmxhZyB0aGF0IGluZGljYXRlcyB3aGV0aGVyIHdlIGV4cGVjdCBpbnB1dCB0byBhcHBlYXIgcmVhbCBzb29uXG4gICAgLy8gbm93IChhZnRlciBzb21lIGV2ZW50IGxpa2UgJ2tleXByZXNzJyBvciAnaW5wdXQnKSBhbmQgYXJlXG4gICAgLy8gcG9sbGluZyBpbnRlbnNpdmVseS5cbiAgICB0aGlzLnBvbGxpbmdGYXN0ID0gZmFsc2U7XG4gICAgLy8gU2VsZi1yZXNldHRpbmcgdGltZW91dCBmb3IgdGhlIHBvbGxlclxuICAgIHRoaXMucG9sbGluZyA9IG5ldyBEZWxheWVkKCk7XG4gICAgLy8gVXNlZCB0byB3b3JrIGFyb3VuZCBJRSBpc3N1ZSB3aXRoIHNlbGVjdGlvbiBiZWluZyBmb3Jnb3R0ZW4gd2hlbiBmb2N1cyBtb3ZlcyBhd2F5IGZyb20gdGV4dGFyZWFcbiAgICB0aGlzLmhhc1NlbGVjdGlvbiA9IGZhbHNlO1xuICAgIHRoaXMuY29tcG9zaW5nID0gbnVsbDtcbiAgfTtcblxuICBUZXh0YXJlYUlucHV0LnByb3RvdHlwZS5pbml0ID0gZnVuY3Rpb24gKGRpc3BsYXkpIHtcbiAgICAgIHZhciB0aGlzJDEgPSB0aGlzO1xuXG4gICAgdmFyIGlucHV0ID0gdGhpcywgY20gPSB0aGlzLmNtO1xuICAgIHRoaXMuY3JlYXRlRmllbGQoZGlzcGxheSk7XG4gICAgdmFyIHRlID0gdGhpcy50ZXh0YXJlYTtcblxuICAgIGRpc3BsYXkud3JhcHBlci5pbnNlcnRCZWZvcmUodGhpcy53cmFwcGVyLCBkaXNwbGF5LndyYXBwZXIuZmlyc3RDaGlsZCk7XG5cbiAgICAvLyBOZWVkZWQgdG8gaGlkZSBiaWcgYmx1ZSBibGlua2luZyBjdXJzb3Igb24gTW9iaWxlIFNhZmFyaSAoZG9lc24ndCBzZWVtIHRvIHdvcmsgaW4gaU9TIDggYW55bW9yZSlcbiAgICBpZiAoaW9zKSB7IHRlLnN0eWxlLndpZHRoID0gXCIwcHhcIjsgfVxuXG4gICAgb24odGUsIFwiaW5wdXRcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgaWYgKGllICYmIGllX3ZlcnNpb24gPj0gOSAmJiB0aGlzJDEuaGFzU2VsZWN0aW9uKSB7IHRoaXMkMS5oYXNTZWxlY3Rpb24gPSBudWxsOyB9XG4gICAgICBpbnB1dC5wb2xsKCk7XG4gICAgfSk7XG5cbiAgICBvbih0ZSwgXCJwYXN0ZVwiLCBmdW5jdGlvbiAoZSkge1xuICAgICAgaWYgKHNpZ25hbERPTUV2ZW50KGNtLCBlKSB8fCBoYW5kbGVQYXN0ZShlLCBjbSkpIHsgcmV0dXJuIH1cblxuICAgICAgY20uc3RhdGUucGFzdGVJbmNvbWluZyA9IHRydWU7XG4gICAgICBpbnB1dC5mYXN0UG9sbCgpO1xuICAgIH0pO1xuXG4gICAgZnVuY3Rpb24gcHJlcGFyZUNvcHlDdXQoZSkge1xuICAgICAgaWYgKHNpZ25hbERPTUV2ZW50KGNtLCBlKSkgeyByZXR1cm4gfVxuICAgICAgaWYgKGNtLnNvbWV0aGluZ1NlbGVjdGVkKCkpIHtcbiAgICAgICAgc2V0TGFzdENvcGllZCh7bGluZVdpc2U6IGZhbHNlLCB0ZXh0OiBjbS5nZXRTZWxlY3Rpb25zKCl9KTtcbiAgICAgIH0gZWxzZSBpZiAoIWNtLm9wdGlvbnMubGluZVdpc2VDb3B5Q3V0KSB7XG4gICAgICAgIHJldHVyblxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdmFyIHJhbmdlcyA9IGNvcHlhYmxlUmFuZ2VzKGNtKTtcbiAgICAgICAgc2V0TGFzdENvcGllZCh7bGluZVdpc2U6IHRydWUsIHRleHQ6IHJhbmdlcy50ZXh0fSk7XG4gICAgICAgIGlmIChlLnR5cGUgPT0gXCJjdXRcIikge1xuICAgICAgICAgIGNtLnNldFNlbGVjdGlvbnMocmFuZ2VzLnJhbmdlcywgbnVsbCwgc2VsX2RvbnRTY3JvbGwpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGlucHV0LnByZXZJbnB1dCA9IFwiXCI7XG4gICAgICAgICAgdGUudmFsdWUgPSByYW5nZXMudGV4dC5qb2luKFwiXFxuXCIpO1xuICAgICAgICAgIHNlbGVjdElucHV0KHRlKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGUudHlwZSA9PSBcImN1dFwiKSB7IGNtLnN0YXRlLmN1dEluY29taW5nID0gdHJ1ZTsgfVxuICAgIH1cbiAgICBvbih0ZSwgXCJjdXRcIiwgcHJlcGFyZUNvcHlDdXQpO1xuICAgIG9uKHRlLCBcImNvcHlcIiwgcHJlcGFyZUNvcHlDdXQpO1xuXG4gICAgb24oZGlzcGxheS5zY3JvbGxlciwgXCJwYXN0ZVwiLCBmdW5jdGlvbiAoZSkge1xuICAgICAgaWYgKGV2ZW50SW5XaWRnZXQoZGlzcGxheSwgZSkgfHwgc2lnbmFsRE9NRXZlbnQoY20sIGUpKSB7IHJldHVybiB9XG4gICAgICBjbS5zdGF0ZS5wYXN0ZUluY29taW5nID0gdHJ1ZTtcbiAgICAgIGlucHV0LmZvY3VzKCk7XG4gICAgfSk7XG5cbiAgICAvLyBQcmV2ZW50IG5vcm1hbCBzZWxlY3Rpb24gaW4gdGhlIGVkaXRvciAod2UgaGFuZGxlIG91ciBvd24pXG4gICAgb24oZGlzcGxheS5saW5lU3BhY2UsIFwic2VsZWN0c3RhcnRcIiwgZnVuY3Rpb24gKGUpIHtcbiAgICAgIGlmICghZXZlbnRJbldpZGdldChkaXNwbGF5LCBlKSkgeyBlX3ByZXZlbnREZWZhdWx0KGUpOyB9XG4gICAgfSk7XG5cbiAgICBvbih0ZSwgXCJjb21wb3NpdGlvbnN0YXJ0XCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgIHZhciBzdGFydCA9IGNtLmdldEN1cnNvcihcImZyb21cIik7XG4gICAgICBpZiAoaW5wdXQuY29tcG9zaW5nKSB7IGlucHV0LmNvbXBvc2luZy5yYW5nZS5jbGVhcigpOyB9XG4gICAgICBpbnB1dC5jb21wb3NpbmcgPSB7XG4gICAgICAgIHN0YXJ0OiBzdGFydCxcbiAgICAgICAgcmFuZ2U6IGNtLm1hcmtUZXh0KHN0YXJ0LCBjbS5nZXRDdXJzb3IoXCJ0b1wiKSwge2NsYXNzTmFtZTogXCJDb2RlTWlycm9yLWNvbXBvc2luZ1wifSlcbiAgICAgIH07XG4gICAgfSk7XG4gICAgb24odGUsIFwiY29tcG9zaXRpb25lbmRcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgaWYgKGlucHV0LmNvbXBvc2luZykge1xuICAgICAgICBpbnB1dC5wb2xsKCk7XG4gICAgICAgIGlucHV0LmNvbXBvc2luZy5yYW5nZS5jbGVhcigpO1xuICAgICAgICBpbnB1dC5jb21wb3NpbmcgPSBudWxsO1xuICAgICAgfVxuICAgIH0pO1xuICB9O1xuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLmNyZWF0ZUZpZWxkID0gZnVuY3Rpb24gKF9kaXNwbGF5KSB7XG4gICAgLy8gV3JhcHMgYW5kIGhpZGVzIGlucHV0IHRleHRhcmVhXG4gICAgdGhpcy53cmFwcGVyID0gaGlkZGVuVGV4dGFyZWEoKTtcbiAgICAvLyBUaGUgc2VtaWhpZGRlbiB0ZXh0YXJlYSB0aGF0IGlzIGZvY3VzZWQgd2hlbiB0aGUgZWRpdG9yIGlzXG4gICAgLy8gZm9jdXNlZCwgYW5kIHJlY2VpdmVzIGlucHV0LlxuICAgIHRoaXMudGV4dGFyZWEgPSB0aGlzLndyYXBwZXIuZmlyc3RDaGlsZDtcbiAgfTtcblxuICBUZXh0YXJlYUlucHV0LnByb3RvdHlwZS5wcmVwYXJlU2VsZWN0aW9uID0gZnVuY3Rpb24gKCkge1xuICAgIC8vIFJlZHJhdyB0aGUgc2VsZWN0aW9uIGFuZC9vciBjdXJzb3JcbiAgICB2YXIgY20gPSB0aGlzLmNtLCBkaXNwbGF5ID0gY20uZGlzcGxheSwgZG9jID0gY20uZG9jO1xuICAgIHZhciByZXN1bHQgPSBwcmVwYXJlU2VsZWN0aW9uKGNtKTtcblxuICAgIC8vIE1vdmUgdGhlIGhpZGRlbiB0ZXh0YXJlYSBuZWFyIHRoZSBjdXJzb3IgdG8gcHJldmVudCBzY3JvbGxpbmcgYXJ0aWZhY3RzXG4gICAgaWYgKGNtLm9wdGlvbnMubW92ZUlucHV0V2l0aEN1cnNvcikge1xuICAgICAgdmFyIGhlYWRQb3MgPSBjdXJzb3JDb29yZHMoY20sIGRvYy5zZWwucHJpbWFyeSgpLmhlYWQsIFwiZGl2XCIpO1xuICAgICAgdmFyIHdyYXBPZmYgPSBkaXNwbGF5LndyYXBwZXIuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCksIGxpbmVPZmYgPSBkaXNwbGF5LmxpbmVEaXYuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgICByZXN1bHQudGVUb3AgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihkaXNwbGF5LndyYXBwZXIuY2xpZW50SGVpZ2h0IC0gMTAsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkUG9zLnRvcCArIGxpbmVPZmYudG9wIC0gd3JhcE9mZi50b3ApKTtcbiAgICAgIHJlc3VsdC50ZUxlZnQgPSBNYXRoLm1heCgwLCBNYXRoLm1pbihkaXNwbGF5LndyYXBwZXIuY2xpZW50V2lkdGggLSAxMCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBoZWFkUG9zLmxlZnQgKyBsaW5lT2ZmLmxlZnQgLSB3cmFwT2ZmLmxlZnQpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0XG4gIH07XG5cbiAgVGV4dGFyZWFJbnB1dC5wcm90b3R5cGUuc2hvd1NlbGVjdGlvbiA9IGZ1bmN0aW9uIChkcmF3bikge1xuICAgIHZhciBjbSA9IHRoaXMuY20sIGRpc3BsYXkgPSBjbS5kaXNwbGF5O1xuICAgIHJlbW92ZUNoaWxkcmVuQW5kQWRkKGRpc3BsYXkuY3Vyc29yRGl2LCBkcmF3bi5jdXJzb3JzKTtcbiAgICByZW1vdmVDaGlsZHJlbkFuZEFkZChkaXNwbGF5LnNlbGVjdGlvbkRpdiwgZHJhd24uc2VsZWN0aW9uKTtcbiAgICBpZiAoZHJhd24udGVUb3AgIT0gbnVsbCkge1xuICAgICAgdGhpcy53cmFwcGVyLnN0eWxlLnRvcCA9IGRyYXduLnRlVG9wICsgXCJweFwiO1xuICAgICAgdGhpcy53cmFwcGVyLnN0eWxlLmxlZnQgPSBkcmF3bi50ZUxlZnQgKyBcInB4XCI7XG4gICAgfVxuICB9O1xuXG4gIC8vIFJlc2V0IHRoZSBpbnB1dCB0byBjb3JyZXNwb25kIHRvIHRoZSBzZWxlY3Rpb24gKG9yIHRvIGJlIGVtcHR5LFxuICAvLyB3aGVuIG5vdCB0eXBpbmcgYW5kIG5vdGhpbmcgaXMgc2VsZWN0ZWQpXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLnJlc2V0ID0gZnVuY3Rpb24gKHR5cGluZykge1xuICAgIGlmICh0aGlzLmNvbnRleHRNZW51UGVuZGluZyB8fCB0aGlzLmNvbXBvc2luZykgeyByZXR1cm4gfVxuICAgIHZhciBjbSA9IHRoaXMuY207XG4gICAgaWYgKGNtLnNvbWV0aGluZ1NlbGVjdGVkKCkpIHtcbiAgICAgIHRoaXMucHJldklucHV0ID0gXCJcIjtcbiAgICAgIHZhciBjb250ZW50ID0gY20uZ2V0U2VsZWN0aW9uKCk7XG4gICAgICB0aGlzLnRleHRhcmVhLnZhbHVlID0gY29udGVudDtcbiAgICAgIGlmIChjbS5zdGF0ZS5mb2N1c2VkKSB7IHNlbGVjdElucHV0KHRoaXMudGV4dGFyZWEpOyB9XG4gICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA+PSA5KSB7IHRoaXMuaGFzU2VsZWN0aW9uID0gY29udGVudDsgfVxuICAgIH0gZWxzZSBpZiAoIXR5cGluZykge1xuICAgICAgdGhpcy5wcmV2SW5wdXQgPSB0aGlzLnRleHRhcmVhLnZhbHVlID0gXCJcIjtcbiAgICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uID49IDkpIHsgdGhpcy5oYXNTZWxlY3Rpb24gPSBudWxsOyB9XG4gICAgfVxuICB9O1xuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLmdldEZpZWxkID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy50ZXh0YXJlYSB9O1xuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLnN1cHBvcnRzVG91Y2ggPSBmdW5jdGlvbiAoKSB7IHJldHVybiBmYWxzZSB9O1xuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLmZvY3VzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmICh0aGlzLmNtLm9wdGlvbnMucmVhZE9ubHkgIT0gXCJub2N1cnNvclwiICYmICghbW9iaWxlIHx8IGFjdGl2ZUVsdCgpICE9IHRoaXMudGV4dGFyZWEpKSB7XG4gICAgICB0cnkgeyB0aGlzLnRleHRhcmVhLmZvY3VzKCk7IH1cbiAgICAgIGNhdGNoIChlKSB7fSAvLyBJRTggd2lsbCB0aHJvdyBpZiB0aGUgdGV4dGFyZWEgaXMgZGlzcGxheTogbm9uZSBvciBub3QgaW4gRE9NXG4gICAgfVxuICB9O1xuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLmJsdXIgPSBmdW5jdGlvbiAoKSB7IHRoaXMudGV4dGFyZWEuYmx1cigpOyB9O1xuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLnJlc2V0UG9zaXRpb24gPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy53cmFwcGVyLnN0eWxlLnRvcCA9IHRoaXMud3JhcHBlci5zdHlsZS5sZWZ0ID0gMDtcbiAgfTtcblxuICBUZXh0YXJlYUlucHV0LnByb3RvdHlwZS5yZWNlaXZlZEZvY3VzID0gZnVuY3Rpb24gKCkgeyB0aGlzLnNsb3dQb2xsKCk7IH07XG5cbiAgLy8gUG9sbCBmb3IgaW5wdXQgY2hhbmdlcywgdXNpbmcgdGhlIG5vcm1hbCByYXRlIG9mIHBvbGxpbmcuIFRoaXNcbiAgLy8gcnVucyBhcyBsb25nIGFzIHRoZSBlZGl0b3IgaXMgZm9jdXNlZC5cbiAgVGV4dGFyZWFJbnB1dC5wcm90b3R5cGUuc2xvd1BvbGwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICB2YXIgdGhpcyQxID0gdGhpcztcblxuICAgIGlmICh0aGlzLnBvbGxpbmdGYXN0KSB7IHJldHVybiB9XG4gICAgdGhpcy5wb2xsaW5nLnNldCh0aGlzLmNtLm9wdGlvbnMucG9sbEludGVydmFsLCBmdW5jdGlvbiAoKSB7XG4gICAgICB0aGlzJDEucG9sbCgpO1xuICAgICAgaWYgKHRoaXMkMS5jbS5zdGF0ZS5mb2N1c2VkKSB7IHRoaXMkMS5zbG93UG9sbCgpOyB9XG4gICAgfSk7XG4gIH07XG5cbiAgLy8gV2hlbiBhbiBldmVudCBoYXMganVzdCBjb21lIGluIHRoYXQgaXMgbGlrZWx5IHRvIGFkZCBvciBjaGFuZ2VcbiAgLy8gc29tZXRoaW5nIGluIHRoZSBpbnB1dCB0ZXh0YXJlYSwgd2UgcG9sbCBmYXN0ZXIsIHRvIGVuc3VyZSB0aGF0XG4gIC8vIHRoZSBjaGFuZ2UgYXBwZWFycyBvbiB0aGUgc2NyZWVuIHF1aWNrbHkuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLmZhc3RQb2xsID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBtaXNzZWQgPSBmYWxzZSwgaW5wdXQgPSB0aGlzO1xuICAgIGlucHV0LnBvbGxpbmdGYXN0ID0gdHJ1ZTtcbiAgICBmdW5jdGlvbiBwKCkge1xuICAgICAgdmFyIGNoYW5nZWQgPSBpbnB1dC5wb2xsKCk7XG4gICAgICBpZiAoIWNoYW5nZWQgJiYgIW1pc3NlZCkge21pc3NlZCA9IHRydWU7IGlucHV0LnBvbGxpbmcuc2V0KDYwLCBwKTt9XG4gICAgICBlbHNlIHtpbnB1dC5wb2xsaW5nRmFzdCA9IGZhbHNlOyBpbnB1dC5zbG93UG9sbCgpO31cbiAgICB9XG4gICAgaW5wdXQucG9sbGluZy5zZXQoMjAsIHApO1xuICB9O1xuXG4gIC8vIFJlYWQgaW5wdXQgZnJvbSB0aGUgdGV4dGFyZWEsIGFuZCB1cGRhdGUgdGhlIGRvY3VtZW50IHRvIG1hdGNoLlxuICAvLyBXaGVuIHNvbWV0aGluZyBpcyBzZWxlY3RlZCwgaXQgaXMgcHJlc2VudCBpbiB0aGUgdGV4dGFyZWEsIGFuZFxuICAvLyBzZWxlY3RlZCAodW5sZXNzIGl0IGlzIGh1Z2UsIGluIHdoaWNoIGNhc2UgYSBwbGFjZWhvbGRlciBpc1xuICAvLyB1c2VkKS4gV2hlbiBub3RoaW5nIGlzIHNlbGVjdGVkLCB0aGUgY3Vyc29yIHNpdHMgYWZ0ZXIgcHJldmlvdXNseVxuICAvLyBzZWVuIHRleHQgKGNhbiBiZSBlbXB0eSksIHdoaWNoIGlzIHN0b3JlZCBpbiBwcmV2SW5wdXQgKHdlIG11c3RcbiAgLy8gbm90IHJlc2V0IHRoZSB0ZXh0YXJlYSB3aGVuIHR5cGluZywgYmVjYXVzZSB0aGF0IGJyZWFrcyBJTUUpLlxuICBUZXh0YXJlYUlucHV0LnByb3RvdHlwZS5wb2xsID0gZnVuY3Rpb24gKCkge1xuICAgICAgdmFyIHRoaXMkMSA9IHRoaXM7XG5cbiAgICB2YXIgY20gPSB0aGlzLmNtLCBpbnB1dCA9IHRoaXMudGV4dGFyZWEsIHByZXZJbnB1dCA9IHRoaXMucHJldklucHV0O1xuICAgIC8vIFNpbmNlIHRoaXMgaXMgY2FsbGVkIGEgKmxvdCosIHRyeSB0byBiYWlsIG91dCBhcyBjaGVhcGx5IGFzXG4gICAgLy8gcG9zc2libGUgd2hlbiBpdCBpcyBjbGVhciB0aGF0IG5vdGhpbmcgaGFwcGVuZWQuIGhhc1NlbGVjdGlvblxuICAgIC8vIHdpbGwgYmUgdGhlIGNhc2Ugd2hlbiB0aGVyZSBpcyBhIGxvdCBvZiB0ZXh0IGluIHRoZSB0ZXh0YXJlYSxcbiAgICAvLyBpbiB3aGljaCBjYXNlIHJlYWRpbmcgaXRzIHZhbHVlIHdvdWxkIGJlIGV4cGVuc2l2ZS5cbiAgICBpZiAodGhpcy5jb250ZXh0TWVudVBlbmRpbmcgfHwgIWNtLnN0YXRlLmZvY3VzZWQgfHxcbiAgICAgICAgKGhhc1NlbGVjdGlvbihpbnB1dCkgJiYgIXByZXZJbnB1dCAmJiAhdGhpcy5jb21wb3NpbmcpIHx8XG4gICAgICAgIGNtLmlzUmVhZE9ubHkoKSB8fCBjbS5vcHRpb25zLmRpc2FibGVJbnB1dCB8fCBjbS5zdGF0ZS5rZXlTZXEpXG4gICAgICB7IHJldHVybiBmYWxzZSB9XG5cbiAgICB2YXIgdGV4dCA9IGlucHV0LnZhbHVlO1xuICAgIC8vIElmIG5vdGhpbmcgY2hhbmdlZCwgYmFpbC5cbiAgICBpZiAodGV4dCA9PSBwcmV2SW5wdXQgJiYgIWNtLnNvbWV0aGluZ1NlbGVjdGVkKCkpIHsgcmV0dXJuIGZhbHNlIH1cbiAgICAvLyBXb3JrIGFyb3VuZCBub25zZW5zaWNhbCBzZWxlY3Rpb24gcmVzZXR0aW5nIGluIElFOS8xMCwgYW5kXG4gICAgLy8gaW5leHBsaWNhYmxlIGFwcGVhcmFuY2Ugb2YgcHJpdmF0ZSBhcmVhIHVuaWNvZGUgY2hhcmFjdGVycyBvblxuICAgIC8vIHNvbWUga2V5IGNvbWJvcyBpbiBNYWMgKCMyNjg5KS5cbiAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA+PSA5ICYmIHRoaXMuaGFzU2VsZWN0aW9uID09PSB0ZXh0IHx8XG4gICAgICAgIG1hYyAmJiAvW1xcdWY3MDAtXFx1ZjdmZl0vLnRlc3QodGV4dCkpIHtcbiAgICAgIGNtLmRpc3BsYXkuaW5wdXQucmVzZXQoKTtcbiAgICAgIHJldHVybiBmYWxzZVxuICAgIH1cblxuICAgIGlmIChjbS5kb2Muc2VsID09IGNtLmRpc3BsYXkuc2VsRm9yQ29udGV4dE1lbnUpIHtcbiAgICAgIHZhciBmaXJzdCA9IHRleHQuY2hhckNvZGVBdCgwKTtcbiAgICAgIGlmIChmaXJzdCA9PSAweDIwMGIgJiYgIXByZXZJbnB1dCkgeyBwcmV2SW5wdXQgPSBcIlxcdTIwMGJcIjsgfVxuICAgICAgaWYgKGZpcnN0ID09IDB4MjFkYSkgeyB0aGlzLnJlc2V0KCk7IHJldHVybiB0aGlzLmNtLmV4ZWNDb21tYW5kKFwidW5kb1wiKSB9XG4gICAgfVxuICAgIC8vIEZpbmQgdGhlIHBhcnQgb2YgdGhlIGlucHV0IHRoYXQgaXMgYWN0dWFsbHkgbmV3XG4gICAgdmFyIHNhbWUgPSAwLCBsID0gTWF0aC5taW4ocHJldklucHV0Lmxlbmd0aCwgdGV4dC5sZW5ndGgpO1xuICAgIHdoaWxlIChzYW1lIDwgbCAmJiBwcmV2SW5wdXQuY2hhckNvZGVBdChzYW1lKSA9PSB0ZXh0LmNoYXJDb2RlQXQoc2FtZSkpIHsgKytzYW1lOyB9XG5cbiAgICBydW5Jbk9wKGNtLCBmdW5jdGlvbiAoKSB7XG4gICAgICBhcHBseVRleHRJbnB1dChjbSwgdGV4dC5zbGljZShzYW1lKSwgcHJldklucHV0Lmxlbmd0aCAtIHNhbWUsXG4gICAgICAgICAgICAgICAgICAgICBudWxsLCB0aGlzJDEuY29tcG9zaW5nID8gXCIqY29tcG9zZVwiIDogbnVsbCk7XG5cbiAgICAgIC8vIERvbid0IGxlYXZlIGxvbmcgdGV4dCBpbiB0aGUgdGV4dGFyZWEsIHNpbmNlIGl0IG1ha2VzIGZ1cnRoZXIgcG9sbGluZyBzbG93XG4gICAgICBpZiAodGV4dC5sZW5ndGggPiAxMDAwIHx8IHRleHQuaW5kZXhPZihcIlxcblwiKSA+IC0xKSB7IGlucHV0LnZhbHVlID0gdGhpcyQxLnByZXZJbnB1dCA9IFwiXCI7IH1cbiAgICAgIGVsc2UgeyB0aGlzJDEucHJldklucHV0ID0gdGV4dDsgfVxuXG4gICAgICBpZiAodGhpcyQxLmNvbXBvc2luZykge1xuICAgICAgICB0aGlzJDEuY29tcG9zaW5nLnJhbmdlLmNsZWFyKCk7XG4gICAgICAgIHRoaXMkMS5jb21wb3NpbmcucmFuZ2UgPSBjbS5tYXJrVGV4dCh0aGlzJDEuY29tcG9zaW5nLnN0YXJ0LCBjbS5nZXRDdXJzb3IoXCJ0b1wiKSxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB7Y2xhc3NOYW1lOiBcIkNvZGVNaXJyb3ItY29tcG9zaW5nXCJ9KTtcbiAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gdHJ1ZVxuICB9O1xuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLmVuc3VyZVBvbGxlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAodGhpcy5wb2xsaW5nRmFzdCAmJiB0aGlzLnBvbGwoKSkgeyB0aGlzLnBvbGxpbmdGYXN0ID0gZmFsc2U7IH1cbiAgfTtcblxuICBUZXh0YXJlYUlucHV0LnByb3RvdHlwZS5vbktleVByZXNzID0gZnVuY3Rpb24gKCkge1xuICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uID49IDkpIHsgdGhpcy5oYXNTZWxlY3Rpb24gPSBudWxsOyB9XG4gICAgdGhpcy5mYXN0UG9sbCgpO1xuICB9O1xuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLm9uQ29udGV4dE1lbnUgPSBmdW5jdGlvbiAoZSkge1xuICAgIHZhciBpbnB1dCA9IHRoaXMsIGNtID0gaW5wdXQuY20sIGRpc3BsYXkgPSBjbS5kaXNwbGF5LCB0ZSA9IGlucHV0LnRleHRhcmVhO1xuICAgIGlmIChpbnB1dC5jb250ZXh0TWVudVBlbmRpbmcpIHsgaW5wdXQuY29udGV4dE1lbnVQZW5kaW5nKCk7IH1cbiAgICB2YXIgcG9zID0gcG9zRnJvbU1vdXNlKGNtLCBlKSwgc2Nyb2xsUG9zID0gZGlzcGxheS5zY3JvbGxlci5zY3JvbGxUb3A7XG4gICAgaWYgKCFwb3MgfHwgcHJlc3RvKSB7IHJldHVybiB9IC8vIE9wZXJhIGlzIGRpZmZpY3VsdC5cblxuICAgIC8vIFJlc2V0IHRoZSBjdXJyZW50IHRleHQgc2VsZWN0aW9uIG9ubHkgaWYgdGhlIGNsaWNrIGlzIGRvbmUgb3V0c2lkZSBvZiB0aGUgc2VsZWN0aW9uXG4gICAgLy8gYW5kICdyZXNldFNlbGVjdGlvbk9uQ29udGV4dE1lbnUnIG9wdGlvbiBpcyB0cnVlLlxuICAgIHZhciByZXNldCA9IGNtLm9wdGlvbnMucmVzZXRTZWxlY3Rpb25PbkNvbnRleHRNZW51O1xuICAgIGlmIChyZXNldCAmJiBjbS5kb2Muc2VsLmNvbnRhaW5zKHBvcykgPT0gLTEpXG4gICAgICB7IG9wZXJhdGlvbihjbSwgc2V0U2VsZWN0aW9uKShjbS5kb2MsIHNpbXBsZVNlbGVjdGlvbihwb3MpLCBzZWxfZG9udFNjcm9sbCk7IH1cblxuICAgIHZhciBvbGRDU1MgPSB0ZS5zdHlsZS5jc3NUZXh0LCBvbGRXcmFwcGVyQ1NTID0gaW5wdXQud3JhcHBlci5zdHlsZS5jc3NUZXh0O1xuICAgIHZhciB3cmFwcGVyQm94ID0gaW5wdXQud3JhcHBlci5vZmZzZXRQYXJlbnQuZ2V0Qm91bmRpbmdDbGllbnRSZWN0KCk7XG4gICAgaW5wdXQud3JhcHBlci5zdHlsZS5jc3NUZXh0ID0gXCJwb3NpdGlvbjogc3RhdGljXCI7XG4gICAgdGUuc3R5bGUuY3NzVGV4dCA9IFwicG9zaXRpb246IGFic29sdXRlOyB3aWR0aDogMzBweDsgaGVpZ2h0OiAzMHB4O1xcbiAgICAgIHRvcDogXCIgKyAoZS5jbGllbnRZIC0gd3JhcHBlckJveC50b3AgLSA1KSArIFwicHg7IGxlZnQ6IFwiICsgKGUuY2xpZW50WCAtIHdyYXBwZXJCb3gubGVmdCAtIDUpICsgXCJweDtcXG4gICAgICB6LWluZGV4OiAxMDAwOyBiYWNrZ3JvdW5kOiBcIiArIChpZSA/IFwicmdiYSgyNTUsIDI1NSwgMjU1LCAuMDUpXCIgOiBcInRyYW5zcGFyZW50XCIpICsgXCI7XFxuICAgICAgb3V0bGluZTogbm9uZTsgYm9yZGVyLXdpZHRoOiAwOyBvdXRsaW5lOiBub25lOyBvdmVyZmxvdzogaGlkZGVuOyBvcGFjaXR5OiAuMDU7IGZpbHRlcjogYWxwaGEob3BhY2l0eT01KTtcIjtcbiAgICB2YXIgb2xkU2Nyb2xsWTtcbiAgICBpZiAod2Via2l0KSB7IG9sZFNjcm9sbFkgPSB3aW5kb3cuc2Nyb2xsWTsgfSAvLyBXb3JrIGFyb3VuZCBDaHJvbWUgaXNzdWUgKCMyNzEyKVxuICAgIGRpc3BsYXkuaW5wdXQuZm9jdXMoKTtcbiAgICBpZiAod2Via2l0KSB7IHdpbmRvdy5zY3JvbGxUbyhudWxsLCBvbGRTY3JvbGxZKTsgfVxuICAgIGRpc3BsYXkuaW5wdXQucmVzZXQoKTtcbiAgICAvLyBBZGRzIFwiU2VsZWN0IGFsbFwiIHRvIGNvbnRleHQgbWVudSBpbiBGRlxuICAgIGlmICghY20uc29tZXRoaW5nU2VsZWN0ZWQoKSkgeyB0ZS52YWx1ZSA9IGlucHV0LnByZXZJbnB1dCA9IFwiIFwiOyB9XG4gICAgaW5wdXQuY29udGV4dE1lbnVQZW5kaW5nID0gcmVoaWRlO1xuICAgIGRpc3BsYXkuc2VsRm9yQ29udGV4dE1lbnUgPSBjbS5kb2Muc2VsO1xuICAgIGNsZWFyVGltZW91dChkaXNwbGF5LmRldGVjdGluZ1NlbGVjdEFsbCk7XG5cbiAgICAvLyBTZWxlY3QtYWxsIHdpbGwgYmUgZ3JleWVkIG91dCBpZiB0aGVyZSdzIG5vdGhpbmcgdG8gc2VsZWN0LCBzb1xuICAgIC8vIHRoaXMgYWRkcyBhIHplcm8td2lkdGggc3BhY2Ugc28gdGhhdCB3ZSBjYW4gbGF0ZXIgY2hlY2sgd2hldGhlclxuICAgIC8vIGl0IGdvdCBzZWxlY3RlZC5cbiAgICBmdW5jdGlvbiBwcmVwYXJlU2VsZWN0QWxsSGFjaygpIHtcbiAgICAgIGlmICh0ZS5zZWxlY3Rpb25TdGFydCAhPSBudWxsKSB7XG4gICAgICAgIHZhciBzZWxlY3RlZCA9IGNtLnNvbWV0aGluZ1NlbGVjdGVkKCk7XG4gICAgICAgIHZhciBleHR2YWwgPSBcIlxcdTIwMGJcIiArIChzZWxlY3RlZCA/IHRlLnZhbHVlIDogXCJcIik7XG4gICAgICAgIHRlLnZhbHVlID0gXCJcXHUyMWRhXCI7IC8vIFVzZWQgdG8gY2F0Y2ggY29udGV4dC1tZW51IHVuZG9cbiAgICAgICAgdGUudmFsdWUgPSBleHR2YWw7XG4gICAgICAgIGlucHV0LnByZXZJbnB1dCA9IHNlbGVjdGVkID8gXCJcIiA6IFwiXFx1MjAwYlwiO1xuICAgICAgICB0ZS5zZWxlY3Rpb25TdGFydCA9IDE7IHRlLnNlbGVjdGlvbkVuZCA9IGV4dHZhbC5sZW5ndGg7XG4gICAgICAgIC8vIFJlLXNldCB0aGlzLCBpbiBjYXNlIHNvbWUgb3RoZXIgaGFuZGxlciB0b3VjaGVkIHRoZVxuICAgICAgICAvLyBzZWxlY3Rpb24gaW4gdGhlIG1lYW50aW1lLlxuICAgICAgICBkaXNwbGF5LnNlbEZvckNvbnRleHRNZW51ID0gY20uZG9jLnNlbDtcbiAgICAgIH1cbiAgICB9XG4gICAgZnVuY3Rpb24gcmVoaWRlKCkge1xuICAgICAgaWYgKGlucHV0LmNvbnRleHRNZW51UGVuZGluZyAhPSByZWhpZGUpIHsgcmV0dXJuIH1cbiAgICAgIGlucHV0LmNvbnRleHRNZW51UGVuZGluZyA9IGZhbHNlO1xuICAgICAgaW5wdXQud3JhcHBlci5zdHlsZS5jc3NUZXh0ID0gb2xkV3JhcHBlckNTUztcbiAgICAgIHRlLnN0eWxlLmNzc1RleHQgPSBvbGRDU1M7XG4gICAgICBpZiAoaWUgJiYgaWVfdmVyc2lvbiA8IDkpIHsgZGlzcGxheS5zY3JvbGxiYXJzLnNldFNjcm9sbFRvcChkaXNwbGF5LnNjcm9sbGVyLnNjcm9sbFRvcCA9IHNjcm9sbFBvcyk7IH1cblxuICAgICAgLy8gVHJ5IHRvIGRldGVjdCB0aGUgdXNlciBjaG9vc2luZyBzZWxlY3QtYWxsXG4gICAgICBpZiAodGUuc2VsZWN0aW9uU3RhcnQgIT0gbnVsbCkge1xuICAgICAgICBpZiAoIWllIHx8IChpZSAmJiBpZV92ZXJzaW9uIDwgOSkpIHsgcHJlcGFyZVNlbGVjdEFsbEhhY2soKTsgfVxuICAgICAgICB2YXIgaSA9IDAsIHBvbGwgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgaWYgKGRpc3BsYXkuc2VsRm9yQ29udGV4dE1lbnUgPT0gY20uZG9jLnNlbCAmJiB0ZS5zZWxlY3Rpb25TdGFydCA9PSAwICYmXG4gICAgICAgICAgICAgIHRlLnNlbGVjdGlvbkVuZCA+IDAgJiYgaW5wdXQucHJldklucHV0ID09IFwiXFx1MjAwYlwiKSB7XG4gICAgICAgICAgICBvcGVyYXRpb24oY20sIHNlbGVjdEFsbCkoY20pO1xuICAgICAgICAgIH0gZWxzZSBpZiAoaSsrIDwgMTApIHtcbiAgICAgICAgICAgIGRpc3BsYXkuZGV0ZWN0aW5nU2VsZWN0QWxsID0gc2V0VGltZW91dChwb2xsLCA1MDApO1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBkaXNwbGF5LnNlbEZvckNvbnRleHRNZW51ID0gbnVsbDtcbiAgICAgICAgICAgIGRpc3BsYXkuaW5wdXQucmVzZXQoKTtcbiAgICAgICAgICB9XG4gICAgICAgIH07XG4gICAgICAgIGRpc3BsYXkuZGV0ZWN0aW5nU2VsZWN0QWxsID0gc2V0VGltZW91dChwb2xsLCAyMDApO1xuICAgICAgfVxuICAgIH1cblxuICAgIGlmIChpZSAmJiBpZV92ZXJzaW9uID49IDkpIHsgcHJlcGFyZVNlbGVjdEFsbEhhY2soKTsgfVxuICAgIGlmIChjYXB0dXJlUmlnaHRDbGljaykge1xuICAgICAgZV9zdG9wKGUpO1xuICAgICAgdmFyIG1vdXNldXAgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIG9mZih3aW5kb3csIFwibW91c2V1cFwiLCBtb3VzZXVwKTtcbiAgICAgICAgc2V0VGltZW91dChyZWhpZGUsIDIwKTtcbiAgICAgIH07XG4gICAgICBvbih3aW5kb3csIFwibW91c2V1cFwiLCBtb3VzZXVwKTtcbiAgICB9IGVsc2Uge1xuICAgICAgc2V0VGltZW91dChyZWhpZGUsIDUwKTtcbiAgICB9XG4gIH07XG5cbiAgVGV4dGFyZWFJbnB1dC5wcm90b3R5cGUucmVhZE9ubHlDaGFuZ2VkID0gZnVuY3Rpb24gKHZhbCkge1xuICAgIGlmICghdmFsKSB7IHRoaXMucmVzZXQoKTsgfVxuICAgIHRoaXMudGV4dGFyZWEuZGlzYWJsZWQgPSB2YWwgPT0gXCJub2N1cnNvclwiO1xuICB9O1xuXG4gIFRleHRhcmVhSW5wdXQucHJvdG90eXBlLnNldFVuZWRpdGFibGUgPSBmdW5jdGlvbiAoKSB7fTtcblxuICBUZXh0YXJlYUlucHV0LnByb3RvdHlwZS5uZWVkc0NvbnRlbnRBdHRyaWJ1dGUgPSBmYWxzZTtcblxuICBmdW5jdGlvbiBmcm9tVGV4dEFyZWEodGV4dGFyZWEsIG9wdGlvbnMpIHtcbiAgICBvcHRpb25zID0gb3B0aW9ucyA/IGNvcHlPYmoob3B0aW9ucykgOiB7fTtcbiAgICBvcHRpb25zLnZhbHVlID0gdGV4dGFyZWEudmFsdWU7XG4gICAgaWYgKCFvcHRpb25zLnRhYmluZGV4ICYmIHRleHRhcmVhLnRhYkluZGV4KVxuICAgICAgeyBvcHRpb25zLnRhYmluZGV4ID0gdGV4dGFyZWEudGFiSW5kZXg7IH1cbiAgICBpZiAoIW9wdGlvbnMucGxhY2Vob2xkZXIgJiYgdGV4dGFyZWEucGxhY2Vob2xkZXIpXG4gICAgICB7IG9wdGlvbnMucGxhY2Vob2xkZXIgPSB0ZXh0YXJlYS5wbGFjZWhvbGRlcjsgfVxuICAgIC8vIFNldCBhdXRvZm9jdXMgdG8gdHJ1ZSBpZiB0aGlzIHRleHRhcmVhIGlzIGZvY3VzZWQsIG9yIGlmIGl0IGhhc1xuICAgIC8vIGF1dG9mb2N1cyBhbmQgbm8gb3RoZXIgZWxlbWVudCBpcyBmb2N1c2VkLlxuICAgIGlmIChvcHRpb25zLmF1dG9mb2N1cyA9PSBudWxsKSB7XG4gICAgICB2YXIgaGFzRm9jdXMgPSBhY3RpdmVFbHQoKTtcbiAgICAgIG9wdGlvbnMuYXV0b2ZvY3VzID0gaGFzRm9jdXMgPT0gdGV4dGFyZWEgfHxcbiAgICAgICAgdGV4dGFyZWEuZ2V0QXR0cmlidXRlKFwiYXV0b2ZvY3VzXCIpICE9IG51bGwgJiYgaGFzRm9jdXMgPT0gZG9jdW1lbnQuYm9keTtcbiAgICB9XG5cbiAgICBmdW5jdGlvbiBzYXZlKCkge3RleHRhcmVhLnZhbHVlID0gY20uZ2V0VmFsdWUoKTt9XG5cbiAgICB2YXIgcmVhbFN1Ym1pdDtcbiAgICBpZiAodGV4dGFyZWEuZm9ybSkge1xuICAgICAgb24odGV4dGFyZWEuZm9ybSwgXCJzdWJtaXRcIiwgc2F2ZSk7XG4gICAgICAvLyBEZXBsb3JhYmxlIGhhY2sgdG8gbWFrZSB0aGUgc3VibWl0IG1ldGhvZCBkbyB0aGUgcmlnaHQgdGhpbmcuXG4gICAgICBpZiAoIW9wdGlvbnMubGVhdmVTdWJtaXRNZXRob2RBbG9uZSkge1xuICAgICAgICB2YXIgZm9ybSA9IHRleHRhcmVhLmZvcm07XG4gICAgICAgIHJlYWxTdWJtaXQgPSBmb3JtLnN1Ym1pdDtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICB2YXIgd3JhcHBlZFN1Ym1pdCA9IGZvcm0uc3VibWl0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2F2ZSgpO1xuICAgICAgICAgICAgZm9ybS5zdWJtaXQgPSByZWFsU3VibWl0O1xuICAgICAgICAgICAgZm9ybS5zdWJtaXQoKTtcbiAgICAgICAgICAgIGZvcm0uc3VibWl0ID0gd3JhcHBlZFN1Ym1pdDtcbiAgICAgICAgICB9O1xuICAgICAgICB9IGNhdGNoKGUpIHt9XG4gICAgICB9XG4gICAgfVxuXG4gICAgb3B0aW9ucy5maW5pc2hJbml0ID0gZnVuY3Rpb24gKGNtKSB7XG4gICAgICBjbS5zYXZlID0gc2F2ZTtcbiAgICAgIGNtLmdldFRleHRBcmVhID0gZnVuY3Rpb24gKCkgeyByZXR1cm4gdGV4dGFyZWE7IH07XG4gICAgICBjbS50b1RleHRBcmVhID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBjbS50b1RleHRBcmVhID0gaXNOYU47IC8vIFByZXZlbnQgdGhpcyBmcm9tIGJlaW5nIHJhbiB0d2ljZVxuICAgICAgICBzYXZlKCk7XG4gICAgICAgIHRleHRhcmVhLnBhcmVudE5vZGUucmVtb3ZlQ2hpbGQoY20uZ2V0V3JhcHBlckVsZW1lbnQoKSk7XG4gICAgICAgIHRleHRhcmVhLnN0eWxlLmRpc3BsYXkgPSBcIlwiO1xuICAgICAgICBpZiAodGV4dGFyZWEuZm9ybSkge1xuICAgICAgICAgIG9mZih0ZXh0YXJlYS5mb3JtLCBcInN1Ym1pdFwiLCBzYXZlKTtcbiAgICAgICAgICBpZiAodHlwZW9mIHRleHRhcmVhLmZvcm0uc3VibWl0ID09IFwiZnVuY3Rpb25cIilcbiAgICAgICAgICAgIHsgdGV4dGFyZWEuZm9ybS5zdWJtaXQgPSByZWFsU3VibWl0OyB9XG4gICAgICAgIH1cbiAgICAgIH07XG4gICAgfTtcblxuICAgIHRleHRhcmVhLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICB2YXIgY20gPSBDb2RlTWlycm9yKGZ1bmN0aW9uIChub2RlKSB7IHJldHVybiB0ZXh0YXJlYS5wYXJlbnROb2RlLmluc2VydEJlZm9yZShub2RlLCB0ZXh0YXJlYS5uZXh0U2libGluZyk7IH0sXG4gICAgICBvcHRpb25zKTtcbiAgICByZXR1cm4gY21cbiAgfVxuXG4gIGZ1bmN0aW9uIGFkZExlZ2FjeVByb3BzKENvZGVNaXJyb3IpIHtcbiAgICBDb2RlTWlycm9yLm9mZiA9IG9mZjtcbiAgICBDb2RlTWlycm9yLm9uID0gb247XG4gICAgQ29kZU1pcnJvci53aGVlbEV2ZW50UGl4ZWxzID0gd2hlZWxFdmVudFBpeGVscztcbiAgICBDb2RlTWlycm9yLkRvYyA9IERvYztcbiAgICBDb2RlTWlycm9yLnNwbGl0TGluZXMgPSBzcGxpdExpbmVzQXV0bztcbiAgICBDb2RlTWlycm9yLmNvdW50Q29sdW1uID0gY291bnRDb2x1bW47XG4gICAgQ29kZU1pcnJvci5maW5kQ29sdW1uID0gZmluZENvbHVtbjtcbiAgICBDb2RlTWlycm9yLmlzV29yZENoYXIgPSBpc1dvcmRDaGFyQmFzaWM7XG4gICAgQ29kZU1pcnJvci5QYXNzID0gUGFzcztcbiAgICBDb2RlTWlycm9yLnNpZ25hbCA9IHNpZ25hbDtcbiAgICBDb2RlTWlycm9yLkxpbmUgPSBMaW5lO1xuICAgIENvZGVNaXJyb3IuY2hhbmdlRW5kID0gY2hhbmdlRW5kO1xuICAgIENvZGVNaXJyb3Iuc2Nyb2xsYmFyTW9kZWwgPSBzY3JvbGxiYXJNb2RlbDtcbiAgICBDb2RlTWlycm9yLlBvcyA9IFBvcztcbiAgICBDb2RlTWlycm9yLmNtcFBvcyA9IGNtcDtcbiAgICBDb2RlTWlycm9yLm1vZGVzID0gbW9kZXM7XG4gICAgQ29kZU1pcnJvci5taW1lTW9kZXMgPSBtaW1lTW9kZXM7XG4gICAgQ29kZU1pcnJvci5yZXNvbHZlTW9kZSA9IHJlc29sdmVNb2RlO1xuICAgIENvZGVNaXJyb3IuZ2V0TW9kZSA9IGdldE1vZGU7XG4gICAgQ29kZU1pcnJvci5tb2RlRXh0ZW5zaW9ucyA9IG1vZGVFeHRlbnNpb25zO1xuICAgIENvZGVNaXJyb3IuZXh0ZW5kTW9kZSA9IGV4dGVuZE1vZGU7XG4gICAgQ29kZU1pcnJvci5jb3B5U3RhdGUgPSBjb3B5U3RhdGU7XG4gICAgQ29kZU1pcnJvci5zdGFydFN0YXRlID0gc3RhcnRTdGF0ZTtcbiAgICBDb2RlTWlycm9yLmlubmVyTW9kZSA9IGlubmVyTW9kZTtcbiAgICBDb2RlTWlycm9yLmNvbW1hbmRzID0gY29tbWFuZHM7XG4gICAgQ29kZU1pcnJvci5rZXlNYXAgPSBrZXlNYXA7XG4gICAgQ29kZU1pcnJvci5rZXlOYW1lID0ga2V5TmFtZTtcbiAgICBDb2RlTWlycm9yLmlzTW9kaWZpZXJLZXkgPSBpc01vZGlmaWVyS2V5O1xuICAgIENvZGVNaXJyb3IubG9va3VwS2V5ID0gbG9va3VwS2V5O1xuICAgIENvZGVNaXJyb3Iubm9ybWFsaXplS2V5TWFwID0gbm9ybWFsaXplS2V5TWFwO1xuICAgIENvZGVNaXJyb3IuU3RyaW5nU3RyZWFtID0gU3RyaW5nU3RyZWFtO1xuICAgIENvZGVNaXJyb3IuU2hhcmVkVGV4dE1hcmtlciA9IFNoYXJlZFRleHRNYXJrZXI7XG4gICAgQ29kZU1pcnJvci5UZXh0TWFya2VyID0gVGV4dE1hcmtlcjtcbiAgICBDb2RlTWlycm9yLkxpbmVXaWRnZXQgPSBMaW5lV2lkZ2V0O1xuICAgIENvZGVNaXJyb3IuZV9wcmV2ZW50RGVmYXVsdCA9IGVfcHJldmVudERlZmF1bHQ7XG4gICAgQ29kZU1pcnJvci5lX3N0b3BQcm9wYWdhdGlvbiA9IGVfc3RvcFByb3BhZ2F0aW9uO1xuICAgIENvZGVNaXJyb3IuZV9zdG9wID0gZV9zdG9wO1xuICAgIENvZGVNaXJyb3IuYWRkQ2xhc3MgPSBhZGRDbGFzcztcbiAgICBDb2RlTWlycm9yLmNvbnRhaW5zID0gY29udGFpbnM7XG4gICAgQ29kZU1pcnJvci5ybUNsYXNzID0gcm1DbGFzcztcbiAgICBDb2RlTWlycm9yLmtleU5hbWVzID0ga2V5TmFtZXM7XG4gIH1cblxuICAvLyBFRElUT1IgQ09OU1RSVUNUT1JcblxuICBkZWZpbmVPcHRpb25zKENvZGVNaXJyb3IpO1xuXG4gIGFkZEVkaXRvck1ldGhvZHMoQ29kZU1pcnJvcik7XG5cbiAgLy8gU2V0IHVwIG1ldGhvZHMgb24gQ29kZU1pcnJvcidzIHByb3RvdHlwZSB0byByZWRpcmVjdCB0byB0aGUgZWRpdG9yJ3MgZG9jdW1lbnQuXG4gIHZhciBkb250RGVsZWdhdGUgPSBcIml0ZXIgaW5zZXJ0IHJlbW92ZSBjb3B5IGdldEVkaXRvciBjb25zdHJ1Y3RvclwiLnNwbGl0KFwiIFwiKTtcbiAgZm9yICh2YXIgcHJvcCBpbiBEb2MucHJvdG90eXBlKSB7IGlmIChEb2MucHJvdG90eXBlLmhhc093blByb3BlcnR5KHByb3ApICYmIGluZGV4T2YoZG9udERlbGVnYXRlLCBwcm9wKSA8IDApXG4gICAgeyBDb2RlTWlycm9yLnByb3RvdHlwZVtwcm9wXSA9IChmdW5jdGlvbihtZXRob2QpIHtcbiAgICAgIHJldHVybiBmdW5jdGlvbigpIHtyZXR1cm4gbWV0aG9kLmFwcGx5KHRoaXMuZG9jLCBhcmd1bWVudHMpfVxuICAgIH0pKERvYy5wcm90b3R5cGVbcHJvcF0pOyB9IH1cblxuICBldmVudE1peGluKERvYyk7XG4gIENvZGVNaXJyb3IuaW5wdXRTdHlsZXMgPSB7XCJ0ZXh0YXJlYVwiOiBUZXh0YXJlYUlucHV0LCBcImNvbnRlbnRlZGl0YWJsZVwiOiBDb250ZW50RWRpdGFibGVJbnB1dH07XG5cbiAgLy8gRXh0cmEgYXJndW1lbnRzIGFyZSBzdG9yZWQgYXMgdGhlIG1vZGUncyBkZXBlbmRlbmNpZXMsIHdoaWNoIGlzXG4gIC8vIHVzZWQgYnkgKGxlZ2FjeSkgbWVjaGFuaXNtcyBsaWtlIGxvYWRtb2RlLmpzIHRvIGF1dG9tYXRpY2FsbHlcbiAgLy8gbG9hZCBhIG1vZGUuIChQcmVmZXJyZWQgbWVjaGFuaXNtIGlzIHRoZSByZXF1aXJlL2RlZmluZSBjYWxscy4pXG4gIENvZGVNaXJyb3IuZGVmaW5lTW9kZSA9IGZ1bmN0aW9uKG5hbWUvKiwgbW9kZSwg4oCmKi8pIHtcbiAgICBpZiAoIUNvZGVNaXJyb3IuZGVmYXVsdHMubW9kZSAmJiBuYW1lICE9IFwibnVsbFwiKSB7IENvZGVNaXJyb3IuZGVmYXVsdHMubW9kZSA9IG5hbWU7IH1cbiAgICBkZWZpbmVNb2RlLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gIH07XG5cbiAgQ29kZU1pcnJvci5kZWZpbmVNSU1FID0gZGVmaW5lTUlNRTtcblxuICAvLyBNaW5pbWFsIGRlZmF1bHQgbW9kZS5cbiAgQ29kZU1pcnJvci5kZWZpbmVNb2RlKFwibnVsbFwiLCBmdW5jdGlvbiAoKSB7IHJldHVybiAoe3Rva2VuOiBmdW5jdGlvbiAoc3RyZWFtKSB7IHJldHVybiBzdHJlYW0uc2tpcFRvRW5kKCk7IH19KTsgfSk7XG4gIENvZGVNaXJyb3IuZGVmaW5lTUlNRShcInRleHQvcGxhaW5cIiwgXCJudWxsXCIpO1xuXG4gIC8vIEVYVEVOU0lPTlNcblxuICBDb2RlTWlycm9yLmRlZmluZUV4dGVuc2lvbiA9IGZ1bmN0aW9uIChuYW1lLCBmdW5jKSB7XG4gICAgQ29kZU1pcnJvci5wcm90b3R5cGVbbmFtZV0gPSBmdW5jO1xuICB9O1xuICBDb2RlTWlycm9yLmRlZmluZURvY0V4dGVuc2lvbiA9IGZ1bmN0aW9uIChuYW1lLCBmdW5jKSB7XG4gICAgRG9jLnByb3RvdHlwZVtuYW1lXSA9IGZ1bmM7XG4gIH07XG5cbiAgQ29kZU1pcnJvci5mcm9tVGV4dEFyZWEgPSBmcm9tVGV4dEFyZWE7XG5cbiAgYWRkTGVnYWN5UHJvcHMoQ29kZU1pcnJvcik7XG5cbiAgQ29kZU1pcnJvci52ZXJzaW9uID0gXCI1LjQyLjJcIjtcblxuICByZXR1cm4gQ29kZU1pcnJvcjtcblxufSkpKTtcbiIsIi8vIENvZGVNaXJyb3IsIGNvcHlyaWdodCAoYykgYnkgTWFyaWpuIEhhdmVyYmVrZSBhbmQgb3RoZXJzXG4vLyBEaXN0cmlidXRlZCB1bmRlciBhbiBNSVQgbGljZW5zZTogaHR0cHM6Ly9jb2RlbWlycm9yLm5ldC9MSUNFTlNFXG5cbihmdW5jdGlvbihtb2QpIHtcbiAgaWYgKHR5cGVvZiBleHBvcnRzID09IFwib2JqZWN0XCIgJiYgdHlwZW9mIG1vZHVsZSA9PSBcIm9iamVjdFwiKSAvLyBDb21tb25KU1xuICAgIG1vZChyZXF1aXJlKFwiLi4vLi4vbGliL2NvZGVtaXJyb3JcIikpO1xuICBlbHNlIGlmICh0eXBlb2YgZGVmaW5lID09IFwiZnVuY3Rpb25cIiAmJiBkZWZpbmUuYW1kKSAvLyBBTURcbiAgICBkZWZpbmUoW1wiLi4vLi4vbGliL2NvZGVtaXJyb3JcIl0sIG1vZCk7XG4gIGVsc2UgLy8gUGxhaW4gYnJvd3NlciBlbnZcbiAgICBtb2QoQ29kZU1pcnJvcik7XG59KShmdW5jdGlvbihDb2RlTWlycm9yKSB7XG5cInVzZSBzdHJpY3RcIjtcblxuQ29kZU1pcnJvci5kZWZpbmVNb2RlKFwiY3NzXCIsIGZ1bmN0aW9uKGNvbmZpZywgcGFyc2VyQ29uZmlnKSB7XG4gIHZhciBpbmxpbmUgPSBwYXJzZXJDb25maWcuaW5saW5lXG4gIGlmICghcGFyc2VyQ29uZmlnLnByb3BlcnR5S2V5d29yZHMpIHBhcnNlckNvbmZpZyA9IENvZGVNaXJyb3IucmVzb2x2ZU1vZGUoXCJ0ZXh0L2Nzc1wiKTtcblxuICB2YXIgaW5kZW50VW5pdCA9IGNvbmZpZy5pbmRlbnRVbml0LFxuICAgICAgdG9rZW5Ib29rcyA9IHBhcnNlckNvbmZpZy50b2tlbkhvb2tzLFxuICAgICAgZG9jdW1lbnRUeXBlcyA9IHBhcnNlckNvbmZpZy5kb2N1bWVudFR5cGVzIHx8IHt9LFxuICAgICAgbWVkaWFUeXBlcyA9IHBhcnNlckNvbmZpZy5tZWRpYVR5cGVzIHx8IHt9LFxuICAgICAgbWVkaWFGZWF0dXJlcyA9IHBhcnNlckNvbmZpZy5tZWRpYUZlYXR1cmVzIHx8IHt9LFxuICAgICAgbWVkaWFWYWx1ZUtleXdvcmRzID0gcGFyc2VyQ29uZmlnLm1lZGlhVmFsdWVLZXl3b3JkcyB8fCB7fSxcbiAgICAgIHByb3BlcnR5S2V5d29yZHMgPSBwYXJzZXJDb25maWcucHJvcGVydHlLZXl3b3JkcyB8fCB7fSxcbiAgICAgIG5vblN0YW5kYXJkUHJvcGVydHlLZXl3b3JkcyA9IHBhcnNlckNvbmZpZy5ub25TdGFuZGFyZFByb3BlcnR5S2V5d29yZHMgfHwge30sXG4gICAgICBmb250UHJvcGVydGllcyA9IHBhcnNlckNvbmZpZy5mb250UHJvcGVydGllcyB8fCB7fSxcbiAgICAgIGNvdW50ZXJEZXNjcmlwdG9ycyA9IHBhcnNlckNvbmZpZy5jb3VudGVyRGVzY3JpcHRvcnMgfHwge30sXG4gICAgICBjb2xvcktleXdvcmRzID0gcGFyc2VyQ29uZmlnLmNvbG9yS2V5d29yZHMgfHwge30sXG4gICAgICB2YWx1ZUtleXdvcmRzID0gcGFyc2VyQ29uZmlnLnZhbHVlS2V5d29yZHMgfHwge30sXG4gICAgICBhbGxvd05lc3RlZCA9IHBhcnNlckNvbmZpZy5hbGxvd05lc3RlZCxcbiAgICAgIGxpbmVDb21tZW50ID0gcGFyc2VyQ29uZmlnLmxpbmVDb21tZW50LFxuICAgICAgc3VwcG9ydHNBdENvbXBvbmVudCA9IHBhcnNlckNvbmZpZy5zdXBwb3J0c0F0Q29tcG9uZW50ID09PSB0cnVlO1xuXG4gIHZhciB0eXBlLCBvdmVycmlkZTtcbiAgZnVuY3Rpb24gcmV0KHN0eWxlLCB0cCkgeyB0eXBlID0gdHA7IHJldHVybiBzdHlsZTsgfVxuXG4gIC8vIFRva2VuaXplcnNcblxuICBmdW5jdGlvbiB0b2tlbkJhc2Uoc3RyZWFtLCBzdGF0ZSkge1xuICAgIHZhciBjaCA9IHN0cmVhbS5uZXh0KCk7XG4gICAgaWYgKHRva2VuSG9va3NbY2hdKSB7XG4gICAgICB2YXIgcmVzdWx0ID0gdG9rZW5Ib29rc1tjaF0oc3RyZWFtLCBzdGF0ZSk7XG4gICAgICBpZiAocmVzdWx0ICE9PSBmYWxzZSkgcmV0dXJuIHJlc3VsdDtcbiAgICB9XG4gICAgaWYgKGNoID09IFwiQFwiKSB7XG4gICAgICBzdHJlYW0uZWF0V2hpbGUoL1tcXHdcXFxcXFwtXS8pO1xuICAgICAgcmV0dXJuIHJldChcImRlZlwiLCBzdHJlYW0uY3VycmVudCgpKTtcbiAgICB9IGVsc2UgaWYgKGNoID09IFwiPVwiIHx8IChjaCA9PSBcIn5cIiB8fCBjaCA9PSBcInxcIikgJiYgc3RyZWFtLmVhdChcIj1cIikpIHtcbiAgICAgIHJldHVybiByZXQobnVsbCwgXCJjb21wYXJlXCIpO1xuICAgIH0gZWxzZSBpZiAoY2ggPT0gXCJcXFwiXCIgfHwgY2ggPT0gXCInXCIpIHtcbiAgICAgIHN0YXRlLnRva2VuaXplID0gdG9rZW5TdHJpbmcoY2gpO1xuICAgICAgcmV0dXJuIHN0YXRlLnRva2VuaXplKHN0cmVhbSwgc3RhdGUpO1xuICAgIH0gZWxzZSBpZiAoY2ggPT0gXCIjXCIpIHtcbiAgICAgIHN0cmVhbS5lYXRXaGlsZSgvW1xcd1xcXFxcXC1dLyk7XG4gICAgICByZXR1cm4gcmV0KFwiYXRvbVwiLCBcImhhc2hcIik7XG4gICAgfSBlbHNlIGlmIChjaCA9PSBcIiFcIikge1xuICAgICAgc3RyZWFtLm1hdGNoKC9eXFxzKlxcdyovKTtcbiAgICAgIHJldHVybiByZXQoXCJrZXl3b3JkXCIsIFwiaW1wb3J0YW50XCIpO1xuICAgIH0gZWxzZSBpZiAoL1xcZC8udGVzdChjaCkgfHwgY2ggPT0gXCIuXCIgJiYgc3RyZWFtLmVhdCgvXFxkLykpIHtcbiAgICAgIHN0cmVhbS5lYXRXaGlsZSgvW1xcdy4lXS8pO1xuICAgICAgcmV0dXJuIHJldChcIm51bWJlclwiLCBcInVuaXRcIik7XG4gICAgfSBlbHNlIGlmIChjaCA9PT0gXCItXCIpIHtcbiAgICAgIGlmICgvW1xcZC5dLy50ZXN0KHN0cmVhbS5wZWVrKCkpKSB7XG4gICAgICAgIHN0cmVhbS5lYXRXaGlsZSgvW1xcdy4lXS8pO1xuICAgICAgICByZXR1cm4gcmV0KFwibnVtYmVyXCIsIFwidW5pdFwiKTtcbiAgICAgIH0gZWxzZSBpZiAoc3RyZWFtLm1hdGNoKC9eLVtcXHdcXFxcXFwtXSovKSkge1xuICAgICAgICBzdHJlYW0uZWF0V2hpbGUoL1tcXHdcXFxcXFwtXS8pO1xuICAgICAgICBpZiAoc3RyZWFtLm1hdGNoKC9eXFxzKjovLCBmYWxzZSkpXG4gICAgICAgICAgcmV0dXJuIHJldChcInZhcmlhYmxlLTJcIiwgXCJ2YXJpYWJsZS1kZWZpbml0aW9uXCIpO1xuICAgICAgICByZXR1cm4gcmV0KFwidmFyaWFibGUtMlwiLCBcInZhcmlhYmxlXCIpO1xuICAgICAgfSBlbHNlIGlmIChzdHJlYW0ubWF0Y2goL15cXHcrLS8pKSB7XG4gICAgICAgIHJldHVybiByZXQoXCJtZXRhXCIsIFwibWV0YVwiKTtcbiAgICAgIH1cbiAgICB9IGVsc2UgaWYgKC9bLCs+KlxcL10vLnRlc3QoY2gpKSB7XG4gICAgICByZXR1cm4gcmV0KG51bGwsIFwic2VsZWN0LW9wXCIpO1xuICAgIH0gZWxzZSBpZiAoY2ggPT0gXCIuXCIgJiYgc3RyZWFtLm1hdGNoKC9eLT9bX2Etel1bX2EtejAtOS1dKi9pKSkge1xuICAgICAgcmV0dXJuIHJldChcInF1YWxpZmllclwiLCBcInF1YWxpZmllclwiKTtcbiAgICB9IGVsc2UgaWYgKC9bOjt7fVxcW1xcXVxcKFxcKV0vLnRlc3QoY2gpKSB7XG4gICAgICByZXR1cm4gcmV0KG51bGwsIGNoKTtcbiAgICB9IGVsc2UgaWYgKCgoY2ggPT0gXCJ1XCIgfHwgY2ggPT0gXCJVXCIpICYmIHN0cmVhbS5tYXRjaCgvcmwoLXByZWZpeCk/XFwoL2kpKSB8fFxuICAgICAgICAgICAgICAgKChjaCA9PSBcImRcIiB8fCBjaCA9PSBcIkRcIikgJiYgc3RyZWFtLm1hdGNoKFwib21haW4oXCIsIHRydWUsIHRydWUpKSB8fFxuICAgICAgICAgICAgICAgKChjaCA9PSBcInJcIiB8fCBjaCA9PSBcIlJcIikgJiYgc3RyZWFtLm1hdGNoKFwiZWdleHAoXCIsIHRydWUsIHRydWUpKSkge1xuICAgICAgc3RyZWFtLmJhY2tVcCgxKTtcbiAgICAgIHN0YXRlLnRva2VuaXplID0gdG9rZW5QYXJlbnRoZXNpemVkO1xuICAgICAgcmV0dXJuIHJldChcInByb3BlcnR5XCIsIFwid29yZFwiKTtcbiAgICB9IGVsc2UgaWYgKC9bXFx3XFxcXFxcLV0vLnRlc3QoY2gpKSB7XG4gICAgICBzdHJlYW0uZWF0V2hpbGUoL1tcXHdcXFxcXFwtXS8pO1xuICAgICAgcmV0dXJuIHJldChcInByb3BlcnR5XCIsIFwid29yZFwiKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHJldChudWxsLCBudWxsKTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiB0b2tlblN0cmluZyhxdW90ZSkge1xuICAgIHJldHVybiBmdW5jdGlvbihzdHJlYW0sIHN0YXRlKSB7XG4gICAgICB2YXIgZXNjYXBlZCA9IGZhbHNlLCBjaDtcbiAgICAgIHdoaWxlICgoY2ggPSBzdHJlYW0ubmV4dCgpKSAhPSBudWxsKSB7XG4gICAgICAgIGlmIChjaCA9PSBxdW90ZSAmJiAhZXNjYXBlZCkge1xuICAgICAgICAgIGlmIChxdW90ZSA9PSBcIilcIikgc3RyZWFtLmJhY2tVcCgxKTtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBlc2NhcGVkID0gIWVzY2FwZWQgJiYgY2ggPT0gXCJcXFxcXCI7XG4gICAgICB9XG4gICAgICBpZiAoY2ggPT0gcXVvdGUgfHwgIWVzY2FwZWQgJiYgcXVvdGUgIT0gXCIpXCIpIHN0YXRlLnRva2VuaXplID0gbnVsbDtcbiAgICAgIHJldHVybiByZXQoXCJzdHJpbmdcIiwgXCJzdHJpbmdcIik7XG4gICAgfTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHRva2VuUGFyZW50aGVzaXplZChzdHJlYW0sIHN0YXRlKSB7XG4gICAgc3RyZWFtLm5leHQoKTsgLy8gTXVzdCBiZSAnKCdcbiAgICBpZiAoIXN0cmVhbS5tYXRjaCgvXFxzKltcXFwiXFwnKV0vLCBmYWxzZSkpXG4gICAgICBzdGF0ZS50b2tlbml6ZSA9IHRva2VuU3RyaW5nKFwiKVwiKTtcbiAgICBlbHNlXG4gICAgICBzdGF0ZS50b2tlbml6ZSA9IG51bGw7XG4gICAgcmV0dXJuIHJldChudWxsLCBcIihcIik7XG4gIH1cblxuICAvLyBDb250ZXh0IG1hbmFnZW1lbnRcblxuICBmdW5jdGlvbiBDb250ZXh0KHR5cGUsIGluZGVudCwgcHJldikge1xuICAgIHRoaXMudHlwZSA9IHR5cGU7XG4gICAgdGhpcy5pbmRlbnQgPSBpbmRlbnQ7XG4gICAgdGhpcy5wcmV2ID0gcHJldjtcbiAgfVxuXG4gIGZ1bmN0aW9uIHB1c2hDb250ZXh0KHN0YXRlLCBzdHJlYW0sIHR5cGUsIGluZGVudCkge1xuICAgIHN0YXRlLmNvbnRleHQgPSBuZXcgQ29udGV4dCh0eXBlLCBzdHJlYW0uaW5kZW50YXRpb24oKSArIChpbmRlbnQgPT09IGZhbHNlID8gMCA6IGluZGVudFVuaXQpLCBzdGF0ZS5jb250ZXh0KTtcbiAgICByZXR1cm4gdHlwZTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHBvcENvbnRleHQoc3RhdGUpIHtcbiAgICBpZiAoc3RhdGUuY29udGV4dC5wcmV2KVxuICAgICAgc3RhdGUuY29udGV4dCA9IHN0YXRlLmNvbnRleHQucHJldjtcbiAgICByZXR1cm4gc3RhdGUuY29udGV4dC50eXBlO1xuICB9XG5cbiAgZnVuY3Rpb24gcGFzcyh0eXBlLCBzdHJlYW0sIHN0YXRlKSB7XG4gICAgcmV0dXJuIHN0YXRlc1tzdGF0ZS5jb250ZXh0LnR5cGVdKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICB9XG4gIGZ1bmN0aW9uIHBvcEFuZFBhc3ModHlwZSwgc3RyZWFtLCBzdGF0ZSwgbikge1xuICAgIGZvciAodmFyIGkgPSBuIHx8IDE7IGkgPiAwOyBpLS0pXG4gICAgICBzdGF0ZS5jb250ZXh0ID0gc3RhdGUuY29udGV4dC5wcmV2O1xuICAgIHJldHVybiBwYXNzKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICB9XG5cbiAgLy8gUGFyc2VyXG5cbiAgZnVuY3Rpb24gd29yZEFzVmFsdWUoc3RyZWFtKSB7XG4gICAgdmFyIHdvcmQgPSBzdHJlYW0uY3VycmVudCgpLnRvTG93ZXJDYXNlKCk7XG4gICAgaWYgKHZhbHVlS2V5d29yZHMuaGFzT3duUHJvcGVydHkod29yZCkpXG4gICAgICBvdmVycmlkZSA9IFwiYXRvbVwiO1xuICAgIGVsc2UgaWYgKGNvbG9yS2V5d29yZHMuaGFzT3duUHJvcGVydHkod29yZCkpXG4gICAgICBvdmVycmlkZSA9IFwia2V5d29yZFwiO1xuICAgIGVsc2VcbiAgICAgIG92ZXJyaWRlID0gXCJ2YXJpYWJsZVwiO1xuICB9XG5cbiAgdmFyIHN0YXRlcyA9IHt9O1xuXG4gIHN0YXRlcy50b3AgPSBmdW5jdGlvbih0eXBlLCBzdHJlYW0sIHN0YXRlKSB7XG4gICAgaWYgKHR5cGUgPT0gXCJ7XCIpIHtcbiAgICAgIHJldHVybiBwdXNoQ29udGV4dChzdGF0ZSwgc3RyZWFtLCBcImJsb2NrXCIpO1xuICAgIH0gZWxzZSBpZiAodHlwZSA9PSBcIn1cIiAmJiBzdGF0ZS5jb250ZXh0LnByZXYpIHtcbiAgICAgIHJldHVybiBwb3BDb250ZXh0KHN0YXRlKTtcbiAgICB9IGVsc2UgaWYgKHN1cHBvcnRzQXRDb21wb25lbnQgJiYgL0Bjb21wb25lbnQvaS50ZXN0KHR5cGUpKSB7XG4gICAgICByZXR1cm4gcHVzaENvbnRleHQoc3RhdGUsIHN0cmVhbSwgXCJhdENvbXBvbmVudEJsb2NrXCIpO1xuICAgIH0gZWxzZSBpZiAoL15AKC1tb3otKT9kb2N1bWVudCQvaS50ZXN0KHR5cGUpKSB7XG4gICAgICByZXR1cm4gcHVzaENvbnRleHQoc3RhdGUsIHN0cmVhbSwgXCJkb2N1bWVudFR5cGVzXCIpO1xuICAgIH0gZWxzZSBpZiAoL15AKG1lZGlhfHN1cHBvcnRzfCgtbW96LSk/ZG9jdW1lbnR8aW1wb3J0KSQvaS50ZXN0KHR5cGUpKSB7XG4gICAgICByZXR1cm4gcHVzaENvbnRleHQoc3RhdGUsIHN0cmVhbSwgXCJhdEJsb2NrXCIpO1xuICAgIH0gZWxzZSBpZiAoL15AKGZvbnQtZmFjZXxjb3VudGVyLXN0eWxlKS9pLnRlc3QodHlwZSkpIHtcbiAgICAgIHN0YXRlLnN0YXRlQXJnID0gdHlwZTtcbiAgICAgIHJldHVybiBcInJlc3RyaWN0ZWRfYXRCbG9ja19iZWZvcmVcIjtcbiAgICB9IGVsc2UgaWYgKC9eQCgtKG1venxtc3xvfHdlYmtpdCktKT9rZXlmcmFtZXMkL2kudGVzdCh0eXBlKSkge1xuICAgICAgcmV0dXJuIFwia2V5ZnJhbWVzXCI7XG4gICAgfSBlbHNlIGlmICh0eXBlICYmIHR5cGUuY2hhckF0KDApID09IFwiQFwiKSB7XG4gICAgICByZXR1cm4gcHVzaENvbnRleHQoc3RhdGUsIHN0cmVhbSwgXCJhdFwiKTtcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT0gXCJoYXNoXCIpIHtcbiAgICAgIG92ZXJyaWRlID0gXCJidWlsdGluXCI7XG4gICAgfSBlbHNlIGlmICh0eXBlID09IFwid29yZFwiKSB7XG4gICAgICBvdmVycmlkZSA9IFwidGFnXCI7XG4gICAgfSBlbHNlIGlmICh0eXBlID09IFwidmFyaWFibGUtZGVmaW5pdGlvblwiKSB7XG4gICAgICByZXR1cm4gXCJtYXliZXByb3BcIjtcbiAgICB9IGVsc2UgaWYgKHR5cGUgPT0gXCJpbnRlcnBvbGF0aW9uXCIpIHtcbiAgICAgIHJldHVybiBwdXNoQ29udGV4dChzdGF0ZSwgc3RyZWFtLCBcImludGVycG9sYXRpb25cIik7XG4gICAgfSBlbHNlIGlmICh0eXBlID09IFwiOlwiKSB7XG4gICAgICByZXR1cm4gXCJwc2V1ZG9cIjtcbiAgICB9IGVsc2UgaWYgKGFsbG93TmVzdGVkICYmIHR5cGUgPT0gXCIoXCIpIHtcbiAgICAgIHJldHVybiBwdXNoQ29udGV4dChzdGF0ZSwgc3RyZWFtLCBcInBhcmVuc1wiKTtcbiAgICB9XG4gICAgcmV0dXJuIHN0YXRlLmNvbnRleHQudHlwZTtcbiAgfTtcblxuICBzdGF0ZXMuYmxvY2sgPSBmdW5jdGlvbih0eXBlLCBzdHJlYW0sIHN0YXRlKSB7XG4gICAgaWYgKHR5cGUgPT0gXCJ3b3JkXCIpIHtcbiAgICAgIHZhciB3b3JkID0gc3RyZWFtLmN1cnJlbnQoKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgaWYgKHByb3BlcnR5S2V5d29yZHMuaGFzT3duUHJvcGVydHkod29yZCkpIHtcbiAgICAgICAgb3ZlcnJpZGUgPSBcInByb3BlcnR5XCI7XG4gICAgICAgIHJldHVybiBcIm1heWJlcHJvcFwiO1xuICAgICAgfSBlbHNlIGlmIChub25TdGFuZGFyZFByb3BlcnR5S2V5d29yZHMuaGFzT3duUHJvcGVydHkod29yZCkpIHtcbiAgICAgICAgb3ZlcnJpZGUgPSBcInN0cmluZy0yXCI7XG4gICAgICAgIHJldHVybiBcIm1heWJlcHJvcFwiO1xuICAgICAgfSBlbHNlIGlmIChhbGxvd05lc3RlZCkge1xuICAgICAgICBvdmVycmlkZSA9IHN0cmVhbS5tYXRjaCgvXlxccyo6KD86XFxzfCQpLywgZmFsc2UpID8gXCJwcm9wZXJ0eVwiIDogXCJ0YWdcIjtcbiAgICAgICAgcmV0dXJuIFwiYmxvY2tcIjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIG92ZXJyaWRlICs9IFwiIGVycm9yXCI7XG4gICAgICAgIHJldHVybiBcIm1heWJlcHJvcFwiO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodHlwZSA9PSBcIm1ldGFcIikge1xuICAgICAgcmV0dXJuIFwiYmxvY2tcIjtcbiAgICB9IGVsc2UgaWYgKCFhbGxvd05lc3RlZCAmJiAodHlwZSA9PSBcImhhc2hcIiB8fCB0eXBlID09IFwicXVhbGlmaWVyXCIpKSB7XG4gICAgICBvdmVycmlkZSA9IFwiZXJyb3JcIjtcbiAgICAgIHJldHVybiBcImJsb2NrXCI7XG4gICAgfSBlbHNlIHtcbiAgICAgIHJldHVybiBzdGF0ZXMudG9wKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICAgIH1cbiAgfTtcblxuICBzdGF0ZXMubWF5YmVwcm9wID0gZnVuY3Rpb24odHlwZSwgc3RyZWFtLCBzdGF0ZSkge1xuICAgIGlmICh0eXBlID09IFwiOlwiKSByZXR1cm4gcHVzaENvbnRleHQoc3RhdGUsIHN0cmVhbSwgXCJwcm9wXCIpO1xuICAgIHJldHVybiBwYXNzKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICB9O1xuXG4gIHN0YXRlcy5wcm9wID0gZnVuY3Rpb24odHlwZSwgc3RyZWFtLCBzdGF0ZSkge1xuICAgIGlmICh0eXBlID09IFwiO1wiKSByZXR1cm4gcG9wQ29udGV4dChzdGF0ZSk7XG4gICAgaWYgKHR5cGUgPT0gXCJ7XCIgJiYgYWxsb3dOZXN0ZWQpIHJldHVybiBwdXNoQ29udGV4dChzdGF0ZSwgc3RyZWFtLCBcInByb3BCbG9ja1wiKTtcbiAgICBpZiAodHlwZSA9PSBcIn1cIiB8fCB0eXBlID09IFwie1wiKSByZXR1cm4gcG9wQW5kUGFzcyh0eXBlLCBzdHJlYW0sIHN0YXRlKTtcbiAgICBpZiAodHlwZSA9PSBcIihcIikgcmV0dXJuIHB1c2hDb250ZXh0KHN0YXRlLCBzdHJlYW0sIFwicGFyZW5zXCIpO1xuXG4gICAgaWYgKHR5cGUgPT0gXCJoYXNoXCIgJiYgIS9eIyhbMC05YS1mQS1mXXszLDR9fFswLTlhLWZBLWZdezZ9fFswLTlhLWZBLWZdezh9KSQvLnRlc3Qoc3RyZWFtLmN1cnJlbnQoKSkpIHtcbiAgICAgIG92ZXJyaWRlICs9IFwiIGVycm9yXCI7XG4gICAgfSBlbHNlIGlmICh0eXBlID09IFwid29yZFwiKSB7XG4gICAgICB3b3JkQXNWYWx1ZShzdHJlYW0pO1xuICAgIH0gZWxzZSBpZiAodHlwZSA9PSBcImludGVycG9sYXRpb25cIikge1xuICAgICAgcmV0dXJuIHB1c2hDb250ZXh0KHN0YXRlLCBzdHJlYW0sIFwiaW50ZXJwb2xhdGlvblwiKTtcbiAgICB9XG4gICAgcmV0dXJuIFwicHJvcFwiO1xuICB9O1xuXG4gIHN0YXRlcy5wcm9wQmxvY2sgPSBmdW5jdGlvbih0eXBlLCBfc3RyZWFtLCBzdGF0ZSkge1xuICAgIGlmICh0eXBlID09IFwifVwiKSByZXR1cm4gcG9wQ29udGV4dChzdGF0ZSk7XG4gICAgaWYgKHR5cGUgPT0gXCJ3b3JkXCIpIHsgb3ZlcnJpZGUgPSBcInByb3BlcnR5XCI7IHJldHVybiBcIm1heWJlcHJvcFwiOyB9XG4gICAgcmV0dXJuIHN0YXRlLmNvbnRleHQudHlwZTtcbiAgfTtcblxuICBzdGF0ZXMucGFyZW5zID0gZnVuY3Rpb24odHlwZSwgc3RyZWFtLCBzdGF0ZSkge1xuICAgIGlmICh0eXBlID09IFwie1wiIHx8IHR5cGUgPT0gXCJ9XCIpIHJldHVybiBwb3BBbmRQYXNzKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICAgIGlmICh0eXBlID09IFwiKVwiKSByZXR1cm4gcG9wQ29udGV4dChzdGF0ZSk7XG4gICAgaWYgKHR5cGUgPT0gXCIoXCIpIHJldHVybiBwdXNoQ29udGV4dChzdGF0ZSwgc3RyZWFtLCBcInBhcmVuc1wiKTtcbiAgICBpZiAodHlwZSA9PSBcImludGVycG9sYXRpb25cIikgcmV0dXJuIHB1c2hDb250ZXh0KHN0YXRlLCBzdHJlYW0sIFwiaW50ZXJwb2xhdGlvblwiKTtcbiAgICBpZiAodHlwZSA9PSBcIndvcmRcIikgd29yZEFzVmFsdWUoc3RyZWFtKTtcbiAgICByZXR1cm4gXCJwYXJlbnNcIjtcbiAgfTtcblxuICBzdGF0ZXMucHNldWRvID0gZnVuY3Rpb24odHlwZSwgc3RyZWFtLCBzdGF0ZSkge1xuICAgIGlmICh0eXBlID09IFwibWV0YVwiKSByZXR1cm4gXCJwc2V1ZG9cIjtcblxuICAgIGlmICh0eXBlID09IFwid29yZFwiKSB7XG4gICAgICBvdmVycmlkZSA9IFwidmFyaWFibGUtM1wiO1xuICAgICAgcmV0dXJuIHN0YXRlLmNvbnRleHQudHlwZTtcbiAgICB9XG4gICAgcmV0dXJuIHBhc3ModHlwZSwgc3RyZWFtLCBzdGF0ZSk7XG4gIH07XG5cbiAgc3RhdGVzLmRvY3VtZW50VHlwZXMgPSBmdW5jdGlvbih0eXBlLCBzdHJlYW0sIHN0YXRlKSB7XG4gICAgaWYgKHR5cGUgPT0gXCJ3b3JkXCIgJiYgZG9jdW1lbnRUeXBlcy5oYXNPd25Qcm9wZXJ0eShzdHJlYW0uY3VycmVudCgpKSkge1xuICAgICAgb3ZlcnJpZGUgPSBcInRhZ1wiO1xuICAgICAgcmV0dXJuIHN0YXRlLmNvbnRleHQudHlwZTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHN0YXRlcy5hdEJsb2NrKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICAgIH1cbiAgfTtcblxuICBzdGF0ZXMuYXRCbG9jayA9IGZ1bmN0aW9uKHR5cGUsIHN0cmVhbSwgc3RhdGUpIHtcbiAgICBpZiAodHlwZSA9PSBcIihcIikgcmV0dXJuIHB1c2hDb250ZXh0KHN0YXRlLCBzdHJlYW0sIFwiYXRCbG9ja19wYXJlbnNcIik7XG4gICAgaWYgKHR5cGUgPT0gXCJ9XCIgfHwgdHlwZSA9PSBcIjtcIikgcmV0dXJuIHBvcEFuZFBhc3ModHlwZSwgc3RyZWFtLCBzdGF0ZSk7XG4gICAgaWYgKHR5cGUgPT0gXCJ7XCIpIHJldHVybiBwb3BDb250ZXh0KHN0YXRlKSAmJiBwdXNoQ29udGV4dChzdGF0ZSwgc3RyZWFtLCBhbGxvd05lc3RlZCA/IFwiYmxvY2tcIiA6IFwidG9wXCIpO1xuXG4gICAgaWYgKHR5cGUgPT0gXCJpbnRlcnBvbGF0aW9uXCIpIHJldHVybiBwdXNoQ29udGV4dChzdGF0ZSwgc3RyZWFtLCBcImludGVycG9sYXRpb25cIik7XG5cbiAgICBpZiAodHlwZSA9PSBcIndvcmRcIikge1xuICAgICAgdmFyIHdvcmQgPSBzdHJlYW0uY3VycmVudCgpLnRvTG93ZXJDYXNlKCk7XG4gICAgICBpZiAod29yZCA9PSBcIm9ubHlcIiB8fCB3b3JkID09IFwibm90XCIgfHwgd29yZCA9PSBcImFuZFwiIHx8IHdvcmQgPT0gXCJvclwiKVxuICAgICAgICBvdmVycmlkZSA9IFwia2V5d29yZFwiO1xuICAgICAgZWxzZSBpZiAobWVkaWFUeXBlcy5oYXNPd25Qcm9wZXJ0eSh3b3JkKSlcbiAgICAgICAgb3ZlcnJpZGUgPSBcImF0dHJpYnV0ZVwiO1xuICAgICAgZWxzZSBpZiAobWVkaWFGZWF0dXJlcy5oYXNPd25Qcm9wZXJ0eSh3b3JkKSlcbiAgICAgICAgb3ZlcnJpZGUgPSBcInByb3BlcnR5XCI7XG4gICAgICBlbHNlIGlmIChtZWRpYVZhbHVlS2V5d29yZHMuaGFzT3duUHJvcGVydHkod29yZCkpXG4gICAgICAgIG92ZXJyaWRlID0gXCJrZXl3b3JkXCI7XG4gICAgICBlbHNlIGlmIChwcm9wZXJ0eUtleXdvcmRzLmhhc093blByb3BlcnR5KHdvcmQpKVxuICAgICAgICBvdmVycmlkZSA9IFwicHJvcGVydHlcIjtcbiAgICAgIGVsc2UgaWYgKG5vblN0YW5kYXJkUHJvcGVydHlLZXl3b3Jkcy5oYXNPd25Qcm9wZXJ0eSh3b3JkKSlcbiAgICAgICAgb3ZlcnJpZGUgPSBcInN0cmluZy0yXCI7XG4gICAgICBlbHNlIGlmICh2YWx1ZUtleXdvcmRzLmhhc093blByb3BlcnR5KHdvcmQpKVxuICAgICAgICBvdmVycmlkZSA9IFwiYXRvbVwiO1xuICAgICAgZWxzZSBpZiAoY29sb3JLZXl3b3Jkcy5oYXNPd25Qcm9wZXJ0eSh3b3JkKSlcbiAgICAgICAgb3ZlcnJpZGUgPSBcImtleXdvcmRcIjtcbiAgICAgIGVsc2VcbiAgICAgICAgb3ZlcnJpZGUgPSBcImVycm9yXCI7XG4gICAgfVxuICAgIHJldHVybiBzdGF0ZS5jb250ZXh0LnR5cGU7XG4gIH07XG5cbiAgc3RhdGVzLmF0Q29tcG9uZW50QmxvY2sgPSBmdW5jdGlvbih0eXBlLCBzdHJlYW0sIHN0YXRlKSB7XG4gICAgaWYgKHR5cGUgPT0gXCJ9XCIpXG4gICAgICByZXR1cm4gcG9wQW5kUGFzcyh0eXBlLCBzdHJlYW0sIHN0YXRlKTtcbiAgICBpZiAodHlwZSA9PSBcIntcIilcbiAgICAgIHJldHVybiBwb3BDb250ZXh0KHN0YXRlKSAmJiBwdXNoQ29udGV4dChzdGF0ZSwgc3RyZWFtLCBhbGxvd05lc3RlZCA/IFwiYmxvY2tcIiA6IFwidG9wXCIsIGZhbHNlKTtcbiAgICBpZiAodHlwZSA9PSBcIndvcmRcIilcbiAgICAgIG92ZXJyaWRlID0gXCJlcnJvclwiO1xuICAgIHJldHVybiBzdGF0ZS5jb250ZXh0LnR5cGU7XG4gIH07XG5cbiAgc3RhdGVzLmF0QmxvY2tfcGFyZW5zID0gZnVuY3Rpb24odHlwZSwgc3RyZWFtLCBzdGF0ZSkge1xuICAgIGlmICh0eXBlID09IFwiKVwiKSByZXR1cm4gcG9wQ29udGV4dChzdGF0ZSk7XG4gICAgaWYgKHR5cGUgPT0gXCJ7XCIgfHwgdHlwZSA9PSBcIn1cIikgcmV0dXJuIHBvcEFuZFBhc3ModHlwZSwgc3RyZWFtLCBzdGF0ZSwgMik7XG4gICAgcmV0dXJuIHN0YXRlcy5hdEJsb2NrKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICB9O1xuXG4gIHN0YXRlcy5yZXN0cmljdGVkX2F0QmxvY2tfYmVmb3JlID0gZnVuY3Rpb24odHlwZSwgc3RyZWFtLCBzdGF0ZSkge1xuICAgIGlmICh0eXBlID09IFwie1wiKVxuICAgICAgcmV0dXJuIHB1c2hDb250ZXh0KHN0YXRlLCBzdHJlYW0sIFwicmVzdHJpY3RlZF9hdEJsb2NrXCIpO1xuICAgIGlmICh0eXBlID09IFwid29yZFwiICYmIHN0YXRlLnN0YXRlQXJnID09IFwiQGNvdW50ZXItc3R5bGVcIikge1xuICAgICAgb3ZlcnJpZGUgPSBcInZhcmlhYmxlXCI7XG4gICAgICByZXR1cm4gXCJyZXN0cmljdGVkX2F0QmxvY2tfYmVmb3JlXCI7XG4gICAgfVxuICAgIHJldHVybiBwYXNzKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICB9O1xuXG4gIHN0YXRlcy5yZXN0cmljdGVkX2F0QmxvY2sgPSBmdW5jdGlvbih0eXBlLCBzdHJlYW0sIHN0YXRlKSB7XG4gICAgaWYgKHR5cGUgPT0gXCJ9XCIpIHtcbiAgICAgIHN0YXRlLnN0YXRlQXJnID0gbnVsbDtcbiAgICAgIHJldHVybiBwb3BDb250ZXh0KHN0YXRlKTtcbiAgICB9XG4gICAgaWYgKHR5cGUgPT0gXCJ3b3JkXCIpIHtcbiAgICAgIGlmICgoc3RhdGUuc3RhdGVBcmcgPT0gXCJAZm9udC1mYWNlXCIgJiYgIWZvbnRQcm9wZXJ0aWVzLmhhc093blByb3BlcnR5KHN0cmVhbS5jdXJyZW50KCkudG9Mb3dlckNhc2UoKSkpIHx8XG4gICAgICAgICAgKHN0YXRlLnN0YXRlQXJnID09IFwiQGNvdW50ZXItc3R5bGVcIiAmJiAhY291bnRlckRlc2NyaXB0b3JzLmhhc093blByb3BlcnR5KHN0cmVhbS5jdXJyZW50KCkudG9Mb3dlckNhc2UoKSkpKVxuICAgICAgICBvdmVycmlkZSA9IFwiZXJyb3JcIjtcbiAgICAgIGVsc2VcbiAgICAgICAgb3ZlcnJpZGUgPSBcInByb3BlcnR5XCI7XG4gICAgICByZXR1cm4gXCJtYXliZXByb3BcIjtcbiAgICB9XG4gICAgcmV0dXJuIFwicmVzdHJpY3RlZF9hdEJsb2NrXCI7XG4gIH07XG5cbiAgc3RhdGVzLmtleWZyYW1lcyA9IGZ1bmN0aW9uKHR5cGUsIHN0cmVhbSwgc3RhdGUpIHtcbiAgICBpZiAodHlwZSA9PSBcIndvcmRcIikgeyBvdmVycmlkZSA9IFwidmFyaWFibGVcIjsgcmV0dXJuIFwia2V5ZnJhbWVzXCI7IH1cbiAgICBpZiAodHlwZSA9PSBcIntcIikgcmV0dXJuIHB1c2hDb250ZXh0KHN0YXRlLCBzdHJlYW0sIFwidG9wXCIpO1xuICAgIHJldHVybiBwYXNzKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICB9O1xuXG4gIHN0YXRlcy5hdCA9IGZ1bmN0aW9uKHR5cGUsIHN0cmVhbSwgc3RhdGUpIHtcbiAgICBpZiAodHlwZSA9PSBcIjtcIikgcmV0dXJuIHBvcENvbnRleHQoc3RhdGUpO1xuICAgIGlmICh0eXBlID09IFwie1wiIHx8IHR5cGUgPT0gXCJ9XCIpIHJldHVybiBwb3BBbmRQYXNzKHR5cGUsIHN0cmVhbSwgc3RhdGUpO1xuICAgIGlmICh0eXBlID09IFwid29yZFwiKSBvdmVycmlkZSA9IFwidGFnXCI7XG4gICAgZWxzZSBpZiAodHlwZSA9PSBcImhhc2hcIikgb3ZlcnJpZGUgPSBcImJ1aWx0aW5cIjtcbiAgICByZXR1cm4gXCJhdFwiO1xuICB9O1xuXG4gIHN0YXRlcy5pbnRlcnBvbGF0aW9uID0gZnVuY3Rpb24odHlwZSwgc3RyZWFtLCBzdGF0ZSkge1xuICAgIGlmICh0eXBlID09IFwifVwiKSByZXR1cm4gcG9wQ29udGV4dChzdGF0ZSk7XG4gICAgaWYgKHR5cGUgPT0gXCJ7XCIgfHwgdHlwZSA9PSBcIjtcIikgcmV0dXJuIHBvcEFuZFBhc3ModHlwZSwgc3RyZWFtLCBzdGF0ZSk7XG4gICAgaWYgKHR5cGUgPT0gXCJ3b3JkXCIpIG92ZXJyaWRlID0gXCJ2YXJpYWJsZVwiO1xuICAgIGVsc2UgaWYgKHR5cGUgIT0gXCJ2YXJpYWJsZVwiICYmIHR5cGUgIT0gXCIoXCIgJiYgdHlwZSAhPSBcIilcIikgb3ZlcnJpZGUgPSBcImVycm9yXCI7XG4gICAgcmV0dXJuIFwiaW50ZXJwb2xhdGlvblwiO1xuICB9O1xuXG4gIHJldHVybiB7XG4gICAgc3RhcnRTdGF0ZTogZnVuY3Rpb24oYmFzZSkge1xuICAgICAgcmV0dXJuIHt0b2tlbml6ZTogbnVsbCxcbiAgICAgICAgICAgICAgc3RhdGU6IGlubGluZSA/IFwiYmxvY2tcIiA6IFwidG9wXCIsXG4gICAgICAgICAgICAgIHN0YXRlQXJnOiBudWxsLFxuICAgICAgICAgICAgICBjb250ZXh0OiBuZXcgQ29udGV4dChpbmxpbmUgPyBcImJsb2NrXCIgOiBcInRvcFwiLCBiYXNlIHx8IDAsIG51bGwpfTtcbiAgICB9LFxuXG4gICAgdG9rZW46IGZ1bmN0aW9uKHN0cmVhbSwgc3RhdGUpIHtcbiAgICAgIGlmICghc3RhdGUudG9rZW5pemUgJiYgc3RyZWFtLmVhdFNwYWNlKCkpIHJldHVybiBudWxsO1xuICAgICAgdmFyIHN0eWxlID0gKHN0YXRlLnRva2VuaXplIHx8IHRva2VuQmFzZSkoc3RyZWFtLCBzdGF0ZSk7XG4gICAgICBpZiAoc3R5bGUgJiYgdHlwZW9mIHN0eWxlID09IFwib2JqZWN0XCIpIHtcbiAgICAgICAgdHlwZSA9IHN0eWxlWzFdO1xuICAgICAgICBzdHlsZSA9IHN0eWxlWzBdO1xuICAgICAgfVxuICAgICAgb3ZlcnJpZGUgPSBzdHlsZTtcbiAgICAgIGlmICh0eXBlICE9IFwiY29tbWVudFwiKVxuICAgICAgICBzdGF0ZS5zdGF0ZSA9IHN0YXRlc1tzdGF0ZS5zdGF0ZV0odHlwZSwgc3RyZWFtLCBzdGF0ZSk7XG4gICAgICByZXR1cm4gb3ZlcnJpZGU7XG4gICAgfSxcblxuICAgIGluZGVudDogZnVuY3Rpb24oc3RhdGUsIHRleHRBZnRlcikge1xuICAgICAgdmFyIGN4ID0gc3RhdGUuY29udGV4dCwgY2ggPSB0ZXh0QWZ0ZXIgJiYgdGV4dEFmdGVyLmNoYXJBdCgwKTtcbiAgICAgIHZhciBpbmRlbnQgPSBjeC5pbmRlbnQ7XG4gICAgICBpZiAoY3gudHlwZSA9PSBcInByb3BcIiAmJiAoY2ggPT0gXCJ9XCIgfHwgY2ggPT0gXCIpXCIpKSBjeCA9IGN4LnByZXY7XG4gICAgICBpZiAoY3gucHJldikge1xuICAgICAgICBpZiAoY2ggPT0gXCJ9XCIgJiYgKGN4LnR5cGUgPT0gXCJibG9ja1wiIHx8IGN4LnR5cGUgPT0gXCJ0b3BcIiB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICBjeC50eXBlID09IFwiaW50ZXJwb2xhdGlvblwiIHx8IGN4LnR5cGUgPT0gXCJyZXN0cmljdGVkX2F0QmxvY2tcIikpIHtcbiAgICAgICAgICAvLyBSZXN1bWUgaW5kZW50YXRpb24gZnJvbSBwYXJlbnQgY29udGV4dC5cbiAgICAgICAgICBjeCA9IGN4LnByZXY7XG4gICAgICAgICAgaW5kZW50ID0gY3guaW5kZW50O1xuICAgICAgICB9IGVsc2UgaWYgKGNoID09IFwiKVwiICYmIChjeC50eXBlID09IFwicGFyZW5zXCIgfHwgY3gudHlwZSA9PSBcImF0QmxvY2tfcGFyZW5zXCIpIHx8XG4gICAgICAgICAgICBjaCA9PSBcIntcIiAmJiAoY3gudHlwZSA9PSBcImF0XCIgfHwgY3gudHlwZSA9PSBcImF0QmxvY2tcIikpIHtcbiAgICAgICAgICAvLyBEZWRlbnQgcmVsYXRpdmUgdG8gY3VycmVudCBjb250ZXh0LlxuICAgICAgICAgIGluZGVudCA9IE1hdGgubWF4KDAsIGN4LmluZGVudCAtIGluZGVudFVuaXQpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICByZXR1cm4gaW5kZW50O1xuICAgIH0sXG5cbiAgICBlbGVjdHJpY0NoYXJzOiBcIn1cIixcbiAgICBibG9ja0NvbW1lbnRTdGFydDogXCIvKlwiLFxuICAgIGJsb2NrQ29tbWVudEVuZDogXCIqL1wiLFxuICAgIGJsb2NrQ29tbWVudENvbnRpbnVlOiBcIiAqIFwiLFxuICAgIGxpbmVDb21tZW50OiBsaW5lQ29tbWVudCxcbiAgICBmb2xkOiBcImJyYWNlXCJcbiAgfTtcbn0pO1xuXG4gIGZ1bmN0aW9uIGtleVNldChhcnJheSkge1xuICAgIHZhciBrZXlzID0ge307XG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7ICsraSkge1xuICAgICAga2V5c1thcnJheVtpXS50b0xvd2VyQ2FzZSgpXSA9IHRydWU7XG4gICAgfVxuICAgIHJldHVybiBrZXlzO1xuICB9XG5cbiAgdmFyIGRvY3VtZW50VHlwZXNfID0gW1xuICAgIFwiZG9tYWluXCIsIFwicmVnZXhwXCIsIFwidXJsXCIsIFwidXJsLXByZWZpeFwiXG4gIF0sIGRvY3VtZW50VHlwZXMgPSBrZXlTZXQoZG9jdW1lbnRUeXBlc18pO1xuXG4gIHZhciBtZWRpYVR5cGVzXyA9IFtcbiAgICBcImFsbFwiLCBcImF1cmFsXCIsIFwiYnJhaWxsZVwiLCBcImhhbmRoZWxkXCIsIFwicHJpbnRcIiwgXCJwcm9qZWN0aW9uXCIsIFwic2NyZWVuXCIsXG4gICAgXCJ0dHlcIiwgXCJ0dlwiLCBcImVtYm9zc2VkXCJcbiAgXSwgbWVkaWFUeXBlcyA9IGtleVNldChtZWRpYVR5cGVzXyk7XG5cbiAgdmFyIG1lZGlhRmVhdHVyZXNfID0gW1xuICAgIFwid2lkdGhcIiwgXCJtaW4td2lkdGhcIiwgXCJtYXgtd2lkdGhcIiwgXCJoZWlnaHRcIiwgXCJtaW4taGVpZ2h0XCIsIFwibWF4LWhlaWdodFwiLFxuICAgIFwiZGV2aWNlLXdpZHRoXCIsIFwibWluLWRldmljZS13aWR0aFwiLCBcIm1heC1kZXZpY2Utd2lkdGhcIiwgXCJkZXZpY2UtaGVpZ2h0XCIsXG4gICAgXCJtaW4tZGV2aWNlLWhlaWdodFwiLCBcIm1heC1kZXZpY2UtaGVpZ2h0XCIsIFwiYXNwZWN0LXJhdGlvXCIsXG4gICAgXCJtaW4tYXNwZWN0LXJhdGlvXCIsIFwibWF4LWFzcGVjdC1yYXRpb1wiLCBcImRldmljZS1hc3BlY3QtcmF0aW9cIixcbiAgICBcIm1pbi1kZXZpY2UtYXNwZWN0LXJhdGlvXCIsIFwibWF4LWRldmljZS1hc3BlY3QtcmF0aW9cIiwgXCJjb2xvclwiLCBcIm1pbi1jb2xvclwiLFxuICAgIFwibWF4LWNvbG9yXCIsIFwiY29sb3ItaW5kZXhcIiwgXCJtaW4tY29sb3ItaW5kZXhcIiwgXCJtYXgtY29sb3ItaW5kZXhcIixcbiAgICBcIm1vbm9jaHJvbWVcIiwgXCJtaW4tbW9ub2Nocm9tZVwiLCBcIm1heC1tb25vY2hyb21lXCIsIFwicmVzb2x1dGlvblwiLFxuICAgIFwibWluLXJlc29sdXRpb25cIiwgXCJtYXgtcmVzb2x1dGlvblwiLCBcInNjYW5cIiwgXCJncmlkXCIsIFwib3JpZW50YXRpb25cIixcbiAgICBcImRldmljZS1waXhlbC1yYXRpb1wiLCBcIm1pbi1kZXZpY2UtcGl4ZWwtcmF0aW9cIiwgXCJtYXgtZGV2aWNlLXBpeGVsLXJhdGlvXCIsXG4gICAgXCJwb2ludGVyXCIsIFwiYW55LXBvaW50ZXJcIiwgXCJob3ZlclwiLCBcImFueS1ob3ZlclwiXG4gIF0sIG1lZGlhRmVhdHVyZXMgPSBrZXlTZXQobWVkaWFGZWF0dXJlc18pO1xuXG4gIHZhciBtZWRpYVZhbHVlS2V5d29yZHNfID0gW1xuICAgIFwibGFuZHNjYXBlXCIsIFwicG9ydHJhaXRcIiwgXCJub25lXCIsIFwiY29hcnNlXCIsIFwiZmluZVwiLCBcIm9uLWRlbWFuZFwiLCBcImhvdmVyXCIsXG4gICAgXCJpbnRlcmxhY2VcIiwgXCJwcm9ncmVzc2l2ZVwiXG4gIF0sIG1lZGlhVmFsdWVLZXl3b3JkcyA9IGtleVNldChtZWRpYVZhbHVlS2V5d29yZHNfKTtcblxuICB2YXIgcHJvcGVydHlLZXl3b3Jkc18gPSBbXG4gICAgXCJhbGlnbi1jb250ZW50XCIsIFwiYWxpZ24taXRlbXNcIiwgXCJhbGlnbi1zZWxmXCIsIFwiYWxpZ25tZW50LWFkanVzdFwiLFxuICAgIFwiYWxpZ25tZW50LWJhc2VsaW5lXCIsIFwiYW5jaG9yLXBvaW50XCIsIFwiYW5pbWF0aW9uXCIsIFwiYW5pbWF0aW9uLWRlbGF5XCIsXG4gICAgXCJhbmltYXRpb24tZGlyZWN0aW9uXCIsIFwiYW5pbWF0aW9uLWR1cmF0aW9uXCIsIFwiYW5pbWF0aW9uLWZpbGwtbW9kZVwiLFxuICAgIFwiYW5pbWF0aW9uLWl0ZXJhdGlvbi1jb3VudFwiLCBcImFuaW1hdGlvbi1uYW1lXCIsIFwiYW5pbWF0aW9uLXBsYXktc3RhdGVcIixcbiAgICBcImFuaW1hdGlvbi10aW1pbmctZnVuY3Rpb25cIiwgXCJhcHBlYXJhbmNlXCIsIFwiYXppbXV0aFwiLCBcImJhY2tmYWNlLXZpc2liaWxpdHlcIixcbiAgICBcImJhY2tncm91bmRcIiwgXCJiYWNrZ3JvdW5kLWF0dGFjaG1lbnRcIiwgXCJiYWNrZ3JvdW5kLWJsZW5kLW1vZGVcIiwgXCJiYWNrZ3JvdW5kLWNsaXBcIixcbiAgICBcImJhY2tncm91bmQtY29sb3JcIiwgXCJiYWNrZ3JvdW5kLWltYWdlXCIsIFwiYmFja2dyb3VuZC1vcmlnaW5cIiwgXCJiYWNrZ3JvdW5kLXBvc2l0aW9uXCIsXG4gICAgXCJiYWNrZ3JvdW5kLXJlcGVhdFwiLCBcImJhY2tncm91bmQtc2l6ZVwiLCBcImJhc2VsaW5lLXNoaWZ0XCIsIFwiYmluZGluZ1wiLFxuICAgIFwiYmxlZWRcIiwgXCJib29rbWFyay1sYWJlbFwiLCBcImJvb2ttYXJrLWxldmVsXCIsIFwiYm9va21hcmstc3RhdGVcIixcbiAgICBcImJvb2ttYXJrLXRhcmdldFwiLCBcImJvcmRlclwiLCBcImJvcmRlci1ib3R0b21cIiwgXCJib3JkZXItYm90dG9tLWNvbG9yXCIsXG4gICAgXCJib3JkZXItYm90dG9tLWxlZnQtcmFkaXVzXCIsIFwiYm9yZGVyLWJvdHRvbS1yaWdodC1yYWRpdXNcIixcbiAgICBcImJvcmRlci1ib3R0b20tc3R5bGVcIiwgXCJib3JkZXItYm90dG9tLXdpZHRoXCIsIFwiYm9yZGVyLWNvbGxhcHNlXCIsXG4gICAgXCJib3JkZXItY29sb3JcIiwgXCJib3JkZXItaW1hZ2VcIiwgXCJib3JkZXItaW1hZ2Utb3V0c2V0XCIsXG4gICAgXCJib3JkZXItaW1hZ2UtcmVwZWF0XCIsIFwiYm9yZGVyLWltYWdlLXNsaWNlXCIsIFwiYm9yZGVyLWltYWdlLXNvdXJjZVwiLFxuICAgIFwiYm9yZGVyLWltYWdlLXdpZHRoXCIsIFwiYm9yZGVyLWxlZnRcIiwgXCJib3JkZXItbGVmdC1jb2xvclwiLFxuICAgIFwiYm9yZGVyLWxlZnQtc3R5bGVcIiwgXCJib3JkZXItbGVmdC13aWR0aFwiLCBcImJvcmRlci1yYWRpdXNcIiwgXCJib3JkZXItcmlnaHRcIixcbiAgICBcImJvcmRlci1yaWdodC1jb2xvclwiLCBcImJvcmRlci1yaWdodC1zdHlsZVwiLCBcImJvcmRlci1yaWdodC13aWR0aFwiLFxuICAgIFwiYm9yZGVyLXNwYWNpbmdcIiwgXCJib3JkZXItc3R5bGVcIiwgXCJib3JkZXItdG9wXCIsIFwiYm9yZGVyLXRvcC1jb2xvclwiLFxuICAgIFwiYm9yZGVyLXRvcC1sZWZ0LXJhZGl1c1wiLCBcImJvcmRlci10b3AtcmlnaHQtcmFkaXVzXCIsIFwiYm9yZGVyLXRvcC1zdHlsZVwiLFxuICAgIFwiYm9yZGVyLXRvcC13aWR0aFwiLCBcImJvcmRlci13aWR0aFwiLCBcImJvdHRvbVwiLCBcImJveC1kZWNvcmF0aW9uLWJyZWFrXCIsXG4gICAgXCJib3gtc2hhZG93XCIsIFwiYm94LXNpemluZ1wiLCBcImJyZWFrLWFmdGVyXCIsIFwiYnJlYWstYmVmb3JlXCIsIFwiYnJlYWstaW5zaWRlXCIsXG4gICAgXCJjYXB0aW9uLXNpZGVcIiwgXCJjYXJldC1jb2xvclwiLCBcImNsZWFyXCIsIFwiY2xpcFwiLCBcImNvbG9yXCIsIFwiY29sb3ItcHJvZmlsZVwiLCBcImNvbHVtbi1jb3VudFwiLFxuICAgIFwiY29sdW1uLWZpbGxcIiwgXCJjb2x1bW4tZ2FwXCIsIFwiY29sdW1uLXJ1bGVcIiwgXCJjb2x1bW4tcnVsZS1jb2xvclwiLFxuICAgIFwiY29sdW1uLXJ1bGUtc3R5bGVcIiwgXCJjb2x1bW4tcnVsZS13aWR0aFwiLCBcImNvbHVtbi1zcGFuXCIsIFwiY29sdW1uLXdpZHRoXCIsXG4gICAgXCJjb2x1bW5zXCIsIFwiY29udGVudFwiLCBcImNvdW50ZXItaW5jcmVtZW50XCIsIFwiY291bnRlci1yZXNldFwiLCBcImNyb3BcIiwgXCJjdWVcIixcbiAgICBcImN1ZS1hZnRlclwiLCBcImN1ZS1iZWZvcmVcIiwgXCJjdXJzb3JcIiwgXCJkaXJlY3Rpb25cIiwgXCJkaXNwbGF5XCIsXG4gICAgXCJkb21pbmFudC1iYXNlbGluZVwiLCBcImRyb3AtaW5pdGlhbC1hZnRlci1hZGp1c3RcIixcbiAgICBcImRyb3AtaW5pdGlhbC1hZnRlci1hbGlnblwiLCBcImRyb3AtaW5pdGlhbC1iZWZvcmUtYWRqdXN0XCIsXG4gICAgXCJkcm9wLWluaXRpYWwtYmVmb3JlLWFsaWduXCIsIFwiZHJvcC1pbml0aWFsLXNpemVcIiwgXCJkcm9wLWluaXRpYWwtdmFsdWVcIixcbiAgICBcImVsZXZhdGlvblwiLCBcImVtcHR5LWNlbGxzXCIsIFwiZml0XCIsIFwiZml0LXBvc2l0aW9uXCIsIFwiZmxleFwiLCBcImZsZXgtYmFzaXNcIixcbiAgICBcImZsZXgtZGlyZWN0aW9uXCIsIFwiZmxleC1mbG93XCIsIFwiZmxleC1ncm93XCIsIFwiZmxleC1zaHJpbmtcIiwgXCJmbGV4LXdyYXBcIixcbiAgICBcImZsb2F0XCIsIFwiZmxvYXQtb2Zmc2V0XCIsIFwiZmxvdy1mcm9tXCIsIFwiZmxvdy1pbnRvXCIsIFwiZm9udFwiLCBcImZvbnQtZmVhdHVyZS1zZXR0aW5nc1wiLFxuICAgIFwiZm9udC1mYW1pbHlcIiwgXCJmb250LWtlcm5pbmdcIiwgXCJmb250LWxhbmd1YWdlLW92ZXJyaWRlXCIsIFwiZm9udC1zaXplXCIsIFwiZm9udC1zaXplLWFkanVzdFwiLFxuICAgIFwiZm9udC1zdHJldGNoXCIsIFwiZm9udC1zdHlsZVwiLCBcImZvbnQtc3ludGhlc2lzXCIsIFwiZm9udC12YXJpYW50XCIsXG4gICAgXCJmb250LXZhcmlhbnQtYWx0ZXJuYXRlc1wiLCBcImZvbnQtdmFyaWFudC1jYXBzXCIsIFwiZm9udC12YXJpYW50LWVhc3QtYXNpYW5cIixcbiAgICBcImZvbnQtdmFyaWFudC1saWdhdHVyZXNcIiwgXCJmb250LXZhcmlhbnQtbnVtZXJpY1wiLCBcImZvbnQtdmFyaWFudC1wb3NpdGlvblwiLFxuICAgIFwiZm9udC13ZWlnaHRcIiwgXCJncmlkXCIsIFwiZ3JpZC1hcmVhXCIsIFwiZ3JpZC1hdXRvLWNvbHVtbnNcIiwgXCJncmlkLWF1dG8tZmxvd1wiLFxuICAgIFwiZ3JpZC1hdXRvLXJvd3NcIiwgXCJncmlkLWNvbHVtblwiLCBcImdyaWQtY29sdW1uLWVuZFwiLCBcImdyaWQtY29sdW1uLWdhcFwiLFxuICAgIFwiZ3JpZC1jb2x1bW4tc3RhcnRcIiwgXCJncmlkLWdhcFwiLCBcImdyaWQtcm93XCIsIFwiZ3JpZC1yb3ctZW5kXCIsIFwiZ3JpZC1yb3ctZ2FwXCIsXG4gICAgXCJncmlkLXJvdy1zdGFydFwiLCBcImdyaWQtdGVtcGxhdGVcIiwgXCJncmlkLXRlbXBsYXRlLWFyZWFzXCIsIFwiZ3JpZC10ZW1wbGF0ZS1jb2x1bW5zXCIsXG4gICAgXCJncmlkLXRlbXBsYXRlLXJvd3NcIiwgXCJoYW5naW5nLXB1bmN0dWF0aW9uXCIsIFwiaGVpZ2h0XCIsIFwiaHlwaGVuc1wiLFxuICAgIFwiaWNvblwiLCBcImltYWdlLW9yaWVudGF0aW9uXCIsIFwiaW1hZ2UtcmVuZGVyaW5nXCIsIFwiaW1hZ2UtcmVzb2x1dGlvblwiLFxuICAgIFwiaW5saW5lLWJveC1hbGlnblwiLCBcImp1c3RpZnktY29udGVudFwiLCBcImp1c3RpZnktaXRlbXNcIiwgXCJqdXN0aWZ5LXNlbGZcIiwgXCJsZWZ0XCIsIFwibGV0dGVyLXNwYWNpbmdcIixcbiAgICBcImxpbmUtYnJlYWtcIiwgXCJsaW5lLWhlaWdodFwiLCBcImxpbmUtc3RhY2tpbmdcIiwgXCJsaW5lLXN0YWNraW5nLXJ1YnlcIixcbiAgICBcImxpbmUtc3RhY2tpbmctc2hpZnRcIiwgXCJsaW5lLXN0YWNraW5nLXN0cmF0ZWd5XCIsIFwibGlzdC1zdHlsZVwiLFxuICAgIFwibGlzdC1zdHlsZS1pbWFnZVwiLCBcImxpc3Qtc3R5bGUtcG9zaXRpb25cIiwgXCJsaXN0LXN0eWxlLXR5cGVcIiwgXCJtYXJnaW5cIixcbiAgICBcIm1hcmdpbi1ib3R0b21cIiwgXCJtYXJnaW4tbGVmdFwiLCBcIm1hcmdpbi1yaWdodFwiLCBcIm1hcmdpbi10b3BcIixcbiAgICBcIm1hcmtzXCIsIFwibWFycXVlZS1kaXJlY3Rpb25cIiwgXCJtYXJxdWVlLWxvb3BcIixcbiAgICBcIm1hcnF1ZWUtcGxheS1jb3VudFwiLCBcIm1hcnF1ZWUtc3BlZWRcIiwgXCJtYXJxdWVlLXN0eWxlXCIsIFwibWF4LWhlaWdodFwiLFxuICAgIFwibWF4LXdpZHRoXCIsIFwibWluLWhlaWdodFwiLCBcIm1pbi13aWR0aFwiLCBcIm1peC1ibGVuZC1tb2RlXCIsIFwibW92ZS10b1wiLCBcIm5hdi1kb3duXCIsIFwibmF2LWluZGV4XCIsXG4gICAgXCJuYXYtbGVmdFwiLCBcIm5hdi1yaWdodFwiLCBcIm5hdi11cFwiLCBcIm9iamVjdC1maXRcIiwgXCJvYmplY3QtcG9zaXRpb25cIixcbiAgICBcIm9wYWNpdHlcIiwgXCJvcmRlclwiLCBcIm9ycGhhbnNcIiwgXCJvdXRsaW5lXCIsXG4gICAgXCJvdXRsaW5lLWNvbG9yXCIsIFwib3V0bGluZS1vZmZzZXRcIiwgXCJvdXRsaW5lLXN0eWxlXCIsIFwib3V0bGluZS13aWR0aFwiLFxuICAgIFwib3ZlcmZsb3dcIiwgXCJvdmVyZmxvdy1zdHlsZVwiLCBcIm92ZXJmbG93LXdyYXBcIiwgXCJvdmVyZmxvdy14XCIsIFwib3ZlcmZsb3cteVwiLFxuICAgIFwicGFkZGluZ1wiLCBcInBhZGRpbmctYm90dG9tXCIsIFwicGFkZGluZy1sZWZ0XCIsIFwicGFkZGluZy1yaWdodFwiLCBcInBhZGRpbmctdG9wXCIsXG4gICAgXCJwYWdlXCIsIFwicGFnZS1icmVhay1hZnRlclwiLCBcInBhZ2UtYnJlYWstYmVmb3JlXCIsIFwicGFnZS1icmVhay1pbnNpZGVcIixcbiAgICBcInBhZ2UtcG9saWN5XCIsIFwicGF1c2VcIiwgXCJwYXVzZS1hZnRlclwiLCBcInBhdXNlLWJlZm9yZVwiLCBcInBlcnNwZWN0aXZlXCIsXG4gICAgXCJwZXJzcGVjdGl2ZS1vcmlnaW5cIiwgXCJwaXRjaFwiLCBcInBpdGNoLXJhbmdlXCIsIFwicGxhY2UtY29udGVudFwiLCBcInBsYWNlLWl0ZW1zXCIsIFwicGxhY2Utc2VsZlwiLCBcInBsYXktZHVyaW5nXCIsIFwicG9zaXRpb25cIixcbiAgICBcInByZXNlbnRhdGlvbi1sZXZlbFwiLCBcInB1bmN0dWF0aW9uLXRyaW1cIiwgXCJxdW90ZXNcIiwgXCJyZWdpb24tYnJlYWstYWZ0ZXJcIixcbiAgICBcInJlZ2lvbi1icmVhay1iZWZvcmVcIiwgXCJyZWdpb24tYnJlYWstaW5zaWRlXCIsIFwicmVnaW9uLWZyYWdtZW50XCIsXG4gICAgXCJyZW5kZXJpbmctaW50ZW50XCIsIFwicmVzaXplXCIsIFwicmVzdFwiLCBcInJlc3QtYWZ0ZXJcIiwgXCJyZXN0LWJlZm9yZVwiLCBcInJpY2huZXNzXCIsXG4gICAgXCJyaWdodFwiLCBcInJvdGF0aW9uXCIsIFwicm90YXRpb24tcG9pbnRcIiwgXCJydWJ5LWFsaWduXCIsIFwicnVieS1vdmVyaGFuZ1wiLFxuICAgIFwicnVieS1wb3NpdGlvblwiLCBcInJ1Ynktc3BhblwiLCBcInNoYXBlLWltYWdlLXRocmVzaG9sZFwiLCBcInNoYXBlLWluc2lkZVwiLCBcInNoYXBlLW1hcmdpblwiLFxuICAgIFwic2hhcGUtb3V0c2lkZVwiLCBcInNpemVcIiwgXCJzcGVha1wiLCBcInNwZWFrLWFzXCIsIFwic3BlYWstaGVhZGVyXCIsXG4gICAgXCJzcGVhay1udW1lcmFsXCIsIFwic3BlYWstcHVuY3R1YXRpb25cIiwgXCJzcGVlY2gtcmF0ZVwiLCBcInN0cmVzc1wiLCBcInN0cmluZy1zZXRcIixcbiAgICBcInRhYi1zaXplXCIsIFwidGFibGUtbGF5b3V0XCIsIFwidGFyZ2V0XCIsIFwidGFyZ2V0LW5hbWVcIiwgXCJ0YXJnZXQtbmV3XCIsXG4gICAgXCJ0YXJnZXQtcG9zaXRpb25cIiwgXCJ0ZXh0LWFsaWduXCIsIFwidGV4dC1hbGlnbi1sYXN0XCIsIFwidGV4dC1kZWNvcmF0aW9uXCIsXG4gICAgXCJ0ZXh0LWRlY29yYXRpb24tY29sb3JcIiwgXCJ0ZXh0LWRlY29yYXRpb24tbGluZVwiLCBcInRleHQtZGVjb3JhdGlvbi1za2lwXCIsXG4gICAgXCJ0ZXh0LWRlY29yYXRpb24tc3R5bGVcIiwgXCJ0ZXh0LWVtcGhhc2lzXCIsIFwidGV4dC1lbXBoYXNpcy1jb2xvclwiLFxuICAgIFwidGV4dC1lbXBoYXNpcy1wb3NpdGlvblwiLCBcInRleHQtZW1waGFzaXMtc3R5bGVcIiwgXCJ0ZXh0LWhlaWdodFwiLFxuICAgIFwidGV4dC1pbmRlbnRcIiwgXCJ0ZXh0LWp1c3RpZnlcIiwgXCJ0ZXh0LW91dGxpbmVcIiwgXCJ0ZXh0LW92ZXJmbG93XCIsIFwidGV4dC1zaGFkb3dcIixcbiAgICBcInRleHQtc2l6ZS1hZGp1c3RcIiwgXCJ0ZXh0LXNwYWNlLWNvbGxhcHNlXCIsIFwidGV4dC10cmFuc2Zvcm1cIiwgXCJ0ZXh0LXVuZGVybGluZS1wb3NpdGlvblwiLFxuICAgIFwidGV4dC13cmFwXCIsIFwidG9wXCIsIFwidHJhbnNmb3JtXCIsIFwidHJhbnNmb3JtLW9yaWdpblwiLCBcInRyYW5zZm9ybS1zdHlsZVwiLFxuICAgIFwidHJhbnNpdGlvblwiLCBcInRyYW5zaXRpb24tZGVsYXlcIiwgXCJ0cmFuc2l0aW9uLWR1cmF0aW9uXCIsXG4gICAgXCJ0cmFuc2l0aW9uLXByb3BlcnR5XCIsIFwidHJhbnNpdGlvbi10aW1pbmctZnVuY3Rpb25cIiwgXCJ1bmljb2RlLWJpZGlcIixcbiAgICBcInVzZXItc2VsZWN0XCIsIFwidmVydGljYWwtYWxpZ25cIiwgXCJ2aXNpYmlsaXR5XCIsIFwidm9pY2UtYmFsYW5jZVwiLCBcInZvaWNlLWR1cmF0aW9uXCIsXG4gICAgXCJ2b2ljZS1mYW1pbHlcIiwgXCJ2b2ljZS1waXRjaFwiLCBcInZvaWNlLXJhbmdlXCIsIFwidm9pY2UtcmF0ZVwiLCBcInZvaWNlLXN0cmVzc1wiLFxuICAgIFwidm9pY2Utdm9sdW1lXCIsIFwidm9sdW1lXCIsIFwid2hpdGUtc3BhY2VcIiwgXCJ3aWRvd3NcIiwgXCJ3aWR0aFwiLCBcIndpbGwtY2hhbmdlXCIsIFwid29yZC1icmVha1wiLFxuICAgIFwid29yZC1zcGFjaW5nXCIsIFwid29yZC13cmFwXCIsIFwiei1pbmRleFwiLFxuICAgIC8vIFNWRy1zcGVjaWZpY1xuICAgIFwiY2xpcC1wYXRoXCIsIFwiY2xpcC1ydWxlXCIsIFwibWFza1wiLCBcImVuYWJsZS1iYWNrZ3JvdW5kXCIsIFwiZmlsdGVyXCIsIFwiZmxvb2QtY29sb3JcIixcbiAgICBcImZsb29kLW9wYWNpdHlcIiwgXCJsaWdodGluZy1jb2xvclwiLCBcInN0b3AtY29sb3JcIiwgXCJzdG9wLW9wYWNpdHlcIiwgXCJwb2ludGVyLWV2ZW50c1wiLFxuICAgIFwiY29sb3ItaW50ZXJwb2xhdGlvblwiLCBcImNvbG9yLWludGVycG9sYXRpb24tZmlsdGVyc1wiLFxuICAgIFwiY29sb3ItcmVuZGVyaW5nXCIsIFwiZmlsbFwiLCBcImZpbGwtb3BhY2l0eVwiLCBcImZpbGwtcnVsZVwiLCBcImltYWdlLXJlbmRlcmluZ1wiLFxuICAgIFwibWFya2VyXCIsIFwibWFya2VyLWVuZFwiLCBcIm1hcmtlci1taWRcIiwgXCJtYXJrZXItc3RhcnRcIiwgXCJzaGFwZS1yZW5kZXJpbmdcIiwgXCJzdHJva2VcIixcbiAgICBcInN0cm9rZS1kYXNoYXJyYXlcIiwgXCJzdHJva2UtZGFzaG9mZnNldFwiLCBcInN0cm9rZS1saW5lY2FwXCIsIFwic3Ryb2tlLWxpbmVqb2luXCIsXG4gICAgXCJzdHJva2UtbWl0ZXJsaW1pdFwiLCBcInN0cm9rZS1vcGFjaXR5XCIsIFwic3Ryb2tlLXdpZHRoXCIsIFwidGV4dC1yZW5kZXJpbmdcIixcbiAgICBcImJhc2VsaW5lLXNoaWZ0XCIsIFwiZG9taW5hbnQtYmFzZWxpbmVcIiwgXCJnbHlwaC1vcmllbnRhdGlvbi1ob3Jpem9udGFsXCIsXG4gICAgXCJnbHlwaC1vcmllbnRhdGlvbi12ZXJ0aWNhbFwiLCBcInRleHQtYW5jaG9yXCIsIFwid3JpdGluZy1tb2RlXCJcbiAgXSwgcHJvcGVydHlLZXl3b3JkcyA9IGtleVNldChwcm9wZXJ0eUtleXdvcmRzXyk7XG5cbiAgdmFyIG5vblN0YW5kYXJkUHJvcGVydHlLZXl3b3Jkc18gPSBbXG4gICAgXCJzY3JvbGxiYXItYXJyb3ctY29sb3JcIiwgXCJzY3JvbGxiYXItYmFzZS1jb2xvclwiLCBcInNjcm9sbGJhci1kYXJrLXNoYWRvdy1jb2xvclwiLFxuICAgIFwic2Nyb2xsYmFyLWZhY2UtY29sb3JcIiwgXCJzY3JvbGxiYXItaGlnaGxpZ2h0LWNvbG9yXCIsIFwic2Nyb2xsYmFyLXNoYWRvdy1jb2xvclwiLFxuICAgIFwic2Nyb2xsYmFyLTNkLWxpZ2h0LWNvbG9yXCIsIFwic2Nyb2xsYmFyLXRyYWNrLWNvbG9yXCIsIFwic2hhcGUtaW5zaWRlXCIsXG4gICAgXCJzZWFyY2hmaWVsZC1jYW5jZWwtYnV0dG9uXCIsIFwic2VhcmNoZmllbGQtZGVjb3JhdGlvblwiLCBcInNlYXJjaGZpZWxkLXJlc3VsdHMtYnV0dG9uXCIsXG4gICAgXCJzZWFyY2hmaWVsZC1yZXN1bHRzLWRlY29yYXRpb25cIiwgXCJ6b29tXCJcbiAgXSwgbm9uU3RhbmRhcmRQcm9wZXJ0eUtleXdvcmRzID0ga2V5U2V0KG5vblN0YW5kYXJkUHJvcGVydHlLZXl3b3Jkc18pO1xuXG4gIHZhciBmb250UHJvcGVydGllc18gPSBbXG4gICAgXCJmb250LWZhbWlseVwiLCBcInNyY1wiLCBcInVuaWNvZGUtcmFuZ2VcIiwgXCJmb250LXZhcmlhbnRcIiwgXCJmb250LWZlYXR1cmUtc2V0dGluZ3NcIixcbiAgICBcImZvbnQtc3RyZXRjaFwiLCBcImZvbnQtd2VpZ2h0XCIsIFwiZm9udC1zdHlsZVwiXG4gIF0sIGZvbnRQcm9wZXJ0aWVzID0ga2V5U2V0KGZvbnRQcm9wZXJ0aWVzXyk7XG5cbiAgdmFyIGNvdW50ZXJEZXNjcmlwdG9yc18gPSBbXG4gICAgXCJhZGRpdGl2ZS1zeW1ib2xzXCIsIFwiZmFsbGJhY2tcIiwgXCJuZWdhdGl2ZVwiLCBcInBhZFwiLCBcInByZWZpeFwiLCBcInJhbmdlXCIsXG4gICAgXCJzcGVhay1hc1wiLCBcInN1ZmZpeFwiLCBcInN5bWJvbHNcIiwgXCJzeXN0ZW1cIlxuICBdLCBjb3VudGVyRGVzY3JpcHRvcnMgPSBrZXlTZXQoY291bnRlckRlc2NyaXB0b3JzXyk7XG5cbiAgdmFyIGNvbG9yS2V5d29yZHNfID0gW1xuICAgIFwiYWxpY2VibHVlXCIsIFwiYW50aXF1ZXdoaXRlXCIsIFwiYXF1YVwiLCBcImFxdWFtYXJpbmVcIiwgXCJhenVyZVwiLCBcImJlaWdlXCIsXG4gICAgXCJiaXNxdWVcIiwgXCJibGFja1wiLCBcImJsYW5jaGVkYWxtb25kXCIsIFwiYmx1ZVwiLCBcImJsdWV2aW9sZXRcIiwgXCJicm93blwiLFxuICAgIFwiYnVybHl3b29kXCIsIFwiY2FkZXRibHVlXCIsIFwiY2hhcnRyZXVzZVwiLCBcImNob2NvbGF0ZVwiLCBcImNvcmFsXCIsIFwiY29ybmZsb3dlcmJsdWVcIixcbiAgICBcImNvcm5zaWxrXCIsIFwiY3JpbXNvblwiLCBcImN5YW5cIiwgXCJkYXJrYmx1ZVwiLCBcImRhcmtjeWFuXCIsIFwiZGFya2dvbGRlbnJvZFwiLFxuICAgIFwiZGFya2dyYXlcIiwgXCJkYXJrZ3JlZW5cIiwgXCJkYXJra2hha2lcIiwgXCJkYXJrbWFnZW50YVwiLCBcImRhcmtvbGl2ZWdyZWVuXCIsXG4gICAgXCJkYXJrb3JhbmdlXCIsIFwiZGFya29yY2hpZFwiLCBcImRhcmtyZWRcIiwgXCJkYXJrc2FsbW9uXCIsIFwiZGFya3NlYWdyZWVuXCIsXG4gICAgXCJkYXJrc2xhdGVibHVlXCIsIFwiZGFya3NsYXRlZ3JheVwiLCBcImRhcmt0dXJxdW9pc2VcIiwgXCJkYXJrdmlvbGV0XCIsXG4gICAgXCJkZWVwcGlua1wiLCBcImRlZXBza3libHVlXCIsIFwiZGltZ3JheVwiLCBcImRvZGdlcmJsdWVcIiwgXCJmaXJlYnJpY2tcIixcbiAgICBcImZsb3JhbHdoaXRlXCIsIFwiZm9yZXN0Z3JlZW5cIiwgXCJmdWNoc2lhXCIsIFwiZ2FpbnNib3JvXCIsIFwiZ2hvc3R3aGl0ZVwiLFxuICAgIFwiZ29sZFwiLCBcImdvbGRlbnJvZFwiLCBcImdyYXlcIiwgXCJncmV5XCIsIFwiZ3JlZW5cIiwgXCJncmVlbnllbGxvd1wiLCBcImhvbmV5ZGV3XCIsXG4gICAgXCJob3RwaW5rXCIsIFwiaW5kaWFucmVkXCIsIFwiaW5kaWdvXCIsIFwiaXZvcnlcIiwgXCJraGFraVwiLCBcImxhdmVuZGVyXCIsXG4gICAgXCJsYXZlbmRlcmJsdXNoXCIsIFwibGF3bmdyZWVuXCIsIFwibGVtb25jaGlmZm9uXCIsIFwibGlnaHRibHVlXCIsIFwibGlnaHRjb3JhbFwiLFxuICAgIFwibGlnaHRjeWFuXCIsIFwibGlnaHRnb2xkZW5yb2R5ZWxsb3dcIiwgXCJsaWdodGdyYXlcIiwgXCJsaWdodGdyZWVuXCIsIFwibGlnaHRwaW5rXCIsXG4gICAgXCJsaWdodHNhbG1vblwiLCBcImxpZ2h0c2VhZ3JlZW5cIiwgXCJsaWdodHNreWJsdWVcIiwgXCJsaWdodHNsYXRlZ3JheVwiLFxuICAgIFwibGlnaHRzdGVlbGJsdWVcIiwgXCJsaWdodHllbGxvd1wiLCBcImxpbWVcIiwgXCJsaW1lZ3JlZW5cIiwgXCJsaW5lblwiLCBcIm1hZ2VudGFcIixcbiAgICBcIm1hcm9vblwiLCBcIm1lZGl1bWFxdWFtYXJpbmVcIiwgXCJtZWRpdW1ibHVlXCIsIFwibWVkaXVtb3JjaGlkXCIsIFwibWVkaXVtcHVycGxlXCIsXG4gICAgXCJtZWRpdW1zZWFncmVlblwiLCBcIm1lZGl1bXNsYXRlYmx1ZVwiLCBcIm1lZGl1bXNwcmluZ2dyZWVuXCIsIFwibWVkaXVtdHVycXVvaXNlXCIsXG4gICAgXCJtZWRpdW12aW9sZXRyZWRcIiwgXCJtaWRuaWdodGJsdWVcIiwgXCJtaW50Y3JlYW1cIiwgXCJtaXN0eXJvc2VcIiwgXCJtb2NjYXNpblwiLFxuICAgIFwibmF2YWpvd2hpdGVcIiwgXCJuYXZ5XCIsIFwib2xkbGFjZVwiLCBcIm9saXZlXCIsIFwib2xpdmVkcmFiXCIsIFwib3JhbmdlXCIsIFwib3JhbmdlcmVkXCIsXG4gICAgXCJvcmNoaWRcIiwgXCJwYWxlZ29sZGVucm9kXCIsIFwicGFsZWdyZWVuXCIsIFwicGFsZXR1cnF1b2lzZVwiLCBcInBhbGV2aW9sZXRyZWRcIixcbiAgICBcInBhcGF5YXdoaXBcIiwgXCJwZWFjaHB1ZmZcIiwgXCJwZXJ1XCIsIFwicGlua1wiLCBcInBsdW1cIiwgXCJwb3dkZXJibHVlXCIsXG4gICAgXCJwdXJwbGVcIiwgXCJyZWJlY2NhcHVycGxlXCIsIFwicmVkXCIsIFwicm9zeWJyb3duXCIsIFwicm95YWxibHVlXCIsIFwic2FkZGxlYnJvd25cIixcbiAgICBcInNhbG1vblwiLCBcInNhbmR5YnJvd25cIiwgXCJzZWFncmVlblwiLCBcInNlYXNoZWxsXCIsIFwic2llbm5hXCIsIFwic2lsdmVyXCIsIFwic2t5Ymx1ZVwiLFxuICAgIFwic2xhdGVibHVlXCIsIFwic2xhdGVncmF5XCIsIFwic25vd1wiLCBcInNwcmluZ2dyZWVuXCIsIFwic3RlZWxibHVlXCIsIFwidGFuXCIsXG4gICAgXCJ0ZWFsXCIsIFwidGhpc3RsZVwiLCBcInRvbWF0b1wiLCBcInR1cnF1b2lzZVwiLCBcInZpb2xldFwiLCBcIndoZWF0XCIsIFwid2hpdGVcIixcbiAgICBcIndoaXRlc21va2VcIiwgXCJ5ZWxsb3dcIiwgXCJ5ZWxsb3dncmVlblwiXG4gIF0sIGNvbG9yS2V5d29yZHMgPSBrZXlTZXQoY29sb3JLZXl3b3Jkc18pO1xuXG4gIHZhciB2YWx1ZUtleXdvcmRzXyA9IFtcbiAgICBcImFib3ZlXCIsIFwiYWJzb2x1dGVcIiwgXCJhY3RpdmVib3JkZXJcIiwgXCJhZGRpdGl2ZVwiLCBcImFjdGl2ZWNhcHRpb25cIiwgXCJhZmFyXCIsXG4gICAgXCJhZnRlci13aGl0ZS1zcGFjZVwiLCBcImFoZWFkXCIsIFwiYWxpYXNcIiwgXCJhbGxcIiwgXCJhbGwtc2Nyb2xsXCIsIFwiYWxwaGFiZXRpY1wiLCBcImFsdGVybmF0ZVwiLFxuICAgIFwiYWx3YXlzXCIsIFwiYW1oYXJpY1wiLCBcImFtaGFyaWMtYWJlZ2VkZVwiLCBcImFudGlhbGlhc2VkXCIsIFwiYXBwd29ya3NwYWNlXCIsXG4gICAgXCJhcmFiaWMtaW5kaWNcIiwgXCJhcm1lbmlhblwiLCBcImFzdGVyaXNrc1wiLCBcImF0dHJcIiwgXCJhdXRvXCIsIFwiYXV0by1mbG93XCIsIFwiYXZvaWRcIiwgXCJhdm9pZC1jb2x1bW5cIiwgXCJhdm9pZC1wYWdlXCIsXG4gICAgXCJhdm9pZC1yZWdpb25cIiwgXCJiYWNrZ3JvdW5kXCIsIFwiYmFja3dhcmRzXCIsIFwiYmFzZWxpbmVcIiwgXCJiZWxvd1wiLCBcImJpZGktb3ZlcnJpZGVcIiwgXCJiaW5hcnlcIixcbiAgICBcImJlbmdhbGlcIiwgXCJibGlua1wiLCBcImJsb2NrXCIsIFwiYmxvY2stYXhpc1wiLCBcImJvbGRcIiwgXCJib2xkZXJcIiwgXCJib3JkZXJcIiwgXCJib3JkZXItYm94XCIsXG4gICAgXCJib3RoXCIsIFwiYm90dG9tXCIsIFwiYnJlYWtcIiwgXCJicmVhay1hbGxcIiwgXCJicmVhay13b3JkXCIsIFwiYnVsbGV0c1wiLCBcImJ1dHRvblwiLCBcImJ1dHRvbi1iZXZlbFwiLFxuICAgIFwiYnV0dG9uZmFjZVwiLCBcImJ1dHRvbmhpZ2hsaWdodFwiLCBcImJ1dHRvbnNoYWRvd1wiLCBcImJ1dHRvbnRleHRcIiwgXCJjYWxjXCIsIFwiY2FtYm9kaWFuXCIsXG4gICAgXCJjYXBpdGFsaXplXCIsIFwiY2Fwcy1sb2NrLWluZGljYXRvclwiLCBcImNhcHRpb25cIiwgXCJjYXB0aW9udGV4dFwiLCBcImNhcmV0XCIsXG4gICAgXCJjZWxsXCIsIFwiY2VudGVyXCIsIFwiY2hlY2tib3hcIiwgXCJjaXJjbGVcIiwgXCJjamstZGVjaW1hbFwiLCBcImNqay1lYXJ0aGx5LWJyYW5jaFwiLFxuICAgIFwiY2prLWhlYXZlbmx5LXN0ZW1cIiwgXCJjamstaWRlb2dyYXBoaWNcIiwgXCJjbGVhclwiLCBcImNsaXBcIiwgXCJjbG9zZS1xdW90ZVwiLFxuICAgIFwiY29sLXJlc2l6ZVwiLCBcImNvbGxhcHNlXCIsIFwiY29sb3JcIiwgXCJjb2xvci1idXJuXCIsIFwiY29sb3ItZG9kZ2VcIiwgXCJjb2x1bW5cIiwgXCJjb2x1bW4tcmV2ZXJzZVwiLFxuICAgIFwiY29tcGFjdFwiLCBcImNvbmRlbnNlZFwiLCBcImNvbnRhaW5cIiwgXCJjb250ZW50XCIsIFwiY29udGVudHNcIixcbiAgICBcImNvbnRlbnQtYm94XCIsIFwiY29udGV4dC1tZW51XCIsIFwiY29udGludW91c1wiLCBcImNvcHlcIiwgXCJjb3VudGVyXCIsIFwiY291bnRlcnNcIiwgXCJjb3ZlclwiLCBcImNyb3BcIixcbiAgICBcImNyb3NzXCIsIFwiY3Jvc3NoYWlyXCIsIFwiY3VycmVudGNvbG9yXCIsIFwiY3Vyc2l2ZVwiLCBcImN5Y2xpY1wiLCBcImRhcmtlblwiLCBcImRhc2hlZFwiLCBcImRlY2ltYWxcIixcbiAgICBcImRlY2ltYWwtbGVhZGluZy16ZXJvXCIsIFwiZGVmYXVsdFwiLCBcImRlZmF1bHQtYnV0dG9uXCIsIFwiZGVuc2VcIiwgXCJkZXN0aW5hdGlvbi1hdG9wXCIsXG4gICAgXCJkZXN0aW5hdGlvbi1pblwiLCBcImRlc3RpbmF0aW9uLW91dFwiLCBcImRlc3RpbmF0aW9uLW92ZXJcIiwgXCJkZXZhbmFnYXJpXCIsIFwiZGlmZmVyZW5jZVwiLFxuICAgIFwiZGlzY1wiLCBcImRpc2NhcmRcIiwgXCJkaXNjbG9zdXJlLWNsb3NlZFwiLCBcImRpc2Nsb3N1cmUtb3BlblwiLCBcImRvY3VtZW50XCIsXG4gICAgXCJkb3QtZGFzaFwiLCBcImRvdC1kb3QtZGFzaFwiLFxuICAgIFwiZG90dGVkXCIsIFwiZG91YmxlXCIsIFwiZG93blwiLCBcImUtcmVzaXplXCIsIFwiZWFzZVwiLCBcImVhc2UtaW5cIiwgXCJlYXNlLWluLW91dFwiLCBcImVhc2Utb3V0XCIsXG4gICAgXCJlbGVtZW50XCIsIFwiZWxsaXBzZVwiLCBcImVsbGlwc2lzXCIsIFwiZW1iZWRcIiwgXCJlbmRcIiwgXCJldGhpb3BpY1wiLCBcImV0aGlvcGljLWFiZWdlZGVcIixcbiAgICBcImV0aGlvcGljLWFiZWdlZGUtYW0tZXRcIiwgXCJldGhpb3BpYy1hYmVnZWRlLWdlelwiLCBcImV0aGlvcGljLWFiZWdlZGUtdGktZXJcIixcbiAgICBcImV0aGlvcGljLWFiZWdlZGUtdGktZXRcIiwgXCJldGhpb3BpYy1oYWxlaGFtZS1hYS1lclwiLFxuICAgIFwiZXRoaW9waWMtaGFsZWhhbWUtYWEtZXRcIiwgXCJldGhpb3BpYy1oYWxlaGFtZS1hbS1ldFwiLFxuICAgIFwiZXRoaW9waWMtaGFsZWhhbWUtZ2V6XCIsIFwiZXRoaW9waWMtaGFsZWhhbWUtb20tZXRcIixcbiAgICBcImV0aGlvcGljLWhhbGVoYW1lLXNpZC1ldFwiLCBcImV0aGlvcGljLWhhbGVoYW1lLXNvLWV0XCIsXG4gICAgXCJldGhpb3BpYy1oYWxlaGFtZS10aS1lclwiLCBcImV0aGlvcGljLWhhbGVoYW1lLXRpLWV0XCIsIFwiZXRoaW9waWMtaGFsZWhhbWUtdGlnXCIsXG4gICAgXCJldGhpb3BpYy1udW1lcmljXCIsIFwiZXctcmVzaXplXCIsIFwiZXhjbHVzaW9uXCIsIFwiZXhwYW5kZWRcIiwgXCJleHRlbmRzXCIsIFwiZXh0cmEtY29uZGVuc2VkXCIsXG4gICAgXCJleHRyYS1leHBhbmRlZFwiLCBcImZhbnRhc3lcIiwgXCJmYXN0XCIsIFwiZmlsbFwiLCBcImZpeGVkXCIsIFwiZmxhdFwiLCBcImZsZXhcIiwgXCJmbGV4LWVuZFwiLCBcImZsZXgtc3RhcnRcIiwgXCJmb290bm90ZXNcIixcbiAgICBcImZvcndhcmRzXCIsIFwiZnJvbVwiLCBcImdlb21ldHJpY1ByZWNpc2lvblwiLCBcImdlb3JnaWFuXCIsIFwiZ3JheXRleHRcIiwgXCJncmlkXCIsIFwiZ3Jvb3ZlXCIsXG4gICAgXCJndWphcmF0aVwiLCBcImd1cm11a2hpXCIsIFwiaGFuZFwiLCBcImhhbmd1bFwiLCBcImhhbmd1bC1jb25zb25hbnRcIiwgXCJoYXJkLWxpZ2h0XCIsIFwiaGVicmV3XCIsXG4gICAgXCJoZWxwXCIsIFwiaGlkZGVuXCIsIFwiaGlkZVwiLCBcImhpZ2hlclwiLCBcImhpZ2hsaWdodFwiLCBcImhpZ2hsaWdodHRleHRcIixcbiAgICBcImhpcmFnYW5hXCIsIFwiaGlyYWdhbmEtaXJvaGFcIiwgXCJob3Jpem9udGFsXCIsIFwiaHNsXCIsIFwiaHNsYVwiLCBcImh1ZVwiLCBcImljb25cIiwgXCJpZ25vcmVcIixcbiAgICBcImluYWN0aXZlYm9yZGVyXCIsIFwiaW5hY3RpdmVjYXB0aW9uXCIsIFwiaW5hY3RpdmVjYXB0aW9udGV4dFwiLCBcImluZmluaXRlXCIsXG4gICAgXCJpbmZvYmFja2dyb3VuZFwiLCBcImluZm90ZXh0XCIsIFwiaW5oZXJpdFwiLCBcImluaXRpYWxcIiwgXCJpbmxpbmVcIiwgXCJpbmxpbmUtYXhpc1wiLFxuICAgIFwiaW5saW5lLWJsb2NrXCIsIFwiaW5saW5lLWZsZXhcIiwgXCJpbmxpbmUtZ3JpZFwiLCBcImlubGluZS10YWJsZVwiLCBcImluc2V0XCIsIFwiaW5zaWRlXCIsIFwiaW50cmluc2ljXCIsIFwiaW52ZXJ0XCIsXG4gICAgXCJpdGFsaWNcIiwgXCJqYXBhbmVzZS1mb3JtYWxcIiwgXCJqYXBhbmVzZS1pbmZvcm1hbFwiLCBcImp1c3RpZnlcIiwgXCJrYW5uYWRhXCIsXG4gICAgXCJrYXRha2FuYVwiLCBcImthdGFrYW5hLWlyb2hhXCIsIFwia2VlcC1hbGxcIiwgXCJraG1lclwiLFxuICAgIFwia29yZWFuLWhhbmd1bC1mb3JtYWxcIiwgXCJrb3JlYW4taGFuamEtZm9ybWFsXCIsIFwia29yZWFuLWhhbmphLWluZm9ybWFsXCIsXG4gICAgXCJsYW5kc2NhcGVcIiwgXCJsYW9cIiwgXCJsYXJnZVwiLCBcImxhcmdlclwiLCBcImxlZnRcIiwgXCJsZXZlbFwiLCBcImxpZ2h0ZXJcIiwgXCJsaWdodGVuXCIsXG4gICAgXCJsaW5lLXRocm91Z2hcIiwgXCJsaW5lYXJcIiwgXCJsaW5lYXItZ3JhZGllbnRcIiwgXCJsaW5lc1wiLCBcImxpc3QtaXRlbVwiLCBcImxpc3Rib3hcIiwgXCJsaXN0aXRlbVwiLFxuICAgIFwibG9jYWxcIiwgXCJsb2dpY2FsXCIsIFwibG91ZFwiLCBcImxvd2VyXCIsIFwibG93ZXItYWxwaGFcIiwgXCJsb3dlci1hcm1lbmlhblwiLFxuICAgIFwibG93ZXItZ3JlZWtcIiwgXCJsb3dlci1oZXhhZGVjaW1hbFwiLCBcImxvd2VyLWxhdGluXCIsIFwibG93ZXItbm9yd2VnaWFuXCIsXG4gICAgXCJsb3dlci1yb21hblwiLCBcImxvd2VyY2FzZVwiLCBcImx0clwiLCBcImx1bWlub3NpdHlcIiwgXCJtYWxheWFsYW1cIiwgXCJtYXRjaFwiLCBcIm1hdHJpeFwiLCBcIm1hdHJpeDNkXCIsXG4gICAgXCJtZWRpYS1jb250cm9scy1iYWNrZ3JvdW5kXCIsIFwibWVkaWEtY3VycmVudC10aW1lLWRpc3BsYXlcIixcbiAgICBcIm1lZGlhLWZ1bGxzY3JlZW4tYnV0dG9uXCIsIFwibWVkaWEtbXV0ZS1idXR0b25cIiwgXCJtZWRpYS1wbGF5LWJ1dHRvblwiLFxuICAgIFwibWVkaWEtcmV0dXJuLXRvLXJlYWx0aW1lLWJ1dHRvblwiLCBcIm1lZGlhLXJld2luZC1idXR0b25cIixcbiAgICBcIm1lZGlhLXNlZWstYmFjay1idXR0b25cIiwgXCJtZWRpYS1zZWVrLWZvcndhcmQtYnV0dG9uXCIsIFwibWVkaWEtc2xpZGVyXCIsXG4gICAgXCJtZWRpYS1zbGlkZXJ0aHVtYlwiLCBcIm1lZGlhLXRpbWUtcmVtYWluaW5nLWRpc3BsYXlcIiwgXCJtZWRpYS12b2x1bWUtc2xpZGVyXCIsXG4gICAgXCJtZWRpYS12b2x1bWUtc2xpZGVyLWNvbnRhaW5lclwiLCBcIm1lZGlhLXZvbHVtZS1zbGlkZXJ0aHVtYlwiLCBcIm1lZGl1bVwiLFxuICAgIFwibWVudVwiLCBcIm1lbnVsaXN0XCIsIFwibWVudWxpc3QtYnV0dG9uXCIsIFwibWVudWxpc3QtdGV4dFwiLFxuICAgIFwibWVudWxpc3QtdGV4dGZpZWxkXCIsIFwibWVudXRleHRcIiwgXCJtZXNzYWdlLWJveFwiLCBcIm1pZGRsZVwiLCBcIm1pbi1pbnRyaW5zaWNcIixcbiAgICBcIm1peFwiLCBcIm1vbmdvbGlhblwiLCBcIm1vbm9zcGFjZVwiLCBcIm1vdmVcIiwgXCJtdWx0aXBsZVwiLCBcIm11bHRpcGx5XCIsIFwibXlhbm1hclwiLCBcIm4tcmVzaXplXCIsXG4gICAgXCJuYXJyb3dlclwiLCBcIm5lLXJlc2l6ZVwiLCBcIm5lc3ctcmVzaXplXCIsIFwibm8tY2xvc2UtcXVvdGVcIiwgXCJuby1kcm9wXCIsXG4gICAgXCJuby1vcGVuLXF1b3RlXCIsIFwibm8tcmVwZWF0XCIsIFwibm9uZVwiLCBcIm5vcm1hbFwiLCBcIm5vdC1hbGxvd2VkXCIsIFwibm93cmFwXCIsXG4gICAgXCJucy1yZXNpemVcIiwgXCJudW1iZXJzXCIsIFwibnVtZXJpY1wiLCBcIm53LXJlc2l6ZVwiLCBcIm53c2UtcmVzaXplXCIsIFwib2JsaXF1ZVwiLCBcIm9jdGFsXCIsIFwib3BhY2l0eVwiLCBcIm9wZW4tcXVvdGVcIixcbiAgICBcIm9wdGltaXplTGVnaWJpbGl0eVwiLCBcIm9wdGltaXplU3BlZWRcIiwgXCJvcml5YVwiLCBcIm9yb21vXCIsIFwib3V0c2V0XCIsXG4gICAgXCJvdXRzaWRlXCIsIFwib3V0c2lkZS1zaGFwZVwiLCBcIm92ZXJsYXlcIiwgXCJvdmVybGluZVwiLCBcInBhZGRpbmdcIiwgXCJwYWRkaW5nLWJveFwiLFxuICAgIFwicGFpbnRlZFwiLCBcInBhZ2VcIiwgXCJwYXVzZWRcIiwgXCJwZXJzaWFuXCIsIFwicGVyc3BlY3RpdmVcIiwgXCJwbHVzLWRhcmtlclwiLCBcInBsdXMtbGlnaHRlclwiLFxuICAgIFwicG9pbnRlclwiLCBcInBvbHlnb25cIiwgXCJwb3J0cmFpdFwiLCBcInByZVwiLCBcInByZS1saW5lXCIsIFwicHJlLXdyYXBcIiwgXCJwcmVzZXJ2ZS0zZFwiLFxuICAgIFwicHJvZ3Jlc3NcIiwgXCJwdXNoLWJ1dHRvblwiLCBcInJhZGlhbC1ncmFkaWVudFwiLCBcInJhZGlvXCIsIFwicmVhZC1vbmx5XCIsXG4gICAgXCJyZWFkLXdyaXRlXCIsIFwicmVhZC13cml0ZS1wbGFpbnRleHQtb25seVwiLCBcInJlY3RhbmdsZVwiLCBcInJlZ2lvblwiLFxuICAgIFwicmVsYXRpdmVcIiwgXCJyZXBlYXRcIiwgXCJyZXBlYXRpbmctbGluZWFyLWdyYWRpZW50XCIsXG4gICAgXCJyZXBlYXRpbmctcmFkaWFsLWdyYWRpZW50XCIsIFwicmVwZWF0LXhcIiwgXCJyZXBlYXQteVwiLCBcInJlc2V0XCIsIFwicmV2ZXJzZVwiLFxuICAgIFwicmdiXCIsIFwicmdiYVwiLCBcInJpZGdlXCIsIFwicmlnaHRcIiwgXCJyb3RhdGVcIiwgXCJyb3RhdGUzZFwiLCBcInJvdGF0ZVhcIiwgXCJyb3RhdGVZXCIsXG4gICAgXCJyb3RhdGVaXCIsIFwicm91bmRcIiwgXCJyb3dcIiwgXCJyb3ctcmVzaXplXCIsIFwicm93LXJldmVyc2VcIiwgXCJydGxcIiwgXCJydW4taW5cIiwgXCJydW5uaW5nXCIsXG4gICAgXCJzLXJlc2l6ZVwiLCBcInNhbnMtc2VyaWZcIiwgXCJzYXR1cmF0aW9uXCIsIFwic2NhbGVcIiwgXCJzY2FsZTNkXCIsIFwic2NhbGVYXCIsIFwic2NhbGVZXCIsIFwic2NhbGVaXCIsIFwic2NyZWVuXCIsXG4gICAgXCJzY3JvbGxcIiwgXCJzY3JvbGxiYXJcIiwgXCJzY3JvbGwtcG9zaXRpb25cIiwgXCJzZS1yZXNpemVcIiwgXCJzZWFyY2hmaWVsZFwiLFxuICAgIFwic2VhcmNoZmllbGQtY2FuY2VsLWJ1dHRvblwiLCBcInNlYXJjaGZpZWxkLWRlY29yYXRpb25cIixcbiAgICBcInNlYXJjaGZpZWxkLXJlc3VsdHMtYnV0dG9uXCIsIFwic2VhcmNoZmllbGQtcmVzdWx0cy1kZWNvcmF0aW9uXCIsIFwic2VsZi1zdGFydFwiLCBcInNlbGYtZW5kXCIsXG4gICAgXCJzZW1pLWNvbmRlbnNlZFwiLCBcInNlbWktZXhwYW5kZWRcIiwgXCJzZXBhcmF0ZVwiLCBcInNlcmlmXCIsIFwic2hvd1wiLCBcInNpZGFtYVwiLFxuICAgIFwic2ltcC1jaGluZXNlLWZvcm1hbFwiLCBcInNpbXAtY2hpbmVzZS1pbmZvcm1hbFwiLCBcInNpbmdsZVwiLFxuICAgIFwic2tld1wiLCBcInNrZXdYXCIsIFwic2tld1lcIiwgXCJza2lwLXdoaXRlLXNwYWNlXCIsIFwic2xpZGVcIiwgXCJzbGlkZXItaG9yaXpvbnRhbFwiLFxuICAgIFwic2xpZGVyLXZlcnRpY2FsXCIsIFwic2xpZGVydGh1bWItaG9yaXpvbnRhbFwiLCBcInNsaWRlcnRodW1iLXZlcnRpY2FsXCIsIFwic2xvd1wiLFxuICAgIFwic21hbGxcIiwgXCJzbWFsbC1jYXBzXCIsIFwic21hbGwtY2FwdGlvblwiLCBcInNtYWxsZXJcIiwgXCJzb2Z0LWxpZ2h0XCIsIFwic29saWRcIiwgXCJzb21hbGlcIixcbiAgICBcInNvdXJjZS1hdG9wXCIsIFwic291cmNlLWluXCIsIFwic291cmNlLW91dFwiLCBcInNvdXJjZS1vdmVyXCIsIFwic3BhY2VcIiwgXCJzcGFjZS1hcm91bmRcIiwgXCJzcGFjZS1iZXR3ZWVuXCIsIFwic3BhY2UtZXZlbmx5XCIsIFwic3BlbGwtb3V0XCIsIFwic3F1YXJlXCIsXG4gICAgXCJzcXVhcmUtYnV0dG9uXCIsIFwic3RhcnRcIiwgXCJzdGF0aWNcIiwgXCJzdGF0dXMtYmFyXCIsIFwic3RyZXRjaFwiLCBcInN0cm9rZVwiLCBcInN1YlwiLFxuICAgIFwic3VicGl4ZWwtYW50aWFsaWFzZWRcIiwgXCJzdXBlclwiLCBcInN3LXJlc2l6ZVwiLCBcInN5bWJvbGljXCIsIFwic3ltYm9sc1wiLCBcInN5c3RlbS11aVwiLCBcInRhYmxlXCIsXG4gICAgXCJ0YWJsZS1jYXB0aW9uXCIsIFwidGFibGUtY2VsbFwiLCBcInRhYmxlLWNvbHVtblwiLCBcInRhYmxlLWNvbHVtbi1ncm91cFwiLFxuICAgIFwidGFibGUtZm9vdGVyLWdyb3VwXCIsIFwidGFibGUtaGVhZGVyLWdyb3VwXCIsIFwidGFibGUtcm93XCIsIFwidGFibGUtcm93LWdyb3VwXCIsXG4gICAgXCJ0YW1pbFwiLFxuICAgIFwidGVsdWd1XCIsIFwidGV4dFwiLCBcInRleHQtYm90dG9tXCIsIFwidGV4dC10b3BcIiwgXCJ0ZXh0YXJlYVwiLCBcInRleHRmaWVsZFwiLCBcInRoYWlcIixcbiAgICBcInRoaWNrXCIsIFwidGhpblwiLCBcInRocmVlZGRhcmtzaGFkb3dcIiwgXCJ0aHJlZWRmYWNlXCIsIFwidGhyZWVkaGlnaGxpZ2h0XCIsXG4gICAgXCJ0aHJlZWRsaWdodHNoYWRvd1wiLCBcInRocmVlZHNoYWRvd1wiLCBcInRpYmV0YW5cIiwgXCJ0aWdyZVwiLCBcInRpZ3JpbnlhLWVyXCIsXG4gICAgXCJ0aWdyaW55YS1lci1hYmVnZWRlXCIsIFwidGlncmlueWEtZXRcIiwgXCJ0aWdyaW55YS1ldC1hYmVnZWRlXCIsIFwidG9cIiwgXCJ0b3BcIixcbiAgICBcInRyYWQtY2hpbmVzZS1mb3JtYWxcIiwgXCJ0cmFkLWNoaW5lc2UtaW5mb3JtYWxcIiwgXCJ0cmFuc2Zvcm1cIixcbiAgICBcInRyYW5zbGF0ZVwiLCBcInRyYW5zbGF0ZTNkXCIsIFwidHJhbnNsYXRlWFwiLCBcInRyYW5zbGF0ZVlcIiwgXCJ0cmFuc2xhdGVaXCIsXG4gICAgXCJ0cmFuc3BhcmVudFwiLCBcInVsdHJhLWNvbmRlbnNlZFwiLCBcInVsdHJhLWV4cGFuZGVkXCIsIFwidW5kZXJsaW5lXCIsIFwidW5zZXRcIiwgXCJ1cFwiLFxuICAgIFwidXBwZXItYWxwaGFcIiwgXCJ1cHBlci1hcm1lbmlhblwiLCBcInVwcGVyLWdyZWVrXCIsIFwidXBwZXItaGV4YWRlY2ltYWxcIixcbiAgICBcInVwcGVyLWxhdGluXCIsIFwidXBwZXItbm9yd2VnaWFuXCIsIFwidXBwZXItcm9tYW5cIiwgXCJ1cHBlcmNhc2VcIiwgXCJ1cmR1XCIsIFwidXJsXCIsXG4gICAgXCJ2YXJcIiwgXCJ2ZXJ0aWNhbFwiLCBcInZlcnRpY2FsLXRleHRcIiwgXCJ2aXNpYmxlXCIsIFwidmlzaWJsZUZpbGxcIiwgXCJ2aXNpYmxlUGFpbnRlZFwiLFxuICAgIFwidmlzaWJsZVN0cm9rZVwiLCBcInZpc3VhbFwiLCBcInctcmVzaXplXCIsIFwid2FpdFwiLCBcIndhdmVcIiwgXCJ3aWRlclwiLFxuICAgIFwid2luZG93XCIsIFwid2luZG93ZnJhbWVcIiwgXCJ3aW5kb3d0ZXh0XCIsIFwid29yZHNcIiwgXCJ3cmFwXCIsIFwid3JhcC1yZXZlcnNlXCIsIFwieC1sYXJnZVwiLCBcIngtc21hbGxcIiwgXCJ4b3JcIixcbiAgICBcInh4LWxhcmdlXCIsIFwieHgtc21hbGxcIlxuICBdLCB2YWx1ZUtleXdvcmRzID0ga2V5U2V0KHZhbHVlS2V5d29yZHNfKTtcblxuICB2YXIgYWxsV29yZHMgPSBkb2N1bWVudFR5cGVzXy5jb25jYXQobWVkaWFUeXBlc18pLmNvbmNhdChtZWRpYUZlYXR1cmVzXykuY29uY2F0KG1lZGlhVmFsdWVLZXl3b3Jkc18pXG4gICAgLmNvbmNhdChwcm9wZXJ0eUtleXdvcmRzXykuY29uY2F0KG5vblN0YW5kYXJkUHJvcGVydHlLZXl3b3Jkc18pLmNvbmNhdChjb2xvcktleXdvcmRzXylcbiAgICAuY29uY2F0KHZhbHVlS2V5d29yZHNfKTtcbiAgQ29kZU1pcnJvci5yZWdpc3RlckhlbHBlcihcImhpbnRXb3Jkc1wiLCBcImNzc1wiLCBhbGxXb3Jkcyk7XG5cbiAgZnVuY3Rpb24gdG9rZW5DQ29tbWVudChzdHJlYW0sIHN0YXRlKSB7XG4gICAgdmFyIG1heWJlRW5kID0gZmFsc2UsIGNoO1xuICAgIHdoaWxlICgoY2ggPSBzdHJlYW0ubmV4dCgpKSAhPSBudWxsKSB7XG4gICAgICBpZiAobWF5YmVFbmQgJiYgY2ggPT0gXCIvXCIpIHtcbiAgICAgICAgc3RhdGUudG9rZW5pemUgPSBudWxsO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIG1heWJlRW5kID0gKGNoID09IFwiKlwiKTtcbiAgICB9XG4gICAgcmV0dXJuIFtcImNvbW1lbnRcIiwgXCJjb21tZW50XCJdO1xuICB9XG5cbiAgQ29kZU1pcnJvci5kZWZpbmVNSU1FKFwidGV4dC9jc3NcIiwge1xuICAgIGRvY3VtZW50VHlwZXM6IGRvY3VtZW50VHlwZXMsXG4gICAgbWVkaWFUeXBlczogbWVkaWFUeXBlcyxcbiAgICBtZWRpYUZlYXR1cmVzOiBtZWRpYUZlYXR1cmVzLFxuICAgIG1lZGlhVmFsdWVLZXl3b3JkczogbWVkaWFWYWx1ZUtleXdvcmRzLFxuICAgIHByb3BlcnR5S2V5d29yZHM6IHByb3BlcnR5S2V5d29yZHMsXG4gICAgbm9uU3RhbmRhcmRQcm9wZXJ0eUtleXdvcmRzOiBub25TdGFuZGFyZFByb3BlcnR5S2V5d29yZHMsXG4gICAgZm9udFByb3BlcnRpZXM6IGZvbnRQcm9wZXJ0aWVzLFxuICAgIGNvdW50ZXJEZXNjcmlwdG9yczogY291bnRlckRlc2NyaXB0b3JzLFxuICAgIGNvbG9yS2V5d29yZHM6IGNvbG9yS2V5d29yZHMsXG4gICAgdmFsdWVLZXl3b3JkczogdmFsdWVLZXl3b3JkcyxcbiAgICB0b2tlbkhvb2tzOiB7XG4gICAgICBcIi9cIjogZnVuY3Rpb24oc3RyZWFtLCBzdGF0ZSkge1xuICAgICAgICBpZiAoIXN0cmVhbS5lYXQoXCIqXCIpKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHN0YXRlLnRva2VuaXplID0gdG9rZW5DQ29tbWVudDtcbiAgICAgICAgcmV0dXJuIHRva2VuQ0NvbW1lbnQoc3RyZWFtLCBzdGF0ZSk7XG4gICAgICB9XG4gICAgfSxcbiAgICBuYW1lOiBcImNzc1wiXG4gIH0pO1xuXG4gIENvZGVNaXJyb3IuZGVmaW5lTUlNRShcInRleHQveC1zY3NzXCIsIHtcbiAgICBtZWRpYVR5cGVzOiBtZWRpYVR5cGVzLFxuICAgIG1lZGlhRmVhdHVyZXM6IG1lZGlhRmVhdHVyZXMsXG4gICAgbWVkaWFWYWx1ZUtleXdvcmRzOiBtZWRpYVZhbHVlS2V5d29yZHMsXG4gICAgcHJvcGVydHlLZXl3b3JkczogcHJvcGVydHlLZXl3b3JkcyxcbiAgICBub25TdGFuZGFyZFByb3BlcnR5S2V5d29yZHM6IG5vblN0YW5kYXJkUHJvcGVydHlLZXl3b3JkcyxcbiAgICBjb2xvcktleXdvcmRzOiBjb2xvcktleXdvcmRzLFxuICAgIHZhbHVlS2V5d29yZHM6IHZhbHVlS2V5d29yZHMsXG4gICAgZm9udFByb3BlcnRpZXM6IGZvbnRQcm9wZXJ0aWVzLFxuICAgIGFsbG93TmVzdGVkOiB0cnVlLFxuICAgIGxpbmVDb21tZW50OiBcIi8vXCIsXG4gICAgdG9rZW5Ib29rczoge1xuICAgICAgXCIvXCI6IGZ1bmN0aW9uKHN0cmVhbSwgc3RhdGUpIHtcbiAgICAgICAgaWYgKHN0cmVhbS5lYXQoXCIvXCIpKSB7XG4gICAgICAgICAgc3RyZWFtLnNraXBUb0VuZCgpO1xuICAgICAgICAgIHJldHVybiBbXCJjb21tZW50XCIsIFwiY29tbWVudFwiXTtcbiAgICAgICAgfSBlbHNlIGlmIChzdHJlYW0uZWF0KFwiKlwiKSkge1xuICAgICAgICAgIHN0YXRlLnRva2VuaXplID0gdG9rZW5DQ29tbWVudDtcbiAgICAgICAgICByZXR1cm4gdG9rZW5DQ29tbWVudChzdHJlYW0sIHN0YXRlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gW1wib3BlcmF0b3JcIiwgXCJvcGVyYXRvclwiXTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIFwiOlwiOiBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXFxzKlxcey8sIGZhbHNlKSlcbiAgICAgICAgICByZXR1cm4gW251bGwsIG51bGxdXG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgIH0sXG4gICAgICBcIiRcIjogZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgIHN0cmVhbS5tYXRjaCgvXltcXHctXSsvKTtcbiAgICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXlxccyo6LywgZmFsc2UpKVxuICAgICAgICAgIHJldHVybiBbXCJ2YXJpYWJsZS0yXCIsIFwidmFyaWFibGUtZGVmaW5pdGlvblwiXTtcbiAgICAgICAgcmV0dXJuIFtcInZhcmlhYmxlLTJcIiwgXCJ2YXJpYWJsZVwiXTtcbiAgICAgIH0sXG4gICAgICBcIiNcIjogZnVuY3Rpb24oc3RyZWFtKSB7XG4gICAgICAgIGlmICghc3RyZWFtLmVhdChcIntcIikpIHJldHVybiBmYWxzZTtcbiAgICAgICAgcmV0dXJuIFtudWxsLCBcImludGVycG9sYXRpb25cIl07XG4gICAgICB9XG4gICAgfSxcbiAgICBuYW1lOiBcImNzc1wiLFxuICAgIGhlbHBlclR5cGU6IFwic2Nzc1wiXG4gIH0pO1xuXG4gIENvZGVNaXJyb3IuZGVmaW5lTUlNRShcInRleHQveC1sZXNzXCIsIHtcbiAgICBtZWRpYVR5cGVzOiBtZWRpYVR5cGVzLFxuICAgIG1lZGlhRmVhdHVyZXM6IG1lZGlhRmVhdHVyZXMsXG4gICAgbWVkaWFWYWx1ZUtleXdvcmRzOiBtZWRpYVZhbHVlS2V5d29yZHMsXG4gICAgcHJvcGVydHlLZXl3b3JkczogcHJvcGVydHlLZXl3b3JkcyxcbiAgICBub25TdGFuZGFyZFByb3BlcnR5S2V5d29yZHM6IG5vblN0YW5kYXJkUHJvcGVydHlLZXl3b3JkcyxcbiAgICBjb2xvcktleXdvcmRzOiBjb2xvcktleXdvcmRzLFxuICAgIHZhbHVlS2V5d29yZHM6IHZhbHVlS2V5d29yZHMsXG4gICAgZm9udFByb3BlcnRpZXM6IGZvbnRQcm9wZXJ0aWVzLFxuICAgIGFsbG93TmVzdGVkOiB0cnVlLFxuICAgIGxpbmVDb21tZW50OiBcIi8vXCIsXG4gICAgdG9rZW5Ib29rczoge1xuICAgICAgXCIvXCI6IGZ1bmN0aW9uKHN0cmVhbSwgc3RhdGUpIHtcbiAgICAgICAgaWYgKHN0cmVhbS5lYXQoXCIvXCIpKSB7XG4gICAgICAgICAgc3RyZWFtLnNraXBUb0VuZCgpO1xuICAgICAgICAgIHJldHVybiBbXCJjb21tZW50XCIsIFwiY29tbWVudFwiXTtcbiAgICAgICAgfSBlbHNlIGlmIChzdHJlYW0uZWF0KFwiKlwiKSkge1xuICAgICAgICAgIHN0YXRlLnRva2VuaXplID0gdG9rZW5DQ29tbWVudDtcbiAgICAgICAgICByZXR1cm4gdG9rZW5DQ29tbWVudChzdHJlYW0sIHN0YXRlKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICByZXR1cm4gW1wib3BlcmF0b3JcIiwgXCJvcGVyYXRvclwiXTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgIFwiQFwiOiBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgaWYgKHN0cmVhbS5lYXQoXCJ7XCIpKSByZXR1cm4gW251bGwsIFwiaW50ZXJwb2xhdGlvblwiXTtcbiAgICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXihjaGFyc2V0fGRvY3VtZW50fGZvbnQtZmFjZXxpbXBvcnR8KC0obW96fG1zfG98d2Via2l0KS0pP2tleWZyYW1lc3xtZWRpYXxuYW1lc3BhY2V8cGFnZXxzdXBwb3J0cylcXGIvaSwgZmFsc2UpKSByZXR1cm4gZmFsc2U7XG4gICAgICAgIHN0cmVhbS5lYXRXaGlsZSgvW1xcd1xcXFxcXC1dLyk7XG4gICAgICAgIGlmIChzdHJlYW0ubWF0Y2goL15cXHMqOi8sIGZhbHNlKSlcbiAgICAgICAgICByZXR1cm4gW1widmFyaWFibGUtMlwiLCBcInZhcmlhYmxlLWRlZmluaXRpb25cIl07XG4gICAgICAgIHJldHVybiBbXCJ2YXJpYWJsZS0yXCIsIFwidmFyaWFibGVcIl07XG4gICAgICB9LFxuICAgICAgXCImXCI6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gW1wiYXRvbVwiLCBcImF0b21cIl07XG4gICAgICB9XG4gICAgfSxcbiAgICBuYW1lOiBcImNzc1wiLFxuICAgIGhlbHBlclR5cGU6IFwibGVzc1wiXG4gIH0pO1xuXG4gIENvZGVNaXJyb3IuZGVmaW5lTUlNRShcInRleHQveC1nc3NcIiwge1xuICAgIGRvY3VtZW50VHlwZXM6IGRvY3VtZW50VHlwZXMsXG4gICAgbWVkaWFUeXBlczogbWVkaWFUeXBlcyxcbiAgICBtZWRpYUZlYXR1cmVzOiBtZWRpYUZlYXR1cmVzLFxuICAgIHByb3BlcnR5S2V5d29yZHM6IHByb3BlcnR5S2V5d29yZHMsXG4gICAgbm9uU3RhbmRhcmRQcm9wZXJ0eUtleXdvcmRzOiBub25TdGFuZGFyZFByb3BlcnR5S2V5d29yZHMsXG4gICAgZm9udFByb3BlcnRpZXM6IGZvbnRQcm9wZXJ0aWVzLFxuICAgIGNvdW50ZXJEZXNjcmlwdG9yczogY291bnRlckRlc2NyaXB0b3JzLFxuICAgIGNvbG9yS2V5d29yZHM6IGNvbG9yS2V5d29yZHMsXG4gICAgdmFsdWVLZXl3b3JkczogdmFsdWVLZXl3b3JkcyxcbiAgICBzdXBwb3J0c0F0Q29tcG9uZW50OiB0cnVlLFxuICAgIHRva2VuSG9va3M6IHtcbiAgICAgIFwiL1wiOiBmdW5jdGlvbihzdHJlYW0sIHN0YXRlKSB7XG4gICAgICAgIGlmICghc3RyZWFtLmVhdChcIipcIikpIHJldHVybiBmYWxzZTtcbiAgICAgICAgc3RhdGUudG9rZW5pemUgPSB0b2tlbkNDb21tZW50O1xuICAgICAgICByZXR1cm4gdG9rZW5DQ29tbWVudChzdHJlYW0sIHN0YXRlKTtcbiAgICAgIH1cbiAgICB9LFxuICAgIG5hbWU6IFwiY3NzXCIsXG4gICAgaGVscGVyVHlwZTogXCJnc3NcIlxuICB9KTtcblxufSk7XG4iLCIvLyBDb2RlTWlycm9yLCBjb3B5cmlnaHQgKGMpIGJ5IE1hcmlqbiBIYXZlcmJla2UgYW5kIG90aGVyc1xuLy8gRGlzdHJpYnV0ZWQgdW5kZXIgYW4gTUlUIGxpY2Vuc2U6IGh0dHBzOi8vY29kZW1pcnJvci5uZXQvTElDRU5TRVxuXG4oZnVuY3Rpb24obW9kKSB7XG4gIGlmICh0eXBlb2YgZXhwb3J0cyA9PSBcIm9iamVjdFwiICYmIHR5cGVvZiBtb2R1bGUgPT0gXCJvYmplY3RcIikgLy8gQ29tbW9uSlNcbiAgICBtb2QocmVxdWlyZShcIi4uLy4uL2xpYi9jb2RlbWlycm9yXCIpLCByZXF1aXJlKFwiLi4vY3NzL2Nzc1wiKSk7XG4gIGVsc2UgaWYgKHR5cGVvZiBkZWZpbmUgPT0gXCJmdW5jdGlvblwiICYmIGRlZmluZS5hbWQpIC8vIEFNRFxuICAgIGRlZmluZShbXCIuLi8uLi9saWIvY29kZW1pcnJvclwiLCBcIi4uL2Nzcy9jc3NcIl0sIG1vZCk7XG4gIGVsc2UgLy8gUGxhaW4gYnJvd3NlciBlbnZcbiAgICBtb2QoQ29kZU1pcnJvcik7XG59KShmdW5jdGlvbihDb2RlTWlycm9yKSB7XG5cInVzZSBzdHJpY3RcIjtcblxuQ29kZU1pcnJvci5kZWZpbmVNb2RlKFwic2Fzc1wiLCBmdW5jdGlvbihjb25maWcpIHtcbiAgdmFyIGNzc01vZGUgPSBDb2RlTWlycm9yLm1pbWVNb2Rlc1tcInRleHQvY3NzXCJdO1xuICB2YXIgcHJvcGVydHlLZXl3b3JkcyA9IGNzc01vZGUucHJvcGVydHlLZXl3b3JkcyB8fCB7fSxcbiAgICAgIGNvbG9yS2V5d29yZHMgPSBjc3NNb2RlLmNvbG9yS2V5d29yZHMgfHwge30sXG4gICAgICB2YWx1ZUtleXdvcmRzID0gY3NzTW9kZS52YWx1ZUtleXdvcmRzIHx8IHt9LFxuICAgICAgZm9udFByb3BlcnRpZXMgPSBjc3NNb2RlLmZvbnRQcm9wZXJ0aWVzIHx8IHt9O1xuXG4gIGZ1bmN0aW9uIHRva2VuUmVnZXhwKHdvcmRzKSB7XG4gICAgcmV0dXJuIG5ldyBSZWdFeHAoXCJeXCIgKyB3b3Jkcy5qb2luKFwifFwiKSk7XG4gIH1cblxuICB2YXIga2V5d29yZHMgPSBbXCJ0cnVlXCIsIFwiZmFsc2VcIiwgXCJudWxsXCIsIFwiYXV0b1wiXTtcbiAgdmFyIGtleXdvcmRzUmVnZXhwID0gbmV3IFJlZ0V4cChcIl5cIiArIGtleXdvcmRzLmpvaW4oXCJ8XCIpKTtcblxuICB2YXIgb3BlcmF0b3JzID0gW1wiXFxcXChcIiwgXCJcXFxcKVwiLCBcIj1cIiwgXCI+XCIsIFwiPFwiLCBcIj09XCIsIFwiPj1cIiwgXCI8PVwiLCBcIlxcXFwrXCIsIFwiLVwiLFxuICAgICAgICAgICAgICAgICAgIFwiXFxcXCE9XCIsIFwiL1wiLCBcIlxcXFwqXCIsIFwiJVwiLCBcImFuZFwiLCBcIm9yXCIsIFwibm90XCIsIFwiO1wiLFwiXFxcXHtcIixcIlxcXFx9XCIsXCI6XCJdO1xuICB2YXIgb3BSZWdleHAgPSB0b2tlblJlZ2V4cChvcGVyYXRvcnMpO1xuXG4gIHZhciBwc2V1ZG9FbGVtZW50c1JlZ2V4cCA9IC9eOjo/W2EtekEtWl9dW1xcd1xcLV0qLztcblxuICB2YXIgd29yZDtcblxuICBmdW5jdGlvbiBpc0VuZExpbmUoc3RyZWFtKSB7XG4gICAgcmV0dXJuICFzdHJlYW0ucGVlaygpIHx8IHN0cmVhbS5tYXRjaCgvXFxzKyQvLCBmYWxzZSk7XG4gIH1cblxuICBmdW5jdGlvbiB1cmxUb2tlbnMoc3RyZWFtLCBzdGF0ZSkge1xuICAgIHZhciBjaCA9IHN0cmVhbS5wZWVrKCk7XG5cbiAgICBpZiAoY2ggPT09IFwiKVwiKSB7XG4gICAgICBzdHJlYW0ubmV4dCgpO1xuICAgICAgc3RhdGUudG9rZW5pemVyID0gdG9rZW5CYXNlO1xuICAgICAgcmV0dXJuIFwib3BlcmF0b3JcIjtcbiAgICB9IGVsc2UgaWYgKGNoID09PSBcIihcIikge1xuICAgICAgc3RyZWFtLm5leHQoKTtcbiAgICAgIHN0cmVhbS5lYXRTcGFjZSgpO1xuXG4gICAgICByZXR1cm4gXCJvcGVyYXRvclwiO1xuICAgIH0gZWxzZSBpZiAoY2ggPT09IFwiJ1wiIHx8IGNoID09PSAnXCInKSB7XG4gICAgICBzdGF0ZS50b2tlbml6ZXIgPSBidWlsZFN0cmluZ1Rva2VuaXplcihzdHJlYW0ubmV4dCgpKTtcbiAgICAgIHJldHVybiBcInN0cmluZ1wiO1xuICAgIH0gZWxzZSB7XG4gICAgICBzdGF0ZS50b2tlbml6ZXIgPSBidWlsZFN0cmluZ1Rva2VuaXplcihcIilcIiwgZmFsc2UpO1xuICAgICAgcmV0dXJuIFwic3RyaW5nXCI7XG4gICAgfVxuICB9XG4gIGZ1bmN0aW9uIGNvbW1lbnQoaW5kZW50YXRpb24sIG11bHRpTGluZSkge1xuICAgIHJldHVybiBmdW5jdGlvbihzdHJlYW0sIHN0YXRlKSB7XG4gICAgICBpZiAoc3RyZWFtLnNvbCgpICYmIHN0cmVhbS5pbmRlbnRhdGlvbigpIDw9IGluZGVudGF0aW9uKSB7XG4gICAgICAgIHN0YXRlLnRva2VuaXplciA9IHRva2VuQmFzZTtcbiAgICAgICAgcmV0dXJuIHRva2VuQmFzZShzdHJlYW0sIHN0YXRlKTtcbiAgICAgIH1cblxuICAgICAgaWYgKG11bHRpTGluZSAmJiBzdHJlYW0uc2tpcFRvKFwiKi9cIikpIHtcbiAgICAgICAgc3RyZWFtLm5leHQoKTtcbiAgICAgICAgc3RyZWFtLm5leHQoKTtcbiAgICAgICAgc3RhdGUudG9rZW5pemVyID0gdG9rZW5CYXNlO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgc3RyZWFtLnNraXBUb0VuZCgpO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4gXCJjb21tZW50XCI7XG4gICAgfTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGJ1aWxkU3RyaW5nVG9rZW5pemVyKHF1b3RlLCBncmVlZHkpIHtcbiAgICBpZiAoZ3JlZWR5ID09IG51bGwpIHsgZ3JlZWR5ID0gdHJ1ZTsgfVxuXG4gICAgZnVuY3Rpb24gc3RyaW5nVG9rZW5pemVyKHN0cmVhbSwgc3RhdGUpIHtcbiAgICAgIHZhciBuZXh0Q2hhciA9IHN0cmVhbS5uZXh0KCk7XG4gICAgICB2YXIgcGVla0NoYXIgPSBzdHJlYW0ucGVlaygpO1xuICAgICAgdmFyIHByZXZpb3VzQ2hhciA9IHN0cmVhbS5zdHJpbmcuY2hhckF0KHN0cmVhbS5wb3MtMik7XG5cbiAgICAgIHZhciBlbmRpbmdTdHJpbmcgPSAoKG5leHRDaGFyICE9PSBcIlxcXFxcIiAmJiBwZWVrQ2hhciA9PT0gcXVvdGUpIHx8IChuZXh0Q2hhciA9PT0gcXVvdGUgJiYgcHJldmlvdXNDaGFyICE9PSBcIlxcXFxcIikpO1xuXG4gICAgICBpZiAoZW5kaW5nU3RyaW5nKSB7XG4gICAgICAgIGlmIChuZXh0Q2hhciAhPT0gcXVvdGUgJiYgZ3JlZWR5KSB7IHN0cmVhbS5uZXh0KCk7IH1cbiAgICAgICAgaWYgKGlzRW5kTGluZShzdHJlYW0pKSB7XG4gICAgICAgICAgc3RhdGUuY3Vyc29ySGFsZiA9IDA7XG4gICAgICAgIH1cbiAgICAgICAgc3RhdGUudG9rZW5pemVyID0gdG9rZW5CYXNlO1xuICAgICAgICByZXR1cm4gXCJzdHJpbmdcIjtcbiAgICAgIH0gZWxzZSBpZiAobmV4dENoYXIgPT09IFwiI1wiICYmIHBlZWtDaGFyID09PSBcIntcIikge1xuICAgICAgICBzdGF0ZS50b2tlbml6ZXIgPSBidWlsZEludGVycG9sYXRpb25Ub2tlbml6ZXIoc3RyaW5nVG9rZW5pemVyKTtcbiAgICAgICAgc3RyZWFtLm5leHQoKTtcbiAgICAgICAgcmV0dXJuIFwib3BlcmF0b3JcIjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiBcInN0cmluZ1wiO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBzdHJpbmdUb2tlbml6ZXI7XG4gIH1cblxuICBmdW5jdGlvbiBidWlsZEludGVycG9sYXRpb25Ub2tlbml6ZXIoY3VycmVudFRva2VuaXplcikge1xuICAgIHJldHVybiBmdW5jdGlvbihzdHJlYW0sIHN0YXRlKSB7XG4gICAgICBpZiAoc3RyZWFtLnBlZWsoKSA9PT0gXCJ9XCIpIHtcbiAgICAgICAgc3RyZWFtLm5leHQoKTtcbiAgICAgICAgc3RhdGUudG9rZW5pemVyID0gY3VycmVudFRva2VuaXplcjtcbiAgICAgICAgcmV0dXJuIFwib3BlcmF0b3JcIjtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHJldHVybiB0b2tlbkJhc2Uoc3RyZWFtLCBzdGF0ZSk7XG4gICAgICB9XG4gICAgfTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGluZGVudChzdGF0ZSkge1xuICAgIGlmIChzdGF0ZS5pbmRlbnRDb3VudCA9PSAwKSB7XG4gICAgICBzdGF0ZS5pbmRlbnRDb3VudCsrO1xuICAgICAgdmFyIGxhc3RTY29wZU9mZnNldCA9IHN0YXRlLnNjb3Blc1swXS5vZmZzZXQ7XG4gICAgICB2YXIgY3VycmVudE9mZnNldCA9IGxhc3RTY29wZU9mZnNldCArIGNvbmZpZy5pbmRlbnRVbml0O1xuICAgICAgc3RhdGUuc2NvcGVzLnVuc2hpZnQoeyBvZmZzZXQ6Y3VycmVudE9mZnNldCB9KTtcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBkZWRlbnQoc3RhdGUpIHtcbiAgICBpZiAoc3RhdGUuc2NvcGVzLmxlbmd0aCA9PSAxKSByZXR1cm47XG5cbiAgICBzdGF0ZS5zY29wZXMuc2hpZnQoKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHRva2VuQmFzZShzdHJlYW0sIHN0YXRlKSB7XG4gICAgdmFyIGNoID0gc3RyZWFtLnBlZWsoKTtcblxuICAgIC8vIENvbW1lbnRcbiAgICBpZiAoc3RyZWFtLm1hdGNoKFwiLypcIikpIHtcbiAgICAgIHN0YXRlLnRva2VuaXplciA9IGNvbW1lbnQoc3RyZWFtLmluZGVudGF0aW9uKCksIHRydWUpO1xuICAgICAgcmV0dXJuIHN0YXRlLnRva2VuaXplcihzdHJlYW0sIHN0YXRlKTtcbiAgICB9XG4gICAgaWYgKHN0cmVhbS5tYXRjaChcIi8vXCIpKSB7XG4gICAgICBzdGF0ZS50b2tlbml6ZXIgPSBjb21tZW50KHN0cmVhbS5pbmRlbnRhdGlvbigpLCBmYWxzZSk7XG4gICAgICByZXR1cm4gc3RhdGUudG9rZW5pemVyKHN0cmVhbSwgc3RhdGUpO1xuICAgIH1cblxuICAgIC8vIEludGVycG9sYXRpb25cbiAgICBpZiAoc3RyZWFtLm1hdGNoKFwiI3tcIikpIHtcbiAgICAgIHN0YXRlLnRva2VuaXplciA9IGJ1aWxkSW50ZXJwb2xhdGlvblRva2VuaXplcih0b2tlbkJhc2UpO1xuICAgICAgcmV0dXJuIFwib3BlcmF0b3JcIjtcbiAgICB9XG5cbiAgICAvLyBTdHJpbmdzXG4gICAgaWYgKGNoID09PSAnXCInIHx8IGNoID09PSBcIidcIikge1xuICAgICAgc3RyZWFtLm5leHQoKTtcbiAgICAgIHN0YXRlLnRva2VuaXplciA9IGJ1aWxkU3RyaW5nVG9rZW5pemVyKGNoKTtcbiAgICAgIHJldHVybiBcInN0cmluZ1wiO1xuICAgIH1cblxuICAgIGlmKCFzdGF0ZS5jdXJzb3JIYWxmKXsvLyBzdGF0ZS5jdXJzb3JIYWxmID09PSAwXG4gICAgLy8gZmlyc3QgaGFsZiBpLmUuIGJlZm9yZSA6IGZvciBrZXktdmFsdWUgcGFpcnNcbiAgICAvLyBpbmNsdWRpbmcgc2VsZWN0b3JzXG5cbiAgICAgIGlmIChjaCA9PT0gXCItXCIpIHtcbiAgICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXi1cXHcrLS8pKSB7XG4gICAgICAgICAgcmV0dXJuIFwibWV0YVwiO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChjaCA9PT0gXCIuXCIpIHtcbiAgICAgICAgc3RyZWFtLm5leHQoKTtcbiAgICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXltcXHctXSsvKSkge1xuICAgICAgICAgIGluZGVudChzdGF0ZSk7XG4gICAgICAgICAgcmV0dXJuIFwicXVhbGlmaWVyXCI7XG4gICAgICAgIH0gZWxzZSBpZiAoc3RyZWFtLnBlZWsoKSA9PT0gXCIjXCIpIHtcbiAgICAgICAgICBpbmRlbnQoc3RhdGUpO1xuICAgICAgICAgIHJldHVybiBcInRhZ1wiO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmIChjaCA9PT0gXCIjXCIpIHtcbiAgICAgICAgc3RyZWFtLm5leHQoKTtcbiAgICAgICAgLy8gSUQgc2VsZWN0b3JzXG4gICAgICAgIGlmIChzdHJlYW0ubWF0Y2goL15bXFx3LV0rLykpIHtcbiAgICAgICAgICBpbmRlbnQoc3RhdGUpO1xuICAgICAgICAgIHJldHVybiBcImJ1aWx0aW5cIjtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc3RyZWFtLnBlZWsoKSA9PT0gXCIjXCIpIHtcbiAgICAgICAgICBpbmRlbnQoc3RhdGUpO1xuICAgICAgICAgIHJldHVybiBcInRhZ1wiO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vIFZhcmlhYmxlc1xuICAgICAgaWYgKGNoID09PSBcIiRcIikge1xuICAgICAgICBzdHJlYW0ubmV4dCgpO1xuICAgICAgICBzdHJlYW0uZWF0V2hpbGUoL1tcXHctXS8pO1xuICAgICAgICByZXR1cm4gXCJ2YXJpYWJsZS0yXCI7XG4gICAgICB9XG5cbiAgICAgIC8vIE51bWJlcnNcbiAgICAgIGlmIChzdHJlYW0ubWF0Y2goL14tP1swLTlcXC5dKy8pKVxuICAgICAgICByZXR1cm4gXCJudW1iZXJcIjtcblxuICAgICAgLy8gVW5pdHNcbiAgICAgIGlmIChzdHJlYW0ubWF0Y2goL14ocHh8ZW18aW4pXFxiLykpXG4gICAgICAgIHJldHVybiBcInVuaXRcIjtcblxuICAgICAgaWYgKHN0cmVhbS5tYXRjaChrZXl3b3Jkc1JlZ2V4cCkpXG4gICAgICAgIHJldHVybiBcImtleXdvcmRcIjtcblxuICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXnVybC8pICYmIHN0cmVhbS5wZWVrKCkgPT09IFwiKFwiKSB7XG4gICAgICAgIHN0YXRlLnRva2VuaXplciA9IHVybFRva2VucztcbiAgICAgICAgcmV0dXJuIFwiYXRvbVwiO1xuICAgICAgfVxuXG4gICAgICBpZiAoY2ggPT09IFwiPVwiKSB7XG4gICAgICAgIC8vIE1hdGNoIHNob3J0Y3V0IG1peGluIGRlZmluaXRpb25cbiAgICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXj1bXFx3LV0rLykpIHtcbiAgICAgICAgICBpbmRlbnQoc3RhdGUpO1xuICAgICAgICAgIHJldHVybiBcIm1ldGFcIjtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBpZiAoY2ggPT09IFwiK1wiKSB7XG4gICAgICAgIC8vIE1hdGNoIHNob3J0Y3V0IG1peGluIGRlZmluaXRpb25cbiAgICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXlxcK1tcXHctXSsvKSl7XG4gICAgICAgICAgcmV0dXJuIFwidmFyaWFibGUtM1wiO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmKGNoID09PSBcIkBcIil7XG4gICAgICAgIGlmKHN0cmVhbS5tYXRjaCgvQGV4dGVuZC8pKXtcbiAgICAgICAgICBpZighc3RyZWFtLm1hdGNoKC9cXHMqW1xcd10vKSlcbiAgICAgICAgICAgIGRlZGVudChzdGF0ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuXG4gICAgICAvLyBJbmRlbnQgRGlyZWN0aXZlc1xuICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXkAoZWxzZSBpZnxpZnxtZWRpYXxlbHNlfGZvcnxlYWNofHdoaWxlfG1peGlufGZ1bmN0aW9uKS8pKSB7XG4gICAgICAgIGluZGVudChzdGF0ZSk7XG4gICAgICAgIHJldHVybiBcImRlZlwiO1xuICAgICAgfVxuXG4gICAgICAvLyBPdGhlciBEaXJlY3RpdmVzXG4gICAgICBpZiAoY2ggPT09IFwiQFwiKSB7XG4gICAgICAgIHN0cmVhbS5uZXh0KCk7XG4gICAgICAgIHN0cmVhbS5lYXRXaGlsZSgvW1xcdy1dLyk7XG4gICAgICAgIHJldHVybiBcImRlZlwiO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3RyZWFtLmVhdFdoaWxlKC9bXFx3LV0vKSl7XG4gICAgICAgIGlmKHN0cmVhbS5tYXRjaCgvICo6ICpbXFx3LVxcK1xcJCMhXFwoXCInXS8sZmFsc2UpKXtcbiAgICAgICAgICB3b3JkID0gc3RyZWFtLmN1cnJlbnQoKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAgIHZhciBwcm9wID0gc3RhdGUucHJldlByb3AgKyBcIi1cIiArIHdvcmQ7XG4gICAgICAgICAgaWYgKHByb3BlcnR5S2V5d29yZHMuaGFzT3duUHJvcGVydHkocHJvcCkpIHtcbiAgICAgICAgICAgIHJldHVybiBcInByb3BlcnR5XCI7XG4gICAgICAgICAgfSBlbHNlIGlmIChwcm9wZXJ0eUtleXdvcmRzLmhhc093blByb3BlcnR5KHdvcmQpKSB7XG4gICAgICAgICAgICBzdGF0ZS5wcmV2UHJvcCA9IHdvcmQ7XG4gICAgICAgICAgICByZXR1cm4gXCJwcm9wZXJ0eVwiO1xuICAgICAgICAgIH0gZWxzZSBpZiAoZm9udFByb3BlcnRpZXMuaGFzT3duUHJvcGVydHkod29yZCkpIHtcbiAgICAgICAgICAgIHJldHVybiBcInByb3BlcnR5XCI7XG4gICAgICAgICAgfVxuICAgICAgICAgIHJldHVybiBcInRhZ1wiO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYoc3RyZWFtLm1hdGNoKC8gKjovLGZhbHNlKSl7XG4gICAgICAgICAgaW5kZW50KHN0YXRlKTtcbiAgICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmID0gMTtcbiAgICAgICAgICBzdGF0ZS5wcmV2UHJvcCA9IHN0cmVhbS5jdXJyZW50KCkudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICByZXR1cm4gXCJwcm9wZXJ0eVwiO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYoc3RyZWFtLm1hdGNoKC8gKiwvLGZhbHNlKSl7XG4gICAgICAgICAgcmV0dXJuIFwidGFnXCI7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZXtcbiAgICAgICAgICBpbmRlbnQoc3RhdGUpO1xuICAgICAgICAgIHJldHVybiBcInRhZ1wiO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGlmKGNoID09PSBcIjpcIil7XG4gICAgICAgIGlmIChzdHJlYW0ubWF0Y2gocHNldWRvRWxlbWVudHNSZWdleHApKXsgLy8gY291bGQgYmUgYSBwc2V1ZG8tZWxlbWVudFxuICAgICAgICAgIHJldHVybiBcInZhcmlhYmxlLTNcIjtcbiAgICAgICAgfVxuICAgICAgICBzdHJlYW0ubmV4dCgpO1xuICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmPTE7XG4gICAgICAgIHJldHVybiBcIm9wZXJhdG9yXCI7XG4gICAgICB9XG5cbiAgICB9IC8vIGN1cnNvckhhbGY9PT0wIGVuZHMgaGVyZVxuICAgIGVsc2V7XG5cbiAgICAgIGlmIChjaCA9PT0gXCIjXCIpIHtcbiAgICAgICAgc3RyZWFtLm5leHQoKTtcbiAgICAgICAgLy8gSGV4IG51bWJlcnNcbiAgICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvWzAtOWEtZkEtRl17Nn18WzAtOWEtZkEtRl17M30vKSl7XG4gICAgICAgICAgaWYgKGlzRW5kTGluZShzdHJlYW0pKSB7XG4gICAgICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmID0gMDtcbiAgICAgICAgICB9XG4gICAgICAgICAgcmV0dXJuIFwibnVtYmVyXCI7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gTnVtYmVyc1xuICAgICAgaWYgKHN0cmVhbS5tYXRjaCgvXi0/WzAtOVxcLl0rLykpe1xuICAgICAgICBpZiAoaXNFbmRMaW5lKHN0cmVhbSkpIHtcbiAgICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmID0gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gXCJudW1iZXJcIjtcbiAgICAgIH1cblxuICAgICAgLy8gVW5pdHNcbiAgICAgIGlmIChzdHJlYW0ubWF0Y2goL14ocHh8ZW18aW4pXFxiLykpe1xuICAgICAgICBpZiAoaXNFbmRMaW5lKHN0cmVhbSkpIHtcbiAgICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmID0gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gXCJ1bml0XCI7XG4gICAgICB9XG5cbiAgICAgIGlmIChzdHJlYW0ubWF0Y2goa2V5d29yZHNSZWdleHApKXtcbiAgICAgICAgaWYgKGlzRW5kTGluZShzdHJlYW0pKSB7XG4gICAgICAgICAgc3RhdGUuY3Vyc29ySGFsZiA9IDA7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIFwia2V5d29yZFwiO1xuICAgICAgfVxuXG4gICAgICBpZiAoc3RyZWFtLm1hdGNoKC9edXJsLykgJiYgc3RyZWFtLnBlZWsoKSA9PT0gXCIoXCIpIHtcbiAgICAgICAgc3RhdGUudG9rZW5pemVyID0gdXJsVG9rZW5zO1xuICAgICAgICBpZiAoaXNFbmRMaW5lKHN0cmVhbSkpIHtcbiAgICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmID0gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gXCJhdG9tXCI7XG4gICAgICB9XG5cbiAgICAgIC8vIFZhcmlhYmxlc1xuICAgICAgaWYgKGNoID09PSBcIiRcIikge1xuICAgICAgICBzdHJlYW0ubmV4dCgpO1xuICAgICAgICBzdHJlYW0uZWF0V2hpbGUoL1tcXHctXS8pO1xuICAgICAgICBpZiAoaXNFbmRMaW5lKHN0cmVhbSkpIHtcbiAgICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmID0gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gXCJ2YXJpYWJsZS0yXCI7XG4gICAgICB9XG5cbiAgICAgIC8vIGJhbmcgY2hhcmFjdGVyIGZvciAhaW1wb3J0YW50LCAhZGVmYXVsdCwgZXRjLlxuICAgICAgaWYgKGNoID09PSBcIiFcIikge1xuICAgICAgICBzdHJlYW0ubmV4dCgpO1xuICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmID0gMDtcbiAgICAgICAgcmV0dXJuIHN0cmVhbS5tYXRjaCgvXltcXHddKy8pID8gXCJrZXl3b3JkXCI6IFwib3BlcmF0b3JcIjtcbiAgICAgIH1cblxuICAgICAgaWYgKHN0cmVhbS5tYXRjaChvcFJlZ2V4cCkpe1xuICAgICAgICBpZiAoaXNFbmRMaW5lKHN0cmVhbSkpIHtcbiAgICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmID0gMDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gXCJvcGVyYXRvclwiO1xuICAgICAgfVxuXG4gICAgICAvLyBhdHRyaWJ1dGVzXG4gICAgICBpZiAoc3RyZWFtLmVhdFdoaWxlKC9bXFx3LV0vKSkge1xuICAgICAgICBpZiAoaXNFbmRMaW5lKHN0cmVhbSkpIHtcbiAgICAgICAgICBzdGF0ZS5jdXJzb3JIYWxmID0gMDtcbiAgICAgICAgfVxuICAgICAgICB3b3JkID0gc3RyZWFtLmN1cnJlbnQoKS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICBpZiAodmFsdWVLZXl3b3Jkcy5oYXNPd25Qcm9wZXJ0eSh3b3JkKSkge1xuICAgICAgICAgIHJldHVybiBcImF0b21cIjtcbiAgICAgICAgfSBlbHNlIGlmIChjb2xvcktleXdvcmRzLmhhc093blByb3BlcnR5KHdvcmQpKSB7XG4gICAgICAgICAgcmV0dXJuIFwia2V5d29yZFwiO1xuICAgICAgICB9IGVsc2UgaWYgKHByb3BlcnR5S2V5d29yZHMuaGFzT3duUHJvcGVydHkod29yZCkpIHtcbiAgICAgICAgICBzdGF0ZS5wcmV2UHJvcCA9IHN0cmVhbS5jdXJyZW50KCkudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICByZXR1cm4gXCJwcm9wZXJ0eVwiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHJldHVybiBcInRhZ1wiO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8vc3RyZWFtLmVhdFNwYWNlKCk7XG4gICAgICBpZiAoaXNFbmRMaW5lKHN0cmVhbSkpIHtcbiAgICAgICAgc3RhdGUuY3Vyc29ySGFsZiA9IDA7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgICAgfVxuXG4gICAgfSAvLyBlbHNlIGVuZHMgaGVyZVxuXG4gICAgaWYgKHN0cmVhbS5tYXRjaChvcFJlZ2V4cCkpXG4gICAgICByZXR1cm4gXCJvcGVyYXRvclwiO1xuXG4gICAgLy8gSWYgd2UgaGF2ZW4ndCByZXR1cm5lZCBieSBub3csIHdlIG1vdmUgMSBjaGFyYWN0ZXJcbiAgICAvLyBhbmQgcmV0dXJuIGFuIGVycm9yXG4gICAgc3RyZWFtLm5leHQoKTtcbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGZ1bmN0aW9uIHRva2VuTGV4ZXIoc3RyZWFtLCBzdGF0ZSkge1xuICAgIGlmIChzdHJlYW0uc29sKCkpIHN0YXRlLmluZGVudENvdW50ID0gMDtcbiAgICB2YXIgc3R5bGUgPSBzdGF0ZS50b2tlbml6ZXIoc3RyZWFtLCBzdGF0ZSk7XG4gICAgdmFyIGN1cnJlbnQgPSBzdHJlYW0uY3VycmVudCgpO1xuXG4gICAgaWYgKGN1cnJlbnQgPT09IFwiQHJldHVyblwiIHx8IGN1cnJlbnQgPT09IFwifVwiKXtcbiAgICAgIGRlZGVudChzdGF0ZSk7XG4gICAgfVxuXG4gICAgaWYgKHN0eWxlICE9PSBudWxsKSB7XG4gICAgICB2YXIgc3RhcnRPZlRva2VuID0gc3RyZWFtLnBvcyAtIGN1cnJlbnQubGVuZ3RoO1xuXG4gICAgICB2YXIgd2l0aEN1cnJlbnRJbmRlbnQgPSBzdGFydE9mVG9rZW4gKyAoY29uZmlnLmluZGVudFVuaXQgKiBzdGF0ZS5pbmRlbnRDb3VudCk7XG5cbiAgICAgIHZhciBuZXdTY29wZXMgPSBbXTtcblxuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBzdGF0ZS5zY29wZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIHNjb3BlID0gc3RhdGUuc2NvcGVzW2ldO1xuXG4gICAgICAgIGlmIChzY29wZS5vZmZzZXQgPD0gd2l0aEN1cnJlbnRJbmRlbnQpXG4gICAgICAgICAgbmV3U2NvcGVzLnB1c2goc2NvcGUpO1xuICAgICAgfVxuXG4gICAgICBzdGF0ZS5zY29wZXMgPSBuZXdTY29wZXM7XG4gICAgfVxuXG5cbiAgICByZXR1cm4gc3R5bGU7XG4gIH1cblxuICByZXR1cm4ge1xuICAgIHN0YXJ0U3RhdGU6IGZ1bmN0aW9uKCkge1xuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdG9rZW5pemVyOiB0b2tlbkJhc2UsXG4gICAgICAgIHNjb3BlczogW3tvZmZzZXQ6IDAsIHR5cGU6IFwic2Fzc1wifV0sXG4gICAgICAgIGluZGVudENvdW50OiAwLFxuICAgICAgICBjdXJzb3JIYWxmOiAwLCAgLy8gY3Vyc29yIGhhbGYgdGVsbHMgdXMgaWYgY3Vyc29yIGxpZXMgYWZ0ZXIgKDEpXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBvciBiZWZvcmUgKDApIGNvbG9uICh3ZWxsLi4uIG1vcmUgb3IgbGVzcylcbiAgICAgICAgZGVmaW5lZFZhcnM6IFtdLFxuICAgICAgICBkZWZpbmVkTWl4aW5zOiBbXVxuICAgICAgfTtcbiAgICB9LFxuICAgIHRva2VuOiBmdW5jdGlvbihzdHJlYW0sIHN0YXRlKSB7XG4gICAgICB2YXIgc3R5bGUgPSB0b2tlbkxleGVyKHN0cmVhbSwgc3RhdGUpO1xuXG4gICAgICBzdGF0ZS5sYXN0VG9rZW4gPSB7IHN0eWxlOiBzdHlsZSwgY29udGVudDogc3RyZWFtLmN1cnJlbnQoKSB9O1xuXG4gICAgICByZXR1cm4gc3R5bGU7XG4gICAgfSxcblxuICAgIGluZGVudDogZnVuY3Rpb24oc3RhdGUpIHtcbiAgICAgIHJldHVybiBzdGF0ZS5zY29wZXNbMF0ub2Zmc2V0O1xuICAgIH1cbiAgfTtcbn0sIFwiY3NzXCIpO1xuXG5Db2RlTWlycm9yLmRlZmluZU1JTUUoXCJ0ZXh0L3gtc2Fzc1wiLCBcInNhc3NcIik7XG5cbn0pO1xuIl19