mapbox.uncompressed.js 1.4 MB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129313031313132313331343135313631373138313931403141314231433144314531463147314831493150315131523153315431553156315731583159316031613162316331643165316631673168316931703171317231733174317531763177317831793180318131823183318431853186318731883189319031913192319331943195319631973198319932003201320232033204320532063207320832093210321132123213321432153216321732183219322032213222322332243225322632273228322932303231323232333234323532363237323832393240324132423243324432453246324732483249325032513252325332543255325632573258325932603261326232633264326532663267326832693270327132723273327432753276327732783279328032813282328332843285328632873288328932903291329232933294329532963297329832993300330133023303330433053306330733083309331033113312331333143315331633173318331933203321332233233324332533263327332833293330333133323333333433353336333733383339334033413342334333443345334633473348334933503351335233533354335533563357335833593360336133623363336433653366336733683369337033713372337333743375337633773378337933803381338233833384338533863387338833893390339133923393339433953396339733983399340034013402340334043405340634073408340934103411341234133414341534163417341834193420342134223423342434253426342734283429343034313432343334343435343634373438343934403441344234433444344534463447344834493450345134523453345434553456345734583459346034613462346334643465346634673468346934703471347234733474347534763477347834793480348134823483348434853486348734883489349034913492349334943495349634973498349935003501350235033504350535063507350835093510351135123513351435153516351735183519352035213522352335243525352635273528352935303531353235333534353535363537353835393540354135423543354435453546354735483549355035513552355335543555355635573558355935603561356235633564356535663567356835693570357135723573357435753576357735783579358035813582358335843585358635873588358935903591359235933594359535963597359835993600360136023603360436053606360736083609361036113612361336143615361636173618361936203621362236233624362536263627362836293630363136323633363436353636363736383639364036413642364336443645364636473648364936503651365236533654365536563657365836593660366136623663366436653666366736683669367036713672367336743675367636773678367936803681368236833684368536863687368836893690369136923693369436953696369736983699370037013702370337043705370637073708370937103711371237133714371537163717371837193720372137223723372437253726372737283729373037313732373337343735373637373738373937403741374237433744374537463747374837493750375137523753375437553756375737583759376037613762376337643765376637673768376937703771377237733774377537763777377837793780378137823783378437853786378737883789379037913792379337943795379637973798379938003801380238033804380538063807380838093810381138123813381438153816381738183819382038213822382338243825382638273828382938303831383238333834383538363837383838393840384138423843384438453846384738483849385038513852385338543855385638573858385938603861386238633864386538663867386838693870387138723873387438753876387738783879388038813882388338843885388638873888388938903891389238933894389538963897389838993900390139023903390439053906390739083909391039113912391339143915391639173918391939203921392239233924392539263927392839293930393139323933393439353936393739383939394039413942394339443945394639473948394939503951395239533954395539563957395839593960396139623963396439653966396739683969397039713972397339743975397639773978397939803981398239833984398539863987398839893990399139923993399439953996399739983999400040014002400340044005400640074008400940104011401240134014401540164017401840194020402140224023402440254026402740284029403040314032403340344035403640374038403940404041404240434044404540464047404840494050405140524053405440554056405740584059406040614062406340644065406640674068406940704071407240734074407540764077407840794080408140824083408440854086408740884089409040914092409340944095409640974098409941004101410241034104410541064107410841094110411141124113411441154116411741184119412041214122412341244125412641274128412941304131413241334134413541364137413841394140414141424143414441454146414741484149415041514152415341544155415641574158415941604161416241634164416541664167416841694170417141724173417441754176417741784179418041814182418341844185418641874188418941904191419241934194419541964197419841994200420142024203420442054206420742084209421042114212421342144215421642174218421942204221422242234224422542264227422842294230423142324233423442354236423742384239424042414242424342444245424642474248424942504251425242534254425542564257425842594260426142624263426442654266426742684269427042714272427342744275427642774278427942804281428242834284428542864287428842894290429142924293429442954296429742984299430043014302430343044305430643074308430943104311431243134314431543164317431843194320432143224323432443254326432743284329433043314332433343344335433643374338433943404341434243434344434543464347434843494350435143524353435443554356435743584359436043614362436343644365436643674368436943704371437243734374437543764377437843794380438143824383438443854386438743884389439043914392439343944395439643974398439944004401440244034404440544064407440844094410441144124413441444154416441744184419442044214422442344244425442644274428442944304431443244334434443544364437443844394440444144424443444444454446444744484449445044514452445344544455445644574458445944604461446244634464446544664467446844694470447144724473447444754476447744784479448044814482448344844485448644874488448944904491449244934494449544964497449844994500450145024503450445054506450745084509451045114512451345144515451645174518451945204521452245234524452545264527452845294530453145324533453445354536453745384539454045414542454345444545454645474548454945504551455245534554455545564557455845594560456145624563456445654566456745684569457045714572457345744575457645774578457945804581458245834584458545864587458845894590459145924593459445954596459745984599460046014602460346044605460646074608460946104611461246134614461546164617461846194620462146224623462446254626462746284629463046314632463346344635463646374638463946404641464246434644464546464647464846494650465146524653465446554656465746584659466046614662466346644665466646674668466946704671467246734674467546764677467846794680468146824683468446854686468746884689469046914692469346944695469646974698469947004701470247034704470547064707470847094710471147124713471447154716471747184719472047214722472347244725472647274728472947304731473247334734473547364737473847394740474147424743474447454746474747484749475047514752475347544755475647574758475947604761476247634764476547664767476847694770477147724773477447754776477747784779478047814782478347844785478647874788478947904791479247934794479547964797479847994800480148024803480448054806480748084809481048114812481348144815481648174818481948204821482248234824482548264827482848294830483148324833483448354836483748384839484048414842484348444845484648474848484948504851485248534854485548564857485848594860486148624863486448654866486748684869487048714872487348744875487648774878487948804881488248834884488548864887488848894890489148924893489448954896489748984899490049014902490349044905490649074908490949104911491249134914491549164917491849194920492149224923492449254926492749284929493049314932493349344935493649374938493949404941494249434944494549464947494849494950495149524953495449554956495749584959496049614962496349644965496649674968496949704971497249734974497549764977497849794980498149824983498449854986498749884989499049914992499349944995499649974998499950005001500250035004500550065007500850095010501150125013501450155016501750185019502050215022502350245025502650275028502950305031503250335034503550365037503850395040504150425043504450455046504750485049505050515052505350545055505650575058505950605061506250635064506550665067506850695070507150725073507450755076507750785079508050815082508350845085508650875088508950905091509250935094509550965097509850995100510151025103510451055106510751085109511051115112511351145115511651175118511951205121512251235124512551265127512851295130513151325133513451355136513751385139514051415142514351445145514651475148514951505151515251535154515551565157515851595160516151625163516451655166516751685169517051715172517351745175517651775178517951805181518251835184518551865187518851895190519151925193519451955196519751985199520052015202520352045205520652075208520952105211521252135214521552165217521852195220522152225223522452255226522752285229523052315232523352345235523652375238523952405241524252435244524552465247524852495250525152525253525452555256525752585259526052615262526352645265526652675268526952705271527252735274527552765277527852795280528152825283528452855286528752885289529052915292529352945295529652975298529953005301530253035304530553065307530853095310531153125313531453155316531753185319532053215322532353245325532653275328532953305331533253335334533553365337533853395340534153425343534453455346534753485349535053515352535353545355535653575358535953605361536253635364536553665367536853695370537153725373537453755376537753785379538053815382538353845385538653875388538953905391539253935394539553965397539853995400540154025403540454055406540754085409541054115412541354145415541654175418541954205421542254235424542554265427542854295430543154325433543454355436543754385439544054415442544354445445544654475448544954505451545254535454545554565457545854595460546154625463546454655466546754685469547054715472547354745475547654775478547954805481548254835484548554865487548854895490549154925493549454955496549754985499550055015502550355045505550655075508550955105511551255135514551555165517551855195520552155225523552455255526552755285529553055315532553355345535553655375538553955405541554255435544554555465547554855495550555155525553555455555556555755585559556055615562556355645565556655675568556955705571557255735574557555765577557855795580558155825583558455855586558755885589559055915592559355945595559655975598559956005601560256035604560556065607560856095610561156125613561456155616561756185619562056215622562356245625562656275628562956305631563256335634563556365637563856395640564156425643564456455646564756485649565056515652565356545655565656575658565956605661566256635664566556665667566856695670567156725673567456755676567756785679568056815682568356845685568656875688568956905691569256935694569556965697569856995700570157025703570457055706570757085709571057115712571357145715571657175718571957205721572257235724572557265727572857295730573157325733573457355736573757385739574057415742574357445745574657475748574957505751575257535754575557565757575857595760576157625763576457655766576757685769577057715772577357745775577657775778577957805781578257835784578557865787578857895790579157925793579457955796579757985799580058015802580358045805580658075808580958105811581258135814581558165817581858195820582158225823582458255826582758285829583058315832583358345835583658375838583958405841584258435844584558465847584858495850585158525853585458555856585758585859586058615862586358645865586658675868586958705871587258735874587558765877587858795880588158825883588458855886588758885889589058915892589358945895589658975898589959005901590259035904590559065907590859095910591159125913591459155916591759185919592059215922592359245925592659275928592959305931593259335934593559365937593859395940594159425943594459455946594759485949595059515952595359545955595659575958595959605961596259635964596559665967596859695970597159725973597459755976597759785979598059815982598359845985598659875988598959905991599259935994599559965997599859996000600160026003600460056006600760086009601060116012601360146015601660176018601960206021602260236024602560266027602860296030603160326033603460356036603760386039604060416042604360446045604660476048604960506051605260536054605560566057605860596060606160626063606460656066606760686069607060716072607360746075607660776078607960806081608260836084608560866087608860896090609160926093609460956096609760986099610061016102610361046105610661076108610961106111611261136114611561166117611861196120612161226123612461256126612761286129613061316132613361346135613661376138613961406141614261436144614561466147614861496150615161526153615461556156615761586159616061616162616361646165616661676168616961706171617261736174617561766177617861796180618161826183618461856186618761886189619061916192619361946195619661976198619962006201620262036204620562066207620862096210621162126213621462156216621762186219622062216222622362246225622662276228622962306231623262336234623562366237623862396240624162426243624462456246624762486249625062516252625362546255625662576258625962606261626262636264626562666267626862696270627162726273627462756276627762786279628062816282628362846285628662876288628962906291629262936294629562966297629862996300630163026303630463056306630763086309631063116312631363146315631663176318631963206321632263236324632563266327632863296330633163326333633463356336633763386339634063416342634363446345634663476348634963506351635263536354635563566357635863596360636163626363636463656366636763686369637063716372637363746375637663776378637963806381638263836384638563866387638863896390639163926393639463956396639763986399640064016402640364046405640664076408640964106411641264136414641564166417641864196420642164226423642464256426642764286429643064316432643364346435643664376438643964406441644264436444644564466447644864496450645164526453645464556456645764586459646064616462646364646465646664676468646964706471647264736474647564766477647864796480648164826483648464856486648764886489649064916492649364946495649664976498649965006501650265036504650565066507650865096510651165126513651465156516651765186519652065216522652365246525652665276528652965306531653265336534653565366537653865396540654165426543654465456546654765486549655065516552655365546555655665576558655965606561656265636564656565666567656865696570657165726573657465756576657765786579658065816582658365846585658665876588658965906591659265936594659565966597659865996600660166026603660466056606660766086609661066116612661366146615661666176618661966206621662266236624662566266627662866296630663166326633663466356636663766386639664066416642664366446645664666476648664966506651665266536654665566566657665866596660666166626663666466656666666766686669667066716672667366746675667666776678667966806681668266836684668566866687668866896690669166926693669466956696669766986699670067016702670367046705670667076708670967106711671267136714671567166717671867196720672167226723672467256726672767286729673067316732673367346735673667376738673967406741674267436744674567466747674867496750675167526753675467556756675767586759676067616762676367646765676667676768676967706771677267736774677567766777677867796780678167826783678467856786678767886789679067916792679367946795679667976798679968006801680268036804680568066807680868096810681168126813681468156816681768186819682068216822682368246825682668276828682968306831683268336834683568366837683868396840684168426843684468456846684768486849685068516852685368546855685668576858685968606861686268636864686568666867686868696870687168726873687468756876687768786879688068816882688368846885688668876888688968906891689268936894689568966897689868996900690169026903690469056906690769086909691069116912691369146915691669176918691969206921692269236924692569266927692869296930693169326933693469356936693769386939694069416942694369446945694669476948694969506951695269536954695569566957695869596960696169626963696469656966696769686969697069716972697369746975697669776978697969806981698269836984698569866987698869896990699169926993699469956996699769986999700070017002700370047005700670077008700970107011701270137014701570167017701870197020702170227023702470257026702770287029703070317032703370347035703670377038703970407041704270437044704570467047704870497050705170527053705470557056705770587059706070617062706370647065706670677068706970707071707270737074707570767077707870797080708170827083708470857086708770887089709070917092709370947095709670977098709971007101710271037104710571067107710871097110711171127113711471157116711771187119712071217122712371247125712671277128712971307131713271337134713571367137713871397140714171427143714471457146714771487149715071517152715371547155715671577158715971607161716271637164716571667167716871697170717171727173717471757176717771787179718071817182718371847185718671877188718971907191719271937194719571967197719871997200720172027203720472057206720772087209721072117212721372147215721672177218721972207221722272237224722572267227722872297230723172327233723472357236723772387239724072417242724372447245724672477248724972507251725272537254725572567257725872597260726172627263726472657266726772687269727072717272727372747275727672777278727972807281728272837284728572867287728872897290729172927293729472957296729772987299730073017302730373047305730673077308730973107311731273137314731573167317731873197320732173227323732473257326732773287329733073317332733373347335733673377338733973407341734273437344734573467347734873497350735173527353735473557356735773587359736073617362736373647365736673677368736973707371737273737374737573767377737873797380738173827383738473857386738773887389739073917392739373947395739673977398739974007401740274037404740574067407740874097410741174127413741474157416741774187419742074217422742374247425742674277428742974307431743274337434743574367437743874397440744174427443744474457446744774487449745074517452745374547455745674577458745974607461746274637464746574667467746874697470747174727473747474757476747774787479748074817482748374847485748674877488748974907491749274937494749574967497749874997500750175027503750475057506750775087509751075117512751375147515751675177518751975207521752275237524752575267527752875297530753175327533753475357536753775387539754075417542754375447545754675477548754975507551755275537554755575567557755875597560756175627563756475657566756775687569757075717572757375747575757675777578757975807581758275837584758575867587758875897590759175927593759475957596759775987599760076017602760376047605760676077608760976107611761276137614761576167617761876197620762176227623762476257626762776287629763076317632763376347635763676377638763976407641764276437644764576467647764876497650765176527653765476557656765776587659766076617662766376647665766676677668766976707671767276737674767576767677767876797680768176827683768476857686768776887689769076917692769376947695769676977698769977007701770277037704770577067707770877097710771177127713771477157716771777187719772077217722772377247725772677277728772977307731773277337734773577367737773877397740774177427743774477457746774777487749775077517752775377547755775677577758775977607761776277637764776577667767776877697770777177727773777477757776777777787779778077817782778377847785778677877788778977907791779277937794779577967797779877997800780178027803780478057806780778087809781078117812781378147815781678177818781978207821782278237824782578267827782878297830783178327833783478357836783778387839784078417842784378447845784678477848784978507851785278537854785578567857785878597860786178627863786478657866786778687869787078717872787378747875787678777878787978807881788278837884788578867887788878897890789178927893789478957896789778987899790079017902790379047905790679077908790979107911791279137914791579167917791879197920792179227923792479257926792779287929793079317932793379347935793679377938793979407941794279437944794579467947794879497950795179527953795479557956795779587959796079617962796379647965796679677968796979707971797279737974797579767977797879797980798179827983798479857986798779887989799079917992799379947995799679977998799980008001800280038004800580068007800880098010801180128013801480158016801780188019802080218022802380248025802680278028802980308031803280338034803580368037803880398040804180428043804480458046804780488049805080518052805380548055805680578058805980608061806280638064806580668067806880698070807180728073807480758076807780788079808080818082808380848085808680878088808980908091809280938094809580968097809880998100810181028103810481058106810781088109811081118112811381148115811681178118811981208121812281238124812581268127812881298130813181328133813481358136813781388139814081418142814381448145814681478148814981508151815281538154815581568157815881598160816181628163816481658166816781688169817081718172817381748175817681778178817981808181818281838184818581868187818881898190819181928193819481958196819781988199820082018202820382048205820682078208820982108211821282138214821582168217821882198220822182228223822482258226822782288229823082318232823382348235823682378238823982408241824282438244824582468247824882498250825182528253825482558256825782588259826082618262826382648265826682678268826982708271827282738274827582768277827882798280828182828283828482858286828782888289829082918292829382948295829682978298829983008301830283038304830583068307830883098310831183128313831483158316831783188319832083218322832383248325832683278328832983308331833283338334833583368337833883398340834183428343834483458346834783488349835083518352835383548355835683578358835983608361836283638364836583668367836883698370837183728373837483758376837783788379838083818382838383848385838683878388838983908391839283938394839583968397839883998400840184028403840484058406840784088409841084118412841384148415841684178418841984208421842284238424842584268427842884298430843184328433843484358436843784388439844084418442844384448445844684478448844984508451845284538454845584568457845884598460846184628463846484658466846784688469847084718472847384748475847684778478847984808481848284838484848584868487848884898490849184928493849484958496849784988499850085018502850385048505850685078508850985108511851285138514851585168517851885198520852185228523852485258526852785288529853085318532853385348535853685378538853985408541854285438544854585468547854885498550855185528553855485558556855785588559856085618562856385648565856685678568856985708571857285738574857585768577857885798580858185828583858485858586858785888589859085918592859385948595859685978598859986008601860286038604860586068607860886098610861186128613861486158616861786188619862086218622862386248625862686278628862986308631863286338634863586368637863886398640864186428643864486458646864786488649865086518652865386548655865686578658865986608661866286638664866586668667866886698670867186728673867486758676867786788679868086818682868386848685868686878688868986908691869286938694869586968697869886998700870187028703870487058706870787088709871087118712871387148715871687178718871987208721872287238724872587268727872887298730873187328733873487358736873787388739874087418742874387448745874687478748874987508751875287538754875587568757875887598760876187628763876487658766876787688769877087718772877387748775877687778778877987808781878287838784878587868787878887898790879187928793879487958796879787988799880088018802880388048805880688078808880988108811881288138814881588168817881888198820882188228823882488258826882788288829883088318832883388348835883688378838883988408841884288438844884588468847884888498850885188528853885488558856885788588859886088618862886388648865886688678868886988708871887288738874887588768877887888798880888188828883888488858886888788888889889088918892889388948895889688978898889989008901890289038904890589068907890889098910891189128913891489158916891789188919892089218922892389248925892689278928892989308931893289338934893589368937893889398940894189428943894489458946894789488949895089518952895389548955895689578958895989608961896289638964896589668967896889698970897189728973897489758976897789788979898089818982898389848985898689878988898989908991899289938994899589968997899889999000900190029003900490059006900790089009901090119012901390149015901690179018901990209021902290239024902590269027902890299030903190329033903490359036903790389039904090419042904390449045904690479048904990509051905290539054905590569057905890599060906190629063906490659066906790689069907090719072907390749075907690779078907990809081908290839084908590869087908890899090909190929093909490959096909790989099910091019102910391049105910691079108910991109111911291139114911591169117911891199120912191229123912491259126912791289129913091319132913391349135913691379138913991409141914291439144914591469147914891499150915191529153915491559156915791589159916091619162916391649165916691679168916991709171917291739174917591769177917891799180918191829183918491859186918791889189919091919192919391949195919691979198919992009201920292039204920592069207920892099210921192129213921492159216921792189219922092219222922392249225922692279228922992309231923292339234923592369237923892399240924192429243924492459246924792489249925092519252925392549255925692579258925992609261926292639264926592669267926892699270927192729273927492759276927792789279928092819282928392849285928692879288928992909291929292939294929592969297929892999300930193029303930493059306930793089309931093119312931393149315931693179318931993209321932293239324932593269327932893299330933193329333933493359336933793389339934093419342934393449345934693479348934993509351935293539354935593569357935893599360936193629363936493659366936793689369937093719372937393749375937693779378937993809381938293839384938593869387938893899390939193929393939493959396939793989399940094019402940394049405940694079408940994109411941294139414941594169417941894199420942194229423942494259426942794289429943094319432943394349435943694379438943994409441944294439444944594469447944894499450945194529453945494559456945794589459946094619462946394649465946694679468946994709471947294739474947594769477947894799480948194829483948494859486948794889489949094919492949394949495949694979498949995009501950295039504950595069507950895099510951195129513951495159516951795189519952095219522952395249525952695279528952995309531953295339534953595369537953895399540954195429543954495459546954795489549955095519552955395549555955695579558955995609561956295639564956595669567956895699570957195729573957495759576957795789579958095819582958395849585958695879588958995909591959295939594959595969597959895999600960196029603960496059606960796089609961096119612961396149615961696179618961996209621962296239624962596269627962896299630963196329633963496359636963796389639964096419642964396449645964696479648964996509651965296539654965596569657965896599660966196629663966496659666966796689669967096719672967396749675967696779678967996809681968296839684968596869687968896899690969196929693969496959696969796989699970097019702970397049705970697079708970997109711971297139714971597169717971897199720972197229723972497259726972797289729973097319732973397349735973697379738973997409741974297439744974597469747974897499750975197529753975497559756975797589759976097619762976397649765976697679768976997709771977297739774977597769777977897799780978197829783978497859786978797889789979097919792979397949795979697979798979998009801980298039804980598069807980898099810981198129813981498159816981798189819982098219822982398249825982698279828982998309831983298339834983598369837983898399840984198429843984498459846984798489849985098519852985398549855985698579858985998609861986298639864986598669867986898699870987198729873987498759876987798789879988098819882988398849885988698879888988998909891989298939894989598969897989898999900990199029903990499059906990799089909991099119912991399149915991699179918991999209921992299239924992599269927992899299930993199329933993499359936993799389939994099419942994399449945994699479948994999509951995299539954995599569957995899599960996199629963996499659966996799689969997099719972997399749975997699779978997999809981998299839984998599869987998899899990999199929993999499959996999799989999100001000110002100031000410005100061000710008100091001010011100121001310014100151001610017100181001910020100211002210023100241002510026100271002810029100301003110032100331003410035100361003710038100391004010041100421004310044100451004610047100481004910050100511005210053100541005510056100571005810059100601006110062100631006410065100661006710068100691007010071100721007310074100751007610077100781007910080100811008210083100841008510086100871008810089100901009110092100931009410095100961009710098100991010010101101021010310104101051010610107101081010910110101111011210113101141011510116101171011810119101201012110122101231012410125101261012710128101291013010131101321013310134101351013610137101381013910140101411014210143101441014510146101471014810149101501015110152101531015410155101561015710158101591016010161101621016310164101651016610167101681016910170101711017210173101741017510176101771017810179101801018110182101831018410185101861018710188101891019010191101921019310194101951019610197101981019910200102011020210203102041020510206102071020810209102101021110212102131021410215102161021710218102191022010221102221022310224102251022610227102281022910230102311023210233102341023510236102371023810239102401024110242102431024410245102461024710248102491025010251102521025310254102551025610257102581025910260102611026210263102641026510266102671026810269102701027110272102731027410275102761027710278102791028010281102821028310284102851028610287102881028910290102911029210293102941029510296102971029810299103001030110302103031030410305103061030710308103091031010311103121031310314103151031610317103181031910320103211032210323103241032510326103271032810329103301033110332103331033410335103361033710338103391034010341103421034310344103451034610347103481034910350103511035210353103541035510356103571035810359103601036110362103631036410365103661036710368103691037010371103721037310374103751037610377103781037910380103811038210383103841038510386103871038810389103901039110392103931039410395103961039710398103991040010401104021040310404104051040610407104081040910410104111041210413104141041510416104171041810419104201042110422104231042410425104261042710428104291043010431104321043310434104351043610437104381043910440104411044210443104441044510446104471044810449104501045110452104531045410455104561045710458104591046010461104621046310464104651046610467104681046910470104711047210473104741047510476104771047810479104801048110482104831048410485104861048710488104891049010491104921049310494104951049610497104981049910500105011050210503105041050510506105071050810509105101051110512105131051410515105161051710518105191052010521105221052310524105251052610527105281052910530105311053210533105341053510536105371053810539105401054110542105431054410545105461054710548105491055010551105521055310554105551055610557105581055910560105611056210563105641056510566105671056810569105701057110572105731057410575105761057710578105791058010581105821058310584105851058610587105881058910590105911059210593105941059510596105971059810599106001060110602106031060410605106061060710608106091061010611106121061310614106151061610617106181061910620106211062210623106241062510626106271062810629106301063110632106331063410635106361063710638106391064010641106421064310644106451064610647106481064910650106511065210653106541065510656106571065810659106601066110662106631066410665106661066710668106691067010671106721067310674106751067610677106781067910680106811068210683106841068510686106871068810689106901069110692106931069410695106961069710698106991070010701107021070310704107051070610707107081070910710107111071210713107141071510716107171071810719107201072110722107231072410725107261072710728107291073010731107321073310734107351073610737107381073910740107411074210743107441074510746107471074810749107501075110752107531075410755107561075710758107591076010761107621076310764107651076610767107681076910770107711077210773107741077510776107771077810779107801078110782107831078410785107861078710788107891079010791107921079310794107951079610797107981079910800108011080210803108041080510806108071080810809108101081110812108131081410815108161081710818108191082010821108221082310824108251082610827108281082910830108311083210833108341083510836108371083810839108401084110842108431084410845108461084710848108491085010851108521085310854108551085610857108581085910860108611086210863108641086510866108671086810869108701087110872108731087410875108761087710878108791088010881108821088310884108851088610887108881088910890108911089210893108941089510896108971089810899109001090110902109031090410905109061090710908109091091010911109121091310914109151091610917109181091910920109211092210923109241092510926109271092810929109301093110932109331093410935109361093710938109391094010941109421094310944109451094610947109481094910950109511095210953109541095510956109571095810959109601096110962109631096410965109661096710968109691097010971109721097310974109751097610977109781097910980109811098210983109841098510986109871098810989109901099110992109931099410995109961099710998109991100011001110021100311004110051100611007110081100911010110111101211013110141101511016110171101811019110201102111022110231102411025110261102711028110291103011031110321103311034110351103611037110381103911040110411104211043110441104511046110471104811049110501105111052110531105411055110561105711058110591106011061110621106311064110651106611067110681106911070110711107211073110741107511076110771107811079110801108111082110831108411085110861108711088110891109011091110921109311094110951109611097110981109911100111011110211103111041110511106111071110811109111101111111112111131111411115111161111711118111191112011121111221112311124111251112611127111281112911130111311113211133111341113511136111371113811139111401114111142111431114411145111461114711148111491115011151111521115311154111551115611157111581115911160111611116211163111641116511166111671116811169111701117111172111731117411175111761117711178111791118011181111821118311184111851118611187111881118911190111911119211193111941119511196111971119811199112001120111202112031120411205112061120711208112091121011211112121121311214112151121611217112181121911220112211122211223112241122511226112271122811229112301123111232112331123411235112361123711238112391124011241112421124311244112451124611247112481124911250112511125211253112541125511256112571125811259112601126111262112631126411265112661126711268112691127011271112721127311274112751127611277112781127911280112811128211283112841128511286112871128811289112901129111292112931129411295112961129711298112991130011301113021130311304113051130611307113081130911310113111131211313113141131511316113171131811319113201132111322113231132411325113261132711328113291133011331113321133311334113351133611337113381133911340113411134211343113441134511346113471134811349113501135111352113531135411355113561135711358113591136011361113621136311364113651136611367113681136911370113711137211373113741137511376113771137811379113801138111382113831138411385113861138711388113891139011391113921139311394113951139611397113981139911400114011140211403114041140511406114071140811409114101141111412114131141411415114161141711418114191142011421114221142311424114251142611427114281142911430114311143211433114341143511436114371143811439114401144111442114431144411445114461144711448114491145011451114521145311454114551145611457114581145911460114611146211463114641146511466114671146811469114701147111472114731147411475114761147711478114791148011481114821148311484114851148611487114881148911490114911149211493114941149511496114971149811499115001150111502115031150411505115061150711508115091151011511115121151311514115151151611517115181151911520115211152211523115241152511526115271152811529115301153111532115331153411535115361153711538115391154011541115421154311544115451154611547115481154911550115511155211553115541155511556115571155811559115601156111562115631156411565115661156711568115691157011571115721157311574115751157611577115781157911580115811158211583115841158511586115871158811589115901159111592115931159411595115961159711598115991160011601116021160311604116051160611607116081160911610116111161211613116141161511616116171161811619116201162111622116231162411625116261162711628116291163011631116321163311634116351163611637116381163911640116411164211643116441164511646116471164811649116501165111652116531165411655116561165711658116591166011661116621166311664116651166611667116681166911670116711167211673116741167511676116771167811679116801168111682116831168411685116861168711688116891169011691116921169311694116951169611697116981169911700117011170211703117041170511706117071170811709117101171111712117131171411715117161171711718117191172011721117221172311724117251172611727117281172911730117311173211733117341173511736117371173811739117401174111742117431174411745117461174711748117491175011751117521175311754117551175611757117581175911760117611176211763117641176511766117671176811769117701177111772117731177411775117761177711778117791178011781117821178311784117851178611787117881178911790117911179211793117941179511796117971179811799118001180111802118031180411805118061180711808118091181011811118121181311814118151181611817118181181911820118211182211823118241182511826118271182811829118301183111832118331183411835118361183711838118391184011841118421184311844118451184611847118481184911850118511185211853118541185511856118571185811859118601186111862118631186411865118661186711868118691187011871118721187311874118751187611877118781187911880118811188211883118841188511886118871188811889118901189111892118931189411895118961189711898118991190011901119021190311904119051190611907119081190911910119111191211913119141191511916119171191811919119201192111922119231192411925119261192711928119291193011931119321193311934119351193611937119381193911940119411194211943119441194511946119471194811949119501195111952119531195411955119561195711958119591196011961119621196311964119651196611967119681196911970119711197211973119741197511976119771197811979119801198111982119831198411985119861198711988119891199011991119921199311994119951199611997119981199912000120011200212003120041200512006120071200812009120101201112012120131201412015120161201712018120191202012021120221202312024120251202612027120281202912030120311203212033120341203512036120371203812039120401204112042120431204412045120461204712048120491205012051120521205312054120551205612057120581205912060120611206212063120641206512066120671206812069120701207112072120731207412075120761207712078120791208012081120821208312084120851208612087120881208912090120911209212093120941209512096120971209812099121001210112102121031210412105121061210712108121091211012111121121211312114121151211612117121181211912120121211212212123121241212512126121271212812129121301213112132121331213412135121361213712138121391214012141121421214312144121451214612147121481214912150121511215212153121541215512156121571215812159121601216112162121631216412165121661216712168121691217012171121721217312174121751217612177121781217912180121811218212183121841218512186121871218812189121901219112192121931219412195121961219712198121991220012201122021220312204122051220612207122081220912210122111221212213122141221512216122171221812219122201222112222122231222412225122261222712228122291223012231122321223312234122351223612237122381223912240122411224212243122441224512246122471224812249122501225112252122531225412255122561225712258122591226012261122621226312264122651226612267122681226912270122711227212273122741227512276122771227812279122801228112282122831228412285122861228712288122891229012291122921229312294122951229612297122981229912300123011230212303123041230512306123071230812309123101231112312123131231412315123161231712318123191232012321123221232312324123251232612327123281232912330123311233212333123341233512336123371233812339123401234112342123431234412345123461234712348123491235012351123521235312354123551235612357123581235912360123611236212363123641236512366123671236812369123701237112372123731237412375123761237712378123791238012381123821238312384123851238612387123881238912390123911239212393123941239512396123971239812399124001240112402124031240412405124061240712408124091241012411124121241312414124151241612417124181241912420124211242212423124241242512426124271242812429124301243112432124331243412435124361243712438124391244012441124421244312444124451244612447124481244912450124511245212453124541245512456124571245812459124601246112462124631246412465124661246712468124691247012471124721247312474124751247612477124781247912480124811248212483124841248512486124871248812489124901249112492124931249412495124961249712498124991250012501125021250312504125051250612507125081250912510125111251212513125141251512516125171251812519125201252112522125231252412525125261252712528125291253012531125321253312534125351253612537125381253912540125411254212543125441254512546125471254812549125501255112552125531255412555125561255712558125591256012561125621256312564125651256612567125681256912570125711257212573125741257512576125771257812579125801258112582125831258412585125861258712588125891259012591125921259312594125951259612597125981259912600126011260212603126041260512606126071260812609126101261112612126131261412615126161261712618126191262012621126221262312624126251262612627126281262912630126311263212633126341263512636126371263812639126401264112642126431264412645126461264712648126491265012651126521265312654126551265612657126581265912660126611266212663126641266512666126671266812669126701267112672126731267412675126761267712678126791268012681126821268312684126851268612687126881268912690126911269212693126941269512696126971269812699127001270112702127031270412705127061270712708127091271012711127121271312714127151271612717127181271912720127211272212723127241272512726127271272812729127301273112732127331273412735127361273712738127391274012741127421274312744127451274612747127481274912750127511275212753127541275512756127571275812759127601276112762127631276412765127661276712768127691277012771127721277312774127751277612777127781277912780127811278212783127841278512786127871278812789127901279112792127931279412795127961279712798127991280012801128021280312804128051280612807128081280912810128111281212813128141281512816128171281812819128201282112822128231282412825128261282712828128291283012831128321283312834128351283612837128381283912840128411284212843128441284512846128471284812849128501285112852128531285412855128561285712858128591286012861128621286312864128651286612867128681286912870128711287212873128741287512876128771287812879128801288112882128831288412885128861288712888128891289012891128921289312894128951289612897128981289912900129011290212903129041290512906129071290812909129101291112912129131291412915129161291712918129191292012921129221292312924129251292612927129281292912930129311293212933129341293512936129371293812939129401294112942129431294412945129461294712948129491295012951129521295312954129551295612957129581295912960129611296212963129641296512966129671296812969129701297112972129731297412975129761297712978129791298012981129821298312984129851298612987129881298912990129911299212993129941299512996129971299812999130001300113002130031300413005130061300713008130091301013011130121301313014130151301613017130181301913020130211302213023130241302513026130271302813029130301303113032130331303413035130361303713038130391304013041130421304313044130451304613047130481304913050130511305213053130541305513056130571305813059130601306113062130631306413065130661306713068130691307013071130721307313074130751307613077130781307913080130811308213083130841308513086130871308813089130901309113092130931309413095130961309713098130991310013101131021310313104131051310613107131081310913110131111311213113131141311513116131171311813119131201312113122131231312413125131261312713128131291313013131131321313313134131351313613137131381313913140131411314213143131441314513146131471314813149131501315113152131531315413155131561315713158131591316013161131621316313164131651316613167131681316913170131711317213173131741317513176131771317813179131801318113182131831318413185131861318713188131891319013191131921319313194131951319613197131981319913200132011320213203132041320513206132071320813209132101321113212132131321413215132161321713218132191322013221132221322313224132251322613227132281322913230132311323213233132341323513236132371323813239132401324113242132431324413245132461324713248132491325013251132521325313254132551325613257132581325913260132611326213263132641326513266132671326813269132701327113272132731327413275132761327713278132791328013281132821328313284132851328613287132881328913290132911329213293132941329513296132971329813299133001330113302133031330413305133061330713308133091331013311133121331313314133151331613317133181331913320133211332213323133241332513326133271332813329133301333113332133331333413335133361333713338133391334013341133421334313344133451334613347133481334913350133511335213353133541335513356133571335813359133601336113362133631336413365133661336713368133691337013371133721337313374133751337613377133781337913380133811338213383133841338513386133871338813389133901339113392133931339413395133961339713398133991340013401134021340313404134051340613407134081340913410134111341213413134141341513416134171341813419134201342113422134231342413425134261342713428134291343013431134321343313434134351343613437134381343913440134411344213443134441344513446134471344813449134501345113452134531345413455134561345713458134591346013461134621346313464134651346613467134681346913470134711347213473134741347513476134771347813479134801348113482134831348413485134861348713488134891349013491134921349313494134951349613497134981349913500135011350213503135041350513506135071350813509135101351113512135131351413515135161351713518135191352013521135221352313524135251352613527135281352913530135311353213533135341353513536135371353813539135401354113542135431354413545135461354713548135491355013551135521355313554135551355613557135581355913560135611356213563135641356513566135671356813569135701357113572135731357413575135761357713578135791358013581135821358313584135851358613587135881358913590135911359213593135941359513596135971359813599136001360113602136031360413605136061360713608136091361013611136121361313614136151361613617136181361913620136211362213623136241362513626136271362813629136301363113632136331363413635136361363713638136391364013641136421364313644136451364613647136481364913650136511365213653136541365513656136571365813659136601366113662136631366413665136661366713668136691367013671136721367313674136751367613677136781367913680136811368213683136841368513686136871368813689136901369113692136931369413695136961369713698136991370013701137021370313704137051370613707137081370913710137111371213713137141371513716137171371813719137201372113722137231372413725137261372713728137291373013731137321373313734137351373613737137381373913740137411374213743137441374513746137471374813749137501375113752137531375413755137561375713758137591376013761137621376313764137651376613767137681376913770137711377213773137741377513776137771377813779137801378113782137831378413785137861378713788137891379013791137921379313794137951379613797137981379913800138011380213803138041380513806138071380813809138101381113812138131381413815138161381713818138191382013821138221382313824138251382613827138281382913830138311383213833138341383513836138371383813839138401384113842138431384413845138461384713848138491385013851138521385313854138551385613857138581385913860138611386213863138641386513866138671386813869138701387113872138731387413875138761387713878138791388013881138821388313884138851388613887138881388913890138911389213893138941389513896138971389813899139001390113902139031390413905139061390713908139091391013911139121391313914139151391613917139181391913920139211392213923139241392513926139271392813929139301393113932139331393413935139361393713938139391394013941139421394313944139451394613947139481394913950139511395213953139541395513956139571395813959139601396113962139631396413965139661396713968139691397013971139721397313974139751397613977139781397913980139811398213983139841398513986139871398813989139901399113992139931399413995139961399713998139991400014001140021400314004140051400614007140081400914010140111401214013140141401514016140171401814019140201402114022140231402414025140261402714028140291403014031140321403314034140351403614037140381403914040140411404214043140441404514046140471404814049140501405114052140531405414055140561405714058140591406014061140621406314064140651406614067140681406914070140711407214073140741407514076140771407814079140801408114082140831408414085140861408714088140891409014091140921409314094140951409614097140981409914100141011410214103141041410514106141071410814109141101411114112141131411414115141161411714118141191412014121141221412314124141251412614127141281412914130141311413214133141341413514136141371413814139141401414114142141431414414145141461414714148141491415014151141521415314154141551415614157141581415914160141611416214163141641416514166141671416814169141701417114172141731417414175141761417714178141791418014181141821418314184141851418614187141881418914190141911419214193141941419514196141971419814199142001420114202142031420414205142061420714208142091421014211142121421314214142151421614217142181421914220142211422214223142241422514226142271422814229142301423114232142331423414235142361423714238142391424014241142421424314244142451424614247142481424914250142511425214253142541425514256142571425814259142601426114262142631426414265142661426714268142691427014271142721427314274142751427614277142781427914280142811428214283142841428514286142871428814289142901429114292142931429414295142961429714298142991430014301143021430314304143051430614307143081430914310143111431214313143141431514316143171431814319143201432114322143231432414325143261432714328143291433014331143321433314334143351433614337143381433914340143411434214343143441434514346143471434814349143501435114352143531435414355143561435714358143591436014361143621436314364143651436614367143681436914370143711437214373143741437514376143771437814379143801438114382143831438414385143861438714388143891439014391143921439314394143951439614397143981439914400144011440214403144041440514406144071440814409144101441114412144131441414415144161441714418144191442014421144221442314424144251442614427144281442914430144311443214433144341443514436144371443814439144401444114442144431444414445144461444714448144491445014451144521445314454144551445614457144581445914460144611446214463144641446514466144671446814469144701447114472144731447414475144761447714478144791448014481144821448314484144851448614487144881448914490144911449214493144941449514496144971449814499145001450114502145031450414505145061450714508145091451014511145121451314514145151451614517145181451914520145211452214523145241452514526145271452814529145301453114532145331453414535145361453714538145391454014541145421454314544145451454614547145481454914550145511455214553145541455514556145571455814559145601456114562145631456414565145661456714568145691457014571145721457314574145751457614577145781457914580145811458214583145841458514586145871458814589145901459114592145931459414595145961459714598145991460014601146021460314604146051460614607146081460914610146111461214613146141461514616146171461814619146201462114622146231462414625146261462714628146291463014631146321463314634146351463614637146381463914640146411464214643146441464514646146471464814649146501465114652146531465414655146561465714658146591466014661146621466314664146651466614667146681466914670146711467214673146741467514676146771467814679146801468114682146831468414685146861468714688146891469014691146921469314694146951469614697146981469914700147011470214703147041470514706147071470814709147101471114712147131471414715147161471714718147191472014721147221472314724147251472614727147281472914730147311473214733147341473514736147371473814739147401474114742147431474414745147461474714748147491475014751147521475314754147551475614757147581475914760147611476214763147641476514766147671476814769147701477114772147731477414775147761477714778147791478014781147821478314784147851478614787147881478914790147911479214793147941479514796147971479814799148001480114802148031480414805148061480714808148091481014811148121481314814148151481614817148181481914820148211482214823148241482514826148271482814829148301483114832148331483414835148361483714838148391484014841148421484314844148451484614847148481484914850148511485214853148541485514856148571485814859148601486114862148631486414865148661486714868148691487014871148721487314874148751487614877148781487914880148811488214883148841488514886148871488814889148901489114892148931489414895148961489714898148991490014901149021490314904149051490614907149081490914910149111491214913149141491514916149171491814919149201492114922149231492414925149261492714928149291493014931149321493314934149351493614937149381493914940149411494214943149441494514946149471494814949149501495114952149531495414955149561495714958149591496014961149621496314964149651496614967149681496914970149711497214973149741497514976149771497814979149801498114982149831498414985149861498714988149891499014991149921499314994149951499614997149981499915000150011500215003150041500515006150071500815009150101501115012150131501415015150161501715018150191502015021150221502315024150251502615027150281502915030150311503215033150341503515036150371503815039150401504115042150431504415045150461504715048150491505015051150521505315054150551505615057150581505915060150611506215063150641506515066150671506815069150701507115072150731507415075150761507715078150791508015081150821508315084150851508615087150881508915090150911509215093150941509515096150971509815099151001510115102151031510415105151061510715108151091511015111151121511315114151151511615117151181511915120151211512215123151241512515126151271512815129151301513115132151331513415135151361513715138151391514015141151421514315144151451514615147151481514915150151511515215153151541515515156151571515815159151601516115162151631516415165151661516715168151691517015171151721517315174151751517615177151781517915180151811518215183151841518515186151871518815189151901519115192151931519415195151961519715198151991520015201152021520315204152051520615207152081520915210152111521215213152141521515216152171521815219152201522115222152231522415225152261522715228152291523015231152321523315234152351523615237152381523915240152411524215243152441524515246152471524815249152501525115252152531525415255152561525715258152591526015261152621526315264152651526615267152681526915270152711527215273152741527515276152771527815279152801528115282152831528415285152861528715288152891529015291152921529315294152951529615297152981529915300153011530215303153041530515306153071530815309153101531115312153131531415315153161531715318153191532015321153221532315324153251532615327153281532915330153311533215333153341533515336153371533815339153401534115342153431534415345153461534715348153491535015351153521535315354153551535615357153581535915360153611536215363153641536515366153671536815369153701537115372153731537415375153761537715378153791538015381153821538315384153851538615387153881538915390153911539215393153941539515396153971539815399154001540115402154031540415405154061540715408154091541015411154121541315414154151541615417154181541915420154211542215423154241542515426154271542815429154301543115432154331543415435154361543715438154391544015441154421544315444154451544615447154481544915450154511545215453154541545515456154571545815459154601546115462154631546415465154661546715468154691547015471154721547315474154751547615477154781547915480154811548215483154841548515486154871548815489154901549115492154931549415495154961549715498154991550015501155021550315504155051550615507155081550915510155111551215513155141551515516155171551815519155201552115522155231552415525155261552715528155291553015531155321553315534155351553615537155381553915540155411554215543155441554515546155471554815549155501555115552155531555415555155561555715558155591556015561155621556315564155651556615567155681556915570155711557215573155741557515576155771557815579155801558115582155831558415585155861558715588155891559015591155921559315594155951559615597155981559915600156011560215603156041560515606156071560815609156101561115612156131561415615156161561715618156191562015621156221562315624156251562615627156281562915630156311563215633156341563515636156371563815639156401564115642156431564415645156461564715648156491565015651156521565315654156551565615657156581565915660156611566215663156641566515666156671566815669156701567115672156731567415675156761567715678156791568015681156821568315684156851568615687156881568915690156911569215693156941569515696156971569815699157001570115702157031570415705157061570715708157091571015711157121571315714157151571615717157181571915720157211572215723157241572515726157271572815729157301573115732157331573415735157361573715738157391574015741157421574315744157451574615747157481574915750157511575215753157541575515756157571575815759157601576115762157631576415765157661576715768157691577015771157721577315774157751577615777157781577915780157811578215783157841578515786157871578815789157901579115792157931579415795157961579715798157991580015801158021580315804158051580615807158081580915810158111581215813158141581515816158171581815819158201582115822158231582415825158261582715828158291583015831158321583315834158351583615837158381583915840158411584215843158441584515846158471584815849158501585115852158531585415855158561585715858158591586015861158621586315864158651586615867158681586915870158711587215873158741587515876158771587815879158801588115882158831588415885158861588715888158891589015891158921589315894158951589615897158981589915900159011590215903159041590515906159071590815909159101591115912159131591415915159161591715918159191592015921159221592315924159251592615927159281592915930159311593215933159341593515936159371593815939159401594115942159431594415945159461594715948159491595015951159521595315954159551595615957159581595915960159611596215963159641596515966159671596815969159701597115972159731597415975159761597715978159791598015981159821598315984159851598615987159881598915990159911599215993159941599515996159971599815999160001600116002160031600416005160061600716008160091601016011160121601316014160151601616017160181601916020160211602216023160241602516026160271602816029160301603116032160331603416035160361603716038160391604016041160421604316044160451604616047160481604916050160511605216053160541605516056160571605816059160601606116062160631606416065160661606716068160691607016071160721607316074160751607616077160781607916080160811608216083160841608516086160871608816089160901609116092160931609416095160961609716098160991610016101161021610316104161051610616107161081610916110161111611216113161141611516116161171611816119161201612116122161231612416125161261612716128161291613016131161321613316134161351613616137161381613916140161411614216143161441614516146161471614816149161501615116152161531615416155161561615716158161591616016161161621616316164161651616616167161681616916170161711617216173161741617516176161771617816179161801618116182161831618416185161861618716188161891619016191161921619316194161951619616197161981619916200162011620216203162041620516206162071620816209162101621116212162131621416215162161621716218162191622016221162221622316224162251622616227162281622916230162311623216233162341623516236162371623816239162401624116242162431624416245162461624716248162491625016251162521625316254162551625616257162581625916260162611626216263162641626516266162671626816269162701627116272162731627416275162761627716278162791628016281162821628316284162851628616287162881628916290162911629216293162941629516296162971629816299163001630116302163031630416305163061630716308163091631016311163121631316314163151631616317163181631916320163211632216323163241632516326163271632816329163301633116332163331633416335163361633716338163391634016341163421634316344163451634616347163481634916350163511635216353163541635516356163571635816359163601636116362163631636416365163661636716368163691637016371163721637316374163751637616377163781637916380163811638216383163841638516386163871638816389163901639116392163931639416395163961639716398163991640016401164021640316404164051640616407164081640916410164111641216413164141641516416164171641816419164201642116422164231642416425164261642716428164291643016431164321643316434164351643616437164381643916440164411644216443164441644516446164471644816449164501645116452164531645416455164561645716458164591646016461164621646316464164651646616467164681646916470164711647216473164741647516476164771647816479164801648116482164831648416485164861648716488164891649016491164921649316494164951649616497164981649916500165011650216503165041650516506165071650816509165101651116512165131651416515165161651716518165191652016521165221652316524165251652616527165281652916530165311653216533165341653516536165371653816539165401654116542165431654416545165461654716548165491655016551165521655316554165551655616557165581655916560165611656216563165641656516566165671656816569165701657116572165731657416575165761657716578165791658016581165821658316584165851658616587165881658916590165911659216593165941659516596165971659816599166001660116602166031660416605166061660716608166091661016611166121661316614166151661616617166181661916620166211662216623166241662516626166271662816629166301663116632166331663416635166361663716638166391664016641166421664316644166451664616647166481664916650166511665216653166541665516656166571665816659166601666116662166631666416665166661666716668166691667016671166721667316674166751667616677166781667916680166811668216683166841668516686166871668816689166901669116692166931669416695166961669716698166991670016701167021670316704167051670616707167081670916710167111671216713167141671516716167171671816719167201672116722167231672416725167261672716728167291673016731167321673316734167351673616737167381673916740167411674216743167441674516746167471674816749167501675116752167531675416755167561675716758167591676016761167621676316764167651676616767167681676916770167711677216773167741677516776167771677816779167801678116782167831678416785167861678716788167891679016791167921679316794167951679616797167981679916800168011680216803168041680516806168071680816809168101681116812168131681416815168161681716818168191682016821168221682316824168251682616827168281682916830168311683216833168341683516836168371683816839168401684116842168431684416845168461684716848168491685016851168521685316854168551685616857168581685916860168611686216863168641686516866168671686816869168701687116872168731687416875168761687716878168791688016881168821688316884168851688616887168881688916890168911689216893168941689516896168971689816899169001690116902169031690416905169061690716908169091691016911169121691316914169151691616917169181691916920169211692216923169241692516926169271692816929169301693116932169331693416935169361693716938169391694016941169421694316944169451694616947169481694916950169511695216953169541695516956169571695816959169601696116962169631696416965169661696716968169691697016971169721697316974169751697616977169781697916980169811698216983169841698516986169871698816989169901699116992169931699416995169961699716998169991700017001170021700317004170051700617007170081700917010170111701217013170141701517016170171701817019170201702117022170231702417025170261702717028170291703017031170321703317034170351703617037170381703917040170411704217043170441704517046170471704817049170501705117052170531705417055170561705717058170591706017061170621706317064170651706617067170681706917070170711707217073170741707517076170771707817079170801708117082170831708417085170861708717088170891709017091170921709317094170951709617097170981709917100171011710217103171041710517106171071710817109171101711117112171131711417115171161711717118171191712017121171221712317124171251712617127171281712917130171311713217133171341713517136171371713817139171401714117142171431714417145171461714717148171491715017151171521715317154171551715617157171581715917160171611716217163171641716517166171671716817169171701717117172171731717417175171761717717178171791718017181171821718317184171851718617187171881718917190171911719217193171941719517196171971719817199172001720117202172031720417205172061720717208172091721017211172121721317214172151721617217172181721917220172211722217223172241722517226172271722817229172301723117232172331723417235172361723717238172391724017241172421724317244172451724617247172481724917250172511725217253172541725517256172571725817259172601726117262172631726417265172661726717268172691727017271172721727317274172751727617277172781727917280172811728217283172841728517286172871728817289172901729117292172931729417295172961729717298172991730017301173021730317304173051730617307173081730917310173111731217313173141731517316173171731817319173201732117322173231732417325173261732717328173291733017331173321733317334173351733617337173381733917340173411734217343173441734517346173471734817349173501735117352173531735417355173561735717358173591736017361173621736317364173651736617367173681736917370173711737217373173741737517376173771737817379173801738117382173831738417385173861738717388173891739017391173921739317394173951739617397173981739917400174011740217403174041740517406174071740817409174101741117412174131741417415174161741717418174191742017421174221742317424174251742617427174281742917430174311743217433174341743517436174371743817439174401744117442174431744417445174461744717448174491745017451174521745317454174551745617457174581745917460174611746217463174641746517466174671746817469174701747117472174731747417475174761747717478174791748017481174821748317484174851748617487174881748917490174911749217493174941749517496174971749817499175001750117502175031750417505175061750717508175091751017511175121751317514175151751617517175181751917520175211752217523175241752517526175271752817529175301753117532175331753417535175361753717538175391754017541175421754317544175451754617547175481754917550175511755217553175541755517556175571755817559175601756117562175631756417565175661756717568175691757017571175721757317574175751757617577175781757917580175811758217583175841758517586175871758817589175901759117592175931759417595175961759717598175991760017601176021760317604176051760617607176081760917610176111761217613176141761517616176171761817619176201762117622176231762417625176261762717628176291763017631176321763317634176351763617637176381763917640176411764217643176441764517646176471764817649176501765117652176531765417655176561765717658176591766017661176621766317664176651766617667176681766917670176711767217673176741767517676176771767817679176801768117682176831768417685176861768717688176891769017691176921769317694176951769617697176981769917700177011770217703177041770517706177071770817709177101771117712177131771417715177161771717718177191772017721177221772317724177251772617727177281772917730177311773217733177341773517736177371773817739177401774117742177431774417745177461774717748177491775017751177521775317754177551775617757177581775917760177611776217763177641776517766177671776817769177701777117772177731777417775177761777717778177791778017781177821778317784177851778617787177881778917790177911779217793177941779517796177971779817799178001780117802178031780417805178061780717808178091781017811178121781317814178151781617817178181781917820178211782217823178241782517826178271782817829178301783117832178331783417835178361783717838178391784017841178421784317844178451784617847178481784917850178511785217853178541785517856178571785817859178601786117862178631786417865178661786717868178691787017871178721787317874178751787617877178781787917880178811788217883178841788517886178871788817889178901789117892178931789417895178961789717898178991790017901179021790317904179051790617907179081790917910179111791217913179141791517916179171791817919179201792117922179231792417925179261792717928179291793017931179321793317934179351793617937179381793917940179411794217943179441794517946179471794817949179501795117952179531795417955179561795717958179591796017961179621796317964179651796617967179681796917970179711797217973179741797517976179771797817979179801798117982179831798417985179861798717988179891799017991179921799317994179951799617997179981799918000180011800218003180041800518006180071800818009180101801118012180131801418015180161801718018180191802018021180221802318024180251802618027180281802918030180311803218033180341803518036180371803818039180401804118042180431804418045180461804718048180491805018051180521805318054180551805618057180581805918060180611806218063180641806518066180671806818069180701807118072180731807418075180761807718078180791808018081180821808318084180851808618087180881808918090180911809218093180941809518096180971809818099181001810118102181031810418105181061810718108181091811018111181121811318114181151811618117181181811918120181211812218123181241812518126181271812818129181301813118132181331813418135181361813718138181391814018141181421814318144181451814618147181481814918150181511815218153181541815518156181571815818159181601816118162181631816418165181661816718168181691817018171181721817318174181751817618177181781817918180181811818218183181841818518186181871818818189181901819118192181931819418195181961819718198181991820018201182021820318204182051820618207182081820918210182111821218213182141821518216182171821818219182201822118222182231822418225182261822718228182291823018231182321823318234182351823618237182381823918240182411824218243182441824518246182471824818249182501825118252182531825418255182561825718258182591826018261182621826318264182651826618267182681826918270182711827218273182741827518276182771827818279182801828118282182831828418285182861828718288182891829018291182921829318294182951829618297182981829918300183011830218303183041830518306183071830818309183101831118312183131831418315183161831718318183191832018321183221832318324183251832618327183281832918330183311833218333183341833518336183371833818339183401834118342183431834418345183461834718348
  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){
  2. function corslite(url, callback, cors) {
  3. var sent = false;
  4. if (typeof window.XMLHttpRequest === 'undefined') {
  5. return callback(Error('Browser not supported'));
  6. }
  7. if (typeof cors === 'undefined') {
  8. var m = url.match(/^\s*https?:\/\/[^\/]*/);
  9. cors = m && (m[0] !== location.protocol + '//' + location.domain +
  10. (location.port ? ':' + location.port : ''));
  11. }
  12. var x = new window.XMLHttpRequest();
  13. function isSuccessful(status) {
  14. return status >= 200 && status < 300 || status === 304;
  15. }
  16. if (cors && !('withCredentials' in x)) {
  17. // IE8-9
  18. x = new window.XDomainRequest();
  19. // Ensure callback is never called synchronously, i.e., before
  20. // x.send() returns (this has been observed in the wild).
  21. // See https://github.com/mapbox/mapbox.js/issues/472
  22. var original = callback;
  23. callback = function() {
  24. if (sent) {
  25. original.apply(this, arguments);
  26. } else {
  27. var that = this, args = arguments;
  28. setTimeout(function() {
  29. original.apply(that, args);
  30. }, 0);
  31. }
  32. }
  33. }
  34. function loaded() {
  35. if (
  36. // XDomainRequest
  37. x.status === undefined ||
  38. // modern browsers
  39. isSuccessful(x.status)) callback.call(x, null, x);
  40. else callback.call(x, x, null);
  41. }
  42. // Both `onreadystatechange` and `onload` can fire. `onreadystatechange`
  43. // has [been supported for longer](http://stackoverflow.com/a/9181508/229001).
  44. if ('onload' in x) {
  45. x.onload = loaded;
  46. } else {
  47. x.onreadystatechange = function readystate() {
  48. if (x.readyState === 4) {
  49. loaded();
  50. }
  51. };
  52. }
  53. // Call the callback with the XMLHttpRequest object as an error and prevent
  54. // it from ever being called again by reassigning it to `noop`
  55. x.onerror = function error(evt) {
  56. // XDomainRequest provides no evt parameter
  57. callback.call(this, evt || true, null);
  58. callback = function() { };
  59. };
  60. // IE9 must have onprogress be set to a unique function.
  61. x.onprogress = function() { };
  62. x.ontimeout = function(evt) {
  63. callback.call(this, evt, null);
  64. callback = function() { };
  65. };
  66. x.onabort = function(evt) {
  67. callback.call(this, evt, null);
  68. callback = function() { };
  69. };
  70. // GET is the only supported HTTP Verb by XDomainRequest and is the
  71. // only one supported here.
  72. x.open('GET', url, true);
  73. // Send the request. Sending data is not supported.
  74. x.send(null);
  75. sent = true;
  76. return x;
  77. }
  78. if (typeof module !== 'undefined') module.exports = corslite;
  79. },{}],2:[function(require,module,exports){
  80. module.exports = Array.isArray || function (arr) {
  81. return Object.prototype.toString.call(arr) == '[object Array]';
  82. };
  83. },{}],3:[function(require,module,exports){
  84. /*
  85. Leaflet 1.0.2, a JS library for interactive maps. http://leafletjs.com
  86. (c) 2010-2016 Vladimir Agafonkin, (c) 2010-2011 CloudMade
  87. */
  88. (function (window, document, undefined) {
  89. var L = {
  90. version: "1.0.2"
  91. };
  92. function expose() {
  93. var oldL = window.L;
  94. L.noConflict = function () {
  95. window.L = oldL;
  96. return this;
  97. };
  98. window.L = L;
  99. }
  100. // define Leaflet for Node module pattern loaders, including Browserify
  101. if (typeof module === 'object' && typeof module.exports === 'object') {
  102. module.exports = L;
  103. // define Leaflet as an AMD module
  104. } else if (typeof define === 'function' && define.amd) {
  105. define(L);
  106. }
  107. // define Leaflet as a global L variable, saving the original L to restore later if needed
  108. if (typeof window !== 'undefined') {
  109. expose();
  110. }
  111. /*
  112. * @namespace Util
  113. *
  114. * Various utility functions, used by Leaflet internally.
  115. */
  116. L.Util = {
  117. // @function extend(dest: Object, src?: Object): Object
  118. // Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut.
  119. extend: function (dest) {
  120. var i, j, len, src;
  121. for (j = 1, len = arguments.length; j < len; j++) {
  122. src = arguments[j];
  123. for (i in src) {
  124. dest[i] = src[i];
  125. }
  126. }
  127. return dest;
  128. },
  129. // @function create(proto: Object, properties?: Object): Object
  130. // Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create)
  131. create: Object.create || (function () {
  132. function F() {}
  133. return function (proto) {
  134. F.prototype = proto;
  135. return new F();
  136. };
  137. })(),
  138. // @function bind(fn: Function, …): Function
  139. // Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind).
  140. // Has a `L.bind()` shortcut.
  141. bind: function (fn, obj) {
  142. var slice = Array.prototype.slice;
  143. if (fn.bind) {
  144. return fn.bind.apply(fn, slice.call(arguments, 1));
  145. }
  146. var args = slice.call(arguments, 2);
  147. return function () {
  148. return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments);
  149. };
  150. },
  151. // @function stamp(obj: Object): Number
  152. // Returns the unique ID of an object, assiging it one if it doesn't have it.
  153. stamp: function (obj) {
  154. /*eslint-disable */
  155. obj._leaflet_id = obj._leaflet_id || ++L.Util.lastId;
  156. return obj._leaflet_id;
  157. /*eslint-enable */
  158. },
  159. // @property lastId: Number
  160. // Last unique ID used by [`stamp()`](#util-stamp)
  161. lastId: 0,
  162. // @function throttle(fn: Function, time: Number, context: Object): Function
  163. // Returns a function which executes function `fn` with the given scope `context`
  164. // (so that the `this` keyword refers to `context` inside `fn`'s code). The function
  165. // `fn` will be called no more than one time per given amount of `time`. The arguments
  166. // received by the bound function will be any arguments passed when binding the
  167. // function, followed by any arguments passed when invoking the bound function.
  168. // Has an `L.bind` shortcut.
  169. throttle: function (fn, time, context) {
  170. var lock, args, wrapperFn, later;
  171. later = function () {
  172. // reset lock and call if queued
  173. lock = false;
  174. if (args) {
  175. wrapperFn.apply(context, args);
  176. args = false;
  177. }
  178. };
  179. wrapperFn = function () {
  180. if (lock) {
  181. // called too soon, queue to call later
  182. args = arguments;
  183. } else {
  184. // call and lock until later
  185. fn.apply(context, arguments);
  186. setTimeout(later, time);
  187. lock = true;
  188. }
  189. };
  190. return wrapperFn;
  191. },
  192. // @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number
  193. // Returns the number `num` modulo `range` in such a way so it lies within
  194. // `range[0]` and `range[1]`. The returned value will be always smaller than
  195. // `range[1]` unless `includeMax` is set to `true`.
  196. wrapNum: function (x, range, includeMax) {
  197. var max = range[1],
  198. min = range[0],
  199. d = max - min;
  200. return x === max && includeMax ? x : ((x - min) % d + d) % d + min;
  201. },
  202. // @function falseFn(): Function
  203. // Returns a function which always returns `false`.
  204. falseFn: function () { return false; },
  205. // @function formatNum(num: Number, digits?: Number): Number
  206. // Returns the number `num` rounded to `digits` decimals, or to 5 decimals by default.
  207. formatNum: function (num, digits) {
  208. var pow = Math.pow(10, digits || 5);
  209. return Math.round(num * pow) / pow;
  210. },
  211. // @function trim(str: String): String
  212. // Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim)
  213. trim: function (str) {
  214. return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, '');
  215. },
  216. // @function splitWords(str: String): String[]
  217. // Trims and splits the string on whitespace and returns the array of parts.
  218. splitWords: function (str) {
  219. return L.Util.trim(str).split(/\s+/);
  220. },
  221. // @function setOptions(obj: Object, options: Object): Object
  222. // Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut.
  223. setOptions: function (obj, options) {
  224. if (!obj.hasOwnProperty('options')) {
  225. obj.options = obj.options ? L.Util.create(obj.options) : {};
  226. }
  227. for (var i in options) {
  228. obj.options[i] = options[i];
  229. }
  230. return obj.options;
  231. },
  232. // @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String
  233. // Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}`
  234. // translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will
  235. // be appended at the end. If `uppercase` is `true`, the parameter names will
  236. // be uppercased (e.g. `'?A=foo&B=bar'`)
  237. getParamString: function (obj, existingUrl, uppercase) {
  238. var params = [];
  239. for (var i in obj) {
  240. params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i]));
  241. }
  242. return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&');
  243. },
  244. // @function template(str: String, data: Object): String
  245. // Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'`
  246. // and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string
  247. // `('Hello foo, bar')`. You can also specify functions instead of strings for
  248. // data values — they will be evaluated passing `data` as an argument.
  249. template: function (str, data) {
  250. return str.replace(L.Util.templateRe, function (str, key) {
  251. var value = data[key];
  252. if (value === undefined) {
  253. throw new Error('No value provided for variable ' + str);
  254. } else if (typeof value === 'function') {
  255. value = value(data);
  256. }
  257. return value;
  258. });
  259. },
  260. templateRe: /\{ *([\w_\-]+) *\}/g,
  261. // @function isArray(obj): Boolean
  262. // Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray)
  263. isArray: Array.isArray || function (obj) {
  264. return (Object.prototype.toString.call(obj) === '[object Array]');
  265. },
  266. // @function indexOf(array: Array, el: Object): Number
  267. // Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf)
  268. indexOf: function (array, el) {
  269. for (var i = 0; i < array.length; i++) {
  270. if (array[i] === el) { return i; }
  271. }
  272. return -1;
  273. },
  274. // @property emptyImageUrl: String
  275. // Data URI string containing a base64-encoded empty GIF image.
  276. // Used as a hack to free memory from unused images on WebKit-powered
  277. // mobile devices (by setting image `src` to this string).
  278. emptyImageUrl: 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='
  279. };
  280. (function () {
  281. // inspired by http://paulirish.com/2011/requestanimationframe-for-smart-animating/
  282. function getPrefixed(name) {
  283. return window['webkit' + name] || window['moz' + name] || window['ms' + name];
  284. }
  285. var lastTime = 0;
  286. // fallback for IE 7-8
  287. function timeoutDefer(fn) {
  288. var time = +new Date(),
  289. timeToCall = Math.max(0, 16 - (time - lastTime));
  290. lastTime = time + timeToCall;
  291. return window.setTimeout(fn, timeToCall);
  292. }
  293. var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer,
  294. cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') ||
  295. getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); };
  296. // @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number
  297. // Schedules `fn` to be executed when the browser repaints. `fn` is bound to
  298. // `context` if given. When `immediate` is set, `fn` is called immediately if
  299. // the browser doesn't have native support for
  300. // [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame),
  301. // otherwise it's delayed. Returns a request ID that can be used to cancel the request.
  302. L.Util.requestAnimFrame = function (fn, context, immediate) {
  303. if (immediate && requestFn === timeoutDefer) {
  304. fn.call(context);
  305. } else {
  306. return requestFn.call(window, L.bind(fn, context));
  307. }
  308. };
  309. // @function cancelAnimFrame(id: Number): undefined
  310. // Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame).
  311. L.Util.cancelAnimFrame = function (id) {
  312. if (id) {
  313. cancelFn.call(window, id);
  314. }
  315. };
  316. })();
  317. // shortcuts for most used utility functions
  318. L.extend = L.Util.extend;
  319. L.bind = L.Util.bind;
  320. L.stamp = L.Util.stamp;
  321. L.setOptions = L.Util.setOptions;
  322. // @class Class
  323. // @aka L.Class
  324. // @section
  325. // @uninheritable
  326. // Thanks to John Resig and Dean Edwards for inspiration!
  327. L.Class = function () {};
  328. L.Class.extend = function (props) {
  329. // @function extend(props: Object): Function
  330. // [Extends the current class](#class-inheritance) given the properties to be included.
  331. // Returns a Javascript function that is a class constructor (to be called with `new`).
  332. var NewClass = function () {
  333. // call the constructor
  334. if (this.initialize) {
  335. this.initialize.apply(this, arguments);
  336. }
  337. // call all constructor hooks
  338. this.callInitHooks();
  339. };
  340. var parentProto = NewClass.__super__ = this.prototype;
  341. var proto = L.Util.create(parentProto);
  342. proto.constructor = NewClass;
  343. NewClass.prototype = proto;
  344. // inherit parent's statics
  345. for (var i in this) {
  346. if (this.hasOwnProperty(i) && i !== 'prototype') {
  347. NewClass[i] = this[i];
  348. }
  349. }
  350. // mix static properties into the class
  351. if (props.statics) {
  352. L.extend(NewClass, props.statics);
  353. delete props.statics;
  354. }
  355. // mix includes into the prototype
  356. if (props.includes) {
  357. L.Util.extend.apply(null, [proto].concat(props.includes));
  358. delete props.includes;
  359. }
  360. // merge options
  361. if (proto.options) {
  362. props.options = L.Util.extend(L.Util.create(proto.options), props.options);
  363. }
  364. // mix given properties into the prototype
  365. L.extend(proto, props);
  366. proto._initHooks = [];
  367. // add method for calling all hooks
  368. proto.callInitHooks = function () {
  369. if (this._initHooksCalled) { return; }
  370. if (parentProto.callInitHooks) {
  371. parentProto.callInitHooks.call(this);
  372. }
  373. this._initHooksCalled = true;
  374. for (var i = 0, len = proto._initHooks.length; i < len; i++) {
  375. proto._initHooks[i].call(this);
  376. }
  377. };
  378. return NewClass;
  379. };
  380. // @function include(properties: Object): this
  381. // [Includes a mixin](#class-includes) into the current class.
  382. L.Class.include = function (props) {
  383. L.extend(this.prototype, props);
  384. return this;
  385. };
  386. // @function mergeOptions(options: Object): this
  387. // [Merges `options`](#class-options) into the defaults of the class.
  388. L.Class.mergeOptions = function (options) {
  389. L.extend(this.prototype.options, options);
  390. return this;
  391. };
  392. // @function addInitHook(fn: Function): this
  393. // Adds a [constructor hook](#class-constructor-hooks) to the class.
  394. L.Class.addInitHook = function (fn) { // (Function) || (String, args...)
  395. var args = Array.prototype.slice.call(arguments, 1);
  396. var init = typeof fn === 'function' ? fn : function () {
  397. this[fn].apply(this, args);
  398. };
  399. this.prototype._initHooks = this.prototype._initHooks || [];
  400. this.prototype._initHooks.push(init);
  401. return this;
  402. };
  403. /*
  404. * @class Evented
  405. * @aka L.Evented
  406. * @inherits Class
  407. *
  408. * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event).
  409. *
  410. * @example
  411. *
  412. * ```js
  413. * map.on('click', function(e) {
  414. * alert(e.latlng);
  415. * } );
  416. * ```
  417. *
  418. * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function:
  419. *
  420. * ```js
  421. * function onClick(e) { ... }
  422. *
  423. * map.on('click', onClick);
  424. * map.off('click', onClick);
  425. * ```
  426. */
  427. L.Evented = L.Class.extend({
  428. /* @method on(type: String, fn: Function, context?: Object): this
  429. * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`).
  430. *
  431. * @alternative
  432. * @method on(eventMap: Object): this
  433. * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
  434. */
  435. on: function (types, fn, context) {
  436. // types can be a map of types/handlers
  437. if (typeof types === 'object') {
  438. for (var type in types) {
  439. // we don't process space-separated events here for performance;
  440. // it's a hot path since Layer uses the on(obj) syntax
  441. this._on(type, types[type], fn);
  442. }
  443. } else {
  444. // types can be a string of space-separated words
  445. types = L.Util.splitWords(types);
  446. for (var i = 0, len = types.length; i < len; i++) {
  447. this._on(types[i], fn, context);
  448. }
  449. }
  450. return this;
  451. },
  452. /* @method off(type: String, fn?: Function, context?: Object): this
  453. * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener.
  454. *
  455. * @alternative
  456. * @method off(eventMap: Object): this
  457. * Removes a set of type/listener pairs.
  458. *
  459. * @alternative
  460. * @method off: this
  461. * Removes all listeners to all events on the object.
  462. */
  463. off: function (types, fn, context) {
  464. if (!types) {
  465. // clear all listeners if called without arguments
  466. delete this._events;
  467. } else if (typeof types === 'object') {
  468. for (var type in types) {
  469. this._off(type, types[type], fn);
  470. }
  471. } else {
  472. types = L.Util.splitWords(types);
  473. for (var i = 0, len = types.length; i < len; i++) {
  474. this._off(types[i], fn, context);
  475. }
  476. }
  477. return this;
  478. },
  479. // attach listener (without syntactic sugar now)
  480. _on: function (type, fn, context) {
  481. this._events = this._events || {};
  482. /* get/init listeners for type */
  483. var typeListeners = this._events[type];
  484. if (!typeListeners) {
  485. typeListeners = [];
  486. this._events[type] = typeListeners;
  487. }
  488. if (context === this) {
  489. // Less memory footprint.
  490. context = undefined;
  491. }
  492. var newListener = {fn: fn, ctx: context},
  493. listeners = typeListeners;
  494. // check if fn already there
  495. for (var i = 0, len = listeners.length; i < len; i++) {
  496. if (listeners[i].fn === fn && listeners[i].ctx === context) {
  497. return;
  498. }
  499. }
  500. listeners.push(newListener);
  501. typeListeners.count++;
  502. },
  503. _off: function (type, fn, context) {
  504. var listeners,
  505. i,
  506. len;
  507. if (!this._events) { return; }
  508. listeners = this._events[type];
  509. if (!listeners) {
  510. return;
  511. }
  512. if (!fn) {
  513. // Set all removed listeners to noop so they are not called if remove happens in fire
  514. for (i = 0, len = listeners.length; i < len; i++) {
  515. listeners[i].fn = L.Util.falseFn;
  516. }
  517. // clear all listeners for a type if function isn't specified
  518. delete this._events[type];
  519. return;
  520. }
  521. if (context === this) {
  522. context = undefined;
  523. }
  524. if (listeners) {
  525. // find fn and remove it
  526. for (i = 0, len = listeners.length; i < len; i++) {
  527. var l = listeners[i];
  528. if (l.ctx !== context) { continue; }
  529. if (l.fn === fn) {
  530. // set the removed listener to noop so that's not called if remove happens in fire
  531. l.fn = L.Util.falseFn;
  532. if (this._firingCount) {
  533. /* copy array in case events are being fired */
  534. this._events[type] = listeners = listeners.slice();
  535. }
  536. listeners.splice(i, 1);
  537. return;
  538. }
  539. }
  540. }
  541. },
  542. // @method fire(type: String, data?: Object, propagate?: Boolean): this
  543. // Fires an event of the specified type. You can optionally provide an data
  544. // object — the first argument of the listener function will contain its
  545. // properties. The event can optionally be propagated to event parents.
  546. fire: function (type, data, propagate) {
  547. if (!this.listens(type, propagate)) { return this; }
  548. var event = L.Util.extend({}, data, {type: type, target: this});
  549. if (this._events) {
  550. var listeners = this._events[type];
  551. if (listeners) {
  552. this._firingCount = (this._firingCount + 1) || 1;
  553. for (var i = 0, len = listeners.length; i < len; i++) {
  554. var l = listeners[i];
  555. l.fn.call(l.ctx || this, event);
  556. }
  557. this._firingCount--;
  558. }
  559. }
  560. if (propagate) {
  561. // propagate the event to parents (set with addEventParent)
  562. this._propagateEvent(event);
  563. }
  564. return this;
  565. },
  566. // @method listens(type: String): Boolean
  567. // Returns `true` if a particular event type has any listeners attached to it.
  568. listens: function (type, propagate) {
  569. var listeners = this._events && this._events[type];
  570. if (listeners && listeners.length) { return true; }
  571. if (propagate) {
  572. // also check parents for listeners if event propagates
  573. for (var id in this._eventParents) {
  574. if (this._eventParents[id].listens(type, propagate)) { return true; }
  575. }
  576. }
  577. return false;
  578. },
  579. // @method once(…): this
  580. // Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed.
  581. once: function (types, fn, context) {
  582. if (typeof types === 'object') {
  583. for (var type in types) {
  584. this.once(type, types[type], fn);
  585. }
  586. return this;
  587. }
  588. var handler = L.bind(function () {
  589. this
  590. .off(types, fn, context)
  591. .off(types, handler, context);
  592. }, this);
  593. // add a listener that's executed once and removed after that
  594. return this
  595. .on(types, fn, context)
  596. .on(types, handler, context);
  597. },
  598. // @method addEventParent(obj: Evented): this
  599. // Adds an event parent - an `Evented` that will receive propagated events
  600. addEventParent: function (obj) {
  601. this._eventParents = this._eventParents || {};
  602. this._eventParents[L.stamp(obj)] = obj;
  603. return this;
  604. },
  605. // @method removeEventParent(obj: Evented): this
  606. // Removes an event parent, so it will stop receiving propagated events
  607. removeEventParent: function (obj) {
  608. if (this._eventParents) {
  609. delete this._eventParents[L.stamp(obj)];
  610. }
  611. return this;
  612. },
  613. _propagateEvent: function (e) {
  614. for (var id in this._eventParents) {
  615. this._eventParents[id].fire(e.type, L.extend({layer: e.target}, e), true);
  616. }
  617. }
  618. });
  619. var proto = L.Evented.prototype;
  620. // aliases; we should ditch those eventually
  621. // @method addEventListener(…): this
  622. // Alias to [`on(…)`](#evented-on)
  623. proto.addEventListener = proto.on;
  624. // @method removeEventListener(…): this
  625. // Alias to [`off(…)`](#evented-off)
  626. // @method clearAllEventListeners(…): this
  627. // Alias to [`off()`](#evented-off)
  628. proto.removeEventListener = proto.clearAllEventListeners = proto.off;
  629. // @method addOneTimeEventListener(…): this
  630. // Alias to [`once(…)`](#evented-once)
  631. proto.addOneTimeEventListener = proto.once;
  632. // @method fireEvent(…): this
  633. // Alias to [`fire(…)`](#evented-fire)
  634. proto.fireEvent = proto.fire;
  635. // @method hasEventListeners(…): Boolean
  636. // Alias to [`listens(…)`](#evented-listens)
  637. proto.hasEventListeners = proto.listens;
  638. L.Mixin = {Events: proto};
  639. /*
  640. * @namespace Browser
  641. * @aka L.Browser
  642. *
  643. * A namespace with static properties for browser/feature detection used by Leaflet internally.
  644. *
  645. * @example
  646. *
  647. * ```js
  648. * if (L.Browser.ielt9) {
  649. * alert('Upgrade your browser, dude!');
  650. * }
  651. * ```
  652. */
  653. (function () {
  654. var ua = navigator.userAgent.toLowerCase(),
  655. doc = document.documentElement,
  656. ie = 'ActiveXObject' in window,
  657. webkit = ua.indexOf('webkit') !== -1,
  658. phantomjs = ua.indexOf('phantom') !== -1,
  659. android23 = ua.search('android [23]') !== -1,
  660. chrome = ua.indexOf('chrome') !== -1,
  661. gecko = ua.indexOf('gecko') !== -1 && !webkit && !window.opera && !ie,
  662. win = navigator.platform.indexOf('Win') === 0,
  663. mobile = typeof orientation !== 'undefined' || ua.indexOf('mobile') !== -1,
  664. msPointer = !window.PointerEvent && window.MSPointerEvent,
  665. pointer = window.PointerEvent || msPointer,
  666. ie3d = ie && ('transition' in doc.style),
  667. webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23,
  668. gecko3d = 'MozPerspective' in doc.style,
  669. opera12 = 'OTransition' in doc.style;
  670. var touch = !window.L_NO_TOUCH && (pointer || 'ontouchstart' in window ||
  671. (window.DocumentTouch && document instanceof window.DocumentTouch));
  672. L.Browser = {
  673. // @property ie: Boolean
  674. // `true` for all Internet Explorer versions (not Edge).
  675. ie: ie,
  676. // @property ielt9: Boolean
  677. // `true` for Internet Explorer versions less than 9.
  678. ielt9: ie && !document.addEventListener,
  679. // @property edge: Boolean
  680. // `true` for the Edge web browser.
  681. edge: 'msLaunchUri' in navigator && !('documentMode' in document),
  682. // @property webkit: Boolean
  683. // `true` for webkit-based browsers like Chrome and Safari (including mobile versions).
  684. webkit: webkit,
  685. // @property gecko: Boolean
  686. // `true` for gecko-based browsers like Firefox.
  687. gecko: gecko,
  688. // @property android: Boolean
  689. // `true` for any browser running on an Android platform.
  690. android: ua.indexOf('android') !== -1,
  691. // @property android23: Boolean
  692. // `true` for browsers running on Android 2 or Android 3.
  693. android23: android23,
  694. // @property chrome: Boolean
  695. // `true` for the Chrome browser.
  696. chrome: chrome,
  697. // @property safari: Boolean
  698. // `true` for the Safari browser.
  699. safari: !chrome && ua.indexOf('safari') !== -1,
  700. // @property win: Boolean
  701. // `true` when the browser is running in a Windows platform
  702. win: win,
  703. // @property ie3d: Boolean
  704. // `true` for all Internet Explorer versions supporting CSS transforms.
  705. ie3d: ie3d,
  706. // @property webkit3d: Boolean
  707. // `true` for webkit-based browsers supporting CSS transforms.
  708. webkit3d: webkit3d,
  709. // @property gecko3d: Boolean
  710. // `true` for gecko-based browsers supporting CSS transforms.
  711. gecko3d: gecko3d,
  712. // @property opera12: Boolean
  713. // `true` for the Opera browser supporting CSS transforms (version 12 or later).
  714. opera12: opera12,
  715. // @property any3d: Boolean
  716. // `true` for all browsers supporting CSS transforms.
  717. any3d: !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantomjs,
  718. // @property mobile: Boolean
  719. // `true` for all browsers running in a mobile device.
  720. mobile: mobile,
  721. // @property mobileWebkit: Boolean
  722. // `true` for all webkit-based browsers in a mobile device.
  723. mobileWebkit: mobile && webkit,
  724. // @property mobileWebkit3d: Boolean
  725. // `true` for all webkit-based browsers in a mobile device supporting CSS transforms.
  726. mobileWebkit3d: mobile && webkit3d,
  727. // @property mobileOpera: Boolean
  728. // `true` for the Opera browser in a mobile device.
  729. mobileOpera: mobile && window.opera,
  730. // @property mobileGecko: Boolean
  731. // `true` for gecko-based browsers running in a mobile device.
  732. mobileGecko: mobile && gecko,
  733. // @property touch: Boolean
  734. // `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events).
  735. touch: !!touch,
  736. // @property msPointer: Boolean
  737. // `true` for browsers implementing the Microsoft touch events model (notably IE10).
  738. msPointer: !!msPointer,
  739. // @property pointer: Boolean
  740. // `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx).
  741. pointer: !!pointer,
  742. // @property retina: Boolean
  743. // `true` for browsers on a high-resolution "retina" screen.
  744. retina: (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1
  745. };
  746. }());
  747. /*
  748. * @class Point
  749. * @aka L.Point
  750. *
  751. * Represents a point with `x` and `y` coordinates in pixels.
  752. *
  753. * @example
  754. *
  755. * ```js
  756. * var point = L.point(200, 300);
  757. * ```
  758. *
  759. * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent:
  760. *
  761. * ```js
  762. * map.panBy([200, 300]);
  763. * map.panBy(L.point(200, 300));
  764. * ```
  765. */
  766. L.Point = function (x, y, round) {
  767. // @property x: Number; The `x` coordinate of the point
  768. this.x = (round ? Math.round(x) : x);
  769. // @property y: Number; The `y` coordinate of the point
  770. this.y = (round ? Math.round(y) : y);
  771. };
  772. L.Point.prototype = {
  773. // @method clone(): Point
  774. // Returns a copy of the current point.
  775. clone: function () {
  776. return new L.Point(this.x, this.y);
  777. },
  778. // @method add(otherPoint: Point): Point
  779. // Returns the result of addition of the current and the given points.
  780. add: function (point) {
  781. // non-destructive, returns a new point
  782. return this.clone()._add(L.point(point));
  783. },
  784. _add: function (point) {
  785. // destructive, used directly for performance in situations where it's safe to modify existing point
  786. this.x += point.x;
  787. this.y += point.y;
  788. return this;
  789. },
  790. // @method subtract(otherPoint: Point): Point
  791. // Returns the result of subtraction of the given point from the current.
  792. subtract: function (point) {
  793. return this.clone()._subtract(L.point(point));
  794. },
  795. _subtract: function (point) {
  796. this.x -= point.x;
  797. this.y -= point.y;
  798. return this;
  799. },
  800. // @method divideBy(num: Number): Point
  801. // Returns the result of division of the current point by the given number.
  802. divideBy: function (num) {
  803. return this.clone()._divideBy(num);
  804. },
  805. _divideBy: function (num) {
  806. this.x /= num;
  807. this.y /= num;
  808. return this;
  809. },
  810. // @method multiplyBy(num: Number): Point
  811. // Returns the result of multiplication of the current point by the given number.
  812. multiplyBy: function (num) {
  813. return this.clone()._multiplyBy(num);
  814. },
  815. _multiplyBy: function (num) {
  816. this.x *= num;
  817. this.y *= num;
  818. return this;
  819. },
  820. // @method scaleBy(scale: Point): Point
  821. // Multiply each coordinate of the current point by each coordinate of
  822. // `scale`. In linear algebra terms, multiply the point by the
  823. // [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation)
  824. // defined by `scale`.
  825. scaleBy: function (point) {
  826. return new L.Point(this.x * point.x, this.y * point.y);
  827. },
  828. // @method unscaleBy(scale: Point): Point
  829. // Inverse of `scaleBy`. Divide each coordinate of the current point by
  830. // each coordinate of `scale`.
  831. unscaleBy: function (point) {
  832. return new L.Point(this.x / point.x, this.y / point.y);
  833. },
  834. // @method round(): Point
  835. // Returns a copy of the current point with rounded coordinates.
  836. round: function () {
  837. return this.clone()._round();
  838. },
  839. _round: function () {
  840. this.x = Math.round(this.x);
  841. this.y = Math.round(this.y);
  842. return this;
  843. },
  844. // @method floor(): Point
  845. // Returns a copy of the current point with floored coordinates (rounded down).
  846. floor: function () {
  847. return this.clone()._floor();
  848. },
  849. _floor: function () {
  850. this.x = Math.floor(this.x);
  851. this.y = Math.floor(this.y);
  852. return this;
  853. },
  854. // @method ceil(): Point
  855. // Returns a copy of the current point with ceiled coordinates (rounded up).
  856. ceil: function () {
  857. return this.clone()._ceil();
  858. },
  859. _ceil: function () {
  860. this.x = Math.ceil(this.x);
  861. this.y = Math.ceil(this.y);
  862. return this;
  863. },
  864. // @method distanceTo(otherPoint: Point): Number
  865. // Returns the cartesian distance between the current and the given points.
  866. distanceTo: function (point) {
  867. point = L.point(point);
  868. var x = point.x - this.x,
  869. y = point.y - this.y;
  870. return Math.sqrt(x * x + y * y);
  871. },
  872. // @method equals(otherPoint: Point): Boolean
  873. // Returns `true` if the given point has the same coordinates.
  874. equals: function (point) {
  875. point = L.point(point);
  876. return point.x === this.x &&
  877. point.y === this.y;
  878. },
  879. // @method contains(otherPoint: Point): Boolean
  880. // Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values).
  881. contains: function (point) {
  882. point = L.point(point);
  883. return Math.abs(point.x) <= Math.abs(this.x) &&
  884. Math.abs(point.y) <= Math.abs(this.y);
  885. },
  886. // @method toString(): String
  887. // Returns a string representation of the point for debugging purposes.
  888. toString: function () {
  889. return 'Point(' +
  890. L.Util.formatNum(this.x) + ', ' +
  891. L.Util.formatNum(this.y) + ')';
  892. }
  893. };
  894. // @factory L.point(x: Number, y: Number, round?: Boolean)
  895. // Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values.
  896. // @alternative
  897. // @factory L.point(coords: Number[])
  898. // Expects an array of the form `[x, y]` instead.
  899. // @alternative
  900. // @factory L.point(coords: Object)
  901. // Expects a plain object of the form `{x: Number, y: Number}` instead.
  902. L.point = function (x, y, round) {
  903. if (x instanceof L.Point) {
  904. return x;
  905. }
  906. if (L.Util.isArray(x)) {
  907. return new L.Point(x[0], x[1]);
  908. }
  909. if (x === undefined || x === null) {
  910. return x;
  911. }
  912. if (typeof x === 'object' && 'x' in x && 'y' in x) {
  913. return new L.Point(x.x, x.y);
  914. }
  915. return new L.Point(x, y, round);
  916. };
  917. /*
  918. * @class Bounds
  919. * @aka L.Bounds
  920. *
  921. * Represents a rectangular area in pixel coordinates.
  922. *
  923. * @example
  924. *
  925. * ```js
  926. * var p1 = L.point(10, 10),
  927. * p2 = L.point(40, 60),
  928. * bounds = L.bounds(p1, p2);
  929. * ```
  930. *
  931. * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
  932. *
  933. * ```js
  934. * otherBounds.intersects([[10, 10], [40, 60]]);
  935. * ```
  936. */
  937. L.Bounds = function (a, b) {
  938. if (!a) { return; }
  939. var points = b ? [a, b] : a;
  940. for (var i = 0, len = points.length; i < len; i++) {
  941. this.extend(points[i]);
  942. }
  943. };
  944. L.Bounds.prototype = {
  945. // @method extend(point: Point): this
  946. // Extends the bounds to contain the given point.
  947. extend: function (point) { // (Point)
  948. point = L.point(point);
  949. // @property min: Point
  950. // The top left corner of the rectangle.
  951. // @property max: Point
  952. // The bottom right corner of the rectangle.
  953. if (!this.min && !this.max) {
  954. this.min = point.clone();
  955. this.max = point.clone();
  956. } else {
  957. this.min.x = Math.min(point.x, this.min.x);
  958. this.max.x = Math.max(point.x, this.max.x);
  959. this.min.y = Math.min(point.y, this.min.y);
  960. this.max.y = Math.max(point.y, this.max.y);
  961. }
  962. return this;
  963. },
  964. // @method getCenter(round?: Boolean): Point
  965. // Returns the center point of the bounds.
  966. getCenter: function (round) {
  967. return new L.Point(
  968. (this.min.x + this.max.x) / 2,
  969. (this.min.y + this.max.y) / 2, round);
  970. },
  971. // @method getBottomLeft(): Point
  972. // Returns the bottom-left point of the bounds.
  973. getBottomLeft: function () {
  974. return new L.Point(this.min.x, this.max.y);
  975. },
  976. // @method getTopRight(): Point
  977. // Returns the top-right point of the bounds.
  978. getTopRight: function () { // -> Point
  979. return new L.Point(this.max.x, this.min.y);
  980. },
  981. // @method getSize(): Point
  982. // Returns the size of the given bounds
  983. getSize: function () {
  984. return this.max.subtract(this.min);
  985. },
  986. // @method contains(otherBounds: Bounds): Boolean
  987. // Returns `true` if the rectangle contains the given one.
  988. // @alternative
  989. // @method contains(point: Point): Boolean
  990. // Returns `true` if the rectangle contains the given point.
  991. contains: function (obj) {
  992. var min, max;
  993. if (typeof obj[0] === 'number' || obj instanceof L.Point) {
  994. obj = L.point(obj);
  995. } else {
  996. obj = L.bounds(obj);
  997. }
  998. if (obj instanceof L.Bounds) {
  999. min = obj.min;
  1000. max = obj.max;
  1001. } else {
  1002. min = max = obj;
  1003. }
  1004. return (min.x >= this.min.x) &&
  1005. (max.x <= this.max.x) &&
  1006. (min.y >= this.min.y) &&
  1007. (max.y <= this.max.y);
  1008. },
  1009. // @method intersects(otherBounds: Bounds): Boolean
  1010. // Returns `true` if the rectangle intersects the given bounds. Two bounds
  1011. // intersect if they have at least one point in common.
  1012. intersects: function (bounds) { // (Bounds) -> Boolean
  1013. bounds = L.bounds(bounds);
  1014. var min = this.min,
  1015. max = this.max,
  1016. min2 = bounds.min,
  1017. max2 = bounds.max,
  1018. xIntersects = (max2.x >= min.x) && (min2.x <= max.x),
  1019. yIntersects = (max2.y >= min.y) && (min2.y <= max.y);
  1020. return xIntersects && yIntersects;
  1021. },
  1022. // @method overlaps(otherBounds: Bounds): Boolean
  1023. // Returns `true` if the rectangle overlaps the given bounds. Two bounds
  1024. // overlap if their intersection is an area.
  1025. overlaps: function (bounds) { // (Bounds) -> Boolean
  1026. bounds = L.bounds(bounds);
  1027. var min = this.min,
  1028. max = this.max,
  1029. min2 = bounds.min,
  1030. max2 = bounds.max,
  1031. xOverlaps = (max2.x > min.x) && (min2.x < max.x),
  1032. yOverlaps = (max2.y > min.y) && (min2.y < max.y);
  1033. return xOverlaps && yOverlaps;
  1034. },
  1035. isValid: function () {
  1036. return !!(this.min && this.max);
  1037. }
  1038. };
  1039. // @factory L.bounds(topLeft: Point, bottomRight: Point)
  1040. // Creates a Bounds object from two coordinates (usually top-left and bottom-right corners).
  1041. // @alternative
  1042. // @factory L.bounds(points: Point[])
  1043. // Creates a Bounds object from the points it contains
  1044. L.bounds = function (a, b) {
  1045. if (!a || a instanceof L.Bounds) {
  1046. return a;
  1047. }
  1048. return new L.Bounds(a, b);
  1049. };
  1050. /*
  1051. * @class Transformation
  1052. * @aka L.Transformation
  1053. *
  1054. * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d`
  1055. * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing
  1056. * the reverse. Used by Leaflet in its projections code.
  1057. *
  1058. * @example
  1059. *
  1060. * ```js
  1061. * var transformation = new L.Transformation(2, 5, -1, 10),
  1062. * p = L.point(1, 2),
  1063. * p2 = transformation.transform(p), // L.point(7, 8)
  1064. * p3 = transformation.untransform(p2); // L.point(1, 2)
  1065. * ```
  1066. */
  1067. // factory new L.Transformation(a: Number, b: Number, c: Number, d: Number)
  1068. // Creates a `Transformation` object with the given coefficients.
  1069. L.Transformation = function (a, b, c, d) {
  1070. this._a = a;
  1071. this._b = b;
  1072. this._c = c;
  1073. this._d = d;
  1074. };
  1075. L.Transformation.prototype = {
  1076. // @method transform(point: Point, scale?: Number): Point
  1077. // Returns a transformed point, optionally multiplied by the given scale.
  1078. // Only accepts actual `L.Point` instances, not arrays.
  1079. transform: function (point, scale) { // (Point, Number) -> Point
  1080. return this._transform(point.clone(), scale);
  1081. },
  1082. // destructive transform (faster)
  1083. _transform: function (point, scale) {
  1084. scale = scale || 1;
  1085. point.x = scale * (this._a * point.x + this._b);
  1086. point.y = scale * (this._c * point.y + this._d);
  1087. return point;
  1088. },
  1089. // @method untransform(point: Point, scale?: Number): Point
  1090. // Returns the reverse transformation of the given point, optionally divided
  1091. // by the given scale. Only accepts actual `L.Point` instances, not arrays.
  1092. untransform: function (point, scale) {
  1093. scale = scale || 1;
  1094. return new L.Point(
  1095. (point.x / scale - this._b) / this._a,
  1096. (point.y / scale - this._d) / this._c);
  1097. }
  1098. };
  1099. /*
  1100. * @namespace DomUtil
  1101. *
  1102. * Utility functions to work with the [DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model)
  1103. * tree, used by Leaflet internally.
  1104. *
  1105. * Most functions expecting or returning a `HTMLElement` also work for
  1106. * SVG elements. The only difference is that classes refer to CSS classes
  1107. * in HTML and SVG classes in SVG.
  1108. */
  1109. L.DomUtil = {
  1110. // @function get(id: String|HTMLElement): HTMLElement
  1111. // Returns an element given its DOM id, or returns the element itself
  1112. // if it was passed directly.
  1113. get: function (id) {
  1114. return typeof id === 'string' ? document.getElementById(id) : id;
  1115. },
  1116. // @function getStyle(el: HTMLElement, styleAttrib: String): String
  1117. // Returns the value for a certain style attribute on an element,
  1118. // including computed values or values set through CSS.
  1119. getStyle: function (el, style) {
  1120. var value = el.style[style] || (el.currentStyle && el.currentStyle[style]);
  1121. if ((!value || value === 'auto') && document.defaultView) {
  1122. var css = document.defaultView.getComputedStyle(el, null);
  1123. value = css ? css[style] : null;
  1124. }
  1125. return value === 'auto' ? null : value;
  1126. },
  1127. // @function create(tagName: String, className?: String, container?: HTMLElement): HTMLElement
  1128. // Creates an HTML element with `tagName`, sets its class to `className`, and optionally appends it to `container` element.
  1129. create: function (tagName, className, container) {
  1130. var el = document.createElement(tagName);
  1131. el.className = className || '';
  1132. if (container) {
  1133. container.appendChild(el);
  1134. }
  1135. return el;
  1136. },
  1137. // @function remove(el: HTMLElement)
  1138. // Removes `el` from its parent element
  1139. remove: function (el) {
  1140. var parent = el.parentNode;
  1141. if (parent) {
  1142. parent.removeChild(el);
  1143. }
  1144. },
  1145. // @function empty(el: HTMLElement)
  1146. // Removes all of `el`'s children elements from `el`
  1147. empty: function (el) {
  1148. while (el.firstChild) {
  1149. el.removeChild(el.firstChild);
  1150. }
  1151. },
  1152. // @function toFront(el: HTMLElement)
  1153. // Makes `el` the last children of its parent, so it renders in front of the other children.
  1154. toFront: function (el) {
  1155. el.parentNode.appendChild(el);
  1156. },
  1157. // @function toBack(el: HTMLElement)
  1158. // Makes `el` the first children of its parent, so it renders back from the other children.
  1159. toBack: function (el) {
  1160. var parent = el.parentNode;
  1161. parent.insertBefore(el, parent.firstChild);
  1162. },
  1163. // @function hasClass(el: HTMLElement, name: String): Boolean
  1164. // Returns `true` if the element's class attribute contains `name`.
  1165. hasClass: function (el, name) {
  1166. if (el.classList !== undefined) {
  1167. return el.classList.contains(name);
  1168. }
  1169. var className = L.DomUtil.getClass(el);
  1170. return className.length > 0 && new RegExp('(^|\\s)' + name + '(\\s|$)').test(className);
  1171. },
  1172. // @function addClass(el: HTMLElement, name: String)
  1173. // Adds `name` to the element's class attribute.
  1174. addClass: function (el, name) {
  1175. if (el.classList !== undefined) {
  1176. var classes = L.Util.splitWords(name);
  1177. for (var i = 0, len = classes.length; i < len; i++) {
  1178. el.classList.add(classes[i]);
  1179. }
  1180. } else if (!L.DomUtil.hasClass(el, name)) {
  1181. var className = L.DomUtil.getClass(el);
  1182. L.DomUtil.setClass(el, (className ? className + ' ' : '') + name);
  1183. }
  1184. },
  1185. // @function removeClass(el: HTMLElement, name: String)
  1186. // Removes `name` from the element's class attribute.
  1187. removeClass: function (el, name) {
  1188. if (el.classList !== undefined) {
  1189. el.classList.remove(name);
  1190. } else {
  1191. L.DomUtil.setClass(el, L.Util.trim((' ' + L.DomUtil.getClass(el) + ' ').replace(' ' + name + ' ', ' ')));
  1192. }
  1193. },
  1194. // @function setClass(el: HTMLElement, name: String)
  1195. // Sets the element's class.
  1196. setClass: function (el, name) {
  1197. if (el.className.baseVal === undefined) {
  1198. el.className = name;
  1199. } else {
  1200. // in case of SVG element
  1201. el.className.baseVal = name;
  1202. }
  1203. },
  1204. // @function getClass(el: HTMLElement): String
  1205. // Returns the element's class.
  1206. getClass: function (el) {
  1207. return el.className.baseVal === undefined ? el.className : el.className.baseVal;
  1208. },
  1209. // @function setOpacity(el: HTMLElement, opacity: Number)
  1210. // Set the opacity of an element (including old IE support).
  1211. // `opacity` must be a number from `0` to `1`.
  1212. setOpacity: function (el, value) {
  1213. if ('opacity' in el.style) {
  1214. el.style.opacity = value;
  1215. } else if ('filter' in el.style) {
  1216. L.DomUtil._setOpacityIE(el, value);
  1217. }
  1218. },
  1219. _setOpacityIE: function (el, value) {
  1220. var filter = false,
  1221. filterName = 'DXImageTransform.Microsoft.Alpha';
  1222. // filters collection throws an error if we try to retrieve a filter that doesn't exist
  1223. try {
  1224. filter = el.filters.item(filterName);
  1225. } catch (e) {
  1226. // don't set opacity to 1 if we haven't already set an opacity,
  1227. // it isn't needed and breaks transparent pngs.
  1228. if (value === 1) { return; }
  1229. }
  1230. value = Math.round(value * 100);
  1231. if (filter) {
  1232. filter.Enabled = (value !== 100);
  1233. filter.Opacity = value;
  1234. } else {
  1235. el.style.filter += ' progid:' + filterName + '(opacity=' + value + ')';
  1236. }
  1237. },
  1238. // @function testProp(props: String[]): String|false
  1239. // Goes through the array of style names and returns the first name
  1240. // that is a valid style name for an element. If no such name is found,
  1241. // it returns false. Useful for vendor-prefixed styles like `transform`.
  1242. testProp: function (props) {
  1243. var style = document.documentElement.style;
  1244. for (var i = 0; i < props.length; i++) {
  1245. if (props[i] in style) {
  1246. return props[i];
  1247. }
  1248. }
  1249. return false;
  1250. },
  1251. // @function setTransform(el: HTMLElement, offset: Point, scale?: Number)
  1252. // Resets the 3D CSS transform of `el` so it is translated by `offset` pixels
  1253. // and optionally scaled by `scale`. Does not have an effect if the
  1254. // browser doesn't support 3D CSS transforms.
  1255. setTransform: function (el, offset, scale) {
  1256. var pos = offset || new L.Point(0, 0);
  1257. el.style[L.DomUtil.TRANSFORM] =
  1258. (L.Browser.ie3d ?
  1259. 'translate(' + pos.x + 'px,' + pos.y + 'px)' :
  1260. 'translate3d(' + pos.x + 'px,' + pos.y + 'px,0)') +
  1261. (scale ? ' scale(' + scale + ')' : '');
  1262. },
  1263. // @function setPosition(el: HTMLElement, position: Point)
  1264. // Sets the position of `el` to coordinates specified by `position`,
  1265. // using CSS translate or top/left positioning depending on the browser
  1266. // (used by Leaflet internally to position its layers).
  1267. setPosition: function (el, point) { // (HTMLElement, Point[, Boolean])
  1268. /*eslint-disable */
  1269. el._leaflet_pos = point;
  1270. /*eslint-enable */
  1271. if (L.Browser.any3d) {
  1272. L.DomUtil.setTransform(el, point);
  1273. } else {
  1274. el.style.left = point.x + 'px';
  1275. el.style.top = point.y + 'px';
  1276. }
  1277. },
  1278. // @function getPosition(el: HTMLElement): Point
  1279. // Returns the coordinates of an element previously positioned with setPosition.
  1280. getPosition: function (el) {
  1281. // this method is only used for elements previously positioned using setPosition,
  1282. // so it's safe to cache the position for performance
  1283. return el._leaflet_pos || new L.Point(0, 0);
  1284. }
  1285. };
  1286. (function () {
  1287. // prefix style property names
  1288. // @property TRANSFORM: String
  1289. // Vendor-prefixed fransform style name (e.g. `'webkitTransform'` for WebKit).
  1290. L.DomUtil.TRANSFORM = L.DomUtil.testProp(
  1291. ['transform', 'WebkitTransform', 'OTransform', 'MozTransform', 'msTransform']);
  1292. // webkitTransition comes first because some browser versions that drop vendor prefix don't do
  1293. // the same for the transitionend event, in particular the Android 4.1 stock browser
  1294. // @property TRANSITION: String
  1295. // Vendor-prefixed transform style name.
  1296. var transition = L.DomUtil.TRANSITION = L.DomUtil.testProp(
  1297. ['webkitTransition', 'transition', 'OTransition', 'MozTransition', 'msTransition']);
  1298. L.DomUtil.TRANSITION_END =
  1299. transition === 'webkitTransition' || transition === 'OTransition' ? transition + 'End' : 'transitionend';
  1300. // @function disableTextSelection()
  1301. // Prevents the user from generating `selectstart` DOM events, usually generated
  1302. // when the user drags the mouse through a page with text. Used internally
  1303. // by Leaflet to override the behaviour of any click-and-drag interaction on
  1304. // the map. Affects drag interactions on the whole document.
  1305. // @function enableTextSelection()
  1306. // Cancels the effects of a previous [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection).
  1307. if ('onselectstart' in document) {
  1308. L.DomUtil.disableTextSelection = function () {
  1309. L.DomEvent.on(window, 'selectstart', L.DomEvent.preventDefault);
  1310. };
  1311. L.DomUtil.enableTextSelection = function () {
  1312. L.DomEvent.off(window, 'selectstart', L.DomEvent.preventDefault);
  1313. };
  1314. } else {
  1315. var userSelectProperty = L.DomUtil.testProp(
  1316. ['userSelect', 'WebkitUserSelect', 'OUserSelect', 'MozUserSelect', 'msUserSelect']);
  1317. L.DomUtil.disableTextSelection = function () {
  1318. if (userSelectProperty) {
  1319. var style = document.documentElement.style;
  1320. this._userSelect = style[userSelectProperty];
  1321. style[userSelectProperty] = 'none';
  1322. }
  1323. };
  1324. L.DomUtil.enableTextSelection = function () {
  1325. if (userSelectProperty) {
  1326. document.documentElement.style[userSelectProperty] = this._userSelect;
  1327. delete this._userSelect;
  1328. }
  1329. };
  1330. }
  1331. // @function disableImageDrag()
  1332. // As [`L.DomUtil.disableTextSelection`](#domutil-disabletextselection), but
  1333. // for `dragstart` DOM events, usually generated when the user drags an image.
  1334. L.DomUtil.disableImageDrag = function () {
  1335. L.DomEvent.on(window, 'dragstart', L.DomEvent.preventDefault);
  1336. };
  1337. // @function enableImageDrag()
  1338. // Cancels the effects of a previous [`L.DomUtil.disableImageDrag`](#domutil-disabletextselection).
  1339. L.DomUtil.enableImageDrag = function () {
  1340. L.DomEvent.off(window, 'dragstart', L.DomEvent.preventDefault);
  1341. };
  1342. // @function preventOutline(el: HTMLElement)
  1343. // Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline)
  1344. // of the element `el` invisible. Used internally by Leaflet to prevent
  1345. // focusable elements from displaying an outline when the user performs a
  1346. // drag interaction on them.
  1347. L.DomUtil.preventOutline = function (element) {
  1348. while (element.tabIndex === -1) {
  1349. element = element.parentNode;
  1350. }
  1351. if (!element || !element.style) { return; }
  1352. L.DomUtil.restoreOutline();
  1353. this._outlineElement = element;
  1354. this._outlineStyle = element.style.outline;
  1355. element.style.outline = 'none';
  1356. L.DomEvent.on(window, 'keydown', L.DomUtil.restoreOutline, this);
  1357. };
  1358. // @function restoreOutline()
  1359. // Cancels the effects of a previous [`L.DomUtil.preventOutline`]().
  1360. L.DomUtil.restoreOutline = function () {
  1361. if (!this._outlineElement) { return; }
  1362. this._outlineElement.style.outline = this._outlineStyle;
  1363. delete this._outlineElement;
  1364. delete this._outlineStyle;
  1365. L.DomEvent.off(window, 'keydown', L.DomUtil.restoreOutline, this);
  1366. };
  1367. })();
  1368. /* @class LatLng
  1369. * @aka L.LatLng
  1370. *
  1371. * Represents a geographical point with a certain latitude and longitude.
  1372. *
  1373. * @example
  1374. *
  1375. * ```
  1376. * var latlng = L.latLng(50.5, 30.5);
  1377. * ```
  1378. *
  1379. * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent:
  1380. *
  1381. * ```
  1382. * map.panTo([50, 30]);
  1383. * map.panTo({lon: 30, lat: 50});
  1384. * map.panTo({lat: 50, lng: 30});
  1385. * map.panTo(L.latLng(50, 30));
  1386. * ```
  1387. */
  1388. L.LatLng = function (lat, lng, alt) {
  1389. if (isNaN(lat) || isNaN(lng)) {
  1390. throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')');
  1391. }
  1392. // @property lat: Number
  1393. // Latitude in degrees
  1394. this.lat = +lat;
  1395. // @property lng: Number
  1396. // Longitude in degrees
  1397. this.lng = +lng;
  1398. // @property alt: Number
  1399. // Altitude in meters (optional)
  1400. if (alt !== undefined) {
  1401. this.alt = +alt;
  1402. }
  1403. };
  1404. L.LatLng.prototype = {
  1405. // @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean
  1406. // Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overriden by setting `maxMargin` to a small number.
  1407. equals: function (obj, maxMargin) {
  1408. if (!obj) { return false; }
  1409. obj = L.latLng(obj);
  1410. var margin = Math.max(
  1411. Math.abs(this.lat - obj.lat),
  1412. Math.abs(this.lng - obj.lng));
  1413. return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin);
  1414. },
  1415. // @method toString(): String
  1416. // Returns a string representation of the point (for debugging purposes).
  1417. toString: function (precision) {
  1418. return 'LatLng(' +
  1419. L.Util.formatNum(this.lat, precision) + ', ' +
  1420. L.Util.formatNum(this.lng, precision) + ')';
  1421. },
  1422. // @method distanceTo(otherLatLng: LatLng): Number
  1423. // Returns the distance (in meters) to the given `LatLng` calculated using the [Haversine formula](http://en.wikipedia.org/wiki/Haversine_formula).
  1424. distanceTo: function (other) {
  1425. return L.CRS.Earth.distance(this, L.latLng(other));
  1426. },
  1427. // @method wrap(): LatLng
  1428. // Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees.
  1429. wrap: function () {
  1430. return L.CRS.Earth.wrapLatLng(this);
  1431. },
  1432. // @method toBounds(sizeInMeters: Number): LatLngBounds
  1433. // Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters` meters apart from the `LatLng`.
  1434. toBounds: function (sizeInMeters) {
  1435. var latAccuracy = 180 * sizeInMeters / 40075017,
  1436. lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat);
  1437. return L.latLngBounds(
  1438. [this.lat - latAccuracy, this.lng - lngAccuracy],
  1439. [this.lat + latAccuracy, this.lng + lngAccuracy]);
  1440. },
  1441. clone: function () {
  1442. return new L.LatLng(this.lat, this.lng, this.alt);
  1443. }
  1444. };
  1445. // @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng
  1446. // Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude).
  1447. // @alternative
  1448. // @factory L.latLng(coords: Array): LatLng
  1449. // Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead.
  1450. // @alternative
  1451. // @factory L.latLng(coords: Object): LatLng
  1452. // Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead.
  1453. L.latLng = function (a, b, c) {
  1454. if (a instanceof L.LatLng) {
  1455. return a;
  1456. }
  1457. if (L.Util.isArray(a) && typeof a[0] !== 'object') {
  1458. if (a.length === 3) {
  1459. return new L.LatLng(a[0], a[1], a[2]);
  1460. }
  1461. if (a.length === 2) {
  1462. return new L.LatLng(a[0], a[1]);
  1463. }
  1464. return null;
  1465. }
  1466. if (a === undefined || a === null) {
  1467. return a;
  1468. }
  1469. if (typeof a === 'object' && 'lat' in a) {
  1470. return new L.LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt);
  1471. }
  1472. if (b === undefined) {
  1473. return null;
  1474. }
  1475. return new L.LatLng(a, b, c);
  1476. };
  1477. /*
  1478. * @class LatLngBounds
  1479. * @aka L.LatLngBounds
  1480. *
  1481. * Represents a rectangular geographical area on a map.
  1482. *
  1483. * @example
  1484. *
  1485. * ```js
  1486. * var corner1 = L.latLng(40.712, -74.227),
  1487. * corner2 = L.latLng(40.774, -74.125),
  1488. * bounds = L.latLngBounds(corner1, corner2);
  1489. * ```
  1490. *
  1491. * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this:
  1492. *
  1493. * ```js
  1494. * map.fitBounds([
  1495. * [40.712, -74.227],
  1496. * [40.774, -74.125]
  1497. * ]);
  1498. * ```
  1499. *
  1500. * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range.
  1501. */
  1502. L.LatLngBounds = function (corner1, corner2) { // (LatLng, LatLng) or (LatLng[])
  1503. if (!corner1) { return; }
  1504. var latlngs = corner2 ? [corner1, corner2] : corner1;
  1505. for (var i = 0, len = latlngs.length; i < len; i++) {
  1506. this.extend(latlngs[i]);
  1507. }
  1508. };
  1509. L.LatLngBounds.prototype = {
  1510. // @method extend(latlng: LatLng): this
  1511. // Extend the bounds to contain the given point
  1512. // @alternative
  1513. // @method extend(otherBounds: LatLngBounds): this
  1514. // Extend the bounds to contain the given bounds
  1515. extend: function (obj) {
  1516. var sw = this._southWest,
  1517. ne = this._northEast,
  1518. sw2, ne2;
  1519. if (obj instanceof L.LatLng) {
  1520. sw2 = obj;
  1521. ne2 = obj;
  1522. } else if (obj instanceof L.LatLngBounds) {
  1523. sw2 = obj._southWest;
  1524. ne2 = obj._northEast;
  1525. if (!sw2 || !ne2) { return this; }
  1526. } else {
  1527. return obj ? this.extend(L.latLng(obj) || L.latLngBounds(obj)) : this;
  1528. }
  1529. if (!sw && !ne) {
  1530. this._southWest = new L.LatLng(sw2.lat, sw2.lng);
  1531. this._northEast = new L.LatLng(ne2.lat, ne2.lng);
  1532. } else {
  1533. sw.lat = Math.min(sw2.lat, sw.lat);
  1534. sw.lng = Math.min(sw2.lng, sw.lng);
  1535. ne.lat = Math.max(ne2.lat, ne.lat);
  1536. ne.lng = Math.max(ne2.lng, ne.lng);
  1537. }
  1538. return this;
  1539. },
  1540. // @method pad(bufferRatio: Number): LatLngBounds
  1541. // Returns bigger bounds created by extending the current bounds by a given percentage in each direction.
  1542. pad: function (bufferRatio) {
  1543. var sw = this._southWest,
  1544. ne = this._northEast,
  1545. heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio,
  1546. widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio;
  1547. return new L.LatLngBounds(
  1548. new L.LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer),
  1549. new L.LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer));
  1550. },
  1551. // @method getCenter(): LatLng
  1552. // Returns the center point of the bounds.
  1553. getCenter: function () {
  1554. return new L.LatLng(
  1555. (this._southWest.lat + this._northEast.lat) / 2,
  1556. (this._southWest.lng + this._northEast.lng) / 2);
  1557. },
  1558. // @method getSouthWest(): LatLng
  1559. // Returns the south-west point of the bounds.
  1560. getSouthWest: function () {
  1561. return this._southWest;
  1562. },
  1563. // @method getNorthEast(): LatLng
  1564. // Returns the north-east point of the bounds.
  1565. getNorthEast: function () {
  1566. return this._northEast;
  1567. },
  1568. // @method getNorthWest(): LatLng
  1569. // Returns the north-west point of the bounds.
  1570. getNorthWest: function () {
  1571. return new L.LatLng(this.getNorth(), this.getWest());
  1572. },
  1573. // @method getSouthEast(): LatLng
  1574. // Returns the south-east point of the bounds.
  1575. getSouthEast: function () {
  1576. return new L.LatLng(this.getSouth(), this.getEast());
  1577. },
  1578. // @method getWest(): Number
  1579. // Returns the west longitude of the bounds
  1580. getWest: function () {
  1581. return this._southWest.lng;
  1582. },
  1583. // @method getSouth(): Number
  1584. // Returns the south latitude of the bounds
  1585. getSouth: function () {
  1586. return this._southWest.lat;
  1587. },
  1588. // @method getEast(): Number
  1589. // Returns the east longitude of the bounds
  1590. getEast: function () {
  1591. return this._northEast.lng;
  1592. },
  1593. // @method getNorth(): Number
  1594. // Returns the north latitude of the bounds
  1595. getNorth: function () {
  1596. return this._northEast.lat;
  1597. },
  1598. // @method contains(otherBounds: LatLngBounds): Boolean
  1599. // Returns `true` if the rectangle contains the given one.
  1600. // @alternative
  1601. // @method contains (latlng: LatLng): Boolean
  1602. // Returns `true` if the rectangle contains the given point.
  1603. contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean
  1604. if (typeof obj[0] === 'number' || obj instanceof L.LatLng) {
  1605. obj = L.latLng(obj);
  1606. } else {
  1607. obj = L.latLngBounds(obj);
  1608. }
  1609. var sw = this._southWest,
  1610. ne = this._northEast,
  1611. sw2, ne2;
  1612. if (obj instanceof L.LatLngBounds) {
  1613. sw2 = obj.getSouthWest();
  1614. ne2 = obj.getNorthEast();
  1615. } else {
  1616. sw2 = ne2 = obj;
  1617. }
  1618. return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) &&
  1619. (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng);
  1620. },
  1621. // @method intersects(otherBounds: LatLngBounds): Boolean
  1622. // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common.
  1623. intersects: function (bounds) {
  1624. bounds = L.latLngBounds(bounds);
  1625. var sw = this._southWest,
  1626. ne = this._northEast,
  1627. sw2 = bounds.getSouthWest(),
  1628. ne2 = bounds.getNorthEast(),
  1629. latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat),
  1630. lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng);
  1631. return latIntersects && lngIntersects;
  1632. },
  1633. // @method overlaps(otherBounds: Bounds): Boolean
  1634. // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area.
  1635. overlaps: function (bounds) {
  1636. bounds = L.latLngBounds(bounds);
  1637. var sw = this._southWest,
  1638. ne = this._northEast,
  1639. sw2 = bounds.getSouthWest(),
  1640. ne2 = bounds.getNorthEast(),
  1641. latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat),
  1642. lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng);
  1643. return latOverlaps && lngOverlaps;
  1644. },
  1645. // @method toBBoxString(): String
  1646. // Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data.
  1647. toBBoxString: function () {
  1648. return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(',');
  1649. },
  1650. // @method equals(otherBounds: LatLngBounds): Boolean
  1651. // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds.
  1652. equals: function (bounds) {
  1653. if (!bounds) { return false; }
  1654. bounds = L.latLngBounds(bounds);
  1655. return this._southWest.equals(bounds.getSouthWest()) &&
  1656. this._northEast.equals(bounds.getNorthEast());
  1657. },
  1658. // @method isValid(): Boolean
  1659. // Returns `true` if the bounds are properly initialized.
  1660. isValid: function () {
  1661. return !!(this._southWest && this._northEast);
  1662. }
  1663. };
  1664. // TODO International date line?
  1665. // @factory L.latLngBounds(corner1: LatLng, corner2: LatLng)
  1666. // Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle.
  1667. // @alternative
  1668. // @factory L.latLngBounds(latlngs: LatLng[])
  1669. // Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds).
  1670. L.latLngBounds = function (a, b) {
  1671. if (a instanceof L.LatLngBounds) {
  1672. return a;
  1673. }
  1674. return new L.LatLngBounds(a, b);
  1675. };
  1676. /*
  1677. * @namespace Projection
  1678. * @section
  1679. * Leaflet comes with a set of already defined Projections out of the box:
  1680. *
  1681. * @projection L.Projection.LonLat
  1682. *
  1683. * Equirectangular, or Plate Carree projection — the most simple projection,
  1684. * mostly used by GIS enthusiasts. Directly maps `x` as longitude, and `y` as
  1685. * latitude. Also suitable for flat worlds, e.g. game maps. Used by the
  1686. * `EPSG:3395` and `Simple` CRS.
  1687. */
  1688. L.Projection = {};
  1689. L.Projection.LonLat = {
  1690. project: function (latlng) {
  1691. return new L.Point(latlng.lng, latlng.lat);
  1692. },
  1693. unproject: function (point) {
  1694. return new L.LatLng(point.y, point.x);
  1695. },
  1696. bounds: L.bounds([-180, -90], [180, 90])
  1697. };
  1698. /*
  1699. * @namespace Projection
  1700. * @projection L.Projection.SphericalMercator
  1701. *
  1702. * Spherical Mercator projection — the most common projection for online maps,
  1703. * used by almost all free and commercial tile providers. Assumes that Earth is
  1704. * a sphere. Used by the `EPSG:3857` CRS.
  1705. */
  1706. L.Projection.SphericalMercator = {
  1707. R: 6378137,
  1708. MAX_LATITUDE: 85.0511287798,
  1709. project: function (latlng) {
  1710. var d = Math.PI / 180,
  1711. max = this.MAX_LATITUDE,
  1712. lat = Math.max(Math.min(max, latlng.lat), -max),
  1713. sin = Math.sin(lat * d);
  1714. return new L.Point(
  1715. this.R * latlng.lng * d,
  1716. this.R * Math.log((1 + sin) / (1 - sin)) / 2);
  1717. },
  1718. unproject: function (point) {
  1719. var d = 180 / Math.PI;
  1720. return new L.LatLng(
  1721. (2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d,
  1722. point.x * d / this.R);
  1723. },
  1724. bounds: (function () {
  1725. var d = 6378137 * Math.PI;
  1726. return L.bounds([-d, -d], [d, d]);
  1727. })()
  1728. };
  1729. /*
  1730. * @class CRS
  1731. * @aka L.CRS
  1732. * Abstract class that defines coordinate reference systems for projecting
  1733. * geographical points into pixel (screen) coordinates and back (and to
  1734. * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See
  1735. * [spatial reference system](http://en.wikipedia.org/wiki/Coordinate_reference_system).
  1736. *
  1737. * Leaflet defines the most usual CRSs by default. If you want to use a
  1738. * CRS not defined by default, take a look at the
  1739. * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin.
  1740. */
  1741. L.CRS = {
  1742. // @method latLngToPoint(latlng: LatLng, zoom: Number): Point
  1743. // Projects geographical coordinates into pixel coordinates for a given zoom.
  1744. latLngToPoint: function (latlng, zoom) {
  1745. var projectedPoint = this.projection.project(latlng),
  1746. scale = this.scale(zoom);
  1747. return this.transformation._transform(projectedPoint, scale);
  1748. },
  1749. // @method pointToLatLng(point: Point, zoom: Number): LatLng
  1750. // The inverse of `latLngToPoint`. Projects pixel coordinates on a given
  1751. // zoom into geographical coordinates.
  1752. pointToLatLng: function (point, zoom) {
  1753. var scale = this.scale(zoom),
  1754. untransformedPoint = this.transformation.untransform(point, scale);
  1755. return this.projection.unproject(untransformedPoint);
  1756. },
  1757. // @method project(latlng: LatLng): Point
  1758. // Projects geographical coordinates into coordinates in units accepted for
  1759. // this CRS (e.g. meters for EPSG:3857, for passing it to WMS services).
  1760. project: function (latlng) {
  1761. return this.projection.project(latlng);
  1762. },
  1763. // @method unproject(point: Point): LatLng
  1764. // Given a projected coordinate returns the corresponding LatLng.
  1765. // The inverse of `project`.
  1766. unproject: function (point) {
  1767. return this.projection.unproject(point);
  1768. },
  1769. // @method scale(zoom: Number): Number
  1770. // Returns the scale used when transforming projected coordinates into
  1771. // pixel coordinates for a particular zoom. For example, it returns
  1772. // `256 * 2^zoom` for Mercator-based CRS.
  1773. scale: function (zoom) {
  1774. return 256 * Math.pow(2, zoom);
  1775. },
  1776. // @method zoom(scale: Number): Number
  1777. // Inverse of `scale()`, returns the zoom level corresponding to a scale
  1778. // factor of `scale`.
  1779. zoom: function (scale) {
  1780. return Math.log(scale / 256) / Math.LN2;
  1781. },
  1782. // @method getProjectedBounds(zoom: Number): Bounds
  1783. // Returns the projection's bounds scaled and transformed for the provided `zoom`.
  1784. getProjectedBounds: function (zoom) {
  1785. if (this.infinite) { return null; }
  1786. var b = this.projection.bounds,
  1787. s = this.scale(zoom),
  1788. min = this.transformation.transform(b.min, s),
  1789. max = this.transformation.transform(b.max, s);
  1790. return L.bounds(min, max);
  1791. },
  1792. // @method distance(latlng1: LatLng, latlng2: LatLng): Number
  1793. // Returns the distance between two geographical coordinates.
  1794. // @property code: String
  1795. // Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`)
  1796. //
  1797. // @property wrapLng: Number[]
  1798. // An array of two numbers defining whether the longitude (horizontal) coordinate
  1799. // axis wraps around a given range and how. Defaults to `[-180, 180]` in most
  1800. // geographical CRSs. If `undefined`, the longitude axis does not wrap around.
  1801. //
  1802. // @property wrapLat: Number[]
  1803. // Like `wrapLng`, but for the latitude (vertical) axis.
  1804. // wrapLng: [min, max],
  1805. // wrapLat: [min, max],
  1806. // @property infinite: Boolean
  1807. // If true, the coordinate space will be unbounded (infinite in both axes)
  1808. infinite: false,
  1809. // @method wrapLatLng(latlng: LatLng): LatLng
  1810. // Returns a `LatLng` where lat and lng has been wrapped according to the
  1811. // CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds.
  1812. wrapLatLng: function (latlng) {
  1813. var lng = this.wrapLng ? L.Util.wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng,
  1814. lat = this.wrapLat ? L.Util.wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat,
  1815. alt = latlng.alt;
  1816. return L.latLng(lat, lng, alt);
  1817. }
  1818. };
  1819. /*
  1820. * @namespace CRS
  1821. * @crs L.CRS.Simple
  1822. *
  1823. * A simple CRS that maps longitude and latitude into `x` and `y` directly.
  1824. * May be used for maps of flat surfaces (e.g. game maps). Note that the `y`
  1825. * axis should still be inverted (going from bottom to top). `distance()` returns
  1826. * simple euclidean distance.
  1827. */
  1828. L.CRS.Simple = L.extend({}, L.CRS, {
  1829. projection: L.Projection.LonLat,
  1830. transformation: new L.Transformation(1, 0, -1, 0),
  1831. scale: function (zoom) {
  1832. return Math.pow(2, zoom);
  1833. },
  1834. zoom: function (scale) {
  1835. return Math.log(scale) / Math.LN2;
  1836. },
  1837. distance: function (latlng1, latlng2) {
  1838. var dx = latlng2.lng - latlng1.lng,
  1839. dy = latlng2.lat - latlng1.lat;
  1840. return Math.sqrt(dx * dx + dy * dy);
  1841. },
  1842. infinite: true
  1843. });
  1844. /*
  1845. * @namespace CRS
  1846. * @crs L.CRS.Earth
  1847. *
  1848. * Serves as the base for CRS that are global such that they cover the earth.
  1849. * Can only be used as the base for other CRS and cannot be used directly,
  1850. * since it does not have a `code`, `projection` or `transformation`. `distance()` returns
  1851. * meters.
  1852. */
  1853. L.CRS.Earth = L.extend({}, L.CRS, {
  1854. wrapLng: [-180, 180],
  1855. // Mean Earth Radius, as recommended for use by
  1856. // the International Union of Geodesy and Geophysics,
  1857. // see http://rosettacode.org/wiki/Haversine_formula
  1858. R: 6371000,
  1859. // distance between two geographical points using spherical law of cosines approximation
  1860. distance: function (latlng1, latlng2) {
  1861. var rad = Math.PI / 180,
  1862. lat1 = latlng1.lat * rad,
  1863. lat2 = latlng2.lat * rad,
  1864. a = Math.sin(lat1) * Math.sin(lat2) +
  1865. Math.cos(lat1) * Math.cos(lat2) * Math.cos((latlng2.lng - latlng1.lng) * rad);
  1866. return this.R * Math.acos(Math.min(a, 1));
  1867. }
  1868. });
  1869. /*
  1870. * @namespace CRS
  1871. * @crs L.CRS.EPSG3857
  1872. *
  1873. * The most common CRS for online maps, used by almost all free and commercial
  1874. * tile providers. Uses Spherical Mercator projection. Set in by default in
  1875. * Map's `crs` option.
  1876. */
  1877. L.CRS.EPSG3857 = L.extend({}, L.CRS.Earth, {
  1878. code: 'EPSG:3857',
  1879. projection: L.Projection.SphericalMercator,
  1880. transformation: (function () {
  1881. var scale = 0.5 / (Math.PI * L.Projection.SphericalMercator.R);
  1882. return new L.Transformation(scale, 0.5, -scale, 0.5);
  1883. }())
  1884. });
  1885. L.CRS.EPSG900913 = L.extend({}, L.CRS.EPSG3857, {
  1886. code: 'EPSG:900913'
  1887. });
  1888. /*
  1889. * @namespace CRS
  1890. * @crs L.CRS.EPSG4326
  1891. *
  1892. * A common CRS among GIS enthusiasts. Uses simple Equirectangular projection.
  1893. *
  1894. * Leaflet 1.0.x complies with the [TMS coordinate scheme for EPSG:4326](https://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic),
  1895. * which is a breaking change from 0.7.x behaviour. If you are using a `TileLayer`
  1896. * with this CRS, ensure that there are two 256x256 pixel tiles covering the
  1897. * whole earth at zoom level zero, and that the tile coordinate origin is (-180,+90),
  1898. * or (-180,-90) for `TileLayer`s with [the `tms` option](#tilelayer-tms) set.
  1899. */
  1900. L.CRS.EPSG4326 = L.extend({}, L.CRS.Earth, {
  1901. code: 'EPSG:4326',
  1902. projection: L.Projection.LonLat,
  1903. transformation: new L.Transformation(1 / 180, 1, -1 / 180, 0.5)
  1904. });
  1905. /*
  1906. * @class Map
  1907. * @aka L.Map
  1908. * @inherits Evented
  1909. *
  1910. * The central class of the API — it is used to create a map on a page and manipulate it.
  1911. *
  1912. * @example
  1913. *
  1914. * ```js
  1915. * // initialize the map on the "map" div with a given center and zoom
  1916. * var map = L.map('map', {
  1917. * center: [51.505, -0.09],
  1918. * zoom: 13
  1919. * });
  1920. * ```
  1921. *
  1922. */
  1923. L.Map = L.Evented.extend({
  1924. options: {
  1925. // @section Map State Options
  1926. // @option crs: CRS = L.CRS.EPSG3857
  1927. // The [Coordinate Reference System](#crs) to use. Don't change this if you're not
  1928. // sure what it means.
  1929. crs: L.CRS.EPSG3857,
  1930. // @option center: LatLng = undefined
  1931. // Initial geographic center of the map
  1932. center: undefined,
  1933. // @option zoom: Number = undefined
  1934. // Initial map zoom level
  1935. zoom: undefined,
  1936. // @option minZoom: Number = undefined
  1937. // Minimum zoom level of the map. Overrides any `minZoom` option set on map layers.
  1938. minZoom: undefined,
  1939. // @option maxZoom: Number = undefined
  1940. // Maximum zoom level of the map. Overrides any `maxZoom` option set on map layers.
  1941. maxZoom: undefined,
  1942. // @option layers: Layer[] = []
  1943. // Array of layers that will be added to the map initially
  1944. layers: [],
  1945. // @option maxBounds: LatLngBounds = null
  1946. // When this option is set, the map restricts the view to the given
  1947. // geographical bounds, bouncing the user back when he tries to pan
  1948. // outside the view. To set the restriction dynamically, use
  1949. // [`setMaxBounds`](#map-setmaxbounds) method.
  1950. maxBounds: undefined,
  1951. // @option renderer: Renderer = *
  1952. // The default method for drawing vector layers on the map. `L.SVG`
  1953. // or `L.Canvas` by default depending on browser support.
  1954. renderer: undefined,
  1955. // @section Animation Options
  1956. // @option zoomAnimation: Boolean = true
  1957. // Whether the map zoom animation is enabled. By default it's enabled
  1958. // in all browsers that support CSS3 Transitions except Android.
  1959. zoomAnimation: true,
  1960. // @option zoomAnimationThreshold: Number = 4
  1961. // Won't animate zoom if the zoom difference exceeds this value.
  1962. zoomAnimationThreshold: 4,
  1963. // @option fadeAnimation: Boolean = true
  1964. // Whether the tile fade animation is enabled. By default it's enabled
  1965. // in all browsers that support CSS3 Transitions except Android.
  1966. fadeAnimation: true,
  1967. // @option markerZoomAnimation: Boolean = true
  1968. // Whether markers animate their zoom with the zoom animation, if disabled
  1969. // they will disappear for the length of the animation. By default it's
  1970. // enabled in all browsers that support CSS3 Transitions except Android.
  1971. markerZoomAnimation: true,
  1972. // @option transform3DLimit: Number = 2^23
  1973. // Defines the maximum size of a CSS translation transform. The default
  1974. // value should not be changed unless a web browser positions layers in
  1975. // the wrong place after doing a large `panBy`.
  1976. transform3DLimit: 8388608, // Precision limit of a 32-bit float
  1977. // @section Interaction Options
  1978. // @option zoomSnap: Number = 1
  1979. // Forces the map's zoom level to always be a multiple of this, particularly
  1980. // right after a [`fitBounds()`](#map-fitbounds) or a pinch-zoom.
  1981. // By default, the zoom level snaps to the nearest integer; lower values
  1982. // (e.g. `0.5` or `0.1`) allow for greater granularity. A value of `0`
  1983. // means the zoom level will not be snapped after `fitBounds` or a pinch-zoom.
  1984. zoomSnap: 1,
  1985. // @option zoomDelta: Number = 1
  1986. // Controls how much the map's zoom level will change after a
  1987. // [`zoomIn()`](#map-zoomin), [`zoomOut()`](#map-zoomout), pressing `+`
  1988. // or `-` on the keyboard, or using the [zoom controls](#control-zoom).
  1989. // Values smaller than `1` (e.g. `0.5`) allow for greater granularity.
  1990. zoomDelta: 1,
  1991. // @option trackResize: Boolean = true
  1992. // Whether the map automatically handles browser window resize to update itself.
  1993. trackResize: true
  1994. },
  1995. initialize: function (id, options) { // (HTMLElement or String, Object)
  1996. options = L.setOptions(this, options);
  1997. this._initContainer(id);
  1998. this._initLayout();
  1999. // hack for https://github.com/Leaflet/Leaflet/issues/1980
  2000. this._onResize = L.bind(this._onResize, this);
  2001. this._initEvents();
  2002. if (options.maxBounds) {
  2003. this.setMaxBounds(options.maxBounds);
  2004. }
  2005. if (options.zoom !== undefined) {
  2006. this._zoom = this._limitZoom(options.zoom);
  2007. }
  2008. if (options.center && options.zoom !== undefined) {
  2009. this.setView(L.latLng(options.center), options.zoom, {reset: true});
  2010. }
  2011. this._handlers = [];
  2012. this._layers = {};
  2013. this._zoomBoundLayers = {};
  2014. this._sizeChanged = true;
  2015. this.callInitHooks();
  2016. // don't animate on browsers without hardware-accelerated transitions or old Android/Opera
  2017. this._zoomAnimated = L.DomUtil.TRANSITION && L.Browser.any3d && !L.Browser.mobileOpera &&
  2018. this.options.zoomAnimation;
  2019. // zoom transitions run with the same duration for all layers, so if one of transitionend events
  2020. // happens after starting zoom animation (propagating to the map pane), we know that it ended globally
  2021. if (this._zoomAnimated) {
  2022. this._createAnimProxy();
  2023. L.DomEvent.on(this._proxy, L.DomUtil.TRANSITION_END, this._catchTransitionEnd, this);
  2024. }
  2025. this._addLayers(this.options.layers);
  2026. },
  2027. // @section Methods for modifying map state
  2028. // @method setView(center: LatLng, zoom: Number, options?: Zoom/pan options): this
  2029. // Sets the view of the map (geographical center and zoom) with the given
  2030. // animation options.
  2031. setView: function (center, zoom, options) {
  2032. zoom = zoom === undefined ? this._zoom : this._limitZoom(zoom);
  2033. center = this._limitCenter(L.latLng(center), zoom, this.options.maxBounds);
  2034. options = options || {};
  2035. this._stop();
  2036. if (this._loaded && !options.reset && options !== true) {
  2037. if (options.animate !== undefined) {
  2038. options.zoom = L.extend({animate: options.animate}, options.zoom);
  2039. options.pan = L.extend({animate: options.animate, duration: options.duration}, options.pan);
  2040. }
  2041. // try animating pan or zoom
  2042. var moved = (this._zoom !== zoom) ?
  2043. this._tryAnimatedZoom && this._tryAnimatedZoom(center, zoom, options.zoom) :
  2044. this._tryAnimatedPan(center, options.pan);
  2045. if (moved) {
  2046. // prevent resize handler call, the view will refresh after animation anyway
  2047. clearTimeout(this._sizeTimer);
  2048. return this;
  2049. }
  2050. }
  2051. // animation didn't start, just reset the map view
  2052. this._resetView(center, zoom);
  2053. return this;
  2054. },
  2055. // @method setZoom(zoom: Number, options: Zoom/pan options): this
  2056. // Sets the zoom of the map.
  2057. setZoom: function (zoom, options) {
  2058. if (!this._loaded) {
  2059. this._zoom = zoom;
  2060. return this;
  2061. }
  2062. return this.setView(this.getCenter(), zoom, {zoom: options});
  2063. },
  2064. // @method zoomIn(delta?: Number, options?: Zoom options): this
  2065. // Increases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
  2066. zoomIn: function (delta, options) {
  2067. delta = delta || (L.Browser.any3d ? this.options.zoomDelta : 1);
  2068. return this.setZoom(this._zoom + delta, options);
  2069. },
  2070. // @method zoomOut(delta?: Number, options?: Zoom options): this
  2071. // Decreases the zoom of the map by `delta` ([`zoomDelta`](#map-zoomdelta) by default).
  2072. zoomOut: function (delta, options) {
  2073. delta = delta || (L.Browser.any3d ? this.options.zoomDelta : 1);
  2074. return this.setZoom(this._zoom - delta, options);
  2075. },
  2076. // @method setZoomAround(latlng: LatLng, zoom: Number, options: Zoom options): this
  2077. // Zooms the map while keeping a specified geographical point on the map
  2078. // stationary (e.g. used internally for scroll zoom and double-click zoom).
  2079. // @alternative
  2080. // @method setZoomAround(offset: Point, zoom: Number, options: Zoom options): this
  2081. // Zooms the map while keeping a specified pixel on the map (relative to the top-left corner) stationary.
  2082. setZoomAround: function (latlng, zoom, options) {
  2083. var scale = this.getZoomScale(zoom),
  2084. viewHalf = this.getSize().divideBy(2),
  2085. containerPoint = latlng instanceof L.Point ? latlng : this.latLngToContainerPoint(latlng),
  2086. centerOffset = containerPoint.subtract(viewHalf).multiplyBy(1 - 1 / scale),
  2087. newCenter = this.containerPointToLatLng(viewHalf.add(centerOffset));
  2088. return this.setView(newCenter, zoom, {zoom: options});
  2089. },
  2090. _getBoundsCenterZoom: function (bounds, options) {
  2091. options = options || {};
  2092. bounds = bounds.getBounds ? bounds.getBounds() : L.latLngBounds(bounds);
  2093. var paddingTL = L.point(options.paddingTopLeft || options.padding || [0, 0]),
  2094. paddingBR = L.point(options.paddingBottomRight || options.padding || [0, 0]),
  2095. zoom = this.getBoundsZoom(bounds, false, paddingTL.add(paddingBR));
  2096. zoom = (typeof options.maxZoom === 'number') ? Math.min(options.maxZoom, zoom) : zoom;
  2097. var paddingOffset = paddingBR.subtract(paddingTL).divideBy(2),
  2098. swPoint = this.project(bounds.getSouthWest(), zoom),
  2099. nePoint = this.project(bounds.getNorthEast(), zoom),
  2100. center = this.unproject(swPoint.add(nePoint).divideBy(2).add(paddingOffset), zoom);
  2101. return {
  2102. center: center,
  2103. zoom: zoom
  2104. };
  2105. },
  2106. // @method fitBounds(bounds: LatLngBounds, options: fitBounds options): this
  2107. // Sets a map view that contains the given geographical bounds with the
  2108. // maximum zoom level possible.
  2109. fitBounds: function (bounds, options) {
  2110. bounds = L.latLngBounds(bounds);
  2111. if (!bounds.isValid()) {
  2112. throw new Error('Bounds are not valid.');
  2113. }
  2114. var target = this._getBoundsCenterZoom(bounds, options);
  2115. return this.setView(target.center, target.zoom, options);
  2116. },
  2117. // @method fitWorld(options?: fitBounds options): this
  2118. // Sets a map view that mostly contains the whole world with the maximum
  2119. // zoom level possible.
  2120. fitWorld: function (options) {
  2121. return this.fitBounds([[-90, -180], [90, 180]], options);
  2122. },
  2123. // @method panTo(latlng: LatLng, options?: Pan options): this
  2124. // Pans the map to a given center.
  2125. panTo: function (center, options) { // (LatLng)
  2126. return this.setView(center, this._zoom, {pan: options});
  2127. },
  2128. // @method panBy(offset: Point): this
  2129. // Pans the map by a given number of pixels (animated).
  2130. panBy: function (offset, options) {
  2131. offset = L.point(offset).round();
  2132. options = options || {};
  2133. if (!offset.x && !offset.y) {
  2134. return this.fire('moveend');
  2135. }
  2136. // If we pan too far, Chrome gets issues with tiles
  2137. // and makes them disappear or appear in the wrong place (slightly offset) #2602
  2138. if (options.animate !== true && !this.getSize().contains(offset)) {
  2139. this._resetView(this.unproject(this.project(this.getCenter()).add(offset)), this.getZoom());
  2140. return this;
  2141. }
  2142. if (!this._panAnim) {
  2143. this._panAnim = new L.PosAnimation();
  2144. this._panAnim.on({
  2145. 'step': this._onPanTransitionStep,
  2146. 'end': this._onPanTransitionEnd
  2147. }, this);
  2148. }
  2149. // don't fire movestart if animating inertia
  2150. if (!options.noMoveStart) {
  2151. this.fire('movestart');
  2152. }
  2153. // animate pan unless animate: false specified
  2154. if (options.animate !== false) {
  2155. L.DomUtil.addClass(this._mapPane, 'leaflet-pan-anim');
  2156. var newPos = this._getMapPanePos().subtract(offset).round();
  2157. this._panAnim.run(this._mapPane, newPos, options.duration || 0.25, options.easeLinearity);
  2158. } else {
  2159. this._rawPanBy(offset);
  2160. this.fire('move').fire('moveend');
  2161. }
  2162. return this;
  2163. },
  2164. // @method flyTo(latlng: LatLng, zoom?: Number, options?: Zoom/pan options): this
  2165. // Sets the view of the map (geographical center and zoom) performing a smooth
  2166. // pan-zoom animation.
  2167. flyTo: function (targetCenter, targetZoom, options) {
  2168. options = options || {};
  2169. if (options.animate === false || !L.Browser.any3d) {
  2170. return this.setView(targetCenter, targetZoom, options);
  2171. }
  2172. this._stop();
  2173. var from = this.project(this.getCenter()),
  2174. to = this.project(targetCenter),
  2175. size = this.getSize(),
  2176. startZoom = this._zoom;
  2177. targetCenter = L.latLng(targetCenter);
  2178. targetZoom = targetZoom === undefined ? startZoom : targetZoom;
  2179. var w0 = Math.max(size.x, size.y),
  2180. w1 = w0 * this.getZoomScale(startZoom, targetZoom),
  2181. u1 = (to.distanceTo(from)) || 1,
  2182. rho = 1.42,
  2183. rho2 = rho * rho;
  2184. function r(i) {
  2185. var s1 = i ? -1 : 1,
  2186. s2 = i ? w1 : w0,
  2187. t1 = w1 * w1 - w0 * w0 + s1 * rho2 * rho2 * u1 * u1,
  2188. b1 = 2 * s2 * rho2 * u1,
  2189. b = t1 / b1,
  2190. sq = Math.sqrt(b * b + 1) - b;
  2191. // workaround for floating point precision bug when sq = 0, log = -Infinite,
  2192. // thus triggering an infinite loop in flyTo
  2193. var log = sq < 0.000000001 ? -18 : Math.log(sq);
  2194. return log;
  2195. }
  2196. function sinh(n) { return (Math.exp(n) - Math.exp(-n)) / 2; }
  2197. function cosh(n) { return (Math.exp(n) + Math.exp(-n)) / 2; }
  2198. function tanh(n) { return sinh(n) / cosh(n); }
  2199. var r0 = r(0);
  2200. function w(s) { return w0 * (cosh(r0) / cosh(r0 + rho * s)); }
  2201. function u(s) { return w0 * (cosh(r0) * tanh(r0 + rho * s) - sinh(r0)) / rho2; }
  2202. function easeOut(t) { return 1 - Math.pow(1 - t, 1.5); }
  2203. var start = Date.now(),
  2204. S = (r(1) - r0) / rho,
  2205. duration = options.duration ? 1000 * options.duration : 1000 * S * 0.8;
  2206. function frame() {
  2207. var t = (Date.now() - start) / duration,
  2208. s = easeOut(t) * S;
  2209. if (t <= 1) {
  2210. this._flyToFrame = L.Util.requestAnimFrame(frame, this);
  2211. this._move(
  2212. this.unproject(from.add(to.subtract(from).multiplyBy(u(s) / u1)), startZoom),
  2213. this.getScaleZoom(w0 / w(s), startZoom),
  2214. {flyTo: true});
  2215. } else {
  2216. this
  2217. ._move(targetCenter, targetZoom)
  2218. ._moveEnd(true);
  2219. }
  2220. }
  2221. this._moveStart(true);
  2222. frame.call(this);
  2223. return this;
  2224. },
  2225. // @method flyToBounds(bounds: LatLngBounds, options?: fitBounds options): this
  2226. // Sets the view of the map with a smooth animation like [`flyTo`](#map-flyto),
  2227. // but takes a bounds parameter like [`fitBounds`](#map-fitbounds).
  2228. flyToBounds: function (bounds, options) {
  2229. var target = this._getBoundsCenterZoom(bounds, options);
  2230. return this.flyTo(target.center, target.zoom, options);
  2231. },
  2232. // @method setMaxBounds(bounds: Bounds): this
  2233. // Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option).
  2234. setMaxBounds: function (bounds) {
  2235. bounds = L.latLngBounds(bounds);
  2236. if (!bounds.isValid()) {
  2237. this.options.maxBounds = null;
  2238. return this.off('moveend', this._panInsideMaxBounds);
  2239. } else if (this.options.maxBounds) {
  2240. this.off('moveend', this._panInsideMaxBounds);
  2241. }
  2242. this.options.maxBounds = bounds;
  2243. if (this._loaded) {
  2244. this._panInsideMaxBounds();
  2245. }
  2246. return this.on('moveend', this._panInsideMaxBounds);
  2247. },
  2248. // @method setMinZoom(zoom: Number): this
  2249. // Sets the lower limit for the available zoom levels (see the [minZoom](#map-minzoom) option).
  2250. setMinZoom: function (zoom) {
  2251. this.options.minZoom = zoom;
  2252. if (this._loaded && this.getZoom() < this.options.minZoom) {
  2253. return this.setZoom(zoom);
  2254. }
  2255. return this;
  2256. },
  2257. // @method setMaxZoom(zoom: Number): this
  2258. // Sets the upper limit for the available zoom levels (see the [maxZoom](#map-maxzoom) option).
  2259. setMaxZoom: function (zoom) {
  2260. this.options.maxZoom = zoom;
  2261. if (this._loaded && (this.getZoom() > this.options.maxZoom)) {
  2262. return this.setZoom(zoom);
  2263. }
  2264. return this;
  2265. },
  2266. // @method panInsideBounds(bounds: LatLngBounds, options?: Pan options): this
  2267. // Pans the map to the closest view that would lie inside the given bounds (if it's not already), controlling the animation using the options specific, if any.
  2268. panInsideBounds: function (bounds, options) {
  2269. this._enforcingBounds = true;
  2270. var center = this.getCenter(),
  2271. newCenter = this._limitCenter(center, this._zoom, L.latLngBounds(bounds));
  2272. if (!center.equals(newCenter)) {
  2273. this.panTo(newCenter, options);
  2274. }
  2275. this._enforcingBounds = false;
  2276. return this;
  2277. },
  2278. // @method invalidateSize(options: Zoom/Pan options): this
  2279. // Checks if the map container size changed and updates the map if so —
  2280. // call it after you've changed the map size dynamically, also animating
  2281. // pan by default. If `options.pan` is `false`, panning will not occur.
  2282. // If `options.debounceMoveend` is `true`, it will delay `moveend` event so
  2283. // that it doesn't happen often even if the method is called many
  2284. // times in a row.
  2285. // @alternative
  2286. // @method invalidateSize(animate: Boolean): this
  2287. // Checks if the map container size changed and updates the map if so —
  2288. // call it after you've changed the map size dynamically, also animating
  2289. // pan by default.
  2290. invalidateSize: function (options) {
  2291. if (!this._loaded) { return this; }
  2292. options = L.extend({
  2293. animate: false,
  2294. pan: true
  2295. }, options === true ? {animate: true} : options);
  2296. var oldSize = this.getSize();
  2297. this._sizeChanged = true;
  2298. this._lastCenter = null;
  2299. var newSize = this.getSize(),
  2300. oldCenter = oldSize.divideBy(2).round(),
  2301. newCenter = newSize.divideBy(2).round(),
  2302. offset = oldCenter.subtract(newCenter);
  2303. if (!offset.x && !offset.y) { return this; }
  2304. if (options.animate && options.pan) {
  2305. this.panBy(offset);
  2306. } else {
  2307. if (options.pan) {
  2308. this._rawPanBy(offset);
  2309. }
  2310. this.fire('move');
  2311. if (options.debounceMoveend) {
  2312. clearTimeout(this._sizeTimer);
  2313. this._sizeTimer = setTimeout(L.bind(this.fire, this, 'moveend'), 200);
  2314. } else {
  2315. this.fire('moveend');
  2316. }
  2317. }
  2318. // @section Map state change events
  2319. // @event resize: ResizeEvent
  2320. // Fired when the map is resized.
  2321. return this.fire('resize', {
  2322. oldSize: oldSize,
  2323. newSize: newSize
  2324. });
  2325. },
  2326. // @section Methods for modifying map state
  2327. // @method stop(): this
  2328. // Stops the currently running `panTo` or `flyTo` animation, if any.
  2329. stop: function () {
  2330. this.setZoom(this._limitZoom(this._zoom));
  2331. if (!this.options.zoomSnap) {
  2332. this.fire('viewreset');
  2333. }
  2334. return this._stop();
  2335. },
  2336. // @section Geolocation methods
  2337. // @method locate(options?: Locate options): this
  2338. // Tries to locate the user using the Geolocation API, firing a [`locationfound`](#map-locationfound)
  2339. // event with location data on success or a [`locationerror`](#map-locationerror) event on failure,
  2340. // and optionally sets the map view to the user's location with respect to
  2341. // detection accuracy (or to the world view if geolocation failed).
  2342. // Note that, if your page doesn't use HTTPS, this method will fail in
  2343. // modern browsers ([Chrome 50 and newer](https://sites.google.com/a/chromium.org/dev/Home/chromium-security/deprecating-powerful-features-on-insecure-origins))
  2344. // See `Locate options` for more details.
  2345. locate: function (options) {
  2346. options = this._locateOptions = L.extend({
  2347. timeout: 10000,
  2348. watch: false
  2349. // setView: false
  2350. // maxZoom: <Number>
  2351. // maximumAge: 0
  2352. // enableHighAccuracy: false
  2353. }, options);
  2354. if (!('geolocation' in navigator)) {
  2355. this._handleGeolocationError({
  2356. code: 0,
  2357. message: 'Geolocation not supported.'
  2358. });
  2359. return this;
  2360. }
  2361. var onResponse = L.bind(this._handleGeolocationResponse, this),
  2362. onError = L.bind(this._handleGeolocationError, this);
  2363. if (options.watch) {
  2364. this._locationWatchId =
  2365. navigator.geolocation.watchPosition(onResponse, onError, options);
  2366. } else {
  2367. navigator.geolocation.getCurrentPosition(onResponse, onError, options);
  2368. }
  2369. return this;
  2370. },
  2371. // @method stopLocate(): this
  2372. // Stops watching location previously initiated by `map.locate({watch: true})`
  2373. // and aborts resetting the map view if map.locate was called with
  2374. // `{setView: true}`.
  2375. stopLocate: function () {
  2376. if (navigator.geolocation && navigator.geolocation.clearWatch) {
  2377. navigator.geolocation.clearWatch(this._locationWatchId);
  2378. }
  2379. if (this._locateOptions) {
  2380. this._locateOptions.setView = false;
  2381. }
  2382. return this;
  2383. },
  2384. _handleGeolocationError: function (error) {
  2385. var c = error.code,
  2386. message = error.message ||
  2387. (c === 1 ? 'permission denied' :
  2388. (c === 2 ? 'position unavailable' : 'timeout'));
  2389. if (this._locateOptions.setView && !this._loaded) {
  2390. this.fitWorld();
  2391. }
  2392. // @section Location events
  2393. // @event locationerror: ErrorEvent
  2394. // Fired when geolocation (using the [`locate`](#map-locate) method) failed.
  2395. this.fire('locationerror', {
  2396. code: c,
  2397. message: 'Geolocation error: ' + message + '.'
  2398. });
  2399. },
  2400. _handleGeolocationResponse: function (pos) {
  2401. var lat = pos.coords.latitude,
  2402. lng = pos.coords.longitude,
  2403. latlng = new L.LatLng(lat, lng),
  2404. bounds = latlng.toBounds(pos.coords.accuracy),
  2405. options = this._locateOptions;
  2406. if (options.setView) {
  2407. var zoom = this.getBoundsZoom(bounds);
  2408. this.setView(latlng, options.maxZoom ? Math.min(zoom, options.maxZoom) : zoom);
  2409. }
  2410. var data = {
  2411. latlng: latlng,
  2412. bounds: bounds,
  2413. timestamp: pos.timestamp
  2414. };
  2415. for (var i in pos.coords) {
  2416. if (typeof pos.coords[i] === 'number') {
  2417. data[i] = pos.coords[i];
  2418. }
  2419. }
  2420. // @event locationfound: LocationEvent
  2421. // Fired when geolocation (using the [`locate`](#map-locate) method)
  2422. // went successfully.
  2423. this.fire('locationfound', data);
  2424. },
  2425. // TODO handler.addTo
  2426. // TODO Appropiate docs section?
  2427. // @section Other Methods
  2428. // @method addHandler(name: String, HandlerClass: Function): this
  2429. // Adds a new `Handler` to the map, given its name and constructor function.
  2430. addHandler: function (name, HandlerClass) {
  2431. if (!HandlerClass) { return this; }
  2432. var handler = this[name] = new HandlerClass(this);
  2433. this._handlers.push(handler);
  2434. if (this.options[name]) {
  2435. handler.enable();
  2436. }
  2437. return this;
  2438. },
  2439. // @method remove(): this
  2440. // Destroys the map and clears all related event listeners.
  2441. remove: function () {
  2442. this._initEvents(true);
  2443. if (this._containerId !== this._container._leaflet_id) {
  2444. throw new Error('Map container is being reused by another instance');
  2445. }
  2446. try {
  2447. // throws error in IE6-8
  2448. delete this._container._leaflet_id;
  2449. delete this._containerId;
  2450. } catch (e) {
  2451. /*eslint-disable */
  2452. this._container._leaflet_id = undefined;
  2453. /*eslint-enable */
  2454. this._containerId = undefined;
  2455. }
  2456. L.DomUtil.remove(this._mapPane);
  2457. if (this._clearControlPos) {
  2458. this._clearControlPos();
  2459. }
  2460. this._clearHandlers();
  2461. if (this._loaded) {
  2462. // @section Map state change events
  2463. // @event unload: Event
  2464. // Fired when the map is destroyed with [remove](#map-remove) method.
  2465. this.fire('unload');
  2466. }
  2467. for (var i in this._layers) {
  2468. this._layers[i].remove();
  2469. }
  2470. return this;
  2471. },
  2472. // @section Other Methods
  2473. // @method createPane(name: String, container?: HTMLElement): HTMLElement
  2474. // Creates a new [map pane](#map-pane) with the given name if it doesn't exist already,
  2475. // then returns it. The pane is created as a children of `container`, or
  2476. // as a children of the main map pane if not set.
  2477. createPane: function (name, container) {
  2478. var className = 'leaflet-pane' + (name ? ' leaflet-' + name.replace('Pane', '') + '-pane' : ''),
  2479. pane = L.DomUtil.create('div', className, container || this._mapPane);
  2480. if (name) {
  2481. this._panes[name] = pane;
  2482. }
  2483. return pane;
  2484. },
  2485. // @section Methods for Getting Map State
  2486. // @method getCenter(): LatLng
  2487. // Returns the geographical center of the map view
  2488. getCenter: function () {
  2489. this._checkIfLoaded();
  2490. if (this._lastCenter && !this._moved()) {
  2491. return this._lastCenter;
  2492. }
  2493. return this.layerPointToLatLng(this._getCenterLayerPoint());
  2494. },
  2495. // @method getZoom(): Number
  2496. // Returns the current zoom level of the map view
  2497. getZoom: function () {
  2498. return this._zoom;
  2499. },
  2500. // @method getBounds(): LatLngBounds
  2501. // Returns the geographical bounds visible in the current map view
  2502. getBounds: function () {
  2503. var bounds = this.getPixelBounds(),
  2504. sw = this.unproject(bounds.getBottomLeft()),
  2505. ne = this.unproject(bounds.getTopRight());
  2506. return new L.LatLngBounds(sw, ne);
  2507. },
  2508. // @method getMinZoom(): Number
  2509. // Returns the minimum zoom level of the map (if set in the `minZoom` option of the map or of any layers), or `0` by default.
  2510. getMinZoom: function () {
  2511. return this.options.minZoom === undefined ? this._layersMinZoom || 0 : this.options.minZoom;
  2512. },
  2513. // @method getMaxZoom(): Number
  2514. // Returns the maximum zoom level of the map (if set in the `maxZoom` option of the map or of any layers).
  2515. getMaxZoom: function () {
  2516. return this.options.maxZoom === undefined ?
  2517. (this._layersMaxZoom === undefined ? Infinity : this._layersMaxZoom) :
  2518. this.options.maxZoom;
  2519. },
  2520. // @method getBoundsZoom(bounds: LatLngBounds, inside?: Boolean): Number
  2521. // Returns the maximum zoom level on which the given bounds fit to the map
  2522. // view in its entirety. If `inside` (optional) is set to `true`, the method
  2523. // instead returns the minimum zoom level on which the map view fits into
  2524. // the given bounds in its entirety.
  2525. getBoundsZoom: function (bounds, inside, padding) { // (LatLngBounds[, Boolean, Point]) -> Number
  2526. bounds = L.latLngBounds(bounds);
  2527. padding = L.point(padding || [0, 0]);
  2528. var zoom = this.getZoom() || 0,
  2529. min = this.getMinZoom(),
  2530. max = this.getMaxZoom(),
  2531. nw = bounds.getNorthWest(),
  2532. se = bounds.getSouthEast(),
  2533. size = this.getSize().subtract(padding),
  2534. boundsSize = this.project(se, zoom).subtract(this.project(nw, zoom)),
  2535. snap = L.Browser.any3d ? this.options.zoomSnap : 1;
  2536. var scale = Math.min(size.x / boundsSize.x, size.y / boundsSize.y);
  2537. zoom = this.getScaleZoom(scale, zoom);
  2538. if (snap) {
  2539. zoom = Math.round(zoom / (snap / 100)) * (snap / 100); // don't jump if within 1% of a snap level
  2540. zoom = inside ? Math.ceil(zoom / snap) * snap : Math.floor(zoom / snap) * snap;
  2541. }
  2542. return Math.max(min, Math.min(max, zoom));
  2543. },
  2544. // @method getSize(): Point
  2545. // Returns the current size of the map container (in pixels).
  2546. getSize: function () {
  2547. if (!this._size || this._sizeChanged) {
  2548. this._size = new L.Point(
  2549. this._container.clientWidth,
  2550. this._container.clientHeight);
  2551. this._sizeChanged = false;
  2552. }
  2553. return this._size.clone();
  2554. },
  2555. // @method getPixelBounds(): Bounds
  2556. // Returns the bounds of the current map view in projected pixel
  2557. // coordinates (sometimes useful in layer and overlay implementations).
  2558. getPixelBounds: function (center, zoom) {
  2559. var topLeftPoint = this._getTopLeftPoint(center, zoom);
  2560. return new L.Bounds(topLeftPoint, topLeftPoint.add(this.getSize()));
  2561. },
  2562. // TODO: Check semantics - isn't the pixel origin the 0,0 coord relative to
  2563. // the map pane? "left point of the map layer" can be confusing, specially
  2564. // since there can be negative offsets.
  2565. // @method getPixelOrigin(): Point
  2566. // Returns the projected pixel coordinates of the top left point of
  2567. // the map layer (useful in custom layer and overlay implementations).
  2568. getPixelOrigin: function () {
  2569. this._checkIfLoaded();
  2570. return this._pixelOrigin;
  2571. },
  2572. // @method getPixelWorldBounds(zoom?: Number): Bounds
  2573. // Returns the world's bounds in pixel coordinates for zoom level `zoom`.
  2574. // If `zoom` is omitted, the map's current zoom level is used.
  2575. getPixelWorldBounds: function (zoom) {
  2576. return this.options.crs.getProjectedBounds(zoom === undefined ? this.getZoom() : zoom);
  2577. },
  2578. // @section Other Methods
  2579. // @method getPane(pane: String|HTMLElement): HTMLElement
  2580. // Returns a [map pane](#map-pane), given its name or its HTML element (its identity).
  2581. getPane: function (pane) {
  2582. return typeof pane === 'string' ? this._panes[pane] : pane;
  2583. },
  2584. // @method getPanes(): Object
  2585. // Returns a plain object containing the names of all [panes](#map-pane) as keys and
  2586. // the panes as values.
  2587. getPanes: function () {
  2588. return this._panes;
  2589. },
  2590. // @method getContainer: HTMLElement
  2591. // Returns the HTML element that contains the map.
  2592. getContainer: function () {
  2593. return this._container;
  2594. },
  2595. // @section Conversion Methods
  2596. // @method getZoomScale(toZoom: Number, fromZoom: Number): Number
  2597. // Returns the scale factor to be applied to a map transition from zoom level
  2598. // `fromZoom` to `toZoom`. Used internally to help with zoom animations.
  2599. getZoomScale: function (toZoom, fromZoom) {
  2600. // TODO replace with universal implementation after refactoring projections
  2601. var crs = this.options.crs;
  2602. fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
  2603. return crs.scale(toZoom) / crs.scale(fromZoom);
  2604. },
  2605. // @method getScaleZoom(scale: Number, fromZoom: Number): Number
  2606. // Returns the zoom level that the map would end up at, if it is at `fromZoom`
  2607. // level and everything is scaled by a factor of `scale`. Inverse of
  2608. // [`getZoomScale`](#map-getZoomScale).
  2609. getScaleZoom: function (scale, fromZoom) {
  2610. var crs = this.options.crs;
  2611. fromZoom = fromZoom === undefined ? this._zoom : fromZoom;
  2612. var zoom = crs.zoom(scale * crs.scale(fromZoom));
  2613. return isNaN(zoom) ? Infinity : zoom;
  2614. },
  2615. // @method project(latlng: LatLng, zoom: Number): Point
  2616. // Projects a geographical coordinate `LatLng` according to the projection
  2617. // of the map's CRS, then scales it according to `zoom` and the CRS's
  2618. // `Transformation`. The result is pixel coordinate relative to
  2619. // the CRS origin.
  2620. project: function (latlng, zoom) {
  2621. zoom = zoom === undefined ? this._zoom : zoom;
  2622. return this.options.crs.latLngToPoint(L.latLng(latlng), zoom);
  2623. },
  2624. // @method unproject(point: Point, zoom: Number): LatLng
  2625. // Inverse of [`project`](#map-project).
  2626. unproject: function (point, zoom) {
  2627. zoom = zoom === undefined ? this._zoom : zoom;
  2628. return this.options.crs.pointToLatLng(L.point(point), zoom);
  2629. },
  2630. // @method layerPointToLatLng(point: Point): LatLng
  2631. // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
  2632. // returns the corresponding geographical coordinate (for the current zoom level).
  2633. layerPointToLatLng: function (point) {
  2634. var projectedPoint = L.point(point).add(this.getPixelOrigin());
  2635. return this.unproject(projectedPoint);
  2636. },
  2637. // @method latLngToLayerPoint(latlng: LatLng): Point
  2638. // Given a geographical coordinate, returns the corresponding pixel coordinate
  2639. // relative to the [origin pixel](#map-getpixelorigin).
  2640. latLngToLayerPoint: function (latlng) {
  2641. var projectedPoint = this.project(L.latLng(latlng))._round();
  2642. return projectedPoint._subtract(this.getPixelOrigin());
  2643. },
  2644. // @method wrapLatLng(latlng: LatLng): LatLng
  2645. // Returns a `LatLng` where `lat` and `lng` has been wrapped according to the
  2646. // map's CRS's `wrapLat` and `wrapLng` properties, if they are outside the
  2647. // CRS's bounds.
  2648. // By default this means longitude is wrapped around the dateline so its
  2649. // value is between -180 and +180 degrees.
  2650. wrapLatLng: function (latlng) {
  2651. return this.options.crs.wrapLatLng(L.latLng(latlng));
  2652. },
  2653. // @method distance(latlng1: LatLng, latlng2: LatLng): Number
  2654. // Returns the distance between two geographical coordinates according to
  2655. // the map's CRS. By default this measures distance in meters.
  2656. distance: function (latlng1, latlng2) {
  2657. return this.options.crs.distance(L.latLng(latlng1), L.latLng(latlng2));
  2658. },
  2659. // @method containerPointToLayerPoint(point: Point): Point
  2660. // Given a pixel coordinate relative to the map container, returns the corresponding
  2661. // pixel coordinate relative to the [origin pixel](#map-getpixelorigin).
  2662. containerPointToLayerPoint: function (point) { // (Point)
  2663. return L.point(point).subtract(this._getMapPanePos());
  2664. },
  2665. // @method layerPointToContainerPoint(point: Point): Point
  2666. // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin),
  2667. // returns the corresponding pixel coordinate relative to the map container.
  2668. layerPointToContainerPoint: function (point) { // (Point)
  2669. return L.point(point).add(this._getMapPanePos());
  2670. },
  2671. // @method containerPointToLatLng(point: Point): Point
  2672. // Given a pixel coordinate relative to the map container, returns
  2673. // the corresponding geographical coordinate (for the current zoom level).
  2674. containerPointToLatLng: function (point) {
  2675. var layerPoint = this.containerPointToLayerPoint(L.point(point));
  2676. return this.layerPointToLatLng(layerPoint);
  2677. },
  2678. // @method latLngToContainerPoint(latlng: LatLng): Point
  2679. // Given a geographical coordinate, returns the corresponding pixel coordinate
  2680. // relative to the map container.
  2681. latLngToContainerPoint: function (latlng) {
  2682. return this.layerPointToContainerPoint(this.latLngToLayerPoint(L.latLng(latlng)));
  2683. },
  2684. // @method mouseEventToContainerPoint(ev: MouseEvent): Point
  2685. // Given a MouseEvent object, returns the pixel coordinate relative to the
  2686. // map container where the event took place.
  2687. mouseEventToContainerPoint: function (e) {
  2688. return L.DomEvent.getMousePosition(e, this._container);
  2689. },
  2690. // @method mouseEventToLayerPoint(ev: MouseEvent): Point
  2691. // Given a MouseEvent object, returns the pixel coordinate relative to
  2692. // the [origin pixel](#map-getpixelorigin) where the event took place.
  2693. mouseEventToLayerPoint: function (e) {
  2694. return this.containerPointToLayerPoint(this.mouseEventToContainerPoint(e));
  2695. },
  2696. // @method mouseEventToLatLng(ev: MouseEvent): LatLng
  2697. // Given a MouseEvent object, returns geographical coordinate where the
  2698. // event took place.
  2699. mouseEventToLatLng: function (e) { // (MouseEvent)
  2700. return this.layerPointToLatLng(this.mouseEventToLayerPoint(e));
  2701. },
  2702. // map initialization methods
  2703. _initContainer: function (id) {
  2704. var container = this._container = L.DomUtil.get(id);
  2705. if (!container) {
  2706. throw new Error('Map container not found.');
  2707. } else if (container._leaflet_id) {
  2708. throw new Error('Map container is already initialized.');
  2709. }
  2710. L.DomEvent.addListener(container, 'scroll', this._onScroll, this);
  2711. this._containerId = L.Util.stamp(container);
  2712. },
  2713. _initLayout: function () {
  2714. var container = this._container;
  2715. this._fadeAnimated = this.options.fadeAnimation && L.Browser.any3d;
  2716. L.DomUtil.addClass(container, 'leaflet-container' +
  2717. (L.Browser.touch ? ' leaflet-touch' : '') +
  2718. (L.Browser.retina ? ' leaflet-retina' : '') +
  2719. (L.Browser.ielt9 ? ' leaflet-oldie' : '') +
  2720. (L.Browser.safari ? ' leaflet-safari' : '') +
  2721. (this._fadeAnimated ? ' leaflet-fade-anim' : ''));
  2722. var position = L.DomUtil.getStyle(container, 'position');
  2723. if (position !== 'absolute' && position !== 'relative' && position !== 'fixed') {
  2724. container.style.position = 'relative';
  2725. }
  2726. this._initPanes();
  2727. if (this._initControlPos) {
  2728. this._initControlPos();
  2729. }
  2730. },
  2731. _initPanes: function () {
  2732. var panes = this._panes = {};
  2733. this._paneRenderers = {};
  2734. // @section
  2735. //
  2736. // Panes are DOM elements used to control the ordering of layers on the map. You
  2737. // can access panes with [`map.getPane`](#map-getpane) or
  2738. // [`map.getPanes`](#map-getpanes) methods. New panes can be created with the
  2739. // [`map.createPane`](#map-createpane) method.
  2740. //
  2741. // Every map has the following default panes that differ only in zIndex.
  2742. //
  2743. // @pane mapPane: HTMLElement = 'auto'
  2744. // Pane that contains all other map panes
  2745. this._mapPane = this.createPane('mapPane', this._container);
  2746. L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
  2747. // @pane tilePane: HTMLElement = 200
  2748. // Pane for `GridLayer`s and `TileLayer`s
  2749. this.createPane('tilePane');
  2750. // @pane overlayPane: HTMLElement = 400
  2751. // Pane for vector overlays (`Path`s), like `Polyline`s and `Polygon`s
  2752. this.createPane('shadowPane');
  2753. // @pane shadowPane: HTMLElement = 500
  2754. // Pane for overlay shadows (e.g. `Marker` shadows)
  2755. this.createPane('overlayPane');
  2756. // @pane markerPane: HTMLElement = 600
  2757. // Pane for `Icon`s of `Marker`s
  2758. this.createPane('markerPane');
  2759. // @pane tooltipPane: HTMLElement = 650
  2760. // Pane for tooltip.
  2761. this.createPane('tooltipPane');
  2762. // @pane popupPane: HTMLElement = 700
  2763. // Pane for `Popup`s.
  2764. this.createPane('popupPane');
  2765. if (!this.options.markerZoomAnimation) {
  2766. L.DomUtil.addClass(panes.markerPane, 'leaflet-zoom-hide');
  2767. L.DomUtil.addClass(panes.shadowPane, 'leaflet-zoom-hide');
  2768. }
  2769. },
  2770. // private methods that modify map state
  2771. // @section Map state change events
  2772. _resetView: function (center, zoom) {
  2773. L.DomUtil.setPosition(this._mapPane, new L.Point(0, 0));
  2774. var loading = !this._loaded;
  2775. this._loaded = true;
  2776. zoom = this._limitZoom(zoom);
  2777. this.fire('viewprereset');
  2778. var zoomChanged = this._zoom !== zoom;
  2779. this
  2780. ._moveStart(zoomChanged)
  2781. ._move(center, zoom)
  2782. ._moveEnd(zoomChanged);
  2783. // @event viewreset: Event
  2784. // Fired when the map needs to redraw its content (this usually happens
  2785. // on map zoom or load). Very useful for creating custom overlays.
  2786. this.fire('viewreset');
  2787. // @event load: Event
  2788. // Fired when the map is initialized (when its center and zoom are set
  2789. // for the first time).
  2790. if (loading) {
  2791. this.fire('load');
  2792. }
  2793. },
  2794. _moveStart: function (zoomChanged) {
  2795. // @event zoomstart: Event
  2796. // Fired when the map zoom is about to change (e.g. before zoom animation).
  2797. // @event movestart: Event
  2798. // Fired when the view of the map starts changing (e.g. user starts dragging the map).
  2799. if (zoomChanged) {
  2800. this.fire('zoomstart');
  2801. }
  2802. return this.fire('movestart');
  2803. },
  2804. _move: function (center, zoom, data) {
  2805. if (zoom === undefined) {
  2806. zoom = this._zoom;
  2807. }
  2808. var zoomChanged = this._zoom !== zoom;
  2809. this._zoom = zoom;
  2810. this._lastCenter = center;
  2811. this._pixelOrigin = this._getNewPixelOrigin(center);
  2812. // @event zoom: Event
  2813. // Fired repeatedly during any change in zoom level, including zoom
  2814. // and fly animations.
  2815. if (zoomChanged || (data && data.pinch)) { // Always fire 'zoom' if pinching because #3530
  2816. this.fire('zoom', data);
  2817. }
  2818. // @event move: Event
  2819. // Fired repeatedly during any movement of the map, including pan and
  2820. // fly animations.
  2821. return this.fire('move', data);
  2822. },
  2823. _moveEnd: function (zoomChanged) {
  2824. // @event zoomend: Event
  2825. // Fired when the map has changed, after any animations.
  2826. if (zoomChanged) {
  2827. this.fire('zoomend');
  2828. }
  2829. // @event moveend: Event
  2830. // Fired when the center of the map stops changing (e.g. user stopped
  2831. // dragging the map).
  2832. return this.fire('moveend');
  2833. },
  2834. _stop: function () {
  2835. L.Util.cancelAnimFrame(this._flyToFrame);
  2836. if (this._panAnim) {
  2837. this._panAnim.stop();
  2838. }
  2839. return this;
  2840. },
  2841. _rawPanBy: function (offset) {
  2842. L.DomUtil.setPosition(this._mapPane, this._getMapPanePos().subtract(offset));
  2843. },
  2844. _getZoomSpan: function () {
  2845. return this.getMaxZoom() - this.getMinZoom();
  2846. },
  2847. _panInsideMaxBounds: function () {
  2848. if (!this._enforcingBounds) {
  2849. this.panInsideBounds(this.options.maxBounds);
  2850. }
  2851. },
  2852. _checkIfLoaded: function () {
  2853. if (!this._loaded) {
  2854. throw new Error('Set map center and zoom first.');
  2855. }
  2856. },
  2857. // DOM event handling
  2858. // @section Interaction events
  2859. _initEvents: function (remove) {
  2860. if (!L.DomEvent) { return; }
  2861. this._targets = {};
  2862. this._targets[L.stamp(this._container)] = this;
  2863. var onOff = remove ? 'off' : 'on';
  2864. // @event click: MouseEvent
  2865. // Fired when the user clicks (or taps) the map.
  2866. // @event dblclick: MouseEvent
  2867. // Fired when the user double-clicks (or double-taps) the map.
  2868. // @event mousedown: MouseEvent
  2869. // Fired when the user pushes the mouse button on the map.
  2870. // @event mouseup: MouseEvent
  2871. // Fired when the user releases the mouse button on the map.
  2872. // @event mouseover: MouseEvent
  2873. // Fired when the mouse enters the map.
  2874. // @event mouseout: MouseEvent
  2875. // Fired when the mouse leaves the map.
  2876. // @event mousemove: MouseEvent
  2877. // Fired while the mouse moves over the map.
  2878. // @event contextmenu: MouseEvent
  2879. // Fired when the user pushes the right mouse button on the map, prevents
  2880. // default browser context menu from showing if there are listeners on
  2881. // this event. Also fired on mobile when the user holds a single touch
  2882. // for a second (also called long press).
  2883. // @event keypress: KeyboardEvent
  2884. // Fired when the user presses a key from the keyboard while the map is focused.
  2885. L.DomEvent[onOff](this._container, 'click dblclick mousedown mouseup ' +
  2886. 'mouseover mouseout mousemove contextmenu keypress', this._handleDOMEvent, this);
  2887. if (this.options.trackResize) {
  2888. L.DomEvent[onOff](window, 'resize', this._onResize, this);
  2889. }
  2890. if (L.Browser.any3d && this.options.transform3DLimit) {
  2891. this[onOff]('moveend', this._onMoveEnd);
  2892. }
  2893. },
  2894. _onResize: function () {
  2895. L.Util.cancelAnimFrame(this._resizeRequest);
  2896. this._resizeRequest = L.Util.requestAnimFrame(
  2897. function () { this.invalidateSize({debounceMoveend: true}); }, this);
  2898. },
  2899. _onScroll: function () {
  2900. this._container.scrollTop = 0;
  2901. this._container.scrollLeft = 0;
  2902. },
  2903. _onMoveEnd: function () {
  2904. var pos = this._getMapPanePos();
  2905. if (Math.max(Math.abs(pos.x), Math.abs(pos.y)) >= this.options.transform3DLimit) {
  2906. // https://bugzilla.mozilla.org/show_bug.cgi?id=1203873 but Webkit also have
  2907. // a pixel offset on very high values, see: http://jsfiddle.net/dg6r5hhb/
  2908. this._resetView(this.getCenter(), this.getZoom());
  2909. }
  2910. },
  2911. _findEventTargets: function (e, type) {
  2912. var targets = [],
  2913. target,
  2914. isHover = type === 'mouseout' || type === 'mouseover',
  2915. src = e.target || e.srcElement,
  2916. dragging = false;
  2917. while (src) {
  2918. target = this._targets[L.stamp(src)];
  2919. if (target && (type === 'click' || type === 'preclick') && !e._simulated && this._draggableMoved(target)) {
  2920. // Prevent firing click after you just dragged an object.
  2921. dragging = true;
  2922. break;
  2923. }
  2924. if (target && target.listens(type, true)) {
  2925. if (isHover && !L.DomEvent._isExternalTarget(src, e)) { break; }
  2926. targets.push(target);
  2927. if (isHover) { break; }
  2928. }
  2929. if (src === this._container) { break; }
  2930. src = src.parentNode;
  2931. }
  2932. if (!targets.length && !dragging && !isHover && L.DomEvent._isExternalTarget(src, e)) {
  2933. targets = [this];
  2934. }
  2935. return targets;
  2936. },
  2937. _handleDOMEvent: function (e) {
  2938. if (!this._loaded || L.DomEvent._skipped(e)) { return; }
  2939. var type = e.type === 'keypress' && e.keyCode === 13 ? 'click' : e.type;
  2940. if (type === 'mousedown') {
  2941. // prevents outline when clicking on keyboard-focusable element
  2942. L.DomUtil.preventOutline(e.target || e.srcElement);
  2943. }
  2944. this._fireDOMEvent(e, type);
  2945. },
  2946. _fireDOMEvent: function (e, type, targets) {
  2947. if (e.type === 'click') {
  2948. // Fire a synthetic 'preclick' event which propagates up (mainly for closing popups).
  2949. // @event preclick: MouseEvent
  2950. // Fired before mouse click on the map (sometimes useful when you
  2951. // want something to happen on click before any existing click
  2952. // handlers start running).
  2953. var synth = L.Util.extend({}, e);
  2954. synth.type = 'preclick';
  2955. this._fireDOMEvent(synth, synth.type, targets);
  2956. }
  2957. if (e._stopped) { return; }
  2958. // Find the layer the event is propagating from and its parents.
  2959. targets = (targets || []).concat(this._findEventTargets(e, type));
  2960. if (!targets.length) { return; }
  2961. var target = targets[0];
  2962. if (type === 'contextmenu' && target.listens(type, true)) {
  2963. L.DomEvent.preventDefault(e);
  2964. }
  2965. var data = {
  2966. originalEvent: e
  2967. };
  2968. if (e.type !== 'keypress') {
  2969. var isMarker = target instanceof L.Marker;
  2970. data.containerPoint = isMarker ?
  2971. this.latLngToContainerPoint(target.getLatLng()) : this.mouseEventToContainerPoint(e);
  2972. data.layerPoint = this.containerPointToLayerPoint(data.containerPoint);
  2973. data.latlng = isMarker ? target.getLatLng() : this.layerPointToLatLng(data.layerPoint);
  2974. }
  2975. for (var i = 0; i < targets.length; i++) {
  2976. targets[i].fire(type, data, true);
  2977. if (data.originalEvent._stopped ||
  2978. (targets[i].options.nonBubblingEvents && L.Util.indexOf(targets[i].options.nonBubblingEvents, type) !== -1)) { return; }
  2979. }
  2980. },
  2981. _draggableMoved: function (obj) {
  2982. obj = obj.dragging && obj.dragging.enabled() ? obj : this;
  2983. return (obj.dragging && obj.dragging.moved()) || (this.boxZoom && this.boxZoom.moved());
  2984. },
  2985. _clearHandlers: function () {
  2986. for (var i = 0, len = this._handlers.length; i < len; i++) {
  2987. this._handlers[i].disable();
  2988. }
  2989. },
  2990. // @section Other Methods
  2991. // @method whenReady(fn: Function, context?: Object): this
  2992. // Runs the given function `fn` when the map gets initialized with
  2993. // a view (center and zoom) and at least one layer, or immediately
  2994. // if it's already initialized, optionally passing a function context.
  2995. whenReady: function (callback, context) {
  2996. if (this._loaded) {
  2997. callback.call(context || this, {target: this});
  2998. } else {
  2999. this.on('load', callback, context);
  3000. }
  3001. return this;
  3002. },
  3003. // private methods for getting map state
  3004. _getMapPanePos: function () {
  3005. return L.DomUtil.getPosition(this._mapPane) || new L.Point(0, 0);
  3006. },
  3007. _moved: function () {
  3008. var pos = this._getMapPanePos();
  3009. return pos && !pos.equals([0, 0]);
  3010. },
  3011. _getTopLeftPoint: function (center, zoom) {
  3012. var pixelOrigin = center && zoom !== undefined ?
  3013. this._getNewPixelOrigin(center, zoom) :
  3014. this.getPixelOrigin();
  3015. return pixelOrigin.subtract(this._getMapPanePos());
  3016. },
  3017. _getNewPixelOrigin: function (center, zoom) {
  3018. var viewHalf = this.getSize()._divideBy(2);
  3019. return this.project(center, zoom)._subtract(viewHalf)._add(this._getMapPanePos())._round();
  3020. },
  3021. _latLngToNewLayerPoint: function (latlng, zoom, center) {
  3022. var topLeft = this._getNewPixelOrigin(center, zoom);
  3023. return this.project(latlng, zoom)._subtract(topLeft);
  3024. },
  3025. _latLngBoundsToNewLayerBounds: function (latLngBounds, zoom, center) {
  3026. var topLeft = this._getNewPixelOrigin(center, zoom);
  3027. return L.bounds([
  3028. this.project(latLngBounds.getSouthWest(), zoom)._subtract(topLeft),
  3029. this.project(latLngBounds.getNorthWest(), zoom)._subtract(topLeft),
  3030. this.project(latLngBounds.getSouthEast(), zoom)._subtract(topLeft),
  3031. this.project(latLngBounds.getNorthEast(), zoom)._subtract(topLeft)
  3032. ]);
  3033. },
  3034. // layer point of the current center
  3035. _getCenterLayerPoint: function () {
  3036. return this.containerPointToLayerPoint(this.getSize()._divideBy(2));
  3037. },
  3038. // offset of the specified place to the current center in pixels
  3039. _getCenterOffset: function (latlng) {
  3040. return this.latLngToLayerPoint(latlng).subtract(this._getCenterLayerPoint());
  3041. },
  3042. // adjust center for view to get inside bounds
  3043. _limitCenter: function (center, zoom, bounds) {
  3044. if (!bounds) { return center; }
  3045. var centerPoint = this.project(center, zoom),
  3046. viewHalf = this.getSize().divideBy(2),
  3047. viewBounds = new L.Bounds(centerPoint.subtract(viewHalf), centerPoint.add(viewHalf)),
  3048. offset = this._getBoundsOffset(viewBounds, bounds, zoom);
  3049. // If offset is less than a pixel, ignore.
  3050. // This prevents unstable projections from getting into
  3051. // an infinite loop of tiny offsets.
  3052. if (offset.round().equals([0, 0])) {
  3053. return center;
  3054. }
  3055. return this.unproject(centerPoint.add(offset), zoom);
  3056. },
  3057. // adjust offset for view to get inside bounds
  3058. _limitOffset: function (offset, bounds) {
  3059. if (!bounds) { return offset; }
  3060. var viewBounds = this.getPixelBounds(),
  3061. newBounds = new L.Bounds(viewBounds.min.add(offset), viewBounds.max.add(offset));
  3062. return offset.add(this._getBoundsOffset(newBounds, bounds));
  3063. },
  3064. // returns offset needed for pxBounds to get inside maxBounds at a specified zoom
  3065. _getBoundsOffset: function (pxBounds, maxBounds, zoom) {
  3066. var projectedMaxBounds = L.bounds(
  3067. this.project(maxBounds.getNorthEast(), zoom),
  3068. this.project(maxBounds.getSouthWest(), zoom)
  3069. ),
  3070. minOffset = projectedMaxBounds.min.subtract(pxBounds.min),
  3071. maxOffset = projectedMaxBounds.max.subtract(pxBounds.max),
  3072. dx = this._rebound(minOffset.x, -maxOffset.x),
  3073. dy = this._rebound(minOffset.y, -maxOffset.y);
  3074. return new L.Point(dx, dy);
  3075. },
  3076. _rebound: function (left, right) {
  3077. return left + right > 0 ?
  3078. Math.round(left - right) / 2 :
  3079. Math.max(0, Math.ceil(left)) - Math.max(0, Math.floor(right));
  3080. },
  3081. _limitZoom: function (zoom) {
  3082. var min = this.getMinZoom(),
  3083. max = this.getMaxZoom(),
  3084. snap = L.Browser.any3d ? this.options.zoomSnap : 1;
  3085. if (snap) {
  3086. zoom = Math.round(zoom / snap) * snap;
  3087. }
  3088. return Math.max(min, Math.min(max, zoom));
  3089. },
  3090. _onPanTransitionStep: function () {
  3091. this.fire('move');
  3092. },
  3093. _onPanTransitionEnd: function () {
  3094. L.DomUtil.removeClass(this._mapPane, 'leaflet-pan-anim');
  3095. this.fire('moveend');
  3096. },
  3097. _tryAnimatedPan: function (center, options) {
  3098. // difference between the new and current centers in pixels
  3099. var offset = this._getCenterOffset(center)._floor();
  3100. // don't animate too far unless animate: true specified in options
  3101. if ((options && options.animate) !== true && !this.getSize().contains(offset)) { return false; }
  3102. this.panBy(offset, options);
  3103. return true;
  3104. },
  3105. _createAnimProxy: function () {
  3106. var proxy = this._proxy = L.DomUtil.create('div', 'leaflet-proxy leaflet-zoom-animated');
  3107. this._panes.mapPane.appendChild(proxy);
  3108. this.on('zoomanim', function (e) {
  3109. var prop = L.DomUtil.TRANSFORM,
  3110. transform = proxy.style[prop];
  3111. L.DomUtil.setTransform(proxy, this.project(e.center, e.zoom), this.getZoomScale(e.zoom, 1));
  3112. // workaround for case when transform is the same and so transitionend event is not fired
  3113. if (transform === proxy.style[prop] && this._animatingZoom) {
  3114. this._onZoomTransitionEnd();
  3115. }
  3116. }, this);
  3117. this.on('load moveend', function () {
  3118. var c = this.getCenter(),
  3119. z = this.getZoom();
  3120. L.DomUtil.setTransform(proxy, this.project(c, z), this.getZoomScale(z, 1));
  3121. }, this);
  3122. },
  3123. _catchTransitionEnd: function (e) {
  3124. if (this._animatingZoom && e.propertyName.indexOf('transform') >= 0) {
  3125. this._onZoomTransitionEnd();
  3126. }
  3127. },
  3128. _nothingToAnimate: function () {
  3129. return !this._container.getElementsByClassName('leaflet-zoom-animated').length;
  3130. },
  3131. _tryAnimatedZoom: function (center, zoom, options) {
  3132. if (this._animatingZoom) { return true; }
  3133. options = options || {};
  3134. // don't animate if disabled, not supported or zoom difference is too large
  3135. if (!this._zoomAnimated || options.animate === false || this._nothingToAnimate() ||
  3136. Math.abs(zoom - this._zoom) > this.options.zoomAnimationThreshold) { return false; }
  3137. // offset is the pixel coords of the zoom origin relative to the current center
  3138. var scale = this.getZoomScale(zoom),
  3139. offset = this._getCenterOffset(center)._divideBy(1 - 1 / scale);
  3140. // don't animate if the zoom origin isn't within one screen from the current center, unless forced
  3141. if (options.animate !== true && !this.getSize().contains(offset)) { return false; }
  3142. L.Util.requestAnimFrame(function () {
  3143. this
  3144. ._moveStart(true)
  3145. ._animateZoom(center, zoom, true);
  3146. }, this);
  3147. return true;
  3148. },
  3149. _animateZoom: function (center, zoom, startAnim, noUpdate) {
  3150. if (startAnim) {
  3151. this._animatingZoom = true;
  3152. // remember what center/zoom to set after animation
  3153. this._animateToCenter = center;
  3154. this._animateToZoom = zoom;
  3155. L.DomUtil.addClass(this._mapPane, 'leaflet-zoom-anim');
  3156. }
  3157. // @event zoomanim: ZoomAnimEvent
  3158. // Fired on every frame of a zoom animation
  3159. this.fire('zoomanim', {
  3160. center: center,
  3161. zoom: zoom,
  3162. noUpdate: noUpdate
  3163. });
  3164. // Work around webkit not firing 'transitionend', see https://github.com/Leaflet/Leaflet/issues/3689, 2693
  3165. setTimeout(L.bind(this._onZoomTransitionEnd, this), 250);
  3166. },
  3167. _onZoomTransitionEnd: function () {
  3168. if (!this._animatingZoom) { return; }
  3169. L.DomUtil.removeClass(this._mapPane, 'leaflet-zoom-anim');
  3170. this._animatingZoom = false;
  3171. this._move(this._animateToCenter, this._animateToZoom);
  3172. // This anim frame should prevent an obscure iOS webkit tile loading race condition.
  3173. L.Util.requestAnimFrame(function () {
  3174. this._moveEnd(true);
  3175. }, this);
  3176. }
  3177. });
  3178. // @section
  3179. // @factory L.map(id: String, options?: Map options)
  3180. // Instantiates a map object given the DOM ID of a `<div>` element
  3181. // and optionally an object literal with `Map options`.
  3182. //
  3183. // @alternative
  3184. // @factory L.map(el: HTMLElement, options?: Map options)
  3185. // Instantiates a map object given an instance of a `<div>` HTML element
  3186. // and optionally an object literal with `Map options`.
  3187. L.map = function (id, options) {
  3188. return new L.Map(id, options);
  3189. };
  3190. /*
  3191. * @class Layer
  3192. * @inherits Evented
  3193. * @aka L.Layer
  3194. * @aka ILayer
  3195. *
  3196. * A set of methods from the Layer base class that all Leaflet layers use.
  3197. * Inherits all methods, options and events from `L.Evented`.
  3198. *
  3199. * @example
  3200. *
  3201. * ```js
  3202. * var layer = L.Marker(latlng).addTo(map);
  3203. * layer.addTo(map);
  3204. * layer.remove();
  3205. * ```
  3206. *
  3207. * @event add: Event
  3208. * Fired after the layer is added to a map
  3209. *
  3210. * @event remove: Event
  3211. * Fired after the layer is removed from a map
  3212. */
  3213. L.Layer = L.Evented.extend({
  3214. // Classes extending `L.Layer` will inherit the following options:
  3215. options: {
  3216. // @option pane: String = 'overlayPane'
  3217. // By default the layer will be added to the map's [overlay pane](#map-overlaypane). Overriding this option will cause the layer to be placed on another pane by default.
  3218. pane: 'overlayPane',
  3219. nonBubblingEvents: [], // Array of events that should not be bubbled to DOM parents (like the map),
  3220. // @option attribution: String = null
  3221. // String to be shown in the attribution control, describes the layer data, e.g. "© Mapbox".
  3222. attribution: null,
  3223. },
  3224. /* @section
  3225. * Classes extending `L.Layer` will inherit the following methods:
  3226. *
  3227. * @method addTo(map: Map): this
  3228. * Adds the layer to the given map
  3229. */
  3230. addTo: function (map) {
  3231. map.addLayer(this);
  3232. return this;
  3233. },
  3234. // @method remove: this
  3235. // Removes the layer from the map it is currently active on.
  3236. remove: function () {
  3237. return this.removeFrom(this._map || this._mapToAdd);
  3238. },
  3239. // @method removeFrom(map: Map): this
  3240. // Removes the layer from the given map
  3241. removeFrom: function (obj) {
  3242. if (obj) {
  3243. obj.removeLayer(this);
  3244. }
  3245. return this;
  3246. },
  3247. // @method getPane(name? : String): HTMLElement
  3248. // Returns the `HTMLElement` representing the named pane on the map. If `name` is omitted, returns the pane for this layer.
  3249. getPane: function (name) {
  3250. return this._map.getPane(name ? (this.options[name] || name) : this.options.pane);
  3251. },
  3252. addInteractiveTarget: function (targetEl) {
  3253. this._map._targets[L.stamp(targetEl)] = this;
  3254. return this;
  3255. },
  3256. removeInteractiveTarget: function (targetEl) {
  3257. delete this._map._targets[L.stamp(targetEl)];
  3258. return this;
  3259. },
  3260. // @method getAttribution: String
  3261. // Used by the `attribution control`, returns the [attribution option](#gridlayer-attribution).
  3262. getAttribution: function () {
  3263. return this.options.attribution;
  3264. },
  3265. _layerAdd: function (e) {
  3266. var map = e.target;
  3267. // check in case layer gets added and then removed before the map is ready
  3268. if (!map.hasLayer(this)) { return; }
  3269. this._map = map;
  3270. this._zoomAnimated = map._zoomAnimated;
  3271. if (this.getEvents) {
  3272. var events = this.getEvents();
  3273. map.on(events, this);
  3274. this.once('remove', function () {
  3275. map.off(events, this);
  3276. }, this);
  3277. }
  3278. this.onAdd(map);
  3279. if (this.getAttribution && this._map.attributionControl) {
  3280. this._map.attributionControl.addAttribution(this.getAttribution());
  3281. }
  3282. this.fire('add');
  3283. map.fire('layeradd', {layer: this});
  3284. }
  3285. });
  3286. /* @section Extension methods
  3287. * @uninheritable
  3288. *
  3289. * Every layer should extend from `L.Layer` and (re-)implement the following methods.
  3290. *
  3291. * @method onAdd(map: Map): this
  3292. * Should contain code that creates DOM elements for the layer, adds them to `map panes` where they should belong and puts listeners on relevant map events. Called on [`map.addLayer(layer)`](#map-addlayer).
  3293. *
  3294. * @method onRemove(map: Map): this
  3295. * Should contain all clean up code that removes the layer's elements from the DOM and removes listeners previously added in [`onAdd`](#layer-onadd). Called on [`map.removeLayer(layer)`](#map-removelayer).
  3296. *
  3297. * @method getEvents(): Object
  3298. * This optional method should return an object like `{ viewreset: this._reset }` for [`addEventListener`](#evented-addeventlistener). The event handlers in this object will be automatically added and removed from the map with your layer.
  3299. *
  3300. * @method getAttribution(): String
  3301. * This optional method should return a string containing HTML to be shown on the `Attribution control` whenever the layer is visible.
  3302. *
  3303. * @method beforeAdd(map: Map): this
  3304. * Optional method. Called on [`map.addLayer(layer)`](#map-addlayer), before the layer is added to the map, before events are initialized, without waiting until the map is in a usable state. Use for early initialization only.
  3305. */
  3306. /* @namespace Map
  3307. * @section Layer events
  3308. *
  3309. * @event layeradd: LayerEvent
  3310. * Fired when a new layer is added to the map.
  3311. *
  3312. * @event layerremove: LayerEvent
  3313. * Fired when some layer is removed from the map
  3314. *
  3315. * @section Methods for Layers and Controls
  3316. */
  3317. L.Map.include({
  3318. // @method addLayer(layer: Layer): this
  3319. // Adds the given layer to the map
  3320. addLayer: function (layer) {
  3321. var id = L.stamp(layer);
  3322. if (this._layers[id]) { return this; }
  3323. this._layers[id] = layer;
  3324. layer._mapToAdd = this;
  3325. if (layer.beforeAdd) {
  3326. layer.beforeAdd(this);
  3327. }
  3328. this.whenReady(layer._layerAdd, layer);
  3329. return this;
  3330. },
  3331. // @method removeLayer(layer: Layer): this
  3332. // Removes the given layer from the map.
  3333. removeLayer: function (layer) {
  3334. var id = L.stamp(layer);
  3335. if (!this._layers[id]) { return this; }
  3336. if (this._loaded) {
  3337. layer.onRemove(this);
  3338. }
  3339. if (layer.getAttribution && this.attributionControl) {
  3340. this.attributionControl.removeAttribution(layer.getAttribution());
  3341. }
  3342. delete this._layers[id];
  3343. if (this._loaded) {
  3344. this.fire('layerremove', {layer: layer});
  3345. layer.fire('remove');
  3346. }
  3347. layer._map = layer._mapToAdd = null;
  3348. return this;
  3349. },
  3350. // @method hasLayer(layer: Layer): Boolean
  3351. // Returns `true` if the given layer is currently added to the map
  3352. hasLayer: function (layer) {
  3353. return !!layer && (L.stamp(layer) in this._layers);
  3354. },
  3355. /* @method eachLayer(fn: Function, context?: Object): this
  3356. * Iterates over the layers of the map, optionally specifying context of the iterator function.
  3357. * ```
  3358. * map.eachLayer(function(layer){
  3359. * layer.bindPopup('Hello');
  3360. * });
  3361. * ```
  3362. */
  3363. eachLayer: function (method, context) {
  3364. for (var i in this._layers) {
  3365. method.call(context, this._layers[i]);
  3366. }
  3367. return this;
  3368. },
  3369. _addLayers: function (layers) {
  3370. layers = layers ? (L.Util.isArray(layers) ? layers : [layers]) : [];
  3371. for (var i = 0, len = layers.length; i < len; i++) {
  3372. this.addLayer(layers[i]);
  3373. }
  3374. },
  3375. _addZoomLimit: function (layer) {
  3376. if (isNaN(layer.options.maxZoom) || !isNaN(layer.options.minZoom)) {
  3377. this._zoomBoundLayers[L.stamp(layer)] = layer;
  3378. this._updateZoomLevels();
  3379. }
  3380. },
  3381. _removeZoomLimit: function (layer) {
  3382. var id = L.stamp(layer);
  3383. if (this._zoomBoundLayers[id]) {
  3384. delete this._zoomBoundLayers[id];
  3385. this._updateZoomLevels();
  3386. }
  3387. },
  3388. _updateZoomLevels: function () {
  3389. var minZoom = Infinity,
  3390. maxZoom = -Infinity,
  3391. oldZoomSpan = this._getZoomSpan();
  3392. for (var i in this._zoomBoundLayers) {
  3393. var options = this._zoomBoundLayers[i].options;
  3394. minZoom = options.minZoom === undefined ? minZoom : Math.min(minZoom, options.minZoom);
  3395. maxZoom = options.maxZoom === undefined ? maxZoom : Math.max(maxZoom, options.maxZoom);
  3396. }
  3397. this._layersMaxZoom = maxZoom === -Infinity ? undefined : maxZoom;
  3398. this._layersMinZoom = minZoom === Infinity ? undefined : minZoom;
  3399. // @section Map state change events
  3400. // @event zoomlevelschange: Event
  3401. // Fired when the number of zoomlevels on the map is changed due
  3402. // to adding or removing a layer.
  3403. if (oldZoomSpan !== this._getZoomSpan()) {
  3404. this.fire('zoomlevelschange');
  3405. }
  3406. if (this.options.maxZoom === undefined && this._layersMaxZoom && this.getZoom() > this._layersMaxZoom) {
  3407. this.setZoom(this._layersMaxZoom);
  3408. }
  3409. if (this.options.minZoom === undefined && this._layersMinZoom && this.getZoom() < this._layersMinZoom) {
  3410. this.setZoom(this._layersMinZoom);
  3411. }
  3412. }
  3413. });
  3414. /*
  3415. * @namespace DomEvent
  3416. * Utility functions to work with the [DOM events](https://developer.mozilla.org/docs/Web/API/Event), used by Leaflet internally.
  3417. */
  3418. // Inspired by John Resig, Dean Edwards and YUI addEvent implementations.
  3419. var eventsKey = '_leaflet_events';
  3420. L.DomEvent = {
  3421. // @function on(el: HTMLElement, types: String, fn: Function, context?: Object): this
  3422. // Adds a listener function (`fn`) to a particular DOM event type of the
  3423. // element `el`. You can optionally specify the context of the listener
  3424. // (object the `this` keyword will point to). You can also pass several
  3425. // space-separated types (e.g. `'click dblclick'`).
  3426. // @alternative
  3427. // @function on(el: HTMLElement, eventMap: Object, context?: Object): this
  3428. // Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
  3429. on: function (obj, types, fn, context) {
  3430. if (typeof types === 'object') {
  3431. for (var type in types) {
  3432. this._on(obj, type, types[type], fn);
  3433. }
  3434. } else {
  3435. types = L.Util.splitWords(types);
  3436. for (var i = 0, len = types.length; i < len; i++) {
  3437. this._on(obj, types[i], fn, context);
  3438. }
  3439. }
  3440. return this;
  3441. },
  3442. // @function off(el: HTMLElement, types: String, fn: Function, context?: Object): this
  3443. // Removes a previously added listener function. If no function is specified,
  3444. // it will remove all the listeners of that particular DOM event from the element.
  3445. // Note that if you passed a custom context to on, you must pass the same
  3446. // context to `off` in order to remove the listener.
  3447. // @alternative
  3448. // @function off(el: HTMLElement, eventMap: Object, context?: Object): this
  3449. // Removes a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}`
  3450. off: function (obj, types, fn, context) {
  3451. if (typeof types === 'object') {
  3452. for (var type in types) {
  3453. this._off(obj, type, types[type], fn);
  3454. }
  3455. } else {
  3456. types = L.Util.splitWords(types);
  3457. for (var i = 0, len = types.length; i < len; i++) {
  3458. this._off(obj, types[i], fn, context);
  3459. }
  3460. }
  3461. return this;
  3462. },
  3463. _on: function (obj, type, fn, context) {
  3464. var id = type + L.stamp(fn) + (context ? '_' + L.stamp(context) : '');
  3465. if (obj[eventsKey] && obj[eventsKey][id]) { return this; }
  3466. var handler = function (e) {
  3467. return fn.call(context || obj, e || window.event);
  3468. };
  3469. var originalHandler = handler;
  3470. if (L.Browser.pointer && type.indexOf('touch') === 0) {
  3471. this.addPointerListener(obj, type, handler, id);
  3472. } else if (L.Browser.touch && (type === 'dblclick') && this.addDoubleTapListener) {
  3473. this.addDoubleTapListener(obj, handler, id);
  3474. } else if ('addEventListener' in obj) {
  3475. if (type === 'mousewheel') {
  3476. obj.addEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);
  3477. } else if ((type === 'mouseenter') || (type === 'mouseleave')) {
  3478. handler = function (e) {
  3479. e = e || window.event;
  3480. if (L.DomEvent._isExternalTarget(obj, e)) {
  3481. originalHandler(e);
  3482. }
  3483. };
  3484. obj.addEventListener(type === 'mouseenter' ? 'mouseover' : 'mouseout', handler, false);
  3485. } else {
  3486. if (type === 'click' && L.Browser.android) {
  3487. handler = function (e) {
  3488. return L.DomEvent._filterClick(e, originalHandler);
  3489. };
  3490. }
  3491. obj.addEventListener(type, handler, false);
  3492. }
  3493. } else if ('attachEvent' in obj) {
  3494. obj.attachEvent('on' + type, handler);
  3495. }
  3496. obj[eventsKey] = obj[eventsKey] || {};
  3497. obj[eventsKey][id] = handler;
  3498. return this;
  3499. },
  3500. _off: function (obj, type, fn, context) {
  3501. var id = type + L.stamp(fn) + (context ? '_' + L.stamp(context) : ''),
  3502. handler = obj[eventsKey] && obj[eventsKey][id];
  3503. if (!handler) { return this; }
  3504. if (L.Browser.pointer && type.indexOf('touch') === 0) {
  3505. this.removePointerListener(obj, type, id);
  3506. } else if (L.Browser.touch && (type === 'dblclick') && this.removeDoubleTapListener) {
  3507. this.removeDoubleTapListener(obj, id);
  3508. } else if ('removeEventListener' in obj) {
  3509. if (type === 'mousewheel') {
  3510. obj.removeEventListener('onwheel' in obj ? 'wheel' : 'mousewheel', handler, false);
  3511. } else {
  3512. obj.removeEventListener(
  3513. type === 'mouseenter' ? 'mouseover' :
  3514. type === 'mouseleave' ? 'mouseout' : type, handler, false);
  3515. }
  3516. } else if ('detachEvent' in obj) {
  3517. obj.detachEvent('on' + type, handler);
  3518. }
  3519. obj[eventsKey][id] = null;
  3520. return this;
  3521. },
  3522. // @function stopPropagation(ev: DOMEvent): this
  3523. // Stop the given event from propagation to parent elements. Used inside the listener functions:
  3524. // ```js
  3525. // L.DomEvent.on(div, 'click', function (ev) {
  3526. // L.DomEvent.stopPropagation(ev);
  3527. // });
  3528. // ```
  3529. stopPropagation: function (e) {
  3530. if (e.stopPropagation) {
  3531. e.stopPropagation();
  3532. } else if (e.originalEvent) { // In case of Leaflet event.
  3533. e.originalEvent._stopped = true;
  3534. } else {
  3535. e.cancelBubble = true;
  3536. }
  3537. L.DomEvent._skipped(e);
  3538. return this;
  3539. },
  3540. // @function disableScrollPropagation(el: HTMLElement): this
  3541. // Adds `stopPropagation` to the element's `'mousewheel'` events (plus browser variants).
  3542. disableScrollPropagation: function (el) {
  3543. return L.DomEvent.on(el, 'mousewheel', L.DomEvent.stopPropagation);
  3544. },
  3545. // @function disableClickPropagation(el: HTMLElement): this
  3546. // Adds `stopPropagation` to the element's `'click'`, `'doubleclick'`,
  3547. // `'mousedown'` and `'touchstart'` events (plus browser variants).
  3548. disableClickPropagation: function (el) {
  3549. var stop = L.DomEvent.stopPropagation;
  3550. L.DomEvent.on(el, L.Draggable.START.join(' '), stop);
  3551. return L.DomEvent.on(el, {
  3552. click: L.DomEvent._fakeStop,
  3553. dblclick: stop
  3554. });
  3555. },
  3556. // @function preventDefault(ev: DOMEvent): this
  3557. // Prevents the default action of the DOM Event `ev` from happening (such as
  3558. // following a link in the href of the a element, or doing a POST request
  3559. // with page reload when a `<form>` is submitted).
  3560. // Use it inside listener functions.
  3561. preventDefault: function (e) {
  3562. if (e.preventDefault) {
  3563. e.preventDefault();
  3564. } else {
  3565. e.returnValue = false;
  3566. }
  3567. return this;
  3568. },
  3569. // @function stop(ev): this
  3570. // Does `stopPropagation` and `preventDefault` at the same time.
  3571. stop: function (e) {
  3572. return L.DomEvent
  3573. .preventDefault(e)
  3574. .stopPropagation(e);
  3575. },
  3576. // @function getMousePosition(ev: DOMEvent, container?: HTMLElement): Point
  3577. // Gets normalized mouse position from a DOM event relative to the
  3578. // `container` or to the whole page if not specified.
  3579. getMousePosition: function (e, container) {
  3580. if (!container) {
  3581. return new L.Point(e.clientX, e.clientY);
  3582. }
  3583. var rect = container.getBoundingClientRect();
  3584. return new L.Point(
  3585. e.clientX - rect.left - container.clientLeft,
  3586. e.clientY - rect.top - container.clientTop);
  3587. },
  3588. // Chrome on Win scrolls double the pixels as in other platforms (see #4538),
  3589. // and Firefox scrolls device pixels, not CSS pixels
  3590. _wheelPxFactor: (L.Browser.win && L.Browser.chrome) ? 2 :
  3591. L.Browser.gecko ? window.devicePixelRatio :
  3592. 1,
  3593. // @function getWheelDelta(ev: DOMEvent): Number
  3594. // Gets normalized wheel delta from a mousewheel DOM event, in vertical
  3595. // pixels scrolled (negative if scrolling down).
  3596. // Events from pointing devices without precise scrolling are mapped to
  3597. // a best guess of 60 pixels.
  3598. getWheelDelta: function (e) {
  3599. return (L.Browser.edge) ? e.wheelDeltaY / 2 : // Don't trust window-geometry-based delta
  3600. (e.deltaY && e.deltaMode === 0) ? -e.deltaY / L.DomEvent._wheelPxFactor : // Pixels
  3601. (e.deltaY && e.deltaMode === 1) ? -e.deltaY * 20 : // Lines
  3602. (e.deltaY && e.deltaMode === 2) ? -e.deltaY * 60 : // Pages
  3603. (e.deltaX || e.deltaZ) ? 0 : // Skip horizontal/depth wheel events
  3604. e.wheelDelta ? (e.wheelDeltaY || e.wheelDelta) / 2 : // Legacy IE pixels
  3605. (e.detail && Math.abs(e.detail) < 32765) ? -e.detail * 20 : // Legacy Moz lines
  3606. e.detail ? e.detail / -32765 * 60 : // Legacy Moz pages
  3607. 0;
  3608. },
  3609. _skipEvents: {},
  3610. _fakeStop: function (e) {
  3611. // fakes stopPropagation by setting a special event flag, checked/reset with L.DomEvent._skipped(e)
  3612. L.DomEvent._skipEvents[e.type] = true;
  3613. },
  3614. _skipped: function (e) {
  3615. var skipped = this._skipEvents[e.type];
  3616. // reset when checking, as it's only used in map container and propagates outside of the map
  3617. this._skipEvents[e.type] = false;
  3618. return skipped;
  3619. },
  3620. // check if element really left/entered the event target (for mouseenter/mouseleave)
  3621. _isExternalTarget: function (el, e) {
  3622. var related = e.relatedTarget;
  3623. if (!related) { return true; }
  3624. try {
  3625. while (related && (related !== el)) {
  3626. related = related.parentNode;
  3627. }
  3628. } catch (err) {
  3629. return false;
  3630. }
  3631. return (related !== el);
  3632. },
  3633. // this is a horrible workaround for a bug in Android where a single touch triggers two click events
  3634. _filterClick: function (e, handler) {
  3635. var timeStamp = (e.timeStamp || (e.originalEvent && e.originalEvent.timeStamp)),
  3636. elapsed = L.DomEvent._lastClick && (timeStamp - L.DomEvent._lastClick);
  3637. // are they closer together than 500ms yet more than 100ms?
  3638. // Android typically triggers them ~300ms apart while multiple listeners
  3639. // on the same event should be triggered far faster;
  3640. // or check if click is simulated on the element, and if it is, reject any non-simulated events
  3641. if ((elapsed && elapsed > 100 && elapsed < 500) || (e.target._simulatedClick && !e._simulated)) {
  3642. L.DomEvent.stop(e);
  3643. return;
  3644. }
  3645. L.DomEvent._lastClick = timeStamp;
  3646. handler(e);
  3647. }
  3648. };
  3649. // @function addListener(…): this
  3650. // Alias to [`L.DomEvent.on`](#domevent-on)
  3651. L.DomEvent.addListener = L.DomEvent.on;
  3652. // @function removeListener(…): this
  3653. // Alias to [`L.DomEvent.off`](#domevent-off)
  3654. L.DomEvent.removeListener = L.DomEvent.off;
  3655. /*
  3656. * @class PosAnimation
  3657. * @aka L.PosAnimation
  3658. * @inherits Evented
  3659. * Used internally for panning animations, utilizing CSS3 Transitions for modern browsers and a timer fallback for IE6-9.
  3660. *
  3661. * @example
  3662. * ```js
  3663. * var fx = new L.PosAnimation();
  3664. * fx.run(el, [300, 500], 0.5);
  3665. * ```
  3666. *
  3667. * @constructor L.PosAnimation()
  3668. * Creates a `PosAnimation` object.
  3669. *
  3670. */
  3671. L.PosAnimation = L.Evented.extend({
  3672. // @method run(el: HTMLElement, newPos: Point, duration?: Number, easeLinearity?: Number)
  3673. // Run an animation of a given element to a new position, optionally setting
  3674. // duration in seconds (`0.25` by default) and easing linearity factor (3rd
  3675. // argument of the [cubic bezier curve](http://cubic-bezier.com/#0,0,.5,1),
  3676. // `0.5` by default).
  3677. run: function (el, newPos, duration, easeLinearity) {
  3678. this.stop();
  3679. this._el = el;
  3680. this._inProgress = true;
  3681. this._duration = duration || 0.25;
  3682. this._easeOutPower = 1 / Math.max(easeLinearity || 0.5, 0.2);
  3683. this._startPos = L.DomUtil.getPosition(el);
  3684. this._offset = newPos.subtract(this._startPos);
  3685. this._startTime = +new Date();
  3686. // @event start: Event
  3687. // Fired when the animation starts
  3688. this.fire('start');
  3689. this._animate();
  3690. },
  3691. // @method stop()
  3692. // Stops the animation (if currently running).
  3693. stop: function () {
  3694. if (!this._inProgress) { return; }
  3695. this._step(true);
  3696. this._complete();
  3697. },
  3698. _animate: function () {
  3699. // animation loop
  3700. this._animId = L.Util.requestAnimFrame(this._animate, this);
  3701. this._step();
  3702. },
  3703. _step: function (round) {
  3704. var elapsed = (+new Date()) - this._startTime,
  3705. duration = this._duration * 1000;
  3706. if (elapsed < duration) {
  3707. this._runFrame(this._easeOut(elapsed / duration), round);
  3708. } else {
  3709. this._runFrame(1);
  3710. this._complete();
  3711. }
  3712. },
  3713. _runFrame: function (progress, round) {
  3714. var pos = this._startPos.add(this._offset.multiplyBy(progress));
  3715. if (round) {
  3716. pos._round();
  3717. }
  3718. L.DomUtil.setPosition(this._el, pos);
  3719. // @event step: Event
  3720. // Fired continuously during the animation.
  3721. this.fire('step');
  3722. },
  3723. _complete: function () {
  3724. L.Util.cancelAnimFrame(this._animId);
  3725. this._inProgress = false;
  3726. // @event end: Event
  3727. // Fired when the animation ends.
  3728. this.fire('end');
  3729. },
  3730. _easeOut: function (t) {
  3731. return 1 - Math.pow(1 - t, this._easeOutPower);
  3732. }
  3733. });
  3734. /*
  3735. * @namespace Projection
  3736. * @projection L.Projection.Mercator
  3737. *
  3738. * Elliptical Mercator projection — more complex than Spherical Mercator. Takes into account that Earth is a geoid, not a perfect sphere. Used by the EPSG:3395 CRS.
  3739. */
  3740. L.Projection.Mercator = {
  3741. R: 6378137,
  3742. R_MINOR: 6356752.314245179,
  3743. bounds: L.bounds([-20037508.34279, -15496570.73972], [20037508.34279, 18764656.23138]),
  3744. project: function (latlng) {
  3745. var d = Math.PI / 180,
  3746. r = this.R,
  3747. y = latlng.lat * d,
  3748. tmp = this.R_MINOR / r,
  3749. e = Math.sqrt(1 - tmp * tmp),
  3750. con = e * Math.sin(y);
  3751. var ts = Math.tan(Math.PI / 4 - y / 2) / Math.pow((1 - con) / (1 + con), e / 2);
  3752. y = -r * Math.log(Math.max(ts, 1E-10));
  3753. return new L.Point(latlng.lng * d * r, y);
  3754. },
  3755. unproject: function (point) {
  3756. var d = 180 / Math.PI,
  3757. r = this.R,
  3758. tmp = this.R_MINOR / r,
  3759. e = Math.sqrt(1 - tmp * tmp),
  3760. ts = Math.exp(-point.y / r),
  3761. phi = Math.PI / 2 - 2 * Math.atan(ts);
  3762. for (var i = 0, dphi = 0.1, con; i < 15 && Math.abs(dphi) > 1e-7; i++) {
  3763. con = e * Math.sin(phi);
  3764. con = Math.pow((1 - con) / (1 + con), e / 2);
  3765. dphi = Math.PI / 2 - 2 * Math.atan(ts * con) - phi;
  3766. phi += dphi;
  3767. }
  3768. return new L.LatLng(phi * d, point.x * d / r);
  3769. }
  3770. };
  3771. /*
  3772. * @namespace CRS
  3773. * @crs L.CRS.EPSG3395
  3774. *
  3775. * Rarely used by some commercial tile providers. Uses Elliptical Mercator projection.
  3776. */
  3777. L.CRS.EPSG3395 = L.extend({}, L.CRS.Earth, {
  3778. code: 'EPSG:3395',
  3779. projection: L.Projection.Mercator,
  3780. transformation: (function () {
  3781. var scale = 0.5 / (Math.PI * L.Projection.Mercator.R);
  3782. return new L.Transformation(scale, 0.5, -scale, 0.5);
  3783. }())
  3784. });
  3785. /*
  3786. * @class GridLayer
  3787. * @inherits Layer
  3788. * @aka L.GridLayer
  3789. *
  3790. * Generic class for handling a tiled grid of HTML elements. This is the base class for all tile layers and replaces `TileLayer.Canvas`.
  3791. * GridLayer can be extended to create a tiled grid of HTML elements like `<canvas>`, `<img>` or `<div>`. GridLayer will handle creating and animating these DOM elements for you.
  3792. *
  3793. *
  3794. * @section Synchronous usage
  3795. * @example
  3796. *
  3797. * To create a custom layer, extend GridLayer and implement the `createTile()` method, which will be passed a `Point` object with the `x`, `y`, and `z` (zoom level) coordinates to draw your tile.
  3798. *
  3799. * ```js
  3800. * var CanvasLayer = L.GridLayer.extend({
  3801. * createTile: function(coords){
  3802. * // create a <canvas> element for drawing
  3803. * var tile = L.DomUtil.create('canvas', 'leaflet-tile');
  3804. *
  3805. * // setup tile width and height according to the options
  3806. * var size = this.getTileSize();
  3807. * tile.width = size.x;
  3808. * tile.height = size.y;
  3809. *
  3810. * // get a canvas context and draw something on it using coords.x, coords.y and coords.z
  3811. * var ctx = tile.getContext('2d');
  3812. *
  3813. * // return the tile so it can be rendered on screen
  3814. * return tile;
  3815. * }
  3816. * });
  3817. * ```
  3818. *
  3819. * @section Asynchronous usage
  3820. * @example
  3821. *
  3822. * Tile creation can also be asynchronous, this is useful when using a third-party drawing library. Once the tile is finished drawing it can be passed to the `done()` callback.
  3823. *
  3824. * ```js
  3825. * var CanvasLayer = L.GridLayer.extend({
  3826. * createTile: function(coords, done){
  3827. * var error;
  3828. *
  3829. * // create a <canvas> element for drawing
  3830. * var tile = L.DomUtil.create('canvas', 'leaflet-tile');
  3831. *
  3832. * // setup tile width and height according to the options
  3833. * var size = this.getTileSize();
  3834. * tile.width = size.x;
  3835. * tile.height = size.y;
  3836. *
  3837. * // draw something asynchronously and pass the tile to the done() callback
  3838. * setTimeout(function() {
  3839. * done(error, tile);
  3840. * }, 1000);
  3841. *
  3842. * return tile;
  3843. * }
  3844. * });
  3845. * ```
  3846. *
  3847. * @section
  3848. */
  3849. L.GridLayer = L.Layer.extend({
  3850. // @section
  3851. // @aka GridLayer options
  3852. options: {
  3853. // @option tileSize: Number|Point = 256
  3854. // Width and height of tiles in the grid. Use a number if width and height are equal, or `L.point(width, height)` otherwise.
  3855. tileSize: 256,
  3856. // @option opacity: Number = 1.0
  3857. // Opacity of the tiles. Can be used in the `createTile()` function.
  3858. opacity: 1,
  3859. // @option updateWhenIdle: Boolean = depends
  3860. // If `false`, new tiles are loaded during panning, otherwise only after it (for better performance). `true` by default on mobile browsers, otherwise `false`.
  3861. updateWhenIdle: L.Browser.mobile,
  3862. // @option updateWhenZooming: Boolean = true
  3863. // By default, a smooth zoom animation (during a [touch zoom](#map-touchzoom) or a [`flyTo()`](#map-flyto)) will update grid layers every integer zoom level. Setting this option to `false` will update the grid layer only when the smooth animation ends.
  3864. updateWhenZooming: true,
  3865. // @option updateInterval: Number = 200
  3866. // Tiles will not update more than once every `updateInterval` milliseconds when panning.
  3867. updateInterval: 200,
  3868. // @option zIndex: Number = 1
  3869. // The explicit zIndex of the tile layer.
  3870. zIndex: 1,
  3871. // @option bounds: LatLngBounds = undefined
  3872. // If set, tiles will only be loaded inside the set `LatLngBounds`.
  3873. bounds: null,
  3874. // @option minZoom: Number = 0
  3875. // The minimum zoom level that tiles will be loaded at. By default the entire map.
  3876. minZoom: 0,
  3877. // @option maxZoom: Number = undefined
  3878. // The maximum zoom level that tiles will be loaded at.
  3879. maxZoom: undefined,
  3880. // @option noWrap: Boolean = false
  3881. // Whether the layer is wrapped around the antimeridian. If `true`, the
  3882. // GridLayer will only be displayed once at low zoom levels. Has no
  3883. // effect when the [map CRS](#map-crs) doesn't wrap around.
  3884. noWrap: false,
  3885. // @option pane: String = 'tilePane'
  3886. // `Map pane` where the grid layer will be added.
  3887. pane: 'tilePane',
  3888. // @option className: String = ''
  3889. // A custom class name to assign to the tile layer. Empty by default.
  3890. className: '',
  3891. // @option keepBuffer: Number = 2
  3892. // When panning the map, keep this many rows and columns of tiles before unloading them.
  3893. keepBuffer: 2
  3894. },
  3895. initialize: function (options) {
  3896. L.setOptions(this, options);
  3897. },
  3898. onAdd: function () {
  3899. this._initContainer();
  3900. this._levels = {};
  3901. this._tiles = {};
  3902. this._resetView();
  3903. this._update();
  3904. },
  3905. beforeAdd: function (map) {
  3906. map._addZoomLimit(this);
  3907. },
  3908. onRemove: function (map) {
  3909. this._removeAllTiles();
  3910. L.DomUtil.remove(this._container);
  3911. map._removeZoomLimit(this);
  3912. this._container = null;
  3913. this._tileZoom = null;
  3914. },
  3915. // @method bringToFront: this
  3916. // Brings the tile layer to the top of all tile layers.
  3917. bringToFront: function () {
  3918. if (this._map) {
  3919. L.DomUtil.toFront(this._container);
  3920. this._setAutoZIndex(Math.max);
  3921. }
  3922. return this;
  3923. },
  3924. // @method bringToBack: this
  3925. // Brings the tile layer to the bottom of all tile layers.
  3926. bringToBack: function () {
  3927. if (this._map) {
  3928. L.DomUtil.toBack(this._container);
  3929. this._setAutoZIndex(Math.min);
  3930. }
  3931. return this;
  3932. },
  3933. // @method getContainer: HTMLElement
  3934. // Returns the HTML element that contains the tiles for this layer.
  3935. getContainer: function () {
  3936. return this._container;
  3937. },
  3938. // @method setOpacity(opacity: Number): this
  3939. // Changes the [opacity](#gridlayer-opacity) of the grid layer.
  3940. setOpacity: function (opacity) {
  3941. this.options.opacity = opacity;
  3942. this._updateOpacity();
  3943. return this;
  3944. },
  3945. // @method setZIndex(zIndex: Number): this
  3946. // Changes the [zIndex](#gridlayer-zindex) of the grid layer.
  3947. setZIndex: function (zIndex) {
  3948. this.options.zIndex = zIndex;
  3949. this._updateZIndex();
  3950. return this;
  3951. },
  3952. // @method isLoading: Boolean
  3953. // Returns `true` if any tile in the grid layer has not finished loading.
  3954. isLoading: function () {
  3955. return this._loading;
  3956. },
  3957. // @method redraw: this
  3958. // Causes the layer to clear all the tiles and request them again.
  3959. redraw: function () {
  3960. if (this._map) {
  3961. this._removeAllTiles();
  3962. this._update();
  3963. }
  3964. return this;
  3965. },
  3966. getEvents: function () {
  3967. var events = {
  3968. viewprereset: this._invalidateAll,
  3969. viewreset: this._resetView,
  3970. zoom: this._resetView,
  3971. moveend: this._onMoveEnd
  3972. };
  3973. if (!this.options.updateWhenIdle) {
  3974. // update tiles on move, but not more often than once per given interval
  3975. if (!this._onMove) {
  3976. this._onMove = L.Util.throttle(this._onMoveEnd, this.options.updateInterval, this);
  3977. }
  3978. events.move = this._onMove;
  3979. }
  3980. if (this._zoomAnimated) {
  3981. events.zoomanim = this._animateZoom;
  3982. }
  3983. return events;
  3984. },
  3985. // @section Extension methods
  3986. // Layers extending `GridLayer` shall reimplement the following method.
  3987. // @method createTile(coords: Object, done?: Function): HTMLElement
  3988. // Called only internally, must be overriden by classes extending `GridLayer`.
  3989. // Returns the `HTMLElement` corresponding to the given `coords`. If the `done` callback
  3990. // is specified, it must be called when the tile has finished loading and drawing.
  3991. createTile: function () {
  3992. return document.createElement('div');
  3993. },
  3994. // @section
  3995. // @method getTileSize: Point
  3996. // Normalizes the [tileSize option](#gridlayer-tilesize) into a point. Used by the `createTile()` method.
  3997. getTileSize: function () {
  3998. var s = this.options.tileSize;
  3999. return s instanceof L.Point ? s : new L.Point(s, s);
  4000. },
  4001. _updateZIndex: function () {
  4002. if (this._container && this.options.zIndex !== undefined && this.options.zIndex !== null) {
  4003. this._container.style.zIndex = this.options.zIndex;
  4004. }
  4005. },
  4006. _setAutoZIndex: function (compare) {
  4007. // go through all other layers of the same pane, set zIndex to max + 1 (front) or min - 1 (back)
  4008. var layers = this.getPane().children,
  4009. edgeZIndex = -compare(-Infinity, Infinity); // -Infinity for max, Infinity for min
  4010. for (var i = 0, len = layers.length, zIndex; i < len; i++) {
  4011. zIndex = layers[i].style.zIndex;
  4012. if (layers[i] !== this._container && zIndex) {
  4013. edgeZIndex = compare(edgeZIndex, +zIndex);
  4014. }
  4015. }
  4016. if (isFinite(edgeZIndex)) {
  4017. this.options.zIndex = edgeZIndex + compare(-1, 1);
  4018. this._updateZIndex();
  4019. }
  4020. },
  4021. _updateOpacity: function () {
  4022. if (!this._map) { return; }
  4023. // IE doesn't inherit filter opacity properly, so we're forced to set it on tiles
  4024. if (L.Browser.ielt9) { return; }
  4025. L.DomUtil.setOpacity(this._container, this.options.opacity);
  4026. var now = +new Date(),
  4027. nextFrame = false,
  4028. willPrune = false;
  4029. for (var key in this._tiles) {
  4030. var tile = this._tiles[key];
  4031. if (!tile.current || !tile.loaded) { continue; }
  4032. var fade = Math.min(1, (now - tile.loaded) / 200);
  4033. L.DomUtil.setOpacity(tile.el, fade);
  4034. if (fade < 1) {
  4035. nextFrame = true;
  4036. } else {
  4037. if (tile.active) { willPrune = true; }
  4038. tile.active = true;
  4039. }
  4040. }
  4041. if (willPrune && !this._noPrune) { this._pruneTiles(); }
  4042. if (nextFrame) {
  4043. L.Util.cancelAnimFrame(this._fadeFrame);
  4044. this._fadeFrame = L.Util.requestAnimFrame(this._updateOpacity, this);
  4045. }
  4046. },
  4047. _initContainer: function () {
  4048. if (this._container) { return; }
  4049. this._container = L.DomUtil.create('div', 'leaflet-layer ' + (this.options.className || ''));
  4050. this._updateZIndex();
  4051. if (this.options.opacity < 1) {
  4052. this._updateOpacity();
  4053. }
  4054. this.getPane().appendChild(this._container);
  4055. },
  4056. _updateLevels: function () {
  4057. var zoom = this._tileZoom,
  4058. maxZoom = this.options.maxZoom;
  4059. if (zoom === undefined) { return undefined; }
  4060. for (var z in this._levels) {
  4061. if (this._levels[z].el.children.length || z === zoom) {
  4062. this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z);
  4063. } else {
  4064. L.DomUtil.remove(this._levels[z].el);
  4065. this._removeTilesAtZoom(z);
  4066. delete this._levels[z];
  4067. }
  4068. }
  4069. var level = this._levels[zoom],
  4070. map = this._map;
  4071. if (!level) {
  4072. level = this._levels[zoom] = {};
  4073. level.el = L.DomUtil.create('div', 'leaflet-tile-container leaflet-zoom-animated', this._container);
  4074. level.el.style.zIndex = maxZoom;
  4075. level.origin = map.project(map.unproject(map.getPixelOrigin()), zoom).round();
  4076. level.zoom = zoom;
  4077. this._setZoomTransform(level, map.getCenter(), map.getZoom());
  4078. // force the browser to consider the newly added element for transition
  4079. L.Util.falseFn(level.el.offsetWidth);
  4080. }
  4081. this._level = level;
  4082. return level;
  4083. },
  4084. _pruneTiles: function () {
  4085. if (!this._map) {
  4086. return;
  4087. }
  4088. var key, tile;
  4089. var zoom = this._map.getZoom();
  4090. if (zoom > this.options.maxZoom ||
  4091. zoom < this.options.minZoom) {
  4092. this._removeAllTiles();
  4093. return;
  4094. }
  4095. for (key in this._tiles) {
  4096. tile = this._tiles[key];
  4097. tile.retain = tile.current;
  4098. }
  4099. for (key in this._tiles) {
  4100. tile = this._tiles[key];
  4101. if (tile.current && !tile.active) {
  4102. var coords = tile.coords;
  4103. if (!this._retainParent(coords.x, coords.y, coords.z, coords.z - 5)) {
  4104. this._retainChildren(coords.x, coords.y, coords.z, coords.z + 2);
  4105. }
  4106. }
  4107. }
  4108. for (key in this._tiles) {
  4109. if (!this._tiles[key].retain) {
  4110. this._removeTile(key);
  4111. }
  4112. }
  4113. },
  4114. _removeTilesAtZoom: function (zoom) {
  4115. for (var key in this._tiles) {
  4116. if (this._tiles[key].coords.z !== zoom) {
  4117. continue;
  4118. }
  4119. this._removeTile(key);
  4120. }
  4121. },
  4122. _removeAllTiles: function () {
  4123. for (var key in this._tiles) {
  4124. this._removeTile(key);
  4125. }
  4126. },
  4127. _invalidateAll: function () {
  4128. for (var z in this._levels) {
  4129. L.DomUtil.remove(this._levels[z].el);
  4130. delete this._levels[z];
  4131. }
  4132. this._removeAllTiles();
  4133. this._tileZoom = null;
  4134. },
  4135. _retainParent: function (x, y, z, minZoom) {
  4136. var x2 = Math.floor(x / 2),
  4137. y2 = Math.floor(y / 2),
  4138. z2 = z - 1,
  4139. coords2 = new L.Point(+x2, +y2);
  4140. coords2.z = +z2;
  4141. var key = this._tileCoordsToKey(coords2),
  4142. tile = this._tiles[key];
  4143. if (tile && tile.active) {
  4144. tile.retain = true;
  4145. return true;
  4146. } else if (tile && tile.loaded) {
  4147. tile.retain = true;
  4148. }
  4149. if (z2 > minZoom) {
  4150. return this._retainParent(x2, y2, z2, minZoom);
  4151. }
  4152. return false;
  4153. },
  4154. _retainChildren: function (x, y, z, maxZoom) {
  4155. for (var i = 2 * x; i < 2 * x + 2; i++) {
  4156. for (var j = 2 * y; j < 2 * y + 2; j++) {
  4157. var coords = new L.Point(i, j);
  4158. coords.z = z + 1;
  4159. var key = this._tileCoordsToKey(coords),
  4160. tile = this._tiles[key];
  4161. if (tile && tile.active) {
  4162. tile.retain = true;
  4163. continue;
  4164. } else if (tile && tile.loaded) {
  4165. tile.retain = true;
  4166. }
  4167. if (z + 1 < maxZoom) {
  4168. this._retainChildren(i, j, z + 1, maxZoom);
  4169. }
  4170. }
  4171. }
  4172. },
  4173. _resetView: function (e) {
  4174. var animating = e && (e.pinch || e.flyTo);
  4175. this._setView(this._map.getCenter(), this._map.getZoom(), animating, animating);
  4176. },
  4177. _animateZoom: function (e) {
  4178. this._setView(e.center, e.zoom, true, e.noUpdate);
  4179. },
  4180. _setView: function (center, zoom, noPrune, noUpdate) {
  4181. var tileZoom = Math.round(zoom);
  4182. if ((this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) ||
  4183. (this.options.minZoom !== undefined && tileZoom < this.options.minZoom)) {
  4184. tileZoom = undefined;
  4185. }
  4186. var tileZoomChanged = this.options.updateWhenZooming && (tileZoom !== this._tileZoom);
  4187. if (!noUpdate || tileZoomChanged) {
  4188. this._tileZoom = tileZoom;
  4189. if (this._abortLoading) {
  4190. this._abortLoading();
  4191. }
  4192. this._updateLevels();
  4193. this._resetGrid();
  4194. if (tileZoom !== undefined) {
  4195. this._update(center);
  4196. }
  4197. if (!noPrune) {
  4198. this._pruneTiles();
  4199. }
  4200. // Flag to prevent _updateOpacity from pruning tiles during
  4201. // a zoom anim or a pinch gesture
  4202. this._noPrune = !!noPrune;
  4203. }
  4204. this._setZoomTransforms(center, zoom);
  4205. },
  4206. _setZoomTransforms: function (center, zoom) {
  4207. for (var i in this._levels) {
  4208. this._setZoomTransform(this._levels[i], center, zoom);
  4209. }
  4210. },
  4211. _setZoomTransform: function (level, center, zoom) {
  4212. var scale = this._map.getZoomScale(zoom, level.zoom),
  4213. translate = level.origin.multiplyBy(scale)
  4214. .subtract(this._map._getNewPixelOrigin(center, zoom)).round();
  4215. if (L.Browser.any3d) {
  4216. L.DomUtil.setTransform(level.el, translate, scale);
  4217. } else {
  4218. L.DomUtil.setPosition(level.el, translate);
  4219. }
  4220. },
  4221. _resetGrid: function () {
  4222. var map = this._map,
  4223. crs = map.options.crs,
  4224. tileSize = this._tileSize = this.getTileSize(),
  4225. tileZoom = this._tileZoom;
  4226. var bounds = this._map.getPixelWorldBounds(this._tileZoom);
  4227. if (bounds) {
  4228. this._globalTileRange = this._pxBoundsToTileRange(bounds);
  4229. }
  4230. this._wrapX = crs.wrapLng && !this.options.noWrap && [
  4231. Math.floor(map.project([0, crs.wrapLng[0]], tileZoom).x / tileSize.x),
  4232. Math.ceil(map.project([0, crs.wrapLng[1]], tileZoom).x / tileSize.y)
  4233. ];
  4234. this._wrapY = crs.wrapLat && !this.options.noWrap && [
  4235. Math.floor(map.project([crs.wrapLat[0], 0], tileZoom).y / tileSize.x),
  4236. Math.ceil(map.project([crs.wrapLat[1], 0], tileZoom).y / tileSize.y)
  4237. ];
  4238. },
  4239. _onMoveEnd: function () {
  4240. if (!this._map || this._map._animatingZoom) { return; }
  4241. this._update();
  4242. },
  4243. _getTiledPixelBounds: function (center) {
  4244. var map = this._map,
  4245. mapZoom = map._animatingZoom ? Math.max(map._animateToZoom, map.getZoom()) : map.getZoom(),
  4246. scale = map.getZoomScale(mapZoom, this._tileZoom),
  4247. pixelCenter = map.project(center, this._tileZoom).floor(),
  4248. halfSize = map.getSize().divideBy(scale * 2);
  4249. return new L.Bounds(pixelCenter.subtract(halfSize), pixelCenter.add(halfSize));
  4250. },
  4251. // Private method to load tiles in the grid's active zoom level according to map bounds
  4252. _update: function (center) {
  4253. var map = this._map;
  4254. if (!map) { return; }
  4255. var zoom = map.getZoom();
  4256. if (center === undefined) { center = map.getCenter(); }
  4257. if (this._tileZoom === undefined) { return; } // if out of minzoom/maxzoom
  4258. var pixelBounds = this._getTiledPixelBounds(center),
  4259. tileRange = this._pxBoundsToTileRange(pixelBounds),
  4260. tileCenter = tileRange.getCenter(),
  4261. queue = [],
  4262. margin = this.options.keepBuffer,
  4263. noPruneRange = new L.Bounds(tileRange.getBottomLeft().subtract([margin, -margin]),
  4264. tileRange.getTopRight().add([margin, -margin]));
  4265. for (var key in this._tiles) {
  4266. var c = this._tiles[key].coords;
  4267. if (c.z !== this._tileZoom || !noPruneRange.contains(L.point(c.x, c.y))) {
  4268. this._tiles[key].current = false;
  4269. }
  4270. }
  4271. // _update just loads more tiles. If the tile zoom level differs too much
  4272. // from the map's, let _setView reset levels and prune old tiles.
  4273. if (Math.abs(zoom - this._tileZoom) > 1) { this._setView(center, zoom); return; }
  4274. // create a queue of coordinates to load tiles from
  4275. for (var j = tileRange.min.y; j <= tileRange.max.y; j++) {
  4276. for (var i = tileRange.min.x; i <= tileRange.max.x; i++) {
  4277. var coords = new L.Point(i, j);
  4278. coords.z = this._tileZoom;
  4279. if (!this._isValidTile(coords)) { continue; }
  4280. var tile = this._tiles[this._tileCoordsToKey(coords)];
  4281. if (tile) {
  4282. tile.current = true;
  4283. } else {
  4284. queue.push(coords);
  4285. }
  4286. }
  4287. }
  4288. // sort tile queue to load tiles in order of their distance to center
  4289. queue.sort(function (a, b) {
  4290. return a.distanceTo(tileCenter) - b.distanceTo(tileCenter);
  4291. });
  4292. if (queue.length !== 0) {
  4293. // if it's the first batch of tiles to load
  4294. if (!this._loading) {
  4295. this._loading = true;
  4296. // @event loading: Event
  4297. // Fired when the grid layer starts loading tiles.
  4298. this.fire('loading');
  4299. }
  4300. // create DOM fragment to append tiles in one batch
  4301. var fragment = document.createDocumentFragment();
  4302. for (i = 0; i < queue.length; i++) {
  4303. this._addTile(queue[i], fragment);
  4304. }
  4305. this._level.el.appendChild(fragment);
  4306. }
  4307. },
  4308. _isValidTile: function (coords) {
  4309. var crs = this._map.options.crs;
  4310. if (!crs.infinite) {
  4311. // don't load tile if it's out of bounds and not wrapped
  4312. var bounds = this._globalTileRange;
  4313. if ((!crs.wrapLng && (coords.x < bounds.min.x || coords.x > bounds.max.x)) ||
  4314. (!crs.wrapLat && (coords.y < bounds.min.y || coords.y > bounds.max.y))) { return false; }
  4315. }
  4316. if (!this.options.bounds) { return true; }
  4317. // don't load tile if it doesn't intersect the bounds in options
  4318. var tileBounds = this._tileCoordsToBounds(coords);
  4319. return L.latLngBounds(this.options.bounds).overlaps(tileBounds);
  4320. },
  4321. _keyToBounds: function (key) {
  4322. return this._tileCoordsToBounds(this._keyToTileCoords(key));
  4323. },
  4324. // converts tile coordinates to its geographical bounds
  4325. _tileCoordsToBounds: function (coords) {
  4326. var map = this._map,
  4327. tileSize = this.getTileSize(),
  4328. nwPoint = coords.scaleBy(tileSize),
  4329. sePoint = nwPoint.add(tileSize),
  4330. nw = map.unproject(nwPoint, coords.z),
  4331. se = map.unproject(sePoint, coords.z);
  4332. if (!this.options.noWrap) {
  4333. nw = map.wrapLatLng(nw);
  4334. se = map.wrapLatLng(se);
  4335. }
  4336. return new L.LatLngBounds(nw, se);
  4337. },
  4338. // converts tile coordinates to key for the tile cache
  4339. _tileCoordsToKey: function (coords) {
  4340. return coords.x + ':' + coords.y + ':' + coords.z;
  4341. },
  4342. // converts tile cache key to coordinates
  4343. _keyToTileCoords: function (key) {
  4344. var k = key.split(':'),
  4345. coords = new L.Point(+k[0], +k[1]);
  4346. coords.z = +k[2];
  4347. return coords;
  4348. },
  4349. _removeTile: function (key) {
  4350. var tile = this._tiles[key];
  4351. if (!tile) { return; }
  4352. L.DomUtil.remove(tile.el);
  4353. delete this._tiles[key];
  4354. // @event tileunload: TileEvent
  4355. // Fired when a tile is removed (e.g. when a tile goes off the screen).
  4356. this.fire('tileunload', {
  4357. tile: tile.el,
  4358. coords: this._keyToTileCoords(key)
  4359. });
  4360. },
  4361. _initTile: function (tile) {
  4362. L.DomUtil.addClass(tile, 'leaflet-tile');
  4363. var tileSize = this.getTileSize();
  4364. tile.style.width = tileSize.x + 'px';
  4365. tile.style.height = tileSize.y + 'px';
  4366. tile.onselectstart = L.Util.falseFn;
  4367. tile.onmousemove = L.Util.falseFn;
  4368. // update opacity on tiles in IE7-8 because of filter inheritance problems
  4369. if (L.Browser.ielt9 && this.options.opacity < 1) {
  4370. L.DomUtil.setOpacity(tile, this.options.opacity);
  4371. }
  4372. // without this hack, tiles disappear after zoom on Chrome for Android
  4373. // https://github.com/Leaflet/Leaflet/issues/2078
  4374. if (L.Browser.android && !L.Browser.android23) {
  4375. tile.style.WebkitBackfaceVisibility = 'hidden';
  4376. }
  4377. },
  4378. _addTile: function (coords, container) {
  4379. var tilePos = this._getTilePos(coords),
  4380. key = this._tileCoordsToKey(coords);
  4381. var tile = this.createTile(this._wrapCoords(coords), L.bind(this._tileReady, this, coords));
  4382. this._initTile(tile);
  4383. // if createTile is defined with a second argument ("done" callback),
  4384. // we know that tile is async and will be ready later; otherwise
  4385. if (this.createTile.length < 2) {
  4386. // mark tile as ready, but delay one frame for opacity animation to happen
  4387. L.Util.requestAnimFrame(L.bind(this._tileReady, this, coords, null, tile));
  4388. }
  4389. L.DomUtil.setPosition(tile, tilePos);
  4390. // save tile in cache
  4391. this._tiles[key] = {
  4392. el: tile,
  4393. coords: coords,
  4394. current: true
  4395. };
  4396. container.appendChild(tile);
  4397. // @event tileloadstart: TileEvent
  4398. // Fired when a tile is requested and starts loading.
  4399. this.fire('tileloadstart', {
  4400. tile: tile,
  4401. coords: coords
  4402. });
  4403. },
  4404. _tileReady: function (coords, err, tile) {
  4405. if (!this._map) { return; }
  4406. if (err) {
  4407. // @event tileerror: TileErrorEvent
  4408. // Fired when there is an error loading a tile.
  4409. this.fire('tileerror', {
  4410. error: err,
  4411. tile: tile,
  4412. coords: coords
  4413. });
  4414. }
  4415. var key = this._tileCoordsToKey(coords);
  4416. tile = this._tiles[key];
  4417. if (!tile) { return; }
  4418. tile.loaded = +new Date();
  4419. if (this._map._fadeAnimated) {
  4420. L.DomUtil.setOpacity(tile.el, 0);
  4421. L.Util.cancelAnimFrame(this._fadeFrame);
  4422. this._fadeFrame = L.Util.requestAnimFrame(this._updateOpacity, this);
  4423. } else {
  4424. tile.active = true;
  4425. this._pruneTiles();
  4426. }
  4427. if (!err) {
  4428. L.DomUtil.addClass(tile.el, 'leaflet-tile-loaded');
  4429. // @event tileload: TileEvent
  4430. // Fired when a tile loads.
  4431. this.fire('tileload', {
  4432. tile: tile.el,
  4433. coords: coords
  4434. });
  4435. }
  4436. if (this._noTilesToLoad()) {
  4437. this._loading = false;
  4438. // @event load: Event
  4439. // Fired when the grid layer loaded all visible tiles.
  4440. this.fire('load');
  4441. if (L.Browser.ielt9 || !this._map._fadeAnimated) {
  4442. L.Util.requestAnimFrame(this._pruneTiles, this);
  4443. } else {
  4444. // Wait a bit more than 0.2 secs (the duration of the tile fade-in)
  4445. // to trigger a pruning.
  4446. setTimeout(L.bind(this._pruneTiles, this), 250);
  4447. }
  4448. }
  4449. },
  4450. _getTilePos: function (coords) {
  4451. return coords.scaleBy(this.getTileSize()).subtract(this._level.origin);
  4452. },
  4453. _wrapCoords: function (coords) {
  4454. var newCoords = new L.Point(
  4455. this._wrapX ? L.Util.wrapNum(coords.x, this._wrapX) : coords.x,
  4456. this._wrapY ? L.Util.wrapNum(coords.y, this._wrapY) : coords.y);
  4457. newCoords.z = coords.z;
  4458. return newCoords;
  4459. },
  4460. _pxBoundsToTileRange: function (bounds) {
  4461. var tileSize = this.getTileSize();
  4462. return new L.Bounds(
  4463. bounds.min.unscaleBy(tileSize).floor(),
  4464. bounds.max.unscaleBy(tileSize).ceil().subtract([1, 1]));
  4465. },
  4466. _noTilesToLoad: function () {
  4467. for (var key in this._tiles) {
  4468. if (!this._tiles[key].loaded) { return false; }
  4469. }
  4470. return true;
  4471. }
  4472. });
  4473. // @factory L.gridLayer(options?: GridLayer options)
  4474. // Creates a new instance of GridLayer with the supplied options.
  4475. L.gridLayer = function (options) {
  4476. return new L.GridLayer(options);
  4477. };
  4478. /*
  4479. * @class TileLayer
  4480. * @inherits GridLayer
  4481. * @aka L.TileLayer
  4482. * Used to load and display tile layers on the map. Extends `GridLayer`.
  4483. *
  4484. * @example
  4485. *
  4486. * ```js
  4487. * L.tileLayer('http://{s}.tile.osm.org/{z}/{x}/{y}.png?{foo}', {foo: 'bar'}).addTo(map);
  4488. * ```
  4489. *
  4490. * @section URL template
  4491. * @example
  4492. *
  4493. * A string of the following form:
  4494. *
  4495. * ```
  4496. * 'http://{s}.somedomain.com/blabla/{z}/{x}/{y}{r}.png'
  4497. * ```
  4498. *
  4499. * `{s}` means one of the available subdomains (used sequentially to help with browser parallel requests per domain limitation; subdomain values are specified in options; `a`, `b` or `c` by default, can be omitted), `{z}` — zoom level, `{x}` and `{y}` — tile coordinates. `{r}` can be used to add @2x to the URL to load retina tiles.
  4500. *
  4501. * You can use custom keys in the template, which will be [evaluated](#util-template) from TileLayer options, like this:
  4502. *
  4503. * ```
  4504. * L.tileLayer('http://{s}.somedomain.com/{foo}/{z}/{x}/{y}.png', {foo: 'bar'});
  4505. * ```
  4506. */
  4507. L.TileLayer = L.GridLayer.extend({
  4508. // @section
  4509. // @aka TileLayer options
  4510. options: {
  4511. // @option minZoom: Number = 0
  4512. // Minimum zoom number.
  4513. minZoom: 0,
  4514. // @option maxZoom: Number = 18
  4515. // Maximum zoom number.
  4516. maxZoom: 18,
  4517. // @option maxNativeZoom: Number = null
  4518. // Maximum zoom number the tile source has available. If it is specified,
  4519. // the tiles on all zoom levels higher than `maxNativeZoom` will be loaded
  4520. // from `maxNativeZoom` level and auto-scaled.
  4521. maxNativeZoom: null,
  4522. // @option minNativeZoom: Number = null
  4523. // Minimum zoom number the tile source has available. If it is specified,
  4524. // the tiles on all zoom levels lower than `minNativeZoom` will be loaded
  4525. // from `minNativeZoom` level and auto-scaled.
  4526. minNativeZoom: null,
  4527. // @option subdomains: String|String[] = 'abc'
  4528. // Subdomains of the tile service. Can be passed in the form of one string (where each letter is a subdomain name) or an array of strings.
  4529. subdomains: 'abc',
  4530. // @option errorTileUrl: String = ''
  4531. // URL to the tile image to show in place of the tile that failed to load.
  4532. errorTileUrl: '',
  4533. // @option zoomOffset: Number = 0
  4534. // The zoom number used in tile URLs will be offset with this value.
  4535. zoomOffset: 0,
  4536. // @option tms: Boolean = false
  4537. // If `true`, inverses Y axis numbering for tiles (turn this on for [TMS](https://en.wikipedia.org/wiki/Tile_Map_Service) services).
  4538. tms: false,
  4539. // @option zoomReverse: Boolean = false
  4540. // If set to true, the zoom number used in tile URLs will be reversed (`maxZoom - zoom` instead of `zoom`)
  4541. zoomReverse: false,
  4542. // @option detectRetina: Boolean = false
  4543. // If `true` and user is on a retina display, it will request four tiles of half the specified size and a bigger zoom level in place of one to utilize the high resolution.
  4544. detectRetina: false,
  4545. // @option crossOrigin: Boolean = false
  4546. // If true, all tiles will have their crossOrigin attribute set to ''. This is needed if you want to access tile pixel data.
  4547. crossOrigin: false
  4548. },
  4549. initialize: function (url, options) {
  4550. this._url = url;
  4551. options = L.setOptions(this, options);
  4552. // detecting retina displays, adjusting tileSize and zoom levels
  4553. if (options.detectRetina && L.Browser.retina && options.maxZoom > 0) {
  4554. options.tileSize = Math.floor(options.tileSize / 2);
  4555. if (!options.zoomReverse) {
  4556. options.zoomOffset++;
  4557. options.maxZoom--;
  4558. } else {
  4559. options.zoomOffset--;
  4560. options.minZoom++;
  4561. }
  4562. options.minZoom = Math.max(0, options.minZoom);
  4563. }
  4564. if (typeof options.subdomains === 'string') {
  4565. options.subdomains = options.subdomains.split('');
  4566. }
  4567. // for https://github.com/Leaflet/Leaflet/issues/137
  4568. if (!L.Browser.android) {
  4569. this.on('tileunload', this._onTileRemove);
  4570. }
  4571. },
  4572. // @method setUrl(url: String, noRedraw?: Boolean): this
  4573. // Updates the layer's URL template and redraws it (unless `noRedraw` is set to `true`).
  4574. setUrl: function (url, noRedraw) {
  4575. this._url = url;
  4576. if (!noRedraw) {
  4577. this.redraw();
  4578. }
  4579. return this;
  4580. },
  4581. // @method createTile(coords: Object, done?: Function): HTMLElement
  4582. // Called only internally, overrides GridLayer's [`createTile()`](#gridlayer-createtile)
  4583. // to return an `<img>` HTML element with the appropiate image URL given `coords`. The `done`
  4584. // callback is called when the tile has been loaded.
  4585. createTile: function (coords, done) {
  4586. var tile = document.createElement('img');
  4587. L.DomEvent.on(tile, 'load', L.bind(this._tileOnLoad, this, done, tile));
  4588. L.DomEvent.on(tile, 'error', L.bind(this._tileOnError, this, done, tile));
  4589. if (this.options.crossOrigin) {
  4590. tile.crossOrigin = '';
  4591. }
  4592. /*
  4593. Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons
  4594. http://www.w3.org/TR/WCAG20-TECHS/H67
  4595. */
  4596. tile.alt = '';
  4597. /*
  4598. Set role="presentation" to force screen readers to ignore this
  4599. https://www.w3.org/TR/wai-aria/roles#textalternativecomputation
  4600. */
  4601. tile.setAttribute('role', 'presentation');
  4602. tile.src = this.getTileUrl(coords);
  4603. return tile;
  4604. },
  4605. // @section Extension methods
  4606. // @uninheritable
  4607. // Layers extending `TileLayer` might reimplement the following method.
  4608. // @method getTileUrl(coords: Object): String
  4609. // Called only internally, returns the URL for a tile given its coordinates.
  4610. // Classes extending `TileLayer` can override this function to provide custom tile URL naming schemes.
  4611. getTileUrl: function (coords) {
  4612. var data = {
  4613. r: L.Browser.retina ? '@2x' : '',
  4614. s: this._getSubdomain(coords),
  4615. x: coords.x,
  4616. y: coords.y,
  4617. z: this._getZoomForUrl()
  4618. };
  4619. if (this._map && !this._map.options.crs.infinite) {
  4620. var invertedY = this._globalTileRange.max.y - coords.y;
  4621. if (this.options.tms) {
  4622. data['y'] = invertedY;
  4623. }
  4624. data['-y'] = invertedY;
  4625. }
  4626. return L.Util.template(this._url, L.extend(data, this.options));
  4627. },
  4628. _tileOnLoad: function (done, tile) {
  4629. // For https://github.com/Leaflet/Leaflet/issues/3332
  4630. if (L.Browser.ielt9) {
  4631. setTimeout(L.bind(done, this, null, tile), 0);
  4632. } else {
  4633. done(null, tile);
  4634. }
  4635. },
  4636. _tileOnError: function (done, tile, e) {
  4637. var errorUrl = this.options.errorTileUrl;
  4638. if (errorUrl) {
  4639. tile.src = errorUrl;
  4640. }
  4641. done(e, tile);
  4642. },
  4643. getTileSize: function () {
  4644. var map = this._map,
  4645. tileSize = L.GridLayer.prototype.getTileSize.call(this),
  4646. zoom = this._tileZoom + this.options.zoomOffset,
  4647. minNativeZoom = this.options.minNativeZoom,
  4648. maxNativeZoom = this.options.maxNativeZoom;
  4649. // decrease tile size when scaling below minNativeZoom
  4650. if (minNativeZoom !== null && zoom < minNativeZoom) {
  4651. return tileSize.divideBy(map.getZoomScale(minNativeZoom, zoom)).round();
  4652. }
  4653. // increase tile size when scaling above maxNativeZoom
  4654. if (maxNativeZoom !== null && zoom > maxNativeZoom) {
  4655. return tileSize.divideBy(map.getZoomScale(maxNativeZoom, zoom)).round();
  4656. }
  4657. return tileSize;
  4658. },
  4659. _onTileRemove: function (e) {
  4660. e.tile.onload = null;
  4661. },
  4662. _getZoomForUrl: function () {
  4663. var zoom = this._tileZoom,
  4664. maxZoom = this.options.maxZoom,
  4665. zoomReverse = this.options.zoomReverse,
  4666. zoomOffset = this.options.zoomOffset,
  4667. minNativeZoom = this.options.minNativeZoom,
  4668. maxNativeZoom = this.options.maxNativeZoom;
  4669. if (zoomReverse) {
  4670. zoom = maxZoom - zoom;
  4671. }
  4672. zoom += zoomOffset;
  4673. if (minNativeZoom !== null && zoom < minNativeZoom) {
  4674. return minNativeZoom;
  4675. }
  4676. if (maxNativeZoom !== null && zoom > maxNativeZoom) {
  4677. return maxNativeZoom;
  4678. }
  4679. return zoom;
  4680. },
  4681. _getSubdomain: function (tilePoint) {
  4682. var index = Math.abs(tilePoint.x + tilePoint.y) % this.options.subdomains.length;
  4683. return this.options.subdomains[index];
  4684. },
  4685. // stops loading all tiles in the background layer
  4686. _abortLoading: function () {
  4687. var i, tile;
  4688. for (i in this._tiles) {
  4689. if (this._tiles[i].coords.z !== this._tileZoom) {
  4690. tile = this._tiles[i].el;
  4691. tile.onload = L.Util.falseFn;
  4692. tile.onerror = L.Util.falseFn;
  4693. if (!tile.complete) {
  4694. tile.src = L.Util.emptyImageUrl;
  4695. L.DomUtil.remove(tile);
  4696. }
  4697. }
  4698. }
  4699. }
  4700. });
  4701. // @factory L.tilelayer(urlTemplate: String, options?: TileLayer options)
  4702. // Instantiates a tile layer object given a `URL template` and optionally an options object.
  4703. L.tileLayer = function (url, options) {
  4704. return new L.TileLayer(url, options);
  4705. };
  4706. /*
  4707. * @class TileLayer.WMS
  4708. * @inherits TileLayer
  4709. * @aka L.TileLayer.WMS
  4710. * Used to display [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services as tile layers on the map. Extends `TileLayer`.
  4711. *
  4712. * @example
  4713. *
  4714. * ```js
  4715. * var nexrad = L.tileLayer.wms("http://mesonet.agron.iastate.edu/cgi-bin/wms/nexrad/n0r.cgi", {
  4716. * layers: 'nexrad-n0r-900913',
  4717. * format: 'image/png',
  4718. * transparent: true,
  4719. * attribution: "Weather data © 2012 IEM Nexrad"
  4720. * });
  4721. * ```
  4722. */
  4723. L.TileLayer.WMS = L.TileLayer.extend({
  4724. // @section
  4725. // @aka TileLayer.WMS options
  4726. // If any custom options not documented here are used, they will be sent to the
  4727. // WMS server as extra parameters in each request URL. This can be useful for
  4728. // [non-standard vendor WMS parameters](http://docs.geoserver.org/stable/en/user/services/wms/vendor.html).
  4729. defaultWmsParams: {
  4730. service: 'WMS',
  4731. request: 'GetMap',
  4732. // @option layers: String = ''
  4733. // **(required)** Comma-separated list of WMS layers to show.
  4734. layers: '',
  4735. // @option styles: String = ''
  4736. // Comma-separated list of WMS styles.
  4737. styles: '',
  4738. // @option format: String = 'image/jpeg'
  4739. // WMS image format (use `'image/png'` for layers with transparency).
  4740. format: 'image/jpeg',
  4741. // @option transparent: Boolean = false
  4742. // If `true`, the WMS service will return images with transparency.
  4743. transparent: false,
  4744. // @option version: String = '1.1.1'
  4745. // Version of the WMS service to use
  4746. version: '1.1.1'
  4747. },
  4748. options: {
  4749. // @option crs: CRS = null
  4750. // Coordinate Reference System to use for the WMS requests, defaults to
  4751. // map CRS. Don't change this if you're not sure what it means.
  4752. crs: null,
  4753. // @option uppercase: Boolean = false
  4754. // If `true`, WMS request parameter keys will be uppercase.
  4755. uppercase: false
  4756. },
  4757. initialize: function (url, options) {
  4758. this._url = url;
  4759. var wmsParams = L.extend({}, this.defaultWmsParams);
  4760. // all keys that are not TileLayer options go to WMS params
  4761. for (var i in options) {
  4762. if (!(i in this.options)) {
  4763. wmsParams[i] = options[i];
  4764. }
  4765. }
  4766. options = L.setOptions(this, options);
  4767. wmsParams.width = wmsParams.height = options.tileSize * (options.detectRetina && L.Browser.retina ? 2 : 1);
  4768. this.wmsParams = wmsParams;
  4769. },
  4770. onAdd: function (map) {
  4771. this._crs = this.options.crs || map.options.crs;
  4772. this._wmsVersion = parseFloat(this.wmsParams.version);
  4773. var projectionKey = this._wmsVersion >= 1.3 ? 'crs' : 'srs';
  4774. this.wmsParams[projectionKey] = this._crs.code;
  4775. L.TileLayer.prototype.onAdd.call(this, map);
  4776. },
  4777. getTileUrl: function (coords) {
  4778. var tileBounds = this._tileCoordsToBounds(coords),
  4779. nw = this._crs.project(tileBounds.getNorthWest()),
  4780. se = this._crs.project(tileBounds.getSouthEast()),
  4781. bbox = (this._wmsVersion >= 1.3 && this._crs === L.CRS.EPSG4326 ?
  4782. [se.y, nw.x, nw.y, se.x] :
  4783. [nw.x, se.y, se.x, nw.y]).join(','),
  4784. url = L.TileLayer.prototype.getTileUrl.call(this, coords);
  4785. return url +
  4786. L.Util.getParamString(this.wmsParams, url, this.options.uppercase) +
  4787. (this.options.uppercase ? '&BBOX=' : '&bbox=') + bbox;
  4788. },
  4789. // @method setParams(params: Object, noRedraw?: Boolean): this
  4790. // Merges an object with the new parameters and re-requests tiles on the current screen (unless `noRedraw` was set to true).
  4791. setParams: function (params, noRedraw) {
  4792. L.extend(this.wmsParams, params);
  4793. if (!noRedraw) {
  4794. this.redraw();
  4795. }
  4796. return this;
  4797. }
  4798. });
  4799. // @factory L.tileLayer.wms(baseUrl: String, options: TileLayer.WMS options)
  4800. // Instantiates a WMS tile layer object given a base URL of the WMS service and a WMS parameters/options object.
  4801. L.tileLayer.wms = function (url, options) {
  4802. return new L.TileLayer.WMS(url, options);
  4803. };
  4804. /*
  4805. * @class ImageOverlay
  4806. * @aka L.ImageOverlay
  4807. * @inherits Interactive layer
  4808. *
  4809. * Used to load and display a single image over specific bounds of the map. Extends `Layer`.
  4810. *
  4811. * @example
  4812. *
  4813. * ```js
  4814. * var imageUrl = 'http://www.lib.utexas.edu/maps/historical/newark_nj_1922.jpg',
  4815. * imageBounds = [[40.712216, -74.22655], [40.773941, -74.12544]];
  4816. * L.imageOverlay(imageUrl, imageBounds).addTo(map);
  4817. * ```
  4818. */
  4819. L.ImageOverlay = L.Layer.extend({
  4820. // @section
  4821. // @aka ImageOverlay options
  4822. options: {
  4823. // @option opacity: Number = 1.0
  4824. // The opacity of the image overlay.
  4825. opacity: 1,
  4826. // @option alt: String = ''
  4827. // Text for the `alt` attribute of the image (useful for accessibility).
  4828. alt: '',
  4829. // @option interactive: Boolean = false
  4830. // If `true`, the image overlay will emit [mouse events](#interactive-layer) when clicked or hovered.
  4831. interactive: false,
  4832. // @option crossOrigin: Boolean = false
  4833. // If true, the image will have its crossOrigin attribute set to ''. This is needed if you want to access image pixel data.
  4834. crossOrigin: false
  4835. },
  4836. initialize: function (url, bounds, options) { // (String, LatLngBounds, Object)
  4837. this._url = url;
  4838. this._bounds = L.latLngBounds(bounds);
  4839. L.setOptions(this, options);
  4840. },
  4841. onAdd: function () {
  4842. if (!this._image) {
  4843. this._initImage();
  4844. if (this.options.opacity < 1) {
  4845. this._updateOpacity();
  4846. }
  4847. }
  4848. if (this.options.interactive) {
  4849. L.DomUtil.addClass(this._image, 'leaflet-interactive');
  4850. this.addInteractiveTarget(this._image);
  4851. }
  4852. this.getPane().appendChild(this._image);
  4853. this._reset();
  4854. },
  4855. onRemove: function () {
  4856. L.DomUtil.remove(this._image);
  4857. if (this.options.interactive) {
  4858. this.removeInteractiveTarget(this._image);
  4859. }
  4860. },
  4861. // @method setOpacity(opacity: Number): this
  4862. // Sets the opacity of the overlay.
  4863. setOpacity: function (opacity) {
  4864. this.options.opacity = opacity;
  4865. if (this._image) {
  4866. this._updateOpacity();
  4867. }
  4868. return this;
  4869. },
  4870. setStyle: function (styleOpts) {
  4871. if (styleOpts.opacity) {
  4872. this.setOpacity(styleOpts.opacity);
  4873. }
  4874. return this;
  4875. },
  4876. // @method bringToFront(): this
  4877. // Brings the layer to the top of all overlays.
  4878. bringToFront: function () {
  4879. if (this._map) {
  4880. L.DomUtil.toFront(this._image);
  4881. }
  4882. return this;
  4883. },
  4884. // @method bringToBack(): this
  4885. // Brings the layer to the bottom of all overlays.
  4886. bringToBack: function () {
  4887. if (this._map) {
  4888. L.DomUtil.toBack(this._image);
  4889. }
  4890. return this;
  4891. },
  4892. // @method setUrl(url: String): this
  4893. // Changes the URL of the image.
  4894. setUrl: function (url) {
  4895. this._url = url;
  4896. if (this._image) {
  4897. this._image.src = url;
  4898. }
  4899. return this;
  4900. },
  4901. setBounds: function (bounds) {
  4902. this._bounds = bounds;
  4903. if (this._map) {
  4904. this._reset();
  4905. }
  4906. return this;
  4907. },
  4908. getEvents: function () {
  4909. var events = {
  4910. zoom: this._reset,
  4911. viewreset: this._reset
  4912. };
  4913. if (this._zoomAnimated) {
  4914. events.zoomanim = this._animateZoom;
  4915. }
  4916. return events;
  4917. },
  4918. getBounds: function () {
  4919. return this._bounds;
  4920. },
  4921. getElement: function () {
  4922. return this._image;
  4923. },
  4924. _initImage: function () {
  4925. var img = this._image = L.DomUtil.create('img',
  4926. 'leaflet-image-layer ' + (this._zoomAnimated ? 'leaflet-zoom-animated' : ''));
  4927. img.onselectstart = L.Util.falseFn;
  4928. img.onmousemove = L.Util.falseFn;
  4929. img.onload = L.bind(this.fire, this, 'load');
  4930. if (this.options.crossOrigin) {
  4931. img.crossOrigin = '';
  4932. }
  4933. img.src = this._url;
  4934. img.alt = this.options.alt;
  4935. },
  4936. _animateZoom: function (e) {
  4937. var scale = this._map.getZoomScale(e.zoom),
  4938. offset = this._map._latLngBoundsToNewLayerBounds(this._bounds, e.zoom, e.center).min;
  4939. L.DomUtil.setTransform(this._image, offset, scale);
  4940. },
  4941. _reset: function () {
  4942. var image = this._image,
  4943. bounds = new L.Bounds(
  4944. this._map.latLngToLayerPoint(this._bounds.getNorthWest()),
  4945. this._map.latLngToLayerPoint(this._bounds.getSouthEast())),
  4946. size = bounds.getSize();
  4947. L.DomUtil.setPosition(image, bounds.min);
  4948. image.style.width = size.x + 'px';
  4949. image.style.height = size.y + 'px';
  4950. },
  4951. _updateOpacity: function () {
  4952. L.DomUtil.setOpacity(this._image, this.options.opacity);
  4953. }
  4954. });
  4955. // @factory L.imageOverlay(imageUrl: String, bounds: LatLngBounds, options?: ImageOverlay options)
  4956. // Instantiates an image overlay object given the URL of the image and the
  4957. // geographical bounds it is tied to.
  4958. L.imageOverlay = function (url, bounds, options) {
  4959. return new L.ImageOverlay(url, bounds, options);
  4960. };
  4961. /*
  4962. * @class Icon
  4963. * @aka L.Icon
  4964. * @inherits Layer
  4965. *
  4966. * Represents an icon to provide when creating a marker.
  4967. *
  4968. * @example
  4969. *
  4970. * ```js
  4971. * var myIcon = L.icon({
  4972. * iconUrl: 'my-icon.png',
  4973. * iconRetinaUrl: 'my-icon@2x.png',
  4974. * iconSize: [38, 95],
  4975. * iconAnchor: [22, 94],
  4976. * popupAnchor: [-3, -76],
  4977. * shadowUrl: 'my-icon-shadow.png',
  4978. * shadowRetinaUrl: 'my-icon-shadow@2x.png',
  4979. * shadowSize: [68, 95],
  4980. * shadowAnchor: [22, 94]
  4981. * });
  4982. *
  4983. * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
  4984. * ```
  4985. *
  4986. * `L.Icon.Default` extends `L.Icon` and is the blue icon Leaflet uses for markers by default.
  4987. *
  4988. */
  4989. L.Icon = L.Class.extend({
  4990. /* @section
  4991. * @aka Icon options
  4992. *
  4993. * @option iconUrl: String = null
  4994. * **(required)** The URL to the icon image (absolute or relative to your script path).
  4995. *
  4996. * @option iconRetinaUrl: String = null
  4997. * The URL to a retina sized version of the icon image (absolute or relative to your
  4998. * script path). Used for Retina screen devices.
  4999. *
  5000. * @option iconSize: Point = null
  5001. * Size of the icon image in pixels.
  5002. *
  5003. * @option iconAnchor: Point = null
  5004. * The coordinates of the "tip" of the icon (relative to its top left corner). The icon
  5005. * will be aligned so that this point is at the marker's geographical location. Centered
  5006. * by default if size is specified, also can be set in CSS with negative margins.
  5007. *
  5008. * @option popupAnchor: Point = null
  5009. * The coordinates of the point from which popups will "open", relative to the icon anchor.
  5010. *
  5011. * @option shadowUrl: String = null
  5012. * The URL to the icon shadow image. If not specified, no shadow image will be created.
  5013. *
  5014. * @option shadowRetinaUrl: String = null
  5015. *
  5016. * @option shadowSize: Point = null
  5017. * Size of the shadow image in pixels.
  5018. *
  5019. * @option shadowAnchor: Point = null
  5020. * The coordinates of the "tip" of the shadow (relative to its top left corner) (the same
  5021. * as iconAnchor if not specified).
  5022. *
  5023. * @option className: String = ''
  5024. * A custom class name to assign to both icon and shadow images. Empty by default.
  5025. */
  5026. initialize: function (options) {
  5027. L.setOptions(this, options);
  5028. },
  5029. // @method createIcon(oldIcon?: HTMLElement): HTMLElement
  5030. // Called internally when the icon has to be shown, returns a `<img>` HTML element
  5031. // styled according to the options.
  5032. createIcon: function (oldIcon) {
  5033. return this._createIcon('icon', oldIcon);
  5034. },
  5035. // @method createShadow(oldIcon?: HTMLElement): HTMLElement
  5036. // As `createIcon`, but for the shadow beneath it.
  5037. createShadow: function (oldIcon) {
  5038. return this._createIcon('shadow', oldIcon);
  5039. },
  5040. _createIcon: function (name, oldIcon) {
  5041. var src = this._getIconUrl(name);
  5042. if (!src) {
  5043. if (name === 'icon') {
  5044. throw new Error('iconUrl not set in Icon options (see the docs).');
  5045. }
  5046. return null;
  5047. }
  5048. var img = this._createImg(src, oldIcon && oldIcon.tagName === 'IMG' ? oldIcon : null);
  5049. this._setIconStyles(img, name);
  5050. return img;
  5051. },
  5052. _setIconStyles: function (img, name) {
  5053. var options = this.options;
  5054. var sizeOption = options[name + 'Size'];
  5055. if (typeof sizeOption === 'number') {
  5056. sizeOption = [sizeOption, sizeOption];
  5057. }
  5058. var size = L.point(sizeOption),
  5059. anchor = L.point(name === 'shadow' && options.shadowAnchor || options.iconAnchor ||
  5060. size && size.divideBy(2, true));
  5061. img.className = 'leaflet-marker-' + name + ' ' + (options.className || '');
  5062. if (anchor) {
  5063. img.style.marginLeft = (-anchor.x) + 'px';
  5064. img.style.marginTop = (-anchor.y) + 'px';
  5065. }
  5066. if (size) {
  5067. img.style.width = size.x + 'px';
  5068. img.style.height = size.y + 'px';
  5069. }
  5070. },
  5071. _createImg: function (src, el) {
  5072. el = el || document.createElement('img');
  5073. el.src = src;
  5074. return el;
  5075. },
  5076. _getIconUrl: function (name) {
  5077. return L.Browser.retina && this.options[name + 'RetinaUrl'] || this.options[name + 'Url'];
  5078. }
  5079. });
  5080. // @factory L.icon(options: Icon options)
  5081. // Creates an icon instance with the given options.
  5082. L.icon = function (options) {
  5083. return new L.Icon(options);
  5084. };
  5085. /*
  5086. * @miniclass Icon.Default (Icon)
  5087. * @aka L.Icon.Default
  5088. * @section
  5089. *
  5090. * A trivial subclass of `Icon`, represents the icon to use in `Marker`s when
  5091. * no icon is specified. Points to the blue marker image distributed with Leaflet
  5092. * releases.
  5093. *
  5094. * In order to customize the default icon, just change the properties of `L.Icon.Default.prototype.options`
  5095. * (which is a set of `Icon options`).
  5096. *
  5097. * If you want to _completely_ replace the default icon, override the
  5098. * `L.Marker.prototype.options.icon` with your own icon instead.
  5099. */
  5100. L.Icon.Default = L.Icon.extend({
  5101. options: {
  5102. iconUrl: 'marker-icon.png',
  5103. iconRetinaUrl: 'marker-icon-2x.png',
  5104. shadowUrl: 'marker-shadow.png',
  5105. iconSize: [25, 41],
  5106. iconAnchor: [12, 41],
  5107. popupAnchor: [1, -34],
  5108. tooltipAnchor: [16, -28],
  5109. shadowSize: [41, 41]
  5110. },
  5111. _getIconUrl: function (name) {
  5112. if (!L.Icon.Default.imagePath) { // Deprecated, backwards-compatibility only
  5113. L.Icon.Default.imagePath = this._detectIconPath();
  5114. }
  5115. // @option imagePath: String
  5116. // `L.Icon.Default` will try to auto-detect the absolute location of the
  5117. // blue icon images. If you are placing these images in a non-standard
  5118. // way, set this option to point to the right absolute path.
  5119. return (this.options.imagePath || L.Icon.Default.imagePath) + L.Icon.prototype._getIconUrl.call(this, name);
  5120. },
  5121. _detectIconPath: function () {
  5122. var el = L.DomUtil.create('div', 'leaflet-default-icon-path', document.body);
  5123. var path = L.DomUtil.getStyle(el, 'background-image') ||
  5124. L.DomUtil.getStyle(el, 'backgroundImage'); // IE8
  5125. document.body.removeChild(el);
  5126. return path.indexOf('url') === 0 ?
  5127. path.replace(/^url\([\"\']?/, '').replace(/marker-icon\.png[\"\']?\)$/, '') : '';
  5128. }
  5129. });
  5130. /*
  5131. * @class Marker
  5132. * @inherits Interactive layer
  5133. * @aka L.Marker
  5134. * L.Marker is used to display clickable/draggable icons on the map. Extends `Layer`.
  5135. *
  5136. * @example
  5137. *
  5138. * ```js
  5139. * L.marker([50.5, 30.5]).addTo(map);
  5140. * ```
  5141. */
  5142. L.Marker = L.Layer.extend({
  5143. // @section
  5144. // @aka Marker options
  5145. options: {
  5146. // @option icon: Icon = *
  5147. // Icon class to use for rendering the marker. See [Icon documentation](#L.Icon) for details on how to customize the marker icon. If not specified, a new `L.Icon.Default` is used.
  5148. icon: new L.Icon.Default(),
  5149. // Option inherited from "Interactive layer" abstract class
  5150. interactive: true,
  5151. // @option draggable: Boolean = false
  5152. // Whether the marker is draggable with mouse/touch or not.
  5153. draggable: false,
  5154. // @option keyboard: Boolean = true
  5155. // Whether the marker can be tabbed to with a keyboard and clicked by pressing enter.
  5156. keyboard: true,
  5157. // @option title: String = ''
  5158. // Text for the browser tooltip that appear on marker hover (no tooltip by default).
  5159. title: '',
  5160. // @option alt: String = ''
  5161. // Text for the `alt` attribute of the icon image (useful for accessibility).
  5162. alt: '',
  5163. // @option zIndexOffset: Number = 0
  5164. // By default, marker images zIndex is set automatically based on its latitude. Use this option if you want to put the marker on top of all others (or below), specifying a high value like `1000` (or high negative value, respectively).
  5165. zIndexOffset: 0,
  5166. // @option opacity: Number = 1.0
  5167. // The opacity of the marker.
  5168. opacity: 1,
  5169. // @option riseOnHover: Boolean = false
  5170. // If `true`, the marker will get on top of others when you hover the mouse over it.
  5171. riseOnHover: false,
  5172. // @option riseOffset: Number = 250
  5173. // The z-index offset used for the `riseOnHover` feature.
  5174. riseOffset: 250,
  5175. // @option pane: String = 'markerPane'
  5176. // `Map pane` where the markers icon will be added.
  5177. pane: 'markerPane',
  5178. // FIXME: shadowPane is no longer a valid option
  5179. nonBubblingEvents: ['click', 'dblclick', 'mouseover', 'mouseout', 'contextmenu']
  5180. },
  5181. /* @section
  5182. *
  5183. * In addition to [shared layer methods](#Layer) like `addTo()` and `remove()` and [popup methods](#Popup) like bindPopup() you can also use the following methods:
  5184. */
  5185. initialize: function (latlng, options) {
  5186. L.setOptions(this, options);
  5187. this._latlng = L.latLng(latlng);
  5188. },
  5189. onAdd: function (map) {
  5190. this._zoomAnimated = this._zoomAnimated && map.options.markerZoomAnimation;
  5191. if (this._zoomAnimated) {
  5192. map.on('zoomanim', this._animateZoom, this);
  5193. }
  5194. this._initIcon();
  5195. this.update();
  5196. },
  5197. onRemove: function (map) {
  5198. if (this.dragging && this.dragging.enabled()) {
  5199. this.options.draggable = true;
  5200. this.dragging.removeHooks();
  5201. }
  5202. if (this._zoomAnimated) {
  5203. map.off('zoomanim', this._animateZoom, this);
  5204. }
  5205. this._removeIcon();
  5206. this._removeShadow();
  5207. },
  5208. getEvents: function () {
  5209. return {
  5210. zoom: this.update,
  5211. viewreset: this.update
  5212. };
  5213. },
  5214. // @method getLatLng: LatLng
  5215. // Returns the current geographical position of the marker.
  5216. getLatLng: function () {
  5217. return this._latlng;
  5218. },
  5219. // @method setLatLng(latlng: LatLng): this
  5220. // Changes the marker position to the given point.
  5221. setLatLng: function (latlng) {
  5222. var oldLatLng = this._latlng;
  5223. this._latlng = L.latLng(latlng);
  5224. this.update();
  5225. // @event move: Event
  5226. // Fired when the marker is moved via [`setLatLng`](#marker-setlatlng) or by [dragging](#marker-dragging). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`.
  5227. return this.fire('move', {oldLatLng: oldLatLng, latlng: this._latlng});
  5228. },
  5229. // @method setZIndexOffset(offset: Number): this
  5230. // Changes the [zIndex offset](#marker-zindexoffset) of the marker.
  5231. setZIndexOffset: function (offset) {
  5232. this.options.zIndexOffset = offset;
  5233. return this.update();
  5234. },
  5235. // @method setIcon(icon: Icon): this
  5236. // Changes the marker icon.
  5237. setIcon: function (icon) {
  5238. this.options.icon = icon;
  5239. if (this._map) {
  5240. this._initIcon();
  5241. this.update();
  5242. }
  5243. if (this._popup) {
  5244. this.bindPopup(this._popup, this._popup.options);
  5245. }
  5246. return this;
  5247. },
  5248. getElement: function () {
  5249. return this._icon;
  5250. },
  5251. update: function () {
  5252. if (this._icon) {
  5253. var pos = this._map.latLngToLayerPoint(this._latlng).round();
  5254. this._setPos(pos);
  5255. }
  5256. return this;
  5257. },
  5258. _initIcon: function () {
  5259. var options = this.options,
  5260. classToAdd = 'leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
  5261. var icon = options.icon.createIcon(this._icon),
  5262. addIcon = false;
  5263. // if we're not reusing the icon, remove the old one and init new one
  5264. if (icon !== this._icon) {
  5265. if (this._icon) {
  5266. this._removeIcon();
  5267. }
  5268. addIcon = true;
  5269. if (options.title) {
  5270. icon.title = options.title;
  5271. }
  5272. if (options.alt) {
  5273. icon.alt = options.alt;
  5274. }
  5275. }
  5276. L.DomUtil.addClass(icon, classToAdd);
  5277. if (options.keyboard) {
  5278. icon.tabIndex = '0';
  5279. }
  5280. this._icon = icon;
  5281. if (options.riseOnHover) {
  5282. this.on({
  5283. mouseover: this._bringToFront,
  5284. mouseout: this._resetZIndex
  5285. });
  5286. }
  5287. var newShadow = options.icon.createShadow(this._shadow),
  5288. addShadow = false;
  5289. if (newShadow !== this._shadow) {
  5290. this._removeShadow();
  5291. addShadow = true;
  5292. }
  5293. if (newShadow) {
  5294. L.DomUtil.addClass(newShadow, classToAdd);
  5295. }
  5296. this._shadow = newShadow;
  5297. if (options.opacity < 1) {
  5298. this._updateOpacity();
  5299. }
  5300. if (addIcon) {
  5301. this.getPane().appendChild(this._icon);
  5302. }
  5303. this._initInteraction();
  5304. if (newShadow && addShadow) {
  5305. this.getPane('shadowPane').appendChild(this._shadow);
  5306. }
  5307. },
  5308. _removeIcon: function () {
  5309. if (this.options.riseOnHover) {
  5310. this.off({
  5311. mouseover: this._bringToFront,
  5312. mouseout: this._resetZIndex
  5313. });
  5314. }
  5315. L.DomUtil.remove(this._icon);
  5316. this.removeInteractiveTarget(this._icon);
  5317. this._icon = null;
  5318. },
  5319. _removeShadow: function () {
  5320. if (this._shadow) {
  5321. L.DomUtil.remove(this._shadow);
  5322. }
  5323. this._shadow = null;
  5324. },
  5325. _setPos: function (pos) {
  5326. L.DomUtil.setPosition(this._icon, pos);
  5327. if (this._shadow) {
  5328. L.DomUtil.setPosition(this._shadow, pos);
  5329. }
  5330. this._zIndex = pos.y + this.options.zIndexOffset;
  5331. this._resetZIndex();
  5332. },
  5333. _updateZIndex: function (offset) {
  5334. this._icon.style.zIndex = this._zIndex + offset;
  5335. },
  5336. _animateZoom: function (opt) {
  5337. var pos = this._map._latLngToNewLayerPoint(this._latlng, opt.zoom, opt.center).round();
  5338. this._setPos(pos);
  5339. },
  5340. _initInteraction: function () {
  5341. if (!this.options.interactive) { return; }
  5342. L.DomUtil.addClass(this._icon, 'leaflet-interactive');
  5343. this.addInteractiveTarget(this._icon);
  5344. if (L.Handler.MarkerDrag) {
  5345. var draggable = this.options.draggable;
  5346. if (this.dragging) {
  5347. draggable = this.dragging.enabled();
  5348. this.dragging.disable();
  5349. }
  5350. this.dragging = new L.Handler.MarkerDrag(this);
  5351. if (draggable) {
  5352. this.dragging.enable();
  5353. }
  5354. }
  5355. },
  5356. // @method setOpacity(opacity: Number): this
  5357. // Changes the opacity of the marker.
  5358. setOpacity: function (opacity) {
  5359. this.options.opacity = opacity;
  5360. if (this._map) {
  5361. this._updateOpacity();
  5362. }
  5363. return this;
  5364. },
  5365. _updateOpacity: function () {
  5366. var opacity = this.options.opacity;
  5367. L.DomUtil.setOpacity(this._icon, opacity);
  5368. if (this._shadow) {
  5369. L.DomUtil.setOpacity(this._shadow, opacity);
  5370. }
  5371. },
  5372. _bringToFront: function () {
  5373. this._updateZIndex(this.options.riseOffset);
  5374. },
  5375. _resetZIndex: function () {
  5376. this._updateZIndex(0);
  5377. },
  5378. _getPopupAnchor: function () {
  5379. return this.options.icon.options.popupAnchor || [0, 0];
  5380. },
  5381. _getTooltipAnchor: function () {
  5382. return this.options.icon.options.tooltipAnchor || [0, 0];
  5383. }
  5384. });
  5385. // factory L.marker(latlng: LatLng, options? : Marker options)
  5386. // @factory L.marker(latlng: LatLng, options? : Marker options)
  5387. // Instantiates a Marker object given a geographical point and optionally an options object.
  5388. L.marker = function (latlng, options) {
  5389. return new L.Marker(latlng, options);
  5390. };
  5391. /*
  5392. * @class DivIcon
  5393. * @aka L.DivIcon
  5394. * @inherits Icon
  5395. *
  5396. * Represents a lightweight icon for markers that uses a simple `<div>`
  5397. * element instead of an image. Inherits from `Icon` but ignores the `iconUrl` and shadow options.
  5398. *
  5399. * @example
  5400. * ```js
  5401. * var myIcon = L.divIcon({className: 'my-div-icon'});
  5402. * // you can set .my-div-icon styles in CSS
  5403. *
  5404. * L.marker([50.505, 30.57], {icon: myIcon}).addTo(map);
  5405. * ```
  5406. *
  5407. * By default, it has a 'leaflet-div-icon' CSS class and is styled as a little white square with a shadow.
  5408. */
  5409. L.DivIcon = L.Icon.extend({
  5410. options: {
  5411. // @section
  5412. // @aka DivIcon options
  5413. iconSize: [12, 12], // also can be set through CSS
  5414. // iconAnchor: (Point),
  5415. // popupAnchor: (Point),
  5416. // @option html: String = ''
  5417. // Custom HTML code to put inside the div element, empty by default.
  5418. html: false,
  5419. // @option bgPos: Point = [0, 0]
  5420. // Optional relative position of the background, in pixels
  5421. bgPos: null,
  5422. className: 'leaflet-div-icon'
  5423. },
  5424. createIcon: function (oldIcon) {
  5425. var div = (oldIcon && oldIcon.tagName === 'DIV') ? oldIcon : document.createElement('div'),
  5426. options = this.options;
  5427. div.innerHTML = options.html !== false ? options.html : '';
  5428. if (options.bgPos) {
  5429. var bgPos = L.point(options.bgPos);
  5430. div.style.backgroundPosition = (-bgPos.x) + 'px ' + (-bgPos.y) + 'px';
  5431. }
  5432. this._setIconStyles(div, 'icon');
  5433. return div;
  5434. },
  5435. createShadow: function () {
  5436. return null;
  5437. }
  5438. });
  5439. // @factory L.divIcon(options: DivIcon options)
  5440. // Creates a `DivIcon` instance with the given options.
  5441. L.divIcon = function (options) {
  5442. return new L.DivIcon(options);
  5443. };
  5444. /*
  5445. * @class DivOverlay
  5446. * @inherits Layer
  5447. * @aka L.DivOverlay
  5448. * Base model for L.Popup and L.Tooltip. Inherit from it for custom popup like plugins.
  5449. */
  5450. // @namespace DivOverlay
  5451. L.DivOverlay = L.Layer.extend({
  5452. // @section
  5453. // @aka DivOverlay options
  5454. options: {
  5455. // @option offset: Point = Point(0, 7)
  5456. // The offset of the popup position. Useful to control the anchor
  5457. // of the popup when opening it on some overlays.
  5458. offset: [0, 7],
  5459. // @option className: String = ''
  5460. // A custom CSS class name to assign to the popup.
  5461. className: '',
  5462. // @option pane: String = 'popupPane'
  5463. // `Map pane` where the popup will be added.
  5464. pane: 'popupPane'
  5465. },
  5466. initialize: function (options, source) {
  5467. L.setOptions(this, options);
  5468. this._source = source;
  5469. },
  5470. onAdd: function (map) {
  5471. this._zoomAnimated = map._zoomAnimated;
  5472. if (!this._container) {
  5473. this._initLayout();
  5474. }
  5475. if (map._fadeAnimated) {
  5476. L.DomUtil.setOpacity(this._container, 0);
  5477. }
  5478. clearTimeout(this._removeTimeout);
  5479. this.getPane().appendChild(this._container);
  5480. this.update();
  5481. if (map._fadeAnimated) {
  5482. L.DomUtil.setOpacity(this._container, 1);
  5483. }
  5484. this.bringToFront();
  5485. },
  5486. onRemove: function (map) {
  5487. if (map._fadeAnimated) {
  5488. L.DomUtil.setOpacity(this._container, 0);
  5489. this._removeTimeout = setTimeout(L.bind(L.DomUtil.remove, L.DomUtil, this._container), 200);
  5490. } else {
  5491. L.DomUtil.remove(this._container);
  5492. }
  5493. },
  5494. // @namespace Popup
  5495. // @method getLatLng: LatLng
  5496. // Returns the geographical point of popup.
  5497. getLatLng: function () {
  5498. return this._latlng;
  5499. },
  5500. // @method setLatLng(latlng: LatLng): this
  5501. // Sets the geographical point where the popup will open.
  5502. setLatLng: function (latlng) {
  5503. this._latlng = L.latLng(latlng);
  5504. if (this._map) {
  5505. this._updatePosition();
  5506. this._adjustPan();
  5507. }
  5508. return this;
  5509. },
  5510. // @method getContent: String|HTMLElement
  5511. // Returns the content of the popup.
  5512. getContent: function () {
  5513. return this._content;
  5514. },
  5515. // @method setContent(htmlContent: String|HTMLElement|Function): this
  5516. // Sets the HTML content of the popup. If a function is passed the source layer will be passed to the function. The function should return a `String` or `HTMLElement` to be used in the popup.
  5517. setContent: function (content) {
  5518. this._content = content;
  5519. this.update();
  5520. return this;
  5521. },
  5522. // @method getElement: String|HTMLElement
  5523. // Alias for [getContent()](#popup-getcontent)
  5524. getElement: function () {
  5525. return this._container;
  5526. },
  5527. // @method update: null
  5528. // Updates the popup content, layout and position. Useful for updating the popup after something inside changed, e.g. image loaded.
  5529. update: function () {
  5530. if (!this._map) { return; }
  5531. this._container.style.visibility = 'hidden';
  5532. this._updateContent();
  5533. this._updateLayout();
  5534. this._updatePosition();
  5535. this._container.style.visibility = '';
  5536. this._adjustPan();
  5537. },
  5538. getEvents: function () {
  5539. var events = {
  5540. zoom: this._updatePosition,
  5541. viewreset: this._updatePosition
  5542. };
  5543. if (this._zoomAnimated) {
  5544. events.zoomanim = this._animateZoom;
  5545. }
  5546. return events;
  5547. },
  5548. // @method isOpen: Boolean
  5549. // Returns `true` when the popup is visible on the map.
  5550. isOpen: function () {
  5551. return !!this._map && this._map.hasLayer(this);
  5552. },
  5553. // @method bringToFront: this
  5554. // Brings this popup in front of other popups (in the same map pane).
  5555. bringToFront: function () {
  5556. if (this._map) {
  5557. L.DomUtil.toFront(this._container);
  5558. }
  5559. return this;
  5560. },
  5561. // @method bringToBack: this
  5562. // Brings this popup to the back of other popups (in the same map pane).
  5563. bringToBack: function () {
  5564. if (this._map) {
  5565. L.DomUtil.toBack(this._container);
  5566. }
  5567. return this;
  5568. },
  5569. _updateContent: function () {
  5570. if (!this._content) { return; }
  5571. var node = this._contentNode;
  5572. var content = (typeof this._content === 'function') ? this._content(this._source || this) : this._content;
  5573. if (typeof content === 'string') {
  5574. node.innerHTML = content;
  5575. } else {
  5576. while (node.hasChildNodes()) {
  5577. node.removeChild(node.firstChild);
  5578. }
  5579. node.appendChild(content);
  5580. }
  5581. this.fire('contentupdate');
  5582. },
  5583. _updatePosition: function () {
  5584. if (!this._map) { return; }
  5585. var pos = this._map.latLngToLayerPoint(this._latlng),
  5586. offset = L.point(this.options.offset),
  5587. anchor = this._getAnchor();
  5588. if (this._zoomAnimated) {
  5589. L.DomUtil.setPosition(this._container, pos.add(anchor));
  5590. } else {
  5591. offset = offset.add(pos).add(anchor);
  5592. }
  5593. var bottom = this._containerBottom = -offset.y,
  5594. left = this._containerLeft = -Math.round(this._containerWidth / 2) + offset.x;
  5595. // bottom position the popup in case the height of the popup changes (images loading etc)
  5596. this._container.style.bottom = bottom + 'px';
  5597. this._container.style.left = left + 'px';
  5598. },
  5599. _getAnchor: function () {
  5600. return [0, 0];
  5601. }
  5602. });
  5603. /*
  5604. * @class Popup
  5605. * @inherits DivOverlay
  5606. * @aka L.Popup
  5607. * Used to open popups in certain places of the map. Use [Map.openPopup](#map-openpopup) to
  5608. * open popups while making sure that only one popup is open at one time
  5609. * (recommended for usability), or use [Map.addLayer](#map-addlayer) to open as many as you want.
  5610. *
  5611. * @example
  5612. *
  5613. * If you want to just bind a popup to marker click and then open it, it's really easy:
  5614. *
  5615. * ```js
  5616. * marker.bindPopup(popupContent).openPopup();
  5617. * ```
  5618. * Path overlays like polylines also have a `bindPopup` method.
  5619. * Here's a more complicated way to open a popup on a map:
  5620. *
  5621. * ```js
  5622. * var popup = L.popup()
  5623. * .setLatLng(latlng)
  5624. * .setContent('<p>Hello world!<br />This is a nice popup.</p>')
  5625. * .openOn(map);
  5626. * ```
  5627. */
  5628. // @namespace Popup
  5629. L.Popup = L.DivOverlay.extend({
  5630. // @section
  5631. // @aka Popup options
  5632. options: {
  5633. // @option maxWidth: Number = 300
  5634. // Max width of the popup, in pixels.
  5635. maxWidth: 300,
  5636. // @option minWidth: Number = 50
  5637. // Min width of the popup, in pixels.
  5638. minWidth: 50,
  5639. // @option maxHeight: Number = null
  5640. // If set, creates a scrollable container of the given height
  5641. // inside a popup if its content exceeds it.
  5642. maxHeight: null,
  5643. // @option autoPan: Boolean = true
  5644. // Set it to `false` if you don't want the map to do panning animation
  5645. // to fit the opened popup.
  5646. autoPan: true,
  5647. // @option autoPanPaddingTopLeft: Point = null
  5648. // The margin between the popup and the top left corner of the map
  5649. // view after autopanning was performed.
  5650. autoPanPaddingTopLeft: null,
  5651. // @option autoPanPaddingBottomRight: Point = null
  5652. // The margin between the popup and the bottom right corner of the map
  5653. // view after autopanning was performed.
  5654. autoPanPaddingBottomRight: null,
  5655. // @option autoPanPadding: Point = Point(5, 5)
  5656. // Equivalent of setting both top left and bottom right autopan padding to the same value.
  5657. autoPanPadding: [5, 5],
  5658. // @option keepInView: Boolean = false
  5659. // Set it to `true` if you want to prevent users from panning the popup
  5660. // off of the screen while it is open.
  5661. keepInView: false,
  5662. // @option closeButton: Boolean = true
  5663. // Controls the presence of a close button in the popup.
  5664. closeButton: true,
  5665. // @option autoClose: Boolean = true
  5666. // Set it to `false` if you want to override the default behavior of
  5667. // the popup closing when user clicks the map (set globally by
  5668. // the Map's [closePopupOnClick](#map-closepopuponclick) option).
  5669. autoClose: true,
  5670. // @option className: String = ''
  5671. // A custom CSS class name to assign to the popup.
  5672. className: ''
  5673. },
  5674. // @namespace Popup
  5675. // @method openOn(map: Map): this
  5676. // Adds the popup to the map and closes the previous one. The same as `map.openPopup(popup)`.
  5677. openOn: function (map) {
  5678. map.openPopup(this);
  5679. return this;
  5680. },
  5681. onAdd: function (map) {
  5682. L.DivOverlay.prototype.onAdd.call(this, map);
  5683. // @namespace Map
  5684. // @section Popup events
  5685. // @event popupopen: PopupEvent
  5686. // Fired when a popup is opened in the map
  5687. map.fire('popupopen', {popup: this});
  5688. if (this._source) {
  5689. // @namespace Layer
  5690. // @section Popup events
  5691. // @event popupopen: PopupEvent
  5692. // Fired when a popup bound to this layer is opened
  5693. this._source.fire('popupopen', {popup: this}, true);
  5694. // For non-path layers, we toggle the popup when clicking
  5695. // again the layer, so prevent the map to reopen it.
  5696. if (!(this._source instanceof L.Path)) {
  5697. this._source.on('preclick', L.DomEvent.stopPropagation);
  5698. }
  5699. }
  5700. },
  5701. onRemove: function (map) {
  5702. L.DivOverlay.prototype.onRemove.call(this, map);
  5703. // @namespace Map
  5704. // @section Popup events
  5705. // @event popupclose: PopupEvent
  5706. // Fired when a popup in the map is closed
  5707. map.fire('popupclose', {popup: this});
  5708. if (this._source) {
  5709. // @namespace Layer
  5710. // @section Popup events
  5711. // @event popupclose: PopupEvent
  5712. // Fired when a popup bound to this layer is closed
  5713. this._source.fire('popupclose', {popup: this}, true);
  5714. if (!(this._source instanceof L.Path)) {
  5715. this._source.off('preclick', L.DomEvent.stopPropagation);
  5716. }
  5717. }
  5718. },
  5719. getEvents: function () {
  5720. var events = L.DivOverlay.prototype.getEvents.call(this);
  5721. if ('closeOnClick' in this.options ? this.options.closeOnClick : this._map.options.closePopupOnClick) {
  5722. events.preclick = this._close;
  5723. }
  5724. if (this.options.keepInView) {
  5725. events.moveend = this._adjustPan;
  5726. }
  5727. return events;
  5728. },
  5729. _close: function () {
  5730. if (this._map) {
  5731. this._map.closePopup(this);
  5732. }
  5733. },
  5734. _initLayout: function () {
  5735. var prefix = 'leaflet-popup',
  5736. container = this._container = L.DomUtil.create('div',
  5737. prefix + ' ' + (this.options.className || '') +
  5738. ' leaflet-zoom-animated');
  5739. if (this.options.closeButton) {
  5740. var closeButton = this._closeButton = L.DomUtil.create('a', prefix + '-close-button', container);
  5741. closeButton.href = '#close';
  5742. closeButton.innerHTML = '&#215;';
  5743. L.DomEvent.on(closeButton, 'click', this._onCloseButtonClick, this);
  5744. }
  5745. var wrapper = this._wrapper = L.DomUtil.create('div', prefix + '-content-wrapper', container);
  5746. this._contentNode = L.DomUtil.create('div', prefix + '-content', wrapper);
  5747. L.DomEvent
  5748. .disableClickPropagation(wrapper)
  5749. .disableScrollPropagation(this._contentNode)
  5750. .on(wrapper, 'contextmenu', L.DomEvent.stopPropagation);
  5751. this._tipContainer = L.DomUtil.create('div', prefix + '-tip-container', container);
  5752. this._tip = L.DomUtil.create('div', prefix + '-tip', this._tipContainer);
  5753. },
  5754. _updateLayout: function () {
  5755. var container = this._contentNode,
  5756. style = container.style;
  5757. style.width = '';
  5758. style.whiteSpace = 'nowrap';
  5759. var width = container.offsetWidth;
  5760. width = Math.min(width, this.options.maxWidth);
  5761. width = Math.max(width, this.options.minWidth);
  5762. style.width = (width + 1) + 'px';
  5763. style.whiteSpace = '';
  5764. style.height = '';
  5765. var height = container.offsetHeight,
  5766. maxHeight = this.options.maxHeight,
  5767. scrolledClass = 'leaflet-popup-scrolled';
  5768. if (maxHeight && height > maxHeight) {
  5769. style.height = maxHeight + 'px';
  5770. L.DomUtil.addClass(container, scrolledClass);
  5771. } else {
  5772. L.DomUtil.removeClass(container, scrolledClass);
  5773. }
  5774. this._containerWidth = this._container.offsetWidth;
  5775. },
  5776. _animateZoom: function (e) {
  5777. var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center),
  5778. anchor = this._getAnchor();
  5779. L.DomUtil.setPosition(this._container, pos.add(anchor));
  5780. },
  5781. _adjustPan: function () {
  5782. if (!this.options.autoPan || (this._map._panAnim && this._map._panAnim._inProgress)) { return; }
  5783. var map = this._map,
  5784. marginBottom = parseInt(L.DomUtil.getStyle(this._container, 'marginBottom'), 10) || 0,
  5785. containerHeight = this._container.offsetHeight + marginBottom,
  5786. containerWidth = this._containerWidth,
  5787. layerPos = new L.Point(this._containerLeft, -containerHeight - this._containerBottom);
  5788. layerPos._add(L.DomUtil.getPosition(this._container));
  5789. var containerPos = map.layerPointToContainerPoint(layerPos),
  5790. padding = L.point(this.options.autoPanPadding),
  5791. paddingTL = L.point(this.options.autoPanPaddingTopLeft || padding),
  5792. paddingBR = L.point(this.options.autoPanPaddingBottomRight || padding),
  5793. size = map.getSize(),
  5794. dx = 0,
  5795. dy = 0;
  5796. if (containerPos.x + containerWidth + paddingBR.x > size.x) { // right
  5797. dx = containerPos.x + containerWidth - size.x + paddingBR.x;
  5798. }
  5799. if (containerPos.x - dx - paddingTL.x < 0) { // left
  5800. dx = containerPos.x - paddingTL.x;
  5801. }
  5802. if (containerPos.y + containerHeight + paddingBR.y > size.y) { // bottom
  5803. dy = containerPos.y + containerHeight - size.y + paddingBR.y;
  5804. }
  5805. if (containerPos.y - dy - paddingTL.y < 0) { // top
  5806. dy = containerPos.y - paddingTL.y;
  5807. }
  5808. // @namespace Map
  5809. // @section Popup events
  5810. // @event autopanstart: Event
  5811. // Fired when the map starts autopanning when opening a popup.
  5812. if (dx || dy) {
  5813. map
  5814. .fire('autopanstart')
  5815. .panBy([dx, dy]);
  5816. }
  5817. },
  5818. _onCloseButtonClick: function (e) {
  5819. this._close();
  5820. L.DomEvent.stop(e);
  5821. },
  5822. _getAnchor: function () {
  5823. // Where should we anchor the popup on the source layer?
  5824. return L.point(this._source && this._source._getPopupAnchor ? this._source._getPopupAnchor() : [0, 0]);
  5825. }
  5826. });
  5827. // @namespace Popup
  5828. // @factory L.popup(options?: Popup options, source?: Layer)
  5829. // Instantiates a `Popup` object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the popup with a reference to the Layer to which it refers.
  5830. L.popup = function (options, source) {
  5831. return new L.Popup(options, source);
  5832. };
  5833. /* @namespace Map
  5834. * @section Interaction Options
  5835. * @option closePopupOnClick: Boolean = true
  5836. * Set it to `false` if you don't want popups to close when user clicks the map.
  5837. */
  5838. L.Map.mergeOptions({
  5839. closePopupOnClick: true
  5840. });
  5841. // @namespace Map
  5842. // @section Methods for Layers and Controls
  5843. L.Map.include({
  5844. // @method openPopup(popup: Popup): this
  5845. // Opens the specified popup while closing the previously opened (to make sure only one is opened at one time for usability).
  5846. // @alternative
  5847. // @method openPopup(content: String|HTMLElement, latlng: LatLng, options?: Popup options): this
  5848. // Creates a popup with the specified content and options and opens it in the given point on a map.
  5849. openPopup: function (popup, latlng, options) {
  5850. if (!(popup instanceof L.Popup)) {
  5851. popup = new L.Popup(options).setContent(popup);
  5852. }
  5853. if (latlng) {
  5854. popup.setLatLng(latlng);
  5855. }
  5856. if (this.hasLayer(popup)) {
  5857. return this;
  5858. }
  5859. if (this._popup && this._popup.options.autoClose) {
  5860. this.closePopup();
  5861. }
  5862. this._popup = popup;
  5863. return this.addLayer(popup);
  5864. },
  5865. // @method closePopup(popup?: Popup): this
  5866. // Closes the popup previously opened with [openPopup](#map-openpopup) (or the given one).
  5867. closePopup: function (popup) {
  5868. if (!popup || popup === this._popup) {
  5869. popup = this._popup;
  5870. this._popup = null;
  5871. }
  5872. if (popup) {
  5873. this.removeLayer(popup);
  5874. }
  5875. return this;
  5876. }
  5877. });
  5878. /*
  5879. * @namespace Layer
  5880. * @section Popup methods example
  5881. *
  5882. * All layers share a set of methods convenient for binding popups to it.
  5883. *
  5884. * ```js
  5885. * var layer = L.Polygon(latlngs).bindPopup('Hi There!').addTo(map);
  5886. * layer.openPopup();
  5887. * layer.closePopup();
  5888. * ```
  5889. *
  5890. * Popups will also be automatically opened when the layer is clicked on and closed when the layer is removed from the map or another popup is opened.
  5891. */
  5892. // @section Popup methods
  5893. L.Layer.include({
  5894. // @method bindPopup(content: String|HTMLElement|Function|Popup, options?: Popup options): this
  5895. // Binds a popup to the layer with the passed `content` and sets up the
  5896. // neccessary event listeners. If a `Function` is passed it will receive
  5897. // the layer as the first argument and should return a `String` or `HTMLElement`.
  5898. bindPopup: function (content, options) {
  5899. if (content instanceof L.Popup) {
  5900. L.setOptions(content, options);
  5901. this._popup = content;
  5902. content._source = this;
  5903. } else {
  5904. if (!this._popup || options) {
  5905. this._popup = new L.Popup(options, this);
  5906. }
  5907. this._popup.setContent(content);
  5908. }
  5909. if (!this._popupHandlersAdded) {
  5910. this.on({
  5911. click: this._openPopup,
  5912. remove: this.closePopup,
  5913. move: this._movePopup
  5914. });
  5915. this._popupHandlersAdded = true;
  5916. }
  5917. return this;
  5918. },
  5919. // @method unbindPopup(): this
  5920. // Removes the popup previously bound with `bindPopup`.
  5921. unbindPopup: function () {
  5922. if (this._popup) {
  5923. this.off({
  5924. click: this._openPopup,
  5925. remove: this.closePopup,
  5926. move: this._movePopup
  5927. });
  5928. this._popupHandlersAdded = false;
  5929. this._popup = null;
  5930. }
  5931. return this;
  5932. },
  5933. // @method openPopup(latlng?: LatLng): this
  5934. // Opens the bound popup at the specificed `latlng` or at the default popup anchor if no `latlng` is passed.
  5935. openPopup: function (layer, latlng) {
  5936. if (!(layer instanceof L.Layer)) {
  5937. latlng = layer;
  5938. layer = this;
  5939. }
  5940. if (layer instanceof L.FeatureGroup) {
  5941. for (var id in this._layers) {
  5942. layer = this._layers[id];
  5943. break;
  5944. }
  5945. }
  5946. if (!latlng) {
  5947. latlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();
  5948. }
  5949. if (this._popup && this._map) {
  5950. // set popup source to this layer
  5951. this._popup._source = layer;
  5952. // update the popup (content, layout, ect...)
  5953. this._popup.update();
  5954. // open the popup on the map
  5955. this._map.openPopup(this._popup, latlng);
  5956. }
  5957. return this;
  5958. },
  5959. // @method closePopup(): this
  5960. // Closes the popup bound to this layer if it is open.
  5961. closePopup: function () {
  5962. if (this._popup) {
  5963. this._popup._close();
  5964. }
  5965. return this;
  5966. },
  5967. // @method togglePopup(): this
  5968. // Opens or closes the popup bound to this layer depending on its current state.
  5969. togglePopup: function (target) {
  5970. if (this._popup) {
  5971. if (this._popup._map) {
  5972. this.closePopup();
  5973. } else {
  5974. this.openPopup(target);
  5975. }
  5976. }
  5977. return this;
  5978. },
  5979. // @method isPopupOpen(): boolean
  5980. // Returns `true` if the popup bound to this layer is currently open.
  5981. isPopupOpen: function () {
  5982. return this._popup.isOpen();
  5983. },
  5984. // @method setPopupContent(content: String|HTMLElement|Popup): this
  5985. // Sets the content of the popup bound to this layer.
  5986. setPopupContent: function (content) {
  5987. if (this._popup) {
  5988. this._popup.setContent(content);
  5989. }
  5990. return this;
  5991. },
  5992. // @method getPopup(): Popup
  5993. // Returns the popup bound to this layer.
  5994. getPopup: function () {
  5995. return this._popup;
  5996. },
  5997. _openPopup: function (e) {
  5998. var layer = e.layer || e.target;
  5999. if (!this._popup) {
  6000. return;
  6001. }
  6002. if (!this._map) {
  6003. return;
  6004. }
  6005. // prevent map click
  6006. L.DomEvent.stop(e);
  6007. // if this inherits from Path its a vector and we can just
  6008. // open the popup at the new location
  6009. if (layer instanceof L.Path) {
  6010. this.openPopup(e.layer || e.target, e.latlng);
  6011. return;
  6012. }
  6013. // otherwise treat it like a marker and figure out
  6014. // if we should toggle it open/closed
  6015. if (this._map.hasLayer(this._popup) && this._popup._source === layer) {
  6016. this.closePopup();
  6017. } else {
  6018. this.openPopup(layer, e.latlng);
  6019. }
  6020. },
  6021. _movePopup: function (e) {
  6022. this._popup.setLatLng(e.latlng);
  6023. }
  6024. });
  6025. /*
  6026. * @class Tooltip
  6027. * @inherits DivOverlay
  6028. * @aka L.Tooltip
  6029. * Used to display small texts on top of map layers.
  6030. *
  6031. * @example
  6032. *
  6033. * ```js
  6034. * marker.bindTooltip("my tooltip text").openTooltip();
  6035. * ```
  6036. * Note about tooltip offset. Leaflet takes two options in consideration
  6037. * for computing tooltip offseting:
  6038. * - the `offset` Tooltip option: it defaults to [0, 0], and it's specific to one tooltip.
  6039. * Add a positive x offset to move the tooltip to the right, and a positive y offset to
  6040. * move it to the bottom. Negatives will move to the left and top.
  6041. * - the `tooltipAnchor` Icon option: this will only be considered for Marker. You
  6042. * should adapt this value if you use a custom icon.
  6043. */
  6044. // @namespace Tooltip
  6045. L.Tooltip = L.DivOverlay.extend({
  6046. // @section
  6047. // @aka Tooltip options
  6048. options: {
  6049. // @option pane: String = 'tooltipPane'
  6050. // `Map pane` where the tooltip will be added.
  6051. pane: 'tooltipPane',
  6052. // @option offset: Point = Point(0, 0)
  6053. // Optional offset of the tooltip position.
  6054. offset: [0, 0],
  6055. // @option direction: String = 'auto'
  6056. // Direction where to open the tooltip. Possible values are: `right`, `left`,
  6057. // `top`, `bottom`, `center`, `auto`.
  6058. // `auto` will dynamicaly switch between `right` and `left` according to the tooltip
  6059. // position on the map.
  6060. direction: 'auto',
  6061. // @option permanent: Boolean = false
  6062. // Whether to open the tooltip permanently or only on mouseover.
  6063. permanent: false,
  6064. // @option sticky: Boolean = false
  6065. // If true, the tooltip will follow the mouse instead of being fixed at the feature center.
  6066. sticky: false,
  6067. // @option interactive: Boolean = false
  6068. // If true, the tooltip will listen to the feature events.
  6069. interactive: false,
  6070. // @option opacity: Number = 0.9
  6071. // Tooltip container opacity.
  6072. opacity: 0.9
  6073. },
  6074. onAdd: function (map) {
  6075. L.DivOverlay.prototype.onAdd.call(this, map);
  6076. this.setOpacity(this.options.opacity);
  6077. // @namespace Map
  6078. // @section Tooltip events
  6079. // @event tooltipopen: TooltipEvent
  6080. // Fired when a tooltip is opened in the map.
  6081. map.fire('tooltipopen', {tooltip: this});
  6082. if (this._source) {
  6083. // @namespace Layer
  6084. // @section Tooltip events
  6085. // @event tooltipopen: TooltipEvent
  6086. // Fired when a tooltip bound to this layer is opened.
  6087. this._source.fire('tooltipopen', {tooltip: this}, true);
  6088. }
  6089. },
  6090. onRemove: function (map) {
  6091. L.DivOverlay.prototype.onRemove.call(this, map);
  6092. // @namespace Map
  6093. // @section Tooltip events
  6094. // @event tooltipclose: TooltipEvent
  6095. // Fired when a tooltip in the map is closed.
  6096. map.fire('tooltipclose', {tooltip: this});
  6097. if (this._source) {
  6098. // @namespace Layer
  6099. // @section Tooltip events
  6100. // @event tooltipclose: TooltipEvent
  6101. // Fired when a tooltip bound to this layer is closed.
  6102. this._source.fire('tooltipclose', {tooltip: this}, true);
  6103. }
  6104. },
  6105. getEvents: function () {
  6106. var events = L.DivOverlay.prototype.getEvents.call(this);
  6107. if (L.Browser.touch && !this.options.permanent) {
  6108. events.preclick = this._close;
  6109. }
  6110. return events;
  6111. },
  6112. _close: function () {
  6113. if (this._map) {
  6114. this._map.closeTooltip(this);
  6115. }
  6116. },
  6117. _initLayout: function () {
  6118. var prefix = 'leaflet-tooltip',
  6119. className = prefix + ' ' + (this.options.className || '') + ' leaflet-zoom-' + (this._zoomAnimated ? 'animated' : 'hide');
  6120. this._contentNode = this._container = L.DomUtil.create('div', className);
  6121. },
  6122. _updateLayout: function () {},
  6123. _adjustPan: function () {},
  6124. _setPosition: function (pos) {
  6125. var map = this._map,
  6126. container = this._container,
  6127. centerPoint = map.latLngToContainerPoint(map.getCenter()),
  6128. tooltipPoint = map.layerPointToContainerPoint(pos),
  6129. direction = this.options.direction,
  6130. tooltipWidth = container.offsetWidth,
  6131. tooltipHeight = container.offsetHeight,
  6132. offset = L.point(this.options.offset),
  6133. anchor = this._getAnchor();
  6134. if (direction === 'top') {
  6135. pos = pos.add(L.point(-tooltipWidth / 2 + offset.x, -tooltipHeight + offset.y + anchor.y, true));
  6136. } else if (direction === 'bottom') {
  6137. pos = pos.subtract(L.point(tooltipWidth / 2 - offset.x, -offset.y, true));
  6138. } else if (direction === 'center') {
  6139. pos = pos.subtract(L.point(tooltipWidth / 2 + offset.x, tooltipHeight / 2 - anchor.y + offset.y, true));
  6140. } else if (direction === 'right' || direction === 'auto' && tooltipPoint.x < centerPoint.x) {
  6141. direction = 'right';
  6142. pos = pos.add(L.point(offset.x + anchor.x, anchor.y - tooltipHeight / 2 + offset.y, true));
  6143. } else {
  6144. direction = 'left';
  6145. pos = pos.subtract(L.point(tooltipWidth + anchor.x - offset.x, tooltipHeight / 2 - anchor.y - offset.y, true));
  6146. }
  6147. L.DomUtil.removeClass(container, 'leaflet-tooltip-right');
  6148. L.DomUtil.removeClass(container, 'leaflet-tooltip-left');
  6149. L.DomUtil.removeClass(container, 'leaflet-tooltip-top');
  6150. L.DomUtil.removeClass(container, 'leaflet-tooltip-bottom');
  6151. L.DomUtil.addClass(container, 'leaflet-tooltip-' + direction);
  6152. L.DomUtil.setPosition(container, pos);
  6153. },
  6154. _updatePosition: function () {
  6155. var pos = this._map.latLngToLayerPoint(this._latlng);
  6156. this._setPosition(pos);
  6157. },
  6158. setOpacity: function (opacity) {
  6159. this.options.opacity = opacity;
  6160. if (this._container) {
  6161. L.DomUtil.setOpacity(this._container, opacity);
  6162. }
  6163. },
  6164. _animateZoom: function (e) {
  6165. var pos = this._map._latLngToNewLayerPoint(this._latlng, e.zoom, e.center);
  6166. this._setPosition(pos);
  6167. },
  6168. _getAnchor: function () {
  6169. // Where should we anchor the tooltip on the source layer?
  6170. return L.point(this._source && this._source._getTooltipAnchor && !this.options.sticky ? this._source._getTooltipAnchor() : [0, 0]);
  6171. }
  6172. });
  6173. // @namespace Tooltip
  6174. // @factory L.tooltip(options?: Tooltip options, source?: Layer)
  6175. // Instantiates a Tooltip object given an optional `options` object that describes its appearance and location and an optional `source` object that is used to tag the tooltip with a reference to the Layer to which it refers.
  6176. L.tooltip = function (options, source) {
  6177. return new L.Tooltip(options, source);
  6178. };
  6179. // @namespace Map
  6180. // @section Methods for Layers and Controls
  6181. L.Map.include({
  6182. // @method openTooltip(tooltip: Tooltip): this
  6183. // Opens the specified tooltip.
  6184. // @alternative
  6185. // @method openTooltip(content: String|HTMLElement, latlng: LatLng, options?: Tooltip options): this
  6186. // Creates a tooltip with the specified content and options and open it.
  6187. openTooltip: function (tooltip, latlng, options) {
  6188. if (!(tooltip instanceof L.Tooltip)) {
  6189. tooltip = new L.Tooltip(options).setContent(tooltip);
  6190. }
  6191. if (latlng) {
  6192. tooltip.setLatLng(latlng);
  6193. }
  6194. if (this.hasLayer(tooltip)) {
  6195. return this;
  6196. }
  6197. return this.addLayer(tooltip);
  6198. },
  6199. // @method closeTooltip(tooltip?: Tooltip): this
  6200. // Closes the tooltip given as parameter.
  6201. closeTooltip: function (tooltip) {
  6202. if (tooltip) {
  6203. this.removeLayer(tooltip);
  6204. }
  6205. return this;
  6206. }
  6207. });
  6208. /*
  6209. * @namespace Layer
  6210. * @section Tooltip methods example
  6211. *
  6212. * All layers share a set of methods convenient for binding tooltips to it.
  6213. *
  6214. * ```js
  6215. * var layer = L.Polygon(latlngs).bindTooltip('Hi There!').addTo(map);
  6216. * layer.openTooltip();
  6217. * layer.closeTooltip();
  6218. * ```
  6219. */
  6220. // @section Tooltip methods
  6221. L.Layer.include({
  6222. // @method bindTooltip(content: String|HTMLElement|Function|Tooltip, options?: Tooltip options): this
  6223. // Binds a tooltip to the layer with the passed `content` and sets up the
  6224. // neccessary event listeners. If a `Function` is passed it will receive
  6225. // the layer as the first argument and should return a `String` or `HTMLElement`.
  6226. bindTooltip: function (content, options) {
  6227. if (content instanceof L.Tooltip) {
  6228. L.setOptions(content, options);
  6229. this._tooltip = content;
  6230. content._source = this;
  6231. } else {
  6232. if (!this._tooltip || options) {
  6233. this._tooltip = L.tooltip(options, this);
  6234. }
  6235. this._tooltip.setContent(content);
  6236. }
  6237. this._initTooltipInteractions();
  6238. if (this._tooltip.options.permanent && this._map && this._map.hasLayer(this)) {
  6239. this.openTooltip();
  6240. }
  6241. return this;
  6242. },
  6243. // @method unbindTooltip(): this
  6244. // Removes the tooltip previously bound with `bindTooltip`.
  6245. unbindTooltip: function () {
  6246. if (this._tooltip) {
  6247. this._initTooltipInteractions(true);
  6248. this.closeTooltip();
  6249. this._tooltip = null;
  6250. }
  6251. return this;
  6252. },
  6253. _initTooltipInteractions: function (remove) {
  6254. if (!remove && this._tooltipHandlersAdded) { return; }
  6255. var onOff = remove ? 'off' : 'on',
  6256. events = {
  6257. remove: this.closeTooltip,
  6258. move: this._moveTooltip
  6259. };
  6260. if (!this._tooltip.options.permanent) {
  6261. events.mouseover = this._openTooltip;
  6262. events.mouseout = this.closeTooltip;
  6263. if (this._tooltip.options.sticky) {
  6264. events.mousemove = this._moveTooltip;
  6265. }
  6266. if (L.Browser.touch) {
  6267. events.click = this._openTooltip;
  6268. }
  6269. } else {
  6270. events.add = this._openTooltip;
  6271. }
  6272. this[onOff](events);
  6273. this._tooltipHandlersAdded = !remove;
  6274. },
  6275. // @method openTooltip(latlng?: LatLng): this
  6276. // Opens the bound tooltip at the specificed `latlng` or at the default tooltip anchor if no `latlng` is passed.
  6277. openTooltip: function (layer, latlng) {
  6278. if (!(layer instanceof L.Layer)) {
  6279. latlng = layer;
  6280. layer = this;
  6281. }
  6282. if (layer instanceof L.FeatureGroup) {
  6283. for (var id in this._layers) {
  6284. layer = this._layers[id];
  6285. break;
  6286. }
  6287. }
  6288. if (!latlng) {
  6289. latlng = layer.getCenter ? layer.getCenter() : layer.getLatLng();
  6290. }
  6291. if (this._tooltip && this._map) {
  6292. // set tooltip source to this layer
  6293. this._tooltip._source = layer;
  6294. // update the tooltip (content, layout, ect...)
  6295. this._tooltip.update();
  6296. // open the tooltip on the map
  6297. this._map.openTooltip(this._tooltip, latlng);
  6298. // Tooltip container may not be defined if not permanent and never
  6299. // opened.
  6300. if (this._tooltip.options.interactive && this._tooltip._container) {
  6301. L.DomUtil.addClass(this._tooltip._container, 'leaflet-clickable');
  6302. this.addInteractiveTarget(this._tooltip._container);
  6303. }
  6304. }
  6305. return this;
  6306. },
  6307. // @method closeTooltip(): this
  6308. // Closes the tooltip bound to this layer if it is open.
  6309. closeTooltip: function () {
  6310. if (this._tooltip) {
  6311. this._tooltip._close();
  6312. if (this._tooltip.options.interactive && this._tooltip._container) {
  6313. L.DomUtil.removeClass(this._tooltip._container, 'leaflet-clickable');
  6314. this.removeInteractiveTarget(this._tooltip._container);
  6315. }
  6316. }
  6317. return this;
  6318. },
  6319. // @method toggleTooltip(): this
  6320. // Opens or closes the tooltip bound to this layer depending on its current state.
  6321. toggleTooltip: function (target) {
  6322. if (this._tooltip) {
  6323. if (this._tooltip._map) {
  6324. this.closeTooltip();
  6325. } else {
  6326. this.openTooltip(target);
  6327. }
  6328. }
  6329. return this;
  6330. },
  6331. // @method isTooltipOpen(): boolean
  6332. // Returns `true` if the tooltip bound to this layer is currently open.
  6333. isTooltipOpen: function () {
  6334. return this._tooltip.isOpen();
  6335. },
  6336. // @method setTooltipContent(content: String|HTMLElement|Tooltip): this
  6337. // Sets the content of the tooltip bound to this layer.
  6338. setTooltipContent: function (content) {
  6339. if (this._tooltip) {
  6340. this._tooltip.setContent(content);
  6341. }
  6342. return this;
  6343. },
  6344. // @method getTooltip(): Tooltip
  6345. // Returns the tooltip bound to this layer.
  6346. getTooltip: function () {
  6347. return this._tooltip;
  6348. },
  6349. _openTooltip: function (e) {
  6350. var layer = e.layer || e.target;
  6351. if (!this._tooltip || !this._map) {
  6352. return;
  6353. }
  6354. this.openTooltip(layer, this._tooltip.options.sticky ? e.latlng : undefined);
  6355. },
  6356. _moveTooltip: function (e) {
  6357. var latlng = e.latlng, containerPoint, layerPoint;
  6358. if (this._tooltip.options.sticky && e.originalEvent) {
  6359. containerPoint = this._map.mouseEventToContainerPoint(e.originalEvent);
  6360. layerPoint = this._map.containerPointToLayerPoint(containerPoint);
  6361. latlng = this._map.layerPointToLatLng(layerPoint);
  6362. }
  6363. this._tooltip.setLatLng(latlng);
  6364. }
  6365. });
  6366. /*
  6367. * @class LayerGroup
  6368. * @aka L.LayerGroup
  6369. * @inherits Layer
  6370. *
  6371. * Used to group several layers and handle them as one. If you add it to the map,
  6372. * any layers added or removed from the group will be added/removed on the map as
  6373. * well. Extends `Layer`.
  6374. *
  6375. * @example
  6376. *
  6377. * ```js
  6378. * L.layerGroup([marker1, marker2])
  6379. * .addLayer(polyline)
  6380. * .addTo(map);
  6381. * ```
  6382. */
  6383. L.LayerGroup = L.Layer.extend({
  6384. initialize: function (layers) {
  6385. this._layers = {};
  6386. var i, len;
  6387. if (layers) {
  6388. for (i = 0, len = layers.length; i < len; i++) {
  6389. this.addLayer(layers[i]);
  6390. }
  6391. }
  6392. },
  6393. // @method addLayer(layer: Layer): this
  6394. // Adds the given layer to the group.
  6395. addLayer: function (layer) {
  6396. var id = this.getLayerId(layer);
  6397. this._layers[id] = layer;
  6398. if (this._map) {
  6399. this._map.addLayer(layer);
  6400. }
  6401. return this;
  6402. },
  6403. // @method removeLayer(layer: Layer): this
  6404. // Removes the given layer from the group.
  6405. // @alternative
  6406. // @method removeLayer(id: Number): this
  6407. // Removes the layer with the given internal ID from the group.
  6408. removeLayer: function (layer) {
  6409. var id = layer in this._layers ? layer : this.getLayerId(layer);
  6410. if (this._map && this._layers[id]) {
  6411. this._map.removeLayer(this._layers[id]);
  6412. }
  6413. delete this._layers[id];
  6414. return this;
  6415. },
  6416. // @method hasLayer(layer: Layer): Boolean
  6417. // Returns `true` if the given layer is currently added to the group.
  6418. hasLayer: function (layer) {
  6419. return !!layer && (layer in this._layers || this.getLayerId(layer) in this._layers);
  6420. },
  6421. // @method clearLayers(): this
  6422. // Removes all the layers from the group.
  6423. clearLayers: function () {
  6424. for (var i in this._layers) {
  6425. this.removeLayer(this._layers[i]);
  6426. }
  6427. return this;
  6428. },
  6429. // @method invoke(methodName: String, …): this
  6430. // Calls `methodName` on every layer contained in this group, passing any
  6431. // additional parameters. Has no effect if the layers contained do not
  6432. // implement `methodName`.
  6433. invoke: function (methodName) {
  6434. var args = Array.prototype.slice.call(arguments, 1),
  6435. i, layer;
  6436. for (i in this._layers) {
  6437. layer = this._layers[i];
  6438. if (layer[methodName]) {
  6439. layer[methodName].apply(layer, args);
  6440. }
  6441. }
  6442. return this;
  6443. },
  6444. onAdd: function (map) {
  6445. for (var i in this._layers) {
  6446. map.addLayer(this._layers[i]);
  6447. }
  6448. },
  6449. onRemove: function (map) {
  6450. for (var i in this._layers) {
  6451. map.removeLayer(this._layers[i]);
  6452. }
  6453. },
  6454. // @method eachLayer(fn: Function, context?: Object): this
  6455. // Iterates over the layers of the group, optionally specifying context of the iterator function.
  6456. // ```js
  6457. // group.eachLayer(function (layer) {
  6458. // layer.bindPopup('Hello');
  6459. // });
  6460. // ```
  6461. eachLayer: function (method, context) {
  6462. for (var i in this._layers) {
  6463. method.call(context, this._layers[i]);
  6464. }
  6465. return this;
  6466. },
  6467. // @method getLayer(id: Number): Layer
  6468. // Returns the layer with the given internal ID.
  6469. getLayer: function (id) {
  6470. return this._layers[id];
  6471. },
  6472. // @method getLayers(): Layer[]
  6473. // Returns an array of all the layers added to the group.
  6474. getLayers: function () {
  6475. var layers = [];
  6476. for (var i in this._layers) {
  6477. layers.push(this._layers[i]);
  6478. }
  6479. return layers;
  6480. },
  6481. // @method setZIndex(zIndex: Number): this
  6482. // Calls `setZIndex` on every layer contained in this group, passing the z-index.
  6483. setZIndex: function (zIndex) {
  6484. return this.invoke('setZIndex', zIndex);
  6485. },
  6486. // @method getLayerId(layer: Layer): Number
  6487. // Returns the internal ID for a layer
  6488. getLayerId: function (layer) {
  6489. return L.stamp(layer);
  6490. }
  6491. });
  6492. // @factory L.layerGroup(layers: Layer[])
  6493. // Create a layer group, optionally given an initial set of layers.
  6494. L.layerGroup = function (layers) {
  6495. return new L.LayerGroup(layers);
  6496. };
  6497. /*
  6498. * @class FeatureGroup
  6499. * @aka L.FeatureGroup
  6500. * @inherits LayerGroup
  6501. *
  6502. * Extended `LayerGroup` that makes it easier to do the same thing to all its member layers:
  6503. * * [`bindPopup`](#layer-bindpopup) binds a popup to all of the layers at once (likewise with [`bindTooltip`](#layer-bindtooltip))
  6504. * * Events are propagated to the `FeatureGroup`, so if the group has an event
  6505. * handler, it will handle events from any of the layers. This includes mouse events
  6506. * and custom events.
  6507. * * Has `layeradd` and `layerremove` events
  6508. *
  6509. * @example
  6510. *
  6511. * ```js
  6512. * L.featureGroup([marker1, marker2, polyline])
  6513. * .bindPopup('Hello world!')
  6514. * .on('click', function() { alert('Clicked on a member of the group!'); })
  6515. * .addTo(map);
  6516. * ```
  6517. */
  6518. L.FeatureGroup = L.LayerGroup.extend({
  6519. addLayer: function (layer) {
  6520. if (this.hasLayer(layer)) {
  6521. return this;
  6522. }
  6523. layer.addEventParent(this);
  6524. L.LayerGroup.prototype.addLayer.call(this, layer);
  6525. // @event layeradd: LayerEvent
  6526. // Fired when a layer is added to this `FeatureGroup`
  6527. return this.fire('layeradd', {layer: layer});
  6528. },
  6529. removeLayer: function (layer) {
  6530. if (!this.hasLayer(layer)) {
  6531. return this;
  6532. }
  6533. if (layer in this._layers) {
  6534. layer = this._layers[layer];
  6535. }
  6536. layer.removeEventParent(this);
  6537. L.LayerGroup.prototype.removeLayer.call(this, layer);
  6538. // @event layerremove: LayerEvent
  6539. // Fired when a layer is removed from this `FeatureGroup`
  6540. return this.fire('layerremove', {layer: layer});
  6541. },
  6542. // @method setStyle(style: Path options): this
  6543. // Sets the given path options to each layer of the group that has a `setStyle` method.
  6544. setStyle: function (style) {
  6545. return this.invoke('setStyle', style);
  6546. },
  6547. // @method bringToFront(): this
  6548. // Brings the layer group to the top of all other layers
  6549. bringToFront: function () {
  6550. return this.invoke('bringToFront');
  6551. },
  6552. // @method bringToBack(): this
  6553. // Brings the layer group to the top of all other layers
  6554. bringToBack: function () {
  6555. return this.invoke('bringToBack');
  6556. },
  6557. // @method getBounds(): LatLngBounds
  6558. // Returns the LatLngBounds of the Feature Group (created from bounds and coordinates of its children).
  6559. getBounds: function () {
  6560. var bounds = new L.LatLngBounds();
  6561. for (var id in this._layers) {
  6562. var layer = this._layers[id];
  6563. bounds.extend(layer.getBounds ? layer.getBounds() : layer.getLatLng());
  6564. }
  6565. return bounds;
  6566. }
  6567. });
  6568. // @factory L.featureGroup(layers: Layer[])
  6569. // Create a feature group, optionally given an initial set of layers.
  6570. L.featureGroup = function (layers) {
  6571. return new L.FeatureGroup(layers);
  6572. };
  6573. /*
  6574. * @class Renderer
  6575. * @inherits Layer
  6576. * @aka L.Renderer
  6577. *
  6578. * Base class for vector renderer implementations (`SVG`, `Canvas`). Handles the
  6579. * DOM container of the renderer, its bounds, and its zoom animation.
  6580. *
  6581. * A `Renderer` works as an implicit layer group for all `Path`s - the renderer
  6582. * itself can be added or removed to the map. All paths use a renderer, which can
  6583. * be implicit (the map will decide the type of renderer and use it automatically)
  6584. * or explicit (using the [`renderer`](#path-renderer) option of the path).
  6585. *
  6586. * Do not use this class directly, use `SVG` and `Canvas` instead.
  6587. *
  6588. * @event update: Event
  6589. * Fired when the renderer updates its bounds, center and zoom, for example when
  6590. * its map has moved
  6591. */
  6592. L.Renderer = L.Layer.extend({
  6593. // @section
  6594. // @aka Renderer options
  6595. options: {
  6596. // @option padding: Number = 0.1
  6597. // How much to extend the clip area around the map view (relative to its size)
  6598. // e.g. 0.1 would be 10% of map view in each direction
  6599. padding: 0.1
  6600. },
  6601. initialize: function (options) {
  6602. L.setOptions(this, options);
  6603. L.stamp(this);
  6604. this._layers = this._layers || {};
  6605. },
  6606. onAdd: function () {
  6607. if (!this._container) {
  6608. this._initContainer(); // defined by renderer implementations
  6609. if (this._zoomAnimated) {
  6610. L.DomUtil.addClass(this._container, 'leaflet-zoom-animated');
  6611. }
  6612. }
  6613. this.getPane().appendChild(this._container);
  6614. this._update();
  6615. this.on('update', this._updatePaths, this);
  6616. },
  6617. onRemove: function () {
  6618. L.DomUtil.remove(this._container);
  6619. this.off('update', this._updatePaths, this);
  6620. },
  6621. getEvents: function () {
  6622. var events = {
  6623. viewreset: this._reset,
  6624. zoom: this._onZoom,
  6625. moveend: this._update,
  6626. zoomend: this._onZoomEnd
  6627. };
  6628. if (this._zoomAnimated) {
  6629. events.zoomanim = this._onAnimZoom;
  6630. }
  6631. return events;
  6632. },
  6633. _onAnimZoom: function (ev) {
  6634. this._updateTransform(ev.center, ev.zoom);
  6635. },
  6636. _onZoom: function () {
  6637. this._updateTransform(this._map.getCenter(), this._map.getZoom());
  6638. },
  6639. _updateTransform: function (center, zoom) {
  6640. var scale = this._map.getZoomScale(zoom, this._zoom),
  6641. position = L.DomUtil.getPosition(this._container),
  6642. viewHalf = this._map.getSize().multiplyBy(0.5 + this.options.padding),
  6643. currentCenterPoint = this._map.project(this._center, zoom),
  6644. destCenterPoint = this._map.project(center, zoom),
  6645. centerOffset = destCenterPoint.subtract(currentCenterPoint),
  6646. topLeftOffset = viewHalf.multiplyBy(-scale).add(position).add(viewHalf).subtract(centerOffset);
  6647. if (L.Browser.any3d) {
  6648. L.DomUtil.setTransform(this._container, topLeftOffset, scale);
  6649. } else {
  6650. L.DomUtil.setPosition(this._container, topLeftOffset);
  6651. }
  6652. },
  6653. _reset: function () {
  6654. this._update();
  6655. this._updateTransform(this._center, this._zoom);
  6656. for (var id in this._layers) {
  6657. this._layers[id]._reset();
  6658. }
  6659. },
  6660. _onZoomEnd: function () {
  6661. for (var id in this._layers) {
  6662. this._layers[id]._project();
  6663. }
  6664. },
  6665. _updatePaths: function () {
  6666. for (var id in this._layers) {
  6667. this._layers[id]._update();
  6668. }
  6669. },
  6670. _update: function () {
  6671. // Update pixel bounds of renderer container (for positioning/sizing/clipping later)
  6672. // Subclasses are responsible of firing the 'update' event.
  6673. var p = this.options.padding,
  6674. size = this._map.getSize(),
  6675. min = this._map.containerPointToLayerPoint(size.multiplyBy(-p)).round();
  6676. this._bounds = new L.Bounds(min, min.add(size.multiplyBy(1 + p * 2)).round());
  6677. this._center = this._map.getCenter();
  6678. this._zoom = this._map.getZoom();
  6679. }
  6680. });
  6681. L.Map.include({
  6682. // @namespace Map; @method getRenderer(layer: Path): Renderer
  6683. // Returns the instance of `Renderer` that should be used to render the given
  6684. // `Path`. It will ensure that the `renderer` options of the map and paths
  6685. // are respected, and that the renderers do exist on the map.
  6686. getRenderer: function (layer) {
  6687. // @namespace Path; @option renderer: Renderer
  6688. // Use this specific instance of `Renderer` for this path. Takes
  6689. // precedence over the map's [default renderer](#map-renderer).
  6690. var renderer = layer.options.renderer || this._getPaneRenderer(layer.options.pane) || this.options.renderer || this._renderer;
  6691. if (!renderer) {
  6692. // @namespace Map; @option preferCanvas: Boolean = false
  6693. // Whether `Path`s should be rendered on a `Canvas` renderer.
  6694. // By default, all `Path`s are rendered in a `SVG` renderer.
  6695. renderer = this._renderer = (this.options.preferCanvas && L.canvas()) || L.svg();
  6696. }
  6697. if (!this.hasLayer(renderer)) {
  6698. this.addLayer(renderer);
  6699. }
  6700. return renderer;
  6701. },
  6702. _getPaneRenderer: function (name) {
  6703. if (name === 'overlayPane' || name === undefined) {
  6704. return false;
  6705. }
  6706. var renderer = this._paneRenderers[name];
  6707. if (renderer === undefined) {
  6708. renderer = (L.SVG && L.svg({pane: name})) || (L.Canvas && L.canvas({pane: name}));
  6709. this._paneRenderers[name] = renderer;
  6710. }
  6711. return renderer;
  6712. }
  6713. });
  6714. /*
  6715. * @class Path
  6716. * @aka L.Path
  6717. * @inherits Interactive layer
  6718. *
  6719. * An abstract class that contains options and constants shared between vector
  6720. * overlays (Polygon, Polyline, Circle). Do not use it directly. Extends `Layer`.
  6721. */
  6722. L.Path = L.Layer.extend({
  6723. // @section
  6724. // @aka Path options
  6725. options: {
  6726. // @option stroke: Boolean = true
  6727. // Whether to draw stroke along the path. Set it to `false` to disable borders on polygons or circles.
  6728. stroke: true,
  6729. // @option color: String = '#3388ff'
  6730. // Stroke color
  6731. color: '#3388ff',
  6732. // @option weight: Number = 3
  6733. // Stroke width in pixels
  6734. weight: 3,
  6735. // @option opacity: Number = 1.0
  6736. // Stroke opacity
  6737. opacity: 1,
  6738. // @option lineCap: String= 'round'
  6739. // A string that defines [shape to be used at the end](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linecap) of the stroke.
  6740. lineCap: 'round',
  6741. // @option lineJoin: String = 'round'
  6742. // A string that defines [shape to be used at the corners](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-linejoin) of the stroke.
  6743. lineJoin: 'round',
  6744. // @option dashArray: String = null
  6745. // A string that defines the stroke [dash pattern](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dasharray). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).
  6746. dashArray: null,
  6747. // @option dashOffset: String = null
  6748. // A string that defines the [distance into the dash pattern to start the dash](https://developer.mozilla.org/docs/Web/SVG/Attribute/stroke-dashoffset). Doesn't work on `Canvas`-powered layers in [some old browsers](https://developer.mozilla.org/docs/Web/API/CanvasRenderingContext2D/setLineDash#Browser_compatibility).
  6749. dashOffset: null,
  6750. // @option fill: Boolean = depends
  6751. // Whether to fill the path with color. Set it to `false` to disable filling on polygons or circles.
  6752. fill: false,
  6753. // @option fillColor: String = *
  6754. // Fill color. Defaults to the value of the [`color`](#path-color) option
  6755. fillColor: null,
  6756. // @option fillOpacity: Number = 0.2
  6757. // Fill opacity.
  6758. fillOpacity: 0.2,
  6759. // @option fillRule: String = 'evenodd'
  6760. // A string that defines [how the inside of a shape](https://developer.mozilla.org/docs/Web/SVG/Attribute/fill-rule) is determined.
  6761. fillRule: 'evenodd',
  6762. // className: '',
  6763. // Option inherited from "Interactive layer" abstract class
  6764. interactive: true
  6765. },
  6766. beforeAdd: function (map) {
  6767. // Renderer is set here because we need to call renderer.getEvents
  6768. // before this.getEvents.
  6769. this._renderer = map.getRenderer(this);
  6770. },
  6771. onAdd: function () {
  6772. this._renderer._initPath(this);
  6773. this._reset();
  6774. this._renderer._addPath(this);
  6775. },
  6776. onRemove: function () {
  6777. this._renderer._removePath(this);
  6778. },
  6779. // @method redraw(): this
  6780. // Redraws the layer. Sometimes useful after you changed the coordinates that the path uses.
  6781. redraw: function () {
  6782. if (this._map) {
  6783. this._renderer._updatePath(this);
  6784. }
  6785. return this;
  6786. },
  6787. // @method setStyle(style: Path options): this
  6788. // Changes the appearance of a Path based on the options in the `Path options` object.
  6789. setStyle: function (style) {
  6790. L.setOptions(this, style);
  6791. if (this._renderer) {
  6792. this._renderer._updateStyle(this);
  6793. }
  6794. return this;
  6795. },
  6796. // @method bringToFront(): this
  6797. // Brings the layer to the top of all path layers.
  6798. bringToFront: function () {
  6799. if (this._renderer) {
  6800. this._renderer._bringToFront(this);
  6801. }
  6802. return this;
  6803. },
  6804. // @method bringToBack(): this
  6805. // Brings the layer to the bottom of all path layers.
  6806. bringToBack: function () {
  6807. if (this._renderer) {
  6808. this._renderer._bringToBack(this);
  6809. }
  6810. return this;
  6811. },
  6812. getElement: function () {
  6813. return this._path;
  6814. },
  6815. _reset: function () {
  6816. // defined in children classes
  6817. this._project();
  6818. this._update();
  6819. },
  6820. _clickTolerance: function () {
  6821. // used when doing hit detection for Canvas layers
  6822. return (this.options.stroke ? this.options.weight / 2 : 0) + (L.Browser.touch ? 10 : 0);
  6823. }
  6824. });
  6825. /*
  6826. * @namespace LineUtil
  6827. *
  6828. * Various utility functions for polyine points processing, used by Leaflet internally to make polylines lightning-fast.
  6829. */
  6830. L.LineUtil = {
  6831. // Simplify polyline with vertex reduction and Douglas-Peucker simplification.
  6832. // Improves rendering performance dramatically by lessening the number of points to draw.
  6833. // @function simplify(points: Point[], tolerance: Number): Point[]
  6834. // Dramatically reduces the number of points in a polyline while retaining
  6835. // its shape and returns a new array of simplified points, using the
  6836. // [Douglas-Peucker algorithm](http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm).
  6837. // Used for a huge performance boost when processing/displaying Leaflet polylines for
  6838. // each zoom level and also reducing visual noise. tolerance affects the amount of
  6839. // simplification (lesser value means higher quality but slower and with more points).
  6840. // Also released as a separated micro-library [Simplify.js](http://mourner.github.com/simplify-js/).
  6841. simplify: function (points, tolerance) {
  6842. if (!tolerance || !points.length) {
  6843. return points.slice();
  6844. }
  6845. var sqTolerance = tolerance * tolerance;
  6846. // stage 1: vertex reduction
  6847. points = this._reducePoints(points, sqTolerance);
  6848. // stage 2: Douglas-Peucker simplification
  6849. points = this._simplifyDP(points, sqTolerance);
  6850. return points;
  6851. },
  6852. // @function pointToSegmentDistance(p: Point, p1: Point, p2: Point): Number
  6853. // Returns the distance between point `p` and segment `p1` to `p2`.
  6854. pointToSegmentDistance: function (p, p1, p2) {
  6855. return Math.sqrt(this._sqClosestPointOnSegment(p, p1, p2, true));
  6856. },
  6857. // @function closestPointOnSegment(p: Point, p1: Point, p2: Point): Number
  6858. // Returns the closest point from a point `p` on a segment `p1` to `p2`.
  6859. closestPointOnSegment: function (p, p1, p2) {
  6860. return this._sqClosestPointOnSegment(p, p1, p2);
  6861. },
  6862. // Douglas-Peucker simplification, see http://en.wikipedia.org/wiki/Douglas-Peucker_algorithm
  6863. _simplifyDP: function (points, sqTolerance) {
  6864. var len = points.length,
  6865. ArrayConstructor = typeof Uint8Array !== undefined + '' ? Uint8Array : Array,
  6866. markers = new ArrayConstructor(len);
  6867. markers[0] = markers[len - 1] = 1;
  6868. this._simplifyDPStep(points, markers, sqTolerance, 0, len - 1);
  6869. var i,
  6870. newPoints = [];
  6871. for (i = 0; i < len; i++) {
  6872. if (markers[i]) {
  6873. newPoints.push(points[i]);
  6874. }
  6875. }
  6876. return newPoints;
  6877. },
  6878. _simplifyDPStep: function (points, markers, sqTolerance, first, last) {
  6879. var maxSqDist = 0,
  6880. index, i, sqDist;
  6881. for (i = first + 1; i <= last - 1; i++) {
  6882. sqDist = this._sqClosestPointOnSegment(points[i], points[first], points[last], true);
  6883. if (sqDist > maxSqDist) {
  6884. index = i;
  6885. maxSqDist = sqDist;
  6886. }
  6887. }
  6888. if (maxSqDist > sqTolerance) {
  6889. markers[index] = 1;
  6890. this._simplifyDPStep(points, markers, sqTolerance, first, index);
  6891. this._simplifyDPStep(points, markers, sqTolerance, index, last);
  6892. }
  6893. },
  6894. // reduce points that are too close to each other to a single point
  6895. _reducePoints: function (points, sqTolerance) {
  6896. var reducedPoints = [points[0]];
  6897. for (var i = 1, prev = 0, len = points.length; i < len; i++) {
  6898. if (this._sqDist(points[i], points[prev]) > sqTolerance) {
  6899. reducedPoints.push(points[i]);
  6900. prev = i;
  6901. }
  6902. }
  6903. if (prev < len - 1) {
  6904. reducedPoints.push(points[len - 1]);
  6905. }
  6906. return reducedPoints;
  6907. },
  6908. // @function clipSegment(a: Point, b: Point, bounds: Bounds, useLastCode?: Boolean, round?: Boolean): Point[]|Boolean
  6909. // Clips the segment a to b by rectangular bounds with the
  6910. // [Cohen-Sutherland algorithm](https://en.wikipedia.org/wiki/Cohen%E2%80%93Sutherland_algorithm)
  6911. // (modifying the segment points directly!). Used by Leaflet to only show polyline
  6912. // points that are on the screen or near, increasing performance.
  6913. clipSegment: function (a, b, bounds, useLastCode, round) {
  6914. var codeA = useLastCode ? this._lastCode : this._getBitCode(a, bounds),
  6915. codeB = this._getBitCode(b, bounds),
  6916. codeOut, p, newCode;
  6917. // save 2nd code to avoid calculating it on the next segment
  6918. this._lastCode = codeB;
  6919. while (true) {
  6920. // if a,b is inside the clip window (trivial accept)
  6921. if (!(codeA | codeB)) {
  6922. return [a, b];
  6923. }
  6924. // if a,b is outside the clip window (trivial reject)
  6925. if (codeA & codeB) {
  6926. return false;
  6927. }
  6928. // other cases
  6929. codeOut = codeA || codeB;
  6930. p = this._getEdgeIntersection(a, b, codeOut, bounds, round);
  6931. newCode = this._getBitCode(p, bounds);
  6932. if (codeOut === codeA) {
  6933. a = p;
  6934. codeA = newCode;
  6935. } else {
  6936. b = p;
  6937. codeB = newCode;
  6938. }
  6939. }
  6940. },
  6941. _getEdgeIntersection: function (a, b, code, bounds, round) {
  6942. var dx = b.x - a.x,
  6943. dy = b.y - a.y,
  6944. min = bounds.min,
  6945. max = bounds.max,
  6946. x, y;
  6947. if (code & 8) { // top
  6948. x = a.x + dx * (max.y - a.y) / dy;
  6949. y = max.y;
  6950. } else if (code & 4) { // bottom
  6951. x = a.x + dx * (min.y - a.y) / dy;
  6952. y = min.y;
  6953. } else if (code & 2) { // right
  6954. x = max.x;
  6955. y = a.y + dy * (max.x - a.x) / dx;
  6956. } else if (code & 1) { // left
  6957. x = min.x;
  6958. y = a.y + dy * (min.x - a.x) / dx;
  6959. }
  6960. return new L.Point(x, y, round);
  6961. },
  6962. _getBitCode: function (p, bounds) {
  6963. var code = 0;
  6964. if (p.x < bounds.min.x) { // left
  6965. code |= 1;
  6966. } else if (p.x > bounds.max.x) { // right
  6967. code |= 2;
  6968. }
  6969. if (p.y < bounds.min.y) { // bottom
  6970. code |= 4;
  6971. } else if (p.y > bounds.max.y) { // top
  6972. code |= 8;
  6973. }
  6974. return code;
  6975. },
  6976. // square distance (to avoid unnecessary Math.sqrt calls)
  6977. _sqDist: function (p1, p2) {
  6978. var dx = p2.x - p1.x,
  6979. dy = p2.y - p1.y;
  6980. return dx * dx + dy * dy;
  6981. },
  6982. // return closest point on segment or distance to that point
  6983. _sqClosestPointOnSegment: function (p, p1, p2, sqDist) {
  6984. var x = p1.x,
  6985. y = p1.y,
  6986. dx = p2.x - x,
  6987. dy = p2.y - y,
  6988. dot = dx * dx + dy * dy,
  6989. t;
  6990. if (dot > 0) {
  6991. t = ((p.x - x) * dx + (p.y - y) * dy) / dot;
  6992. if (t > 1) {
  6993. x = p2.x;
  6994. y = p2.y;
  6995. } else if (t > 0) {
  6996. x += dx * t;
  6997. y += dy * t;
  6998. }
  6999. }
  7000. dx = p.x - x;
  7001. dy = p.y - y;
  7002. return sqDist ? dx * dx + dy * dy : new L.Point(x, y);
  7003. }
  7004. };
  7005. /*
  7006. * @class Polyline
  7007. * @aka L.Polyline
  7008. * @inherits Path
  7009. *
  7010. * A class for drawing polyline overlays on a map. Extends `Path`.
  7011. *
  7012. * @example
  7013. *
  7014. * ```js
  7015. * // create a red polyline from an array of LatLng points
  7016. * var latlngs = [
  7017. * [-122.68, 45.51],
  7018. * [-122.43, 37.77],
  7019. * [-118.2, 34.04]
  7020. * ];
  7021. *
  7022. * var polyline = L.polyline(latlngs, {color: 'red'}).addTo(map);
  7023. *
  7024. * // zoom the map to the polyline
  7025. * map.fitBounds(polyline.getBounds());
  7026. * ```
  7027. *
  7028. * You can also pass a multi-dimensional array to represent a `MultiPolyline` shape:
  7029. *
  7030. * ```js
  7031. * // create a red polyline from an array of arrays of LatLng points
  7032. * var latlngs = [
  7033. * [[-122.68, 45.51],
  7034. * [-122.43, 37.77],
  7035. * [-118.2, 34.04]],
  7036. * [[-73.91, 40.78],
  7037. * [-87.62, 41.83],
  7038. * [-96.72, 32.76]]
  7039. * ];
  7040. * ```
  7041. */
  7042. L.Polyline = L.Path.extend({
  7043. // @section
  7044. // @aka Polyline options
  7045. options: {
  7046. // @option smoothFactor: Number = 1.0
  7047. // How much to simplify the polyline on each zoom level. More means
  7048. // better performance and smoother look, and less means more accurate representation.
  7049. smoothFactor: 1.0,
  7050. // @option noClip: Boolean = false
  7051. // Disable polyline clipping.
  7052. noClip: false
  7053. },
  7054. initialize: function (latlngs, options) {
  7055. L.setOptions(this, options);
  7056. this._setLatLngs(latlngs);
  7057. },
  7058. // @method getLatLngs(): LatLng[]
  7059. // Returns an array of the points in the path, or nested arrays of points in case of multi-polyline.
  7060. getLatLngs: function () {
  7061. return this._latlngs;
  7062. },
  7063. // @method setLatLngs(latlngs: LatLng[]): this
  7064. // Replaces all the points in the polyline with the given array of geographical points.
  7065. setLatLngs: function (latlngs) {
  7066. this._setLatLngs(latlngs);
  7067. return this.redraw();
  7068. },
  7069. // @method isEmpty(): Boolean
  7070. // Returns `true` if the Polyline has no LatLngs.
  7071. isEmpty: function () {
  7072. return !this._latlngs.length;
  7073. },
  7074. closestLayerPoint: function (p) {
  7075. var minDistance = Infinity,
  7076. minPoint = null,
  7077. closest = L.LineUtil._sqClosestPointOnSegment,
  7078. p1, p2;
  7079. for (var j = 0, jLen = this._parts.length; j < jLen; j++) {
  7080. var points = this._parts[j];
  7081. for (var i = 1, len = points.length; i < len; i++) {
  7082. p1 = points[i - 1];
  7083. p2 = points[i];
  7084. var sqDist = closest(p, p1, p2, true);
  7085. if (sqDist < minDistance) {
  7086. minDistance = sqDist;
  7087. minPoint = closest(p, p1, p2);
  7088. }
  7089. }
  7090. }
  7091. if (minPoint) {
  7092. minPoint.distance = Math.sqrt(minDistance);
  7093. }
  7094. return minPoint;
  7095. },
  7096. // @method getCenter(): LatLng
  7097. // Returns the center ([centroid](http://en.wikipedia.org/wiki/Centroid)) of the polyline.
  7098. getCenter: function () {
  7099. // throws error when not yet added to map as this center calculation requires projected coordinates
  7100. if (!this._map) {
  7101. throw new Error('Must add layer to map before using getCenter()');
  7102. }
  7103. var i, halfDist, segDist, dist, p1, p2, ratio,
  7104. points = this._rings[0],
  7105. len = points.length;
  7106. if (!len) { return null; }
  7107. // polyline centroid algorithm; only uses the first ring if there are multiple
  7108. for (i = 0, halfDist = 0; i < len - 1; i++) {
  7109. halfDist += points[i].distanceTo(points[i + 1]) / 2;
  7110. }
  7111. // The line is so small in the current view that all points are on the same pixel.
  7112. if (halfDist === 0) {
  7113. return this._map.layerPointToLatLng(points[0]);
  7114. }
  7115. for (i = 0, dist = 0; i < len - 1; i++) {
  7116. p1 = points[i];
  7117. p2 = points[i + 1];
  7118. segDist = p1.distanceTo(p2);
  7119. dist += segDist;
  7120. if (dist > halfDist) {
  7121. ratio = (dist - halfDist) / segDist;
  7122. return this._map.layerPointToLatLng([
  7123. p2.x - ratio * (p2.x - p1.x),
  7124. p2.y - ratio * (p2.y - p1.y)
  7125. ]);
  7126. }
  7127. }
  7128. },
  7129. // @method getBounds(): LatLngBounds
  7130. // Returns the `LatLngBounds` of the path.
  7131. getBounds: function () {
  7132. return this._bounds;
  7133. },
  7134. // @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this
  7135. // Adds a given point to the polyline. By default, adds to the first ring of
  7136. // the polyline in case of a multi-polyline, but can be overridden by passing
  7137. // a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)).
  7138. addLatLng: function (latlng, latlngs) {
  7139. latlngs = latlngs || this._defaultShape();
  7140. latlng = L.latLng(latlng);
  7141. latlngs.push(latlng);
  7142. this._bounds.extend(latlng);
  7143. return this.redraw();
  7144. },
  7145. _setLatLngs: function (latlngs) {
  7146. this._bounds = new L.LatLngBounds();
  7147. this._latlngs = this._convertLatLngs(latlngs);
  7148. },
  7149. _defaultShape: function () {
  7150. return L.Polyline._flat(this._latlngs) ? this._latlngs : this._latlngs[0];
  7151. },
  7152. // recursively convert latlngs input into actual LatLng instances; calculate bounds along the way
  7153. _convertLatLngs: function (latlngs) {
  7154. var result = [],
  7155. flat = L.Polyline._flat(latlngs);
  7156. for (var i = 0, len = latlngs.length; i < len; i++) {
  7157. if (flat) {
  7158. result[i] = L.latLng(latlngs[i]);
  7159. this._bounds.extend(result[i]);
  7160. } else {
  7161. result[i] = this._convertLatLngs(latlngs[i]);
  7162. }
  7163. }
  7164. return result;
  7165. },
  7166. _project: function () {
  7167. var pxBounds = new L.Bounds();
  7168. this._rings = [];
  7169. this._projectLatlngs(this._latlngs, this._rings, pxBounds);
  7170. var w = this._clickTolerance(),
  7171. p = new L.Point(w, w);
  7172. if (this._bounds.isValid() && pxBounds.isValid()) {
  7173. pxBounds.min._subtract(p);
  7174. pxBounds.max._add(p);
  7175. this._pxBounds = pxBounds;
  7176. }
  7177. },
  7178. // recursively turns latlngs into a set of rings with projected coordinates
  7179. _projectLatlngs: function (latlngs, result, projectedBounds) {
  7180. var flat = latlngs[0] instanceof L.LatLng,
  7181. len = latlngs.length,
  7182. i, ring;
  7183. if (flat) {
  7184. ring = [];
  7185. for (i = 0; i < len; i++) {
  7186. ring[i] = this._map.latLngToLayerPoint(latlngs[i]);
  7187. projectedBounds.extend(ring[i]);
  7188. }
  7189. result.push(ring);
  7190. } else {
  7191. for (i = 0; i < len; i++) {
  7192. this._projectLatlngs(latlngs[i], result, projectedBounds);
  7193. }
  7194. }
  7195. },
  7196. // clip polyline by renderer bounds so that we have less to render for performance
  7197. _clipPoints: function () {
  7198. var bounds = this._renderer._bounds;
  7199. this._parts = [];
  7200. if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
  7201. return;
  7202. }
  7203. if (this.options.noClip) {
  7204. this._parts = this._rings;
  7205. return;
  7206. }
  7207. var parts = this._parts,
  7208. i, j, k, len, len2, segment, points;
  7209. for (i = 0, k = 0, len = this._rings.length; i < len; i++) {
  7210. points = this._rings[i];
  7211. for (j = 0, len2 = points.length; j < len2 - 1; j++) {
  7212. segment = L.LineUtil.clipSegment(points[j], points[j + 1], bounds, j, true);
  7213. if (!segment) { continue; }
  7214. parts[k] = parts[k] || [];
  7215. parts[k].push(segment[0]);
  7216. // if segment goes out of screen, or it's the last one, it's the end of the line part
  7217. if ((segment[1] !== points[j + 1]) || (j === len2 - 2)) {
  7218. parts[k].push(segment[1]);
  7219. k++;
  7220. }
  7221. }
  7222. }
  7223. },
  7224. // simplify each clipped part of the polyline for performance
  7225. _simplifyPoints: function () {
  7226. var parts = this._parts,
  7227. tolerance = this.options.smoothFactor;
  7228. for (var i = 0, len = parts.length; i < len; i++) {
  7229. parts[i] = L.LineUtil.simplify(parts[i], tolerance);
  7230. }
  7231. },
  7232. _update: function () {
  7233. if (!this._map) { return; }
  7234. this._clipPoints();
  7235. this._simplifyPoints();
  7236. this._updatePath();
  7237. },
  7238. _updatePath: function () {
  7239. this._renderer._updatePoly(this);
  7240. }
  7241. });
  7242. // @factory L.polyline(latlngs: LatLng[], options?: Polyline options)
  7243. // Instantiates a polyline object given an array of geographical points and
  7244. // optionally an options object. You can create a `Polyline` object with
  7245. // multiple separate lines (`MultiPolyline`) by passing an array of arrays
  7246. // of geographic points.
  7247. L.polyline = function (latlngs, options) {
  7248. return new L.Polyline(latlngs, options);
  7249. };
  7250. L.Polyline._flat = function (latlngs) {
  7251. // true if it's a flat array of latlngs; false if nested
  7252. return !L.Util.isArray(latlngs[0]) || (typeof latlngs[0][0] !== 'object' && typeof latlngs[0][0] !== 'undefined');
  7253. };
  7254. /*
  7255. * @namespace PolyUtil
  7256. * Various utility functions for polygon geometries.
  7257. */
  7258. L.PolyUtil = {};
  7259. /* @function clipPolygon(points: Point[], bounds: Bounds, round?: Boolean): Point[]
  7260. * Clips the polygon geometry defined by the given `points` by the given bounds (using the [Sutherland-Hodgeman algorithm](https://en.wikipedia.org/wiki/Sutherland%E2%80%93Hodgman_algorithm)).
  7261. * Used by Leaflet to only show polygon points that are on the screen or near, increasing
  7262. * performance. Note that polygon points needs different algorithm for clipping
  7263. * than polyline, so there's a seperate method for it.
  7264. */
  7265. L.PolyUtil.clipPolygon = function (points, bounds, round) {
  7266. var clippedPoints,
  7267. edges = [1, 4, 2, 8],
  7268. i, j, k,
  7269. a, b,
  7270. len, edge, p,
  7271. lu = L.LineUtil;
  7272. for (i = 0, len = points.length; i < len; i++) {
  7273. points[i]._code = lu._getBitCode(points[i], bounds);
  7274. }
  7275. // for each edge (left, bottom, right, top)
  7276. for (k = 0; k < 4; k++) {
  7277. edge = edges[k];
  7278. clippedPoints = [];
  7279. for (i = 0, len = points.length, j = len - 1; i < len; j = i++) {
  7280. a = points[i];
  7281. b = points[j];
  7282. // if a is inside the clip window
  7283. if (!(a._code & edge)) {
  7284. // if b is outside the clip window (a->b goes out of screen)
  7285. if (b._code & edge) {
  7286. p = lu._getEdgeIntersection(b, a, edge, bounds, round);
  7287. p._code = lu._getBitCode(p, bounds);
  7288. clippedPoints.push(p);
  7289. }
  7290. clippedPoints.push(a);
  7291. // else if b is inside the clip window (a->b enters the screen)
  7292. } else if (!(b._code & edge)) {
  7293. p = lu._getEdgeIntersection(b, a, edge, bounds, round);
  7294. p._code = lu._getBitCode(p, bounds);
  7295. clippedPoints.push(p);
  7296. }
  7297. }
  7298. points = clippedPoints;
  7299. }
  7300. return points;
  7301. };
  7302. /*
  7303. * @class Polygon
  7304. * @aka L.Polygon
  7305. * @inherits Polyline
  7306. *
  7307. * A class for drawing polygon overlays on a map. Extends `Polyline`.
  7308. *
  7309. * Note that points you pass when creating a polygon shouldn't have an additional last point equal to the first one — it's better to filter out such points.
  7310. *
  7311. *
  7312. * @example
  7313. *
  7314. * ```js
  7315. * // create a red polygon from an array of LatLng points
  7316. * var latlngs = [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]];
  7317. *
  7318. * var polygon = L.polygon(latlngs, {color: 'red'}).addTo(map);
  7319. *
  7320. * // zoom the map to the polygon
  7321. * map.fitBounds(polygon.getBounds());
  7322. * ```
  7323. *
  7324. * You can also pass an array of arrays of latlngs, with the first array representing the outer shape and the other arrays representing holes in the outer shape:
  7325. *
  7326. * ```js
  7327. * var latlngs = [
  7328. * [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]], // outer ring
  7329. * [[-108.58,37.29],[-108.58,40.71],[-102.50,40.71],[-102.50,37.29]] // hole
  7330. * ];
  7331. * ```
  7332. *
  7333. * Additionally, you can pass a multi-dimensional array to represent a MultiPolygon shape.
  7334. *
  7335. * ```js
  7336. * var latlngs = [
  7337. * [ // first polygon
  7338. * [[-111.03, 41],[-111.04, 45],[-104.05, 45],[-104.05, 41]], // outer ring
  7339. * [[-108.58,37.29],[-108.58,40.71],[-102.50,40.71],[-102.50,37.29]] // hole
  7340. * ],
  7341. * [ // second polygon
  7342. * [[-109.05, 37],[-109.03, 41],[-102.05, 41],[-102.04, 37],[-109.05, 38]]
  7343. * ]
  7344. * ];
  7345. * ```
  7346. */
  7347. L.Polygon = L.Polyline.extend({
  7348. options: {
  7349. fill: true
  7350. },
  7351. isEmpty: function () {
  7352. return !this._latlngs.length || !this._latlngs[0].length;
  7353. },
  7354. getCenter: function () {
  7355. // throws error when not yet added to map as this center calculation requires projected coordinates
  7356. if (!this._map) {
  7357. throw new Error('Must add layer to map before using getCenter()');
  7358. }
  7359. var i, j, p1, p2, f, area, x, y, center,
  7360. points = this._rings[0],
  7361. len = points.length;
  7362. if (!len) { return null; }
  7363. // polygon centroid algorithm; only uses the first ring if there are multiple
  7364. area = x = y = 0;
  7365. for (i = 0, j = len - 1; i < len; j = i++) {
  7366. p1 = points[i];
  7367. p2 = points[j];
  7368. f = p1.y * p2.x - p2.y * p1.x;
  7369. x += (p1.x + p2.x) * f;
  7370. y += (p1.y + p2.y) * f;
  7371. area += f * 3;
  7372. }
  7373. if (area === 0) {
  7374. // Polygon is so small that all points are on same pixel.
  7375. center = points[0];
  7376. } else {
  7377. center = [x / area, y / area];
  7378. }
  7379. return this._map.layerPointToLatLng(center);
  7380. },
  7381. _convertLatLngs: function (latlngs) {
  7382. var result = L.Polyline.prototype._convertLatLngs.call(this, latlngs),
  7383. len = result.length;
  7384. // remove last point if it equals first one
  7385. if (len >= 2 && result[0] instanceof L.LatLng && result[0].equals(result[len - 1])) {
  7386. result.pop();
  7387. }
  7388. return result;
  7389. },
  7390. _setLatLngs: function (latlngs) {
  7391. L.Polyline.prototype._setLatLngs.call(this, latlngs);
  7392. if (L.Polyline._flat(this._latlngs)) {
  7393. this._latlngs = [this._latlngs];
  7394. }
  7395. },
  7396. _defaultShape: function () {
  7397. return L.Polyline._flat(this._latlngs[0]) ? this._latlngs[0] : this._latlngs[0][0];
  7398. },
  7399. _clipPoints: function () {
  7400. // polygons need a different clipping algorithm so we redefine that
  7401. var bounds = this._renderer._bounds,
  7402. w = this.options.weight,
  7403. p = new L.Point(w, w);
  7404. // increase clip padding by stroke width to avoid stroke on clip edges
  7405. bounds = new L.Bounds(bounds.min.subtract(p), bounds.max.add(p));
  7406. this._parts = [];
  7407. if (!this._pxBounds || !this._pxBounds.intersects(bounds)) {
  7408. return;
  7409. }
  7410. if (this.options.noClip) {
  7411. this._parts = this._rings;
  7412. return;
  7413. }
  7414. for (var i = 0, len = this._rings.length, clipped; i < len; i++) {
  7415. clipped = L.PolyUtil.clipPolygon(this._rings[i], bounds, true);
  7416. if (clipped.length) {
  7417. this._parts.push(clipped);
  7418. }
  7419. }
  7420. },
  7421. _updatePath: function () {
  7422. this._renderer._updatePoly(this, true);
  7423. }
  7424. });
  7425. // @factory L.polygon(latlngs: LatLng[], options?: Polyline options)
  7426. L.polygon = function (latlngs, options) {
  7427. return new L.Polygon(latlngs, options);
  7428. };
  7429. /*
  7430. * L.Rectangle extends Polygon and creates a rectangle when passed a LatLngBounds object.
  7431. */
  7432. /*
  7433. * @class Rectangle
  7434. * @aka L.Retangle
  7435. * @inherits Polygon
  7436. *
  7437. * A class for drawing rectangle overlays on a map. Extends `Polygon`.
  7438. *
  7439. * @example
  7440. *
  7441. * ```js
  7442. * // define rectangle geographical bounds
  7443. * var bounds = [[54.559322, -5.767822], [56.1210604, -3.021240]];
  7444. *
  7445. * // create an orange rectangle
  7446. * L.rectangle(bounds, {color: "#ff7800", weight: 1}).addTo(map);
  7447. *
  7448. * // zoom the map to the rectangle bounds
  7449. * map.fitBounds(bounds);
  7450. * ```
  7451. *
  7452. */
  7453. L.Rectangle = L.Polygon.extend({
  7454. initialize: function (latLngBounds, options) {
  7455. L.Polygon.prototype.initialize.call(this, this._boundsToLatLngs(latLngBounds), options);
  7456. },
  7457. // @method setBounds(latLngBounds: LatLngBounds): this
  7458. // Redraws the rectangle with the passed bounds.
  7459. setBounds: function (latLngBounds) {
  7460. return this.setLatLngs(this._boundsToLatLngs(latLngBounds));
  7461. },
  7462. _boundsToLatLngs: function (latLngBounds) {
  7463. latLngBounds = L.latLngBounds(latLngBounds);
  7464. return [
  7465. latLngBounds.getSouthWest(),
  7466. latLngBounds.getNorthWest(),
  7467. latLngBounds.getNorthEast(),
  7468. latLngBounds.getSouthEast()
  7469. ];
  7470. }
  7471. });
  7472. // @factory L.rectangle(latLngBounds: LatLngBounds, options?: Polyline options)
  7473. L.rectangle = function (latLngBounds, options) {
  7474. return new L.Rectangle(latLngBounds, options);
  7475. };
  7476. /*
  7477. * @class CircleMarker
  7478. * @aka L.CircleMarker
  7479. * @inherits Path
  7480. *
  7481. * A circle of a fixed size with radius specified in pixels. Extends `Path`.
  7482. */
  7483. L.CircleMarker = L.Path.extend({
  7484. // @section
  7485. // @aka CircleMarker options
  7486. options: {
  7487. fill: true,
  7488. // @option radius: Number = 10
  7489. // Radius of the circle marker, in pixels
  7490. radius: 10
  7491. },
  7492. initialize: function (latlng, options) {
  7493. L.setOptions(this, options);
  7494. this._latlng = L.latLng(latlng);
  7495. this._radius = this.options.radius;
  7496. },
  7497. // @method setLatLng(latLng: LatLng): this
  7498. // Sets the position of a circle marker to a new location.
  7499. setLatLng: function (latlng) {
  7500. this._latlng = L.latLng(latlng);
  7501. this.redraw();
  7502. return this.fire('move', {latlng: this._latlng});
  7503. },
  7504. // @method getLatLng(): LatLng
  7505. // Returns the current geographical position of the circle marker
  7506. getLatLng: function () {
  7507. return this._latlng;
  7508. },
  7509. // @method setRadius(radius: Number): this
  7510. // Sets the radius of a circle marker. Units are in pixels.
  7511. setRadius: function (radius) {
  7512. this.options.radius = this._radius = radius;
  7513. return this.redraw();
  7514. },
  7515. // @method getRadius(): Number
  7516. // Returns the current radius of the circle
  7517. getRadius: function () {
  7518. return this._radius;
  7519. },
  7520. setStyle : function (options) {
  7521. var radius = options && options.radius || this._radius;
  7522. L.Path.prototype.setStyle.call(this, options);
  7523. this.setRadius(radius);
  7524. return this;
  7525. },
  7526. _project: function () {
  7527. this._point = this._map.latLngToLayerPoint(this._latlng);
  7528. this._updateBounds();
  7529. },
  7530. _updateBounds: function () {
  7531. var r = this._radius,
  7532. r2 = this._radiusY || r,
  7533. w = this._clickTolerance(),
  7534. p = [r + w, r2 + w];
  7535. this._pxBounds = new L.Bounds(this._point.subtract(p), this._point.add(p));
  7536. },
  7537. _update: function () {
  7538. if (this._map) {
  7539. this._updatePath();
  7540. }
  7541. },
  7542. _updatePath: function () {
  7543. this._renderer._updateCircle(this);
  7544. },
  7545. _empty: function () {
  7546. return this._radius && !this._renderer._bounds.intersects(this._pxBounds);
  7547. }
  7548. });
  7549. // @factory L.circleMarker(latlng: LatLng, options?: CircleMarker options)
  7550. // Instantiates a circle marker object given a geographical point, and an optional options object.
  7551. L.circleMarker = function (latlng, options) {
  7552. return new L.CircleMarker(latlng, options);
  7553. };
  7554. /*
  7555. * @class Circle
  7556. * @aka L.Circle
  7557. * @inherits CircleMarker
  7558. *
  7559. * A class for drawing circle overlays on a map. Extends `CircleMarker`.
  7560. *
  7561. * It's an approximation and starts to diverge from a real circle closer to poles (due to projection distortion).
  7562. *
  7563. * @example
  7564. *
  7565. * ```js
  7566. * L.circle([50.5, 30.5], {radius: 200}).addTo(map);
  7567. * ```
  7568. */
  7569. L.Circle = L.CircleMarker.extend({
  7570. initialize: function (latlng, options, legacyOptions) {
  7571. if (typeof options === 'number') {
  7572. // Backwards compatibility with 0.7.x factory (latlng, radius, options?)
  7573. options = L.extend({}, legacyOptions, {radius: options});
  7574. }
  7575. L.setOptions(this, options);
  7576. this._latlng = L.latLng(latlng);
  7577. if (isNaN(this.options.radius)) { throw new Error('Circle radius cannot be NaN'); }
  7578. // @section
  7579. // @aka Circle options
  7580. // @option radius: Number; Radius of the circle, in meters.
  7581. this._mRadius = this.options.radius;
  7582. },
  7583. // @method setRadius(radius: Number): this
  7584. // Sets the radius of a circle. Units are in meters.
  7585. setRadius: function (radius) {
  7586. this._mRadius = radius;
  7587. return this.redraw();
  7588. },
  7589. // @method getRadius(): Number
  7590. // Returns the current radius of a circle. Units are in meters.
  7591. getRadius: function () {
  7592. return this._mRadius;
  7593. },
  7594. // @method getBounds(): LatLngBounds
  7595. // Returns the `LatLngBounds` of the path.
  7596. getBounds: function () {
  7597. var half = [this._radius, this._radiusY || this._radius];
  7598. return new L.LatLngBounds(
  7599. this._map.layerPointToLatLng(this._point.subtract(half)),
  7600. this._map.layerPointToLatLng(this._point.add(half)));
  7601. },
  7602. setStyle: L.Path.prototype.setStyle,
  7603. _project: function () {
  7604. var lng = this._latlng.lng,
  7605. lat = this._latlng.lat,
  7606. map = this._map,
  7607. crs = map.options.crs;
  7608. if (crs.distance === L.CRS.Earth.distance) {
  7609. var d = Math.PI / 180,
  7610. latR = (this._mRadius / L.CRS.Earth.R) / d,
  7611. top = map.project([lat + latR, lng]),
  7612. bottom = map.project([lat - latR, lng]),
  7613. p = top.add(bottom).divideBy(2),
  7614. lat2 = map.unproject(p).lat,
  7615. lngR = Math.acos((Math.cos(latR * d) - Math.sin(lat * d) * Math.sin(lat2 * d)) /
  7616. (Math.cos(lat * d) * Math.cos(lat2 * d))) / d;
  7617. if (isNaN(lngR) || lngR === 0) {
  7618. lngR = latR / Math.cos(Math.PI / 180 * lat); // Fallback for edge case, #2425
  7619. }
  7620. this._point = p.subtract(map.getPixelOrigin());
  7621. this._radius = isNaN(lngR) ? 0 : Math.max(Math.round(p.x - map.project([lat2, lng - lngR]).x), 1);
  7622. this._radiusY = Math.max(Math.round(p.y - top.y), 1);
  7623. } else {
  7624. var latlng2 = crs.unproject(crs.project(this._latlng).subtract([this._mRadius, 0]));
  7625. this._point = map.latLngToLayerPoint(this._latlng);
  7626. this._radius = this._point.x - map.latLngToLayerPoint(latlng2).x;
  7627. }
  7628. this._updateBounds();
  7629. }
  7630. });
  7631. // @factory L.circle(latlng: LatLng, options?: Circle options)
  7632. // Instantiates a circle object given a geographical point, and an options object
  7633. // which contains the circle radius.
  7634. // @alternative
  7635. // @factory L.circle(latlng: LatLng, radius: Number, options?: Circle options)
  7636. // Obsolete way of instantiating a circle, for compatibility with 0.7.x code.
  7637. // Do not use in new applications or plugins.
  7638. L.circle = function (latlng, options, legacyOptions) {
  7639. return new L.Circle(latlng, options, legacyOptions);
  7640. };
  7641. /*
  7642. * @class SVG
  7643. * @inherits Renderer
  7644. * @aka L.SVG
  7645. *
  7646. * Allows vector layers to be displayed with [SVG](https://developer.mozilla.org/docs/Web/SVG).
  7647. * Inherits `Renderer`.
  7648. *
  7649. * Due to [technical limitations](http://caniuse.com/#search=svg), SVG is not
  7650. * available in all web browsers, notably Android 2.x and 3.x.
  7651. *
  7652. * Although SVG is not available on IE7 and IE8, these browsers support
  7653. * [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language)
  7654. * (a now deprecated technology), and the SVG renderer will fall back to VML in
  7655. * this case.
  7656. *
  7657. * @example
  7658. *
  7659. * Use SVG by default for all paths in the map:
  7660. *
  7661. * ```js
  7662. * var map = L.map('map', {
  7663. * renderer: L.svg()
  7664. * });
  7665. * ```
  7666. *
  7667. * Use a SVG renderer with extra padding for specific vector geometries:
  7668. *
  7669. * ```js
  7670. * var map = L.map('map');
  7671. * var myRenderer = L.svg({ padding: 0.5 });
  7672. * var line = L.polyline( coordinates, { renderer: myRenderer } );
  7673. * var circle = L.circle( center, { renderer: myRenderer } );
  7674. * ```
  7675. */
  7676. L.SVG = L.Renderer.extend({
  7677. getEvents: function () {
  7678. var events = L.Renderer.prototype.getEvents.call(this);
  7679. events.zoomstart = this._onZoomStart;
  7680. return events;
  7681. },
  7682. _initContainer: function () {
  7683. this._container = L.SVG.create('svg');
  7684. // makes it possible to click through svg root; we'll reset it back in individual paths
  7685. this._container.setAttribute('pointer-events', 'none');
  7686. this._rootGroup = L.SVG.create('g');
  7687. this._container.appendChild(this._rootGroup);
  7688. },
  7689. _onZoomStart: function () {
  7690. // Drag-then-pinch interactions might mess up the center and zoom.
  7691. // In this case, the easiest way to prevent this is re-do the renderer
  7692. // bounds and padding when the zooming starts.
  7693. this._update();
  7694. },
  7695. _update: function () {
  7696. if (this._map._animatingZoom && this._bounds) { return; }
  7697. L.Renderer.prototype._update.call(this);
  7698. var b = this._bounds,
  7699. size = b.getSize(),
  7700. container = this._container;
  7701. // set size of svg-container if changed
  7702. if (!this._svgSize || !this._svgSize.equals(size)) {
  7703. this._svgSize = size;
  7704. container.setAttribute('width', size.x);
  7705. container.setAttribute('height', size.y);
  7706. }
  7707. // movement: update container viewBox so that we don't have to change coordinates of individual layers
  7708. L.DomUtil.setPosition(container, b.min);
  7709. container.setAttribute('viewBox', [b.min.x, b.min.y, size.x, size.y].join(' '));
  7710. this.fire('update');
  7711. },
  7712. // methods below are called by vector layers implementations
  7713. _initPath: function (layer) {
  7714. var path = layer._path = L.SVG.create('path');
  7715. // @namespace Path
  7716. // @option className: String = null
  7717. // Custom class name set on an element. Only for SVG renderer.
  7718. if (layer.options.className) {
  7719. L.DomUtil.addClass(path, layer.options.className);
  7720. }
  7721. if (layer.options.interactive) {
  7722. L.DomUtil.addClass(path, 'leaflet-interactive');
  7723. }
  7724. this._updateStyle(layer);
  7725. this._layers[L.stamp(layer)] = layer;
  7726. },
  7727. _addPath: function (layer) {
  7728. this._rootGroup.appendChild(layer._path);
  7729. layer.addInteractiveTarget(layer._path);
  7730. },
  7731. _removePath: function (layer) {
  7732. L.DomUtil.remove(layer._path);
  7733. layer.removeInteractiveTarget(layer._path);
  7734. delete this._layers[L.stamp(layer)];
  7735. },
  7736. _updatePath: function (layer) {
  7737. layer._project();
  7738. layer._update();
  7739. },
  7740. _updateStyle: function (layer) {
  7741. var path = layer._path,
  7742. options = layer.options;
  7743. if (!path) { return; }
  7744. if (options.stroke) {
  7745. path.setAttribute('stroke', options.color);
  7746. path.setAttribute('stroke-opacity', options.opacity);
  7747. path.setAttribute('stroke-width', options.weight);
  7748. path.setAttribute('stroke-linecap', options.lineCap);
  7749. path.setAttribute('stroke-linejoin', options.lineJoin);
  7750. if (options.dashArray) {
  7751. path.setAttribute('stroke-dasharray', options.dashArray);
  7752. } else {
  7753. path.removeAttribute('stroke-dasharray');
  7754. }
  7755. if (options.dashOffset) {
  7756. path.setAttribute('stroke-dashoffset', options.dashOffset);
  7757. } else {
  7758. path.removeAttribute('stroke-dashoffset');
  7759. }
  7760. } else {
  7761. path.setAttribute('stroke', 'none');
  7762. }
  7763. if (options.fill) {
  7764. path.setAttribute('fill', options.fillColor || options.color);
  7765. path.setAttribute('fill-opacity', options.fillOpacity);
  7766. path.setAttribute('fill-rule', options.fillRule || 'evenodd');
  7767. } else {
  7768. path.setAttribute('fill', 'none');
  7769. }
  7770. },
  7771. _updatePoly: function (layer, closed) {
  7772. this._setPath(layer, L.SVG.pointsToPath(layer._parts, closed));
  7773. },
  7774. _updateCircle: function (layer) {
  7775. var p = layer._point,
  7776. r = layer._radius,
  7777. r2 = layer._radiusY || r,
  7778. arc = 'a' + r + ',' + r2 + ' 0 1,0 ';
  7779. // drawing a circle with two half-arcs
  7780. var d = layer._empty() ? 'M0 0' :
  7781. 'M' + (p.x - r) + ',' + p.y +
  7782. arc + (r * 2) + ',0 ' +
  7783. arc + (-r * 2) + ',0 ';
  7784. this._setPath(layer, d);
  7785. },
  7786. _setPath: function (layer, path) {
  7787. layer._path.setAttribute('d', path);
  7788. },
  7789. // SVG does not have the concept of zIndex so we resort to changing the DOM order of elements
  7790. _bringToFront: function (layer) {
  7791. L.DomUtil.toFront(layer._path);
  7792. },
  7793. _bringToBack: function (layer) {
  7794. L.DomUtil.toBack(layer._path);
  7795. }
  7796. });
  7797. // @namespace SVG; @section
  7798. // There are several static functions which can be called without instantiating L.SVG:
  7799. L.extend(L.SVG, {
  7800. // @function create(name: String): SVGElement
  7801. // Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement),
  7802. // corresponding to the class name passed. For example, using 'line' will return
  7803. // an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement).
  7804. create: function (name) {
  7805. return document.createElementNS('http://www.w3.org/2000/svg', name);
  7806. },
  7807. // @function pointsToPath(rings: Point[], closed: Boolean): String
  7808. // Generates a SVG path string for multiple rings, with each ring turning
  7809. // into "M..L..L.." instructions
  7810. pointsToPath: function (rings, closed) {
  7811. var str = '',
  7812. i, j, len, len2, points, p;
  7813. for (i = 0, len = rings.length; i < len; i++) {
  7814. points = rings[i];
  7815. for (j = 0, len2 = points.length; j < len2; j++) {
  7816. p = points[j];
  7817. str += (j ? 'L' : 'M') + p.x + ' ' + p.y;
  7818. }
  7819. // closes the ring for polygons; "x" is VML syntax
  7820. str += closed ? (L.Browser.svg ? 'z' : 'x') : '';
  7821. }
  7822. // SVG complains about empty path strings
  7823. return str || 'M0 0';
  7824. }
  7825. });
  7826. // @namespace Browser; @property svg: Boolean
  7827. // `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG).
  7828. L.Browser.svg = !!(document.createElementNS && L.SVG.create('svg').createSVGRect);
  7829. // @namespace SVG
  7830. // @factory L.svg(options?: Renderer options)
  7831. // Creates a SVG renderer with the given options.
  7832. L.svg = function (options) {
  7833. return L.Browser.svg || L.Browser.vml ? new L.SVG(options) : null;
  7834. };
  7835. /*
  7836. * Thanks to Dmitry Baranovsky and his Raphael library for inspiration!
  7837. */
  7838. /*
  7839. * @class SVG
  7840. *
  7841. * Although SVG is not available on IE7 and IE8, these browsers support [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language), and the SVG renderer will fall back to VML in this case.
  7842. *
  7843. * VML was deprecated in 2012, which means VML functionality exists only for backwards compatibility
  7844. * with old versions of Internet Explorer.
  7845. */
  7846. // @namespace Browser; @property vml: Boolean
  7847. // `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language).
  7848. L.Browser.vml = !L.Browser.svg && (function () {
  7849. try {
  7850. var div = document.createElement('div');
  7851. div.innerHTML = '<v:shape adj="1"/>';
  7852. var shape = div.firstChild;
  7853. shape.style.behavior = 'url(#default#VML)';
  7854. return shape && (typeof shape.adj === 'object');
  7855. } catch (e) {
  7856. return false;
  7857. }
  7858. }());
  7859. // redefine some SVG methods to handle VML syntax which is similar but with some differences
  7860. L.SVG.include(!L.Browser.vml ? {} : {
  7861. _initContainer: function () {
  7862. this._container = L.DomUtil.create('div', 'leaflet-vml-container');
  7863. },
  7864. _update: function () {
  7865. if (this._map._animatingZoom) { return; }
  7866. L.Renderer.prototype._update.call(this);
  7867. this.fire('update');
  7868. },
  7869. _initPath: function (layer) {
  7870. var container = layer._container = L.SVG.create('shape');
  7871. L.DomUtil.addClass(container, 'leaflet-vml-shape ' + (this.options.className || ''));
  7872. container.coordsize = '1 1';
  7873. layer._path = L.SVG.create('path');
  7874. container.appendChild(layer._path);
  7875. this._updateStyle(layer);
  7876. },
  7877. _addPath: function (layer) {
  7878. var container = layer._container;
  7879. this._container.appendChild(container);
  7880. if (layer.options.interactive) {
  7881. layer.addInteractiveTarget(container);
  7882. }
  7883. },
  7884. _removePath: function (layer) {
  7885. var container = layer._container;
  7886. L.DomUtil.remove(container);
  7887. layer.removeInteractiveTarget(container);
  7888. },
  7889. _updateStyle: function (layer) {
  7890. var stroke = layer._stroke,
  7891. fill = layer._fill,
  7892. options = layer.options,
  7893. container = layer._container;
  7894. container.stroked = !!options.stroke;
  7895. container.filled = !!options.fill;
  7896. if (options.stroke) {
  7897. if (!stroke) {
  7898. stroke = layer._stroke = L.SVG.create('stroke');
  7899. }
  7900. container.appendChild(stroke);
  7901. stroke.weight = options.weight + 'px';
  7902. stroke.color = options.color;
  7903. stroke.opacity = options.opacity;
  7904. if (options.dashArray) {
  7905. stroke.dashStyle = L.Util.isArray(options.dashArray) ?
  7906. options.dashArray.join(' ') :
  7907. options.dashArray.replace(/( *, *)/g, ' ');
  7908. } else {
  7909. stroke.dashStyle = '';
  7910. }
  7911. stroke.endcap = options.lineCap.replace('butt', 'flat');
  7912. stroke.joinstyle = options.lineJoin;
  7913. } else if (stroke) {
  7914. container.removeChild(stroke);
  7915. layer._stroke = null;
  7916. }
  7917. if (options.fill) {
  7918. if (!fill) {
  7919. fill = layer._fill = L.SVG.create('fill');
  7920. }
  7921. container.appendChild(fill);
  7922. fill.color = options.fillColor || options.color;
  7923. fill.opacity = options.fillOpacity;
  7924. } else if (fill) {
  7925. container.removeChild(fill);
  7926. layer._fill = null;
  7927. }
  7928. },
  7929. _updateCircle: function (layer) {
  7930. var p = layer._point.round(),
  7931. r = Math.round(layer._radius),
  7932. r2 = Math.round(layer._radiusY || r);
  7933. this._setPath(layer, layer._empty() ? 'M0 0' :
  7934. 'AL ' + p.x + ',' + p.y + ' ' + r + ',' + r2 + ' 0,' + (65535 * 360));
  7935. },
  7936. _setPath: function (layer, path) {
  7937. layer._path.v = path;
  7938. },
  7939. _bringToFront: function (layer) {
  7940. L.DomUtil.toFront(layer._container);
  7941. },
  7942. _bringToBack: function (layer) {
  7943. L.DomUtil.toBack(layer._container);
  7944. }
  7945. });
  7946. if (L.Browser.vml) {
  7947. L.SVG.create = (function () {
  7948. try {
  7949. document.namespaces.add('lvml', 'urn:schemas-microsoft-com:vml');
  7950. return function (name) {
  7951. return document.createElement('<lvml:' + name + ' class="lvml">');
  7952. };
  7953. } catch (e) {
  7954. return function (name) {
  7955. return document.createElement('<' + name + ' xmlns="urn:schemas-microsoft.com:vml" class="lvml">');
  7956. };
  7957. }
  7958. })();
  7959. }
  7960. /*
  7961. * @class Canvas
  7962. * @inherits Renderer
  7963. * @aka L.Canvas
  7964. *
  7965. * Allows vector layers to be displayed with [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
  7966. * Inherits `Renderer`.
  7967. *
  7968. * Due to [technical limitations](http://caniuse.com/#search=canvas), Canvas is not
  7969. * available in all web browsers, notably IE8, and overlapping geometries might
  7970. * not display properly in some edge cases.
  7971. *
  7972. * @example
  7973. *
  7974. * Use Canvas by default for all paths in the map:
  7975. *
  7976. * ```js
  7977. * var map = L.map('map', {
  7978. * renderer: L.canvas()
  7979. * });
  7980. * ```
  7981. *
  7982. * Use a Canvas renderer with extra padding for specific vector geometries:
  7983. *
  7984. * ```js
  7985. * var map = L.map('map');
  7986. * var myRenderer = L.canvas({ padding: 0.5 });
  7987. * var line = L.polyline( coordinates, { renderer: myRenderer } );
  7988. * var circle = L.circle( center, { renderer: myRenderer } );
  7989. * ```
  7990. */
  7991. L.Canvas = L.Renderer.extend({
  7992. onAdd: function () {
  7993. L.Renderer.prototype.onAdd.call(this);
  7994. // Redraw vectors since canvas is cleared upon removal,
  7995. // in case of removing the renderer itself from the map.
  7996. this._draw();
  7997. },
  7998. _initContainer: function () {
  7999. var container = this._container = document.createElement('canvas');
  8000. L.DomEvent
  8001. .on(container, 'mousemove', L.Util.throttle(this._onMouseMove, 32, this), this)
  8002. .on(container, 'click dblclick mousedown mouseup contextmenu', this._onClick, this)
  8003. .on(container, 'mouseout', this._handleMouseOut, this);
  8004. this._ctx = container.getContext('2d');
  8005. },
  8006. _updatePaths: function () {
  8007. var layer;
  8008. this._redrawBounds = null;
  8009. for (var id in this._layers) {
  8010. layer = this._layers[id];
  8011. layer._update();
  8012. }
  8013. this._redraw();
  8014. },
  8015. _update: function () {
  8016. if (this._map._animatingZoom && this._bounds) { return; }
  8017. this._drawnLayers = {};
  8018. L.Renderer.prototype._update.call(this);
  8019. var b = this._bounds,
  8020. container = this._container,
  8021. size = b.getSize(),
  8022. m = L.Browser.retina ? 2 : 1;
  8023. L.DomUtil.setPosition(container, b.min);
  8024. // set canvas size (also clearing it); use double size on retina
  8025. container.width = m * size.x;
  8026. container.height = m * size.y;
  8027. container.style.width = size.x + 'px';
  8028. container.style.height = size.y + 'px';
  8029. if (L.Browser.retina) {
  8030. this._ctx.scale(2, 2);
  8031. }
  8032. // translate so we use the same path coordinates after canvas element moves
  8033. this._ctx.translate(-b.min.x, -b.min.y);
  8034. // Tell paths to redraw themselves
  8035. this.fire('update');
  8036. },
  8037. _initPath: function (layer) {
  8038. this._updateDashArray(layer);
  8039. this._layers[L.stamp(layer)] = layer;
  8040. var order = layer._order = {
  8041. layer: layer,
  8042. prev: this._drawLast,
  8043. next: null
  8044. };
  8045. if (this._drawLast) { this._drawLast.next = order; }
  8046. this._drawLast = order;
  8047. this._drawFirst = this._drawFirst || this._drawLast;
  8048. },
  8049. _addPath: function (layer) {
  8050. this._requestRedraw(layer);
  8051. },
  8052. _removePath: function (layer) {
  8053. var order = layer._order;
  8054. var next = order.next;
  8055. var prev = order.prev;
  8056. if (next) {
  8057. next.prev = prev;
  8058. } else {
  8059. this._drawLast = prev;
  8060. }
  8061. if (prev) {
  8062. prev.next = next;
  8063. } else {
  8064. this._drawFirst = next;
  8065. }
  8066. delete layer._order;
  8067. delete this._layers[L.stamp(layer)];
  8068. this._requestRedraw(layer);
  8069. },
  8070. _updatePath: function (layer) {
  8071. // Redraw the union of the layer's old pixel
  8072. // bounds and the new pixel bounds.
  8073. this._extendRedrawBounds(layer);
  8074. layer._project();
  8075. layer._update();
  8076. // The redraw will extend the redraw bounds
  8077. // with the new pixel bounds.
  8078. this._requestRedraw(layer);
  8079. },
  8080. _updateStyle: function (layer) {
  8081. this._updateDashArray(layer);
  8082. this._requestRedraw(layer);
  8083. },
  8084. _updateDashArray: function (layer) {
  8085. if (layer.options.dashArray) {
  8086. var parts = layer.options.dashArray.split(','),
  8087. dashArray = [],
  8088. i;
  8089. for (i = 0; i < parts.length; i++) {
  8090. dashArray.push(Number(parts[i]));
  8091. }
  8092. layer.options._dashArray = dashArray;
  8093. }
  8094. },
  8095. _requestRedraw: function (layer) {
  8096. if (!this._map) { return; }
  8097. this._extendRedrawBounds(layer);
  8098. this._redrawRequest = this._redrawRequest || L.Util.requestAnimFrame(this._redraw, this);
  8099. },
  8100. _extendRedrawBounds: function (layer) {
  8101. var padding = (layer.options.weight || 0) + 1;
  8102. this._redrawBounds = this._redrawBounds || new L.Bounds();
  8103. this._redrawBounds.extend(layer._pxBounds.min.subtract([padding, padding]));
  8104. this._redrawBounds.extend(layer._pxBounds.max.add([padding, padding]));
  8105. },
  8106. _redraw: function () {
  8107. this._redrawRequest = null;
  8108. this._clear(); // clear layers in redraw bounds
  8109. this._draw(); // draw layers
  8110. this._redrawBounds = null;
  8111. },
  8112. _clear: function () {
  8113. var bounds = this._redrawBounds;
  8114. if (bounds) {
  8115. var size = bounds.getSize();
  8116. this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y);
  8117. } else {
  8118. this._ctx.clearRect(0, 0, this._container.width, this._container.height);
  8119. }
  8120. },
  8121. _draw: function () {
  8122. var layer, bounds = this._redrawBounds;
  8123. this._ctx.save();
  8124. if (bounds) {
  8125. var size = bounds.getSize();
  8126. this._ctx.beginPath();
  8127. this._ctx.rect(bounds.min.x, bounds.min.y, size.x, size.y);
  8128. this._ctx.clip();
  8129. }
  8130. this._drawing = true;
  8131. for (var order = this._drawFirst; order; order = order.next) {
  8132. layer = order.layer;
  8133. if (!bounds || (layer._pxBounds && layer._pxBounds.intersects(bounds))) {
  8134. layer._updatePath();
  8135. }
  8136. }
  8137. this._drawing = false;
  8138. this._ctx.restore(); // Restore state before clipping.
  8139. },
  8140. _updatePoly: function (layer, closed) {
  8141. if (!this._drawing) { return; }
  8142. var i, j, len2, p,
  8143. parts = layer._parts,
  8144. len = parts.length,
  8145. ctx = this._ctx;
  8146. if (!len) { return; }
  8147. this._drawnLayers[layer._leaflet_id] = layer;
  8148. ctx.beginPath();
  8149. if (ctx.setLineDash) {
  8150. ctx.setLineDash(layer.options && layer.options._dashArray || []);
  8151. }
  8152. for (i = 0; i < len; i++) {
  8153. for (j = 0, len2 = parts[i].length; j < len2; j++) {
  8154. p = parts[i][j];
  8155. ctx[j ? 'lineTo' : 'moveTo'](p.x, p.y);
  8156. }
  8157. if (closed) {
  8158. ctx.closePath();
  8159. }
  8160. }
  8161. this._fillStroke(ctx, layer);
  8162. // TODO optimization: 1 fill/stroke for all features with equal style instead of 1 for each feature
  8163. },
  8164. _updateCircle: function (layer) {
  8165. if (!this._drawing || layer._empty()) { return; }
  8166. var p = layer._point,
  8167. ctx = this._ctx,
  8168. r = layer._radius,
  8169. s = (layer._radiusY || r) / r;
  8170. this._drawnLayers[layer._leaflet_id] = layer;
  8171. if (s !== 1) {
  8172. ctx.save();
  8173. ctx.scale(1, s);
  8174. }
  8175. ctx.beginPath();
  8176. ctx.arc(p.x, p.y / s, r, 0, Math.PI * 2, false);
  8177. if (s !== 1) {
  8178. ctx.restore();
  8179. }
  8180. this._fillStroke(ctx, layer);
  8181. },
  8182. _fillStroke: function (ctx, layer) {
  8183. var options = layer.options;
  8184. if (options.fill) {
  8185. ctx.globalAlpha = options.fillOpacity;
  8186. ctx.fillStyle = options.fillColor || options.color;
  8187. ctx.fill(options.fillRule || 'evenodd');
  8188. }
  8189. if (options.stroke && options.weight !== 0) {
  8190. ctx.globalAlpha = options.opacity;
  8191. ctx.lineWidth = options.weight;
  8192. ctx.strokeStyle = options.color;
  8193. ctx.lineCap = options.lineCap;
  8194. ctx.lineJoin = options.lineJoin;
  8195. ctx.stroke();
  8196. }
  8197. },
  8198. // Canvas obviously doesn't have mouse events for individual drawn objects,
  8199. // so we emulate that by calculating what's under the mouse on mousemove/click manually
  8200. _onClick: function (e) {
  8201. var point = this._map.mouseEventToLayerPoint(e), layer, clickedLayer;
  8202. for (var order = this._drawFirst; order; order = order.next) {
  8203. layer = order.layer;
  8204. if (layer.options.interactive && layer._containsPoint(point) && !this._map._draggableMoved(layer)) {
  8205. clickedLayer = layer;
  8206. }
  8207. }
  8208. if (clickedLayer) {
  8209. L.DomEvent._fakeStop(e);
  8210. this._fireEvent([clickedLayer], e);
  8211. }
  8212. },
  8213. _onMouseMove: function (e) {
  8214. if (!this._map || this._map.dragging.moving() || this._map._animatingZoom) { return; }
  8215. var point = this._map.mouseEventToLayerPoint(e);
  8216. this._handleMouseHover(e, point);
  8217. },
  8218. _handleMouseOut: function (e) {
  8219. var layer = this._hoveredLayer;
  8220. if (layer) {
  8221. // if we're leaving the layer, fire mouseout
  8222. L.DomUtil.removeClass(this._container, 'leaflet-interactive');
  8223. this._fireEvent([layer], e, 'mouseout');
  8224. this._hoveredLayer = null;
  8225. }
  8226. },
  8227. _handleMouseHover: function (e, point) {
  8228. var layer, candidateHoveredLayer;
  8229. for (var order = this._drawFirst; order; order = order.next) {
  8230. layer = order.layer;
  8231. if (layer.options.interactive && layer._containsPoint(point)) {
  8232. candidateHoveredLayer = layer;
  8233. }
  8234. }
  8235. if (candidateHoveredLayer !== this._hoveredLayer) {
  8236. this._handleMouseOut(e);
  8237. if (candidateHoveredLayer) {
  8238. L.DomUtil.addClass(this._container, 'leaflet-interactive'); // change cursor
  8239. this._fireEvent([candidateHoveredLayer], e, 'mouseover');
  8240. this._hoveredLayer = candidateHoveredLayer;
  8241. }
  8242. }
  8243. if (this._hoveredLayer) {
  8244. this._fireEvent([this._hoveredLayer], e);
  8245. }
  8246. },
  8247. _fireEvent: function (layers, e, type) {
  8248. this._map._fireDOMEvent(e, type || e.type, layers);
  8249. },
  8250. _bringToFront: function (layer) {
  8251. var order = layer._order;
  8252. var next = order.next;
  8253. var prev = order.prev;
  8254. if (next) {
  8255. next.prev = prev;
  8256. } else {
  8257. // Already last
  8258. return;
  8259. }
  8260. if (prev) {
  8261. prev.next = next;
  8262. } else if (next) {
  8263. // Update first entry unless this is the
  8264. // signle entry
  8265. this._drawFirst = next;
  8266. }
  8267. order.prev = this._drawLast;
  8268. this._drawLast.next = order;
  8269. order.next = null;
  8270. this._drawLast = order;
  8271. this._requestRedraw(layer);
  8272. },
  8273. _bringToBack: function (layer) {
  8274. var order = layer._order;
  8275. var next = order.next;
  8276. var prev = order.prev;
  8277. if (prev) {
  8278. prev.next = next;
  8279. } else {
  8280. // Already first
  8281. return;
  8282. }
  8283. if (next) {
  8284. next.prev = prev;
  8285. } else if (prev) {
  8286. // Update last entry unless this is the
  8287. // signle entry
  8288. this._drawLast = prev;
  8289. }
  8290. order.prev = null;
  8291. order.next = this._drawFirst;
  8292. this._drawFirst.prev = order;
  8293. this._drawFirst = order;
  8294. this._requestRedraw(layer);
  8295. }
  8296. });
  8297. // @namespace Browser; @property canvas: Boolean
  8298. // `true` when the browser supports [`<canvas>`](https://developer.mozilla.org/docs/Web/API/Canvas_API).
  8299. L.Browser.canvas = (function () {
  8300. return !!document.createElement('canvas').getContext;
  8301. }());
  8302. // @namespace Canvas
  8303. // @factory L.canvas(options?: Renderer options)
  8304. // Creates a Canvas renderer with the given options.
  8305. L.canvas = function (options) {
  8306. return L.Browser.canvas ? new L.Canvas(options) : null;
  8307. };
  8308. L.Polyline.prototype._containsPoint = function (p, closed) {
  8309. var i, j, k, len, len2, part,
  8310. w = this._clickTolerance();
  8311. if (!this._pxBounds.contains(p)) { return false; }
  8312. // hit detection for polylines
  8313. for (i = 0, len = this._parts.length; i < len; i++) {
  8314. part = this._parts[i];
  8315. for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
  8316. if (!closed && (j === 0)) { continue; }
  8317. if (L.LineUtil.pointToSegmentDistance(p, part[k], part[j]) <= w) {
  8318. return true;
  8319. }
  8320. }
  8321. }
  8322. return false;
  8323. };
  8324. L.Polygon.prototype._containsPoint = function (p) {
  8325. var inside = false,
  8326. part, p1, p2, i, j, k, len, len2;
  8327. if (!this._pxBounds.contains(p)) { return false; }
  8328. // ray casting algorithm for detecting if point is in polygon
  8329. for (i = 0, len = this._parts.length; i < len; i++) {
  8330. part = this._parts[i];
  8331. for (j = 0, len2 = part.length, k = len2 - 1; j < len2; k = j++) {
  8332. p1 = part[j];
  8333. p2 = part[k];
  8334. if (((p1.y > p.y) !== (p2.y > p.y)) && (p.x < (p2.x - p1.x) * (p.y - p1.y) / (p2.y - p1.y) + p1.x)) {
  8335. inside = !inside;
  8336. }
  8337. }
  8338. }
  8339. // also check if it's on polygon stroke
  8340. return inside || L.Polyline.prototype._containsPoint.call(this, p, true);
  8341. };
  8342. L.CircleMarker.prototype._containsPoint = function (p) {
  8343. return p.distanceTo(this._point) <= this._radius + this._clickTolerance();
  8344. };
  8345. /*
  8346. * @class GeoJSON
  8347. * @aka L.GeoJSON
  8348. * @inherits FeatureGroup
  8349. *
  8350. * Represents a GeoJSON object or an array of GeoJSON objects. Allows you to parse
  8351. * GeoJSON data and display it on the map. Extends `FeatureGroup`.
  8352. *
  8353. * @example
  8354. *
  8355. * ```js
  8356. * L.geoJSON(data, {
  8357. * style: function (feature) {
  8358. * return {color: feature.properties.color};
  8359. * }
  8360. * }).bindPopup(function (layer) {
  8361. * return layer.feature.properties.description;
  8362. * }).addTo(map);
  8363. * ```
  8364. */
  8365. L.GeoJSON = L.FeatureGroup.extend({
  8366. /* @section
  8367. * @aka GeoJSON options
  8368. *
  8369. * @option pointToLayer: Function = *
  8370. * A `Function` defining how GeoJSON points spawn Leaflet layers. It is internally
  8371. * called when data is added, passing the GeoJSON point feature and its `LatLng`.
  8372. * The default is to spawn a default `Marker`:
  8373. * ```js
  8374. * function(geoJsonPoint, latlng) {
  8375. * return L.marker(latlng);
  8376. * }
  8377. * ```
  8378. *
  8379. * @option style: Function = *
  8380. * A `Function` defining the `Path options` for styling GeoJSON lines and polygons,
  8381. * called internally when data is added.
  8382. * The default value is to not override any defaults:
  8383. * ```js
  8384. * function (geoJsonFeature) {
  8385. * return {}
  8386. * }
  8387. * ```
  8388. *
  8389. * @option onEachFeature: Function = *
  8390. * A `Function` that will be called once for each created `Feature`, after it has
  8391. * been created and styled. Useful for attaching events and popups to features.
  8392. * The default is to do nothing with the newly created layers:
  8393. * ```js
  8394. * function (feature, layer) {}
  8395. * ```
  8396. *
  8397. * @option filter: Function = *
  8398. * A `Function` that will be used to decide whether to include a feature or not.
  8399. * The default is to include all features:
  8400. * ```js
  8401. * function (geoJsonFeature) {
  8402. * return true;
  8403. * }
  8404. * ```
  8405. * Note: dynamically changing the `filter` option will have effect only on newly
  8406. * added data. It will _not_ re-evaluate already included features.
  8407. *
  8408. * @option coordsToLatLng: Function = *
  8409. * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s.
  8410. * The default is the `coordsToLatLng` static method.
  8411. */
  8412. initialize: function (geojson, options) {
  8413. L.setOptions(this, options);
  8414. this._layers = {};
  8415. if (geojson) {
  8416. this.addData(geojson);
  8417. }
  8418. },
  8419. // @method addData( <GeoJSON> data ): this
  8420. // Adds a GeoJSON object to the layer.
  8421. addData: function (geojson) {
  8422. var features = L.Util.isArray(geojson) ? geojson : geojson.features,
  8423. i, len, feature;
  8424. if (features) {
  8425. for (i = 0, len = features.length; i < len; i++) {
  8426. // only add this if geometry or geometries are set and not null
  8427. feature = features[i];
  8428. if (feature.geometries || feature.geometry || feature.features || feature.coordinates) {
  8429. this.addData(feature);
  8430. }
  8431. }
  8432. return this;
  8433. }
  8434. var options = this.options;
  8435. if (options.filter && !options.filter(geojson)) { return this; }
  8436. var layer = L.GeoJSON.geometryToLayer(geojson, options);
  8437. if (!layer) {
  8438. return this;
  8439. }
  8440. layer.feature = L.GeoJSON.asFeature(geojson);
  8441. layer.defaultOptions = layer.options;
  8442. this.resetStyle(layer);
  8443. if (options.onEachFeature) {
  8444. options.onEachFeature(geojson, layer);
  8445. }
  8446. return this.addLayer(layer);
  8447. },
  8448. // @method resetStyle( <Path> layer ): this
  8449. // Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events.
  8450. resetStyle: function (layer) {
  8451. // reset any custom styles
  8452. layer.options = L.Util.extend({}, layer.defaultOptions);
  8453. this._setLayerStyle(layer, this.options.style);
  8454. return this;
  8455. },
  8456. // @method setStyle( <Function> style ): this
  8457. // Changes styles of GeoJSON vector layers with the given style function.
  8458. setStyle: function (style) {
  8459. return this.eachLayer(function (layer) {
  8460. this._setLayerStyle(layer, style);
  8461. }, this);
  8462. },
  8463. _setLayerStyle: function (layer, style) {
  8464. if (typeof style === 'function') {
  8465. style = style(layer.feature);
  8466. }
  8467. if (layer.setStyle) {
  8468. layer.setStyle(style);
  8469. }
  8470. }
  8471. });
  8472. // @section
  8473. // There are several static functions which can be called without instantiating L.GeoJSON:
  8474. L.extend(L.GeoJSON, {
  8475. // @function geometryToLayer(featureData: Object, options?: GeoJSON options): Layer
  8476. // Creates a `Layer` from a given GeoJSON feature. Can use a custom
  8477. // [`pointToLayer`](#geojson-pointtolayer) and/or [`coordsToLatLng`](#geojson-coordstolatlng)
  8478. // functions if provided as options.
  8479. geometryToLayer: function (geojson, options) {
  8480. var geometry = geojson.type === 'Feature' ? geojson.geometry : geojson,
  8481. coords = geometry ? geometry.coordinates : null,
  8482. layers = [],
  8483. pointToLayer = options && options.pointToLayer,
  8484. coordsToLatLng = options && options.coordsToLatLng || this.coordsToLatLng,
  8485. latlng, latlngs, i, len;
  8486. if (!coords && !geometry) {
  8487. return null;
  8488. }
  8489. switch (geometry.type) {
  8490. case 'Point':
  8491. latlng = coordsToLatLng(coords);
  8492. return pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng);
  8493. case 'MultiPoint':
  8494. for (i = 0, len = coords.length; i < len; i++) {
  8495. latlng = coordsToLatLng(coords[i]);
  8496. layers.push(pointToLayer ? pointToLayer(geojson, latlng) : new L.Marker(latlng));
  8497. }
  8498. return new L.FeatureGroup(layers);
  8499. case 'LineString':
  8500. case 'MultiLineString':
  8501. latlngs = this.coordsToLatLngs(coords, geometry.type === 'LineString' ? 0 : 1, coordsToLatLng);
  8502. return new L.Polyline(latlngs, options);
  8503. case 'Polygon':
  8504. case 'MultiPolygon':
  8505. latlngs = this.coordsToLatLngs(coords, geometry.type === 'Polygon' ? 1 : 2, coordsToLatLng);
  8506. return new L.Polygon(latlngs, options);
  8507. case 'GeometryCollection':
  8508. for (i = 0, len = geometry.geometries.length; i < len; i++) {
  8509. var layer = this.geometryToLayer({
  8510. geometry: geometry.geometries[i],
  8511. type: 'Feature',
  8512. properties: geojson.properties
  8513. }, options);
  8514. if (layer) {
  8515. layers.push(layer);
  8516. }
  8517. }
  8518. return new L.FeatureGroup(layers);
  8519. default:
  8520. throw new Error('Invalid GeoJSON object.');
  8521. }
  8522. },
  8523. // @function coordsToLatLng(coords: Array): LatLng
  8524. // Creates a `LatLng` object from an array of 2 numbers (longitude, latitude)
  8525. // or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points.
  8526. coordsToLatLng: function (coords) {
  8527. return new L.LatLng(coords[1], coords[0], coords[2]);
  8528. },
  8529. // @function coordsToLatLngs(coords: Array, levelsDeep?: Number, coordsToLatLng?: Function): Array
  8530. // Creates a multidimensional array of `LatLng`s from a GeoJSON coordinates array.
  8531. // `levelsDeep` specifies the nesting level (0 is for an array of points, 1 for an array of arrays of points, etc., 0 by default).
  8532. // Can use a custom [`coordsToLatLng`](#geojson-coordstolatlng) function.
  8533. coordsToLatLngs: function (coords, levelsDeep, coordsToLatLng) {
  8534. var latlngs = [];
  8535. for (var i = 0, len = coords.length, latlng; i < len; i++) {
  8536. latlng = levelsDeep ?
  8537. this.coordsToLatLngs(coords[i], levelsDeep - 1, coordsToLatLng) :
  8538. (coordsToLatLng || this.coordsToLatLng)(coords[i]);
  8539. latlngs.push(latlng);
  8540. }
  8541. return latlngs;
  8542. },
  8543. // @function latLngToCoords(latlng: LatLng): Array
  8544. // Reverse of [`coordsToLatLng`](#geojson-coordstolatlng)
  8545. latLngToCoords: function (latlng) {
  8546. return latlng.alt !== undefined ?
  8547. [latlng.lng, latlng.lat, latlng.alt] :
  8548. [latlng.lng, latlng.lat];
  8549. },
  8550. // @function latLngsToCoords(latlngs: Array, levelsDeep?: Number, closed?: Boolean): Array
  8551. // Reverse of [`coordsToLatLngs`](#geojson-coordstolatlngs)
  8552. // `closed` determines whether the first point should be appended to the end of the array to close the feature, only used when `levelsDeep` is 0. False by default.
  8553. latLngsToCoords: function (latlngs, levelsDeep, closed) {
  8554. var coords = [];
  8555. for (var i = 0, len = latlngs.length; i < len; i++) {
  8556. coords.push(levelsDeep ?
  8557. L.GeoJSON.latLngsToCoords(latlngs[i], levelsDeep - 1, closed) :
  8558. L.GeoJSON.latLngToCoords(latlngs[i]));
  8559. }
  8560. if (!levelsDeep && closed) {
  8561. coords.push(coords[0]);
  8562. }
  8563. return coords;
  8564. },
  8565. getFeature: function (layer, newGeometry) {
  8566. return layer.feature ?
  8567. L.extend({}, layer.feature, {geometry: newGeometry}) :
  8568. L.GeoJSON.asFeature(newGeometry);
  8569. },
  8570. // @function asFeature(geojson: Object): Object
  8571. // Normalize GeoJSON geometries/features into GeoJSON features.
  8572. asFeature: function (geojson) {
  8573. if (geojson.type === 'Feature' || geojson.type === 'FeatureCollection') {
  8574. return geojson;
  8575. }
  8576. return {
  8577. type: 'Feature',
  8578. properties: {},
  8579. geometry: geojson
  8580. };
  8581. }
  8582. });
  8583. var PointToGeoJSON = {
  8584. toGeoJSON: function () {
  8585. return L.GeoJSON.getFeature(this, {
  8586. type: 'Point',
  8587. coordinates: L.GeoJSON.latLngToCoords(this.getLatLng())
  8588. });
  8589. }
  8590. };
  8591. // @namespace Marker
  8592. // @method toGeoJSON(): Object
  8593. // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the marker (as a GeoJSON `Point` Feature).
  8594. L.Marker.include(PointToGeoJSON);
  8595. // @namespace CircleMarker
  8596. // @method toGeoJSON(): Object
  8597. // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the circle marker (as a GeoJSON `Point` Feature).
  8598. L.Circle.include(PointToGeoJSON);
  8599. L.CircleMarker.include(PointToGeoJSON);
  8600. // @namespace Polyline
  8601. // @method toGeoJSON(): Object
  8602. // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polyline (as a GeoJSON `LineString` or `MultiLineString` Feature).
  8603. L.Polyline.prototype.toGeoJSON = function () {
  8604. var multi = !L.Polyline._flat(this._latlngs);
  8605. var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 1 : 0);
  8606. return L.GeoJSON.getFeature(this, {
  8607. type: (multi ? 'Multi' : '') + 'LineString',
  8608. coordinates: coords
  8609. });
  8610. };
  8611. // @namespace Polygon
  8612. // @method toGeoJSON(): Object
  8613. // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the polygon (as a GeoJSON `Polygon` or `MultiPolygon` Feature).
  8614. L.Polygon.prototype.toGeoJSON = function () {
  8615. var holes = !L.Polyline._flat(this._latlngs),
  8616. multi = holes && !L.Polyline._flat(this._latlngs[0]);
  8617. var coords = L.GeoJSON.latLngsToCoords(this._latlngs, multi ? 2 : holes ? 1 : 0, true);
  8618. if (!holes) {
  8619. coords = [coords];
  8620. }
  8621. return L.GeoJSON.getFeature(this, {
  8622. type: (multi ? 'Multi' : '') + 'Polygon',
  8623. coordinates: coords
  8624. });
  8625. };
  8626. // @namespace LayerGroup
  8627. L.LayerGroup.include({
  8628. toMultiPoint: function () {
  8629. var coords = [];
  8630. this.eachLayer(function (layer) {
  8631. coords.push(layer.toGeoJSON().geometry.coordinates);
  8632. });
  8633. return L.GeoJSON.getFeature(this, {
  8634. type: 'MultiPoint',
  8635. coordinates: coords
  8636. });
  8637. },
  8638. // @method toGeoJSON(): Object
  8639. // Returns a [`GeoJSON`](http://en.wikipedia.org/wiki/GeoJSON) representation of the layer group (as a GeoJSON `GeometryCollection`).
  8640. toGeoJSON: function () {
  8641. var type = this.feature && this.feature.geometry && this.feature.geometry.type;
  8642. if (type === 'MultiPoint') {
  8643. return this.toMultiPoint();
  8644. }
  8645. var isGeometryCollection = type === 'GeometryCollection',
  8646. jsons = [];
  8647. this.eachLayer(function (layer) {
  8648. if (layer.toGeoJSON) {
  8649. var json = layer.toGeoJSON();
  8650. jsons.push(isGeometryCollection ? json.geometry : L.GeoJSON.asFeature(json));
  8651. }
  8652. });
  8653. if (isGeometryCollection) {
  8654. return L.GeoJSON.getFeature(this, {
  8655. geometries: jsons,
  8656. type: 'GeometryCollection'
  8657. });
  8658. }
  8659. return {
  8660. type: 'FeatureCollection',
  8661. features: jsons
  8662. };
  8663. }
  8664. });
  8665. // @namespace GeoJSON
  8666. // @factory L.geoJSON(geojson?: Object, options?: GeoJSON options)
  8667. // Creates a GeoJSON layer. Optionally accepts an object in
  8668. // [GeoJSON format](http://geojson.org/geojson-spec.html) to display on the map
  8669. // (you can alternatively add it later with `addData` method) and an `options` object.
  8670. L.geoJSON = function (geojson, options) {
  8671. return new L.GeoJSON(geojson, options);
  8672. };
  8673. // Backward compatibility.
  8674. L.geoJson = L.geoJSON;
  8675. /*
  8676. * @class Draggable
  8677. * @aka L.Draggable
  8678. * @inherits Evented
  8679. *
  8680. * A class for making DOM elements draggable (including touch support).
  8681. * Used internally for map and marker dragging. Only works for elements
  8682. * that were positioned with [`L.DomUtil.setPosition`](#domutil-setposition).
  8683. *
  8684. * @example
  8685. * ```js
  8686. * var draggable = new L.Draggable(elementToDrag);
  8687. * draggable.enable();
  8688. * ```
  8689. */
  8690. L.Draggable = L.Evented.extend({
  8691. options: {
  8692. // @option clickTolerance: Number = 3
  8693. // The max number of pixels a user can shift the mouse pointer during a click
  8694. // for it to be considered a valid click (as opposed to a mouse drag).
  8695. clickTolerance: 3
  8696. },
  8697. statics: {
  8698. START: L.Browser.touch ? ['touchstart', 'mousedown'] : ['mousedown'],
  8699. END: {
  8700. mousedown: 'mouseup',
  8701. touchstart: 'touchend',
  8702. pointerdown: 'touchend',
  8703. MSPointerDown: 'touchend'
  8704. },
  8705. MOVE: {
  8706. mousedown: 'mousemove',
  8707. touchstart: 'touchmove',
  8708. pointerdown: 'touchmove',
  8709. MSPointerDown: 'touchmove'
  8710. }
  8711. },
  8712. // @constructor L.Draggable(el: HTMLElement, dragHandle?: HTMLElement, preventOutline: Boolean)
  8713. // Creates a `Draggable` object for moving `el` when you start dragging the `dragHandle` element (equals `el` itself by default).
  8714. initialize: function (element, dragStartTarget, preventOutline) {
  8715. this._element = element;
  8716. this._dragStartTarget = dragStartTarget || element;
  8717. this._preventOutline = preventOutline;
  8718. },
  8719. // @method enable()
  8720. // Enables the dragging ability
  8721. enable: function () {
  8722. if (this._enabled) { return; }
  8723. L.DomEvent.on(this._dragStartTarget, L.Draggable.START.join(' '), this._onDown, this);
  8724. this._enabled = true;
  8725. },
  8726. // @method disable()
  8727. // Disables the dragging ability
  8728. disable: function () {
  8729. if (!this._enabled) { return; }
  8730. // If we're currently dragging this draggable,
  8731. // disabling it counts as first ending the drag.
  8732. if (L.Draggable._dragging === this) {
  8733. this.finishDrag();
  8734. }
  8735. L.DomEvent.off(this._dragStartTarget, L.Draggable.START.join(' '), this._onDown, this);
  8736. this._enabled = false;
  8737. this._moved = false;
  8738. },
  8739. _onDown: function (e) {
  8740. // Ignore simulated events, since we handle both touch and
  8741. // mouse explicitly; otherwise we risk getting duplicates of
  8742. // touch events, see #4315.
  8743. // Also ignore the event if disabled; this happens in IE11
  8744. // under some circumstances, see #3666.
  8745. if (e._simulated || !this._enabled) { return; }
  8746. this._moved = false;
  8747. if (L.DomUtil.hasClass(this._element, 'leaflet-zoom-anim')) { return; }
  8748. if (L.Draggable._dragging || e.shiftKey || ((e.which !== 1) && (e.button !== 1) && !e.touches)) { return; }
  8749. L.Draggable._dragging = this; // Prevent dragging multiple objects at once.
  8750. if (this._preventOutline) {
  8751. L.DomUtil.preventOutline(this._element);
  8752. }
  8753. L.DomUtil.disableImageDrag();
  8754. L.DomUtil.disableTextSelection();
  8755. if (this._moving) { return; }
  8756. // @event down: Event
  8757. // Fired when a drag is about to start.
  8758. this.fire('down');
  8759. var first = e.touches ? e.touches[0] : e;
  8760. this._startPoint = new L.Point(first.clientX, first.clientY);
  8761. L.DomEvent
  8762. .on(document, L.Draggable.MOVE[e.type], this._onMove, this)
  8763. .on(document, L.Draggable.END[e.type], this._onUp, this);
  8764. },
  8765. _onMove: function (e) {
  8766. // Ignore simulated events, since we handle both touch and
  8767. // mouse explicitly; otherwise we risk getting duplicates of
  8768. // touch events, see #4315.
  8769. // Also ignore the event if disabled; this happens in IE11
  8770. // under some circumstances, see #3666.
  8771. if (e._simulated || !this._enabled) { return; }
  8772. if (e.touches && e.touches.length > 1) {
  8773. this._moved = true;
  8774. return;
  8775. }
  8776. var first = (e.touches && e.touches.length === 1 ? e.touches[0] : e),
  8777. newPoint = new L.Point(first.clientX, first.clientY),
  8778. offset = newPoint.subtract(this._startPoint);
  8779. if (!offset.x && !offset.y) { return; }
  8780. if (Math.abs(offset.x) + Math.abs(offset.y) < this.options.clickTolerance) { return; }
  8781. L.DomEvent.preventDefault(e);
  8782. if (!this._moved) {
  8783. // @event dragstart: Event
  8784. // Fired when a drag starts
  8785. this.fire('dragstart');
  8786. this._moved = true;
  8787. this._startPos = L.DomUtil.getPosition(this._element).subtract(offset);
  8788. L.DomUtil.addClass(document.body, 'leaflet-dragging');
  8789. this._lastTarget = e.target || e.srcElement;
  8790. // IE and Edge do not give the <use> element, so fetch it
  8791. // if necessary
  8792. if ((window.SVGElementInstance) && (this._lastTarget instanceof SVGElementInstance)) {
  8793. this._lastTarget = this._lastTarget.correspondingUseElement;
  8794. }
  8795. L.DomUtil.addClass(this._lastTarget, 'leaflet-drag-target');
  8796. }
  8797. this._newPos = this._startPos.add(offset);
  8798. this._moving = true;
  8799. L.Util.cancelAnimFrame(this._animRequest);
  8800. this._lastEvent = e;
  8801. this._animRequest = L.Util.requestAnimFrame(this._updatePosition, this, true);
  8802. },
  8803. _updatePosition: function () {
  8804. var e = {originalEvent: this._lastEvent};
  8805. // @event predrag: Event
  8806. // Fired continuously during dragging *before* each corresponding
  8807. // update of the element's position.
  8808. this.fire('predrag', e);
  8809. L.DomUtil.setPosition(this._element, this._newPos);
  8810. // @event drag: Event
  8811. // Fired continuously during dragging.
  8812. this.fire('drag', e);
  8813. },
  8814. _onUp: function (e) {
  8815. // Ignore simulated events, since we handle both touch and
  8816. // mouse explicitly; otherwise we risk getting duplicates of
  8817. // touch events, see #4315.
  8818. // Also ignore the event if disabled; this happens in IE11
  8819. // under some circumstances, see #3666.
  8820. if (e._simulated || !this._enabled) { return; }
  8821. this.finishDrag();
  8822. },
  8823. finishDrag: function () {
  8824. L.DomUtil.removeClass(document.body, 'leaflet-dragging');
  8825. if (this._lastTarget) {
  8826. L.DomUtil.removeClass(this._lastTarget, 'leaflet-drag-target');
  8827. this._lastTarget = null;
  8828. }
  8829. for (var i in L.Draggable.MOVE) {
  8830. L.DomEvent
  8831. .off(document, L.Draggable.MOVE[i], this._onMove, this)
  8832. .off(document, L.Draggable.END[i], this._onUp, this);
  8833. }
  8834. L.DomUtil.enableImageDrag();
  8835. L.DomUtil.enableTextSelection();
  8836. if (this._moved && this._moving) {
  8837. // ensure drag is not fired after dragend
  8838. L.Util.cancelAnimFrame(this._animRequest);
  8839. // @event dragend: DragEndEvent
  8840. // Fired when the drag ends.
  8841. this.fire('dragend', {
  8842. distance: this._newPos.distanceTo(this._startPos)
  8843. });
  8844. }
  8845. this._moving = false;
  8846. L.Draggable._dragging = false;
  8847. }
  8848. });
  8849. /*
  8850. L.Handler is a base class for handler classes that are used internally to inject
  8851. interaction features like dragging to classes like Map and Marker.
  8852. */
  8853. // @class Handler
  8854. // @aka L.Handler
  8855. // Abstract class for map interaction handlers
  8856. L.Handler = L.Class.extend({
  8857. initialize: function (map) {
  8858. this._map = map;
  8859. },
  8860. // @method enable(): this
  8861. // Enables the handler
  8862. enable: function () {
  8863. if (this._enabled) { return this; }
  8864. this._enabled = true;
  8865. this.addHooks();
  8866. return this;
  8867. },
  8868. // @method disable(): this
  8869. // Disables the handler
  8870. disable: function () {
  8871. if (!this._enabled) { return this; }
  8872. this._enabled = false;
  8873. this.removeHooks();
  8874. return this;
  8875. },
  8876. // @method enabled(): Boolean
  8877. // Returns `true` if the handler is enabled
  8878. enabled: function () {
  8879. return !!this._enabled;
  8880. }
  8881. // @section Extension methods
  8882. // Classes inheriting from `Handler` must implement the two following methods:
  8883. // @method addHooks()
  8884. // Called when the handler is enabled, should add event hooks.
  8885. // @method removeHooks()
  8886. // Called when the handler is disabled, should remove the event hooks added previously.
  8887. });
  8888. /*
  8889. * L.Handler.MapDrag is used to make the map draggable (with panning inertia), enabled by default.
  8890. */
  8891. // @namespace Map
  8892. // @section Interaction Options
  8893. L.Map.mergeOptions({
  8894. // @option dragging: Boolean = true
  8895. // Whether the map be draggable with mouse/touch or not.
  8896. dragging: true,
  8897. // @section Panning Inertia Options
  8898. // @option inertia: Boolean = *
  8899. // If enabled, panning of the map will have an inertia effect where
  8900. // the map builds momentum while dragging and continues moving in
  8901. // the same direction for some time. Feels especially nice on touch
  8902. // devices. Enabled by default unless running on old Android devices.
  8903. inertia: !L.Browser.android23,
  8904. // @option inertiaDeceleration: Number = 3000
  8905. // The rate with which the inertial movement slows down, in pixels/second².
  8906. inertiaDeceleration: 3400, // px/s^2
  8907. // @option inertiaMaxSpeed: Number = Infinity
  8908. // Max speed of the inertial movement, in pixels/second.
  8909. inertiaMaxSpeed: Infinity, // px/s
  8910. // @option easeLinearity: Number = 0.2
  8911. easeLinearity: 0.2,
  8912. // TODO refactor, move to CRS
  8913. // @option worldCopyJump: Boolean = false
  8914. // With this option enabled, the map tracks when you pan to another "copy"
  8915. // of the world and seamlessly jumps to the original one so that all overlays
  8916. // like markers and vector layers are still visible.
  8917. worldCopyJump: false,
  8918. // @option maxBoundsViscosity: Number = 0.0
  8919. // If `maxBounds` is set, this option will control how solid the bounds
  8920. // are when dragging the map around. The default value of `0.0` allows the
  8921. // user to drag outside the bounds at normal speed, higher values will
  8922. // slow down map dragging outside bounds, and `1.0` makes the bounds fully
  8923. // solid, preventing the user from dragging outside the bounds.
  8924. maxBoundsViscosity: 0.0
  8925. });
  8926. L.Map.Drag = L.Handler.extend({
  8927. addHooks: function () {
  8928. if (!this._draggable) {
  8929. var map = this._map;
  8930. this._draggable = new L.Draggable(map._mapPane, map._container);
  8931. this._draggable.on({
  8932. down: this._onDown,
  8933. dragstart: this._onDragStart,
  8934. drag: this._onDrag,
  8935. dragend: this._onDragEnd
  8936. }, this);
  8937. this._draggable.on('predrag', this._onPreDragLimit, this);
  8938. if (map.options.worldCopyJump) {
  8939. this._draggable.on('predrag', this._onPreDragWrap, this);
  8940. map.on('zoomend', this._onZoomEnd, this);
  8941. map.whenReady(this._onZoomEnd, this);
  8942. }
  8943. }
  8944. L.DomUtil.addClass(this._map._container, 'leaflet-grab leaflet-touch-drag');
  8945. this._draggable.enable();
  8946. this._positions = [];
  8947. this._times = [];
  8948. },
  8949. removeHooks: function () {
  8950. L.DomUtil.removeClass(this._map._container, 'leaflet-grab');
  8951. L.DomUtil.removeClass(this._map._container, 'leaflet-touch-drag');
  8952. this._draggable.disable();
  8953. },
  8954. moved: function () {
  8955. return this._draggable && this._draggable._moved;
  8956. },
  8957. moving: function () {
  8958. return this._draggable && this._draggable._moving;
  8959. },
  8960. _onDown: function () {
  8961. this._map._stop();
  8962. },
  8963. _onDragStart: function () {
  8964. var map = this._map;
  8965. if (this._map.options.maxBounds && this._map.options.maxBoundsViscosity) {
  8966. var bounds = L.latLngBounds(this._map.options.maxBounds);
  8967. this._offsetLimit = L.bounds(
  8968. this._map.latLngToContainerPoint(bounds.getNorthWest()).multiplyBy(-1),
  8969. this._map.latLngToContainerPoint(bounds.getSouthEast()).multiplyBy(-1)
  8970. .add(this._map.getSize()));
  8971. this._viscosity = Math.min(1.0, Math.max(0.0, this._map.options.maxBoundsViscosity));
  8972. } else {
  8973. this._offsetLimit = null;
  8974. }
  8975. map
  8976. .fire('movestart')
  8977. .fire('dragstart');
  8978. if (map.options.inertia) {
  8979. this._positions = [];
  8980. this._times = [];
  8981. }
  8982. },
  8983. _onDrag: function (e) {
  8984. if (this._map.options.inertia) {
  8985. var time = this._lastTime = +new Date(),
  8986. pos = this._lastPos = this._draggable._absPos || this._draggable._newPos;
  8987. this._positions.push(pos);
  8988. this._times.push(time);
  8989. if (time - this._times[0] > 50) {
  8990. this._positions.shift();
  8991. this._times.shift();
  8992. }
  8993. }
  8994. this._map
  8995. .fire('move', e)
  8996. .fire('drag', e);
  8997. },
  8998. _onZoomEnd: function () {
  8999. var pxCenter = this._map.getSize().divideBy(2),
  9000. pxWorldCenter = this._map.latLngToLayerPoint([0, 0]);
  9001. this._initialWorldOffset = pxWorldCenter.subtract(pxCenter).x;
  9002. this._worldWidth = this._map.getPixelWorldBounds().getSize().x;
  9003. },
  9004. _viscousLimit: function (value, threshold) {
  9005. return value - (value - threshold) * this._viscosity;
  9006. },
  9007. _onPreDragLimit: function () {
  9008. if (!this._viscosity || !this._offsetLimit) { return; }
  9009. var offset = this._draggable._newPos.subtract(this._draggable._startPos);
  9010. var limit = this._offsetLimit;
  9011. if (offset.x < limit.min.x) { offset.x = this._viscousLimit(offset.x, limit.min.x); }
  9012. if (offset.y < limit.min.y) { offset.y = this._viscousLimit(offset.y, limit.min.y); }
  9013. if (offset.x > limit.max.x) { offset.x = this._viscousLimit(offset.x, limit.max.x); }
  9014. if (offset.y > limit.max.y) { offset.y = this._viscousLimit(offset.y, limit.max.y); }
  9015. this._draggable._newPos = this._draggable._startPos.add(offset);
  9016. },
  9017. _onPreDragWrap: function () {
  9018. // TODO refactor to be able to adjust map pane position after zoom
  9019. var worldWidth = this._worldWidth,
  9020. halfWidth = Math.round(worldWidth / 2),
  9021. dx = this._initialWorldOffset,
  9022. x = this._draggable._newPos.x,
  9023. newX1 = (x - halfWidth + dx) % worldWidth + halfWidth - dx,
  9024. newX2 = (x + halfWidth + dx) % worldWidth - halfWidth - dx,
  9025. newX = Math.abs(newX1 + dx) < Math.abs(newX2 + dx) ? newX1 : newX2;
  9026. this._draggable._absPos = this._draggable._newPos.clone();
  9027. this._draggable._newPos.x = newX;
  9028. },
  9029. _onDragEnd: function (e) {
  9030. var map = this._map,
  9031. options = map.options,
  9032. noInertia = !options.inertia || this._times.length < 2;
  9033. map.fire('dragend', e);
  9034. if (noInertia) {
  9035. map.fire('moveend');
  9036. } else {
  9037. var direction = this._lastPos.subtract(this._positions[0]),
  9038. duration = (this._lastTime - this._times[0]) / 1000,
  9039. ease = options.easeLinearity,
  9040. speedVector = direction.multiplyBy(ease / duration),
  9041. speed = speedVector.distanceTo([0, 0]),
  9042. limitedSpeed = Math.min(options.inertiaMaxSpeed, speed),
  9043. limitedSpeedVector = speedVector.multiplyBy(limitedSpeed / speed),
  9044. decelerationDuration = limitedSpeed / (options.inertiaDeceleration * ease),
  9045. offset = limitedSpeedVector.multiplyBy(-decelerationDuration / 2).round();
  9046. if (!offset.x && !offset.y) {
  9047. map.fire('moveend');
  9048. } else {
  9049. offset = map._limitOffset(offset, map.options.maxBounds);
  9050. L.Util.requestAnimFrame(function () {
  9051. map.panBy(offset, {
  9052. duration: decelerationDuration,
  9053. easeLinearity: ease,
  9054. noMoveStart: true,
  9055. animate: true
  9056. });
  9057. });
  9058. }
  9059. }
  9060. }
  9061. });
  9062. // @section Handlers
  9063. // @property dragging: Handler
  9064. // Map dragging handler (by both mouse and touch).
  9065. L.Map.addInitHook('addHandler', 'dragging', L.Map.Drag);
  9066. /*
  9067. * L.Handler.DoubleClickZoom is used to handle double-click zoom on the map, enabled by default.
  9068. */
  9069. // @namespace Map
  9070. // @section Interaction Options
  9071. L.Map.mergeOptions({
  9072. // @option doubleClickZoom: Boolean|String = true
  9073. // Whether the map can be zoomed in by double clicking on it and
  9074. // zoomed out by double clicking while holding shift. If passed
  9075. // `'center'`, double-click zoom will zoom to the center of the
  9076. // view regardless of where the mouse was.
  9077. doubleClickZoom: true
  9078. });
  9079. L.Map.DoubleClickZoom = L.Handler.extend({
  9080. addHooks: function () {
  9081. this._map.on('dblclick', this._onDoubleClick, this);
  9082. },
  9083. removeHooks: function () {
  9084. this._map.off('dblclick', this._onDoubleClick, this);
  9085. },
  9086. _onDoubleClick: function (e) {
  9087. var map = this._map,
  9088. oldZoom = map.getZoom(),
  9089. delta = map.options.zoomDelta,
  9090. zoom = e.originalEvent.shiftKey ? oldZoom - delta : oldZoom + delta;
  9091. if (map.options.doubleClickZoom === 'center') {
  9092. map.setZoom(zoom);
  9093. } else {
  9094. map.setZoomAround(e.containerPoint, zoom);
  9095. }
  9096. }
  9097. });
  9098. // @section Handlers
  9099. //
  9100. // Map properties include interaction handlers that allow you to control
  9101. // interaction behavior in runtime, enabling or disabling certain features such
  9102. // as dragging or touch zoom (see `Handler` methods). For example:
  9103. //
  9104. // ```js
  9105. // map.doubleClickZoom.disable();
  9106. // ```
  9107. //
  9108. // @property doubleClickZoom: Handler
  9109. // Double click zoom handler.
  9110. L.Map.addInitHook('addHandler', 'doubleClickZoom', L.Map.DoubleClickZoom);
  9111. /*
  9112. * L.Handler.ScrollWheelZoom is used by L.Map to enable mouse scroll wheel zoom on the map.
  9113. */
  9114. // @namespace Map
  9115. // @section Interaction Options
  9116. L.Map.mergeOptions({
  9117. // @section Mousewheel options
  9118. // @option scrollWheelZoom: Boolean|String = true
  9119. // Whether the map can be zoomed by using the mouse wheel. If passed `'center'`,
  9120. // it will zoom to the center of the view regardless of where the mouse was.
  9121. scrollWheelZoom: true,
  9122. // @option wheelDebounceTime: Number = 40
  9123. // Limits the rate at which a wheel can fire (in milliseconds). By default
  9124. // user can't zoom via wheel more often than once per 40 ms.
  9125. wheelDebounceTime: 40,
  9126. // @option wheelPxPerZoomLevel: Number = 60
  9127. // How many scroll pixels (as reported by [L.DomEvent.getWheelDelta](#domevent-getwheeldelta))
  9128. // mean a change of one full zoom level. Smaller values will make wheel-zooming
  9129. // faster (and vice versa).
  9130. wheelPxPerZoomLevel: 60
  9131. });
  9132. L.Map.ScrollWheelZoom = L.Handler.extend({
  9133. addHooks: function () {
  9134. L.DomEvent.on(this._map._container, 'mousewheel', this._onWheelScroll, this);
  9135. this._delta = 0;
  9136. },
  9137. removeHooks: function () {
  9138. L.DomEvent.off(this._map._container, 'mousewheel', this._onWheelScroll, this);
  9139. },
  9140. _onWheelScroll: function (e) {
  9141. var delta = L.DomEvent.getWheelDelta(e);
  9142. var debounce = this._map.options.wheelDebounceTime;
  9143. this._delta += delta;
  9144. this._lastMousePos = this._map.mouseEventToContainerPoint(e);
  9145. if (!this._startTime) {
  9146. this._startTime = +new Date();
  9147. }
  9148. var left = Math.max(debounce - (+new Date() - this._startTime), 0);
  9149. clearTimeout(this._timer);
  9150. this._timer = setTimeout(L.bind(this._performZoom, this), left);
  9151. L.DomEvent.stop(e);
  9152. },
  9153. _performZoom: function () {
  9154. var map = this._map,
  9155. zoom = map.getZoom(),
  9156. snap = this._map.options.zoomSnap || 0;
  9157. map._stop(); // stop panning and fly animations if any
  9158. // map the delta with a sigmoid function to -4..4 range leaning on -1..1
  9159. var d2 = this._delta / (this._map.options.wheelPxPerZoomLevel * 4),
  9160. d3 = 4 * Math.log(2 / (1 + Math.exp(-Math.abs(d2)))) / Math.LN2,
  9161. d4 = snap ? Math.ceil(d3 / snap) * snap : d3,
  9162. delta = map._limitZoom(zoom + (this._delta > 0 ? d4 : -d4)) - zoom;
  9163. this._delta = 0;
  9164. this._startTime = null;
  9165. if (!delta) { return; }
  9166. if (map.options.scrollWheelZoom === 'center') {
  9167. map.setZoom(zoom + delta);
  9168. } else {
  9169. map.setZoomAround(this._lastMousePos, zoom + delta);
  9170. }
  9171. }
  9172. });
  9173. // @section Handlers
  9174. // @property scrollWheelZoom: Handler
  9175. // Scroll wheel zoom handler.
  9176. L.Map.addInitHook('addHandler', 'scrollWheelZoom', L.Map.ScrollWheelZoom);
  9177. /*
  9178. * Extends the event handling code with double tap support for mobile browsers.
  9179. */
  9180. L.extend(L.DomEvent, {
  9181. _touchstart: L.Browser.msPointer ? 'MSPointerDown' : L.Browser.pointer ? 'pointerdown' : 'touchstart',
  9182. _touchend: L.Browser.msPointer ? 'MSPointerUp' : L.Browser.pointer ? 'pointerup' : 'touchend',
  9183. // inspired by Zepto touch code by Thomas Fuchs
  9184. addDoubleTapListener: function (obj, handler, id) {
  9185. var last, touch,
  9186. doubleTap = false,
  9187. delay = 250;
  9188. function onTouchStart(e) {
  9189. var count;
  9190. if (L.Browser.pointer) {
  9191. count = L.DomEvent._pointersCount;
  9192. } else {
  9193. count = e.touches.length;
  9194. }
  9195. if (count > 1) { return; }
  9196. var now = Date.now(),
  9197. delta = now - (last || now);
  9198. touch = e.touches ? e.touches[0] : e;
  9199. doubleTap = (delta > 0 && delta <= delay);
  9200. last = now;
  9201. }
  9202. function onTouchEnd() {
  9203. if (doubleTap && !touch.cancelBubble) {
  9204. if (L.Browser.pointer) {
  9205. // work around .type being readonly with MSPointer* events
  9206. var newTouch = {},
  9207. prop, i;
  9208. for (i in touch) {
  9209. prop = touch[i];
  9210. newTouch[i] = prop && prop.bind ? prop.bind(touch) : prop;
  9211. }
  9212. touch = newTouch;
  9213. }
  9214. touch.type = 'dblclick';
  9215. handler(touch);
  9216. last = null;
  9217. }
  9218. }
  9219. var pre = '_leaflet_',
  9220. touchstart = this._touchstart,
  9221. touchend = this._touchend;
  9222. obj[pre + touchstart + id] = onTouchStart;
  9223. obj[pre + touchend + id] = onTouchEnd;
  9224. obj[pre + 'dblclick' + id] = handler;
  9225. obj.addEventListener(touchstart, onTouchStart, false);
  9226. obj.addEventListener(touchend, onTouchEnd, false);
  9227. // On some platforms (notably, chrome on win10 + touchscreen + mouse),
  9228. // the browser doesn't fire touchend/pointerup events but does fire
  9229. // native dblclicks. See #4127.
  9230. if (!L.Browser.edge) {
  9231. obj.addEventListener('dblclick', handler, false);
  9232. }
  9233. return this;
  9234. },
  9235. removeDoubleTapListener: function (obj, id) {
  9236. var pre = '_leaflet_',
  9237. touchstart = obj[pre + this._touchstart + id],
  9238. touchend = obj[pre + this._touchend + id],
  9239. dblclick = obj[pre + 'dblclick' + id];
  9240. obj.removeEventListener(this._touchstart, touchstart, false);
  9241. obj.removeEventListener(this._touchend, touchend, false);
  9242. if (!L.Browser.edge) {
  9243. obj.removeEventListener('dblclick', dblclick, false);
  9244. }
  9245. return this;
  9246. }
  9247. });
  9248. /*
  9249. * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices.
  9250. */
  9251. L.extend(L.DomEvent, {
  9252. POINTER_DOWN: L.Browser.msPointer ? 'MSPointerDown' : 'pointerdown',
  9253. POINTER_MOVE: L.Browser.msPointer ? 'MSPointerMove' : 'pointermove',
  9254. POINTER_UP: L.Browser.msPointer ? 'MSPointerUp' : 'pointerup',
  9255. POINTER_CANCEL: L.Browser.msPointer ? 'MSPointerCancel' : 'pointercancel',
  9256. TAG_WHITE_LIST: ['INPUT', 'SELECT', 'OPTION'],
  9257. _pointers: {},
  9258. _pointersCount: 0,
  9259. // Provides a touch events wrapper for (ms)pointer events.
  9260. // ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890
  9261. addPointerListener: function (obj, type, handler, id) {
  9262. if (type === 'touchstart') {
  9263. this._addPointerStart(obj, handler, id);
  9264. } else if (type === 'touchmove') {
  9265. this._addPointerMove(obj, handler, id);
  9266. } else if (type === 'touchend') {
  9267. this._addPointerEnd(obj, handler, id);
  9268. }
  9269. return this;
  9270. },
  9271. removePointerListener: function (obj, type, id) {
  9272. var handler = obj['_leaflet_' + type + id];
  9273. if (type === 'touchstart') {
  9274. obj.removeEventListener(this.POINTER_DOWN, handler, false);
  9275. } else if (type === 'touchmove') {
  9276. obj.removeEventListener(this.POINTER_MOVE, handler, false);
  9277. } else if (type === 'touchend') {
  9278. obj.removeEventListener(this.POINTER_UP, handler, false);
  9279. obj.removeEventListener(this.POINTER_CANCEL, handler, false);
  9280. }
  9281. return this;
  9282. },
  9283. _addPointerStart: function (obj, handler, id) {
  9284. var onDown = L.bind(function (e) {
  9285. if (e.pointerType !== 'mouse' && e.pointerType !== e.MSPOINTER_TYPE_MOUSE) {
  9286. // In IE11, some touch events needs to fire for form controls, or
  9287. // the controls will stop working. We keep a whitelist of tag names that
  9288. // need these events. For other target tags, we prevent default on the event.
  9289. if (this.TAG_WHITE_LIST.indexOf(e.target.tagName) < 0) {
  9290. L.DomEvent.preventDefault(e);
  9291. } else {
  9292. return;
  9293. }
  9294. }
  9295. this._handlePointer(e, handler);
  9296. }, this);
  9297. obj['_leaflet_touchstart' + id] = onDown;
  9298. obj.addEventListener(this.POINTER_DOWN, onDown, false);
  9299. // need to keep track of what pointers and how many are active to provide e.touches emulation
  9300. if (!this._pointerDocListener) {
  9301. var pointerUp = L.bind(this._globalPointerUp, this);
  9302. // we listen documentElement as any drags that end by moving the touch off the screen get fired there
  9303. document.documentElement.addEventListener(this.POINTER_DOWN, L.bind(this._globalPointerDown, this), true);
  9304. document.documentElement.addEventListener(this.POINTER_MOVE, L.bind(this._globalPointerMove, this), true);
  9305. document.documentElement.addEventListener(this.POINTER_UP, pointerUp, true);
  9306. document.documentElement.addEventListener(this.POINTER_CANCEL, pointerUp, true);
  9307. this._pointerDocListener = true;
  9308. }
  9309. },
  9310. _globalPointerDown: function (e) {
  9311. this._pointers[e.pointerId] = e;
  9312. this._pointersCount++;
  9313. },
  9314. _globalPointerMove: function (e) {
  9315. if (this._pointers[e.pointerId]) {
  9316. this._pointers[e.pointerId] = e;
  9317. }
  9318. },
  9319. _globalPointerUp: function (e) {
  9320. delete this._pointers[e.pointerId];
  9321. this._pointersCount--;
  9322. },
  9323. _handlePointer: function (e, handler) {
  9324. e.touches = [];
  9325. for (var i in this._pointers) {
  9326. e.touches.push(this._pointers[i]);
  9327. }
  9328. e.changedTouches = [e];
  9329. handler(e);
  9330. },
  9331. _addPointerMove: function (obj, handler, id) {
  9332. var onMove = L.bind(function (e) {
  9333. // don't fire touch moves when mouse isn't down
  9334. if ((e.pointerType === e.MSPOINTER_TYPE_MOUSE || e.pointerType === 'mouse') && e.buttons === 0) { return; }
  9335. this._handlePointer(e, handler);
  9336. }, this);
  9337. obj['_leaflet_touchmove' + id] = onMove;
  9338. obj.addEventListener(this.POINTER_MOVE, onMove, false);
  9339. },
  9340. _addPointerEnd: function (obj, handler, id) {
  9341. var onUp = L.bind(function (e) {
  9342. this._handlePointer(e, handler);
  9343. }, this);
  9344. obj['_leaflet_touchend' + id] = onUp;
  9345. obj.addEventListener(this.POINTER_UP, onUp, false);
  9346. obj.addEventListener(this.POINTER_CANCEL, onUp, false);
  9347. }
  9348. });
  9349. /*
  9350. * L.Handler.TouchZoom is used by L.Map to add pinch zoom on supported mobile browsers.
  9351. */
  9352. // @namespace Map
  9353. // @section Interaction Options
  9354. L.Map.mergeOptions({
  9355. // @section Touch interaction options
  9356. // @option touchZoom: Boolean|String = *
  9357. // Whether the map can be zoomed by touch-dragging with two fingers. If
  9358. // passed `'center'`, it will zoom to the center of the view regardless of
  9359. // where the touch events (fingers) were. Enabled for touch-capable web
  9360. // browsers except for old Androids.
  9361. touchZoom: L.Browser.touch && !L.Browser.android23,
  9362. // @option bounceAtZoomLimits: Boolean = true
  9363. // Set it to false if you don't want the map to zoom beyond min/max zoom
  9364. // and then bounce back when pinch-zooming.
  9365. bounceAtZoomLimits: true
  9366. });
  9367. L.Map.TouchZoom = L.Handler.extend({
  9368. addHooks: function () {
  9369. L.DomUtil.addClass(this._map._container, 'leaflet-touch-zoom');
  9370. L.DomEvent.on(this._map._container, 'touchstart', this._onTouchStart, this);
  9371. },
  9372. removeHooks: function () {
  9373. L.DomUtil.removeClass(this._map._container, 'leaflet-touch-zoom');
  9374. L.DomEvent.off(this._map._container, 'touchstart', this._onTouchStart, this);
  9375. },
  9376. _onTouchStart: function (e) {
  9377. var map = this._map;
  9378. if (!e.touches || e.touches.length !== 2 || map._animatingZoom || this._zooming) { return; }
  9379. var p1 = map.mouseEventToContainerPoint(e.touches[0]),
  9380. p2 = map.mouseEventToContainerPoint(e.touches[1]);
  9381. this._centerPoint = map.getSize()._divideBy(2);
  9382. this._startLatLng = map.containerPointToLatLng(this._centerPoint);
  9383. if (map.options.touchZoom !== 'center') {
  9384. this._pinchStartLatLng = map.containerPointToLatLng(p1.add(p2)._divideBy(2));
  9385. }
  9386. this._startDist = p1.distanceTo(p2);
  9387. this._startZoom = map.getZoom();
  9388. this._moved = false;
  9389. this._zooming = true;
  9390. map._stop();
  9391. L.DomEvent
  9392. .on(document, 'touchmove', this._onTouchMove, this)
  9393. .on(document, 'touchend', this._onTouchEnd, this);
  9394. L.DomEvent.preventDefault(e);
  9395. },
  9396. _onTouchMove: function (e) {
  9397. if (!e.touches || e.touches.length !== 2 || !this._zooming) { return; }
  9398. var map = this._map,
  9399. p1 = map.mouseEventToContainerPoint(e.touches[0]),
  9400. p2 = map.mouseEventToContainerPoint(e.touches[1]),
  9401. scale = p1.distanceTo(p2) / this._startDist;
  9402. this._zoom = map.getScaleZoom(scale, this._startZoom);
  9403. if (!map.options.bounceAtZoomLimits && (
  9404. (this._zoom < map.getMinZoom() && scale < 1) ||
  9405. (this._zoom > map.getMaxZoom() && scale > 1))) {
  9406. this._zoom = map._limitZoom(this._zoom);
  9407. }
  9408. if (map.options.touchZoom === 'center') {
  9409. this._center = this._startLatLng;
  9410. if (scale === 1) { return; }
  9411. } else {
  9412. // Get delta from pinch to center, so centerLatLng is delta applied to initial pinchLatLng
  9413. var delta = p1._add(p2)._divideBy(2)._subtract(this._centerPoint);
  9414. if (scale === 1 && delta.x === 0 && delta.y === 0) { return; }
  9415. this._center = map.unproject(map.project(this._pinchStartLatLng, this._zoom).subtract(delta), this._zoom);
  9416. }
  9417. if (!this._moved) {
  9418. map._moveStart(true);
  9419. this._moved = true;
  9420. }
  9421. L.Util.cancelAnimFrame(this._animRequest);
  9422. var moveFn = L.bind(map._move, map, this._center, this._zoom, {pinch: true, round: false});
  9423. this._animRequest = L.Util.requestAnimFrame(moveFn, this, true);
  9424. L.DomEvent.preventDefault(e);
  9425. },
  9426. _onTouchEnd: function () {
  9427. if (!this._moved || !this._zooming) {
  9428. this._zooming = false;
  9429. return;
  9430. }
  9431. this._zooming = false;
  9432. L.Util.cancelAnimFrame(this._animRequest);
  9433. L.DomEvent
  9434. .off(document, 'touchmove', this._onTouchMove)
  9435. .off(document, 'touchend', this._onTouchEnd);
  9436. // Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate.
  9437. if (this._map.options.zoomAnimation) {
  9438. this._map._animateZoom(this._center, this._map._limitZoom(this._zoom), true, this._map.options.zoomSnap);
  9439. } else {
  9440. this._map._resetView(this._center, this._map._limitZoom(this._zoom));
  9441. }
  9442. }
  9443. });
  9444. // @section Handlers
  9445. // @property touchZoom: Handler
  9446. // Touch zoom handler.
  9447. L.Map.addInitHook('addHandler', 'touchZoom', L.Map.TouchZoom);
  9448. /*
  9449. * L.Map.Tap is used to enable mobile hacks like quick taps and long hold.
  9450. */
  9451. // @namespace Map
  9452. // @section Interaction Options
  9453. L.Map.mergeOptions({
  9454. // @section Touch interaction options
  9455. // @option tap: Boolean = true
  9456. // Enables mobile hacks for supporting instant taps (fixing 200ms click
  9457. // delay on iOS/Android) and touch holds (fired as `contextmenu` events).
  9458. tap: true,
  9459. // @option tapTolerance: Number = 15
  9460. // The max number of pixels a user can shift his finger during touch
  9461. // for it to be considered a valid tap.
  9462. tapTolerance: 15
  9463. });
  9464. L.Map.Tap = L.Handler.extend({
  9465. addHooks: function () {
  9466. L.DomEvent.on(this._map._container, 'touchstart', this._onDown, this);
  9467. },
  9468. removeHooks: function () {
  9469. L.DomEvent.off(this._map._container, 'touchstart', this._onDown, this);
  9470. },
  9471. _onDown: function (e) {
  9472. if (!e.touches) { return; }
  9473. L.DomEvent.preventDefault(e);
  9474. this._fireClick = true;
  9475. // don't simulate click or track longpress if more than 1 touch
  9476. if (e.touches.length > 1) {
  9477. this._fireClick = false;
  9478. clearTimeout(this._holdTimeout);
  9479. return;
  9480. }
  9481. var first = e.touches[0],
  9482. el = first.target;
  9483. this._startPos = this._newPos = new L.Point(first.clientX, first.clientY);
  9484. // if touching a link, highlight it
  9485. if (el.tagName && el.tagName.toLowerCase() === 'a') {
  9486. L.DomUtil.addClass(el, 'leaflet-active');
  9487. }
  9488. // simulate long hold but setting a timeout
  9489. this._holdTimeout = setTimeout(L.bind(function () {
  9490. if (this._isTapValid()) {
  9491. this._fireClick = false;
  9492. this._onUp();
  9493. this._simulateEvent('contextmenu', first);
  9494. }
  9495. }, this), 1000);
  9496. this._simulateEvent('mousedown', first);
  9497. L.DomEvent.on(document, {
  9498. touchmove: this._onMove,
  9499. touchend: this._onUp
  9500. }, this);
  9501. },
  9502. _onUp: function (e) {
  9503. clearTimeout(this._holdTimeout);
  9504. L.DomEvent.off(document, {
  9505. touchmove: this._onMove,
  9506. touchend: this._onUp
  9507. }, this);
  9508. if (this._fireClick && e && e.changedTouches) {
  9509. var first = e.changedTouches[0],
  9510. el = first.target;
  9511. if (el && el.tagName && el.tagName.toLowerCase() === 'a') {
  9512. L.DomUtil.removeClass(el, 'leaflet-active');
  9513. }
  9514. this._simulateEvent('mouseup', first);
  9515. // simulate click if the touch didn't move too much
  9516. if (this._isTapValid()) {
  9517. this._simulateEvent('click', first);
  9518. }
  9519. }
  9520. },
  9521. _isTapValid: function () {
  9522. return this._newPos.distanceTo(this._startPos) <= this._map.options.tapTolerance;
  9523. },
  9524. _onMove: function (e) {
  9525. var first = e.touches[0];
  9526. this._newPos = new L.Point(first.clientX, first.clientY);
  9527. this._simulateEvent('mousemove', first);
  9528. },
  9529. _simulateEvent: function (type, e) {
  9530. var simulatedEvent = document.createEvent('MouseEvents');
  9531. simulatedEvent._simulated = true;
  9532. e.target._simulatedClick = true;
  9533. simulatedEvent.initMouseEvent(
  9534. type, true, true, window, 1,
  9535. e.screenX, e.screenY,
  9536. e.clientX, e.clientY,
  9537. false, false, false, false, 0, null);
  9538. e.target.dispatchEvent(simulatedEvent);
  9539. }
  9540. });
  9541. // @section Handlers
  9542. // @property tap: Handler
  9543. // Mobile touch hacks (quick tap and touch hold) handler.
  9544. if (L.Browser.touch && !L.Browser.pointer) {
  9545. L.Map.addInitHook('addHandler', 'tap', L.Map.Tap);
  9546. }
  9547. /*
  9548. * L.Handler.BoxZoom is used to add shift-drag zoom interaction to the map
  9549. * (zoom to a selected bounding box), enabled by default.
  9550. */
  9551. // @namespace Map
  9552. // @section Interaction Options
  9553. L.Map.mergeOptions({
  9554. // @option boxZoom: Boolean = true
  9555. // Whether the map can be zoomed to a rectangular area specified by
  9556. // dragging the mouse while pressing the shift key.
  9557. boxZoom: true
  9558. });
  9559. L.Map.BoxZoom = L.Handler.extend({
  9560. initialize: function (map) {
  9561. this._map = map;
  9562. this._container = map._container;
  9563. this._pane = map._panes.overlayPane;
  9564. },
  9565. addHooks: function () {
  9566. L.DomEvent.on(this._container, 'mousedown', this._onMouseDown, this);
  9567. },
  9568. removeHooks: function () {
  9569. L.DomEvent.off(this._container, 'mousedown', this._onMouseDown, this);
  9570. },
  9571. moved: function () {
  9572. return this._moved;
  9573. },
  9574. _resetState: function () {
  9575. this._moved = false;
  9576. },
  9577. _onMouseDown: function (e) {
  9578. if (!e.shiftKey || ((e.which !== 1) && (e.button !== 1))) { return false; }
  9579. this._resetState();
  9580. L.DomUtil.disableTextSelection();
  9581. L.DomUtil.disableImageDrag();
  9582. this._startPoint = this._map.mouseEventToContainerPoint(e);
  9583. L.DomEvent.on(document, {
  9584. contextmenu: L.DomEvent.stop,
  9585. mousemove: this._onMouseMove,
  9586. mouseup: this._onMouseUp,
  9587. keydown: this._onKeyDown
  9588. }, this);
  9589. },
  9590. _onMouseMove: function (e) {
  9591. if (!this._moved) {
  9592. this._moved = true;
  9593. this._box = L.DomUtil.create('div', 'leaflet-zoom-box', this._container);
  9594. L.DomUtil.addClass(this._container, 'leaflet-crosshair');
  9595. this._map.fire('boxzoomstart');
  9596. }
  9597. this._point = this._map.mouseEventToContainerPoint(e);
  9598. var bounds = new L.Bounds(this._point, this._startPoint),
  9599. size = bounds.getSize();
  9600. L.DomUtil.setPosition(this._box, bounds.min);
  9601. this._box.style.width = size.x + 'px';
  9602. this._box.style.height = size.y + 'px';
  9603. },
  9604. _finish: function () {
  9605. if (this._moved) {
  9606. L.DomUtil.remove(this._box);
  9607. L.DomUtil.removeClass(this._container, 'leaflet-crosshair');
  9608. }
  9609. L.DomUtil.enableTextSelection();
  9610. L.DomUtil.enableImageDrag();
  9611. L.DomEvent.off(document, {
  9612. contextmenu: L.DomEvent.stop,
  9613. mousemove: this._onMouseMove,
  9614. mouseup: this._onMouseUp,
  9615. keydown: this._onKeyDown
  9616. }, this);
  9617. },
  9618. _onMouseUp: function (e) {
  9619. if ((e.which !== 1) && (e.button !== 1)) { return; }
  9620. this._finish();
  9621. if (!this._moved) { return; }
  9622. // Postpone to next JS tick so internal click event handling
  9623. // still see it as "moved".
  9624. setTimeout(L.bind(this._resetState, this), 0);
  9625. var bounds = new L.LatLngBounds(
  9626. this._map.containerPointToLatLng(this._startPoint),
  9627. this._map.containerPointToLatLng(this._point));
  9628. this._map
  9629. .fitBounds(bounds)
  9630. .fire('boxzoomend', {boxZoomBounds: bounds});
  9631. },
  9632. _onKeyDown: function (e) {
  9633. if (e.keyCode === 27) {
  9634. this._finish();
  9635. }
  9636. }
  9637. });
  9638. // @section Handlers
  9639. // @property boxZoom: Handler
  9640. // Box (shift-drag with mouse) zoom handler.
  9641. L.Map.addInitHook('addHandler', 'boxZoom', L.Map.BoxZoom);
  9642. /*
  9643. * L.Map.Keyboard is handling keyboard interaction with the map, enabled by default.
  9644. */
  9645. // @namespace Map
  9646. // @section Keyboard Navigation Options
  9647. L.Map.mergeOptions({
  9648. // @option keyboard: Boolean = true
  9649. // Makes the map focusable and allows users to navigate the map with keyboard
  9650. // arrows and `+`/`-` keys.
  9651. keyboard: true,
  9652. // @option keyboardPanDelta: Number = 80
  9653. // Amount of pixels to pan when pressing an arrow key.
  9654. keyboardPanDelta: 80
  9655. });
  9656. L.Map.Keyboard = L.Handler.extend({
  9657. keyCodes: {
  9658. left: [37],
  9659. right: [39],
  9660. down: [40],
  9661. up: [38],
  9662. zoomIn: [187, 107, 61, 171],
  9663. zoomOut: [189, 109, 54, 173]
  9664. },
  9665. initialize: function (map) {
  9666. this._map = map;
  9667. this._setPanDelta(map.options.keyboardPanDelta);
  9668. this._setZoomDelta(map.options.zoomDelta);
  9669. },
  9670. addHooks: function () {
  9671. var container = this._map._container;
  9672. // make the container focusable by tabbing
  9673. if (container.tabIndex <= 0) {
  9674. container.tabIndex = '0';
  9675. }
  9676. L.DomEvent.on(container, {
  9677. focus: this._onFocus,
  9678. blur: this._onBlur,
  9679. mousedown: this._onMouseDown
  9680. }, this);
  9681. this._map.on({
  9682. focus: this._addHooks,
  9683. blur: this._removeHooks
  9684. }, this);
  9685. },
  9686. removeHooks: function () {
  9687. this._removeHooks();
  9688. L.DomEvent.off(this._map._container, {
  9689. focus: this._onFocus,
  9690. blur: this._onBlur,
  9691. mousedown: this._onMouseDown
  9692. }, this);
  9693. this._map.off({
  9694. focus: this._addHooks,
  9695. blur: this._removeHooks
  9696. }, this);
  9697. },
  9698. _onMouseDown: function () {
  9699. if (this._focused) { return; }
  9700. var body = document.body,
  9701. docEl = document.documentElement,
  9702. top = body.scrollTop || docEl.scrollTop,
  9703. left = body.scrollLeft || docEl.scrollLeft;
  9704. this._map._container.focus();
  9705. window.scrollTo(left, top);
  9706. },
  9707. _onFocus: function () {
  9708. this._focused = true;
  9709. this._map.fire('focus');
  9710. },
  9711. _onBlur: function () {
  9712. this._focused = false;
  9713. this._map.fire('blur');
  9714. },
  9715. _setPanDelta: function (panDelta) {
  9716. var keys = this._panKeys = {},
  9717. codes = this.keyCodes,
  9718. i, len;
  9719. for (i = 0, len = codes.left.length; i < len; i++) {
  9720. keys[codes.left[i]] = [-1 * panDelta, 0];
  9721. }
  9722. for (i = 0, len = codes.right.length; i < len; i++) {
  9723. keys[codes.right[i]] = [panDelta, 0];
  9724. }
  9725. for (i = 0, len = codes.down.length; i < len; i++) {
  9726. keys[codes.down[i]] = [0, panDelta];
  9727. }
  9728. for (i = 0, len = codes.up.length; i < len; i++) {
  9729. keys[codes.up[i]] = [0, -1 * panDelta];
  9730. }
  9731. },
  9732. _setZoomDelta: function (zoomDelta) {
  9733. var keys = this._zoomKeys = {},
  9734. codes = this.keyCodes,
  9735. i, len;
  9736. for (i = 0, len = codes.zoomIn.length; i < len; i++) {
  9737. keys[codes.zoomIn[i]] = zoomDelta;
  9738. }
  9739. for (i = 0, len = codes.zoomOut.length; i < len; i++) {
  9740. keys[codes.zoomOut[i]] = -zoomDelta;
  9741. }
  9742. },
  9743. _addHooks: function () {
  9744. L.DomEvent.on(document, 'keydown', this._onKeyDown, this);
  9745. },
  9746. _removeHooks: function () {
  9747. L.DomEvent.off(document, 'keydown', this._onKeyDown, this);
  9748. },
  9749. _onKeyDown: function (e) {
  9750. if (e.altKey || e.ctrlKey || e.metaKey) { return; }
  9751. var key = e.keyCode,
  9752. map = this._map,
  9753. offset;
  9754. if (key in this._panKeys) {
  9755. if (map._panAnim && map._panAnim._inProgress) { return; }
  9756. offset = this._panKeys[key];
  9757. if (e.shiftKey) {
  9758. offset = L.point(offset).multiplyBy(3);
  9759. }
  9760. map.panBy(offset);
  9761. if (map.options.maxBounds) {
  9762. map.panInsideBounds(map.options.maxBounds);
  9763. }
  9764. } else if (key in this._zoomKeys) {
  9765. map.setZoom(map.getZoom() + (e.shiftKey ? 3 : 1) * this._zoomKeys[key]);
  9766. } else if (key === 27) {
  9767. map.closePopup();
  9768. } else {
  9769. return;
  9770. }
  9771. L.DomEvent.stop(e);
  9772. }
  9773. });
  9774. // @section Handlers
  9775. // @section Handlers
  9776. // @property keyboard: Handler
  9777. // Keyboard navigation handler.
  9778. L.Map.addInitHook('addHandler', 'keyboard', L.Map.Keyboard);
  9779. /*
  9780. * L.Handler.MarkerDrag is used internally by L.Marker to make the markers draggable.
  9781. */
  9782. /* @namespace Marker
  9783. * @section Interaction handlers
  9784. *
  9785. * Interaction handlers are properties of a marker instance that allow you to control interaction behavior in runtime, enabling or disabling certain features such as dragging (see `Handler` methods). Example:
  9786. *
  9787. * ```js
  9788. * marker.dragging.disable();
  9789. * ```
  9790. *
  9791. * @property dragging: Handler
  9792. * Marker dragging handler (by both mouse and touch).
  9793. */
  9794. L.Handler.MarkerDrag = L.Handler.extend({
  9795. initialize: function (marker) {
  9796. this._marker = marker;
  9797. },
  9798. addHooks: function () {
  9799. var icon = this._marker._icon;
  9800. if (!this._draggable) {
  9801. this._draggable = new L.Draggable(icon, icon, true);
  9802. }
  9803. this._draggable.on({
  9804. dragstart: this._onDragStart,
  9805. drag: this._onDrag,
  9806. dragend: this._onDragEnd
  9807. }, this).enable();
  9808. L.DomUtil.addClass(icon, 'leaflet-marker-draggable');
  9809. },
  9810. removeHooks: function () {
  9811. this._draggable.off({
  9812. dragstart: this._onDragStart,
  9813. drag: this._onDrag,
  9814. dragend: this._onDragEnd
  9815. }, this).disable();
  9816. if (this._marker._icon) {
  9817. L.DomUtil.removeClass(this._marker._icon, 'leaflet-marker-draggable');
  9818. }
  9819. },
  9820. moved: function () {
  9821. return this._draggable && this._draggable._moved;
  9822. },
  9823. _onDragStart: function () {
  9824. // @section Dragging events
  9825. // @event dragstart: Event
  9826. // Fired when the user starts dragging the marker.
  9827. // @event movestart: Event
  9828. // Fired when the marker starts moving (because of dragging).
  9829. this._oldLatLng = this._marker.getLatLng();
  9830. this._marker
  9831. .closePopup()
  9832. .fire('movestart')
  9833. .fire('dragstart');
  9834. },
  9835. _onDrag: function (e) {
  9836. var marker = this._marker,
  9837. shadow = marker._shadow,
  9838. iconPos = L.DomUtil.getPosition(marker._icon),
  9839. latlng = marker._map.layerPointToLatLng(iconPos);
  9840. // update shadow position
  9841. if (shadow) {
  9842. L.DomUtil.setPosition(shadow, iconPos);
  9843. }
  9844. marker._latlng = latlng;
  9845. e.latlng = latlng;
  9846. e.oldLatLng = this._oldLatLng;
  9847. // @event drag: Event
  9848. // Fired repeatedly while the user drags the marker.
  9849. marker
  9850. .fire('move', e)
  9851. .fire('drag', e);
  9852. },
  9853. _onDragEnd: function (e) {
  9854. // @event dragend: DragEndEvent
  9855. // Fired when the user stops dragging the marker.
  9856. // @event moveend: Event
  9857. // Fired when the marker stops moving (because of dragging).
  9858. delete this._oldLatLng;
  9859. this._marker
  9860. .fire('moveend')
  9861. .fire('dragend', e);
  9862. }
  9863. });
  9864. /*
  9865. * @class Control
  9866. * @aka L.Control
  9867. * @inherits Class
  9868. *
  9869. * L.Control is a base class for implementing map controls. Handles positioning.
  9870. * All other controls extend from this class.
  9871. */
  9872. L.Control = L.Class.extend({
  9873. // @section
  9874. // @aka Control options
  9875. options: {
  9876. // @option position: String = 'topright'
  9877. // The position of the control (one of the map corners). Possible values are `'topleft'`,
  9878. // `'topright'`, `'bottomleft'` or `'bottomright'`
  9879. position: 'topright'
  9880. },
  9881. initialize: function (options) {
  9882. L.setOptions(this, options);
  9883. },
  9884. /* @section
  9885. * Classes extending L.Control will inherit the following methods:
  9886. *
  9887. * @method getPosition: string
  9888. * Returns the position of the control.
  9889. */
  9890. getPosition: function () {
  9891. return this.options.position;
  9892. },
  9893. // @method setPosition(position: string): this
  9894. // Sets the position of the control.
  9895. setPosition: function (position) {
  9896. var map = this._map;
  9897. if (map) {
  9898. map.removeControl(this);
  9899. }
  9900. this.options.position = position;
  9901. if (map) {
  9902. map.addControl(this);
  9903. }
  9904. return this;
  9905. },
  9906. // @method getContainer: HTMLElement
  9907. // Returns the HTMLElement that contains the control.
  9908. getContainer: function () {
  9909. return this._container;
  9910. },
  9911. // @method addTo(map: Map): this
  9912. // Adds the control to the given map.
  9913. addTo: function (map) {
  9914. this.remove();
  9915. this._map = map;
  9916. var container = this._container = this.onAdd(map),
  9917. pos = this.getPosition(),
  9918. corner = map._controlCorners[pos];
  9919. L.DomUtil.addClass(container, 'leaflet-control');
  9920. if (pos.indexOf('bottom') !== -1) {
  9921. corner.insertBefore(container, corner.firstChild);
  9922. } else {
  9923. corner.appendChild(container);
  9924. }
  9925. return this;
  9926. },
  9927. // @method remove: this
  9928. // Removes the control from the map it is currently active on.
  9929. remove: function () {
  9930. if (!this._map) {
  9931. return this;
  9932. }
  9933. L.DomUtil.remove(this._container);
  9934. if (this.onRemove) {
  9935. this.onRemove(this._map);
  9936. }
  9937. this._map = null;
  9938. return this;
  9939. },
  9940. _refocusOnMap: function (e) {
  9941. // if map exists and event is not a keyboard event
  9942. if (this._map && e && e.screenX > 0 && e.screenY > 0) {
  9943. this._map.getContainer().focus();
  9944. }
  9945. }
  9946. });
  9947. L.control = function (options) {
  9948. return new L.Control(options);
  9949. };
  9950. /* @section Extension methods
  9951. * @uninheritable
  9952. *
  9953. * Every control should extend from `L.Control` and (re-)implement the following methods.
  9954. *
  9955. * @method onAdd(map: Map): HTMLElement
  9956. * Should return the container DOM element for the control and add listeners on relevant map events. Called on [`control.addTo(map)`](#control-addTo).
  9957. *
  9958. * @method onRemove(map: Map)
  9959. * Optional method. Should contain all clean up code that removes the listeners previously added in [`onAdd`](#control-onadd). Called on [`control.remove()`](#control-remove).
  9960. */
  9961. /* @namespace Map
  9962. * @section Methods for Layers and Controls
  9963. */
  9964. L.Map.include({
  9965. // @method addControl(control: Control): this
  9966. // Adds the given control to the map
  9967. addControl: function (control) {
  9968. control.addTo(this);
  9969. return this;
  9970. },
  9971. // @method removeControl(control: Control): this
  9972. // Removes the given control from the map
  9973. removeControl: function (control) {
  9974. control.remove();
  9975. return this;
  9976. },
  9977. _initControlPos: function () {
  9978. var corners = this._controlCorners = {},
  9979. l = 'leaflet-',
  9980. container = this._controlContainer =
  9981. L.DomUtil.create('div', l + 'control-container', this._container);
  9982. function createCorner(vSide, hSide) {
  9983. var className = l + vSide + ' ' + l + hSide;
  9984. corners[vSide + hSide] = L.DomUtil.create('div', className, container);
  9985. }
  9986. createCorner('top', 'left');
  9987. createCorner('top', 'right');
  9988. createCorner('bottom', 'left');
  9989. createCorner('bottom', 'right');
  9990. },
  9991. _clearControlPos: function () {
  9992. L.DomUtil.remove(this._controlContainer);
  9993. }
  9994. });
  9995. /*
  9996. * @class Control.Zoom
  9997. * @aka L.Control.Zoom
  9998. * @inherits Control
  9999. *
  10000. * A basic zoom control with two buttons (zoom in and zoom out). It is put on the map by default unless you set its [`zoomControl` option](#map-zoomcontrol) to `false`. Extends `Control`.
  10001. */
  10002. L.Control.Zoom = L.Control.extend({
  10003. // @section
  10004. // @aka Control.Zoom options
  10005. options: {
  10006. position: 'topleft',
  10007. // @option zoomInText: String = '+'
  10008. // The text set on the 'zoom in' button.
  10009. zoomInText: '+',
  10010. // @option zoomInTitle: String = 'Zoom in'
  10011. // The title set on the 'zoom in' button.
  10012. zoomInTitle: 'Zoom in',
  10013. // @option zoomOutText: String = '-'
  10014. // The text set on the 'zoom out' button.
  10015. zoomOutText: '-',
  10016. // @option zoomOutTitle: String = 'Zoom out'
  10017. // The title set on the 'zoom out' button.
  10018. zoomOutTitle: 'Zoom out'
  10019. },
  10020. onAdd: function (map) {
  10021. var zoomName = 'leaflet-control-zoom',
  10022. container = L.DomUtil.create('div', zoomName + ' leaflet-bar'),
  10023. options = this.options;
  10024. this._zoomInButton = this._createButton(options.zoomInText, options.zoomInTitle,
  10025. zoomName + '-in', container, this._zoomIn);
  10026. this._zoomOutButton = this._createButton(options.zoomOutText, options.zoomOutTitle,
  10027. zoomName + '-out', container, this._zoomOut);
  10028. this._updateDisabled();
  10029. map.on('zoomend zoomlevelschange', this._updateDisabled, this);
  10030. return container;
  10031. },
  10032. onRemove: function (map) {
  10033. map.off('zoomend zoomlevelschange', this._updateDisabled, this);
  10034. },
  10035. disable: function () {
  10036. this._disabled = true;
  10037. this._updateDisabled();
  10038. return this;
  10039. },
  10040. enable: function () {
  10041. this._disabled = false;
  10042. this._updateDisabled();
  10043. return this;
  10044. },
  10045. _zoomIn: function (e) {
  10046. if (!this._disabled && this._map._zoom < this._map.getMaxZoom()) {
  10047. this._map.zoomIn(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
  10048. }
  10049. },
  10050. _zoomOut: function (e) {
  10051. if (!this._disabled && this._map._zoom > this._map.getMinZoom()) {
  10052. this._map.zoomOut(this._map.options.zoomDelta * (e.shiftKey ? 3 : 1));
  10053. }
  10054. },
  10055. _createButton: function (html, title, className, container, fn) {
  10056. var link = L.DomUtil.create('a', className, container);
  10057. link.innerHTML = html;
  10058. link.href = '#';
  10059. link.title = title;
  10060. /*
  10061. * Will force screen readers like VoiceOver to read this as "Zoom in - button"
  10062. */
  10063. link.setAttribute('role', 'button');
  10064. link.setAttribute('aria-label', title);
  10065. L.DomEvent
  10066. .on(link, 'mousedown dblclick', L.DomEvent.stopPropagation)
  10067. .on(link, 'click', L.DomEvent.stop)
  10068. .on(link, 'click', fn, this)
  10069. .on(link, 'click', this._refocusOnMap, this);
  10070. return link;
  10071. },
  10072. _updateDisabled: function () {
  10073. var map = this._map,
  10074. className = 'leaflet-disabled';
  10075. L.DomUtil.removeClass(this._zoomInButton, className);
  10076. L.DomUtil.removeClass(this._zoomOutButton, className);
  10077. if (this._disabled || map._zoom === map.getMinZoom()) {
  10078. L.DomUtil.addClass(this._zoomOutButton, className);
  10079. }
  10080. if (this._disabled || map._zoom === map.getMaxZoom()) {
  10081. L.DomUtil.addClass(this._zoomInButton, className);
  10082. }
  10083. }
  10084. });
  10085. // @namespace Map
  10086. // @section Control options
  10087. // @option zoomControl: Boolean = true
  10088. // Whether a [zoom control](#control-zoom) is added to the map by default.
  10089. L.Map.mergeOptions({
  10090. zoomControl: true
  10091. });
  10092. L.Map.addInitHook(function () {
  10093. if (this.options.zoomControl) {
  10094. this.zoomControl = new L.Control.Zoom();
  10095. this.addControl(this.zoomControl);
  10096. }
  10097. });
  10098. // @namespace Control.Zoom
  10099. // @factory L.control.zoom(options: Control.Zoom options)
  10100. // Creates a zoom control
  10101. L.control.zoom = function (options) {
  10102. return new L.Control.Zoom(options);
  10103. };
  10104. /*
  10105. * @class Control.Attribution
  10106. * @aka L.Control.Attribution
  10107. * @inherits Control
  10108. *
  10109. * The attribution control allows you to display attribution data in a small text box on a map. It is put on the map by default unless you set its [`attributionControl` option](#map-attributioncontrol) to `false`, and it fetches attribution texts from layers with the [`getAttribution` method](#layer-getattribution) automatically. Extends Control.
  10110. */
  10111. L.Control.Attribution = L.Control.extend({
  10112. // @section
  10113. // @aka Control.Attribution options
  10114. options: {
  10115. position: 'bottomright',
  10116. // @option prefix: String = 'Leaflet'
  10117. // The HTML text shown before the attributions. Pass `false` to disable.
  10118. prefix: '<a href="http://leafletjs.com" title="A JS library for interactive maps">Leaflet</a>'
  10119. },
  10120. initialize: function (options) {
  10121. L.setOptions(this, options);
  10122. this._attributions = {};
  10123. },
  10124. onAdd: function (map) {
  10125. map.attributionControl = this;
  10126. this._container = L.DomUtil.create('div', 'leaflet-control-attribution');
  10127. if (L.DomEvent) {
  10128. L.DomEvent.disableClickPropagation(this._container);
  10129. }
  10130. // TODO ugly, refactor
  10131. for (var i in map._layers) {
  10132. if (map._layers[i].getAttribution) {
  10133. this.addAttribution(map._layers[i].getAttribution());
  10134. }
  10135. }
  10136. this._update();
  10137. return this._container;
  10138. },
  10139. // @method setPrefix(prefix: String): this
  10140. // Sets the text before the attributions.
  10141. setPrefix: function (prefix) {
  10142. this.options.prefix = prefix;
  10143. this._update();
  10144. return this;
  10145. },
  10146. // @method addAttribution(text: String): this
  10147. // Adds an attribution text (e.g. `'Vector data &copy; Mapbox'`).
  10148. addAttribution: function (text) {
  10149. if (!text) { return this; }
  10150. if (!this._attributions[text]) {
  10151. this._attributions[text] = 0;
  10152. }
  10153. this._attributions[text]++;
  10154. this._update();
  10155. return this;
  10156. },
  10157. // @method removeAttribution(text: String): this
  10158. // Removes an attribution text.
  10159. removeAttribution: function (text) {
  10160. if (!text) { return this; }
  10161. if (this._attributions[text]) {
  10162. this._attributions[text]--;
  10163. this._update();
  10164. }
  10165. return this;
  10166. },
  10167. _update: function () {
  10168. if (!this._map) { return; }
  10169. var attribs = [];
  10170. for (var i in this._attributions) {
  10171. if (this._attributions[i]) {
  10172. attribs.push(i);
  10173. }
  10174. }
  10175. var prefixAndAttribs = [];
  10176. if (this.options.prefix) {
  10177. prefixAndAttribs.push(this.options.prefix);
  10178. }
  10179. if (attribs.length) {
  10180. prefixAndAttribs.push(attribs.join(', '));
  10181. }
  10182. this._container.innerHTML = prefixAndAttribs.join(' | ');
  10183. }
  10184. });
  10185. // @namespace Map
  10186. // @section Control options
  10187. // @option attributionControl: Boolean = true
  10188. // Whether a [attribution control](#control-attribution) is added to the map by default.
  10189. L.Map.mergeOptions({
  10190. attributionControl: true
  10191. });
  10192. L.Map.addInitHook(function () {
  10193. if (this.options.attributionControl) {
  10194. new L.Control.Attribution().addTo(this);
  10195. }
  10196. });
  10197. // @namespace Control.Attribution
  10198. // @factory L.control.attribution(options: Control.Attribution options)
  10199. // Creates an attribution control.
  10200. L.control.attribution = function (options) {
  10201. return new L.Control.Attribution(options);
  10202. };
  10203. /*
  10204. * @class Control.Scale
  10205. * @aka L.Control.Scale
  10206. * @inherits Control
  10207. *
  10208. * A simple scale control that shows the scale of the current center of screen in metric (m/km) and imperial (mi/ft) systems. Extends `Control`.
  10209. *
  10210. * @example
  10211. *
  10212. * ```js
  10213. * L.control.scale().addTo(map);
  10214. * ```
  10215. */
  10216. L.Control.Scale = L.Control.extend({
  10217. // @section
  10218. // @aka Control.Scale options
  10219. options: {
  10220. position: 'bottomleft',
  10221. // @option maxWidth: Number = 100
  10222. // Maximum width of the control in pixels. The width is set dynamically to show round values (e.g. 100, 200, 500).
  10223. maxWidth: 100,
  10224. // @option metric: Boolean = True
  10225. // Whether to show the metric scale line (m/km).
  10226. metric: true,
  10227. // @option imperial: Boolean = True
  10228. // Whether to show the imperial scale line (mi/ft).
  10229. imperial: true
  10230. // @option updateWhenIdle: Boolean = false
  10231. // If `true`, the control is updated on [`moveend`](#map-moveend), otherwise it's always up-to-date (updated on [`move`](#map-move)).
  10232. },
  10233. onAdd: function (map) {
  10234. var className = 'leaflet-control-scale',
  10235. container = L.DomUtil.create('div', className),
  10236. options = this.options;
  10237. this._addScales(options, className + '-line', container);
  10238. map.on(options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
  10239. map.whenReady(this._update, this);
  10240. return container;
  10241. },
  10242. onRemove: function (map) {
  10243. map.off(this.options.updateWhenIdle ? 'moveend' : 'move', this._update, this);
  10244. },
  10245. _addScales: function (options, className, container) {
  10246. if (options.metric) {
  10247. this._mScale = L.DomUtil.create('div', className, container);
  10248. }
  10249. if (options.imperial) {
  10250. this._iScale = L.DomUtil.create('div', className, container);
  10251. }
  10252. },
  10253. _update: function () {
  10254. var map = this._map,
  10255. y = map.getSize().y / 2;
  10256. var maxMeters = map.distance(
  10257. map.containerPointToLatLng([0, y]),
  10258. map.containerPointToLatLng([this.options.maxWidth, y]));
  10259. this._updateScales(maxMeters);
  10260. },
  10261. _updateScales: function (maxMeters) {
  10262. if (this.options.metric && maxMeters) {
  10263. this._updateMetric(maxMeters);
  10264. }
  10265. if (this.options.imperial && maxMeters) {
  10266. this._updateImperial(maxMeters);
  10267. }
  10268. },
  10269. _updateMetric: function (maxMeters) {
  10270. var meters = this._getRoundNum(maxMeters),
  10271. label = meters < 1000 ? meters + ' m' : (meters / 1000) + ' km';
  10272. this._updateScale(this._mScale, label, meters / maxMeters);
  10273. },
  10274. _updateImperial: function (maxMeters) {
  10275. var maxFeet = maxMeters * 3.2808399,
  10276. maxMiles, miles, feet;
  10277. if (maxFeet > 5280) {
  10278. maxMiles = maxFeet / 5280;
  10279. miles = this._getRoundNum(maxMiles);
  10280. this._updateScale(this._iScale, miles + ' mi', miles / maxMiles);
  10281. } else {
  10282. feet = this._getRoundNum(maxFeet);
  10283. this._updateScale(this._iScale, feet + ' ft', feet / maxFeet);
  10284. }
  10285. },
  10286. _updateScale: function (scale, text, ratio) {
  10287. scale.style.width = Math.round(this.options.maxWidth * ratio) + 'px';
  10288. scale.innerHTML = text;
  10289. },
  10290. _getRoundNum: function (num) {
  10291. var pow10 = Math.pow(10, (Math.floor(num) + '').length - 1),
  10292. d = num / pow10;
  10293. d = d >= 10 ? 10 :
  10294. d >= 5 ? 5 :
  10295. d >= 3 ? 3 :
  10296. d >= 2 ? 2 : 1;
  10297. return pow10 * d;
  10298. }
  10299. });
  10300. // @factory L.control.scale(options?: Control.Scale options)
  10301. // Creates an scale control with the given options.
  10302. L.control.scale = function (options) {
  10303. return new L.Control.Scale(options);
  10304. };
  10305. /*
  10306. * @class Control.Layers
  10307. * @aka L.Control.Layers
  10308. * @inherits Control
  10309. *
  10310. * The layers control gives users the ability to switch between different base layers and switch overlays on/off (check out the [detailed example](http://leafletjs.com/examples/layers-control.html)). Extends `Control`.
  10311. *
  10312. * @example
  10313. *
  10314. * ```js
  10315. * var baseLayers = {
  10316. * "Mapbox": mapbox,
  10317. * "OpenStreetMap": osm
  10318. * };
  10319. *
  10320. * var overlays = {
  10321. * "Marker": marker,
  10322. * "Roads": roadsLayer
  10323. * };
  10324. *
  10325. * L.control.layers(baseLayers, overlays).addTo(map);
  10326. * ```
  10327. *
  10328. * The `baseLayers` and `overlays` parameters are object literals with layer names as keys and `Layer` objects as values:
  10329. *
  10330. * ```js
  10331. * {
  10332. * "<someName1>": layer1,
  10333. * "<someName2>": layer2
  10334. * }
  10335. * ```
  10336. *
  10337. * The layer names can contain HTML, which allows you to add additional styling to the items:
  10338. *
  10339. * ```js
  10340. * {"<img src='my-layer-icon' /> <span class='my-layer-item'>My Layer</span>": myLayer}
  10341. * ```
  10342. */
  10343. L.Control.Layers = L.Control.extend({
  10344. // @section
  10345. // @aka Control.Layers options
  10346. options: {
  10347. // @option collapsed: Boolean = true
  10348. // If `true`, the control will be collapsed into an icon and expanded on mouse hover or touch.
  10349. collapsed: true,
  10350. position: 'topright',
  10351. // @option autoZIndex: Boolean = true
  10352. // If `true`, the control will assign zIndexes in increasing order to all of its layers so that the order is preserved when switching them on/off.
  10353. autoZIndex: true,
  10354. // @option hideSingleBase: Boolean = false
  10355. // If `true`, the base layers in the control will be hidden when there is only one.
  10356. hideSingleBase: false,
  10357. // @option sortLayers: Boolean = false
  10358. // Whether to sort the layers. When `false`, layers will keep the order
  10359. // in which they were added to the control.
  10360. sortLayers: false,
  10361. // @option sortFunction: Function = *
  10362. // A [compare function](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/sort)
  10363. // that will be used for sorting the layers, when `sortLayers` is `true`.
  10364. // The function receives both the `L.Layer` instances and their names, as in
  10365. // `sortFunction(layerA, layerB, nameA, nameB)`.
  10366. // By default, it sorts layers alphabetically by their name.
  10367. sortFunction: function (layerA, layerB, nameA, nameB) {
  10368. return nameA < nameB ? -1 : (nameB < nameA ? 1 : 0);
  10369. }
  10370. },
  10371. initialize: function (baseLayers, overlays, options) {
  10372. L.setOptions(this, options);
  10373. this._layers = [];
  10374. this._lastZIndex = 0;
  10375. this._handlingClick = false;
  10376. for (var i in baseLayers) {
  10377. this._addLayer(baseLayers[i], i);
  10378. }
  10379. for (i in overlays) {
  10380. this._addLayer(overlays[i], i, true);
  10381. }
  10382. },
  10383. onAdd: function (map) {
  10384. this._initLayout();
  10385. this._update();
  10386. this._map = map;
  10387. map.on('zoomend', this._checkDisabledLayers, this);
  10388. return this._container;
  10389. },
  10390. onRemove: function () {
  10391. this._map.off('zoomend', this._checkDisabledLayers, this);
  10392. for (var i = 0; i < this._layers.length; i++) {
  10393. this._layers[i].layer.off('add remove', this._onLayerChange, this);
  10394. }
  10395. },
  10396. // @method addBaseLayer(layer: Layer, name: String): this
  10397. // Adds a base layer (radio button entry) with the given name to the control.
  10398. addBaseLayer: function (layer, name) {
  10399. this._addLayer(layer, name);
  10400. return (this._map) ? this._update() : this;
  10401. },
  10402. // @method addOverlay(layer: Layer, name: String): this
  10403. // Adds an overlay (checkbox entry) with the given name to the control.
  10404. addOverlay: function (layer, name) {
  10405. this._addLayer(layer, name, true);
  10406. return (this._map) ? this._update() : this;
  10407. },
  10408. // @method removeLayer(layer: Layer): this
  10409. // Remove the given layer from the control.
  10410. removeLayer: function (layer) {
  10411. layer.off('add remove', this._onLayerChange, this);
  10412. var obj = this._getLayer(L.stamp(layer));
  10413. if (obj) {
  10414. this._layers.splice(this._layers.indexOf(obj), 1);
  10415. }
  10416. return (this._map) ? this._update() : this;
  10417. },
  10418. // @method expand(): this
  10419. // Expand the control container if collapsed.
  10420. expand: function () {
  10421. L.DomUtil.addClass(this._container, 'leaflet-control-layers-expanded');
  10422. this._form.style.height = null;
  10423. var acceptableHeight = this._map.getSize().y - (this._container.offsetTop + 50);
  10424. if (acceptableHeight < this._form.clientHeight) {
  10425. L.DomUtil.addClass(this._form, 'leaflet-control-layers-scrollbar');
  10426. this._form.style.height = acceptableHeight + 'px';
  10427. } else {
  10428. L.DomUtil.removeClass(this._form, 'leaflet-control-layers-scrollbar');
  10429. }
  10430. this._checkDisabledLayers();
  10431. return this;
  10432. },
  10433. // @method collapse(): this
  10434. // Collapse the control container if expanded.
  10435. collapse: function () {
  10436. L.DomUtil.removeClass(this._container, 'leaflet-control-layers-expanded');
  10437. return this;
  10438. },
  10439. _initLayout: function () {
  10440. var className = 'leaflet-control-layers',
  10441. container = this._container = L.DomUtil.create('div', className);
  10442. // makes this work on IE touch devices by stopping it from firing a mouseout event when the touch is released
  10443. container.setAttribute('aria-haspopup', true);
  10444. L.DomEvent.disableClickPropagation(container);
  10445. if (!L.Browser.touch) {
  10446. L.DomEvent.disableScrollPropagation(container);
  10447. }
  10448. var form = this._form = L.DomUtil.create('form', className + '-list');
  10449. if (!L.Browser.android) {
  10450. L.DomEvent.on(container, {
  10451. mouseenter: this.expand,
  10452. mouseleave: this.collapse
  10453. }, this);
  10454. }
  10455. var link = this._layersLink = L.DomUtil.create('a', className + '-toggle', container);
  10456. link.href = '#';
  10457. link.title = 'Layers';
  10458. if (L.Browser.touch) {
  10459. L.DomEvent
  10460. .on(link, 'click', L.DomEvent.stop)
  10461. .on(link, 'click', this.expand, this);
  10462. } else {
  10463. L.DomEvent.on(link, 'focus', this.expand, this);
  10464. }
  10465. // work around for Firefox Android issue https://github.com/Leaflet/Leaflet/issues/2033
  10466. L.DomEvent.on(form, 'click', function () {
  10467. setTimeout(L.bind(this._onInputClick, this), 0);
  10468. }, this);
  10469. this._map.on('click', this.collapse, this);
  10470. // TODO keyboard accessibility
  10471. if (!this.options.collapsed) {
  10472. this.expand();
  10473. }
  10474. this._baseLayersList = L.DomUtil.create('div', className + '-base', form);
  10475. this._separator = L.DomUtil.create('div', className + '-separator', form);
  10476. this._overlaysList = L.DomUtil.create('div', className + '-overlays', form);
  10477. container.appendChild(form);
  10478. },
  10479. _getLayer: function (id) {
  10480. for (var i = 0; i < this._layers.length; i++) {
  10481. if (this._layers[i] && L.stamp(this._layers[i].layer) === id) {
  10482. return this._layers[i];
  10483. }
  10484. }
  10485. },
  10486. _addLayer: function (layer, name, overlay) {
  10487. layer.on('add remove', this._onLayerChange, this);
  10488. this._layers.push({
  10489. layer: layer,
  10490. name: name,
  10491. overlay: overlay
  10492. });
  10493. if (this.options.sortLayers) {
  10494. this._layers.sort(L.bind(function (a, b) {
  10495. return this.options.sortFunction(a.layer, b.layer, a.name, b.name);
  10496. }, this));
  10497. }
  10498. if (this.options.autoZIndex && layer.setZIndex) {
  10499. this._lastZIndex++;
  10500. layer.setZIndex(this._lastZIndex);
  10501. }
  10502. },
  10503. _update: function () {
  10504. if (!this._container) { return this; }
  10505. L.DomUtil.empty(this._baseLayersList);
  10506. L.DomUtil.empty(this._overlaysList);
  10507. var baseLayersPresent, overlaysPresent, i, obj, baseLayersCount = 0;
  10508. for (i = 0; i < this._layers.length; i++) {
  10509. obj = this._layers[i];
  10510. this._addItem(obj);
  10511. overlaysPresent = overlaysPresent || obj.overlay;
  10512. baseLayersPresent = baseLayersPresent || !obj.overlay;
  10513. baseLayersCount += !obj.overlay ? 1 : 0;
  10514. }
  10515. // Hide base layers section if there's only one layer.
  10516. if (this.options.hideSingleBase) {
  10517. baseLayersPresent = baseLayersPresent && baseLayersCount > 1;
  10518. this._baseLayersList.style.display = baseLayersPresent ? '' : 'none';
  10519. }
  10520. this._separator.style.display = overlaysPresent && baseLayersPresent ? '' : 'none';
  10521. return this;
  10522. },
  10523. _onLayerChange: function (e) {
  10524. if (!this._handlingClick) {
  10525. this._update();
  10526. }
  10527. var obj = this._getLayer(L.stamp(e.target));
  10528. // @namespace Map
  10529. // @section Layer events
  10530. // @event baselayerchange: LayersControlEvent
  10531. // Fired when the base layer is changed through the [layer control](#control-layers).
  10532. // @event overlayadd: LayersControlEvent
  10533. // Fired when an overlay is selected through the [layer control](#control-layers).
  10534. // @event overlayremove: LayersControlEvent
  10535. // Fired when an overlay is deselected through the [layer control](#control-layers).
  10536. // @namespace Control.Layers
  10537. var type = obj.overlay ?
  10538. (e.type === 'add' ? 'overlayadd' : 'overlayremove') :
  10539. (e.type === 'add' ? 'baselayerchange' : null);
  10540. if (type) {
  10541. this._map.fire(type, obj);
  10542. }
  10543. },
  10544. // IE7 bugs out if you create a radio dynamically, so you have to do it this hacky way (see http://bit.ly/PqYLBe)
  10545. _createRadioElement: function (name, checked) {
  10546. var radioHtml = '<input type="radio" class="leaflet-control-layers-selector" name="' +
  10547. name + '"' + (checked ? ' checked="checked"' : '') + '/>';
  10548. var radioFragment = document.createElement('div');
  10549. radioFragment.innerHTML = radioHtml;
  10550. return radioFragment.firstChild;
  10551. },
  10552. _addItem: function (obj) {
  10553. var label = document.createElement('label'),
  10554. checked = this._map.hasLayer(obj.layer),
  10555. input;
  10556. if (obj.overlay) {
  10557. input = document.createElement('input');
  10558. input.type = 'checkbox';
  10559. input.className = 'leaflet-control-layers-selector';
  10560. input.defaultChecked = checked;
  10561. } else {
  10562. input = this._createRadioElement('leaflet-base-layers', checked);
  10563. }
  10564. input.layerId = L.stamp(obj.layer);
  10565. L.DomEvent.on(input, 'click', this._onInputClick, this);
  10566. var name = document.createElement('span');
  10567. name.innerHTML = ' ' + obj.name;
  10568. // Helps from preventing layer control flicker when checkboxes are disabled
  10569. // https://github.com/Leaflet/Leaflet/issues/2771
  10570. var holder = document.createElement('div');
  10571. label.appendChild(holder);
  10572. holder.appendChild(input);
  10573. holder.appendChild(name);
  10574. var container = obj.overlay ? this._overlaysList : this._baseLayersList;
  10575. container.appendChild(label);
  10576. this._checkDisabledLayers();
  10577. return label;
  10578. },
  10579. _onInputClick: function () {
  10580. var inputs = this._form.getElementsByTagName('input'),
  10581. input, layer, hasLayer;
  10582. var addedLayers = [],
  10583. removedLayers = [];
  10584. this._handlingClick = true;
  10585. for (var i = inputs.length - 1; i >= 0; i--) {
  10586. input = inputs[i];
  10587. layer = this._getLayer(input.layerId).layer;
  10588. hasLayer = this._map.hasLayer(layer);
  10589. if (input.checked && !hasLayer) {
  10590. addedLayers.push(layer);
  10591. } else if (!input.checked && hasLayer) {
  10592. removedLayers.push(layer);
  10593. }
  10594. }
  10595. // Bugfix issue 2318: Should remove all old layers before readding new ones
  10596. for (i = 0; i < removedLayers.length; i++) {
  10597. this._map.removeLayer(removedLayers[i]);
  10598. }
  10599. for (i = 0; i < addedLayers.length; i++) {
  10600. this._map.addLayer(addedLayers[i]);
  10601. }
  10602. this._handlingClick = false;
  10603. this._refocusOnMap();
  10604. },
  10605. _checkDisabledLayers: function () {
  10606. var inputs = this._form.getElementsByTagName('input'),
  10607. input,
  10608. layer,
  10609. zoom = this._map.getZoom();
  10610. for (var i = inputs.length - 1; i >= 0; i--) {
  10611. input = inputs[i];
  10612. layer = this._getLayer(input.layerId).layer;
  10613. input.disabled = (layer.options.minZoom !== undefined && zoom < layer.options.minZoom) ||
  10614. (layer.options.maxZoom !== undefined && zoom > layer.options.maxZoom);
  10615. }
  10616. },
  10617. _expand: function () {
  10618. // Backward compatibility, remove me in 1.1.
  10619. return this.expand();
  10620. },
  10621. _collapse: function () {
  10622. // Backward compatibility, remove me in 1.1.
  10623. return this.collapse();
  10624. }
  10625. });
  10626. // @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options)
  10627. // Creates an attribution control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation.
  10628. L.control.layers = function (baseLayers, overlays, options) {
  10629. return new L.Control.Layers(baseLayers, overlays, options);
  10630. };
  10631. }(window, document));
  10632. },{}],4:[function(require,module,exports){
  10633. /*!
  10634. * mustache.js - Logic-less {{mustache}} templates with JavaScript
  10635. * http://github.com/janl/mustache.js
  10636. */
  10637. /*global define: false Mustache: true*/
  10638. (function defineMustache (global, factory) {
  10639. if (typeof exports === 'object' && exports && typeof exports.nodeName !== 'string') {
  10640. factory(exports); // CommonJS
  10641. } else if (typeof define === 'function' && define.amd) {
  10642. define(['exports'], factory); // AMD
  10643. } else {
  10644. global.Mustache = {};
  10645. factory(global.Mustache); // script, wsh, asp
  10646. }
  10647. }(this, function mustacheFactory (mustache) {
  10648. var objectToString = Object.prototype.toString;
  10649. var isArray = Array.isArray || function isArrayPolyfill (object) {
  10650. return objectToString.call(object) === '[object Array]';
  10651. };
  10652. function isFunction (object) {
  10653. return typeof object === 'function';
  10654. }
  10655. /**
  10656. * More correct typeof string handling array
  10657. * which normally returns typeof 'object'
  10658. */
  10659. function typeStr (obj) {
  10660. return isArray(obj) ? 'array' : typeof obj;
  10661. }
  10662. function escapeRegExp (string) {
  10663. return string.replace(/[\-\[\]{}()*+?.,\\\^$|#\s]/g, '\\$&');
  10664. }
  10665. /**
  10666. * Null safe way of checking whether or not an object,
  10667. * including its prototype, has a given property
  10668. */
  10669. function hasProperty (obj, propName) {
  10670. return obj != null && typeof obj === 'object' && (propName in obj);
  10671. }
  10672. // Workaround for https://issues.apache.org/jira/browse/COUCHDB-577
  10673. // See https://github.com/janl/mustache.js/issues/189
  10674. var regExpTest = RegExp.prototype.test;
  10675. function testRegExp (re, string) {
  10676. return regExpTest.call(re, string);
  10677. }
  10678. var nonSpaceRe = /\S/;
  10679. function isWhitespace (string) {
  10680. return !testRegExp(nonSpaceRe, string);
  10681. }
  10682. var entityMap = {
  10683. '&': '&amp;',
  10684. '<': '&lt;',
  10685. '>': '&gt;',
  10686. '"': '&quot;',
  10687. "'": '&#39;',
  10688. '/': '&#x2F;',
  10689. '`': '&#x60;',
  10690. '=': '&#x3D;'
  10691. };
  10692. function escapeHtml (string) {
  10693. return String(string).replace(/[&<>"'`=\/]/g, function fromEntityMap (s) {
  10694. return entityMap[s];
  10695. });
  10696. }
  10697. var whiteRe = /\s*/;
  10698. var spaceRe = /\s+/;
  10699. var equalsRe = /\s*=/;
  10700. var curlyRe = /\s*\}/;
  10701. var tagRe = /#|\^|\/|>|\{|&|=|!/;
  10702. /**
  10703. * Breaks up the given `template` string into a tree of tokens. If the `tags`
  10704. * argument is given here it must be an array with two string values: the
  10705. * opening and closing tags used in the template (e.g. [ "<%", "%>" ]). Of
  10706. * course, the default is to use mustaches (i.e. mustache.tags).
  10707. *
  10708. * A token is an array with at least 4 elements. The first element is the
  10709. * mustache symbol that was used inside the tag, e.g. "#" or "&". If the tag
  10710. * did not contain a symbol (i.e. {{myValue}}) this element is "name". For
  10711. * all text that appears outside a symbol this element is "text".
  10712. *
  10713. * The second element of a token is its "value". For mustache tags this is
  10714. * whatever else was inside the tag besides the opening symbol. For text tokens
  10715. * this is the text itself.
  10716. *
  10717. * The third and fourth elements of the token are the start and end indices,
  10718. * respectively, of the token in the original template.
  10719. *
  10720. * Tokens that are the root node of a subtree contain two more elements: 1) an
  10721. * array of tokens in the subtree and 2) the index in the original template at
  10722. * which the closing tag for that section begins.
  10723. */
  10724. function parseTemplate (template, tags) {
  10725. if (!template)
  10726. return [];
  10727. var sections = []; // Stack to hold section tokens
  10728. var tokens = []; // Buffer to hold the tokens
  10729. var spaces = []; // Indices of whitespace tokens on the current line
  10730. var hasTag = false; // Is there a {{tag}} on the current line?
  10731. var nonSpace = false; // Is there a non-space char on the current line?
  10732. // Strips all whitespace tokens array for the current line
  10733. // if there was a {{#tag}} on it and otherwise only space.
  10734. function stripSpace () {
  10735. if (hasTag && !nonSpace) {
  10736. while (spaces.length)
  10737. delete tokens[spaces.pop()];
  10738. } else {
  10739. spaces = [];
  10740. }
  10741. hasTag = false;
  10742. nonSpace = false;
  10743. }
  10744. var openingTagRe, closingTagRe, closingCurlyRe;
  10745. function compileTags (tagsToCompile) {
  10746. if (typeof tagsToCompile === 'string')
  10747. tagsToCompile = tagsToCompile.split(spaceRe, 2);
  10748. if (!isArray(tagsToCompile) || tagsToCompile.length !== 2)
  10749. throw new Error('Invalid tags: ' + tagsToCompile);
  10750. openingTagRe = new RegExp(escapeRegExp(tagsToCompile[0]) + '\\s*');
  10751. closingTagRe = new RegExp('\\s*' + escapeRegExp(tagsToCompile[1]));
  10752. closingCurlyRe = new RegExp('\\s*' + escapeRegExp('}' + tagsToCompile[1]));
  10753. }
  10754. compileTags(tags || mustache.tags);
  10755. var scanner = new Scanner(template);
  10756. var start, type, value, chr, token, openSection;
  10757. while (!scanner.eos()) {
  10758. start = scanner.pos;
  10759. // Match any text between tags.
  10760. value = scanner.scanUntil(openingTagRe);
  10761. if (value) {
  10762. for (var i = 0, valueLength = value.length; i < valueLength; ++i) {
  10763. chr = value.charAt(i);
  10764. if (isWhitespace(chr)) {
  10765. spaces.push(tokens.length);
  10766. } else {
  10767. nonSpace = true;
  10768. }
  10769. tokens.push([ 'text', chr, start, start + 1 ]);
  10770. start += 1;
  10771. // Check for whitespace on the current line.
  10772. if (chr === '\n')
  10773. stripSpace();
  10774. }
  10775. }
  10776. // Match the opening tag.
  10777. if (!scanner.scan(openingTagRe))
  10778. break;
  10779. hasTag = true;
  10780. // Get the tag type.
  10781. type = scanner.scan(tagRe) || 'name';
  10782. scanner.scan(whiteRe);
  10783. // Get the tag value.
  10784. if (type === '=') {
  10785. value = scanner.scanUntil(equalsRe);
  10786. scanner.scan(equalsRe);
  10787. scanner.scanUntil(closingTagRe);
  10788. } else if (type === '{') {
  10789. value = scanner.scanUntil(closingCurlyRe);
  10790. scanner.scan(curlyRe);
  10791. scanner.scanUntil(closingTagRe);
  10792. type = '&';
  10793. } else {
  10794. value = scanner.scanUntil(closingTagRe);
  10795. }
  10796. // Match the closing tag.
  10797. if (!scanner.scan(closingTagRe))
  10798. throw new Error('Unclosed tag at ' + scanner.pos);
  10799. token = [ type, value, start, scanner.pos ];
  10800. tokens.push(token);
  10801. if (type === '#' || type === '^') {
  10802. sections.push(token);
  10803. } else if (type === '/') {
  10804. // Check section nesting.
  10805. openSection = sections.pop();
  10806. if (!openSection)
  10807. throw new Error('Unopened section "' + value + '" at ' + start);
  10808. if (openSection[1] !== value)
  10809. throw new Error('Unclosed section "' + openSection[1] + '" at ' + start);
  10810. } else if (type === 'name' || type === '{' || type === '&') {
  10811. nonSpace = true;
  10812. } else if (type === '=') {
  10813. // Set the tags for the next time around.
  10814. compileTags(value);
  10815. }
  10816. }
  10817. // Make sure there are no open sections when we're done.
  10818. openSection = sections.pop();
  10819. if (openSection)
  10820. throw new Error('Unclosed section "' + openSection[1] + '" at ' + scanner.pos);
  10821. return nestTokens(squashTokens(tokens));
  10822. }
  10823. /**
  10824. * Combines the values of consecutive text tokens in the given `tokens` array
  10825. * to a single token.
  10826. */
  10827. function squashTokens (tokens) {
  10828. var squashedTokens = [];
  10829. var token, lastToken;
  10830. for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
  10831. token = tokens[i];
  10832. if (token) {
  10833. if (token[0] === 'text' && lastToken && lastToken[0] === 'text') {
  10834. lastToken[1] += token[1];
  10835. lastToken[3] = token[3];
  10836. } else {
  10837. squashedTokens.push(token);
  10838. lastToken = token;
  10839. }
  10840. }
  10841. }
  10842. return squashedTokens;
  10843. }
  10844. /**
  10845. * Forms the given array of `tokens` into a nested tree structure where
  10846. * tokens that represent a section have two additional items: 1) an array of
  10847. * all tokens that appear in that section and 2) the index in the original
  10848. * template that represents the end of that section.
  10849. */
  10850. function nestTokens (tokens) {
  10851. var nestedTokens = [];
  10852. var collector = nestedTokens;
  10853. var sections = [];
  10854. var token, section;
  10855. for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
  10856. token = tokens[i];
  10857. switch (token[0]) {
  10858. case '#':
  10859. case '^':
  10860. collector.push(token);
  10861. sections.push(token);
  10862. collector = token[4] = [];
  10863. break;
  10864. case '/':
  10865. section = sections.pop();
  10866. section[5] = token[2];
  10867. collector = sections.length > 0 ? sections[sections.length - 1][4] : nestedTokens;
  10868. break;
  10869. default:
  10870. collector.push(token);
  10871. }
  10872. }
  10873. return nestedTokens;
  10874. }
  10875. /**
  10876. * A simple string scanner that is used by the template parser to find
  10877. * tokens in template strings.
  10878. */
  10879. function Scanner (string) {
  10880. this.string = string;
  10881. this.tail = string;
  10882. this.pos = 0;
  10883. }
  10884. /**
  10885. * Returns `true` if the tail is empty (end of string).
  10886. */
  10887. Scanner.prototype.eos = function eos () {
  10888. return this.tail === '';
  10889. };
  10890. /**
  10891. * Tries to match the given regular expression at the current position.
  10892. * Returns the matched text if it can match, the empty string otherwise.
  10893. */
  10894. Scanner.prototype.scan = function scan (re) {
  10895. var match = this.tail.match(re);
  10896. if (!match || match.index !== 0)
  10897. return '';
  10898. var string = match[0];
  10899. this.tail = this.tail.substring(string.length);
  10900. this.pos += string.length;
  10901. return string;
  10902. };
  10903. /**
  10904. * Skips all text until the given regular expression can be matched. Returns
  10905. * the skipped string, which is the entire tail if no match can be made.
  10906. */
  10907. Scanner.prototype.scanUntil = function scanUntil (re) {
  10908. var index = this.tail.search(re), match;
  10909. switch (index) {
  10910. case -1:
  10911. match = this.tail;
  10912. this.tail = '';
  10913. break;
  10914. case 0:
  10915. match = '';
  10916. break;
  10917. default:
  10918. match = this.tail.substring(0, index);
  10919. this.tail = this.tail.substring(index);
  10920. }
  10921. this.pos += match.length;
  10922. return match;
  10923. };
  10924. /**
  10925. * Represents a rendering context by wrapping a view object and
  10926. * maintaining a reference to the parent context.
  10927. */
  10928. function Context (view, parentContext) {
  10929. this.view = view;
  10930. this.cache = { '.': this.view };
  10931. this.parent = parentContext;
  10932. }
  10933. /**
  10934. * Creates a new context using the given view with this context
  10935. * as the parent.
  10936. */
  10937. Context.prototype.push = function push (view) {
  10938. return new Context(view, this);
  10939. };
  10940. /**
  10941. * Returns the value of the given name in this context, traversing
  10942. * up the context hierarchy if the value is absent in this context's view.
  10943. */
  10944. Context.prototype.lookup = function lookup (name) {
  10945. var cache = this.cache;
  10946. var value;
  10947. if (cache.hasOwnProperty(name)) {
  10948. value = cache[name];
  10949. } else {
  10950. var context = this, names, index, lookupHit = false;
  10951. while (context) {
  10952. if (name.indexOf('.') > 0) {
  10953. value = context.view;
  10954. names = name.split('.');
  10955. index = 0;
  10956. /**
  10957. * Using the dot notion path in `name`, we descend through the
  10958. * nested objects.
  10959. *
  10960. * To be certain that the lookup has been successful, we have to
  10961. * check if the last object in the path actually has the property
  10962. * we are looking for. We store the result in `lookupHit`.
  10963. *
  10964. * This is specially necessary for when the value has been set to
  10965. * `undefined` and we want to avoid looking up parent contexts.
  10966. **/
  10967. while (value != null && index < names.length) {
  10968. if (index === names.length - 1)
  10969. lookupHit = hasProperty(value, names[index]);
  10970. value = value[names[index++]];
  10971. }
  10972. } else {
  10973. value = context.view[name];
  10974. lookupHit = hasProperty(context.view, name);
  10975. }
  10976. if (lookupHit)
  10977. break;
  10978. context = context.parent;
  10979. }
  10980. cache[name] = value;
  10981. }
  10982. if (isFunction(value))
  10983. value = value.call(this.view);
  10984. return value;
  10985. };
  10986. /**
  10987. * A Writer knows how to take a stream of tokens and render them to a
  10988. * string, given a context. It also maintains a cache of templates to
  10989. * avoid the need to parse the same template twice.
  10990. */
  10991. function Writer () {
  10992. this.cache = {};
  10993. }
  10994. /**
  10995. * Clears all cached templates in this writer.
  10996. */
  10997. Writer.prototype.clearCache = function clearCache () {
  10998. this.cache = {};
  10999. };
  11000. /**
  11001. * Parses and caches the given `template` and returns the array of tokens
  11002. * that is generated from the parse.
  11003. */
  11004. Writer.prototype.parse = function parse (template, tags) {
  11005. var cache = this.cache;
  11006. var tokens = cache[template];
  11007. if (tokens == null)
  11008. tokens = cache[template] = parseTemplate(template, tags);
  11009. return tokens;
  11010. };
  11011. /**
  11012. * High-level method that is used to render the given `template` with
  11013. * the given `view`.
  11014. *
  11015. * The optional `partials` argument may be an object that contains the
  11016. * names and templates of partials that are used in the template. It may
  11017. * also be a function that is used to load partial templates on the fly
  11018. * that takes a single argument: the name of the partial.
  11019. */
  11020. Writer.prototype.render = function render (template, view, partials) {
  11021. var tokens = this.parse(template);
  11022. var context = (view instanceof Context) ? view : new Context(view);
  11023. return this.renderTokens(tokens, context, partials, template);
  11024. };
  11025. /**
  11026. * Low-level method that renders the given array of `tokens` using
  11027. * the given `context` and `partials`.
  11028. *
  11029. * Note: The `originalTemplate` is only ever used to extract the portion
  11030. * of the original template that was contained in a higher-order section.
  11031. * If the template doesn't use higher-order sections, this argument may
  11032. * be omitted.
  11033. */
  11034. Writer.prototype.renderTokens = function renderTokens (tokens, context, partials, originalTemplate) {
  11035. var buffer = '';
  11036. var token, symbol, value;
  11037. for (var i = 0, numTokens = tokens.length; i < numTokens; ++i) {
  11038. value = undefined;
  11039. token = tokens[i];
  11040. symbol = token[0];
  11041. if (symbol === '#') value = this.renderSection(token, context, partials, originalTemplate);
  11042. else if (symbol === '^') value = this.renderInverted(token, context, partials, originalTemplate);
  11043. else if (symbol === '>') value = this.renderPartial(token, context, partials, originalTemplate);
  11044. else if (symbol === '&') value = this.unescapedValue(token, context);
  11045. else if (symbol === 'name') value = this.escapedValue(token, context);
  11046. else if (symbol === 'text') value = this.rawValue(token);
  11047. if (value !== undefined)
  11048. buffer += value;
  11049. }
  11050. return buffer;
  11051. };
  11052. Writer.prototype.renderSection = function renderSection (token, context, partials, originalTemplate) {
  11053. var self = this;
  11054. var buffer = '';
  11055. var value = context.lookup(token[1]);
  11056. // This function is used to render an arbitrary template
  11057. // in the current context by higher-order sections.
  11058. function subRender (template) {
  11059. return self.render(template, context, partials);
  11060. }
  11061. if (!value) return;
  11062. if (isArray(value)) {
  11063. for (var j = 0, valueLength = value.length; j < valueLength; ++j) {
  11064. buffer += this.renderTokens(token[4], context.push(value[j]), partials, originalTemplate);
  11065. }
  11066. } else if (typeof value === 'object' || typeof value === 'string' || typeof value === 'number') {
  11067. buffer += this.renderTokens(token[4], context.push(value), partials, originalTemplate);
  11068. } else if (isFunction(value)) {
  11069. if (typeof originalTemplate !== 'string')
  11070. throw new Error('Cannot use higher-order sections without the original template');
  11071. // Extract the portion of the original template that the section contains.
  11072. value = value.call(context.view, originalTemplate.slice(token[3], token[5]), subRender);
  11073. if (value != null)
  11074. buffer += value;
  11075. } else {
  11076. buffer += this.renderTokens(token[4], context, partials, originalTemplate);
  11077. }
  11078. return buffer;
  11079. };
  11080. Writer.prototype.renderInverted = function renderInverted (token, context, partials, originalTemplate) {
  11081. var value = context.lookup(token[1]);
  11082. // Use JavaScript's definition of falsy. Include empty arrays.
  11083. // See https://github.com/janl/mustache.js/issues/186
  11084. if (!value || (isArray(value) && value.length === 0))
  11085. return this.renderTokens(token[4], context, partials, originalTemplate);
  11086. };
  11087. Writer.prototype.renderPartial = function renderPartial (token, context, partials) {
  11088. if (!partials) return;
  11089. var value = isFunction(partials) ? partials(token[1]) : partials[token[1]];
  11090. if (value != null)
  11091. return this.renderTokens(this.parse(value), context, partials, value);
  11092. };
  11093. Writer.prototype.unescapedValue = function unescapedValue (token, context) {
  11094. var value = context.lookup(token[1]);
  11095. if (value != null)
  11096. return value;
  11097. };
  11098. Writer.prototype.escapedValue = function escapedValue (token, context) {
  11099. var value = context.lookup(token[1]);
  11100. if (value != null)
  11101. return mustache.escape(value);
  11102. };
  11103. Writer.prototype.rawValue = function rawValue (token) {
  11104. return token[1];
  11105. };
  11106. mustache.name = 'mustache.js';
  11107. mustache.version = '2.2.1';
  11108. mustache.tags = [ '{{', '}}' ];
  11109. // All high-level mustache.* functions use this writer.
  11110. var defaultWriter = new Writer();
  11111. /**
  11112. * Clears all cached templates in the default writer.
  11113. */
  11114. mustache.clearCache = function clearCache () {
  11115. return defaultWriter.clearCache();
  11116. };
  11117. /**
  11118. * Parses and caches the given template in the default writer and returns the
  11119. * array of tokens it contains. Doing this ahead of time avoids the need to
  11120. * parse templates on the fly as they are rendered.
  11121. */
  11122. mustache.parse = function parse (template, tags) {
  11123. return defaultWriter.parse(template, tags);
  11124. };
  11125. /**
  11126. * Renders the `template` with the given `view` and `partials` using the
  11127. * default writer.
  11128. */
  11129. mustache.render = function render (template, view, partials) {
  11130. if (typeof template !== 'string') {
  11131. throw new TypeError('Invalid template! Template should be a "string" ' +
  11132. 'but "' + typeStr(template) + '" was given as the first ' +
  11133. 'argument for mustache#render(template, view, partials)');
  11134. }
  11135. return defaultWriter.render(template, view, partials);
  11136. };
  11137. // This is here for backwards compatibility with 0.4.x.,
  11138. /*eslint-disable */ // eslint wants camel cased function name
  11139. mustache.to_html = function to_html (template, view, partials, send) {
  11140. /*eslint-enable*/
  11141. var result = mustache.render(template, view, partials);
  11142. if (isFunction(send)) {
  11143. send(result);
  11144. } else {
  11145. return result;
  11146. }
  11147. };
  11148. // Export the escaping function so that the user may override it.
  11149. // See https://github.com/janl/mustache.js/issues/244
  11150. mustache.escape = escapeHtml;
  11151. // Export these mainly for testing, but also for advanced usage.
  11152. mustache.Scanner = Scanner;
  11153. mustache.Context = Context;
  11154. mustache.Writer = Writer;
  11155. }));
  11156. },{}],5:[function(require,module,exports){
  11157. var html_sanitize = require('./sanitizer-bundle.js');
  11158. module.exports = function(_) {
  11159. if (!_) return '';
  11160. return html_sanitize(_, cleanUrl, cleanId);
  11161. };
  11162. // https://bugzilla.mozilla.org/show_bug.cgi?id=255107
  11163. function cleanUrl(url) {
  11164. 'use strict';
  11165. if (/^https?/.test(url.getScheme())) return url.toString();
  11166. if (/^mailto?/.test(url.getScheme())) return url.toString();
  11167. if ('data' == url.getScheme() && /^image/.test(url.getPath())) {
  11168. return url.toString();
  11169. }
  11170. }
  11171. function cleanId(id) { return id; }
  11172. },{"./sanitizer-bundle.js":6}],6:[function(require,module,exports){
  11173. // Copyright (C) 2010 Google Inc.
  11174. //
  11175. // Licensed under the Apache License, Version 2.0 (the "License");
  11176. // you may not use this file except in compliance with the License.
  11177. // You may obtain a copy of the License at
  11178. //
  11179. // http://www.apache.org/licenses/LICENSE-2.0
  11180. //
  11181. // Unless required by applicable law or agreed to in writing, software
  11182. // distributed under the License is distributed on an "AS IS" BASIS,
  11183. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11184. // See the License for the specific language governing permissions and
  11185. // limitations under the License.
  11186. /**
  11187. * @fileoverview
  11188. * Implements RFC 3986 for parsing/formatting URIs.
  11189. *
  11190. * @author mikesamuel@gmail.com
  11191. * \@provides URI
  11192. * \@overrides window
  11193. */
  11194. var URI = (function () {
  11195. /**
  11196. * creates a uri from the string form. The parser is relaxed, so special
  11197. * characters that aren't escaped but don't cause ambiguities will not cause
  11198. * parse failures.
  11199. *
  11200. * @return {URI|null}
  11201. */
  11202. function parse(uriStr) {
  11203. var m = ('' + uriStr).match(URI_RE_);
  11204. if (!m) { return null; }
  11205. return new URI(
  11206. nullIfAbsent(m[1]),
  11207. nullIfAbsent(m[2]),
  11208. nullIfAbsent(m[3]),
  11209. nullIfAbsent(m[4]),
  11210. nullIfAbsent(m[5]),
  11211. nullIfAbsent(m[6]),
  11212. nullIfAbsent(m[7]));
  11213. }
  11214. /**
  11215. * creates a uri from the given parts.
  11216. *
  11217. * @param scheme {string} an unencoded scheme such as "http" or null
  11218. * @param credentials {string} unencoded user credentials or null
  11219. * @param domain {string} an unencoded domain name or null
  11220. * @param port {number} a port number in [1, 32768].
  11221. * -1 indicates no port, as does null.
  11222. * @param path {string} an unencoded path
  11223. * @param query {Array.<string>|string|null} a list of unencoded cgi
  11224. * parameters where even values are keys and odds the corresponding values
  11225. * or an unencoded query.
  11226. * @param fragment {string} an unencoded fragment without the "#" or null.
  11227. * @return {URI}
  11228. */
  11229. function create(scheme, credentials, domain, port, path, query, fragment) {
  11230. var uri = new URI(
  11231. encodeIfExists2(scheme, URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_),
  11232. encodeIfExists2(
  11233. credentials, URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_),
  11234. encodeIfExists(domain),
  11235. port > 0 ? port.toString() : null,
  11236. encodeIfExists2(path, URI_DISALLOWED_IN_PATH_),
  11237. null,
  11238. encodeIfExists(fragment));
  11239. if (query) {
  11240. if ('string' === typeof query) {
  11241. uri.setRawQuery(query.replace(/[^?&=0-9A-Za-z_\-~.%]/g, encodeOne));
  11242. } else {
  11243. uri.setAllParameters(query);
  11244. }
  11245. }
  11246. return uri;
  11247. }
  11248. function encodeIfExists(unescapedPart) {
  11249. if ('string' == typeof unescapedPart) {
  11250. return encodeURIComponent(unescapedPart);
  11251. }
  11252. return null;
  11253. };
  11254. /**
  11255. * if unescapedPart is non null, then escapes any characters in it that aren't
  11256. * valid characters in a url and also escapes any special characters that
  11257. * appear in extra.
  11258. *
  11259. * @param unescapedPart {string}
  11260. * @param extra {RegExp} a character set of characters in [\01-\177].
  11261. * @return {string|null} null iff unescapedPart == null.
  11262. */
  11263. function encodeIfExists2(unescapedPart, extra) {
  11264. if ('string' == typeof unescapedPart) {
  11265. return encodeURI(unescapedPart).replace(extra, encodeOne);
  11266. }
  11267. return null;
  11268. };
  11269. /** converts a character in [\01-\177] to its url encoded equivalent. */
  11270. function encodeOne(ch) {
  11271. var n = ch.charCodeAt(0);
  11272. return '%' + '0123456789ABCDEF'.charAt((n >> 4) & 0xf) +
  11273. '0123456789ABCDEF'.charAt(n & 0xf);
  11274. }
  11275. /**
  11276. * {@updoc
  11277. * $ normPath('foo/./bar')
  11278. * # 'foo/bar'
  11279. * $ normPath('./foo')
  11280. * # 'foo'
  11281. * $ normPath('foo/.')
  11282. * # 'foo'
  11283. * $ normPath('foo//bar')
  11284. * # 'foo/bar'
  11285. * }
  11286. */
  11287. function normPath(path) {
  11288. return path.replace(/(^|\/)\.(?:\/|$)/g, '$1').replace(/\/{2,}/g, '/');
  11289. }
  11290. var PARENT_DIRECTORY_HANDLER = new RegExp(
  11291. ''
  11292. // A path break
  11293. + '(/|^)'
  11294. // followed by a non .. path element
  11295. // (cannot be . because normPath is used prior to this RegExp)
  11296. + '(?:[^./][^/]*|\\.{2,}(?:[^./][^/]*)|\\.{3,}[^/]*)'
  11297. // followed by .. followed by a path break.
  11298. + '/\\.\\.(?:/|$)');
  11299. var PARENT_DIRECTORY_HANDLER_RE = new RegExp(PARENT_DIRECTORY_HANDLER);
  11300. var EXTRA_PARENT_PATHS_RE = /^(?:\.\.\/)*(?:\.\.$)?/;
  11301. /**
  11302. * Normalizes its input path and collapses all . and .. sequences except for
  11303. * .. sequences that would take it above the root of the current parent
  11304. * directory.
  11305. * {@updoc
  11306. * $ collapse_dots('foo/../bar')
  11307. * # 'bar'
  11308. * $ collapse_dots('foo/./bar')
  11309. * # 'foo/bar'
  11310. * $ collapse_dots('foo/../bar/./../../baz')
  11311. * # 'baz'
  11312. * $ collapse_dots('../foo')
  11313. * # '../foo'
  11314. * $ collapse_dots('../foo').replace(EXTRA_PARENT_PATHS_RE, '')
  11315. * # 'foo'
  11316. * }
  11317. */
  11318. function collapse_dots(path) {
  11319. if (path === null) { return null; }
  11320. var p = normPath(path);
  11321. // Only /../ left to flatten
  11322. var r = PARENT_DIRECTORY_HANDLER_RE;
  11323. // We replace with $1 which matches a / before the .. because this
  11324. // guarantees that:
  11325. // (1) we have at most 1 / between the adjacent place,
  11326. // (2) always have a slash if there is a preceding path section, and
  11327. // (3) we never turn a relative path into an absolute path.
  11328. for (var q; (q = p.replace(r, '$1')) != p; p = q) {};
  11329. return p;
  11330. }
  11331. /**
  11332. * resolves a relative url string to a base uri.
  11333. * @return {URI}
  11334. */
  11335. function resolve(baseUri, relativeUri) {
  11336. // there are several kinds of relative urls:
  11337. // 1. //foo - replaces everything from the domain on. foo is a domain name
  11338. // 2. foo - replaces the last part of the path, the whole query and fragment
  11339. // 3. /foo - replaces the the path, the query and fragment
  11340. // 4. ?foo - replace the query and fragment
  11341. // 5. #foo - replace the fragment only
  11342. var absoluteUri = baseUri.clone();
  11343. // we satisfy these conditions by looking for the first part of relativeUri
  11344. // that is not blank and applying defaults to the rest
  11345. var overridden = relativeUri.hasScheme();
  11346. if (overridden) {
  11347. absoluteUri.setRawScheme(relativeUri.getRawScheme());
  11348. } else {
  11349. overridden = relativeUri.hasCredentials();
  11350. }
  11351. if (overridden) {
  11352. absoluteUri.setRawCredentials(relativeUri.getRawCredentials());
  11353. } else {
  11354. overridden = relativeUri.hasDomain();
  11355. }
  11356. if (overridden) {
  11357. absoluteUri.setRawDomain(relativeUri.getRawDomain());
  11358. } else {
  11359. overridden = relativeUri.hasPort();
  11360. }
  11361. var rawPath = relativeUri.getRawPath();
  11362. var simplifiedPath = collapse_dots(rawPath);
  11363. if (overridden) {
  11364. absoluteUri.setPort(relativeUri.getPort());
  11365. simplifiedPath = simplifiedPath
  11366. && simplifiedPath.replace(EXTRA_PARENT_PATHS_RE, '');
  11367. } else {
  11368. overridden = !!rawPath;
  11369. if (overridden) {
  11370. // resolve path properly
  11371. if (simplifiedPath.charCodeAt(0) !== 0x2f /* / */) { // path is relative
  11372. var absRawPath = collapse_dots(absoluteUri.getRawPath() || '')
  11373. .replace(EXTRA_PARENT_PATHS_RE, '');
  11374. var slash = absRawPath.lastIndexOf('/') + 1;
  11375. simplifiedPath = collapse_dots(
  11376. (slash ? absRawPath.substring(0, slash) : '')
  11377. + collapse_dots(rawPath))
  11378. .replace(EXTRA_PARENT_PATHS_RE, '');
  11379. }
  11380. } else {
  11381. simplifiedPath = simplifiedPath
  11382. && simplifiedPath.replace(EXTRA_PARENT_PATHS_RE, '');
  11383. if (simplifiedPath !== rawPath) {
  11384. absoluteUri.setRawPath(simplifiedPath);
  11385. }
  11386. }
  11387. }
  11388. if (overridden) {
  11389. absoluteUri.setRawPath(simplifiedPath);
  11390. } else {
  11391. overridden = relativeUri.hasQuery();
  11392. }
  11393. if (overridden) {
  11394. absoluteUri.setRawQuery(relativeUri.getRawQuery());
  11395. } else {
  11396. overridden = relativeUri.hasFragment();
  11397. }
  11398. if (overridden) {
  11399. absoluteUri.setRawFragment(relativeUri.getRawFragment());
  11400. }
  11401. return absoluteUri;
  11402. }
  11403. /**
  11404. * a mutable URI.
  11405. *
  11406. * This class contains setters and getters for the parts of the URI.
  11407. * The <tt>getXYZ</tt>/<tt>setXYZ</tt> methods return the decoded part -- so
  11408. * <code>uri.parse('/foo%20bar').getPath()</code> will return the decoded path,
  11409. * <tt>/foo bar</tt>.
  11410. *
  11411. * <p>The raw versions of fields are available too.
  11412. * <code>uri.parse('/foo%20bar').getRawPath()</code> will return the raw path,
  11413. * <tt>/foo%20bar</tt>. Use the raw setters with care, since
  11414. * <code>URI::toString</code> is not guaranteed to return a valid url if a
  11415. * raw setter was used.
  11416. *
  11417. * <p>All setters return <tt>this</tt> and so may be chained, a la
  11418. * <code>uri.parse('/foo').setFragment('part').toString()</code>.
  11419. *
  11420. * <p>You should not use this constructor directly -- please prefer the factory
  11421. * functions {@link uri.parse}, {@link uri.create}, {@link uri.resolve}
  11422. * instead.</p>
  11423. *
  11424. * <p>The parameters are all raw (assumed to be properly escaped) parts, and
  11425. * any (but not all) may be null. Undefined is not allowed.</p>
  11426. *
  11427. * @constructor
  11428. */
  11429. function URI(
  11430. rawScheme,
  11431. rawCredentials, rawDomain, port,
  11432. rawPath, rawQuery, rawFragment) {
  11433. this.scheme_ = rawScheme;
  11434. this.credentials_ = rawCredentials;
  11435. this.domain_ = rawDomain;
  11436. this.port_ = port;
  11437. this.path_ = rawPath;
  11438. this.query_ = rawQuery;
  11439. this.fragment_ = rawFragment;
  11440. /**
  11441. * @type {Array|null}
  11442. */
  11443. this.paramCache_ = null;
  11444. }
  11445. /** returns the string form of the url. */
  11446. URI.prototype.toString = function () {
  11447. var out = [];
  11448. if (null !== this.scheme_) { out.push(this.scheme_, ':'); }
  11449. if (null !== this.domain_) {
  11450. out.push('//');
  11451. if (null !== this.credentials_) { out.push(this.credentials_, '@'); }
  11452. out.push(this.domain_);
  11453. if (null !== this.port_) { out.push(':', this.port_.toString()); }
  11454. }
  11455. if (null !== this.path_) { out.push(this.path_); }
  11456. if (null !== this.query_) { out.push('?', this.query_); }
  11457. if (null !== this.fragment_) { out.push('#', this.fragment_); }
  11458. return out.join('');
  11459. };
  11460. URI.prototype.clone = function () {
  11461. return new URI(this.scheme_, this.credentials_, this.domain_, this.port_,
  11462. this.path_, this.query_, this.fragment_);
  11463. };
  11464. URI.prototype.getScheme = function () {
  11465. // HTML5 spec does not require the scheme to be lowercased but
  11466. // all common browsers except Safari lowercase the scheme.
  11467. return this.scheme_ && decodeURIComponent(this.scheme_).toLowerCase();
  11468. };
  11469. URI.prototype.getRawScheme = function () {
  11470. return this.scheme_;
  11471. };
  11472. URI.prototype.setScheme = function (newScheme) {
  11473. this.scheme_ = encodeIfExists2(
  11474. newScheme, URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_);
  11475. return this;
  11476. };
  11477. URI.prototype.setRawScheme = function (newScheme) {
  11478. this.scheme_ = newScheme ? newScheme : null;
  11479. return this;
  11480. };
  11481. URI.prototype.hasScheme = function () {
  11482. return null !== this.scheme_;
  11483. };
  11484. URI.prototype.getCredentials = function () {
  11485. return this.credentials_ && decodeURIComponent(this.credentials_);
  11486. };
  11487. URI.prototype.getRawCredentials = function () {
  11488. return this.credentials_;
  11489. };
  11490. URI.prototype.setCredentials = function (newCredentials) {
  11491. this.credentials_ = encodeIfExists2(
  11492. newCredentials, URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_);
  11493. return this;
  11494. };
  11495. URI.prototype.setRawCredentials = function (newCredentials) {
  11496. this.credentials_ = newCredentials ? newCredentials : null;
  11497. return this;
  11498. };
  11499. URI.prototype.hasCredentials = function () {
  11500. return null !== this.credentials_;
  11501. };
  11502. URI.prototype.getDomain = function () {
  11503. return this.domain_ && decodeURIComponent(this.domain_);
  11504. };
  11505. URI.prototype.getRawDomain = function () {
  11506. return this.domain_;
  11507. };
  11508. URI.prototype.setDomain = function (newDomain) {
  11509. return this.setRawDomain(newDomain && encodeURIComponent(newDomain));
  11510. };
  11511. URI.prototype.setRawDomain = function (newDomain) {
  11512. this.domain_ = newDomain ? newDomain : null;
  11513. // Maintain the invariant that paths must start with a slash when the URI
  11514. // is not path-relative.
  11515. return this.setRawPath(this.path_);
  11516. };
  11517. URI.prototype.hasDomain = function () {
  11518. return null !== this.domain_;
  11519. };
  11520. URI.prototype.getPort = function () {
  11521. return this.port_ && decodeURIComponent(this.port_);
  11522. };
  11523. URI.prototype.setPort = function (newPort) {
  11524. if (newPort) {
  11525. newPort = Number(newPort);
  11526. if (newPort !== (newPort & 0xffff)) {
  11527. throw new Error('Bad port number ' + newPort);
  11528. }
  11529. this.port_ = '' + newPort;
  11530. } else {
  11531. this.port_ = null;
  11532. }
  11533. return this;
  11534. };
  11535. URI.prototype.hasPort = function () {
  11536. return null !== this.port_;
  11537. };
  11538. URI.prototype.getPath = function () {
  11539. return this.path_ && decodeURIComponent(this.path_);
  11540. };
  11541. URI.prototype.getRawPath = function () {
  11542. return this.path_;
  11543. };
  11544. URI.prototype.setPath = function (newPath) {
  11545. return this.setRawPath(encodeIfExists2(newPath, URI_DISALLOWED_IN_PATH_));
  11546. };
  11547. URI.prototype.setRawPath = function (newPath) {
  11548. if (newPath) {
  11549. newPath = String(newPath);
  11550. this.path_ =
  11551. // Paths must start with '/' unless this is a path-relative URL.
  11552. (!this.domain_ || /^\//.test(newPath)) ? newPath : '/' + newPath;
  11553. } else {
  11554. this.path_ = null;
  11555. }
  11556. return this;
  11557. };
  11558. URI.prototype.hasPath = function () {
  11559. return null !== this.path_;
  11560. };
  11561. URI.prototype.getQuery = function () {
  11562. // From http://www.w3.org/Addressing/URL/4_URI_Recommentations.html
  11563. // Within the query string, the plus sign is reserved as shorthand notation
  11564. // for a space.
  11565. return this.query_ && decodeURIComponent(this.query_).replace(/\+/g, ' ');
  11566. };
  11567. URI.prototype.getRawQuery = function () {
  11568. return this.query_;
  11569. };
  11570. URI.prototype.setQuery = function (newQuery) {
  11571. this.paramCache_ = null;
  11572. this.query_ = encodeIfExists(newQuery);
  11573. return this;
  11574. };
  11575. URI.prototype.setRawQuery = function (newQuery) {
  11576. this.paramCache_ = null;
  11577. this.query_ = newQuery ? newQuery : null;
  11578. return this;
  11579. };
  11580. URI.prototype.hasQuery = function () {
  11581. return null !== this.query_;
  11582. };
  11583. /**
  11584. * sets the query given a list of strings of the form
  11585. * [ key0, value0, key1, value1, ... ].
  11586. *
  11587. * <p><code>uri.setAllParameters(['a', 'b', 'c', 'd']).getQuery()</code>
  11588. * will yield <code>'a=b&c=d'</code>.
  11589. */
  11590. URI.prototype.setAllParameters = function (params) {
  11591. if (typeof params === 'object') {
  11592. if (!(params instanceof Array)
  11593. && (params instanceof Object
  11594. || Object.prototype.toString.call(params) !== '[object Array]')) {
  11595. var newParams = [];
  11596. var i = -1;
  11597. for (var k in params) {
  11598. var v = params[k];
  11599. if ('string' === typeof v) {
  11600. newParams[++i] = k;
  11601. newParams[++i] = v;
  11602. }
  11603. }
  11604. params = newParams;
  11605. }
  11606. }
  11607. this.paramCache_ = null;
  11608. var queryBuf = [];
  11609. var separator = '';
  11610. for (var j = 0; j < params.length;) {
  11611. var k = params[j++];
  11612. var v = params[j++];
  11613. queryBuf.push(separator, encodeURIComponent(k.toString()));
  11614. separator = '&';
  11615. if (v) {
  11616. queryBuf.push('=', encodeURIComponent(v.toString()));
  11617. }
  11618. }
  11619. this.query_ = queryBuf.join('');
  11620. return this;
  11621. };
  11622. URI.prototype.checkParameterCache_ = function () {
  11623. if (!this.paramCache_) {
  11624. var q = this.query_;
  11625. if (!q) {
  11626. this.paramCache_ = [];
  11627. } else {
  11628. var cgiParams = q.split(/[&\?]/);
  11629. var out = [];
  11630. var k = -1;
  11631. for (var i = 0; i < cgiParams.length; ++i) {
  11632. var m = cgiParams[i].match(/^([^=]*)(?:=(.*))?$/);
  11633. // From http://www.w3.org/Addressing/URL/4_URI_Recommentations.html
  11634. // Within the query string, the plus sign is reserved as shorthand
  11635. // notation for a space.
  11636. out[++k] = decodeURIComponent(m[1]).replace(/\+/g, ' ');
  11637. out[++k] = decodeURIComponent(m[2] || '').replace(/\+/g, ' ');
  11638. }
  11639. this.paramCache_ = out;
  11640. }
  11641. }
  11642. };
  11643. /**
  11644. * sets the values of the named cgi parameters.
  11645. *
  11646. * <p>So, <code>uri.parse('foo?a=b&c=d&e=f').setParameterValues('c', ['new'])
  11647. * </code> yields <tt>foo?a=b&c=new&e=f</tt>.</p>
  11648. *
  11649. * @param key {string}
  11650. * @param values {Array.<string>} the new values. If values is a single string
  11651. * then it will be treated as the sole value.
  11652. */
  11653. URI.prototype.setParameterValues = function (key, values) {
  11654. // be nice and avoid subtle bugs where [] operator on string performs charAt
  11655. // on some browsers and crashes on IE
  11656. if (typeof values === 'string') {
  11657. values = [ values ];
  11658. }
  11659. this.checkParameterCache_();
  11660. var newValueIndex = 0;
  11661. var pc = this.paramCache_;
  11662. var params = [];
  11663. for (var i = 0, k = 0; i < pc.length; i += 2) {
  11664. if (key === pc[i]) {
  11665. if (newValueIndex < values.length) {
  11666. params.push(key, values[newValueIndex++]);
  11667. }
  11668. } else {
  11669. params.push(pc[i], pc[i + 1]);
  11670. }
  11671. }
  11672. while (newValueIndex < values.length) {
  11673. params.push(key, values[newValueIndex++]);
  11674. }
  11675. this.setAllParameters(params);
  11676. return this;
  11677. };
  11678. URI.prototype.removeParameter = function (key) {
  11679. return this.setParameterValues(key, []);
  11680. };
  11681. /**
  11682. * returns the parameters specified in the query part of the uri as a list of
  11683. * keys and values like [ key0, value0, key1, value1, ... ].
  11684. *
  11685. * @return {Array.<string>}
  11686. */
  11687. URI.prototype.getAllParameters = function () {
  11688. this.checkParameterCache_();
  11689. return this.paramCache_.slice(0, this.paramCache_.length);
  11690. };
  11691. /**
  11692. * returns the value<b>s</b> for a given cgi parameter as a list of decoded
  11693. * query parameter values.
  11694. * @return {Array.<string>}
  11695. */
  11696. URI.prototype.getParameterValues = function (paramNameUnescaped) {
  11697. this.checkParameterCache_();
  11698. var values = [];
  11699. for (var i = 0; i < this.paramCache_.length; i += 2) {
  11700. if (paramNameUnescaped === this.paramCache_[i]) {
  11701. values.push(this.paramCache_[i + 1]);
  11702. }
  11703. }
  11704. return values;
  11705. };
  11706. /**
  11707. * returns a map of cgi parameter names to (non-empty) lists of values.
  11708. * @return {Object.<string,Array.<string>>}
  11709. */
  11710. URI.prototype.getParameterMap = function (paramNameUnescaped) {
  11711. this.checkParameterCache_();
  11712. var paramMap = {};
  11713. for (var i = 0; i < this.paramCache_.length; i += 2) {
  11714. var key = this.paramCache_[i++],
  11715. value = this.paramCache_[i++];
  11716. if (!(key in paramMap)) {
  11717. paramMap[key] = [value];
  11718. } else {
  11719. paramMap[key].push(value);
  11720. }
  11721. }
  11722. return paramMap;
  11723. };
  11724. /**
  11725. * returns the first value for a given cgi parameter or null if the given
  11726. * parameter name does not appear in the query string.
  11727. * If the given parameter name does appear, but has no '<tt>=</tt>' following
  11728. * it, then the empty string will be returned.
  11729. * @return {string|null}
  11730. */
  11731. URI.prototype.getParameterValue = function (paramNameUnescaped) {
  11732. this.checkParameterCache_();
  11733. for (var i = 0; i < this.paramCache_.length; i += 2) {
  11734. if (paramNameUnescaped === this.paramCache_[i]) {
  11735. return this.paramCache_[i + 1];
  11736. }
  11737. }
  11738. return null;
  11739. };
  11740. URI.prototype.getFragment = function () {
  11741. return this.fragment_ && decodeURIComponent(this.fragment_);
  11742. };
  11743. URI.prototype.getRawFragment = function () {
  11744. return this.fragment_;
  11745. };
  11746. URI.prototype.setFragment = function (newFragment) {
  11747. this.fragment_ = newFragment ? encodeURIComponent(newFragment) : null;
  11748. return this;
  11749. };
  11750. URI.prototype.setRawFragment = function (newFragment) {
  11751. this.fragment_ = newFragment ? newFragment : null;
  11752. return this;
  11753. };
  11754. URI.prototype.hasFragment = function () {
  11755. return null !== this.fragment_;
  11756. };
  11757. function nullIfAbsent(matchPart) {
  11758. return ('string' == typeof matchPart) && (matchPart.length > 0)
  11759. ? matchPart
  11760. : null;
  11761. }
  11762. /**
  11763. * a regular expression for breaking a URI into its component parts.
  11764. *
  11765. * <p>http://www.gbiv.com/protocols/uri/rfc/rfc3986.html#RFC2234 says
  11766. * As the "first-match-wins" algorithm is identical to the "greedy"
  11767. * disambiguation method used by POSIX regular expressions, it is natural and
  11768. * commonplace to use a regular expression for parsing the potential five
  11769. * components of a URI reference.
  11770. *
  11771. * <p>The following line is the regular expression for breaking-down a
  11772. * well-formed URI reference into its components.
  11773. *
  11774. * <pre>
  11775. * ^(([^:/?#]+):)?(//([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?
  11776. * 12 3 4 5 6 7 8 9
  11777. * </pre>
  11778. *
  11779. * <p>The numbers in the second line above are only to assist readability; they
  11780. * indicate the reference points for each subexpression (i.e., each paired
  11781. * parenthesis). We refer to the value matched for subexpression <n> as $<n>.
  11782. * For example, matching the above expression to
  11783. * <pre>
  11784. * http://www.ics.uci.edu/pub/ietf/uri/#Related
  11785. * </pre>
  11786. * results in the following subexpression matches:
  11787. * <pre>
  11788. * $1 = http:
  11789. * $2 = http
  11790. * $3 = //www.ics.uci.edu
  11791. * $4 = www.ics.uci.edu
  11792. * $5 = /pub/ietf/uri/
  11793. * $6 = <undefined>
  11794. * $7 = <undefined>
  11795. * $8 = #Related
  11796. * $9 = Related
  11797. * </pre>
  11798. * where <undefined> indicates that the component is not present, as is the
  11799. * case for the query component in the above example. Therefore, we can
  11800. * determine the value of the five components as
  11801. * <pre>
  11802. * scheme = $2
  11803. * authority = $4
  11804. * path = $5
  11805. * query = $7
  11806. * fragment = $9
  11807. * </pre>
  11808. *
  11809. * <p>msamuel: I have modified the regular expression slightly to expose the
  11810. * credentials, domain, and port separately from the authority.
  11811. * The modified version yields
  11812. * <pre>
  11813. * $1 = http scheme
  11814. * $2 = <undefined> credentials -\
  11815. * $3 = www.ics.uci.edu domain | authority
  11816. * $4 = <undefined> port -/
  11817. * $5 = /pub/ietf/uri/ path
  11818. * $6 = <undefined> query without ?
  11819. * $7 = Related fragment without #
  11820. * </pre>
  11821. */
  11822. var URI_RE_ = new RegExp(
  11823. "^" +
  11824. "(?:" +
  11825. "([^:/?#]+)" + // scheme
  11826. ":)?" +
  11827. "(?://" +
  11828. "(?:([^/?#]*)@)?" + // credentials
  11829. "([^/?#:@]*)" + // domain
  11830. "(?::([0-9]+))?" + // port
  11831. ")?" +
  11832. "([^?#]+)?" + // path
  11833. "(?:\\?([^#]*))?" + // query
  11834. "(?:#(.*))?" + // fragment
  11835. "$"
  11836. );
  11837. var URI_DISALLOWED_IN_SCHEME_OR_CREDENTIALS_ = /[#\/\?@]/g;
  11838. var URI_DISALLOWED_IN_PATH_ = /[\#\?]/g;
  11839. URI.parse = parse;
  11840. URI.create = create;
  11841. URI.resolve = resolve;
  11842. URI.collapse_dots = collapse_dots; // Visible for testing.
  11843. // lightweight string-based api for loadModuleMaker
  11844. URI.utils = {
  11845. mimeTypeOf: function (uri) {
  11846. var uriObj = parse(uri);
  11847. if (/\.html$/.test(uriObj.getPath())) {
  11848. return 'text/html';
  11849. } else {
  11850. return 'application/javascript';
  11851. }
  11852. },
  11853. resolve: function (base, uri) {
  11854. if (base) {
  11855. return resolve(parse(base), parse(uri)).toString();
  11856. } else {
  11857. return '' + uri;
  11858. }
  11859. }
  11860. };
  11861. return URI;
  11862. })();
  11863. // Copyright Google Inc.
  11864. // Licensed under the Apache Licence Version 2.0
  11865. // Autogenerated at Mon Feb 25 13:05:42 EST 2013
  11866. // @overrides window
  11867. // @provides html4
  11868. var html4 = {};
  11869. html4.atype = {
  11870. 'NONE': 0,
  11871. 'URI': 1,
  11872. 'URI_FRAGMENT': 11,
  11873. 'SCRIPT': 2,
  11874. 'STYLE': 3,
  11875. 'HTML': 12,
  11876. 'ID': 4,
  11877. 'IDREF': 5,
  11878. 'IDREFS': 6,
  11879. 'GLOBAL_NAME': 7,
  11880. 'LOCAL_NAME': 8,
  11881. 'CLASSES': 9,
  11882. 'FRAME_TARGET': 10,
  11883. 'MEDIA_QUERY': 13
  11884. };
  11885. html4[ 'atype' ] = html4.atype;
  11886. html4.ATTRIBS = {
  11887. '*::class': 9,
  11888. '*::dir': 0,
  11889. '*::draggable': 0,
  11890. '*::hidden': 0,
  11891. '*::id': 4,
  11892. '*::inert': 0,
  11893. '*::itemprop': 0,
  11894. '*::itemref': 6,
  11895. '*::itemscope': 0,
  11896. '*::lang': 0,
  11897. '*::onblur': 2,
  11898. '*::onchange': 2,
  11899. '*::onclick': 2,
  11900. '*::ondblclick': 2,
  11901. '*::onfocus': 2,
  11902. '*::onkeydown': 2,
  11903. '*::onkeypress': 2,
  11904. '*::onkeyup': 2,
  11905. '*::onload': 2,
  11906. '*::onmousedown': 2,
  11907. '*::onmousemove': 2,
  11908. '*::onmouseout': 2,
  11909. '*::onmouseover': 2,
  11910. '*::onmouseup': 2,
  11911. '*::onreset': 2,
  11912. '*::onscroll': 2,
  11913. '*::onselect': 2,
  11914. '*::onsubmit': 2,
  11915. '*::onunload': 2,
  11916. '*::spellcheck': 0,
  11917. '*::style': 3,
  11918. '*::title': 0,
  11919. '*::translate': 0,
  11920. 'a::accesskey': 0,
  11921. 'a::coords': 0,
  11922. 'a::href': 1,
  11923. 'a::hreflang': 0,
  11924. 'a::name': 7,
  11925. 'a::onblur': 2,
  11926. 'a::onfocus': 2,
  11927. 'a::shape': 0,
  11928. 'a::tabindex': 0,
  11929. 'a::target': 10,
  11930. 'a::type': 0,
  11931. 'area::accesskey': 0,
  11932. 'area::alt': 0,
  11933. 'area::coords': 0,
  11934. 'area::href': 1,
  11935. 'area::nohref': 0,
  11936. 'area::onblur': 2,
  11937. 'area::onfocus': 2,
  11938. 'area::shape': 0,
  11939. 'area::tabindex': 0,
  11940. 'area::target': 10,
  11941. 'audio::controls': 0,
  11942. 'audio::loop': 0,
  11943. 'audio::mediagroup': 5,
  11944. 'audio::muted': 0,
  11945. 'audio::preload': 0,
  11946. 'bdo::dir': 0,
  11947. 'blockquote::cite': 1,
  11948. 'br::clear': 0,
  11949. 'button::accesskey': 0,
  11950. 'button::disabled': 0,
  11951. 'button::name': 8,
  11952. 'button::onblur': 2,
  11953. 'button::onfocus': 2,
  11954. 'button::tabindex': 0,
  11955. 'button::type': 0,
  11956. 'button::value': 0,
  11957. 'canvas::height': 0,
  11958. 'canvas::width': 0,
  11959. 'caption::align': 0,
  11960. 'col::align': 0,
  11961. 'col::char': 0,
  11962. 'col::charoff': 0,
  11963. 'col::span': 0,
  11964. 'col::valign': 0,
  11965. 'col::width': 0,
  11966. 'colgroup::align': 0,
  11967. 'colgroup::char': 0,
  11968. 'colgroup::charoff': 0,
  11969. 'colgroup::span': 0,
  11970. 'colgroup::valign': 0,
  11971. 'colgroup::width': 0,
  11972. 'command::checked': 0,
  11973. 'command::command': 5,
  11974. 'command::disabled': 0,
  11975. 'command::icon': 1,
  11976. 'command::label': 0,
  11977. 'command::radiogroup': 0,
  11978. 'command::type': 0,
  11979. 'data::value': 0,
  11980. 'del::cite': 1,
  11981. 'del::datetime': 0,
  11982. 'details::open': 0,
  11983. 'dir::compact': 0,
  11984. 'div::align': 0,
  11985. 'dl::compact': 0,
  11986. 'fieldset::disabled': 0,
  11987. 'font::color': 0,
  11988. 'font::face': 0,
  11989. 'font::size': 0,
  11990. 'form::accept': 0,
  11991. 'form::action': 1,
  11992. 'form::autocomplete': 0,
  11993. 'form::enctype': 0,
  11994. 'form::method': 0,
  11995. 'form::name': 7,
  11996. 'form::novalidate': 0,
  11997. 'form::onreset': 2,
  11998. 'form::onsubmit': 2,
  11999. 'form::target': 10,
  12000. 'h1::align': 0,
  12001. 'h2::align': 0,
  12002. 'h3::align': 0,
  12003. 'h4::align': 0,
  12004. 'h5::align': 0,
  12005. 'h6::align': 0,
  12006. 'hr::align': 0,
  12007. 'hr::noshade': 0,
  12008. 'hr::size': 0,
  12009. 'hr::width': 0,
  12010. 'iframe::align': 0,
  12011. 'iframe::frameborder': 0,
  12012. 'iframe::height': 0,
  12013. 'iframe::marginheight': 0,
  12014. 'iframe::marginwidth': 0,
  12015. 'iframe::width': 0,
  12016. 'img::align': 0,
  12017. 'img::alt': 0,
  12018. 'img::border': 0,
  12019. 'img::height': 0,
  12020. 'img::hspace': 0,
  12021. 'img::ismap': 0,
  12022. 'img::name': 7,
  12023. 'img::src': 1,
  12024. 'img::usemap': 11,
  12025. 'img::vspace': 0,
  12026. 'img::width': 0,
  12027. 'input::accept': 0,
  12028. 'input::accesskey': 0,
  12029. 'input::align': 0,
  12030. 'input::alt': 0,
  12031. 'input::autocomplete': 0,
  12032. 'input::checked': 0,
  12033. 'input::disabled': 0,
  12034. 'input::inputmode': 0,
  12035. 'input::ismap': 0,
  12036. 'input::list': 5,
  12037. 'input::max': 0,
  12038. 'input::maxlength': 0,
  12039. 'input::min': 0,
  12040. 'input::multiple': 0,
  12041. 'input::name': 8,
  12042. 'input::onblur': 2,
  12043. 'input::onchange': 2,
  12044. 'input::onfocus': 2,
  12045. 'input::onselect': 2,
  12046. 'input::placeholder': 0,
  12047. 'input::readonly': 0,
  12048. 'input::required': 0,
  12049. 'input::size': 0,
  12050. 'input::src': 1,
  12051. 'input::step': 0,
  12052. 'input::tabindex': 0,
  12053. 'input::type': 0,
  12054. 'input::usemap': 11,
  12055. 'input::value': 0,
  12056. 'ins::cite': 1,
  12057. 'ins::datetime': 0,
  12058. 'label::accesskey': 0,
  12059. 'label::for': 5,
  12060. 'label::onblur': 2,
  12061. 'label::onfocus': 2,
  12062. 'legend::accesskey': 0,
  12063. 'legend::align': 0,
  12064. 'li::type': 0,
  12065. 'li::value': 0,
  12066. 'map::name': 7,
  12067. 'menu::compact': 0,
  12068. 'menu::label': 0,
  12069. 'menu::type': 0,
  12070. 'meter::high': 0,
  12071. 'meter::low': 0,
  12072. 'meter::max': 0,
  12073. 'meter::min': 0,
  12074. 'meter::value': 0,
  12075. 'ol::compact': 0,
  12076. 'ol::reversed': 0,
  12077. 'ol::start': 0,
  12078. 'ol::type': 0,
  12079. 'optgroup::disabled': 0,
  12080. 'optgroup::label': 0,
  12081. 'option::disabled': 0,
  12082. 'option::label': 0,
  12083. 'option::selected': 0,
  12084. 'option::value': 0,
  12085. 'output::for': 6,
  12086. 'output::name': 8,
  12087. 'p::align': 0,
  12088. 'pre::width': 0,
  12089. 'progress::max': 0,
  12090. 'progress::min': 0,
  12091. 'progress::value': 0,
  12092. 'q::cite': 1,
  12093. 'select::autocomplete': 0,
  12094. 'select::disabled': 0,
  12095. 'select::multiple': 0,
  12096. 'select::name': 8,
  12097. 'select::onblur': 2,
  12098. 'select::onchange': 2,
  12099. 'select::onfocus': 2,
  12100. 'select::required': 0,
  12101. 'select::size': 0,
  12102. 'select::tabindex': 0,
  12103. 'source::type': 0,
  12104. 'table::align': 0,
  12105. 'table::bgcolor': 0,
  12106. 'table::border': 0,
  12107. 'table::cellpadding': 0,
  12108. 'table::cellspacing': 0,
  12109. 'table::frame': 0,
  12110. 'table::rules': 0,
  12111. 'table::summary': 0,
  12112. 'table::width': 0,
  12113. 'tbody::align': 0,
  12114. 'tbody::char': 0,
  12115. 'tbody::charoff': 0,
  12116. 'tbody::valign': 0,
  12117. 'td::abbr': 0,
  12118. 'td::align': 0,
  12119. 'td::axis': 0,
  12120. 'td::bgcolor': 0,
  12121. 'td::char': 0,
  12122. 'td::charoff': 0,
  12123. 'td::colspan': 0,
  12124. 'td::headers': 6,
  12125. 'td::height': 0,
  12126. 'td::nowrap': 0,
  12127. 'td::rowspan': 0,
  12128. 'td::scope': 0,
  12129. 'td::valign': 0,
  12130. 'td::width': 0,
  12131. 'textarea::accesskey': 0,
  12132. 'textarea::autocomplete': 0,
  12133. 'textarea::cols': 0,
  12134. 'textarea::disabled': 0,
  12135. 'textarea::inputmode': 0,
  12136. 'textarea::name': 8,
  12137. 'textarea::onblur': 2,
  12138. 'textarea::onchange': 2,
  12139. 'textarea::onfocus': 2,
  12140. 'textarea::onselect': 2,
  12141. 'textarea::placeholder': 0,
  12142. 'textarea::readonly': 0,
  12143. 'textarea::required': 0,
  12144. 'textarea::rows': 0,
  12145. 'textarea::tabindex': 0,
  12146. 'textarea::wrap': 0,
  12147. 'tfoot::align': 0,
  12148. 'tfoot::char': 0,
  12149. 'tfoot::charoff': 0,
  12150. 'tfoot::valign': 0,
  12151. 'th::abbr': 0,
  12152. 'th::align': 0,
  12153. 'th::axis': 0,
  12154. 'th::bgcolor': 0,
  12155. 'th::char': 0,
  12156. 'th::charoff': 0,
  12157. 'th::colspan': 0,
  12158. 'th::headers': 6,
  12159. 'th::height': 0,
  12160. 'th::nowrap': 0,
  12161. 'th::rowspan': 0,
  12162. 'th::scope': 0,
  12163. 'th::valign': 0,
  12164. 'th::width': 0,
  12165. 'thead::align': 0,
  12166. 'thead::char': 0,
  12167. 'thead::charoff': 0,
  12168. 'thead::valign': 0,
  12169. 'tr::align': 0,
  12170. 'tr::bgcolor': 0,
  12171. 'tr::char': 0,
  12172. 'tr::charoff': 0,
  12173. 'tr::valign': 0,
  12174. 'track::default': 0,
  12175. 'track::kind': 0,
  12176. 'track::label': 0,
  12177. 'track::srclang': 0,
  12178. 'ul::compact': 0,
  12179. 'ul::type': 0,
  12180. 'video::controls': 0,
  12181. 'video::height': 0,
  12182. 'video::loop': 0,
  12183. 'video::mediagroup': 5,
  12184. 'video::muted': 0,
  12185. 'video::poster': 1,
  12186. 'video::preload': 0,
  12187. 'video::width': 0
  12188. };
  12189. html4[ 'ATTRIBS' ] = html4.ATTRIBS;
  12190. html4.eflags = {
  12191. 'OPTIONAL_ENDTAG': 1,
  12192. 'EMPTY': 2,
  12193. 'CDATA': 4,
  12194. 'RCDATA': 8,
  12195. 'UNSAFE': 16,
  12196. 'FOLDABLE': 32,
  12197. 'SCRIPT': 64,
  12198. 'STYLE': 128,
  12199. 'VIRTUALIZED': 256
  12200. };
  12201. html4[ 'eflags' ] = html4.eflags;
  12202. // these are bitmasks of the eflags above.
  12203. html4.ELEMENTS = {
  12204. 'a': 0,
  12205. 'abbr': 0,
  12206. 'acronym': 0,
  12207. 'address': 0,
  12208. 'applet': 272,
  12209. 'area': 2,
  12210. 'article': 0,
  12211. 'aside': 0,
  12212. 'audio': 0,
  12213. 'b': 0,
  12214. 'base': 274,
  12215. 'basefont': 274,
  12216. 'bdi': 0,
  12217. 'bdo': 0,
  12218. 'big': 0,
  12219. 'blockquote': 0,
  12220. 'body': 305,
  12221. 'br': 2,
  12222. 'button': 0,
  12223. 'canvas': 0,
  12224. 'caption': 0,
  12225. 'center': 0,
  12226. 'cite': 0,
  12227. 'code': 0,
  12228. 'col': 2,
  12229. 'colgroup': 1,
  12230. 'command': 2,
  12231. 'data': 0,
  12232. 'datalist': 0,
  12233. 'dd': 1,
  12234. 'del': 0,
  12235. 'details': 0,
  12236. 'dfn': 0,
  12237. 'dialog': 272,
  12238. 'dir': 0,
  12239. 'div': 0,
  12240. 'dl': 0,
  12241. 'dt': 1,
  12242. 'em': 0,
  12243. 'fieldset': 0,
  12244. 'figcaption': 0,
  12245. 'figure': 0,
  12246. 'font': 0,
  12247. 'footer': 0,
  12248. 'form': 0,
  12249. 'frame': 274,
  12250. 'frameset': 272,
  12251. 'h1': 0,
  12252. 'h2': 0,
  12253. 'h3': 0,
  12254. 'h4': 0,
  12255. 'h5': 0,
  12256. 'h6': 0,
  12257. 'head': 305,
  12258. 'header': 0,
  12259. 'hgroup': 0,
  12260. 'hr': 2,
  12261. 'html': 305,
  12262. 'i': 0,
  12263. 'iframe': 16,
  12264. 'img': 2,
  12265. 'input': 2,
  12266. 'ins': 0,
  12267. 'isindex': 274,
  12268. 'kbd': 0,
  12269. 'keygen': 274,
  12270. 'label': 0,
  12271. 'legend': 0,
  12272. 'li': 1,
  12273. 'link': 274,
  12274. 'map': 0,
  12275. 'mark': 0,
  12276. 'menu': 0,
  12277. 'meta': 274,
  12278. 'meter': 0,
  12279. 'nav': 0,
  12280. 'nobr': 0,
  12281. 'noembed': 276,
  12282. 'noframes': 276,
  12283. 'noscript': 276,
  12284. 'object': 272,
  12285. 'ol': 0,
  12286. 'optgroup': 0,
  12287. 'option': 1,
  12288. 'output': 0,
  12289. 'p': 1,
  12290. 'param': 274,
  12291. 'pre': 0,
  12292. 'progress': 0,
  12293. 'q': 0,
  12294. 's': 0,
  12295. 'samp': 0,
  12296. 'script': 84,
  12297. 'section': 0,
  12298. 'select': 0,
  12299. 'small': 0,
  12300. 'source': 2,
  12301. 'span': 0,
  12302. 'strike': 0,
  12303. 'strong': 0,
  12304. 'style': 148,
  12305. 'sub': 0,
  12306. 'summary': 0,
  12307. 'sup': 0,
  12308. 'table': 0,
  12309. 'tbody': 1,
  12310. 'td': 1,
  12311. 'textarea': 8,
  12312. 'tfoot': 1,
  12313. 'th': 1,
  12314. 'thead': 1,
  12315. 'time': 0,
  12316. 'title': 280,
  12317. 'tr': 1,
  12318. 'track': 2,
  12319. 'tt': 0,
  12320. 'u': 0,
  12321. 'ul': 0,
  12322. 'var': 0,
  12323. 'video': 0,
  12324. 'wbr': 2
  12325. };
  12326. html4[ 'ELEMENTS' ] = html4.ELEMENTS;
  12327. html4.ELEMENT_DOM_INTERFACES = {
  12328. 'a': 'HTMLAnchorElement',
  12329. 'abbr': 'HTMLElement',
  12330. 'acronym': 'HTMLElement',
  12331. 'address': 'HTMLElement',
  12332. 'applet': 'HTMLAppletElement',
  12333. 'area': 'HTMLAreaElement',
  12334. 'article': 'HTMLElement',
  12335. 'aside': 'HTMLElement',
  12336. 'audio': 'HTMLAudioElement',
  12337. 'b': 'HTMLElement',
  12338. 'base': 'HTMLBaseElement',
  12339. 'basefont': 'HTMLBaseFontElement',
  12340. 'bdi': 'HTMLElement',
  12341. 'bdo': 'HTMLElement',
  12342. 'big': 'HTMLElement',
  12343. 'blockquote': 'HTMLQuoteElement',
  12344. 'body': 'HTMLBodyElement',
  12345. 'br': 'HTMLBRElement',
  12346. 'button': 'HTMLButtonElement',
  12347. 'canvas': 'HTMLCanvasElement',
  12348. 'caption': 'HTMLTableCaptionElement',
  12349. 'center': 'HTMLElement',
  12350. 'cite': 'HTMLElement',
  12351. 'code': 'HTMLElement',
  12352. 'col': 'HTMLTableColElement',
  12353. 'colgroup': 'HTMLTableColElement',
  12354. 'command': 'HTMLCommandElement',
  12355. 'data': 'HTMLElement',
  12356. 'datalist': 'HTMLDataListElement',
  12357. 'dd': 'HTMLElement',
  12358. 'del': 'HTMLModElement',
  12359. 'details': 'HTMLDetailsElement',
  12360. 'dfn': 'HTMLElement',
  12361. 'dialog': 'HTMLDialogElement',
  12362. 'dir': 'HTMLDirectoryElement',
  12363. 'div': 'HTMLDivElement',
  12364. 'dl': 'HTMLDListElement',
  12365. 'dt': 'HTMLElement',
  12366. 'em': 'HTMLElement',
  12367. 'fieldset': 'HTMLFieldSetElement',
  12368. 'figcaption': 'HTMLElement',
  12369. 'figure': 'HTMLElement',
  12370. 'font': 'HTMLFontElement',
  12371. 'footer': 'HTMLElement',
  12372. 'form': 'HTMLFormElement',
  12373. 'frame': 'HTMLFrameElement',
  12374. 'frameset': 'HTMLFrameSetElement',
  12375. 'h1': 'HTMLHeadingElement',
  12376. 'h2': 'HTMLHeadingElement',
  12377. 'h3': 'HTMLHeadingElement',
  12378. 'h4': 'HTMLHeadingElement',
  12379. 'h5': 'HTMLHeadingElement',
  12380. 'h6': 'HTMLHeadingElement',
  12381. 'head': 'HTMLHeadElement',
  12382. 'header': 'HTMLElement',
  12383. 'hgroup': 'HTMLElement',
  12384. 'hr': 'HTMLHRElement',
  12385. 'html': 'HTMLHtmlElement',
  12386. 'i': 'HTMLElement',
  12387. 'iframe': 'HTMLIFrameElement',
  12388. 'img': 'HTMLImageElement',
  12389. 'input': 'HTMLInputElement',
  12390. 'ins': 'HTMLModElement',
  12391. 'isindex': 'HTMLUnknownElement',
  12392. 'kbd': 'HTMLElement',
  12393. 'keygen': 'HTMLKeygenElement',
  12394. 'label': 'HTMLLabelElement',
  12395. 'legend': 'HTMLLegendElement',
  12396. 'li': 'HTMLLIElement',
  12397. 'link': 'HTMLLinkElement',
  12398. 'map': 'HTMLMapElement',
  12399. 'mark': 'HTMLElement',
  12400. 'menu': 'HTMLMenuElement',
  12401. 'meta': 'HTMLMetaElement',
  12402. 'meter': 'HTMLMeterElement',
  12403. 'nav': 'HTMLElement',
  12404. 'nobr': 'HTMLElement',
  12405. 'noembed': 'HTMLElement',
  12406. 'noframes': 'HTMLElement',
  12407. 'noscript': 'HTMLElement',
  12408. 'object': 'HTMLObjectElement',
  12409. 'ol': 'HTMLOListElement',
  12410. 'optgroup': 'HTMLOptGroupElement',
  12411. 'option': 'HTMLOptionElement',
  12412. 'output': 'HTMLOutputElement',
  12413. 'p': 'HTMLParagraphElement',
  12414. 'param': 'HTMLParamElement',
  12415. 'pre': 'HTMLPreElement',
  12416. 'progress': 'HTMLProgressElement',
  12417. 'q': 'HTMLQuoteElement',
  12418. 's': 'HTMLElement',
  12419. 'samp': 'HTMLElement',
  12420. 'script': 'HTMLScriptElement',
  12421. 'section': 'HTMLElement',
  12422. 'select': 'HTMLSelectElement',
  12423. 'small': 'HTMLElement',
  12424. 'source': 'HTMLSourceElement',
  12425. 'span': 'HTMLSpanElement',
  12426. 'strike': 'HTMLElement',
  12427. 'strong': 'HTMLElement',
  12428. 'style': 'HTMLStyleElement',
  12429. 'sub': 'HTMLElement',
  12430. 'summary': 'HTMLElement',
  12431. 'sup': 'HTMLElement',
  12432. 'table': 'HTMLTableElement',
  12433. 'tbody': 'HTMLTableSectionElement',
  12434. 'td': 'HTMLTableDataCellElement',
  12435. 'textarea': 'HTMLTextAreaElement',
  12436. 'tfoot': 'HTMLTableSectionElement',
  12437. 'th': 'HTMLTableHeaderCellElement',
  12438. 'thead': 'HTMLTableSectionElement',
  12439. 'time': 'HTMLTimeElement',
  12440. 'title': 'HTMLTitleElement',
  12441. 'tr': 'HTMLTableRowElement',
  12442. 'track': 'HTMLTrackElement',
  12443. 'tt': 'HTMLElement',
  12444. 'u': 'HTMLElement',
  12445. 'ul': 'HTMLUListElement',
  12446. 'var': 'HTMLElement',
  12447. 'video': 'HTMLVideoElement',
  12448. 'wbr': 'HTMLElement'
  12449. };
  12450. html4[ 'ELEMENT_DOM_INTERFACES' ] = html4.ELEMENT_DOM_INTERFACES;
  12451. html4.ueffects = {
  12452. 'NOT_LOADED': 0,
  12453. 'SAME_DOCUMENT': 1,
  12454. 'NEW_DOCUMENT': 2
  12455. };
  12456. html4[ 'ueffects' ] = html4.ueffects;
  12457. html4.URIEFFECTS = {
  12458. 'a::href': 2,
  12459. 'area::href': 2,
  12460. 'blockquote::cite': 0,
  12461. 'command::icon': 1,
  12462. 'del::cite': 0,
  12463. 'form::action': 2,
  12464. 'img::src': 1,
  12465. 'input::src': 1,
  12466. 'ins::cite': 0,
  12467. 'q::cite': 0,
  12468. 'video::poster': 1
  12469. };
  12470. html4[ 'URIEFFECTS' ] = html4.URIEFFECTS;
  12471. html4.ltypes = {
  12472. 'UNSANDBOXED': 2,
  12473. 'SANDBOXED': 1,
  12474. 'DATA': 0
  12475. };
  12476. html4[ 'ltypes' ] = html4.ltypes;
  12477. html4.LOADERTYPES = {
  12478. 'a::href': 2,
  12479. 'area::href': 2,
  12480. 'blockquote::cite': 2,
  12481. 'command::icon': 1,
  12482. 'del::cite': 2,
  12483. 'form::action': 2,
  12484. 'img::src': 1,
  12485. 'input::src': 1,
  12486. 'ins::cite': 2,
  12487. 'q::cite': 2,
  12488. 'video::poster': 1
  12489. };
  12490. html4[ 'LOADERTYPES' ] = html4.LOADERTYPES;
  12491. // Copyright (C) 2006 Google Inc.
  12492. //
  12493. // Licensed under the Apache License, Version 2.0 (the "License");
  12494. // you may not use this file except in compliance with the License.
  12495. // You may obtain a copy of the License at
  12496. //
  12497. // http://www.apache.org/licenses/LICENSE-2.0
  12498. //
  12499. // Unless required by applicable law or agreed to in writing, software
  12500. // distributed under the License is distributed on an "AS IS" BASIS,
  12501. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12502. // See the License for the specific language governing permissions and
  12503. // limitations under the License.
  12504. /**
  12505. * @fileoverview
  12506. * An HTML sanitizer that can satisfy a variety of security policies.
  12507. *
  12508. * <p>
  12509. * The HTML sanitizer is built around a SAX parser and HTML element and
  12510. * attributes schemas.
  12511. *
  12512. * If the cssparser is loaded, inline styles are sanitized using the
  12513. * css property and value schemas. Else they are remove during
  12514. * sanitization.
  12515. *
  12516. * If it exists, uses parseCssDeclarations, sanitizeCssProperty, cssSchema
  12517. *
  12518. * @author mikesamuel@gmail.com
  12519. * @author jasvir@gmail.com
  12520. * \@requires html4, URI
  12521. * \@overrides window
  12522. * \@provides html, html_sanitize
  12523. */
  12524. // The Turkish i seems to be a non-issue, but abort in case it is.
  12525. if ('I'.toLowerCase() !== 'i') { throw 'I/i problem'; }
  12526. /**
  12527. * \@namespace
  12528. */
  12529. var html = (function(html4) {
  12530. // For closure compiler
  12531. var parseCssDeclarations, sanitizeCssProperty, cssSchema;
  12532. if ('undefined' !== typeof window) {
  12533. parseCssDeclarations = window['parseCssDeclarations'];
  12534. sanitizeCssProperty = window['sanitizeCssProperty'];
  12535. cssSchema = window['cssSchema'];
  12536. }
  12537. // The keys of this object must be 'quoted' or JSCompiler will mangle them!
  12538. // This is a partial list -- lookupEntity() uses the host browser's parser
  12539. // (when available) to implement full entity lookup.
  12540. // Note that entities are in general case-sensitive; the uppercase ones are
  12541. // explicitly defined by HTML5 (presumably as compatibility).
  12542. var ENTITIES = {
  12543. 'lt': '<',
  12544. 'LT': '<',
  12545. 'gt': '>',
  12546. 'GT': '>',
  12547. 'amp': '&',
  12548. 'AMP': '&',
  12549. 'quot': '"',
  12550. 'apos': '\'',
  12551. 'nbsp': '\u00A0'
  12552. };
  12553. // Patterns for types of entity/character reference names.
  12554. var decimalEscapeRe = /^#(\d+)$/;
  12555. var hexEscapeRe = /^#x([0-9A-Fa-f]+)$/;
  12556. // contains every entity per http://www.w3.org/TR/2011/WD-html5-20110113/named-character-references.html
  12557. var safeEntityNameRe = /^[A-Za-z][A-za-z0-9]+$/;
  12558. // Used as a hook to invoke the browser's entity parsing. <textarea> is used
  12559. // because its content is parsed for entities but not tags.
  12560. // TODO(kpreid): This retrieval is a kludge and leads to silent loss of
  12561. // functionality if the document isn't available.
  12562. var entityLookupElement =
  12563. ('undefined' !== typeof window && window['document'])
  12564. ? window['document'].createElement('textarea') : null;
  12565. /**
  12566. * Decodes an HTML entity.
  12567. *
  12568. * {\@updoc
  12569. * $ lookupEntity('lt')
  12570. * # '<'
  12571. * $ lookupEntity('GT')
  12572. * # '>'
  12573. * $ lookupEntity('amp')
  12574. * # '&'
  12575. * $ lookupEntity('nbsp')
  12576. * # '\xA0'
  12577. * $ lookupEntity('apos')
  12578. * # "'"
  12579. * $ lookupEntity('quot')
  12580. * # '"'
  12581. * $ lookupEntity('#xa')
  12582. * # '\n'
  12583. * $ lookupEntity('#10')
  12584. * # '\n'
  12585. * $ lookupEntity('#x0a')
  12586. * # '\n'
  12587. * $ lookupEntity('#010')
  12588. * # '\n'
  12589. * $ lookupEntity('#x00A')
  12590. * # '\n'
  12591. * $ lookupEntity('Pi') // Known failure
  12592. * # '\u03A0'
  12593. * $ lookupEntity('pi') // Known failure
  12594. * # '\u03C0'
  12595. * }
  12596. *
  12597. * @param {string} name the content between the '&' and the ';'.
  12598. * @return {string} a single unicode code-point as a string.
  12599. */
  12600. function lookupEntity(name) {
  12601. // TODO: entity lookup as specified by HTML5 actually depends on the
  12602. // presence of the ";".
  12603. if (ENTITIES.hasOwnProperty(name)) { return ENTITIES[name]; }
  12604. var m = name.match(decimalEscapeRe);
  12605. if (m) {
  12606. return String.fromCharCode(parseInt(m[1], 10));
  12607. } else if (!!(m = name.match(hexEscapeRe))) {
  12608. return String.fromCharCode(parseInt(m[1], 16));
  12609. } else if (entityLookupElement && safeEntityNameRe.test(name)) {
  12610. entityLookupElement.innerHTML = '&' + name + ';';
  12611. var text = entityLookupElement.textContent;
  12612. ENTITIES[name] = text;
  12613. return text;
  12614. } else {
  12615. return '&' + name + ';';
  12616. }
  12617. }
  12618. function decodeOneEntity(_, name) {
  12619. return lookupEntity(name);
  12620. }
  12621. var nulRe = /\0/g;
  12622. function stripNULs(s) {
  12623. return s.replace(nulRe, '');
  12624. }
  12625. var ENTITY_RE_1 = /&(#[0-9]+|#[xX][0-9A-Fa-f]+|\w+);/g;
  12626. var ENTITY_RE_2 = /^(#[0-9]+|#[xX][0-9A-Fa-f]+|\w+);/;
  12627. /**
  12628. * The plain text of a chunk of HTML CDATA which possibly containing.
  12629. *
  12630. * {\@updoc
  12631. * $ unescapeEntities('')
  12632. * # ''
  12633. * $ unescapeEntities('hello World!')
  12634. * # 'hello World!'
  12635. * $ unescapeEntities('1 &lt; 2 &amp;&AMP; 4 &gt; 3&#10;')
  12636. * # '1 < 2 && 4 > 3\n'
  12637. * $ unescapeEntities('&lt;&lt <- unfinished entity&gt;')
  12638. * # '<&lt <- unfinished entity>'
  12639. * $ unescapeEntities('/foo?bar=baz&copy=true') // & often unescaped in URLS
  12640. * # '/foo?bar=baz&copy=true'
  12641. * $ unescapeEntities('pi=&pi;&#x3c0;, Pi=&Pi;\u03A0') // FIXME: known failure
  12642. * # 'pi=\u03C0\u03c0, Pi=\u03A0\u03A0'
  12643. * }
  12644. *
  12645. * @param {string} s a chunk of HTML CDATA. It must not start or end inside
  12646. * an HTML entity.
  12647. */
  12648. function unescapeEntities(s) {
  12649. return s.replace(ENTITY_RE_1, decodeOneEntity);
  12650. }
  12651. var ampRe = /&/g;
  12652. var looseAmpRe = /&([^a-z#]|#(?:[^0-9x]|x(?:[^0-9a-f]|$)|$)|$)/gi;
  12653. var ltRe = /[<]/g;
  12654. var gtRe = />/g;
  12655. var quotRe = /\"/g;
  12656. /**
  12657. * Escapes HTML special characters in attribute values.
  12658. *
  12659. * {\@updoc
  12660. * $ escapeAttrib('')
  12661. * # ''
  12662. * $ escapeAttrib('"<<&==&>>"') // Do not just escape the first occurrence.
  12663. * # '&#34;&lt;&lt;&amp;&#61;&#61;&amp;&gt;&gt;&#34;'
  12664. * $ escapeAttrib('Hello <World>!')
  12665. * # 'Hello &lt;World&gt;!'
  12666. * }
  12667. */
  12668. function escapeAttrib(s) {
  12669. return ('' + s).replace(ampRe, '&amp;').replace(ltRe, '&lt;')
  12670. .replace(gtRe, '&gt;').replace(quotRe, '&#34;');
  12671. }
  12672. /**
  12673. * Escape entities in RCDATA that can be escaped without changing the meaning.
  12674. * {\@updoc
  12675. * $ normalizeRCData('1 < 2 &&amp; 3 > 4 &amp;& 5 &lt; 7&8')
  12676. * # '1 &lt; 2 &amp;&amp; 3 &gt; 4 &amp;&amp; 5 &lt; 7&amp;8'
  12677. * }
  12678. */
  12679. function normalizeRCData(rcdata) {
  12680. return rcdata
  12681. .replace(looseAmpRe, '&amp;$1')
  12682. .replace(ltRe, '&lt;')
  12683. .replace(gtRe, '&gt;');
  12684. }
  12685. // TODO(felix8a): validate sanitizer regexs against the HTML5 grammar at
  12686. // http://www.whatwg.org/specs/web-apps/current-work/multipage/syntax.html
  12687. // http://www.whatwg.org/specs/web-apps/current-work/multipage/parsing.html
  12688. // http://www.whatwg.org/specs/web-apps/current-work/multipage/tokenization.html
  12689. // http://www.whatwg.org/specs/web-apps/current-work/multipage/tree-construction.html
  12690. // We initially split input so that potentially meaningful characters
  12691. // like '<' and '>' are separate tokens, using a fast dumb process that
  12692. // ignores quoting. Then we walk that token stream, and when we see a
  12693. // '<' that's the start of a tag, we use ATTR_RE to extract tag
  12694. // attributes from the next token. That token will never have a '>'
  12695. // character. However, it might have an unbalanced quote character, and
  12696. // when we see that, we combine additional tokens to balance the quote.
  12697. var ATTR_RE = new RegExp(
  12698. '^\\s*' +
  12699. '([-.:\\w]+)' + // 1 = Attribute name
  12700. '(?:' + (
  12701. '\\s*(=)\\s*' + // 2 = Is there a value?
  12702. '(' + ( // 3 = Attribute value
  12703. // TODO(felix8a): maybe use backref to match quotes
  12704. '(\")[^\"]*(\"|$)' + // 4, 5 = Double-quoted string
  12705. '|' +
  12706. '(\')[^\']*(\'|$)' + // 6, 7 = Single-quoted string
  12707. '|' +
  12708. // Positive lookahead to prevent interpretation of
  12709. // <foo a= b=c> as <foo a='b=c'>
  12710. // TODO(felix8a): might be able to drop this case
  12711. '(?=[a-z][-\\w]*\\s*=)' +
  12712. '|' +
  12713. // Unquoted value that isn't an attribute name
  12714. // (since we didn't match the positive lookahead above)
  12715. '[^\"\'\\s]*' ) +
  12716. ')' ) +
  12717. ')?',
  12718. 'i');
  12719. // false on IE<=8, true on most other browsers
  12720. var splitWillCapture = ('a,b'.split(/(,)/).length === 3);
  12721. // bitmask for tags with special parsing, like <script> and <textarea>
  12722. var EFLAGS_TEXT = html4.eflags['CDATA'] | html4.eflags['RCDATA'];
  12723. /**
  12724. * Given a SAX-like event handler, produce a function that feeds those
  12725. * events and a parameter to the event handler.
  12726. *
  12727. * The event handler has the form:{@code
  12728. * {
  12729. * // Name is an upper-case HTML tag name. Attribs is an array of
  12730. * // alternating upper-case attribute names, and attribute values. The
  12731. * // attribs array is reused by the parser. Param is the value passed to
  12732. * // the saxParser.
  12733. * startTag: function (name, attribs, param) { ... },
  12734. * endTag: function (name, param) { ... },
  12735. * pcdata: function (text, param) { ... },
  12736. * rcdata: function (text, param) { ... },
  12737. * cdata: function (text, param) { ... },
  12738. * startDoc: function (param) { ... },
  12739. * endDoc: function (param) { ... }
  12740. * }}
  12741. *
  12742. * @param {Object} handler a record containing event handlers.
  12743. * @return {function(string, Object)} A function that takes a chunk of HTML
  12744. * and a parameter. The parameter is passed on to the handler methods.
  12745. */
  12746. function makeSaxParser(handler) {
  12747. // Accept quoted or unquoted keys (Closure compat)
  12748. var hcopy = {
  12749. cdata: handler.cdata || handler['cdata'],
  12750. comment: handler.comment || handler['comment'],
  12751. endDoc: handler.endDoc || handler['endDoc'],
  12752. endTag: handler.endTag || handler['endTag'],
  12753. pcdata: handler.pcdata || handler['pcdata'],
  12754. rcdata: handler.rcdata || handler['rcdata'],
  12755. startDoc: handler.startDoc || handler['startDoc'],
  12756. startTag: handler.startTag || handler['startTag']
  12757. };
  12758. return function(htmlText, param) {
  12759. return parse(htmlText, hcopy, param);
  12760. };
  12761. }
  12762. // Parsing strategy is to split input into parts that might be lexically
  12763. // meaningful (every ">" becomes a separate part), and then recombine
  12764. // parts if we discover they're in a different context.
  12765. // TODO(felix8a): Significant performance regressions from -legacy,
  12766. // tested on
  12767. // Chrome 18.0
  12768. // Firefox 11.0
  12769. // IE 6, 7, 8, 9
  12770. // Opera 11.61
  12771. // Safari 5.1.3
  12772. // Many of these are unusual patterns that are linearly slower and still
  12773. // pretty fast (eg 1ms to 5ms), so not necessarily worth fixing.
  12774. // TODO(felix8a): "<script> && && && ... <\/script>" is slower on all
  12775. // browsers. The hotspot is htmlSplit.
  12776. // TODO(felix8a): "<p title='>>>>...'><\/p>" is slower on all browsers.
  12777. // This is partly htmlSplit, but the hotspot is parseTagAndAttrs.
  12778. // TODO(felix8a): "<a><\/a><a><\/a>..." is slower on IE9.
  12779. // "<a>1<\/a><a>1<\/a>..." is faster, "<a><\/a>2<a><\/a>2..." is faster.
  12780. // TODO(felix8a): "<p<p<p..." is slower on IE[6-8]
  12781. var continuationMarker = {};
  12782. function parse(htmlText, handler, param) {
  12783. var m, p, tagName;
  12784. var parts = htmlSplit(htmlText);
  12785. var state = {
  12786. noMoreGT: false,
  12787. noMoreEndComments: false
  12788. };
  12789. parseCPS(handler, parts, 0, state, param);
  12790. }
  12791. function continuationMaker(h, parts, initial, state, param) {
  12792. return function () {
  12793. parseCPS(h, parts, initial, state, param);
  12794. };
  12795. }
  12796. function parseCPS(h, parts, initial, state, param) {
  12797. try {
  12798. if (h.startDoc && initial == 0) { h.startDoc(param); }
  12799. var m, p, tagName;
  12800. for (var pos = initial, end = parts.length; pos < end;) {
  12801. var current = parts[pos++];
  12802. var next = parts[pos];
  12803. switch (current) {
  12804. case '&':
  12805. if (ENTITY_RE_2.test(next)) {
  12806. if (h.pcdata) {
  12807. h.pcdata('&' + next, param, continuationMarker,
  12808. continuationMaker(h, parts, pos, state, param));
  12809. }
  12810. pos++;
  12811. } else {
  12812. if (h.pcdata) { h.pcdata("&amp;", param, continuationMarker,
  12813. continuationMaker(h, parts, pos, state, param));
  12814. }
  12815. }
  12816. break;
  12817. case '<\/':
  12818. if (m = /^([-\w:]+)[^\'\"]*/.exec(next)) {
  12819. if (m[0].length === next.length && parts[pos + 1] === '>') {
  12820. // fast case, no attribute parsing needed
  12821. pos += 2;
  12822. tagName = m[1].toLowerCase();
  12823. if (h.endTag) {
  12824. h.endTag(tagName, param, continuationMarker,
  12825. continuationMaker(h, parts, pos, state, param));
  12826. }
  12827. } else {
  12828. // slow case, need to parse attributes
  12829. // TODO(felix8a): do we really care about misparsing this?
  12830. pos = parseEndTag(
  12831. parts, pos, h, param, continuationMarker, state);
  12832. }
  12833. } else {
  12834. if (h.pcdata) {
  12835. h.pcdata('&lt;/', param, continuationMarker,
  12836. continuationMaker(h, parts, pos, state, param));
  12837. }
  12838. }
  12839. break;
  12840. case '<':
  12841. if (m = /^([-\w:]+)\s*\/?/.exec(next)) {
  12842. if (m[0].length === next.length && parts[pos + 1] === '>') {
  12843. // fast case, no attribute parsing needed
  12844. pos += 2;
  12845. tagName = m[1].toLowerCase();
  12846. if (h.startTag) {
  12847. h.startTag(tagName, [], param, continuationMarker,
  12848. continuationMaker(h, parts, pos, state, param));
  12849. }
  12850. // tags like <script> and <textarea> have special parsing
  12851. var eflags = html4.ELEMENTS[tagName];
  12852. if (eflags & EFLAGS_TEXT) {
  12853. var tag = { name: tagName, next: pos, eflags: eflags };
  12854. pos = parseText(
  12855. parts, tag, h, param, continuationMarker, state);
  12856. }
  12857. } else {
  12858. // slow case, need to parse attributes
  12859. pos = parseStartTag(
  12860. parts, pos, h, param, continuationMarker, state);
  12861. }
  12862. } else {
  12863. if (h.pcdata) {
  12864. h.pcdata('&lt;', param, continuationMarker,
  12865. continuationMaker(h, parts, pos, state, param));
  12866. }
  12867. }
  12868. break;
  12869. case '<\!--':
  12870. // The pathological case is n copies of '<\!--' without '-->', and
  12871. // repeated failure to find '-->' is quadratic. We avoid that by
  12872. // remembering when search for '-->' fails.
  12873. if (!state.noMoreEndComments) {
  12874. // A comment <\!--x--> is split into three tokens:
  12875. // '<\!--', 'x--', '>'
  12876. // We want to find the next '>' token that has a preceding '--'.
  12877. // pos is at the 'x--'.
  12878. for (p = pos + 1; p < end; p++) {
  12879. if (parts[p] === '>' && /--$/.test(parts[p - 1])) { break; }
  12880. }
  12881. if (p < end) {
  12882. if (h.comment) {
  12883. var comment = parts.slice(pos, p).join('');
  12884. h.comment(
  12885. comment.substr(0, comment.length - 2), param,
  12886. continuationMarker,
  12887. continuationMaker(h, parts, p + 1, state, param));
  12888. }
  12889. pos = p + 1;
  12890. } else {
  12891. state.noMoreEndComments = true;
  12892. }
  12893. }
  12894. if (state.noMoreEndComments) {
  12895. if (h.pcdata) {
  12896. h.pcdata('&lt;!--', param, continuationMarker,
  12897. continuationMaker(h, parts, pos, state, param));
  12898. }
  12899. }
  12900. break;
  12901. case '<\!':
  12902. if (!/^\w/.test(next)) {
  12903. if (h.pcdata) {
  12904. h.pcdata('&lt;!', param, continuationMarker,
  12905. continuationMaker(h, parts, pos, state, param));
  12906. }
  12907. } else {
  12908. // similar to noMoreEndComment logic
  12909. if (!state.noMoreGT) {
  12910. for (p = pos + 1; p < end; p++) {
  12911. if (parts[p] === '>') { break; }
  12912. }
  12913. if (p < end) {
  12914. pos = p + 1;
  12915. } else {
  12916. state.noMoreGT = true;
  12917. }
  12918. }
  12919. if (state.noMoreGT) {
  12920. if (h.pcdata) {
  12921. h.pcdata('&lt;!', param, continuationMarker,
  12922. continuationMaker(h, parts, pos, state, param));
  12923. }
  12924. }
  12925. }
  12926. break;
  12927. case '<?':
  12928. // similar to noMoreEndComment logic
  12929. if (!state.noMoreGT) {
  12930. for (p = pos + 1; p < end; p++) {
  12931. if (parts[p] === '>') { break; }
  12932. }
  12933. if (p < end) {
  12934. pos = p + 1;
  12935. } else {
  12936. state.noMoreGT = true;
  12937. }
  12938. }
  12939. if (state.noMoreGT) {
  12940. if (h.pcdata) {
  12941. h.pcdata('&lt;?', param, continuationMarker,
  12942. continuationMaker(h, parts, pos, state, param));
  12943. }
  12944. }
  12945. break;
  12946. case '>':
  12947. if (h.pcdata) {
  12948. h.pcdata("&gt;", param, continuationMarker,
  12949. continuationMaker(h, parts, pos, state, param));
  12950. }
  12951. break;
  12952. case '':
  12953. break;
  12954. default:
  12955. if (h.pcdata) {
  12956. h.pcdata(current, param, continuationMarker,
  12957. continuationMaker(h, parts, pos, state, param));
  12958. }
  12959. break;
  12960. }
  12961. }
  12962. if (h.endDoc) { h.endDoc(param); }
  12963. } catch (e) {
  12964. if (e !== continuationMarker) { throw e; }
  12965. }
  12966. }
  12967. // Split str into parts for the html parser.
  12968. function htmlSplit(str) {
  12969. // can't hoist this out of the function because of the re.exec loop.
  12970. var re = /(<\/|<\!--|<[!?]|[&<>])/g;
  12971. str += '';
  12972. if (splitWillCapture) {
  12973. return str.split(re);
  12974. } else {
  12975. var parts = [];
  12976. var lastPos = 0;
  12977. var m;
  12978. while ((m = re.exec(str)) !== null) {
  12979. parts.push(str.substring(lastPos, m.index));
  12980. parts.push(m[0]);
  12981. lastPos = m.index + m[0].length;
  12982. }
  12983. parts.push(str.substring(lastPos));
  12984. return parts;
  12985. }
  12986. }
  12987. function parseEndTag(parts, pos, h, param, continuationMarker, state) {
  12988. var tag = parseTagAndAttrs(parts, pos);
  12989. // drop unclosed tags
  12990. if (!tag) { return parts.length; }
  12991. if (h.endTag) {
  12992. h.endTag(tag.name, param, continuationMarker,
  12993. continuationMaker(h, parts, pos, state, param));
  12994. }
  12995. return tag.next;
  12996. }
  12997. function parseStartTag(parts, pos, h, param, continuationMarker, state) {
  12998. var tag = parseTagAndAttrs(parts, pos);
  12999. // drop unclosed tags
  13000. if (!tag) { return parts.length; }
  13001. if (h.startTag) {
  13002. h.startTag(tag.name, tag.attrs, param, continuationMarker,
  13003. continuationMaker(h, parts, tag.next, state, param));
  13004. }
  13005. // tags like <script> and <textarea> have special parsing
  13006. if (tag.eflags & EFLAGS_TEXT) {
  13007. return parseText(parts, tag, h, param, continuationMarker, state);
  13008. } else {
  13009. return tag.next;
  13010. }
  13011. }
  13012. var endTagRe = {};
  13013. // Tags like <script> and <textarea> are flagged as CDATA or RCDATA,
  13014. // which means everything is text until we see the correct closing tag.
  13015. function parseText(parts, tag, h, param, continuationMarker, state) {
  13016. var end = parts.length;
  13017. if (!endTagRe.hasOwnProperty(tag.name)) {
  13018. endTagRe[tag.name] = new RegExp('^' + tag.name + '(?:[\\s\\/]|$)', 'i');
  13019. }
  13020. var re = endTagRe[tag.name];
  13021. var first = tag.next;
  13022. var p = tag.next + 1;
  13023. for (; p < end; p++) {
  13024. if (parts[p - 1] === '<\/' && re.test(parts[p])) { break; }
  13025. }
  13026. if (p < end) { p -= 1; }
  13027. var buf = parts.slice(first, p).join('');
  13028. if (tag.eflags & html4.eflags['CDATA']) {
  13029. if (h.cdata) {
  13030. h.cdata(buf, param, continuationMarker,
  13031. continuationMaker(h, parts, p, state, param));
  13032. }
  13033. } else if (tag.eflags & html4.eflags['RCDATA']) {
  13034. if (h.rcdata) {
  13035. h.rcdata(normalizeRCData(buf), param, continuationMarker,
  13036. continuationMaker(h, parts, p, state, param));
  13037. }
  13038. } else {
  13039. throw new Error('bug');
  13040. }
  13041. return p;
  13042. }
  13043. // at this point, parts[pos-1] is either "<" or "<\/".
  13044. function parseTagAndAttrs(parts, pos) {
  13045. var m = /^([-\w:]+)/.exec(parts[pos]);
  13046. var tag = {};
  13047. tag.name = m[1].toLowerCase();
  13048. tag.eflags = html4.ELEMENTS[tag.name];
  13049. var buf = parts[pos].substr(m[0].length);
  13050. // Find the next '>'. We optimistically assume this '>' is not in a
  13051. // quoted context, and further down we fix things up if it turns out to
  13052. // be quoted.
  13053. var p = pos + 1;
  13054. var end = parts.length;
  13055. for (; p < end; p++) {
  13056. if (parts[p] === '>') { break; }
  13057. buf += parts[p];
  13058. }
  13059. if (end <= p) { return void 0; }
  13060. var attrs = [];
  13061. while (buf !== '') {
  13062. m = ATTR_RE.exec(buf);
  13063. if (!m) {
  13064. // No attribute found: skip garbage
  13065. buf = buf.replace(/^[\s\S][^a-z\s]*/, '');
  13066. } else if ((m[4] && !m[5]) || (m[6] && !m[7])) {
  13067. // Unterminated quote: slurp to the next unquoted '>'
  13068. var quote = m[4] || m[6];
  13069. var sawQuote = false;
  13070. var abuf = [buf, parts[p++]];
  13071. for (; p < end; p++) {
  13072. if (sawQuote) {
  13073. if (parts[p] === '>') { break; }
  13074. } else if (0 <= parts[p].indexOf(quote)) {
  13075. sawQuote = true;
  13076. }
  13077. abuf.push(parts[p]);
  13078. }
  13079. // Slurp failed: lose the garbage
  13080. if (end <= p) { break; }
  13081. // Otherwise retry attribute parsing
  13082. buf = abuf.join('');
  13083. continue;
  13084. } else {
  13085. // We have an attribute
  13086. var aName = m[1].toLowerCase();
  13087. var aValue = m[2] ? decodeValue(m[3]) : '';
  13088. attrs.push(aName, aValue);
  13089. buf = buf.substr(m[0].length);
  13090. }
  13091. }
  13092. tag.attrs = attrs;
  13093. tag.next = p + 1;
  13094. return tag;
  13095. }
  13096. function decodeValue(v) {
  13097. var q = v.charCodeAt(0);
  13098. if (q === 0x22 || q === 0x27) { // " or '
  13099. v = v.substr(1, v.length - 2);
  13100. }
  13101. return unescapeEntities(stripNULs(v));
  13102. }
  13103. /**
  13104. * Returns a function that strips unsafe tags and attributes from html.
  13105. * @param {function(string, Array.<string>): ?Array.<string>} tagPolicy
  13106. * A function that takes (tagName, attribs[]), where tagName is a key in
  13107. * html4.ELEMENTS and attribs is an array of alternating attribute names
  13108. * and values. It should return a record (as follows), or null to delete
  13109. * the element. It's okay for tagPolicy to modify the attribs array,
  13110. * but the same array is reused, so it should not be held between calls.
  13111. * Record keys:
  13112. * attribs: (required) Sanitized attributes array.
  13113. * tagName: Replacement tag name.
  13114. * @return {function(string, Array)} A function that sanitizes a string of
  13115. * HTML and appends result strings to the second argument, an array.
  13116. */
  13117. function makeHtmlSanitizer(tagPolicy) {
  13118. var stack;
  13119. var ignoring;
  13120. var emit = function (text, out) {
  13121. if (!ignoring) { out.push(text); }
  13122. };
  13123. return makeSaxParser({
  13124. 'startDoc': function(_) {
  13125. stack = [];
  13126. ignoring = false;
  13127. },
  13128. 'startTag': function(tagNameOrig, attribs, out) {
  13129. if (ignoring) { return; }
  13130. if (!html4.ELEMENTS.hasOwnProperty(tagNameOrig)) { return; }
  13131. var eflagsOrig = html4.ELEMENTS[tagNameOrig];
  13132. if (eflagsOrig & html4.eflags['FOLDABLE']) {
  13133. return;
  13134. }
  13135. var decision = tagPolicy(tagNameOrig, attribs);
  13136. if (!decision) {
  13137. ignoring = !(eflagsOrig & html4.eflags['EMPTY']);
  13138. return;
  13139. } else if (typeof decision !== 'object') {
  13140. throw new Error('tagPolicy did not return object (old API?)');
  13141. }
  13142. if ('attribs' in decision) {
  13143. attribs = decision['attribs'];
  13144. } else {
  13145. throw new Error('tagPolicy gave no attribs');
  13146. }
  13147. var eflagsRep;
  13148. var tagNameRep;
  13149. if ('tagName' in decision) {
  13150. tagNameRep = decision['tagName'];
  13151. eflagsRep = html4.ELEMENTS[tagNameRep];
  13152. } else {
  13153. tagNameRep = tagNameOrig;
  13154. eflagsRep = eflagsOrig;
  13155. }
  13156. // TODO(mikesamuel): relying on tagPolicy not to insert unsafe
  13157. // attribute names.
  13158. // If this is an optional-end-tag element and either this element or its
  13159. // previous like sibling was rewritten, then insert a close tag to
  13160. // preserve structure.
  13161. if (eflagsOrig & html4.eflags['OPTIONAL_ENDTAG']) {
  13162. var onStack = stack[stack.length - 1];
  13163. if (onStack && onStack.orig === tagNameOrig &&
  13164. (onStack.rep !== tagNameRep || tagNameOrig !== tagNameRep)) {
  13165. out.push('<\/', onStack.rep, '>');
  13166. }
  13167. }
  13168. if (!(eflagsOrig & html4.eflags['EMPTY'])) {
  13169. stack.push({orig: tagNameOrig, rep: tagNameRep});
  13170. }
  13171. out.push('<', tagNameRep);
  13172. for (var i = 0, n = attribs.length; i < n; i += 2) {
  13173. var attribName = attribs[i],
  13174. value = attribs[i + 1];
  13175. if (value !== null && value !== void 0) {
  13176. out.push(' ', attribName, '="', escapeAttrib(value), '"');
  13177. }
  13178. }
  13179. out.push('>');
  13180. if ((eflagsOrig & html4.eflags['EMPTY'])
  13181. && !(eflagsRep & html4.eflags['EMPTY'])) {
  13182. // replacement is non-empty, synthesize end tag
  13183. out.push('<\/', tagNameRep, '>');
  13184. }
  13185. },
  13186. 'endTag': function(tagName, out) {
  13187. if (ignoring) {
  13188. ignoring = false;
  13189. return;
  13190. }
  13191. if (!html4.ELEMENTS.hasOwnProperty(tagName)) { return; }
  13192. var eflags = html4.ELEMENTS[tagName];
  13193. if (!(eflags & (html4.eflags['EMPTY'] | html4.eflags['FOLDABLE']))) {
  13194. var index;
  13195. if (eflags & html4.eflags['OPTIONAL_ENDTAG']) {
  13196. for (index = stack.length; --index >= 0;) {
  13197. var stackElOrigTag = stack[index].orig;
  13198. if (stackElOrigTag === tagName) { break; }
  13199. if (!(html4.ELEMENTS[stackElOrigTag] &
  13200. html4.eflags['OPTIONAL_ENDTAG'])) {
  13201. // Don't pop non optional end tags looking for a match.
  13202. return;
  13203. }
  13204. }
  13205. } else {
  13206. for (index = stack.length; --index >= 0;) {
  13207. if (stack[index].orig === tagName) { break; }
  13208. }
  13209. }
  13210. if (index < 0) { return; } // Not opened.
  13211. for (var i = stack.length; --i > index;) {
  13212. var stackElRepTag = stack[i].rep;
  13213. if (!(html4.ELEMENTS[stackElRepTag] &
  13214. html4.eflags['OPTIONAL_ENDTAG'])) {
  13215. out.push('<\/', stackElRepTag, '>');
  13216. }
  13217. }
  13218. if (index < stack.length) {
  13219. tagName = stack[index].rep;
  13220. }
  13221. stack.length = index;
  13222. out.push('<\/', tagName, '>');
  13223. }
  13224. },
  13225. 'pcdata': emit,
  13226. 'rcdata': emit,
  13227. 'cdata': emit,
  13228. 'endDoc': function(out) {
  13229. for (; stack.length; stack.length--) {
  13230. out.push('<\/', stack[stack.length - 1].rep, '>');
  13231. }
  13232. }
  13233. });
  13234. }
  13235. var ALLOWED_URI_SCHEMES = /^(?:https?|mailto|data)$/i;
  13236. function safeUri(uri, effect, ltype, hints, naiveUriRewriter) {
  13237. if (!naiveUriRewriter) { return null; }
  13238. try {
  13239. var parsed = URI.parse('' + uri);
  13240. if (parsed) {
  13241. if (!parsed.hasScheme() ||
  13242. ALLOWED_URI_SCHEMES.test(parsed.getScheme())) {
  13243. var safe = naiveUriRewriter(parsed, effect, ltype, hints);
  13244. return safe ? safe.toString() : null;
  13245. }
  13246. }
  13247. } catch (e) {
  13248. return null;
  13249. }
  13250. return null;
  13251. }
  13252. function log(logger, tagName, attribName, oldValue, newValue) {
  13253. if (!attribName) {
  13254. logger(tagName + " removed", {
  13255. change: "removed",
  13256. tagName: tagName
  13257. });
  13258. }
  13259. if (oldValue !== newValue) {
  13260. var changed = "changed";
  13261. if (oldValue && !newValue) {
  13262. changed = "removed";
  13263. } else if (!oldValue && newValue) {
  13264. changed = "added";
  13265. }
  13266. logger(tagName + "." + attribName + " " + changed, {
  13267. change: changed,
  13268. tagName: tagName,
  13269. attribName: attribName,
  13270. oldValue: oldValue,
  13271. newValue: newValue
  13272. });
  13273. }
  13274. }
  13275. function lookupAttribute(map, tagName, attribName) {
  13276. var attribKey;
  13277. attribKey = tagName + '::' + attribName;
  13278. if (map.hasOwnProperty(attribKey)) {
  13279. return map[attribKey];
  13280. }
  13281. attribKey = '*::' + attribName;
  13282. if (map.hasOwnProperty(attribKey)) {
  13283. return map[attribKey];
  13284. }
  13285. return void 0;
  13286. }
  13287. function getAttributeType(tagName, attribName) {
  13288. return lookupAttribute(html4.ATTRIBS, tagName, attribName);
  13289. }
  13290. function getLoaderType(tagName, attribName) {
  13291. return lookupAttribute(html4.LOADERTYPES, tagName, attribName);
  13292. }
  13293. function getUriEffect(tagName, attribName) {
  13294. return lookupAttribute(html4.URIEFFECTS, tagName, attribName);
  13295. }
  13296. /**
  13297. * Sanitizes attributes on an HTML tag.
  13298. * @param {string} tagName An HTML tag name in lowercase.
  13299. * @param {Array.<?string>} attribs An array of alternating names and values.
  13300. * @param {?function(?string): ?string} opt_naiveUriRewriter A transform to
  13301. * apply to URI attributes; it can return a new string value, or null to
  13302. * delete the attribute. If unspecified, URI attributes are deleted.
  13303. * @param {function(?string): ?string} opt_nmTokenPolicy A transform to apply
  13304. * to attributes containing HTML names, element IDs, and space-separated
  13305. * lists of classes; it can return a new string value, or null to delete
  13306. * the attribute. If unspecified, these attributes are kept unchanged.
  13307. * @return {Array.<?string>} The sanitized attributes as a list of alternating
  13308. * names and values, where a null value means to omit the attribute.
  13309. */
  13310. function sanitizeAttribs(tagName, attribs,
  13311. opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger) {
  13312. // TODO(felix8a): it's obnoxious that domado duplicates much of this
  13313. // TODO(felix8a): maybe consistently enforce constraints like target=
  13314. for (var i = 0; i < attribs.length; i += 2) {
  13315. var attribName = attribs[i];
  13316. var value = attribs[i + 1];
  13317. var oldValue = value;
  13318. var atype = null, attribKey;
  13319. if ((attribKey = tagName + '::' + attribName,
  13320. html4.ATTRIBS.hasOwnProperty(attribKey)) ||
  13321. (attribKey = '*::' + attribName,
  13322. html4.ATTRIBS.hasOwnProperty(attribKey))) {
  13323. atype = html4.ATTRIBS[attribKey];
  13324. }
  13325. if (atype !== null) {
  13326. switch (atype) {
  13327. case html4.atype['NONE']: break;
  13328. case html4.atype['SCRIPT']:
  13329. value = null;
  13330. if (opt_logger) {
  13331. log(opt_logger, tagName, attribName, oldValue, value);
  13332. }
  13333. break;
  13334. case html4.atype['STYLE']:
  13335. if ('undefined' === typeof parseCssDeclarations) {
  13336. value = null;
  13337. if (opt_logger) {
  13338. log(opt_logger, tagName, attribName, oldValue, value);
  13339. }
  13340. break;
  13341. }
  13342. var sanitizedDeclarations = [];
  13343. parseCssDeclarations(
  13344. value,
  13345. {
  13346. declaration: function (property, tokens) {
  13347. var normProp = property.toLowerCase();
  13348. var schema = cssSchema[normProp];
  13349. if (!schema) {
  13350. return;
  13351. }
  13352. sanitizeCssProperty(
  13353. normProp, schema, tokens,
  13354. opt_naiveUriRewriter
  13355. ? function (url) {
  13356. return safeUri(
  13357. url, html4.ueffects.SAME_DOCUMENT,
  13358. html4.ltypes.SANDBOXED,
  13359. {
  13360. "TYPE": "CSS",
  13361. "CSS_PROP": normProp
  13362. }, opt_naiveUriRewriter);
  13363. }
  13364. : null);
  13365. sanitizedDeclarations.push(property + ': ' + tokens.join(' '));
  13366. }
  13367. });
  13368. value = sanitizedDeclarations.length > 0 ?
  13369. sanitizedDeclarations.join(' ; ') : null;
  13370. if (opt_logger) {
  13371. log(opt_logger, tagName, attribName, oldValue, value);
  13372. }
  13373. break;
  13374. case html4.atype['ID']:
  13375. case html4.atype['IDREF']:
  13376. case html4.atype['IDREFS']:
  13377. case html4.atype['GLOBAL_NAME']:
  13378. case html4.atype['LOCAL_NAME']:
  13379. case html4.atype['CLASSES']:
  13380. value = opt_nmTokenPolicy ? opt_nmTokenPolicy(value) : value;
  13381. if (opt_logger) {
  13382. log(opt_logger, tagName, attribName, oldValue, value);
  13383. }
  13384. break;
  13385. case html4.atype['URI']:
  13386. value = safeUri(value,
  13387. getUriEffect(tagName, attribName),
  13388. getLoaderType(tagName, attribName),
  13389. {
  13390. "TYPE": "MARKUP",
  13391. "XML_ATTR": attribName,
  13392. "XML_TAG": tagName
  13393. }, opt_naiveUriRewriter);
  13394. if (opt_logger) {
  13395. log(opt_logger, tagName, attribName, oldValue, value);
  13396. }
  13397. break;
  13398. case html4.atype['URI_FRAGMENT']:
  13399. if (value && '#' === value.charAt(0)) {
  13400. value = value.substring(1); // remove the leading '#'
  13401. value = opt_nmTokenPolicy ? opt_nmTokenPolicy(value) : value;
  13402. if (value !== null && value !== void 0) {
  13403. value = '#' + value; // restore the leading '#'
  13404. }
  13405. } else {
  13406. value = null;
  13407. }
  13408. if (opt_logger) {
  13409. log(opt_logger, tagName, attribName, oldValue, value);
  13410. }
  13411. break;
  13412. default:
  13413. value = null;
  13414. if (opt_logger) {
  13415. log(opt_logger, tagName, attribName, oldValue, value);
  13416. }
  13417. break;
  13418. }
  13419. } else {
  13420. value = null;
  13421. if (opt_logger) {
  13422. log(opt_logger, tagName, attribName, oldValue, value);
  13423. }
  13424. }
  13425. attribs[i + 1] = value;
  13426. }
  13427. return attribs;
  13428. }
  13429. /**
  13430. * Creates a tag policy that omits all tags marked UNSAFE in html4-defs.js
  13431. * and applies the default attribute sanitizer with the supplied policy for
  13432. * URI attributes and NMTOKEN attributes.
  13433. * @param {?function(?string): ?string} opt_naiveUriRewriter A transform to
  13434. * apply to URI attributes. If not given, URI attributes are deleted.
  13435. * @param {function(?string): ?string} opt_nmTokenPolicy A transform to apply
  13436. * to attributes containing HTML names, element IDs, and space-separated
  13437. * lists of classes. If not given, such attributes are left unchanged.
  13438. * @return {function(string, Array.<?string>)} A tagPolicy suitable for
  13439. * passing to html.sanitize.
  13440. */
  13441. function makeTagPolicy(
  13442. opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger) {
  13443. return function(tagName, attribs) {
  13444. if (!(html4.ELEMENTS[tagName] & html4.eflags['UNSAFE'])) {
  13445. return {
  13446. 'attribs': sanitizeAttribs(tagName, attribs,
  13447. opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger)
  13448. };
  13449. } else {
  13450. if (opt_logger) {
  13451. log(opt_logger, tagName, undefined, undefined, undefined);
  13452. }
  13453. }
  13454. };
  13455. }
  13456. /**
  13457. * Sanitizes HTML tags and attributes according to a given policy.
  13458. * @param {string} inputHtml The HTML to sanitize.
  13459. * @param {function(string, Array.<?string>)} tagPolicy A function that
  13460. * decides which tags to accept and sanitizes their attributes (see
  13461. * makeHtmlSanitizer above for details).
  13462. * @return {string} The sanitized HTML.
  13463. */
  13464. function sanitizeWithPolicy(inputHtml, tagPolicy) {
  13465. var outputArray = [];
  13466. makeHtmlSanitizer(tagPolicy)(inputHtml, outputArray);
  13467. return outputArray.join('');
  13468. }
  13469. /**
  13470. * Strips unsafe tags and attributes from HTML.
  13471. * @param {string} inputHtml The HTML to sanitize.
  13472. * @param {?function(?string): ?string} opt_naiveUriRewriter A transform to
  13473. * apply to URI attributes. If not given, URI attributes are deleted.
  13474. * @param {function(?string): ?string} opt_nmTokenPolicy A transform to apply
  13475. * to attributes containing HTML names, element IDs, and space-separated
  13476. * lists of classes. If not given, such attributes are left unchanged.
  13477. */
  13478. function sanitize(inputHtml,
  13479. opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger) {
  13480. var tagPolicy = makeTagPolicy(
  13481. opt_naiveUriRewriter, opt_nmTokenPolicy, opt_logger);
  13482. return sanitizeWithPolicy(inputHtml, tagPolicy);
  13483. }
  13484. // Export both quoted and unquoted names for Closure linkage.
  13485. var html = {};
  13486. html.escapeAttrib = html['escapeAttrib'] = escapeAttrib;
  13487. html.makeHtmlSanitizer = html['makeHtmlSanitizer'] = makeHtmlSanitizer;
  13488. html.makeSaxParser = html['makeSaxParser'] = makeSaxParser;
  13489. html.makeTagPolicy = html['makeTagPolicy'] = makeTagPolicy;
  13490. html.normalizeRCData = html['normalizeRCData'] = normalizeRCData;
  13491. html.sanitize = html['sanitize'] = sanitize;
  13492. html.sanitizeAttribs = html['sanitizeAttribs'] = sanitizeAttribs;
  13493. html.sanitizeWithPolicy = html['sanitizeWithPolicy'] = sanitizeWithPolicy;
  13494. html.unescapeEntities = html['unescapeEntities'] = unescapeEntities;
  13495. return html;
  13496. })(html4);
  13497. var html_sanitize = html['sanitize'];
  13498. // Loosen restrictions of Caja's
  13499. // html-sanitizer to allow for styling
  13500. html4.ATTRIBS['*::style'] = 0;
  13501. html4.ELEMENTS['style'] = 0;
  13502. html4.ATTRIBS['a::target'] = 0;
  13503. html4.ELEMENTS['video'] = 0;
  13504. html4.ATTRIBS['video::src'] = 0;
  13505. html4.ATTRIBS['video::poster'] = 0;
  13506. html4.ATTRIBS['video::controls'] = 0;
  13507. html4.ELEMENTS['audio'] = 0;
  13508. html4.ATTRIBS['audio::src'] = 0;
  13509. html4.ATTRIBS['video::autoplay'] = 0;
  13510. html4.ATTRIBS['video::controls'] = 0;
  13511. if (typeof module !== 'undefined') {
  13512. module.exports = html_sanitize;
  13513. }
  13514. },{}],7:[function(require,module,exports){
  13515. module.exports={
  13516. "author": "Mapbox",
  13517. "name": "mapbox.js",
  13518. "description": "mapbox javascript api",
  13519. "version": "3.1.1",
  13520. "homepage": "http://mapbox.com/",
  13521. "repository": {
  13522. "type": "git",
  13523. "url": "git://github.com/mapbox/mapbox.js.git"
  13524. },
  13525. "main": "src/index.js",
  13526. "dependencies": {
  13527. "corslite": "0.0.6",
  13528. "isarray": "0.0.1",
  13529. "leaflet": "1.0.2",
  13530. "mustache": "2.2.1",
  13531. "sanitize-caja": "0.1.4"
  13532. },
  13533. "scripts": {
  13534. "test": "eslint --no-eslintrc -c .eslintrc src && phantomjs node_modules/mocha-phantomjs-core/mocha-phantomjs-core.js test/index.html"
  13535. },
  13536. "license": "BSD-3-Clause",
  13537. "devDependencies": {
  13538. "browserify": "^13.0.0",
  13539. "clean-css": "~2.0.7",
  13540. "cz-conventional-changelog": "1.2.0",
  13541. "eslint": "^0.23.0",
  13542. "expect.js": "0.3.1",
  13543. "happen": "0.1.3",
  13544. "leaflet-fullscreen": "0.0.4",
  13545. "leaflet-hash": "0.2.1",
  13546. "marked": "~0.3.0",
  13547. "minifyify": "^6.1.0",
  13548. "minimist": "0.0.5",
  13549. "mocha": "2.4.5",
  13550. "mocha-phantomjs-core": "2.0.1",
  13551. "phantomjs-prebuilt": "2.1.12",
  13552. "sinon": "1.10.2"
  13553. },
  13554. "optionalDependencies": {},
  13555. "engines": {
  13556. "node": "*"
  13557. },
  13558. "config": {
  13559. "commitizen": {
  13560. "path": "./node_modules/cz-conventional-changelog"
  13561. }
  13562. }
  13563. }
  13564. },{}],8:[function(require,module,exports){
  13565. 'use strict';
  13566. module.exports = {
  13567. HTTP_URL: 'http://a.tiles.mapbox.com/v4',
  13568. HTTPS_URL: 'https://a.tiles.mapbox.com/v4',
  13569. FORCE_HTTPS: false,
  13570. REQUIRE_ACCESS_TOKEN: true
  13571. };
  13572. },{}],9:[function(require,module,exports){
  13573. 'use strict';
  13574. var util = require('./util'),
  13575. format_url = require('./format_url'),
  13576. request = require('./request'),
  13577. marker = require('./marker'),
  13578. simplestyle = require('./simplestyle');
  13579. // # featureLayer
  13580. //
  13581. // A layer of features, loaded from Mapbox or else. Adds the ability
  13582. // to reset features, filter them, and load them from a GeoJSON URL.
  13583. var FeatureLayer = L.FeatureGroup.extend({
  13584. options: {
  13585. filter: function() { return true; },
  13586. sanitizer: require('sanitize-caja'),
  13587. style: simplestyle.style,
  13588. popupOptions: { closeButton: false }
  13589. },
  13590. initialize: function(_, options) {
  13591. L.setOptions(this, options);
  13592. this._layers = {};
  13593. if (typeof _ === 'string') {
  13594. util.idUrl(_, this);
  13595. // javascript object of TileJSON data
  13596. } else if (_ && typeof _ === 'object') {
  13597. this.setGeoJSON(_);
  13598. }
  13599. },
  13600. setGeoJSON: function(_) {
  13601. this._geojson = _;
  13602. this.clearLayers();
  13603. this._initialize(_);
  13604. return this;
  13605. },
  13606. getGeoJSON: function() {
  13607. return this._geojson;
  13608. },
  13609. loadURL: function(url) {
  13610. if (this._request && 'abort' in this._request) this._request.abort();
  13611. this._request = request(url, L.bind(function(err, json) {
  13612. this._request = null;
  13613. if (err && err.type !== 'abort') {
  13614. util.log('could not load features at ' + url);
  13615. this.fire('error', {error: err});
  13616. } else if (json) {
  13617. this.setGeoJSON(json);
  13618. this.fire('ready');
  13619. }
  13620. }, this));
  13621. return this;
  13622. },
  13623. loadID: function(id) {
  13624. return this.loadURL(format_url('/v4/' + id + '/features.json', this.options.accessToken));
  13625. },
  13626. setFilter: function(_) {
  13627. this.options.filter = _;
  13628. if (this._geojson) {
  13629. this.clearLayers();
  13630. this._initialize(this._geojson);
  13631. }
  13632. return this;
  13633. },
  13634. getFilter: function() {
  13635. return this.options.filter;
  13636. },
  13637. _initialize: function(json) {
  13638. var features = L.Util.isArray(json) ? json : json.features,
  13639. i, len;
  13640. if (features) {
  13641. for (i = 0, len = features.length; i < len; i++) {
  13642. // Only add this if geometry or geometries are set and not null
  13643. if (features[i].geometries || features[i].geometry || features[i].features) {
  13644. this._initialize(features[i]);
  13645. }
  13646. }
  13647. } else if (this.options.filter(json)) {
  13648. var opts = {accessToken: this.options.accessToken},
  13649. pointToLayer = this.options.pointToLayer || function(feature, latlon) {
  13650. return marker.style(feature, latlon, opts);
  13651. },
  13652. layer = L.GeoJSON.geometryToLayer(json, {
  13653. pointToLayer: pointToLayer
  13654. }),
  13655. popupHtml = marker.createPopup(json, this.options.sanitizer),
  13656. style = this.options.style,
  13657. defaultStyle = style === simplestyle.style;
  13658. if (style && 'setStyle' in layer &&
  13659. // if the style method is the simplestyle default, then
  13660. // never style L.Circle or L.CircleMarker because
  13661. // simplestyle has no rules over them, only over geometry
  13662. // primitives directly from GeoJSON
  13663. (!(defaultStyle && (layer instanceof L.Circle ||
  13664. layer instanceof L.CircleMarker)))) {
  13665. if (typeof style === 'function') {
  13666. style = style(json);
  13667. }
  13668. layer.setStyle(style);
  13669. }
  13670. layer.feature = json;
  13671. if (popupHtml) {
  13672. layer.bindPopup(popupHtml, this.options.popupOptions);
  13673. }
  13674. this.addLayer(layer);
  13675. }
  13676. }
  13677. });
  13678. module.exports.FeatureLayer = FeatureLayer;
  13679. module.exports.featureLayer = function(_, options) {
  13680. return new FeatureLayer(_, options);
  13681. };
  13682. },{"./format_url":11,"./marker":24,"./request":25,"./simplestyle":27,"./util":30,"sanitize-caja":5}],10:[function(require,module,exports){
  13683. 'use strict';
  13684. var Feedback = L.Class.extend({
  13685. includes: L.Mixin.Events,
  13686. data: {},
  13687. record: function(data) {
  13688. L.extend(this.data, data);
  13689. this.fire('change');
  13690. }
  13691. });
  13692. module.exports = new Feedback();
  13693. },{}],11:[function(require,module,exports){
  13694. 'use strict';
  13695. var config = require('./config'),
  13696. version = require('../package.json').version;
  13697. module.exports = function(path, accessToken) {
  13698. accessToken = accessToken || L.mapbox.accessToken;
  13699. if (!accessToken && config.REQUIRE_ACCESS_TOKEN) {
  13700. throw new Error('An API access token is required to use Mapbox.js. ' +
  13701. 'See https://www.mapbox.com/mapbox.js/api/v' + version + '/api-access-tokens/');
  13702. }
  13703. var url = (document.location.protocol === 'https:' || config.FORCE_HTTPS) ? config.HTTPS_URL : config.HTTP_URL;
  13704. url = url.replace(/\/v4$/, '');
  13705. url += path;
  13706. if (config.REQUIRE_ACCESS_TOKEN) {
  13707. if (accessToken[0] === 's') {
  13708. throw new Error('Use a public access token (pk.*) with Mapbox.js, not a secret access token (sk.*). ' +
  13709. 'See https://www.mapbox.com/mapbox.js/api/v' + version + '/api-access-tokens/');
  13710. }
  13711. url += url.indexOf('?') !== -1 ? '&access_token=' : '?access_token=';
  13712. url += accessToken;
  13713. }
  13714. return url;
  13715. };
  13716. module.exports.tileJSON = function(urlOrMapID, accessToken) {
  13717. if (urlOrMapID.indexOf('mapbox://styles') === 0) {
  13718. throw new Error('Styles created with Mapbox Studio need to be used with ' +
  13719. 'L.mapbox.styleLayer, not L.mapbox.tileLayer');
  13720. }
  13721. if (urlOrMapID.indexOf('/') !== -1)
  13722. return urlOrMapID;
  13723. var url = module.exports('/v4/' + urlOrMapID + '.json', accessToken);
  13724. // TileJSON requests need a secure flag appended to their URLs so
  13725. // that the server knows to send SSL-ified resource references.
  13726. if (url.indexOf('https') === 0)
  13727. url += '&secure';
  13728. return url;
  13729. };
  13730. module.exports.style = function(styleURL, accessToken) {
  13731. if (styleURL.indexOf('mapbox://styles/') === -1) throw new Error('Incorrectly formatted Mapbox style at ' + styleURL);
  13732. var ownerIDStyle = styleURL.split('mapbox://styles/')[1];
  13733. var url = module.exports('/styles/v1/' + ownerIDStyle, accessToken)
  13734. .replace('http://', 'https://');
  13735. return url;
  13736. };
  13737. },{"../package.json":7,"./config":8}],12:[function(require,module,exports){
  13738. 'use strict';
  13739. var isArray = require('isarray'),
  13740. util = require('./util'),
  13741. format_url = require('./format_url'),
  13742. feedback = require('./feedback'),
  13743. request = require('./request');
  13744. // Low-level geocoding interface - wraps specific API calls and their
  13745. // return values.
  13746. module.exports = function(url, options) {
  13747. if (!options) options = {};
  13748. var geocoder = {};
  13749. util.strict(url, 'string');
  13750. if (url.indexOf('/') === -1) {
  13751. url = format_url('/geocoding/v5/' + url + '/{query}.json', options.accessToken, 5);
  13752. }
  13753. function roundTo(latLng, precision) {
  13754. var mult = Math.pow(10, precision);
  13755. latLng.lat = Math.round(latLng.lat * mult) / mult;
  13756. latLng.lng = Math.round(latLng.lng * mult) / mult;
  13757. return latLng;
  13758. }
  13759. geocoder.getURL = function() {
  13760. return url;
  13761. };
  13762. geocoder.queryURL = function(_) {
  13763. var isObject = !(isArray(_) || typeof _ === 'string'),
  13764. query = isObject ? _.query : _;
  13765. if (isArray(query)) {
  13766. var parts = [];
  13767. for (var i = 0; i < query.length; i++) {
  13768. parts[i] = encodeURIComponent(query[i]);
  13769. }
  13770. query = parts.join(';');
  13771. } else {
  13772. query = encodeURIComponent(query);
  13773. }
  13774. feedback.record({ geocoding: query });
  13775. var url = L.Util.template(geocoder.getURL(), {query: query});
  13776. if (isObject) {
  13777. if (_.types) {
  13778. if (isArray(_.types)) {
  13779. url += '&types=' + _.types.join();
  13780. } else {
  13781. url += '&types=' + _.types;
  13782. }
  13783. }
  13784. if (_.country) {
  13785. if (isArray(_.country)) {
  13786. url += '&country=' + _.country.join();
  13787. } else {
  13788. url += '&country=' + _.country;
  13789. }
  13790. }
  13791. if (_.bbox) {
  13792. if (isArray(_.bbox)) {
  13793. url += '&bbox=' + _.bbox.join();
  13794. } else {
  13795. url += '&bbox=' + _.bbox;
  13796. }
  13797. }
  13798. if (_.proximity) {
  13799. var proximity = roundTo(L.latLng(_.proximity), 3);
  13800. url += '&proximity=' + proximity.lng + ',' + proximity.lat;
  13801. }
  13802. if (typeof _.autocomplete === 'boolean') {
  13803. url += '&autocomplete=' + _.autocomplete;
  13804. }
  13805. }
  13806. return url;
  13807. };
  13808. geocoder.query = function(_, callback) {
  13809. util.strict(callback, 'function');
  13810. request(geocoder.queryURL(_), function(err, json) {
  13811. if (json && (json.length || json.features)) {
  13812. var res = {
  13813. results: json
  13814. };
  13815. if (json.features && json.features.length) {
  13816. res.latlng = [
  13817. json.features[0].center[1],
  13818. json.features[0].center[0]];
  13819. if (json.features[0].bbox) {
  13820. res.bounds = json.features[0].bbox;
  13821. res.lbounds = util.lbounds(res.bounds);
  13822. }
  13823. }
  13824. callback(null, res);
  13825. } else callback(err || true);
  13826. });
  13827. return geocoder;
  13828. };
  13829. // a reverse geocode:
  13830. //
  13831. // geocoder.reverseQuery([80, 20])
  13832. geocoder.reverseQuery = function(_, callback) {
  13833. var q = '';
  13834. // sort through different ways people represent lat and lon pairs
  13835. function normalize(x) {
  13836. var latLng;
  13837. if (x.lat !== undefined && x.lng !== undefined) {
  13838. latLng = L.latLng(x.lat, x.lng);
  13839. } else if (x.lat !== undefined && x.lon !== undefined) {
  13840. latLng = L.latLng(x.lat, x.lon);
  13841. } else {
  13842. latLng = L.latLng(x[1], x[0]);
  13843. }
  13844. latLng = roundTo(latLng, 5);
  13845. return latLng.lng + ',' + latLng.lat;
  13846. }
  13847. if (_.length && _[0].length) {
  13848. for (var i = 0, pts = []; i < _.length; i++) {
  13849. pts.push(normalize(_[i]));
  13850. }
  13851. q = pts.join(';');
  13852. } else {
  13853. q = normalize(_);
  13854. }
  13855. request(geocoder.queryURL(q), function(err, json) {
  13856. callback(err, json);
  13857. });
  13858. return geocoder;
  13859. };
  13860. return geocoder;
  13861. };
  13862. },{"./feedback":10,"./format_url":11,"./request":25,"./util":30,"isarray":2}],13:[function(require,module,exports){
  13863. 'use strict';
  13864. var geocoder = require('./geocoder'),
  13865. util = require('./util');
  13866. var GeocoderControl = L.Control.extend({
  13867. includes: L.Mixin.Events,
  13868. options: {
  13869. proximity: true,
  13870. position: 'topleft',
  13871. pointZoom: 16,
  13872. keepOpen: false,
  13873. autocomplete: false,
  13874. queryOptions: {}
  13875. },
  13876. initialize: function(_, options) {
  13877. L.Util.setOptions(this, options);
  13878. this.setURL(_);
  13879. this._updateSubmit = L.bind(this._updateSubmit, this);
  13880. this._updateAutocomplete = L.bind(this._updateAutocomplete, this);
  13881. this._chooseResult = L.bind(this._chooseResult, this);
  13882. },
  13883. setURL: function(_) {
  13884. this.geocoder = geocoder(_, {
  13885. accessToken: this.options.accessToken
  13886. });
  13887. return this;
  13888. },
  13889. getURL: function() {
  13890. return this.geocoder.getURL();
  13891. },
  13892. setID: function(_) {
  13893. return this.setURL(_);
  13894. },
  13895. setTileJSON: function(_) {
  13896. return this.setURL(_.geocoder);
  13897. },
  13898. _toggle: function(e) {
  13899. if (e) L.DomEvent.stop(e);
  13900. if (L.DomUtil.hasClass(this._container, 'active')) {
  13901. L.DomUtil.removeClass(this._container, 'active');
  13902. this._results.innerHTML = '';
  13903. this._input.blur();
  13904. } else {
  13905. L.DomUtil.addClass(this._container, 'active');
  13906. this._input.focus();
  13907. this._input.select();
  13908. }
  13909. },
  13910. _closeIfOpen: function() {
  13911. if (L.DomUtil.hasClass(this._container, 'active') &&
  13912. !this.options.keepOpen) {
  13913. L.DomUtil.removeClass(this._container, 'active');
  13914. this._results.innerHTML = '';
  13915. this._input.blur();
  13916. }
  13917. },
  13918. onAdd: function(map) {
  13919. var container = L.DomUtil.create('div', 'leaflet-control-mapbox-geocoder leaflet-bar leaflet-control'),
  13920. link = L.DomUtil.create('a', 'leaflet-control-mapbox-geocoder-toggle mapbox-icon mapbox-icon-geocoder', container),
  13921. results = L.DomUtil.create('div', 'leaflet-control-mapbox-geocoder-results', container),
  13922. wrap = L.DomUtil.create('div', 'leaflet-control-mapbox-geocoder-wrap', container),
  13923. form = L.DomUtil.create('form', 'leaflet-control-mapbox-geocoder-form', wrap),
  13924. input = L.DomUtil.create('input', '', form);
  13925. link.href = '#';
  13926. link.innerHTML = '&nbsp;';
  13927. input.type = 'text';
  13928. input.setAttribute('placeholder', 'Search');
  13929. L.DomEvent.addListener(form, 'submit', this._geocode, this);
  13930. L.DomEvent.addListener(input, 'keyup', this._autocomplete, this);
  13931. L.DomEvent.disableClickPropagation(container);
  13932. this._map = map;
  13933. this._results = results;
  13934. this._input = input;
  13935. this._form = form;
  13936. if (this.options.keepOpen) {
  13937. L.DomUtil.addClass(container, 'active');
  13938. } else {
  13939. this._map.on('click', this._closeIfOpen, this);
  13940. L.DomEvent.addListener(link, 'click', this._toggle, this);
  13941. }
  13942. return container;
  13943. },
  13944. _updateSubmit: function(err, resp) {
  13945. L.DomUtil.removeClass(this._container, 'searching');
  13946. this._results.innerHTML = '';
  13947. if (err || !resp) {
  13948. this.fire('error', {error: err});
  13949. } else {
  13950. var features = [];
  13951. if (resp.results && resp.results.features) {
  13952. features = resp.results.features;
  13953. }
  13954. if (features.length === 1) {
  13955. this.fire('autoselect', { feature: features[0] });
  13956. this.fire('found', {results: resp.results});
  13957. this._chooseResult(features[0]);
  13958. this._closeIfOpen();
  13959. } else if (features.length > 1) {
  13960. this.fire('found', {results: resp.results});
  13961. this._displayResults(features);
  13962. } else {
  13963. this.fire('notfound');
  13964. this._displayResults(features);
  13965. }
  13966. }
  13967. },
  13968. _updateAutocomplete: function(err, resp) {
  13969. this._results.innerHTML = '';
  13970. if (err || !resp) {
  13971. this.fire('error', {error: err});
  13972. } else {
  13973. var features = [];
  13974. if (resp.results && resp.results.features) {
  13975. features = resp.results.features;
  13976. }
  13977. if (features.length) {
  13978. this.fire('found', {results: resp.results});
  13979. } else {
  13980. this.fire('notfound');
  13981. }
  13982. this._displayResults(features);
  13983. }
  13984. },
  13985. _displayResults: function(features) {
  13986. for (var i = 0, l = Math.min(features.length, 5); i < l; i++) {
  13987. var feature = features[i];
  13988. var name = feature.place_name;
  13989. if (!name.length) continue;
  13990. var r = L.DomUtil.create('a', '', this._results);
  13991. var text = ('innerText' in r) ? 'innerText' : 'textContent';
  13992. r[text] = name;
  13993. r.setAttribute('title', name);
  13994. r.href = '#';
  13995. (L.bind(function(feature) {
  13996. L.DomEvent.addListener(r, 'click', function(e) {
  13997. this._chooseResult(feature);
  13998. L.DomEvent.stop(e);
  13999. this.fire('select', { feature: feature });
  14000. }, this);
  14001. }, this))(feature);
  14002. }
  14003. if (features.length > 5) {
  14004. var outof = L.DomUtil.create('span', '', this._results);
  14005. outof.innerHTML = 'Top 5 of ' + features.length + ' results';
  14006. }
  14007. },
  14008. _chooseResult: function(result) {
  14009. if (result.bbox) {
  14010. this._map.fitBounds(util.lbounds(result.bbox));
  14011. } else if (result.center) {
  14012. this._map.setView([result.center[1], result.center[0]], (this._map.getZoom() === undefined) ?
  14013. this.options.pointZoom :
  14014. Math.max(this._map.getZoom(), this.options.pointZoom));
  14015. }
  14016. },
  14017. _geocode: function(e) {
  14018. L.DomEvent.preventDefault(e);
  14019. if (this._input.value === '') return this._updateSubmit();
  14020. L.DomUtil.addClass(this._container, 'searching');
  14021. this.geocoder.query(L.Util.extend({
  14022. query: this._input.value,
  14023. proximity: this.options.proximity ? this._map.getCenter() : false
  14024. }, this.options.queryOptions), this._updateSubmit);
  14025. },
  14026. _autocomplete: function() {
  14027. if (!this.options.autocomplete) return;
  14028. if (this._input.value === '') return this._updateAutocomplete();
  14029. this.geocoder.query(L.Util.extend({
  14030. query: this._input.value,
  14031. proximity: this.options.proximity ? this._map.getCenter() : false
  14032. }, this.options.queryOptions), this._updateAutocomplete);
  14033. }
  14034. });
  14035. module.exports.GeocoderControl = GeocoderControl;
  14036. module.exports.geocoderControl = function(_, options) {
  14037. return new GeocoderControl(_, options);
  14038. };
  14039. },{"./geocoder":12,"./util":30}],14:[function(require,module,exports){
  14040. 'use strict';
  14041. function utfDecode(c) {
  14042. if (c >= 93) c--;
  14043. if (c >= 35) c--;
  14044. return c - 32;
  14045. }
  14046. module.exports = function(data) {
  14047. return function(x, y) {
  14048. if (!data) return;
  14049. var idx = utfDecode(data.grid[y].charCodeAt(x)),
  14050. key = data.keys[idx];
  14051. return data.data[key];
  14052. };
  14053. };
  14054. },{}],15:[function(require,module,exports){
  14055. 'use strict';
  14056. var util = require('./util'),
  14057. Mustache = require('mustache');
  14058. var GridControl = L.Control.extend({
  14059. options: {
  14060. pinnable: true,
  14061. follow: false,
  14062. sanitizer: require('sanitize-caja'),
  14063. touchTeaser: true,
  14064. location: true
  14065. },
  14066. _currentContent: '',
  14067. // pinned means that this control is on a feature and the user has likely
  14068. // clicked. pinned will not become false unless the user clicks off
  14069. // of the feature onto another or clicks x
  14070. _pinned: false,
  14071. initialize: function(_, options) {
  14072. L.Util.setOptions(this, options);
  14073. util.strict_instance(_, L.Class, 'L.mapbox.gridLayer');
  14074. this._layer = _;
  14075. },
  14076. setTemplate: function(template) {
  14077. util.strict(template, 'string');
  14078. this.options.template = template;
  14079. return this;
  14080. },
  14081. _template: function(format, data) {
  14082. if (!data) return;
  14083. var template = this.options.template || this._layer.getTileJSON().template;
  14084. if (template) {
  14085. var d = {};
  14086. d['__' + format + '__'] = true;
  14087. return this.options.sanitizer(
  14088. Mustache.to_html(template, L.extend(d, data)));
  14089. }
  14090. },
  14091. // change the content of the tooltip HTML if it has changed, otherwise
  14092. // noop
  14093. _show: function(content, o) {
  14094. if (content === this._currentContent) return;
  14095. this._currentContent = content;
  14096. if (this.options.follow) {
  14097. this._popup.setContent(content)
  14098. .setLatLng(o.latLng);
  14099. if (this._map._popup !== this._popup) this._popup.openOn(this._map);
  14100. } else {
  14101. this._container.style.display = 'block';
  14102. this._contentWrapper.innerHTML = content;
  14103. }
  14104. },
  14105. hide: function() {
  14106. this._pinned = false;
  14107. this._currentContent = '';
  14108. this._map.closePopup();
  14109. this._container.style.display = 'none';
  14110. this._contentWrapper.innerHTML = '';
  14111. L.DomUtil.removeClass(this._container, 'closable');
  14112. return this;
  14113. },
  14114. _mouseover: function(o) {
  14115. if (o.data) {
  14116. L.DomUtil.addClass(this._map._container, 'map-clickable');
  14117. } else {
  14118. L.DomUtil.removeClass(this._map._container, 'map-clickable');
  14119. }
  14120. if (this._pinned) return;
  14121. var content = this._template('teaser', o.data);
  14122. if (content) {
  14123. this._show(content, o);
  14124. } else {
  14125. this.hide();
  14126. }
  14127. },
  14128. _mousemove: function(o) {
  14129. if (this._pinned) return;
  14130. if (!this.options.follow) return;
  14131. this._popup.setLatLng(o.latLng);
  14132. },
  14133. _navigateTo: function(url) {
  14134. window.top.location.href = url;
  14135. },
  14136. _click: function(o) {
  14137. var location_formatted = this._template('location', o.data);
  14138. if (this.options.location && location_formatted &&
  14139. location_formatted.search(/^https?:/) === 0) {
  14140. return this._navigateTo(this._template('location', o.data));
  14141. }
  14142. if (!this.options.pinnable) return;
  14143. var content = this._template('full', o.data);
  14144. if (!content && this.options.touchTeaser && L.Browser.touch) {
  14145. content = this._template('teaser', o.data);
  14146. }
  14147. if (content) {
  14148. L.DomUtil.addClass(this._container, 'closable');
  14149. this._pinned = true;
  14150. this._show(content, o);
  14151. } else if (this._pinned) {
  14152. L.DomUtil.removeClass(this._container, 'closable');
  14153. this._pinned = false;
  14154. this.hide();
  14155. }
  14156. },
  14157. _onPopupClose: function() {
  14158. this._currentContent = null;
  14159. this._pinned = false;
  14160. },
  14161. _createClosebutton: function(container, fn) {
  14162. var link = L.DomUtil.create('a', 'close', container);
  14163. link.innerHTML = 'close';
  14164. link.href = '#';
  14165. link.title = 'close';
  14166. L.DomEvent
  14167. .on(link, 'click', L.DomEvent.stopPropagation)
  14168. .on(link, 'mousedown', L.DomEvent.stopPropagation)
  14169. .on(link, 'dblclick', L.DomEvent.stopPropagation)
  14170. .on(link, 'click', L.DomEvent.preventDefault)
  14171. .on(link, 'click', fn, this);
  14172. return link;
  14173. },
  14174. onAdd: function(map) {
  14175. this._map = map;
  14176. var className = 'leaflet-control-grid map-tooltip',
  14177. container = L.DomUtil.create('div', className),
  14178. contentWrapper = L.DomUtil.create('div', 'map-tooltip-content');
  14179. // hide the container element initially
  14180. container.style.display = 'none';
  14181. this._createClosebutton(container, this.hide);
  14182. container.appendChild(contentWrapper);
  14183. this._contentWrapper = contentWrapper;
  14184. this._popup = new L.Popup({ autoPan: false, closeOnClick: false });
  14185. map.on('popupclose', this._onPopupClose, this);
  14186. L.DomEvent
  14187. .disableClickPropagation(container)
  14188. // allow people to scroll tooltips with mousewheel
  14189. .addListener(container, 'mousewheel', L.DomEvent.stopPropagation);
  14190. this._layer
  14191. .on('mouseover', this._mouseover, this)
  14192. .on('mousemove', this._mousemove, this)
  14193. .on('click', this._click, this);
  14194. return container;
  14195. },
  14196. onRemove: function (map) {
  14197. map.off('popupclose', this._onPopupClose, this);
  14198. this._layer
  14199. .off('mouseover', this._mouseover, this)
  14200. .off('mousemove', this._mousemove, this)
  14201. .off('click', this._click, this);
  14202. }
  14203. });
  14204. module.exports.GridControl = GridControl;
  14205. module.exports.gridControl = function(_, options) {
  14206. return new GridControl(_, options);
  14207. };
  14208. },{"./util":30,"mustache":4,"sanitize-caja":5}],16:[function(require,module,exports){
  14209. 'use strict';
  14210. var util = require('./util'),
  14211. request = require('./request'),
  14212. grid = require('./grid');
  14213. // forked from danzel/L.UTFGrid
  14214. var GridLayer = L.Layer.extend({
  14215. includes: [require('./load_tilejson')],
  14216. options: {
  14217. template: function() { return ''; }
  14218. },
  14219. _mouseOn: null,
  14220. _tilejson: {},
  14221. _cache: {},
  14222. initialize: function(_, options) {
  14223. L.Util.setOptions(this, options);
  14224. this._loadTileJSON(_);
  14225. },
  14226. _setTileJSON: function(json) {
  14227. util.strict(json, 'object');
  14228. L.extend(this.options, {
  14229. grids: json.grids,
  14230. minZoom: json.minzoom,
  14231. maxZoom: json.maxzoom,
  14232. bounds: json.bounds && util.lbounds(json.bounds)
  14233. });
  14234. this._tilejson = json;
  14235. this._cache = {};
  14236. this._update();
  14237. return this;
  14238. },
  14239. getTileJSON: function() {
  14240. return this._tilejson;
  14241. },
  14242. active: function() {
  14243. return !!(this._map && this.options.grids && this.options.grids.length);
  14244. },
  14245. onAdd: function(map) {
  14246. this._map = map;
  14247. this._update();
  14248. this._map
  14249. .on('click', this._click, this)
  14250. .on('mousemove', this._move, this)
  14251. .on('moveend', this._update, this);
  14252. },
  14253. onRemove: function() {
  14254. this._map
  14255. .off('click', this._click, this)
  14256. .off('mousemove', this._move, this)
  14257. .off('moveend', this._update, this);
  14258. },
  14259. getData: function(latlng, callback) {
  14260. if (!this.active()) return;
  14261. var map = this._map,
  14262. point = map.project(latlng.wrap()),
  14263. tileSize = 256,
  14264. resolution = 4,
  14265. x = Math.floor(point.x / tileSize),
  14266. y = Math.floor(point.y / tileSize),
  14267. max = map.options.crs.scale(map.getZoom()) / tileSize;
  14268. x = (x + max) % max;
  14269. y = (y + max) % max;
  14270. this._getTile(map.getZoom(), x, y, function(grid) {
  14271. var gridX = Math.floor((point.x - (x * tileSize)) / resolution),
  14272. gridY = Math.floor((point.y - (y * tileSize)) / resolution);
  14273. callback(grid(gridX, gridY));
  14274. });
  14275. return this;
  14276. },
  14277. _click: function(e) {
  14278. this.getData(e.latlng, L.bind(function(data) {
  14279. this.fire('click', {
  14280. latLng: e.latlng,
  14281. data: data
  14282. });
  14283. }, this));
  14284. },
  14285. _move: function(e) {
  14286. this.getData(e.latlng, L.bind(function(data) {
  14287. if (data !== this._mouseOn) {
  14288. if (this._mouseOn) {
  14289. this.fire('mouseout', {
  14290. latLng: e.latlng,
  14291. data: this._mouseOn
  14292. });
  14293. }
  14294. this.fire('mouseover', {
  14295. latLng: e.latlng,
  14296. data: data
  14297. });
  14298. this._mouseOn = data;
  14299. } else {
  14300. this.fire('mousemove', {
  14301. latLng: e.latlng,
  14302. data: data
  14303. });
  14304. }
  14305. }, this));
  14306. },
  14307. _getTileURL: function(tilePoint) {
  14308. var urls = this.options.grids,
  14309. index = (tilePoint.x + tilePoint.y) % urls.length,
  14310. url = urls[index];
  14311. return L.Util.template(url, tilePoint);
  14312. },
  14313. // Load up all required json grid files
  14314. _update: function() {
  14315. if (!this.active()) return;
  14316. var bounds = this._map.getPixelBounds(),
  14317. z = this._map.getZoom(),
  14318. tileSize = 256;
  14319. if (z > this.options.maxZoom || z < this.options.minZoom) return;
  14320. var tileBounds = L.bounds(
  14321. bounds.min.divideBy(tileSize)._floor(),
  14322. bounds.max.divideBy(tileSize)._floor()),
  14323. max = this._map.options.crs.scale(z) / tileSize;
  14324. for (var x = tileBounds.min.x; x <= tileBounds.max.x; x++) {
  14325. for (var y = tileBounds.min.y; y <= tileBounds.max.y; y++) {
  14326. // x wrapped
  14327. this._getTile(z, ((x % max) + max) % max, ((y % max) + max) % max);
  14328. }
  14329. }
  14330. },
  14331. _getTile: function(z, x, y, callback) {
  14332. var key = z + '_' + x + '_' + y,
  14333. tilePoint = L.point(x, y);
  14334. tilePoint.z = z;
  14335. if (!this._tileShouldBeLoaded(tilePoint)) {
  14336. return;
  14337. }
  14338. if (key in this._cache) {
  14339. if (!callback) return;
  14340. if (typeof this._cache[key] === 'function') {
  14341. callback(this._cache[key]); // Already loaded
  14342. } else {
  14343. this._cache[key].push(callback); // Pending
  14344. }
  14345. return;
  14346. }
  14347. this._cache[key] = [];
  14348. if (callback) {
  14349. this._cache[key].push(callback);
  14350. }
  14351. request(this._getTileURL(tilePoint), L.bind(function(err, json) {
  14352. var callbacks = this._cache[key];
  14353. this._cache[key] = grid(json);
  14354. for (var i = 0; i < callbacks.length; ++i) {
  14355. callbacks[i](this._cache[key]);
  14356. }
  14357. }, this));
  14358. },
  14359. _tileShouldBeLoaded: function(tilePoint) {
  14360. if (tilePoint.z > this.options.maxZoom || tilePoint.z < this.options.minZoom) {
  14361. return false;
  14362. }
  14363. if (this.options.bounds) {
  14364. var tileSize = 256,
  14365. nwPoint = tilePoint.multiplyBy(tileSize),
  14366. sePoint = nwPoint.add(new L.Point(tileSize, tileSize)),
  14367. nw = this._map.unproject(nwPoint),
  14368. se = this._map.unproject(sePoint),
  14369. bounds = new L.LatLngBounds([nw, se]);
  14370. if (!this.options.bounds.intersects(bounds)) {
  14371. return false;
  14372. }
  14373. }
  14374. return true;
  14375. }
  14376. });
  14377. module.exports.GridLayer = GridLayer;
  14378. module.exports.gridLayer = function(_, options) {
  14379. return new GridLayer(_, options);
  14380. };
  14381. },{"./grid":14,"./load_tilejson":20,"./request":25,"./util":30}],17:[function(require,module,exports){
  14382. 'use strict';
  14383. var leaflet = require('./leaflet');
  14384. require('./mapbox');
  14385. module.exports = leaflet;
  14386. },{"./leaflet":18,"./mapbox":22}],18:[function(require,module,exports){
  14387. module.exports = window.L = require('leaflet/dist/leaflet-src');
  14388. },{"leaflet/dist/leaflet-src":3}],19:[function(require,module,exports){
  14389. 'use strict';
  14390. var LegendControl = L.Control.extend({
  14391. options: {
  14392. position: 'bottomright',
  14393. sanitizer: require('sanitize-caja')
  14394. },
  14395. initialize: function(options) {
  14396. L.setOptions(this, options);
  14397. this._legends = {};
  14398. },
  14399. onAdd: function() {
  14400. this._container = L.DomUtil.create('div', 'map-legends wax-legends');
  14401. L.DomEvent.disableClickPropagation(this._container);
  14402. this._update();
  14403. return this._container;
  14404. },
  14405. addLegend: function(text) {
  14406. if (!text) { return this; }
  14407. if (!this._legends[text]) {
  14408. this._legends[text] = 0;
  14409. }
  14410. this._legends[text]++;
  14411. return this._update();
  14412. },
  14413. removeLegend: function(text) {
  14414. if (!text) { return this; }
  14415. if (this._legends[text]) this._legends[text]--;
  14416. return this._update();
  14417. },
  14418. _update: function() {
  14419. if (!this._map) { return this; }
  14420. this._container.innerHTML = '';
  14421. var hide = 'none';
  14422. for (var i in this._legends) {
  14423. if (this._legends.hasOwnProperty(i) && this._legends[i]) {
  14424. var div = L.DomUtil.create('div', 'map-legend wax-legend', this._container);
  14425. div.innerHTML = this.options.sanitizer(i);
  14426. hide = 'block';
  14427. }
  14428. }
  14429. // hide the control entirely unless there is at least one legend;
  14430. // otherwise there will be a small grey blemish on the map.
  14431. this._container.style.display = hide;
  14432. return this;
  14433. }
  14434. });
  14435. module.exports.LegendControl = LegendControl;
  14436. module.exports.legendControl = function(options) {
  14437. return new LegendControl(options);
  14438. };
  14439. },{"sanitize-caja":5}],20:[function(require,module,exports){
  14440. 'use strict';
  14441. var request = require('./request'),
  14442. format_url = require('./format_url'),
  14443. util = require('./util');
  14444. module.exports = {
  14445. _loadTileJSON: function(_) {
  14446. if (typeof _ === 'string') {
  14447. _ = format_url.tileJSON(_, this.options && this.options.accessToken);
  14448. request(_, L.bind(function(err, json) {
  14449. if (err) {
  14450. util.log('could not load TileJSON at ' + _);
  14451. this.fire('error', {error: err});
  14452. } else if (json) {
  14453. this._setTileJSON(json);
  14454. this.fire('ready');
  14455. }
  14456. }, this));
  14457. } else if (_ && typeof _ === 'object') {
  14458. this._setTileJSON(_);
  14459. }
  14460. }
  14461. };
  14462. },{"./format_url":11,"./request":25,"./util":30}],21:[function(require,module,exports){
  14463. 'use strict';
  14464. var tileLayer = require('./tile_layer').tileLayer,
  14465. featureLayer = require('./feature_layer').featureLayer,
  14466. gridLayer = require('./grid_layer').gridLayer,
  14467. gridControl = require('./grid_control').gridControl,
  14468. shareControl = require('./share_control').shareControl,
  14469. legendControl = require('./legend_control').legendControl,
  14470. mapboxLogoControl = require('./mapbox_logo').mapboxLogoControl,
  14471. feedback = require('./feedback');
  14472. function withAccessToken(options, accessToken) {
  14473. if (!accessToken || options.accessToken)
  14474. return options;
  14475. return L.extend({accessToken: accessToken}, options);
  14476. }
  14477. var LMap = L.Map.extend({
  14478. includes: [require('./load_tilejson')],
  14479. options: {
  14480. tileLayer: {},
  14481. featureLayer: {},
  14482. gridLayer: {},
  14483. legendControl: {},
  14484. gridControl: {},
  14485. shareControl: false,
  14486. sanitizer: require('sanitize-caja')
  14487. },
  14488. _tilejson: {},
  14489. initialize: function(element, _, options) {
  14490. L.Map.prototype.initialize.call(this, element,
  14491. L.extend({}, L.Map.prototype.options, options));
  14492. // Disable the default 'Leaflet' text
  14493. if (this.attributionControl) {
  14494. this.attributionControl.setPrefix('');
  14495. var compact = this.options.attributionControl.compact;
  14496. // Set a compact display if map container width is < 640 or
  14497. // compact is set to `true` in attributionControl options.
  14498. if (compact || (compact !== false && this._container.offsetWidth <= 640)) {
  14499. L.DomUtil.addClass(this.attributionControl._container, 'leaflet-compact-attribution');
  14500. }
  14501. if (compact === undefined) {
  14502. this.on('resize', function() {
  14503. if (this._container.offsetWidth > 640) {
  14504. L.DomUtil.removeClass(this.attributionControl._container, 'leaflet-compact-attribution');
  14505. } else {
  14506. L.DomUtil.addClass(this.attributionControl._container, 'leaflet-compact-attribution');
  14507. }
  14508. });
  14509. }
  14510. }
  14511. if (this.options.tileLayer) {
  14512. this.tileLayer = tileLayer(undefined,
  14513. withAccessToken(this.options.tileLayer, this.options.accessToken));
  14514. this.addLayer(this.tileLayer);
  14515. }
  14516. if (this.options.featureLayer) {
  14517. this.featureLayer = featureLayer(undefined,
  14518. withAccessToken(this.options.featureLayer, this.options.accessToken));
  14519. this.addLayer(this.featureLayer);
  14520. }
  14521. if (this.options.gridLayer) {
  14522. this.gridLayer = gridLayer(undefined,
  14523. withAccessToken(this.options.gridLayer, this.options.accessToken));
  14524. this.addLayer(this.gridLayer);
  14525. }
  14526. if (this.options.gridLayer && this.options.gridControl) {
  14527. this.gridControl = gridControl(this.gridLayer, this.options.gridControl);
  14528. this.addControl(this.gridControl);
  14529. }
  14530. if (this.options.legendControl) {
  14531. this.legendControl = legendControl(this.options.legendControl);
  14532. this.addControl(this.legendControl);
  14533. }
  14534. if (this.options.shareControl) {
  14535. this.shareControl = shareControl(undefined,
  14536. withAccessToken(this.options.shareControl, this.options.accessToken));
  14537. this.addControl(this.shareControl);
  14538. }
  14539. this._mapboxLogoControl = mapboxLogoControl(this.options.mapboxLogoControl);
  14540. this.addControl(this._mapboxLogoControl);
  14541. this._loadTileJSON(_);
  14542. this.on('layeradd', this._onLayerAdd, this)
  14543. .on('layerremove', this._onLayerRemove, this)
  14544. .on('moveend', this._updateMapFeedbackLink, this);
  14545. this.whenReady(function () {
  14546. feedback.on('change', this._updateMapFeedbackLink, this);
  14547. });
  14548. this.on('unload', function () {
  14549. feedback.off('change', this._updateMapFeedbackLink, this);
  14550. });
  14551. },
  14552. // use a javascript object of tilejson data to configure this layer
  14553. _setTileJSON: function(_) {
  14554. this._tilejson = _;
  14555. this._initialize(_);
  14556. return this;
  14557. },
  14558. getTileJSON: function() {
  14559. return this._tilejson;
  14560. },
  14561. _initialize: function(json) {
  14562. if (this.tileLayer) {
  14563. this.tileLayer._setTileJSON(json);
  14564. this._updateLayer(this.tileLayer);
  14565. }
  14566. if (this.featureLayer && !this.featureLayer.getGeoJSON() && json.data && json.data[0]) {
  14567. this.featureLayer.loadURL(json.data[0]);
  14568. }
  14569. if (this.gridLayer) {
  14570. this.gridLayer._setTileJSON(json);
  14571. this._updateLayer(this.gridLayer);
  14572. }
  14573. if (this.legendControl && json.legend) {
  14574. this.legendControl.addLegend(json.legend);
  14575. }
  14576. if (this.shareControl) {
  14577. this.shareControl._setTileJSON(json);
  14578. }
  14579. this._mapboxLogoControl._setTileJSON(json);
  14580. if (!this._loaded && json.center) {
  14581. var zoom = this.getZoom() !== undefined ? this.getZoom() : json.center[2],
  14582. center = L.latLng(json.center[1], json.center[0]);
  14583. this.setView(center, zoom);
  14584. }
  14585. },
  14586. _updateMapFeedbackLink: function() {
  14587. if (!this._controlContainer.getElementsByClassName) return;
  14588. var link = this._controlContainer.getElementsByClassName('mapbox-improve-map');
  14589. if (link.length && this._loaded) {
  14590. var center = this.getCenter().wrap();
  14591. var tilejson = this._tilejson || {};
  14592. var id = tilejson.id || '';
  14593. var hash = '#' + id + '/' +
  14594. center.lng.toFixed(3) + '/' +
  14595. center.lat.toFixed(3) + '/' +
  14596. this.getZoom();
  14597. for (var key in feedback.data) {
  14598. hash += '/' + key + '=' + feedback.data[key];
  14599. }
  14600. for (var i = 0; i < link.length; i++) {
  14601. link[i].hash = hash;
  14602. }
  14603. }
  14604. },
  14605. _onLayerAdd: function(e) {
  14606. if ('on' in e.layer) {
  14607. e.layer.on('ready', this._onLayerReady, this);
  14608. }
  14609. window.setTimeout(L.bind(this._updateMapFeedbackLink, this), 0); // Update after attribution control resets the HTML.
  14610. },
  14611. _onLayerRemove: function(e) {
  14612. if ('on' in e.layer) {
  14613. e.layer.off('ready', this._onLayerReady, this);
  14614. }
  14615. window.setTimeout(L.bind(this._updateMapFeedbackLink, this), 0); // Update after attribution control resets the HTML.
  14616. },
  14617. _onLayerReady: function(e) {
  14618. this._updateLayer(e.target);
  14619. },
  14620. _updateLayer: function(layer) {
  14621. if (!layer.options) return;
  14622. if (this.attributionControl && this._loaded && layer.getAttribution) {
  14623. this.attributionControl.addAttribution(layer.getAttribution());
  14624. }
  14625. if (!(L.stamp(layer) in this._zoomBoundLayers) &&
  14626. (layer.options.maxZoom || layer.options.minZoom)) {
  14627. this._zoomBoundLayers[L.stamp(layer)] = layer;
  14628. }
  14629. this._updateMapFeedbackLink();
  14630. this._updateZoomLevels();
  14631. }
  14632. });
  14633. module.exports.Map = LMap;
  14634. module.exports.map = function(element, _, options) {
  14635. return new LMap(element, _, options);
  14636. };
  14637. },{"./feature_layer":9,"./feedback":10,"./grid_control":15,"./grid_layer":16,"./legend_control":19,"./load_tilejson":20,"./mapbox_logo":23,"./share_control":26,"./tile_layer":29,"sanitize-caja":5}],22:[function(require,module,exports){
  14638. 'use strict';
  14639. var geocoderControl = require('./geocoder_control'),
  14640. gridControl = require('./grid_control'),
  14641. featureLayer = require('./feature_layer'),
  14642. legendControl = require('./legend_control'),
  14643. shareControl = require('./share_control'),
  14644. tileLayer = require('./tile_layer'),
  14645. map = require('./map'),
  14646. gridLayer = require('./grid_layer'),
  14647. styleLayer = require('./style_layer');
  14648. L.mapbox = module.exports = {
  14649. VERSION: require('../package.json').version,
  14650. geocoder: require('./geocoder'),
  14651. marker: require('./marker'),
  14652. simplestyle: require('./simplestyle'),
  14653. tileLayer: tileLayer.tileLayer,
  14654. TileLayer: tileLayer.TileLayer,
  14655. styleLayer: styleLayer.styleLayer,
  14656. StyleLayer: styleLayer.StyleLayer,
  14657. shareControl: shareControl.shareControl,
  14658. ShareControl: shareControl.ShareControl,
  14659. legendControl: legendControl.legendControl,
  14660. LegendControl: legendControl.LegendControl,
  14661. geocoderControl: geocoderControl.geocoderControl,
  14662. GeocoderControl: geocoderControl.GeocoderControl,
  14663. gridControl: gridControl.gridControl,
  14664. GridControl: gridControl.GridControl,
  14665. gridLayer: gridLayer.gridLayer,
  14666. GridLayer: gridLayer.GridLayer,
  14667. featureLayer: featureLayer.featureLayer,
  14668. FeatureLayer: featureLayer.FeatureLayer,
  14669. map: map.map,
  14670. Map: map.Map,
  14671. config: require('./config'),
  14672. sanitize: require('sanitize-caja'),
  14673. template: require('mustache').to_html,
  14674. feedback: require('./feedback')
  14675. };
  14676. // Hardcode image path, because Leaflet's autodetection
  14677. // fails, because mapbox.js is not named leaflet.js
  14678. window.L.Icon.Default.imagePath =
  14679. // Detect bad-news protocols like file:// and hardcode
  14680. // to https if they're detected.
  14681. ((document.location.protocol === 'https:' ||
  14682. document.location.protocol === 'http:') ? '' : 'https:') +
  14683. '//api.tiles.mapbox.com/mapbox.js/' + 'v' +
  14684. require('../package.json').version + '/images/';
  14685. },{"../package.json":7,"./config":8,"./feature_layer":9,"./feedback":10,"./geocoder":12,"./geocoder_control":13,"./grid_control":15,"./grid_layer":16,"./legend_control":19,"./map":21,"./marker":24,"./share_control":26,"./simplestyle":27,"./style_layer":28,"./tile_layer":29,"mustache":4,"sanitize-caja":5}],23:[function(require,module,exports){
  14686. 'use strict';
  14687. var MapboxLogoControl = L.Control.extend({
  14688. options: {
  14689. position: 'bottomleft'
  14690. },
  14691. initialize: function(options) {
  14692. L.setOptions(this, options);
  14693. },
  14694. onAdd: function() {
  14695. this._container = L.DomUtil.create('div', 'mapbox-logo');
  14696. return this._container;
  14697. },
  14698. _setTileJSON: function(json) {
  14699. // Check if account referenced by the accessToken
  14700. // is asscociated with the Mapbox Logo
  14701. // as determined by mapbox-maps.
  14702. if (json.mapbox_logo) {
  14703. L.DomUtil.addClass(this._container, 'mapbox-logo-true');
  14704. }
  14705. }
  14706. });
  14707. module.exports.MapboxLogoControl = MapboxLogoControl;
  14708. module.exports.mapboxLogoControl = function(options) {
  14709. return new MapboxLogoControl(options);
  14710. };
  14711. },{}],24:[function(require,module,exports){
  14712. 'use strict';
  14713. var format_url = require('./format_url'),
  14714. util = require('./util'),
  14715. sanitize = require('sanitize-caja');
  14716. // mapbox-related markers functionality
  14717. // provide an icon from mapbox's simple-style spec and hosted markers
  14718. // service
  14719. function icon(fp, options) {
  14720. fp = fp || {};
  14721. var sizes = {
  14722. small: [20, 50],
  14723. medium: [30, 70],
  14724. large: [35, 90]
  14725. },
  14726. size = fp['marker-size'] || 'medium',
  14727. symbol = ('marker-symbol' in fp && fp['marker-symbol'] !== '') ? '-' + fp['marker-symbol'] : '',
  14728. color = (fp['marker-color'] || '7e7e7e').replace('#', '');
  14729. return L.icon({
  14730. iconUrl: format_url('/v4/marker/' +
  14731. 'pin-' + size.charAt(0) + symbol + '+' + color +
  14732. // detect and use retina markers, which are x2 resolution
  14733. (L.Browser.retina ? '@2x' : '') + '.png', options && options.accessToken),
  14734. iconSize: sizes[size],
  14735. iconAnchor: [sizes[size][0] / 2, sizes[size][1] / 2],
  14736. popupAnchor: [0, -sizes[size][1] / 2]
  14737. });
  14738. }
  14739. // a factory that provides markers for Leaflet from Mapbox's
  14740. // [simple-style specification](https://github.com/mapbox/simplestyle-spec)
  14741. // and [Markers API](http://mapbox.com/developers/api/#markers).
  14742. function style(f, latlon, options) {
  14743. return L.marker(latlon, {
  14744. icon: icon(f.properties, options),
  14745. title: util.strip_tags(
  14746. sanitize((f.properties && f.properties.title) || ''))
  14747. });
  14748. }
  14749. // Sanitize and format properties of a GeoJSON Feature object in order
  14750. // to form the HTML string used as the argument for `L.createPopup`
  14751. function createPopup(f, sanitizer) {
  14752. if (!f || !f.properties) return '';
  14753. var popup = '';
  14754. if (f.properties.title) {
  14755. popup += '<div class="marker-title">' + f.properties.title + '</div>';
  14756. }
  14757. if (f.properties.description) {
  14758. popup += '<div class="marker-description">' + f.properties.description + '</div>';
  14759. }
  14760. return (sanitizer || sanitize)(popup);
  14761. }
  14762. module.exports = {
  14763. icon: icon,
  14764. style: style,
  14765. createPopup: createPopup
  14766. };
  14767. },{"./format_url":11,"./util":30,"sanitize-caja":5}],25:[function(require,module,exports){
  14768. 'use strict';
  14769. var corslite = require('corslite'),
  14770. strict = require('./util').strict,
  14771. config = require('./config');
  14772. var protocol = /^(https?:)?(?=\/\/(.|api)\.tiles\.mapbox\.com\/)/;
  14773. module.exports = function(url, callback) {
  14774. strict(url, 'string');
  14775. strict(callback, 'function');
  14776. url = url.replace(protocol, function(match, protocol) {
  14777. if (!('withCredentials' in new window.XMLHttpRequest())) {
  14778. // XDomainRequest in use; doesn't support cross-protocol requests
  14779. return document.location.protocol;
  14780. } else if (protocol === 'https:' || document.location.protocol === 'https:' || config.FORCE_HTTPS) {
  14781. return 'https:';
  14782. } else {
  14783. return 'http:';
  14784. }
  14785. });
  14786. function onload(err, resp) {
  14787. if (!err && resp) {
  14788. resp = JSON.parse(resp.responseText);
  14789. }
  14790. callback(err, resp);
  14791. }
  14792. return corslite(url, onload);
  14793. };
  14794. },{"./config":8,"./util":30,"corslite":1}],26:[function(require,module,exports){
  14795. 'use strict';
  14796. var format_url = require('./format_url');
  14797. var ShareControl = L.Control.extend({
  14798. includes: [require('./load_tilejson')],
  14799. options: {
  14800. position: 'topleft',
  14801. url: ''
  14802. },
  14803. initialize: function(_, options) {
  14804. L.setOptions(this, options);
  14805. this._loadTileJSON(_);
  14806. },
  14807. _setTileJSON: function(json) {
  14808. this._tilejson = json;
  14809. },
  14810. onAdd: function(map) {
  14811. this._map = map;
  14812. var container = L.DomUtil.create('div', 'leaflet-control-mapbox-share leaflet-bar');
  14813. var link = L.DomUtil.create('a', 'mapbox-share mapbox-icon mapbox-icon-share', container);
  14814. link.href = '#';
  14815. this._modal = L.DomUtil.create('div', 'mapbox-modal', this._map._container);
  14816. this._mask = L.DomUtil.create('div', 'mapbox-modal-mask', this._modal);
  14817. this._content = L.DomUtil.create('div', 'mapbox-modal-content', this._modal);
  14818. L.DomEvent.addListener(link, 'click', this._shareClick, this);
  14819. L.DomEvent.disableClickPropagation(container);
  14820. this._map.on('mousedown', this._clickOut, this);
  14821. return container;
  14822. },
  14823. _clickOut: function(e) {
  14824. if (this._sharing) {
  14825. L.DomEvent.preventDefault(e);
  14826. L.DomUtil.removeClass(this._modal, 'active');
  14827. this._content.innerHTML = '';
  14828. this._sharing = null;
  14829. return;
  14830. }
  14831. },
  14832. _shareClick: function(e) {
  14833. L.DomEvent.stop(e);
  14834. if (this._sharing) return this._clickOut(e);
  14835. var tilejson = this._tilejson || this._map._tilejson || {},
  14836. url = encodeURIComponent(this.options.url || tilejson.webpage || window.location),
  14837. name = encodeURIComponent(tilejson.name),
  14838. image = format_url('/v4/' + tilejson.id + '/' + this._map.getCenter().lng + ',' + this._map.getCenter().lat + ',' + this._map.getZoom() + '/600x600.png', this.options.accessToken),
  14839. embed = format_url('/v4/' + tilejson.id + '.html', this.options.accessToken),
  14840. twitterURL = '//twitter.com/intent/tweet?status=' + name + ' ' + url,
  14841. facebookURL = '//www.facebook.com/sharer.php?u=' + url + '&t=' + name,
  14842. pinterestURL = '//www.pinterest.com/pin/create/button/?url=' + url + '&media=' + image + '&description=' + name,
  14843. embedValue = '<iframe width="100%" height="500px" frameBorder="0" src="' + embed + '"></iframe>',
  14844. embedLabel = 'Copy and paste this <strong>HTML code</strong> into documents to embed this map on web pages.';
  14845. function createShareButton(buttonClass, href, socialMediaName) {
  14846. var elem = document.createElement('a');
  14847. elem.setAttribute('class', buttonClass);
  14848. elem.setAttribute('href', href);
  14849. elem.setAttribute('target', '_blank');
  14850. socialMediaName = document.createTextNode(socialMediaName);
  14851. elem.appendChild(socialMediaName);
  14852. return elem;
  14853. }
  14854. L.DomUtil.addClass(this._modal, 'active');
  14855. this._sharing = L.DomUtil.create('div', 'mapbox-modal-body', this._content);
  14856. var twitterButton = createShareButton('mapbox-button mapbox-button-icon mapbox-icon-twitter', twitterURL, 'Twitter');
  14857. var facebookButton = createShareButton('mapbox-button mapbox-button-icon mapbox-icon-facebook', facebookURL, 'Facebook');
  14858. var pinterestButton = createShareButton('mapbox-button mapbox-button-icon mapbox-icon-pinterest', pinterestURL, 'Pinterest');
  14859. var shareHeader = document.createElement('h3');
  14860. var shareText = document.createTextNode('Share this map');
  14861. shareHeader.appendChild(shareText);
  14862. var shareButtons = document.createElement('div');
  14863. shareButtons.setAttribute('class', 'mapbox-share-buttons');
  14864. shareButtons.appendChild(facebookButton);
  14865. shareButtons.appendChild(twitterButton);
  14866. shareButtons.appendChild(pinterestButton);
  14867. this._sharing.appendChild(shareHeader);
  14868. this._sharing.appendChild(shareButtons);
  14869. var input = L.DomUtil.create('input', 'mapbox-embed', this._sharing);
  14870. input.type = 'text';
  14871. input.value = embedValue;
  14872. var label = L.DomUtil.create('label', 'mapbox-embed-description', this._sharing);
  14873. label.innerHTML = embedLabel;
  14874. var close = L.DomUtil.create('a', 'leaflet-popup-close-button', this._sharing);
  14875. close.href = '#';
  14876. L.DomEvent.disableClickPropagation(this._sharing);
  14877. L.DomEvent.addListener(close, 'click', this._clickOut, this);
  14878. L.DomEvent.addListener(input, 'click', function(e) {
  14879. e.target.focus();
  14880. e.target.select();
  14881. });
  14882. }
  14883. });
  14884. module.exports.ShareControl = ShareControl;
  14885. module.exports.shareControl = function(_, options) {
  14886. return new ShareControl(_, options);
  14887. };
  14888. },{"./format_url":11,"./load_tilejson":20}],27:[function(require,module,exports){
  14889. 'use strict';
  14890. // an implementation of the simplestyle spec for polygon and linestring features
  14891. // https://github.com/mapbox/simplestyle-spec
  14892. var defaults = {
  14893. stroke: '#555555',
  14894. 'stroke-width': 2,
  14895. 'stroke-opacity': 1,
  14896. fill: '#555555',
  14897. 'fill-opacity': 0.5
  14898. };
  14899. var mapping = [
  14900. ['stroke', 'color'],
  14901. ['stroke-width', 'weight'],
  14902. ['stroke-opacity', 'opacity'],
  14903. ['fill', 'fillColor'],
  14904. ['fill-opacity', 'fillOpacity']
  14905. ];
  14906. function fallback(a, b) {
  14907. var c = {};
  14908. for (var k in b) {
  14909. if (a[k] === undefined) c[k] = b[k];
  14910. else c[k] = a[k];
  14911. }
  14912. return c;
  14913. }
  14914. function remap(a) {
  14915. var d = {};
  14916. for (var i = 0; i < mapping.length; i++) {
  14917. d[mapping[i][1]] = a[mapping[i][0]];
  14918. }
  14919. return d;
  14920. }
  14921. function style(feature) {
  14922. return remap(fallback(feature.properties || {}, defaults));
  14923. }
  14924. module.exports = {
  14925. style: style,
  14926. defaults: defaults
  14927. };
  14928. },{}],28:[function(require,module,exports){
  14929. 'use strict';
  14930. var util = require('./util');
  14931. var format_url = require('./format_url');
  14932. var request = require('./request');
  14933. var StyleLayer = L.TileLayer.extend({
  14934. options: {
  14935. sanitizer: require('sanitize-caja')
  14936. },
  14937. initialize: function(_, options) {
  14938. L.TileLayer.prototype.initialize.call(this, undefined, L.extend({}, options, {
  14939. tileSize: 512,
  14940. zoomOffset: -1,
  14941. minNativeZoom: 0,
  14942. tms: false
  14943. }));
  14944. this._url = this._formatTileURL(_);
  14945. this._getAttribution(_);
  14946. },
  14947. _getAttribution: function(_) {
  14948. var styleURL = format_url.style(_, this.options && this.options.accessToken);
  14949. request(styleURL, L.bind(function(err, style) {
  14950. if (err) {
  14951. util.log('could not load Mapbox style at ' + styleURL);
  14952. this.fire('error', {error: err});
  14953. }
  14954. var sources = [];
  14955. for (var id in style.sources) {
  14956. var source = style.sources[id].url.split('mapbox://')[1];
  14957. sources.push(source);
  14958. }
  14959. request(format_url.tileJSON(sources.join(), this.options.accessToken), L.bind(function(err, json) {
  14960. if (err) {
  14961. util.log('could not load TileJSON at ' + _);
  14962. this.fire('error', {error: err});
  14963. } else if (json) {
  14964. util.strict(json, 'object');
  14965. this.options.attribution = this.options.sanitizer(json.attribution);
  14966. this._tilejson = json;
  14967. this.fire('ready');
  14968. }
  14969. }, this));
  14970. }, this));
  14971. },
  14972. // disable the setUrl function, which is not available on mapbox tilelayers
  14973. setUrl: null,
  14974. _formatTileURL: function(style) {
  14975. if (typeof style === 'string') {
  14976. if (style.indexOf('mapbox://styles/') === -1) {
  14977. util.log('Incorrectly formatted Mapbox style at ' + style);
  14978. this.fire('error');
  14979. }
  14980. var ownerIDStyle = style.split('mapbox://styles/')[1];
  14981. return format_url('/styles/v1/' + ownerIDStyle + '/tiles/{z}/{x}/{y}{r}', this.options.accessToken);
  14982. } else if (typeof style === 'object') {
  14983. return format_url('/styles/v1/' + style.owner + '/' + style.id + '/tiles/{z}/{x}/{y}{r}', this.options.accessToken);
  14984. }
  14985. }
  14986. });
  14987. module.exports.StyleLayer = StyleLayer;
  14988. module.exports.styleLayer = function(_, options) {
  14989. return new StyleLayer(_, options);
  14990. };
  14991. },{"./format_url":11,"./request":25,"./util":30,"sanitize-caja":5}],29:[function(require,module,exports){
  14992. 'use strict';
  14993. var util = require('./util');
  14994. var formatPattern = /\.((?:png|jpg)\d*)(?=$|\?)/;
  14995. var TileLayer = L.TileLayer.extend({
  14996. includes: [require('./load_tilejson')],
  14997. options: {
  14998. sanitizer: require('sanitize-caja')
  14999. },
  15000. // http://mapbox.com/developers/api/#image_quality
  15001. formats: [
  15002. 'png', 'jpg',
  15003. // PNG
  15004. 'png32', 'png64', 'png128', 'png256',
  15005. // JPG
  15006. 'jpg70', 'jpg80', 'jpg90'],
  15007. scalePrefix: '@2x.',
  15008. initialize: function(_, options) {
  15009. L.TileLayer.prototype.initialize.call(this, undefined, options);
  15010. this._tilejson = {};
  15011. if (options && options.format) {
  15012. util.strict_oneof(options.format, this.formats);
  15013. }
  15014. this._loadTileJSON(_);
  15015. },
  15016. setFormat: function(_) {
  15017. util.strict(_, 'string');
  15018. this.options.format = _;
  15019. this.redraw();
  15020. return this;
  15021. },
  15022. // disable the setUrl function, which is not available on mapbox tilelayers
  15023. setUrl: null,
  15024. _setTileJSON: function(json) {
  15025. util.strict(json, 'object');
  15026. if (!this.options.format) {
  15027. var match = json.tiles[0].match(formatPattern);
  15028. if (match) {
  15029. this.options.format = match[1];
  15030. }
  15031. }
  15032. L.extend(this.options, {
  15033. tiles: json.tiles,
  15034. attribution: this.options.sanitizer(json.attribution),
  15035. minZoom: json.minzoom || 0,
  15036. maxZoom: json.maxzoom || 18,
  15037. tms: json.scheme === 'tms',
  15038. bounds: json.bounds && util.lbounds(json.bounds)
  15039. });
  15040. this._tilejson = json;
  15041. this.redraw();
  15042. return this;
  15043. },
  15044. getTileJSON: function() {
  15045. return this._tilejson;
  15046. },
  15047. // this is an exception to mapbox.js naming rules because it's called
  15048. // by `L.map`
  15049. getTileUrl: function(tilePoint) {
  15050. var tiles = this.options.tiles,
  15051. index = Math.floor(Math.abs(tilePoint.x + tilePoint.y) % tiles.length),
  15052. url = tiles[index];
  15053. var templated = L.Util.template(url, tilePoint);
  15054. if (!templated || !this.options.format) {
  15055. return templated;
  15056. } else {
  15057. return templated.replace(formatPattern,
  15058. (L.Browser.retina ? this.scalePrefix : '.') + this.options.format);
  15059. }
  15060. },
  15061. // TileJSON.TileLayers are added to the map immediately, so that they get
  15062. // the desired z-index, but do not update until the TileJSON has been loaded.
  15063. _update: function() {
  15064. if (this.options.tiles) {
  15065. L.TileLayer.prototype._update.call(this);
  15066. }
  15067. }
  15068. });
  15069. module.exports.TileLayer = TileLayer;
  15070. module.exports.tileLayer = function(_, options) {
  15071. return new TileLayer(_, options);
  15072. };
  15073. },{"./load_tilejson":20,"./util":30,"sanitize-caja":5}],30:[function(require,module,exports){
  15074. 'use strict';
  15075. function contains(item, list) {
  15076. if (!list || !list.length) return false;
  15077. for (var i = 0; i < list.length; i++) {
  15078. if (list[i] === item) return true;
  15079. }
  15080. return false;
  15081. }
  15082. module.exports = {
  15083. idUrl: function(_, t) {
  15084. if (_.indexOf('/') === -1) t.loadID(_);
  15085. else t.loadURL(_);
  15086. },
  15087. log: function(_) {
  15088. if (typeof console === 'object' &&
  15089. typeof console.error === 'function') {
  15090. console.error(_);
  15091. }
  15092. },
  15093. strict: function(_, type) {
  15094. if (typeof _ !== type) {
  15095. throw new Error('Invalid argument: ' + type + ' expected');
  15096. }
  15097. },
  15098. strict_instance: function(_, klass, name) {
  15099. if (!(_ instanceof klass)) {
  15100. throw new Error('Invalid argument: ' + name + ' expected');
  15101. }
  15102. },
  15103. strict_oneof: function(_, values) {
  15104. if (!contains(_, values)) {
  15105. throw new Error('Invalid argument: ' + _ + ' given, valid values are ' +
  15106. values.join(', '));
  15107. }
  15108. },
  15109. strip_tags: function(_) {
  15110. return _.replace(/<[^<]+>/g, '');
  15111. },
  15112. lbounds: function(_) {
  15113. // leaflet-compatible bounds, since leaflet does not do geojson
  15114. return new L.LatLngBounds([[_[1], _[0]], [_[3], _[2]]]);
  15115. }
  15116. };
  15117. },{}]},{},[17])
  15118. //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIm5vZGVfbW9kdWxlcy9icm93c2VyLXBhY2svX3ByZWx1ZGUuanMiLCJub2RlX21vZHVsZXMvY29yc2xpdGUvY29yc2xpdGUuanMiLCJub2RlX21vZHVsZXMvaXNhcnJheS9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9sZWFmbGV0L2Rpc3QvbGVhZmxldC1zcmMuanMiLCJub2RlX21vZHVsZXMvbXVzdGFjaGUvbXVzdGFjaGUuanMiLCJub2RlX21vZHVsZXMvc2FuaXRpemUtY2FqYS9pbmRleC5qcyIsIm5vZGVfbW9kdWxlcy9zYW5pdGl6ZS1jYWphL3Nhbml0aXplci1idW5kbGUuanMiLCJwYWNrYWdlLmpzb24iLCJzcmMvY29uZmlnLmpzIiwic3JjL2ZlYXR1cmVfbGF5ZXIuanMiLCJzcmMvZmVlZGJhY2suanMiLCJzcmMvZm9ybWF0X3VybC5qcyIsInNyYy9nZW9jb2Rlci5qcyIsInNyYy9nZW9jb2Rlcl9jb250cm9sLmpzIiwic3JjL2dyaWQuanMiLCJzcmMvZ3JpZF9jb250cm9sLmpzIiwic3JjL2dyaWRfbGF5ZXIuanMiLCJzcmMvaW5kZXguanMiLCJzcmMvbGVhZmxldC5qcyIsInNyYy9sZWdlbmRfY29udHJvbC5qcyIsInNyYy9sb2FkX3RpbGVqc29uLmpzIiwic3JjL21hcC5qcyIsInNyYy9tYXBib3guanMiLCJzcmMvbWFwYm94X2xvZ28uanMiLCJzcmMvbWFya2VyLmpzIiwic3JjL3JlcXVlc3QuanMiLCJzcmMvc2hhcmVfY29udHJvbC5qcyIsInNyYy9zaW1wbGVzdHlsZS5qcyIsInNyYy9zdHlsZV9sYXllci5qcyIsInNyYy90aWxlX2xheWVyLmpzIiwic3JjL3V0aWwuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3RkE7QUFDQTtBQUNBO0FBQ0E7O0FDSEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2ozWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbEJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvNEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDakRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqSUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RKQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdE1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxTkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNQQTtBQUNBOztBQ0RBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDbkVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMU5BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25EQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaENBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM3Q0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6RUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDdEdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBIiwiZmlsZSI6ImdlbmVyYXRlZC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzQ29udGVudCI6WyIoZnVuY3Rpb24gZSh0LG4scil7ZnVuY3Rpb24gcyhvLHUpe2lmKCFuW29dKXtpZighdFtvXSl7dmFyIGE9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtpZighdSYmYSlyZXR1cm4gYShvLCEwKTtpZihpKXJldHVybiBpKG8sITApO3ZhciBmPW5ldyBFcnJvcihcIkNhbm5vdCBmaW5kIG1vZHVsZSAnXCIrbytcIidcIik7dGhyb3cgZi5jb2RlPVwiTU9EVUxFX05PVF9GT1VORFwiLGZ9dmFyIGw9bltvXT17ZXhwb3J0czp7fX07dFtvXVswXS5jYWxsKGwuZXhwb3J0cyxmdW5jdGlvbihlKXt2YXIgbj10W29dWzFdW2VdO3JldHVybiBzKG4/bjplKX0sbCxsLmV4cG9ydHMsZSx0LG4scil9cmV0dXJuIG5bb10uZXhwb3J0c312YXIgaT10eXBlb2YgcmVxdWlyZT09XCJmdW5jdGlvblwiJiZyZXF1aXJlO2Zvcih2YXIgbz0wO288ci5sZW5ndGg7bysrKXMocltvXSk7cmV0dXJuIHN9KSIsImZ1bmN0aW9uIGNvcnNsaXRlKHVybCwgY2FsbGJhY2ssIGNvcnMpIHtcbiAgICB2YXIgc2VudCA9IGZhbHNlO1xuXG4gICAgaWYgKHR5cGVvZiB3aW5kb3cuWE1MSHR0cFJlcXVlc3QgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHJldHVybiBjYWxsYmFjayhFcnJvcignQnJvd3NlciBub3Qgc3VwcG9ydGVkJykpO1xuICAgIH1cblxuICAgIGlmICh0eXBlb2YgY29ycyA9PT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgdmFyIG0gPSB1cmwubWF0Y2goL15cXHMqaHR0cHM/OlxcL1xcL1teXFwvXSovKTtcbiAgICAgICAgY29ycyA9IG0gJiYgKG1bMF0gIT09IGxvY2F0aW9uLnByb3RvY29sICsgJy8vJyArIGxvY2F0aW9uLmRvbWFpbiArXG4gICAgICAgICAgICAgICAgKGxvY2F0aW9uLnBvcnQgPyAnOicgKyBsb2NhdGlvbi5wb3J0IDogJycpKTtcbiAgICB9XG5cbiAgICB2YXIgeCA9IG5ldyB3aW5kb3cuWE1MSHR0cFJlcXVlc3QoKTtcblxuICAgIGZ1bmN0aW9uIGlzU3VjY2Vzc2Z1bChzdGF0dXMpIHtcbiAgICAgICAgcmV0dXJuIHN0YXR1cyA+PSAyMDAgJiYgc3RhdHVzIDwgMzAwIHx8IHN0YXR1cyA9PT0gMzA0O1xuICAgIH1cblxuICAgIGlmIChjb3JzICYmICEoJ3dpdGhDcmVkZW50aWFscycgaW4geCkpIHtcbiAgICAgICAgLy8gSUU4LTlcbiAgICAgICAgeCA9IG5ldyB3aW5kb3cuWERvbWFpblJlcXVlc3QoKTtcblxuICAgICAgICAvLyBFbnN1cmUgY2FsbGJhY2sgaXMgbmV2ZXIgY2FsbGVkIHN5bmNocm9ub3VzbHksIGkuZS4sIGJlZm9yZVxuICAgICAgICAvLyB4LnNlbmQoKSByZXR1cm5zICh0aGlzIGhhcyBiZWVuIG9ic2VydmVkIGluIHRoZSB3aWxkKS5cbiAgICAgICAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9tYXBib3gvbWFwYm94LmpzL2lzc3Vlcy80NzJcbiAgICAgICAgdmFyIG9yaWdpbmFsID0gY2FsbGJhY2s7XG4gICAgICAgIGNhbGxiYWNrID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBpZiAoc2VudCkge1xuICAgICAgICAgICAgICAgIG9yaWdpbmFsLmFwcGx5KHRoaXMsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHZhciB0aGF0ID0gdGhpcywgYXJncyA9IGFyZ3VtZW50cztcbiAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICBvcmlnaW5hbC5hcHBseSh0aGF0LCBhcmdzKTtcbiAgICAgICAgICAgICAgICB9LCAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH1cblxuICAgIGZ1bmN0aW9uIGxvYWRlZCgpIHtcbiAgICAgICAgaWYgKFxuICAgICAgICAgICAgLy8gWERvbWFpblJlcXVlc3RcbiAgICAgICAgICAgIHguc3RhdHVzID09PSB1bmRlZmluZWQgfHxcbiAgICAgICAgICAgIC8vIG1vZGVybiBicm93c2Vyc1xuICAgICAgICAgICAgaXNTdWNjZXNzZnVsKHguc3RhdHVzKSkgY2FsbGJhY2suY2FsbCh4LCBudWxsLCB4KTtcbiAgICAgICAgZWxzZSBjYWxsYmFjay5jYWxsKHgsIHgsIG51bGwpO1xuICAgIH1cblxuICAgIC8vIEJvdGggYG9ucmVhZHlzdGF0ZWNoYW5nZWAgYW5kIGBvbmxvYWRgIGNhbiBmaXJlLiBgb25yZWFkeXN0YXRlY2hhbmdlYFxuICAgIC8vIGhhcyBbYmVlbiBzdXBwb3J0ZWQgZm9yIGxvbmdlcl0oaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL2EvOTE4MTUwOC8yMjkwMDEpLlxuICAgIGlmICgnb25sb2FkJyBpbiB4KSB7XG4gICAgICAgIHgub25sb2FkID0gbG9hZGVkO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHgub25yZWFkeXN0YXRlY2hhbmdlID0gZnVuY3Rpb24gcmVhZHlzdGF0ZSgpIHtcbiAgICAgICAgICAgIGlmICh4LnJlYWR5U3RhdGUgPT09IDQpIHtcbiAgICAgICAgICAgICAgICBsb2FkZWQoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBDYWxsIHRoZSBjYWxsYmFjayB3aXRoIHRoZSBYTUxIdHRwUmVxdWVzdCBvYmplY3QgYXMgYW4gZXJyb3IgYW5kIHByZXZlbnRcbiAgICAvLyBpdCBmcm9tIGV2ZXIgYmVpbmcgY2FsbGVkIGFnYWluIGJ5IHJlYXNzaWduaW5nIGl0IHRvIGBub29wYFxuICAgIHgub25lcnJvciA9IGZ1bmN0aW9uIGVycm9yKGV2dCkge1xuICAgICAgICAvLyBYRG9tYWluUmVxdWVzdCBwcm92aWRlcyBubyBldnQgcGFyYW1ldGVyXG4gICAgICAgIGNhbGxiYWNrLmNhbGwodGhpcywgZXZ0IHx8IHRydWUsIG51bGwpO1xuICAgICAgICBjYWxsYmFjayA9IGZ1bmN0aW9uKCkgeyB9O1xuICAgIH07XG5cbiAgICAvLyBJRTkgbXVzdCBoYXZlIG9ucHJvZ3Jlc3MgYmUgc2V0IHRvIGEgdW5pcXVlIGZ1bmN0aW9uLlxuICAgIHgub25wcm9ncmVzcyA9IGZ1bmN0aW9uKCkgeyB9O1xuXG4gICAgeC5vbnRpbWVvdXQgPSBmdW5jdGlvbihldnQpIHtcbiAgICAgICAgY2FsbGJhY2suY2FsbCh0aGlzLCBldnQsIG51bGwpO1xuICAgICAgICBjYWxsYmFjayA9IGZ1bmN0aW9uKCkgeyB9O1xuICAgIH07XG5cbiAgICB4Lm9uYWJvcnQgPSBmdW5jdGlvbihldnQpIHtcbiAgICAgICAgY2FsbGJhY2suY2FsbCh0aGlzLCBldnQsIG51bGwpO1xuICAgICAgICBjYWxsYmFjayA9IGZ1bmN0aW9uKCkgeyB9O1xuICAgIH07XG5cbiAgICAvLyBHRVQgaXMgdGhlIG9ubHkgc3VwcG9ydGVkIEhUVFAgVmVyYiBieSBYRG9tYWluUmVxdWVzdCBhbmQgaXMgdGhlXG4gICAgLy8gb25seSBvbmUgc3VwcG9ydGVkIGhlcmUuXG4gICAgeC5vcGVuKCdHRVQnLCB1cmwsIHRydWUpO1xuXG4gICAgLy8gU2VuZCB0aGUgcmVxdWVzdC4gU2VuZGluZyBkYXRhIGlzIG5vdCBzdXBwb3J0ZWQuXG4gICAgeC5zZW5kKG51bGwpO1xuICAgIHNlbnQgPSB0cnVlO1xuXG4gICAgcmV0dXJuIHg7XG59XG5cbmlmICh0eXBlb2YgbW9kdWxlICE9PSAndW5kZWZpbmVkJykgbW9kdWxlLmV4cG9ydHMgPSBjb3JzbGl0ZTtcbiIsIm1vZHVsZS5leHBvcnRzID0gQXJyYXkuaXNBcnJheSB8fCBmdW5jdGlvbiAoYXJyKSB7XG4gIHJldHVybiBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nLmNhbGwoYXJyKSA9PSAnW29iamVjdCBBcnJheV0nO1xufTtcbiIsIi8qXG4gTGVhZmxldCAxLjAuMiwgYSBKUyBsaWJyYXJ5IGZvciBpbnRlcmFjdGl2ZSBtYXBzLiBodHRwOi8vbGVhZmxldGpzLmNvbVxuIChjKSAyMDEwLTIwMTYgVmxhZGltaXIgQWdhZm9ua2luLCAoYykgMjAxMC0yMDExIENsb3VkTWFkZVxuKi9cbihmdW5jdGlvbiAod2luZG93LCBkb2N1bWVudCwgdW5kZWZpbmVkKSB7XHJcbnZhciBMID0ge1xyXG5cdHZlcnNpb246IFwiMS4wLjJcIlxyXG59O1xyXG5cclxuZnVuY3Rpb24gZXhwb3NlKCkge1xyXG5cdHZhciBvbGRMID0gd2luZG93Lkw7XHJcblxyXG5cdEwubm9Db25mbGljdCA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdHdpbmRvdy5MID0gb2xkTDtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH07XHJcblxyXG5cdHdpbmRvdy5MID0gTDtcclxufVxyXG5cclxuLy8gZGVmaW5lIExlYWZsZXQgZm9yIE5vZGUgbW9kdWxlIHBhdHRlcm4gbG9hZGVycywgaW5jbHVkaW5nIEJyb3dzZXJpZnlcclxuaWYgKHR5cGVvZiBtb2R1bGUgPT09ICdvYmplY3QnICYmIHR5cGVvZiBtb2R1bGUuZXhwb3J0cyA9PT0gJ29iamVjdCcpIHtcclxuXHRtb2R1bGUuZXhwb3J0cyA9IEw7XHJcblxyXG4vLyBkZWZpbmUgTGVhZmxldCBhcyBhbiBBTUQgbW9kdWxlXHJcbn0gZWxzZSBpZiAodHlwZW9mIGRlZmluZSA9PT0gJ2Z1bmN0aW9uJyAmJiBkZWZpbmUuYW1kKSB7XHJcblx0ZGVmaW5lKEwpO1xyXG59XHJcblxyXG4vLyBkZWZpbmUgTGVhZmxldCBhcyBhIGdsb2JhbCBMIHZhcmlhYmxlLCBzYXZpbmcgdGhlIG9yaWdpbmFsIEwgdG8gcmVzdG9yZSBsYXRlciBpZiBuZWVkZWRcclxuaWYgKHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnKSB7XHJcblx0ZXhwb3NlKCk7XHJcbn1cclxuXG5cblxuLypcclxuICogQG5hbWVzcGFjZSBVdGlsXHJcbiAqXHJcbiAqIFZhcmlvdXMgdXRpbGl0eSBmdW5jdGlvbnMsIHVzZWQgYnkgTGVhZmxldCBpbnRlcm5hbGx5LlxyXG4gKi9cclxuXHJcbkwuVXRpbCA9IHtcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIGV4dGVuZChkZXN0OiBPYmplY3QsIHNyYz86IE9iamVjdCk6IE9iamVjdFxyXG5cdC8vIE1lcmdlcyB0aGUgcHJvcGVydGllcyBvZiB0aGUgYHNyY2Agb2JqZWN0IChvciBtdWx0aXBsZSBvYmplY3RzKSBpbnRvIGBkZXN0YCBvYmplY3QgYW5kIHJldHVybnMgdGhlIGxhdHRlci4gSGFzIGFuIGBMLmV4dGVuZGAgc2hvcnRjdXQuXHJcblx0ZXh0ZW5kOiBmdW5jdGlvbiAoZGVzdCkge1xyXG5cdFx0dmFyIGksIGosIGxlbiwgc3JjO1xyXG5cclxuXHRcdGZvciAoaiA9IDEsIGxlbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGogPCBsZW47IGorKykge1xyXG5cdFx0XHRzcmMgPSBhcmd1bWVudHNbal07XHJcblx0XHRcdGZvciAoaSBpbiBzcmMpIHtcclxuXHRcdFx0XHRkZXN0W2ldID0gc3JjW2ldO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gZGVzdDtcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gY3JlYXRlKHByb3RvOiBPYmplY3QsIHByb3BlcnRpZXM/OiBPYmplY3QpOiBPYmplY3RcclxuXHQvLyBDb21wYXRpYmlsaXR5IHBvbHlmaWxsIGZvciBbT2JqZWN0LmNyZWF0ZV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvT2JqZWN0L2NyZWF0ZSlcclxuXHRjcmVhdGU6IE9iamVjdC5jcmVhdGUgfHwgKGZ1bmN0aW9uICgpIHtcclxuXHRcdGZ1bmN0aW9uIEYoKSB7fVxyXG5cdFx0cmV0dXJuIGZ1bmN0aW9uIChwcm90bykge1xyXG5cdFx0XHRGLnByb3RvdHlwZSA9IHByb3RvO1xyXG5cdFx0XHRyZXR1cm4gbmV3IEYoKTtcclxuXHRcdH07XHJcblx0fSkoKSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIGJpbmQoZm46IEZ1bmN0aW9uLCDigKYpOiBGdW5jdGlvblxyXG5cdC8vIFJldHVybnMgYSBuZXcgZnVuY3Rpb24gYm91bmQgdG8gdGhlIGFyZ3VtZW50cyBwYXNzZWQsIGxpa2UgW0Z1bmN0aW9uLnByb3RvdHlwZS5iaW5kXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9GdW5jdGlvbi9iaW5kKS5cclxuXHQvLyBIYXMgYSBgTC5iaW5kKClgIHNob3J0Y3V0LlxyXG5cdGJpbmQ6IGZ1bmN0aW9uIChmbiwgb2JqKSB7XHJcblx0XHR2YXIgc2xpY2UgPSBBcnJheS5wcm90b3R5cGUuc2xpY2U7XHJcblxyXG5cdFx0aWYgKGZuLmJpbmQpIHtcclxuXHRcdFx0cmV0dXJuIGZuLmJpbmQuYXBwbHkoZm4sIHNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSk7XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIGFyZ3MgPSBzbGljZS5jYWxsKGFyZ3VtZW50cywgMik7XHJcblxyXG5cdFx0cmV0dXJuIGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0cmV0dXJuIGZuLmFwcGx5KG9iaiwgYXJncy5sZW5ndGggPyBhcmdzLmNvbmNhdChzbGljZS5jYWxsKGFyZ3VtZW50cykpIDogYXJndW1lbnRzKTtcclxuXHRcdH07XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHN0YW1wKG9iajogT2JqZWN0KTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgdW5pcXVlIElEIG9mIGFuIG9iamVjdCwgYXNzaWdpbmcgaXQgb25lIGlmIGl0IGRvZXNuJ3QgaGF2ZSBpdC5cclxuXHRzdGFtcDogZnVuY3Rpb24gKG9iaikge1xyXG5cdFx0Lyplc2xpbnQtZGlzYWJsZSAqL1xyXG5cdFx0b2JqLl9sZWFmbGV0X2lkID0gb2JqLl9sZWFmbGV0X2lkIHx8ICsrTC5VdGlsLmxhc3RJZDtcclxuXHRcdHJldHVybiBvYmouX2xlYWZsZXRfaWQ7XHJcblx0XHQvKmVzbGludC1lbmFibGUgKi9cclxuXHR9LFxyXG5cclxuXHQvLyBAcHJvcGVydHkgbGFzdElkOiBOdW1iZXJcclxuXHQvLyBMYXN0IHVuaXF1ZSBJRCB1c2VkIGJ5IFtgc3RhbXAoKWBdKCN1dGlsLXN0YW1wKVxyXG5cdGxhc3RJZDogMCxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHRocm90dGxlKGZuOiBGdW5jdGlvbiwgdGltZTogTnVtYmVyLCBjb250ZXh0OiBPYmplY3QpOiBGdW5jdGlvblxyXG5cdC8vIFJldHVybnMgYSBmdW5jdGlvbiB3aGljaCBleGVjdXRlcyBmdW5jdGlvbiBgZm5gIHdpdGggdGhlIGdpdmVuIHNjb3BlIGBjb250ZXh0YFxyXG5cdC8vIChzbyB0aGF0IHRoZSBgdGhpc2Aga2V5d29yZCByZWZlcnMgdG8gYGNvbnRleHRgIGluc2lkZSBgZm5gJ3MgY29kZSkuIFRoZSBmdW5jdGlvblxyXG5cdC8vIGBmbmAgd2lsbCBiZSBjYWxsZWQgbm8gbW9yZSB0aGFuIG9uZSB0aW1lIHBlciBnaXZlbiBhbW91bnQgb2YgYHRpbWVgLiBUaGUgYXJndW1lbnRzXHJcblx0Ly8gcmVjZWl2ZWQgYnkgdGhlIGJvdW5kIGZ1bmN0aW9uIHdpbGwgYmUgYW55IGFyZ3VtZW50cyBwYXNzZWQgd2hlbiBiaW5kaW5nIHRoZVxyXG5cdC8vIGZ1bmN0aW9uLCBmb2xsb3dlZCBieSBhbnkgYXJndW1lbnRzIHBhc3NlZCB3aGVuIGludm9raW5nIHRoZSBib3VuZCBmdW5jdGlvbi5cclxuXHQvLyBIYXMgYW4gYEwuYmluZGAgc2hvcnRjdXQuXHJcblx0dGhyb3R0bGU6IGZ1bmN0aW9uIChmbiwgdGltZSwgY29udGV4dCkge1xyXG5cdFx0dmFyIGxvY2ssIGFyZ3MsIHdyYXBwZXJGbiwgbGF0ZXI7XHJcblxyXG5cdFx0bGF0ZXIgPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdC8vIHJlc2V0IGxvY2sgYW5kIGNhbGwgaWYgcXVldWVkXHJcblx0XHRcdGxvY2sgPSBmYWxzZTtcclxuXHRcdFx0aWYgKGFyZ3MpIHtcclxuXHRcdFx0XHR3cmFwcGVyRm4uYXBwbHkoY29udGV4dCwgYXJncyk7XHJcblx0XHRcdFx0YXJncyA9IGZhbHNlO1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cclxuXHRcdHdyYXBwZXJGbiA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0aWYgKGxvY2spIHtcclxuXHRcdFx0XHQvLyBjYWxsZWQgdG9vIHNvb24sIHF1ZXVlIHRvIGNhbGwgbGF0ZXJcclxuXHRcdFx0XHRhcmdzID0gYXJndW1lbnRzO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHQvLyBjYWxsIGFuZCBsb2NrIHVudGlsIGxhdGVyXHJcblx0XHRcdFx0Zm4uYXBwbHkoY29udGV4dCwgYXJndW1lbnRzKTtcclxuXHRcdFx0XHRzZXRUaW1lb3V0KGxhdGVyLCB0aW1lKTtcclxuXHRcdFx0XHRsb2NrID0gdHJ1ZTtcclxuXHRcdFx0fVxyXG5cdFx0fTtcclxuXHJcblx0XHRyZXR1cm4gd3JhcHBlckZuO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiB3cmFwTnVtKG51bTogTnVtYmVyLCByYW5nZTogTnVtYmVyW10sIGluY2x1ZGVNYXg/OiBCb29sZWFuKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgbnVtYmVyIGBudW1gIG1vZHVsbyBgcmFuZ2VgIGluIHN1Y2ggYSB3YXkgc28gaXQgbGllcyB3aXRoaW5cclxuXHQvLyBgcmFuZ2VbMF1gIGFuZCBgcmFuZ2VbMV1gLiBUaGUgcmV0dXJuZWQgdmFsdWUgd2lsbCBiZSBhbHdheXMgc21hbGxlciB0aGFuXHJcblx0Ly8gYHJhbmdlWzFdYCB1bmxlc3MgYGluY2x1ZGVNYXhgIGlzIHNldCB0byBgdHJ1ZWAuXHJcblx0d3JhcE51bTogZnVuY3Rpb24gKHgsIHJhbmdlLCBpbmNsdWRlTWF4KSB7XHJcblx0XHR2YXIgbWF4ID0gcmFuZ2VbMV0sXHJcblx0XHQgICAgbWluID0gcmFuZ2VbMF0sXHJcblx0XHQgICAgZCA9IG1heCAtIG1pbjtcclxuXHRcdHJldHVybiB4ID09PSBtYXggJiYgaW5jbHVkZU1heCA/IHggOiAoKHggLSBtaW4pICUgZCArIGQpICUgZCArIG1pbjtcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gZmFsc2VGbigpOiBGdW5jdGlvblxyXG5cdC8vIFJldHVybnMgYSBmdW5jdGlvbiB3aGljaCBhbHdheXMgcmV0dXJucyBgZmFsc2VgLlxyXG5cdGZhbHNlRm46IGZ1bmN0aW9uICgpIHsgcmV0dXJuIGZhbHNlOyB9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gZm9ybWF0TnVtKG51bTogTnVtYmVyLCBkaWdpdHM/OiBOdW1iZXIpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBudW1iZXIgYG51bWAgcm91bmRlZCB0byBgZGlnaXRzYCBkZWNpbWFscywgb3IgdG8gNSBkZWNpbWFscyBieSBkZWZhdWx0LlxyXG5cdGZvcm1hdE51bTogZnVuY3Rpb24gKG51bSwgZGlnaXRzKSB7XHJcblx0XHR2YXIgcG93ID0gTWF0aC5wb3coMTAsIGRpZ2l0cyB8fCA1KTtcclxuXHRcdHJldHVybiBNYXRoLnJvdW5kKG51bSAqIHBvdykgLyBwb3c7XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHRyaW0oc3RyOiBTdHJpbmcpOiBTdHJpbmdcclxuXHQvLyBDb21wYXRpYmlsaXR5IHBvbHlmaWxsIGZvciBbU3RyaW5nLnByb3RvdHlwZS50cmltXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9TdHJpbmcvVHJpbSlcclxuXHR0cmltOiBmdW5jdGlvbiAoc3RyKSB7XHJcblx0XHRyZXR1cm4gc3RyLnRyaW0gPyBzdHIudHJpbSgpIDogc3RyLnJlcGxhY2UoL15cXHMrfFxccyskL2csICcnKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gc3BsaXRXb3JkcyhzdHI6IFN0cmluZyk6IFN0cmluZ1tdXHJcblx0Ly8gVHJpbXMgYW5kIHNwbGl0cyB0aGUgc3RyaW5nIG9uIHdoaXRlc3BhY2UgYW5kIHJldHVybnMgdGhlIGFycmF5IG9mIHBhcnRzLlxyXG5cdHNwbGl0V29yZHM6IGZ1bmN0aW9uIChzdHIpIHtcclxuXHRcdHJldHVybiBMLlV0aWwudHJpbShzdHIpLnNwbGl0KC9cXHMrLyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHNldE9wdGlvbnMob2JqOiBPYmplY3QsIG9wdGlvbnM6IE9iamVjdCk6IE9iamVjdFxyXG5cdC8vIE1lcmdlcyB0aGUgZ2l2ZW4gcHJvcGVydGllcyB0byB0aGUgYG9wdGlvbnNgIG9mIHRoZSBgb2JqYCBvYmplY3QsIHJldHVybmluZyB0aGUgcmVzdWx0aW5nIG9wdGlvbnMuIFNlZSBgQ2xhc3Mgb3B0aW9uc2AuIEhhcyBhbiBgTC5zZXRPcHRpb25zYCBzaG9ydGN1dC5cclxuXHRzZXRPcHRpb25zOiBmdW5jdGlvbiAob2JqLCBvcHRpb25zKSB7XHJcblx0XHRpZiAoIW9iai5oYXNPd25Qcm9wZXJ0eSgnb3B0aW9ucycpKSB7XHJcblx0XHRcdG9iai5vcHRpb25zID0gb2JqLm9wdGlvbnMgPyBMLlV0aWwuY3JlYXRlKG9iai5vcHRpb25zKSA6IHt9O1xyXG5cdFx0fVxyXG5cdFx0Zm9yICh2YXIgaSBpbiBvcHRpb25zKSB7XHJcblx0XHRcdG9iai5vcHRpb25zW2ldID0gb3B0aW9uc1tpXTtcclxuXHRcdH1cclxuXHRcdHJldHVybiBvYmoub3B0aW9ucztcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gZ2V0UGFyYW1TdHJpbmcob2JqOiBPYmplY3QsIGV4aXN0aW5nVXJsPzogU3RyaW5nLCB1cHBlcmNhc2U/OiBCb29sZWFuKTogU3RyaW5nXHJcblx0Ly8gQ29udmVydHMgYW4gb2JqZWN0IGludG8gYSBwYXJhbWV0ZXIgVVJMIHN0cmluZywgZS5nLiBge2E6IFwiZm9vXCIsIGI6IFwiYmFyXCJ9YFxyXG5cdC8vIHRyYW5zbGF0ZXMgdG8gYCc/YT1mb28mYj1iYXInYC4gSWYgYGV4aXN0aW5nVXJsYCBpcyBzZXQsIHRoZSBwYXJhbWV0ZXJzIHdpbGxcclxuXHQvLyBiZSBhcHBlbmRlZCBhdCB0aGUgZW5kLiBJZiBgdXBwZXJjYXNlYCBpcyBgdHJ1ZWAsIHRoZSBwYXJhbWV0ZXIgbmFtZXMgd2lsbFxyXG5cdC8vIGJlIHVwcGVyY2FzZWQgKGUuZy4gYCc/QT1mb28mQj1iYXInYClcclxuXHRnZXRQYXJhbVN0cmluZzogZnVuY3Rpb24gKG9iaiwgZXhpc3RpbmdVcmwsIHVwcGVyY2FzZSkge1xyXG5cdFx0dmFyIHBhcmFtcyA9IFtdO1xyXG5cdFx0Zm9yICh2YXIgaSBpbiBvYmopIHtcclxuXHRcdFx0cGFyYW1zLnB1c2goZW5jb2RlVVJJQ29tcG9uZW50KHVwcGVyY2FzZSA/IGkudG9VcHBlckNhc2UoKSA6IGkpICsgJz0nICsgZW5jb2RlVVJJQ29tcG9uZW50KG9ialtpXSkpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuICgoIWV4aXN0aW5nVXJsIHx8IGV4aXN0aW5nVXJsLmluZGV4T2YoJz8nKSA9PT0gLTEpID8gJz8nIDogJyYnKSArIHBhcmFtcy5qb2luKCcmJyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHRlbXBsYXRlKHN0cjogU3RyaW5nLCBkYXRhOiBPYmplY3QpOiBTdHJpbmdcclxuXHQvLyBTaW1wbGUgdGVtcGxhdGluZyBmYWNpbGl0eSwgYWNjZXB0cyBhIHRlbXBsYXRlIHN0cmluZyBvZiB0aGUgZm9ybSBgJ0hlbGxvIHthfSwge2J9J2BcclxuXHQvLyBhbmQgYSBkYXRhIG9iamVjdCBsaWtlIGB7YTogJ2ZvbycsIGI6ICdiYXInfWAsIHJldHVybnMgZXZhbHVhdGVkIHN0cmluZ1xyXG5cdC8vIGAoJ0hlbGxvIGZvbywgYmFyJylgLiBZb3UgY2FuIGFsc28gc3BlY2lmeSBmdW5jdGlvbnMgaW5zdGVhZCBvZiBzdHJpbmdzIGZvclxyXG5cdC8vIGRhdGEgdmFsdWVzIOKAlCB0aGV5IHdpbGwgYmUgZXZhbHVhdGVkIHBhc3NpbmcgYGRhdGFgIGFzIGFuIGFyZ3VtZW50LlxyXG5cdHRlbXBsYXRlOiBmdW5jdGlvbiAoc3RyLCBkYXRhKSB7XHJcblx0XHRyZXR1cm4gc3RyLnJlcGxhY2UoTC5VdGlsLnRlbXBsYXRlUmUsIGZ1bmN0aW9uIChzdHIsIGtleSkge1xyXG5cdFx0XHR2YXIgdmFsdWUgPSBkYXRhW2tleV07XHJcblxyXG5cdFx0XHRpZiAodmFsdWUgPT09IHVuZGVmaW5lZCkge1xyXG5cdFx0XHRcdHRocm93IG5ldyBFcnJvcignTm8gdmFsdWUgcHJvdmlkZWQgZm9yIHZhcmlhYmxlICcgKyBzdHIpO1xyXG5cclxuXHRcdFx0fSBlbHNlIGlmICh0eXBlb2YgdmFsdWUgPT09ICdmdW5jdGlvbicpIHtcclxuXHRcdFx0XHR2YWx1ZSA9IHZhbHVlKGRhdGEpO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiB2YWx1ZTtcclxuXHRcdH0pO1xyXG5cdH0sXHJcblxyXG5cdHRlbXBsYXRlUmU6IC9cXHsgKihbXFx3X1xcLV0rKSAqXFx9L2csXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBpc0FycmF5KG9iaik6IEJvb2xlYW5cclxuXHQvLyBDb21wYXRpYmlsaXR5IHBvbHlmaWxsIGZvciBbQXJyYXkuaXNBcnJheV0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvaXNBcnJheSlcclxuXHRpc0FycmF5OiBBcnJheS5pc0FycmF5IHx8IGZ1bmN0aW9uIChvYmopIHtcclxuXHRcdHJldHVybiAoT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKG9iaikgPT09ICdbb2JqZWN0IEFycmF5XScpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBpbmRleE9mKGFycmF5OiBBcnJheSwgZWw6IE9iamVjdCk6IE51bWJlclxyXG5cdC8vIENvbXBhdGliaWxpdHkgcG9seWZpbGwgZm9yIFtBcnJheS5wcm90b3R5cGUuaW5kZXhPZl0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvSmF2YVNjcmlwdC9SZWZlcmVuY2UvR2xvYmFsX09iamVjdHMvQXJyYXkvaW5kZXhPZilcclxuXHRpbmRleE9mOiBmdW5jdGlvbiAoYXJyYXksIGVsKSB7XHJcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IGFycmF5Lmxlbmd0aDsgaSsrKSB7XHJcblx0XHRcdGlmIChhcnJheVtpXSA9PT0gZWwpIHsgcmV0dXJuIGk7IH1cclxuXHRcdH1cclxuXHRcdHJldHVybiAtMTtcclxuXHR9LFxyXG5cclxuXHQvLyBAcHJvcGVydHkgZW1wdHlJbWFnZVVybDogU3RyaW5nXHJcblx0Ly8gRGF0YSBVUkkgc3RyaW5nIGNvbnRhaW5pbmcgYSBiYXNlNjQtZW5jb2RlZCBlbXB0eSBHSUYgaW1hZ2UuXHJcblx0Ly8gVXNlZCBhcyBhIGhhY2sgdG8gZnJlZSBtZW1vcnkgZnJvbSB1bnVzZWQgaW1hZ2VzIG9uIFdlYktpdC1wb3dlcmVkXHJcblx0Ly8gbW9iaWxlIGRldmljZXMgKGJ5IHNldHRpbmcgaW1hZ2UgYHNyY2AgdG8gdGhpcyBzdHJpbmcpLlxyXG5cdGVtcHR5SW1hZ2VVcmw6ICdkYXRhOmltYWdlL2dpZjtiYXNlNjQsUjBsR09EbGhBUUFCQUFEL0FDd0FBQUFBQVFBQkFBQUNBRHM9J1xyXG59O1xyXG5cclxuKGZ1bmN0aW9uICgpIHtcclxuXHQvLyBpbnNwaXJlZCBieSBodHRwOi8vcGF1bGlyaXNoLmNvbS8yMDExL3JlcXVlc3RhbmltYXRpb25mcmFtZS1mb3Itc21hcnQtYW5pbWF0aW5nL1xyXG5cclxuXHRmdW5jdGlvbiBnZXRQcmVmaXhlZChuYW1lKSB7XHJcblx0XHRyZXR1cm4gd2luZG93Wyd3ZWJraXQnICsgbmFtZV0gfHwgd2luZG93Wydtb3onICsgbmFtZV0gfHwgd2luZG93WydtcycgKyBuYW1lXTtcclxuXHR9XHJcblxyXG5cdHZhciBsYXN0VGltZSA9IDA7XHJcblxyXG5cdC8vIGZhbGxiYWNrIGZvciBJRSA3LThcclxuXHRmdW5jdGlvbiB0aW1lb3V0RGVmZXIoZm4pIHtcclxuXHRcdHZhciB0aW1lID0gK25ldyBEYXRlKCksXHJcblx0XHQgICAgdGltZVRvQ2FsbCA9IE1hdGgubWF4KDAsIDE2IC0gKHRpbWUgLSBsYXN0VGltZSkpO1xyXG5cclxuXHRcdGxhc3RUaW1lID0gdGltZSArIHRpbWVUb0NhbGw7XHJcblx0XHRyZXR1cm4gd2luZG93LnNldFRpbWVvdXQoZm4sIHRpbWVUb0NhbGwpO1xyXG5cdH1cclxuXHJcblx0dmFyIHJlcXVlc3RGbiA9IHdpbmRvdy5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUgfHwgZ2V0UHJlZml4ZWQoJ1JlcXVlc3RBbmltYXRpb25GcmFtZScpIHx8IHRpbWVvdXREZWZlcixcclxuXHQgICAgY2FuY2VsRm4gPSB3aW5kb3cuY2FuY2VsQW5pbWF0aW9uRnJhbWUgfHwgZ2V0UHJlZml4ZWQoJ0NhbmNlbEFuaW1hdGlvbkZyYW1lJykgfHxcclxuXHQgICAgICAgICAgICAgICBnZXRQcmVmaXhlZCgnQ2FuY2VsUmVxdWVzdEFuaW1hdGlvbkZyYW1lJykgfHwgZnVuY3Rpb24gKGlkKSB7IHdpbmRvdy5jbGVhclRpbWVvdXQoaWQpOyB9O1xyXG5cclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHJlcXVlc3RBbmltRnJhbWUoZm46IEZ1bmN0aW9uLCBjb250ZXh0PzogT2JqZWN0LCBpbW1lZGlhdGU/OiBCb29sZWFuKTogTnVtYmVyXHJcblx0Ly8gU2NoZWR1bGVzIGBmbmAgdG8gYmUgZXhlY3V0ZWQgd2hlbiB0aGUgYnJvd3NlciByZXBhaW50cy4gYGZuYCBpcyBib3VuZCB0b1xyXG5cdC8vIGBjb250ZXh0YCBpZiBnaXZlbi4gV2hlbiBgaW1tZWRpYXRlYCBpcyBzZXQsIGBmbmAgaXMgY2FsbGVkIGltbWVkaWF0ZWx5IGlmXHJcblx0Ly8gdGhlIGJyb3dzZXIgZG9lc24ndCBoYXZlIG5hdGl2ZSBzdXBwb3J0IGZvclxyXG5cdC8vIFtgd2luZG93LnJlcXVlc3RBbmltYXRpb25GcmFtZWBdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0FQSS93aW5kb3cvcmVxdWVzdEFuaW1hdGlvbkZyYW1lKSxcclxuXHQvLyBvdGhlcndpc2UgaXQncyBkZWxheWVkLiBSZXR1cm5zIGEgcmVxdWVzdCBJRCB0aGF0IGNhbiBiZSB1c2VkIHRvIGNhbmNlbCB0aGUgcmVxdWVzdC5cclxuXHRMLlV0aWwucmVxdWVzdEFuaW1GcmFtZSA9IGZ1bmN0aW9uIChmbiwgY29udGV4dCwgaW1tZWRpYXRlKSB7XHJcblx0XHRpZiAoaW1tZWRpYXRlICYmIHJlcXVlc3RGbiA9PT0gdGltZW91dERlZmVyKSB7XHJcblx0XHRcdGZuLmNhbGwoY29udGV4dCk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRyZXR1cm4gcmVxdWVzdEZuLmNhbGwod2luZG93LCBMLmJpbmQoZm4sIGNvbnRleHQpKTtcclxuXHRcdH1cclxuXHR9O1xyXG5cclxuXHQvLyBAZnVuY3Rpb24gY2FuY2VsQW5pbUZyYW1lKGlkOiBOdW1iZXIpOiB1bmRlZmluZWRcclxuXHQvLyBDYW5jZWxzIGEgcHJldmlvdXMgYHJlcXVlc3RBbmltRnJhbWVgLiBTZWUgYWxzbyBbd2luZG93LmNhbmNlbEFuaW1hdGlvbkZyYW1lXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9BUEkvd2luZG93L2NhbmNlbEFuaW1hdGlvbkZyYW1lKS5cclxuXHRMLlV0aWwuY2FuY2VsQW5pbUZyYW1lID0gZnVuY3Rpb24gKGlkKSB7XHJcblx0XHRpZiAoaWQpIHtcclxuXHRcdFx0Y2FuY2VsRm4uY2FsbCh3aW5kb3csIGlkKTtcclxuXHRcdH1cclxuXHR9O1xyXG59KSgpO1xyXG5cclxuLy8gc2hvcnRjdXRzIGZvciBtb3N0IHVzZWQgdXRpbGl0eSBmdW5jdGlvbnNcclxuTC5leHRlbmQgPSBMLlV0aWwuZXh0ZW5kO1xyXG5MLmJpbmQgPSBMLlV0aWwuYmluZDtcclxuTC5zdGFtcCA9IEwuVXRpbC5zdGFtcDtcclxuTC5zZXRPcHRpb25zID0gTC5VdGlsLnNldE9wdGlvbnM7XHJcblxuXG5cblxyXG4vLyBAY2xhc3MgQ2xhc3NcclxuLy8gQGFrYSBMLkNsYXNzXHJcblxyXG4vLyBAc2VjdGlvblxyXG4vLyBAdW5pbmhlcml0YWJsZVxyXG5cclxuLy8gVGhhbmtzIHRvIEpvaG4gUmVzaWcgYW5kIERlYW4gRWR3YXJkcyBmb3IgaW5zcGlyYXRpb24hXHJcblxyXG5MLkNsYXNzID0gZnVuY3Rpb24gKCkge307XHJcblxyXG5MLkNsYXNzLmV4dGVuZCA9IGZ1bmN0aW9uIChwcm9wcykge1xyXG5cclxuXHQvLyBAZnVuY3Rpb24gZXh0ZW5kKHByb3BzOiBPYmplY3QpOiBGdW5jdGlvblxyXG5cdC8vIFtFeHRlbmRzIHRoZSBjdXJyZW50IGNsYXNzXSgjY2xhc3MtaW5oZXJpdGFuY2UpIGdpdmVuIHRoZSBwcm9wZXJ0aWVzIHRvIGJlIGluY2x1ZGVkLlxyXG5cdC8vIFJldHVybnMgYSBKYXZhc2NyaXB0IGZ1bmN0aW9uIHRoYXQgaXMgYSBjbGFzcyBjb25zdHJ1Y3RvciAodG8gYmUgY2FsbGVkIHdpdGggYG5ld2ApLlxyXG5cdHZhciBOZXdDbGFzcyA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHQvLyBjYWxsIHRoZSBjb25zdHJ1Y3RvclxyXG5cdFx0aWYgKHRoaXMuaW5pdGlhbGl6ZSkge1xyXG5cdFx0XHR0aGlzLmluaXRpYWxpemUuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBjYWxsIGFsbCBjb25zdHJ1Y3RvciBob29rc1xyXG5cdFx0dGhpcy5jYWxsSW5pdEhvb2tzKCk7XHJcblx0fTtcclxuXHJcblx0dmFyIHBhcmVudFByb3RvID0gTmV3Q2xhc3MuX19zdXBlcl9fID0gdGhpcy5wcm90b3R5cGU7XHJcblxyXG5cdHZhciBwcm90byA9IEwuVXRpbC5jcmVhdGUocGFyZW50UHJvdG8pO1xyXG5cdHByb3RvLmNvbnN0cnVjdG9yID0gTmV3Q2xhc3M7XHJcblxyXG5cdE5ld0NsYXNzLnByb3RvdHlwZSA9IHByb3RvO1xyXG5cclxuXHQvLyBpbmhlcml0IHBhcmVudCdzIHN0YXRpY3NcclxuXHRmb3IgKHZhciBpIGluIHRoaXMpIHtcclxuXHRcdGlmICh0aGlzLmhhc093blByb3BlcnR5KGkpICYmIGkgIT09ICdwcm90b3R5cGUnKSB7XHJcblx0XHRcdE5ld0NsYXNzW2ldID0gdGhpc1tpXTtcclxuXHRcdH1cclxuXHR9XHJcblxyXG5cdC8vIG1peCBzdGF0aWMgcHJvcGVydGllcyBpbnRvIHRoZSBjbGFzc1xyXG5cdGlmIChwcm9wcy5zdGF0aWNzKSB7XHJcblx0XHRMLmV4dGVuZChOZXdDbGFzcywgcHJvcHMuc3RhdGljcyk7XHJcblx0XHRkZWxldGUgcHJvcHMuc3RhdGljcztcclxuXHR9XHJcblxyXG5cdC8vIG1peCBpbmNsdWRlcyBpbnRvIHRoZSBwcm90b3R5cGVcclxuXHRpZiAocHJvcHMuaW5jbHVkZXMpIHtcclxuXHRcdEwuVXRpbC5leHRlbmQuYXBwbHkobnVsbCwgW3Byb3RvXS5jb25jYXQocHJvcHMuaW5jbHVkZXMpKTtcclxuXHRcdGRlbGV0ZSBwcm9wcy5pbmNsdWRlcztcclxuXHR9XHJcblxyXG5cdC8vIG1lcmdlIG9wdGlvbnNcclxuXHRpZiAocHJvdG8ub3B0aW9ucykge1xyXG5cdFx0cHJvcHMub3B0aW9ucyA9IEwuVXRpbC5leHRlbmQoTC5VdGlsLmNyZWF0ZShwcm90by5vcHRpb25zKSwgcHJvcHMub3B0aW9ucyk7XHJcblx0fVxyXG5cclxuXHQvLyBtaXggZ2l2ZW4gcHJvcGVydGllcyBpbnRvIHRoZSBwcm90b3R5cGVcclxuXHRMLmV4dGVuZChwcm90bywgcHJvcHMpO1xyXG5cclxuXHRwcm90by5faW5pdEhvb2tzID0gW107XHJcblxyXG5cdC8vIGFkZCBtZXRob2QgZm9yIGNhbGxpbmcgYWxsIGhvb2tzXHJcblx0cHJvdG8uY2FsbEluaXRIb29rcyA9IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHRpZiAodGhpcy5faW5pdEhvb2tzQ2FsbGVkKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdGlmIChwYXJlbnRQcm90by5jYWxsSW5pdEhvb2tzKSB7XHJcblx0XHRcdHBhcmVudFByb3RvLmNhbGxJbml0SG9va3MuY2FsbCh0aGlzKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9pbml0SG9va3NDYWxsZWQgPSB0cnVlO1xyXG5cclxuXHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSBwcm90by5faW5pdEhvb2tzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdHByb3RvLl9pbml0SG9va3NbaV0uY2FsbCh0aGlzKTtcclxuXHRcdH1cclxuXHR9O1xyXG5cclxuXHRyZXR1cm4gTmV3Q2xhc3M7XHJcbn07XHJcblxyXG5cclxuLy8gQGZ1bmN0aW9uIGluY2x1ZGUocHJvcGVydGllczogT2JqZWN0KTogdGhpc1xyXG4vLyBbSW5jbHVkZXMgYSBtaXhpbl0oI2NsYXNzLWluY2x1ZGVzKSBpbnRvIHRoZSBjdXJyZW50IGNsYXNzLlxyXG5MLkNsYXNzLmluY2x1ZGUgPSBmdW5jdGlvbiAocHJvcHMpIHtcclxuXHRMLmV4dGVuZCh0aGlzLnByb3RvdHlwZSwgcHJvcHMpO1xyXG5cdHJldHVybiB0aGlzO1xyXG59O1xyXG5cclxuLy8gQGZ1bmN0aW9uIG1lcmdlT3B0aW9ucyhvcHRpb25zOiBPYmplY3QpOiB0aGlzXHJcbi8vIFtNZXJnZXMgYG9wdGlvbnNgXSgjY2xhc3Mtb3B0aW9ucykgaW50byB0aGUgZGVmYXVsdHMgb2YgdGhlIGNsYXNzLlxyXG5MLkNsYXNzLm1lcmdlT3B0aW9ucyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcblx0TC5leHRlbmQodGhpcy5wcm90b3R5cGUub3B0aW9ucywgb3B0aW9ucyk7XHJcblx0cmV0dXJuIHRoaXM7XHJcbn07XHJcblxyXG4vLyBAZnVuY3Rpb24gYWRkSW5pdEhvb2soZm46IEZ1bmN0aW9uKTogdGhpc1xyXG4vLyBBZGRzIGEgW2NvbnN0cnVjdG9yIGhvb2tdKCNjbGFzcy1jb25zdHJ1Y3Rvci1ob29rcykgdG8gdGhlIGNsYXNzLlxyXG5MLkNsYXNzLmFkZEluaXRIb29rID0gZnVuY3Rpb24gKGZuKSB7IC8vIChGdW5jdGlvbikgfHwgKFN0cmluZywgYXJncy4uLilcclxuXHR2YXIgYXJncyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XHJcblxyXG5cdHZhciBpbml0ID0gdHlwZW9mIGZuID09PSAnZnVuY3Rpb24nID8gZm4gOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzW2ZuXS5hcHBseSh0aGlzLCBhcmdzKTtcclxuXHR9O1xyXG5cclxuXHR0aGlzLnByb3RvdHlwZS5faW5pdEhvb2tzID0gdGhpcy5wcm90b3R5cGUuX2luaXRIb29rcyB8fCBbXTtcclxuXHR0aGlzLnByb3RvdHlwZS5faW5pdEhvb2tzLnB1c2goaW5pdCk7XHJcblx0cmV0dXJuIHRoaXM7XHJcbn07XHJcblxuXG5cbi8qXHJcbiAqIEBjbGFzcyBFdmVudGVkXHJcbiAqIEBha2EgTC5FdmVudGVkXHJcbiAqIEBpbmhlcml0cyBDbGFzc1xyXG4gKlxyXG4gKiBBIHNldCBvZiBtZXRob2RzIHNoYXJlZCBiZXR3ZWVuIGV2ZW50LXBvd2VyZWQgY2xhc3NlcyAobGlrZSBgTWFwYCBhbmQgYE1hcmtlcmApLiBHZW5lcmFsbHksIGV2ZW50cyBhbGxvdyB5b3UgdG8gZXhlY3V0ZSBzb21lIGZ1bmN0aW9uIHdoZW4gc29tZXRoaW5nIGhhcHBlbnMgd2l0aCBhbiBvYmplY3QgKGUuZy4gdGhlIHVzZXIgY2xpY2tzIG9uIHRoZSBtYXAsIGNhdXNpbmcgdGhlIG1hcCB0byBmaXJlIGAnY2xpY2snYCBldmVudCkuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIG1hcC5vbignY2xpY2snLCBmdW5jdGlvbihlKSB7XHJcbiAqIFx0YWxlcnQoZS5sYXRsbmcpO1xyXG4gKiB9ICk7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBMZWFmbGV0IGRlYWxzIHdpdGggZXZlbnQgbGlzdGVuZXJzIGJ5IHJlZmVyZW5jZSwgc28gaWYgeW91IHdhbnQgdG8gYWRkIGEgbGlzdGVuZXIgYW5kIHRoZW4gcmVtb3ZlIGl0LCBkZWZpbmUgaXQgYXMgYSBmdW5jdGlvbjpcclxuICpcclxuICogYGBganNcclxuICogZnVuY3Rpb24gb25DbGljayhlKSB7IC4uLiB9XHJcbiAqXHJcbiAqIG1hcC5vbignY2xpY2snLCBvbkNsaWNrKTtcclxuICogbWFwLm9mZignY2xpY2snLCBvbkNsaWNrKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxuXHJcbkwuRXZlbnRlZCA9IEwuQ2xhc3MuZXh0ZW5kKHtcclxuXHJcblx0LyogQG1ldGhvZCBvbih0eXBlOiBTdHJpbmcsIGZuOiBGdW5jdGlvbiwgY29udGV4dD86IE9iamVjdCk6IHRoaXNcclxuXHQgKiBBZGRzIGEgbGlzdGVuZXIgZnVuY3Rpb24gKGBmbmApIHRvIGEgcGFydGljdWxhciBldmVudCB0eXBlIG9mIHRoZSBvYmplY3QuIFlvdSBjYW4gb3B0aW9uYWxseSBzcGVjaWZ5IHRoZSBjb250ZXh0IG9mIHRoZSBsaXN0ZW5lciAob2JqZWN0IHRoZSB0aGlzIGtleXdvcmQgd2lsbCBwb2ludCB0bykuIFlvdSBjYW4gYWxzbyBwYXNzIHNldmVyYWwgc3BhY2Utc2VwYXJhdGVkIHR5cGVzIChlLmcuIGAnY2xpY2sgZGJsY2xpY2snYCkuXHJcblx0ICpcclxuXHQgKiBAYWx0ZXJuYXRpdmVcclxuXHQgKiBAbWV0aG9kIG9uKGV2ZW50TWFwOiBPYmplY3QpOiB0aGlzXHJcblx0ICogQWRkcyBhIHNldCBvZiB0eXBlL2xpc3RlbmVyIHBhaXJzLCBlLmcuIGB7Y2xpY2s6IG9uQ2xpY2ssIG1vdXNlbW92ZTogb25Nb3VzZU1vdmV9YFxyXG5cdCAqL1xyXG5cdG9uOiBmdW5jdGlvbiAodHlwZXMsIGZuLCBjb250ZXh0KSB7XHJcblxyXG5cdFx0Ly8gdHlwZXMgY2FuIGJlIGEgbWFwIG9mIHR5cGVzL2hhbmRsZXJzXHJcblx0XHRpZiAodHlwZW9mIHR5cGVzID09PSAnb2JqZWN0Jykge1xyXG5cdFx0XHRmb3IgKHZhciB0eXBlIGluIHR5cGVzKSB7XHJcblx0XHRcdFx0Ly8gd2UgZG9uJ3QgcHJvY2VzcyBzcGFjZS1zZXBhcmF0ZWQgZXZlbnRzIGhlcmUgZm9yIHBlcmZvcm1hbmNlO1xyXG5cdFx0XHRcdC8vIGl0J3MgYSBob3QgcGF0aCBzaW5jZSBMYXllciB1c2VzIHRoZSBvbihvYmopIHN5bnRheFxyXG5cdFx0XHRcdHRoaXMuX29uKHR5cGUsIHR5cGVzW3R5cGVdLCBmbik7XHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHQvLyB0eXBlcyBjYW4gYmUgYSBzdHJpbmcgb2Ygc3BhY2Utc2VwYXJhdGVkIHdvcmRzXHJcblx0XHRcdHR5cGVzID0gTC5VdGlsLnNwbGl0V29yZHModHlwZXMpO1xyXG5cclxuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IHR5cGVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdFx0dGhpcy5fb24odHlwZXNbaV0sIGZuLCBjb250ZXh0KTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8qIEBtZXRob2Qgb2ZmKHR5cGU6IFN0cmluZywgZm4/OiBGdW5jdGlvbiwgY29udGV4dD86IE9iamVjdCk6IHRoaXNcclxuXHQgKiBSZW1vdmVzIGEgcHJldmlvdXNseSBhZGRlZCBsaXN0ZW5lciBmdW5jdGlvbi4gSWYgbm8gZnVuY3Rpb24gaXMgc3BlY2lmaWVkLCBpdCB3aWxsIHJlbW92ZSBhbGwgdGhlIGxpc3RlbmVycyBvZiB0aGF0IHBhcnRpY3VsYXIgZXZlbnQgZnJvbSB0aGUgb2JqZWN0LiBOb3RlIHRoYXQgaWYgeW91IHBhc3NlZCBhIGN1c3RvbSBjb250ZXh0IHRvIGBvbmAsIHlvdSBtdXN0IHBhc3MgdGhlIHNhbWUgY29udGV4dCB0byBgb2ZmYCBpbiBvcmRlciB0byByZW1vdmUgdGhlIGxpc3RlbmVyLlxyXG5cdCAqXHJcblx0ICogQGFsdGVybmF0aXZlXHJcblx0ICogQG1ldGhvZCBvZmYoZXZlbnRNYXA6IE9iamVjdCk6IHRoaXNcclxuXHQgKiBSZW1vdmVzIGEgc2V0IG9mIHR5cGUvbGlzdGVuZXIgcGFpcnMuXHJcblx0ICpcclxuXHQgKiBAYWx0ZXJuYXRpdmVcclxuXHQgKiBAbWV0aG9kIG9mZjogdGhpc1xyXG5cdCAqIFJlbW92ZXMgYWxsIGxpc3RlbmVycyB0byBhbGwgZXZlbnRzIG9uIHRoZSBvYmplY3QuXHJcblx0ICovXHJcblx0b2ZmOiBmdW5jdGlvbiAodHlwZXMsIGZuLCBjb250ZXh0KSB7XHJcblxyXG5cdFx0aWYgKCF0eXBlcykge1xyXG5cdFx0XHQvLyBjbGVhciBhbGwgbGlzdGVuZXJzIGlmIGNhbGxlZCB3aXRob3V0IGFyZ3VtZW50c1xyXG5cdFx0XHRkZWxldGUgdGhpcy5fZXZlbnRzO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAodHlwZW9mIHR5cGVzID09PSAnb2JqZWN0Jykge1xyXG5cdFx0XHRmb3IgKHZhciB0eXBlIGluIHR5cGVzKSB7XHJcblx0XHRcdFx0dGhpcy5fb2ZmKHR5cGUsIHR5cGVzW3R5cGVdLCBmbik7XHJcblx0XHRcdH1cclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR0eXBlcyA9IEwuVXRpbC5zcGxpdFdvcmRzKHR5cGVzKTtcclxuXHJcblx0XHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSB0eXBlcy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0XHRcdHRoaXMuX29mZih0eXBlc1tpXSwgZm4sIGNvbnRleHQpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gYXR0YWNoIGxpc3RlbmVyICh3aXRob3V0IHN5bnRhY3RpYyBzdWdhciBub3cpXHJcblx0X29uOiBmdW5jdGlvbiAodHlwZSwgZm4sIGNvbnRleHQpIHtcclxuXHRcdHRoaXMuX2V2ZW50cyA9IHRoaXMuX2V2ZW50cyB8fCB7fTtcclxuXHJcblx0XHQvKiBnZXQvaW5pdCBsaXN0ZW5lcnMgZm9yIHR5cGUgKi9cclxuXHRcdHZhciB0eXBlTGlzdGVuZXJzID0gdGhpcy5fZXZlbnRzW3R5cGVdO1xyXG5cdFx0aWYgKCF0eXBlTGlzdGVuZXJzKSB7XHJcblx0XHRcdHR5cGVMaXN0ZW5lcnMgPSBbXTtcclxuXHRcdFx0dGhpcy5fZXZlbnRzW3R5cGVdID0gdHlwZUxpc3RlbmVycztcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoY29udGV4dCA9PT0gdGhpcykge1xyXG5cdFx0XHQvLyBMZXNzIG1lbW9yeSBmb290cHJpbnQuXHJcblx0XHRcdGNvbnRleHQgPSB1bmRlZmluZWQ7XHJcblx0XHR9XHJcblx0XHR2YXIgbmV3TGlzdGVuZXIgPSB7Zm46IGZuLCBjdHg6IGNvbnRleHR9LFxyXG5cdFx0ICAgIGxpc3RlbmVycyA9IHR5cGVMaXN0ZW5lcnM7XHJcblxyXG5cdFx0Ly8gY2hlY2sgaWYgZm4gYWxyZWFkeSB0aGVyZVxyXG5cdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IGxpc3RlbmVycy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0XHRpZiAobGlzdGVuZXJzW2ldLmZuID09PSBmbiAmJiBsaXN0ZW5lcnNbaV0uY3R4ID09PSBjb250ZXh0KSB7XHJcblx0XHRcdFx0cmV0dXJuO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0bGlzdGVuZXJzLnB1c2gobmV3TGlzdGVuZXIpO1xyXG5cdFx0dHlwZUxpc3RlbmVycy5jb3VudCsrO1xyXG5cdH0sXHJcblxyXG5cdF9vZmY6IGZ1bmN0aW9uICh0eXBlLCBmbiwgY29udGV4dCkge1xyXG5cdFx0dmFyIGxpc3RlbmVycyxcclxuXHRcdCAgICBpLFxyXG5cdFx0ICAgIGxlbjtcclxuXHJcblx0XHRpZiAoIXRoaXMuX2V2ZW50cykgeyByZXR1cm47IH1cclxuXHJcblx0XHRsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbdHlwZV07XHJcblxyXG5cdFx0aWYgKCFsaXN0ZW5lcnMpIHtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICghZm4pIHtcclxuXHRcdFx0Ly8gU2V0IGFsbCByZW1vdmVkIGxpc3RlbmVycyB0byBub29wIHNvIHRoZXkgYXJlIG5vdCBjYWxsZWQgaWYgcmVtb3ZlIGhhcHBlbnMgaW4gZmlyZVxyXG5cdFx0XHRmb3IgKGkgPSAwLCBsZW4gPSBsaXN0ZW5lcnMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0XHRsaXN0ZW5lcnNbaV0uZm4gPSBMLlV0aWwuZmFsc2VGbjtcclxuXHRcdFx0fVxyXG5cdFx0XHQvLyBjbGVhciBhbGwgbGlzdGVuZXJzIGZvciBhIHR5cGUgaWYgZnVuY3Rpb24gaXNuJ3Qgc3BlY2lmaWVkXHJcblx0XHRcdGRlbGV0ZSB0aGlzLl9ldmVudHNbdHlwZV07XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoY29udGV4dCA9PT0gdGhpcykge1xyXG5cdFx0XHRjb250ZXh0ID0gdW5kZWZpbmVkO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChsaXN0ZW5lcnMpIHtcclxuXHJcblx0XHRcdC8vIGZpbmQgZm4gYW5kIHJlbW92ZSBpdFxyXG5cdFx0XHRmb3IgKGkgPSAwLCBsZW4gPSBsaXN0ZW5lcnMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0XHR2YXIgbCA9IGxpc3RlbmVyc1tpXTtcclxuXHRcdFx0XHRpZiAobC5jdHggIT09IGNvbnRleHQpIHsgY29udGludWU7IH1cclxuXHRcdFx0XHRpZiAobC5mbiA9PT0gZm4pIHtcclxuXHJcblx0XHRcdFx0XHQvLyBzZXQgdGhlIHJlbW92ZWQgbGlzdGVuZXIgdG8gbm9vcCBzbyB0aGF0J3Mgbm90IGNhbGxlZCBpZiByZW1vdmUgaGFwcGVucyBpbiBmaXJlXHJcblx0XHRcdFx0XHRsLmZuID0gTC5VdGlsLmZhbHNlRm47XHJcblxyXG5cdFx0XHRcdFx0aWYgKHRoaXMuX2ZpcmluZ0NvdW50KSB7XHJcblx0XHRcdFx0XHRcdC8qIGNvcHkgYXJyYXkgaW4gY2FzZSBldmVudHMgYXJlIGJlaW5nIGZpcmVkICovXHJcblx0XHRcdFx0XHRcdHRoaXMuX2V2ZW50c1t0eXBlXSA9IGxpc3RlbmVycyA9IGxpc3RlbmVycy5zbGljZSgpO1xyXG5cdFx0XHRcdFx0fVxyXG5cdFx0XHRcdFx0bGlzdGVuZXJzLnNwbGljZShpLCAxKTtcclxuXHJcblx0XHRcdFx0XHRyZXR1cm47XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBmaXJlKHR5cGU6IFN0cmluZywgZGF0YT86IE9iamVjdCwgcHJvcGFnYXRlPzogQm9vbGVhbik6IHRoaXNcclxuXHQvLyBGaXJlcyBhbiBldmVudCBvZiB0aGUgc3BlY2lmaWVkIHR5cGUuIFlvdSBjYW4gb3B0aW9uYWxseSBwcm92aWRlIGFuIGRhdGFcclxuXHQvLyBvYmplY3Qg4oCUIHRoZSBmaXJzdCBhcmd1bWVudCBvZiB0aGUgbGlzdGVuZXIgZnVuY3Rpb24gd2lsbCBjb250YWluIGl0c1xyXG5cdC8vIHByb3BlcnRpZXMuIFRoZSBldmVudCBjYW4gb3B0aW9uYWxseSBiZSBwcm9wYWdhdGVkIHRvIGV2ZW50IHBhcmVudHMuXHJcblx0ZmlyZTogZnVuY3Rpb24gKHR5cGUsIGRhdGEsIHByb3BhZ2F0ZSkge1xyXG5cdFx0aWYgKCF0aGlzLmxpc3RlbnModHlwZSwgcHJvcGFnYXRlKSkgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdHZhciBldmVudCA9IEwuVXRpbC5leHRlbmQoe30sIGRhdGEsIHt0eXBlOiB0eXBlLCB0YXJnZXQ6IHRoaXN9KTtcclxuXHJcblx0XHRpZiAodGhpcy5fZXZlbnRzKSB7XHJcblx0XHRcdHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHNbdHlwZV07XHJcblxyXG5cdFx0XHRpZiAobGlzdGVuZXJzKSB7XHJcblx0XHRcdFx0dGhpcy5fZmlyaW5nQ291bnQgPSAodGhpcy5fZmlyaW5nQ291bnQgKyAxKSB8fCAxO1xyXG5cdFx0XHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSBsaXN0ZW5lcnMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0XHRcdHZhciBsID0gbGlzdGVuZXJzW2ldO1xyXG5cdFx0XHRcdFx0bC5mbi5jYWxsKGwuY3R4IHx8IHRoaXMsIGV2ZW50KTtcclxuXHRcdFx0XHR9XHJcblxyXG5cdFx0XHRcdHRoaXMuX2ZpcmluZ0NvdW50LS07XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRpZiAocHJvcGFnYXRlKSB7XHJcblx0XHRcdC8vIHByb3BhZ2F0ZSB0aGUgZXZlbnQgdG8gcGFyZW50cyAoc2V0IHdpdGggYWRkRXZlbnRQYXJlbnQpXHJcblx0XHRcdHRoaXMuX3Byb3BhZ2F0ZUV2ZW50KGV2ZW50KTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGxpc3RlbnModHlwZTogU3RyaW5nKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIGEgcGFydGljdWxhciBldmVudCB0eXBlIGhhcyBhbnkgbGlzdGVuZXJzIGF0dGFjaGVkIHRvIGl0LlxyXG5cdGxpc3RlbnM6IGZ1bmN0aW9uICh0eXBlLCBwcm9wYWdhdGUpIHtcclxuXHRcdHZhciBsaXN0ZW5lcnMgPSB0aGlzLl9ldmVudHMgJiYgdGhpcy5fZXZlbnRzW3R5cGVdO1xyXG5cdFx0aWYgKGxpc3RlbmVycyAmJiBsaXN0ZW5lcnMubGVuZ3RoKSB7IHJldHVybiB0cnVlOyB9XHJcblxyXG5cdFx0aWYgKHByb3BhZ2F0ZSkge1xyXG5cdFx0XHQvLyBhbHNvIGNoZWNrIHBhcmVudHMgZm9yIGxpc3RlbmVycyBpZiBldmVudCBwcm9wYWdhdGVzXHJcblx0XHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2V2ZW50UGFyZW50cykge1xyXG5cdFx0XHRcdGlmICh0aGlzLl9ldmVudFBhcmVudHNbaWRdLmxpc3RlbnModHlwZSwgcHJvcGFnYXRlKSkgeyByZXR1cm4gdHJ1ZTsgfVxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gZmFsc2U7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBvbmNlKOKApik6IHRoaXNcclxuXHQvLyBCZWhhdmVzIGFzIFtgb24o4oCmKWBdKCNldmVudGVkLW9uKSwgZXhjZXB0IHRoZSBsaXN0ZW5lciB3aWxsIG9ubHkgZ2V0IGZpcmVkIG9uY2UgYW5kIHRoZW4gcmVtb3ZlZC5cclxuXHRvbmNlOiBmdW5jdGlvbiAodHlwZXMsIGZuLCBjb250ZXh0KSB7XHJcblxyXG5cdFx0aWYgKHR5cGVvZiB0eXBlcyA9PT0gJ29iamVjdCcpIHtcclxuXHRcdFx0Zm9yICh2YXIgdHlwZSBpbiB0eXBlcykge1xyXG5cdFx0XHRcdHRoaXMub25jZSh0eXBlLCB0eXBlc1t0eXBlXSwgZm4pO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBoYW5kbGVyID0gTC5iaW5kKGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0dGhpc1xyXG5cdFx0XHQgICAgLm9mZih0eXBlcywgZm4sIGNvbnRleHQpXHJcblx0XHRcdCAgICAub2ZmKHR5cGVzLCBoYW5kbGVyLCBjb250ZXh0KTtcclxuXHRcdH0sIHRoaXMpO1xyXG5cclxuXHRcdC8vIGFkZCBhIGxpc3RlbmVyIHRoYXQncyBleGVjdXRlZCBvbmNlIGFuZCByZW1vdmVkIGFmdGVyIHRoYXRcclxuXHRcdHJldHVybiB0aGlzXHJcblx0XHQgICAgLm9uKHR5cGVzLCBmbiwgY29udGV4dClcclxuXHRcdCAgICAub24odHlwZXMsIGhhbmRsZXIsIGNvbnRleHQpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgYWRkRXZlbnRQYXJlbnQob2JqOiBFdmVudGVkKTogdGhpc1xyXG5cdC8vIEFkZHMgYW4gZXZlbnQgcGFyZW50IC0gYW4gYEV2ZW50ZWRgIHRoYXQgd2lsbCByZWNlaXZlIHByb3BhZ2F0ZWQgZXZlbnRzXHJcblx0YWRkRXZlbnRQYXJlbnQ6IGZ1bmN0aW9uIChvYmopIHtcclxuXHRcdHRoaXMuX2V2ZW50UGFyZW50cyA9IHRoaXMuX2V2ZW50UGFyZW50cyB8fCB7fTtcclxuXHRcdHRoaXMuX2V2ZW50UGFyZW50c1tMLnN0YW1wKG9iaildID0gb2JqO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCByZW1vdmVFdmVudFBhcmVudChvYmo6IEV2ZW50ZWQpOiB0aGlzXHJcblx0Ly8gUmVtb3ZlcyBhbiBldmVudCBwYXJlbnQsIHNvIGl0IHdpbGwgc3RvcCByZWNlaXZpbmcgcHJvcGFnYXRlZCBldmVudHNcclxuXHRyZW1vdmVFdmVudFBhcmVudDogZnVuY3Rpb24gKG9iaikge1xyXG5cdFx0aWYgKHRoaXMuX2V2ZW50UGFyZW50cykge1xyXG5cdFx0XHRkZWxldGUgdGhpcy5fZXZlbnRQYXJlbnRzW0wuc3RhbXAob2JqKV07XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfcHJvcGFnYXRlRXZlbnQ6IGZ1bmN0aW9uIChlKSB7XHJcblx0XHRmb3IgKHZhciBpZCBpbiB0aGlzLl9ldmVudFBhcmVudHMpIHtcclxuXHRcdFx0dGhpcy5fZXZlbnRQYXJlbnRzW2lkXS5maXJlKGUudHlwZSwgTC5leHRlbmQoe2xheWVyOiBlLnRhcmdldH0sIGUpLCB0cnVlKTtcclxuXHRcdH1cclxuXHR9XHJcbn0pO1xyXG5cclxudmFyIHByb3RvID0gTC5FdmVudGVkLnByb3RvdHlwZTtcclxuXHJcbi8vIGFsaWFzZXM7IHdlIHNob3VsZCBkaXRjaCB0aG9zZSBldmVudHVhbGx5XHJcblxyXG4vLyBAbWV0aG9kIGFkZEV2ZW50TGlzdGVuZXIo4oCmKTogdGhpc1xyXG4vLyBBbGlhcyB0byBbYG9uKOKApilgXSgjZXZlbnRlZC1vbilcclxucHJvdG8uYWRkRXZlbnRMaXN0ZW5lciA9IHByb3RvLm9uO1xyXG5cclxuLy8gQG1ldGhvZCByZW1vdmVFdmVudExpc3RlbmVyKOKApik6IHRoaXNcclxuLy8gQWxpYXMgdG8gW2BvZmYo4oCmKWBdKCNldmVudGVkLW9mZilcclxuXHJcbi8vIEBtZXRob2QgY2xlYXJBbGxFdmVudExpc3RlbmVycyjigKYpOiB0aGlzXHJcbi8vIEFsaWFzIHRvIFtgb2ZmKClgXSgjZXZlbnRlZC1vZmYpXHJcbnByb3RvLnJlbW92ZUV2ZW50TGlzdGVuZXIgPSBwcm90by5jbGVhckFsbEV2ZW50TGlzdGVuZXJzID0gcHJvdG8ub2ZmO1xyXG5cclxuLy8gQG1ldGhvZCBhZGRPbmVUaW1lRXZlbnRMaXN0ZW5lcijigKYpOiB0aGlzXHJcbi8vIEFsaWFzIHRvIFtgb25jZSjigKYpYF0oI2V2ZW50ZWQtb25jZSlcclxucHJvdG8uYWRkT25lVGltZUV2ZW50TGlzdGVuZXIgPSBwcm90by5vbmNlO1xyXG5cclxuLy8gQG1ldGhvZCBmaXJlRXZlbnQo4oCmKTogdGhpc1xyXG4vLyBBbGlhcyB0byBbYGZpcmUo4oCmKWBdKCNldmVudGVkLWZpcmUpXHJcbnByb3RvLmZpcmVFdmVudCA9IHByb3RvLmZpcmU7XHJcblxyXG4vLyBAbWV0aG9kIGhhc0V2ZW50TGlzdGVuZXJzKOKApik6IEJvb2xlYW5cclxuLy8gQWxpYXMgdG8gW2BsaXN0ZW5zKOKApilgXSgjZXZlbnRlZC1saXN0ZW5zKVxyXG5wcm90by5oYXNFdmVudExpc3RlbmVycyA9IHByb3RvLmxpc3RlbnM7XHJcblxyXG5MLk1peGluID0ge0V2ZW50czogcHJvdG99O1xyXG5cblxuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIEJyb3dzZXJcclxuICogQGFrYSBMLkJyb3dzZXJcclxuICpcclxuICogQSBuYW1lc3BhY2Ugd2l0aCBzdGF0aWMgcHJvcGVydGllcyBmb3IgYnJvd3Nlci9mZWF0dXJlIGRldGVjdGlvbiB1c2VkIGJ5IExlYWZsZXQgaW50ZXJuYWxseS5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogaWYgKEwuQnJvd3Nlci5pZWx0OSkge1xyXG4gKiAgIGFsZXJ0KCdVcGdyYWRlIHlvdXIgYnJvd3NlciwgZHVkZSEnKTtcclxuICogfVxyXG4gKiBgYGBcclxuICovXHJcblxyXG4oZnVuY3Rpb24gKCkge1xyXG5cclxuXHR2YXIgdWEgPSBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCksXHJcblx0ICAgIGRvYyA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCxcclxuXHJcblx0ICAgIGllID0gJ0FjdGl2ZVhPYmplY3QnIGluIHdpbmRvdyxcclxuXHJcblx0ICAgIHdlYmtpdCAgICA9IHVhLmluZGV4T2YoJ3dlYmtpdCcpICE9PSAtMSxcclxuXHQgICAgcGhhbnRvbWpzID0gdWEuaW5kZXhPZigncGhhbnRvbScpICE9PSAtMSxcclxuXHQgICAgYW5kcm9pZDIzID0gdWEuc2VhcmNoKCdhbmRyb2lkIFsyM10nKSAhPT0gLTEsXHJcblx0ICAgIGNocm9tZSAgICA9IHVhLmluZGV4T2YoJ2Nocm9tZScpICE9PSAtMSxcclxuXHQgICAgZ2Vja28gICAgID0gdWEuaW5kZXhPZignZ2Vja28nKSAhPT0gLTEgICYmICF3ZWJraXQgJiYgIXdpbmRvdy5vcGVyYSAmJiAhaWUsXHJcblxyXG5cdCAgICB3aW4gPSBuYXZpZ2F0b3IucGxhdGZvcm0uaW5kZXhPZignV2luJykgPT09IDAsXHJcblxyXG5cdCAgICBtb2JpbGUgPSB0eXBlb2Ygb3JpZW50YXRpb24gIT09ICd1bmRlZmluZWQnIHx8IHVhLmluZGV4T2YoJ21vYmlsZScpICE9PSAtMSxcclxuXHQgICAgbXNQb2ludGVyID0gIXdpbmRvdy5Qb2ludGVyRXZlbnQgJiYgd2luZG93Lk1TUG9pbnRlckV2ZW50LFxyXG5cdCAgICBwb2ludGVyID0gd2luZG93LlBvaW50ZXJFdmVudCB8fCBtc1BvaW50ZXIsXHJcblxyXG5cdCAgICBpZTNkID0gaWUgJiYgKCd0cmFuc2l0aW9uJyBpbiBkb2Muc3R5bGUpLFxyXG5cdCAgICB3ZWJraXQzZCA9ICgnV2ViS2l0Q1NTTWF0cml4JyBpbiB3aW5kb3cpICYmICgnbTExJyBpbiBuZXcgd2luZG93LldlYktpdENTU01hdHJpeCgpKSAmJiAhYW5kcm9pZDIzLFxyXG5cdCAgICBnZWNrbzNkID0gJ01velBlcnNwZWN0aXZlJyBpbiBkb2Muc3R5bGUsXHJcblx0ICAgIG9wZXJhMTIgPSAnT1RyYW5zaXRpb24nIGluIGRvYy5zdHlsZTtcclxuXHJcblxyXG5cdHZhciB0b3VjaCA9ICF3aW5kb3cuTF9OT19UT1VDSCAmJiAocG9pbnRlciB8fCAnb250b3VjaHN0YXJ0JyBpbiB3aW5kb3cgfHxcclxuXHRcdFx0KHdpbmRvdy5Eb2N1bWVudFRvdWNoICYmIGRvY3VtZW50IGluc3RhbmNlb2Ygd2luZG93LkRvY3VtZW50VG91Y2gpKTtcclxuXHJcblx0TC5Ccm93c2VyID0ge1xyXG5cclxuXHRcdC8vIEBwcm9wZXJ0eSBpZTogQm9vbGVhblxyXG5cdFx0Ly8gYHRydWVgIGZvciBhbGwgSW50ZXJuZXQgRXhwbG9yZXIgdmVyc2lvbnMgKG5vdCBFZGdlKS5cclxuXHRcdGllOiBpZSxcclxuXHJcblx0XHQvLyBAcHJvcGVydHkgaWVsdDk6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgSW50ZXJuZXQgRXhwbG9yZXIgdmVyc2lvbnMgbGVzcyB0aGFuIDkuXHJcblx0XHRpZWx0OTogaWUgJiYgIWRvY3VtZW50LmFkZEV2ZW50TGlzdGVuZXIsXHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IGVkZ2U6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgdGhlIEVkZ2Ugd2ViIGJyb3dzZXIuXHJcblx0XHRlZGdlOiAnbXNMYXVuY2hVcmknIGluIG5hdmlnYXRvciAmJiAhKCdkb2N1bWVudE1vZGUnIGluIGRvY3VtZW50KSxcclxuXHJcblx0XHQvLyBAcHJvcGVydHkgd2Via2l0OiBCb29sZWFuXHJcblx0XHQvLyBgdHJ1ZWAgZm9yIHdlYmtpdC1iYXNlZCBicm93c2VycyBsaWtlIENocm9tZSBhbmQgU2FmYXJpIChpbmNsdWRpbmcgbW9iaWxlIHZlcnNpb25zKS5cclxuXHRcdHdlYmtpdDogd2Via2l0LFxyXG5cclxuXHRcdC8vIEBwcm9wZXJ0eSBnZWNrbzogQm9vbGVhblxyXG5cdFx0Ly8gYHRydWVgIGZvciBnZWNrby1iYXNlZCBicm93c2VycyBsaWtlIEZpcmVmb3guXHJcblx0XHRnZWNrbzogZ2Vja28sXHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IGFuZHJvaWQ6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgYW55IGJyb3dzZXIgcnVubmluZyBvbiBhbiBBbmRyb2lkIHBsYXRmb3JtLlxyXG5cdFx0YW5kcm9pZDogdWEuaW5kZXhPZignYW5kcm9pZCcpICE9PSAtMSxcclxuXHJcblx0XHQvLyBAcHJvcGVydHkgYW5kcm9pZDIzOiBCb29sZWFuXHJcblx0XHQvLyBgdHJ1ZWAgZm9yIGJyb3dzZXJzIHJ1bm5pbmcgb24gQW5kcm9pZCAyIG9yIEFuZHJvaWQgMy5cclxuXHRcdGFuZHJvaWQyMzogYW5kcm9pZDIzLFxyXG5cclxuXHRcdC8vIEBwcm9wZXJ0eSBjaHJvbWU6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgdGhlIENocm9tZSBicm93c2VyLlxyXG5cdFx0Y2hyb21lOiBjaHJvbWUsXHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IHNhZmFyaTogQm9vbGVhblxyXG5cdFx0Ly8gYHRydWVgIGZvciB0aGUgU2FmYXJpIGJyb3dzZXIuXHJcblx0XHRzYWZhcmk6ICFjaHJvbWUgJiYgdWEuaW5kZXhPZignc2FmYXJpJykgIT09IC0xLFxyXG5cclxuXHJcblx0XHQvLyBAcHJvcGVydHkgd2luOiBCb29sZWFuXHJcblx0XHQvLyBgdHJ1ZWAgd2hlbiB0aGUgYnJvd3NlciBpcyBydW5uaW5nIGluIGEgV2luZG93cyBwbGF0Zm9ybVxyXG5cdFx0d2luOiB3aW4sXHJcblxyXG5cclxuXHRcdC8vIEBwcm9wZXJ0eSBpZTNkOiBCb29sZWFuXHJcblx0XHQvLyBgdHJ1ZWAgZm9yIGFsbCBJbnRlcm5ldCBFeHBsb3JlciB2ZXJzaW9ucyBzdXBwb3J0aW5nIENTUyB0cmFuc2Zvcm1zLlxyXG5cdFx0aWUzZDogaWUzZCxcclxuXHJcblx0XHQvLyBAcHJvcGVydHkgd2Via2l0M2Q6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3Igd2Via2l0LWJhc2VkIGJyb3dzZXJzIHN1cHBvcnRpbmcgQ1NTIHRyYW5zZm9ybXMuXHJcblx0XHR3ZWJraXQzZDogd2Via2l0M2QsXHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IGdlY2tvM2Q6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgZ2Vja28tYmFzZWQgYnJvd3NlcnMgc3VwcG9ydGluZyBDU1MgdHJhbnNmb3Jtcy5cclxuXHRcdGdlY2tvM2Q6IGdlY2tvM2QsXHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IG9wZXJhMTI6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgdGhlIE9wZXJhIGJyb3dzZXIgc3VwcG9ydGluZyBDU1MgdHJhbnNmb3JtcyAodmVyc2lvbiAxMiBvciBsYXRlcikuXHJcblx0XHRvcGVyYTEyOiBvcGVyYTEyLFxyXG5cclxuXHRcdC8vIEBwcm9wZXJ0eSBhbnkzZDogQm9vbGVhblxyXG5cdFx0Ly8gYHRydWVgIGZvciBhbGwgYnJvd3NlcnMgc3VwcG9ydGluZyBDU1MgdHJhbnNmb3Jtcy5cclxuXHRcdGFueTNkOiAhd2luZG93LkxfRElTQUJMRV8zRCAmJiAoaWUzZCB8fCB3ZWJraXQzZCB8fCBnZWNrbzNkKSAmJiAhb3BlcmExMiAmJiAhcGhhbnRvbWpzLFxyXG5cclxuXHJcblx0XHQvLyBAcHJvcGVydHkgbW9iaWxlOiBCb29sZWFuXHJcblx0XHQvLyBgdHJ1ZWAgZm9yIGFsbCBicm93c2VycyBydW5uaW5nIGluIGEgbW9iaWxlIGRldmljZS5cclxuXHRcdG1vYmlsZTogbW9iaWxlLFxyXG5cclxuXHRcdC8vIEBwcm9wZXJ0eSBtb2JpbGVXZWJraXQ6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgYWxsIHdlYmtpdC1iYXNlZCBicm93c2VycyBpbiBhIG1vYmlsZSBkZXZpY2UuXHJcblx0XHRtb2JpbGVXZWJraXQ6IG1vYmlsZSAmJiB3ZWJraXQsXHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IG1vYmlsZVdlYmtpdDNkOiBCb29sZWFuXHJcblx0XHQvLyBgdHJ1ZWAgZm9yIGFsbCB3ZWJraXQtYmFzZWQgYnJvd3NlcnMgaW4gYSBtb2JpbGUgZGV2aWNlIHN1cHBvcnRpbmcgQ1NTIHRyYW5zZm9ybXMuXHJcblx0XHRtb2JpbGVXZWJraXQzZDogbW9iaWxlICYmIHdlYmtpdDNkLFxyXG5cclxuXHRcdC8vIEBwcm9wZXJ0eSBtb2JpbGVPcGVyYTogQm9vbGVhblxyXG5cdFx0Ly8gYHRydWVgIGZvciB0aGUgT3BlcmEgYnJvd3NlciBpbiBhIG1vYmlsZSBkZXZpY2UuXHJcblx0XHRtb2JpbGVPcGVyYTogbW9iaWxlICYmIHdpbmRvdy5vcGVyYSxcclxuXHJcblx0XHQvLyBAcHJvcGVydHkgbW9iaWxlR2Vja286IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgZ2Vja28tYmFzZWQgYnJvd3NlcnMgcnVubmluZyBpbiBhIG1vYmlsZSBkZXZpY2UuXHJcblx0XHRtb2JpbGVHZWNrbzogbW9iaWxlICYmIGdlY2tvLFxyXG5cclxuXHJcblx0XHQvLyBAcHJvcGVydHkgdG91Y2g6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgYWxsIGJyb3dzZXJzIHN1cHBvcnRpbmcgW3RvdWNoIGV2ZW50c10oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvQVBJL1RvdWNoX2V2ZW50cykuXHJcblx0XHR0b3VjaDogISF0b3VjaCxcclxuXHJcblx0XHQvLyBAcHJvcGVydHkgbXNQb2ludGVyOiBCb29sZWFuXHJcblx0XHQvLyBgdHJ1ZWAgZm9yIGJyb3dzZXJzIGltcGxlbWVudGluZyB0aGUgTWljcm9zb2Z0IHRvdWNoIGV2ZW50cyBtb2RlbCAobm90YWJseSBJRTEwKS5cclxuXHRcdG1zUG9pbnRlcjogISFtc1BvaW50ZXIsXHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IHBvaW50ZXI6IEJvb2xlYW5cclxuXHRcdC8vIGB0cnVlYCBmb3IgYWxsIGJyb3dzZXJzIHN1cHBvcnRpbmcgW3BvaW50ZXIgZXZlbnRzXShodHRwczovL21zZG4ubWljcm9zb2Z0LmNvbS9lbi11cy9saWJyYXJ5L2RuNDMzMjQ0JTI4dj12cy44NSUyOS5hc3B4KS5cclxuXHRcdHBvaW50ZXI6ICEhcG9pbnRlcixcclxuXHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IHJldGluYTogQm9vbGVhblxyXG5cdFx0Ly8gYHRydWVgIGZvciBicm93c2VycyBvbiBhIGhpZ2gtcmVzb2x1dGlvbiBcInJldGluYVwiIHNjcmVlbi5cclxuXHRcdHJldGluYTogKHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvIHx8ICh3aW5kb3cuc2NyZWVuLmRldmljZVhEUEkgLyB3aW5kb3cuc2NyZWVuLmxvZ2ljYWxYRFBJKSkgPiAxXHJcblx0fTtcclxuXHJcbn0oKSk7XHJcblxuXG5cbi8qXHJcbiAqIEBjbGFzcyBQb2ludFxyXG4gKiBAYWthIEwuUG9pbnRcclxuICpcclxuICogUmVwcmVzZW50cyBhIHBvaW50IHdpdGggYHhgIGFuZCBgeWAgY29vcmRpbmF0ZXMgaW4gcGl4ZWxzLlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiB2YXIgcG9pbnQgPSBMLnBvaW50KDIwMCwgMzAwKTtcclxuICogYGBgXHJcbiAqXHJcbiAqIEFsbCBMZWFmbGV0IG1ldGhvZHMgYW5kIG9wdGlvbnMgdGhhdCBhY2NlcHQgYFBvaW50YCBvYmplY3RzIGFsc28gYWNjZXB0IHRoZW0gaW4gYSBzaW1wbGUgQXJyYXkgZm9ybSAodW5sZXNzIG5vdGVkIG90aGVyd2lzZSksIHNvIHRoZXNlIGxpbmVzIGFyZSBlcXVpdmFsZW50OlxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiBtYXAucGFuQnkoWzIwMCwgMzAwXSk7XHJcbiAqIG1hcC5wYW5CeShMLnBvaW50KDIwMCwgMzAwKSk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbkwuUG9pbnQgPSBmdW5jdGlvbiAoeCwgeSwgcm91bmQpIHtcclxuXHQvLyBAcHJvcGVydHkgeDogTnVtYmVyOyBUaGUgYHhgIGNvb3JkaW5hdGUgb2YgdGhlIHBvaW50XHJcblx0dGhpcy54ID0gKHJvdW5kID8gTWF0aC5yb3VuZCh4KSA6IHgpO1xyXG5cdC8vIEBwcm9wZXJ0eSB5OiBOdW1iZXI7IFRoZSBgeWAgY29vcmRpbmF0ZSBvZiB0aGUgcG9pbnRcclxuXHR0aGlzLnkgPSAocm91bmQgPyBNYXRoLnJvdW5kKHkpIDogeSk7XHJcbn07XHJcblxyXG5MLlBvaW50LnByb3RvdHlwZSA9IHtcclxuXHJcblx0Ly8gQG1ldGhvZCBjbG9uZSgpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgYSBjb3B5IG9mIHRoZSBjdXJyZW50IHBvaW50LlxyXG5cdGNsb25lOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gbmV3IEwuUG9pbnQodGhpcy54LCB0aGlzLnkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgYWRkKG90aGVyUG9pbnQ6IFBvaW50KTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIHRoZSByZXN1bHQgb2YgYWRkaXRpb24gb2YgdGhlIGN1cnJlbnQgYW5kIHRoZSBnaXZlbiBwb2ludHMuXHJcblx0YWRkOiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdC8vIG5vbi1kZXN0cnVjdGl2ZSwgcmV0dXJucyBhIG5ldyBwb2ludFxyXG5cdFx0cmV0dXJuIHRoaXMuY2xvbmUoKS5fYWRkKEwucG9pbnQocG9pbnQpKTtcclxuXHR9LFxyXG5cclxuXHRfYWRkOiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdC8vIGRlc3RydWN0aXZlLCB1c2VkIGRpcmVjdGx5IGZvciBwZXJmb3JtYW5jZSBpbiBzaXR1YXRpb25zIHdoZXJlIGl0J3Mgc2FmZSB0byBtb2RpZnkgZXhpc3RpbmcgcG9pbnRcclxuXHRcdHRoaXMueCArPSBwb2ludC54O1xyXG5cdFx0dGhpcy55ICs9IHBvaW50Lnk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHN1YnRyYWN0KG90aGVyUG9pbnQ6IFBvaW50KTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIHRoZSByZXN1bHQgb2Ygc3VidHJhY3Rpb24gb2YgdGhlIGdpdmVuIHBvaW50IGZyb20gdGhlIGN1cnJlbnQuXHJcblx0c3VidHJhY3Q6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuY2xvbmUoKS5fc3VidHJhY3QoTC5wb2ludChwb2ludCkpO1xyXG5cdH0sXHJcblxyXG5cdF9zdWJ0cmFjdDogZnVuY3Rpb24gKHBvaW50KSB7XHJcblx0XHR0aGlzLnggLT0gcG9pbnQueDtcclxuXHRcdHRoaXMueSAtPSBwb2ludC55O1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBkaXZpZGVCeShudW06IE51bWJlcik6IFBvaW50XHJcblx0Ly8gUmV0dXJucyB0aGUgcmVzdWx0IG9mIGRpdmlzaW9uIG9mIHRoZSBjdXJyZW50IHBvaW50IGJ5IHRoZSBnaXZlbiBudW1iZXIuXHJcblx0ZGl2aWRlQnk6IGZ1bmN0aW9uIChudW0pIHtcclxuXHRcdHJldHVybiB0aGlzLmNsb25lKCkuX2RpdmlkZUJ5KG51bSk7XHJcblx0fSxcclxuXHJcblx0X2RpdmlkZUJ5OiBmdW5jdGlvbiAobnVtKSB7XHJcblx0XHR0aGlzLnggLz0gbnVtO1xyXG5cdFx0dGhpcy55IC89IG51bTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgbXVsdGlwbHlCeShudW06IE51bWJlcik6IFBvaW50XHJcblx0Ly8gUmV0dXJucyB0aGUgcmVzdWx0IG9mIG11bHRpcGxpY2F0aW9uIG9mIHRoZSBjdXJyZW50IHBvaW50IGJ5IHRoZSBnaXZlbiBudW1iZXIuXHJcblx0bXVsdGlwbHlCeTogZnVuY3Rpb24gKG51bSkge1xyXG5cdFx0cmV0dXJuIHRoaXMuY2xvbmUoKS5fbXVsdGlwbHlCeShudW0pO1xyXG5cdH0sXHJcblxyXG5cdF9tdWx0aXBseUJ5OiBmdW5jdGlvbiAobnVtKSB7XHJcblx0XHR0aGlzLnggKj0gbnVtO1xyXG5cdFx0dGhpcy55ICo9IG51bTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2NhbGVCeShzY2FsZTogUG9pbnQpOiBQb2ludFxyXG5cdC8vIE11bHRpcGx5IGVhY2ggY29vcmRpbmF0ZSBvZiB0aGUgY3VycmVudCBwb2ludCBieSBlYWNoIGNvb3JkaW5hdGUgb2ZcclxuXHQvLyBgc2NhbGVgLiBJbiBsaW5lYXIgYWxnZWJyYSB0ZXJtcywgbXVsdGlwbHkgdGhlIHBvaW50IGJ5IHRoZVxyXG5cdC8vIFtzY2FsaW5nIG1hdHJpeF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvU2NhbGluZ18lMjhnZW9tZXRyeSUyOSNNYXRyaXhfcmVwcmVzZW50YXRpb24pXHJcblx0Ly8gZGVmaW5lZCBieSBgc2NhbGVgLlxyXG5cdHNjYWxlQnk6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cmV0dXJuIG5ldyBMLlBvaW50KHRoaXMueCAqIHBvaW50LngsIHRoaXMueSAqIHBvaW50LnkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgdW5zY2FsZUJ5KHNjYWxlOiBQb2ludCk6IFBvaW50XHJcblx0Ly8gSW52ZXJzZSBvZiBgc2NhbGVCeWAuIERpdmlkZSBlYWNoIGNvb3JkaW5hdGUgb2YgdGhlIGN1cnJlbnQgcG9pbnQgYnlcclxuXHQvLyBlYWNoIGNvb3JkaW5hdGUgb2YgYHNjYWxlYC5cclxuXHR1bnNjYWxlQnk6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cmV0dXJuIG5ldyBMLlBvaW50KHRoaXMueCAvIHBvaW50LngsIHRoaXMueSAvIHBvaW50LnkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgcm91bmQoKTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIGEgY29weSBvZiB0aGUgY3VycmVudCBwb2ludCB3aXRoIHJvdW5kZWQgY29vcmRpbmF0ZXMuXHJcblx0cm91bmQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLmNsb25lKCkuX3JvdW5kKCk7XHJcblx0fSxcclxuXHJcblx0X3JvdW5kOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzLnggPSBNYXRoLnJvdW5kKHRoaXMueCk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLnJvdW5kKHRoaXMueSk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGZsb29yKCk6IFBvaW50XHJcblx0Ly8gUmV0dXJucyBhIGNvcHkgb2YgdGhlIGN1cnJlbnQgcG9pbnQgd2l0aCBmbG9vcmVkIGNvb3JkaW5hdGVzIChyb3VuZGVkIGRvd24pLlxyXG5cdGZsb29yOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5jbG9uZSgpLl9mbG9vcigpO1xyXG5cdH0sXHJcblxyXG5cdF9mbG9vcjogZnVuY3Rpb24gKCkge1xyXG5cdFx0dGhpcy54ID0gTWF0aC5mbG9vcih0aGlzLngpO1xyXG5cdFx0dGhpcy55ID0gTWF0aC5mbG9vcih0aGlzLnkpO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjZWlsKCk6IFBvaW50XHJcblx0Ly8gUmV0dXJucyBhIGNvcHkgb2YgdGhlIGN1cnJlbnQgcG9pbnQgd2l0aCBjZWlsZWQgY29vcmRpbmF0ZXMgKHJvdW5kZWQgdXApLlxyXG5cdGNlaWw6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLmNsb25lKCkuX2NlaWwoKTtcclxuXHR9LFxyXG5cclxuXHRfY2VpbDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dGhpcy54ID0gTWF0aC5jZWlsKHRoaXMueCk7XHJcblx0XHR0aGlzLnkgPSBNYXRoLmNlaWwodGhpcy55KTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZGlzdGFuY2VUbyhvdGhlclBvaW50OiBQb2ludCk6IE51bWJlclxyXG5cdC8vIFJldHVybnMgdGhlIGNhcnRlc2lhbiBkaXN0YW5jZSBiZXR3ZWVuIHRoZSBjdXJyZW50IGFuZCB0aGUgZ2l2ZW4gcG9pbnRzLlxyXG5cdGRpc3RhbmNlVG86IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cG9pbnQgPSBMLnBvaW50KHBvaW50KTtcclxuXHJcblx0XHR2YXIgeCA9IHBvaW50LnggLSB0aGlzLngsXHJcblx0XHQgICAgeSA9IHBvaW50LnkgLSB0aGlzLnk7XHJcblxyXG5cdFx0cmV0dXJuIE1hdGguc3FydCh4ICogeCArIHkgKiB5KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGVxdWFscyhvdGhlclBvaW50OiBQb2ludCk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgZ2l2ZW4gcG9pbnQgaGFzIHRoZSBzYW1lIGNvb3JkaW5hdGVzLlxyXG5cdGVxdWFsczogZnVuY3Rpb24gKHBvaW50KSB7XHJcblx0XHRwb2ludCA9IEwucG9pbnQocG9pbnQpO1xyXG5cclxuXHRcdHJldHVybiBwb2ludC54ID09PSB0aGlzLnggJiZcclxuXHRcdCAgICAgICBwb2ludC55ID09PSB0aGlzLnk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjb250YWlucyhvdGhlclBvaW50OiBQb2ludCk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiBib3RoIGNvb3JkaW5hdGVzIG9mIHRoZSBnaXZlbiBwb2ludCBhcmUgbGVzcyB0aGFuIHRoZSBjb3JyZXNwb25kaW5nIGN1cnJlbnQgcG9pbnQgY29vcmRpbmF0ZXMgKGluIGFic29sdXRlIHZhbHVlcykuXHJcblx0Y29udGFpbnM6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cG9pbnQgPSBMLnBvaW50KHBvaW50KTtcclxuXHJcblx0XHRyZXR1cm4gTWF0aC5hYnMocG9pbnQueCkgPD0gTWF0aC5hYnModGhpcy54KSAmJlxyXG5cdFx0ICAgICAgIE1hdGguYWJzKHBvaW50LnkpIDw9IE1hdGguYWJzKHRoaXMueSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB0b1N0cmluZygpOiBTdHJpbmdcclxuXHQvLyBSZXR1cm5zIGEgc3RyaW5nIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBwb2ludCBmb3IgZGVidWdnaW5nIHB1cnBvc2VzLlxyXG5cdHRvU3RyaW5nOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gJ1BvaW50KCcgK1xyXG5cdFx0ICAgICAgICBMLlV0aWwuZm9ybWF0TnVtKHRoaXMueCkgKyAnLCAnICtcclxuXHRcdCAgICAgICAgTC5VdGlsLmZvcm1hdE51bSh0aGlzLnkpICsgJyknO1xyXG5cdH1cclxufTtcclxuXHJcbi8vIEBmYWN0b3J5IEwucG9pbnQoeDogTnVtYmVyLCB5OiBOdW1iZXIsIHJvdW5kPzogQm9vbGVhbilcclxuLy8gQ3JlYXRlcyBhIFBvaW50IG9iamVjdCB3aXRoIHRoZSBnaXZlbiBgeGAgYW5kIGB5YCBjb29yZGluYXRlcy4gSWYgb3B0aW9uYWwgYHJvdW5kYCBpcyBzZXQgdG8gdHJ1ZSwgcm91bmRzIHRoZSBgeGAgYW5kIGB5YCB2YWx1ZXMuXHJcblxyXG4vLyBAYWx0ZXJuYXRpdmVcclxuLy8gQGZhY3RvcnkgTC5wb2ludChjb29yZHM6IE51bWJlcltdKVxyXG4vLyBFeHBlY3RzIGFuIGFycmF5IG9mIHRoZSBmb3JtIGBbeCwgeV1gIGluc3RlYWQuXHJcblxyXG4vLyBAYWx0ZXJuYXRpdmVcclxuLy8gQGZhY3RvcnkgTC5wb2ludChjb29yZHM6IE9iamVjdClcclxuLy8gRXhwZWN0cyBhIHBsYWluIG9iamVjdCBvZiB0aGUgZm9ybSBge3g6IE51bWJlciwgeTogTnVtYmVyfWAgaW5zdGVhZC5cclxuTC5wb2ludCA9IGZ1bmN0aW9uICh4LCB5LCByb3VuZCkge1xyXG5cdGlmICh4IGluc3RhbmNlb2YgTC5Qb2ludCkge1xyXG5cdFx0cmV0dXJuIHg7XHJcblx0fVxyXG5cdGlmIChMLlV0aWwuaXNBcnJheSh4KSkge1xyXG5cdFx0cmV0dXJuIG5ldyBMLlBvaW50KHhbMF0sIHhbMV0pO1xyXG5cdH1cclxuXHRpZiAoeCA9PT0gdW5kZWZpbmVkIHx8IHggPT09IG51bGwpIHtcclxuXHRcdHJldHVybiB4O1xyXG5cdH1cclxuXHRpZiAodHlwZW9mIHggPT09ICdvYmplY3QnICYmICd4JyBpbiB4ICYmICd5JyBpbiB4KSB7XHJcblx0XHRyZXR1cm4gbmV3IEwuUG9pbnQoeC54LCB4LnkpO1xyXG5cdH1cclxuXHRyZXR1cm4gbmV3IEwuUG9pbnQoeCwgeSwgcm91bmQpO1xyXG59O1xyXG5cblxuXG4vKlxyXG4gKiBAY2xhc3MgQm91bmRzXHJcbiAqIEBha2EgTC5Cb3VuZHNcclxuICpcclxuICogUmVwcmVzZW50cyBhIHJlY3Rhbmd1bGFyIGFyZWEgaW4gcGl4ZWwgY29vcmRpbmF0ZXMuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBwMSA9IEwucG9pbnQoMTAsIDEwKSxcclxuICogcDIgPSBMLnBvaW50KDQwLCA2MCksXHJcbiAqIGJvdW5kcyA9IEwuYm91bmRzKHAxLCBwMik7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBBbGwgTGVhZmxldCBtZXRob2RzIHRoYXQgYWNjZXB0IGBCb3VuZHNgIG9iamVjdHMgYWxzbyBhY2NlcHQgdGhlbSBpbiBhIHNpbXBsZSBBcnJheSBmb3JtICh1bmxlc3Mgbm90ZWQgb3RoZXJ3aXNlKSwgc28gdGhlIGJvdW5kcyBleGFtcGxlIGFib3ZlIGNhbiBiZSBwYXNzZWQgbGlrZSB0aGlzOlxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiBvdGhlckJvdW5kcy5pbnRlcnNlY3RzKFtbMTAsIDEwXSwgWzQwLCA2MF1dKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxuTC5Cb3VuZHMgPSBmdW5jdGlvbiAoYSwgYikge1xyXG5cdGlmICghYSkgeyByZXR1cm47IH1cclxuXHJcblx0dmFyIHBvaW50cyA9IGIgPyBbYSwgYl0gOiBhO1xyXG5cclxuXHRmb3IgKHZhciBpID0gMCwgbGVuID0gcG9pbnRzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHR0aGlzLmV4dGVuZChwb2ludHNbaV0pO1xyXG5cdH1cclxufTtcclxuXHJcbkwuQm91bmRzLnByb3RvdHlwZSA9IHtcclxuXHQvLyBAbWV0aG9kIGV4dGVuZChwb2ludDogUG9pbnQpOiB0aGlzXHJcblx0Ly8gRXh0ZW5kcyB0aGUgYm91bmRzIHRvIGNvbnRhaW4gdGhlIGdpdmVuIHBvaW50LlxyXG5cdGV4dGVuZDogZnVuY3Rpb24gKHBvaW50KSB7IC8vIChQb2ludClcclxuXHRcdHBvaW50ID0gTC5wb2ludChwb2ludCk7XHJcblxyXG5cdFx0Ly8gQHByb3BlcnR5IG1pbjogUG9pbnRcclxuXHRcdC8vIFRoZSB0b3AgbGVmdCBjb3JuZXIgb2YgdGhlIHJlY3RhbmdsZS5cclxuXHRcdC8vIEBwcm9wZXJ0eSBtYXg6IFBvaW50XHJcblx0XHQvLyBUaGUgYm90dG9tIHJpZ2h0IGNvcm5lciBvZiB0aGUgcmVjdGFuZ2xlLlxyXG5cdFx0aWYgKCF0aGlzLm1pbiAmJiAhdGhpcy5tYXgpIHtcclxuXHRcdFx0dGhpcy5taW4gPSBwb2ludC5jbG9uZSgpO1xyXG5cdFx0XHR0aGlzLm1heCA9IHBvaW50LmNsb25lKCk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR0aGlzLm1pbi54ID0gTWF0aC5taW4ocG9pbnQueCwgdGhpcy5taW4ueCk7XHJcblx0XHRcdHRoaXMubWF4LnggPSBNYXRoLm1heChwb2ludC54LCB0aGlzLm1heC54KTtcclxuXHRcdFx0dGhpcy5taW4ueSA9IE1hdGgubWluKHBvaW50LnksIHRoaXMubWluLnkpO1xyXG5cdFx0XHR0aGlzLm1heC55ID0gTWF0aC5tYXgocG9pbnQueSwgdGhpcy5tYXgueSk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldENlbnRlcihyb3VuZD86IEJvb2xlYW4pOiBQb2ludFxyXG5cdC8vIFJldHVybnMgdGhlIGNlbnRlciBwb2ludCBvZiB0aGUgYm91bmRzLlxyXG5cdGdldENlbnRlcjogZnVuY3Rpb24gKHJvdW5kKSB7XHJcblx0XHRyZXR1cm4gbmV3IEwuUG9pbnQoXHJcblx0XHQgICAgICAgICh0aGlzLm1pbi54ICsgdGhpcy5tYXgueCkgLyAyLFxyXG5cdFx0ICAgICAgICAodGhpcy5taW4ueSArIHRoaXMubWF4LnkpIC8gMiwgcm91bmQpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Qm90dG9tTGVmdCgpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgdGhlIGJvdHRvbS1sZWZ0IHBvaW50IG9mIHRoZSBib3VuZHMuXHJcblx0Z2V0Qm90dG9tTGVmdDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIG5ldyBMLlBvaW50KHRoaXMubWluLngsIHRoaXMubWF4LnkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0VG9wUmlnaHQoKTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIHRoZSB0b3AtcmlnaHQgcG9pbnQgb2YgdGhlIGJvdW5kcy5cclxuXHRnZXRUb3BSaWdodDogZnVuY3Rpb24gKCkgeyAvLyAtPiBQb2ludFxyXG5cdFx0cmV0dXJuIG5ldyBMLlBvaW50KHRoaXMubWF4LngsIHRoaXMubWluLnkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0U2l6ZSgpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgdGhlIHNpemUgb2YgdGhlIGdpdmVuIGJvdW5kc1xyXG5cdGdldFNpemU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLm1heC5zdWJ0cmFjdCh0aGlzLm1pbik7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjb250YWlucyhvdGhlckJvdW5kczogQm91bmRzKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSByZWN0YW5nbGUgY29udGFpbnMgdGhlIGdpdmVuIG9uZS5cclxuXHQvLyBAYWx0ZXJuYXRpdmVcclxuXHQvLyBAbWV0aG9kIGNvbnRhaW5zKHBvaW50OiBQb2ludCk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcmVjdGFuZ2xlIGNvbnRhaW5zIHRoZSBnaXZlbiBwb2ludC5cclxuXHRjb250YWluczogZnVuY3Rpb24gKG9iaikge1xyXG5cdFx0dmFyIG1pbiwgbWF4O1xyXG5cclxuXHRcdGlmICh0eXBlb2Ygb2JqWzBdID09PSAnbnVtYmVyJyB8fCBvYmogaW5zdGFuY2VvZiBMLlBvaW50KSB7XHJcblx0XHRcdG9iaiA9IEwucG9pbnQob2JqKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdG9iaiA9IEwuYm91bmRzKG9iaik7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKG9iaiBpbnN0YW5jZW9mIEwuQm91bmRzKSB7XHJcblx0XHRcdG1pbiA9IG9iai5taW47XHJcblx0XHRcdG1heCA9IG9iai5tYXg7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRtaW4gPSBtYXggPSBvYmo7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIChtaW4ueCA+PSB0aGlzLm1pbi54KSAmJlxyXG5cdFx0ICAgICAgIChtYXgueCA8PSB0aGlzLm1heC54KSAmJlxyXG5cdFx0ICAgICAgIChtaW4ueSA+PSB0aGlzLm1pbi55KSAmJlxyXG5cdFx0ICAgICAgIChtYXgueSA8PSB0aGlzLm1heC55KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGludGVyc2VjdHMob3RoZXJCb3VuZHM6IEJvdW5kcyk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcmVjdGFuZ2xlIGludGVyc2VjdHMgdGhlIGdpdmVuIGJvdW5kcy4gVHdvIGJvdW5kc1xyXG5cdC8vIGludGVyc2VjdCBpZiB0aGV5IGhhdmUgYXQgbGVhc3Qgb25lIHBvaW50IGluIGNvbW1vbi5cclxuXHRpbnRlcnNlY3RzOiBmdW5jdGlvbiAoYm91bmRzKSB7IC8vIChCb3VuZHMpIC0+IEJvb2xlYW5cclxuXHRcdGJvdW5kcyA9IEwuYm91bmRzKGJvdW5kcyk7XHJcblxyXG5cdFx0dmFyIG1pbiA9IHRoaXMubWluLFxyXG5cdFx0ICAgIG1heCA9IHRoaXMubWF4LFxyXG5cdFx0ICAgIG1pbjIgPSBib3VuZHMubWluLFxyXG5cdFx0ICAgIG1heDIgPSBib3VuZHMubWF4LFxyXG5cdFx0ICAgIHhJbnRlcnNlY3RzID0gKG1heDIueCA+PSBtaW4ueCkgJiYgKG1pbjIueCA8PSBtYXgueCksXHJcblx0XHQgICAgeUludGVyc2VjdHMgPSAobWF4Mi55ID49IG1pbi55KSAmJiAobWluMi55IDw9IG1heC55KTtcclxuXHJcblx0XHRyZXR1cm4geEludGVyc2VjdHMgJiYgeUludGVyc2VjdHM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBvdmVybGFwcyhvdGhlckJvdW5kczogQm91bmRzKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSByZWN0YW5nbGUgb3ZlcmxhcHMgdGhlIGdpdmVuIGJvdW5kcy4gVHdvIGJvdW5kc1xyXG5cdC8vIG92ZXJsYXAgaWYgdGhlaXIgaW50ZXJzZWN0aW9uIGlzIGFuIGFyZWEuXHJcblx0b3ZlcmxhcHM6IGZ1bmN0aW9uIChib3VuZHMpIHsgLy8gKEJvdW5kcykgLT4gQm9vbGVhblxyXG5cdFx0Ym91bmRzID0gTC5ib3VuZHMoYm91bmRzKTtcclxuXHJcblx0XHR2YXIgbWluID0gdGhpcy5taW4sXHJcblx0XHQgICAgbWF4ID0gdGhpcy5tYXgsXHJcblx0XHQgICAgbWluMiA9IGJvdW5kcy5taW4sXHJcblx0XHQgICAgbWF4MiA9IGJvdW5kcy5tYXgsXHJcblx0XHQgICAgeE92ZXJsYXBzID0gKG1heDIueCA+IG1pbi54KSAmJiAobWluMi54IDwgbWF4LngpLFxyXG5cdFx0ICAgIHlPdmVybGFwcyA9IChtYXgyLnkgPiBtaW4ueSkgJiYgKG1pbjIueSA8IG1heC55KTtcclxuXHJcblx0XHRyZXR1cm4geE92ZXJsYXBzICYmIHlPdmVybGFwcztcclxuXHR9LFxyXG5cclxuXHRpc1ZhbGlkOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gISEodGhpcy5taW4gJiYgdGhpcy5tYXgpO1xyXG5cdH1cclxufTtcclxuXHJcblxyXG4vLyBAZmFjdG9yeSBMLmJvdW5kcyh0b3BMZWZ0OiBQb2ludCwgYm90dG9tUmlnaHQ6IFBvaW50KVxyXG4vLyBDcmVhdGVzIGEgQm91bmRzIG9iamVjdCBmcm9tIHR3byBjb29yZGluYXRlcyAodXN1YWxseSB0b3AtbGVmdCBhbmQgYm90dG9tLXJpZ2h0IGNvcm5lcnMpLlxyXG4vLyBAYWx0ZXJuYXRpdmVcclxuLy8gQGZhY3RvcnkgTC5ib3VuZHMocG9pbnRzOiBQb2ludFtdKVxyXG4vLyBDcmVhdGVzIGEgQm91bmRzIG9iamVjdCBmcm9tIHRoZSBwb2ludHMgaXQgY29udGFpbnNcclxuTC5ib3VuZHMgPSBmdW5jdGlvbiAoYSwgYikge1xyXG5cdGlmICghYSB8fCBhIGluc3RhbmNlb2YgTC5Cb3VuZHMpIHtcclxuXHRcdHJldHVybiBhO1xyXG5cdH1cclxuXHRyZXR1cm4gbmV3IEwuQm91bmRzKGEsIGIpO1xyXG59O1xyXG5cblxuXG4vKlxyXG4gKiBAY2xhc3MgVHJhbnNmb3JtYXRpb25cclxuICogQGFrYSBMLlRyYW5zZm9ybWF0aW9uXHJcbiAqXHJcbiAqIFJlcHJlc2VudHMgYW4gYWZmaW5lIHRyYW5zZm9ybWF0aW9uOiBhIHNldCBvZiBjb2VmZmljaWVudHMgYGFgLCBgYmAsIGBjYCwgYGRgXHJcbiAqIGZvciB0cmFuc2Zvcm1pbmcgYSBwb2ludCBvZiBhIGZvcm0gYCh4LCB5KWAgaW50byBgKGEqeCArIGIsIGMqeSArIGQpYCBhbmQgZG9pbmdcclxuICogdGhlIHJldmVyc2UuIFVzZWQgYnkgTGVhZmxldCBpbiBpdHMgcHJvamVjdGlvbnMgY29kZS5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogdmFyIHRyYW5zZm9ybWF0aW9uID0gbmV3IEwuVHJhbnNmb3JtYXRpb24oMiwgNSwgLTEsIDEwKSxcclxuICogXHRwID0gTC5wb2ludCgxLCAyKSxcclxuICogXHRwMiA9IHRyYW5zZm9ybWF0aW9uLnRyYW5zZm9ybShwKSwgLy8gIEwucG9pbnQoNywgOClcclxuICogXHRwMyA9IHRyYW5zZm9ybWF0aW9uLnVudHJhbnNmb3JtKHAyKTsgLy8gIEwucG9pbnQoMSwgMilcclxuICogYGBgXHJcbiAqL1xyXG5cclxuXHJcbi8vIGZhY3RvcnkgbmV3IEwuVHJhbnNmb3JtYXRpb24oYTogTnVtYmVyLCBiOiBOdW1iZXIsIGM6IE51bWJlciwgZDogTnVtYmVyKVxyXG4vLyBDcmVhdGVzIGEgYFRyYW5zZm9ybWF0aW9uYCBvYmplY3Qgd2l0aCB0aGUgZ2l2ZW4gY29lZmZpY2llbnRzLlxyXG5MLlRyYW5zZm9ybWF0aW9uID0gZnVuY3Rpb24gKGEsIGIsIGMsIGQpIHtcclxuXHR0aGlzLl9hID0gYTtcclxuXHR0aGlzLl9iID0gYjtcclxuXHR0aGlzLl9jID0gYztcclxuXHR0aGlzLl9kID0gZDtcclxufTtcclxuXHJcbkwuVHJhbnNmb3JtYXRpb24ucHJvdG90eXBlID0ge1xyXG5cdC8vIEBtZXRob2QgdHJhbnNmb3JtKHBvaW50OiBQb2ludCwgc2NhbGU/OiBOdW1iZXIpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgYSB0cmFuc2Zvcm1lZCBwb2ludCwgb3B0aW9uYWxseSBtdWx0aXBsaWVkIGJ5IHRoZSBnaXZlbiBzY2FsZS5cclxuXHQvLyBPbmx5IGFjY2VwdHMgYWN0dWFsIGBMLlBvaW50YCBpbnN0YW5jZXMsIG5vdCBhcnJheXMuXHJcblx0dHJhbnNmb3JtOiBmdW5jdGlvbiAocG9pbnQsIHNjYWxlKSB7IC8vIChQb2ludCwgTnVtYmVyKSAtPiBQb2ludFxyXG5cdFx0cmV0dXJuIHRoaXMuX3RyYW5zZm9ybShwb2ludC5jbG9uZSgpLCBzY2FsZSk7XHJcblx0fSxcclxuXHJcblx0Ly8gZGVzdHJ1Y3RpdmUgdHJhbnNmb3JtIChmYXN0ZXIpXHJcblx0X3RyYW5zZm9ybTogZnVuY3Rpb24gKHBvaW50LCBzY2FsZSkge1xyXG5cdFx0c2NhbGUgPSBzY2FsZSB8fCAxO1xyXG5cdFx0cG9pbnQueCA9IHNjYWxlICogKHRoaXMuX2EgKiBwb2ludC54ICsgdGhpcy5fYik7XHJcblx0XHRwb2ludC55ID0gc2NhbGUgKiAodGhpcy5fYyAqIHBvaW50LnkgKyB0aGlzLl9kKTtcclxuXHRcdHJldHVybiBwb2ludDtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHVudHJhbnNmb3JtKHBvaW50OiBQb2ludCwgc2NhbGU/OiBOdW1iZXIpOiBQb2ludFxyXG5cdC8vIFJldHVybnMgdGhlIHJldmVyc2UgdHJhbnNmb3JtYXRpb24gb2YgdGhlIGdpdmVuIHBvaW50LCBvcHRpb25hbGx5IGRpdmlkZWRcclxuXHQvLyBieSB0aGUgZ2l2ZW4gc2NhbGUuIE9ubHkgYWNjZXB0cyBhY3R1YWwgYEwuUG9pbnRgIGluc3RhbmNlcywgbm90IGFycmF5cy5cclxuXHR1bnRyYW5zZm9ybTogZnVuY3Rpb24gKHBvaW50LCBzY2FsZSkge1xyXG5cdFx0c2NhbGUgPSBzY2FsZSB8fCAxO1xyXG5cdFx0cmV0dXJuIG5ldyBMLlBvaW50KFxyXG5cdFx0ICAgICAgICAocG9pbnQueCAvIHNjYWxlIC0gdGhpcy5fYikgLyB0aGlzLl9hLFxyXG5cdFx0ICAgICAgICAocG9pbnQueSAvIHNjYWxlIC0gdGhpcy5fZCkgLyB0aGlzLl9jKTtcclxuXHR9XHJcbn07XHJcblxuXG5cbi8qXHJcbiAqIEBuYW1lc3BhY2UgRG9tVXRpbFxyXG4gKlxyXG4gKiBVdGlsaXR5IGZ1bmN0aW9ucyB0byB3b3JrIHdpdGggdGhlIFtET01dKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0FQSS9Eb2N1bWVudF9PYmplY3RfTW9kZWwpXHJcbiAqIHRyZWUsIHVzZWQgYnkgTGVhZmxldCBpbnRlcm5hbGx5LlxyXG4gKlxyXG4gKiBNb3N0IGZ1bmN0aW9ucyBleHBlY3Rpbmcgb3IgcmV0dXJuaW5nIGEgYEhUTUxFbGVtZW50YCBhbHNvIHdvcmsgZm9yXHJcbiAqIFNWRyBlbGVtZW50cy4gVGhlIG9ubHkgZGlmZmVyZW5jZSBpcyB0aGF0IGNsYXNzZXMgcmVmZXIgdG8gQ1NTIGNsYXNzZXNcclxuICogaW4gSFRNTCBhbmQgU1ZHIGNsYXNzZXMgaW4gU1ZHLlxyXG4gKi9cclxuXHJcbkwuRG9tVXRpbCA9IHtcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIGdldChpZDogU3RyaW5nfEhUTUxFbGVtZW50KTogSFRNTEVsZW1lbnRcclxuXHQvLyBSZXR1cm5zIGFuIGVsZW1lbnQgZ2l2ZW4gaXRzIERPTSBpZCwgb3IgcmV0dXJucyB0aGUgZWxlbWVudCBpdHNlbGZcclxuXHQvLyBpZiBpdCB3YXMgcGFzc2VkIGRpcmVjdGx5LlxyXG5cdGdldDogZnVuY3Rpb24gKGlkKSB7XHJcblx0XHRyZXR1cm4gdHlwZW9mIGlkID09PSAnc3RyaW5nJyA/IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKSA6IGlkO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBnZXRTdHlsZShlbDogSFRNTEVsZW1lbnQsIHN0eWxlQXR0cmliOiBTdHJpbmcpOiBTdHJpbmdcclxuXHQvLyBSZXR1cm5zIHRoZSB2YWx1ZSBmb3IgYSBjZXJ0YWluIHN0eWxlIGF0dHJpYnV0ZSBvbiBhbiBlbGVtZW50LFxyXG5cdC8vIGluY2x1ZGluZyBjb21wdXRlZCB2YWx1ZXMgb3IgdmFsdWVzIHNldCB0aHJvdWdoIENTUy5cclxuXHRnZXRTdHlsZTogZnVuY3Rpb24gKGVsLCBzdHlsZSkge1xyXG5cclxuXHRcdHZhciB2YWx1ZSA9IGVsLnN0eWxlW3N0eWxlXSB8fCAoZWwuY3VycmVudFN0eWxlICYmIGVsLmN1cnJlbnRTdHlsZVtzdHlsZV0pO1xyXG5cclxuXHRcdGlmICgoIXZhbHVlIHx8IHZhbHVlID09PSAnYXV0bycpICYmIGRvY3VtZW50LmRlZmF1bHRWaWV3KSB7XHJcblx0XHRcdHZhciBjc3MgPSBkb2N1bWVudC5kZWZhdWx0Vmlldy5nZXRDb21wdXRlZFN0eWxlKGVsLCBudWxsKTtcclxuXHRcdFx0dmFsdWUgPSBjc3MgPyBjc3Nbc3R5bGVdIDogbnVsbDtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdmFsdWUgPT09ICdhdXRvJyA/IG51bGwgOiB2YWx1ZTtcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gY3JlYXRlKHRhZ05hbWU6IFN0cmluZywgY2xhc3NOYW1lPzogU3RyaW5nLCBjb250YWluZXI/OiBIVE1MRWxlbWVudCk6IEhUTUxFbGVtZW50XHJcblx0Ly8gQ3JlYXRlcyBhbiBIVE1MIGVsZW1lbnQgd2l0aCBgdGFnTmFtZWAsIHNldHMgaXRzIGNsYXNzIHRvIGBjbGFzc05hbWVgLCBhbmQgb3B0aW9uYWxseSBhcHBlbmRzIGl0IHRvIGBjb250YWluZXJgIGVsZW1lbnQuXHJcblx0Y3JlYXRlOiBmdW5jdGlvbiAodGFnTmFtZSwgY2xhc3NOYW1lLCBjb250YWluZXIpIHtcclxuXHJcblx0XHR2YXIgZWwgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KHRhZ05hbWUpO1xyXG5cdFx0ZWwuY2xhc3NOYW1lID0gY2xhc3NOYW1lIHx8ICcnO1xyXG5cclxuXHRcdGlmIChjb250YWluZXIpIHtcclxuXHRcdFx0Y29udGFpbmVyLmFwcGVuZENoaWxkKGVsKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZWw7XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHJlbW92ZShlbDogSFRNTEVsZW1lbnQpXHJcblx0Ly8gUmVtb3ZlcyBgZWxgIGZyb20gaXRzIHBhcmVudCBlbGVtZW50XHJcblx0cmVtb3ZlOiBmdW5jdGlvbiAoZWwpIHtcclxuXHRcdHZhciBwYXJlbnQgPSBlbC5wYXJlbnROb2RlO1xyXG5cdFx0aWYgKHBhcmVudCkge1xyXG5cdFx0XHRwYXJlbnQucmVtb3ZlQ2hpbGQoZWwpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBlbXB0eShlbDogSFRNTEVsZW1lbnQpXHJcblx0Ly8gUmVtb3ZlcyBhbGwgb2YgYGVsYCdzIGNoaWxkcmVuIGVsZW1lbnRzIGZyb20gYGVsYFxyXG5cdGVtcHR5OiBmdW5jdGlvbiAoZWwpIHtcclxuXHRcdHdoaWxlIChlbC5maXJzdENoaWxkKSB7XHJcblx0XHRcdGVsLnJlbW92ZUNoaWxkKGVsLmZpcnN0Q2hpbGQpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiB0b0Zyb250KGVsOiBIVE1MRWxlbWVudClcclxuXHQvLyBNYWtlcyBgZWxgIHRoZSBsYXN0IGNoaWxkcmVuIG9mIGl0cyBwYXJlbnQsIHNvIGl0IHJlbmRlcnMgaW4gZnJvbnQgb2YgdGhlIG90aGVyIGNoaWxkcmVuLlxyXG5cdHRvRnJvbnQ6IGZ1bmN0aW9uIChlbCkge1xyXG5cdFx0ZWwucGFyZW50Tm9kZS5hcHBlbmRDaGlsZChlbCk7XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHRvQmFjayhlbDogSFRNTEVsZW1lbnQpXHJcblx0Ly8gTWFrZXMgYGVsYCB0aGUgZmlyc3QgY2hpbGRyZW4gb2YgaXRzIHBhcmVudCwgc28gaXQgcmVuZGVycyBiYWNrIGZyb20gdGhlIG90aGVyIGNoaWxkcmVuLlxyXG5cdHRvQmFjazogZnVuY3Rpb24gKGVsKSB7XHJcblx0XHR2YXIgcGFyZW50ID0gZWwucGFyZW50Tm9kZTtcclxuXHRcdHBhcmVudC5pbnNlcnRCZWZvcmUoZWwsIHBhcmVudC5maXJzdENoaWxkKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gaGFzQ2xhc3MoZWw6IEhUTUxFbGVtZW50LCBuYW1lOiBTdHJpbmcpOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGVsZW1lbnQncyBjbGFzcyBhdHRyaWJ1dGUgY29udGFpbnMgYG5hbWVgLlxyXG5cdGhhc0NsYXNzOiBmdW5jdGlvbiAoZWwsIG5hbWUpIHtcclxuXHRcdGlmIChlbC5jbGFzc0xpc3QgIT09IHVuZGVmaW5lZCkge1xyXG5cdFx0XHRyZXR1cm4gZWwuY2xhc3NMaXN0LmNvbnRhaW5zKG5hbWUpO1xyXG5cdFx0fVxyXG5cdFx0dmFyIGNsYXNzTmFtZSA9IEwuRG9tVXRpbC5nZXRDbGFzcyhlbCk7XHJcblx0XHRyZXR1cm4gY2xhc3NOYW1lLmxlbmd0aCA+IDAgJiYgbmV3IFJlZ0V4cCgnKF58XFxcXHMpJyArIG5hbWUgKyAnKFxcXFxzfCQpJykudGVzdChjbGFzc05hbWUpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBhZGRDbGFzcyhlbDogSFRNTEVsZW1lbnQsIG5hbWU6IFN0cmluZylcclxuXHQvLyBBZGRzIGBuYW1lYCB0byB0aGUgZWxlbWVudCdzIGNsYXNzIGF0dHJpYnV0ZS5cclxuXHRhZGRDbGFzczogZnVuY3Rpb24gKGVsLCBuYW1lKSB7XHJcblx0XHRpZiAoZWwuY2xhc3NMaXN0ICE9PSB1bmRlZmluZWQpIHtcclxuXHRcdFx0dmFyIGNsYXNzZXMgPSBMLlV0aWwuc3BsaXRXb3JkcyhuYW1lKTtcclxuXHRcdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IGNsYXNzZXMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0XHRlbC5jbGFzc0xpc3QuYWRkKGNsYXNzZXNbaV0pO1xyXG5cdFx0XHR9XHJcblx0XHR9IGVsc2UgaWYgKCFMLkRvbVV0aWwuaGFzQ2xhc3MoZWwsIG5hbWUpKSB7XHJcblx0XHRcdHZhciBjbGFzc05hbWUgPSBMLkRvbVV0aWwuZ2V0Q2xhc3MoZWwpO1xyXG5cdFx0XHRMLkRvbVV0aWwuc2V0Q2xhc3MoZWwsIChjbGFzc05hbWUgPyBjbGFzc05hbWUgKyAnICcgOiAnJykgKyBuYW1lKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gcmVtb3ZlQ2xhc3MoZWw6IEhUTUxFbGVtZW50LCBuYW1lOiBTdHJpbmcpXHJcblx0Ly8gUmVtb3ZlcyBgbmFtZWAgZnJvbSB0aGUgZWxlbWVudCdzIGNsYXNzIGF0dHJpYnV0ZS5cclxuXHRyZW1vdmVDbGFzczogZnVuY3Rpb24gKGVsLCBuYW1lKSB7XHJcblx0XHRpZiAoZWwuY2xhc3NMaXN0ICE9PSB1bmRlZmluZWQpIHtcclxuXHRcdFx0ZWwuY2xhc3NMaXN0LnJlbW92ZShuYW1lKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdEwuRG9tVXRpbC5zZXRDbGFzcyhlbCwgTC5VdGlsLnRyaW0oKCcgJyArIEwuRG9tVXRpbC5nZXRDbGFzcyhlbCkgKyAnICcpLnJlcGxhY2UoJyAnICsgbmFtZSArICcgJywgJyAnKSkpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBzZXRDbGFzcyhlbDogSFRNTEVsZW1lbnQsIG5hbWU6IFN0cmluZylcclxuXHQvLyBTZXRzIHRoZSBlbGVtZW50J3MgY2xhc3MuXHJcblx0c2V0Q2xhc3M6IGZ1bmN0aW9uIChlbCwgbmFtZSkge1xyXG5cdFx0aWYgKGVsLmNsYXNzTmFtZS5iYXNlVmFsID09PSB1bmRlZmluZWQpIHtcclxuXHRcdFx0ZWwuY2xhc3NOYW1lID0gbmFtZTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdC8vIGluIGNhc2Ugb2YgU1ZHIGVsZW1lbnRcclxuXHRcdFx0ZWwuY2xhc3NOYW1lLmJhc2VWYWwgPSBuYW1lO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBnZXRDbGFzcyhlbDogSFRNTEVsZW1lbnQpOiBTdHJpbmdcclxuXHQvLyBSZXR1cm5zIHRoZSBlbGVtZW50J3MgY2xhc3MuXHJcblx0Z2V0Q2xhc3M6IGZ1bmN0aW9uIChlbCkge1xyXG5cdFx0cmV0dXJuIGVsLmNsYXNzTmFtZS5iYXNlVmFsID09PSB1bmRlZmluZWQgPyBlbC5jbGFzc05hbWUgOiBlbC5jbGFzc05hbWUuYmFzZVZhbDtcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gc2V0T3BhY2l0eShlbDogSFRNTEVsZW1lbnQsIG9wYWNpdHk6IE51bWJlcilcclxuXHQvLyBTZXQgdGhlIG9wYWNpdHkgb2YgYW4gZWxlbWVudCAoaW5jbHVkaW5nIG9sZCBJRSBzdXBwb3J0KS5cclxuXHQvLyBgb3BhY2l0eWAgbXVzdCBiZSBhIG51bWJlciBmcm9tIGAwYCB0byBgMWAuXHJcblx0c2V0T3BhY2l0eTogZnVuY3Rpb24gKGVsLCB2YWx1ZSkge1xyXG5cclxuXHRcdGlmICgnb3BhY2l0eScgaW4gZWwuc3R5bGUpIHtcclxuXHRcdFx0ZWwuc3R5bGUub3BhY2l0eSA9IHZhbHVlO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoJ2ZpbHRlcicgaW4gZWwuc3R5bGUpIHtcclxuXHRcdFx0TC5Eb21VdGlsLl9zZXRPcGFjaXR5SUUoZWwsIHZhbHVlKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfc2V0T3BhY2l0eUlFOiBmdW5jdGlvbiAoZWwsIHZhbHVlKSB7XHJcblx0XHR2YXIgZmlsdGVyID0gZmFsc2UsXHJcblx0XHQgICAgZmlsdGVyTmFtZSA9ICdEWEltYWdlVHJhbnNmb3JtLk1pY3Jvc29mdC5BbHBoYSc7XHJcblxyXG5cdFx0Ly8gZmlsdGVycyBjb2xsZWN0aW9uIHRocm93cyBhbiBlcnJvciBpZiB3ZSB0cnkgdG8gcmV0cmlldmUgYSBmaWx0ZXIgdGhhdCBkb2Vzbid0IGV4aXN0XHJcblx0XHR0cnkge1xyXG5cdFx0XHRmaWx0ZXIgPSBlbC5maWx0ZXJzLml0ZW0oZmlsdGVyTmFtZSk7XHJcblx0XHR9IGNhdGNoIChlKSB7XHJcblx0XHRcdC8vIGRvbid0IHNldCBvcGFjaXR5IHRvIDEgaWYgd2UgaGF2ZW4ndCBhbHJlYWR5IHNldCBhbiBvcGFjaXR5LFxyXG5cdFx0XHQvLyBpdCBpc24ndCBuZWVkZWQgYW5kIGJyZWFrcyB0cmFuc3BhcmVudCBwbmdzLlxyXG5cdFx0XHRpZiAodmFsdWUgPT09IDEpIHsgcmV0dXJuOyB9XHJcblx0XHR9XHJcblxyXG5cdFx0dmFsdWUgPSBNYXRoLnJvdW5kKHZhbHVlICogMTAwKTtcclxuXHJcblx0XHRpZiAoZmlsdGVyKSB7XHJcblx0XHRcdGZpbHRlci5FbmFibGVkID0gKHZhbHVlICE9PSAxMDApO1xyXG5cdFx0XHRmaWx0ZXIuT3BhY2l0eSA9IHZhbHVlO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0ZWwuc3R5bGUuZmlsdGVyICs9ICcgcHJvZ2lkOicgKyBmaWx0ZXJOYW1lICsgJyhvcGFjaXR5PScgKyB2YWx1ZSArICcpJztcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gdGVzdFByb3AocHJvcHM6IFN0cmluZ1tdKTogU3RyaW5nfGZhbHNlXHJcblx0Ly8gR29lcyB0aHJvdWdoIHRoZSBhcnJheSBvZiBzdHlsZSBuYW1lcyBhbmQgcmV0dXJucyB0aGUgZmlyc3QgbmFtZVxyXG5cdC8vIHRoYXQgaXMgYSB2YWxpZCBzdHlsZSBuYW1lIGZvciBhbiBlbGVtZW50LiBJZiBubyBzdWNoIG5hbWUgaXMgZm91bmQsXHJcblx0Ly8gaXQgcmV0dXJucyBmYWxzZS4gVXNlZnVsIGZvciB2ZW5kb3ItcHJlZml4ZWQgc3R5bGVzIGxpa2UgYHRyYW5zZm9ybWAuXHJcblx0dGVzdFByb3A6IGZ1bmN0aW9uIChwcm9wcykge1xyXG5cclxuXHRcdHZhciBzdHlsZSA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZTtcclxuXHJcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHByb3BzLmxlbmd0aDsgaSsrKSB7XHJcblx0XHRcdGlmIChwcm9wc1tpXSBpbiBzdHlsZSkge1xyXG5cdFx0XHRcdHJldHVybiBwcm9wc1tpXTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIGZhbHNlO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBzZXRUcmFuc2Zvcm0oZWw6IEhUTUxFbGVtZW50LCBvZmZzZXQ6IFBvaW50LCBzY2FsZT86IE51bWJlcilcclxuXHQvLyBSZXNldHMgdGhlIDNEIENTUyB0cmFuc2Zvcm0gb2YgYGVsYCBzbyBpdCBpcyB0cmFuc2xhdGVkIGJ5IGBvZmZzZXRgIHBpeGVsc1xyXG5cdC8vIGFuZCBvcHRpb25hbGx5IHNjYWxlZCBieSBgc2NhbGVgLiBEb2VzIG5vdCBoYXZlIGFuIGVmZmVjdCBpZiB0aGVcclxuXHQvLyBicm93c2VyIGRvZXNuJ3Qgc3VwcG9ydCAzRCBDU1MgdHJhbnNmb3Jtcy5cclxuXHRzZXRUcmFuc2Zvcm06IGZ1bmN0aW9uIChlbCwgb2Zmc2V0LCBzY2FsZSkge1xyXG5cdFx0dmFyIHBvcyA9IG9mZnNldCB8fCBuZXcgTC5Qb2ludCgwLCAwKTtcclxuXHJcblx0XHRlbC5zdHlsZVtMLkRvbVV0aWwuVFJBTlNGT1JNXSA9XHJcblx0XHRcdChMLkJyb3dzZXIuaWUzZCA/XHJcblx0XHRcdFx0J3RyYW5zbGF0ZSgnICsgcG9zLnggKyAncHgsJyArIHBvcy55ICsgJ3B4KScgOlxyXG5cdFx0XHRcdCd0cmFuc2xhdGUzZCgnICsgcG9zLnggKyAncHgsJyArIHBvcy55ICsgJ3B4LDApJykgK1xyXG5cdFx0XHQoc2NhbGUgPyAnIHNjYWxlKCcgKyBzY2FsZSArICcpJyA6ICcnKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gc2V0UG9zaXRpb24oZWw6IEhUTUxFbGVtZW50LCBwb3NpdGlvbjogUG9pbnQpXHJcblx0Ly8gU2V0cyB0aGUgcG9zaXRpb24gb2YgYGVsYCB0byBjb29yZGluYXRlcyBzcGVjaWZpZWQgYnkgYHBvc2l0aW9uYCxcclxuXHQvLyB1c2luZyBDU1MgdHJhbnNsYXRlIG9yIHRvcC9sZWZ0IHBvc2l0aW9uaW5nIGRlcGVuZGluZyBvbiB0aGUgYnJvd3NlclxyXG5cdC8vICh1c2VkIGJ5IExlYWZsZXQgaW50ZXJuYWxseSB0byBwb3NpdGlvbiBpdHMgbGF5ZXJzKS5cclxuXHRzZXRQb3NpdGlvbjogZnVuY3Rpb24gKGVsLCBwb2ludCkgeyAvLyAoSFRNTEVsZW1lbnQsIFBvaW50WywgQm9vbGVhbl0pXHJcblxyXG5cdFx0Lyplc2xpbnQtZGlzYWJsZSAqL1xyXG5cdFx0ZWwuX2xlYWZsZXRfcG9zID0gcG9pbnQ7XHJcblx0XHQvKmVzbGludC1lbmFibGUgKi9cclxuXHJcblx0XHRpZiAoTC5Ccm93c2VyLmFueTNkKSB7XHJcblx0XHRcdEwuRG9tVXRpbC5zZXRUcmFuc2Zvcm0oZWwsIHBvaW50KTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGVsLnN0eWxlLmxlZnQgPSBwb2ludC54ICsgJ3B4JztcclxuXHRcdFx0ZWwuc3R5bGUudG9wID0gcG9pbnQueSArICdweCc7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIGdldFBvc2l0aW9uKGVsOiBIVE1MRWxlbWVudCk6IFBvaW50XHJcblx0Ly8gUmV0dXJucyB0aGUgY29vcmRpbmF0ZXMgb2YgYW4gZWxlbWVudCBwcmV2aW91c2x5IHBvc2l0aW9uZWQgd2l0aCBzZXRQb3NpdGlvbi5cclxuXHRnZXRQb3NpdGlvbjogZnVuY3Rpb24gKGVsKSB7XHJcblx0XHQvLyB0aGlzIG1ldGhvZCBpcyBvbmx5IHVzZWQgZm9yIGVsZW1lbnRzIHByZXZpb3VzbHkgcG9zaXRpb25lZCB1c2luZyBzZXRQb3NpdGlvbixcclxuXHRcdC8vIHNvIGl0J3Mgc2FmZSB0byBjYWNoZSB0aGUgcG9zaXRpb24gZm9yIHBlcmZvcm1hbmNlXHJcblxyXG5cdFx0cmV0dXJuIGVsLl9sZWFmbGV0X3BvcyB8fCBuZXcgTC5Qb2ludCgwLCAwKTtcclxuXHR9XHJcbn07XHJcblxyXG5cclxuKGZ1bmN0aW9uICgpIHtcclxuXHQvLyBwcmVmaXggc3R5bGUgcHJvcGVydHkgbmFtZXNcclxuXHJcblx0Ly8gQHByb3BlcnR5IFRSQU5TRk9STTogU3RyaW5nXHJcblx0Ly8gVmVuZG9yLXByZWZpeGVkIGZyYW5zZm9ybSBzdHlsZSBuYW1lIChlLmcuIGAnd2Via2l0VHJhbnNmb3JtJ2AgZm9yIFdlYktpdCkuXHJcblx0TC5Eb21VdGlsLlRSQU5TRk9STSA9IEwuRG9tVXRpbC50ZXN0UHJvcChcclxuXHRcdFx0Wyd0cmFuc2Zvcm0nLCAnV2Via2l0VHJhbnNmb3JtJywgJ09UcmFuc2Zvcm0nLCAnTW96VHJhbnNmb3JtJywgJ21zVHJhbnNmb3JtJ10pO1xyXG5cclxuXHJcblx0Ly8gd2Via2l0VHJhbnNpdGlvbiBjb21lcyBmaXJzdCBiZWNhdXNlIHNvbWUgYnJvd3NlciB2ZXJzaW9ucyB0aGF0IGRyb3AgdmVuZG9yIHByZWZpeCBkb24ndCBkb1xyXG5cdC8vIHRoZSBzYW1lIGZvciB0aGUgdHJhbnNpdGlvbmVuZCBldmVudCwgaW4gcGFydGljdWxhciB0aGUgQW5kcm9pZCA0LjEgc3RvY2sgYnJvd3NlclxyXG5cclxuXHQvLyBAcHJvcGVydHkgVFJBTlNJVElPTjogU3RyaW5nXHJcblx0Ly8gVmVuZG9yLXByZWZpeGVkIHRyYW5zZm9ybSBzdHlsZSBuYW1lLlxyXG5cdHZhciB0cmFuc2l0aW9uID0gTC5Eb21VdGlsLlRSQU5TSVRJT04gPSBMLkRvbVV0aWwudGVzdFByb3AoXHJcblx0XHRcdFsnd2Via2l0VHJhbnNpdGlvbicsICd0cmFuc2l0aW9uJywgJ09UcmFuc2l0aW9uJywgJ01velRyYW5zaXRpb24nLCAnbXNUcmFuc2l0aW9uJ10pO1xyXG5cclxuXHRMLkRvbVV0aWwuVFJBTlNJVElPTl9FTkQgPVxyXG5cdFx0XHR0cmFuc2l0aW9uID09PSAnd2Via2l0VHJhbnNpdGlvbicgfHwgdHJhbnNpdGlvbiA9PT0gJ09UcmFuc2l0aW9uJyA/IHRyYW5zaXRpb24gKyAnRW5kJyA6ICd0cmFuc2l0aW9uZW5kJztcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIGRpc2FibGVUZXh0U2VsZWN0aW9uKClcclxuXHQvLyBQcmV2ZW50cyB0aGUgdXNlciBmcm9tIGdlbmVyYXRpbmcgYHNlbGVjdHN0YXJ0YCBET00gZXZlbnRzLCB1c3VhbGx5IGdlbmVyYXRlZFxyXG5cdC8vIHdoZW4gdGhlIHVzZXIgZHJhZ3MgdGhlIG1vdXNlIHRocm91Z2ggYSBwYWdlIHdpdGggdGV4dC4gVXNlZCBpbnRlcm5hbGx5XHJcblx0Ly8gYnkgTGVhZmxldCB0byBvdmVycmlkZSB0aGUgYmVoYXZpb3VyIG9mIGFueSBjbGljay1hbmQtZHJhZyBpbnRlcmFjdGlvbiBvblxyXG5cdC8vIHRoZSBtYXAuIEFmZmVjdHMgZHJhZyBpbnRlcmFjdGlvbnMgb24gdGhlIHdob2xlIGRvY3VtZW50LlxyXG5cclxuXHQvLyBAZnVuY3Rpb24gZW5hYmxlVGV4dFNlbGVjdGlvbigpXHJcblx0Ly8gQ2FuY2VscyB0aGUgZWZmZWN0cyBvZiBhIHByZXZpb3VzIFtgTC5Eb21VdGlsLmRpc2FibGVUZXh0U2VsZWN0aW9uYF0oI2RvbXV0aWwtZGlzYWJsZXRleHRzZWxlY3Rpb24pLlxyXG5cdGlmICgnb25zZWxlY3RzdGFydCcgaW4gZG9jdW1lbnQpIHtcclxuXHRcdEwuRG9tVXRpbC5kaXNhYmxlVGV4dFNlbGVjdGlvbiA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0TC5Eb21FdmVudC5vbih3aW5kb3csICdzZWxlY3RzdGFydCcsIEwuRG9tRXZlbnQucHJldmVudERlZmF1bHQpO1xyXG5cdFx0fTtcclxuXHRcdEwuRG9tVXRpbC5lbmFibGVUZXh0U2VsZWN0aW9uID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRMLkRvbUV2ZW50Lm9mZih3aW5kb3csICdzZWxlY3RzdGFydCcsIEwuRG9tRXZlbnQucHJldmVudERlZmF1bHQpO1xyXG5cdFx0fTtcclxuXHJcblx0fSBlbHNlIHtcclxuXHRcdHZhciB1c2VyU2VsZWN0UHJvcGVydHkgPSBMLkRvbVV0aWwudGVzdFByb3AoXHJcblx0XHRcdFsndXNlclNlbGVjdCcsICdXZWJraXRVc2VyU2VsZWN0JywgJ09Vc2VyU2VsZWN0JywgJ01velVzZXJTZWxlY3QnLCAnbXNVc2VyU2VsZWN0J10pO1xyXG5cclxuXHRcdEwuRG9tVXRpbC5kaXNhYmxlVGV4dFNlbGVjdGlvbiA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdFx0aWYgKHVzZXJTZWxlY3RQcm9wZXJ0eSkge1xyXG5cdFx0XHRcdHZhciBzdHlsZSA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudC5zdHlsZTtcclxuXHRcdFx0XHR0aGlzLl91c2VyU2VsZWN0ID0gc3R5bGVbdXNlclNlbGVjdFByb3BlcnR5XTtcclxuXHRcdFx0XHRzdHlsZVt1c2VyU2VsZWN0UHJvcGVydHldID0gJ25vbmUnO1xyXG5cdFx0XHR9XHJcblx0XHR9O1xyXG5cdFx0TC5Eb21VdGlsLmVuYWJsZVRleHRTZWxlY3Rpb24gPSBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdGlmICh1c2VyU2VsZWN0UHJvcGVydHkpIHtcclxuXHRcdFx0XHRkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuc3R5bGVbdXNlclNlbGVjdFByb3BlcnR5XSA9IHRoaXMuX3VzZXJTZWxlY3Q7XHJcblx0XHRcdFx0ZGVsZXRlIHRoaXMuX3VzZXJTZWxlY3Q7XHJcblx0XHRcdH1cclxuXHRcdH07XHJcblx0fVxyXG5cclxuXHQvLyBAZnVuY3Rpb24gZGlzYWJsZUltYWdlRHJhZygpXHJcblx0Ly8gQXMgW2BMLkRvbVV0aWwuZGlzYWJsZVRleHRTZWxlY3Rpb25gXSgjZG9tdXRpbC1kaXNhYmxldGV4dHNlbGVjdGlvbiksIGJ1dFxyXG5cdC8vIGZvciBgZHJhZ3N0YXJ0YCBET00gZXZlbnRzLCB1c3VhbGx5IGdlbmVyYXRlZCB3aGVuIHRoZSB1c2VyIGRyYWdzIGFuIGltYWdlLlxyXG5cdEwuRG9tVXRpbC5kaXNhYmxlSW1hZ2VEcmFnID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0TC5Eb21FdmVudC5vbih3aW5kb3csICdkcmFnc3RhcnQnLCBMLkRvbUV2ZW50LnByZXZlbnREZWZhdWx0KTtcclxuXHR9O1xyXG5cclxuXHQvLyBAZnVuY3Rpb24gZW5hYmxlSW1hZ2VEcmFnKClcclxuXHQvLyBDYW5jZWxzIHRoZSBlZmZlY3RzIG9mIGEgcHJldmlvdXMgW2BMLkRvbVV0aWwuZGlzYWJsZUltYWdlRHJhZ2BdKCNkb211dGlsLWRpc2FibGV0ZXh0c2VsZWN0aW9uKS5cclxuXHRMLkRvbVV0aWwuZW5hYmxlSW1hZ2VEcmFnID0gZnVuY3Rpb24gKCkge1xyXG5cdFx0TC5Eb21FdmVudC5vZmYod2luZG93LCAnZHJhZ3N0YXJ0JywgTC5Eb21FdmVudC5wcmV2ZW50RGVmYXVsdCk7XHJcblx0fTtcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHByZXZlbnRPdXRsaW5lKGVsOiBIVE1MRWxlbWVudClcclxuXHQvLyBNYWtlcyB0aGUgW291dGxpbmVdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0NTUy9vdXRsaW5lKVxyXG5cdC8vIG9mIHRoZSBlbGVtZW50IGBlbGAgaW52aXNpYmxlLiBVc2VkIGludGVybmFsbHkgYnkgTGVhZmxldCB0byBwcmV2ZW50XHJcblx0Ly8gZm9jdXNhYmxlIGVsZW1lbnRzIGZyb20gZGlzcGxheWluZyBhbiBvdXRsaW5lIHdoZW4gdGhlIHVzZXIgcGVyZm9ybXMgYVxyXG5cdC8vIGRyYWcgaW50ZXJhY3Rpb24gb24gdGhlbS5cclxuXHRMLkRvbVV0aWwucHJldmVudE91dGxpbmUgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xyXG5cdFx0d2hpbGUgKGVsZW1lbnQudGFiSW5kZXggPT09IC0xKSB7XHJcblx0XHRcdGVsZW1lbnQgPSBlbGVtZW50LnBhcmVudE5vZGU7XHJcblx0XHR9XHJcblx0XHRpZiAoIWVsZW1lbnQgfHwgIWVsZW1lbnQuc3R5bGUpIHsgcmV0dXJuOyB9XHJcblx0XHRMLkRvbVV0aWwucmVzdG9yZU91dGxpbmUoKTtcclxuXHRcdHRoaXMuX291dGxpbmVFbGVtZW50ID0gZWxlbWVudDtcclxuXHRcdHRoaXMuX291dGxpbmVTdHlsZSA9IGVsZW1lbnQuc3R5bGUub3V0bGluZTtcclxuXHRcdGVsZW1lbnQuc3R5bGUub3V0bGluZSA9ICdub25lJztcclxuXHRcdEwuRG9tRXZlbnQub24od2luZG93LCAna2V5ZG93bicsIEwuRG9tVXRpbC5yZXN0b3JlT3V0bGluZSwgdGhpcyk7XHJcblx0fTtcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHJlc3RvcmVPdXRsaW5lKClcclxuXHQvLyBDYW5jZWxzIHRoZSBlZmZlY3RzIG9mIGEgcHJldmlvdXMgW2BMLkRvbVV0aWwucHJldmVudE91dGxpbmVgXSgpLlxyXG5cdEwuRG9tVXRpbC5yZXN0b3JlT3V0bGluZSA9IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICghdGhpcy5fb3V0bGluZUVsZW1lbnQpIHsgcmV0dXJuOyB9XHJcblx0XHR0aGlzLl9vdXRsaW5lRWxlbWVudC5zdHlsZS5vdXRsaW5lID0gdGhpcy5fb3V0bGluZVN0eWxlO1xyXG5cdFx0ZGVsZXRlIHRoaXMuX291dGxpbmVFbGVtZW50O1xyXG5cdFx0ZGVsZXRlIHRoaXMuX291dGxpbmVTdHlsZTtcclxuXHRcdEwuRG9tRXZlbnQub2ZmKHdpbmRvdywgJ2tleWRvd24nLCBMLkRvbVV0aWwucmVzdG9yZU91dGxpbmUsIHRoaXMpO1xyXG5cdH07XHJcbn0pKCk7XHJcblxuXG5cbi8qIEBjbGFzcyBMYXRMbmdcclxuICogQGFrYSBMLkxhdExuZ1xyXG4gKlxyXG4gKiBSZXByZXNlbnRzIGEgZ2VvZ3JhcGhpY2FsIHBvaW50IHdpdGggYSBjZXJ0YWluIGxhdGl0dWRlIGFuZCBsb25naXR1ZGUuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYFxyXG4gKiB2YXIgbGF0bG5nID0gTC5sYXRMbmcoNTAuNSwgMzAuNSk7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBBbGwgTGVhZmxldCBtZXRob2RzIHRoYXQgYWNjZXB0IExhdExuZyBvYmplY3RzIGFsc28gYWNjZXB0IHRoZW0gaW4gYSBzaW1wbGUgQXJyYXkgZm9ybSBhbmQgc2ltcGxlIG9iamVjdCBmb3JtICh1bmxlc3Mgbm90ZWQgb3RoZXJ3aXNlKSwgc28gdGhlc2UgbGluZXMgYXJlIGVxdWl2YWxlbnQ6XHJcbiAqXHJcbiAqIGBgYFxyXG4gKiBtYXAucGFuVG8oWzUwLCAzMF0pO1xyXG4gKiBtYXAucGFuVG8oe2xvbjogMzAsIGxhdDogNTB9KTtcclxuICogbWFwLnBhblRvKHtsYXQ6IDUwLCBsbmc6IDMwfSk7XHJcbiAqIG1hcC5wYW5UbyhMLmxhdExuZyg1MCwgMzApKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxuTC5MYXRMbmcgPSBmdW5jdGlvbiAobGF0LCBsbmcsIGFsdCkge1xyXG5cdGlmIChpc05hTihsYXQpIHx8IGlzTmFOKGxuZykpIHtcclxuXHRcdHRocm93IG5ldyBFcnJvcignSW52YWxpZCBMYXRMbmcgb2JqZWN0OiAoJyArIGxhdCArICcsICcgKyBsbmcgKyAnKScpO1xyXG5cdH1cclxuXHJcblx0Ly8gQHByb3BlcnR5IGxhdDogTnVtYmVyXHJcblx0Ly8gTGF0aXR1ZGUgaW4gZGVncmVlc1xyXG5cdHRoaXMubGF0ID0gK2xhdDtcclxuXHJcblx0Ly8gQHByb3BlcnR5IGxuZzogTnVtYmVyXHJcblx0Ly8gTG9uZ2l0dWRlIGluIGRlZ3JlZXNcclxuXHR0aGlzLmxuZyA9ICtsbmc7XHJcblxyXG5cdC8vIEBwcm9wZXJ0eSBhbHQ6IE51bWJlclxyXG5cdC8vIEFsdGl0dWRlIGluIG1ldGVycyAob3B0aW9uYWwpXHJcblx0aWYgKGFsdCAhPT0gdW5kZWZpbmVkKSB7XHJcblx0XHR0aGlzLmFsdCA9ICthbHQ7XHJcblx0fVxyXG59O1xyXG5cclxuTC5MYXRMbmcucHJvdG90eXBlID0ge1xyXG5cdC8vIEBtZXRob2QgZXF1YWxzKG90aGVyTGF0TG5nOiBMYXRMbmcsIG1heE1hcmdpbj86IE51bWJlcik6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgZ2l2ZW4gYExhdExuZ2AgcG9pbnQgaXMgYXQgdGhlIHNhbWUgcG9zaXRpb24gKHdpdGhpbiBhIHNtYWxsIG1hcmdpbiBvZiBlcnJvcikuIFRoZSBtYXJnaW4gb2YgZXJyb3IgY2FuIGJlIG92ZXJyaWRlbiBieSBzZXR0aW5nIGBtYXhNYXJnaW5gIHRvIGEgc21hbGwgbnVtYmVyLlxyXG5cdGVxdWFsczogZnVuY3Rpb24gKG9iaiwgbWF4TWFyZ2luKSB7XHJcblx0XHRpZiAoIW9iaikgeyByZXR1cm4gZmFsc2U7IH1cclxuXHJcblx0XHRvYmogPSBMLmxhdExuZyhvYmopO1xyXG5cclxuXHRcdHZhciBtYXJnaW4gPSBNYXRoLm1heChcclxuXHRcdCAgICAgICAgTWF0aC5hYnModGhpcy5sYXQgLSBvYmoubGF0KSxcclxuXHRcdCAgICAgICAgTWF0aC5hYnModGhpcy5sbmcgLSBvYmoubG5nKSk7XHJcblxyXG5cdFx0cmV0dXJuIG1hcmdpbiA8PSAobWF4TWFyZ2luID09PSB1bmRlZmluZWQgPyAxLjBFLTkgOiBtYXhNYXJnaW4pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgdG9TdHJpbmcoKTogU3RyaW5nXHJcblx0Ly8gUmV0dXJucyBhIHN0cmluZyByZXByZXNlbnRhdGlvbiBvZiB0aGUgcG9pbnQgKGZvciBkZWJ1Z2dpbmcgcHVycG9zZXMpLlxyXG5cdHRvU3RyaW5nOiBmdW5jdGlvbiAocHJlY2lzaW9uKSB7XHJcblx0XHRyZXR1cm4gJ0xhdExuZygnICtcclxuXHRcdCAgICAgICAgTC5VdGlsLmZvcm1hdE51bSh0aGlzLmxhdCwgcHJlY2lzaW9uKSArICcsICcgK1xyXG5cdFx0ICAgICAgICBMLlV0aWwuZm9ybWF0TnVtKHRoaXMubG5nLCBwcmVjaXNpb24pICsgJyknO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZGlzdGFuY2VUbyhvdGhlckxhdExuZzogTGF0TG5nKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgZGlzdGFuY2UgKGluIG1ldGVycykgdG8gdGhlIGdpdmVuIGBMYXRMbmdgIGNhbGN1bGF0ZWQgdXNpbmcgdGhlIFtIYXZlcnNpbmUgZm9ybXVsYV0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9IYXZlcnNpbmVfZm9ybXVsYSkuXHJcblx0ZGlzdGFuY2VUbzogZnVuY3Rpb24gKG90aGVyKSB7XHJcblx0XHRyZXR1cm4gTC5DUlMuRWFydGguZGlzdGFuY2UodGhpcywgTC5sYXRMbmcob3RoZXIpKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHdyYXAoKTogTGF0TG5nXHJcblx0Ly8gUmV0dXJucyBhIG5ldyBgTGF0TG5nYCBvYmplY3Qgd2l0aCB0aGUgbG9uZ2l0dWRlIHdyYXBwZWQgc28gaXQncyBhbHdheXMgYmV0d2VlbiAtMTgwIGFuZCArMTgwIGRlZ3JlZXMuXHJcblx0d3JhcDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIEwuQ1JTLkVhcnRoLndyYXBMYXRMbmcodGhpcyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB0b0JvdW5kcyhzaXplSW5NZXRlcnM6IE51bWJlcik6IExhdExuZ0JvdW5kc1xyXG5cdC8vIFJldHVybnMgYSBuZXcgYExhdExuZ0JvdW5kc2Agb2JqZWN0IGluIHdoaWNoIGVhY2ggYm91bmRhcnkgaXMgYHNpemVJbk1ldGVyc2AgbWV0ZXJzIGFwYXJ0IGZyb20gdGhlIGBMYXRMbmdgLlxyXG5cdHRvQm91bmRzOiBmdW5jdGlvbiAoc2l6ZUluTWV0ZXJzKSB7XHJcblx0XHR2YXIgbGF0QWNjdXJhY3kgPSAxODAgKiBzaXplSW5NZXRlcnMgLyA0MDA3NTAxNyxcclxuXHRcdCAgICBsbmdBY2N1cmFjeSA9IGxhdEFjY3VyYWN5IC8gTWF0aC5jb3MoKE1hdGguUEkgLyAxODApICogdGhpcy5sYXQpO1xyXG5cclxuXHRcdHJldHVybiBMLmxhdExuZ0JvdW5kcyhcclxuXHRcdCAgICAgICAgW3RoaXMubGF0IC0gbGF0QWNjdXJhY3ksIHRoaXMubG5nIC0gbG5nQWNjdXJhY3ldLFxyXG5cdFx0ICAgICAgICBbdGhpcy5sYXQgKyBsYXRBY2N1cmFjeSwgdGhpcy5sbmcgKyBsbmdBY2N1cmFjeV0pO1xyXG5cdH0sXHJcblxyXG5cdGNsb25lOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gbmV3IEwuTGF0TG5nKHRoaXMubGF0LCB0aGlzLmxuZywgdGhpcy5hbHQpO1xyXG5cdH1cclxufTtcclxuXHJcblxyXG5cclxuLy8gQGZhY3RvcnkgTC5sYXRMbmcobGF0aXR1ZGU6IE51bWJlciwgbG9uZ2l0dWRlOiBOdW1iZXIsIGFsdGl0dWRlPzogTnVtYmVyKTogTGF0TG5nXHJcbi8vIENyZWF0ZXMgYW4gb2JqZWN0IHJlcHJlc2VudGluZyBhIGdlb2dyYXBoaWNhbCBwb2ludCB3aXRoIHRoZSBnaXZlbiBsYXRpdHVkZSBhbmQgbG9uZ2l0dWRlIChhbmQgb3B0aW9uYWxseSBhbHRpdHVkZSkuXHJcblxyXG4vLyBAYWx0ZXJuYXRpdmVcclxuLy8gQGZhY3RvcnkgTC5sYXRMbmcoY29vcmRzOiBBcnJheSk6IExhdExuZ1xyXG4vLyBFeHBlY3RzIGFuIGFycmF5IG9mIHRoZSBmb3JtIGBbTnVtYmVyLCBOdW1iZXJdYCBvciBgW051bWJlciwgTnVtYmVyLCBOdW1iZXJdYCBpbnN0ZWFkLlxyXG5cclxuLy8gQGFsdGVybmF0aXZlXHJcbi8vIEBmYWN0b3J5IEwubGF0TG5nKGNvb3JkczogT2JqZWN0KTogTGF0TG5nXHJcbi8vIEV4cGVjdHMgYW4gcGxhaW4gb2JqZWN0IG9mIHRoZSBmb3JtIGB7bGF0OiBOdW1iZXIsIGxuZzogTnVtYmVyfWAgb3IgYHtsYXQ6IE51bWJlciwgbG5nOiBOdW1iZXIsIGFsdDogTnVtYmVyfWAgaW5zdGVhZC5cclxuXHJcbkwubGF0TG5nID0gZnVuY3Rpb24gKGEsIGIsIGMpIHtcclxuXHRpZiAoYSBpbnN0YW5jZW9mIEwuTGF0TG5nKSB7XHJcblx0XHRyZXR1cm4gYTtcclxuXHR9XHJcblx0aWYgKEwuVXRpbC5pc0FycmF5KGEpICYmIHR5cGVvZiBhWzBdICE9PSAnb2JqZWN0Jykge1xyXG5cdFx0aWYgKGEubGVuZ3RoID09PSAzKSB7XHJcblx0XHRcdHJldHVybiBuZXcgTC5MYXRMbmcoYVswXSwgYVsxXSwgYVsyXSk7XHJcblx0XHR9XHJcblx0XHRpZiAoYS5sZW5ndGggPT09IDIpIHtcclxuXHRcdFx0cmV0dXJuIG5ldyBMLkxhdExuZyhhWzBdLCBhWzFdKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiBudWxsO1xyXG5cdH1cclxuXHRpZiAoYSA9PT0gdW5kZWZpbmVkIHx8IGEgPT09IG51bGwpIHtcclxuXHRcdHJldHVybiBhO1xyXG5cdH1cclxuXHRpZiAodHlwZW9mIGEgPT09ICdvYmplY3QnICYmICdsYXQnIGluIGEpIHtcclxuXHRcdHJldHVybiBuZXcgTC5MYXRMbmcoYS5sYXQsICdsbmcnIGluIGEgPyBhLmxuZyA6IGEubG9uLCBhLmFsdCk7XHJcblx0fVxyXG5cdGlmIChiID09PSB1bmRlZmluZWQpIHtcclxuXHRcdHJldHVybiBudWxsO1xyXG5cdH1cclxuXHRyZXR1cm4gbmV3IEwuTGF0TG5nKGEsIGIsIGMpO1xyXG59O1xyXG5cblxuXG4vKlxyXG4gKiBAY2xhc3MgTGF0TG5nQm91bmRzXHJcbiAqIEBha2EgTC5MYXRMbmdCb3VuZHNcclxuICpcclxuICogUmVwcmVzZW50cyBhIHJlY3Rhbmd1bGFyIGdlb2dyYXBoaWNhbCBhcmVhIG9uIGEgbWFwLlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiB2YXIgY29ybmVyMSA9IEwubGF0TG5nKDQwLjcxMiwgLTc0LjIyNyksXHJcbiAqIGNvcm5lcjIgPSBMLmxhdExuZyg0MC43NzQsIC03NC4xMjUpLFxyXG4gKiBib3VuZHMgPSBMLmxhdExuZ0JvdW5kcyhjb3JuZXIxLCBjb3JuZXIyKTtcclxuICogYGBgXHJcbiAqXHJcbiAqIEFsbCBMZWFmbGV0IG1ldGhvZHMgdGhhdCBhY2NlcHQgTGF0TG5nQm91bmRzIG9iamVjdHMgYWxzbyBhY2NlcHQgdGhlbSBpbiBhIHNpbXBsZSBBcnJheSBmb3JtICh1bmxlc3Mgbm90ZWQgb3RoZXJ3aXNlKSwgc28gdGhlIGJvdW5kcyBleGFtcGxlIGFib3ZlIGNhbiBiZSBwYXNzZWQgbGlrZSB0aGlzOlxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiBtYXAuZml0Qm91bmRzKFtcclxuICogXHRbNDAuNzEyLCAtNzQuMjI3XSxcclxuICogXHRbNDAuNzc0LCAtNzQuMTI1XVxyXG4gKiBdKTtcclxuICogYGBgXHJcbiAqXHJcbiAqIENhdXRpb246IGlmIHRoZSBhcmVhIGNyb3NzZXMgdGhlIGFudGltZXJpZGlhbiAob2Z0ZW4gY29uZnVzZWQgd2l0aCB0aGUgSW50ZXJuYXRpb25hbCBEYXRlIExpbmUpLCB5b3UgbXVzdCBzcGVjaWZ5IGNvcm5lcnMgX291dHNpZGVfIHRoZSBbLTE4MCwgMTgwXSBkZWdyZWVzIGxvbmdpdHVkZSByYW5nZS5cclxuICovXHJcblxyXG5MLkxhdExuZ0JvdW5kcyA9IGZ1bmN0aW9uIChjb3JuZXIxLCBjb3JuZXIyKSB7IC8vIChMYXRMbmcsIExhdExuZykgb3IgKExhdExuZ1tdKVxyXG5cdGlmICghY29ybmVyMSkgeyByZXR1cm47IH1cclxuXHJcblx0dmFyIGxhdGxuZ3MgPSBjb3JuZXIyID8gW2Nvcm5lcjEsIGNvcm5lcjJdIDogY29ybmVyMTtcclxuXHJcblx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IGxhdGxuZ3MubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdHRoaXMuZXh0ZW5kKGxhdGxuZ3NbaV0pO1xyXG5cdH1cclxufTtcclxuXHJcbkwuTGF0TG5nQm91bmRzLnByb3RvdHlwZSA9IHtcclxuXHJcblx0Ly8gQG1ldGhvZCBleHRlbmQobGF0bG5nOiBMYXRMbmcpOiB0aGlzXHJcblx0Ly8gRXh0ZW5kIHRoZSBib3VuZHMgdG8gY29udGFpbiB0aGUgZ2l2ZW4gcG9pbnRcclxuXHJcblx0Ly8gQGFsdGVybmF0aXZlXHJcblx0Ly8gQG1ldGhvZCBleHRlbmQob3RoZXJCb3VuZHM6IExhdExuZ0JvdW5kcyk6IHRoaXNcclxuXHQvLyBFeHRlbmQgdGhlIGJvdW5kcyB0byBjb250YWluIHRoZSBnaXZlbiBib3VuZHNcclxuXHRleHRlbmQ6IGZ1bmN0aW9uIChvYmopIHtcclxuXHRcdHZhciBzdyA9IHRoaXMuX3NvdXRoV2VzdCxcclxuXHRcdCAgICBuZSA9IHRoaXMuX25vcnRoRWFzdCxcclxuXHRcdCAgICBzdzIsIG5lMjtcclxuXHJcblx0XHRpZiAob2JqIGluc3RhbmNlb2YgTC5MYXRMbmcpIHtcclxuXHRcdFx0c3cyID0gb2JqO1xyXG5cdFx0XHRuZTIgPSBvYmo7XHJcblxyXG5cdFx0fSBlbHNlIGlmIChvYmogaW5zdGFuY2VvZiBMLkxhdExuZ0JvdW5kcykge1xyXG5cdFx0XHRzdzIgPSBvYmouX3NvdXRoV2VzdDtcclxuXHRcdFx0bmUyID0gb2JqLl9ub3J0aEVhc3Q7XHJcblxyXG5cdFx0XHRpZiAoIXN3MiB8fCAhbmUyKSB7IHJldHVybiB0aGlzOyB9XHJcblxyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0cmV0dXJuIG9iaiA/IHRoaXMuZXh0ZW5kKEwubGF0TG5nKG9iaikgfHwgTC5sYXRMbmdCb3VuZHMob2JqKSkgOiB0aGlzO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICghc3cgJiYgIW5lKSB7XHJcblx0XHRcdHRoaXMuX3NvdXRoV2VzdCA9IG5ldyBMLkxhdExuZyhzdzIubGF0LCBzdzIubG5nKTtcclxuXHRcdFx0dGhpcy5fbm9ydGhFYXN0ID0gbmV3IEwuTGF0TG5nKG5lMi5sYXQsIG5lMi5sbmcpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0c3cubGF0ID0gTWF0aC5taW4oc3cyLmxhdCwgc3cubGF0KTtcclxuXHRcdFx0c3cubG5nID0gTWF0aC5taW4oc3cyLmxuZywgc3cubG5nKTtcclxuXHRcdFx0bmUubGF0ID0gTWF0aC5tYXgobmUyLmxhdCwgbmUubGF0KTtcclxuXHRcdFx0bmUubG5nID0gTWF0aC5tYXgobmUyLmxuZywgbmUubG5nKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHBhZChidWZmZXJSYXRpbzogTnVtYmVyKTogTGF0TG5nQm91bmRzXHJcblx0Ly8gUmV0dXJucyBiaWdnZXIgYm91bmRzIGNyZWF0ZWQgYnkgZXh0ZW5kaW5nIHRoZSBjdXJyZW50IGJvdW5kcyBieSBhIGdpdmVuIHBlcmNlbnRhZ2UgaW4gZWFjaCBkaXJlY3Rpb24uXHJcblx0cGFkOiBmdW5jdGlvbiAoYnVmZmVyUmF0aW8pIHtcclxuXHRcdHZhciBzdyA9IHRoaXMuX3NvdXRoV2VzdCxcclxuXHRcdCAgICBuZSA9IHRoaXMuX25vcnRoRWFzdCxcclxuXHRcdCAgICBoZWlnaHRCdWZmZXIgPSBNYXRoLmFicyhzdy5sYXQgLSBuZS5sYXQpICogYnVmZmVyUmF0aW8sXHJcblx0XHQgICAgd2lkdGhCdWZmZXIgPSBNYXRoLmFicyhzdy5sbmcgLSBuZS5sbmcpICogYnVmZmVyUmF0aW87XHJcblxyXG5cdFx0cmV0dXJuIG5ldyBMLkxhdExuZ0JvdW5kcyhcclxuXHRcdCAgICAgICAgbmV3IEwuTGF0TG5nKHN3LmxhdCAtIGhlaWdodEJ1ZmZlciwgc3cubG5nIC0gd2lkdGhCdWZmZXIpLFxyXG5cdFx0ICAgICAgICBuZXcgTC5MYXRMbmcobmUubGF0ICsgaGVpZ2h0QnVmZmVyLCBuZS5sbmcgKyB3aWR0aEJ1ZmZlcikpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Q2VudGVyKCk6IExhdExuZ1xyXG5cdC8vIFJldHVybnMgdGhlIGNlbnRlciBwb2ludCBvZiB0aGUgYm91bmRzLlxyXG5cdGdldENlbnRlcjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIG5ldyBMLkxhdExuZyhcclxuXHRcdCAgICAgICAgKHRoaXMuX3NvdXRoV2VzdC5sYXQgKyB0aGlzLl9ub3J0aEVhc3QubGF0KSAvIDIsXHJcblx0XHQgICAgICAgICh0aGlzLl9zb3V0aFdlc3QubG5nICsgdGhpcy5fbm9ydGhFYXN0LmxuZykgLyAyKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFNvdXRoV2VzdCgpOiBMYXRMbmdcclxuXHQvLyBSZXR1cm5zIHRoZSBzb3V0aC13ZXN0IHBvaW50IG9mIHRoZSBib3VuZHMuXHJcblx0Z2V0U291dGhXZXN0OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fc291dGhXZXN0O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Tm9ydGhFYXN0KCk6IExhdExuZ1xyXG5cdC8vIFJldHVybnMgdGhlIG5vcnRoLWVhc3QgcG9pbnQgb2YgdGhlIGJvdW5kcy5cclxuXHRnZXROb3J0aEVhc3Q6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9ub3J0aEVhc3Q7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXROb3J0aFdlc3QoKTogTGF0TG5nXHJcblx0Ly8gUmV0dXJucyB0aGUgbm9ydGgtd2VzdCBwb2ludCBvZiB0aGUgYm91bmRzLlxyXG5cdGdldE5vcnRoV2VzdDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIG5ldyBMLkxhdExuZyh0aGlzLmdldE5vcnRoKCksIHRoaXMuZ2V0V2VzdCgpKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFNvdXRoRWFzdCgpOiBMYXRMbmdcclxuXHQvLyBSZXR1cm5zIHRoZSBzb3V0aC1lYXN0IHBvaW50IG9mIHRoZSBib3VuZHMuXHJcblx0Z2V0U291dGhFYXN0OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gbmV3IEwuTGF0TG5nKHRoaXMuZ2V0U291dGgoKSwgdGhpcy5nZXRFYXN0KCkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0V2VzdCgpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSB3ZXN0IGxvbmdpdHVkZSBvZiB0aGUgYm91bmRzXHJcblx0Z2V0V2VzdDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX3NvdXRoV2VzdC5sbmc7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRTb3V0aCgpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBzb3V0aCBsYXRpdHVkZSBvZiB0aGUgYm91bmRzXHJcblx0Z2V0U291dGg6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9zb3V0aFdlc3QubGF0O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0RWFzdCgpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBlYXN0IGxvbmdpdHVkZSBvZiB0aGUgYm91bmRzXHJcblx0Z2V0RWFzdDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX25vcnRoRWFzdC5sbmc7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXROb3J0aCgpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBub3J0aCBsYXRpdHVkZSBvZiB0aGUgYm91bmRzXHJcblx0Z2V0Tm9ydGg6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9ub3J0aEVhc3QubGF0O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgY29udGFpbnMob3RoZXJCb3VuZHM6IExhdExuZ0JvdW5kcyk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcmVjdGFuZ2xlIGNvbnRhaW5zIHRoZSBnaXZlbiBvbmUuXHJcblxyXG5cdC8vIEBhbHRlcm5hdGl2ZVxyXG5cdC8vIEBtZXRob2QgY29udGFpbnMgKGxhdGxuZzogTGF0TG5nKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSByZWN0YW5nbGUgY29udGFpbnMgdGhlIGdpdmVuIHBvaW50LlxyXG5cdGNvbnRhaW5zOiBmdW5jdGlvbiAob2JqKSB7IC8vIChMYXRMbmdCb3VuZHMpIG9yIChMYXRMbmcpIC0+IEJvb2xlYW5cclxuXHRcdGlmICh0eXBlb2Ygb2JqWzBdID09PSAnbnVtYmVyJyB8fCBvYmogaW5zdGFuY2VvZiBMLkxhdExuZykge1xyXG5cdFx0XHRvYmogPSBMLmxhdExuZyhvYmopO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0b2JqID0gTC5sYXRMbmdCb3VuZHMob2JqKTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgc3cgPSB0aGlzLl9zb3V0aFdlc3QsXHJcblx0XHQgICAgbmUgPSB0aGlzLl9ub3J0aEVhc3QsXHJcblx0XHQgICAgc3cyLCBuZTI7XHJcblxyXG5cdFx0aWYgKG9iaiBpbnN0YW5jZW9mIEwuTGF0TG5nQm91bmRzKSB7XHJcblx0XHRcdHN3MiA9IG9iai5nZXRTb3V0aFdlc3QoKTtcclxuXHRcdFx0bmUyID0gb2JqLmdldE5vcnRoRWFzdCgpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0c3cyID0gbmUyID0gb2JqO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiAoc3cyLmxhdCA+PSBzdy5sYXQpICYmIChuZTIubGF0IDw9IG5lLmxhdCkgJiZcclxuXHRcdCAgICAgICAoc3cyLmxuZyA+PSBzdy5sbmcpICYmIChuZTIubG5nIDw9IG5lLmxuZyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBpbnRlcnNlY3RzKG90aGVyQm91bmRzOiBMYXRMbmdCb3VuZHMpOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIHJlY3RhbmdsZSBpbnRlcnNlY3RzIHRoZSBnaXZlbiBib3VuZHMuIFR3byBib3VuZHMgaW50ZXJzZWN0IGlmIHRoZXkgaGF2ZSBhdCBsZWFzdCBvbmUgcG9pbnQgaW4gY29tbW9uLlxyXG5cdGludGVyc2VjdHM6IGZ1bmN0aW9uIChib3VuZHMpIHtcclxuXHRcdGJvdW5kcyA9IEwubGF0TG5nQm91bmRzKGJvdW5kcyk7XHJcblxyXG5cdFx0dmFyIHN3ID0gdGhpcy5fc291dGhXZXN0LFxyXG5cdFx0ICAgIG5lID0gdGhpcy5fbm9ydGhFYXN0LFxyXG5cdFx0ICAgIHN3MiA9IGJvdW5kcy5nZXRTb3V0aFdlc3QoKSxcclxuXHRcdCAgICBuZTIgPSBib3VuZHMuZ2V0Tm9ydGhFYXN0KCksXHJcblxyXG5cdFx0ICAgIGxhdEludGVyc2VjdHMgPSAobmUyLmxhdCA+PSBzdy5sYXQpICYmIChzdzIubGF0IDw9IG5lLmxhdCksXHJcblx0XHQgICAgbG5nSW50ZXJzZWN0cyA9IChuZTIubG5nID49IHN3LmxuZykgJiYgKHN3Mi5sbmcgPD0gbmUubG5nKTtcclxuXHJcblx0XHRyZXR1cm4gbGF0SW50ZXJzZWN0cyAmJiBsbmdJbnRlcnNlY3RzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgb3ZlcmxhcHMob3RoZXJCb3VuZHM6IEJvdW5kcyk6IEJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcmVjdGFuZ2xlIG92ZXJsYXBzIHRoZSBnaXZlbiBib3VuZHMuIFR3byBib3VuZHMgb3ZlcmxhcCBpZiB0aGVpciBpbnRlcnNlY3Rpb24gaXMgYW4gYXJlYS5cclxuXHRvdmVybGFwczogZnVuY3Rpb24gKGJvdW5kcykge1xyXG5cdFx0Ym91bmRzID0gTC5sYXRMbmdCb3VuZHMoYm91bmRzKTtcclxuXHJcblx0XHR2YXIgc3cgPSB0aGlzLl9zb3V0aFdlc3QsXHJcblx0XHQgICAgbmUgPSB0aGlzLl9ub3J0aEVhc3QsXHJcblx0XHQgICAgc3cyID0gYm91bmRzLmdldFNvdXRoV2VzdCgpLFxyXG5cdFx0ICAgIG5lMiA9IGJvdW5kcy5nZXROb3J0aEVhc3QoKSxcclxuXHJcblx0XHQgICAgbGF0T3ZlcmxhcHMgPSAobmUyLmxhdCA+IHN3LmxhdCkgJiYgKHN3Mi5sYXQgPCBuZS5sYXQpLFxyXG5cdFx0ICAgIGxuZ092ZXJsYXBzID0gKG5lMi5sbmcgPiBzdy5sbmcpICYmIChzdzIubG5nIDwgbmUubG5nKTtcclxuXHJcblx0XHRyZXR1cm4gbGF0T3ZlcmxhcHMgJiYgbG5nT3ZlcmxhcHM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB0b0JCb3hTdHJpbmcoKTogU3RyaW5nXHJcblx0Ly8gUmV0dXJucyBhIHN0cmluZyB3aXRoIGJvdW5kaW5nIGJveCBjb29yZGluYXRlcyBpbiBhICdzb3V0aHdlc3RfbG5nLHNvdXRod2VzdF9sYXQsbm9ydGhlYXN0X2xuZyxub3J0aGVhc3RfbGF0JyBmb3JtYXQuIFVzZWZ1bCBmb3Igc2VuZGluZyByZXF1ZXN0cyB0byB3ZWIgc2VydmljZXMgdGhhdCByZXR1cm4gZ2VvIGRhdGEuXHJcblx0dG9CQm94U3RyaW5nOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gW3RoaXMuZ2V0V2VzdCgpLCB0aGlzLmdldFNvdXRoKCksIHRoaXMuZ2V0RWFzdCgpLCB0aGlzLmdldE5vcnRoKCldLmpvaW4oJywnKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGVxdWFscyhvdGhlckJvdW5kczogTGF0TG5nQm91bmRzKTogQm9vbGVhblxyXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSByZWN0YW5nbGUgaXMgZXF1aXZhbGVudCAod2l0aGluIGEgc21hbGwgbWFyZ2luIG9mIGVycm9yKSB0byB0aGUgZ2l2ZW4gYm91bmRzLlxyXG5cdGVxdWFsczogZnVuY3Rpb24gKGJvdW5kcykge1xyXG5cdFx0aWYgKCFib3VuZHMpIHsgcmV0dXJuIGZhbHNlOyB9XHJcblxyXG5cdFx0Ym91bmRzID0gTC5sYXRMbmdCb3VuZHMoYm91bmRzKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5fc291dGhXZXN0LmVxdWFscyhib3VuZHMuZ2V0U291dGhXZXN0KCkpICYmXHJcblx0XHQgICAgICAgdGhpcy5fbm9ydGhFYXN0LmVxdWFscyhib3VuZHMuZ2V0Tm9ydGhFYXN0KCkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgaXNWYWxpZCgpOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGJvdW5kcyBhcmUgcHJvcGVybHkgaW5pdGlhbGl6ZWQuXHJcblx0aXNWYWxpZDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuICEhKHRoaXMuX3NvdXRoV2VzdCAmJiB0aGlzLl9ub3J0aEVhc3QpO1xyXG5cdH1cclxufTtcclxuXHJcbi8vIFRPRE8gSW50ZXJuYXRpb25hbCBkYXRlIGxpbmU/XHJcblxyXG4vLyBAZmFjdG9yeSBMLmxhdExuZ0JvdW5kcyhjb3JuZXIxOiBMYXRMbmcsIGNvcm5lcjI6IExhdExuZylcclxuLy8gQ3JlYXRlcyBhIGBMYXRMbmdCb3VuZHNgIG9iamVjdCBieSBkZWZpbmluZyB0d28gZGlhZ29uYWxseSBvcHBvc2l0ZSBjb3JuZXJzIG9mIHRoZSByZWN0YW5nbGUuXHJcblxyXG4vLyBAYWx0ZXJuYXRpdmVcclxuLy8gQGZhY3RvcnkgTC5sYXRMbmdCb3VuZHMobGF0bG5nczogTGF0TG5nW10pXHJcbi8vIENyZWF0ZXMgYSBgTGF0TG5nQm91bmRzYCBvYmplY3QgZGVmaW5lZCBieSB0aGUgZ2VvZ3JhcGhpY2FsIHBvaW50cyBpdCBjb250YWlucy4gVmVyeSB1c2VmdWwgZm9yIHpvb21pbmcgdGhlIG1hcCB0byBmaXQgYSBwYXJ0aWN1bGFyIHNldCBvZiBsb2NhdGlvbnMgd2l0aCBbYGZpdEJvdW5kc2BdKCNtYXAtZml0Ym91bmRzKS5cclxuTC5sYXRMbmdCb3VuZHMgPSBmdW5jdGlvbiAoYSwgYikge1xyXG5cdGlmIChhIGluc3RhbmNlb2YgTC5MYXRMbmdCb3VuZHMpIHtcclxuXHRcdHJldHVybiBhO1xyXG5cdH1cclxuXHRyZXR1cm4gbmV3IEwuTGF0TG5nQm91bmRzKGEsIGIpO1xyXG59O1xyXG5cblxuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIFByb2plY3Rpb25cclxuICogQHNlY3Rpb25cclxuICogTGVhZmxldCBjb21lcyB3aXRoIGEgc2V0IG9mIGFscmVhZHkgZGVmaW5lZCBQcm9qZWN0aW9ucyBvdXQgb2YgdGhlIGJveDpcclxuICpcclxuICogQHByb2plY3Rpb24gTC5Qcm9qZWN0aW9uLkxvbkxhdFxyXG4gKlxyXG4gKiBFcXVpcmVjdGFuZ3VsYXIsIG9yIFBsYXRlIENhcnJlZSBwcm9qZWN0aW9uIOKAlCB0aGUgbW9zdCBzaW1wbGUgcHJvamVjdGlvbixcclxuICogbW9zdGx5IHVzZWQgYnkgR0lTIGVudGh1c2lhc3RzLiBEaXJlY3RseSBtYXBzIGB4YCBhcyBsb25naXR1ZGUsIGFuZCBgeWAgYXNcclxuICogbGF0aXR1ZGUuIEFsc28gc3VpdGFibGUgZm9yIGZsYXQgd29ybGRzLCBlLmcuIGdhbWUgbWFwcy4gVXNlZCBieSB0aGVcclxuICogYEVQU0c6MzM5NWAgYW5kIGBTaW1wbGVgIENSUy5cclxuICovXHJcblxyXG5MLlByb2plY3Rpb24gPSB7fTtcclxuXHJcbkwuUHJvamVjdGlvbi5Mb25MYXQgPSB7XHJcblx0cHJvamVjdDogZnVuY3Rpb24gKGxhdGxuZykge1xyXG5cdFx0cmV0dXJuIG5ldyBMLlBvaW50KGxhdGxuZy5sbmcsIGxhdGxuZy5sYXQpO1xyXG5cdH0sXHJcblxyXG5cdHVucHJvamVjdDogZnVuY3Rpb24gKHBvaW50KSB7XHJcblx0XHRyZXR1cm4gbmV3IEwuTGF0TG5nKHBvaW50LnksIHBvaW50LngpO1xyXG5cdH0sXHJcblxyXG5cdGJvdW5kczogTC5ib3VuZHMoWy0xODAsIC05MF0sIFsxODAsIDkwXSlcclxufTtcclxuXG5cblxuLypcclxuICogQG5hbWVzcGFjZSBQcm9qZWN0aW9uXHJcbiAqIEBwcm9qZWN0aW9uIEwuUHJvamVjdGlvbi5TcGhlcmljYWxNZXJjYXRvclxyXG4gKlxyXG4gKiBTcGhlcmljYWwgTWVyY2F0b3IgcHJvamVjdGlvbiDigJQgdGhlIG1vc3QgY29tbW9uIHByb2plY3Rpb24gZm9yIG9ubGluZSBtYXBzLFxyXG4gKiB1c2VkIGJ5IGFsbW9zdCBhbGwgZnJlZSBhbmQgY29tbWVyY2lhbCB0aWxlIHByb3ZpZGVycy4gQXNzdW1lcyB0aGF0IEVhcnRoIGlzXHJcbiAqIGEgc3BoZXJlLiBVc2VkIGJ5IHRoZSBgRVBTRzozODU3YCBDUlMuXHJcbiAqL1xyXG5cclxuTC5Qcm9qZWN0aW9uLlNwaGVyaWNhbE1lcmNhdG9yID0ge1xyXG5cclxuXHRSOiA2Mzc4MTM3LFxyXG5cdE1BWF9MQVRJVFVERTogODUuMDUxMTI4Nzc5OCxcclxuXHJcblx0cHJvamVjdDogZnVuY3Rpb24gKGxhdGxuZykge1xyXG5cdFx0dmFyIGQgPSBNYXRoLlBJIC8gMTgwLFxyXG5cdFx0ICAgIG1heCA9IHRoaXMuTUFYX0xBVElUVURFLFxyXG5cdFx0ICAgIGxhdCA9IE1hdGgubWF4KE1hdGgubWluKG1heCwgbGF0bG5nLmxhdCksIC1tYXgpLFxyXG5cdFx0ICAgIHNpbiA9IE1hdGguc2luKGxhdCAqIGQpO1xyXG5cclxuXHRcdHJldHVybiBuZXcgTC5Qb2ludChcclxuXHRcdFx0XHR0aGlzLlIgKiBsYXRsbmcubG5nICogZCxcclxuXHRcdFx0XHR0aGlzLlIgKiBNYXRoLmxvZygoMSArIHNpbikgLyAoMSAtIHNpbikpIC8gMik7XHJcblx0fSxcclxuXHJcblx0dW5wcm9qZWN0OiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdHZhciBkID0gMTgwIC8gTWF0aC5QSTtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEwuTGF0TG5nKFxyXG5cdFx0XHQoMiAqIE1hdGguYXRhbihNYXRoLmV4cChwb2ludC55IC8gdGhpcy5SKSkgLSAoTWF0aC5QSSAvIDIpKSAqIGQsXHJcblx0XHRcdHBvaW50LnggKiBkIC8gdGhpcy5SKTtcclxuXHR9LFxyXG5cclxuXHRib3VuZHM6IChmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgZCA9IDYzNzgxMzcgKiBNYXRoLlBJO1xyXG5cdFx0cmV0dXJuIEwuYm91bmRzKFstZCwgLWRdLCBbZCwgZF0pO1xyXG5cdH0pKClcclxufTtcclxuXG5cblxuLypcclxuICogQGNsYXNzIENSU1xyXG4gKiBAYWthIEwuQ1JTXHJcbiAqIEFic3RyYWN0IGNsYXNzIHRoYXQgZGVmaW5lcyBjb29yZGluYXRlIHJlZmVyZW5jZSBzeXN0ZW1zIGZvciBwcm9qZWN0aW5nXHJcbiAqIGdlb2dyYXBoaWNhbCBwb2ludHMgaW50byBwaXhlbCAoc2NyZWVuKSBjb29yZGluYXRlcyBhbmQgYmFjayAoYW5kIHRvXHJcbiAqIGNvb3JkaW5hdGVzIGluIG90aGVyIHVuaXRzIGZvciBbV01TXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9XZWJfTWFwX1NlcnZpY2UpIHNlcnZpY2VzKS4gU2VlXHJcbiAqIFtzcGF0aWFsIHJlZmVyZW5jZSBzeXN0ZW1dKGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvQ29vcmRpbmF0ZV9yZWZlcmVuY2Vfc3lzdGVtKS5cclxuICpcclxuICogTGVhZmxldCBkZWZpbmVzIHRoZSBtb3N0IHVzdWFsIENSU3MgYnkgZGVmYXVsdC4gSWYgeW91IHdhbnQgdG8gdXNlIGFcclxuICogQ1JTIG5vdCBkZWZpbmVkIGJ5IGRlZmF1bHQsIHRha2UgYSBsb29rIGF0IHRoZVxyXG4gKiBbUHJvajRMZWFmbGV0XShodHRwczovL2dpdGh1Yi5jb20va2FydGVuYS9Qcm9qNExlYWZsZXQpIHBsdWdpbi5cclxuICovXHJcblxyXG5MLkNSUyA9IHtcclxuXHQvLyBAbWV0aG9kIGxhdExuZ1RvUG9pbnQobGF0bG5nOiBMYXRMbmcsIHpvb206IE51bWJlcik6IFBvaW50XHJcblx0Ly8gUHJvamVjdHMgZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGVzIGludG8gcGl4ZWwgY29vcmRpbmF0ZXMgZm9yIGEgZ2l2ZW4gem9vbS5cclxuXHRsYXRMbmdUb1BvaW50OiBmdW5jdGlvbiAobGF0bG5nLCB6b29tKSB7XHJcblx0XHR2YXIgcHJvamVjdGVkUG9pbnQgPSB0aGlzLnByb2plY3Rpb24ucHJvamVjdChsYXRsbmcpLFxyXG5cdFx0ICAgIHNjYWxlID0gdGhpcy5zY2FsZSh6b29tKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy50cmFuc2Zvcm1hdGlvbi5fdHJhbnNmb3JtKHByb2plY3RlZFBvaW50LCBzY2FsZSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBwb2ludFRvTGF0TG5nKHBvaW50OiBQb2ludCwgem9vbTogTnVtYmVyKTogTGF0TG5nXHJcblx0Ly8gVGhlIGludmVyc2Ugb2YgYGxhdExuZ1RvUG9pbnRgLiBQcm9qZWN0cyBwaXhlbCBjb29yZGluYXRlcyBvbiBhIGdpdmVuXHJcblx0Ly8gem9vbSBpbnRvIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlcy5cclxuXHRwb2ludFRvTGF0TG5nOiBmdW5jdGlvbiAocG9pbnQsIHpvb20pIHtcclxuXHRcdHZhciBzY2FsZSA9IHRoaXMuc2NhbGUoem9vbSksXHJcblx0XHQgICAgdW50cmFuc2Zvcm1lZFBvaW50ID0gdGhpcy50cmFuc2Zvcm1hdGlvbi51bnRyYW5zZm9ybShwb2ludCwgc2NhbGUpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLnByb2plY3Rpb24udW5wcm9qZWN0KHVudHJhbnNmb3JtZWRQb2ludCk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBwcm9qZWN0KGxhdGxuZzogTGF0TG5nKTogUG9pbnRcclxuXHQvLyBQcm9qZWN0cyBnZW9ncmFwaGljYWwgY29vcmRpbmF0ZXMgaW50byBjb29yZGluYXRlcyBpbiB1bml0cyBhY2NlcHRlZCBmb3JcclxuXHQvLyB0aGlzIENSUyAoZS5nLiBtZXRlcnMgZm9yIEVQU0c6Mzg1NywgZm9yIHBhc3NpbmcgaXQgdG8gV01TIHNlcnZpY2VzKS5cclxuXHRwcm9qZWN0OiBmdW5jdGlvbiAobGF0bG5nKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5wcm9qZWN0aW9uLnByb2plY3QobGF0bG5nKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHVucHJvamVjdChwb2ludDogUG9pbnQpOiBMYXRMbmdcclxuXHQvLyBHaXZlbiBhIHByb2plY3RlZCBjb29yZGluYXRlIHJldHVybnMgdGhlIGNvcnJlc3BvbmRpbmcgTGF0TG5nLlxyXG5cdC8vIFRoZSBpbnZlcnNlIG9mIGBwcm9qZWN0YC5cclxuXHR1bnByb2plY3Q6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0cmV0dXJuIHRoaXMucHJvamVjdGlvbi51bnByb2plY3QocG9pbnQpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2NhbGUoem9vbTogTnVtYmVyKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgc2NhbGUgdXNlZCB3aGVuIHRyYW5zZm9ybWluZyBwcm9qZWN0ZWQgY29vcmRpbmF0ZXMgaW50b1xyXG5cdC8vIHBpeGVsIGNvb3JkaW5hdGVzIGZvciBhIHBhcnRpY3VsYXIgem9vbS4gRm9yIGV4YW1wbGUsIGl0IHJldHVybnNcclxuXHQvLyBgMjU2ICogMl56b29tYCBmb3IgTWVyY2F0b3ItYmFzZWQgQ1JTLlxyXG5cdHNjYWxlOiBmdW5jdGlvbiAoem9vbSkge1xyXG5cdFx0cmV0dXJuIDI1NiAqIE1hdGgucG93KDIsIHpvb20pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgem9vbShzY2FsZTogTnVtYmVyKTogTnVtYmVyXHJcblx0Ly8gSW52ZXJzZSBvZiBgc2NhbGUoKWAsIHJldHVybnMgdGhlIHpvb20gbGV2ZWwgY29ycmVzcG9uZGluZyB0byBhIHNjYWxlXHJcblx0Ly8gZmFjdG9yIG9mIGBzY2FsZWAuXHJcblx0em9vbTogZnVuY3Rpb24gKHNjYWxlKSB7XHJcblx0XHRyZXR1cm4gTWF0aC5sb2coc2NhbGUgLyAyNTYpIC8gTWF0aC5MTjI7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRQcm9qZWN0ZWRCb3VuZHMoem9vbTogTnVtYmVyKTogQm91bmRzXHJcblx0Ly8gUmV0dXJucyB0aGUgcHJvamVjdGlvbidzIGJvdW5kcyBzY2FsZWQgYW5kIHRyYW5zZm9ybWVkIGZvciB0aGUgcHJvdmlkZWQgYHpvb21gLlxyXG5cdGdldFByb2plY3RlZEJvdW5kczogZnVuY3Rpb24gKHpvb20pIHtcclxuXHRcdGlmICh0aGlzLmluZmluaXRlKSB7IHJldHVybiBudWxsOyB9XHJcblxyXG5cdFx0dmFyIGIgPSB0aGlzLnByb2plY3Rpb24uYm91bmRzLFxyXG5cdFx0ICAgIHMgPSB0aGlzLnNjYWxlKHpvb20pLFxyXG5cdFx0ICAgIG1pbiA9IHRoaXMudHJhbnNmb3JtYXRpb24udHJhbnNmb3JtKGIubWluLCBzKSxcclxuXHRcdCAgICBtYXggPSB0aGlzLnRyYW5zZm9ybWF0aW9uLnRyYW5zZm9ybShiLm1heCwgcyk7XHJcblxyXG5cdFx0cmV0dXJuIEwuYm91bmRzKG1pbiwgbWF4KTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGRpc3RhbmNlKGxhdGxuZzE6IExhdExuZywgbGF0bG5nMjogTGF0TG5nKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgZGlzdGFuY2UgYmV0d2VlbiB0d28gZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGVzLlxyXG5cclxuXHQvLyBAcHJvcGVydHkgY29kZTogU3RyaW5nXHJcblx0Ly8gU3RhbmRhcmQgY29kZSBuYW1lIG9mIHRoZSBDUlMgcGFzc2VkIGludG8gV01TIHNlcnZpY2VzIChlLmcuIGAnRVBTRzozODU3J2ApXHJcblx0Ly9cclxuXHQvLyBAcHJvcGVydHkgd3JhcExuZzogTnVtYmVyW11cclxuXHQvLyBBbiBhcnJheSBvZiB0d28gbnVtYmVycyBkZWZpbmluZyB3aGV0aGVyIHRoZSBsb25naXR1ZGUgKGhvcml6b250YWwpIGNvb3JkaW5hdGVcclxuXHQvLyBheGlzIHdyYXBzIGFyb3VuZCBhIGdpdmVuIHJhbmdlIGFuZCBob3cuIERlZmF1bHRzIHRvIGBbLTE4MCwgMTgwXWAgaW4gbW9zdFxyXG5cdC8vIGdlb2dyYXBoaWNhbCBDUlNzLiBJZiBgdW5kZWZpbmVkYCwgdGhlIGxvbmdpdHVkZSBheGlzIGRvZXMgbm90IHdyYXAgYXJvdW5kLlxyXG5cdC8vXHJcblx0Ly8gQHByb3BlcnR5IHdyYXBMYXQ6IE51bWJlcltdXHJcblx0Ly8gTGlrZSBgd3JhcExuZ2AsIGJ1dCBmb3IgdGhlIGxhdGl0dWRlICh2ZXJ0aWNhbCkgYXhpcy5cclxuXHJcblx0Ly8gd3JhcExuZzogW21pbiwgbWF4XSxcclxuXHQvLyB3cmFwTGF0OiBbbWluLCBtYXhdLFxyXG5cclxuXHQvLyBAcHJvcGVydHkgaW5maW5pdGU6IEJvb2xlYW5cclxuXHQvLyBJZiB0cnVlLCB0aGUgY29vcmRpbmF0ZSBzcGFjZSB3aWxsIGJlIHVuYm91bmRlZCAoaW5maW5pdGUgaW4gYm90aCBheGVzKVxyXG5cdGluZmluaXRlOiBmYWxzZSxcclxuXHJcblx0Ly8gQG1ldGhvZCB3cmFwTGF0TG5nKGxhdGxuZzogTGF0TG5nKTogTGF0TG5nXHJcblx0Ly8gUmV0dXJucyBhIGBMYXRMbmdgIHdoZXJlIGxhdCBhbmQgbG5nIGhhcyBiZWVuIHdyYXBwZWQgYWNjb3JkaW5nIHRvIHRoZVxyXG5cdC8vIENSUydzIGB3cmFwTGF0YCBhbmQgYHdyYXBMbmdgIHByb3BlcnRpZXMsIGlmIHRoZXkgYXJlIG91dHNpZGUgdGhlIENSUydzIGJvdW5kcy5cclxuXHR3cmFwTGF0TG5nOiBmdW5jdGlvbiAobGF0bG5nKSB7XHJcblx0XHR2YXIgbG5nID0gdGhpcy53cmFwTG5nID8gTC5VdGlsLndyYXBOdW0obGF0bG5nLmxuZywgdGhpcy53cmFwTG5nLCB0cnVlKSA6IGxhdGxuZy5sbmcsXHJcblx0XHQgICAgbGF0ID0gdGhpcy53cmFwTGF0ID8gTC5VdGlsLndyYXBOdW0obGF0bG5nLmxhdCwgdGhpcy53cmFwTGF0LCB0cnVlKSA6IGxhdGxuZy5sYXQsXHJcblx0XHQgICAgYWx0ID0gbGF0bG5nLmFsdDtcclxuXHJcblx0XHRyZXR1cm4gTC5sYXRMbmcobGF0LCBsbmcsIGFsdCk7XHJcblx0fVxyXG59O1xyXG5cblxuXG4vKlxuICogQG5hbWVzcGFjZSBDUlNcbiAqIEBjcnMgTC5DUlMuU2ltcGxlXG4gKlxuICogQSBzaW1wbGUgQ1JTIHRoYXQgbWFwcyBsb25naXR1ZGUgYW5kIGxhdGl0dWRlIGludG8gYHhgIGFuZCBgeWAgZGlyZWN0bHkuXG4gKiBNYXkgYmUgdXNlZCBmb3IgbWFwcyBvZiBmbGF0IHN1cmZhY2VzIChlLmcuIGdhbWUgbWFwcykuIE5vdGUgdGhhdCB0aGUgYHlgXG4gKiBheGlzIHNob3VsZCBzdGlsbCBiZSBpbnZlcnRlZCAoZ29pbmcgZnJvbSBib3R0b20gdG8gdG9wKS4gYGRpc3RhbmNlKClgIHJldHVybnNcbiAqIHNpbXBsZSBldWNsaWRlYW4gZGlzdGFuY2UuXG4gKi9cblxuTC5DUlMuU2ltcGxlID0gTC5leHRlbmQoe30sIEwuQ1JTLCB7XG5cdHByb2plY3Rpb246IEwuUHJvamVjdGlvbi5Mb25MYXQsXG5cdHRyYW5zZm9ybWF0aW9uOiBuZXcgTC5UcmFuc2Zvcm1hdGlvbigxLCAwLCAtMSwgMCksXG5cblx0c2NhbGU6IGZ1bmN0aW9uICh6b29tKSB7XG5cdFx0cmV0dXJuIE1hdGgucG93KDIsIHpvb20pO1xuXHR9LFxuXG5cdHpvb206IGZ1bmN0aW9uIChzY2FsZSkge1xuXHRcdHJldHVybiBNYXRoLmxvZyhzY2FsZSkgLyBNYXRoLkxOMjtcblx0fSxcblxuXHRkaXN0YW5jZTogZnVuY3Rpb24gKGxhdGxuZzEsIGxhdGxuZzIpIHtcblx0XHR2YXIgZHggPSBsYXRsbmcyLmxuZyAtIGxhdGxuZzEubG5nLFxuXHRcdCAgICBkeSA9IGxhdGxuZzIubGF0IC0gbGF0bG5nMS5sYXQ7XG5cblx0XHRyZXR1cm4gTWF0aC5zcXJ0KGR4ICogZHggKyBkeSAqIGR5KTtcblx0fSxcblxuXHRpbmZpbml0ZTogdHJ1ZVxufSk7XG5cblxuXG4vKlxuICogQG5hbWVzcGFjZSBDUlNcbiAqIEBjcnMgTC5DUlMuRWFydGhcbiAqXG4gKiBTZXJ2ZXMgYXMgdGhlIGJhc2UgZm9yIENSUyB0aGF0IGFyZSBnbG9iYWwgc3VjaCB0aGF0IHRoZXkgY292ZXIgdGhlIGVhcnRoLlxuICogQ2FuIG9ubHkgYmUgdXNlZCBhcyB0aGUgYmFzZSBmb3Igb3RoZXIgQ1JTIGFuZCBjYW5ub3QgYmUgdXNlZCBkaXJlY3RseSxcbiAqIHNpbmNlIGl0IGRvZXMgbm90IGhhdmUgYSBgY29kZWAsIGBwcm9qZWN0aW9uYCBvciBgdHJhbnNmb3JtYXRpb25gLiBgZGlzdGFuY2UoKWAgcmV0dXJuc1xuICogbWV0ZXJzLlxuICovXG5cbkwuQ1JTLkVhcnRoID0gTC5leHRlbmQoe30sIEwuQ1JTLCB7XG5cdHdyYXBMbmc6IFstMTgwLCAxODBdLFxuXG5cdC8vIE1lYW4gRWFydGggUmFkaXVzLCBhcyByZWNvbW1lbmRlZCBmb3IgdXNlIGJ5XG5cdC8vIHRoZSBJbnRlcm5hdGlvbmFsIFVuaW9uIG9mIEdlb2Rlc3kgYW5kIEdlb3BoeXNpY3MsXG5cdC8vIHNlZSBodHRwOi8vcm9zZXR0YWNvZGUub3JnL3dpa2kvSGF2ZXJzaW5lX2Zvcm11bGFcblx0UjogNjM3MTAwMCxcblxuXHQvLyBkaXN0YW5jZSBiZXR3ZWVuIHR3byBnZW9ncmFwaGljYWwgcG9pbnRzIHVzaW5nIHNwaGVyaWNhbCBsYXcgb2YgY29zaW5lcyBhcHByb3hpbWF0aW9uXG5cdGRpc3RhbmNlOiBmdW5jdGlvbiAobGF0bG5nMSwgbGF0bG5nMikge1xuXHRcdHZhciByYWQgPSBNYXRoLlBJIC8gMTgwLFxuXHRcdCAgICBsYXQxID0gbGF0bG5nMS5sYXQgKiByYWQsXG5cdFx0ICAgIGxhdDIgPSBsYXRsbmcyLmxhdCAqIHJhZCxcblx0XHQgICAgYSA9IE1hdGguc2luKGxhdDEpICogTWF0aC5zaW4obGF0MikgK1xuXHRcdCAgICAgICAgTWF0aC5jb3MobGF0MSkgKiBNYXRoLmNvcyhsYXQyKSAqIE1hdGguY29zKChsYXRsbmcyLmxuZyAtIGxhdGxuZzEubG5nKSAqIHJhZCk7XG5cblx0XHRyZXR1cm4gdGhpcy5SICogTWF0aC5hY29zKE1hdGgubWluKGEsIDEpKTtcblx0fVxufSk7XG5cblxuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIENSU1xyXG4gKiBAY3JzIEwuQ1JTLkVQU0czODU3XHJcbiAqXHJcbiAqIFRoZSBtb3N0IGNvbW1vbiBDUlMgZm9yIG9ubGluZSBtYXBzLCB1c2VkIGJ5IGFsbW9zdCBhbGwgZnJlZSBhbmQgY29tbWVyY2lhbFxyXG4gKiB0aWxlIHByb3ZpZGVycy4gVXNlcyBTcGhlcmljYWwgTWVyY2F0b3IgcHJvamVjdGlvbi4gU2V0IGluIGJ5IGRlZmF1bHQgaW5cclxuICogTWFwJ3MgYGNyc2Agb3B0aW9uLlxyXG4gKi9cclxuXHJcbkwuQ1JTLkVQU0czODU3ID0gTC5leHRlbmQoe30sIEwuQ1JTLkVhcnRoLCB7XHJcblx0Y29kZTogJ0VQU0c6Mzg1NycsXHJcblx0cHJvamVjdGlvbjogTC5Qcm9qZWN0aW9uLlNwaGVyaWNhbE1lcmNhdG9yLFxyXG5cclxuXHR0cmFuc2Zvcm1hdGlvbjogKGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBzY2FsZSA9IDAuNSAvIChNYXRoLlBJICogTC5Qcm9qZWN0aW9uLlNwaGVyaWNhbE1lcmNhdG9yLlIpO1xyXG5cdFx0cmV0dXJuIG5ldyBMLlRyYW5zZm9ybWF0aW9uKHNjYWxlLCAwLjUsIC1zY2FsZSwgMC41KTtcclxuXHR9KCkpXHJcbn0pO1xyXG5cclxuTC5DUlMuRVBTRzkwMDkxMyA9IEwuZXh0ZW5kKHt9LCBMLkNSUy5FUFNHMzg1Nywge1xyXG5cdGNvZGU6ICdFUFNHOjkwMDkxMydcclxufSk7XHJcblxuXG5cbi8qXHJcbiAqIEBuYW1lc3BhY2UgQ1JTXHJcbiAqIEBjcnMgTC5DUlMuRVBTRzQzMjZcclxuICpcclxuICogQSBjb21tb24gQ1JTIGFtb25nIEdJUyBlbnRodXNpYXN0cy4gVXNlcyBzaW1wbGUgRXF1aXJlY3Rhbmd1bGFyIHByb2plY3Rpb24uXHJcbiAqXHJcbiAqIExlYWZsZXQgMS4wLnggY29tcGxpZXMgd2l0aCB0aGUgW1RNUyBjb29yZGluYXRlIHNjaGVtZSBmb3IgRVBTRzo0MzI2XShodHRwczovL3dpa2kub3NnZW8ub3JnL3dpa2kvVGlsZV9NYXBfU2VydmljZV9TcGVjaWZpY2F0aW9uI2dsb2JhbC1nZW9kZXRpYyksXHJcbiAqIHdoaWNoIGlzIGEgYnJlYWtpbmcgY2hhbmdlIGZyb20gMC43LnggYmVoYXZpb3VyLiAgSWYgeW91IGFyZSB1c2luZyBhIGBUaWxlTGF5ZXJgXHJcbiAqIHdpdGggdGhpcyBDUlMsIGVuc3VyZSB0aGF0IHRoZXJlIGFyZSB0d28gMjU2eDI1NiBwaXhlbCB0aWxlcyBjb3ZlcmluZyB0aGVcclxuICogd2hvbGUgZWFydGggYXQgem9vbSBsZXZlbCB6ZXJvLCBhbmQgdGhhdCB0aGUgdGlsZSBjb29yZGluYXRlIG9yaWdpbiBpcyAoLTE4MCwrOTApLFxyXG4gKiBvciAoLTE4MCwtOTApIGZvciBgVGlsZUxheWVyYHMgd2l0aCBbdGhlIGB0bXNgIG9wdGlvbl0oI3RpbGVsYXllci10bXMpIHNldC5cclxuICovXHJcblxyXG5MLkNSUy5FUFNHNDMyNiA9IEwuZXh0ZW5kKHt9LCBMLkNSUy5FYXJ0aCwge1xyXG5cdGNvZGU6ICdFUFNHOjQzMjYnLFxyXG5cdHByb2plY3Rpb246IEwuUHJvamVjdGlvbi5Mb25MYXQsXHJcblx0dHJhbnNmb3JtYXRpb246IG5ldyBMLlRyYW5zZm9ybWF0aW9uKDEgLyAxODAsIDEsIC0xIC8gMTgwLCAwLjUpXHJcbn0pO1xyXG5cblxuXG4vKlxyXG4gKiBAY2xhc3MgTWFwXHJcbiAqIEBha2EgTC5NYXBcclxuICogQGluaGVyaXRzIEV2ZW50ZWRcclxuICpcclxuICogVGhlIGNlbnRyYWwgY2xhc3Mgb2YgdGhlIEFQSSDigJQgaXQgaXMgdXNlZCB0byBjcmVhdGUgYSBtYXAgb24gYSBwYWdlIGFuZCBtYW5pcHVsYXRlIGl0LlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiAvLyBpbml0aWFsaXplIHRoZSBtYXAgb24gdGhlIFwibWFwXCIgZGl2IHdpdGggYSBnaXZlbiBjZW50ZXIgYW5kIHpvb21cclxuICogdmFyIG1hcCA9IEwubWFwKCdtYXAnLCB7XHJcbiAqIFx0Y2VudGVyOiBbNTEuNTA1LCAtMC4wOV0sXHJcbiAqIFx0em9vbTogMTNcclxuICogfSk7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKi9cclxuXHJcbkwuTWFwID0gTC5FdmVudGVkLmV4dGVuZCh7XHJcblxyXG5cdG9wdGlvbnM6IHtcclxuXHRcdC8vIEBzZWN0aW9uIE1hcCBTdGF0ZSBPcHRpb25zXHJcblx0XHQvLyBAb3B0aW9uIGNyczogQ1JTID0gTC5DUlMuRVBTRzM4NTdcclxuXHRcdC8vIFRoZSBbQ29vcmRpbmF0ZSBSZWZlcmVuY2UgU3lzdGVtXSgjY3JzKSB0byB1c2UuIERvbid0IGNoYW5nZSB0aGlzIGlmIHlvdSdyZSBub3RcclxuXHRcdC8vIHN1cmUgd2hhdCBpdCBtZWFucy5cclxuXHRcdGNyczogTC5DUlMuRVBTRzM4NTcsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBjZW50ZXI6IExhdExuZyA9IHVuZGVmaW5lZFxyXG5cdFx0Ly8gSW5pdGlhbCBnZW9ncmFwaGljIGNlbnRlciBvZiB0aGUgbWFwXHJcblx0XHRjZW50ZXI6IHVuZGVmaW5lZCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHpvb206IE51bWJlciA9IHVuZGVmaW5lZFxyXG5cdFx0Ly8gSW5pdGlhbCBtYXAgem9vbSBsZXZlbFxyXG5cdFx0em9vbTogdW5kZWZpbmVkLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gbWluWm9vbTogTnVtYmVyID0gdW5kZWZpbmVkXHJcblx0XHQvLyBNaW5pbXVtIHpvb20gbGV2ZWwgb2YgdGhlIG1hcC4gT3ZlcnJpZGVzIGFueSBgbWluWm9vbWAgb3B0aW9uIHNldCBvbiBtYXAgbGF5ZXJzLlxyXG5cdFx0bWluWm9vbTogdW5kZWZpbmVkLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gbWF4Wm9vbTogTnVtYmVyID0gdW5kZWZpbmVkXHJcblx0XHQvLyBNYXhpbXVtIHpvb20gbGV2ZWwgb2YgdGhlIG1hcC4gT3ZlcnJpZGVzIGFueSBgbWF4Wm9vbWAgb3B0aW9uIHNldCBvbiBtYXAgbGF5ZXJzLlxyXG5cdFx0bWF4Wm9vbTogdW5kZWZpbmVkLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gbGF5ZXJzOiBMYXllcltdID0gW11cclxuXHRcdC8vIEFycmF5IG9mIGxheWVycyB0aGF0IHdpbGwgYmUgYWRkZWQgdG8gdGhlIG1hcCBpbml0aWFsbHlcclxuXHRcdGxheWVyczogW10sXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBtYXhCb3VuZHM6IExhdExuZ0JvdW5kcyA9IG51bGxcclxuXHRcdC8vIFdoZW4gdGhpcyBvcHRpb24gaXMgc2V0LCB0aGUgbWFwIHJlc3RyaWN0cyB0aGUgdmlldyB0byB0aGUgZ2l2ZW5cclxuXHRcdC8vIGdlb2dyYXBoaWNhbCBib3VuZHMsIGJvdW5jaW5nIHRoZSB1c2VyIGJhY2sgd2hlbiBoZSB0cmllcyB0byBwYW5cclxuXHRcdC8vIG91dHNpZGUgdGhlIHZpZXcuIFRvIHNldCB0aGUgcmVzdHJpY3Rpb24gZHluYW1pY2FsbHksIHVzZVxyXG5cdFx0Ly8gW2BzZXRNYXhCb3VuZHNgXSgjbWFwLXNldG1heGJvdW5kcykgbWV0aG9kLlxyXG5cdFx0bWF4Qm91bmRzOiB1bmRlZmluZWQsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiByZW5kZXJlcjogUmVuZGVyZXIgPSAqXHJcblx0XHQvLyBUaGUgZGVmYXVsdCBtZXRob2QgZm9yIGRyYXdpbmcgdmVjdG9yIGxheWVycyBvbiB0aGUgbWFwLiBgTC5TVkdgXHJcblx0XHQvLyBvciBgTC5DYW52YXNgIGJ5IGRlZmF1bHQgZGVwZW5kaW5nIG9uIGJyb3dzZXIgc3VwcG9ydC5cclxuXHRcdHJlbmRlcmVyOiB1bmRlZmluZWQsXHJcblxyXG5cclxuXHRcdC8vIEBzZWN0aW9uIEFuaW1hdGlvbiBPcHRpb25zXHJcblx0XHQvLyBAb3B0aW9uIHpvb21BbmltYXRpb246IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBXaGV0aGVyIHRoZSBtYXAgem9vbSBhbmltYXRpb24gaXMgZW5hYmxlZC4gQnkgZGVmYXVsdCBpdCdzIGVuYWJsZWRcclxuXHRcdC8vIGluIGFsbCBicm93c2VycyB0aGF0IHN1cHBvcnQgQ1NTMyBUcmFuc2l0aW9ucyBleGNlcHQgQW5kcm9pZC5cclxuXHRcdHpvb21BbmltYXRpb246IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiB6b29tQW5pbWF0aW9uVGhyZXNob2xkOiBOdW1iZXIgPSA0XHJcblx0XHQvLyBXb24ndCBhbmltYXRlIHpvb20gaWYgdGhlIHpvb20gZGlmZmVyZW5jZSBleGNlZWRzIHRoaXMgdmFsdWUuXHJcblx0XHR6b29tQW5pbWF0aW9uVGhyZXNob2xkOiA0LFxyXG5cclxuXHRcdC8vIEBvcHRpb24gZmFkZUFuaW1hdGlvbjogQm9vbGVhbiA9IHRydWVcclxuXHRcdC8vIFdoZXRoZXIgdGhlIHRpbGUgZmFkZSBhbmltYXRpb24gaXMgZW5hYmxlZC4gQnkgZGVmYXVsdCBpdCdzIGVuYWJsZWRcclxuXHRcdC8vIGluIGFsbCBicm93c2VycyB0aGF0IHN1cHBvcnQgQ1NTMyBUcmFuc2l0aW9ucyBleGNlcHQgQW5kcm9pZC5cclxuXHRcdGZhZGVBbmltYXRpb246IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBtYXJrZXJab29tQW5pbWF0aW9uOiBCb29sZWFuID0gdHJ1ZVxyXG5cdFx0Ly8gV2hldGhlciBtYXJrZXJzIGFuaW1hdGUgdGhlaXIgem9vbSB3aXRoIHRoZSB6b29tIGFuaW1hdGlvbiwgaWYgZGlzYWJsZWRcclxuXHRcdC8vIHRoZXkgd2lsbCBkaXNhcHBlYXIgZm9yIHRoZSBsZW5ndGggb2YgdGhlIGFuaW1hdGlvbi4gQnkgZGVmYXVsdCBpdCdzXHJcblx0XHQvLyBlbmFibGVkIGluIGFsbCBicm93c2VycyB0aGF0IHN1cHBvcnQgQ1NTMyBUcmFuc2l0aW9ucyBleGNlcHQgQW5kcm9pZC5cclxuXHRcdG1hcmtlclpvb21BbmltYXRpb246IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiB0cmFuc2Zvcm0zRExpbWl0OiBOdW1iZXIgPSAyXjIzXHJcblx0XHQvLyBEZWZpbmVzIHRoZSBtYXhpbXVtIHNpemUgb2YgYSBDU1MgdHJhbnNsYXRpb24gdHJhbnNmb3JtLiBUaGUgZGVmYXVsdFxyXG5cdFx0Ly8gdmFsdWUgc2hvdWxkIG5vdCBiZSBjaGFuZ2VkIHVubGVzcyBhIHdlYiBicm93c2VyIHBvc2l0aW9ucyBsYXllcnMgaW5cclxuXHRcdC8vIHRoZSB3cm9uZyBwbGFjZSBhZnRlciBkb2luZyBhIGxhcmdlIGBwYW5CeWAuXHJcblx0XHR0cmFuc2Zvcm0zRExpbWl0OiA4Mzg4NjA4LCAvLyBQcmVjaXNpb24gbGltaXQgb2YgYSAzMi1iaXQgZmxvYXRcclxuXHJcblx0XHQvLyBAc2VjdGlvbiBJbnRlcmFjdGlvbiBPcHRpb25zXHJcblx0XHQvLyBAb3B0aW9uIHpvb21TbmFwOiBOdW1iZXIgPSAxXHJcblx0XHQvLyBGb3JjZXMgdGhlIG1hcCdzIHpvb20gbGV2ZWwgdG8gYWx3YXlzIGJlIGEgbXVsdGlwbGUgb2YgdGhpcywgcGFydGljdWxhcmx5XHJcblx0XHQvLyByaWdodCBhZnRlciBhIFtgZml0Qm91bmRzKClgXSgjbWFwLWZpdGJvdW5kcykgb3IgYSBwaW5jaC16b29tLlxyXG5cdFx0Ly8gQnkgZGVmYXVsdCwgdGhlIHpvb20gbGV2ZWwgc25hcHMgdG8gdGhlIG5lYXJlc3QgaW50ZWdlcjsgbG93ZXIgdmFsdWVzXHJcblx0XHQvLyAoZS5nLiBgMC41YCBvciBgMC4xYCkgYWxsb3cgZm9yIGdyZWF0ZXIgZ3JhbnVsYXJpdHkuIEEgdmFsdWUgb2YgYDBgXHJcblx0XHQvLyBtZWFucyB0aGUgem9vbSBsZXZlbCB3aWxsIG5vdCBiZSBzbmFwcGVkIGFmdGVyIGBmaXRCb3VuZHNgIG9yIGEgcGluY2gtem9vbS5cclxuXHRcdHpvb21TbmFwOiAxLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gem9vbURlbHRhOiBOdW1iZXIgPSAxXHJcblx0XHQvLyBDb250cm9scyBob3cgbXVjaCB0aGUgbWFwJ3Mgem9vbSBsZXZlbCB3aWxsIGNoYW5nZSBhZnRlciBhXHJcblx0XHQvLyBbYHpvb21JbigpYF0oI21hcC16b29taW4pLCBbYHpvb21PdXQoKWBdKCNtYXAtem9vbW91dCksIHByZXNzaW5nIGArYFxyXG5cdFx0Ly8gb3IgYC1gIG9uIHRoZSBrZXlib2FyZCwgb3IgdXNpbmcgdGhlIFt6b29tIGNvbnRyb2xzXSgjY29udHJvbC16b29tKS5cclxuXHRcdC8vIFZhbHVlcyBzbWFsbGVyIHRoYW4gYDFgIChlLmcuIGAwLjVgKSBhbGxvdyBmb3IgZ3JlYXRlciBncmFudWxhcml0eS5cclxuXHRcdHpvb21EZWx0YTogMSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHRyYWNrUmVzaXplOiBCb29sZWFuID0gdHJ1ZVxyXG5cdFx0Ly8gV2hldGhlciB0aGUgbWFwIGF1dG9tYXRpY2FsbHkgaGFuZGxlcyBicm93c2VyIHdpbmRvdyByZXNpemUgdG8gdXBkYXRlIGl0c2VsZi5cclxuXHRcdHRyYWNrUmVzaXplOiB0cnVlXHJcblx0fSxcclxuXHJcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGlkLCBvcHRpb25zKSB7IC8vIChIVE1MRWxlbWVudCBvciBTdHJpbmcsIE9iamVjdClcclxuXHRcdG9wdGlvbnMgPSBMLnNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XHJcblxyXG5cdFx0dGhpcy5faW5pdENvbnRhaW5lcihpZCk7XHJcblx0XHR0aGlzLl9pbml0TGF5b3V0KCk7XHJcblxyXG5cdFx0Ly8gaGFjayBmb3IgaHR0cHM6Ly9naXRodWIuY29tL0xlYWZsZXQvTGVhZmxldC9pc3N1ZXMvMTk4MFxyXG5cdFx0dGhpcy5fb25SZXNpemUgPSBMLmJpbmQodGhpcy5fb25SZXNpemUsIHRoaXMpO1xyXG5cclxuXHRcdHRoaXMuX2luaXRFdmVudHMoKTtcclxuXHJcblx0XHRpZiAob3B0aW9ucy5tYXhCb3VuZHMpIHtcclxuXHRcdFx0dGhpcy5zZXRNYXhCb3VuZHMob3B0aW9ucy5tYXhCb3VuZHMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChvcHRpb25zLnpvb20gIT09IHVuZGVmaW5lZCkge1xyXG5cdFx0XHR0aGlzLl96b29tID0gdGhpcy5fbGltaXRab29tKG9wdGlvbnMuem9vbSk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKG9wdGlvbnMuY2VudGVyICYmIG9wdGlvbnMuem9vbSAhPT0gdW5kZWZpbmVkKSB7XHJcblx0XHRcdHRoaXMuc2V0VmlldyhMLmxhdExuZyhvcHRpb25zLmNlbnRlciksIG9wdGlvbnMuem9vbSwge3Jlc2V0OiB0cnVlfSk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5faGFuZGxlcnMgPSBbXTtcclxuXHRcdHRoaXMuX2xheWVycyA9IHt9O1xyXG5cdFx0dGhpcy5fem9vbUJvdW5kTGF5ZXJzID0ge307XHJcblx0XHR0aGlzLl9zaXplQ2hhbmdlZCA9IHRydWU7XHJcblxyXG5cdFx0dGhpcy5jYWxsSW5pdEhvb2tzKCk7XHJcblxyXG5cdFx0Ly8gZG9uJ3QgYW5pbWF0ZSBvbiBicm93c2VycyB3aXRob3V0IGhhcmR3YXJlLWFjY2VsZXJhdGVkIHRyYW5zaXRpb25zIG9yIG9sZCBBbmRyb2lkL09wZXJhXHJcblx0XHR0aGlzLl96b29tQW5pbWF0ZWQgPSBMLkRvbVV0aWwuVFJBTlNJVElPTiAmJiBMLkJyb3dzZXIuYW55M2QgJiYgIUwuQnJvd3Nlci5tb2JpbGVPcGVyYSAmJlxyXG5cdFx0XHRcdHRoaXMub3B0aW9ucy56b29tQW5pbWF0aW9uO1xyXG5cclxuXHRcdC8vIHpvb20gdHJhbnNpdGlvbnMgcnVuIHdpdGggdGhlIHNhbWUgZHVyYXRpb24gZm9yIGFsbCBsYXllcnMsIHNvIGlmIG9uZSBvZiB0cmFuc2l0aW9uZW5kIGV2ZW50c1xyXG5cdFx0Ly8gaGFwcGVucyBhZnRlciBzdGFydGluZyB6b29tIGFuaW1hdGlvbiAocHJvcGFnYXRpbmcgdG8gdGhlIG1hcCBwYW5lKSwgd2Uga25vdyB0aGF0IGl0IGVuZGVkIGdsb2JhbGx5XHJcblx0XHRpZiAodGhpcy5fem9vbUFuaW1hdGVkKSB7XHJcblx0XHRcdHRoaXMuX2NyZWF0ZUFuaW1Qcm94eSgpO1xyXG5cdFx0XHRMLkRvbUV2ZW50Lm9uKHRoaXMuX3Byb3h5LCBMLkRvbVV0aWwuVFJBTlNJVElPTl9FTkQsIHRoaXMuX2NhdGNoVHJhbnNpdGlvbkVuZCwgdGhpcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fYWRkTGF5ZXJzKHRoaXMub3B0aW9ucy5sYXllcnMpO1xyXG5cdH0sXHJcblxyXG5cclxuXHQvLyBAc2VjdGlvbiBNZXRob2RzIGZvciBtb2RpZnlpbmcgbWFwIHN0YXRlXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0VmlldyhjZW50ZXI6IExhdExuZywgem9vbTogTnVtYmVyLCBvcHRpb25zPzogWm9vbS9wYW4gb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBTZXRzIHRoZSB2aWV3IG9mIHRoZSBtYXAgKGdlb2dyYXBoaWNhbCBjZW50ZXIgYW5kIHpvb20pIHdpdGggdGhlIGdpdmVuXHJcblx0Ly8gYW5pbWF0aW9uIG9wdGlvbnMuXHJcblx0c2V0VmlldzogZnVuY3Rpb24gKGNlbnRlciwgem9vbSwgb3B0aW9ucykge1xyXG5cclxuXHRcdHpvb20gPSB6b29tID09PSB1bmRlZmluZWQgPyB0aGlzLl96b29tIDogdGhpcy5fbGltaXRab29tKHpvb20pO1xyXG5cdFx0Y2VudGVyID0gdGhpcy5fbGltaXRDZW50ZXIoTC5sYXRMbmcoY2VudGVyKSwgem9vbSwgdGhpcy5vcHRpb25zLm1heEJvdW5kcyk7XHJcblx0XHRvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcclxuXHJcblx0XHR0aGlzLl9zdG9wKCk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2xvYWRlZCAmJiAhb3B0aW9ucy5yZXNldCAmJiBvcHRpb25zICE9PSB0cnVlKSB7XHJcblxyXG5cdFx0XHRpZiAob3B0aW9ucy5hbmltYXRlICE9PSB1bmRlZmluZWQpIHtcclxuXHRcdFx0XHRvcHRpb25zLnpvb20gPSBMLmV4dGVuZCh7YW5pbWF0ZTogb3B0aW9ucy5hbmltYXRlfSwgb3B0aW9ucy56b29tKTtcclxuXHRcdFx0XHRvcHRpb25zLnBhbiA9IEwuZXh0ZW5kKHthbmltYXRlOiBvcHRpb25zLmFuaW1hdGUsIGR1cmF0aW9uOiBvcHRpb25zLmR1cmF0aW9ufSwgb3B0aW9ucy5wYW4pO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyB0cnkgYW5pbWF0aW5nIHBhbiBvciB6b29tXHJcblx0XHRcdHZhciBtb3ZlZCA9ICh0aGlzLl96b29tICE9PSB6b29tKSA/XHJcblx0XHRcdFx0dGhpcy5fdHJ5QW5pbWF0ZWRab29tICYmIHRoaXMuX3RyeUFuaW1hdGVkWm9vbShjZW50ZXIsIHpvb20sIG9wdGlvbnMuem9vbSkgOlxyXG5cdFx0XHRcdHRoaXMuX3RyeUFuaW1hdGVkUGFuKGNlbnRlciwgb3B0aW9ucy5wYW4pO1xyXG5cclxuXHRcdFx0aWYgKG1vdmVkKSB7XHJcblx0XHRcdFx0Ly8gcHJldmVudCByZXNpemUgaGFuZGxlciBjYWxsLCB0aGUgdmlldyB3aWxsIHJlZnJlc2ggYWZ0ZXIgYW5pbWF0aW9uIGFueXdheVxyXG5cdFx0XHRcdGNsZWFyVGltZW91dCh0aGlzLl9zaXplVGltZXIpO1xyXG5cdFx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gYW5pbWF0aW9uIGRpZG4ndCBzdGFydCwganVzdCByZXNldCB0aGUgbWFwIHZpZXdcclxuXHRcdHRoaXMuX3Jlc2V0VmlldyhjZW50ZXIsIHpvb20pO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0Wm9vbSh6b29tOiBOdW1iZXIsIG9wdGlvbnM6IFpvb20vcGFuIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gU2V0cyB0aGUgem9vbSBvZiB0aGUgbWFwLlxyXG5cdHNldFpvb206IGZ1bmN0aW9uICh6b29tLCBvcHRpb25zKSB7XHJcblx0XHRpZiAoIXRoaXMuX2xvYWRlZCkge1xyXG5cdFx0XHR0aGlzLl96b29tID0gem9vbTtcclxuXHRcdFx0cmV0dXJuIHRoaXM7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcy5zZXRWaWV3KHRoaXMuZ2V0Q2VudGVyKCksIHpvb20sIHt6b29tOiBvcHRpb25zfSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB6b29tSW4oZGVsdGE/OiBOdW1iZXIsIG9wdGlvbnM/OiBab29tIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gSW5jcmVhc2VzIHRoZSB6b29tIG9mIHRoZSBtYXAgYnkgYGRlbHRhYCAoW2B6b29tRGVsdGFgXSgjbWFwLXpvb21kZWx0YSkgYnkgZGVmYXVsdCkuXHJcblx0em9vbUluOiBmdW5jdGlvbiAoZGVsdGEsIG9wdGlvbnMpIHtcclxuXHRcdGRlbHRhID0gZGVsdGEgfHwgKEwuQnJvd3Nlci5hbnkzZCA/IHRoaXMub3B0aW9ucy56b29tRGVsdGEgOiAxKTtcclxuXHRcdHJldHVybiB0aGlzLnNldFpvb20odGhpcy5fem9vbSArIGRlbHRhLCBvcHRpb25zKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHpvb21PdXQoZGVsdGE/OiBOdW1iZXIsIG9wdGlvbnM/OiBab29tIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gRGVjcmVhc2VzIHRoZSB6b29tIG9mIHRoZSBtYXAgYnkgYGRlbHRhYCAoW2B6b29tRGVsdGFgXSgjbWFwLXpvb21kZWx0YSkgYnkgZGVmYXVsdCkuXHJcblx0em9vbU91dDogZnVuY3Rpb24gKGRlbHRhLCBvcHRpb25zKSB7XHJcblx0XHRkZWx0YSA9IGRlbHRhIHx8IChMLkJyb3dzZXIuYW55M2QgPyB0aGlzLm9wdGlvbnMuem9vbURlbHRhIDogMSk7XHJcblx0XHRyZXR1cm4gdGhpcy5zZXRab29tKHRoaXMuX3pvb20gLSBkZWx0YSwgb3B0aW9ucyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBzZXRab29tQXJvdW5kKGxhdGxuZzogTGF0TG5nLCB6b29tOiBOdW1iZXIsIG9wdGlvbnM6IFpvb20gb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBab29tcyB0aGUgbWFwIHdoaWxlIGtlZXBpbmcgYSBzcGVjaWZpZWQgZ2VvZ3JhcGhpY2FsIHBvaW50IG9uIHRoZSBtYXBcclxuXHQvLyBzdGF0aW9uYXJ5IChlLmcuIHVzZWQgaW50ZXJuYWxseSBmb3Igc2Nyb2xsIHpvb20gYW5kIGRvdWJsZS1jbGljayB6b29tKS5cclxuXHQvLyBAYWx0ZXJuYXRpdmVcclxuXHQvLyBAbWV0aG9kIHNldFpvb21Bcm91bmQob2Zmc2V0OiBQb2ludCwgem9vbTogTnVtYmVyLCBvcHRpb25zOiBab29tIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gWm9vbXMgdGhlIG1hcCB3aGlsZSBrZWVwaW5nIGEgc3BlY2lmaWVkIHBpeGVsIG9uIHRoZSBtYXAgKHJlbGF0aXZlIHRvIHRoZSB0b3AtbGVmdCBjb3JuZXIpIHN0YXRpb25hcnkuXHJcblx0c2V0Wm9vbUFyb3VuZDogZnVuY3Rpb24gKGxhdGxuZywgem9vbSwgb3B0aW9ucykge1xyXG5cdFx0dmFyIHNjYWxlID0gdGhpcy5nZXRab29tU2NhbGUoem9vbSksXHJcblx0XHQgICAgdmlld0hhbGYgPSB0aGlzLmdldFNpemUoKS5kaXZpZGVCeSgyKSxcclxuXHRcdCAgICBjb250YWluZXJQb2ludCA9IGxhdGxuZyBpbnN0YW5jZW9mIEwuUG9pbnQgPyBsYXRsbmcgOiB0aGlzLmxhdExuZ1RvQ29udGFpbmVyUG9pbnQobGF0bG5nKSxcclxuXHJcblx0XHQgICAgY2VudGVyT2Zmc2V0ID0gY29udGFpbmVyUG9pbnQuc3VidHJhY3Qodmlld0hhbGYpLm11bHRpcGx5QnkoMSAtIDEgLyBzY2FsZSksXHJcblx0XHQgICAgbmV3Q2VudGVyID0gdGhpcy5jb250YWluZXJQb2ludFRvTGF0TG5nKHZpZXdIYWxmLmFkZChjZW50ZXJPZmZzZXQpKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcy5zZXRWaWV3KG5ld0NlbnRlciwgem9vbSwge3pvb206IG9wdGlvbnN9KTtcclxuXHR9LFxyXG5cclxuXHRfZ2V0Qm91bmRzQ2VudGVyWm9vbTogZnVuY3Rpb24gKGJvdW5kcywgb3B0aW9ucykge1xyXG5cclxuXHRcdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xyXG5cdFx0Ym91bmRzID0gYm91bmRzLmdldEJvdW5kcyA/IGJvdW5kcy5nZXRCb3VuZHMoKSA6IEwubGF0TG5nQm91bmRzKGJvdW5kcyk7XHJcblxyXG5cdFx0dmFyIHBhZGRpbmdUTCA9IEwucG9pbnQob3B0aW9ucy5wYWRkaW5nVG9wTGVmdCB8fCBvcHRpb25zLnBhZGRpbmcgfHwgWzAsIDBdKSxcclxuXHRcdCAgICBwYWRkaW5nQlIgPSBMLnBvaW50KG9wdGlvbnMucGFkZGluZ0JvdHRvbVJpZ2h0IHx8IG9wdGlvbnMucGFkZGluZyB8fCBbMCwgMF0pLFxyXG5cclxuXHRcdCAgICB6b29tID0gdGhpcy5nZXRCb3VuZHNab29tKGJvdW5kcywgZmFsc2UsIHBhZGRpbmdUTC5hZGQocGFkZGluZ0JSKSk7XHJcblxyXG5cdFx0em9vbSA9ICh0eXBlb2Ygb3B0aW9ucy5tYXhab29tID09PSAnbnVtYmVyJykgPyBNYXRoLm1pbihvcHRpb25zLm1heFpvb20sIHpvb20pIDogem9vbTtcclxuXHJcblx0XHR2YXIgcGFkZGluZ09mZnNldCA9IHBhZGRpbmdCUi5zdWJ0cmFjdChwYWRkaW5nVEwpLmRpdmlkZUJ5KDIpLFxyXG5cclxuXHRcdCAgICBzd1BvaW50ID0gdGhpcy5wcm9qZWN0KGJvdW5kcy5nZXRTb3V0aFdlc3QoKSwgem9vbSksXHJcblx0XHQgICAgbmVQb2ludCA9IHRoaXMucHJvamVjdChib3VuZHMuZ2V0Tm9ydGhFYXN0KCksIHpvb20pLFxyXG5cdFx0ICAgIGNlbnRlciA9IHRoaXMudW5wcm9qZWN0KHN3UG9pbnQuYWRkKG5lUG9pbnQpLmRpdmlkZUJ5KDIpLmFkZChwYWRkaW5nT2Zmc2V0KSwgem9vbSk7XHJcblxyXG5cdFx0cmV0dXJuIHtcclxuXHRcdFx0Y2VudGVyOiBjZW50ZXIsXHJcblx0XHRcdHpvb206IHpvb21cclxuXHRcdH07XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBmaXRCb3VuZHMoYm91bmRzOiBMYXRMbmdCb3VuZHMsIG9wdGlvbnM6IGZpdEJvdW5kcyBvcHRpb25zKTogdGhpc1xyXG5cdC8vIFNldHMgYSBtYXAgdmlldyB0aGF0IGNvbnRhaW5zIHRoZSBnaXZlbiBnZW9ncmFwaGljYWwgYm91bmRzIHdpdGggdGhlXHJcblx0Ly8gbWF4aW11bSB6b29tIGxldmVsIHBvc3NpYmxlLlxyXG5cdGZpdEJvdW5kczogZnVuY3Rpb24gKGJvdW5kcywgb3B0aW9ucykge1xyXG5cclxuXHRcdGJvdW5kcyA9IEwubGF0TG5nQm91bmRzKGJvdW5kcyk7XHJcblxyXG5cdFx0aWYgKCFib3VuZHMuaXNWYWxpZCgpKSB7XHJcblx0XHRcdHRocm93IG5ldyBFcnJvcignQm91bmRzIGFyZSBub3QgdmFsaWQuJyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIHRhcmdldCA9IHRoaXMuX2dldEJvdW5kc0NlbnRlclpvb20oYm91bmRzLCBvcHRpb25zKTtcclxuXHRcdHJldHVybiB0aGlzLnNldFZpZXcodGFyZ2V0LmNlbnRlciwgdGFyZ2V0Lnpvb20sIG9wdGlvbnMpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZml0V29ybGQob3B0aW9ucz86IGZpdEJvdW5kcyBvcHRpb25zKTogdGhpc1xyXG5cdC8vIFNldHMgYSBtYXAgdmlldyB0aGF0IG1vc3RseSBjb250YWlucyB0aGUgd2hvbGUgd29ybGQgd2l0aCB0aGUgbWF4aW11bVxyXG5cdC8vIHpvb20gbGV2ZWwgcG9zc2libGUuXHJcblx0Zml0V29ybGQ6IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5maXRCb3VuZHMoW1stOTAsIC0xODBdLCBbOTAsIDE4MF1dLCBvcHRpb25zKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHBhblRvKGxhdGxuZzogTGF0TG5nLCBvcHRpb25zPzogUGFuIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gUGFucyB0aGUgbWFwIHRvIGEgZ2l2ZW4gY2VudGVyLlxyXG5cdHBhblRvOiBmdW5jdGlvbiAoY2VudGVyLCBvcHRpb25zKSB7IC8vIChMYXRMbmcpXHJcblx0XHRyZXR1cm4gdGhpcy5zZXRWaWV3KGNlbnRlciwgdGhpcy5fem9vbSwge3Bhbjogb3B0aW9uc30pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgcGFuQnkob2Zmc2V0OiBQb2ludCk6IHRoaXNcclxuXHQvLyBQYW5zIHRoZSBtYXAgYnkgYSBnaXZlbiBudW1iZXIgb2YgcGl4ZWxzIChhbmltYXRlZCkuXHJcblx0cGFuQnk6IGZ1bmN0aW9uIChvZmZzZXQsIG9wdGlvbnMpIHtcclxuXHRcdG9mZnNldCA9IEwucG9pbnQob2Zmc2V0KS5yb3VuZCgpO1xyXG5cdFx0b3B0aW9ucyA9IG9wdGlvbnMgfHwge307XHJcblxyXG5cdFx0aWYgKCFvZmZzZXQueCAmJiAhb2Zmc2V0LnkpIHtcclxuXHRcdFx0cmV0dXJuIHRoaXMuZmlyZSgnbW92ZWVuZCcpO1xyXG5cdFx0fVxyXG5cdFx0Ly8gSWYgd2UgcGFuIHRvbyBmYXIsIENocm9tZSBnZXRzIGlzc3VlcyB3aXRoIHRpbGVzXHJcblx0XHQvLyBhbmQgbWFrZXMgdGhlbSBkaXNhcHBlYXIgb3IgYXBwZWFyIGluIHRoZSB3cm9uZyBwbGFjZSAoc2xpZ2h0bHkgb2Zmc2V0KSAjMjYwMlxyXG5cdFx0aWYgKG9wdGlvbnMuYW5pbWF0ZSAhPT0gdHJ1ZSAmJiAhdGhpcy5nZXRTaXplKCkuY29udGFpbnMob2Zmc2V0KSkge1xyXG5cdFx0XHR0aGlzLl9yZXNldFZpZXcodGhpcy51bnByb2plY3QodGhpcy5wcm9qZWN0KHRoaXMuZ2V0Q2VudGVyKCkpLmFkZChvZmZzZXQpKSwgdGhpcy5nZXRab29tKCkpO1xyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIXRoaXMuX3BhbkFuaW0pIHtcclxuXHRcdFx0dGhpcy5fcGFuQW5pbSA9IG5ldyBMLlBvc0FuaW1hdGlvbigpO1xyXG5cclxuXHRcdFx0dGhpcy5fcGFuQW5pbS5vbih7XHJcblx0XHRcdFx0J3N0ZXAnOiB0aGlzLl9vblBhblRyYW5zaXRpb25TdGVwLFxyXG5cdFx0XHRcdCdlbmQnOiB0aGlzLl9vblBhblRyYW5zaXRpb25FbmRcclxuXHRcdFx0fSwgdGhpcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gZG9uJ3QgZmlyZSBtb3Zlc3RhcnQgaWYgYW5pbWF0aW5nIGluZXJ0aWFcclxuXHRcdGlmICghb3B0aW9ucy5ub01vdmVTdGFydCkge1xyXG5cdFx0XHR0aGlzLmZpcmUoJ21vdmVzdGFydCcpO1xyXG5cdFx0fVxyXG5cclxuXHRcdC8vIGFuaW1hdGUgcGFuIHVubGVzcyBhbmltYXRlOiBmYWxzZSBzcGVjaWZpZWRcclxuXHRcdGlmIChvcHRpb25zLmFuaW1hdGUgIT09IGZhbHNlKSB7XHJcblx0XHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9tYXBQYW5lLCAnbGVhZmxldC1wYW4tYW5pbScpO1xyXG5cclxuXHRcdFx0dmFyIG5ld1BvcyA9IHRoaXMuX2dldE1hcFBhbmVQb3MoKS5zdWJ0cmFjdChvZmZzZXQpLnJvdW5kKCk7XHJcblx0XHRcdHRoaXMuX3BhbkFuaW0ucnVuKHRoaXMuX21hcFBhbmUsIG5ld1Bvcywgb3B0aW9ucy5kdXJhdGlvbiB8fCAwLjI1LCBvcHRpb25zLmVhc2VMaW5lYXJpdHkpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0dGhpcy5fcmF3UGFuQnkob2Zmc2V0KTtcclxuXHRcdFx0dGhpcy5maXJlKCdtb3ZlJykuZmlyZSgnbW92ZWVuZCcpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZmx5VG8obGF0bG5nOiBMYXRMbmcsIHpvb20/OiBOdW1iZXIsIG9wdGlvbnM/OiBab29tL3BhbiBvcHRpb25zKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIHZpZXcgb2YgdGhlIG1hcCAoZ2VvZ3JhcGhpY2FsIGNlbnRlciBhbmQgem9vbSkgcGVyZm9ybWluZyBhIHNtb290aFxyXG5cdC8vIHBhbi16b29tIGFuaW1hdGlvbi5cclxuXHRmbHlUbzogZnVuY3Rpb24gKHRhcmdldENlbnRlciwgdGFyZ2V0Wm9vbSwgb3B0aW9ucykge1xyXG5cclxuXHRcdG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xyXG5cdFx0aWYgKG9wdGlvbnMuYW5pbWF0ZSA9PT0gZmFsc2UgfHwgIUwuQnJvd3Nlci5hbnkzZCkge1xyXG5cdFx0XHRyZXR1cm4gdGhpcy5zZXRWaWV3KHRhcmdldENlbnRlciwgdGFyZ2V0Wm9vbSwgb3B0aW9ucyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fc3RvcCgpO1xyXG5cclxuXHRcdHZhciBmcm9tID0gdGhpcy5wcm9qZWN0KHRoaXMuZ2V0Q2VudGVyKCkpLFxyXG5cdFx0ICAgIHRvID0gdGhpcy5wcm9qZWN0KHRhcmdldENlbnRlciksXHJcblx0XHQgICAgc2l6ZSA9IHRoaXMuZ2V0U2l6ZSgpLFxyXG5cdFx0ICAgIHN0YXJ0Wm9vbSA9IHRoaXMuX3pvb207XHJcblxyXG5cdFx0dGFyZ2V0Q2VudGVyID0gTC5sYXRMbmcodGFyZ2V0Q2VudGVyKTtcclxuXHRcdHRhcmdldFpvb20gPSB0YXJnZXRab29tID09PSB1bmRlZmluZWQgPyBzdGFydFpvb20gOiB0YXJnZXRab29tO1xyXG5cclxuXHRcdHZhciB3MCA9IE1hdGgubWF4KHNpemUueCwgc2l6ZS55KSxcclxuXHRcdCAgICB3MSA9IHcwICogdGhpcy5nZXRab29tU2NhbGUoc3RhcnRab29tLCB0YXJnZXRab29tKSxcclxuXHRcdCAgICB1MSA9ICh0by5kaXN0YW5jZVRvKGZyb20pKSB8fCAxLFxyXG5cdFx0ICAgIHJobyA9IDEuNDIsXHJcblx0XHQgICAgcmhvMiA9IHJobyAqIHJobztcclxuXHJcblx0XHRmdW5jdGlvbiByKGkpIHtcclxuXHRcdFx0dmFyIHMxID0gaSA/IC0xIDogMSxcclxuXHRcdFx0ICAgIHMyID0gaSA/IHcxIDogdzAsXHJcblx0XHRcdCAgICB0MSA9IHcxICogdzEgLSB3MCAqIHcwICsgczEgKiByaG8yICogcmhvMiAqIHUxICogdTEsXHJcblx0XHRcdCAgICBiMSA9IDIgKiBzMiAqIHJobzIgKiB1MSxcclxuXHRcdFx0ICAgIGIgPSB0MSAvIGIxLFxyXG5cdFx0XHQgICAgc3EgPSBNYXRoLnNxcnQoYiAqIGIgKyAxKSAtIGI7XHJcblxyXG5cdFx0XHQgICAgLy8gd29ya2Fyb3VuZCBmb3IgZmxvYXRpbmcgcG9pbnQgcHJlY2lzaW9uIGJ1ZyB3aGVuIHNxID0gMCwgbG9nID0gLUluZmluaXRlLFxyXG5cdFx0XHQgICAgLy8gdGh1cyB0cmlnZ2VyaW5nIGFuIGluZmluaXRlIGxvb3AgaW4gZmx5VG9cclxuXHRcdFx0ICAgIHZhciBsb2cgPSBzcSA8IDAuMDAwMDAwMDAxID8gLTE4IDogTWF0aC5sb2coc3EpO1xyXG5cclxuXHRcdFx0cmV0dXJuIGxvZztcclxuXHRcdH1cclxuXHJcblx0XHRmdW5jdGlvbiBzaW5oKG4pIHsgcmV0dXJuIChNYXRoLmV4cChuKSAtIE1hdGguZXhwKC1uKSkgLyAyOyB9XHJcblx0XHRmdW5jdGlvbiBjb3NoKG4pIHsgcmV0dXJuIChNYXRoLmV4cChuKSArIE1hdGguZXhwKC1uKSkgLyAyOyB9XHJcblx0XHRmdW5jdGlvbiB0YW5oKG4pIHsgcmV0dXJuIHNpbmgobikgLyBjb3NoKG4pOyB9XHJcblxyXG5cdFx0dmFyIHIwID0gcigwKTtcclxuXHJcblx0XHRmdW5jdGlvbiB3KHMpIHsgcmV0dXJuIHcwICogKGNvc2gocjApIC8gY29zaChyMCArIHJobyAqIHMpKTsgfVxyXG5cdFx0ZnVuY3Rpb24gdShzKSB7IHJldHVybiB3MCAqIChjb3NoKHIwKSAqIHRhbmgocjAgKyByaG8gKiBzKSAtIHNpbmgocjApKSAvIHJobzI7IH1cclxuXHJcblx0XHRmdW5jdGlvbiBlYXNlT3V0KHQpIHsgcmV0dXJuIDEgLSBNYXRoLnBvdygxIC0gdCwgMS41KTsgfVxyXG5cclxuXHRcdHZhciBzdGFydCA9IERhdGUubm93KCksXHJcblx0XHQgICAgUyA9IChyKDEpIC0gcjApIC8gcmhvLFxyXG5cdFx0ICAgIGR1cmF0aW9uID0gb3B0aW9ucy5kdXJhdGlvbiA/IDEwMDAgKiBvcHRpb25zLmR1cmF0aW9uIDogMTAwMCAqIFMgKiAwLjg7XHJcblxyXG5cdFx0ZnVuY3Rpb24gZnJhbWUoKSB7XHJcblx0XHRcdHZhciB0ID0gKERhdGUubm93KCkgLSBzdGFydCkgLyBkdXJhdGlvbixcclxuXHRcdFx0ICAgIHMgPSBlYXNlT3V0KHQpICogUztcclxuXHJcblx0XHRcdGlmICh0IDw9IDEpIHtcclxuXHRcdFx0XHR0aGlzLl9mbHlUb0ZyYW1lID0gTC5VdGlsLnJlcXVlc3RBbmltRnJhbWUoZnJhbWUsIHRoaXMpO1xyXG5cclxuXHRcdFx0XHR0aGlzLl9tb3ZlKFxyXG5cdFx0XHRcdFx0dGhpcy51bnByb2plY3QoZnJvbS5hZGQodG8uc3VidHJhY3QoZnJvbSkubXVsdGlwbHlCeSh1KHMpIC8gdTEpKSwgc3RhcnRab29tKSxcclxuXHRcdFx0XHRcdHRoaXMuZ2V0U2NhbGVab29tKHcwIC8gdyhzKSwgc3RhcnRab29tKSxcclxuXHRcdFx0XHRcdHtmbHlUbzogdHJ1ZX0pO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHR0aGlzXHJcblx0XHRcdFx0XHQuX21vdmUodGFyZ2V0Q2VudGVyLCB0YXJnZXRab29tKVxyXG5cdFx0XHRcdFx0Ll9tb3ZlRW5kKHRydWUpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fbW92ZVN0YXJ0KHRydWUpO1xyXG5cclxuXHRcdGZyYW1lLmNhbGwodGhpcyk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGZseVRvQm91bmRzKGJvdW5kczogTGF0TG5nQm91bmRzLCBvcHRpb25zPzogZml0Qm91bmRzIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gU2V0cyB0aGUgdmlldyBvZiB0aGUgbWFwIHdpdGggYSBzbW9vdGggYW5pbWF0aW9uIGxpa2UgW2BmbHlUb2BdKCNtYXAtZmx5dG8pLFxyXG5cdC8vIGJ1dCB0YWtlcyBhIGJvdW5kcyBwYXJhbWV0ZXIgbGlrZSBbYGZpdEJvdW5kc2BdKCNtYXAtZml0Ym91bmRzKS5cclxuXHRmbHlUb0JvdW5kczogZnVuY3Rpb24gKGJvdW5kcywgb3B0aW9ucykge1xyXG5cdFx0dmFyIHRhcmdldCA9IHRoaXMuX2dldEJvdW5kc0NlbnRlclpvb20oYm91bmRzLCBvcHRpb25zKTtcclxuXHRcdHJldHVybiB0aGlzLmZseVRvKHRhcmdldC5jZW50ZXIsIHRhcmdldC56b29tLCBvcHRpb25zKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldE1heEJvdW5kcyhib3VuZHM6IEJvdW5kcyk6IHRoaXNcclxuXHQvLyBSZXN0cmljdHMgdGhlIG1hcCB2aWV3IHRvIHRoZSBnaXZlbiBib3VuZHMgKHNlZSB0aGUgW21heEJvdW5kc10oI21hcC1tYXhib3VuZHMpIG9wdGlvbikuXHJcblx0c2V0TWF4Qm91bmRzOiBmdW5jdGlvbiAoYm91bmRzKSB7XHJcblx0XHRib3VuZHMgPSBMLmxhdExuZ0JvdW5kcyhib3VuZHMpO1xyXG5cclxuXHRcdGlmICghYm91bmRzLmlzVmFsaWQoKSkge1xyXG5cdFx0XHR0aGlzLm9wdGlvbnMubWF4Qm91bmRzID0gbnVsbDtcclxuXHRcdFx0cmV0dXJuIHRoaXMub2ZmKCdtb3ZlZW5kJywgdGhpcy5fcGFuSW5zaWRlTWF4Qm91bmRzKTtcclxuXHRcdH0gZWxzZSBpZiAodGhpcy5vcHRpb25zLm1heEJvdW5kcykge1xyXG5cdFx0XHR0aGlzLm9mZignbW92ZWVuZCcsIHRoaXMuX3Bhbkluc2lkZU1heEJvdW5kcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5vcHRpb25zLm1heEJvdW5kcyA9IGJvdW5kcztcclxuXHJcblx0XHRpZiAodGhpcy5fbG9hZGVkKSB7XHJcblx0XHRcdHRoaXMuX3Bhbkluc2lkZU1heEJvdW5kcygpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzLm9uKCdtb3ZlZW5kJywgdGhpcy5fcGFuSW5zaWRlTWF4Qm91bmRzKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldE1pblpvb20oem9vbTogTnVtYmVyKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIGxvd2VyIGxpbWl0IGZvciB0aGUgYXZhaWxhYmxlIHpvb20gbGV2ZWxzIChzZWUgdGhlIFttaW5ab29tXSgjbWFwLW1pbnpvb20pIG9wdGlvbikuXHJcblx0c2V0TWluWm9vbTogZnVuY3Rpb24gKHpvb20pIHtcclxuXHRcdHRoaXMub3B0aW9ucy5taW5ab29tID0gem9vbTtcclxuXHJcblx0XHRpZiAodGhpcy5fbG9hZGVkICYmIHRoaXMuZ2V0Wm9vbSgpIDwgdGhpcy5vcHRpb25zLm1pblpvb20pIHtcclxuXHRcdFx0cmV0dXJuIHRoaXMuc2V0Wm9vbSh6b29tKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldE1heFpvb20oem9vbTogTnVtYmVyKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIHVwcGVyIGxpbWl0IGZvciB0aGUgYXZhaWxhYmxlIHpvb20gbGV2ZWxzIChzZWUgdGhlIFttYXhab29tXSgjbWFwLW1heHpvb20pIG9wdGlvbikuXHJcblx0c2V0TWF4Wm9vbTogZnVuY3Rpb24gKHpvb20pIHtcclxuXHRcdHRoaXMub3B0aW9ucy5tYXhab29tID0gem9vbTtcclxuXHJcblx0XHRpZiAodGhpcy5fbG9hZGVkICYmICh0aGlzLmdldFpvb20oKSA+IHRoaXMub3B0aW9ucy5tYXhab29tKSkge1xyXG5cdFx0XHRyZXR1cm4gdGhpcy5zZXRab29tKHpvb20pO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgcGFuSW5zaWRlQm91bmRzKGJvdW5kczogTGF0TG5nQm91bmRzLCBvcHRpb25zPzogUGFuIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gUGFucyB0aGUgbWFwIHRvIHRoZSBjbG9zZXN0IHZpZXcgdGhhdCB3b3VsZCBsaWUgaW5zaWRlIHRoZSBnaXZlbiBib3VuZHMgKGlmIGl0J3Mgbm90IGFscmVhZHkpLCBjb250cm9sbGluZyB0aGUgYW5pbWF0aW9uIHVzaW5nIHRoZSBvcHRpb25zIHNwZWNpZmljLCBpZiBhbnkuXHJcblx0cGFuSW5zaWRlQm91bmRzOiBmdW5jdGlvbiAoYm91bmRzLCBvcHRpb25zKSB7XHJcblx0XHR0aGlzLl9lbmZvcmNpbmdCb3VuZHMgPSB0cnVlO1xyXG5cdFx0dmFyIGNlbnRlciA9IHRoaXMuZ2V0Q2VudGVyKCksXHJcblx0XHQgICAgbmV3Q2VudGVyID0gdGhpcy5fbGltaXRDZW50ZXIoY2VudGVyLCB0aGlzLl96b29tLCBMLmxhdExuZ0JvdW5kcyhib3VuZHMpKTtcclxuXHJcblx0XHRpZiAoIWNlbnRlci5lcXVhbHMobmV3Q2VudGVyKSkge1xyXG5cdFx0XHR0aGlzLnBhblRvKG5ld0NlbnRlciwgb3B0aW9ucyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fZW5mb3JjaW5nQm91bmRzID0gZmFsc2U7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGludmFsaWRhdGVTaXplKG9wdGlvbnM6IFpvb20vUGFuIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gQ2hlY2tzIGlmIHRoZSBtYXAgY29udGFpbmVyIHNpemUgY2hhbmdlZCBhbmQgdXBkYXRlcyB0aGUgbWFwIGlmIHNvIOKAlFxyXG5cdC8vIGNhbGwgaXQgYWZ0ZXIgeW91J3ZlIGNoYW5nZWQgdGhlIG1hcCBzaXplIGR5bmFtaWNhbGx5LCBhbHNvIGFuaW1hdGluZ1xyXG5cdC8vIHBhbiBieSBkZWZhdWx0LiBJZiBgb3B0aW9ucy5wYW5gIGlzIGBmYWxzZWAsIHBhbm5pbmcgd2lsbCBub3Qgb2NjdXIuXHJcblx0Ly8gSWYgYG9wdGlvbnMuZGVib3VuY2VNb3ZlZW5kYCBpcyBgdHJ1ZWAsIGl0IHdpbGwgZGVsYXkgYG1vdmVlbmRgIGV2ZW50IHNvXHJcblx0Ly8gdGhhdCBpdCBkb2Vzbid0IGhhcHBlbiBvZnRlbiBldmVuIGlmIHRoZSBtZXRob2QgaXMgY2FsbGVkIG1hbnlcclxuXHQvLyB0aW1lcyBpbiBhIHJvdy5cclxuXHJcblx0Ly8gQGFsdGVybmF0aXZlXHJcblx0Ly8gQG1ldGhvZCBpbnZhbGlkYXRlU2l6ZShhbmltYXRlOiBCb29sZWFuKTogdGhpc1xyXG5cdC8vIENoZWNrcyBpZiB0aGUgbWFwIGNvbnRhaW5lciBzaXplIGNoYW5nZWQgYW5kIHVwZGF0ZXMgdGhlIG1hcCBpZiBzbyDigJRcclxuXHQvLyBjYWxsIGl0IGFmdGVyIHlvdSd2ZSBjaGFuZ2VkIHRoZSBtYXAgc2l6ZSBkeW5hbWljYWxseSwgYWxzbyBhbmltYXRpbmdcclxuXHQvLyBwYW4gYnkgZGVmYXVsdC5cclxuXHRpbnZhbGlkYXRlU2l6ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcclxuXHRcdGlmICghdGhpcy5fbG9hZGVkKSB7IHJldHVybiB0aGlzOyB9XHJcblxyXG5cdFx0b3B0aW9ucyA9IEwuZXh0ZW5kKHtcclxuXHRcdFx0YW5pbWF0ZTogZmFsc2UsXHJcblx0XHRcdHBhbjogdHJ1ZVxyXG5cdFx0fSwgb3B0aW9ucyA9PT0gdHJ1ZSA/IHthbmltYXRlOiB0cnVlfSA6IG9wdGlvbnMpO1xyXG5cclxuXHRcdHZhciBvbGRTaXplID0gdGhpcy5nZXRTaXplKCk7XHJcblx0XHR0aGlzLl9zaXplQ2hhbmdlZCA9IHRydWU7XHJcblx0XHR0aGlzLl9sYXN0Q2VudGVyID0gbnVsbDtcclxuXHJcblx0XHR2YXIgbmV3U2l6ZSA9IHRoaXMuZ2V0U2l6ZSgpLFxyXG5cdFx0ICAgIG9sZENlbnRlciA9IG9sZFNpemUuZGl2aWRlQnkoMikucm91bmQoKSxcclxuXHRcdCAgICBuZXdDZW50ZXIgPSBuZXdTaXplLmRpdmlkZUJ5KDIpLnJvdW5kKCksXHJcblx0XHQgICAgb2Zmc2V0ID0gb2xkQ2VudGVyLnN1YnRyYWN0KG5ld0NlbnRlcik7XHJcblxyXG5cdFx0aWYgKCFvZmZzZXQueCAmJiAhb2Zmc2V0LnkpIHsgcmV0dXJuIHRoaXM7IH1cclxuXHJcblx0XHRpZiAob3B0aW9ucy5hbmltYXRlICYmIG9wdGlvbnMucGFuKSB7XHJcblx0XHRcdHRoaXMucGFuQnkob2Zmc2V0KTtcclxuXHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRpZiAob3B0aW9ucy5wYW4pIHtcclxuXHRcdFx0XHR0aGlzLl9yYXdQYW5CeShvZmZzZXQpO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHR0aGlzLmZpcmUoJ21vdmUnKTtcclxuXHJcblx0XHRcdGlmIChvcHRpb25zLmRlYm91bmNlTW92ZWVuZCkge1xyXG5cdFx0XHRcdGNsZWFyVGltZW91dCh0aGlzLl9zaXplVGltZXIpO1xyXG5cdFx0XHRcdHRoaXMuX3NpemVUaW1lciA9IHNldFRpbWVvdXQoTC5iaW5kKHRoaXMuZmlyZSwgdGhpcywgJ21vdmVlbmQnKSwgMjAwKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHR0aGlzLmZpcmUoJ21vdmVlbmQnKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEBzZWN0aW9uIE1hcCBzdGF0ZSBjaGFuZ2UgZXZlbnRzXHJcblx0XHQvLyBAZXZlbnQgcmVzaXplOiBSZXNpemVFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFwIGlzIHJlc2l6ZWQuXHJcblx0XHRyZXR1cm4gdGhpcy5maXJlKCdyZXNpemUnLCB7XHJcblx0XHRcdG9sZFNpemU6IG9sZFNpemUsXHJcblx0XHRcdG5ld1NpemU6IG5ld1NpemVcclxuXHRcdH0pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBzZWN0aW9uIE1ldGhvZHMgZm9yIG1vZGlmeWluZyBtYXAgc3RhdGVcclxuXHQvLyBAbWV0aG9kIHN0b3AoKTogdGhpc1xyXG5cdC8vIFN0b3BzIHRoZSBjdXJyZW50bHkgcnVubmluZyBgcGFuVG9gIG9yIGBmbHlUb2AgYW5pbWF0aW9uLCBpZiBhbnkuXHJcblx0c3RvcDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dGhpcy5zZXRab29tKHRoaXMuX2xpbWl0Wm9vbSh0aGlzLl96b29tKSk7XHJcblx0XHRpZiAoIXRoaXMub3B0aW9ucy56b29tU25hcCkge1xyXG5cdFx0XHR0aGlzLmZpcmUoJ3ZpZXdyZXNldCcpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXMuX3N0b3AoKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAc2VjdGlvbiBHZW9sb2NhdGlvbiBtZXRob2RzXHJcblx0Ly8gQG1ldGhvZCBsb2NhdGUob3B0aW9ucz86IExvY2F0ZSBvcHRpb25zKTogdGhpc1xyXG5cdC8vIFRyaWVzIHRvIGxvY2F0ZSB0aGUgdXNlciB1c2luZyB0aGUgR2VvbG9jYXRpb24gQVBJLCBmaXJpbmcgYSBbYGxvY2F0aW9uZm91bmRgXSgjbWFwLWxvY2F0aW9uZm91bmQpXHJcblx0Ly8gZXZlbnQgd2l0aCBsb2NhdGlvbiBkYXRhIG9uIHN1Y2Nlc3Mgb3IgYSBbYGxvY2F0aW9uZXJyb3JgXSgjbWFwLWxvY2F0aW9uZXJyb3IpIGV2ZW50IG9uIGZhaWx1cmUsXHJcblx0Ly8gYW5kIG9wdGlvbmFsbHkgc2V0cyB0aGUgbWFwIHZpZXcgdG8gdGhlIHVzZXIncyBsb2NhdGlvbiB3aXRoIHJlc3BlY3QgdG9cclxuXHQvLyBkZXRlY3Rpb24gYWNjdXJhY3kgKG9yIHRvIHRoZSB3b3JsZCB2aWV3IGlmIGdlb2xvY2F0aW9uIGZhaWxlZCkuXHJcblx0Ly8gTm90ZSB0aGF0LCBpZiB5b3VyIHBhZ2UgZG9lc24ndCB1c2UgSFRUUFMsIHRoaXMgbWV0aG9kIHdpbGwgZmFpbCBpblxyXG5cdC8vIG1vZGVybiBicm93c2VycyAoW0Nocm9tZSA1MCBhbmQgbmV3ZXJdKGh0dHBzOi8vc2l0ZXMuZ29vZ2xlLmNvbS9hL2Nocm9taXVtLm9yZy9kZXYvSG9tZS9jaHJvbWl1bS1zZWN1cml0eS9kZXByZWNhdGluZy1wb3dlcmZ1bC1mZWF0dXJlcy1vbi1pbnNlY3VyZS1vcmlnaW5zKSlcclxuXHQvLyBTZWUgYExvY2F0ZSBvcHRpb25zYCBmb3IgbW9yZSBkZXRhaWxzLlxyXG5cdGxvY2F0ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcclxuXHJcblx0XHRvcHRpb25zID0gdGhpcy5fbG9jYXRlT3B0aW9ucyA9IEwuZXh0ZW5kKHtcclxuXHRcdFx0dGltZW91dDogMTAwMDAsXHJcblx0XHRcdHdhdGNoOiBmYWxzZVxyXG5cdFx0XHQvLyBzZXRWaWV3OiBmYWxzZVxyXG5cdFx0XHQvLyBtYXhab29tOiA8TnVtYmVyPlxyXG5cdFx0XHQvLyBtYXhpbXVtQWdlOiAwXHJcblx0XHRcdC8vIGVuYWJsZUhpZ2hBY2N1cmFjeTogZmFsc2VcclxuXHRcdH0sIG9wdGlvbnMpO1xyXG5cclxuXHRcdGlmICghKCdnZW9sb2NhdGlvbicgaW4gbmF2aWdhdG9yKSkge1xyXG5cdFx0XHR0aGlzLl9oYW5kbGVHZW9sb2NhdGlvbkVycm9yKHtcclxuXHRcdFx0XHRjb2RlOiAwLFxyXG5cdFx0XHRcdG1lc3NhZ2U6ICdHZW9sb2NhdGlvbiBub3Qgc3VwcG9ydGVkLidcclxuXHRcdFx0fSk7XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBvblJlc3BvbnNlID0gTC5iaW5kKHRoaXMuX2hhbmRsZUdlb2xvY2F0aW9uUmVzcG9uc2UsIHRoaXMpLFxyXG5cdFx0ICAgIG9uRXJyb3IgPSBMLmJpbmQodGhpcy5faGFuZGxlR2VvbG9jYXRpb25FcnJvciwgdGhpcyk7XHJcblxyXG5cdFx0aWYgKG9wdGlvbnMud2F0Y2gpIHtcclxuXHRcdFx0dGhpcy5fbG9jYXRpb25XYXRjaElkID1cclxuXHRcdFx0ICAgICAgICBuYXZpZ2F0b3IuZ2VvbG9jYXRpb24ud2F0Y2hQb3NpdGlvbihvblJlc3BvbnNlLCBvbkVycm9yLCBvcHRpb25zKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdG5hdmlnYXRvci5nZW9sb2NhdGlvbi5nZXRDdXJyZW50UG9zaXRpb24ob25SZXNwb25zZSwgb25FcnJvciwgb3B0aW9ucyk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHN0b3BMb2NhdGUoKTogdGhpc1xyXG5cdC8vIFN0b3BzIHdhdGNoaW5nIGxvY2F0aW9uIHByZXZpb3VzbHkgaW5pdGlhdGVkIGJ5IGBtYXAubG9jYXRlKHt3YXRjaDogdHJ1ZX0pYFxyXG5cdC8vIGFuZCBhYm9ydHMgcmVzZXR0aW5nIHRoZSBtYXAgdmlldyBpZiBtYXAubG9jYXRlIHdhcyBjYWxsZWQgd2l0aFxyXG5cdC8vIGB7c2V0VmlldzogdHJ1ZX1gLlxyXG5cdHN0b3BMb2NhdGU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmIChuYXZpZ2F0b3IuZ2VvbG9jYXRpb24gJiYgbmF2aWdhdG9yLmdlb2xvY2F0aW9uLmNsZWFyV2F0Y2gpIHtcclxuXHRcdFx0bmF2aWdhdG9yLmdlb2xvY2F0aW9uLmNsZWFyV2F0Y2godGhpcy5fbG9jYXRpb25XYXRjaElkKTtcclxuXHRcdH1cclxuXHRcdGlmICh0aGlzLl9sb2NhdGVPcHRpb25zKSB7XHJcblx0XHRcdHRoaXMuX2xvY2F0ZU9wdGlvbnMuc2V0VmlldyA9IGZhbHNlO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0X2hhbmRsZUdlb2xvY2F0aW9uRXJyb3I6IGZ1bmN0aW9uIChlcnJvcikge1xyXG5cdFx0dmFyIGMgPSBlcnJvci5jb2RlLFxyXG5cdFx0ICAgIG1lc3NhZ2UgPSBlcnJvci5tZXNzYWdlIHx8XHJcblx0XHQgICAgICAgICAgICAoYyA9PT0gMSA/ICdwZXJtaXNzaW9uIGRlbmllZCcgOlxyXG5cdFx0ICAgICAgICAgICAgKGMgPT09IDIgPyAncG9zaXRpb24gdW5hdmFpbGFibGUnIDogJ3RpbWVvdXQnKSk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2xvY2F0ZU9wdGlvbnMuc2V0VmlldyAmJiAhdGhpcy5fbG9hZGVkKSB7XHJcblx0XHRcdHRoaXMuZml0V29ybGQoKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBAc2VjdGlvbiBMb2NhdGlvbiBldmVudHNcclxuXHRcdC8vIEBldmVudCBsb2NhdGlvbmVycm9yOiBFcnJvckV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIGdlb2xvY2F0aW9uICh1c2luZyB0aGUgW2Bsb2NhdGVgXSgjbWFwLWxvY2F0ZSkgbWV0aG9kKSBmYWlsZWQuXHJcblx0XHR0aGlzLmZpcmUoJ2xvY2F0aW9uZXJyb3InLCB7XHJcblx0XHRcdGNvZGU6IGMsXHJcblx0XHRcdG1lc3NhZ2U6ICdHZW9sb2NhdGlvbiBlcnJvcjogJyArIG1lc3NhZ2UgKyAnLidcclxuXHRcdH0pO1xyXG5cdH0sXHJcblxyXG5cdF9oYW5kbGVHZW9sb2NhdGlvblJlc3BvbnNlOiBmdW5jdGlvbiAocG9zKSB7XHJcblx0XHR2YXIgbGF0ID0gcG9zLmNvb3Jkcy5sYXRpdHVkZSxcclxuXHRcdCAgICBsbmcgPSBwb3MuY29vcmRzLmxvbmdpdHVkZSxcclxuXHRcdCAgICBsYXRsbmcgPSBuZXcgTC5MYXRMbmcobGF0LCBsbmcpLFxyXG5cdFx0ICAgIGJvdW5kcyA9IGxhdGxuZy50b0JvdW5kcyhwb3MuY29vcmRzLmFjY3VyYWN5KSxcclxuXHRcdCAgICBvcHRpb25zID0gdGhpcy5fbG9jYXRlT3B0aW9ucztcclxuXHJcblx0XHRpZiAob3B0aW9ucy5zZXRWaWV3KSB7XHJcblx0XHRcdHZhciB6b29tID0gdGhpcy5nZXRCb3VuZHNab29tKGJvdW5kcyk7XHJcblx0XHRcdHRoaXMuc2V0VmlldyhsYXRsbmcsIG9wdGlvbnMubWF4Wm9vbSA/IE1hdGgubWluKHpvb20sIG9wdGlvbnMubWF4Wm9vbSkgOiB6b29tKTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgZGF0YSA9IHtcclxuXHRcdFx0bGF0bG5nOiBsYXRsbmcsXHJcblx0XHRcdGJvdW5kczogYm91bmRzLFxyXG5cdFx0XHR0aW1lc3RhbXA6IHBvcy50aW1lc3RhbXBcclxuXHRcdH07XHJcblxyXG5cdFx0Zm9yICh2YXIgaSBpbiBwb3MuY29vcmRzKSB7XHJcblx0XHRcdGlmICh0eXBlb2YgcG9zLmNvb3Jkc1tpXSA9PT0gJ251bWJlcicpIHtcclxuXHRcdFx0XHRkYXRhW2ldID0gcG9zLmNvb3Jkc1tpXTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEBldmVudCBsb2NhdGlvbmZvdW5kOiBMb2NhdGlvbkV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIGdlb2xvY2F0aW9uICh1c2luZyB0aGUgW2Bsb2NhdGVgXSgjbWFwLWxvY2F0ZSkgbWV0aG9kKVxyXG5cdFx0Ly8gd2VudCBzdWNjZXNzZnVsbHkuXHJcblx0XHR0aGlzLmZpcmUoJ2xvY2F0aW9uZm91bmQnLCBkYXRhKTtcclxuXHR9LFxyXG5cclxuXHQvLyBUT0RPIGhhbmRsZXIuYWRkVG9cclxuXHQvLyBUT0RPIEFwcHJvcGlhdGUgZG9jcyBzZWN0aW9uP1xyXG5cdC8vIEBzZWN0aW9uIE90aGVyIE1ldGhvZHNcclxuXHQvLyBAbWV0aG9kIGFkZEhhbmRsZXIobmFtZTogU3RyaW5nLCBIYW5kbGVyQ2xhc3M6IEZ1bmN0aW9uKTogdGhpc1xyXG5cdC8vIEFkZHMgYSBuZXcgYEhhbmRsZXJgIHRvIHRoZSBtYXAsIGdpdmVuIGl0cyBuYW1lIGFuZCBjb25zdHJ1Y3RvciBmdW5jdGlvbi5cclxuXHRhZGRIYW5kbGVyOiBmdW5jdGlvbiAobmFtZSwgSGFuZGxlckNsYXNzKSB7XHJcblx0XHRpZiAoIUhhbmRsZXJDbGFzcykgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdHZhciBoYW5kbGVyID0gdGhpc1tuYW1lXSA9IG5ldyBIYW5kbGVyQ2xhc3ModGhpcyk7XHJcblxyXG5cdFx0dGhpcy5faGFuZGxlcnMucHVzaChoYW5kbGVyKTtcclxuXHJcblx0XHRpZiAodGhpcy5vcHRpb25zW25hbWVdKSB7XHJcblx0XHRcdGhhbmRsZXIuZW5hYmxlKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCByZW1vdmUoKTogdGhpc1xyXG5cdC8vIERlc3Ryb3lzIHRoZSBtYXAgYW5kIGNsZWFycyBhbGwgcmVsYXRlZCBldmVudCBsaXN0ZW5lcnMuXHJcblx0cmVtb3ZlOiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0dGhpcy5faW5pdEV2ZW50cyh0cnVlKTtcclxuXHJcblx0XHRpZiAodGhpcy5fY29udGFpbmVySWQgIT09IHRoaXMuX2NvbnRhaW5lci5fbGVhZmxldF9pZCkge1xyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ01hcCBjb250YWluZXIgaXMgYmVpbmcgcmV1c2VkIGJ5IGFub3RoZXIgaW5zdGFuY2UnKTtcclxuXHRcdH1cclxuXHJcblx0XHR0cnkge1xyXG5cdFx0XHQvLyB0aHJvd3MgZXJyb3IgaW4gSUU2LThcclxuXHRcdFx0ZGVsZXRlIHRoaXMuX2NvbnRhaW5lci5fbGVhZmxldF9pZDtcclxuXHRcdFx0ZGVsZXRlIHRoaXMuX2NvbnRhaW5lcklkO1xyXG5cdFx0fSBjYXRjaCAoZSkge1xyXG5cdFx0XHQvKmVzbGludC1kaXNhYmxlICovXHJcblx0XHRcdHRoaXMuX2NvbnRhaW5lci5fbGVhZmxldF9pZCA9IHVuZGVmaW5lZDtcclxuXHRcdFx0Lyplc2xpbnQtZW5hYmxlICovXHJcblx0XHRcdHRoaXMuX2NvbnRhaW5lcklkID0gdW5kZWZpbmVkO1xyXG5cdFx0fVxyXG5cclxuXHRcdEwuRG9tVXRpbC5yZW1vdmUodGhpcy5fbWFwUGFuZSk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2NsZWFyQ29udHJvbFBvcykge1xyXG5cdFx0XHR0aGlzLl9jbGVhckNvbnRyb2xQb3MoKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9jbGVhckhhbmRsZXJzKCk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2xvYWRlZCkge1xyXG5cdFx0XHQvLyBAc2VjdGlvbiBNYXAgc3RhdGUgY2hhbmdlIGV2ZW50c1xyXG5cdFx0XHQvLyBAZXZlbnQgdW5sb2FkOiBFdmVudFxyXG5cdFx0XHQvLyBGaXJlZCB3aGVuIHRoZSBtYXAgaXMgZGVzdHJveWVkIHdpdGggW3JlbW92ZV0oI21hcC1yZW1vdmUpIG1ldGhvZC5cclxuXHRcdFx0dGhpcy5maXJlKCd1bmxvYWQnKTtcclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKHZhciBpIGluIHRoaXMuX2xheWVycykge1xyXG5cdFx0XHR0aGlzLl9sYXllcnNbaV0ucmVtb3ZlKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQHNlY3Rpb24gT3RoZXIgTWV0aG9kc1xyXG5cdC8vIEBtZXRob2QgY3JlYXRlUGFuZShuYW1lOiBTdHJpbmcsIGNvbnRhaW5lcj86IEhUTUxFbGVtZW50KTogSFRNTEVsZW1lbnRcclxuXHQvLyBDcmVhdGVzIGEgbmV3IFttYXAgcGFuZV0oI21hcC1wYW5lKSB3aXRoIHRoZSBnaXZlbiBuYW1lIGlmIGl0IGRvZXNuJ3QgZXhpc3QgYWxyZWFkeSxcclxuXHQvLyB0aGVuIHJldHVybnMgaXQuIFRoZSBwYW5lIGlzIGNyZWF0ZWQgYXMgYSBjaGlsZHJlbiBvZiBgY29udGFpbmVyYCwgb3JcclxuXHQvLyBhcyBhIGNoaWxkcmVuIG9mIHRoZSBtYWluIG1hcCBwYW5lIGlmIG5vdCBzZXQuXHJcblx0Y3JlYXRlUGFuZTogZnVuY3Rpb24gKG5hbWUsIGNvbnRhaW5lcikge1xyXG5cdFx0dmFyIGNsYXNzTmFtZSA9ICdsZWFmbGV0LXBhbmUnICsgKG5hbWUgPyAnIGxlYWZsZXQtJyArIG5hbWUucmVwbGFjZSgnUGFuZScsICcnKSArICctcGFuZScgOiAnJyksXHJcblx0XHQgICAgcGFuZSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsIGNsYXNzTmFtZSwgY29udGFpbmVyIHx8IHRoaXMuX21hcFBhbmUpO1xyXG5cclxuXHRcdGlmIChuYW1lKSB7XHJcblx0XHRcdHRoaXMuX3BhbmVzW25hbWVdID0gcGFuZTtcclxuXHRcdH1cclxuXHRcdHJldHVybiBwYW5lO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBzZWN0aW9uIE1ldGhvZHMgZm9yIEdldHRpbmcgTWFwIFN0YXRlXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Q2VudGVyKCk6IExhdExuZ1xyXG5cdC8vIFJldHVybnMgdGhlIGdlb2dyYXBoaWNhbCBjZW50ZXIgb2YgdGhlIG1hcCB2aWV3XHJcblx0Z2V0Q2VudGVyOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzLl9jaGVja0lmTG9hZGVkKCk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2xhc3RDZW50ZXIgJiYgIXRoaXMuX21vdmVkKCkpIHtcclxuXHRcdFx0cmV0dXJuIHRoaXMuX2xhc3RDZW50ZXI7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcy5sYXllclBvaW50VG9MYXRMbmcodGhpcy5fZ2V0Q2VudGVyTGF5ZXJQb2ludCgpKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFpvb20oKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgY3VycmVudCB6b29tIGxldmVsIG9mIHRoZSBtYXAgdmlld1xyXG5cdGdldFpvb206IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl96b29tO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Qm91bmRzKCk6IExhdExuZ0JvdW5kc1xyXG5cdC8vIFJldHVybnMgdGhlIGdlb2dyYXBoaWNhbCBib3VuZHMgdmlzaWJsZSBpbiB0aGUgY3VycmVudCBtYXAgdmlld1xyXG5cdGdldEJvdW5kczogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGJvdW5kcyA9IHRoaXMuZ2V0UGl4ZWxCb3VuZHMoKSxcclxuXHRcdCAgICBzdyA9IHRoaXMudW5wcm9qZWN0KGJvdW5kcy5nZXRCb3R0b21MZWZ0KCkpLFxyXG5cdFx0ICAgIG5lID0gdGhpcy51bnByb2plY3QoYm91bmRzLmdldFRvcFJpZ2h0KCkpO1xyXG5cclxuXHRcdHJldHVybiBuZXcgTC5MYXRMbmdCb3VuZHMoc3csIG5lKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldE1pblpvb20oKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgbWluaW11bSB6b29tIGxldmVsIG9mIHRoZSBtYXAgKGlmIHNldCBpbiB0aGUgYG1pblpvb21gIG9wdGlvbiBvZiB0aGUgbWFwIG9yIG9mIGFueSBsYXllcnMpLCBvciBgMGAgYnkgZGVmYXVsdC5cclxuXHRnZXRNaW5ab29tOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLm1pblpvb20gPT09IHVuZGVmaW5lZCA/IHRoaXMuX2xheWVyc01pblpvb20gfHwgMCA6IHRoaXMub3B0aW9ucy5taW5ab29tO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0TWF4Wm9vbSgpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBtYXhpbXVtIHpvb20gbGV2ZWwgb2YgdGhlIG1hcCAoaWYgc2V0IGluIHRoZSBgbWF4Wm9vbWAgb3B0aW9uIG9mIHRoZSBtYXAgb3Igb2YgYW55IGxheWVycykuXHJcblx0Z2V0TWF4Wm9vbTogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5tYXhab29tID09PSB1bmRlZmluZWQgP1xyXG5cdFx0XHQodGhpcy5fbGF5ZXJzTWF4Wm9vbSA9PT0gdW5kZWZpbmVkID8gSW5maW5pdHkgOiB0aGlzLl9sYXllcnNNYXhab29tKSA6XHJcblx0XHRcdHRoaXMub3B0aW9ucy5tYXhab29tO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Qm91bmRzWm9vbShib3VuZHM6IExhdExuZ0JvdW5kcywgaW5zaWRlPzogQm9vbGVhbik6IE51bWJlclxyXG5cdC8vIFJldHVybnMgdGhlIG1heGltdW0gem9vbSBsZXZlbCBvbiB3aGljaCB0aGUgZ2l2ZW4gYm91bmRzIGZpdCB0byB0aGUgbWFwXHJcblx0Ly8gdmlldyBpbiBpdHMgZW50aXJldHkuIElmIGBpbnNpZGVgIChvcHRpb25hbCkgaXMgc2V0IHRvIGB0cnVlYCwgdGhlIG1ldGhvZFxyXG5cdC8vIGluc3RlYWQgcmV0dXJucyB0aGUgbWluaW11bSB6b29tIGxldmVsIG9uIHdoaWNoIHRoZSBtYXAgdmlldyBmaXRzIGludG9cclxuXHQvLyB0aGUgZ2l2ZW4gYm91bmRzIGluIGl0cyBlbnRpcmV0eS5cclxuXHRnZXRCb3VuZHNab29tOiBmdW5jdGlvbiAoYm91bmRzLCBpbnNpZGUsIHBhZGRpbmcpIHsgLy8gKExhdExuZ0JvdW5kc1ssIEJvb2xlYW4sIFBvaW50XSkgLT4gTnVtYmVyXHJcblx0XHRib3VuZHMgPSBMLmxhdExuZ0JvdW5kcyhib3VuZHMpO1xyXG5cdFx0cGFkZGluZyA9IEwucG9pbnQocGFkZGluZyB8fCBbMCwgMF0pO1xyXG5cclxuXHRcdHZhciB6b29tID0gdGhpcy5nZXRab29tKCkgfHwgMCxcclxuXHRcdCAgICBtaW4gPSB0aGlzLmdldE1pblpvb20oKSxcclxuXHRcdCAgICBtYXggPSB0aGlzLmdldE1heFpvb20oKSxcclxuXHRcdCAgICBudyA9IGJvdW5kcy5nZXROb3J0aFdlc3QoKSxcclxuXHRcdCAgICBzZSA9IGJvdW5kcy5nZXRTb3V0aEVhc3QoKSxcclxuXHRcdCAgICBzaXplID0gdGhpcy5nZXRTaXplKCkuc3VidHJhY3QocGFkZGluZyksXHJcblx0XHQgICAgYm91bmRzU2l6ZSA9IHRoaXMucHJvamVjdChzZSwgem9vbSkuc3VidHJhY3QodGhpcy5wcm9qZWN0KG53LCB6b29tKSksXHJcblx0XHQgICAgc25hcCA9IEwuQnJvd3Nlci5hbnkzZCA/IHRoaXMub3B0aW9ucy56b29tU25hcCA6IDE7XHJcblxyXG5cdFx0dmFyIHNjYWxlID0gTWF0aC5taW4oc2l6ZS54IC8gYm91bmRzU2l6ZS54LCBzaXplLnkgLyBib3VuZHNTaXplLnkpO1xyXG5cdFx0em9vbSA9IHRoaXMuZ2V0U2NhbGVab29tKHNjYWxlLCB6b29tKTtcclxuXHJcblx0XHRpZiAoc25hcCkge1xyXG5cdFx0XHR6b29tID0gTWF0aC5yb3VuZCh6b29tIC8gKHNuYXAgLyAxMDApKSAqIChzbmFwIC8gMTAwKTsgLy8gZG9uJ3QganVtcCBpZiB3aXRoaW4gMSUgb2YgYSBzbmFwIGxldmVsXHJcblx0XHRcdHpvb20gPSBpbnNpZGUgPyBNYXRoLmNlaWwoem9vbSAvIHNuYXApICogc25hcCA6IE1hdGguZmxvb3Ioem9vbSAvIHNuYXApICogc25hcDtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gTWF0aC5tYXgobWluLCBNYXRoLm1pbihtYXgsIHpvb20pKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFNpemUoKTogUG9pbnRcclxuXHQvLyBSZXR1cm5zIHRoZSBjdXJyZW50IHNpemUgb2YgdGhlIG1hcCBjb250YWluZXIgKGluIHBpeGVscykuXHJcblx0Z2V0U2l6ZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLl9zaXplIHx8IHRoaXMuX3NpemVDaGFuZ2VkKSB7XHJcblx0XHRcdHRoaXMuX3NpemUgPSBuZXcgTC5Qb2ludChcclxuXHRcdFx0XHR0aGlzLl9jb250YWluZXIuY2xpZW50V2lkdGgsXHJcblx0XHRcdFx0dGhpcy5fY29udGFpbmVyLmNsaWVudEhlaWdodCk7XHJcblxyXG5cdFx0XHR0aGlzLl9zaXplQ2hhbmdlZCA9IGZhbHNlO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXMuX3NpemUuY2xvbmUoKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFBpeGVsQm91bmRzKCk6IEJvdW5kc1xyXG5cdC8vIFJldHVybnMgdGhlIGJvdW5kcyBvZiB0aGUgY3VycmVudCBtYXAgdmlldyBpbiBwcm9qZWN0ZWQgcGl4ZWxcclxuXHQvLyBjb29yZGluYXRlcyAoc29tZXRpbWVzIHVzZWZ1bCBpbiBsYXllciBhbmQgb3ZlcmxheSBpbXBsZW1lbnRhdGlvbnMpLlxyXG5cdGdldFBpeGVsQm91bmRzOiBmdW5jdGlvbiAoY2VudGVyLCB6b29tKSB7XHJcblx0XHR2YXIgdG9wTGVmdFBvaW50ID0gdGhpcy5fZ2V0VG9wTGVmdFBvaW50KGNlbnRlciwgem9vbSk7XHJcblx0XHRyZXR1cm4gbmV3IEwuQm91bmRzKHRvcExlZnRQb2ludCwgdG9wTGVmdFBvaW50LmFkZCh0aGlzLmdldFNpemUoKSkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIFRPRE86IENoZWNrIHNlbWFudGljcyAtIGlzbid0IHRoZSBwaXhlbCBvcmlnaW4gdGhlIDAsMCBjb29yZCByZWxhdGl2ZSB0b1xyXG5cdC8vIHRoZSBtYXAgcGFuZT8gXCJsZWZ0IHBvaW50IG9mIHRoZSBtYXAgbGF5ZXJcIiBjYW4gYmUgY29uZnVzaW5nLCBzcGVjaWFsbHlcclxuXHQvLyBzaW5jZSB0aGVyZSBjYW4gYmUgbmVnYXRpdmUgb2Zmc2V0cy5cclxuXHQvLyBAbWV0aG9kIGdldFBpeGVsT3JpZ2luKCk6IFBvaW50XHJcblx0Ly8gUmV0dXJucyB0aGUgcHJvamVjdGVkIHBpeGVsIGNvb3JkaW5hdGVzIG9mIHRoZSB0b3AgbGVmdCBwb2ludCBvZlxyXG5cdC8vIHRoZSBtYXAgbGF5ZXIgKHVzZWZ1bCBpbiBjdXN0b20gbGF5ZXIgYW5kIG92ZXJsYXkgaW1wbGVtZW50YXRpb25zKS5cclxuXHRnZXRQaXhlbE9yaWdpbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0dGhpcy5fY2hlY2tJZkxvYWRlZCgpO1xyXG5cdFx0cmV0dXJuIHRoaXMuX3BpeGVsT3JpZ2luO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0UGl4ZWxXb3JsZEJvdW5kcyh6b29tPzogTnVtYmVyKTogQm91bmRzXHJcblx0Ly8gUmV0dXJucyB0aGUgd29ybGQncyBib3VuZHMgaW4gcGl4ZWwgY29vcmRpbmF0ZXMgZm9yIHpvb20gbGV2ZWwgYHpvb21gLlxyXG5cdC8vIElmIGB6b29tYCBpcyBvbWl0dGVkLCB0aGUgbWFwJ3MgY3VycmVudCB6b29tIGxldmVsIGlzIHVzZWQuXHJcblx0Z2V0UGl4ZWxXb3JsZEJvdW5kczogZnVuY3Rpb24gKHpvb20pIHtcclxuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMuY3JzLmdldFByb2plY3RlZEJvdW5kcyh6b29tID09PSB1bmRlZmluZWQgPyB0aGlzLmdldFpvb20oKSA6IHpvb20pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBzZWN0aW9uIE90aGVyIE1ldGhvZHNcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRQYW5lKHBhbmU6IFN0cmluZ3xIVE1MRWxlbWVudCk6IEhUTUxFbGVtZW50XHJcblx0Ly8gUmV0dXJucyBhIFttYXAgcGFuZV0oI21hcC1wYW5lKSwgZ2l2ZW4gaXRzIG5hbWUgb3IgaXRzIEhUTUwgZWxlbWVudCAoaXRzIGlkZW50aXR5KS5cclxuXHRnZXRQYW5lOiBmdW5jdGlvbiAocGFuZSkge1xyXG5cdFx0cmV0dXJuIHR5cGVvZiBwYW5lID09PSAnc3RyaW5nJyA/IHRoaXMuX3BhbmVzW3BhbmVdIDogcGFuZTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFBhbmVzKCk6IE9iamVjdFxyXG5cdC8vIFJldHVybnMgYSBwbGFpbiBvYmplY3QgY29udGFpbmluZyB0aGUgbmFtZXMgb2YgYWxsIFtwYW5lc10oI21hcC1wYW5lKSBhcyBrZXlzIGFuZFxyXG5cdC8vIHRoZSBwYW5lcyBhcyB2YWx1ZXMuXHJcblx0Z2V0UGFuZXM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9wYW5lcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldENvbnRhaW5lcjogSFRNTEVsZW1lbnRcclxuXHQvLyBSZXR1cm5zIHRoZSBIVE1MIGVsZW1lbnQgdGhhdCBjb250YWlucyB0aGUgbWFwLlxyXG5cdGdldENvbnRhaW5lcjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX2NvbnRhaW5lcjtcclxuXHR9LFxyXG5cclxuXHJcblx0Ly8gQHNlY3Rpb24gQ29udmVyc2lvbiBNZXRob2RzXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0Wm9vbVNjYWxlKHRvWm9vbTogTnVtYmVyLCBmcm9tWm9vbTogTnVtYmVyKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgc2NhbGUgZmFjdG9yIHRvIGJlIGFwcGxpZWQgdG8gYSBtYXAgdHJhbnNpdGlvbiBmcm9tIHpvb20gbGV2ZWxcclxuXHQvLyBgZnJvbVpvb21gIHRvIGB0b1pvb21gLiBVc2VkIGludGVybmFsbHkgdG8gaGVscCB3aXRoIHpvb20gYW5pbWF0aW9ucy5cclxuXHRnZXRab29tU2NhbGU6IGZ1bmN0aW9uICh0b1pvb20sIGZyb21ab29tKSB7XHJcblx0XHQvLyBUT0RPIHJlcGxhY2Ugd2l0aCB1bml2ZXJzYWwgaW1wbGVtZW50YXRpb24gYWZ0ZXIgcmVmYWN0b3JpbmcgcHJvamVjdGlvbnNcclxuXHRcdHZhciBjcnMgPSB0aGlzLm9wdGlvbnMuY3JzO1xyXG5cdFx0ZnJvbVpvb20gPSBmcm9tWm9vbSA9PT0gdW5kZWZpbmVkID8gdGhpcy5fem9vbSA6IGZyb21ab29tO1xyXG5cdFx0cmV0dXJuIGNycy5zY2FsZSh0b1pvb20pIC8gY3JzLnNjYWxlKGZyb21ab29tKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldFNjYWxlWm9vbShzY2FsZTogTnVtYmVyLCBmcm9tWm9vbTogTnVtYmVyKTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgem9vbSBsZXZlbCB0aGF0IHRoZSBtYXAgd291bGQgZW5kIHVwIGF0LCBpZiBpdCBpcyBhdCBgZnJvbVpvb21gXHJcblx0Ly8gbGV2ZWwgYW5kIGV2ZXJ5dGhpbmcgaXMgc2NhbGVkIGJ5IGEgZmFjdG9yIG9mIGBzY2FsZWAuIEludmVyc2Ugb2ZcclxuXHQvLyBbYGdldFpvb21TY2FsZWBdKCNtYXAtZ2V0Wm9vbVNjYWxlKS5cclxuXHRnZXRTY2FsZVpvb206IGZ1bmN0aW9uIChzY2FsZSwgZnJvbVpvb20pIHtcclxuXHRcdHZhciBjcnMgPSB0aGlzLm9wdGlvbnMuY3JzO1xyXG5cdFx0ZnJvbVpvb20gPSBmcm9tWm9vbSA9PT0gdW5kZWZpbmVkID8gdGhpcy5fem9vbSA6IGZyb21ab29tO1xyXG5cdFx0dmFyIHpvb20gPSBjcnMuem9vbShzY2FsZSAqIGNycy5zY2FsZShmcm9tWm9vbSkpO1xyXG5cdFx0cmV0dXJuIGlzTmFOKHpvb20pID8gSW5maW5pdHkgOiB6b29tO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgcHJvamVjdChsYXRsbmc6IExhdExuZywgem9vbTogTnVtYmVyKTogUG9pbnRcclxuXHQvLyBQcm9qZWN0cyBhIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlIGBMYXRMbmdgIGFjY29yZGluZyB0byB0aGUgcHJvamVjdGlvblxyXG5cdC8vIG9mIHRoZSBtYXAncyBDUlMsIHRoZW4gc2NhbGVzIGl0IGFjY29yZGluZyB0byBgem9vbWAgYW5kIHRoZSBDUlMnc1xyXG5cdC8vIGBUcmFuc2Zvcm1hdGlvbmAuIFRoZSByZXN1bHQgaXMgcGl4ZWwgY29vcmRpbmF0ZSByZWxhdGl2ZSB0b1xyXG5cdC8vIHRoZSBDUlMgb3JpZ2luLlxyXG5cdHByb2plY3Q6IGZ1bmN0aW9uIChsYXRsbmcsIHpvb20pIHtcclxuXHRcdHpvb20gPSB6b29tID09PSB1bmRlZmluZWQgPyB0aGlzLl96b29tIDogem9vbTtcclxuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMuY3JzLmxhdExuZ1RvUG9pbnQoTC5sYXRMbmcobGF0bG5nKSwgem9vbSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB1bnByb2plY3QocG9pbnQ6IFBvaW50LCB6b29tOiBOdW1iZXIpOiBMYXRMbmdcclxuXHQvLyBJbnZlcnNlIG9mIFtgcHJvamVjdGBdKCNtYXAtcHJvamVjdCkuXHJcblx0dW5wcm9qZWN0OiBmdW5jdGlvbiAocG9pbnQsIHpvb20pIHtcclxuXHRcdHpvb20gPSB6b29tID09PSB1bmRlZmluZWQgPyB0aGlzLl96b29tIDogem9vbTtcclxuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMuY3JzLnBvaW50VG9MYXRMbmcoTC5wb2ludChwb2ludCksIHpvb20pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgbGF5ZXJQb2ludFRvTGF0TG5nKHBvaW50OiBQb2ludCk6IExhdExuZ1xyXG5cdC8vIEdpdmVuIGEgcGl4ZWwgY29vcmRpbmF0ZSByZWxhdGl2ZSB0byB0aGUgW29yaWdpbiBwaXhlbF0oI21hcC1nZXRwaXhlbG9yaWdpbiksXHJcblx0Ly8gcmV0dXJucyB0aGUgY29ycmVzcG9uZGluZyBnZW9ncmFwaGljYWwgY29vcmRpbmF0ZSAoZm9yIHRoZSBjdXJyZW50IHpvb20gbGV2ZWwpLlxyXG5cdGxheWVyUG9pbnRUb0xhdExuZzogZnVuY3Rpb24gKHBvaW50KSB7XHJcblx0XHR2YXIgcHJvamVjdGVkUG9pbnQgPSBMLnBvaW50KHBvaW50KS5hZGQodGhpcy5nZXRQaXhlbE9yaWdpbigpKTtcclxuXHRcdHJldHVybiB0aGlzLnVucHJvamVjdChwcm9qZWN0ZWRQb2ludCk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBsYXRMbmdUb0xheWVyUG9pbnQobGF0bG5nOiBMYXRMbmcpOiBQb2ludFxyXG5cdC8vIEdpdmVuIGEgZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGUsIHJldHVybnMgdGhlIGNvcnJlc3BvbmRpbmcgcGl4ZWwgY29vcmRpbmF0ZVxyXG5cdC8vIHJlbGF0aXZlIHRvIHRoZSBbb3JpZ2luIHBpeGVsXSgjbWFwLWdldHBpeGVsb3JpZ2luKS5cclxuXHRsYXRMbmdUb0xheWVyUG9pbnQ6IGZ1bmN0aW9uIChsYXRsbmcpIHtcclxuXHRcdHZhciBwcm9qZWN0ZWRQb2ludCA9IHRoaXMucHJvamVjdChMLmxhdExuZyhsYXRsbmcpKS5fcm91bmQoKTtcclxuXHRcdHJldHVybiBwcm9qZWN0ZWRQb2ludC5fc3VidHJhY3QodGhpcy5nZXRQaXhlbE9yaWdpbigpKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHdyYXBMYXRMbmcobGF0bG5nOiBMYXRMbmcpOiBMYXRMbmdcclxuXHQvLyBSZXR1cm5zIGEgYExhdExuZ2Agd2hlcmUgYGxhdGAgYW5kIGBsbmdgIGhhcyBiZWVuIHdyYXBwZWQgYWNjb3JkaW5nIHRvIHRoZVxyXG5cdC8vIG1hcCdzIENSUydzIGB3cmFwTGF0YCBhbmQgYHdyYXBMbmdgIHByb3BlcnRpZXMsIGlmIHRoZXkgYXJlIG91dHNpZGUgdGhlXHJcblx0Ly8gQ1JTJ3MgYm91bmRzLlxyXG5cdC8vIEJ5IGRlZmF1bHQgdGhpcyBtZWFucyBsb25naXR1ZGUgaXMgd3JhcHBlZCBhcm91bmQgdGhlIGRhdGVsaW5lIHNvIGl0c1xyXG5cdC8vIHZhbHVlIGlzIGJldHdlZW4gLTE4MCBhbmQgKzE4MCBkZWdyZWVzLlxyXG5cdHdyYXBMYXRMbmc6IGZ1bmN0aW9uIChsYXRsbmcpIHtcclxuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMuY3JzLndyYXBMYXRMbmcoTC5sYXRMbmcobGF0bG5nKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBkaXN0YW5jZShsYXRsbmcxOiBMYXRMbmcsIGxhdGxuZzI6IExhdExuZyk6IE51bWJlclxyXG5cdC8vIFJldHVybnMgdGhlIGRpc3RhbmNlIGJldHdlZW4gdHdvIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlcyBhY2NvcmRpbmcgdG9cclxuXHQvLyB0aGUgbWFwJ3MgQ1JTLiBCeSBkZWZhdWx0IHRoaXMgbWVhc3VyZXMgZGlzdGFuY2UgaW4gbWV0ZXJzLlxyXG5cdGRpc3RhbmNlOiBmdW5jdGlvbiAobGF0bG5nMSwgbGF0bG5nMikge1xyXG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5jcnMuZGlzdGFuY2UoTC5sYXRMbmcobGF0bG5nMSksIEwubGF0TG5nKGxhdGxuZzIpKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGNvbnRhaW5lclBvaW50VG9MYXllclBvaW50KHBvaW50OiBQb2ludCk6IFBvaW50XHJcblx0Ly8gR2l2ZW4gYSBwaXhlbCBjb29yZGluYXRlIHJlbGF0aXZlIHRvIHRoZSBtYXAgY29udGFpbmVyLCByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nXHJcblx0Ly8gcGl4ZWwgY29vcmRpbmF0ZSByZWxhdGl2ZSB0byB0aGUgW29yaWdpbiBwaXhlbF0oI21hcC1nZXRwaXhlbG9yaWdpbikuXHJcblx0Y29udGFpbmVyUG9pbnRUb0xheWVyUG9pbnQ6IGZ1bmN0aW9uIChwb2ludCkgeyAvLyAoUG9pbnQpXHJcblx0XHRyZXR1cm4gTC5wb2ludChwb2ludCkuc3VidHJhY3QodGhpcy5fZ2V0TWFwUGFuZVBvcygpKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGxheWVyUG9pbnRUb0NvbnRhaW5lclBvaW50KHBvaW50OiBQb2ludCk6IFBvaW50XHJcblx0Ly8gR2l2ZW4gYSBwaXhlbCBjb29yZGluYXRlIHJlbGF0aXZlIHRvIHRoZSBbb3JpZ2luIHBpeGVsXSgjbWFwLWdldHBpeGVsb3JpZ2luKSxcclxuXHQvLyByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIHBpeGVsIGNvb3JkaW5hdGUgcmVsYXRpdmUgdG8gdGhlIG1hcCBjb250YWluZXIuXHJcblx0bGF5ZXJQb2ludFRvQ29udGFpbmVyUG9pbnQ6IGZ1bmN0aW9uIChwb2ludCkgeyAvLyAoUG9pbnQpXHJcblx0XHRyZXR1cm4gTC5wb2ludChwb2ludCkuYWRkKHRoaXMuX2dldE1hcFBhbmVQb3MoKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjb250YWluZXJQb2ludFRvTGF0TG5nKHBvaW50OiBQb2ludCk6IFBvaW50XHJcblx0Ly8gR2l2ZW4gYSBwaXhlbCBjb29yZGluYXRlIHJlbGF0aXZlIHRvIHRoZSBtYXAgY29udGFpbmVyLCByZXR1cm5zXHJcblx0Ly8gdGhlIGNvcnJlc3BvbmRpbmcgZ2VvZ3JhcGhpY2FsIGNvb3JkaW5hdGUgKGZvciB0aGUgY3VycmVudCB6b29tIGxldmVsKS5cclxuXHRjb250YWluZXJQb2ludFRvTGF0TG5nOiBmdW5jdGlvbiAocG9pbnQpIHtcclxuXHRcdHZhciBsYXllclBvaW50ID0gdGhpcy5jb250YWluZXJQb2ludFRvTGF5ZXJQb2ludChMLnBvaW50KHBvaW50KSk7XHJcblx0XHRyZXR1cm4gdGhpcy5sYXllclBvaW50VG9MYXRMbmcobGF5ZXJQb2ludCk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBsYXRMbmdUb0NvbnRhaW5lclBvaW50KGxhdGxuZzogTGF0TG5nKTogUG9pbnRcclxuXHQvLyBHaXZlbiBhIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlLCByZXR1cm5zIHRoZSBjb3JyZXNwb25kaW5nIHBpeGVsIGNvb3JkaW5hdGVcclxuXHQvLyByZWxhdGl2ZSB0byB0aGUgbWFwIGNvbnRhaW5lci5cclxuXHRsYXRMbmdUb0NvbnRhaW5lclBvaW50OiBmdW5jdGlvbiAobGF0bG5nKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5sYXllclBvaW50VG9Db250YWluZXJQb2ludCh0aGlzLmxhdExuZ1RvTGF5ZXJQb2ludChMLmxhdExuZyhsYXRsbmcpKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBtb3VzZUV2ZW50VG9Db250YWluZXJQb2ludChldjogTW91c2VFdmVudCk6IFBvaW50XHJcblx0Ly8gR2l2ZW4gYSBNb3VzZUV2ZW50IG9iamVjdCwgcmV0dXJucyB0aGUgcGl4ZWwgY29vcmRpbmF0ZSByZWxhdGl2ZSB0byB0aGVcclxuXHQvLyBtYXAgY29udGFpbmVyIHdoZXJlIHRoZSBldmVudCB0b29rIHBsYWNlLlxyXG5cdG1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50OiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0cmV0dXJuIEwuRG9tRXZlbnQuZ2V0TW91c2VQb3NpdGlvbihlLCB0aGlzLl9jb250YWluZXIpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgbW91c2VFdmVudFRvTGF5ZXJQb2ludChldjogTW91c2VFdmVudCk6IFBvaW50XHJcblx0Ly8gR2l2ZW4gYSBNb3VzZUV2ZW50IG9iamVjdCwgcmV0dXJucyB0aGUgcGl4ZWwgY29vcmRpbmF0ZSByZWxhdGl2ZSB0b1xyXG5cdC8vIHRoZSBbb3JpZ2luIHBpeGVsXSgjbWFwLWdldHBpeGVsb3JpZ2luKSB3aGVyZSB0aGUgZXZlbnQgdG9vayBwbGFjZS5cclxuXHRtb3VzZUV2ZW50VG9MYXllclBvaW50OiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0cmV0dXJuIHRoaXMuY29udGFpbmVyUG9pbnRUb0xheWVyUG9pbnQodGhpcy5tb3VzZUV2ZW50VG9Db250YWluZXJQb2ludChlKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBtb3VzZUV2ZW50VG9MYXRMbmcoZXY6IE1vdXNlRXZlbnQpOiBMYXRMbmdcclxuXHQvLyBHaXZlbiBhIE1vdXNlRXZlbnQgb2JqZWN0LCByZXR1cm5zIGdlb2dyYXBoaWNhbCBjb29yZGluYXRlIHdoZXJlIHRoZVxyXG5cdC8vIGV2ZW50IHRvb2sgcGxhY2UuXHJcblx0bW91c2VFdmVudFRvTGF0TG5nOiBmdW5jdGlvbiAoZSkgeyAvLyAoTW91c2VFdmVudClcclxuXHRcdHJldHVybiB0aGlzLmxheWVyUG9pbnRUb0xhdExuZyh0aGlzLm1vdXNlRXZlbnRUb0xheWVyUG9pbnQoZSkpO1xyXG5cdH0sXHJcblxyXG5cclxuXHQvLyBtYXAgaW5pdGlhbGl6YXRpb24gbWV0aG9kc1xyXG5cclxuXHRfaW5pdENvbnRhaW5lcjogZnVuY3Rpb24gKGlkKSB7XHJcblx0XHR2YXIgY29udGFpbmVyID0gdGhpcy5fY29udGFpbmVyID0gTC5Eb21VdGlsLmdldChpZCk7XHJcblxyXG5cdFx0aWYgKCFjb250YWluZXIpIHtcclxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCdNYXAgY29udGFpbmVyIG5vdCBmb3VuZC4nKTtcclxuXHRcdH0gZWxzZSBpZiAoY29udGFpbmVyLl9sZWFmbGV0X2lkKSB7XHJcblx0XHRcdHRocm93IG5ldyBFcnJvcignTWFwIGNvbnRhaW5lciBpcyBhbHJlYWR5IGluaXRpYWxpemVkLicpO1xyXG5cdFx0fVxyXG5cclxuXHRcdEwuRG9tRXZlbnQuYWRkTGlzdGVuZXIoY29udGFpbmVyLCAnc2Nyb2xsJywgdGhpcy5fb25TY3JvbGwsIHRoaXMpO1xyXG5cdFx0dGhpcy5fY29udGFpbmVySWQgPSBMLlV0aWwuc3RhbXAoY29udGFpbmVyKTtcclxuXHR9LFxyXG5cclxuXHRfaW5pdExheW91dDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGNvbnRhaW5lciA9IHRoaXMuX2NvbnRhaW5lcjtcclxuXHJcblx0XHR0aGlzLl9mYWRlQW5pbWF0ZWQgPSB0aGlzLm9wdGlvbnMuZmFkZUFuaW1hdGlvbiAmJiBMLkJyb3dzZXIuYW55M2Q7XHJcblxyXG5cdFx0TC5Eb21VdGlsLmFkZENsYXNzKGNvbnRhaW5lciwgJ2xlYWZsZXQtY29udGFpbmVyJyArXHJcblx0XHRcdChMLkJyb3dzZXIudG91Y2ggPyAnIGxlYWZsZXQtdG91Y2gnIDogJycpICtcclxuXHRcdFx0KEwuQnJvd3Nlci5yZXRpbmEgPyAnIGxlYWZsZXQtcmV0aW5hJyA6ICcnKSArXHJcblx0XHRcdChMLkJyb3dzZXIuaWVsdDkgPyAnIGxlYWZsZXQtb2xkaWUnIDogJycpICtcclxuXHRcdFx0KEwuQnJvd3Nlci5zYWZhcmkgPyAnIGxlYWZsZXQtc2FmYXJpJyA6ICcnKSArXHJcblx0XHRcdCh0aGlzLl9mYWRlQW5pbWF0ZWQgPyAnIGxlYWZsZXQtZmFkZS1hbmltJyA6ICcnKSk7XHJcblxyXG5cdFx0dmFyIHBvc2l0aW9uID0gTC5Eb21VdGlsLmdldFN0eWxlKGNvbnRhaW5lciwgJ3Bvc2l0aW9uJyk7XHJcblxyXG5cdFx0aWYgKHBvc2l0aW9uICE9PSAnYWJzb2x1dGUnICYmIHBvc2l0aW9uICE9PSAncmVsYXRpdmUnICYmIHBvc2l0aW9uICE9PSAnZml4ZWQnKSB7XHJcblx0XHRcdGNvbnRhaW5lci5zdHlsZS5wb3NpdGlvbiA9ICdyZWxhdGl2ZSc7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5faW5pdFBhbmVzKCk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2luaXRDb250cm9sUG9zKSB7XHJcblx0XHRcdHRoaXMuX2luaXRDb250cm9sUG9zKCk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X2luaXRQYW5lczogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIHBhbmVzID0gdGhpcy5fcGFuZXMgPSB7fTtcclxuXHRcdHRoaXMuX3BhbmVSZW5kZXJlcnMgPSB7fTtcclxuXHJcblx0XHQvLyBAc2VjdGlvblxyXG5cdFx0Ly9cclxuXHRcdC8vIFBhbmVzIGFyZSBET00gZWxlbWVudHMgdXNlZCB0byBjb250cm9sIHRoZSBvcmRlcmluZyBvZiBsYXllcnMgb24gdGhlIG1hcC4gWW91XHJcblx0XHQvLyBjYW4gYWNjZXNzIHBhbmVzIHdpdGggW2BtYXAuZ2V0UGFuZWBdKCNtYXAtZ2V0cGFuZSkgb3JcclxuXHRcdC8vIFtgbWFwLmdldFBhbmVzYF0oI21hcC1nZXRwYW5lcykgbWV0aG9kcy4gTmV3IHBhbmVzIGNhbiBiZSBjcmVhdGVkIHdpdGggdGhlXHJcblx0XHQvLyBbYG1hcC5jcmVhdGVQYW5lYF0oI21hcC1jcmVhdGVwYW5lKSBtZXRob2QuXHJcblx0XHQvL1xyXG5cdFx0Ly8gRXZlcnkgbWFwIGhhcyB0aGUgZm9sbG93aW5nIGRlZmF1bHQgcGFuZXMgdGhhdCBkaWZmZXIgb25seSBpbiB6SW5kZXguXHJcblx0XHQvL1xyXG5cdFx0Ly8gQHBhbmUgbWFwUGFuZTogSFRNTEVsZW1lbnQgPSAnYXV0bydcclxuXHRcdC8vIFBhbmUgdGhhdCBjb250YWlucyBhbGwgb3RoZXIgbWFwIHBhbmVzXHJcblxyXG5cdFx0dGhpcy5fbWFwUGFuZSA9IHRoaXMuY3JlYXRlUGFuZSgnbWFwUGFuZScsIHRoaXMuX2NvbnRhaW5lcik7XHJcblx0XHRMLkRvbVV0aWwuc2V0UG9zaXRpb24odGhpcy5fbWFwUGFuZSwgbmV3IEwuUG9pbnQoMCwgMCkpO1xyXG5cclxuXHRcdC8vIEBwYW5lIHRpbGVQYW5lOiBIVE1MRWxlbWVudCA9IDIwMFxyXG5cdFx0Ly8gUGFuZSBmb3IgYEdyaWRMYXllcmBzIGFuZCBgVGlsZUxheWVyYHNcclxuXHRcdHRoaXMuY3JlYXRlUGFuZSgndGlsZVBhbmUnKTtcclxuXHRcdC8vIEBwYW5lIG92ZXJsYXlQYW5lOiBIVE1MRWxlbWVudCA9IDQwMFxyXG5cdFx0Ly8gUGFuZSBmb3IgdmVjdG9yIG92ZXJsYXlzIChgUGF0aGBzKSwgbGlrZSBgUG9seWxpbmVgcyBhbmQgYFBvbHlnb25gc1xyXG5cdFx0dGhpcy5jcmVhdGVQYW5lKCdzaGFkb3dQYW5lJyk7XHJcblx0XHQvLyBAcGFuZSBzaGFkb3dQYW5lOiBIVE1MRWxlbWVudCA9IDUwMFxyXG5cdFx0Ly8gUGFuZSBmb3Igb3ZlcmxheSBzaGFkb3dzIChlLmcuIGBNYXJrZXJgIHNoYWRvd3MpXHJcblx0XHR0aGlzLmNyZWF0ZVBhbmUoJ292ZXJsYXlQYW5lJyk7XHJcblx0XHQvLyBAcGFuZSBtYXJrZXJQYW5lOiBIVE1MRWxlbWVudCA9IDYwMFxyXG5cdFx0Ly8gUGFuZSBmb3IgYEljb25gcyBvZiBgTWFya2VyYHNcclxuXHRcdHRoaXMuY3JlYXRlUGFuZSgnbWFya2VyUGFuZScpO1xyXG5cdFx0Ly8gQHBhbmUgdG9vbHRpcFBhbmU6IEhUTUxFbGVtZW50ID0gNjUwXHJcblx0XHQvLyBQYW5lIGZvciB0b29sdGlwLlxyXG5cdFx0dGhpcy5jcmVhdGVQYW5lKCd0b29sdGlwUGFuZScpO1xyXG5cdFx0Ly8gQHBhbmUgcG9wdXBQYW5lOiBIVE1MRWxlbWVudCA9IDcwMFxyXG5cdFx0Ly8gUGFuZSBmb3IgYFBvcHVwYHMuXHJcblx0XHR0aGlzLmNyZWF0ZVBhbmUoJ3BvcHVwUGFuZScpO1xyXG5cclxuXHRcdGlmICghdGhpcy5vcHRpb25zLm1hcmtlclpvb21BbmltYXRpb24pIHtcclxuXHRcdFx0TC5Eb21VdGlsLmFkZENsYXNzKHBhbmVzLm1hcmtlclBhbmUsICdsZWFmbGV0LXpvb20taGlkZScpO1xyXG5cdFx0XHRMLkRvbVV0aWwuYWRkQ2xhc3MocGFuZXMuc2hhZG93UGFuZSwgJ2xlYWZsZXQtem9vbS1oaWRlJyk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblxyXG5cdC8vIHByaXZhdGUgbWV0aG9kcyB0aGF0IG1vZGlmeSBtYXAgc3RhdGVcclxuXHJcblx0Ly8gQHNlY3Rpb24gTWFwIHN0YXRlIGNoYW5nZSBldmVudHNcclxuXHRfcmVzZXRWaWV3OiBmdW5jdGlvbiAoY2VudGVyLCB6b29tKSB7XHJcblx0XHRMLkRvbVV0aWwuc2V0UG9zaXRpb24odGhpcy5fbWFwUGFuZSwgbmV3IEwuUG9pbnQoMCwgMCkpO1xyXG5cclxuXHRcdHZhciBsb2FkaW5nID0gIXRoaXMuX2xvYWRlZDtcclxuXHRcdHRoaXMuX2xvYWRlZCA9IHRydWU7XHJcblx0XHR6b29tID0gdGhpcy5fbGltaXRab29tKHpvb20pO1xyXG5cclxuXHRcdHRoaXMuZmlyZSgndmlld3ByZXJlc2V0Jyk7XHJcblxyXG5cdFx0dmFyIHpvb21DaGFuZ2VkID0gdGhpcy5fem9vbSAhPT0gem9vbTtcclxuXHRcdHRoaXNcclxuXHRcdFx0Ll9tb3ZlU3RhcnQoem9vbUNoYW5nZWQpXHJcblx0XHRcdC5fbW92ZShjZW50ZXIsIHpvb20pXHJcblx0XHRcdC5fbW92ZUVuZCh6b29tQ2hhbmdlZCk7XHJcblxyXG5cdFx0Ly8gQGV2ZW50IHZpZXdyZXNldDogRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIG1hcCBuZWVkcyB0byByZWRyYXcgaXRzIGNvbnRlbnQgKHRoaXMgdXN1YWxseSBoYXBwZW5zXHJcblx0XHQvLyBvbiBtYXAgem9vbSBvciBsb2FkKS4gVmVyeSB1c2VmdWwgZm9yIGNyZWF0aW5nIGN1c3RvbSBvdmVybGF5cy5cclxuXHRcdHRoaXMuZmlyZSgndmlld3Jlc2V0Jyk7XHJcblxyXG5cdFx0Ly8gQGV2ZW50IGxvYWQ6IEV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSBtYXAgaXMgaW5pdGlhbGl6ZWQgKHdoZW4gaXRzIGNlbnRlciBhbmQgem9vbSBhcmUgc2V0XHJcblx0XHQvLyBmb3IgdGhlIGZpcnN0IHRpbWUpLlxyXG5cdFx0aWYgKGxvYWRpbmcpIHtcclxuXHRcdFx0dGhpcy5maXJlKCdsb2FkJyk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X21vdmVTdGFydDogZnVuY3Rpb24gKHpvb21DaGFuZ2VkKSB7XHJcblx0XHQvLyBAZXZlbnQgem9vbXN0YXJ0OiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFwIHpvb20gaXMgYWJvdXQgdG8gY2hhbmdlIChlLmcuIGJlZm9yZSB6b29tIGFuaW1hdGlvbikuXHJcblx0XHQvLyBAZXZlbnQgbW92ZXN0YXJ0OiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgdmlldyBvZiB0aGUgbWFwIHN0YXJ0cyBjaGFuZ2luZyAoZS5nLiB1c2VyIHN0YXJ0cyBkcmFnZ2luZyB0aGUgbWFwKS5cclxuXHRcdGlmICh6b29tQ2hhbmdlZCkge1xyXG5cdFx0XHR0aGlzLmZpcmUoJ3pvb21zdGFydCcpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXMuZmlyZSgnbW92ZXN0YXJ0Jyk7XHJcblx0fSxcclxuXHJcblx0X21vdmU6IGZ1bmN0aW9uIChjZW50ZXIsIHpvb20sIGRhdGEpIHtcclxuXHRcdGlmICh6b29tID09PSB1bmRlZmluZWQpIHtcclxuXHRcdFx0em9vbSA9IHRoaXMuX3pvb207XHJcblx0XHR9XHJcblx0XHR2YXIgem9vbUNoYW5nZWQgPSB0aGlzLl96b29tICE9PSB6b29tO1xyXG5cclxuXHRcdHRoaXMuX3pvb20gPSB6b29tO1xyXG5cdFx0dGhpcy5fbGFzdENlbnRlciA9IGNlbnRlcjtcclxuXHRcdHRoaXMuX3BpeGVsT3JpZ2luID0gdGhpcy5fZ2V0TmV3UGl4ZWxPcmlnaW4oY2VudGVyKTtcclxuXHJcblx0XHQvLyBAZXZlbnQgem9vbTogRXZlbnRcclxuXHRcdC8vIEZpcmVkIHJlcGVhdGVkbHkgZHVyaW5nIGFueSBjaGFuZ2UgaW4gem9vbSBsZXZlbCwgaW5jbHVkaW5nIHpvb21cclxuXHRcdC8vIGFuZCBmbHkgYW5pbWF0aW9ucy5cclxuXHRcdGlmICh6b29tQ2hhbmdlZCB8fCAoZGF0YSAmJiBkYXRhLnBpbmNoKSkge1x0Ly8gQWx3YXlzIGZpcmUgJ3pvb20nIGlmIHBpbmNoaW5nIGJlY2F1c2UgIzM1MzBcclxuXHRcdFx0dGhpcy5maXJlKCd6b29tJywgZGF0YSk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gQGV2ZW50IG1vdmU6IEV2ZW50XHJcblx0XHQvLyBGaXJlZCByZXBlYXRlZGx5IGR1cmluZyBhbnkgbW92ZW1lbnQgb2YgdGhlIG1hcCwgaW5jbHVkaW5nIHBhbiBhbmRcclxuXHRcdC8vIGZseSBhbmltYXRpb25zLlxyXG5cdFx0cmV0dXJuIHRoaXMuZmlyZSgnbW92ZScsIGRhdGEpO1xyXG5cdH0sXHJcblxyXG5cdF9tb3ZlRW5kOiBmdW5jdGlvbiAoem9vbUNoYW5nZWQpIHtcclxuXHRcdC8vIEBldmVudCB6b29tZW5kOiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFwIGhhcyBjaGFuZ2VkLCBhZnRlciBhbnkgYW5pbWF0aW9ucy5cclxuXHRcdGlmICh6b29tQ2hhbmdlZCkge1xyXG5cdFx0XHR0aGlzLmZpcmUoJ3pvb21lbmQnKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBAZXZlbnQgbW92ZWVuZDogRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIGNlbnRlciBvZiB0aGUgbWFwIHN0b3BzIGNoYW5naW5nIChlLmcuIHVzZXIgc3RvcHBlZFxyXG5cdFx0Ly8gZHJhZ2dpbmcgdGhlIG1hcCkuXHJcblx0XHRyZXR1cm4gdGhpcy5maXJlKCdtb3ZlZW5kJyk7XHJcblx0fSxcclxuXHJcblx0X3N0b3A6IGZ1bmN0aW9uICgpIHtcclxuXHRcdEwuVXRpbC5jYW5jZWxBbmltRnJhbWUodGhpcy5fZmx5VG9GcmFtZSk7XHJcblx0XHRpZiAodGhpcy5fcGFuQW5pbSkge1xyXG5cdFx0XHR0aGlzLl9wYW5BbmltLnN0b3AoKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdF9yYXdQYW5CeTogZnVuY3Rpb24gKG9mZnNldCkge1xyXG5cdFx0TC5Eb21VdGlsLnNldFBvc2l0aW9uKHRoaXMuX21hcFBhbmUsIHRoaXMuX2dldE1hcFBhbmVQb3MoKS5zdWJ0cmFjdChvZmZzZXQpKTtcclxuXHR9LFxyXG5cclxuXHRfZ2V0Wm9vbVNwYW46IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLmdldE1heFpvb20oKSAtIHRoaXMuZ2V0TWluWm9vbSgpO1xyXG5cdH0sXHJcblxyXG5cdF9wYW5JbnNpZGVNYXhCb3VuZHM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICghdGhpcy5fZW5mb3JjaW5nQm91bmRzKSB7XHJcblx0XHRcdHRoaXMucGFuSW5zaWRlQm91bmRzKHRoaXMub3B0aW9ucy5tYXhCb3VuZHMpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdF9jaGVja0lmTG9hZGVkOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX2xvYWRlZCkge1xyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ1NldCBtYXAgY2VudGVyIGFuZCB6b29tIGZpcnN0LicpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIERPTSBldmVudCBoYW5kbGluZ1xyXG5cclxuXHQvLyBAc2VjdGlvbiBJbnRlcmFjdGlvbiBldmVudHNcclxuXHRfaW5pdEV2ZW50czogZnVuY3Rpb24gKHJlbW92ZSkge1xyXG5cdFx0aWYgKCFMLkRvbUV2ZW50KSB7IHJldHVybjsgfVxyXG5cclxuXHRcdHRoaXMuX3RhcmdldHMgPSB7fTtcclxuXHRcdHRoaXMuX3RhcmdldHNbTC5zdGFtcCh0aGlzLl9jb250YWluZXIpXSA9IHRoaXM7XHJcblxyXG5cdFx0dmFyIG9uT2ZmID0gcmVtb3ZlID8gJ29mZicgOiAnb24nO1xyXG5cclxuXHRcdC8vIEBldmVudCBjbGljazogTW91c2VFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgdXNlciBjbGlja3MgKG9yIHRhcHMpIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgZGJsY2xpY2s6IE1vdXNlRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIHVzZXIgZG91YmxlLWNsaWNrcyAob3IgZG91YmxlLXRhcHMpIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgbW91c2Vkb3duOiBNb3VzZUV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSB1c2VyIHB1c2hlcyB0aGUgbW91c2UgYnV0dG9uIG9uIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgbW91c2V1cDogTW91c2VFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgdXNlciByZWxlYXNlcyB0aGUgbW91c2UgYnV0dG9uIG9uIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgbW91c2VvdmVyOiBNb3VzZUV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSBtb3VzZSBlbnRlcnMgdGhlIG1hcC5cclxuXHRcdC8vIEBldmVudCBtb3VzZW91dDogTW91c2VFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbW91c2UgbGVhdmVzIHRoZSBtYXAuXHJcblx0XHQvLyBAZXZlbnQgbW91c2Vtb3ZlOiBNb3VzZUV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGlsZSB0aGUgbW91c2UgbW92ZXMgb3ZlciB0aGUgbWFwLlxyXG5cdFx0Ly8gQGV2ZW50IGNvbnRleHRtZW51OiBNb3VzZUV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSB1c2VyIHB1c2hlcyB0aGUgcmlnaHQgbW91c2UgYnV0dG9uIG9uIHRoZSBtYXAsIHByZXZlbnRzXHJcblx0XHQvLyBkZWZhdWx0IGJyb3dzZXIgY29udGV4dCBtZW51IGZyb20gc2hvd2luZyBpZiB0aGVyZSBhcmUgbGlzdGVuZXJzIG9uXHJcblx0XHQvLyB0aGlzIGV2ZW50LiBBbHNvIGZpcmVkIG9uIG1vYmlsZSB3aGVuIHRoZSB1c2VyIGhvbGRzIGEgc2luZ2xlIHRvdWNoXHJcblx0XHQvLyBmb3IgYSBzZWNvbmQgKGFsc28gY2FsbGVkIGxvbmcgcHJlc3MpLlxyXG5cdFx0Ly8gQGV2ZW50IGtleXByZXNzOiBLZXlib2FyZEV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSB1c2VyIHByZXNzZXMgYSBrZXkgZnJvbSB0aGUga2V5Ym9hcmQgd2hpbGUgdGhlIG1hcCBpcyBmb2N1c2VkLlxyXG5cdFx0TC5Eb21FdmVudFtvbk9mZl0odGhpcy5fY29udGFpbmVyLCAnY2xpY2sgZGJsY2xpY2sgbW91c2Vkb3duIG1vdXNldXAgJyArXHJcblx0XHRcdCdtb3VzZW92ZXIgbW91c2VvdXQgbW91c2Vtb3ZlIGNvbnRleHRtZW51IGtleXByZXNzJywgdGhpcy5faGFuZGxlRE9NRXZlbnQsIHRoaXMpO1xyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMudHJhY2tSZXNpemUpIHtcclxuXHRcdFx0TC5Eb21FdmVudFtvbk9mZl0od2luZG93LCAncmVzaXplJywgdGhpcy5fb25SZXNpemUsIHRoaXMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChMLkJyb3dzZXIuYW55M2QgJiYgdGhpcy5vcHRpb25zLnRyYW5zZm9ybTNETGltaXQpIHtcclxuXHRcdFx0dGhpc1tvbk9mZl0oJ21vdmVlbmQnLCB0aGlzLl9vbk1vdmVFbmQpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdF9vblJlc2l6ZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0TC5VdGlsLmNhbmNlbEFuaW1GcmFtZSh0aGlzLl9yZXNpemVSZXF1ZXN0KTtcclxuXHRcdHRoaXMuX3Jlc2l6ZVJlcXVlc3QgPSBMLlV0aWwucmVxdWVzdEFuaW1GcmFtZShcclxuXHRcdCAgICAgICAgZnVuY3Rpb24gKCkgeyB0aGlzLmludmFsaWRhdGVTaXplKHtkZWJvdW5jZU1vdmVlbmQ6IHRydWV9KTsgfSwgdGhpcyk7XHJcblx0fSxcclxuXHJcblx0X29uU2Nyb2xsOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR0aGlzLl9jb250YWluZXIuc2Nyb2xsVG9wICA9IDA7XHJcblx0XHR0aGlzLl9jb250YWluZXIuc2Nyb2xsTGVmdCA9IDA7XHJcblx0fSxcclxuXHJcblx0X29uTW92ZUVuZDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIHBvcyA9IHRoaXMuX2dldE1hcFBhbmVQb3MoKTtcclxuXHRcdGlmIChNYXRoLm1heChNYXRoLmFicyhwb3MueCksIE1hdGguYWJzKHBvcy55KSkgPj0gdGhpcy5vcHRpb25zLnRyYW5zZm9ybTNETGltaXQpIHtcclxuXHRcdFx0Ly8gaHR0cHM6Ly9idWd6aWxsYS5tb3ppbGxhLm9yZy9zaG93X2J1Zy5jZ2k/aWQ9MTIwMzg3MyBidXQgV2Via2l0IGFsc28gaGF2ZVxyXG5cdFx0XHQvLyBhIHBpeGVsIG9mZnNldCBvbiB2ZXJ5IGhpZ2ggdmFsdWVzLCBzZWU6IGh0dHA6Ly9qc2ZpZGRsZS5uZXQvZGc2cjVoaGIvXHJcblx0XHRcdHRoaXMuX3Jlc2V0Vmlldyh0aGlzLmdldENlbnRlcigpLCB0aGlzLmdldFpvb20oKSk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X2ZpbmRFdmVudFRhcmdldHM6IGZ1bmN0aW9uIChlLCB0eXBlKSB7XHJcblx0XHR2YXIgdGFyZ2V0cyA9IFtdLFxyXG5cdFx0ICAgIHRhcmdldCxcclxuXHRcdCAgICBpc0hvdmVyID0gdHlwZSA9PT0gJ21vdXNlb3V0JyB8fCB0eXBlID09PSAnbW91c2VvdmVyJyxcclxuXHRcdCAgICBzcmMgPSBlLnRhcmdldCB8fCBlLnNyY0VsZW1lbnQsXHJcblx0XHQgICAgZHJhZ2dpbmcgPSBmYWxzZTtcclxuXHJcblx0XHR3aGlsZSAoc3JjKSB7XHJcblx0XHRcdHRhcmdldCA9IHRoaXMuX3RhcmdldHNbTC5zdGFtcChzcmMpXTtcclxuXHRcdFx0aWYgKHRhcmdldCAmJiAodHlwZSA9PT0gJ2NsaWNrJyB8fCB0eXBlID09PSAncHJlY2xpY2snKSAmJiAhZS5fc2ltdWxhdGVkICYmIHRoaXMuX2RyYWdnYWJsZU1vdmVkKHRhcmdldCkpIHtcclxuXHRcdFx0XHQvLyBQcmV2ZW50IGZpcmluZyBjbGljayBhZnRlciB5b3UganVzdCBkcmFnZ2VkIGFuIG9iamVjdC5cclxuXHRcdFx0XHRkcmFnZ2luZyA9IHRydWU7XHJcblx0XHRcdFx0YnJlYWs7XHJcblx0XHRcdH1cclxuXHRcdFx0aWYgKHRhcmdldCAmJiB0YXJnZXQubGlzdGVucyh0eXBlLCB0cnVlKSkge1xyXG5cdFx0XHRcdGlmIChpc0hvdmVyICYmICFMLkRvbUV2ZW50Ll9pc0V4dGVybmFsVGFyZ2V0KHNyYywgZSkpIHsgYnJlYWs7IH1cclxuXHRcdFx0XHR0YXJnZXRzLnB1c2godGFyZ2V0KTtcclxuXHRcdFx0XHRpZiAoaXNIb3ZlcikgeyBicmVhazsgfVxyXG5cdFx0XHR9XHJcblx0XHRcdGlmIChzcmMgPT09IHRoaXMuX2NvbnRhaW5lcikgeyBicmVhazsgfVxyXG5cdFx0XHRzcmMgPSBzcmMucGFyZW50Tm9kZTtcclxuXHRcdH1cclxuXHRcdGlmICghdGFyZ2V0cy5sZW5ndGggJiYgIWRyYWdnaW5nICYmICFpc0hvdmVyICYmIEwuRG9tRXZlbnQuX2lzRXh0ZXJuYWxUYXJnZXQoc3JjLCBlKSkge1xyXG5cdFx0XHR0YXJnZXRzID0gW3RoaXNdO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRhcmdldHM7XHJcblx0fSxcclxuXHJcblx0X2hhbmRsZURPTUV2ZW50OiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0aWYgKCF0aGlzLl9sb2FkZWQgfHwgTC5Eb21FdmVudC5fc2tpcHBlZChlKSkgeyByZXR1cm47IH1cclxuXHJcblx0XHR2YXIgdHlwZSA9IGUudHlwZSA9PT0gJ2tleXByZXNzJyAmJiBlLmtleUNvZGUgPT09IDEzID8gJ2NsaWNrJyA6IGUudHlwZTtcclxuXHJcblx0XHRpZiAodHlwZSA9PT0gJ21vdXNlZG93bicpIHtcclxuXHRcdFx0Ly8gcHJldmVudHMgb3V0bGluZSB3aGVuIGNsaWNraW5nIG9uIGtleWJvYXJkLWZvY3VzYWJsZSBlbGVtZW50XHJcblx0XHRcdEwuRG9tVXRpbC5wcmV2ZW50T3V0bGluZShlLnRhcmdldCB8fCBlLnNyY0VsZW1lbnQpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2ZpcmVET01FdmVudChlLCB0eXBlKTtcclxuXHR9LFxyXG5cclxuXHRfZmlyZURPTUV2ZW50OiBmdW5jdGlvbiAoZSwgdHlwZSwgdGFyZ2V0cykge1xyXG5cclxuXHRcdGlmIChlLnR5cGUgPT09ICdjbGljaycpIHtcclxuXHRcdFx0Ly8gRmlyZSBhIHN5bnRoZXRpYyAncHJlY2xpY2snIGV2ZW50IHdoaWNoIHByb3BhZ2F0ZXMgdXAgKG1haW5seSBmb3IgY2xvc2luZyBwb3B1cHMpLlxyXG5cdFx0XHQvLyBAZXZlbnQgcHJlY2xpY2s6IE1vdXNlRXZlbnRcclxuXHRcdFx0Ly8gRmlyZWQgYmVmb3JlIG1vdXNlIGNsaWNrIG9uIHRoZSBtYXAgKHNvbWV0aW1lcyB1c2VmdWwgd2hlbiB5b3VcclxuXHRcdFx0Ly8gd2FudCBzb21ldGhpbmcgdG8gaGFwcGVuIG9uIGNsaWNrIGJlZm9yZSBhbnkgZXhpc3RpbmcgY2xpY2tcclxuXHRcdFx0Ly8gaGFuZGxlcnMgc3RhcnQgcnVubmluZykuXHJcblx0XHRcdHZhciBzeW50aCA9IEwuVXRpbC5leHRlbmQoe30sIGUpO1xyXG5cdFx0XHRzeW50aC50eXBlID0gJ3ByZWNsaWNrJztcclxuXHRcdFx0dGhpcy5fZmlyZURPTUV2ZW50KHN5bnRoLCBzeW50aC50eXBlLCB0YXJnZXRzKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoZS5fc3RvcHBlZCkgeyByZXR1cm47IH1cclxuXHJcblx0XHQvLyBGaW5kIHRoZSBsYXllciB0aGUgZXZlbnQgaXMgcHJvcGFnYXRpbmcgZnJvbSBhbmQgaXRzIHBhcmVudHMuXHJcblx0XHR0YXJnZXRzID0gKHRhcmdldHMgfHwgW10pLmNvbmNhdCh0aGlzLl9maW5kRXZlbnRUYXJnZXRzKGUsIHR5cGUpKTtcclxuXHJcblx0XHRpZiAoIXRhcmdldHMubGVuZ3RoKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdHZhciB0YXJnZXQgPSB0YXJnZXRzWzBdO1xyXG5cdFx0aWYgKHR5cGUgPT09ICdjb250ZXh0bWVudScgJiYgdGFyZ2V0Lmxpc3RlbnModHlwZSwgdHJ1ZSkpIHtcclxuXHRcdFx0TC5Eb21FdmVudC5wcmV2ZW50RGVmYXVsdChlKTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgZGF0YSA9IHtcclxuXHRcdFx0b3JpZ2luYWxFdmVudDogZVxyXG5cdFx0fTtcclxuXHJcblx0XHRpZiAoZS50eXBlICE9PSAna2V5cHJlc3MnKSB7XHJcblx0XHRcdHZhciBpc01hcmtlciA9IHRhcmdldCBpbnN0YW5jZW9mIEwuTWFya2VyO1xyXG5cdFx0XHRkYXRhLmNvbnRhaW5lclBvaW50ID0gaXNNYXJrZXIgP1xyXG5cdFx0XHRcdFx0dGhpcy5sYXRMbmdUb0NvbnRhaW5lclBvaW50KHRhcmdldC5nZXRMYXRMbmcoKSkgOiB0aGlzLm1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50KGUpO1xyXG5cdFx0XHRkYXRhLmxheWVyUG9pbnQgPSB0aGlzLmNvbnRhaW5lclBvaW50VG9MYXllclBvaW50KGRhdGEuY29udGFpbmVyUG9pbnQpO1xyXG5cdFx0XHRkYXRhLmxhdGxuZyA9IGlzTWFya2VyID8gdGFyZ2V0LmdldExhdExuZygpIDogdGhpcy5sYXllclBvaW50VG9MYXRMbmcoZGF0YS5sYXllclBvaW50KTtcclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHRhcmdldHMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0dGFyZ2V0c1tpXS5maXJlKHR5cGUsIGRhdGEsIHRydWUpO1xyXG5cdFx0XHRpZiAoZGF0YS5vcmlnaW5hbEV2ZW50Ll9zdG9wcGVkIHx8XHJcblx0XHRcdFx0KHRhcmdldHNbaV0ub3B0aW9ucy5ub25CdWJibGluZ0V2ZW50cyAmJiBMLlV0aWwuaW5kZXhPZih0YXJnZXRzW2ldLm9wdGlvbnMubm9uQnViYmxpbmdFdmVudHMsIHR5cGUpICE9PSAtMSkpIHsgcmV0dXJuOyB9XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X2RyYWdnYWJsZU1vdmVkOiBmdW5jdGlvbiAob2JqKSB7XHJcblx0XHRvYmogPSBvYmouZHJhZ2dpbmcgJiYgb2JqLmRyYWdnaW5nLmVuYWJsZWQoKSA/IG9iaiA6IHRoaXM7XHJcblx0XHRyZXR1cm4gKG9iai5kcmFnZ2luZyAmJiBvYmouZHJhZ2dpbmcubW92ZWQoKSkgfHwgKHRoaXMuYm94Wm9vbSAmJiB0aGlzLmJveFpvb20ubW92ZWQoKSk7XHJcblx0fSxcclxuXHJcblx0X2NsZWFySGFuZGxlcnM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSB0aGlzLl9oYW5kbGVycy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0XHR0aGlzLl9oYW5kbGVyc1tpXS5kaXNhYmxlKCk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQHNlY3Rpb24gT3RoZXIgTWV0aG9kc1xyXG5cclxuXHQvLyBAbWV0aG9kIHdoZW5SZWFkeShmbjogRnVuY3Rpb24sIGNvbnRleHQ/OiBPYmplY3QpOiB0aGlzXHJcblx0Ly8gUnVucyB0aGUgZ2l2ZW4gZnVuY3Rpb24gYGZuYCB3aGVuIHRoZSBtYXAgZ2V0cyBpbml0aWFsaXplZCB3aXRoXHJcblx0Ly8gYSB2aWV3IChjZW50ZXIgYW5kIHpvb20pIGFuZCBhdCBsZWFzdCBvbmUgbGF5ZXIsIG9yIGltbWVkaWF0ZWx5XHJcblx0Ly8gaWYgaXQncyBhbHJlYWR5IGluaXRpYWxpemVkLCBvcHRpb25hbGx5IHBhc3NpbmcgYSBmdW5jdGlvbiBjb250ZXh0LlxyXG5cdHdoZW5SZWFkeTogZnVuY3Rpb24gKGNhbGxiYWNrLCBjb250ZXh0KSB7XHJcblx0XHRpZiAodGhpcy5fbG9hZGVkKSB7XHJcblx0XHRcdGNhbGxiYWNrLmNhbGwoY29udGV4dCB8fCB0aGlzLCB7dGFyZ2V0OiB0aGlzfSk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR0aGlzLm9uKCdsb2FkJywgY2FsbGJhY2ssIGNvbnRleHQpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblxyXG5cdC8vIHByaXZhdGUgbWV0aG9kcyBmb3IgZ2V0dGluZyBtYXAgc3RhdGVcclxuXHJcblx0X2dldE1hcFBhbmVQb3M6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiBMLkRvbVV0aWwuZ2V0UG9zaXRpb24odGhpcy5fbWFwUGFuZSkgfHwgbmV3IEwuUG9pbnQoMCwgMCk7XHJcblx0fSxcclxuXHJcblx0X21vdmVkOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgcG9zID0gdGhpcy5fZ2V0TWFwUGFuZVBvcygpO1xyXG5cdFx0cmV0dXJuIHBvcyAmJiAhcG9zLmVxdWFscyhbMCwgMF0pO1xyXG5cdH0sXHJcblxyXG5cdF9nZXRUb3BMZWZ0UG9pbnQ6IGZ1bmN0aW9uIChjZW50ZXIsIHpvb20pIHtcclxuXHRcdHZhciBwaXhlbE9yaWdpbiA9IGNlbnRlciAmJiB6b29tICE9PSB1bmRlZmluZWQgP1xyXG5cdFx0XHR0aGlzLl9nZXROZXdQaXhlbE9yaWdpbihjZW50ZXIsIHpvb20pIDpcclxuXHRcdFx0dGhpcy5nZXRQaXhlbE9yaWdpbigpO1xyXG5cdFx0cmV0dXJuIHBpeGVsT3JpZ2luLnN1YnRyYWN0KHRoaXMuX2dldE1hcFBhbmVQb3MoKSk7XHJcblx0fSxcclxuXHJcblx0X2dldE5ld1BpeGVsT3JpZ2luOiBmdW5jdGlvbiAoY2VudGVyLCB6b29tKSB7XHJcblx0XHR2YXIgdmlld0hhbGYgPSB0aGlzLmdldFNpemUoKS5fZGl2aWRlQnkoMik7XHJcblx0XHRyZXR1cm4gdGhpcy5wcm9qZWN0KGNlbnRlciwgem9vbSkuX3N1YnRyYWN0KHZpZXdIYWxmKS5fYWRkKHRoaXMuX2dldE1hcFBhbmVQb3MoKSkuX3JvdW5kKCk7XHJcblx0fSxcclxuXHJcblx0X2xhdExuZ1RvTmV3TGF5ZXJQb2ludDogZnVuY3Rpb24gKGxhdGxuZywgem9vbSwgY2VudGVyKSB7XHJcblx0XHR2YXIgdG9wTGVmdCA9IHRoaXMuX2dldE5ld1BpeGVsT3JpZ2luKGNlbnRlciwgem9vbSk7XHJcblx0XHRyZXR1cm4gdGhpcy5wcm9qZWN0KGxhdGxuZywgem9vbSkuX3N1YnRyYWN0KHRvcExlZnQpO1xyXG5cdH0sXHJcblxyXG5cdF9sYXRMbmdCb3VuZHNUb05ld0xheWVyQm91bmRzOiBmdW5jdGlvbiAobGF0TG5nQm91bmRzLCB6b29tLCBjZW50ZXIpIHtcclxuXHRcdHZhciB0b3BMZWZ0ID0gdGhpcy5fZ2V0TmV3UGl4ZWxPcmlnaW4oY2VudGVyLCB6b29tKTtcclxuXHRcdHJldHVybiBMLmJvdW5kcyhbXHJcblx0XHRcdHRoaXMucHJvamVjdChsYXRMbmdCb3VuZHMuZ2V0U291dGhXZXN0KCksIHpvb20pLl9zdWJ0cmFjdCh0b3BMZWZ0KSxcclxuXHRcdFx0dGhpcy5wcm9qZWN0KGxhdExuZ0JvdW5kcy5nZXROb3J0aFdlc3QoKSwgem9vbSkuX3N1YnRyYWN0KHRvcExlZnQpLFxyXG5cdFx0XHR0aGlzLnByb2plY3QobGF0TG5nQm91bmRzLmdldFNvdXRoRWFzdCgpLCB6b29tKS5fc3VidHJhY3QodG9wTGVmdCksXHJcblx0XHRcdHRoaXMucHJvamVjdChsYXRMbmdCb3VuZHMuZ2V0Tm9ydGhFYXN0KCksIHpvb20pLl9zdWJ0cmFjdCh0b3BMZWZ0KVxyXG5cdFx0XSk7XHJcblx0fSxcclxuXHJcblx0Ly8gbGF5ZXIgcG9pbnQgb2YgdGhlIGN1cnJlbnQgY2VudGVyXHJcblx0X2dldENlbnRlckxheWVyUG9pbnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLmNvbnRhaW5lclBvaW50VG9MYXllclBvaW50KHRoaXMuZ2V0U2l6ZSgpLl9kaXZpZGVCeSgyKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gb2Zmc2V0IG9mIHRoZSBzcGVjaWZpZWQgcGxhY2UgdG8gdGhlIGN1cnJlbnQgY2VudGVyIGluIHBpeGVsc1xyXG5cdF9nZXRDZW50ZXJPZmZzZXQ6IGZ1bmN0aW9uIChsYXRsbmcpIHtcclxuXHRcdHJldHVybiB0aGlzLmxhdExuZ1RvTGF5ZXJQb2ludChsYXRsbmcpLnN1YnRyYWN0KHRoaXMuX2dldENlbnRlckxheWVyUG9pbnQoKSk7XHJcblx0fSxcclxuXHJcblx0Ly8gYWRqdXN0IGNlbnRlciBmb3IgdmlldyB0byBnZXQgaW5zaWRlIGJvdW5kc1xyXG5cdF9saW1pdENlbnRlcjogZnVuY3Rpb24gKGNlbnRlciwgem9vbSwgYm91bmRzKSB7XHJcblxyXG5cdFx0aWYgKCFib3VuZHMpIHsgcmV0dXJuIGNlbnRlcjsgfVxyXG5cclxuXHRcdHZhciBjZW50ZXJQb2ludCA9IHRoaXMucHJvamVjdChjZW50ZXIsIHpvb20pLFxyXG5cdFx0ICAgIHZpZXdIYWxmID0gdGhpcy5nZXRTaXplKCkuZGl2aWRlQnkoMiksXHJcblx0XHQgICAgdmlld0JvdW5kcyA9IG5ldyBMLkJvdW5kcyhjZW50ZXJQb2ludC5zdWJ0cmFjdCh2aWV3SGFsZiksIGNlbnRlclBvaW50LmFkZCh2aWV3SGFsZikpLFxyXG5cdFx0ICAgIG9mZnNldCA9IHRoaXMuX2dldEJvdW5kc09mZnNldCh2aWV3Qm91bmRzLCBib3VuZHMsIHpvb20pO1xyXG5cclxuXHRcdC8vIElmIG9mZnNldCBpcyBsZXNzIHRoYW4gYSBwaXhlbCwgaWdub3JlLlxyXG5cdFx0Ly8gVGhpcyBwcmV2ZW50cyB1bnN0YWJsZSBwcm9qZWN0aW9ucyBmcm9tIGdldHRpbmcgaW50b1xyXG5cdFx0Ly8gYW4gaW5maW5pdGUgbG9vcCBvZiB0aW55IG9mZnNldHMuXHJcblx0XHRpZiAob2Zmc2V0LnJvdW5kKCkuZXF1YWxzKFswLCAwXSkpIHtcclxuXHRcdFx0cmV0dXJuIGNlbnRlcjtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcy51bnByb2plY3QoY2VudGVyUG9pbnQuYWRkKG9mZnNldCksIHpvb20pO1xyXG5cdH0sXHJcblxyXG5cdC8vIGFkanVzdCBvZmZzZXQgZm9yIHZpZXcgdG8gZ2V0IGluc2lkZSBib3VuZHNcclxuXHRfbGltaXRPZmZzZXQ6IGZ1bmN0aW9uIChvZmZzZXQsIGJvdW5kcykge1xyXG5cdFx0aWYgKCFib3VuZHMpIHsgcmV0dXJuIG9mZnNldDsgfVxyXG5cclxuXHRcdHZhciB2aWV3Qm91bmRzID0gdGhpcy5nZXRQaXhlbEJvdW5kcygpLFxyXG5cdFx0ICAgIG5ld0JvdW5kcyA9IG5ldyBMLkJvdW5kcyh2aWV3Qm91bmRzLm1pbi5hZGQob2Zmc2V0KSwgdmlld0JvdW5kcy5tYXguYWRkKG9mZnNldCkpO1xyXG5cclxuXHRcdHJldHVybiBvZmZzZXQuYWRkKHRoaXMuX2dldEJvdW5kc09mZnNldChuZXdCb3VuZHMsIGJvdW5kcykpO1xyXG5cdH0sXHJcblxyXG5cdC8vIHJldHVybnMgb2Zmc2V0IG5lZWRlZCBmb3IgcHhCb3VuZHMgdG8gZ2V0IGluc2lkZSBtYXhCb3VuZHMgYXQgYSBzcGVjaWZpZWQgem9vbVxyXG5cdF9nZXRCb3VuZHNPZmZzZXQ6IGZ1bmN0aW9uIChweEJvdW5kcywgbWF4Qm91bmRzLCB6b29tKSB7XHJcblx0XHR2YXIgcHJvamVjdGVkTWF4Qm91bmRzID0gTC5ib3VuZHMoXHJcblx0XHQgICAgICAgIHRoaXMucHJvamVjdChtYXhCb3VuZHMuZ2V0Tm9ydGhFYXN0KCksIHpvb20pLFxyXG5cdFx0ICAgICAgICB0aGlzLnByb2plY3QobWF4Qm91bmRzLmdldFNvdXRoV2VzdCgpLCB6b29tKVxyXG5cdFx0ICAgICksXHJcblx0XHQgICAgbWluT2Zmc2V0ID0gcHJvamVjdGVkTWF4Qm91bmRzLm1pbi5zdWJ0cmFjdChweEJvdW5kcy5taW4pLFxyXG5cdFx0ICAgIG1heE9mZnNldCA9IHByb2plY3RlZE1heEJvdW5kcy5tYXguc3VidHJhY3QocHhCb3VuZHMubWF4KSxcclxuXHJcblx0XHQgICAgZHggPSB0aGlzLl9yZWJvdW5kKG1pbk9mZnNldC54LCAtbWF4T2Zmc2V0LngpLFxyXG5cdFx0ICAgIGR5ID0gdGhpcy5fcmVib3VuZChtaW5PZmZzZXQueSwgLW1heE9mZnNldC55KTtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEwuUG9pbnQoZHgsIGR5KTtcclxuXHR9LFxyXG5cclxuXHRfcmVib3VuZDogZnVuY3Rpb24gKGxlZnQsIHJpZ2h0KSB7XHJcblx0XHRyZXR1cm4gbGVmdCArIHJpZ2h0ID4gMCA/XHJcblx0XHRcdE1hdGgucm91bmQobGVmdCAtIHJpZ2h0KSAvIDIgOlxyXG5cdFx0XHRNYXRoLm1heCgwLCBNYXRoLmNlaWwobGVmdCkpIC0gTWF0aC5tYXgoMCwgTWF0aC5mbG9vcihyaWdodCkpO1xyXG5cdH0sXHJcblxyXG5cdF9saW1pdFpvb206IGZ1bmN0aW9uICh6b29tKSB7XHJcblx0XHR2YXIgbWluID0gdGhpcy5nZXRNaW5ab29tKCksXHJcblx0XHQgICAgbWF4ID0gdGhpcy5nZXRNYXhab29tKCksXHJcblx0XHQgICAgc25hcCA9IEwuQnJvd3Nlci5hbnkzZCA/IHRoaXMub3B0aW9ucy56b29tU25hcCA6IDE7XHJcblx0XHRpZiAoc25hcCkge1xyXG5cdFx0XHR6b29tID0gTWF0aC5yb3VuZCh6b29tIC8gc25hcCkgKiBzbmFwO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIE1hdGgubWF4KG1pbiwgTWF0aC5taW4obWF4LCB6b29tKSk7XHJcblx0fSxcclxuXHJcblx0X29uUGFuVHJhbnNpdGlvblN0ZXA6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuZmlyZSgnbW92ZScpO1xyXG5cdH0sXHJcblxyXG5cdF9vblBhblRyYW5zaXRpb25FbmQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl9tYXBQYW5lLCAnbGVhZmxldC1wYW4tYW5pbScpO1xyXG5cdFx0dGhpcy5maXJlKCdtb3ZlZW5kJyk7XHJcblx0fSxcclxuXHJcblx0X3RyeUFuaW1hdGVkUGFuOiBmdW5jdGlvbiAoY2VudGVyLCBvcHRpb25zKSB7XHJcblx0XHQvLyBkaWZmZXJlbmNlIGJldHdlZW4gdGhlIG5ldyBhbmQgY3VycmVudCBjZW50ZXJzIGluIHBpeGVsc1xyXG5cdFx0dmFyIG9mZnNldCA9IHRoaXMuX2dldENlbnRlck9mZnNldChjZW50ZXIpLl9mbG9vcigpO1xyXG5cclxuXHRcdC8vIGRvbid0IGFuaW1hdGUgdG9vIGZhciB1bmxlc3MgYW5pbWF0ZTogdHJ1ZSBzcGVjaWZpZWQgaW4gb3B0aW9uc1xyXG5cdFx0aWYgKChvcHRpb25zICYmIG9wdGlvbnMuYW5pbWF0ZSkgIT09IHRydWUgJiYgIXRoaXMuZ2V0U2l6ZSgpLmNvbnRhaW5zKG9mZnNldCkpIHsgcmV0dXJuIGZhbHNlOyB9XHJcblxyXG5cdFx0dGhpcy5wYW5CeShvZmZzZXQsIG9wdGlvbnMpO1xyXG5cclxuXHRcdHJldHVybiB0cnVlO1xyXG5cdH0sXHJcblxyXG5cdF9jcmVhdGVBbmltUHJveHk6IGZ1bmN0aW9uICgpIHtcclxuXHJcblx0XHR2YXIgcHJveHkgPSB0aGlzLl9wcm94eSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsICdsZWFmbGV0LXByb3h5IGxlYWZsZXQtem9vbS1hbmltYXRlZCcpO1xyXG5cdFx0dGhpcy5fcGFuZXMubWFwUGFuZS5hcHBlbmRDaGlsZChwcm94eSk7XHJcblxyXG5cdFx0dGhpcy5vbignem9vbWFuaW0nLCBmdW5jdGlvbiAoZSkge1xyXG5cdFx0XHR2YXIgcHJvcCA9IEwuRG9tVXRpbC5UUkFOU0ZPUk0sXHJcblx0XHRcdCAgICB0cmFuc2Zvcm0gPSBwcm94eS5zdHlsZVtwcm9wXTtcclxuXHJcblx0XHRcdEwuRG9tVXRpbC5zZXRUcmFuc2Zvcm0ocHJveHksIHRoaXMucHJvamVjdChlLmNlbnRlciwgZS56b29tKSwgdGhpcy5nZXRab29tU2NhbGUoZS56b29tLCAxKSk7XHJcblxyXG5cdFx0XHQvLyB3b3JrYXJvdW5kIGZvciBjYXNlIHdoZW4gdHJhbnNmb3JtIGlzIHRoZSBzYW1lIGFuZCBzbyB0cmFuc2l0aW9uZW5kIGV2ZW50IGlzIG5vdCBmaXJlZFxyXG5cdFx0XHRpZiAodHJhbnNmb3JtID09PSBwcm94eS5zdHlsZVtwcm9wXSAmJiB0aGlzLl9hbmltYXRpbmdab29tKSB7XHJcblx0XHRcdFx0dGhpcy5fb25ab29tVHJhbnNpdGlvbkVuZCgpO1xyXG5cdFx0XHR9XHJcblx0XHR9LCB0aGlzKTtcclxuXHJcblx0XHR0aGlzLm9uKCdsb2FkIG1vdmVlbmQnLCBmdW5jdGlvbiAoKSB7XHJcblx0XHRcdHZhciBjID0gdGhpcy5nZXRDZW50ZXIoKSxcclxuXHRcdFx0ICAgIHogPSB0aGlzLmdldFpvb20oKTtcclxuXHRcdFx0TC5Eb21VdGlsLnNldFRyYW5zZm9ybShwcm94eSwgdGhpcy5wcm9qZWN0KGMsIHopLCB0aGlzLmdldFpvb21TY2FsZSh6LCAxKSk7XHJcblx0XHR9LCB0aGlzKTtcclxuXHR9LFxyXG5cclxuXHRfY2F0Y2hUcmFuc2l0aW9uRW5kOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0aWYgKHRoaXMuX2FuaW1hdGluZ1pvb20gJiYgZS5wcm9wZXJ0eU5hbWUuaW5kZXhPZigndHJhbnNmb3JtJykgPj0gMCkge1xyXG5cdFx0XHR0aGlzLl9vblpvb21UcmFuc2l0aW9uRW5kKCk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X25vdGhpbmdUb0FuaW1hdGU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiAhdGhpcy5fY29udGFpbmVyLmdldEVsZW1lbnRzQnlDbGFzc05hbWUoJ2xlYWZsZXQtem9vbS1hbmltYXRlZCcpLmxlbmd0aDtcclxuXHR9LFxyXG5cclxuXHRfdHJ5QW5pbWF0ZWRab29tOiBmdW5jdGlvbiAoY2VudGVyLCB6b29tLCBvcHRpb25zKSB7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2FuaW1hdGluZ1pvb20pIHsgcmV0dXJuIHRydWU7IH1cclxuXHJcblx0XHRvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcclxuXHJcblx0XHQvLyBkb24ndCBhbmltYXRlIGlmIGRpc2FibGVkLCBub3Qgc3VwcG9ydGVkIG9yIHpvb20gZGlmZmVyZW5jZSBpcyB0b28gbGFyZ2VcclxuXHRcdGlmICghdGhpcy5fem9vbUFuaW1hdGVkIHx8IG9wdGlvbnMuYW5pbWF0ZSA9PT0gZmFsc2UgfHwgdGhpcy5fbm90aGluZ1RvQW5pbWF0ZSgpIHx8XHJcblx0XHQgICAgICAgIE1hdGguYWJzKHpvb20gLSB0aGlzLl96b29tKSA+IHRoaXMub3B0aW9ucy56b29tQW5pbWF0aW9uVGhyZXNob2xkKSB7IHJldHVybiBmYWxzZTsgfVxyXG5cclxuXHRcdC8vIG9mZnNldCBpcyB0aGUgcGl4ZWwgY29vcmRzIG9mIHRoZSB6b29tIG9yaWdpbiByZWxhdGl2ZSB0byB0aGUgY3VycmVudCBjZW50ZXJcclxuXHRcdHZhciBzY2FsZSA9IHRoaXMuZ2V0Wm9vbVNjYWxlKHpvb20pLFxyXG5cdFx0ICAgIG9mZnNldCA9IHRoaXMuX2dldENlbnRlck9mZnNldChjZW50ZXIpLl9kaXZpZGVCeSgxIC0gMSAvIHNjYWxlKTtcclxuXHJcblx0XHQvLyBkb24ndCBhbmltYXRlIGlmIHRoZSB6b29tIG9yaWdpbiBpc24ndCB3aXRoaW4gb25lIHNjcmVlbiBmcm9tIHRoZSBjdXJyZW50IGNlbnRlciwgdW5sZXNzIGZvcmNlZFxyXG5cdFx0aWYgKG9wdGlvbnMuYW5pbWF0ZSAhPT0gdHJ1ZSAmJiAhdGhpcy5nZXRTaXplKCkuY29udGFpbnMob2Zmc2V0KSkgeyByZXR1cm4gZmFsc2U7IH1cclxuXHJcblx0XHRMLlV0aWwucmVxdWVzdEFuaW1GcmFtZShmdW5jdGlvbiAoKSB7XHJcblx0XHRcdHRoaXNcclxuXHRcdFx0ICAgIC5fbW92ZVN0YXJ0KHRydWUpXHJcblx0XHRcdCAgICAuX2FuaW1hdGVab29tKGNlbnRlciwgem9vbSwgdHJ1ZSk7XHJcblx0XHR9LCB0aGlzKTtcclxuXHJcblx0XHRyZXR1cm4gdHJ1ZTtcclxuXHR9LFxyXG5cclxuXHRfYW5pbWF0ZVpvb206IGZ1bmN0aW9uIChjZW50ZXIsIHpvb20sIHN0YXJ0QW5pbSwgbm9VcGRhdGUpIHtcclxuXHRcdGlmIChzdGFydEFuaW0pIHtcclxuXHRcdFx0dGhpcy5fYW5pbWF0aW5nWm9vbSA9IHRydWU7XHJcblxyXG5cdFx0XHQvLyByZW1lbWJlciB3aGF0IGNlbnRlci96b29tIHRvIHNldCBhZnRlciBhbmltYXRpb25cclxuXHRcdFx0dGhpcy5fYW5pbWF0ZVRvQ2VudGVyID0gY2VudGVyO1xyXG5cdFx0XHR0aGlzLl9hbmltYXRlVG9ab29tID0gem9vbTtcclxuXHJcblx0XHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9tYXBQYW5lLCAnbGVhZmxldC16b29tLWFuaW0nKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBAZXZlbnQgem9vbWFuaW06IFpvb21BbmltRXZlbnRcclxuXHRcdC8vIEZpcmVkIG9uIGV2ZXJ5IGZyYW1lIG9mIGEgem9vbSBhbmltYXRpb25cclxuXHRcdHRoaXMuZmlyZSgnem9vbWFuaW0nLCB7XHJcblx0XHRcdGNlbnRlcjogY2VudGVyLFxyXG5cdFx0XHR6b29tOiB6b29tLFxyXG5cdFx0XHRub1VwZGF0ZTogbm9VcGRhdGVcclxuXHRcdH0pO1xyXG5cclxuXHRcdC8vIFdvcmsgYXJvdW5kIHdlYmtpdCBub3QgZmlyaW5nICd0cmFuc2l0aW9uZW5kJywgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9MZWFmbGV0L0xlYWZsZXQvaXNzdWVzLzM2ODksIDI2OTNcclxuXHRcdHNldFRpbWVvdXQoTC5iaW5kKHRoaXMuX29uWm9vbVRyYW5zaXRpb25FbmQsIHRoaXMpLCAyNTApO1xyXG5cdH0sXHJcblxyXG5cdF9vblpvb21UcmFuc2l0aW9uRW5kOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX2FuaW1hdGluZ1pvb20pIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0TC5Eb21VdGlsLnJlbW92ZUNsYXNzKHRoaXMuX21hcFBhbmUsICdsZWFmbGV0LXpvb20tYW5pbScpO1xyXG5cclxuXHRcdHRoaXMuX2FuaW1hdGluZ1pvb20gPSBmYWxzZTtcclxuXHJcblx0XHR0aGlzLl9tb3ZlKHRoaXMuX2FuaW1hdGVUb0NlbnRlciwgdGhpcy5fYW5pbWF0ZVRvWm9vbSk7XHJcblxyXG5cdFx0Ly8gVGhpcyBhbmltIGZyYW1lIHNob3VsZCBwcmV2ZW50IGFuIG9ic2N1cmUgaU9TIHdlYmtpdCB0aWxlIGxvYWRpbmcgcmFjZSBjb25kaXRpb24uXHJcblx0XHRMLlV0aWwucmVxdWVzdEFuaW1GcmFtZShmdW5jdGlvbiAoKSB7XHJcblx0XHRcdHRoaXMuX21vdmVFbmQodHJ1ZSk7XHJcblx0XHR9LCB0aGlzKTtcclxuXHR9XHJcbn0pO1xyXG5cclxuLy8gQHNlY3Rpb25cclxuXHJcbi8vIEBmYWN0b3J5IEwubWFwKGlkOiBTdHJpbmcsIG9wdGlvbnM/OiBNYXAgb3B0aW9ucylcclxuLy8gSW5zdGFudGlhdGVzIGEgbWFwIG9iamVjdCBnaXZlbiB0aGUgRE9NIElEIG9mIGEgYDxkaXY+YCBlbGVtZW50XHJcbi8vIGFuZCBvcHRpb25hbGx5IGFuIG9iamVjdCBsaXRlcmFsIHdpdGggYE1hcCBvcHRpb25zYC5cclxuLy9cclxuLy8gQGFsdGVybmF0aXZlXHJcbi8vIEBmYWN0b3J5IEwubWFwKGVsOiBIVE1MRWxlbWVudCwgb3B0aW9ucz86IE1hcCBvcHRpb25zKVxyXG4vLyBJbnN0YW50aWF0ZXMgYSBtYXAgb2JqZWN0IGdpdmVuIGFuIGluc3RhbmNlIG9mIGEgYDxkaXY+YCBIVE1MIGVsZW1lbnRcclxuLy8gYW5kIG9wdGlvbmFsbHkgYW4gb2JqZWN0IGxpdGVyYWwgd2l0aCBgTWFwIG9wdGlvbnNgLlxyXG5MLm1hcCA9IGZ1bmN0aW9uIChpZCwgb3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgTC5NYXAoaWQsIG9wdGlvbnMpO1xyXG59O1xyXG5cblxuXG5cbi8qXG4gKiBAY2xhc3MgTGF5ZXJcbiAqIEBpbmhlcml0cyBFdmVudGVkXG4gKiBAYWthIEwuTGF5ZXJcbiAqIEBha2EgSUxheWVyXG4gKlxuICogQSBzZXQgb2YgbWV0aG9kcyBmcm9tIHRoZSBMYXllciBiYXNlIGNsYXNzIHRoYXQgYWxsIExlYWZsZXQgbGF5ZXJzIHVzZS5cbiAqIEluaGVyaXRzIGFsbCBtZXRob2RzLCBvcHRpb25zIGFuZCBldmVudHMgZnJvbSBgTC5FdmVudGVkYC5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGBgYGpzXG4gKiB2YXIgbGF5ZXIgPSBMLk1hcmtlcihsYXRsbmcpLmFkZFRvKG1hcCk7XG4gKiBsYXllci5hZGRUbyhtYXApO1xuICogbGF5ZXIucmVtb3ZlKCk7XG4gKiBgYGBcbiAqXG4gKiBAZXZlbnQgYWRkOiBFdmVudFxuICogRmlyZWQgYWZ0ZXIgdGhlIGxheWVyIGlzIGFkZGVkIHRvIGEgbWFwXG4gKlxuICogQGV2ZW50IHJlbW92ZTogRXZlbnRcbiAqIEZpcmVkIGFmdGVyIHRoZSBsYXllciBpcyByZW1vdmVkIGZyb20gYSBtYXBcbiAqL1xuXG5cbkwuTGF5ZXIgPSBMLkV2ZW50ZWQuZXh0ZW5kKHtcblxuXHQvLyBDbGFzc2VzIGV4dGVuZGluZyBgTC5MYXllcmAgd2lsbCBpbmhlcml0IHRoZSBmb2xsb3dpbmcgb3B0aW9uczpcblx0b3B0aW9uczoge1xuXHRcdC8vIEBvcHRpb24gcGFuZTogU3RyaW5nID0gJ292ZXJsYXlQYW5lJ1xuXHRcdC8vIEJ5IGRlZmF1bHQgdGhlIGxheWVyIHdpbGwgYmUgYWRkZWQgdG8gdGhlIG1hcCdzIFtvdmVybGF5IHBhbmVdKCNtYXAtb3ZlcmxheXBhbmUpLiBPdmVycmlkaW5nIHRoaXMgb3B0aW9uIHdpbGwgY2F1c2UgdGhlIGxheWVyIHRvIGJlIHBsYWNlZCBvbiBhbm90aGVyIHBhbmUgYnkgZGVmYXVsdC5cblx0XHRwYW5lOiAnb3ZlcmxheVBhbmUnLFxuXHRcdG5vbkJ1YmJsaW5nRXZlbnRzOiBbXSwgIC8vIEFycmF5IG9mIGV2ZW50cyB0aGF0IHNob3VsZCBub3QgYmUgYnViYmxlZCB0byBET00gcGFyZW50cyAobGlrZSB0aGUgbWFwKSxcblxuXHRcdC8vIEBvcHRpb24gYXR0cmlidXRpb246IFN0cmluZyA9IG51bGxcblx0XHQvLyBTdHJpbmcgdG8gYmUgc2hvd24gaW4gdGhlIGF0dHJpYnV0aW9uIGNvbnRyb2wsIGRlc2NyaWJlcyB0aGUgbGF5ZXIgZGF0YSwgZS5nLiBcIsKpIE1hcGJveFwiLlxuXHRcdGF0dHJpYnV0aW9uOiBudWxsLFxuXHR9LFxuXG5cdC8qIEBzZWN0aW9uXG5cdCAqIENsYXNzZXMgZXh0ZW5kaW5nIGBMLkxheWVyYCB3aWxsIGluaGVyaXQgdGhlIGZvbGxvd2luZyBtZXRob2RzOlxuXHQgKlxuXHQgKiBAbWV0aG9kIGFkZFRvKG1hcDogTWFwKTogdGhpc1xuXHQgKiBBZGRzIHRoZSBsYXllciB0byB0aGUgZ2l2ZW4gbWFwXG5cdCAqL1xuXHRhZGRUbzogZnVuY3Rpb24gKG1hcCkge1xuXHRcdG1hcC5hZGRMYXllcih0aGlzKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIHJlbW92ZTogdGhpc1xuXHQvLyBSZW1vdmVzIHRoZSBsYXllciBmcm9tIHRoZSBtYXAgaXQgaXMgY3VycmVudGx5IGFjdGl2ZSBvbi5cblx0cmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMucmVtb3ZlRnJvbSh0aGlzLl9tYXAgfHwgdGhpcy5fbWFwVG9BZGQpO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgcmVtb3ZlRnJvbShtYXA6IE1hcCk6IHRoaXNcblx0Ly8gUmVtb3ZlcyB0aGUgbGF5ZXIgZnJvbSB0aGUgZ2l2ZW4gbWFwXG5cdHJlbW92ZUZyb206IGZ1bmN0aW9uIChvYmopIHtcblx0XHRpZiAob2JqKSB7XG5cdFx0XHRvYmoucmVtb3ZlTGF5ZXIodGhpcyk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgZ2V0UGFuZShuYW1lPyA6IFN0cmluZyk6IEhUTUxFbGVtZW50XG5cdC8vIFJldHVybnMgdGhlIGBIVE1MRWxlbWVudGAgcmVwcmVzZW50aW5nIHRoZSBuYW1lZCBwYW5lIG9uIHRoZSBtYXAuIElmIGBuYW1lYCBpcyBvbWl0dGVkLCByZXR1cm5zIHRoZSBwYW5lIGZvciB0aGlzIGxheWVyLlxuXHRnZXRQYW5lOiBmdW5jdGlvbiAobmFtZSkge1xuXHRcdHJldHVybiB0aGlzLl9tYXAuZ2V0UGFuZShuYW1lID8gKHRoaXMub3B0aW9uc1tuYW1lXSB8fCBuYW1lKSA6IHRoaXMub3B0aW9ucy5wYW5lKTtcblx0fSxcblxuXHRhZGRJbnRlcmFjdGl2ZVRhcmdldDogZnVuY3Rpb24gKHRhcmdldEVsKSB7XG5cdFx0dGhpcy5fbWFwLl90YXJnZXRzW0wuc3RhbXAodGFyZ2V0RWwpXSA9IHRoaXM7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0cmVtb3ZlSW50ZXJhY3RpdmVUYXJnZXQ6IGZ1bmN0aW9uICh0YXJnZXRFbCkge1xuXHRcdGRlbGV0ZSB0aGlzLl9tYXAuX3RhcmdldHNbTC5zdGFtcCh0YXJnZXRFbCldO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgZ2V0QXR0cmlidXRpb246IFN0cmluZ1xuXHQvLyBVc2VkIGJ5IHRoZSBgYXR0cmlidXRpb24gY29udHJvbGAsIHJldHVybnMgdGhlIFthdHRyaWJ1dGlvbiBvcHRpb25dKCNncmlkbGF5ZXItYXR0cmlidXRpb24pLlxuXHRnZXRBdHRyaWJ1dGlvbjogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMuYXR0cmlidXRpb247XG5cdH0sXG5cblx0X2xheWVyQWRkOiBmdW5jdGlvbiAoZSkge1xuXHRcdHZhciBtYXAgPSBlLnRhcmdldDtcblxuXHRcdC8vIGNoZWNrIGluIGNhc2UgbGF5ZXIgZ2V0cyBhZGRlZCBhbmQgdGhlbiByZW1vdmVkIGJlZm9yZSB0aGUgbWFwIGlzIHJlYWR5XG5cdFx0aWYgKCFtYXAuaGFzTGF5ZXIodGhpcykpIHsgcmV0dXJuOyB9XG5cblx0XHR0aGlzLl9tYXAgPSBtYXA7XG5cdFx0dGhpcy5fem9vbUFuaW1hdGVkID0gbWFwLl96b29tQW5pbWF0ZWQ7XG5cblx0XHRpZiAodGhpcy5nZXRFdmVudHMpIHtcblx0XHRcdHZhciBldmVudHMgPSB0aGlzLmdldEV2ZW50cygpO1xuXHRcdFx0bWFwLm9uKGV2ZW50cywgdGhpcyk7XG5cdFx0XHR0aGlzLm9uY2UoJ3JlbW92ZScsIGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0bWFwLm9mZihldmVudHMsIHRoaXMpO1xuXHRcdFx0fSwgdGhpcyk7XG5cdFx0fVxuXG5cdFx0dGhpcy5vbkFkZChtYXApO1xuXG5cdFx0aWYgKHRoaXMuZ2V0QXR0cmlidXRpb24gJiYgdGhpcy5fbWFwLmF0dHJpYnV0aW9uQ29udHJvbCkge1xuXHRcdFx0dGhpcy5fbWFwLmF0dHJpYnV0aW9uQ29udHJvbC5hZGRBdHRyaWJ1dGlvbih0aGlzLmdldEF0dHJpYnV0aW9uKCkpO1xuXHRcdH1cblxuXHRcdHRoaXMuZmlyZSgnYWRkJyk7XG5cdFx0bWFwLmZpcmUoJ2xheWVyYWRkJywge2xheWVyOiB0aGlzfSk7XG5cdH1cbn0pO1xuXG4vKiBAc2VjdGlvbiBFeHRlbnNpb24gbWV0aG9kc1xuICogQHVuaW5oZXJpdGFibGVcbiAqXG4gKiBFdmVyeSBsYXllciBzaG91bGQgZXh0ZW5kIGZyb20gYEwuTGF5ZXJgIGFuZCAocmUtKWltcGxlbWVudCB0aGUgZm9sbG93aW5nIG1ldGhvZHMuXG4gKlxuICogQG1ldGhvZCBvbkFkZChtYXA6IE1hcCk6IHRoaXNcbiAqIFNob3VsZCBjb250YWluIGNvZGUgdGhhdCBjcmVhdGVzIERPTSBlbGVtZW50cyBmb3IgdGhlIGxheWVyLCBhZGRzIHRoZW0gdG8gYG1hcCBwYW5lc2Agd2hlcmUgdGhleSBzaG91bGQgYmVsb25nIGFuZCBwdXRzIGxpc3RlbmVycyBvbiByZWxldmFudCBtYXAgZXZlbnRzLiBDYWxsZWQgb24gW2BtYXAuYWRkTGF5ZXIobGF5ZXIpYF0oI21hcC1hZGRsYXllcikuXG4gKlxuICogQG1ldGhvZCBvblJlbW92ZShtYXA6IE1hcCk6IHRoaXNcbiAqIFNob3VsZCBjb250YWluIGFsbCBjbGVhbiB1cCBjb2RlIHRoYXQgcmVtb3ZlcyB0aGUgbGF5ZXIncyBlbGVtZW50cyBmcm9tIHRoZSBET00gYW5kIHJlbW92ZXMgbGlzdGVuZXJzIHByZXZpb3VzbHkgYWRkZWQgaW4gW2BvbkFkZGBdKCNsYXllci1vbmFkZCkuIENhbGxlZCBvbiBbYG1hcC5yZW1vdmVMYXllcihsYXllcilgXSgjbWFwLXJlbW92ZWxheWVyKS5cbiAqXG4gKiBAbWV0aG9kIGdldEV2ZW50cygpOiBPYmplY3RcbiAqIFRoaXMgb3B0aW9uYWwgbWV0aG9kIHNob3VsZCByZXR1cm4gYW4gb2JqZWN0IGxpa2UgYHsgdmlld3Jlc2V0OiB0aGlzLl9yZXNldCB9YCBmb3IgW2BhZGRFdmVudExpc3RlbmVyYF0oI2V2ZW50ZWQtYWRkZXZlbnRsaXN0ZW5lcikuIFRoZSBldmVudCBoYW5kbGVycyBpbiB0aGlzIG9iamVjdCB3aWxsIGJlIGF1dG9tYXRpY2FsbHkgYWRkZWQgYW5kIHJlbW92ZWQgZnJvbSB0aGUgbWFwIHdpdGggeW91ciBsYXllci5cbiAqXG4gKiBAbWV0aG9kIGdldEF0dHJpYnV0aW9uKCk6IFN0cmluZ1xuICogVGhpcyBvcHRpb25hbCBtZXRob2Qgc2hvdWxkIHJldHVybiBhIHN0cmluZyBjb250YWluaW5nIEhUTUwgdG8gYmUgc2hvd24gb24gdGhlIGBBdHRyaWJ1dGlvbiBjb250cm9sYCB3aGVuZXZlciB0aGUgbGF5ZXIgaXMgdmlzaWJsZS5cbiAqXG4gKiBAbWV0aG9kIGJlZm9yZUFkZChtYXA6IE1hcCk6IHRoaXNcbiAqIE9wdGlvbmFsIG1ldGhvZC4gQ2FsbGVkIG9uIFtgbWFwLmFkZExheWVyKGxheWVyKWBdKCNtYXAtYWRkbGF5ZXIpLCBiZWZvcmUgdGhlIGxheWVyIGlzIGFkZGVkIHRvIHRoZSBtYXAsIGJlZm9yZSBldmVudHMgYXJlIGluaXRpYWxpemVkLCB3aXRob3V0IHdhaXRpbmcgdW50aWwgdGhlIG1hcCBpcyBpbiBhIHVzYWJsZSBzdGF0ZS4gVXNlIGZvciBlYXJseSBpbml0aWFsaXphdGlvbiBvbmx5LlxuICovXG5cblxuLyogQG5hbWVzcGFjZSBNYXBcbiAqIEBzZWN0aW9uIExheWVyIGV2ZW50c1xuICpcbiAqIEBldmVudCBsYXllcmFkZDogTGF5ZXJFdmVudFxuICogRmlyZWQgd2hlbiBhIG5ldyBsYXllciBpcyBhZGRlZCB0byB0aGUgbWFwLlxuICpcbiAqIEBldmVudCBsYXllcnJlbW92ZTogTGF5ZXJFdmVudFxuICogRmlyZWQgd2hlbiBzb21lIGxheWVyIGlzIHJlbW92ZWQgZnJvbSB0aGUgbWFwXG4gKlxuICogQHNlY3Rpb24gTWV0aG9kcyBmb3IgTGF5ZXJzIGFuZCBDb250cm9sc1xuICovXG5MLk1hcC5pbmNsdWRlKHtcblx0Ly8gQG1ldGhvZCBhZGRMYXllcihsYXllcjogTGF5ZXIpOiB0aGlzXG5cdC8vIEFkZHMgdGhlIGdpdmVuIGxheWVyIHRvIHRoZSBtYXBcblx0YWRkTGF5ZXI6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBpZCA9IEwuc3RhbXAobGF5ZXIpO1xuXHRcdGlmICh0aGlzLl9sYXllcnNbaWRdKSB7IHJldHVybiB0aGlzOyB9XG5cdFx0dGhpcy5fbGF5ZXJzW2lkXSA9IGxheWVyO1xuXG5cdFx0bGF5ZXIuX21hcFRvQWRkID0gdGhpcztcblxuXHRcdGlmIChsYXllci5iZWZvcmVBZGQpIHtcblx0XHRcdGxheWVyLmJlZm9yZUFkZCh0aGlzKTtcblx0XHR9XG5cblx0XHR0aGlzLndoZW5SZWFkeShsYXllci5fbGF5ZXJBZGQsIGxheWVyKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgcmVtb3ZlTGF5ZXIobGF5ZXI6IExheWVyKTogdGhpc1xuXHQvLyBSZW1vdmVzIHRoZSBnaXZlbiBsYXllciBmcm9tIHRoZSBtYXAuXG5cdHJlbW92ZUxheWVyOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR2YXIgaWQgPSBMLnN0YW1wKGxheWVyKTtcblxuXHRcdGlmICghdGhpcy5fbGF5ZXJzW2lkXSkgeyByZXR1cm4gdGhpczsgfVxuXG5cdFx0aWYgKHRoaXMuX2xvYWRlZCkge1xuXHRcdFx0bGF5ZXIub25SZW1vdmUodGhpcyk7XG5cdFx0fVxuXG5cdFx0aWYgKGxheWVyLmdldEF0dHJpYnV0aW9uICYmIHRoaXMuYXR0cmlidXRpb25Db250cm9sKSB7XG5cdFx0XHR0aGlzLmF0dHJpYnV0aW9uQ29udHJvbC5yZW1vdmVBdHRyaWJ1dGlvbihsYXllci5nZXRBdHRyaWJ1dGlvbigpKTtcblx0XHR9XG5cblx0XHRkZWxldGUgdGhpcy5fbGF5ZXJzW2lkXTtcblxuXHRcdGlmICh0aGlzLl9sb2FkZWQpIHtcblx0XHRcdHRoaXMuZmlyZSgnbGF5ZXJyZW1vdmUnLCB7bGF5ZXI6IGxheWVyfSk7XG5cdFx0XHRsYXllci5maXJlKCdyZW1vdmUnKTtcblx0XHR9XG5cblx0XHRsYXllci5fbWFwID0gbGF5ZXIuX21hcFRvQWRkID0gbnVsbDtcblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgaGFzTGF5ZXIobGF5ZXI6IExheWVyKTogQm9vbGVhblxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgZ2l2ZW4gbGF5ZXIgaXMgY3VycmVudGx5IGFkZGVkIHRvIHRoZSBtYXBcblx0aGFzTGF5ZXI6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHJldHVybiAhIWxheWVyICYmIChMLnN0YW1wKGxheWVyKSBpbiB0aGlzLl9sYXllcnMpO1xuXHR9LFxuXG5cdC8qIEBtZXRob2QgZWFjaExheWVyKGZuOiBGdW5jdGlvbiwgY29udGV4dD86IE9iamVjdCk6IHRoaXNcblx0ICogSXRlcmF0ZXMgb3ZlciB0aGUgbGF5ZXJzIG9mIHRoZSBtYXAsIG9wdGlvbmFsbHkgc3BlY2lmeWluZyBjb250ZXh0IG9mIHRoZSBpdGVyYXRvciBmdW5jdGlvbi5cblx0ICogYGBgXG5cdCAqIG1hcC5lYWNoTGF5ZXIoZnVuY3Rpb24obGF5ZXIpe1xuXHQgKiAgICAgbGF5ZXIuYmluZFBvcHVwKCdIZWxsbycpO1xuXHQgKiB9KTtcblx0ICogYGBgXG5cdCAqL1xuXHRlYWNoTGF5ZXI6IGZ1bmN0aW9uIChtZXRob2QsIGNvbnRleHQpIHtcblx0XHRmb3IgKHZhciBpIGluIHRoaXMuX2xheWVycykge1xuXHRcdFx0bWV0aG9kLmNhbGwoY29udGV4dCwgdGhpcy5fbGF5ZXJzW2ldKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X2FkZExheWVyczogZnVuY3Rpb24gKGxheWVycykge1xuXHRcdGxheWVycyA9IGxheWVycyA/IChMLlV0aWwuaXNBcnJheShsYXllcnMpID8gbGF5ZXJzIDogW2xheWVyc10pIDogW107XG5cblx0XHRmb3IgKHZhciBpID0gMCwgbGVuID0gbGF5ZXJzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHR0aGlzLmFkZExheWVyKGxheWVyc1tpXSk7XG5cdFx0fVxuXHR9LFxuXG5cdF9hZGRab29tTGltaXQ6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdGlmIChpc05hTihsYXllci5vcHRpb25zLm1heFpvb20pIHx8ICFpc05hTihsYXllci5vcHRpb25zLm1pblpvb20pKSB7XG5cdFx0XHR0aGlzLl96b29tQm91bmRMYXllcnNbTC5zdGFtcChsYXllcildID0gbGF5ZXI7XG5cdFx0XHR0aGlzLl91cGRhdGVab29tTGV2ZWxzKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZW1vdmVab29tTGltaXQ6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBpZCA9IEwuc3RhbXAobGF5ZXIpO1xuXG5cdFx0aWYgKHRoaXMuX3pvb21Cb3VuZExheWVyc1tpZF0pIHtcblx0XHRcdGRlbGV0ZSB0aGlzLl96b29tQm91bmRMYXllcnNbaWRdO1xuXHRcdFx0dGhpcy5fdXBkYXRlWm9vbUxldmVscygpO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlWm9vbUxldmVsczogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBtaW5ab29tID0gSW5maW5pdHksXG5cdFx0ICAgIG1heFpvb20gPSAtSW5maW5pdHksXG5cdFx0ICAgIG9sZFpvb21TcGFuID0gdGhpcy5fZ2V0Wm9vbVNwYW4oKTtcblxuXHRcdGZvciAodmFyIGkgaW4gdGhpcy5fem9vbUJvdW5kTGF5ZXJzKSB7XG5cdFx0XHR2YXIgb3B0aW9ucyA9IHRoaXMuX3pvb21Cb3VuZExheWVyc1tpXS5vcHRpb25zO1xuXG5cdFx0XHRtaW5ab29tID0gb3B0aW9ucy5taW5ab29tID09PSB1bmRlZmluZWQgPyBtaW5ab29tIDogTWF0aC5taW4obWluWm9vbSwgb3B0aW9ucy5taW5ab29tKTtcblx0XHRcdG1heFpvb20gPSBvcHRpb25zLm1heFpvb20gPT09IHVuZGVmaW5lZCA/IG1heFpvb20gOiBNYXRoLm1heChtYXhab29tLCBvcHRpb25zLm1heFpvb20pO1xuXHRcdH1cblxuXHRcdHRoaXMuX2xheWVyc01heFpvb20gPSBtYXhab29tID09PSAtSW5maW5pdHkgPyB1bmRlZmluZWQgOiBtYXhab29tO1xuXHRcdHRoaXMuX2xheWVyc01pblpvb20gPSBtaW5ab29tID09PSBJbmZpbml0eSA/IHVuZGVmaW5lZCA6IG1pblpvb207XG5cblx0XHQvLyBAc2VjdGlvbiBNYXAgc3RhdGUgY2hhbmdlIGV2ZW50c1xuXHRcdC8vIEBldmVudCB6b29tbGV2ZWxzY2hhbmdlOiBFdmVudFxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIG51bWJlciBvZiB6b29tbGV2ZWxzIG9uIHRoZSBtYXAgaXMgY2hhbmdlZCBkdWVcblx0XHQvLyB0byBhZGRpbmcgb3IgcmVtb3ZpbmcgYSBsYXllci5cblx0XHRpZiAob2xkWm9vbVNwYW4gIT09IHRoaXMuX2dldFpvb21TcGFuKCkpIHtcblx0XHRcdHRoaXMuZmlyZSgnem9vbWxldmVsc2NoYW5nZScpO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLm9wdGlvbnMubWF4Wm9vbSA9PT0gdW5kZWZpbmVkICYmIHRoaXMuX2xheWVyc01heFpvb20gJiYgdGhpcy5nZXRab29tKCkgPiB0aGlzLl9sYXllcnNNYXhab29tKSB7XG5cdFx0XHR0aGlzLnNldFpvb20odGhpcy5fbGF5ZXJzTWF4Wm9vbSk7XG5cdFx0fVxuXHRcdGlmICh0aGlzLm9wdGlvbnMubWluWm9vbSA9PT0gdW5kZWZpbmVkICYmIHRoaXMuX2xheWVyc01pblpvb20gJiYgdGhpcy5nZXRab29tKCkgPCB0aGlzLl9sYXllcnNNaW5ab29tKSB7XG5cdFx0XHR0aGlzLnNldFpvb20odGhpcy5fbGF5ZXJzTWluWm9vbSk7XG5cdFx0fVxuXHR9XG59KTtcblxuXG5cbi8qXHJcbiAqIEBuYW1lc3BhY2UgRG9tRXZlbnRcclxuICogVXRpbGl0eSBmdW5jdGlvbnMgdG8gd29yayB3aXRoIHRoZSBbRE9NIGV2ZW50c10oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvQVBJL0V2ZW50KSwgdXNlZCBieSBMZWFmbGV0IGludGVybmFsbHkuXHJcbiAqL1xyXG5cclxuLy8gSW5zcGlyZWQgYnkgSm9obiBSZXNpZywgRGVhbiBFZHdhcmRzIGFuZCBZVUkgYWRkRXZlbnQgaW1wbGVtZW50YXRpb25zLlxyXG5cclxuXHJcblxyXG52YXIgZXZlbnRzS2V5ID0gJ19sZWFmbGV0X2V2ZW50cyc7XHJcblxyXG5MLkRvbUV2ZW50ID0ge1xyXG5cclxuXHQvLyBAZnVuY3Rpb24gb24oZWw6IEhUTUxFbGVtZW50LCB0eXBlczogU3RyaW5nLCBmbjogRnVuY3Rpb24sIGNvbnRleHQ/OiBPYmplY3QpOiB0aGlzXHJcblx0Ly8gQWRkcyBhIGxpc3RlbmVyIGZ1bmN0aW9uIChgZm5gKSB0byBhIHBhcnRpY3VsYXIgRE9NIGV2ZW50IHR5cGUgb2YgdGhlXHJcblx0Ly8gZWxlbWVudCBgZWxgLiBZb3UgY2FuIG9wdGlvbmFsbHkgc3BlY2lmeSB0aGUgY29udGV4dCBvZiB0aGUgbGlzdGVuZXJcclxuXHQvLyAob2JqZWN0IHRoZSBgdGhpc2Aga2V5d29yZCB3aWxsIHBvaW50IHRvKS4gWW91IGNhbiBhbHNvIHBhc3Mgc2V2ZXJhbFxyXG5cdC8vIHNwYWNlLXNlcGFyYXRlZCB0eXBlcyAoZS5nLiBgJ2NsaWNrIGRibGNsaWNrJ2ApLlxyXG5cclxuXHQvLyBAYWx0ZXJuYXRpdmVcclxuXHQvLyBAZnVuY3Rpb24gb24oZWw6IEhUTUxFbGVtZW50LCBldmVudE1hcDogT2JqZWN0LCBjb250ZXh0PzogT2JqZWN0KTogdGhpc1xyXG5cdC8vIEFkZHMgYSBzZXQgb2YgdHlwZS9saXN0ZW5lciBwYWlycywgZS5nLiBge2NsaWNrOiBvbkNsaWNrLCBtb3VzZW1vdmU6IG9uTW91c2VNb3ZlfWBcclxuXHRvbjogZnVuY3Rpb24gKG9iaiwgdHlwZXMsIGZuLCBjb250ZXh0KSB7XHJcblxyXG5cdFx0aWYgKHR5cGVvZiB0eXBlcyA9PT0gJ29iamVjdCcpIHtcclxuXHRcdFx0Zm9yICh2YXIgdHlwZSBpbiB0eXBlcykge1xyXG5cdFx0XHRcdHRoaXMuX29uKG9iaiwgdHlwZSwgdHlwZXNbdHlwZV0sIGZuKTtcclxuXHRcdFx0fVxyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0dHlwZXMgPSBMLlV0aWwuc3BsaXRXb3Jkcyh0eXBlcyk7XHJcblxyXG5cdFx0XHRmb3IgKHZhciBpID0gMCwgbGVuID0gdHlwZXMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0XHR0aGlzLl9vbihvYmosIHR5cGVzW2ldLCBmbiwgY29udGV4dCk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gb2ZmKGVsOiBIVE1MRWxlbWVudCwgdHlwZXM6IFN0cmluZywgZm46IEZ1bmN0aW9uLCBjb250ZXh0PzogT2JqZWN0KTogdGhpc1xyXG5cdC8vIFJlbW92ZXMgYSBwcmV2aW91c2x5IGFkZGVkIGxpc3RlbmVyIGZ1bmN0aW9uLiBJZiBubyBmdW5jdGlvbiBpcyBzcGVjaWZpZWQsXHJcblx0Ly8gaXQgd2lsbCByZW1vdmUgYWxsIHRoZSBsaXN0ZW5lcnMgb2YgdGhhdCBwYXJ0aWN1bGFyIERPTSBldmVudCBmcm9tIHRoZSBlbGVtZW50LlxyXG5cdC8vIE5vdGUgdGhhdCBpZiB5b3UgcGFzc2VkIGEgY3VzdG9tIGNvbnRleHQgdG8gb24sIHlvdSBtdXN0IHBhc3MgdGhlIHNhbWVcclxuXHQvLyBjb250ZXh0IHRvIGBvZmZgIGluIG9yZGVyIHRvIHJlbW92ZSB0aGUgbGlzdGVuZXIuXHJcblxyXG5cdC8vIEBhbHRlcm5hdGl2ZVxyXG5cdC8vIEBmdW5jdGlvbiBvZmYoZWw6IEhUTUxFbGVtZW50LCBldmVudE1hcDogT2JqZWN0LCBjb250ZXh0PzogT2JqZWN0KTogdGhpc1xyXG5cdC8vIFJlbW92ZXMgYSBzZXQgb2YgdHlwZS9saXN0ZW5lciBwYWlycywgZS5nLiBge2NsaWNrOiBvbkNsaWNrLCBtb3VzZW1vdmU6IG9uTW91c2VNb3ZlfWBcclxuXHRvZmY6IGZ1bmN0aW9uIChvYmosIHR5cGVzLCBmbiwgY29udGV4dCkge1xyXG5cclxuXHRcdGlmICh0eXBlb2YgdHlwZXMgPT09ICdvYmplY3QnKSB7XHJcblx0XHRcdGZvciAodmFyIHR5cGUgaW4gdHlwZXMpIHtcclxuXHRcdFx0XHR0aGlzLl9vZmYob2JqLCB0eXBlLCB0eXBlc1t0eXBlXSwgZm4pO1xyXG5cdFx0XHR9XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHR0eXBlcyA9IEwuVXRpbC5zcGxpdFdvcmRzKHR5cGVzKTtcclxuXHJcblx0XHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSB0eXBlcy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0XHRcdHRoaXMuX29mZihvYmosIHR5cGVzW2ldLCBmbiwgY29udGV4dCk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfb246IGZ1bmN0aW9uIChvYmosIHR5cGUsIGZuLCBjb250ZXh0KSB7XHJcblx0XHR2YXIgaWQgPSB0eXBlICsgTC5zdGFtcChmbikgKyAoY29udGV4dCA/ICdfJyArIEwuc3RhbXAoY29udGV4dCkgOiAnJyk7XHJcblxyXG5cdFx0aWYgKG9ialtldmVudHNLZXldICYmIG9ialtldmVudHNLZXldW2lkXSkgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdHZhciBoYW5kbGVyID0gZnVuY3Rpb24gKGUpIHtcclxuXHRcdFx0cmV0dXJuIGZuLmNhbGwoY29udGV4dCB8fCBvYmosIGUgfHwgd2luZG93LmV2ZW50KTtcclxuXHRcdH07XHJcblxyXG5cdFx0dmFyIG9yaWdpbmFsSGFuZGxlciA9IGhhbmRsZXI7XHJcblxyXG5cdFx0aWYgKEwuQnJvd3Nlci5wb2ludGVyICYmIHR5cGUuaW5kZXhPZigndG91Y2gnKSA9PT0gMCkge1xyXG5cdFx0XHR0aGlzLmFkZFBvaW50ZXJMaXN0ZW5lcihvYmosIHR5cGUsIGhhbmRsZXIsIGlkKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKEwuQnJvd3Nlci50b3VjaCAmJiAodHlwZSA9PT0gJ2RibGNsaWNrJykgJiYgdGhpcy5hZGREb3VibGVUYXBMaXN0ZW5lcikge1xyXG5cdFx0XHR0aGlzLmFkZERvdWJsZVRhcExpc3RlbmVyKG9iaiwgaGFuZGxlciwgaWQpO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoJ2FkZEV2ZW50TGlzdGVuZXInIGluIG9iaikge1xyXG5cclxuXHRcdFx0aWYgKHR5cGUgPT09ICdtb3VzZXdoZWVsJykge1xyXG5cdFx0XHRcdG9iai5hZGRFdmVudExpc3RlbmVyKCdvbndoZWVsJyBpbiBvYmogPyAnd2hlZWwnIDogJ21vdXNld2hlZWwnLCBoYW5kbGVyLCBmYWxzZSk7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCh0eXBlID09PSAnbW91c2VlbnRlcicpIHx8ICh0eXBlID09PSAnbW91c2VsZWF2ZScpKSB7XHJcblx0XHRcdFx0aGFuZGxlciA9IGZ1bmN0aW9uIChlKSB7XHJcblx0XHRcdFx0XHRlID0gZSB8fCB3aW5kb3cuZXZlbnQ7XHJcblx0XHRcdFx0XHRpZiAoTC5Eb21FdmVudC5faXNFeHRlcm5hbFRhcmdldChvYmosIGUpKSB7XHJcblx0XHRcdFx0XHRcdG9yaWdpbmFsSGFuZGxlcihlKTtcclxuXHRcdFx0XHRcdH1cclxuXHRcdFx0XHR9O1xyXG5cdFx0XHRcdG9iai5hZGRFdmVudExpc3RlbmVyKHR5cGUgPT09ICdtb3VzZWVudGVyJyA/ICdtb3VzZW92ZXInIDogJ21vdXNlb3V0JywgaGFuZGxlciwgZmFsc2UpO1xyXG5cclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRpZiAodHlwZSA9PT0gJ2NsaWNrJyAmJiBMLkJyb3dzZXIuYW5kcm9pZCkge1xyXG5cdFx0XHRcdFx0aGFuZGxlciA9IGZ1bmN0aW9uIChlKSB7XHJcblx0XHRcdFx0XHRcdHJldHVybiBMLkRvbUV2ZW50Ll9maWx0ZXJDbGljayhlLCBvcmlnaW5hbEhhbmRsZXIpO1xyXG5cdFx0XHRcdFx0fTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0b2JqLmFkZEV2ZW50TGlzdGVuZXIodHlwZSwgaGFuZGxlciwgZmFsc2UpO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0fSBlbHNlIGlmICgnYXR0YWNoRXZlbnQnIGluIG9iaikge1xyXG5cdFx0XHRvYmouYXR0YWNoRXZlbnQoJ29uJyArIHR5cGUsIGhhbmRsZXIpO1xyXG5cdFx0fVxyXG5cclxuXHRcdG9ialtldmVudHNLZXldID0gb2JqW2V2ZW50c0tleV0gfHwge307XHJcblx0XHRvYmpbZXZlbnRzS2V5XVtpZF0gPSBoYW5kbGVyO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdF9vZmY6IGZ1bmN0aW9uIChvYmosIHR5cGUsIGZuLCBjb250ZXh0KSB7XHJcblxyXG5cdFx0dmFyIGlkID0gdHlwZSArIEwuc3RhbXAoZm4pICsgKGNvbnRleHQgPyAnXycgKyBMLnN0YW1wKGNvbnRleHQpIDogJycpLFxyXG5cdFx0ICAgIGhhbmRsZXIgPSBvYmpbZXZlbnRzS2V5XSAmJiBvYmpbZXZlbnRzS2V5XVtpZF07XHJcblxyXG5cdFx0aWYgKCFoYW5kbGVyKSB7IHJldHVybiB0aGlzOyB9XHJcblxyXG5cdFx0aWYgKEwuQnJvd3Nlci5wb2ludGVyICYmIHR5cGUuaW5kZXhPZigndG91Y2gnKSA9PT0gMCkge1xyXG5cdFx0XHR0aGlzLnJlbW92ZVBvaW50ZXJMaXN0ZW5lcihvYmosIHR5cGUsIGlkKTtcclxuXHJcblx0XHR9IGVsc2UgaWYgKEwuQnJvd3Nlci50b3VjaCAmJiAodHlwZSA9PT0gJ2RibGNsaWNrJykgJiYgdGhpcy5yZW1vdmVEb3VibGVUYXBMaXN0ZW5lcikge1xyXG5cdFx0XHR0aGlzLnJlbW92ZURvdWJsZVRhcExpc3RlbmVyKG9iaiwgaWQpO1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoJ3JlbW92ZUV2ZW50TGlzdGVuZXInIGluIG9iaikge1xyXG5cclxuXHRcdFx0aWYgKHR5cGUgPT09ICdtb3VzZXdoZWVsJykge1xyXG5cdFx0XHRcdG9iai5yZW1vdmVFdmVudExpc3RlbmVyKCdvbndoZWVsJyBpbiBvYmogPyAnd2hlZWwnIDogJ21vdXNld2hlZWwnLCBoYW5kbGVyLCBmYWxzZSk7XHJcblxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdG9iai5yZW1vdmVFdmVudExpc3RlbmVyKFxyXG5cdFx0XHRcdFx0dHlwZSA9PT0gJ21vdXNlZW50ZXInID8gJ21vdXNlb3ZlcicgOlxyXG5cdFx0XHRcdFx0dHlwZSA9PT0gJ21vdXNlbGVhdmUnID8gJ21vdXNlb3V0JyA6IHR5cGUsIGhhbmRsZXIsIGZhbHNlKTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdH0gZWxzZSBpZiAoJ2RldGFjaEV2ZW50JyBpbiBvYmopIHtcclxuXHRcdFx0b2JqLmRldGFjaEV2ZW50KCdvbicgKyB0eXBlLCBoYW5kbGVyKTtcclxuXHRcdH1cclxuXHJcblx0XHRvYmpbZXZlbnRzS2V5XVtpZF0gPSBudWxsO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBzdG9wUHJvcGFnYXRpb24oZXY6IERPTUV2ZW50KTogdGhpc1xyXG5cdC8vIFN0b3AgdGhlIGdpdmVuIGV2ZW50IGZyb20gcHJvcGFnYXRpb24gdG8gcGFyZW50IGVsZW1lbnRzLiBVc2VkIGluc2lkZSB0aGUgbGlzdGVuZXIgZnVuY3Rpb25zOlxyXG5cdC8vIGBgYGpzXHJcblx0Ly8gTC5Eb21FdmVudC5vbihkaXYsICdjbGljaycsIGZ1bmN0aW9uIChldikge1xyXG5cdC8vIFx0TC5Eb21FdmVudC5zdG9wUHJvcGFnYXRpb24oZXYpO1xyXG5cdC8vIH0pO1xyXG5cdC8vIGBgYFxyXG5cdHN0b3BQcm9wYWdhdGlvbjogZnVuY3Rpb24gKGUpIHtcclxuXHJcblx0XHRpZiAoZS5zdG9wUHJvcGFnYXRpb24pIHtcclxuXHRcdFx0ZS5zdG9wUHJvcGFnYXRpb24oKTtcclxuXHRcdH0gZWxzZSBpZiAoZS5vcmlnaW5hbEV2ZW50KSB7ICAvLyBJbiBjYXNlIG9mIExlYWZsZXQgZXZlbnQuXHJcblx0XHRcdGUub3JpZ2luYWxFdmVudC5fc3RvcHBlZCA9IHRydWU7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRlLmNhbmNlbEJ1YmJsZSA9IHRydWU7XHJcblx0XHR9XHJcblx0XHRMLkRvbUV2ZW50Ll9za2lwcGVkKGUpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBkaXNhYmxlU2Nyb2xsUHJvcGFnYXRpb24oZWw6IEhUTUxFbGVtZW50KTogdGhpc1xyXG5cdC8vIEFkZHMgYHN0b3BQcm9wYWdhdGlvbmAgdG8gdGhlIGVsZW1lbnQncyBgJ21vdXNld2hlZWwnYCBldmVudHMgKHBsdXMgYnJvd3NlciB2YXJpYW50cykuXHJcblx0ZGlzYWJsZVNjcm9sbFByb3BhZ2F0aW9uOiBmdW5jdGlvbiAoZWwpIHtcclxuXHRcdHJldHVybiBMLkRvbUV2ZW50Lm9uKGVsLCAnbW91c2V3aGVlbCcsIEwuRG9tRXZlbnQuc3RvcFByb3BhZ2F0aW9uKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAZnVuY3Rpb24gZGlzYWJsZUNsaWNrUHJvcGFnYXRpb24oZWw6IEhUTUxFbGVtZW50KTogdGhpc1xyXG5cdC8vIEFkZHMgYHN0b3BQcm9wYWdhdGlvbmAgdG8gdGhlIGVsZW1lbnQncyBgJ2NsaWNrJ2AsIGAnZG91YmxlY2xpY2snYCxcclxuXHQvLyBgJ21vdXNlZG93bidgIGFuZCBgJ3RvdWNoc3RhcnQnYCBldmVudHMgKHBsdXMgYnJvd3NlciB2YXJpYW50cykuXHJcblx0ZGlzYWJsZUNsaWNrUHJvcGFnYXRpb246IGZ1bmN0aW9uIChlbCkge1xyXG5cdFx0dmFyIHN0b3AgPSBMLkRvbUV2ZW50LnN0b3BQcm9wYWdhdGlvbjtcclxuXHJcblx0XHRMLkRvbUV2ZW50Lm9uKGVsLCBMLkRyYWdnYWJsZS5TVEFSVC5qb2luKCcgJyksIHN0b3ApO1xyXG5cclxuXHRcdHJldHVybiBMLkRvbUV2ZW50Lm9uKGVsLCB7XHJcblx0XHRcdGNsaWNrOiBMLkRvbUV2ZW50Ll9mYWtlU3RvcCxcclxuXHRcdFx0ZGJsY2xpY2s6IHN0b3BcclxuXHRcdH0pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBwcmV2ZW50RGVmYXVsdChldjogRE9NRXZlbnQpOiB0aGlzXHJcblx0Ly8gUHJldmVudHMgdGhlIGRlZmF1bHQgYWN0aW9uIG9mIHRoZSBET00gRXZlbnQgYGV2YCBmcm9tIGhhcHBlbmluZyAoc3VjaCBhc1xyXG5cdC8vIGZvbGxvd2luZyBhIGxpbmsgaW4gdGhlIGhyZWYgb2YgdGhlIGEgZWxlbWVudCwgb3IgZG9pbmcgYSBQT1NUIHJlcXVlc3RcclxuXHQvLyB3aXRoIHBhZ2UgcmVsb2FkIHdoZW4gYSBgPGZvcm0+YCBpcyBzdWJtaXR0ZWQpLlxyXG5cdC8vIFVzZSBpdCBpbnNpZGUgbGlzdGVuZXIgZnVuY3Rpb25zLlxyXG5cdHByZXZlbnREZWZhdWx0OiBmdW5jdGlvbiAoZSkge1xyXG5cclxuXHRcdGlmIChlLnByZXZlbnREZWZhdWx0KSB7XHJcblx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGUucmV0dXJuVmFsdWUgPSBmYWxzZTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBzdG9wKGV2KTogdGhpc1xyXG5cdC8vIERvZXMgYHN0b3BQcm9wYWdhdGlvbmAgYW5kIGBwcmV2ZW50RGVmYXVsdGAgYXQgdGhlIHNhbWUgdGltZS5cclxuXHRzdG9wOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0cmV0dXJuIEwuRG9tRXZlbnRcclxuXHRcdFx0LnByZXZlbnREZWZhdWx0KGUpXHJcblx0XHRcdC5zdG9wUHJvcGFnYXRpb24oZSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIGdldE1vdXNlUG9zaXRpb24oZXY6IERPTUV2ZW50LCBjb250YWluZXI/OiBIVE1MRWxlbWVudCk6IFBvaW50XHJcblx0Ly8gR2V0cyBub3JtYWxpemVkIG1vdXNlIHBvc2l0aW9uIGZyb20gYSBET00gZXZlbnQgcmVsYXRpdmUgdG8gdGhlXHJcblx0Ly8gYGNvbnRhaW5lcmAgb3IgdG8gdGhlIHdob2xlIHBhZ2UgaWYgbm90IHNwZWNpZmllZC5cclxuXHRnZXRNb3VzZVBvc2l0aW9uOiBmdW5jdGlvbiAoZSwgY29udGFpbmVyKSB7XHJcblx0XHRpZiAoIWNvbnRhaW5lcikge1xyXG5cdFx0XHRyZXR1cm4gbmV3IEwuUG9pbnQoZS5jbGllbnRYLCBlLmNsaWVudFkpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciByZWN0ID0gY29udGFpbmVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xyXG5cclxuXHRcdHJldHVybiBuZXcgTC5Qb2ludChcclxuXHRcdFx0ZS5jbGllbnRYIC0gcmVjdC5sZWZ0IC0gY29udGFpbmVyLmNsaWVudExlZnQsXHJcblx0XHRcdGUuY2xpZW50WSAtIHJlY3QudG9wIC0gY29udGFpbmVyLmNsaWVudFRvcCk7XHJcblx0fSxcclxuXHJcblx0Ly8gQ2hyb21lIG9uIFdpbiBzY3JvbGxzIGRvdWJsZSB0aGUgcGl4ZWxzIGFzIGluIG90aGVyIHBsYXRmb3JtcyAoc2VlICM0NTM4KSxcclxuXHQvLyBhbmQgRmlyZWZveCBzY3JvbGxzIGRldmljZSBwaXhlbHMsIG5vdCBDU1MgcGl4ZWxzXHJcblx0X3doZWVsUHhGYWN0b3I6IChMLkJyb3dzZXIud2luICYmIEwuQnJvd3Nlci5jaHJvbWUpID8gMiA6XHJcblx0ICAgICAgICAgICAgICAgIEwuQnJvd3Nlci5nZWNrbyA/IHdpbmRvdy5kZXZpY2VQaXhlbFJhdGlvIDpcclxuXHQgICAgICAgICAgICAgICAgMSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIGdldFdoZWVsRGVsdGEoZXY6IERPTUV2ZW50KTogTnVtYmVyXHJcblx0Ly8gR2V0cyBub3JtYWxpemVkIHdoZWVsIGRlbHRhIGZyb20gYSBtb3VzZXdoZWVsIERPTSBldmVudCwgaW4gdmVydGljYWxcclxuXHQvLyBwaXhlbHMgc2Nyb2xsZWQgKG5lZ2F0aXZlIGlmIHNjcm9sbGluZyBkb3duKS5cclxuXHQvLyBFdmVudHMgZnJvbSBwb2ludGluZyBkZXZpY2VzIHdpdGhvdXQgcHJlY2lzZSBzY3JvbGxpbmcgYXJlIG1hcHBlZCB0b1xyXG5cdC8vIGEgYmVzdCBndWVzcyBvZiA2MCBwaXhlbHMuXHJcblx0Z2V0V2hlZWxEZWx0YTogZnVuY3Rpb24gKGUpIHtcclxuXHRcdHJldHVybiAoTC5Ccm93c2VyLmVkZ2UpID8gZS53aGVlbERlbHRhWSAvIDIgOiAvLyBEb24ndCB0cnVzdCB3aW5kb3ctZ2VvbWV0cnktYmFzZWQgZGVsdGFcclxuXHRcdCAgICAgICAoZS5kZWx0YVkgJiYgZS5kZWx0YU1vZGUgPT09IDApID8gLWUuZGVsdGFZIC8gTC5Eb21FdmVudC5fd2hlZWxQeEZhY3RvciA6IC8vIFBpeGVsc1xyXG5cdFx0ICAgICAgIChlLmRlbHRhWSAmJiBlLmRlbHRhTW9kZSA9PT0gMSkgPyAtZS5kZWx0YVkgKiAyMCA6IC8vIExpbmVzXHJcblx0XHQgICAgICAgKGUuZGVsdGFZICYmIGUuZGVsdGFNb2RlID09PSAyKSA/IC1lLmRlbHRhWSAqIDYwIDogLy8gUGFnZXNcclxuXHRcdCAgICAgICAoZS5kZWx0YVggfHwgZS5kZWx0YVopID8gMCA6XHQvLyBTa2lwIGhvcml6b250YWwvZGVwdGggd2hlZWwgZXZlbnRzXHJcblx0XHQgICAgICAgZS53aGVlbERlbHRhID8gKGUud2hlZWxEZWx0YVkgfHwgZS53aGVlbERlbHRhKSAvIDIgOiAvLyBMZWdhY3kgSUUgcGl4ZWxzXHJcblx0XHQgICAgICAgKGUuZGV0YWlsICYmIE1hdGguYWJzKGUuZGV0YWlsKSA8IDMyNzY1KSA/IC1lLmRldGFpbCAqIDIwIDogLy8gTGVnYWN5IE1veiBsaW5lc1xyXG5cdFx0ICAgICAgIGUuZGV0YWlsID8gZS5kZXRhaWwgLyAtMzI3NjUgKiA2MCA6IC8vIExlZ2FjeSBNb3ogcGFnZXNcclxuXHRcdCAgICAgICAwO1xyXG5cdH0sXHJcblxyXG5cdF9za2lwRXZlbnRzOiB7fSxcclxuXHJcblx0X2Zha2VTdG9wOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0Ly8gZmFrZXMgc3RvcFByb3BhZ2F0aW9uIGJ5IHNldHRpbmcgYSBzcGVjaWFsIGV2ZW50IGZsYWcsIGNoZWNrZWQvcmVzZXQgd2l0aCBMLkRvbUV2ZW50Ll9za2lwcGVkKGUpXHJcblx0XHRMLkRvbUV2ZW50Ll9za2lwRXZlbnRzW2UudHlwZV0gPSB0cnVlO1xyXG5cdH0sXHJcblxyXG5cdF9za2lwcGVkOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0dmFyIHNraXBwZWQgPSB0aGlzLl9za2lwRXZlbnRzW2UudHlwZV07XHJcblx0XHQvLyByZXNldCB3aGVuIGNoZWNraW5nLCBhcyBpdCdzIG9ubHkgdXNlZCBpbiBtYXAgY29udGFpbmVyIGFuZCBwcm9wYWdhdGVzIG91dHNpZGUgb2YgdGhlIG1hcFxyXG5cdFx0dGhpcy5fc2tpcEV2ZW50c1tlLnR5cGVdID0gZmFsc2U7XHJcblx0XHRyZXR1cm4gc2tpcHBlZDtcclxuXHR9LFxyXG5cclxuXHQvLyBjaGVjayBpZiBlbGVtZW50IHJlYWxseSBsZWZ0L2VudGVyZWQgdGhlIGV2ZW50IHRhcmdldCAoZm9yIG1vdXNlZW50ZXIvbW91c2VsZWF2ZSlcclxuXHRfaXNFeHRlcm5hbFRhcmdldDogZnVuY3Rpb24gKGVsLCBlKSB7XHJcblxyXG5cdFx0dmFyIHJlbGF0ZWQgPSBlLnJlbGF0ZWRUYXJnZXQ7XHJcblxyXG5cdFx0aWYgKCFyZWxhdGVkKSB7IHJldHVybiB0cnVlOyB9XHJcblxyXG5cdFx0dHJ5IHtcclxuXHRcdFx0d2hpbGUgKHJlbGF0ZWQgJiYgKHJlbGF0ZWQgIT09IGVsKSkge1xyXG5cdFx0XHRcdHJlbGF0ZWQgPSByZWxhdGVkLnBhcmVudE5vZGU7XHJcblx0XHRcdH1cclxuXHRcdH0gY2F0Y2ggKGVycikge1xyXG5cdFx0XHRyZXR1cm4gZmFsc2U7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gKHJlbGF0ZWQgIT09IGVsKTtcclxuXHR9LFxyXG5cclxuXHQvLyB0aGlzIGlzIGEgaG9ycmlibGUgd29ya2Fyb3VuZCBmb3IgYSBidWcgaW4gQW5kcm9pZCB3aGVyZSBhIHNpbmdsZSB0b3VjaCB0cmlnZ2VycyB0d28gY2xpY2sgZXZlbnRzXHJcblx0X2ZpbHRlckNsaWNrOiBmdW5jdGlvbiAoZSwgaGFuZGxlcikge1xyXG5cdFx0dmFyIHRpbWVTdGFtcCA9IChlLnRpbWVTdGFtcCB8fCAoZS5vcmlnaW5hbEV2ZW50ICYmIGUub3JpZ2luYWxFdmVudC50aW1lU3RhbXApKSxcclxuXHRcdCAgICBlbGFwc2VkID0gTC5Eb21FdmVudC5fbGFzdENsaWNrICYmICh0aW1lU3RhbXAgLSBMLkRvbUV2ZW50Ll9sYXN0Q2xpY2spO1xyXG5cclxuXHRcdC8vIGFyZSB0aGV5IGNsb3NlciB0b2dldGhlciB0aGFuIDUwMG1zIHlldCBtb3JlIHRoYW4gMTAwbXM/XHJcblx0XHQvLyBBbmRyb2lkIHR5cGljYWxseSB0cmlnZ2VycyB0aGVtIH4zMDBtcyBhcGFydCB3aGlsZSBtdWx0aXBsZSBsaXN0ZW5lcnNcclxuXHRcdC8vIG9uIHRoZSBzYW1lIGV2ZW50IHNob3VsZCBiZSB0cmlnZ2VyZWQgZmFyIGZhc3RlcjtcclxuXHRcdC8vIG9yIGNoZWNrIGlmIGNsaWNrIGlzIHNpbXVsYXRlZCBvbiB0aGUgZWxlbWVudCwgYW5kIGlmIGl0IGlzLCByZWplY3QgYW55IG5vbi1zaW11bGF0ZWQgZXZlbnRzXHJcblxyXG5cdFx0aWYgKChlbGFwc2VkICYmIGVsYXBzZWQgPiAxMDAgJiYgZWxhcHNlZCA8IDUwMCkgfHwgKGUudGFyZ2V0Ll9zaW11bGF0ZWRDbGljayAmJiAhZS5fc2ltdWxhdGVkKSkge1xyXG5cdFx0XHRMLkRvbUV2ZW50LnN0b3AoZSk7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHRcdEwuRG9tRXZlbnQuX2xhc3RDbGljayA9IHRpbWVTdGFtcDtcclxuXHJcblx0XHRoYW5kbGVyKGUpO1xyXG5cdH1cclxufTtcclxuXHJcbi8vIEBmdW5jdGlvbiBhZGRMaXN0ZW5lcijigKYpOiB0aGlzXHJcbi8vIEFsaWFzIHRvIFtgTC5Eb21FdmVudC5vbmBdKCNkb21ldmVudC1vbilcclxuTC5Eb21FdmVudC5hZGRMaXN0ZW5lciA9IEwuRG9tRXZlbnQub247XHJcblxyXG4vLyBAZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXIo4oCmKTogdGhpc1xyXG4vLyBBbGlhcyB0byBbYEwuRG9tRXZlbnQub2ZmYF0oI2RvbWV2ZW50LW9mZilcclxuTC5Eb21FdmVudC5yZW1vdmVMaXN0ZW5lciA9IEwuRG9tRXZlbnQub2ZmO1xyXG5cblxuXG4vKlxuICogQGNsYXNzIFBvc0FuaW1hdGlvblxuICogQGFrYSBMLlBvc0FuaW1hdGlvblxuICogQGluaGVyaXRzIEV2ZW50ZWRcbiAqIFVzZWQgaW50ZXJuYWxseSBmb3IgcGFubmluZyBhbmltYXRpb25zLCB1dGlsaXppbmcgQ1NTMyBUcmFuc2l0aW9ucyBmb3IgbW9kZXJuIGJyb3dzZXJzIGFuZCBhIHRpbWVyIGZhbGxiYWNrIGZvciBJRTYtOS5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBganNcbiAqIHZhciBmeCA9IG5ldyBMLlBvc0FuaW1hdGlvbigpO1xuICogZngucnVuKGVsLCBbMzAwLCA1MDBdLCAwLjUpO1xuICogYGBgXG4gKlxuICogQGNvbnN0cnVjdG9yIEwuUG9zQW5pbWF0aW9uKClcbiAqIENyZWF0ZXMgYSBgUG9zQW5pbWF0aW9uYCBvYmplY3QuXG4gKlxuICovXG5cbkwuUG9zQW5pbWF0aW9uID0gTC5FdmVudGVkLmV4dGVuZCh7XG5cblx0Ly8gQG1ldGhvZCBydW4oZWw6IEhUTUxFbGVtZW50LCBuZXdQb3M6IFBvaW50LCBkdXJhdGlvbj86IE51bWJlciwgZWFzZUxpbmVhcml0eT86IE51bWJlcilcblx0Ly8gUnVuIGFuIGFuaW1hdGlvbiBvZiBhIGdpdmVuIGVsZW1lbnQgdG8gYSBuZXcgcG9zaXRpb24sIG9wdGlvbmFsbHkgc2V0dGluZ1xuXHQvLyBkdXJhdGlvbiBpbiBzZWNvbmRzIChgMC4yNWAgYnkgZGVmYXVsdCkgYW5kIGVhc2luZyBsaW5lYXJpdHkgZmFjdG9yICgzcmRcblx0Ly8gYXJndW1lbnQgb2YgdGhlIFtjdWJpYyBiZXppZXIgY3VydmVdKGh0dHA6Ly9jdWJpYy1iZXppZXIuY29tLyMwLDAsLjUsMSksXG5cdC8vIGAwLjVgIGJ5IGRlZmF1bHQpLlxuXHRydW46IGZ1bmN0aW9uIChlbCwgbmV3UG9zLCBkdXJhdGlvbiwgZWFzZUxpbmVhcml0eSkge1xuXHRcdHRoaXMuc3RvcCgpO1xuXG5cdFx0dGhpcy5fZWwgPSBlbDtcblx0XHR0aGlzLl9pblByb2dyZXNzID0gdHJ1ZTtcblx0XHR0aGlzLl9kdXJhdGlvbiA9IGR1cmF0aW9uIHx8IDAuMjU7XG5cdFx0dGhpcy5fZWFzZU91dFBvd2VyID0gMSAvIE1hdGgubWF4KGVhc2VMaW5lYXJpdHkgfHwgMC41LCAwLjIpO1xuXG5cdFx0dGhpcy5fc3RhcnRQb3MgPSBMLkRvbVV0aWwuZ2V0UG9zaXRpb24oZWwpO1xuXHRcdHRoaXMuX29mZnNldCA9IG5ld1Bvcy5zdWJ0cmFjdCh0aGlzLl9zdGFydFBvcyk7XG5cdFx0dGhpcy5fc3RhcnRUaW1lID0gK25ldyBEYXRlKCk7XG5cblx0XHQvLyBAZXZlbnQgc3RhcnQ6IEV2ZW50XG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgYW5pbWF0aW9uIHN0YXJ0c1xuXHRcdHRoaXMuZmlyZSgnc3RhcnQnKTtcblxuXHRcdHRoaXMuX2FuaW1hdGUoKTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIHN0b3AoKVxuXHQvLyBTdG9wcyB0aGUgYW5pbWF0aW9uIChpZiBjdXJyZW50bHkgcnVubmluZykuXG5cdHN0b3A6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAoIXRoaXMuX2luUHJvZ3Jlc3MpIHsgcmV0dXJuOyB9XG5cblx0XHR0aGlzLl9zdGVwKHRydWUpO1xuXHRcdHRoaXMuX2NvbXBsZXRlKCk7XG5cdH0sXG5cblx0X2FuaW1hdGU6IGZ1bmN0aW9uICgpIHtcblx0XHQvLyBhbmltYXRpb24gbG9vcFxuXHRcdHRoaXMuX2FuaW1JZCA9IEwuVXRpbC5yZXF1ZXN0QW5pbUZyYW1lKHRoaXMuX2FuaW1hdGUsIHRoaXMpO1xuXHRcdHRoaXMuX3N0ZXAoKTtcblx0fSxcblxuXHRfc3RlcDogZnVuY3Rpb24gKHJvdW5kKSB7XG5cdFx0dmFyIGVsYXBzZWQgPSAoK25ldyBEYXRlKCkpIC0gdGhpcy5fc3RhcnRUaW1lLFxuXHRcdCAgICBkdXJhdGlvbiA9IHRoaXMuX2R1cmF0aW9uICogMTAwMDtcblxuXHRcdGlmIChlbGFwc2VkIDwgZHVyYXRpb24pIHtcblx0XHRcdHRoaXMuX3J1bkZyYW1lKHRoaXMuX2Vhc2VPdXQoZWxhcHNlZCAvIGR1cmF0aW9uKSwgcm91bmQpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9ydW5GcmFtZSgxKTtcblx0XHRcdHRoaXMuX2NvbXBsZXRlKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9ydW5GcmFtZTogZnVuY3Rpb24gKHByb2dyZXNzLCByb3VuZCkge1xuXHRcdHZhciBwb3MgPSB0aGlzLl9zdGFydFBvcy5hZGQodGhpcy5fb2Zmc2V0Lm11bHRpcGx5QnkocHJvZ3Jlc3MpKTtcblx0XHRpZiAocm91bmQpIHtcblx0XHRcdHBvcy5fcm91bmQoKTtcblx0XHR9XG5cdFx0TC5Eb21VdGlsLnNldFBvc2l0aW9uKHRoaXMuX2VsLCBwb3MpO1xuXG5cdFx0Ly8gQGV2ZW50IHN0ZXA6IEV2ZW50XG5cdFx0Ly8gRmlyZWQgY29udGludW91c2x5IGR1cmluZyB0aGUgYW5pbWF0aW9uLlxuXHRcdHRoaXMuZmlyZSgnc3RlcCcpO1xuXHR9LFxuXG5cdF9jb21wbGV0ZTogZnVuY3Rpb24gKCkge1xuXHRcdEwuVXRpbC5jYW5jZWxBbmltRnJhbWUodGhpcy5fYW5pbUlkKTtcblxuXHRcdHRoaXMuX2luUHJvZ3Jlc3MgPSBmYWxzZTtcblx0XHQvLyBAZXZlbnQgZW5kOiBFdmVudFxuXHRcdC8vIEZpcmVkIHdoZW4gdGhlIGFuaW1hdGlvbiBlbmRzLlxuXHRcdHRoaXMuZmlyZSgnZW5kJyk7XG5cdH0sXG5cblx0X2Vhc2VPdXQ6IGZ1bmN0aW9uICh0KSB7XG5cdFx0cmV0dXJuIDEgLSBNYXRoLnBvdygxIC0gdCwgdGhpcy5fZWFzZU91dFBvd2VyKTtcblx0fVxufSk7XG5cblxuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIFByb2plY3Rpb25cclxuICogQHByb2plY3Rpb24gTC5Qcm9qZWN0aW9uLk1lcmNhdG9yXHJcbiAqXHJcbiAqIEVsbGlwdGljYWwgTWVyY2F0b3IgcHJvamVjdGlvbiDigJQgbW9yZSBjb21wbGV4IHRoYW4gU3BoZXJpY2FsIE1lcmNhdG9yLiBUYWtlcyBpbnRvIGFjY291bnQgdGhhdCBFYXJ0aCBpcyBhIGdlb2lkLCBub3QgYSBwZXJmZWN0IHNwaGVyZS4gVXNlZCBieSB0aGUgRVBTRzozMzk1IENSUy5cclxuICovXHJcblxyXG5MLlByb2plY3Rpb24uTWVyY2F0b3IgPSB7XHJcblx0UjogNjM3ODEzNyxcclxuXHRSX01JTk9SOiA2MzU2NzUyLjMxNDI0NTE3OSxcclxuXHJcblx0Ym91bmRzOiBMLmJvdW5kcyhbLTIwMDM3NTA4LjM0Mjc5LCAtMTU0OTY1NzAuNzM5NzJdLCBbMjAwMzc1MDguMzQyNzksIDE4NzY0NjU2LjIzMTM4XSksXHJcblxyXG5cdHByb2plY3Q6IGZ1bmN0aW9uIChsYXRsbmcpIHtcclxuXHRcdHZhciBkID0gTWF0aC5QSSAvIDE4MCxcclxuXHRcdCAgICByID0gdGhpcy5SLFxyXG5cdFx0ICAgIHkgPSBsYXRsbmcubGF0ICogZCxcclxuXHRcdCAgICB0bXAgPSB0aGlzLlJfTUlOT1IgLyByLFxyXG5cdFx0ICAgIGUgPSBNYXRoLnNxcnQoMSAtIHRtcCAqIHRtcCksXHJcblx0XHQgICAgY29uID0gZSAqIE1hdGguc2luKHkpO1xyXG5cclxuXHRcdHZhciB0cyA9IE1hdGgudGFuKE1hdGguUEkgLyA0IC0geSAvIDIpIC8gTWF0aC5wb3coKDEgLSBjb24pIC8gKDEgKyBjb24pLCBlIC8gMik7XHJcblx0XHR5ID0gLXIgKiBNYXRoLmxvZyhNYXRoLm1heCh0cywgMUUtMTApKTtcclxuXHJcblx0XHRyZXR1cm4gbmV3IEwuUG9pbnQobGF0bG5nLmxuZyAqIGQgKiByLCB5KTtcclxuXHR9LFxyXG5cclxuXHR1bnByb2plY3Q6IGZ1bmN0aW9uIChwb2ludCkge1xyXG5cdFx0dmFyIGQgPSAxODAgLyBNYXRoLlBJLFxyXG5cdFx0ICAgIHIgPSB0aGlzLlIsXHJcblx0XHQgICAgdG1wID0gdGhpcy5SX01JTk9SIC8gcixcclxuXHRcdCAgICBlID0gTWF0aC5zcXJ0KDEgLSB0bXAgKiB0bXApLFxyXG5cdFx0ICAgIHRzID0gTWF0aC5leHAoLXBvaW50LnkgLyByKSxcclxuXHRcdCAgICBwaGkgPSBNYXRoLlBJIC8gMiAtIDIgKiBNYXRoLmF0YW4odHMpO1xyXG5cclxuXHRcdGZvciAodmFyIGkgPSAwLCBkcGhpID0gMC4xLCBjb247IGkgPCAxNSAmJiBNYXRoLmFicyhkcGhpKSA+IDFlLTc7IGkrKykge1xyXG5cdFx0XHRjb24gPSBlICogTWF0aC5zaW4ocGhpKTtcclxuXHRcdFx0Y29uID0gTWF0aC5wb3coKDEgLSBjb24pIC8gKDEgKyBjb24pLCBlIC8gMik7XHJcblx0XHRcdGRwaGkgPSBNYXRoLlBJIC8gMiAtIDIgKiBNYXRoLmF0YW4odHMgKiBjb24pIC0gcGhpO1xyXG5cdFx0XHRwaGkgKz0gZHBoaTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gbmV3IEwuTGF0TG5nKHBoaSAqIGQsIHBvaW50LnggKiBkIC8gcik7XHJcblx0fVxyXG59O1xyXG5cblxuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIENSU1xyXG4gKiBAY3JzIEwuQ1JTLkVQU0czMzk1XHJcbiAqXHJcbiAqIFJhcmVseSB1c2VkIGJ5IHNvbWUgY29tbWVyY2lhbCB0aWxlIHByb3ZpZGVycy4gVXNlcyBFbGxpcHRpY2FsIE1lcmNhdG9yIHByb2plY3Rpb24uXHJcbiAqL1xyXG5cclxuTC5DUlMuRVBTRzMzOTUgPSBMLmV4dGVuZCh7fSwgTC5DUlMuRWFydGgsIHtcclxuXHRjb2RlOiAnRVBTRzozMzk1JyxcclxuXHRwcm9qZWN0aW9uOiBMLlByb2plY3Rpb24uTWVyY2F0b3IsXHJcblxyXG5cdHRyYW5zZm9ybWF0aW9uOiAoZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIHNjYWxlID0gMC41IC8gKE1hdGguUEkgKiBMLlByb2plY3Rpb24uTWVyY2F0b3IuUik7XHJcblx0XHRyZXR1cm4gbmV3IEwuVHJhbnNmb3JtYXRpb24oc2NhbGUsIDAuNSwgLXNjYWxlLCAwLjUpO1xyXG5cdH0oKSlcclxufSk7XHJcblxuXG5cbi8qXG4gKiBAY2xhc3MgR3JpZExheWVyXG4gKiBAaW5oZXJpdHMgTGF5ZXJcbiAqIEBha2EgTC5HcmlkTGF5ZXJcbiAqXG4gKiBHZW5lcmljIGNsYXNzIGZvciBoYW5kbGluZyBhIHRpbGVkIGdyaWQgb2YgSFRNTCBlbGVtZW50cy4gVGhpcyBpcyB0aGUgYmFzZSBjbGFzcyBmb3IgYWxsIHRpbGUgbGF5ZXJzIGFuZCByZXBsYWNlcyBgVGlsZUxheWVyLkNhbnZhc2AuXG4gKiBHcmlkTGF5ZXIgY2FuIGJlIGV4dGVuZGVkIHRvIGNyZWF0ZSBhIHRpbGVkIGdyaWQgb2YgSFRNTCBlbGVtZW50cyBsaWtlIGA8Y2FudmFzPmAsIGA8aW1nPmAgb3IgYDxkaXY+YC4gR3JpZExheWVyIHdpbGwgaGFuZGxlIGNyZWF0aW5nIGFuZCBhbmltYXRpbmcgdGhlc2UgRE9NIGVsZW1lbnRzIGZvciB5b3UuXG4gKlxuICpcbiAqIEBzZWN0aW9uIFN5bmNocm9ub3VzIHVzYWdlXG4gKiBAZXhhbXBsZVxuICpcbiAqIFRvIGNyZWF0ZSBhIGN1c3RvbSBsYXllciwgZXh0ZW5kIEdyaWRMYXllciBhbmQgaW1wbGVtZW50IHRoZSBgY3JlYXRlVGlsZSgpYCBtZXRob2QsIHdoaWNoIHdpbGwgYmUgcGFzc2VkIGEgYFBvaW50YCBvYmplY3Qgd2l0aCB0aGUgYHhgLCBgeWAsIGFuZCBgemAgKHpvb20gbGV2ZWwpIGNvb3JkaW5hdGVzIHRvIGRyYXcgeW91ciB0aWxlLlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgQ2FudmFzTGF5ZXIgPSBMLkdyaWRMYXllci5leHRlbmQoe1xuICogICAgIGNyZWF0ZVRpbGU6IGZ1bmN0aW9uKGNvb3Jkcyl7XG4gKiAgICAgICAgIC8vIGNyZWF0ZSBhIDxjYW52YXM+IGVsZW1lbnQgZm9yIGRyYXdpbmdcbiAqICAgICAgICAgdmFyIHRpbGUgPSBMLkRvbVV0aWwuY3JlYXRlKCdjYW52YXMnLCAnbGVhZmxldC10aWxlJyk7XG4gKlxuICogICAgICAgICAvLyBzZXR1cCB0aWxlIHdpZHRoIGFuZCBoZWlnaHQgYWNjb3JkaW5nIHRvIHRoZSBvcHRpb25zXG4gKiAgICAgICAgIHZhciBzaXplID0gdGhpcy5nZXRUaWxlU2l6ZSgpO1xuICogICAgICAgICB0aWxlLndpZHRoID0gc2l6ZS54O1xuICogICAgICAgICB0aWxlLmhlaWdodCA9IHNpemUueTtcbiAqXG4gKiAgICAgICAgIC8vIGdldCBhIGNhbnZhcyBjb250ZXh0IGFuZCBkcmF3IHNvbWV0aGluZyBvbiBpdCB1c2luZyBjb29yZHMueCwgY29vcmRzLnkgYW5kIGNvb3Jkcy56XG4gKiAgICAgICAgIHZhciBjdHggPSB0aWxlLmdldENvbnRleHQoJzJkJyk7XG4gKlxuICogICAgICAgICAvLyByZXR1cm4gdGhlIHRpbGUgc28gaXQgY2FuIGJlIHJlbmRlcmVkIG9uIHNjcmVlblxuICogICAgICAgICByZXR1cm4gdGlsZTtcbiAqICAgICB9XG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqIEBzZWN0aW9uIEFzeW5jaHJvbm91cyB1c2FnZVxuICogQGV4YW1wbGVcbiAqXG4gKiBUaWxlIGNyZWF0aW9uIGNhbiBhbHNvIGJlIGFzeW5jaHJvbm91cywgdGhpcyBpcyB1c2VmdWwgd2hlbiB1c2luZyBhIHRoaXJkLXBhcnR5IGRyYXdpbmcgbGlicmFyeS4gT25jZSB0aGUgdGlsZSBpcyBmaW5pc2hlZCBkcmF3aW5nIGl0IGNhbiBiZSBwYXNzZWQgdG8gdGhlIGBkb25lKClgIGNhbGxiYWNrLlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgQ2FudmFzTGF5ZXIgPSBMLkdyaWRMYXllci5leHRlbmQoe1xuICogICAgIGNyZWF0ZVRpbGU6IGZ1bmN0aW9uKGNvb3JkcywgZG9uZSl7XG4gKiAgICAgICAgIHZhciBlcnJvcjtcbiAqXG4gKiAgICAgICAgIC8vIGNyZWF0ZSBhIDxjYW52YXM+IGVsZW1lbnQgZm9yIGRyYXdpbmdcbiAqICAgICAgICAgdmFyIHRpbGUgPSBMLkRvbVV0aWwuY3JlYXRlKCdjYW52YXMnLCAnbGVhZmxldC10aWxlJyk7XG4gKlxuICogICAgICAgICAvLyBzZXR1cCB0aWxlIHdpZHRoIGFuZCBoZWlnaHQgYWNjb3JkaW5nIHRvIHRoZSBvcHRpb25zXG4gKiAgICAgICAgIHZhciBzaXplID0gdGhpcy5nZXRUaWxlU2l6ZSgpO1xuICogICAgICAgICB0aWxlLndpZHRoID0gc2l6ZS54O1xuICogICAgICAgICB0aWxlLmhlaWdodCA9IHNpemUueTtcbiAqXG4gKiAgICAgICAgIC8vIGRyYXcgc29tZXRoaW5nIGFzeW5jaHJvbm91c2x5IGFuZCBwYXNzIHRoZSB0aWxlIHRvIHRoZSBkb25lKCkgY2FsbGJhY2tcbiAqICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpIHtcbiAqICAgICAgICAgICAgIGRvbmUoZXJyb3IsIHRpbGUpO1xuICogICAgICAgICB9LCAxMDAwKTtcbiAqXG4gKiAgICAgICAgIHJldHVybiB0aWxlO1xuICogICAgIH1cbiAqIH0pO1xuICogYGBgXG4gKlxuICogQHNlY3Rpb25cbiAqL1xuXG5cbkwuR3JpZExheWVyID0gTC5MYXllci5leHRlbmQoe1xuXG5cdC8vIEBzZWN0aW9uXG5cdC8vIEBha2EgR3JpZExheWVyIG9wdGlvbnNcblx0b3B0aW9uczoge1xuXHRcdC8vIEBvcHRpb24gdGlsZVNpemU6IE51bWJlcnxQb2ludCA9IDI1NlxuXHRcdC8vIFdpZHRoIGFuZCBoZWlnaHQgb2YgdGlsZXMgaW4gdGhlIGdyaWQuIFVzZSBhIG51bWJlciBpZiB3aWR0aCBhbmQgaGVpZ2h0IGFyZSBlcXVhbCwgb3IgYEwucG9pbnQod2lkdGgsIGhlaWdodClgIG90aGVyd2lzZS5cblx0XHR0aWxlU2l6ZTogMjU2LFxuXG5cdFx0Ly8gQG9wdGlvbiBvcGFjaXR5OiBOdW1iZXIgPSAxLjBcblx0XHQvLyBPcGFjaXR5IG9mIHRoZSB0aWxlcy4gQ2FuIGJlIHVzZWQgaW4gdGhlIGBjcmVhdGVUaWxlKClgIGZ1bmN0aW9uLlxuXHRcdG9wYWNpdHk6IDEsXG5cblx0XHQvLyBAb3B0aW9uIHVwZGF0ZVdoZW5JZGxlOiBCb29sZWFuID0gZGVwZW5kc1xuXHRcdC8vIElmIGBmYWxzZWAsIG5ldyB0aWxlcyBhcmUgbG9hZGVkIGR1cmluZyBwYW5uaW5nLCBvdGhlcndpc2Ugb25seSBhZnRlciBpdCAoZm9yIGJldHRlciBwZXJmb3JtYW5jZSkuIGB0cnVlYCBieSBkZWZhdWx0IG9uIG1vYmlsZSBicm93c2Vycywgb3RoZXJ3aXNlIGBmYWxzZWAuXG5cdFx0dXBkYXRlV2hlbklkbGU6IEwuQnJvd3Nlci5tb2JpbGUsXG5cblx0XHQvLyBAb3B0aW9uIHVwZGF0ZVdoZW5ab29taW5nOiBCb29sZWFuID0gdHJ1ZVxuXHRcdC8vIEJ5IGRlZmF1bHQsIGEgc21vb3RoIHpvb20gYW5pbWF0aW9uIChkdXJpbmcgYSBbdG91Y2ggem9vbV0oI21hcC10b3VjaHpvb20pIG9yIGEgW2BmbHlUbygpYF0oI21hcC1mbHl0bykpIHdpbGwgdXBkYXRlIGdyaWQgbGF5ZXJzIGV2ZXJ5IGludGVnZXIgem9vbSBsZXZlbC4gU2V0dGluZyB0aGlzIG9wdGlvbiB0byBgZmFsc2VgIHdpbGwgdXBkYXRlIHRoZSBncmlkIGxheWVyIG9ubHkgd2hlbiB0aGUgc21vb3RoIGFuaW1hdGlvbiBlbmRzLlxuXHRcdHVwZGF0ZVdoZW5ab29taW5nOiB0cnVlLFxuXG5cdFx0Ly8gQG9wdGlvbiB1cGRhdGVJbnRlcnZhbDogTnVtYmVyID0gMjAwXG5cdFx0Ly8gVGlsZXMgd2lsbCBub3QgdXBkYXRlIG1vcmUgdGhhbiBvbmNlIGV2ZXJ5IGB1cGRhdGVJbnRlcnZhbGAgbWlsbGlzZWNvbmRzIHdoZW4gcGFubmluZy5cblx0XHR1cGRhdGVJbnRlcnZhbDogMjAwLFxuXG5cdFx0Ly8gQG9wdGlvbiB6SW5kZXg6IE51bWJlciA9IDFcblx0XHQvLyBUaGUgZXhwbGljaXQgekluZGV4IG9mIHRoZSB0aWxlIGxheWVyLlxuXHRcdHpJbmRleDogMSxcblxuXHRcdC8vIEBvcHRpb24gYm91bmRzOiBMYXRMbmdCb3VuZHMgPSB1bmRlZmluZWRcblx0XHQvLyBJZiBzZXQsIHRpbGVzIHdpbGwgb25seSBiZSBsb2FkZWQgaW5zaWRlIHRoZSBzZXQgYExhdExuZ0JvdW5kc2AuXG5cdFx0Ym91bmRzOiBudWxsLFxuXG5cdFx0Ly8gQG9wdGlvbiBtaW5ab29tOiBOdW1iZXIgPSAwXG5cdFx0Ly8gVGhlIG1pbmltdW0gem9vbSBsZXZlbCB0aGF0IHRpbGVzIHdpbGwgYmUgbG9hZGVkIGF0LiBCeSBkZWZhdWx0IHRoZSBlbnRpcmUgbWFwLlxuXHRcdG1pblpvb206IDAsXG5cblx0XHQvLyBAb3B0aW9uIG1heFpvb206IE51bWJlciA9IHVuZGVmaW5lZFxuXHRcdC8vIFRoZSBtYXhpbXVtIHpvb20gbGV2ZWwgdGhhdCB0aWxlcyB3aWxsIGJlIGxvYWRlZCBhdC5cblx0XHRtYXhab29tOiB1bmRlZmluZWQsXG5cblx0XHQvLyBAb3B0aW9uIG5vV3JhcDogQm9vbGVhbiA9IGZhbHNlXG5cdFx0Ly8gV2hldGhlciB0aGUgbGF5ZXIgaXMgd3JhcHBlZCBhcm91bmQgdGhlIGFudGltZXJpZGlhbi4gSWYgYHRydWVgLCB0aGVcblx0XHQvLyBHcmlkTGF5ZXIgd2lsbCBvbmx5IGJlIGRpc3BsYXllZCBvbmNlIGF0IGxvdyB6b29tIGxldmVscy4gSGFzIG5vXG5cdFx0Ly8gZWZmZWN0IHdoZW4gdGhlIFttYXAgQ1JTXSgjbWFwLWNycykgZG9lc24ndCB3cmFwIGFyb3VuZC5cblx0XHRub1dyYXA6IGZhbHNlLFxuXG5cdFx0Ly8gQG9wdGlvbiBwYW5lOiBTdHJpbmcgPSAndGlsZVBhbmUnXG5cdFx0Ly8gYE1hcCBwYW5lYCB3aGVyZSB0aGUgZ3JpZCBsYXllciB3aWxsIGJlIGFkZGVkLlxuXHRcdHBhbmU6ICd0aWxlUGFuZScsXG5cblx0XHQvLyBAb3B0aW9uIGNsYXNzTmFtZTogU3RyaW5nID0gJydcblx0XHQvLyBBIGN1c3RvbSBjbGFzcyBuYW1lIHRvIGFzc2lnbiB0byB0aGUgdGlsZSBsYXllci4gRW1wdHkgYnkgZGVmYXVsdC5cblx0XHRjbGFzc05hbWU6ICcnLFxuXG5cdFx0Ly8gQG9wdGlvbiBrZWVwQnVmZmVyOiBOdW1iZXIgPSAyXG5cdFx0Ly8gV2hlbiBwYW5uaW5nIHRoZSBtYXAsIGtlZXAgdGhpcyBtYW55IHJvd3MgYW5kIGNvbHVtbnMgb2YgdGlsZXMgYmVmb3JlIHVubG9hZGluZyB0aGVtLlxuXHRcdGtlZXBCdWZmZXI6IDJcblx0fSxcblxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuXHRcdEwuc2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcblx0fSxcblxuXHRvbkFkZDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX2luaXRDb250YWluZXIoKTtcblxuXHRcdHRoaXMuX2xldmVscyA9IHt9O1xuXHRcdHRoaXMuX3RpbGVzID0ge307XG5cblx0XHR0aGlzLl9yZXNldFZpZXcoKTtcblx0XHR0aGlzLl91cGRhdGUoKTtcblx0fSxcblxuXHRiZWZvcmVBZGQ6IGZ1bmN0aW9uIChtYXApIHtcblx0XHRtYXAuX2FkZFpvb21MaW1pdCh0aGlzKTtcblx0fSxcblxuXHRvblJlbW92ZTogZnVuY3Rpb24gKG1hcCkge1xuXHRcdHRoaXMuX3JlbW92ZUFsbFRpbGVzKCk7XG5cdFx0TC5Eb21VdGlsLnJlbW92ZSh0aGlzLl9jb250YWluZXIpO1xuXHRcdG1hcC5fcmVtb3ZlWm9vbUxpbWl0KHRoaXMpO1xuXHRcdHRoaXMuX2NvbnRhaW5lciA9IG51bGw7XG5cdFx0dGhpcy5fdGlsZVpvb20gPSBudWxsO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgYnJpbmdUb0Zyb250OiB0aGlzXG5cdC8vIEJyaW5ncyB0aGUgdGlsZSBsYXllciB0byB0aGUgdG9wIG9mIGFsbCB0aWxlIGxheWVycy5cblx0YnJpbmdUb0Zyb250OiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21hcCkge1xuXHRcdFx0TC5Eb21VdGlsLnRvRnJvbnQodGhpcy5fY29udGFpbmVyKTtcblx0XHRcdHRoaXMuX3NldEF1dG9aSW5kZXgoTWF0aC5tYXgpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGJyaW5nVG9CYWNrOiB0aGlzXG5cdC8vIEJyaW5ncyB0aGUgdGlsZSBsYXllciB0byB0aGUgYm90dG9tIG9mIGFsbCB0aWxlIGxheWVycy5cblx0YnJpbmdUb0JhY2s6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fbWFwKSB7XG5cdFx0XHRMLkRvbVV0aWwudG9CYWNrKHRoaXMuX2NvbnRhaW5lcik7XG5cdFx0XHR0aGlzLl9zZXRBdXRvWkluZGV4KE1hdGgubWluKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBnZXRDb250YWluZXI6IEhUTUxFbGVtZW50XG5cdC8vIFJldHVybnMgdGhlIEhUTUwgZWxlbWVudCB0aGF0IGNvbnRhaW5zIHRoZSB0aWxlcyBmb3IgdGhpcyBsYXllci5cblx0Z2V0Q29udGFpbmVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2NvbnRhaW5lcjtcblx0fSxcblxuXHQvLyBAbWV0aG9kIHNldE9wYWNpdHkob3BhY2l0eTogTnVtYmVyKTogdGhpc1xuXHQvLyBDaGFuZ2VzIHRoZSBbb3BhY2l0eV0oI2dyaWRsYXllci1vcGFjaXR5KSBvZiB0aGUgZ3JpZCBsYXllci5cblx0c2V0T3BhY2l0eTogZnVuY3Rpb24gKG9wYWNpdHkpIHtcblx0XHR0aGlzLm9wdGlvbnMub3BhY2l0eSA9IG9wYWNpdHk7XG5cdFx0dGhpcy5fdXBkYXRlT3BhY2l0eSgpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2Qgc2V0WkluZGV4KHpJbmRleDogTnVtYmVyKTogdGhpc1xuXHQvLyBDaGFuZ2VzIHRoZSBbekluZGV4XSgjZ3JpZGxheWVyLXppbmRleCkgb2YgdGhlIGdyaWQgbGF5ZXIuXG5cdHNldFpJbmRleDogZnVuY3Rpb24gKHpJbmRleCkge1xuXHRcdHRoaXMub3B0aW9ucy56SW5kZXggPSB6SW5kZXg7XG5cdFx0dGhpcy5fdXBkYXRlWkluZGV4KCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGlzTG9hZGluZzogQm9vbGVhblxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiBhbnkgdGlsZSBpbiB0aGUgZ3JpZCBsYXllciBoYXMgbm90IGZpbmlzaGVkIGxvYWRpbmcuXG5cdGlzTG9hZGluZzogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLl9sb2FkaW5nO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgcmVkcmF3OiB0aGlzXG5cdC8vIENhdXNlcyB0aGUgbGF5ZXIgdG8gY2xlYXIgYWxsIHRoZSB0aWxlcyBhbmQgcmVxdWVzdCB0aGVtIGFnYWluLlxuXHRyZWRyYXc6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fbWFwKSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVBbGxUaWxlcygpO1xuXHRcdFx0dGhpcy5fdXBkYXRlKCk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdGdldEV2ZW50czogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBldmVudHMgPSB7XG5cdFx0XHR2aWV3cHJlcmVzZXQ6IHRoaXMuX2ludmFsaWRhdGVBbGwsXG5cdFx0XHR2aWV3cmVzZXQ6IHRoaXMuX3Jlc2V0Vmlldyxcblx0XHRcdHpvb206IHRoaXMuX3Jlc2V0Vmlldyxcblx0XHRcdG1vdmVlbmQ6IHRoaXMuX29uTW92ZUVuZFxuXHRcdH07XG5cblx0XHRpZiAoIXRoaXMub3B0aW9ucy51cGRhdGVXaGVuSWRsZSkge1xuXHRcdFx0Ly8gdXBkYXRlIHRpbGVzIG9uIG1vdmUsIGJ1dCBub3QgbW9yZSBvZnRlbiB0aGFuIG9uY2UgcGVyIGdpdmVuIGludGVydmFsXG5cdFx0XHRpZiAoIXRoaXMuX29uTW92ZSkge1xuXHRcdFx0XHR0aGlzLl9vbk1vdmUgPSBMLlV0aWwudGhyb3R0bGUodGhpcy5fb25Nb3ZlRW5kLCB0aGlzLm9wdGlvbnMudXBkYXRlSW50ZXJ2YWwsIHRoaXMpO1xuXHRcdFx0fVxuXG5cdFx0XHRldmVudHMubW92ZSA9IHRoaXMuX29uTW92ZTtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5fem9vbUFuaW1hdGVkKSB7XG5cdFx0XHRldmVudHMuem9vbWFuaW0gPSB0aGlzLl9hbmltYXRlWm9vbTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZXZlbnRzO1xuXHR9LFxuXG5cdC8vIEBzZWN0aW9uIEV4dGVuc2lvbiBtZXRob2RzXG5cdC8vIExheWVycyBleHRlbmRpbmcgYEdyaWRMYXllcmAgc2hhbGwgcmVpbXBsZW1lbnQgdGhlIGZvbGxvd2luZyBtZXRob2QuXG5cdC8vIEBtZXRob2QgY3JlYXRlVGlsZShjb29yZHM6IE9iamVjdCwgZG9uZT86IEZ1bmN0aW9uKTogSFRNTEVsZW1lbnRcblx0Ly8gQ2FsbGVkIG9ubHkgaW50ZXJuYWxseSwgbXVzdCBiZSBvdmVycmlkZW4gYnkgY2xhc3NlcyBleHRlbmRpbmcgYEdyaWRMYXllcmAuXG5cdC8vIFJldHVybnMgdGhlIGBIVE1MRWxlbWVudGAgY29ycmVzcG9uZGluZyB0byB0aGUgZ2l2ZW4gYGNvb3Jkc2AuIElmIHRoZSBgZG9uZWAgY2FsbGJhY2tcblx0Ly8gaXMgc3BlY2lmaWVkLCBpdCBtdXN0IGJlIGNhbGxlZCB3aGVuIHRoZSB0aWxlIGhhcyBmaW5pc2hlZCBsb2FkaW5nIGFuZCBkcmF3aW5nLlxuXHRjcmVhdGVUaWxlOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2RpdicpO1xuXHR9LFxuXG5cdC8vIEBzZWN0aW9uXG5cdC8vIEBtZXRob2QgZ2V0VGlsZVNpemU6IFBvaW50XG5cdC8vIE5vcm1hbGl6ZXMgdGhlIFt0aWxlU2l6ZSBvcHRpb25dKCNncmlkbGF5ZXItdGlsZXNpemUpIGludG8gYSBwb2ludC4gVXNlZCBieSB0aGUgYGNyZWF0ZVRpbGUoKWAgbWV0aG9kLlxuXHRnZXRUaWxlU2l6ZTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBzID0gdGhpcy5vcHRpb25zLnRpbGVTaXplO1xuXHRcdHJldHVybiBzIGluc3RhbmNlb2YgTC5Qb2ludCA/IHMgOiBuZXcgTC5Qb2ludChzLCBzKTtcblx0fSxcblxuXHRfdXBkYXRlWkluZGV4OiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX2NvbnRhaW5lciAmJiB0aGlzLm9wdGlvbnMuekluZGV4ICE9PSB1bmRlZmluZWQgJiYgdGhpcy5vcHRpb25zLnpJbmRleCAhPT0gbnVsbCkge1xuXHRcdFx0dGhpcy5fY29udGFpbmVyLnN0eWxlLnpJbmRleCA9IHRoaXMub3B0aW9ucy56SW5kZXg7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRBdXRvWkluZGV4OiBmdW5jdGlvbiAoY29tcGFyZSkge1xuXHRcdC8vIGdvIHRocm91Z2ggYWxsIG90aGVyIGxheWVycyBvZiB0aGUgc2FtZSBwYW5lLCBzZXQgekluZGV4IHRvIG1heCArIDEgKGZyb250KSBvciBtaW4gLSAxIChiYWNrKVxuXG5cdFx0dmFyIGxheWVycyA9IHRoaXMuZ2V0UGFuZSgpLmNoaWxkcmVuLFxuXHRcdCAgICBlZGdlWkluZGV4ID0gLWNvbXBhcmUoLUluZmluaXR5LCBJbmZpbml0eSk7IC8vIC1JbmZpbml0eSBmb3IgbWF4LCBJbmZpbml0eSBmb3IgbWluXG5cblx0XHRmb3IgKHZhciBpID0gMCwgbGVuID0gbGF5ZXJzLmxlbmd0aCwgekluZGV4OyBpIDwgbGVuOyBpKyspIHtcblxuXHRcdFx0ekluZGV4ID0gbGF5ZXJzW2ldLnN0eWxlLnpJbmRleDtcblxuXHRcdFx0aWYgKGxheWVyc1tpXSAhPT0gdGhpcy5fY29udGFpbmVyICYmIHpJbmRleCkge1xuXHRcdFx0XHRlZGdlWkluZGV4ID0gY29tcGFyZShlZGdlWkluZGV4LCArekluZGV4KTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoaXNGaW5pdGUoZWRnZVpJbmRleCkpIHtcblx0XHRcdHRoaXMub3B0aW9ucy56SW5kZXggPSBlZGdlWkluZGV4ICsgY29tcGFyZSgtMSwgMSk7XG5cdFx0XHR0aGlzLl91cGRhdGVaSW5kZXgoKTtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZU9wYWNpdHk6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAoIXRoaXMuX21hcCkgeyByZXR1cm47IH1cblxuXHRcdC8vIElFIGRvZXNuJ3QgaW5oZXJpdCBmaWx0ZXIgb3BhY2l0eSBwcm9wZXJseSwgc28gd2UncmUgZm9yY2VkIHRvIHNldCBpdCBvbiB0aWxlc1xuXHRcdGlmIChMLkJyb3dzZXIuaWVsdDkpIHsgcmV0dXJuOyB9XG5cblx0XHRMLkRvbVV0aWwuc2V0T3BhY2l0eSh0aGlzLl9jb250YWluZXIsIHRoaXMub3B0aW9ucy5vcGFjaXR5KTtcblxuXHRcdHZhciBub3cgPSArbmV3IERhdGUoKSxcblx0XHQgICAgbmV4dEZyYW1lID0gZmFsc2UsXG5cdFx0ICAgIHdpbGxQcnVuZSA9IGZhbHNlO1xuXG5cdFx0Zm9yICh2YXIga2V5IGluIHRoaXMuX3RpbGVzKSB7XG5cdFx0XHR2YXIgdGlsZSA9IHRoaXMuX3RpbGVzW2tleV07XG5cdFx0XHRpZiAoIXRpbGUuY3VycmVudCB8fCAhdGlsZS5sb2FkZWQpIHsgY29udGludWU7IH1cblxuXHRcdFx0dmFyIGZhZGUgPSBNYXRoLm1pbigxLCAobm93IC0gdGlsZS5sb2FkZWQpIC8gMjAwKTtcblxuXHRcdFx0TC5Eb21VdGlsLnNldE9wYWNpdHkodGlsZS5lbCwgZmFkZSk7XG5cdFx0XHRpZiAoZmFkZSA8IDEpIHtcblx0XHRcdFx0bmV4dEZyYW1lID0gdHJ1ZTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdGlmICh0aWxlLmFjdGl2ZSkgeyB3aWxsUHJ1bmUgPSB0cnVlOyB9XG5cdFx0XHRcdHRpbGUuYWN0aXZlID0gdHJ1ZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAod2lsbFBydW5lICYmICF0aGlzLl9ub1BydW5lKSB7IHRoaXMuX3BydW5lVGlsZXMoKTsgfVxuXG5cdFx0aWYgKG5leHRGcmFtZSkge1xuXHRcdFx0TC5VdGlsLmNhbmNlbEFuaW1GcmFtZSh0aGlzLl9mYWRlRnJhbWUpO1xuXHRcdFx0dGhpcy5fZmFkZUZyYW1lID0gTC5VdGlsLnJlcXVlc3RBbmltRnJhbWUodGhpcy5fdXBkYXRlT3BhY2l0eSwgdGhpcyk7XG5cdFx0fVxuXHR9LFxuXG5cdF9pbml0Q29udGFpbmVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX2NvbnRhaW5lcikgeyByZXR1cm47IH1cblxuXHRcdHRoaXMuX2NvbnRhaW5lciA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsICdsZWFmbGV0LWxheWVyICcgKyAodGhpcy5vcHRpb25zLmNsYXNzTmFtZSB8fCAnJykpO1xuXHRcdHRoaXMuX3VwZGF0ZVpJbmRleCgpO1xuXG5cdFx0aWYgKHRoaXMub3B0aW9ucy5vcGFjaXR5IDwgMSkge1xuXHRcdFx0dGhpcy5fdXBkYXRlT3BhY2l0eSgpO1xuXHRcdH1cblxuXHRcdHRoaXMuZ2V0UGFuZSgpLmFwcGVuZENoaWxkKHRoaXMuX2NvbnRhaW5lcik7XG5cdH0sXG5cblx0X3VwZGF0ZUxldmVsczogZnVuY3Rpb24gKCkge1xuXG5cdFx0dmFyIHpvb20gPSB0aGlzLl90aWxlWm9vbSxcblx0XHQgICAgbWF4Wm9vbSA9IHRoaXMub3B0aW9ucy5tYXhab29tO1xuXG5cdFx0aWYgKHpvb20gPT09IHVuZGVmaW5lZCkgeyByZXR1cm4gdW5kZWZpbmVkOyB9XG5cblx0XHRmb3IgKHZhciB6IGluIHRoaXMuX2xldmVscykge1xuXHRcdFx0aWYgKHRoaXMuX2xldmVsc1t6XS5lbC5jaGlsZHJlbi5sZW5ndGggfHwgeiA9PT0gem9vbSkge1xuXHRcdFx0XHR0aGlzLl9sZXZlbHNbel0uZWwuc3R5bGUuekluZGV4ID0gbWF4Wm9vbSAtIE1hdGguYWJzKHpvb20gLSB6KTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdEwuRG9tVXRpbC5yZW1vdmUodGhpcy5fbGV2ZWxzW3pdLmVsKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlVGlsZXNBdFpvb20oeik7XG5cdFx0XHRcdGRlbGV0ZSB0aGlzLl9sZXZlbHNbel07XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dmFyIGxldmVsID0gdGhpcy5fbGV2ZWxzW3pvb21dLFxuXHRcdCAgICBtYXAgPSB0aGlzLl9tYXA7XG5cblx0XHRpZiAoIWxldmVsKSB7XG5cdFx0XHRsZXZlbCA9IHRoaXMuX2xldmVsc1t6b29tXSA9IHt9O1xuXG5cdFx0XHRsZXZlbC5lbCA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsICdsZWFmbGV0LXRpbGUtY29udGFpbmVyIGxlYWZsZXQtem9vbS1hbmltYXRlZCcsIHRoaXMuX2NvbnRhaW5lcik7XG5cdFx0XHRsZXZlbC5lbC5zdHlsZS56SW5kZXggPSBtYXhab29tO1xuXG5cdFx0XHRsZXZlbC5vcmlnaW4gPSBtYXAucHJvamVjdChtYXAudW5wcm9qZWN0KG1hcC5nZXRQaXhlbE9yaWdpbigpKSwgem9vbSkucm91bmQoKTtcblx0XHRcdGxldmVsLnpvb20gPSB6b29tO1xuXG5cdFx0XHR0aGlzLl9zZXRab29tVHJhbnNmb3JtKGxldmVsLCBtYXAuZ2V0Q2VudGVyKCksIG1hcC5nZXRab29tKCkpO1xuXG5cdFx0XHQvLyBmb3JjZSB0aGUgYnJvd3NlciB0byBjb25zaWRlciB0aGUgbmV3bHkgYWRkZWQgZWxlbWVudCBmb3IgdHJhbnNpdGlvblxuXHRcdFx0TC5VdGlsLmZhbHNlRm4obGV2ZWwuZWwub2Zmc2V0V2lkdGgpO1xuXHRcdH1cblxuXHRcdHRoaXMuX2xldmVsID0gbGV2ZWw7XG5cblx0XHRyZXR1cm4gbGV2ZWw7XG5cdH0sXG5cblx0X3BydW5lVGlsZXM6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAoIXRoaXMuX21hcCkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciBrZXksIHRpbGU7XG5cblx0XHR2YXIgem9vbSA9IHRoaXMuX21hcC5nZXRab29tKCk7XG5cdFx0aWYgKHpvb20gPiB0aGlzLm9wdGlvbnMubWF4Wm9vbSB8fFxuXHRcdFx0em9vbSA8IHRoaXMub3B0aW9ucy5taW5ab29tKSB7XG5cdFx0XHR0aGlzLl9yZW1vdmVBbGxUaWxlcygpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGZvciAoa2V5IGluIHRoaXMuX3RpbGVzKSB7XG5cdFx0XHR0aWxlID0gdGhpcy5fdGlsZXNba2V5XTtcblx0XHRcdHRpbGUucmV0YWluID0gdGlsZS5jdXJyZW50O1xuXHRcdH1cblxuXHRcdGZvciAoa2V5IGluIHRoaXMuX3RpbGVzKSB7XG5cdFx0XHR0aWxlID0gdGhpcy5fdGlsZXNba2V5XTtcblx0XHRcdGlmICh0aWxlLmN1cnJlbnQgJiYgIXRpbGUuYWN0aXZlKSB7XG5cdFx0XHRcdHZhciBjb29yZHMgPSB0aWxlLmNvb3Jkcztcblx0XHRcdFx0aWYgKCF0aGlzLl9yZXRhaW5QYXJlbnQoY29vcmRzLngsIGNvb3Jkcy55LCBjb29yZHMueiwgY29vcmRzLnogLSA1KSkge1xuXHRcdFx0XHRcdHRoaXMuX3JldGFpbkNoaWxkcmVuKGNvb3Jkcy54LCBjb29yZHMueSwgY29vcmRzLnosIGNvb3Jkcy56ICsgMik7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cblx0XHRmb3IgKGtleSBpbiB0aGlzLl90aWxlcykge1xuXHRcdFx0aWYgKCF0aGlzLl90aWxlc1trZXldLnJldGFpbikge1xuXHRcdFx0XHR0aGlzLl9yZW1vdmVUaWxlKGtleSk7XG5cdFx0XHR9XG5cdFx0fVxuXHR9LFxuXG5cdF9yZW1vdmVUaWxlc0F0Wm9vbTogZnVuY3Rpb24gKHpvb20pIHtcblx0XHRmb3IgKHZhciBrZXkgaW4gdGhpcy5fdGlsZXMpIHtcblx0XHRcdGlmICh0aGlzLl90aWxlc1trZXldLmNvb3Jkcy56ICE9PSB6b29tKSB7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0fVxuXHRcdFx0dGhpcy5fcmVtb3ZlVGlsZShrZXkpO1xuXHRcdH1cblx0fSxcblxuXHRfcmVtb3ZlQWxsVGlsZXM6IGZ1bmN0aW9uICgpIHtcblx0XHRmb3IgKHZhciBrZXkgaW4gdGhpcy5fdGlsZXMpIHtcblx0XHRcdHRoaXMuX3JlbW92ZVRpbGUoa2V5KTtcblx0XHR9XG5cdH0sXG5cblx0X2ludmFsaWRhdGVBbGw6IGZ1bmN0aW9uICgpIHtcblx0XHRmb3IgKHZhciB6IGluIHRoaXMuX2xldmVscykge1xuXHRcdFx0TC5Eb21VdGlsLnJlbW92ZSh0aGlzLl9sZXZlbHNbel0uZWwpO1xuXHRcdFx0ZGVsZXRlIHRoaXMuX2xldmVsc1t6XTtcblx0XHR9XG5cdFx0dGhpcy5fcmVtb3ZlQWxsVGlsZXMoKTtcblxuXHRcdHRoaXMuX3RpbGVab29tID0gbnVsbDtcblx0fSxcblxuXHRfcmV0YWluUGFyZW50OiBmdW5jdGlvbiAoeCwgeSwgeiwgbWluWm9vbSkge1xuXHRcdHZhciB4MiA9IE1hdGguZmxvb3IoeCAvIDIpLFxuXHRcdCAgICB5MiA9IE1hdGguZmxvb3IoeSAvIDIpLFxuXHRcdCAgICB6MiA9IHogLSAxLFxuXHRcdCAgICBjb29yZHMyID0gbmV3IEwuUG9pbnQoK3gyLCAreTIpO1xuXHRcdGNvb3JkczIueiA9ICt6MjtcblxuXHRcdHZhciBrZXkgPSB0aGlzLl90aWxlQ29vcmRzVG9LZXkoY29vcmRzMiksXG5cdFx0ICAgIHRpbGUgPSB0aGlzLl90aWxlc1trZXldO1xuXG5cdFx0aWYgKHRpbGUgJiYgdGlsZS5hY3RpdmUpIHtcblx0XHRcdHRpbGUucmV0YWluID0gdHJ1ZTtcblx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0fSBlbHNlIGlmICh0aWxlICYmIHRpbGUubG9hZGVkKSB7XG5cdFx0XHR0aWxlLnJldGFpbiA9IHRydWU7XG5cdFx0fVxuXG5cdFx0aWYgKHoyID4gbWluWm9vbSkge1xuXHRcdFx0cmV0dXJuIHRoaXMuX3JldGFpblBhcmVudCh4MiwgeTIsIHoyLCBtaW5ab29tKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cdH0sXG5cblx0X3JldGFpbkNoaWxkcmVuOiBmdW5jdGlvbiAoeCwgeSwgeiwgbWF4Wm9vbSkge1xuXG5cdFx0Zm9yICh2YXIgaSA9IDIgKiB4OyBpIDwgMiAqIHggKyAyOyBpKyspIHtcblx0XHRcdGZvciAodmFyIGogPSAyICogeTsgaiA8IDIgKiB5ICsgMjsgaisrKSB7XG5cblx0XHRcdFx0dmFyIGNvb3JkcyA9IG5ldyBMLlBvaW50KGksIGopO1xuXHRcdFx0XHRjb29yZHMueiA9IHogKyAxO1xuXG5cdFx0XHRcdHZhciBrZXkgPSB0aGlzLl90aWxlQ29vcmRzVG9LZXkoY29vcmRzKSxcblx0XHRcdFx0ICAgIHRpbGUgPSB0aGlzLl90aWxlc1trZXldO1xuXG5cdFx0XHRcdGlmICh0aWxlICYmIHRpbGUuYWN0aXZlKSB7XG5cdFx0XHRcdFx0dGlsZS5yZXRhaW4gPSB0cnVlO1xuXHRcdFx0XHRcdGNvbnRpbnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAodGlsZSAmJiB0aWxlLmxvYWRlZCkge1xuXHRcdFx0XHRcdHRpbGUucmV0YWluID0gdHJ1ZTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICh6ICsgMSA8IG1heFpvb20pIHtcblx0XHRcdFx0XHR0aGlzLl9yZXRhaW5DaGlsZHJlbihpLCBqLCB6ICsgMSwgbWF4Wm9vbSk7XG5cdFx0XHRcdH1cblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X3Jlc2V0VmlldzogZnVuY3Rpb24gKGUpIHtcblx0XHR2YXIgYW5pbWF0aW5nID0gZSAmJiAoZS5waW5jaCB8fCBlLmZseVRvKTtcblx0XHR0aGlzLl9zZXRWaWV3KHRoaXMuX21hcC5nZXRDZW50ZXIoKSwgdGhpcy5fbWFwLmdldFpvb20oKSwgYW5pbWF0aW5nLCBhbmltYXRpbmcpO1xuXHR9LFxuXG5cdF9hbmltYXRlWm9vbTogZnVuY3Rpb24gKGUpIHtcblx0XHR0aGlzLl9zZXRWaWV3KGUuY2VudGVyLCBlLnpvb20sIHRydWUsIGUubm9VcGRhdGUpO1xuXHR9LFxuXG5cdF9zZXRWaWV3OiBmdW5jdGlvbiAoY2VudGVyLCB6b29tLCBub1BydW5lLCBub1VwZGF0ZSkge1xuXHRcdHZhciB0aWxlWm9vbSA9IE1hdGgucm91bmQoem9vbSk7XG5cdFx0aWYgKCh0aGlzLm9wdGlvbnMubWF4Wm9vbSAhPT0gdW5kZWZpbmVkICYmIHRpbGVab29tID4gdGhpcy5vcHRpb25zLm1heFpvb20pIHx8XG5cdFx0ICAgICh0aGlzLm9wdGlvbnMubWluWm9vbSAhPT0gdW5kZWZpbmVkICYmIHRpbGVab29tIDwgdGhpcy5vcHRpb25zLm1pblpvb20pKSB7XG5cdFx0XHR0aWxlWm9vbSA9IHVuZGVmaW5lZDtcblx0XHR9XG5cblx0XHR2YXIgdGlsZVpvb21DaGFuZ2VkID0gdGhpcy5vcHRpb25zLnVwZGF0ZVdoZW5ab29taW5nICYmICh0aWxlWm9vbSAhPT0gdGhpcy5fdGlsZVpvb20pO1xuXG5cdFx0aWYgKCFub1VwZGF0ZSB8fCB0aWxlWm9vbUNoYW5nZWQpIHtcblxuXHRcdFx0dGhpcy5fdGlsZVpvb20gPSB0aWxlWm9vbTtcblxuXHRcdFx0aWYgKHRoaXMuX2Fib3J0TG9hZGluZykge1xuXHRcdFx0XHR0aGlzLl9hYm9ydExvYWRpbmcoKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fdXBkYXRlTGV2ZWxzKCk7XG5cdFx0XHR0aGlzLl9yZXNldEdyaWQoKTtcblxuXHRcdFx0aWYgKHRpbGVab29tICE9PSB1bmRlZmluZWQpIHtcblx0XHRcdFx0dGhpcy5fdXBkYXRlKGNlbnRlcik7XG5cdFx0XHR9XG5cblx0XHRcdGlmICghbm9QcnVuZSkge1xuXHRcdFx0XHR0aGlzLl9wcnVuZVRpbGVzKCk7XG5cdFx0XHR9XG5cblx0XHRcdC8vIEZsYWcgdG8gcHJldmVudCBfdXBkYXRlT3BhY2l0eSBmcm9tIHBydW5pbmcgdGlsZXMgZHVyaW5nXG5cdFx0XHQvLyBhIHpvb20gYW5pbSBvciBhIHBpbmNoIGdlc3R1cmVcblx0XHRcdHRoaXMuX25vUHJ1bmUgPSAhIW5vUHJ1bmU7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc2V0Wm9vbVRyYW5zZm9ybXMoY2VudGVyLCB6b29tKTtcblx0fSxcblxuXHRfc2V0Wm9vbVRyYW5zZm9ybXM6IGZ1bmN0aW9uIChjZW50ZXIsIHpvb20pIHtcblx0XHRmb3IgKHZhciBpIGluIHRoaXMuX2xldmVscykge1xuXHRcdFx0dGhpcy5fc2V0Wm9vbVRyYW5zZm9ybSh0aGlzLl9sZXZlbHNbaV0sIGNlbnRlciwgem9vbSk7XG5cdFx0fVxuXHR9LFxuXG5cdF9zZXRab29tVHJhbnNmb3JtOiBmdW5jdGlvbiAobGV2ZWwsIGNlbnRlciwgem9vbSkge1xuXHRcdHZhciBzY2FsZSA9IHRoaXMuX21hcC5nZXRab29tU2NhbGUoem9vbSwgbGV2ZWwuem9vbSksXG5cdFx0ICAgIHRyYW5zbGF0ZSA9IGxldmVsLm9yaWdpbi5tdWx0aXBseUJ5KHNjYWxlKVxuXHRcdCAgICAgICAgLnN1YnRyYWN0KHRoaXMuX21hcC5fZ2V0TmV3UGl4ZWxPcmlnaW4oY2VudGVyLCB6b29tKSkucm91bmQoKTtcblxuXHRcdGlmIChMLkJyb3dzZXIuYW55M2QpIHtcblx0XHRcdEwuRG9tVXRpbC5zZXRUcmFuc2Zvcm0obGV2ZWwuZWwsIHRyYW5zbGF0ZSwgc2NhbGUpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRMLkRvbVV0aWwuc2V0UG9zaXRpb24obGV2ZWwuZWwsIHRyYW5zbGF0ZSk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZXNldEdyaWQ6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBjcnMgPSBtYXAub3B0aW9ucy5jcnMsXG5cdFx0ICAgIHRpbGVTaXplID0gdGhpcy5fdGlsZVNpemUgPSB0aGlzLmdldFRpbGVTaXplKCksXG5cdFx0ICAgIHRpbGVab29tID0gdGhpcy5fdGlsZVpvb207XG5cblx0XHR2YXIgYm91bmRzID0gdGhpcy5fbWFwLmdldFBpeGVsV29ybGRCb3VuZHModGhpcy5fdGlsZVpvb20pO1xuXHRcdGlmIChib3VuZHMpIHtcblx0XHRcdHRoaXMuX2dsb2JhbFRpbGVSYW5nZSA9IHRoaXMuX3B4Qm91bmRzVG9UaWxlUmFuZ2UoYm91bmRzKTtcblx0XHR9XG5cblx0XHR0aGlzLl93cmFwWCA9IGNycy53cmFwTG5nICYmICF0aGlzLm9wdGlvbnMubm9XcmFwICYmIFtcblx0XHRcdE1hdGguZmxvb3IobWFwLnByb2plY3QoWzAsIGNycy53cmFwTG5nWzBdXSwgdGlsZVpvb20pLnggLyB0aWxlU2l6ZS54KSxcblx0XHRcdE1hdGguY2VpbChtYXAucHJvamVjdChbMCwgY3JzLndyYXBMbmdbMV1dLCB0aWxlWm9vbSkueCAvIHRpbGVTaXplLnkpXG5cdFx0XTtcblx0XHR0aGlzLl93cmFwWSA9IGNycy53cmFwTGF0ICYmICF0aGlzLm9wdGlvbnMubm9XcmFwICYmIFtcblx0XHRcdE1hdGguZmxvb3IobWFwLnByb2plY3QoW2Nycy53cmFwTGF0WzBdLCAwXSwgdGlsZVpvb20pLnkgLyB0aWxlU2l6ZS54KSxcblx0XHRcdE1hdGguY2VpbChtYXAucHJvamVjdChbY3JzLndyYXBMYXRbMV0sIDBdLCB0aWxlWm9vbSkueSAvIHRpbGVTaXplLnkpXG5cdFx0XTtcblx0fSxcblxuXHRfb25Nb3ZlRW5kOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKCF0aGlzLl9tYXAgfHwgdGhpcy5fbWFwLl9hbmltYXRpbmdab29tKSB7IHJldHVybjsgfVxuXG5cdFx0dGhpcy5fdXBkYXRlKCk7XG5cdH0sXG5cblx0X2dldFRpbGVkUGl4ZWxCb3VuZHM6IGZ1bmN0aW9uIChjZW50ZXIpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBtYXBab29tID0gbWFwLl9hbmltYXRpbmdab29tID8gTWF0aC5tYXgobWFwLl9hbmltYXRlVG9ab29tLCBtYXAuZ2V0Wm9vbSgpKSA6IG1hcC5nZXRab29tKCksXG5cdFx0ICAgIHNjYWxlID0gbWFwLmdldFpvb21TY2FsZShtYXBab29tLCB0aGlzLl90aWxlWm9vbSksXG5cdFx0ICAgIHBpeGVsQ2VudGVyID0gbWFwLnByb2plY3QoY2VudGVyLCB0aGlzLl90aWxlWm9vbSkuZmxvb3IoKSxcblx0XHQgICAgaGFsZlNpemUgPSBtYXAuZ2V0U2l6ZSgpLmRpdmlkZUJ5KHNjYWxlICogMik7XG5cblx0XHRyZXR1cm4gbmV3IEwuQm91bmRzKHBpeGVsQ2VudGVyLnN1YnRyYWN0KGhhbGZTaXplKSwgcGl4ZWxDZW50ZXIuYWRkKGhhbGZTaXplKSk7XG5cdH0sXG5cblx0Ly8gUHJpdmF0ZSBtZXRob2QgdG8gbG9hZCB0aWxlcyBpbiB0aGUgZ3JpZCdzIGFjdGl2ZSB6b29tIGxldmVsIGFjY29yZGluZyB0byBtYXAgYm91bmRzXG5cdF91cGRhdGU6IGZ1bmN0aW9uIChjZW50ZXIpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwO1xuXHRcdGlmICghbWFwKSB7IHJldHVybjsgfVxuXHRcdHZhciB6b29tID0gbWFwLmdldFpvb20oKTtcblxuXHRcdGlmIChjZW50ZXIgPT09IHVuZGVmaW5lZCkgeyBjZW50ZXIgPSBtYXAuZ2V0Q2VudGVyKCk7IH1cblx0XHRpZiAodGhpcy5fdGlsZVpvb20gPT09IHVuZGVmaW5lZCkgeyByZXR1cm47IH1cdC8vIGlmIG91dCBvZiBtaW56b29tL21heHpvb21cblxuXHRcdHZhciBwaXhlbEJvdW5kcyA9IHRoaXMuX2dldFRpbGVkUGl4ZWxCb3VuZHMoY2VudGVyKSxcblx0XHQgICAgdGlsZVJhbmdlID0gdGhpcy5fcHhCb3VuZHNUb1RpbGVSYW5nZShwaXhlbEJvdW5kcyksXG5cdFx0ICAgIHRpbGVDZW50ZXIgPSB0aWxlUmFuZ2UuZ2V0Q2VudGVyKCksXG5cdFx0ICAgIHF1ZXVlID0gW10sXG5cdFx0ICAgIG1hcmdpbiA9IHRoaXMub3B0aW9ucy5rZWVwQnVmZmVyLFxuXHRcdCAgICBub1BydW5lUmFuZ2UgPSBuZXcgTC5Cb3VuZHModGlsZVJhbmdlLmdldEJvdHRvbUxlZnQoKS5zdWJ0cmFjdChbbWFyZ2luLCAtbWFyZ2luXSksXG5cdFx0ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGlsZVJhbmdlLmdldFRvcFJpZ2h0KCkuYWRkKFttYXJnaW4sIC1tYXJnaW5dKSk7XG5cblx0XHRmb3IgKHZhciBrZXkgaW4gdGhpcy5fdGlsZXMpIHtcblx0XHRcdHZhciBjID0gdGhpcy5fdGlsZXNba2V5XS5jb29yZHM7XG5cdFx0XHRpZiAoYy56ICE9PSB0aGlzLl90aWxlWm9vbSB8fCAhbm9QcnVuZVJhbmdlLmNvbnRhaW5zKEwucG9pbnQoYy54LCBjLnkpKSkge1xuXHRcdFx0XHR0aGlzLl90aWxlc1trZXldLmN1cnJlbnQgPSBmYWxzZTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHQvLyBfdXBkYXRlIGp1c3QgbG9hZHMgbW9yZSB0aWxlcy4gSWYgdGhlIHRpbGUgem9vbSBsZXZlbCBkaWZmZXJzIHRvbyBtdWNoXG5cdFx0Ly8gZnJvbSB0aGUgbWFwJ3MsIGxldCBfc2V0VmlldyByZXNldCBsZXZlbHMgYW5kIHBydW5lIG9sZCB0aWxlcy5cblx0XHRpZiAoTWF0aC5hYnMoem9vbSAtIHRoaXMuX3RpbGVab29tKSA+IDEpIHsgdGhpcy5fc2V0VmlldyhjZW50ZXIsIHpvb20pOyByZXR1cm47IH1cblxuXHRcdC8vIGNyZWF0ZSBhIHF1ZXVlIG9mIGNvb3JkaW5hdGVzIHRvIGxvYWQgdGlsZXMgZnJvbVxuXHRcdGZvciAodmFyIGogPSB0aWxlUmFuZ2UubWluLnk7IGogPD0gdGlsZVJhbmdlLm1heC55OyBqKyspIHtcblx0XHRcdGZvciAodmFyIGkgPSB0aWxlUmFuZ2UubWluLng7IGkgPD0gdGlsZVJhbmdlLm1heC54OyBpKyspIHtcblx0XHRcdFx0dmFyIGNvb3JkcyA9IG5ldyBMLlBvaW50KGksIGopO1xuXHRcdFx0XHRjb29yZHMueiA9IHRoaXMuX3RpbGVab29tO1xuXG5cdFx0XHRcdGlmICghdGhpcy5faXNWYWxpZFRpbGUoY29vcmRzKSkgeyBjb250aW51ZTsgfVxuXG5cdFx0XHRcdHZhciB0aWxlID0gdGhpcy5fdGlsZXNbdGhpcy5fdGlsZUNvb3Jkc1RvS2V5KGNvb3JkcyldO1xuXHRcdFx0XHRpZiAodGlsZSkge1xuXHRcdFx0XHRcdHRpbGUuY3VycmVudCA9IHRydWU7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cXVldWUucHVzaChjb29yZHMpO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0Ly8gc29ydCB0aWxlIHF1ZXVlIHRvIGxvYWQgdGlsZXMgaW4gb3JkZXIgb2YgdGhlaXIgZGlzdGFuY2UgdG8gY2VudGVyXG5cdFx0cXVldWUuc29ydChmdW5jdGlvbiAoYSwgYikge1xuXHRcdFx0cmV0dXJuIGEuZGlzdGFuY2VUbyh0aWxlQ2VudGVyKSAtIGIuZGlzdGFuY2VUbyh0aWxlQ2VudGVyKTtcblx0XHR9KTtcblxuXHRcdGlmIChxdWV1ZS5sZW5ndGggIT09IDApIHtcblx0XHRcdC8vIGlmIGl0J3MgdGhlIGZpcnN0IGJhdGNoIG9mIHRpbGVzIHRvIGxvYWRcblx0XHRcdGlmICghdGhpcy5fbG9hZGluZykge1xuXHRcdFx0XHR0aGlzLl9sb2FkaW5nID0gdHJ1ZTtcblx0XHRcdFx0Ly8gQGV2ZW50IGxvYWRpbmc6IEV2ZW50XG5cdFx0XHRcdC8vIEZpcmVkIHdoZW4gdGhlIGdyaWQgbGF5ZXIgc3RhcnRzIGxvYWRpbmcgdGlsZXMuXG5cdFx0XHRcdHRoaXMuZmlyZSgnbG9hZGluZycpO1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBjcmVhdGUgRE9NIGZyYWdtZW50IHRvIGFwcGVuZCB0aWxlcyBpbiBvbmUgYmF0Y2hcblx0XHRcdHZhciBmcmFnbWVudCA9IGRvY3VtZW50LmNyZWF0ZURvY3VtZW50RnJhZ21lbnQoKTtcblxuXHRcdFx0Zm9yIChpID0gMDsgaSA8IHF1ZXVlLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRcdHRoaXMuX2FkZFRpbGUocXVldWVbaV0sIGZyYWdtZW50KTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fbGV2ZWwuZWwuYXBwZW5kQ2hpbGQoZnJhZ21lbnQpO1xuXHRcdH1cblx0fSxcblxuXHRfaXNWYWxpZFRpbGU6IGZ1bmN0aW9uIChjb29yZHMpIHtcblx0XHR2YXIgY3JzID0gdGhpcy5fbWFwLm9wdGlvbnMuY3JzO1xuXG5cdFx0aWYgKCFjcnMuaW5maW5pdGUpIHtcblx0XHRcdC8vIGRvbid0IGxvYWQgdGlsZSBpZiBpdCdzIG91dCBvZiBib3VuZHMgYW5kIG5vdCB3cmFwcGVkXG5cdFx0XHR2YXIgYm91bmRzID0gdGhpcy5fZ2xvYmFsVGlsZVJhbmdlO1xuXHRcdFx0aWYgKCghY3JzLndyYXBMbmcgJiYgKGNvb3Jkcy54IDwgYm91bmRzLm1pbi54IHx8IGNvb3Jkcy54ID4gYm91bmRzLm1heC54KSkgfHxcblx0XHRcdCAgICAoIWNycy53cmFwTGF0ICYmIChjb29yZHMueSA8IGJvdW5kcy5taW4ueSB8fCBjb29yZHMueSA+IGJvdW5kcy5tYXgueSkpKSB7IHJldHVybiBmYWxzZTsgfVxuXHRcdH1cblxuXHRcdGlmICghdGhpcy5vcHRpb25zLmJvdW5kcykgeyByZXR1cm4gdHJ1ZTsgfVxuXG5cdFx0Ly8gZG9uJ3QgbG9hZCB0aWxlIGlmIGl0IGRvZXNuJ3QgaW50ZXJzZWN0IHRoZSBib3VuZHMgaW4gb3B0aW9uc1xuXHRcdHZhciB0aWxlQm91bmRzID0gdGhpcy5fdGlsZUNvb3Jkc1RvQm91bmRzKGNvb3Jkcyk7XG5cdFx0cmV0dXJuIEwubGF0TG5nQm91bmRzKHRoaXMub3B0aW9ucy5ib3VuZHMpLm92ZXJsYXBzKHRpbGVCb3VuZHMpO1xuXHR9LFxuXG5cdF9rZXlUb0JvdW5kczogZnVuY3Rpb24gKGtleSkge1xuXHRcdHJldHVybiB0aGlzLl90aWxlQ29vcmRzVG9Cb3VuZHModGhpcy5fa2V5VG9UaWxlQ29vcmRzKGtleSkpO1xuXHR9LFxuXG5cdC8vIGNvbnZlcnRzIHRpbGUgY29vcmRpbmF0ZXMgdG8gaXRzIGdlb2dyYXBoaWNhbCBib3VuZHNcblx0X3RpbGVDb29yZHNUb0JvdW5kczogZnVuY3Rpb24gKGNvb3Jkcykge1xuXG5cdFx0dmFyIG1hcCA9IHRoaXMuX21hcCxcblx0XHQgICAgdGlsZVNpemUgPSB0aGlzLmdldFRpbGVTaXplKCksXG5cblx0XHQgICAgbndQb2ludCA9IGNvb3Jkcy5zY2FsZUJ5KHRpbGVTaXplKSxcblx0XHQgICAgc2VQb2ludCA9IG53UG9pbnQuYWRkKHRpbGVTaXplKSxcblxuXHRcdCAgICBudyA9IG1hcC51bnByb2plY3QobndQb2ludCwgY29vcmRzLnopLFxuXHRcdCAgICBzZSA9IG1hcC51bnByb2plY3Qoc2VQb2ludCwgY29vcmRzLnopO1xuXG5cdFx0aWYgKCF0aGlzLm9wdGlvbnMubm9XcmFwKSB7XG5cdFx0XHRudyA9IG1hcC53cmFwTGF0TG5nKG53KTtcblx0XHRcdHNlID0gbWFwLndyYXBMYXRMbmcoc2UpO1xuXHRcdH1cblxuXHRcdHJldHVybiBuZXcgTC5MYXRMbmdCb3VuZHMobncsIHNlKTtcblx0fSxcblxuXHQvLyBjb252ZXJ0cyB0aWxlIGNvb3JkaW5hdGVzIHRvIGtleSBmb3IgdGhlIHRpbGUgY2FjaGVcblx0X3RpbGVDb29yZHNUb0tleTogZnVuY3Rpb24gKGNvb3Jkcykge1xuXHRcdHJldHVybiBjb29yZHMueCArICc6JyArIGNvb3Jkcy55ICsgJzonICsgY29vcmRzLno7XG5cdH0sXG5cblx0Ly8gY29udmVydHMgdGlsZSBjYWNoZSBrZXkgdG8gY29vcmRpbmF0ZXNcblx0X2tleVRvVGlsZUNvb3JkczogZnVuY3Rpb24gKGtleSkge1xuXHRcdHZhciBrID0ga2V5LnNwbGl0KCc6JyksXG5cdFx0ICAgIGNvb3JkcyA9IG5ldyBMLlBvaW50KCtrWzBdLCAra1sxXSk7XG5cdFx0Y29vcmRzLnogPSAra1syXTtcblx0XHRyZXR1cm4gY29vcmRzO1xuXHR9LFxuXG5cdF9yZW1vdmVUaWxlOiBmdW5jdGlvbiAoa2V5KSB7XG5cdFx0dmFyIHRpbGUgPSB0aGlzLl90aWxlc1trZXldO1xuXHRcdGlmICghdGlsZSkgeyByZXR1cm47IH1cblxuXHRcdEwuRG9tVXRpbC5yZW1vdmUodGlsZS5lbCk7XG5cblx0XHRkZWxldGUgdGhpcy5fdGlsZXNba2V5XTtcblxuXHRcdC8vIEBldmVudCB0aWxldW5sb2FkOiBUaWxlRXZlbnRcblx0XHQvLyBGaXJlZCB3aGVuIGEgdGlsZSBpcyByZW1vdmVkIChlLmcuIHdoZW4gYSB0aWxlIGdvZXMgb2ZmIHRoZSBzY3JlZW4pLlxuXHRcdHRoaXMuZmlyZSgndGlsZXVubG9hZCcsIHtcblx0XHRcdHRpbGU6IHRpbGUuZWwsXG5cdFx0XHRjb29yZHM6IHRoaXMuX2tleVRvVGlsZUNvb3JkcyhrZXkpXG5cdFx0fSk7XG5cdH0sXG5cblx0X2luaXRUaWxlOiBmdW5jdGlvbiAodGlsZSkge1xuXHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aWxlLCAnbGVhZmxldC10aWxlJyk7XG5cblx0XHR2YXIgdGlsZVNpemUgPSB0aGlzLmdldFRpbGVTaXplKCk7XG5cdFx0dGlsZS5zdHlsZS53aWR0aCA9IHRpbGVTaXplLnggKyAncHgnO1xuXHRcdHRpbGUuc3R5bGUuaGVpZ2h0ID0gdGlsZVNpemUueSArICdweCc7XG5cblx0XHR0aWxlLm9uc2VsZWN0c3RhcnQgPSBMLlV0aWwuZmFsc2VGbjtcblx0XHR0aWxlLm9ubW91c2Vtb3ZlID0gTC5VdGlsLmZhbHNlRm47XG5cblx0XHQvLyB1cGRhdGUgb3BhY2l0eSBvbiB0aWxlcyBpbiBJRTctOCBiZWNhdXNlIG9mIGZpbHRlciBpbmhlcml0YW5jZSBwcm9ibGVtc1xuXHRcdGlmIChMLkJyb3dzZXIuaWVsdDkgJiYgdGhpcy5vcHRpb25zLm9wYWNpdHkgPCAxKSB7XG5cdFx0XHRMLkRvbVV0aWwuc2V0T3BhY2l0eSh0aWxlLCB0aGlzLm9wdGlvbnMub3BhY2l0eSk7XG5cdFx0fVxuXG5cdFx0Ly8gd2l0aG91dCB0aGlzIGhhY2ssIHRpbGVzIGRpc2FwcGVhciBhZnRlciB6b29tIG9uIENocm9tZSBmb3IgQW5kcm9pZFxuXHRcdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9MZWFmbGV0L0xlYWZsZXQvaXNzdWVzLzIwNzhcblx0XHRpZiAoTC5Ccm93c2VyLmFuZHJvaWQgJiYgIUwuQnJvd3Nlci5hbmRyb2lkMjMpIHtcblx0XHRcdHRpbGUuc3R5bGUuV2Via2l0QmFja2ZhY2VWaXNpYmlsaXR5ID0gJ2hpZGRlbic7XG5cdFx0fVxuXHR9LFxuXG5cdF9hZGRUaWxlOiBmdW5jdGlvbiAoY29vcmRzLCBjb250YWluZXIpIHtcblx0XHR2YXIgdGlsZVBvcyA9IHRoaXMuX2dldFRpbGVQb3MoY29vcmRzKSxcblx0XHQgICAga2V5ID0gdGhpcy5fdGlsZUNvb3Jkc1RvS2V5KGNvb3Jkcyk7XG5cblx0XHR2YXIgdGlsZSA9IHRoaXMuY3JlYXRlVGlsZSh0aGlzLl93cmFwQ29vcmRzKGNvb3JkcyksIEwuYmluZCh0aGlzLl90aWxlUmVhZHksIHRoaXMsIGNvb3JkcykpO1xuXG5cdFx0dGhpcy5faW5pdFRpbGUodGlsZSk7XG5cblx0XHQvLyBpZiBjcmVhdGVUaWxlIGlzIGRlZmluZWQgd2l0aCBhIHNlY29uZCBhcmd1bWVudCAoXCJkb25lXCIgY2FsbGJhY2spLFxuXHRcdC8vIHdlIGtub3cgdGhhdCB0aWxlIGlzIGFzeW5jIGFuZCB3aWxsIGJlIHJlYWR5IGxhdGVyOyBvdGhlcndpc2Vcblx0XHRpZiAodGhpcy5jcmVhdGVUaWxlLmxlbmd0aCA8IDIpIHtcblx0XHRcdC8vIG1hcmsgdGlsZSBhcyByZWFkeSwgYnV0IGRlbGF5IG9uZSBmcmFtZSBmb3Igb3BhY2l0eSBhbmltYXRpb24gdG8gaGFwcGVuXG5cdFx0XHRMLlV0aWwucmVxdWVzdEFuaW1GcmFtZShMLmJpbmQodGhpcy5fdGlsZVJlYWR5LCB0aGlzLCBjb29yZHMsIG51bGwsIHRpbGUpKTtcblx0XHR9XG5cblx0XHRMLkRvbVV0aWwuc2V0UG9zaXRpb24odGlsZSwgdGlsZVBvcyk7XG5cblx0XHQvLyBzYXZlIHRpbGUgaW4gY2FjaGVcblx0XHR0aGlzLl90aWxlc1trZXldID0ge1xuXHRcdFx0ZWw6IHRpbGUsXG5cdFx0XHRjb29yZHM6IGNvb3Jkcyxcblx0XHRcdGN1cnJlbnQ6IHRydWVcblx0XHR9O1xuXG5cdFx0Y29udGFpbmVyLmFwcGVuZENoaWxkKHRpbGUpO1xuXHRcdC8vIEBldmVudCB0aWxlbG9hZHN0YXJ0OiBUaWxlRXZlbnRcblx0XHQvLyBGaXJlZCB3aGVuIGEgdGlsZSBpcyByZXF1ZXN0ZWQgYW5kIHN0YXJ0cyBsb2FkaW5nLlxuXHRcdHRoaXMuZmlyZSgndGlsZWxvYWRzdGFydCcsIHtcblx0XHRcdHRpbGU6IHRpbGUsXG5cdFx0XHRjb29yZHM6IGNvb3Jkc1xuXHRcdH0pO1xuXHR9LFxuXG5cdF90aWxlUmVhZHk6IGZ1bmN0aW9uIChjb29yZHMsIGVyciwgdGlsZSkge1xuXHRcdGlmICghdGhpcy5fbWFwKSB7IHJldHVybjsgfVxuXG5cdFx0aWYgKGVycikge1xuXHRcdFx0Ly8gQGV2ZW50IHRpbGVlcnJvcjogVGlsZUVycm9yRXZlbnRcblx0XHRcdC8vIEZpcmVkIHdoZW4gdGhlcmUgaXMgYW4gZXJyb3IgbG9hZGluZyBhIHRpbGUuXG5cdFx0XHR0aGlzLmZpcmUoJ3RpbGVlcnJvcicsIHtcblx0XHRcdFx0ZXJyb3I6IGVycixcblx0XHRcdFx0dGlsZTogdGlsZSxcblx0XHRcdFx0Y29vcmRzOiBjb29yZHNcblx0XHRcdH0pO1xuXHRcdH1cblxuXHRcdHZhciBrZXkgPSB0aGlzLl90aWxlQ29vcmRzVG9LZXkoY29vcmRzKTtcblxuXHRcdHRpbGUgPSB0aGlzLl90aWxlc1trZXldO1xuXHRcdGlmICghdGlsZSkgeyByZXR1cm47IH1cblxuXHRcdHRpbGUubG9hZGVkID0gK25ldyBEYXRlKCk7XG5cdFx0aWYgKHRoaXMuX21hcC5fZmFkZUFuaW1hdGVkKSB7XG5cdFx0XHRMLkRvbVV0aWwuc2V0T3BhY2l0eSh0aWxlLmVsLCAwKTtcblx0XHRcdEwuVXRpbC5jYW5jZWxBbmltRnJhbWUodGhpcy5fZmFkZUZyYW1lKTtcblx0XHRcdHRoaXMuX2ZhZGVGcmFtZSA9IEwuVXRpbC5yZXF1ZXN0QW5pbUZyYW1lKHRoaXMuX3VwZGF0ZU9wYWNpdHksIHRoaXMpO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aWxlLmFjdGl2ZSA9IHRydWU7XG5cdFx0XHR0aGlzLl9wcnVuZVRpbGVzKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCFlcnIpIHtcblx0XHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aWxlLmVsLCAnbGVhZmxldC10aWxlLWxvYWRlZCcpO1xuXG5cdFx0XHQvLyBAZXZlbnQgdGlsZWxvYWQ6IFRpbGVFdmVudFxuXHRcdFx0Ly8gRmlyZWQgd2hlbiBhIHRpbGUgbG9hZHMuXG5cdFx0XHR0aGlzLmZpcmUoJ3RpbGVsb2FkJywge1xuXHRcdFx0XHR0aWxlOiB0aWxlLmVsLFxuXHRcdFx0XHRjb29yZHM6IGNvb3Jkc1xuXHRcdFx0fSk7XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuX25vVGlsZXNUb0xvYWQoKSkge1xuXHRcdFx0dGhpcy5fbG9hZGluZyA9IGZhbHNlO1xuXHRcdFx0Ly8gQGV2ZW50IGxvYWQ6IEV2ZW50XG5cdFx0XHQvLyBGaXJlZCB3aGVuIHRoZSBncmlkIGxheWVyIGxvYWRlZCBhbGwgdmlzaWJsZSB0aWxlcy5cblx0XHRcdHRoaXMuZmlyZSgnbG9hZCcpO1xuXG5cdFx0XHRpZiAoTC5Ccm93c2VyLmllbHQ5IHx8ICF0aGlzLl9tYXAuX2ZhZGVBbmltYXRlZCkge1xuXHRcdFx0XHRMLlV0aWwucmVxdWVzdEFuaW1GcmFtZSh0aGlzLl9wcnVuZVRpbGVzLCB0aGlzKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIFdhaXQgYSBiaXQgbW9yZSB0aGFuIDAuMiBzZWNzICh0aGUgZHVyYXRpb24gb2YgdGhlIHRpbGUgZmFkZS1pbilcblx0XHRcdFx0Ly8gdG8gdHJpZ2dlciBhIHBydW5pbmcuXG5cdFx0XHRcdHNldFRpbWVvdXQoTC5iaW5kKHRoaXMuX3BydW5lVGlsZXMsIHRoaXMpLCAyNTApO1xuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHRfZ2V0VGlsZVBvczogZnVuY3Rpb24gKGNvb3Jkcykge1xuXHRcdHJldHVybiBjb29yZHMuc2NhbGVCeSh0aGlzLmdldFRpbGVTaXplKCkpLnN1YnRyYWN0KHRoaXMuX2xldmVsLm9yaWdpbik7XG5cdH0sXG5cblx0X3dyYXBDb29yZHM6IGZ1bmN0aW9uIChjb29yZHMpIHtcblx0XHR2YXIgbmV3Q29vcmRzID0gbmV3IEwuUG9pbnQoXG5cdFx0XHR0aGlzLl93cmFwWCA/IEwuVXRpbC53cmFwTnVtKGNvb3Jkcy54LCB0aGlzLl93cmFwWCkgOiBjb29yZHMueCxcblx0XHRcdHRoaXMuX3dyYXBZID8gTC5VdGlsLndyYXBOdW0oY29vcmRzLnksIHRoaXMuX3dyYXBZKSA6IGNvb3Jkcy55KTtcblx0XHRuZXdDb29yZHMueiA9IGNvb3Jkcy56O1xuXHRcdHJldHVybiBuZXdDb29yZHM7XG5cdH0sXG5cblx0X3B4Qm91bmRzVG9UaWxlUmFuZ2U6IGZ1bmN0aW9uIChib3VuZHMpIHtcblx0XHR2YXIgdGlsZVNpemUgPSB0aGlzLmdldFRpbGVTaXplKCk7XG5cdFx0cmV0dXJuIG5ldyBMLkJvdW5kcyhcblx0XHRcdGJvdW5kcy5taW4udW5zY2FsZUJ5KHRpbGVTaXplKS5mbG9vcigpLFxuXHRcdFx0Ym91bmRzLm1heC51bnNjYWxlQnkodGlsZVNpemUpLmNlaWwoKS5zdWJ0cmFjdChbMSwgMV0pKTtcblx0fSxcblxuXHRfbm9UaWxlc1RvTG9hZDogZnVuY3Rpb24gKCkge1xuXHRcdGZvciAodmFyIGtleSBpbiB0aGlzLl90aWxlcykge1xuXHRcdFx0aWYgKCF0aGlzLl90aWxlc1trZXldLmxvYWRlZCkgeyByZXR1cm4gZmFsc2U7IH1cblx0XHR9XG5cdFx0cmV0dXJuIHRydWU7XG5cdH1cbn0pO1xuXG4vLyBAZmFjdG9yeSBMLmdyaWRMYXllcihvcHRpb25zPzogR3JpZExheWVyIG9wdGlvbnMpXG4vLyBDcmVhdGVzIGEgbmV3IGluc3RhbmNlIG9mIEdyaWRMYXllciB3aXRoIHRoZSBzdXBwbGllZCBvcHRpb25zLlxuTC5ncmlkTGF5ZXIgPSBmdW5jdGlvbiAob3B0aW9ucykge1xuXHRyZXR1cm4gbmV3IEwuR3JpZExheWVyKG9wdGlvbnMpO1xufTtcblxuXG5cbi8qXHJcbiAqIEBjbGFzcyBUaWxlTGF5ZXJcclxuICogQGluaGVyaXRzIEdyaWRMYXllclxyXG4gKiBAYWthIEwuVGlsZUxheWVyXHJcbiAqIFVzZWQgdG8gbG9hZCBhbmQgZGlzcGxheSB0aWxlIGxheWVycyBvbiB0aGUgbWFwLiBFeHRlbmRzIGBHcmlkTGF5ZXJgLlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiBMLnRpbGVMYXllcignaHR0cDovL3tzfS50aWxlLm9zbS5vcmcve3p9L3t4fS97eX0ucG5nP3tmb299Jywge2ZvbzogJ2Jhcid9KS5hZGRUbyhtYXApO1xyXG4gKiBgYGBcclxuICpcclxuICogQHNlY3Rpb24gVVJMIHRlbXBsYXRlXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIEEgc3RyaW5nIG9mIHRoZSBmb2xsb3dpbmcgZm9ybTpcclxuICpcclxuICogYGBgXHJcbiAqICdodHRwOi8ve3N9LnNvbWVkb21haW4uY29tL2JsYWJsYS97en0ve3h9L3t5fXtyfS5wbmcnXHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBge3N9YCBtZWFucyBvbmUgb2YgdGhlIGF2YWlsYWJsZSBzdWJkb21haW5zICh1c2VkIHNlcXVlbnRpYWxseSB0byBoZWxwIHdpdGggYnJvd3NlciBwYXJhbGxlbCByZXF1ZXN0cyBwZXIgZG9tYWluIGxpbWl0YXRpb247IHN1YmRvbWFpbiB2YWx1ZXMgYXJlIHNwZWNpZmllZCBpbiBvcHRpb25zOyBgYWAsIGBiYCBvciBgY2AgYnkgZGVmYXVsdCwgY2FuIGJlIG9taXR0ZWQpLCBge3p9YCDigJQgem9vbSBsZXZlbCwgYHt4fWAgYW5kIGB7eX1gIOKAlCB0aWxlIGNvb3JkaW5hdGVzLiBge3J9YCBjYW4gYmUgdXNlZCB0byBhZGQgQDJ4IHRvIHRoZSBVUkwgdG8gbG9hZCByZXRpbmEgdGlsZXMuXHJcbiAqXHJcbiAqIFlvdSBjYW4gdXNlIGN1c3RvbSBrZXlzIGluIHRoZSB0ZW1wbGF0ZSwgd2hpY2ggd2lsbCBiZSBbZXZhbHVhdGVkXSgjdXRpbC10ZW1wbGF0ZSkgZnJvbSBUaWxlTGF5ZXIgb3B0aW9ucywgbGlrZSB0aGlzOlxyXG4gKlxyXG4gKiBgYGBcclxuICogTC50aWxlTGF5ZXIoJ2h0dHA6Ly97c30uc29tZWRvbWFpbi5jb20ve2Zvb30ve3p9L3t4fS97eX0ucG5nJywge2ZvbzogJ2Jhcid9KTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxuXHJcbkwuVGlsZUxheWVyID0gTC5HcmlkTGF5ZXIuZXh0ZW5kKHtcclxuXHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIFRpbGVMYXllciBvcHRpb25zXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQG9wdGlvbiBtaW5ab29tOiBOdW1iZXIgPSAwXHJcblx0XHQvLyBNaW5pbXVtIHpvb20gbnVtYmVyLlxyXG5cdFx0bWluWm9vbTogMCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIG1heFpvb206IE51bWJlciA9IDE4XHJcblx0XHQvLyBNYXhpbXVtIHpvb20gbnVtYmVyLlxyXG5cdFx0bWF4Wm9vbTogMTgsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBtYXhOYXRpdmVab29tOiBOdW1iZXIgPSBudWxsXHJcblx0XHQvLyBNYXhpbXVtIHpvb20gbnVtYmVyIHRoZSB0aWxlIHNvdXJjZSBoYXMgYXZhaWxhYmxlLiBJZiBpdCBpcyBzcGVjaWZpZWQsXHJcblx0XHQvLyB0aGUgdGlsZXMgb24gYWxsIHpvb20gbGV2ZWxzIGhpZ2hlciB0aGFuIGBtYXhOYXRpdmVab29tYCB3aWxsIGJlIGxvYWRlZFxyXG5cdFx0Ly8gZnJvbSBgbWF4TmF0aXZlWm9vbWAgbGV2ZWwgYW5kIGF1dG8tc2NhbGVkLlxyXG5cdFx0bWF4TmF0aXZlWm9vbTogbnVsbCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIG1pbk5hdGl2ZVpvb206IE51bWJlciA9IG51bGxcclxuXHRcdC8vIE1pbmltdW0gem9vbSBudW1iZXIgdGhlIHRpbGUgc291cmNlIGhhcyBhdmFpbGFibGUuIElmIGl0IGlzIHNwZWNpZmllZCxcclxuXHRcdC8vIHRoZSB0aWxlcyBvbiBhbGwgem9vbSBsZXZlbHMgbG93ZXIgdGhhbiBgbWluTmF0aXZlWm9vbWAgd2lsbCBiZSBsb2FkZWRcclxuXHRcdC8vIGZyb20gYG1pbk5hdGl2ZVpvb21gIGxldmVsIGFuZCBhdXRvLXNjYWxlZC5cclxuXHRcdG1pbk5hdGl2ZVpvb206IG51bGwsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBzdWJkb21haW5zOiBTdHJpbmd8U3RyaW5nW10gPSAnYWJjJ1xyXG5cdFx0Ly8gU3ViZG9tYWlucyBvZiB0aGUgdGlsZSBzZXJ2aWNlLiBDYW4gYmUgcGFzc2VkIGluIHRoZSBmb3JtIG9mIG9uZSBzdHJpbmcgKHdoZXJlIGVhY2ggbGV0dGVyIGlzIGEgc3ViZG9tYWluIG5hbWUpIG9yIGFuIGFycmF5IG9mIHN0cmluZ3MuXHJcblx0XHRzdWJkb21haW5zOiAnYWJjJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGVycm9yVGlsZVVybDogU3RyaW5nID0gJydcclxuXHRcdC8vIFVSTCB0byB0aGUgdGlsZSBpbWFnZSB0byBzaG93IGluIHBsYWNlIG9mIHRoZSB0aWxlIHRoYXQgZmFpbGVkIHRvIGxvYWQuXHJcblx0XHRlcnJvclRpbGVVcmw6ICcnLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gem9vbU9mZnNldDogTnVtYmVyID0gMFxyXG5cdFx0Ly8gVGhlIHpvb20gbnVtYmVyIHVzZWQgaW4gdGlsZSBVUkxzIHdpbGwgYmUgb2Zmc2V0IHdpdGggdGhpcyB2YWx1ZS5cclxuXHRcdHpvb21PZmZzZXQ6IDAsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiB0bXM6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gSWYgYHRydWVgLCBpbnZlcnNlcyBZIGF4aXMgbnVtYmVyaW5nIGZvciB0aWxlcyAodHVybiB0aGlzIG9uIGZvciBbVE1TXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9UaWxlX01hcF9TZXJ2aWNlKSBzZXJ2aWNlcykuXHJcblx0XHR0bXM6IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gem9vbVJldmVyc2U6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gSWYgc2V0IHRvIHRydWUsIHRoZSB6b29tIG51bWJlciB1c2VkIGluIHRpbGUgVVJMcyB3aWxsIGJlIHJldmVyc2VkIChgbWF4Wm9vbSAtIHpvb21gIGluc3RlYWQgb2YgYHpvb21gKVxyXG5cdFx0em9vbVJldmVyc2U6IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gZGV0ZWN0UmV0aW5hOiBCb29sZWFuID0gZmFsc2VcclxuXHRcdC8vIElmIGB0cnVlYCBhbmQgdXNlciBpcyBvbiBhIHJldGluYSBkaXNwbGF5LCBpdCB3aWxsIHJlcXVlc3QgZm91ciB0aWxlcyBvZiBoYWxmIHRoZSBzcGVjaWZpZWQgc2l6ZSBhbmQgYSBiaWdnZXIgem9vbSBsZXZlbCBpbiBwbGFjZSBvZiBvbmUgdG8gdXRpbGl6ZSB0aGUgaGlnaCByZXNvbHV0aW9uLlxyXG5cdFx0ZGV0ZWN0UmV0aW5hOiBmYWxzZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGNyb3NzT3JpZ2luOiBCb29sZWFuID0gZmFsc2VcclxuXHRcdC8vIElmIHRydWUsIGFsbCB0aWxlcyB3aWxsIGhhdmUgdGhlaXIgY3Jvc3NPcmlnaW4gYXR0cmlidXRlIHNldCB0byAnJy4gVGhpcyBpcyBuZWVkZWQgaWYgeW91IHdhbnQgdG8gYWNjZXNzIHRpbGUgcGl4ZWwgZGF0YS5cclxuXHRcdGNyb3NzT3JpZ2luOiBmYWxzZVxyXG5cdH0sXHJcblxyXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uICh1cmwsIG9wdGlvbnMpIHtcclxuXHJcblx0XHR0aGlzLl91cmwgPSB1cmw7XHJcblxyXG5cdFx0b3B0aW9ucyA9IEwuc2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcclxuXHJcblx0XHQvLyBkZXRlY3RpbmcgcmV0aW5hIGRpc3BsYXlzLCBhZGp1c3RpbmcgdGlsZVNpemUgYW5kIHpvb20gbGV2ZWxzXHJcblx0XHRpZiAob3B0aW9ucy5kZXRlY3RSZXRpbmEgJiYgTC5Ccm93c2VyLnJldGluYSAmJiBvcHRpb25zLm1heFpvb20gPiAwKSB7XHJcblxyXG5cdFx0XHRvcHRpb25zLnRpbGVTaXplID0gTWF0aC5mbG9vcihvcHRpb25zLnRpbGVTaXplIC8gMik7XHJcblxyXG5cdFx0XHRpZiAoIW9wdGlvbnMuem9vbVJldmVyc2UpIHtcclxuXHRcdFx0XHRvcHRpb25zLnpvb21PZmZzZXQrKztcclxuXHRcdFx0XHRvcHRpb25zLm1heFpvb20tLTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRvcHRpb25zLnpvb21PZmZzZXQtLTtcclxuXHRcdFx0XHRvcHRpb25zLm1pblpvb20rKztcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0b3B0aW9ucy5taW5ab29tID0gTWF0aC5tYXgoMCwgb3B0aW9ucy5taW5ab29tKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodHlwZW9mIG9wdGlvbnMuc3ViZG9tYWlucyA9PT0gJ3N0cmluZycpIHtcclxuXHRcdFx0b3B0aW9ucy5zdWJkb21haW5zID0gb3B0aW9ucy5zdWJkb21haW5zLnNwbGl0KCcnKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBmb3IgaHR0cHM6Ly9naXRodWIuY29tL0xlYWZsZXQvTGVhZmxldC9pc3N1ZXMvMTM3XHJcblx0XHRpZiAoIUwuQnJvd3Nlci5hbmRyb2lkKSB7XHJcblx0XHRcdHRoaXMub24oJ3RpbGV1bmxvYWQnLCB0aGlzLl9vblRpbGVSZW1vdmUpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0VXJsKHVybDogU3RyaW5nLCBub1JlZHJhdz86IEJvb2xlYW4pOiB0aGlzXHJcblx0Ly8gVXBkYXRlcyB0aGUgbGF5ZXIncyBVUkwgdGVtcGxhdGUgYW5kIHJlZHJhd3MgaXQgKHVubGVzcyBgbm9SZWRyYXdgIGlzIHNldCB0byBgdHJ1ZWApLlxyXG5cdHNldFVybDogZnVuY3Rpb24gKHVybCwgbm9SZWRyYXcpIHtcclxuXHRcdHRoaXMuX3VybCA9IHVybDtcclxuXHJcblx0XHRpZiAoIW5vUmVkcmF3KSB7XHJcblx0XHRcdHRoaXMucmVkcmF3KCk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGNyZWF0ZVRpbGUoY29vcmRzOiBPYmplY3QsIGRvbmU/OiBGdW5jdGlvbik6IEhUTUxFbGVtZW50XHJcblx0Ly8gQ2FsbGVkIG9ubHkgaW50ZXJuYWxseSwgb3ZlcnJpZGVzIEdyaWRMYXllcidzIFtgY3JlYXRlVGlsZSgpYF0oI2dyaWRsYXllci1jcmVhdGV0aWxlKVxyXG5cdC8vIHRvIHJldHVybiBhbiBgPGltZz5gIEhUTUwgZWxlbWVudCB3aXRoIHRoZSBhcHByb3BpYXRlIGltYWdlIFVSTCBnaXZlbiBgY29vcmRzYC4gVGhlIGBkb25lYFxyXG5cdC8vIGNhbGxiYWNrIGlzIGNhbGxlZCB3aGVuIHRoZSB0aWxlIGhhcyBiZWVuIGxvYWRlZC5cclxuXHRjcmVhdGVUaWxlOiBmdW5jdGlvbiAoY29vcmRzLCBkb25lKSB7XHJcblx0XHR2YXIgdGlsZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2ltZycpO1xyXG5cclxuXHRcdEwuRG9tRXZlbnQub24odGlsZSwgJ2xvYWQnLCBMLmJpbmQodGhpcy5fdGlsZU9uTG9hZCwgdGhpcywgZG9uZSwgdGlsZSkpO1xyXG5cdFx0TC5Eb21FdmVudC5vbih0aWxlLCAnZXJyb3InLCBMLmJpbmQodGhpcy5fdGlsZU9uRXJyb3IsIHRoaXMsIGRvbmUsIHRpbGUpKTtcclxuXHJcblx0XHRpZiAodGhpcy5vcHRpb25zLmNyb3NzT3JpZ2luKSB7XHJcblx0XHRcdHRpbGUuY3Jvc3NPcmlnaW4gPSAnJztcclxuXHRcdH1cclxuXHJcblx0XHQvKlxyXG5cdFx0IEFsdCB0YWcgaXMgc2V0IHRvIGVtcHR5IHN0cmluZyB0byBrZWVwIHNjcmVlbiByZWFkZXJzIGZyb20gcmVhZGluZyBVUkwgYW5kIGZvciBjb21wbGlhbmNlIHJlYXNvbnNcclxuXHRcdCBodHRwOi8vd3d3LnczLm9yZy9UUi9XQ0FHMjAtVEVDSFMvSDY3XHJcblx0XHQqL1xyXG5cdFx0dGlsZS5hbHQgPSAnJztcclxuXHJcblx0XHQvKlxyXG5cdFx0IFNldCByb2xlPVwicHJlc2VudGF0aW9uXCIgdG8gZm9yY2Ugc2NyZWVuIHJlYWRlcnMgdG8gaWdub3JlIHRoaXNcclxuXHRcdCBodHRwczovL3d3dy53My5vcmcvVFIvd2FpLWFyaWEvcm9sZXMjdGV4dGFsdGVybmF0aXZlY29tcHV0YXRpb25cclxuXHRcdCovXHJcblx0XHR0aWxlLnNldEF0dHJpYnV0ZSgncm9sZScsICdwcmVzZW50YXRpb24nKTtcclxuXHJcblx0XHR0aWxlLnNyYyA9IHRoaXMuZ2V0VGlsZVVybChjb29yZHMpO1xyXG5cclxuXHRcdHJldHVybiB0aWxlO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBzZWN0aW9uIEV4dGVuc2lvbiBtZXRob2RzXHJcblx0Ly8gQHVuaW5oZXJpdGFibGVcclxuXHQvLyBMYXllcnMgZXh0ZW5kaW5nIGBUaWxlTGF5ZXJgIG1pZ2h0IHJlaW1wbGVtZW50IHRoZSBmb2xsb3dpbmcgbWV0aG9kLlxyXG5cdC8vIEBtZXRob2QgZ2V0VGlsZVVybChjb29yZHM6IE9iamVjdCk6IFN0cmluZ1xyXG5cdC8vIENhbGxlZCBvbmx5IGludGVybmFsbHksIHJldHVybnMgdGhlIFVSTCBmb3IgYSB0aWxlIGdpdmVuIGl0cyBjb29yZGluYXRlcy5cclxuXHQvLyBDbGFzc2VzIGV4dGVuZGluZyBgVGlsZUxheWVyYCBjYW4gb3ZlcnJpZGUgdGhpcyBmdW5jdGlvbiB0byBwcm92aWRlIGN1c3RvbSB0aWxlIFVSTCBuYW1pbmcgc2NoZW1lcy5cclxuXHRnZXRUaWxlVXJsOiBmdW5jdGlvbiAoY29vcmRzKSB7XHJcblx0XHR2YXIgZGF0YSA9IHtcclxuXHRcdFx0cjogTC5Ccm93c2VyLnJldGluYSA/ICdAMngnIDogJycsXHJcblx0XHRcdHM6IHRoaXMuX2dldFN1YmRvbWFpbihjb29yZHMpLFxyXG5cdFx0XHR4OiBjb29yZHMueCxcclxuXHRcdFx0eTogY29vcmRzLnksXHJcblx0XHRcdHo6IHRoaXMuX2dldFpvb21Gb3JVcmwoKVxyXG5cdFx0fTtcclxuXHRcdGlmICh0aGlzLl9tYXAgJiYgIXRoaXMuX21hcC5vcHRpb25zLmNycy5pbmZpbml0ZSkge1xyXG5cdFx0XHR2YXIgaW52ZXJ0ZWRZID0gdGhpcy5fZ2xvYmFsVGlsZVJhbmdlLm1heC55IC0gY29vcmRzLnk7XHJcblx0XHRcdGlmICh0aGlzLm9wdGlvbnMudG1zKSB7XHJcblx0XHRcdFx0ZGF0YVsneSddID0gaW52ZXJ0ZWRZO1xyXG5cdFx0XHR9XHJcblx0XHRcdGRhdGFbJy15J10gPSBpbnZlcnRlZFk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIEwuVXRpbC50ZW1wbGF0ZSh0aGlzLl91cmwsIEwuZXh0ZW5kKGRhdGEsIHRoaXMub3B0aW9ucykpO1xyXG5cdH0sXHJcblxyXG5cdF90aWxlT25Mb2FkOiBmdW5jdGlvbiAoZG9uZSwgdGlsZSkge1xyXG5cdFx0Ly8gRm9yIGh0dHBzOi8vZ2l0aHViLmNvbS9MZWFmbGV0L0xlYWZsZXQvaXNzdWVzLzMzMzJcclxuXHRcdGlmIChMLkJyb3dzZXIuaWVsdDkpIHtcclxuXHRcdFx0c2V0VGltZW91dChMLmJpbmQoZG9uZSwgdGhpcywgbnVsbCwgdGlsZSksIDApO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0ZG9uZShudWxsLCB0aWxlKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfdGlsZU9uRXJyb3I6IGZ1bmN0aW9uIChkb25lLCB0aWxlLCBlKSB7XHJcblx0XHR2YXIgZXJyb3JVcmwgPSB0aGlzLm9wdGlvbnMuZXJyb3JUaWxlVXJsO1xyXG5cdFx0aWYgKGVycm9yVXJsKSB7XHJcblx0XHRcdHRpbGUuc3JjID0gZXJyb3JVcmw7XHJcblx0XHR9XHJcblx0XHRkb25lKGUsIHRpbGUpO1xyXG5cdH0sXHJcblxyXG5cdGdldFRpbGVTaXplOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxyXG5cdFx0dGlsZVNpemUgPSBMLkdyaWRMYXllci5wcm90b3R5cGUuZ2V0VGlsZVNpemUuY2FsbCh0aGlzKSxcclxuXHRcdHpvb20gPSB0aGlzLl90aWxlWm9vbSArIHRoaXMub3B0aW9ucy56b29tT2Zmc2V0LFxyXG5cdFx0bWluTmF0aXZlWm9vbSA9IHRoaXMub3B0aW9ucy5taW5OYXRpdmVab29tLFxyXG5cdFx0bWF4TmF0aXZlWm9vbSA9IHRoaXMub3B0aW9ucy5tYXhOYXRpdmVab29tO1xyXG5cclxuXHRcdC8vIGRlY3JlYXNlIHRpbGUgc2l6ZSB3aGVuIHNjYWxpbmcgYmVsb3cgbWluTmF0aXZlWm9vbVxyXG5cdFx0aWYgKG1pbk5hdGl2ZVpvb20gIT09IG51bGwgJiYgem9vbSA8IG1pbk5hdGl2ZVpvb20pIHtcclxuXHRcdFx0cmV0dXJuIHRpbGVTaXplLmRpdmlkZUJ5KG1hcC5nZXRab29tU2NhbGUobWluTmF0aXZlWm9vbSwgem9vbSkpLnJvdW5kKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gaW5jcmVhc2UgdGlsZSBzaXplIHdoZW4gc2NhbGluZyBhYm92ZSBtYXhOYXRpdmVab29tXHJcblx0XHRpZiAobWF4TmF0aXZlWm9vbSAhPT0gbnVsbCAmJiB6b29tID4gbWF4TmF0aXZlWm9vbSkge1xyXG5cdFx0XHRyZXR1cm4gdGlsZVNpemUuZGl2aWRlQnkobWFwLmdldFpvb21TY2FsZShtYXhOYXRpdmVab29tLCB6b29tKSkucm91bmQoKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGlsZVNpemU7XHJcblx0fSxcclxuXHJcblx0X29uVGlsZVJlbW92ZTogZnVuY3Rpb24gKGUpIHtcclxuXHRcdGUudGlsZS5vbmxvYWQgPSBudWxsO1xyXG5cdH0sXHJcblxyXG5cdF9nZXRab29tRm9yVXJsOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgem9vbSA9IHRoaXMuX3RpbGVab29tLFxyXG5cdFx0bWF4Wm9vbSA9IHRoaXMub3B0aW9ucy5tYXhab29tLFxyXG5cdFx0em9vbVJldmVyc2UgPSB0aGlzLm9wdGlvbnMuem9vbVJldmVyc2UsXHJcblx0XHR6b29tT2Zmc2V0ID0gdGhpcy5vcHRpb25zLnpvb21PZmZzZXQsXHJcblx0XHRtaW5OYXRpdmVab29tID0gdGhpcy5vcHRpb25zLm1pbk5hdGl2ZVpvb20sXHJcblx0XHRtYXhOYXRpdmVab29tID0gdGhpcy5vcHRpb25zLm1heE5hdGl2ZVpvb207XHJcblxyXG5cdFx0aWYgKHpvb21SZXZlcnNlKSB7XHJcblx0XHRcdHpvb20gPSBtYXhab29tIC0gem9vbTtcclxuXHRcdH1cclxuXHJcblx0XHR6b29tICs9IHpvb21PZmZzZXQ7XHJcblxyXG5cdFx0aWYgKG1pbk5hdGl2ZVpvb20gIT09IG51bGwgJiYgem9vbSA8IG1pbk5hdGl2ZVpvb20pIHtcclxuXHRcdFx0cmV0dXJuIG1pbk5hdGl2ZVpvb207XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKG1heE5hdGl2ZVpvb20gIT09IG51bGwgJiYgem9vbSA+IG1heE5hdGl2ZVpvb20pIHtcclxuXHRcdFx0cmV0dXJuIG1heE5hdGl2ZVpvb207XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHpvb207XHJcblx0fSxcclxuXHJcblx0X2dldFN1YmRvbWFpbjogZnVuY3Rpb24gKHRpbGVQb2ludCkge1xyXG5cdFx0dmFyIGluZGV4ID0gTWF0aC5hYnModGlsZVBvaW50LnggKyB0aWxlUG9pbnQueSkgJSB0aGlzLm9wdGlvbnMuc3ViZG9tYWlucy5sZW5ndGg7XHJcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLnN1YmRvbWFpbnNbaW5kZXhdO1xyXG5cdH0sXHJcblxyXG5cdC8vIHN0b3BzIGxvYWRpbmcgYWxsIHRpbGVzIGluIHRoZSBiYWNrZ3JvdW5kIGxheWVyXHJcblx0X2Fib3J0TG9hZGluZzogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGksIHRpbGU7XHJcblx0XHRmb3IgKGkgaW4gdGhpcy5fdGlsZXMpIHtcclxuXHRcdFx0aWYgKHRoaXMuX3RpbGVzW2ldLmNvb3Jkcy56ICE9PSB0aGlzLl90aWxlWm9vbSkge1xyXG5cdFx0XHRcdHRpbGUgPSB0aGlzLl90aWxlc1tpXS5lbDtcclxuXHJcblx0XHRcdFx0dGlsZS5vbmxvYWQgPSBMLlV0aWwuZmFsc2VGbjtcclxuXHRcdFx0XHR0aWxlLm9uZXJyb3IgPSBMLlV0aWwuZmFsc2VGbjtcclxuXHJcblx0XHRcdFx0aWYgKCF0aWxlLmNvbXBsZXRlKSB7XHJcblx0XHRcdFx0XHR0aWxlLnNyYyA9IEwuVXRpbC5lbXB0eUltYWdlVXJsO1xyXG5cdFx0XHRcdFx0TC5Eb21VdGlsLnJlbW92ZSh0aWxlKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9XHJcbn0pO1xyXG5cclxuXHJcbi8vIEBmYWN0b3J5IEwudGlsZWxheWVyKHVybFRlbXBsYXRlOiBTdHJpbmcsIG9wdGlvbnM/OiBUaWxlTGF5ZXIgb3B0aW9ucylcclxuLy8gSW5zdGFudGlhdGVzIGEgdGlsZSBsYXllciBvYmplY3QgZ2l2ZW4gYSBgVVJMIHRlbXBsYXRlYCBhbmQgb3B0aW9uYWxseSBhbiBvcHRpb25zIG9iamVjdC5cclxuXHJcbkwudGlsZUxheWVyID0gZnVuY3Rpb24gKHVybCwgb3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgTC5UaWxlTGF5ZXIodXJsLCBvcHRpb25zKTtcclxufTtcclxuXG5cblxuLypcclxuICogQGNsYXNzIFRpbGVMYXllci5XTVNcclxuICogQGluaGVyaXRzIFRpbGVMYXllclxyXG4gKiBAYWthIEwuVGlsZUxheWVyLldNU1xyXG4gKiBVc2VkIHRvIGRpc3BsYXkgW1dNU10oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvV2ViX01hcF9TZXJ2aWNlKSBzZXJ2aWNlcyBhcyB0aWxlIGxheWVycyBvbiB0aGUgbWFwLiBFeHRlbmRzIGBUaWxlTGF5ZXJgLlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiB2YXIgbmV4cmFkID0gTC50aWxlTGF5ZXIud21zKFwiaHR0cDovL21lc29uZXQuYWdyb24uaWFzdGF0ZS5lZHUvY2dpLWJpbi93bXMvbmV4cmFkL24wci5jZ2lcIiwge1xyXG4gKiBcdGxheWVyczogJ25leHJhZC1uMHItOTAwOTEzJyxcclxuICogXHRmb3JtYXQ6ICdpbWFnZS9wbmcnLFxyXG4gKiBcdHRyYW5zcGFyZW50OiB0cnVlLFxyXG4gKiBcdGF0dHJpYnV0aW9uOiBcIldlYXRoZXIgZGF0YSDCqSAyMDEyIElFTSBOZXhyYWRcIlxyXG4gKiB9KTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxuTC5UaWxlTGF5ZXIuV01TID0gTC5UaWxlTGF5ZXIuZXh0ZW5kKHtcclxuXHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIFRpbGVMYXllci5XTVMgb3B0aW9uc1xyXG5cdC8vIElmIGFueSBjdXN0b20gb3B0aW9ucyBub3QgZG9jdW1lbnRlZCBoZXJlIGFyZSB1c2VkLCB0aGV5IHdpbGwgYmUgc2VudCB0byB0aGVcclxuXHQvLyBXTVMgc2VydmVyIGFzIGV4dHJhIHBhcmFtZXRlcnMgaW4gZWFjaCByZXF1ZXN0IFVSTC4gVGhpcyBjYW4gYmUgdXNlZnVsIGZvclxyXG5cdC8vIFtub24tc3RhbmRhcmQgdmVuZG9yIFdNUyBwYXJhbWV0ZXJzXShodHRwOi8vZG9jcy5nZW9zZXJ2ZXIub3JnL3N0YWJsZS9lbi91c2VyL3NlcnZpY2VzL3dtcy92ZW5kb3IuaHRtbCkuXHJcblx0ZGVmYXVsdFdtc1BhcmFtczoge1xyXG5cdFx0c2VydmljZTogJ1dNUycsXHJcblx0XHRyZXF1ZXN0OiAnR2V0TWFwJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGxheWVyczogU3RyaW5nID0gJydcclxuXHRcdC8vICoqKHJlcXVpcmVkKSoqIENvbW1hLXNlcGFyYXRlZCBsaXN0IG9mIFdNUyBsYXllcnMgdG8gc2hvdy5cclxuXHRcdGxheWVyczogJycsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBzdHlsZXM6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBDb21tYS1zZXBhcmF0ZWQgbGlzdCBvZiBXTVMgc3R5bGVzLlxyXG5cdFx0c3R5bGVzOiAnJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGZvcm1hdDogU3RyaW5nID0gJ2ltYWdlL2pwZWcnXHJcblx0XHQvLyBXTVMgaW1hZ2UgZm9ybWF0ICh1c2UgYCdpbWFnZS9wbmcnYCBmb3IgbGF5ZXJzIHdpdGggdHJhbnNwYXJlbmN5KS5cclxuXHRcdGZvcm1hdDogJ2ltYWdlL2pwZWcnLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gdHJhbnNwYXJlbnQ6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gSWYgYHRydWVgLCB0aGUgV01TIHNlcnZpY2Ugd2lsbCByZXR1cm4gaW1hZ2VzIHdpdGggdHJhbnNwYXJlbmN5LlxyXG5cdFx0dHJhbnNwYXJlbnQ6IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gdmVyc2lvbjogU3RyaW5nID0gJzEuMS4xJ1xyXG5cdFx0Ly8gVmVyc2lvbiBvZiB0aGUgV01TIHNlcnZpY2UgdG8gdXNlXHJcblx0XHR2ZXJzaW9uOiAnMS4xLjEnXHJcblx0fSxcclxuXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQG9wdGlvbiBjcnM6IENSUyA9IG51bGxcclxuXHRcdC8vIENvb3JkaW5hdGUgUmVmZXJlbmNlIFN5c3RlbSB0byB1c2UgZm9yIHRoZSBXTVMgcmVxdWVzdHMsIGRlZmF1bHRzIHRvXHJcblx0XHQvLyBtYXAgQ1JTLiBEb24ndCBjaGFuZ2UgdGhpcyBpZiB5b3UncmUgbm90IHN1cmUgd2hhdCBpdCBtZWFucy5cclxuXHRcdGNyczogbnVsbCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHVwcGVyY2FzZTogQm9vbGVhbiA9IGZhbHNlXHJcblx0XHQvLyBJZiBgdHJ1ZWAsIFdNUyByZXF1ZXN0IHBhcmFtZXRlciBrZXlzIHdpbGwgYmUgdXBwZXJjYXNlLlxyXG5cdFx0dXBwZXJjYXNlOiBmYWxzZVxyXG5cdH0sXHJcblxyXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uICh1cmwsIG9wdGlvbnMpIHtcclxuXHJcblx0XHR0aGlzLl91cmwgPSB1cmw7XHJcblxyXG5cdFx0dmFyIHdtc1BhcmFtcyA9IEwuZXh0ZW5kKHt9LCB0aGlzLmRlZmF1bHRXbXNQYXJhbXMpO1xyXG5cclxuXHRcdC8vIGFsbCBrZXlzIHRoYXQgYXJlIG5vdCBUaWxlTGF5ZXIgb3B0aW9ucyBnbyB0byBXTVMgcGFyYW1zXHJcblx0XHRmb3IgKHZhciBpIGluIG9wdGlvbnMpIHtcclxuXHRcdFx0aWYgKCEoaSBpbiB0aGlzLm9wdGlvbnMpKSB7XHJcblx0XHRcdFx0d21zUGFyYW1zW2ldID0gb3B0aW9uc1tpXTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdG9wdGlvbnMgPSBMLnNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XHJcblxyXG5cdFx0d21zUGFyYW1zLndpZHRoID0gd21zUGFyYW1zLmhlaWdodCA9IG9wdGlvbnMudGlsZVNpemUgKiAob3B0aW9ucy5kZXRlY3RSZXRpbmEgJiYgTC5Ccm93c2VyLnJldGluYSA/IDIgOiAxKTtcclxuXHJcblx0XHR0aGlzLndtc1BhcmFtcyA9IHdtc1BhcmFtcztcclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKG1hcCkge1xyXG5cclxuXHRcdHRoaXMuX2NycyA9IHRoaXMub3B0aW9ucy5jcnMgfHwgbWFwLm9wdGlvbnMuY3JzO1xyXG5cdFx0dGhpcy5fd21zVmVyc2lvbiA9IHBhcnNlRmxvYXQodGhpcy53bXNQYXJhbXMudmVyc2lvbik7XHJcblxyXG5cdFx0dmFyIHByb2plY3Rpb25LZXkgPSB0aGlzLl93bXNWZXJzaW9uID49IDEuMyA/ICdjcnMnIDogJ3Nycyc7XHJcblx0XHR0aGlzLndtc1BhcmFtc1twcm9qZWN0aW9uS2V5XSA9IHRoaXMuX2Nycy5jb2RlO1xyXG5cclxuXHRcdEwuVGlsZUxheWVyLnByb3RvdHlwZS5vbkFkZC5jYWxsKHRoaXMsIG1hcCk7XHJcblx0fSxcclxuXHJcblx0Z2V0VGlsZVVybDogZnVuY3Rpb24gKGNvb3Jkcykge1xyXG5cclxuXHRcdHZhciB0aWxlQm91bmRzID0gdGhpcy5fdGlsZUNvb3Jkc1RvQm91bmRzKGNvb3JkcyksXHJcblx0XHQgICAgbncgPSB0aGlzLl9jcnMucHJvamVjdCh0aWxlQm91bmRzLmdldE5vcnRoV2VzdCgpKSxcclxuXHRcdCAgICBzZSA9IHRoaXMuX2Nycy5wcm9qZWN0KHRpbGVCb3VuZHMuZ2V0U291dGhFYXN0KCkpLFxyXG5cclxuXHRcdCAgICBiYm94ID0gKHRoaXMuX3dtc1ZlcnNpb24gPj0gMS4zICYmIHRoaXMuX2NycyA9PT0gTC5DUlMuRVBTRzQzMjYgP1xyXG5cdFx0XHQgICAgW3NlLnksIG53LngsIG53LnksIHNlLnhdIDpcclxuXHRcdFx0ICAgIFtudy54LCBzZS55LCBzZS54LCBudy55XSkuam9pbignLCcpLFxyXG5cclxuXHRcdCAgICB1cmwgPSBMLlRpbGVMYXllci5wcm90b3R5cGUuZ2V0VGlsZVVybC5jYWxsKHRoaXMsIGNvb3Jkcyk7XHJcblxyXG5cdFx0cmV0dXJuIHVybCArXHJcblx0XHRcdEwuVXRpbC5nZXRQYXJhbVN0cmluZyh0aGlzLndtc1BhcmFtcywgdXJsLCB0aGlzLm9wdGlvbnMudXBwZXJjYXNlKSArXHJcblx0XHRcdCh0aGlzLm9wdGlvbnMudXBwZXJjYXNlID8gJyZCQk9YPScgOiAnJmJib3g9JykgKyBiYm94O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0UGFyYW1zKHBhcmFtczogT2JqZWN0LCBub1JlZHJhdz86IEJvb2xlYW4pOiB0aGlzXHJcblx0Ly8gTWVyZ2VzIGFuIG9iamVjdCB3aXRoIHRoZSBuZXcgcGFyYW1ldGVycyBhbmQgcmUtcmVxdWVzdHMgdGlsZXMgb24gdGhlIGN1cnJlbnQgc2NyZWVuICh1bmxlc3MgYG5vUmVkcmF3YCB3YXMgc2V0IHRvIHRydWUpLlxyXG5cdHNldFBhcmFtczogZnVuY3Rpb24gKHBhcmFtcywgbm9SZWRyYXcpIHtcclxuXHJcblx0XHRMLmV4dGVuZCh0aGlzLndtc1BhcmFtcywgcGFyYW1zKTtcclxuXHJcblx0XHRpZiAoIW5vUmVkcmF3KSB7XHJcblx0XHRcdHRoaXMucmVkcmF3KCk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fVxyXG59KTtcclxuXHJcblxyXG4vLyBAZmFjdG9yeSBMLnRpbGVMYXllci53bXMoYmFzZVVybDogU3RyaW5nLCBvcHRpb25zOiBUaWxlTGF5ZXIuV01TIG9wdGlvbnMpXHJcbi8vIEluc3RhbnRpYXRlcyBhIFdNUyB0aWxlIGxheWVyIG9iamVjdCBnaXZlbiBhIGJhc2UgVVJMIG9mIHRoZSBXTVMgc2VydmljZSBhbmQgYSBXTVMgcGFyYW1ldGVycy9vcHRpb25zIG9iamVjdC5cclxuTC50aWxlTGF5ZXIud21zID0gZnVuY3Rpb24gKHVybCwgb3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgTC5UaWxlTGF5ZXIuV01TKHVybCwgb3B0aW9ucyk7XHJcbn07XHJcblxuXG5cbi8qXHJcbiAqIEBjbGFzcyBJbWFnZU92ZXJsYXlcclxuICogQGFrYSBMLkltYWdlT3ZlcmxheVxyXG4gKiBAaW5oZXJpdHMgSW50ZXJhY3RpdmUgbGF5ZXJcclxuICpcclxuICogVXNlZCB0byBsb2FkIGFuZCBkaXNwbGF5IGEgc2luZ2xlIGltYWdlIG92ZXIgc3BlY2lmaWMgYm91bmRzIG9mIHRoZSBtYXAuIEV4dGVuZHMgYExheWVyYC5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogYGBganNcclxuICogdmFyIGltYWdlVXJsID0gJ2h0dHA6Ly93d3cubGliLnV0ZXhhcy5lZHUvbWFwcy9oaXN0b3JpY2FsL25ld2Fya19ual8xOTIyLmpwZycsXHJcbiAqIFx0aW1hZ2VCb3VuZHMgPSBbWzQwLjcxMjIxNiwgLTc0LjIyNjU1XSwgWzQwLjc3Mzk0MSwgLTc0LjEyNTQ0XV07XHJcbiAqIEwuaW1hZ2VPdmVybGF5KGltYWdlVXJsLCBpbWFnZUJvdW5kcykuYWRkVG8obWFwKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxuTC5JbWFnZU92ZXJsYXkgPSBMLkxheWVyLmV4dGVuZCh7XHJcblxyXG5cdC8vIEBzZWN0aW9uXHJcblx0Ly8gQGFrYSBJbWFnZU92ZXJsYXkgb3B0aW9uc1xyXG5cdG9wdGlvbnM6IHtcclxuXHRcdC8vIEBvcHRpb24gb3BhY2l0eTogTnVtYmVyID0gMS4wXHJcblx0XHQvLyBUaGUgb3BhY2l0eSBvZiB0aGUgaW1hZ2Ugb3ZlcmxheS5cclxuXHRcdG9wYWNpdHk6IDEsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhbHQ6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBUZXh0IGZvciB0aGUgYGFsdGAgYXR0cmlidXRlIG9mIHRoZSBpbWFnZSAodXNlZnVsIGZvciBhY2Nlc3NpYmlsaXR5KS5cclxuXHRcdGFsdDogJycsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBpbnRlcmFjdGl2ZTogQm9vbGVhbiA9IGZhbHNlXHJcblx0XHQvLyBJZiBgdHJ1ZWAsIHRoZSBpbWFnZSBvdmVybGF5IHdpbGwgZW1pdCBbbW91c2UgZXZlbnRzXSgjaW50ZXJhY3RpdmUtbGF5ZXIpIHdoZW4gY2xpY2tlZCBvciBob3ZlcmVkLlxyXG5cdFx0aW50ZXJhY3RpdmU6IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gY3Jvc3NPcmlnaW46IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gSWYgdHJ1ZSwgdGhlIGltYWdlIHdpbGwgaGF2ZSBpdHMgY3Jvc3NPcmlnaW4gYXR0cmlidXRlIHNldCB0byAnJy4gVGhpcyBpcyBuZWVkZWQgaWYgeW91IHdhbnQgdG8gYWNjZXNzIGltYWdlIHBpeGVsIGRhdGEuXHJcblx0XHRjcm9zc09yaWdpbjogZmFsc2VcclxuXHR9LFxyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAodXJsLCBib3VuZHMsIG9wdGlvbnMpIHsgLy8gKFN0cmluZywgTGF0TG5nQm91bmRzLCBPYmplY3QpXHJcblx0XHR0aGlzLl91cmwgPSB1cmw7XHJcblx0XHR0aGlzLl9ib3VuZHMgPSBMLmxhdExuZ0JvdW5kcyhib3VuZHMpO1xyXG5cclxuXHRcdEwuc2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLl9pbWFnZSkge1xyXG5cdFx0XHR0aGlzLl9pbml0SW1hZ2UoKTtcclxuXHJcblx0XHRcdGlmICh0aGlzLm9wdGlvbnMub3BhY2l0eSA8IDEpIHtcclxuXHRcdFx0XHR0aGlzLl91cGRhdGVPcGFjaXR5KCk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5vcHRpb25zLmludGVyYWN0aXZlKSB7XHJcblx0XHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9pbWFnZSwgJ2xlYWZsZXQtaW50ZXJhY3RpdmUnKTtcclxuXHRcdFx0dGhpcy5hZGRJbnRlcmFjdGl2ZVRhcmdldCh0aGlzLl9pbWFnZSk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5nZXRQYW5lKCkuYXBwZW5kQ2hpbGQodGhpcy5faW1hZ2UpO1xyXG5cdFx0dGhpcy5fcmVzZXQoKTtcclxuXHR9LFxyXG5cclxuXHRvblJlbW92ZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0TC5Eb21VdGlsLnJlbW92ZSh0aGlzLl9pbWFnZSk7XHJcblx0XHRpZiAodGhpcy5vcHRpb25zLmludGVyYWN0aXZlKSB7XHJcblx0XHRcdHRoaXMucmVtb3ZlSW50ZXJhY3RpdmVUYXJnZXQodGhpcy5faW1hZ2UpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0T3BhY2l0eShvcGFjaXR5OiBOdW1iZXIpOiB0aGlzXHJcblx0Ly8gU2V0cyB0aGUgb3BhY2l0eSBvZiB0aGUgb3ZlcmxheS5cclxuXHRzZXRPcGFjaXR5OiBmdW5jdGlvbiAob3BhY2l0eSkge1xyXG5cdFx0dGhpcy5vcHRpb25zLm9wYWNpdHkgPSBvcGFjaXR5O1xyXG5cclxuXHRcdGlmICh0aGlzLl9pbWFnZSkge1xyXG5cdFx0XHR0aGlzLl91cGRhdGVPcGFjaXR5KCk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRzZXRTdHlsZTogZnVuY3Rpb24gKHN0eWxlT3B0cykge1xyXG5cdFx0aWYgKHN0eWxlT3B0cy5vcGFjaXR5KSB7XHJcblx0XHRcdHRoaXMuc2V0T3BhY2l0eShzdHlsZU9wdHMub3BhY2l0eSk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGJyaW5nVG9Gcm9udCgpOiB0aGlzXHJcblx0Ly8gQnJpbmdzIHRoZSBsYXllciB0byB0aGUgdG9wIG9mIGFsbCBvdmVybGF5cy5cclxuXHRicmluZ1RvRnJvbnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICh0aGlzLl9tYXApIHtcclxuXHRcdFx0TC5Eb21VdGlsLnRvRnJvbnQodGhpcy5faW1hZ2UpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBicmluZ1RvQmFjaygpOiB0aGlzXHJcblx0Ly8gQnJpbmdzIHRoZSBsYXllciB0byB0aGUgYm90dG9tIG9mIGFsbCBvdmVybGF5cy5cclxuXHRicmluZ1RvQmFjazogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKHRoaXMuX21hcCkge1xyXG5cdFx0XHRMLkRvbVV0aWwudG9CYWNrKHRoaXMuX2ltYWdlKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0VXJsKHVybDogU3RyaW5nKTogdGhpc1xyXG5cdC8vIENoYW5nZXMgdGhlIFVSTCBvZiB0aGUgaW1hZ2UuXHJcblx0c2V0VXJsOiBmdW5jdGlvbiAodXJsKSB7XHJcblx0XHR0aGlzLl91cmwgPSB1cmw7XHJcblxyXG5cdFx0aWYgKHRoaXMuX2ltYWdlKSB7XHJcblx0XHRcdHRoaXMuX2ltYWdlLnNyYyA9IHVybDtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdHNldEJvdW5kczogZnVuY3Rpb24gKGJvdW5kcykge1xyXG5cdFx0dGhpcy5fYm91bmRzID0gYm91bmRzO1xyXG5cclxuXHRcdGlmICh0aGlzLl9tYXApIHtcclxuXHRcdFx0dGhpcy5fcmVzZXQoKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdGdldEV2ZW50czogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGV2ZW50cyA9IHtcclxuXHRcdFx0em9vbTogdGhpcy5fcmVzZXQsXHJcblx0XHRcdHZpZXdyZXNldDogdGhpcy5fcmVzZXRcclxuXHRcdH07XHJcblxyXG5cdFx0aWYgKHRoaXMuX3pvb21BbmltYXRlZCkge1xyXG5cdFx0XHRldmVudHMuem9vbWFuaW0gPSB0aGlzLl9hbmltYXRlWm9vbTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZXZlbnRzO1xyXG5cdH0sXHJcblxyXG5cdGdldEJvdW5kczogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX2JvdW5kcztcclxuXHR9LFxyXG5cclxuXHRnZXRFbGVtZW50OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5faW1hZ2U7XHJcblx0fSxcclxuXHJcblx0X2luaXRJbWFnZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGltZyA9IHRoaXMuX2ltYWdlID0gTC5Eb21VdGlsLmNyZWF0ZSgnaW1nJyxcclxuXHRcdFx0XHQnbGVhZmxldC1pbWFnZS1sYXllciAnICsgKHRoaXMuX3pvb21BbmltYXRlZCA/ICdsZWFmbGV0LXpvb20tYW5pbWF0ZWQnIDogJycpKTtcclxuXHJcblx0XHRpbWcub25zZWxlY3RzdGFydCA9IEwuVXRpbC5mYWxzZUZuO1xyXG5cdFx0aW1nLm9ubW91c2Vtb3ZlID0gTC5VdGlsLmZhbHNlRm47XHJcblxyXG5cdFx0aW1nLm9ubG9hZCA9IEwuYmluZCh0aGlzLmZpcmUsIHRoaXMsICdsb2FkJyk7XHJcblxyXG5cdFx0aWYgKHRoaXMub3B0aW9ucy5jcm9zc09yaWdpbikge1xyXG5cdFx0XHRpbWcuY3Jvc3NPcmlnaW4gPSAnJztcclxuXHRcdH1cclxuXHJcblx0XHRpbWcuc3JjID0gdGhpcy5fdXJsO1xyXG5cdFx0aW1nLmFsdCA9IHRoaXMub3B0aW9ucy5hbHQ7XHJcblx0fSxcclxuXHJcblx0X2FuaW1hdGVab29tOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0dmFyIHNjYWxlID0gdGhpcy5fbWFwLmdldFpvb21TY2FsZShlLnpvb20pLFxyXG5cdFx0ICAgIG9mZnNldCA9IHRoaXMuX21hcC5fbGF0TG5nQm91bmRzVG9OZXdMYXllckJvdW5kcyh0aGlzLl9ib3VuZHMsIGUuem9vbSwgZS5jZW50ZXIpLm1pbjtcclxuXHJcblx0XHRMLkRvbVV0aWwuc2V0VHJhbnNmb3JtKHRoaXMuX2ltYWdlLCBvZmZzZXQsIHNjYWxlKTtcclxuXHR9LFxyXG5cclxuXHRfcmVzZXQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBpbWFnZSA9IHRoaXMuX2ltYWdlLFxyXG5cdFx0ICAgIGJvdW5kcyA9IG5ldyBMLkJvdW5kcyhcclxuXHRcdCAgICAgICAgdGhpcy5fbWFwLmxhdExuZ1RvTGF5ZXJQb2ludCh0aGlzLl9ib3VuZHMuZ2V0Tm9ydGhXZXN0KCkpLFxyXG5cdFx0ICAgICAgICB0aGlzLl9tYXAubGF0TG5nVG9MYXllclBvaW50KHRoaXMuX2JvdW5kcy5nZXRTb3V0aEVhc3QoKSkpLFxyXG5cdFx0ICAgIHNpemUgPSBib3VuZHMuZ2V0U2l6ZSgpO1xyXG5cclxuXHRcdEwuRG9tVXRpbC5zZXRQb3NpdGlvbihpbWFnZSwgYm91bmRzLm1pbik7XHJcblxyXG5cdFx0aW1hZ2Uuc3R5bGUud2lkdGggID0gc2l6ZS54ICsgJ3B4JztcclxuXHRcdGltYWdlLnN0eWxlLmhlaWdodCA9IHNpemUueSArICdweCc7XHJcblx0fSxcclxuXHJcblx0X3VwZGF0ZU9wYWNpdHk6IGZ1bmN0aW9uICgpIHtcclxuXHRcdEwuRG9tVXRpbC5zZXRPcGFjaXR5KHRoaXMuX2ltYWdlLCB0aGlzLm9wdGlvbnMub3BhY2l0eSk7XHJcblx0fVxyXG59KTtcclxuXHJcbi8vIEBmYWN0b3J5IEwuaW1hZ2VPdmVybGF5KGltYWdlVXJsOiBTdHJpbmcsIGJvdW5kczogTGF0TG5nQm91bmRzLCBvcHRpb25zPzogSW1hZ2VPdmVybGF5IG9wdGlvbnMpXHJcbi8vIEluc3RhbnRpYXRlcyBhbiBpbWFnZSBvdmVybGF5IG9iamVjdCBnaXZlbiB0aGUgVVJMIG9mIHRoZSBpbWFnZSBhbmQgdGhlXHJcbi8vIGdlb2dyYXBoaWNhbCBib3VuZHMgaXQgaXMgdGllZCB0by5cclxuTC5pbWFnZU92ZXJsYXkgPSBmdW5jdGlvbiAodXJsLCBib3VuZHMsIG9wdGlvbnMpIHtcclxuXHRyZXR1cm4gbmV3IEwuSW1hZ2VPdmVybGF5KHVybCwgYm91bmRzLCBvcHRpb25zKTtcclxufTtcclxuXG5cblxuLypcclxuICogQGNsYXNzIEljb25cclxuICogQGFrYSBMLkljb25cclxuICogQGluaGVyaXRzIExheWVyXHJcbiAqXHJcbiAqIFJlcHJlc2VudHMgYW4gaWNvbiB0byBwcm92aWRlIHdoZW4gY3JlYXRpbmcgYSBtYXJrZXIuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBteUljb24gPSBMLmljb24oe1xyXG4gKiAgICAgaWNvblVybDogJ215LWljb24ucG5nJyxcclxuICogICAgIGljb25SZXRpbmFVcmw6ICdteS1pY29uQDJ4LnBuZycsXHJcbiAqICAgICBpY29uU2l6ZTogWzM4LCA5NV0sXHJcbiAqICAgICBpY29uQW5jaG9yOiBbMjIsIDk0XSxcclxuICogICAgIHBvcHVwQW5jaG9yOiBbLTMsIC03Nl0sXHJcbiAqICAgICBzaGFkb3dVcmw6ICdteS1pY29uLXNoYWRvdy5wbmcnLFxyXG4gKiAgICAgc2hhZG93UmV0aW5hVXJsOiAnbXktaWNvbi1zaGFkb3dAMngucG5nJyxcclxuICogICAgIHNoYWRvd1NpemU6IFs2OCwgOTVdLFxyXG4gKiAgICAgc2hhZG93QW5jaG9yOiBbMjIsIDk0XVxyXG4gKiB9KTtcclxuICpcclxuICogTC5tYXJrZXIoWzUwLjUwNSwgMzAuNTddLCB7aWNvbjogbXlJY29ufSkuYWRkVG8obWFwKTtcclxuICogYGBgXHJcbiAqXHJcbiAqIGBMLkljb24uRGVmYXVsdGAgZXh0ZW5kcyBgTC5JY29uYCBhbmQgaXMgdGhlIGJsdWUgaWNvbiBMZWFmbGV0IHVzZXMgZm9yIG1hcmtlcnMgYnkgZGVmYXVsdC5cclxuICpcclxuICovXHJcblxyXG5MLkljb24gPSBMLkNsYXNzLmV4dGVuZCh7XHJcblxyXG5cdC8qIEBzZWN0aW9uXHJcblx0ICogQGFrYSBJY29uIG9wdGlvbnNcclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gaWNvblVybDogU3RyaW5nID0gbnVsbFxyXG5cdCAqICoqKHJlcXVpcmVkKSoqIFRoZSBVUkwgdG8gdGhlIGljb24gaW1hZ2UgKGFic29sdXRlIG9yIHJlbGF0aXZlIHRvIHlvdXIgc2NyaXB0IHBhdGgpLlxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBpY29uUmV0aW5hVXJsOiBTdHJpbmcgPSBudWxsXHJcblx0ICogVGhlIFVSTCB0byBhIHJldGluYSBzaXplZCB2ZXJzaW9uIG9mIHRoZSBpY29uIGltYWdlIChhYnNvbHV0ZSBvciByZWxhdGl2ZSB0byB5b3VyXHJcblx0ICogc2NyaXB0IHBhdGgpLiBVc2VkIGZvciBSZXRpbmEgc2NyZWVuIGRldmljZXMuXHJcblx0ICpcclxuXHQgKiBAb3B0aW9uIGljb25TaXplOiBQb2ludCA9IG51bGxcclxuXHQgKiBTaXplIG9mIHRoZSBpY29uIGltYWdlIGluIHBpeGVscy5cclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gaWNvbkFuY2hvcjogUG9pbnQgPSBudWxsXHJcblx0ICogVGhlIGNvb3JkaW5hdGVzIG9mIHRoZSBcInRpcFwiIG9mIHRoZSBpY29uIChyZWxhdGl2ZSB0byBpdHMgdG9wIGxlZnQgY29ybmVyKS4gVGhlIGljb25cclxuXHQgKiB3aWxsIGJlIGFsaWduZWQgc28gdGhhdCB0aGlzIHBvaW50IGlzIGF0IHRoZSBtYXJrZXIncyBnZW9ncmFwaGljYWwgbG9jYXRpb24uIENlbnRlcmVkXHJcblx0ICogYnkgZGVmYXVsdCBpZiBzaXplIGlzIHNwZWNpZmllZCwgYWxzbyBjYW4gYmUgc2V0IGluIENTUyB3aXRoIG5lZ2F0aXZlIG1hcmdpbnMuXHJcblx0ICpcclxuXHQgKiBAb3B0aW9uIHBvcHVwQW5jaG9yOiBQb2ludCA9IG51bGxcclxuXHQgKiBUaGUgY29vcmRpbmF0ZXMgb2YgdGhlIHBvaW50IGZyb20gd2hpY2ggcG9wdXBzIHdpbGwgXCJvcGVuXCIsIHJlbGF0aXZlIHRvIHRoZSBpY29uIGFuY2hvci5cclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gc2hhZG93VXJsOiBTdHJpbmcgPSBudWxsXHJcblx0ICogVGhlIFVSTCB0byB0aGUgaWNvbiBzaGFkb3cgaW1hZ2UuIElmIG5vdCBzcGVjaWZpZWQsIG5vIHNoYWRvdyBpbWFnZSB3aWxsIGJlIGNyZWF0ZWQuXHJcblx0ICpcclxuXHQgKiBAb3B0aW9uIHNoYWRvd1JldGluYVVybDogU3RyaW5nID0gbnVsbFxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBzaGFkb3dTaXplOiBQb2ludCA9IG51bGxcclxuXHQgKiBTaXplIG9mIHRoZSBzaGFkb3cgaW1hZ2UgaW4gcGl4ZWxzLlxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBzaGFkb3dBbmNob3I6IFBvaW50ID0gbnVsbFxyXG5cdCAqIFRoZSBjb29yZGluYXRlcyBvZiB0aGUgXCJ0aXBcIiBvZiB0aGUgc2hhZG93IChyZWxhdGl2ZSB0byBpdHMgdG9wIGxlZnQgY29ybmVyKSAodGhlIHNhbWVcclxuXHQgKiBhcyBpY29uQW5jaG9yIGlmIG5vdCBzcGVjaWZpZWQpLlxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBjbGFzc05hbWU6IFN0cmluZyA9ICcnXHJcblx0ICogQSBjdXN0b20gY2xhc3MgbmFtZSB0byBhc3NpZ24gdG8gYm90aCBpY29uIGFuZCBzaGFkb3cgaW1hZ2VzLiBFbXB0eSBieSBkZWZhdWx0LlxyXG5cdCAqL1xyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xyXG5cdFx0TC5zZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgY3JlYXRlSWNvbihvbGRJY29uPzogSFRNTEVsZW1lbnQpOiBIVE1MRWxlbWVudFxyXG5cdC8vIENhbGxlZCBpbnRlcm5hbGx5IHdoZW4gdGhlIGljb24gaGFzIHRvIGJlIHNob3duLCByZXR1cm5zIGEgYDxpbWc+YCBIVE1MIGVsZW1lbnRcclxuXHQvLyBzdHlsZWQgYWNjb3JkaW5nIHRvIHRoZSBvcHRpb25zLlxyXG5cdGNyZWF0ZUljb246IGZ1bmN0aW9uIChvbGRJY29uKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fY3JlYXRlSWNvbignaWNvbicsIG9sZEljb24pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgY3JlYXRlU2hhZG93KG9sZEljb24/OiBIVE1MRWxlbWVudCk6IEhUTUxFbGVtZW50XHJcblx0Ly8gQXMgYGNyZWF0ZUljb25gLCBidXQgZm9yIHRoZSBzaGFkb3cgYmVuZWF0aCBpdC5cclxuXHRjcmVhdGVTaGFkb3c6IGZ1bmN0aW9uIChvbGRJY29uKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fY3JlYXRlSWNvbignc2hhZG93Jywgb2xkSWNvbik7XHJcblx0fSxcclxuXHJcblx0X2NyZWF0ZUljb246IGZ1bmN0aW9uIChuYW1lLCBvbGRJY29uKSB7XHJcblx0XHR2YXIgc3JjID0gdGhpcy5fZ2V0SWNvblVybChuYW1lKTtcclxuXHJcblx0XHRpZiAoIXNyYykge1xyXG5cdFx0XHRpZiAobmFtZSA9PT0gJ2ljb24nKSB7XHJcblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCdpY29uVXJsIG5vdCBzZXQgaW4gSWNvbiBvcHRpb25zIChzZWUgdGhlIGRvY3MpLicpO1xyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBpbWcgPSB0aGlzLl9jcmVhdGVJbWcoc3JjLCBvbGRJY29uICYmIG9sZEljb24udGFnTmFtZSA9PT0gJ0lNRycgPyBvbGRJY29uIDogbnVsbCk7XHJcblx0XHR0aGlzLl9zZXRJY29uU3R5bGVzKGltZywgbmFtZSk7XHJcblxyXG5cdFx0cmV0dXJuIGltZztcclxuXHR9LFxyXG5cclxuXHRfc2V0SWNvblN0eWxlczogZnVuY3Rpb24gKGltZywgbmFtZSkge1xyXG5cdFx0dmFyIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XHJcblx0XHR2YXIgc2l6ZU9wdGlvbiA9IG9wdGlvbnNbbmFtZSArICdTaXplJ107XHJcblxyXG5cdFx0aWYgKHR5cGVvZiBzaXplT3B0aW9uID09PSAnbnVtYmVyJykge1xyXG5cdFx0XHRzaXplT3B0aW9uID0gW3NpemVPcHRpb24sIHNpemVPcHRpb25dO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBzaXplID0gTC5wb2ludChzaXplT3B0aW9uKSxcclxuXHRcdCAgICBhbmNob3IgPSBMLnBvaW50KG5hbWUgPT09ICdzaGFkb3cnICYmIG9wdGlvbnMuc2hhZG93QW5jaG9yIHx8IG9wdGlvbnMuaWNvbkFuY2hvciB8fFxyXG5cdFx0ICAgICAgICAgICAgc2l6ZSAmJiBzaXplLmRpdmlkZUJ5KDIsIHRydWUpKTtcclxuXHJcblx0XHRpbWcuY2xhc3NOYW1lID0gJ2xlYWZsZXQtbWFya2VyLScgKyBuYW1lICsgJyAnICsgKG9wdGlvbnMuY2xhc3NOYW1lIHx8ICcnKTtcclxuXHJcblx0XHRpZiAoYW5jaG9yKSB7XHJcblx0XHRcdGltZy5zdHlsZS5tYXJnaW5MZWZ0ID0gKC1hbmNob3IueCkgKyAncHgnO1xyXG5cdFx0XHRpbWcuc3R5bGUubWFyZ2luVG9wICA9ICgtYW5jaG9yLnkpICsgJ3B4JztcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoc2l6ZSkge1xyXG5cdFx0XHRpbWcuc3R5bGUud2lkdGggID0gc2l6ZS54ICsgJ3B4JztcclxuXHRcdFx0aW1nLnN0eWxlLmhlaWdodCA9IHNpemUueSArICdweCc7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X2NyZWF0ZUltZzogZnVuY3Rpb24gKHNyYywgZWwpIHtcclxuXHRcdGVsID0gZWwgfHwgZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW1nJyk7XHJcblx0XHRlbC5zcmMgPSBzcmM7XHJcblx0XHRyZXR1cm4gZWw7XHJcblx0fSxcclxuXHJcblx0X2dldEljb25Vcmw6IGZ1bmN0aW9uIChuYW1lKSB7XHJcblx0XHRyZXR1cm4gTC5Ccm93c2VyLnJldGluYSAmJiB0aGlzLm9wdGlvbnNbbmFtZSArICdSZXRpbmFVcmwnXSB8fCB0aGlzLm9wdGlvbnNbbmFtZSArICdVcmwnXTtcclxuXHR9XHJcbn0pO1xyXG5cclxuXHJcbi8vIEBmYWN0b3J5IEwuaWNvbihvcHRpb25zOiBJY29uIG9wdGlvbnMpXHJcbi8vIENyZWF0ZXMgYW4gaWNvbiBpbnN0YW5jZSB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxyXG5MLmljb24gPSBmdW5jdGlvbiAob3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgTC5JY29uKG9wdGlvbnMpO1xyXG59O1xyXG5cblxuXG4vKlxuICogQG1pbmljbGFzcyBJY29uLkRlZmF1bHQgKEljb24pXG4gKiBAYWthIEwuSWNvbi5EZWZhdWx0XG4gKiBAc2VjdGlvblxuICpcbiAqIEEgdHJpdmlhbCBzdWJjbGFzcyBvZiBgSWNvbmAsIHJlcHJlc2VudHMgdGhlIGljb24gdG8gdXNlIGluIGBNYXJrZXJgcyB3aGVuXG4gKiBubyBpY29uIGlzIHNwZWNpZmllZC4gUG9pbnRzIHRvIHRoZSBibHVlIG1hcmtlciBpbWFnZSBkaXN0cmlidXRlZCB3aXRoIExlYWZsZXRcbiAqIHJlbGVhc2VzLlxuICpcbiAqIEluIG9yZGVyIHRvIGN1c3RvbWl6ZSB0aGUgZGVmYXVsdCBpY29uLCBqdXN0IGNoYW5nZSB0aGUgcHJvcGVydGllcyBvZiBgTC5JY29uLkRlZmF1bHQucHJvdG90eXBlLm9wdGlvbnNgXG4gKiAod2hpY2ggaXMgYSBzZXQgb2YgYEljb24gb3B0aW9uc2ApLlxuICpcbiAqIElmIHlvdSB3YW50IHRvIF9jb21wbGV0ZWx5XyByZXBsYWNlIHRoZSBkZWZhdWx0IGljb24sIG92ZXJyaWRlIHRoZVxuICogYEwuTWFya2VyLnByb3RvdHlwZS5vcHRpb25zLmljb25gIHdpdGggeW91ciBvd24gaWNvbiBpbnN0ZWFkLlxuICovXG5cbkwuSWNvbi5EZWZhdWx0ID0gTC5JY29uLmV4dGVuZCh7XG5cblx0b3B0aW9uczoge1xuXHRcdGljb25Vcmw6ICAgICAgICdtYXJrZXItaWNvbi5wbmcnLFxuXHRcdGljb25SZXRpbmFVcmw6ICdtYXJrZXItaWNvbi0yeC5wbmcnLFxuXHRcdHNoYWRvd1VybDogICAgICdtYXJrZXItc2hhZG93LnBuZycsXG5cdFx0aWNvblNpemU6ICAgIFsyNSwgNDFdLFxuXHRcdGljb25BbmNob3I6ICBbMTIsIDQxXSxcblx0XHRwb3B1cEFuY2hvcjogWzEsIC0zNF0sXG5cdFx0dG9vbHRpcEFuY2hvcjogWzE2LCAtMjhdLFxuXHRcdHNoYWRvd1NpemU6ICBbNDEsIDQxXVxuXHR9LFxuXG5cdF9nZXRJY29uVXJsOiBmdW5jdGlvbiAobmFtZSkge1xuXHRcdGlmICghTC5JY29uLkRlZmF1bHQuaW1hZ2VQYXRoKSB7XHQvLyBEZXByZWNhdGVkLCBiYWNrd2FyZHMtY29tcGF0aWJpbGl0eSBvbmx5XG5cdFx0XHRMLkljb24uRGVmYXVsdC5pbWFnZVBhdGggPSB0aGlzLl9kZXRlY3RJY29uUGF0aCgpO1xuXHRcdH1cblxuXHRcdC8vIEBvcHRpb24gaW1hZ2VQYXRoOiBTdHJpbmdcblx0XHQvLyBgTC5JY29uLkRlZmF1bHRgIHdpbGwgdHJ5IHRvIGF1dG8tZGV0ZWN0IHRoZSBhYnNvbHV0ZSBsb2NhdGlvbiBvZiB0aGVcblx0XHQvLyBibHVlIGljb24gaW1hZ2VzLiBJZiB5b3UgYXJlIHBsYWNpbmcgdGhlc2UgaW1hZ2VzIGluIGEgbm9uLXN0YW5kYXJkXG5cdFx0Ly8gd2F5LCBzZXQgdGhpcyBvcHRpb24gdG8gcG9pbnQgdG8gdGhlIHJpZ2h0IGFic29sdXRlIHBhdGguXG5cdFx0cmV0dXJuICh0aGlzLm9wdGlvbnMuaW1hZ2VQYXRoIHx8IEwuSWNvbi5EZWZhdWx0LmltYWdlUGF0aCkgKyBMLkljb24ucHJvdG90eXBlLl9nZXRJY29uVXJsLmNhbGwodGhpcywgbmFtZSk7XG5cdH0sXG5cblx0X2RldGVjdEljb25QYXRoOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGVsID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2JywgICdsZWFmbGV0LWRlZmF1bHQtaWNvbi1wYXRoJywgZG9jdW1lbnQuYm9keSk7XG5cdFx0dmFyIHBhdGggPSBMLkRvbVV0aWwuZ2V0U3R5bGUoZWwsICdiYWNrZ3JvdW5kLWltYWdlJykgfHxcblx0XHQgICAgICAgICAgIEwuRG9tVXRpbC5nZXRTdHlsZShlbCwgJ2JhY2tncm91bmRJbWFnZScpO1x0Ly8gSUU4XG5cblx0XHRkb2N1bWVudC5ib2R5LnJlbW92ZUNoaWxkKGVsKTtcblxuXHRcdHJldHVybiBwYXRoLmluZGV4T2YoJ3VybCcpID09PSAwID9cblx0XHRcdHBhdGgucmVwbGFjZSgvXnVybFxcKFtcXFwiXFwnXT8vLCAnJykucmVwbGFjZSgvbWFya2VyLWljb25cXC5wbmdbXFxcIlxcJ10/XFwpJC8sICcnKSA6ICcnO1xuXHR9XG59KTtcblxuXG5cbi8qXHJcbiAqIEBjbGFzcyBNYXJrZXJcclxuICogQGluaGVyaXRzIEludGVyYWN0aXZlIGxheWVyXHJcbiAqIEBha2EgTC5NYXJrZXJcclxuICogTC5NYXJrZXIgaXMgdXNlZCB0byBkaXNwbGF5IGNsaWNrYWJsZS9kcmFnZ2FibGUgaWNvbnMgb24gdGhlIG1hcC4gRXh0ZW5kcyBgTGF5ZXJgLlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiBMLm1hcmtlcihbNTAuNSwgMzAuNV0pLmFkZFRvKG1hcCk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbkwuTWFya2VyID0gTC5MYXllci5leHRlbmQoe1xyXG5cclxuXHQvLyBAc2VjdGlvblxyXG5cdC8vIEBha2EgTWFya2VyIG9wdGlvbnNcclxuXHRvcHRpb25zOiB7XHJcblx0XHQvLyBAb3B0aW9uIGljb246IEljb24gPSAqXHJcblx0XHQvLyBJY29uIGNsYXNzIHRvIHVzZSBmb3IgcmVuZGVyaW5nIHRoZSBtYXJrZXIuIFNlZSBbSWNvbiBkb2N1bWVudGF0aW9uXSgjTC5JY29uKSBmb3IgZGV0YWlscyBvbiBob3cgdG8gY3VzdG9taXplIHRoZSBtYXJrZXIgaWNvbi4gSWYgbm90IHNwZWNpZmllZCwgYSBuZXcgYEwuSWNvbi5EZWZhdWx0YCBpcyB1c2VkLlxyXG5cdFx0aWNvbjogbmV3IEwuSWNvbi5EZWZhdWx0KCksXHJcblxyXG5cdFx0Ly8gT3B0aW9uIGluaGVyaXRlZCBmcm9tIFwiSW50ZXJhY3RpdmUgbGF5ZXJcIiBhYnN0cmFjdCBjbGFzc1xyXG5cdFx0aW50ZXJhY3RpdmU6IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBkcmFnZ2FibGU6IEJvb2xlYW4gPSBmYWxzZVxyXG5cdFx0Ly8gV2hldGhlciB0aGUgbWFya2VyIGlzIGRyYWdnYWJsZSB3aXRoIG1vdXNlL3RvdWNoIG9yIG5vdC5cclxuXHRcdGRyYWdnYWJsZTogZmFsc2UsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBrZXlib2FyZDogQm9vbGVhbiA9IHRydWVcclxuXHRcdC8vIFdoZXRoZXIgdGhlIG1hcmtlciBjYW4gYmUgdGFiYmVkIHRvIHdpdGggYSBrZXlib2FyZCBhbmQgY2xpY2tlZCBieSBwcmVzc2luZyBlbnRlci5cclxuXHRcdGtleWJvYXJkOiB0cnVlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gdGl0bGU6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBUZXh0IGZvciB0aGUgYnJvd3NlciB0b29sdGlwIHRoYXQgYXBwZWFyIG9uIG1hcmtlciBob3ZlciAobm8gdG9vbHRpcCBieSBkZWZhdWx0KS5cclxuXHRcdHRpdGxlOiAnJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGFsdDogU3RyaW5nID0gJydcclxuXHRcdC8vIFRleHQgZm9yIHRoZSBgYWx0YCBhdHRyaWJ1dGUgb2YgdGhlIGljb24gaW1hZ2UgKHVzZWZ1bCBmb3IgYWNjZXNzaWJpbGl0eSkuXHJcblx0XHRhbHQ6ICcnLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gekluZGV4T2Zmc2V0OiBOdW1iZXIgPSAwXHJcblx0XHQvLyBCeSBkZWZhdWx0LCBtYXJrZXIgaW1hZ2VzIHpJbmRleCBpcyBzZXQgYXV0b21hdGljYWxseSBiYXNlZCBvbiBpdHMgbGF0aXR1ZGUuIFVzZSB0aGlzIG9wdGlvbiBpZiB5b3Ugd2FudCB0byBwdXQgdGhlIG1hcmtlciBvbiB0b3Agb2YgYWxsIG90aGVycyAob3IgYmVsb3cpLCBzcGVjaWZ5aW5nIGEgaGlnaCB2YWx1ZSBsaWtlIGAxMDAwYCAob3IgaGlnaCBuZWdhdGl2ZSB2YWx1ZSwgcmVzcGVjdGl2ZWx5KS5cclxuXHRcdHpJbmRleE9mZnNldDogMCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIG9wYWNpdHk6IE51bWJlciA9IDEuMFxyXG5cdFx0Ly8gVGhlIG9wYWNpdHkgb2YgdGhlIG1hcmtlci5cclxuXHRcdG9wYWNpdHk6IDEsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiByaXNlT25Ib3ZlcjogQm9vbGVhbiA9IGZhbHNlXHJcblx0XHQvLyBJZiBgdHJ1ZWAsIHRoZSBtYXJrZXIgd2lsbCBnZXQgb24gdG9wIG9mIG90aGVycyB3aGVuIHlvdSBob3ZlciB0aGUgbW91c2Ugb3ZlciBpdC5cclxuXHRcdHJpc2VPbkhvdmVyOiBmYWxzZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHJpc2VPZmZzZXQ6IE51bWJlciA9IDI1MFxyXG5cdFx0Ly8gVGhlIHotaW5kZXggb2Zmc2V0IHVzZWQgZm9yIHRoZSBgcmlzZU9uSG92ZXJgIGZlYXR1cmUuXHJcblx0XHRyaXNlT2Zmc2V0OiAyNTAsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBwYW5lOiBTdHJpbmcgPSAnbWFya2VyUGFuZSdcclxuXHRcdC8vIGBNYXAgcGFuZWAgd2hlcmUgdGhlIG1hcmtlcnMgaWNvbiB3aWxsIGJlIGFkZGVkLlxyXG5cdFx0cGFuZTogJ21hcmtlclBhbmUnLFxyXG5cclxuXHRcdC8vIEZJWE1FOiBzaGFkb3dQYW5lIGlzIG5vIGxvbmdlciBhIHZhbGlkIG9wdGlvblxyXG5cdFx0bm9uQnViYmxpbmdFdmVudHM6IFsnY2xpY2snLCAnZGJsY2xpY2snLCAnbW91c2VvdmVyJywgJ21vdXNlb3V0JywgJ2NvbnRleHRtZW51J11cclxuXHR9LFxyXG5cclxuXHQvKiBAc2VjdGlvblxyXG5cdCAqXHJcblx0ICogSW4gYWRkaXRpb24gdG8gW3NoYXJlZCBsYXllciBtZXRob2RzXSgjTGF5ZXIpIGxpa2UgYGFkZFRvKClgIGFuZCBgcmVtb3ZlKClgIGFuZCBbcG9wdXAgbWV0aG9kc10oI1BvcHVwKSBsaWtlIGJpbmRQb3B1cCgpIHlvdSBjYW4gYWxzbyB1c2UgdGhlIGZvbGxvd2luZyBtZXRob2RzOlxyXG5cdCAqL1xyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAobGF0bG5nLCBvcHRpb25zKSB7XHJcblx0XHRMLnNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XHJcblx0XHR0aGlzLl9sYXRsbmcgPSBMLmxhdExuZyhsYXRsbmcpO1xyXG5cdH0sXHJcblxyXG5cdG9uQWRkOiBmdW5jdGlvbiAobWFwKSB7XHJcblx0XHR0aGlzLl96b29tQW5pbWF0ZWQgPSB0aGlzLl96b29tQW5pbWF0ZWQgJiYgbWFwLm9wdGlvbnMubWFya2VyWm9vbUFuaW1hdGlvbjtcclxuXHJcblx0XHRpZiAodGhpcy5fem9vbUFuaW1hdGVkKSB7XHJcblx0XHRcdG1hcC5vbignem9vbWFuaW0nLCB0aGlzLl9hbmltYXRlWm9vbSwgdGhpcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5faW5pdEljb24oKTtcclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblx0fSxcclxuXHJcblx0b25SZW1vdmU6IGZ1bmN0aW9uIChtYXApIHtcclxuXHRcdGlmICh0aGlzLmRyYWdnaW5nICYmIHRoaXMuZHJhZ2dpbmcuZW5hYmxlZCgpKSB7XHJcblx0XHRcdHRoaXMub3B0aW9ucy5kcmFnZ2FibGUgPSB0cnVlO1xyXG5cdFx0XHR0aGlzLmRyYWdnaW5nLnJlbW92ZUhvb2tzKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKHRoaXMuX3pvb21BbmltYXRlZCkge1xyXG5cdFx0XHRtYXAub2ZmKCd6b29tYW5pbScsIHRoaXMuX2FuaW1hdGVab29tLCB0aGlzKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9yZW1vdmVJY29uKCk7XHJcblx0XHR0aGlzLl9yZW1vdmVTaGFkb3coKTtcclxuXHR9LFxyXG5cclxuXHRnZXRFdmVudHM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB7XHJcblx0XHRcdHpvb206IHRoaXMudXBkYXRlLFxyXG5cdFx0XHR2aWV3cmVzZXQ6IHRoaXMudXBkYXRlXHJcblx0XHR9O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0TGF0TG5nOiBMYXRMbmdcclxuXHQvLyBSZXR1cm5zIHRoZSBjdXJyZW50IGdlb2dyYXBoaWNhbCBwb3NpdGlvbiBvZiB0aGUgbWFya2VyLlxyXG5cdGdldExhdExuZzogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX2xhdGxuZztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldExhdExuZyhsYXRsbmc6IExhdExuZyk6IHRoaXNcclxuXHQvLyBDaGFuZ2VzIHRoZSBtYXJrZXIgcG9zaXRpb24gdG8gdGhlIGdpdmVuIHBvaW50LlxyXG5cdHNldExhdExuZzogZnVuY3Rpb24gKGxhdGxuZykge1xyXG5cdFx0dmFyIG9sZExhdExuZyA9IHRoaXMuX2xhdGxuZztcclxuXHRcdHRoaXMuX2xhdGxuZyA9IEwubGF0TG5nKGxhdGxuZyk7XHJcblx0XHR0aGlzLnVwZGF0ZSgpO1xyXG5cclxuXHRcdC8vIEBldmVudCBtb3ZlOiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFya2VyIGlzIG1vdmVkIHZpYSBbYHNldExhdExuZ2BdKCNtYXJrZXItc2V0bGF0bG5nKSBvciBieSBbZHJhZ2dpbmddKCNtYXJrZXItZHJhZ2dpbmcpLiBPbGQgYW5kIG5ldyBjb29yZGluYXRlcyBhcmUgaW5jbHVkZWQgaW4gZXZlbnQgYXJndW1lbnRzIGFzIGBvbGRMYXRMbmdgLCBgbGF0bG5nYC5cclxuXHRcdHJldHVybiB0aGlzLmZpcmUoJ21vdmUnLCB7b2xkTGF0TG5nOiBvbGRMYXRMbmcsIGxhdGxuZzogdGhpcy5fbGF0bG5nfSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBzZXRaSW5kZXhPZmZzZXQob2Zmc2V0OiBOdW1iZXIpOiB0aGlzXHJcblx0Ly8gQ2hhbmdlcyB0aGUgW3pJbmRleCBvZmZzZXRdKCNtYXJrZXItemluZGV4b2Zmc2V0KSBvZiB0aGUgbWFya2VyLlxyXG5cdHNldFpJbmRleE9mZnNldDogZnVuY3Rpb24gKG9mZnNldCkge1xyXG5cdFx0dGhpcy5vcHRpb25zLnpJbmRleE9mZnNldCA9IG9mZnNldDtcclxuXHRcdHJldHVybiB0aGlzLnVwZGF0ZSgpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0SWNvbihpY29uOiBJY29uKTogdGhpc1xyXG5cdC8vIENoYW5nZXMgdGhlIG1hcmtlciBpY29uLlxyXG5cdHNldEljb246IGZ1bmN0aW9uIChpY29uKSB7XHJcblxyXG5cdFx0dGhpcy5vcHRpb25zLmljb24gPSBpY29uO1xyXG5cclxuXHRcdGlmICh0aGlzLl9tYXApIHtcclxuXHRcdFx0dGhpcy5faW5pdEljb24oKTtcclxuXHRcdFx0dGhpcy51cGRhdGUoKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5fcG9wdXApIHtcclxuXHRcdFx0dGhpcy5iaW5kUG9wdXAodGhpcy5fcG9wdXAsIHRoaXMuX3BvcHVwLm9wdGlvbnMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdGdldEVsZW1lbnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9pY29uO1xyXG5cdH0sXHJcblxyXG5cdHVwZGF0ZTogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdGlmICh0aGlzLl9pY29uKSB7XHJcblx0XHRcdHZhciBwb3MgPSB0aGlzLl9tYXAubGF0TG5nVG9MYXllclBvaW50KHRoaXMuX2xhdGxuZykucm91bmQoKTtcclxuXHRcdFx0dGhpcy5fc2V0UG9zKHBvcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0X2luaXRJY29uOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgb3B0aW9ucyA9IHRoaXMub3B0aW9ucyxcclxuXHRcdCAgICBjbGFzc1RvQWRkID0gJ2xlYWZsZXQtem9vbS0nICsgKHRoaXMuX3pvb21BbmltYXRlZCA/ICdhbmltYXRlZCcgOiAnaGlkZScpO1xyXG5cclxuXHRcdHZhciBpY29uID0gb3B0aW9ucy5pY29uLmNyZWF0ZUljb24odGhpcy5faWNvbiksXHJcblx0XHQgICAgYWRkSWNvbiA9IGZhbHNlO1xyXG5cclxuXHRcdC8vIGlmIHdlJ3JlIG5vdCByZXVzaW5nIHRoZSBpY29uLCByZW1vdmUgdGhlIG9sZCBvbmUgYW5kIGluaXQgbmV3IG9uZVxyXG5cdFx0aWYgKGljb24gIT09IHRoaXMuX2ljb24pIHtcclxuXHRcdFx0aWYgKHRoaXMuX2ljb24pIHtcclxuXHRcdFx0XHR0aGlzLl9yZW1vdmVJY29uKCk7XHJcblx0XHRcdH1cclxuXHRcdFx0YWRkSWNvbiA9IHRydWU7XHJcblxyXG5cdFx0XHRpZiAob3B0aW9ucy50aXRsZSkge1xyXG5cdFx0XHRcdGljb24udGl0bGUgPSBvcHRpb25zLnRpdGxlO1xyXG5cdFx0XHR9XHJcblx0XHRcdGlmIChvcHRpb25zLmFsdCkge1xyXG5cdFx0XHRcdGljb24uYWx0ID0gb3B0aW9ucy5hbHQ7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRMLkRvbVV0aWwuYWRkQ2xhc3MoaWNvbiwgY2xhc3NUb0FkZCk7XHJcblxyXG5cdFx0aWYgKG9wdGlvbnMua2V5Ym9hcmQpIHtcclxuXHRcdFx0aWNvbi50YWJJbmRleCA9ICcwJztcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9pY29uID0gaWNvbjtcclxuXHJcblx0XHRpZiAob3B0aW9ucy5yaXNlT25Ib3Zlcikge1xyXG5cdFx0XHR0aGlzLm9uKHtcclxuXHRcdFx0XHRtb3VzZW92ZXI6IHRoaXMuX2JyaW5nVG9Gcm9udCxcclxuXHRcdFx0XHRtb3VzZW91dDogdGhpcy5fcmVzZXRaSW5kZXhcclxuXHRcdFx0fSk7XHJcblx0XHR9XHJcblxyXG5cdFx0dmFyIG5ld1NoYWRvdyA9IG9wdGlvbnMuaWNvbi5jcmVhdGVTaGFkb3codGhpcy5fc2hhZG93KSxcclxuXHRcdCAgICBhZGRTaGFkb3cgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAobmV3U2hhZG93ICE9PSB0aGlzLl9zaGFkb3cpIHtcclxuXHRcdFx0dGhpcy5fcmVtb3ZlU2hhZG93KCk7XHJcblx0XHRcdGFkZFNoYWRvdyA9IHRydWU7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKG5ld1NoYWRvdykge1xyXG5cdFx0XHRMLkRvbVV0aWwuYWRkQ2xhc3MobmV3U2hhZG93LCBjbGFzc1RvQWRkKTtcclxuXHRcdH1cclxuXHRcdHRoaXMuX3NoYWRvdyA9IG5ld1NoYWRvdztcclxuXHJcblxyXG5cdFx0aWYgKG9wdGlvbnMub3BhY2l0eSA8IDEpIHtcclxuXHRcdFx0dGhpcy5fdXBkYXRlT3BhY2l0eSgpO1xyXG5cdFx0fVxyXG5cclxuXHJcblx0XHRpZiAoYWRkSWNvbikge1xyXG5cdFx0XHR0aGlzLmdldFBhbmUoKS5hcHBlbmRDaGlsZCh0aGlzLl9pY29uKTtcclxuXHRcdH1cclxuXHRcdHRoaXMuX2luaXRJbnRlcmFjdGlvbigpO1xyXG5cdFx0aWYgKG5ld1NoYWRvdyAmJiBhZGRTaGFkb3cpIHtcclxuXHRcdFx0dGhpcy5nZXRQYW5lKCdzaGFkb3dQYW5lJykuYXBwZW5kQ2hpbGQodGhpcy5fc2hhZG93KTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfcmVtb3ZlSWNvbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKHRoaXMub3B0aW9ucy5yaXNlT25Ib3Zlcikge1xyXG5cdFx0XHR0aGlzLm9mZih7XHJcblx0XHRcdFx0bW91c2VvdmVyOiB0aGlzLl9icmluZ1RvRnJvbnQsXHJcblx0XHRcdFx0bW91c2VvdXQ6IHRoaXMuX3Jlc2V0WkluZGV4XHJcblx0XHRcdH0pO1xyXG5cdFx0fVxyXG5cclxuXHRcdEwuRG9tVXRpbC5yZW1vdmUodGhpcy5faWNvbik7XHJcblx0XHR0aGlzLnJlbW92ZUludGVyYWN0aXZlVGFyZ2V0KHRoaXMuX2ljb24pO1xyXG5cclxuXHRcdHRoaXMuX2ljb24gPSBudWxsO1xyXG5cdH0sXHJcblxyXG5cdF9yZW1vdmVTaGFkb3c6IGZ1bmN0aW9uICgpIHtcclxuXHRcdGlmICh0aGlzLl9zaGFkb3cpIHtcclxuXHRcdFx0TC5Eb21VdGlsLnJlbW92ZSh0aGlzLl9zaGFkb3cpO1xyXG5cdFx0fVxyXG5cdFx0dGhpcy5fc2hhZG93ID0gbnVsbDtcclxuXHR9LFxyXG5cclxuXHRfc2V0UG9zOiBmdW5jdGlvbiAocG9zKSB7XHJcblx0XHRMLkRvbVV0aWwuc2V0UG9zaXRpb24odGhpcy5faWNvbiwgcG9zKTtcclxuXHJcblx0XHRpZiAodGhpcy5fc2hhZG93KSB7XHJcblx0XHRcdEwuRG9tVXRpbC5zZXRQb3NpdGlvbih0aGlzLl9zaGFkb3csIHBvcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fekluZGV4ID0gcG9zLnkgKyB0aGlzLm9wdGlvbnMuekluZGV4T2Zmc2V0O1xyXG5cclxuXHRcdHRoaXMuX3Jlc2V0WkluZGV4KCk7XHJcblx0fSxcclxuXHJcblx0X3VwZGF0ZVpJbmRleDogZnVuY3Rpb24gKG9mZnNldCkge1xyXG5cdFx0dGhpcy5faWNvbi5zdHlsZS56SW5kZXggPSB0aGlzLl96SW5kZXggKyBvZmZzZXQ7XHJcblx0fSxcclxuXHJcblx0X2FuaW1hdGVab29tOiBmdW5jdGlvbiAob3B0KSB7XHJcblx0XHR2YXIgcG9zID0gdGhpcy5fbWFwLl9sYXRMbmdUb05ld0xheWVyUG9pbnQodGhpcy5fbGF0bG5nLCBvcHQuem9vbSwgb3B0LmNlbnRlcikucm91bmQoKTtcclxuXHJcblx0XHR0aGlzLl9zZXRQb3MocG9zKTtcclxuXHR9LFxyXG5cclxuXHRfaW5pdEludGVyYWN0aW9uOiBmdW5jdGlvbiAoKSB7XHJcblxyXG5cdFx0aWYgKCF0aGlzLm9wdGlvbnMuaW50ZXJhY3RpdmUpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0TC5Eb21VdGlsLmFkZENsYXNzKHRoaXMuX2ljb24sICdsZWFmbGV0LWludGVyYWN0aXZlJyk7XHJcblxyXG5cdFx0dGhpcy5hZGRJbnRlcmFjdGl2ZVRhcmdldCh0aGlzLl9pY29uKTtcclxuXHJcblx0XHRpZiAoTC5IYW5kbGVyLk1hcmtlckRyYWcpIHtcclxuXHRcdFx0dmFyIGRyYWdnYWJsZSA9IHRoaXMub3B0aW9ucy5kcmFnZ2FibGU7XHJcblx0XHRcdGlmICh0aGlzLmRyYWdnaW5nKSB7XHJcblx0XHRcdFx0ZHJhZ2dhYmxlID0gdGhpcy5kcmFnZ2luZy5lbmFibGVkKCk7XHJcblx0XHRcdFx0dGhpcy5kcmFnZ2luZy5kaXNhYmxlKCk7XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdHRoaXMuZHJhZ2dpbmcgPSBuZXcgTC5IYW5kbGVyLk1hcmtlckRyYWcodGhpcyk7XHJcblxyXG5cdFx0XHRpZiAoZHJhZ2dhYmxlKSB7XHJcblx0XHRcdFx0dGhpcy5kcmFnZ2luZy5lbmFibGUoKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0T3BhY2l0eShvcGFjaXR5OiBOdW1iZXIpOiB0aGlzXHJcblx0Ly8gQ2hhbmdlcyB0aGUgb3BhY2l0eSBvZiB0aGUgbWFya2VyLlxyXG5cdHNldE9wYWNpdHk6IGZ1bmN0aW9uIChvcGFjaXR5KSB7XHJcblx0XHR0aGlzLm9wdGlvbnMub3BhY2l0eSA9IG9wYWNpdHk7XHJcblx0XHRpZiAodGhpcy5fbWFwKSB7XHJcblx0XHRcdHRoaXMuX3VwZGF0ZU9wYWNpdHkoKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfdXBkYXRlT3BhY2l0eTogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIG9wYWNpdHkgPSB0aGlzLm9wdGlvbnMub3BhY2l0eTtcclxuXHJcblx0XHRMLkRvbVV0aWwuc2V0T3BhY2l0eSh0aGlzLl9pY29uLCBvcGFjaXR5KTtcclxuXHJcblx0XHRpZiAodGhpcy5fc2hhZG93KSB7XHJcblx0XHRcdEwuRG9tVXRpbC5zZXRPcGFjaXR5KHRoaXMuX3NoYWRvdywgb3BhY2l0eSk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X2JyaW5nVG9Gcm9udDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dGhpcy5fdXBkYXRlWkluZGV4KHRoaXMub3B0aW9ucy5yaXNlT2Zmc2V0KTtcclxuXHR9LFxyXG5cclxuXHRfcmVzZXRaSW5kZXg6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuX3VwZGF0ZVpJbmRleCgwKTtcclxuXHR9LFxyXG5cclxuXHRfZ2V0UG9wdXBBbmNob3I6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLm9wdGlvbnMuaWNvbi5vcHRpb25zLnBvcHVwQW5jaG9yIHx8IFswLCAwXTtcclxuXHR9LFxyXG5cclxuXHRfZ2V0VG9vbHRpcEFuY2hvcjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMub3B0aW9ucy5pY29uLm9wdGlvbnMudG9vbHRpcEFuY2hvciB8fCBbMCwgMF07XHJcblx0fVxyXG59KTtcclxuXHJcblxyXG4vLyBmYWN0b3J5IEwubWFya2VyKGxhdGxuZzogTGF0TG5nLCBvcHRpb25zPyA6IE1hcmtlciBvcHRpb25zKVxyXG5cclxuLy8gQGZhY3RvcnkgTC5tYXJrZXIobGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/IDogTWFya2VyIG9wdGlvbnMpXHJcbi8vIEluc3RhbnRpYXRlcyBhIE1hcmtlciBvYmplY3QgZ2l2ZW4gYSBnZW9ncmFwaGljYWwgcG9pbnQgYW5kIG9wdGlvbmFsbHkgYW4gb3B0aW9ucyBvYmplY3QuXHJcbkwubWFya2VyID0gZnVuY3Rpb24gKGxhdGxuZywgb3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgTC5NYXJrZXIobGF0bG5nLCBvcHRpb25zKTtcclxufTtcclxuXG5cblxuLypcbiAqIEBjbGFzcyBEaXZJY29uXG4gKiBAYWthIEwuRGl2SWNvblxuICogQGluaGVyaXRzIEljb25cbiAqXG4gKiBSZXByZXNlbnRzIGEgbGlnaHR3ZWlnaHQgaWNvbiBmb3IgbWFya2VycyB0aGF0IHVzZXMgYSBzaW1wbGUgYDxkaXY+YFxuICogZWxlbWVudCBpbnN0ZWFkIG9mIGFuIGltYWdlLiBJbmhlcml0cyBmcm9tIGBJY29uYCBidXQgaWdub3JlcyB0aGUgYGljb25VcmxgIGFuZCBzaGFkb3cgb3B0aW9ucy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBganNcbiAqIHZhciBteUljb24gPSBMLmRpdkljb24oe2NsYXNzTmFtZTogJ215LWRpdi1pY29uJ30pO1xuICogLy8geW91IGNhbiBzZXQgLm15LWRpdi1pY29uIHN0eWxlcyBpbiBDU1NcbiAqXG4gKiBMLm1hcmtlcihbNTAuNTA1LCAzMC41N10sIHtpY29uOiBteUljb259KS5hZGRUbyhtYXApO1xuICogYGBgXG4gKlxuICogQnkgZGVmYXVsdCwgaXQgaGFzIGEgJ2xlYWZsZXQtZGl2LWljb24nIENTUyBjbGFzcyBhbmQgaXMgc3R5bGVkIGFzIGEgbGl0dGxlIHdoaXRlIHNxdWFyZSB3aXRoIGEgc2hhZG93LlxuICovXG5cbkwuRGl2SWNvbiA9IEwuSWNvbi5leHRlbmQoe1xuXHRvcHRpb25zOiB7XG5cdFx0Ly8gQHNlY3Rpb25cblx0XHQvLyBAYWthIERpdkljb24gb3B0aW9uc1xuXHRcdGljb25TaXplOiBbMTIsIDEyXSwgLy8gYWxzbyBjYW4gYmUgc2V0IHRocm91Z2ggQ1NTXG5cblx0XHQvLyBpY29uQW5jaG9yOiAoUG9pbnQpLFxuXHRcdC8vIHBvcHVwQW5jaG9yOiAoUG9pbnQpLFxuXG5cdFx0Ly8gQG9wdGlvbiBodG1sOiBTdHJpbmcgPSAnJ1xuXHRcdC8vIEN1c3RvbSBIVE1MIGNvZGUgdG8gcHV0IGluc2lkZSB0aGUgZGl2IGVsZW1lbnQsIGVtcHR5IGJ5IGRlZmF1bHQuXG5cdFx0aHRtbDogZmFsc2UsXG5cblx0XHQvLyBAb3B0aW9uIGJnUG9zOiBQb2ludCA9IFswLCAwXVxuXHRcdC8vIE9wdGlvbmFsIHJlbGF0aXZlIHBvc2l0aW9uIG9mIHRoZSBiYWNrZ3JvdW5kLCBpbiBwaXhlbHNcblx0XHRiZ1BvczogbnVsbCxcblxuXHRcdGNsYXNzTmFtZTogJ2xlYWZsZXQtZGl2LWljb24nXG5cdH0sXG5cblx0Y3JlYXRlSWNvbjogZnVuY3Rpb24gKG9sZEljb24pIHtcblx0XHR2YXIgZGl2ID0gKG9sZEljb24gJiYgb2xkSWNvbi50YWdOYW1lID09PSAnRElWJykgPyBvbGRJY29uIDogZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2JyksXG5cdFx0ICAgIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHRkaXYuaW5uZXJIVE1MID0gb3B0aW9ucy5odG1sICE9PSBmYWxzZSA/IG9wdGlvbnMuaHRtbCA6ICcnO1xuXG5cdFx0aWYgKG9wdGlvbnMuYmdQb3MpIHtcblx0XHRcdHZhciBiZ1BvcyA9IEwucG9pbnQob3B0aW9ucy5iZ1Bvcyk7XG5cdFx0XHRkaXYuc3R5bGUuYmFja2dyb3VuZFBvc2l0aW9uID0gKC1iZ1Bvcy54KSArICdweCAnICsgKC1iZ1Bvcy55KSArICdweCc7XG5cdFx0fVxuXHRcdHRoaXMuX3NldEljb25TdHlsZXMoZGl2LCAnaWNvbicpO1xuXG5cdFx0cmV0dXJuIGRpdjtcblx0fSxcblxuXHRjcmVhdGVTaGFkb3c6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gbnVsbDtcblx0fVxufSk7XG5cbi8vIEBmYWN0b3J5IEwuZGl2SWNvbihvcHRpb25zOiBEaXZJY29uIG9wdGlvbnMpXG4vLyBDcmVhdGVzIGEgYERpdkljb25gIGluc3RhbmNlIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG5MLmRpdkljb24gPSBmdW5jdGlvbiAob3B0aW9ucykge1xuXHRyZXR1cm4gbmV3IEwuRGl2SWNvbihvcHRpb25zKTtcbn07XG5cblxuXG4vKlxyXG4gKiBAY2xhc3MgRGl2T3ZlcmxheVxyXG4gKiBAaW5oZXJpdHMgTGF5ZXJcclxuICogQGFrYSBMLkRpdk92ZXJsYXlcclxuICogQmFzZSBtb2RlbCBmb3IgTC5Qb3B1cCBhbmQgTC5Ub29sdGlwLiBJbmhlcml0IGZyb20gaXQgZm9yIGN1c3RvbSBwb3B1cCBsaWtlIHBsdWdpbnMuXHJcbiAqL1xyXG5cclxuLy8gQG5hbWVzcGFjZSBEaXZPdmVybGF5XHJcbkwuRGl2T3ZlcmxheSA9IEwuTGF5ZXIuZXh0ZW5kKHtcclxuXHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIERpdk92ZXJsYXkgb3B0aW9uc1xyXG5cdG9wdGlvbnM6IHtcclxuXHRcdC8vIEBvcHRpb24gb2Zmc2V0OiBQb2ludCA9IFBvaW50KDAsIDcpXHJcblx0XHQvLyBUaGUgb2Zmc2V0IG9mIHRoZSBwb3B1cCBwb3NpdGlvbi4gVXNlZnVsIHRvIGNvbnRyb2wgdGhlIGFuY2hvclxyXG5cdFx0Ly8gb2YgdGhlIHBvcHVwIHdoZW4gb3BlbmluZyBpdCBvbiBzb21lIG92ZXJsYXlzLlxyXG5cdFx0b2Zmc2V0OiBbMCwgN10sXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBjbGFzc05hbWU6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBBIGN1c3RvbSBDU1MgY2xhc3MgbmFtZSB0byBhc3NpZ24gdG8gdGhlIHBvcHVwLlxyXG5cdFx0Y2xhc3NOYW1lOiAnJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHBhbmU6IFN0cmluZyA9ICdwb3B1cFBhbmUnXHJcblx0XHQvLyBgTWFwIHBhbmVgIHdoZXJlIHRoZSBwb3B1cCB3aWxsIGJlIGFkZGVkLlxyXG5cdFx0cGFuZTogJ3BvcHVwUGFuZSdcclxuXHR9LFxyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucywgc291cmNlKSB7XHJcblx0XHRMLnNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XHJcblxyXG5cdFx0dGhpcy5fc291cmNlID0gc291cmNlO1xyXG5cdH0sXHJcblxyXG5cdG9uQWRkOiBmdW5jdGlvbiAobWFwKSB7XHJcblx0XHR0aGlzLl96b29tQW5pbWF0ZWQgPSBtYXAuX3pvb21BbmltYXRlZDtcclxuXHJcblx0XHRpZiAoIXRoaXMuX2NvbnRhaW5lcikge1xyXG5cdFx0XHR0aGlzLl9pbml0TGF5b3V0KCk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKG1hcC5fZmFkZUFuaW1hdGVkKSB7XHJcblx0XHRcdEwuRG9tVXRpbC5zZXRPcGFjaXR5KHRoaXMuX2NvbnRhaW5lciwgMCk7XHJcblx0XHR9XHJcblxyXG5cdFx0Y2xlYXJUaW1lb3V0KHRoaXMuX3JlbW92ZVRpbWVvdXQpO1xyXG5cdFx0dGhpcy5nZXRQYW5lKCkuYXBwZW5kQ2hpbGQodGhpcy5fY29udGFpbmVyKTtcclxuXHRcdHRoaXMudXBkYXRlKCk7XHJcblxyXG5cdFx0aWYgKG1hcC5fZmFkZUFuaW1hdGVkKSB7XHJcblx0XHRcdEwuRG9tVXRpbC5zZXRPcGFjaXR5KHRoaXMuX2NvbnRhaW5lciwgMSk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5icmluZ1RvRnJvbnQoKTtcclxuXHR9LFxyXG5cclxuXHRvblJlbW92ZTogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0aWYgKG1hcC5fZmFkZUFuaW1hdGVkKSB7XHJcblx0XHRcdEwuRG9tVXRpbC5zZXRPcGFjaXR5KHRoaXMuX2NvbnRhaW5lciwgMCk7XHJcblx0XHRcdHRoaXMuX3JlbW92ZVRpbWVvdXQgPSBzZXRUaW1lb3V0KEwuYmluZChMLkRvbVV0aWwucmVtb3ZlLCBMLkRvbVV0aWwsIHRoaXMuX2NvbnRhaW5lciksIDIwMCk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRMLkRvbVV0aWwucmVtb3ZlKHRoaXMuX2NvbnRhaW5lcik7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQG5hbWVzcGFjZSBQb3B1cFxyXG5cdC8vIEBtZXRob2QgZ2V0TGF0TG5nOiBMYXRMbmdcclxuXHQvLyBSZXR1cm5zIHRoZSBnZW9ncmFwaGljYWwgcG9pbnQgb2YgcG9wdXAuXHJcblx0Z2V0TGF0TG5nOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fbGF0bG5nO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0TGF0TG5nKGxhdGxuZzogTGF0TG5nKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIGdlb2dyYXBoaWNhbCBwb2ludCB3aGVyZSB0aGUgcG9wdXAgd2lsbCBvcGVuLlxyXG5cdHNldExhdExuZzogZnVuY3Rpb24gKGxhdGxuZykge1xyXG5cdFx0dGhpcy5fbGF0bG5nID0gTC5sYXRMbmcobGF0bG5nKTtcclxuXHRcdGlmICh0aGlzLl9tYXApIHtcclxuXHRcdFx0dGhpcy5fdXBkYXRlUG9zaXRpb24oKTtcclxuXHRcdFx0dGhpcy5fYWRqdXN0UGFuKCk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldENvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudFxyXG5cdC8vIFJldHVybnMgdGhlIGNvbnRlbnQgb2YgdGhlIHBvcHVwLlxyXG5cdGdldENvbnRlbnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9jb250ZW50O1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0Q29udGVudChodG1sQ29udGVudDogU3RyaW5nfEhUTUxFbGVtZW50fEZ1bmN0aW9uKTogdGhpc1xyXG5cdC8vIFNldHMgdGhlIEhUTUwgY29udGVudCBvZiB0aGUgcG9wdXAuIElmIGEgZnVuY3Rpb24gaXMgcGFzc2VkIHRoZSBzb3VyY2UgbGF5ZXIgd2lsbCBiZSBwYXNzZWQgdG8gdGhlIGZ1bmN0aW9uLiBUaGUgZnVuY3Rpb24gc2hvdWxkIHJldHVybiBhIGBTdHJpbmdgIG9yIGBIVE1MRWxlbWVudGAgdG8gYmUgdXNlZCBpbiB0aGUgcG9wdXAuXHJcblx0c2V0Q29udGVudDogZnVuY3Rpb24gKGNvbnRlbnQpIHtcclxuXHRcdHRoaXMuX2NvbnRlbnQgPSBjb250ZW50O1xyXG5cdFx0dGhpcy51cGRhdGUoKTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0RWxlbWVudDogU3RyaW5nfEhUTUxFbGVtZW50XHJcblx0Ly8gQWxpYXMgZm9yIFtnZXRDb250ZW50KCldKCNwb3B1cC1nZXRjb250ZW50KVxyXG5cdGdldEVsZW1lbnQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9jb250YWluZXI7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB1cGRhdGU6IG51bGxcclxuXHQvLyBVcGRhdGVzIHRoZSBwb3B1cCBjb250ZW50LCBsYXlvdXQgYW5kIHBvc2l0aW9uLiBVc2VmdWwgZm9yIHVwZGF0aW5nIHRoZSBwb3B1cCBhZnRlciBzb21ldGhpbmcgaW5zaWRlIGNoYW5nZWQsIGUuZy4gaW1hZ2UgbG9hZGVkLlxyXG5cdHVwZGF0ZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLl9tYXApIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0dGhpcy5fY29udGFpbmVyLnN0eWxlLnZpc2liaWxpdHkgPSAnaGlkZGVuJztcclxuXHJcblx0XHR0aGlzLl91cGRhdGVDb250ZW50KCk7XHJcblx0XHR0aGlzLl91cGRhdGVMYXlvdXQoKTtcclxuXHRcdHRoaXMuX3VwZGF0ZVBvc2l0aW9uKCk7XHJcblxyXG5cdFx0dGhpcy5fY29udGFpbmVyLnN0eWxlLnZpc2liaWxpdHkgPSAnJztcclxuXHJcblx0XHR0aGlzLl9hZGp1c3RQYW4oKTtcclxuXHR9LFxyXG5cclxuXHRnZXRFdmVudHM6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBldmVudHMgPSB7XHJcblx0XHRcdHpvb206IHRoaXMuX3VwZGF0ZVBvc2l0aW9uLFxyXG5cdFx0XHR2aWV3cmVzZXQ6IHRoaXMuX3VwZGF0ZVBvc2l0aW9uXHJcblx0XHR9O1xyXG5cclxuXHRcdGlmICh0aGlzLl96b29tQW5pbWF0ZWQpIHtcclxuXHRcdFx0ZXZlbnRzLnpvb21hbmltID0gdGhpcy5fYW5pbWF0ZVpvb207XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gZXZlbnRzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgaXNPcGVuOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgd2hlbiB0aGUgcG9wdXAgaXMgdmlzaWJsZSBvbiB0aGUgbWFwLlxyXG5cdGlzT3BlbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuICEhdGhpcy5fbWFwICYmIHRoaXMuX21hcC5oYXNMYXllcih0aGlzKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGJyaW5nVG9Gcm9udDogdGhpc1xyXG5cdC8vIEJyaW5ncyB0aGlzIHBvcHVwIGluIGZyb250IG9mIG90aGVyIHBvcHVwcyAoaW4gdGhlIHNhbWUgbWFwIHBhbmUpLlxyXG5cdGJyaW5nVG9Gcm9udDogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKHRoaXMuX21hcCkge1xyXG5cdFx0XHRMLkRvbVV0aWwudG9Gcm9udCh0aGlzLl9jb250YWluZXIpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBicmluZ1RvQmFjazogdGhpc1xyXG5cdC8vIEJyaW5ncyB0aGlzIHBvcHVwIHRvIHRoZSBiYWNrIG9mIG90aGVyIHBvcHVwcyAoaW4gdGhlIHNhbWUgbWFwIHBhbmUpLlxyXG5cdGJyaW5nVG9CYWNrOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAodGhpcy5fbWFwKSB7XHJcblx0XHRcdEwuRG9tVXRpbC50b0JhY2sodGhpcy5fY29udGFpbmVyKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdF91cGRhdGVDb250ZW50OiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX2NvbnRlbnQpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0dmFyIG5vZGUgPSB0aGlzLl9jb250ZW50Tm9kZTtcclxuXHRcdHZhciBjb250ZW50ID0gKHR5cGVvZiB0aGlzLl9jb250ZW50ID09PSAnZnVuY3Rpb24nKSA/IHRoaXMuX2NvbnRlbnQodGhpcy5fc291cmNlIHx8IHRoaXMpIDogdGhpcy5fY29udGVudDtcclxuXHJcblx0XHRpZiAodHlwZW9mIGNvbnRlbnQgPT09ICdzdHJpbmcnKSB7XHJcblx0XHRcdG5vZGUuaW5uZXJIVE1MID0gY29udGVudDtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdHdoaWxlIChub2RlLmhhc0NoaWxkTm9kZXMoKSkge1xyXG5cdFx0XHRcdG5vZGUucmVtb3ZlQ2hpbGQobm9kZS5maXJzdENoaWxkKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRub2RlLmFwcGVuZENoaWxkKGNvbnRlbnQpO1xyXG5cdFx0fVxyXG5cdFx0dGhpcy5maXJlKCdjb250ZW50dXBkYXRlJyk7XHJcblx0fSxcclxuXHJcblx0X3VwZGF0ZVBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX21hcCkgeyByZXR1cm47IH1cclxuXHJcblx0XHR2YXIgcG9zID0gdGhpcy5fbWFwLmxhdExuZ1RvTGF5ZXJQb2ludCh0aGlzLl9sYXRsbmcpLFxyXG5cdFx0ICAgIG9mZnNldCA9IEwucG9pbnQodGhpcy5vcHRpb25zLm9mZnNldCksXHJcblx0XHQgICAgYW5jaG9yID0gdGhpcy5fZ2V0QW5jaG9yKCk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX3pvb21BbmltYXRlZCkge1xyXG5cdFx0XHRMLkRvbVV0aWwuc2V0UG9zaXRpb24odGhpcy5fY29udGFpbmVyLCBwb3MuYWRkKGFuY2hvcikpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0b2Zmc2V0ID0gb2Zmc2V0LmFkZChwb3MpLmFkZChhbmNob3IpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBib3R0b20gPSB0aGlzLl9jb250YWluZXJCb3R0b20gPSAtb2Zmc2V0LnksXHJcblx0XHQgICAgbGVmdCA9IHRoaXMuX2NvbnRhaW5lckxlZnQgPSAtTWF0aC5yb3VuZCh0aGlzLl9jb250YWluZXJXaWR0aCAvIDIpICsgb2Zmc2V0Lng7XHJcblxyXG5cdFx0Ly8gYm90dG9tIHBvc2l0aW9uIHRoZSBwb3B1cCBpbiBjYXNlIHRoZSBoZWlnaHQgb2YgdGhlIHBvcHVwIGNoYW5nZXMgKGltYWdlcyBsb2FkaW5nIGV0YylcclxuXHRcdHRoaXMuX2NvbnRhaW5lci5zdHlsZS5ib3R0b20gPSBib3R0b20gKyAncHgnO1xyXG5cdFx0dGhpcy5fY29udGFpbmVyLnN0eWxlLmxlZnQgPSBsZWZ0ICsgJ3B4JztcclxuXHR9LFxyXG5cclxuXHRfZ2V0QW5jaG9yOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gWzAsIDBdO1xyXG5cdH1cclxuXHJcbn0pO1xyXG5cblxuXG4vKlxyXG4gKiBAY2xhc3MgUG9wdXBcclxuICogQGluaGVyaXRzIERpdk92ZXJsYXlcclxuICogQGFrYSBMLlBvcHVwXHJcbiAqIFVzZWQgdG8gb3BlbiBwb3B1cHMgaW4gY2VydGFpbiBwbGFjZXMgb2YgdGhlIG1hcC4gVXNlIFtNYXAub3BlblBvcHVwXSgjbWFwLW9wZW5wb3B1cCkgdG9cclxuICogb3BlbiBwb3B1cHMgd2hpbGUgbWFraW5nIHN1cmUgdGhhdCBvbmx5IG9uZSBwb3B1cCBpcyBvcGVuIGF0IG9uZSB0aW1lXHJcbiAqIChyZWNvbW1lbmRlZCBmb3IgdXNhYmlsaXR5KSwgb3IgdXNlIFtNYXAuYWRkTGF5ZXJdKCNtYXAtYWRkbGF5ZXIpIHRvIG9wZW4gYXMgbWFueSBhcyB5b3Ugd2FudC5cclxuICpcclxuICogQGV4YW1wbGVcclxuICpcclxuICogSWYgeW91IHdhbnQgdG8ganVzdCBiaW5kIGEgcG9wdXAgdG8gbWFya2VyIGNsaWNrIGFuZCB0aGVuIG9wZW4gaXQsIGl0J3MgcmVhbGx5IGVhc3k6XHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIG1hcmtlci5iaW5kUG9wdXAocG9wdXBDb250ZW50KS5vcGVuUG9wdXAoKTtcclxuICogYGBgXHJcbiAqIFBhdGggb3ZlcmxheXMgbGlrZSBwb2x5bGluZXMgYWxzbyBoYXZlIGEgYGJpbmRQb3B1cGAgbWV0aG9kLlxyXG4gKiBIZXJlJ3MgYSBtb3JlIGNvbXBsaWNhdGVkIHdheSB0byBvcGVuIGEgcG9wdXAgb24gYSBtYXA6XHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBwb3B1cCA9IEwucG9wdXAoKVxyXG4gKiBcdC5zZXRMYXRMbmcobGF0bG5nKVxyXG4gKiBcdC5zZXRDb250ZW50KCc8cD5IZWxsbyB3b3JsZCE8YnIgLz5UaGlzIGlzIGEgbmljZSBwb3B1cC48L3A+JylcclxuICogXHQub3Blbk9uKG1hcCk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcblxyXG4vLyBAbmFtZXNwYWNlIFBvcHVwXHJcbkwuUG9wdXAgPSBMLkRpdk92ZXJsYXkuZXh0ZW5kKHtcclxuXHJcblx0Ly8gQHNlY3Rpb25cclxuXHQvLyBAYWthIFBvcHVwIG9wdGlvbnNcclxuXHRvcHRpb25zOiB7XHJcblx0XHQvLyBAb3B0aW9uIG1heFdpZHRoOiBOdW1iZXIgPSAzMDBcclxuXHRcdC8vIE1heCB3aWR0aCBvZiB0aGUgcG9wdXAsIGluIHBpeGVscy5cclxuXHRcdG1heFdpZHRoOiAzMDAsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBtaW5XaWR0aDogTnVtYmVyID0gNTBcclxuXHRcdC8vIE1pbiB3aWR0aCBvZiB0aGUgcG9wdXAsIGluIHBpeGVscy5cclxuXHRcdG1pbldpZHRoOiA1MCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIG1heEhlaWdodDogTnVtYmVyID0gbnVsbFxyXG5cdFx0Ly8gSWYgc2V0LCBjcmVhdGVzIGEgc2Nyb2xsYWJsZSBjb250YWluZXIgb2YgdGhlIGdpdmVuIGhlaWdodFxyXG5cdFx0Ly8gaW5zaWRlIGEgcG9wdXAgaWYgaXRzIGNvbnRlbnQgZXhjZWVkcyBpdC5cclxuXHRcdG1heEhlaWdodDogbnVsbCxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGF1dG9QYW46IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBTZXQgaXQgdG8gYGZhbHNlYCBpZiB5b3UgZG9uJ3Qgd2FudCB0aGUgbWFwIHRvIGRvIHBhbm5pbmcgYW5pbWF0aW9uXHJcblx0XHQvLyB0byBmaXQgdGhlIG9wZW5lZCBwb3B1cC5cclxuXHRcdGF1dG9QYW46IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvUGFuUGFkZGluZ1RvcExlZnQ6IFBvaW50ID0gbnVsbFxyXG5cdFx0Ly8gVGhlIG1hcmdpbiBiZXR3ZWVuIHRoZSBwb3B1cCBhbmQgdGhlIHRvcCBsZWZ0IGNvcm5lciBvZiB0aGUgbWFwXHJcblx0XHQvLyB2aWV3IGFmdGVyIGF1dG9wYW5uaW5nIHdhcyBwZXJmb3JtZWQuXHJcblx0XHRhdXRvUGFuUGFkZGluZ1RvcExlZnQ6IG51bGwsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvUGFuUGFkZGluZ0JvdHRvbVJpZ2h0OiBQb2ludCA9IG51bGxcclxuXHRcdC8vIFRoZSBtYXJnaW4gYmV0d2VlbiB0aGUgcG9wdXAgYW5kIHRoZSBib3R0b20gcmlnaHQgY29ybmVyIG9mIHRoZSBtYXBcclxuXHRcdC8vIHZpZXcgYWZ0ZXIgYXV0b3Bhbm5pbmcgd2FzIHBlcmZvcm1lZC5cclxuXHRcdGF1dG9QYW5QYWRkaW5nQm90dG9tUmlnaHQ6IG51bGwsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvUGFuUGFkZGluZzogUG9pbnQgPSBQb2ludCg1LCA1KVxyXG5cdFx0Ly8gRXF1aXZhbGVudCBvZiBzZXR0aW5nIGJvdGggdG9wIGxlZnQgYW5kIGJvdHRvbSByaWdodCBhdXRvcGFuIHBhZGRpbmcgdG8gdGhlIHNhbWUgdmFsdWUuXHJcblx0XHRhdXRvUGFuUGFkZGluZzogWzUsIDVdLFxyXG5cclxuXHRcdC8vIEBvcHRpb24ga2VlcEluVmlldzogQm9vbGVhbiA9IGZhbHNlXHJcblx0XHQvLyBTZXQgaXQgdG8gYHRydWVgIGlmIHlvdSB3YW50IHRvIHByZXZlbnQgdXNlcnMgZnJvbSBwYW5uaW5nIHRoZSBwb3B1cFxyXG5cdFx0Ly8gb2ZmIG9mIHRoZSBzY3JlZW4gd2hpbGUgaXQgaXMgb3Blbi5cclxuXHRcdGtlZXBJblZpZXc6IGZhbHNlLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gY2xvc2VCdXR0b246IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBDb250cm9scyB0aGUgcHJlc2VuY2Ugb2YgYSBjbG9zZSBidXR0b24gaW4gdGhlIHBvcHVwLlxyXG5cdFx0Y2xvc2VCdXR0b246IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBhdXRvQ2xvc2U6IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBTZXQgaXQgdG8gYGZhbHNlYCBpZiB5b3Ugd2FudCB0byBvdmVycmlkZSB0aGUgZGVmYXVsdCBiZWhhdmlvciBvZlxyXG5cdFx0Ly8gdGhlIHBvcHVwIGNsb3Npbmcgd2hlbiB1c2VyIGNsaWNrcyB0aGUgbWFwIChzZXQgZ2xvYmFsbHkgYnlcclxuXHRcdC8vIHRoZSBNYXAncyBbY2xvc2VQb3B1cE9uQ2xpY2tdKCNtYXAtY2xvc2Vwb3B1cG9uY2xpY2spIG9wdGlvbikuXHJcblx0XHRhdXRvQ2xvc2U6IHRydWUsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBjbGFzc05hbWU6IFN0cmluZyA9ICcnXHJcblx0XHQvLyBBIGN1c3RvbSBDU1MgY2xhc3MgbmFtZSB0byBhc3NpZ24gdG8gdGhlIHBvcHVwLlxyXG5cdFx0Y2xhc3NOYW1lOiAnJ1xyXG5cdH0sXHJcblxyXG5cdC8vIEBuYW1lc3BhY2UgUG9wdXBcclxuXHQvLyBAbWV0aG9kIG9wZW5PbihtYXA6IE1hcCk6IHRoaXNcclxuXHQvLyBBZGRzIHRoZSBwb3B1cCB0byB0aGUgbWFwIGFuZCBjbG9zZXMgdGhlIHByZXZpb3VzIG9uZS4gVGhlIHNhbWUgYXMgYG1hcC5vcGVuUG9wdXAocG9wdXApYC5cclxuXHRvcGVuT246IGZ1bmN0aW9uIChtYXApIHtcclxuXHRcdG1hcC5vcGVuUG9wdXAodGhpcyk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0TC5EaXZPdmVybGF5LnByb3RvdHlwZS5vbkFkZC5jYWxsKHRoaXMsIG1hcCk7XHJcblxyXG5cdFx0Ly8gQG5hbWVzcGFjZSBNYXBcclxuXHRcdC8vIEBzZWN0aW9uIFBvcHVwIGV2ZW50c1xyXG5cdFx0Ly8gQGV2ZW50IHBvcHVwb3BlbjogUG9wdXBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiBhIHBvcHVwIGlzIG9wZW5lZCBpbiB0aGUgbWFwXHJcblx0XHRtYXAuZmlyZSgncG9wdXBvcGVuJywge3BvcHVwOiB0aGlzfSk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX3NvdXJjZSkge1xyXG5cdFx0XHQvLyBAbmFtZXNwYWNlIExheWVyXHJcblx0XHRcdC8vIEBzZWN0aW9uIFBvcHVwIGV2ZW50c1xyXG5cdFx0XHQvLyBAZXZlbnQgcG9wdXBvcGVuOiBQb3B1cEV2ZW50XHJcblx0XHRcdC8vIEZpcmVkIHdoZW4gYSBwb3B1cCBib3VuZCB0byB0aGlzIGxheWVyIGlzIG9wZW5lZFxyXG5cdFx0XHR0aGlzLl9zb3VyY2UuZmlyZSgncG9wdXBvcGVuJywge3BvcHVwOiB0aGlzfSwgdHJ1ZSk7XHJcblx0XHRcdC8vIEZvciBub24tcGF0aCBsYXllcnMsIHdlIHRvZ2dsZSB0aGUgcG9wdXAgd2hlbiBjbGlja2luZ1xyXG5cdFx0XHQvLyBhZ2FpbiB0aGUgbGF5ZXIsIHNvIHByZXZlbnQgdGhlIG1hcCB0byByZW9wZW4gaXQuXHJcblx0XHRcdGlmICghKHRoaXMuX3NvdXJjZSBpbnN0YW5jZW9mIEwuUGF0aCkpIHtcclxuXHRcdFx0XHR0aGlzLl9zb3VyY2Uub24oJ3ByZWNsaWNrJywgTC5Eb21FdmVudC5zdG9wUHJvcGFnYXRpb24pO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0b25SZW1vdmU6IGZ1bmN0aW9uIChtYXApIHtcclxuXHRcdEwuRGl2T3ZlcmxheS5wcm90b3R5cGUub25SZW1vdmUuY2FsbCh0aGlzLCBtYXApO1xyXG5cclxuXHRcdC8vIEBuYW1lc3BhY2UgTWFwXHJcblx0XHQvLyBAc2VjdGlvbiBQb3B1cCBldmVudHNcclxuXHRcdC8vIEBldmVudCBwb3B1cGNsb3NlOiBQb3B1cEV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIGEgcG9wdXAgaW4gdGhlIG1hcCBpcyBjbG9zZWRcclxuXHRcdG1hcC5maXJlKCdwb3B1cGNsb3NlJywge3BvcHVwOiB0aGlzfSk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX3NvdXJjZSkge1xyXG5cdFx0XHQvLyBAbmFtZXNwYWNlIExheWVyXHJcblx0XHRcdC8vIEBzZWN0aW9uIFBvcHVwIGV2ZW50c1xyXG5cdFx0XHQvLyBAZXZlbnQgcG9wdXBjbG9zZTogUG9wdXBFdmVudFxyXG5cdFx0XHQvLyBGaXJlZCB3aGVuIGEgcG9wdXAgYm91bmQgdG8gdGhpcyBsYXllciBpcyBjbG9zZWRcclxuXHRcdFx0dGhpcy5fc291cmNlLmZpcmUoJ3BvcHVwY2xvc2UnLCB7cG9wdXA6IHRoaXN9LCB0cnVlKTtcclxuXHRcdFx0aWYgKCEodGhpcy5fc291cmNlIGluc3RhbmNlb2YgTC5QYXRoKSkge1xyXG5cdFx0XHRcdHRoaXMuX3NvdXJjZS5vZmYoJ3ByZWNsaWNrJywgTC5Eb21FdmVudC5zdG9wUHJvcGFnYXRpb24pO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Z2V0RXZlbnRzOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgZXZlbnRzID0gTC5EaXZPdmVybGF5LnByb3RvdHlwZS5nZXRFdmVudHMuY2FsbCh0aGlzKTtcclxuXHJcblx0XHRpZiAoJ2Nsb3NlT25DbGljaycgaW4gdGhpcy5vcHRpb25zID8gdGhpcy5vcHRpb25zLmNsb3NlT25DbGljayA6IHRoaXMuX21hcC5vcHRpb25zLmNsb3NlUG9wdXBPbkNsaWNrKSB7XHJcblx0XHRcdGV2ZW50cy5wcmVjbGljayA9IHRoaXMuX2Nsb3NlO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMua2VlcEluVmlldykge1xyXG5cdFx0XHRldmVudHMubW92ZWVuZCA9IHRoaXMuX2FkanVzdFBhbjtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gZXZlbnRzO1xyXG5cdH0sXHJcblxyXG5cdF9jbG9zZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKHRoaXMuX21hcCkge1xyXG5cdFx0XHR0aGlzLl9tYXAuY2xvc2VQb3B1cCh0aGlzKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfaW5pdExheW91dDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIHByZWZpeCA9ICdsZWFmbGV0LXBvcHVwJyxcclxuXHRcdCAgICBjb250YWluZXIgPSB0aGlzLl9jb250YWluZXIgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLFxyXG5cdFx0XHRwcmVmaXggKyAnICcgKyAodGhpcy5vcHRpb25zLmNsYXNzTmFtZSB8fCAnJykgK1xyXG5cdFx0XHQnIGxlYWZsZXQtem9vbS1hbmltYXRlZCcpO1xyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMuY2xvc2VCdXR0b24pIHtcclxuXHRcdFx0dmFyIGNsb3NlQnV0dG9uID0gdGhpcy5fY2xvc2VCdXR0b24gPSBMLkRvbVV0aWwuY3JlYXRlKCdhJywgcHJlZml4ICsgJy1jbG9zZS1idXR0b24nLCBjb250YWluZXIpO1xyXG5cdFx0XHRjbG9zZUJ1dHRvbi5ocmVmID0gJyNjbG9zZSc7XHJcblx0XHRcdGNsb3NlQnV0dG9uLmlubmVySFRNTCA9ICcmIzIxNTsnO1xyXG5cclxuXHRcdFx0TC5Eb21FdmVudC5vbihjbG9zZUJ1dHRvbiwgJ2NsaWNrJywgdGhpcy5fb25DbG9zZUJ1dHRvbkNsaWNrLCB0aGlzKTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgd3JhcHBlciA9IHRoaXMuX3dyYXBwZXIgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCBwcmVmaXggKyAnLWNvbnRlbnQtd3JhcHBlcicsIGNvbnRhaW5lcik7XHJcblx0XHR0aGlzLl9jb250ZW50Tm9kZSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsIHByZWZpeCArICctY29udGVudCcsIHdyYXBwZXIpO1xyXG5cclxuXHRcdEwuRG9tRXZlbnRcclxuXHRcdFx0LmRpc2FibGVDbGlja1Byb3BhZ2F0aW9uKHdyYXBwZXIpXHJcblx0XHRcdC5kaXNhYmxlU2Nyb2xsUHJvcGFnYXRpb24odGhpcy5fY29udGVudE5vZGUpXHJcblx0XHRcdC5vbih3cmFwcGVyLCAnY29udGV4dG1lbnUnLCBMLkRvbUV2ZW50LnN0b3BQcm9wYWdhdGlvbik7XHJcblxyXG5cdFx0dGhpcy5fdGlwQ29udGFpbmVyID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2JywgcHJlZml4ICsgJy10aXAtY29udGFpbmVyJywgY29udGFpbmVyKTtcclxuXHRcdHRoaXMuX3RpcCA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsIHByZWZpeCArICctdGlwJywgdGhpcy5fdGlwQ29udGFpbmVyKTtcclxuXHR9LFxyXG5cclxuXHRfdXBkYXRlTGF5b3V0OiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgY29udGFpbmVyID0gdGhpcy5fY29udGVudE5vZGUsXHJcblx0XHQgICAgc3R5bGUgPSBjb250YWluZXIuc3R5bGU7XHJcblxyXG5cdFx0c3R5bGUud2lkdGggPSAnJztcclxuXHRcdHN0eWxlLndoaXRlU3BhY2UgPSAnbm93cmFwJztcclxuXHJcblx0XHR2YXIgd2lkdGggPSBjb250YWluZXIub2Zmc2V0V2lkdGg7XHJcblx0XHR3aWR0aCA9IE1hdGgubWluKHdpZHRoLCB0aGlzLm9wdGlvbnMubWF4V2lkdGgpO1xyXG5cdFx0d2lkdGggPSBNYXRoLm1heCh3aWR0aCwgdGhpcy5vcHRpb25zLm1pbldpZHRoKTtcclxuXHJcblx0XHRzdHlsZS53aWR0aCA9ICh3aWR0aCArIDEpICsgJ3B4JztcclxuXHRcdHN0eWxlLndoaXRlU3BhY2UgPSAnJztcclxuXHJcblx0XHRzdHlsZS5oZWlnaHQgPSAnJztcclxuXHJcblx0XHR2YXIgaGVpZ2h0ID0gY29udGFpbmVyLm9mZnNldEhlaWdodCxcclxuXHRcdCAgICBtYXhIZWlnaHQgPSB0aGlzLm9wdGlvbnMubWF4SGVpZ2h0LFxyXG5cdFx0ICAgIHNjcm9sbGVkQ2xhc3MgPSAnbGVhZmxldC1wb3B1cC1zY3JvbGxlZCc7XHJcblxyXG5cdFx0aWYgKG1heEhlaWdodCAmJiBoZWlnaHQgPiBtYXhIZWlnaHQpIHtcclxuXHRcdFx0c3R5bGUuaGVpZ2h0ID0gbWF4SGVpZ2h0ICsgJ3B4JztcclxuXHRcdFx0TC5Eb21VdGlsLmFkZENsYXNzKGNvbnRhaW5lciwgc2Nyb2xsZWRDbGFzcyk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRMLkRvbVV0aWwucmVtb3ZlQ2xhc3MoY29udGFpbmVyLCBzY3JvbGxlZENsYXNzKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9jb250YWluZXJXaWR0aCA9IHRoaXMuX2NvbnRhaW5lci5vZmZzZXRXaWR0aDtcclxuXHR9LFxyXG5cclxuXHRfYW5pbWF0ZVpvb206IGZ1bmN0aW9uIChlKSB7XHJcblx0XHR2YXIgcG9zID0gdGhpcy5fbWFwLl9sYXRMbmdUb05ld0xheWVyUG9pbnQodGhpcy5fbGF0bG5nLCBlLnpvb20sIGUuY2VudGVyKSxcclxuXHRcdCAgICBhbmNob3IgPSB0aGlzLl9nZXRBbmNob3IoKTtcclxuXHRcdEwuRG9tVXRpbC5zZXRQb3NpdGlvbih0aGlzLl9jb250YWluZXIsIHBvcy5hZGQoYW5jaG9yKSk7XHJcblx0fSxcclxuXHJcblx0X2FkanVzdFBhbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLm9wdGlvbnMuYXV0b1BhbiB8fCAodGhpcy5fbWFwLl9wYW5BbmltICYmIHRoaXMuX21hcC5fcGFuQW5pbS5faW5Qcm9ncmVzcykpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0dmFyIG1hcCA9IHRoaXMuX21hcCxcclxuXHRcdCAgICBtYXJnaW5Cb3R0b20gPSBwYXJzZUludChMLkRvbVV0aWwuZ2V0U3R5bGUodGhpcy5fY29udGFpbmVyLCAnbWFyZ2luQm90dG9tJyksIDEwKSB8fCAwLFxyXG5cdFx0ICAgIGNvbnRhaW5lckhlaWdodCA9IHRoaXMuX2NvbnRhaW5lci5vZmZzZXRIZWlnaHQgKyBtYXJnaW5Cb3R0b20sXHJcblx0XHQgICAgY29udGFpbmVyV2lkdGggPSB0aGlzLl9jb250YWluZXJXaWR0aCxcclxuXHRcdCAgICBsYXllclBvcyA9IG5ldyBMLlBvaW50KHRoaXMuX2NvbnRhaW5lckxlZnQsIC1jb250YWluZXJIZWlnaHQgLSB0aGlzLl9jb250YWluZXJCb3R0b20pO1xyXG5cclxuXHRcdGxheWVyUG9zLl9hZGQoTC5Eb21VdGlsLmdldFBvc2l0aW9uKHRoaXMuX2NvbnRhaW5lcikpO1xyXG5cclxuXHRcdHZhciBjb250YWluZXJQb3MgPSBtYXAubGF5ZXJQb2ludFRvQ29udGFpbmVyUG9pbnQobGF5ZXJQb3MpLFxyXG5cdFx0ICAgIHBhZGRpbmcgPSBMLnBvaW50KHRoaXMub3B0aW9ucy5hdXRvUGFuUGFkZGluZyksXHJcblx0XHQgICAgcGFkZGluZ1RMID0gTC5wb2ludCh0aGlzLm9wdGlvbnMuYXV0b1BhblBhZGRpbmdUb3BMZWZ0IHx8IHBhZGRpbmcpLFxyXG5cdFx0ICAgIHBhZGRpbmdCUiA9IEwucG9pbnQodGhpcy5vcHRpb25zLmF1dG9QYW5QYWRkaW5nQm90dG9tUmlnaHQgfHwgcGFkZGluZyksXHJcblx0XHQgICAgc2l6ZSA9IG1hcC5nZXRTaXplKCksXHJcblx0XHQgICAgZHggPSAwLFxyXG5cdFx0ICAgIGR5ID0gMDtcclxuXHJcblx0XHRpZiAoY29udGFpbmVyUG9zLnggKyBjb250YWluZXJXaWR0aCArIHBhZGRpbmdCUi54ID4gc2l6ZS54KSB7IC8vIHJpZ2h0XHJcblx0XHRcdGR4ID0gY29udGFpbmVyUG9zLnggKyBjb250YWluZXJXaWR0aCAtIHNpemUueCArIHBhZGRpbmdCUi54O1xyXG5cdFx0fVxyXG5cdFx0aWYgKGNvbnRhaW5lclBvcy54IC0gZHggLSBwYWRkaW5nVEwueCA8IDApIHsgLy8gbGVmdFxyXG5cdFx0XHRkeCA9IGNvbnRhaW5lclBvcy54IC0gcGFkZGluZ1RMLng7XHJcblx0XHR9XHJcblx0XHRpZiAoY29udGFpbmVyUG9zLnkgKyBjb250YWluZXJIZWlnaHQgKyBwYWRkaW5nQlIueSA+IHNpemUueSkgeyAvLyBib3R0b21cclxuXHRcdFx0ZHkgPSBjb250YWluZXJQb3MueSArIGNvbnRhaW5lckhlaWdodCAtIHNpemUueSArIHBhZGRpbmdCUi55O1xyXG5cdFx0fVxyXG5cdFx0aWYgKGNvbnRhaW5lclBvcy55IC0gZHkgLSBwYWRkaW5nVEwueSA8IDApIHsgLy8gdG9wXHJcblx0XHRcdGR5ID0gY29udGFpbmVyUG9zLnkgLSBwYWRkaW5nVEwueTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyBAbmFtZXNwYWNlIE1hcFxyXG5cdFx0Ly8gQHNlY3Rpb24gUG9wdXAgZXZlbnRzXHJcblx0XHQvLyBAZXZlbnQgYXV0b3BhbnN0YXJ0OiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFwIHN0YXJ0cyBhdXRvcGFubmluZyB3aGVuIG9wZW5pbmcgYSBwb3B1cC5cclxuXHRcdGlmIChkeCB8fCBkeSkge1xyXG5cdFx0XHRtYXBcclxuXHRcdFx0ICAgIC5maXJlKCdhdXRvcGFuc3RhcnQnKVxyXG5cdFx0XHQgICAgLnBhbkJ5KFtkeCwgZHldKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfb25DbG9zZUJ1dHRvbkNsaWNrOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0dGhpcy5fY2xvc2UoKTtcclxuXHRcdEwuRG9tRXZlbnQuc3RvcChlKTtcclxuXHR9LFxyXG5cclxuXHRfZ2V0QW5jaG9yOiBmdW5jdGlvbiAoKSB7XHJcblx0XHQvLyBXaGVyZSBzaG91bGQgd2UgYW5jaG9yIHRoZSBwb3B1cCBvbiB0aGUgc291cmNlIGxheWVyP1xyXG5cdFx0cmV0dXJuIEwucG9pbnQodGhpcy5fc291cmNlICYmIHRoaXMuX3NvdXJjZS5fZ2V0UG9wdXBBbmNob3IgPyB0aGlzLl9zb3VyY2UuX2dldFBvcHVwQW5jaG9yKCkgOiBbMCwgMF0pO1xyXG5cdH1cclxuXHJcbn0pO1xyXG5cclxuLy8gQG5hbWVzcGFjZSBQb3B1cFxyXG4vLyBAZmFjdG9yeSBMLnBvcHVwKG9wdGlvbnM/OiBQb3B1cCBvcHRpb25zLCBzb3VyY2U/OiBMYXllcilcclxuLy8gSW5zdGFudGlhdGVzIGEgYFBvcHVwYCBvYmplY3QgZ2l2ZW4gYW4gb3B0aW9uYWwgYG9wdGlvbnNgIG9iamVjdCB0aGF0IGRlc2NyaWJlcyBpdHMgYXBwZWFyYW5jZSBhbmQgbG9jYXRpb24gYW5kIGFuIG9wdGlvbmFsIGBzb3VyY2VgIG9iamVjdCB0aGF0IGlzIHVzZWQgdG8gdGFnIHRoZSBwb3B1cCB3aXRoIGEgcmVmZXJlbmNlIHRvIHRoZSBMYXllciB0byB3aGljaCBpdCByZWZlcnMuXHJcbkwucG9wdXAgPSBmdW5jdGlvbiAob3B0aW9ucywgc291cmNlKSB7XHJcblx0cmV0dXJuIG5ldyBMLlBvcHVwKG9wdGlvbnMsIHNvdXJjZSk7XHJcbn07XHJcblxyXG5cclxuLyogQG5hbWVzcGFjZSBNYXBcclxuICogQHNlY3Rpb24gSW50ZXJhY3Rpb24gT3B0aW9uc1xyXG4gKiBAb3B0aW9uIGNsb3NlUG9wdXBPbkNsaWNrOiBCb29sZWFuID0gdHJ1ZVxyXG4gKiBTZXQgaXQgdG8gYGZhbHNlYCBpZiB5b3UgZG9uJ3Qgd2FudCBwb3B1cHMgdG8gY2xvc2Ugd2hlbiB1c2VyIGNsaWNrcyB0aGUgbWFwLlxyXG4gKi9cclxuTC5NYXAubWVyZ2VPcHRpb25zKHtcclxuXHRjbG9zZVBvcHVwT25DbGljazogdHJ1ZVxyXG59KTtcclxuXHJcblxyXG4vLyBAbmFtZXNwYWNlIE1hcFxyXG4vLyBAc2VjdGlvbiBNZXRob2RzIGZvciBMYXllcnMgYW5kIENvbnRyb2xzXHJcbkwuTWFwLmluY2x1ZGUoe1xyXG5cdC8vIEBtZXRob2Qgb3BlblBvcHVwKHBvcHVwOiBQb3B1cCk6IHRoaXNcclxuXHQvLyBPcGVucyB0aGUgc3BlY2lmaWVkIHBvcHVwIHdoaWxlIGNsb3NpbmcgdGhlIHByZXZpb3VzbHkgb3BlbmVkICh0byBtYWtlIHN1cmUgb25seSBvbmUgaXMgb3BlbmVkIGF0IG9uZSB0aW1lIGZvciB1c2FiaWxpdHkpLlxyXG5cdC8vIEBhbHRlcm5hdGl2ZVxyXG5cdC8vIEBtZXRob2Qgb3BlblBvcHVwKGNvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudCwgbGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/OiBQb3B1cCBvcHRpb25zKTogdGhpc1xyXG5cdC8vIENyZWF0ZXMgYSBwb3B1cCB3aXRoIHRoZSBzcGVjaWZpZWQgY29udGVudCBhbmQgb3B0aW9ucyBhbmQgb3BlbnMgaXQgaW4gdGhlIGdpdmVuIHBvaW50IG9uIGEgbWFwLlxyXG5cdG9wZW5Qb3B1cDogZnVuY3Rpb24gKHBvcHVwLCBsYXRsbmcsIG9wdGlvbnMpIHtcclxuXHRcdGlmICghKHBvcHVwIGluc3RhbmNlb2YgTC5Qb3B1cCkpIHtcclxuXHRcdFx0cG9wdXAgPSBuZXcgTC5Qb3B1cChvcHRpb25zKS5zZXRDb250ZW50KHBvcHVwKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAobGF0bG5nKSB7XHJcblx0XHRcdHBvcHVwLnNldExhdExuZyhsYXRsbmcpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICh0aGlzLmhhc0xheWVyKHBvcHVwKSkge1xyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5fcG9wdXAgJiYgdGhpcy5fcG9wdXAub3B0aW9ucy5hdXRvQ2xvc2UpIHtcclxuXHRcdFx0dGhpcy5jbG9zZVBvcHVwKCk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fcG9wdXAgPSBwb3B1cDtcclxuXHRcdHJldHVybiB0aGlzLmFkZExheWVyKHBvcHVwKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGNsb3NlUG9wdXAocG9wdXA/OiBQb3B1cCk6IHRoaXNcclxuXHQvLyBDbG9zZXMgdGhlIHBvcHVwIHByZXZpb3VzbHkgb3BlbmVkIHdpdGggW29wZW5Qb3B1cF0oI21hcC1vcGVucG9wdXApIChvciB0aGUgZ2l2ZW4gb25lKS5cclxuXHRjbG9zZVBvcHVwOiBmdW5jdGlvbiAocG9wdXApIHtcclxuXHRcdGlmICghcG9wdXAgfHwgcG9wdXAgPT09IHRoaXMuX3BvcHVwKSB7XHJcblx0XHRcdHBvcHVwID0gdGhpcy5fcG9wdXA7XHJcblx0XHRcdHRoaXMuX3BvcHVwID0gbnVsbDtcclxuXHRcdH1cclxuXHRcdGlmIChwb3B1cCkge1xyXG5cdFx0XHR0aGlzLnJlbW92ZUxheWVyKHBvcHVwKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH1cclxufSk7XHJcblxyXG4vKlxyXG4gKiBAbmFtZXNwYWNlIExheWVyXHJcbiAqIEBzZWN0aW9uIFBvcHVwIG1ldGhvZHMgZXhhbXBsZVxyXG4gKlxyXG4gKiBBbGwgbGF5ZXJzIHNoYXJlIGEgc2V0IG9mIG1ldGhvZHMgY29udmVuaWVudCBmb3IgYmluZGluZyBwb3B1cHMgdG8gaXQuXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBsYXllciA9IEwuUG9seWdvbihsYXRsbmdzKS5iaW5kUG9wdXAoJ0hpIFRoZXJlIScpLmFkZFRvKG1hcCk7XHJcbiAqIGxheWVyLm9wZW5Qb3B1cCgpO1xyXG4gKiBsYXllci5jbG9zZVBvcHVwKCk7XHJcbiAqIGBgYFxyXG4gKlxyXG4gKiBQb3B1cHMgd2lsbCBhbHNvIGJlIGF1dG9tYXRpY2FsbHkgb3BlbmVkIHdoZW4gdGhlIGxheWVyIGlzIGNsaWNrZWQgb24gYW5kIGNsb3NlZCB3aGVuIHRoZSBsYXllciBpcyByZW1vdmVkIGZyb20gdGhlIG1hcCBvciBhbm90aGVyIHBvcHVwIGlzIG9wZW5lZC5cclxuICovXHJcblxyXG4vLyBAc2VjdGlvbiBQb3B1cCBtZXRob2RzXHJcbkwuTGF5ZXIuaW5jbHVkZSh7XHJcblxyXG5cdC8vIEBtZXRob2QgYmluZFBvcHVwKGNvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudHxGdW5jdGlvbnxQb3B1cCwgb3B0aW9ucz86IFBvcHVwIG9wdGlvbnMpOiB0aGlzXHJcblx0Ly8gQmluZHMgYSBwb3B1cCB0byB0aGUgbGF5ZXIgd2l0aCB0aGUgcGFzc2VkIGBjb250ZW50YCBhbmQgc2V0cyB1cCB0aGVcclxuXHQvLyBuZWNjZXNzYXJ5IGV2ZW50IGxpc3RlbmVycy4gSWYgYSBgRnVuY3Rpb25gIGlzIHBhc3NlZCBpdCB3aWxsIHJlY2VpdmVcclxuXHQvLyB0aGUgbGF5ZXIgYXMgdGhlIGZpcnN0IGFyZ3VtZW50IGFuZCBzaG91bGQgcmV0dXJuIGEgYFN0cmluZ2Agb3IgYEhUTUxFbGVtZW50YC5cclxuXHRiaW5kUG9wdXA6IGZ1bmN0aW9uIChjb250ZW50LCBvcHRpb25zKSB7XHJcblxyXG5cdFx0aWYgKGNvbnRlbnQgaW5zdGFuY2VvZiBMLlBvcHVwKSB7XHJcblx0XHRcdEwuc2V0T3B0aW9ucyhjb250ZW50LCBvcHRpb25zKTtcclxuXHRcdFx0dGhpcy5fcG9wdXAgPSBjb250ZW50O1xyXG5cdFx0XHRjb250ZW50Ll9zb3VyY2UgPSB0aGlzO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0aWYgKCF0aGlzLl9wb3B1cCB8fCBvcHRpb25zKSB7XHJcblx0XHRcdFx0dGhpcy5fcG9wdXAgPSBuZXcgTC5Qb3B1cChvcHRpb25zLCB0aGlzKTtcclxuXHRcdFx0fVxyXG5cdFx0XHR0aGlzLl9wb3B1cC5zZXRDb250ZW50KGNvbnRlbnQpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICghdGhpcy5fcG9wdXBIYW5kbGVyc0FkZGVkKSB7XHJcblx0XHRcdHRoaXMub24oe1xyXG5cdFx0XHRcdGNsaWNrOiB0aGlzLl9vcGVuUG9wdXAsXHJcblx0XHRcdFx0cmVtb3ZlOiB0aGlzLmNsb3NlUG9wdXAsXHJcblx0XHRcdFx0bW92ZTogdGhpcy5fbW92ZVBvcHVwXHJcblx0XHRcdH0pO1xyXG5cdFx0XHR0aGlzLl9wb3B1cEhhbmRsZXJzQWRkZWQgPSB0cnVlO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgdW5iaW5kUG9wdXAoKTogdGhpc1xyXG5cdC8vIFJlbW92ZXMgdGhlIHBvcHVwIHByZXZpb3VzbHkgYm91bmQgd2l0aCBgYmluZFBvcHVwYC5cclxuXHR1bmJpbmRQb3B1cDogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKHRoaXMuX3BvcHVwKSB7XHJcblx0XHRcdHRoaXMub2ZmKHtcclxuXHRcdFx0XHRjbGljazogdGhpcy5fb3BlblBvcHVwLFxyXG5cdFx0XHRcdHJlbW92ZTogdGhpcy5jbG9zZVBvcHVwLFxyXG5cdFx0XHRcdG1vdmU6IHRoaXMuX21vdmVQb3B1cFxyXG5cdFx0XHR9KTtcclxuXHRcdFx0dGhpcy5fcG9wdXBIYW5kbGVyc0FkZGVkID0gZmFsc2U7XHJcblx0XHRcdHRoaXMuX3BvcHVwID0gbnVsbDtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgb3BlblBvcHVwKGxhdGxuZz86IExhdExuZyk6IHRoaXNcclxuXHQvLyBPcGVucyB0aGUgYm91bmQgcG9wdXAgYXQgdGhlIHNwZWNpZmljZWQgYGxhdGxuZ2Agb3IgYXQgdGhlIGRlZmF1bHQgcG9wdXAgYW5jaG9yIGlmIG5vIGBsYXRsbmdgIGlzIHBhc3NlZC5cclxuXHRvcGVuUG9wdXA6IGZ1bmN0aW9uIChsYXllciwgbGF0bG5nKSB7XHJcblx0XHRpZiAoIShsYXllciBpbnN0YW5jZW9mIEwuTGF5ZXIpKSB7XHJcblx0XHRcdGxhdGxuZyA9IGxheWVyO1xyXG5cdFx0XHRsYXllciA9IHRoaXM7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKGxheWVyIGluc3RhbmNlb2YgTC5GZWF0dXJlR3JvdXApIHtcclxuXHRcdFx0Zm9yICh2YXIgaWQgaW4gdGhpcy5fbGF5ZXJzKSB7XHJcblx0XHRcdFx0bGF5ZXIgPSB0aGlzLl9sYXllcnNbaWRdO1xyXG5cdFx0XHRcdGJyZWFrO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCFsYXRsbmcpIHtcclxuXHRcdFx0bGF0bG5nID0gbGF5ZXIuZ2V0Q2VudGVyID8gbGF5ZXIuZ2V0Q2VudGVyKCkgOiBsYXllci5nZXRMYXRMbmcoKTtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAodGhpcy5fcG9wdXAgJiYgdGhpcy5fbWFwKSB7XHJcblx0XHRcdC8vIHNldCBwb3B1cCBzb3VyY2UgdG8gdGhpcyBsYXllclxyXG5cdFx0XHR0aGlzLl9wb3B1cC5fc291cmNlID0gbGF5ZXI7XHJcblxyXG5cdFx0XHQvLyB1cGRhdGUgdGhlIHBvcHVwIChjb250ZW50LCBsYXlvdXQsIGVjdC4uLilcclxuXHRcdFx0dGhpcy5fcG9wdXAudXBkYXRlKCk7XHJcblxyXG5cdFx0XHQvLyBvcGVuIHRoZSBwb3B1cCBvbiB0aGUgbWFwXHJcblx0XHRcdHRoaXMuX21hcC5vcGVuUG9wdXAodGhpcy5fcG9wdXAsIGxhdGxuZyk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjbG9zZVBvcHVwKCk6IHRoaXNcclxuXHQvLyBDbG9zZXMgdGhlIHBvcHVwIGJvdW5kIHRvIHRoaXMgbGF5ZXIgaWYgaXQgaXMgb3Blbi5cclxuXHRjbG9zZVBvcHVwOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAodGhpcy5fcG9wdXApIHtcclxuXHRcdFx0dGhpcy5fcG9wdXAuX2Nsb3NlKCk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHRvZ2dsZVBvcHVwKCk6IHRoaXNcclxuXHQvLyBPcGVucyBvciBjbG9zZXMgdGhlIHBvcHVwIGJvdW5kIHRvIHRoaXMgbGF5ZXIgZGVwZW5kaW5nIG9uIGl0cyBjdXJyZW50IHN0YXRlLlxyXG5cdHRvZ2dsZVBvcHVwOiBmdW5jdGlvbiAodGFyZ2V0KSB7XHJcblx0XHRpZiAodGhpcy5fcG9wdXApIHtcclxuXHRcdFx0aWYgKHRoaXMuX3BvcHVwLl9tYXApIHtcclxuXHRcdFx0XHR0aGlzLmNsb3NlUG9wdXAoKTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHR0aGlzLm9wZW5Qb3B1cCh0YXJnZXQpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGlzUG9wdXBPcGVuKCk6IGJvb2xlYW5cclxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgcG9wdXAgYm91bmQgdG8gdGhpcyBsYXllciBpcyBjdXJyZW50bHkgb3Blbi5cclxuXHRpc1BvcHVwT3BlbjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX3BvcHVwLmlzT3BlbigpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0UG9wdXBDb250ZW50KGNvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudHxQb3B1cCk6IHRoaXNcclxuXHQvLyBTZXRzIHRoZSBjb250ZW50IG9mIHRoZSBwb3B1cCBib3VuZCB0byB0aGlzIGxheWVyLlxyXG5cdHNldFBvcHVwQ29udGVudDogZnVuY3Rpb24gKGNvbnRlbnQpIHtcclxuXHRcdGlmICh0aGlzLl9wb3B1cCkge1xyXG5cdFx0XHR0aGlzLl9wb3B1cC5zZXRDb250ZW50KGNvbnRlbnQpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRQb3B1cCgpOiBQb3B1cFxyXG5cdC8vIFJldHVybnMgdGhlIHBvcHVwIGJvdW5kIHRvIHRoaXMgbGF5ZXIuXHJcblx0Z2V0UG9wdXA6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHJldHVybiB0aGlzLl9wb3B1cDtcclxuXHR9LFxyXG5cclxuXHRfb3BlblBvcHVwOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0dmFyIGxheWVyID0gZS5sYXllciB8fCBlLnRhcmdldDtcclxuXHJcblx0XHRpZiAoIXRoaXMuX3BvcHVwKSB7XHJcblx0XHRcdHJldHVybjtcclxuXHRcdH1cclxuXHJcblx0XHRpZiAoIXRoaXMuX21hcCkge1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gcHJldmVudCBtYXAgY2xpY2tcclxuXHRcdEwuRG9tRXZlbnQuc3RvcChlKTtcclxuXHJcblx0XHQvLyBpZiB0aGlzIGluaGVyaXRzIGZyb20gUGF0aCBpdHMgYSB2ZWN0b3IgYW5kIHdlIGNhbiBqdXN0XHJcblx0XHQvLyBvcGVuIHRoZSBwb3B1cCBhdCB0aGUgbmV3IGxvY2F0aW9uXHJcblx0XHRpZiAobGF5ZXIgaW5zdGFuY2VvZiBMLlBhdGgpIHtcclxuXHRcdFx0dGhpcy5vcGVuUG9wdXAoZS5sYXllciB8fCBlLnRhcmdldCwgZS5sYXRsbmcpO1xyXG5cdFx0XHRyZXR1cm47XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gb3RoZXJ3aXNlIHRyZWF0IGl0IGxpa2UgYSBtYXJrZXIgYW5kIGZpZ3VyZSBvdXRcclxuXHRcdC8vIGlmIHdlIHNob3VsZCB0b2dnbGUgaXQgb3Blbi9jbG9zZWRcclxuXHRcdGlmICh0aGlzLl9tYXAuaGFzTGF5ZXIodGhpcy5fcG9wdXApICYmIHRoaXMuX3BvcHVwLl9zb3VyY2UgPT09IGxheWVyKSB7XHJcblx0XHRcdHRoaXMuY2xvc2VQb3B1cCgpO1xyXG5cdFx0fSBlbHNlIHtcclxuXHRcdFx0dGhpcy5vcGVuUG9wdXAobGF5ZXIsIGUubGF0bG5nKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfbW92ZVBvcHVwOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0dGhpcy5fcG9wdXAuc2V0TGF0TG5nKGUubGF0bG5nKTtcclxuXHR9XHJcbn0pO1xyXG5cblxuXG4vKlxuICogQGNsYXNzIFRvb2x0aXBcbiAqIEBpbmhlcml0cyBEaXZPdmVybGF5XG4gKiBAYWthIEwuVG9vbHRpcFxuICogVXNlZCB0byBkaXNwbGF5IHNtYWxsIHRleHRzIG9uIHRvcCBvZiBtYXAgbGF5ZXJzLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogYGBganNcbiAqIG1hcmtlci5iaW5kVG9vbHRpcChcIm15IHRvb2x0aXAgdGV4dFwiKS5vcGVuVG9vbHRpcCgpO1xuICogYGBgXG4gKiBOb3RlIGFib3V0IHRvb2x0aXAgb2Zmc2V0LiBMZWFmbGV0IHRha2VzIHR3byBvcHRpb25zIGluIGNvbnNpZGVyYXRpb25cbiAqIGZvciBjb21wdXRpbmcgdG9vbHRpcCBvZmZzZXRpbmc6XG4gKiAtIHRoZSBgb2Zmc2V0YCBUb29sdGlwIG9wdGlvbjogaXQgZGVmYXVsdHMgdG8gWzAsIDBdLCBhbmQgaXQncyBzcGVjaWZpYyB0byBvbmUgdG9vbHRpcC5cbiAqICAgQWRkIGEgcG9zaXRpdmUgeCBvZmZzZXQgdG8gbW92ZSB0aGUgdG9vbHRpcCB0byB0aGUgcmlnaHQsIGFuZCBhIHBvc2l0aXZlIHkgb2Zmc2V0IHRvXG4gKiAgIG1vdmUgaXQgdG8gdGhlIGJvdHRvbS4gTmVnYXRpdmVzIHdpbGwgbW92ZSB0byB0aGUgbGVmdCBhbmQgdG9wLlxuICogLSB0aGUgYHRvb2x0aXBBbmNob3JgIEljb24gb3B0aW9uOiB0aGlzIHdpbGwgb25seSBiZSBjb25zaWRlcmVkIGZvciBNYXJrZXIuIFlvdVxuICogICBzaG91bGQgYWRhcHQgdGhpcyB2YWx1ZSBpZiB5b3UgdXNlIGEgY3VzdG9tIGljb24uXG4gKi9cblxuXG4vLyBAbmFtZXNwYWNlIFRvb2x0aXBcbkwuVG9vbHRpcCA9IEwuRGl2T3ZlcmxheS5leHRlbmQoe1xuXG5cdC8vIEBzZWN0aW9uXG5cdC8vIEBha2EgVG9vbHRpcCBvcHRpb25zXG5cdG9wdGlvbnM6IHtcblx0XHQvLyBAb3B0aW9uIHBhbmU6IFN0cmluZyA9ICd0b29sdGlwUGFuZSdcblx0XHQvLyBgTWFwIHBhbmVgIHdoZXJlIHRoZSB0b29sdGlwIHdpbGwgYmUgYWRkZWQuXG5cdFx0cGFuZTogJ3Rvb2x0aXBQYW5lJyxcblxuXHRcdC8vIEBvcHRpb24gb2Zmc2V0OiBQb2ludCA9IFBvaW50KDAsIDApXG5cdFx0Ly8gT3B0aW9uYWwgb2Zmc2V0IG9mIHRoZSB0b29sdGlwIHBvc2l0aW9uLlxuXHRcdG9mZnNldDogWzAsIDBdLFxuXG5cdFx0Ly8gQG9wdGlvbiBkaXJlY3Rpb246IFN0cmluZyA9ICdhdXRvJ1xuXHRcdC8vIERpcmVjdGlvbiB3aGVyZSB0byBvcGVuIHRoZSB0b29sdGlwLiBQb3NzaWJsZSB2YWx1ZXMgYXJlOiBgcmlnaHRgLCBgbGVmdGAsXG5cdFx0Ly8gYHRvcGAsIGBib3R0b21gLCBgY2VudGVyYCwgYGF1dG9gLlxuXHRcdC8vIGBhdXRvYCB3aWxsIGR5bmFtaWNhbHkgc3dpdGNoIGJldHdlZW4gYHJpZ2h0YCBhbmQgYGxlZnRgIGFjY29yZGluZyB0byB0aGUgdG9vbHRpcFxuXHRcdC8vIHBvc2l0aW9uIG9uIHRoZSBtYXAuXG5cdFx0ZGlyZWN0aW9uOiAnYXV0bycsXG5cblx0XHQvLyBAb3B0aW9uIHBlcm1hbmVudDogQm9vbGVhbiA9IGZhbHNlXG5cdFx0Ly8gV2hldGhlciB0byBvcGVuIHRoZSB0b29sdGlwIHBlcm1hbmVudGx5IG9yIG9ubHkgb24gbW91c2VvdmVyLlxuXHRcdHBlcm1hbmVudDogZmFsc2UsXG5cblx0XHQvLyBAb3B0aW9uIHN0aWNreTogQm9vbGVhbiA9IGZhbHNlXG5cdFx0Ly8gSWYgdHJ1ZSwgdGhlIHRvb2x0aXAgd2lsbCBmb2xsb3cgdGhlIG1vdXNlIGluc3RlYWQgb2YgYmVpbmcgZml4ZWQgYXQgdGhlIGZlYXR1cmUgY2VudGVyLlxuXHRcdHN0aWNreTogZmFsc2UsXG5cblx0XHQvLyBAb3B0aW9uIGludGVyYWN0aXZlOiBCb29sZWFuID0gZmFsc2Vcblx0XHQvLyBJZiB0cnVlLCB0aGUgdG9vbHRpcCB3aWxsIGxpc3RlbiB0byB0aGUgZmVhdHVyZSBldmVudHMuXG5cdFx0aW50ZXJhY3RpdmU6IGZhbHNlLFxuXG5cdFx0Ly8gQG9wdGlvbiBvcGFjaXR5OiBOdW1iZXIgPSAwLjlcblx0XHQvLyBUb29sdGlwIGNvbnRhaW5lciBvcGFjaXR5LlxuXHRcdG9wYWNpdHk6IDAuOVxuXHR9LFxuXG5cdG9uQWRkOiBmdW5jdGlvbiAobWFwKSB7XG5cdFx0TC5EaXZPdmVybGF5LnByb3RvdHlwZS5vbkFkZC5jYWxsKHRoaXMsIG1hcCk7XG5cdFx0dGhpcy5zZXRPcGFjaXR5KHRoaXMub3B0aW9ucy5vcGFjaXR5KTtcblxuXHRcdC8vIEBuYW1lc3BhY2UgTWFwXG5cdFx0Ly8gQHNlY3Rpb24gVG9vbHRpcCBldmVudHNcblx0XHQvLyBAZXZlbnQgdG9vbHRpcG9wZW46IFRvb2x0aXBFdmVudFxuXHRcdC8vIEZpcmVkIHdoZW4gYSB0b29sdGlwIGlzIG9wZW5lZCBpbiB0aGUgbWFwLlxuXHRcdG1hcC5maXJlKCd0b29sdGlwb3BlbicsIHt0b29sdGlwOiB0aGlzfSk7XG5cblx0XHRpZiAodGhpcy5fc291cmNlKSB7XG5cdFx0XHQvLyBAbmFtZXNwYWNlIExheWVyXG5cdFx0XHQvLyBAc2VjdGlvbiBUb29sdGlwIGV2ZW50c1xuXHRcdFx0Ly8gQGV2ZW50IHRvb2x0aXBvcGVuOiBUb29sdGlwRXZlbnRcblx0XHRcdC8vIEZpcmVkIHdoZW4gYSB0b29sdGlwIGJvdW5kIHRvIHRoaXMgbGF5ZXIgaXMgb3BlbmVkLlxuXHRcdFx0dGhpcy5fc291cmNlLmZpcmUoJ3Rvb2x0aXBvcGVuJywge3Rvb2x0aXA6IHRoaXN9LCB0cnVlKTtcblx0XHR9XG5cdH0sXG5cblx0b25SZW1vdmU6IGZ1bmN0aW9uIChtYXApIHtcblx0XHRMLkRpdk92ZXJsYXkucHJvdG90eXBlLm9uUmVtb3ZlLmNhbGwodGhpcywgbWFwKTtcblxuXHRcdC8vIEBuYW1lc3BhY2UgTWFwXG5cdFx0Ly8gQHNlY3Rpb24gVG9vbHRpcCBldmVudHNcblx0XHQvLyBAZXZlbnQgdG9vbHRpcGNsb3NlOiBUb29sdGlwRXZlbnRcblx0XHQvLyBGaXJlZCB3aGVuIGEgdG9vbHRpcCBpbiB0aGUgbWFwIGlzIGNsb3NlZC5cblx0XHRtYXAuZmlyZSgndG9vbHRpcGNsb3NlJywge3Rvb2x0aXA6IHRoaXN9KTtcblxuXHRcdGlmICh0aGlzLl9zb3VyY2UpIHtcblx0XHRcdC8vIEBuYW1lc3BhY2UgTGF5ZXJcblx0XHRcdC8vIEBzZWN0aW9uIFRvb2x0aXAgZXZlbnRzXG5cdFx0XHQvLyBAZXZlbnQgdG9vbHRpcGNsb3NlOiBUb29sdGlwRXZlbnRcblx0XHRcdC8vIEZpcmVkIHdoZW4gYSB0b29sdGlwIGJvdW5kIHRvIHRoaXMgbGF5ZXIgaXMgY2xvc2VkLlxuXHRcdFx0dGhpcy5fc291cmNlLmZpcmUoJ3Rvb2x0aXBjbG9zZScsIHt0b29sdGlwOiB0aGlzfSwgdHJ1ZSk7XG5cdFx0fVxuXHR9LFxuXG5cdGdldEV2ZW50czogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBldmVudHMgPSBMLkRpdk92ZXJsYXkucHJvdG90eXBlLmdldEV2ZW50cy5jYWxsKHRoaXMpO1xuXG5cdFx0aWYgKEwuQnJvd3Nlci50b3VjaCAmJiAhdGhpcy5vcHRpb25zLnBlcm1hbmVudCkge1xuXHRcdFx0ZXZlbnRzLnByZWNsaWNrID0gdGhpcy5fY2xvc2U7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIGV2ZW50cztcblx0fSxcblxuXHRfY2xvc2U6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fbWFwKSB7XG5cdFx0XHR0aGlzLl9tYXAuY2xvc2VUb29sdGlwKHRoaXMpO1xuXHRcdH1cblx0fSxcblxuXHRfaW5pdExheW91dDogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBwcmVmaXggPSAnbGVhZmxldC10b29sdGlwJyxcblx0XHQgICAgY2xhc3NOYW1lID0gcHJlZml4ICsgJyAnICsgKHRoaXMub3B0aW9ucy5jbGFzc05hbWUgfHwgJycpICsgJyBsZWFmbGV0LXpvb20tJyArICh0aGlzLl96b29tQW5pbWF0ZWQgPyAnYW5pbWF0ZWQnIDogJ2hpZGUnKTtcblxuXHRcdHRoaXMuX2NvbnRlbnROb2RlID0gdGhpcy5fY29udGFpbmVyID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2JywgY2xhc3NOYW1lKTtcblx0fSxcblxuXHRfdXBkYXRlTGF5b3V0OiBmdW5jdGlvbiAoKSB7fSxcblxuXHRfYWRqdXN0UGFuOiBmdW5jdGlvbiAoKSB7fSxcblxuXHRfc2V0UG9zaXRpb246IGZ1bmN0aW9uIChwb3MpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBjb250YWluZXIgPSB0aGlzLl9jb250YWluZXIsXG5cdFx0ICAgIGNlbnRlclBvaW50ID0gbWFwLmxhdExuZ1RvQ29udGFpbmVyUG9pbnQobWFwLmdldENlbnRlcigpKSxcblx0XHQgICAgdG9vbHRpcFBvaW50ID0gbWFwLmxheWVyUG9pbnRUb0NvbnRhaW5lclBvaW50KHBvcyksXG5cdFx0ICAgIGRpcmVjdGlvbiA9IHRoaXMub3B0aW9ucy5kaXJlY3Rpb24sXG5cdFx0ICAgIHRvb2x0aXBXaWR0aCA9IGNvbnRhaW5lci5vZmZzZXRXaWR0aCxcblx0XHQgICAgdG9vbHRpcEhlaWdodCA9IGNvbnRhaW5lci5vZmZzZXRIZWlnaHQsXG5cdFx0ICAgIG9mZnNldCA9IEwucG9pbnQodGhpcy5vcHRpb25zLm9mZnNldCksXG5cdFx0ICAgIGFuY2hvciA9IHRoaXMuX2dldEFuY2hvcigpO1xuXG5cdFx0aWYgKGRpcmVjdGlvbiA9PT0gJ3RvcCcpIHtcblx0XHRcdHBvcyA9IHBvcy5hZGQoTC5wb2ludCgtdG9vbHRpcFdpZHRoIC8gMiArIG9mZnNldC54LCAtdG9vbHRpcEhlaWdodCArIG9mZnNldC55ICsgYW5jaG9yLnksIHRydWUpKTtcblx0XHR9IGVsc2UgaWYgKGRpcmVjdGlvbiA9PT0gJ2JvdHRvbScpIHtcblx0XHRcdHBvcyA9IHBvcy5zdWJ0cmFjdChMLnBvaW50KHRvb2x0aXBXaWR0aCAvIDIgLSBvZmZzZXQueCwgLW9mZnNldC55LCB0cnVlKSk7XG5cdFx0fSBlbHNlIGlmIChkaXJlY3Rpb24gPT09ICdjZW50ZXInKSB7XG5cdFx0XHRwb3MgPSBwb3Muc3VidHJhY3QoTC5wb2ludCh0b29sdGlwV2lkdGggLyAyICsgb2Zmc2V0LngsIHRvb2x0aXBIZWlnaHQgLyAyIC0gYW5jaG9yLnkgKyBvZmZzZXQueSwgdHJ1ZSkpO1xuXHRcdH0gZWxzZSBpZiAoZGlyZWN0aW9uID09PSAncmlnaHQnIHx8IGRpcmVjdGlvbiA9PT0gJ2F1dG8nICYmIHRvb2x0aXBQb2ludC54IDwgY2VudGVyUG9pbnQueCkge1xuXHRcdFx0ZGlyZWN0aW9uID0gJ3JpZ2h0Jztcblx0XHRcdHBvcyA9IHBvcy5hZGQoTC5wb2ludChvZmZzZXQueCArIGFuY2hvci54LCBhbmNob3IueSAtIHRvb2x0aXBIZWlnaHQgLyAyICsgb2Zmc2V0LnksIHRydWUpKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0ZGlyZWN0aW9uID0gJ2xlZnQnO1xuXHRcdFx0cG9zID0gcG9zLnN1YnRyYWN0KEwucG9pbnQodG9vbHRpcFdpZHRoICsgYW5jaG9yLnggLSBvZmZzZXQueCwgdG9vbHRpcEhlaWdodCAvIDIgLSBhbmNob3IueSAtIG9mZnNldC55LCB0cnVlKSk7XG5cdFx0fVxuXG5cdFx0TC5Eb21VdGlsLnJlbW92ZUNsYXNzKGNvbnRhaW5lciwgJ2xlYWZsZXQtdG9vbHRpcC1yaWdodCcpO1xuXHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyhjb250YWluZXIsICdsZWFmbGV0LXRvb2x0aXAtbGVmdCcpO1xuXHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyhjb250YWluZXIsICdsZWFmbGV0LXRvb2x0aXAtdG9wJyk7XG5cdFx0TC5Eb21VdGlsLnJlbW92ZUNsYXNzKGNvbnRhaW5lciwgJ2xlYWZsZXQtdG9vbHRpcC1ib3R0b20nKTtcblx0XHRMLkRvbVV0aWwuYWRkQ2xhc3MoY29udGFpbmVyLCAnbGVhZmxldC10b29sdGlwLScgKyBkaXJlY3Rpb24pO1xuXHRcdEwuRG9tVXRpbC5zZXRQb3NpdGlvbihjb250YWluZXIsIHBvcyk7XG5cdH0sXG5cblx0X3VwZGF0ZVBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHBvcyA9IHRoaXMuX21hcC5sYXRMbmdUb0xheWVyUG9pbnQodGhpcy5fbGF0bG5nKTtcblx0XHR0aGlzLl9zZXRQb3NpdGlvbihwb3MpO1xuXHR9LFxuXG5cdHNldE9wYWNpdHk6IGZ1bmN0aW9uIChvcGFjaXR5KSB7XG5cdFx0dGhpcy5vcHRpb25zLm9wYWNpdHkgPSBvcGFjaXR5O1xuXG5cdFx0aWYgKHRoaXMuX2NvbnRhaW5lcikge1xuXHRcdFx0TC5Eb21VdGlsLnNldE9wYWNpdHkodGhpcy5fY29udGFpbmVyLCBvcGFjaXR5KTtcblx0XHR9XG5cdH0sXG5cblx0X2FuaW1hdGVab29tOiBmdW5jdGlvbiAoZSkge1xuXHRcdHZhciBwb3MgPSB0aGlzLl9tYXAuX2xhdExuZ1RvTmV3TGF5ZXJQb2ludCh0aGlzLl9sYXRsbmcsIGUuem9vbSwgZS5jZW50ZXIpO1xuXHRcdHRoaXMuX3NldFBvc2l0aW9uKHBvcyk7XG5cdH0sXG5cblx0X2dldEFuY2hvcjogZnVuY3Rpb24gKCkge1xuXHRcdC8vIFdoZXJlIHNob3VsZCB3ZSBhbmNob3IgdGhlIHRvb2x0aXAgb24gdGhlIHNvdXJjZSBsYXllcj9cblx0XHRyZXR1cm4gTC5wb2ludCh0aGlzLl9zb3VyY2UgJiYgdGhpcy5fc291cmNlLl9nZXRUb29sdGlwQW5jaG9yICYmICF0aGlzLm9wdGlvbnMuc3RpY2t5ID8gdGhpcy5fc291cmNlLl9nZXRUb29sdGlwQW5jaG9yKCkgOiBbMCwgMF0pO1xuXHR9XG5cbn0pO1xuXG4vLyBAbmFtZXNwYWNlIFRvb2x0aXBcbi8vIEBmYWN0b3J5IEwudG9vbHRpcChvcHRpb25zPzogVG9vbHRpcCBvcHRpb25zLCBzb3VyY2U/OiBMYXllcilcbi8vIEluc3RhbnRpYXRlcyBhIFRvb2x0aXAgb2JqZWN0IGdpdmVuIGFuIG9wdGlvbmFsIGBvcHRpb25zYCBvYmplY3QgdGhhdCBkZXNjcmliZXMgaXRzIGFwcGVhcmFuY2UgYW5kIGxvY2F0aW9uIGFuZCBhbiBvcHRpb25hbCBgc291cmNlYCBvYmplY3QgdGhhdCBpcyB1c2VkIHRvIHRhZyB0aGUgdG9vbHRpcCB3aXRoIGEgcmVmZXJlbmNlIHRvIHRoZSBMYXllciB0byB3aGljaCBpdCByZWZlcnMuXG5MLnRvb2x0aXAgPSBmdW5jdGlvbiAob3B0aW9ucywgc291cmNlKSB7XG5cdHJldHVybiBuZXcgTC5Ub29sdGlwKG9wdGlvbnMsIHNvdXJjZSk7XG59O1xuXG4vLyBAbmFtZXNwYWNlIE1hcFxuLy8gQHNlY3Rpb24gTWV0aG9kcyBmb3IgTGF5ZXJzIGFuZCBDb250cm9sc1xuTC5NYXAuaW5jbHVkZSh7XG5cblx0Ly8gQG1ldGhvZCBvcGVuVG9vbHRpcCh0b29sdGlwOiBUb29sdGlwKTogdGhpc1xuXHQvLyBPcGVucyB0aGUgc3BlY2lmaWVkIHRvb2x0aXAuXG5cdC8vIEBhbHRlcm5hdGl2ZVxuXHQvLyBAbWV0aG9kIG9wZW5Ub29sdGlwKGNvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudCwgbGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/OiBUb29sdGlwIG9wdGlvbnMpOiB0aGlzXG5cdC8vIENyZWF0ZXMgYSB0b29sdGlwIHdpdGggdGhlIHNwZWNpZmllZCBjb250ZW50IGFuZCBvcHRpb25zIGFuZCBvcGVuIGl0LlxuXHRvcGVuVG9vbHRpcDogZnVuY3Rpb24gKHRvb2x0aXAsIGxhdGxuZywgb3B0aW9ucykge1xuXHRcdGlmICghKHRvb2x0aXAgaW5zdGFuY2VvZiBMLlRvb2x0aXApKSB7XG5cdFx0XHR0b29sdGlwID0gbmV3IEwuVG9vbHRpcChvcHRpb25zKS5zZXRDb250ZW50KHRvb2x0aXApO1xuXHRcdH1cblxuXHRcdGlmIChsYXRsbmcpIHtcblx0XHRcdHRvb2x0aXAuc2V0TGF0TG5nKGxhdGxuZyk7XG5cdFx0fVxuXG5cdFx0aWYgKHRoaXMuaGFzTGF5ZXIodG9vbHRpcCkpIHtcblx0XHRcdHJldHVybiB0aGlzO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmFkZExheWVyKHRvb2x0aXApO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgY2xvc2VUb29sdGlwKHRvb2x0aXA/OiBUb29sdGlwKTogdGhpc1xuXHQvLyBDbG9zZXMgdGhlIHRvb2x0aXAgZ2l2ZW4gYXMgcGFyYW1ldGVyLlxuXHRjbG9zZVRvb2x0aXA6IGZ1bmN0aW9uICh0b29sdGlwKSB7XG5cdFx0aWYgKHRvb2x0aXApIHtcblx0XHRcdHRoaXMucmVtb3ZlTGF5ZXIodG9vbHRpcCk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cbn0pO1xuXG4vKlxuICogQG5hbWVzcGFjZSBMYXllclxuICogQHNlY3Rpb24gVG9vbHRpcCBtZXRob2RzIGV4YW1wbGVcbiAqXG4gKiBBbGwgbGF5ZXJzIHNoYXJlIGEgc2V0IG9mIG1ldGhvZHMgY29udmVuaWVudCBmb3IgYmluZGluZyB0b29sdGlwcyB0byBpdC5cbiAqXG4gKiBgYGBqc1xuICogdmFyIGxheWVyID0gTC5Qb2x5Z29uKGxhdGxuZ3MpLmJpbmRUb29sdGlwKCdIaSBUaGVyZSEnKS5hZGRUbyhtYXApO1xuICogbGF5ZXIub3BlblRvb2x0aXAoKTtcbiAqIGxheWVyLmNsb3NlVG9vbHRpcCgpO1xuICogYGBgXG4gKi9cblxuLy8gQHNlY3Rpb24gVG9vbHRpcCBtZXRob2RzXG5MLkxheWVyLmluY2x1ZGUoe1xuXG5cdC8vIEBtZXRob2QgYmluZFRvb2x0aXAoY29udGVudDogU3RyaW5nfEhUTUxFbGVtZW50fEZ1bmN0aW9ufFRvb2x0aXAsIG9wdGlvbnM/OiBUb29sdGlwIG9wdGlvbnMpOiB0aGlzXG5cdC8vIEJpbmRzIGEgdG9vbHRpcCB0byB0aGUgbGF5ZXIgd2l0aCB0aGUgcGFzc2VkIGBjb250ZW50YCBhbmQgc2V0cyB1cCB0aGVcblx0Ly8gbmVjY2Vzc2FyeSBldmVudCBsaXN0ZW5lcnMuIElmIGEgYEZ1bmN0aW9uYCBpcyBwYXNzZWQgaXQgd2lsbCByZWNlaXZlXG5cdC8vIHRoZSBsYXllciBhcyB0aGUgZmlyc3QgYXJndW1lbnQgYW5kIHNob3VsZCByZXR1cm4gYSBgU3RyaW5nYCBvciBgSFRNTEVsZW1lbnRgLlxuXHRiaW5kVG9vbHRpcDogZnVuY3Rpb24gKGNvbnRlbnQsIG9wdGlvbnMpIHtcblxuXHRcdGlmIChjb250ZW50IGluc3RhbmNlb2YgTC5Ub29sdGlwKSB7XG5cdFx0XHRMLnNldE9wdGlvbnMoY29udGVudCwgb3B0aW9ucyk7XG5cdFx0XHR0aGlzLl90b29sdGlwID0gY29udGVudDtcblx0XHRcdGNvbnRlbnQuX3NvdXJjZSA9IHRoaXM7XG5cdFx0fSBlbHNlIHtcblx0XHRcdGlmICghdGhpcy5fdG9vbHRpcCB8fCBvcHRpb25zKSB7XG5cdFx0XHRcdHRoaXMuX3Rvb2x0aXAgPSBMLnRvb2x0aXAob3B0aW9ucywgdGhpcyk7XG5cdFx0XHR9XG5cdFx0XHR0aGlzLl90b29sdGlwLnNldENvbnRlbnQoY29udGVudCk7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9pbml0VG9vbHRpcEludGVyYWN0aW9ucygpO1xuXG5cdFx0aWYgKHRoaXMuX3Rvb2x0aXAub3B0aW9ucy5wZXJtYW5lbnQgJiYgdGhpcy5fbWFwICYmIHRoaXMuX21hcC5oYXNMYXllcih0aGlzKSkge1xuXHRcdFx0dGhpcy5vcGVuVG9vbHRpcCgpO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgdW5iaW5kVG9vbHRpcCgpOiB0aGlzXG5cdC8vIFJlbW92ZXMgdGhlIHRvb2x0aXAgcHJldmlvdXNseSBib3VuZCB3aXRoIGBiaW5kVG9vbHRpcGAuXG5cdHVuYmluZFRvb2x0aXA6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fdG9vbHRpcCkge1xuXHRcdFx0dGhpcy5faW5pdFRvb2x0aXBJbnRlcmFjdGlvbnModHJ1ZSk7XG5cdFx0XHR0aGlzLmNsb3NlVG9vbHRpcCgpO1xuXHRcdFx0dGhpcy5fdG9vbHRpcCA9IG51bGw7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdF9pbml0VG9vbHRpcEludGVyYWN0aW9uczogZnVuY3Rpb24gKHJlbW92ZSkge1xuXHRcdGlmICghcmVtb3ZlICYmIHRoaXMuX3Rvb2x0aXBIYW5kbGVyc0FkZGVkKSB7IHJldHVybjsgfVxuXHRcdHZhciBvbk9mZiA9IHJlbW92ZSA/ICdvZmYnIDogJ29uJyxcblx0XHQgICAgZXZlbnRzID0ge1xuXHRcdFx0cmVtb3ZlOiB0aGlzLmNsb3NlVG9vbHRpcCxcblx0XHRcdG1vdmU6IHRoaXMuX21vdmVUb29sdGlwXG5cdFx0ICAgIH07XG5cdFx0aWYgKCF0aGlzLl90b29sdGlwLm9wdGlvbnMucGVybWFuZW50KSB7XG5cdFx0XHRldmVudHMubW91c2VvdmVyID0gdGhpcy5fb3BlblRvb2x0aXA7XG5cdFx0XHRldmVudHMubW91c2VvdXQgPSB0aGlzLmNsb3NlVG9vbHRpcDtcblx0XHRcdGlmICh0aGlzLl90b29sdGlwLm9wdGlvbnMuc3RpY2t5KSB7XG5cdFx0XHRcdGV2ZW50cy5tb3VzZW1vdmUgPSB0aGlzLl9tb3ZlVG9vbHRpcDtcblx0XHRcdH1cblx0XHRcdGlmIChMLkJyb3dzZXIudG91Y2gpIHtcblx0XHRcdFx0ZXZlbnRzLmNsaWNrID0gdGhpcy5fb3BlblRvb2x0aXA7XG5cdFx0XHR9XG5cdFx0fSBlbHNlIHtcblx0XHRcdGV2ZW50cy5hZGQgPSB0aGlzLl9vcGVuVG9vbHRpcDtcblx0XHR9XG5cdFx0dGhpc1tvbk9mZl0oZXZlbnRzKTtcblx0XHR0aGlzLl90b29sdGlwSGFuZGxlcnNBZGRlZCA9ICFyZW1vdmU7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBvcGVuVG9vbHRpcChsYXRsbmc/OiBMYXRMbmcpOiB0aGlzXG5cdC8vIE9wZW5zIHRoZSBib3VuZCB0b29sdGlwIGF0IHRoZSBzcGVjaWZpY2VkIGBsYXRsbmdgIG9yIGF0IHRoZSBkZWZhdWx0IHRvb2x0aXAgYW5jaG9yIGlmIG5vIGBsYXRsbmdgIGlzIHBhc3NlZC5cblx0b3BlblRvb2x0aXA6IGZ1bmN0aW9uIChsYXllciwgbGF0bG5nKSB7XG5cdFx0aWYgKCEobGF5ZXIgaW5zdGFuY2VvZiBMLkxheWVyKSkge1xuXHRcdFx0bGF0bG5nID0gbGF5ZXI7XG5cdFx0XHRsYXllciA9IHRoaXM7XG5cdFx0fVxuXG5cdFx0aWYgKGxheWVyIGluc3RhbmNlb2YgTC5GZWF0dXJlR3JvdXApIHtcblx0XHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2xheWVycykge1xuXHRcdFx0XHRsYXllciA9IHRoaXMuX2xheWVyc1tpZF07XG5cdFx0XHRcdGJyZWFrO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdGlmICghbGF0bG5nKSB7XG5cdFx0XHRsYXRsbmcgPSBsYXllci5nZXRDZW50ZXIgPyBsYXllci5nZXRDZW50ZXIoKSA6IGxheWVyLmdldExhdExuZygpO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLl90b29sdGlwICYmIHRoaXMuX21hcCkge1xuXG5cdFx0XHQvLyBzZXQgdG9vbHRpcCBzb3VyY2UgdG8gdGhpcyBsYXllclxuXHRcdFx0dGhpcy5fdG9vbHRpcC5fc291cmNlID0gbGF5ZXI7XG5cblx0XHRcdC8vIHVwZGF0ZSB0aGUgdG9vbHRpcCAoY29udGVudCwgbGF5b3V0LCBlY3QuLi4pXG5cdFx0XHR0aGlzLl90b29sdGlwLnVwZGF0ZSgpO1xuXG5cdFx0XHQvLyBvcGVuIHRoZSB0b29sdGlwIG9uIHRoZSBtYXBcblx0XHRcdHRoaXMuX21hcC5vcGVuVG9vbHRpcCh0aGlzLl90b29sdGlwLCBsYXRsbmcpO1xuXG5cdFx0XHQvLyBUb29sdGlwIGNvbnRhaW5lciBtYXkgbm90IGJlIGRlZmluZWQgaWYgbm90IHBlcm1hbmVudCBhbmQgbmV2ZXJcblx0XHRcdC8vIG9wZW5lZC5cblx0XHRcdGlmICh0aGlzLl90b29sdGlwLm9wdGlvbnMuaW50ZXJhY3RpdmUgJiYgdGhpcy5fdG9vbHRpcC5fY29udGFpbmVyKSB7XG5cdFx0XHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl90b29sdGlwLl9jb250YWluZXIsICdsZWFmbGV0LWNsaWNrYWJsZScpO1xuXHRcdFx0XHR0aGlzLmFkZEludGVyYWN0aXZlVGFyZ2V0KHRoaXMuX3Rvb2x0aXAuX2NvbnRhaW5lcik7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBjbG9zZVRvb2x0aXAoKTogdGhpc1xuXHQvLyBDbG9zZXMgdGhlIHRvb2x0aXAgYm91bmQgdG8gdGhpcyBsYXllciBpZiBpdCBpcyBvcGVuLlxuXHRjbG9zZVRvb2x0aXA6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fdG9vbHRpcCkge1xuXHRcdFx0dGhpcy5fdG9vbHRpcC5fY2xvc2UoKTtcblx0XHRcdGlmICh0aGlzLl90b29sdGlwLm9wdGlvbnMuaW50ZXJhY3RpdmUgJiYgdGhpcy5fdG9vbHRpcC5fY29udGFpbmVyKSB7XG5cdFx0XHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl90b29sdGlwLl9jb250YWluZXIsICdsZWFmbGV0LWNsaWNrYWJsZScpO1xuXHRcdFx0XHR0aGlzLnJlbW92ZUludGVyYWN0aXZlVGFyZ2V0KHRoaXMuX3Rvb2x0aXAuX2NvbnRhaW5lcik7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgdG9nZ2xlVG9vbHRpcCgpOiB0aGlzXG5cdC8vIE9wZW5zIG9yIGNsb3NlcyB0aGUgdG9vbHRpcCBib3VuZCB0byB0aGlzIGxheWVyIGRlcGVuZGluZyBvbiBpdHMgY3VycmVudCBzdGF0ZS5cblx0dG9nZ2xlVG9vbHRpcDogZnVuY3Rpb24gKHRhcmdldCkge1xuXHRcdGlmICh0aGlzLl90b29sdGlwKSB7XG5cdFx0XHRpZiAodGhpcy5fdG9vbHRpcC5fbWFwKSB7XG5cdFx0XHRcdHRoaXMuY2xvc2VUb29sdGlwKCk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHR0aGlzLm9wZW5Ub29sdGlwKHRhcmdldCk7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgaXNUb29sdGlwT3BlbigpOiBib29sZWFuXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSB0b29sdGlwIGJvdW5kIHRvIHRoaXMgbGF5ZXIgaXMgY3VycmVudGx5IG9wZW4uXG5cdGlzVG9vbHRpcE9wZW46IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fdG9vbHRpcC5pc09wZW4oKTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIHNldFRvb2x0aXBDb250ZW50KGNvbnRlbnQ6IFN0cmluZ3xIVE1MRWxlbWVudHxUb29sdGlwKTogdGhpc1xuXHQvLyBTZXRzIHRoZSBjb250ZW50IG9mIHRoZSB0b29sdGlwIGJvdW5kIHRvIHRoaXMgbGF5ZXIuXG5cdHNldFRvb2x0aXBDb250ZW50OiBmdW5jdGlvbiAoY29udGVudCkge1xuXHRcdGlmICh0aGlzLl90b29sdGlwKSB7XG5cdFx0XHR0aGlzLl90b29sdGlwLnNldENvbnRlbnQoY29udGVudCk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgZ2V0VG9vbHRpcCgpOiBUb29sdGlwXG5cdC8vIFJldHVybnMgdGhlIHRvb2x0aXAgYm91bmQgdG8gdGhpcyBsYXllci5cblx0Z2V0VG9vbHRpcDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLl90b29sdGlwO1xuXHR9LFxuXG5cdF9vcGVuVG9vbHRpcDogZnVuY3Rpb24gKGUpIHtcblx0XHR2YXIgbGF5ZXIgPSBlLmxheWVyIHx8IGUudGFyZ2V0O1xuXG5cdFx0aWYgKCF0aGlzLl90b29sdGlwIHx8ICF0aGlzLl9tYXApIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cdFx0dGhpcy5vcGVuVG9vbHRpcChsYXllciwgdGhpcy5fdG9vbHRpcC5vcHRpb25zLnN0aWNreSA/IGUubGF0bG5nIDogdW5kZWZpbmVkKTtcblx0fSxcblxuXHRfbW92ZVRvb2x0aXA6IGZ1bmN0aW9uIChlKSB7XG5cdFx0dmFyIGxhdGxuZyA9IGUubGF0bG5nLCBjb250YWluZXJQb2ludCwgbGF5ZXJQb2ludDtcblx0XHRpZiAodGhpcy5fdG9vbHRpcC5vcHRpb25zLnN0aWNreSAmJiBlLm9yaWdpbmFsRXZlbnQpIHtcblx0XHRcdGNvbnRhaW5lclBvaW50ID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50KGUub3JpZ2luYWxFdmVudCk7XG5cdFx0XHRsYXllclBvaW50ID0gdGhpcy5fbWFwLmNvbnRhaW5lclBvaW50VG9MYXllclBvaW50KGNvbnRhaW5lclBvaW50KTtcblx0XHRcdGxhdGxuZyA9IHRoaXMuX21hcC5sYXllclBvaW50VG9MYXRMbmcobGF5ZXJQb2ludCk7XG5cdFx0fVxuXHRcdHRoaXMuX3Rvb2x0aXAuc2V0TGF0TG5nKGxhdGxuZyk7XG5cdH1cbn0pO1xuXG5cblxuLypcclxuICogQGNsYXNzIExheWVyR3JvdXBcclxuICogQGFrYSBMLkxheWVyR3JvdXBcclxuICogQGluaGVyaXRzIExheWVyXHJcbiAqXHJcbiAqIFVzZWQgdG8gZ3JvdXAgc2V2ZXJhbCBsYXllcnMgYW5kIGhhbmRsZSB0aGVtIGFzIG9uZS4gSWYgeW91IGFkZCBpdCB0byB0aGUgbWFwLFxyXG4gKiBhbnkgbGF5ZXJzIGFkZGVkIG9yIHJlbW92ZWQgZnJvbSB0aGUgZ3JvdXAgd2lsbCBiZSBhZGRlZC9yZW1vdmVkIG9uIHRoZSBtYXAgYXNcclxuICogd2VsbC4gRXh0ZW5kcyBgTGF5ZXJgLlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiBMLmxheWVyR3JvdXAoW21hcmtlcjEsIG1hcmtlcjJdKVxyXG4gKiBcdC5hZGRMYXllcihwb2x5bGluZSlcclxuICogXHQuYWRkVG8obWFwKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxuTC5MYXllckdyb3VwID0gTC5MYXllci5leHRlbmQoe1xyXG5cclxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAobGF5ZXJzKSB7XHJcblx0XHR0aGlzLl9sYXllcnMgPSB7fTtcclxuXHJcblx0XHR2YXIgaSwgbGVuO1xyXG5cclxuXHRcdGlmIChsYXllcnMpIHtcclxuXHRcdFx0Zm9yIChpID0gMCwgbGVuID0gbGF5ZXJzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdFx0dGhpcy5hZGRMYXllcihsYXllcnNbaV0pO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBhZGRMYXllcihsYXllcjogTGF5ZXIpOiB0aGlzXHJcblx0Ly8gQWRkcyB0aGUgZ2l2ZW4gbGF5ZXIgdG8gdGhlIGdyb3VwLlxyXG5cdGFkZExheWVyOiBmdW5jdGlvbiAobGF5ZXIpIHtcclxuXHRcdHZhciBpZCA9IHRoaXMuZ2V0TGF5ZXJJZChsYXllcik7XHJcblxyXG5cdFx0dGhpcy5fbGF5ZXJzW2lkXSA9IGxheWVyO1xyXG5cclxuXHRcdGlmICh0aGlzLl9tYXApIHtcclxuXHRcdFx0dGhpcy5fbWFwLmFkZExheWVyKGxheWVyKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlbW92ZUxheWVyKGxheWVyOiBMYXllcik6IHRoaXNcclxuXHQvLyBSZW1vdmVzIHRoZSBnaXZlbiBsYXllciBmcm9tIHRoZSBncm91cC5cclxuXHQvLyBAYWx0ZXJuYXRpdmVcclxuXHQvLyBAbWV0aG9kIHJlbW92ZUxheWVyKGlkOiBOdW1iZXIpOiB0aGlzXHJcblx0Ly8gUmVtb3ZlcyB0aGUgbGF5ZXIgd2l0aCB0aGUgZ2l2ZW4gaW50ZXJuYWwgSUQgZnJvbSB0aGUgZ3JvdXAuXHJcblx0cmVtb3ZlTGF5ZXI6IGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0dmFyIGlkID0gbGF5ZXIgaW4gdGhpcy5fbGF5ZXJzID8gbGF5ZXIgOiB0aGlzLmdldExheWVySWQobGF5ZXIpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9tYXAgJiYgdGhpcy5fbGF5ZXJzW2lkXSkge1xyXG5cdFx0XHR0aGlzLl9tYXAucmVtb3ZlTGF5ZXIodGhpcy5fbGF5ZXJzW2lkXSk7XHJcblx0XHR9XHJcblxyXG5cdFx0ZGVsZXRlIHRoaXMuX2xheWVyc1tpZF07XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBoYXNMYXllcihsYXllcjogTGF5ZXIpOiBCb29sZWFuXHJcblx0Ly8gUmV0dXJucyBgdHJ1ZWAgaWYgdGhlIGdpdmVuIGxheWVyIGlzIGN1cnJlbnRseSBhZGRlZCB0byB0aGUgZ3JvdXAuXHJcblx0aGFzTGF5ZXI6IGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0cmV0dXJuICEhbGF5ZXIgJiYgKGxheWVyIGluIHRoaXMuX2xheWVycyB8fCB0aGlzLmdldExheWVySWQobGF5ZXIpIGluIHRoaXMuX2xheWVycyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBjbGVhckxheWVycygpOiB0aGlzXHJcblx0Ly8gUmVtb3ZlcyBhbGwgdGhlIGxheWVycyBmcm9tIHRoZSBncm91cC5cclxuXHRjbGVhckxheWVyczogZnVuY3Rpb24gKCkge1xyXG5cdFx0Zm9yICh2YXIgaSBpbiB0aGlzLl9sYXllcnMpIHtcclxuXHRcdFx0dGhpcy5yZW1vdmVMYXllcih0aGlzLl9sYXllcnNbaV0pO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBpbnZva2UobWV0aG9kTmFtZTogU3RyaW5nLCDigKYpOiB0aGlzXHJcblx0Ly8gQ2FsbHMgYG1ldGhvZE5hbWVgIG9uIGV2ZXJ5IGxheWVyIGNvbnRhaW5lZCBpbiB0aGlzIGdyb3VwLCBwYXNzaW5nIGFueVxyXG5cdC8vIGFkZGl0aW9uYWwgcGFyYW1ldGVycy4gSGFzIG5vIGVmZmVjdCBpZiB0aGUgbGF5ZXJzIGNvbnRhaW5lZCBkbyBub3RcclxuXHQvLyBpbXBsZW1lbnQgYG1ldGhvZE5hbWVgLlxyXG5cdGludm9rZTogZnVuY3Rpb24gKG1ldGhvZE5hbWUpIHtcclxuXHRcdHZhciBhcmdzID0gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoYXJndW1lbnRzLCAxKSxcclxuXHRcdCAgICBpLCBsYXllcjtcclxuXHJcblx0XHRmb3IgKGkgaW4gdGhpcy5fbGF5ZXJzKSB7XHJcblx0XHRcdGxheWVyID0gdGhpcy5fbGF5ZXJzW2ldO1xyXG5cclxuXHRcdFx0aWYgKGxheWVyW21ldGhvZE5hbWVdKSB7XHJcblx0XHRcdFx0bGF5ZXJbbWV0aG9kTmFtZV0uYXBwbHkobGF5ZXIsIGFyZ3MpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0b25BZGQ6IGZ1bmN0aW9uIChtYXApIHtcclxuXHRcdGZvciAodmFyIGkgaW4gdGhpcy5fbGF5ZXJzKSB7XHJcblx0XHRcdG1hcC5hZGRMYXllcih0aGlzLl9sYXllcnNbaV0pO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdG9uUmVtb3ZlOiBmdW5jdGlvbiAobWFwKSB7XHJcblx0XHRmb3IgKHZhciBpIGluIHRoaXMuX2xheWVycykge1xyXG5cdFx0XHRtYXAucmVtb3ZlTGF5ZXIodGhpcy5fbGF5ZXJzW2ldKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGVhY2hMYXllcihmbjogRnVuY3Rpb24sIGNvbnRleHQ/OiBPYmplY3QpOiB0aGlzXHJcblx0Ly8gSXRlcmF0ZXMgb3ZlciB0aGUgbGF5ZXJzIG9mIHRoZSBncm91cCwgb3B0aW9uYWxseSBzcGVjaWZ5aW5nIGNvbnRleHQgb2YgdGhlIGl0ZXJhdG9yIGZ1bmN0aW9uLlxyXG5cdC8vIGBgYGpzXHJcblx0Ly8gZ3JvdXAuZWFjaExheWVyKGZ1bmN0aW9uIChsYXllcikge1xyXG5cdC8vIFx0bGF5ZXIuYmluZFBvcHVwKCdIZWxsbycpO1xyXG5cdC8vIH0pO1xyXG5cdC8vIGBgYFxyXG5cdGVhY2hMYXllcjogZnVuY3Rpb24gKG1ldGhvZCwgY29udGV4dCkge1xyXG5cdFx0Zm9yICh2YXIgaSBpbiB0aGlzLl9sYXllcnMpIHtcclxuXHRcdFx0bWV0aG9kLmNhbGwoY29udGV4dCwgdGhpcy5fbGF5ZXJzW2ldKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0TGF5ZXIoaWQ6IE51bWJlcik6IExheWVyXHJcblx0Ly8gUmV0dXJucyB0aGUgbGF5ZXIgd2l0aCB0aGUgZ2l2ZW4gaW50ZXJuYWwgSUQuXHJcblx0Z2V0TGF5ZXI6IGZ1bmN0aW9uIChpZCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX2xheWVyc1tpZF07XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRMYXllcnMoKTogTGF5ZXJbXVxyXG5cdC8vIFJldHVybnMgYW4gYXJyYXkgb2YgYWxsIHRoZSBsYXllcnMgYWRkZWQgdG8gdGhlIGdyb3VwLlxyXG5cdGdldExheWVyczogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGxheWVycyA9IFtdO1xyXG5cclxuXHRcdGZvciAodmFyIGkgaW4gdGhpcy5fbGF5ZXJzKSB7XHJcblx0XHRcdGxheWVycy5wdXNoKHRoaXMuX2xheWVyc1tpXSk7XHJcblx0XHR9XHJcblx0XHRyZXR1cm4gbGF5ZXJzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0WkluZGV4KHpJbmRleDogTnVtYmVyKTogdGhpc1xyXG5cdC8vIENhbGxzIGBzZXRaSW5kZXhgIG9uIGV2ZXJ5IGxheWVyIGNvbnRhaW5lZCBpbiB0aGlzIGdyb3VwLCBwYXNzaW5nIHRoZSB6LWluZGV4LlxyXG5cdHNldFpJbmRleDogZnVuY3Rpb24gKHpJbmRleCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuaW52b2tlKCdzZXRaSW5kZXgnLCB6SW5kZXgpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZ2V0TGF5ZXJJZChsYXllcjogTGF5ZXIpOiBOdW1iZXJcclxuXHQvLyBSZXR1cm5zIHRoZSBpbnRlcm5hbCBJRCBmb3IgYSBsYXllclxyXG5cdGdldExheWVySWQ6IGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0cmV0dXJuIEwuc3RhbXAobGF5ZXIpO1xyXG5cdH1cclxufSk7XHJcblxyXG5cclxuLy8gQGZhY3RvcnkgTC5sYXllckdyb3VwKGxheWVyczogTGF5ZXJbXSlcclxuLy8gQ3JlYXRlIGEgbGF5ZXIgZ3JvdXAsIG9wdGlvbmFsbHkgZ2l2ZW4gYW4gaW5pdGlhbCBzZXQgb2YgbGF5ZXJzLlxyXG5MLmxheWVyR3JvdXAgPSBmdW5jdGlvbiAobGF5ZXJzKSB7XHJcblx0cmV0dXJuIG5ldyBMLkxheWVyR3JvdXAobGF5ZXJzKTtcclxufTtcclxuXG5cblxuLypcclxuICogQGNsYXNzIEZlYXR1cmVHcm91cFxyXG4gKiBAYWthIEwuRmVhdHVyZUdyb3VwXHJcbiAqIEBpbmhlcml0cyBMYXllckdyb3VwXHJcbiAqXHJcbiAqIEV4dGVuZGVkIGBMYXllckdyb3VwYCB0aGF0IG1ha2VzIGl0IGVhc2llciB0byBkbyB0aGUgc2FtZSB0aGluZyB0byBhbGwgaXRzIG1lbWJlciBsYXllcnM6XHJcbiAqICAqIFtgYmluZFBvcHVwYF0oI2xheWVyLWJpbmRwb3B1cCkgYmluZHMgYSBwb3B1cCB0byBhbGwgb2YgdGhlIGxheWVycyBhdCBvbmNlIChsaWtld2lzZSB3aXRoIFtgYmluZFRvb2x0aXBgXSgjbGF5ZXItYmluZHRvb2x0aXApKVxyXG4gKiAgKiBFdmVudHMgYXJlIHByb3BhZ2F0ZWQgdG8gdGhlIGBGZWF0dXJlR3JvdXBgLCBzbyBpZiB0aGUgZ3JvdXAgaGFzIGFuIGV2ZW50XHJcbiAqIGhhbmRsZXIsIGl0IHdpbGwgaGFuZGxlIGV2ZW50cyBmcm9tIGFueSBvZiB0aGUgbGF5ZXJzLiBUaGlzIGluY2x1ZGVzIG1vdXNlIGV2ZW50c1xyXG4gKiBhbmQgY3VzdG9tIGV2ZW50cy5cclxuICogICogSGFzIGBsYXllcmFkZGAgYW5kIGBsYXllcnJlbW92ZWAgZXZlbnRzXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIEwuZmVhdHVyZUdyb3VwKFttYXJrZXIxLCBtYXJrZXIyLCBwb2x5bGluZV0pXHJcbiAqIFx0LmJpbmRQb3B1cCgnSGVsbG8gd29ybGQhJylcclxuICogXHQub24oJ2NsaWNrJywgZnVuY3Rpb24oKSB7IGFsZXJ0KCdDbGlja2VkIG9uIGEgbWVtYmVyIG9mIHRoZSBncm91cCEnKTsgfSlcclxuICogXHQuYWRkVG8obWFwKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxuTC5GZWF0dXJlR3JvdXAgPSBMLkxheWVyR3JvdXAuZXh0ZW5kKHtcclxuXHJcblx0YWRkTGF5ZXI6IGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0aWYgKHRoaXMuaGFzTGF5ZXIobGF5ZXIpKSB7XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0fVxyXG5cclxuXHRcdGxheWVyLmFkZEV2ZW50UGFyZW50KHRoaXMpO1xyXG5cclxuXHRcdEwuTGF5ZXJHcm91cC5wcm90b3R5cGUuYWRkTGF5ZXIuY2FsbCh0aGlzLCBsYXllcik7XHJcblxyXG5cdFx0Ly8gQGV2ZW50IGxheWVyYWRkOiBMYXllckV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIGEgbGF5ZXIgaXMgYWRkZWQgdG8gdGhpcyBgRmVhdHVyZUdyb3VwYFxyXG5cdFx0cmV0dXJuIHRoaXMuZmlyZSgnbGF5ZXJhZGQnLCB7bGF5ZXI6IGxheWVyfSk7XHJcblx0fSxcclxuXHJcblx0cmVtb3ZlTGF5ZXI6IGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0aWYgKCF0aGlzLmhhc0xheWVyKGxheWVyKSkge1xyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHRcdH1cclxuXHRcdGlmIChsYXllciBpbiB0aGlzLl9sYXllcnMpIHtcclxuXHRcdFx0bGF5ZXIgPSB0aGlzLl9sYXllcnNbbGF5ZXJdO1xyXG5cdFx0fVxyXG5cclxuXHRcdGxheWVyLnJlbW92ZUV2ZW50UGFyZW50KHRoaXMpO1xyXG5cclxuXHRcdEwuTGF5ZXJHcm91cC5wcm90b3R5cGUucmVtb3ZlTGF5ZXIuY2FsbCh0aGlzLCBsYXllcik7XHJcblxyXG5cdFx0Ly8gQGV2ZW50IGxheWVycmVtb3ZlOiBMYXllckV2ZW50XHJcblx0XHQvLyBGaXJlZCB3aGVuIGEgbGF5ZXIgaXMgcmVtb3ZlZCBmcm9tIHRoaXMgYEZlYXR1cmVHcm91cGBcclxuXHRcdHJldHVybiB0aGlzLmZpcmUoJ2xheWVycmVtb3ZlJywge2xheWVyOiBsYXllcn0pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0U3R5bGUoc3R5bGU6IFBhdGggb3B0aW9ucyk6IHRoaXNcclxuXHQvLyBTZXRzIHRoZSBnaXZlbiBwYXRoIG9wdGlvbnMgdG8gZWFjaCBsYXllciBvZiB0aGUgZ3JvdXAgdGhhdCBoYXMgYSBgc2V0U3R5bGVgIG1ldGhvZC5cclxuXHRzZXRTdHlsZTogZnVuY3Rpb24gKHN0eWxlKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5pbnZva2UoJ3NldFN0eWxlJywgc3R5bGUpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgYnJpbmdUb0Zyb250KCk6IHRoaXNcclxuXHQvLyBCcmluZ3MgdGhlIGxheWVyIGdyb3VwIHRvIHRoZSB0b3Agb2YgYWxsIG90aGVyIGxheWVyc1xyXG5cdGJyaW5nVG9Gcm9udDogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuaW52b2tlKCdicmluZ1RvRnJvbnQnKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGJyaW5nVG9CYWNrKCk6IHRoaXNcclxuXHQvLyBCcmluZ3MgdGhlIGxheWVyIGdyb3VwIHRvIHRoZSB0b3Agb2YgYWxsIG90aGVyIGxheWVyc1xyXG5cdGJyaW5nVG9CYWNrOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5pbnZva2UoJ2JyaW5nVG9CYWNrJyk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBnZXRCb3VuZHMoKTogTGF0TG5nQm91bmRzXHJcblx0Ly8gUmV0dXJucyB0aGUgTGF0TG5nQm91bmRzIG9mIHRoZSBGZWF0dXJlIEdyb3VwIChjcmVhdGVkIGZyb20gYm91bmRzIGFuZCBjb29yZGluYXRlcyBvZiBpdHMgY2hpbGRyZW4pLlxyXG5cdGdldEJvdW5kczogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGJvdW5kcyA9IG5ldyBMLkxhdExuZ0JvdW5kcygpO1xyXG5cclxuXHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2xheWVycykge1xyXG5cdFx0XHR2YXIgbGF5ZXIgPSB0aGlzLl9sYXllcnNbaWRdO1xyXG5cdFx0XHRib3VuZHMuZXh0ZW5kKGxheWVyLmdldEJvdW5kcyA/IGxheWVyLmdldEJvdW5kcygpIDogbGF5ZXIuZ2V0TGF0TG5nKCkpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuIGJvdW5kcztcclxuXHR9XHJcbn0pO1xyXG5cclxuLy8gQGZhY3RvcnkgTC5mZWF0dXJlR3JvdXAobGF5ZXJzOiBMYXllcltdKVxyXG4vLyBDcmVhdGUgYSBmZWF0dXJlIGdyb3VwLCBvcHRpb25hbGx5IGdpdmVuIGFuIGluaXRpYWwgc2V0IG9mIGxheWVycy5cclxuTC5mZWF0dXJlR3JvdXAgPSBmdW5jdGlvbiAobGF5ZXJzKSB7XHJcblx0cmV0dXJuIG5ldyBMLkZlYXR1cmVHcm91cChsYXllcnMpO1xyXG59O1xyXG5cblxuXG4vKlxuICogQGNsYXNzIFJlbmRlcmVyXG4gKiBAaW5oZXJpdHMgTGF5ZXJcbiAqIEBha2EgTC5SZW5kZXJlclxuICpcbiAqIEJhc2UgY2xhc3MgZm9yIHZlY3RvciByZW5kZXJlciBpbXBsZW1lbnRhdGlvbnMgKGBTVkdgLCBgQ2FudmFzYCkuIEhhbmRsZXMgdGhlXG4gKiBET00gY29udGFpbmVyIG9mIHRoZSByZW5kZXJlciwgaXRzIGJvdW5kcywgYW5kIGl0cyB6b29tIGFuaW1hdGlvbi5cbiAqXG4gKiBBIGBSZW5kZXJlcmAgd29ya3MgYXMgYW4gaW1wbGljaXQgbGF5ZXIgZ3JvdXAgZm9yIGFsbCBgUGF0aGBzIC0gdGhlIHJlbmRlcmVyXG4gKiBpdHNlbGYgY2FuIGJlIGFkZGVkIG9yIHJlbW92ZWQgdG8gdGhlIG1hcC4gQWxsIHBhdGhzIHVzZSBhIHJlbmRlcmVyLCB3aGljaCBjYW5cbiAqIGJlIGltcGxpY2l0ICh0aGUgbWFwIHdpbGwgZGVjaWRlIHRoZSB0eXBlIG9mIHJlbmRlcmVyIGFuZCB1c2UgaXQgYXV0b21hdGljYWxseSlcbiAqIG9yIGV4cGxpY2l0ICh1c2luZyB0aGUgW2ByZW5kZXJlcmBdKCNwYXRoLXJlbmRlcmVyKSBvcHRpb24gb2YgdGhlIHBhdGgpLlxuICpcbiAqIERvIG5vdCB1c2UgdGhpcyBjbGFzcyBkaXJlY3RseSwgdXNlIGBTVkdgIGFuZCBgQ2FudmFzYCBpbnN0ZWFkLlxuICpcbiAqIEBldmVudCB1cGRhdGU6IEV2ZW50XG4gKiBGaXJlZCB3aGVuIHRoZSByZW5kZXJlciB1cGRhdGVzIGl0cyBib3VuZHMsIGNlbnRlciBhbmQgem9vbSwgZm9yIGV4YW1wbGUgd2hlblxuICogaXRzIG1hcCBoYXMgbW92ZWRcbiAqL1xuXG5MLlJlbmRlcmVyID0gTC5MYXllci5leHRlbmQoe1xuXG5cdC8vIEBzZWN0aW9uXG5cdC8vIEBha2EgUmVuZGVyZXIgb3B0aW9uc1xuXHRvcHRpb25zOiB7XG5cdFx0Ly8gQG9wdGlvbiBwYWRkaW5nOiBOdW1iZXIgPSAwLjFcblx0XHQvLyBIb3cgbXVjaCB0byBleHRlbmQgdGhlIGNsaXAgYXJlYSBhcm91bmQgdGhlIG1hcCB2aWV3IChyZWxhdGl2ZSB0byBpdHMgc2l6ZSlcblx0XHQvLyBlLmcuIDAuMSB3b3VsZCBiZSAxMCUgb2YgbWFwIHZpZXcgaW4gZWFjaCBkaXJlY3Rpb25cblx0XHRwYWRkaW5nOiAwLjFcblx0fSxcblxuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAob3B0aW9ucykge1xuXHRcdEwuc2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcblx0XHRMLnN0YW1wKHRoaXMpO1xuXHRcdHRoaXMuX2xheWVycyA9IHRoaXMuX2xheWVycyB8fCB7fTtcblx0fSxcblxuXHRvbkFkZDogZnVuY3Rpb24gKCkge1xuXHRcdGlmICghdGhpcy5fY29udGFpbmVyKSB7XG5cdFx0XHR0aGlzLl9pbml0Q29udGFpbmVyKCk7IC8vIGRlZmluZWQgYnkgcmVuZGVyZXIgaW1wbGVtZW50YXRpb25zXG5cblx0XHRcdGlmICh0aGlzLl96b29tQW5pbWF0ZWQpIHtcblx0XHRcdFx0TC5Eb21VdGlsLmFkZENsYXNzKHRoaXMuX2NvbnRhaW5lciwgJ2xlYWZsZXQtem9vbS1hbmltYXRlZCcpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuZ2V0UGFuZSgpLmFwcGVuZENoaWxkKHRoaXMuX2NvbnRhaW5lcik7XG5cdFx0dGhpcy5fdXBkYXRlKCk7XG5cdFx0dGhpcy5vbigndXBkYXRlJywgdGhpcy5fdXBkYXRlUGF0aHMsIHRoaXMpO1xuXHR9LFxuXG5cdG9uUmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG5cdFx0TC5Eb21VdGlsLnJlbW92ZSh0aGlzLl9jb250YWluZXIpO1xuXHRcdHRoaXMub2ZmKCd1cGRhdGUnLCB0aGlzLl91cGRhdGVQYXRocywgdGhpcyk7XG5cdH0sXG5cblx0Z2V0RXZlbnRzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGV2ZW50cyA9IHtcblx0XHRcdHZpZXdyZXNldDogdGhpcy5fcmVzZXQsXG5cdFx0XHR6b29tOiB0aGlzLl9vblpvb20sXG5cdFx0XHRtb3ZlZW5kOiB0aGlzLl91cGRhdGUsXG5cdFx0XHR6b29tZW5kOiB0aGlzLl9vblpvb21FbmRcblx0XHR9O1xuXHRcdGlmICh0aGlzLl96b29tQW5pbWF0ZWQpIHtcblx0XHRcdGV2ZW50cy56b29tYW5pbSA9IHRoaXMuX29uQW5pbVpvb207XG5cdFx0fVxuXHRcdHJldHVybiBldmVudHM7XG5cdH0sXG5cblx0X29uQW5pbVpvb206IGZ1bmN0aW9uIChldikge1xuXHRcdHRoaXMuX3VwZGF0ZVRyYW5zZm9ybShldi5jZW50ZXIsIGV2Lnpvb20pO1xuXHR9LFxuXG5cdF9vblpvb206IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl91cGRhdGVUcmFuc2Zvcm0odGhpcy5fbWFwLmdldENlbnRlcigpLCB0aGlzLl9tYXAuZ2V0Wm9vbSgpKTtcblx0fSxcblxuXHRfdXBkYXRlVHJhbnNmb3JtOiBmdW5jdGlvbiAoY2VudGVyLCB6b29tKSB7XG5cdFx0dmFyIHNjYWxlID0gdGhpcy5fbWFwLmdldFpvb21TY2FsZSh6b29tLCB0aGlzLl96b29tKSxcblx0XHQgICAgcG9zaXRpb24gPSBMLkRvbVV0aWwuZ2V0UG9zaXRpb24odGhpcy5fY29udGFpbmVyKSxcblx0XHQgICAgdmlld0hhbGYgPSB0aGlzLl9tYXAuZ2V0U2l6ZSgpLm11bHRpcGx5QnkoMC41ICsgdGhpcy5vcHRpb25zLnBhZGRpbmcpLFxuXHRcdCAgICBjdXJyZW50Q2VudGVyUG9pbnQgPSB0aGlzLl9tYXAucHJvamVjdCh0aGlzLl9jZW50ZXIsIHpvb20pLFxuXHRcdCAgICBkZXN0Q2VudGVyUG9pbnQgPSB0aGlzLl9tYXAucHJvamVjdChjZW50ZXIsIHpvb20pLFxuXHRcdCAgICBjZW50ZXJPZmZzZXQgPSBkZXN0Q2VudGVyUG9pbnQuc3VidHJhY3QoY3VycmVudENlbnRlclBvaW50KSxcblxuXHRcdCAgICB0b3BMZWZ0T2Zmc2V0ID0gdmlld0hhbGYubXVsdGlwbHlCeSgtc2NhbGUpLmFkZChwb3NpdGlvbikuYWRkKHZpZXdIYWxmKS5zdWJ0cmFjdChjZW50ZXJPZmZzZXQpO1xuXG5cdFx0aWYgKEwuQnJvd3Nlci5hbnkzZCkge1xuXHRcdFx0TC5Eb21VdGlsLnNldFRyYW5zZm9ybSh0aGlzLl9jb250YWluZXIsIHRvcExlZnRPZmZzZXQsIHNjYWxlKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0TC5Eb21VdGlsLnNldFBvc2l0aW9uKHRoaXMuX2NvbnRhaW5lciwgdG9wTGVmdE9mZnNldCk7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZXNldDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3VwZGF0ZSgpO1xuXHRcdHRoaXMuX3VwZGF0ZVRyYW5zZm9ybSh0aGlzLl9jZW50ZXIsIHRoaXMuX3pvb20pO1xuXG5cdFx0Zm9yICh2YXIgaWQgaW4gdGhpcy5fbGF5ZXJzKSB7XG5cdFx0XHR0aGlzLl9sYXllcnNbaWRdLl9yZXNldCgpO1xuXHRcdH1cblx0fSxcblxuXHRfb25ab29tRW5kOiBmdW5jdGlvbiAoKSB7XG5cdFx0Zm9yICh2YXIgaWQgaW4gdGhpcy5fbGF5ZXJzKSB7XG5cdFx0XHR0aGlzLl9sYXllcnNbaWRdLl9wcm9qZWN0KCk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGVQYXRoczogZnVuY3Rpb24gKCkge1xuXHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2xheWVycykge1xuXHRcdFx0dGhpcy5fbGF5ZXJzW2lkXS5fdXBkYXRlKCk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGU6IGZ1bmN0aW9uICgpIHtcblx0XHQvLyBVcGRhdGUgcGl4ZWwgYm91bmRzIG9mIHJlbmRlcmVyIGNvbnRhaW5lciAoZm9yIHBvc2l0aW9uaW5nL3NpemluZy9jbGlwcGluZyBsYXRlcilcblx0XHQvLyBTdWJjbGFzc2VzIGFyZSByZXNwb25zaWJsZSBvZiBmaXJpbmcgdGhlICd1cGRhdGUnIGV2ZW50LlxuXHRcdHZhciBwID0gdGhpcy5vcHRpb25zLnBhZGRpbmcsXG5cdFx0ICAgIHNpemUgPSB0aGlzLl9tYXAuZ2V0U2l6ZSgpLFxuXHRcdCAgICBtaW4gPSB0aGlzLl9tYXAuY29udGFpbmVyUG9pbnRUb0xheWVyUG9pbnQoc2l6ZS5tdWx0aXBseUJ5KC1wKSkucm91bmQoKTtcblxuXHRcdHRoaXMuX2JvdW5kcyA9IG5ldyBMLkJvdW5kcyhtaW4sIG1pbi5hZGQoc2l6ZS5tdWx0aXBseUJ5KDEgKyBwICogMikpLnJvdW5kKCkpO1xuXG5cdFx0dGhpcy5fY2VudGVyID0gdGhpcy5fbWFwLmdldENlbnRlcigpO1xuXHRcdHRoaXMuX3pvb20gPSB0aGlzLl9tYXAuZ2V0Wm9vbSgpO1xuXHR9XG59KTtcblxuXG5MLk1hcC5pbmNsdWRlKHtcblx0Ly8gQG5hbWVzcGFjZSBNYXA7IEBtZXRob2QgZ2V0UmVuZGVyZXIobGF5ZXI6IFBhdGgpOiBSZW5kZXJlclxuXHQvLyBSZXR1cm5zIHRoZSBpbnN0YW5jZSBvZiBgUmVuZGVyZXJgIHRoYXQgc2hvdWxkIGJlIHVzZWQgdG8gcmVuZGVyIHRoZSBnaXZlblxuXHQvLyBgUGF0aGAuIEl0IHdpbGwgZW5zdXJlIHRoYXQgdGhlIGByZW5kZXJlcmAgb3B0aW9ucyBvZiB0aGUgbWFwIGFuZCBwYXRoc1xuXHQvLyBhcmUgcmVzcGVjdGVkLCBhbmQgdGhhdCB0aGUgcmVuZGVyZXJzIGRvIGV4aXN0IG9uIHRoZSBtYXAuXG5cdGdldFJlbmRlcmVyOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHQvLyBAbmFtZXNwYWNlIFBhdGg7IEBvcHRpb24gcmVuZGVyZXI6IFJlbmRlcmVyXG5cdFx0Ly8gVXNlIHRoaXMgc3BlY2lmaWMgaW5zdGFuY2Ugb2YgYFJlbmRlcmVyYCBmb3IgdGhpcyBwYXRoLiBUYWtlc1xuXHRcdC8vIHByZWNlZGVuY2Ugb3ZlciB0aGUgbWFwJ3MgW2RlZmF1bHQgcmVuZGVyZXJdKCNtYXAtcmVuZGVyZXIpLlxuXHRcdHZhciByZW5kZXJlciA9IGxheWVyLm9wdGlvbnMucmVuZGVyZXIgfHwgdGhpcy5fZ2V0UGFuZVJlbmRlcmVyKGxheWVyLm9wdGlvbnMucGFuZSkgfHwgdGhpcy5vcHRpb25zLnJlbmRlcmVyIHx8IHRoaXMuX3JlbmRlcmVyO1xuXG5cdFx0aWYgKCFyZW5kZXJlcikge1xuXHRcdFx0Ly8gQG5hbWVzcGFjZSBNYXA7IEBvcHRpb24gcHJlZmVyQ2FudmFzOiBCb29sZWFuID0gZmFsc2Vcblx0XHRcdC8vIFdoZXRoZXIgYFBhdGhgcyBzaG91bGQgYmUgcmVuZGVyZWQgb24gYSBgQ2FudmFzYCByZW5kZXJlci5cblx0XHRcdC8vIEJ5IGRlZmF1bHQsIGFsbCBgUGF0aGBzIGFyZSByZW5kZXJlZCBpbiBhIGBTVkdgIHJlbmRlcmVyLlxuXHRcdFx0cmVuZGVyZXIgPSB0aGlzLl9yZW5kZXJlciA9ICh0aGlzLm9wdGlvbnMucHJlZmVyQ2FudmFzICYmIEwuY2FudmFzKCkpIHx8IEwuc3ZnKCk7XG5cdFx0fVxuXG5cdFx0aWYgKCF0aGlzLmhhc0xheWVyKHJlbmRlcmVyKSkge1xuXHRcdFx0dGhpcy5hZGRMYXllcihyZW5kZXJlcik7XG5cdFx0fVxuXHRcdHJldHVybiByZW5kZXJlcjtcblx0fSxcblxuXHRfZ2V0UGFuZVJlbmRlcmVyOiBmdW5jdGlvbiAobmFtZSkge1xuXHRcdGlmIChuYW1lID09PSAnb3ZlcmxheVBhbmUnIHx8IG5hbWUgPT09IHVuZGVmaW5lZCkge1xuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXHRcdH1cblxuXHRcdHZhciByZW5kZXJlciA9IHRoaXMuX3BhbmVSZW5kZXJlcnNbbmFtZV07XG5cdFx0aWYgKHJlbmRlcmVyID09PSB1bmRlZmluZWQpIHtcblx0XHRcdHJlbmRlcmVyID0gKEwuU1ZHICYmIEwuc3ZnKHtwYW5lOiBuYW1lfSkpIHx8IChMLkNhbnZhcyAmJiBMLmNhbnZhcyh7cGFuZTogbmFtZX0pKTtcblx0XHRcdHRoaXMuX3BhbmVSZW5kZXJlcnNbbmFtZV0gPSByZW5kZXJlcjtcblx0XHR9XG5cdFx0cmV0dXJuIHJlbmRlcmVyO1xuXHR9XG59KTtcblxuXG5cbi8qXG4gKiBAY2xhc3MgUGF0aFxuICogQGFrYSBMLlBhdGhcbiAqIEBpbmhlcml0cyBJbnRlcmFjdGl2ZSBsYXllclxuICpcbiAqIEFuIGFic3RyYWN0IGNsYXNzIHRoYXQgY29udGFpbnMgb3B0aW9ucyBhbmQgY29uc3RhbnRzIHNoYXJlZCBiZXR3ZWVuIHZlY3RvclxuICogb3ZlcmxheXMgKFBvbHlnb24sIFBvbHlsaW5lLCBDaXJjbGUpLiBEbyBub3QgdXNlIGl0IGRpcmVjdGx5LiBFeHRlbmRzIGBMYXllcmAuXG4gKi9cblxuTC5QYXRoID0gTC5MYXllci5leHRlbmQoe1xuXG5cdC8vIEBzZWN0aW9uXG5cdC8vIEBha2EgUGF0aCBvcHRpb25zXG5cdG9wdGlvbnM6IHtcblx0XHQvLyBAb3B0aW9uIHN0cm9rZTogQm9vbGVhbiA9IHRydWVcblx0XHQvLyBXaGV0aGVyIHRvIGRyYXcgc3Ryb2tlIGFsb25nIHRoZSBwYXRoLiBTZXQgaXQgdG8gYGZhbHNlYCB0byBkaXNhYmxlIGJvcmRlcnMgb24gcG9seWdvbnMgb3IgY2lyY2xlcy5cblx0XHRzdHJva2U6IHRydWUsXG5cblx0XHQvLyBAb3B0aW9uIGNvbG9yOiBTdHJpbmcgPSAnIzMzODhmZidcblx0XHQvLyBTdHJva2UgY29sb3Jcblx0XHRjb2xvcjogJyMzMzg4ZmYnLFxuXG5cdFx0Ly8gQG9wdGlvbiB3ZWlnaHQ6IE51bWJlciA9IDNcblx0XHQvLyBTdHJva2Ugd2lkdGggaW4gcGl4ZWxzXG5cdFx0d2VpZ2h0OiAzLFxuXG5cdFx0Ly8gQG9wdGlvbiBvcGFjaXR5OiBOdW1iZXIgPSAxLjBcblx0XHQvLyBTdHJva2Ugb3BhY2l0eVxuXHRcdG9wYWNpdHk6IDEsXG5cblx0XHQvLyBAb3B0aW9uIGxpbmVDYXA6IFN0cmluZz0gJ3JvdW5kJ1xuXHRcdC8vIEEgc3RyaW5nIHRoYXQgZGVmaW5lcyBbc2hhcGUgdG8gYmUgdXNlZCBhdCB0aGUgZW5kXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9TVkcvQXR0cmlidXRlL3N0cm9rZS1saW5lY2FwKSBvZiB0aGUgc3Ryb2tlLlxuXHRcdGxpbmVDYXA6ICdyb3VuZCcsXG5cblx0XHQvLyBAb3B0aW9uIGxpbmVKb2luOiBTdHJpbmcgPSAncm91bmQnXG5cdFx0Ly8gQSBzdHJpbmcgdGhhdCBkZWZpbmVzIFtzaGFwZSB0byBiZSB1c2VkIGF0IHRoZSBjb3JuZXJzXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9TVkcvQXR0cmlidXRlL3N0cm9rZS1saW5lam9pbikgb2YgdGhlIHN0cm9rZS5cblx0XHRsaW5lSm9pbjogJ3JvdW5kJyxcblxuXHRcdC8vIEBvcHRpb24gZGFzaEFycmF5OiBTdHJpbmcgPSBudWxsXG5cdFx0Ly8gQSBzdHJpbmcgdGhhdCBkZWZpbmVzIHRoZSBzdHJva2UgW2Rhc2ggcGF0dGVybl0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvU1ZHL0F0dHJpYnV0ZS9zdHJva2UtZGFzaGFycmF5KS4gRG9lc24ndCB3b3JrIG9uIGBDYW52YXNgLXBvd2VyZWQgbGF5ZXJzIGluIFtzb21lIG9sZCBicm93c2Vyc10oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvQVBJL0NhbnZhc1JlbmRlcmluZ0NvbnRleHQyRC9zZXRMaW5lRGFzaCNCcm93c2VyX2NvbXBhdGliaWxpdHkpLlxuXHRcdGRhc2hBcnJheTogbnVsbCxcblxuXHRcdC8vIEBvcHRpb24gZGFzaE9mZnNldDogU3RyaW5nID0gbnVsbFxuXHRcdC8vIEEgc3RyaW5nIHRoYXQgZGVmaW5lcyB0aGUgW2Rpc3RhbmNlIGludG8gdGhlIGRhc2ggcGF0dGVybiB0byBzdGFydCB0aGUgZGFzaF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvU1ZHL0F0dHJpYnV0ZS9zdHJva2UtZGFzaG9mZnNldCkuIERvZXNuJ3Qgd29yayBvbiBgQ2FudmFzYC1wb3dlcmVkIGxheWVycyBpbiBbc29tZSBvbGQgYnJvd3NlcnNdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0FQSS9DYW52YXNSZW5kZXJpbmdDb250ZXh0MkQvc2V0TGluZURhc2gjQnJvd3Nlcl9jb21wYXRpYmlsaXR5KS5cblx0XHRkYXNoT2Zmc2V0OiBudWxsLFxuXG5cdFx0Ly8gQG9wdGlvbiBmaWxsOiBCb29sZWFuID0gZGVwZW5kc1xuXHRcdC8vIFdoZXRoZXIgdG8gZmlsbCB0aGUgcGF0aCB3aXRoIGNvbG9yLiBTZXQgaXQgdG8gYGZhbHNlYCB0byBkaXNhYmxlIGZpbGxpbmcgb24gcG9seWdvbnMgb3IgY2lyY2xlcy5cblx0XHRmaWxsOiBmYWxzZSxcblxuXHRcdC8vIEBvcHRpb24gZmlsbENvbG9yOiBTdHJpbmcgPSAqXG5cdFx0Ly8gRmlsbCBjb2xvci4gRGVmYXVsdHMgdG8gdGhlIHZhbHVlIG9mIHRoZSBbYGNvbG9yYF0oI3BhdGgtY29sb3IpIG9wdGlvblxuXHRcdGZpbGxDb2xvcjogbnVsbCxcblxuXHRcdC8vIEBvcHRpb24gZmlsbE9wYWNpdHk6IE51bWJlciA9IDAuMlxuXHRcdC8vIEZpbGwgb3BhY2l0eS5cblx0XHRmaWxsT3BhY2l0eTogMC4yLFxuXG5cdFx0Ly8gQG9wdGlvbiBmaWxsUnVsZTogU3RyaW5nID0gJ2V2ZW5vZGQnXG5cdFx0Ly8gQSBzdHJpbmcgdGhhdCBkZWZpbmVzIFtob3cgdGhlIGluc2lkZSBvZiBhIHNoYXBlXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9TVkcvQXR0cmlidXRlL2ZpbGwtcnVsZSkgaXMgZGV0ZXJtaW5lZC5cblx0XHRmaWxsUnVsZTogJ2V2ZW5vZGQnLFxuXG5cdFx0Ly8gY2xhc3NOYW1lOiAnJyxcblxuXHRcdC8vIE9wdGlvbiBpbmhlcml0ZWQgZnJvbSBcIkludGVyYWN0aXZlIGxheWVyXCIgYWJzdHJhY3QgY2xhc3Ncblx0XHRpbnRlcmFjdGl2ZTogdHJ1ZVxuXHR9LFxuXG5cdGJlZm9yZUFkZDogZnVuY3Rpb24gKG1hcCkge1xuXHRcdC8vIFJlbmRlcmVyIGlzIHNldCBoZXJlIGJlY2F1c2Ugd2UgbmVlZCB0byBjYWxsIHJlbmRlcmVyLmdldEV2ZW50c1xuXHRcdC8vIGJlZm9yZSB0aGlzLmdldEV2ZW50cy5cblx0XHR0aGlzLl9yZW5kZXJlciA9IG1hcC5nZXRSZW5kZXJlcih0aGlzKTtcblx0fSxcblxuXHRvbkFkZDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3JlbmRlcmVyLl9pbml0UGF0aCh0aGlzKTtcblx0XHR0aGlzLl9yZXNldCgpO1xuXHRcdHRoaXMuX3JlbmRlcmVyLl9hZGRQYXRoKHRoaXMpO1xuXHR9LFxuXG5cdG9uUmVtb3ZlOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fcmVuZGVyZXIuX3JlbW92ZVBhdGgodGhpcyk7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCByZWRyYXcoKTogdGhpc1xuXHQvLyBSZWRyYXdzIHRoZSBsYXllci4gU29tZXRpbWVzIHVzZWZ1bCBhZnRlciB5b3UgY2hhbmdlZCB0aGUgY29vcmRpbmF0ZXMgdGhhdCB0aGUgcGF0aCB1c2VzLlxuXHRyZWRyYXc6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fbWFwKSB7XG5cdFx0XHR0aGlzLl9yZW5kZXJlci5fdXBkYXRlUGF0aCh0aGlzKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRTdHlsZShzdHlsZTogUGF0aCBvcHRpb25zKTogdGhpc1xuXHQvLyBDaGFuZ2VzIHRoZSBhcHBlYXJhbmNlIG9mIGEgUGF0aCBiYXNlZCBvbiB0aGUgb3B0aW9ucyBpbiB0aGUgYFBhdGggb3B0aW9uc2Agb2JqZWN0LlxuXHRzZXRTdHlsZTogZnVuY3Rpb24gKHN0eWxlKSB7XG5cdFx0TC5zZXRPcHRpb25zKHRoaXMsIHN0eWxlKTtcblx0XHRpZiAodGhpcy5fcmVuZGVyZXIpIHtcblx0XHRcdHRoaXMuX3JlbmRlcmVyLl91cGRhdGVTdHlsZSh0aGlzKTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBicmluZ1RvRnJvbnQoKTogdGhpc1xuXHQvLyBCcmluZ3MgdGhlIGxheWVyIHRvIHRoZSB0b3Agb2YgYWxsIHBhdGggbGF5ZXJzLlxuXHRicmluZ1RvRnJvbnQ6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fcmVuZGVyZXIpIHtcblx0XHRcdHRoaXMuX3JlbmRlcmVyLl9icmluZ1RvRnJvbnQodGhpcyk7XG5cdFx0fVxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgYnJpbmdUb0JhY2soKTogdGhpc1xuXHQvLyBCcmluZ3MgdGhlIGxheWVyIHRvIHRoZSBib3R0b20gb2YgYWxsIHBhdGggbGF5ZXJzLlxuXHRicmluZ1RvQmFjazogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9yZW5kZXJlcikge1xuXHRcdFx0dGhpcy5fcmVuZGVyZXIuX2JyaW5nVG9CYWNrKHRoaXMpO1xuXHRcdH1cblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHRnZXRFbGVtZW50OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3BhdGg7XG5cdH0sXG5cblx0X3Jlc2V0OiBmdW5jdGlvbiAoKSB7XG5cdFx0Ly8gZGVmaW5lZCBpbiBjaGlsZHJlbiBjbGFzc2VzXG5cdFx0dGhpcy5fcHJvamVjdCgpO1xuXHRcdHRoaXMuX3VwZGF0ZSgpO1xuXHR9LFxuXG5cdF9jbGlja1RvbGVyYW5jZTogZnVuY3Rpb24gKCkge1xuXHRcdC8vIHVzZWQgd2hlbiBkb2luZyBoaXQgZGV0ZWN0aW9uIGZvciBDYW52YXMgbGF5ZXJzXG5cdFx0cmV0dXJuICh0aGlzLm9wdGlvbnMuc3Ryb2tlID8gdGhpcy5vcHRpb25zLndlaWdodCAvIDIgOiAwKSArIChMLkJyb3dzZXIudG91Y2ggPyAxMCA6IDApO1xuXHR9XG59KTtcblxuXG5cbi8qXHJcbiAqIEBuYW1lc3BhY2UgTGluZVV0aWxcclxuICpcclxuICogVmFyaW91cyB1dGlsaXR5IGZ1bmN0aW9ucyBmb3IgcG9seWluZSBwb2ludHMgcHJvY2Vzc2luZywgdXNlZCBieSBMZWFmbGV0IGludGVybmFsbHkgdG8gbWFrZSBwb2x5bGluZXMgbGlnaHRuaW5nLWZhc3QuXHJcbiAqL1xyXG5cclxuTC5MaW5lVXRpbCA9IHtcclxuXHJcblx0Ly8gU2ltcGxpZnkgcG9seWxpbmUgd2l0aCB2ZXJ0ZXggcmVkdWN0aW9uIGFuZCBEb3VnbGFzLVBldWNrZXIgc2ltcGxpZmljYXRpb24uXHJcblx0Ly8gSW1wcm92ZXMgcmVuZGVyaW5nIHBlcmZvcm1hbmNlIGRyYW1hdGljYWxseSBieSBsZXNzZW5pbmcgdGhlIG51bWJlciBvZiBwb2ludHMgdG8gZHJhdy5cclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHNpbXBsaWZ5KHBvaW50czogUG9pbnRbXSwgdG9sZXJhbmNlOiBOdW1iZXIpOiBQb2ludFtdXHJcblx0Ly8gRHJhbWF0aWNhbGx5IHJlZHVjZXMgdGhlIG51bWJlciBvZiBwb2ludHMgaW4gYSBwb2x5bGluZSB3aGlsZSByZXRhaW5pbmdcclxuXHQvLyBpdHMgc2hhcGUgYW5kIHJldHVybnMgYSBuZXcgYXJyYXkgb2Ygc2ltcGxpZmllZCBwb2ludHMsIHVzaW5nIHRoZVxyXG5cdC8vIFtEb3VnbGFzLVBldWNrZXIgYWxnb3JpdGhtXShodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0RvdWdsYXMtUGV1Y2tlcl9hbGdvcml0aG0pLlxyXG5cdC8vIFVzZWQgZm9yIGEgaHVnZSBwZXJmb3JtYW5jZSBib29zdCB3aGVuIHByb2Nlc3NpbmcvZGlzcGxheWluZyBMZWFmbGV0IHBvbHlsaW5lcyBmb3JcclxuXHQvLyBlYWNoIHpvb20gbGV2ZWwgYW5kIGFsc28gcmVkdWNpbmcgdmlzdWFsIG5vaXNlLiB0b2xlcmFuY2UgYWZmZWN0cyB0aGUgYW1vdW50IG9mXHJcblx0Ly8gc2ltcGxpZmljYXRpb24gKGxlc3NlciB2YWx1ZSBtZWFucyBoaWdoZXIgcXVhbGl0eSBidXQgc2xvd2VyIGFuZCB3aXRoIG1vcmUgcG9pbnRzKS5cclxuXHQvLyBBbHNvIHJlbGVhc2VkIGFzIGEgc2VwYXJhdGVkIG1pY3JvLWxpYnJhcnkgW1NpbXBsaWZ5LmpzXShodHRwOi8vbW91cm5lci5naXRodWIuY29tL3NpbXBsaWZ5LWpzLykuXHJcblx0c2ltcGxpZnk6IGZ1bmN0aW9uIChwb2ludHMsIHRvbGVyYW5jZSkge1xyXG5cdFx0aWYgKCF0b2xlcmFuY2UgfHwgIXBvaW50cy5sZW5ndGgpIHtcclxuXHRcdFx0cmV0dXJuIHBvaW50cy5zbGljZSgpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBzcVRvbGVyYW5jZSA9IHRvbGVyYW5jZSAqIHRvbGVyYW5jZTtcclxuXHJcblx0XHQvLyBzdGFnZSAxOiB2ZXJ0ZXggcmVkdWN0aW9uXHJcblx0XHRwb2ludHMgPSB0aGlzLl9yZWR1Y2VQb2ludHMocG9pbnRzLCBzcVRvbGVyYW5jZSk7XHJcblxyXG5cdFx0Ly8gc3RhZ2UgMjogRG91Z2xhcy1QZXVja2VyIHNpbXBsaWZpY2F0aW9uXHJcblx0XHRwb2ludHMgPSB0aGlzLl9zaW1wbGlmeURQKHBvaW50cywgc3FUb2xlcmFuY2UpO1xyXG5cclxuXHRcdHJldHVybiBwb2ludHM7XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIHBvaW50VG9TZWdtZW50RGlzdGFuY2UocDogUG9pbnQsIHAxOiBQb2ludCwgcDI6IFBvaW50KTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgZGlzdGFuY2UgYmV0d2VlbiBwb2ludCBgcGAgYW5kIHNlZ21lbnQgYHAxYCB0byBgcDJgLlxyXG5cdHBvaW50VG9TZWdtZW50RGlzdGFuY2U6ICBmdW5jdGlvbiAocCwgcDEsIHAyKSB7XHJcblx0XHRyZXR1cm4gTWF0aC5zcXJ0KHRoaXMuX3NxQ2xvc2VzdFBvaW50T25TZWdtZW50KHAsIHAxLCBwMiwgdHJ1ZSkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBjbG9zZXN0UG9pbnRPblNlZ21lbnQocDogUG9pbnQsIHAxOiBQb2ludCwgcDI6IFBvaW50KTogTnVtYmVyXHJcblx0Ly8gUmV0dXJucyB0aGUgY2xvc2VzdCBwb2ludCBmcm9tIGEgcG9pbnQgYHBgIG9uIGEgc2VnbWVudCBgcDFgIHRvIGBwMmAuXHJcblx0Y2xvc2VzdFBvaW50T25TZWdtZW50OiBmdW5jdGlvbiAocCwgcDEsIHAyKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5fc3FDbG9zZXN0UG9pbnRPblNlZ21lbnQocCwgcDEsIHAyKTtcclxuXHR9LFxyXG5cclxuXHQvLyBEb3VnbGFzLVBldWNrZXIgc2ltcGxpZmljYXRpb24sIHNlZSBodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0RvdWdsYXMtUGV1Y2tlcl9hbGdvcml0aG1cclxuXHRfc2ltcGxpZnlEUDogZnVuY3Rpb24gKHBvaW50cywgc3FUb2xlcmFuY2UpIHtcclxuXHJcblx0XHR2YXIgbGVuID0gcG9pbnRzLmxlbmd0aCxcclxuXHRcdCAgICBBcnJheUNvbnN0cnVjdG9yID0gdHlwZW9mIFVpbnQ4QXJyYXkgIT09IHVuZGVmaW5lZCArICcnID8gVWludDhBcnJheSA6IEFycmF5LFxyXG5cdFx0ICAgIG1hcmtlcnMgPSBuZXcgQXJyYXlDb25zdHJ1Y3RvcihsZW4pO1xyXG5cclxuXHRcdG1hcmtlcnNbMF0gPSBtYXJrZXJzW2xlbiAtIDFdID0gMTtcclxuXHJcblx0XHR0aGlzLl9zaW1wbGlmeURQU3RlcChwb2ludHMsIG1hcmtlcnMsIHNxVG9sZXJhbmNlLCAwLCBsZW4gLSAxKTtcclxuXHJcblx0XHR2YXIgaSxcclxuXHRcdCAgICBuZXdQb2ludHMgPSBbXTtcclxuXHJcblx0XHRmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0aWYgKG1hcmtlcnNbaV0pIHtcclxuXHRcdFx0XHRuZXdQb2ludHMucHVzaChwb2ludHNbaV0pO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIG5ld1BvaW50cztcclxuXHR9LFxyXG5cclxuXHRfc2ltcGxpZnlEUFN0ZXA6IGZ1bmN0aW9uIChwb2ludHMsIG1hcmtlcnMsIHNxVG9sZXJhbmNlLCBmaXJzdCwgbGFzdCkge1xyXG5cclxuXHRcdHZhciBtYXhTcURpc3QgPSAwLFxyXG5cdFx0ICAgIGluZGV4LCBpLCBzcURpc3Q7XHJcblxyXG5cdFx0Zm9yIChpID0gZmlyc3QgKyAxOyBpIDw9IGxhc3QgLSAxOyBpKyspIHtcclxuXHRcdFx0c3FEaXN0ID0gdGhpcy5fc3FDbG9zZXN0UG9pbnRPblNlZ21lbnQocG9pbnRzW2ldLCBwb2ludHNbZmlyc3RdLCBwb2ludHNbbGFzdF0sIHRydWUpO1xyXG5cclxuXHRcdFx0aWYgKHNxRGlzdCA+IG1heFNxRGlzdCkge1xyXG5cdFx0XHRcdGluZGV4ID0gaTtcclxuXHRcdFx0XHRtYXhTcURpc3QgPSBzcURpc3Q7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHRpZiAobWF4U3FEaXN0ID4gc3FUb2xlcmFuY2UpIHtcclxuXHRcdFx0bWFya2Vyc1tpbmRleF0gPSAxO1xyXG5cclxuXHRcdFx0dGhpcy5fc2ltcGxpZnlEUFN0ZXAocG9pbnRzLCBtYXJrZXJzLCBzcVRvbGVyYW5jZSwgZmlyc3QsIGluZGV4KTtcclxuXHRcdFx0dGhpcy5fc2ltcGxpZnlEUFN0ZXAocG9pbnRzLCBtYXJrZXJzLCBzcVRvbGVyYW5jZSwgaW5kZXgsIGxhc3QpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIHJlZHVjZSBwb2ludHMgdGhhdCBhcmUgdG9vIGNsb3NlIHRvIGVhY2ggb3RoZXIgdG8gYSBzaW5nbGUgcG9pbnRcclxuXHRfcmVkdWNlUG9pbnRzOiBmdW5jdGlvbiAocG9pbnRzLCBzcVRvbGVyYW5jZSkge1xyXG5cdFx0dmFyIHJlZHVjZWRQb2ludHMgPSBbcG9pbnRzWzBdXTtcclxuXHJcblx0XHRmb3IgKHZhciBpID0gMSwgcHJldiA9IDAsIGxlbiA9IHBvaW50cy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0XHRpZiAodGhpcy5fc3FEaXN0KHBvaW50c1tpXSwgcG9pbnRzW3ByZXZdKSA+IHNxVG9sZXJhbmNlKSB7XHJcblx0XHRcdFx0cmVkdWNlZFBvaW50cy5wdXNoKHBvaW50c1tpXSk7XHJcblx0XHRcdFx0cHJldiA9IGk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHRcdGlmIChwcmV2IDwgbGVuIC0gMSkge1xyXG5cdFx0XHRyZWR1Y2VkUG9pbnRzLnB1c2gocG9pbnRzW2xlbiAtIDFdKTtcclxuXHRcdH1cclxuXHRcdHJldHVybiByZWR1Y2VkUG9pbnRzO1xyXG5cdH0sXHJcblxyXG5cclxuXHQvLyBAZnVuY3Rpb24gY2xpcFNlZ21lbnQoYTogUG9pbnQsIGI6IFBvaW50LCBib3VuZHM6IEJvdW5kcywgdXNlTGFzdENvZGU/OiBCb29sZWFuLCByb3VuZD86IEJvb2xlYW4pOiBQb2ludFtdfEJvb2xlYW5cclxuXHQvLyBDbGlwcyB0aGUgc2VnbWVudCBhIHRvIGIgYnkgcmVjdGFuZ3VsYXIgYm91bmRzIHdpdGggdGhlXHJcblx0Ly8gW0NvaGVuLVN1dGhlcmxhbmQgYWxnb3JpdGhtXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9Db2hlbiVFMiU4MCU5M1N1dGhlcmxhbmRfYWxnb3JpdGhtKVxyXG5cdC8vIChtb2RpZnlpbmcgdGhlIHNlZ21lbnQgcG9pbnRzIGRpcmVjdGx5ISkuIFVzZWQgYnkgTGVhZmxldCB0byBvbmx5IHNob3cgcG9seWxpbmVcclxuXHQvLyBwb2ludHMgdGhhdCBhcmUgb24gdGhlIHNjcmVlbiBvciBuZWFyLCBpbmNyZWFzaW5nIHBlcmZvcm1hbmNlLlxyXG5cdGNsaXBTZWdtZW50OiBmdW5jdGlvbiAoYSwgYiwgYm91bmRzLCB1c2VMYXN0Q29kZSwgcm91bmQpIHtcclxuXHRcdHZhciBjb2RlQSA9IHVzZUxhc3RDb2RlID8gdGhpcy5fbGFzdENvZGUgOiB0aGlzLl9nZXRCaXRDb2RlKGEsIGJvdW5kcyksXHJcblx0XHQgICAgY29kZUIgPSB0aGlzLl9nZXRCaXRDb2RlKGIsIGJvdW5kcyksXHJcblxyXG5cdFx0ICAgIGNvZGVPdXQsIHAsIG5ld0NvZGU7XHJcblxyXG5cdFx0Ly8gc2F2ZSAybmQgY29kZSB0byBhdm9pZCBjYWxjdWxhdGluZyBpdCBvbiB0aGUgbmV4dCBzZWdtZW50XHJcblx0XHR0aGlzLl9sYXN0Q29kZSA9IGNvZGVCO1xyXG5cclxuXHRcdHdoaWxlICh0cnVlKSB7XHJcblx0XHRcdC8vIGlmIGEsYiBpcyBpbnNpZGUgdGhlIGNsaXAgd2luZG93ICh0cml2aWFsIGFjY2VwdClcclxuXHRcdFx0aWYgKCEoY29kZUEgfCBjb2RlQikpIHtcclxuXHRcdFx0XHRyZXR1cm4gW2EsIGJdO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBpZiBhLGIgaXMgb3V0c2lkZSB0aGUgY2xpcCB3aW5kb3cgKHRyaXZpYWwgcmVqZWN0KVxyXG5cdFx0XHRpZiAoY29kZUEgJiBjb2RlQikge1xyXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gb3RoZXIgY2FzZXNcclxuXHRcdFx0Y29kZU91dCA9IGNvZGVBIHx8IGNvZGVCO1xyXG5cdFx0XHRwID0gdGhpcy5fZ2V0RWRnZUludGVyc2VjdGlvbihhLCBiLCBjb2RlT3V0LCBib3VuZHMsIHJvdW5kKTtcclxuXHRcdFx0bmV3Q29kZSA9IHRoaXMuX2dldEJpdENvZGUocCwgYm91bmRzKTtcclxuXHJcblx0XHRcdGlmIChjb2RlT3V0ID09PSBjb2RlQSkge1xyXG5cdFx0XHRcdGEgPSBwO1xyXG5cdFx0XHRcdGNvZGVBID0gbmV3Q29kZTtcclxuXHRcdFx0fSBlbHNlIHtcclxuXHRcdFx0XHRiID0gcDtcclxuXHRcdFx0XHRjb2RlQiA9IG5ld0NvZGU7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfZ2V0RWRnZUludGVyc2VjdGlvbjogZnVuY3Rpb24gKGEsIGIsIGNvZGUsIGJvdW5kcywgcm91bmQpIHtcclxuXHRcdHZhciBkeCA9IGIueCAtIGEueCxcclxuXHRcdCAgICBkeSA9IGIueSAtIGEueSxcclxuXHRcdCAgICBtaW4gPSBib3VuZHMubWluLFxyXG5cdFx0ICAgIG1heCA9IGJvdW5kcy5tYXgsXHJcblx0XHQgICAgeCwgeTtcclxuXHJcblx0XHRpZiAoY29kZSAmIDgpIHsgLy8gdG9wXHJcblx0XHRcdHggPSBhLnggKyBkeCAqIChtYXgueSAtIGEueSkgLyBkeTtcclxuXHRcdFx0eSA9IG1heC55O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoY29kZSAmIDQpIHsgLy8gYm90dG9tXHJcblx0XHRcdHggPSBhLnggKyBkeCAqIChtaW4ueSAtIGEueSkgLyBkeTtcclxuXHRcdFx0eSA9IG1pbi55O1xyXG5cclxuXHRcdH0gZWxzZSBpZiAoY29kZSAmIDIpIHsgLy8gcmlnaHRcclxuXHRcdFx0eCA9IG1heC54O1xyXG5cdFx0XHR5ID0gYS55ICsgZHkgKiAobWF4LnggLSBhLngpIC8gZHg7XHJcblxyXG5cdFx0fSBlbHNlIGlmIChjb2RlICYgMSkgeyAvLyBsZWZ0XHJcblx0XHRcdHggPSBtaW4ueDtcclxuXHRcdFx0eSA9IGEueSArIGR5ICogKG1pbi54IC0gYS54KSAvIGR4O1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBuZXcgTC5Qb2ludCh4LCB5LCByb3VuZCk7XHJcblx0fSxcclxuXHJcblx0X2dldEJpdENvZGU6IGZ1bmN0aW9uIChwLCBib3VuZHMpIHtcclxuXHRcdHZhciBjb2RlID0gMDtcclxuXHJcblx0XHRpZiAocC54IDwgYm91bmRzLm1pbi54KSB7IC8vIGxlZnRcclxuXHRcdFx0Y29kZSB8PSAxO1xyXG5cdFx0fSBlbHNlIGlmIChwLnggPiBib3VuZHMubWF4LngpIHsgLy8gcmlnaHRcclxuXHRcdFx0Y29kZSB8PSAyO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmIChwLnkgPCBib3VuZHMubWluLnkpIHsgLy8gYm90dG9tXHJcblx0XHRcdGNvZGUgfD0gNDtcclxuXHRcdH0gZWxzZSBpZiAocC55ID4gYm91bmRzLm1heC55KSB7IC8vIHRvcFxyXG5cdFx0XHRjb2RlIHw9IDg7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIGNvZGU7XHJcblx0fSxcclxuXHJcblx0Ly8gc3F1YXJlIGRpc3RhbmNlICh0byBhdm9pZCB1bm5lY2Vzc2FyeSBNYXRoLnNxcnQgY2FsbHMpXHJcblx0X3NxRGlzdDogZnVuY3Rpb24gKHAxLCBwMikge1xyXG5cdFx0dmFyIGR4ID0gcDIueCAtIHAxLngsXHJcblx0XHQgICAgZHkgPSBwMi55IC0gcDEueTtcclxuXHRcdHJldHVybiBkeCAqIGR4ICsgZHkgKiBkeTtcclxuXHR9LFxyXG5cclxuXHQvLyByZXR1cm4gY2xvc2VzdCBwb2ludCBvbiBzZWdtZW50IG9yIGRpc3RhbmNlIHRvIHRoYXQgcG9pbnRcclxuXHRfc3FDbG9zZXN0UG9pbnRPblNlZ21lbnQ6IGZ1bmN0aW9uIChwLCBwMSwgcDIsIHNxRGlzdCkge1xyXG5cdFx0dmFyIHggPSBwMS54LFxyXG5cdFx0ICAgIHkgPSBwMS55LFxyXG5cdFx0ICAgIGR4ID0gcDIueCAtIHgsXHJcblx0XHQgICAgZHkgPSBwMi55IC0geSxcclxuXHRcdCAgICBkb3QgPSBkeCAqIGR4ICsgZHkgKiBkeSxcclxuXHRcdCAgICB0O1xyXG5cclxuXHRcdGlmIChkb3QgPiAwKSB7XHJcblx0XHRcdHQgPSAoKHAueCAtIHgpICogZHggKyAocC55IC0geSkgKiBkeSkgLyBkb3Q7XHJcblxyXG5cdFx0XHRpZiAodCA+IDEpIHtcclxuXHRcdFx0XHR4ID0gcDIueDtcclxuXHRcdFx0XHR5ID0gcDIueTtcclxuXHRcdFx0fSBlbHNlIGlmICh0ID4gMCkge1xyXG5cdFx0XHRcdHggKz0gZHggKiB0O1xyXG5cdFx0XHRcdHkgKz0gZHkgKiB0O1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0ZHggPSBwLnggLSB4O1xyXG5cdFx0ZHkgPSBwLnkgLSB5O1xyXG5cclxuXHRcdHJldHVybiBzcURpc3QgPyBkeCAqIGR4ICsgZHkgKiBkeSA6IG5ldyBMLlBvaW50KHgsIHkpO1xyXG5cdH1cclxufTtcclxuXG5cblxuLypcbiAqIEBjbGFzcyBQb2x5bGluZVxuICogQGFrYSBMLlBvbHlsaW5lXG4gKiBAaW5oZXJpdHMgUGF0aFxuICpcbiAqIEEgY2xhc3MgZm9yIGRyYXdpbmcgcG9seWxpbmUgb3ZlcmxheXMgb24gYSBtYXAuIEV4dGVuZHMgYFBhdGhgLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogYGBganNcbiAqIC8vIGNyZWF0ZSBhIHJlZCBwb2x5bGluZSBmcm9tIGFuIGFycmF5IG9mIExhdExuZyBwb2ludHNcbiAqIHZhciBsYXRsbmdzID0gW1xuICogXHRbLTEyMi42OCwgNDUuNTFdLFxuICogXHRbLTEyMi40MywgMzcuNzddLFxuICogXHRbLTExOC4yLCAzNC4wNF1cbiAqIF07XG4gKlxuICogdmFyIHBvbHlsaW5lID0gTC5wb2x5bGluZShsYXRsbmdzLCB7Y29sb3I6ICdyZWQnfSkuYWRkVG8obWFwKTtcbiAqXG4gKiAvLyB6b29tIHRoZSBtYXAgdG8gdGhlIHBvbHlsaW5lXG4gKiBtYXAuZml0Qm91bmRzKHBvbHlsaW5lLmdldEJvdW5kcygpKTtcbiAqIGBgYFxuICpcbiAqIFlvdSBjYW4gYWxzbyBwYXNzIGEgbXVsdGktZGltZW5zaW9uYWwgYXJyYXkgdG8gcmVwcmVzZW50IGEgYE11bHRpUG9seWxpbmVgIHNoYXBlOlxuICpcbiAqIGBgYGpzXG4gKiAvLyBjcmVhdGUgYSByZWQgcG9seWxpbmUgZnJvbSBhbiBhcnJheSBvZiBhcnJheXMgb2YgTGF0TG5nIHBvaW50c1xuICogdmFyIGxhdGxuZ3MgPSBbXG4gKiBcdFtbLTEyMi42OCwgNDUuNTFdLFxuICogXHQgWy0xMjIuNDMsIDM3Ljc3XSxcbiAqIFx0IFstMTE4LjIsIDM0LjA0XV0sXG4gKiBcdFtbLTczLjkxLCA0MC43OF0sXG4gKiBcdCBbLTg3LjYyLCA0MS44M10sXG4gKiBcdCBbLTk2LjcyLCAzMi43Nl1dXG4gKiBdO1xuICogYGBgXG4gKi9cblxuTC5Qb2x5bGluZSA9IEwuUGF0aC5leHRlbmQoe1xuXG5cdC8vIEBzZWN0aW9uXG5cdC8vIEBha2EgUG9seWxpbmUgb3B0aW9uc1xuXHRvcHRpb25zOiB7XG5cdFx0Ly8gQG9wdGlvbiBzbW9vdGhGYWN0b3I6IE51bWJlciA9IDEuMFxuXHRcdC8vIEhvdyBtdWNoIHRvIHNpbXBsaWZ5IHRoZSBwb2x5bGluZSBvbiBlYWNoIHpvb20gbGV2ZWwuIE1vcmUgbWVhbnNcblx0XHQvLyBiZXR0ZXIgcGVyZm9ybWFuY2UgYW5kIHNtb290aGVyIGxvb2ssIGFuZCBsZXNzIG1lYW5zIG1vcmUgYWNjdXJhdGUgcmVwcmVzZW50YXRpb24uXG5cdFx0c21vb3RoRmFjdG9yOiAxLjAsXG5cblx0XHQvLyBAb3B0aW9uIG5vQ2xpcDogQm9vbGVhbiA9IGZhbHNlXG5cdFx0Ly8gRGlzYWJsZSBwb2x5bGluZSBjbGlwcGluZy5cblx0XHRub0NsaXA6IGZhbHNlXG5cdH0sXG5cblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGxhdGxuZ3MsIG9wdGlvbnMpIHtcblx0XHRMLnNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XG5cdFx0dGhpcy5fc2V0TGF0TG5ncyhsYXRsbmdzKTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIGdldExhdExuZ3MoKTogTGF0TG5nW11cblx0Ly8gUmV0dXJucyBhbiBhcnJheSBvZiB0aGUgcG9pbnRzIGluIHRoZSBwYXRoLCBvciBuZXN0ZWQgYXJyYXlzIG9mIHBvaW50cyBpbiBjYXNlIG9mIG11bHRpLXBvbHlsaW5lLlxuXHRnZXRMYXRMbmdzOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2xhdGxuZ3M7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRMYXRMbmdzKGxhdGxuZ3M6IExhdExuZ1tdKTogdGhpc1xuXHQvLyBSZXBsYWNlcyBhbGwgdGhlIHBvaW50cyBpbiB0aGUgcG9seWxpbmUgd2l0aCB0aGUgZ2l2ZW4gYXJyYXkgb2YgZ2VvZ3JhcGhpY2FsIHBvaW50cy5cblx0c2V0TGF0TG5nczogZnVuY3Rpb24gKGxhdGxuZ3MpIHtcblx0XHR0aGlzLl9zZXRMYXRMbmdzKGxhdGxuZ3MpO1xuXHRcdHJldHVybiB0aGlzLnJlZHJhdygpO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgaXNFbXB0eSgpOiBCb29sZWFuXG5cdC8vIFJldHVybnMgYHRydWVgIGlmIHRoZSBQb2x5bGluZSBoYXMgbm8gTGF0TG5ncy5cblx0aXNFbXB0eTogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiAhdGhpcy5fbGF0bG5ncy5sZW5ndGg7XG5cdH0sXG5cblx0Y2xvc2VzdExheWVyUG9pbnQ6IGZ1bmN0aW9uIChwKSB7XG5cdFx0dmFyIG1pbkRpc3RhbmNlID0gSW5maW5pdHksXG5cdFx0ICAgIG1pblBvaW50ID0gbnVsbCxcblx0XHQgICAgY2xvc2VzdCA9IEwuTGluZVV0aWwuX3NxQ2xvc2VzdFBvaW50T25TZWdtZW50LFxuXHRcdCAgICBwMSwgcDI7XG5cblx0XHRmb3IgKHZhciBqID0gMCwgakxlbiA9IHRoaXMuX3BhcnRzLmxlbmd0aDsgaiA8IGpMZW47IGorKykge1xuXHRcdFx0dmFyIHBvaW50cyA9IHRoaXMuX3BhcnRzW2pdO1xuXG5cdFx0XHRmb3IgKHZhciBpID0gMSwgbGVuID0gcG9pbnRzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRcdHAxID0gcG9pbnRzW2kgLSAxXTtcblx0XHRcdFx0cDIgPSBwb2ludHNbaV07XG5cblx0XHRcdFx0dmFyIHNxRGlzdCA9IGNsb3Nlc3QocCwgcDEsIHAyLCB0cnVlKTtcblxuXHRcdFx0XHRpZiAoc3FEaXN0IDwgbWluRGlzdGFuY2UpIHtcblx0XHRcdFx0XHRtaW5EaXN0YW5jZSA9IHNxRGlzdDtcblx0XHRcdFx0XHRtaW5Qb2ludCA9IGNsb3Nlc3QocCwgcDEsIHAyKTtcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0XHRpZiAobWluUG9pbnQpIHtcblx0XHRcdG1pblBvaW50LmRpc3RhbmNlID0gTWF0aC5zcXJ0KG1pbkRpc3RhbmNlKTtcblx0XHR9XG5cdFx0cmV0dXJuIG1pblBvaW50O1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgZ2V0Q2VudGVyKCk6IExhdExuZ1xuXHQvLyBSZXR1cm5zIHRoZSBjZW50ZXIgKFtjZW50cm9pZF0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9DZW50cm9pZCkpIG9mIHRoZSBwb2x5bGluZS5cblx0Z2V0Q2VudGVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0Ly8gdGhyb3dzIGVycm9yIHdoZW4gbm90IHlldCBhZGRlZCB0byBtYXAgYXMgdGhpcyBjZW50ZXIgY2FsY3VsYXRpb24gcmVxdWlyZXMgcHJvamVjdGVkIGNvb3JkaW5hdGVzXG5cdFx0aWYgKCF0aGlzLl9tYXApIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignTXVzdCBhZGQgbGF5ZXIgdG8gbWFwIGJlZm9yZSB1c2luZyBnZXRDZW50ZXIoKScpO1xuXHRcdH1cblxuXHRcdHZhciBpLCBoYWxmRGlzdCwgc2VnRGlzdCwgZGlzdCwgcDEsIHAyLCByYXRpbyxcblx0XHQgICAgcG9pbnRzID0gdGhpcy5fcmluZ3NbMF0sXG5cdFx0ICAgIGxlbiA9IHBvaW50cy5sZW5ndGg7XG5cblx0XHRpZiAoIWxlbikgeyByZXR1cm4gbnVsbDsgfVxuXG5cdFx0Ly8gcG9seWxpbmUgY2VudHJvaWQgYWxnb3JpdGhtOyBvbmx5IHVzZXMgdGhlIGZpcnN0IHJpbmcgaWYgdGhlcmUgYXJlIG11bHRpcGxlXG5cblx0XHRmb3IgKGkgPSAwLCBoYWxmRGlzdCA9IDA7IGkgPCBsZW4gLSAxOyBpKyspIHtcblx0XHRcdGhhbGZEaXN0ICs9IHBvaW50c1tpXS5kaXN0YW5jZVRvKHBvaW50c1tpICsgMV0pIC8gMjtcblx0XHR9XG5cblx0XHQvLyBUaGUgbGluZSBpcyBzbyBzbWFsbCBpbiB0aGUgY3VycmVudCB2aWV3IHRoYXQgYWxsIHBvaW50cyBhcmUgb24gdGhlIHNhbWUgcGl4ZWwuXG5cdFx0aWYgKGhhbGZEaXN0ID09PSAwKSB7XG5cdFx0XHRyZXR1cm4gdGhpcy5fbWFwLmxheWVyUG9pbnRUb0xhdExuZyhwb2ludHNbMF0pO1xuXHRcdH1cblxuXHRcdGZvciAoaSA9IDAsIGRpc3QgPSAwOyBpIDwgbGVuIC0gMTsgaSsrKSB7XG5cdFx0XHRwMSA9IHBvaW50c1tpXTtcblx0XHRcdHAyID0gcG9pbnRzW2kgKyAxXTtcblx0XHRcdHNlZ0Rpc3QgPSBwMS5kaXN0YW5jZVRvKHAyKTtcblx0XHRcdGRpc3QgKz0gc2VnRGlzdDtcblxuXHRcdFx0aWYgKGRpc3QgPiBoYWxmRGlzdCkge1xuXHRcdFx0XHRyYXRpbyA9IChkaXN0IC0gaGFsZkRpc3QpIC8gc2VnRGlzdDtcblx0XHRcdFx0cmV0dXJuIHRoaXMuX21hcC5sYXllclBvaW50VG9MYXRMbmcoW1xuXHRcdFx0XHRcdHAyLnggLSByYXRpbyAqIChwMi54IC0gcDEueCksXG5cdFx0XHRcdFx0cDIueSAtIHJhdGlvICogKHAyLnkgLSBwMS55KVxuXHRcdFx0XHRdKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBnZXRCb3VuZHMoKTogTGF0TG5nQm91bmRzXG5cdC8vIFJldHVybnMgdGhlIGBMYXRMbmdCb3VuZHNgIG9mIHRoZSBwYXRoLlxuXHRnZXRCb3VuZHM6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fYm91bmRzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgYWRkTGF0TG5nKGxhdGxuZzogTGF0TG5nLCBsYXRsbmdzPyBMYXRMbmdbXSk6IHRoaXNcblx0Ly8gQWRkcyBhIGdpdmVuIHBvaW50IHRvIHRoZSBwb2x5bGluZS4gQnkgZGVmYXVsdCwgYWRkcyB0byB0aGUgZmlyc3QgcmluZyBvZlxuXHQvLyB0aGUgcG9seWxpbmUgaW4gY2FzZSBvZiBhIG11bHRpLXBvbHlsaW5lLCBidXQgY2FuIGJlIG92ZXJyaWRkZW4gYnkgcGFzc2luZ1xuXHQvLyBhIHNwZWNpZmljIHJpbmcgYXMgYSBMYXRMbmcgYXJyYXkgKHRoYXQgeW91IGNhbiBlYXJsaWVyIGFjY2VzcyB3aXRoIFtgZ2V0TGF0TG5nc2BdKCNwb2x5bGluZS1nZXRsYXRsbmdzKSkuXG5cdGFkZExhdExuZzogZnVuY3Rpb24gKGxhdGxuZywgbGF0bG5ncykge1xuXHRcdGxhdGxuZ3MgPSBsYXRsbmdzIHx8IHRoaXMuX2RlZmF1bHRTaGFwZSgpO1xuXHRcdGxhdGxuZyA9IEwubGF0TG5nKGxhdGxuZyk7XG5cdFx0bGF0bG5ncy5wdXNoKGxhdGxuZyk7XG5cdFx0dGhpcy5fYm91bmRzLmV4dGVuZChsYXRsbmcpO1xuXHRcdHJldHVybiB0aGlzLnJlZHJhdygpO1xuXHR9LFxuXG5cdF9zZXRMYXRMbmdzOiBmdW5jdGlvbiAobGF0bG5ncykge1xuXHRcdHRoaXMuX2JvdW5kcyA9IG5ldyBMLkxhdExuZ0JvdW5kcygpO1xuXHRcdHRoaXMuX2xhdGxuZ3MgPSB0aGlzLl9jb252ZXJ0TGF0TG5ncyhsYXRsbmdzKTtcblx0fSxcblxuXHRfZGVmYXVsdFNoYXBlOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIEwuUG9seWxpbmUuX2ZsYXQodGhpcy5fbGF0bG5ncykgPyB0aGlzLl9sYXRsbmdzIDogdGhpcy5fbGF0bG5nc1swXTtcblx0fSxcblxuXHQvLyByZWN1cnNpdmVseSBjb252ZXJ0IGxhdGxuZ3MgaW5wdXQgaW50byBhY3R1YWwgTGF0TG5nIGluc3RhbmNlczsgY2FsY3VsYXRlIGJvdW5kcyBhbG9uZyB0aGUgd2F5XG5cdF9jb252ZXJ0TGF0TG5nczogZnVuY3Rpb24gKGxhdGxuZ3MpIHtcblx0XHR2YXIgcmVzdWx0ID0gW10sXG5cdFx0ICAgIGZsYXQgPSBMLlBvbHlsaW5lLl9mbGF0KGxhdGxuZ3MpO1xuXG5cdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IGxhdGxuZ3MubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdGlmIChmbGF0KSB7XG5cdFx0XHRcdHJlc3VsdFtpXSA9IEwubGF0TG5nKGxhdGxuZ3NbaV0pO1xuXHRcdFx0XHR0aGlzLl9ib3VuZHMuZXh0ZW5kKHJlc3VsdFtpXSk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRyZXN1bHRbaV0gPSB0aGlzLl9jb252ZXJ0TGF0TG5ncyhsYXRsbmdzW2ldKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRyZXR1cm4gcmVzdWx0O1xuXHR9LFxuXG5cdF9wcm9qZWN0OiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHB4Qm91bmRzID0gbmV3IEwuQm91bmRzKCk7XG5cdFx0dGhpcy5fcmluZ3MgPSBbXTtcblx0XHR0aGlzLl9wcm9qZWN0TGF0bG5ncyh0aGlzLl9sYXRsbmdzLCB0aGlzLl9yaW5ncywgcHhCb3VuZHMpO1xuXG5cdFx0dmFyIHcgPSB0aGlzLl9jbGlja1RvbGVyYW5jZSgpLFxuXHRcdCAgICBwID0gbmV3IEwuUG9pbnQodywgdyk7XG5cblx0XHRpZiAodGhpcy5fYm91bmRzLmlzVmFsaWQoKSAmJiBweEJvdW5kcy5pc1ZhbGlkKCkpIHtcblx0XHRcdHB4Qm91bmRzLm1pbi5fc3VidHJhY3QocCk7XG5cdFx0XHRweEJvdW5kcy5tYXguX2FkZChwKTtcblx0XHRcdHRoaXMuX3B4Qm91bmRzID0gcHhCb3VuZHM7XG5cdFx0fVxuXHR9LFxuXG5cdC8vIHJlY3Vyc2l2ZWx5IHR1cm5zIGxhdGxuZ3MgaW50byBhIHNldCBvZiByaW5ncyB3aXRoIHByb2plY3RlZCBjb29yZGluYXRlc1xuXHRfcHJvamVjdExhdGxuZ3M6IGZ1bmN0aW9uIChsYXRsbmdzLCByZXN1bHQsIHByb2plY3RlZEJvdW5kcykge1xuXHRcdHZhciBmbGF0ID0gbGF0bG5nc1swXSBpbnN0YW5jZW9mIEwuTGF0TG5nLFxuXHRcdCAgICBsZW4gPSBsYXRsbmdzLmxlbmd0aCxcblx0XHQgICAgaSwgcmluZztcblxuXHRcdGlmIChmbGF0KSB7XG5cdFx0XHRyaW5nID0gW107XG5cdFx0XHRmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdFx0cmluZ1tpXSA9IHRoaXMuX21hcC5sYXRMbmdUb0xheWVyUG9pbnQobGF0bG5nc1tpXSk7XG5cdFx0XHRcdHByb2plY3RlZEJvdW5kcy5leHRlbmQocmluZ1tpXSk7XG5cdFx0XHR9XG5cdFx0XHRyZXN1bHQucHVzaChyaW5nKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Zm9yIChpID0gMDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRcdHRoaXMuX3Byb2plY3RMYXRsbmdzKGxhdGxuZ3NbaV0sIHJlc3VsdCwgcHJvamVjdGVkQm91bmRzKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0Ly8gY2xpcCBwb2x5bGluZSBieSByZW5kZXJlciBib3VuZHMgc28gdGhhdCB3ZSBoYXZlIGxlc3MgdG8gcmVuZGVyIGZvciBwZXJmb3JtYW5jZVxuXHRfY2xpcFBvaW50czogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBib3VuZHMgPSB0aGlzLl9yZW5kZXJlci5fYm91bmRzO1xuXG5cdFx0dGhpcy5fcGFydHMgPSBbXTtcblx0XHRpZiAoIXRoaXMuX3B4Qm91bmRzIHx8ICF0aGlzLl9weEJvdW5kcy5pbnRlcnNlY3RzKGJvdW5kcykpIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRpZiAodGhpcy5vcHRpb25zLm5vQ2xpcCkge1xuXHRcdFx0dGhpcy5fcGFydHMgPSB0aGlzLl9yaW5ncztcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHR2YXIgcGFydHMgPSB0aGlzLl9wYXJ0cyxcblx0XHQgICAgaSwgaiwgaywgbGVuLCBsZW4yLCBzZWdtZW50LCBwb2ludHM7XG5cblx0XHRmb3IgKGkgPSAwLCBrID0gMCwgbGVuID0gdGhpcy5fcmluZ3MubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdHBvaW50cyA9IHRoaXMuX3JpbmdzW2ldO1xuXG5cdFx0XHRmb3IgKGogPSAwLCBsZW4yID0gcG9pbnRzLmxlbmd0aDsgaiA8IGxlbjIgLSAxOyBqKyspIHtcblx0XHRcdFx0c2VnbWVudCA9IEwuTGluZVV0aWwuY2xpcFNlZ21lbnQocG9pbnRzW2pdLCBwb2ludHNbaiArIDFdLCBib3VuZHMsIGosIHRydWUpO1xuXG5cdFx0XHRcdGlmICghc2VnbWVudCkgeyBjb250aW51ZTsgfVxuXG5cdFx0XHRcdHBhcnRzW2tdID0gcGFydHNba10gfHwgW107XG5cdFx0XHRcdHBhcnRzW2tdLnB1c2goc2VnbWVudFswXSk7XG5cblx0XHRcdFx0Ly8gaWYgc2VnbWVudCBnb2VzIG91dCBvZiBzY3JlZW4sIG9yIGl0J3MgdGhlIGxhc3Qgb25lLCBpdCdzIHRoZSBlbmQgb2YgdGhlIGxpbmUgcGFydFxuXHRcdFx0XHRpZiAoKHNlZ21lbnRbMV0gIT09IHBvaW50c1tqICsgMV0pIHx8IChqID09PSBsZW4yIC0gMikpIHtcblx0XHRcdFx0XHRwYXJ0c1trXS5wdXNoKHNlZ21lbnRbMV0pO1xuXHRcdFx0XHRcdGsrKztcblx0XHRcdFx0fVxuXHRcdFx0fVxuXHRcdH1cblx0fSxcblxuXHQvLyBzaW1wbGlmeSBlYWNoIGNsaXBwZWQgcGFydCBvZiB0aGUgcG9seWxpbmUgZm9yIHBlcmZvcm1hbmNlXG5cdF9zaW1wbGlmeVBvaW50czogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBwYXJ0cyA9IHRoaXMuX3BhcnRzLFxuXHRcdCAgICB0b2xlcmFuY2UgPSB0aGlzLm9wdGlvbnMuc21vb3RoRmFjdG9yO1xuXG5cdFx0Zm9yICh2YXIgaSA9IDAsIGxlbiA9IHBhcnRzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRwYXJ0c1tpXSA9IEwuTGluZVV0aWwuc2ltcGxpZnkocGFydHNbaV0sIHRvbGVyYW5jZSk7XG5cdFx0fVxuXHR9LFxuXG5cdF91cGRhdGU6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAoIXRoaXMuX21hcCkgeyByZXR1cm47IH1cblxuXHRcdHRoaXMuX2NsaXBQb2ludHMoKTtcblx0XHR0aGlzLl9zaW1wbGlmeVBvaW50cygpO1xuXHRcdHRoaXMuX3VwZGF0ZVBhdGgoKTtcblx0fSxcblxuXHRfdXBkYXRlUGF0aDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3JlbmRlcmVyLl91cGRhdGVQb2x5KHRoaXMpO1xuXHR9XG59KTtcblxuLy8gQGZhY3RvcnkgTC5wb2x5bGluZShsYXRsbmdzOiBMYXRMbmdbXSwgb3B0aW9ucz86IFBvbHlsaW5lIG9wdGlvbnMpXG4vLyBJbnN0YW50aWF0ZXMgYSBwb2x5bGluZSBvYmplY3QgZ2l2ZW4gYW4gYXJyYXkgb2YgZ2VvZ3JhcGhpY2FsIHBvaW50cyBhbmRcbi8vIG9wdGlvbmFsbHkgYW4gb3B0aW9ucyBvYmplY3QuIFlvdSBjYW4gY3JlYXRlIGEgYFBvbHlsaW5lYCBvYmplY3Qgd2l0aFxuLy8gbXVsdGlwbGUgc2VwYXJhdGUgbGluZXMgKGBNdWx0aVBvbHlsaW5lYCkgYnkgcGFzc2luZyBhbiBhcnJheSBvZiBhcnJheXNcbi8vIG9mIGdlb2dyYXBoaWMgcG9pbnRzLlxuTC5wb2x5bGluZSA9IGZ1bmN0aW9uIChsYXRsbmdzLCBvcHRpb25zKSB7XG5cdHJldHVybiBuZXcgTC5Qb2x5bGluZShsYXRsbmdzLCBvcHRpb25zKTtcbn07XG5cbkwuUG9seWxpbmUuX2ZsYXQgPSBmdW5jdGlvbiAobGF0bG5ncykge1xuXHQvLyB0cnVlIGlmIGl0J3MgYSBmbGF0IGFycmF5IG9mIGxhdGxuZ3M7IGZhbHNlIGlmIG5lc3RlZFxuXHRyZXR1cm4gIUwuVXRpbC5pc0FycmF5KGxhdGxuZ3NbMF0pIHx8ICh0eXBlb2YgbGF0bG5nc1swXVswXSAhPT0gJ29iamVjdCcgJiYgdHlwZW9mIGxhdGxuZ3NbMF1bMF0gIT09ICd1bmRlZmluZWQnKTtcbn07XG5cblxuXG4vKlxyXG4gKiBAbmFtZXNwYWNlIFBvbHlVdGlsXHJcbiAqIFZhcmlvdXMgdXRpbGl0eSBmdW5jdGlvbnMgZm9yIHBvbHlnb24gZ2VvbWV0cmllcy5cclxuICovXHJcblxyXG5MLlBvbHlVdGlsID0ge307XHJcblxyXG4vKiBAZnVuY3Rpb24gY2xpcFBvbHlnb24ocG9pbnRzOiBQb2ludFtdLCBib3VuZHM6IEJvdW5kcywgcm91bmQ/OiBCb29sZWFuKTogUG9pbnRbXVxyXG4gKiBDbGlwcyB0aGUgcG9seWdvbiBnZW9tZXRyeSBkZWZpbmVkIGJ5IHRoZSBnaXZlbiBgcG9pbnRzYCBieSB0aGUgZ2l2ZW4gYm91bmRzICh1c2luZyB0aGUgW1N1dGhlcmxhbmQtSG9kZ2VtYW4gYWxnb3JpdGhtXShodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9TdXRoZXJsYW5kJUUyJTgwJTkzSG9kZ21hbl9hbGdvcml0aG0pKS5cclxuICogVXNlZCBieSBMZWFmbGV0IHRvIG9ubHkgc2hvdyBwb2x5Z29uIHBvaW50cyB0aGF0IGFyZSBvbiB0aGUgc2NyZWVuIG9yIG5lYXIsIGluY3JlYXNpbmdcclxuICogcGVyZm9ybWFuY2UuIE5vdGUgdGhhdCBwb2x5Z29uIHBvaW50cyBuZWVkcyBkaWZmZXJlbnQgYWxnb3JpdGhtIGZvciBjbGlwcGluZ1xyXG4gKiB0aGFuIHBvbHlsaW5lLCBzbyB0aGVyZSdzIGEgc2VwZXJhdGUgbWV0aG9kIGZvciBpdC5cclxuICovXHJcbkwuUG9seVV0aWwuY2xpcFBvbHlnb24gPSBmdW5jdGlvbiAocG9pbnRzLCBib3VuZHMsIHJvdW5kKSB7XHJcblx0dmFyIGNsaXBwZWRQb2ludHMsXHJcblx0ICAgIGVkZ2VzID0gWzEsIDQsIDIsIDhdLFxyXG5cdCAgICBpLCBqLCBrLFxyXG5cdCAgICBhLCBiLFxyXG5cdCAgICBsZW4sIGVkZ2UsIHAsXHJcblx0ICAgIGx1ID0gTC5MaW5lVXRpbDtcclxuXHJcblx0Zm9yIChpID0gMCwgbGVuID0gcG9pbnRzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRwb2ludHNbaV0uX2NvZGUgPSBsdS5fZ2V0Qml0Q29kZShwb2ludHNbaV0sIGJvdW5kcyk7XHJcblx0fVxyXG5cclxuXHQvLyBmb3IgZWFjaCBlZGdlIChsZWZ0LCBib3R0b20sIHJpZ2h0LCB0b3ApXHJcblx0Zm9yIChrID0gMDsgayA8IDQ7IGsrKykge1xyXG5cdFx0ZWRnZSA9IGVkZ2VzW2tdO1xyXG5cdFx0Y2xpcHBlZFBvaW50cyA9IFtdO1xyXG5cclxuXHRcdGZvciAoaSA9IDAsIGxlbiA9IHBvaW50cy5sZW5ndGgsIGogPSBsZW4gLSAxOyBpIDwgbGVuOyBqID0gaSsrKSB7XHJcblx0XHRcdGEgPSBwb2ludHNbaV07XHJcblx0XHRcdGIgPSBwb2ludHNbal07XHJcblxyXG5cdFx0XHQvLyBpZiBhIGlzIGluc2lkZSB0aGUgY2xpcCB3aW5kb3dcclxuXHRcdFx0aWYgKCEoYS5fY29kZSAmIGVkZ2UpKSB7XHJcblx0XHRcdFx0Ly8gaWYgYiBpcyBvdXRzaWRlIHRoZSBjbGlwIHdpbmRvdyAoYS0+YiBnb2VzIG91dCBvZiBzY3JlZW4pXHJcblx0XHRcdFx0aWYgKGIuX2NvZGUgJiBlZGdlKSB7XHJcblx0XHRcdFx0XHRwID0gbHUuX2dldEVkZ2VJbnRlcnNlY3Rpb24oYiwgYSwgZWRnZSwgYm91bmRzLCByb3VuZCk7XHJcblx0XHRcdFx0XHRwLl9jb2RlID0gbHUuX2dldEJpdENvZGUocCwgYm91bmRzKTtcclxuXHRcdFx0XHRcdGNsaXBwZWRQb2ludHMucHVzaChwKTtcclxuXHRcdFx0XHR9XHJcblx0XHRcdFx0Y2xpcHBlZFBvaW50cy5wdXNoKGEpO1xyXG5cclxuXHRcdFx0Ly8gZWxzZSBpZiBiIGlzIGluc2lkZSB0aGUgY2xpcCB3aW5kb3cgKGEtPmIgZW50ZXJzIHRoZSBzY3JlZW4pXHJcblx0XHRcdH0gZWxzZSBpZiAoIShiLl9jb2RlICYgZWRnZSkpIHtcclxuXHRcdFx0XHRwID0gbHUuX2dldEVkZ2VJbnRlcnNlY3Rpb24oYiwgYSwgZWRnZSwgYm91bmRzLCByb3VuZCk7XHJcblx0XHRcdFx0cC5fY29kZSA9IGx1Ll9nZXRCaXRDb2RlKHAsIGJvdW5kcyk7XHJcblx0XHRcdFx0Y2xpcHBlZFBvaW50cy5wdXNoKHApO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0XHRwb2ludHMgPSBjbGlwcGVkUG9pbnRzO1xyXG5cdH1cclxuXHJcblx0cmV0dXJuIHBvaW50cztcclxufTtcclxuXG5cblxuLypcbiAqIEBjbGFzcyBQb2x5Z29uXG4gKiBAYWthIEwuUG9seWdvblxuICogQGluaGVyaXRzIFBvbHlsaW5lXG4gKlxuICogQSBjbGFzcyBmb3IgZHJhd2luZyBwb2x5Z29uIG92ZXJsYXlzIG9uIGEgbWFwLiBFeHRlbmRzIGBQb2x5bGluZWAuXG4gKlxuICogTm90ZSB0aGF0IHBvaW50cyB5b3UgcGFzcyB3aGVuIGNyZWF0aW5nIGEgcG9seWdvbiBzaG91bGRuJ3QgaGF2ZSBhbiBhZGRpdGlvbmFsIGxhc3QgcG9pbnQgZXF1YWwgdG8gdGhlIGZpcnN0IG9uZSDigJQgaXQncyBiZXR0ZXIgdG8gZmlsdGVyIG91dCBzdWNoIHBvaW50cy5cbiAqXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBgYGBqc1xuICogLy8gY3JlYXRlIGEgcmVkIHBvbHlnb24gZnJvbSBhbiBhcnJheSBvZiBMYXRMbmcgcG9pbnRzXG4gKiB2YXIgbGF0bG5ncyA9IFtbLTExMS4wMywgNDFdLFstMTExLjA0LCA0NV0sWy0xMDQuMDUsIDQ1XSxbLTEwNC4wNSwgNDFdXTtcbiAqXG4gKiB2YXIgcG9seWdvbiA9IEwucG9seWdvbihsYXRsbmdzLCB7Y29sb3I6ICdyZWQnfSkuYWRkVG8obWFwKTtcbiAqXG4gKiAvLyB6b29tIHRoZSBtYXAgdG8gdGhlIHBvbHlnb25cbiAqIG1hcC5maXRCb3VuZHMocG9seWdvbi5nZXRCb3VuZHMoKSk7XG4gKiBgYGBcbiAqXG4gKiBZb3UgY2FuIGFsc28gcGFzcyBhbiBhcnJheSBvZiBhcnJheXMgb2YgbGF0bG5ncywgd2l0aCB0aGUgZmlyc3QgYXJyYXkgcmVwcmVzZW50aW5nIHRoZSBvdXRlciBzaGFwZSBhbmQgdGhlIG90aGVyIGFycmF5cyByZXByZXNlbnRpbmcgaG9sZXMgaW4gdGhlIG91dGVyIHNoYXBlOlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgbGF0bG5ncyA9IFtcbiAqICAgW1stMTExLjAzLCA0MV0sWy0xMTEuMDQsIDQ1XSxbLTEwNC4wNSwgNDVdLFstMTA0LjA1LCA0MV1dLCAvLyBvdXRlciByaW5nXG4gKiAgIFtbLTEwOC41OCwzNy4yOV0sWy0xMDguNTgsNDAuNzFdLFstMTAyLjUwLDQwLjcxXSxbLTEwMi41MCwzNy4yOV1dIC8vIGhvbGVcbiAqIF07XG4gKiBgYGBcbiAqXG4gKiBBZGRpdGlvbmFsbHksIHlvdSBjYW4gcGFzcyBhIG11bHRpLWRpbWVuc2lvbmFsIGFycmF5IHRvIHJlcHJlc2VudCBhIE11bHRpUG9seWdvbiBzaGFwZS5cbiAqXG4gKiBgYGBqc1xuICogdmFyIGxhdGxuZ3MgPSBbXG4gKiAgIFsgLy8gZmlyc3QgcG9seWdvblxuICogICAgIFtbLTExMS4wMywgNDFdLFstMTExLjA0LCA0NV0sWy0xMDQuMDUsIDQ1XSxbLTEwNC4wNSwgNDFdXSwgLy8gb3V0ZXIgcmluZ1xuICogICAgIFtbLTEwOC41OCwzNy4yOV0sWy0xMDguNTgsNDAuNzFdLFstMTAyLjUwLDQwLjcxXSxbLTEwMi41MCwzNy4yOV1dIC8vIGhvbGVcbiAqICAgXSxcbiAqICAgWyAvLyBzZWNvbmQgcG9seWdvblxuICogICAgIFtbLTEwOS4wNSwgMzddLFstMTA5LjAzLCA0MV0sWy0xMDIuMDUsIDQxXSxbLTEwMi4wNCwgMzddLFstMTA5LjA1LCAzOF1dXG4gKiAgIF1cbiAqIF07XG4gKiBgYGBcbiAqL1xuXG5MLlBvbHlnb24gPSBMLlBvbHlsaW5lLmV4dGVuZCh7XG5cblx0b3B0aW9uczoge1xuXHRcdGZpbGw6IHRydWVcblx0fSxcblxuXHRpc0VtcHR5OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuICF0aGlzLl9sYXRsbmdzLmxlbmd0aCB8fCAhdGhpcy5fbGF0bG5nc1swXS5sZW5ndGg7XG5cdH0sXG5cblx0Z2V0Q2VudGVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0Ly8gdGhyb3dzIGVycm9yIHdoZW4gbm90IHlldCBhZGRlZCB0byBtYXAgYXMgdGhpcyBjZW50ZXIgY2FsY3VsYXRpb24gcmVxdWlyZXMgcHJvamVjdGVkIGNvb3JkaW5hdGVzXG5cdFx0aWYgKCF0aGlzLl9tYXApIHtcblx0XHRcdHRocm93IG5ldyBFcnJvcignTXVzdCBhZGQgbGF5ZXIgdG8gbWFwIGJlZm9yZSB1c2luZyBnZXRDZW50ZXIoKScpO1xuXHRcdH1cblxuXHRcdHZhciBpLCBqLCBwMSwgcDIsIGYsIGFyZWEsIHgsIHksIGNlbnRlcixcblx0XHQgICAgcG9pbnRzID0gdGhpcy5fcmluZ3NbMF0sXG5cdFx0ICAgIGxlbiA9IHBvaW50cy5sZW5ndGg7XG5cblx0XHRpZiAoIWxlbikgeyByZXR1cm4gbnVsbDsgfVxuXG5cdFx0Ly8gcG9seWdvbiBjZW50cm9pZCBhbGdvcml0aG07IG9ubHkgdXNlcyB0aGUgZmlyc3QgcmluZyBpZiB0aGVyZSBhcmUgbXVsdGlwbGVcblxuXHRcdGFyZWEgPSB4ID0geSA9IDA7XG5cblx0XHRmb3IgKGkgPSAwLCBqID0gbGVuIC0gMTsgaSA8IGxlbjsgaiA9IGkrKykge1xuXHRcdFx0cDEgPSBwb2ludHNbaV07XG5cdFx0XHRwMiA9IHBvaW50c1tqXTtcblxuXHRcdFx0ZiA9IHAxLnkgKiBwMi54IC0gcDIueSAqIHAxLng7XG5cdFx0XHR4ICs9IChwMS54ICsgcDIueCkgKiBmO1xuXHRcdFx0eSArPSAocDEueSArIHAyLnkpICogZjtcblx0XHRcdGFyZWEgKz0gZiAqIDM7XG5cdFx0fVxuXG5cdFx0aWYgKGFyZWEgPT09IDApIHtcblx0XHRcdC8vIFBvbHlnb24gaXMgc28gc21hbGwgdGhhdCBhbGwgcG9pbnRzIGFyZSBvbiBzYW1lIHBpeGVsLlxuXHRcdFx0Y2VudGVyID0gcG9pbnRzWzBdO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHRjZW50ZXIgPSBbeCAvIGFyZWEsIHkgLyBhcmVhXTtcblx0XHR9XG5cdFx0cmV0dXJuIHRoaXMuX21hcC5sYXllclBvaW50VG9MYXRMbmcoY2VudGVyKTtcblx0fSxcblxuXHRfY29udmVydExhdExuZ3M6IGZ1bmN0aW9uIChsYXRsbmdzKSB7XG5cdFx0dmFyIHJlc3VsdCA9IEwuUG9seWxpbmUucHJvdG90eXBlLl9jb252ZXJ0TGF0TG5ncy5jYWxsKHRoaXMsIGxhdGxuZ3MpLFxuXHRcdCAgICBsZW4gPSByZXN1bHQubGVuZ3RoO1xuXG5cdFx0Ly8gcmVtb3ZlIGxhc3QgcG9pbnQgaWYgaXQgZXF1YWxzIGZpcnN0IG9uZVxuXHRcdGlmIChsZW4gPj0gMiAmJiByZXN1bHRbMF0gaW5zdGFuY2VvZiBMLkxhdExuZyAmJiByZXN1bHRbMF0uZXF1YWxzKHJlc3VsdFtsZW4gLSAxXSkpIHtcblx0XHRcdHJlc3VsdC5wb3AoKTtcblx0XHR9XG5cdFx0cmV0dXJuIHJlc3VsdDtcblx0fSxcblxuXHRfc2V0TGF0TG5nczogZnVuY3Rpb24gKGxhdGxuZ3MpIHtcblx0XHRMLlBvbHlsaW5lLnByb3RvdHlwZS5fc2V0TGF0TG5ncy5jYWxsKHRoaXMsIGxhdGxuZ3MpO1xuXHRcdGlmIChMLlBvbHlsaW5lLl9mbGF0KHRoaXMuX2xhdGxuZ3MpKSB7XG5cdFx0XHR0aGlzLl9sYXRsbmdzID0gW3RoaXMuX2xhdGxuZ3NdO1xuXHRcdH1cblx0fSxcblxuXHRfZGVmYXVsdFNoYXBlOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIEwuUG9seWxpbmUuX2ZsYXQodGhpcy5fbGF0bG5nc1swXSkgPyB0aGlzLl9sYXRsbmdzWzBdIDogdGhpcy5fbGF0bG5nc1swXVswXTtcblx0fSxcblxuXHRfY2xpcFBvaW50czogZnVuY3Rpb24gKCkge1xuXHRcdC8vIHBvbHlnb25zIG5lZWQgYSBkaWZmZXJlbnQgY2xpcHBpbmcgYWxnb3JpdGhtIHNvIHdlIHJlZGVmaW5lIHRoYXRcblxuXHRcdHZhciBib3VuZHMgPSB0aGlzLl9yZW5kZXJlci5fYm91bmRzLFxuXHRcdCAgICB3ID0gdGhpcy5vcHRpb25zLndlaWdodCxcblx0XHQgICAgcCA9IG5ldyBMLlBvaW50KHcsIHcpO1xuXG5cdFx0Ly8gaW5jcmVhc2UgY2xpcCBwYWRkaW5nIGJ5IHN0cm9rZSB3aWR0aCB0byBhdm9pZCBzdHJva2Ugb24gY2xpcCBlZGdlc1xuXHRcdGJvdW5kcyA9IG5ldyBMLkJvdW5kcyhib3VuZHMubWluLnN1YnRyYWN0KHApLCBib3VuZHMubWF4LmFkZChwKSk7XG5cblx0XHR0aGlzLl9wYXJ0cyA9IFtdO1xuXHRcdGlmICghdGhpcy5fcHhCb3VuZHMgfHwgIXRoaXMuX3B4Qm91bmRzLmludGVyc2VjdHMoYm91bmRzKSkge1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGlmICh0aGlzLm9wdGlvbnMubm9DbGlwKSB7XG5cdFx0XHR0aGlzLl9wYXJ0cyA9IHRoaXMuX3JpbmdzO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSB0aGlzLl9yaW5ncy5sZW5ndGgsIGNsaXBwZWQ7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0Y2xpcHBlZCA9IEwuUG9seVV0aWwuY2xpcFBvbHlnb24odGhpcy5fcmluZ3NbaV0sIGJvdW5kcywgdHJ1ZSk7XG5cdFx0XHRpZiAoY2xpcHBlZC5sZW5ndGgpIHtcblx0XHRcdFx0dGhpcy5fcGFydHMucHVzaChjbGlwcGVkKTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZVBhdGg6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9yZW5kZXJlci5fdXBkYXRlUG9seSh0aGlzLCB0cnVlKTtcblx0fVxufSk7XG5cblxuLy8gQGZhY3RvcnkgTC5wb2x5Z29uKGxhdGxuZ3M6IExhdExuZ1tdLCBvcHRpb25zPzogUG9seWxpbmUgb3B0aW9ucylcbkwucG9seWdvbiA9IGZ1bmN0aW9uIChsYXRsbmdzLCBvcHRpb25zKSB7XG5cdHJldHVybiBuZXcgTC5Qb2x5Z29uKGxhdGxuZ3MsIG9wdGlvbnMpO1xufTtcblxuXG5cbi8qXG4gKiBMLlJlY3RhbmdsZSBleHRlbmRzIFBvbHlnb24gYW5kIGNyZWF0ZXMgYSByZWN0YW5nbGUgd2hlbiBwYXNzZWQgYSBMYXRMbmdCb3VuZHMgb2JqZWN0LlxuICovXG5cbi8qXG4gKiBAY2xhc3MgUmVjdGFuZ2xlXG4gKiBAYWthIEwuUmV0YW5nbGVcbiAqIEBpbmhlcml0cyBQb2x5Z29uXG4gKlxuICogQSBjbGFzcyBmb3IgZHJhd2luZyByZWN0YW5nbGUgb3ZlcmxheXMgb24gYSBtYXAuIEV4dGVuZHMgYFBvbHlnb25gLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogYGBganNcbiAqIC8vIGRlZmluZSByZWN0YW5nbGUgZ2VvZ3JhcGhpY2FsIGJvdW5kc1xuICogdmFyIGJvdW5kcyA9IFtbNTQuNTU5MzIyLCAtNS43Njc4MjJdLCBbNTYuMTIxMDYwNCwgLTMuMDIxMjQwXV07XG4gKlxuICogLy8gY3JlYXRlIGFuIG9yYW5nZSByZWN0YW5nbGVcbiAqIEwucmVjdGFuZ2xlKGJvdW5kcywge2NvbG9yOiBcIiNmZjc4MDBcIiwgd2VpZ2h0OiAxfSkuYWRkVG8obWFwKTtcbiAqXG4gKiAvLyB6b29tIHRoZSBtYXAgdG8gdGhlIHJlY3RhbmdsZSBib3VuZHNcbiAqIG1hcC5maXRCb3VuZHMoYm91bmRzKTtcbiAqIGBgYFxuICpcbiAqL1xuXG5cbkwuUmVjdGFuZ2xlID0gTC5Qb2x5Z29uLmV4dGVuZCh7XG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChsYXRMbmdCb3VuZHMsIG9wdGlvbnMpIHtcblx0XHRMLlBvbHlnb24ucHJvdG90eXBlLmluaXRpYWxpemUuY2FsbCh0aGlzLCB0aGlzLl9ib3VuZHNUb0xhdExuZ3MobGF0TG5nQm91bmRzKSwgb3B0aW9ucyk7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRCb3VuZHMobGF0TG5nQm91bmRzOiBMYXRMbmdCb3VuZHMpOiB0aGlzXG5cdC8vIFJlZHJhd3MgdGhlIHJlY3RhbmdsZSB3aXRoIHRoZSBwYXNzZWQgYm91bmRzLlxuXHRzZXRCb3VuZHM6IGZ1bmN0aW9uIChsYXRMbmdCb3VuZHMpIHtcblx0XHRyZXR1cm4gdGhpcy5zZXRMYXRMbmdzKHRoaXMuX2JvdW5kc1RvTGF0TG5ncyhsYXRMbmdCb3VuZHMpKTtcblx0fSxcblxuXHRfYm91bmRzVG9MYXRMbmdzOiBmdW5jdGlvbiAobGF0TG5nQm91bmRzKSB7XG5cdFx0bGF0TG5nQm91bmRzID0gTC5sYXRMbmdCb3VuZHMobGF0TG5nQm91bmRzKTtcblx0XHRyZXR1cm4gW1xuXHRcdFx0bGF0TG5nQm91bmRzLmdldFNvdXRoV2VzdCgpLFxuXHRcdFx0bGF0TG5nQm91bmRzLmdldE5vcnRoV2VzdCgpLFxuXHRcdFx0bGF0TG5nQm91bmRzLmdldE5vcnRoRWFzdCgpLFxuXHRcdFx0bGF0TG5nQm91bmRzLmdldFNvdXRoRWFzdCgpXG5cdFx0XTtcblx0fVxufSk7XG5cblxuLy8gQGZhY3RvcnkgTC5yZWN0YW5nbGUobGF0TG5nQm91bmRzOiBMYXRMbmdCb3VuZHMsIG9wdGlvbnM/OiBQb2x5bGluZSBvcHRpb25zKVxuTC5yZWN0YW5nbGUgPSBmdW5jdGlvbiAobGF0TG5nQm91bmRzLCBvcHRpb25zKSB7XG5cdHJldHVybiBuZXcgTC5SZWN0YW5nbGUobGF0TG5nQm91bmRzLCBvcHRpb25zKTtcbn07XG5cblxuXG4vKlxuICogQGNsYXNzIENpcmNsZU1hcmtlclxuICogQGFrYSBMLkNpcmNsZU1hcmtlclxuICogQGluaGVyaXRzIFBhdGhcbiAqXG4gKiBBIGNpcmNsZSBvZiBhIGZpeGVkIHNpemUgd2l0aCByYWRpdXMgc3BlY2lmaWVkIGluIHBpeGVscy4gRXh0ZW5kcyBgUGF0aGAuXG4gKi9cblxuTC5DaXJjbGVNYXJrZXIgPSBMLlBhdGguZXh0ZW5kKHtcblxuXHQvLyBAc2VjdGlvblxuXHQvLyBAYWthIENpcmNsZU1hcmtlciBvcHRpb25zXG5cdG9wdGlvbnM6IHtcblx0XHRmaWxsOiB0cnVlLFxuXG5cdFx0Ly8gQG9wdGlvbiByYWRpdXM6IE51bWJlciA9IDEwXG5cdFx0Ly8gUmFkaXVzIG9mIHRoZSBjaXJjbGUgbWFya2VyLCBpbiBwaXhlbHNcblx0XHRyYWRpdXM6IDEwXG5cdH0sXG5cblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGxhdGxuZywgb3B0aW9ucykge1xuXHRcdEwuc2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcblx0XHR0aGlzLl9sYXRsbmcgPSBMLmxhdExuZyhsYXRsbmcpO1xuXHRcdHRoaXMuX3JhZGl1cyA9IHRoaXMub3B0aW9ucy5yYWRpdXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRMYXRMbmcobGF0TG5nOiBMYXRMbmcpOiB0aGlzXG5cdC8vIFNldHMgdGhlIHBvc2l0aW9uIG9mIGEgY2lyY2xlIG1hcmtlciB0byBhIG5ldyBsb2NhdGlvbi5cblx0c2V0TGF0TG5nOiBmdW5jdGlvbiAobGF0bG5nKSB7XG5cdFx0dGhpcy5fbGF0bG5nID0gTC5sYXRMbmcobGF0bG5nKTtcblx0XHR0aGlzLnJlZHJhdygpO1xuXHRcdHJldHVybiB0aGlzLmZpcmUoJ21vdmUnLCB7bGF0bG5nOiB0aGlzLl9sYXRsbmd9KTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIGdldExhdExuZygpOiBMYXRMbmdcblx0Ly8gUmV0dXJucyB0aGUgY3VycmVudCBnZW9ncmFwaGljYWwgcG9zaXRpb24gb2YgdGhlIGNpcmNsZSBtYXJrZXJcblx0Z2V0TGF0TG5nOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2xhdGxuZztcblx0fSxcblxuXHQvLyBAbWV0aG9kIHNldFJhZGl1cyhyYWRpdXM6IE51bWJlcik6IHRoaXNcblx0Ly8gU2V0cyB0aGUgcmFkaXVzIG9mIGEgY2lyY2xlIG1hcmtlci4gVW5pdHMgYXJlIGluIHBpeGVscy5cblx0c2V0UmFkaXVzOiBmdW5jdGlvbiAocmFkaXVzKSB7XG5cdFx0dGhpcy5vcHRpb25zLnJhZGl1cyA9IHRoaXMuX3JhZGl1cyA9IHJhZGl1cztcblx0XHRyZXR1cm4gdGhpcy5yZWRyYXcoKTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIGdldFJhZGl1cygpOiBOdW1iZXJcblx0Ly8gUmV0dXJucyB0aGUgY3VycmVudCByYWRpdXMgb2YgdGhlIGNpcmNsZVxuXHRnZXRSYWRpdXM6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fcmFkaXVzO1xuXHR9LFxuXG5cdHNldFN0eWxlIDogZnVuY3Rpb24gKG9wdGlvbnMpIHtcblx0XHR2YXIgcmFkaXVzID0gb3B0aW9ucyAmJiBvcHRpb25zLnJhZGl1cyB8fCB0aGlzLl9yYWRpdXM7XG5cdFx0TC5QYXRoLnByb3RvdHlwZS5zZXRTdHlsZS5jYWxsKHRoaXMsIG9wdGlvbnMpO1xuXHRcdHRoaXMuc2V0UmFkaXVzKHJhZGl1cyk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X3Byb2plY3Q6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9wb2ludCA9IHRoaXMuX21hcC5sYXRMbmdUb0xheWVyUG9pbnQodGhpcy5fbGF0bG5nKTtcblx0XHR0aGlzLl91cGRhdGVCb3VuZHMoKTtcblx0fSxcblxuXHRfdXBkYXRlQm91bmRzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIHIgPSB0aGlzLl9yYWRpdXMsXG5cdFx0ICAgIHIyID0gdGhpcy5fcmFkaXVzWSB8fCByLFxuXHRcdCAgICB3ID0gdGhpcy5fY2xpY2tUb2xlcmFuY2UoKSxcblx0XHQgICAgcCA9IFtyICsgdywgcjIgKyB3XTtcblx0XHR0aGlzLl9weEJvdW5kcyA9IG5ldyBMLkJvdW5kcyh0aGlzLl9wb2ludC5zdWJ0cmFjdChwKSwgdGhpcy5fcG9pbnQuYWRkKHApKTtcblx0fSxcblxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21hcCkge1xuXHRcdFx0dGhpcy5fdXBkYXRlUGF0aCgpO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlUGF0aDogZnVuY3Rpb24gKCkge1xuXHRcdHRoaXMuX3JlbmRlcmVyLl91cGRhdGVDaXJjbGUodGhpcyk7XG5cdH0sXG5cblx0X2VtcHR5OiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX3JhZGl1cyAmJiAhdGhpcy5fcmVuZGVyZXIuX2JvdW5kcy5pbnRlcnNlY3RzKHRoaXMuX3B4Qm91bmRzKTtcblx0fVxufSk7XG5cblxuLy8gQGZhY3RvcnkgTC5jaXJjbGVNYXJrZXIobGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/OiBDaXJjbGVNYXJrZXIgb3B0aW9ucylcbi8vIEluc3RhbnRpYXRlcyBhIGNpcmNsZSBtYXJrZXIgb2JqZWN0IGdpdmVuIGEgZ2VvZ3JhcGhpY2FsIHBvaW50LCBhbmQgYW4gb3B0aW9uYWwgb3B0aW9ucyBvYmplY3QuXG5MLmNpcmNsZU1hcmtlciA9IGZ1bmN0aW9uIChsYXRsbmcsIG9wdGlvbnMpIHtcblx0cmV0dXJuIG5ldyBMLkNpcmNsZU1hcmtlcihsYXRsbmcsIG9wdGlvbnMpO1xufTtcblxuXG5cbi8qXG4gKiBAY2xhc3MgQ2lyY2xlXG4gKiBAYWthIEwuQ2lyY2xlXG4gKiBAaW5oZXJpdHMgQ2lyY2xlTWFya2VyXG4gKlxuICogQSBjbGFzcyBmb3IgZHJhd2luZyBjaXJjbGUgb3ZlcmxheXMgb24gYSBtYXAuIEV4dGVuZHMgYENpcmNsZU1hcmtlcmAuXG4gKlxuICogSXQncyBhbiBhcHByb3hpbWF0aW9uIGFuZCBzdGFydHMgdG8gZGl2ZXJnZSBmcm9tIGEgcmVhbCBjaXJjbGUgY2xvc2VyIHRvIHBvbGVzIChkdWUgdG8gcHJvamVjdGlvbiBkaXN0b3J0aW9uKS5cbiAqXG4gKiBAZXhhbXBsZVxuICpcbiAqIGBgYGpzXG4gKiBMLmNpcmNsZShbNTAuNSwgMzAuNV0sIHtyYWRpdXM6IDIwMH0pLmFkZFRvKG1hcCk7XG4gKiBgYGBcbiAqL1xuXG5MLkNpcmNsZSA9IEwuQ2lyY2xlTWFya2VyLmV4dGVuZCh7XG5cblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGxhdGxuZywgb3B0aW9ucywgbGVnYWN5T3B0aW9ucykge1xuXHRcdGlmICh0eXBlb2Ygb3B0aW9ucyA9PT0gJ251bWJlcicpIHtcblx0XHRcdC8vIEJhY2t3YXJkcyBjb21wYXRpYmlsaXR5IHdpdGggMC43LnggZmFjdG9yeSAobGF0bG5nLCByYWRpdXMsIG9wdGlvbnM/KVxuXHRcdFx0b3B0aW9ucyA9IEwuZXh0ZW5kKHt9LCBsZWdhY3lPcHRpb25zLCB7cmFkaXVzOiBvcHRpb25zfSk7XG5cdFx0fVxuXHRcdEwuc2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcblx0XHR0aGlzLl9sYXRsbmcgPSBMLmxhdExuZyhsYXRsbmcpO1xuXG5cdFx0aWYgKGlzTmFOKHRoaXMub3B0aW9ucy5yYWRpdXMpKSB7IHRocm93IG5ldyBFcnJvcignQ2lyY2xlIHJhZGl1cyBjYW5ub3QgYmUgTmFOJyk7IH1cblxuXHRcdC8vIEBzZWN0aW9uXG5cdFx0Ly8gQGFrYSBDaXJjbGUgb3B0aW9uc1xuXHRcdC8vIEBvcHRpb24gcmFkaXVzOiBOdW1iZXI7IFJhZGl1cyBvZiB0aGUgY2lyY2xlLCBpbiBtZXRlcnMuXG5cdFx0dGhpcy5fbVJhZGl1cyA9IHRoaXMub3B0aW9ucy5yYWRpdXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBzZXRSYWRpdXMocmFkaXVzOiBOdW1iZXIpOiB0aGlzXG5cdC8vIFNldHMgdGhlIHJhZGl1cyBvZiBhIGNpcmNsZS4gVW5pdHMgYXJlIGluIG1ldGVycy5cblx0c2V0UmFkaXVzOiBmdW5jdGlvbiAocmFkaXVzKSB7XG5cdFx0dGhpcy5fbVJhZGl1cyA9IHJhZGl1cztcblx0XHRyZXR1cm4gdGhpcy5yZWRyYXcoKTtcblx0fSxcblxuXHQvLyBAbWV0aG9kIGdldFJhZGl1cygpOiBOdW1iZXJcblx0Ly8gUmV0dXJucyB0aGUgY3VycmVudCByYWRpdXMgb2YgYSBjaXJjbGUuIFVuaXRzIGFyZSBpbiBtZXRlcnMuXG5cdGdldFJhZGl1czogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLl9tUmFkaXVzO1xuXHR9LFxuXG5cdC8vIEBtZXRob2QgZ2V0Qm91bmRzKCk6IExhdExuZ0JvdW5kc1xuXHQvLyBSZXR1cm5zIHRoZSBgTGF0TG5nQm91bmRzYCBvZiB0aGUgcGF0aC5cblx0Z2V0Qm91bmRzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGhhbGYgPSBbdGhpcy5fcmFkaXVzLCB0aGlzLl9yYWRpdXNZIHx8IHRoaXMuX3JhZGl1c107XG5cblx0XHRyZXR1cm4gbmV3IEwuTGF0TG5nQm91bmRzKFxuXHRcdFx0dGhpcy5fbWFwLmxheWVyUG9pbnRUb0xhdExuZyh0aGlzLl9wb2ludC5zdWJ0cmFjdChoYWxmKSksXG5cdFx0XHR0aGlzLl9tYXAubGF5ZXJQb2ludFRvTGF0TG5nKHRoaXMuX3BvaW50LmFkZChoYWxmKSkpO1xuXHR9LFxuXG5cdHNldFN0eWxlOiBMLlBhdGgucHJvdG90eXBlLnNldFN0eWxlLFxuXG5cdF9wcm9qZWN0OiBmdW5jdGlvbiAoKSB7XG5cblx0XHR2YXIgbG5nID0gdGhpcy5fbGF0bG5nLmxuZyxcblx0XHQgICAgbGF0ID0gdGhpcy5fbGF0bG5nLmxhdCxcblx0XHQgICAgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBjcnMgPSBtYXAub3B0aW9ucy5jcnM7XG5cblx0XHRpZiAoY3JzLmRpc3RhbmNlID09PSBMLkNSUy5FYXJ0aC5kaXN0YW5jZSkge1xuXHRcdFx0dmFyIGQgPSBNYXRoLlBJIC8gMTgwLFxuXHRcdFx0ICAgIGxhdFIgPSAodGhpcy5fbVJhZGl1cyAvIEwuQ1JTLkVhcnRoLlIpIC8gZCxcblx0XHRcdCAgICB0b3AgPSBtYXAucHJvamVjdChbbGF0ICsgbGF0UiwgbG5nXSksXG5cdFx0XHQgICAgYm90dG9tID0gbWFwLnByb2plY3QoW2xhdCAtIGxhdFIsIGxuZ10pLFxuXHRcdFx0ICAgIHAgPSB0b3AuYWRkKGJvdHRvbSkuZGl2aWRlQnkoMiksXG5cdFx0XHQgICAgbGF0MiA9IG1hcC51bnByb2plY3QocCkubGF0LFxuXHRcdFx0ICAgIGxuZ1IgPSBNYXRoLmFjb3MoKE1hdGguY29zKGxhdFIgKiBkKSAtIE1hdGguc2luKGxhdCAqIGQpICogTWF0aC5zaW4obGF0MiAqIGQpKSAvXG5cdFx0XHQgICAgICAgICAgICAoTWF0aC5jb3MobGF0ICogZCkgKiBNYXRoLmNvcyhsYXQyICogZCkpKSAvIGQ7XG5cblx0XHRcdGlmIChpc05hTihsbmdSKSB8fCBsbmdSID09PSAwKSB7XG5cdFx0XHRcdGxuZ1IgPSBsYXRSIC8gTWF0aC5jb3MoTWF0aC5QSSAvIDE4MCAqIGxhdCk7IC8vIEZhbGxiYWNrIGZvciBlZGdlIGNhc2UsICMyNDI1XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX3BvaW50ID0gcC5zdWJ0cmFjdChtYXAuZ2V0UGl4ZWxPcmlnaW4oKSk7XG5cdFx0XHR0aGlzLl9yYWRpdXMgPSBpc05hTihsbmdSKSA/IDAgOiBNYXRoLm1heChNYXRoLnJvdW5kKHAueCAtIG1hcC5wcm9qZWN0KFtsYXQyLCBsbmcgLSBsbmdSXSkueCksIDEpO1xuXHRcdFx0dGhpcy5fcmFkaXVzWSA9IE1hdGgubWF4KE1hdGgucm91bmQocC55IC0gdG9wLnkpLCAxKTtcblxuXHRcdH0gZWxzZSB7XG5cdFx0XHR2YXIgbGF0bG5nMiA9IGNycy51bnByb2plY3QoY3JzLnByb2plY3QodGhpcy5fbGF0bG5nKS5zdWJ0cmFjdChbdGhpcy5fbVJhZGl1cywgMF0pKTtcblxuXHRcdFx0dGhpcy5fcG9pbnQgPSBtYXAubGF0TG5nVG9MYXllclBvaW50KHRoaXMuX2xhdGxuZyk7XG5cdFx0XHR0aGlzLl9yYWRpdXMgPSB0aGlzLl9wb2ludC54IC0gbWFwLmxhdExuZ1RvTGF5ZXJQb2ludChsYXRsbmcyKS54O1xuXHRcdH1cblxuXHRcdHRoaXMuX3VwZGF0ZUJvdW5kcygpO1xuXHR9XG59KTtcblxuLy8gQGZhY3RvcnkgTC5jaXJjbGUobGF0bG5nOiBMYXRMbmcsIG9wdGlvbnM/OiBDaXJjbGUgb3B0aW9ucylcbi8vIEluc3RhbnRpYXRlcyBhIGNpcmNsZSBvYmplY3QgZ2l2ZW4gYSBnZW9ncmFwaGljYWwgcG9pbnQsIGFuZCBhbiBvcHRpb25zIG9iamVjdFxuLy8gd2hpY2ggY29udGFpbnMgdGhlIGNpcmNsZSByYWRpdXMuXG4vLyBAYWx0ZXJuYXRpdmVcbi8vIEBmYWN0b3J5IEwuY2lyY2xlKGxhdGxuZzogTGF0TG5nLCByYWRpdXM6IE51bWJlciwgb3B0aW9ucz86IENpcmNsZSBvcHRpb25zKVxuLy8gT2Jzb2xldGUgd2F5IG9mIGluc3RhbnRpYXRpbmcgYSBjaXJjbGUsIGZvciBjb21wYXRpYmlsaXR5IHdpdGggMC43LnggY29kZS5cbi8vIERvIG5vdCB1c2UgaW4gbmV3IGFwcGxpY2F0aW9ucyBvciBwbHVnaW5zLlxuTC5jaXJjbGUgPSBmdW5jdGlvbiAobGF0bG5nLCBvcHRpb25zLCBsZWdhY3lPcHRpb25zKSB7XG5cdHJldHVybiBuZXcgTC5DaXJjbGUobGF0bG5nLCBvcHRpb25zLCBsZWdhY3lPcHRpb25zKTtcbn07XG5cblxuXG4vKlxuICogQGNsYXNzIFNWR1xuICogQGluaGVyaXRzIFJlbmRlcmVyXG4gKiBAYWthIEwuU1ZHXG4gKlxuICogQWxsb3dzIHZlY3RvciBsYXllcnMgdG8gYmUgZGlzcGxheWVkIHdpdGggW1NWR10oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvU1ZHKS5cbiAqIEluaGVyaXRzIGBSZW5kZXJlcmAuXG4gKlxuICogRHVlIHRvIFt0ZWNobmljYWwgbGltaXRhdGlvbnNdKGh0dHA6Ly9jYW5pdXNlLmNvbS8jc2VhcmNoPXN2ZyksIFNWRyBpcyBub3RcbiAqIGF2YWlsYWJsZSBpbiBhbGwgd2ViIGJyb3dzZXJzLCBub3RhYmx5IEFuZHJvaWQgMi54IGFuZCAzLnguXG4gKlxuICogQWx0aG91Z2ggU1ZHIGlzIG5vdCBhdmFpbGFibGUgb24gSUU3IGFuZCBJRTgsIHRoZXNlIGJyb3dzZXJzIHN1cHBvcnRcbiAqIFtWTUxdKGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1ZlY3Rvcl9NYXJrdXBfTGFuZ3VhZ2UpXG4gKiAoYSBub3cgZGVwcmVjYXRlZCB0ZWNobm9sb2d5KSwgYW5kIHRoZSBTVkcgcmVuZGVyZXIgd2lsbCBmYWxsIGJhY2sgdG8gVk1MIGluXG4gKiB0aGlzIGNhc2UuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBVc2UgU1ZHIGJ5IGRlZmF1bHQgZm9yIGFsbCBwYXRocyBpbiB0aGUgbWFwOlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgbWFwID0gTC5tYXAoJ21hcCcsIHtcbiAqIFx0cmVuZGVyZXI6IEwuc3ZnKClcbiAqIH0pO1xuICogYGBgXG4gKlxuICogVXNlIGEgU1ZHIHJlbmRlcmVyIHdpdGggZXh0cmEgcGFkZGluZyBmb3Igc3BlY2lmaWMgdmVjdG9yIGdlb21ldHJpZXM6XG4gKlxuICogYGBganNcbiAqIHZhciBtYXAgPSBMLm1hcCgnbWFwJyk7XG4gKiB2YXIgbXlSZW5kZXJlciA9IEwuc3ZnKHsgcGFkZGluZzogMC41IH0pO1xuICogdmFyIGxpbmUgPSBMLnBvbHlsaW5lKCBjb29yZGluYXRlcywgeyByZW5kZXJlcjogbXlSZW5kZXJlciB9ICk7XG4gKiB2YXIgY2lyY2xlID0gTC5jaXJjbGUoIGNlbnRlciwgeyByZW5kZXJlcjogbXlSZW5kZXJlciB9ICk7XG4gKiBgYGBcbiAqL1xuXG5MLlNWRyA9IEwuUmVuZGVyZXIuZXh0ZW5kKHtcblxuXHRnZXRFdmVudHM6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgZXZlbnRzID0gTC5SZW5kZXJlci5wcm90b3R5cGUuZ2V0RXZlbnRzLmNhbGwodGhpcyk7XG5cdFx0ZXZlbnRzLnpvb21zdGFydCA9IHRoaXMuX29uWm9vbVN0YXJ0O1xuXHRcdHJldHVybiBldmVudHM7XG5cdH0sXG5cblx0X2luaXRDb250YWluZXI6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9jb250YWluZXIgPSBMLlNWRy5jcmVhdGUoJ3N2ZycpO1xuXG5cdFx0Ly8gbWFrZXMgaXQgcG9zc2libGUgdG8gY2xpY2sgdGhyb3VnaCBzdmcgcm9vdDsgd2UnbGwgcmVzZXQgaXQgYmFjayBpbiBpbmRpdmlkdWFsIHBhdGhzXG5cdFx0dGhpcy5fY29udGFpbmVyLnNldEF0dHJpYnV0ZSgncG9pbnRlci1ldmVudHMnLCAnbm9uZScpO1xuXG5cdFx0dGhpcy5fcm9vdEdyb3VwID0gTC5TVkcuY3JlYXRlKCdnJyk7XG5cdFx0dGhpcy5fY29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMuX3Jvb3RHcm91cCk7XG5cdH0sXG5cblx0X29uWm9vbVN0YXJ0OiBmdW5jdGlvbiAoKSB7XG5cdFx0Ly8gRHJhZy10aGVuLXBpbmNoIGludGVyYWN0aW9ucyBtaWdodCBtZXNzIHVwIHRoZSBjZW50ZXIgYW5kIHpvb20uXG5cdFx0Ly8gSW4gdGhpcyBjYXNlLCB0aGUgZWFzaWVzdCB3YXkgdG8gcHJldmVudCB0aGlzIGlzIHJlLWRvIHRoZSByZW5kZXJlclxuXHRcdC8vICAgYm91bmRzIGFuZCBwYWRkaW5nIHdoZW4gdGhlIHpvb21pbmcgc3RhcnRzLlxuXHRcdHRoaXMuX3VwZGF0ZSgpO1xuXHR9LFxuXG5cdF91cGRhdGU6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fbWFwLl9hbmltYXRpbmdab29tICYmIHRoaXMuX2JvdW5kcykgeyByZXR1cm47IH1cblxuXHRcdEwuUmVuZGVyZXIucHJvdG90eXBlLl91cGRhdGUuY2FsbCh0aGlzKTtcblxuXHRcdHZhciBiID0gdGhpcy5fYm91bmRzLFxuXHRcdCAgICBzaXplID0gYi5nZXRTaXplKCksXG5cdFx0ICAgIGNvbnRhaW5lciA9IHRoaXMuX2NvbnRhaW5lcjtcblxuXHRcdC8vIHNldCBzaXplIG9mIHN2Zy1jb250YWluZXIgaWYgY2hhbmdlZFxuXHRcdGlmICghdGhpcy5fc3ZnU2l6ZSB8fCAhdGhpcy5fc3ZnU2l6ZS5lcXVhbHMoc2l6ZSkpIHtcblx0XHRcdHRoaXMuX3N2Z1NpemUgPSBzaXplO1xuXHRcdFx0Y29udGFpbmVyLnNldEF0dHJpYnV0ZSgnd2lkdGgnLCBzaXplLngpO1xuXHRcdFx0Y29udGFpbmVyLnNldEF0dHJpYnV0ZSgnaGVpZ2h0Jywgc2l6ZS55KTtcblx0XHR9XG5cblx0XHQvLyBtb3ZlbWVudDogdXBkYXRlIGNvbnRhaW5lciB2aWV3Qm94IHNvIHRoYXQgd2UgZG9uJ3QgaGF2ZSB0byBjaGFuZ2UgY29vcmRpbmF0ZXMgb2YgaW5kaXZpZHVhbCBsYXllcnNcblx0XHRMLkRvbVV0aWwuc2V0UG9zaXRpb24oY29udGFpbmVyLCBiLm1pbik7XG5cdFx0Y29udGFpbmVyLnNldEF0dHJpYnV0ZSgndmlld0JveCcsIFtiLm1pbi54LCBiLm1pbi55LCBzaXplLngsIHNpemUueV0uam9pbignICcpKTtcblxuXHRcdHRoaXMuZmlyZSgndXBkYXRlJyk7XG5cdH0sXG5cblx0Ly8gbWV0aG9kcyBiZWxvdyBhcmUgY2FsbGVkIGJ5IHZlY3RvciBsYXllcnMgaW1wbGVtZW50YXRpb25zXG5cblx0X2luaXRQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR2YXIgcGF0aCA9IGxheWVyLl9wYXRoID0gTC5TVkcuY3JlYXRlKCdwYXRoJyk7XG5cblx0XHQvLyBAbmFtZXNwYWNlIFBhdGhcblx0XHQvLyBAb3B0aW9uIGNsYXNzTmFtZTogU3RyaW5nID0gbnVsbFxuXHRcdC8vIEN1c3RvbSBjbGFzcyBuYW1lIHNldCBvbiBhbiBlbGVtZW50LiBPbmx5IGZvciBTVkcgcmVuZGVyZXIuXG5cdFx0aWYgKGxheWVyLm9wdGlvbnMuY2xhc3NOYW1lKSB7XG5cdFx0XHRMLkRvbVV0aWwuYWRkQ2xhc3MocGF0aCwgbGF5ZXIub3B0aW9ucy5jbGFzc05hbWUpO1xuXHRcdH1cblxuXHRcdGlmIChsYXllci5vcHRpb25zLmludGVyYWN0aXZlKSB7XG5cdFx0XHRMLkRvbVV0aWwuYWRkQ2xhc3MocGF0aCwgJ2xlYWZsZXQtaW50ZXJhY3RpdmUnKTtcblx0XHR9XG5cblx0XHR0aGlzLl91cGRhdGVTdHlsZShsYXllcik7XG5cdFx0dGhpcy5fbGF5ZXJzW0wuc3RhbXAobGF5ZXIpXSA9IGxheWVyO1xuXHR9LFxuXG5cdF9hZGRQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR0aGlzLl9yb290R3JvdXAuYXBwZW5kQ2hpbGQobGF5ZXIuX3BhdGgpO1xuXHRcdGxheWVyLmFkZEludGVyYWN0aXZlVGFyZ2V0KGxheWVyLl9wYXRoKTtcblx0fSxcblxuXHRfcmVtb3ZlUGF0aDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0TC5Eb21VdGlsLnJlbW92ZShsYXllci5fcGF0aCk7XG5cdFx0bGF5ZXIucmVtb3ZlSW50ZXJhY3RpdmVUYXJnZXQobGF5ZXIuX3BhdGgpO1xuXHRcdGRlbGV0ZSB0aGlzLl9sYXllcnNbTC5zdGFtcChsYXllcildO1xuXHR9LFxuXG5cdF91cGRhdGVQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHRsYXllci5fcHJvamVjdCgpO1xuXHRcdGxheWVyLl91cGRhdGUoKTtcblx0fSxcblxuXHRfdXBkYXRlU3R5bGU6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBwYXRoID0gbGF5ZXIuX3BhdGgsXG5cdFx0ICAgIG9wdGlvbnMgPSBsYXllci5vcHRpb25zO1xuXG5cdFx0aWYgKCFwYXRoKSB7IHJldHVybjsgfVxuXG5cdFx0aWYgKG9wdGlvbnMuc3Ryb2tlKSB7XG5cdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnc3Ryb2tlJywgb3B0aW9ucy5jb2xvcik7XG5cdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnc3Ryb2tlLW9wYWNpdHknLCBvcHRpb25zLm9wYWNpdHkpO1xuXHRcdFx0cGF0aC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS13aWR0aCcsIG9wdGlvbnMud2VpZ2h0KTtcblx0XHRcdHBhdGguc2V0QXR0cmlidXRlKCdzdHJva2UtbGluZWNhcCcsIG9wdGlvbnMubGluZUNhcCk7XG5cdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnc3Ryb2tlLWxpbmVqb2luJywgb3B0aW9ucy5saW5lSm9pbik7XG5cblx0XHRcdGlmIChvcHRpb25zLmRhc2hBcnJheSkge1xuXHRcdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnc3Ryb2tlLWRhc2hhcnJheScsIG9wdGlvbnMuZGFzaEFycmF5KTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHBhdGgucmVtb3ZlQXR0cmlidXRlKCdzdHJva2UtZGFzaGFycmF5Jyk7XG5cdFx0XHR9XG5cblx0XHRcdGlmIChvcHRpb25zLmRhc2hPZmZzZXQpIHtcblx0XHRcdFx0cGF0aC5zZXRBdHRyaWJ1dGUoJ3N0cm9rZS1kYXNob2Zmc2V0Jywgb3B0aW9ucy5kYXNoT2Zmc2V0KTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdHBhdGgucmVtb3ZlQXR0cmlidXRlKCdzdHJva2UtZGFzaG9mZnNldCcpO1xuXHRcdFx0fVxuXHRcdH0gZWxzZSB7XG5cdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnc3Ryb2tlJywgJ25vbmUnKTtcblx0XHR9XG5cblx0XHRpZiAob3B0aW9ucy5maWxsKSB7XG5cdFx0XHRwYXRoLnNldEF0dHJpYnV0ZSgnZmlsbCcsIG9wdGlvbnMuZmlsbENvbG9yIHx8IG9wdGlvbnMuY29sb3IpO1xuXHRcdFx0cGF0aC5zZXRBdHRyaWJ1dGUoJ2ZpbGwtb3BhY2l0eScsIG9wdGlvbnMuZmlsbE9wYWNpdHkpO1xuXHRcdFx0cGF0aC5zZXRBdHRyaWJ1dGUoJ2ZpbGwtcnVsZScsIG9wdGlvbnMuZmlsbFJ1bGUgfHwgJ2V2ZW5vZGQnKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0cGF0aC5zZXRBdHRyaWJ1dGUoJ2ZpbGwnLCAnbm9uZScpO1xuXHRcdH1cblx0fSxcblxuXHRfdXBkYXRlUG9seTogZnVuY3Rpb24gKGxheWVyLCBjbG9zZWQpIHtcblx0XHR0aGlzLl9zZXRQYXRoKGxheWVyLCBMLlNWRy5wb2ludHNUb1BhdGgobGF5ZXIuX3BhcnRzLCBjbG9zZWQpKTtcblx0fSxcblxuXHRfdXBkYXRlQ2lyY2xlOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR2YXIgcCA9IGxheWVyLl9wb2ludCxcblx0XHQgICAgciA9IGxheWVyLl9yYWRpdXMsXG5cdFx0ICAgIHIyID0gbGF5ZXIuX3JhZGl1c1kgfHwgcixcblx0XHQgICAgYXJjID0gJ2EnICsgciArICcsJyArIHIyICsgJyAwIDEsMCAnO1xuXG5cdFx0Ly8gZHJhd2luZyBhIGNpcmNsZSB3aXRoIHR3byBoYWxmLWFyY3Ncblx0XHR2YXIgZCA9IGxheWVyLl9lbXB0eSgpID8gJ00wIDAnIDpcblx0XHRcdFx0J00nICsgKHAueCAtIHIpICsgJywnICsgcC55ICtcblx0XHRcdFx0YXJjICsgKHIgKiAyKSArICcsMCAnICtcblx0XHRcdFx0YXJjICsgKC1yICogMikgKyAnLDAgJztcblxuXHRcdHRoaXMuX3NldFBhdGgobGF5ZXIsIGQpO1xuXHR9LFxuXG5cdF9zZXRQYXRoOiBmdW5jdGlvbiAobGF5ZXIsIHBhdGgpIHtcblx0XHRsYXllci5fcGF0aC5zZXRBdHRyaWJ1dGUoJ2QnLCBwYXRoKTtcblx0fSxcblxuXHQvLyBTVkcgZG9lcyBub3QgaGF2ZSB0aGUgY29uY2VwdCBvZiB6SW5kZXggc28gd2UgcmVzb3J0IHRvIGNoYW5naW5nIHRoZSBET00gb3JkZXIgb2YgZWxlbWVudHNcblx0X2JyaW5nVG9Gcm9udDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0TC5Eb21VdGlsLnRvRnJvbnQobGF5ZXIuX3BhdGgpO1xuXHR9LFxuXG5cdF9icmluZ1RvQmFjazogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0TC5Eb21VdGlsLnRvQmFjayhsYXllci5fcGF0aCk7XG5cdH1cbn0pO1xuXG5cbi8vIEBuYW1lc3BhY2UgU1ZHOyBAc2VjdGlvblxuLy8gVGhlcmUgYXJlIHNldmVyYWwgc3RhdGljIGZ1bmN0aW9ucyB3aGljaCBjYW4gYmUgY2FsbGVkIHdpdGhvdXQgaW5zdGFudGlhdGluZyBMLlNWRzpcbkwuZXh0ZW5kKEwuU1ZHLCB7XG5cdC8vIEBmdW5jdGlvbiBjcmVhdGUobmFtZTogU3RyaW5nKTogU1ZHRWxlbWVudFxuXHQvLyBSZXR1cm5zIGEgaW5zdGFuY2Ugb2YgW1NWR0VsZW1lbnRdKGh0dHBzOi8vZGV2ZWxvcGVyLm1vemlsbGEub3JnL2RvY3MvV2ViL0FQSS9TVkdFbGVtZW50KSxcblx0Ly8gY29ycmVzcG9uZGluZyB0byB0aGUgY2xhc3MgbmFtZSBwYXNzZWQuIEZvciBleGFtcGxlLCB1c2luZyAnbGluZScgd2lsbCByZXR1cm5cblx0Ly8gYW4gaW5zdGFuY2Ugb2YgW1NWR0xpbmVFbGVtZW50XShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9BUEkvU1ZHTGluZUVsZW1lbnQpLlxuXHRjcmVhdGU6IGZ1bmN0aW9uIChuYW1lKSB7XG5cdFx0cmV0dXJuIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUygnaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmcnLCBuYW1lKTtcblx0fSxcblxuXHQvLyBAZnVuY3Rpb24gcG9pbnRzVG9QYXRoKHJpbmdzOiBQb2ludFtdLCBjbG9zZWQ6IEJvb2xlYW4pOiBTdHJpbmdcblx0Ly8gR2VuZXJhdGVzIGEgU1ZHIHBhdGggc3RyaW5nIGZvciBtdWx0aXBsZSByaW5ncywgd2l0aCBlYWNoIHJpbmcgdHVybmluZ1xuXHQvLyBpbnRvIFwiTS4uTC4uTC4uXCIgaW5zdHJ1Y3Rpb25zXG5cdHBvaW50c1RvUGF0aDogZnVuY3Rpb24gKHJpbmdzLCBjbG9zZWQpIHtcblx0XHR2YXIgc3RyID0gJycsXG5cdFx0ICAgIGksIGosIGxlbiwgbGVuMiwgcG9pbnRzLCBwO1xuXG5cdFx0Zm9yIChpID0gMCwgbGVuID0gcmluZ3MubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdHBvaW50cyA9IHJpbmdzW2ldO1xuXG5cdFx0XHRmb3IgKGogPSAwLCBsZW4yID0gcG9pbnRzLmxlbmd0aDsgaiA8IGxlbjI7IGorKykge1xuXHRcdFx0XHRwID0gcG9pbnRzW2pdO1xuXHRcdFx0XHRzdHIgKz0gKGogPyAnTCcgOiAnTScpICsgcC54ICsgJyAnICsgcC55O1xuXHRcdFx0fVxuXG5cdFx0XHQvLyBjbG9zZXMgdGhlIHJpbmcgZm9yIHBvbHlnb25zOyBcInhcIiBpcyBWTUwgc3ludGF4XG5cdFx0XHRzdHIgKz0gY2xvc2VkID8gKEwuQnJvd3Nlci5zdmcgPyAneicgOiAneCcpIDogJyc7XG5cdFx0fVxuXG5cdFx0Ly8gU1ZHIGNvbXBsYWlucyBhYm91dCBlbXB0eSBwYXRoIHN0cmluZ3Ncblx0XHRyZXR1cm4gc3RyIHx8ICdNMCAwJztcblx0fVxufSk7XG5cbi8vIEBuYW1lc3BhY2UgQnJvd3NlcjsgQHByb3BlcnR5IHN2ZzogQm9vbGVhblxuLy8gYHRydWVgIHdoZW4gdGhlIGJyb3dzZXIgc3VwcG9ydHMgW1NWR10oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvU1ZHKS5cbkwuQnJvd3Nlci5zdmcgPSAhIShkb2N1bWVudC5jcmVhdGVFbGVtZW50TlMgJiYgTC5TVkcuY3JlYXRlKCdzdmcnKS5jcmVhdGVTVkdSZWN0KTtcblxuXG4vLyBAbmFtZXNwYWNlIFNWR1xuLy8gQGZhY3RvcnkgTC5zdmcob3B0aW9ucz86IFJlbmRlcmVyIG9wdGlvbnMpXG4vLyBDcmVhdGVzIGEgU1ZHIHJlbmRlcmVyIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG5MLnN2ZyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG5cdHJldHVybiBMLkJyb3dzZXIuc3ZnIHx8IEwuQnJvd3Nlci52bWwgPyBuZXcgTC5TVkcob3B0aW9ucykgOiBudWxsO1xufTtcblxuXG5cbi8qXG4gKiBUaGFua3MgdG8gRG1pdHJ5IEJhcmFub3Zza3kgYW5kIGhpcyBSYXBoYWVsIGxpYnJhcnkgZm9yIGluc3BpcmF0aW9uIVxuICovXG5cbi8qXG4gKiBAY2xhc3MgU1ZHXG4gKlxuICogQWx0aG91Z2ggU1ZHIGlzIG5vdCBhdmFpbGFibGUgb24gSUU3IGFuZCBJRTgsIHRoZXNlIGJyb3dzZXJzIHN1cHBvcnQgW1ZNTF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVmVjdG9yX01hcmt1cF9MYW5ndWFnZSksIGFuZCB0aGUgU1ZHIHJlbmRlcmVyIHdpbGwgZmFsbCBiYWNrIHRvIFZNTCBpbiB0aGlzIGNhc2UuXG4gKlxuICogVk1MIHdhcyBkZXByZWNhdGVkIGluIDIwMTIsIHdoaWNoIG1lYW5zIFZNTCBmdW5jdGlvbmFsaXR5IGV4aXN0cyBvbmx5IGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eVxuICogd2l0aCBvbGQgdmVyc2lvbnMgb2YgSW50ZXJuZXQgRXhwbG9yZXIuXG4gKi9cblxuLy8gQG5hbWVzcGFjZSBCcm93c2VyOyBAcHJvcGVydHkgdm1sOiBCb29sZWFuXG4vLyBgdHJ1ZWAgaWYgdGhlIGJyb3dzZXIgc3VwcG9ydHMgW1ZNTF0oaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvVmVjdG9yX01hcmt1cF9MYW5ndWFnZSkuXG5MLkJyb3dzZXIudm1sID0gIUwuQnJvd3Nlci5zdmcgJiYgKGZ1bmN0aW9uICgpIHtcblx0dHJ5IHtcblx0XHR2YXIgZGl2ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG5cdFx0ZGl2LmlubmVySFRNTCA9ICc8djpzaGFwZSBhZGo9XCIxXCIvPic7XG5cblx0XHR2YXIgc2hhcGUgPSBkaXYuZmlyc3RDaGlsZDtcblx0XHRzaGFwZS5zdHlsZS5iZWhhdmlvciA9ICd1cmwoI2RlZmF1bHQjVk1MKSc7XG5cblx0XHRyZXR1cm4gc2hhcGUgJiYgKHR5cGVvZiBzaGFwZS5hZGogPT09ICdvYmplY3QnKTtcblxuXHR9IGNhdGNoIChlKSB7XG5cdFx0cmV0dXJuIGZhbHNlO1xuXHR9XG59KCkpO1xuXG4vLyByZWRlZmluZSBzb21lIFNWRyBtZXRob2RzIHRvIGhhbmRsZSBWTUwgc3ludGF4IHdoaWNoIGlzIHNpbWlsYXIgYnV0IHdpdGggc29tZSBkaWZmZXJlbmNlc1xuTC5TVkcuaW5jbHVkZSghTC5Ccm93c2VyLnZtbCA/IHt9IDoge1xuXG5cdF9pbml0Q29udGFpbmVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fY29udGFpbmVyID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2JywgJ2xlYWZsZXQtdm1sLWNvbnRhaW5lcicpO1xuXHR9LFxuXG5cdF91cGRhdGU6IGZ1bmN0aW9uICgpIHtcblx0XHRpZiAodGhpcy5fbWFwLl9hbmltYXRpbmdab29tKSB7IHJldHVybjsgfVxuXHRcdEwuUmVuZGVyZXIucHJvdG90eXBlLl91cGRhdGUuY2FsbCh0aGlzKTtcblx0XHR0aGlzLmZpcmUoJ3VwZGF0ZScpO1xuXHR9LFxuXG5cdF9pbml0UGF0aDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIGNvbnRhaW5lciA9IGxheWVyLl9jb250YWluZXIgPSBMLlNWRy5jcmVhdGUoJ3NoYXBlJyk7XG5cblx0XHRMLkRvbVV0aWwuYWRkQ2xhc3MoY29udGFpbmVyLCAnbGVhZmxldC12bWwtc2hhcGUgJyArICh0aGlzLm9wdGlvbnMuY2xhc3NOYW1lIHx8ICcnKSk7XG5cblx0XHRjb250YWluZXIuY29vcmRzaXplID0gJzEgMSc7XG5cblx0XHRsYXllci5fcGF0aCA9IEwuU1ZHLmNyZWF0ZSgncGF0aCcpO1xuXHRcdGNvbnRhaW5lci5hcHBlbmRDaGlsZChsYXllci5fcGF0aCk7XG5cblx0XHR0aGlzLl91cGRhdGVTdHlsZShsYXllcik7XG5cdH0sXG5cblx0X2FkZFBhdGg6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBjb250YWluZXIgPSBsYXllci5fY29udGFpbmVyO1xuXHRcdHRoaXMuX2NvbnRhaW5lci5hcHBlbmRDaGlsZChjb250YWluZXIpO1xuXG5cdFx0aWYgKGxheWVyLm9wdGlvbnMuaW50ZXJhY3RpdmUpIHtcblx0XHRcdGxheWVyLmFkZEludGVyYWN0aXZlVGFyZ2V0KGNvbnRhaW5lcik7XG5cdFx0fVxuXHR9LFxuXG5cdF9yZW1vdmVQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR2YXIgY29udGFpbmVyID0gbGF5ZXIuX2NvbnRhaW5lcjtcblx0XHRMLkRvbVV0aWwucmVtb3ZlKGNvbnRhaW5lcik7XG5cdFx0bGF5ZXIucmVtb3ZlSW50ZXJhY3RpdmVUYXJnZXQoY29udGFpbmVyKTtcblx0fSxcblxuXHRfdXBkYXRlU3R5bGU6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdHZhciBzdHJva2UgPSBsYXllci5fc3Ryb2tlLFxuXHRcdCAgICBmaWxsID0gbGF5ZXIuX2ZpbGwsXG5cdFx0ICAgIG9wdGlvbnMgPSBsYXllci5vcHRpb25zLFxuXHRcdCAgICBjb250YWluZXIgPSBsYXllci5fY29udGFpbmVyO1xuXG5cdFx0Y29udGFpbmVyLnN0cm9rZWQgPSAhIW9wdGlvbnMuc3Ryb2tlO1xuXHRcdGNvbnRhaW5lci5maWxsZWQgPSAhIW9wdGlvbnMuZmlsbDtcblxuXHRcdGlmIChvcHRpb25zLnN0cm9rZSkge1xuXHRcdFx0aWYgKCFzdHJva2UpIHtcblx0XHRcdFx0c3Ryb2tlID0gbGF5ZXIuX3N0cm9rZSA9IEwuU1ZHLmNyZWF0ZSgnc3Ryb2tlJyk7XG5cdFx0XHR9XG5cdFx0XHRjb250YWluZXIuYXBwZW5kQ2hpbGQoc3Ryb2tlKTtcblx0XHRcdHN0cm9rZS53ZWlnaHQgPSBvcHRpb25zLndlaWdodCArICdweCc7XG5cdFx0XHRzdHJva2UuY29sb3IgPSBvcHRpb25zLmNvbG9yO1xuXHRcdFx0c3Ryb2tlLm9wYWNpdHkgPSBvcHRpb25zLm9wYWNpdHk7XG5cblx0XHRcdGlmIChvcHRpb25zLmRhc2hBcnJheSkge1xuXHRcdFx0XHRzdHJva2UuZGFzaFN0eWxlID0gTC5VdGlsLmlzQXJyYXkob3B0aW9ucy5kYXNoQXJyYXkpID9cblx0XHRcdFx0ICAgIG9wdGlvbnMuZGFzaEFycmF5LmpvaW4oJyAnKSA6XG5cdFx0XHRcdCAgICBvcHRpb25zLmRhc2hBcnJheS5yZXBsYWNlKC8oICosICopL2csICcgJyk7XG5cdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRzdHJva2UuZGFzaFN0eWxlID0gJyc7XG5cdFx0XHR9XG5cdFx0XHRzdHJva2UuZW5kY2FwID0gb3B0aW9ucy5saW5lQ2FwLnJlcGxhY2UoJ2J1dHQnLCAnZmxhdCcpO1xuXHRcdFx0c3Ryb2tlLmpvaW5zdHlsZSA9IG9wdGlvbnMubGluZUpvaW47XG5cblx0XHR9IGVsc2UgaWYgKHN0cm9rZSkge1xuXHRcdFx0Y29udGFpbmVyLnJlbW92ZUNoaWxkKHN0cm9rZSk7XG5cdFx0XHRsYXllci5fc3Ryb2tlID0gbnVsbDtcblx0XHR9XG5cblx0XHRpZiAob3B0aW9ucy5maWxsKSB7XG5cdFx0XHRpZiAoIWZpbGwpIHtcblx0XHRcdFx0ZmlsbCA9IGxheWVyLl9maWxsID0gTC5TVkcuY3JlYXRlKCdmaWxsJyk7XG5cdFx0XHR9XG5cdFx0XHRjb250YWluZXIuYXBwZW5kQ2hpbGQoZmlsbCk7XG5cdFx0XHRmaWxsLmNvbG9yID0gb3B0aW9ucy5maWxsQ29sb3IgfHwgb3B0aW9ucy5jb2xvcjtcblx0XHRcdGZpbGwub3BhY2l0eSA9IG9wdGlvbnMuZmlsbE9wYWNpdHk7XG5cblx0XHR9IGVsc2UgaWYgKGZpbGwpIHtcblx0XHRcdGNvbnRhaW5lci5yZW1vdmVDaGlsZChmaWxsKTtcblx0XHRcdGxheWVyLl9maWxsID0gbnVsbDtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZUNpcmNsZTogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIHAgPSBsYXllci5fcG9pbnQucm91bmQoKSxcblx0XHQgICAgciA9IE1hdGgucm91bmQobGF5ZXIuX3JhZGl1cyksXG5cdFx0ICAgIHIyID0gTWF0aC5yb3VuZChsYXllci5fcmFkaXVzWSB8fCByKTtcblxuXHRcdHRoaXMuX3NldFBhdGgobGF5ZXIsIGxheWVyLl9lbXB0eSgpID8gJ00wIDAnIDpcblx0XHRcdFx0J0FMICcgKyBwLnggKyAnLCcgKyBwLnkgKyAnICcgKyByICsgJywnICsgcjIgKyAnIDAsJyArICg2NTUzNSAqIDM2MCkpO1xuXHR9LFxuXG5cdF9zZXRQYXRoOiBmdW5jdGlvbiAobGF5ZXIsIHBhdGgpIHtcblx0XHRsYXllci5fcGF0aC52ID0gcGF0aDtcblx0fSxcblxuXHRfYnJpbmdUb0Zyb250OiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHRMLkRvbVV0aWwudG9Gcm9udChsYXllci5fY29udGFpbmVyKTtcblx0fSxcblxuXHRfYnJpbmdUb0JhY2s6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdEwuRG9tVXRpbC50b0JhY2sobGF5ZXIuX2NvbnRhaW5lcik7XG5cdH1cbn0pO1xuXG5pZiAoTC5Ccm93c2VyLnZtbCkge1xuXHRMLlNWRy5jcmVhdGUgPSAoZnVuY3Rpb24gKCkge1xuXHRcdHRyeSB7XG5cdFx0XHRkb2N1bWVudC5uYW1lc3BhY2VzLmFkZCgnbHZtbCcsICd1cm46c2NoZW1hcy1taWNyb3NvZnQtY29tOnZtbCcpO1xuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uIChuYW1lKSB7XG5cdFx0XHRcdHJldHVybiBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCc8bHZtbDonICsgbmFtZSArICcgY2xhc3M9XCJsdm1sXCI+Jyk7XG5cdFx0XHR9O1xuXHRcdH0gY2F0Y2ggKGUpIHtcblx0XHRcdHJldHVybiBmdW5jdGlvbiAobmFtZSkge1xuXHRcdFx0XHRyZXR1cm4gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnPCcgKyBuYW1lICsgJyB4bWxucz1cInVybjpzY2hlbWFzLW1pY3Jvc29mdC5jb206dm1sXCIgY2xhc3M9XCJsdm1sXCI+Jyk7XG5cdFx0XHR9O1xuXHRcdH1cblx0fSkoKTtcbn1cblxuXG5cbi8qXG4gKiBAY2xhc3MgQ2FudmFzXG4gKiBAaW5oZXJpdHMgUmVuZGVyZXJcbiAqIEBha2EgTC5DYW52YXNcbiAqXG4gKiBBbGxvd3MgdmVjdG9yIGxheWVycyB0byBiZSBkaXNwbGF5ZWQgd2l0aCBbYDxjYW52YXM+YF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvQVBJL0NhbnZhc19BUEkpLlxuICogSW5oZXJpdHMgYFJlbmRlcmVyYC5cbiAqXG4gKiBEdWUgdG8gW3RlY2huaWNhbCBsaW1pdGF0aW9uc10oaHR0cDovL2Nhbml1c2UuY29tLyNzZWFyY2g9Y2FudmFzKSwgQ2FudmFzIGlzIG5vdFxuICogYXZhaWxhYmxlIGluIGFsbCB3ZWIgYnJvd3NlcnMsIG5vdGFibHkgSUU4LCBhbmQgb3ZlcmxhcHBpbmcgZ2VvbWV0cmllcyBtaWdodFxuICogbm90IGRpc3BsYXkgcHJvcGVybHkgaW4gc29tZSBlZGdlIGNhc2VzLlxuICpcbiAqIEBleGFtcGxlXG4gKlxuICogVXNlIENhbnZhcyBieSBkZWZhdWx0IGZvciBhbGwgcGF0aHMgaW4gdGhlIG1hcDpcbiAqXG4gKiBgYGBqc1xuICogdmFyIG1hcCA9IEwubWFwKCdtYXAnLCB7XG4gKiBcdHJlbmRlcmVyOiBMLmNhbnZhcygpXG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqIFVzZSBhIENhbnZhcyByZW5kZXJlciB3aXRoIGV4dHJhIHBhZGRpbmcgZm9yIHNwZWNpZmljIHZlY3RvciBnZW9tZXRyaWVzOlxuICpcbiAqIGBgYGpzXG4gKiB2YXIgbWFwID0gTC5tYXAoJ21hcCcpO1xuICogdmFyIG15UmVuZGVyZXIgPSBMLmNhbnZhcyh7IHBhZGRpbmc6IDAuNSB9KTtcbiAqIHZhciBsaW5lID0gTC5wb2x5bGluZSggY29vcmRpbmF0ZXMsIHsgcmVuZGVyZXI6IG15UmVuZGVyZXIgfSApO1xuICogdmFyIGNpcmNsZSA9IEwuY2lyY2xlKCBjZW50ZXIsIHsgcmVuZGVyZXI6IG15UmVuZGVyZXIgfSApO1xuICogYGBgXG4gKi9cblxuTC5DYW52YXMgPSBMLlJlbmRlcmVyLmV4dGVuZCh7XG5cblx0b25BZGQ6IGZ1bmN0aW9uICgpIHtcblx0XHRMLlJlbmRlcmVyLnByb3RvdHlwZS5vbkFkZC5jYWxsKHRoaXMpO1xuXG5cdFx0Ly8gUmVkcmF3IHZlY3RvcnMgc2luY2UgY2FudmFzIGlzIGNsZWFyZWQgdXBvbiByZW1vdmFsLFxuXHRcdC8vIGluIGNhc2Ugb2YgcmVtb3ZpbmcgdGhlIHJlbmRlcmVyIGl0c2VsZiBmcm9tIHRoZSBtYXAuXG5cdFx0dGhpcy5fZHJhdygpO1xuXHR9LFxuXG5cdF9pbml0Q29udGFpbmVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGNvbnRhaW5lciA9IHRoaXMuX2NvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuXG5cdFx0TC5Eb21FdmVudFxuXHRcdFx0Lm9uKGNvbnRhaW5lciwgJ21vdXNlbW92ZScsIEwuVXRpbC50aHJvdHRsZSh0aGlzLl9vbk1vdXNlTW92ZSwgMzIsIHRoaXMpLCB0aGlzKVxuXHRcdFx0Lm9uKGNvbnRhaW5lciwgJ2NsaWNrIGRibGNsaWNrIG1vdXNlZG93biBtb3VzZXVwIGNvbnRleHRtZW51JywgdGhpcy5fb25DbGljaywgdGhpcylcblx0XHRcdC5vbihjb250YWluZXIsICdtb3VzZW91dCcsIHRoaXMuX2hhbmRsZU1vdXNlT3V0LCB0aGlzKTtcblxuXHRcdHRoaXMuX2N0eCA9IGNvbnRhaW5lci5nZXRDb250ZXh0KCcyZCcpO1xuXHR9LFxuXG5cdF91cGRhdGVQYXRoczogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBsYXllcjtcblx0XHR0aGlzLl9yZWRyYXdCb3VuZHMgPSBudWxsO1xuXHRcdGZvciAodmFyIGlkIGluIHRoaXMuX2xheWVycykge1xuXHRcdFx0bGF5ZXIgPSB0aGlzLl9sYXllcnNbaWRdO1xuXHRcdFx0bGF5ZXIuX3VwZGF0ZSgpO1xuXHRcdH1cblx0XHR0aGlzLl9yZWRyYXcoKTtcblx0fSxcblxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21hcC5fYW5pbWF0aW5nWm9vbSAmJiB0aGlzLl9ib3VuZHMpIHsgcmV0dXJuOyB9XG5cblx0XHR0aGlzLl9kcmF3bkxheWVycyA9IHt9O1xuXG5cdFx0TC5SZW5kZXJlci5wcm90b3R5cGUuX3VwZGF0ZS5jYWxsKHRoaXMpO1xuXG5cdFx0dmFyIGIgPSB0aGlzLl9ib3VuZHMsXG5cdFx0ICAgIGNvbnRhaW5lciA9IHRoaXMuX2NvbnRhaW5lcixcblx0XHQgICAgc2l6ZSA9IGIuZ2V0U2l6ZSgpLFxuXHRcdCAgICBtID0gTC5Ccm93c2VyLnJldGluYSA/IDIgOiAxO1xuXG5cdFx0TC5Eb21VdGlsLnNldFBvc2l0aW9uKGNvbnRhaW5lciwgYi5taW4pO1xuXG5cdFx0Ly8gc2V0IGNhbnZhcyBzaXplIChhbHNvIGNsZWFyaW5nIGl0KTsgdXNlIGRvdWJsZSBzaXplIG9uIHJldGluYVxuXHRcdGNvbnRhaW5lci53aWR0aCA9IG0gKiBzaXplLng7XG5cdFx0Y29udGFpbmVyLmhlaWdodCA9IG0gKiBzaXplLnk7XG5cdFx0Y29udGFpbmVyLnN0eWxlLndpZHRoID0gc2l6ZS54ICsgJ3B4Jztcblx0XHRjb250YWluZXIuc3R5bGUuaGVpZ2h0ID0gc2l6ZS55ICsgJ3B4JztcblxuXHRcdGlmIChMLkJyb3dzZXIucmV0aW5hKSB7XG5cdFx0XHR0aGlzLl9jdHguc2NhbGUoMiwgMik7XG5cdFx0fVxuXG5cdFx0Ly8gdHJhbnNsYXRlIHNvIHdlIHVzZSB0aGUgc2FtZSBwYXRoIGNvb3JkaW5hdGVzIGFmdGVyIGNhbnZhcyBlbGVtZW50IG1vdmVzXG5cdFx0dGhpcy5fY3R4LnRyYW5zbGF0ZSgtYi5taW4ueCwgLWIubWluLnkpO1xuXG5cdFx0Ly8gVGVsbCBwYXRocyB0byByZWRyYXcgdGhlbXNlbHZlc1xuXHRcdHRoaXMuZmlyZSgndXBkYXRlJyk7XG5cdH0sXG5cblx0X2luaXRQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR0aGlzLl91cGRhdGVEYXNoQXJyYXkobGF5ZXIpO1xuXHRcdHRoaXMuX2xheWVyc1tMLnN0YW1wKGxheWVyKV0gPSBsYXllcjtcblxuXHRcdHZhciBvcmRlciA9IGxheWVyLl9vcmRlciA9IHtcblx0XHRcdGxheWVyOiBsYXllcixcblx0XHRcdHByZXY6IHRoaXMuX2RyYXdMYXN0LFxuXHRcdFx0bmV4dDogbnVsbFxuXHRcdH07XG5cdFx0aWYgKHRoaXMuX2RyYXdMYXN0KSB7IHRoaXMuX2RyYXdMYXN0Lm5leHQgPSBvcmRlcjsgfVxuXHRcdHRoaXMuX2RyYXdMYXN0ID0gb3JkZXI7XG5cdFx0dGhpcy5fZHJhd0ZpcnN0ID0gdGhpcy5fZHJhd0ZpcnN0IHx8IHRoaXMuX2RyYXdMYXN0O1xuXHR9LFxuXG5cdF9hZGRQYXRoOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR0aGlzLl9yZXF1ZXN0UmVkcmF3KGxheWVyKTtcblx0fSxcblxuXHRfcmVtb3ZlUGF0aDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIG9yZGVyID0gbGF5ZXIuX29yZGVyO1xuXHRcdHZhciBuZXh0ID0gb3JkZXIubmV4dDtcblx0XHR2YXIgcHJldiA9IG9yZGVyLnByZXY7XG5cblx0XHRpZiAobmV4dCkge1xuXHRcdFx0bmV4dC5wcmV2ID0gcHJldjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5fZHJhd0xhc3QgPSBwcmV2O1xuXHRcdH1cblx0XHRpZiAocHJldikge1xuXHRcdFx0cHJldi5uZXh0ID0gbmV4dDtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5fZHJhd0ZpcnN0ID0gbmV4dDtcblx0XHR9XG5cblx0XHRkZWxldGUgbGF5ZXIuX29yZGVyO1xuXG5cdFx0ZGVsZXRlIHRoaXMuX2xheWVyc1tMLnN0YW1wKGxheWVyKV07XG5cblx0XHR0aGlzLl9yZXF1ZXN0UmVkcmF3KGxheWVyKTtcblx0fSxcblxuXHRfdXBkYXRlUGF0aDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0Ly8gUmVkcmF3IHRoZSB1bmlvbiBvZiB0aGUgbGF5ZXIncyBvbGQgcGl4ZWxcblx0XHQvLyBib3VuZHMgYW5kIHRoZSBuZXcgcGl4ZWwgYm91bmRzLlxuXHRcdHRoaXMuX2V4dGVuZFJlZHJhd0JvdW5kcyhsYXllcik7XG5cdFx0bGF5ZXIuX3Byb2plY3QoKTtcblx0XHRsYXllci5fdXBkYXRlKCk7XG5cdFx0Ly8gVGhlIHJlZHJhdyB3aWxsIGV4dGVuZCB0aGUgcmVkcmF3IGJvdW5kc1xuXHRcdC8vIHdpdGggdGhlIG5ldyBwaXhlbCBib3VuZHMuXG5cdFx0dGhpcy5fcmVxdWVzdFJlZHJhdyhsYXllcik7XG5cdH0sXG5cblx0X3VwZGF0ZVN0eWxlOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR0aGlzLl91cGRhdGVEYXNoQXJyYXkobGF5ZXIpO1xuXHRcdHRoaXMuX3JlcXVlc3RSZWRyYXcobGF5ZXIpO1xuXHR9LFxuXG5cdF91cGRhdGVEYXNoQXJyYXk6IGZ1bmN0aW9uIChsYXllcikge1xuXHRcdGlmIChsYXllci5vcHRpb25zLmRhc2hBcnJheSkge1xuXHRcdFx0dmFyIHBhcnRzID0gbGF5ZXIub3B0aW9ucy5kYXNoQXJyYXkuc3BsaXQoJywnKSxcblx0XHRcdCAgICBkYXNoQXJyYXkgPSBbXSxcblx0XHRcdCAgICBpO1xuXHRcdFx0Zm9yIChpID0gMDsgaSA8IHBhcnRzLmxlbmd0aDsgaSsrKSB7XG5cdFx0XHRcdGRhc2hBcnJheS5wdXNoKE51bWJlcihwYXJ0c1tpXSkpO1xuXHRcdFx0fVxuXHRcdFx0bGF5ZXIub3B0aW9ucy5fZGFzaEFycmF5ID0gZGFzaEFycmF5O1xuXHRcdH1cblx0fSxcblxuXHRfcmVxdWVzdFJlZHJhdzogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0aWYgKCF0aGlzLl9tYXApIHsgcmV0dXJuOyB9XG5cblx0XHR0aGlzLl9leHRlbmRSZWRyYXdCb3VuZHMobGF5ZXIpO1xuXHRcdHRoaXMuX3JlZHJhd1JlcXVlc3QgPSB0aGlzLl9yZWRyYXdSZXF1ZXN0IHx8IEwuVXRpbC5yZXF1ZXN0QW5pbUZyYW1lKHRoaXMuX3JlZHJhdywgdGhpcyk7XG5cdH0sXG5cblx0X2V4dGVuZFJlZHJhd0JvdW5kczogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIHBhZGRpbmcgPSAobGF5ZXIub3B0aW9ucy53ZWlnaHQgfHwgMCkgKyAxO1xuXHRcdHRoaXMuX3JlZHJhd0JvdW5kcyA9IHRoaXMuX3JlZHJhd0JvdW5kcyB8fCBuZXcgTC5Cb3VuZHMoKTtcblx0XHR0aGlzLl9yZWRyYXdCb3VuZHMuZXh0ZW5kKGxheWVyLl9weEJvdW5kcy5taW4uc3VidHJhY3QoW3BhZGRpbmcsIHBhZGRpbmddKSk7XG5cdFx0dGhpcy5fcmVkcmF3Qm91bmRzLmV4dGVuZChsYXllci5fcHhCb3VuZHMubWF4LmFkZChbcGFkZGluZywgcGFkZGluZ10pKTtcblx0fSxcblxuXHRfcmVkcmF3OiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fcmVkcmF3UmVxdWVzdCA9IG51bGw7XG5cblx0XHR0aGlzLl9jbGVhcigpOyAvLyBjbGVhciBsYXllcnMgaW4gcmVkcmF3IGJvdW5kc1xuXHRcdHRoaXMuX2RyYXcoKTsgLy8gZHJhdyBsYXllcnNcblxuXHRcdHRoaXMuX3JlZHJhd0JvdW5kcyA9IG51bGw7XG5cdH0sXG5cblx0X2NsZWFyOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGJvdW5kcyA9IHRoaXMuX3JlZHJhd0JvdW5kcztcblx0XHRpZiAoYm91bmRzKSB7XG5cdFx0XHR2YXIgc2l6ZSA9IGJvdW5kcy5nZXRTaXplKCk7XG5cdFx0XHR0aGlzLl9jdHguY2xlYXJSZWN0KGJvdW5kcy5taW4ueCwgYm91bmRzLm1pbi55LCBzaXplLngsIHNpemUueSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdHRoaXMuX2N0eC5jbGVhclJlY3QoMCwgMCwgdGhpcy5fY29udGFpbmVyLndpZHRoLCB0aGlzLl9jb250YWluZXIuaGVpZ2h0KTtcblx0XHR9XG5cdH0sXG5cblx0X2RyYXc6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgbGF5ZXIsIGJvdW5kcyA9IHRoaXMuX3JlZHJhd0JvdW5kcztcblx0XHR0aGlzLl9jdHguc2F2ZSgpO1xuXHRcdGlmIChib3VuZHMpIHtcblx0XHRcdHZhciBzaXplID0gYm91bmRzLmdldFNpemUoKTtcblx0XHRcdHRoaXMuX2N0eC5iZWdpblBhdGgoKTtcblx0XHRcdHRoaXMuX2N0eC5yZWN0KGJvdW5kcy5taW4ueCwgYm91bmRzLm1pbi55LCBzaXplLngsIHNpemUueSk7XG5cdFx0XHR0aGlzLl9jdHguY2xpcCgpO1xuXHRcdH1cblxuXHRcdHRoaXMuX2RyYXdpbmcgPSB0cnVlO1xuXG5cdFx0Zm9yICh2YXIgb3JkZXIgPSB0aGlzLl9kcmF3Rmlyc3Q7IG9yZGVyOyBvcmRlciA9IG9yZGVyLm5leHQpIHtcblx0XHRcdGxheWVyID0gb3JkZXIubGF5ZXI7XG5cdFx0XHRpZiAoIWJvdW5kcyB8fCAobGF5ZXIuX3B4Qm91bmRzICYmIGxheWVyLl9weEJvdW5kcy5pbnRlcnNlY3RzKGJvdW5kcykpKSB7XG5cdFx0XHRcdGxheWVyLl91cGRhdGVQYXRoKCk7XG5cdFx0XHR9XG5cdFx0fVxuXG5cdFx0dGhpcy5fZHJhd2luZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5fY3R4LnJlc3RvcmUoKTsgIC8vIFJlc3RvcmUgc3RhdGUgYmVmb3JlIGNsaXBwaW5nLlxuXHR9LFxuXG5cdF91cGRhdGVQb2x5OiBmdW5jdGlvbiAobGF5ZXIsIGNsb3NlZCkge1xuXHRcdGlmICghdGhpcy5fZHJhd2luZykgeyByZXR1cm47IH1cblxuXHRcdHZhciBpLCBqLCBsZW4yLCBwLFxuXHRcdCAgICBwYXJ0cyA9IGxheWVyLl9wYXJ0cyxcblx0XHQgICAgbGVuID0gcGFydHMubGVuZ3RoLFxuXHRcdCAgICBjdHggPSB0aGlzLl9jdHg7XG5cblx0XHRpZiAoIWxlbikgeyByZXR1cm47IH1cblxuXHRcdHRoaXMuX2RyYXduTGF5ZXJzW2xheWVyLl9sZWFmbGV0X2lkXSA9IGxheWVyO1xuXG5cdFx0Y3R4LmJlZ2luUGF0aCgpO1xuXG5cdFx0aWYgKGN0eC5zZXRMaW5lRGFzaCkge1xuXHRcdFx0Y3R4LnNldExpbmVEYXNoKGxheWVyLm9wdGlvbnMgJiYgbGF5ZXIub3B0aW9ucy5fZGFzaEFycmF5IHx8IFtdKTtcblx0XHR9XG5cblx0XHRmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdGZvciAoaiA9IDAsIGxlbjIgPSBwYXJ0c1tpXS5sZW5ndGg7IGogPCBsZW4yOyBqKyspIHtcblx0XHRcdFx0cCA9IHBhcnRzW2ldW2pdO1xuXHRcdFx0XHRjdHhbaiA/ICdsaW5lVG8nIDogJ21vdmVUbyddKHAueCwgcC55KTtcblx0XHRcdH1cblx0XHRcdGlmIChjbG9zZWQpIHtcblx0XHRcdFx0Y3R4LmNsb3NlUGF0aCgpO1xuXHRcdFx0fVxuXHRcdH1cblxuXHRcdHRoaXMuX2ZpbGxTdHJva2UoY3R4LCBsYXllcik7XG5cblx0XHQvLyBUT0RPIG9wdGltaXphdGlvbjogMSBmaWxsL3N0cm9rZSBmb3IgYWxsIGZlYXR1cmVzIHdpdGggZXF1YWwgc3R5bGUgaW5zdGVhZCBvZiAxIGZvciBlYWNoIGZlYXR1cmVcblx0fSxcblxuXHRfdXBkYXRlQ2lyY2xlOiBmdW5jdGlvbiAobGF5ZXIpIHtcblxuXHRcdGlmICghdGhpcy5fZHJhd2luZyB8fCBsYXllci5fZW1wdHkoKSkgeyByZXR1cm47IH1cblxuXHRcdHZhciBwID0gbGF5ZXIuX3BvaW50LFxuXHRcdCAgICBjdHggPSB0aGlzLl9jdHgsXG5cdFx0ICAgIHIgPSBsYXllci5fcmFkaXVzLFxuXHRcdCAgICBzID0gKGxheWVyLl9yYWRpdXNZIHx8IHIpIC8gcjtcblxuXHRcdHRoaXMuX2RyYXduTGF5ZXJzW2xheWVyLl9sZWFmbGV0X2lkXSA9IGxheWVyO1xuXG5cdFx0aWYgKHMgIT09IDEpIHtcblx0XHRcdGN0eC5zYXZlKCk7XG5cdFx0XHRjdHguc2NhbGUoMSwgcyk7XG5cdFx0fVxuXG5cdFx0Y3R4LmJlZ2luUGF0aCgpO1xuXHRcdGN0eC5hcmMocC54LCBwLnkgLyBzLCByLCAwLCBNYXRoLlBJICogMiwgZmFsc2UpO1xuXG5cdFx0aWYgKHMgIT09IDEpIHtcblx0XHRcdGN0eC5yZXN0b3JlKCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fZmlsbFN0cm9rZShjdHgsIGxheWVyKTtcblx0fSxcblxuXHRfZmlsbFN0cm9rZTogZnVuY3Rpb24gKGN0eCwgbGF5ZXIpIHtcblx0XHR2YXIgb3B0aW9ucyA9IGxheWVyLm9wdGlvbnM7XG5cblx0XHRpZiAob3B0aW9ucy5maWxsKSB7XG5cdFx0XHRjdHguZ2xvYmFsQWxwaGEgPSBvcHRpb25zLmZpbGxPcGFjaXR5O1xuXHRcdFx0Y3R4LmZpbGxTdHlsZSA9IG9wdGlvbnMuZmlsbENvbG9yIHx8IG9wdGlvbnMuY29sb3I7XG5cdFx0XHRjdHguZmlsbChvcHRpb25zLmZpbGxSdWxlIHx8ICdldmVub2RkJyk7XG5cdFx0fVxuXG5cdFx0aWYgKG9wdGlvbnMuc3Ryb2tlICYmIG9wdGlvbnMud2VpZ2h0ICE9PSAwKSB7XG5cdFx0XHRjdHguZ2xvYmFsQWxwaGEgPSBvcHRpb25zLm9wYWNpdHk7XG5cdFx0XHRjdHgubGluZVdpZHRoID0gb3B0aW9ucy53ZWlnaHQ7XG5cdFx0XHRjdHguc3Ryb2tlU3R5bGUgPSBvcHRpb25zLmNvbG9yO1xuXHRcdFx0Y3R4LmxpbmVDYXAgPSBvcHRpb25zLmxpbmVDYXA7XG5cdFx0XHRjdHgubGluZUpvaW4gPSBvcHRpb25zLmxpbmVKb2luO1xuXHRcdFx0Y3R4LnN0cm9rZSgpO1xuXHRcdH1cblx0fSxcblxuXHQvLyBDYW52YXMgb2J2aW91c2x5IGRvZXNuJ3QgaGF2ZSBtb3VzZSBldmVudHMgZm9yIGluZGl2aWR1YWwgZHJhd24gb2JqZWN0cyxcblx0Ly8gc28gd2UgZW11bGF0ZSB0aGF0IGJ5IGNhbGN1bGF0aW5nIHdoYXQncyB1bmRlciB0aGUgbW91c2Ugb24gbW91c2Vtb3ZlL2NsaWNrIG1hbnVhbGx5XG5cblx0X29uQ2xpY2s6IGZ1bmN0aW9uIChlKSB7XG5cdFx0dmFyIHBvaW50ID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0xheWVyUG9pbnQoZSksIGxheWVyLCBjbGlja2VkTGF5ZXI7XG5cblx0XHRmb3IgKHZhciBvcmRlciA9IHRoaXMuX2RyYXdGaXJzdDsgb3JkZXI7IG9yZGVyID0gb3JkZXIubmV4dCkge1xuXHRcdFx0bGF5ZXIgPSBvcmRlci5sYXllcjtcblx0XHRcdGlmIChsYXllci5vcHRpb25zLmludGVyYWN0aXZlICYmIGxheWVyLl9jb250YWluc1BvaW50KHBvaW50KSAmJiAhdGhpcy5fbWFwLl9kcmFnZ2FibGVNb3ZlZChsYXllcikpIHtcblx0XHRcdFx0Y2xpY2tlZExheWVyID0gbGF5ZXI7XG5cdFx0XHR9XG5cdFx0fVxuXHRcdGlmIChjbGlja2VkTGF5ZXIpICB7XG5cdFx0XHRMLkRvbUV2ZW50Ll9mYWtlU3RvcChlKTtcblx0XHRcdHRoaXMuX2ZpcmVFdmVudChbY2xpY2tlZExheWVyXSwgZSk7XG5cdFx0fVxuXHR9LFxuXG5cdF9vbk1vdXNlTW92ZTogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAoIXRoaXMuX21hcCB8fCB0aGlzLl9tYXAuZHJhZ2dpbmcubW92aW5nKCkgfHwgdGhpcy5fbWFwLl9hbmltYXRpbmdab29tKSB7IHJldHVybjsgfVxuXG5cdFx0dmFyIHBvaW50ID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0xheWVyUG9pbnQoZSk7XG5cdFx0dGhpcy5faGFuZGxlTW91c2VIb3ZlcihlLCBwb2ludCk7XG5cdH0sXG5cblxuXHRfaGFuZGxlTW91c2VPdXQ6IGZ1bmN0aW9uIChlKSB7XG5cdFx0dmFyIGxheWVyID0gdGhpcy5faG92ZXJlZExheWVyO1xuXHRcdGlmIChsYXllcikge1xuXHRcdFx0Ly8gaWYgd2UncmUgbGVhdmluZyB0aGUgbGF5ZXIsIGZpcmUgbW91c2VvdXRcblx0XHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl9jb250YWluZXIsICdsZWFmbGV0LWludGVyYWN0aXZlJyk7XG5cdFx0XHR0aGlzLl9maXJlRXZlbnQoW2xheWVyXSwgZSwgJ21vdXNlb3V0Jyk7XG5cdFx0XHR0aGlzLl9ob3ZlcmVkTGF5ZXIgPSBudWxsO1xuXHRcdH1cblx0fSxcblxuXHRfaGFuZGxlTW91c2VIb3ZlcjogZnVuY3Rpb24gKGUsIHBvaW50KSB7XG5cdFx0dmFyIGxheWVyLCBjYW5kaWRhdGVIb3ZlcmVkTGF5ZXI7XG5cblx0XHRmb3IgKHZhciBvcmRlciA9IHRoaXMuX2RyYXdGaXJzdDsgb3JkZXI7IG9yZGVyID0gb3JkZXIubmV4dCkge1xuXHRcdFx0bGF5ZXIgPSBvcmRlci5sYXllcjtcblx0XHRcdGlmIChsYXllci5vcHRpb25zLmludGVyYWN0aXZlICYmIGxheWVyLl9jb250YWluc1BvaW50KHBvaW50KSkge1xuXHRcdFx0XHRjYW5kaWRhdGVIb3ZlcmVkTGF5ZXIgPSBsYXllcjtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAoY2FuZGlkYXRlSG92ZXJlZExheWVyICE9PSB0aGlzLl9ob3ZlcmVkTGF5ZXIpIHtcblx0XHRcdHRoaXMuX2hhbmRsZU1vdXNlT3V0KGUpO1xuXG5cdFx0XHRpZiAoY2FuZGlkYXRlSG92ZXJlZExheWVyKSB7XG5cdFx0XHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9jb250YWluZXIsICdsZWFmbGV0LWludGVyYWN0aXZlJyk7IC8vIGNoYW5nZSBjdXJzb3Jcblx0XHRcdFx0dGhpcy5fZmlyZUV2ZW50KFtjYW5kaWRhdGVIb3ZlcmVkTGF5ZXJdLCBlLCAnbW91c2VvdmVyJyk7XG5cdFx0XHRcdHRoaXMuX2hvdmVyZWRMYXllciA9IGNhbmRpZGF0ZUhvdmVyZWRMYXllcjtcblx0XHRcdH1cblx0XHR9XG5cblx0XHRpZiAodGhpcy5faG92ZXJlZExheWVyKSB7XG5cdFx0XHR0aGlzLl9maXJlRXZlbnQoW3RoaXMuX2hvdmVyZWRMYXllcl0sIGUpO1xuXHRcdH1cblx0fSxcblxuXHRfZmlyZUV2ZW50OiBmdW5jdGlvbiAobGF5ZXJzLCBlLCB0eXBlKSB7XG5cdFx0dGhpcy5fbWFwLl9maXJlRE9NRXZlbnQoZSwgdHlwZSB8fCBlLnR5cGUsIGxheWVycyk7XG5cdH0sXG5cblx0X2JyaW5nVG9Gcm9udDogZnVuY3Rpb24gKGxheWVyKSB7XG5cdFx0dmFyIG9yZGVyID0gbGF5ZXIuX29yZGVyO1xuXHRcdHZhciBuZXh0ID0gb3JkZXIubmV4dDtcblx0XHR2YXIgcHJldiA9IG9yZGVyLnByZXY7XG5cblx0XHRpZiAobmV4dCkge1xuXHRcdFx0bmV4dC5wcmV2ID0gcHJldjtcblx0XHR9IGVsc2Uge1xuXHRcdFx0Ly8gQWxyZWFkeSBsYXN0XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmIChwcmV2KSB7XG5cdFx0XHRwcmV2Lm5leHQgPSBuZXh0O1xuXHRcdH0gZWxzZSBpZiAobmV4dCkge1xuXHRcdFx0Ly8gVXBkYXRlIGZpcnN0IGVudHJ5IHVubGVzcyB0aGlzIGlzIHRoZVxuXHRcdFx0Ly8gc2lnbmxlIGVudHJ5XG5cdFx0XHR0aGlzLl9kcmF3Rmlyc3QgPSBuZXh0O1xuXHRcdH1cblxuXHRcdG9yZGVyLnByZXYgPSB0aGlzLl9kcmF3TGFzdDtcblx0XHR0aGlzLl9kcmF3TGFzdC5uZXh0ID0gb3JkZXI7XG5cblx0XHRvcmRlci5uZXh0ID0gbnVsbDtcblx0XHR0aGlzLl9kcmF3TGFzdCA9IG9yZGVyO1xuXG5cdFx0dGhpcy5fcmVxdWVzdFJlZHJhdyhsYXllcik7XG5cdH0sXG5cblx0X2JyaW5nVG9CYWNrOiBmdW5jdGlvbiAobGF5ZXIpIHtcblx0XHR2YXIgb3JkZXIgPSBsYXllci5fb3JkZXI7XG5cdFx0dmFyIG5leHQgPSBvcmRlci5uZXh0O1xuXHRcdHZhciBwcmV2ID0gb3JkZXIucHJldjtcblxuXHRcdGlmIChwcmV2KSB7XG5cdFx0XHRwcmV2Lm5leHQgPSBuZXh0O1xuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBBbHJlYWR5IGZpcnN0XG5cdFx0XHRyZXR1cm47XG5cdFx0fVxuXHRcdGlmIChuZXh0KSB7XG5cdFx0XHRuZXh0LnByZXYgPSBwcmV2O1xuXHRcdH0gZWxzZSBpZiAocHJldikge1xuXHRcdFx0Ly8gVXBkYXRlIGxhc3QgZW50cnkgdW5sZXNzIHRoaXMgaXMgdGhlXG5cdFx0XHQvLyBzaWdubGUgZW50cnlcblx0XHRcdHRoaXMuX2RyYXdMYXN0ID0gcHJldjtcblx0XHR9XG5cblx0XHRvcmRlci5wcmV2ID0gbnVsbDtcblxuXHRcdG9yZGVyLm5leHQgPSB0aGlzLl9kcmF3Rmlyc3Q7XG5cdFx0dGhpcy5fZHJhd0ZpcnN0LnByZXYgPSBvcmRlcjtcblx0XHR0aGlzLl9kcmF3Rmlyc3QgPSBvcmRlcjtcblxuXHRcdHRoaXMuX3JlcXVlc3RSZWRyYXcobGF5ZXIpO1xuXHR9XG59KTtcblxuLy8gQG5hbWVzcGFjZSBCcm93c2VyOyBAcHJvcGVydHkgY2FudmFzOiBCb29sZWFuXG4vLyBgdHJ1ZWAgd2hlbiB0aGUgYnJvd3NlciBzdXBwb3J0cyBbYDxjYW52YXM+YF0oaHR0cHM6Ly9kZXZlbG9wZXIubW96aWxsYS5vcmcvZG9jcy9XZWIvQVBJL0NhbnZhc19BUEkpLlxuTC5Ccm93c2VyLmNhbnZhcyA9IChmdW5jdGlvbiAoKSB7XG5cdHJldHVybiAhIWRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpLmdldENvbnRleHQ7XG59KCkpO1xuXG4vLyBAbmFtZXNwYWNlIENhbnZhc1xuLy8gQGZhY3RvcnkgTC5jYW52YXMob3B0aW9ucz86IFJlbmRlcmVyIG9wdGlvbnMpXG4vLyBDcmVhdGVzIGEgQ2FudmFzIHJlbmRlcmVyIHdpdGggdGhlIGdpdmVuIG9wdGlvbnMuXG5MLmNhbnZhcyA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG5cdHJldHVybiBMLkJyb3dzZXIuY2FudmFzID8gbmV3IEwuQ2FudmFzKG9wdGlvbnMpIDogbnVsbDtcbn07XG5cbkwuUG9seWxpbmUucHJvdG90eXBlLl9jb250YWluc1BvaW50ID0gZnVuY3Rpb24gKHAsIGNsb3NlZCkge1xuXHR2YXIgaSwgaiwgaywgbGVuLCBsZW4yLCBwYXJ0LFxuXHQgICAgdyA9IHRoaXMuX2NsaWNrVG9sZXJhbmNlKCk7XG5cblx0aWYgKCF0aGlzLl9weEJvdW5kcy5jb250YWlucyhwKSkgeyByZXR1cm4gZmFsc2U7IH1cblxuXHQvLyBoaXQgZGV0ZWN0aW9uIGZvciBwb2x5bGluZXNcblx0Zm9yIChpID0gMCwgbGVuID0gdGhpcy5fcGFydHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRwYXJ0ID0gdGhpcy5fcGFydHNbaV07XG5cblx0XHRmb3IgKGogPSAwLCBsZW4yID0gcGFydC5sZW5ndGgsIGsgPSBsZW4yIC0gMTsgaiA8IGxlbjI7IGsgPSBqKyspIHtcblx0XHRcdGlmICghY2xvc2VkICYmIChqID09PSAwKSkgeyBjb250aW51ZTsgfVxuXG5cdFx0XHRpZiAoTC5MaW5lVXRpbC5wb2ludFRvU2VnbWVudERpc3RhbmNlKHAsIHBhcnRba10sIHBhcnRbal0pIDw9IHcpIHtcblx0XHRcdFx0cmV0dXJuIHRydWU7XG5cdFx0XHR9XG5cdFx0fVxuXHR9XG5cdHJldHVybiBmYWxzZTtcbn07XG5cbkwuUG9seWdvbi5wcm90b3R5cGUuX2NvbnRhaW5zUG9pbnQgPSBmdW5jdGlvbiAocCkge1xuXHR2YXIgaW5zaWRlID0gZmFsc2UsXG5cdCAgICBwYXJ0LCBwMSwgcDIsIGksIGosIGssIGxlbiwgbGVuMjtcblxuXHRpZiAoIXRoaXMuX3B4Qm91bmRzLmNvbnRhaW5zKHApKSB7IHJldHVybiBmYWxzZTsgfVxuXG5cdC8vIHJheSBjYXN0aW5nIGFsZ29yaXRobSBmb3IgZGV0ZWN0aW5nIGlmIHBvaW50IGlzIGluIHBvbHlnb25cblx0Zm9yIChpID0gMCwgbGVuID0gdGhpcy5fcGFydHMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRwYXJ0ID0gdGhpcy5fcGFydHNbaV07XG5cblx0XHRmb3IgKGogPSAwLCBsZW4yID0gcGFydC5sZW5ndGgsIGsgPSBsZW4yIC0gMTsgaiA8IGxlbjI7IGsgPSBqKyspIHtcblx0XHRcdHAxID0gcGFydFtqXTtcblx0XHRcdHAyID0gcGFydFtrXTtcblxuXHRcdFx0aWYgKCgocDEueSA+IHAueSkgIT09IChwMi55ID4gcC55KSkgJiYgKHAueCA8IChwMi54IC0gcDEueCkgKiAocC55IC0gcDEueSkgLyAocDIueSAtIHAxLnkpICsgcDEueCkpIHtcblx0XHRcdFx0aW5zaWRlID0gIWluc2lkZTtcblx0XHRcdH1cblx0XHR9XG5cdH1cblxuXHQvLyBhbHNvIGNoZWNrIGlmIGl0J3Mgb24gcG9seWdvbiBzdHJva2Vcblx0cmV0dXJuIGluc2lkZSB8fCBMLlBvbHlsaW5lLnByb3RvdHlwZS5fY29udGFpbnNQb2ludC5jYWxsKHRoaXMsIHAsIHRydWUpO1xufTtcblxuTC5DaXJjbGVNYXJrZXIucHJvdG90eXBlLl9jb250YWluc1BvaW50ID0gZnVuY3Rpb24gKHApIHtcblx0cmV0dXJuIHAuZGlzdGFuY2VUbyh0aGlzLl9wb2ludCkgPD0gdGhpcy5fcmFkaXVzICsgdGhpcy5fY2xpY2tUb2xlcmFuY2UoKTtcbn07XG5cblxuXG4vKlxyXG4gKiBAY2xhc3MgR2VvSlNPTlxyXG4gKiBAYWthIEwuR2VvSlNPTlxyXG4gKiBAaW5oZXJpdHMgRmVhdHVyZUdyb3VwXHJcbiAqXHJcbiAqIFJlcHJlc2VudHMgYSBHZW9KU09OIG9iamVjdCBvciBhbiBhcnJheSBvZiBHZW9KU09OIG9iamVjdHMuIEFsbG93cyB5b3UgdG8gcGFyc2VcclxuICogR2VvSlNPTiBkYXRhIGFuZCBkaXNwbGF5IGl0IG9uIHRoZSBtYXAuIEV4dGVuZHMgYEZlYXR1cmVHcm91cGAuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqXHJcbiAqIGBgYGpzXHJcbiAqIEwuZ2VvSlNPTihkYXRhLCB7XHJcbiAqIFx0c3R5bGU6IGZ1bmN0aW9uIChmZWF0dXJlKSB7XHJcbiAqIFx0XHRyZXR1cm4ge2NvbG9yOiBmZWF0dXJlLnByb3BlcnRpZXMuY29sb3J9O1xyXG4gKiBcdH1cclxuICogfSkuYmluZFBvcHVwKGZ1bmN0aW9uIChsYXllcikge1xyXG4gKiBcdHJldHVybiBsYXllci5mZWF0dXJlLnByb3BlcnRpZXMuZGVzY3JpcHRpb247XHJcbiAqIH0pLmFkZFRvKG1hcCk7XHJcbiAqIGBgYFxyXG4gKi9cclxuXHJcbkwuR2VvSlNPTiA9IEwuRmVhdHVyZUdyb3VwLmV4dGVuZCh7XHJcblxyXG5cdC8qIEBzZWN0aW9uXHJcblx0ICogQGFrYSBHZW9KU09OIG9wdGlvbnNcclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gcG9pbnRUb0xheWVyOiBGdW5jdGlvbiA9ICpcclxuXHQgKiBBIGBGdW5jdGlvbmAgZGVmaW5pbmcgaG93IEdlb0pTT04gcG9pbnRzIHNwYXduIExlYWZsZXQgbGF5ZXJzLiBJdCBpcyBpbnRlcm5hbGx5XHJcblx0ICogY2FsbGVkIHdoZW4gZGF0YSBpcyBhZGRlZCwgcGFzc2luZyB0aGUgR2VvSlNPTiBwb2ludCBmZWF0dXJlIGFuZCBpdHMgYExhdExuZ2AuXHJcblx0ICogVGhlIGRlZmF1bHQgaXMgdG8gc3Bhd24gYSBkZWZhdWx0IGBNYXJrZXJgOlxyXG5cdCAqIGBgYGpzXHJcblx0ICogZnVuY3Rpb24oZ2VvSnNvblBvaW50LCBsYXRsbmcpIHtcclxuXHQgKiBcdHJldHVybiBMLm1hcmtlcihsYXRsbmcpO1xyXG5cdCAqIH1cclxuXHQgKiBgYGBcclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gc3R5bGU6IEZ1bmN0aW9uID0gKlxyXG5cdCAqIEEgYEZ1bmN0aW9uYCBkZWZpbmluZyB0aGUgYFBhdGggb3B0aW9uc2AgZm9yIHN0eWxpbmcgR2VvSlNPTiBsaW5lcyBhbmQgcG9seWdvbnMsXHJcblx0ICogY2FsbGVkIGludGVybmFsbHkgd2hlbiBkYXRhIGlzIGFkZGVkLlxyXG5cdCAqIFRoZSBkZWZhdWx0IHZhbHVlIGlzIHRvIG5vdCBvdmVycmlkZSBhbnkgZGVmYXVsdHM6XHJcblx0ICogYGBganNcclxuXHQgKiBmdW5jdGlvbiAoZ2VvSnNvbkZlYXR1cmUpIHtcclxuXHQgKiBcdHJldHVybiB7fVxyXG5cdCAqIH1cclxuXHQgKiBgYGBcclxuXHQgKlxyXG5cdCAqIEBvcHRpb24gb25FYWNoRmVhdHVyZTogRnVuY3Rpb24gPSAqXHJcblx0ICogQSBgRnVuY3Rpb25gIHRoYXQgd2lsbCBiZSBjYWxsZWQgb25jZSBmb3IgZWFjaCBjcmVhdGVkIGBGZWF0dXJlYCwgYWZ0ZXIgaXQgaGFzXHJcblx0ICogYmVlbiBjcmVhdGVkIGFuZCBzdHlsZWQuIFVzZWZ1bCBmb3IgYXR0YWNoaW5nIGV2ZW50cyBhbmQgcG9wdXBzIHRvIGZlYXR1cmVzLlxyXG5cdCAqIFRoZSBkZWZhdWx0IGlzIHRvIGRvIG5vdGhpbmcgd2l0aCB0aGUgbmV3bHkgY3JlYXRlZCBsYXllcnM6XHJcblx0ICogYGBganNcclxuXHQgKiBmdW5jdGlvbiAoZmVhdHVyZSwgbGF5ZXIpIHt9XHJcblx0ICogYGBgXHJcblx0ICpcclxuXHQgKiBAb3B0aW9uIGZpbHRlcjogRnVuY3Rpb24gPSAqXHJcblx0ICogQSBgRnVuY3Rpb25gIHRoYXQgd2lsbCBiZSB1c2VkIHRvIGRlY2lkZSB3aGV0aGVyIHRvIGluY2x1ZGUgYSBmZWF0dXJlIG9yIG5vdC5cclxuXHQgKiBUaGUgZGVmYXVsdCBpcyB0byBpbmNsdWRlIGFsbCBmZWF0dXJlczpcclxuXHQgKiBgYGBqc1xyXG5cdCAqIGZ1bmN0aW9uIChnZW9Kc29uRmVhdHVyZSkge1xyXG5cdCAqIFx0cmV0dXJuIHRydWU7XHJcblx0ICogfVxyXG5cdCAqIGBgYFxyXG5cdCAqIE5vdGU6IGR5bmFtaWNhbGx5IGNoYW5naW5nIHRoZSBgZmlsdGVyYCBvcHRpb24gd2lsbCBoYXZlIGVmZmVjdCBvbmx5IG9uIG5ld2x5XHJcblx0ICogYWRkZWQgZGF0YS4gSXQgd2lsbCBfbm90XyByZS1ldmFsdWF0ZSBhbHJlYWR5IGluY2x1ZGVkIGZlYXR1cmVzLlxyXG5cdCAqXHJcblx0ICogQG9wdGlvbiBjb29yZHNUb0xhdExuZzogRnVuY3Rpb24gPSAqXHJcblx0ICogQSBgRnVuY3Rpb25gIHRoYXQgd2lsbCBiZSB1c2VkIGZvciBjb252ZXJ0aW5nIEdlb0pTT04gY29vcmRpbmF0ZXMgdG8gYExhdExuZ2BzLlxyXG5cdCAqIFRoZSBkZWZhdWx0IGlzIHRoZSBgY29vcmRzVG9MYXRMbmdgIHN0YXRpYyBtZXRob2QuXHJcblx0ICovXHJcblxyXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChnZW9qc29uLCBvcHRpb25zKSB7XHJcblx0XHRMLnNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XHJcblxyXG5cdFx0dGhpcy5fbGF5ZXJzID0ge307XHJcblxyXG5cdFx0aWYgKGdlb2pzb24pIHtcclxuXHRcdFx0dGhpcy5hZGREYXRhKGdlb2pzb24pO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgYWRkRGF0YSggPEdlb0pTT04+IGRhdGEgKTogdGhpc1xyXG5cdC8vIEFkZHMgYSBHZW9KU09OIG9iamVjdCB0byB0aGUgbGF5ZXIuXHJcblx0YWRkRGF0YTogZnVuY3Rpb24gKGdlb2pzb24pIHtcclxuXHRcdHZhciBmZWF0dXJlcyA9IEwuVXRpbC5pc0FycmF5KGdlb2pzb24pID8gZ2VvanNvbiA6IGdlb2pzb24uZmVhdHVyZXMsXHJcblx0XHQgICAgaSwgbGVuLCBmZWF0dXJlO1xyXG5cclxuXHRcdGlmIChmZWF0dXJlcykge1xyXG5cdFx0XHRmb3IgKGkgPSAwLCBsZW4gPSBmZWF0dXJlcy5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xyXG5cdFx0XHRcdC8vIG9ubHkgYWRkIHRoaXMgaWYgZ2VvbWV0cnkgb3IgZ2VvbWV0cmllcyBhcmUgc2V0IGFuZCBub3QgbnVsbFxyXG5cdFx0XHRcdGZlYXR1cmUgPSBmZWF0dXJlc1tpXTtcclxuXHRcdFx0XHRpZiAoZmVhdHVyZS5nZW9tZXRyaWVzIHx8IGZlYXR1cmUuZ2VvbWV0cnkgfHwgZmVhdHVyZS5mZWF0dXJlcyB8fCBmZWF0dXJlLmNvb3JkaW5hdGVzKSB7XHJcblx0XHRcdFx0XHR0aGlzLmFkZERhdGEoZmVhdHVyZSk7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiB0aGlzO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBvcHRpb25zID0gdGhpcy5vcHRpb25zO1xyXG5cclxuXHRcdGlmIChvcHRpb25zLmZpbHRlciAmJiAhb3B0aW9ucy5maWx0ZXIoZ2VvanNvbikpIHsgcmV0dXJuIHRoaXM7IH1cclxuXHJcblx0XHR2YXIgbGF5ZXIgPSBMLkdlb0pTT04uZ2VvbWV0cnlUb0xheWVyKGdlb2pzb24sIG9wdGlvbnMpO1xyXG5cdFx0aWYgKCFsYXllcikge1xyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHRcdH1cclxuXHRcdGxheWVyLmZlYXR1cmUgPSBMLkdlb0pTT04uYXNGZWF0dXJlKGdlb2pzb24pO1xyXG5cclxuXHRcdGxheWVyLmRlZmF1bHRPcHRpb25zID0gbGF5ZXIub3B0aW9ucztcclxuXHRcdHRoaXMucmVzZXRTdHlsZShsYXllcik7XHJcblxyXG5cdFx0aWYgKG9wdGlvbnMub25FYWNoRmVhdHVyZSkge1xyXG5cdFx0XHRvcHRpb25zLm9uRWFjaEZlYXR1cmUoZ2VvanNvbiwgbGF5ZXIpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB0aGlzLmFkZExheWVyKGxheWVyKTtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlc2V0U3R5bGUoIDxQYXRoPiBsYXllciApOiB0aGlzXHJcblx0Ly8gUmVzZXRzIHRoZSBnaXZlbiB2ZWN0b3IgbGF5ZXIncyBzdHlsZSB0byB0aGUgb3JpZ2luYWwgR2VvSlNPTiBzdHlsZSwgdXNlZnVsIGZvciByZXNldHRpbmcgc3R5bGUgYWZ0ZXIgaG92ZXIgZXZlbnRzLlxyXG5cdHJlc2V0U3R5bGU6IGZ1bmN0aW9uIChsYXllcikge1xyXG5cdFx0Ly8gcmVzZXQgYW55IGN1c3RvbSBzdHlsZXNcclxuXHRcdGxheWVyLm9wdGlvbnMgPSBMLlV0aWwuZXh0ZW5kKHt9LCBsYXllci5kZWZhdWx0T3B0aW9ucyk7XHJcblx0XHR0aGlzLl9zZXRMYXllclN0eWxlKGxheWVyLCB0aGlzLm9wdGlvbnMuc3R5bGUpO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBzZXRTdHlsZSggPEZ1bmN0aW9uPiBzdHlsZSApOiB0aGlzXHJcblx0Ly8gQ2hhbmdlcyBzdHlsZXMgb2YgR2VvSlNPTiB2ZWN0b3IgbGF5ZXJzIHdpdGggdGhlIGdpdmVuIHN0eWxlIGZ1bmN0aW9uLlxyXG5cdHNldFN0eWxlOiBmdW5jdGlvbiAoc3R5bGUpIHtcclxuXHRcdHJldHVybiB0aGlzLmVhY2hMYXllcihmdW5jdGlvbiAobGF5ZXIpIHtcclxuXHRcdFx0dGhpcy5fc2V0TGF5ZXJTdHlsZShsYXllciwgc3R5bGUpO1xyXG5cdFx0fSwgdGhpcyk7XHJcblx0fSxcclxuXHJcblx0X3NldExheWVyU3R5bGU6IGZ1bmN0aW9uIChsYXllciwgc3R5bGUpIHtcclxuXHRcdGlmICh0eXBlb2Ygc3R5bGUgPT09ICdmdW5jdGlvbicpIHtcclxuXHRcdFx0c3R5bGUgPSBzdHlsZShsYXllci5mZWF0dXJlKTtcclxuXHRcdH1cclxuXHRcdGlmIChsYXllci5zZXRTdHlsZSkge1xyXG5cdFx0XHRsYXllci5zZXRTdHlsZShzdHlsZSk7XHJcblx0XHR9XHJcblx0fVxyXG59KTtcclxuXHJcbi8vIEBzZWN0aW9uXHJcbi8vIFRoZXJlIGFyZSBzZXZlcmFsIHN0YXRpYyBmdW5jdGlvbnMgd2hpY2ggY2FuIGJlIGNhbGxlZCB3aXRob3V0IGluc3RhbnRpYXRpbmcgTC5HZW9KU09OOlxyXG5MLmV4dGVuZChMLkdlb0pTT04sIHtcclxuXHQvLyBAZnVuY3Rpb24gZ2VvbWV0cnlUb0xheWVyKGZlYXR1cmVEYXRhOiBPYmplY3QsIG9wdGlvbnM/OiBHZW9KU09OIG9wdGlvbnMpOiBMYXllclxyXG5cdC8vIENyZWF0ZXMgYSBgTGF5ZXJgIGZyb20gYSBnaXZlbiBHZW9KU09OIGZlYXR1cmUuIENhbiB1c2UgYSBjdXN0b21cclxuXHQvLyBbYHBvaW50VG9MYXllcmBdKCNnZW9qc29uLXBvaW50dG9sYXllcikgYW5kL29yIFtgY29vcmRzVG9MYXRMbmdgXSgjZ2VvanNvbi1jb29yZHN0b2xhdGxuZylcclxuXHQvLyBmdW5jdGlvbnMgaWYgcHJvdmlkZWQgYXMgb3B0aW9ucy5cclxuXHRnZW9tZXRyeVRvTGF5ZXI6IGZ1bmN0aW9uIChnZW9qc29uLCBvcHRpb25zKSB7XHJcblxyXG5cdFx0dmFyIGdlb21ldHJ5ID0gZ2VvanNvbi50eXBlID09PSAnRmVhdHVyZScgPyBnZW9qc29uLmdlb21ldHJ5IDogZ2VvanNvbixcclxuXHRcdCAgICBjb29yZHMgPSBnZW9tZXRyeSA/IGdlb21ldHJ5LmNvb3JkaW5hdGVzIDogbnVsbCxcclxuXHRcdCAgICBsYXllcnMgPSBbXSxcclxuXHRcdCAgICBwb2ludFRvTGF5ZXIgPSBvcHRpb25zICYmIG9wdGlvbnMucG9pbnRUb0xheWVyLFxyXG5cdFx0ICAgIGNvb3Jkc1RvTGF0TG5nID0gb3B0aW9ucyAmJiBvcHRpb25zLmNvb3Jkc1RvTGF0TG5nIHx8IHRoaXMuY29vcmRzVG9MYXRMbmcsXHJcblx0XHQgICAgbGF0bG5nLCBsYXRsbmdzLCBpLCBsZW47XHJcblxyXG5cdFx0aWYgKCFjb29yZHMgJiYgIWdlb21ldHJ5KSB7XHJcblx0XHRcdHJldHVybiBudWxsO1xyXG5cdFx0fVxyXG5cclxuXHRcdHN3aXRjaCAoZ2VvbWV0cnkudHlwZSkge1xyXG5cdFx0Y2FzZSAnUG9pbnQnOlxyXG5cdFx0XHRsYXRsbmcgPSBjb29yZHNUb0xhdExuZyhjb29yZHMpO1xyXG5cdFx0XHRyZXR1cm4gcG9pbnRUb0xheWVyID8gcG9pbnRUb0xheWVyKGdlb2pzb24sIGxhdGxuZykgOiBuZXcgTC5NYXJrZXIobGF0bG5nKTtcclxuXHJcblx0XHRjYXNlICdNdWx0aVBvaW50JzpcclxuXHRcdFx0Zm9yIChpID0gMCwgbGVuID0gY29vcmRzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdFx0bGF0bG5nID0gY29vcmRzVG9MYXRMbmcoY29vcmRzW2ldKTtcclxuXHRcdFx0XHRsYXllcnMucHVzaChwb2ludFRvTGF5ZXIgPyBwb2ludFRvTGF5ZXIoZ2VvanNvbiwgbGF0bG5nKSA6IG5ldyBMLk1hcmtlcihsYXRsbmcpKTtcclxuXHRcdFx0fVxyXG5cdFx0XHRyZXR1cm4gbmV3IEwuRmVhdHVyZUdyb3VwKGxheWVycyk7XHJcblxyXG5cdFx0Y2FzZSAnTGluZVN0cmluZyc6XHJcblx0XHRjYXNlICdNdWx0aUxpbmVTdHJpbmcnOlxyXG5cdFx0XHRsYXRsbmdzID0gdGhpcy5jb29yZHNUb0xhdExuZ3MoY29vcmRzLCBnZW9tZXRyeS50eXBlID09PSAnTGluZVN0cmluZycgPyAwIDogMSwgY29vcmRzVG9MYXRMbmcpO1xyXG5cdFx0XHRyZXR1cm4gbmV3IEwuUG9seWxpbmUobGF0bG5ncywgb3B0aW9ucyk7XHJcblxyXG5cdFx0Y2FzZSAnUG9seWdvbic6XHJcblx0XHRjYXNlICdNdWx0aVBvbHlnb24nOlxyXG5cdFx0XHRsYXRsbmdzID0gdGhpcy5jb29yZHNUb0xhdExuZ3MoY29vcmRzLCBnZW9tZXRyeS50eXBlID09PSAnUG9seWdvbicgPyAxIDogMiwgY29vcmRzVG9MYXRMbmcpO1xyXG5cdFx0XHRyZXR1cm4gbmV3IEwuUG9seWdvbihsYXRsbmdzLCBvcHRpb25zKTtcclxuXHJcblx0XHRjYXNlICdHZW9tZXRyeUNvbGxlY3Rpb24nOlxyXG5cdFx0XHRmb3IgKGkgPSAwLCBsZW4gPSBnZW9tZXRyeS5nZW9tZXRyaWVzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdFx0dmFyIGxheWVyID0gdGhpcy5nZW9tZXRyeVRvTGF5ZXIoe1xyXG5cdFx0XHRcdFx0Z2VvbWV0cnk6IGdlb21ldHJ5Lmdlb21ldHJpZXNbaV0sXHJcblx0XHRcdFx0XHR0eXBlOiAnRmVhdHVyZScsXHJcblx0XHRcdFx0XHRwcm9wZXJ0aWVzOiBnZW9qc29uLnByb3BlcnRpZXNcclxuXHRcdFx0XHR9LCBvcHRpb25zKTtcclxuXHJcblx0XHRcdFx0aWYgKGxheWVyKSB7XHJcblx0XHRcdFx0XHRsYXllcnMucHVzaChsYXllcik7XHJcblx0XHRcdFx0fVxyXG5cdFx0XHR9XHJcblx0XHRcdHJldHVybiBuZXcgTC5GZWF0dXJlR3JvdXAobGF5ZXJzKTtcclxuXHJcblx0XHRkZWZhdWx0OlxyXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgR2VvSlNPTiBvYmplY3QuJyk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQGZ1bmN0aW9uIGNvb3Jkc1RvTGF0TG5nKGNvb3JkczogQXJyYXkpOiBMYXRMbmdcclxuXHQvLyBDcmVhdGVzIGEgYExhdExuZ2Agb2JqZWN0IGZyb20gYW4gYXJyYXkgb2YgMiBudW1iZXJzIChsb25naXR1ZGUsIGxhdGl0dWRlKVxyXG5cdC8vIG9yIDMgbnVtYmVycyAobG9uZ2l0dWRlLCBsYXRpdHVkZSwgYWx0aXR1ZGUpIHVzZWQgaW4gR2VvSlNPTiBmb3IgcG9pbnRzLlxyXG5cdGNvb3Jkc1RvTGF0TG5nOiBmdW5jdGlvbiAoY29vcmRzKSB7XHJcblx0XHRyZXR1cm4gbmV3IEwuTGF0TG5nKGNvb3Jkc1sxXSwgY29vcmRzWzBdLCBjb29yZHNbMl0pO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBjb29yZHNUb0xhdExuZ3MoY29vcmRzOiBBcnJheSwgbGV2ZWxzRGVlcD86IE51bWJlciwgY29vcmRzVG9MYXRMbmc/OiBGdW5jdGlvbik6IEFycmF5XHJcblx0Ly8gQ3JlYXRlcyBhIG11bHRpZGltZW5zaW9uYWwgYXJyYXkgb2YgYExhdExuZ2BzIGZyb20gYSBHZW9KU09OIGNvb3JkaW5hdGVzIGFycmF5LlxyXG5cdC8vIGBsZXZlbHNEZWVwYCBzcGVjaWZpZXMgdGhlIG5lc3RpbmcgbGV2ZWwgKDAgaXMgZm9yIGFuIGFycmF5IG9mIHBvaW50cywgMSBmb3IgYW4gYXJyYXkgb2YgYXJyYXlzIG9mIHBvaW50cywgZXRjLiwgMCBieSBkZWZhdWx0KS5cclxuXHQvLyBDYW4gdXNlIGEgY3VzdG9tIFtgY29vcmRzVG9MYXRMbmdgXSgjZ2VvanNvbi1jb29yZHN0b2xhdGxuZykgZnVuY3Rpb24uXHJcblx0Y29vcmRzVG9MYXRMbmdzOiBmdW5jdGlvbiAoY29vcmRzLCBsZXZlbHNEZWVwLCBjb29yZHNUb0xhdExuZykge1xyXG5cdFx0dmFyIGxhdGxuZ3MgPSBbXTtcclxuXHJcblx0XHRmb3IgKHZhciBpID0gMCwgbGVuID0gY29vcmRzLmxlbmd0aCwgbGF0bG5nOyBpIDwgbGVuOyBpKyspIHtcclxuXHRcdFx0bGF0bG5nID0gbGV2ZWxzRGVlcCA/XHJcblx0XHRcdCAgICAgICAgdGhpcy5jb29yZHNUb0xhdExuZ3MoY29vcmRzW2ldLCBsZXZlbHNEZWVwIC0gMSwgY29vcmRzVG9MYXRMbmcpIDpcclxuXHRcdFx0ICAgICAgICAoY29vcmRzVG9MYXRMbmcgfHwgdGhpcy5jb29yZHNUb0xhdExuZykoY29vcmRzW2ldKTtcclxuXHJcblx0XHRcdGxhdGxuZ3MucHVzaChsYXRsbmcpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBsYXRsbmdzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBsYXRMbmdUb0Nvb3JkcyhsYXRsbmc6IExhdExuZyk6IEFycmF5XHJcblx0Ly8gUmV2ZXJzZSBvZiBbYGNvb3Jkc1RvTGF0TG5nYF0oI2dlb2pzb24tY29vcmRzdG9sYXRsbmcpXHJcblx0bGF0TG5nVG9Db29yZHM6IGZ1bmN0aW9uIChsYXRsbmcpIHtcclxuXHRcdHJldHVybiBsYXRsbmcuYWx0ICE9PSB1bmRlZmluZWQgP1xyXG5cdFx0XHRcdFtsYXRsbmcubG5nLCBsYXRsbmcubGF0LCBsYXRsbmcuYWx0XSA6XHJcblx0XHRcdFx0W2xhdGxuZy5sbmcsIGxhdGxuZy5sYXRdO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBsYXRMbmdzVG9Db29yZHMobGF0bG5nczogQXJyYXksIGxldmVsc0RlZXA/OiBOdW1iZXIsIGNsb3NlZD86IEJvb2xlYW4pOiBBcnJheVxyXG5cdC8vIFJldmVyc2Ugb2YgW2Bjb29yZHNUb0xhdExuZ3NgXSgjZ2VvanNvbi1jb29yZHN0b2xhdGxuZ3MpXHJcblx0Ly8gYGNsb3NlZGAgZGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBmaXJzdCBwb2ludCBzaG91bGQgYmUgYXBwZW5kZWQgdG8gdGhlIGVuZCBvZiB0aGUgYXJyYXkgdG8gY2xvc2UgdGhlIGZlYXR1cmUsIG9ubHkgdXNlZCB3aGVuIGBsZXZlbHNEZWVwYCBpcyAwLiBGYWxzZSBieSBkZWZhdWx0LlxyXG5cdGxhdExuZ3NUb0Nvb3JkczogZnVuY3Rpb24gKGxhdGxuZ3MsIGxldmVsc0RlZXAsIGNsb3NlZCkge1xyXG5cdFx0dmFyIGNvb3JkcyA9IFtdO1xyXG5cclxuXHRcdGZvciAodmFyIGkgPSAwLCBsZW4gPSBsYXRsbmdzLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XHJcblx0XHRcdGNvb3Jkcy5wdXNoKGxldmVsc0RlZXAgP1xyXG5cdFx0XHRcdEwuR2VvSlNPTi5sYXRMbmdzVG9Db29yZHMobGF0bG5nc1tpXSwgbGV2ZWxzRGVlcCAtIDEsIGNsb3NlZCkgOlxyXG5cdFx0XHRcdEwuR2VvSlNPTi5sYXRMbmdUb0Nvb3JkcyhsYXRsbmdzW2ldKSk7XHJcblx0XHR9XHJcblxyXG5cdFx0aWYgKCFsZXZlbHNEZWVwICYmIGNsb3NlZCkge1xyXG5cdFx0XHRjb29yZHMucHVzaChjb29yZHNbMF0pO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiBjb29yZHM7XHJcblx0fSxcclxuXHJcblx0Z2V0RmVhdHVyZTogZnVuY3Rpb24gKGxheWVyLCBuZXdHZW9tZXRyeSkge1xyXG5cdFx0cmV0dXJuIGxheWVyLmZlYXR1cmUgP1xyXG5cdFx0XHRcdEwuZXh0ZW5kKHt9LCBsYXllci5mZWF0dXJlLCB7Z2VvbWV0cnk6IG5ld0dlb21ldHJ5fSkgOlxyXG5cdFx0XHRcdEwuR2VvSlNPTi5hc0ZlYXR1cmUobmV3R2VvbWV0cnkpO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBmdW5jdGlvbiBhc0ZlYXR1cmUoZ2VvanNvbjogT2JqZWN0KTogT2JqZWN0XHJcblx0Ly8gTm9ybWFsaXplIEdlb0pTT04gZ2VvbWV0cmllcy9mZWF0dXJlcyBpbnRvIEdlb0pTT04gZmVhdHVyZXMuXHJcblx0YXNGZWF0dXJlOiBmdW5jdGlvbiAoZ2VvanNvbikge1xyXG5cdFx0aWYgKGdlb2pzb24udHlwZSA9PT0gJ0ZlYXR1cmUnIHx8IGdlb2pzb24udHlwZSA9PT0gJ0ZlYXR1cmVDb2xsZWN0aW9uJykge1xyXG5cdFx0XHRyZXR1cm4gZ2VvanNvbjtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4ge1xyXG5cdFx0XHR0eXBlOiAnRmVhdHVyZScsXHJcblx0XHRcdHByb3BlcnRpZXM6IHt9LFxyXG5cdFx0XHRnZW9tZXRyeTogZ2VvanNvblxyXG5cdFx0fTtcclxuXHR9XHJcbn0pO1xyXG5cclxudmFyIFBvaW50VG9HZW9KU09OID0ge1xyXG5cdHRvR2VvSlNPTjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIEwuR2VvSlNPTi5nZXRGZWF0dXJlKHRoaXMsIHtcclxuXHRcdFx0dHlwZTogJ1BvaW50JyxcclxuXHRcdFx0Y29vcmRpbmF0ZXM6IEwuR2VvSlNPTi5sYXRMbmdUb0Nvb3Jkcyh0aGlzLmdldExhdExuZygpKVxyXG5cdFx0fSk7XHJcblx0fVxyXG59O1xyXG5cclxuLy8gQG5hbWVzcGFjZSBNYXJrZXJcclxuLy8gQG1ldGhvZCB0b0dlb0pTT04oKTogT2JqZWN0XHJcbi8vIFJldHVybnMgYSBbYEdlb0pTT05gXShodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0dlb0pTT04pIHJlcHJlc2VudGF0aW9uIG9mIHRoZSBtYXJrZXIgKGFzIGEgR2VvSlNPTiBgUG9pbnRgIEZlYXR1cmUpLlxyXG5MLk1hcmtlci5pbmNsdWRlKFBvaW50VG9HZW9KU09OKTtcclxuXHJcbi8vIEBuYW1lc3BhY2UgQ2lyY2xlTWFya2VyXHJcbi8vIEBtZXRob2QgdG9HZW9KU09OKCk6IE9iamVjdFxyXG4vLyBSZXR1cm5zIGEgW2BHZW9KU09OYF0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9HZW9KU09OKSByZXByZXNlbnRhdGlvbiBvZiB0aGUgY2lyY2xlIG1hcmtlciAoYXMgYSBHZW9KU09OIGBQb2ludGAgRmVhdHVyZSkuXHJcbkwuQ2lyY2xlLmluY2x1ZGUoUG9pbnRUb0dlb0pTT04pO1xyXG5MLkNpcmNsZU1hcmtlci5pbmNsdWRlKFBvaW50VG9HZW9KU09OKTtcclxuXHJcblxyXG4vLyBAbmFtZXNwYWNlIFBvbHlsaW5lXHJcbi8vIEBtZXRob2QgdG9HZW9KU09OKCk6IE9iamVjdFxyXG4vLyBSZXR1cm5zIGEgW2BHZW9KU09OYF0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9HZW9KU09OKSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcG9seWxpbmUgKGFzIGEgR2VvSlNPTiBgTGluZVN0cmluZ2Agb3IgYE11bHRpTGluZVN0cmluZ2AgRmVhdHVyZSkuXHJcbkwuUG9seWxpbmUucHJvdG90eXBlLnRvR2VvSlNPTiA9IGZ1bmN0aW9uICgpIHtcclxuXHR2YXIgbXVsdGkgPSAhTC5Qb2x5bGluZS5fZmxhdCh0aGlzLl9sYXRsbmdzKTtcclxuXHJcblx0dmFyIGNvb3JkcyA9IEwuR2VvSlNPTi5sYXRMbmdzVG9Db29yZHModGhpcy5fbGF0bG5ncywgbXVsdGkgPyAxIDogMCk7XHJcblxyXG5cdHJldHVybiBMLkdlb0pTT04uZ2V0RmVhdHVyZSh0aGlzLCB7XHJcblx0XHR0eXBlOiAobXVsdGkgPyAnTXVsdGknIDogJycpICsgJ0xpbmVTdHJpbmcnLFxyXG5cdFx0Y29vcmRpbmF0ZXM6IGNvb3Jkc1xyXG5cdH0pO1xyXG59O1xyXG5cclxuLy8gQG5hbWVzcGFjZSBQb2x5Z29uXHJcbi8vIEBtZXRob2QgdG9HZW9KU09OKCk6IE9iamVjdFxyXG4vLyBSZXR1cm5zIGEgW2BHZW9KU09OYF0oaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9HZW9KU09OKSByZXByZXNlbnRhdGlvbiBvZiB0aGUgcG9seWdvbiAoYXMgYSBHZW9KU09OIGBQb2x5Z29uYCBvciBgTXVsdGlQb2x5Z29uYCBGZWF0dXJlKS5cclxuTC5Qb2x5Z29uLnByb3RvdHlwZS50b0dlb0pTT04gPSBmdW5jdGlvbiAoKSB7XHJcblx0dmFyIGhvbGVzID0gIUwuUG9seWxpbmUuX2ZsYXQodGhpcy5fbGF0bG5ncyksXHJcblx0ICAgIG11bHRpID0gaG9sZXMgJiYgIUwuUG9seWxpbmUuX2ZsYXQodGhpcy5fbGF0bG5nc1swXSk7XHJcblxyXG5cdHZhciBjb29yZHMgPSBMLkdlb0pTT04ubGF0TG5nc1RvQ29vcmRzKHRoaXMuX2xhdGxuZ3MsIG11bHRpID8gMiA6IGhvbGVzID8gMSA6IDAsIHRydWUpO1xyXG5cclxuXHRpZiAoIWhvbGVzKSB7XHJcblx0XHRjb29yZHMgPSBbY29vcmRzXTtcclxuXHR9XHJcblxyXG5cdHJldHVybiBMLkdlb0pTT04uZ2V0RmVhdHVyZSh0aGlzLCB7XHJcblx0XHR0eXBlOiAobXVsdGkgPyAnTXVsdGknIDogJycpICsgJ1BvbHlnb24nLFxyXG5cdFx0Y29vcmRpbmF0ZXM6IGNvb3Jkc1xyXG5cdH0pO1xyXG59O1xyXG5cclxuXHJcbi8vIEBuYW1lc3BhY2UgTGF5ZXJHcm91cFxyXG5MLkxheWVyR3JvdXAuaW5jbHVkZSh7XHJcblx0dG9NdWx0aVBvaW50OiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgY29vcmRzID0gW107XHJcblxyXG5cdFx0dGhpcy5lYWNoTGF5ZXIoZnVuY3Rpb24gKGxheWVyKSB7XHJcblx0XHRcdGNvb3Jkcy5wdXNoKGxheWVyLnRvR2VvSlNPTigpLmdlb21ldHJ5LmNvb3JkaW5hdGVzKTtcclxuXHRcdH0pO1xyXG5cclxuXHRcdHJldHVybiBMLkdlb0pTT04uZ2V0RmVhdHVyZSh0aGlzLCB7XHJcblx0XHRcdHR5cGU6ICdNdWx0aVBvaW50JyxcclxuXHRcdFx0Y29vcmRpbmF0ZXM6IGNvb3Jkc1xyXG5cdFx0fSk7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCB0b0dlb0pTT04oKTogT2JqZWN0XHJcblx0Ly8gUmV0dXJucyBhIFtgR2VvSlNPTmBdKGh0dHA6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvR2VvSlNPTikgcmVwcmVzZW50YXRpb24gb2YgdGhlIGxheWVyIGdyb3VwIChhcyBhIEdlb0pTT04gYEdlb21ldHJ5Q29sbGVjdGlvbmApLlxyXG5cdHRvR2VvSlNPTjogZnVuY3Rpb24gKCkge1xyXG5cclxuXHRcdHZhciB0eXBlID0gdGhpcy5mZWF0dXJlICYmIHRoaXMuZmVhdHVyZS5nZW9tZXRyeSAmJiB0aGlzLmZlYXR1cmUuZ2VvbWV0cnkudHlwZTtcclxuXHJcblx0XHRpZiAodHlwZSA9PT0gJ011bHRpUG9pbnQnKSB7XHJcblx0XHRcdHJldHVybiB0aGlzLnRvTXVsdGlQb2ludCgpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBpc0dlb21ldHJ5Q29sbGVjdGlvbiA9IHR5cGUgPT09ICdHZW9tZXRyeUNvbGxlY3Rpb24nLFxyXG5cdFx0ICAgIGpzb25zID0gW107XHJcblxyXG5cdFx0dGhpcy5lYWNoTGF5ZXIoZnVuY3Rpb24gKGxheWVyKSB7XHJcblx0XHRcdGlmIChsYXllci50b0dlb0pTT04pIHtcclxuXHRcdFx0XHR2YXIganNvbiA9IGxheWVyLnRvR2VvSlNPTigpO1xyXG5cdFx0XHRcdGpzb25zLnB1c2goaXNHZW9tZXRyeUNvbGxlY3Rpb24gPyBqc29uLmdlb21ldHJ5IDogTC5HZW9KU09OLmFzRmVhdHVyZShqc29uKSk7XHJcblx0XHRcdH1cclxuXHRcdH0pO1xyXG5cclxuXHRcdGlmIChpc0dlb21ldHJ5Q29sbGVjdGlvbikge1xyXG5cdFx0XHRyZXR1cm4gTC5HZW9KU09OLmdldEZlYXR1cmUodGhpcywge1xyXG5cdFx0XHRcdGdlb21ldHJpZXM6IGpzb25zLFxyXG5cdFx0XHRcdHR5cGU6ICdHZW9tZXRyeUNvbGxlY3Rpb24nXHJcblx0XHRcdH0pO1xyXG5cdFx0fVxyXG5cclxuXHRcdHJldHVybiB7XHJcblx0XHRcdHR5cGU6ICdGZWF0dXJlQ29sbGVjdGlvbicsXHJcblx0XHRcdGZlYXR1cmVzOiBqc29uc1xyXG5cdFx0fTtcclxuXHR9XHJcbn0pO1xyXG5cclxuLy8gQG5hbWVzcGFjZSBHZW9KU09OXHJcbi8vIEBmYWN0b3J5IEwuZ2VvSlNPTihnZW9qc29uPzogT2JqZWN0LCBvcHRpb25zPzogR2VvSlNPTiBvcHRpb25zKVxyXG4vLyBDcmVhdGVzIGEgR2VvSlNPTiBsYXllci4gT3B0aW9uYWxseSBhY2NlcHRzIGFuIG9iamVjdCBpblxyXG4vLyBbR2VvSlNPTiBmb3JtYXRdKGh0dHA6Ly9nZW9qc29uLm9yZy9nZW9qc29uLXNwZWMuaHRtbCkgdG8gZGlzcGxheSBvbiB0aGUgbWFwXHJcbi8vICh5b3UgY2FuIGFsdGVybmF0aXZlbHkgYWRkIGl0IGxhdGVyIHdpdGggYGFkZERhdGFgIG1ldGhvZCkgYW5kIGFuIGBvcHRpb25zYCBvYmplY3QuXHJcbkwuZ2VvSlNPTiA9IGZ1bmN0aW9uIChnZW9qc29uLCBvcHRpb25zKSB7XHJcblx0cmV0dXJuIG5ldyBMLkdlb0pTT04oZ2VvanNvbiwgb3B0aW9ucyk7XHJcbn07XHJcbi8vIEJhY2t3YXJkIGNvbXBhdGliaWxpdHkuXHJcbkwuZ2VvSnNvbiA9IEwuZ2VvSlNPTjtcclxuXG5cblxuLypcclxuICogQGNsYXNzIERyYWdnYWJsZVxyXG4gKiBAYWthIEwuRHJhZ2dhYmxlXHJcbiAqIEBpbmhlcml0cyBFdmVudGVkXHJcbiAqXHJcbiAqIEEgY2xhc3MgZm9yIG1ha2luZyBET00gZWxlbWVudHMgZHJhZ2dhYmxlIChpbmNsdWRpbmcgdG91Y2ggc3VwcG9ydCkuXHJcbiAqIFVzZWQgaW50ZXJuYWxseSBmb3IgbWFwIGFuZCBtYXJrZXIgZHJhZ2dpbmcuIE9ubHkgd29ya3MgZm9yIGVsZW1lbnRzXHJcbiAqIHRoYXQgd2VyZSBwb3NpdGlvbmVkIHdpdGggW2BMLkRvbVV0aWwuc2V0UG9zaXRpb25gXSgjZG9tdXRpbC1zZXRwb3NpdGlvbikuXHJcbiAqXHJcbiAqIEBleGFtcGxlXHJcbiAqIGBgYGpzXHJcbiAqIHZhciBkcmFnZ2FibGUgPSBuZXcgTC5EcmFnZ2FibGUoZWxlbWVudFRvRHJhZyk7XHJcbiAqIGRyYWdnYWJsZS5lbmFibGUoKTtcclxuICogYGBgXHJcbiAqL1xyXG5cclxuTC5EcmFnZ2FibGUgPSBMLkV2ZW50ZWQuZXh0ZW5kKHtcclxuXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQG9wdGlvbiBjbGlja1RvbGVyYW5jZTogTnVtYmVyID0gM1xyXG5cdFx0Ly8gVGhlIG1heCBudW1iZXIgb2YgcGl4ZWxzIGEgdXNlciBjYW4gc2hpZnQgdGhlIG1vdXNlIHBvaW50ZXIgZHVyaW5nIGEgY2xpY2tcclxuXHRcdC8vIGZvciBpdCB0byBiZSBjb25zaWRlcmVkIGEgdmFsaWQgY2xpY2sgKGFzIG9wcG9zZWQgdG8gYSBtb3VzZSBkcmFnKS5cclxuXHRcdGNsaWNrVG9sZXJhbmNlOiAzXHJcblx0fSxcclxuXHJcblx0c3RhdGljczoge1xyXG5cdFx0U1RBUlQ6IEwuQnJvd3Nlci50b3VjaCA/IFsndG91Y2hzdGFydCcsICdtb3VzZWRvd24nXSA6IFsnbW91c2Vkb3duJ10sXHJcblx0XHRFTkQ6IHtcclxuXHRcdFx0bW91c2Vkb3duOiAnbW91c2V1cCcsXHJcblx0XHRcdHRvdWNoc3RhcnQ6ICd0b3VjaGVuZCcsXHJcblx0XHRcdHBvaW50ZXJkb3duOiAndG91Y2hlbmQnLFxyXG5cdFx0XHRNU1BvaW50ZXJEb3duOiAndG91Y2hlbmQnXHJcblx0XHR9LFxyXG5cdFx0TU9WRToge1xyXG5cdFx0XHRtb3VzZWRvd246ICdtb3VzZW1vdmUnLFxyXG5cdFx0XHR0b3VjaHN0YXJ0OiAndG91Y2htb3ZlJyxcclxuXHRcdFx0cG9pbnRlcmRvd246ICd0b3VjaG1vdmUnLFxyXG5cdFx0XHRNU1BvaW50ZXJEb3duOiAndG91Y2htb3ZlJ1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdC8vIEBjb25zdHJ1Y3RvciBMLkRyYWdnYWJsZShlbDogSFRNTEVsZW1lbnQsIGRyYWdIYW5kbGU/OiBIVE1MRWxlbWVudCwgcHJldmVudE91dGxpbmU6IEJvb2xlYW4pXHJcblx0Ly8gQ3JlYXRlcyBhIGBEcmFnZ2FibGVgIG9iamVjdCBmb3IgbW92aW5nIGBlbGAgd2hlbiB5b3Ugc3RhcnQgZHJhZ2dpbmcgdGhlIGBkcmFnSGFuZGxlYCBlbGVtZW50IChlcXVhbHMgYGVsYCBpdHNlbGYgYnkgZGVmYXVsdCkuXHJcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKGVsZW1lbnQsIGRyYWdTdGFydFRhcmdldCwgcHJldmVudE91dGxpbmUpIHtcclxuXHRcdHRoaXMuX2VsZW1lbnQgPSBlbGVtZW50O1xyXG5cdFx0dGhpcy5fZHJhZ1N0YXJ0VGFyZ2V0ID0gZHJhZ1N0YXJ0VGFyZ2V0IHx8IGVsZW1lbnQ7XHJcblx0XHR0aGlzLl9wcmV2ZW50T3V0bGluZSA9IHByZXZlbnRPdXRsaW5lO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZW5hYmxlKClcclxuXHQvLyBFbmFibGVzIHRoZSBkcmFnZ2luZyBhYmlsaXR5XHJcblx0ZW5hYmxlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAodGhpcy5fZW5hYmxlZCkgeyByZXR1cm47IH1cclxuXHJcblx0XHRMLkRvbUV2ZW50Lm9uKHRoaXMuX2RyYWdTdGFydFRhcmdldCwgTC5EcmFnZ2FibGUuU1RBUlQuam9pbignICcpLCB0aGlzLl9vbkRvd24sIHRoaXMpO1xyXG5cclxuXHRcdHRoaXMuX2VuYWJsZWQgPSB0cnVlO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZGlzYWJsZSgpXHJcblx0Ly8gRGlzYWJsZXMgdGhlIGRyYWdnaW5nIGFiaWxpdHlcclxuXHRkaXNhYmxlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX2VuYWJsZWQpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0Ly8gSWYgd2UncmUgY3VycmVudGx5IGRyYWdnaW5nIHRoaXMgZHJhZ2dhYmxlLFxyXG5cdFx0Ly8gZGlzYWJsaW5nIGl0IGNvdW50cyBhcyBmaXJzdCBlbmRpbmcgdGhlIGRyYWcuXHJcblx0XHRpZiAoTC5EcmFnZ2FibGUuX2RyYWdnaW5nID09PSB0aGlzKSB7XHJcblx0XHRcdHRoaXMuZmluaXNoRHJhZygpO1xyXG5cdFx0fVxyXG5cclxuXHRcdEwuRG9tRXZlbnQub2ZmKHRoaXMuX2RyYWdTdGFydFRhcmdldCwgTC5EcmFnZ2FibGUuU1RBUlQuam9pbignICcpLCB0aGlzLl9vbkRvd24sIHRoaXMpO1xyXG5cclxuXHRcdHRoaXMuX2VuYWJsZWQgPSBmYWxzZTtcclxuXHRcdHRoaXMuX21vdmVkID0gZmFsc2U7XHJcblx0fSxcclxuXHJcblx0X29uRG93bjogZnVuY3Rpb24gKGUpIHtcclxuXHRcdC8vIElnbm9yZSBzaW11bGF0ZWQgZXZlbnRzLCBzaW5jZSB3ZSBoYW5kbGUgYm90aCB0b3VjaCBhbmRcclxuXHRcdC8vIG1vdXNlIGV4cGxpY2l0bHk7IG90aGVyd2lzZSB3ZSByaXNrIGdldHRpbmcgZHVwbGljYXRlcyBvZlxyXG5cdFx0Ly8gdG91Y2ggZXZlbnRzLCBzZWUgIzQzMTUuXHJcblx0XHQvLyBBbHNvIGlnbm9yZSB0aGUgZXZlbnQgaWYgZGlzYWJsZWQ7IHRoaXMgaGFwcGVucyBpbiBJRTExXHJcblx0XHQvLyB1bmRlciBzb21lIGNpcmN1bXN0YW5jZXMsIHNlZSAjMzY2Ni5cclxuXHRcdGlmIChlLl9zaW11bGF0ZWQgfHwgIXRoaXMuX2VuYWJsZWQpIHsgcmV0dXJuOyB9XHJcblxyXG5cdFx0dGhpcy5fbW92ZWQgPSBmYWxzZTtcclxuXHJcblx0XHRpZiAoTC5Eb21VdGlsLmhhc0NsYXNzKHRoaXMuX2VsZW1lbnQsICdsZWFmbGV0LXpvb20tYW5pbScpKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdGlmIChMLkRyYWdnYWJsZS5fZHJhZ2dpbmcgfHwgZS5zaGlmdEtleSB8fCAoKGUud2hpY2ggIT09IDEpICYmIChlLmJ1dHRvbiAhPT0gMSkgJiYgIWUudG91Y2hlcykpIHsgcmV0dXJuOyB9XHJcblx0XHRMLkRyYWdnYWJsZS5fZHJhZ2dpbmcgPSB0aGlzOyAgLy8gUHJldmVudCBkcmFnZ2luZyBtdWx0aXBsZSBvYmplY3RzIGF0IG9uY2UuXHJcblxyXG5cdFx0aWYgKHRoaXMuX3ByZXZlbnRPdXRsaW5lKSB7XHJcblx0XHRcdEwuRG9tVXRpbC5wcmV2ZW50T3V0bGluZSh0aGlzLl9lbGVtZW50KTtcclxuXHRcdH1cclxuXHJcblx0XHRMLkRvbVV0aWwuZGlzYWJsZUltYWdlRHJhZygpO1xyXG5cdFx0TC5Eb21VdGlsLmRpc2FibGVUZXh0U2VsZWN0aW9uKCk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX21vdmluZykgeyByZXR1cm47IH1cclxuXHJcblx0XHQvLyBAZXZlbnQgZG93bjogRXZlbnRcclxuXHRcdC8vIEZpcmVkIHdoZW4gYSBkcmFnIGlzIGFib3V0IHRvIHN0YXJ0LlxyXG5cdFx0dGhpcy5maXJlKCdkb3duJyk7XHJcblxyXG5cdFx0dmFyIGZpcnN0ID0gZS50b3VjaGVzID8gZS50b3VjaGVzWzBdIDogZTtcclxuXHJcblx0XHR0aGlzLl9zdGFydFBvaW50ID0gbmV3IEwuUG9pbnQoZmlyc3QuY2xpZW50WCwgZmlyc3QuY2xpZW50WSk7XHJcblxyXG5cdFx0TC5Eb21FdmVudFxyXG5cdFx0XHQub24oZG9jdW1lbnQsIEwuRHJhZ2dhYmxlLk1PVkVbZS50eXBlXSwgdGhpcy5fb25Nb3ZlLCB0aGlzKVxyXG5cdFx0XHQub24oZG9jdW1lbnQsIEwuRHJhZ2dhYmxlLkVORFtlLnR5cGVdLCB0aGlzLl9vblVwLCB0aGlzKTtcclxuXHR9LFxyXG5cclxuXHRfb25Nb3ZlOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0Ly8gSWdub3JlIHNpbXVsYXRlZCBldmVudHMsIHNpbmNlIHdlIGhhbmRsZSBib3RoIHRvdWNoIGFuZFxyXG5cdFx0Ly8gbW91c2UgZXhwbGljaXRseTsgb3RoZXJ3aXNlIHdlIHJpc2sgZ2V0dGluZyBkdXBsaWNhdGVzIG9mXHJcblx0XHQvLyB0b3VjaCBldmVudHMsIHNlZSAjNDMxNS5cclxuXHRcdC8vIEFsc28gaWdub3JlIHRoZSBldmVudCBpZiBkaXNhYmxlZDsgdGhpcyBoYXBwZW5zIGluIElFMTFcclxuXHRcdC8vIHVuZGVyIHNvbWUgY2lyY3Vtc3RhbmNlcywgc2VlICMzNjY2LlxyXG5cdFx0aWYgKGUuX3NpbXVsYXRlZCB8fCAhdGhpcy5fZW5hYmxlZCkgeyByZXR1cm47IH1cclxuXHJcblx0XHRpZiAoZS50b3VjaGVzICYmIGUudG91Y2hlcy5sZW5ndGggPiAxKSB7XHJcblx0XHRcdHRoaXMuX21vdmVkID0gdHJ1ZTtcclxuXHRcdFx0cmV0dXJuO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBmaXJzdCA9IChlLnRvdWNoZXMgJiYgZS50b3VjaGVzLmxlbmd0aCA9PT0gMSA/IGUudG91Y2hlc1swXSA6IGUpLFxyXG5cdFx0ICAgIG5ld1BvaW50ID0gbmV3IEwuUG9pbnQoZmlyc3QuY2xpZW50WCwgZmlyc3QuY2xpZW50WSksXHJcblx0XHQgICAgb2Zmc2V0ID0gbmV3UG9pbnQuc3VidHJhY3QodGhpcy5fc3RhcnRQb2ludCk7XHJcblxyXG5cdFx0aWYgKCFvZmZzZXQueCAmJiAhb2Zmc2V0LnkpIHsgcmV0dXJuOyB9XHJcblx0XHRpZiAoTWF0aC5hYnMob2Zmc2V0LngpICsgTWF0aC5hYnMob2Zmc2V0LnkpIDwgdGhpcy5vcHRpb25zLmNsaWNrVG9sZXJhbmNlKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdEwuRG9tRXZlbnQucHJldmVudERlZmF1bHQoZSk7XHJcblxyXG5cdFx0aWYgKCF0aGlzLl9tb3ZlZCkge1xyXG5cdFx0XHQvLyBAZXZlbnQgZHJhZ3N0YXJ0OiBFdmVudFxyXG5cdFx0XHQvLyBGaXJlZCB3aGVuIGEgZHJhZyBzdGFydHNcclxuXHRcdFx0dGhpcy5maXJlKCdkcmFnc3RhcnQnKTtcclxuXHJcblx0XHRcdHRoaXMuX21vdmVkID0gdHJ1ZTtcclxuXHRcdFx0dGhpcy5fc3RhcnRQb3MgPSBMLkRvbVV0aWwuZ2V0UG9zaXRpb24odGhpcy5fZWxlbWVudCkuc3VidHJhY3Qob2Zmc2V0KTtcclxuXHJcblx0XHRcdEwuRG9tVXRpbC5hZGRDbGFzcyhkb2N1bWVudC5ib2R5LCAnbGVhZmxldC1kcmFnZ2luZycpO1xyXG5cclxuXHRcdFx0dGhpcy5fbGFzdFRhcmdldCA9IGUudGFyZ2V0IHx8IGUuc3JjRWxlbWVudDtcclxuXHRcdFx0Ly8gSUUgYW5kIEVkZ2UgZG8gbm90IGdpdmUgdGhlIDx1c2U+IGVsZW1lbnQsIHNvIGZldGNoIGl0XHJcblx0XHRcdC8vIGlmIG5lY2Vzc2FyeVxyXG5cdFx0XHRpZiAoKHdpbmRvdy5TVkdFbGVtZW50SW5zdGFuY2UpICYmICh0aGlzLl9sYXN0VGFyZ2V0IGluc3RhbmNlb2YgU1ZHRWxlbWVudEluc3RhbmNlKSkge1xyXG5cdFx0XHRcdHRoaXMuX2xhc3RUYXJnZXQgPSB0aGlzLl9sYXN0VGFyZ2V0LmNvcnJlc3BvbmRpbmdVc2VFbGVtZW50O1xyXG5cdFx0XHR9XHJcblx0XHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9sYXN0VGFyZ2V0LCAnbGVhZmxldC1kcmFnLXRhcmdldCcpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX25ld1BvcyA9IHRoaXMuX3N0YXJ0UG9zLmFkZChvZmZzZXQpO1xyXG5cdFx0dGhpcy5fbW92aW5nID0gdHJ1ZTtcclxuXHJcblx0XHRMLlV0aWwuY2FuY2VsQW5pbUZyYW1lKHRoaXMuX2FuaW1SZXF1ZXN0KTtcclxuXHRcdHRoaXMuX2xhc3RFdmVudCA9IGU7XHJcblx0XHR0aGlzLl9hbmltUmVxdWVzdCA9IEwuVXRpbC5yZXF1ZXN0QW5pbUZyYW1lKHRoaXMuX3VwZGF0ZVBvc2l0aW9uLCB0aGlzLCB0cnVlKTtcclxuXHR9LFxyXG5cclxuXHRfdXBkYXRlUG9zaXRpb246IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBlID0ge29yaWdpbmFsRXZlbnQ6IHRoaXMuX2xhc3RFdmVudH07XHJcblxyXG5cdFx0Ly8gQGV2ZW50IHByZWRyYWc6IEV2ZW50XHJcblx0XHQvLyBGaXJlZCBjb250aW51b3VzbHkgZHVyaW5nIGRyYWdnaW5nICpiZWZvcmUqIGVhY2ggY29ycmVzcG9uZGluZ1xyXG5cdFx0Ly8gdXBkYXRlIG9mIHRoZSBlbGVtZW50J3MgcG9zaXRpb24uXHJcblx0XHR0aGlzLmZpcmUoJ3ByZWRyYWcnLCBlKTtcclxuXHRcdEwuRG9tVXRpbC5zZXRQb3NpdGlvbih0aGlzLl9lbGVtZW50LCB0aGlzLl9uZXdQb3MpO1xyXG5cclxuXHRcdC8vIEBldmVudCBkcmFnOiBFdmVudFxyXG5cdFx0Ly8gRmlyZWQgY29udGludW91c2x5IGR1cmluZyBkcmFnZ2luZy5cclxuXHRcdHRoaXMuZmlyZSgnZHJhZycsIGUpO1xyXG5cdH0sXHJcblxyXG5cdF9vblVwOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0Ly8gSWdub3JlIHNpbXVsYXRlZCBldmVudHMsIHNpbmNlIHdlIGhhbmRsZSBib3RoIHRvdWNoIGFuZFxyXG5cdFx0Ly8gbW91c2UgZXhwbGljaXRseTsgb3RoZXJ3aXNlIHdlIHJpc2sgZ2V0dGluZyBkdXBsaWNhdGVzIG9mXHJcblx0XHQvLyB0b3VjaCBldmVudHMsIHNlZSAjNDMxNS5cclxuXHRcdC8vIEFsc28gaWdub3JlIHRoZSBldmVudCBpZiBkaXNhYmxlZDsgdGhpcyBoYXBwZW5zIGluIElFMTFcclxuXHRcdC8vIHVuZGVyIHNvbWUgY2lyY3Vtc3RhbmNlcywgc2VlICMzNjY2LlxyXG5cdFx0aWYgKGUuX3NpbXVsYXRlZCB8fCAhdGhpcy5fZW5hYmxlZCkgeyByZXR1cm47IH1cclxuXHRcdHRoaXMuZmluaXNoRHJhZygpO1xyXG5cdH0sXHJcblxyXG5cdGZpbmlzaERyYWc6IGZ1bmN0aW9uICgpIHtcclxuXHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyhkb2N1bWVudC5ib2R5LCAnbGVhZmxldC1kcmFnZ2luZycpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9sYXN0VGFyZ2V0KSB7XHJcblx0XHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl9sYXN0VGFyZ2V0LCAnbGVhZmxldC1kcmFnLXRhcmdldCcpO1xyXG5cdFx0XHR0aGlzLl9sYXN0VGFyZ2V0ID0gbnVsbDtcclxuXHRcdH1cclxuXHJcblx0XHRmb3IgKHZhciBpIGluIEwuRHJhZ2dhYmxlLk1PVkUpIHtcclxuXHRcdFx0TC5Eb21FdmVudFxyXG5cdFx0XHRcdC5vZmYoZG9jdW1lbnQsIEwuRHJhZ2dhYmxlLk1PVkVbaV0sIHRoaXMuX29uTW92ZSwgdGhpcylcclxuXHRcdFx0XHQub2ZmKGRvY3VtZW50LCBMLkRyYWdnYWJsZS5FTkRbaV0sIHRoaXMuX29uVXAsIHRoaXMpO1xyXG5cdFx0fVxyXG5cclxuXHRcdEwuRG9tVXRpbC5lbmFibGVJbWFnZURyYWcoKTtcclxuXHRcdEwuRG9tVXRpbC5lbmFibGVUZXh0U2VsZWN0aW9uKCk7XHJcblxyXG5cdFx0aWYgKHRoaXMuX21vdmVkICYmIHRoaXMuX21vdmluZykge1xyXG5cdFx0XHQvLyBlbnN1cmUgZHJhZyBpcyBub3QgZmlyZWQgYWZ0ZXIgZHJhZ2VuZFxyXG5cdFx0XHRMLlV0aWwuY2FuY2VsQW5pbUZyYW1lKHRoaXMuX2FuaW1SZXF1ZXN0KTtcclxuXHJcblx0XHRcdC8vIEBldmVudCBkcmFnZW5kOiBEcmFnRW5kRXZlbnRcclxuXHRcdFx0Ly8gRmlyZWQgd2hlbiB0aGUgZHJhZyBlbmRzLlxyXG5cdFx0XHR0aGlzLmZpcmUoJ2RyYWdlbmQnLCB7XHJcblx0XHRcdFx0ZGlzdGFuY2U6IHRoaXMuX25ld1Bvcy5kaXN0YW5jZVRvKHRoaXMuX3N0YXJ0UG9zKVxyXG5cdFx0XHR9KTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9tb3ZpbmcgPSBmYWxzZTtcclxuXHRcdEwuRHJhZ2dhYmxlLl9kcmFnZ2luZyA9IGZhbHNlO1xyXG5cdH1cclxuXHJcbn0pO1xyXG5cblxuXG4vKlxuXHRMLkhhbmRsZXIgaXMgYSBiYXNlIGNsYXNzIGZvciBoYW5kbGVyIGNsYXNzZXMgdGhhdCBhcmUgdXNlZCBpbnRlcm5hbGx5IHRvIGluamVjdFxuXHRpbnRlcmFjdGlvbiBmZWF0dXJlcyBsaWtlIGRyYWdnaW5nIHRvIGNsYXNzZXMgbGlrZSBNYXAgYW5kIE1hcmtlci5cbiovXG5cbi8vIEBjbGFzcyBIYW5kbGVyXG4vLyBAYWthIEwuSGFuZGxlclxuLy8gQWJzdHJhY3QgY2xhc3MgZm9yIG1hcCBpbnRlcmFjdGlvbiBoYW5kbGVyc1xuXG5MLkhhbmRsZXIgPSBMLkNsYXNzLmV4dGVuZCh7XG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChtYXApIHtcblx0XHR0aGlzLl9tYXAgPSBtYXA7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBlbmFibGUoKTogdGhpc1xuXHQvLyBFbmFibGVzIHRoZSBoYW5kbGVyXG5cdGVuYWJsZTogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9lbmFibGVkKSB7IHJldHVybiB0aGlzOyB9XG5cblx0XHR0aGlzLl9lbmFibGVkID0gdHJ1ZTtcblx0XHR0aGlzLmFkZEhvb2tzKCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0Ly8gQG1ldGhvZCBkaXNhYmxlKCk6IHRoaXNcblx0Ly8gRGlzYWJsZXMgdGhlIGhhbmRsZXJcblx0ZGlzYWJsZTogZnVuY3Rpb24gKCkge1xuXHRcdGlmICghdGhpcy5fZW5hYmxlZCkgeyByZXR1cm4gdGhpczsgfVxuXG5cdFx0dGhpcy5fZW5hYmxlZCA9IGZhbHNlO1xuXHRcdHRoaXMucmVtb3ZlSG9va3MoKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fSxcblxuXHQvLyBAbWV0aG9kIGVuYWJsZWQoKTogQm9vbGVhblxuXHQvLyBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgaGFuZGxlciBpcyBlbmFibGVkXG5cdGVuYWJsZWQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gISF0aGlzLl9lbmFibGVkO1xuXHR9XG5cblx0Ly8gQHNlY3Rpb24gRXh0ZW5zaW9uIG1ldGhvZHNcblx0Ly8gQ2xhc3NlcyBpbmhlcml0aW5nIGZyb20gYEhhbmRsZXJgIG11c3QgaW1wbGVtZW50IHRoZSB0d28gZm9sbG93aW5nIG1ldGhvZHM6XG5cdC8vIEBtZXRob2QgYWRkSG9va3MoKVxuXHQvLyBDYWxsZWQgd2hlbiB0aGUgaGFuZGxlciBpcyBlbmFibGVkLCBzaG91bGQgYWRkIGV2ZW50IGhvb2tzLlxuXHQvLyBAbWV0aG9kIHJlbW92ZUhvb2tzKClcblx0Ly8gQ2FsbGVkIHdoZW4gdGhlIGhhbmRsZXIgaXMgZGlzYWJsZWQsIHNob3VsZCByZW1vdmUgdGhlIGV2ZW50IGhvb2tzIGFkZGVkIHByZXZpb3VzbHkuXG59KTtcblxuXG5cbi8qXG4gKiBMLkhhbmRsZXIuTWFwRHJhZyBpcyB1c2VkIHRvIG1ha2UgdGhlIG1hcCBkcmFnZ2FibGUgKHdpdGggcGFubmluZyBpbmVydGlhKSwgZW5hYmxlZCBieSBkZWZhdWx0LlxuICovXG5cbi8vIEBuYW1lc3BhY2UgTWFwXG4vLyBAc2VjdGlvbiBJbnRlcmFjdGlvbiBPcHRpb25zXG5MLk1hcC5tZXJnZU9wdGlvbnMoe1xuXHQvLyBAb3B0aW9uIGRyYWdnaW5nOiBCb29sZWFuID0gdHJ1ZVxuXHQvLyBXaGV0aGVyIHRoZSBtYXAgYmUgZHJhZ2dhYmxlIHdpdGggbW91c2UvdG91Y2ggb3Igbm90LlxuXHRkcmFnZ2luZzogdHJ1ZSxcblxuXHQvLyBAc2VjdGlvbiBQYW5uaW5nIEluZXJ0aWEgT3B0aW9uc1xuXHQvLyBAb3B0aW9uIGluZXJ0aWE6IEJvb2xlYW4gPSAqXG5cdC8vIElmIGVuYWJsZWQsIHBhbm5pbmcgb2YgdGhlIG1hcCB3aWxsIGhhdmUgYW4gaW5lcnRpYSBlZmZlY3Qgd2hlcmVcblx0Ly8gdGhlIG1hcCBidWlsZHMgbW9tZW50dW0gd2hpbGUgZHJhZ2dpbmcgYW5kIGNvbnRpbnVlcyBtb3ZpbmcgaW5cblx0Ly8gdGhlIHNhbWUgZGlyZWN0aW9uIGZvciBzb21lIHRpbWUuIEZlZWxzIGVzcGVjaWFsbHkgbmljZSBvbiB0b3VjaFxuXHQvLyBkZXZpY2VzLiBFbmFibGVkIGJ5IGRlZmF1bHQgdW5sZXNzIHJ1bm5pbmcgb24gb2xkIEFuZHJvaWQgZGV2aWNlcy5cblx0aW5lcnRpYTogIUwuQnJvd3Nlci5hbmRyb2lkMjMsXG5cblx0Ly8gQG9wdGlvbiBpbmVydGlhRGVjZWxlcmF0aW9uOiBOdW1iZXIgPSAzMDAwXG5cdC8vIFRoZSByYXRlIHdpdGggd2hpY2ggdGhlIGluZXJ0aWFsIG1vdmVtZW50IHNsb3dzIGRvd24sIGluIHBpeGVscy9zZWNvbmTCsi5cblx0aW5lcnRpYURlY2VsZXJhdGlvbjogMzQwMCwgLy8gcHgvc14yXG5cblx0Ly8gQG9wdGlvbiBpbmVydGlhTWF4U3BlZWQ6IE51bWJlciA9IEluZmluaXR5XG5cdC8vIE1heCBzcGVlZCBvZiB0aGUgaW5lcnRpYWwgbW92ZW1lbnQsIGluIHBpeGVscy9zZWNvbmQuXG5cdGluZXJ0aWFNYXhTcGVlZDogSW5maW5pdHksIC8vIHB4L3NcblxuXHQvLyBAb3B0aW9uIGVhc2VMaW5lYXJpdHk6IE51bWJlciA9IDAuMlxuXHRlYXNlTGluZWFyaXR5OiAwLjIsXG5cblx0Ly8gVE9ETyByZWZhY3RvciwgbW92ZSB0byBDUlNcblx0Ly8gQG9wdGlvbiB3b3JsZENvcHlKdW1wOiBCb29sZWFuID0gZmFsc2Vcblx0Ly8gV2l0aCB0aGlzIG9wdGlvbiBlbmFibGVkLCB0aGUgbWFwIHRyYWNrcyB3aGVuIHlvdSBwYW4gdG8gYW5vdGhlciBcImNvcHlcIlxuXHQvLyBvZiB0aGUgd29ybGQgYW5kIHNlYW1sZXNzbHkganVtcHMgdG8gdGhlIG9yaWdpbmFsIG9uZSBzbyB0aGF0IGFsbCBvdmVybGF5c1xuXHQvLyBsaWtlIG1hcmtlcnMgYW5kIHZlY3RvciBsYXllcnMgYXJlIHN0aWxsIHZpc2libGUuXG5cdHdvcmxkQ29weUp1bXA6IGZhbHNlLFxuXG5cdC8vIEBvcHRpb24gbWF4Qm91bmRzVmlzY29zaXR5OiBOdW1iZXIgPSAwLjBcblx0Ly8gSWYgYG1heEJvdW5kc2AgaXMgc2V0LCB0aGlzIG9wdGlvbiB3aWxsIGNvbnRyb2wgaG93IHNvbGlkIHRoZSBib3VuZHNcblx0Ly8gYXJlIHdoZW4gZHJhZ2dpbmcgdGhlIG1hcCBhcm91bmQuIFRoZSBkZWZhdWx0IHZhbHVlIG9mIGAwLjBgIGFsbG93cyB0aGVcblx0Ly8gdXNlciB0byBkcmFnIG91dHNpZGUgdGhlIGJvdW5kcyBhdCBub3JtYWwgc3BlZWQsIGhpZ2hlciB2YWx1ZXMgd2lsbFxuXHQvLyBzbG93IGRvd24gbWFwIGRyYWdnaW5nIG91dHNpZGUgYm91bmRzLCBhbmQgYDEuMGAgbWFrZXMgdGhlIGJvdW5kcyBmdWxseVxuXHQvLyBzb2xpZCwgcHJldmVudGluZyB0aGUgdXNlciBmcm9tIGRyYWdnaW5nIG91dHNpZGUgdGhlIGJvdW5kcy5cblx0bWF4Qm91bmRzVmlzY29zaXR5OiAwLjBcbn0pO1xuXG5MLk1hcC5EcmFnID0gTC5IYW5kbGVyLmV4dGVuZCh7XG5cdGFkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKCF0aGlzLl9kcmFnZ2FibGUpIHtcblx0XHRcdHZhciBtYXAgPSB0aGlzLl9tYXA7XG5cblx0XHRcdHRoaXMuX2RyYWdnYWJsZSA9IG5ldyBMLkRyYWdnYWJsZShtYXAuX21hcFBhbmUsIG1hcC5fY29udGFpbmVyKTtcblxuXHRcdFx0dGhpcy5fZHJhZ2dhYmxlLm9uKHtcblx0XHRcdFx0ZG93bjogdGhpcy5fb25Eb3duLFxuXHRcdFx0XHRkcmFnc3RhcnQ6IHRoaXMuX29uRHJhZ1N0YXJ0LFxuXHRcdFx0XHRkcmFnOiB0aGlzLl9vbkRyYWcsXG5cdFx0XHRcdGRyYWdlbmQ6IHRoaXMuX29uRHJhZ0VuZFxuXHRcdFx0fSwgdGhpcyk7XG5cblx0XHRcdHRoaXMuX2RyYWdnYWJsZS5vbigncHJlZHJhZycsIHRoaXMuX29uUHJlRHJhZ0xpbWl0LCB0aGlzKTtcblx0XHRcdGlmIChtYXAub3B0aW9ucy53b3JsZENvcHlKdW1wKSB7XG5cdFx0XHRcdHRoaXMuX2RyYWdnYWJsZS5vbigncHJlZHJhZycsIHRoaXMuX29uUHJlRHJhZ1dyYXAsIHRoaXMpO1xuXHRcdFx0XHRtYXAub24oJ3pvb21lbmQnLCB0aGlzLl9vblpvb21FbmQsIHRoaXMpO1xuXG5cdFx0XHRcdG1hcC53aGVuUmVhZHkodGhpcy5fb25ab29tRW5kLCB0aGlzKTtcblx0XHRcdH1cblx0XHR9XG5cdFx0TC5Eb21VdGlsLmFkZENsYXNzKHRoaXMuX21hcC5fY29udGFpbmVyLCAnbGVhZmxldC1ncmFiIGxlYWZsZXQtdG91Y2gtZHJhZycpO1xuXHRcdHRoaXMuX2RyYWdnYWJsZS5lbmFibGUoKTtcblx0XHR0aGlzLl9wb3NpdGlvbnMgPSBbXTtcblx0XHR0aGlzLl90aW1lcyA9IFtdO1xuXHR9LFxuXG5cdHJlbW92ZUhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0TC5Eb21VdGlsLnJlbW92ZUNsYXNzKHRoaXMuX21hcC5fY29udGFpbmVyLCAnbGVhZmxldC1ncmFiJyk7XG5cdFx0TC5Eb21VdGlsLnJlbW92ZUNsYXNzKHRoaXMuX21hcC5fY29udGFpbmVyLCAnbGVhZmxldC10b3VjaC1kcmFnJyk7XG5cdFx0dGhpcy5fZHJhZ2dhYmxlLmRpc2FibGUoKTtcblx0fSxcblxuXHRtb3ZlZDogZnVuY3Rpb24gKCkge1xuXHRcdHJldHVybiB0aGlzLl9kcmFnZ2FibGUgJiYgdGhpcy5fZHJhZ2dhYmxlLl9tb3ZlZDtcblx0fSxcblxuXHRtb3Zpbmc6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fZHJhZ2dhYmxlICYmIHRoaXMuX2RyYWdnYWJsZS5fbW92aW5nO1xuXHR9LFxuXG5cdF9vbkRvd246IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9tYXAuX3N0b3AoKTtcblx0fSxcblxuXHRfb25EcmFnU3RhcnQ6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwO1xuXG5cdFx0aWYgKHRoaXMuX21hcC5vcHRpb25zLm1heEJvdW5kcyAmJiB0aGlzLl9tYXAub3B0aW9ucy5tYXhCb3VuZHNWaXNjb3NpdHkpIHtcblx0XHRcdHZhciBib3VuZHMgPSBMLmxhdExuZ0JvdW5kcyh0aGlzLl9tYXAub3B0aW9ucy5tYXhCb3VuZHMpO1xuXG5cdFx0XHR0aGlzLl9vZmZzZXRMaW1pdCA9IEwuYm91bmRzKFxuXHRcdFx0XHR0aGlzLl9tYXAubGF0TG5nVG9Db250YWluZXJQb2ludChib3VuZHMuZ2V0Tm9ydGhXZXN0KCkpLm11bHRpcGx5QnkoLTEpLFxuXHRcdFx0XHR0aGlzLl9tYXAubGF0TG5nVG9Db250YWluZXJQb2ludChib3VuZHMuZ2V0U291dGhFYXN0KCkpLm11bHRpcGx5QnkoLTEpXG5cdFx0XHRcdFx0LmFkZCh0aGlzLl9tYXAuZ2V0U2l6ZSgpKSk7XG5cblx0XHRcdHRoaXMuX3Zpc2Nvc2l0eSA9IE1hdGgubWluKDEuMCwgTWF0aC5tYXgoMC4wLCB0aGlzLl9tYXAub3B0aW9ucy5tYXhCb3VuZHNWaXNjb3NpdHkpKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0dGhpcy5fb2Zmc2V0TGltaXQgPSBudWxsO1xuXHRcdH1cblxuXHRcdG1hcFxuXHRcdCAgICAuZmlyZSgnbW92ZXN0YXJ0Jylcblx0XHQgICAgLmZpcmUoJ2RyYWdzdGFydCcpO1xuXG5cdFx0aWYgKG1hcC5vcHRpb25zLmluZXJ0aWEpIHtcblx0XHRcdHRoaXMuX3Bvc2l0aW9ucyA9IFtdO1xuXHRcdFx0dGhpcy5fdGltZXMgPSBbXTtcblx0XHR9XG5cdH0sXG5cblx0X29uRHJhZzogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAodGhpcy5fbWFwLm9wdGlvbnMuaW5lcnRpYSkge1xuXHRcdFx0dmFyIHRpbWUgPSB0aGlzLl9sYXN0VGltZSA9ICtuZXcgRGF0ZSgpLFxuXHRcdFx0ICAgIHBvcyA9IHRoaXMuX2xhc3RQb3MgPSB0aGlzLl9kcmFnZ2FibGUuX2Fic1BvcyB8fCB0aGlzLl9kcmFnZ2FibGUuX25ld1BvcztcblxuXHRcdFx0dGhpcy5fcG9zaXRpb25zLnB1c2gocG9zKTtcblx0XHRcdHRoaXMuX3RpbWVzLnB1c2godGltZSk7XG5cblx0XHRcdGlmICh0aW1lIC0gdGhpcy5fdGltZXNbMF0gPiA1MCkge1xuXHRcdFx0XHR0aGlzLl9wb3NpdGlvbnMuc2hpZnQoKTtcblx0XHRcdFx0dGhpcy5fdGltZXMuc2hpZnQoKTtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR0aGlzLl9tYXBcblx0XHQgICAgLmZpcmUoJ21vdmUnLCBlKVxuXHRcdCAgICAuZmlyZSgnZHJhZycsIGUpO1xuXHR9LFxuXG5cdF9vblpvb21FbmQ6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgcHhDZW50ZXIgPSB0aGlzLl9tYXAuZ2V0U2l6ZSgpLmRpdmlkZUJ5KDIpLFxuXHRcdCAgICBweFdvcmxkQ2VudGVyID0gdGhpcy5fbWFwLmxhdExuZ1RvTGF5ZXJQb2ludChbMCwgMF0pO1xuXG5cdFx0dGhpcy5faW5pdGlhbFdvcmxkT2Zmc2V0ID0gcHhXb3JsZENlbnRlci5zdWJ0cmFjdChweENlbnRlcikueDtcblx0XHR0aGlzLl93b3JsZFdpZHRoID0gdGhpcy5fbWFwLmdldFBpeGVsV29ybGRCb3VuZHMoKS5nZXRTaXplKCkueDtcblx0fSxcblxuXHRfdmlzY291c0xpbWl0OiBmdW5jdGlvbiAodmFsdWUsIHRocmVzaG9sZCkge1xuXHRcdHJldHVybiB2YWx1ZSAtICh2YWx1ZSAtIHRocmVzaG9sZCkgKiB0aGlzLl92aXNjb3NpdHk7XG5cdH0sXG5cblx0X29uUHJlRHJhZ0xpbWl0OiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKCF0aGlzLl92aXNjb3NpdHkgfHwgIXRoaXMuX29mZnNldExpbWl0KSB7IHJldHVybjsgfVxuXG5cdFx0dmFyIG9mZnNldCA9IHRoaXMuX2RyYWdnYWJsZS5fbmV3UG9zLnN1YnRyYWN0KHRoaXMuX2RyYWdnYWJsZS5fc3RhcnRQb3MpO1xuXG5cdFx0dmFyIGxpbWl0ID0gdGhpcy5fb2Zmc2V0TGltaXQ7XG5cdFx0aWYgKG9mZnNldC54IDwgbGltaXQubWluLngpIHsgb2Zmc2V0LnggPSB0aGlzLl92aXNjb3VzTGltaXQob2Zmc2V0LngsIGxpbWl0Lm1pbi54KTsgfVxuXHRcdGlmIChvZmZzZXQueSA8IGxpbWl0Lm1pbi55KSB7IG9mZnNldC55ID0gdGhpcy5fdmlzY291c0xpbWl0KG9mZnNldC55LCBsaW1pdC5taW4ueSk7IH1cblx0XHRpZiAob2Zmc2V0LnggPiBsaW1pdC5tYXgueCkgeyBvZmZzZXQueCA9IHRoaXMuX3Zpc2NvdXNMaW1pdChvZmZzZXQueCwgbGltaXQubWF4LngpOyB9XG5cdFx0aWYgKG9mZnNldC55ID4gbGltaXQubWF4LnkpIHsgb2Zmc2V0LnkgPSB0aGlzLl92aXNjb3VzTGltaXQob2Zmc2V0LnksIGxpbWl0Lm1heC55KTsgfVxuXG5cdFx0dGhpcy5fZHJhZ2dhYmxlLl9uZXdQb3MgPSB0aGlzLl9kcmFnZ2FibGUuX3N0YXJ0UG9zLmFkZChvZmZzZXQpO1xuXHR9LFxuXG5cdF9vblByZURyYWdXcmFwOiBmdW5jdGlvbiAoKSB7XG5cdFx0Ly8gVE9ETyByZWZhY3RvciB0byBiZSBhYmxlIHRvIGFkanVzdCBtYXAgcGFuZSBwb3NpdGlvbiBhZnRlciB6b29tXG5cdFx0dmFyIHdvcmxkV2lkdGggPSB0aGlzLl93b3JsZFdpZHRoLFxuXHRcdCAgICBoYWxmV2lkdGggPSBNYXRoLnJvdW5kKHdvcmxkV2lkdGggLyAyKSxcblx0XHQgICAgZHggPSB0aGlzLl9pbml0aWFsV29ybGRPZmZzZXQsXG5cdFx0ICAgIHggPSB0aGlzLl9kcmFnZ2FibGUuX25ld1Bvcy54LFxuXHRcdCAgICBuZXdYMSA9ICh4IC0gaGFsZldpZHRoICsgZHgpICUgd29ybGRXaWR0aCArIGhhbGZXaWR0aCAtIGR4LFxuXHRcdCAgICBuZXdYMiA9ICh4ICsgaGFsZldpZHRoICsgZHgpICUgd29ybGRXaWR0aCAtIGhhbGZXaWR0aCAtIGR4LFxuXHRcdCAgICBuZXdYID0gTWF0aC5hYnMobmV3WDEgKyBkeCkgPCBNYXRoLmFicyhuZXdYMiArIGR4KSA/IG5ld1gxIDogbmV3WDI7XG5cblx0XHR0aGlzLl9kcmFnZ2FibGUuX2Fic1BvcyA9IHRoaXMuX2RyYWdnYWJsZS5fbmV3UG9zLmNsb25lKCk7XG5cdFx0dGhpcy5fZHJhZ2dhYmxlLl9uZXdQb3MueCA9IG5ld1g7XG5cdH0sXG5cblx0X29uRHJhZ0VuZDogZnVuY3Rpb24gKGUpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBvcHRpb25zID0gbWFwLm9wdGlvbnMsXG5cblx0XHQgICAgbm9JbmVydGlhID0gIW9wdGlvbnMuaW5lcnRpYSB8fCB0aGlzLl90aW1lcy5sZW5ndGggPCAyO1xuXG5cdFx0bWFwLmZpcmUoJ2RyYWdlbmQnLCBlKTtcblxuXHRcdGlmIChub0luZXJ0aWEpIHtcblx0XHRcdG1hcC5maXJlKCdtb3ZlZW5kJyk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR2YXIgZGlyZWN0aW9uID0gdGhpcy5fbGFzdFBvcy5zdWJ0cmFjdCh0aGlzLl9wb3NpdGlvbnNbMF0pLFxuXHRcdFx0ICAgIGR1cmF0aW9uID0gKHRoaXMuX2xhc3RUaW1lIC0gdGhpcy5fdGltZXNbMF0pIC8gMTAwMCxcblx0XHRcdCAgICBlYXNlID0gb3B0aW9ucy5lYXNlTGluZWFyaXR5LFxuXG5cdFx0XHQgICAgc3BlZWRWZWN0b3IgPSBkaXJlY3Rpb24ubXVsdGlwbHlCeShlYXNlIC8gZHVyYXRpb24pLFxuXHRcdFx0ICAgIHNwZWVkID0gc3BlZWRWZWN0b3IuZGlzdGFuY2VUbyhbMCwgMF0pLFxuXG5cdFx0XHQgICAgbGltaXRlZFNwZWVkID0gTWF0aC5taW4ob3B0aW9ucy5pbmVydGlhTWF4U3BlZWQsIHNwZWVkKSxcblx0XHRcdCAgICBsaW1pdGVkU3BlZWRWZWN0b3IgPSBzcGVlZFZlY3Rvci5tdWx0aXBseUJ5KGxpbWl0ZWRTcGVlZCAvIHNwZWVkKSxcblxuXHRcdFx0ICAgIGRlY2VsZXJhdGlvbkR1cmF0aW9uID0gbGltaXRlZFNwZWVkIC8gKG9wdGlvbnMuaW5lcnRpYURlY2VsZXJhdGlvbiAqIGVhc2UpLFxuXHRcdFx0ICAgIG9mZnNldCA9IGxpbWl0ZWRTcGVlZFZlY3Rvci5tdWx0aXBseUJ5KC1kZWNlbGVyYXRpb25EdXJhdGlvbiAvIDIpLnJvdW5kKCk7XG5cblx0XHRcdGlmICghb2Zmc2V0LnggJiYgIW9mZnNldC55KSB7XG5cdFx0XHRcdG1hcC5maXJlKCdtb3ZlZW5kJyk7XG5cblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdG9mZnNldCA9IG1hcC5fbGltaXRPZmZzZXQob2Zmc2V0LCBtYXAub3B0aW9ucy5tYXhCb3VuZHMpO1xuXG5cdFx0XHRcdEwuVXRpbC5yZXF1ZXN0QW5pbUZyYW1lKGZ1bmN0aW9uICgpIHtcblx0XHRcdFx0XHRtYXAucGFuQnkob2Zmc2V0LCB7XG5cdFx0XHRcdFx0XHRkdXJhdGlvbjogZGVjZWxlcmF0aW9uRHVyYXRpb24sXG5cdFx0XHRcdFx0XHRlYXNlTGluZWFyaXR5OiBlYXNlLFxuXHRcdFx0XHRcdFx0bm9Nb3ZlU3RhcnQ6IHRydWUsXG5cdFx0XHRcdFx0XHRhbmltYXRlOiB0cnVlXG5cdFx0XHRcdFx0fSk7XG5cdFx0XHRcdH0pO1xuXHRcdFx0fVxuXHRcdH1cblx0fVxufSk7XG5cbi8vIEBzZWN0aW9uIEhhbmRsZXJzXG4vLyBAcHJvcGVydHkgZHJhZ2dpbmc6IEhhbmRsZXJcbi8vIE1hcCBkcmFnZ2luZyBoYW5kbGVyIChieSBib3RoIG1vdXNlIGFuZCB0b3VjaCkuXG5MLk1hcC5hZGRJbml0SG9vaygnYWRkSGFuZGxlcicsICdkcmFnZ2luZycsIEwuTWFwLkRyYWcpO1xuXG5cblxuLypcbiAqIEwuSGFuZGxlci5Eb3VibGVDbGlja1pvb20gaXMgdXNlZCB0byBoYW5kbGUgZG91YmxlLWNsaWNrIHpvb20gb24gdGhlIG1hcCwgZW5hYmxlZCBieSBkZWZhdWx0LlxuICovXG5cbi8vIEBuYW1lc3BhY2UgTWFwXG4vLyBAc2VjdGlvbiBJbnRlcmFjdGlvbiBPcHRpb25zXG5cbkwuTWFwLm1lcmdlT3B0aW9ucyh7XG5cdC8vIEBvcHRpb24gZG91YmxlQ2xpY2tab29tOiBCb29sZWFufFN0cmluZyA9IHRydWVcblx0Ly8gV2hldGhlciB0aGUgbWFwIGNhbiBiZSB6b29tZWQgaW4gYnkgZG91YmxlIGNsaWNraW5nIG9uIGl0IGFuZFxuXHQvLyB6b29tZWQgb3V0IGJ5IGRvdWJsZSBjbGlja2luZyB3aGlsZSBob2xkaW5nIHNoaWZ0LiBJZiBwYXNzZWRcblx0Ly8gYCdjZW50ZXInYCwgZG91YmxlLWNsaWNrIHpvb20gd2lsbCB6b29tIHRvIHRoZSBjZW50ZXIgb2YgdGhlXG5cdC8vICB2aWV3IHJlZ2FyZGxlc3Mgb2Ygd2hlcmUgdGhlIG1vdXNlIHdhcy5cblx0ZG91YmxlQ2xpY2tab29tOiB0cnVlXG59KTtcblxuTC5NYXAuRG91YmxlQ2xpY2tab29tID0gTC5IYW5kbGVyLmV4dGVuZCh7XG5cdGFkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fbWFwLm9uKCdkYmxjbGljaycsIHRoaXMuX29uRG91YmxlQ2xpY2ssIHRoaXMpO1xuXHR9LFxuXG5cdHJlbW92ZUhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fbWFwLm9mZignZGJsY2xpY2snLCB0aGlzLl9vbkRvdWJsZUNsaWNrLCB0aGlzKTtcblx0fSxcblxuXHRfb25Eb3VibGVDbGljazogZnVuY3Rpb24gKGUpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwLFxuXHRcdCAgICBvbGRab29tID0gbWFwLmdldFpvb20oKSxcblx0XHQgICAgZGVsdGEgPSBtYXAub3B0aW9ucy56b29tRGVsdGEsXG5cdFx0ICAgIHpvb20gPSBlLm9yaWdpbmFsRXZlbnQuc2hpZnRLZXkgPyBvbGRab29tIC0gZGVsdGEgOiBvbGRab29tICsgZGVsdGE7XG5cblx0XHRpZiAobWFwLm9wdGlvbnMuZG91YmxlQ2xpY2tab29tID09PSAnY2VudGVyJykge1xuXHRcdFx0bWFwLnNldFpvb20oem9vbSk7XG5cdFx0fSBlbHNlIHtcblx0XHRcdG1hcC5zZXRab29tQXJvdW5kKGUuY29udGFpbmVyUG9pbnQsIHpvb20pO1xuXHRcdH1cblx0fVxufSk7XG5cbi8vIEBzZWN0aW9uIEhhbmRsZXJzXG4vL1xuLy8gTWFwIHByb3BlcnRpZXMgaW5jbHVkZSBpbnRlcmFjdGlvbiBoYW5kbGVycyB0aGF0IGFsbG93IHlvdSB0byBjb250cm9sXG4vLyBpbnRlcmFjdGlvbiBiZWhhdmlvciBpbiBydW50aW1lLCBlbmFibGluZyBvciBkaXNhYmxpbmcgY2VydGFpbiBmZWF0dXJlcyBzdWNoXG4vLyBhcyBkcmFnZ2luZyBvciB0b3VjaCB6b29tIChzZWUgYEhhbmRsZXJgIG1ldGhvZHMpLiBGb3IgZXhhbXBsZTpcbi8vXG4vLyBgYGBqc1xuLy8gbWFwLmRvdWJsZUNsaWNrWm9vbS5kaXNhYmxlKCk7XG4vLyBgYGBcbi8vXG4vLyBAcHJvcGVydHkgZG91YmxlQ2xpY2tab29tOiBIYW5kbGVyXG4vLyBEb3VibGUgY2xpY2sgem9vbSBoYW5kbGVyLlxuTC5NYXAuYWRkSW5pdEhvb2soJ2FkZEhhbmRsZXInLCAnZG91YmxlQ2xpY2tab29tJywgTC5NYXAuRG91YmxlQ2xpY2tab29tKTtcblxuXG5cbi8qXG4gKiBMLkhhbmRsZXIuU2Nyb2xsV2hlZWxab29tIGlzIHVzZWQgYnkgTC5NYXAgdG8gZW5hYmxlIG1vdXNlIHNjcm9sbCB3aGVlbCB6b29tIG9uIHRoZSBtYXAuXG4gKi9cblxuLy8gQG5hbWVzcGFjZSBNYXBcbi8vIEBzZWN0aW9uIEludGVyYWN0aW9uIE9wdGlvbnNcbkwuTWFwLm1lcmdlT3B0aW9ucyh7XG5cdC8vIEBzZWN0aW9uIE1vdXNld2hlZWwgb3B0aW9uc1xuXHQvLyBAb3B0aW9uIHNjcm9sbFdoZWVsWm9vbTogQm9vbGVhbnxTdHJpbmcgPSB0cnVlXG5cdC8vIFdoZXRoZXIgdGhlIG1hcCBjYW4gYmUgem9vbWVkIGJ5IHVzaW5nIHRoZSBtb3VzZSB3aGVlbC4gSWYgcGFzc2VkIGAnY2VudGVyJ2AsXG5cdC8vIGl0IHdpbGwgem9vbSB0byB0aGUgY2VudGVyIG9mIHRoZSB2aWV3IHJlZ2FyZGxlc3Mgb2Ygd2hlcmUgdGhlIG1vdXNlIHdhcy5cblx0c2Nyb2xsV2hlZWxab29tOiB0cnVlLFxuXG5cdC8vIEBvcHRpb24gd2hlZWxEZWJvdW5jZVRpbWU6IE51bWJlciA9IDQwXG5cdC8vIExpbWl0cyB0aGUgcmF0ZSBhdCB3aGljaCBhIHdoZWVsIGNhbiBmaXJlIChpbiBtaWxsaXNlY29uZHMpLiBCeSBkZWZhdWx0XG5cdC8vIHVzZXIgY2FuJ3Qgem9vbSB2aWEgd2hlZWwgbW9yZSBvZnRlbiB0aGFuIG9uY2UgcGVyIDQwIG1zLlxuXHR3aGVlbERlYm91bmNlVGltZTogNDAsXG5cblx0Ly8gQG9wdGlvbiB3aGVlbFB4UGVyWm9vbUxldmVsOiBOdW1iZXIgPSA2MFxuXHQvLyBIb3cgbWFueSBzY3JvbGwgcGl4ZWxzIChhcyByZXBvcnRlZCBieSBbTC5Eb21FdmVudC5nZXRXaGVlbERlbHRhXSgjZG9tZXZlbnQtZ2V0d2hlZWxkZWx0YSkpXG5cdC8vIG1lYW4gYSBjaGFuZ2Ugb2Ygb25lIGZ1bGwgem9vbSBsZXZlbC4gU21hbGxlciB2YWx1ZXMgd2lsbCBtYWtlIHdoZWVsLXpvb21pbmdcblx0Ly8gZmFzdGVyIChhbmQgdmljZSB2ZXJzYSkuXG5cdHdoZWVsUHhQZXJab29tTGV2ZWw6IDYwXG59KTtcblxuTC5NYXAuU2Nyb2xsV2hlZWxab29tID0gTC5IYW5kbGVyLmV4dGVuZCh7XG5cdGFkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0TC5Eb21FdmVudC5vbih0aGlzLl9tYXAuX2NvbnRhaW5lciwgJ21vdXNld2hlZWwnLCB0aGlzLl9vbldoZWVsU2Nyb2xsLCB0aGlzKTtcblxuXHRcdHRoaXMuX2RlbHRhID0gMDtcblx0fSxcblxuXHRyZW1vdmVIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdEwuRG9tRXZlbnQub2ZmKHRoaXMuX21hcC5fY29udGFpbmVyLCAnbW91c2V3aGVlbCcsIHRoaXMuX29uV2hlZWxTY3JvbGwsIHRoaXMpO1xuXHR9LFxuXG5cdF9vbldoZWVsU2Nyb2xsOiBmdW5jdGlvbiAoZSkge1xuXHRcdHZhciBkZWx0YSA9IEwuRG9tRXZlbnQuZ2V0V2hlZWxEZWx0YShlKTtcblxuXHRcdHZhciBkZWJvdW5jZSA9IHRoaXMuX21hcC5vcHRpb25zLndoZWVsRGVib3VuY2VUaW1lO1xuXG5cdFx0dGhpcy5fZGVsdGEgKz0gZGVsdGE7XG5cdFx0dGhpcy5fbGFzdE1vdXNlUG9zID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50KGUpO1xuXG5cdFx0aWYgKCF0aGlzLl9zdGFydFRpbWUpIHtcblx0XHRcdHRoaXMuX3N0YXJ0VGltZSA9ICtuZXcgRGF0ZSgpO1xuXHRcdH1cblxuXHRcdHZhciBsZWZ0ID0gTWF0aC5tYXgoZGVib3VuY2UgLSAoK25ldyBEYXRlKCkgLSB0aGlzLl9zdGFydFRpbWUpLCAwKTtcblxuXHRcdGNsZWFyVGltZW91dCh0aGlzLl90aW1lcik7XG5cdFx0dGhpcy5fdGltZXIgPSBzZXRUaW1lb3V0KEwuYmluZCh0aGlzLl9wZXJmb3JtWm9vbSwgdGhpcyksIGxlZnQpO1xuXG5cdFx0TC5Eb21FdmVudC5zdG9wKGUpO1xuXHR9LFxuXG5cdF9wZXJmb3JtWm9vbTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBtYXAgPSB0aGlzLl9tYXAsXG5cdFx0ICAgIHpvb20gPSBtYXAuZ2V0Wm9vbSgpLFxuXHRcdCAgICBzbmFwID0gdGhpcy5fbWFwLm9wdGlvbnMuem9vbVNuYXAgfHwgMDtcblxuXHRcdG1hcC5fc3RvcCgpOyAvLyBzdG9wIHBhbm5pbmcgYW5kIGZseSBhbmltYXRpb25zIGlmIGFueVxuXG5cdFx0Ly8gbWFwIHRoZSBkZWx0YSB3aXRoIGEgc2lnbW9pZCBmdW5jdGlvbiB0byAtNC4uNCByYW5nZSBsZWFuaW5nIG9uIC0xLi4xXG5cdFx0dmFyIGQyID0gdGhpcy5fZGVsdGEgLyAodGhpcy5fbWFwLm9wdGlvbnMud2hlZWxQeFBlclpvb21MZXZlbCAqIDQpLFxuXHRcdCAgICBkMyA9IDQgKiBNYXRoLmxvZygyIC8gKDEgKyBNYXRoLmV4cCgtTWF0aC5hYnMoZDIpKSkpIC8gTWF0aC5MTjIsXG5cdFx0ICAgIGQ0ID0gc25hcCA/IE1hdGguY2VpbChkMyAvIHNuYXApICogc25hcCA6IGQzLFxuXHRcdCAgICBkZWx0YSA9IG1hcC5fbGltaXRab29tKHpvb20gKyAodGhpcy5fZGVsdGEgPiAwID8gZDQgOiAtZDQpKSAtIHpvb207XG5cblx0XHR0aGlzLl9kZWx0YSA9IDA7XG5cdFx0dGhpcy5fc3RhcnRUaW1lID0gbnVsbDtcblxuXHRcdGlmICghZGVsdGEpIHsgcmV0dXJuOyB9XG5cblx0XHRpZiAobWFwLm9wdGlvbnMuc2Nyb2xsV2hlZWxab29tID09PSAnY2VudGVyJykge1xuXHRcdFx0bWFwLnNldFpvb20oem9vbSArIGRlbHRhKTtcblx0XHR9IGVsc2Uge1xuXHRcdFx0bWFwLnNldFpvb21Bcm91bmQodGhpcy5fbGFzdE1vdXNlUG9zLCB6b29tICsgZGVsdGEpO1xuXHRcdH1cblx0fVxufSk7XG5cbi8vIEBzZWN0aW9uIEhhbmRsZXJzXG4vLyBAcHJvcGVydHkgc2Nyb2xsV2hlZWxab29tOiBIYW5kbGVyXG4vLyBTY3JvbGwgd2hlZWwgem9vbSBoYW5kbGVyLlxuTC5NYXAuYWRkSW5pdEhvb2soJ2FkZEhhbmRsZXInLCAnc2Nyb2xsV2hlZWxab29tJywgTC5NYXAuU2Nyb2xsV2hlZWxab29tKTtcblxuXG5cbi8qXHJcbiAqIEV4dGVuZHMgdGhlIGV2ZW50IGhhbmRsaW5nIGNvZGUgd2l0aCBkb3VibGUgdGFwIHN1cHBvcnQgZm9yIG1vYmlsZSBicm93c2Vycy5cclxuICovXHJcblxyXG5MLmV4dGVuZChMLkRvbUV2ZW50LCB7XHJcblxyXG5cdF90b3VjaHN0YXJ0OiBMLkJyb3dzZXIubXNQb2ludGVyID8gJ01TUG9pbnRlckRvd24nIDogTC5Ccm93c2VyLnBvaW50ZXIgPyAncG9pbnRlcmRvd24nIDogJ3RvdWNoc3RhcnQnLFxyXG5cdF90b3VjaGVuZDogTC5Ccm93c2VyLm1zUG9pbnRlciA/ICdNU1BvaW50ZXJVcCcgOiBMLkJyb3dzZXIucG9pbnRlciA/ICdwb2ludGVydXAnIDogJ3RvdWNoZW5kJyxcclxuXHJcblx0Ly8gaW5zcGlyZWQgYnkgWmVwdG8gdG91Y2ggY29kZSBieSBUaG9tYXMgRnVjaHNcclxuXHRhZGREb3VibGVUYXBMaXN0ZW5lcjogZnVuY3Rpb24gKG9iaiwgaGFuZGxlciwgaWQpIHtcclxuXHRcdHZhciBsYXN0LCB0b3VjaCxcclxuXHRcdCAgICBkb3VibGVUYXAgPSBmYWxzZSxcclxuXHRcdCAgICBkZWxheSA9IDI1MDtcclxuXHJcblx0XHRmdW5jdGlvbiBvblRvdWNoU3RhcnQoZSkge1xyXG5cdFx0XHR2YXIgY291bnQ7XHJcblxyXG5cdFx0XHRpZiAoTC5Ccm93c2VyLnBvaW50ZXIpIHtcclxuXHRcdFx0XHRjb3VudCA9IEwuRG9tRXZlbnQuX3BvaW50ZXJzQ291bnQ7XHJcblx0XHRcdH0gZWxzZSB7XHJcblx0XHRcdFx0Y291bnQgPSBlLnRvdWNoZXMubGVuZ3RoO1xyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHRpZiAoY291bnQgPiAxKSB7IHJldHVybjsgfVxyXG5cclxuXHRcdFx0dmFyIG5vdyA9IERhdGUubm93KCksXHJcblx0XHRcdCAgICBkZWx0YSA9IG5vdyAtIChsYXN0IHx8IG5vdyk7XHJcblxyXG5cdFx0XHR0b3VjaCA9IGUudG91Y2hlcyA/IGUudG91Y2hlc1swXSA6IGU7XHJcblx0XHRcdGRvdWJsZVRhcCA9IChkZWx0YSA+IDAgJiYgZGVsdGEgPD0gZGVsYXkpO1xyXG5cdFx0XHRsYXN0ID0gbm93O1xyXG5cdFx0fVxyXG5cclxuXHRcdGZ1bmN0aW9uIG9uVG91Y2hFbmQoKSB7XHJcblx0XHRcdGlmIChkb3VibGVUYXAgJiYgIXRvdWNoLmNhbmNlbEJ1YmJsZSkge1xyXG5cdFx0XHRcdGlmIChMLkJyb3dzZXIucG9pbnRlcikge1xyXG5cdFx0XHRcdFx0Ly8gd29yayBhcm91bmQgLnR5cGUgYmVpbmcgcmVhZG9ubHkgd2l0aCBNU1BvaW50ZXIqIGV2ZW50c1xyXG5cdFx0XHRcdFx0dmFyIG5ld1RvdWNoID0ge30sXHJcblx0XHRcdFx0XHQgICAgcHJvcCwgaTtcclxuXHJcblx0XHRcdFx0XHRmb3IgKGkgaW4gdG91Y2gpIHtcclxuXHRcdFx0XHRcdFx0cHJvcCA9IHRvdWNoW2ldO1xyXG5cdFx0XHRcdFx0XHRuZXdUb3VjaFtpXSA9IHByb3AgJiYgcHJvcC5iaW5kID8gcHJvcC5iaW5kKHRvdWNoKSA6IHByb3A7XHJcblx0XHRcdFx0XHR9XHJcblx0XHRcdFx0XHR0b3VjaCA9IG5ld1RvdWNoO1xyXG5cdFx0XHRcdH1cclxuXHRcdFx0XHR0b3VjaC50eXBlID0gJ2RibGNsaWNrJztcclxuXHRcdFx0XHRoYW5kbGVyKHRvdWNoKTtcclxuXHRcdFx0XHRsYXN0ID0gbnVsbDtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBwcmUgPSAnX2xlYWZsZXRfJyxcclxuXHRcdCAgICB0b3VjaHN0YXJ0ID0gdGhpcy5fdG91Y2hzdGFydCxcclxuXHRcdCAgICB0b3VjaGVuZCA9IHRoaXMuX3RvdWNoZW5kO1xyXG5cclxuXHRcdG9ialtwcmUgKyB0b3VjaHN0YXJ0ICsgaWRdID0gb25Ub3VjaFN0YXJ0O1xyXG5cdFx0b2JqW3ByZSArIHRvdWNoZW5kICsgaWRdID0gb25Ub3VjaEVuZDtcclxuXHRcdG9ialtwcmUgKyAnZGJsY2xpY2snICsgaWRdID0gaGFuZGxlcjtcclxuXHJcblx0XHRvYmouYWRkRXZlbnRMaXN0ZW5lcih0b3VjaHN0YXJ0LCBvblRvdWNoU3RhcnQsIGZhbHNlKTtcclxuXHRcdG9iai5hZGRFdmVudExpc3RlbmVyKHRvdWNoZW5kLCBvblRvdWNoRW5kLCBmYWxzZSk7XHJcblxyXG5cdFx0Ly8gT24gc29tZSBwbGF0Zm9ybXMgKG5vdGFibHksIGNocm9tZSBvbiB3aW4xMCArIHRvdWNoc2NyZWVuICsgbW91c2UpLFxyXG5cdFx0Ly8gdGhlIGJyb3dzZXIgZG9lc24ndCBmaXJlIHRvdWNoZW5kL3BvaW50ZXJ1cCBldmVudHMgYnV0IGRvZXMgZmlyZVxyXG5cdFx0Ly8gbmF0aXZlIGRibGNsaWNrcy4gU2VlICM0MTI3LlxyXG5cdFx0aWYgKCFMLkJyb3dzZXIuZWRnZSkge1xyXG5cdFx0XHRvYmouYWRkRXZlbnRMaXN0ZW5lcignZGJsY2xpY2snLCBoYW5kbGVyLCBmYWxzZSk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0cmVtb3ZlRG91YmxlVGFwTGlzdGVuZXI6IGZ1bmN0aW9uIChvYmosIGlkKSB7XHJcblx0XHR2YXIgcHJlID0gJ19sZWFmbGV0XycsXHJcblx0XHQgICAgdG91Y2hzdGFydCA9IG9ialtwcmUgKyB0aGlzLl90b3VjaHN0YXJ0ICsgaWRdLFxyXG5cdFx0ICAgIHRvdWNoZW5kID0gb2JqW3ByZSArIHRoaXMuX3RvdWNoZW5kICsgaWRdLFxyXG5cdFx0ICAgIGRibGNsaWNrID0gb2JqW3ByZSArICdkYmxjbGljaycgKyBpZF07XHJcblxyXG5cdFx0b2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIodGhpcy5fdG91Y2hzdGFydCwgdG91Y2hzdGFydCwgZmFsc2UpO1xyXG5cdFx0b2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIodGhpcy5fdG91Y2hlbmQsIHRvdWNoZW5kLCBmYWxzZSk7XHJcblx0XHRpZiAoIUwuQnJvd3Nlci5lZGdlKSB7XHJcblx0XHRcdG9iai5yZW1vdmVFdmVudExpc3RlbmVyKCdkYmxjbGljaycsIGRibGNsaWNrLCBmYWxzZSk7XHJcblx0XHR9XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fVxyXG59KTtcclxuXG5cblxuLypcbiAqIEV4dGVuZHMgTC5Eb21FdmVudCB0byBwcm92aWRlIHRvdWNoIHN1cHBvcnQgZm9yIEludGVybmV0IEV4cGxvcmVyIGFuZCBXaW5kb3dzLWJhc2VkIGRldmljZXMuXG4gKi9cblxuTC5leHRlbmQoTC5Eb21FdmVudCwge1xuXG5cdFBPSU5URVJfRE9XTjogICBMLkJyb3dzZXIubXNQb2ludGVyID8gJ01TUG9pbnRlckRvd24nICAgOiAncG9pbnRlcmRvd24nLFxuXHRQT0lOVEVSX01PVkU6ICAgTC5Ccm93c2VyLm1zUG9pbnRlciA/ICdNU1BvaW50ZXJNb3ZlJyAgIDogJ3BvaW50ZXJtb3ZlJyxcblx0UE9JTlRFUl9VUDogICAgIEwuQnJvd3Nlci5tc1BvaW50ZXIgPyAnTVNQb2ludGVyVXAnICAgICA6ICdwb2ludGVydXAnLFxuXHRQT0lOVEVSX0NBTkNFTDogTC5Ccm93c2VyLm1zUG9pbnRlciA/ICdNU1BvaW50ZXJDYW5jZWwnIDogJ3BvaW50ZXJjYW5jZWwnLFxuXHRUQUdfV0hJVEVfTElTVDogWydJTlBVVCcsICdTRUxFQ1QnLCAnT1BUSU9OJ10sXG5cblx0X3BvaW50ZXJzOiB7fSxcblx0X3BvaW50ZXJzQ291bnQ6IDAsXG5cblx0Ly8gUHJvdmlkZXMgYSB0b3VjaCBldmVudHMgd3JhcHBlciBmb3IgKG1zKXBvaW50ZXIgZXZlbnRzLlxuXHQvLyByZWYgaHR0cDovL3d3dy53My5vcmcvVFIvcG9pbnRlcmV2ZW50cy8gaHR0cHM6Ly93d3cudzMub3JnL0J1Z3MvUHVibGljL3Nob3dfYnVnLmNnaT9pZD0yMjg5MFxuXG5cdGFkZFBvaW50ZXJMaXN0ZW5lcjogZnVuY3Rpb24gKG9iaiwgdHlwZSwgaGFuZGxlciwgaWQpIHtcblxuXHRcdGlmICh0eXBlID09PSAndG91Y2hzdGFydCcpIHtcblx0XHRcdHRoaXMuX2FkZFBvaW50ZXJTdGFydChvYmosIGhhbmRsZXIsIGlkKTtcblxuXHRcdH0gZWxzZSBpZiAodHlwZSA9PT0gJ3RvdWNobW92ZScpIHtcblx0XHRcdHRoaXMuX2FkZFBvaW50ZXJNb3ZlKG9iaiwgaGFuZGxlciwgaWQpO1xuXG5cdFx0fSBlbHNlIGlmICh0eXBlID09PSAndG91Y2hlbmQnKSB7XG5cdFx0XHR0aGlzLl9hZGRQb2ludGVyRW5kKG9iaiwgaGFuZGxlciwgaWQpO1xuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXHR9LFxuXG5cdHJlbW92ZVBvaW50ZXJMaXN0ZW5lcjogZnVuY3Rpb24gKG9iaiwgdHlwZSwgaWQpIHtcblx0XHR2YXIgaGFuZGxlciA9IG9ialsnX2xlYWZsZXRfJyArIHR5cGUgKyBpZF07XG5cblx0XHRpZiAodHlwZSA9PT0gJ3RvdWNoc3RhcnQnKSB7XG5cdFx0XHRvYmoucmVtb3ZlRXZlbnRMaXN0ZW5lcih0aGlzLlBPSU5URVJfRE9XTiwgaGFuZGxlciwgZmFsc2UpO1xuXG5cdFx0fSBlbHNlIGlmICh0eXBlID09PSAndG91Y2htb3ZlJykge1xuXHRcdFx0b2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIodGhpcy5QT0lOVEVSX01PVkUsIGhhbmRsZXIsIGZhbHNlKTtcblxuXHRcdH0gZWxzZSBpZiAodHlwZSA9PT0gJ3RvdWNoZW5kJykge1xuXHRcdFx0b2JqLnJlbW92ZUV2ZW50TGlzdGVuZXIodGhpcy5QT0lOVEVSX1VQLCBoYW5kbGVyLCBmYWxzZSk7XG5cdFx0XHRvYmoucmVtb3ZlRXZlbnRMaXN0ZW5lcih0aGlzLlBPSU5URVJfQ0FOQ0VMLCBoYW5kbGVyLCBmYWxzZSk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cdH0sXG5cblx0X2FkZFBvaW50ZXJTdGFydDogZnVuY3Rpb24gKG9iaiwgaGFuZGxlciwgaWQpIHtcblx0XHR2YXIgb25Eb3duID0gTC5iaW5kKGZ1bmN0aW9uIChlKSB7XG5cdFx0XHRpZiAoZS5wb2ludGVyVHlwZSAhPT0gJ21vdXNlJyAmJiBlLnBvaW50ZXJUeXBlICE9PSBlLk1TUE9JTlRFUl9UWVBFX01PVVNFKSB7XG5cdFx0XHRcdC8vIEluIElFMTEsIHNvbWUgdG91Y2ggZXZlbnRzIG5lZWRzIHRvIGZpcmUgZm9yIGZvcm0gY29udHJvbHMsIG9yXG5cdFx0XHRcdC8vIHRoZSBjb250cm9scyB3aWxsIHN0b3Agd29ya2luZy4gV2Uga2VlcCBhIHdoaXRlbGlzdCBvZiB0YWcgbmFtZXMgdGhhdFxuXHRcdFx0XHQvLyBuZWVkIHRoZXNlIGV2ZW50cy4gRm9yIG90aGVyIHRhcmdldCB0YWdzLCB3ZSBwcmV2ZW50IGRlZmF1bHQgb24gdGhlIGV2ZW50LlxuXHRcdFx0XHRpZiAodGhpcy5UQUdfV0hJVEVfTElTVC5pbmRleE9mKGUudGFyZ2V0LnRhZ05hbWUpIDwgMCkge1xuXHRcdFx0XHRcdEwuRG9tRXZlbnQucHJldmVudERlZmF1bHQoZSk7XG5cdFx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXHRcdFx0XHR9XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2hhbmRsZVBvaW50ZXIoZSwgaGFuZGxlcik7XG5cdFx0fSwgdGhpcyk7XG5cblx0XHRvYmpbJ19sZWFmbGV0X3RvdWNoc3RhcnQnICsgaWRdID0gb25Eb3duO1xuXHRcdG9iai5hZGRFdmVudExpc3RlbmVyKHRoaXMuUE9JTlRFUl9ET1dOLCBvbkRvd24sIGZhbHNlKTtcblxuXHRcdC8vIG5lZWQgdG8ga2VlcCB0cmFjayBvZiB3aGF0IHBvaW50ZXJzIGFuZCBob3cgbWFueSBhcmUgYWN0aXZlIHRvIHByb3ZpZGUgZS50b3VjaGVzIGVtdWxhdGlvblxuXHRcdGlmICghdGhpcy5fcG9pbnRlckRvY0xpc3RlbmVyKSB7XG5cdFx0XHR2YXIgcG9pbnRlclVwID0gTC5iaW5kKHRoaXMuX2dsb2JhbFBvaW50ZXJVcCwgdGhpcyk7XG5cblx0XHRcdC8vIHdlIGxpc3RlbiBkb2N1bWVudEVsZW1lbnQgYXMgYW55IGRyYWdzIHRoYXQgZW5kIGJ5IG1vdmluZyB0aGUgdG91Y2ggb2ZmIHRoZSBzY3JlZW4gZ2V0IGZpcmVkIHRoZXJlXG5cdFx0XHRkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0aGlzLlBPSU5URVJfRE9XTiwgTC5iaW5kKHRoaXMuX2dsb2JhbFBvaW50ZXJEb3duLCB0aGlzKSwgdHJ1ZSk7XG5cdFx0XHRkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0aGlzLlBPSU5URVJfTU9WRSwgTC5iaW5kKHRoaXMuX2dsb2JhbFBvaW50ZXJNb3ZlLCB0aGlzKSwgdHJ1ZSk7XG5cdFx0XHRkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0aGlzLlBPSU5URVJfVVAsIHBvaW50ZXJVcCwgdHJ1ZSk7XG5cdFx0XHRkb2N1bWVudC5kb2N1bWVudEVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lcih0aGlzLlBPSU5URVJfQ0FOQ0VMLCBwb2ludGVyVXAsIHRydWUpO1xuXG5cdFx0XHR0aGlzLl9wb2ludGVyRG9jTGlzdGVuZXIgPSB0cnVlO1xuXHRcdH1cblx0fSxcblxuXHRfZ2xvYmFsUG9pbnRlckRvd246IGZ1bmN0aW9uIChlKSB7XG5cdFx0dGhpcy5fcG9pbnRlcnNbZS5wb2ludGVySWRdID0gZTtcblx0XHR0aGlzLl9wb2ludGVyc0NvdW50Kys7XG5cdH0sXG5cblx0X2dsb2JhbFBvaW50ZXJNb3ZlOiBmdW5jdGlvbiAoZSkge1xuXHRcdGlmICh0aGlzLl9wb2ludGVyc1tlLnBvaW50ZXJJZF0pIHtcblx0XHRcdHRoaXMuX3BvaW50ZXJzW2UucG9pbnRlcklkXSA9IGU7XG5cdFx0fVxuXHR9LFxuXG5cdF9nbG9iYWxQb2ludGVyVXA6IGZ1bmN0aW9uIChlKSB7XG5cdFx0ZGVsZXRlIHRoaXMuX3BvaW50ZXJzW2UucG9pbnRlcklkXTtcblx0XHR0aGlzLl9wb2ludGVyc0NvdW50LS07XG5cdH0sXG5cblx0X2hhbmRsZVBvaW50ZXI6IGZ1bmN0aW9uIChlLCBoYW5kbGVyKSB7XG5cdFx0ZS50b3VjaGVzID0gW107XG5cdFx0Zm9yICh2YXIgaSBpbiB0aGlzLl9wb2ludGVycykge1xuXHRcdFx0ZS50b3VjaGVzLnB1c2godGhpcy5fcG9pbnRlcnNbaV0pO1xuXHRcdH1cblx0XHRlLmNoYW5nZWRUb3VjaGVzID0gW2VdO1xuXG5cdFx0aGFuZGxlcihlKTtcblx0fSxcblxuXHRfYWRkUG9pbnRlck1vdmU6IGZ1bmN0aW9uIChvYmosIGhhbmRsZXIsIGlkKSB7XG5cdFx0dmFyIG9uTW92ZSA9IEwuYmluZChmdW5jdGlvbiAoZSkge1xuXHRcdFx0Ly8gZG9uJ3QgZmlyZSB0b3VjaCBtb3ZlcyB3aGVuIG1vdXNlIGlzbid0IGRvd25cblx0XHRcdGlmICgoZS5wb2ludGVyVHlwZSA9PT0gZS5NU1BPSU5URVJfVFlQRV9NT1VTRSB8fCBlLnBvaW50ZXJUeXBlID09PSAnbW91c2UnKSAmJiBlLmJ1dHRvbnMgPT09IDApIHsgcmV0dXJuOyB9XG5cblx0XHRcdHRoaXMuX2hhbmRsZVBvaW50ZXIoZSwgaGFuZGxlcik7XG5cdFx0fSwgdGhpcyk7XG5cblx0XHRvYmpbJ19sZWFmbGV0X3RvdWNobW92ZScgKyBpZF0gPSBvbk1vdmU7XG5cdFx0b2JqLmFkZEV2ZW50TGlzdGVuZXIodGhpcy5QT0lOVEVSX01PVkUsIG9uTW92ZSwgZmFsc2UpO1xuXHR9LFxuXG5cdF9hZGRQb2ludGVyRW5kOiBmdW5jdGlvbiAob2JqLCBoYW5kbGVyLCBpZCkge1xuXHRcdHZhciBvblVwID0gTC5iaW5kKGZ1bmN0aW9uIChlKSB7XG5cdFx0XHR0aGlzLl9oYW5kbGVQb2ludGVyKGUsIGhhbmRsZXIpO1xuXHRcdH0sIHRoaXMpO1xuXG5cdFx0b2JqWydfbGVhZmxldF90b3VjaGVuZCcgKyBpZF0gPSBvblVwO1xuXHRcdG9iai5hZGRFdmVudExpc3RlbmVyKHRoaXMuUE9JTlRFUl9VUCwgb25VcCwgZmFsc2UpO1xuXHRcdG9iai5hZGRFdmVudExpc3RlbmVyKHRoaXMuUE9JTlRFUl9DQU5DRUwsIG9uVXAsIGZhbHNlKTtcblx0fVxufSk7XG5cblxuXG4vKlxuICogTC5IYW5kbGVyLlRvdWNoWm9vbSBpcyB1c2VkIGJ5IEwuTWFwIHRvIGFkZCBwaW5jaCB6b29tIG9uIHN1cHBvcnRlZCBtb2JpbGUgYnJvd3NlcnMuXG4gKi9cblxuLy8gQG5hbWVzcGFjZSBNYXBcbi8vIEBzZWN0aW9uIEludGVyYWN0aW9uIE9wdGlvbnNcbkwuTWFwLm1lcmdlT3B0aW9ucyh7XG5cdC8vIEBzZWN0aW9uIFRvdWNoIGludGVyYWN0aW9uIG9wdGlvbnNcblx0Ly8gQG9wdGlvbiB0b3VjaFpvb206IEJvb2xlYW58U3RyaW5nID0gKlxuXHQvLyBXaGV0aGVyIHRoZSBtYXAgY2FuIGJlIHpvb21lZCBieSB0b3VjaC1kcmFnZ2luZyB3aXRoIHR3byBmaW5nZXJzLiBJZlxuXHQvLyBwYXNzZWQgYCdjZW50ZXInYCwgaXQgd2lsbCB6b29tIHRvIHRoZSBjZW50ZXIgb2YgdGhlIHZpZXcgcmVnYXJkbGVzcyBvZlxuXHQvLyB3aGVyZSB0aGUgdG91Y2ggZXZlbnRzIChmaW5nZXJzKSB3ZXJlLiBFbmFibGVkIGZvciB0b3VjaC1jYXBhYmxlIHdlYlxuXHQvLyBicm93c2VycyBleGNlcHQgZm9yIG9sZCBBbmRyb2lkcy5cblx0dG91Y2hab29tOiBMLkJyb3dzZXIudG91Y2ggJiYgIUwuQnJvd3Nlci5hbmRyb2lkMjMsXG5cblx0Ly8gQG9wdGlvbiBib3VuY2VBdFpvb21MaW1pdHM6IEJvb2xlYW4gPSB0cnVlXG5cdC8vIFNldCBpdCB0byBmYWxzZSBpZiB5b3UgZG9uJ3Qgd2FudCB0aGUgbWFwIHRvIHpvb20gYmV5b25kIG1pbi9tYXggem9vbVxuXHQvLyBhbmQgdGhlbiBib3VuY2UgYmFjayB3aGVuIHBpbmNoLXpvb21pbmcuXG5cdGJvdW5jZUF0Wm9vbUxpbWl0czogdHJ1ZVxufSk7XG5cbkwuTWFwLlRvdWNoWm9vbSA9IEwuSGFuZGxlci5leHRlbmQoe1xuXHRhZGRIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9tYXAuX2NvbnRhaW5lciwgJ2xlYWZsZXQtdG91Y2gtem9vbScpO1xuXHRcdEwuRG9tRXZlbnQub24odGhpcy5fbWFwLl9jb250YWluZXIsICd0b3VjaHN0YXJ0JywgdGhpcy5fb25Ub3VjaFN0YXJ0LCB0aGlzKTtcblx0fSxcblxuXHRyZW1vdmVIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl9tYXAuX2NvbnRhaW5lciwgJ2xlYWZsZXQtdG91Y2gtem9vbScpO1xuXHRcdEwuRG9tRXZlbnQub2ZmKHRoaXMuX21hcC5fY29udGFpbmVyLCAndG91Y2hzdGFydCcsIHRoaXMuX29uVG91Y2hTdGFydCwgdGhpcyk7XG5cdH0sXG5cblx0X29uVG91Y2hTdGFydDogZnVuY3Rpb24gKGUpIHtcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwO1xuXHRcdGlmICghZS50b3VjaGVzIHx8IGUudG91Y2hlcy5sZW5ndGggIT09IDIgfHwgbWFwLl9hbmltYXRpbmdab29tIHx8IHRoaXMuX3pvb21pbmcpIHsgcmV0dXJuOyB9XG5cblx0XHR2YXIgcDEgPSBtYXAubW91c2VFdmVudFRvQ29udGFpbmVyUG9pbnQoZS50b3VjaGVzWzBdKSxcblx0XHQgICAgcDIgPSBtYXAubW91c2VFdmVudFRvQ29udGFpbmVyUG9pbnQoZS50b3VjaGVzWzFdKTtcblxuXHRcdHRoaXMuX2NlbnRlclBvaW50ID0gbWFwLmdldFNpemUoKS5fZGl2aWRlQnkoMik7XG5cdFx0dGhpcy5fc3RhcnRMYXRMbmcgPSBtYXAuY29udGFpbmVyUG9pbnRUb0xhdExuZyh0aGlzLl9jZW50ZXJQb2ludCk7XG5cdFx0aWYgKG1hcC5vcHRpb25zLnRvdWNoWm9vbSAhPT0gJ2NlbnRlcicpIHtcblx0XHRcdHRoaXMuX3BpbmNoU3RhcnRMYXRMbmcgPSBtYXAuY29udGFpbmVyUG9pbnRUb0xhdExuZyhwMS5hZGQocDIpLl9kaXZpZGVCeSgyKSk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fc3RhcnREaXN0ID0gcDEuZGlzdGFuY2VUbyhwMik7XG5cdFx0dGhpcy5fc3RhcnRab29tID0gbWFwLmdldFpvb20oKTtcblxuXHRcdHRoaXMuX21vdmVkID0gZmFsc2U7XG5cdFx0dGhpcy5fem9vbWluZyA9IHRydWU7XG5cblx0XHRtYXAuX3N0b3AoKTtcblxuXHRcdEwuRG9tRXZlbnRcblx0XHQgICAgLm9uKGRvY3VtZW50LCAndG91Y2htb3ZlJywgdGhpcy5fb25Ub3VjaE1vdmUsIHRoaXMpXG5cdFx0ICAgIC5vbihkb2N1bWVudCwgJ3RvdWNoZW5kJywgdGhpcy5fb25Ub3VjaEVuZCwgdGhpcyk7XG5cblx0XHRMLkRvbUV2ZW50LnByZXZlbnREZWZhdWx0KGUpO1xuXHR9LFxuXG5cdF9vblRvdWNoTW92ZTogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAoIWUudG91Y2hlcyB8fCBlLnRvdWNoZXMubGVuZ3RoICE9PSAyIHx8ICF0aGlzLl96b29taW5nKSB7IHJldHVybjsgfVxuXG5cdFx0dmFyIG1hcCA9IHRoaXMuX21hcCxcblx0XHQgICAgcDEgPSBtYXAubW91c2VFdmVudFRvQ29udGFpbmVyUG9pbnQoZS50b3VjaGVzWzBdKSxcblx0XHQgICAgcDIgPSBtYXAubW91c2VFdmVudFRvQ29udGFpbmVyUG9pbnQoZS50b3VjaGVzWzFdKSxcblx0XHQgICAgc2NhbGUgPSBwMS5kaXN0YW5jZVRvKHAyKSAvIHRoaXMuX3N0YXJ0RGlzdDtcblxuXG5cdFx0dGhpcy5fem9vbSA9IG1hcC5nZXRTY2FsZVpvb20oc2NhbGUsIHRoaXMuX3N0YXJ0Wm9vbSk7XG5cblx0XHRpZiAoIW1hcC5vcHRpb25zLmJvdW5jZUF0Wm9vbUxpbWl0cyAmJiAoXG5cdFx0XHQodGhpcy5fem9vbSA8IG1hcC5nZXRNaW5ab29tKCkgJiYgc2NhbGUgPCAxKSB8fFxuXHRcdFx0KHRoaXMuX3pvb20gPiBtYXAuZ2V0TWF4Wm9vbSgpICYmIHNjYWxlID4gMSkpKSB7XG5cdFx0XHR0aGlzLl96b29tID0gbWFwLl9saW1pdFpvb20odGhpcy5fem9vbSk7XG5cdFx0fVxuXG5cdFx0aWYgKG1hcC5vcHRpb25zLnRvdWNoWm9vbSA9PT0gJ2NlbnRlcicpIHtcblx0XHRcdHRoaXMuX2NlbnRlciA9IHRoaXMuX3N0YXJ0TGF0TG5nO1xuXHRcdFx0aWYgKHNjYWxlID09PSAxKSB7IHJldHVybjsgfVxuXHRcdH0gZWxzZSB7XG5cdFx0XHQvLyBHZXQgZGVsdGEgZnJvbSBwaW5jaCB0byBjZW50ZXIsIHNvIGNlbnRlckxhdExuZyBpcyBkZWx0YSBhcHBsaWVkIHRvIGluaXRpYWwgcGluY2hMYXRMbmdcblx0XHRcdHZhciBkZWx0YSA9IHAxLl9hZGQocDIpLl9kaXZpZGVCeSgyKS5fc3VidHJhY3QodGhpcy5fY2VudGVyUG9pbnQpO1xuXHRcdFx0aWYgKHNjYWxlID09PSAxICYmIGRlbHRhLnggPT09IDAgJiYgZGVsdGEueSA9PT0gMCkgeyByZXR1cm47IH1cblx0XHRcdHRoaXMuX2NlbnRlciA9IG1hcC51bnByb2plY3QobWFwLnByb2plY3QodGhpcy5fcGluY2hTdGFydExhdExuZywgdGhpcy5fem9vbSkuc3VidHJhY3QoZGVsdGEpLCB0aGlzLl96b29tKTtcblx0XHR9XG5cblx0XHRpZiAoIXRoaXMuX21vdmVkKSB7XG5cdFx0XHRtYXAuX21vdmVTdGFydCh0cnVlKTtcblx0XHRcdHRoaXMuX21vdmVkID0gdHJ1ZTtcblx0XHR9XG5cblx0XHRMLlV0aWwuY2FuY2VsQW5pbUZyYW1lKHRoaXMuX2FuaW1SZXF1ZXN0KTtcblxuXHRcdHZhciBtb3ZlRm4gPSBMLmJpbmQobWFwLl9tb3ZlLCBtYXAsIHRoaXMuX2NlbnRlciwgdGhpcy5fem9vbSwge3BpbmNoOiB0cnVlLCByb3VuZDogZmFsc2V9KTtcblx0XHR0aGlzLl9hbmltUmVxdWVzdCA9IEwuVXRpbC5yZXF1ZXN0QW5pbUZyYW1lKG1vdmVGbiwgdGhpcywgdHJ1ZSk7XG5cblx0XHRMLkRvbUV2ZW50LnByZXZlbnREZWZhdWx0KGUpO1xuXHR9LFxuXG5cdF9vblRvdWNoRW5kOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKCF0aGlzLl9tb3ZlZCB8fCAhdGhpcy5fem9vbWluZykge1xuXHRcdFx0dGhpcy5fem9vbWluZyA9IGZhbHNlO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHRoaXMuX3pvb21pbmcgPSBmYWxzZTtcblx0XHRMLlV0aWwuY2FuY2VsQW5pbUZyYW1lKHRoaXMuX2FuaW1SZXF1ZXN0KTtcblxuXHRcdEwuRG9tRXZlbnRcblx0XHQgICAgLm9mZihkb2N1bWVudCwgJ3RvdWNobW92ZScsIHRoaXMuX29uVG91Y2hNb3ZlKVxuXHRcdCAgICAub2ZmKGRvY3VtZW50LCAndG91Y2hlbmQnLCB0aGlzLl9vblRvdWNoRW5kKTtcblxuXHRcdC8vIFBpbmNoIHVwZGF0ZXMgR3JpZExheWVycycgbGV2ZWxzIG9ubHkgd2hlbiB6b29tU25hcCBpcyBvZmYsIHNvIHpvb21TbmFwIGJlY29tZXMgbm9VcGRhdGUuXG5cdFx0aWYgKHRoaXMuX21hcC5vcHRpb25zLnpvb21BbmltYXRpb24pIHtcblx0XHRcdHRoaXMuX21hcC5fYW5pbWF0ZVpvb20odGhpcy5fY2VudGVyLCB0aGlzLl9tYXAuX2xpbWl0Wm9vbSh0aGlzLl96b29tKSwgdHJ1ZSwgdGhpcy5fbWFwLm9wdGlvbnMuem9vbVNuYXApO1xuXHRcdH0gZWxzZSB7XG5cdFx0XHR0aGlzLl9tYXAuX3Jlc2V0Vmlldyh0aGlzLl9jZW50ZXIsIHRoaXMuX21hcC5fbGltaXRab29tKHRoaXMuX3pvb20pKTtcblx0XHR9XG5cdH1cbn0pO1xuXG4vLyBAc2VjdGlvbiBIYW5kbGVyc1xuLy8gQHByb3BlcnR5IHRvdWNoWm9vbTogSGFuZGxlclxuLy8gVG91Y2ggem9vbSBoYW5kbGVyLlxuTC5NYXAuYWRkSW5pdEhvb2soJ2FkZEhhbmRsZXInLCAndG91Y2hab29tJywgTC5NYXAuVG91Y2hab29tKTtcblxuXG5cbi8qXG4gKiBMLk1hcC5UYXAgaXMgdXNlZCB0byBlbmFibGUgbW9iaWxlIGhhY2tzIGxpa2UgcXVpY2sgdGFwcyBhbmQgbG9uZyBob2xkLlxuICovXG5cbi8vIEBuYW1lc3BhY2UgTWFwXG4vLyBAc2VjdGlvbiBJbnRlcmFjdGlvbiBPcHRpb25zXG5MLk1hcC5tZXJnZU9wdGlvbnMoe1xuXHQvLyBAc2VjdGlvbiBUb3VjaCBpbnRlcmFjdGlvbiBvcHRpb25zXG5cdC8vIEBvcHRpb24gdGFwOiBCb29sZWFuID0gdHJ1ZVxuXHQvLyBFbmFibGVzIG1vYmlsZSBoYWNrcyBmb3Igc3VwcG9ydGluZyBpbnN0YW50IHRhcHMgKGZpeGluZyAyMDBtcyBjbGlja1xuXHQvLyBkZWxheSBvbiBpT1MvQW5kcm9pZCkgYW5kIHRvdWNoIGhvbGRzIChmaXJlZCBhcyBgY29udGV4dG1lbnVgIGV2ZW50cykuXG5cdHRhcDogdHJ1ZSxcblxuXHQvLyBAb3B0aW9uIHRhcFRvbGVyYW5jZTogTnVtYmVyID0gMTVcblx0Ly8gVGhlIG1heCBudW1iZXIgb2YgcGl4ZWxzIGEgdXNlciBjYW4gc2hpZnQgaGlzIGZpbmdlciBkdXJpbmcgdG91Y2hcblx0Ly8gZm9yIGl0IHRvIGJlIGNvbnNpZGVyZWQgYSB2YWxpZCB0YXAuXG5cdHRhcFRvbGVyYW5jZTogMTVcbn0pO1xuXG5MLk1hcC5UYXAgPSBMLkhhbmRsZXIuZXh0ZW5kKHtcblx0YWRkSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHRMLkRvbUV2ZW50Lm9uKHRoaXMuX21hcC5fY29udGFpbmVyLCAndG91Y2hzdGFydCcsIHRoaXMuX29uRG93biwgdGhpcyk7XG5cdH0sXG5cblx0cmVtb3ZlSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHRMLkRvbUV2ZW50Lm9mZih0aGlzLl9tYXAuX2NvbnRhaW5lciwgJ3RvdWNoc3RhcnQnLCB0aGlzLl9vbkRvd24sIHRoaXMpO1xuXHR9LFxuXG5cdF9vbkRvd246IGZ1bmN0aW9uIChlKSB7XG5cdFx0aWYgKCFlLnRvdWNoZXMpIHsgcmV0dXJuOyB9XG5cblx0XHRMLkRvbUV2ZW50LnByZXZlbnREZWZhdWx0KGUpO1xuXG5cdFx0dGhpcy5fZmlyZUNsaWNrID0gdHJ1ZTtcblxuXHRcdC8vIGRvbid0IHNpbXVsYXRlIGNsaWNrIG9yIHRyYWNrIGxvbmdwcmVzcyBpZiBtb3JlIHRoYW4gMSB0b3VjaFxuXHRcdGlmIChlLnRvdWNoZXMubGVuZ3RoID4gMSkge1xuXHRcdFx0dGhpcy5fZmlyZUNsaWNrID0gZmFsc2U7XG5cdFx0XHRjbGVhclRpbWVvdXQodGhpcy5faG9sZFRpbWVvdXQpO1xuXHRcdFx0cmV0dXJuO1xuXHRcdH1cblxuXHRcdHZhciBmaXJzdCA9IGUudG91Y2hlc1swXSxcblx0XHQgICAgZWwgPSBmaXJzdC50YXJnZXQ7XG5cblx0XHR0aGlzLl9zdGFydFBvcyA9IHRoaXMuX25ld1BvcyA9IG5ldyBMLlBvaW50KGZpcnN0LmNsaWVudFgsIGZpcnN0LmNsaWVudFkpO1xuXG5cdFx0Ly8gaWYgdG91Y2hpbmcgYSBsaW5rLCBoaWdobGlnaHQgaXRcblx0XHRpZiAoZWwudGFnTmFtZSAmJiBlbC50YWdOYW1lLnRvTG93ZXJDYXNlKCkgPT09ICdhJykge1xuXHRcdFx0TC5Eb21VdGlsLmFkZENsYXNzKGVsLCAnbGVhZmxldC1hY3RpdmUnKTtcblx0XHR9XG5cblx0XHQvLyBzaW11bGF0ZSBsb25nIGhvbGQgYnV0IHNldHRpbmcgYSB0aW1lb3V0XG5cdFx0dGhpcy5faG9sZFRpbWVvdXQgPSBzZXRUaW1lb3V0KEwuYmluZChmdW5jdGlvbiAoKSB7XG5cdFx0XHRpZiAodGhpcy5faXNUYXBWYWxpZCgpKSB7XG5cdFx0XHRcdHRoaXMuX2ZpcmVDbGljayA9IGZhbHNlO1xuXHRcdFx0XHR0aGlzLl9vblVwKCk7XG5cdFx0XHRcdHRoaXMuX3NpbXVsYXRlRXZlbnQoJ2NvbnRleHRtZW51JywgZmlyc3QpO1xuXHRcdFx0fVxuXHRcdH0sIHRoaXMpLCAxMDAwKTtcblxuXHRcdHRoaXMuX3NpbXVsYXRlRXZlbnQoJ21vdXNlZG93bicsIGZpcnN0KTtcblxuXHRcdEwuRG9tRXZlbnQub24oZG9jdW1lbnQsIHtcblx0XHRcdHRvdWNobW92ZTogdGhpcy5fb25Nb3ZlLFxuXHRcdFx0dG91Y2hlbmQ6IHRoaXMuX29uVXBcblx0XHR9LCB0aGlzKTtcblx0fSxcblxuXHRfb25VcDogZnVuY3Rpb24gKGUpIHtcblx0XHRjbGVhclRpbWVvdXQodGhpcy5faG9sZFRpbWVvdXQpO1xuXG5cdFx0TC5Eb21FdmVudC5vZmYoZG9jdW1lbnQsIHtcblx0XHRcdHRvdWNobW92ZTogdGhpcy5fb25Nb3ZlLFxuXHRcdFx0dG91Y2hlbmQ6IHRoaXMuX29uVXBcblx0XHR9LCB0aGlzKTtcblxuXHRcdGlmICh0aGlzLl9maXJlQ2xpY2sgJiYgZSAmJiBlLmNoYW5nZWRUb3VjaGVzKSB7XG5cblx0XHRcdHZhciBmaXJzdCA9IGUuY2hhbmdlZFRvdWNoZXNbMF0sXG5cdFx0XHQgICAgZWwgPSBmaXJzdC50YXJnZXQ7XG5cblx0XHRcdGlmIChlbCAmJiBlbC50YWdOYW1lICYmIGVsLnRhZ05hbWUudG9Mb3dlckNhc2UoKSA9PT0gJ2EnKSB7XG5cdFx0XHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyhlbCwgJ2xlYWZsZXQtYWN0aXZlJyk7XG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX3NpbXVsYXRlRXZlbnQoJ21vdXNldXAnLCBmaXJzdCk7XG5cblx0XHRcdC8vIHNpbXVsYXRlIGNsaWNrIGlmIHRoZSB0b3VjaCBkaWRuJ3QgbW92ZSB0b28gbXVjaFxuXHRcdFx0aWYgKHRoaXMuX2lzVGFwVmFsaWQoKSkge1xuXHRcdFx0XHR0aGlzLl9zaW11bGF0ZUV2ZW50KCdjbGljaycsIGZpcnN0KTtcblx0XHRcdH1cblx0XHR9XG5cdH0sXG5cblx0X2lzVGFwVmFsaWQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fbmV3UG9zLmRpc3RhbmNlVG8odGhpcy5fc3RhcnRQb3MpIDw9IHRoaXMuX21hcC5vcHRpb25zLnRhcFRvbGVyYW5jZTtcblx0fSxcblxuXHRfb25Nb3ZlOiBmdW5jdGlvbiAoZSkge1xuXHRcdHZhciBmaXJzdCA9IGUudG91Y2hlc1swXTtcblx0XHR0aGlzLl9uZXdQb3MgPSBuZXcgTC5Qb2ludChmaXJzdC5jbGllbnRYLCBmaXJzdC5jbGllbnRZKTtcblx0XHR0aGlzLl9zaW11bGF0ZUV2ZW50KCdtb3VzZW1vdmUnLCBmaXJzdCk7XG5cdH0sXG5cblx0X3NpbXVsYXRlRXZlbnQ6IGZ1bmN0aW9uICh0eXBlLCBlKSB7XG5cdFx0dmFyIHNpbXVsYXRlZEV2ZW50ID0gZG9jdW1lbnQuY3JlYXRlRXZlbnQoJ01vdXNlRXZlbnRzJyk7XG5cblx0XHRzaW11bGF0ZWRFdmVudC5fc2ltdWxhdGVkID0gdHJ1ZTtcblx0XHRlLnRhcmdldC5fc2ltdWxhdGVkQ2xpY2sgPSB0cnVlO1xuXG5cdFx0c2ltdWxhdGVkRXZlbnQuaW5pdE1vdXNlRXZlbnQoXG5cdFx0ICAgICAgICB0eXBlLCB0cnVlLCB0cnVlLCB3aW5kb3csIDEsXG5cdFx0ICAgICAgICBlLnNjcmVlblgsIGUuc2NyZWVuWSxcblx0XHQgICAgICAgIGUuY2xpZW50WCwgZS5jbGllbnRZLFxuXHRcdCAgICAgICAgZmFsc2UsIGZhbHNlLCBmYWxzZSwgZmFsc2UsIDAsIG51bGwpO1xuXG5cdFx0ZS50YXJnZXQuZGlzcGF0Y2hFdmVudChzaW11bGF0ZWRFdmVudCk7XG5cdH1cbn0pO1xuXG4vLyBAc2VjdGlvbiBIYW5kbGVyc1xuLy8gQHByb3BlcnR5IHRhcDogSGFuZGxlclxuLy8gTW9iaWxlIHRvdWNoIGhhY2tzIChxdWljayB0YXAgYW5kIHRvdWNoIGhvbGQpIGhhbmRsZXIuXG5pZiAoTC5Ccm93c2VyLnRvdWNoICYmICFMLkJyb3dzZXIucG9pbnRlcikge1xuXHRMLk1hcC5hZGRJbml0SG9vaygnYWRkSGFuZGxlcicsICd0YXAnLCBMLk1hcC5UYXApO1xufVxuXG5cblxuLypcbiAqIEwuSGFuZGxlci5Cb3hab29tIGlzIHVzZWQgdG8gYWRkIHNoaWZ0LWRyYWcgem9vbSBpbnRlcmFjdGlvbiB0byB0aGUgbWFwXG4gKiAoem9vbSB0byBhIHNlbGVjdGVkIGJvdW5kaW5nIGJveCksIGVuYWJsZWQgYnkgZGVmYXVsdC5cbiAqL1xuXG4vLyBAbmFtZXNwYWNlIE1hcFxuLy8gQHNlY3Rpb24gSW50ZXJhY3Rpb24gT3B0aW9uc1xuTC5NYXAubWVyZ2VPcHRpb25zKHtcblx0Ly8gQG9wdGlvbiBib3hab29tOiBCb29sZWFuID0gdHJ1ZVxuXHQvLyBXaGV0aGVyIHRoZSBtYXAgY2FuIGJlIHpvb21lZCB0byBhIHJlY3Rhbmd1bGFyIGFyZWEgc3BlY2lmaWVkIGJ5XG5cdC8vIGRyYWdnaW5nIHRoZSBtb3VzZSB3aGlsZSBwcmVzc2luZyB0aGUgc2hpZnQga2V5LlxuXHRib3hab29tOiB0cnVlXG59KTtcblxuTC5NYXAuQm94Wm9vbSA9IEwuSGFuZGxlci5leHRlbmQoe1xuXHRpbml0aWFsaXplOiBmdW5jdGlvbiAobWFwKSB7XG5cdFx0dGhpcy5fbWFwID0gbWFwO1xuXHRcdHRoaXMuX2NvbnRhaW5lciA9IG1hcC5fY29udGFpbmVyO1xuXHRcdHRoaXMuX3BhbmUgPSBtYXAuX3BhbmVzLm92ZXJsYXlQYW5lO1xuXHR9LFxuXG5cdGFkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0TC5Eb21FdmVudC5vbih0aGlzLl9jb250YWluZXIsICdtb3VzZWRvd24nLCB0aGlzLl9vbk1vdXNlRG93biwgdGhpcyk7XG5cdH0sXG5cblx0cmVtb3ZlSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHRMLkRvbUV2ZW50Lm9mZih0aGlzLl9jb250YWluZXIsICdtb3VzZWRvd24nLCB0aGlzLl9vbk1vdXNlRG93biwgdGhpcyk7XG5cdH0sXG5cblx0bW92ZWQ6IGZ1bmN0aW9uICgpIHtcblx0XHRyZXR1cm4gdGhpcy5fbW92ZWQ7XG5cdH0sXG5cblx0X3Jlc2V0U3RhdGU6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9tb3ZlZCA9IGZhbHNlO1xuXHR9LFxuXG5cdF9vbk1vdXNlRG93bjogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAoIWUuc2hpZnRLZXkgfHwgKChlLndoaWNoICE9PSAxKSAmJiAoZS5idXR0b24gIT09IDEpKSkgeyByZXR1cm4gZmFsc2U7IH1cblxuXHRcdHRoaXMuX3Jlc2V0U3RhdGUoKTtcblxuXHRcdEwuRG9tVXRpbC5kaXNhYmxlVGV4dFNlbGVjdGlvbigpO1xuXHRcdEwuRG9tVXRpbC5kaXNhYmxlSW1hZ2VEcmFnKCk7XG5cblx0XHR0aGlzLl9zdGFydFBvaW50ID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50KGUpO1xuXG5cdFx0TC5Eb21FdmVudC5vbihkb2N1bWVudCwge1xuXHRcdFx0Y29udGV4dG1lbnU6IEwuRG9tRXZlbnQuc3RvcCxcblx0XHRcdG1vdXNlbW92ZTogdGhpcy5fb25Nb3VzZU1vdmUsXG5cdFx0XHRtb3VzZXVwOiB0aGlzLl9vbk1vdXNlVXAsXG5cdFx0XHRrZXlkb3duOiB0aGlzLl9vbktleURvd25cblx0XHR9LCB0aGlzKTtcblx0fSxcblxuXHRfb25Nb3VzZU1vdmU6IGZ1bmN0aW9uIChlKSB7XG5cdFx0aWYgKCF0aGlzLl9tb3ZlZCkge1xuXHRcdFx0dGhpcy5fbW92ZWQgPSB0cnVlO1xuXG5cdFx0XHR0aGlzLl9ib3ggPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCAnbGVhZmxldC16b29tLWJveCcsIHRoaXMuX2NvbnRhaW5lcik7XG5cdFx0XHRMLkRvbVV0aWwuYWRkQ2xhc3ModGhpcy5fY29udGFpbmVyLCAnbGVhZmxldC1jcm9zc2hhaXInKTtcblxuXHRcdFx0dGhpcy5fbWFwLmZpcmUoJ2JveHpvb21zdGFydCcpO1xuXHRcdH1cblxuXHRcdHRoaXMuX3BvaW50ID0gdGhpcy5fbWFwLm1vdXNlRXZlbnRUb0NvbnRhaW5lclBvaW50KGUpO1xuXG5cdFx0dmFyIGJvdW5kcyA9IG5ldyBMLkJvdW5kcyh0aGlzLl9wb2ludCwgdGhpcy5fc3RhcnRQb2ludCksXG5cdFx0ICAgIHNpemUgPSBib3VuZHMuZ2V0U2l6ZSgpO1xuXG5cdFx0TC5Eb21VdGlsLnNldFBvc2l0aW9uKHRoaXMuX2JveCwgYm91bmRzLm1pbik7XG5cblx0XHR0aGlzLl9ib3guc3R5bGUud2lkdGggID0gc2l6ZS54ICsgJ3B4Jztcblx0XHR0aGlzLl9ib3guc3R5bGUuaGVpZ2h0ID0gc2l6ZS55ICsgJ3B4Jztcblx0fSxcblxuXHRfZmluaXNoOiBmdW5jdGlvbiAoKSB7XG5cdFx0aWYgKHRoaXMuX21vdmVkKSB7XG5cdFx0XHRMLkRvbVV0aWwucmVtb3ZlKHRoaXMuX2JveCk7XG5cdFx0XHRMLkRvbVV0aWwucmVtb3ZlQ2xhc3ModGhpcy5fY29udGFpbmVyLCAnbGVhZmxldC1jcm9zc2hhaXInKTtcblx0XHR9XG5cblx0XHRMLkRvbVV0aWwuZW5hYmxlVGV4dFNlbGVjdGlvbigpO1xuXHRcdEwuRG9tVXRpbC5lbmFibGVJbWFnZURyYWcoKTtcblxuXHRcdEwuRG9tRXZlbnQub2ZmKGRvY3VtZW50LCB7XG5cdFx0XHRjb250ZXh0bWVudTogTC5Eb21FdmVudC5zdG9wLFxuXHRcdFx0bW91c2Vtb3ZlOiB0aGlzLl9vbk1vdXNlTW92ZSxcblx0XHRcdG1vdXNldXA6IHRoaXMuX29uTW91c2VVcCxcblx0XHRcdGtleWRvd246IHRoaXMuX29uS2V5RG93blxuXHRcdH0sIHRoaXMpO1xuXHR9LFxuXG5cdF9vbk1vdXNlVXA6IGZ1bmN0aW9uIChlKSB7XG5cdFx0aWYgKChlLndoaWNoICE9PSAxKSAmJiAoZS5idXR0b24gIT09IDEpKSB7IHJldHVybjsgfVxuXG5cdFx0dGhpcy5fZmluaXNoKCk7XG5cblx0XHRpZiAoIXRoaXMuX21vdmVkKSB7IHJldHVybjsgfVxuXHRcdC8vIFBvc3Rwb25lIHRvIG5leHQgSlMgdGljayBzbyBpbnRlcm5hbCBjbGljayBldmVudCBoYW5kbGluZ1xuXHRcdC8vIHN0aWxsIHNlZSBpdCBhcyBcIm1vdmVkXCIuXG5cdFx0c2V0VGltZW91dChMLmJpbmQodGhpcy5fcmVzZXRTdGF0ZSwgdGhpcyksIDApO1xuXG5cdFx0dmFyIGJvdW5kcyA9IG5ldyBMLkxhdExuZ0JvdW5kcyhcblx0XHQgICAgICAgIHRoaXMuX21hcC5jb250YWluZXJQb2ludFRvTGF0TG5nKHRoaXMuX3N0YXJ0UG9pbnQpLFxuXHRcdCAgICAgICAgdGhpcy5fbWFwLmNvbnRhaW5lclBvaW50VG9MYXRMbmcodGhpcy5fcG9pbnQpKTtcblxuXHRcdHRoaXMuX21hcFxuXHRcdFx0LmZpdEJvdW5kcyhib3VuZHMpXG5cdFx0XHQuZmlyZSgnYm94em9vbWVuZCcsIHtib3hab29tQm91bmRzOiBib3VuZHN9KTtcblx0fSxcblxuXHRfb25LZXlEb3duOiBmdW5jdGlvbiAoZSkge1xuXHRcdGlmIChlLmtleUNvZGUgPT09IDI3KSB7XG5cdFx0XHR0aGlzLl9maW5pc2goKTtcblx0XHR9XG5cdH1cbn0pO1xuXG4vLyBAc2VjdGlvbiBIYW5kbGVyc1xuLy8gQHByb3BlcnR5IGJveFpvb206IEhhbmRsZXJcbi8vIEJveCAoc2hpZnQtZHJhZyB3aXRoIG1vdXNlKSB6b29tIGhhbmRsZXIuXG5MLk1hcC5hZGRJbml0SG9vaygnYWRkSGFuZGxlcicsICdib3hab29tJywgTC5NYXAuQm94Wm9vbSk7XG5cblxuXG4vKlxuICogTC5NYXAuS2V5Ym9hcmQgaXMgaGFuZGxpbmcga2V5Ym9hcmQgaW50ZXJhY3Rpb24gd2l0aCB0aGUgbWFwLCBlbmFibGVkIGJ5IGRlZmF1bHQuXG4gKi9cblxuLy8gQG5hbWVzcGFjZSBNYXBcbi8vIEBzZWN0aW9uIEtleWJvYXJkIE5hdmlnYXRpb24gT3B0aW9uc1xuTC5NYXAubWVyZ2VPcHRpb25zKHtcblx0Ly8gQG9wdGlvbiBrZXlib2FyZDogQm9vbGVhbiA9IHRydWVcblx0Ly8gTWFrZXMgdGhlIG1hcCBmb2N1c2FibGUgYW5kIGFsbG93cyB1c2VycyB0byBuYXZpZ2F0ZSB0aGUgbWFwIHdpdGgga2V5Ym9hcmRcblx0Ly8gYXJyb3dzIGFuZCBgK2AvYC1gIGtleXMuXG5cdGtleWJvYXJkOiB0cnVlLFxuXG5cdC8vIEBvcHRpb24ga2V5Ym9hcmRQYW5EZWx0YTogTnVtYmVyID0gODBcblx0Ly8gQW1vdW50IG9mIHBpeGVscyB0byBwYW4gd2hlbiBwcmVzc2luZyBhbiBhcnJvdyBrZXkuXG5cdGtleWJvYXJkUGFuRGVsdGE6IDgwXG59KTtcblxuTC5NYXAuS2V5Ym9hcmQgPSBMLkhhbmRsZXIuZXh0ZW5kKHtcblxuXHRrZXlDb2Rlczoge1xuXHRcdGxlZnQ6ICAgIFszN10sXG5cdFx0cmlnaHQ6ICAgWzM5XSxcblx0XHRkb3duOiAgICBbNDBdLFxuXHRcdHVwOiAgICAgIFszOF0sXG5cdFx0em9vbUluOiAgWzE4NywgMTA3LCA2MSwgMTcxXSxcblx0XHR6b29tT3V0OiBbMTg5LCAxMDksIDU0LCAxNzNdXG5cdH0sXG5cblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKG1hcCkge1xuXHRcdHRoaXMuX21hcCA9IG1hcDtcblxuXHRcdHRoaXMuX3NldFBhbkRlbHRhKG1hcC5vcHRpb25zLmtleWJvYXJkUGFuRGVsdGEpO1xuXHRcdHRoaXMuX3NldFpvb21EZWx0YShtYXAub3B0aW9ucy56b29tRGVsdGEpO1xuXHR9LFxuXG5cdGFkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0dmFyIGNvbnRhaW5lciA9IHRoaXMuX21hcC5fY29udGFpbmVyO1xuXG5cdFx0Ly8gbWFrZSB0aGUgY29udGFpbmVyIGZvY3VzYWJsZSBieSB0YWJiaW5nXG5cdFx0aWYgKGNvbnRhaW5lci50YWJJbmRleCA8PSAwKSB7XG5cdFx0XHRjb250YWluZXIudGFiSW5kZXggPSAnMCc7XG5cdFx0fVxuXG5cdFx0TC5Eb21FdmVudC5vbihjb250YWluZXIsIHtcblx0XHRcdGZvY3VzOiB0aGlzLl9vbkZvY3VzLFxuXHRcdFx0Ymx1cjogdGhpcy5fb25CbHVyLFxuXHRcdFx0bW91c2Vkb3duOiB0aGlzLl9vbk1vdXNlRG93blxuXHRcdH0sIHRoaXMpO1xuXG5cdFx0dGhpcy5fbWFwLm9uKHtcblx0XHRcdGZvY3VzOiB0aGlzLl9hZGRIb29rcyxcblx0XHRcdGJsdXI6IHRoaXMuX3JlbW92ZUhvb2tzXG5cdFx0fSwgdGhpcyk7XG5cdH0sXG5cblx0cmVtb3ZlSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9yZW1vdmVIb29rcygpO1xuXG5cdFx0TC5Eb21FdmVudC5vZmYodGhpcy5fbWFwLl9jb250YWluZXIsIHtcblx0XHRcdGZvY3VzOiB0aGlzLl9vbkZvY3VzLFxuXHRcdFx0Ymx1cjogdGhpcy5fb25CbHVyLFxuXHRcdFx0bW91c2Vkb3duOiB0aGlzLl9vbk1vdXNlRG93blxuXHRcdH0sIHRoaXMpO1xuXG5cdFx0dGhpcy5fbWFwLm9mZih7XG5cdFx0XHRmb2N1czogdGhpcy5fYWRkSG9va3MsXG5cdFx0XHRibHVyOiB0aGlzLl9yZW1vdmVIb29rc1xuXHRcdH0sIHRoaXMpO1xuXHR9LFxuXG5cdF9vbk1vdXNlRG93bjogZnVuY3Rpb24gKCkge1xuXHRcdGlmICh0aGlzLl9mb2N1c2VkKSB7IHJldHVybjsgfVxuXG5cdFx0dmFyIGJvZHkgPSBkb2N1bWVudC5ib2R5LFxuXHRcdCAgICBkb2NFbCA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudCxcblx0XHQgICAgdG9wID0gYm9keS5zY3JvbGxUb3AgfHwgZG9jRWwuc2Nyb2xsVG9wLFxuXHRcdCAgICBsZWZ0ID0gYm9keS5zY3JvbGxMZWZ0IHx8IGRvY0VsLnNjcm9sbExlZnQ7XG5cblx0XHR0aGlzLl9tYXAuX2NvbnRhaW5lci5mb2N1cygpO1xuXG5cdFx0d2luZG93LnNjcm9sbFRvKGxlZnQsIHRvcCk7XG5cdH0sXG5cblx0X29uRm9jdXM6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9mb2N1c2VkID0gdHJ1ZTtcblx0XHR0aGlzLl9tYXAuZmlyZSgnZm9jdXMnKTtcblx0fSxcblxuXHRfb25CbHVyOiBmdW5jdGlvbiAoKSB7XG5cdFx0dGhpcy5fZm9jdXNlZCA9IGZhbHNlO1xuXHRcdHRoaXMuX21hcC5maXJlKCdibHVyJyk7XG5cdH0sXG5cblx0X3NldFBhbkRlbHRhOiBmdW5jdGlvbiAocGFuRGVsdGEpIHtcblx0XHR2YXIga2V5cyA9IHRoaXMuX3BhbktleXMgPSB7fSxcblx0XHQgICAgY29kZXMgPSB0aGlzLmtleUNvZGVzLFxuXHRcdCAgICBpLCBsZW47XG5cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjb2Rlcy5sZWZ0Lmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRrZXlzW2NvZGVzLmxlZnRbaV1dID0gWy0xICogcGFuRGVsdGEsIDBdO1xuXHRcdH1cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjb2Rlcy5yaWdodC5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0a2V5c1tjb2Rlcy5yaWdodFtpXV0gPSBbcGFuRGVsdGEsIDBdO1xuXHRcdH1cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjb2Rlcy5kb3duLmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRrZXlzW2NvZGVzLmRvd25baV1dID0gWzAsIHBhbkRlbHRhXTtcblx0XHR9XG5cdFx0Zm9yIChpID0gMCwgbGVuID0gY29kZXMudXAubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcblx0XHRcdGtleXNbY29kZXMudXBbaV1dID0gWzAsIC0xICogcGFuRGVsdGFdO1xuXHRcdH1cblx0fSxcblxuXHRfc2V0Wm9vbURlbHRhOiBmdW5jdGlvbiAoem9vbURlbHRhKSB7XG5cdFx0dmFyIGtleXMgPSB0aGlzLl96b29tS2V5cyA9IHt9LFxuXHRcdCAgICBjb2RlcyA9IHRoaXMua2V5Q29kZXMsXG5cdFx0ICAgIGksIGxlbjtcblxuXHRcdGZvciAoaSA9IDAsIGxlbiA9IGNvZGVzLnpvb21Jbi5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuXHRcdFx0a2V5c1tjb2Rlcy56b29tSW5baV1dID0gem9vbURlbHRhO1xuXHRcdH1cblx0XHRmb3IgKGkgPSAwLCBsZW4gPSBjb2Rlcy56b29tT3V0Lmxlbmd0aDsgaSA8IGxlbjsgaSsrKSB7XG5cdFx0XHRrZXlzW2NvZGVzLnpvb21PdXRbaV1dID0gLXpvb21EZWx0YTtcblx0XHR9XG5cdH0sXG5cblx0X2FkZEhvb2tzOiBmdW5jdGlvbiAoKSB7XG5cdFx0TC5Eb21FdmVudC5vbihkb2N1bWVudCwgJ2tleWRvd24nLCB0aGlzLl9vbktleURvd24sIHRoaXMpO1xuXHR9LFxuXG5cdF9yZW1vdmVIb29rczogZnVuY3Rpb24gKCkge1xuXHRcdEwuRG9tRXZlbnQub2ZmKGRvY3VtZW50LCAna2V5ZG93bicsIHRoaXMuX29uS2V5RG93biwgdGhpcyk7XG5cdH0sXG5cblx0X29uS2V5RG93bjogZnVuY3Rpb24gKGUpIHtcblx0XHRpZiAoZS5hbHRLZXkgfHwgZS5jdHJsS2V5IHx8IGUubWV0YUtleSkgeyByZXR1cm47IH1cblxuXHRcdHZhciBrZXkgPSBlLmtleUNvZGUsXG5cdFx0ICAgIG1hcCA9IHRoaXMuX21hcCxcblx0XHQgICAgb2Zmc2V0O1xuXG5cdFx0aWYgKGtleSBpbiB0aGlzLl9wYW5LZXlzKSB7XG5cblx0XHRcdGlmIChtYXAuX3BhbkFuaW0gJiYgbWFwLl9wYW5BbmltLl9pblByb2dyZXNzKSB7IHJldHVybjsgfVxuXG5cdFx0XHRvZmZzZXQgPSB0aGlzLl9wYW5LZXlzW2tleV07XG5cdFx0XHRpZiAoZS5zaGlmdEtleSkge1xuXHRcdFx0XHRvZmZzZXQgPSBMLnBvaW50KG9mZnNldCkubXVsdGlwbHlCeSgzKTtcblx0XHRcdH1cblxuXHRcdFx0bWFwLnBhbkJ5KG9mZnNldCk7XG5cblx0XHRcdGlmIChtYXAub3B0aW9ucy5tYXhCb3VuZHMpIHtcblx0XHRcdFx0bWFwLnBhbkluc2lkZUJvdW5kcyhtYXAub3B0aW9ucy5tYXhCb3VuZHMpO1xuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIGlmIChrZXkgaW4gdGhpcy5fem9vbUtleXMpIHtcblx0XHRcdG1hcC5zZXRab29tKG1hcC5nZXRab29tKCkgKyAoZS5zaGlmdEtleSA/IDMgOiAxKSAqIHRoaXMuX3pvb21LZXlzW2tleV0pO1xuXG5cdFx0fSBlbHNlIGlmIChrZXkgPT09IDI3KSB7XG5cdFx0XHRtYXAuY2xvc2VQb3B1cCgpO1xuXG5cdFx0fSBlbHNlIHtcblx0XHRcdHJldHVybjtcblx0XHR9XG5cblx0XHRMLkRvbUV2ZW50LnN0b3AoZSk7XG5cdH1cbn0pO1xuXG4vLyBAc2VjdGlvbiBIYW5kbGVyc1xuLy8gQHNlY3Rpb24gSGFuZGxlcnNcbi8vIEBwcm9wZXJ0eSBrZXlib2FyZDogSGFuZGxlclxuLy8gS2V5Ym9hcmQgbmF2aWdhdGlvbiBoYW5kbGVyLlxuTC5NYXAuYWRkSW5pdEhvb2soJ2FkZEhhbmRsZXInLCAna2V5Ym9hcmQnLCBMLk1hcC5LZXlib2FyZCk7XG5cblxuXG4vKlxuICogTC5IYW5kbGVyLk1hcmtlckRyYWcgaXMgdXNlZCBpbnRlcm5hbGx5IGJ5IEwuTWFya2VyIHRvIG1ha2UgdGhlIG1hcmtlcnMgZHJhZ2dhYmxlLlxuICovXG5cblxuLyogQG5hbWVzcGFjZSBNYXJrZXJcbiAqIEBzZWN0aW9uIEludGVyYWN0aW9uIGhhbmRsZXJzXG4gKlxuICogSW50ZXJhY3Rpb24gaGFuZGxlcnMgYXJlIHByb3BlcnRpZXMgb2YgYSBtYXJrZXIgaW5zdGFuY2UgdGhhdCBhbGxvdyB5b3UgdG8gY29udHJvbCBpbnRlcmFjdGlvbiBiZWhhdmlvciBpbiBydW50aW1lLCBlbmFibGluZyBvciBkaXNhYmxpbmcgY2VydGFpbiBmZWF0dXJlcyBzdWNoIGFzIGRyYWdnaW5nIChzZWUgYEhhbmRsZXJgIG1ldGhvZHMpLiBFeGFtcGxlOlxuICpcbiAqIGBgYGpzXG4gKiBtYXJrZXIuZHJhZ2dpbmcuZGlzYWJsZSgpO1xuICogYGBgXG4gKlxuICogQHByb3BlcnR5IGRyYWdnaW5nOiBIYW5kbGVyXG4gKiBNYXJrZXIgZHJhZ2dpbmcgaGFuZGxlciAoYnkgYm90aCBtb3VzZSBhbmQgdG91Y2gpLlxuICovXG5cbkwuSGFuZGxlci5NYXJrZXJEcmFnID0gTC5IYW5kbGVyLmV4dGVuZCh7XG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChtYXJrZXIpIHtcblx0XHR0aGlzLl9tYXJrZXIgPSBtYXJrZXI7XG5cdH0sXG5cblx0YWRkSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHR2YXIgaWNvbiA9IHRoaXMuX21hcmtlci5faWNvbjtcblxuXHRcdGlmICghdGhpcy5fZHJhZ2dhYmxlKSB7XG5cdFx0XHR0aGlzLl9kcmFnZ2FibGUgPSBuZXcgTC5EcmFnZ2FibGUoaWNvbiwgaWNvbiwgdHJ1ZSk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fZHJhZ2dhYmxlLm9uKHtcblx0XHRcdGRyYWdzdGFydDogdGhpcy5fb25EcmFnU3RhcnQsXG5cdFx0XHRkcmFnOiB0aGlzLl9vbkRyYWcsXG5cdFx0XHRkcmFnZW5kOiB0aGlzLl9vbkRyYWdFbmRcblx0XHR9LCB0aGlzKS5lbmFibGUoKTtcblxuXHRcdEwuRG9tVXRpbC5hZGRDbGFzcyhpY29uLCAnbGVhZmxldC1tYXJrZXItZHJhZ2dhYmxlJyk7XG5cdH0sXG5cblx0cmVtb3ZlSG9va3M6IGZ1bmN0aW9uICgpIHtcblx0XHR0aGlzLl9kcmFnZ2FibGUub2ZmKHtcblx0XHRcdGRyYWdzdGFydDogdGhpcy5fb25EcmFnU3RhcnQsXG5cdFx0XHRkcmFnOiB0aGlzLl9vbkRyYWcsXG5cdFx0XHRkcmFnZW5kOiB0aGlzLl9vbkRyYWdFbmRcblx0XHR9LCB0aGlzKS5kaXNhYmxlKCk7XG5cblx0XHRpZiAodGhpcy5fbWFya2VyLl9pY29uKSB7XG5cdFx0XHRMLkRvbVV0aWwucmVtb3ZlQ2xhc3ModGhpcy5fbWFya2VyLl9pY29uLCAnbGVhZmxldC1tYXJrZXItZHJhZ2dhYmxlJyk7XG5cdFx0fVxuXHR9LFxuXG5cdG1vdmVkOiBmdW5jdGlvbiAoKSB7XG5cdFx0cmV0dXJuIHRoaXMuX2RyYWdnYWJsZSAmJiB0aGlzLl9kcmFnZ2FibGUuX21vdmVkO1xuXHR9LFxuXG5cdF9vbkRyYWdTdGFydDogZnVuY3Rpb24gKCkge1xuXHRcdC8vIEBzZWN0aW9uIERyYWdnaW5nIGV2ZW50c1xuXHRcdC8vIEBldmVudCBkcmFnc3RhcnQ6IEV2ZW50XG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgdXNlciBzdGFydHMgZHJhZ2dpbmcgdGhlIG1hcmtlci5cblxuXHRcdC8vIEBldmVudCBtb3Zlc3RhcnQ6IEV2ZW50XG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgbWFya2VyIHN0YXJ0cyBtb3ZpbmcgKGJlY2F1c2Ugb2YgZHJhZ2dpbmcpLlxuXG5cdFx0dGhpcy5fb2xkTGF0TG5nID0gdGhpcy5fbWFya2VyLmdldExhdExuZygpO1xuXHRcdHRoaXMuX21hcmtlclxuXHRcdCAgICAuY2xvc2VQb3B1cCgpXG5cdFx0ICAgIC5maXJlKCdtb3Zlc3RhcnQnKVxuXHRcdCAgICAuZmlyZSgnZHJhZ3N0YXJ0Jyk7XG5cdH0sXG5cblx0X29uRHJhZzogZnVuY3Rpb24gKGUpIHtcblx0XHR2YXIgbWFya2VyID0gdGhpcy5fbWFya2VyLFxuXHRcdCAgICBzaGFkb3cgPSBtYXJrZXIuX3NoYWRvdyxcblx0XHQgICAgaWNvblBvcyA9IEwuRG9tVXRpbC5nZXRQb3NpdGlvbihtYXJrZXIuX2ljb24pLFxuXHRcdCAgICBsYXRsbmcgPSBtYXJrZXIuX21hcC5sYXllclBvaW50VG9MYXRMbmcoaWNvblBvcyk7XG5cblx0XHQvLyB1cGRhdGUgc2hhZG93IHBvc2l0aW9uXG5cdFx0aWYgKHNoYWRvdykge1xuXHRcdFx0TC5Eb21VdGlsLnNldFBvc2l0aW9uKHNoYWRvdywgaWNvblBvcyk7XG5cdFx0fVxuXG5cdFx0bWFya2VyLl9sYXRsbmcgPSBsYXRsbmc7XG5cdFx0ZS5sYXRsbmcgPSBsYXRsbmc7XG5cdFx0ZS5vbGRMYXRMbmcgPSB0aGlzLl9vbGRMYXRMbmc7XG5cblx0XHQvLyBAZXZlbnQgZHJhZzogRXZlbnRcblx0XHQvLyBGaXJlZCByZXBlYXRlZGx5IHdoaWxlIHRoZSB1c2VyIGRyYWdzIHRoZSBtYXJrZXIuXG5cdFx0bWFya2VyXG5cdFx0ICAgIC5maXJlKCdtb3ZlJywgZSlcblx0XHQgICAgLmZpcmUoJ2RyYWcnLCBlKTtcblx0fSxcblxuXHRfb25EcmFnRW5kOiBmdW5jdGlvbiAoZSkge1xuXHRcdC8vIEBldmVudCBkcmFnZW5kOiBEcmFnRW5kRXZlbnRcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSB1c2VyIHN0b3BzIGRyYWdnaW5nIHRoZSBtYXJrZXIuXG5cblx0XHQvLyBAZXZlbnQgbW92ZWVuZDogRXZlbnRcblx0XHQvLyBGaXJlZCB3aGVuIHRoZSBtYXJrZXIgc3RvcHMgbW92aW5nIChiZWNhdXNlIG9mIGRyYWdnaW5nKS5cblx0XHRkZWxldGUgdGhpcy5fb2xkTGF0TG5nO1xuXHRcdHRoaXMuX21hcmtlclxuXHRcdCAgICAuZmlyZSgnbW92ZWVuZCcpXG5cdFx0ICAgIC5maXJlKCdkcmFnZW5kJywgZSk7XG5cdH1cbn0pO1xuXG5cblxuLypcclxuICogQGNsYXNzIENvbnRyb2xcclxuICogQGFrYSBMLkNvbnRyb2xcclxuICogQGluaGVyaXRzIENsYXNzXHJcbiAqXHJcbiAqIEwuQ29udHJvbCBpcyBhIGJhc2UgY2xhc3MgZm9yIGltcGxlbWVudGluZyBtYXAgY29udHJvbHMuIEhhbmRsZXMgcG9zaXRpb25pbmcuXHJcbiAqIEFsbCBvdGhlciBjb250cm9scyBleHRlbmQgZnJvbSB0aGlzIGNsYXNzLlxyXG4gKi9cclxuXHJcbkwuQ29udHJvbCA9IEwuQ2xhc3MuZXh0ZW5kKHtcclxuXHQvLyBAc2VjdGlvblxyXG5cdC8vIEBha2EgQ29udHJvbCBvcHRpb25zXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQG9wdGlvbiBwb3NpdGlvbjogU3RyaW5nID0gJ3RvcHJpZ2h0J1xyXG5cdFx0Ly8gVGhlIHBvc2l0aW9uIG9mIHRoZSBjb250cm9sIChvbmUgb2YgdGhlIG1hcCBjb3JuZXJzKS4gUG9zc2libGUgdmFsdWVzIGFyZSBgJ3RvcGxlZnQnYCxcclxuXHRcdC8vIGAndG9wcmlnaHQnYCwgYCdib3R0b21sZWZ0J2Agb3IgYCdib3R0b21yaWdodCdgXHJcblx0XHRwb3NpdGlvbjogJ3RvcHJpZ2h0J1xyXG5cdH0sXHJcblxyXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcblx0XHRMLnNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XHJcblx0fSxcclxuXHJcblx0LyogQHNlY3Rpb25cclxuXHQgKiBDbGFzc2VzIGV4dGVuZGluZyBMLkNvbnRyb2wgd2lsbCBpbmhlcml0IHRoZSBmb2xsb3dpbmcgbWV0aG9kczpcclxuXHQgKlxyXG5cdCAqIEBtZXRob2QgZ2V0UG9zaXRpb246IHN0cmluZ1xyXG5cdCAqIFJldHVybnMgdGhlIHBvc2l0aW9uIG9mIHRoZSBjb250cm9sLlxyXG5cdCAqL1xyXG5cdGdldFBvc2l0aW9uOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRyZXR1cm4gdGhpcy5vcHRpb25zLnBvc2l0aW9uO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2Qgc2V0UG9zaXRpb24ocG9zaXRpb246IHN0cmluZyk6IHRoaXNcclxuXHQvLyBTZXRzIHRoZSBwb3NpdGlvbiBvZiB0aGUgY29udHJvbC5cclxuXHRzZXRQb3NpdGlvbjogZnVuY3Rpb24gKHBvc2l0aW9uKSB7XHJcblx0XHR2YXIgbWFwID0gdGhpcy5fbWFwO1xyXG5cclxuXHRcdGlmIChtYXApIHtcclxuXHRcdFx0bWFwLnJlbW92ZUNvbnRyb2wodGhpcyk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5vcHRpb25zLnBvc2l0aW9uID0gcG9zaXRpb247XHJcblxyXG5cdFx0aWYgKG1hcCkge1xyXG5cdFx0XHRtYXAuYWRkQ29udHJvbCh0aGlzKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGdldENvbnRhaW5lcjogSFRNTEVsZW1lbnRcclxuXHQvLyBSZXR1cm5zIHRoZSBIVE1MRWxlbWVudCB0aGF0IGNvbnRhaW5zIHRoZSBjb250cm9sLlxyXG5cdGdldENvbnRhaW5lcjogZnVuY3Rpb24gKCkge1xyXG5cdFx0cmV0dXJuIHRoaXMuX2NvbnRhaW5lcjtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGFkZFRvKG1hcDogTWFwKTogdGhpc1xyXG5cdC8vIEFkZHMgdGhlIGNvbnRyb2wgdG8gdGhlIGdpdmVuIG1hcC5cclxuXHRhZGRUbzogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0dGhpcy5yZW1vdmUoKTtcclxuXHRcdHRoaXMuX21hcCA9IG1hcDtcclxuXHJcblx0XHR2YXIgY29udGFpbmVyID0gdGhpcy5fY29udGFpbmVyID0gdGhpcy5vbkFkZChtYXApLFxyXG5cdFx0ICAgIHBvcyA9IHRoaXMuZ2V0UG9zaXRpb24oKSxcclxuXHRcdCAgICBjb3JuZXIgPSBtYXAuX2NvbnRyb2xDb3JuZXJzW3Bvc107XHJcblxyXG5cdFx0TC5Eb21VdGlsLmFkZENsYXNzKGNvbnRhaW5lciwgJ2xlYWZsZXQtY29udHJvbCcpO1xyXG5cclxuXHRcdGlmIChwb3MuaW5kZXhPZignYm90dG9tJykgIT09IC0xKSB7XHJcblx0XHRcdGNvcm5lci5pbnNlcnRCZWZvcmUoY29udGFpbmVyLCBjb3JuZXIuZmlyc3RDaGlsZCk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRjb3JuZXIuYXBwZW5kQ2hpbGQoY29udGFpbmVyKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlbW92ZTogdGhpc1xyXG5cdC8vIFJlbW92ZXMgdGhlIGNvbnRyb2wgZnJvbSB0aGUgbWFwIGl0IGlzIGN1cnJlbnRseSBhY3RpdmUgb24uXHJcblx0cmVtb3ZlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX21hcCkge1xyXG5cdFx0XHRyZXR1cm4gdGhpcztcclxuXHRcdH1cclxuXHJcblx0XHRMLkRvbVV0aWwucmVtb3ZlKHRoaXMuX2NvbnRhaW5lcik7XHJcblxyXG5cdFx0aWYgKHRoaXMub25SZW1vdmUpIHtcclxuXHRcdFx0dGhpcy5vblJlbW92ZSh0aGlzLl9tYXApO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX21hcCA9IG51bGw7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0X3JlZm9jdXNPbk1hcDogZnVuY3Rpb24gKGUpIHtcclxuXHRcdC8vIGlmIG1hcCBleGlzdHMgYW5kIGV2ZW50IGlzIG5vdCBhIGtleWJvYXJkIGV2ZW50XHJcblx0XHRpZiAodGhpcy5fbWFwICYmIGUgJiYgZS5zY3JlZW5YID4gMCAmJiBlLnNjcmVlblkgPiAwKSB7XHJcblx0XHRcdHRoaXMuX21hcC5nZXRDb250YWluZXIoKS5mb2N1cygpO1xyXG5cdFx0fVxyXG5cdH1cclxufSk7XHJcblxyXG5MLmNvbnRyb2wgPSBmdW5jdGlvbiAob3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgTC5Db250cm9sKG9wdGlvbnMpO1xyXG59O1xyXG5cclxuLyogQHNlY3Rpb24gRXh0ZW5zaW9uIG1ldGhvZHNcclxuICogQHVuaW5oZXJpdGFibGVcclxuICpcclxuICogRXZlcnkgY29udHJvbCBzaG91bGQgZXh0ZW5kIGZyb20gYEwuQ29udHJvbGAgYW5kIChyZS0paW1wbGVtZW50IHRoZSBmb2xsb3dpbmcgbWV0aG9kcy5cclxuICpcclxuICogQG1ldGhvZCBvbkFkZChtYXA6IE1hcCk6IEhUTUxFbGVtZW50XHJcbiAqIFNob3VsZCByZXR1cm4gdGhlIGNvbnRhaW5lciBET00gZWxlbWVudCBmb3IgdGhlIGNvbnRyb2wgYW5kIGFkZCBsaXN0ZW5lcnMgb24gcmVsZXZhbnQgbWFwIGV2ZW50cy4gQ2FsbGVkIG9uIFtgY29udHJvbC5hZGRUbyhtYXApYF0oI2NvbnRyb2wtYWRkVG8pLlxyXG4gKlxyXG4gKiBAbWV0aG9kIG9uUmVtb3ZlKG1hcDogTWFwKVxyXG4gKiBPcHRpb25hbCBtZXRob2QuIFNob3VsZCBjb250YWluIGFsbCBjbGVhbiB1cCBjb2RlIHRoYXQgcmVtb3ZlcyB0aGUgbGlzdGVuZXJzIHByZXZpb3VzbHkgYWRkZWQgaW4gW2BvbkFkZGBdKCNjb250cm9sLW9uYWRkKS4gQ2FsbGVkIG9uIFtgY29udHJvbC5yZW1vdmUoKWBdKCNjb250cm9sLXJlbW92ZSkuXHJcbiAqL1xyXG5cclxuLyogQG5hbWVzcGFjZSBNYXBcclxuICogQHNlY3Rpb24gTWV0aG9kcyBmb3IgTGF5ZXJzIGFuZCBDb250cm9sc1xyXG4gKi9cclxuTC5NYXAuaW5jbHVkZSh7XHJcblx0Ly8gQG1ldGhvZCBhZGRDb250cm9sKGNvbnRyb2w6IENvbnRyb2wpOiB0aGlzXHJcblx0Ly8gQWRkcyB0aGUgZ2l2ZW4gY29udHJvbCB0byB0aGUgbWFwXHJcblx0YWRkQ29udHJvbDogZnVuY3Rpb24gKGNvbnRyb2wpIHtcclxuXHRcdGNvbnRyb2wuYWRkVG8odGhpcyk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlbW92ZUNvbnRyb2woY29udHJvbDogQ29udHJvbCk6IHRoaXNcclxuXHQvLyBSZW1vdmVzIHRoZSBnaXZlbiBjb250cm9sIGZyb20gdGhlIG1hcFxyXG5cdHJlbW92ZUNvbnRyb2w6IGZ1bmN0aW9uIChjb250cm9sKSB7XHJcblx0XHRjb250cm9sLnJlbW92ZSgpO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0X2luaXRDb250cm9sUG9zOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgY29ybmVycyA9IHRoaXMuX2NvbnRyb2xDb3JuZXJzID0ge30sXHJcblx0XHQgICAgbCA9ICdsZWFmbGV0LScsXHJcblx0XHQgICAgY29udGFpbmVyID0gdGhpcy5fY29udHJvbENvbnRhaW5lciA9XHJcblx0XHQgICAgICAgICAgICBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCBsICsgJ2NvbnRyb2wtY29udGFpbmVyJywgdGhpcy5fY29udGFpbmVyKTtcclxuXHJcblx0XHRmdW5jdGlvbiBjcmVhdGVDb3JuZXIodlNpZGUsIGhTaWRlKSB7XHJcblx0XHRcdHZhciBjbGFzc05hbWUgPSBsICsgdlNpZGUgKyAnICcgKyBsICsgaFNpZGU7XHJcblxyXG5cdFx0XHRjb3JuZXJzW3ZTaWRlICsgaFNpZGVdID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2JywgY2xhc3NOYW1lLCBjb250YWluZXIpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGNyZWF0ZUNvcm5lcigndG9wJywgJ2xlZnQnKTtcclxuXHRcdGNyZWF0ZUNvcm5lcigndG9wJywgJ3JpZ2h0Jyk7XHJcblx0XHRjcmVhdGVDb3JuZXIoJ2JvdHRvbScsICdsZWZ0Jyk7XHJcblx0XHRjcmVhdGVDb3JuZXIoJ2JvdHRvbScsICdyaWdodCcpO1xyXG5cdH0sXHJcblxyXG5cdF9jbGVhckNvbnRyb2xQb3M6IGZ1bmN0aW9uICgpIHtcclxuXHRcdEwuRG9tVXRpbC5yZW1vdmUodGhpcy5fY29udHJvbENvbnRhaW5lcik7XHJcblx0fVxyXG59KTtcclxuXG5cblxuLypcclxuICogQGNsYXNzIENvbnRyb2wuWm9vbVxyXG4gKiBAYWthIEwuQ29udHJvbC5ab29tXHJcbiAqIEBpbmhlcml0cyBDb250cm9sXHJcbiAqXHJcbiAqIEEgYmFzaWMgem9vbSBjb250cm9sIHdpdGggdHdvIGJ1dHRvbnMgKHpvb20gaW4gYW5kIHpvb20gb3V0KS4gSXQgaXMgcHV0IG9uIHRoZSBtYXAgYnkgZGVmYXVsdCB1bmxlc3MgeW91IHNldCBpdHMgW2B6b29tQ29udHJvbGAgb3B0aW9uXSgjbWFwLXpvb21jb250cm9sKSB0byBgZmFsc2VgLiBFeHRlbmRzIGBDb250cm9sYC5cclxuICovXHJcblxyXG5MLkNvbnRyb2wuWm9vbSA9IEwuQ29udHJvbC5leHRlbmQoe1xyXG5cdC8vIEBzZWN0aW9uXHJcblx0Ly8gQGFrYSBDb250cm9sLlpvb20gb3B0aW9uc1xyXG5cdG9wdGlvbnM6IHtcclxuXHRcdHBvc2l0aW9uOiAndG9wbGVmdCcsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiB6b29tSW5UZXh0OiBTdHJpbmcgPSAnKydcclxuXHRcdC8vIFRoZSB0ZXh0IHNldCBvbiB0aGUgJ3pvb20gaW4nIGJ1dHRvbi5cclxuXHRcdHpvb21JblRleHQ6ICcrJyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHpvb21JblRpdGxlOiBTdHJpbmcgPSAnWm9vbSBpbidcclxuXHRcdC8vIFRoZSB0aXRsZSBzZXQgb24gdGhlICd6b29tIGluJyBidXR0b24uXHJcblx0XHR6b29tSW5UaXRsZTogJ1pvb20gaW4nLFxyXG5cclxuXHRcdC8vIEBvcHRpb24gem9vbU91dFRleHQ6IFN0cmluZyA9ICctJ1xyXG5cdFx0Ly8gVGhlIHRleHQgc2V0IG9uIHRoZSAnem9vbSBvdXQnIGJ1dHRvbi5cclxuXHRcdHpvb21PdXRUZXh0OiAnLScsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiB6b29tT3V0VGl0bGU6IFN0cmluZyA9ICdab29tIG91dCdcclxuXHRcdC8vIFRoZSB0aXRsZSBzZXQgb24gdGhlICd6b29tIG91dCcgYnV0dG9uLlxyXG5cdFx0em9vbU91dFRpdGxlOiAnWm9vbSBvdXQnXHJcblx0fSxcclxuXHJcblx0b25BZGQ6IGZ1bmN0aW9uIChtYXApIHtcclxuXHRcdHZhciB6b29tTmFtZSA9ICdsZWFmbGV0LWNvbnRyb2wtem9vbScsXHJcblx0XHQgICAgY29udGFpbmVyID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2Jywgem9vbU5hbWUgKyAnIGxlYWZsZXQtYmFyJyksXHJcblx0XHQgICAgb3B0aW9ucyA9IHRoaXMub3B0aW9ucztcclxuXHJcblx0XHR0aGlzLl96b29tSW5CdXR0b24gID0gdGhpcy5fY3JlYXRlQnV0dG9uKG9wdGlvbnMuem9vbUluVGV4dCwgb3B0aW9ucy56b29tSW5UaXRsZSxcclxuXHRcdCAgICAgICAgem9vbU5hbWUgKyAnLWluJywgIGNvbnRhaW5lciwgdGhpcy5fem9vbUluKTtcclxuXHRcdHRoaXMuX3pvb21PdXRCdXR0b24gPSB0aGlzLl9jcmVhdGVCdXR0b24ob3B0aW9ucy56b29tT3V0VGV4dCwgb3B0aW9ucy56b29tT3V0VGl0bGUsXHJcblx0XHQgICAgICAgIHpvb21OYW1lICsgJy1vdXQnLCBjb250YWluZXIsIHRoaXMuX3pvb21PdXQpO1xyXG5cclxuXHRcdHRoaXMuX3VwZGF0ZURpc2FibGVkKCk7XHJcblx0XHRtYXAub24oJ3pvb21lbmQgem9vbWxldmVsc2NoYW5nZScsIHRoaXMuX3VwZGF0ZURpc2FibGVkLCB0aGlzKTtcclxuXHJcblx0XHRyZXR1cm4gY29udGFpbmVyO1xyXG5cdH0sXHJcblxyXG5cdG9uUmVtb3ZlOiBmdW5jdGlvbiAobWFwKSB7XHJcblx0XHRtYXAub2ZmKCd6b29tZW5kIHpvb21sZXZlbHNjaGFuZ2UnLCB0aGlzLl91cGRhdGVEaXNhYmxlZCwgdGhpcyk7XHJcblx0fSxcclxuXHJcblx0ZGlzYWJsZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0dGhpcy5fZGlzYWJsZWQgPSB0cnVlO1xyXG5cdFx0dGhpcy5fdXBkYXRlRGlzYWJsZWQoKTtcclxuXHRcdHJldHVybiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdGVuYWJsZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0dGhpcy5fZGlzYWJsZWQgPSBmYWxzZTtcclxuXHRcdHRoaXMuX3VwZGF0ZURpc2FibGVkKCk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfem9vbUluOiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0aWYgKCF0aGlzLl9kaXNhYmxlZCAmJiB0aGlzLl9tYXAuX3pvb20gPCB0aGlzLl9tYXAuZ2V0TWF4Wm9vbSgpKSB7XHJcblx0XHRcdHRoaXMuX21hcC56b29tSW4odGhpcy5fbWFwLm9wdGlvbnMuem9vbURlbHRhICogKGUuc2hpZnRLZXkgPyAzIDogMSkpO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdF96b29tT3V0OiBmdW5jdGlvbiAoZSkge1xyXG5cdFx0aWYgKCF0aGlzLl9kaXNhYmxlZCAmJiB0aGlzLl9tYXAuX3pvb20gPiB0aGlzLl9tYXAuZ2V0TWluWm9vbSgpKSB7XHJcblx0XHRcdHRoaXMuX21hcC56b29tT3V0KHRoaXMuX21hcC5vcHRpb25zLnpvb21EZWx0YSAqIChlLnNoaWZ0S2V5ID8gMyA6IDEpKTtcclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfY3JlYXRlQnV0dG9uOiBmdW5jdGlvbiAoaHRtbCwgdGl0bGUsIGNsYXNzTmFtZSwgY29udGFpbmVyLCBmbikge1xyXG5cdFx0dmFyIGxpbmsgPSBMLkRvbVV0aWwuY3JlYXRlKCdhJywgY2xhc3NOYW1lLCBjb250YWluZXIpO1xyXG5cdFx0bGluay5pbm5lckhUTUwgPSBodG1sO1xyXG5cdFx0bGluay5ocmVmID0gJyMnO1xyXG5cdFx0bGluay50aXRsZSA9IHRpdGxlO1xyXG5cclxuXHRcdC8qXHJcblx0XHQgKiBXaWxsIGZvcmNlIHNjcmVlbiByZWFkZXJzIGxpa2UgVm9pY2VPdmVyIHRvIHJlYWQgdGhpcyBhcyBcIlpvb20gaW4gLSBidXR0b25cIlxyXG5cdFx0ICovXHJcblx0XHRsaW5rLnNldEF0dHJpYnV0ZSgncm9sZScsICdidXR0b24nKTtcclxuXHRcdGxpbmsuc2V0QXR0cmlidXRlKCdhcmlhLWxhYmVsJywgdGl0bGUpO1xyXG5cclxuXHRcdEwuRG9tRXZlbnRcclxuXHRcdCAgICAub24obGluaywgJ21vdXNlZG93biBkYmxjbGljaycsIEwuRG9tRXZlbnQuc3RvcFByb3BhZ2F0aW9uKVxyXG5cdFx0ICAgIC5vbihsaW5rLCAnY2xpY2snLCBMLkRvbUV2ZW50LnN0b3ApXHJcblx0XHQgICAgLm9uKGxpbmssICdjbGljaycsIGZuLCB0aGlzKVxyXG5cdFx0ICAgIC5vbihsaW5rLCAnY2xpY2snLCB0aGlzLl9yZWZvY3VzT25NYXAsIHRoaXMpO1xyXG5cclxuXHRcdHJldHVybiBsaW5rO1xyXG5cdH0sXHJcblxyXG5cdF91cGRhdGVEaXNhYmxlZDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIG1hcCA9IHRoaXMuX21hcCxcclxuXHRcdCAgICBjbGFzc05hbWUgPSAnbGVhZmxldC1kaXNhYmxlZCc7XHJcblxyXG5cdFx0TC5Eb21VdGlsLnJlbW92ZUNsYXNzKHRoaXMuX3pvb21JbkJ1dHRvbiwgY2xhc3NOYW1lKTtcclxuXHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl96b29tT3V0QnV0dG9uLCBjbGFzc05hbWUpO1xyXG5cclxuXHRcdGlmICh0aGlzLl9kaXNhYmxlZCB8fCBtYXAuX3pvb20gPT09IG1hcC5nZXRNaW5ab29tKCkpIHtcclxuXHRcdFx0TC5Eb21VdGlsLmFkZENsYXNzKHRoaXMuX3pvb21PdXRCdXR0b24sIGNsYXNzTmFtZSk7XHJcblx0XHR9XHJcblx0XHRpZiAodGhpcy5fZGlzYWJsZWQgfHwgbWFwLl96b29tID09PSBtYXAuZ2V0TWF4Wm9vbSgpKSB7XHJcblx0XHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl96b29tSW5CdXR0b24sIGNsYXNzTmFtZSk7XHJcblx0XHR9XHJcblx0fVxyXG59KTtcclxuXHJcbi8vIEBuYW1lc3BhY2UgTWFwXHJcbi8vIEBzZWN0aW9uIENvbnRyb2wgb3B0aW9uc1xyXG4vLyBAb3B0aW9uIHpvb21Db250cm9sOiBCb29sZWFuID0gdHJ1ZVxyXG4vLyBXaGV0aGVyIGEgW3pvb20gY29udHJvbF0oI2NvbnRyb2wtem9vbSkgaXMgYWRkZWQgdG8gdGhlIG1hcCBieSBkZWZhdWx0LlxyXG5MLk1hcC5tZXJnZU9wdGlvbnMoe1xyXG5cdHpvb21Db250cm9sOiB0cnVlXHJcbn0pO1xyXG5cclxuTC5NYXAuYWRkSW5pdEhvb2soZnVuY3Rpb24gKCkge1xyXG5cdGlmICh0aGlzLm9wdGlvbnMuem9vbUNvbnRyb2wpIHtcclxuXHRcdHRoaXMuem9vbUNvbnRyb2wgPSBuZXcgTC5Db250cm9sLlpvb20oKTtcclxuXHRcdHRoaXMuYWRkQ29udHJvbCh0aGlzLnpvb21Db250cm9sKTtcclxuXHR9XHJcbn0pO1xyXG5cclxuLy8gQG5hbWVzcGFjZSBDb250cm9sLlpvb21cclxuLy8gQGZhY3RvcnkgTC5jb250cm9sLnpvb20ob3B0aW9uczogQ29udHJvbC5ab29tIG9wdGlvbnMpXHJcbi8vIENyZWF0ZXMgYSB6b29tIGNvbnRyb2xcclxuTC5jb250cm9sLnpvb20gPSBmdW5jdGlvbiAob3B0aW9ucykge1xyXG5cdHJldHVybiBuZXcgTC5Db250cm9sLlpvb20ob3B0aW9ucyk7XHJcbn07XHJcblxuXG5cbi8qXHJcbiAqIEBjbGFzcyBDb250cm9sLkF0dHJpYnV0aW9uXHJcbiAqIEBha2EgTC5Db250cm9sLkF0dHJpYnV0aW9uXHJcbiAqIEBpbmhlcml0cyBDb250cm9sXHJcbiAqXHJcbiAqIFRoZSBhdHRyaWJ1dGlvbiBjb250cm9sIGFsbG93cyB5b3UgdG8gZGlzcGxheSBhdHRyaWJ1dGlvbiBkYXRhIGluIGEgc21hbGwgdGV4dCBib3ggb24gYSBtYXAuIEl0IGlzIHB1dCBvbiB0aGUgbWFwIGJ5IGRlZmF1bHQgdW5sZXNzIHlvdSBzZXQgaXRzIFtgYXR0cmlidXRpb25Db250cm9sYCBvcHRpb25dKCNtYXAtYXR0cmlidXRpb25jb250cm9sKSB0byBgZmFsc2VgLCBhbmQgaXQgZmV0Y2hlcyBhdHRyaWJ1dGlvbiB0ZXh0cyBmcm9tIGxheWVycyB3aXRoIHRoZSBbYGdldEF0dHJpYnV0aW9uYCBtZXRob2RdKCNsYXllci1nZXRhdHRyaWJ1dGlvbikgYXV0b21hdGljYWxseS4gRXh0ZW5kcyBDb250cm9sLlxyXG4gKi9cclxuXHJcbkwuQ29udHJvbC5BdHRyaWJ1dGlvbiA9IEwuQ29udHJvbC5leHRlbmQoe1xyXG5cdC8vIEBzZWN0aW9uXHJcblx0Ly8gQGFrYSBDb250cm9sLkF0dHJpYnV0aW9uIG9wdGlvbnNcclxuXHRvcHRpb25zOiB7XHJcblx0XHRwb3NpdGlvbjogJ2JvdHRvbXJpZ2h0JyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHByZWZpeDogU3RyaW5nID0gJ0xlYWZsZXQnXHJcblx0XHQvLyBUaGUgSFRNTCB0ZXh0IHNob3duIGJlZm9yZSB0aGUgYXR0cmlidXRpb25zLiBQYXNzIGBmYWxzZWAgdG8gZGlzYWJsZS5cclxuXHRcdHByZWZpeDogJzxhIGhyZWY9XCJodHRwOi8vbGVhZmxldGpzLmNvbVwiIHRpdGxlPVwiQSBKUyBsaWJyYXJ5IGZvciBpbnRlcmFjdGl2ZSBtYXBzXCI+TGVhZmxldDwvYT4nXHJcblx0fSxcclxuXHJcblx0aW5pdGlhbGl6ZTogZnVuY3Rpb24gKG9wdGlvbnMpIHtcclxuXHRcdEwuc2V0T3B0aW9ucyh0aGlzLCBvcHRpb25zKTtcclxuXHJcblx0XHR0aGlzLl9hdHRyaWJ1dGlvbnMgPSB7fTtcclxuXHR9LFxyXG5cclxuXHRvbkFkZDogZnVuY3Rpb24gKG1hcCkge1xyXG5cdFx0bWFwLmF0dHJpYnV0aW9uQ29udHJvbCA9IHRoaXM7XHJcblx0XHR0aGlzLl9jb250YWluZXIgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCAnbGVhZmxldC1jb250cm9sLWF0dHJpYnV0aW9uJyk7XHJcblx0XHRpZiAoTC5Eb21FdmVudCkge1xyXG5cdFx0XHRMLkRvbUV2ZW50LmRpc2FibGVDbGlja1Byb3BhZ2F0aW9uKHRoaXMuX2NvbnRhaW5lcik7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gVE9ETyB1Z2x5LCByZWZhY3RvclxyXG5cdFx0Zm9yICh2YXIgaSBpbiBtYXAuX2xheWVycykge1xyXG5cdFx0XHRpZiAobWFwLl9sYXllcnNbaV0uZ2V0QXR0cmlidXRpb24pIHtcclxuXHRcdFx0XHR0aGlzLmFkZEF0dHJpYnV0aW9uKG1hcC5fbGF5ZXJzW2ldLmdldEF0dHJpYnV0aW9uKCkpO1xyXG5cdFx0XHR9XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fdXBkYXRlKCk7XHJcblxyXG5cdFx0cmV0dXJuIHRoaXMuX2NvbnRhaW5lcjtcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHNldFByZWZpeChwcmVmaXg6IFN0cmluZyk6IHRoaXNcclxuXHQvLyBTZXRzIHRoZSB0ZXh0IGJlZm9yZSB0aGUgYXR0cmlidXRpb25zLlxyXG5cdHNldFByZWZpeDogZnVuY3Rpb24gKHByZWZpeCkge1xyXG5cdFx0dGhpcy5vcHRpb25zLnByZWZpeCA9IHByZWZpeDtcclxuXHRcdHRoaXMuX3VwZGF0ZSgpO1xyXG5cdFx0cmV0dXJuIHRoaXM7XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBhZGRBdHRyaWJ1dGlvbih0ZXh0OiBTdHJpbmcpOiB0aGlzXHJcblx0Ly8gQWRkcyBhbiBhdHRyaWJ1dGlvbiB0ZXh0IChlLmcuIGAnVmVjdG9yIGRhdGEgJmNvcHk7IE1hcGJveCdgKS5cclxuXHRhZGRBdHRyaWJ1dGlvbjogZnVuY3Rpb24gKHRleHQpIHtcclxuXHRcdGlmICghdGV4dCkgeyByZXR1cm4gdGhpczsgfVxyXG5cclxuXHRcdGlmICghdGhpcy5fYXR0cmlidXRpb25zW3RleHRdKSB7XHJcblx0XHRcdHRoaXMuX2F0dHJpYnV0aW9uc1t0ZXh0XSA9IDA7XHJcblx0XHR9XHJcblx0XHR0aGlzLl9hdHRyaWJ1dGlvbnNbdGV4dF0rKztcclxuXHJcblx0XHR0aGlzLl91cGRhdGUoKTtcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIHJlbW92ZUF0dHJpYnV0aW9uKHRleHQ6IFN0cmluZyk6IHRoaXNcclxuXHQvLyBSZW1vdmVzIGFuIGF0dHJpYnV0aW9uIHRleHQuXHJcblx0cmVtb3ZlQXR0cmlidXRpb246IGZ1bmN0aW9uICh0ZXh0KSB7XHJcblx0XHRpZiAoIXRleHQpIHsgcmV0dXJuIHRoaXM7IH1cclxuXHJcblx0XHRpZiAodGhpcy5fYXR0cmlidXRpb25zW3RleHRdKSB7XHJcblx0XHRcdHRoaXMuX2F0dHJpYnV0aW9uc1t0ZXh0XS0tO1xyXG5cdFx0XHR0aGlzLl91cGRhdGUoKTtcclxuXHRcdH1cclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfdXBkYXRlOiBmdW5jdGlvbiAoKSB7XHJcblx0XHRpZiAoIXRoaXMuX21hcCkgeyByZXR1cm47IH1cclxuXHJcblx0XHR2YXIgYXR0cmlicyA9IFtdO1xyXG5cclxuXHRcdGZvciAodmFyIGkgaW4gdGhpcy5fYXR0cmlidXRpb25zKSB7XHJcblx0XHRcdGlmICh0aGlzLl9hdHRyaWJ1dGlvbnNbaV0pIHtcclxuXHRcdFx0XHRhdHRyaWJzLnB1c2goaSk7XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHJcblx0XHR2YXIgcHJlZml4QW5kQXR0cmlicyA9IFtdO1xyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMucHJlZml4KSB7XHJcblx0XHRcdHByZWZpeEFuZEF0dHJpYnMucHVzaCh0aGlzLm9wdGlvbnMucHJlZml4KTtcclxuXHRcdH1cclxuXHRcdGlmIChhdHRyaWJzLmxlbmd0aCkge1xyXG5cdFx0XHRwcmVmaXhBbmRBdHRyaWJzLnB1c2goYXR0cmlicy5qb2luKCcsICcpKTtcclxuXHRcdH1cclxuXHJcblx0XHR0aGlzLl9jb250YWluZXIuaW5uZXJIVE1MID0gcHJlZml4QW5kQXR0cmlicy5qb2luKCcgfCAnKTtcclxuXHR9XHJcbn0pO1xyXG5cclxuLy8gQG5hbWVzcGFjZSBNYXBcclxuLy8gQHNlY3Rpb24gQ29udHJvbCBvcHRpb25zXHJcbi8vIEBvcHRpb24gYXR0cmlidXRpb25Db250cm9sOiBCb29sZWFuID0gdHJ1ZVxyXG4vLyBXaGV0aGVyIGEgW2F0dHJpYnV0aW9uIGNvbnRyb2xdKCNjb250cm9sLWF0dHJpYnV0aW9uKSBpcyBhZGRlZCB0byB0aGUgbWFwIGJ5IGRlZmF1bHQuXHJcbkwuTWFwLm1lcmdlT3B0aW9ucyh7XHJcblx0YXR0cmlidXRpb25Db250cm9sOiB0cnVlXHJcbn0pO1xyXG5cclxuTC5NYXAuYWRkSW5pdEhvb2soZnVuY3Rpb24gKCkge1xyXG5cdGlmICh0aGlzLm9wdGlvbnMuYXR0cmlidXRpb25Db250cm9sKSB7XHJcblx0XHRuZXcgTC5Db250cm9sLkF0dHJpYnV0aW9uKCkuYWRkVG8odGhpcyk7XHJcblx0fVxyXG59KTtcclxuXHJcbi8vIEBuYW1lc3BhY2UgQ29udHJvbC5BdHRyaWJ1dGlvblxyXG4vLyBAZmFjdG9yeSBMLmNvbnRyb2wuYXR0cmlidXRpb24ob3B0aW9uczogQ29udHJvbC5BdHRyaWJ1dGlvbiBvcHRpb25zKVxyXG4vLyBDcmVhdGVzIGFuIGF0dHJpYnV0aW9uIGNvbnRyb2wuXHJcbkwuY29udHJvbC5hdHRyaWJ1dGlvbiA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XHJcblx0cmV0dXJuIG5ldyBMLkNvbnRyb2wuQXR0cmlidXRpb24ob3B0aW9ucyk7XHJcbn07XHJcblxuXG5cbi8qXG4gKiBAY2xhc3MgQ29udHJvbC5TY2FsZVxuICogQGFrYSBMLkNvbnRyb2wuU2NhbGVcbiAqIEBpbmhlcml0cyBDb250cm9sXG4gKlxuICogQSBzaW1wbGUgc2NhbGUgY29udHJvbCB0aGF0IHNob3dzIHRoZSBzY2FsZSBvZiB0aGUgY3VycmVudCBjZW50ZXIgb2Ygc2NyZWVuIGluIG1ldHJpYyAobS9rbSkgYW5kIGltcGVyaWFsIChtaS9mdCkgc3lzdGVtcy4gRXh0ZW5kcyBgQ29udHJvbGAuXG4gKlxuICogQGV4YW1wbGVcbiAqXG4gKiBgYGBqc1xuICogTC5jb250cm9sLnNjYWxlKCkuYWRkVG8obWFwKTtcbiAqIGBgYFxuICovXG5cbkwuQ29udHJvbC5TY2FsZSA9IEwuQ29udHJvbC5leHRlbmQoe1xuXHQvLyBAc2VjdGlvblxuXHQvLyBAYWthIENvbnRyb2wuU2NhbGUgb3B0aW9uc1xuXHRvcHRpb25zOiB7XG5cdFx0cG9zaXRpb246ICdib3R0b21sZWZ0JyxcblxuXHRcdC8vIEBvcHRpb24gbWF4V2lkdGg6IE51bWJlciA9IDEwMFxuXHRcdC8vIE1heGltdW0gd2lkdGggb2YgdGhlIGNvbnRyb2wgaW4gcGl4ZWxzLiBUaGUgd2lkdGggaXMgc2V0IGR5bmFtaWNhbGx5IHRvIHNob3cgcm91bmQgdmFsdWVzIChlLmcuIDEwMCwgMjAwLCA1MDApLlxuXHRcdG1heFdpZHRoOiAxMDAsXG5cblx0XHQvLyBAb3B0aW9uIG1ldHJpYzogQm9vbGVhbiA9IFRydWVcblx0XHQvLyBXaGV0aGVyIHRvIHNob3cgdGhlIG1ldHJpYyBzY2FsZSBsaW5lIChtL2ttKS5cblx0XHRtZXRyaWM6IHRydWUsXG5cblx0XHQvLyBAb3B0aW9uIGltcGVyaWFsOiBCb29sZWFuID0gVHJ1ZVxuXHRcdC8vIFdoZXRoZXIgdG8gc2hvdyB0aGUgaW1wZXJpYWwgc2NhbGUgbGluZSAobWkvZnQpLlxuXHRcdGltcGVyaWFsOiB0cnVlXG5cblx0XHQvLyBAb3B0aW9uIHVwZGF0ZVdoZW5JZGxlOiBCb29sZWFuID0gZmFsc2Vcblx0XHQvLyBJZiBgdHJ1ZWAsIHRoZSBjb250cm9sIGlzIHVwZGF0ZWQgb24gW2Btb3ZlZW5kYF0oI21hcC1tb3ZlZW5kKSwgb3RoZXJ3aXNlIGl0J3MgYWx3YXlzIHVwLXRvLWRhdGUgKHVwZGF0ZWQgb24gW2Btb3ZlYF0oI21hcC1tb3ZlKSkuXG5cdH0sXG5cblx0b25BZGQ6IGZ1bmN0aW9uIChtYXApIHtcblx0XHR2YXIgY2xhc3NOYW1lID0gJ2xlYWZsZXQtY29udHJvbC1zY2FsZScsXG5cdFx0ICAgIGNvbnRhaW5lciA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsIGNsYXNzTmFtZSksXG5cdFx0ICAgIG9wdGlvbnMgPSB0aGlzLm9wdGlvbnM7XG5cblx0XHR0aGlzLl9hZGRTY2FsZXMob3B0aW9ucywgY2xhc3NOYW1lICsgJy1saW5lJywgY29udGFpbmVyKTtcblxuXHRcdG1hcC5vbihvcHRpb25zLnVwZGF0ZVdoZW5JZGxlID8gJ21vdmVlbmQnIDogJ21vdmUnLCB0aGlzLl91cGRhdGUsIHRoaXMpO1xuXHRcdG1hcC53aGVuUmVhZHkodGhpcy5fdXBkYXRlLCB0aGlzKTtcblxuXHRcdHJldHVybiBjb250YWluZXI7XG5cdH0sXG5cblx0b25SZW1vdmU6IGZ1bmN0aW9uIChtYXApIHtcblx0XHRtYXAub2ZmKHRoaXMub3B0aW9ucy51cGRhdGVXaGVuSWRsZSA/ICdtb3ZlZW5kJyA6ICdtb3ZlJywgdGhpcy5fdXBkYXRlLCB0aGlzKTtcblx0fSxcblxuXHRfYWRkU2NhbGVzOiBmdW5jdGlvbiAob3B0aW9ucywgY2xhc3NOYW1lLCBjb250YWluZXIpIHtcblx0XHRpZiAob3B0aW9ucy5tZXRyaWMpIHtcblx0XHRcdHRoaXMuX21TY2FsZSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsIGNsYXNzTmFtZSwgY29udGFpbmVyKTtcblx0XHR9XG5cdFx0aWYgKG9wdGlvbnMuaW1wZXJpYWwpIHtcblx0XHRcdHRoaXMuX2lTY2FsZSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsIGNsYXNzTmFtZSwgY29udGFpbmVyKTtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZTogZnVuY3Rpb24gKCkge1xuXHRcdHZhciBtYXAgPSB0aGlzLl9tYXAsXG5cdFx0ICAgIHkgPSBtYXAuZ2V0U2l6ZSgpLnkgLyAyO1xuXG5cdFx0dmFyIG1heE1ldGVycyA9IG1hcC5kaXN0YW5jZShcblx0XHRcdFx0bWFwLmNvbnRhaW5lclBvaW50VG9MYXRMbmcoWzAsIHldKSxcblx0XHRcdFx0bWFwLmNvbnRhaW5lclBvaW50VG9MYXRMbmcoW3RoaXMub3B0aW9ucy5tYXhXaWR0aCwgeV0pKTtcblxuXHRcdHRoaXMuX3VwZGF0ZVNjYWxlcyhtYXhNZXRlcnMpO1xuXHR9LFxuXG5cdF91cGRhdGVTY2FsZXM6IGZ1bmN0aW9uIChtYXhNZXRlcnMpIHtcblx0XHRpZiAodGhpcy5vcHRpb25zLm1ldHJpYyAmJiBtYXhNZXRlcnMpIHtcblx0XHRcdHRoaXMuX3VwZGF0ZU1ldHJpYyhtYXhNZXRlcnMpO1xuXHRcdH1cblx0XHRpZiAodGhpcy5vcHRpb25zLmltcGVyaWFsICYmIG1heE1ldGVycykge1xuXHRcdFx0dGhpcy5fdXBkYXRlSW1wZXJpYWwobWF4TWV0ZXJzKTtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZU1ldHJpYzogZnVuY3Rpb24gKG1heE1ldGVycykge1xuXHRcdHZhciBtZXRlcnMgPSB0aGlzLl9nZXRSb3VuZE51bShtYXhNZXRlcnMpLFxuXHRcdCAgICBsYWJlbCA9IG1ldGVycyA8IDEwMDAgPyBtZXRlcnMgKyAnIG0nIDogKG1ldGVycyAvIDEwMDApICsgJyBrbSc7XG5cblx0XHR0aGlzLl91cGRhdGVTY2FsZSh0aGlzLl9tU2NhbGUsIGxhYmVsLCBtZXRlcnMgLyBtYXhNZXRlcnMpO1xuXHR9LFxuXG5cdF91cGRhdGVJbXBlcmlhbDogZnVuY3Rpb24gKG1heE1ldGVycykge1xuXHRcdHZhciBtYXhGZWV0ID0gbWF4TWV0ZXJzICogMy4yODA4Mzk5LFxuXHRcdCAgICBtYXhNaWxlcywgbWlsZXMsIGZlZXQ7XG5cblx0XHRpZiAobWF4RmVldCA+IDUyODApIHtcblx0XHRcdG1heE1pbGVzID0gbWF4RmVldCAvIDUyODA7XG5cdFx0XHRtaWxlcyA9IHRoaXMuX2dldFJvdW5kTnVtKG1heE1pbGVzKTtcblx0XHRcdHRoaXMuX3VwZGF0ZVNjYWxlKHRoaXMuX2lTY2FsZSwgbWlsZXMgKyAnIG1pJywgbWlsZXMgLyBtYXhNaWxlcyk7XG5cblx0XHR9IGVsc2Uge1xuXHRcdFx0ZmVldCA9IHRoaXMuX2dldFJvdW5kTnVtKG1heEZlZXQpO1xuXHRcdFx0dGhpcy5fdXBkYXRlU2NhbGUodGhpcy5faVNjYWxlLCBmZWV0ICsgJyBmdCcsIGZlZXQgLyBtYXhGZWV0KTtcblx0XHR9XG5cdH0sXG5cblx0X3VwZGF0ZVNjYWxlOiBmdW5jdGlvbiAoc2NhbGUsIHRleHQsIHJhdGlvKSB7XG5cdFx0c2NhbGUuc3R5bGUud2lkdGggPSBNYXRoLnJvdW5kKHRoaXMub3B0aW9ucy5tYXhXaWR0aCAqIHJhdGlvKSArICdweCc7XG5cdFx0c2NhbGUuaW5uZXJIVE1MID0gdGV4dDtcblx0fSxcblxuXHRfZ2V0Um91bmROdW06IGZ1bmN0aW9uIChudW0pIHtcblx0XHR2YXIgcG93MTAgPSBNYXRoLnBvdygxMCwgKE1hdGguZmxvb3IobnVtKSArICcnKS5sZW5ndGggLSAxKSxcblx0XHQgICAgZCA9IG51bSAvIHBvdzEwO1xuXG5cdFx0ZCA9IGQgPj0gMTAgPyAxMCA6XG5cdFx0ICAgIGQgPj0gNSA/IDUgOlxuXHRcdCAgICBkID49IDMgPyAzIDpcblx0XHQgICAgZCA+PSAyID8gMiA6IDE7XG5cblx0XHRyZXR1cm4gcG93MTAgKiBkO1xuXHR9XG59KTtcblxuXG4vLyBAZmFjdG9yeSBMLmNvbnRyb2wuc2NhbGUob3B0aW9ucz86IENvbnRyb2wuU2NhbGUgb3B0aW9ucylcbi8vIENyZWF0ZXMgYW4gc2NhbGUgY29udHJvbCB3aXRoIHRoZSBnaXZlbiBvcHRpb25zLlxuTC5jb250cm9sLnNjYWxlID0gZnVuY3Rpb24gKG9wdGlvbnMpIHtcblx0cmV0dXJuIG5ldyBMLkNvbnRyb2wuU2NhbGUob3B0aW9ucyk7XG59O1xuXG5cblxuLypcclxuICogQGNsYXNzIENvbnRyb2wuTGF5ZXJzXHJcbiAqIEBha2EgTC5Db250cm9sLkxheWVyc1xyXG4gKiBAaW5oZXJpdHMgQ29udHJvbFxyXG4gKlxyXG4gKiBUaGUgbGF5ZXJzIGNvbnRyb2wgZ2l2ZXMgdXNlcnMgdGhlIGFiaWxpdHkgdG8gc3dpdGNoIGJldHdlZW4gZGlmZmVyZW50IGJhc2UgbGF5ZXJzIGFuZCBzd2l0Y2ggb3ZlcmxheXMgb24vb2ZmIChjaGVjayBvdXQgdGhlIFtkZXRhaWxlZCBleGFtcGxlXShodHRwOi8vbGVhZmxldGpzLmNvbS9leGFtcGxlcy9sYXllcnMtY29udHJvbC5odG1sKSkuIEV4dGVuZHMgYENvbnRyb2xgLlxyXG4gKlxyXG4gKiBAZXhhbXBsZVxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiB2YXIgYmFzZUxheWVycyA9IHtcclxuICogXHRcIk1hcGJveFwiOiBtYXBib3gsXHJcbiAqIFx0XCJPcGVuU3RyZWV0TWFwXCI6IG9zbVxyXG4gKiB9O1xyXG4gKlxyXG4gKiB2YXIgb3ZlcmxheXMgPSB7XHJcbiAqIFx0XCJNYXJrZXJcIjogbWFya2VyLFxyXG4gKiBcdFwiUm9hZHNcIjogcm9hZHNMYXllclxyXG4gKiB9O1xyXG4gKlxyXG4gKiBMLmNvbnRyb2wubGF5ZXJzKGJhc2VMYXllcnMsIG92ZXJsYXlzKS5hZGRUbyhtYXApO1xyXG4gKiBgYGBcclxuICpcclxuICogVGhlIGBiYXNlTGF5ZXJzYCBhbmQgYG92ZXJsYXlzYCBwYXJhbWV0ZXJzIGFyZSBvYmplY3QgbGl0ZXJhbHMgd2l0aCBsYXllciBuYW1lcyBhcyBrZXlzIGFuZCBgTGF5ZXJgIG9iamVjdHMgYXMgdmFsdWVzOlxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiB7XHJcbiAqICAgICBcIjxzb21lTmFtZTE+XCI6IGxheWVyMSxcclxuICogICAgIFwiPHNvbWVOYW1lMj5cIjogbGF5ZXIyXHJcbiAqIH1cclxuICogYGBgXHJcbiAqXHJcbiAqIFRoZSBsYXllciBuYW1lcyBjYW4gY29udGFpbiBIVE1MLCB3aGljaCBhbGxvd3MgeW91IHRvIGFkZCBhZGRpdGlvbmFsIHN0eWxpbmcgdG8gdGhlIGl0ZW1zOlxyXG4gKlxyXG4gKiBgYGBqc1xyXG4gKiB7XCI8aW1nIHNyYz0nbXktbGF5ZXItaWNvbicgLz4gPHNwYW4gY2xhc3M9J215LWxheWVyLWl0ZW0nPk15IExheWVyPC9zcGFuPlwiOiBteUxheWVyfVxyXG4gKiBgYGBcclxuICovXHJcblxyXG5cclxuTC5Db250cm9sLkxheWVycyA9IEwuQ29udHJvbC5leHRlbmQoe1xyXG5cdC8vIEBzZWN0aW9uXHJcblx0Ly8gQGFrYSBDb250cm9sLkxheWVycyBvcHRpb25zXHJcblx0b3B0aW9uczoge1xyXG5cdFx0Ly8gQG9wdGlvbiBjb2xsYXBzZWQ6IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBJZiBgdHJ1ZWAsIHRoZSBjb250cm9sIHdpbGwgYmUgY29sbGFwc2VkIGludG8gYW4gaWNvbiBhbmQgZXhwYW5kZWQgb24gbW91c2UgaG92ZXIgb3IgdG91Y2guXHJcblx0XHRjb2xsYXBzZWQ6IHRydWUsXHJcblx0XHRwb3NpdGlvbjogJ3RvcHJpZ2h0JyxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGF1dG9aSW5kZXg6IEJvb2xlYW4gPSB0cnVlXHJcblx0XHQvLyBJZiBgdHJ1ZWAsIHRoZSBjb250cm9sIHdpbGwgYXNzaWduIHpJbmRleGVzIGluIGluY3JlYXNpbmcgb3JkZXIgdG8gYWxsIG9mIGl0cyBsYXllcnMgc28gdGhhdCB0aGUgb3JkZXIgaXMgcHJlc2VydmVkIHdoZW4gc3dpdGNoaW5nIHRoZW0gb24vb2ZmLlxyXG5cdFx0YXV0b1pJbmRleDogdHJ1ZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIGhpZGVTaW5nbGVCYXNlOiBCb29sZWFuID0gZmFsc2VcclxuXHRcdC8vIElmIGB0cnVlYCwgdGhlIGJhc2UgbGF5ZXJzIGluIHRoZSBjb250cm9sIHdpbGwgYmUgaGlkZGVuIHdoZW4gdGhlcmUgaXMgb25seSBvbmUuXHJcblx0XHRoaWRlU2luZ2xlQmFzZTogZmFsc2UsXHJcblxyXG5cdFx0Ly8gQG9wdGlvbiBzb3J0TGF5ZXJzOiBCb29sZWFuID0gZmFsc2VcclxuXHRcdC8vIFdoZXRoZXIgdG8gc29ydCB0aGUgbGF5ZXJzLiBXaGVuIGBmYWxzZWAsIGxheWVycyB3aWxsIGtlZXAgdGhlIG9yZGVyXHJcblx0XHQvLyBpbiB3aGljaCB0aGV5IHdlcmUgYWRkZWQgdG8gdGhlIGNvbnRyb2wuXHJcblx0XHRzb3J0TGF5ZXJzOiBmYWxzZSxcclxuXHJcblx0XHQvLyBAb3B0aW9uIHNvcnRGdW5jdGlvbjogRnVuY3Rpb24gPSAqXHJcblx0XHQvLyBBIFtjb21wYXJlIGZ1bmN0aW9uXShodHRwczovL2RldmVsb3Blci5tb3ppbGxhLm9yZy9kb2NzL1dlYi9KYXZhU2NyaXB0L1JlZmVyZW5jZS9HbG9iYWxfT2JqZWN0cy9BcnJheS9zb3J0KVxyXG5cdFx0Ly8gdGhhdCB3aWxsIGJlIHVzZWQgZm9yIHNvcnRpbmcgdGhlIGxheWVycywgd2hlbiBgc29ydExheWVyc2AgaXMgYHRydWVgLlxyXG5cdFx0Ly8gVGhlIGZ1bmN0aW9uIHJlY2VpdmVzIGJvdGggdGhlIGBMLkxheWVyYCBpbnN0YW5jZXMgYW5kIHRoZWlyIG5hbWVzLCBhcyBpblxyXG5cdFx0Ly8gYHNvcnRGdW5jdGlvbihsYXllckEsIGxheWVyQiwgbmFtZUEsIG5hbWVCKWAuXHJcblx0XHQvLyBCeSBkZWZhdWx0LCBpdCBzb3J0cyBsYXllcnMgYWxwaGFiZXRpY2FsbHkgYnkgdGhlaXIgbmFtZS5cclxuXHRcdHNvcnRGdW5jdGlvbjogZnVuY3Rpb24gKGxheWVyQSwgbGF5ZXJCLCBuYW1lQSwgbmFtZUIpIHtcclxuXHRcdFx0cmV0dXJuIG5hbWVBIDwgbmFtZUIgPyAtMSA6IChuYW1lQiA8IG5hbWVBID8gMSA6IDApO1xyXG5cdFx0fVxyXG5cdH0sXHJcblxyXG5cdGluaXRpYWxpemU6IGZ1bmN0aW9uIChiYXNlTGF5ZXJzLCBvdmVybGF5cywgb3B0aW9ucykge1xyXG5cdFx0TC5zZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xyXG5cclxuXHRcdHRoaXMuX2xheWVycyA9IFtdO1xyXG5cdFx0dGhpcy5fbGFzdFpJbmRleCA9IDA7XHJcblx0XHR0aGlzLl9oYW5kbGluZ0NsaWNrID0gZmFsc2U7XHJcblxyXG5cdFx0Zm9yICh2YXIgaSBpbiBiYXNlTGF5ZXJzKSB7XHJcblx0XHRcdHRoaXMuX2FkZExheWVyKGJhc2VMYXllcnNbaV0sIGkpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGZvciAoaSBpbiBvdmVybGF5cykge1xyXG5cdFx0XHR0aGlzLl9hZGRMYXllcihvdmVybGF5c1tpXSwgaSwgdHJ1ZSk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0b25BZGQ6IGZ1bmN0aW9uIChtYXApIHtcclxuXHRcdHRoaXMuX2luaXRMYXlvdXQoKTtcclxuXHRcdHRoaXMuX3VwZGF0ZSgpO1xyXG5cclxuXHRcdHRoaXMuX21hcCA9IG1hcDtcclxuXHRcdG1hcC5vbignem9vbWVuZCcsIHRoaXMuX2NoZWNrRGlzYWJsZWRMYXllcnMsIHRoaXMpO1xyXG5cclxuXHRcdHJldHVybiB0aGlzLl9jb250YWluZXI7XHJcblx0fSxcclxuXHJcblx0b25SZW1vdmU6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHRoaXMuX21hcC5vZmYoJ3pvb21lbmQnLCB0aGlzLl9jaGVja0Rpc2FibGVkTGF5ZXJzLCB0aGlzKTtcclxuXHJcblx0XHRmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMuX2xheWVycy5sZW5ndGg7IGkrKykge1xyXG5cdFx0XHR0aGlzLl9sYXllcnNbaV0ubGF5ZXIub2ZmKCdhZGQgcmVtb3ZlJywgdGhpcy5fb25MYXllckNoYW5nZSwgdGhpcyk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gQG1ldGhvZCBhZGRCYXNlTGF5ZXIobGF5ZXI6IExheWVyLCBuYW1lOiBTdHJpbmcpOiB0aGlzXHJcblx0Ly8gQWRkcyBhIGJhc2UgbGF5ZXIgKHJhZGlvIGJ1dHRvbiBlbnRyeSkgd2l0aCB0aGUgZ2l2ZW4gbmFtZSB0byB0aGUgY29udHJvbC5cclxuXHRhZGRCYXNlTGF5ZXI6IGZ1bmN0aW9uIChsYXllciwgbmFtZSkge1xyXG5cdFx0dGhpcy5fYWRkTGF5ZXIobGF5ZXIsIG5hbWUpO1xyXG5cdFx0cmV0dXJuICh0aGlzLl9tYXApID8gdGhpcy5fdXBkYXRlKCkgOiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgYWRkT3ZlcmxheShsYXllcjogTGF5ZXIsIG5hbWU6IFN0cmluZyk6IHRoaXNcclxuXHQvLyBBZGRzIGFuIG92ZXJsYXkgKGNoZWNrYm94IGVudHJ5KSB3aXRoIHRoZSBnaXZlbiBuYW1lIHRvIHRoZSBjb250cm9sLlxyXG5cdGFkZE92ZXJsYXk6IGZ1bmN0aW9uIChsYXllciwgbmFtZSkge1xyXG5cdFx0dGhpcy5fYWRkTGF5ZXIobGF5ZXIsIG5hbWUsIHRydWUpO1xyXG5cdFx0cmV0dXJuICh0aGlzLl9tYXApID8gdGhpcy5fdXBkYXRlKCkgOiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgcmVtb3ZlTGF5ZXIobGF5ZXI6IExheWVyKTogdGhpc1xyXG5cdC8vIFJlbW92ZSB0aGUgZ2l2ZW4gbGF5ZXIgZnJvbSB0aGUgY29udHJvbC5cclxuXHRyZW1vdmVMYXllcjogZnVuY3Rpb24gKGxheWVyKSB7XHJcblx0XHRsYXllci5vZmYoJ2FkZCByZW1vdmUnLCB0aGlzLl9vbkxheWVyQ2hhbmdlLCB0aGlzKTtcclxuXHJcblx0XHR2YXIgb2JqID0gdGhpcy5fZ2V0TGF5ZXIoTC5zdGFtcChsYXllcikpO1xyXG5cdFx0aWYgKG9iaikge1xyXG5cdFx0XHR0aGlzLl9sYXllcnMuc3BsaWNlKHRoaXMuX2xheWVycy5pbmRleE9mKG9iaiksIDEpO1xyXG5cdFx0fVxyXG5cdFx0cmV0dXJuICh0aGlzLl9tYXApID8gdGhpcy5fdXBkYXRlKCkgOiB0aGlzO1xyXG5cdH0sXHJcblxyXG5cdC8vIEBtZXRob2QgZXhwYW5kKCk6IHRoaXNcclxuXHQvLyBFeHBhbmQgdGhlIGNvbnRyb2wgY29udGFpbmVyIGlmIGNvbGxhcHNlZC5cclxuXHRleHBhbmQ6IGZ1bmN0aW9uICgpIHtcclxuXHRcdEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9jb250YWluZXIsICdsZWFmbGV0LWNvbnRyb2wtbGF5ZXJzLWV4cGFuZGVkJyk7XHJcblx0XHR0aGlzLl9mb3JtLnN0eWxlLmhlaWdodCA9IG51bGw7XHJcblx0XHR2YXIgYWNjZXB0YWJsZUhlaWdodCA9IHRoaXMuX21hcC5nZXRTaXplKCkueSAtICh0aGlzLl9jb250YWluZXIub2Zmc2V0VG9wICsgNTApO1xyXG5cdFx0aWYgKGFjY2VwdGFibGVIZWlnaHQgPCB0aGlzLl9mb3JtLmNsaWVudEhlaWdodCkge1xyXG5cdFx0XHRMLkRvbVV0aWwuYWRkQ2xhc3ModGhpcy5fZm9ybSwgJ2xlYWZsZXQtY29udHJvbC1sYXllcnMtc2Nyb2xsYmFyJyk7XHJcblx0XHRcdHRoaXMuX2Zvcm0uc3R5bGUuaGVpZ2h0ID0gYWNjZXB0YWJsZUhlaWdodCArICdweCc7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRMLkRvbVV0aWwucmVtb3ZlQ2xhc3ModGhpcy5fZm9ybSwgJ2xlYWZsZXQtY29udHJvbC1sYXllcnMtc2Nyb2xsYmFyJyk7XHJcblx0XHR9XHJcblx0XHR0aGlzLl9jaGVja0Rpc2FibGVkTGF5ZXJzKCk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHQvLyBAbWV0aG9kIGNvbGxhcHNlKCk6IHRoaXNcclxuXHQvLyBDb2xsYXBzZSB0aGUgY29udHJvbCBjb250YWluZXIgaWYgZXhwYW5kZWQuXHJcblx0Y29sbGFwc2U6IGZ1bmN0aW9uICgpIHtcclxuXHRcdEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl9jb250YWluZXIsICdsZWFmbGV0LWNvbnRyb2wtbGF5ZXJzLWV4cGFuZGVkJyk7XHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfaW5pdExheW91dDogZnVuY3Rpb24gKCkge1xyXG5cdFx0dmFyIGNsYXNzTmFtZSA9ICdsZWFmbGV0LWNvbnRyb2wtbGF5ZXJzJyxcclxuXHRcdCAgICBjb250YWluZXIgPSB0aGlzLl9jb250YWluZXIgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCBjbGFzc05hbWUpO1xyXG5cclxuXHRcdC8vIG1ha2VzIHRoaXMgd29yayBvbiBJRSB0b3VjaCBkZXZpY2VzIGJ5IHN0b3BwaW5nIGl0IGZyb20gZmlyaW5nIGEgbW91c2VvdXQgZXZlbnQgd2hlbiB0aGUgdG91Y2ggaXMgcmVsZWFzZWRcclxuXHRcdGNvbnRhaW5lci5zZXRBdHRyaWJ1dGUoJ2FyaWEtaGFzcG9wdXAnLCB0cnVlKTtcclxuXHJcblx0XHRMLkRvbUV2ZW50LmRpc2FibGVDbGlja1Byb3BhZ2F0aW9uKGNvbnRhaW5lcik7XHJcblx0XHRpZiAoIUwuQnJvd3Nlci50b3VjaCkge1xyXG5cdFx0XHRMLkRvbUV2ZW50LmRpc2FibGVTY3JvbGxQcm9wYWdhdGlvbihjb250YWluZXIpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHZhciBmb3JtID0gdGhpcy5fZm9ybSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2Zvcm0nLCBjbGFzc05hbWUgKyAnLWxpc3QnKTtcclxuXHJcblx0XHRpZiAoIUwuQnJvd3Nlci5hbmRyb2lkKSB7XHJcblx0XHRcdEwuRG9tRXZlbnQub24oY29udGFpbmVyLCB7XHJcblx0XHRcdFx0bW91c2VlbnRlcjogdGhpcy5leHBhbmQsXHJcblx0XHRcdFx0bW91c2VsZWF2ZTogdGhpcy5jb2xsYXBzZVxyXG5cdFx0XHR9LCB0aGlzKTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgbGluayA9IHRoaXMuX2xheWVyc0xpbmsgPSBMLkRvbVV0aWwuY3JlYXRlKCdhJywgY2xhc3NOYW1lICsgJy10b2dnbGUnLCBjb250YWluZXIpO1xyXG5cdFx0bGluay5ocmVmID0gJyMnO1xyXG5cdFx0bGluay50aXRsZSA9ICdMYXllcnMnO1xyXG5cclxuXHRcdGlmIChMLkJyb3dzZXIudG91Y2gpIHtcclxuXHRcdFx0TC5Eb21FdmVudFxyXG5cdFx0XHQgICAgLm9uKGxpbmssICdjbGljaycsIEwuRG9tRXZlbnQuc3RvcClcclxuXHRcdFx0ICAgIC5vbihsaW5rLCAnY2xpY2snLCB0aGlzLmV4cGFuZCwgdGhpcyk7XHJcblx0XHR9IGVsc2Uge1xyXG5cdFx0XHRMLkRvbUV2ZW50Lm9uKGxpbmssICdmb2N1cycsIHRoaXMuZXhwYW5kLCB0aGlzKTtcclxuXHRcdH1cclxuXHJcblx0XHQvLyB3b3JrIGFyb3VuZCBmb3IgRmlyZWZveCBBbmRyb2lkIGlzc3VlIGh0dHBzOi8vZ2l0aHViLmNvbS9MZWFmbGV0L0xlYWZsZXQvaXNzdWVzLzIwMzNcclxuXHRcdEwuRG9tRXZlbnQub24oZm9ybSwgJ2NsaWNrJywgZnVuY3Rpb24gKCkge1xyXG5cdFx0XHRzZXRUaW1lb3V0KEwuYmluZCh0aGlzLl9vbklucHV0Q2xpY2ssIHRoaXMpLCAwKTtcclxuXHRcdH0sIHRoaXMpO1xyXG5cclxuXHRcdHRoaXMuX21hcC5vbignY2xpY2snLCB0aGlzLmNvbGxhcHNlLCB0aGlzKTtcclxuXHRcdC8vIFRPRE8ga2V5Ym9hcmQgYWNjZXNzaWJpbGl0eVxyXG5cclxuXHRcdGlmICghdGhpcy5vcHRpb25zLmNvbGxhcHNlZCkge1xyXG5cdFx0XHR0aGlzLmV4cGFuZCgpO1xyXG5cdFx0fVxyXG5cclxuXHRcdHRoaXMuX2Jhc2VMYXllcnNMaXN0ID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2JywgY2xhc3NOYW1lICsgJy1iYXNlJywgZm9ybSk7XHJcblx0XHR0aGlzLl9zZXBhcmF0b3IgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCBjbGFzc05hbWUgKyAnLXNlcGFyYXRvcicsIGZvcm0pO1xyXG5cdFx0dGhpcy5fb3ZlcmxheXNMaXN0ID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2JywgY2xhc3NOYW1lICsgJy1vdmVybGF5cycsIGZvcm0pO1xyXG5cclxuXHRcdGNvbnRhaW5lci5hcHBlbmRDaGlsZChmb3JtKTtcclxuXHR9LFxyXG5cclxuXHRfZ2V0TGF5ZXI6IGZ1bmN0aW9uIChpZCkge1xyXG5cdFx0Zm9yICh2YXIgaSA9IDA7IGkgPCB0aGlzLl9sYXllcnMubGVuZ3RoOyBpKyspIHtcclxuXHJcblx0XHRcdGlmICh0aGlzLl9sYXllcnNbaV0gJiYgTC5zdGFtcCh0aGlzLl9sYXllcnNbaV0ubGF5ZXIpID09PSBpZCkge1xyXG5cdFx0XHRcdHJldHVybiB0aGlzLl9sYXllcnNbaV07XHJcblx0XHRcdH1cclxuXHRcdH1cclxuXHR9LFxyXG5cclxuXHRfYWRkTGF5ZXI6IGZ1bmN0aW9uIChsYXllciwgbmFtZSwgb3ZlcmxheSkge1xyXG5cdFx0bGF5ZXIub24oJ2FkZCByZW1vdmUnLCB0aGlzLl9vbkxheWVyQ2hhbmdlLCB0aGlzKTtcclxuXHJcblx0XHR0aGlzLl9sYXllcnMucHVzaCh7XHJcblx0XHRcdGxheWVyOiBsYXllcixcclxuXHRcdFx0bmFtZTogbmFtZSxcclxuXHRcdFx0b3ZlcmxheTogb3ZlcmxheVxyXG5cdFx0fSk7XHJcblxyXG5cdFx0aWYgKHRoaXMub3B0aW9ucy5zb3J0TGF5ZXJzKSB7XHJcblx0XHRcdHRoaXMuX2xheWVycy5zb3J0KEwuYmluZChmdW5jdGlvbiAoYSwgYikge1xyXG5cdFx0XHRcdHJldHVybiB0aGlzLm9wdGlvbnMuc29ydEZ1bmN0aW9uKGEubGF5ZXIsIGIubGF5ZXIsIGEubmFtZSwgYi5uYW1lKTtcclxuXHRcdFx0fSwgdGhpcykpO1xyXG5cdFx0fVxyXG5cclxuXHRcdGlmICh0aGlzLm9wdGlvbnMuYXV0b1pJbmRleCAmJiBsYXllci5zZXRaSW5kZXgpIHtcclxuXHRcdFx0dGhpcy5fbGFzdFpJbmRleCsrO1xyXG5cdFx0XHRsYXllci5zZXRaSW5kZXgodGhpcy5fbGFzdFpJbmRleCk7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X3VwZGF0ZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0aWYgKCF0aGlzLl9jb250YWluZXIpIHsgcmV0dXJuIHRoaXM7IH1cclxuXHJcblx0XHRMLkRvbVV0aWwuZW1wdHkodGhpcy5fYmFzZUxheWVyc0xpc3QpO1xyXG5cdFx0TC5Eb21VdGlsLmVtcHR5KHRoaXMuX292ZXJsYXlzTGlzdCk7XHJcblxyXG5cdFx0dmFyIGJhc2VMYXllcnNQcmVzZW50LCBvdmVybGF5c1ByZXNlbnQsIGksIG9iaiwgYmFzZUxheWVyc0NvdW50ID0gMDtcclxuXHJcblx0XHRmb3IgKGkgPSAwOyBpIDwgdGhpcy5fbGF5ZXJzLmxlbmd0aDsgaSsrKSB7XHJcblx0XHRcdG9iaiA9IHRoaXMuX2xheWVyc1tpXTtcclxuXHRcdFx0dGhpcy5fYWRkSXRlbShvYmopO1xyXG5cdFx0XHRvdmVybGF5c1ByZXNlbnQgPSBvdmVybGF5c1ByZXNlbnQgfHwgb2JqLm92ZXJsYXk7XHJcblx0XHRcdGJhc2VMYXllcnNQcmVzZW50ID0gYmFzZUxheWVyc1ByZXNlbnQgfHwgIW9iai5vdmVybGF5O1xyXG5cdFx0XHRiYXNlTGF5ZXJzQ291bnQgKz0gIW9iai5vdmVybGF5ID8gMSA6IDA7XHJcblx0XHR9XHJcblxyXG5cdFx0Ly8gSGlkZSBiYXNlIGxheWVycyBzZWN0aW9uIGlmIHRoZXJlJ3Mgb25seSBvbmUgbGF5ZXIuXHJcblx0XHRpZiAodGhpcy5vcHRpb25zLmhpZGVTaW5nbGVCYXNlKSB7XHJcblx0XHRcdGJhc2VMYXllcnNQcmVzZW50ID0gYmFzZUxheWVyc1ByZXNlbnQgJiYgYmFzZUxheWVyc0NvdW50ID4gMTtcclxuXHRcdFx0dGhpcy5fYmFzZUxheWVyc0xpc3Quc3R5bGUuZGlzcGxheSA9IGJhc2VMYXllcnNQcmVzZW50ID8gJycgOiAnbm9uZSc7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5fc2VwYXJhdG9yLnN0eWxlLmRpc3BsYXkgPSBvdmVybGF5c1ByZXNlbnQgJiYgYmFzZUxheWVyc1ByZXNlbnQgPyAnJyA6ICdub25lJztcclxuXHJcblx0XHRyZXR1cm4gdGhpcztcclxuXHR9LFxyXG5cclxuXHRfb25MYXllckNoYW5nZTogZnVuY3Rpb24gKGUpIHtcclxuXHRcdGlmICghdGhpcy5faGFuZGxpbmdDbGljaykge1xyXG5cdFx0XHR0aGlzLl91cGRhdGUoKTtcclxuXHRcdH1cclxuXHJcblx0XHR2YXIgb2JqID0gdGhpcy5fZ2V0TGF5ZXIoTC5zdGFtcChlLnRhcmdldCkpO1xyXG5cclxuXHRcdC8vIEBuYW1lc3BhY2UgTWFwXHJcblx0XHQvLyBAc2VjdGlvbiBMYXllciBldmVudHNcclxuXHRcdC8vIEBldmVudCBiYXNlbGF5ZXJjaGFuZ2U6IExheWVyc0NvbnRyb2xFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiB0aGUgYmFzZSBsYXllciBpcyBjaGFuZ2VkIHRocm91Z2ggdGhlIFtsYXllciBjb250cm9sXSgjY29udHJvbC1sYXllcnMpLlxyXG5cdFx0Ly8gQGV2ZW50IG92ZXJsYXlhZGQ6IExheWVyc0NvbnRyb2xFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiBhbiBvdmVybGF5IGlzIHNlbGVjdGVkIHRocm91Z2ggdGhlIFtsYXllciBjb250cm9sXSgjY29udHJvbC1sYXllcnMpLlxyXG5cdFx0Ly8gQGV2ZW50IG92ZXJsYXlyZW1vdmU6IExheWVyc0NvbnRyb2xFdmVudFxyXG5cdFx0Ly8gRmlyZWQgd2hlbiBhbiBvdmVybGF5IGlzIGRlc2VsZWN0ZWQgdGhyb3VnaCB0aGUgW2xheWVyIGNvbnRyb2xdKCNjb250cm9sLWxheWVycykuXHJcblx0XHQvLyBAbmFtZXNwYWNlIENvbnRyb2wuTGF5ZXJzXHJcblx0XHR2YXIgdHlwZSA9IG9iai5vdmVybGF5ID9cclxuXHRcdFx0KGUudHlwZSA9PT0gJ2FkZCcgPyAnb3ZlcmxheWFkZCcgOiAnb3ZlcmxheXJlbW92ZScpIDpcclxuXHRcdFx0KGUudHlwZSA9PT0gJ2FkZCcgPyAnYmFzZWxheWVyY2hhbmdlJyA6IG51bGwpO1xyXG5cclxuXHRcdGlmICh0eXBlKSB7XHJcblx0XHRcdHRoaXMuX21hcC5maXJlKHR5cGUsIG9iaik7XHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0Ly8gSUU3IGJ1Z3Mgb3V0IGlmIHlvdSBjcmVhdGUgYSByYWRpbyBkeW5hbWljYWxseSwgc28geW91IGhhdmUgdG8gZG8gaXQgdGhpcyBoYWNreSB3YXkgKHNlZSBodHRwOi8vYml0Lmx5L1BxWUxCZSlcclxuXHRfY3JlYXRlUmFkaW9FbGVtZW50OiBmdW5jdGlvbiAobmFtZSwgY2hlY2tlZCkge1xyXG5cclxuXHRcdHZhciByYWRpb0h0bWwgPSAnPGlucHV0IHR5cGU9XCJyYWRpb1wiIGNsYXNzPVwibGVhZmxldC1jb250cm9sLWxheWVycy1zZWxlY3RvclwiIG5hbWU9XCInICtcclxuXHRcdFx0XHRuYW1lICsgJ1wiJyArIChjaGVja2VkID8gJyBjaGVja2VkPVwiY2hlY2tlZFwiJyA6ICcnKSArICcvPic7XHJcblxyXG5cdFx0dmFyIHJhZGlvRnJhZ21lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuXHRcdHJhZGlvRnJhZ21lbnQuaW5uZXJIVE1MID0gcmFkaW9IdG1sO1xyXG5cclxuXHRcdHJldHVybiByYWRpb0ZyYWdtZW50LmZpcnN0Q2hpbGQ7XHJcblx0fSxcclxuXHJcblx0X2FkZEl0ZW06IGZ1bmN0aW9uIChvYmopIHtcclxuXHRcdHZhciBsYWJlbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xhYmVsJyksXHJcblx0XHQgICAgY2hlY2tlZCA9IHRoaXMuX21hcC5oYXNMYXllcihvYmoubGF5ZXIpLFxyXG5cdFx0ICAgIGlucHV0O1xyXG5cclxuXHRcdGlmIChvYmoub3ZlcmxheSkge1xyXG5cdFx0XHRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2lucHV0Jyk7XHJcblx0XHRcdGlucHV0LnR5cGUgPSAnY2hlY2tib3gnO1xyXG5cdFx0XHRpbnB1dC5jbGFzc05hbWUgPSAnbGVhZmxldC1jb250cm9sLWxheWVycy1zZWxlY3Rvcic7XHJcblx0XHRcdGlucHV0LmRlZmF1bHRDaGVja2VkID0gY2hlY2tlZDtcclxuXHRcdH0gZWxzZSB7XHJcblx0XHRcdGlucHV0ID0gdGhpcy5fY3JlYXRlUmFkaW9FbGVtZW50KCdsZWFmbGV0LWJhc2UtbGF5ZXJzJywgY2hlY2tlZCk7XHJcblx0XHR9XHJcblxyXG5cdFx0aW5wdXQubGF5ZXJJZCA9IEwuc3RhbXAob2JqLmxheWVyKTtcclxuXHJcblx0XHRMLkRvbUV2ZW50Lm9uKGlucHV0LCAnY2xpY2snLCB0aGlzLl9vbklucHV0Q2xpY2ssIHRoaXMpO1xyXG5cclxuXHRcdHZhciBuYW1lID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xyXG5cdFx0bmFtZS5pbm5lckhUTUwgPSAnICcgKyBvYmoubmFtZTtcclxuXHJcblx0XHQvLyBIZWxwcyBmcm9tIHByZXZlbnRpbmcgbGF5ZXIgY29udHJvbCBmbGlja2VyIHdoZW4gY2hlY2tib3hlcyBhcmUgZGlzYWJsZWRcclxuXHRcdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9MZWFmbGV0L0xlYWZsZXQvaXNzdWVzLzI3NzFcclxuXHRcdHZhciBob2xkZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcclxuXHJcblx0XHRsYWJlbC5hcHBlbmRDaGlsZChob2xkZXIpO1xyXG5cdFx0aG9sZGVyLmFwcGVuZENoaWxkKGlucHV0KTtcclxuXHRcdGhvbGRlci5hcHBlbmRDaGlsZChuYW1lKTtcclxuXHJcblx0XHR2YXIgY29udGFpbmVyID0gb2JqLm92ZXJsYXkgPyB0aGlzLl9vdmVybGF5c0xpc3QgOiB0aGlzLl9iYXNlTGF5ZXJzTGlzdDtcclxuXHRcdGNvbnRhaW5lci5hcHBlbmRDaGlsZChsYWJlbCk7XHJcblxyXG5cdFx0dGhpcy5fY2hlY2tEaXNhYmxlZExheWVycygpO1xyXG5cdFx0cmV0dXJuIGxhYmVsO1xyXG5cdH0sXHJcblxyXG5cdF9vbklucHV0Q2xpY2s6IGZ1bmN0aW9uICgpIHtcclxuXHRcdHZhciBpbnB1dHMgPSB0aGlzLl9mb3JtLmdldEVsZW1lbnRzQnlUYWdOYW1lKCdpbnB1dCcpLFxyXG5cdFx0ICAgIGlucHV0LCBsYXllciwgaGFzTGF5ZXI7XHJcblx0XHR2YXIgYWRkZWRMYXllcnMgPSBbXSxcclxuXHRcdCAgICByZW1vdmVkTGF5ZXJzID0gW107XHJcblxyXG5cdFx0dGhpcy5faGFuZGxpbmdDbGljayA9IHRydWU7XHJcblxyXG5cdFx0Zm9yICh2YXIgaSA9IGlucHV0cy5sZW5ndGggLSAxOyBpID49IDA7IGktLSkge1xyXG5cdFx0XHRpbnB1dCA9IGlucHV0c1tpXTtcclxuXHRcdFx0bGF5ZXIgPSB0aGlzLl9nZXRMYXllcihpbnB1dC5sYXllcklkKS5sYXllcjtcclxuXHRcdFx0aGFzTGF5ZXIgPSB0aGlzLl9tYXAuaGFzTGF5ZXIobGF5ZXIpO1xyXG5cclxuXHRcdFx0aWYgKGlucHV0LmNoZWNrZWQgJiYgIWhhc0xheWVyKSB7XHJcblx0XHRcdFx0YWRkZWRMYXllcnMucHVzaChsYXllcik7XHJcblxyXG5cdFx0XHR9IGVsc2UgaWYgKCFpbnB1dC5jaGVja2VkICYmIGhhc0xheWVyKSB7XHJcblx0XHRcdFx0cmVtb3ZlZExheWVycy5wdXNoKGxheWVyKTtcclxuXHRcdFx0fVxyXG5cdFx0fVxyXG5cclxuXHRcdC8vIEJ1Z2ZpeCBpc3N1ZSAyMzE4OiBTaG91bGQgcmVtb3ZlIGFsbCBvbGQgbGF5ZXJzIGJlZm9yZSByZWFkZGluZyBuZXcgb25lc1xyXG5cdFx0Zm9yIChpID0gMDsgaSA8IHJlbW92ZWRMYXllcnMubGVuZ3RoOyBpKyspIHtcclxuXHRcdFx0dGhpcy5fbWFwLnJlbW92ZUxheWVyKHJlbW92ZWRMYXllcnNbaV0pO1xyXG5cdFx0fVxyXG5cdFx0Zm9yIChpID0gMDsgaSA8IGFkZGVkTGF5ZXJzLmxlbmd0aDsgaSsrKSB7XHJcblx0XHRcdHRoaXMuX21hcC5hZGRMYXllcihhZGRlZExheWVyc1tpXSk7XHJcblx0XHR9XHJcblxyXG5cdFx0dGhpcy5faGFuZGxpbmdDbGljayA9IGZhbHNlO1xyXG5cclxuXHRcdHRoaXMuX3JlZm9jdXNPbk1hcCgpO1xyXG5cdH0sXHJcblxyXG5cdF9jaGVja0Rpc2FibGVkTGF5ZXJzOiBmdW5jdGlvbiAoKSB7XHJcblx0XHR2YXIgaW5wdXRzID0gdGhpcy5fZm9ybS5nZXRFbGVtZW50c0J5VGFnTmFtZSgnaW5wdXQnKSxcclxuXHRcdCAgICBpbnB1dCxcclxuXHRcdCAgICBsYXllcixcclxuXHRcdCAgICB6b29tID0gdGhpcy5fbWFwLmdldFpvb20oKTtcclxuXHJcblx0XHRmb3IgKHZhciBpID0gaW5wdXRzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XHJcblx0XHRcdGlucHV0ID0gaW5wdXRzW2ldO1xyXG5cdFx0XHRsYXllciA9IHRoaXMuX2dldExheWVyKGlucHV0LmxheWVySWQpLmxheWVyO1xyXG5cdFx0XHRpbnB1dC5kaXNhYmxlZCA9IChsYXllci5vcHRpb25zLm1pblpvb20gIT09IHVuZGVmaW5lZCAmJiB6b29tIDwgbGF5ZXIub3B0aW9ucy5taW5ab29tKSB8fFxyXG5cdFx0XHQgICAgICAgICAgICAgICAgIChsYXllci5vcHRpb25zLm1heFpvb20gIT09IHVuZGVmaW5lZCAmJiB6b29tID4gbGF5ZXIub3B0aW9ucy5tYXhab29tKTtcclxuXHJcblx0XHR9XHJcblx0fSxcclxuXHJcblx0X2V4cGFuZDogZnVuY3Rpb24gKCkge1xyXG5cdFx0Ly8gQmFja3dhcmQgY29tcGF0aWJpbGl0eSwgcmVtb3ZlIG1lIGluIDEuMS5cclxuXHRcdHJldHVybiB0aGlzLmV4cGFuZCgpO1xyXG5cdH0sXHJcblxyXG5cdF9jb2xsYXBzZTogZnVuY3Rpb24gKCkge1xyXG5cdFx0Ly8gQmFja3dhcmQgY29tcGF0aWJpbGl0eSwgcmVtb3ZlIG1lIGluIDEuMS5cclxuXHRcdHJldHVybiB0aGlzLmNvbGxhcHNlKCk7XHJcblx0fVxyXG5cclxufSk7XHJcblxyXG5cclxuLy8gQGZhY3RvcnkgTC5jb250cm9sLmxheWVycyhiYXNlbGF5ZXJzPzogT2JqZWN0LCBvdmVybGF5cz86IE9iamVjdCwgb3B0aW9ucz86IENvbnRyb2wuTGF5ZXJzIG9wdGlvbnMpXHJcbi8vIENyZWF0ZXMgYW4gYXR0cmlidXRpb24gY29udHJvbCB3aXRoIHRoZSBnaXZlbiBsYXllcnMuIEJhc2UgbGF5ZXJzIHdpbGwgYmUgc3dpdGNoZWQgd2l0aCByYWRpbyBidXR0b25zLCB3aGlsZSBvdmVybGF5cyB3aWxsIGJlIHN3aXRjaGVkIHdpdGggY2hlY2tib3hlcy4gTm90ZSB0aGF0IGFsbCBiYXNlIGxheWVycyBzaG91bGQgYmUgcGFzc2VkIGluIHRoZSBiYXNlIGxheWVycyBvYmplY3QsIGJ1dCBvbmx5IG9uZSBzaG91bGQgYmUgYWRkZWQgdG8gdGhlIG1hcCBkdXJpbmcgbWFwIGluc3RhbnRpYXRpb24uXHJcbkwuY29udHJvbC5sYXllcnMgPSBmdW5jdGlvbiAoYmFzZUxheWVycywgb3ZlcmxheXMsIG9wdGlvbnMpIHtcclxuXHRyZXR1cm4gbmV3IEwuQ29udHJvbC5MYXllcnMoYmFzZUxheWVycywgb3ZlcmxheXMsIG9wdGlvbnMpO1xyXG59O1xyXG5cblxuXG59KHdpbmRvdywgZG9jdW1lbnQpKTtcbi8vIyBzb3VyY2VNYXBwaW5nVVJMPWxlYWZsZXQtc3JjLm1hcCIsIi8qIVxuICogbXVzdGFjaGUuanMgLSBMb2dpYy1sZXNzIHt7bXVzdGFjaGV9fSB0ZW1wbGF0ZXMgd2l0aCBKYXZhU2NyaXB0XG4gKiBodHRwOi8vZ2l0aHViLmNvbS9qYW5sL211c3RhY2hlLmpzXG4gKi9cblxuLypnbG9iYWwgZGVmaW5lOiBmYWxzZSBNdXN0YWNoZTogdHJ1ZSovXG5cbihmdW5jdGlvbiBkZWZpbmVNdXN0YWNoZSAoZ2xvYmFsLCBmYWN0b3J5KSB7XG4gIGlmICh0eXBlb2YgZXhwb3J0cyA9PT0gJ29iamVjdCcgJiYgZXhwb3J0cyAmJiB0eXBlb2YgZXhwb3J0cy5ub2RlTmFtZSAhPT0gJ3N0cmluZycpIHtcbiAgICBmYWN0b3J5KGV4cG9ydHMpOyAvLyBDb21tb25KU1xuICB9IGVsc2UgaWYgKHR5cGVvZiBkZWZpbmUgPT09ICdmdW5jdGlvbicgJiYgZGVmaW5lLmFtZCkge1xuICAgIGRlZmluZShbJ2V4cG9ydHMnXSwgZmFjdG9yeSk7IC8vIEFNRFxuICB9IGVsc2Uge1xuICAgIGdsb2JhbC5NdXN0YWNoZSA9IHt9O1xuICAgIGZhY3RvcnkoZ2xvYmFsLk11c3RhY2hlKTsgLy8gc2NyaXB0LCB3c2gsIGFzcFxuICB9XG59KHRoaXMsIGZ1bmN0aW9uIG11c3RhY2hlRmFjdG9yeSAobXVzdGFjaGUpIHtcblxuICB2YXIgb2JqZWN0VG9TdHJpbmcgPSBPYmplY3QucHJvdG90eXBlLnRvU3RyaW5nO1xuICB2YXIgaXNBcnJheSA9IEFycmF5LmlzQXJyYXkgfHwgZnVuY3Rpb24gaXNBcnJheVBvbHlmaWxsIChvYmplY3QpIHtcbiAgICByZXR1cm4gb2JqZWN0VG9TdHJpbmcuY2FsbChvYmplY3QpID09PSAnW29iamVjdCBBcnJheV0nO1xuICB9O1xuXG4gIGZ1bmN0aW9uIGlzRnVuY3Rpb24gKG9iamVjdCkge1xuICAgIHJldHVybiB0eXBlb2Ygb2JqZWN0ID09PSAnZnVuY3Rpb24nO1xuICB9XG5cbiAgLyoqXG4gICAqIE1vcmUgY29ycmVjdCB0eXBlb2Ygc3RyaW5nIGhhbmRsaW5nIGFycmF5XG4gICAqIHdoaWNoIG5vcm1hbGx5IHJldHVybnMgdHlwZW9mICdvYmplY3QnXG4gICAqL1xuICBmdW5jdGlvbiB0eXBlU3RyIChvYmopIHtcbiAgICByZXR1cm4gaXNBcnJheShvYmopID8gJ2FycmF5JyA6IHR5cGVvZiBvYmo7XG4gIH1cblxuICBmdW5jdGlvbiBlc2NhcGVSZWdFeHAgKHN0cmluZykge1xuICAgIHJldHVybiBzdHJpbmcucmVwbGFjZSgvW1xcLVxcW1xcXXt9KCkqKz8uLFxcXFxcXF4kfCNcXHNdL2csICdcXFxcJCYnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBOdWxsIHNhZmUgd2F5IG9mIGNoZWNraW5nIHdoZXRoZXIgb3Igbm90IGFuIG9iamVjdCxcbiAgICogaW5jbHVkaW5nIGl0cyBwcm90b3R5cGUsIGhhcyBhIGdpdmVuIHByb3BlcnR5XG4gICAqL1xuICBmdW5jdGlvbiBoYXNQcm9wZXJ0eSAob2JqLCBwcm9wTmFtZSkge1xuICAgIHJldHVybiBvYmogIT0gbnVsbCAmJiB0eXBlb2Ygb2JqID09PSAnb2JqZWN0JyAmJiAocHJvcE5hbWUgaW4gb2JqKTtcbiAgfVxuXG4gIC8vIFdvcmthcm91bmQgZm9yIGh0dHBzOi8vaXNzdWVzLmFwYWNoZS5vcmcvamlyYS9icm93c2UvQ09VQ0hEQi01NzdcbiAgLy8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9qYW5sL211c3RhY2hlLmpzL2lzc3Vlcy8xODlcbiAgdmFyIHJlZ0V4cFRlc3QgPSBSZWdFeHAucHJvdG90eXBlLnRlc3Q7XG4gIGZ1bmN0aW9uIHRlc3RSZWdFeHAgKHJlLCBzdHJpbmcpIHtcbiAgICByZXR1cm4gcmVnRXhwVGVzdC5jYWxsKHJlLCBzdHJpbmcpO1xuICB9XG5cbiAgdmFyIG5vblNwYWNlUmUgPSAvXFxTLztcbiAgZnVuY3Rpb24gaXNXaGl0ZXNwYWNlIChzdHJpbmcpIHtcbiAgICByZXR1cm4gIXRlc3RSZWdFeHAobm9uU3BhY2VSZSwgc3RyaW5nKTtcbiAgfVxuXG4gIHZhciBlbnRpdHlNYXAgPSB7XG4gICAgJyYnOiAnJmFtcDsnLFxuICAgICc8JzogJyZsdDsnLFxuICAgICc+JzogJyZndDsnLFxuICAgICdcIic6ICcmcXVvdDsnLFxuICAgIFwiJ1wiOiAnJiMzOTsnLFxuICAgICcvJzogJyYjeDJGOycsXG4gICAgJ2AnOiAnJiN4NjA7JyxcbiAgICAnPSc6ICcmI3gzRDsnXG4gIH07XG5cbiAgZnVuY3Rpb24gZXNjYXBlSHRtbCAoc3RyaW5nKSB7XG4gICAgcmV0dXJuIFN0cmluZyhzdHJpbmcpLnJlcGxhY2UoL1smPD5cIidgPVxcL10vZywgZnVuY3Rpb24gZnJvbUVudGl0eU1hcCAocykge1xuICAgICAgcmV0dXJuIGVudGl0eU1hcFtzXTtcbiAgICB9KTtcbiAgfVxuXG4gIHZhciB3aGl0ZVJlID0gL1xccyovO1xuICB2YXIgc3BhY2VSZSA9IC9cXHMrLztcbiAgdmFyIGVxdWFsc1JlID0gL1xccyo9LztcbiAgdmFyIGN1cmx5UmUgPSAvXFxzKlxcfS87XG4gIHZhciB0YWdSZSA9IC8jfFxcXnxcXC98PnxcXHt8Jnw9fCEvO1xuXG4gIC8qKlxuICAgKiBCcmVha3MgdXAgdGhlIGdpdmVuIGB0ZW1wbGF0ZWAgc3RyaW5nIGludG8gYSB0cmVlIG9mIHRva2Vucy4gSWYgdGhlIGB0YWdzYFxuICAgKiBhcmd1bWVudCBpcyBnaXZlbiBoZXJlIGl0IG11c3QgYmUgYW4gYXJyYXkgd2l0aCB0d28gc3RyaW5nIHZhbHVlczogdGhlXG4gICAqIG9wZW5pbmcgYW5kIGNsb3NpbmcgdGFncyB1c2VkIGluIHRoZSB0ZW1wbGF0ZSAoZS5nLiBbIFwiPCVcIiwgXCIlPlwiIF0pLiBPZlxuICAgKiBjb3Vyc2UsIHRoZSBkZWZhdWx0IGlzIHRvIHVzZSBtdXN0YWNoZXMgKGkuZS4gbXVzdGFjaGUudGFncykuXG4gICAqXG4gICAqIEEgdG9rZW4gaXMgYW4gYXJyYXkgd2l0aCBhdCBsZWFzdCA0IGVsZW1lbnRzLiBUaGUgZmlyc3QgZWxlbWVudCBpcyB0aGVcbiAgICogbXVzdGFjaGUgc3ltYm9sIHRoYXQgd2FzIHVzZWQgaW5zaWRlIHRoZSB0YWcsIGUuZy4gXCIjXCIgb3IgXCImXCIuIElmIHRoZSB0YWdcbiAgICogZGlkIG5vdCBjb250YWluIGEgc3ltYm9sIChpLmUuIHt7bXlWYWx1ZX19KSB0aGlzIGVsZW1lbnQgaXMgXCJuYW1lXCIuIEZvclxuICAgKiBhbGwgdGV4dCB0aGF0IGFwcGVhcnMgb3V0c2lkZSBhIHN5bWJvbCB0aGlzIGVsZW1lbnQgaXMgXCJ0ZXh0XCIuXG4gICAqXG4gICAqIFRoZSBzZWNvbmQgZWxlbWVudCBvZiBhIHRva2VuIGlzIGl0cyBcInZhbHVlXCIuIEZvciBtdXN0YWNoZSB0YWdzIHRoaXMgaXNcbiAgICogd2hhdGV2ZXIgZWxzZSB3YXMgaW5zaWRlIHRoZSB0YWcgYmVzaWRlcyB0aGUgb3BlbmluZyBzeW1ib2wuIEZvciB0ZXh0IHRva2Vuc1xuICAgKiB0aGlzIGlzIHRoZSB0ZXh0IGl0c2VsZi5cbiAgICpcbiAgICogVGhlIHRoaXJkIGFuZCBmb3VydGggZWxlbWVudHMgb2YgdGhlIHRva2VuIGFyZSB0aGUgc3RhcnQgYW5kIGVuZCBpbmRpY2VzLFxuICAgKiByZXNwZWN0aXZlbHksIG9mIHRoZSB0b2tlbiBpbiB0aGUgb3JpZ2luYWwgdGVtcGxhdGUuXG4gICAqXG4gICAqIFRva2VucyB0aGF0IGFyZSB0aGUgcm9vdCBub2RlIG9mIGEgc3VidHJlZSBjb250YWluIHR3byBtb3JlIGVsZW1lbnRzOiAxKSBhblxuICAgKiBhcnJheSBvZiB0b2tlbnMgaW4gdGhlIHN1YnRyZWUgYW5kIDIpIHRoZSBpbmRleCBpbiB0aGUgb3JpZ2luYWwgdGVtcGxhdGUgYXRcbiAgICogd2hpY2ggdGhlIGNsb3NpbmcgdGFnIGZvciB0aGF0IHNlY3Rpb24gYmVnaW5zLlxuICAgKi9cbiAgZnVuY3Rpb24gcGFyc2VUZW1wbGF0ZSAodGVtcGxhdGUsIHRhZ3MpIHtcbiAgICBpZiAoIXRlbXBsYXRlKVxuICAgICAgcmV0dXJuIFtdO1xuXG4gICAgdmFyIHNlY3Rpb25zID0gW107ICAgICAvLyBTdGFjayB0byBob2xkIHNlY3Rpb24gdG9rZW5zXG4gICAgdmFyIHRva2VucyA9IFtdOyAgICAgICAvLyBCdWZmZXIgdG8gaG9sZCB0aGUgdG9rZW5zXG4gICAgdmFyIHNwYWNlcyA9IFtdOyAgICAgICAvLyBJbmRpY2VzIG9mIHdoaXRlc3BhY2UgdG9rZW5zIG9uIHRoZSBjdXJyZW50IGxpbmVcbiAgICB2YXIgaGFzVGFnID0gZmFsc2U7ICAgIC8vIElzIHRoZXJlIGEge3t0YWd9fSBvbiB0aGUgY3VycmVudCBsaW5lP1xuICAgIHZhciBub25TcGFjZSA9IGZhbHNlOyAgLy8gSXMgdGhlcmUgYSBub24tc3BhY2UgY2hhciBvbiB0aGUgY3VycmVudCBsaW5lP1xuXG4gICAgLy8gU3RyaXBzIGFsbCB3aGl0ZXNwYWNlIHRva2VucyBhcnJheSBmb3IgdGhlIGN1cnJlbnQgbGluZVxuICAgIC8vIGlmIHRoZXJlIHdhcyBhIHt7I3RhZ319IG9uIGl0IGFuZCBvdGhlcndpc2Ugb25seSBzcGFjZS5cbiAgICBmdW5jdGlvbiBzdHJpcFNwYWNlICgpIHtcbiAgICAgIGlmIChoYXNUYWcgJiYgIW5vblNwYWNlKSB7XG4gICAgICAgIHdoaWxlIChzcGFjZXMubGVuZ3RoKVxuICAgICAgICAgIGRlbGV0ZSB0b2tlbnNbc3BhY2VzLnBvcCgpXTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHNwYWNlcyA9IFtdO1xuICAgICAgfVxuXG4gICAgICBoYXNUYWcgPSBmYWxzZTtcbiAgICAgIG5vblNwYWNlID0gZmFsc2U7XG4gICAgfVxuXG4gICAgdmFyIG9wZW5pbmdUYWdSZSwgY2xvc2luZ1RhZ1JlLCBjbG9zaW5nQ3VybHlSZTtcbiAgICBmdW5jdGlvbiBjb21waWxlVGFncyAodGFnc1RvQ29tcGlsZSkge1xuICAgICAgaWYgKHR5cGVvZiB0YWdzVG9Db21waWxlID09PSAnc3RyaW5nJylcbiAgICAgICAgdGFnc1RvQ29tcGlsZSA9IHRhZ3NUb0NvbXBpbGUuc3BsaXQoc3BhY2VSZSwgMik7XG5cbiAgICAgIGlmICghaXNBcnJheSh0YWdzVG9Db21waWxlKSB8fCB0YWdzVG9Db21waWxlLmxlbmd0aCAhPT0gMilcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIHRhZ3M6ICcgKyB0YWdzVG9Db21waWxlKTtcblxuICAgICAgb3BlbmluZ1RhZ1JlID0gbmV3IFJlZ0V4cChlc2NhcGVSZWdFeHAodGFnc1RvQ29tcGlsZVswXSkgKyAnXFxcXHMqJyk7XG4gICAgICBjbG9zaW5nVGFnUmUgPSBuZXcgUmVnRXhwKCdcXFxccyonICsgZXNjYXBlUmVnRXhwKHRhZ3NUb0NvbXBpbGVbMV0pKTtcbiAgICAgIGNsb3NpbmdDdXJseVJlID0gbmV3IFJlZ0V4cCgnXFxcXHMqJyArIGVzY2FwZVJlZ0V4cCgnfScgKyB0YWdzVG9Db21waWxlWzFdKSk7XG4gICAgfVxuXG4gICAgY29tcGlsZVRhZ3ModGFncyB8fCBtdXN0YWNoZS50YWdzKTtcblxuICAgIHZhciBzY2FubmVyID0gbmV3IFNjYW5uZXIodGVtcGxhdGUpO1xuXG4gICAgdmFyIHN0YXJ0LCB0eXBlLCB2YWx1ZSwgY2hyLCB0b2tlbiwgb3BlblNlY3Rpb247XG4gICAgd2hpbGUgKCFzY2FubmVyLmVvcygpKSB7XG4gICAgICBzdGFydCA9IHNjYW5uZXIucG9zO1xuXG4gICAgICAvLyBNYXRjaCBhbnkgdGV4dCBiZXR3ZWVuIHRhZ3MuXG4gICAgICB2YWx1ZSA9IHNjYW5uZXIuc2NhblVudGlsKG9wZW5pbmdUYWdSZSk7XG5cbiAgICAgIGlmICh2YWx1ZSkge1xuICAgICAgICBmb3IgKHZhciBpID0gMCwgdmFsdWVMZW5ndGggPSB2YWx1ZS5sZW5ndGg7IGkgPCB2YWx1ZUxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgY2hyID0gdmFsdWUuY2hhckF0KGkpO1xuXG4gICAgICAgICAgaWYgKGlzV2hpdGVzcGFjZShjaHIpKSB7XG4gICAgICAgICAgICBzcGFjZXMucHVzaCh0b2tlbnMubGVuZ3RoKTtcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbm9uU3BhY2UgPSB0cnVlO1xuICAgICAgICAgIH1cblxuICAgICAgICAgIHRva2Vucy5wdXNoKFsgJ3RleHQnLCBjaHIsIHN0YXJ0LCBzdGFydCArIDEgXSk7XG4gICAgICAgICAgc3RhcnQgKz0gMTtcblxuICAgICAgICAgIC8vIENoZWNrIGZvciB3aGl0ZXNwYWNlIG9uIHRoZSBjdXJyZW50IGxpbmUuXG4gICAgICAgICAgaWYgKGNociA9PT0gJ1xcbicpXG4gICAgICAgICAgICBzdHJpcFNwYWNlKCk7XG4gICAgICAgIH1cbiAgICAgIH1cblxuICAgICAgLy8gTWF0Y2ggdGhlIG9wZW5pbmcgdGFnLlxuICAgICAgaWYgKCFzY2FubmVyLnNjYW4ob3BlbmluZ1RhZ1JlKSlcbiAgICAgICAgYnJlYWs7XG5cbiAgICAgIGhhc1RhZyA9IHRydWU7XG5cbiAgICAgIC8vIEdldCB0aGUgdGFnIHR5cGUuXG4gICAgICB0eXBlID0gc2Nhbm5lci5zY2FuKHRhZ1JlKSB8fCAnbmFtZSc7XG4gICAgICBzY2FubmVyLnNjYW4od2hpdGVSZSk7XG5cbiAgICAgIC8vIEdldCB0aGUgdGFnIHZhbHVlLlxuICAgICAgaWYgKHR5cGUgPT09ICc9Jykge1xuICAgICAgICB2YWx1ZSA9IHNjYW5uZXIuc2NhblVudGlsKGVxdWFsc1JlKTtcbiAgICAgICAgc2Nhbm5lci5zY2FuKGVxdWFsc1JlKTtcbiAgICAgICAgc2Nhbm5lci5zY2FuVW50aWwoY2xvc2luZ1RhZ1JlKTtcbiAgICAgIH0gZWxzZSBpZiAodHlwZSA9PT0gJ3snKSB7XG4gICAgICAgIHZhbHVlID0gc2Nhbm5lci5zY2FuVW50aWwoY2xvc2luZ0N1cmx5UmUpO1xuICAgICAgICBzY2FubmVyLnNjYW4oY3VybHlSZSk7XG4gICAgICAgIHNjYW5uZXIuc2NhblVudGlsKGNsb3NpbmdUYWdSZSk7XG4gICAgICAgIHR5cGUgPSAnJic7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YWx1ZSA9IHNjYW5uZXIuc2NhblVudGlsKGNsb3NpbmdUYWdSZSk7XG4gICAgICB9XG5cbiAgICAgIC8vIE1hdGNoIHRoZSBjbG9zaW5nIHRhZy5cbiAgICAgIGlmICghc2Nhbm5lci5zY2FuKGNsb3NpbmdUYWdSZSkpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignVW5jbG9zZWQgdGFnIGF0ICcgKyBzY2FubmVyLnBvcyk7XG5cbiAgICAgIHRva2VuID0gWyB0eXBlLCB2YWx1ZSwgc3RhcnQsIHNjYW5uZXIucG9zIF07XG4gICAgICB0b2tlbnMucHVzaCh0b2tlbik7XG5cbiAgICAgIGlmICh0eXBlID09PSAnIycgfHwgdHlwZSA9PT0gJ14nKSB7XG4gICAgICAgIHNlY3Rpb25zLnB1c2godG9rZW4pO1xuICAgICAgfSBlbHNlIGlmICh0eXBlID09PSAnLycpIHtcbiAgICAgICAgLy8gQ2hlY2sgc2VjdGlvbiBuZXN0aW5nLlxuICAgICAgICBvcGVuU2VjdGlvbiA9IHNlY3Rpb25zLnBvcCgpO1xuXG4gICAgICAgIGlmICghb3BlblNlY3Rpb24pXG4gICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdVbm9wZW5lZCBzZWN0aW9uIFwiJyArIHZhbHVlICsgJ1wiIGF0ICcgKyBzdGFydCk7XG5cbiAgICAgICAgaWYgKG9wZW5TZWN0aW9uWzFdICE9PSB2YWx1ZSlcbiAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VuY2xvc2VkIHNlY3Rpb24gXCInICsgb3BlblNlY3Rpb25bMV0gKyAnXCIgYXQgJyArIHN0YXJ0KTtcbiAgICAgIH0gZWxzZSBpZiAodHlwZSA9PT0gJ25hbWUnIHx8IHR5cGUgPT09ICd7JyB8fCB0eXBlID09PSAnJicpIHtcbiAgICAgICAgbm9uU3BhY2UgPSB0cnVlO1xuICAgICAgfSBlbHNlIGlmICh0eXBlID09PSAnPScpIHtcbiAgICAgICAgLy8gU2V0IHRoZSB0YWdzIGZvciB0aGUgbmV4dCB0aW1lIGFyb3VuZC5cbiAgICAgICAgY29tcGlsZVRhZ3ModmFsdWUpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIE1ha2Ugc3VyZSB0aGVyZSBhcmUgbm8gb3BlbiBzZWN0aW9ucyB3aGVuIHdlJ3JlIGRvbmUuXG4gICAgb3BlblNlY3Rpb24gPSBzZWN0aW9ucy5wb3AoKTtcblxuICAgIGlmIChvcGVuU2VjdGlvbilcbiAgICAgIHRocm93IG5ldyBFcnJvcignVW5jbG9zZWQgc2VjdGlvbiBcIicgKyBvcGVuU2VjdGlvblsxXSArICdcIiBhdCAnICsgc2Nhbm5lci5wb3MpO1xuXG4gICAgcmV0dXJuIG5lc3RUb2tlbnMoc3F1YXNoVG9rZW5zKHRva2VucykpO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbWJpbmVzIHRoZSB2YWx1ZXMgb2YgY29uc2VjdXRpdmUgdGV4dCB0b2tlbnMgaW4gdGhlIGdpdmVuIGB0b2tlbnNgIGFycmF5XG4gICAqIHRvIGEgc2luZ2xlIHRva2VuLlxuICAgKi9cbiAgZnVuY3Rpb24gc3F1YXNoVG9rZW5zICh0b2tlbnMpIHtcbiAgICB2YXIgc3F1YXNoZWRUb2tlbnMgPSBbXTtcblxuICAgIHZhciB0b2tlbiwgbGFzdFRva2VuO1xuICAgIGZvciAodmFyIGkgPSAwLCBudW1Ub2tlbnMgPSB0b2tlbnMubGVuZ3RoOyBpIDwgbnVtVG9rZW5zOyArK2kpIHtcbiAgICAgIHRva2VuID0gdG9rZW5zW2ldO1xuXG4gICAgICBpZiAodG9rZW4pIHtcbiAgICAgICAgaWYgKHRva2VuWzBdID09PSAndGV4dCcgJiYgbGFzdFRva2VuICYmIGxhc3RUb2tlblswXSA9PT0gJ3RleHQnKSB7XG4gICAgICAgICAgbGFzdFRva2VuWzFdICs9IHRva2VuWzFdO1xuICAgICAgICAgIGxhc3RUb2tlblszXSA9IHRva2VuWzNdO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHNxdWFzaGVkVG9rZW5zLnB1c2godG9rZW4pO1xuICAgICAgICAgIGxhc3RUb2tlbiA9IHRva2VuO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHNxdWFzaGVkVG9rZW5zO1xuICB9XG5cbiAgLyoqXG4gICAqIEZvcm1zIHRoZSBnaXZlbiBhcnJheSBvZiBgdG9rZW5zYCBpbnRvIGEgbmVzdGVkIHRyZWUgc3RydWN0dXJlIHdoZXJlXG4gICAqIHRva2VucyB0aGF0IHJlcHJlc2VudCBhIHNlY3Rpb24gaGF2ZSB0d28gYWRkaXRpb25hbCBpdGVtczogMSkgYW4gYXJyYXkgb2ZcbiAgICogYWxsIHRva2VucyB0aGF0IGFwcGVhciBpbiB0aGF0IHNlY3Rpb24gYW5kIDIpIHRoZSBpbmRleCBpbiB0aGUgb3JpZ2luYWxcbiAgICogdGVtcGxhdGUgdGhhdCByZXByZXNlbnRzIHRoZSBlbmQgb2YgdGhhdCBzZWN0aW9uLlxuICAgKi9cbiAgZnVuY3Rpb24gbmVzdFRva2VucyAodG9rZW5zKSB7XG4gICAgdmFyIG5lc3RlZFRva2VucyA9IFtdO1xuICAgIHZhciBjb2xsZWN0b3IgPSBuZXN0ZWRUb2tlbnM7XG4gICAgdmFyIHNlY3Rpb25zID0gW107XG5cbiAgICB2YXIgdG9rZW4sIHNlY3Rpb247XG4gICAgZm9yICh2YXIgaSA9IDAsIG51bVRva2VucyA9IHRva2Vucy5sZW5ndGg7IGkgPCBudW1Ub2tlbnM7ICsraSkge1xuICAgICAgdG9rZW4gPSB0b2tlbnNbaV07XG5cbiAgICAgIHN3aXRjaCAodG9rZW5bMF0pIHtcbiAgICAgICAgY2FzZSAnIyc6XG4gICAgICAgIGNhc2UgJ14nOlxuICAgICAgICAgIGNvbGxlY3Rvci5wdXNoKHRva2VuKTtcbiAgICAgICAgICBzZWN0aW9ucy5wdXNoKHRva2VuKTtcbiAgICAgICAgICBjb2xsZWN0b3IgPSB0b2tlbls0XSA9IFtdO1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICcvJzpcbiAgICAgICAgICBzZWN0aW9uID0gc2VjdGlvbnMucG9wKCk7XG4gICAgICAgICAgc2VjdGlvbls1XSA9IHRva2VuWzJdO1xuICAgICAgICAgIGNvbGxlY3RvciA9IHNlY3Rpb25zLmxlbmd0aCA+IDAgPyBzZWN0aW9uc1tzZWN0aW9ucy5sZW5ndGggLSAxXVs0XSA6IG5lc3RlZFRva2VucztcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICBjb2xsZWN0b3IucHVzaCh0b2tlbik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG5lc3RlZFRva2VucztcbiAgfVxuXG4gIC8qKlxuICAgKiBBIHNpbXBsZSBzdHJpbmcgc2Nhbm5lciB0aGF0IGlzIHVzZWQgYnkgdGhlIHRlbXBsYXRlIHBhcnNlciB0byBmaW5kXG4gICAqIHRva2VucyBpbiB0ZW1wbGF0ZSBzdHJpbmdzLlxuICAgKi9cbiAgZnVuY3Rpb24gU2Nhbm5lciAoc3RyaW5nKSB7XG4gICAgdGhpcy5zdHJpbmcgPSBzdHJpbmc7XG4gICAgdGhpcy50YWlsID0gc3RyaW5nO1xuICAgIHRoaXMucG9zID0gMDtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGB0cnVlYCBpZiB0aGUgdGFpbCBpcyBlbXB0eSAoZW5kIG9mIHN0cmluZykuXG4gICAqL1xuICBTY2FubmVyLnByb3RvdHlwZS5lb3MgPSBmdW5jdGlvbiBlb3MgKCkge1xuICAgIHJldHVybiB0aGlzLnRhaWwgPT09ICcnO1xuICB9O1xuXG4gIC8qKlxuICAgKiBUcmllcyB0byBtYXRjaCB0aGUgZ2l2ZW4gcmVndWxhciBleHByZXNzaW9uIGF0IHRoZSBjdXJyZW50IHBvc2l0aW9uLlxuICAgKiBSZXR1cm5zIHRoZSBtYXRjaGVkIHRleHQgaWYgaXQgY2FuIG1hdGNoLCB0aGUgZW1wdHkgc3RyaW5nIG90aGVyd2lzZS5cbiAgICovXG4gIFNjYW5uZXIucHJvdG90eXBlLnNjYW4gPSBmdW5jdGlvbiBzY2FuIChyZSkge1xuICAgIHZhciBtYXRjaCA9IHRoaXMudGFpbC5tYXRjaChyZSk7XG5cbiAgICBpZiAoIW1hdGNoIHx8IG1hdGNoLmluZGV4ICE9PSAwKVxuICAgICAgcmV0dXJuICcnO1xuXG4gICAgdmFyIHN0cmluZyA9IG1hdGNoWzBdO1xuXG4gICAgdGhpcy50YWlsID0gdGhpcy50YWlsLnN1YnN0cmluZyhzdHJpbmcubGVuZ3RoKTtcbiAgICB0aGlzLnBvcyArPSBzdHJpbmcubGVuZ3RoO1xuXG4gICAgcmV0dXJuIHN0cmluZztcbiAgfTtcblxuICAvKipcbiAgICogU2tpcHMgYWxsIHRleHQgdW50aWwgdGhlIGdpdmVuIHJlZ3VsYXIgZXhwcmVzc2lvbiBjYW4gYmUgbWF0Y2hlZC4gUmV0dXJuc1xuICAgKiB0aGUgc2tpcHBlZCBzdHJpbmcsIHdoaWNoIGlzIHRoZSBlbnRpcmUgdGFpbCBpZiBubyBtYXRjaCBjYW4gYmUgbWFkZS5cbiAgICovXG4gIFNjYW5uZXIucHJvdG90eXBlLnNjYW5VbnRpbCA9IGZ1bmN0aW9uIHNjYW5VbnRpbCAocmUpIHtcbiAgICB2YXIgaW5kZXggPSB0aGlzLnRhaWwuc2VhcmNoKHJlKSwgbWF0Y2g7XG5cbiAgICBzd2l0Y2ggKGluZGV4KSB7XG4gICAgICBjYXNlIC0xOlxuICAgICAgICBtYXRjaCA9IHRoaXMudGFpbDtcbiAgICAgICAgdGhpcy50YWlsID0gJyc7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAwOlxuICAgICAgICBtYXRjaCA9ICcnO1xuICAgICAgICBicmVhaztcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIG1hdGNoID0gdGhpcy50YWlsLnN1YnN0cmluZygwLCBpbmRleCk7XG4gICAgICAgIHRoaXMudGFpbCA9IHRoaXMudGFpbC5zdWJzdHJpbmcoaW5kZXgpO1xuICAgIH1cblxuICAgIHRoaXMucG9zICs9IG1hdGNoLmxlbmd0aDtcblxuICAgIHJldHVybiBtYXRjaDtcbiAgfTtcblxuICAvKipcbiAgICogUmVwcmVzZW50cyBhIHJlbmRlcmluZyBjb250ZXh0IGJ5IHdyYXBwaW5nIGEgdmlldyBvYmplY3QgYW5kXG4gICAqIG1haW50YWluaW5nIGEgcmVmZXJlbmNlIHRvIHRoZSBwYXJlbnQgY29udGV4dC5cbiAgICovXG4gIGZ1bmN0aW9uIENvbnRleHQgKHZpZXcsIHBhcmVudENvbnRleHQpIHtcbiAgICB0aGlzLnZpZXcgPSB2aWV3O1xuICAgIHRoaXMuY2FjaGUgPSB7ICcuJzogdGhpcy52aWV3IH07XG4gICAgdGhpcy5wYXJlbnQgPSBwYXJlbnRDb250ZXh0O1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSBuZXcgY29udGV4dCB1c2luZyB0aGUgZ2l2ZW4gdmlldyB3aXRoIHRoaXMgY29udGV4dFxuICAgKiBhcyB0aGUgcGFyZW50LlxuICAgKi9cbiAgQ29udGV4dC5wcm90b3R5cGUucHVzaCA9IGZ1bmN0aW9uIHB1c2ggKHZpZXcpIHtcbiAgICByZXR1cm4gbmV3IENvbnRleHQodmlldywgdGhpcyk7XG4gIH07XG5cbiAgLyoqXG4gICAqIFJldHVybnMgdGhlIHZhbHVlIG9mIHRoZSBnaXZlbiBuYW1lIGluIHRoaXMgY29udGV4dCwgdHJhdmVyc2luZ1xuICAgKiB1cCB0aGUgY29udGV4dCBoaWVyYXJjaHkgaWYgdGhlIHZhbHVlIGlzIGFic2VudCBpbiB0aGlzIGNvbnRleHQncyB2aWV3LlxuICAgKi9cbiAgQ29udGV4dC5wcm90b3R5cGUubG9va3VwID0gZnVuY3Rpb24gbG9va3VwIChuYW1lKSB7XG4gICAgdmFyIGNhY2hlID0gdGhpcy5jYWNoZTtcblxuICAgIHZhciB2YWx1ZTtcbiAgICBpZiAoY2FjaGUuaGFzT3duUHJvcGVydHkobmFtZSkpIHtcbiAgICAgIHZhbHVlID0gY2FjaGVbbmFtZV07XG4gICAgfSBlbHNlIHtcbiAgICAgIHZhciBjb250ZXh0ID0gdGhpcywgbmFtZXMsIGluZGV4LCBsb29rdXBIaXQgPSBmYWxzZTtcblxuICAgICAgd2hpbGUgKGNvbnRleHQpIHtcbiAgICAgICAgaWYgKG5hbWUuaW5kZXhPZignLicpID4gMCkge1xuICAgICAgICAgIHZhbHVlID0gY29udGV4dC52aWV3O1xuICAgICAgICAgIG5hbWVzID0gbmFtZS5zcGxpdCgnLicpO1xuICAgICAgICAgIGluZGV4ID0gMDtcblxuICAgICAgICAgIC8qKlxuICAgICAgICAgICAqIFVzaW5nIHRoZSBkb3Qgbm90aW9uIHBhdGggaW4gYG5hbWVgLCB3ZSBkZXNjZW5kIHRocm91Z2ggdGhlXG4gICAgICAgICAgICogbmVzdGVkIG9iamVjdHMuXG4gICAgICAgICAgICpcbiAgICAgICAgICAgKiBUbyBiZSBjZXJ0YWluIHRoYXQgdGhlIGxvb2t1cCBoYXMgYmVlbiBzdWNjZXNzZnVsLCB3ZSBoYXZlIHRvXG4gICAgICAgICAgICogY2hlY2sgaWYgdGhlIGxhc3Qgb2JqZWN0IGluIHRoZSBwYXRoIGFjdHVhbGx5IGhhcyB0aGUgcHJvcGVydHlcbiAgICAgICAgICAgKiB3ZSBhcmUgbG9va2luZyBmb3IuIFdlIHN0b3JlIHRoZSByZXN1bHQgaW4gYGxvb2t1cEhpdGAuXG4gICAgICAgICAgICpcbiAgICAgICAgICAgKiBUaGlzIGlzIHNwZWNpYWxseSBuZWNlc3NhcnkgZm9yIHdoZW4gdGhlIHZhbHVlIGhhcyBiZWVuIHNldCB0b1xuICAgICAgICAgICAqIGB1bmRlZmluZWRgIGFuZCB3ZSB3YW50IHRvIGF2b2lkIGxvb2tpbmcgdXAgcGFyZW50IGNvbnRleHRzLlxuICAgICAgICAgICAqKi9cbiAgICAgICAgICB3aGlsZSAodmFsdWUgIT0gbnVsbCAmJiBpbmRleCA8IG5hbWVzLmxlbmd0aCkge1xuICAgICAgICAgICAgaWYgKGluZGV4ID09PSBuYW1lcy5sZW5ndGggLSAxKVxuICAgICAgICAgICAgICBsb29rdXBIaXQgPSBoYXNQcm9wZXJ0eSh2YWx1ZSwgbmFtZXNbaW5kZXhdKTtcblxuICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZVtuYW1lc1tpbmRleCsrXV07XG4gICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhbHVlID0gY29udGV4dC52aWV3W25hbWVdO1xuICAgICAgICAgIGxvb2t1cEhpdCA9IGhhc1Byb3BlcnR5KGNvbnRleHQudmlldywgbmFtZSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobG9va3VwSGl0KVxuICAgICAgICAgIGJyZWFrO1xuXG4gICAgICAgIGNvbnRleHQgPSBjb250ZXh0LnBhcmVudDtcbiAgICAgIH1cblxuICAgICAgY2FjaGVbbmFtZV0gPSB2YWx1ZTtcbiAgICB9XG5cbiAgICBpZiAoaXNGdW5jdGlvbih2YWx1ZSkpXG4gICAgICB2YWx1ZSA9IHZhbHVlLmNhbGwodGhpcy52aWV3KTtcblxuICAgIHJldHVybiB2YWx1ZTtcbiAgfTtcblxuICAvKipcbiAgICogQSBXcml0ZXIga25vd3MgaG93IHRvIHRha2UgYSBzdHJlYW0gb2YgdG9rZW5zIGFuZCByZW5kZXIgdGhlbSB0byBhXG4gICAqIHN0cmluZywgZ2l2ZW4gYSBjb250ZXh0LiBJdCBhbHNvIG1haW50YWlucyBhIGNhY2hlIG9mIHRlbXBsYXRlcyB0b1xuICAgKiBhdm9pZCB0aGUgbmVlZCB0byBwYXJzZSB0aGUgc2FtZSB0ZW1wbGF0ZSB0d2ljZS5cbiAgICovXG4gIGZ1bmN0aW9uIFdyaXRlciAoKSB7XG4gICAgdGhpcy5jYWNoZSA9IHt9O1xuICB9XG5cbiAgLyoqXG4gICAqIENsZWFycyBhbGwgY2FjaGVkIHRlbXBsYXRlcyBpbiB0aGlzIHdyaXRlci5cbiAgICovXG4gIFdyaXRlci5wcm90b3R5cGUuY2xlYXJDYWNoZSA9IGZ1bmN0aW9uIGNsZWFyQ2FjaGUgKCkge1xuICAgIHRoaXMuY2FjaGUgPSB7fTtcbiAgfTtcblxuICAvKipcbiAgICogUGFyc2VzIGFuZCBjYWNoZXMgdGhlIGdpdmVuIGB0ZW1wbGF0ZWAgYW5kIHJldHVybnMgdGhlIGFycmF5IG9mIHRva2Vuc1xuICAgKiB0aGF0IGlzIGdlbmVyYXRlZCBmcm9tIHRoZSBwYXJzZS5cbiAgICovXG4gIFdyaXRlci5wcm90b3R5cGUucGFyc2UgPSBmdW5jdGlvbiBwYXJzZSAodGVtcGxhdGUsIHRhZ3MpIHtcbiAgICB2YXIgY2FjaGUgPSB0aGlzLmNhY2hlO1xuICAgIHZhciB0b2tlbnMgPSBjYWNoZVt0ZW1wbGF0ZV07XG5cbiAgICBpZiAodG9rZW5zID09IG51bGwpXG4gICAgICB0b2tlbnMgPSBjYWNoZVt0ZW1wbGF0ZV0gPSBwYXJzZVRlbXBsYXRlKHRlbXBsYXRlLCB0YWdzKTtcblxuICAgIHJldHVybiB0b2tlbnM7XG4gIH07XG5cbiAgLyoqXG4gICAqIEhpZ2gtbGV2ZWwgbWV0aG9kIHRoYXQgaXMgdXNlZCB0byByZW5kZXIgdGhlIGdpdmVuIGB0ZW1wbGF0ZWAgd2l0aFxuICAgKiB0aGUgZ2l2ZW4gYHZpZXdgLlxuICAgKlxuICAgKiBUaGUgb3B0aW9uYWwgYHBhcnRpYWxzYCBhcmd1bWVudCBtYXkgYmUgYW4gb2JqZWN0IHRoYXQgY29udGFpbnMgdGhlXG4gICAqIG5hbWVzIGFuZCB0ZW1wbGF0ZXMgb2YgcGFydGlhbHMgdGhhdCBhcmUgdXNlZCBpbiB0aGUgdGVtcGxhdGUuIEl0IG1heVxuICAgKiBhbHNvIGJlIGEgZnVuY3Rpb24gdGhhdCBpcyB1c2VkIHRvIGxvYWQgcGFydGlhbCB0ZW1wbGF0ZXMgb24gdGhlIGZseVxuICAgKiB0aGF0IHRha2VzIGEgc2luZ2xlIGFyZ3VtZW50OiB0aGUgbmFtZSBvZiB0aGUgcGFydGlhbC5cbiAgICovXG4gIFdyaXRlci5wcm90b3R5cGUucmVuZGVyID0gZnVuY3Rpb24gcmVuZGVyICh0ZW1wbGF0ZSwgdmlldywgcGFydGlhbHMpIHtcbiAgICB2YXIgdG9rZW5zID0gdGhpcy5wYXJzZSh0ZW1wbGF0ZSk7XG4gICAgdmFyIGNvbnRleHQgPSAodmlldyBpbnN0YW5jZW9mIENvbnRleHQpID8gdmlldyA6IG5ldyBDb250ZXh0KHZpZXcpO1xuICAgIHJldHVybiB0aGlzLnJlbmRlclRva2Vucyh0b2tlbnMsIGNvbnRleHQsIHBhcnRpYWxzLCB0ZW1wbGF0ZSk7XG4gIH07XG5cbiAgLyoqXG4gICAqIExvdy1sZXZlbCBtZXRob2QgdGhhdCByZW5kZXJzIHRoZSBnaXZlbiBhcnJheSBvZiBgdG9rZW5zYCB1c2luZ1xuICAgKiB0aGUgZ2l2ZW4gYGNvbnRleHRgIGFuZCBgcGFydGlhbHNgLlxuICAgKlxuICAgKiBOb3RlOiBUaGUgYG9yaWdpbmFsVGVtcGxhdGVgIGlzIG9ubHkgZXZlciB1c2VkIHRvIGV4dHJhY3QgdGhlIHBvcnRpb25cbiAgICogb2YgdGhlIG9yaWdpbmFsIHRlbXBsYXRlIHRoYXQgd2FzIGNvbnRhaW5lZCBpbiBhIGhpZ2hlci1vcmRlciBzZWN0aW9uLlxuICAgKiBJZiB0aGUgdGVtcGxhdGUgZG9lc24ndCB1c2UgaGlnaGVyLW9yZGVyIHNlY3Rpb25zLCB0aGlzIGFyZ3VtZW50IG1heVxuICAgKiBiZSBvbWl0dGVkLlxuICAgKi9cbiAgV3JpdGVyLnByb3RvdHlwZS5yZW5kZXJUb2tlbnMgPSBmdW5jdGlvbiByZW5kZXJUb2tlbnMgKHRva2VucywgY29udGV4dCwgcGFydGlhbHMsIG9yaWdpbmFsVGVtcGxhdGUpIHtcbiAgICB2YXIgYnVmZmVyID0gJyc7XG5cbiAgICB2YXIgdG9rZW4sIHN5bWJvbCwgdmFsdWU7XG4gICAgZm9yICh2YXIgaSA9IDAsIG51bVRva2VucyA9IHRva2Vucy5sZW5ndGg7IGkgPCBudW1Ub2tlbnM7ICsraSkge1xuICAgICAgdmFsdWUgPSB1bmRlZmluZWQ7XG4gICAgICB0b2tlbiA9IHRva2Vuc1tpXTtcbiAgICAgIHN5bWJvbCA9IHRva2VuWzBdO1xuXG4gICAgICBpZiAoc3ltYm9sID09PSAnIycpIHZhbHVlID0gdGhpcy5yZW5kZXJTZWN0aW9uKHRva2VuLCBjb250ZXh0LCBwYXJ0aWFscywgb3JpZ2luYWxUZW1wbGF0ZSk7XG4gICAgICBlbHNlIGlmIChzeW1ib2wgPT09ICdeJykgdmFsdWUgPSB0aGlzLnJlbmRlckludmVydGVkKHRva2VuLCBjb250ZXh0LCBwYXJ0aWFscywgb3JpZ2luYWxUZW1wbGF0ZSk7XG4gICAgICBlbHNlIGlmIChzeW1ib2wgPT09ICc+JykgdmFsdWUgPSB0aGlzLnJlbmRlclBhcnRpYWwodG9rZW4sIGNvbnRleHQsIHBhcnRpYWxzLCBvcmlnaW5hbFRlbXBsYXRlKTtcbiAgICAgIGVsc2UgaWYgKHN5bWJvbCA9PT0gJyYnKSB2YWx1ZSA9IHRoaXMudW5lc2NhcGVkVmFsdWUodG9rZW4sIGNvbnRleHQpO1xuICAgICAgZWxzZSBpZiAoc3ltYm9sID09PSAnbmFtZScpIHZhbHVlID0gdGhpcy5lc2NhcGVkVmFsdWUodG9rZW4sIGNvbnRleHQpO1xuICAgICAgZWxzZSBpZiAoc3ltYm9sID09PSAndGV4dCcpIHZhbHVlID0gdGhpcy5yYXdWYWx1ZSh0b2tlbik7XG5cbiAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKVxuICAgICAgICBidWZmZXIgKz0gdmFsdWU7XG4gICAgfVxuXG4gICAgcmV0dXJuIGJ1ZmZlcjtcbiAgfTtcblxuICBXcml0ZXIucHJvdG90eXBlLnJlbmRlclNlY3Rpb24gPSBmdW5jdGlvbiByZW5kZXJTZWN0aW9uICh0b2tlbiwgY29udGV4dCwgcGFydGlhbHMsIG9yaWdpbmFsVGVtcGxhdGUpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGJ1ZmZlciA9ICcnO1xuICAgIHZhciB2YWx1ZSA9IGNvbnRleHQubG9va3VwKHRva2VuWzFdKTtcblxuICAgIC8vIFRoaXMgZnVuY3Rpb24gaXMgdXNlZCB0byByZW5kZXIgYW4gYXJiaXRyYXJ5IHRlbXBsYXRlXG4gICAgLy8gaW4gdGhlIGN1cnJlbnQgY29udGV4dCBieSBoaWdoZXItb3JkZXIgc2VjdGlvbnMuXG4gICAgZnVuY3Rpb24gc3ViUmVuZGVyICh0ZW1wbGF0ZSkge1xuICAgICAgcmV0dXJuIHNlbGYucmVuZGVyKHRlbXBsYXRlLCBjb250ZXh0LCBwYXJ0aWFscyk7XG4gICAgfVxuXG4gICAgaWYgKCF2YWx1ZSkgcmV0dXJuO1xuXG4gICAgaWYgKGlzQXJyYXkodmFsdWUpKSB7XG4gICAgICBmb3IgKHZhciBqID0gMCwgdmFsdWVMZW5ndGggPSB2YWx1ZS5sZW5ndGg7IGogPCB2YWx1ZUxlbmd0aDsgKytqKSB7XG4gICAgICAgIGJ1ZmZlciArPSB0aGlzLnJlbmRlclRva2Vucyh0b2tlbls0XSwgY29udGV4dC5wdXNoKHZhbHVlW2pdKSwgcGFydGlhbHMsIG9yaWdpbmFsVGVtcGxhdGUpO1xuICAgICAgfVxuICAgIH0gZWxzZSBpZiAodHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyB8fCB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicpIHtcbiAgICAgIGJ1ZmZlciArPSB0aGlzLnJlbmRlclRva2Vucyh0b2tlbls0XSwgY29udGV4dC5wdXNoKHZhbHVlKSwgcGFydGlhbHMsIG9yaWdpbmFsVGVtcGxhdGUpO1xuICAgIH0gZWxzZSBpZiAoaXNGdW5jdGlvbih2YWx1ZSkpIHtcbiAgICAgIGlmICh0eXBlb2Ygb3JpZ2luYWxUZW1wbGF0ZSAhPT0gJ3N0cmluZycpXG4gICAgICAgIHRocm93IG5ldyBFcnJvcignQ2Fubm90IHVzZSBoaWdoZXItb3JkZXIgc2VjdGlvbnMgd2l0aG91dCB0aGUgb3JpZ2luYWwgdGVtcGxhdGUnKTtcblxuICAgICAgLy8gRXh0cmFjdCB0aGUgcG9ydGlvbiBvZiB0aGUgb3JpZ2luYWwgdGVtcGxhdGUgdGhhdCB0aGUgc2VjdGlvbiBjb250YWlucy5cbiAgICAgIHZhbHVlID0gdmFsdWUuY2FsbChjb250ZXh0LnZpZXcsIG9yaWdpbmFsVGVtcGxhdGUuc2xpY2UodG9rZW5bM10sIHRva2VuWzVdKSwgc3ViUmVuZGVyKTtcblxuICAgICAgaWYgKHZhbHVlICE9IG51bGwpXG4gICAgICAgIGJ1ZmZlciArPSB2YWx1ZTtcbiAgICB9IGVsc2Uge1xuICAgICAgYnVmZmVyICs9IHRoaXMucmVuZGVyVG9rZW5zKHRva2VuWzRdLCBjb250ZXh0LCBwYXJ0aWFscywgb3JpZ2luYWxUZW1wbGF0ZSk7XG4gICAgfVxuICAgIHJldHVybiBidWZmZXI7XG4gIH07XG5cbiAgV3JpdGVyLnByb3RvdHlwZS5yZW5kZXJJbnZlcnRlZCA9IGZ1bmN0aW9uIHJlbmRlckludmVydGVkICh0b2tlbiwgY29udGV4dCwgcGFydGlhbHMsIG9yaWdpbmFsVGVtcGxhdGUpIHtcbiAgICB2YXIgdmFsdWUgPSBjb250ZXh0Lmxvb2t1cCh0b2tlblsxXSk7XG5cbiAgICAvLyBVc2UgSmF2YVNjcmlwdCdzIGRlZmluaXRpb24gb2YgZmFsc3kuIEluY2x1ZGUgZW1wdHkgYXJyYXlzLlxuICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20vamFubC9tdXN0YWNoZS5qcy9pc3N1ZXMvMTg2XG4gICAgaWYgKCF2YWx1ZSB8fCAoaXNBcnJheSh2YWx1ZSkgJiYgdmFsdWUubGVuZ3RoID09PSAwKSlcbiAgICAgIHJldHVybiB0aGlzLnJlbmRlclRva2Vucyh0b2tlbls0XSwgY29udGV4dCwgcGFydGlhbHMsIG9yaWdpbmFsVGVtcGxhdGUpO1xuICB9O1xuXG4gIFdyaXRlci5wcm90b3R5cGUucmVuZGVyUGFydGlhbCA9IGZ1bmN0aW9uIHJlbmRlclBhcnRpYWwgKHRva2VuLCBjb250ZXh0LCBwYXJ0aWFscykge1xuICAgIGlmICghcGFydGlhbHMpIHJldHVybjtcblxuICAgIHZhciB2YWx1ZSA9IGlzRnVuY3Rpb24ocGFydGlhbHMpID8gcGFydGlhbHModG9rZW5bMV0pIDogcGFydGlhbHNbdG9rZW5bMV1dO1xuICAgIGlmICh2YWx1ZSAhPSBudWxsKVxuICAgICAgcmV0dXJuIHRoaXMucmVuZGVyVG9rZW5zKHRoaXMucGFyc2UodmFsdWUpLCBjb250ZXh0LCBwYXJ0aWFscywgdmFsdWUpO1xuICB9O1xuXG4gIFdyaXRlci5wcm90b3R5cGUudW5lc2NhcGVkVmFsdWUgPSBmdW5jdGlvbiB1bmVzY2FwZWRWYWx1ZSAodG9rZW4sIGNvbnRleHQpIHtcbiAgICB2YXIgdmFsdWUgPSBjb250ZXh0Lmxvb2t1cCh0b2tlblsxXSk7XG4gICAgaWYgKHZhbHVlICE9IG51bGwpXG4gICAgICByZXR1cm4gdmFsdWU7XG4gIH07XG5cbiAgV3JpdGVyLnByb3RvdHlwZS5lc2NhcGVkVmFsdWUgPSBmdW5jdGlvbiBlc2NhcGVkVmFsdWUgKHRva2VuLCBjb250ZXh0KSB7XG4gICAgdmFyIHZhbHVlID0gY29udGV4dC5sb29rdXAodG9rZW5bMV0pO1xuICAgIGlmICh2YWx1ZSAhPSBudWxsKVxuICAgICAgcmV0dXJuIG11c3RhY2hlLmVzY2FwZSh2YWx1ZSk7XG4gIH07XG5cbiAgV3JpdGVyLnByb3RvdHlwZS5yYXdWYWx1ZSA9IGZ1bmN0aW9uIHJhd1ZhbHVlICh0b2tlbikge1xuICAgIHJldHVybiB0b2tlblsxXTtcbiAgfTtcblxuICBtdXN0YWNoZS5uYW1lID0gJ211c3RhY2hlLmpzJztcbiAgbXVzdGFjaGUudmVyc2lvbiA9ICcyLjIuMSc7XG4gIG11c3RhY2hlLnRhZ3MgPSBbICd7eycsICd9fScgXTtcblxuICAvLyBBbGwgaGlnaC1sZXZlbCBtdXN0YWNoZS4qIGZ1bmN0aW9ucyB1c2UgdGhpcyB3cml0ZXIuXG4gIHZhciBkZWZhdWx0V3JpdGVyID0gbmV3IFdyaXRlcigpO1xuXG4gIC8qKlxuICAgKiBDbGVhcnMgYWxsIGNhY2hlZCB0ZW1wbGF0ZXMgaW4gdGhlIGRlZmF1bHQgd3JpdGVyLlxuICAgKi9cbiAgbXVzdGFjaGUuY2xlYXJDYWNoZSA9IGZ1bmN0aW9uIGNsZWFyQ2FjaGUgKCkge1xuICAgIHJldHVybiBkZWZhdWx0V3JpdGVyLmNsZWFyQ2FjaGUoKTtcbiAgfTtcblxuICAvKipcbiAgICogUGFyc2VzIGFuZCBjYWNoZXMgdGhlIGdpdmVuIHRlbXBsYXRlIGluIHRoZSBkZWZhdWx0IHdyaXRlciBhbmQgcmV0dXJucyB0aGVcbiAgICogYXJyYXkgb2YgdG9rZW5zIGl0IGNvbnRhaW5zLiBEb2luZyB0aGlzIGFoZWFkIG9mIHRpbWUgYXZvaWRzIHRoZSBuZWVkIHRvXG4gICAqIHBhcnNlIHRlbXBsYXRlcyBvbiB0aGUgZmx5IGFzIHRoZXkgYXJlIHJlbmRlcmVkLlxuICAgKi9cbiAgbXVzdGFjaGUucGFyc2UgPSBmdW5jdGlvbiBwYXJzZSAodGVtcGxhdGUsIHRhZ3MpIHtcbiAgICByZXR1cm4gZGVmYXVsdFdyaXRlci5wYXJzZSh0ZW1wbGF0ZSwgdGFncyk7XG4gIH07XG5cbiAgLyoqXG4gICAqIFJlbmRlcnMgdGhlIGB0ZW1wbGF0ZWAgd2l0aCB0aGUgZ2l2ZW4gYHZpZXdgIGFuZCBgcGFydGlhbHNgIHVzaW5nIHRoZVxuICAgKiBkZWZhdWx0IHdyaXRlci5cbiAgICovXG4gIG11c3RhY2hlLnJlbmRlciA9IGZ1bmN0aW9uIHJlbmRlciAodGVtcGxhdGUsIHZpZXcsIHBhcnRpYWxzKSB7XG4gICAgaWYgKHR5cGVvZiB0ZW1wbGF0ZSAhPT0gJ3N0cmluZycpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3IoJ0ludmFsaWQgdGVtcGxhdGUhIFRlbXBsYXRlIHNob3VsZCBiZSBhIFwic3RyaW5nXCIgJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICdidXQgXCInICsgdHlwZVN0cih0ZW1wbGF0ZSkgKyAnXCIgd2FzIGdpdmVuIGFzIHRoZSBmaXJzdCAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgJ2FyZ3VtZW50IGZvciBtdXN0YWNoZSNyZW5kZXIodGVtcGxhdGUsIHZpZXcsIHBhcnRpYWxzKScpO1xuICAgIH1cblxuICAgIHJldHVybiBkZWZhdWx0V3JpdGVyLnJlbmRlcih0ZW1wbGF0ZSwgdmlldywgcGFydGlhbHMpO1xuICB9O1xuXG4gIC8vIFRoaXMgaXMgaGVyZSBmb3IgYmFja3dhcmRzIGNvbXBhdGliaWxpdHkgd2l0aCAwLjQueC4sXG4gIC8qZXNsaW50LWRpc2FibGUgKi8gLy8gZXNsaW50IHdhbnRzIGNhbWVsIGNhc2VkIGZ1bmN0aW9uIG5hbWVcbiAgbXVzdGFjaGUudG9faHRtbCA9IGZ1bmN0aW9uIHRvX2h0bWwgKHRlbXBsYXRlLCB2aWV3LCBwYXJ0aWFscywgc2VuZCkge1xuICAgIC8qZXNsaW50LWVuYWJsZSovXG5cbiAgICB2YXIgcmVzdWx0ID0gbXVzdGFjaGUucmVuZGVyKHRlbXBsYXRlLCB2aWV3LCBwYXJ0aWFscyk7XG5cbiAgICBpZiAoaXNGdW5jdGlvbihzZW5kKSkge1xuICAgICAgc2VuZChyZXN1bHQpO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gcmVzdWx0O1xuICAgIH1cbiAgfTtcblxuICAvLyBFeHBvcnQgdGhlIGVzY2FwaW5nIGZ1bmN0aW9uIHNvIHRoYXQgdGhlIHVzZXIgbWF5IG92ZXJyaWRlIGl0LlxuICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2phbmwvbXVzdGFjaGUuanMvaXNzdWVzLzI0NFxuICBtdXN0YWNoZS5lc2NhcGUgPSBlc2NhcGVIdG1sO1xuXG4gIC8vIEV4cG9ydCB0aGVzZSBtYWlubHkgZm9yIHRlc3RpbmcsIGJ1dCBhbHNvIGZvciBhZHZhbmNlZCB1c2FnZS5cbiAgbXVzdGFjaGUuU2Nhbm5lciA9IFNjYW5uZXI7XG4gIG11c3RhY2hlLkNvbnRleHQgPSBDb250ZXh0O1xuICBtdXN0YWNoZS5Xcml0ZXIgPSBXcml0ZXI7XG5cbn0pKTtcbiIsInZhciBodG1sX3Nhbml0aXplID0gcmVxdWlyZSgnLi9zYW5pdGl6ZXItYnVuZGxlLmpzJyk7XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oXykge1xuICAgIGlmICghXykgcmV0dXJuICcnO1xuICAgIHJldHVybiBodG1sX3Nhbml0aXplKF8sIGNsZWFuVXJsLCBjbGVhbklkKTtcbn07XG5cbi8vIGh0dHBzOi8vYnVnemlsbGEubW96aWxsYS5vcmcvc2hvd19idWcuY2dpP2lkPTI1NTEwN1xuZnVuY3Rpb24gY2xlYW5VcmwodXJsKSB7XG4gICAgJ3VzZSBzdHJpY3QnO1xuICAgIGlmICgvXmh0dHBzPy8udGVzdCh1cmwuZ2V0U2NoZW1lKCkpKSByZXR1cm4gdXJsLnRvU3RyaW5nKCk7XG4gICAgaWYgKC9ebWFpbHRvPy8udGVzdCh1cmwuZ2V0U2NoZW1lKCkpKSByZXR1cm4gdXJsLnRvU3RyaW5nKCk7XG4gICAgaWYgKCdkYXRhJyA9PSB1cmwuZ2V0U2NoZW1lKCkgJiYgL15pbWFnZS8udGVzdCh1cmwuZ2V0UGF0aCgpKSkge1xuICAgICAgICByZXR1cm4gdXJsLnRvU3RyaW5nKCk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBjbGVhbklkKGlkKSB7IHJldHVybiBpZDsgfVxuIiwiXG4vLyBDb3B5cmlnaHQgKEMpIDIwMTAgR29vZ2xlIEluYy5cbi8vXG4vLyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2Vuc2UsIFZlcnNpb24gMi4wICh0aGUgXCJMaWNlbnNlXCIpO1xuLy8geW91IG1heSBub3QgdXNlIHRoaXMgZmlsZSBleGNlcHQgaW4gY29tcGxpYW5jZSB3aXRoIHRoZSBMaWNlbnNlLlxuLy8gWW91IG1heSBvYnRhaW4gYSBjb3B5IG9mIHRoZSBMaWNlbnNlIGF0XG4vL1xuLy8gICAgICBodHRwOi8vd3d3LmFwYWNoZS5vcmcvbGljZW5zZXMvTElDRU5TRS0yLjBcbi8vXG4vLyBVbmxlc3MgcmVxdWlyZWQgYnkgYXBwbGljYWJsZSBsYXcgb3IgYWdyZWVkIHRvIGluIHdyaXRpbmcsIHNvZnR3YXJlXG4vLyBkaXN0cmlidXRlZCB1bmRlciB0aGUgTGljZW5zZSBpcyBkaXN0cmlidXRlZCBvbiBhbiBcIkFTIElTXCIgQkFTSVMsXG4vLyBXSVRIT1VUIFdBUlJBTlRJRVMgT1IgQ09ORElUSU9OUyBPRiBBTlkgS0lORCwgZWl0aGVyIGV4cHJlc3Mgb3IgaW1wbGllZC5cbi8vIFNlZSB0aGUgTGljZW5zZSBmb3IgdGhlIHNwZWNpZmljIGxhbmd1YWdlIGdvdmVybmluZyBwZXJtaXNzaW9ucyBhbmRcbi8vIGxpbWl0YXRpb25zIHVuZGVyIHRoZSBMaWNlbnNlLlxuXG4vKipcbiAqIEBmaWxlb3ZlcnZpZXdcbiAqIEltcGxlbWVudHMgUkZDIDM5ODYgZm9yIHBhcnNpbmcvZm9ybWF0dGluZyBVUklzLlxuICpcbiAqIEBhdXRob3IgbWlrZXNhbXVlbEBnbWFpbC5jb21cbiAqIFxcQHByb3ZpZGVzIFVSSVxuICogXFxAb3ZlcnJpZGVzIHdpbmRvd1xuICovXG5cbnZhciBVUkkgPSAoZnVuY3Rpb24gKCkge1xuXG4vKipcbiAqIGNyZWF0ZXMgYSB1cmkgZnJvbSB0aGUgc3RyaW5nIGZvcm0uICBUaGUgcGFyc2VyIGlzIHJlbGF4ZWQsIHNvIHNwZWNpYWxcbiAqIGNoYXJhY3RlcnMgdGhhdCBhcmVuJ3QgZXNjYXBlZCBidXQgZG9uJ3QgY2F1c2UgYW1iaWd1aXRpZXMgd2lsbCBub3QgY2F1c2VcbiAqIHBhcnNlIGZhaWx1cmVzLlxuICpcbiAqIEByZXR1cm4ge1VSSXxudWxsfVxuICovXG5mdW5jdGlvbiBwYXJzZSh1cmlTdHIpIHtcbiAgdmFyIG0gPSAoJycgKyB1cmlTdHIpLm1hdGNoKFVSSV9SRV8pO1xuICBpZiAoIW0pIHsgcmV0dXJuIG51bGw7IH1cbiAgcmV0dXJuIG5ldyBVUkkoXG4gICAgICBudWxsSWZBYnNlbnQobVsxXSksXG4gICAgICBudWxsSWZBYnNlbnQobVsyXSksXG4gICAgICBudWxsSWZBYnNlbnQobVszXSksXG4gICAgICBudWxsSWZBYnNlbnQobVs0XSksXG4gICAgICBudWxsSWZBYnNlbnQobVs1XSksXG4gICAgICBudWxsSWZBYnNlbnQobVs2XSksXG4gICAgICBudWxsSWZBYnNlbnQobVs3XSkpO1xufVxuXG5cbi8qKlxuICogY3JlYXRlcyBhIHVyaSBmcm9tIHRoZSBnaXZlbiBwYXJ0cy5cbiAqXG4gKiBAcGFyYW0gc2NoZW1lIHtzdHJpbmd9IGFuIHVuZW5jb2RlZCBzY2hlbWUgc3VjaCBhcyBcImh0dHBcIiBvciBudWxsXG4gKiBAcGFyYW0gY3JlZGVudGlhbHMge3N0cmluZ30gdW5lbmNvZGVkIHVzZXIgY3JlZGVudGlhbHMgb3IgbnVsbFxuICogQHBhcmFtIGRvbWFpbiB7c3RyaW5nfSBhbiB1bmVuY29kZWQgZG9tYWluIG5hbWUgb3IgbnVsbFxuICogQHBhcmFtIHBvcnQge251bWJlcn0gYSBwb3J0IG51bWJlciBpbiBbMSwgMzI3NjhdLlxuICogICAgLTEgaW5kaWNhdGVzIG5vIHBvcnQsIGFzIGRvZXMgbnVsbC5cbiAqIEBwYXJhbSBwYXRoIHtzdHJpbmd9IGFuIHVuZW5jb2RlZCBwYXRoXG4gKiBAcGFyYW0gcXVlcnkge0FycmF5LjxzdHJpbmc+fHN0cmluZ3xudWxsfSBhIGxpc3Qgb2YgdW5lbmNvZGVkIGNnaVxuICogICBwYXJhbWV0ZXJzIHdoZXJlIGV2ZW4gdmFsdWVzIGFyZSBrZXlzIGFuZCBvZGRzIHRoZSBjb3JyZXNwb25kaW5nIHZhbHVlc1xuICogICBvciBhbiB1bmVuY29kZWQgcXVlcnkuXG4gKiBAcGFyYW0gZnJhZ21lbnQge3N0cmluZ30gYW4gdW5lbmNvZGVkIGZyYWdtZW50IHdpdGhvdXQgdGhlIFwiI1wiIG9yIG51bGwuXG4gKiBAcmV0dXJuIHtVUkl9XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZShzY2hlbWUsIGNyZWRlbnRpYWxzLCBkb21haW4sIHBvcnQsIHBhdGgsIHF1ZXJ5LCBmcmFnbWVudCkge1xuICB2YXIgdXJpID0gbmV3IFVSSShcbiAgICAgIGVuY29kZUlmRXhpc3RzMihzY2hlbWUsIFVSSV9ESVNBTExPV0VEX0lOX1NDSEVNRV9PUl9DUkVERU5USUFMU18pLFxuICAgICAgZW5jb2RlSWZFeGlzdHMyKFxuICAgICAgICAgIGNyZWRlbnRpYWxzLCBVUklfRElTQUxMT1dFRF9JTl9TQ0hFTUVfT1JfQ1JFREVOVElBTFNfKSxcbiAgICAgIGVuY29kZUlmRXhpc3RzKGRvbWFpbiksXG4gICAgICBwb3J0ID4gMCA/IHBvcnQudG9TdHJpbmcoKSA6IG51bGwsXG4gICAgICBlbmNvZGVJZkV4aXN0czIocGF0aCwgVVJJX0RJU0FMTE9XRURfSU5fUEFUSF8pLFxuICAgICAgbnVsbCxcbiAgICAgIGVuY29kZUlmRXhpc3RzKGZyYWdtZW50KSk7XG4gIGlmIChxdWVyeSkge1xuICAgIGlmICgnc3RyaW5nJyA9PT0gdHlwZW9mIHF1ZXJ5KSB7XG4gICAgICB1cmkuc2V0UmF3UXVlcnkocXVlcnkucmVwbGFjZSgvW14/Jj0wLTlBLVphLXpfXFwtfi4lXS9nLCBlbmNvZGVPbmUpKTtcbiAgICB9IGVsc2Uge1xuICAgICAgdXJpLnNldEFsbFBhcmFtZXRlcnMocXVlcnkpO1xuICAgIH1cbiAgfVxuICByZXR1cm4gdXJpO1xufVxuZnVuY3Rpb24gZW5jb2RlSWZFeGlzdHModW5lc2NhcGVkUGFydCkge1xuICBpZiAoJ3N0cmluZycgPT0gdHlwZW9mIHVuZXNjYXBlZFBhcnQpIHtcbiAgICByZXR1cm4gZW5jb2RlVVJJQ29tcG9uZW50KHVuZXNjYXBlZFBhcnQpO1xuICB9XG4gIHJldHVybiBudWxsO1xufTtcbi8qKlxuICogaWYgdW5lc2NhcGVkUGFydCBpcyBub24gbnVsbCwgdGhlbiBlc2NhcGVzIGFueSBjaGFyYWN0ZXJzIGluIGl0IHRoYXQgYXJlbid0XG4gKiB2YWxpZCBjaGFyYWN0ZXJzIGluIGEgdXJsIGFuZCBhbHNvIGVzY2FwZXMgYW55IHNwZWNpYWwgY2hhcmFjdGVycyB0aGF0XG4gKiBhcHBlYXIgaW4gZXh0cmEuXG4gKlxuICogQHBhcmFtIHVuZXNjYXBlZFBhcnQge3N0cmluZ31cbiAqIEBwYXJhbSBleHRyYSB7UmVnRXhwfSBhIGNoYXJhY3RlciBzZXQgb2YgY2hhcmFjdGVycyBpbiBbXFwwMS1cXDE3N10uXG4gKiBAcmV0dXJuIHtzdHJpbmd8bnVsbH0gbnVsbCBpZmYgdW5lc2NhcGVkUGFydCA9PSBudWxsLlxuICovXG5mdW5jdGlvbiBlbmNvZGVJZkV4aXN0czIodW5lc2NhcGVkUGFydCwgZXh0cmEpIHtcbiAgaWYgKCdzdHJpbmcnID09IHR5cGVvZiB1bmVzY2FwZWRQYXJ0KSB7XG4gICAgcmV0dXJuIGVuY29kZVVSSSh1bmVzY2FwZWRQYXJ0KS5yZXBsYWNlKGV4dHJhLCBlbmNvZGVPbmUpO1xuICB9XG4gIHJldHVybiBudWxsO1xufTtcbi8qKiBjb252ZXJ0cyBhIGNoYXJhY3RlciBpbiBbXFwwMS1cXDE3N10gdG8gaXRzIHVybCBlbmNvZGVkIGVxdWl2YWxlbnQuICovXG5mdW5jdGlvbiBlbmNvZGVPbmUoY2gpIHtcbiAgdmFyIG4gPSBjaC5jaGFyQ29kZUF0KDApO1xuICByZXR1cm4gJyUnICsgJzAxMjM0NTY3ODlBQkNERUYnLmNoYXJBdCgobiA+PiA0KSAmIDB4ZikgK1xuICAgICAgJzAxMjM0NTY3ODlBQkNERUYnLmNoYXJBdChuICYgMHhmKTtcbn1cblxuLyoqXG4gKiB7QHVwZG9jXG4gKiAgJCBub3JtUGF0aCgnZm9vLy4vYmFyJylcbiAqICAjICdmb28vYmFyJ1xuICogICQgbm9ybVBhdGgoJy4vZm9vJylcbiAqICAjICdmb28nXG4gKiAgJCBub3JtUGF0aCgnZm9vLy4nKVxuICogICMgJ2ZvbydcbiAqICAkIG5vcm1QYXRoKCdmb28vL2JhcicpXG4gKiAgIyAnZm9vL2JhcidcbiAqIH1cbiAqL1xuZnVuY3Rpb24gbm9ybVBhdGgocGF0aCkge1xuICByZXR1cm4gcGF0aC5yZXBsYWNlKC8oXnxcXC8pXFwuKD86XFwvfCQpL2csICckMScpLnJlcGxhY2UoL1xcL3syLH0vZywgJy8nKTtcbn1cblxudmFyIFBBUkVOVF9ESVJFQ1RPUllfSEFORExFUiA9IG5ldyBSZWdFeHAoXG4gICAgJydcbiAgICAvLyBBIHBhdGggYnJlYWtcbiAgICArICcoL3xeKSdcbiAgICAvLyBmb2xsb3dlZCBieSBhIG5vbiAuLiBwYXRoIGVsZW1lbnRcbiAgICAvLyAoY2Fubm90IGJlIC4gYmVjYXVzZSBub3JtUGF0aCBpcyB1c2VkIHByaW9yIHRvIHRoaXMgUmVnRXhwKVxuICAgICsgJyg/OlteLi9dW14vXSp8XFxcXC57Mix9KD86W14uL11bXi9dKil8XFxcXC57Myx9W14vXSopJ1xuICAgIC8vIGZvbGxvd2VkIGJ5IC4uIGZvbGxvd2VkIGJ5IGEgcGF0aCBicmVhay5cbiAgICArICcvXFxcXC5cXFxcLig/Oi98JCknKTtcblxudmFyIFBBUkVOVF9ESVJFQ1RPUllfSEFORExFUl9SRSA9IG5ldyBSZWdFeHAoUEFSRU5UX0RJUkVDVE9SWV9IQU5ETEVSKTtcblxudmFyIEVYVFJBX1BBUkVOVF9QQVRIU19SRSA9IC9eKD86XFwuXFwuXFwvKSooPzpcXC5cXC4kKT8vO1xuXG4vKipcbiAqIE5vcm1hbGl6ZXMgaXRzIGlucHV0IHBhdGggYW5kIGNvbGxhcHNlcyBhbGwgLiBhbmQgLi4gc2VxdWVuY2VzIGV4Y2VwdCBmb3JcbiAqIC4uIHNlcXVlbmNlcyB0aGF0IHdvdWxkIHRha2UgaXQgYWJvdmUgdGhlIHJvb3Qgb2YgdGhlIGN1cnJlbnQgcGFyZW50XG4gKiBkaXJlY3RvcnkuXG4gKiB7QHVwZG9jXG4gKiAgJCBjb2xsYXBzZV9kb3RzKCdmb28vLi4vYmFyJylcbiAqICAjICdiYXInXG4gKiAgJCBjb2xsYXBzZV9kb3RzKCdmb28vLi9iYXInKVxuICogICMgJ2Zvby9iYXInXG4gKiAgJCBjb2xsYXBzZV9kb3RzKCdmb28vLi4vYmFyLy4vLi4vLi4vYmF6JylcbiAqICAjICdiYXonXG4gKiAgJCBjb2xsYXBzZV9kb3RzKCcuLi9mb28nKVxuICogICMgJy4uL2ZvbydcbiAqICAkIGNvbGxhcHNlX2RvdHMoJy4uL2ZvbycpLnJlcGxhY2UoRVhUUkFfUEFSRU5UX1BBVEhTX1JFLCAnJylcbiAqICAjICdmb28nXG4gKiB9XG4gKi9cbmZ1bmN0aW9uIGNvbGxhcHNlX2RvdHMocGF0aCkge1xuICBpZiAocGF0aCA9PT0gbnVsbCkgeyByZXR1cm4gbnVsbDsgfVxuICB2YXIgcCA9IG5vcm1QYXRoKHBhdGgpO1xuICAvLyBPbmx5IC8uLi8gbGVmdCB0byBmbGF0dGVuXG4gIHZhciByID0gUEFSRU5UX0RJUkVDVE9SWV9IQU5ETEVSX1JFO1xuICAvLyBXZSByZXBsYWNlIHdpdGggJDEgd2hpY2ggbWF0Y2hlcyBhIC8gYmVmb3JlIHRoZSAuLiBiZWNhdXNlIHRoaXNcbiAgLy8gZ3VhcmFudGVlcyB0aGF0OlxuICAvLyAoMSkgd2UgaGF2ZSBhdCBtb3N0IDEgLyBiZXR3ZWVuIHRoZSBhZGphY2VudCBwbGFjZSxcbiAgLy8gKDIpIGFsd2F5cyBoYXZlIGEgc2xhc2ggaWYgdGhlcmUgaXMgYSBwcmVjZWRpbmcgcGF0aCBzZWN0aW9uLCBhbmRcbiAgLy8gKDMpIHdlIG5ldmVyIHR1cm4gYSByZWxhdGl2ZSBwYXRoIGludG8gYW4gYWJzb2x1dGUgcGF0aC5cbiAgZm9yICh2YXIgcTsgKHEgPSBwLnJlcGxhY2UociwgJyQxJykpICE9IHA7IHAgPSBxKSB7fTtcbiAgcmV0dXJuIHA7XG59XG5cbi8qKlxuICogcmVzb2x2ZXMgYSByZWxhdGl2ZSB1cmwgc3RyaW5nIHRvIGEgYmFzZSB1cmkuXG4gKiBAcmV0dXJuIHtVUkl9XG4gKi9cbmZ1bmN0aW9uIHJlc29sdmUoYmFzZVVyaSwgcmVsYXRpdmVVcmkpIHtcbiAgLy8gdGhlcmUgYXJlIHNldmVyYWwga2luZHMgb2YgcmVsYXRpdmUgdXJsczpcbiAgLy8gMS4gLy9mb28gLSByZXBsYWNlcyBldmVyeXRoaW5nIGZyb20gdGhlIGRvbWFpbiBvbi4gIGZvbyBpcyBhIGRvbWFpbiBuYW1lXG4gIC8vIDIuIGZvbyAtIHJlcGxhY2VzIHRoZSBsYXN0IHBhcnQgb2YgdGhlIHBhdGgsIHRoZSB3aG9sZSBxdWVyeSBhbmQgZnJhZ21lbnRcbiAgLy8gMy4gL2ZvbyAtIHJlcGxhY2VzIHRoZSB0aGUgcGF0aCwgdGhlIHF1ZXJ5IGFuZCBmcmFnbWVudFxuICAvLyA0LiA/Zm9vIC0gcmVwbGFjZSB0aGUgcXVlcnkgYW5kIGZyYWdtZW50XG4gIC8vIDUuICNmb28gLSByZXBsYWNlIHRoZSBmcmFnbWVudCBvbmx5XG5cbiAgdmFyIGFic29sdXRlVXJpID0gYmFzZVVyaS5jbG9uZSgpO1xuICAvLyB3ZSBzYXRpc2Z5IHRoZXNlIGNvbmRpdGlvbnMgYnkgbG9va2luZyBmb3IgdGhlIGZpcnN0IHBhcnQgb2YgcmVsYXRpdmVVcmlcbiAgLy8gdGhhdCBpcyBub3QgYmxhbmsgYW5kIGFwcGx5aW5nIGRlZmF1bHRzIHRvIHRoZSByZXN0XG5cbiAgdmFyIG92ZXJyaWRkZW4gPSByZWxhdGl2ZVVyaS5oYXNTY2hlbWUoKTtcblxuICBpZiAob3ZlcnJpZGRlbikge1xuICAgIGFic29sdXRlVXJpLnNldFJhd1NjaGVtZShyZWxhdGl2ZVVyaS5nZXRSYXdTY2hlbWUoKSk7XG4gIH0gZWxzZSB7XG4gICAgb3ZlcnJpZGRlbiA9IHJlbGF0aXZlVXJpLmhhc0NyZWRlbnRpYWxzKCk7XG4gIH1cblxuICBpZiAob3ZlcnJpZGRlbikge1xuICAgIGFic29sdXRlVXJpLnNldFJhd0NyZWRlbnRpYWxzKHJlbGF0aXZlVXJpLmdldFJhd0NyZWRlbnRpYWxzKCkpO1xuICB9IGVsc2Uge1xuICAgIG92ZXJyaWRkZW4gPSByZWxhdGl2ZVVyaS5oYXNEb21haW4oKTtcbiAgfVxuXG4gIGlmIChvdmVycmlkZGVuKSB7XG4gICAgYWJzb2x1dGVVcmkuc2V0UmF3RG9tYWluKHJlbGF0aXZlVXJpLmdldFJhd0RvbWFpbigpKTtcbiAgfSBlbHNlIHtcbiAgICBvdmVycmlkZGVuID0gcmVsYXRpdmVVcmkuaGFzUG9ydCgpO1xuICB9XG5cbiAgdmFyIHJhd1BhdGggPSByZWxhdGl2ZVVyaS5nZXRSYXdQYXRoKCk7XG4gIHZhciBzaW1wbGlmaWVkUGF0aCA9IGNvbGxhcHNlX2RvdHMocmF3UGF0aCk7XG4gIGlmIChvdmVycmlkZGVuKSB7XG4gICAgYWJzb2x1dGVVcmkuc2V0UG9ydChyZWxhdGl2ZVVyaS5nZXRQb3J0KCkpO1xuICAgIHNpbXBsaWZpZWRQYXRoID0gc2ltcGxpZmllZFBhdGhcbiAgICAgICAgJiYgc2ltcGxpZmllZFBhdGgucmVwbGFjZShFWFRSQV9QQVJFTlRfUEFUSFNfUkUsICcnKTtcbiAgfSBlbHNlIHtcbiAgICBvdmVycmlkZGVuID0gISFyYXdQYXRoO1xuICAgIGlmIChvdmVycmlkZGVuKSB7XG4gICAgICAvLyByZXNvbHZlIHBhdGggcHJvcGVybHlcbiAgICAgIGlmIChzaW1wbGlmaWVkUGF0aC5jaGFyQ29kZUF0KDApICE9PSAweDJmIC8qIC8gKi8pIHsgIC8vIHBhdGggaXMgcmVsYXRpdmVcbiAgICAgICAgdmFyIGFic1Jhd1BhdGggPSBjb2xsYXBzZV9kb3RzKGFic29sdXRlVXJpLmdldFJhd1BhdGgoKSB8fCAnJylcbiAgICAgICAgICAgIC5yZXBsYWNlKEVYVFJBX1BBUkVOVF9QQVRIU19SRSwgJycpO1xuICAgICAgICB2YXIgc2xhc2ggPSBhYnNSYXdQYXRoLmxhc3RJbmRleE9mKCcvJykgKyAxO1xuICAgICAgICBzaW1wbGlmaWVkUGF0aCA9IGNvbGxhcHNlX2RvdHMoXG4gICAgICAgICAgICAoc2xhc2ggPyBhYnNSYXdQYXRoLnN1YnN0cmluZygwLCBzbGFzaCkgOiAnJylcbiAgICAgICAgICAgICsgY29sbGFwc2VfZG90cyhyYXdQYXRoKSlcbiAgICAgICAgICAgIC5yZXBsYWNlKEVYVFJBX1BBUkVOVF9QQVRIU19SRSwgJycpO1xuICAgICAgfVxuICAgIH0gZWxzZSB7XG4gICAgICBzaW1wbGlmaWVkUGF0aCA9IHNpbXBsaWZpZWRQYXRoXG4gICAgICAgICAgJiYgc2ltcGxpZmllZFBhdGgucmVwbGFjZShFWFRSQV9QQVJFTlRfUEFUSFNfUkUsICcnKTtcbiAgICAgIGlmIChzaW1wbGlmaWVkUGF0aCAhPT0gcmF3UGF0aCkge1xuICAgICAgICBhYnNvbHV0ZVVyaS5zZXRSYXdQYXRoKHNpbXBsaWZpZWRQYXRoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBpZiAob3ZlcnJpZGRlbikge1xuICAgIGFic29sdXRlVXJpLnNldFJhd1BhdGgoc2ltcGxpZmllZFBhdGgpO1xuICB9IGVsc2Uge1xuICAgIG92ZXJyaWRkZW4gPSByZWxhdGl2ZVVyaS5oYXNRdWVyeSgpO1xuICB9XG5cbiAgaWYgKG92ZXJyaWRkZW4pIHtcbiAgICBhYnNvbHV0ZVVyaS5zZXRSYXdRdWVyeShyZWxhdGl2ZVVyaS5nZXRSYXdRdWVyeSgpKTtcbiAgfSBlbHNlIHtcbiAgICBvdmVycmlkZGVuID0gcmVsYXRpdmVVcmkuaGFzRnJhZ21lbnQoKTtcbiAgfVxuXG4gIGlmIChvdmVycmlkZGVuKSB7XG4gICAgYWJzb2x1dGVVcmkuc2V0UmF3RnJhZ21lbnQocmVsYXRpdmVVcmkuZ2V0UmF3RnJhZ21lbnQoKSk7XG4gIH1cblxuICByZXR1cm4gYWJzb2x1dGVVcmk7XG59XG5cbi8qKlxuICogYSBtdXRhYmxlIFVSSS5cbiAqXG4gKiBUaGlzIGNsYXNzIGNvbnRhaW5zIHNldHRlcnMgYW5kIGdldHRlcnMgZm9yIHRoZSBwYXJ0cyBvZiB0aGUgVVJJLlxuICogVGhlIDx0dD5nZXRYWVo8L3R0Pi88dHQ+c2V0WFlaPC90dD4gbWV0aG9kcyByZXR1cm4gdGhlIGRlY29kZWQgcGFydCAtLSBzb1xuICogPGNvZGU+dXJpLnBhcnNlKCcvZm9vJTIwYmFyJykuZ2V0UGF0aCgpPC9jb2RlPiB3aWxsIHJldHVybiB0aGUgZGVjb2RlZCBwYXRoLFxuICogPHR0Pi9mb28gYmFyPC90dD4uXG4gKlxuICogPHA+VGhlIHJhdyB2ZXJzaW9ucyBvZiBmaWVsZHMgYXJlIGF2YWlsYWJsZSB0b28uXG4gKiA8Y29kZT51cmkucGFyc2UoJy9mb28lMjBiYXInKS5nZXRSYXdQYXRoKCk8L2NvZGU+IHdpbGwgcmV0dXJuIHRoZSByYXcgcGF0aCxcbiAqIDx0dD4vZm9vJTIwYmFyPC90dD4uICBVc2UgdGhlIHJhdyBzZXR0ZXJzIHdpdGggY2FyZSwgc2luY2VcbiAqIDxjb2RlPlVSSTo6dG9TdHJpbmc8L2NvZGU+IGlzIG5vdCBndWFyYW50ZWVkIHRvIHJldHVybiBhIHZhbGlkIHVybCBpZiBhXG4gKiByYXcgc2V0dGVyIHdhcyB1c2VkLlxuICpcbiAqIDxwPkFsbCBzZXR0ZXJzIHJldHVybiA8dHQ+dGhpczwvdHQ+IGFuZCBzbyBtYXkgYmUgY2hhaW5lZCwgYSBsYVxuICogPGNvZGU+dXJpLnBhcnNlKCcvZm9vJykuc2V0RnJhZ21lbnQoJ3BhcnQnKS50b1N0cmluZygpPC9jb2RlPi5cbiAqXG4gKiA8cD5Zb3Ugc2hvdWxkIG5vdCB1c2UgdGhpcyBjb25zdHJ1Y3RvciBkaXJlY3RseSAtLSBwbGVhc2UgcHJlZmVyIHRoZSBmYWN0b3J5XG4gKiBmdW5jdGlvbnMge0BsaW5rIHVyaS5wYXJzZX0sIHtAbGluayB1cmkuY3JlYXRlfSwge0BsaW5rIHVyaS5yZXNvbHZlfVxuICogaW5zdGVhZC48L3A+XG4gKlxuICogPHA+VGhlIHBhcmFtZXRlcnMgYXJlIGFsbCByYXcgKGFzc3VtZWQgdG8gYmUgcHJvcGVybHkgZXNjYXBlZCkgcGFydHMsIGFuZFxuICogYW55IChidXQgbm90IGFsbCkgbWF5IGJlIG51bGwuICBVbmRlZmluZWQgaXMgbm90IGFsbG93ZWQuPC9wPlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBVUkkoXG4gICAgcmF3U2NoZW1lLFxuICAgIHJhd0NyZWRlbnRpYWxzLCByYXdEb21haW4sIHBvcnQsXG4gICAgcmF3UGF0aCwgcmF3UXVlcnksIHJhd0ZyYWdtZW50KSB7XG4gIHRoaXMuc2NoZW1lXyA9IHJhd1NjaGVtZTtcbiAgdGhpcy5jcmVkZW50aWFsc18gPSByYXdDcmVkZW50aWFscztcbiAgdGhpcy5kb21haW5fID0gcmF3RG9tYWluO1xuICB0aGlzLnBvcnRfID0gcG9ydDtcbiAgdGhpcy5wYXRoXyA9IHJhd1BhdGg7XG4gIHRoaXMucXVlcnlfID0gcmF3UXVlcnk7XG4gIHRoaXMuZnJhZ21lbnRfID0gcmF3RnJhZ21lbnQ7XG4gIC8qKlxuICAgKiBAdHlwZSB7QXJyYXl8bnVsbH1cbiAgICovXG4gIHRoaXMucGFyYW1DYWNoZV8gPSBudWxsO1xufVxuXG4vKiogcmV0dXJucyB0aGUgc3RyaW5nIGZvcm0gb2YgdGhlIHVybC4gKi9cblVSSS5wcm90b3R5cGUudG9TdHJpbmcgPSBmdW5jdGlvbiAoKSB7XG4gIHZhciBvdXQgPSBbXTtcbiAgaWYgKG51bGwgIT09IHRoaXMuc2NoZW1lXykgeyBvdXQucHVzaCh0aGlzLnNjaGVtZV8sICc6Jyk7IH1cbiAgaWYgKG51bGwgIT09IHRoaXMuZG9tYWluXykge1xuICAgIG91dC5wdXNoKCcvLycpO1xuICAgIGlmIChudWxsICE9PSB0aGlzLmNyZWRlbnRpYWxzXykgeyBvdXQucHVzaCh0aGlzLmNyZWRlbnRpYWxzXywgJ0AnKTsgfVxuICAgIG91dC5wdXNoKHRoaXMuZG9tYWluXyk7XG4gICAgaWYgKG51bGwgIT09IHRoaXMucG9ydF8pIHsgb3V0LnB1c2goJzonLCB0aGlzLnBvcnRfLnRvU3RyaW5nKCkpOyB9XG4gIH1cbiAgaWYgKG51bGwgIT09IHRoaXMucGF0aF8pIHsgb3V0LnB1c2godGhpcy5wYXRoXyk7IH1cbiAgaWYgKG51bGwgIT09IHRoaXMucXVlcnlfKSB7IG91dC5wdXNoKCc/JywgdGhpcy5xdWVyeV8pOyB9XG4gIGlmIChudWxsICE9PSB0aGlzLmZyYWdtZW50XykgeyBvdXQucHVzaCgnIycsIHRoaXMuZnJhZ21lbnRfKTsgfVxuICByZXR1cm4gb3V0LmpvaW4oJycpO1xufTtcblxuVVJJLnByb3RvdHlwZS5jbG9uZSA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIG5ldyBVUkkodGhpcy5zY2hlbWVfLCB0aGlzLmNyZWRlbnRpYWxzXywgdGhpcy5kb21haW5fLCB0aGlzLnBvcnRfLFxuICAgICAgICAgICAgICAgICB0aGlzLnBhdGhfLCB0aGlzLnF1ZXJ5XywgdGhpcy5mcmFnbWVudF8pO1xufTtcblxuVVJJLnByb3RvdHlwZS5nZXRTY2hlbWUgPSBmdW5jdGlvbiAoKSB7XG4gIC8vIEhUTUw1IHNwZWMgZG9lcyBub3QgcmVxdWlyZSB0aGUgc2NoZW1lIHRvIGJlIGxvd2VyY2FzZWQgYnV0XG4gIC8vIGFsbCBjb21tb24gYnJvd3NlcnMgZXhjZXB0IFNhZmFyaSBsb3dlcmNhc2UgdGhlIHNjaGVtZS5cbiAgcmV0dXJuIHRoaXMuc2NoZW1lXyAmJiBkZWNvZGVVUklDb21wb25lbnQodGhpcy5zY2hlbWVfKS50b0xvd2VyQ2FzZSgpO1xufTtcblVSSS5wcm90b3R5cGUuZ2V0UmF3U2NoZW1lID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy5zY2hlbWVfO1xufTtcblVSSS5wcm90b3R5cGUuc2V0U2NoZW1lID0gZnVuY3Rpb24gKG5ld1NjaGVtZSkge1xuICB0aGlzLnNjaGVtZV8gPSBlbmNvZGVJZkV4aXN0czIoXG4gICAgICBuZXdTY2hlbWUsIFVSSV9ESVNBTExPV0VEX0lOX1NDSEVNRV9PUl9DUkVERU5USUFMU18pO1xuICByZXR1cm4gdGhpcztcbn07XG5VUkkucHJvdG90eXBlLnNldFJhd1NjaGVtZSA9IGZ1bmN0aW9uIChuZXdTY2hlbWUpIHtcbiAgdGhpcy5zY2hlbWVfID0gbmV3U2NoZW1lID8gbmV3U2NoZW1lIDogbnVsbDtcbiAgcmV0dXJuIHRoaXM7XG59O1xuVVJJLnByb3RvdHlwZS5oYXNTY2hlbWUgPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiBudWxsICE9PSB0aGlzLnNjaGVtZV87XG59O1xuXG5cblVSSS5wcm90b3R5cGUuZ2V0Q3JlZGVudGlhbHMgPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiB0aGlzLmNyZWRlbnRpYWxzXyAmJiBkZWNvZGVVUklDb21wb25lbnQodGhpcy5jcmVkZW50aWFsc18pO1xufTtcblVSSS5wcm90b3R5cGUuZ2V0UmF3Q3JlZGVudGlhbHMgPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiB0aGlzLmNyZWRlbnRpYWxzXztcbn07XG5VUkkucHJvdG90eXBlLnNldENyZWRlbnRpYWxzID0gZnVuY3Rpb24gKG5ld0NyZWRlbnRpYWxzKSB7XG4gIHRoaXMuY3JlZGVudGlhbHNfID0gZW5jb2RlSWZFeGlzdHMyKFxuICAgICAgbmV3Q3JlZGVudGlhbHMsIFVSSV9ESVNBTExPV0VEX0lOX1NDSEVNRV9PUl9DUkVERU5USUFMU18pO1xuXG4gIHJldHVybiB0aGlzO1xufTtcblVSSS5wcm90b3R5cGUuc2V0UmF3Q3JlZGVudGlhbHMgPSBmdW5jdGlvbiAobmV3Q3JlZGVudGlhbHMpIHtcbiAgdGhpcy5jcmVkZW50aWFsc18gPSBuZXdDcmVkZW50aWFscyA/IG5ld0NyZWRlbnRpYWxzIDogbnVsbDtcbiAgcmV0dXJuIHRoaXM7XG59O1xuVVJJLnByb3RvdHlwZS5oYXNDcmVkZW50aWFscyA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIG51bGwgIT09IHRoaXMuY3JlZGVudGlhbHNfO1xufTtcblxuXG5VUkkucHJvdG90eXBlLmdldERvbWFpbiA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIHRoaXMuZG9tYWluXyAmJiBkZWNvZGVVUklDb21wb25lbnQodGhpcy5kb21haW5fKTtcbn07XG5VUkkucHJvdG90eXBlLmdldFJhd0RvbWFpbiA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIHRoaXMuZG9tYWluXztcbn07XG5VUkkucHJvdG90eXBlLnNldERvbWFpbiA9IGZ1bmN0aW9uIChuZXdEb21haW4pIHtcbiAgcmV0dXJuIHRoaXMuc2V0UmF3RG9tYWluKG5ld0RvbWFpbiAmJiBlbmNvZGVVUklDb21wb25lbnQobmV3RG9tYWluKSk7XG59O1xuVVJJLnByb3RvdHlwZS5zZXRSYXdEb21haW4gPSBmdW5jdGlvbiAobmV3RG9tYWluKSB7XG4gIHRoaXMuZG9tYWluXyA9IG5ld0RvbWFpbiA/IG5ld0RvbWFpbiA6IG51bGw7XG4gIC8vIE1haW50YWluIHRoZSBpbnZhcmlhbnQgdGhhdCBwYXRocyBtdXN0IHN0YXJ0IHdpdGggYSBzbGFzaCB3aGVuIHRoZSBVUklcbiAgLy8gaXMgbm90IHBhdGgtcmVsYXRpdmUuXG4gIHJldHVybiB0aGlzLnNldFJhd1BhdGgodGhpcy5wYXRoXyk7XG59O1xuVVJJLnByb3RvdHlwZS5oYXNEb21haW4gPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiBudWxsICE9PSB0aGlzLmRvbWFpbl87XG59O1xuXG5cblVSSS5wcm90b3R5cGUuZ2V0UG9ydCA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIHRoaXMucG9ydF8gJiYgZGVjb2RlVVJJQ29tcG9uZW50KHRoaXMucG9ydF8pO1xufTtcblVSSS5wcm90b3R5cGUuc2V0UG9ydCA9IGZ1bmN0aW9uIChuZXdQb3J0KSB7XG4gIGlmIChuZXdQb3J0KSB7XG4gICAgbmV3UG9ydCA9IE51bWJlcihuZXdQb3J0KTtcbiAgICBpZiAobmV3UG9ydCAhPT0gKG5ld1BvcnQgJiAweGZmZmYpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoJ0JhZCBwb3J0IG51bWJlciAnICsgbmV3UG9ydCk7XG4gICAgfVxuICAgIHRoaXMucG9ydF8gPSAnJyArIG5ld1BvcnQ7XG4gIH0gZWxzZSB7XG4gICAgdGhpcy5wb3J0XyA9IG51bGw7XG4gIH1cbiAgcmV0dXJuIHRoaXM7XG59O1xuVVJJLnByb3RvdHlwZS5oYXNQb3J0ID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gbnVsbCAhPT0gdGhpcy5wb3J0Xztcbn07XG5cblxuVVJJLnByb3RvdHlwZS5nZXRQYXRoID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy5wYXRoXyAmJiBkZWNvZGVVUklDb21wb25lbnQodGhpcy5wYXRoXyk7XG59O1xuVVJJLnByb3RvdHlwZS5nZXRSYXdQYXRoID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy5wYXRoXztcbn07XG5VUkkucHJvdG90eXBlLnNldFBhdGggPSBmdW5jdGlvbiAobmV3UGF0aCkge1xuICByZXR1cm4gdGhpcy5zZXRSYXdQYXRoKGVuY29kZUlmRXhpc3RzMihuZXdQYXRoLCBVUklfRElTQUxMT1dFRF9JTl9QQVRIXykpO1xufTtcblVSSS5wcm90b3R5cGUuc2V0UmF3UGF0aCA9IGZ1bmN0aW9uIChuZXdQYXRoKSB7XG4gIGlmIChuZXdQYXRoKSB7XG4gICAgbmV3UGF0aCA9IFN0cmluZyhuZXdQYXRoKTtcbiAgICB0aGlzLnBhdGhfID0gXG4gICAgICAvLyBQYXRocyBtdXN0IHN0YXJ0IHdpdGggJy8nIHVubGVzcyB0aGlzIGlzIGEgcGF0aC1yZWxhdGl2ZSBVUkwuXG4gICAgICAoIXRoaXMuZG9tYWluXyB8fCAvXlxcLy8udGVzdChuZXdQYXRoKSkgPyBuZXdQYXRoIDogJy8nICsgbmV3UGF0aDtcbiAgfSBlbHNlIHtcbiAgICB0aGlzLnBhdGhfID0gbnVsbDtcbiAgfVxuICByZXR1cm4gdGhpcztcbn07XG5VUkkucHJvdG90eXBlLmhhc1BhdGggPSBmdW5jdGlvbiAoKSB7XG4gIHJldHVybiBudWxsICE9PSB0aGlzLnBhdGhfO1xufTtcblxuXG5VUkkucHJvdG90eXBlLmdldFF1ZXJ5ID0gZnVuY3Rpb24gKCkge1xuICAvLyBGcm9tIGh0dHA6Ly93d3cudzMub3JnL0FkZHJlc3NpbmcvVVJMLzRfVVJJX1JlY29tbWVudGF0aW9ucy5odG1sXG4gIC8vIFdpdGhpbiB0aGUgcXVlcnkgc3RyaW5nLCB0aGUgcGx1cyBzaWduIGlzIHJlc2VydmVkIGFzIHNob3J0aGFuZCBub3RhdGlvblxuICAvLyBmb3IgYSBzcGFjZS5cbiAgcmV0dXJuIHRoaXMucXVlcnlfICYmIGRlY29kZVVSSUNvbXBvbmVudCh0aGlzLnF1ZXJ5XykucmVwbGFjZSgvXFwrL2csICcgJyk7XG59O1xuVVJJLnByb3RvdHlwZS5nZXRSYXdRdWVyeSA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIHRoaXMucXVlcnlfO1xufTtcblVSSS5wcm90b3R5cGUuc2V0UXVlcnkgPSBmdW5jdGlvbiAobmV3UXVlcnkpIHtcbiAgdGhpcy5wYXJhbUNhY2hlXyA9IG51bGw7XG4gIHRoaXMucXVlcnlfID0gZW5jb2RlSWZFeGlzdHMobmV3UXVlcnkpO1xuICByZXR1cm4gdGhpcztcbn07XG5VUkkucHJvdG90eXBlLnNldFJhd1F1ZXJ5ID0gZnVuY3Rpb24gKG5ld1F1ZXJ5KSB7XG4gIHRoaXMucGFyYW1DYWNoZV8gPSBudWxsO1xuICB0aGlzLnF1ZXJ5XyA9IG5ld1F1ZXJ5ID8gbmV3UXVlcnkgOiBudWxsO1xuICByZXR1cm4gdGhpcztcbn07XG5VUkkucHJvdG90eXBlLmhhc1F1ZXJ5ID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gbnVsbCAhPT0gdGhpcy5xdWVyeV87XG59O1xuXG4vKipcbiAqIHNldHMgdGhlIHF1ZXJ5IGdpdmVuIGEgbGlzdCBvZiBzdHJpbmdzIG9mIHRoZSBmb3JtXG4gKiBbIGtleTAsIHZhbHVlMCwga2V5MSwgdmFsdWUxLCAuLi4gXS5cbiAqXG4gKiA8cD48Y29kZT51cmkuc2V0QWxsUGFyYW1ldGVycyhbJ2EnLCAnYicsICdjJywgJ2QnXSkuZ2V0UXVlcnkoKTwvY29kZT5cbiAqIHdpbGwgeWllbGQgPGNvZGU+J2E9YiZjPWQnPC9jb2RlPi5cbiAqL1xuVVJJLnByb3RvdHlwZS5zZXRBbGxQYXJhbWV0ZXJzID0gZnVuY3Rpb24gKHBhcmFtcykge1xuICBpZiAodHlwZW9mIHBhcmFtcyA9PT0gJ29iamVjdCcpIHtcbiAgICBpZiAoIShwYXJhbXMgaW5zdGFuY2VvZiBBcnJheSlcbiAgICAgICAgJiYgKHBhcmFtcyBpbnN0YW5jZW9mIE9iamVjdFxuICAgICAgICAgICAgfHwgT2JqZWN0LnByb3RvdHlwZS50b1N0cmluZy5jYWxsKHBhcmFtcykgIT09ICdbb2JqZWN0IEFycmF5XScpKSB7XG4gICAgICB2YXIgbmV3UGFyYW1zID0gW107XG4gICAgICB2YXIgaSA9IC0xO1xuICAgICAgZm9yICh2YXIgayBpbiBwYXJhbXMpIHtcbiAgICAgICAgdmFyIHYgPSBwYXJhbXNba107XG4gICAgICAgIGlmICgnc3RyaW5nJyA9PT0gdHlwZW9mIHYpIHtcbiAgICAgICAgICBuZXdQYXJhbXNbKytpXSA9IGs7XG4gICAgICAgICAgbmV3UGFyYW1zWysraV0gPSB2O1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBwYXJhbXMgPSBuZXdQYXJhbXM7XG4gICAgfVxuICB9XG4gIHRoaXMucGFyYW1DYWNoZV8gPSBudWxsO1xuICB2YXIgcXVlcnlCdWYgPSBbXTtcbiAgdmFyIHNlcGFyYXRvciA9ICcnO1xuICBmb3IgKHZhciBqID0gMDsgaiA8IHBhcmFtcy5sZW5ndGg7KSB7XG4gICAgdmFyIGsgPSBwYXJhbXNbaisrXTtcbiAgICB2YXIgdiA9IHBhcmFtc1tqKytdO1xuICAgIHF1ZXJ5QnVmLnB1c2goc2VwYXJhdG9yLCBlbmNvZGVVUklDb21wb25lbnQoay50b1N0cmluZygpKSk7XG4gICAgc2VwYXJhdG9yID0gJyYnO1xuICAgIGlmICh2KSB7XG4gICAgICBxdWVyeUJ1Zi5wdXNoKCc9JywgZW5jb2RlVVJJQ29tcG9uZW50KHYudG9TdHJpbmcoKSkpO1xuICAgIH1cbiAgfVxuICB0aGlzLnF1ZXJ5XyA9IHF1ZXJ5QnVmLmpvaW4oJycpO1xuICByZXR1cm4gdGhpcztcbn07XG5VUkkucHJvdG90eXBlLmNoZWNrUGFyYW1ldGVyQ2FjaGVfID0gZnVuY3Rpb24gKCkge1xuICBpZiAoIXRoaXMucGFyYW1DYWNoZV8pIHtcbiAgICB2YXIgcSA9IHRoaXMucXVlcnlfO1xuICAgIGlmICghcSkge1xuICAgICAgdGhpcy5wYXJhbUNhY2hlXyA9IFtdO1xuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgY2dpUGFyYW1zID0gcS5zcGxpdCgvWyZcXD9dLyk7XG4gICAgICB2YXIgb3V0ID0gW107XG4gICAgICB2YXIgayA9IC0xO1xuICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjZ2lQYXJhbXMubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgdmFyIG0gPSBjZ2lQYXJhbXNbaV0ubWF0Y2goL14oW149XSopKD86PSguKikpPyQvKTtcbiAgICAgICAgLy8gRnJvbSBodHRwOi8vd3d3LnczLm9yZy9BZGRyZXNzaW5nL1VSTC80X1VSSV9SZWNvbW1lbnRhdGlvbnMuaHRtbFxuICAgICAgICAvLyBXaXRoaW4gdGhlIHF1ZXJ5IHN0cmluZywgdGhlIHBsdXMgc2lnbiBpcyByZXNlcnZlZCBhcyBzaG9ydGhhbmRcbiAgICAgICAgLy8gbm90YXRpb24gZm9yIGEgc3BhY2UuXG4gICAgICAgIG91dFsrK2tdID0gZGVjb2RlVVJJQ29tcG9uZW50KG1bMV0pLnJlcGxhY2UoL1xcKy9nLCAnICcpO1xuICAgICAgICBvdXRbKytrXSA9IGRlY29kZVVSSUNvbXBvbmVudChtWzJdIHx8ICcnKS5yZXBsYWNlKC9cXCsvZywgJyAnKTtcbiAgICAgIH1cbiAgICAgIHRoaXMucGFyYW1DYWNoZV8gPSBvdXQ7XG4gICAgfVxuICB9XG59O1xuLyoqXG4gKiBzZXRzIHRoZSB2YWx1ZXMgb2YgdGhlIG5hbWVkIGNnaSBwYXJhbWV0ZXJzLlxuICpcbiAqIDxwPlNvLCA8Y29kZT51cmkucGFyc2UoJ2Zvbz9hPWImYz1kJmU9ZicpLnNldFBhcmFtZXRlclZhbHVlcygnYycsIFsnbmV3J10pXG4gKiA8L2NvZGU+IHlpZWxkcyA8dHQ+Zm9vP2E9YiZjPW5ldyZlPWY8L3R0Pi48L3A+XG4gKlxuICogQHBhcmFtIGtleSB7c3RyaW5nfVxuICogQHBhcmFtIHZhbHVlcyB7QXJyYXkuPHN0cmluZz59IHRoZSBuZXcgdmFsdWVzLiAgSWYgdmFsdWVzIGlzIGEgc2luZ2xlIHN0cmluZ1xuICogICB0aGVuIGl0IHdpbGwgYmUgdHJlYXRlZCBhcyB0aGUgc29sZSB2YWx1ZS5cbiAqL1xuVVJJLnByb3RvdHlwZS5zZXRQYXJhbWV0ZXJWYWx1ZXMgPSBmdW5jdGlvbiAoa2V5LCB2YWx1ZXMpIHtcbiAgLy8gYmUgbmljZSBhbmQgYXZvaWQgc3VidGxlIGJ1Z3Mgd2hlcmUgW10gb3BlcmF0b3Igb24gc3RyaW5nIHBlcmZvcm1zIGNoYXJBdFxuICAvLyBvbiBzb21lIGJyb3dzZXJzIGFuZCBjcmFzaGVzIG9uIElFXG4gIGlmICh0eXBlb2YgdmFsdWVzID09PSAnc3RyaW5nJykge1xuICAgIHZhbHVlcyA9IFsgdmFsdWVzIF07XG4gIH1cblxuICB0aGlzLmNoZWNrUGFyYW1ldGVyQ2FjaGVfKCk7XG4gIHZhciBuZXdWYWx1ZUluZGV4ID0gMDtcbiAgdmFyIHBjID0gdGhpcy5wYXJhbUNhY2hlXztcbiAgdmFyIHBhcmFtcyA9IFtdO1xuICBmb3IgKHZhciBpID0gMCwgayA9IDA7IGkgPCBwYy5sZW5ndGg7IGkgKz0gMikge1xuICAgIGlmIChrZXkgPT09IHBjW2ldKSB7XG4gICAgICBpZiAobmV3VmFsdWVJbmRleCA8IHZhbHVlcy5sZW5ndGgpIHtcbiAgICAgICAgcGFyYW1zLnB1c2goa2V5LCB2YWx1ZXNbbmV3VmFsdWVJbmRleCsrXSk7XG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIHBhcmFtcy5wdXNoKHBjW2ldLCBwY1tpICsgMV0pO1xuICAgIH1cbiAgfVxuICB3aGlsZSAobmV3VmFsdWVJbmRleCA8IHZhbHVlcy5sZW5ndGgpIHtcbiAgICBwYXJhbXMucHVzaChrZXksIHZhbHVlc1tuZXdWYWx1ZUluZGV4KytdKTtcbiAgfVxuICB0aGlzLnNldEFsbFBhcmFtZXRlcnMocGFyYW1zKTtcbiAgcmV0dXJuIHRoaXM7XG59O1xuVVJJLnByb3RvdHlwZS5yZW1vdmVQYXJhbWV0ZXIgPSBmdW5jdGlvbiAoa2V5KSB7XG4gIHJldHVybiB0aGlzLnNldFBhcmFtZXRlclZhbHVlcyhrZXksIFtdKTtcbn07XG4vKipcbiAqIHJldHVybnMgdGhlIHBhcmFtZXRlcnMgc3BlY2lmaWVkIGluIHRoZSBxdWVyeSBwYXJ0IG9mIHRoZSB1cmkgYXMgYSBsaXN0IG9mXG4gKiBrZXlzIGFuZCB2YWx1ZXMgbGlrZSBbIGtleTAsIHZhbHVlMCwga2V5MSwgdmFsdWUxLCAuLi4gXS5cbiAqXG4gKiBAcmV0dXJuIHtBcnJheS48c3RyaW5nPn1cbiAqL1xuVVJJLnByb3RvdHlwZS5nZXRBbGxQYXJhbWV0ZXJzID0gZnVuY3Rpb24gKCkge1xuICB0aGlzLmNoZWNrUGFyYW1ldGVyQ2FjaGVfKCk7XG4gIHJldHVybiB0aGlzLnBhcmFtQ2FjaGVfLnNsaWNlKDAsIHRoaXMucGFyYW1DYWNoZV8ubGVuZ3RoKTtcbn07XG4vKipcbiAqIHJldHVybnMgdGhlIHZhbHVlPGI+czwvYj4gZm9yIGEgZ2l2ZW4gY2dpIHBhcmFtZXRlciBhcyBhIGxpc3Qgb2YgZGVjb2RlZFxuICogcXVlcnkgcGFyYW1ldGVyIHZhbHVlcy5cbiAqIEByZXR1cm4ge0FycmF5LjxzdHJpbmc+fVxuICovXG5VUkkucHJvdG90eXBlLmdldFBhcmFtZXRlclZhbHVlcyA9IGZ1bmN0aW9uIChwYXJhbU5hbWVVbmVzY2FwZWQpIHtcbiAgdGhpcy5jaGVja1BhcmFtZXRlckNhY2hlXygpO1xuICB2YXIgdmFsdWVzID0gW107XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5wYXJhbUNhY2hlXy5sZW5ndGg7IGkgKz0gMikge1xuICAgIGlmIChwYXJhbU5hbWVVbmVzY2FwZWQgPT09IHRoaXMucGFyYW1DYWNoZV9baV0pIHtcbiAgICAgIHZhbHVlcy5wdXNoKHRoaXMucGFyYW1DYWNoZV9baSArIDFdKTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIHZhbHVlcztcbn07XG4vKipcbiAqIHJldHVybnMgYSBtYXAgb2YgY2dpIHBhcmFtZXRlciBuYW1lcyB0byAobm9uLWVtcHR5KSBsaXN0cyBvZiB2YWx1ZXMuXG4gKiBAcmV0dXJuIHtPYmplY3QuPHN0cmluZyxBcnJheS48c3RyaW5nPj59XG4gKi9cblVSSS5wcm90b3R5cGUuZ2V0UGFyYW1ldGVyTWFwID0gZnVuY3Rpb24gKHBhcmFtTmFtZVVuZXNjYXBlZCkge1xuICB0aGlzLmNoZWNrUGFyYW1ldGVyQ2FjaGVfKCk7XG4gIHZhciBwYXJhbU1hcCA9IHt9O1xuICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMucGFyYW1DYWNoZV8ubGVuZ3RoOyBpICs9IDIpIHtcbiAgICB2YXIga2V5ID0gdGhpcy5wYXJhbUNhY2hlX1tpKytdLFxuICAgICAgdmFsdWUgPSB0aGlzLnBhcmFtQ2FjaGVfW2krK107XG4gICAgaWYgKCEoa2V5IGluIHBhcmFtTWFwKSkge1xuICAgICAgcGFyYW1NYXBba2V5XSA9IFt2YWx1ZV07XG4gICAgfSBlbHNlIHtcbiAgICAgIHBhcmFtTWFwW2tleV0ucHVzaCh2YWx1ZSk7XG4gICAgfVxuICB9XG4gIHJldHVybiBwYXJhbU1hcDtcbn07XG4vKipcbiAqIHJldHVybnMgdGhlIGZpcnN0IHZhbHVlIGZvciBhIGdpdmVuIGNnaSBwYXJhbWV0ZXIgb3IgbnVsbCBpZiB0aGUgZ2l2ZW5cbiAqIHBhcmFtZXRlciBuYW1lIGRvZXMgbm90IGFwcGVhciBpbiB0aGUgcXVlcnkgc3RyaW5nLlxuICogSWYgdGhlIGdpdmVuIHBhcmFtZXRlciBuYW1lIGRvZXMgYXBwZWFyLCBidXQgaGFzIG5vICc8dHQ+PTwvdHQ+JyBmb2xsb3dpbmdcbiAqIGl0LCB0aGVuIHRoZSBlbXB0eSBzdHJpbmcgd2lsbCBiZSByZXR1cm5lZC5cbiAqIEByZXR1cm4ge3N0cmluZ3xudWxsfVxuICovXG5VUkkucHJvdG90eXBlLmdldFBhcmFtZXRlclZhbHVlID0gZnVuY3Rpb24gKHBhcmFtTmFtZVVuZXNjYXBlZCkge1xuICB0aGlzLmNoZWNrUGFyYW1ldGVyQ2FjaGVfKCk7XG4gIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5wYXJhbUNhY2hlXy5sZW5ndGg7IGkgKz0gMikge1xuICAgIGlmIChwYXJhbU5hbWVVbmVzY2FwZWQgPT09IHRoaXMucGFyYW1DYWNoZV9baV0pIHtcbiAgICAgIHJldHVybiB0aGlzLnBhcmFtQ2FjaGVfW2kgKyAxXTtcbiAgICB9XG4gIH1cbiAgcmV0dXJuIG51bGw7XG59O1xuXG5VUkkucHJvdG90eXBlLmdldEZyYWdtZW50ID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy5mcmFnbWVudF8gJiYgZGVjb2RlVVJJQ29tcG9uZW50KHRoaXMuZnJhZ21lbnRfKTtcbn07XG5VUkkucHJvdG90eXBlLmdldFJhd0ZyYWdtZW50ID0gZnVuY3Rpb24gKCkge1xuICByZXR1cm4gdGhpcy5mcmFnbWVudF87XG59O1xuVVJJLnByb3RvdHlwZS5zZXRGcmFnbWVudCA9IGZ1bmN0aW9uIChuZXdGcmFnbWVudCkge1xuICB0aGlzLmZyYWdtZW50XyA9IG5ld0ZyYWdtZW50ID8gZW5jb2RlVVJJQ29tcG9uZW50KG5ld0ZyYWdtZW50KSA6IG51bGw7XG4gIHJldHVybiB0aGlzO1xufTtcblVSSS5wcm90b3R5cGUuc2V0UmF3RnJhZ21lbnQgPSBmdW5jdGlvbiAobmV3RnJhZ21lbnQpIHtcbiAgdGhpcy5mcmFnbWVudF8gPSBuZXdGcmFnbWVudCA/IG5ld0ZyYWdtZW50IDogbnVsbDtcbiAgcmV0dXJuIHRoaXM7XG59O1xuVVJJLnByb3RvdHlwZS5oYXNGcmFnbWVudCA9IGZ1bmN0aW9uICgpIHtcbiAgcmV0dXJuIG51bGwgIT09IHRoaXMuZnJhZ21lbnRfO1xufTtcblxuZnVuY3Rpb24gbnVsbElmQWJzZW50KG1hdGNoUGFydCkge1xuICByZXR1cm4gKCdzdHJpbmcnID09IHR5cGVvZiBtYXRjaFBhcnQpICYmIChtYXRjaFBhcnQubGVuZ3RoID4gMClcbiAgICAgICAgID8gbWF0Y2hQYXJ0XG4gICAgICAgICA6IG51bGw7XG59XG5cblxuXG5cbi8qKlxuICogYSByZWd1bGFyIGV4cHJlc3Npb24gZm9yIGJyZWFraW5nIGEgVVJJIGludG8gaXRzIGNvbXBvbmVudCBwYXJ0cy5cbiAqXG4gKiA8cD5odHRwOi8vd3d3LmdiaXYuY29tL3Byb3RvY29scy91cmkvcmZjL3JmYzM5ODYuaHRtbCNSRkMyMjM0IHNheXNcbiAqIEFzIHRoZSBcImZpcnN0LW1hdGNoLXdpbnNcIiBhbGdvcml0aG0gaXMgaWRlbnRpY2FsIHRvIHRoZSBcImdyZWVkeVwiXG4gKiBkaXNhbWJpZ3VhdGlvbiBtZXRob2QgdXNlZCBieSBQT1NJWCByZWd1bGFyIGV4cHJlc3Npb25zLCBpdCBpcyBuYXR1cmFsIGFuZFxuICogY29tbW9ucGxhY2UgdG8gdXNlIGEgcmVndWxhciBleHByZXNzaW9uIGZvciBwYXJzaW5nIHRoZSBwb3RlbnRpYWwgZml2ZVxuICogY29tcG9uZW50cyBvZiBhIFVSSSByZWZlcmVuY2UuXG4gKlxuICogPHA+VGhlIGZvbGxvd2luZyBsaW5lIGlzIHRoZSByZWd1bGFyIGV4cHJlc3Npb24gZm9yIGJyZWFraW5nLWRvd24gYVxuICogd2VsbC1mb3JtZWQgVVJJIHJlZmVyZW5jZSBpbnRvIGl0cyBjb21wb25lbnRzLlxuICpcbiAqIDxwcmU+XG4gKiBeKChbXjovPyNdKyk6KT8oLy8oW14vPyNdKikpPyhbXj8jXSopKFxcPyhbXiNdKikpPygjKC4qKSk/XG4gKiAgMTIgICAgICAgICAgICAzICA0ICAgICAgICAgIDUgICAgICAgNiAgNyAgICAgICAgOCA5XG4gKiA8L3ByZT5cbiAqXG4gKiA8cD5UaGUgbnVtYmVycyBpbiB0aGUgc2Vjb25kIGxpbmUgYWJvdmUgYXJlIG9ubHkgdG8gYXNzaXN0IHJlYWRhYmlsaXR5OyB0aGV5XG4gKiBpbmRpY2F0ZSB0aGUgcmVmZXJlbmNlIHBvaW50cyBmb3IgZWFjaCBzdWJleHByZXNzaW9uIChpLmUuLCBlYWNoIHBhaXJlZFxuICogcGFyZW50aGVzaXMpLiBXZSByZWZlciB0byB0aGUgdmFsdWUgbWF0Y2hlZCBmb3Igc3ViZXhwcmVzc2lvbiA8bj4gYXMgJDxuPi5cbiAqIEZvciBleGFtcGxlLCBtYXRjaGluZyB0aGUgYWJvdmUgZXhwcmVzc2lvbiB0b1xuICogPHByZT5cbiAqICAgICBodHRwOi8vd3d3Lmljcy51Y2kuZWR1L3B1Yi9pZXRmL3VyaS8jUmVsYXRlZFxuICogPC9wcmU+XG4gKiByZXN1bHRzIGluIHRoZSBmb2xsb3dpbmcgc3ViZXhwcmVzc2lvbiBtYXRjaGVzOlxuICogPHByZT5cbiAqICAgICQxID0gaHR0cDpcbiAqICAgICQyID0gaHR0cFxuICogICAgJDMgPSAvL3d3dy5pY3MudWNpLmVkdVxuICogICAgJDQgPSB3d3cuaWNzLnVjaS5lZHVcbiAqICAgICQ1ID0gL3B1Yi9pZXRmL3VyaS9cbiAqICAgICQ2ID0gPHVuZGVmaW5lZD5cbiAqICAgICQ3ID0gPHVuZGVmaW5lZD5cbiAqICAgICQ4ID0gI1JlbGF0ZWRcbiAqICAgICQ5ID0gUmVsYXRlZFxuICogPC9wcmU+XG4gKiB3aGVyZSA8dW5kZWZpbmVkPiBpbmRpY2F0ZXMgdGhhdCB0aGUgY29tcG9uZW50IGlzIG5vdCBwcmVzZW50LCBhcyBpcyB0aGVcbiAqIGNhc2UgZm9yIHRoZSBxdWVyeSBjb21wb25lbnQgaW4gdGhlIGFib3ZlIGV4YW1wbGUuIFRoZXJlZm9yZSwgd2UgY2FuXG4gKiBkZXRlcm1pbmUgdGhlIHZhbHVlIG9mIHRoZSBmaXZlIGNvbXBvbmVudHMgYXNcbiAqIDxwcmU+XG4gKiAgICBzY2hlbWUgICAgPSAkMlxuICogICAgYXV0aG9yaXR5ID0gJDRcbiAqICAgIHBhdGggICAgICA9ICQ1XG4gKiAgICBxdWVyeSAgICAgPSAkN1xuICogICAgZnJhZ21lbnQgID0gJDlcbiAqIDwvcHJlPlxuICpcbiAqIDxwPm1zYW11ZWw6IEkgaGF2ZSBtb2RpZmllZCB0aGUgcmVndWxhciBleHByZXNzaW9uIHNsaWdodGx5IHRvIGV4cG9zZSB0aGVcbiAqIGNyZWRlbnRpYWxzLCBkb21haW4sIGFuZCBwb3J0IHNlcGFyYXRlbHkgZnJvbSB0aGUgYXV0aG9yaXR5LlxuICogVGhlIG1vZGlmaWVkIHZlcnNpb24geWllbGRzXG4gKiA8cHJlPlxuICogICAgJDEgPSBodHRwICAgICAgICAgICAgICBzY2hlbWVcbiAqICAgICQyID0gPHVuZGVmaW5lZD4gICAgICAgY3JlZGVudGlhbHMgLVxcXG4gKiAgICAkMyA9IHd3dy5pY3MudWNpLmVkdSAgIGRvbWFpbiAgICAgICB8IGF1dGhvcml0eVxuICogICAgJDQgPSA8dW5kZWZpbmVkPiAgICAgICBwb3J0ICAgICAgICAtL1xuICogICAgJDUgPSAvcHViL2lldGYvdXJpLyAgICBwYXRoXG4gKiAgICAkNiA9IDx1bmRlZmluZWQ+ICAgICAgIHF1ZXJ5IHdpdGhvdXQgP1xuICogICAgJDcgPSBSZWxhdGVkICAgICAgICAgICBmcmFnbWVudCB3aXRob3V0ICNcbiAqIDwvcHJlPlxuICovXG52YXIgVVJJX1JFXyA9IG5ldyBSZWdFeHAoXG4gICAgICBcIl5cIiArXG4gICAgICBcIig/OlwiICtcbiAgICAgICAgXCIoW146Lz8jXSspXCIgKyAgICAgICAgIC8vIHNjaGVtZVxuICAgICAgXCI6KT9cIiArXG4gICAgICBcIig/Oi8vXCIgK1xuICAgICAgICBcIig/OihbXi8/I10qKUApP1wiICsgICAgLy8gY3JlZGVudGlhbHNcbiAgICAgICAgXCIoW14vPyM6QF0qKVwiICsgICAgICAgIC8vIGRvbWFpblxuICAgICAgICBcIig/OjooWzAtOV0rKSk/XCIgKyAgICAgLy8gcG9ydFxuICAgICAgXCIpP1wiICtcbiAgICAgIFwiKFtePyNdKyk/XCIgKyAgICAgICAgICAgIC8vIHBhdGhcbiAgICAgIFwiKD86XFxcXD8oW14jXSopKT9cIiArICAgICAgLy8gcXVlcnlcbiAgICAgIFwiKD86IyguKikpP1wiICsgICAgICAgICAgIC8vIGZyYWdtZW50XG4gICAgICBcIiRcIlxuICAgICAgKTtcblxudmFyIFVSSV9ESVNBTExPV0VEX0lOX1NDSEVNRV9PUl9DUkVERU5USUFMU18gPSAvWyNcXC9cXD9AXS9nO1xudmFyIFVSSV9ESVNBTExPV0VEX0lOX1BBVEhfID0gL1tcXCNcXD9dL2c7XG5cblVSSS5wYXJzZSA9IHBhcnNlO1xuVVJJLmNyZWF0ZSA9IGNyZWF0ZTtcblVSSS5yZXNvbHZlID0gcmVzb2x2ZTtcblVSSS5jb2xsYXBzZV9kb3RzID0gY29sbGFwc2VfZG90czsgIC8vIFZpc2libGUgZm9yIHRlc3RpbmcuXG5cbi8vIGxpZ2h0d2VpZ2h0IHN0cmluZy1iYXNlZCBhcGkgZm9yIGxvYWRNb2R1bGVNYWtlclxuVVJJLnV0aWxzID0ge1xuICBtaW1lVHlwZU9mOiBmdW5jdGlvbiAodXJpKSB7XG4gICAgdmFyIHVyaU9iaiA9IHBhcnNlKHVyaSk7XG4gICAgaWYgKC9cXC5odG1sJC8udGVzdCh1cmlPYmouZ2V0UGF0aCgpKSkge1xuICAgICAgcmV0dXJuICd0ZXh0L2h0bWwnO1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gJ2FwcGxpY2F0aW9uL2phdmFzY3JpcHQnO1xuICAgIH1cbiAgfSxcbiAgcmVzb2x2ZTogZnVuY3Rpb24gKGJhc2UsIHVyaSkge1xuICAgIGlmIChiYXNlKSB7XG4gICAgICByZXR1cm4gcmVzb2x2ZShwYXJzZShiYXNlKSwgcGFyc2UodXJpKSkudG9TdHJpbmcoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuICcnICsgdXJpO1xuICAgIH1cbiAgfVxufTtcblxuXG5yZXR1cm4gVVJJO1xufSkoKTtcblxuLy8gQ29weXJpZ2h0IEdvb2dsZSBJbmMuXG4vLyBMaWNlbnNlZCB1bmRlciB0aGUgQXBhY2hlIExpY2VuY2UgVmVyc2lvbiAyLjBcbi8vIEF1dG9nZW5lcmF0ZWQgYXQgTW9uIEZlYiAyNSAxMzowNTo0MiBFU1QgMjAxM1xuLy8gQG92ZXJyaWRlcyB3aW5kb3dcbi8vIEBwcm92aWRlcyBodG1sNFxudmFyIGh0bWw0ID0ge307XG5odG1sNC5hdHlwZSA9IHtcbiAgJ05PTkUnOiAwLFxuICAnVVJJJzogMSxcbiAgJ1VSSV9GUkFHTUVOVCc6IDExLFxuICAnU0NSSVBUJzogMixcbiAgJ1NUWUxFJzogMyxcbiAgJ0hUTUwnOiAxMixcbiAgJ0lEJzogNCxcbiAgJ0lEUkVGJzogNSxcbiAgJ0lEUkVGUyc6IDYsXG4gICdHTE9CQUxfTkFNRSc6IDcsXG4gICdMT0NBTF9OQU1FJzogOCxcbiAgJ0NMQVNTRVMnOiA5LFxuICAnRlJBTUVfVEFSR0VUJzogMTAsXG4gICdNRURJQV9RVUVSWSc6IDEzXG59O1xuaHRtbDRbICdhdHlwZScgXSA9IGh0bWw0LmF0eXBlO1xuaHRtbDQuQVRUUklCUyA9IHtcbiAgJyo6OmNsYXNzJzogOSxcbiAgJyo6OmRpcic6IDAsXG4gICcqOjpkcmFnZ2FibGUnOiAwLFxuICAnKjo6aGlkZGVuJzogMCxcbiAgJyo6OmlkJzogNCxcbiAgJyo6OmluZXJ0JzogMCxcbiAgJyo6Oml0ZW1wcm9wJzogMCxcbiAgJyo6Oml0ZW1yZWYnOiA2LFxuICAnKjo6aXRlbXNjb3BlJzogMCxcbiAgJyo6OmxhbmcnOiAwLFxuICAnKjo6b25ibHVyJzogMixcbiAgJyo6Om9uY2hhbmdlJzogMixcbiAgJyo6Om9uY2xpY2snOiAyLFxuICAnKjo6b25kYmxjbGljayc6IDIsXG4gICcqOjpvbmZvY3VzJzogMixcbiAgJyo6Om9ua2V5ZG93bic6IDIsXG4gICcqOjpvbmtleXByZXNzJzogMixcbiAgJyo6Om9ua2V5dXAnOiAyLFxuICAnKjo6b25sb2FkJzogMixcbiAgJyo6Om9ubW91c2Vkb3duJzogMixcbiAgJyo6Om9ubW91c2Vtb3ZlJzogMixcbiAgJyo6Om9ubW91c2VvdXQnOiAyLFxuICAnKjo6b25tb3VzZW92ZXInOiAyLFxuICAnKjo6b25tb3VzZXVwJzogMixcbiAgJyo6Om9ucmVzZXQnOiAyLFxuICAnKjo6b25zY3JvbGwnOiAyLFxuICAnKjo6b25zZWxlY3QnOiAyLFxuICAnKjo6b25zdWJtaXQnOiAyLFxuICAnKjo6b251bmxvYWQnOiAyLFxuICAnKjo6c3BlbGxjaGVjayc6IDAsXG4gICcqOjpzdHlsZSc6IDMsXG4gICcqOjp0aXRsZSc6IDAsXG4gICcqOjp0cmFuc2xhdGUnOiAwLFxuICAnYTo6YWNjZXNza2V5JzogMCxcbiAgJ2E6OmNvb3Jkcyc6IDAsXG4gICdhOjpocmVmJzogMSxcbiAgJ2E6OmhyZWZsYW5nJzogMCxcbiAgJ2E6Om5hbWUnOiA3LFxuICAnYTo6b25ibHVyJzogMixcbiAgJ2E6Om9uZm9jdXMnOiAyLFxuICAnYTo6c2hhcGUnOiAwLFxuICAnYTo6dGFiaW5kZXgnOiAwLFxuICAnYTo6dGFyZ2V0JzogMTAsXG4gICdhOjp0eXBlJzogMCxcbiAgJ2FyZWE6OmFjY2Vzc2tleSc6IDAsXG4gICdhcmVhOjphbHQnOiAwLFxuICAnYXJlYTo6Y29vcmRzJzogMCxcbiAgJ2FyZWE6OmhyZWYnOiAxLFxuICAnYXJlYTo6bm9ocmVmJzogMCxcbiAgJ2FyZWE6Om9uYmx1cic6IDIsXG4gICdhcmVhOjpvbmZvY3VzJzogMixcbiAgJ2FyZWE6OnNoYXBlJzogMCxcbiAgJ2FyZWE6OnRhYmluZGV4JzogMCxcbiAgJ2FyZWE6OnRhcmdldCc6IDEwLFxuICAnYXVkaW86OmNvbnRyb2xzJzogMCxcbiAgJ2F1ZGlvOjpsb29wJzogMCxcbiAgJ2F1ZGlvOjptZWRpYWdyb3VwJzogNSxcbiAgJ2F1ZGlvOjptdXRlZCc6IDAsXG4gICdhdWRpbzo6cHJlbG9hZCc6IDAsXG4gICdiZG86OmRpcic6IDAsXG4gICdibG9ja3F1b3RlOjpjaXRlJzogMSxcbiAgJ2JyOjpjbGVhcic6IDAsXG4gICdidXR0b246OmFjY2Vzc2tleSc6IDAsXG4gICdidXR0b246OmRpc2FibGVkJzogMCxcbiAgJ2J1dHRvbjo6bmFtZSc6IDgsXG4gICdidXR0b246Om9uYmx1cic6IDIsXG4gICdidXR0b246Om9uZm9jdXMnOiAyLFxuICAnYnV0dG9uOjp0YWJpbmRleCc6IDAsXG4gICdidXR0b246OnR5cGUnOiAwLFxuICAnYnV0dG9uOjp2YWx1ZSc6IDAsXG4gICdjYW52YXM6OmhlaWdodCc6IDAsXG4gICdjYW52YXM6OndpZHRoJzogMCxcbiAgJ2NhcHRpb246OmFsaWduJzogMCxcbiAgJ2NvbDo6YWxpZ24nOiAwLFxuICAnY29sOjpjaGFyJzogMCxcbiAgJ2NvbDo6Y2hhcm9mZic6IDAsXG4gICdjb2w6OnNwYW4nOiAwLFxuICAnY29sOjp2YWxpZ24nOiAwLFxuICAnY29sOjp3aWR0aCc6IDAsXG4gICdjb2xncm91cDo6YWxpZ24nOiAwLFxuICAnY29sZ3JvdXA6OmNoYXInOiAwLFxuICAnY29sZ3JvdXA6OmNoYXJvZmYnOiAwLFxuICAnY29sZ3JvdXA6OnNwYW4nOiAwLFxuICAnY29sZ3JvdXA6OnZhbGlnbic6IDAsXG4gICdjb2xncm91cDo6d2lkdGgnOiAwLFxuICAnY29tbWFuZDo6Y2hlY2tlZCc6IDAsXG4gICdjb21tYW5kOjpjb21tYW5kJzogNSxcbiAgJ2NvbW1hbmQ6OmRpc2FibGVkJzogMCxcbiAgJ2NvbW1hbmQ6Omljb24nOiAxLFxuICAnY29tbWFuZDo6bGFiZWwnOiAwLFxuICAnY29tbWFuZDo6cmFkaW9ncm91cCc6IDAsXG4gICdjb21tYW5kOjp0eXBlJzogMCxcbiAgJ2RhdGE6OnZhbHVlJzogMCxcbiAgJ2RlbDo6Y2l0ZSc6IDEsXG4gICdkZWw6OmRhdGV0aW1lJzogMCxcbiAgJ2RldGFpbHM6Om9wZW4nOiAwLFxuICAnZGlyOjpjb21wYWN0JzogMCxcbiAgJ2Rpdjo6YWxpZ24nOiAwLFxuICAnZGw6OmNvbXBhY3QnOiAwLFxuICAnZmllbGRzZXQ6OmRpc2FibGVkJzogMCxcbiAgJ2ZvbnQ6OmNvbG9yJzogMCxcbiAgJ2ZvbnQ6OmZhY2UnOiAwLFxuICAnZm9udDo6c2l6ZSc6IDAsXG4gICdmb3JtOjphY2NlcHQnOiAwLFxuICAnZm9ybTo6YWN0aW9uJzogMSxcbiAgJ2Zvcm06OmF1dG9jb21wbGV0ZSc6IDAsXG4gICdmb3JtOjplbmN0eXBlJzogMCxcbiAgJ2Zvcm06Om1ldGhvZCc6IDAsXG4gICdmb3JtOjpuYW1lJzogNyxcbiAgJ2Zvcm06Om5vdmFsaWRhdGUnOiAwLFxuICAnZm9ybTo6b25yZXNldCc6IDIsXG4gICdmb3JtOjpvbnN1Ym1pdCc6IDIsXG4gICdmb3JtOjp0YXJnZXQnOiAxMCxcbiAgJ2gxOjphbGlnbic6IDAsXG4gICdoMjo6YWxpZ24nOiAwLFxuICAnaDM6OmFsaWduJzogMCxcbiAgJ2g0OjphbGlnbic6IDAsXG4gICdoNTo6YWxpZ24nOiAwLFxuICAnaDY6OmFsaWduJzogMCxcbiAgJ2hyOjphbGlnbic6IDAsXG4gICdocjo6bm9zaGFkZSc6IDAsXG4gICdocjo6c2l6ZSc6IDAsXG4gICdocjo6d2lkdGgnOiAwLFxuICAnaWZyYW1lOjphbGlnbic6IDAsXG4gICdpZnJhbWU6OmZyYW1lYm9yZGVyJzogMCxcbiAgJ2lmcmFtZTo6aGVpZ2h0JzogMCxcbiAgJ2lmcmFtZTo6bWFyZ2luaGVpZ2h0JzogMCxcbiAgJ2lmcmFtZTo6bWFyZ2lud2lkdGgnOiAwLFxuICAnaWZyYW1lOjp3aWR0aCc6IDAsXG4gICdpbWc6OmFsaWduJzogMCxcbiAgJ2ltZzo6YWx0JzogMCxcbiAgJ2ltZzo6Ym9yZGVyJzogMCxcbiAgJ2ltZzo6aGVpZ2h0JzogMCxcbiAgJ2ltZzo6aHNwYWNlJzogMCxcbiAgJ2ltZzo6aXNtYXAnOiAwLFxuICAnaW1nOjpuYW1lJzogNyxcbiAgJ2ltZzo6c3JjJzogMSxcbiAgJ2ltZzo6dXNlbWFwJzogMTEsXG4gICdpbWc6OnZzcGFjZSc6IDAsXG4gICdpbWc6OndpZHRoJzogMCxcbiAgJ2lucHV0OjphY2NlcHQnOiAwLFxuICAnaW5wdXQ6OmFjY2Vzc2tleSc6IDAsXG4gICdpbnB1dDo6YWxpZ24nOiAwLFxuICAnaW5wdXQ6OmFsdCc6IDAsXG4gICdpbnB1dDo6YXV0b2NvbXBsZXRlJzogMCxcbiAgJ2lucHV0OjpjaGVja2VkJzogMCxcbiAgJ2lucHV0OjpkaXNhYmxlZCc6IDAsXG4gICdpbnB1dDo6aW5wdXRtb2RlJzogMCxcbiAgJ2lucHV0Ojppc21hcCc6IDAsXG4gICdpbnB1dDo6bGlzdCc6IDUsXG4gICdpbnB1dDo6bWF4JzogMCxcbiAgJ2lucHV0OjptYXhsZW5ndGgnOiAwLFxuICAnaW5wdXQ6Om1pbic6IDAsXG4gICdpbnB1dDo6bXVsdGlwbGUnOiAwLFxuICAnaW5wdXQ6Om5hbWUnOiA4LFxuICAnaW5wdXQ6Om9uYmx1cic6IDIsXG4gICdpbnB1dDo6b25jaGFuZ2UnOiAyLFxuICAnaW5wdXQ6Om9uZm9jdXMnOiAyLFxuICAnaW5wdXQ6Om9uc2VsZWN0JzogMixcbiAgJ2lucHV0OjpwbGFjZWhvbGRlcic6IDAsXG4gICdpbnB1dDo6cmVhZG9ubHknOiAwLFxuICAnaW5wdXQ6OnJlcXVpcmVkJzogMCxcbiAgJ2lucHV0OjpzaXplJzogMCxcbiAgJ2lucHV0OjpzcmMnOiAxLFxuICAnaW5wdXQ6OnN0ZXAnOiAwLFxuICAnaW5wdXQ6OnRhYmluZGV4JzogMCxcbiAgJ2lucHV0Ojp0eXBlJzogMCxcbiAgJ2lucHV0Ojp1c2VtYXAnOiAxMSxcbiAgJ2lucHV0Ojp2YWx1ZSc6IDAsXG4gICdpbnM6OmNpdGUnOiAxLFxuICAnaW5zOjpkYXRldGltZSc6IDAsXG4gICdsYWJlbDo6YWNjZXNza2V5JzogMCxcbiAgJ2xhYmVsOjpmb3InOiA1LFxuICAnbGFiZWw6Om9uYmx1cic6IDIsXG4gICdsYWJlbDo6b25mb2N1cyc6IDIsXG4gICdsZWdlbmQ6OmFjY2Vzc2tleSc6IDAsXG4gICdsZWdlbmQ6OmFsaWduJzogMCxcbiAgJ2xpOjp0eXBlJzogMCxcbiAgJ2xpOjp2YWx1ZSc6IDAsXG4gICdtYXA6Om5hbWUnOiA3LFxuICAnbWVudTo6Y29tcGFjdCc6IDAsXG4gICdtZW51OjpsYWJlbCc6IDAsXG4gICdtZW51Ojp0eXBlJzogMCxcbiAgJ21ldGVyOjpoaWdoJzogMCxcbiAgJ21ldGVyOjpsb3cnOiAwLFxuICAnbWV0ZXI6Om1heCc6IDAsXG4gICdtZXRlcjo6bWluJzogMCxcbiAgJ21ldGVyOjp2YWx1ZSc6IDAsXG4gICdvbDo6Y29tcGFjdCc6IDAsXG4gICdvbDo6cmV2ZXJzZWQnOiAwLFxuICAnb2w6OnN0YXJ0JzogMCxcbiAgJ29sOjp0eXBlJzogMCxcbiAgJ29wdGdyb3VwOjpkaXNhYmxlZCc6IDAsXG4gICdvcHRncm91cDo6bGFiZWwnOiAwLFxuICAnb3B0aW9uOjpkaXNhYmxlZCc6IDAsXG4gICdvcHRpb246OmxhYmVsJzogMCxcbiAgJ29wdGlvbjo6c2VsZWN0ZWQnOiAwLFxuICAnb3B0aW9uOjp2YWx1ZSc6IDAsXG4gICdvdXRwdXQ6OmZvcic6IDYsXG4gICdvdXRwdXQ6Om5hbWUnOiA4LFxuICAncDo6YWxpZ24nOiAwLFxuICAncHJlOjp3aWR0aCc6IDAsXG4gICdwcm9ncmVzczo6bWF4JzogMCxcbiAgJ3Byb2dyZXNzOjptaW4nOiAwLFxuICAncHJvZ3Jlc3M6OnZhbHVlJzogMCxcbiAgJ3E6OmNpdGUnOiAxLFxuICAnc2VsZWN0OjphdXRvY29tcGxldGUnOiAwLFxuICAnc2VsZWN0OjpkaXNhYmxlZCc6IDAsXG4gICdzZWxlY3Q6Om11bHRpcGxlJzogMCxcbiAgJ3NlbGVjdDo6bmFtZSc6IDgsXG4gICdzZWxlY3Q6Om9uYmx1cic6IDIsXG4gICdzZWxlY3Q6Om9uY2hhbmdlJzogMixcbiAgJ3NlbGVjdDo6b25mb2N1cyc6IDIsXG4gICdzZWxlY3Q6OnJlcXVpcmVkJzogMCxcbiAgJ3NlbGVjdDo6c2l6ZSc6IDAsXG4gICdzZWxlY3Q6OnRhYmluZGV4JzogMCxcbiAgJ3NvdXJjZTo6dHlwZSc6IDAsXG4gICd0YWJsZTo6YWxpZ24nOiAwLFxuICAndGFibGU6OmJnY29sb3InOiAwLFxuICAndGFibGU6OmJvcmRlcic6IDAsXG4gICd0YWJsZTo6Y2VsbHBhZGRpbmcnOiAwLFxuICAndGFibGU6OmNlbGxzcGFjaW5nJzogMCxcbiAgJ3RhYmxlOjpmcmFtZSc6IDAsXG4gICd0YWJsZTo6cnVsZXMnOiAwLFxuICAndGFibGU6OnN1bW1hcnknOiAwLFxuICAndGFibGU6OndpZHRoJzogMCxcbiAgJ3Rib2R5OjphbGlnbic6IDAsXG4gICd0Ym9keTo6Y2hhcic6IDAsXG4gICd0Ym9keTo6Y2hhcm9mZic6IDAsXG4gICd0Ym9keTo6dmFsaWduJzogMCxcbiAgJ3RkOjphYmJyJzogMCxcbiAgJ3RkOjphbGlnbic6IDAsXG4gICd0ZDo6YXhpcyc6IDAsXG4gICd0ZDo6Ymdjb2xvcic6IDAsXG4gICd0ZDo6Y2hhcic6IDAsXG4gICd0ZDo6Y2hhcm9mZic6IDAsXG4gICd0ZDo6Y29sc3Bhbic6IDAsXG4gICd0ZDo6aGVhZGVycyc6IDYsXG4gICd0ZDo6aGVpZ2h0JzogMCxcbiAgJ3RkOjpub3dyYXAnOiAwLFxuICAndGQ6OnJvd3NwYW4nOiAwLFxuICAndGQ6OnNjb3BlJzogMCxcbiAgJ3RkOjp2YWxpZ24nOiAwLFxuICAndGQ6OndpZHRoJzogMCxcbiAgJ3RleHRhcmVhOjphY2Nlc3NrZXknOiAwLFxuICAndGV4dGFyZWE6OmF1dG9jb21wbGV0ZSc6IDAsXG4gICd0ZXh0YXJlYTo6Y29scyc6IDAsXG4gICd0ZXh0YXJlYTo6ZGlzYWJsZWQnOiAwLFxuICAndGV4dGFyZWE6OmlucHV0bW9kZSc6IDAsXG4gICd0ZXh0YXJlYTo6bmFtZSc6IDgsXG4gICd0ZXh0YXJlYTo6b25ibHVyJzogMixcbiAgJ3RleHRhcmVhOjpvbmNoYW5nZSc6IDIsXG4gICd0ZXh0YXJlYTo6b25mb2N1cyc6IDIsXG4gICd0ZXh0YXJlYTo6b25zZWxlY3QnOiAyLFxuICAndGV4dGFyZWE6OnBsYWNlaG9sZGVyJzogMCxcbiAgJ3RleHRhcmVhOjpyZWFkb25seSc6IDAsXG4gICd0ZXh0YXJlYTo6cmVxdWlyZWQnOiAwLFxuICAndGV4dGFyZWE6OnJvd3MnOiAwLFxuICAndGV4dGFyZWE6OnRhYmluZGV4JzogMCxcbiAgJ3RleHRhcmVhOjp3cmFwJzogMCxcbiAgJ3Rmb290OjphbGlnbic6IDAsXG4gICd0Zm9vdDo6Y2hhcic6IDAsXG4gICd0Zm9vdDo6Y2hhcm9mZic6IDAsXG4gICd0Zm9vdDo6dmFsaWduJzogMCxcbiAgJ3RoOjphYmJyJzogMCxcbiAgJ3RoOjphbGlnbic6IDAsXG4gICd0aDo6YXhpcyc6IDAsXG4gICd0aDo6Ymdjb2xvcic6IDAsXG4gICd0aDo6Y2hhcic6IDAsXG4gICd0aDo6Y2hhcm9mZic6IDAsXG4gICd0aDo6Y29sc3Bhbic6IDAsXG4gICd0aDo6aGVhZGVycyc6IDYsXG4gICd0aDo6aGVpZ2h0JzogMCxcbiAgJ3RoOjpub3dyYXAnOiAwLFxuICAndGg6OnJvd3NwYW4nOiAwLFxuICAndGg6OnNjb3BlJzogMCxcbiAgJ3RoOjp2YWxpZ24nOiAwLFxuICAndGg6OndpZHRoJzogMCxcbiAgJ3RoZWFkOjphbGlnbic6IDAsXG4gICd0aGVhZDo6Y2hhcic6IDAsXG4gICd0aGVhZDo6Y2hhcm9mZic6IDAsXG4gICd0aGVhZDo6dmFsaWduJzogMCxcbiAgJ3RyOjphbGlnbic6IDAsXG4gICd0cjo6Ymdjb2xvcic6IDAsXG4gICd0cjo6Y2hhcic6IDAsXG4gICd0cjo6Y2hhcm9mZic6IDAsXG4gICd0cjo6dmFsaWduJzogMCxcbiAgJ3RyYWNrOjpkZWZhdWx0JzogMCxcbiAgJ3RyYWNrOjpraW5kJzogMCxcbiAgJ3RyYWNrOjpsYWJlbCc6IDAsXG4gICd0cmFjazo6c3JjbGFuZyc6IDAsXG4gICd1bDo6Y29tcGFjdCc6IDAsXG4gICd1bDo6dHlwZSc6IDAsXG4gICd2aWRlbzo6Y29udHJvbHMnOiAwLFxuICAndmlkZW86OmhlaWdodCc6IDAsXG4gICd2aWRlbzo6bG9vcCc6IDAsXG4gICd2aWRlbzo6bWVkaWFncm91cCc6IDUsXG4gICd2aWRlbzo6bXV0ZWQnOiAwLFxuICAndmlkZW86OnBvc3Rlcic6IDEsXG4gICd2aWRlbzo6cHJlbG9hZCc6IDAsXG4gICd2aWRlbzo6d2lkdGgnOiAwXG59O1xuaHRtbDRbICdBVFRSSUJTJyBdID0gaHRtbDQuQVRUUklCUztcbmh0bWw0LmVmbGFncyA9IHtcbiAgJ09QVElPTkFMX0VORFRBRyc6IDEsXG4gICdFTVBUWSc6IDIsXG4gICdDREFUQSc6IDQsXG4gICdSQ0RBVEEnOiA4LFxuICAnVU5TQUZFJzogMTYsXG4gICdGT0xEQUJMRSc6IDMyLFxuICAnU0NSSVBUJzogNjQsXG4gICdTVFlMRSc6IDEyOCxcbiAgJ1ZJUlRVQUxJWkVEJzogMjU2XG59O1xuaHRtbDRbICdlZmxhZ3MnIF0gPSBodG1sNC5lZmxhZ3M7XG4vLyB0aGVzZSBhcmUgYml0bWFza3Mgb2YgdGhlIGVmbGFncyBhYm92ZS5cbmh0bWw0LkVMRU1FTlRTID0ge1xuICAnYSc6IDAsXG4gICdhYmJyJzogMCxcbiAgJ2Fjcm9ueW0nOiAwLFxuICAnYWRkcmVzcyc6IDAsXG4gICdhcHBsZXQnOiAyNzIsXG4gICdhcmVhJzogMixcbiAgJ2FydGljbGUnOiAwLFxuICAnYXNpZGUnOiAwLFxuICAnYXVkaW8nOiAwLFxuICAnYic6IDAsXG4gICdiYXNlJzogMjc0LFxuICAnYmFzZWZvbnQnOiAyNzQsXG4gICdiZGknOiAwLFxuICAnYmRvJzogMCxcbiAgJ2JpZyc6IDAsXG4gICdibG9ja3F1b3RlJzogMCxcbiAgJ2JvZHknOiAzMDUsXG4gICdicic6IDIsXG4gICdidXR0b24nOiAwLFxuICAnY2FudmFzJzogMCxcbiAgJ2NhcHRpb24nOiAwLFxuICAnY2VudGVyJzogMCxcbiAgJ2NpdGUnOiAwLFxuICAnY29kZSc6IDAsXG4gICdjb2wnOiAyLFxuICAnY29sZ3JvdXAnOiAxLFxuICAnY29tbWFuZCc6IDIsXG4gICdkYXRhJzogMCxcbiAgJ2RhdGFsaXN0JzogMCxcbiAgJ2RkJzogMSxcbiAgJ2RlbCc6IDAsXG4gICdkZXRhaWxzJzogMCxcbiAgJ2Rmbic6IDAsXG4gICdkaWFsb2cnOiAyNzIsXG4gICdkaXInOiAwLFxuICAnZGl2JzogMCxcbiAgJ2RsJzogMCxcbiAgJ2R0JzogMSxcbiAgJ2VtJzogMCxcbiAgJ2ZpZWxkc2V0JzogMCxcbiAgJ2ZpZ2NhcHRpb24nOiAwLFxuICAnZmlndXJlJzogMCxcbiAgJ2ZvbnQnOiAwLFxuICAnZm9vdGVyJzogMCxcbiAgJ2Zvcm0nOiAwLFxuICAnZnJhbWUnOiAyNzQsXG4gICdmcmFtZXNldCc6IDI3MixcbiAgJ2gxJzogMCxcbiAgJ2gyJzogMCxcbiAgJ2gzJzogMCxcbiAgJ2g0JzogMCxcbiAgJ2g1JzogMCxcbiAgJ2g2JzogMCxcbiAgJ2hlYWQnOiAzMDUsXG4gICdoZWFkZXInOiAwLFxuICAnaGdyb3VwJzogMCxcbiAgJ2hyJzogMixcbiAgJ2h0bWwnOiAzMDUsXG4gICdpJzogMCxcbiAgJ2lmcmFtZSc6IDE2LFxuICAnaW1nJzogMixcbiAgJ2lucHV0JzogMixcbiAgJ2lucyc6IDAsXG4gICdpc2luZGV4JzogMjc0LFxuICAna2JkJzogMCxcbiAgJ2tleWdlbic6IDI3NCxcbiAgJ2xhYmVsJzogMCxcbiAgJ2xlZ2VuZCc6IDAsXG4gICdsaSc6IDEsXG4gICdsaW5rJzogMjc0LFxuICAnbWFwJzogMCxcbiAgJ21hcmsnOiAwLFxuICAnbWVudSc6IDAsXG4gICdtZXRhJzogMjc0LFxuICAnbWV0ZXInOiAwLFxuICAnbmF2JzogMCxcbiAgJ25vYnInOiAwLFxuICAnbm9lbWJlZCc6IDI3NixcbiAgJ25vZnJhbWVzJzogMjc2LFxuICAnbm9zY3JpcHQnOiAyNzYsXG4gICdvYmplY3QnOiAyNzIsXG4gICdvbCc6IDAsXG4gICdvcHRncm91cCc6IDAsXG4gICdvcHRpb24nOiAxLFxuICAnb3V0cHV0JzogMCxcbiAgJ3AnOiAxLFxuICAncGFyYW0nOiAyNzQsXG4gICdwcmUnOiAwLFxuICAncHJvZ3Jlc3MnOiAwLFxuICAncSc6IDAsXG4gICdzJzogMCxcbiAgJ3NhbXAnOiAwLFxuICAnc2NyaXB0JzogODQsXG4gICdzZWN0aW9uJzogMCxcbiAgJ3NlbGVjdCc6IDAsXG4gICdzbWFsbCc6IDAsXG4gICdzb3VyY2UnOiAyLFxuICAnc3Bhbic6IDAsXG4gICdzdHJpa2UnOiAwLFxuICAnc3Ryb25nJzogMCxcbiAgJ3N0eWxlJzogMTQ4LFxuICAnc3ViJzogMCxcbiAgJ3N1bW1hcnknOiAwLFxuICAnc3VwJzogMCxcbiAgJ3RhYmxlJzogMCxcbiAgJ3Rib2R5JzogMSxcbiAgJ3RkJzogMSxcbiAgJ3RleHRhcmVhJzogOCxcbiAgJ3Rmb290JzogMSxcbiAgJ3RoJzogMSxcbiAgJ3RoZWFkJzogMSxcbiAgJ3RpbWUnOiAwLFxuICAndGl0bGUnOiAyODAsXG4gICd0cic6IDEsXG4gICd0cmFjayc6IDIsXG4gICd0dCc6IDAsXG4gICd1JzogMCxcbiAgJ3VsJzogMCxcbiAgJ3Zhcic6IDAsXG4gICd2aWRlbyc6IDAsXG4gICd3YnInOiAyXG59O1xuaHRtbDRbICdFTEVNRU5UUycgXSA9IGh0bWw0LkVMRU1FTlRTO1xuaHRtbDQuRUxFTUVOVF9ET01fSU5URVJGQUNFUyA9IHtcbiAgJ2EnOiAnSFRNTEFuY2hvckVsZW1lbnQnLFxuICAnYWJicic6ICdIVE1MRWxlbWVudCcsXG4gICdhY3JvbnltJzogJ0hUTUxFbGVtZW50JyxcbiAgJ2FkZHJlc3MnOiAnSFRNTEVsZW1lbnQnLFxuICAnYXBwbGV0JzogJ0hUTUxBcHBsZXRFbGVtZW50JyxcbiAgJ2FyZWEnOiAnSFRNTEFyZWFFbGVtZW50JyxcbiAgJ2FydGljbGUnOiAnSFRNTEVsZW1lbnQnLFxuICAnYXNpZGUnOiAnSFRNTEVsZW1lbnQnLFxuICAnYXVkaW8nOiAnSFRNTEF1ZGlvRWxlbWVudCcsXG4gICdiJzogJ0hUTUxFbGVtZW50JyxcbiAgJ2Jhc2UnOiAnSFRNTEJhc2VFbGVtZW50JyxcbiAgJ2Jhc2Vmb250JzogJ0hUTUxCYXNlRm9udEVsZW1lbnQnLFxuICAnYmRpJzogJ0hUTUxFbGVtZW50JyxcbiAgJ2Jkbyc6ICdIVE1MRWxlbWVudCcsXG4gICdiaWcnOiAnSFRNTEVsZW1lbnQnLFxuICAnYmxvY2txdW90ZSc6ICdIVE1MUXVvdGVFbGVtZW50JyxcbiAgJ2JvZHknOiAnSFRNTEJvZHlFbGVtZW50JyxcbiAgJ2JyJzogJ0hUTUxCUkVsZW1lbnQnLFxuICAnYnV0dG9uJzogJ0hUTUxCdXR0b25FbGVtZW50JyxcbiAgJ2NhbnZhcyc6ICdIVE1MQ2FudmFzRWxlbWVudCcsXG4gICdjYXB0aW9uJzogJ0hUTUxUYWJsZUNhcHRpb25FbGVtZW50JyxcbiAgJ2NlbnRlcic6ICdIVE1MRWxlbWVudCcsXG4gICdjaXRlJzogJ0hUTUxFbGVtZW50JyxcbiAgJ2NvZGUnOiAnSFRNTEVsZW1lbnQnLFxuICAnY29sJzogJ0hUTUxUYWJsZUNvbEVsZW1lbnQnLFxuICAnY29sZ3JvdXAnOiAnSFRNTFRhYmxlQ29sRWxlbWVudCcsXG4gICdjb21tYW5kJzogJ0hUTUxDb21tYW5kRWxlbWVudCcsXG4gICdkYXRhJzogJ0hUTUxFbGVtZW50JyxcbiAgJ2RhdGFsaXN0JzogJ0hUTUxEYXRhTGlzdEVsZW1lbnQnLFxuICAnZGQnOiAnSFRNTEVsZW1lbnQnLFxuICAnZGVsJzogJ0hUTUxNb2RFbGVtZW50JyxcbiAgJ2RldGFpbHMnOiAnSFRNTERldGFpbHNFbGVtZW50JyxcbiAgJ2Rmbic6ICdIVE1MRWxlbWVudCcsXG4gICdkaWFsb2cnOiAnSFRNTERpYWxvZ0VsZW1lbnQnLFxuICAnZGlyJzogJ0hUTUxEaXJlY3RvcnlFbGVtZW50JyxcbiAgJ2Rpdic6ICdIVE1MRGl2RWxlbWVudCcsXG4gICdkbCc6ICdIVE1MRExpc3RFbGVtZW50JyxcbiAgJ2R0JzogJ0hUTUxFbGVtZW50JyxcbiAgJ2VtJzogJ0hUTUxFbGVtZW50JyxcbiAgJ2ZpZWxkc2V0JzogJ0hUTUxGaWVsZFNldEVsZW1lbnQnLFxuICAnZmlnY2FwdGlvbic6ICdIVE1MRWxlbWVudCcsXG4gICdmaWd1cmUnOiAnSFRNTEVsZW1lbnQnLFxuICAnZm9udCc6ICdIVE1MRm9udEVsZW1lbnQnLFxuICAnZm9vdGVyJzogJ0hUTUxFbGVtZW50JyxcbiAgJ2Zvcm0nOiAnSFRNTEZvcm1FbGVtZW50JyxcbiAgJ2ZyYW1lJzogJ0hUTUxGcmFtZUVsZW1lbnQnLFxuICAnZnJhbWVzZXQnOiAnSFRNTEZyYW1lU2V0RWxlbWVudCcsXG4gICdoMSc6ICdIVE1MSGVhZGluZ0VsZW1lbnQnLFxuICAnaDInOiAnSFRNTEhlYWRpbmdFbGVtZW50JyxcbiAgJ2gzJzogJ0hUTUxIZWFkaW5nRWxlbWVudCcsXG4gICdoNCc6ICdIVE1MSGVhZGluZ0VsZW1lbnQnLFxuICAnaDUnOiAnSFRNTEhlYWRpbmdFbGVtZW50JyxcbiAgJ2g2JzogJ0hUTUxIZWFkaW5nRWxlbWVudCcsXG4gICdoZWFkJzogJ0hUTUxIZWFkRWxlbWVudCcsXG4gICdoZWFkZXInOiAnSFRNTEVsZW1lbnQnLFxuICAnaGdyb3VwJzogJ0hUTUxFbGVtZW50JyxcbiAgJ2hyJzogJ0hUTUxIUkVsZW1lbnQnLFxuICAnaHRtbCc6ICdIVE1MSHRtbEVsZW1lbnQnLFxuICAnaSc6ICdIVE1MRWxlbWVudCcsXG4gICdpZnJhbWUnOiAnSFRNTElGcmFtZUVsZW1lbnQnLFxuICAnaW1nJzogJ0hUTUxJbWFnZUVsZW1lbnQnLFxuICAnaW5wdXQnOiAnSFRNTElucHV0RWxlbWVudCcsXG4gICdpbnMnOiAnSFRNTE1vZEVsZW1lbnQnLFxuICAnaXNpbmRleCc6ICdIVE1MVW5rbm93bkVsZW1lbnQnLFxuICAna2JkJzogJ0hUTUxFbGVtZW50JyxcbiAgJ2tleWdlbic6ICdIVE1MS2V5Z2VuRWxlbWVudCcsXG4gICdsYWJlbCc6ICdIVE1MTGFiZWxFbGVtZW50JyxcbiAgJ2xlZ2VuZCc6ICdIVE1MTGVnZW5kRWxlbWVudCcsXG4gICdsaSc6ICdIVE1MTElFbGVtZW50JyxcbiAgJ2xpbmsnOiAnSFRNTExpbmtFbGVtZW50JyxcbiAgJ21hcCc6ICdIVE1MTWFwRWxlbWVudCcsXG4gICdtYXJrJzogJ0hUTUxFbGVtZW50JyxcbiAgJ21lbnUnOiAnSFRNTE1lbnVFbGVtZW50JyxcbiAgJ21ldGEnOiAnSFRNTE1ldGFFbGVtZW50JyxcbiAgJ21ldGVyJzogJ0hUTUxNZXRlckVsZW1lbnQnLFxuICAnbmF2JzogJ0hUTUxFbGVtZW50JyxcbiAgJ25vYnInOiAnSFRNTEVsZW1lbnQnLFxuICAnbm9lbWJlZCc6ICdIVE1MRWxlbWVudCcsXG4gICdub2ZyYW1lcyc6ICdIVE1MRWxlbWVudCcsXG4gICdub3NjcmlwdCc6ICdIVE1MRWxlbWVudCcsXG4gICdvYmplY3QnOiAnSFRNTE9iamVjdEVsZW1lbnQnLFxuICAnb2wnOiAnSFRNTE9MaXN0RWxlbWVudCcsXG4gICdvcHRncm91cCc6ICdIVE1MT3B0R3JvdXBFbGVtZW50JyxcbiAgJ29wdGlvbic6ICdIVE1MT3B0aW9uRWxlbWVudCcsXG4gICdvdXRwdXQnOiAnSFRNTE91dHB1dEVsZW1lbnQnLFxuICAncCc6ICdIVE1MUGFyYWdyYXBoRWxlbWVudCcsXG4gICdwYXJhbSc6ICdIVE1MUGFyYW1FbGVtZW50JyxcbiAgJ3ByZSc6ICdIVE1MUHJlRWxlbWVudCcsXG4gICdwcm9ncmVzcyc6ICdIVE1MUHJvZ3Jlc3NFbGVtZW50JyxcbiAgJ3EnOiAnSFRNTFF1b3RlRWxlbWVudCcsXG4gICdzJzogJ0hUTUxFbGVtZW50JyxcbiAgJ3NhbXAnOiAnSFRNTEVsZW1lbnQnLFxuICAnc2NyaXB0JzogJ0hUTUxTY3JpcHRFbGVtZW50JyxcbiAgJ3NlY3Rpb24nOiAnSFRNTEVsZW1lbnQnLFxuICAnc2VsZWN0JzogJ0hUTUxTZWxlY3RFbGVtZW50JyxcbiAgJ3NtYWxsJzogJ0hUTUxFbGVtZW50JyxcbiAgJ3NvdXJjZSc6ICdIVE1MU291cmNlRWxlbWVudCcsXG4gICdzcGFuJzogJ0hUTUxTcGFuRWxlbWVudCcsXG4gICdzdHJpa2UnOiAnSFRNTEVsZW1lbnQnLFxuICAnc3Ryb25nJzogJ0hUTUxFbGVtZW50JyxcbiAgJ3N0eWxlJzogJ0hUTUxTdHlsZUVsZW1lbnQnLFxuICAnc3ViJzogJ0hUTUxFbGVtZW50JyxcbiAgJ3N1bW1hcnknOiAnSFRNTEVsZW1lbnQnLFxuICAnc3VwJzogJ0hUTUxFbGVtZW50JyxcbiAgJ3RhYmxlJzogJ0hUTUxUYWJsZUVsZW1lbnQnLFxuICAndGJvZHknOiAnSFRNTFRhYmxlU2VjdGlvbkVsZW1lbnQnLFxuICAndGQnOiAnSFRNTFRhYmxlRGF0YUNlbGxFbGVtZW50JyxcbiAgJ3RleHRhcmVhJzogJ0hUTUxUZXh0QXJlYUVsZW1lbnQnLFxuICAndGZvb3QnOiAnSFRNTFRhYmxlU2VjdGlvbkVsZW1lbnQnLFxuICAndGgnOiAnSFRNTFRhYmxlSGVhZGVyQ2VsbEVsZW1lbnQnLFxuICAndGhlYWQnOiAnSFRNTFRhYmxlU2VjdGlvbkVsZW1lbnQnLFxuICAndGltZSc6ICdIVE1MVGltZUVsZW1lbnQnLFxuICAndGl0bGUnOiAnSFRNTFRpdGxlRWxlbWVudCcsXG4gICd0cic6ICdIVE1MVGFibGVSb3dFbGVtZW50JyxcbiAgJ3RyYWNrJzogJ0hUTUxUcmFja0VsZW1lbnQnLFxuICAndHQnOiAnSFRNTEVsZW1lbnQnLFxuICAndSc6ICdIVE1MRWxlbWVudCcsXG4gICd1bCc6ICdIVE1MVUxpc3RFbGVtZW50JyxcbiAgJ3Zhcic6ICdIVE1MRWxlbWVudCcsXG4gICd2aWRlbyc6ICdIVE1MVmlkZW9FbGVtZW50JyxcbiAgJ3dicic6ICdIVE1MRWxlbWVudCdcbn07XG5odG1sNFsgJ0VMRU1FTlRfRE9NX0lOVEVSRkFDRVMnIF0gPSBodG1sNC5FTEVNRU5UX0RPTV9JTlRFUkZBQ0VTO1xuaHRtbDQudWVmZmVjdHMgPSB7XG4gICdOT1RfTE9BREVEJzogMCxcbiAgJ1NBTUVfRE9DVU1FTlQnOiAxLFxuICAnTkVXX0RPQ1VNRU5UJzogMlxufTtcbmh0bWw0WyAndWVmZmVjdHMnIF0gPSBodG1sNC51ZWZmZWN0cztcbmh0bWw0LlVSSUVGRkVDVFMgPSB7XG4gICdhOjpocmVmJzogMixcbiAgJ2FyZWE6OmhyZWYnOiAyLFxuICAnYmxvY2txdW90ZTo6Y2l0ZSc6IDAsXG4gICdjb21tYW5kOjppY29uJzogMSxcbiAgJ2RlbDo6Y2l0ZSc6IDAsXG4gICdmb3JtOjphY3Rpb24nOiAyLFxuICAnaW1nOjpzcmMnOiAxLFxuICAnaW5wdXQ6OnNyYyc6IDEsXG4gICdpbnM6OmNpdGUnOiAwLFxuICAncTo6Y2l0ZSc6IDAsXG4gICd2aWRlbzo6cG9zdGVyJzogMVxufTtcbmh0bWw0WyAnVVJJRUZGRUNUUycgXSA9IGh0bWw0LlVSSUVGRkVDVFM7XG5odG1sNC5sdHlwZXMgPSB7XG4gICdVTlNBTkRCT1hFRCc6IDIsXG4gICdTQU5EQk9YRUQnOiAxLFxuICAnREFUQSc6IDBcbn07XG5odG1sNFsgJ2x0eXBlcycgXSA9IGh0bWw0Lmx0eXBlcztcbmh0bWw0LkxPQURFUlRZUEVTID0ge1xuICAnYTo6aHJlZic6IDIsXG4gICdhcmVhOjpocmVmJzogMixcbiAgJ2Jsb2NrcXVvdGU6OmNpdGUnOiAyLFxuICAnY29tbWFuZDo6aWNvbic6IDEsXG4gICdkZWw6OmNpdGUnOiAyLFxuICAnZm9ybTo6YWN0aW9uJzogMixcbiAgJ2ltZzo6c3JjJzogMSxcbiAgJ2lucHV0OjpzcmMnOiAxLFxuICAnaW5zOjpjaXRlJzogMixcbiAgJ3E6OmNpdGUnOiAyLFxuICAndmlkZW86OnBvc3Rlcic6IDFcbn07XG5odG1sNFsgJ0xPQURFUlRZUEVTJyBdID0gaHRtbDQuTE9BREVSVFlQRVM7XG5cbi8vIENvcHlyaWdodCAoQykgMjAwNiBHb29nbGUgSW5jLlxuLy9cbi8vIExpY2Vuc2VkIHVuZGVyIHRoZSBBcGFjaGUgTGljZW5zZSwgVmVyc2lvbiAyLjAgKHRoZSBcIkxpY2Vuc2VcIik7XG4vLyB5b3UgbWF5IG5vdCB1c2UgdGhpcyBmaWxlIGV4Y2VwdCBpbiBjb21wbGlhbmNlIHdpdGggdGhlIExpY2Vuc2UuXG4vLyBZb3UgbWF5IG9idGFpbiBhIGNvcHkgb2YgdGhlIExpY2Vuc2UgYXRcbi8vXG4vLyAgICAgIGh0dHA6Ly93d3cuYXBhY2hlLm9yZy9saWNlbnNlcy9MSUNFTlNFLTIuMFxuLy9cbi8vIFVubGVzcyByZXF1aXJlZCBieSBhcHBsaWNhYmxlIGxhdyBvciBhZ3JlZWQgdG8gaW4gd3JpdGluZywgc29mdHdhcmVcbi8vIGRpc3RyaWJ1dGVkIHVuZGVyIHRoZSBMaWNlbnNlIGlzIGRpc3RyaWJ1dGVkIG9uIGFuIFwiQVMgSVNcIiBCQVNJUyxcbi8vIFdJVEhPVVQgV0FSUkFOVElFUyBPUiBDT05ESVRJT05TIE9GIEFOWSBLSU5ELCBlaXRoZXIgZXhwcmVzcyBvciBpbXBsaWVkLlxuLy8gU2VlIHRoZSBMaWNlbnNlIGZvciB0aGUgc3BlY2lmaWMgbGFuZ3VhZ2UgZ292ZXJuaW5nIHBlcm1pc3Npb25zIGFuZFxuLy8gbGltaXRhdGlvbnMgdW5kZXIgdGhlIExpY2Vuc2UuXG5cbi8qKlxuICogQGZpbGVvdmVydmlld1xuICogQW4gSFRNTCBzYW5pdGl6ZXIgdGhhdCBjYW4gc2F0aXNmeSBhIHZhcmlldHkgb2Ygc2VjdXJpdHkgcG9saWNpZXMuXG4gKlxuICogPHA+XG4gKiBUaGUgSFRNTCBzYW5pdGl6ZXIgaXMgYnVpbHQgYXJvdW5kIGEgU0FYIHBhcnNlciBhbmQgSFRNTCBlbGVtZW50IGFuZFxuICogYXR0cmlidXRlcyBzY2hlbWFzLlxuICpcbiAqIElmIHRoZSBjc3NwYXJzZXIgaXMgbG9hZGVkLCBpbmxpbmUgc3R5bGVzIGFyZSBzYW5pdGl6ZWQgdXNpbmcgdGhlXG4gKiBjc3MgcHJvcGVydHkgYW5kIHZhbHVlIHNjaGVtYXMuICBFbHNlIHRoZXkgYXJlIHJlbW92ZSBkdXJpbmdcbiAqIHNhbml0aXphdGlvbi5cbiAqXG4gKiBJZiBpdCBleGlzdHMsIHVzZXMgcGFyc2VDc3NEZWNsYXJhdGlvbnMsIHNhbml0aXplQ3NzUHJvcGVydHksICBjc3NTY2hlbWFcbiAqXG4gKiBAYXV0aG9yIG1pa2VzYW11ZWxAZ21haWwuY29tXG4gKiBAYXV0aG9yIGphc3ZpckBnbWFpbC5jb21cbiAqIFxcQHJlcXVpcmVzIGh0bWw0LCBVUklcbiAqIFxcQG92ZXJyaWRlcyB3aW5kb3dcbiAqIFxcQHByb3ZpZGVzIGh0bWwsIGh0bWxfc2FuaXRpemVcbiAqL1xuXG4vLyBUaGUgVHVya2lzaCBpIHNlZW1zIHRvIGJlIGEgbm9uLWlzc3VlLCBidXQgYWJvcnQgaW4gY2FzZSBpdCBpcy5cbmlmICgnSScudG9Mb3dlckNhc2UoKSAhPT0gJ2knKSB7IHRocm93ICdJL2kgcHJvYmxlbSc7IH1cblxuLyoqXG4gKiBcXEBuYW1lc3BhY2VcbiAqL1xudmFyIGh0bWwgPSAoZnVuY3Rpb24oaHRtbDQpIHtcblxuICAvLyBGb3IgY2xvc3VyZSBjb21waWxlclxuICB2YXIgcGFyc2VDc3NEZWNsYXJhdGlvbnMsIHNhbml0aXplQ3NzUHJvcGVydHksIGNzc1NjaGVtYTtcbiAgaWYgKCd1bmRlZmluZWQnICE9PSB0eXBlb2Ygd2luZG93KSB7XG4gICAgcGFyc2VDc3NEZWNsYXJhdGlvbnMgPSB3aW5kb3dbJ3BhcnNlQ3NzRGVjbGFyYXRpb25zJ107XG4gICAgc2FuaXRpemVDc3NQcm9wZXJ0eSA9IHdpbmRvd1snc2FuaXRpemVDc3NQcm9wZXJ0eSddO1xuICAgIGNzc1NjaGVtYSA9IHdpbmRvd1snY3NzU2NoZW1hJ107XG4gIH1cblxuICAvLyBUaGUga2V5cyBvZiB0aGlzIG9iamVjdCBtdXN0IGJlICdxdW90ZWQnIG9yIEpTQ29tcGlsZXIgd2lsbCBtYW5nbGUgdGhlbSFcbiAgLy8gVGhpcyBpcyBhIHBhcnRpYWwgbGlzdCAtLSBsb29rdXBFbnRpdHkoKSB1c2VzIHRoZSBob3N0IGJyb3dzZXIncyBwYXJzZXJcbiAgLy8gKHdoZW4gYXZhaWxhYmxlKSB0byBpbXBsZW1lbnQgZnVsbCBlbnRpdHkgbG9va3VwLlxuICAvLyBOb3RlIHRoYXQgZW50aXRpZXMgYXJlIGluIGdlbmVyYWwgY2FzZS1zZW5zaXRpdmU7IHRoZSB1cHBlcmNhc2Ugb25lcyBhcmVcbiAgLy8gZXhwbGljaXRseSBkZWZpbmVkIGJ5IEhUTUw1IChwcmVzdW1hYmx5IGFzIGNvbXBhdGliaWxpdHkpLlxuICB2YXIgRU5USVRJRVMgPSB7XG4gICAgJ2x0JzogJzwnLFxuICAgICdMVCc6ICc8JyxcbiAgICAnZ3QnOiAnPicsXG4gICAgJ0dUJzogJz4nLFxuICAgICdhbXAnOiAnJicsXG4gICAgJ0FNUCc6ICcmJyxcbiAgICAncXVvdCc6ICdcIicsXG4gICAgJ2Fwb3MnOiAnXFwnJyxcbiAgICAnbmJzcCc6ICdcXHUwMEEwJ1xuICB9O1xuXG4gIC8vIFBhdHRlcm5zIGZvciB0eXBlcyBvZiBlbnRpdHkvY2hhcmFjdGVyIHJlZmVyZW5jZSBuYW1lcy5cbiAgdmFyIGRlY2ltYWxFc2NhcGVSZSA9IC9eIyhcXGQrKSQvO1xuICB2YXIgaGV4RXNjYXBlUmUgPSAvXiN4KFswLTlBLUZhLWZdKykkLztcbiAgLy8gY29udGFpbnMgZXZlcnkgZW50aXR5IHBlciBodHRwOi8vd3d3LnczLm9yZy9UUi8yMDExL1dELWh0bWw1LTIwMTEwMTEzL25hbWVkLWNoYXJhY3Rlci1yZWZlcmVuY2VzLmh0bWxcbiAgdmFyIHNhZmVFbnRpdHlOYW1lUmUgPSAvXltBLVphLXpdW0EtemEtejAtOV0rJC87XG4gIC8vIFVzZWQgYXMgYSBob29rIHRvIGludm9rZSB0aGUgYnJvd3NlcidzIGVudGl0eSBwYXJzaW5nLiA8dGV4dGFyZWE+IGlzIHVzZWRcbiAgLy8gYmVjYXVzZSBpdHMgY29udGVudCBpcyBwYXJzZWQgZm9yIGVudGl0aWVzIGJ1dCBub3QgdGFncy5cbiAgLy8gVE9ETyhrcHJlaWQpOiBUaGlzIHJldHJpZXZhbCBpcyBhIGtsdWRnZSBhbmQgbGVhZHMgdG8gc2lsZW50IGxvc3Mgb2ZcbiAgLy8gZnVuY3Rpb25hbGl0eSBpZiB0aGUgZG9jdW1lbnQgaXNuJ3QgYXZhaWxhYmxlLlxuICB2YXIgZW50aXR5TG9va3VwRWxlbWVudCA9XG4gICAgICAoJ3VuZGVmaW5lZCcgIT09IHR5cGVvZiB3aW5kb3cgJiYgd2luZG93Wydkb2N1bWVudCddKVxuICAgICAgICAgID8gd2luZG93Wydkb2N1bWVudCddLmNyZWF0ZUVsZW1lbnQoJ3RleHRhcmVhJykgOiBudWxsO1xuICAvKipcbiAgICogRGVjb2RlcyBhbiBIVE1MIGVudGl0eS5cbiAgICpcbiAgICoge1xcQHVwZG9jXG4gICAqICQgbG9va3VwRW50aXR5KCdsdCcpXG4gICAqICMgJzwnXG4gICAqICQgbG9va3VwRW50aXR5KCdHVCcpXG4gICAqICMgJz4nXG4gICAqICQgbG9va3VwRW50aXR5KCdhbXAnKVxuICAgKiAjICcmJ1xuICAgKiAkIGxvb2t1cEVudGl0eSgnbmJzcCcpXG4gICAqICMgJ1xceEEwJ1xuICAgKiAkIGxvb2t1cEVudGl0eSgnYXBvcycpXG4gICAqICMgXCInXCJcbiAgICogJCBsb29rdXBFbnRpdHkoJ3F1b3QnKVxuICAgKiAjICdcIidcbiAgICogJCBsb29rdXBFbnRpdHkoJyN4YScpXG4gICAqICMgJ1xcbidcbiAgICogJCBsb29rdXBFbnRpdHkoJyMxMCcpXG4gICAqICMgJ1xcbidcbiAgICogJCBsb29rdXBFbnRpdHkoJyN4MGEnKVxuICAgKiAjICdcXG4nXG4gICAqICQgbG9va3VwRW50aXR5KCcjMDEwJylcbiAgICogIyAnXFxuJ1xuICAgKiAkIGxvb2t1cEVudGl0eSgnI3gwMEEnKVxuICAgKiAjICdcXG4nXG4gICAqICQgbG9va3VwRW50aXR5KCdQaScpICAgICAgLy8gS25vd24gZmFpbHVyZVxuICAgKiAjICdcXHUwM0EwJ1xuICAgKiAkIGxvb2t1cEVudGl0eSgncGknKSAgICAgIC8vIEtub3duIGZhaWx1cmVcbiAgICogIyAnXFx1MDNDMCdcbiAgICogfVxuICAgKlxuICAgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSB0aGUgY29udGVudCBiZXR3ZWVuIHRoZSAnJicgYW5kIHRoZSAnOycuXG4gICAqIEByZXR1cm4ge3N0cmluZ30gYSBzaW5nbGUgdW5pY29kZSBjb2RlLXBvaW50IGFzIGEgc3RyaW5nLlxuICAgKi9cbiAgZnVuY3Rpb24gbG9va3VwRW50aXR5KG5hbWUpIHtcbiAgICAvLyBUT0RPOiBlbnRpdHkgbG9va3VwIGFzIHNwZWNpZmllZCBieSBIVE1MNSBhY3R1YWxseSBkZXBlbmRzIG9uIHRoZVxuICAgIC8vIHByZXNlbmNlIG9mIHRoZSBcIjtcIi5cbiAgICBpZiAoRU5USVRJRVMuaGFzT3duUHJvcGVydHkobmFtZSkpIHsgcmV0dXJuIEVOVElUSUVTW25hbWVdOyB9XG4gICAgdmFyIG0gPSBuYW1lLm1hdGNoKGRlY2ltYWxFc2NhcGVSZSk7XG4gICAgaWYgKG0pIHtcbiAgICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlKHBhcnNlSW50KG1bMV0sIDEwKSk7XG4gICAgfSBlbHNlIGlmICghIShtID0gbmFtZS5tYXRjaChoZXhFc2NhcGVSZSkpKSB7XG4gICAgICByZXR1cm4gU3RyaW5nLmZyb21DaGFyQ29kZShwYXJzZUludChtWzFdLCAxNikpO1xuICAgIH0gZWxzZSBpZiAoZW50aXR5TG9va3VwRWxlbWVudCAmJiBzYWZlRW50aXR5TmFtZVJlLnRlc3QobmFtZSkpIHtcbiAgICAgIGVudGl0eUxvb2t1cEVsZW1lbnQuaW5uZXJIVE1MID0gJyYnICsgbmFtZSArICc7JztcbiAgICAgIHZhciB0ZXh0ID0gZW50aXR5TG9va3VwRWxlbWVudC50ZXh0Q29udGVudDtcbiAgICAgIEVOVElUSUVTW25hbWVdID0gdGV4dDtcbiAgICAgIHJldHVybiB0ZXh0O1xuICAgIH0gZWxzZSB7XG4gICAgICByZXR1cm4gJyYnICsgbmFtZSArICc7JztcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBkZWNvZGVPbmVFbnRpdHkoXywgbmFtZSkge1xuICAgIHJldHVybiBsb29rdXBFbnRpdHkobmFtZSk7XG4gIH1cblxuICB2YXIgbnVsUmUgPSAvXFwwL2c7XG4gIGZ1bmN0aW9uIHN0cmlwTlVMcyhzKSB7XG4gICAgcmV0dXJuIHMucmVwbGFjZShudWxSZSwgJycpO1xuICB9XG5cbiAgdmFyIEVOVElUWV9SRV8xID0gLyYoI1swLTldK3wjW3hYXVswLTlBLUZhLWZdK3xcXHcrKTsvZztcbiAgdmFyIEVOVElUWV9SRV8yID0gL14oI1swLTldK3wjW3hYXVswLTlBLUZhLWZdK3xcXHcrKTsvO1xuICAvKipcbiAgICogVGhlIHBsYWluIHRleHQgb2YgYSBjaHVuayBvZiBIVE1MIENEQVRBIHdoaWNoIHBvc3NpYmx5IGNvbnRhaW5pbmcuXG4gICAqXG4gICAqIHtcXEB1cGRvY1xuICAgKiAkIHVuZXNjYXBlRW50aXRpZXMoJycpXG4gICAqICMgJydcbiAgICogJCB1bmVzY2FwZUVudGl0aWVzKCdoZWxsbyBXb3JsZCEnKVxuICAgKiAjICdoZWxsbyBXb3JsZCEnXG4gICAqICQgdW5lc2NhcGVFbnRpdGllcygnMSAmbHQ7IDIgJmFtcDsmQU1QOyA0ICZndDsgMyYjMTA7JylcbiAgICogIyAnMSA8IDIgJiYgNCA+IDNcXG4nXG4gICAqICQgdW5lc2NhcGVFbnRpdGllcygnJmx0OyZsdCA8LSB1bmZpbmlzaGVkIGVudGl0eSZndDsnKVxuICAgKiAjICc8Jmx0IDwtIHVuZmluaXNoZWQgZW50aXR5PidcbiAgICogJCB1bmVzY2FwZUVudGl0aWVzKCcvZm9vP2Jhcj1iYXomY29weT10cnVlJykgIC8vICYgb2Z0ZW4gdW5lc2NhcGVkIGluIFVSTFNcbiAgICogIyAnL2Zvbz9iYXI9YmF6JmNvcHk9dHJ1ZSdcbiAgICogJCB1bmVzY2FwZUVudGl0aWVzKCdwaT0mcGk7JiN4M2MwOywgUGk9JlBpO1xcdTAzQTAnKSAvLyBGSVhNRToga25vd24gZmFpbHVyZVxuICAgKiAjICdwaT1cXHUwM0MwXFx1MDNjMCwgUGk9XFx1MDNBMFxcdTAzQTAnXG4gICAqIH1cbiAgICpcbiAgICogQHBhcmFtIHtzdHJpbmd9IHMgYSBjaHVuayBvZiBIVE1MIENEQVRBLiAgSXQgbXVzdCBub3Qgc3RhcnQgb3IgZW5kIGluc2lkZVxuICAgKiAgICAgYW4gSFRNTCBlbnRpdHkuXG4gICAqL1xuICBmdW5jdGlvbiB1bmVzY2FwZUVudGl0aWVzKHMpIHtcbiAgICByZXR1cm4gcy5yZXBsYWNlKEVOVElUWV9SRV8xLCBkZWNvZGVPbmVFbnRpdHkpO1xuICB9XG5cbiAgdmFyIGFtcFJlID0gLyYvZztcbiAgdmFyIGxvb3NlQW1wUmUgPSAvJihbXmEteiNdfCMoPzpbXjAtOXhdfHgoPzpbXjAtOWEtZl18JCl8JCl8JCkvZ2k7XG4gIHZhciBsdFJlID0gL1s8XS9nO1xuICB2YXIgZ3RSZSA9IC8+L2c7XG4gIHZhciBxdW90UmUgPSAvXFxcIi9nO1xuXG4gIC8qKlxuICAgKiBFc2NhcGVzIEhUTUwgc3BlY2lhbCBjaGFyYWN0ZXJzIGluIGF0dHJpYnV0ZSB2YWx1ZXMuXG4gICAqXG4gICAqIHtcXEB1cGRvY1xuICAgKiAkIGVzY2FwZUF0dHJpYignJylcbiAgICogIyAnJ1xuICAgKiAkIGVzY2FwZUF0dHJpYignXCI8PCY9PSY+PlwiJykgIC8vIERvIG5vdCBqdXN0IGVzY2FwZSB0aGUgZmlyc3Qgb2NjdXJyZW5jZS5cbiAgICogIyAnJiMzNDsmbHQ7Jmx0OyZhbXA7JiM2MTsmIzYxOyZhbXA7Jmd0OyZndDsmIzM0OydcbiAgICogJCBlc2NhcGVBdHRyaWIoJ0hlbGxvIDxXb3JsZD4hJylcbiAgICogIyAnSGVsbG8gJmx0O1dvcmxkJmd0OyEnXG4gICAqIH1cbiAgICovXG4gIGZ1bmN0aW9uIGVzY2FwZUF0dHJpYihzKSB7XG4gICAgcmV0dXJuICgnJyArIHMpLnJlcGxhY2UoYW1wUmUsICcmYW1wOycpLnJlcGxhY2UobHRSZSwgJyZsdDsnKVxuICAgICAgICAucmVwbGFjZShndFJlLCAnJmd0OycpLnJlcGxhY2UocXVvdFJlLCAnJiMzNDsnKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFc2NhcGUgZW50aXRpZXMgaW4gUkNEQVRBIHRoYXQgY2FuIGJlIGVzY2FwZWQgd2l0aG91dCBjaGFuZ2luZyB0aGUgbWVhbmluZy5cbiAgICoge1xcQHVwZG9jXG4gICAqICQgbm9ybWFsaXplUkNEYXRhKCcxIDwgMiAmJmFtcDsgMyA+IDQgJmFtcDsmIDUgJmx0OyA3JjgnKVxuICAgKiAjICcxICZsdDsgMiAmYW1wOyZhbXA7IDMgJmd0OyA0ICZhbXA7JmFtcDsgNSAmbHQ7IDcmYW1wOzgnXG4gICAqIH1cbiAgICovXG4gIGZ1bmN0aW9uIG5vcm1hbGl6ZVJDRGF0YShyY2RhdGEpIHtcbiAgICByZXR1cm4gcmNkYXRhXG4gICAgICAgIC5yZXBsYWNlKGxvb3NlQW1wUmUsICcmYW1wOyQxJylcbiAgICAgICAgLnJlcGxhY2UobHRSZSwgJyZsdDsnKVxuICAgICAgICAucmVwbGFjZShndFJlLCAnJmd0OycpO1xuICB9XG5cbiAgLy8gVE9ETyhmZWxpeDhhKTogdmFsaWRhdGUgc2FuaXRpemVyIHJlZ2V4cyBhZ2FpbnN0IHRoZSBIVE1MNSBncmFtbWFyIGF0XG4gIC8vIGh0dHA6Ly93d3cud2hhdHdnLm9yZy9zcGVjcy93ZWItYXBwcy9jdXJyZW50LXdvcmsvbXVsdGlwYWdlL3N5bnRheC5odG1sXG4gIC8vIGh0dHA6Ly93d3cud2hhdHdnLm9yZy9zcGVjcy93ZWItYXBwcy9jdXJyZW50LXdvcmsvbXVsdGlwYWdlL3BhcnNpbmcuaHRtbFxuICAvLyBodHRwOi8vd3d3LndoYXR3Zy5vcmcvc3BlY3Mvd2ViLWFwcHMvY3VycmVudC13b3JrL211bHRpcGFnZS90b2tlbml6YXRpb24uaHRtbFxuICAvLyBodHRwOi8vd3d3LndoYXR3Zy5vcmcvc3BlY3Mvd2ViLWFwcHMvY3VycmVudC13b3JrL211bHRpcGFnZS90cmVlLWNvbnN0cnVjdGlvbi5odG1sXG5cbiAgLy8gV2UgaW5pdGlhbGx5IHNwbGl0IGlucHV0IHNvIHRoYXQgcG90ZW50aWFsbHkgbWVhbmluZ2Z1bCBjaGFyYWN0ZXJzXG4gIC8vIGxpa2UgJzwnIGFuZCAnPicgYXJlIHNlcGFyYXRlIHRva2VucywgdXNpbmcgYSBmYXN0IGR1bWIgcHJvY2VzcyB0aGF0XG4gIC8vIGlnbm9yZXMgcXVvdGluZy4gIFRoZW4gd2Ugd2FsayB0aGF0IHRva2VuIHN0cmVhbSwgYW5kIHdoZW4gd2Ugc2VlIGFcbiAgLy8gJzwnIHRoYXQncyB0aGUgc3RhcnQgb2YgYSB0YWcsIHdlIHVzZSBBVFRSX1JFIHRvIGV4dHJhY3QgdGFnXG4gIC8vIGF0dHJpYnV0ZXMgZnJvbSB0aGUgbmV4dCB0b2tlbi4gIFRoYXQgdG9rZW4gd2lsbCBuZXZlciBoYXZlIGEgJz4nXG4gIC8vIGNoYXJhY3Rlci4gIEhvd2V2ZXIsIGl0IG1pZ2h0IGhhdmUgYW4gdW5iYWxhbmNlZCBxdW90ZSBjaGFyYWN0ZXIsIGFuZFxuICAvLyB3aGVuIHdlIHNlZSB0aGF0LCB3ZSBjb21iaW5lIGFkZGl0aW9uYWwgdG9rZW5zIHRvIGJhbGFuY2UgdGhlIHF1b3RlLlxuXG4gIHZhciBBVFRSX1JFID0gbmV3IFJlZ0V4cChcbiAgICAnXlxcXFxzKicgK1xuICAgICcoWy0uOlxcXFx3XSspJyArICAgICAgICAgICAgIC8vIDEgPSBBdHRyaWJ1dGUgbmFtZVxuICAgICcoPzonICsgKFxuICAgICAgJ1xcXFxzKig9KVxcXFxzKicgKyAgICAgICAgICAgLy8gMiA9IElzIHRoZXJlIGEgdmFsdWU/XG4gICAgICAnKCcgKyAoICAgICAgICAgICAgICAgICAgIC8vIDMgPSBBdHRyaWJ1dGUgdmFsdWVcbiAgICAgICAgLy8gVE9ETyhmZWxpeDhhKTogbWF5YmUgdXNlIGJhY2tyZWYgdG8gbWF0Y2ggcXVvdGVzXG4gICAgICAgICcoXFxcIilbXlxcXCJdKihcXFwifCQpJyArICAgIC8vIDQsIDUgPSBEb3VibGUtcXVvdGVkIHN0cmluZ1xuICAgICAgICAnfCcgK1xuICAgICAgICAnKFxcJylbXlxcJ10qKFxcJ3wkKScgKyAgICAvLyA2LCA3ID0gU2luZ2xlLXF1b3RlZCBzdHJpbmdcbiAgICAgICAgJ3wnICtcbiAgICAgICAgLy8gUG9zaXRpdmUgbG9va2FoZWFkIHRvIHByZXZlbnQgaW50ZXJwcmV0YXRpb24gb2ZcbiAgICAgICAgLy8gPGZvbyBhPSBiPWM+IGFzIDxmb28gYT0nYj1jJz5cbiAgICAgICAgLy8gVE9ETyhmZWxpeDhhKTogbWlnaHQgYmUgYWJsZSB0byBkcm9wIHRoaXMgY2FzZVxuICAgICAgICAnKD89W2Etel1bLVxcXFx3XSpcXFxccyo9KScgK1xuICAgICAgICAnfCcgK1xuICAgICAgICAvLyBVbnF1b3RlZCB2YWx1ZSB0aGF0IGlzbid0IGFuIGF0dHJpYnV0ZSBuYW1lXG4gICAgICAgIC8vIChzaW5jZSB3ZSBkaWRuJ3QgbWF0Y2ggdGhlIHBvc2l0aXZlIGxvb2thaGVhZCBhYm92ZSlcbiAgICAgICAgJ1teXFxcIlxcJ1xcXFxzXSonICkgK1xuICAgICAgJyknICkgK1xuICAgICcpPycsXG4gICAgJ2knKTtcblxuICAvLyBmYWxzZSBvbiBJRTw9OCwgdHJ1ZSBvbiBtb3N0IG90aGVyIGJyb3dzZXJzXG4gIHZhciBzcGxpdFdpbGxDYXB0dXJlID0gKCdhLGInLnNwbGl0KC8oLCkvKS5sZW5ndGggPT09IDMpO1xuXG4gIC8vIGJpdG1hc2sgZm9yIHRhZ3Mgd2l0aCBzcGVjaWFsIHBhcnNpbmcsIGxpa2UgPHNjcmlwdD4gYW5kIDx0ZXh0YXJlYT5cbiAgdmFyIEVGTEFHU19URVhUID0gaHRtbDQuZWZsYWdzWydDREFUQSddIHwgaHRtbDQuZWZsYWdzWydSQ0RBVEEnXTtcblxuICAvKipcbiAgICogR2l2ZW4gYSBTQVgtbGlrZSBldmVudCBoYW5kbGVyLCBwcm9kdWNlIGEgZnVuY3Rpb24gdGhhdCBmZWVkcyB0aG9zZVxuICAgKiBldmVudHMgYW5kIGEgcGFyYW1ldGVyIHRvIHRoZSBldmVudCBoYW5kbGVyLlxuICAgKlxuICAgKiBUaGUgZXZlbnQgaGFuZGxlciBoYXMgdGhlIGZvcm06e0Bjb2RlXG4gICAqIHtcbiAgICogICAvLyBOYW1lIGlzIGFuIHVwcGVyLWNhc2UgSFRNTCB0YWcgbmFtZS4gIEF0dHJpYnMgaXMgYW4gYXJyYXkgb2ZcbiAgICogICAvLyBhbHRlcm5hdGluZyB1cHBlci1jYXNlIGF0dHJpYnV0ZSBuYW1lcywgYW5kIGF0dHJpYnV0ZSB2YWx1ZXMuICBUaGVcbiAgICogICAvLyBhdHRyaWJzIGFycmF5IGlzIHJldXNlZCBieSB0aGUgcGFyc2VyLiAgUGFyYW0gaXMgdGhlIHZhbHVlIHBhc3NlZCB0b1xuICAgKiAgIC8vIHRoZSBzYXhQYXJzZXIuXG4gICAqICAgc3RhcnRUYWc6IGZ1bmN0aW9uIChuYW1lLCBhdHRyaWJzLCBwYXJhbSkgeyAuLi4gfSxcbiAgICogICBlbmRUYWc6ICAgZnVuY3Rpb24gKG5hbWUsIHBhcmFtKSB7IC4uLiB9LFxuICAgKiAgIHBjZGF0YTogICBmdW5jdGlvbiAodGV4dCwgcGFyYW0pIHsgLi4uIH0sXG4gICAqICAgcmNkYXRhOiAgIGZ1bmN0aW9uICh0ZXh0LCBwYXJhbSkgeyAuLi4gfSxcbiAgICogICBjZGF0YTogICAgZnVuY3Rpb24gKHRleHQsIHBhcmFtKSB7IC4uLiB9LFxuICAgKiAgIHN0YXJ0RG9jOiBmdW5jdGlvbiAocGFyYW0pIHsgLi4uIH0sXG4gICAqICAgZW5kRG9jOiAgIGZ1bmN0aW9uIChwYXJhbSkgeyAuLi4gfVxuICAgKiB9fVxuICAgKlxuICAgKiBAcGFyYW0ge09iamVjdH0gaGFuZGxlciBhIHJlY29yZCBjb250YWluaW5nIGV2ZW50IGhhbmRsZXJzLlxuICAgKiBAcmV0dXJuIHtmdW5jdGlvbihzdHJpbmcsIE9iamVjdCl9IEEgZnVuY3Rpb24gdGhhdCB0YWtlcyBhIGNodW5rIG9mIEhUTUxcbiAgICogICAgIGFuZCBhIHBhcmFtZXRlci4gIFRoZSBwYXJhbWV0ZXIgaXMgcGFzc2VkIG9uIHRvIHRoZSBoYW5kbGVyIG1ldGhvZHMuXG4gICAqL1xuICBmdW5jdGlvbiBtYWtlU2F4UGFyc2VyKGhhbmRsZXIpIHtcbiAgICAvLyBBY2NlcHQgcXVvdGVkIG9yIHVucXVvdGVkIGtleXMgKENsb3N1cmUgY29tcGF0KVxuICAgIHZhciBoY29weSA9IHtcbiAgICAgIGNkYXRhOiBoYW5kbGVyLmNkYXRhIHx8IGhhbmRsZXJbJ2NkYXRhJ10sXG4gICAgICBjb21tZW50OiBoYW5kbGVyLmNvbW1lbnQgfHwgaGFuZGxlclsnY29tbWVudCddLFxuICAgICAgZW5kRG9jOiBoYW5kbGVyLmVuZERvYyB8fCBoYW5kbGVyWydlbmREb2MnXSxcbiAgICAgIGVuZFRhZzogaGFuZGxlci5lbmRUYWcgfHwgaGFuZGxlclsnZW5kVGFnJ10sXG4gICAgICBwY2RhdGE6IGhhbmRsZXIucGNkYXRhIHx8IGhhbmRsZXJbJ3BjZGF0YSddLFxuICAgICAgcmNkYXRhOiBoYW5kbGVyLnJjZGF0YSB8fCBoYW5kbGVyWydyY2RhdGEnXSxcbiAgICAgIHN0YXJ0RG9jOiBoYW5kbGVyLnN0YXJ0RG9jIHx8IGhhbmRsZXJbJ3N0YXJ0RG9jJ10sXG4gICAgICBzdGFydFRhZzogaGFuZGxlci5zdGFydFRhZyB8fCBoYW5kbGVyWydzdGFydFRhZyddXG4gICAgfTtcbiAgICByZXR1cm4gZnVuY3Rpb24oaHRtbFRleHQsIHBhcmFtKSB7XG4gICAgICByZXR1cm4gcGFyc2UoaHRtbFRleHQsIGhjb3B5LCBwYXJhbSk7XG4gICAgfTtcbiAgfVxuXG4gIC8vIFBhcnNpbmcgc3RyYXRlZ3kgaXMgdG8gc3BsaXQgaW5wdXQgaW50byBwYXJ0cyB0aGF0IG1pZ2h0IGJlIGxleGljYWxseVxuICAvLyBtZWFuaW5nZnVsIChldmVyeSBcIj5cIiBiZWNvbWVzIGEgc2VwYXJhdGUgcGFydCksIGFuZCB0aGVuIHJlY29tYmluZVxuICAvLyBwYXJ0cyBpZiB3ZSBkaXNjb3ZlciB0aGV5J3JlIGluIGEgZGlmZmVyZW50IGNvbnRleHQuXG5cbiAgLy8gVE9ETyhmZWxpeDhhKTogU2lnbmlmaWNhbnQgcGVyZm9ybWFuY2UgcmVncmVzc2lvbnMgZnJvbSAtbGVnYWN5LFxuICAvLyB0ZXN0ZWQgb25cbiAgLy8gICAgQ2hyb21lIDE4LjBcbiAgLy8gICAgRmlyZWZveCAxMS4wXG4gIC8vICAgIElFIDYsIDcsIDgsIDlcbiAgLy8gICAgT3BlcmEgMTEuNjFcbiAgLy8gICAgU2FmYXJpIDUuMS4zXG4gIC8vIE1hbnkgb2YgdGhlc2UgYXJlIHVudXN1YWwgcGF0dGVybnMgdGhhdCBhcmUgbGluZWFybHkgc2xvd2VyIGFuZCBzdGlsbFxuICAvLyBwcmV0dHkgZmFzdCAoZWcgMW1zIHRvIDVtcyksIHNvIG5vdCBuZWNlc3NhcmlseSB3b3J0aCBmaXhpbmcuXG5cbiAgLy8gVE9ETyhmZWxpeDhhKTogXCI8c2NyaXB0PiAmJiAmJiAmJiAuLi4gPFxcL3NjcmlwdD5cIiBpcyBzbG93ZXIgb24gYWxsXG4gIC8vIGJyb3dzZXJzLiAgVGhlIGhvdHNwb3QgaXMgaHRtbFNwbGl0LlxuXG4gIC8vIFRPRE8oZmVsaXg4YSk6IFwiPHAgdGl0bGU9Jz4+Pj4uLi4nPjxcXC9wPlwiIGlzIHNsb3dlciBvbiBhbGwgYnJvd3NlcnMuXG4gIC8vIFRoaXMgaXMgcGFydGx5IGh0bWxTcGxpdCwgYnV0IHRoZSBob3RzcG90IGlzIHBhcnNlVGFnQW5kQXR0cnMuXG5cbiAgLy8gVE9ETyhmZWxpeDhhKTogXCI8YT48XFwvYT48YT48XFwvYT4uLi5cIiBpcyBzbG93ZXIgb24gSUU5LlxuICAvLyBcIjxhPjE8XFwvYT48YT4xPFxcL2E+Li4uXCIgaXMgZmFzdGVyLCBcIjxhPjxcXC9hPjI8YT48XFwvYT4yLi4uXCIgaXMgZmFzdGVyLlxuXG4gIC8vIFRPRE8oZmVsaXg4YSk6IFwiPHA8cDxwLi4uXCIgaXMgc2xvd2VyIG9uIElFWzYtOF1cblxuICB2YXIgY29udGludWF0aW9uTWFya2VyID0ge307XG4gIGZ1bmN0aW9uIHBhcnNlKGh0bWxUZXh0LCBoYW5kbGVyLCBwYXJhbSkge1xuICAgIHZhciBtLCBwLCB0YWdOYW1lO1xuICAgIHZhciBwYXJ0cyA9IGh0bWxTcGxpdChodG1sVGV4dCk7XG4gICAgdmFyIHN0YXRlID0ge1xuICAgICAgbm9Nb3JlR1Q6IGZhbHNlLFxuICAgICAgbm9Nb3JlRW5kQ29tbWVudHM6IGZhbHNlXG4gICAgfTtcbiAgICBwYXJzZUNQUyhoYW5kbGVyLCBwYXJ0cywgMCwgc3RhdGUsIHBhcmFtKTtcbiAgfVxuXG4gIGZ1bmN0aW9uIGNvbnRpbnVhdGlvbk1ha2VyKGgsIHBhcnRzLCBpbml0aWFsLCBzdGF0ZSwgcGFyYW0pIHtcbiAgICByZXR1cm4gZnVuY3Rpb24gKCkge1xuICAgICAgcGFyc2VDUFMoaCwgcGFydHMsIGluaXRpYWwsIHN0YXRlLCBwYXJhbSk7XG4gICAgfTtcbiAgfVxuXG4gIGZ1bmN0aW9uIHBhcnNlQ1BTKGgsIHBhcnRzLCBpbml0aWFsLCBzdGF0ZSwgcGFyYW0pIHtcbiAgICB0cnkge1xuICAgICAgaWYgKGguc3RhcnREb2MgJiYgaW5pdGlhbCA9PSAwKSB7IGguc3RhcnREb2MocGFyYW0pOyB9XG4gICAgICB2YXIgbSwgcCwgdGFnTmFtZTtcbiAgICAgIGZvciAodmFyIHBvcyA9IGluaXRpYWwsIGVuZCA9IHBhcnRzLmxlbmd0aDsgcG9zIDwgZW5kOykge1xuICAgICAgICB2YXIgY3VycmVudCA9IHBhcnRzW3BvcysrXTtcbiAgICAgICAgdmFyIG5leHQgPSBwYXJ0c1twb3NdO1xuICAgICAgICBzd2l0Y2ggKGN1cnJlbnQpIHtcbiAgICAgICAgY2FzZSAnJic6XG4gICAgICAgICAgaWYgKEVOVElUWV9SRV8yLnRlc3QobmV4dCkpIHtcbiAgICAgICAgICAgIGlmIChoLnBjZGF0YSkge1xuICAgICAgICAgICAgICBoLnBjZGF0YSgnJicgKyBuZXh0LCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLFxuICAgICAgICAgICAgICAgIGNvbnRpbnVhdGlvbk1ha2VyKGgsIHBhcnRzLCBwb3MsIHN0YXRlLCBwYXJhbSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcG9zKys7XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChoLnBjZGF0YSkgeyBoLnBjZGF0YShcIiZhbXA7XCIsIHBhcmFtLCBjb250aW51YXRpb25NYXJrZXIsXG4gICAgICAgICAgICAgICAgY29udGludWF0aW9uTWFrZXIoaCwgcGFydHMsIHBvcywgc3RhdGUsIHBhcmFtKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICc8XFwvJzpcbiAgICAgICAgICBpZiAobSA9IC9eKFstXFx3Ol0rKVteXFwnXFxcIl0qLy5leGVjKG5leHQpKSB7XG4gICAgICAgICAgICBpZiAobVswXS5sZW5ndGggPT09IG5leHQubGVuZ3RoICYmIHBhcnRzW3BvcyArIDFdID09PSAnPicpIHtcbiAgICAgICAgICAgICAgLy8gZmFzdCBjYXNlLCBubyBhdHRyaWJ1dGUgcGFyc2luZyBuZWVkZWRcbiAgICAgICAgICAgICAgcG9zICs9IDI7XG4gICAgICAgICAgICAgIHRhZ05hbWUgPSBtWzFdLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgICAgICAgIGlmIChoLmVuZFRhZykge1xuICAgICAgICAgICAgICAgIGguZW5kVGFnKHRhZ05hbWUsIHBhcmFtLCBjb250aW51YXRpb25NYXJrZXIsXG4gICAgICAgICAgICAgICAgICBjb250aW51YXRpb25NYWtlcihoLCBwYXJ0cywgcG9zLCBzdGF0ZSwgcGFyYW0pKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgLy8gc2xvdyBjYXNlLCBuZWVkIHRvIHBhcnNlIGF0dHJpYnV0ZXNcbiAgICAgICAgICAgICAgLy8gVE9ETyhmZWxpeDhhKTogZG8gd2UgcmVhbGx5IGNhcmUgYWJvdXQgbWlzcGFyc2luZyB0aGlzP1xuICAgICAgICAgICAgICBwb3MgPSBwYXJzZUVuZFRhZyhcbiAgICAgICAgICAgICAgICBwYXJ0cywgcG9zLCBoLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLCBzdGF0ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChoLnBjZGF0YSkge1xuICAgICAgICAgICAgICBoLnBjZGF0YSgnJmx0Oy8nLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLFxuICAgICAgICAgICAgICAgIGNvbnRpbnVhdGlvbk1ha2VyKGgsIHBhcnRzLCBwb3MsIHN0YXRlLCBwYXJhbSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnPCc6XG4gICAgICAgICAgaWYgKG0gPSAvXihbLVxcdzpdKylcXHMqXFwvPy8uZXhlYyhuZXh0KSkge1xuICAgICAgICAgICAgaWYgKG1bMF0ubGVuZ3RoID09PSBuZXh0Lmxlbmd0aCAmJiBwYXJ0c1twb3MgKyAxXSA9PT0gJz4nKSB7XG4gICAgICAgICAgICAgIC8vIGZhc3QgY2FzZSwgbm8gYXR0cmlidXRlIHBhcnNpbmcgbmVlZGVkXG4gICAgICAgICAgICAgIHBvcyArPSAyO1xuICAgICAgICAgICAgICB0YWdOYW1lID0gbVsxXS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICAgICAgICBpZiAoaC5zdGFydFRhZykge1xuICAgICAgICAgICAgICAgIGguc3RhcnRUYWcodGFnTmFtZSwgW10sIHBhcmFtLCBjb250aW51YXRpb25NYXJrZXIsXG4gICAgICAgICAgICAgICAgICBjb250aW51YXRpb25NYWtlcihoLCBwYXJ0cywgcG9zLCBzdGF0ZSwgcGFyYW0pKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAvLyB0YWdzIGxpa2UgPHNjcmlwdD4gYW5kIDx0ZXh0YXJlYT4gaGF2ZSBzcGVjaWFsIHBhcnNpbmdcbiAgICAgICAgICAgICAgdmFyIGVmbGFncyA9IGh0bWw0LkVMRU1FTlRTW3RhZ05hbWVdO1xuICAgICAgICAgICAgICBpZiAoZWZsYWdzICYgRUZMQUdTX1RFWFQpIHtcbiAgICAgICAgICAgICAgICB2YXIgdGFnID0geyBuYW1lOiB0YWdOYW1lLCBuZXh0OiBwb3MsIGVmbGFnczogZWZsYWdzIH07XG4gICAgICAgICAgICAgICAgcG9zID0gcGFyc2VUZXh0KFxuICAgICAgICAgICAgICAgICAgcGFydHMsIHRhZywgaCwgcGFyYW0sIGNvbnRpbnVhdGlvbk1hcmtlciwgc3RhdGUpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAvLyBzbG93IGNhc2UsIG5lZWQgdG8gcGFyc2UgYXR0cmlidXRlc1xuICAgICAgICAgICAgICBwb3MgPSBwYXJzZVN0YXJ0VGFnKFxuICAgICAgICAgICAgICAgIHBhcnRzLCBwb3MsIGgsIHBhcmFtLCBjb250aW51YXRpb25NYXJrZXIsIHN0YXRlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKGgucGNkYXRhKSB7XG4gICAgICAgICAgICAgIGgucGNkYXRhKCcmbHQ7JywgcGFyYW0sIGNvbnRpbnVhdGlvbk1hcmtlcixcbiAgICAgICAgICAgICAgICBjb250aW51YXRpb25NYWtlcihoLCBwYXJ0cywgcG9zLCBzdGF0ZSwgcGFyYW0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJzxcXCEtLSc6XG4gICAgICAgICAgLy8gVGhlIHBhdGhvbG9naWNhbCBjYXNlIGlzIG4gY29waWVzIG9mICc8XFwhLS0nIHdpdGhvdXQgJy0tPicsIGFuZFxuICAgICAgICAgIC8vIHJlcGVhdGVkIGZhaWx1cmUgdG8gZmluZCAnLS0+JyBpcyBxdWFkcmF0aWMuICBXZSBhdm9pZCB0aGF0IGJ5XG4gICAgICAgICAgLy8gcmVtZW1iZXJpbmcgd2hlbiBzZWFyY2ggZm9yICctLT4nIGZhaWxzLlxuICAgICAgICAgIGlmICghc3RhdGUubm9Nb3JlRW5kQ29tbWVudHMpIHtcbiAgICAgICAgICAgIC8vIEEgY29tbWVudCA8XFwhLS14LS0+IGlzIHNwbGl0IGludG8gdGhyZWUgdG9rZW5zOlxuICAgICAgICAgICAgLy8gICAnPFxcIS0tJywgJ3gtLScsICc+J1xuICAgICAgICAgICAgLy8gV2Ugd2FudCB0byBmaW5kIHRoZSBuZXh0ICc+JyB0b2tlbiB0aGF0IGhhcyBhIHByZWNlZGluZyAnLS0nLlxuICAgICAgICAgICAgLy8gcG9zIGlzIGF0IHRoZSAneC0tJy5cbiAgICAgICAgICAgIGZvciAocCA9IHBvcyArIDE7IHAgPCBlbmQ7IHArKykge1xuICAgICAgICAgICAgICBpZiAocGFydHNbcF0gPT09ICc+JyAmJiAvLS0kLy50ZXN0KHBhcnRzW3AgLSAxXSkpIHsgYnJlYWs7IH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChwIDwgZW5kKSB7XG4gICAgICAgICAgICAgIGlmIChoLmNvbW1lbnQpIHtcbiAgICAgICAgICAgICAgICB2YXIgY29tbWVudCA9IHBhcnRzLnNsaWNlKHBvcywgcCkuam9pbignJyk7XG4gICAgICAgICAgICAgICAgaC5jb21tZW50KFxuICAgICAgICAgICAgICAgICAgY29tbWVudC5zdWJzdHIoMCwgY29tbWVudC5sZW5ndGggLSAyKSwgcGFyYW0sXG4gICAgICAgICAgICAgICAgICBjb250aW51YXRpb25NYXJrZXIsXG4gICAgICAgICAgICAgICAgICBjb250aW51YXRpb25NYWtlcihoLCBwYXJ0cywgcCArIDEsIHN0YXRlLCBwYXJhbSkpO1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHBvcyA9IHAgKyAxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc3RhdGUubm9Nb3JlRW5kQ29tbWVudHMgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoc3RhdGUubm9Nb3JlRW5kQ29tbWVudHMpIHtcbiAgICAgICAgICAgIGlmIChoLnBjZGF0YSkge1xuICAgICAgICAgICAgICBoLnBjZGF0YSgnJmx0OyEtLScsIHBhcmFtLCBjb250aW51YXRpb25NYXJrZXIsXG4gICAgICAgICAgICAgICAgY29udGludWF0aW9uTWFrZXIoaCwgcGFydHMsIHBvcywgc3RhdGUsIHBhcmFtKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICc8XFwhJzpcbiAgICAgICAgICBpZiAoIS9eXFx3Ly50ZXN0KG5leHQpKSB7XG4gICAgICAgICAgICBpZiAoaC5wY2RhdGEpIHtcbiAgICAgICAgICAgICAgaC5wY2RhdGEoJyZsdDshJywgcGFyYW0sIGNvbnRpbnVhdGlvbk1hcmtlcixcbiAgICAgICAgICAgICAgICBjb250aW51YXRpb25NYWtlcihoLCBwYXJ0cywgcG9zLCBzdGF0ZSwgcGFyYW0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy8gc2ltaWxhciB0byBub01vcmVFbmRDb21tZW50IGxvZ2ljXG4gICAgICAgICAgICBpZiAoIXN0YXRlLm5vTW9yZUdUKSB7XG4gICAgICAgICAgICAgIGZvciAocCA9IHBvcyArIDE7IHAgPCBlbmQ7IHArKykge1xuICAgICAgICAgICAgICAgIGlmIChwYXJ0c1twXSA9PT0gJz4nKSB7IGJyZWFrOyB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaWYgKHAgPCBlbmQpIHtcbiAgICAgICAgICAgICAgICBwb3MgPSBwICsgMTtcbiAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzdGF0ZS5ub01vcmVHVCA9IHRydWU7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChzdGF0ZS5ub01vcmVHVCkge1xuICAgICAgICAgICAgICBpZiAoaC5wY2RhdGEpIHtcbiAgICAgICAgICAgICAgICBoLnBjZGF0YSgnJmx0OyEnLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLFxuICAgICAgICAgICAgICAgICAgY29udGludWF0aW9uTWFrZXIoaCwgcGFydHMsIHBvcywgc3RhdGUsIHBhcmFtKSk7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJzw/JzpcbiAgICAgICAgICAvLyBzaW1pbGFyIHRvIG5vTW9yZUVuZENvbW1lbnQgbG9naWNcbiAgICAgICAgICBpZiAoIXN0YXRlLm5vTW9yZUdUKSB7XG4gICAgICAgICAgICBmb3IgKHAgPSBwb3MgKyAxOyBwIDwgZW5kOyBwKyspIHtcbiAgICAgICAgICAgICAgaWYgKHBhcnRzW3BdID09PSAnPicpIHsgYnJlYWs7IH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChwIDwgZW5kKSB7XG4gICAgICAgICAgICAgIHBvcyA9IHAgKyAxO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgc3RhdGUubm9Nb3JlR1QgPSB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoc3RhdGUubm9Nb3JlR1QpIHtcbiAgICAgICAgICAgIGlmIChoLnBjZGF0YSkge1xuICAgICAgICAgICAgICBoLnBjZGF0YSgnJmx0Oz8nLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLFxuICAgICAgICAgICAgICAgIGNvbnRpbnVhdGlvbk1ha2VyKGgsIHBhcnRzLCBwb3MsIHN0YXRlLCBwYXJhbSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnPic6XG4gICAgICAgICAgaWYgKGgucGNkYXRhKSB7XG4gICAgICAgICAgICBoLnBjZGF0YShcIiZndDtcIiwgcGFyYW0sIGNvbnRpbnVhdGlvbk1hcmtlcixcbiAgICAgICAgICAgICAgY29udGludWF0aW9uTWFrZXIoaCwgcGFydHMsIHBvcywgc3RhdGUsIHBhcmFtKSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICcnOlxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICBkZWZhdWx0OlxuICAgICAgICAgIGlmIChoLnBjZGF0YSkge1xuICAgICAgICAgICAgaC5wY2RhdGEoY3VycmVudCwgcGFyYW0sIGNvbnRpbnVhdGlvbk1hcmtlcixcbiAgICAgICAgICAgICAgY29udGludWF0aW9uTWFrZXIoaCwgcGFydHMsIHBvcywgc3RhdGUsIHBhcmFtKSk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAoaC5lbmREb2MpIHsgaC5lbmREb2MocGFyYW0pOyB9XG4gICAgfSBjYXRjaCAoZSkge1xuICAgICAgaWYgKGUgIT09IGNvbnRpbnVhdGlvbk1hcmtlcikgeyB0aHJvdyBlOyB9XG4gICAgfVxuICB9XG5cbiAgLy8gU3BsaXQgc3RyIGludG8gcGFydHMgZm9yIHRoZSBodG1sIHBhcnNlci5cbiAgZnVuY3Rpb24gaHRtbFNwbGl0KHN0cikge1xuICAgIC8vIGNhbid0IGhvaXN0IHRoaXMgb3V0IG9mIHRoZSBmdW5jdGlvbiBiZWNhdXNlIG9mIHRoZSByZS5leGVjIGxvb3AuXG4gICAgdmFyIHJlID0gLyg8XFwvfDxcXCEtLXw8WyE/XXxbJjw+XSkvZztcbiAgICBzdHIgKz0gJyc7XG4gICAgaWYgKHNwbGl0V2lsbENhcHR1cmUpIHtcbiAgICAgIHJldHVybiBzdHIuc3BsaXQocmUpO1xuICAgIH0gZWxzZSB7XG4gICAgICB2YXIgcGFydHMgPSBbXTtcbiAgICAgIHZhciBsYXN0UG9zID0gMDtcbiAgICAgIHZhciBtO1xuICAgICAgd2hpbGUgKChtID0gcmUuZXhlYyhzdHIpKSAhPT0gbnVsbCkge1xuICAgICAgICBwYXJ0cy5wdXNoKHN0ci5zdWJzdHJpbmcobGFzdFBvcywgbS5pbmRleCkpO1xuICAgICAgICBwYXJ0cy5wdXNoKG1bMF0pO1xuICAgICAgICBsYXN0UG9zID0gbS5pbmRleCArIG1bMF0ubGVuZ3RoO1xuICAgICAgfVxuICAgICAgcGFydHMucHVzaChzdHIuc3Vic3RyaW5nKGxhc3RQb3MpKTtcbiAgICAgIHJldHVybiBwYXJ0cztcbiAgICB9XG4gIH1cblxuICBmdW5jdGlvbiBwYXJzZUVuZFRhZyhwYXJ0cywgcG9zLCBoLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLCBzdGF0ZSkge1xuICAgIHZhciB0YWcgPSBwYXJzZVRhZ0FuZEF0dHJzKHBhcnRzLCBwb3MpO1xuICAgIC8vIGRyb3AgdW5jbG9zZWQgdGFnc1xuICAgIGlmICghdGFnKSB7IHJldHVybiBwYXJ0cy5sZW5ndGg7IH1cbiAgICBpZiAoaC5lbmRUYWcpIHtcbiAgICAgIGguZW5kVGFnKHRhZy5uYW1lLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLFxuICAgICAgICBjb250aW51YXRpb25NYWtlcihoLCBwYXJ0cywgcG9zLCBzdGF0ZSwgcGFyYW0pKTtcbiAgICB9XG4gICAgcmV0dXJuIHRhZy5uZXh0O1xuICB9XG5cbiAgZnVuY3Rpb24gcGFyc2VTdGFydFRhZyhwYXJ0cywgcG9zLCBoLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLCBzdGF0ZSkge1xuICAgIHZhciB0YWcgPSBwYXJzZVRhZ0FuZEF0dHJzKHBhcnRzLCBwb3MpO1xuICAgIC8vIGRyb3AgdW5jbG9zZWQgdGFnc1xuICAgIGlmICghdGFnKSB7IHJldHVybiBwYXJ0cy5sZW5ndGg7IH1cbiAgICBpZiAoaC5zdGFydFRhZykge1xuICAgICAgaC5zdGFydFRhZyh0YWcubmFtZSwgdGFnLmF0dHJzLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLFxuICAgICAgICBjb250aW51YXRpb25NYWtlcihoLCBwYXJ0cywgdGFnLm5leHQsIHN0YXRlLCBwYXJhbSkpO1xuICAgIH1cbiAgICAvLyB0YWdzIGxpa2UgPHNjcmlwdD4gYW5kIDx0ZXh0YXJlYT4gaGF2ZSBzcGVjaWFsIHBhcnNpbmdcbiAgICBpZiAodGFnLmVmbGFncyAmIEVGTEFHU19URVhUKSB7XG4gICAgICByZXR1cm4gcGFyc2VUZXh0KHBhcnRzLCB0YWcsIGgsIHBhcmFtLCBjb250aW51YXRpb25NYXJrZXIsIHN0YXRlKTtcbiAgICB9IGVsc2Uge1xuICAgICAgcmV0dXJuIHRhZy5uZXh0O1xuICAgIH1cbiAgfVxuXG4gIHZhciBlbmRUYWdSZSA9IHt9O1xuXG4gIC8vIFRhZ3MgbGlrZSA8c2NyaXB0PiBhbmQgPHRleHRhcmVhPiBhcmUgZmxhZ2dlZCBhcyBDREFUQSBvciBSQ0RBVEEsXG4gIC8vIHdoaWNoIG1lYW5zIGV2ZXJ5dGhpbmcgaXMgdGV4dCB1bnRpbCB3ZSBzZWUgdGhlIGNvcnJlY3QgY2xvc2luZyB0YWcuXG4gIGZ1bmN0aW9uIHBhcnNlVGV4dChwYXJ0cywgdGFnLCBoLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLCBzdGF0ZSkge1xuICAgIHZhciBlbmQgPSBwYXJ0cy5sZW5ndGg7XG4gICAgaWYgKCFlbmRUYWdSZS5oYXNPd25Qcm9wZXJ0eSh0YWcubmFtZSkpIHtcbiAgICAgIGVuZFRhZ1JlW3RhZy5uYW1lXSA9IG5ldyBSZWdFeHAoJ14nICsgdGFnLm5hbWUgKyAnKD86W1xcXFxzXFxcXC9dfCQpJywgJ2knKTtcbiAgICB9XG4gICAgdmFyIHJlID0gZW5kVGFnUmVbdGFnLm5hbWVdO1xuICAgIHZhciBmaXJzdCA9IHRhZy5uZXh0O1xuICAgIHZhciBwID0gdGFnLm5leHQgKyAxO1xuICAgIGZvciAoOyBwIDwgZW5kOyBwKyspIHtcbiAgICAgIGlmIChwYXJ0c1twIC0gMV0gPT09ICc8XFwvJyAmJiByZS50ZXN0KHBhcnRzW3BdKSkgeyBicmVhazsgfVxuICAgIH1cbiAgICBpZiAocCA8IGVuZCkgeyBwIC09IDE7IH1cbiAgICB2YXIgYnVmID0gcGFydHMuc2xpY2UoZmlyc3QsIHApLmpvaW4oJycpO1xuICAgIGlmICh0YWcuZWZsYWdzICYgaHRtbDQuZWZsYWdzWydDREFUQSddKSB7XG4gICAgICBpZiAoaC5jZGF0YSkge1xuICAgICAgICBoLmNkYXRhKGJ1ZiwgcGFyYW0sIGNvbnRpbnVhdGlvbk1hcmtlcixcbiAgICAgICAgICBjb250aW51YXRpb25NYWtlcihoLCBwYXJ0cywgcCwgc3RhdGUsIHBhcmFtKSk7XG4gICAgICB9XG4gICAgfSBlbHNlIGlmICh0YWcuZWZsYWdzICYgaHRtbDQuZWZsYWdzWydSQ0RBVEEnXSkge1xuICAgICAgaWYgKGgucmNkYXRhKSB7XG4gICAgICAgIGgucmNkYXRhKG5vcm1hbGl6ZVJDRGF0YShidWYpLCBwYXJhbSwgY29udGludWF0aW9uTWFya2VyLFxuICAgICAgICAgIGNvbnRpbnVhdGlvbk1ha2VyKGgsIHBhcnRzLCBwLCBzdGF0ZSwgcGFyYW0pKTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKCdidWcnKTtcbiAgICB9XG4gICAgcmV0dXJuIHA7XG4gIH1cblxuICAvLyBhdCB0aGlzIHBvaW50LCBwYXJ0c1twb3MtMV0gaXMgZWl0aGVyIFwiPFwiIG9yIFwiPFxcL1wiLlxuICBmdW5jdGlvbiBwYXJzZVRhZ0FuZEF0dHJzKHBhcnRzLCBwb3MpIHtcbiAgICB2YXIgbSA9IC9eKFstXFx3Ol0rKS8uZXhlYyhwYXJ0c1twb3NdKTtcbiAgICB2YXIgdGFnID0ge307XG4gICAgdGFnLm5hbWUgPSBtWzFdLnRvTG93ZXJDYXNlKCk7XG4gICAgdGFnLmVmbGFncyA9IGh0bWw0LkVMRU1FTlRTW3RhZy5uYW1lXTtcbiAgICB2YXIgYnVmID0gcGFydHNbcG9zXS5zdWJzdHIobVswXS5sZW5ndGgpO1xuICAgIC8vIEZpbmQgdGhlIG5leHQgJz4nLiAgV2Ugb3B0aW1pc3RpY2FsbHkgYXNzdW1lIHRoaXMgJz4nIGlzIG5vdCBpbiBhXG4gICAgLy8gcXVvdGVkIGNvbnRleHQsIGFuZCBmdXJ0aGVyIGRvd24gd2UgZml4IHRoaW5ncyB1cCBpZiBpdCB0dXJucyBvdXQgdG9cbiAgICAvLyBiZSBxdW90ZWQuXG4gICAgdmFyIHAgPSBwb3MgKyAxO1xuICAgIHZhciBlbmQgPSBwYXJ0cy5sZW5ndGg7XG4gICAgZm9yICg7IHAgPCBlbmQ7IHArKykge1xuICAgICAgaWYgKHBhcnRzW3BdID09PSAnPicpIHsgYnJlYWs7IH1cbiAgICAgIGJ1ZiArPSBwYXJ0c1twXTtcbiAgICB9XG4gICAgaWYgKGVuZCA8PSBwKSB7IHJldHVybiB2b2lkIDA7IH1cbiAgICB2YXIgYXR0cnMgPSBbXTtcbiAgICB3aGlsZSAoYnVmICE9PSAnJykge1xuICAgICAgbSA9IEFUVFJfUkUuZXhlYyhidWYpO1xuICAgICAgaWYgKCFtKSB7XG4gICAgICAgIC8vIE5vIGF0dHJpYnV0ZSBmb3VuZDogc2tpcCBnYXJiYWdlXG4gICAgICAgIGJ1ZiA9IGJ1Zi5yZXBsYWNlKC9eW1xcc1xcU11bXmEtelxcc10qLywgJycpO1xuXG4gICAgICB9IGVsc2UgaWYgKChtWzRdICYmICFtWzVdKSB8fCAobVs2XSAmJiAhbVs3XSkpIHtcbiAgICAgICAgLy8gVW50ZXJtaW5hdGVkIHF1b3RlOiBzbHVycCB0byB0aGUgbmV4dCB1bnF1b3RlZCAnPidcbiAgICAgICAgdmFyIHF1b3RlID0gbVs0XSB8fCBtWzZdO1xuICAgICAgICB2YXIgc2F3UXVvdGUgPSBmYWxzZTtcbiAgICAgICAgdmFyIGFidWYgPSBbYnVmLCBwYXJ0c1twKytdXTtcbiAgICAgICAgZm9yICg7IHAgPCBlbmQ7IHArKykge1xuICAgICAgICAgIGlmIChzYXdRdW90ZSkge1xuICAgICAgICAgICAgaWYgKHBhcnRzW3BdID09PSAnPicpIHsgYnJlYWs7IH1cbiAgICAgICAgICB9IGVsc2UgaWYgKDAgPD0gcGFydHNbcF0uaW5kZXhPZihxdW90ZSkpIHtcbiAgICAgICAgICAgIHNhd1F1b3RlID0gdHJ1ZTtcbiAgICAgICAgICB9XG4gICAgICAgICAgYWJ1Zi5wdXNoKHBhcnRzW3BdKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBTbHVycCBmYWlsZWQ6IGxvc2UgdGhlIGdhcmJhZ2VcbiAgICAgICAgaWYgKGVuZCA8PSBwKSB7IGJyZWFrOyB9XG4gICAgICAgIC8vIE90aGVyd2lzZSByZXRyeSBhdHRyaWJ1dGUgcGFyc2luZ1xuICAgICAgICBidWYgPSBhYnVmLmpvaW4oJycpO1xuICAgICAgICBjb250aW51ZTtcblxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgLy8gV2UgaGF2ZSBhbiBhdHRyaWJ1dGVcbiAgICAgICAgdmFyIGFOYW1lID0gbVsxXS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICB2YXIgYVZhbHVlID0gbVsyXSA/IGRlY29kZVZhbHVlKG1bM10pIDogJyc7XG4gICAgICAgIGF0dHJzLnB1c2goYU5hbWUsIGFWYWx1ZSk7XG4gICAgICAgIGJ1ZiA9IGJ1Zi5zdWJzdHIobVswXS5sZW5ndGgpO1xuICAgICAgfVxuICAgIH1cbiAgICB0YWcuYXR0cnMgPSBhdHRycztcbiAgICB0YWcubmV4dCA9IHAgKyAxO1xuICAgIHJldHVybiB0YWc7XG4gIH1cblxuICBmdW5jdGlvbiBkZWNvZGVWYWx1ZSh2KSB7XG4gICAgdmFyIHEgPSB2LmNoYXJDb2RlQXQoMCk7XG4gICAgaWYgKHEgPT09IDB4MjIgfHwgcSA9PT0gMHgyNykgeyAvLyBcIiBvciAnXG4gICAgICB2ID0gdi5zdWJzdHIoMSwgdi5sZW5ndGggLSAyKTtcbiAgICB9XG4gICAgcmV0dXJuIHVuZXNjYXBlRW50aXRpZXMoc3RyaXBOVUxzKHYpKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZXR1cm5zIGEgZnVuY3Rpb24gdGhhdCBzdHJpcHMgdW5zYWZlIHRhZ3MgYW5kIGF0dHJpYnV0ZXMgZnJvbSBodG1sLlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9uKHN0cmluZywgQXJyYXkuPHN0cmluZz4pOiA/QXJyYXkuPHN0cmluZz59IHRhZ1BvbGljeVxuICAgKiAgICAgQSBmdW5jdGlvbiB0aGF0IHRha2VzICh0YWdOYW1lLCBhdHRyaWJzW10pLCB3aGVyZSB0YWdOYW1lIGlzIGEga2V5IGluXG4gICAqICAgICBodG1sNC5FTEVNRU5UUyBhbmQgYXR0cmlicyBpcyBhbiBhcnJheSBvZiBhbHRlcm5hdGluZyBhdHRyaWJ1dGUgbmFtZXNcbiAgICogICAgIGFuZCB2YWx1ZXMuICBJdCBzaG91bGQgcmV0dXJuIGEgcmVjb3JkIChhcyBmb2xsb3dzKSwgb3IgbnVsbCB0byBkZWxldGVcbiAgICogICAgIHRoZSBlbGVtZW50LiAgSXQncyBva2F5IGZvciB0YWdQb2xpY3kgdG8gbW9kaWZ5IHRoZSBhdHRyaWJzIGFycmF5LFxuICAgKiAgICAgYnV0IHRoZSBzYW1lIGFycmF5IGlzIHJldXNlZCwgc28gaXQgc2hvdWxkIG5vdCBiZSBoZWxkIGJldHdlZW4gY2FsbHMuXG4gICAqICAgICBSZWNvcmQga2V5czpcbiAgICogICAgICAgIGF0dHJpYnM6IChyZXF1aXJlZCkgU2FuaXRpemVkIGF0dHJpYnV0ZXMgYXJyYXkuXG4gICAqICAgICAgICB0YWdOYW1lOiBSZXBsYWNlbWVudCB0YWcgbmFtZS5cbiAgICogQHJldHVybiB7ZnVuY3Rpb24oc3RyaW5nLCBBcnJheSl9IEEgZnVuY3Rpb24gdGhhdCBzYW5pdGl6ZXMgYSBzdHJpbmcgb2ZcbiAgICogICAgIEhUTUwgYW5kIGFwcGVuZHMgcmVzdWx0IHN0cmluZ3MgdG8gdGhlIHNlY29uZCBhcmd1bWVudCwgYW4gYXJyYXkuXG4gICAqL1xuICBmdW5jdGlvbiBtYWtlSHRtbFNhbml0aXplcih0YWdQb2xpY3kpIHtcbiAgICB2YXIgc3RhY2s7XG4gICAgdmFyIGlnbm9yaW5nO1xuICAgIHZhciBlbWl0ID0gZnVuY3Rpb24gKHRleHQsIG91dCkge1xuICAgICAgaWYgKCFpZ25vcmluZykgeyBvdXQucHVzaCh0ZXh0KTsgfVxuICAgIH07XG4gICAgcmV0dXJuIG1ha2VTYXhQYXJzZXIoe1xuICAgICAgJ3N0YXJ0RG9jJzogZnVuY3Rpb24oXykge1xuICAgICAgICBzdGFjayA9IFtdO1xuICAgICAgICBpZ25vcmluZyA9IGZhbHNlO1xuICAgICAgfSxcbiAgICAgICdzdGFydFRhZyc6IGZ1bmN0aW9uKHRhZ05hbWVPcmlnLCBhdHRyaWJzLCBvdXQpIHtcbiAgICAgICAgaWYgKGlnbm9yaW5nKSB7IHJldHVybjsgfVxuICAgICAgICBpZiAoIWh0bWw0LkVMRU1FTlRTLmhhc093blByb3BlcnR5KHRhZ05hbWVPcmlnKSkgeyByZXR1cm47IH1cbiAgICAgICAgdmFyIGVmbGFnc09yaWcgPSBodG1sNC5FTEVNRU5UU1t0YWdOYW1lT3JpZ107XG4gICAgICAgIGlmIChlZmxhZ3NPcmlnICYgaHRtbDQuZWZsYWdzWydGT0xEQUJMRSddKSB7XG4gICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGRlY2lzaW9uID0gdGFnUG9saWN5KHRhZ05hbWVPcmlnLCBhdHRyaWJzKTtcbiAgICAgICAgaWYgKCFkZWNpc2lvbikge1xuICAgICAgICAgIGlnbm9yaW5nID0gIShlZmxhZ3NPcmlnICYgaHRtbDQuZWZsYWdzWydFTVBUWSddKTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIGRlY2lzaW9uICE9PSAnb2JqZWN0Jykge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcigndGFnUG9saWN5IGRpZCBub3QgcmV0dXJuIG9iamVjdCAob2xkIEFQST8pJyk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCdhdHRyaWJzJyBpbiBkZWNpc2lvbikge1xuICAgICAgICAgIGF0dHJpYnMgPSBkZWNpc2lvblsnYXR0cmlicyddO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRocm93IG5ldyBFcnJvcigndGFnUG9saWN5IGdhdmUgbm8gYXR0cmlicycpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBlZmxhZ3NSZXA7XG4gICAgICAgIHZhciB0YWdOYW1lUmVwO1xuICAgICAgICBpZiAoJ3RhZ05hbWUnIGluIGRlY2lzaW9uKSB7XG4gICAgICAgICAgdGFnTmFtZVJlcCA9IGRlY2lzaW9uWyd0YWdOYW1lJ107XG4gICAgICAgICAgZWZsYWdzUmVwID0gaHRtbDQuRUxFTUVOVFNbdGFnTmFtZVJlcF07XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdGFnTmFtZVJlcCA9IHRhZ05hbWVPcmlnO1xuICAgICAgICAgIGVmbGFnc1JlcCA9IGVmbGFnc09yaWc7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVE9ETyhtaWtlc2FtdWVsKTogcmVseWluZyBvbiB0YWdQb2xpY3kgbm90IHRvIGluc2VydCB1bnNhZmVcbiAgICAgICAgLy8gYXR0cmlidXRlIG5hbWVzLlxuXG4gICAgICAgIC8vIElmIHRoaXMgaXMgYW4gb3B0aW9uYWwtZW5kLXRhZyBlbGVtZW50IGFuZCBlaXRoZXIgdGhpcyBlbGVtZW50IG9yIGl0c1xuICAgICAgICAvLyBwcmV2aW91cyBsaWtlIHNpYmxpbmcgd2FzIHJld3JpdHRlbiwgdGhlbiBpbnNlcnQgYSBjbG9zZSB0YWcgdG9cbiAgICAgICAgLy8gcHJlc2VydmUgc3RydWN0dXJlLlxuICAgICAgICBpZiAoZWZsYWdzT3JpZyAmIGh0bWw0LmVmbGFnc1snT1BUSU9OQUxfRU5EVEFHJ10pIHtcbiAgICAgICAgICB2YXIgb25TdGFjayA9IHN0YWNrW3N0YWNrLmxlbmd0aCAtIDFdO1xuICAgICAgICAgIGlmIChvblN0YWNrICYmIG9uU3RhY2sub3JpZyA9PT0gdGFnTmFtZU9yaWcgJiZcbiAgICAgICAgICAgICAgKG9uU3RhY2sucmVwICE9PSB0YWdOYW1lUmVwIHx8IHRhZ05hbWVPcmlnICE9PSB0YWdOYW1lUmVwKSkge1xuICAgICAgICAgICAgICAgIG91dC5wdXNoKCc8XFwvJywgb25TdGFjay5yZXAsICc+Jyk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCEoZWZsYWdzT3JpZyAmIGh0bWw0LmVmbGFnc1snRU1QVFknXSkpIHtcbiAgICAgICAgICBzdGFjay5wdXNoKHtvcmlnOiB0YWdOYW1lT3JpZywgcmVwOiB0YWdOYW1lUmVwfSk7XG4gICAgICAgIH1cblxuICAgICAgICBvdXQucHVzaCgnPCcsIHRhZ05hbWVSZXApO1xuICAgICAgICBmb3IgKHZhciBpID0gMCwgbiA9IGF0dHJpYnMubGVuZ3RoOyBpIDwgbjsgaSArPSAyKSB7XG4gICAgICAgICAgdmFyIGF0dHJpYk5hbWUgPSBhdHRyaWJzW2ldLFxuICAgICAgICAgICAgICB2YWx1ZSA9IGF0dHJpYnNbaSArIDFdO1xuICAgICAgICAgIGlmICh2YWx1ZSAhPT0gbnVsbCAmJiB2YWx1ZSAhPT0gdm9pZCAwKSB7XG4gICAgICAgICAgICBvdXQucHVzaCgnICcsIGF0dHJpYk5hbWUsICc9XCInLCBlc2NhcGVBdHRyaWIodmFsdWUpLCAnXCInKTtcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgb3V0LnB1c2goJz4nKTtcblxuICAgICAgICBpZiAoKGVmbGFnc09yaWcgJiBodG1sNC5lZmxhZ3NbJ0VNUFRZJ10pXG4gICAgICAgICAgICAmJiAhKGVmbGFnc1JlcCAmIGh0bWw0LmVmbGFnc1snRU1QVFknXSkpIHtcbiAgICAgICAgICAvLyByZXBsYWNlbWVudCBpcyBub24tZW1wdHksIHN5bnRoZXNpemUgZW5kIHRhZ1xuICAgICAgICAgIG91dC5wdXNoKCc8XFwvJywgdGFnTmFtZVJlcCwgJz4nKTtcbiAgICAgICAgfVxuICAgICAgfSxcbiAgICAgICdlbmRUYWcnOiBmdW5jdGlvbih0YWdOYW1lLCBvdXQpIHtcbiAgICAgICAgaWYgKGlnbm9yaW5nKSB7XG4gICAgICAgICAgaWdub3JpbmcgPSBmYWxzZTtcbiAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFodG1sNC5FTEVNRU5UUy5oYXNPd25Qcm9wZXJ0eSh0YWdOYW1lKSkgeyByZXR1cm47IH1cbiAgICAgICAgdmFyIGVmbGFncyA9IGh0bWw0LkVMRU1FTlRTW3RhZ05hbWVdO1xuICAgICAgICBpZiAoIShlZmxhZ3MgJiAoaHRtbDQuZWZsYWdzWydFTVBUWSddIHwgaHRtbDQuZWZsYWdzWydGT0xEQUJMRSddKSkpIHtcbiAgICAgICAgICB2YXIgaW5kZXg7XG4gICAgICAgICAgaWYgKGVmbGFncyAmIGh0bWw0LmVmbGFnc1snT1BUSU9OQUxfRU5EVEFHJ10pIHtcbiAgICAgICAgICAgIGZvciAoaW5kZXggPSBzdGFjay5sZW5ndGg7IC0taW5kZXggPj0gMDspIHtcbiAgICAgICAgICAgICAgdmFyIHN0YWNrRWxPcmlnVGFnID0gc3RhY2tbaW5kZXhdLm9yaWc7XG4gICAgICAgICAgICAgIGlmIChzdGFja0VsT3JpZ1RhZyA9PT0gdGFnTmFtZSkgeyBicmVhazsgfVxuICAgICAgICAgICAgICBpZiAoIShodG1sNC5FTEVNRU5UU1tzdGFja0VsT3JpZ1RhZ10gJlxuICAgICAgICAgICAgICAgICAgICBodG1sNC5lZmxhZ3NbJ09QVElPTkFMX0VORFRBRyddKSkge1xuICAgICAgICAgICAgICAgIC8vIERvbid0IHBvcCBub24gb3B0aW9uYWwgZW5kIHRhZ3MgbG9va2luZyBmb3IgYSBtYXRjaC5cbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZm9yIChpbmRleCA9IHN0YWNrLmxlbmd0aDsgLS1pbmRleCA+PSAwOykge1xuICAgICAgICAgICAgICBpZiAoc3RhY2tbaW5kZXhdLm9yaWcgPT09IHRhZ05hbWUpIHsgYnJlYWs7IH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGluZGV4IDwgMCkgeyByZXR1cm47IH0gIC8vIE5vdCBvcGVuZWQuXG4gICAgICAgICAgZm9yICh2YXIgaSA9IHN0YWNrLmxlbmd0aDsgLS1pID4gaW5kZXg7KSB7XG4gICAgICAgICAgICB2YXIgc3RhY2tFbFJlcFRhZyA9IHN0YWNrW2ldLnJlcDtcbiAgICAgICAgICAgIGlmICghKGh0bWw0LkVMRU1FTlRTW3N0YWNrRWxSZXBUYWddICZcbiAgICAgICAgICAgICAgICAgIGh0bWw0LmVmbGFnc1snT1BUSU9OQUxfRU5EVEFHJ10pKSB7XG4gICAgICAgICAgICAgIG91dC5wdXNoKCc8XFwvJywgc3RhY2tFbFJlcFRhZywgJz4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgaWYgKGluZGV4IDwgc3RhY2subGVuZ3RoKSB7XG4gICAgICAgICAgICB0YWdOYW1lID0gc3RhY2tbaW5kZXhdLnJlcDtcbiAgICAgICAgICB9XG4gICAgICAgICAgc3RhY2subGVuZ3RoID0gaW5kZXg7XG4gICAgICAgICAgb3V0LnB1c2goJzxcXC8nLCB0YWdOYW1lLCAnPicpO1xuICAgICAgICB9XG4gICAgICB9LFxuICAgICAgJ3BjZGF0YSc6IGVtaXQsXG4gICAgICAncmNkYXRhJzogZW1pdCxcbiAgICAgICdjZGF0YSc6IGVtaXQsXG4gICAgICAnZW5kRG9jJzogZnVuY3Rpb24ob3V0KSB7XG4gICAgICAgIGZvciAoOyBzdGFjay5sZW5ndGg7IHN0YWNrLmxlbmd0aC0tKSB7XG4gICAgICAgICAgb3V0LnB1c2goJzxcXC8nLCBzdGFja1tzdGFjay5sZW5ndGggLSAxXS5yZXAsICc+Jyk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9KTtcbiAgfVxuXG4gIHZhciBBTExPV0VEX1VSSV9TQ0hFTUVTID0gL14oPzpodHRwcz98bWFpbHRvfGRhdGEpJC9pO1xuXG4gIGZ1bmN0aW9uIHNhZmVVcmkodXJpLCBlZmZlY3QsIGx0eXBlLCBoaW50cywgbmFpdmVVcmlSZXdyaXRlcikge1xuICAgIGlmICghbmFpdmVVcmlSZXdyaXRlcikgeyByZXR1cm4gbnVsbDsgfVxuICAgIHRyeSB7XG4gICAgICB2YXIgcGFyc2VkID0gVVJJLnBhcnNlKCcnICsgdXJpKTtcbiAgICAgIGlmIChwYXJzZWQpIHtcbiAgICAgICAgaWYgKCFwYXJzZWQuaGFzU2NoZW1lKCkgfHxcbiAgICAgICAgICAgIEFMTE9XRURfVVJJX1NDSEVNRVMudGVzdChwYXJzZWQuZ2V0U2NoZW1lKCkpKSB7XG4gICAgICAgICAgdmFyIHNhZmUgPSBuYWl2ZVVyaVJld3JpdGVyKHBhcnNlZCwgZWZmZWN0LCBsdHlwZSwgaGludHMpO1xuICAgICAgICAgIHJldHVybiBzYWZlID8gc2FmZS50b1N0cmluZygpIDogbnVsbDtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4gbnVsbDtcbiAgfVxuXG4gIGZ1bmN0aW9uIGxvZyhsb2dnZXIsIHRhZ05hbWUsIGF0dHJpYk5hbWUsIG9sZFZhbHVlLCBuZXdWYWx1ZSkge1xuICAgIGlmICghYXR0cmliTmFtZSkge1xuICAgICAgbG9nZ2VyKHRhZ05hbWUgKyBcIiByZW1vdmVkXCIsIHtcbiAgICAgICAgY2hhbmdlOiBcInJlbW92ZWRcIixcbiAgICAgICAgdGFnTmFtZTogdGFnTmFtZVxuICAgICAgfSk7XG4gICAgfVxuICAgIGlmIChvbGRWYWx1ZSAhPT0gbmV3VmFsdWUpIHtcbiAgICAgIHZhciBjaGFuZ2VkID0gXCJjaGFuZ2VkXCI7XG4gICAgICBpZiAob2xkVmFsdWUgJiYgIW5ld1ZhbHVlKSB7XG4gICAgICAgIGNoYW5nZWQgPSBcInJlbW92ZWRcIjtcbiAgICAgIH0gZWxzZSBpZiAoIW9sZFZhbHVlICYmIG5ld1ZhbHVlKSAge1xuICAgICAgICBjaGFuZ2VkID0gXCJhZGRlZFwiO1xuICAgICAgfVxuICAgICAgbG9nZ2VyKHRhZ05hbWUgKyBcIi5cIiArIGF0dHJpYk5hbWUgKyBcIiBcIiArIGNoYW5nZWQsIHtcbiAgICAgICAgY2hhbmdlOiBjaGFuZ2VkLFxuICAgICAgICB0YWdOYW1lOiB0YWdOYW1lLFxuICAgICAgICBhdHRyaWJOYW1lOiBhdHRyaWJOYW1lLFxuICAgICAgICBvbGRWYWx1ZTogb2xkVmFsdWUsXG4gICAgICAgIG5ld1ZhbHVlOiBuZXdWYWx1ZVxuICAgICAgfSk7XG4gICAgfVxuICB9XG5cbiAgZnVuY3Rpb24gbG9va3VwQXR0cmlidXRlKG1hcCwgdGFnTmFtZSwgYXR0cmliTmFtZSkge1xuICAgIHZhciBhdHRyaWJLZXk7XG4gICAgYXR0cmliS2V5ID0gdGFnTmFtZSArICc6OicgKyBhdHRyaWJOYW1lO1xuICAgIGlmIChtYXAuaGFzT3duUHJvcGVydHkoYXR0cmliS2V5KSkge1xuICAgICAgcmV0dXJuIG1hcFthdHRyaWJLZXldO1xuICAgIH1cbiAgICBhdHRyaWJLZXkgPSAnKjo6JyArIGF0dHJpYk5hbWU7XG4gICAgaWYgKG1hcC5oYXNPd25Qcm9wZXJ0eShhdHRyaWJLZXkpKSB7XG4gICAgICByZXR1cm4gbWFwW2F0dHJpYktleV07XG4gICAgfVxuICAgIHJldHVybiB2b2lkIDA7XG4gIH1cbiAgZnVuY3Rpb24gZ2V0QXR0cmlidXRlVHlwZSh0YWdOYW1lLCBhdHRyaWJOYW1lKSB7XG4gICAgcmV0dXJuIGxvb2t1cEF0dHJpYnV0ZShodG1sNC5BVFRSSUJTLCB0YWdOYW1lLCBhdHRyaWJOYW1lKTtcbiAgfVxuICBmdW5jdGlvbiBnZXRMb2FkZXJUeXBlKHRhZ05hbWUsIGF0dHJpYk5hbWUpIHtcbiAgICByZXR1cm4gbG9va3VwQXR0cmlidXRlKGh0bWw0LkxPQURFUlRZUEVTLCB0YWdOYW1lLCBhdHRyaWJOYW1lKTtcbiAgfVxuICBmdW5jdGlvbiBnZXRVcmlFZmZlY3QodGFnTmFtZSwgYXR0cmliTmFtZSkge1xuICAgIHJldHVybiBsb29rdXBBdHRyaWJ1dGUoaHRtbDQuVVJJRUZGRUNUUywgdGFnTmFtZSwgYXR0cmliTmFtZSk7XG4gIH1cblxuICAvKipcbiAgICogU2FuaXRpemVzIGF0dHJpYnV0ZXMgb24gYW4gSFRNTCB0YWcuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSB0YWdOYW1lIEFuIEhUTUwgdGFnIG5hbWUgaW4gbG93ZXJjYXNlLlxuICAgKiBAcGFyYW0ge0FycmF5Ljw/c3RyaW5nPn0gYXR0cmlicyBBbiBhcnJheSBvZiBhbHRlcm5hdGluZyBuYW1lcyBhbmQgdmFsdWVzLlxuICAgKiBAcGFyYW0gez9mdW5jdGlvbig/c3RyaW5nKTogP3N0cmluZ30gb3B0X25haXZlVXJpUmV3cml0ZXIgQSB0cmFuc2Zvcm0gdG9cbiAgICogICAgIGFwcGx5IHRvIFVSSSBhdHRyaWJ1dGVzOyBpdCBjYW4gcmV0dXJuIGEgbmV3IHN0cmluZyB2YWx1ZSwgb3IgbnVsbCB0b1xuICAgKiAgICAgZGVsZXRlIHRoZSBhdHRyaWJ1dGUuICBJZiB1bnNwZWNpZmllZCwgVVJJIGF0dHJpYnV0ZXMgYXJlIGRlbGV0ZWQuXG4gICAqIEBwYXJhbSB7ZnVuY3Rpb24oP3N0cmluZyk6ID9zdHJpbmd9IG9wdF9ubVRva2VuUG9saWN5IEEgdHJhbnNmb3JtIHRvIGFwcGx5XG4gICAqICAgICB0byBhdHRyaWJ1dGVzIGNvbnRhaW5pbmcgSFRNTCBuYW1lcywgZWxlbWVudCBJRHMsIGFuZCBzcGFjZS1zZXBhcmF0ZWRcbiAgICogICAgIGxpc3RzIG9mIGNsYXNzZXM7IGl0IGNhbiByZXR1cm4gYSBuZXcgc3RyaW5nIHZhbHVlLCBvciBudWxsIHRvIGRlbGV0ZVxuICAgKiAgICAgdGhlIGF0dHJpYnV0ZS4gIElmIHVuc3BlY2lmaWVkLCB0aGVzZSBhdHRyaWJ1dGVzIGFyZSBrZXB0IHVuY2hhbmdlZC5cbiAgICogQHJldHVybiB7QXJyYXkuPD9zdHJpbmc+fSBUaGUgc2FuaXRpemVkIGF0dHJpYnV0ZXMgYXMgYSBsaXN0IG9mIGFsdGVybmF0aW5nXG4gICAqICAgICBuYW1lcyBhbmQgdmFsdWVzLCB3aGVyZSBhIG51bGwgdmFsdWUgbWVhbnMgdG8gb21pdCB0aGUgYXR0cmlidXRlLlxuICAgKi9cbiAgZnVuY3Rpb24gc2FuaXRpemVBdHRyaWJzKHRhZ05hbWUsIGF0dHJpYnMsXG4gICAgb3B0X25haXZlVXJpUmV3cml0ZXIsIG9wdF9ubVRva2VuUG9saWN5LCBvcHRfbG9nZ2VyKSB7XG4gICAgLy8gVE9ETyhmZWxpeDhhKTogaXQncyBvYm5veGlvdXMgdGhhdCBkb21hZG8gZHVwbGljYXRlcyBtdWNoIG9mIHRoaXNcbiAgICAvLyBUT0RPKGZlbGl4OGEpOiBtYXliZSBjb25zaXN0ZW50bHkgZW5mb3JjZSBjb25zdHJhaW50cyBsaWtlIHRhcmdldD1cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGF0dHJpYnMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgIHZhciBhdHRyaWJOYW1lID0gYXR0cmlic1tpXTtcbiAgICAgIHZhciB2YWx1ZSA9IGF0dHJpYnNbaSArIDFdO1xuICAgICAgdmFyIG9sZFZhbHVlID0gdmFsdWU7XG4gICAgICB2YXIgYXR5cGUgPSBudWxsLCBhdHRyaWJLZXk7XG4gICAgICBpZiAoKGF0dHJpYktleSA9IHRhZ05hbWUgKyAnOjonICsgYXR0cmliTmFtZSxcbiAgICAgICAgICAgaHRtbDQuQVRUUklCUy5oYXNPd25Qcm9wZXJ0eShhdHRyaWJLZXkpKSB8fFxuICAgICAgICAgIChhdHRyaWJLZXkgPSAnKjo6JyArIGF0dHJpYk5hbWUsXG4gICAgICAgICAgIGh0bWw0LkFUVFJJQlMuaGFzT3duUHJvcGVydHkoYXR0cmliS2V5KSkpIHtcbiAgICAgICAgYXR5cGUgPSBodG1sNC5BVFRSSUJTW2F0dHJpYktleV07XG4gICAgICB9XG4gICAgICBpZiAoYXR5cGUgIT09IG51bGwpIHtcbiAgICAgICAgc3dpdGNoIChhdHlwZSkge1xuICAgICAgICAgIGNhc2UgaHRtbDQuYXR5cGVbJ05PTkUnXTogYnJlYWs7XG4gICAgICAgICAgY2FzZSBodG1sNC5hdHlwZVsnU0NSSVBUJ106XG4gICAgICAgICAgICB2YWx1ZSA9IG51bGw7XG4gICAgICAgICAgICBpZiAob3B0X2xvZ2dlcikge1xuICAgICAgICAgICAgICBsb2cob3B0X2xvZ2dlciwgdGFnTmFtZSwgYXR0cmliTmFtZSwgb2xkVmFsdWUsIHZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIGNhc2UgaHRtbDQuYXR5cGVbJ1NUWUxFJ106XG4gICAgICAgICAgICBpZiAoJ3VuZGVmaW5lZCcgPT09IHR5cGVvZiBwYXJzZUNzc0RlY2xhcmF0aW9ucykge1xuICAgICAgICAgICAgICB2YWx1ZSA9IG51bGw7XG4gICAgICAgICAgICAgIGlmIChvcHRfbG9nZ2VyKSB7XG4gICAgICAgICAgICAgICAgbG9nKG9wdF9sb2dnZXIsIHRhZ05hbWUsIGF0dHJpYk5hbWUsIG9sZFZhbHVlLCB2YWx1ZSk7XG5cdCAgICAgIH1cbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YXIgc2FuaXRpemVkRGVjbGFyYXRpb25zID0gW107XG4gICAgICAgICAgICBwYXJzZUNzc0RlY2xhcmF0aW9ucyhcbiAgICAgICAgICAgICAgICB2YWx1ZSxcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBkZWNsYXJhdGlvbjogZnVuY3Rpb24gKHByb3BlcnR5LCB0b2tlbnMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG5vcm1Qcm9wID0gcHJvcGVydHkudG9Mb3dlckNhc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNjaGVtYSA9IGNzc1NjaGVtYVtub3JtUHJvcF07XG4gICAgICAgICAgICAgICAgICAgIGlmICghc2NoZW1hKSB7XG4gICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHNhbml0aXplQ3NzUHJvcGVydHkoXG4gICAgICAgICAgICAgICAgICAgICAgICBub3JtUHJvcCwgc2NoZW1hLCB0b2tlbnMsXG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRfbmFpdmVVcmlSZXdyaXRlclxuICAgICAgICAgICAgICAgICAgICAgICAgPyBmdW5jdGlvbiAodXJsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHNhZmVVcmkoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVybCwgaHRtbDQudWVmZmVjdHMuU0FNRV9ET0NVTUVOVCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaHRtbDQubHR5cGVzLlNBTkRCT1hFRCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiVFlQRVwiOiBcIkNTU1wiLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiQ1NTX1BST1BcIjogbm9ybVByb3BcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfSwgb3B0X25haXZlVXJpUmV3cml0ZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICA6IG51bGwpO1xuICAgICAgICAgICAgICAgICAgICBzYW5pdGl6ZWREZWNsYXJhdGlvbnMucHVzaChwcm9wZXJ0eSArICc6ICcgKyB0b2tlbnMuam9pbignICcpKTtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHZhbHVlID0gc2FuaXRpemVkRGVjbGFyYXRpb25zLmxlbmd0aCA+IDAgP1xuICAgICAgICAgICAgICBzYW5pdGl6ZWREZWNsYXJhdGlvbnMuam9pbignIDsgJykgOiBudWxsO1xuICAgICAgICAgICAgaWYgKG9wdF9sb2dnZXIpIHtcbiAgICAgICAgICAgICAgbG9nKG9wdF9sb2dnZXIsIHRhZ05hbWUsIGF0dHJpYk5hbWUsIG9sZFZhbHVlLCB2YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlIGh0bWw0LmF0eXBlWydJRCddOlxuICAgICAgICAgIGNhc2UgaHRtbDQuYXR5cGVbJ0lEUkVGJ106XG4gICAgICAgICAgY2FzZSBodG1sNC5hdHlwZVsnSURSRUZTJ106XG4gICAgICAgICAgY2FzZSBodG1sNC5hdHlwZVsnR0xPQkFMX05BTUUnXTpcbiAgICAgICAgICBjYXNlIGh0bWw0LmF0eXBlWydMT0NBTF9OQU1FJ106XG4gICAgICAgICAgY2FzZSBodG1sNC5hdHlwZVsnQ0xBU1NFUyddOlxuICAgICAgICAgICAgdmFsdWUgPSBvcHRfbm1Ub2tlblBvbGljeSA/IG9wdF9ubVRva2VuUG9saWN5KHZhbHVlKSA6IHZhbHVlO1xuICAgICAgICAgICAgaWYgKG9wdF9sb2dnZXIpIHtcbiAgICAgICAgICAgICAgbG9nKG9wdF9sb2dnZXIsIHRhZ05hbWUsIGF0dHJpYk5hbWUsIG9sZFZhbHVlLCB2YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlIGh0bWw0LmF0eXBlWydVUkknXTpcbiAgICAgICAgICAgIHZhbHVlID0gc2FmZVVyaSh2YWx1ZSxcbiAgICAgICAgICAgICAgZ2V0VXJpRWZmZWN0KHRhZ05hbWUsIGF0dHJpYk5hbWUpLFxuICAgICAgICAgICAgICBnZXRMb2FkZXJUeXBlKHRhZ05hbWUsIGF0dHJpYk5hbWUpLFxuICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgXCJUWVBFXCI6IFwiTUFSS1VQXCIsXG4gICAgICAgICAgICAgICAgXCJYTUxfQVRUUlwiOiBhdHRyaWJOYW1lLFxuICAgICAgICAgICAgICAgIFwiWE1MX1RBR1wiOiB0YWdOYW1lXG4gICAgICAgICAgICAgIH0sIG9wdF9uYWl2ZVVyaVJld3JpdGVyKTtcbiAgICAgICAgICAgICAgaWYgKG9wdF9sb2dnZXIpIHtcbiAgICAgICAgICAgICAgbG9nKG9wdF9sb2dnZXIsIHRhZ05hbWUsIGF0dHJpYk5hbWUsIG9sZFZhbHVlLCB2YWx1ZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICBjYXNlIGh0bWw0LmF0eXBlWydVUklfRlJBR01FTlQnXTpcbiAgICAgICAgICAgIGlmICh2YWx1ZSAmJiAnIycgPT09IHZhbHVlLmNoYXJBdCgwKSkge1xuICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlLnN1YnN0cmluZygxKTsgIC8vIHJlbW92ZSB0aGUgbGVhZGluZyAnIydcbiAgICAgICAgICAgICAgdmFsdWUgPSBvcHRfbm1Ub2tlblBvbGljeSA/IG9wdF9ubVRva2VuUG9saWN5KHZhbHVlKSA6IHZhbHVlO1xuICAgICAgICAgICAgICBpZiAodmFsdWUgIT09IG51bGwgJiYgdmFsdWUgIT09IHZvaWQgMCkge1xuICAgICAgICAgICAgICAgIHZhbHVlID0gJyMnICsgdmFsdWU7ICAvLyByZXN0b3JlIHRoZSBsZWFkaW5nICcjJ1xuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB2YWx1ZSA9IG51bGw7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAob3B0X2xvZ2dlcikge1xuICAgICAgICAgICAgICBsb2cob3B0X2xvZ2dlciwgdGFnTmFtZSwgYXR0cmliTmFtZSwgb2xkVmFsdWUsIHZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICB2YWx1ZSA9IG51bGw7XG4gICAgICAgICAgICBpZiAob3B0X2xvZ2dlcikge1xuICAgICAgICAgICAgICBsb2cob3B0X2xvZ2dlciwgdGFnTmFtZSwgYXR0cmliTmFtZSwgb2xkVmFsdWUsIHZhbHVlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB2YWx1ZSA9IG51bGw7XG4gICAgICAgIGlmIChvcHRfbG9nZ2VyKSB7XG4gICAgICAgICAgbG9nKG9wdF9sb2dnZXIsIHRhZ05hbWUsIGF0dHJpYk5hbWUsIG9sZFZhbHVlLCB2YWx1ZSk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIGF0dHJpYnNbaSArIDFdID0gdmFsdWU7XG4gICAgfVxuICAgIHJldHVybiBhdHRyaWJzO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWF0ZXMgYSB0YWcgcG9saWN5IHRoYXQgb21pdHMgYWxsIHRhZ3MgbWFya2VkIFVOU0FGRSBpbiBodG1sNC1kZWZzLmpzXG4gICAqIGFuZCBhcHBsaWVzIHRoZSBkZWZhdWx0IGF0dHJpYnV0ZSBzYW5pdGl6ZXIgd2l0aCB0aGUgc3VwcGxpZWQgcG9saWN5IGZvclxuICAgKiBVUkkgYXR0cmlidXRlcyBhbmQgTk1UT0tFTiBhdHRyaWJ1dGVzLlxuICAgKiBAcGFyYW0gez9mdW5jdGlvbig/c3RyaW5nKTogP3N0cmluZ30gb3B0X25haXZlVXJpUmV3cml0ZXIgQSB0cmFuc2Zvcm0gdG9cbiAgICogICAgIGFwcGx5IHRvIFVSSSBhdHRyaWJ1dGVzLiAgSWYgbm90IGdpdmVuLCBVUkkgYXR0cmlidXRlcyBhcmUgZGVsZXRlZC5cbiAgICogQHBhcmFtIHtmdW5jdGlvbig/c3RyaW5nKTogP3N0cmluZ30gb3B0X25tVG9rZW5Qb2xpY3kgQSB0cmFuc2Zvcm0gdG8gYXBwbHlcbiAgICogICAgIHRvIGF0dHJpYnV0ZXMgY29udGFpbmluZyBIVE1MIG5hbWVzLCBlbGVtZW50IElEcywgYW5kIHNwYWNlLXNlcGFyYXRlZFxuICAgKiAgICAgbGlzdHMgb2YgY2xhc3Nlcy4gIElmIG5vdCBnaXZlbiwgc3VjaCBhdHRyaWJ1dGVzIGFyZSBsZWZ0IHVuY2hhbmdlZC5cbiAgICogQHJldHVybiB7ZnVuY3Rpb24oc3RyaW5nLCBBcnJheS48P3N0cmluZz4pfSBBIHRhZ1BvbGljeSBzdWl0YWJsZSBmb3JcbiAgICogICAgIHBhc3NpbmcgdG8gaHRtbC5zYW5pdGl6ZS5cbiAgICovXG4gIGZ1bmN0aW9uIG1ha2VUYWdQb2xpY3koXG4gICAgb3B0X25haXZlVXJpUmV3cml0ZXIsIG9wdF9ubVRva2VuUG9saWN5LCBvcHRfbG9nZ2VyKSB7XG4gICAgcmV0dXJuIGZ1bmN0aW9uKHRhZ05hbWUsIGF0dHJpYnMpIHtcbiAgICAgIGlmICghKGh0bWw0LkVMRU1FTlRTW3RhZ05hbWVdICYgaHRtbDQuZWZsYWdzWydVTlNBRkUnXSkpIHtcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAnYXR0cmlicyc6IHNhbml0aXplQXR0cmlicyh0YWdOYW1lLCBhdHRyaWJzLFxuICAgICAgICAgICAgb3B0X25haXZlVXJpUmV3cml0ZXIsIG9wdF9ubVRva2VuUG9saWN5LCBvcHRfbG9nZ2VyKVxuICAgICAgICB9O1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgaWYgKG9wdF9sb2dnZXIpIHtcbiAgICAgICAgICBsb2cob3B0X2xvZ2dlciwgdGFnTmFtZSwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCk7XG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFNhbml0aXplcyBIVE1MIHRhZ3MgYW5kIGF0dHJpYnV0ZXMgYWNjb3JkaW5nIHRvIGEgZ2l2ZW4gcG9saWN5LlxuICAgKiBAcGFyYW0ge3N0cmluZ30gaW5wdXRIdG1sIFRoZSBIVE1MIHRvIHNhbml0aXplLlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9uKHN0cmluZywgQXJyYXkuPD9zdHJpbmc+KX0gdGFnUG9saWN5IEEgZnVuY3Rpb24gdGhhdFxuICAgKiAgICAgZGVjaWRlcyB3aGljaCB0YWdzIHRvIGFjY2VwdCBhbmQgc2FuaXRpemVzIHRoZWlyIGF0dHJpYnV0ZXMgKHNlZVxuICAgKiAgICAgbWFrZUh0bWxTYW5pdGl6ZXIgYWJvdmUgZm9yIGRldGFpbHMpLlxuICAgKiBAcmV0dXJuIHtzdHJpbmd9IFRoZSBzYW5pdGl6ZWQgSFRNTC5cbiAgICovXG4gIGZ1bmN0aW9uIHNhbml0aXplV2l0aFBvbGljeShpbnB1dEh0bWwsIHRhZ1BvbGljeSkge1xuICAgIHZhciBvdXRwdXRBcnJheSA9IFtdO1xuICAgIG1ha2VIdG1sU2FuaXRpemVyKHRhZ1BvbGljeSkoaW5wdXRIdG1sLCBvdXRwdXRBcnJheSk7XG4gICAgcmV0dXJuIG91dHB1dEFycmF5LmpvaW4oJycpO1xuICB9XG5cbiAgLyoqXG4gICAqIFN0cmlwcyB1bnNhZmUgdGFncyBhbmQgYXR0cmlidXRlcyBmcm9tIEhUTUwuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBpbnB1dEh0bWwgVGhlIEhUTUwgdG8gc2FuaXRpemUuXG4gICAqIEBwYXJhbSB7P2Z1bmN0aW9uKD9zdHJpbmcpOiA/c3RyaW5nfSBvcHRfbmFpdmVVcmlSZXdyaXRlciBBIHRyYW5zZm9ybSB0b1xuICAgKiAgICAgYXBwbHkgdG8gVVJJIGF0dHJpYnV0ZXMuICBJZiBub3QgZ2l2ZW4sIFVSSSBhdHRyaWJ1dGVzIGFyZSBkZWxldGVkLlxuICAgKiBAcGFyYW0ge2Z1bmN0aW9uKD9zdHJpbmcpOiA/c3RyaW5nfSBvcHRfbm1Ub2tlblBvbGljeSBBIHRyYW5zZm9ybSB0byBhcHBseVxuICAgKiAgICAgdG8gYXR0cmlidXRlcyBjb250YWluaW5nIEhUTUwgbmFtZXMsIGVsZW1lbnQgSURzLCBhbmQgc3BhY2Utc2VwYXJhdGVkXG4gICAqICAgICBsaXN0cyBvZiBjbGFzc2VzLiAgSWYgbm90IGdpdmVuLCBzdWNoIGF0dHJpYnV0ZXMgYXJlIGxlZnQgdW5jaGFuZ2VkLlxuICAgKi9cbiAgZnVuY3Rpb24gc2FuaXRpemUoaW5wdXRIdG1sLFxuICAgIG9wdF9uYWl2ZVVyaVJld3JpdGVyLCBvcHRfbm1Ub2tlblBvbGljeSwgb3B0X2xvZ2dlcikge1xuICAgIHZhciB0YWdQb2xpY3kgPSBtYWtlVGFnUG9saWN5KFxuICAgICAgb3B0X25haXZlVXJpUmV3cml0ZXIsIG9wdF9ubVRva2VuUG9saWN5LCBvcHRfbG9nZ2VyKTtcbiAgICByZXR1cm4gc2FuaXRpemVXaXRoUG9saWN5KGlucHV0SHRtbCwgdGFnUG9saWN5KTtcbiAgfVxuXG4gIC8vIEV4cG9ydCBib3RoIHF1b3RlZCBhbmQgdW5xdW90ZWQgbmFtZXMgZm9yIENsb3N1cmUgbGlua2FnZS5cbiAgdmFyIGh0bWwgPSB7fTtcbiAgaHRtbC5lc2NhcGVBdHRyaWIgPSBodG1sWydlc2NhcGVBdHRyaWInXSA9IGVzY2FwZUF0dHJpYjtcbiAgaHRtbC5tYWtlSHRtbFNhbml0aXplciA9IGh0bWxbJ21ha2VIdG1sU2FuaXRpemVyJ10gPSBtYWtlSHRtbFNhbml0aXplcjtcbiAgaHRtbC5tYWtlU2F4UGFyc2VyID0gaHRtbFsnbWFrZVNheFBhcnNlciddID0gbWFrZVNheFBhcnNlcjtcbiAgaHRtbC5tYWtlVGFnUG9saWN5ID0gaHRtbFsnbWFrZVRhZ1BvbGljeSddID0gbWFrZVRhZ1BvbGljeTtcbiAgaHRtbC5ub3JtYWxpemVSQ0RhdGEgPSBodG1sWydub3JtYWxpemVSQ0RhdGEnXSA9IG5vcm1hbGl6ZVJDRGF0YTtcbiAgaHRtbC5zYW5pdGl6ZSA9IGh0bWxbJ3Nhbml0aXplJ10gPSBzYW5pdGl6ZTtcbiAgaHRtbC5zYW5pdGl6ZUF0dHJpYnMgPSBodG1sWydzYW5pdGl6ZUF0dHJpYnMnXSA9IHNhbml0aXplQXR0cmlicztcbiAgaHRtbC5zYW5pdGl6ZVdpdGhQb2xpY3kgPSBodG1sWydzYW5pdGl6ZVdpdGhQb2xpY3knXSA9IHNhbml0aXplV2l0aFBvbGljeTtcbiAgaHRtbC51bmVzY2FwZUVudGl0aWVzID0gaHRtbFsndW5lc2NhcGVFbnRpdGllcyddID0gdW5lc2NhcGVFbnRpdGllcztcbiAgcmV0dXJuIGh0bWw7XG59KShodG1sNCk7XG5cbnZhciBodG1sX3Nhbml0aXplID0gaHRtbFsnc2FuaXRpemUnXTtcblxuLy8gTG9vc2VuIHJlc3RyaWN0aW9ucyBvZiBDYWphJ3Ncbi8vIGh0bWwtc2FuaXRpemVyIHRvIGFsbG93IGZvciBzdHlsaW5nXG5odG1sNC5BVFRSSUJTWycqOjpzdHlsZSddID0gMDtcbmh0bWw0LkVMRU1FTlRTWydzdHlsZSddID0gMDtcbmh0bWw0LkFUVFJJQlNbJ2E6OnRhcmdldCddID0gMDtcbmh0bWw0LkVMRU1FTlRTWyd2aWRlbyddID0gMDtcbmh0bWw0LkFUVFJJQlNbJ3ZpZGVvOjpzcmMnXSA9IDA7XG5odG1sNC5BVFRSSUJTWyd2aWRlbzo6cG9zdGVyJ10gPSAwO1xuaHRtbDQuQVRUUklCU1sndmlkZW86OmNvbnRyb2xzJ10gPSAwO1xuaHRtbDQuRUxFTUVOVFNbJ2F1ZGlvJ10gPSAwO1xuaHRtbDQuQVRUUklCU1snYXVkaW86OnNyYyddID0gMDtcbmh0bWw0LkFUVFJJQlNbJ3ZpZGVvOjphdXRvcGxheSddID0gMDtcbmh0bWw0LkFUVFJJQlNbJ3ZpZGVvOjpjb250cm9scyddID0gMDtcblxuaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgbW9kdWxlLmV4cG9ydHMgPSBodG1sX3Nhbml0aXplO1xufVxuIiwibW9kdWxlLmV4cG9ydHM9e1xuICBcImF1dGhvclwiOiBcIk1hcGJveFwiLFxuICBcIm5hbWVcIjogXCJtYXBib3guanNcIixcbiAgXCJkZXNjcmlwdGlvblwiOiBcIm1hcGJveCBqYXZhc2NyaXB0IGFwaVwiLFxuICBcInZlcnNpb25cIjogXCIzLjEuMVwiLFxuICBcImhvbWVwYWdlXCI6IFwiaHR0cDovL21hcGJveC5jb20vXCIsXG4gIFwicmVwb3NpdG9yeVwiOiB7XG4gICAgXCJ0eXBlXCI6IFwiZ2l0XCIsXG4gICAgXCJ1cmxcIjogXCJnaXQ6Ly9naXRodWIuY29tL21hcGJveC9tYXBib3guanMuZ2l0XCJcbiAgfSxcbiAgXCJtYWluXCI6IFwic3JjL2luZGV4LmpzXCIsXG4gIFwiZGVwZW5kZW5jaWVzXCI6IHtcbiAgICBcImNvcnNsaXRlXCI6IFwiMC4wLjZcIixcbiAgICBcImlzYXJyYXlcIjogXCIwLjAuMVwiLFxuICAgIFwibGVhZmxldFwiOiBcIjEuMC4yXCIsXG4gICAgXCJtdXN0YWNoZVwiOiBcIjIuMi4xXCIsXG4gICAgXCJzYW5pdGl6ZS1jYWphXCI6IFwiMC4xLjRcIlxuICB9LFxuICBcInNjcmlwdHNcIjoge1xuICAgIFwidGVzdFwiOiBcImVzbGludCAtLW5vLWVzbGludHJjIC1jIC5lc2xpbnRyYyBzcmMgJiYgcGhhbnRvbWpzIG5vZGVfbW9kdWxlcy9tb2NoYS1waGFudG9tanMtY29yZS9tb2NoYS1waGFudG9tanMtY29yZS5qcyB0ZXN0L2luZGV4Lmh0bWxcIlxuICB9LFxuICBcImxpY2Vuc2VcIjogXCJCU0QtMy1DbGF1c2VcIixcbiAgXCJkZXZEZXBlbmRlbmNpZXNcIjoge1xuICAgIFwiYnJvd3NlcmlmeVwiOiBcIl4xMy4wLjBcIixcbiAgICBcImNsZWFuLWNzc1wiOiBcIn4yLjAuN1wiLFxuICAgIFwiY3otY29udmVudGlvbmFsLWNoYW5nZWxvZ1wiOiBcIjEuMi4wXCIsXG4gICAgXCJlc2xpbnRcIjogXCJeMC4yMy4wXCIsXG4gICAgXCJleHBlY3QuanNcIjogXCIwLjMuMVwiLFxuICAgIFwiaGFwcGVuXCI6IFwiMC4xLjNcIixcbiAgICBcImxlYWZsZXQtZnVsbHNjcmVlblwiOiBcIjAuMC40XCIsXG4gICAgXCJsZWFmbGV0LWhhc2hcIjogXCIwLjIuMVwiLFxuICAgIFwibWFya2VkXCI6IFwifjAuMy4wXCIsXG4gICAgXCJtaW5pZnlpZnlcIjogXCJeNi4xLjBcIixcbiAgICBcIm1pbmltaXN0XCI6IFwiMC4wLjVcIixcbiAgICBcIm1vY2hhXCI6IFwiMi40LjVcIixcbiAgICBcIm1vY2hhLXBoYW50b21qcy1jb3JlXCI6IFwiMi4wLjFcIixcbiAgICBcInBoYW50b21qcy1wcmVidWlsdFwiOiBcIjIuMS4xMlwiLFxuICAgIFwic2lub25cIjogXCIxLjEwLjJcIlxuICB9LFxuICBcIm9wdGlvbmFsRGVwZW5kZW5jaWVzXCI6IHt9LFxuICBcImVuZ2luZXNcIjoge1xuICAgIFwibm9kZVwiOiBcIipcIlxuICB9LFxuICBcImNvbmZpZ1wiOiB7XG4gICAgXCJjb21taXRpemVuXCI6IHtcbiAgICAgIFwicGF0aFwiOiBcIi4vbm9kZV9tb2R1bGVzL2N6LWNvbnZlbnRpb25hbC1jaGFuZ2Vsb2dcIlxuICAgIH1cbiAgfVxufVxuIiwiJ3VzZSBzdHJpY3QnO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBIVFRQX1VSTDogJ2h0dHA6Ly9hLnRpbGVzLm1hcGJveC5jb20vdjQnLFxuICAgIEhUVFBTX1VSTDogJ2h0dHBzOi8vYS50aWxlcy5tYXBib3guY29tL3Y0JyxcbiAgICBGT1JDRV9IVFRQUzogZmFsc2UsXG4gICAgUkVRVUlSRV9BQ0NFU1NfVE9LRU46IHRydWVcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi91dGlsJyksXG4gICAgZm9ybWF0X3VybCA9IHJlcXVpcmUoJy4vZm9ybWF0X3VybCcpLFxuICAgIHJlcXVlc3QgPSByZXF1aXJlKCcuL3JlcXVlc3QnKSxcbiAgICBtYXJrZXIgPSByZXF1aXJlKCcuL21hcmtlcicpLFxuICAgIHNpbXBsZXN0eWxlID0gcmVxdWlyZSgnLi9zaW1wbGVzdHlsZScpO1xuXG4vLyAjIGZlYXR1cmVMYXllclxuLy9cbi8vIEEgbGF5ZXIgb2YgZmVhdHVyZXMsIGxvYWRlZCBmcm9tIE1hcGJveCBvciBlbHNlLiBBZGRzIHRoZSBhYmlsaXR5XG4vLyB0byByZXNldCBmZWF0dXJlcywgZmlsdGVyIHRoZW0sIGFuZCBsb2FkIHRoZW0gZnJvbSBhIEdlb0pTT04gVVJMLlxudmFyIEZlYXR1cmVMYXllciA9IEwuRmVhdHVyZUdyb3VwLmV4dGVuZCh7XG4gICAgb3B0aW9uczoge1xuICAgICAgICBmaWx0ZXI6IGZ1bmN0aW9uKCkgeyByZXR1cm4gdHJ1ZTsgfSxcbiAgICAgICAgc2FuaXRpemVyOiByZXF1aXJlKCdzYW5pdGl6ZS1jYWphJyksXG4gICAgICAgIHN0eWxlOiBzaW1wbGVzdHlsZS5zdHlsZSxcbiAgICAgICAgcG9wdXBPcHRpb25zOiB7IGNsb3NlQnV0dG9uOiBmYWxzZSB9XG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uKF8sIG9wdGlvbnMpIHtcbiAgICAgICAgTC5zZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xuXG4gICAgICAgIHRoaXMuX2xheWVycyA9IHt9O1xuXG4gICAgICAgIGlmICh0eXBlb2YgXyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHV0aWwuaWRVcmwoXywgdGhpcyk7XG4gICAgICAgIC8vIGphdmFzY3JpcHQgb2JqZWN0IG9mIFRpbGVKU09OIGRhdGFcbiAgICAgICAgfSBlbHNlIGlmIChfICYmIHR5cGVvZiBfID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgdGhpcy5zZXRHZW9KU09OKF8pO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIHNldEdlb0pTT046IGZ1bmN0aW9uKF8pIHtcbiAgICAgICAgdGhpcy5fZ2VvanNvbiA9IF87XG4gICAgICAgIHRoaXMuY2xlYXJMYXllcnMoKTtcbiAgICAgICAgdGhpcy5faW5pdGlhbGl6ZShfKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldEdlb0pTT046IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fZ2VvanNvbjtcbiAgICB9LFxuXG4gICAgbG9hZFVSTDogZnVuY3Rpb24odXJsKSB7XG4gICAgICAgIGlmICh0aGlzLl9yZXF1ZXN0ICYmICdhYm9ydCcgaW4gdGhpcy5fcmVxdWVzdCkgdGhpcy5fcmVxdWVzdC5hYm9ydCgpO1xuICAgICAgICB0aGlzLl9yZXF1ZXN0ID0gcmVxdWVzdCh1cmwsIEwuYmluZChmdW5jdGlvbihlcnIsIGpzb24pIHtcbiAgICAgICAgICAgIHRoaXMuX3JlcXVlc3QgPSBudWxsO1xuICAgICAgICAgICAgaWYgKGVyciAmJiBlcnIudHlwZSAhPT0gJ2Fib3J0Jykge1xuICAgICAgICAgICAgICAgIHV0aWwubG9nKCdjb3VsZCBub3QgbG9hZCBmZWF0dXJlcyBhdCAnICsgdXJsKTtcbiAgICAgICAgICAgICAgICB0aGlzLmZpcmUoJ2Vycm9yJywge2Vycm9yOiBlcnJ9KTtcbiAgICAgICAgICAgIH0gZWxzZSBpZiAoanNvbikge1xuICAgICAgICAgICAgICAgIHRoaXMuc2V0R2VvSlNPTihqc29uKTtcbiAgICAgICAgICAgICAgICB0aGlzLmZpcmUoJ3JlYWR5Jyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIHRoaXMpKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGxvYWRJRDogZnVuY3Rpb24oaWQpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMubG9hZFVSTChmb3JtYXRfdXJsKCcvdjQvJyArIGlkICsgJy9mZWF0dXJlcy5qc29uJywgdGhpcy5vcHRpb25zLmFjY2Vzc1Rva2VuKSk7XG4gICAgfSxcblxuICAgIHNldEZpbHRlcjogZnVuY3Rpb24oXykge1xuICAgICAgICB0aGlzLm9wdGlvbnMuZmlsdGVyID0gXztcbiAgICAgICAgaWYgKHRoaXMuX2dlb2pzb24pIHtcbiAgICAgICAgICAgIHRoaXMuY2xlYXJMYXllcnMoKTtcbiAgICAgICAgICAgIHRoaXMuX2luaXRpYWxpemUodGhpcy5fZ2VvanNvbik7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIGdldEZpbHRlcjogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLm9wdGlvbnMuZmlsdGVyO1xuICAgIH0sXG5cbiAgICBfaW5pdGlhbGl6ZTogZnVuY3Rpb24oanNvbikge1xuICAgICAgICB2YXIgZmVhdHVyZXMgPSBMLlV0aWwuaXNBcnJheShqc29uKSA/IGpzb24gOiBqc29uLmZlYXR1cmVzLFxuICAgICAgICAgICAgaSwgbGVuO1xuXG4gICAgICAgIGlmIChmZWF0dXJlcykge1xuICAgICAgICAgICAgZm9yIChpID0gMCwgbGVuID0gZmVhdHVyZXMubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgICAgICAgICAvLyBPbmx5IGFkZCB0aGlzIGlmIGdlb21ldHJ5IG9yIGdlb21ldHJpZXMgYXJlIHNldCBhbmQgbm90IG51bGxcbiAgICAgICAgICAgICAgICBpZiAoZmVhdHVyZXNbaV0uZ2VvbWV0cmllcyB8fCBmZWF0dXJlc1tpXS5nZW9tZXRyeSB8fCBmZWF0dXJlc1tpXS5mZWF0dXJlcykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLl9pbml0aWFsaXplKGZlYXR1cmVzW2ldKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAodGhpcy5vcHRpb25zLmZpbHRlcihqc29uKSkge1xuXG4gICAgICAgICAgICB2YXIgb3B0cyA9IHthY2Nlc3NUb2tlbjogdGhpcy5vcHRpb25zLmFjY2Vzc1Rva2VufSxcbiAgICAgICAgICAgICAgICBwb2ludFRvTGF5ZXIgPSB0aGlzLm9wdGlvbnMucG9pbnRUb0xheWVyIHx8IGZ1bmN0aW9uKGZlYXR1cmUsIGxhdGxvbikge1xuICAgICAgICAgICAgICAgICAgcmV0dXJuIG1hcmtlci5zdHlsZShmZWF0dXJlLCBsYXRsb24sIG9wdHMpO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgbGF5ZXIgPSBMLkdlb0pTT04uZ2VvbWV0cnlUb0xheWVyKGpzb24sIHtcbiAgICAgICAgICAgICAgICAgICAgcG9pbnRUb0xheWVyOiBwb2ludFRvTGF5ZXJcbiAgICAgICAgICAgICAgICB9KSxcbiAgICAgICAgICAgICAgICBwb3B1cEh0bWwgPSBtYXJrZXIuY3JlYXRlUG9wdXAoanNvbiwgdGhpcy5vcHRpb25zLnNhbml0aXplciksXG4gICAgICAgICAgICAgICAgc3R5bGUgPSB0aGlzLm9wdGlvbnMuc3R5bGUsXG4gICAgICAgICAgICAgICAgZGVmYXVsdFN0eWxlID0gc3R5bGUgPT09IHNpbXBsZXN0eWxlLnN0eWxlO1xuXG4gICAgICAgICAgICBpZiAoc3R5bGUgJiYgJ3NldFN0eWxlJyBpbiBsYXllciAmJlxuICAgICAgICAgICAgICAgIC8vIGlmIHRoZSBzdHlsZSBtZXRob2QgaXMgdGhlIHNpbXBsZXN0eWxlIGRlZmF1bHQsIHRoZW5cbiAgICAgICAgICAgICAgICAvLyBuZXZlciBzdHlsZSBMLkNpcmNsZSBvciBMLkNpcmNsZU1hcmtlciBiZWNhdXNlXG4gICAgICAgICAgICAgICAgLy8gc2ltcGxlc3R5bGUgaGFzIG5vIHJ1bGVzIG92ZXIgdGhlbSwgb25seSBvdmVyIGdlb21ldHJ5XG4gICAgICAgICAgICAgICAgLy8gcHJpbWl0aXZlcyBkaXJlY3RseSBmcm9tIEdlb0pTT05cbiAgICAgICAgICAgICAgICAoIShkZWZhdWx0U3R5bGUgJiYgKGxheWVyIGluc3RhbmNlb2YgTC5DaXJjbGUgfHxcbiAgICAgICAgICAgICAgICAgIGxheWVyIGluc3RhbmNlb2YgTC5DaXJjbGVNYXJrZXIpKSkpIHtcbiAgICAgICAgICAgICAgICBpZiAodHlwZW9mIHN0eWxlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgIHN0eWxlID0gc3R5bGUoanNvbik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGxheWVyLnNldFN0eWxlKHN0eWxlKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgbGF5ZXIuZmVhdHVyZSA9IGpzb247XG5cbiAgICAgICAgICAgIGlmIChwb3B1cEh0bWwpIHtcbiAgICAgICAgICAgICAgICBsYXllci5iaW5kUG9wdXAocG9wdXBIdG1sLCB0aGlzLm9wdGlvbnMucG9wdXBPcHRpb25zKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdGhpcy5hZGRMYXllcihsYXllcik7XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMuRmVhdHVyZUxheWVyID0gRmVhdHVyZUxheWVyO1xuXG5tb2R1bGUuZXhwb3J0cy5mZWF0dXJlTGF5ZXIgPSBmdW5jdGlvbihfLCBvcHRpb25zKSB7XG4gICAgcmV0dXJuIG5ldyBGZWF0dXJlTGF5ZXIoXywgb3B0aW9ucyk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgRmVlZGJhY2sgPSBMLkNsYXNzLmV4dGVuZCh7XG4gICAgaW5jbHVkZXM6IEwuTWl4aW4uRXZlbnRzLFxuICAgIGRhdGE6IHt9LFxuICAgIHJlY29yZDogZnVuY3Rpb24oZGF0YSkge1xuICAgICAgICBMLmV4dGVuZCh0aGlzLmRhdGEsIGRhdGEpO1xuICAgICAgICB0aGlzLmZpcmUoJ2NoYW5nZScpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IG5ldyBGZWVkYmFjaygpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY29uZmlnID0gcmVxdWlyZSgnLi9jb25maWcnKSxcbiAgICB2ZXJzaW9uID0gcmVxdWlyZSgnLi4vcGFja2FnZS5qc29uJykudmVyc2lvbjtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihwYXRoLCBhY2Nlc3NUb2tlbikge1xuICAgIGFjY2Vzc1Rva2VuID0gYWNjZXNzVG9rZW4gfHwgTC5tYXBib3guYWNjZXNzVG9rZW47XG5cbiAgICBpZiAoIWFjY2Vzc1Rva2VuICYmIGNvbmZpZy5SRVFVSVJFX0FDQ0VTU19UT0tFTikge1xuICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0FuIEFQSSBhY2Nlc3MgdG9rZW4gaXMgcmVxdWlyZWQgdG8gdXNlIE1hcGJveC5qcy4gJyArXG4gICAgICAgICAgICAnU2VlIGh0dHBzOi8vd3d3Lm1hcGJveC5jb20vbWFwYm94LmpzL2FwaS92JyArIHZlcnNpb24gKyAnL2FwaS1hY2Nlc3MtdG9rZW5zLycpO1xuICAgIH1cblxuICAgIHZhciB1cmwgPSAoZG9jdW1lbnQubG9jYXRpb24ucHJvdG9jb2wgPT09ICdodHRwczonIHx8IGNvbmZpZy5GT1JDRV9IVFRQUykgPyBjb25maWcuSFRUUFNfVVJMIDogY29uZmlnLkhUVFBfVVJMO1xuICAgIHVybCA9IHVybC5yZXBsYWNlKC9cXC92NCQvLCAnJyk7XG4gICAgdXJsICs9IHBhdGg7XG5cbiAgICBpZiAoY29uZmlnLlJFUVVJUkVfQUNDRVNTX1RPS0VOKSB7XG4gICAgICAgIGlmIChhY2Nlc3NUb2tlblswXSA9PT0gJ3MnKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ1VzZSBhIHB1YmxpYyBhY2Nlc3MgdG9rZW4gKHBrLiopIHdpdGggTWFwYm94LmpzLCBub3QgYSBzZWNyZXQgYWNjZXNzIHRva2VuIChzay4qKS4gJyArXG4gICAgICAgICAgICAgICAgJ1NlZSBodHRwczovL3d3dy5tYXBib3guY29tL21hcGJveC5qcy9hcGkvdicgKyB2ZXJzaW9uICsgJy9hcGktYWNjZXNzLXRva2Vucy8nKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHVybCArPSB1cmwuaW5kZXhPZignPycpICE9PSAtMSA/ICcmYWNjZXNzX3Rva2VuPScgOiAnP2FjY2Vzc190b2tlbj0nO1xuICAgICAgICB1cmwgKz0gYWNjZXNzVG9rZW47XG4gICAgfVxuXG4gICAgcmV0dXJuIHVybDtcbn07XG5cbm1vZHVsZS5leHBvcnRzLnRpbGVKU09OID0gZnVuY3Rpb24odXJsT3JNYXBJRCwgYWNjZXNzVG9rZW4pIHtcblxuICAgIGlmICh1cmxPck1hcElELmluZGV4T2YoJ21hcGJveDovL3N0eWxlcycpID09PSAwKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcignU3R5bGVzIGNyZWF0ZWQgd2l0aCBNYXBib3ggU3R1ZGlvIG5lZWQgdG8gYmUgdXNlZCB3aXRoICcgK1xuICAgICAgICAgICAgJ0wubWFwYm94LnN0eWxlTGF5ZXIsIG5vdCBMLm1hcGJveC50aWxlTGF5ZXInKTtcbiAgICB9XG5cbiAgICBpZiAodXJsT3JNYXBJRC5pbmRleE9mKCcvJykgIT09IC0xKVxuICAgICAgICByZXR1cm4gdXJsT3JNYXBJRDtcblxuICAgIHZhciB1cmwgPSBtb2R1bGUuZXhwb3J0cygnL3Y0LycgKyB1cmxPck1hcElEICsgJy5qc29uJywgYWNjZXNzVG9rZW4pO1xuXG4gICAgLy8gVGlsZUpTT04gcmVxdWVzdHMgbmVlZCBhIHNlY3VyZSBmbGFnIGFwcGVuZGVkIHRvIHRoZWlyIFVSTHMgc29cbiAgICAvLyB0aGF0IHRoZSBzZXJ2ZXIga25vd3MgdG8gc2VuZCBTU0wtaWZpZWQgcmVzb3VyY2UgcmVmZXJlbmNlcy5cbiAgICBpZiAodXJsLmluZGV4T2YoJ2h0dHBzJykgPT09IDApXG4gICAgICAgIHVybCArPSAnJnNlY3VyZSc7XG5cbiAgICByZXR1cm4gdXJsO1xufTtcblxuXG5tb2R1bGUuZXhwb3J0cy5zdHlsZSA9IGZ1bmN0aW9uKHN0eWxlVVJMLCBhY2Nlc3NUb2tlbikge1xuICAgIGlmIChzdHlsZVVSTC5pbmRleE9mKCdtYXBib3g6Ly9zdHlsZXMvJykgPT09IC0xKSB0aHJvdyBuZXcgRXJyb3IoJ0luY29ycmVjdGx5IGZvcm1hdHRlZCBNYXBib3ggc3R5bGUgYXQgJyArIHN0eWxlVVJMKTtcblxuICAgIHZhciBvd25lcklEU3R5bGUgPSBzdHlsZVVSTC5zcGxpdCgnbWFwYm94Oi8vc3R5bGVzLycpWzFdO1xuICAgIHZhciB1cmwgPSBtb2R1bGUuZXhwb3J0cygnL3N0eWxlcy92MS8nICsgb3duZXJJRFN0eWxlLCBhY2Nlc3NUb2tlbilcbiAgICAgICAgLnJlcGxhY2UoJ2h0dHA6Ly8nLCAnaHR0cHM6Ly8nKTtcblxuICAgIHJldHVybiB1cmw7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaXNBcnJheSA9IHJlcXVpcmUoJ2lzYXJyYXknKSxcbiAgICB1dGlsID0gcmVxdWlyZSgnLi91dGlsJyksXG4gICAgZm9ybWF0X3VybCA9IHJlcXVpcmUoJy4vZm9ybWF0X3VybCcpLFxuICAgIGZlZWRiYWNrID0gcmVxdWlyZSgnLi9mZWVkYmFjaycpLFxuICAgIHJlcXVlc3QgPSByZXF1aXJlKCcuL3JlcXVlc3QnKTtcblxuLy8gTG93LWxldmVsIGdlb2NvZGluZyBpbnRlcmZhY2UgLSB3cmFwcyBzcGVjaWZpYyBBUEkgY2FsbHMgYW5kIHRoZWlyXG4vLyByZXR1cm4gdmFsdWVzLlxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbih1cmwsIG9wdGlvbnMpIHtcbiAgICBpZiAoIW9wdGlvbnMpIG9wdGlvbnMgPSB7fTtcbiAgICB2YXIgZ2VvY29kZXIgPSB7fTtcblxuICAgIHV0aWwuc3RyaWN0KHVybCwgJ3N0cmluZycpO1xuXG4gICAgaWYgKHVybC5pbmRleE9mKCcvJykgPT09IC0xKSB7XG4gICAgICAgIHVybCA9IGZvcm1hdF91cmwoJy9nZW9jb2RpbmcvdjUvJyArIHVybCArICcve3F1ZXJ5fS5qc29uJywgb3B0aW9ucy5hY2Nlc3NUb2tlbiwgNSk7XG4gICAgfVxuXG4gICAgZnVuY3Rpb24gcm91bmRUbyhsYXRMbmcsIHByZWNpc2lvbikge1xuICAgICAgICB2YXIgbXVsdCA9IE1hdGgucG93KDEwLCBwcmVjaXNpb24pO1xuICAgICAgICBsYXRMbmcubGF0ID0gTWF0aC5yb3VuZChsYXRMbmcubGF0ICogbXVsdCkgLyBtdWx0O1xuICAgICAgICBsYXRMbmcubG5nID0gTWF0aC5yb3VuZChsYXRMbmcubG5nICogbXVsdCkgLyBtdWx0O1xuICAgICAgICByZXR1cm4gbGF0TG5nO1xuICAgIH1cblxuICAgIGdlb2NvZGVyLmdldFVSTCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdXJsO1xuICAgIH07XG5cbiAgICBnZW9jb2Rlci5xdWVyeVVSTCA9IGZ1bmN0aW9uKF8pIHtcbiAgICAgICAgdmFyIGlzT2JqZWN0ID0gIShpc0FycmF5KF8pIHx8IHR5cGVvZiBfID09PSAnc3RyaW5nJyksXG4gICAgICAgICAgICBxdWVyeSA9IGlzT2JqZWN0ID8gXy5xdWVyeSA6IF87XG5cbiAgICAgICAgaWYgKGlzQXJyYXkocXVlcnkpKSB7XG4gICAgICAgICAgICB2YXIgcGFydHMgPSBbXTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcXVlcnkubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBwYXJ0c1tpXSA9IGVuY29kZVVSSUNvbXBvbmVudChxdWVyeVtpXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBxdWVyeSA9IHBhcnRzLmpvaW4oJzsnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHF1ZXJ5ID0gZW5jb2RlVVJJQ29tcG9uZW50KHF1ZXJ5KTtcbiAgICAgICAgfVxuXG4gICAgICAgIGZlZWRiYWNrLnJlY29yZCh7IGdlb2NvZGluZzogcXVlcnkgfSk7XG5cbiAgICAgICAgdmFyIHVybCA9IEwuVXRpbC50ZW1wbGF0ZShnZW9jb2Rlci5nZXRVUkwoKSwge3F1ZXJ5OiBxdWVyeX0pO1xuXG4gICAgICAgIGlmIChpc09iamVjdCkge1xuICAgICAgICAgICAgaWYgKF8udHlwZXMpIHtcbiAgICAgICAgICAgICAgICBpZiAoaXNBcnJheShfLnR5cGVzKSkge1xuICAgICAgICAgICAgICAgICAgICB1cmwgKz0gJyZ0eXBlcz0nICsgXy50eXBlcy5qb2luKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdXJsICs9ICcmdHlwZXM9JyArIF8udHlwZXM7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoXy5jb3VudHJ5KSB7XG4gICAgICAgICAgICAgICAgaWYgKGlzQXJyYXkoXy5jb3VudHJ5KSkge1xuICAgICAgICAgICAgICAgICAgICB1cmwgKz0gJyZjb3VudHJ5PScgKyBfLmNvdW50cnkuam9pbigpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHVybCArPSAnJmNvdW50cnk9JyArIF8uY291bnRyeTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChfLmJib3gpIHtcbiAgICAgICAgICAgICAgICBpZiAoaXNBcnJheShfLmJib3gpKSB7XG4gICAgICAgICAgICAgICAgICAgIHVybCArPSAnJmJib3g9JyArIF8uYmJveC5qb2luKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdXJsICs9ICcmYmJveD0nICsgXy5iYm94O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKF8ucHJveGltaXR5KSB7XG4gICAgICAgICAgICAgICAgdmFyIHByb3hpbWl0eSA9IHJvdW5kVG8oTC5sYXRMbmcoXy5wcm94aW1pdHkpLCAzKTtcbiAgICAgICAgICAgICAgICB1cmwgKz0gJyZwcm94aW1pdHk9JyArIHByb3hpbWl0eS5sbmcgKyAnLCcgKyBwcm94aW1pdHkubGF0O1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodHlwZW9mIF8uYXV0b2NvbXBsZXRlID09PSAnYm9vbGVhbicpIHtcbiAgICAgICAgICAgICAgICB1cmwgKz0gJyZhdXRvY29tcGxldGU9JyArIF8uYXV0b2NvbXBsZXRlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHVybDtcbiAgICB9O1xuXG4gICAgZ2VvY29kZXIucXVlcnkgPSBmdW5jdGlvbihfLCBjYWxsYmFjaykge1xuICAgICAgICB1dGlsLnN0cmljdChjYWxsYmFjaywgJ2Z1bmN0aW9uJyk7XG5cbiAgICAgICAgcmVxdWVzdChnZW9jb2Rlci5xdWVyeVVSTChfKSwgZnVuY3Rpb24oZXJyLCBqc29uKSB7XG4gICAgICAgICAgICBpZiAoanNvbiAmJiAoanNvbi5sZW5ndGggfHwganNvbi5mZWF0dXJlcykpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzID0ge1xuICAgICAgICAgICAgICAgICAgICByZXN1bHRzOiBqc29uXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICBpZiAoanNvbi5mZWF0dXJlcyAmJiBqc29uLmZlYXR1cmVzLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICByZXMubGF0bG5nID0gW1xuICAgICAgICAgICAgICAgICAgICAgICAganNvbi5mZWF0dXJlc1swXS5jZW50ZXJbMV0sXG4gICAgICAgICAgICAgICAgICAgICAgICBqc29uLmZlYXR1cmVzWzBdLmNlbnRlclswXV07XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGpzb24uZmVhdHVyZXNbMF0uYmJveCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzLmJvdW5kcyA9IGpzb24uZmVhdHVyZXNbMF0uYmJveDtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcy5sYm91bmRzID0gdXRpbC5sYm91bmRzKHJlcy5ib3VuZHMpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhbGxiYWNrKG51bGwsIHJlcyk7XG4gICAgICAgICAgICB9IGVsc2UgY2FsbGJhY2soZXJyIHx8IHRydWUpO1xuICAgICAgICB9KTtcblxuICAgICAgICByZXR1cm4gZ2VvY29kZXI7XG4gICAgfTtcblxuICAgIC8vIGEgcmV2ZXJzZSBnZW9jb2RlOlxuICAgIC8vXG4gICAgLy8gIGdlb2NvZGVyLnJldmVyc2VRdWVyeShbODAsIDIwXSlcbiAgICBnZW9jb2Rlci5yZXZlcnNlUXVlcnkgPSBmdW5jdGlvbihfLCBjYWxsYmFjaykge1xuICAgICAgICB2YXIgcSA9ICcnO1xuXG4gICAgICAgIC8vIHNvcnQgdGhyb3VnaCBkaWZmZXJlbnQgd2F5cyBwZW9wbGUgcmVwcmVzZW50IGxhdCBhbmQgbG9uIHBhaXJzXG4gICAgICAgIGZ1bmN0aW9uIG5vcm1hbGl6ZSh4KSB7XG4gICAgICAgICAgICB2YXIgbGF0TG5nO1xuICAgICAgICAgICAgaWYgKHgubGF0ICE9PSB1bmRlZmluZWQgJiYgeC5sbmcgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGxhdExuZyA9IEwubGF0TG5nKHgubGF0LCB4LmxuZyk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKHgubGF0ICE9PSB1bmRlZmluZWQgJiYgeC5sb24gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGxhdExuZyA9IEwubGF0TG5nKHgubGF0LCB4Lmxvbik7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGxhdExuZyA9IEwubGF0TG5nKHhbMV0sIHhbMF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbGF0TG5nID0gcm91bmRUbyhsYXRMbmcsIDUpO1xuICAgICAgICAgICAgcmV0dXJuIGxhdExuZy5sbmcgKyAnLCcgKyBsYXRMbmcubGF0O1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKF8ubGVuZ3RoICYmIF9bMF0ubGVuZ3RoKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMCwgcHRzID0gW107IGkgPCBfLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcHRzLnB1c2gobm9ybWFsaXplKF9baV0pKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHEgPSBwdHMuam9pbignOycpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcSA9IG5vcm1hbGl6ZShfKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlcXVlc3QoZ2VvY29kZXIucXVlcnlVUkwocSksIGZ1bmN0aW9uKGVyciwganNvbikge1xuICAgICAgICAgICAgY2FsbGJhY2soZXJyLCBqc29uKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIGdlb2NvZGVyO1xuICAgIH07XG5cbiAgICByZXR1cm4gZ2VvY29kZXI7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZ2VvY29kZXIgPSByZXF1aXJlKCcuL2dlb2NvZGVyJyksXG4gICAgdXRpbCA9IHJlcXVpcmUoJy4vdXRpbCcpO1xuXG52YXIgR2VvY29kZXJDb250cm9sID0gTC5Db250cm9sLmV4dGVuZCh7XG4gICAgaW5jbHVkZXM6IEwuTWl4aW4uRXZlbnRzLFxuXG4gICAgb3B0aW9uczoge1xuICAgICAgICBwcm94aW1pdHk6IHRydWUsXG4gICAgICAgIHBvc2l0aW9uOiAndG9wbGVmdCcsXG4gICAgICAgIHBvaW50Wm9vbTogMTYsXG4gICAgICAgIGtlZXBPcGVuOiBmYWxzZSxcbiAgICAgICAgYXV0b2NvbXBsZXRlOiBmYWxzZSxcbiAgICAgICAgcXVlcnlPcHRpb25zOiB7fVxuICAgIH0sXG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbihfLCBvcHRpb25zKSB7XG4gICAgICAgIEwuVXRpbC5zZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLnNldFVSTChfKTtcbiAgICAgICAgdGhpcy5fdXBkYXRlU3VibWl0ID0gTC5iaW5kKHRoaXMuX3VwZGF0ZVN1Ym1pdCwgdGhpcyk7XG4gICAgICAgIHRoaXMuX3VwZGF0ZUF1dG9jb21wbGV0ZSA9IEwuYmluZCh0aGlzLl91cGRhdGVBdXRvY29tcGxldGUsIHRoaXMpO1xuICAgICAgICB0aGlzLl9jaG9vc2VSZXN1bHQgPSBMLmJpbmQodGhpcy5fY2hvb3NlUmVzdWx0LCB0aGlzKTtcbiAgICB9LFxuXG4gICAgc2V0VVJMOiBmdW5jdGlvbihfKSB7XG4gICAgICAgIHRoaXMuZ2VvY29kZXIgPSBnZW9jb2RlcihfLCB7XG4gICAgICAgICAgICBhY2Nlc3NUb2tlbjogdGhpcy5vcHRpb25zLmFjY2Vzc1Rva2VuXG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgZ2V0VVJMOiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuZ2VvY29kZXIuZ2V0VVJMKCk7XG4gICAgfSxcblxuICAgIHNldElEOiBmdW5jdGlvbihfKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnNldFVSTChfKTtcbiAgICB9LFxuXG4gICAgc2V0VGlsZUpTT046IGZ1bmN0aW9uKF8pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMuc2V0VVJMKF8uZ2VvY29kZXIpO1xuICAgIH0sXG5cbiAgICBfdG9nZ2xlOiBmdW5jdGlvbihlKSB7XG4gICAgICAgIGlmIChlKSBMLkRvbUV2ZW50LnN0b3AoZSk7XG4gICAgICAgIGlmIChMLkRvbVV0aWwuaGFzQ2xhc3ModGhpcy5fY29udGFpbmVyLCAnYWN0aXZlJykpIHtcbiAgICAgICAgICAgIEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl9jb250YWluZXIsICdhY3RpdmUnKTtcbiAgICAgICAgICAgIHRoaXMuX3Jlc3VsdHMuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgICAgICB0aGlzLl9pbnB1dC5ibHVyKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBMLkRvbVV0aWwuYWRkQ2xhc3ModGhpcy5fY29udGFpbmVyLCAnYWN0aXZlJyk7XG4gICAgICAgICAgICB0aGlzLl9pbnB1dC5mb2N1cygpO1xuICAgICAgICAgICAgdGhpcy5faW5wdXQuc2VsZWN0KCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX2Nsb3NlSWZPcGVuOiBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKEwuRG9tVXRpbC5oYXNDbGFzcyh0aGlzLl9jb250YWluZXIsICdhY3RpdmUnKSAmJlxuICAgICAgICAgICAgIXRoaXMub3B0aW9ucy5rZWVwT3Blbikge1xuICAgICAgICAgICAgTC5Eb21VdGlsLnJlbW92ZUNsYXNzKHRoaXMuX2NvbnRhaW5lciwgJ2FjdGl2ZScpO1xuICAgICAgICAgICAgdGhpcy5fcmVzdWx0cy5pbm5lckhUTUwgPSAnJztcbiAgICAgICAgICAgIHRoaXMuX2lucHV0LmJsdXIoKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBvbkFkZDogZnVuY3Rpb24obWFwKSB7XG5cbiAgICAgICAgdmFyIGNvbnRhaW5lciA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsICdsZWFmbGV0LWNvbnRyb2wtbWFwYm94LWdlb2NvZGVyIGxlYWZsZXQtYmFyIGxlYWZsZXQtY29udHJvbCcpLFxuICAgICAgICAgICAgbGluayA9IEwuRG9tVXRpbC5jcmVhdGUoJ2EnLCAnbGVhZmxldC1jb250cm9sLW1hcGJveC1nZW9jb2Rlci10b2dnbGUgbWFwYm94LWljb24gbWFwYm94LWljb24tZ2VvY29kZXInLCBjb250YWluZXIpLFxuICAgICAgICAgICAgcmVzdWx0cyA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsICdsZWFmbGV0LWNvbnRyb2wtbWFwYm94LWdlb2NvZGVyLXJlc3VsdHMnLCBjb250YWluZXIpLFxuICAgICAgICAgICAgd3JhcCA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsICdsZWFmbGV0LWNvbnRyb2wtbWFwYm94LWdlb2NvZGVyLXdyYXAnLCBjb250YWluZXIpLFxuICAgICAgICAgICAgZm9ybSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2Zvcm0nLCAnbGVhZmxldC1jb250cm9sLW1hcGJveC1nZW9jb2Rlci1mb3JtJywgd3JhcCksXG4gICAgICAgICAgICBpbnB1dCA9IEwuRG9tVXRpbC5jcmVhdGUoJ2lucHV0JywgJycsIGZvcm0pO1xuXG4gICAgICAgIGxpbmsuaHJlZiA9ICcjJztcbiAgICAgICAgbGluay5pbm5lckhUTUwgPSAnJm5ic3A7JztcblxuICAgICAgICBpbnB1dC50eXBlID0gJ3RleHQnO1xuICAgICAgICBpbnB1dC5zZXRBdHRyaWJ1dGUoJ3BsYWNlaG9sZGVyJywgJ1NlYXJjaCcpO1xuXG4gICAgICAgIEwuRG9tRXZlbnQuYWRkTGlzdGVuZXIoZm9ybSwgJ3N1Ym1pdCcsIHRoaXMuX2dlb2NvZGUsIHRoaXMpO1xuICAgICAgICBMLkRvbUV2ZW50LmFkZExpc3RlbmVyKGlucHV0LCAna2V5dXAnLCB0aGlzLl9hdXRvY29tcGxldGUsIHRoaXMpO1xuICAgICAgICBMLkRvbUV2ZW50LmRpc2FibGVDbGlja1Byb3BhZ2F0aW9uKGNvbnRhaW5lcik7XG5cbiAgICAgICAgdGhpcy5fbWFwID0gbWFwO1xuICAgICAgICB0aGlzLl9yZXN1bHRzID0gcmVzdWx0cztcbiAgICAgICAgdGhpcy5faW5wdXQgPSBpbnB1dDtcbiAgICAgICAgdGhpcy5fZm9ybSA9IGZvcm07XG5cbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5rZWVwT3Blbikge1xuICAgICAgICAgICAgTC5Eb21VdGlsLmFkZENsYXNzKGNvbnRhaW5lciwgJ2FjdGl2ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5fbWFwLm9uKCdjbGljaycsIHRoaXMuX2Nsb3NlSWZPcGVuLCB0aGlzKTtcbiAgICAgICAgICAgIEwuRG9tRXZlbnQuYWRkTGlzdGVuZXIobGluaywgJ2NsaWNrJywgdGhpcy5fdG9nZ2xlLCB0aGlzKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBjb250YWluZXI7XG4gICAgfSxcblxuICAgIF91cGRhdGVTdWJtaXQ6IGZ1bmN0aW9uKGVyciwgcmVzcCkge1xuICAgICAgICBMLkRvbVV0aWwucmVtb3ZlQ2xhc3ModGhpcy5fY29udGFpbmVyLCAnc2VhcmNoaW5nJyk7XG4gICAgICAgIHRoaXMuX3Jlc3VsdHMuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIGlmIChlcnIgfHwgIXJlc3ApIHtcbiAgICAgICAgICAgIHRoaXMuZmlyZSgnZXJyb3InLCB7ZXJyb3I6IGVycn0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdmFyIGZlYXR1cmVzID0gW107XG4gICAgICAgICAgICBpZiAocmVzcC5yZXN1bHRzICYmIHJlc3AucmVzdWx0cy5mZWF0dXJlcykge1xuICAgICAgICAgICAgICAgIGZlYXR1cmVzID0gcmVzcC5yZXN1bHRzLmZlYXR1cmVzO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKGZlYXR1cmVzLmxlbmd0aCA9PT0gMSkge1xuICAgICAgICAgICAgICAgIHRoaXMuZmlyZSgnYXV0b3NlbGVjdCcsIHsgZmVhdHVyZTogZmVhdHVyZXNbMF0gfSk7XG4gICAgICAgICAgICAgICAgdGhpcy5maXJlKCdmb3VuZCcsIHtyZXN1bHRzOiByZXNwLnJlc3VsdHN9KTtcbiAgICAgICAgICAgICAgICB0aGlzLl9jaG9vc2VSZXN1bHQoZmVhdHVyZXNbMF0pO1xuICAgICAgICAgICAgICAgIHRoaXMuX2Nsb3NlSWZPcGVuKCk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGZlYXR1cmVzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmZpcmUoJ2ZvdW5kJywge3Jlc3VsdHM6IHJlc3AucmVzdWx0c30pO1xuICAgICAgICAgICAgICAgIHRoaXMuX2Rpc3BsYXlSZXN1bHRzKGZlYXR1cmVzKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5maXJlKCdub3Rmb3VuZCcpO1xuICAgICAgICAgICAgICAgIHRoaXMuX2Rpc3BsYXlSZXN1bHRzKGZlYXR1cmVzKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfdXBkYXRlQXV0b2NvbXBsZXRlOiBmdW5jdGlvbihlcnIsIHJlc3ApIHtcbiAgICAgICAgdGhpcy5fcmVzdWx0cy5pbm5lckhUTUwgPSAnJztcbiAgICAgICAgaWYgKGVyciB8fCAhcmVzcCkge1xuICAgICAgICAgICAgdGhpcy5maXJlKCdlcnJvcicsIHtlcnJvcjogZXJyfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgZmVhdHVyZXMgPSBbXTtcbiAgICAgICAgICAgIGlmIChyZXNwLnJlc3VsdHMgJiYgcmVzcC5yZXN1bHRzLmZlYXR1cmVzKSB7XG4gICAgICAgICAgICAgICAgZmVhdHVyZXMgPSByZXNwLnJlc3VsdHMuZmVhdHVyZXM7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoZmVhdHVyZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5maXJlKCdmb3VuZCcsIHtyZXN1bHRzOiByZXNwLnJlc3VsdHN9KTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5maXJlKCdub3Rmb3VuZCcpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5fZGlzcGxheVJlc3VsdHMoZmVhdHVyZXMpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIF9kaXNwbGF5UmVzdWx0czogZnVuY3Rpb24oZmVhdHVyZXMpIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBNYXRoLm1pbihmZWF0dXJlcy5sZW5ndGgsIDUpOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgZmVhdHVyZSA9IGZlYXR1cmVzW2ldO1xuICAgICAgICAgICAgdmFyIG5hbWUgPSBmZWF0dXJlLnBsYWNlX25hbWU7XG4gICAgICAgICAgICBpZiAoIW5hbWUubGVuZ3RoKSBjb250aW51ZTtcblxuICAgICAgICAgICAgdmFyIHIgPSBMLkRvbVV0aWwuY3JlYXRlKCdhJywgJycsIHRoaXMuX3Jlc3VsdHMpO1xuICAgICAgICAgICAgdmFyIHRleHQgPSAoJ2lubmVyVGV4dCcgaW4gcikgPyAnaW5uZXJUZXh0JyA6ICd0ZXh0Q29udGVudCc7XG4gICAgICAgICAgICByW3RleHRdID0gbmFtZTtcbiAgICAgICAgICAgIHIuc2V0QXR0cmlidXRlKCd0aXRsZScsIG5hbWUpO1xuICAgICAgICAgICAgci5ocmVmID0gJyMnO1xuXG4gICAgICAgICAgICAoTC5iaW5kKGZ1bmN0aW9uKGZlYXR1cmUpIHtcbiAgICAgICAgICAgICAgICBMLkRvbUV2ZW50LmFkZExpc3RlbmVyKHIsICdjbGljaycsIGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fY2hvb3NlUmVzdWx0KGZlYXR1cmUpO1xuICAgICAgICAgICAgICAgICAgICBMLkRvbUV2ZW50LnN0b3AoZSk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmlyZSgnc2VsZWN0JywgeyBmZWF0dXJlOiBmZWF0dXJlIH0pO1xuICAgICAgICAgICAgICAgIH0sIHRoaXMpO1xuICAgICAgICAgICAgfSwgdGhpcykpKGZlYXR1cmUpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChmZWF0dXJlcy5sZW5ndGggPiA1KSB7XG4gICAgICAgICAgICB2YXIgb3V0b2YgPSBMLkRvbVV0aWwuY3JlYXRlKCdzcGFuJywgJycsIHRoaXMuX3Jlc3VsdHMpO1xuICAgICAgICAgICAgb3V0b2YuaW5uZXJIVE1MID0gJ1RvcCA1IG9mICcgKyBmZWF0dXJlcy5sZW5ndGggKyAnICByZXN1bHRzJztcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfY2hvb3NlUmVzdWx0OiBmdW5jdGlvbihyZXN1bHQpIHtcbiAgICAgICAgaWYgKHJlc3VsdC5iYm94KSB7XG4gICAgICAgICAgICB0aGlzLl9tYXAuZml0Qm91bmRzKHV0aWwubGJvdW5kcyhyZXN1bHQuYmJveCkpO1xuICAgICAgICB9IGVsc2UgaWYgKHJlc3VsdC5jZW50ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuX21hcC5zZXRWaWV3KFtyZXN1bHQuY2VudGVyWzFdLCByZXN1bHQuY2VudGVyWzBdXSwgKHRoaXMuX21hcC5nZXRab29tKCkgPT09IHVuZGVmaW5lZCkgP1xuICAgICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5wb2ludFpvb20gOlxuICAgICAgICAgICAgICAgIE1hdGgubWF4KHRoaXMuX21hcC5nZXRab29tKCksIHRoaXMub3B0aW9ucy5wb2ludFpvb20pKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfZ2VvY29kZTogZnVuY3Rpb24oZSkge1xuICAgICAgICBMLkRvbUV2ZW50LnByZXZlbnREZWZhdWx0KGUpO1xuICAgICAgICBpZiAodGhpcy5faW5wdXQudmFsdWUgPT09ICcnKSByZXR1cm4gdGhpcy5fdXBkYXRlU3VibWl0KCk7XG4gICAgICAgIEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9jb250YWluZXIsICdzZWFyY2hpbmcnKTtcbiAgICAgICAgdGhpcy5nZW9jb2Rlci5xdWVyeShMLlV0aWwuZXh0ZW5kKHtcbiAgICAgICAgICAgIHF1ZXJ5OiB0aGlzLl9pbnB1dC52YWx1ZSxcbiAgICAgICAgICAgIHByb3hpbWl0eTogdGhpcy5vcHRpb25zLnByb3hpbWl0eSA/IHRoaXMuX21hcC5nZXRDZW50ZXIoKSA6IGZhbHNlXG4gICAgICAgIH0sIHRoaXMub3B0aW9ucy5xdWVyeU9wdGlvbnMpLCB0aGlzLl91cGRhdGVTdWJtaXQpO1xuICAgIH0sXG5cbiAgICBfYXV0b2NvbXBsZXRlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvbnMuYXV0b2NvbXBsZXRlKSByZXR1cm47XG4gICAgICAgIGlmICh0aGlzLl9pbnB1dC52YWx1ZSA9PT0gJycpIHJldHVybiB0aGlzLl91cGRhdGVBdXRvY29tcGxldGUoKTtcbiAgICAgICAgdGhpcy5nZW9jb2Rlci5xdWVyeShMLlV0aWwuZXh0ZW5kKHtcbiAgICAgICAgICAgIHF1ZXJ5OiB0aGlzLl9pbnB1dC52YWx1ZSxcbiAgICAgICAgICAgIHByb3hpbWl0eTogdGhpcy5vcHRpb25zLnByb3hpbWl0eSA/IHRoaXMuX21hcC5nZXRDZW50ZXIoKSA6IGZhbHNlXG4gICAgICAgIH0sIHRoaXMub3B0aW9ucy5xdWVyeU9wdGlvbnMpLCB0aGlzLl91cGRhdGVBdXRvY29tcGxldGUpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cy5HZW9jb2RlckNvbnRyb2wgPSBHZW9jb2RlckNvbnRyb2w7XG5cbm1vZHVsZS5leHBvcnRzLmdlb2NvZGVyQ29udHJvbCA9IGZ1bmN0aW9uKF8sIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IEdlb2NvZGVyQ29udHJvbChfLCBvcHRpb25zKTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbmZ1bmN0aW9uIHV0ZkRlY29kZShjKSB7XG4gICAgaWYgKGMgPj0gOTMpIGMtLTtcbiAgICBpZiAoYyA+PSAzNSkgYy0tO1xuICAgIHJldHVybiBjIC0gMzI7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24oZGF0YSkge1xuICAgIHJldHVybiBmdW5jdGlvbih4LCB5KSB7XG4gICAgICAgIGlmICghZGF0YSkgcmV0dXJuO1xuICAgICAgICB2YXIgaWR4ID0gdXRmRGVjb2RlKGRhdGEuZ3JpZFt5XS5jaGFyQ29kZUF0KHgpKSxcbiAgICAgICAgICAgIGtleSA9IGRhdGEua2V5c1tpZHhdO1xuICAgICAgICByZXR1cm4gZGF0YS5kYXRhW2tleV07XG4gICAgfTtcbn07XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciB1dGlsID0gcmVxdWlyZSgnLi91dGlsJyksXG4gICAgTXVzdGFjaGUgPSByZXF1aXJlKCdtdXN0YWNoZScpO1xuXG52YXIgR3JpZENvbnRyb2wgPSBMLkNvbnRyb2wuZXh0ZW5kKHtcblxuICAgIG9wdGlvbnM6IHtcbiAgICAgICAgcGlubmFibGU6IHRydWUsXG4gICAgICAgIGZvbGxvdzogZmFsc2UsXG4gICAgICAgIHNhbml0aXplcjogcmVxdWlyZSgnc2FuaXRpemUtY2FqYScpLFxuICAgICAgICB0b3VjaFRlYXNlcjogdHJ1ZSxcbiAgICAgICAgbG9jYXRpb246IHRydWVcbiAgICB9LFxuXG4gICAgX2N1cnJlbnRDb250ZW50OiAnJyxcblxuICAgIC8vIHBpbm5lZCBtZWFucyB0aGF0IHRoaXMgY29udHJvbCBpcyBvbiBhIGZlYXR1cmUgYW5kIHRoZSB1c2VyIGhhcyBsaWtlbHlcbiAgICAvLyBjbGlja2VkLiBwaW5uZWQgd2lsbCBub3QgYmVjb21lIGZhbHNlIHVubGVzcyB0aGUgdXNlciBjbGlja3Mgb2ZmXG4gICAgLy8gb2YgdGhlIGZlYXR1cmUgb250byBhbm90aGVyIG9yIGNsaWNrcyB4XG4gICAgX3Bpbm5lZDogZmFsc2UsXG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbihfLCBvcHRpb25zKSB7XG4gICAgICAgIEwuVXRpbC5zZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xuICAgICAgICB1dGlsLnN0cmljdF9pbnN0YW5jZShfLCBMLkNsYXNzLCAnTC5tYXBib3guZ3JpZExheWVyJyk7XG4gICAgICAgIHRoaXMuX2xheWVyID0gXztcbiAgICB9LFxuXG4gICAgc2V0VGVtcGxhdGU6IGZ1bmN0aW9uKHRlbXBsYXRlKSB7XG4gICAgICAgIHV0aWwuc3RyaWN0KHRlbXBsYXRlLCAnc3RyaW5nJyk7XG4gICAgICAgIHRoaXMub3B0aW9ucy50ZW1wbGF0ZSA9IHRlbXBsYXRlO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgX3RlbXBsYXRlOiBmdW5jdGlvbihmb3JtYXQsIGRhdGEpIHtcbiAgICAgICAgaWYgKCFkYXRhKSByZXR1cm47XG4gICAgICAgIHZhciB0ZW1wbGF0ZSA9IHRoaXMub3B0aW9ucy50ZW1wbGF0ZSB8fCB0aGlzLl9sYXllci5nZXRUaWxlSlNPTigpLnRlbXBsYXRlO1xuICAgICAgICBpZiAodGVtcGxhdGUpIHtcbiAgICAgICAgICAgIHZhciBkID0ge307XG4gICAgICAgICAgICBkWydfXycgKyBmb3JtYXQgKyAnX18nXSA9IHRydWU7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5vcHRpb25zLnNhbml0aXplcihcbiAgICAgICAgICAgICAgICBNdXN0YWNoZS50b19odG1sKHRlbXBsYXRlLCBMLmV4dGVuZChkLCBkYXRhKSkpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIC8vIGNoYW5nZSB0aGUgY29udGVudCBvZiB0aGUgdG9vbHRpcCBIVE1MIGlmIGl0IGhhcyBjaGFuZ2VkLCBvdGhlcndpc2VcbiAgICAvLyBub29wXG4gICAgX3Nob3c6IGZ1bmN0aW9uKGNvbnRlbnQsIG8pIHtcbiAgICAgICAgaWYgKGNvbnRlbnQgPT09IHRoaXMuX2N1cnJlbnRDb250ZW50KSByZXR1cm47XG5cbiAgICAgICAgdGhpcy5fY3VycmVudENvbnRlbnQgPSBjb250ZW50O1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuZm9sbG93KSB7XG4gICAgICAgICAgICB0aGlzLl9wb3B1cC5zZXRDb250ZW50KGNvbnRlbnQpXG4gICAgICAgICAgICAgICAgLnNldExhdExuZyhvLmxhdExuZyk7XG4gICAgICAgICAgICBpZiAodGhpcy5fbWFwLl9wb3B1cCAhPT0gdGhpcy5fcG9wdXApIHRoaXMuX3BvcHVwLm9wZW5Pbih0aGlzLl9tYXApO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhpcy5fY29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSAnYmxvY2snO1xuICAgICAgICAgICAgdGhpcy5fY29udGVudFdyYXBwZXIuaW5uZXJIVE1MID0gY29udGVudDtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBoaWRlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgdGhpcy5fcGlubmVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMuX2N1cnJlbnRDb250ZW50ID0gJyc7XG5cbiAgICAgICAgdGhpcy5fbWFwLmNsb3NlUG9wdXAoKTtcbiAgICAgICAgdGhpcy5fY29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSAnbm9uZSc7XG4gICAgICAgIHRoaXMuX2NvbnRlbnRXcmFwcGVyLmlubmVySFRNTCA9ICcnO1xuXG4gICAgICAgIEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl9jb250YWluZXIsICdjbG9zYWJsZScpO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICBfbW91c2VvdmVyOiBmdW5jdGlvbihvKSB7XG4gICAgICAgIGlmIChvLmRhdGEpIHtcbiAgICAgICAgICAgIEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9tYXAuX2NvbnRhaW5lciwgJ21hcC1jbGlja2FibGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIEwuRG9tVXRpbC5yZW1vdmVDbGFzcyh0aGlzLl9tYXAuX2NvbnRhaW5lciwgJ21hcC1jbGlja2FibGUnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLl9waW5uZWQpIHJldHVybjtcblxuICAgICAgICB2YXIgY29udGVudCA9IHRoaXMuX3RlbXBsYXRlKCd0ZWFzZXInLCBvLmRhdGEpO1xuICAgICAgICBpZiAoY29udGVudCkge1xuICAgICAgICAgICAgdGhpcy5fc2hvdyhjb250ZW50LCBvKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuaGlkZSgpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIF9tb3VzZW1vdmU6IGZ1bmN0aW9uKG8pIHtcbiAgICAgICAgaWYgKHRoaXMuX3Bpbm5lZCkgcmV0dXJuO1xuICAgICAgICBpZiAoIXRoaXMub3B0aW9ucy5mb2xsb3cpIHJldHVybjtcblxuICAgICAgICB0aGlzLl9wb3B1cC5zZXRMYXRMbmcoby5sYXRMbmcpO1xuICAgIH0sXG5cbiAgICBfbmF2aWdhdGVUbzogZnVuY3Rpb24odXJsKSB7XG4gICAgICAgIHdpbmRvdy50b3AubG9jYXRpb24uaHJlZiA9IHVybDtcbiAgICB9LFxuXG4gICAgX2NsaWNrOiBmdW5jdGlvbihvKSB7XG5cbiAgICAgICAgdmFyIGxvY2F0aW9uX2Zvcm1hdHRlZCA9IHRoaXMuX3RlbXBsYXRlKCdsb2NhdGlvbicsIG8uZGF0YSk7XG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMubG9jYXRpb24gJiYgbG9jYXRpb25fZm9ybWF0dGVkICYmXG4gICAgICAgICAgICBsb2NhdGlvbl9mb3JtYXR0ZWQuc2VhcmNoKC9eaHR0cHM/Oi8pID09PSAwKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5fbmF2aWdhdGVUbyh0aGlzLl90ZW1wbGF0ZSgnbG9jYXRpb24nLCBvLmRhdGEpKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghdGhpcy5vcHRpb25zLnBpbm5hYmxlKSByZXR1cm47XG5cbiAgICAgICAgdmFyIGNvbnRlbnQgPSB0aGlzLl90ZW1wbGF0ZSgnZnVsbCcsIG8uZGF0YSk7XG5cbiAgICAgICAgaWYgKCFjb250ZW50ICYmIHRoaXMub3B0aW9ucy50b3VjaFRlYXNlciAmJiBMLkJyb3dzZXIudG91Y2gpIHtcbiAgICAgICAgICAgIGNvbnRlbnQgPSB0aGlzLl90ZW1wbGF0ZSgndGVhc2VyJywgby5kYXRhKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjb250ZW50KSB7XG4gICAgICAgICAgICBMLkRvbVV0aWwuYWRkQ2xhc3ModGhpcy5fY29udGFpbmVyLCAnY2xvc2FibGUnKTtcbiAgICAgICAgICAgIHRoaXMuX3Bpbm5lZCA9IHRydWU7XG4gICAgICAgICAgICB0aGlzLl9zaG93KGNvbnRlbnQsIG8pO1xuICAgICAgICB9IGVsc2UgaWYgKHRoaXMuX3Bpbm5lZCkge1xuICAgICAgICAgICAgTC5Eb21VdGlsLnJlbW92ZUNsYXNzKHRoaXMuX2NvbnRhaW5lciwgJ2Nsb3NhYmxlJyk7XG4gICAgICAgICAgICB0aGlzLl9waW5uZWQgPSBmYWxzZTtcbiAgICAgICAgICAgIHRoaXMuaGlkZSgpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIF9vblBvcHVwQ2xvc2U6IGZ1bmN0aW9uKCkge1xuICAgICAgICB0aGlzLl9jdXJyZW50Q29udGVudCA9IG51bGw7XG4gICAgICAgIHRoaXMuX3Bpbm5lZCA9IGZhbHNlO1xuICAgIH0sXG5cbiAgICBfY3JlYXRlQ2xvc2VidXR0b246IGZ1bmN0aW9uKGNvbnRhaW5lciwgZm4pIHtcbiAgICAgICAgdmFyIGxpbmsgPSBMLkRvbVV0aWwuY3JlYXRlKCdhJywgJ2Nsb3NlJywgY29udGFpbmVyKTtcblxuICAgICAgICBsaW5rLmlubmVySFRNTCA9ICdjbG9zZSc7XG4gICAgICAgIGxpbmsuaHJlZiA9ICcjJztcbiAgICAgICAgbGluay50aXRsZSA9ICdjbG9zZSc7XG5cbiAgICAgICAgTC5Eb21FdmVudFxuICAgICAgICAgICAgLm9uKGxpbmssICdjbGljaycsIEwuRG9tRXZlbnQuc3RvcFByb3BhZ2F0aW9uKVxuICAgICAgICAgICAgLm9uKGxpbmssICdtb3VzZWRvd24nLCBMLkRvbUV2ZW50LnN0b3BQcm9wYWdhdGlvbilcbiAgICAgICAgICAgIC5vbihsaW5rLCAnZGJsY2xpY2snLCBMLkRvbUV2ZW50LnN0b3BQcm9wYWdhdGlvbilcbiAgICAgICAgICAgIC5vbihsaW5rLCAnY2xpY2snLCBMLkRvbUV2ZW50LnByZXZlbnREZWZhdWx0KVxuICAgICAgICAgICAgLm9uKGxpbmssICdjbGljaycsIGZuLCB0aGlzKTtcblxuICAgICAgICByZXR1cm4gbGluaztcbiAgICB9LFxuXG4gICAgb25BZGQ6IGZ1bmN0aW9uKG1hcCkge1xuICAgICAgICB0aGlzLl9tYXAgPSBtYXA7XG5cbiAgICAgICAgdmFyIGNsYXNzTmFtZSA9ICdsZWFmbGV0LWNvbnRyb2wtZ3JpZCBtYXAtdG9vbHRpcCcsXG4gICAgICAgICAgICBjb250YWluZXIgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCBjbGFzc05hbWUpLFxuICAgICAgICAgICAgY29udGVudFdyYXBwZXIgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCAnbWFwLXRvb2x0aXAtY29udGVudCcpO1xuXG4gICAgICAgIC8vIGhpZGUgdGhlIGNvbnRhaW5lciBlbGVtZW50IGluaXRpYWxseVxuICAgICAgICBjb250YWluZXIuc3R5bGUuZGlzcGxheSA9ICdub25lJztcbiAgICAgICAgdGhpcy5fY3JlYXRlQ2xvc2VidXR0b24oY29udGFpbmVyLCB0aGlzLmhpZGUpO1xuICAgICAgICBjb250YWluZXIuYXBwZW5kQ2hpbGQoY29udGVudFdyYXBwZXIpO1xuXG4gICAgICAgIHRoaXMuX2NvbnRlbnRXcmFwcGVyID0gY29udGVudFdyYXBwZXI7XG4gICAgICAgIHRoaXMuX3BvcHVwID0gbmV3IEwuUG9wdXAoeyBhdXRvUGFuOiBmYWxzZSwgY2xvc2VPbkNsaWNrOiBmYWxzZSB9KTtcblxuICAgICAgICBtYXAub24oJ3BvcHVwY2xvc2UnLCB0aGlzLl9vblBvcHVwQ2xvc2UsIHRoaXMpO1xuXG4gICAgICAgIEwuRG9tRXZlbnRcbiAgICAgICAgICAgIC5kaXNhYmxlQ2xpY2tQcm9wYWdhdGlvbihjb250YWluZXIpXG4gICAgICAgICAgICAvLyBhbGxvdyBwZW9wbGUgdG8gc2Nyb2xsIHRvb2x0aXBzIHdpdGggbW91c2V3aGVlbFxuICAgICAgICAgICAgLmFkZExpc3RlbmVyKGNvbnRhaW5lciwgJ21vdXNld2hlZWwnLCBMLkRvbUV2ZW50LnN0b3BQcm9wYWdhdGlvbik7XG5cbiAgICAgICAgdGhpcy5fbGF5ZXJcbiAgICAgICAgICAgIC5vbignbW91c2VvdmVyJywgdGhpcy5fbW91c2VvdmVyLCB0aGlzKVxuICAgICAgICAgICAgLm9uKCdtb3VzZW1vdmUnLCB0aGlzLl9tb3VzZW1vdmUsIHRoaXMpXG4gICAgICAgICAgICAub24oJ2NsaWNrJywgdGhpcy5fY2xpY2ssIHRoaXMpO1xuXG4gICAgICAgIHJldHVybiBjb250YWluZXI7XG4gICAgfSxcblxuICAgIG9uUmVtb3ZlOiBmdW5jdGlvbiAobWFwKSB7XG5cbiAgICAgICAgbWFwLm9mZigncG9wdXBjbG9zZScsIHRoaXMuX29uUG9wdXBDbG9zZSwgdGhpcyk7XG5cbiAgICAgICAgdGhpcy5fbGF5ZXJcbiAgICAgICAgICAgIC5vZmYoJ21vdXNlb3ZlcicsIHRoaXMuX21vdXNlb3ZlciwgdGhpcylcbiAgICAgICAgICAgIC5vZmYoJ21vdXNlbW92ZScsIHRoaXMuX21vdXNlbW92ZSwgdGhpcylcbiAgICAgICAgICAgIC5vZmYoJ2NsaWNrJywgdGhpcy5fY2xpY2ssIHRoaXMpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cy5HcmlkQ29udHJvbCA9IEdyaWRDb250cm9sO1xuXG5tb2R1bGUuZXhwb3J0cy5ncmlkQ29udHJvbCA9IGZ1bmN0aW9uKF8sIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IEdyaWRDb250cm9sKF8sIG9wdGlvbnMpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHV0aWwgPSByZXF1aXJlKCcuL3V0aWwnKSxcbiAgICByZXF1ZXN0ID0gcmVxdWlyZSgnLi9yZXF1ZXN0JyksXG4gICAgZ3JpZCA9IHJlcXVpcmUoJy4vZ3JpZCcpO1xuXG4vLyBmb3JrZWQgZnJvbSBkYW56ZWwvTC5VVEZHcmlkXG52YXIgR3JpZExheWVyID0gTC5MYXllci5leHRlbmQoe1xuICAgIGluY2x1ZGVzOiBbcmVxdWlyZSgnLi9sb2FkX3RpbGVqc29uJyldLFxuXG4gICAgb3B0aW9uczoge1xuICAgICAgICB0ZW1wbGF0ZTogZnVuY3Rpb24oKSB7IHJldHVybiAnJzsgfVxuICAgIH0sXG5cbiAgICBfbW91c2VPbjogbnVsbCxcbiAgICBfdGlsZWpzb246IHt9LFxuICAgIF9jYWNoZToge30sXG5cbiAgICBpbml0aWFsaXplOiBmdW5jdGlvbihfLCBvcHRpb25zKSB7XG4gICAgICAgIEwuVXRpbC5zZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xuICAgICAgICB0aGlzLl9sb2FkVGlsZUpTT04oXyk7XG4gICAgfSxcblxuICAgIF9zZXRUaWxlSlNPTjogZnVuY3Rpb24oanNvbikge1xuICAgICAgICB1dGlsLnN0cmljdChqc29uLCAnb2JqZWN0Jyk7XG5cbiAgICAgICAgTC5leHRlbmQodGhpcy5vcHRpb25zLCB7XG4gICAgICAgICAgICBncmlkczoganNvbi5ncmlkcyxcbiAgICAgICAgICAgIG1pblpvb206IGpzb24ubWluem9vbSxcbiAgICAgICAgICAgIG1heFpvb206IGpzb24ubWF4em9vbSxcbiAgICAgICAgICAgIGJvdW5kczoganNvbi5ib3VuZHMgJiYgdXRpbC5sYm91bmRzKGpzb24uYm91bmRzKVxuICAgICAgICB9KTtcblxuICAgICAgICB0aGlzLl90aWxlanNvbiA9IGpzb247XG4gICAgICAgIHRoaXMuX2NhY2hlID0ge307XG4gICAgICAgIHRoaXMuX3VwZGF0ZSgpO1xuXG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICBnZXRUaWxlSlNPTjogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl90aWxlanNvbjtcbiAgICB9LFxuXG4gICAgYWN0aXZlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgcmV0dXJuICEhKHRoaXMuX21hcCAmJiB0aGlzLm9wdGlvbnMuZ3JpZHMgJiYgdGhpcy5vcHRpb25zLmdyaWRzLmxlbmd0aCk7XG4gICAgfSxcblxuICAgIG9uQWRkOiBmdW5jdGlvbihtYXApIHtcbiAgICAgICAgdGhpcy5fbWFwID0gbWFwO1xuICAgICAgICB0aGlzLl91cGRhdGUoKTtcblxuICAgICAgICB0aGlzLl9tYXBcbiAgICAgICAgICAgIC5vbignY2xpY2snLCB0aGlzLl9jbGljaywgdGhpcylcbiAgICAgICAgICAgIC5vbignbW91c2Vtb3ZlJywgdGhpcy5fbW92ZSwgdGhpcylcbiAgICAgICAgICAgIC5vbignbW92ZWVuZCcsIHRoaXMuX3VwZGF0ZSwgdGhpcyk7XG4gICAgfSxcblxuICAgIG9uUmVtb3ZlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgdGhpcy5fbWFwXG4gICAgICAgICAgICAub2ZmKCdjbGljaycsIHRoaXMuX2NsaWNrLCB0aGlzKVxuICAgICAgICAgICAgLm9mZignbW91c2Vtb3ZlJywgdGhpcy5fbW92ZSwgdGhpcylcbiAgICAgICAgICAgIC5vZmYoJ21vdmVlbmQnLCB0aGlzLl91cGRhdGUsIHRoaXMpO1xuICAgIH0sXG5cbiAgICBnZXREYXRhOiBmdW5jdGlvbihsYXRsbmcsIGNhbGxiYWNrKSB7XG4gICAgICAgIGlmICghdGhpcy5hY3RpdmUoKSkgcmV0dXJuO1xuXG4gICAgICAgIHZhciBtYXAgPSB0aGlzLl9tYXAsXG4gICAgICAgICAgICBwb2ludCA9IG1hcC5wcm9qZWN0KGxhdGxuZy53cmFwKCkpLFxuICAgICAgICAgICAgdGlsZVNpemUgPSAyNTYsXG4gICAgICAgICAgICByZXNvbHV0aW9uID0gNCxcbiAgICAgICAgICAgIHggPSBNYXRoLmZsb29yKHBvaW50LnggLyB0aWxlU2l6ZSksXG4gICAgICAgICAgICB5ID0gTWF0aC5mbG9vcihwb2ludC55IC8gdGlsZVNpemUpLFxuICAgICAgICAgICAgbWF4ID0gbWFwLm9wdGlvbnMuY3JzLnNjYWxlKG1hcC5nZXRab29tKCkpIC8gdGlsZVNpemU7XG5cbiAgICAgICAgeCA9ICh4ICsgbWF4KSAlIG1heDtcbiAgICAgICAgeSA9ICh5ICsgbWF4KSAlIG1heDtcblxuICAgICAgICB0aGlzLl9nZXRUaWxlKG1hcC5nZXRab29tKCksIHgsIHksIGZ1bmN0aW9uKGdyaWQpIHtcbiAgICAgICAgICAgIHZhciBncmlkWCA9IE1hdGguZmxvb3IoKHBvaW50LnggLSAoeCAqIHRpbGVTaXplKSkgLyByZXNvbHV0aW9uKSxcbiAgICAgICAgICAgICAgICBncmlkWSA9IE1hdGguZmxvb3IoKHBvaW50LnkgLSAoeSAqIHRpbGVTaXplKSkgLyByZXNvbHV0aW9uKTtcblxuICAgICAgICAgICAgY2FsbGJhY2soZ3JpZChncmlkWCwgZ3JpZFkpKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIF9jbGljazogZnVuY3Rpb24oZSkge1xuICAgICAgICB0aGlzLmdldERhdGEoZS5sYXRsbmcsIEwuYmluZChmdW5jdGlvbihkYXRhKSB7XG4gICAgICAgICAgICB0aGlzLmZpcmUoJ2NsaWNrJywge1xuICAgICAgICAgICAgICAgIGxhdExuZzogZS5sYXRsbmcsXG4gICAgICAgICAgICAgICAgZGF0YTogZGF0YVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sIHRoaXMpKTtcbiAgICB9LFxuXG4gICAgX21vdmU6IGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgdGhpcy5nZXREYXRhKGUubGF0bG5nLCBMLmJpbmQoZnVuY3Rpb24oZGF0YSkge1xuICAgICAgICAgICAgaWYgKGRhdGEgIT09IHRoaXMuX21vdXNlT24pIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5fbW91c2VPbikge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmZpcmUoJ21vdXNlb3V0Jywge1xuICAgICAgICAgICAgICAgICAgICAgICAgbGF0TG5nOiBlLmxhdGxuZyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRhdGE6IHRoaXMuX21vdXNlT25cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5maXJlKCdtb3VzZW92ZXInLCB7XG4gICAgICAgICAgICAgICAgICAgIGxhdExuZzogZS5sYXRsbmcsXG4gICAgICAgICAgICAgICAgICAgIGRhdGE6IGRhdGFcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIHRoaXMuX21vdXNlT24gPSBkYXRhO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB0aGlzLmZpcmUoJ21vdXNlbW92ZScsIHtcbiAgICAgICAgICAgICAgICAgICAgbGF0TG5nOiBlLmxhdGxuZyxcbiAgICAgICAgICAgICAgICAgICAgZGF0YTogZGF0YVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LCB0aGlzKSk7XG4gICAgfSxcblxuICAgIF9nZXRUaWxlVVJMOiBmdW5jdGlvbih0aWxlUG9pbnQpIHtcbiAgICAgICAgdmFyIHVybHMgPSB0aGlzLm9wdGlvbnMuZ3JpZHMsXG4gICAgICAgICAgICBpbmRleCA9ICh0aWxlUG9pbnQueCArIHRpbGVQb2ludC55KSAlIHVybHMubGVuZ3RoLFxuICAgICAgICAgICAgdXJsID0gdXJsc1tpbmRleF07XG5cbiAgICAgICAgcmV0dXJuIEwuVXRpbC50ZW1wbGF0ZSh1cmwsIHRpbGVQb2ludCk7XG4gICAgfSxcblxuICAgIC8vIExvYWQgdXAgYWxsIHJlcXVpcmVkIGpzb24gZ3JpZCBmaWxlc1xuICAgIF91cGRhdGU6IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAoIXRoaXMuYWN0aXZlKCkpIHJldHVybjtcblxuICAgICAgICB2YXIgYm91bmRzID0gdGhpcy5fbWFwLmdldFBpeGVsQm91bmRzKCksXG4gICAgICAgICAgICB6ID0gdGhpcy5fbWFwLmdldFpvb20oKSxcbiAgICAgICAgICAgIHRpbGVTaXplID0gMjU2O1xuXG4gICAgICAgIGlmICh6ID4gdGhpcy5vcHRpb25zLm1heFpvb20gfHwgeiA8IHRoaXMub3B0aW9ucy5taW5ab29tKSByZXR1cm47XG5cbiAgICAgICAgdmFyIHRpbGVCb3VuZHMgPSBMLmJvdW5kcyhcbiAgICAgICAgICAgICAgICBib3VuZHMubWluLmRpdmlkZUJ5KHRpbGVTaXplKS5fZmxvb3IoKSxcbiAgICAgICAgICAgICAgICBib3VuZHMubWF4LmRpdmlkZUJ5KHRpbGVTaXplKS5fZmxvb3IoKSksXG4gICAgICAgICAgICBtYXggPSB0aGlzLl9tYXAub3B0aW9ucy5jcnMuc2NhbGUoeikgLyB0aWxlU2l6ZTtcblxuICAgICAgICBmb3IgKHZhciB4ID0gdGlsZUJvdW5kcy5taW4ueDsgeCA8PSB0aWxlQm91bmRzLm1heC54OyB4KyspIHtcbiAgICAgICAgICAgIGZvciAodmFyIHkgPSB0aWxlQm91bmRzLm1pbi55OyB5IDw9IHRpbGVCb3VuZHMubWF4Lnk7IHkrKykge1xuICAgICAgICAgICAgICAgIC8vIHggd3JhcHBlZFxuICAgICAgICAgICAgICAgIHRoaXMuX2dldFRpbGUoeiwgKCh4ICUgbWF4KSArIG1heCkgJSBtYXgsICgoeSAlIG1heCkgKyBtYXgpICUgbWF4KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfZ2V0VGlsZTogZnVuY3Rpb24oeiwgeCwgeSwgY2FsbGJhY2spIHtcbiAgICAgICAgdmFyIGtleSA9IHogKyAnXycgKyB4ICsgJ18nICsgeSxcbiAgICAgICAgICAgIHRpbGVQb2ludCA9IEwucG9pbnQoeCwgeSk7XG5cbiAgICAgICAgdGlsZVBvaW50LnogPSB6O1xuXG4gICAgICAgIGlmICghdGhpcy5fdGlsZVNob3VsZEJlTG9hZGVkKHRpbGVQb2ludCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChrZXkgaW4gdGhpcy5fY2FjaGUpIHtcbiAgICAgICAgICAgIGlmICghY2FsbGJhY2spIHJldHVybjtcblxuICAgICAgICAgICAgaWYgKHR5cGVvZiB0aGlzLl9jYWNoZVtrZXldID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2sodGhpcy5fY2FjaGVba2V5XSk7IC8vIEFscmVhZHkgbG9hZGVkXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHRoaXMuX2NhY2hlW2tleV0ucHVzaChjYWxsYmFjayk7IC8vIFBlbmRpbmdcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fY2FjaGVba2V5XSA9IFtdO1xuXG4gICAgICAgIGlmIChjYWxsYmFjaykge1xuICAgICAgICAgICAgdGhpcy5fY2FjaGVba2V5XS5wdXNoKGNhbGxiYWNrKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlcXVlc3QodGhpcy5fZ2V0VGlsZVVSTCh0aWxlUG9pbnQpLCBMLmJpbmQoZnVuY3Rpb24oZXJyLCBqc29uKSB7XG4gICAgICAgICAgICB2YXIgY2FsbGJhY2tzID0gdGhpcy5fY2FjaGVba2V5XTtcbiAgICAgICAgICAgIHRoaXMuX2NhY2hlW2tleV0gPSBncmlkKGpzb24pO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBjYWxsYmFja3MubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgICAgICAgICBjYWxsYmFja3NbaV0odGhpcy5fY2FjaGVba2V5XSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sIHRoaXMpKTtcbiAgICB9LFxuXG4gICAgX3RpbGVTaG91bGRCZUxvYWRlZDogZnVuY3Rpb24odGlsZVBvaW50KSB7XG4gICAgICAgIGlmICh0aWxlUG9pbnQueiA+IHRoaXMub3B0aW9ucy5tYXhab29tIHx8IHRpbGVQb2ludC56IDwgdGhpcy5vcHRpb25zLm1pblpvb20pIHtcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuYm91bmRzKSB7XG4gICAgICAgICAgICB2YXIgdGlsZVNpemUgPSAyNTYsXG4gICAgICAgICAgICAgICAgbndQb2ludCA9IHRpbGVQb2ludC5tdWx0aXBseUJ5KHRpbGVTaXplKSxcbiAgICAgICAgICAgICAgICBzZVBvaW50ID0gbndQb2ludC5hZGQobmV3IEwuUG9pbnQodGlsZVNpemUsIHRpbGVTaXplKSksXG4gICAgICAgICAgICAgICAgbncgPSB0aGlzLl9tYXAudW5wcm9qZWN0KG53UG9pbnQpLFxuICAgICAgICAgICAgICAgIHNlID0gdGhpcy5fbWFwLnVucHJvamVjdChzZVBvaW50KSxcbiAgICAgICAgICAgICAgICBib3VuZHMgPSBuZXcgTC5MYXRMbmdCb3VuZHMoW253LCBzZV0pO1xuXG4gICAgICAgICAgICBpZiAoIXRoaXMub3B0aW9ucy5ib3VuZHMuaW50ZXJzZWN0cyhib3VuZHMpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzLkdyaWRMYXllciA9IEdyaWRMYXllcjtcblxubW9kdWxlLmV4cG9ydHMuZ3JpZExheWVyID0gZnVuY3Rpb24oXywgb3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgR3JpZExheWVyKF8sIG9wdGlvbnMpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGxlYWZsZXQgPSByZXF1aXJlKCcuL2xlYWZsZXQnKTtcblxucmVxdWlyZSgnLi9tYXBib3gnKTtcblxubW9kdWxlLmV4cG9ydHMgPSBsZWFmbGV0O1xuIiwibW9kdWxlLmV4cG9ydHMgPSB3aW5kb3cuTCA9IHJlcXVpcmUoJ2xlYWZsZXQvZGlzdC9sZWFmbGV0LXNyYycpO1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgTGVnZW5kQ29udHJvbCA9IEwuQ29udHJvbC5leHRlbmQoe1xuXG4gICAgb3B0aW9uczoge1xuICAgICAgICBwb3NpdGlvbjogJ2JvdHRvbXJpZ2h0JyxcbiAgICAgICAgc2FuaXRpemVyOiByZXF1aXJlKCdzYW5pdGl6ZS1jYWphJylcbiAgICB9LFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24ob3B0aW9ucykge1xuICAgICAgICBMLnNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XG4gICAgICAgIHRoaXMuX2xlZ2VuZHMgPSB7fTtcbiAgICB9LFxuXG4gICAgb25BZGQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICB0aGlzLl9jb250YWluZXIgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCAnbWFwLWxlZ2VuZHMgd2F4LWxlZ2VuZHMnKTtcbiAgICAgICAgTC5Eb21FdmVudC5kaXNhYmxlQ2xpY2tQcm9wYWdhdGlvbih0aGlzLl9jb250YWluZXIpO1xuXG4gICAgICAgIHRoaXMuX3VwZGF0ZSgpO1xuXG4gICAgICAgIHJldHVybiB0aGlzLl9jb250YWluZXI7XG4gICAgfSxcblxuICAgIGFkZExlZ2VuZDogZnVuY3Rpb24odGV4dCkge1xuICAgICAgICBpZiAoIXRleHQpIHsgcmV0dXJuIHRoaXM7IH1cblxuICAgICAgICBpZiAoIXRoaXMuX2xlZ2VuZHNbdGV4dF0pIHtcbiAgICAgICAgICAgIHRoaXMuX2xlZ2VuZHNbdGV4dF0gPSAwO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fbGVnZW5kc1t0ZXh0XSsrO1xuICAgICAgICByZXR1cm4gdGhpcy5fdXBkYXRlKCk7XG4gICAgfSxcblxuICAgIHJlbW92ZUxlZ2VuZDogZnVuY3Rpb24odGV4dCkge1xuICAgICAgICBpZiAoIXRleHQpIHsgcmV0dXJuIHRoaXM7IH1cbiAgICAgICAgaWYgKHRoaXMuX2xlZ2VuZHNbdGV4dF0pIHRoaXMuX2xlZ2VuZHNbdGV4dF0tLTtcbiAgICAgICAgcmV0dXJuIHRoaXMuX3VwZGF0ZSgpO1xuICAgIH0sXG5cbiAgICBfdXBkYXRlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgaWYgKCF0aGlzLl9tYXApIHsgcmV0dXJuIHRoaXM7IH1cblxuICAgICAgICB0aGlzLl9jb250YWluZXIuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIHZhciBoaWRlID0gJ25vbmUnO1xuXG4gICAgICAgIGZvciAodmFyIGkgaW4gdGhpcy5fbGVnZW5kcykge1xuICAgICAgICAgICAgaWYgKHRoaXMuX2xlZ2VuZHMuaGFzT3duUHJvcGVydHkoaSkgJiYgdGhpcy5fbGVnZW5kc1tpXSkge1xuICAgICAgICAgICAgICAgIHZhciBkaXYgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCAnbWFwLWxlZ2VuZCB3YXgtbGVnZW5kJywgdGhpcy5fY29udGFpbmVyKTtcbiAgICAgICAgICAgICAgICBkaXYuaW5uZXJIVE1MID0gdGhpcy5vcHRpb25zLnNhbml0aXplcihpKTtcbiAgICAgICAgICAgICAgICBoaWRlID0gJ2Jsb2NrJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIGhpZGUgdGhlIGNvbnRyb2wgZW50aXJlbHkgdW5sZXNzIHRoZXJlIGlzIGF0IGxlYXN0IG9uZSBsZWdlbmQ7XG4gICAgICAgIC8vIG90aGVyd2lzZSB0aGVyZSB3aWxsIGJlIGEgc21hbGwgZ3JleSBibGVtaXNoIG9uIHRoZSBtYXAuXG4gICAgICAgIHRoaXMuX2NvbnRhaW5lci5zdHlsZS5kaXNwbGF5ID0gaGlkZTtcblxuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMuTGVnZW5kQ29udHJvbCA9IExlZ2VuZENvbnRyb2w7XG5cbm1vZHVsZS5leHBvcnRzLmxlZ2VuZENvbnRyb2wgPSBmdW5jdGlvbihvcHRpb25zKSB7XG4gICAgcmV0dXJuIG5ldyBMZWdlbmRDb250cm9sKG9wdGlvbnMpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHJlcXVlc3QgPSByZXF1aXJlKCcuL3JlcXVlc3QnKSxcbiAgICBmb3JtYXRfdXJsID0gcmVxdWlyZSgnLi9mb3JtYXRfdXJsJyksXG4gICAgdXRpbCA9IHJlcXVpcmUoJy4vdXRpbCcpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBfbG9hZFRpbGVKU09OOiBmdW5jdGlvbihfKSB7XG4gICAgICAgIGlmICh0eXBlb2YgXyA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIF8gPSBmb3JtYXRfdXJsLnRpbGVKU09OKF8sIHRoaXMub3B0aW9ucyAmJiB0aGlzLm9wdGlvbnMuYWNjZXNzVG9rZW4pO1xuICAgICAgICAgICAgcmVxdWVzdChfLCBMLmJpbmQoZnVuY3Rpb24oZXJyLCBqc29uKSB7XG4gICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICB1dGlsLmxvZygnY291bGQgbm90IGxvYWQgVGlsZUpTT04gYXQgJyArIF8pO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmZpcmUoJ2Vycm9yJywge2Vycm9yOiBlcnJ9KTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKGpzb24pIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5fc2V0VGlsZUpTT04oanNvbik7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmlyZSgncmVhZHknKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCB0aGlzKSk7XG4gICAgICAgIH0gZWxzZSBpZiAoXyAmJiB0eXBlb2YgXyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIHRoaXMuX3NldFRpbGVKU09OKF8pO1xuICAgICAgICB9XG4gICAgfVxufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIHRpbGVMYXllciA9IHJlcXVpcmUoJy4vdGlsZV9sYXllcicpLnRpbGVMYXllcixcbiAgICBmZWF0dXJlTGF5ZXIgPSByZXF1aXJlKCcuL2ZlYXR1cmVfbGF5ZXInKS5mZWF0dXJlTGF5ZXIsXG4gICAgZ3JpZExheWVyID0gcmVxdWlyZSgnLi9ncmlkX2xheWVyJykuZ3JpZExheWVyLFxuICAgIGdyaWRDb250cm9sID0gcmVxdWlyZSgnLi9ncmlkX2NvbnRyb2wnKS5ncmlkQ29udHJvbCxcbiAgICBzaGFyZUNvbnRyb2wgPSByZXF1aXJlKCcuL3NoYXJlX2NvbnRyb2wnKS5zaGFyZUNvbnRyb2wsXG4gICAgbGVnZW5kQ29udHJvbCA9IHJlcXVpcmUoJy4vbGVnZW5kX2NvbnRyb2wnKS5sZWdlbmRDb250cm9sLFxuICAgIG1hcGJveExvZ29Db250cm9sID0gcmVxdWlyZSgnLi9tYXBib3hfbG9nbycpLm1hcGJveExvZ29Db250cm9sLFxuICAgIGZlZWRiYWNrID0gcmVxdWlyZSgnLi9mZWVkYmFjaycpO1xuXG5mdW5jdGlvbiB3aXRoQWNjZXNzVG9rZW4ob3B0aW9ucywgYWNjZXNzVG9rZW4pIHtcbiAgICBpZiAoIWFjY2Vzc1Rva2VuIHx8IG9wdGlvbnMuYWNjZXNzVG9rZW4pXG4gICAgICAgIHJldHVybiBvcHRpb25zO1xuICAgIHJldHVybiBMLmV4dGVuZCh7YWNjZXNzVG9rZW46IGFjY2Vzc1Rva2VufSwgb3B0aW9ucyk7XG59XG5cbnZhciBMTWFwID0gTC5NYXAuZXh0ZW5kKHtcbiAgICBpbmNsdWRlczogW3JlcXVpcmUoJy4vbG9hZF90aWxlanNvbicpXSxcblxuICAgIG9wdGlvbnM6IHtcbiAgICAgICAgdGlsZUxheWVyOiB7fSxcbiAgICAgICAgZmVhdHVyZUxheWVyOiB7fSxcbiAgICAgICAgZ3JpZExheWVyOiB7fSxcbiAgICAgICAgbGVnZW5kQ29udHJvbDoge30sXG4gICAgICAgIGdyaWRDb250cm9sOiB7fSxcbiAgICAgICAgc2hhcmVDb250cm9sOiBmYWxzZSxcbiAgICAgICAgc2FuaXRpemVyOiByZXF1aXJlKCdzYW5pdGl6ZS1jYWphJylcbiAgICB9LFxuXG4gICAgX3RpbGVqc29uOiB7fSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uKGVsZW1lbnQsIF8sIG9wdGlvbnMpIHtcblxuICAgICAgICBMLk1hcC5wcm90b3R5cGUuaW5pdGlhbGl6ZS5jYWxsKHRoaXMsIGVsZW1lbnQsXG4gICAgICAgICAgICBMLmV4dGVuZCh7fSwgTC5NYXAucHJvdG90eXBlLm9wdGlvbnMsIG9wdGlvbnMpKTtcblxuICAgICAgICAvLyBEaXNhYmxlIHRoZSBkZWZhdWx0ICdMZWFmbGV0JyB0ZXh0XG4gICAgICAgIGlmICh0aGlzLmF0dHJpYnV0aW9uQ29udHJvbCkge1xuICAgICAgICAgICAgdGhpcy5hdHRyaWJ1dGlvbkNvbnRyb2wuc2V0UHJlZml4KCcnKTtcblxuICAgICAgICAgICAgdmFyIGNvbXBhY3QgPSB0aGlzLm9wdGlvbnMuYXR0cmlidXRpb25Db250cm9sLmNvbXBhY3Q7XG4gICAgICAgICAgICAvLyBTZXQgYSBjb21wYWN0IGRpc3BsYXkgaWYgbWFwIGNvbnRhaW5lciB3aWR0aCBpcyA8IDY0MCBvclxuICAgICAgICAgICAgLy8gY29tcGFjdCBpcyBzZXQgdG8gYHRydWVgIGluIGF0dHJpYnV0aW9uQ29udHJvbCBvcHRpb25zLlxuICAgICAgICAgICAgaWYgKGNvbXBhY3QgfHwgKGNvbXBhY3QgIT09IGZhbHNlICYmIHRoaXMuX2NvbnRhaW5lci5vZmZzZXRXaWR0aCA8PSA2NDApKSB7XG4gICAgICAgICAgICAgICAgTC5Eb21VdGlsLmFkZENsYXNzKHRoaXMuYXR0cmlidXRpb25Db250cm9sLl9jb250YWluZXIsICdsZWFmbGV0LWNvbXBhY3QtYXR0cmlidXRpb24nKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKGNvbXBhY3QgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIHRoaXMub24oJ3Jlc2l6ZScsIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAodGhpcy5fY29udGFpbmVyLm9mZnNldFdpZHRoID4gNjQwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBMLkRvbVV0aWwucmVtb3ZlQ2xhc3ModGhpcy5hdHRyaWJ1dGlvbkNvbnRyb2wuX2NvbnRhaW5lciwgJ2xlYWZsZXQtY29tcGFjdC1hdHRyaWJ1dGlvbicpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgTC5Eb21VdGlsLmFkZENsYXNzKHRoaXMuYXR0cmlidXRpb25Db250cm9sLl9jb250YWluZXIsICdsZWFmbGV0LWNvbXBhY3QtYXR0cmlidXRpb24nKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy50aWxlTGF5ZXIpIHtcbiAgICAgICAgICAgIHRoaXMudGlsZUxheWVyID0gdGlsZUxheWVyKHVuZGVmaW5lZCxcbiAgICAgICAgICAgICAgICB3aXRoQWNjZXNzVG9rZW4odGhpcy5vcHRpb25zLnRpbGVMYXllciwgdGhpcy5vcHRpb25zLmFjY2Vzc1Rva2VuKSk7XG4gICAgICAgICAgICB0aGlzLmFkZExheWVyKHRoaXMudGlsZUxheWVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMuZmVhdHVyZUxheWVyKSB7XG4gICAgICAgICAgICB0aGlzLmZlYXR1cmVMYXllciA9IGZlYXR1cmVMYXllcih1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgd2l0aEFjY2Vzc1Rva2VuKHRoaXMub3B0aW9ucy5mZWF0dXJlTGF5ZXIsIHRoaXMub3B0aW9ucy5hY2Nlc3NUb2tlbikpO1xuICAgICAgICAgICAgdGhpcy5hZGRMYXllcih0aGlzLmZlYXR1cmVMYXllcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLmdyaWRMYXllcikge1xuICAgICAgICAgICAgdGhpcy5ncmlkTGF5ZXIgPSBncmlkTGF5ZXIodW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHdpdGhBY2Nlc3NUb2tlbih0aGlzLm9wdGlvbnMuZ3JpZExheWVyLCB0aGlzLm9wdGlvbnMuYWNjZXNzVG9rZW4pKTtcbiAgICAgICAgICAgIHRoaXMuYWRkTGF5ZXIodGhpcy5ncmlkTGF5ZXIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5ncmlkTGF5ZXIgJiYgdGhpcy5vcHRpb25zLmdyaWRDb250cm9sKSB7XG4gICAgICAgICAgICB0aGlzLmdyaWRDb250cm9sID0gZ3JpZENvbnRyb2wodGhpcy5ncmlkTGF5ZXIsIHRoaXMub3B0aW9ucy5ncmlkQ29udHJvbCk7XG4gICAgICAgICAgICB0aGlzLmFkZENvbnRyb2wodGhpcy5ncmlkQ29udHJvbCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLmxlZ2VuZENvbnRyb2wpIHtcbiAgICAgICAgICAgIHRoaXMubGVnZW5kQ29udHJvbCA9IGxlZ2VuZENvbnRyb2wodGhpcy5vcHRpb25zLmxlZ2VuZENvbnRyb2wpO1xuICAgICAgICAgICAgdGhpcy5hZGRDb250cm9sKHRoaXMubGVnZW5kQ29udHJvbCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5vcHRpb25zLnNoYXJlQ29udHJvbCkge1xuICAgICAgICAgICAgdGhpcy5zaGFyZUNvbnRyb2wgPSBzaGFyZUNvbnRyb2wodW5kZWZpbmVkLFxuICAgICAgICAgICAgICAgIHdpdGhBY2Nlc3NUb2tlbih0aGlzLm9wdGlvbnMuc2hhcmVDb250cm9sLCB0aGlzLm9wdGlvbnMuYWNjZXNzVG9rZW4pKTtcbiAgICAgICAgICAgIHRoaXMuYWRkQ29udHJvbCh0aGlzLnNoYXJlQ29udHJvbCk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9tYXBib3hMb2dvQ29udHJvbCA9IG1hcGJveExvZ29Db250cm9sKHRoaXMub3B0aW9ucy5tYXBib3hMb2dvQ29udHJvbCk7XG4gICAgICAgIHRoaXMuYWRkQ29udHJvbCh0aGlzLl9tYXBib3hMb2dvQ29udHJvbCk7XG5cbiAgICAgICAgdGhpcy5fbG9hZFRpbGVKU09OKF8pO1xuXG4gICAgICAgIHRoaXMub24oJ2xheWVyYWRkJywgdGhpcy5fb25MYXllckFkZCwgdGhpcylcbiAgICAgICAgICAgIC5vbignbGF5ZXJyZW1vdmUnLCB0aGlzLl9vbkxheWVyUmVtb3ZlLCB0aGlzKVxuICAgICAgICAgICAgLm9uKCdtb3ZlZW5kJywgdGhpcy5fdXBkYXRlTWFwRmVlZGJhY2tMaW5rLCB0aGlzKTtcblxuICAgICAgICB0aGlzLndoZW5SZWFkeShmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBmZWVkYmFjay5vbignY2hhbmdlJywgdGhpcy5fdXBkYXRlTWFwRmVlZGJhY2tMaW5rLCB0aGlzKTtcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5vbigndW5sb2FkJywgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgZmVlZGJhY2sub2ZmKCdjaGFuZ2UnLCB0aGlzLl91cGRhdGVNYXBGZWVkYmFja0xpbmssIHRoaXMpO1xuICAgICAgICB9KTtcbiAgICB9LFxuXG4gICAgLy8gdXNlIGEgamF2YXNjcmlwdCBvYmplY3Qgb2YgdGlsZWpzb24gZGF0YSB0byBjb25maWd1cmUgdGhpcyBsYXllclxuICAgIF9zZXRUaWxlSlNPTjogZnVuY3Rpb24oXykge1xuICAgICAgICB0aGlzLl90aWxlanNvbiA9IF87XG4gICAgICAgIHRoaXMuX2luaXRpYWxpemUoXyk7XG4gICAgICAgIHJldHVybiB0aGlzO1xuICAgIH0sXG5cbiAgICBnZXRUaWxlSlNPTjogZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiB0aGlzLl90aWxlanNvbjtcbiAgICB9LFxuXG4gICAgX2luaXRpYWxpemU6IGZ1bmN0aW9uKGpzb24pIHtcbiAgICAgICAgaWYgKHRoaXMudGlsZUxheWVyKSB7XG4gICAgICAgICAgICB0aGlzLnRpbGVMYXllci5fc2V0VGlsZUpTT04oanNvbik7XG4gICAgICAgICAgICB0aGlzLl91cGRhdGVMYXllcih0aGlzLnRpbGVMYXllcik7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5mZWF0dXJlTGF5ZXIgJiYgIXRoaXMuZmVhdHVyZUxheWVyLmdldEdlb0pTT04oKSAmJiBqc29uLmRhdGEgJiYganNvbi5kYXRhWzBdKSB7XG4gICAgICAgICAgICB0aGlzLmZlYXR1cmVMYXllci5sb2FkVVJMKGpzb24uZGF0YVswXSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodGhpcy5ncmlkTGF5ZXIpIHtcbiAgICAgICAgICAgIHRoaXMuZ3JpZExheWVyLl9zZXRUaWxlSlNPTihqc29uKTtcbiAgICAgICAgICAgIHRoaXMuX3VwZGF0ZUxheWVyKHRoaXMuZ3JpZExheWVyKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICh0aGlzLmxlZ2VuZENvbnRyb2wgJiYganNvbi5sZWdlbmQpIHtcbiAgICAgICAgICAgIHRoaXMubGVnZW5kQ29udHJvbC5hZGRMZWdlbmQoanNvbi5sZWdlbmQpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMuc2hhcmVDb250cm9sKSB7XG4gICAgICAgICAgICB0aGlzLnNoYXJlQ29udHJvbC5fc2V0VGlsZUpTT04oanNvbik7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl9tYXBib3hMb2dvQ29udHJvbC5fc2V0VGlsZUpTT04oanNvbik7XG5cbiAgICAgICAgaWYgKCF0aGlzLl9sb2FkZWQgJiYganNvbi5jZW50ZXIpIHtcbiAgICAgICAgICAgIHZhciB6b29tID0gdGhpcy5nZXRab29tKCkgIT09IHVuZGVmaW5lZCA/IHRoaXMuZ2V0Wm9vbSgpIDoganNvbi5jZW50ZXJbMl0sXG4gICAgICAgICAgICAgICAgY2VudGVyID0gTC5sYXRMbmcoanNvbi5jZW50ZXJbMV0sIGpzb24uY2VudGVyWzBdKTtcblxuICAgICAgICAgICAgdGhpcy5zZXRWaWV3KGNlbnRlciwgem9vbSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgX3VwZGF0ZU1hcEZlZWRiYWNrTGluazogZnVuY3Rpb24oKSB7XG4gICAgICAgIGlmICghdGhpcy5fY29udHJvbENvbnRhaW5lci5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKSByZXR1cm47XG4gICAgICAgIHZhciBsaW5rID0gdGhpcy5fY29udHJvbENvbnRhaW5lci5nZXRFbGVtZW50c0J5Q2xhc3NOYW1lKCdtYXBib3gtaW1wcm92ZS1tYXAnKTtcbiAgICAgICAgaWYgKGxpbmsubGVuZ3RoICYmIHRoaXMuX2xvYWRlZCkge1xuICAgICAgICAgICAgdmFyIGNlbnRlciA9IHRoaXMuZ2V0Q2VudGVyKCkud3JhcCgpO1xuICAgICAgICAgICAgdmFyIHRpbGVqc29uID0gdGhpcy5fdGlsZWpzb24gfHwge307XG4gICAgICAgICAgICB2YXIgaWQgPSB0aWxlanNvbi5pZCB8fCAnJztcblxuICAgICAgICAgICAgdmFyIGhhc2ggPSAnIycgKyBpZCArICcvJyArXG4gICAgICAgICAgICAgICAgY2VudGVyLmxuZy50b0ZpeGVkKDMpICsgJy8nICtcbiAgICAgICAgICAgICAgICBjZW50ZXIubGF0LnRvRml4ZWQoMykgKyAnLycgK1xuICAgICAgICAgICAgICAgIHRoaXMuZ2V0Wm9vbSgpO1xuXG4gICAgICAgICAgICBmb3IgKHZhciBrZXkgaW4gZmVlZGJhY2suZGF0YSkge1xuICAgICAgICAgICAgICAgIGhhc2ggKz0gJy8nICsga2V5ICsgJz0nICsgZmVlZGJhY2suZGF0YVtrZXldO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmsubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBsaW5rW2ldLmhhc2ggPSBoYXNoO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSxcblxuICAgIF9vbkxheWVyQWRkOiBmdW5jdGlvbihlKSB7XG4gICAgICAgIGlmICgnb24nIGluIGUubGF5ZXIpIHtcbiAgICAgICAgICAgIGUubGF5ZXIub24oJ3JlYWR5JywgdGhpcy5fb25MYXllclJlYWR5LCB0aGlzKTtcbiAgICAgICAgfVxuICAgICAgICB3aW5kb3cuc2V0VGltZW91dChMLmJpbmQodGhpcy5fdXBkYXRlTWFwRmVlZGJhY2tMaW5rLCB0aGlzKSwgMCk7IC8vIFVwZGF0ZSBhZnRlciBhdHRyaWJ1dGlvbiBjb250cm9sIHJlc2V0cyB0aGUgSFRNTC5cbiAgICB9LFxuXG4gICAgX29uTGF5ZXJSZW1vdmU6IGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgaWYgKCdvbicgaW4gZS5sYXllcikge1xuICAgICAgICAgICAgZS5sYXllci5vZmYoJ3JlYWR5JywgdGhpcy5fb25MYXllclJlYWR5LCB0aGlzKTtcbiAgICAgICAgfVxuICAgICAgICB3aW5kb3cuc2V0VGltZW91dChMLmJpbmQodGhpcy5fdXBkYXRlTWFwRmVlZGJhY2tMaW5rLCB0aGlzKSwgMCk7IC8vIFVwZGF0ZSBhZnRlciBhdHRyaWJ1dGlvbiBjb250cm9sIHJlc2V0cyB0aGUgSFRNTC5cbiAgICB9LFxuXG4gICAgX29uTGF5ZXJSZWFkeTogZnVuY3Rpb24oZSkge1xuICAgICAgICB0aGlzLl91cGRhdGVMYXllcihlLnRhcmdldCk7XG4gICAgfSxcblxuICAgIF91cGRhdGVMYXllcjogZnVuY3Rpb24obGF5ZXIpIHtcbiAgICAgICAgaWYgKCFsYXllci5vcHRpb25zKSByZXR1cm47XG5cbiAgICAgICAgaWYgKHRoaXMuYXR0cmlidXRpb25Db250cm9sICYmIHRoaXMuX2xvYWRlZCAmJiBsYXllci5nZXRBdHRyaWJ1dGlvbikge1xuICAgICAgICAgICAgdGhpcy5hdHRyaWJ1dGlvbkNvbnRyb2wuYWRkQXR0cmlidXRpb24obGF5ZXIuZ2V0QXR0cmlidXRpb24oKSk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoIShMLnN0YW1wKGxheWVyKSBpbiB0aGlzLl96b29tQm91bmRMYXllcnMpICYmXG4gICAgICAgICAgICAgICAgKGxheWVyLm9wdGlvbnMubWF4Wm9vbSB8fCBsYXllci5vcHRpb25zLm1pblpvb20pKSB7XG4gICAgICAgICAgICB0aGlzLl96b29tQm91bmRMYXllcnNbTC5zdGFtcChsYXllcildID0gbGF5ZXI7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLl91cGRhdGVNYXBGZWVkYmFja0xpbmsoKTtcbiAgICAgICAgdGhpcy5fdXBkYXRlWm9vbUxldmVscygpO1xuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cy5NYXAgPSBMTWFwO1xuXG5tb2R1bGUuZXhwb3J0cy5tYXAgPSBmdW5jdGlvbihlbGVtZW50LCBfLCBvcHRpb25zKSB7XG4gICAgcmV0dXJuIG5ldyBMTWFwKGVsZW1lbnQsIF8sIG9wdGlvbnMpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGdlb2NvZGVyQ29udHJvbCA9IHJlcXVpcmUoJy4vZ2VvY29kZXJfY29udHJvbCcpLFxuICAgIGdyaWRDb250cm9sID0gcmVxdWlyZSgnLi9ncmlkX2NvbnRyb2wnKSxcbiAgICBmZWF0dXJlTGF5ZXIgPSByZXF1aXJlKCcuL2ZlYXR1cmVfbGF5ZXInKSxcbiAgICBsZWdlbmRDb250cm9sID0gcmVxdWlyZSgnLi9sZWdlbmRfY29udHJvbCcpLFxuICAgIHNoYXJlQ29udHJvbCA9IHJlcXVpcmUoJy4vc2hhcmVfY29udHJvbCcpLFxuICAgIHRpbGVMYXllciA9IHJlcXVpcmUoJy4vdGlsZV9sYXllcicpLFxuICAgIG1hcCA9IHJlcXVpcmUoJy4vbWFwJyksXG4gICAgZ3JpZExheWVyID0gcmVxdWlyZSgnLi9ncmlkX2xheWVyJyksXG4gICAgc3R5bGVMYXllciA9IHJlcXVpcmUoJy4vc3R5bGVfbGF5ZXInKTtcblxuTC5tYXBib3ggPSBtb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBWRVJTSU9OOiByZXF1aXJlKCcuLi9wYWNrYWdlLmpzb24nKS52ZXJzaW9uLFxuICAgIGdlb2NvZGVyOiByZXF1aXJlKCcuL2dlb2NvZGVyJyksXG4gICAgbWFya2VyOiByZXF1aXJlKCcuL21hcmtlcicpLFxuICAgIHNpbXBsZXN0eWxlOiByZXF1aXJlKCcuL3NpbXBsZXN0eWxlJyksXG4gICAgdGlsZUxheWVyOiB0aWxlTGF5ZXIudGlsZUxheWVyLFxuICAgIFRpbGVMYXllcjogdGlsZUxheWVyLlRpbGVMYXllcixcbiAgICBzdHlsZUxheWVyOiBzdHlsZUxheWVyLnN0eWxlTGF5ZXIsXG4gICAgU3R5bGVMYXllcjogc3R5bGVMYXllci5TdHlsZUxheWVyLFxuICAgIHNoYXJlQ29udHJvbDogc2hhcmVDb250cm9sLnNoYXJlQ29udHJvbCxcbiAgICBTaGFyZUNvbnRyb2w6IHNoYXJlQ29udHJvbC5TaGFyZUNvbnRyb2wsXG4gICAgbGVnZW5kQ29udHJvbDogbGVnZW5kQ29udHJvbC5sZWdlbmRDb250cm9sLFxuICAgIExlZ2VuZENvbnRyb2w6IGxlZ2VuZENvbnRyb2wuTGVnZW5kQ29udHJvbCxcbiAgICBnZW9jb2RlckNvbnRyb2w6IGdlb2NvZGVyQ29udHJvbC5nZW9jb2RlckNvbnRyb2wsXG4gICAgR2VvY29kZXJDb250cm9sOiBnZW9jb2RlckNvbnRyb2wuR2VvY29kZXJDb250cm9sLFxuICAgIGdyaWRDb250cm9sOiBncmlkQ29udHJvbC5ncmlkQ29udHJvbCxcbiAgICBHcmlkQ29udHJvbDogZ3JpZENvbnRyb2wuR3JpZENvbnRyb2wsXG4gICAgZ3JpZExheWVyOiBncmlkTGF5ZXIuZ3JpZExheWVyLFxuICAgIEdyaWRMYXllcjogZ3JpZExheWVyLkdyaWRMYXllcixcbiAgICBmZWF0dXJlTGF5ZXI6IGZlYXR1cmVMYXllci5mZWF0dXJlTGF5ZXIsXG4gICAgRmVhdHVyZUxheWVyOiBmZWF0dXJlTGF5ZXIuRmVhdHVyZUxheWVyLFxuICAgIG1hcDogbWFwLm1hcCxcbiAgICBNYXA6IG1hcC5NYXAsXG4gICAgY29uZmlnOiByZXF1aXJlKCcuL2NvbmZpZycpLFxuICAgIHNhbml0aXplOiByZXF1aXJlKCdzYW5pdGl6ZS1jYWphJyksXG4gICAgdGVtcGxhdGU6IHJlcXVpcmUoJ211c3RhY2hlJykudG9faHRtbCxcbiAgICBmZWVkYmFjazogcmVxdWlyZSgnLi9mZWVkYmFjaycpXG59O1xuXG5cbi8vIEhhcmRjb2RlIGltYWdlIHBhdGgsIGJlY2F1c2UgTGVhZmxldCdzIGF1dG9kZXRlY3Rpb25cbi8vIGZhaWxzLCBiZWNhdXNlIG1hcGJveC5qcyBpcyBub3QgbmFtZWQgbGVhZmxldC5qc1xud2luZG93LkwuSWNvbi5EZWZhdWx0LmltYWdlUGF0aCA9XG4gICAgLy8gRGV0ZWN0IGJhZC1uZXdzIHByb3RvY29scyBsaWtlIGZpbGU6Ly8gYW5kIGhhcmRjb2RlXG4gICAgLy8gdG8gaHR0cHMgaWYgdGhleSdyZSBkZXRlY3RlZC5cbiAgICAoKGRvY3VtZW50LmxvY2F0aW9uLnByb3RvY29sID09PSAnaHR0cHM6JyB8fFxuICAgIGRvY3VtZW50LmxvY2F0aW9uLnByb3RvY29sID09PSAnaHR0cDonKSA/ICcnIDogJ2h0dHBzOicpICtcbiAgICAnLy9hcGkudGlsZXMubWFwYm94LmNvbS9tYXBib3guanMvJyArICd2JyArXG4gICAgcmVxdWlyZSgnLi4vcGFja2FnZS5qc29uJykudmVyc2lvbiArICcvaW1hZ2VzLyc7XG4iLCIndXNlIHN0cmljdCc7XG5cbnZhciBNYXBib3hMb2dvQ29udHJvbCA9IEwuQ29udHJvbC5leHRlbmQoe1xuXG4gICAgb3B0aW9uczoge1xuICAgICAgICBwb3NpdGlvbjogJ2JvdHRvbWxlZnQnXG4gICAgfSxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICAgICAgTC5zZXRPcHRpb25zKHRoaXMsIG9wdGlvbnMpO1xuICAgIH0sXG5cbiAgICBvbkFkZDogZnVuY3Rpb24oKSB7XG4gICAgICAgIHRoaXMuX2NvbnRhaW5lciA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsICdtYXBib3gtbG9nbycpO1xuICAgICAgICByZXR1cm4gdGhpcy5fY29udGFpbmVyO1xuICAgIH0sXG5cbiAgICBfc2V0VGlsZUpTT046IGZ1bmN0aW9uKGpzb24pIHtcbiAgICAgICAgLy8gQ2hlY2sgaWYgYWNjb3VudCByZWZlcmVuY2VkIGJ5IHRoZSBhY2Nlc3NUb2tlblxuICAgICAgICAvLyBpcyBhc3Njb2NpYXRlZCB3aXRoIHRoZSBNYXBib3ggTG9nb1xuICAgICAgICAvLyBhcyBkZXRlcm1pbmVkIGJ5IG1hcGJveC1tYXBzLlxuICAgICAgICBpZiAoanNvbi5tYXBib3hfbG9nbykge1xuICAgICAgICAgICAgTC5Eb21VdGlsLmFkZENsYXNzKHRoaXMuX2NvbnRhaW5lciwgJ21hcGJveC1sb2dvLXRydWUnKTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cy5NYXBib3hMb2dvQ29udHJvbCA9IE1hcGJveExvZ29Db250cm9sO1xuXG5tb2R1bGUuZXhwb3J0cy5tYXBib3hMb2dvQ29udHJvbCA9IGZ1bmN0aW9uKG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IE1hcGJveExvZ29Db250cm9sKG9wdGlvbnMpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxudmFyIGZvcm1hdF91cmwgPSByZXF1aXJlKCcuL2Zvcm1hdF91cmwnKSxcbiAgICB1dGlsID0gcmVxdWlyZSgnLi91dGlsJyksXG4gICAgc2FuaXRpemUgPSByZXF1aXJlKCdzYW5pdGl6ZS1jYWphJyk7XG5cbi8vIG1hcGJveC1yZWxhdGVkIG1hcmtlcnMgZnVuY3Rpb25hbGl0eVxuLy8gcHJvdmlkZSBhbiBpY29uIGZyb20gbWFwYm94J3Mgc2ltcGxlLXN0eWxlIHNwZWMgYW5kIGhvc3RlZCBtYXJrZXJzXG4vLyBzZXJ2aWNlXG5mdW5jdGlvbiBpY29uKGZwLCBvcHRpb25zKSB7XG4gICAgZnAgPSBmcCB8fCB7fTtcblxuICAgIHZhciBzaXplcyA9IHtcbiAgICAgICAgICAgIHNtYWxsOiBbMjAsIDUwXSxcbiAgICAgICAgICAgIG1lZGl1bTogWzMwLCA3MF0sXG4gICAgICAgICAgICBsYXJnZTogWzM1LCA5MF1cbiAgICAgICAgfSxcbiAgICAgICAgc2l6ZSA9IGZwWydtYXJrZXItc2l6ZSddIHx8ICdtZWRpdW0nLFxuICAgICAgICBzeW1ib2wgPSAoJ21hcmtlci1zeW1ib2wnIGluIGZwICYmIGZwWydtYXJrZXItc3ltYm9sJ10gIT09ICcnKSA/ICctJyArIGZwWydtYXJrZXItc3ltYm9sJ10gOiAnJyxcbiAgICAgICAgY29sb3IgPSAoZnBbJ21hcmtlci1jb2xvciddIHx8ICc3ZTdlN2UnKS5yZXBsYWNlKCcjJywgJycpO1xuXG4gICAgcmV0dXJuIEwuaWNvbih7XG4gICAgICAgIGljb25Vcmw6IGZvcm1hdF91cmwoJy92NC9tYXJrZXIvJyArXG4gICAgICAgICAgICAncGluLScgKyBzaXplLmNoYXJBdCgwKSArIHN5bWJvbCArICcrJyArIGNvbG9yICtcbiAgICAgICAgICAgIC8vIGRldGVjdCBhbmQgdXNlIHJldGluYSBtYXJrZXJzLCB3aGljaCBhcmUgeDIgcmVzb2x1dGlvblxuICAgICAgICAgICAgKEwuQnJvd3Nlci5yZXRpbmEgPyAnQDJ4JyA6ICcnKSArICcucG5nJywgb3B0aW9ucyAmJiBvcHRpb25zLmFjY2Vzc1Rva2VuKSxcbiAgICAgICAgaWNvblNpemU6IHNpemVzW3NpemVdLFxuICAgICAgICBpY29uQW5jaG9yOiBbc2l6ZXNbc2l6ZV1bMF0gLyAyLCBzaXplc1tzaXplXVsxXSAvIDJdLFxuICAgICAgICBwb3B1cEFuY2hvcjogWzAsIC1zaXplc1tzaXplXVsxXSAvIDJdXG4gICAgfSk7XG59XG5cbi8vIGEgZmFjdG9yeSB0aGF0IHByb3ZpZGVzIG1hcmtlcnMgZm9yIExlYWZsZXQgZnJvbSBNYXBib3gnc1xuLy8gW3NpbXBsZS1zdHlsZSBzcGVjaWZpY2F0aW9uXShodHRwczovL2dpdGh1Yi5jb20vbWFwYm94L3NpbXBsZXN0eWxlLXNwZWMpXG4vLyBhbmQgW01hcmtlcnMgQVBJXShodHRwOi8vbWFwYm94LmNvbS9kZXZlbG9wZXJzL2FwaS8jbWFya2VycykuXG5mdW5jdGlvbiBzdHlsZShmLCBsYXRsb24sIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gTC5tYXJrZXIobGF0bG9uLCB7XG4gICAgICAgIGljb246IGljb24oZi5wcm9wZXJ0aWVzLCBvcHRpb25zKSxcbiAgICAgICAgdGl0bGU6IHV0aWwuc3RyaXBfdGFncyhcbiAgICAgICAgICAgIHNhbml0aXplKChmLnByb3BlcnRpZXMgJiYgZi5wcm9wZXJ0aWVzLnRpdGxlKSB8fCAnJykpXG4gICAgfSk7XG59XG5cbi8vIFNhbml0aXplIGFuZCBmb3JtYXQgcHJvcGVydGllcyBvZiBhIEdlb0pTT04gRmVhdHVyZSBvYmplY3QgaW4gb3JkZXJcbi8vIHRvIGZvcm0gdGhlIEhUTUwgc3RyaW5nIHVzZWQgYXMgdGhlIGFyZ3VtZW50IGZvciBgTC5jcmVhdGVQb3B1cGBcbmZ1bmN0aW9uIGNyZWF0ZVBvcHVwKGYsIHNhbml0aXplcikge1xuICAgIGlmICghZiB8fCAhZi5wcm9wZXJ0aWVzKSByZXR1cm4gJyc7XG4gICAgdmFyIHBvcHVwID0gJyc7XG5cbiAgICBpZiAoZi5wcm9wZXJ0aWVzLnRpdGxlKSB7XG4gICAgICAgIHBvcHVwICs9ICc8ZGl2IGNsYXNzPVwibWFya2VyLXRpdGxlXCI+JyArIGYucHJvcGVydGllcy50aXRsZSArICc8L2Rpdj4nO1xuICAgIH1cblxuICAgIGlmIChmLnByb3BlcnRpZXMuZGVzY3JpcHRpb24pIHtcbiAgICAgICAgcG9wdXAgKz0gJzxkaXYgY2xhc3M9XCJtYXJrZXItZGVzY3JpcHRpb25cIj4nICsgZi5wcm9wZXJ0aWVzLmRlc2NyaXB0aW9uICsgJzwvZGl2Pic7XG4gICAgfVxuXG4gICAgcmV0dXJuIChzYW5pdGl6ZXIgfHwgc2FuaXRpemUpKHBvcHVwKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgaWNvbjogaWNvbixcbiAgICBzdHlsZTogc3R5bGUsXG4gICAgY3JlYXRlUG9wdXA6IGNyZWF0ZVBvcHVwXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgY29yc2xpdGUgPSByZXF1aXJlKCdjb3JzbGl0ZScpLFxuICAgIHN0cmljdCA9IHJlcXVpcmUoJy4vdXRpbCcpLnN0cmljdCxcbiAgICBjb25maWcgPSByZXF1aXJlKCcuL2NvbmZpZycpO1xuXG52YXIgcHJvdG9jb2wgPSAvXihodHRwcz86KT8oPz1cXC9cXC8oLnxhcGkpXFwudGlsZXNcXC5tYXBib3hcXC5jb21cXC8pLztcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbih1cmwsIGNhbGxiYWNrKSB7XG4gICAgc3RyaWN0KHVybCwgJ3N0cmluZycpO1xuICAgIHN0cmljdChjYWxsYmFjaywgJ2Z1bmN0aW9uJyk7XG5cbiAgICB1cmwgPSB1cmwucmVwbGFjZShwcm90b2NvbCwgZnVuY3Rpb24obWF0Y2gsIHByb3RvY29sKSB7XG4gICAgICAgIGlmICghKCd3aXRoQ3JlZGVudGlhbHMnIGluIG5ldyB3aW5kb3cuWE1MSHR0cFJlcXVlc3QoKSkpIHtcbiAgICAgICAgICAgIC8vIFhEb21haW5SZXF1ZXN0IGluIHVzZTsgZG9lc24ndCBzdXBwb3J0IGNyb3NzLXByb3RvY29sIHJlcXVlc3RzXG4gICAgICAgICAgICByZXR1cm4gZG9jdW1lbnQubG9jYXRpb24ucHJvdG9jb2w7XG4gICAgICAgIH0gZWxzZSBpZiAocHJvdG9jb2wgPT09ICdodHRwczonIHx8IGRvY3VtZW50LmxvY2F0aW9uLnByb3RvY29sID09PSAnaHR0cHM6JyB8fCBjb25maWcuRk9SQ0VfSFRUUFMpIHtcbiAgICAgICAgICAgIHJldHVybiAnaHR0cHM6JztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHJldHVybiAnaHR0cDonO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICBmdW5jdGlvbiBvbmxvYWQoZXJyLCByZXNwKSB7XG4gICAgICAgIGlmICghZXJyICYmIHJlc3ApIHtcbiAgICAgICAgICAgIHJlc3AgPSBKU09OLnBhcnNlKHJlc3AucmVzcG9uc2VUZXh0KTtcbiAgICAgICAgfVxuICAgICAgICBjYWxsYmFjayhlcnIsIHJlc3ApO1xuICAgIH1cblxuICAgIHJldHVybiBjb3JzbGl0ZSh1cmwsIG9ubG9hZCk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgZm9ybWF0X3VybCA9IHJlcXVpcmUoJy4vZm9ybWF0X3VybCcpO1xuXG52YXIgU2hhcmVDb250cm9sID0gTC5Db250cm9sLmV4dGVuZCh7XG4gICAgaW5jbHVkZXM6IFtyZXF1aXJlKCcuL2xvYWRfdGlsZWpzb24nKV0sXG5cbiAgICBvcHRpb25zOiB7XG4gICAgICAgIHBvc2l0aW9uOiAndG9wbGVmdCcsXG4gICAgICAgIHVybDogJydcbiAgICB9LFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24oXywgb3B0aW9ucykge1xuICAgICAgICBMLnNldE9wdGlvbnModGhpcywgb3B0aW9ucyk7XG4gICAgICAgIHRoaXMuX2xvYWRUaWxlSlNPTihfKTtcbiAgICB9LFxuXG4gICAgX3NldFRpbGVKU09OOiBmdW5jdGlvbihqc29uKSB7XG4gICAgICAgIHRoaXMuX3RpbGVqc29uID0ganNvbjtcbiAgICB9LFxuXG4gICAgb25BZGQ6IGZ1bmN0aW9uKG1hcCkge1xuICAgICAgICB0aGlzLl9tYXAgPSBtYXA7XG5cbiAgICAgICAgdmFyIGNvbnRhaW5lciA9IEwuRG9tVXRpbC5jcmVhdGUoJ2RpdicsICdsZWFmbGV0LWNvbnRyb2wtbWFwYm94LXNoYXJlIGxlYWZsZXQtYmFyJyk7XG4gICAgICAgIHZhciBsaW5rID0gTC5Eb21VdGlsLmNyZWF0ZSgnYScsICdtYXBib3gtc2hhcmUgbWFwYm94LWljb24gbWFwYm94LWljb24tc2hhcmUnLCBjb250YWluZXIpO1xuICAgICAgICBsaW5rLmhyZWYgPSAnIyc7XG5cbiAgICAgICAgdGhpcy5fbW9kYWwgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCAnbWFwYm94LW1vZGFsJywgdGhpcy5fbWFwLl9jb250YWluZXIpO1xuICAgICAgICB0aGlzLl9tYXNrID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2JywgJ21hcGJveC1tb2RhbC1tYXNrJywgdGhpcy5fbW9kYWwpO1xuICAgICAgICB0aGlzLl9jb250ZW50ID0gTC5Eb21VdGlsLmNyZWF0ZSgnZGl2JywgJ21hcGJveC1tb2RhbC1jb250ZW50JywgdGhpcy5fbW9kYWwpO1xuXG4gICAgICAgIEwuRG9tRXZlbnQuYWRkTGlzdGVuZXIobGluaywgJ2NsaWNrJywgdGhpcy5fc2hhcmVDbGljaywgdGhpcyk7XG4gICAgICAgIEwuRG9tRXZlbnQuZGlzYWJsZUNsaWNrUHJvcGFnYXRpb24oY29udGFpbmVyKTtcblxuICAgICAgICB0aGlzLl9tYXAub24oJ21vdXNlZG93bicsIHRoaXMuX2NsaWNrT3V0LCB0aGlzKTtcblxuICAgICAgICByZXR1cm4gY29udGFpbmVyO1xuICAgIH0sXG5cbiAgICBfY2xpY2tPdXQ6IGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgaWYgKHRoaXMuX3NoYXJpbmcpIHtcbiAgICAgICAgICAgIEwuRG9tRXZlbnQucHJldmVudERlZmF1bHQoZSk7XG4gICAgICAgICAgICBMLkRvbVV0aWwucmVtb3ZlQ2xhc3ModGhpcy5fbW9kYWwsICdhY3RpdmUnKTtcbiAgICAgICAgICAgIHRoaXMuX2NvbnRlbnQuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgICAgICB0aGlzLl9zaGFyaW5nID0gbnVsbDtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBfc2hhcmVDbGljazogZnVuY3Rpb24oZSkge1xuICAgICAgICBMLkRvbUV2ZW50LnN0b3AoZSk7XG4gICAgICAgIGlmICh0aGlzLl9zaGFyaW5nKSByZXR1cm4gdGhpcy5fY2xpY2tPdXQoZSk7XG5cbiAgICAgICAgdmFyIHRpbGVqc29uID0gdGhpcy5fdGlsZWpzb24gfHwgdGhpcy5fbWFwLl90aWxlanNvbiB8fCB7fSxcbiAgICAgICAgICAgIHVybCA9IGVuY29kZVVSSUNvbXBvbmVudCh0aGlzLm9wdGlvbnMudXJsIHx8IHRpbGVqc29uLndlYnBhZ2UgfHwgd2luZG93LmxvY2F0aW9uKSxcbiAgICAgICAgICAgIG5hbWUgPSBlbmNvZGVVUklDb21wb25lbnQodGlsZWpzb24ubmFtZSksXG4gICAgICAgICAgICBpbWFnZSA9IGZvcm1hdF91cmwoJy92NC8nICsgdGlsZWpzb24uaWQgKyAnLycgKyB0aGlzLl9tYXAuZ2V0Q2VudGVyKCkubG5nICsgJywnICsgdGhpcy5fbWFwLmdldENlbnRlcigpLmxhdCArICcsJyArIHRoaXMuX21hcC5nZXRab29tKCkgKyAnLzYwMHg2MDAucG5nJywgdGhpcy5vcHRpb25zLmFjY2Vzc1Rva2VuKSxcbiAgICAgICAgICAgIGVtYmVkID0gZm9ybWF0X3VybCgnL3Y0LycgKyB0aWxlanNvbi5pZCArICcuaHRtbCcsIHRoaXMub3B0aW9ucy5hY2Nlc3NUb2tlbiksXG4gICAgICAgICAgICB0d2l0dGVyVVJMID0gJy8vdHdpdHRlci5jb20vaW50ZW50L3R3ZWV0P3N0YXR1cz0nICsgbmFtZSArICcgJyArIHVybCxcbiAgICAgICAgICAgIGZhY2Vib29rVVJMID0gJy8vd3d3LmZhY2Vib29rLmNvbS9zaGFyZXIucGhwP3U9JyArIHVybCArICcmdD0nICsgbmFtZSxcbiAgICAgICAgICAgIHBpbnRlcmVzdFVSTCA9ICcvL3d3dy5waW50ZXJlc3QuY29tL3Bpbi9jcmVhdGUvYnV0dG9uLz91cmw9JyArIHVybCArICcmbWVkaWE9JyArIGltYWdlICsgJyZkZXNjcmlwdGlvbj0nICsgbmFtZSxcbiAgICAgICAgICAgIGVtYmVkVmFsdWUgPSAnPGlmcmFtZSB3aWR0aD1cIjEwMCVcIiBoZWlnaHQ9XCI1MDBweFwiIGZyYW1lQm9yZGVyPVwiMFwiIHNyYz1cIicgKyBlbWJlZCArICdcIj48L2lmcmFtZT4nLFxuICAgICAgICAgICAgZW1iZWRMYWJlbCA9ICdDb3B5IGFuZCBwYXN0ZSB0aGlzIDxzdHJvbmc+SFRNTCBjb2RlPC9zdHJvbmc+IGludG8gZG9jdW1lbnRzIHRvIGVtYmVkIHRoaXMgbWFwIG9uIHdlYiBwYWdlcy4nO1xuXG4gICAgICAgIGZ1bmN0aW9uIGNyZWF0ZVNoYXJlQnV0dG9uKGJ1dHRvbkNsYXNzLCBocmVmLCBzb2NpYWxNZWRpYU5hbWUpIHtcbiAgICAgICAgICAgIHZhciBlbGVtID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYScpO1xuICAgICAgICAgICAgZWxlbS5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywgYnV0dG9uQ2xhc3MpO1xuICAgICAgICAgICAgZWxlbS5zZXRBdHRyaWJ1dGUoJ2hyZWYnLCBocmVmKTtcbiAgICAgICAgICAgIGVsZW0uc2V0QXR0cmlidXRlKCd0YXJnZXQnLCAnX2JsYW5rJyk7XG4gICAgICAgICAgICBzb2NpYWxNZWRpYU5hbWUgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShzb2NpYWxNZWRpYU5hbWUpO1xuICAgICAgICAgICAgZWxlbS5hcHBlbmRDaGlsZChzb2NpYWxNZWRpYU5hbWUpO1xuXG4gICAgICAgICAgICByZXR1cm4gZWxlbTtcbiAgICAgICAgfVxuXG4gICAgICAgIEwuRG9tVXRpbC5hZGRDbGFzcyh0aGlzLl9tb2RhbCwgJ2FjdGl2ZScpO1xuXG4gICAgICAgIHRoaXMuX3NoYXJpbmcgPSBMLkRvbVV0aWwuY3JlYXRlKCdkaXYnLCAnbWFwYm94LW1vZGFsLWJvZHknLCB0aGlzLl9jb250ZW50KTtcblxuICAgICAgICB2YXIgdHdpdHRlckJ1dHRvbiA9IGNyZWF0ZVNoYXJlQnV0dG9uKCdtYXBib3gtYnV0dG9uIG1hcGJveC1idXR0b24taWNvbiBtYXBib3gtaWNvbi10d2l0dGVyJywgdHdpdHRlclVSTCwgJ1R3aXR0ZXInKTtcbiAgICAgICAgdmFyIGZhY2Vib29rQnV0dG9uID0gY3JlYXRlU2hhcmVCdXR0b24oJ21hcGJveC1idXR0b24gbWFwYm94LWJ1dHRvbi1pY29uIG1hcGJveC1pY29uLWZhY2Vib29rJywgZmFjZWJvb2tVUkwsICdGYWNlYm9vaycpO1xuICAgICAgICB2YXIgcGludGVyZXN0QnV0dG9uID0gY3JlYXRlU2hhcmVCdXR0b24oJ21hcGJveC1idXR0b24gbWFwYm94LWJ1dHRvbi1pY29uIG1hcGJveC1pY29uLXBpbnRlcmVzdCcsIHBpbnRlcmVzdFVSTCwgJ1BpbnRlcmVzdCcpO1xuXG4gICAgICAgIHZhciBzaGFyZUhlYWRlciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2gzJyk7XG4gICAgICAgIHZhciBzaGFyZVRleHQgPSBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZSgnU2hhcmUgdGhpcyBtYXAnKTtcbiAgICAgICAgc2hhcmVIZWFkZXIuYXBwZW5kQ2hpbGQoc2hhcmVUZXh0KTtcblxuICAgICAgICB2YXIgc2hhcmVCdXR0b25zID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICAgIHNoYXJlQnV0dG9ucy5zZXRBdHRyaWJ1dGUoJ2NsYXNzJywgJ21hcGJveC1zaGFyZS1idXR0b25zJyk7XG4gICAgICAgIHNoYXJlQnV0dG9ucy5hcHBlbmRDaGlsZChmYWNlYm9va0J1dHRvbik7XG4gICAgICAgIHNoYXJlQnV0dG9ucy5hcHBlbmRDaGlsZCh0d2l0dGVyQnV0dG9uKTtcbiAgICAgICAgc2hhcmVCdXR0b25zLmFwcGVuZENoaWxkKHBpbnRlcmVzdEJ1dHRvbik7XG5cbiAgICAgICAgdGhpcy5fc2hhcmluZy5hcHBlbmRDaGlsZChzaGFyZUhlYWRlcik7XG4gICAgICAgIHRoaXMuX3NoYXJpbmcuYXBwZW5kQ2hpbGQoc2hhcmVCdXR0b25zKTtcblxuICAgICAgICB2YXIgaW5wdXQgPSBMLkRvbVV0aWwuY3JlYXRlKCdpbnB1dCcsICdtYXBib3gtZW1iZWQnLCB0aGlzLl9zaGFyaW5nKTtcbiAgICAgICAgaW5wdXQudHlwZSA9ICd0ZXh0JztcbiAgICAgICAgaW5wdXQudmFsdWUgPSBlbWJlZFZhbHVlO1xuXG4gICAgICAgIHZhciBsYWJlbCA9IEwuRG9tVXRpbC5jcmVhdGUoJ2xhYmVsJywgJ21hcGJveC1lbWJlZC1kZXNjcmlwdGlvbicsIHRoaXMuX3NoYXJpbmcpO1xuICAgICAgICBsYWJlbC5pbm5lckhUTUwgPSBlbWJlZExhYmVsO1xuXG4gICAgICAgIHZhciBjbG9zZSA9IEwuRG9tVXRpbC5jcmVhdGUoJ2EnLCAnbGVhZmxldC1wb3B1cC1jbG9zZS1idXR0b24nLCB0aGlzLl9zaGFyaW5nKTtcbiAgICAgICAgY2xvc2UuaHJlZiA9ICcjJztcblxuICAgICAgICBMLkRvbUV2ZW50LmRpc2FibGVDbGlja1Byb3BhZ2F0aW9uKHRoaXMuX3NoYXJpbmcpO1xuICAgICAgICBMLkRvbUV2ZW50LmFkZExpc3RlbmVyKGNsb3NlLCAnY2xpY2snLCB0aGlzLl9jbGlja091dCwgdGhpcyk7XG4gICAgICAgIEwuRG9tRXZlbnQuYWRkTGlzdGVuZXIoaW5wdXQsICdjbGljaycsIGZ1bmN0aW9uKGUpIHtcbiAgICAgICAgICAgIGUudGFyZ2V0LmZvY3VzKCk7XG4gICAgICAgICAgICBlLnRhcmdldC5zZWxlY3QoKTtcbiAgICAgICAgfSk7XG4gICAgfVxufSk7XG5cbm1vZHVsZS5leHBvcnRzLlNoYXJlQ29udHJvbCA9IFNoYXJlQ29udHJvbDtcblxubW9kdWxlLmV4cG9ydHMuc2hhcmVDb250cm9sID0gZnVuY3Rpb24oXywgb3B0aW9ucykge1xuICAgIHJldHVybiBuZXcgU2hhcmVDb250cm9sKF8sIG9wdGlvbnMpO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuLy8gYW4gaW1wbGVtZW50YXRpb24gb2YgdGhlIHNpbXBsZXN0eWxlIHNwZWMgZm9yIHBvbHlnb24gYW5kIGxpbmVzdHJpbmcgZmVhdHVyZXNcbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9tYXBib3gvc2ltcGxlc3R5bGUtc3BlY1xudmFyIGRlZmF1bHRzID0ge1xuICAgIHN0cm9rZTogJyM1NTU1NTUnLFxuICAgICdzdHJva2Utd2lkdGgnOiAyLFxuICAgICdzdHJva2Utb3BhY2l0eSc6IDEsXG4gICAgZmlsbDogJyM1NTU1NTUnLFxuICAgICdmaWxsLW9wYWNpdHknOiAwLjVcbn07XG5cbnZhciBtYXBwaW5nID0gW1xuICAgIFsnc3Ryb2tlJywgJ2NvbG9yJ10sXG4gICAgWydzdHJva2Utd2lkdGgnLCAnd2VpZ2h0J10sXG4gICAgWydzdHJva2Utb3BhY2l0eScsICdvcGFjaXR5J10sXG4gICAgWydmaWxsJywgJ2ZpbGxDb2xvciddLFxuICAgIFsnZmlsbC1vcGFjaXR5JywgJ2ZpbGxPcGFjaXR5J11cbl07XG5cbmZ1bmN0aW9uIGZhbGxiYWNrKGEsIGIpIHtcbiAgICB2YXIgYyA9IHt9O1xuICAgIGZvciAodmFyIGsgaW4gYikge1xuICAgICAgICBpZiAoYVtrXSA9PT0gdW5kZWZpbmVkKSBjW2tdID0gYltrXTtcbiAgICAgICAgZWxzZSBjW2tdID0gYVtrXTtcbiAgICB9XG4gICAgcmV0dXJuIGM7XG59XG5cbmZ1bmN0aW9uIHJlbWFwKGEpIHtcbiAgICB2YXIgZCA9IHt9O1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbWFwcGluZy5sZW5ndGg7IGkrKykge1xuICAgICAgICBkW21hcHBpbmdbaV1bMV1dID0gYVttYXBwaW5nW2ldWzBdXTtcbiAgICB9XG4gICAgcmV0dXJuIGQ7XG59XG5cbmZ1bmN0aW9uIHN0eWxlKGZlYXR1cmUpIHtcbiAgICByZXR1cm4gcmVtYXAoZmFsbGJhY2soZmVhdHVyZS5wcm9wZXJ0aWVzIHx8IHt9LCBkZWZhdWx0cykpO1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBzdHlsZTogc3R5bGUsXG4gICAgZGVmYXVsdHM6IGRlZmF1bHRzXG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4vdXRpbCcpO1xudmFyIGZvcm1hdF91cmwgPSByZXF1aXJlKCcuL2Zvcm1hdF91cmwnKTtcbnZhciByZXF1ZXN0ID0gcmVxdWlyZSgnLi9yZXF1ZXN0Jyk7XG5cbnZhciBTdHlsZUxheWVyID0gTC5UaWxlTGF5ZXIuZXh0ZW5kKHtcblxuICAgIG9wdGlvbnM6IHtcbiAgICAgICAgc2FuaXRpemVyOiByZXF1aXJlKCdzYW5pdGl6ZS1jYWphJylcbiAgICB9LFxuXG4gICAgaW5pdGlhbGl6ZTogZnVuY3Rpb24oXywgb3B0aW9ucykge1xuICAgICAgICBMLlRpbGVMYXllci5wcm90b3R5cGUuaW5pdGlhbGl6ZS5jYWxsKHRoaXMsIHVuZGVmaW5lZCwgTC5leHRlbmQoe30sIG9wdGlvbnMsIHtcbiAgICAgICAgICAgIHRpbGVTaXplOiA1MTIsXG4gICAgICAgICAgICB6b29tT2Zmc2V0OiAtMSxcbiAgICAgICAgICAgIG1pbk5hdGl2ZVpvb206IDAsXG4gICAgICAgICAgICB0bXM6IGZhbHNlXG4gICAgICAgIH0pKTtcbiAgICAgICAgdGhpcy5fdXJsID0gdGhpcy5fZm9ybWF0VGlsZVVSTChfKTtcbiAgICAgICAgdGhpcy5fZ2V0QXR0cmlidXRpb24oXyk7XG4gICAgfSxcblxuICAgIF9nZXRBdHRyaWJ1dGlvbjogZnVuY3Rpb24oXykge1xuICAgICAgICB2YXIgc3R5bGVVUkwgPSBmb3JtYXRfdXJsLnN0eWxlKF8sIHRoaXMub3B0aW9ucyAmJiB0aGlzLm9wdGlvbnMuYWNjZXNzVG9rZW4pO1xuICAgICAgICByZXF1ZXN0KHN0eWxlVVJMLCBMLmJpbmQoZnVuY3Rpb24oZXJyLCBzdHlsZSkge1xuICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgIHV0aWwubG9nKCdjb3VsZCBub3QgbG9hZCBNYXBib3ggc3R5bGUgYXQgJyArIHN0eWxlVVJMKTtcbiAgICAgICAgICAgICAgICB0aGlzLmZpcmUoJ2Vycm9yJywge2Vycm9yOiBlcnJ9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBzb3VyY2VzID0gW107XG4gICAgICAgICAgICBmb3IgKHZhciBpZCBpbiBzdHlsZS5zb3VyY2VzKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNvdXJjZSA9IHN0eWxlLnNvdXJjZXNbaWRdLnVybC5zcGxpdCgnbWFwYm94Oi8vJylbMV07XG4gICAgICAgICAgICAgICAgc291cmNlcy5wdXNoKHNvdXJjZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXF1ZXN0KGZvcm1hdF91cmwudGlsZUpTT04oc291cmNlcy5qb2luKCksIHRoaXMub3B0aW9ucy5hY2Nlc3NUb2tlbiksIEwuYmluZChmdW5jdGlvbihlcnIsIGpzb24pIHtcbiAgICAgICAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICAgICAgICAgIHV0aWwubG9nKCdjb3VsZCBub3QgbG9hZCBUaWxlSlNPTiBhdCAnICsgXyk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmlyZSgnZXJyb3InLCB7ZXJyb3I6IGVycn0pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoanNvbikge1xuICAgICAgICAgICAgICAgICAgICB1dGlsLnN0cmljdChqc29uLCAnb2JqZWN0Jyk7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5vcHRpb25zLmF0dHJpYnV0aW9uID0gdGhpcy5vcHRpb25zLnNhbml0aXplcihqc29uLmF0dHJpYnV0aW9uKTtcblxuICAgICAgICAgICAgICAgICAgICB0aGlzLl90aWxlanNvbiA9IGpzb247XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuZmlyZSgncmVhZHknKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LCB0aGlzKSk7XG4gICAgICAgIH0sIHRoaXMpKTtcbiAgICB9LFxuXG4gICAgLy8gZGlzYWJsZSB0aGUgc2V0VXJsIGZ1bmN0aW9uLCB3aGljaCBpcyBub3QgYXZhaWxhYmxlIG9uIG1hcGJveCB0aWxlbGF5ZXJzXG4gICAgc2V0VXJsOiBudWxsLFxuXG4gICAgX2Zvcm1hdFRpbGVVUkw6IGZ1bmN0aW9uKHN0eWxlKSB7XG4gICAgICAgIGlmICh0eXBlb2Ygc3R5bGUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBpZiAoc3R5bGUuaW5kZXhPZignbWFwYm94Oi8vc3R5bGVzLycpID09PSAtMSkge1xuICAgICAgICAgICAgICAgIHV0aWwubG9nKCdJbmNvcnJlY3RseSBmb3JtYXR0ZWQgTWFwYm94IHN0eWxlIGF0ICcgKyBzdHlsZSk7XG4gICAgICAgICAgICAgICAgdGhpcy5maXJlKCdlcnJvcicpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIG93bmVySURTdHlsZSA9IHN0eWxlLnNwbGl0KCdtYXBib3g6Ly9zdHlsZXMvJylbMV07XG4gICAgICAgICAgICByZXR1cm4gZm9ybWF0X3VybCgnL3N0eWxlcy92MS8nICsgb3duZXJJRFN0eWxlICsgJy90aWxlcy97en0ve3h9L3t5fXtyfScsIHRoaXMub3B0aW9ucy5hY2Nlc3NUb2tlbik7XG4gICAgICAgIH0gZWxzZSBpZiAodHlwZW9mIHN0eWxlID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgcmV0dXJuIGZvcm1hdF91cmwoJy9zdHlsZXMvdjEvJyArIHN0eWxlLm93bmVyICsgJy8nICsgc3R5bGUuaWQgKyAnL3RpbGVzL3t6fS97eH0ve3l9e3J9JywgdGhpcy5vcHRpb25zLmFjY2Vzc1Rva2VuKTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG5tb2R1bGUuZXhwb3J0cy5TdHlsZUxheWVyID0gU3R5bGVMYXllcjtcblxubW9kdWxlLmV4cG9ydHMuc3R5bGVMYXllciA9IGZ1bmN0aW9uKF8sIG9wdGlvbnMpIHtcbiAgICByZXR1cm4gbmV3IFN0eWxlTGF5ZXIoXywgb3B0aW9ucyk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXRpbCA9IHJlcXVpcmUoJy4vdXRpbCcpO1xudmFyIGZvcm1hdFBhdHRlcm4gPSAvXFwuKCg/OnBuZ3xqcGcpXFxkKikoPz0kfFxcPykvO1xuXG52YXIgVGlsZUxheWVyID0gTC5UaWxlTGF5ZXIuZXh0ZW5kKHtcbiAgICBpbmNsdWRlczogW3JlcXVpcmUoJy4vbG9hZF90aWxlanNvbicpXSxcblxuICAgIG9wdGlvbnM6IHtcbiAgICAgICAgc2FuaXRpemVyOiByZXF1aXJlKCdzYW5pdGl6ZS1jYWphJylcbiAgICB9LFxuXG4gICAgLy8gaHR0cDovL21hcGJveC5jb20vZGV2ZWxvcGVycy9hcGkvI2ltYWdlX3F1YWxpdHlcbiAgICBmb3JtYXRzOiBbXG4gICAgICAgICdwbmcnLCAnanBnJyxcbiAgICAgICAgLy8gUE5HXG4gICAgICAgICdwbmczMicsICdwbmc2NCcsICdwbmcxMjgnLCAncG5nMjU2JyxcbiAgICAgICAgLy8gSlBHXG4gICAgICAgICdqcGc3MCcsICdqcGc4MCcsICdqcGc5MCddLFxuXG4gICAgc2NhbGVQcmVmaXg6ICdAMnguJyxcblxuICAgIGluaXRpYWxpemU6IGZ1bmN0aW9uKF8sIG9wdGlvbnMpIHtcbiAgICAgICAgTC5UaWxlTGF5ZXIucHJvdG90eXBlLmluaXRpYWxpemUuY2FsbCh0aGlzLCB1bmRlZmluZWQsIG9wdGlvbnMpO1xuXG4gICAgICAgIHRoaXMuX3RpbGVqc29uID0ge307XG5cbiAgICAgICAgaWYgKG9wdGlvbnMgJiYgb3B0aW9ucy5mb3JtYXQpIHtcbiAgICAgICAgICAgIHV0aWwuc3RyaWN0X29uZW9mKG9wdGlvbnMuZm9ybWF0LCB0aGlzLmZvcm1hdHMpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5fbG9hZFRpbGVKU09OKF8pO1xuICAgIH0sXG5cbiAgICBzZXRGb3JtYXQ6IGZ1bmN0aW9uKF8pIHtcbiAgICAgICAgdXRpbC5zdHJpY3QoXywgJ3N0cmluZycpO1xuICAgICAgICB0aGlzLm9wdGlvbnMuZm9ybWF0ID0gXztcbiAgICAgICAgdGhpcy5yZWRyYXcoKTtcbiAgICAgICAgcmV0dXJuIHRoaXM7XG4gICAgfSxcblxuICAgIC8vIGRpc2FibGUgdGhlIHNldFVybCBmdW5jdGlvbiwgd2hpY2ggaXMgbm90IGF2YWlsYWJsZSBvbiBtYXBib3ggdGlsZWxheWVyc1xuICAgIHNldFVybDogbnVsbCxcblxuICAgIF9zZXRUaWxlSlNPTjogZnVuY3Rpb24oanNvbikge1xuICAgICAgICB1dGlsLnN0cmljdChqc29uLCAnb2JqZWN0Jyk7XG5cbiAgICAgICAgaWYgKCF0aGlzLm9wdGlvbnMuZm9ybWF0KSB7XG4gICAgICAgICAgdmFyIG1hdGNoID0ganNvbi50aWxlc1swXS5tYXRjaChmb3JtYXRQYXR0ZXJuKTtcbiAgICAgICAgICBpZiAobWF0Y2gpIHtcbiAgICAgICAgICAgICAgdGhpcy5vcHRpb25zLmZvcm1hdCA9IG1hdGNoWzFdO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIEwuZXh0ZW5kKHRoaXMub3B0aW9ucywge1xuICAgICAgICAgICAgdGlsZXM6IGpzb24udGlsZXMsXG4gICAgICAgICAgICBhdHRyaWJ1dGlvbjogdGhpcy5vcHRpb25zLnNhbml0aXplcihqc29uLmF0dHJpYnV0aW9uKSxcbiAgICAgICAgICAgIG1pblpvb206IGpzb24ubWluem9vbSB8fCAwLFxuICAgICAgICAgICAgbWF4Wm9vbToganNvbi5tYXh6b29tIHx8IDE4LFxuICAgICAgICAgICAgdG1zOiBqc29uLnNjaGVtZSA9PT0gJ3RtcycsXG4gICAgICAgICAgICBib3VuZHM6IGpzb24uYm91bmRzICYmIHV0aWwubGJvdW5kcyhqc29uLmJvdW5kcylcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5fdGlsZWpzb24gPSBqc29uO1xuICAgICAgICB0aGlzLnJlZHJhdygpO1xuICAgICAgICByZXR1cm4gdGhpcztcbiAgICB9LFxuXG4gICAgZ2V0VGlsZUpTT046IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gdGhpcy5fdGlsZWpzb247XG4gICAgfSxcblxuICAgIC8vIHRoaXMgaXMgYW4gZXhjZXB0aW9uIHRvIG1hcGJveC5qcyBuYW1pbmcgcnVsZXMgYmVjYXVzZSBpdCdzIGNhbGxlZFxuICAgIC8vIGJ5IGBMLm1hcGBcbiAgICBnZXRUaWxlVXJsOiBmdW5jdGlvbih0aWxlUG9pbnQpIHtcbiAgICAgICAgdmFyIHRpbGVzID0gdGhpcy5vcHRpb25zLnRpbGVzLFxuICAgICAgICAgICAgaW5kZXggPSBNYXRoLmZsb29yKE1hdGguYWJzKHRpbGVQb2ludC54ICsgdGlsZVBvaW50LnkpICUgdGlsZXMubGVuZ3RoKSxcbiAgICAgICAgICAgIHVybCA9IHRpbGVzW2luZGV4XTtcblxuICAgICAgICB2YXIgdGVtcGxhdGVkID0gTC5VdGlsLnRlbXBsYXRlKHVybCwgdGlsZVBvaW50KTtcbiAgICAgICAgaWYgKCF0ZW1wbGF0ZWQgfHwgIXRoaXMub3B0aW9ucy5mb3JtYXQpIHtcbiAgICAgICAgICAgIHJldHVybiB0ZW1wbGF0ZWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm4gdGVtcGxhdGVkLnJlcGxhY2UoZm9ybWF0UGF0dGVybixcbiAgICAgICAgICAgICAgICAoTC5Ccm93c2VyLnJldGluYSA/IHRoaXMuc2NhbGVQcmVmaXggOiAnLicpICsgdGhpcy5vcHRpb25zLmZvcm1hdCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLy8gVGlsZUpTT04uVGlsZUxheWVycyBhcmUgYWRkZWQgdG8gdGhlIG1hcCBpbW1lZGlhdGVseSwgc28gdGhhdCB0aGV5IGdldFxuICAgIC8vIHRoZSBkZXNpcmVkIHotaW5kZXgsIGJ1dCBkbyBub3QgdXBkYXRlIHVudGlsIHRoZSBUaWxlSlNPTiBoYXMgYmVlbiBsb2FkZWQuXG4gICAgX3VwZGF0ZTogZnVuY3Rpb24oKSB7XG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMudGlsZXMpIHtcbiAgICAgICAgICAgIEwuVGlsZUxheWVyLnByb3RvdHlwZS5fdXBkYXRlLmNhbGwodGhpcyk7XG4gICAgICAgIH1cbiAgICB9XG59KTtcblxubW9kdWxlLmV4cG9ydHMuVGlsZUxheWVyID0gVGlsZUxheWVyO1xuXG5tb2R1bGUuZXhwb3J0cy50aWxlTGF5ZXIgPSBmdW5jdGlvbihfLCBvcHRpb25zKSB7XG4gICAgcmV0dXJuIG5ldyBUaWxlTGF5ZXIoXywgb3B0aW9ucyk7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG5mdW5jdGlvbiBjb250YWlucyhpdGVtLCBsaXN0KSB7XG4gICAgaWYgKCFsaXN0IHx8ICFsaXN0Lmxlbmd0aCkgcmV0dXJuIGZhbHNlO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGlzdC5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAobGlzdFtpXSA9PT0gaXRlbSkgcmV0dXJuIHRydWU7XG4gICAgfVxuICAgIHJldHVybiBmYWxzZTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgaWRVcmw6IGZ1bmN0aW9uKF8sIHQpIHtcbiAgICAgICAgaWYgKF8uaW5kZXhPZignLycpID09PSAtMSkgdC5sb2FkSUQoXyk7XG4gICAgICAgIGVsc2UgdC5sb2FkVVJMKF8pO1xuICAgIH0sXG4gICAgbG9nOiBmdW5jdGlvbihfKSB7XG4gICAgICAgIGlmICh0eXBlb2YgY29uc29sZSA9PT0gJ29iamVjdCcgJiZcbiAgICAgICAgICAgIHR5cGVvZiBjb25zb2xlLmVycm9yID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKF8pO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBzdHJpY3Q6IGZ1bmN0aW9uKF8sIHR5cGUpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBfICE9PSB0eXBlKSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ0ludmFsaWQgYXJndW1lbnQ6ICcgKyB0eXBlICsgJyBleHBlY3RlZCcpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBzdHJpY3RfaW5zdGFuY2U6IGZ1bmN0aW9uKF8sIGtsYXNzLCBuYW1lKSB7XG4gICAgICAgIGlmICghKF8gaW5zdGFuY2VvZiBrbGFzcykpIHtcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcignSW52YWxpZCBhcmd1bWVudDogJyArIG5hbWUgKyAnIGV4cGVjdGVkJyk7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHN0cmljdF9vbmVvZjogZnVuY3Rpb24oXywgdmFsdWVzKSB7XG4gICAgICAgIGlmICghY29udGFpbnMoXywgdmFsdWVzKSkge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdJbnZhbGlkIGFyZ3VtZW50OiAnICsgXyArICcgZ2l2ZW4sIHZhbGlkIHZhbHVlcyBhcmUgJyArXG4gICAgICAgICAgICAgICAgdmFsdWVzLmpvaW4oJywgJykpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBzdHJpcF90YWdzOiBmdW5jdGlvbihfKSB7XG4gICAgICAgIHJldHVybiBfLnJlcGxhY2UoLzxbXjxdKz4vZywgJycpO1xuICAgIH0sXG4gICAgbGJvdW5kczogZnVuY3Rpb24oXykge1xuICAgICAgICAvLyBsZWFmbGV0LWNvbXBhdGlibGUgYm91bmRzLCBzaW5jZSBsZWFmbGV0IGRvZXMgbm90IGRvIGdlb2pzb25cbiAgICAgICAgcmV0dXJuIG5ldyBMLkxhdExuZ0JvdW5kcyhbW19bMV0sIF9bMF1dLCBbX1szXSwgX1syXV1dKTtcbiAgICB9XG59O1xuIl19