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

app.bundle.js 2.1MB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804580558065807580858095810581158125813581458155816581758185819582058215822582358245825582658275828582958305831583258335834583558365837583858395840584158425843584458455846584758485849585058515852585358545855585658575858585958605861586258635864586558665867586858695870587158725873587458755876587758785879588058815882588358845885588658875888588958905891589258935894589558965897589858995900590159025903590459055906590759085909591059115912591359145915591659175918591959205921592259235924592559265927592859295930593159325933593459355936593759385939594059415942594359445945594659475948594959505951595259535954595559565957595859595960596159625963596459655966596759685969597059715972597359745975597659775978597959805981598259835984598559865987598859895990599159925993599459955996599759985999600060016002600360046005600660076008600960106011601260136014601560166017601860196020602160226023602460256026602760286029603060316032603360346035603660376038603960406041604260436044604560466047604860496050605160526053605460556056605760586059606060616062606360646065606660676068606960706071607260736074607560766077607860796080608160826083608460856086608760886089609060916092609360946095609660976098609961006101610261036104610561066107610861096110611161126113611461156116611761186119612061216122612361246125612661276128612961306131613261336134613561366137613861396140614161426143614461456146614761486149615061516152615361546155615661576158615961606161616261636164616561666167616861696170617161726173617461756176617761786179618061816182618361846185618661876188618961906191619261936194619561966197619861996200620162026203620462056206620762086209621062116212621362146215621662176218621962206221622262236224622562266227622862296230623162326233623462356236623762386239624062416242624362446245624662476248624962506251625262536254625562566257625862596260626162626263626462656266626762686269627062716272627362746275627662776278627962806281628262836284628562866287628862896290629162926293629462956296629762986299630063016302630363046305630663076308630963106311631263136314631563166317631863196320632163226323632463256326632763286329633063316332633363346335633663376338633963406341634263436344634563466347634863496350635163526353635463556356635763586359636063616362636363646365636663676368636963706371637263736374637563766377637863796380638163826383638463856386638763886389639063916392639363946395639663976398639964006401640264036404640564066407640864096410641164126413641464156416641764186419642064216422642364246425642664276428642964306431643264336434643564366437643864396440644164426443644464456446644764486449645064516452645364546455645664576458645964606461646264636464646564666467646864696470647164726473647464756476647764786479648064816482648364846485648664876488648964906491649264936494649564966497649864996500650165026503650465056506650765086509651065116512651365146515651665176518651965206521652265236524652565266527652865296530653165326533653465356536653765386539654065416542654365446545654665476548654965506551655265536554655565566557655865596560656165626563656465656566656765686569657065716572657365746575657665776578657965806581658265836584658565866587658865896590659165926593659465956596659765986599660066016602660366046605660666076608660966106611661266136614661566166617661866196620662166226623662466256626662766286629663066316632663366346635663666376638663966406641664266436644664566466647664866496650665166526653665466556656665766586659666066616662666366646665666666676668666966706671667266736674667566766677667866796680668166826683668466856686668766886689669066916692669366946695669666976698669967006701670267036704670567066707670867096710671167126713671467156716671767186719672067216722672367246725672667276728672967306731673267336734673567366737673867396740674167426743674467456746674767486749675067516752675367546755675667576758675967606761676267636764676567666767676867696770677167726773677467756776677767786779678067816782678367846785678667876788678967906791679267936794679567966797679867996800680168026803680468056806680768086809681068116812681368146815681668176818681968206821682268236824682568266827682868296830683168326833683468356836683768386839684068416842684368446845684668476848684968506851685268536854685568566857685868596860686168626863686468656866686768686869687068716872687368746875687668776878687968806881688268836884688568866887688868896890689168926893689468956896689768986899690069016902690369046905690669076908690969106911691269136914691569166917691869196920692169226923692469256926692769286929693069316932693369346935693669376938693969406941694269436944694569466947694869496950695169526953695469556956695769586959696069616962696369646965696669676968696969706971697269736974697569766977697869796980698169826983698469856986698769886989699069916992699369946995699669976998699970007001700270037004700570067007700870097010701170127013701470157016701770187019702070217022702370247025702670277028702970307031703270337034703570367037703870397040704170427043704470457046704770487049705070517052705370547055705670577058705970607061706270637064706570667067706870697070707170727073707470757076707770787079708070817082708370847085708670877088708970907091709270937094709570967097709870997100710171027103710471057106710771087109711071117112711371147115711671177118711971207121712271237124712571267127712871297130713171327133713471357136713771387139714071417142714371447145714671477148714971507151715271537154715571567157715871597160716171627163716471657166716771687169717071717172717371747175717671777178717971807181718271837184718571867187718871897190719171927193719471957196719771987199720072017202720372047205720672077208720972107211721272137214721572167217721872197220722172227223722472257226722772287229723072317232723372347235723672377238723972407241724272437244724572467247724872497250725172527253725472557256725772587259726072617262726372647265726672677268726972707271727272737274727572767277727872797280728172827283728472857286728772887289729072917292729372947295729672977298729973007301730273037304730573067307730873097310731173127313731473157316731773187319732073217322732373247325732673277328732973307331733273337334733573367337733873397340734173427343734473457346734773487349735073517352735373547355735673577358735973607361736273637364736573667367736873697370737173727373737473757376737773787379738073817382738373847385738673877388738973907391739273937394739573967397739873997400740174027403740474057406740774087409741074117412741374147415741674177418741974207421742274237424742574267427742874297430743174327433743474357436743774387439744074417442744374447445744674477448744974507451745274537454745574567457745874597460746174627463746474657466746774687469747074717472747374747475747674777478747974807481748274837484748574867487748874897490749174927493749474957496749774987499750075017502750375047505750675077508750975107511751275137514751575167517751875197520752175227523752475257526752775287529753075317532753375347535753675377538753975407541754275437544754575467547754875497550755175527553755475557556755775587559756075617562756375647565756675677568756975707571757275737574757575767577757875797580758175827583758475857586758775887589759075917592759375947595759675977598759976007601760276037604760576067607760876097610761176127613761476157616761776187619762076217622762376247625762676277628762976307631763276337634763576367637763876397640764176427643764476457646764776487649765076517652765376547655765676577658765976607661766276637664766576667667766876697670767176727673767476757676767776787679768076817682768376847685768676877688768976907691769276937694769576967697769876997700770177027703770477057706770777087709771077117712771377147715771677177718771977207721772277237724772577267727772877297730773177327733773477357736773777387739774077417742774377447745774677477748774977507751775277537754775577567757775877597760776177627763776477657766776777687769777077717772777377747775777677777778777977807781778277837784778577867787778877897790779177927793779477957796779777987799780078017802780378047805780678077808780978107811781278137814781578167817781878197820782178227823782478257826782778287829783078317832783378347835783678377838783978407841784278437844784578467847784878497850785178527853785478557856785778587859786078617862786378647865786678677868786978707871787278737874787578767877787878797880788178827883788478857886788778887889789078917892789378947895789678977898789979007901790279037904790579067907790879097910791179127913791479157916791779187919792079217922792379247925792679277928792979307931793279337934793579367937793879397940794179427943794479457946794779487949795079517952795379547955795679577958795979607961796279637964796579667967796879697970797179727973797479757976797779787979798079817982798379847985798679877988798979907991799279937994799579967997799879998000800180028003800480058006800780088009801080118012801380148015801680178018801980208021802280238024802580268027802880298030803180328033803480358036803780388039804080418042804380448045804680478048804980508051805280538054805580568057805880598060806180628063806480658066806780688069807080718072807380748075807680778078807980808081808280838084808580868087808880898090809180928093809480958096809780988099810081018102810381048105810681078108810981108111811281138114811581168117811881198120812181228123812481258126812781288129813081318132813381348135813681378138813981408141814281438144814581468147814881498150815181528153815481558156815781588159816081618162816381648165816681678168816981708171817281738174817581768177817881798180818181828183818481858186818781888189819081918192819381948195819681978198819982008201820282038204820582068207820882098210821182128213821482158216821782188219822082218222822382248225822682278228822982308231823282338234823582368237823882398240824182428243824482458246824782488249825082518252825382548255825682578258825982608261826282638264826582668267826882698270827182728273827482758276827782788279828082818282828382848285828682878288828982908291829282938294829582968297829882998300830183028303830483058306830783088309831083118312831383148315831683178318831983208321832283238324832583268327832883298330833183328333833483358336833783388339834083418342834383448345834683478348834983508351835283538354835583568357835883598360836183628363836483658366836783688369837083718372837383748375837683778378837983808381838283838384838583868387838883898390839183928393839483958396839783988399840084018402840384048405840684078408840984108411841284138414841584168417841884198420842184228423842484258426842784288429843084318432843384348435843684378438843984408441844284438444844584468447844884498450845184528453845484558456845784588459846084618462846384648465846684678468846984708471847284738474847584768477847884798480848184828483848484858486848784888489849084918492849384948495849684978498849985008501850285038504850585068507850885098510851185128513851485158516851785188519852085218522852385248525852685278528852985308531853285338534853585368537853885398540854185428543854485458546854785488549855085518552855385548555855685578558855985608561856285638564856585668567856885698570857185728573857485758576857785788579858085818582858385848585858685878588858985908591859285938594859585968597859885998600860186028603860486058606860786088609861086118612861386148615861686178618861986208621862286238624862586268627862886298630863186328633863486358636863786388639864086418642864386448645864686478648864986508651865286538654865586568657865886598660866186628663866486658666866786688669867086718672867386748675867686778678867986808681868286838684868586868687868886898690869186928693869486958696869786988699870087018702870387048705870687078708870987108711871287138714871587168717871887198720872187228723872487258726872787288729873087318732873387348735873687378738873987408741874287438744874587468747874887498750875187528753875487558756875787588759876087618762876387648765876687678768876987708771877287738774877587768777877887798780878187828783878487858786878787888789879087918792879387948795879687978798879988008801880288038804880588068807880888098810881188128813881488158816881788188819882088218822882388248825882688278828882988308831883288338834883588368837883888398840884188428843884488458846884788488849885088518852885388548855885688578858885988608861886288638864886588668867886888698870887188728873887488758876887788788879888088818882888388848885888688878888888988908891889288938894889588968897889888998900890189028903890489058906890789088909891089118912891389148915891689178918891989208921892289238924892589268927892889298930893189328933893489358936893789388939894089418942894389448945894689478948894989508951895289538954895589568957895889598960896189628963896489658966896789688969897089718972897389748975897689778978897989808981898289838984898589868987898889898990899189928993899489958996899789988999900090019002900390049005900690079008900990109011901290139014901590169017901890199020902190229023902490259026902790289029903090319032903390349035903690379038903990409041904290439044904590469047904890499050905190529053905490559056905790589059906090619062906390649065906690679068906990709071907290739074907590769077907890799080908190829083908490859086908790889089909090919092909390949095909690979098909991009101910291039104910591069107910891099110911191129113911491159116911791189119912091219122912391249125912691279128912991309131913291339134913591369137913891399140914191429143914491459146914791489149915091519152915391549155915691579158915991609161916291639164916591669167916891699170917191729173917491759176917791789179918091819182918391849185918691879188918991909191919291939194919591969197919891999200920192029203920492059206920792089209921092119212921392149215921692179218921992209221922292239224922592269227922892299230923192329233923492359236923792389239924092419242924392449245924692479248924992509251925292539254925592569257925892599260926192629263926492659266926792689269927092719272927392749275927692779278927992809281928292839284928592869287928892899290929192929293929492959296929792989299930093019302930393049305930693079308930993109311931293139314931593169317931893199320932193229323932493259326932793289329933093319332933393349335933693379338933993409341934293439344934593469347934893499350935193529353935493559356935793589359936093619362936393649365936693679368936993709371937293739374937593769377937893799380938193829383938493859386938793889389939093919392939393949395939693979398939994009401940294039404940594069407940894099410941194129413941494159416941794189419942094219422942394249425942694279428942994309431943294339434943594369437943894399440944194429443944494459446944794489449945094519452945394549455945694579458945994609461946294639464946594669467946894699470947194729473947494759476947794789479948094819482948394849485948694879488948994909491949294939494949594969497949894999500950195029503950495059506950795089509951095119512951395149515951695179518951995209521952295239524952595269527952895299530953195329533953495359536953795389539954095419542954395449545954695479548954995509551955295539554955595569557955895599560956195629563956495659566956795689569957095719572957395749575957695779578957995809581958295839584958595869587958895899590959195929593959495959596959795989599960096019602960396049605960696079608960996109611961296139614961596169617961896199620962196229623962496259626962796289629963096319632963396349635963696379638963996409641964296439644964596469647964896499650965196529653965496559656965796589659966096619662966396649665966696679668966996709671967296739674967596769677967896799680968196829683968496859686968796889689969096919692969396949695969696979698969997009701970297039704970597069707970897099710971197129713971497159716971797189719972097219722972397249725972697279728972997309731973297339734973597369737973897399740974197429743974497459746974797489749975097519752975397549755975697579758975997609761976297639764976597669767976897699770977197729773977497759776977797789779978097819782978397849785978697879788978997909791979297939794979597969797979897999800980198029803980498059806980798089809981098119812981398149815981698179818981998209821982298239824982598269827982898299830983198329833983498359836983798389839984098419842984398449845984698479848984998509851985298539854985598569857985898599860986198629863986498659866986798689869987098719872987398749875987698779878987998809881988298839884988598869887988898899890989198929893989498959896989798989899990099019902990399049905990699079908990999109911991299139914991599169917991899199920992199229923992499259926992799289929993099319932993399349935993699379938993999409941994299439944994599469947994899499950995199529953995499559956995799589959996099619962996399649965996699679968996999709971997299739974997599769977997899799980998199829983998499859986998799889989999099919992999399949995999699979998999910000100011000210003100041000510006100071000810009100101001110012100131001410015100161001710018100191002010021100221002310024100251002610027100281002910030100311003210033100341003510036100371003810039100401004110042100431004410045100461004710048100491005010051100521005310054100551005610057100581005910060100611006210063100641006510066100671006810069100701007110072100731007410075100761007710078100791008010081100821008310084100851008610087100881008910090100911009210093100941009510096100971009810099101001010110102101031010410105101061010710108101091011010111101121011310114101151011610117101181011910120101211012210123101241012510126101271012810129101301013110132101331013410135101361013710138101391014010141101421014310144101451014610147101481014910150101511015210153101541015510156101571015810159101601016110162101631016410165101661016710168101691017010171101721017310174101751017610177101781017910180101811018210183101841018510186101871018810189101901019110192101931019410195101961019710198101991020010201102021020310204102051020610207102081020910210102111021210213102141021510216102171021810219102201022110222102231022410225102261022710228102291023010231102321023310234102351023610237102381023910240102411024210243102441024510246102471024810249102501025110252102531025410255102561025710258102591026010261102621026310264102651026610267102681026910270102711027210273102741027510276102771027810279102801028110282102831028410285102861028710288102891029010291102921029310294102951029610297102981029910300103011030210303103041030510306103071030810309103101031110312103131031410315103161031710318103191032010321103221032310324103251032610327103281032910330103311033210333103341033510336103371033810339103401034110342103431034410345103461034710348103491035010351103521035310354103551035610357103581035910360103611036210363103641036510366103671036810369103701037110372103731037410375103761037710378103791038010381103821038310384103851038610387103881038910390103911039210393103941039510396103971039810399104001040110402104031040410405104061040710408104091041010411104121041310414104151041610417104181041910420104211042210423104241042510426104271042810429104301043110432104331043410435104361043710438104391044010441104421044310444104451044610447104481044910450104511045210453104541045510456104571045810459104601046110462104631046410465104661046710468104691047010471104721047310474104751047610477104781047910480104811048210483104841048510486104871048810489104901049110492104931049410495104961049710498104991050010501105021050310504105051050610507105081050910510105111051210513105141051510516105171051810519105201052110522105231052410525105261052710528105291053010531105321053310534105351053610537105381053910540105411054210543105441054510546105471054810549105501055110552105531055410555105561055710558105591056010561105621056310564105651056610567105681056910570105711057210573105741057510576105771057810579105801058110582105831058410585105861058710588105891059010591105921059310594105951059610597105981059910600106011060210603106041060510606106071060810609106101061110612106131061410615106161061710618106191062010621106221062310624106251062610627106281062910630106311063210633106341063510636106371063810639106401064110642106431064410645106461064710648106491065010651106521065310654106551065610657106581065910660106611066210663106641066510666106671066810669106701067110672106731067410675106761067710678106791068010681106821068310684106851068610687106881068910690106911069210693106941069510696106971069810699107001070110702107031070410705107061070710708107091071010711107121071310714107151071610717107181071910720107211072210723107241072510726107271072810729107301073110732107331073410735107361073710738107391074010741107421074310744107451074610747107481074910750107511075210753107541075510756107571075810759107601076110762107631076410765107661076710768107691077010771107721077310774107751077610777107781077910780107811078210783107841078510786107871078810789107901079110792107931079410795107961079710798107991080010801108021080310804108051080610807108081080910810108111081210813108141081510816108171081810819108201082110822108231082410825108261082710828108291083010831108321083310834108351083610837108381083910840108411084210843108441084510846108471084810849108501085110852108531085410855108561085710858108591086010861108621086310864108651086610867108681086910870108711087210873108741087510876108771087810879108801088110882108831088410885108861088710888108891089010891108921089310894108951089610897108981089910900109011090210903109041090510906109071090810909109101091110912109131091410915109161091710918109191092010921109221092310924109251092610927109281092910930109311093210933109341093510936109371093810939109401094110942109431094410945109461094710948109491095010951109521095310954109551095610957109581095910960109611096210963109641096510966109671096810969109701097110972109731097410975109761097710978109791098010981109821098310984109851098610987109881098910990109911099210993109941099510996109971099810999110001100111002110031100411005110061100711008110091101011011110121101311014110151101611017110181101911020110211102211023110241102511026110271102811029110301103111032110331103411035110361103711038110391104011041110421104311044110451104611047110481104911050110511105211053110541105511056110571105811059110601106111062110631106411065110661106711068110691107011071110721107311074110751107611077110781107911080110811108211083110841108511086110871108811089110901109111092110931109411095110961109711098110991110011101111021110311104111051110611107111081110911110111111111211113111141111511116111171111811119111201112111122111231112411125111261112711128111291113011131111321113311134111351113611137111381113911140111411114211143111441114511146111471114811149111501115111152111531115411155111561115711158111591116011161111621116311164111651116611167111681116911170111711117211173111741117511176111771117811179111801118111182111831118411185111861118711188111891119011191111921119311194111951119611197111981119911200112011120211203112041120511206112071120811209112101121111212112131121411215112161121711218112191122011221112221122311224112251122611227112281122911230112311123211233112341123511236112371123811239112401124111242112431124411245112461124711248112491125011251112521125311254112551125611257112581125911260112611126211263112641126511266112671126811269112701127111272112731127411275112761127711278112791128011281112821128311284112851128611287112881128911290112911129211293112941129511296112971129811299113001130111302113031130411305113061130711308113091131011311113121131311314113151131611317113181131911320113211132211323113241132511326113271132811329113301133111332113331133411335113361133711338113391134011341113421134311344113451134611347113481134911350113511135211353113541135511356113571135811359113601136111362113631136411365113661136711368113691137011371113721137311374113751137611377113781137911380113811138211383113841138511386113871138811389113901139111392113931139411395113961139711398113991140011401114021140311404114051140611407114081140911410114111141211413114141141511416114171141811419114201142111422114231142411425114261142711428114291143011431114321143311434114351143611437114381143911440114411144211443114441144511446114471144811449114501145111452114531145411455114561145711458114591146011461114621146311464114651146611467114681146911470114711147211473114741147511476114771147811479114801148111482114831148411485114861148711488114891149011491114921149311494114951149611497114981149911500115011150211503115041150511506115071150811509115101151111512115131151411515115161151711518115191152011521115221152311524115251152611527115281152911530115311153211533115341153511536115371153811539115401154111542115431154411545115461154711548115491155011551115521155311554115551155611557115581155911560115611156211563115641156511566115671156811569115701157111572115731157411575115761157711578115791158011581115821158311584115851158611587115881158911590115911159211593115941159511596115971159811599116001160111602116031160411605116061160711608116091161011611116121161311614116151161611617116181161911620116211162211623116241162511626116271162811629116301163111632116331163411635116361163711638116391164011641116421164311644116451164611647116481164911650116511165211653116541165511656116571165811659116601166111662116631166411665116661166711668116691167011671116721167311674116751167611677116781167911680116811168211683116841168511686116871168811689116901169111692116931169411695116961169711698116991170011701117021170311704117051170611707117081170911710117111171211713117141171511716117171171811719117201172111722117231172411725117261172711728117291173011731117321173311734117351173611737117381173911740117411174211743117441174511746117471174811749117501175111752117531175411755117561175711758117591176011761117621176311764117651176611767117681176911770117711177211773117741177511776117771177811779117801178111782117831178411785117861178711788117891179011791117921179311794117951179611797117981179911800118011180211803118041180511806118071180811809118101181111812118131181411815118161181711818118191182011821118221182311824118251182611827118281182911830118311183211833118341183511836118371183811839118401184111842118431184411845118461184711848118491185011851118521185311854118551185611857118581185911860118611186211863118641186511866118671186811869118701187111872118731187411875118761187711878118791188011881118821188311884118851188611887118881188911890118911189211893118941189511896118971189811899119001190111902119031190411905119061190711908119091191011911119121191311914119151191611917119181191911920119211192211923119241192511926119271192811929119301193111932119331193411935119361193711938119391194011941119421194311944119451194611947119481194911950119511195211953119541195511956119571195811959119601196111962119631196411965119661196711968119691197011971119721197311974119751197611977119781197911980119811198211983119841198511986119871198811989119901199111992119931199411995119961199711998119991200012001120021200312004120051200612007120081200912010120111201212013120141201512016120171201812019120201202112022120231202412025120261202712028120291203012031120321203312034120351203612037120381203912040120411204212043120441204512046120471204812049120501205112052120531205412055120561205712058120591206012061120621206312064120651206612067120681206912070120711207212073120741207512076120771207812079120801208112082120831208412085120861208712088120891209012091120921209312094120951209612097120981209912100121011210212103121041210512106121071210812109121101211112112121131211412115121161211712118121191212012121121221212312124121251212612127121281212912130121311213212133121341213512136121371213812139121401214112142121431214412145121461214712148121491215012151121521215312154121551215612157121581215912160121611216212163121641216512166121671216812169121701217112172121731217412175121761217712178121791218012181121821218312184121851218612187121881218912190121911219212193121941219512196121971219812199122001220112202122031220412205122061220712208122091221012211122121221312214122151221612217122181221912220122211222212223122241222512226122271222812229122301223112232122331223412235122361223712238122391224012241122421224312244122451224612247122481224912250122511225212253122541225512256122571225812259122601226112262122631226412265122661226712268122691227012271122721227312274122751227612277122781227912280122811228212283122841228512286122871228812289122901229112292122931229412295122961229712298122991230012301123021230312304123051230612307123081230912310123111231212313123141231512316123171231812319123201232112322123231232412325123261232712328123291233012331123321233312334123351233612337123381233912340123411234212343123441234512346123471234812349123501235112352123531235412355123561235712358123591236012361123621236312364123651236612367123681236912370123711237212373123741237512376123771237812379123801238112382123831238412385123861238712388123891239012391123921239312394123951239612397123981239912400124011240212403124041240512406124071240812409124101241112412124131241412415124161241712418124191242012421124221242312424124251242612427124281242912430124311243212433124341243512436124371243812439124401244112442124431244412445124461244712448124491245012451124521245312454124551245612457124581245912460124611246212463124641246512466124671246812469124701247112472124731247412475124761247712478124791248012481124821248312484124851248612487124881248912490124911249212493124941249512496124971249812499125001250112502125031250412505125061250712508125091251012511125121251312514125151251612517125181251912520125211252212523125241252512526125271252812529125301253112532125331253412535125361253712538125391254012541125421254312544125451254612547125481254912550125511255212553125541255512556125571255812559125601256112562125631256412565125661256712568125691257012571125721257312574125751257612577125781257912580125811258212583125841258512586125871258812589125901259112592125931259412595125961259712598125991260012601126021260312604126051260612607126081260912610126111261212613126141261512616126171261812619126201262112622126231262412625126261262712628126291263012631126321263312634126351263612637126381263912640126411264212643126441264512646126471264812649126501265112652126531265412655126561265712658126591266012661126621266312664126651266612667126681266912670126711267212673126741267512676126771267812679126801268112682126831268412685126861268712688126891269012691126921269312694126951269612697126981269912700127011270212703127041270512706127071270812709127101271112712127131271412715127161271712718127191272012721127221272312724127251272612727127281272912730127311273212733127341273512736127371273812739127401274112742127431274412745127461274712748127491275012751127521275312754127551275612757127581275912760127611276212763127641276512766127671276812769127701277112772127731277412775127761277712778127791278012781127821278312784127851278612787127881278912790127911279212793127941279512796127971279812799128001280112802128031280412805128061280712808128091281012811128121281312814128151281612817128181281912820128211282212823128241282512826128271282812829128301283112832128331283412835128361283712838128391284012841128421284312844128451284612847128481284912850128511285212853128541285512856128571285812859128601286112862128631286412865128661286712868128691287012871128721287312874128751287612877128781287912880128811288212883128841288512886128871288812889128901289112892128931289412895128961289712898128991290012901129021290312904129051290612907129081290912910129111291212913129141291512916129171291812919129201292112922129231292412925129261292712928129291293012931129321293312934129351293612937129381293912940129411294212943129441294512946129471294812949129501295112952129531295412955129561295712958129591296012961129621296312964129651296612967129681296912970129711297212973129741297512976129771297812979129801298112982129831298412985129861298712988129891299012991129921299312994129951299612997129981299913000130011300213003130041300513006130071300813009130101301113012130131301413015130161301713018130191302013021130221302313024130251302613027130281302913030130311303213033130341303513036130371303813039130401304113042130431304413045130461304713048130491305013051130521305313054130551305613057130581305913060130611306213063130641306513066130671306813069130701307113072130731307413075130761307713078130791308013081130821308313084130851308613087130881308913090130911309213093130941309513096130971309813099131001310113102131031310413105131061310713108131091311013111131121311313114131151311613117131181311913120131211312213123131241312513126131271312813129131301313113132131331313413135131361313713138131391314013141131421314313144131451314613147131481314913150131511315213153131541315513156131571315813159131601316113162131631316413165131661316713168131691317013171131721317313174131751317613177131781317913180131811318213183131841318513186131871318813189131901319113192131931319413195131961319713198131991320013201132021320313204132051320613207132081320913210132111321213213132141321513216132171321813219132201322113222132231322413225132261322713228132291323013231132321323313234132351323613237132381323913240132411324213243132441324513246132471324813249132501325113252132531325413255132561325713258132591326013261132621326313264132651326613267132681326913270132711327213273132741327513276132771327813279132801328113282132831328413285132861328713288132891329013291132921329313294132951329613297132981329913300133011330213303133041330513306133071330813309133101331113312133131331413315133161331713318133191332013321133221332313324133251332613327133281332913330133311333213333133341333513336133371333813339133401334113342133431334413345133461334713348133491335013351133521335313354133551335613357133581335913360133611336213363133641336513366133671336813369133701337113372133731337413375133761337713378133791338013381133821338313384133851338613387133881338913390133911339213393133941339513396133971339813399134001340113402134031340413405134061340713408134091341013411134121341313414134151341613417134181341913420134211342213423134241342513426134271342813429134301343113432134331343413435134361343713438134391344013441134421344313444134451344613447134481344913450134511345213453134541345513456134571345813459134601346113462134631346413465134661346713468134691347013471134721347313474134751347613477134781347913480134811348213483134841348513486134871348813489134901349113492134931349413495134961349713498134991350013501135021350313504135051350613507135081350913510135111351213513135141351513516135171351813519135201352113522135231352413525135261352713528135291353013531135321353313534135351353613537135381353913540135411354213543135441354513546135471354813549135501355113552135531355413555135561355713558135591356013561135621356313564135651356613567135681356913570135711357213573135741357513576135771357813579135801358113582135831358413585135861358713588135891359013591135921359313594135951359613597135981359913600136011360213603136041360513606136071360813609136101361113612136131361413615136161361713618136191362013621136221362313624136251362613627136281362913630136311363213633136341363513636136371363813639136401364113642136431364413645136461364713648136491365013651136521365313654136551365613657136581365913660136611366213663136641366513666136671366813669136701367113672136731367413675136761367713678136791368013681136821368313684136851368613687136881368913690136911369213693136941369513696136971369813699137001370113702137031370413705137061370713708137091371013711137121371313714137151371613717137181371913720137211372213723137241372513726137271372813729137301373113732137331373413735137361373713738137391374013741137421374313744137451374613747137481374913750137511375213753137541375513756137571375813759137601376113762137631376413765137661376713768137691377013771137721377313774137751377613777137781377913780137811378213783137841378513786137871378813789137901379113792137931379413795137961379713798137991380013801138021380313804138051380613807138081380913810138111381213813138141381513816138171381813819138201382113822138231382413825138261382713828138291383013831138321383313834138351383613837138381383913840138411384213843138441384513846138471384813849138501385113852138531385413855138561385713858138591386013861138621386313864138651386613867138681386913870138711387213873138741387513876138771387813879138801388113882138831388413885138861388713888138891389013891138921389313894138951389613897138981389913900139011390213903139041390513906139071390813909139101391113912139131391413915139161391713918139191392013921139221392313924139251392613927139281392913930139311393213933139341393513936139371393813939139401394113942139431394413945139461394713948139491395013951139521395313954139551395613957139581395913960139611396213963139641396513966139671396813969139701397113972139731397413975139761397713978139791398013981139821398313984139851398613987139881398913990139911399213993139941399513996139971399813999140001400114002140031400414005140061400714008140091401014011140121401314014140151401614017140181401914020140211402214023140241402514026140271402814029140301403114032140331403414035140361403714038140391404014041140421404314044140451404614047140481404914050140511405214053140541405514056140571405814059140601406114062140631406414065140661406714068140691407014071140721407314074140751407614077140781407914080140811408214083140841408514086140871408814089140901409114092140931409414095140961409714098140991410014101141021410314104141051410614107141081410914110141111411214113141141411514116141171411814119141201412114122141231412414125141261412714128141291413014131141321413314134141351413614137141381413914140141411414214143141441414514146141471414814149141501415114152141531415414155141561415714158141591416014161141621416314164141651416614167141681416914170141711417214173141741417514176141771417814179141801418114182141831418414185141861418714188141891419014191141921419314194141951419614197141981419914200142011420214203142041420514206142071420814209142101421114212142131421414215142161421714218142191422014221142221422314224142251422614227142281422914230142311423214233142341423514236142371423814239142401424114242142431424414245142461424714248142491425014251142521425314254142551425614257142581425914260142611426214263142641426514266142671426814269142701427114272142731427414275142761427714278142791428014281142821428314284142851428614287142881428914290142911429214293142941429514296142971429814299143001430114302143031430414305143061430714308143091431014311143121431314314143151431614317143181431914320143211432214323143241432514326143271432814329143301433114332143331433414335143361433714338143391434014341143421434314344143451434614347143481434914350143511435214353143541435514356143571435814359143601436114362143631436414365143661436714368143691437014371143721437314374143751437614377143781437914380143811438214383143841438514386143871438814389143901439114392143931439414395143961439714398143991440014401144021440314404144051440614407144081440914410144111441214413144141441514416144171441814419144201442114422144231442414425144261442714428144291443014431144321443314434144351443614437144381443914440144411444214443144441444514446144471444814449144501445114452144531445414455144561445714458144591446014461144621446314464144651446614467144681446914470144711447214473144741447514476144771447814479144801448114482144831448414485144861448714488144891449014491144921449314494144951449614497144981449914500145011450214503145041450514506145071450814509145101451114512145131451414515145161451714518145191452014521145221452314524145251452614527145281452914530145311453214533145341453514536145371453814539145401454114542145431454414545145461454714548145491455014551145521455314554145551455614557145581455914560145611456214563145641456514566145671456814569145701457114572145731457414575145761457714578145791458014581145821458314584145851458614587145881458914590145911459214593145941459514596145971459814599146001460114602146031460414605146061460714608146091461014611146121461314614146151461614617146181461914620146211462214623146241462514626146271462814629146301463114632146331463414635146361463714638146391464014641146421464314644146451464614647146481464914650146511465214653146541465514656146571465814659146601466114662146631466414665146661466714668146691467014671146721467314674146751467614677146781467914680146811468214683146841468514686146871468814689146901469114692146931469414695146961469714698146991470014701147021470314704147051470614707147081470914710147111471214713147141471514716147171471814719147201472114722147231472414725147261472714728147291473014731147321473314734147351473614737147381473914740147411474214743147441474514746147471474814749147501475114752147531475414755147561475714758147591476014761147621476314764147651476614767147681476914770147711477214773147741477514776147771477814779147801478114782147831478414785147861478714788147891479014791147921479314794147951479614797147981479914800148011480214803148041480514806148071480814809148101481114812148131481414815148161481714818148191482014821148221482314824148251482614827148281482914830148311483214833148341483514836148371483814839148401484114842148431484414845148461484714848148491485014851148521485314854148551485614857148581485914860148611486214863148641486514866148671486814869148701487114872148731487414875148761487714878148791488014881148821488314884148851488614887148881488914890148911489214893148941489514896148971489814899149001490114902149031490414905149061490714908149091491014911149121491314914149151491614917149181491914920149211492214923149241492514926149271492814929149301493114932149331493414935149361493714938149391494014941149421494314944149451494614947149481494914950149511495214953149541495514956149571495814959149601496114962149631496414965149661496714968149691497014971149721497314974149751497614977149781497914980149811498214983149841498514986149871498814989149901499114992149931499414995149961499714998149991500015001150021500315004150051500615007150081500915010150111501215013150141501515016150171501815019150201502115022150231502415025150261502715028150291503015031150321503315034150351503615037150381503915040150411504215043150441504515046150471504815049150501505115052150531505415055150561505715058150591506015061150621506315064150651506615067150681506915070150711507215073150741507515076150771507815079150801508115082150831508415085150861508715088150891509015091150921509315094150951509615097150981509915100151011510215103151041510515106151071510815109151101511115112151131511415115151161511715118151191512015121151221512315124151251512615127151281512915130151311513215133151341513515136151371513815139151401514115142151431514415145151461514715148151491515015151151521515315154151551515615157151581515915160151611516215163151641516515166151671516815169151701517115172151731517415175151761517715178151791518015181151821518315184151851518615187151881518915190151911519215193151941519515196151971519815199152001520115202152031520415205152061520715208152091521015211152121521315214152151521615217152181521915220152211522215223152241522515226152271522815229152301523115232152331523415235152361523715238152391524015241152421524315244152451524615247152481524915250152511525215253152541525515256152571525815259152601526115262152631526415265152661526715268152691527015271152721527315274152751527615277152781527915280152811528215283152841528515286152871528815289152901529115292152931529415295152961529715298152991530015301153021530315304153051530615307153081530915310153111531215313153141531515316153171531815319153201532115322153231532415325153261532715328153291533015331153321533315334153351533615337153381533915340153411534215343153441534515346153471534815349153501535115352153531535415355153561535715358153591536015361153621536315364153651536615367153681536915370153711537215373153741537515376153771537815379153801538115382153831538415385153861538715388153891539015391153921539315394153951539615397153981539915400154011540215403154041540515406154071540815409154101541115412154131541415415154161541715418154191542015421154221542315424154251542615427154281542915430154311543215433154341543515436154371543815439154401544115442154431544415445154461544715448154491545015451154521545315454154551545615457154581545915460154611546215463154641546515466154671546815469154701547115472154731547415475154761547715478154791548015481154821548315484154851548615487154881548915490154911549215493154941549515496154971549815499155001550115502155031550415505155061550715508155091551015511155121551315514155151551615517155181551915520155211552215523155241552515526155271552815529155301553115532155331553415535155361553715538155391554015541155421554315544155451554615547155481554915550155511555215553155541555515556155571555815559155601556115562155631556415565155661556715568155691557015571155721557315574155751557615577155781557915580155811558215583155841558515586155871558815589155901559115592155931559415595155961559715598155991560015601156021560315604156051560615607156081560915610156111561215613156141561515616156171561815619156201562115622156231562415625156261562715628156291563015631156321563315634156351563615637156381563915640156411564215643156441564515646156471564815649156501565115652156531565415655156561565715658156591566015661156621566315664156651566615667156681566915670156711567215673156741567515676156771567815679156801568115682156831568415685156861568715688156891569015691156921569315694156951569615697156981569915700157011570215703157041570515706157071570815709157101571115712157131571415715157161571715718157191572015721157221572315724157251572615727157281572915730157311573215733157341573515736157371573815739157401574115742157431574415745157461574715748157491575015751157521575315754157551575615757157581575915760157611576215763157641576515766157671576815769157701577115772157731577415775157761577715778157791578015781157821578315784157851578615787157881578915790157911579215793157941579515796157971579815799158001580115802158031580415805158061580715808158091581015811158121581315814158151581615817158181581915820158211582215823158241582515826158271582815829158301583115832158331583415835158361583715838158391584015841158421584315844158451584615847158481584915850158511585215853158541585515856158571585815859158601586115862158631586415865158661586715868158691587015871158721587315874158751587615877158781587915880158811588215883158841588515886158871588815889158901589115892158931589415895158961589715898158991590015901159021590315904159051590615907159081590915910159111591215913159141591515916159171591815919159201592115922159231592415925159261592715928159291593015931159321593315934159351593615937159381593915940159411594215943159441594515946159471594815949159501595115952159531595415955159561595715958159591596015961159621596315964159651596615967159681596915970159711597215973159741597515976159771597815979159801598115982159831598415985159861598715988159891599015991159921599315994159951599615997159981599916000160011600216003160041600516006160071600816009160101601116012160131601416015160161601716018160191602016021160221602316024160251602616027160281602916030160311603216033160341603516036160371603816039160401604116042160431604416045160461604716048160491605016051160521605316054160551605616057160581605916060160611606216063160641606516066160671606816069160701607116072160731607416075160761607716078160791608016081160821608316084160851608616087160881608916090160911609216093160941609516096160971609816099161001610116102161031610416105161061610716108161091611016111161121611316114161151611616117161181611916120161211612216123161241612516126161271612816129161301613116132161331613416135161361613716138161391614016141161421614316144161451614616147161481614916150161511615216153161541615516156161571615816159161601616116162161631616416165161661616716168161691617016171161721617316174161751617616177161781617916180161811618216183161841618516186161871618816189161901619116192161931619416195161961619716198161991620016201162021620316204162051620616207162081620916210162111621216213162141621516216162171621816219162201622116222162231622416225162261622716228162291623016231162321623316234162351623616237162381623916240162411624216243162441624516246162471624816249162501625116252162531625416255162561625716258162591626016261162621626316264162651626616267162681626916270162711627216273162741627516276162771627816279162801628116282162831628416285162861628716288162891629016291162921629316294162951629616297162981629916300163011630216303163041630516306163071630816309163101631116312163131631416315163161631716318163191632016321163221632316324163251632616327163281632916330163311633216333163341633516336163371633816339163401634116342163431634416345163461634716348163491635016351163521635316354163551635616357163581635916360163611636216363163641636516366163671636816369163701637116372163731637416375163761637716378163791638016381163821638316384163851638616387163881638916390163911639216393163941639516396163971639816399164001640116402164031640416405164061640716408164091641016411164121641316414164151641616417164181641916420164211642216423164241642516426164271642816429164301643116432164331643416435164361643716438164391644016441164421644316444164451644616447164481644916450164511645216453164541645516456164571645816459164601646116462164631646416465164661646716468164691647016471164721647316474164751647616477164781647916480164811648216483164841648516486164871648816489164901649116492164931649416495164961649716498164991650016501165021650316504165051650616507165081650916510165111651216513165141651516516165171651816519165201652116522165231652416525165261652716528165291653016531165321653316534165351653616537165381653916540165411654216543165441654516546165471654816549165501655116552165531655416555165561655716558165591656016561165621656316564165651656616567165681656916570165711657216573165741657516576165771657816579165801658116582165831658416585165861658716588165891659016591165921659316594165951659616597165981659916600166011660216603166041660516606166071660816609166101661116612166131661416615166161661716618166191662016621166221662316624166251662616627166281662916630166311663216633166341663516636166371663816639166401664116642166431664416645166461664716648166491665016651166521665316654166551665616657166581665916660166611666216663166641666516666166671666816669166701667116672166731667416675166761667716678166791668016681166821668316684166851668616687166881668916690166911669216693166941669516696166971669816699167001670116702167031670416705167061670716708167091671016711167121671316714167151671616717167181671916720167211672216723167241672516726167271672816729167301673116732167331673416735167361673716738167391674016741167421674316744167451674616747167481674916750167511675216753167541675516756167571675816759167601676116762167631676416765167661676716768167691677016771167721677316774167751677616777167781677916780167811678216783167841678516786167871678816789167901679116792167931679416795167961679716798167991680016801168021680316804168051680616807168081680916810168111681216813168141681516816168171681816819168201682116822168231682416825168261682716828168291683016831168321683316834168351683616837168381683916840168411684216843168441684516846168471684816849168501685116852168531685416855168561685716858168591686016861168621686316864168651686616867168681686916870168711687216873168741687516876168771687816879168801688116882168831688416885168861688716888168891689016891168921689316894168951689616897168981689916900169011690216903169041690516906169071690816909169101691116912169131691416915169161691716918169191692016921169221692316924169251692616927169281692916930169311693216933169341693516936169371693816939169401694116942169431694416945169461694716948169491695016951169521695316954169551695616957169581695916960169611696216963169641696516966169671696816969169701697116972169731697416975169761697716978169791698016981169821698316984169851698616987169881698916990169911699216993169941699516996169971699816999170001700117002170031700417005170061700717008170091701017011170121701317014170151701617017170181701917020170211702217023170241702517026170271702817029170301703117032170331703417035170361703717038170391704017041170421704317044170451704617047170481704917050170511705217053170541705517056170571705817059170601706117062170631706417065170661706717068170691707017071170721707317074170751707617077170781707917080170811708217083170841708517086170871708817089170901709117092170931709417095170961709717098170991710017101171021710317104171051710617107171081710917110171111711217113171141711517116171171711817119171201712117122171231712417125171261712717128171291713017131171321713317134171351713617137171381713917140171411714217143171441714517146171471714817149171501715117152171531715417155171561715717158171591716017161171621716317164171651716617167171681716917170171711717217173171741717517176171771717817179171801718117182171831718417185171861718717188171891719017191171921719317194171951719617197171981719917200172011720217203172041720517206172071720817209172101721117212172131721417215172161721717218172191722017221172221722317224172251722617227172281722917230172311723217233172341723517236172371723817239172401724117242172431724417245172461724717248172491725017251172521725317254172551725617257172581725917260172611726217263172641726517266172671726817269172701727117272172731727417275172761727717278172791728017281172821728317284172851728617287172881728917290172911729217293172941729517296172971729817299173001730117302173031730417305173061730717308173091731017311173121731317314173151731617317173181731917320173211732217323173241732517326173271732817329173301733117332173331733417335173361733717338173391734017341173421734317344173451734617347173481734917350173511735217353173541735517356173571735817359173601736117362173631736417365173661736717368173691737017371173721737317374173751737617377173781737917380173811738217383173841738517386173871738817389173901739117392173931739417395173961739717398173991740017401174021740317404174051740617407174081740917410174111741217413174141741517416174171741817419174201742117422174231742417425174261742717428174291743017431174321743317434174351743617437174381743917440174411744217443174441744517446174471744817449174501745117452174531745417455174561745717458174591746017461174621746317464174651746617467174681746917470174711747217473174741747517476174771747817479174801748117482174831748417485174861748717488174891749017491174921749317494174951749617497174981749917500175011750217503175041750517506175071750817509175101751117512175131751417515175161751717518175191752017521175221752317524175251752617527175281752917530175311753217533175341753517536175371753817539175401754117542175431754417545175461754717548175491755017551175521755317554175551755617557175581755917560175611756217563175641756517566175671756817569175701757117572175731757417575175761757717578175791758017581175821758317584175851758617587175881758917590175911759217593175941759517596175971759817599176001760117602176031760417605176061760717608176091761017611176121761317614176151761617617176181761917620176211762217623176241762517626176271762817629176301763117632176331763417635176361763717638176391764017641176421764317644176451764617647176481764917650176511765217653176541765517656176571765817659176601766117662176631766417665176661766717668176691767017671176721767317674176751767617677176781767917680176811768217683176841768517686176871768817689176901769117692176931769417695176961769717698176991770017701177021770317704177051770617707177081770917710177111771217713177141771517716177171771817719177201772117722177231772417725177261772717728177291773017731177321773317734177351773617737177381773917740177411774217743177441774517746177471774817749177501775117752177531775417755177561775717758177591776017761177621776317764177651776617767177681776917770177711777217773177741777517776177771777817779177801778117782177831778417785177861778717788177891779017791177921779317794177951779617797177981779917800178011780217803178041780517806178071780817809178101781117812178131781417815178161781717818178191782017821178221782317824178251782617827178281782917830178311783217833178341783517836178371783817839178401784117842178431784417845178461784717848178491785017851178521785317854178551785617857178581785917860178611786217863178641786517866178671786817869178701787117872178731787417875178761787717878178791788017881178821788317884178851788617887178881788917890178911789217893178941789517896178971789817899179001790117902179031790417905179061790717908179091791017911179121791317914179151791617917179181791917920179211792217923179241792517926179271792817929179301793117932179331793417935179361793717938179391794017941179421794317944179451794617947179481794917950179511795217953179541795517956179571795817959179601796117962179631796417965179661796717968179691797017971179721797317974179751797617977179781797917980179811798217983179841798517986179871798817989179901799117992179931799417995179961799717998179991800018001180021800318004180051800618007180081800918010180111801218013180141801518016180171801818019180201802118022180231802418025180261802718028180291803018031180321803318034180351803618037180381803918040180411804218043180441804518046180471804818049180501805118052180531805418055180561805718058180591806018061180621806318064180651806618067180681806918070180711807218073180741807518076180771807818079180801808118082180831808418085180861808718088180891809018091180921809318094180951809618097180981809918100181011810218103181041810518106181071810818109181101811118112181131811418115181161811718118181191812018121181221812318124181251812618127181281812918130181311813218133181341813518136181371813818139181401814118142181431814418145181461814718148181491815018151181521815318154181551815618157181581815918160181611816218163181641816518166181671816818169181701817118172181731817418175181761817718178181791818018181181821818318184181851818618187181881818918190181911819218193181941819518196181971819818199182001820118202182031820418205182061820718208182091821018211182121821318214182151821618217182181821918220182211822218223182241822518226182271822818229182301823118232182331823418235182361823718238182391824018241182421824318244182451824618247182481824918250182511825218253182541825518256182571825818259182601826118262182631826418265182661826718268182691827018271182721827318274182751827618277182781827918280182811828218283182841828518286182871828818289182901829118292182931829418295182961829718298182991830018301183021830318304183051830618307183081830918310183111831218313183141831518316183171831818319183201832118322183231832418325183261832718328183291833018331183321833318334183351833618337183381833918340183411834218343183441834518346183471834818349183501835118352183531835418355183561835718358183591836018361183621836318364183651836618367183681836918370183711837218373183741837518376183771837818379183801838118382183831838418385183861838718388183891839018391183921839318394183951839618397183981839918400184011840218403184041840518406184071840818409184101841118412184131841418415184161841718418184191842018421184221842318424184251842618427184281842918430184311843218433184341843518436184371843818439184401844118442184431844418445184461844718448184491845018451184521845318454184551845618457184581845918460184611846218463184641846518466184671846818469184701847118472184731847418475184761847718478184791848018481184821848318484184851848618487184881848918490184911849218493184941849518496184971849818499185001850118502185031850418505185061850718508185091851018511185121851318514185151851618517185181851918520185211852218523185241852518526185271852818529185301853118532185331853418535185361853718538185391854018541185421854318544185451854618547185481854918550185511855218553185541855518556185571855818559185601856118562185631856418565185661856718568185691857018571185721857318574185751857618577185781857918580185811858218583185841858518586185871858818589185901859118592185931859418595185961859718598185991860018601186021860318604186051860618607186081860918610186111861218613186141861518616186171861818619186201862118622186231862418625186261862718628186291863018631186321863318634186351863618637186381863918640186411864218643186441864518646186471864818649186501865118652186531865418655186561865718658186591866018661186621866318664186651866618667186681866918670186711867218673186741867518676186771867818679186801868118682186831868418685186861868718688186891869018691186921869318694186951869618697186981869918700187011870218703187041870518706187071870818709187101871118712187131871418715187161871718718187191872018721187221872318724187251872618727187281872918730187311873218733187341873518736187371873818739187401874118742187431874418745187461874718748187491875018751187521875318754187551875618757187581875918760187611876218763187641876518766187671876818769187701877118772187731877418775187761877718778187791878018781187821878318784187851878618787187881878918790187911879218793187941879518796187971879818799188001880118802188031880418805188061880718808188091881018811188121881318814188151881618817188181881918820188211882218823188241882518826188271882818829188301883118832188331883418835188361883718838188391884018841188421884318844188451884618847188481884918850188511885218853188541885518856188571885818859188601886118862188631886418865188661886718868188691887018871188721887318874188751887618877188781887918880188811888218883188841888518886188871888818889188901889118892188931889418895188961889718898188991890018901189021890318904189051890618907189081890918910189111891218913189141891518916189171891818919189201892118922189231892418925189261892718928189291893018931189321893318934189351893618937189381893918940189411894218943189441894518946189471894818949189501895118952189531895418955189561895718958189591896018961189621896318964189651896618967189681896918970189711897218973189741897518976189771897818979189801898118982189831898418985189861898718988189891899018991189921899318994189951899618997189981899919000190011900219003190041900519006190071900819009190101901119012190131901419015190161901719018190191902019021190221902319024190251902619027190281902919030190311903219033190341903519036190371903819039190401904119042190431904419045190461904719048190491905019051190521905319054190551905619057190581905919060190611906219063190641906519066190671906819069190701907119072190731907419075190761907719078190791908019081190821908319084190851908619087190881908919090190911909219093190941909519096190971909819099191001910119102191031910419105191061910719108191091911019111191121911319114191151911619117191181911919120191211912219123191241912519126191271912819129191301913119132191331913419135191361913719138191391914019141191421914319144191451914619147191481914919150191511915219153191541915519156191571915819159191601916119162191631916419165191661916719168191691917019171191721917319174191751917619177191781917919180191811918219183191841918519186191871918819189191901919119192191931919419195191961919719198191991920019201192021920319204192051920619207192081920919210192111921219213192141921519216192171921819219192201922119222192231922419225192261922719228192291923019231192321923319234192351923619237192381923919240192411924219243192441924519246192471924819249192501925119252192531925419255192561925719258192591926019261192621926319264192651926619267192681926919270192711927219273192741927519276192771927819279192801928119282192831928419285192861928719288192891929019291192921929319294192951929619297192981929919300193011930219303193041930519306193071930819309193101931119312193131931419315193161931719318193191932019321193221932319324193251932619327193281932919330193311933219333193341933519336193371933819339193401934119342193431934419345193461934719348193491935019351193521935319354193551935619357193581935919360193611936219363193641936519366193671936819369193701937119372193731937419375193761937719378193791938019381193821938319384193851938619387193881938919390193911939219393193941939519396193971939819399194001940119402194031940419405194061940719408194091941019411194121941319414194151941619417194181941919420194211942219423194241942519426194271942819429194301943119432194331943419435194361943719438194391944019441194421944319444194451944619447194481944919450194511945219453194541945519456194571945819459194601946119462194631946419465194661946719468194691947019471194721947319474194751947619477194781947919480194811948219483194841948519486194871948819489194901949119492194931949419495194961949719498194991950019501195021950319504195051950619507195081950919510195111951219513195141951519516195171951819519195201952119522195231952419525195261952719528195291953019531195321953319534195351953619537195381953919540195411954219543195441954519546195471954819549195501955119552195531955419555195561955719558195591956019561195621956319564195651956619567195681956919570195711957219573195741957519576195771957819579195801958119582195831958419585195861958719588195891959019591195921959319594195951959619597195981959919600196011960219603196041960519606196071960819609196101961119612196131961419615196161961719618196191962019621196221962319624196251962619627196281962919630196311963219633196341963519636196371963819639196401964119642196431964419645196461964719648196491965019651196521965319654196551965619657196581965919660196611966219663196641966519666196671966819669196701967119672196731967419675196761967719678196791968019681196821968319684196851968619687196881968919690196911969219693196941969519696196971969819699197001970119702197031970419705197061970719708197091971019711197121971319714197151971619717197181971919720197211972219723197241972519726197271972819729197301973119732197331973419735197361973719738197391974019741197421974319744197451974619747197481974919750197511975219753197541975519756197571975819759197601976119762197631976419765197661976719768197691977019771197721977319774197751977619777197781977919780197811978219783197841978519786197871978819789197901979119792197931979419795197961979719798197991980019801198021980319804198051980619807198081980919810198111981219813198141981519816198171981819819198201982119822198231982419825198261982719828198291983019831198321983319834198351983619837198381983919840198411984219843198441984519846198471984819849198501985119852198531985419855198561985719858198591986019861198621986319864198651986619867198681986919870198711987219873198741987519876198771987819879198801988119882198831988419885198861988719888198891989019891198921989319894198951989619897198981989919900199011990219903199041990519906199071990819909199101991119912199131991419915199161991719918199191992019921199221992319924199251992619927199281992919930199311993219933199341993519936199371993819939199401994119942199431994419945199461994719948199491995019951199521995319954199551995619957199581995919960199611996219963199641996519966199671996819969199701997119972199731997419975199761997719978199791998019981199821998319984199851998619987199881998919990199911999219993199941999519996199971999819999200002000120002200032000420005200062000720008200092001020011200122001320014200152001620017200182001920020200212002220023200242002520026200272002820029200302003120032200332003420035200362003720038200392004020041200422004320044200452004620047200482004920050200512005220053200542005520056200572005820059200602006120062200632006420065200662006720068200692007020071200722007320074200752007620077200782007920080200812008220083200842008520086200872008820089200902009120092200932009420095200962009720098200992010020101201022010320104201052010620107201082010920110201112011220113201142011520116201172011820119201202012120122201232012420125201262012720128201292013020131201322013320134201352013620137201382013920140201412014220143201442014520146201472014820149201502015120152201532015420155201562015720158201592016020161201622016320164201652016620167201682016920170201712017220173201742017520176201772017820179201802018120182201832018420185201862018720188201892019020191201922019320194201952019620197201982019920200202012020220203202042020520206202072020820209202102021120212202132021420215202162021720218202192022020221202222022320224202252022620227202282022920230202312023220233202342023520236202372023820239202402024120242202432024420245202462024720248202492025020251202522025320254202552025620257202582025920260202612026220263202642026520266202672026820269202702027120272202732027420275202762027720278202792028020281202822028320284202852028620287202882028920290202912029220293202942029520296202972029820299203002030120302203032030420305203062030720308203092031020311203122031320314203152031620317203182031920320203212032220323203242032520326203272032820329203302033120332203332033420335203362033720338203392034020341203422034320344203452034620347203482034920350203512035220353203542035520356203572035820359203602036120362203632036420365203662036720368203692037020371203722037320374203752037620377203782037920380203812038220383203842038520386203872038820389203902039120392203932039420395203962039720398203992040020401204022040320404204052040620407204082040920410204112041220413204142041520416204172041820419204202042120422204232042420425204262042720428204292043020431204322043320434204352043620437204382043920440204412044220443204442044520446204472044820449204502045120452204532045420455204562045720458204592046020461204622046320464204652046620467204682046920470204712047220473204742047520476204772047820479204802048120482204832048420485204862048720488204892049020491204922049320494204952049620497204982049920500205012050220503205042050520506205072050820509205102051120512205132051420515205162051720518205192052020521205222052320524205252052620527205282052920530205312053220533205342053520536205372053820539205402054120542205432054420545205462054720548205492055020551205522055320554205552055620557205582055920560205612056220563205642056520566205672056820569205702057120572205732057420575205762057720578205792058020581205822058320584205852058620587205882058920590205912059220593205942059520596205972059820599206002060120602206032060420605206062060720608206092061020611206122061320614206152061620617206182061920620206212062220623206242062520626206272062820629206302063120632206332063420635206362063720638206392064020641206422064320644206452064620647206482064920650206512065220653206542065520656206572065820659206602066120662206632066420665206662066720668206692067020671206722067320674206752067620677206782067920680206812068220683206842068520686206872068820689206902069120692206932069420695206962069720698206992070020701207022070320704207052070620707207082070920710207112071220713207142071520716207172071820719207202072120722207232072420725207262072720728207292073020731207322073320734207352073620737207382073920740207412074220743207442074520746207472074820749207502075120752207532075420755207562075720758207592076020761207622076320764207652076620767207682076920770207712077220773207742077520776207772077820779207802078120782207832078420785207862078720788207892079020791207922079320794207952079620797207982079920800208012080220803208042080520806208072080820809208102081120812208132081420815208162081720818208192082020821208222082320824208252082620827208282082920830208312083220833208342083520836208372083820839208402084120842208432084420845208462084720848208492085020851208522085320854208552085620857208582085920860208612086220863208642086520866208672086820869208702087120872208732087420875208762087720878208792088020881208822088320884208852088620887208882088920890208912089220893208942089520896208972089820899209002090120902209032090420905209062090720908209092091020911209122091320914209152091620917209182091920920209212092220923209242092520926209272092820929209302093120932209332093420935209362093720938209392094020941209422094320944209452094620947209482094920950209512095220953209542095520956209572095820959209602096120962209632096420965209662096720968209692097020971209722097320974209752097620977209782097920980209812098220983209842098520986209872098820989209902099120992209932099420995209962099720998209992100021001210022100321004210052100621007210082100921010210112101221013210142101521016210172101821019210202102121022210232102421025210262102721028210292103021031210322103321034210352103621037210382103921040210412104221043210442104521046210472104821049210502105121052210532105421055210562105721058210592106021061210622106321064210652106621067210682106921070210712107221073210742107521076210772107821079210802108121082210832108421085210862108721088210892109021091210922109321094210952109621097210982109921100211012110221103211042110521106211072110821109211102111121112211132111421115211162111721118211192112021121211222112321124211252112621127211282112921130211312113221133211342113521136211372113821139211402114121142211432114421145211462114721148211492115021151211522115321154211552115621157211582115921160211612116221163211642116521166211672116821169211702117121172211732117421175211762117721178211792118021181211822118321184211852118621187211882118921190211912119221193211942119521196211972119821199212002120121202212032120421205212062120721208212092121021211212122121321214212152121621217212182121921220212212122221223212242122521226212272122821229212302123121232212332123421235212362123721238212392124021241212422124321244212452124621247212482124921250212512125221253212542125521256212572125821259212602126121262212632126421265212662126721268212692127021271212722127321274212752127621277212782127921280212812128221283212842128521286212872128821289212902129121292212932129421295212962129721298212992130021301213022130321304213052130621307213082130921310213112131221313213142131521316213172131821319213202132121322213232132421325213262132721328213292133021331213322133321334213352133621337213382133921340213412134221343213442134521346213472134821349213502135121352213532135421355213562135721358213592136021361213622136321364213652136621367213682136921370213712137221373213742137521376213772137821379213802138121382213832138421385213862138721388213892139021391213922139321394213952139621397213982139921400214012140221403214042140521406214072140821409214102141121412214132141421415214162141721418214192142021421214222142321424214252142621427214282142921430214312143221433214342143521436214372143821439214402144121442214432144421445214462144721448214492145021451214522145321454214552145621457214582145921460214612146221463214642146521466214672146821469214702147121472214732147421475214762147721478214792148021481214822148321484214852148621487214882148921490214912149221493214942149521496214972149821499215002150121502215032150421505215062150721508215092151021511215122151321514215152151621517215182151921520215212152221523215242152521526215272152821529215302153121532215332153421535215362153721538215392154021541215422154321544215452154621547215482154921550215512155221553215542155521556215572155821559215602156121562215632156421565215662156721568215692157021571215722157321574215752157621577215782157921580215812158221583215842158521586215872158821589215902159121592215932159421595215962159721598215992160021601216022160321604216052160621607216082160921610216112161221613216142161521616216172161821619216202162121622216232162421625216262162721628216292163021631216322163321634216352163621637216382163921640216412164221643216442164521646216472164821649216502165121652216532165421655216562165721658216592166021661216622166321664216652166621667216682166921670216712167221673216742167521676216772167821679216802168121682216832168421685216862168721688216892169021691216922169321694216952169621697216982169921700217012170221703217042170521706217072170821709217102171121712217132171421715217162171721718217192172021721217222172321724217252172621727217282172921730217312173221733217342173521736217372173821739217402174121742217432174421745217462174721748217492175021751217522175321754217552175621757217582175921760217612176221763217642176521766217672176821769217702177121772217732177421775217762177721778217792178021781217822178321784217852178621787217882178921790217912179221793217942179521796217972179821799218002180121802218032180421805218062180721808218092181021811218122181321814218152181621817218182181921820218212182221823218242182521826218272182821829218302183121832218332183421835218362183721838218392184021841218422184321844218452184621847218482184921850218512185221853218542185521856218572185821859218602186121862218632186421865218662186721868218692187021871218722187321874218752187621877218782187921880218812188221883218842188521886218872188821889218902189121892218932189421895218962189721898218992190021901219022190321904219052190621907219082190921910219112191221913219142191521916219172191821919219202192121922219232192421925219262192721928219292193021931219322193321934219352193621937219382193921940219412194221943219442194521946219472194821949219502195121952219532195421955219562195721958219592196021961219622196321964219652196621967219682196921970219712197221973219742197521976219772197821979219802198121982219832198421985219862198721988219892199021991219922199321994219952199621997219982199922000220012200222003220042200522006220072200822009220102201122012220132201422015220162201722018220192202022021220222202322024220252202622027220282202922030220312203222033220342203522036220372203822039220402204122042220432204422045220462204722048220492205022051220522205322054220552205622057220582205922060220612206222063220642206522066220672206822069220702207122072220732207422075220762207722078220792208022081220822208322084220852208622087220882208922090220912209222093220942209522096220972209822099221002210122102221032210422105221062210722108221092211022111221122211322114221152211622117221182211922120221212212222123221242212522126221272212822129221302213122132221332213422135221362213722138221392214022141221422214322144221452214622147221482214922150221512215222153221542215522156221572215822159221602216122162221632216422165221662216722168221692217022171221722217322174221752217622177221782217922180221812218222183221842218522186221872218822189221902219122192221932219422195221962219722198221992220022201222022220322204222052220622207222082220922210222112221222213222142221522216222172221822219222202222122222222232222422225222262222722228222292223022231222322223322234222352223622237222382223922240222412224222243222442224522246222472224822249222502225122252222532225422255222562225722258222592226022261222622226322264222652226622267222682226922270222712227222273222742227522276222772227822279222802228122282222832228422285222862228722288222892229022291222922229322294222952229622297222982229922300223012230222303223042230522306223072230822309223102231122312223132231422315223162231722318223192232022321223222232322324223252232622327223282232922330223312233222333223342233522336223372233822339223402234122342223432234422345223462234722348223492235022351223522235322354223552235622357223582235922360223612236222363223642236522366223672236822369223702237122372223732237422375223762237722378223792238022381223822238322384223852238622387223882238922390223912239222393223942239522396223972239822399224002240122402224032240422405224062240722408224092241022411224122241322414224152241622417224182241922420224212242222423224242242522426224272242822429224302243122432224332243422435224362243722438224392244022441224422244322444224452244622447224482244922450224512245222453224542245522456224572245822459224602246122462224632246422465224662246722468224692247022471224722247322474224752247622477224782247922480224812248222483224842248522486224872248822489224902249122492224932249422495224962249722498224992250022501225022250322504225052250622507225082250922510225112251222513225142251522516225172251822519225202252122522225232252422525225262252722528225292253022531225322253322534225352253622537225382253922540225412254222543225442254522546225472254822549225502255122552225532255422555225562255722558225592256022561225622256322564225652256622567225682256922570225712257222573225742257522576225772257822579225802258122582225832258422585225862258722588225892259022591225922259322594225952259622597225982259922600226012260222603226042260522606226072260822609226102261122612226132261422615226162261722618226192262022621226222262322624226252262622627226282262922630226312263222633226342263522636226372263822639226402264122642226432264422645226462264722648226492265022651226522265322654226552265622657226582265922660226612266222663226642266522666226672266822669226702267122672226732267422675226762267722678226792268022681226822268322684226852268622687226882268922690226912269222693226942269522696226972269822699227002270122702227032270422705227062270722708227092271022711227122271322714227152271622717227182271922720227212272222723227242272522726227272272822729227302273122732227332273422735227362273722738227392274022741227422274322744227452274622747227482274922750227512275222753227542275522756227572275822759227602276122762227632276422765227662276722768227692277022771227722277322774227752277622777227782277922780227812278222783227842278522786227872278822789227902279122792227932279422795227962279722798227992280022801228022280322804228052280622807228082280922810228112281222813228142281522816228172281822819228202282122822228232282422825228262282722828228292283022831228322283322834228352283622837228382283922840228412284222843228442284522846228472284822849228502285122852228532285422855228562285722858228592286022861228622286322864228652286622867228682286922870228712287222873228742287522876228772287822879228802288122882228832288422885228862288722888228892289022891228922289322894228952289622897228982289922900229012290222903229042290522906229072290822909229102291122912229132291422915229162291722918229192292022921229222292322924229252292622927229282292922930229312293222933229342293522936229372293822939229402294122942229432294422945229462294722948229492295022951229522295322954229552295622957229582295922960229612296222963229642296522966229672296822969229702297122972229732297422975229762297722978229792298022981229822298322984229852298622987229882298922990229912299222993229942299522996229972299822999230002300123002230032300423005230062300723008230092301023011230122301323014230152301623017230182301923020230212302223023230242302523026230272302823029230302303123032230332303423035230362303723038230392304023041230422304323044230452304623047230482304923050230512305223053230542305523056230572305823059230602306123062230632306423065230662306723068230692307023071230722307323074230752307623077230782307923080230812308223083230842308523086230872308823089230902309123092230932309423095230962309723098230992310023101231022310323104231052310623107231082310923110231112311223113231142311523116231172311823119231202312123122231232312423125231262312723128231292313023131231322313323134231352313623137231382313923140231412314223143231442314523146231472314823149231502315123152231532315423155231562315723158231592316023161231622316323164231652316623167231682316923170231712317223173231742317523176231772317823179231802318123182231832318423185231862318723188231892319023191231922319323194231952319623197231982319923200232012320223203232042320523206232072320823209232102321123212232132321423215232162321723218232192322023221232222322323224232252322623227232282322923230232312323223233232342323523236232372323823239232402324123242232432324423245232462324723248232492325023251232522325323254232552325623257232582325923260232612326223263232642326523266232672326823269232702327123272232732327423275232762327723278232792328023281232822328323284232852328623287232882328923290232912329223293232942329523296232972329823299233002330123302233032330423305233062330723308233092331023311233122331323314233152331623317233182331923320233212332223323233242332523326233272332823329233302333123332233332333423335233362333723338233392334023341233422334323344233452334623347233482334923350233512335223353233542335523356233572335823359233602336123362233632336423365233662336723368233692337023371233722337323374233752337623377233782337923380233812338223383233842338523386233872338823389233902339123392233932339423395233962339723398233992340023401234022340323404234052340623407234082340923410234112341223413234142341523416234172341823419234202342123422234232342423425234262342723428234292343023431234322343323434234352343623437234382343923440234412344223443234442344523446234472344823449234502345123452234532345423455234562345723458234592346023461234622346323464234652346623467234682346923470234712347223473234742347523476234772347823479234802348123482234832348423485234862348723488234892349023491234922349323494234952349623497234982349923500235012350223503235042350523506235072350823509235102351123512235132351423515235162351723518235192352023521235222352323524235252352623527235282352923530235312353223533235342353523536235372353823539235402354123542235432354423545235462354723548235492355023551235522355323554235552355623557235582355923560235612356223563235642356523566235672356823569235702357123572235732357423575235762357723578235792358023581235822358323584235852358623587235882358923590235912359223593235942359523596235972359823599236002360123602236032360423605236062360723608236092361023611236122361323614236152361623617236182361923620236212362223623236242362523626236272362823629236302363123632236332363423635236362363723638236392364023641236422364323644236452364623647236482364923650236512365223653236542365523656236572365823659236602366123662236632366423665236662366723668236692367023671236722367323674236752367623677236782367923680236812368223683236842368523686236872368823689236902369123692236932369423695236962369723698236992370023701237022370323704237052370623707237082370923710237112371223713237142371523716237172371823719237202372123722237232372423725237262372723728237292373023731237322373323734237352373623737237382373923740237412374223743237442374523746237472374823749237502375123752237532375423755237562375723758237592376023761237622376323764237652376623767237682376923770237712377223773237742377523776237772377823779237802378123782237832378423785237862378723788237892379023791237922379323794237952379623797237982379923800238012380223803238042380523806238072380823809238102381123812238132381423815238162381723818238192382023821238222382323824238252382623827238282382923830238312383223833238342383523836238372383823839238402384123842238432384423845238462384723848238492385023851238522385323854238552385623857238582385923860238612386223863238642386523866238672386823869238702387123872238732387423875238762387723878238792388023881238822388323884238852388623887238882388923890238912389223893238942389523896238972389823899239002390123902239032390423905239062390723908239092391023911239122391323914239152391623917239182391923920239212392223923239242392523926239272392823929239302393123932239332393423935239362393723938239392394023941239422394323944239452394623947239482394923950239512395223953239542395523956239572395823959239602396123962239632396423965239662396723968239692397023971239722397323974239752397623977239782397923980239812398223983239842398523986239872398823989239902399123992239932399423995239962399723998239992400024001240022400324004240052400624007240082400924010240112401224013240142401524016240172401824019240202402124022240232402424025240262402724028240292403024031240322403324034240352403624037240382403924040240412404224043240442404524046240472404824049240502405124052240532405424055240562405724058240592406024061240622406324064240652406624067240682406924070240712407224073240742407524076240772407824079240802408124082240832408424085240862408724088240892409024091240922409324094240952409624097240982409924100241012410224103241042410524106241072410824109241102411124112241132411424115241162411724118241192412024121241222412324124241252412624127241282412924130241312413224133241342413524136241372413824139241402414124142241432414424145241462414724148241492415024151241522415324154241552415624157241582415924160241612416224163241642416524166241672416824169241702417124172241732417424175241762417724178241792418024181241822418324184241852418624187241882418924190241912419224193241942419524196241972419824199242002420124202242032420424205242062420724208242092421024211242122421324214242152421624217242182421924220242212422224223242242422524226242272422824229242302423124232242332423424235242362423724238242392424024241242422424324244242452424624247242482424924250242512425224253242542425524256242572425824259242602426124262242632426424265242662426724268242692427024271242722427324274242752427624277242782427924280242812428224283242842428524286242872428824289242902429124292242932429424295242962429724298242992430024301243022430324304243052430624307243082430924310243112431224313243142431524316243172431824319243202432124322243232432424325243262432724328243292433024331243322433324334243352433624337243382433924340243412434224343243442434524346243472434824349243502435124352243532435424355243562435724358243592436024361243622436324364243652436624367243682436924370243712437224373243742437524376243772437824379243802438124382243832438424385243862438724388243892439024391243922439324394243952439624397243982439924400244012440224403244042440524406244072440824409244102441124412244132441424415244162441724418244192442024421244222442324424244252442624427244282442924430244312443224433244342443524436244372443824439244402444124442244432444424445244462444724448244492445024451244522445324454244552445624457244582445924460244612446224463244642446524466244672446824469244702447124472244732447424475244762447724478244792448024481244822448324484244852448624487244882448924490244912449224493244942449524496244972449824499245002450124502245032450424505245062450724508245092451024511245122451324514245152451624517245182451924520245212452224523245242452524526245272452824529245302453124532245332453424535245362453724538245392454024541245422454324544245452454624547245482454924550245512455224553245542455524556245572455824559245602456124562245632456424565245662456724568245692457024571245722457324574245752457624577245782457924580245812458224583245842458524586245872458824589245902459124592245932459424595245962459724598245992460024601246022460324604246052460624607246082460924610246112461224613246142461524616246172461824619246202462124622246232462424625246262462724628246292463024631246322463324634246352463624637246382463924640246412464224643246442464524646246472464824649246502465124652246532465424655246562465724658246592466024661246622466324664246652466624667246682466924670246712467224673246742467524676246772467824679246802468124682246832468424685246862468724688246892469024691246922469324694246952469624697246982469924700247012470224703247042470524706247072470824709247102471124712247132471424715247162471724718247192472024721247222472324724247252472624727247282472924730247312473224733247342473524736247372473824739247402474124742247432474424745247462474724748247492475024751247522475324754247552475624757247582475924760247612476224763247642476524766247672476824769247702477124772247732477424775247762477724778247792478024781247822478324784247852478624787247882478924790247912479224793247942479524796247972479824799248002480124802248032480424805248062480724808248092481024811248122481324814248152481624817248182481924820248212482224823248242482524826248272482824829248302483124832248332483424835248362483724838248392484024841248422484324844248452484624847248482484924850248512485224853248542485524856248572485824859248602486124862248632486424865248662486724868248692487024871248722487324874248752487624877248782487924880248812488224883248842488524886248872488824889248902489124892248932489424895248962489724898248992490024901249022490324904249052490624907249082490924910249112491224913249142491524916249172491824919249202492124922249232492424925249262492724928249292493024931249322493324934249352493624937249382493924940249412494224943249442494524946249472494824949249502495124952249532495424955249562495724958249592496024961249622496324964249652496624967249682496924970249712497224973249742497524976249772497824979249802498124982249832498424985249862498724988249892499024991249922499324994249952499624997249982499925000250012500225003250042500525006250072500825009250102501125012250132501425015250162501725018250192502025021250222502325024250252502625027250282502925030250312503225033250342503525036250372503825039250402504125042250432504425045250462504725048250492505025051250522505325054250552505625057250582505925060250612506225063250642506525066250672506825069250702507125072250732507425075250762507725078250792508025081250822508325084250852508625087250882508925090250912509225093250942509525096250972509825099251002510125102251032510425105251062510725108251092511025111251122511325114251152511625117251182511925120251212512225123251242512525126251272512825129251302513125132251332513425135251362513725138251392514025141251422514325144251452514625147251482514925150251512515225153251542515525156251572515825159251602516125162251632516425165251662516725168251692517025171251722517325174251752517625177251782517925180251812518225183251842518525186
  1. !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var f;"undefined"!=typeof window?f=window:"undefined"!=typeof global?f=global:"undefined"!=typeof self&&(f=self),f.APP=e()}}(function(){var define,module,exports;return (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. /* jshint -W117 */
  3. /* application specific logic */
  4. var APP =
  5. {
  6. init: function () {
  7. this.UI = require("./modules/UI/UI");
  8. this.API = require("./modules/API/API");
  9. this.connectionquality = require("./modules/connectionquality/connectionquality");
  10. this.statistics = require("./modules/statistics/statistics");
  11. this.RTC = require("./modules/RTC/RTC");
  12. this.simulcast = require("./modules/simulcast/simulcast");
  13. this.desktopsharing = require("./modules/desktopsharing/desktopsharing");
  14. this.xmpp = require("./modules/xmpp/xmpp");
  15. this.keyboardshortcut = require("./modules/keyboardshortcut/keyboardshortcut");
  16. this.translation = require("./modules/translation/translation");
  17. }
  18. };
  19. function init() {
  20. APP.RTC.start();
  21. APP.xmpp.start(APP.UI.getCredentials());
  22. APP.statistics.start();
  23. APP.connectionquality.init();
  24. // Set default desktop sharing method
  25. APP.desktopsharing.init();
  26. APP.keyboardshortcut.init();
  27. }
  28. $(document).ready(function () {
  29. APP.init();
  30. APP.translation.init();
  31. if(APP.API.isEnabled())
  32. APP.API.init();
  33. APP.UI.start(init);
  34. });
  35. $(window).bind('beforeunload', function () {
  36. if(APP.API.isEnabled())
  37. APP.API.dispose();
  38. });
  39. module.exports = APP;
  40. },{"./modules/API/API":2,"./modules/RTC/RTC":6,"./modules/UI/UI":8,"./modules/connectionquality/connectionquality":35,"./modules/desktopsharing/desktopsharing":36,"./modules/keyboardshortcut/keyboardshortcut":37,"./modules/simulcast/simulcast":42,"./modules/statistics/statistics":45,"./modules/translation/translation":46,"./modules/xmpp/xmpp":60}],2:[function(require,module,exports){
  41. /**
  42. * Implements API class that communicates with external api class
  43. * and provides interface to access Jitsi Meet features by external
  44. * applications that embed Jitsi Meet
  45. */
  46. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  47. /**
  48. * List of the available commands.
  49. * @type {{
  50. * displayName: inputDisplayNameHandler,
  51. * muteAudio: toggleAudio,
  52. * muteVideo: toggleVideo,
  53. * filmStrip: toggleFilmStrip
  54. * }}
  55. */
  56. var commands =
  57. {
  58. displayName: APP.UI.inputDisplayNameHandler,
  59. muteAudio: APP.UI.toggleAudio,
  60. muteVideo: APP.UI.toggleVideo,
  61. toggleFilmStrip: APP.UI.toggleFilmStrip,
  62. toggleChat: APP.UI.toggleChat,
  63. toggleContactList: APP.UI.toggleContactList
  64. };
  65. /**
  66. * Maps the supported events and their status
  67. * (true it the event is enabled and false if it is disabled)
  68. * @type {{
  69. * incomingMessage: boolean,
  70. * outgoingMessage: boolean,
  71. * displayNameChange: boolean,
  72. * participantJoined: boolean,
  73. * participantLeft: boolean
  74. * }}
  75. */
  76. var events =
  77. {
  78. incomingMessage: false,
  79. outgoingMessage:false,
  80. displayNameChange: false,
  81. participantJoined: false,
  82. participantLeft: false
  83. };
  84. var displayName = {};
  85. /**
  86. * Processes commands from external applicaiton.
  87. * @param message the object with the command
  88. */
  89. function processCommand(message)
  90. {
  91. if(message.action != "execute")
  92. {
  93. console.error("Unknown action of the message");
  94. return;
  95. }
  96. for(var key in message)
  97. {
  98. if(commands[key])
  99. commands[key].apply(null, message[key]);
  100. }
  101. }
  102. /**
  103. * Processes events objects from external applications
  104. * @param event the event
  105. */
  106. function processEvent(event) {
  107. if(!event.action)
  108. {
  109. console.error("Event with no action is received.");
  110. return;
  111. }
  112. var i = 0;
  113. switch(event.action)
  114. {
  115. case "add":
  116. for(; i < event.events.length; i++)
  117. {
  118. events[event.events[i]] = true;
  119. }
  120. break;
  121. case "remove":
  122. for(; i < event.events.length; i++)
  123. {
  124. events[event.events[i]] = false;
  125. }
  126. break;
  127. default:
  128. console.error("Unknown action for event.");
  129. }
  130. }
  131. /**
  132. * Sends message to the external application.
  133. * @param object
  134. */
  135. function sendMessage(object) {
  136. window.parent.postMessage(JSON.stringify(object), "*");
  137. }
  138. /**
  139. * Processes a message event from the external application
  140. * @param event the message event
  141. */
  142. function processMessage(event)
  143. {
  144. var message;
  145. try {
  146. message = JSON.parse(event.data);
  147. } catch (e) {}
  148. if(!message.type)
  149. return;
  150. switch (message.type)
  151. {
  152. case "command":
  153. processCommand(message);
  154. break;
  155. case "event":
  156. processEvent(message);
  157. break;
  158. default:
  159. console.error("Unknown type of the message");
  160. return;
  161. }
  162. }
  163. function setupListeners() {
  164. APP.xmpp.addListener(XMPPEvents.MUC_ENTER, function (from) {
  165. API.triggerEvent("participantJoined", {jid: from});
  166. });
  167. APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, function (from, nick, txt, myjid) {
  168. if (from != myjid)
  169. API.triggerEvent("incomingMessage",
  170. {"from": from, "nick": nick, "message": txt});
  171. });
  172. APP.xmpp.addListener(XMPPEvents.MUC_LEFT, function (jid) {
  173. API.triggerEvent("participantLeft", {jid: jid});
  174. });
  175. APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, function (jid, newDisplayName) {
  176. name = displayName[jid];
  177. if(!name || name != newDisplayName) {
  178. API.triggerEvent("displayNameChange", {jid: jid, displayname: newDisplayName});
  179. displayName[jid] = newDisplayName;
  180. }
  181. });
  182. APP.xmpp.addListener(XMPPEvents.SENDING_CHAT_MESSAGE, function (body) {
  183. APP.API.triggerEvent("outgoingMessage", {"message": body});
  184. });
  185. }
  186. var API = {
  187. /**
  188. * Check whether the API should be enabled or not.
  189. * @returns {boolean}
  190. */
  191. isEnabled: function () {
  192. var hash = location.hash;
  193. if(hash && hash.indexOf("external") > -1 && window.postMessage)
  194. return true;
  195. return false;
  196. },
  197. /**
  198. * Initializes the APIConnector. Setups message event listeners that will
  199. * receive information from external applications that embed Jitsi Meet.
  200. * It also sends a message to the external application that APIConnector
  201. * is initialized.
  202. */
  203. init: function () {
  204. if (window.addEventListener)
  205. {
  206. window.addEventListener('message',
  207. processMessage, false);
  208. }
  209. else
  210. {
  211. window.attachEvent('onmessage', processMessage);
  212. }
  213. sendMessage({type: "system", loaded: true});
  214. setupListeners();
  215. },
  216. /**
  217. * Checks whether the event is enabled ot not.
  218. * @param name the name of the event.
  219. * @returns {*}
  220. */
  221. isEventEnabled: function (name) {
  222. return events[name];
  223. },
  224. /**
  225. * Sends event object to the external application that has been subscribed
  226. * for that event.
  227. * @param name the name event
  228. * @param object data associated with the event
  229. */
  230. triggerEvent: function (name, object) {
  231. if(this.isEnabled() && this.isEventEnabled(name))
  232. sendMessage({
  233. type: "event", action: "result", event: name, result: object});
  234. },
  235. /**
  236. * Removes the listeners.
  237. */
  238. dispose: function () {
  239. if(window.removeEventListener)
  240. {
  241. window.removeEventListener("message",
  242. processMessage, false);
  243. }
  244. else
  245. {
  246. window.detachEvent('onmessage', processMessage);
  247. }
  248. }
  249. };
  250. module.exports = API;
  251. },{"../../service/xmpp/XMPPEvents":86}],3:[function(require,module,exports){
  252. /* global Strophe, updateLargeVideo, focusedVideoSrc*/
  253. // cache datachannels to avoid garbage collection
  254. // https://code.google.com/p/chromium/issues/detail?id=405545
  255. var RTCEvents = require("../../service/RTC/RTCEvents");
  256. var _dataChannels = [];
  257. var eventEmitter = null;
  258. var DataChannels =
  259. {
  260. /**
  261. * Callback triggered by PeerConnection when new data channel is opened
  262. * on the bridge.
  263. * @param event the event info object.
  264. */
  265. onDataChannel: function (event)
  266. {
  267. var dataChannel = event.channel;
  268. dataChannel.onopen = function () {
  269. console.info("Data channel opened by the Videobridge!", dataChannel);
  270. // Code sample for sending string and/or binary data
  271. // Sends String message to the bridge
  272. //dataChannel.send("Hello bridge!");
  273. // Sends 12 bytes binary message to the bridge
  274. //dataChannel.send(new ArrayBuffer(12));
  275. // when the data channel becomes available, tell the bridge about video
  276. // selections so that it can do adaptive simulcast,
  277. // we want the notification to trigger even if userJid is undefined,
  278. // or null.
  279. var userJid = APP.UI.getLargeVideoState().userJid;
  280. // we want the notification to trigger even if userJid is undefined,
  281. // or null.
  282. onSelectedEndpointChanged(userJid);
  283. };
  284. dataChannel.onerror = function (error) {
  285. console.error("Data Channel Error:", error, dataChannel);
  286. };
  287. dataChannel.onmessage = function (event) {
  288. var data = event.data;
  289. // JSON
  290. var obj;
  291. try {
  292. obj = JSON.parse(data);
  293. }
  294. catch (e) {
  295. console.error(
  296. "Failed to parse data channel message as JSON: ",
  297. data,
  298. dataChannel);
  299. }
  300. if (('undefined' !== typeof(obj)) && (null !== obj)) {
  301. var colibriClass = obj.colibriClass;
  302. if ("DominantSpeakerEndpointChangeEvent" === colibriClass) {
  303. // Endpoint ID from the Videobridge.
  304. var dominantSpeakerEndpoint = obj.dominantSpeakerEndpoint;
  305. console.info(
  306. "Data channel new dominant speaker event: ",
  307. dominantSpeakerEndpoint);
  308. eventEmitter.emit(RTCEvents.DOMINANTSPEAKER_CHANGED, dominantSpeakerEndpoint);
  309. }
  310. else if ("InLastNChangeEvent" === colibriClass)
  311. {
  312. var oldValue = obj.oldValue;
  313. var newValue = obj.newValue;
  314. // Make sure that oldValue and newValue are of type boolean.
  315. var type;
  316. if ((type = typeof oldValue) !== 'boolean') {
  317. if (type === 'string') {
  318. oldValue = (oldValue == "true");
  319. } else {
  320. oldValue = new Boolean(oldValue).valueOf();
  321. }
  322. }
  323. if ((type = typeof newValue) !== 'boolean') {
  324. if (type === 'string') {
  325. newValue = (newValue == "true");
  326. } else {
  327. newValue = new Boolean(newValue).valueOf();
  328. }
  329. }
  330. eventEmitter.emit(RTCEvents.LASTN_CHANGED, oldValue, newValue);
  331. }
  332. else if ("LastNEndpointsChangeEvent" === colibriClass)
  333. {
  334. // The new/latest list of last-n endpoint IDs.
  335. var lastNEndpoints = obj.lastNEndpoints;
  336. // The list of endpoint IDs which are entering the list of
  337. // last-n at this time i.e. were not in the old list of last-n
  338. // endpoint IDs.
  339. var endpointsEnteringLastN = obj.endpointsEnteringLastN;
  340. var stream = obj.stream;
  341. console.log(
  342. "Data channel new last-n event: ",
  343. lastNEndpoints, endpointsEnteringLastN, obj);
  344. eventEmitter.emit(RTCEvents.LASTN_ENDPOINT_CHANGED,
  345. lastNEndpoints, endpointsEnteringLastN, obj);
  346. }
  347. else if ("SimulcastLayersChangedEvent" === colibriClass)
  348. {
  349. eventEmitter.emit(RTCEvents.SIMULCAST_LAYER_CHANGED,
  350. obj.endpointSimulcastLayers);
  351. }
  352. else if ("SimulcastLayersChangingEvent" === colibriClass)
  353. {
  354. eventEmitter.emit(RTCEvents.SIMULCAST_LAYER_CHANGING,
  355. obj.endpointSimulcastLayers);
  356. }
  357. else if ("StartSimulcastLayerEvent" === colibriClass)
  358. {
  359. eventEmitter.emit(RTCEvents.SIMULCAST_START, obj.simulcastLayer);
  360. }
  361. else if ("StopSimulcastLayerEvent" === colibriClass)
  362. {
  363. eventEmitter.emit(RTCEvents.SIMULCAST_STOP, obj.simulcastLayer);
  364. }
  365. else
  366. {
  367. console.debug("Data channel JSON-formatted message: ", obj);
  368. }
  369. }
  370. };
  371. dataChannel.onclose = function ()
  372. {
  373. console.info("The Data Channel closed", dataChannel);
  374. var idx = _dataChannels.indexOf(dataChannel);
  375. if (idx > -1)
  376. _dataChannels = _dataChannels.splice(idx, 1);
  377. };
  378. _dataChannels.push(dataChannel);
  379. },
  380. /**
  381. * Binds "ondatachannel" event listener to given PeerConnection instance.
  382. * @param peerConnection WebRTC peer connection instance.
  383. */
  384. init: function (peerConnection, emitter) {
  385. if(!config.openSctp)
  386. return;
  387. peerConnection.ondatachannel = this.onDataChannel;
  388. eventEmitter = emitter;
  389. // Sample code for opening new data channel from Jitsi Meet to the bridge.
  390. // Although it's not a requirement to open separate channels from both bridge
  391. // and peer as single channel can be used for sending and receiving data.
  392. // So either channel opened by the bridge or the one opened here is enough
  393. // for communication with the bridge.
  394. /*var dataChannelOptions =
  395. {
  396. reliable: true
  397. };
  398. var dataChannel
  399. = peerConnection.createDataChannel("myChannel", dataChannelOptions);
  400. // Can be used only when is in open state
  401. dataChannel.onopen = function ()
  402. {
  403. dataChannel.send("My channel !!!");
  404. };
  405. dataChannel.onmessage = function (event)
  406. {
  407. var msgData = event.data;
  408. console.info("Got My Data Channel Message:", msgData, dataChannel);
  409. };*/
  410. },
  411. handleSelectedEndpointEvent: onSelectedEndpointChanged,
  412. handlePinnedEndpointEvent: onPinnedEndpointChanged
  413. };
  414. function onSelectedEndpointChanged(userResource)
  415. {
  416. console.log('selected endpoint changed: ', userResource);
  417. if (_dataChannels && _dataChannels.length != 0)
  418. {
  419. _dataChannels.some(function (dataChannel) {
  420. if (dataChannel.readyState == 'open')
  421. {
  422. dataChannel.send(JSON.stringify({
  423. 'colibriClass': 'SelectedEndpointChangedEvent',
  424. 'selectedEndpoint':
  425. (!userResource || userResource === null)?
  426. null : userResource
  427. }));
  428. return true;
  429. }
  430. });
  431. }
  432. }
  433. function onPinnedEndpointChanged(userResource)
  434. {
  435. console.log('pinned endpoint changed: ', userResource);
  436. if (_dataChannels && _dataChannels.length != 0)
  437. {
  438. _dataChannels.some(function (dataChannel) {
  439. if (dataChannel.readyState == 'open')
  440. {
  441. dataChannel.send(JSON.stringify({
  442. 'colibriClass': 'PinnedEndpointChangedEvent',
  443. 'pinnedEndpoint':
  444. (!userResource || userResource == null)?
  445. null : userResource
  446. }));
  447. return true;
  448. }
  449. });
  450. }
  451. }
  452. module.exports = DataChannels;
  453. },{"../../service/RTC/RTCEvents":80}],4:[function(require,module,exports){
  454. var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
  455. function LocalStream(stream, type, eventEmitter, videoType)
  456. {
  457. this.stream = stream;
  458. this.eventEmitter = eventEmitter;
  459. this.type = type;
  460. this.videoType = videoType;
  461. var self = this;
  462. if(type == "audio")
  463. {
  464. this.getTracks = function () {
  465. return self.stream.getAudioTracks();
  466. };
  467. }
  468. else
  469. {
  470. this.getTracks = function () {
  471. return self.stream.getVideoTracks();
  472. };
  473. }
  474. this.stream.onended = function()
  475. {
  476. self.streamEnded();
  477. };
  478. }
  479. LocalStream.prototype.streamEnded = function () {
  480. this.eventEmitter.emit(StreamEventTypes.EVENT_TYPE_LOCAL_ENDED, this);
  481. }
  482. LocalStream.prototype.getOriginalStream = function()
  483. {
  484. return this.stream;
  485. }
  486. LocalStream.prototype.isAudioStream = function () {
  487. return (this.stream.getAudioTracks() && this.stream.getAudioTracks().length > 0);
  488. };
  489. LocalStream.prototype.mute = function()
  490. {
  491. var ismuted = false;
  492. var tracks = this.getTracks();
  493. for (var idx = 0; idx < tracks.length; idx++) {
  494. ismuted = !tracks[idx].enabled;
  495. tracks[idx].enabled = ismuted;
  496. }
  497. return ismuted;
  498. };
  499. LocalStream.prototype.setMute = function(mute)
  500. {
  501. var tracks = this.getTracks();
  502. for (var idx = 0; idx < tracks.length; idx++) {
  503. tracks[idx].enabled = mute;
  504. }
  505. };
  506. LocalStream.prototype.isMuted = function () {
  507. var tracks = [];
  508. if(this.type == "audio")
  509. {
  510. tracks = this.stream.getAudioTracks();
  511. }
  512. else
  513. {
  514. tracks = this.stream.getVideoTracks();
  515. }
  516. for (var idx = 0; idx < tracks.length; idx++) {
  517. if(tracks[idx].enabled)
  518. return false;
  519. }
  520. return true;
  521. }
  522. LocalStream.prototype.getId = function () {
  523. return this.stream.getTracks()[0].id;
  524. }
  525. module.exports = LocalStream;
  526. },{"../../service/RTC/StreamEventTypes.js":81}],5:[function(require,module,exports){
  527. ////These lines should be uncommented when require works in app.js
  528. var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
  529. var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
  530. /**
  531. * Creates a MediaStream object for the given data, session id and ssrc.
  532. * It is a wrapper class for the MediaStream.
  533. *
  534. * @param data the data object from which we obtain the stream,
  535. * the peerjid, etc.
  536. * @param sid the session id
  537. * @param ssrc the ssrc corresponding to this MediaStream
  538. *
  539. * @constructor
  540. */
  541. function MediaStream(data, sid, ssrc, browser) {
  542. // XXX(gp) to minimize headaches in the future, we should build our
  543. // abstractions around tracks and not streams. ORTC is track based API.
  544. // Mozilla expects m-lines to represent media tracks.
  545. //
  546. // Practically, what I'm saying is that we should have a MediaTrack class
  547. // and not a MediaStream class.
  548. //
  549. // Also, we should be able to associate multiple SSRCs with a MediaTrack as
  550. // a track might have an associated RTX and FEC sources.
  551. this.sid = sid;
  552. this.stream = data.stream;
  553. this.peerjid = data.peerjid;
  554. this.ssrc = ssrc;
  555. this.type = (this.stream.getVideoTracks().length > 0)?
  556. MediaStreamType.VIDEO_TYPE : MediaStreamType.AUDIO_TYPE;
  557. this.videoType = null;
  558. this.muted = false;
  559. if(browser == RTCBrowserType.RTC_BROWSER_FIREFOX)
  560. {
  561. if (!this.getVideoTracks)
  562. this.getVideoTracks = function () { return []; };
  563. if (!this.getAudioTracks)
  564. this.getAudioTracks = function () { return []; };
  565. }
  566. }
  567. MediaStream.prototype.getOriginalStream = function()
  568. {
  569. return this.stream;
  570. }
  571. MediaStream.prototype.setMute = function (value)
  572. {
  573. this.stream.muted = value;
  574. this.muted = value;
  575. }
  576. module.exports = MediaStream;
  577. },{"../../service/RTC/MediaStreamTypes":78,"../../service/RTC/RTCBrowserType.js":79}],6:[function(require,module,exports){
  578. var EventEmitter = require("events");
  579. var RTCUtils = require("./RTCUtils.js");
  580. var LocalStream = require("./LocalStream.js");
  581. var DataChannels = require("./DataChannels");
  582. var MediaStream = require("./MediaStream.js");
  583. var DesktopSharingEventTypes
  584. = require("../../service/desktopsharing/DesktopSharingEventTypes");
  585. var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
  586. var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
  587. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  588. var UIEvents = require("../../service/UI/UIEvents");
  589. var eventEmitter = new EventEmitter();
  590. var RTC = {
  591. rtcUtils: null,
  592. localStreams: [],
  593. remoteStreams: {},
  594. localAudio: null,
  595. localVideo: null,
  596. addStreamListener: function (listener, eventType) {
  597. eventEmitter.on(eventType, listener);
  598. },
  599. addListener: function (type, listener) {
  600. eventEmitter.on(type, listener);
  601. },
  602. removeStreamListener: function (listener, eventType) {
  603. if(!(eventType instanceof StreamEventTypes))
  604. throw "Illegal argument";
  605. eventEmitter.removeListener(eventType, listener);
  606. },
  607. createLocalStream: function (stream, type, change) {
  608. var localStream = new LocalStream(stream, type, eventEmitter);
  609. //in firefox we have only one stream object
  610. if(this.localStreams.length == 0 ||
  611. this.localStreams[0].getOriginalStream() != stream)
  612. this.localStreams.push(localStream);
  613. if(type == "audio")
  614. {
  615. this.localAudio = localStream;
  616. }
  617. else
  618. {
  619. this.localVideo = localStream;
  620. }
  621. var eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CREATED;
  622. if(change)
  623. eventType = StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED;
  624. eventEmitter.emit(eventType, localStream);
  625. return localStream;
  626. },
  627. removeLocalStream: function (stream) {
  628. for(var i = 0; i < this.localStreams.length; i++)
  629. {
  630. if(this.localStreams[i].getOriginalStream() === stream) {
  631. delete this.localStreams[i];
  632. return;
  633. }
  634. }
  635. },
  636. createRemoteStream: function (data, sid, thessrc) {
  637. var remoteStream = new MediaStream(data, sid, thessrc,
  638. this.getBrowserType());
  639. var jid = data.peerjid || APP.xmpp.myJid();
  640. if(!this.remoteStreams[jid]) {
  641. this.remoteStreams[jid] = {};
  642. }
  643. this.remoteStreams[jid][remoteStream.type]= remoteStream;
  644. eventEmitter.emit(StreamEventTypes.EVENT_TYPE_REMOTE_CREATED, remoteStream);
  645. console.debug("ADD remote stream ", remoteStream.type, " ", jid, " ", thessrc);
  646. return remoteStream;
  647. },
  648. getBrowserType: function () {
  649. return this.rtcUtils.browser;
  650. },
  651. getPCConstraints: function () {
  652. return this.rtcUtils.pc_constraints;
  653. },
  654. getUserMediaWithConstraints:function(um, success_callback,
  655. failure_callback, resolution,
  656. bandwidth, fps, desktopStream)
  657. {
  658. return this.rtcUtils.getUserMediaWithConstraints(um, success_callback,
  659. failure_callback, resolution, bandwidth, fps, desktopStream);
  660. },
  661. attachMediaStream: function (element, stream) {
  662. this.rtcUtils.attachMediaStream(element, stream);
  663. },
  664. getStreamID: function (stream) {
  665. return this.rtcUtils.getStreamID(stream);
  666. },
  667. getVideoSrc: function (element) {
  668. return this.rtcUtils.getVideoSrc(element);
  669. },
  670. setVideoSrc: function (element, src) {
  671. this.rtcUtils.setVideoSrc(element, src);
  672. },
  673. dispose: function() {
  674. if (this.rtcUtils) {
  675. this.rtcUtils = null;
  676. }
  677. },
  678. stop: function () {
  679. this.dispose();
  680. },
  681. start: function () {
  682. var self = this;
  683. APP.desktopsharing.addListener(
  684. function (stream, isUsingScreenStream, callback) {
  685. self.changeLocalVideo(stream, isUsingScreenStream, callback);
  686. }, DesktopSharingEventTypes.NEW_STREAM_CREATED);
  687. APP.xmpp.addListener(XMPPEvents.CHANGED_STREAMS, function (jid, changedStreams) {
  688. for(var i = 0; i < changedStreams.length; i++) {
  689. var type = changedStreams[i].type;
  690. if (type != "audio") {
  691. var peerStreams = self.remoteStreams[jid];
  692. if(!peerStreams)
  693. continue;
  694. var videoStream = peerStreams[MediaStreamType.VIDEO_TYPE];
  695. if(!videoStream)
  696. continue;
  697. videoStream.videoType = changedStreams[i].type;
  698. }
  699. }
  700. });
  701. APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function(event) {
  702. DataChannels.init(event.peerconnection, eventEmitter);
  703. });
  704. APP.UI.addListener(UIEvents.SELECTED_ENDPOINT,
  705. DataChannels.handleSelectedEndpointEvent);
  706. APP.UI.addListener(UIEvents.PINNED_ENDPOINT,
  707. DataChannels.handlePinnedEndpointEvent);
  708. this.rtcUtils = new RTCUtils(this);
  709. this.rtcUtils.obtainAudioAndVideoPermissions();
  710. },
  711. muteRemoteVideoStream: function (jid, value) {
  712. var stream;
  713. if(this.remoteStreams[jid] &&
  714. this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE])
  715. {
  716. stream = this.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
  717. }
  718. if(!stream)
  719. return false;
  720. if (value != stream.muted) {
  721. stream.setMute(value);
  722. return true;
  723. }
  724. return false;
  725. },
  726. switchVideoStreams: function (new_stream) {
  727. this.localVideo.stream = new_stream;
  728. this.localStreams = [];
  729. //in firefox we have only one stream object
  730. if (this.localAudio.getOriginalStream() != new_stream)
  731. this.localStreams.push(this.localAudio);
  732. this.localStreams.push(this.localVideo);
  733. },
  734. changeLocalVideo: function (stream, isUsingScreenStream, callback) {
  735. var oldStream = this.localVideo.getOriginalStream();
  736. var type = (isUsingScreenStream? "screen" : "video");
  737. this.localVideo = this.createLocalStream(stream, "video", true, type);
  738. // Stop the stream to trigger onended event for old stream
  739. oldStream.stop();
  740. APP.xmpp.switchStreams(stream, oldStream,callback);
  741. },
  742. /**
  743. * Checks if video identified by given src is desktop stream.
  744. * @param videoSrc eg.
  745. * blob:https%3A//pawel.jitsi.net/9a46e0bd-131e-4d18-9c14-a9264e8db395
  746. * @returns {boolean}
  747. */
  748. isVideoSrcDesktop: function (jid) {
  749. if(!jid)
  750. return false;
  751. var isDesktop = false;
  752. var stream = null;
  753. if (APP.xmpp.myJid() &&
  754. APP.xmpp.myResource() === jid) {
  755. // local video
  756. stream = this.localVideo;
  757. } else {
  758. var peerStreams = this.remoteStreams[jid];
  759. if(!peerStreams)
  760. return false;
  761. stream = peerStreams[MediaStreamType.VIDEO_TYPE];
  762. }
  763. if(stream)
  764. isDesktop = (stream.videoType === "screen");
  765. return isDesktop;
  766. }
  767. };
  768. module.exports = RTC;
  769. },{"../../service/RTC/MediaStreamTypes":78,"../../service/RTC/StreamEventTypes.js":81,"../../service/UI/UIEvents":82,"../../service/desktopsharing/DesktopSharingEventTypes":84,"../../service/xmpp/XMPPEvents":86,"./DataChannels":3,"./LocalStream.js":4,"./MediaStream.js":5,"./RTCUtils.js":7,"events":87}],7:[function(require,module,exports){
  770. var RTCBrowserType = require("../../service/RTC/RTCBrowserType.js");
  771. function setResolutionConstraints(constraints, resolution, isAndroid)
  772. {
  773. if (resolution && !constraints.video || isAndroid) {
  774. constraints.video = { mandatory: {}, optional: [] };// same behaviour as true
  775. }
  776. // see https://code.google.com/p/chromium/issues/detail?id=143631#c9 for list of supported resolutions
  777. switch (resolution) {
  778. // 16:9 first
  779. case '1080':
  780. case 'fullhd':
  781. constraints.video.mandatory.minWidth = 1920;
  782. constraints.video.mandatory.minHeight = 1080;
  783. break;
  784. case '720':
  785. case 'hd':
  786. constraints.video.mandatory.minWidth = 1280;
  787. constraints.video.mandatory.minHeight = 720;
  788. break;
  789. case '360':
  790. constraints.video.mandatory.minWidth = 640;
  791. constraints.video.mandatory.minHeight = 360;
  792. break;
  793. case '180':
  794. constraints.video.mandatory.minWidth = 320;
  795. constraints.video.mandatory.minHeight = 180;
  796. break;
  797. // 4:3
  798. case '960':
  799. constraints.video.mandatory.minWidth = 960;
  800. constraints.video.mandatory.minHeight = 720;
  801. break;
  802. case '640':
  803. case 'vga':
  804. constraints.video.mandatory.minWidth = 640;
  805. constraints.video.mandatory.minHeight = 480;
  806. break;
  807. case '320':
  808. constraints.video.mandatory.minWidth = 320;
  809. constraints.video.mandatory.minHeight = 240;
  810. break;
  811. default:
  812. if (isAndroid) {
  813. constraints.video.mandatory.minWidth = 320;
  814. constraints.video.mandatory.minHeight = 240;
  815. constraints.video.mandatory.maxFrameRate = 15;
  816. }
  817. break;
  818. }
  819. if (constraints.video.mandatory.minWidth)
  820. constraints.video.mandatory.maxWidth = constraints.video.mandatory.minWidth;
  821. if (constraints.video.mandatory.minHeight)
  822. constraints.video.mandatory.maxHeight = constraints.video.mandatory.minHeight;
  823. }
  824. function getConstraints(um, resolution, bandwidth, fps, desktopStream, isAndroid)
  825. {
  826. var constraints = {audio: false, video: false};
  827. if (um.indexOf('video') >= 0) {
  828. constraints.video = { mandatory: {}, optional: [] };// same behaviour as true
  829. }
  830. if (um.indexOf('audio') >= 0) {
  831. constraints.audio = { mandatory: {}, optional: []};// same behaviour as true
  832. }
  833. if (um.indexOf('screen') >= 0) {
  834. constraints.video = {
  835. mandatory: {
  836. chromeMediaSource: "screen",
  837. googLeakyBucket: true,
  838. maxWidth: window.screen.width,
  839. maxHeight: window.screen.height,
  840. maxFrameRate: 3
  841. },
  842. optional: []
  843. };
  844. }
  845. if (um.indexOf('desktop') >= 0) {
  846. constraints.video = {
  847. mandatory: {
  848. chromeMediaSource: "desktop",
  849. chromeMediaSourceId: desktopStream,
  850. googLeakyBucket: true,
  851. maxWidth: window.screen.width,
  852. maxHeight: window.screen.height,
  853. maxFrameRate: 3
  854. },
  855. optional: []
  856. };
  857. }
  858. if (constraints.audio) {
  859. // if it is good enough for hangouts...
  860. constraints.audio.optional.push(
  861. {googEchoCancellation: true},
  862. {googAutoGainControl: true},
  863. {googNoiseSupression: true},
  864. {googHighpassFilter: true},
  865. {googNoisesuppression2: true},
  866. {googEchoCancellation2: true},
  867. {googAutoGainControl2: true}
  868. );
  869. }
  870. if (constraints.video) {
  871. constraints.video.optional.push(
  872. {googNoiseReduction: false} // chrome 37 workaround for issue 3807, reenable in M38
  873. );
  874. if (um.indexOf('video') >= 0) {
  875. constraints.video.optional.push(
  876. {googLeakyBucket: true}
  877. );
  878. }
  879. }
  880. if (um.indexOf('video') >= 0) {
  881. setResolutionConstraints(constraints, resolution, isAndroid);
  882. }
  883. if (bandwidth) { // doesn't work currently, see webrtc issue 1846
  884. if (!constraints.video) constraints.video = {mandatory: {}, optional: []};//same behaviour as true
  885. constraints.video.optional.push({bandwidth: bandwidth});
  886. }
  887. if (fps) { // for some cameras it might be necessary to request 30fps
  888. // so they choose 30fps mjpg over 10fps yuy2
  889. if (!constraints.video) constraints.video = {mandatory: {}, optional: []};// same behaviour as true;
  890. constraints.video.mandatory.minFrameRate = fps;
  891. }
  892. return constraints;
  893. }
  894. function RTCUtils(RTCService)
  895. {
  896. this.service = RTCService;
  897. if (navigator.mozGetUserMedia) {
  898. console.log('This appears to be Firefox');
  899. var version = parseInt(navigator.userAgent.match(/Firefox\/([0-9]+)\./)[1], 10);
  900. if (version >= 22) {
  901. this.peerconnection = mozRTCPeerConnection;
  902. this.browser = RTCBrowserType.RTC_BROWSER_FIREFOX;
  903. this.getUserMedia = navigator.mozGetUserMedia.bind(navigator);
  904. this.pc_constraints = {};
  905. this.attachMediaStream = function (element, stream) {
  906. element[0].mozSrcObject = stream;
  907. element[0].play();
  908. };
  909. this.getStreamID = function (stream) {
  910. var tracks = stream.getVideoTracks();
  911. if(!tracks || tracks.length == 0)
  912. {
  913. tracks = stream.getAudioTracks();
  914. }
  915. return tracks[0].id.replace(/[\{,\}]/g,"");
  916. };
  917. this.getVideoSrc = function (element) {
  918. return element.mozSrcObject;
  919. };
  920. this.setVideoSrc = function (element, src) {
  921. element.mozSrcObject = src;
  922. };
  923. RTCSessionDescription = mozRTCSessionDescription;
  924. RTCIceCandidate = mozRTCIceCandidate;
  925. }
  926. } else if (navigator.webkitGetUserMedia) {
  927. console.log('This appears to be Chrome');
  928. this.peerconnection = webkitRTCPeerConnection;
  929. this.browser = RTCBrowserType.RTC_BROWSER_CHROME;
  930. this.getUserMedia = navigator.webkitGetUserMedia.bind(navigator);
  931. this.attachMediaStream = function (element, stream) {
  932. element.attr('src', webkitURL.createObjectURL(stream));
  933. };
  934. this.getStreamID = function (stream) {
  935. // streams from FF endpoints have the characters '{' and '}'
  936. // that make jQuery choke.
  937. return stream.id.replace(/[\{,\}]/g,"");
  938. };
  939. this.getVideoSrc = function (element) {
  940. return element.getAttribute("src");
  941. };
  942. this.setVideoSrc = function (element, src) {
  943. element.setAttribute("src", src);
  944. };
  945. // DTLS should now be enabled by default but..
  946. this.pc_constraints = {'optional': [{'DtlsSrtpKeyAgreement': 'true'}]};
  947. if (navigator.userAgent.indexOf('Android') != -1) {
  948. this.pc_constraints = {}; // disable DTLS on Android
  949. }
  950. if (!webkitMediaStream.prototype.getVideoTracks) {
  951. webkitMediaStream.prototype.getVideoTracks = function () {
  952. return this.videoTracks;
  953. };
  954. }
  955. if (!webkitMediaStream.prototype.getAudioTracks) {
  956. webkitMediaStream.prototype.getAudioTracks = function () {
  957. return this.audioTracks;
  958. };
  959. }
  960. }
  961. else
  962. {
  963. try { console.log('Browser does not appear to be WebRTC-capable'); } catch (e) { }
  964. window.location.href = 'webrtcrequired.html';
  965. return;
  966. }
  967. if (this.browser !== RTCBrowserType.RTC_BROWSER_CHROME &&
  968. config.enableFirefoxSupport !== true) {
  969. window.location.href = 'chromeonly.html';
  970. return;
  971. }
  972. }
  973. RTCUtils.prototype.getUserMediaWithConstraints = function(
  974. um, success_callback, failure_callback, resolution,bandwidth, fps,
  975. desktopStream)
  976. {
  977. // Check if we are running on Android device
  978. var isAndroid = navigator.userAgent.indexOf('Android') != -1;
  979. var constraints = getConstraints(
  980. um, resolution, bandwidth, fps, desktopStream, isAndroid);
  981. var isFF = navigator.userAgent.toLowerCase().indexOf('firefox') > -1;
  982. try {
  983. if (config.enableSimulcast
  984. && constraints.video
  985. && constraints.video.chromeMediaSource !== 'screen'
  986. && constraints.video.chromeMediaSource !== 'desktop'
  987. && !isAndroid
  988. // We currently do not support FF, as it doesn't have multistream support.
  989. && !isFF) {
  990. APP.simulcast.getUserMedia(constraints, function (stream) {
  991. console.log('onUserMediaSuccess');
  992. success_callback(stream);
  993. },
  994. function (error) {
  995. console.warn('Failed to get access to local media. Error ', error);
  996. if (failure_callback) {
  997. failure_callback(error);
  998. }
  999. });
  1000. } else {
  1001. this.getUserMedia(constraints,
  1002. function (stream) {
  1003. console.log('onUserMediaSuccess');
  1004. success_callback(stream);
  1005. },
  1006. function (error) {
  1007. console.warn('Failed to get access to local media. Error ',
  1008. error, constraints);
  1009. if (failure_callback) {
  1010. failure_callback(error);
  1011. }
  1012. });
  1013. }
  1014. } catch (e) {
  1015. console.error('GUM failed: ', e);
  1016. if(failure_callback) {
  1017. failure_callback(e);
  1018. }
  1019. }
  1020. };
  1021. /**
  1022. * We ask for audio and video combined stream in order to get permissions and
  1023. * not to ask twice.
  1024. */
  1025. RTCUtils.prototype.obtainAudioAndVideoPermissions = function() {
  1026. var self = this;
  1027. // Get AV
  1028. var cb = function (stream) {
  1029. console.log('got', stream, stream.getAudioTracks().length, stream.getVideoTracks().length);
  1030. self.handleLocalStream(stream);
  1031. };
  1032. var self = this;
  1033. this.getUserMediaWithConstraints(
  1034. ['audio', 'video'],
  1035. cb,
  1036. function (error) {
  1037. console.error('failed to obtain audio/video stream - trying audio only', error);
  1038. self.getUserMediaWithConstraints(
  1039. ['audio'],
  1040. cb,
  1041. function (error) {
  1042. console.error('failed to obtain audio/video stream - stop', error);
  1043. APP.UI.messageHandler.showError("Error",
  1044. "Failed to obtain permissions to use the local microphone" +
  1045. "and/or camera.");
  1046. }
  1047. );
  1048. },
  1049. config.resolution || '360');
  1050. }
  1051. RTCUtils.prototype.handleLocalStream = function(stream)
  1052. {
  1053. if(window.webkitMediaStream)
  1054. {
  1055. var audioStream = new webkitMediaStream();
  1056. var videoStream = new webkitMediaStream();
  1057. var audioTracks = stream.getAudioTracks();
  1058. var videoTracks = stream.getVideoTracks();
  1059. for (var i = 0; i < audioTracks.length; i++) {
  1060. audioStream.addTrack(audioTracks[i]);
  1061. }
  1062. this.service.createLocalStream(audioStream, "audio");
  1063. for (i = 0; i < videoTracks.length; i++) {
  1064. videoStream.addTrack(videoTracks[i]);
  1065. }
  1066. this.service.createLocalStream(videoStream, "video");
  1067. }
  1068. else
  1069. {//firefox
  1070. this.service.createLocalStream(stream, "stream");
  1071. }
  1072. };
  1073. module.exports = RTCUtils;
  1074. },{"../../service/RTC/RTCBrowserType.js":79}],8:[function(require,module,exports){
  1075. var UI = {};
  1076. var VideoLayout = require("./videolayout/VideoLayout.js");
  1077. var AudioLevels = require("./audio_levels/AudioLevels.js");
  1078. var Prezi = require("./prezi/Prezi.js");
  1079. var Etherpad = require("./etherpad/Etherpad.js");
  1080. var Chat = require("./side_pannels/chat/Chat.js");
  1081. var Toolbar = require("./toolbars/Toolbar");
  1082. var ToolbarToggler = require("./toolbars/ToolbarToggler");
  1083. var BottomToolbar = require("./toolbars/BottomToolbar");
  1084. var ContactList = require("./side_pannels/contactlist/ContactList");
  1085. var Avatar = require("./avatar/Avatar");
  1086. var EventEmitter = require("events");
  1087. var SettingsMenu = require("./side_pannels/settings/SettingsMenu");
  1088. var Settings = require("./side_pannels/settings/Settings");
  1089. var PanelToggler = require("./side_pannels/SidePanelToggler");
  1090. var RoomNameGenerator = require("./welcome_page/RoomnameGenerator");
  1091. UI.messageHandler = require("./util/MessageHandler");
  1092. var messageHandler = UI.messageHandler;
  1093. var Authentication = require("./authentication/Authentication");
  1094. var UIUtil = require("./util/UIUtil");
  1095. var NicknameHandler = require("./util/NicknameHandler");
  1096. var CQEvents = require("../../service/connectionquality/CQEvents");
  1097. var DesktopSharingEventTypes
  1098. = require("../../service/desktopsharing/DesktopSharingEventTypes");
  1099. var RTCEvents = require("../../service/RTC/RTCEvents");
  1100. var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
  1101. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  1102. var eventEmitter = new EventEmitter();
  1103. var roomName = null;
  1104. function setupPrezi()
  1105. {
  1106. $("#reloadPresentationLink").click(function()
  1107. {
  1108. Prezi.reloadPresentation();
  1109. });
  1110. }
  1111. function setupChat()
  1112. {
  1113. Chat.init();
  1114. $("#toggle_smileys").click(function() {
  1115. Chat.toggleSmileys();
  1116. });
  1117. }
  1118. function setupToolbars() {
  1119. Toolbar.init(UI);
  1120. Toolbar.setupButtonsFromConfig();
  1121. BottomToolbar.init();
  1122. }
  1123. function streamHandler(stream) {
  1124. switch (stream.type)
  1125. {
  1126. case "audio":
  1127. VideoLayout.changeLocalAudio(stream);
  1128. break;
  1129. case "video":
  1130. VideoLayout.changeLocalVideo(stream);
  1131. break;
  1132. case "stream":
  1133. VideoLayout.changeLocalStream(stream);
  1134. break;
  1135. }
  1136. }
  1137. function onDisposeConference(unload) {
  1138. Toolbar.showAuthenticateButton(false);
  1139. };
  1140. function onDisplayNameChanged(jid, displayName) {
  1141. ContactList.onDisplayNameChange(jid, displayName);
  1142. SettingsMenu.onDisplayNameChange(jid, displayName);
  1143. VideoLayout.onDisplayNameChanged(jid, displayName);
  1144. }
  1145. function registerListeners() {
  1146. APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
  1147. APP.RTC.addStreamListener(streamHandler, StreamEventTypes.EVENT_TYPE_LOCAL_CHANGED);
  1148. APP.RTC.addStreamListener(function (stream) {
  1149. VideoLayout.onRemoteStreamAdded(stream);
  1150. }, StreamEventTypes.EVENT_TYPE_REMOTE_CREATED);
  1151. APP.RTC.addListener(RTCEvents.LASTN_CHANGED, onLastNChanged);
  1152. APP.RTC.addListener(RTCEvents.DOMINANTSPEAKER_CHANGED, function (resourceJid) {
  1153. VideoLayout.onDominantSpeakerChanged(resourceJid);
  1154. });
  1155. APP.RTC.addListener(RTCEvents.LASTN_ENDPOINT_CHANGED,
  1156. function (lastNEndpoints, endpointsEnteringLastN, stream) {
  1157. VideoLayout.onLastNEndpointsChanged(lastNEndpoints,
  1158. endpointsEnteringLastN, stream);
  1159. });
  1160. APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGED,
  1161. function (endpointSimulcastLayers) {
  1162. VideoLayout.onSimulcastLayersChanged(endpointSimulcastLayers);
  1163. });
  1164. APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGING,
  1165. function (endpointSimulcastLayers) {
  1166. VideoLayout.onSimulcastLayersChanging(endpointSimulcastLayers);
  1167. });
  1168. VideoLayout.init(eventEmitter);
  1169. APP.statistics.addAudioLevelListener(function(jid, audioLevel)
  1170. {
  1171. var resourceJid;
  1172. if(jid === APP.statistics.LOCAL_JID)
  1173. {
  1174. resourceJid = AudioLevels.LOCAL_LEVEL;
  1175. if(APP.RTC.localAudio.isMuted())
  1176. {
  1177. audioLevel = 0;
  1178. }
  1179. }
  1180. else
  1181. {
  1182. resourceJid = Strophe.getResourceFromJid(jid);
  1183. }
  1184. AudioLevels.updateAudioLevel(resourceJid, audioLevel,
  1185. UI.getLargeVideoState().userResourceJid);
  1186. });
  1187. APP.desktopsharing.addListener(function () {
  1188. ToolbarToggler.showDesktopSharingButton();
  1189. }, DesktopSharingEventTypes.INIT);
  1190. APP.desktopsharing.addListener(
  1191. Toolbar.changeDesktopSharingButtonState,
  1192. DesktopSharingEventTypes.SWITCHING_DONE);
  1193. APP.connectionquality.addListener(CQEvents.LOCALSTATS_UPDATED,
  1194. VideoLayout.updateLocalConnectionStats);
  1195. APP.connectionquality.addListener(CQEvents.REMOTESTATS_UPDATED,
  1196. VideoLayout.updateConnectionStats);
  1197. APP.connectionquality.addListener(CQEvents.STOP,
  1198. VideoLayout.onStatsStop);
  1199. APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
  1200. APP.xmpp.addListener(XMPPEvents.KICKED, function () {
  1201. messageHandler.openMessageDialog("Session Terminated",
  1202. "Ouch! You have been kicked out of the meet!");
  1203. });
  1204. APP.xmpp.addListener(XMPPEvents.BRIDGE_DOWN, function () {
  1205. messageHandler.showError("Error",
  1206. "Jitsi Videobridge is currently unavailable. Please try again later!");
  1207. });
  1208. APP.xmpp.addListener(XMPPEvents.USER_ID_CHANGED, function (from, id) {
  1209. Avatar.setUserAvatar(from, id);
  1210. });
  1211. APP.xmpp.addListener(XMPPEvents.CHANGED_STREAMS, function (jid, changedStreams) {
  1212. for(stream in changedStreams)
  1213. {
  1214. // might need to update the direction if participant just went from sendrecv to recvonly
  1215. if (stream.type === 'video' || stream.type === 'screen') {
  1216. var el = $('#participant_' + Strophe.getResourceFromJid(jid) + '>video');
  1217. switch (stream.direction) {
  1218. case 'sendrecv':
  1219. el.show();
  1220. break;
  1221. case 'recvonly':
  1222. el.hide();
  1223. // FIXME: Check if we have to change large video
  1224. //VideoLayout.updateLargeVideo(el);
  1225. break;
  1226. }
  1227. }
  1228. }
  1229. });
  1230. APP.xmpp.addListener(XMPPEvents.DISPLAY_NAME_CHANGED, onDisplayNameChanged);
  1231. APP.xmpp.addListener(XMPPEvents.MUC_JOINED, onMucJoined);
  1232. APP.xmpp.addListener(XMPPEvents.LOCALROLE_CHANGED, onLocalRoleChange);
  1233. APP.xmpp.addListener(XMPPEvents.MUC_ENTER, onMucEntered);
  1234. APP.xmpp.addListener(XMPPEvents.MUC_ROLE_CHANGED, onMucRoleChanged);
  1235. APP.xmpp.addListener(XMPPEvents.PRESENCE_STATUS, onMucPresenceStatus);
  1236. APP.xmpp.addListener(XMPPEvents.SUBJECT_CHANGED, chatSetSubject);
  1237. APP.xmpp.addListener(XMPPEvents.MESSAGE_RECEIVED, updateChatConversation);
  1238. APP.xmpp.addListener(XMPPEvents.MUC_LEFT, onMucLeft);
  1239. APP.xmpp.addListener(XMPPEvents.PASSWORD_REQUIRED, onPasswordReqiured);
  1240. APP.xmpp.addListener(XMPPEvents.CHAT_ERROR_RECEIVED, chatAddError);
  1241. APP.xmpp.addListener(XMPPEvents.ETHERPAD, initEtherpad);
  1242. APP.xmpp.addListener(XMPPEvents.AUTHENTICATION_REQUIRED, onAuthenticationRequired);
  1243. }
  1244. /**
  1245. * Mutes/unmutes the local video.
  1246. *
  1247. * @param mute <tt>true</tt> to mute the local video; otherwise, <tt>false</tt>
  1248. * @param options an object which specifies optional arguments such as the
  1249. * <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
  1250. * specifies whether the method was initiated in response to a user command (in
  1251. * contrast to an automatic decision taken by the application logic)
  1252. */
  1253. function setVideoMute(mute, options) {
  1254. APP.xmpp.setVideoMute(
  1255. mute,
  1256. function (mute) {
  1257. var video = $('#video');
  1258. var communicativeClass = "icon-camera";
  1259. var muteClass = "icon-camera icon-camera-disabled";
  1260. if (mute) {
  1261. video.removeClass(communicativeClass);
  1262. video.addClass(muteClass);
  1263. } else {
  1264. video.removeClass(muteClass);
  1265. video.addClass(communicativeClass);
  1266. }
  1267. },
  1268. options);
  1269. }
  1270. function bindEvents()
  1271. {
  1272. /**
  1273. * Resizes and repositions videos in full screen mode.
  1274. */
  1275. $(document).on('webkitfullscreenchange mozfullscreenchange fullscreenchange',
  1276. function () {
  1277. VideoLayout.resizeLargeVideoContainer();
  1278. VideoLayout.positionLarge();
  1279. }
  1280. );
  1281. $(window).resize(function () {
  1282. VideoLayout.resizeLargeVideoContainer();
  1283. VideoLayout.positionLarge();
  1284. });
  1285. }
  1286. UI.start = function (init) {
  1287. document.title = interfaceConfig.APP_NAME;
  1288. if(config.enableWelcomePage && window.location.pathname == "/" &&
  1289. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  1290. {
  1291. $("#videoconference_page").hide();
  1292. var setupWelcomePage = require("./welcome_page/WelcomePage");
  1293. setupWelcomePage();
  1294. return;
  1295. }
  1296. if (interfaceConfig.SHOW_JITSI_WATERMARK) {
  1297. var leftWatermarkDiv
  1298. = $("#largeVideoContainer div[class='watermark leftwatermark']");
  1299. leftWatermarkDiv.css({display: 'block'});
  1300. leftWatermarkDiv.parent().get(0).href
  1301. = interfaceConfig.JITSI_WATERMARK_LINK;
  1302. }
  1303. if (interfaceConfig.SHOW_BRAND_WATERMARK) {
  1304. var rightWatermarkDiv
  1305. = $("#largeVideoContainer div[class='watermark rightwatermark']");
  1306. rightWatermarkDiv.css({display: 'block'});
  1307. rightWatermarkDiv.parent().get(0).href
  1308. = interfaceConfig.BRAND_WATERMARK_LINK;
  1309. rightWatermarkDiv.get(0).style.backgroundImage
  1310. = "url(images/rightwatermark.png)";
  1311. }
  1312. if (interfaceConfig.SHOW_POWERED_BY) {
  1313. $("#largeVideoContainer>a[class='poweredby']").css({display: 'block'});
  1314. }
  1315. $("#welcome_page").hide();
  1316. VideoLayout.resizeLargeVideoContainer();
  1317. $("#videospace").mousemove(function () {
  1318. return ToolbarToggler.showToolbar();
  1319. });
  1320. // Set the defaults for prompt dialogs.
  1321. jQuery.prompt.setDefaults({persistent: false});
  1322. NicknameHandler.init(eventEmitter);
  1323. registerListeners();
  1324. bindEvents();
  1325. setupPrezi();
  1326. setupToolbars();
  1327. setupChat();
  1328. document.title = interfaceConfig.APP_NAME;
  1329. $("#downloadlog").click(function (event) {
  1330. dump(event.target);
  1331. });
  1332. if(config.enableWelcomePage && window.location.pathname == "/" &&
  1333. (!window.localStorage.welcomePageDisabled || window.localStorage.welcomePageDisabled == "false"))
  1334. {
  1335. $("#videoconference_page").hide();
  1336. var setupWelcomePage = require("./welcome_page/WelcomePage");
  1337. setupWelcomePage();
  1338. return;
  1339. }
  1340. $("#welcome_page").hide();
  1341. document.getElementById('largeVideo').volume = 0;
  1342. if (!$('#settings').is(':visible')) {
  1343. console.log('init');
  1344. init();
  1345. } else {
  1346. loginInfo.onsubmit = function (e) {
  1347. if (e.preventDefault) e.preventDefault();
  1348. $('#settings').hide();
  1349. init();
  1350. };
  1351. }
  1352. toastr.options = {
  1353. "closeButton": true,
  1354. "debug": false,
  1355. "positionClass": "notification-bottom-right",
  1356. "onclick": null,
  1357. "showDuration": "300",
  1358. "hideDuration": "1000",
  1359. "timeOut": "2000",
  1360. "extendedTimeOut": "1000",
  1361. "showEasing": "swing",
  1362. "hideEasing": "linear",
  1363. "showMethod": "fadeIn",
  1364. "hideMethod": "fadeOut",
  1365. "reposition": function() {
  1366. if(PanelToggler.isVisible()) {
  1367. $("#toast-container").addClass("notification-bottom-right-center");
  1368. } else {
  1369. $("#toast-container").removeClass("notification-bottom-right-center");
  1370. }
  1371. },
  1372. "newestOnTop": false
  1373. };
  1374. SettingsMenu.init();
  1375. };
  1376. function chatAddError(errorMessage, originalText)
  1377. {
  1378. return Chat.chatAddError(errorMessage, originalText);
  1379. };
  1380. function chatSetSubject(text)
  1381. {
  1382. return Chat.chatSetSubject(text);
  1383. };
  1384. function updateChatConversation(from, displayName, message) {
  1385. return Chat.updateChatConversation(from, displayName, message);
  1386. };
  1387. function onMucJoined(jid, info) {
  1388. Toolbar.updateRoomUrl(window.location.href);
  1389. document.getElementById('localNick').appendChild(
  1390. document.createTextNode(Strophe.getResourceFromJid(jid) + ' (me)')
  1391. );
  1392. var settings = Settings.getSettings();
  1393. // Add myself to the contact list.
  1394. ContactList.addContact(jid, settings.email || settings.uid);
  1395. // Once we've joined the muc show the toolbar
  1396. ToolbarToggler.showToolbar();
  1397. // Show authenticate button if needed
  1398. Toolbar.showAuthenticateButton(
  1399. APP.xmpp.isExternalAuthEnabled() && !APP.xmpp.isModerator());
  1400. var displayName = !config.displayJids
  1401. ? info.displayName : Strophe.getResourceFromJid(jid);
  1402. if (displayName)
  1403. onDisplayNameChanged('localVideoContainer', displayName + ' (me)');
  1404. }
  1405. function initEtherpad(name) {
  1406. Etherpad.init(name);
  1407. };
  1408. function onMucLeft(jid) {
  1409. console.log('left.muc', jid);
  1410. var displayName = $('#participant_' + Strophe.getResourceFromJid(jid) +
  1411. '>.displayname').html();
  1412. messageHandler.notify(displayName || 'Somebody',
  1413. 'disconnected',
  1414. 'disconnected');
  1415. // Need to call this with a slight delay, otherwise the element couldn't be
  1416. // found for some reason.
  1417. // XXX(gp) it works fine without the timeout for me (with Chrome 38).
  1418. window.setTimeout(function () {
  1419. var container = document.getElementById(
  1420. 'participant_' + Strophe.getResourceFromJid(jid));
  1421. if (container) {
  1422. ContactList.removeContact(jid);
  1423. VideoLayout.removeConnectionIndicator(jid);
  1424. // hide here, wait for video to close before removing
  1425. $(container).hide();
  1426. VideoLayout.resizeThumbnails();
  1427. }
  1428. }, 10);
  1429. VideoLayout.participantLeft(jid);
  1430. };
  1431. function onLocalRoleChange(jid, info, pres, isModerator, isExternalAuthEnabled)
  1432. {
  1433. console.info("My role changed, new role: " + info.role);
  1434. onModeratorStatusChanged(isModerator);
  1435. VideoLayout.showModeratorIndicator();
  1436. Toolbar.showAuthenticateButton(
  1437. isExternalAuthEnabled && !isModerator);
  1438. if (isModerator) {
  1439. Authentication.closeAuthenticationWindow();
  1440. messageHandler.notify(
  1441. 'Me', 'connected', 'Moderator rights granted !');
  1442. }
  1443. }
  1444. function onModeratorStatusChanged(isModerator) {
  1445. Toolbar.showSipCallButton(isModerator);
  1446. Toolbar.showRecordingButton(
  1447. isModerator); //&&
  1448. // FIXME:
  1449. // Recording visible if
  1450. // there are at least 2(+ 1 focus) participants
  1451. //Object.keys(connection.emuc.members).length >= 3);
  1452. if (isModerator && config.etherpad_base) {
  1453. Etherpad.init();
  1454. }
  1455. };
  1456. function onPasswordReqiured(callback) {
  1457. // password is required
  1458. Toolbar.lockLockButton();
  1459. messageHandler.openTwoButtonDialog(null,
  1460. '<h2>Password required</h2>' +
  1461. '<input id="lockKey" type="text" placeholder="password" autofocus>',
  1462. true,
  1463. "Ok",
  1464. function (e, v, m, f) {},
  1465. function (event) {
  1466. document.getElementById('lockKey').focus();
  1467. },
  1468. function (e, v, m, f) {
  1469. if (v) {
  1470. var lockKey = document.getElementById('lockKey');
  1471. if (lockKey.value !== null) {
  1472. Toolbar.setSharedKey(lockKey.value);
  1473. callback(lockKey.value);
  1474. }
  1475. }
  1476. }
  1477. );
  1478. }
  1479. function onMucEntered(jid, id, displayName) {
  1480. messageHandler.notify(displayName || 'Somebody',
  1481. 'connected',
  1482. 'connected');
  1483. // Add Peer's container
  1484. VideoLayout.ensurePeerContainerExists(jid,id);
  1485. }
  1486. function onMucPresenceStatus( jid, info) {
  1487. VideoLayout.setPresenceStatus(
  1488. 'participant_' + Strophe.getResourceFromJid(jid), info.status);
  1489. }
  1490. function onMucRoleChanged(role, displayName) {
  1491. VideoLayout.showModeratorIndicator();
  1492. if (role === 'moderator') {
  1493. var displayName = displayName;
  1494. if (!displayName) {
  1495. displayName = 'Somebody';
  1496. }
  1497. messageHandler.notify(
  1498. displayName,
  1499. 'connected',
  1500. 'Moderator rights granted to ' + displayName + '!');
  1501. }
  1502. }
  1503. function onAuthenticationRequired(intervalCallback) {
  1504. Authentication.openAuthenticationDialog(
  1505. roomName, intervalCallback, function () {
  1506. Toolbar.authenticateClicked();
  1507. });
  1508. };
  1509. function onLastNChanged(oldValue, newValue) {
  1510. if (config.muteLocalVideoIfNotInLastN) {
  1511. setVideoMute(!newValue, { 'byUser': false });
  1512. }
  1513. }
  1514. UI.toggleSmileys = function () {
  1515. Chat.toggleSmileys();
  1516. };
  1517. UI.getSettings = function () {
  1518. return Settings.getSettings();
  1519. };
  1520. UI.toggleFilmStrip = function () {
  1521. return BottomToolbar.toggleFilmStrip();
  1522. };
  1523. UI.toggleChat = function () {
  1524. return BottomToolbar.toggleChat();
  1525. };
  1526. UI.toggleContactList = function () {
  1527. return BottomToolbar.toggleContactList();
  1528. };
  1529. UI.inputDisplayNameHandler = function (value) {
  1530. VideoLayout.inputDisplayNameHandler(value);
  1531. };
  1532. UI.getLargeVideoState = function()
  1533. {
  1534. return VideoLayout.getLargeVideoState();
  1535. };
  1536. UI.generateRoomName = function() {
  1537. if(roomName)
  1538. return roomName;
  1539. var roomnode = null;
  1540. var path = window.location.pathname;
  1541. // determinde the room node from the url
  1542. // TODO: just the roomnode or the whole bare jid?
  1543. if (config.getroomnode && typeof config.getroomnode === 'function') {
  1544. // custom function might be responsible for doing the pushstate
  1545. roomnode = config.getroomnode(path);
  1546. } else {
  1547. /* fall back to default strategy
  1548. * this is making assumptions about how the URL->room mapping happens.
  1549. * It currently assumes deployment at root, with a rewrite like the
  1550. * following one (for nginx):
  1551. location ~ ^/([a-zA-Z0-9]+)$ {
  1552. rewrite ^/(.*)$ / break;
  1553. }
  1554. */
  1555. if (path.length > 1) {
  1556. roomnode = path.substr(1).toLowerCase();
  1557. } else {
  1558. var word = RoomNameGenerator.generateRoomWithoutSeparator();
  1559. roomnode = word.toLowerCase();
  1560. window.history.pushState('VideoChat',
  1561. 'Room: ' + word, window.location.pathname + word);
  1562. }
  1563. }
  1564. roomName = roomnode + '@' + config.hosts.muc;
  1565. return roomName;
  1566. };
  1567. UI.connectionIndicatorShowMore = function(id)
  1568. {
  1569. return VideoLayout.connectionIndicators[id].showMore();
  1570. };
  1571. UI.getCredentials = function () {
  1572. var settings = this.getSettings();
  1573. return {
  1574. bosh: document.getElementById('boshURL').value,
  1575. password: document.getElementById('password').value,
  1576. jid: document.getElementById('jid').value,
  1577. email: settings.email,
  1578. displayName: settings.displayName,
  1579. uid: settings.uid
  1580. };
  1581. };
  1582. UI.disableConnect = function () {
  1583. document.getElementById('connect').disabled = true;
  1584. };
  1585. UI.showLoginPopup = function(callback)
  1586. {
  1587. console.log('password is required');
  1588. UI.messageHandler.openTwoButtonDialog(null,
  1589. '<h2>Password required</h2>' +
  1590. '<input id="passwordrequired.username" type="text" placeholder="user@domain.net" autofocus>' +
  1591. '<input id="passwordrequired.password" type="password" placeholder="user password">',
  1592. true,
  1593. "Ok",
  1594. function (e, v, m, f) {
  1595. if (v) {
  1596. var username = document.getElementById('passwordrequired.username');
  1597. var password = document.getElementById('passwordrequired.password');
  1598. if (username.value !== null && password.value != null) {
  1599. callback(username.value, password.value);
  1600. }
  1601. }
  1602. },
  1603. function (event) {
  1604. document.getElementById('passwordrequired.username').focus();
  1605. }
  1606. );
  1607. }
  1608. UI.checkForNicknameAndJoin = function () {
  1609. Authentication.closeAuthenticationDialog();
  1610. Authentication.stopInterval();
  1611. var nick = null;
  1612. if (config.useNicks) {
  1613. nick = window.prompt('Your nickname (optional)');
  1614. }
  1615. APP.xmpp.joinRoom(roomName, config.useNicks, nick);
  1616. };
  1617. function dump(elem, filename) {
  1618. elem = elem.parentNode;
  1619. elem.download = filename || 'meetlog.json';
  1620. elem.href = 'data:application/json;charset=utf-8,\n';
  1621. var data = APP.xmpp.populateData();
  1622. var metadata = {};
  1623. metadata.time = new Date();
  1624. metadata.url = window.location.href;
  1625. metadata.ua = navigator.userAgent;
  1626. var log = APP.xmpp.getLogger();
  1627. if (log) {
  1628. metadata.xmpp = log;
  1629. }
  1630. data.metadata = metadata;
  1631. elem.href += encodeURIComponent(JSON.stringify(data, null, ' '));
  1632. return false;
  1633. }
  1634. UI.getRoomName = function () {
  1635. return roomName;
  1636. };
  1637. /**
  1638. * Mutes/unmutes the local video.
  1639. */
  1640. UI.toggleVideo = function () {
  1641. UIUtil.buttonClick("#video", "icon-camera icon-camera-disabled");
  1642. setVideoMute(!APP.RTC.localVideo.isMuted());
  1643. };
  1644. /**
  1645. * Mutes / unmutes audio for the local participant.
  1646. */
  1647. UI.toggleAudio = function() {
  1648. UI.setAudioMuted(!APP.RTC.localAudio.isMuted());
  1649. };
  1650. /**
  1651. * Sets muted audio state for the local participant.
  1652. */
  1653. UI.setAudioMuted = function (mute) {
  1654. if(!APP.xmpp.setAudioMute(mute, function () {
  1655. VideoLayout.showLocalAudioIndicator(mute);
  1656. UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
  1657. }))
  1658. {
  1659. // We still click the button.
  1660. UIUtil.buttonClick("#mute", "icon-microphone icon-mic-disabled");
  1661. return;
  1662. }
  1663. }
  1664. UI.addListener = function (type, listener) {
  1665. eventEmitter.on(type, listener);
  1666. }
  1667. UI.clickOnVideo = function (videoNumber) {
  1668. var remoteVideos = $(".videocontainer:not(#mixedstream)");
  1669. if (remoteVideos.length > videoNumber) {
  1670. remoteVideos[videoNumber].click();
  1671. }
  1672. }
  1673. //Used by torture
  1674. UI.showToolbar = function () {
  1675. return ToolbarToggler.showToolbar();
  1676. }
  1677. //Used by torture
  1678. UI.dockToolbar = function (isDock) {
  1679. return ToolbarToggler.dockToolbar(isDock);
  1680. }
  1681. module.exports = UI;
  1682. },{"../../service/RTC/RTCEvents":80,"../../service/RTC/StreamEventTypes":81,"../../service/connectionquality/CQEvents":83,"../../service/desktopsharing/DesktopSharingEventTypes":84,"../../service/xmpp/XMPPEvents":86,"./audio_levels/AudioLevels.js":9,"./authentication/Authentication":11,"./avatar/Avatar":12,"./etherpad/Etherpad.js":13,"./prezi/Prezi.js":14,"./side_pannels/SidePanelToggler":16,"./side_pannels/chat/Chat.js":17,"./side_pannels/contactlist/ContactList":21,"./side_pannels/settings/Settings":22,"./side_pannels/settings/SettingsMenu":23,"./toolbars/BottomToolbar":24,"./toolbars/Toolbar":25,"./toolbars/ToolbarToggler":26,"./util/MessageHandler":28,"./util/NicknameHandler":29,"./util/UIUtil":30,"./videolayout/VideoLayout.js":32,"./welcome_page/RoomnameGenerator":33,"./welcome_page/WelcomePage":34,"events":87}],9:[function(require,module,exports){
  1683. var CanvasUtil = require("./CanvasUtils");
  1684. /**
  1685. * The audio Levels plugin.
  1686. */
  1687. var AudioLevels = (function(my) {
  1688. var audioLevelCanvasCache = {};
  1689. my.LOCAL_LEVEL = 'local';
  1690. /**
  1691. * Updates the audio level canvas for the given peerJid. If the canvas
  1692. * didn't exist we create it.
  1693. */
  1694. my.updateAudioLevelCanvas = function (peerJid, VideoLayout) {
  1695. var resourceJid = null;
  1696. var videoSpanId = null;
  1697. if (!peerJid)
  1698. videoSpanId = 'localVideoContainer';
  1699. else {
  1700. resourceJid = Strophe.getResourceFromJid(peerJid);
  1701. videoSpanId = 'participant_' + resourceJid;
  1702. }
  1703. var videoSpan = document.getElementById(videoSpanId);
  1704. if (!videoSpan) {
  1705. if (resourceJid)
  1706. console.error("No video element for jid", resourceJid);
  1707. else
  1708. console.error("No video element for local video.");
  1709. return;
  1710. }
  1711. var audioLevelCanvas = $('#' + videoSpanId + '>canvas');
  1712. var videoSpaceWidth = $('#remoteVideos').width();
  1713. var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
  1714. var thumbnailWidth = thumbnailSize[0];
  1715. var thumbnailHeight = thumbnailSize[1];
  1716. if (!audioLevelCanvas || audioLevelCanvas.length === 0) {
  1717. audioLevelCanvas = document.createElement('canvas');
  1718. audioLevelCanvas.className = "audiolevel";
  1719. audioLevelCanvas.style.bottom = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
  1720. audioLevelCanvas.style.left = "-" + interfaceConfig.CANVAS_EXTRA/2 + "px";
  1721. resizeAudioLevelCanvas( audioLevelCanvas,
  1722. thumbnailWidth,
  1723. thumbnailHeight);
  1724. videoSpan.appendChild(audioLevelCanvas);
  1725. } else {
  1726. audioLevelCanvas = audioLevelCanvas.get(0);
  1727. resizeAudioLevelCanvas( audioLevelCanvas,
  1728. thumbnailWidth,
  1729. thumbnailHeight);
  1730. }
  1731. };
  1732. /**
  1733. * Updates the audio level UI for the given resourceJid.
  1734. *
  1735. * @param resourceJid the resource jid indicating the video element for
  1736. * which we draw the audio level
  1737. * @param audioLevel the newAudio level to render
  1738. */
  1739. my.updateAudioLevel = function (resourceJid, audioLevel, largeVideoResourceJid) {
  1740. drawAudioLevelCanvas(resourceJid, audioLevel);
  1741. var videoSpanId = getVideoSpanId(resourceJid);
  1742. var audioLevelCanvas = $('#' + videoSpanId + '>canvas').get(0);
  1743. if (!audioLevelCanvas)
  1744. return;
  1745. var drawContext = audioLevelCanvas.getContext('2d');
  1746. var canvasCache = audioLevelCanvasCache[resourceJid];
  1747. drawContext.clearRect (0, 0,
  1748. audioLevelCanvas.width, audioLevelCanvas.height);
  1749. drawContext.drawImage(canvasCache, 0, 0);
  1750. if(resourceJid === AudioLevels.LOCAL_LEVEL) {
  1751. if(!APP.xmpp.myJid()) {
  1752. return;
  1753. }
  1754. resourceJid = APP.xmpp.myResource();
  1755. }
  1756. if(resourceJid === largeVideoResourceJid) {
  1757. AudioLevels.updateActiveSpeakerAudioLevel(audioLevel);
  1758. }
  1759. };
  1760. my.updateActiveSpeakerAudioLevel = function(audioLevel) {
  1761. var drawContext = $('#activeSpeakerAudioLevel')[0].getContext('2d');
  1762. var r = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE / 2;
  1763. var center = (interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE + r) / 2;
  1764. // Save the previous state of the context.
  1765. drawContext.save();
  1766. drawContext.clearRect(0, 0, 300, 300);
  1767. // Draw a circle.
  1768. drawContext.arc(center, center, r, 0, 2 * Math.PI);
  1769. // Add a shadow around the circle
  1770. drawContext.shadowColor = interfaceConfig.SHADOW_COLOR;
  1771. drawContext.shadowBlur = getShadowLevel(audioLevel);
  1772. drawContext.shadowOffsetX = 0;
  1773. drawContext.shadowOffsetY = 0;
  1774. // Fill the shape.
  1775. drawContext.fill();
  1776. drawContext.save();
  1777. drawContext.restore();
  1778. drawContext.arc(center, center, r, 0, 2 * Math.PI);
  1779. drawContext.clip();
  1780. drawContext.clearRect(0, 0, 277, 200);
  1781. // Restore the previous context state.
  1782. drawContext.restore();
  1783. };
  1784. /**
  1785. * Resizes the given audio level canvas to match the given thumbnail size.
  1786. */
  1787. function resizeAudioLevelCanvas(audioLevelCanvas,
  1788. thumbnailWidth,
  1789. thumbnailHeight) {
  1790. audioLevelCanvas.width = thumbnailWidth + interfaceConfig.CANVAS_EXTRA;
  1791. audioLevelCanvas.height = thumbnailHeight + interfaceConfig.CANVAS_EXTRA;
  1792. }
  1793. /**
  1794. * Draws the audio level canvas into the cached canvas object.
  1795. *
  1796. * @param resourceJid the resource jid indicating the video element for
  1797. * which we draw the audio level
  1798. * @param audioLevel the newAudio level to render
  1799. */
  1800. function drawAudioLevelCanvas(resourceJid, audioLevel) {
  1801. if (!audioLevelCanvasCache[resourceJid]) {
  1802. var videoSpanId = getVideoSpanId(resourceJid);
  1803. var audioLevelCanvasOrig = $('#' + videoSpanId + '>canvas').get(0);
  1804. /*
  1805. * FIXME Testing has shown that audioLevelCanvasOrig may not exist.
  1806. * In such a case, the method CanvasUtil.cloneCanvas may throw an
  1807. * error. Since audio levels are frequently updated, the errors have
  1808. * been observed to pile into the console, strain the CPU.
  1809. */
  1810. if (audioLevelCanvasOrig)
  1811. {
  1812. audioLevelCanvasCache[resourceJid]
  1813. = CanvasUtil.cloneCanvas(audioLevelCanvasOrig);
  1814. }
  1815. }
  1816. var canvas = audioLevelCanvasCache[resourceJid];
  1817. if (!canvas)
  1818. return;
  1819. var drawContext = canvas.getContext('2d');
  1820. drawContext.clearRect(0, 0, canvas.width, canvas.height);
  1821. var shadowLevel = getShadowLevel(audioLevel);
  1822. if (shadowLevel > 0)
  1823. // drawContext, x, y, w, h, r, shadowColor, shadowLevel
  1824. CanvasUtil.drawRoundRectGlow( drawContext,
  1825. interfaceConfig.CANVAS_EXTRA/2, interfaceConfig.CANVAS_EXTRA/2,
  1826. canvas.width - interfaceConfig.CANVAS_EXTRA,
  1827. canvas.height - interfaceConfig.CANVAS_EXTRA,
  1828. interfaceConfig.CANVAS_RADIUS,
  1829. interfaceConfig.SHADOW_COLOR,
  1830. shadowLevel);
  1831. }
  1832. /**
  1833. * Returns the shadow/glow level for the given audio level.
  1834. *
  1835. * @param audioLevel the audio level from which we determine the shadow
  1836. * level
  1837. */
  1838. function getShadowLevel (audioLevel) {
  1839. var shadowLevel = 0;
  1840. if (audioLevel <= 0.3) {
  1841. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*(audioLevel/0.3));
  1842. }
  1843. else if (audioLevel <= 0.6) {
  1844. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.3) / 0.3));
  1845. }
  1846. else {
  1847. shadowLevel = Math.round(interfaceConfig.CANVAS_EXTRA/2*((audioLevel - 0.6) / 0.4));
  1848. }
  1849. return shadowLevel;
  1850. }
  1851. /**
  1852. * Returns the video span id corresponding to the given resourceJid or local
  1853. * user.
  1854. */
  1855. function getVideoSpanId(resourceJid) {
  1856. var videoSpanId = null;
  1857. if (resourceJid === AudioLevels.LOCAL_LEVEL
  1858. || (APP.xmpp.myResource() && resourceJid
  1859. === APP.xmpp.myResource()))
  1860. videoSpanId = 'localVideoContainer';
  1861. else
  1862. videoSpanId = 'participant_' + resourceJid;
  1863. return videoSpanId;
  1864. }
  1865. /**
  1866. * Indicates that the remote video has been resized.
  1867. */
  1868. $(document).bind('remotevideo.resized', function (event, width, height) {
  1869. var resized = false;
  1870. $('#remoteVideos>span>canvas').each(function() {
  1871. var canvas = $(this).get(0);
  1872. if (canvas.width !== width + interfaceConfig.CANVAS_EXTRA) {
  1873. canvas.width = width + interfaceConfig.CANVAS_EXTRA;
  1874. resized = true;
  1875. }
  1876. if (canvas.heigh !== height + interfaceConfig.CANVAS_EXTRA) {
  1877. canvas.height = height + interfaceConfig.CANVAS_EXTRA;
  1878. resized = true;
  1879. }
  1880. });
  1881. if (resized)
  1882. Object.keys(audioLevelCanvasCache).forEach(function (resourceJid) {
  1883. audioLevelCanvasCache[resourceJid].width
  1884. = width + interfaceConfig.CANVAS_EXTRA;
  1885. audioLevelCanvasCache[resourceJid].height
  1886. = height + interfaceConfig.CANVAS_EXTRA;
  1887. });
  1888. });
  1889. return my;
  1890. })(AudioLevels || {});
  1891. module.exports = AudioLevels;
  1892. },{"./CanvasUtils":10}],10:[function(require,module,exports){
  1893. /**
  1894. * Utility class for drawing canvas shapes.
  1895. */
  1896. var CanvasUtil = (function(my) {
  1897. /**
  1898. * Draws a round rectangle with a glow. The glowWidth indicates the depth
  1899. * of the glow.
  1900. *
  1901. * @param drawContext the context of the canvas to draw to
  1902. * @param x the x coordinate of the round rectangle
  1903. * @param y the y coordinate of the round rectangle
  1904. * @param w the width of the round rectangle
  1905. * @param h the height of the round rectangle
  1906. * @param glowColor the color of the glow
  1907. * @param glowWidth the width of the glow
  1908. */
  1909. my.drawRoundRectGlow
  1910. = function(drawContext, x, y, w, h, r, glowColor, glowWidth) {
  1911. // Save the previous state of the context.
  1912. drawContext.save();
  1913. if (w < 2 * r) r = w / 2;
  1914. if (h < 2 * r) r = h / 2;
  1915. // Draw a round rectangle.
  1916. drawContext.beginPath();
  1917. drawContext.moveTo(x+r, y);
  1918. drawContext.arcTo(x+w, y, x+w, y+h, r);
  1919. drawContext.arcTo(x+w, y+h, x, y+h, r);
  1920. drawContext.arcTo(x, y+h, x, y, r);
  1921. drawContext.arcTo(x, y, x+w, y, r);
  1922. drawContext.closePath();
  1923. // Add a shadow around the rectangle
  1924. drawContext.shadowColor = glowColor;
  1925. drawContext.shadowBlur = glowWidth;
  1926. drawContext.shadowOffsetX = 0;
  1927. drawContext.shadowOffsetY = 0;
  1928. // Fill the shape.
  1929. drawContext.fill();
  1930. drawContext.save();
  1931. drawContext.restore();
  1932. // 1) Uncomment this line to use Composite Operation, which is doing the
  1933. // same as the clip function below and is also antialiasing the round
  1934. // border, but is said to be less fast performance wise.
  1935. // drawContext.globalCompositeOperation='destination-out';
  1936. drawContext.beginPath();
  1937. drawContext.moveTo(x+r, y);
  1938. drawContext.arcTo(x+w, y, x+w, y+h, r);
  1939. drawContext.arcTo(x+w, y+h, x, y+h, r);
  1940. drawContext.arcTo(x, y+h, x, y, r);
  1941. drawContext.arcTo(x, y, x+w, y, r);
  1942. drawContext.closePath();
  1943. // 2) Uncomment this line to use Composite Operation, which is doing the
  1944. // same as the clip function below and is also antialiasing the round
  1945. // border, but is said to be less fast performance wise.
  1946. // drawContext.fill();
  1947. // Comment these two lines if choosing to do the same with composite
  1948. // operation above 1 and 2.
  1949. drawContext.clip();
  1950. drawContext.clearRect(0, 0, 277, 200);
  1951. // Restore the previous context state.
  1952. drawContext.restore();
  1953. };
  1954. /**
  1955. * Clones the given canvas.
  1956. *
  1957. * @return the new cloned canvas.
  1958. */
  1959. my.cloneCanvas = function (oldCanvas) {
  1960. /*
  1961. * FIXME Testing has shown that oldCanvas may not exist. In such a case,
  1962. * the method CanvasUtil.cloneCanvas may throw an error. Since audio
  1963. * levels are frequently updated, the errors have been observed to pile
  1964. * into the console, strain the CPU.
  1965. */
  1966. if (!oldCanvas)
  1967. return oldCanvas;
  1968. //create a new canvas
  1969. var newCanvas = document.createElement('canvas');
  1970. var context = newCanvas.getContext('2d');
  1971. //set dimensions
  1972. newCanvas.width = oldCanvas.width;
  1973. newCanvas.height = oldCanvas.height;
  1974. //apply the old canvas to the new one
  1975. context.drawImage(oldCanvas, 0, 0);
  1976. //return the new canvas
  1977. return newCanvas;
  1978. };
  1979. return my;
  1980. })(CanvasUtil || {});
  1981. module.exports = CanvasUtil;
  1982. },{}],11:[function(require,module,exports){
  1983. /* Initial "authentication required" dialog */
  1984. var authDialog = null;
  1985. /* Loop retry ID that wits for other user to create the room */
  1986. var authRetryId = null;
  1987. var authenticationWindow = null;
  1988. var Authentication = {
  1989. openAuthenticationDialog: function (roomName, intervalCallback, callback) {
  1990. // This is the loop that will wait for the room to be created by
  1991. // someone else. 'auth_required.moderator' will bring us back here.
  1992. authRetryId = window.setTimeout(intervalCallback , 5000);
  1993. // Show prompt only if it's not open
  1994. if (authDialog !== null) {
  1995. return;
  1996. }
  1997. // extract room name from 'room@muc.server.net'
  1998. var room = roomName.substr(0, roomName.indexOf('@'));
  1999. authDialog = messageHandler.openDialog(
  2000. 'Stop',
  2001. 'Authentication is required to create room:<br/><b>' + room +
  2002. '</b></br> You can either authenticate to create the room or ' +
  2003. 'just wait for someone else to do so.',
  2004. true,
  2005. {
  2006. Authenticate: 'authNow'
  2007. },
  2008. function (onSubmitEvent, submitValue) {
  2009. // Do not close the dialog yet
  2010. onSubmitEvent.preventDefault();
  2011. // Open login popup
  2012. if (submitValue === 'authNow') {
  2013. callback();
  2014. }
  2015. }
  2016. );
  2017. },
  2018. closeAuthenticationWindow:function () {
  2019. if (authenticationWindow) {
  2020. authenticationWindow.close();
  2021. authenticationWindow = null;
  2022. }
  2023. },
  2024. focusAuthenticationWindow: function () {
  2025. // If auth window exists just bring it to the front
  2026. if (authenticationWindow) {
  2027. authenticationWindow.focus();
  2028. return;
  2029. }
  2030. },
  2031. closeAuthenticationDialog: function () {
  2032. // Close authentication dialog if opened
  2033. if (authDialog) {
  2034. APP.UI.messageHandler.closeDialog();
  2035. authDialog = null;
  2036. }
  2037. },
  2038. createAuthenticationWindow: function (callback, url) {
  2039. authenticationWindow = messageHandler.openCenteredPopup(
  2040. url, 910, 660,
  2041. // On closed
  2042. function () {
  2043. // Close authentication dialog if opened
  2044. if (authDialog) {
  2045. messageHandler.closeDialog();
  2046. authDialog = null;
  2047. }
  2048. callback();
  2049. authenticationWindow = null;
  2050. });
  2051. return authenticationWindow;
  2052. },
  2053. stopInterval: function () {
  2054. // Clear retry interval, so that we don't call 'doJoinAfterFocus' twice
  2055. if (authRetryId) {
  2056. window.clearTimeout(authRetryId);
  2057. authRetryId = null;
  2058. }
  2059. }
  2060. };
  2061. module.exports = Authentication;
  2062. },{}],12:[function(require,module,exports){
  2063. var Settings = require("../side_pannels/settings/Settings");
  2064. var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
  2065. var users = {};
  2066. var activeSpeakerJid;
  2067. function setVisibility(selector, show) {
  2068. if (selector && selector.length > 0) {
  2069. selector.css("visibility", show ? "visible" : "hidden");
  2070. }
  2071. }
  2072. function isUserMuted(jid) {
  2073. // XXX(gp) we may want to rename this method to something like
  2074. // isUserStreaming, for example.
  2075. if (jid && jid != APP.xmpp.myJid()) {
  2076. var resource = Strophe.getResourceFromJid(jid);
  2077. if (!require("../videolayout/VideoLayout").isInLastN(resource)) {
  2078. return true;
  2079. }
  2080. }
  2081. if (!APP.RTC.remoteStreams[jid] || !APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE]) {
  2082. return null;
  2083. }
  2084. return APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE].muted;
  2085. }
  2086. function getGravatarUrl(id, size) {
  2087. if(id === APP.xmpp.myJid() || !id) {
  2088. id = Settings.getSettings().uid;
  2089. }
  2090. return 'https://www.gravatar.com/avatar/' +
  2091. MD5.hexdigest(id.trim().toLowerCase()) +
  2092. "?d=wavatar&size=" + (size || "30");
  2093. }
  2094. var Avatar = {
  2095. /**
  2096. * Sets the user's avatar in the settings menu(if local user), contact list
  2097. * and thumbnail
  2098. * @param jid jid of the user
  2099. * @param id email or userID to be used as a hash
  2100. */
  2101. setUserAvatar: function (jid, id) {
  2102. if (id) {
  2103. if (users[jid] === id) {
  2104. return;
  2105. }
  2106. users[jid] = id;
  2107. }
  2108. var thumbUrl = getGravatarUrl(users[jid] || jid, 100);
  2109. var contactListUrl = getGravatarUrl(users[jid] || jid);
  2110. var resourceJid = Strophe.getResourceFromJid(jid);
  2111. var thumbnail = $('#participant_' + resourceJid);
  2112. var avatar = $('#avatar_' + resourceJid);
  2113. // set the avatar in the settings menu if it is local user and get the
  2114. // local video container
  2115. if (jid === APP.xmpp.myJid()) {
  2116. $('#avatar').get(0).src = thumbUrl;
  2117. thumbnail = $('#localVideoContainer');
  2118. }
  2119. // set the avatar in the contact list
  2120. var contact = $('#' + resourceJid + '>img');
  2121. if (contact && contact.length > 0) {
  2122. contact.get(0).src = contactListUrl;
  2123. }
  2124. // set the avatar in the thumbnail
  2125. if (avatar && avatar.length > 0) {
  2126. avatar[0].src = thumbUrl;
  2127. } else {
  2128. if (thumbnail && thumbnail.length > 0) {
  2129. avatar = document.createElement('img');
  2130. avatar.id = 'avatar_' + resourceJid;
  2131. avatar.className = 'userAvatar';
  2132. avatar.src = thumbUrl;
  2133. thumbnail.append(avatar);
  2134. }
  2135. }
  2136. //if the user is the current active speaker - update the active speaker
  2137. // avatar
  2138. if (jid === activeSpeakerJid) {
  2139. this.updateActiveSpeakerAvatarSrc(jid);
  2140. }
  2141. },
  2142. /**
  2143. * Hides or shows the user's avatar
  2144. * @param jid jid of the user
  2145. * @param show whether we should show the avatar or not
  2146. * video because there is no dominant speaker and no focused speaker
  2147. */
  2148. showUserAvatar: function (jid, show) {
  2149. if (users[jid]) {
  2150. var resourceJid = Strophe.getResourceFromJid(jid);
  2151. var video = $('#participant_' + resourceJid + '>video');
  2152. var avatar = $('#avatar_' + resourceJid);
  2153. if (jid === APP.xmpp.myJid()) {
  2154. video = $('#localVideoWrapper>video');
  2155. }
  2156. if (show === undefined || show === null) {
  2157. show = isUserMuted(jid);
  2158. }
  2159. //if the user is the currently focused, the dominant speaker or if
  2160. //there is no focused and no dominant speaker and the large video is
  2161. //currently shown
  2162. if (activeSpeakerJid === jid && require("../videolayout/VideoLayout").isLargeVideoOnTop()) {
  2163. setVisibility($("#largeVideo"), !show);
  2164. setVisibility($('#activeSpeaker'), show);
  2165. setVisibility(avatar, false);
  2166. setVisibility(video, false);
  2167. } else {
  2168. if (video && video.length > 0) {
  2169. setVisibility(video, !show);
  2170. setVisibility(avatar, show);
  2171. }
  2172. }
  2173. }
  2174. },
  2175. /**
  2176. * Updates the src of the active speaker avatar
  2177. * @param jid of the current active speaker
  2178. */
  2179. updateActiveSpeakerAvatarSrc: function (jid) {
  2180. if (!jid) {
  2181. jid = APP.xmpp.findJidFromResource(
  2182. require("../videolayout/VideoLayout").getLargeVideoState().userResourceJid);
  2183. }
  2184. var avatar = $("#activeSpeakerAvatar")[0];
  2185. var url = getGravatarUrl(users[jid],
  2186. interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE);
  2187. if (jid === activeSpeakerJid && avatar.src === url) {
  2188. return;
  2189. }
  2190. activeSpeakerJid = jid;
  2191. var isMuted = isUserMuted(jid);
  2192. if (jid && isMuted !== null) {
  2193. avatar.src = url;
  2194. setVisibility($("#largeVideo"), !isMuted);
  2195. Avatar.showUserAvatar(jid, isMuted);
  2196. }
  2197. }
  2198. };
  2199. module.exports = Avatar;
  2200. },{"../../../service/RTC/MediaStreamTypes":78,"../side_pannels/settings/Settings":22,"../videolayout/VideoLayout":32}],13:[function(require,module,exports){
  2201. /* global $, config,
  2202. setLargeVideoVisible, Util */
  2203. var VideoLayout = require("../videolayout/VideoLayout");
  2204. var Prezi = require("../prezi/Prezi");
  2205. var UIUtil = require("../util/UIUtil");
  2206. var etherpadName = null;
  2207. var etherpadIFrame = null;
  2208. var domain = null;
  2209. var options = "?showControls=true&showChat=false&showLineNumbers=true&useMonospaceFont=false";
  2210. /**
  2211. * Resizes the etherpad.
  2212. */
  2213. function resize() {
  2214. if ($('#etherpad>iframe').length) {
  2215. var remoteVideos = $('#remoteVideos');
  2216. var availableHeight
  2217. = window.innerHeight - remoteVideos.outerHeight();
  2218. var availableWidth = UIUtil.getAvailableVideoWidth();
  2219. $('#etherpad>iframe').width(availableWidth);
  2220. $('#etherpad>iframe').height(availableHeight);
  2221. }
  2222. }
  2223. /**
  2224. * Shares the Etherpad name with other participants.
  2225. */
  2226. function shareEtherpad() {
  2227. APP.xmpp.addToPresence("etherpad", etherpadName);
  2228. }
  2229. /**
  2230. * Creates the Etherpad button and adds it to the toolbar.
  2231. */
  2232. function enableEtherpadButton() {
  2233. if (!$('#etherpadButton').is(":visible"))
  2234. $('#etherpadButton').css({display: 'inline-block'});
  2235. }
  2236. /**
  2237. * Creates the IFrame for the etherpad.
  2238. */
  2239. function createIFrame() {
  2240. etherpadIFrame = document.createElement('iframe');
  2241. etherpadIFrame.src = domain + etherpadName + options;
  2242. etherpadIFrame.frameBorder = 0;
  2243. etherpadIFrame.scrolling = "no";
  2244. etherpadIFrame.width = $('#largeVideoContainer').width() || 640;
  2245. etherpadIFrame.height = $('#largeVideoContainer').height() || 480;
  2246. etherpadIFrame.setAttribute('style', 'visibility: hidden;');
  2247. document.getElementById('etherpad').appendChild(etherpadIFrame);
  2248. etherpadIFrame.onload = function() {
  2249. document.domain = document.domain;
  2250. bubbleIframeMouseMove(etherpadIFrame);
  2251. setTimeout(function() {
  2252. // the iframes inside of the etherpad are
  2253. // not yet loaded when the etherpad iframe is loaded
  2254. var outer = etherpadIFrame.
  2255. contentDocument.getElementsByName("ace_outer")[0];
  2256. bubbleIframeMouseMove(outer);
  2257. var inner = outer.
  2258. contentDocument.getElementsByName("ace_inner")[0];
  2259. bubbleIframeMouseMove(inner);
  2260. }, 2000);
  2261. };
  2262. }
  2263. function bubbleIframeMouseMove(iframe){
  2264. var existingOnMouseMove = iframe.contentWindow.onmousemove;
  2265. iframe.contentWindow.onmousemove = function(e){
  2266. if(existingOnMouseMove) existingOnMouseMove(e);
  2267. var evt = document.createEvent("MouseEvents");
  2268. var boundingClientRect = iframe.getBoundingClientRect();
  2269. evt.initMouseEvent(
  2270. "mousemove",
  2271. true, // bubbles
  2272. false, // not cancelable
  2273. window,
  2274. e.detail,
  2275. e.screenX,
  2276. e.screenY,
  2277. e.clientX + boundingClientRect.left,
  2278. e.clientY + boundingClientRect.top,
  2279. e.ctrlKey,
  2280. e.altKey,
  2281. e.shiftKey,
  2282. e.metaKey,
  2283. e.button,
  2284. null // no related element
  2285. );
  2286. iframe.dispatchEvent(evt);
  2287. };
  2288. }
  2289. /**
  2290. * On video selected event.
  2291. */
  2292. $(document).bind('video.selected', function (event, isPresentation) {
  2293. if (config.etherpad_base && etherpadIFrame && etherpadIFrame.style.visibility !== 'hidden')
  2294. Etherpad.toggleEtherpad(isPresentation);
  2295. });
  2296. var Etherpad = {
  2297. /**
  2298. * Initializes the etherpad.
  2299. */
  2300. init: function (name) {
  2301. if (config.etherpad_base && !etherpadName) {
  2302. domain = config.etherpad_base;
  2303. if (!name) {
  2304. // In case we're the focus we generate the name.
  2305. etherpadName = Math.random().toString(36).substring(7) +
  2306. '_' + (new Date().getTime()).toString();
  2307. shareEtherpad();
  2308. }
  2309. else
  2310. etherpadName = name;
  2311. enableEtherpadButton();
  2312. /**
  2313. * Resizes the etherpad, when the window is resized.
  2314. */
  2315. $(window).resize(function () {
  2316. resize();
  2317. });
  2318. }
  2319. },
  2320. /**
  2321. * Opens/hides the Etherpad.
  2322. */
  2323. toggleEtherpad: function (isPresentation) {
  2324. if (!etherpadIFrame)
  2325. createIFrame();
  2326. var largeVideo = null;
  2327. if (Prezi.isPresentationVisible())
  2328. largeVideo = $('#presentation>iframe');
  2329. else
  2330. largeVideo = $('#largeVideo');
  2331. if ($('#etherpad>iframe').css('visibility') === 'hidden') {
  2332. $('#activeSpeaker').css('visibility', 'hidden');
  2333. largeVideo.fadeOut(300, function () {
  2334. if (Prezi.isPresentationVisible()) {
  2335. largeVideo.css({opacity: '0'});
  2336. } else {
  2337. VideoLayout.setLargeVideoVisible(false);
  2338. }
  2339. });
  2340. $('#etherpad>iframe').fadeIn(300, function () {
  2341. document.body.style.background = '#eeeeee';
  2342. $('#etherpad>iframe').css({visibility: 'visible'});
  2343. $('#etherpad').css({zIndex: 2});
  2344. });
  2345. }
  2346. else if ($('#etherpad>iframe')) {
  2347. $('#etherpad>iframe').fadeOut(300, function () {
  2348. $('#etherpad>iframe').css({visibility: 'hidden'});
  2349. $('#etherpad').css({zIndex: 0});
  2350. document.body.style.background = 'black';
  2351. });
  2352. if (!isPresentation) {
  2353. $('#largeVideo').fadeIn(300, function () {
  2354. VideoLayout.setLargeVideoVisible(true);
  2355. });
  2356. }
  2357. }
  2358. resize();
  2359. },
  2360. isVisible: function() {
  2361. var etherpadIframe = $('#etherpad>iframe');
  2362. return etherpadIframe && etherpadIframe.is(':visible');
  2363. }
  2364. };
  2365. module.exports = Etherpad;
  2366. },{"../prezi/Prezi":14,"../util/UIUtil":30,"../videolayout/VideoLayout":32}],14:[function(require,module,exports){
  2367. var ToolbarToggler = require("../toolbars/ToolbarToggler");
  2368. var UIUtil = require("../util/UIUtil");
  2369. var VideoLayout = require("../videolayout/VideoLayout");
  2370. var messageHandler = require("../util/MessageHandler");
  2371. var PreziPlayer = require("./PreziPlayer");
  2372. var preziPlayer = null;
  2373. var Prezi = {
  2374. /**
  2375. * Reloads the current presentation.
  2376. */
  2377. reloadPresentation: function() {
  2378. var iframe = document.getElementById(preziPlayer.options.preziId);
  2379. iframe.src = iframe.src;
  2380. },
  2381. /**
  2382. * Returns <tt>true</tt> if the presentation is visible, <tt>false</tt> -
  2383. * otherwise.
  2384. */
  2385. isPresentationVisible: function () {
  2386. return ($('#presentation>iframe') != null
  2387. && $('#presentation>iframe').css('opacity') == 1);
  2388. },
  2389. /**
  2390. * Opens the Prezi dialog, from which the user could choose a presentation
  2391. * to load.
  2392. */
  2393. openPreziDialog: function() {
  2394. var myprezi = APP.xmpp.getPrezi();
  2395. if (myprezi) {
  2396. messageHandler.openTwoButtonDialog("Remove Prezi",
  2397. "Are you sure you would like to remove your Prezi?",
  2398. false,
  2399. "Remove",
  2400. function(e,v,m,f) {
  2401. if(v) {
  2402. APP.xmpp.removePreziFromPresence();
  2403. }
  2404. }
  2405. );
  2406. }
  2407. else if (preziPlayer != null) {
  2408. messageHandler.openTwoButtonDialog("Share a Prezi",
  2409. "Another participant is already sharing a Prezi." +
  2410. "This conference allows only one Prezi at a time.",
  2411. false,
  2412. "Ok",
  2413. function(e,v,m,f) {
  2414. $.prompt.close();
  2415. }
  2416. );
  2417. }
  2418. else {
  2419. var openPreziState = {
  2420. state0: {
  2421. html: '<h2>Share a Prezi</h2>' +
  2422. '<input id="preziUrl" type="text" ' +
  2423. 'placeholder="e.g. ' +
  2424. 'http://prezi.com/wz7vhjycl7e6/my-prezi" autofocus>',
  2425. persistent: false,
  2426. buttons: { "Share": true , "Cancel": false},
  2427. defaultButton: 1,
  2428. submit: function(e,v,m,f){
  2429. e.preventDefault();
  2430. if(v)
  2431. {
  2432. var preziUrl = document.getElementById('preziUrl');
  2433. if (preziUrl.value)
  2434. {
  2435. var urlValue
  2436. = encodeURI(UIUtil.escapeHtml(preziUrl.value));
  2437. if (urlValue.indexOf('http://prezi.com/') != 0
  2438. && urlValue.indexOf('https://prezi.com/') != 0)
  2439. {
  2440. $.prompt.goToState('state1');
  2441. return false;
  2442. }
  2443. else {
  2444. var presIdTmp = urlValue.substring(
  2445. urlValue.indexOf("prezi.com/") + 10);
  2446. if (!isAlphanumeric(presIdTmp)
  2447. || presIdTmp.indexOf('/') < 2) {
  2448. $.prompt.goToState('state1');
  2449. return false;
  2450. }
  2451. else {
  2452. APP.xmpp.addToPresence("prezi", urlValue);
  2453. $.prompt.close();
  2454. }
  2455. }
  2456. }
  2457. }
  2458. else
  2459. $.prompt.close();
  2460. }
  2461. },
  2462. state1: {
  2463. html: '<h2>Share a Prezi</h2>' +
  2464. 'Please provide a correct prezi link.',
  2465. persistent: false,
  2466. buttons: { "Back": true, "Cancel": false },
  2467. defaultButton: 1,
  2468. submit:function(e,v,m,f) {
  2469. e.preventDefault();
  2470. if(v==0)
  2471. $.prompt.close();
  2472. else
  2473. $.prompt.goToState('state0');
  2474. }
  2475. }
  2476. };
  2477. var focusPreziUrl = function(e) {
  2478. document.getElementById('preziUrl').focus();
  2479. };
  2480. messageHandler.openDialogWithStates(openPreziState, focusPreziUrl, focusPreziUrl);
  2481. }
  2482. }
  2483. };
  2484. /**
  2485. * A new presentation has been added.
  2486. *
  2487. * @param event the event indicating the add of a presentation
  2488. * @param jid the jid from which the presentation was added
  2489. * @param presUrl url of the presentation
  2490. * @param currentSlide the current slide to which we should move
  2491. */
  2492. function presentationAdded(event, jid, presUrl, currentSlide) {
  2493. console.log("presentation added", presUrl);
  2494. var presId = getPresentationId(presUrl);
  2495. var elementId = 'participant_'
  2496. + Strophe.getResourceFromJid(jid)
  2497. + '_' + presId;
  2498. // We explicitly don't specify the peer jid here, because we don't want
  2499. // this video to be dealt with as a peer related one (for example we
  2500. // don't want to show a mute/kick menu for this one, etc.).
  2501. VideoLayout.addRemoteVideoContainer(null, elementId);
  2502. VideoLayout.resizeThumbnails();
  2503. var controlsEnabled = false;
  2504. if (jid === APP.xmpp.myJid())
  2505. controlsEnabled = true;
  2506. setPresentationVisible(true);
  2507. $('#largeVideoContainer').hover(
  2508. function (event) {
  2509. if (Prezi.isPresentationVisible()) {
  2510. var reloadButtonRight = window.innerWidth
  2511. - $('#presentation>iframe').offset().left
  2512. - $('#presentation>iframe').width();
  2513. $('#reloadPresentation').css({ right: reloadButtonRight,
  2514. display:'inline-block'});
  2515. }
  2516. },
  2517. function (event) {
  2518. if (!Prezi.isPresentationVisible())
  2519. $('#reloadPresentation').css({display:'none'});
  2520. else {
  2521. var e = event.toElement || event.relatedTarget;
  2522. if (e && e.id != 'reloadPresentation' && e.id != 'header')
  2523. $('#reloadPresentation').css({display:'none'});
  2524. }
  2525. });
  2526. preziPlayer = new PreziPlayer(
  2527. 'presentation',
  2528. {preziId: presId,
  2529. width: getPresentationWidth(),
  2530. height: getPresentationHeihgt(),
  2531. controls: controlsEnabled,
  2532. debug: true
  2533. });
  2534. $('#presentation>iframe').attr('id', preziPlayer.options.preziId);
  2535. preziPlayer.on(PreziPlayer.EVENT_STATUS, function(event) {
  2536. console.log("prezi status", event.value);
  2537. if (event.value == PreziPlayer.STATUS_CONTENT_READY) {
  2538. if (jid != APP.xmpp.myJid())
  2539. preziPlayer.flyToStep(currentSlide);
  2540. }
  2541. });
  2542. preziPlayer.on(PreziPlayer.EVENT_CURRENT_STEP, function(event) {
  2543. console.log("event value", event.value);
  2544. APP.xmpp.addToPresence("preziSlide", event.value);
  2545. });
  2546. $("#" + elementId).css( 'background-image',
  2547. 'url(../images/avatarprezi.png)');
  2548. $("#" + elementId).click(
  2549. function () {
  2550. setPresentationVisible(true);
  2551. }
  2552. );
  2553. };
  2554. /**
  2555. * A presentation has been removed.
  2556. *
  2557. * @param event the event indicating the remove of a presentation
  2558. * @param jid the jid for which the presentation was removed
  2559. * @param the url of the presentation
  2560. */
  2561. function presentationRemoved(event, jid, presUrl) {
  2562. console.log('presentation removed', presUrl);
  2563. var presId = getPresentationId(presUrl);
  2564. setPresentationVisible(false);
  2565. $('#participant_'
  2566. + Strophe.getResourceFromJid(jid)
  2567. + '_' + presId).remove();
  2568. $('#presentation>iframe').remove();
  2569. if (preziPlayer != null) {
  2570. preziPlayer.destroy();
  2571. preziPlayer = null;
  2572. }
  2573. };
  2574. /**
  2575. * Indicates if the given string is an alphanumeric string.
  2576. * Note that some special characters are also allowed (-, _ , /, &, ?, =, ;) for the
  2577. * purpose of checking URIs.
  2578. */
  2579. function isAlphanumeric(unsafeText) {
  2580. var regex = /^[a-z0-9-_\/&\?=;]+$/i;
  2581. return regex.test(unsafeText);
  2582. }
  2583. /**
  2584. * Returns the presentation id from the given url.
  2585. */
  2586. function getPresentationId (presUrl) {
  2587. var presIdTmp = presUrl.substring(presUrl.indexOf("prezi.com/") + 10);
  2588. return presIdTmp.substring(0, presIdTmp.indexOf('/'));
  2589. }
  2590. /**
  2591. * Returns the presentation width.
  2592. */
  2593. function getPresentationWidth() {
  2594. var availableWidth = UIUtil.getAvailableVideoWidth();
  2595. var availableHeight = getPresentationHeihgt();
  2596. var aspectRatio = 16.0 / 9.0;
  2597. if (availableHeight < availableWidth / aspectRatio) {
  2598. availableWidth = Math.floor(availableHeight * aspectRatio);
  2599. }
  2600. return availableWidth;
  2601. }
  2602. /**
  2603. * Returns the presentation height.
  2604. */
  2605. function getPresentationHeihgt() {
  2606. var remoteVideos = $('#remoteVideos');
  2607. return window.innerHeight - remoteVideos.outerHeight();
  2608. }
  2609. /**
  2610. * Resizes the presentation iframe.
  2611. */
  2612. function resize() {
  2613. if ($('#presentation>iframe')) {
  2614. $('#presentation>iframe').width(getPresentationWidth());
  2615. $('#presentation>iframe').height(getPresentationHeihgt());
  2616. }
  2617. }
  2618. /**
  2619. * Shows/hides a presentation.
  2620. */
  2621. function setPresentationVisible(visible) {
  2622. var prezi = $('#presentation>iframe');
  2623. if (visible) {
  2624. // Trigger the video.selected event to indicate a change in the
  2625. // large video.
  2626. $(document).trigger("video.selected", [true]);
  2627. $('#largeVideo').fadeOut(300);
  2628. prezi.fadeIn(300, function() {
  2629. prezi.css({opacity:'1'});
  2630. ToolbarToggler.dockToolbar(true);
  2631. VideoLayout.setLargeVideoVisible(false);
  2632. });
  2633. $('#activeSpeaker').css('visibility', 'hidden');
  2634. }
  2635. else {
  2636. if (prezi.css('opacity') == '1') {
  2637. prezi.fadeOut(300, function () {
  2638. prezi.css({opacity:'0'});
  2639. $('#reloadPresentation').css({display:'none'});
  2640. $('#largeVideo').fadeIn(300, function() {
  2641. VideoLayout.setLargeVideoVisible(true);
  2642. ToolbarToggler.dockToolbar(false);
  2643. });
  2644. });
  2645. }
  2646. }
  2647. }
  2648. /**
  2649. * Presentation has been removed.
  2650. */
  2651. $(document).bind('presentationremoved.muc', presentationRemoved);
  2652. /**
  2653. * Presentation has been added.
  2654. */
  2655. $(document).bind('presentationadded.muc', presentationAdded);
  2656. /*
  2657. * Indicates presentation slide change.
  2658. */
  2659. $(document).bind('gotoslide.muc', function (event, jid, presUrl, current) {
  2660. if (preziPlayer && preziPlayer.getCurrentStep() != current) {
  2661. preziPlayer.flyToStep(current);
  2662. var animationStepsArray = preziPlayer.getAnimationCountOnSteps();
  2663. for (var i = 0; i < parseInt(animationStepsArray[current]); i++) {
  2664. preziPlayer.flyToStep(current, i);
  2665. }
  2666. }
  2667. });
  2668. /**
  2669. * On video selected event.
  2670. */
  2671. $(document).bind('video.selected', function (event, isPresentation) {
  2672. if (!isPresentation && $('#presentation>iframe')) {
  2673. setPresentationVisible(false);
  2674. }
  2675. });
  2676. $(window).resize(function () {
  2677. resize();
  2678. });
  2679. module.exports = Prezi;
  2680. },{"../toolbars/ToolbarToggler":26,"../util/MessageHandler":28,"../util/UIUtil":30,"../videolayout/VideoLayout":32,"./PreziPlayer":15}],15:[function(require,module,exports){
  2681. (function() {
  2682. "use strict";
  2683. var __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; };
  2684. window.PreziPlayer = (function() {
  2685. PreziPlayer.API_VERSION = 1;
  2686. PreziPlayer.CURRENT_STEP = 'currentStep';
  2687. PreziPlayer.CURRENT_ANIMATION_STEP = 'currentAnimationStep';
  2688. PreziPlayer.CURRENT_OBJECT = 'currentObject';
  2689. PreziPlayer.STATUS_LOADING = 'loading';
  2690. PreziPlayer.STATUS_READY = 'ready';
  2691. PreziPlayer.STATUS_CONTENT_READY = 'contentready';
  2692. PreziPlayer.EVENT_CURRENT_STEP = "currentStepChange";
  2693. PreziPlayer.EVENT_CURRENT_ANIMATION_STEP = "currentAnimationStepChange";
  2694. PreziPlayer.EVENT_CURRENT_OBJECT = "currentObjectChange";
  2695. PreziPlayer.EVENT_STATUS = "statusChange";
  2696. PreziPlayer.EVENT_PLAYING = "isAutoPlayingChange";
  2697. PreziPlayer.EVENT_IS_MOVING = "isMovingChange";
  2698. PreziPlayer.domain = "https://prezi.com";
  2699. PreziPlayer.path = "/player/";
  2700. PreziPlayer.players = {};
  2701. PreziPlayer.binded_methods = ['changesHandler'];
  2702. PreziPlayer.createMultiplePlayers = function(optionArray){
  2703. for(var i=0; i<optionArray.length; i++) {
  2704. var optionSet = optionArray[i];
  2705. new PreziPlayer(optionSet.id, optionSet);
  2706. };
  2707. };
  2708. PreziPlayer.messageReceived = function(event){
  2709. var message, item, player;
  2710. try {
  2711. message = JSON.parse(event.data);
  2712. } catch (e) {}
  2713. if (message.id && (player = PreziPlayer.players[message.id])){
  2714. if (player.options.debug === true) {
  2715. if (console && console.log) console.log('received', message);
  2716. }
  2717. if (message.type === "changes"){
  2718. player.changesHandler(message);
  2719. }
  2720. for (var i=0; i<player.callbacks.length; i++) {
  2721. item = player.callbacks[i];
  2722. if (item && message.type === item.event){
  2723. item.callback(message);
  2724. }
  2725. }
  2726. }
  2727. };
  2728. function PreziPlayer(id, options) {
  2729. var params, paramString = "", _this = this;
  2730. if (PreziPlayer.players[id]){
  2731. PreziPlayer.players[id].destroy();
  2732. }
  2733. for(var i=0; i<PreziPlayer.binded_methods.length; i++) {
  2734. var method_name = PreziPlayer.binded_methods[i];
  2735. _this[method_name] = __bind(_this[method_name], _this);
  2736. };
  2737. options = options || {};
  2738. this.options = options;
  2739. this.values = {'status': PreziPlayer.STATUS_LOADING};
  2740. this.values[PreziPlayer.CURRENT_STEP] = 0;
  2741. this.values[PreziPlayer.CURRENT_ANIMATION_STEP] = 0;
  2742. this.values[PreziPlayer.CURRENT_OBJECT] = null;
  2743. this.callbacks = [];
  2744. this.id = id;
  2745. this.embedTo = document.getElementById(id);
  2746. if (!this.embedTo) {
  2747. throw "The element id is not available.";
  2748. }
  2749. this.iframe = document.createElement('iframe');
  2750. params = [
  2751. { name: 'oid', value: options.preziId },
  2752. { name: 'explorable', value: options.explorable ? 1 : 0 },
  2753. { name: 'controls', value: options.controls ? 1 : 0 }
  2754. ];
  2755. for(var i=0; i<params.length; i++) {
  2756. var param = params[i];
  2757. paramString += (i===0 ? "?" : "&") + param.name + "=" + param.value;
  2758. };
  2759. this.iframe.src = PreziPlayer.domain + PreziPlayer.path + paramString;
  2760. this.iframe.frameBorder = 0;
  2761. this.iframe.scrolling = "no";
  2762. this.iframe.width = options.width || 640;
  2763. this.iframe.height = options.height || 480;
  2764. this.embedTo.innerHTML = '';
  2765. // JITSI: IN CASE SOMETHING GOES WRONG.
  2766. try {
  2767. this.embedTo.appendChild(this.iframe);
  2768. }
  2769. catch (err) {
  2770. console.log("CATCH ERROR");
  2771. }
  2772. // JITSI: Increase interval from 200 to 500, which fixes prezi
  2773. // crashes for us.
  2774. this.initPollInterval = setInterval(function(){
  2775. _this.sendMessage({'action': 'init'});
  2776. }, 500);
  2777. PreziPlayer.players[id] = this;
  2778. }
  2779. PreziPlayer.prototype.changesHandler = function(message) {
  2780. var key, value, j, item;
  2781. if (this.initPollInterval) {
  2782. clearInterval(this.initPollInterval);
  2783. this.initPollInterval = false;
  2784. }
  2785. for (key in message.data) {
  2786. if (message.data.hasOwnProperty(key)){
  2787. value = message.data[key];
  2788. this.values[key] = value;
  2789. for (j=0; j<this.callbacks.length; j++) {
  2790. item = this.callbacks[j];
  2791. if (item && item.event === key + "Change"){
  2792. item.callback({type: item.event, value: value});
  2793. }
  2794. }
  2795. }
  2796. }
  2797. };
  2798. PreziPlayer.prototype.destroy = function() {
  2799. if (this.initPollInterval) {
  2800. clearInterval(this.initPollInterval);
  2801. this.initPollInterval = false;
  2802. }
  2803. this.embedTo.innerHTML = '';
  2804. };
  2805. PreziPlayer.prototype.sendMessage = function(message) {
  2806. if (this.options.debug === true) {
  2807. if (console && console.log) console.log('sent', message);
  2808. }
  2809. message.version = PreziPlayer.API_VERSION;
  2810. message.id = this.id;
  2811. return this.iframe.contentWindow.postMessage(JSON.stringify(message), '*');
  2812. };
  2813. PreziPlayer.prototype.nextStep = /* nextStep is DEPRECATED */
  2814. PreziPlayer.prototype.flyToNextStep = function() {
  2815. return this.sendMessage({
  2816. 'action': 'present',
  2817. 'data': ['moveToNextStep']
  2818. });
  2819. };
  2820. PreziPlayer.prototype.previousStep = /* previousStep is DEPRECATED */
  2821. PreziPlayer.prototype.flyToPreviousStep = function() {
  2822. return this.sendMessage({
  2823. 'action': 'present',
  2824. 'data': ['moveToPrevStep']
  2825. });
  2826. };
  2827. PreziPlayer.prototype.toStep = /* toStep is DEPRECATED */
  2828. PreziPlayer.prototype.flyToStep = function(step, animation_step) {
  2829. var obj = this;
  2830. // check animation_step
  2831. if (animation_step > 0 &&
  2832. obj.values.animationCountOnSteps &&
  2833. obj.values.animationCountOnSteps[step] <= animation_step) {
  2834. animation_step = obj.values.animationCountOnSteps[step];
  2835. }
  2836. // jump to animation steps by calling flyToNextStep()
  2837. function doAnimationSteps() {
  2838. if (obj.values.isMoving == true) {
  2839. setTimeout(doAnimationSteps, 100); // wait until the flight ends
  2840. return;
  2841. }
  2842. while (animation_step-- > 0) {
  2843. obj.flyToNextStep(); // do the animation steps
  2844. }
  2845. }
  2846. setTimeout(doAnimationSteps, 200); // 200ms is the internal "reporting" time
  2847. // jump to the step
  2848. return this.sendMessage({
  2849. 'action': 'present',
  2850. 'data': ['moveToStep', step]
  2851. });
  2852. };
  2853. PreziPlayer.prototype.toObject = /* toObject is DEPRECATED */
  2854. PreziPlayer.prototype.flyToObject = function(objectId) {
  2855. return this.sendMessage({
  2856. 'action': 'present',
  2857. 'data': ['moveToObject', objectId]
  2858. });
  2859. };
  2860. PreziPlayer.prototype.play = function(defaultDelay) {
  2861. return this.sendMessage({
  2862. 'action': 'present',
  2863. 'data': ['startAutoPlay', defaultDelay]
  2864. });
  2865. };
  2866. PreziPlayer.prototype.stop = function() {
  2867. return this.sendMessage({
  2868. 'action': 'present',
  2869. 'data': ['stopAutoPlay']
  2870. });
  2871. };
  2872. PreziPlayer.prototype.pause = function(defaultDelay) {
  2873. return this.sendMessage({
  2874. 'action': 'present',
  2875. 'data': ['pauseAutoPlay', defaultDelay]
  2876. });
  2877. };
  2878. PreziPlayer.prototype.getCurrentStep = function() {
  2879. return this.values.currentStep;
  2880. };
  2881. PreziPlayer.prototype.getCurrentAnimationStep = function() {
  2882. return this.values.currentAnimationStep;
  2883. };
  2884. PreziPlayer.prototype.getCurrentObject = function() {
  2885. return this.values.currentObject;
  2886. };
  2887. PreziPlayer.prototype.getStatus = function() {
  2888. return this.values.status;
  2889. };
  2890. PreziPlayer.prototype.isPlaying = function() {
  2891. return this.values.isAutoPlaying;
  2892. };
  2893. PreziPlayer.prototype.getStepCount = function() {
  2894. return this.values.stepCount;
  2895. };
  2896. PreziPlayer.prototype.getAnimationCountOnSteps = function() {
  2897. return this.values.animationCountOnSteps;
  2898. };
  2899. PreziPlayer.prototype.getTitle = function() {
  2900. return this.values.title;
  2901. };
  2902. PreziPlayer.prototype.setDimensions = function(dims) {
  2903. for (var parameter in dims) {
  2904. this.iframe[parameter] = dims[parameter];
  2905. }
  2906. }
  2907. PreziPlayer.prototype.getDimensions = function() {
  2908. return {
  2909. width: parseInt(this.iframe.width, 10),
  2910. height: parseInt(this.iframe.height, 10)
  2911. }
  2912. }
  2913. PreziPlayer.prototype.on = function(event, callback) {
  2914. this.callbacks.push({
  2915. event: event,
  2916. callback: callback
  2917. });
  2918. };
  2919. PreziPlayer.prototype.off = function(event, callback) {
  2920. var j, item;
  2921. if (event === undefined) {
  2922. this.callbacks = [];
  2923. }
  2924. j = this.callbacks.length;
  2925. while (j--) {
  2926. item = this.callbacks[j];
  2927. if (item && item.event === event && (callback === undefined || item.callback === callback)){
  2928. this.callbacks.splice(j, 1);
  2929. }
  2930. }
  2931. };
  2932. if (window.addEventListener) {
  2933. window.addEventListener('message', PreziPlayer.messageReceived, false);
  2934. } else {
  2935. window.attachEvent('onmessage', PreziPlayer.messageReceived);
  2936. }
  2937. return PreziPlayer;
  2938. })();
  2939. })();
  2940. module.exports = PreziPlayer;
  2941. },{}],16:[function(require,module,exports){
  2942. var Chat = require("./chat/Chat");
  2943. var ContactList = require("./contactlist/ContactList");
  2944. var Settings = require("./settings/Settings");
  2945. var SettingsMenu = require("./settings/SettingsMenu");
  2946. var VideoLayout = require("../videolayout/VideoLayout");
  2947. var ToolbarToggler = require("../toolbars/ToolbarToggler");
  2948. var UIUtil = require("../util/UIUtil");
  2949. /**
  2950. * Toggler for the chat, contact list, settings menu, etc..
  2951. */
  2952. var PanelToggler = (function(my) {
  2953. var currentlyOpen = null;
  2954. var buttons = {
  2955. '#chatspace': '#chatBottomButton',
  2956. '#contactlist': '#contactListButton',
  2957. '#settingsmenu': '#settingsButton'
  2958. };
  2959. /**
  2960. * Resizes the video area
  2961. * @param isClosing whether the side panel is going to be closed or is going to open / remain opened
  2962. * @param completeFunction a function to be called when the video space is resized
  2963. */
  2964. var resizeVideoArea = function(isClosing, completeFunction) {
  2965. var videospace = $('#videospace');
  2966. var panelSize = isClosing ? [0, 0] : PanelToggler.getPanelSize();
  2967. var videospaceWidth = window.innerWidth - panelSize[0];
  2968. var videospaceHeight = window.innerHeight;
  2969. var videoSize
  2970. = VideoLayout.getVideoSize(null, null, videospaceWidth, videospaceHeight);
  2971. var videoWidth = videoSize[0];
  2972. var videoHeight = videoSize[1];
  2973. var videoPosition = VideoLayout.getVideoPosition(videoWidth,
  2974. videoHeight,
  2975. videospaceWidth,
  2976. videospaceHeight);
  2977. var horizontalIndent = videoPosition[0];
  2978. var verticalIndent = videoPosition[1];
  2979. var thumbnailSize = VideoLayout.calculateThumbnailSize(videospaceWidth);
  2980. var thumbnailsWidth = thumbnailSize[0];
  2981. var thumbnailsHeight = thumbnailSize[1];
  2982. //for chat
  2983. videospace.animate({
  2984. right: panelSize[0],
  2985. width: videospaceWidth,
  2986. height: videospaceHeight
  2987. },
  2988. {
  2989. queue: false,
  2990. duration: 500,
  2991. complete: completeFunction
  2992. });
  2993. $('#remoteVideos').animate({
  2994. height: thumbnailsHeight
  2995. },
  2996. {
  2997. queue: false,
  2998. duration: 500
  2999. });
  3000. $('#remoteVideos>span').animate({
  3001. height: thumbnailsHeight,
  3002. width: thumbnailsWidth
  3003. },
  3004. {
  3005. queue: false,
  3006. duration: 500,
  3007. complete: function () {
  3008. $(document).trigger(
  3009. "remotevideo.resized",
  3010. [thumbnailsWidth,
  3011. thumbnailsHeight]);
  3012. }
  3013. });
  3014. $('#largeVideoContainer').animate({
  3015. width: videospaceWidth,
  3016. height: videospaceHeight
  3017. },
  3018. {
  3019. queue: false,
  3020. duration: 500
  3021. });
  3022. $('#largeVideo').animate({
  3023. width: videoWidth,
  3024. height: videoHeight,
  3025. top: verticalIndent,
  3026. bottom: verticalIndent,
  3027. left: horizontalIndent,
  3028. right: horizontalIndent
  3029. },
  3030. {
  3031. queue: false,
  3032. duration: 500
  3033. });
  3034. };
  3035. /**
  3036. * Toggles the windows in the side panel
  3037. * @param object the window that should be shown
  3038. * @param selector the selector for the element containing the panel
  3039. * @param onOpenComplete function to be called when the panel is opened
  3040. * @param onOpen function to be called if the window is going to be opened
  3041. * @param onClose function to be called if the window is going to be closed
  3042. */
  3043. var toggle = function(object, selector, onOpenComplete, onOpen, onClose) {
  3044. UIUtil.buttonClick(buttons[selector], "active");
  3045. if (object.isVisible()) {
  3046. $("#toast-container").animate({
  3047. right: '5px'
  3048. },
  3049. {
  3050. queue: false,
  3051. duration: 500
  3052. });
  3053. $(selector).hide("slide", {
  3054. direction: "right",
  3055. queue: false,
  3056. duration: 500
  3057. });
  3058. if(typeof onClose === "function") {
  3059. onClose();
  3060. }
  3061. currentlyOpen = null;
  3062. }
  3063. else {
  3064. // Undock the toolbar when the chat is shown and if we're in a
  3065. // video mode.
  3066. if (VideoLayout.isLargeVideoVisible()) {
  3067. ToolbarToggler.dockToolbar(false);
  3068. }
  3069. if(currentlyOpen) {
  3070. var current = $(currentlyOpen);
  3071. UIUtil.buttonClick(buttons[currentlyOpen], "active");
  3072. current.css('z-index', 4);
  3073. setTimeout(function () {
  3074. current.css('display', 'none');
  3075. current.css('z-index', 5);
  3076. }, 500);
  3077. }
  3078. $("#toast-container").animate({
  3079. right: (PanelToggler.getPanelSize()[0] + 5) + 'px'
  3080. },
  3081. {
  3082. queue: false,
  3083. duration: 500
  3084. });
  3085. $(selector).show("slide", {
  3086. direction: "right",
  3087. queue: false,
  3088. duration: 500,
  3089. complete: onOpenComplete
  3090. });
  3091. if(typeof onOpen === "function") {
  3092. onOpen();
  3093. }
  3094. currentlyOpen = selector;
  3095. }
  3096. };
  3097. /**
  3098. * Opens / closes the chat area.
  3099. */
  3100. my.toggleChat = function() {
  3101. var chatCompleteFunction = Chat.isVisible() ?
  3102. function() {} : function () {
  3103. Chat.scrollChatToBottom();
  3104. $('#chatspace').trigger('shown');
  3105. };
  3106. resizeVideoArea(Chat.isVisible(), chatCompleteFunction);
  3107. toggle(Chat,
  3108. '#chatspace',
  3109. function () {
  3110. // Request the focus in the nickname field or the chat input field.
  3111. if ($('#nickname').css('visibility') === 'visible') {
  3112. $('#nickinput').focus();
  3113. } else {
  3114. $('#usermsg').focus();
  3115. }
  3116. },
  3117. null,
  3118. Chat.resizeChat,
  3119. null);
  3120. };
  3121. /**
  3122. * Opens / closes the contact list area.
  3123. */
  3124. my.toggleContactList = function () {
  3125. var completeFunction = ContactList.isVisible() ?
  3126. function() {} : function () { $('#contactlist').trigger('shown');};
  3127. resizeVideoArea(ContactList.isVisible(), completeFunction);
  3128. toggle(ContactList,
  3129. '#contactlist',
  3130. null,
  3131. function() {
  3132. ContactList.setVisualNotification(false);
  3133. },
  3134. null);
  3135. };
  3136. /**
  3137. * Opens / closes the settings menu
  3138. */
  3139. my.toggleSettingsMenu = function() {
  3140. resizeVideoArea(SettingsMenu.isVisible(), function (){});
  3141. toggle(SettingsMenu,
  3142. '#settingsmenu',
  3143. null,
  3144. function() {
  3145. var settings = Settings.getSettings();
  3146. $('#setDisplayName').get(0).value = settings.displayName;
  3147. $('#setEmail').get(0).value = settings.email;
  3148. },
  3149. null);
  3150. };
  3151. /**
  3152. * Returns the size of the side panel.
  3153. */
  3154. my.getPanelSize = function () {
  3155. var availableHeight = window.innerHeight;
  3156. var availableWidth = window.innerWidth;
  3157. var panelWidth = 200;
  3158. if (availableWidth * 0.2 < 200) {
  3159. panelWidth = availableWidth * 0.2;
  3160. }
  3161. return [panelWidth, availableHeight];
  3162. };
  3163. my.isVisible = function() {
  3164. return (Chat.isVisible() || ContactList.isVisible() || SettingsMenu.isVisible());
  3165. };
  3166. return my;
  3167. }(PanelToggler || {}));
  3168. module.exports = PanelToggler;
  3169. },{"../toolbars/ToolbarToggler":26,"../util/UIUtil":30,"../videolayout/VideoLayout":32,"./chat/Chat":17,"./contactlist/ContactList":21,"./settings/Settings":22,"./settings/SettingsMenu":23}],17:[function(require,module,exports){
  3170. /* global $, Util, nickname:true */
  3171. var Replacement = require("./Replacement");
  3172. var CommandsProcessor = require("./Commands");
  3173. var ToolbarToggler = require("../../toolbars/ToolbarToggler");
  3174. var smileys = require("./smileys.json").smileys;
  3175. var NicknameHandler = require("../../util/NicknameHandler");
  3176. var UIUtil = require("../../util/UIUtil");
  3177. var UIEvents = require("../../../../service/UI/UIEvents");
  3178. var notificationInterval = false;
  3179. var unreadMessages = 0;
  3180. /**
  3181. * Shows/hides a visual notification, indicating that a message has arrived.
  3182. */
  3183. function setVisualNotification(show) {
  3184. var unreadMsgElement = document.getElementById('unreadMessages');
  3185. var unreadMsgBottomElement
  3186. = document.getElementById('bottomUnreadMessages');
  3187. var glower = $('#chatButton');
  3188. var bottomGlower = $('#chatBottomButton');
  3189. if (unreadMessages) {
  3190. unreadMsgElement.innerHTML = unreadMessages.toString();
  3191. unreadMsgBottomElement.innerHTML = unreadMessages.toString();
  3192. ToolbarToggler.dockToolbar(true);
  3193. var chatButtonElement
  3194. = document.getElementById('chatButton').parentNode;
  3195. var leftIndent = (UIUtil.getTextWidth(chatButtonElement) -
  3196. UIUtil.getTextWidth(unreadMsgElement)) / 2;
  3197. var topIndent = (UIUtil.getTextHeight(chatButtonElement) -
  3198. UIUtil.getTextHeight(unreadMsgElement)) / 2 - 3;
  3199. unreadMsgElement.setAttribute(
  3200. 'style',
  3201. 'top:' + topIndent +
  3202. '; left:' + leftIndent + ';');
  3203. var chatBottomButtonElement
  3204. = document.getElementById('chatBottomButton').parentNode;
  3205. var bottomLeftIndent = (UIUtil.getTextWidth(chatBottomButtonElement) -
  3206. UIUtil.getTextWidth(unreadMsgBottomElement)) / 2;
  3207. var bottomTopIndent = (UIUtil.getTextHeight(chatBottomButtonElement) -
  3208. UIUtil.getTextHeight(unreadMsgBottomElement)) / 2 - 2;
  3209. unreadMsgBottomElement.setAttribute(
  3210. 'style',
  3211. 'top:' + bottomTopIndent +
  3212. '; left:' + bottomLeftIndent + ';');
  3213. if (!glower.hasClass('icon-chat-simple')) {
  3214. glower.removeClass('icon-chat');
  3215. glower.addClass('icon-chat-simple');
  3216. }
  3217. }
  3218. else {
  3219. unreadMsgElement.innerHTML = '';
  3220. unreadMsgBottomElement.innerHTML = '';
  3221. glower.removeClass('icon-chat-simple');
  3222. glower.addClass('icon-chat');
  3223. }
  3224. if (show && !notificationInterval) {
  3225. notificationInterval = window.setInterval(function () {
  3226. glower.toggleClass('active');
  3227. bottomGlower.toggleClass('active glowing');
  3228. }, 800);
  3229. }
  3230. else if (!show && notificationInterval) {
  3231. window.clearInterval(notificationInterval);
  3232. notificationInterval = false;
  3233. glower.removeClass('active');
  3234. bottomGlower.removeClass('glowing');
  3235. bottomGlower.addClass('active');
  3236. }
  3237. }
  3238. /**
  3239. * Returns the current time in the format it is shown to the user
  3240. * @returns {string}
  3241. */
  3242. function getCurrentTime() {
  3243. var now = new Date();
  3244. var hour = now.getHours();
  3245. var minute = now.getMinutes();
  3246. var second = now.getSeconds();
  3247. if(hour.toString().length === 1) {
  3248. hour = '0'+hour;
  3249. }
  3250. if(minute.toString().length === 1) {
  3251. minute = '0'+minute;
  3252. }
  3253. if(second.toString().length === 1) {
  3254. second = '0'+second;
  3255. }
  3256. return hour+':'+minute+':'+second;
  3257. }
  3258. function toggleSmileys()
  3259. {
  3260. var smileys = $('#smileysContainer');
  3261. if(!smileys.is(':visible')) {
  3262. smileys.show("slide", { direction: "down", duration: 300});
  3263. } else {
  3264. smileys.hide("slide", { direction: "down", duration: 300});
  3265. }
  3266. $('#usermsg').focus();
  3267. }
  3268. function addClickFunction(smiley, number) {
  3269. smiley.onclick = function addSmileyToMessage() {
  3270. var usermsg = $('#usermsg');
  3271. var message = usermsg.val();
  3272. message += smileys['smiley' + number];
  3273. usermsg.val(message);
  3274. usermsg.get(0).setSelectionRange(message.length, message.length);
  3275. toggleSmileys();
  3276. usermsg.focus();
  3277. };
  3278. }
  3279. /**
  3280. * Adds the smileys container to the chat
  3281. */
  3282. function addSmileys() {
  3283. var smileysContainer = document.createElement('div');
  3284. smileysContainer.id = 'smileysContainer';
  3285. for(var i = 1; i <= 21; i++) {
  3286. var smileyContainer = document.createElement('div');
  3287. smileyContainer.id = 'smiley' + i;
  3288. smileyContainer.className = 'smileyContainer';
  3289. var smiley = document.createElement('img');
  3290. smiley.src = 'images/smileys/smiley' + i + '.svg';
  3291. smiley.className = 'smiley';
  3292. addClickFunction(smiley, i);
  3293. smileyContainer.appendChild(smiley);
  3294. smileysContainer.appendChild(smileyContainer);
  3295. }
  3296. $("#chatspace").append(smileysContainer);
  3297. }
  3298. /**
  3299. * Resizes the chat conversation.
  3300. */
  3301. function resizeChatConversation() {
  3302. var msgareaHeight = $('#usermsg').outerHeight();
  3303. var chatspace = $('#chatspace');
  3304. var width = chatspace.width();
  3305. var chat = $('#chatconversation');
  3306. var smileys = $('#smileysarea');
  3307. smileys.height(msgareaHeight);
  3308. $("#smileys").css('bottom', (msgareaHeight - 26) / 2);
  3309. $('#smileysContainer').css('bottom', msgareaHeight);
  3310. chat.width(width - 10);
  3311. chat.height(window.innerHeight - 15 - msgareaHeight);
  3312. }
  3313. /**
  3314. * Chat related user interface.
  3315. */
  3316. var Chat = (function (my) {
  3317. /**
  3318. * Initializes chat related interface.
  3319. */
  3320. my.init = function () {
  3321. if(NicknameHandler.getNickname())
  3322. Chat.setChatConversationMode(true);
  3323. NicknameHandler.addListener(UIEvents.NICKNAME_CHANGED,
  3324. function (nickname) {
  3325. Chat.setChatConversationMode(true);
  3326. });
  3327. $('#nickinput').keydown(function (event) {
  3328. if (event.keyCode === 13) {
  3329. event.preventDefault();
  3330. var val = UIUtil.escapeHtml(this.value);
  3331. this.value = '';
  3332. if (!NicknameHandler.getNickname()) {
  3333. NicknameHandler.setNickname(val);
  3334. return;
  3335. }
  3336. }
  3337. });
  3338. $('#usermsg').keydown(function (event) {
  3339. if (event.keyCode === 13) {
  3340. event.preventDefault();
  3341. var value = this.value;
  3342. $('#usermsg').val('').trigger('autosize.resize');
  3343. this.focus();
  3344. var command = new CommandsProcessor(value);
  3345. if(command.isCommand())
  3346. {
  3347. command.processCommand();
  3348. }
  3349. else
  3350. {
  3351. var message = UIUtil.escapeHtml(value);
  3352. APP.xmpp.sendChatMessage(message, NicknameHandler.getNickname());
  3353. }
  3354. }
  3355. });
  3356. var onTextAreaResize = function () {
  3357. resizeChatConversation();
  3358. Chat.scrollChatToBottom();
  3359. };
  3360. $('#usermsg').autosize({callback: onTextAreaResize});
  3361. $("#chatspace").bind("shown",
  3362. function () {
  3363. unreadMessages = 0;
  3364. setVisualNotification(false);
  3365. });
  3366. addSmileys();
  3367. };
  3368. /**
  3369. * Appends the given message to the chat conversation.
  3370. */
  3371. my.updateChatConversation = function (from, displayName, message) {
  3372. var divClassName = '';
  3373. if (APP.xmpp.myJid() === from) {
  3374. divClassName = "localuser";
  3375. }
  3376. else {
  3377. divClassName = "remoteuser";
  3378. if (!Chat.isVisible()) {
  3379. unreadMessages++;
  3380. UIUtil.playSoundNotification('chatNotification');
  3381. setVisualNotification(true);
  3382. }
  3383. }
  3384. // replace links and smileys
  3385. // Strophe already escapes special symbols on sending,
  3386. // so we escape here only tags to avoid double &amp;
  3387. var escMessage = message.replace(/</g, '&lt;').
  3388. replace(/>/g, '&gt;').replace(/\n/g, '<br/>');
  3389. var escDisplayName = UIUtil.escapeHtml(displayName);
  3390. message = Replacement.processReplacements(escMessage);
  3391. var messageContainer =
  3392. '<div class="chatmessage">'+
  3393. '<img src="../images/chatArrow.svg" class="chatArrow">' +
  3394. '<div class="username ' + divClassName +'">' + escDisplayName +
  3395. '</div>' + '<div class="timestamp">' + getCurrentTime() +
  3396. '</div>' + '<div class="usermessage">' + message + '</div>' +
  3397. '</div>';
  3398. $('#chatconversation').append(messageContainer);
  3399. $('#chatconversation').animate(
  3400. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  3401. };
  3402. /**
  3403. * Appends error message to the conversation
  3404. * @param errorMessage the received error message.
  3405. * @param originalText the original message.
  3406. */
  3407. my.chatAddError = function(errorMessage, originalText)
  3408. {
  3409. errorMessage = UIUtil.escapeHtml(errorMessage);
  3410. originalText = UIUtil.escapeHtml(originalText);
  3411. $('#chatconversation').append(
  3412. '<div class="errorMessage"><b>Error: </b>' + 'Your message' +
  3413. (originalText? (' \"'+ originalText + '\"') : "") +
  3414. ' was not sent.' +
  3415. (errorMessage? (' Reason: ' + errorMessage) : '') + '</div>');
  3416. $('#chatconversation').animate(
  3417. { scrollTop: $('#chatconversation')[0].scrollHeight}, 1000);
  3418. };
  3419. /**
  3420. * Sets the subject to the UI
  3421. * @param subject the subject
  3422. */
  3423. my.chatSetSubject = function(subject)
  3424. {
  3425. if(subject)
  3426. subject = subject.trim();
  3427. $('#subject').html(Replacement.linkify(UIUtil.escapeHtml(subject)));
  3428. if(subject === "")
  3429. {
  3430. $("#subject").css({display: "none"});
  3431. }
  3432. else
  3433. {
  3434. $("#subject").css({display: "block"});
  3435. }
  3436. };
  3437. /**
  3438. * Sets the chat conversation mode.
  3439. */
  3440. my.setChatConversationMode = function (isConversationMode) {
  3441. if (isConversationMode) {
  3442. $('#nickname').css({visibility: 'hidden'});
  3443. $('#chatconversation').css({visibility: 'visible'});
  3444. $('#usermsg').css({visibility: 'visible'});
  3445. $('#smileysarea').css({visibility: 'visible'});
  3446. $('#usermsg').focus();
  3447. }
  3448. };
  3449. /**
  3450. * Resizes the chat area.
  3451. */
  3452. my.resizeChat = function () {
  3453. var chatSize = require("../SidePanelToggler").getPanelSize();
  3454. $('#chatspace').width(chatSize[0]);
  3455. $('#chatspace').height(chatSize[1]);
  3456. resizeChatConversation();
  3457. };
  3458. /**
  3459. * Indicates if the chat is currently visible.
  3460. */
  3461. my.isVisible = function () {
  3462. return $('#chatspace').is(":visible");
  3463. };
  3464. /**
  3465. * Shows and hides the window with the smileys
  3466. */
  3467. my.toggleSmileys = toggleSmileys;
  3468. /**
  3469. * Scrolls chat to the bottom.
  3470. */
  3471. my.scrollChatToBottom = function() {
  3472. setTimeout(function () {
  3473. $('#chatconversation').scrollTop(
  3474. $('#chatconversation')[0].scrollHeight);
  3475. }, 5);
  3476. };
  3477. return my;
  3478. }(Chat || {}));
  3479. module.exports = Chat;
  3480. },{"../../../../service/UI/UIEvents":82,"../../toolbars/ToolbarToggler":26,"../../util/NicknameHandler":29,"../../util/UIUtil":30,"../SidePanelToggler":16,"./Commands":18,"./Replacement":19,"./smileys.json":20}],18:[function(require,module,exports){
  3481. var UIUtil = require("../../util/UIUtil");
  3482. /**
  3483. * List with supported commands. The keys are the names of the commands and
  3484. * the value is the function that processes the message.
  3485. * @type {{String: function}}
  3486. */
  3487. var commands = {
  3488. "topic" : processTopic
  3489. };
  3490. /**
  3491. * Extracts the command from the message.
  3492. * @param message the received message
  3493. * @returns {string} the command
  3494. */
  3495. function getCommand(message)
  3496. {
  3497. if(message)
  3498. {
  3499. for(var command in commands)
  3500. {
  3501. if(message.indexOf("/" + command) == 0)
  3502. return command;
  3503. }
  3504. }
  3505. return "";
  3506. };
  3507. /**
  3508. * Processes the data for topic command.
  3509. * @param commandArguments the arguments of the topic command.
  3510. */
  3511. function processTopic(commandArguments)
  3512. {
  3513. var topic = UIUtil.escapeHtml(commandArguments);
  3514. APP.xmpp.setSubject(topic);
  3515. }
  3516. /**
  3517. * Constructs new CommandProccessor instance from a message that
  3518. * handles commands received via chat messages.
  3519. * @param message the message
  3520. * @constructor
  3521. */
  3522. function CommandsProcessor(message)
  3523. {
  3524. var command = getCommand(message);
  3525. /**
  3526. * Returns the name of the command.
  3527. * @returns {String} the command
  3528. */
  3529. this.getCommand = function()
  3530. {
  3531. return command;
  3532. };
  3533. var messageArgument = message.substr(command.length + 2);
  3534. /**
  3535. * Returns the arguments of the command.
  3536. * @returns {string}
  3537. */
  3538. this.getArgument = function()
  3539. {
  3540. return messageArgument;
  3541. };
  3542. }
  3543. /**
  3544. * Checks whether this instance is valid command or not.
  3545. * @returns {boolean}
  3546. */
  3547. CommandsProcessor.prototype.isCommand = function()
  3548. {
  3549. if(this.getCommand())
  3550. return true;
  3551. return false;
  3552. };
  3553. /**
  3554. * Processes the command.
  3555. */
  3556. CommandsProcessor.prototype.processCommand = function()
  3557. {
  3558. if(!this.isCommand())
  3559. return;
  3560. commands[this.getCommand()](this.getArgument());
  3561. };
  3562. module.exports = CommandsProcessor;
  3563. },{"../../util/UIUtil":30}],19:[function(require,module,exports){
  3564. var Smileys = require("./smileys.json");
  3565. /**
  3566. * Processes links and smileys in "body"
  3567. */
  3568. function processReplacements(body)
  3569. {
  3570. //make links clickable
  3571. body = linkify(body);
  3572. //add smileys
  3573. body = smilify(body);
  3574. return body;
  3575. }
  3576. /**
  3577. * Finds and replaces all links in the links in "body"
  3578. * with their <a href=""></a>
  3579. */
  3580. function linkify(inputText)
  3581. {
  3582. var replacedText, replacePattern1, replacePattern2, replacePattern3;
  3583. //URLs starting with http://, https://, or ftp://
  3584. replacePattern1 = /(\b(https?|ftp):\/\/[-A-Z0-9+&@#\/%?=~_|!:,.;]*[-A-Z0-9+&@#\/%=~_|])/gim;
  3585. replacedText = inputText.replace(replacePattern1, '<a href="$1" target="_blank">$1</a>');
  3586. //URLs starting with "www." (without // before it, or it'd re-link the ones done above).
  3587. replacePattern2 = /(^|[^\/])(www\.[\S]+(\b|$))/gim;
  3588. replacedText = replacedText.replace(replacePattern2, '$1<a href="http://$2" target="_blank">$2</a>');
  3589. //Change email addresses to mailto:: links.
  3590. replacePattern3 = /(([a-zA-Z0-9\-\_\.])+@[a-zA-Z\_]+?(\.[a-zA-Z]{2,6})+)/gim;
  3591. replacedText = replacedText.replace(replacePattern3, '<a href="mailto:$1">$1</a>');
  3592. return replacedText;
  3593. }
  3594. /**
  3595. * Replaces common smiley strings with images
  3596. */
  3597. function smilify(body)
  3598. {
  3599. if(!body) {
  3600. return body;
  3601. }
  3602. var regexs = Smileys["regexs"];
  3603. for(var smiley in regexs) {
  3604. if(regexs.hasOwnProperty(smiley)) {
  3605. body = body.replace(regexs[smiley],
  3606. '<img class="smiley" src="images/smileys/' + smiley + '.svg">');
  3607. }
  3608. }
  3609. return body;
  3610. }
  3611. module.exports = {
  3612. processReplacements: processReplacements,
  3613. linkify: linkify
  3614. };
  3615. },{"./smileys.json":20}],20:[function(require,module,exports){
  3616. module.exports={
  3617. "smileys": {
  3618. "smiley1": ":)",
  3619. "smiley2": ":(",
  3620. "smiley3": ":D",
  3621. "smiley4": "(y)",
  3622. "smiley5": " :P",
  3623. "smiley6": "(wave)",
  3624. "smiley7": "(blush)",
  3625. "smiley8": "(chuckle)",
  3626. "smiley9": "(shocked)",
  3627. "smiley10": ":*",
  3628. "smiley11": "(n)",
  3629. "smiley12": "(search)",
  3630. "smiley13": " <3",
  3631. "smiley14": "(oops)",
  3632. "smiley15": "(angry)",
  3633. "smiley16": "(angel)",
  3634. "smiley17": "(sick)",
  3635. "smiley18": ";(",
  3636. "smiley19": "(bomb)",
  3637. "smiley20": "(clap)",
  3638. "smiley21": " ;)"
  3639. },
  3640. "regexs": {
  3641. "smiley2": /(:-\(\(|:-\(|:\(\(|:\(|\(sad\))/gi,
  3642. "smiley3": /(:-\)\)|:\)\)|\(lol\)|:-D|:D)/gi,
  3643. "smiley1": /(:-\)|:\))/gi,
  3644. "smiley4": /(\(y\)|\(Y\)|\(ok\))/gi,
  3645. "smiley5": /(:-P|:P|:-p|:p)/gi,
  3646. "smiley6": /(\(wave\))/gi,
  3647. "smiley7": /(\(blush\))/gi,
  3648. "smiley8": /(\(chuckle\))/gi,
  3649. "smiley9": /(:-0|\(shocked\))/gi,
  3650. "smiley10": /(:-\*|:\*|\(kiss\))/gi,
  3651. "smiley11": /(\(n\))/gi,
  3652. "smiley12": /(\(search\))/g,
  3653. "smiley13": /(<3|&lt;3|&amp;lt;3|\(L\)|\(l\)|\(H\)|\(h\))/gi,
  3654. "smiley14": /(\(oops\))/gi,
  3655. "smiley15": /(\(angry\))/gi,
  3656. "smiley16": /(\(angel\))/gi,
  3657. "smiley17": /(\(sick\))/gi,
  3658. "smiley18": /(;-\(\(|;\(\(|;-\(|;\(|:"\(|:"-\(|:~-\(|:~\(|\(upset\))/gi,
  3659. "smiley19": /(\(bomb\))/gi,
  3660. "smiley20": /(\(clap\))/gi,
  3661. "smiley21": /(;-\)|;\)|;-\)\)|;\)\)|;-D|;D|\(wink\))/gi
  3662. }
  3663. }
  3664. },{}],21:[function(require,module,exports){
  3665. var numberOfContacts = 0;
  3666. var notificationInterval;
  3667. /**
  3668. * Updates the number of participants in the contact list button and sets
  3669. * the glow
  3670. * @param delta indicates whether a new user has joined (1) or someone has
  3671. * left(-1)
  3672. */
  3673. function updateNumberOfParticipants(delta) {
  3674. //when the user is alone we don't show the number of participants
  3675. if(numberOfContacts === 0) {
  3676. $("#numberOfParticipants").text('');
  3677. numberOfContacts += delta;
  3678. } else if(numberOfContacts !== 0 && !ContactList.isVisible()) {
  3679. ContactList.setVisualNotification(true);
  3680. numberOfContacts += delta;
  3681. $("#numberOfParticipants").text(numberOfContacts);
  3682. }
  3683. }
  3684. /**
  3685. * Creates the avatar element.
  3686. *
  3687. * @return the newly created avatar element
  3688. */
  3689. function createAvatar(id) {
  3690. var avatar = document.createElement('img');
  3691. avatar.className = "icon-avatar avatar";
  3692. avatar.src = "https://www.gravatar.com/avatar/" + id + "?d=wavatar&size=30";
  3693. return avatar;
  3694. }
  3695. /**
  3696. * Creates the display name paragraph.
  3697. *
  3698. * @param displayName the display name to set
  3699. */
  3700. function createDisplayNameParagraph(displayName) {
  3701. var p = document.createElement('p');
  3702. p.innerText = displayName;
  3703. return p;
  3704. }
  3705. function stopGlowing(glower) {
  3706. window.clearInterval(notificationInterval);
  3707. notificationInterval = false;
  3708. glower.removeClass('glowing');
  3709. if (!ContactList.isVisible()) {
  3710. glower.removeClass('active');
  3711. }
  3712. }
  3713. /**
  3714. * Contact list.
  3715. */
  3716. var ContactList = {
  3717. /**
  3718. * Indicates if the chat is currently visible.
  3719. *
  3720. * @return <tt>true</tt> if the chat is currently visible, <tt>false</tt> -
  3721. * otherwise
  3722. */
  3723. isVisible: function () {
  3724. return $('#contactlist').is(":visible");
  3725. },
  3726. /**
  3727. * Adds a contact for the given peerJid if such doesn't yet exist.
  3728. *
  3729. * @param peerJid the peerJid corresponding to the contact
  3730. * @param id the user's email or userId used to get the user's avatar
  3731. */
  3732. ensureAddContact: function (peerJid, id) {
  3733. var resourceJid = Strophe.getResourceFromJid(peerJid);
  3734. var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
  3735. if (!contact || contact.length <= 0)
  3736. ContactList.addContact(peerJid, id);
  3737. },
  3738. /**
  3739. * Adds a contact for the given peer jid.
  3740. *
  3741. * @param peerJid the jid of the contact to add
  3742. * @param id the email or userId of the user
  3743. */
  3744. addContact: function (peerJid, id) {
  3745. var resourceJid = Strophe.getResourceFromJid(peerJid);
  3746. var contactlist = $('#contactlist>ul');
  3747. var newContact = document.createElement('li');
  3748. newContact.id = resourceJid;
  3749. newContact.className = "clickable";
  3750. newContact.onclick = function (event) {
  3751. if (event.currentTarget.className === "clickable") {
  3752. $(ContactList).trigger('contactclicked', [peerJid]);
  3753. }
  3754. };
  3755. newContact.appendChild(createAvatar(id));
  3756. newContact.appendChild(createDisplayNameParagraph("Participant"));
  3757. var clElement = contactlist.get(0);
  3758. if (resourceJid === APP.xmpp.myResource()
  3759. && $('#contactlist>ul .title')[0].nextSibling.nextSibling) {
  3760. clElement.insertBefore(newContact,
  3761. $('#contactlist>ul .title')[0].nextSibling.nextSibling);
  3762. }
  3763. else {
  3764. clElement.appendChild(newContact);
  3765. }
  3766. updateNumberOfParticipants(1);
  3767. },
  3768. /**
  3769. * Removes a contact for the given peer jid.
  3770. *
  3771. * @param peerJid the peerJid corresponding to the contact to remove
  3772. */
  3773. removeContact: function (peerJid) {
  3774. var resourceJid = Strophe.getResourceFromJid(peerJid);
  3775. var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
  3776. if (contact && contact.length > 0) {
  3777. var contactlist = $('#contactlist>ul');
  3778. contactlist.get(0).removeChild(contact.get(0));
  3779. updateNumberOfParticipants(-1);
  3780. }
  3781. },
  3782. setVisualNotification: function (show, stopGlowingIn) {
  3783. var glower = $('#contactListButton');
  3784. if (show && !notificationInterval) {
  3785. notificationInterval = window.setInterval(function () {
  3786. glower.toggleClass('active glowing');
  3787. }, 800);
  3788. }
  3789. else if (!show && notificationInterval) {
  3790. stopGlowing(glower);
  3791. }
  3792. if (stopGlowingIn) {
  3793. setTimeout(function () {
  3794. stopGlowing(glower);
  3795. }, stopGlowingIn);
  3796. }
  3797. },
  3798. setClickable: function (resourceJid, isClickable) {
  3799. var contact = $('#contactlist>ul>li[id="' + resourceJid + '"]');
  3800. if (isClickable) {
  3801. contact.addClass('clickable');
  3802. } else {
  3803. contact.removeClass('clickable');
  3804. }
  3805. },
  3806. onDisplayNameChange: function (peerJid, displayName) {
  3807. if (peerJid === 'localVideoContainer')
  3808. peerJid = APP.xmpp.myJid();
  3809. var resourceJid = Strophe.getResourceFromJid(peerJid);
  3810. var contactName = $('#contactlist #' + resourceJid + '>p');
  3811. if (contactName && displayName && displayName.length > 0)
  3812. contactName.html(displayName);
  3813. }
  3814. };
  3815. module.exports = ContactList;
  3816. },{}],22:[function(require,module,exports){
  3817. var email = '';
  3818. var displayName = '';
  3819. var userId;
  3820. function supportsLocalStorage() {
  3821. try {
  3822. return 'localStorage' in window && window.localStorage !== null;
  3823. } catch (e) {
  3824. console.log("localstorage is not supported");
  3825. return false;
  3826. }
  3827. }
  3828. function generateUniqueId() {
  3829. function _p8() {
  3830. return (Math.random().toString(16)+"000000000").substr(2,8);
  3831. }
  3832. return _p8() + _p8() + _p8() + _p8();
  3833. }
  3834. if(supportsLocalStorage()) {
  3835. if(!window.localStorage.jitsiMeetId) {
  3836. window.localStorage.jitsiMeetId = generateUniqueId();
  3837. console.log("generated id", window.localStorage.jitsiMeetId);
  3838. }
  3839. userId = window.localStorage.jitsiMeetId || '';
  3840. email = window.localStorage.email || '';
  3841. displayName = window.localStorage.displayname || '';
  3842. } else {
  3843. console.log("local storage is not supported");
  3844. userId = generateUniqueId();
  3845. }
  3846. var Settings =
  3847. {
  3848. setDisplayName: function (newDisplayName) {
  3849. displayName = newDisplayName;
  3850. window.localStorage.displayname = displayName;
  3851. return displayName;
  3852. },
  3853. setEmail: function(newEmail)
  3854. {
  3855. email = newEmail;
  3856. window.localStorage.email = newEmail;
  3857. return email;
  3858. },
  3859. getSettings: function () {
  3860. return {
  3861. email: email,
  3862. displayName: displayName,
  3863. uid: userId
  3864. };
  3865. }
  3866. };
  3867. module.exports = Settings;
  3868. },{}],23:[function(require,module,exports){
  3869. var Avatar = require("../../avatar/Avatar");
  3870. var Settings = require("./Settings");
  3871. var UIUtil = require("../../util/UIUtil");
  3872. var languages = require("../../../../service/translation/languages");
  3873. function generateLanguagesSelectBox()
  3874. {
  3875. var currentLang = APP.translation.getCurrentLanguage();
  3876. var html = "<select id=\"languages_selectbox\">";
  3877. var langArray = languages.getLanguages();
  3878. for(var i = 0; i < langArray.length; i++)
  3879. {
  3880. var lang = langArray[i];
  3881. html += "<option ";
  3882. if(lang === currentLang)
  3883. html += "selected ";
  3884. html += "value=\"" + lang + "\" data-i18n='languages:" + lang + "'>";
  3885. html += "</option>";
  3886. }
  3887. return html + "</select>";
  3888. }
  3889. var SettingsMenu = {
  3890. init: function () {
  3891. $("#updateSettings").before(generateLanguagesSelectBox());
  3892. $('#settingsmenu>input').keyup(function(event){
  3893. if(event.keyCode === 13) {//enter
  3894. SettingsMenu.update();
  3895. }
  3896. });
  3897. $("#updateSettings").click(function () {
  3898. SettingsMenu.update();
  3899. });
  3900. },
  3901. update: function() {
  3902. var newDisplayName = UIUtil.escapeHtml($('#setDisplayName').get(0).value);
  3903. var newEmail = UIUtil.escapeHtml($('#setEmail').get(0).value);
  3904. if(newDisplayName) {
  3905. var displayName = Settings.setDisplayName(newDisplayName);
  3906. APP.xmpp.addToPresence("displayName", displayName, true);
  3907. }
  3908. APP.translation.setLanguage($("#languages_selectbox").val());
  3909. APP.xmpp.addToPresence("email", newEmail);
  3910. var email = Settings.setEmail(newEmail);
  3911. Avatar.setUserAvatar(APP.xmpp.myJid(), email);
  3912. },
  3913. isVisible: function() {
  3914. return $('#settingsmenu').is(':visible');
  3915. },
  3916. setDisplayName: function(newDisplayName) {
  3917. var displayName = Settings.setDisplayName(newDisplayName);
  3918. $('#setDisplayName').get(0).value = displayName;
  3919. },
  3920. onDisplayNameChange: function(peerJid, newDisplayName) {
  3921. if(peerJid === 'localVideoContainer' ||
  3922. peerJid === APP.xmpp.myJid()) {
  3923. this.setDisplayName(newDisplayName);
  3924. }
  3925. }
  3926. };
  3927. module.exports = SettingsMenu;
  3928. },{"../../../../service/translation/languages":85,"../../avatar/Avatar":12,"../../util/UIUtil":30,"./Settings":22}],24:[function(require,module,exports){
  3929. var PanelToggler = require("../side_pannels/SidePanelToggler");
  3930. var buttonHandlers = {
  3931. "bottom_toolbar_contact_list": function () {
  3932. BottomToolbar.toggleContactList();
  3933. },
  3934. "bottom_toolbar_film_strip": function () {
  3935. BottomToolbar.toggleFilmStrip();
  3936. },
  3937. "bottom_toolbar_chat": function () {
  3938. BottomToolbar.toggleChat();
  3939. }
  3940. };
  3941. var BottomToolbar = (function (my) {
  3942. my.init = function () {
  3943. for(var k in buttonHandlers)
  3944. $("#" + k).click(buttonHandlers[k]);
  3945. };
  3946. my.toggleChat = function() {
  3947. PanelToggler.toggleChat();
  3948. };
  3949. my.toggleContactList = function() {
  3950. PanelToggler.toggleContactList();
  3951. };
  3952. my.toggleFilmStrip = function() {
  3953. var filmstrip = $("#remoteVideos");
  3954. filmstrip.toggleClass("hidden");
  3955. };
  3956. $(document).bind("remotevideo.resized", function (event, width, height) {
  3957. var bottom = (height - $('#bottomToolbar').outerHeight())/2 + 18;
  3958. $('#bottomToolbar').css({bottom: bottom + 'px'});
  3959. });
  3960. return my;
  3961. }(BottomToolbar || {}));
  3962. module.exports = BottomToolbar;
  3963. },{"../side_pannels/SidePanelToggler":16}],25:[function(require,module,exports){
  3964. /* global $, buttonClick, config, lockRoom,
  3965. setSharedKey, Util */
  3966. var messageHandler = require("../util/MessageHandler");
  3967. var BottomToolbar = require("./BottomToolbar");
  3968. var Prezi = require("../prezi/Prezi");
  3969. var Etherpad = require("../etherpad/Etherpad");
  3970. var PanelToggler = require("../side_pannels/SidePanelToggler");
  3971. var Authentication = require("../authentication/Authentication");
  3972. var UIUtil = require("../util/UIUtil");
  3973. var roomUrl = null;
  3974. var sharedKey = '';
  3975. var UI = null;
  3976. var buttonHandlers =
  3977. {
  3978. "toolbar_button_mute": function () {
  3979. return APP.UI.toggleAudio();
  3980. },
  3981. "toolbar_button_camera": function () {
  3982. return APP.UI.toggleVideo();
  3983. },
  3984. "toolbar_button_authentication": function () {
  3985. return Toolbar.authenticateClicked();
  3986. },
  3987. "toolbar_button_record": function () {
  3988. return toggleRecording();
  3989. },
  3990. "toolbar_button_security": function () {
  3991. return Toolbar.openLockDialog();
  3992. },
  3993. "toolbar_button_link": function () {
  3994. return Toolbar.openLinkDialog();
  3995. },
  3996. "toolbar_button_chat": function () {
  3997. return BottomToolbar.toggleChat();
  3998. },
  3999. "toolbar_button_prezi": function () {
  4000. return Prezi.openPreziDialog();
  4001. },
  4002. "toolbar_button_etherpad": function () {
  4003. return Etherpad.toggleEtherpad(0);
  4004. },
  4005. "toolbar_button_desktopsharing": function () {
  4006. return APP.desktopsharing.toggleScreenSharing();
  4007. },
  4008. "toolbar_button_fullScreen": function()
  4009. {
  4010. UIUtil.buttonClick("#fullScreen", "icon-full-screen icon-exit-full-screen");
  4011. return Toolbar.toggleFullScreen();
  4012. },
  4013. "toolbar_button_sip": function () {
  4014. return callSipButtonClicked();
  4015. },
  4016. "toolbar_button_settings": function () {
  4017. PanelToggler.toggleSettingsMenu();
  4018. },
  4019. "toolbar_button_hangup": function () {
  4020. return hangup();
  4021. }
  4022. };
  4023. function hangup() {
  4024. APP.xmpp.disposeConference();
  4025. if(config.enableWelcomePage)
  4026. {
  4027. setTimeout(function()
  4028. {
  4029. window.localStorage.welcomePageDisabled = false;
  4030. window.location.pathname = "/";
  4031. }, 10000);
  4032. }
  4033. UI.messageHandler.openDialog(
  4034. "Session Terminated",
  4035. "You hung up the call",
  4036. true,
  4037. { "Join again": true },
  4038. function(event, value, message, formVals)
  4039. {
  4040. window.location.reload();
  4041. return false;
  4042. }
  4043. );
  4044. }
  4045. /**
  4046. * Starts or stops the recording for the conference.
  4047. */
  4048. function toggleRecording() {
  4049. APP.xmpp.toggleRecording(function (callback) {
  4050. APP.UI.messageHandler.openTwoButtonDialog(null,
  4051. '<h2>Enter recording token</h2>' +
  4052. '<input id="recordingToken" type="text" ' +
  4053. 'placeholder="token" autofocus>',
  4054. false,
  4055. "Save",
  4056. function (e, v, m, f) {
  4057. if (v) {
  4058. var token = document.getElementById('recordingToken');
  4059. if (token.value) {
  4060. callback(UIUtil.escapeHtml(token.value));
  4061. }
  4062. }
  4063. },
  4064. function (event) {
  4065. document.getElementById('recordingToken').focus();
  4066. },
  4067. function () {
  4068. }
  4069. );
  4070. }, Toolbar.setRecordingButtonState, Toolbar.setRecordingButtonState);
  4071. }
  4072. /**
  4073. * Locks / unlocks the room.
  4074. */
  4075. function lockRoom(lock) {
  4076. var currentSharedKey = '';
  4077. if (lock)
  4078. currentSharedKey = sharedKey;
  4079. APP.xmpp.lockRoom(currentSharedKey, function (res) {
  4080. // password is required
  4081. if (sharedKey)
  4082. {
  4083. console.log('set room password');
  4084. Toolbar.lockLockButton();
  4085. }
  4086. else
  4087. {
  4088. console.log('removed room password');
  4089. Toolbar.unlockLockButton();
  4090. }
  4091. }, function (err) {
  4092. console.warn('setting password failed', err);
  4093. messageHandler.showError('Lock failed',
  4094. 'Failed to lock conference.',
  4095. err);
  4096. Toolbar.setSharedKey('');
  4097. }, function () {
  4098. console.warn('room passwords not supported');
  4099. messageHandler.showError('Warning',
  4100. 'Room passwords are currently not supported.');
  4101. Toolbar.setSharedKey('');
  4102. });
  4103. };
  4104. /**
  4105. * Invite participants to conference.
  4106. */
  4107. function inviteParticipants() {
  4108. if (roomUrl === null)
  4109. return;
  4110. var sharedKeyText = "";
  4111. if (sharedKey && sharedKey.length > 0) {
  4112. sharedKeyText =
  4113. "This conference is password protected. Please use the " +
  4114. "following pin when joining:%0D%0A%0D%0A" +
  4115. sharedKey + "%0D%0A%0D%0A";
  4116. }
  4117. var conferenceName = roomUrl.substring(roomUrl.lastIndexOf('/') + 1);
  4118. var subject = "Invitation to a " + interfaceConfig.APP_NAME + " (" + conferenceName + ")";
  4119. var body = "Hey there, I%27d like to invite you to a " + interfaceConfig.APP_NAME +
  4120. " conference I%27ve just set up.%0D%0A%0D%0A" +
  4121. "Please click on the following link in order" +
  4122. " to join the conference.%0D%0A%0D%0A" +
  4123. roomUrl +
  4124. "%0D%0A%0D%0A" +
  4125. sharedKeyText +
  4126. "Note that " + interfaceConfig.APP_NAME + " is currently" +
  4127. " only supported by Chromium," +
  4128. " Google Chrome and Opera, so you need" +
  4129. " to be using one of these browsers.%0D%0A%0D%0A" +
  4130. "Talk to you in a sec!";
  4131. if (window.localStorage.displayname) {
  4132. body += "%0D%0A%0D%0A" + window.localStorage.displayname;
  4133. }
  4134. if (interfaceConfig.INVITATION_POWERED_BY) {
  4135. body += "%0D%0A%0D%0A--%0D%0Apowered by jitsi.org";
  4136. }
  4137. window.open("mailto:?subject=" + subject + "&body=" + body, '_blank');
  4138. }
  4139. function callSipButtonClicked()
  4140. {
  4141. var defaultNumber
  4142. = config.defaultSipNumber ? config.defaultSipNumber : '';
  4143. messageHandler.openTwoButtonDialog(null,
  4144. '<h2>Enter SIP number</h2>' +
  4145. '<input id="sipNumber" type="text"' +
  4146. ' value="' + defaultNumber + '" autofocus>',
  4147. false,
  4148. "Dial",
  4149. function (e, v, m, f) {
  4150. if (v) {
  4151. var numberInput = document.getElementById('sipNumber');
  4152. if (numberInput.value) {
  4153. APP.xmpp.dial(numberInput.value, 'fromnumber',
  4154. UI.getRoomName(), sharedKey);
  4155. }
  4156. }
  4157. },
  4158. function (event) {
  4159. document.getElementById('sipNumber').focus();
  4160. }
  4161. );
  4162. }
  4163. var Toolbar = (function (my) {
  4164. my.init = function (ui) {
  4165. for(var k in buttonHandlers)
  4166. $("#" + k).click(buttonHandlers[k]);
  4167. UI = ui;
  4168. }
  4169. /**
  4170. * Sets shared key
  4171. * @param sKey the shared key
  4172. */
  4173. my.setSharedKey = function (sKey) {
  4174. sharedKey = sKey;
  4175. };
  4176. my.authenticateClicked = function () {
  4177. Authentication.focusAuthenticationWindow();
  4178. // Get authentication URL
  4179. APP.xmpp.getAuthUrl(APP.UI.getRoomName(), function (url) {
  4180. // Open popup with authentication URL
  4181. var authenticationWindow = Authentication.createAuthenticationWindow(function () {
  4182. // On popup closed - retry room allocation
  4183. APP.xmpp.allocateConferenceFocus(APP.UI.getRoomName(), APP.UI.checkForNicknameAndJoin);
  4184. }, url);
  4185. if (!authenticationWindow) {
  4186. Toolbar.showAuthenticateButton(true);
  4187. messageHandler.openMessageDialog(
  4188. null, "Your browser is blocking popup windows from this site." +
  4189. " Please enable popups in your browser security settings" +
  4190. " and try again.");
  4191. }
  4192. });
  4193. };
  4194. /**
  4195. * Updates the room invite url.
  4196. */
  4197. my.updateRoomUrl = function (newRoomUrl) {
  4198. roomUrl = newRoomUrl;
  4199. // If the invite dialog has been already opened we update the information.
  4200. var inviteLink = document.getElementById('inviteLinkRef');
  4201. if (inviteLink) {
  4202. inviteLink.value = roomUrl;
  4203. inviteLink.select();
  4204. document.getElementById('jqi_state0_buttonInvite').disabled = false;
  4205. }
  4206. };
  4207. /**
  4208. * Disables and enables some of the buttons.
  4209. */
  4210. my.setupButtonsFromConfig = function () {
  4211. if (config.disablePrezi)
  4212. {
  4213. $("#prezi_button").css({display: "none"});
  4214. }
  4215. };
  4216. /**
  4217. * Opens the lock room dialog.
  4218. */
  4219. my.openLockDialog = function () {
  4220. // Only the focus is able to set a shared key.
  4221. if (!APP.xmpp.isModerator()) {
  4222. if (sharedKey) {
  4223. messageHandler.openMessageDialog(null,
  4224. "This conversation is currently protected by" +
  4225. " a password. Only the owner of the conference" +
  4226. " could set a password.",
  4227. false,
  4228. "Password");
  4229. } else {
  4230. messageHandler.openMessageDialog(null,
  4231. "This conversation isn't currently protected by" +
  4232. " a password. Only the owner of the conference" +
  4233. " could set a password.",
  4234. false,
  4235. "Password");
  4236. }
  4237. } else {
  4238. if (sharedKey) {
  4239. messageHandler.openTwoButtonDialog(null,
  4240. "Are you sure you would like to remove your password?",
  4241. false,
  4242. "Remove",
  4243. function (e, v) {
  4244. if (v) {
  4245. Toolbar.setSharedKey('');
  4246. lockRoom(false);
  4247. }
  4248. });
  4249. } else {
  4250. messageHandler.openTwoButtonDialog(null,
  4251. '<h2>Set a password to lock your room</h2>' +
  4252. '<input id="lockKey" type="text"' +
  4253. 'placeholder="your password" autofocus>',
  4254. false,
  4255. "Save",
  4256. function (e, v) {
  4257. if (v) {
  4258. var lockKey = document.getElementById('lockKey');
  4259. if (lockKey.value) {
  4260. Toolbar.setSharedKey(UIUtil.escapeHtml(lockKey.value));
  4261. lockRoom(true);
  4262. }
  4263. }
  4264. },
  4265. function () {
  4266. document.getElementById('lockKey').focus();
  4267. }
  4268. );
  4269. }
  4270. }
  4271. };
  4272. /**
  4273. * Opens the invite link dialog.
  4274. */
  4275. my.openLinkDialog = function () {
  4276. var inviteLink;
  4277. if (roomUrl === null) {
  4278. inviteLink = "Your conference is currently being created...";
  4279. } else {
  4280. inviteLink = encodeURI(roomUrl);
  4281. }
  4282. messageHandler.openTwoButtonDialog(
  4283. "Share this link with everyone you want to invite",
  4284. '<input id="inviteLinkRef" type="text" value="' +
  4285. inviteLink + '" onclick="this.select();" readonly>',
  4286. false,
  4287. "Invite",
  4288. function (e, v) {
  4289. if (v) {
  4290. if (roomUrl) {
  4291. inviteParticipants();
  4292. }
  4293. }
  4294. },
  4295. function () {
  4296. if (roomUrl) {
  4297. document.getElementById('inviteLinkRef').select();
  4298. } else {
  4299. document.getElementById('jqi_state0_buttonInvite')
  4300. .disabled = true;
  4301. }
  4302. }
  4303. );
  4304. };
  4305. /**
  4306. * Opens the settings dialog.
  4307. */
  4308. my.openSettingsDialog = function () {
  4309. messageHandler.openTwoButtonDialog(
  4310. '<h2>Configure your conference</h2>' +
  4311. '<input type="checkbox" id="initMuted">' +
  4312. 'Participants join muted<br/>' +
  4313. '<input type="checkbox" id="requireNicknames">' +
  4314. 'Require nicknames<br/><br/>' +
  4315. 'Set a password to lock your room:' +
  4316. '<input id="lockKey" type="text" placeholder="your password"' +
  4317. 'autofocus>',
  4318. null,
  4319. false,
  4320. "Save",
  4321. function () {
  4322. document.getElementById('lockKey').focus();
  4323. },
  4324. function (e, v) {
  4325. if (v) {
  4326. if ($('#initMuted').is(":checked")) {
  4327. // it is checked
  4328. }
  4329. if ($('#requireNicknames').is(":checked")) {
  4330. // it is checked
  4331. }
  4332. /*
  4333. var lockKey = document.getElementById('lockKey');
  4334. if (lockKey.value) {
  4335. setSharedKey(lockKey.value);
  4336. lockRoom(true);
  4337. }
  4338. */
  4339. }
  4340. }
  4341. );
  4342. };
  4343. /**
  4344. * Toggles the application in and out of full screen mode
  4345. * (a.k.a. presentation mode in Chrome).
  4346. */
  4347. my.toggleFullScreen = function () {
  4348. var fsElement = document.documentElement;
  4349. if (!document.mozFullScreen && !document.webkitIsFullScreen) {
  4350. //Enter Full Screen
  4351. if (fsElement.mozRequestFullScreen) {
  4352. fsElement.mozRequestFullScreen();
  4353. }
  4354. else {
  4355. fsElement.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT);
  4356. }
  4357. } else {
  4358. //Exit Full Screen
  4359. if (document.mozCancelFullScreen) {
  4360. document.mozCancelFullScreen();
  4361. } else {
  4362. document.webkitCancelFullScreen();
  4363. }
  4364. }
  4365. };
  4366. /**
  4367. * Unlocks the lock button state.
  4368. */
  4369. my.unlockLockButton = function () {
  4370. if ($("#lockIcon").hasClass("icon-security-locked"))
  4371. UIUtil.buttonClick("#lockIcon", "icon-security icon-security-locked");
  4372. };
  4373. /**
  4374. * Updates the lock button state to locked.
  4375. */
  4376. my.lockLockButton = function () {
  4377. if ($("#lockIcon").hasClass("icon-security"))
  4378. UIUtil.buttonClick("#lockIcon", "icon-security icon-security-locked");
  4379. };
  4380. /**
  4381. * Shows or hides authentication button
  4382. * @param show <tt>true</tt> to show or <tt>false</tt> to hide
  4383. */
  4384. my.showAuthenticateButton = function (show) {
  4385. if (show) {
  4386. $('#authentication').css({display: "inline"});
  4387. }
  4388. else {
  4389. $('#authentication').css({display: "none"});
  4390. }
  4391. };
  4392. // Shows or hides the 'recording' button.
  4393. my.showRecordingButton = function (show) {
  4394. if (!config.enableRecording) {
  4395. return;
  4396. }
  4397. if (show) {
  4398. $('#recording').css({display: "inline"});
  4399. }
  4400. else {
  4401. $('#recording').css({display: "none"});
  4402. }
  4403. };
  4404. // Sets the state of the recording button
  4405. my.setRecordingButtonState = function (isRecording) {
  4406. if (isRecording) {
  4407. $('#recordButton').removeClass("icon-recEnable");
  4408. $('#recordButton').addClass("icon-recEnable active");
  4409. } else {
  4410. $('#recordButton').removeClass("icon-recEnable active");
  4411. $('#recordButton').addClass("icon-recEnable");
  4412. }
  4413. };
  4414. // Shows or hides SIP calls button
  4415. my.showSipCallButton = function (show) {
  4416. if (APP.xmpp.isSipGatewayEnabled() && show) {
  4417. $('#sipCallButton').css({display: "inline"});
  4418. } else {
  4419. $('#sipCallButton').css({display: "none"});
  4420. }
  4421. };
  4422. /**
  4423. * Sets the state of the button. The button has blue glow if desktop
  4424. * streaming is active.
  4425. * @param active the state of the desktop streaming.
  4426. */
  4427. my.changeDesktopSharingButtonState = function (active) {
  4428. var button = $("#desktopsharing > a");
  4429. if (active)
  4430. {
  4431. button.addClass("glow");
  4432. }
  4433. else
  4434. {
  4435. button.removeClass("glow");
  4436. }
  4437. };
  4438. return my;
  4439. }(Toolbar || {}));
  4440. module.exports = Toolbar;
  4441. },{"../authentication/Authentication":11,"../etherpad/Etherpad":13,"../prezi/Prezi":14,"../side_pannels/SidePanelToggler":16,"../util/MessageHandler":28,"../util/UIUtil":30,"./BottomToolbar":24}],26:[function(require,module,exports){
  4442. /* global $, interfaceConfig, Moderator, DesktopStreaming.showDesktopSharingButton */
  4443. var toolbarTimeoutObject,
  4444. toolbarTimeout = interfaceConfig.INITIAL_TOOLBAR_TIMEOUT;
  4445. function showDesktopSharingButton() {
  4446. if (APP.desktopsharing.isDesktopSharingEnabled()) {
  4447. $('#desktopsharing').css({display: "inline"});
  4448. } else {
  4449. $('#desktopsharing').css({display: "none"});
  4450. }
  4451. }
  4452. /**
  4453. * Hides the toolbar.
  4454. */
  4455. function hideToolbar() {
  4456. var header = $("#header"),
  4457. bottomToolbar = $("#bottomToolbar");
  4458. var isToolbarHover = false;
  4459. header.find('*').each(function () {
  4460. var id = $(this).attr('id');
  4461. if ($("#" + id + ":hover").length > 0) {
  4462. isToolbarHover = true;
  4463. }
  4464. });
  4465. if ($("#bottomToolbar:hover").length > 0) {
  4466. isToolbarHover = true;
  4467. }
  4468. clearTimeout(toolbarTimeoutObject);
  4469. toolbarTimeoutObject = null;
  4470. if (!isToolbarHover) {
  4471. header.hide("slide", { direction: "up", duration: 300});
  4472. $('#subject').animate({top: "-=40"}, 300);
  4473. if ($("#remoteVideos").hasClass("hidden")) {
  4474. bottomToolbar.hide(
  4475. "slide", {direction: "right", duration: 300});
  4476. }
  4477. }
  4478. else {
  4479. toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
  4480. }
  4481. }
  4482. var ToolbarToggler = {
  4483. /**
  4484. * Shows the main toolbar.
  4485. */
  4486. showToolbar: function () {
  4487. var header = $("#header"),
  4488. bottomToolbar = $("#bottomToolbar");
  4489. if (!header.is(':visible') || !bottomToolbar.is(":visible")) {
  4490. header.show("slide", { direction: "up", duration: 300});
  4491. $('#subject').animate({top: "+=40"}, 300);
  4492. if (!bottomToolbar.is(":visible")) {
  4493. bottomToolbar.show(
  4494. "slide", {direction: "right", duration: 300});
  4495. }
  4496. if (toolbarTimeoutObject) {
  4497. clearTimeout(toolbarTimeoutObject);
  4498. toolbarTimeoutObject = null;
  4499. }
  4500. toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
  4501. toolbarTimeout = interfaceConfig.TOOLBAR_TIMEOUT;
  4502. }
  4503. if (APP.xmpp.isModerator())
  4504. {
  4505. // TODO: Enable settings functionality.
  4506. // Need to uncomment the settings button in index.html.
  4507. // $('#settingsButton').css({visibility:"visible"});
  4508. }
  4509. // Show/hide desktop sharing button
  4510. showDesktopSharingButton();
  4511. },
  4512. /**
  4513. * Docks/undocks the toolbar.
  4514. *
  4515. * @param isDock indicates what operation to perform
  4516. */
  4517. dockToolbar: function (isDock) {
  4518. if (isDock) {
  4519. // First make sure the toolbar is shown.
  4520. if (!$('#header').is(':visible')) {
  4521. this.showToolbar();
  4522. }
  4523. // Then clear the time out, to dock the toolbar.
  4524. if (toolbarTimeoutObject) {
  4525. clearTimeout(toolbarTimeoutObject);
  4526. toolbarTimeoutObject = null;
  4527. }
  4528. }
  4529. else {
  4530. if (!$('#header').is(':visible')) {
  4531. this.showToolbar();
  4532. }
  4533. else {
  4534. toolbarTimeoutObject = setTimeout(hideToolbar, toolbarTimeout);
  4535. }
  4536. }
  4537. },
  4538. showDesktopSharingButton: showDesktopSharingButton
  4539. };
  4540. module.exports = ToolbarToggler;
  4541. },{}],27:[function(require,module,exports){
  4542. var JitsiPopover = (function () {
  4543. /**
  4544. * Constructs new JitsiPopover and attaches it to the element
  4545. * @param element jquery selector
  4546. * @param options the options for the popover.
  4547. * @constructor
  4548. */
  4549. function JitsiPopover(element, options)
  4550. {
  4551. this.options = {
  4552. skin: "white",
  4553. content: ""
  4554. };
  4555. if(options)
  4556. {
  4557. if(options.skin)
  4558. this.options.skin = options.skin;
  4559. if(options.content)
  4560. this.options.content = options.content;
  4561. }
  4562. this.elementIsHovered = false;
  4563. this.popoverIsHovered = false;
  4564. this.popoverShown = false;
  4565. element.data("jitsi_popover", this);
  4566. this.element = element;
  4567. this.template = ' <div class="jitsipopover ' + this.options.skin +
  4568. '"><div class="arrow"></div><div class="jitsipopover-content"></div>' +
  4569. '<div class="jitsiPopupmenuPadding"></div></div>';
  4570. var self = this;
  4571. this.element.on("mouseenter", function () {
  4572. self.elementIsHovered = true;
  4573. self.show();
  4574. }).on("mouseleave", function () {
  4575. self.elementIsHovered = false;
  4576. setTimeout(function () {
  4577. self.hide();
  4578. }, 10);
  4579. });
  4580. }
  4581. /**
  4582. * Shows the popover
  4583. */
  4584. JitsiPopover.prototype.show = function () {
  4585. this.createPopover();
  4586. this.popoverShown = true;
  4587. };
  4588. /**
  4589. * Hides the popover
  4590. */
  4591. JitsiPopover.prototype.hide = function () {
  4592. if(!this.elementIsHovered && !this.popoverIsHovered && this.popoverShown)
  4593. {
  4594. this.forceHide();
  4595. }
  4596. };
  4597. /**
  4598. * Hides the popover
  4599. */
  4600. JitsiPopover.prototype.forceHide = function () {
  4601. $(".jitsipopover").remove();
  4602. this.popoverShown = false;
  4603. };
  4604. /**
  4605. * Creates the popover html
  4606. */
  4607. JitsiPopover.prototype.createPopover = function () {
  4608. $("body").append(this.template);
  4609. $(".jitsipopover > .jitsipopover-content").html(this.options.content);
  4610. var self = this;
  4611. $(".jitsipopover").on("mouseenter", function () {
  4612. self.popoverIsHovered = true;
  4613. }).on("mouseleave", function () {
  4614. self.popoverIsHovered = false;
  4615. self.hide();
  4616. });
  4617. this.refreshPosition();
  4618. };
  4619. /**
  4620. * Refreshes the position of the popover
  4621. */
  4622. JitsiPopover.prototype.refreshPosition = function () {
  4623. $(".jitsipopover").position({
  4624. my: "bottom",
  4625. at: "top",
  4626. collision: "fit",
  4627. of: this.element,
  4628. using: function (position, elements) {
  4629. var calcLeft = elements.target.left - elements.element.left + elements.target.width/2;
  4630. $(".jitsipopover").css({top: position.top, left: position.left, display: "table"});
  4631. $(".jitsipopover > .arrow").css({left: calcLeft});
  4632. $(".jitsipopover > .jitsiPopupmenuPadding").css({left: calcLeft - 50});
  4633. }
  4634. });
  4635. };
  4636. /**
  4637. * Updates the content of popover.
  4638. * @param content new content
  4639. */
  4640. JitsiPopover.prototype.updateContent = function (content) {
  4641. this.options.content = content;
  4642. if(!this.popoverShown)
  4643. return;
  4644. $(".jitsipopover").remove();
  4645. this.createPopover();
  4646. };
  4647. return JitsiPopover;
  4648. })();
  4649. module.exports = JitsiPopover;
  4650. },{}],28:[function(require,module,exports){
  4651. /* global $, jQuery */
  4652. var messageHandler = (function(my) {
  4653. /**
  4654. * Shows a message to the user.
  4655. *
  4656. * @param titleString the title of the message
  4657. * @param messageString the text of the message
  4658. */
  4659. my.openMessageDialog = function(titleString, messageString) {
  4660. $.prompt(messageString,
  4661. {
  4662. title: titleString,
  4663. persistent: false
  4664. }
  4665. );
  4666. };
  4667. /**
  4668. * Shows a message to the user with two buttons: first is given as a parameter and the second is Cancel.
  4669. *
  4670. * @param titleString the title of the message
  4671. * @param msgString the text of the message
  4672. * @param persistent boolean value which determines whether the message is persistent or not
  4673. * @param leftButton the fist button's text
  4674. * @param submitFunction function to be called on submit
  4675. * @param loadedFunction function to be called after the prompt is fully loaded
  4676. * @param closeFunction function to be called after the prompt is closed
  4677. */
  4678. my.openTwoButtonDialog = function(titleString, msgString, persistent, leftButton,
  4679. submitFunction, loadedFunction, closeFunction) {
  4680. var buttons = {};
  4681. buttons[leftButton] = true;
  4682. buttons.Cancel = false;
  4683. $.prompt(msgString, {
  4684. title: titleString,
  4685. persistent: false,
  4686. buttons: buttons,
  4687. defaultButton: 1,
  4688. loaded: loadedFunction,
  4689. submit: submitFunction,
  4690. close: closeFunction
  4691. });
  4692. };
  4693. /**
  4694. * Shows a message to the user with two buttons: first is given as a parameter and the second is Cancel.
  4695. *
  4696. * @param titleString the title of the message
  4697. * @param msgString the text of the message
  4698. * @param persistent boolean value which determines whether the message is persistent or not
  4699. * @param buttons object with the buttons. The keys must be the name of the button and value is the value
  4700. * that will be passed to submitFunction
  4701. * @param submitFunction function to be called on submit
  4702. * @param loadedFunction function to be called after the prompt is fully loaded
  4703. */
  4704. my.openDialog = function (titleString, msgString, persistent, buttons,
  4705. submitFunction, loadedFunction) {
  4706. var args = {
  4707. title: titleString,
  4708. persistent: persistent,
  4709. buttons: buttons,
  4710. defaultButton: 1,
  4711. loaded: loadedFunction,
  4712. submit: submitFunction
  4713. };
  4714. if (persistent) {
  4715. args.closeText = '';
  4716. }
  4717. return $.prompt(msgString, args);
  4718. };
  4719. /**
  4720. * Closes currently opened dialog.
  4721. */
  4722. my.closeDialog = function () {
  4723. $.prompt.close();
  4724. };
  4725. /**
  4726. * Shows a dialog with different states to the user.
  4727. *
  4728. * @param statesObject object containing all the states of the dialog
  4729. * @param loadedFunction function to be called after the prompt is fully loaded
  4730. * @param stateChangedFunction function to be called when the state of the dialog is changed
  4731. */
  4732. my.openDialogWithStates = function(statesObject, loadedFunction, stateChangedFunction) {
  4733. var myPrompt = $.prompt(statesObject);
  4734. myPrompt.on('impromptu:loaded', loadedFunction);
  4735. myPrompt.on('impromptu:statechanged', stateChangedFunction);
  4736. };
  4737. /**
  4738. * Opens new popup window for given <tt>url</tt> centered over current
  4739. * window.
  4740. *
  4741. * @param url the URL to be displayed in the popup window
  4742. * @param w the width of the popup window
  4743. * @param h the height of the popup window
  4744. * @param onPopupClosed optional callback function called when popup window
  4745. * has been closed.
  4746. *
  4747. * @returns popup window object if opened successfully or undefined
  4748. * in case we failed to open it(popup blocked)
  4749. */
  4750. my.openCenteredPopup = function (url, w, h, onPopupClosed) {
  4751. var l = window.screenX + (window.innerWidth / 2) - (w / 2);
  4752. var t = window.screenY + (window.innerHeight / 2) - (h / 2);
  4753. var popup = window.open(
  4754. url, '_blank',
  4755. 'top=' + t + ', left=' + l + ', width=' + w + ', height=' + h + '');
  4756. if (popup && onPopupClosed) {
  4757. var pollTimer = window.setInterval(function () {
  4758. if (popup.closed !== false) {
  4759. window.clearInterval(pollTimer);
  4760. onPopupClosed();
  4761. }
  4762. }, 200);
  4763. }
  4764. return popup;
  4765. };
  4766. /**
  4767. * Shows a dialog prompting the user to send an error report.
  4768. *
  4769. * @param titleString the title of the message
  4770. * @param msgString the text of the message
  4771. * @param error the error that is being reported
  4772. */
  4773. my.openReportDialog = function(titleString, msgString, error) {
  4774. my.openMessageDialog(titleString, msgString);
  4775. console.log(error);
  4776. //FIXME send the error to the server
  4777. };
  4778. /**
  4779. * Shows an error dialog to the user.
  4780. * @param title the title of the message
  4781. * @param message the text of the messafe
  4782. */
  4783. my.showError = function(title, message) {
  4784. if(!(title || message)) {
  4785. title = title || "Oops!";
  4786. message = message || "There was some kind of error";
  4787. }
  4788. messageHandler.openMessageDialog(title, message);
  4789. };
  4790. my.notify = function(displayName, cls, message) {
  4791. toastr.info(
  4792. '<span class="nickname">' +
  4793. displayName +
  4794. '</span><br>' +
  4795. '<span class=' + cls + '>' +
  4796. message +
  4797. '</span>');
  4798. };
  4799. return my;
  4800. }(messageHandler || {}));
  4801. module.exports = messageHandler;
  4802. },{}],29:[function(require,module,exports){
  4803. var UIEvents = require("../../../service/UI/UIEvents");
  4804. var nickname = null;
  4805. var eventEmitter = null;
  4806. var NickanameHandler = {
  4807. init: function (emitter) {
  4808. eventEmitter = emitter;
  4809. var storedDisplayName = window.localStorage.displayname;
  4810. if (storedDisplayName) {
  4811. nickname = storedDisplayName;
  4812. }
  4813. },
  4814. setNickname: function (newNickname) {
  4815. if (!newNickname || nickname === newNickname)
  4816. return;
  4817. nickname = newNickname;
  4818. window.localStorage.displayname = nickname;
  4819. eventEmitter.emit(UIEvents.NICKNAME_CHANGED, newNickname);
  4820. },
  4821. getNickname: function () {
  4822. return nickname;
  4823. },
  4824. addListener: function (type, listener) {
  4825. eventEmitter.on(type, listener);
  4826. }
  4827. };
  4828. module.exports = NickanameHandler;
  4829. },{"../../../service/UI/UIEvents":82}],30:[function(require,module,exports){
  4830. /**
  4831. * Created by hristo on 12/22/14.
  4832. */
  4833. module.exports = {
  4834. /**
  4835. * Returns the available video width.
  4836. */
  4837. getAvailableVideoWidth: function () {
  4838. var PanelToggler = require("../side_pannels/SidePanelToggler");
  4839. var rightPanelWidth
  4840. = PanelToggler.isVisible() ? PanelToggler.getPanelSize()[0] : 0;
  4841. return window.innerWidth - rightPanelWidth;
  4842. },
  4843. /**
  4844. * Changes the style class of the element given by id.
  4845. */
  4846. buttonClick: function(id, classname) {
  4847. $(id).toggleClass(classname); // add the class to the clicked element
  4848. },
  4849. /**
  4850. * Returns the text width for the given element.
  4851. *
  4852. * @param el the element
  4853. */
  4854. getTextWidth: function (el) {
  4855. return (el.clientWidth + 1);
  4856. },
  4857. /**
  4858. * Returns the text height for the given element.
  4859. *
  4860. * @param el the element
  4861. */
  4862. getTextHeight: function (el) {
  4863. return (el.clientHeight + 1);
  4864. },
  4865. /**
  4866. * Plays the sound given by id.
  4867. *
  4868. * @param id the identifier of the audio element.
  4869. */
  4870. playSoundNotification: function (id) {
  4871. document.getElementById(id).play();
  4872. },
  4873. /**
  4874. * Escapes the given text.
  4875. */
  4876. escapeHtml: function (unsafeText) {
  4877. return $('<div/>').text(unsafeText).html();
  4878. },
  4879. imageToGrayScale: function (canvas) {
  4880. var context = canvas.getContext('2d');
  4881. var imgData = context.getImageData(0, 0, canvas.width, canvas.height);
  4882. var pixels = imgData.data;
  4883. for (var i = 0, n = pixels.length; i < n; i += 4) {
  4884. var grayscale
  4885. = pixels[i] * .3 + pixels[i+1] * .59 + pixels[i+2] * .11;
  4886. pixels[i ] = grayscale; // red
  4887. pixels[i+1] = grayscale; // green
  4888. pixels[i+2] = grayscale; // blue
  4889. // pixels[i+3] is alpha
  4890. }
  4891. // redraw the image in black & white
  4892. context.putImageData(imgData, 0, 0);
  4893. },
  4894. setTooltip: function (element, key, position) {
  4895. element.setAttribute("data-i18n", "[data-content]" + key);
  4896. element.setAttribute("data-toggle", "popover");
  4897. element.setAttribute("data-placement", position);
  4898. element.setAttribute("data-html", true);
  4899. element.setAttribute("data-container", "body");
  4900. }
  4901. };
  4902. },{"../side_pannels/SidePanelToggler":16}],31:[function(require,module,exports){
  4903. var JitsiPopover = require("../util/JitsiPopover");
  4904. /**
  4905. * Constructs new connection indicator.
  4906. * @param videoContainer the video container associated with the indicator.
  4907. * @constructor
  4908. */
  4909. function ConnectionIndicator(videoContainer, jid, VideoLayout)
  4910. {
  4911. this.videoContainer = videoContainer;
  4912. this.bandwidth = null;
  4913. this.packetLoss = null;
  4914. this.bitrate = null;
  4915. this.showMoreValue = false;
  4916. this.resolution = null;
  4917. this.transport = [];
  4918. this.popover = null;
  4919. this.jid = jid;
  4920. this.create();
  4921. this.videoLayout = VideoLayout;
  4922. }
  4923. /**
  4924. * Values for the connection quality
  4925. * @type {{98: string,
  4926. * 81: string,
  4927. * 64: string,
  4928. * 47: string,
  4929. * 30: string,
  4930. * 0: string}}
  4931. */
  4932. ConnectionIndicator.connectionQualityValues = {
  4933. 98: "18px", //full
  4934. 81: "15px",//4 bars
  4935. 64: "11px",//3 bars
  4936. 47: "7px",//2 bars
  4937. 30: "3px",//1 bar
  4938. 0: "0px"//empty
  4939. };
  4940. ConnectionIndicator.getIP = function(value)
  4941. {
  4942. return value.substring(0, value.lastIndexOf(":"));
  4943. };
  4944. ConnectionIndicator.getPort = function(value)
  4945. {
  4946. return value.substring(value.lastIndexOf(":") + 1, value.length);
  4947. };
  4948. ConnectionIndicator.getStringFromArray = function (array) {
  4949. var res = "";
  4950. for(var i = 0; i < array.length; i++)
  4951. {
  4952. res += (i === 0? "" : ", ") + array[i];
  4953. }
  4954. return res;
  4955. };
  4956. /**
  4957. * Generates the html content.
  4958. * @returns {string} the html content.
  4959. */
  4960. ConnectionIndicator.prototype.generateText = function () {
  4961. var downloadBitrate, uploadBitrate, packetLoss, resolution, i;
  4962. var translate = APP.translation.translateString;
  4963. if(this.bitrate === null)
  4964. {
  4965. downloadBitrate = "N/A";
  4966. uploadBitrate = "N/A";
  4967. }
  4968. else
  4969. {
  4970. downloadBitrate =
  4971. this.bitrate.download? this.bitrate.download + " Kbps" : "N/A";
  4972. uploadBitrate =
  4973. this.bitrate.upload? this.bitrate.upload + " Kbps" : "N/A";
  4974. }
  4975. if(this.packetLoss === null)
  4976. {
  4977. packetLoss = "N/A";
  4978. }
  4979. else
  4980. {
  4981. packetLoss = "<span class='jitsipopover_green'>&darr;</span>" +
  4982. (this.packetLoss.download !== null? this.packetLoss.download : "N/A") +
  4983. "% <span class='jitsipopover_orange'>&uarr;</span>" +
  4984. (this.packetLoss.upload !== null? this.packetLoss.upload : "N/A") + "%";
  4985. }
  4986. var resolutionValue = null;
  4987. if(this.resolution && this.jid != null)
  4988. {
  4989. var keys = Object.keys(this.resolution);
  4990. if(keys.length == 1)
  4991. {
  4992. for(var ssrc in this.resolution)
  4993. {
  4994. resolutionValue = this.resolution[ssrc];
  4995. }
  4996. }
  4997. else if(keys.length > 1)
  4998. {
  4999. var displayedSsrc = APP.simulcast.getReceivingSSRC(this.jid);
  5000. resolutionValue = this.resolution[displayedSsrc];
  5001. }
  5002. }
  5003. if(this.jid === null)
  5004. {
  5005. resolution = "";
  5006. if(this.resolution === null || !Object.keys(this.resolution) ||
  5007. Object.keys(this.resolution).length === 0)
  5008. {
  5009. resolution = "N/A";
  5010. }
  5011. else
  5012. for(i in this.resolution)
  5013. {
  5014. resolutionValue = this.resolution[i];
  5015. if(resolutionValue)
  5016. {
  5017. if(resolutionValue.height &&
  5018. resolutionValue.width)
  5019. {
  5020. resolution += (resolution === ""? "" : ", ") +
  5021. resolutionValue.width + "x" +
  5022. resolutionValue.height;
  5023. }
  5024. }
  5025. }
  5026. }
  5027. else if(!resolutionValue ||
  5028. !resolutionValue.height ||
  5029. !resolutionValue.width)
  5030. {
  5031. resolution = "N/A";
  5032. }
  5033. else
  5034. {
  5035. resolution = resolutionValue.width + "x" + resolutionValue.height;
  5036. }
  5037. var result = "<table style='width:100%'>" +
  5038. "<tr>" +
  5039. "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.bitrate'>" +
  5040. translate("connectionindicator.bitrate") + "</span></td>" +
  5041. "<td><span class='jitsipopover_green'>&darr;</span>" +
  5042. downloadBitrate + " <span class='jitsipopover_orange'>&uarr;</span>" +
  5043. uploadBitrate + "</td>" +
  5044. "</tr><tr>" +
  5045. "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.packetloss'>" +
  5046. translate("connectionindicator.packetloss") + "</span></td>" +
  5047. "<td>" + packetLoss + "</td>" +
  5048. "</tr><tr>" +
  5049. "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.resolution'>" +
  5050. translate("connectionindicator.resolution") + "</span></td>" +
  5051. "<td>" + resolution + "</td></tr></table>";
  5052. if(this.videoContainer.id == "localVideoContainer") {
  5053. result += "<div class=\"jitsipopover_showmore\" " +
  5054. "onclick = \"APP.UI.connectionIndicatorShowMore('" +
  5055. this.videoContainer.id + "')\" data-i18n='connectionindicator." +
  5056. (this.showMoreValue ? "less" : "more") + "'>" +
  5057. translate("connectionindicator." + (this.showMoreValue ? "less" : "more")) +
  5058. "</div><br />";
  5059. }
  5060. if(this.showMoreValue)
  5061. {
  5062. var downloadBandwidth, uploadBandwidth, transport;
  5063. if(this.bandwidth === null)
  5064. {
  5065. downloadBandwidth = "N/A";
  5066. uploadBandwidth = "N/A";
  5067. }
  5068. else
  5069. {
  5070. downloadBandwidth = this.bandwidth.download?
  5071. this.bandwidth.download + " Kbps" :
  5072. "N/A";
  5073. uploadBandwidth = this.bandwidth.upload?
  5074. this.bandwidth.upload + " Kbps" :
  5075. "N/A";
  5076. }
  5077. if(!this.transport || this.transport.length === 0)
  5078. {
  5079. transport = "<tr>" +
  5080. "<td><span class='jitsipopover_blue' " +
  5081. "data-i18n='connectionindicator.address'>" +
  5082. translate("connectionindicator.address") + "</span></td>" +
  5083. "<td> N/A</td></tr>";
  5084. }
  5085. else
  5086. {
  5087. var data = {remoteIP: [], localIP:[], remotePort:[], localPort:[]};
  5088. for(i = 0; i < this.transport.length; i++)
  5089. {
  5090. var ip = ConnectionIndicator.getIP(this.transport[i].ip);
  5091. var port = ConnectionIndicator.getPort(this.transport[i].ip);
  5092. var localIP =
  5093. ConnectionIndicator.getIP(this.transport[i].localip);
  5094. var localPort =
  5095. ConnectionIndicator.getPort(this.transport[i].localip);
  5096. if(data.remoteIP.indexOf(ip) == -1)
  5097. {
  5098. data.remoteIP.push(ip);
  5099. }
  5100. if(data.remotePort.indexOf(port) == -1)
  5101. {
  5102. data.remotePort.push(port);
  5103. }
  5104. if(data.localIP.indexOf(localIP) == -1)
  5105. {
  5106. data.localIP.push(localIP);
  5107. }
  5108. if(data.localPort.indexOf(localPort) == -1)
  5109. {
  5110. data.localPort.push(localPort);
  5111. }
  5112. }
  5113. var local_address_key = "connectionindicator." +
  5114. (data.localIP.length > 1? "localaddresses" : "localaddress");
  5115. var remote_address_key = "connectionindicator." +
  5116. (data.remoteIP.length > 1? "remoteaddresses" : "remoteaddress");
  5117. var localTransport =
  5118. "<tr><td><span class='jitsipopover_blue' data-i18n='" +
  5119. local_address_key +"'>" +
  5120. translate(local_address_key) + "</span></td><td> " +
  5121. ConnectionIndicator.getStringFromArray(data.localIP) +
  5122. "</td></tr>";
  5123. transport =
  5124. "<tr><td><span class='jitsipopover_blue' data-i18n='" +
  5125. remote_address_key + "'>" +
  5126. translate(remote_address_key) + "</span></td><td> " +
  5127. ConnectionIndicator.getStringFromArray(data.remoteIP) +
  5128. "</td></tr>";
  5129. var key_remote = "connectionindicator.",
  5130. key_local = "connectionindicator.";
  5131. if(this.transport.length > 1)
  5132. {
  5133. key_remote += "remoteports";
  5134. key_local += "localports";
  5135. }
  5136. else
  5137. {
  5138. key_remote += "remoteport";
  5139. key_local += "localport";
  5140. }
  5141. transport += "<tr>" +
  5142. "<td>" +
  5143. "<span class='jitsipopover_blue' data-i18n='" + key_remote +
  5144. "'>" +
  5145. translate(key_remote) + "</span></td><td>";
  5146. localTransport += "<tr>" +
  5147. "<td>" +
  5148. "<span class='jitsipopover_blue' data-i18n='" + key_local +
  5149. "'>" +
  5150. translate(key_local) + "</span></td><td>";
  5151. transport +=
  5152. ConnectionIndicator.getStringFromArray(data.remotePort);
  5153. localTransport +=
  5154. ConnectionIndicator.getStringFromArray(data.localPort);
  5155. transport += "</td></tr>";
  5156. transport += localTransport + "</td></tr>";
  5157. transport +="<tr>" +
  5158. "<td><span class='jitsipopover_blue' data-i18n='connectionindicator.transport'>" +
  5159. translate("connectionindicator.transport") + "</span></td>" +
  5160. "<td>" + this.transport[0].type + "</td></tr>";
  5161. }
  5162. result += "<table style='width:100%'>" +
  5163. "<tr>" +
  5164. "<td>" +
  5165. "<span class='jitsipopover_blue' data-i18n='connectionindicator.bandwidth'>" +
  5166. translate("connectionindicator.bandwidth") + "</span>" +
  5167. "</td><td>" +
  5168. "<span class='jitsipopover_green'>&darr;</span>" +
  5169. downloadBandwidth +
  5170. " <span class='jitsipopover_orange'>&uarr;</span>" +
  5171. uploadBandwidth + "</td></tr>";
  5172. result += transport + "</table>";
  5173. }
  5174. return result;
  5175. };
  5176. /**
  5177. * Shows or hide the additional information.
  5178. */
  5179. ConnectionIndicator.prototype.showMore = function () {
  5180. this.showMoreValue = !this.showMoreValue;
  5181. this.updatePopoverData();
  5182. };
  5183. function createIcon(classes)
  5184. {
  5185. var icon = document.createElement("span");
  5186. for(var i in classes)
  5187. {
  5188. icon.classList.add(classes[i]);
  5189. }
  5190. icon.appendChild(
  5191. document.createElement("i")).classList.add("icon-connection");
  5192. return icon;
  5193. }
  5194. /**
  5195. * Creates the indicator
  5196. */
  5197. ConnectionIndicator.prototype.create = function () {
  5198. this.connectionIndicatorContainer = document.createElement("div");
  5199. this.connectionIndicatorContainer.className = "connectionindicator";
  5200. this.connectionIndicatorContainer.style.display = "none";
  5201. this.videoContainer.appendChild(this.connectionIndicatorContainer);
  5202. this.popover = new JitsiPopover(
  5203. $("#" + this.videoContainer.id + " > .connectionindicator"),
  5204. {content: "<div class=\"connection_info\" data-i18n='connectionindicator.na'>" +
  5205. APP.translation.translateString("connectionindicator.na") + "</div>",
  5206. skin: "black"});
  5207. this.emptyIcon = this.connectionIndicatorContainer.appendChild(
  5208. createIcon(["connection", "connection_empty"]));
  5209. this.fullIcon = this.connectionIndicatorContainer.appendChild(
  5210. createIcon(["connection", "connection_full"]));
  5211. };
  5212. /**
  5213. * Removes the indicator
  5214. */
  5215. ConnectionIndicator.prototype.remove = function()
  5216. {
  5217. this.connectionIndicatorContainer.remove();
  5218. this.popover.forceHide();
  5219. };
  5220. /**
  5221. * Updates the data of the indicator
  5222. * @param percent the percent of connection quality
  5223. * @param object the statistics data.
  5224. */
  5225. ConnectionIndicator.prototype.updateConnectionQuality =
  5226. function (percent, object) {
  5227. if(percent === null)
  5228. {
  5229. this.connectionIndicatorContainer.style.display = "none";
  5230. this.popover.forceHide();
  5231. return;
  5232. }
  5233. else
  5234. {
  5235. if(this.connectionIndicatorContainer.style.display == "none") {
  5236. this.connectionIndicatorContainer.style.display = "block";
  5237. this.videoLayout.updateMutePosition(this.videoContainer.id);
  5238. }
  5239. }
  5240. this.bandwidth = object.bandwidth;
  5241. this.bitrate = object.bitrate;
  5242. this.packetLoss = object.packetLoss;
  5243. this.transport = object.transport;
  5244. if(object.resolution)
  5245. {
  5246. this.resolution = object.resolution;
  5247. }
  5248. for(var quality in ConnectionIndicator.connectionQualityValues)
  5249. {
  5250. if(percent >= quality)
  5251. {
  5252. this.fullIcon.style.width =
  5253. ConnectionIndicator.connectionQualityValues[quality];
  5254. }
  5255. }
  5256. this.updatePopoverData();
  5257. };
  5258. /**
  5259. * Updates the resolution
  5260. * @param resolution the new resolution
  5261. */
  5262. ConnectionIndicator.prototype.updateResolution = function (resolution) {
  5263. this.resolution = resolution;
  5264. this.updatePopoverData();
  5265. };
  5266. /**
  5267. * Updates the content of the popover
  5268. */
  5269. ConnectionIndicator.prototype.updatePopoverData = function () {
  5270. this.popover.updateContent(
  5271. "<div class=\"connection_info\">" + this.generateText() + "</div>");
  5272. APP.translation.translateElement($(".connection_info"));
  5273. };
  5274. /**
  5275. * Hides the popover
  5276. */
  5277. ConnectionIndicator.prototype.hide = function () {
  5278. this.popover.forceHide();
  5279. };
  5280. /**
  5281. * Hides the indicator
  5282. */
  5283. ConnectionIndicator.prototype.hideIndicator = function () {
  5284. this.connectionIndicatorContainer.style.display = "none";
  5285. if(this.popover)
  5286. this.popover.forceHide();
  5287. };
  5288. module.exports = ConnectionIndicator;
  5289. },{"../util/JitsiPopover":27}],32:[function(require,module,exports){
  5290. var AudioLevels = require("../audio_levels/AudioLevels");
  5291. var Avatar = require("../avatar/Avatar");
  5292. var Chat = require("../side_pannels/chat/Chat");
  5293. var ContactList = require("../side_pannels/contactlist/ContactList");
  5294. var UIUtil = require("../util/UIUtil");
  5295. var ConnectionIndicator = require("./ConnectionIndicator");
  5296. var NicknameHandler = require("../util/NicknameHandler");
  5297. var MediaStreamType = require("../../../service/RTC/MediaStreamTypes");
  5298. var UIEvents = require("../../../service/UI/UIEvents");
  5299. var currentDominantSpeaker = null;
  5300. var lastNCount = config.channelLastN;
  5301. var localLastNCount = config.channelLastN;
  5302. var localLastNSet = [];
  5303. var lastNEndpointsCache = [];
  5304. var lastNPickupJid = null;
  5305. var largeVideoState = {
  5306. updateInProgress: false,
  5307. newSrc: ''
  5308. };
  5309. var eventEmitter = null;
  5310. /**
  5311. * Currently focused video "src"(displayed in large video).
  5312. * @type {String}
  5313. */
  5314. var focusedVideoInfo = null;
  5315. /**
  5316. * Indicates if we have muted our audio before the conference has started.
  5317. * @type {boolean}
  5318. */
  5319. var preMuted = false;
  5320. var mutedAudios = {};
  5321. var flipXLocalVideo = true;
  5322. var currentVideoWidth = null;
  5323. var currentVideoHeight = null;
  5324. var localVideoSrc = null;
  5325. function videoactive( videoelem) {
  5326. if (videoelem.attr('id').indexOf('mixedmslabel') === -1) {
  5327. // ignore mixedmslabela0 and v0
  5328. videoelem.show();
  5329. VideoLayout.resizeThumbnails();
  5330. var videoParent = videoelem.parent();
  5331. var parentResourceJid = null;
  5332. if (videoParent)
  5333. parentResourceJid
  5334. = VideoLayout.getPeerContainerResourceJid(videoParent[0]);
  5335. // Update the large video to the last added video only if there's no
  5336. // current dominant, focused speaker or prezi playing or update it to
  5337. // the current dominant speaker.
  5338. if ((!focusedVideoInfo &&
  5339. !VideoLayout.getDominantSpeakerResourceJid() &&
  5340. !require("../prezi/Prezi").isPresentationVisible()) ||
  5341. (parentResourceJid &&
  5342. VideoLayout.getDominantSpeakerResourceJid() === parentResourceJid)) {
  5343. VideoLayout.updateLargeVideo(
  5344. APP.RTC.getVideoSrc(videoelem[0]),
  5345. 1,
  5346. parentResourceJid);
  5347. }
  5348. VideoLayout.showModeratorIndicator();
  5349. }
  5350. }
  5351. function waitForRemoteVideo(selector, ssrc, stream, jid) {
  5352. // XXX(gp) so, every call to this function is *always* preceded by a call
  5353. // to the RTC.attachMediaStream() function but that call is *not* followed
  5354. // by an update to the videoSrcToSsrc map!
  5355. //
  5356. // The above way of doing things results in video SRCs that don't correspond
  5357. // to any SSRC for a short period of time (to be more precise, for as long
  5358. // the waitForRemoteVideo takes to complete). This causes problems (see
  5359. // bellow).
  5360. //
  5361. // I'm wondering why we need to do that; i.e. why call RTC.attachMediaStream()
  5362. // a second time in here and only then update the videoSrcToSsrc map? Why
  5363. // not simply update the videoSrcToSsrc map when the RTC.attachMediaStream()
  5364. // is called the first time? I actually do that in the lastN changed event
  5365. // handler because the "orphan" video SRC is causing troubles there. The
  5366. // purpose of this method would then be to fire the "videoactive.jingle".
  5367. //
  5368. // Food for though I guess :-)
  5369. if (selector.removed || !selector.parent().is(":visible")) {
  5370. console.warn("Media removed before had started", selector);
  5371. return;
  5372. }
  5373. if (stream.id === 'mixedmslabel') return;
  5374. if (selector[0].currentTime > 0) {
  5375. var videoStream = APP.simulcast.getReceivingVideoStream(stream);
  5376. APP.RTC.attachMediaStream(selector, videoStream); // FIXME: why do i have to do this for FF?
  5377. videoactive(selector);
  5378. } else {
  5379. setTimeout(function () {
  5380. waitForRemoteVideo(selector, ssrc, stream, jid);
  5381. }, 250);
  5382. }
  5383. }
  5384. /**
  5385. * Returns an array of the video horizontal and vertical indents,
  5386. * so that if fits its parent.
  5387. *
  5388. * @return an array with 2 elements, the horizontal indent and the vertical
  5389. * indent
  5390. */
  5391. function getCameraVideoPosition(videoWidth,
  5392. videoHeight,
  5393. videoSpaceWidth,
  5394. videoSpaceHeight) {
  5395. // Parent height isn't completely calculated when we position the video in
  5396. // full screen mode and this is why we use the screen height in this case.
  5397. // Need to think it further at some point and implement it properly.
  5398. var isFullScreen = document.fullScreen ||
  5399. document.mozFullScreen ||
  5400. document.webkitIsFullScreen;
  5401. if (isFullScreen)
  5402. videoSpaceHeight = window.innerHeight;
  5403. var horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
  5404. var verticalIndent = (videoSpaceHeight - videoHeight) / 2;
  5405. return [horizontalIndent, verticalIndent];
  5406. }
  5407. /**
  5408. * Returns an array of the video horizontal and vertical indents.
  5409. * Centers horizontally and top aligns vertically.
  5410. *
  5411. * @return an array with 2 elements, the horizontal indent and the vertical
  5412. * indent
  5413. */
  5414. function getDesktopVideoPosition(videoWidth,
  5415. videoHeight,
  5416. videoSpaceWidth,
  5417. videoSpaceHeight) {
  5418. var horizontalIndent = (videoSpaceWidth - videoWidth) / 2;
  5419. var verticalIndent = 0;// Top aligned
  5420. return [horizontalIndent, verticalIndent];
  5421. }
  5422. /**
  5423. * Returns an array of the video dimensions, so that it covers the screen.
  5424. * It leaves no empty areas, but some parts of the video might not be visible.
  5425. *
  5426. * @return an array with 2 elements, the video width and the video height
  5427. */
  5428. function getCameraVideoSize(videoWidth,
  5429. videoHeight,
  5430. videoSpaceWidth,
  5431. videoSpaceHeight) {
  5432. if (!videoWidth)
  5433. videoWidth = currentVideoWidth;
  5434. if (!videoHeight)
  5435. videoHeight = currentVideoHeight;
  5436. var aspectRatio = videoWidth / videoHeight;
  5437. var availableWidth = Math.max(videoWidth, videoSpaceWidth);
  5438. var availableHeight = Math.max(videoHeight, videoSpaceHeight);
  5439. if (availableWidth / aspectRatio < videoSpaceHeight) {
  5440. availableHeight = videoSpaceHeight;
  5441. availableWidth = availableHeight * aspectRatio;
  5442. }
  5443. if (availableHeight * aspectRatio < videoSpaceWidth) {
  5444. availableWidth = videoSpaceWidth;
  5445. availableHeight = availableWidth / aspectRatio;
  5446. }
  5447. return [availableWidth, availableHeight];
  5448. }
  5449. /**
  5450. * Sets the display name for the given video span id.
  5451. */
  5452. function setDisplayName(videoSpanId, displayName) {
  5453. var nameSpan = $('#' + videoSpanId + '>span.displayname');
  5454. var defaultLocalDisplayName = interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME;
  5455. // If we already have a display name for this video.
  5456. if (nameSpan.length > 0) {
  5457. var nameSpanElement = nameSpan.get(0);
  5458. if (nameSpanElement.id === 'localDisplayName' &&
  5459. $('#localDisplayName').text() !== displayName) {
  5460. if (displayName && displayName.length > 0)
  5461. $('#localDisplayName').html(displayName + ' (me)');
  5462. else
  5463. $('#localDisplayName').text(defaultLocalDisplayName);
  5464. } else {
  5465. if (displayName && displayName.length > 0)
  5466. $('#' + videoSpanId + '_name').html(displayName);
  5467. else
  5468. $('#' + videoSpanId + '_name').text(interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME);
  5469. }
  5470. } else {
  5471. var editButton = null;
  5472. nameSpan = document.createElement('span');
  5473. nameSpan.className = 'displayname';
  5474. $('#' + videoSpanId)[0].appendChild(nameSpan);
  5475. if (videoSpanId === 'localVideoContainer') {
  5476. editButton = createEditDisplayNameButton();
  5477. nameSpan.innerText = defaultLocalDisplayName;
  5478. }
  5479. else {
  5480. nameSpan.innerText = interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME;
  5481. }
  5482. if (displayName && displayName.length > 0) {
  5483. nameSpan.innerText = displayName;
  5484. }
  5485. if (!editButton) {
  5486. nameSpan.id = videoSpanId + '_name';
  5487. } else {
  5488. nameSpan.id = 'localDisplayName';
  5489. $('#' + videoSpanId)[0].appendChild(editButton);
  5490. //translates popover of edit button
  5491. APP.translation.translateElement($("a.displayname"));
  5492. var editableText = document.createElement('input');
  5493. editableText.className = 'displayname';
  5494. editableText.type = 'text';
  5495. editableText.id = 'editDisplayName';
  5496. if (displayName && displayName.length) {
  5497. editableText.value
  5498. = displayName.substring(0, displayName.indexOf(' (me)'));
  5499. }
  5500. editableText.setAttribute('style', 'display:none;');
  5501. editableText.setAttribute('placeholder', 'ex. Jane Pink');
  5502. $('#' + videoSpanId)[0].appendChild(editableText);
  5503. $('#localVideoContainer .displayname')
  5504. .bind("click", function (e) {
  5505. e.preventDefault();
  5506. e.stopPropagation();
  5507. $('#localDisplayName').hide();
  5508. $('#editDisplayName').show();
  5509. $('#editDisplayName').focus();
  5510. $('#editDisplayName').select();
  5511. $('#editDisplayName').one("focusout", function (e) {
  5512. VideoLayout.inputDisplayNameHandler(this.value);
  5513. });
  5514. $('#editDisplayName').on('keydown', function (e) {
  5515. if (e.keyCode === 13) {
  5516. e.preventDefault();
  5517. VideoLayout.inputDisplayNameHandler(this.value);
  5518. }
  5519. });
  5520. });
  5521. }
  5522. }
  5523. }
  5524. /**
  5525. * Gets the selector of video thumbnail container for the user identified by
  5526. * given <tt>userJid</tt>
  5527. * @param resourceJid user's Jid for whom we want to get the video container.
  5528. */
  5529. function getParticipantContainer(resourceJid)
  5530. {
  5531. if (!resourceJid)
  5532. return null;
  5533. if (resourceJid === APP.xmpp.myResource())
  5534. return $("#localVideoContainer");
  5535. else
  5536. return $("#participant_" + resourceJid);
  5537. }
  5538. /**
  5539. * Sets the size and position of the given video element.
  5540. *
  5541. * @param video the video element to position
  5542. * @param width the desired video width
  5543. * @param height the desired video height
  5544. * @param horizontalIndent the left and right indent
  5545. * @param verticalIndent the top and bottom indent
  5546. */
  5547. function positionVideo(video,
  5548. width,
  5549. height,
  5550. horizontalIndent,
  5551. verticalIndent) {
  5552. video.width(width);
  5553. video.height(height);
  5554. video.css({ top: verticalIndent + 'px',
  5555. bottom: verticalIndent + 'px',
  5556. left: horizontalIndent + 'px',
  5557. right: horizontalIndent + 'px'});
  5558. }
  5559. /**
  5560. * Adds the remote video menu element for the given <tt>jid</tt> in the
  5561. * given <tt>parentElement</tt>.
  5562. *
  5563. * @param jid the jid indicating the video for which we're adding a menu.
  5564. * @param parentElement the parent element where this menu will be added
  5565. */
  5566. function addRemoteVideoMenu(jid, parentElement) {
  5567. var spanElement = document.createElement('span');
  5568. spanElement.className = 'remotevideomenu';
  5569. parentElement.appendChild(spanElement);
  5570. var menuElement = document.createElement('i');
  5571. menuElement.className = 'fa fa-angle-down';
  5572. menuElement.title = 'Remote user controls';
  5573. spanElement.appendChild(menuElement);
  5574. // <ul class="popupmenu">
  5575. // <li><a href="#">Mute</a></li>
  5576. // <li><a href="#">Eject</a></li>
  5577. // </ul>
  5578. var popupmenuElement = document.createElement('ul');
  5579. popupmenuElement.className = 'popupmenu';
  5580. popupmenuElement.id
  5581. = 'remote_popupmenu_' + Strophe.getResourceFromJid(jid);
  5582. spanElement.appendChild(popupmenuElement);
  5583. var muteMenuItem = document.createElement('li');
  5584. var muteLinkItem = document.createElement('a');
  5585. var mutedIndicator = "<i style='float:left;' class='icon-mic-disabled'></i>";
  5586. if (!mutedAudios[jid]) {
  5587. muteLinkItem.innerHTML = mutedIndicator +
  5588. " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
  5589. muteLinkItem.className = 'mutelink';
  5590. }
  5591. else {
  5592. muteLinkItem.innerHTML = mutedIndicator +
  5593. " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
  5594. muteLinkItem.className = 'mutelink disabled';
  5595. }
  5596. muteLinkItem.onclick = function(){
  5597. if ($(this).attr('disabled') != undefined) {
  5598. event.preventDefault();
  5599. }
  5600. var isMute = mutedAudios[jid] == true;
  5601. APP.xmpp.setMute(jid, !isMute);
  5602. popupmenuElement.setAttribute('style', 'display:none;');
  5603. if (isMute) {
  5604. this.innerHTML = mutedIndicator +
  5605. " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.muted'></div>";
  5606. this.className = 'mutelink disabled';
  5607. }
  5608. else {
  5609. this.innerHTML = mutedIndicator +
  5610. " <div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.domute'></div>";
  5611. this.className = 'mutelink';
  5612. }
  5613. };
  5614. muteMenuItem.appendChild(muteLinkItem);
  5615. popupmenuElement.appendChild(muteMenuItem);
  5616. var ejectIndicator = "<i style='float:left;' class='fa fa-eject'></i>";
  5617. var ejectMenuItem = document.createElement('li');
  5618. var ejectLinkItem = document.createElement('a');
  5619. var ejectText = "<div style='width: 90px;margin-left: 20px;' data-i18n='videothumbnail.kick'>&nbsp;</div>";
  5620. ejectLinkItem.innerHTML = ejectIndicator + ' ' + ejectText;
  5621. ejectLinkItem.onclick = function(){
  5622. APP.xmpp.eject(jid);
  5623. popupmenuElement.setAttribute('style', 'display:none;');
  5624. };
  5625. ejectMenuItem.appendChild(ejectLinkItem);
  5626. popupmenuElement.appendChild(ejectMenuItem);
  5627. var paddingSpan = document.createElement('span');
  5628. paddingSpan.className = 'popupmenuPadding';
  5629. popupmenuElement.appendChild(paddingSpan);
  5630. APP.translation.translateElement($("#" + popupmenuElement.id + " > li > a > div"));
  5631. }
  5632. /**
  5633. * Removes remote video menu element from video element identified by
  5634. * given <tt>videoElementId</tt>.
  5635. *
  5636. * @param videoElementId the id of local or remote video element.
  5637. */
  5638. function removeRemoteVideoMenu(videoElementId) {
  5639. var menuSpan = $('#' + videoElementId + '>span.remotevideomenu');
  5640. if (menuSpan.length) {
  5641. menuSpan.remove();
  5642. }
  5643. }
  5644. /**
  5645. * Updates the data for the indicator
  5646. * @param id the id of the indicator
  5647. * @param percent the percent for connection quality
  5648. * @param object the data
  5649. */
  5650. function updateStatsIndicator(id, percent, object) {
  5651. if(VideoLayout.connectionIndicators[id])
  5652. VideoLayout.connectionIndicators[id].updateConnectionQuality(percent, object);
  5653. }
  5654. /**
  5655. * Returns an array of the video dimensions, so that it keeps it's aspect
  5656. * ratio and fits available area with it's larger dimension. This method
  5657. * ensures that whole video will be visible and can leave empty areas.
  5658. *
  5659. * @return an array with 2 elements, the video width and the video height
  5660. */
  5661. function getDesktopVideoSize(videoWidth,
  5662. videoHeight,
  5663. videoSpaceWidth,
  5664. videoSpaceHeight) {
  5665. if (!videoWidth)
  5666. videoWidth = currentVideoWidth;
  5667. if (!videoHeight)
  5668. videoHeight = currentVideoHeight;
  5669. var aspectRatio = videoWidth / videoHeight;
  5670. var availableWidth = Math.max(videoWidth, videoSpaceWidth);
  5671. var availableHeight = Math.max(videoHeight, videoSpaceHeight);
  5672. videoSpaceHeight -= $('#remoteVideos').outerHeight();
  5673. if (availableWidth / aspectRatio >= videoSpaceHeight)
  5674. {
  5675. availableHeight = videoSpaceHeight;
  5676. availableWidth = availableHeight * aspectRatio;
  5677. }
  5678. if (availableHeight * aspectRatio >= videoSpaceWidth)
  5679. {
  5680. availableWidth = videoSpaceWidth;
  5681. availableHeight = availableWidth / aspectRatio;
  5682. }
  5683. return [availableWidth, availableHeight];
  5684. }
  5685. /**
  5686. * Creates the edit display name button.
  5687. *
  5688. * @returns the edit button
  5689. */
  5690. function createEditDisplayNameButton() {
  5691. var editButton = document.createElement('a');
  5692. editButton.className = 'displayname';
  5693. UIUtil.setTooltip(editButton,
  5694. "videothumbnail.editnickname",
  5695. "top");
  5696. editButton.innerHTML = '<i class="fa fa-pencil"></i>';
  5697. return editButton;
  5698. }
  5699. /**
  5700. * Creates the element indicating the moderator(owner) of the conference.
  5701. *
  5702. * @param parentElement the parent element where the owner indicator will
  5703. * be added
  5704. */
  5705. function createModeratorIndicatorElement(parentElement) {
  5706. var moderatorIndicator = document.createElement('i');
  5707. moderatorIndicator.className = 'fa fa-star';
  5708. parentElement.appendChild(moderatorIndicator);
  5709. UIUtil.setTooltip(parentElement,
  5710. "videothumbnail.moderator",
  5711. "top");
  5712. }
  5713. var VideoLayout = (function (my) {
  5714. my.connectionIndicators = {};
  5715. // By default we use camera
  5716. my.getVideoSize = getCameraVideoSize;
  5717. my.getVideoPosition = getCameraVideoPosition;
  5718. my.init = function (emitter) {
  5719. // Listen for large video size updates
  5720. document.getElementById('largeVideo')
  5721. .addEventListener('loadedmetadata', function (e) {
  5722. currentVideoWidth = this.videoWidth;
  5723. currentVideoHeight = this.videoHeight;
  5724. VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
  5725. });
  5726. eventEmitter = emitter;
  5727. };
  5728. my.isInLastN = function(resource) {
  5729. return lastNCount < 0 // lastN is disabled, return true
  5730. || (lastNCount > 0 && lastNEndpointsCache.length == 0) // lastNEndpoints cache not built yet, return true
  5731. || (lastNEndpointsCache && lastNEndpointsCache.indexOf(resource) !== -1);
  5732. };
  5733. my.changeLocalStream = function (stream) {
  5734. VideoLayout.changeLocalVideo(stream);
  5735. };
  5736. my.changeLocalAudio = function(stream) {
  5737. APP.RTC.attachMediaStream($('#localAudio'), stream.getOriginalStream());
  5738. document.getElementById('localAudio').autoplay = true;
  5739. document.getElementById('localAudio').volume = 0;
  5740. if (preMuted) {
  5741. if(!APP.UI.setAudioMuted(true))
  5742. {
  5743. preMuted = mute;
  5744. }
  5745. preMuted = false;
  5746. }
  5747. };
  5748. my.changeLocalVideo = function(stream) {
  5749. var flipX = true;
  5750. if(stream.videoType == "screen")
  5751. flipX = false;
  5752. var localVideo = document.createElement('video');
  5753. localVideo.id = 'localVideo_' +
  5754. APP.RTC.getStreamID(stream.getOriginalStream());
  5755. localVideo.autoplay = true;
  5756. localVideo.volume = 0; // is it required if audio is separated ?
  5757. localVideo.oncontextmenu = function () { return false; };
  5758. var localVideoContainer = document.getElementById('localVideoWrapper');
  5759. localVideoContainer.appendChild(localVideo);
  5760. // Set default display name.
  5761. setDisplayName('localVideoContainer');
  5762. if(!VideoLayout.connectionIndicators["localVideoContainer"]) {
  5763. VideoLayout.connectionIndicators["localVideoContainer"]
  5764. = new ConnectionIndicator($("#localVideoContainer")[0], null, VideoLayout);
  5765. }
  5766. AudioLevels.updateAudioLevelCanvas(null, VideoLayout);
  5767. var localVideoSelector = $('#' + localVideo.id);
  5768. function localVideoClick(event) {
  5769. event.stopPropagation();
  5770. VideoLayout.handleVideoThumbClicked(
  5771. APP.RTC.getVideoSrc(localVideo),
  5772. false,
  5773. APP.xmpp.myResource());
  5774. }
  5775. // Add click handler to both video and video wrapper elements in case
  5776. // there's no video.
  5777. localVideoSelector.click(localVideoClick);
  5778. $('#localVideoContainer').click(localVideoClick);
  5779. // Add hover handler
  5780. $('#localVideoContainer').hover(
  5781. function() {
  5782. VideoLayout.showDisplayName('localVideoContainer', true);
  5783. },
  5784. function() {
  5785. if (!VideoLayout.isLargeVideoVisible()
  5786. || APP.RTC.getVideoSrc(localVideo) !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
  5787. VideoLayout.showDisplayName('localVideoContainer', false);
  5788. }
  5789. );
  5790. // Add stream ended handler
  5791. stream.getOriginalStream().onended = function () {
  5792. localVideoContainer.removeChild(localVideo);
  5793. VideoLayout.updateRemovedVideo(APP.RTC.getVideoSrc(localVideo));
  5794. };
  5795. // Flip video x axis if needed
  5796. flipXLocalVideo = flipX;
  5797. if (flipX) {
  5798. localVideoSelector.addClass("flipVideoX");
  5799. }
  5800. // Attach WebRTC stream
  5801. var videoStream = APP.simulcast.getLocalVideoStream();
  5802. APP.RTC.attachMediaStream(localVideoSelector, videoStream);
  5803. localVideoSrc = APP.RTC.getVideoSrc(localVideo);
  5804. var myResourceJid = APP.xmpp.myResource();
  5805. VideoLayout.updateLargeVideo(localVideoSrc, 0,
  5806. myResourceJid);
  5807. };
  5808. /**
  5809. * Checks if removed video is currently displayed and tries to display
  5810. * another one instead.
  5811. * @param removedVideoSrc src stream identifier of the video.
  5812. */
  5813. my.updateRemovedVideo = function(removedVideoSrc) {
  5814. if (removedVideoSrc === APP.RTC.getVideoSrc($('#largeVideo')[0])) {
  5815. // this is currently displayed as large
  5816. // pick the last visible video in the row
  5817. // if nobody else is left, this picks the local video
  5818. var pick
  5819. = $('#remoteVideos>span[id!="mixedstream"]:visible:last>video')
  5820. .get(0);
  5821. if (!pick) {
  5822. console.info("Last visible video no longer exists");
  5823. pick = $('#remoteVideos>span[id!="mixedstream"]>video').get(0);
  5824. if (!pick || !APP.RTC.getVideoSrc(pick)) {
  5825. // Try local video
  5826. console.info("Fallback to local video...");
  5827. pick = $('#remoteVideos>span>span>video').get(0);
  5828. }
  5829. }
  5830. // mute if localvideo
  5831. if (pick) {
  5832. var container = pick.parentNode;
  5833. var jid = null;
  5834. if(container)
  5835. {
  5836. if(container.id == "localVideoWrapper")
  5837. {
  5838. jid = APP.xmpp.myResource();
  5839. }
  5840. else
  5841. {
  5842. jid = VideoLayout.getPeerContainerResourceJid(container);
  5843. }
  5844. }
  5845. VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(pick), pick.volume, jid);
  5846. } else {
  5847. console.warn("Failed to elect large video");
  5848. }
  5849. }
  5850. };
  5851. my.onRemoteStreamAdded = function (stream) {
  5852. var container;
  5853. var remotes = document.getElementById('remoteVideos');
  5854. if (stream.peerjid) {
  5855. VideoLayout.ensurePeerContainerExists(stream.peerjid);
  5856. container = document.getElementById(
  5857. 'participant_' + Strophe.getResourceFromJid(stream.peerjid));
  5858. } else {
  5859. var id = stream.getOriginalStream().id;
  5860. if (id !== 'mixedmslabel'
  5861. // FIXME: default stream is added always with new focus
  5862. // (to be investigated)
  5863. && id !== 'default') {
  5864. console.error('can not associate stream',
  5865. id,
  5866. 'with a participant');
  5867. // We don't want to add it here since it will cause troubles
  5868. return;
  5869. }
  5870. // FIXME: for the mixed ms we dont need a video -- currently
  5871. container = document.createElement('span');
  5872. container.id = 'mixedstream';
  5873. container.className = 'videocontainer';
  5874. remotes.appendChild(container);
  5875. UIUtil.playSoundNotification('userJoined');
  5876. }
  5877. if (container) {
  5878. VideoLayout.addRemoteStreamElement( container,
  5879. stream.sid,
  5880. stream.getOriginalStream(),
  5881. stream.peerjid,
  5882. stream.ssrc);
  5883. }
  5884. }
  5885. my.getLargeVideoState = function () {
  5886. return largeVideoState;
  5887. };
  5888. /**
  5889. * Updates the large video with the given new video source.
  5890. */
  5891. my.updateLargeVideo = function(newSrc, vol, resourceJid) {
  5892. console.log('hover in', newSrc);
  5893. if (APP.RTC.getVideoSrc($('#largeVideo')[0]) !== newSrc) {
  5894. $('#activeSpeaker').css('visibility', 'hidden');
  5895. // Due to the simulcast the localVideoSrc may have changed when the
  5896. // fadeOut event triggers. In that case the getJidFromVideoSrc and
  5897. // isVideoSrcDesktop methods will not function correctly.
  5898. //
  5899. // Also, again due to the simulcast, the updateLargeVideo method can
  5900. // be called multiple times almost simultaneously. Therefore, we
  5901. // store the state here and update only once.
  5902. largeVideoState.newSrc = newSrc;
  5903. largeVideoState.isVisible = $('#largeVideo').is(':visible');
  5904. largeVideoState.isDesktop = APP.RTC.isVideoSrcDesktop(resourceJid);
  5905. if(largeVideoState.userResourceJid) {
  5906. largeVideoState.oldResourceJid = largeVideoState.userResourceJid;
  5907. } else {
  5908. largeVideoState.oldResourceJid = null;
  5909. }
  5910. largeVideoState.userResourceJid = resourceJid;
  5911. // Screen stream is already rotated
  5912. largeVideoState.flipX = (newSrc === localVideoSrc) && flipXLocalVideo;
  5913. var userChanged = false;
  5914. if (largeVideoState.oldResourceJid !== largeVideoState.userResourceJid) {
  5915. userChanged = true;
  5916. // we want the notification to trigger even if userJid is undefined,
  5917. // or null.
  5918. eventEmitter.emit(UIEvents.SELECTED_ENDPOINT,
  5919. largeVideoState.userResourceJid);
  5920. }
  5921. if (!largeVideoState.updateInProgress) {
  5922. largeVideoState.updateInProgress = true;
  5923. var doUpdate = function () {
  5924. Avatar.updateActiveSpeakerAvatarSrc(
  5925. APP.xmpp.findJidFromResource(
  5926. largeVideoState.userResourceJid));
  5927. if (!userChanged && largeVideoState.preload &&
  5928. largeVideoState.preload !== null &&
  5929. APP.RTC.getVideoSrc($(largeVideoState.preload)[0]) === newSrc)
  5930. {
  5931. console.info('Switching to preloaded video');
  5932. var attributes = $('#largeVideo').prop("attributes");
  5933. // loop through largeVideo attributes and apply them on
  5934. // preload.
  5935. $.each(attributes, function () {
  5936. if (this.name !== 'id' && this.name !== 'src') {
  5937. largeVideoState.preload.attr(this.name, this.value);
  5938. }
  5939. });
  5940. largeVideoState.preload.appendTo($('#largeVideoContainer'));
  5941. $('#largeVideo').attr('id', 'previousLargeVideo');
  5942. largeVideoState.preload.attr('id', 'largeVideo');
  5943. $('#previousLargeVideo').remove();
  5944. largeVideoState.preload.on('loadedmetadata', function (e) {
  5945. currentVideoWidth = this.videoWidth;
  5946. currentVideoHeight = this.videoHeight;
  5947. VideoLayout.positionLarge(currentVideoWidth, currentVideoHeight);
  5948. });
  5949. largeVideoState.preload = null;
  5950. largeVideoState.preload_ssrc = 0;
  5951. } else {
  5952. APP.RTC.setVideoSrc($('#largeVideo')[0], largeVideoState.newSrc);
  5953. }
  5954. var videoTransform = document.getElementById('largeVideo')
  5955. .style.webkitTransform;
  5956. if (largeVideoState.flipX && videoTransform !== 'scaleX(-1)') {
  5957. document.getElementById('largeVideo').style.webkitTransform
  5958. = "scaleX(-1)";
  5959. }
  5960. else if (!largeVideoState.flipX && videoTransform === 'scaleX(-1)') {
  5961. document.getElementById('largeVideo').style.webkitTransform
  5962. = "none";
  5963. }
  5964. // Change the way we'll be measuring and positioning large video
  5965. VideoLayout.getVideoSize = largeVideoState.isDesktop
  5966. ? getDesktopVideoSize
  5967. : getCameraVideoSize;
  5968. VideoLayout.getVideoPosition = largeVideoState.isDesktop
  5969. ? getDesktopVideoPosition
  5970. : getCameraVideoPosition;
  5971. // Only if the large video is currently visible.
  5972. // Disable previous dominant speaker video.
  5973. if (largeVideoState.oldResourceJid) {
  5974. VideoLayout.enableDominantSpeaker(
  5975. largeVideoState.oldResourceJid,
  5976. false);
  5977. }
  5978. // Enable new dominant speaker in the remote videos section.
  5979. if (largeVideoState.userResourceJid) {
  5980. VideoLayout.enableDominantSpeaker(
  5981. largeVideoState.userResourceJid,
  5982. true);
  5983. }
  5984. if (userChanged && largeVideoState.isVisible) {
  5985. // using "this" should be ok because we're called
  5986. // from within the fadeOut event.
  5987. $(this).fadeIn(300);
  5988. }
  5989. if(userChanged) {
  5990. Avatar.showUserAvatar(
  5991. APP.xmpp.findJidFromResource(
  5992. largeVideoState.oldResourceJid));
  5993. }
  5994. largeVideoState.updateInProgress = false;
  5995. };
  5996. if (userChanged) {
  5997. $('#largeVideo').fadeOut(300, doUpdate);
  5998. } else {
  5999. doUpdate();
  6000. }
  6001. }
  6002. } else {
  6003. Avatar.showUserAvatar(
  6004. APP.xmpp.findJidFromResource(
  6005. largeVideoState.userResourceJid));
  6006. }
  6007. };
  6008. my.handleVideoThumbClicked = function(videoSrc,
  6009. noPinnedEndpointChangedEvent,
  6010. resourceJid) {
  6011. // Restore style for previously focused video
  6012. var oldContainer = null;
  6013. if(focusedVideoInfo) {
  6014. var focusResourceJid = focusedVideoInfo.resourceJid;
  6015. oldContainer = getParticipantContainer(focusResourceJid);
  6016. }
  6017. if (oldContainer) {
  6018. oldContainer.removeClass("videoContainerFocused");
  6019. }
  6020. // Unlock current focused.
  6021. if (focusedVideoInfo && focusedVideoInfo.src === videoSrc)
  6022. {
  6023. focusedVideoInfo = null;
  6024. var dominantSpeakerVideo = null;
  6025. // Enable the currently set dominant speaker.
  6026. if (currentDominantSpeaker) {
  6027. dominantSpeakerVideo
  6028. = $('#participant_' + currentDominantSpeaker + '>video')
  6029. .get(0);
  6030. if (dominantSpeakerVideo) {
  6031. VideoLayout.updateLargeVideo(
  6032. APP.RTC.getVideoSrc(dominantSpeakerVideo),
  6033. 1,
  6034. currentDominantSpeaker);
  6035. }
  6036. }
  6037. if (!noPinnedEndpointChangedEvent) {
  6038. eventEmitter.emit(UIEvents.PINNED_ENDPOINT);
  6039. }
  6040. return;
  6041. }
  6042. // Lock new video
  6043. focusedVideoInfo = {
  6044. src: videoSrc,
  6045. resourceJid: resourceJid
  6046. };
  6047. // Update focused/pinned interface.
  6048. if (resourceJid)
  6049. {
  6050. var container = getParticipantContainer(resourceJid);
  6051. container.addClass("videoContainerFocused");
  6052. if (!noPinnedEndpointChangedEvent) {
  6053. eventEmitter.emit(UIEvents.PINNED_ENDPOINT, resourceJid);
  6054. }
  6055. }
  6056. if ($('#largeVideo').attr('src') === videoSrc &&
  6057. VideoLayout.isLargeVideoOnTop()) {
  6058. return;
  6059. }
  6060. // Triggers a "video.selected" event. The "false" parameter indicates
  6061. // this isn't a prezi.
  6062. $(document).trigger("video.selected", [false]);
  6063. VideoLayout.updateLargeVideo(videoSrc, 1, resourceJid);
  6064. $('audio').each(function (idx, el) {
  6065. if (el.id.indexOf('mixedmslabel') !== -1) {
  6066. el.volume = 0;
  6067. el.volume = 1;
  6068. }
  6069. });
  6070. };
  6071. /**
  6072. * Positions the large video.
  6073. *
  6074. * @param videoWidth the stream video width
  6075. * @param videoHeight the stream video height
  6076. */
  6077. my.positionLarge = function (videoWidth, videoHeight) {
  6078. var videoSpaceWidth = $('#videospace').width();
  6079. var videoSpaceHeight = window.innerHeight;
  6080. var videoSize = VideoLayout.getVideoSize(videoWidth,
  6081. videoHeight,
  6082. videoSpaceWidth,
  6083. videoSpaceHeight);
  6084. var largeVideoWidth = videoSize[0];
  6085. var largeVideoHeight = videoSize[1];
  6086. var videoPosition = VideoLayout.getVideoPosition(largeVideoWidth,
  6087. largeVideoHeight,
  6088. videoSpaceWidth,
  6089. videoSpaceHeight);
  6090. var horizontalIndent = videoPosition[0];
  6091. var verticalIndent = videoPosition[1];
  6092. positionVideo($('#largeVideo'),
  6093. largeVideoWidth,
  6094. largeVideoHeight,
  6095. horizontalIndent, verticalIndent);
  6096. };
  6097. /**
  6098. * Shows/hides the large video.
  6099. */
  6100. my.setLargeVideoVisible = function(isVisible) {
  6101. var resourceJid = largeVideoState.userResourceJid;
  6102. if (isVisible) {
  6103. $('#largeVideo').css({visibility: 'visible'});
  6104. $('.watermark').css({visibility: 'visible'});
  6105. VideoLayout.enableDominantSpeaker(resourceJid, true);
  6106. }
  6107. else {
  6108. $('#largeVideo').css({visibility: 'hidden'});
  6109. $('#activeSpeaker').css('visibility', 'hidden');
  6110. $('.watermark').css({visibility: 'hidden'});
  6111. VideoLayout.enableDominantSpeaker(resourceJid, false);
  6112. if(focusedVideoInfo) {
  6113. var focusResourceJid = focusedVideoInfo.resourceJid;
  6114. var oldContainer = getParticipantContainer(focusResourceJid);
  6115. if (oldContainer && oldContainer.length > 0) {
  6116. oldContainer.removeClass("videoContainerFocused");
  6117. }
  6118. focusedVideoInfo = null;
  6119. if(focusResourceJid) {
  6120. Avatar.showUserAvatar(
  6121. APP.xmpp.findJidFromResource(focusResourceJid));
  6122. }
  6123. }
  6124. }
  6125. };
  6126. /**
  6127. * Indicates if the large video is currently visible.
  6128. *
  6129. * @return <tt>true</tt> if visible, <tt>false</tt> - otherwise
  6130. */
  6131. my.isLargeVideoVisible = function() {
  6132. return $('#largeVideo').is(':visible');
  6133. };
  6134. my.isLargeVideoOnTop = function () {
  6135. var Etherpad = require("../etherpad/Etherpad");
  6136. var Prezi = require("../prezi/Prezi");
  6137. return !Prezi.isPresentationVisible() && !Etherpad.isVisible();
  6138. };
  6139. /**
  6140. * Checks if container for participant identified by given peerJid exists
  6141. * in the document and creates it eventually.
  6142. *
  6143. * @param peerJid peer Jid to check.
  6144. * @param userId user email or id for setting the avatar
  6145. *
  6146. * @return Returns <tt>true</tt> if the peer container exists,
  6147. * <tt>false</tt> - otherwise
  6148. */
  6149. my.ensurePeerContainerExists = function(peerJid, userId) {
  6150. ContactList.ensureAddContact(peerJid, userId);
  6151. var resourceJid = Strophe.getResourceFromJid(peerJid);
  6152. var videoSpanId = 'participant_' + resourceJid;
  6153. if (!$('#' + videoSpanId).length) {
  6154. var container =
  6155. VideoLayout.addRemoteVideoContainer(peerJid, videoSpanId, userId);
  6156. Avatar.setUserAvatar(peerJid, userId);
  6157. // Set default display name.
  6158. setDisplayName(videoSpanId);
  6159. VideoLayout.connectionIndicators[videoSpanId] =
  6160. new ConnectionIndicator(container, peerJid, VideoLayout);
  6161. var nickfield = document.createElement('span');
  6162. nickfield.className = "nick";
  6163. nickfield.appendChild(document.createTextNode(resourceJid));
  6164. container.appendChild(nickfield);
  6165. // In case this is not currently in the last n we don't show it.
  6166. if (localLastNCount
  6167. && localLastNCount > 0
  6168. && $('#remoteVideos>span').length >= localLastNCount + 2) {
  6169. showPeerContainer(resourceJid, 'hide');
  6170. }
  6171. else
  6172. VideoLayout.resizeThumbnails();
  6173. }
  6174. };
  6175. my.addRemoteVideoContainer = function(peerJid, spanId) {
  6176. var container = document.createElement('span');
  6177. container.id = spanId;
  6178. container.className = 'videocontainer';
  6179. var remotes = document.getElementById('remoteVideos');
  6180. remotes.appendChild(container);
  6181. // If the peerJid is null then this video span couldn't be directly
  6182. // associated with a participant (this could happen in the case of prezi).
  6183. if (APP.xmpp.isModerator() && peerJid !== null)
  6184. addRemoteVideoMenu(peerJid, container);
  6185. AudioLevels.updateAudioLevelCanvas(peerJid, VideoLayout);
  6186. return container;
  6187. };
  6188. /**
  6189. * Creates an audio or video stream element.
  6190. */
  6191. my.createStreamElement = function (sid, stream) {
  6192. var isVideo = stream.getVideoTracks().length > 0;
  6193. var element = isVideo
  6194. ? document.createElement('video')
  6195. : document.createElement('audio');
  6196. var id = (isVideo ? 'remoteVideo_' : 'remoteAudio_')
  6197. + sid + '_' + APP.RTC.getStreamID(stream);
  6198. element.id = id;
  6199. element.autoplay = true;
  6200. element.oncontextmenu = function () { return false; };
  6201. return element;
  6202. };
  6203. my.addRemoteStreamElement
  6204. = function (container, sid, stream, peerJid, thessrc) {
  6205. var newElementId = null;
  6206. var isVideo = stream.getVideoTracks().length > 0;
  6207. if (container) {
  6208. var streamElement = VideoLayout.createStreamElement(sid, stream);
  6209. newElementId = streamElement.id;
  6210. container.appendChild(streamElement);
  6211. var sel = $('#' + newElementId);
  6212. sel.hide();
  6213. // If the container is currently visible we attach the stream.
  6214. if (!isVideo
  6215. || (container.offsetParent !== null && isVideo)) {
  6216. var videoStream = APP.simulcast.getReceivingVideoStream(stream);
  6217. APP.RTC.attachMediaStream(sel, videoStream);
  6218. if (isVideo)
  6219. waitForRemoteVideo(sel, thessrc, stream, peerJid);
  6220. }
  6221. stream.onended = function () {
  6222. console.log('stream ended', this);
  6223. VideoLayout.removeRemoteStreamElement(
  6224. stream, isVideo, container);
  6225. // NOTE(gp) it seems that under certain circumstances, the
  6226. // onended event is not fired and thus the contact list is not
  6227. // updated.
  6228. //
  6229. // The onended event of a stream should be fired when the SSRCs
  6230. // corresponding to that stream are removed from the SDP; but
  6231. // this doesn't seem to always be the case, resulting in ghost
  6232. // contacts.
  6233. //
  6234. // In an attempt to fix the ghost contacts problem, I'm moving
  6235. // the removeContact() method call in app.js, inside the
  6236. // 'muc.left' event handler.
  6237. //if (peerJid)
  6238. // ContactList.removeContact(peerJid);
  6239. };
  6240. // Add click handler.
  6241. container.onclick = function (event) {
  6242. /*
  6243. * FIXME It turns out that videoThumb may not exist (if there is
  6244. * no actual video).
  6245. */
  6246. var videoThumb = $('#' + container.id + '>video').get(0);
  6247. if (videoThumb) {
  6248. VideoLayout.handleVideoThumbClicked(
  6249. APP.RTC.getVideoSrc(videoThumb),
  6250. false,
  6251. Strophe.getResourceFromJid(peerJid));
  6252. }
  6253. event.stopPropagation();
  6254. event.preventDefault();
  6255. return false;
  6256. };
  6257. // Add hover handler
  6258. $(container).hover(
  6259. function() {
  6260. VideoLayout.showDisplayName(container.id, true);
  6261. },
  6262. function() {
  6263. var videoSrc = null;
  6264. if ($('#' + container.id + '>video')
  6265. && $('#' + container.id + '>video').length > 0) {
  6266. videoSrc = APP.RTC.getVideoSrc($('#' + container.id + '>video').get(0));
  6267. }
  6268. // If the video has been "pinned" by the user we want to
  6269. // keep the display name on place.
  6270. if (!VideoLayout.isLargeVideoVisible()
  6271. || videoSrc !== APP.RTC.getVideoSrc($('#largeVideo')[0]))
  6272. VideoLayout.showDisplayName(container.id, false);
  6273. }
  6274. );
  6275. }
  6276. return newElementId;
  6277. };
  6278. /**
  6279. * Removes the remote stream element corresponding to the given stream and
  6280. * parent container.
  6281. *
  6282. * @param stream the stream
  6283. * @param isVideo <tt>true</tt> if given <tt>stream</tt> is a video one.
  6284. * @param container
  6285. */
  6286. my.removeRemoteStreamElement = function (stream, isVideo, container) {
  6287. if (!container)
  6288. return;
  6289. var select = null;
  6290. var removedVideoSrc = null;
  6291. if (isVideo) {
  6292. select = $('#' + container.id + '>video');
  6293. removedVideoSrc = APP.RTC.getVideoSrc(select.get(0));
  6294. }
  6295. else
  6296. select = $('#' + container.id + '>audio');
  6297. // Mark video as removed to cancel waiting loop(if video is removed
  6298. // before has started)
  6299. select.removed = true;
  6300. select.remove();
  6301. var audioCount = $('#' + container.id + '>audio').length;
  6302. var videoCount = $('#' + container.id + '>video').length;
  6303. if (!audioCount && !videoCount) {
  6304. console.log("Remove whole user", container.id);
  6305. if(VideoLayout.connectionIndicators[container.id])
  6306. VideoLayout.connectionIndicators[container.id].remove();
  6307. // Remove whole container
  6308. container.remove();
  6309. UIUtil.playSoundNotification('userLeft');
  6310. VideoLayout.resizeThumbnails();
  6311. }
  6312. if (removedVideoSrc)
  6313. VideoLayout.updateRemovedVideo(removedVideoSrc);
  6314. };
  6315. /**
  6316. * Show/hide peer container for the given resourceJid.
  6317. */
  6318. function showPeerContainer(resourceJid, state) {
  6319. var peerContainer = $('#participant_' + resourceJid);
  6320. if (!peerContainer)
  6321. return;
  6322. var isHide = state === 'hide';
  6323. var resizeThumbnails = false;
  6324. if (!isHide) {
  6325. if (!peerContainer.is(':visible')) {
  6326. resizeThumbnails = true;
  6327. peerContainer.show();
  6328. }
  6329. var jid = APP.xmpp.findJidFromResource(resourceJid);
  6330. if (state == 'show')
  6331. {
  6332. // peerContainer.css('-webkit-filter', '');
  6333. Avatar.showUserAvatar(jid, false);
  6334. }
  6335. else // if (state == 'avatar')
  6336. {
  6337. // peerContainer.css('-webkit-filter', 'grayscale(100%)');
  6338. Avatar.showUserAvatar(jid, true);
  6339. }
  6340. }
  6341. else if (peerContainer.is(':visible') && isHide)
  6342. {
  6343. resizeThumbnails = true;
  6344. peerContainer.hide();
  6345. if(VideoLayout.connectionIndicators['participant_' + resourceJid])
  6346. VideoLayout.connectionIndicators['participant_' + resourceJid].hide();
  6347. }
  6348. if (resizeThumbnails) {
  6349. VideoLayout.resizeThumbnails();
  6350. }
  6351. // We want to be able to pin a participant from the contact list, even
  6352. // if he's not in the lastN set!
  6353. // ContactList.setClickable(resourceJid, !isHide);
  6354. };
  6355. my.inputDisplayNameHandler = function (name) {
  6356. NicknameHandler.setNickname(name);
  6357. if (!$('#localDisplayName').is(":visible")) {
  6358. if (NicknameHandler.getNickname())
  6359. $('#localDisplayName').text(NicknameHandler.getNickname() + " (me)");
  6360. else
  6361. $('#localDisplayName')
  6362. .text(interfaceConfig.DEFAULT_LOCAL_DISPLAY_NAME);
  6363. $('#localDisplayName').show();
  6364. }
  6365. $('#editDisplayName').hide();
  6366. };
  6367. /**
  6368. * Shows/hides the display name on the remote video.
  6369. * @param videoSpanId the identifier of the video span element
  6370. * @param isShow indicates if the display name should be shown or hidden
  6371. */
  6372. my.showDisplayName = function(videoSpanId, isShow) {
  6373. var nameSpan = $('#' + videoSpanId + '>span.displayname').get(0);
  6374. if (isShow) {
  6375. if (nameSpan && nameSpan.innerHTML && nameSpan.innerHTML.length)
  6376. nameSpan.setAttribute("style", "display:inline-block;");
  6377. }
  6378. else {
  6379. if (nameSpan)
  6380. nameSpan.setAttribute("style", "display:none;");
  6381. }
  6382. };
  6383. /**
  6384. * Shows the presence status message for the given video.
  6385. */
  6386. my.setPresenceStatus = function (videoSpanId, statusMsg) {
  6387. if (!$('#' + videoSpanId).length) {
  6388. // No container
  6389. return;
  6390. }
  6391. var statusSpan = $('#' + videoSpanId + '>span.status');
  6392. if (!statusSpan.length) {
  6393. //Add status span
  6394. statusSpan = document.createElement('span');
  6395. statusSpan.className = 'status';
  6396. statusSpan.id = videoSpanId + '_status';
  6397. $('#' + videoSpanId)[0].appendChild(statusSpan);
  6398. statusSpan = $('#' + videoSpanId + '>span.status');
  6399. }
  6400. // Display status
  6401. if (statusMsg && statusMsg.length) {
  6402. $('#' + videoSpanId + '_status').text(statusMsg);
  6403. statusSpan.get(0).setAttribute("style", "display:inline-block;");
  6404. }
  6405. else {
  6406. // Hide
  6407. statusSpan.get(0).setAttribute("style", "display:none;");
  6408. }
  6409. };
  6410. /**
  6411. * Shows a visual indicator for the moderator of the conference.
  6412. */
  6413. my.showModeratorIndicator = function () {
  6414. var isModerator = APP.xmpp.isModerator();
  6415. if (isModerator) {
  6416. var indicatorSpan = $('#localVideoContainer .focusindicator');
  6417. if (indicatorSpan.children().length === 0)
  6418. {
  6419. createModeratorIndicatorElement(indicatorSpan[0]);
  6420. //translates text in focus indicator
  6421. APP.translation.translateElement($('#localVideoContainer .focusindicator'));
  6422. }
  6423. }
  6424. var members = APP.xmpp.getMembers();
  6425. Object.keys(members).forEach(function (jid) {
  6426. if (Strophe.getResourceFromJid(jid) === 'focus') {
  6427. // Skip server side focus
  6428. return;
  6429. }
  6430. var resourceJid = Strophe.getResourceFromJid(jid);
  6431. var videoSpanId = 'participant_' + resourceJid;
  6432. var videoContainer = document.getElementById(videoSpanId);
  6433. if (!videoContainer) {
  6434. console.error("No video container for " + jid);
  6435. return;
  6436. }
  6437. var member = members[jid];
  6438. if (member.role === 'moderator') {
  6439. // Remove menu if peer is moderator
  6440. var menuSpan = $('#' + videoSpanId + '>span.remotevideomenu');
  6441. if (menuSpan.length) {
  6442. removeRemoteVideoMenu(videoSpanId);
  6443. }
  6444. // Show moderator indicator
  6445. var indicatorSpan
  6446. = $('#' + videoSpanId + ' .focusindicator');
  6447. if (!indicatorSpan || indicatorSpan.length === 0) {
  6448. indicatorSpan = document.createElement('span');
  6449. indicatorSpan.className = 'focusindicator';
  6450. videoContainer.appendChild(indicatorSpan);
  6451. createModeratorIndicatorElement(indicatorSpan);
  6452. //translates text in focus indicators
  6453. APP.translation.translateElement($('#' + videoSpanId + ' .focusindicator'));
  6454. }
  6455. } else if (isModerator) {
  6456. // We are moderator, but user is not - add menu
  6457. if ($('#remote_popupmenu_' + resourceJid).length <= 0) {
  6458. addRemoteVideoMenu(
  6459. jid,
  6460. document.getElementById('participant_' + resourceJid));
  6461. }
  6462. }
  6463. });
  6464. };
  6465. /**
  6466. * Shows video muted indicator over small videos.
  6467. */
  6468. my.showVideoIndicator = function(videoSpanId, isMuted) {
  6469. var videoMutedSpan = $('#' + videoSpanId + '>span.videoMuted');
  6470. if (isMuted === 'false') {
  6471. if (videoMutedSpan.length > 0) {
  6472. videoMutedSpan.remove();
  6473. }
  6474. }
  6475. else {
  6476. if(videoMutedSpan.length == 0) {
  6477. videoMutedSpan = document.createElement('span');
  6478. videoMutedSpan.className = 'videoMuted';
  6479. $('#' + videoSpanId)[0].appendChild(videoMutedSpan);
  6480. var mutedIndicator = document.createElement('i');
  6481. mutedIndicator.className = 'icon-camera-disabled';
  6482. UIUtil.setTooltip(mutedIndicator,
  6483. "videothumbnail.videomute",
  6484. "top");
  6485. videoMutedSpan.appendChild(mutedIndicator);
  6486. //translate texts for muted indicator
  6487. APP.translation.translateElement($('#' + videoSpanId + " > i"));
  6488. }
  6489. VideoLayout.updateMutePosition(videoSpanId);
  6490. }
  6491. };
  6492. my.updateMutePosition = function (videoSpanId) {
  6493. var audioMutedSpan = $('#' + videoSpanId + '>span.audioMuted');
  6494. var connectionIndicator = $('#' + videoSpanId + '>div.connectionindicator');
  6495. var videoMutedSpan = $('#' + videoSpanId + '>span.videoMuted');
  6496. if(connectionIndicator.length > 0
  6497. && connectionIndicator[0].style.display != "none") {
  6498. audioMutedSpan.css({right: "23px"});
  6499. videoMutedSpan.css({right: ((audioMutedSpan.length > 0? 23 : 0) + 30) + "px"});
  6500. }
  6501. else
  6502. {
  6503. audioMutedSpan.css({right: "0px"});
  6504. videoMutedSpan.css({right: (audioMutedSpan.length > 0? 30 : 0) + "px"});
  6505. }
  6506. }
  6507. /**
  6508. * Shows audio muted indicator over small videos.
  6509. * @param {string} isMuted
  6510. */
  6511. my.showAudioIndicator = function(videoSpanId, isMuted) {
  6512. var audioMutedSpan = $('#' + videoSpanId + '>span.audioMuted');
  6513. if (isMuted === 'false') {
  6514. if (audioMutedSpan.length > 0) {
  6515. audioMutedSpan.popover('hide');
  6516. audioMutedSpan.remove();
  6517. }
  6518. }
  6519. else {
  6520. if(audioMutedSpan.length == 0 ) {
  6521. audioMutedSpan = document.createElement('span');
  6522. audioMutedSpan.className = 'audioMuted';
  6523. UIUtil.setTooltip(audioMutedSpan,
  6524. "videothumbnail.mute",
  6525. "top");
  6526. $('#' + videoSpanId)[0].appendChild(audioMutedSpan);
  6527. APP.translation.translateElement($('#' + videoSpanId + " > span"));
  6528. var mutedIndicator = document.createElement('i');
  6529. mutedIndicator.className = 'icon-mic-disabled';
  6530. audioMutedSpan.appendChild(mutedIndicator);
  6531. }
  6532. VideoLayout.updateMutePosition(videoSpanId);
  6533. }
  6534. };
  6535. /*
  6536. * Shows or hides the audio muted indicator over the local thumbnail video.
  6537. * @param {boolean} isMuted
  6538. */
  6539. my.showLocalAudioIndicator = function(isMuted) {
  6540. VideoLayout.showAudioIndicator('localVideoContainer', isMuted.toString());
  6541. };
  6542. /**
  6543. * Resizes the large video container.
  6544. */
  6545. my.resizeLargeVideoContainer = function () {
  6546. Chat.resizeChat();
  6547. var availableHeight = window.innerHeight;
  6548. var availableWidth = UIUtil.getAvailableVideoWidth();
  6549. if (availableWidth < 0 || availableHeight < 0) return;
  6550. $('#videospace').width(availableWidth);
  6551. $('#videospace').height(availableHeight);
  6552. $('#largeVideoContainer').width(availableWidth);
  6553. $('#largeVideoContainer').height(availableHeight);
  6554. var avatarSize = interfaceConfig.ACTIVE_SPEAKER_AVATAR_SIZE;
  6555. var top = availableHeight / 2 - avatarSize / 4 * 3;
  6556. $('#activeSpeaker').css('top', top);
  6557. VideoLayout.resizeThumbnails();
  6558. };
  6559. /**
  6560. * Resizes thumbnails.
  6561. */
  6562. my.resizeThumbnails = function() {
  6563. var videoSpaceWidth = $('#remoteVideos').width();
  6564. var thumbnailSize = VideoLayout.calculateThumbnailSize(videoSpaceWidth);
  6565. var width = thumbnailSize[0];
  6566. var height = thumbnailSize[1];
  6567. // size videos so that while keeping AR and max height, we have a
  6568. // nice fit
  6569. $('#remoteVideos').height(height);
  6570. $('#remoteVideos>span').width(width);
  6571. $('#remoteVideos>span').height(height);
  6572. $('.userAvatar').css('left', (width - height) / 2);
  6573. $(document).trigger("remotevideo.resized", [width, height]);
  6574. };
  6575. /**
  6576. * Enables the dominant speaker UI.
  6577. *
  6578. * @param resourceJid the jid indicating the video element to
  6579. * activate/deactivate
  6580. * @param isEnable indicates if the dominant speaker should be enabled or
  6581. * disabled
  6582. */
  6583. my.enableDominantSpeaker = function(resourceJid, isEnable) {
  6584. var videoSpanId = null;
  6585. var videoContainerId = null;
  6586. if (resourceJid
  6587. === APP.xmpp.myResource()) {
  6588. videoSpanId = 'localVideoWrapper';
  6589. videoContainerId = 'localVideoContainer';
  6590. }
  6591. else {
  6592. videoSpanId = 'participant_' + resourceJid;
  6593. videoContainerId = videoSpanId;
  6594. }
  6595. var displayName = resourceJid;
  6596. var nameSpan = $('#' + videoContainerId + '>span.displayname');
  6597. if (nameSpan.length > 0)
  6598. displayName = nameSpan.html();
  6599. console.log("UI enable dominant speaker",
  6600. displayName,
  6601. resourceJid,
  6602. isEnable);
  6603. videoSpan = document.getElementById(videoContainerId);
  6604. if (!videoSpan) {
  6605. return;
  6606. }
  6607. var video = $('#' + videoSpanId + '>video');
  6608. if (video && video.length > 0) {
  6609. if (isEnable) {
  6610. var isLargeVideoVisible = VideoLayout.isLargeVideoOnTop();
  6611. VideoLayout.showDisplayName(videoContainerId, isLargeVideoVisible);
  6612. if (!videoSpan.classList.contains("dominantspeaker"))
  6613. videoSpan.classList.add("dominantspeaker");
  6614. }
  6615. else {
  6616. VideoLayout.showDisplayName(videoContainerId, false);
  6617. if (videoSpan.classList.contains("dominantspeaker"))
  6618. videoSpan.classList.remove("dominantspeaker");
  6619. }
  6620. Avatar.showUserAvatar(
  6621. APP.xmpp.findJidFromResource(resourceJid));
  6622. }
  6623. };
  6624. /**
  6625. * Calculates the thumbnail size.
  6626. *
  6627. * @param videoSpaceWidth the width of the video space
  6628. */
  6629. my.calculateThumbnailSize = function (videoSpaceWidth) {
  6630. // Calculate the available height, which is the inner window height minus
  6631. // 39px for the header minus 2px for the delimiter lines on the top and
  6632. // bottom of the large video, minus the 36px space inside the remoteVideos
  6633. // container used for highlighting shadow.
  6634. var availableHeight = 100;
  6635. var numvids = $('#remoteVideos>span:visible').length;
  6636. if (localLastNCount && localLastNCount > 0) {
  6637. numvids = Math.min(localLastNCount + 1, numvids);
  6638. }
  6639. // Remove the 3px borders arround videos and border around the remote
  6640. // videos area and the 4 pixels between the local video and the others
  6641. //TODO: Find out where the 4 pixels come from and remove them
  6642. var availableWinWidth = videoSpaceWidth - 2 * 3 * numvids - 70 - 4;
  6643. var availableWidth = availableWinWidth / numvids;
  6644. var aspectRatio = 16.0 / 9.0;
  6645. var maxHeight = Math.min(160, availableHeight);
  6646. availableHeight = Math.min(maxHeight, availableWidth / aspectRatio);
  6647. if (availableHeight < availableWidth / aspectRatio) {
  6648. availableWidth = Math.floor(availableHeight * aspectRatio);
  6649. }
  6650. return [availableWidth, availableHeight];
  6651. };
  6652. /**
  6653. * Updates the remote video menu.
  6654. *
  6655. * @param jid the jid indicating the video for which we're adding a menu.
  6656. * @param isMuted indicates the current mute state
  6657. */
  6658. my.updateRemoteVideoMenu = function(jid, isMuted) {
  6659. var muteMenuItem
  6660. = $('#remote_popupmenu_'
  6661. + Strophe.getResourceFromJid(jid)
  6662. + '>li>a.mutelink');
  6663. var mutedIndicator = "<i class='icon-mic-disabled'></i>";
  6664. if (muteMenuItem.length) {
  6665. var muteLink = muteMenuItem.get(0);
  6666. if (isMuted === 'true') {
  6667. muteLink.innerHTML = mutedIndicator + ' Muted';
  6668. muteLink.className = 'mutelink disabled';
  6669. }
  6670. else {
  6671. muteLink.innerHTML = mutedIndicator + ' Mute';
  6672. muteLink.className = 'mutelink';
  6673. }
  6674. }
  6675. };
  6676. /**
  6677. * Returns the current dominant speaker resource jid.
  6678. */
  6679. my.getDominantSpeakerResourceJid = function () {
  6680. return currentDominantSpeaker;
  6681. };
  6682. /**
  6683. * Returns the corresponding resource jid to the given peer container
  6684. * DOM element.
  6685. *
  6686. * @return the corresponding resource jid to the given peer container
  6687. * DOM element
  6688. */
  6689. my.getPeerContainerResourceJid = function (containerElement) {
  6690. var i = containerElement.id.indexOf('participant_');
  6691. if (i >= 0)
  6692. return containerElement.id.substring(i + 12);
  6693. };
  6694. /**
  6695. * On contact list item clicked.
  6696. */
  6697. $(ContactList).bind('contactclicked', function(event, jid) {
  6698. if (!jid) {
  6699. return;
  6700. }
  6701. var resource = Strophe.getResourceFromJid(jid);
  6702. var videoContainer = $("#participant_" + resource);
  6703. if (videoContainer.length > 0) {
  6704. var videoThumb = $('video', videoContainer).get(0);
  6705. // It is not always the case that a videoThumb exists (if there is
  6706. // no actual video).
  6707. if (videoThumb) {
  6708. if (videoThumb.src && videoThumb.src != '') {
  6709. // We have a video src, great! Let's update the large video
  6710. // now.
  6711. VideoLayout.handleVideoThumbClicked(
  6712. videoThumb.src,
  6713. false,
  6714. Strophe.getResourceFromJid(jid));
  6715. } else {
  6716. // If we don't have a video src for jid, there's absolutely
  6717. // no point in calling handleVideoThumbClicked; Quite
  6718. // simply, it won't work because it needs an src to attach
  6719. // to the large video.
  6720. //
  6721. // Instead, we trigger the pinned endpoint changed event to
  6722. // let the bridge adjust its lastN set for myjid and store
  6723. // the pinned user in the lastNPickupJid variable to be
  6724. // picked up later by the lastN changed event handler.
  6725. lastNPickupJid = jid;
  6726. eventEmitter.emit(UIEvents.PINNED_ENDPOINT,
  6727. Strophe.getResourceFromJid(jid));
  6728. }
  6729. } else if (jid == APP.xmpp.myJid()) {
  6730. $("#localVideoContainer").click();
  6731. }
  6732. }
  6733. });
  6734. /**
  6735. * On audio muted event.
  6736. */
  6737. $(document).bind('audiomuted.muc', function (event, jid, isMuted) {
  6738. /*
  6739. // FIXME: but focus can not mute in this case ? - check
  6740. if (jid === xmpp.myJid()) {
  6741. // The local mute indicator is controlled locally
  6742. return;
  6743. }*/
  6744. var videoSpanId = null;
  6745. if (jid === APP.xmpp.myJid()) {
  6746. videoSpanId = 'localVideoContainer';
  6747. } else {
  6748. VideoLayout.ensurePeerContainerExists(jid);
  6749. videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
  6750. }
  6751. mutedAudios[jid] = isMuted;
  6752. if (APP.xmpp.isModerator()) {
  6753. VideoLayout.updateRemoteVideoMenu(jid, isMuted);
  6754. }
  6755. if (videoSpanId)
  6756. VideoLayout.showAudioIndicator(videoSpanId, isMuted);
  6757. });
  6758. /**
  6759. * On video muted event.
  6760. */
  6761. $(document).bind('videomuted.muc', function (event, jid, value) {
  6762. var isMuted = (value === "true");
  6763. if(!APP.RTC.muteRemoteVideoStream(jid, isMuted))
  6764. return;
  6765. Avatar.showUserAvatar(jid, isMuted);
  6766. var videoSpanId = null;
  6767. if (jid === APP.xmpp.myJid()) {
  6768. videoSpanId = 'localVideoContainer';
  6769. } else {
  6770. VideoLayout.ensurePeerContainerExists(jid);
  6771. videoSpanId = 'participant_' + Strophe.getResourceFromJid(jid);
  6772. }
  6773. if (videoSpanId)
  6774. VideoLayout.showVideoIndicator(videoSpanId, value);
  6775. });
  6776. /**
  6777. * Display name changed.
  6778. */
  6779. my.onDisplayNameChanged =
  6780. function (jid, displayName, status) {
  6781. if (jid === 'localVideoContainer'
  6782. || jid === APP.xmpp.myJid()) {
  6783. setDisplayName('localVideoContainer',
  6784. displayName);
  6785. } else {
  6786. VideoLayout.ensurePeerContainerExists(jid);
  6787. setDisplayName(
  6788. 'participant_' + Strophe.getResourceFromJid(jid),
  6789. displayName,
  6790. status);
  6791. }
  6792. };
  6793. /**
  6794. * On dominant speaker changed event.
  6795. */
  6796. my.onDominantSpeakerChanged = function (resourceJid) {
  6797. // We ignore local user events.
  6798. if (resourceJid
  6799. === APP.xmpp.myResource())
  6800. return;
  6801. // Update the current dominant speaker.
  6802. if (resourceJid !== currentDominantSpeaker) {
  6803. var oldSpeakerVideoSpanId = "participant_" + currentDominantSpeaker,
  6804. newSpeakerVideoSpanId = "participant_" + resourceJid;
  6805. if($("#" + oldSpeakerVideoSpanId + ">span.displayname").text() ===
  6806. interfaceConfig.DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME) {
  6807. setDisplayName(oldSpeakerVideoSpanId, null);
  6808. }
  6809. if($("#" + newSpeakerVideoSpanId + ">span.displayname").text() ===
  6810. interfaceConfig.DEFAULT_REMOTE_DISPLAY_NAME) {
  6811. setDisplayName(newSpeakerVideoSpanId,
  6812. interfaceConfig.DEFAULT_DOMINANT_SPEAKER_DISPLAY_NAME);
  6813. }
  6814. currentDominantSpeaker = resourceJid;
  6815. } else {
  6816. return;
  6817. }
  6818. // Obtain container for new dominant speaker.
  6819. var container = document.getElementById(
  6820. 'participant_' + resourceJid);
  6821. // Local video will not have container found, but that's ok
  6822. // since we don't want to switch to local video.
  6823. if (container && !focusedVideoInfo)
  6824. {
  6825. var video = container.getElementsByTagName("video");
  6826. // Update the large video if the video source is already available,
  6827. // otherwise wait for the "videoactive.jingle" event.
  6828. if (video.length && video[0].currentTime > 0)
  6829. VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(video[0]), resourceJid);
  6830. }
  6831. };
  6832. /**
  6833. * On last N change event.
  6834. *
  6835. * @param lastNEndpoints the list of last N endpoints
  6836. * @param endpointsEnteringLastN the list currently entering last N
  6837. * endpoints
  6838. */
  6839. my.onLastNEndpointsChanged = function ( lastNEndpoints,
  6840. endpointsEnteringLastN,
  6841. stream) {
  6842. if (lastNCount !== lastNEndpoints.length)
  6843. lastNCount = lastNEndpoints.length;
  6844. lastNEndpointsCache = lastNEndpoints;
  6845. // Say A, B, C, D, E, and F are in a conference and LastN = 3.
  6846. //
  6847. // If LastN drops to, say, 2, because of adaptivity, then E should see
  6848. // thumbnails for A, B and C. A and B are in E's server side LastN set,
  6849. // so E sees them. C is only in E's local LastN set.
  6850. //
  6851. // If F starts talking and LastN = 3, then E should see thumbnails for
  6852. // F, A, B. B gets "ejected" from E's server side LastN set, but it
  6853. // enters E's local LastN ejecting C.
  6854. // Increase the local LastN set size, if necessary.
  6855. if (lastNCount > localLastNCount) {
  6856. localLastNCount = lastNCount;
  6857. }
  6858. // Update the local LastN set preserving the order in which the
  6859. // endpoints appeared in the LastN/local LastN set.
  6860. var nextLocalLastNSet = lastNEndpoints.slice(0);
  6861. for (var i = 0; i < localLastNSet.length; i++) {
  6862. if (nextLocalLastNSet.length >= localLastNCount) {
  6863. break;
  6864. }
  6865. var resourceJid = localLastNSet[i];
  6866. if (nextLocalLastNSet.indexOf(resourceJid) === -1) {
  6867. nextLocalLastNSet.push(resourceJid);
  6868. }
  6869. }
  6870. localLastNSet = nextLocalLastNSet;
  6871. var updateLargeVideo = false;
  6872. // Handle LastN/local LastN changes.
  6873. $('#remoteVideos>span').each(function( index, element ) {
  6874. var resourceJid = VideoLayout.getPeerContainerResourceJid(element);
  6875. var isReceived = true;
  6876. if (resourceJid
  6877. && lastNEndpoints.indexOf(resourceJid) < 0
  6878. && localLastNSet.indexOf(resourceJid) < 0) {
  6879. console.log("Remove from last N", resourceJid);
  6880. showPeerContainer(resourceJid, 'hide');
  6881. isReceived = false;
  6882. } else if (resourceJid
  6883. && $('#participant_' + resourceJid).is(':visible')
  6884. && lastNEndpoints.indexOf(resourceJid) < 0
  6885. && localLastNSet.indexOf(resourceJid) >= 0) {
  6886. showPeerContainer(resourceJid, 'avatar');
  6887. isReceived = false;
  6888. }
  6889. if (!isReceived) {
  6890. // resourceJid has dropped out of the server side lastN set, so
  6891. // it is no longer being received. If resourceJid was being
  6892. // displayed in the large video we have to switch to another
  6893. // user.
  6894. var largeVideoResource = largeVideoState.userResourceJid;
  6895. if (!updateLargeVideo && resourceJid === largeVideoResource) {
  6896. updateLargeVideo = true;
  6897. }
  6898. }
  6899. });
  6900. if (!endpointsEnteringLastN || endpointsEnteringLastN.length < 0)
  6901. endpointsEnteringLastN = lastNEndpoints;
  6902. if (endpointsEnteringLastN && endpointsEnteringLastN.length > 0) {
  6903. endpointsEnteringLastN.forEach(function (resourceJid) {
  6904. var isVisible = $('#participant_' + resourceJid).is(':visible');
  6905. showPeerContainer(resourceJid, 'show');
  6906. if (!isVisible) {
  6907. console.log("Add to last N", resourceJid);
  6908. var jid = APP.xmpp.findJidFromResource(resourceJid);
  6909. var mediaStream = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
  6910. var sel = $('#participant_' + resourceJid + '>video');
  6911. var videoStream = APP.simulcast.getReceivingVideoStream(
  6912. mediaStream.stream);
  6913. APP.RTC.attachMediaStream(sel, videoStream);
  6914. if (lastNPickupJid == mediaStream.peerjid) {
  6915. // Clean up the lastN pickup jid.
  6916. lastNPickupJid = null;
  6917. // Don't fire the events again, they've already
  6918. // been fired in the contact list click handler.
  6919. VideoLayout.handleVideoThumbClicked(
  6920. $(sel).attr('src'),
  6921. false,
  6922. Strophe.getResourceFromJid(mediaStream.peerjid));
  6923. updateLargeVideo = false;
  6924. }
  6925. waitForRemoteVideo(sel, mediaStream.ssrc, mediaStream.stream, resourceJid);
  6926. }
  6927. })
  6928. }
  6929. // The endpoint that was being shown in the large video has dropped out
  6930. // of the lastN set and there was no lastN pickup jid. We need to update
  6931. // the large video now.
  6932. if (updateLargeVideo) {
  6933. var resource, container, src;
  6934. var myResource
  6935. = APP.xmpp.myResource();
  6936. // Find out which endpoint to show in the large video.
  6937. for (var i = 0; i < lastNEndpoints.length; i++) {
  6938. resource = lastNEndpoints[i];
  6939. if (!resource || resource === myResource)
  6940. continue;
  6941. container = $("#participant_" + resource);
  6942. if (container.length == 0)
  6943. continue;
  6944. src = $('video', container).attr('src');
  6945. if (!src)
  6946. continue;
  6947. // videoSrcToSsrc needs to be update for this call to succeed.
  6948. VideoLayout.updateLargeVideo(src);
  6949. break;
  6950. }
  6951. }
  6952. };
  6953. my.onSimulcastLayersChanging = function (endpointSimulcastLayers) {
  6954. endpointSimulcastLayers.forEach(function (esl) {
  6955. var resource = esl.endpoint;
  6956. // if lastN is enabled *and* the endpoint is *not* in the lastN set,
  6957. // then ignore the event (= do not preload anything).
  6958. //
  6959. // The bridge could probably stop sending this message if it's for
  6960. // an endpoint that's not in lastN.
  6961. if (lastNCount != -1
  6962. && (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) {
  6963. return;
  6964. }
  6965. var primarySSRC = esl.simulcastLayer.primarySSRC;
  6966. // Get session and stream from primary ssrc.
  6967. var res = APP.simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
  6968. var sid = res.sid;
  6969. var electedStream = res.stream;
  6970. if (sid && electedStream) {
  6971. var msid = APP.simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
  6972. console.info([esl, primarySSRC, msid, sid, electedStream]);
  6973. var preload = (Strophe.getResourceFromJid(APP.xmpp.getJidFromSSRC(primarySSRC)) == largeVideoState.userResourceJid);
  6974. if (preload) {
  6975. if (largeVideoState.preload)
  6976. {
  6977. $(largeVideoState.preload).remove();
  6978. }
  6979. console.info('Preloading remote video');
  6980. largeVideoState.preload = $('<video autoplay></video>');
  6981. // ssrcs are unique in an rtp session
  6982. largeVideoState.preload_ssrc = primarySSRC;
  6983. APP.RTC.attachMediaStream(largeVideoState.preload, electedStream)
  6984. }
  6985. } else {
  6986. console.error('Could not find a stream or a session.', sid, electedStream);
  6987. }
  6988. });
  6989. };
  6990. /**
  6991. * On simulcast layers changed event.
  6992. */
  6993. my.onSimulcastLayersChanged = function (endpointSimulcastLayers) {
  6994. endpointSimulcastLayers.forEach(function (esl) {
  6995. var resource = esl.endpoint;
  6996. // if lastN is enabled *and* the endpoint is *not* in the lastN set,
  6997. // then ignore the event (= do not change large video/thumbnail
  6998. // SRCs).
  6999. //
  7000. // Note that even if we ignore the "changed" event in this event
  7001. // handler, the bridge must continue sending these events because
  7002. // the simulcast code in simulcast.js uses it to know what's going
  7003. // to be streamed by the bridge when/if the endpoint gets back into
  7004. // the lastN set.
  7005. if (lastNCount != -1
  7006. && (lastNCount < 1 || lastNEndpointsCache.indexOf(resource) === -1)) {
  7007. return;
  7008. }
  7009. var primarySSRC = esl.simulcastLayer.primarySSRC;
  7010. // Get session and stream from primary ssrc.
  7011. var res = APP.simulcast.getReceivingVideoStreamBySSRC(primarySSRC);
  7012. var sid = res.sid;
  7013. var electedStream = res.stream;
  7014. if (sid && electedStream) {
  7015. var msid = APP.simulcast.getRemoteVideoStreamIdBySSRC(primarySSRC);
  7016. console.info('Switching simulcast substream.');
  7017. console.info([esl, primarySSRC, msid, sid, electedStream]);
  7018. var msidParts = msid.split(' ');
  7019. var selRemoteVideo = $(['#', 'remoteVideo_', sid, '_', msidParts[0]].join(''));
  7020. var updateLargeVideo = (Strophe.getResourceFromJid(APP.xmpp.getJidFromSSRC(primarySSRC))
  7021. == largeVideoState.userResourceJid);
  7022. var updateFocusedVideoSrc = (focusedVideoInfo && focusedVideoInfo.src && focusedVideoInfo.src != '' &&
  7023. (APP.RTC.getVideoSrc(selRemoteVideo[0]) == focusedVideoInfo.src));
  7024. var electedStreamUrl;
  7025. if (largeVideoState.preload_ssrc == primarySSRC)
  7026. {
  7027. APP.RTC.setVideoSrc(selRemoteVideo[0], APP.RTC.getVideoSrc(largeVideoState.preload[0]));
  7028. }
  7029. else
  7030. {
  7031. if (largeVideoState.preload
  7032. && largeVideoState.preload != null) {
  7033. $(largeVideoState.preload).remove();
  7034. }
  7035. largeVideoState.preload_ssrc = 0;
  7036. APP.RTC.attachMediaStream(selRemoteVideo, electedStream);
  7037. }
  7038. var jid = APP.xmpp.getJidFromSSRC(primarySSRC);
  7039. if (updateLargeVideo) {
  7040. VideoLayout.updateLargeVideo(APP.RTC.getVideoSrc(selRemoteVideo[0]), null,
  7041. Strophe.getResourceFromJid(jid));
  7042. }
  7043. if (updateFocusedVideoSrc) {
  7044. focusedVideoInfo.src = APP.RTC.getVideoSrc(selRemoteVideo[0]);
  7045. }
  7046. var videoId;
  7047. if(resource == APP.xmpp.myResource())
  7048. {
  7049. videoId = "localVideoContainer";
  7050. }
  7051. else
  7052. {
  7053. videoId = "participant_" + resource;
  7054. }
  7055. var connectionIndicator = VideoLayout.connectionIndicators[videoId];
  7056. if(connectionIndicator)
  7057. connectionIndicator.updatePopoverData();
  7058. } else {
  7059. console.error('Could not find a stream or a sid.', sid, electedStream);
  7060. }
  7061. });
  7062. };
  7063. /**
  7064. * Updates local stats
  7065. * @param percent
  7066. * @param object
  7067. */
  7068. my.updateLocalConnectionStats = function (percent, object) {
  7069. var resolution = null;
  7070. if(object.resolution !== null)
  7071. {
  7072. resolution = object.resolution;
  7073. object.resolution = resolution[APP.xmpp.myJid()];
  7074. delete resolution[APP.xmpp.myJid()];
  7075. }
  7076. updateStatsIndicator("localVideoContainer", percent, object);
  7077. for(var jid in resolution)
  7078. {
  7079. if(resolution[jid] === null)
  7080. continue;
  7081. var id = 'participant_' + Strophe.getResourceFromJid(jid);
  7082. if(VideoLayout.connectionIndicators[id])
  7083. {
  7084. VideoLayout.connectionIndicators[id].updateResolution(resolution[jid]);
  7085. }
  7086. }
  7087. };
  7088. /**
  7089. * Updates remote stats.
  7090. * @param jid the jid associated with the stats
  7091. * @param percent the connection quality percent
  7092. * @param object the stats data
  7093. */
  7094. my.updateConnectionStats = function (jid, percent, object) {
  7095. var resourceJid = Strophe.getResourceFromJid(jid);
  7096. var videoSpanId = 'participant_' + resourceJid;
  7097. updateStatsIndicator(videoSpanId, percent, object);
  7098. };
  7099. /**
  7100. * Removes the connection
  7101. * @param jid
  7102. */
  7103. my.removeConnectionIndicator = function (jid) {
  7104. if(VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)])
  7105. VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)].remove();
  7106. };
  7107. /**
  7108. * Hides the connection indicator
  7109. * @param jid
  7110. */
  7111. my.hideConnectionIndicator = function (jid) {
  7112. if(VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)])
  7113. VideoLayout.connectionIndicators['participant_' + Strophe.getResourceFromJid(jid)].hide();
  7114. };
  7115. /**
  7116. * Hides all the indicators
  7117. */
  7118. my.onStatsStop = function () {
  7119. for(var indicator in VideoLayout.connectionIndicators)
  7120. {
  7121. VideoLayout.connectionIndicators[indicator].hideIndicator();
  7122. }
  7123. };
  7124. my.participantLeft = function (jid) {
  7125. // Unlock large video
  7126. if (focusedVideoInfo && focusedVideoInfo.jid === jid)
  7127. {
  7128. console.info("Focused video owner has left the conference");
  7129. focusedVideoInfo = null;
  7130. }
  7131. }
  7132. return my;
  7133. }(VideoLayout || {}));
  7134. module.exports = VideoLayout;
  7135. },{"../../../service/RTC/MediaStreamTypes":78,"../../../service/UI/UIEvents":82,"../audio_levels/AudioLevels":9,"../avatar/Avatar":12,"../etherpad/Etherpad":13,"../prezi/Prezi":14,"../side_pannels/chat/Chat":17,"../side_pannels/contactlist/ContactList":21,"../util/NicknameHandler":29,"../util/UIUtil":30,"./ConnectionIndicator":31}],33:[function(require,module,exports){
  7136. //var nouns = [
  7137. //];
  7138. var pluralNouns = [
  7139. "Aliens", "Animals", "Antelopes", "Ants", "Apes", "Apples", "Baboons", "Bacteria", "Badgers", "Bananas", "Bats",
  7140. "Bears", "Birds", "Bonobos", "Brides", "Bugs", "Bulls", "Butterflies", "Cheetahs",
  7141. "Cherries", "Chicken", "Children", "Chimps", "Clowns", "Cows", "Creatures", "Dinosaurs", "Dogs", "Dolphins",
  7142. "Donkeys", "Dragons", "Ducks", "Dwarfs", "Eagles", "Elephants", "Elves", "FAIL", "Fathers",
  7143. "Fish", "Flowers", "Frogs", "Fruit", "Fungi", "Galaxies", "Geese", "Goats",
  7144. "Gorillas", "Hedgehogs", "Hippos", "Horses", "Hunters", "Insects", "Kids", "Knights",
  7145. "Lemons", "Lemurs", "Leopards", "LifeForms", "Lions", "Lizards", "Mice", "Monkeys", "Monsters",
  7146. "Mushrooms", "Octopodes", "Oranges", "Orangutans", "Organisms", "Pants", "Parrots", "Penguins",
  7147. "People", "Pigeons", "Pigs", "Pineapples", "Plants", "Potatoes", "Priests", "Rats", "Reptiles", "Reptilians",
  7148. "Rhinos", "Seagulls", "Sheep", "Siblings", "Snakes", "Spaghetti", "Spiders", "Squid", "Squirrels",
  7149. "Stars", "Students", "Teachers", "Tigers", "Tomatoes", "Trees", "Vampires", "Vegetables", "Viruses", "Vulcans",
  7150. "Warewolves", "Weasels", "Whales", "Witches", "Wizards", "Wolves", "Workers", "Worms", "Zebras"
  7151. ];
  7152. //var places = [
  7153. //"Pub", "University", "Airport", "Library", "Mall", "Theater", "Stadium", "Office", "Show", "Gallows", "Beach",
  7154. // "Cemetery", "Hospital", "Reception", "Restaurant", "Bar", "Church", "House", "School", "Square", "Village",
  7155. // "Cinema", "Movies", "Party", "Restroom", "End", "Jail", "PostOffice", "Station", "Circus", "Gates", "Entrance",
  7156. // "Bridge"
  7157. //];
  7158. var verbs = [
  7159. "Abandon", "Adapt", "Advertise", "Answer", "Anticipate", "Appreciate",
  7160. "Approach", "Argue", "Ask", "Bite", "Blossom", "Blush", "Breathe", "Breed", "Bribe", "Burn", "Calculate",
  7161. "Clean", "Code", "Communicate", "Compute", "Confess", "Confiscate", "Conjugate", "Conjure", "Consume",
  7162. "Contemplate", "Crawl", "Dance", "Delegate", "Devour", "Develop", "Differ", "Discuss",
  7163. "Dissolve", "Drink", "Eat", "Elaborate", "Emancipate", "Estimate", "Expire", "Extinguish",
  7164. "Extract", "FAIL", "Facilitate", "Fall", "Feed", "Finish", "Floss", "Fly", "Follow", "Fragment", "Freeze",
  7165. "Gather", "Glow", "Grow", "Hex", "Hide", "Hug", "Hurry", "Improve", "Intersect", "Investigate", "Jinx",
  7166. "Joke", "Jubilate", "Kiss", "Laugh", "Manage", "Meet", "Merge", "Move", "Object", "Observe", "Offer",
  7167. "Paint", "Participate", "Party", "Perform", "Plan", "Pursue", "Pierce", "Play", "Postpone", "Pray", "Proclaim",
  7168. "Question", "Read", "Reckon", "Rejoice", "Represent", "Resize", "Rhyme", "Scream", "Search", "Select", "Share", "Shoot",
  7169. "Shout", "Signal", "Sing", "Skate", "Sleep", "Smile", "Smoke", "Solve", "Spell", "Steer", "Stink",
  7170. "Substitute", "Swim", "Taste", "Teach", "Terminate", "Think", "Type", "Unite", "Vanish", "Worship"
  7171. ];
  7172. var adverbs = [
  7173. "Absently", "Accurately", "Accusingly", "Adorably", "AllTheTime", "Alone", "Always", "Amazingly", "Angrily",
  7174. "Anxiously", "Anywhere", "Appallingly", "Apparently", "Articulately", "Astonishingly", "Badly", "Barely",
  7175. "Beautifully", "Blindly", "Bravely", "Brightly", "Briskly", "Brutally", "Calmly", "Carefully", "Casually",
  7176. "Cautiously", "Cleverly", "Constantly", "Correctly", "Crazily", "Curiously", "Cynically", "Daily",
  7177. "Dangerously", "Deliberately", "Delicately", "Desperately", "Discreetly", "Eagerly", "Easily", "Euphoricly",
  7178. "Evenly", "Everywhere", "Exactly", "Expectantly", "Extensively", "FAIL", "Ferociously", "Fiercely", "Finely",
  7179. "Flatly", "Frequently", "Frighteningly", "Gently", "Gloriously", "Grimly", "Guiltily", "Happily",
  7180. "Hard", "Hastily", "Heroically", "High", "Highly", "Hourly", "Humbly", "Hysterically", "Immensely",
  7181. "Impartially", "Impolitely", "Indifferently", "Intensely", "Jealously", "Jovially", "Kindly", "Lazily",
  7182. "Lightly", "Loudly", "Lovingly", "Loyally", "Magnificently", "Malevolently", "Merrily", "Mightily", "Miserably",
  7183. "Mysteriously", "NOT", "Nervously", "Nicely", "Nowhere", "Objectively", "Obnoxiously", "Obsessively",
  7184. "Obviously", "Often", "Painfully", "Patiently", "Playfully", "Politely", "Poorly", "Precisely", "Promptly",
  7185. "Quickly", "Quietly", "Randomly", "Rapidly", "Rarely", "Recklessly", "Regularly", "Remorsefully", "Responsibly",
  7186. "Rudely", "Ruthlessly", "Sadly", "Scornfully", "Seamlessly", "Seldom", "Selfishly", "Seriously", "Shakily",
  7187. "Sharply", "Sideways", "Silently", "Sleepily", "Slightly", "Slowly", "Slyly", "Smoothly", "Softly", "Solemnly", "Steadily", "Sternly", "Strangely", "Strongly", "Stunningly", "Surely", "Tenderly", "Thoughtfully",
  7188. "Tightly", "Uneasily", "Vanishingly", "Violently", "Warmly", "Weakly", "Wearily", "Weekly", "Weirdly", "Well",
  7189. "Well", "Wickedly", "Wildly", "Wisely", "Wonderfully", "Yearly"
  7190. ];
  7191. var adjectives = [
  7192. "Abominable", "Accurate", "Adorable", "All", "Alleged", "Ancient", "Angry", "Angry", "Anxious", "Appalling",
  7193. "Apparent", "Astonishing", "Attractive", "Awesome", "Baby", "Bad", "Beautiful", "Benign", "Big", "Bitter",
  7194. "Blind", "Blue", "Bold", "Brave", "Bright", "Brisk", "Calm", "Camouflaged", "Casual", "Cautious",
  7195. "Choppy", "Chosen", "Clever", "Cold", "Cool", "Crawly", "Crazy", "Creepy", "Cruel", "Curious", "Cynical",
  7196. "Dangerous", "Dark", "Delicate", "Desperate", "Difficult", "Discreet", "Disguised", "Dizzy",
  7197. "Dumb", "Eager", "Easy", "Edgy", "Electric", "Elegant", "Emancipated", "Enormous", "Euphoric", "Evil",
  7198. "FAIL", "Fast", "Ferocious", "Fierce", "Fine", "Flawed", "Flying", "Foolish", "Foxy",
  7199. "Freezing", "Funny", "Furious", "Gentle", "Glorious", "Golden", "Good", "Green", "Green", "Guilty",
  7200. "Hairy", "Happy", "Hard", "Hasty", "Hazy", "Heroic", "Hostile", "Hot", "Humble", "Humongous",
  7201. "Humorous", "Hysterical", "Idealistic", "Ignorant", "Immense", "Impartial", "Impolite", "Indifferent",
  7202. "Infuriated", "Insightful", "Intense", "Interesting", "Intimidated", "Intriguing", "Jealous", "Jolly", "Jovial",
  7203. "Jumpy", "Kind", "Laughing", "Lazy", "Liquid", "Lonely", "Longing", "Loud", "Loving", "Loyal", "Macabre", "Mad",
  7204. "Magical", "Magnificent", "Malevolent", "Medieval", "Memorable", "Mere", "Merry", "Mighty",
  7205. "Mischievous", "Miserable", "Modified", "Moody", "Most", "Mysterious", "Mystical", "Needy",
  7206. "Nervous", "Nice", "Objective", "Obnoxious", "Obsessive", "Obvious", "Opinionated", "Orange",
  7207. "Painful", "Passionate", "Perfect", "Pink", "Playful", "Poisonous", "Polite", "Poor", "Popular", "Powerful",
  7208. "Precise", "Preserved", "Pretty", "Purple", "Quick", "Quiet", "Random", "Rapid", "Rare", "Real",
  7209. "Reassuring", "Reckless", "Red", "Regular", "Remorseful", "Responsible", "Rich", "Rude", "Ruthless",
  7210. "Sad", "Scared", "Scary", "Scornful", "Screaming", "Selfish", "Serious", "Shady", "Shaky", "Sharp",
  7211. "Shiny", "Shy", "Simple", "Sleepy", "Slow", "Sly", "Small", "Smart", "Smelly", "Smiling", "Smooth",
  7212. "Smug", "Sober", "Soft", "Solemn", "Square", "Square", "Steady", "Strange", "Strong",
  7213. "Stunning", "Subjective", "Successful", "Surly", "Sweet", "Tactful", "Tense",
  7214. "Thoughtful", "Tight", "Tiny", "Tolerant", "Uneasy", "Unique", "Unseen", "Warm", "Weak",
  7215. "Weird", "WellCooked", "Wild", "Wise", "Witty", "Wonderful", "Worried", "Yellow", "Young",
  7216. "Zealous"
  7217. ];
  7218. //var pronouns = [
  7219. //];
  7220. //var conjunctions = [
  7221. //"And", "Or", "For", "Above", "Before", "Against", "Between"
  7222. //];
  7223. /*
  7224. * Maps a string (category name) to the array of words from that category.
  7225. */
  7226. var CATEGORIES =
  7227. {
  7228. //"_NOUN_": nouns,
  7229. "_PLURALNOUN_": pluralNouns,
  7230. //"_PLACE_": places,
  7231. "_VERB_": verbs,
  7232. "_ADVERB_": adverbs,
  7233. "_ADJECTIVE_": adjectives
  7234. //"_PRONOUN_": pronouns,
  7235. //"_CONJUNCTION_": conjunctions,
  7236. };
  7237. var PATTERNS = [
  7238. "_ADJECTIVE__PLURALNOUN__VERB__ADVERB_"
  7239. // BeautifulFungiOrSpaghetti
  7240. //"_ADJECTIVE__PLURALNOUN__CONJUNCTION__PLURALNOUN_",
  7241. // AmazinglyScaryToy
  7242. //"_ADVERB__ADJECTIVE__NOUN_",
  7243. // NeitherTrashNorRifle
  7244. //"Neither_NOUN_Nor_NOUN_",
  7245. //"Either_NOUN_Or_NOUN_",
  7246. // EitherCopulateOrInvestigate
  7247. //"Either_VERB_Or_VERB_",
  7248. //"Neither_VERB_Nor_VERB_",
  7249. //"The_ADJECTIVE__ADJECTIVE__NOUN_",
  7250. //"The_ADVERB__ADJECTIVE__NOUN_",
  7251. //"The_ADVERB__ADJECTIVE__NOUN_s",
  7252. //"The_ADVERB__ADJECTIVE__PLURALNOUN__VERB_",
  7253. // WolvesComputeBadly
  7254. //"_PLURALNOUN__VERB__ADVERB_",
  7255. // UniteFacilitateAndMerge
  7256. //"_VERB__VERB_And_VERB_",
  7257. //NastyWitchesAtThePub
  7258. //"_ADJECTIVE__PLURALNOUN_AtThe_PLACE_",
  7259. ];
  7260. /*
  7261. * Returns a random element from the array 'arr'
  7262. */
  7263. function randomElement(arr)
  7264. {
  7265. return arr[Math.floor(Math.random() * arr.length)];
  7266. }
  7267. /*
  7268. * Returns true if the string 's' contains one of the
  7269. * template strings.
  7270. */
  7271. function hasTemplate(s)
  7272. {
  7273. for (var template in CATEGORIES){
  7274. if (s.indexOf(template) >= 0){
  7275. return true;
  7276. }
  7277. }
  7278. }
  7279. /**
  7280. * Generates new room name.
  7281. */
  7282. var RoomNameGenerator = {
  7283. generateRoomWithoutSeparator: function()
  7284. {
  7285. // Note that if more than one pattern is available, the choice of 'name' won't be random (names from patterns
  7286. // with fewer options will have higher probability of being chosen that names from patterns with more options).
  7287. var name = randomElement(PATTERNS);
  7288. var word;
  7289. while (hasTemplate(name)){
  7290. for (var template in CATEGORIES){
  7291. word = randomElement(CATEGORIES[template]);
  7292. name = name.replace(template, word);
  7293. }
  7294. }
  7295. return name;
  7296. }
  7297. }
  7298. module.exports = RoomNameGenerator;
  7299. },{}],34:[function(require,module,exports){
  7300. var animateTimeout, updateTimeout;
  7301. var RoomNameGenerator = require("./RoomnameGenerator");
  7302. function enter_room()
  7303. {
  7304. var val = $("#enter_room_field").val();
  7305. if(!val) {
  7306. val = $("#enter_room_field").attr("room_name");
  7307. }
  7308. if (val) {
  7309. window.location.pathname = "/" + val;
  7310. }
  7311. }
  7312. function animate(word) {
  7313. var currentVal = $("#enter_room_field").attr("placeholder");
  7314. $("#enter_room_field").attr("placeholder", currentVal + word.substr(0, 1));
  7315. animateTimeout = setTimeout(function() {
  7316. animate(word.substring(1, word.length))
  7317. }, 70);
  7318. }
  7319. function update_roomname()
  7320. {
  7321. var word = RoomNameGenerator.generateRoomWithoutSeparator();
  7322. $("#enter_room_field").attr("room_name", word);
  7323. $("#enter_room_field").attr("placeholder", "");
  7324. clearTimeout(animateTimeout);
  7325. animate(word);
  7326. updateTimeout = setTimeout(update_roomname, 10000);
  7327. }
  7328. function setupWelcomePage()
  7329. {
  7330. $("#videoconference_page").hide();
  7331. $("#domain_name").text(
  7332. window.location.protocol + "//" + window.location.host + "/");
  7333. if (interfaceConfig.SHOW_JITSI_WATERMARK) {
  7334. var leftWatermarkDiv
  7335. = $("#welcome_page_header div[class='watermark leftwatermark']");
  7336. if(leftWatermarkDiv && leftWatermarkDiv.length > 0)
  7337. {
  7338. leftWatermarkDiv.css({display: 'block'});
  7339. leftWatermarkDiv.parent().get(0).href
  7340. = interfaceConfig.JITSI_WATERMARK_LINK;
  7341. }
  7342. }
  7343. if (interfaceConfig.SHOW_BRAND_WATERMARK) {
  7344. var rightWatermarkDiv
  7345. = $("#welcome_page_header div[class='watermark rightwatermark']");
  7346. if(rightWatermarkDiv && rightWatermarkDiv.length > 0) {
  7347. rightWatermarkDiv.css({display: 'block'});
  7348. rightWatermarkDiv.parent().get(0).href
  7349. = interfaceConfig.BRAND_WATERMARK_LINK;
  7350. rightWatermarkDiv.get(0).style.backgroundImage
  7351. = "url(images/rightwatermark.png)";
  7352. }
  7353. }
  7354. if (interfaceConfig.SHOW_POWERED_BY) {
  7355. $("#welcome_page_header>a[class='poweredby']")
  7356. .css({display: 'block'});
  7357. }
  7358. $("#enter_room_button").click(function()
  7359. {
  7360. enter_room();
  7361. });
  7362. $("#enter_room_field").keydown(function (event) {
  7363. if (event.keyCode === 13 /* enter */) {
  7364. enter_room();
  7365. }
  7366. });
  7367. if (!(interfaceConfig.GENERATE_ROOMNAMES_ON_WELCOME_PAGE === false)){
  7368. var updateTimeout;
  7369. var animateTimeout;
  7370. $("#reload_roomname").click(function () {
  7371. clearTimeout(updateTimeout);
  7372. clearTimeout(animateTimeout);
  7373. update_roomname();
  7374. });
  7375. $("#reload_roomname").show();
  7376. update_roomname();
  7377. }
  7378. $("#disable_welcome").click(function () {
  7379. window.localStorage.welcomePageDisabled
  7380. = $("#disable_welcome").is(":checked");
  7381. });
  7382. }
  7383. module.exports = setupWelcomePage;
  7384. },{"./RoomnameGenerator":33}],35:[function(require,module,exports){
  7385. var EventEmitter = require("events");
  7386. var eventEmitter = new EventEmitter();
  7387. var CQEvents = require("../../service/connectionquality/CQEvents");
  7388. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  7389. /**
  7390. * local stats
  7391. * @type {{}}
  7392. */
  7393. var stats = {};
  7394. /**
  7395. * remote stats
  7396. * @type {{}}
  7397. */
  7398. var remoteStats = {};
  7399. /**
  7400. * Interval for sending statistics to other participants
  7401. * @type {null}
  7402. */
  7403. var sendIntervalId = null;
  7404. /**
  7405. * Start statistics sending.
  7406. */
  7407. function startSendingStats() {
  7408. sendStats();
  7409. sendIntervalId = setInterval(sendStats, 10000);
  7410. }
  7411. /**
  7412. * Sends statistics to other participants
  7413. */
  7414. function sendStats() {
  7415. APP.xmpp.addToPresence("connectionQuality", convertToMUCStats(stats));
  7416. }
  7417. /**
  7418. * Converts statistics to format for sending through XMPP
  7419. * @param stats the statistics
  7420. * @returns {{bitrate_donwload: *, bitrate_uplpoad: *, packetLoss_total: *, packetLoss_download: *, packetLoss_upload: *}}
  7421. */
  7422. function convertToMUCStats(stats) {
  7423. return {
  7424. "bitrate_download": stats.bitrate.download,
  7425. "bitrate_upload": stats.bitrate.upload,
  7426. "packetLoss_total": stats.packetLoss.total,
  7427. "packetLoss_download": stats.packetLoss.download,
  7428. "packetLoss_upload": stats.packetLoss.upload
  7429. };
  7430. }
  7431. /**
  7432. * Converts statitistics to format used by VideoLayout
  7433. * @param stats
  7434. * @returns {{bitrate: {download: *, upload: *}, packetLoss: {total: *, download: *, upload: *}}}
  7435. */
  7436. function parseMUCStats(stats) {
  7437. return {
  7438. bitrate: {
  7439. download: stats.bitrate_download,
  7440. upload: stats.bitrate_upload
  7441. },
  7442. packetLoss: {
  7443. total: stats.packetLoss_total,
  7444. download: stats.packetLoss_download,
  7445. upload: stats.packetLoss_upload
  7446. }
  7447. };
  7448. }
  7449. var ConnectionQuality = {
  7450. init: function () {
  7451. APP.xmpp.addListener(XMPPEvents.REMOTE_STATS, this.updateRemoteStats);
  7452. APP.statistics.addConnectionStatsListener(this.updateLocalStats);
  7453. APP.statistics.addRemoteStatsStopListener(this.stopSendingStats);
  7454. },
  7455. /**
  7456. * Updates the local statistics
  7457. * @param data new statistics
  7458. */
  7459. updateLocalStats: function (data) {
  7460. stats = data;
  7461. eventEmitter.emit(CQEvents.LOCALSTATS_UPDATED, 100 - stats.packetLoss.total, stats);
  7462. if (sendIntervalId == null) {
  7463. startSendingStats();
  7464. }
  7465. },
  7466. /**
  7467. * Updates remote statistics
  7468. * @param jid the jid associated with the statistics
  7469. * @param data the statistics
  7470. */
  7471. updateRemoteStats: function (jid, data) {
  7472. if (data == null || data.packetLoss_total == null) {
  7473. eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED, jid, null, null);
  7474. return;
  7475. }
  7476. remoteStats[jid] = parseMUCStats(data);
  7477. eventEmitter.emit(CQEvents.REMOTESTATS_UPDATED,
  7478. jid, 100 - data.packetLoss_total, remoteStats[jid]);
  7479. },
  7480. /**
  7481. * Stops statistics sending.
  7482. */
  7483. stopSendingStats: function () {
  7484. clearInterval(sendIntervalId);
  7485. sendIntervalId = null;
  7486. //notify UI about stopping statistics gathering
  7487. eventEmitter.emit(CQEvents.STOP);
  7488. },
  7489. /**
  7490. * Returns the local statistics.
  7491. */
  7492. getStats: function () {
  7493. return stats;
  7494. },
  7495. addListener: function (type, listener) {
  7496. eventEmitter.on(type, listener);
  7497. }
  7498. };
  7499. module.exports = ConnectionQuality;
  7500. },{"../../service/connectionquality/CQEvents":83,"../../service/xmpp/XMPPEvents":86,"events":87}],36:[function(require,module,exports){
  7501. /* global $, alert, changeLocalVideo, chrome, config, getConferenceHandler, getUserMediaWithConstraints */
  7502. /**
  7503. * Indicates that desktop stream is currently in use(for toggle purpose).
  7504. * @type {boolean}
  7505. */
  7506. var isUsingScreenStream = false;
  7507. /**
  7508. * Indicates that switch stream operation is in progress and prevent from triggering new events.
  7509. * @type {boolean}
  7510. */
  7511. var switchInProgress = false;
  7512. /**
  7513. * Method used to get screen sharing stream.
  7514. *
  7515. * @type {function (stream_callback, failure_callback}
  7516. */
  7517. var obtainDesktopStream = null;
  7518. /**
  7519. * Flag used to cache desktop sharing enabled state. Do not use directly as it can be <tt>null</tt>.
  7520. * @type {null|boolean}
  7521. */
  7522. var _desktopSharingEnabled = null;
  7523. var EventEmitter = require("events");
  7524. var eventEmitter = new EventEmitter();
  7525. var DesktopSharingEventTypes = require("../../service/desktopsharing/DesktopSharingEventTypes");
  7526. /**
  7527. * Method obtains desktop stream from WebRTC 'screen' source.
  7528. * Flag 'chrome://flags/#enable-usermedia-screen-capture' must be enabled.
  7529. */
  7530. function obtainWebRTCScreen(streamCallback, failCallback) {
  7531. APP.RTC.getUserMediaWithConstraints(
  7532. ['screen'],
  7533. streamCallback,
  7534. failCallback
  7535. );
  7536. }
  7537. /**
  7538. * Constructs inline install URL for Chrome desktop streaming extension.
  7539. * The 'chromeExtensionId' must be defined in config.js.
  7540. * @returns {string}
  7541. */
  7542. function getWebStoreInstallUrl()
  7543. {
  7544. return "https://chrome.google.com/webstore/detail/" + config.chromeExtensionId;
  7545. }
  7546. /**
  7547. * Checks whether extension update is required.
  7548. * @param minVersion minimal required version
  7549. * @param extVersion current extension version
  7550. * @returns {boolean}
  7551. */
  7552. function isUpdateRequired(minVersion, extVersion)
  7553. {
  7554. try
  7555. {
  7556. var s1 = minVersion.split('.');
  7557. var s2 = extVersion.split('.');
  7558. var len = Math.max(s1.length, s2.length);
  7559. for (var i = 0; i < len; i++)
  7560. {
  7561. var n1 = 0,
  7562. n2 = 0;
  7563. if (i < s1.length)
  7564. n1 = parseInt(s1[i]);
  7565. if (i < s2.length)
  7566. n2 = parseInt(s2[i]);
  7567. if (isNaN(n1) || isNaN(n2))
  7568. {
  7569. return true;
  7570. }
  7571. else if (n1 !== n2)
  7572. {
  7573. return n1 > n2;
  7574. }
  7575. }
  7576. // will happen if boths version has identical numbers in
  7577. // their components (even if one of them is longer, has more components)
  7578. return false;
  7579. }
  7580. catch (e)
  7581. {
  7582. console.error("Failed to parse extension version", e);
  7583. APP.UI.messageHandler.showError('Error',
  7584. 'Error when trying to detect desktopsharing extension.');
  7585. return true;
  7586. }
  7587. }
  7588. function checkExtInstalled(isInstalledCallback) {
  7589. if (!chrome.runtime) {
  7590. // No API, so no extension for sure
  7591. isInstalledCallback(false);
  7592. return;
  7593. }
  7594. chrome.runtime.sendMessage(
  7595. config.chromeExtensionId,
  7596. { getVersion: true },
  7597. function (response) {
  7598. if (!response || !response.version) {
  7599. // Communication failure - assume that no endpoint exists
  7600. console.warn("Extension not installed?: " + chrome.runtime.lastError);
  7601. isInstalledCallback(false);
  7602. } else {
  7603. // Check installed extension version
  7604. var extVersion = response.version;
  7605. console.log('Extension version is: ' + extVersion);
  7606. var updateRequired = isUpdateRequired(config.minChromeExtVersion, extVersion);
  7607. if (updateRequired) {
  7608. alert(
  7609. 'Jitsi Desktop Streamer requires update. ' +
  7610. 'Changes will take effect after next Chrome restart.');
  7611. }
  7612. isInstalledCallback(!updateRequired);
  7613. }
  7614. }
  7615. );
  7616. }
  7617. function doGetStreamFromExtension(streamCallback, failCallback) {
  7618. // Sends 'getStream' msg to the extension. Extension id must be defined in the config.
  7619. chrome.runtime.sendMessage(
  7620. config.chromeExtensionId,
  7621. { getStream: true, sources: config.desktopSharingSources },
  7622. function (response) {
  7623. if (!response) {
  7624. failCallback(chrome.runtime.lastError);
  7625. return;
  7626. }
  7627. console.log("Response from extension: " + response);
  7628. if (response.streamId) {
  7629. APP.RTC.getUserMediaWithConstraints(
  7630. ['desktop'],
  7631. function (stream) {
  7632. streamCallback(stream);
  7633. },
  7634. failCallback,
  7635. null, null, null,
  7636. response.streamId);
  7637. } else {
  7638. failCallback("Extension failed to get the stream");
  7639. }
  7640. }
  7641. );
  7642. }
  7643. /**
  7644. * Asks Chrome extension to call chooseDesktopMedia and gets chrome 'desktop' stream for returned stream token.
  7645. */
  7646. function obtainScreenFromExtension(streamCallback, failCallback) {
  7647. checkExtInstalled(
  7648. function (isInstalled) {
  7649. if (isInstalled) {
  7650. doGetStreamFromExtension(streamCallback, failCallback);
  7651. } else {
  7652. chrome.webstore.install(
  7653. getWebStoreInstallUrl(),
  7654. function (arg) {
  7655. console.log("Extension installed successfully", arg);
  7656. // We need to reload the page in order to get the access to chrome.runtime
  7657. window.location.reload(false);
  7658. },
  7659. function (arg) {
  7660. console.log("Failed to install the extension", arg);
  7661. failCallback(arg);
  7662. APP.UI.messageHandler.showError('Error',
  7663. 'Failed to install desktop sharing extension');
  7664. }
  7665. );
  7666. }
  7667. }
  7668. );
  7669. }
  7670. /**
  7671. * Call this method to toggle desktop sharing feature.
  7672. * @param method pass "ext" to use chrome extension for desktop capture(chrome extension required),
  7673. * pass "webrtc" to use WebRTC "screen" desktop source('chrome://flags/#enable-usermedia-screen-capture'
  7674. * must be enabled), pass any other string or nothing in order to disable this feature completely.
  7675. */
  7676. function setDesktopSharing(method) {
  7677. // Check if we are running chrome
  7678. if (!navigator.webkitGetUserMedia) {
  7679. obtainDesktopStream = null;
  7680. console.info("Desktop sharing disabled");
  7681. } else if (method == "ext") {
  7682. obtainDesktopStream = obtainScreenFromExtension;
  7683. console.info("Using Chrome extension for desktop sharing");
  7684. } else if (method == "webrtc") {
  7685. obtainDesktopStream = obtainWebRTCScreen;
  7686. console.info("Using Chrome WebRTC for desktop sharing");
  7687. }
  7688. // Reset enabled cache
  7689. _desktopSharingEnabled = null;
  7690. }
  7691. /**
  7692. * Initializes <link rel=chrome-webstore-item /> with extension id set in config.js to support inline installs.
  7693. * Host site must be selected as main website of published extension.
  7694. */
  7695. function initInlineInstalls()
  7696. {
  7697. $("link[rel=chrome-webstore-item]").attr("href", getWebStoreInstallUrl());
  7698. }
  7699. function getSwitchStreamFailed(error) {
  7700. console.error("Failed to obtain the stream to switch to", error);
  7701. switchInProgress = false;
  7702. }
  7703. function streamSwitchDone() {
  7704. switchInProgress = false;
  7705. eventEmitter.emit(
  7706. DesktopSharingEventTypes.SWITCHING_DONE,
  7707. isUsingScreenStream);
  7708. }
  7709. function newStreamCreated(stream)
  7710. {
  7711. eventEmitter.emit(DesktopSharingEventTypes.NEW_STREAM_CREATED,
  7712. stream, isUsingScreenStream, streamSwitchDone);
  7713. }
  7714. module.exports = {
  7715. isUsingScreenStream: function () {
  7716. return isUsingScreenStream;
  7717. },
  7718. /**
  7719. * @returns {boolean} <tt>true</tt> if desktop sharing feature is available and enabled.
  7720. */
  7721. isDesktopSharingEnabled: function () {
  7722. if (_desktopSharingEnabled === null) {
  7723. if (obtainDesktopStream === obtainScreenFromExtension) {
  7724. // Parse chrome version
  7725. var userAgent = navigator.userAgent.toLowerCase();
  7726. // We can assume that user agent is chrome, because it's enforced when 'ext' streaming method is set
  7727. var ver = parseInt(userAgent.match(/chrome\/(\d+)\./)[1], 10);
  7728. console.log("Chrome version" + userAgent, ver);
  7729. _desktopSharingEnabled = ver >= 34;
  7730. } else {
  7731. _desktopSharingEnabled = obtainDesktopStream === obtainWebRTCScreen;
  7732. }
  7733. }
  7734. return _desktopSharingEnabled;
  7735. },
  7736. init: function () {
  7737. setDesktopSharing(config.desktopSharing);
  7738. // Initialize Chrome extension inline installs
  7739. if (config.chromeExtensionId) {
  7740. initInlineInstalls();
  7741. }
  7742. eventEmitter.emit(DesktopSharingEventTypes.INIT);
  7743. },
  7744. addListener: function(listener, type)
  7745. {
  7746. eventEmitter.on(type, listener);
  7747. },
  7748. removeListener: function (listener,type) {
  7749. eventEmitter.removeListener(type, listener);
  7750. },
  7751. /*
  7752. * Toggles screen sharing.
  7753. */
  7754. toggleScreenSharing: function () {
  7755. if (switchInProgress || !obtainDesktopStream) {
  7756. console.warn("Switch in progress or no method defined");
  7757. return;
  7758. }
  7759. switchInProgress = true;
  7760. if (!isUsingScreenStream)
  7761. {
  7762. // Switch to desktop stream
  7763. obtainDesktopStream(
  7764. function (stream) {
  7765. // We now use screen stream
  7766. isUsingScreenStream = true;
  7767. // Hook 'ended' event to restore camera when screen stream stops
  7768. stream.addEventListener('ended',
  7769. function (e) {
  7770. if (!switchInProgress && isUsingScreenStream) {
  7771. toggleScreenSharing();
  7772. }
  7773. }
  7774. );
  7775. newStreamCreated(stream);
  7776. },
  7777. getSwitchStreamFailed);
  7778. } else {
  7779. // Disable screen stream
  7780. APP.RTC.getUserMediaWithConstraints(
  7781. ['video'],
  7782. function (stream) {
  7783. // We are now using camera stream
  7784. isUsingScreenStream = false;
  7785. newStreamCreated(stream);
  7786. },
  7787. getSwitchStreamFailed, config.resolution || '360'
  7788. );
  7789. }
  7790. }
  7791. };
  7792. },{"../../service/desktopsharing/DesktopSharingEventTypes":84,"events":87}],37:[function(require,module,exports){
  7793. //maps keycode to character, id of popover for given function and function
  7794. var shortcuts = {
  7795. 67: {
  7796. character: "C",
  7797. id: "toggleChatPopover",
  7798. function: APP.UI.toggleChat
  7799. },
  7800. 70: {
  7801. character: "F",
  7802. id: "filmstripPopover",
  7803. function: APP.UI.toggleFilmStrip
  7804. },
  7805. 77: {
  7806. character: "M",
  7807. id: "mutePopover",
  7808. function: APP.UI.toggleAudio
  7809. },
  7810. 84: {
  7811. character: "T",
  7812. function: function() {
  7813. if(!APP.RTC.localAudio.isMuted()) {
  7814. APP.UI.toggleAudio();
  7815. }
  7816. }
  7817. },
  7818. 86: {
  7819. character: "V",
  7820. id: "toggleVideoPopover",
  7821. function: APP.UI.toggleVideo
  7822. }
  7823. };
  7824. var KeyboardShortcut = {
  7825. init: function () {
  7826. window.onkeyup = function(e) {
  7827. var keycode = e.which;
  7828. if(!($(":focus").is("input[type=text]") ||
  7829. $(":focus").is("input[type=password]") ||
  7830. $(":focus").is("textarea"))) {
  7831. if (typeof shortcuts[keycode] === "object") {
  7832. shortcuts[keycode].function();
  7833. }
  7834. else if (keycode >= "0".charCodeAt(0) &&
  7835. keycode <= "9".charCodeAt(0)) {
  7836. APP.UI.clickOnVideo(keycode - "0".charCodeAt(0) + 1);
  7837. }
  7838. //esc while the smileys are visible hides them
  7839. } else if (keycode === 27 && $('#smileysContainer').is(':visible')) {
  7840. APP.UI.toggleSmileys();
  7841. }
  7842. };
  7843. window.onkeydown = function(e) {
  7844. if(!($(":focus").is("input[type=text]") ||
  7845. $(":focus").is("input[type=password]") ||
  7846. $(":focus").is("textarea"))) {
  7847. if(e.which === "T".charCodeAt(0)) {
  7848. if(APP.RTC.localAudio.isMuted()) {
  7849. APP.UI.toggleAudio();
  7850. }
  7851. }
  7852. }
  7853. };
  7854. var self = this;
  7855. $('body').popover({ selector: '[data-toggle=popover]',
  7856. trigger: 'click hover',
  7857. content: function() {
  7858. return this.getAttribute("content") +
  7859. self.getShortcut(this.getAttribute("shortcut"));
  7860. }
  7861. });
  7862. },
  7863. /**
  7864. *
  7865. * @param id indicates the popover associated with the shortcut
  7866. * @returns {string} the keyboard shortcut used for the id given
  7867. */
  7868. getShortcut: function (id) {
  7869. for (var keycode in shortcuts) {
  7870. if (shortcuts.hasOwnProperty(keycode)) {
  7871. if (shortcuts[keycode].id === id) {
  7872. return " (" + shortcuts[keycode].character + ")";
  7873. }
  7874. }
  7875. }
  7876. return "";
  7877. }
  7878. };
  7879. module.exports = KeyboardShortcut;
  7880. },{}],38:[function(require,module,exports){
  7881. /**
  7882. *
  7883. * @constructor
  7884. */
  7885. function SimulcastLogger(name, lvl) {
  7886. this.name = name;
  7887. this.lvl = lvl;
  7888. }
  7889. SimulcastLogger.prototype.log = function (text) {
  7890. if (this.lvl) {
  7891. console.log(text);
  7892. }
  7893. };
  7894. SimulcastLogger.prototype.info = function (text) {
  7895. if (this.lvl > 1) {
  7896. console.info(text);
  7897. }
  7898. };
  7899. SimulcastLogger.prototype.fine = function (text) {
  7900. if (this.lvl > 2) {
  7901. console.log(text);
  7902. }
  7903. };
  7904. SimulcastLogger.prototype.error = function (text) {
  7905. console.error(text);
  7906. };
  7907. module.exports = SimulcastLogger;
  7908. },{}],39:[function(require,module,exports){
  7909. var SimulcastLogger = require("./SimulcastLogger");
  7910. var SimulcastUtils = require("./SimulcastUtils");
  7911. var MediaStreamType = require("../../service/RTC/MediaStreamTypes");
  7912. function SimulcastReceiver() {
  7913. this.simulcastUtils = new SimulcastUtils();
  7914. this.logger = new SimulcastLogger('SimulcastReceiver', 1);
  7915. }
  7916. SimulcastReceiver.prototype._remoteVideoSourceCache = '';
  7917. SimulcastReceiver.prototype._remoteMaps = {
  7918. msid2Quality: {},
  7919. ssrc2Msid: {},
  7920. msid2ssrc: {},
  7921. receivingVideoStreams: {}
  7922. };
  7923. SimulcastReceiver.prototype._cacheRemoteVideoSources = function (lines) {
  7924. this._remoteVideoSourceCache = this.simulcastUtils._getVideoSources(lines);
  7925. };
  7926. SimulcastReceiver.prototype._restoreRemoteVideoSources = function (lines) {
  7927. this.simulcastUtils._replaceVideoSources(lines, this._remoteVideoSourceCache);
  7928. };
  7929. SimulcastReceiver.prototype._ensureGoogConference = function (lines) {
  7930. var sb;
  7931. this.logger.info('Ensuring x-google-conference flag...')
  7932. if (this.simulcastUtils._indexOfArray('a=x-google-flag:conference', lines) === this.simulcastUtils._emptyCompoundIndex) {
  7933. // TODO(gp) do that for the audio as well as suggested by fippo.
  7934. // Add the google conference flag
  7935. sb = this.simulcastUtils._getVideoSources(lines);
  7936. sb = ['a=x-google-flag:conference'].concat(sb);
  7937. this.simulcastUtils._replaceVideoSources(lines, sb);
  7938. }
  7939. };
  7940. SimulcastReceiver.prototype._restoreSimulcastGroups = function (sb) {
  7941. this._restoreRemoteVideoSources(sb);
  7942. };
  7943. /**
  7944. * Restores the simulcast groups of the remote description. In
  7945. * transformRemoteDescription we remove those in order for the set remote
  7946. * description to succeed. The focus needs the signal the groups to new
  7947. * participants.
  7948. *
  7949. * @param desc
  7950. * @returns {*}
  7951. */
  7952. SimulcastReceiver.prototype.reverseTransformRemoteDescription = function (desc) {
  7953. var sb;
  7954. if (!this.simulcastUtils.isValidDescription(desc)) {
  7955. return desc;
  7956. }
  7957. if (config.enableSimulcast) {
  7958. sb = desc.sdp.split('\r\n');
  7959. this._restoreSimulcastGroups(sb);
  7960. desc = new RTCSessionDescription({
  7961. type: desc.type,
  7962. sdp: sb.join('\r\n')
  7963. });
  7964. }
  7965. return desc;
  7966. };
  7967. SimulcastUtils.prototype._ensureOrder = function (lines) {
  7968. var videoSources, sb;
  7969. videoSources = this.parseMedia(lines, ['video'])[0];
  7970. sb = this._compileVideoSources(videoSources);
  7971. this._replaceVideoSources(lines, sb);
  7972. };
  7973. SimulcastReceiver.prototype._updateRemoteMaps = function (lines) {
  7974. var remoteVideoSources = this.simulcastUtils.parseMedia(lines, ['video'])[0],
  7975. videoSource, quality;
  7976. // (re) initialize the remote maps.
  7977. this._remoteMaps.msid2Quality = {};
  7978. this._remoteMaps.ssrc2Msid = {};
  7979. this._remoteMaps.msid2ssrc = {};
  7980. var self = this;
  7981. if (remoteVideoSources.groups && remoteVideoSources.groups.length !== 0) {
  7982. remoteVideoSources.groups.forEach(function (group) {
  7983. if (group.semantics === 'SIM' && group.ssrcs && group.ssrcs.length !== 0) {
  7984. quality = 0;
  7985. group.ssrcs.forEach(function (ssrc) {
  7986. videoSource = remoteVideoSources.sources[ssrc];
  7987. self._remoteMaps.msid2Quality[videoSource.msid] = quality++;
  7988. self._remoteMaps.ssrc2Msid[videoSource.ssrc] = videoSource.msid;
  7989. self._remoteMaps.msid2ssrc[videoSource.msid] = videoSource.ssrc;
  7990. });
  7991. }
  7992. });
  7993. }
  7994. };
  7995. SimulcastReceiver.prototype._setReceivingVideoStream = function (resource, ssrc) {
  7996. this._remoteMaps.receivingVideoStreams[resource] = ssrc;
  7997. };
  7998. /**
  7999. * Returns a stream with single video track, the one currently being
  8000. * received by this endpoint.
  8001. *
  8002. * @param stream the remote simulcast stream.
  8003. * @returns {webkitMediaStream}
  8004. */
  8005. SimulcastReceiver.prototype.getReceivingVideoStream = function (stream) {
  8006. var tracks, i, electedTrack, msid, quality = 0, receivingTrackId;
  8007. var self = this;
  8008. if (config.enableSimulcast) {
  8009. stream.getVideoTracks().some(function (track) {
  8010. return Object.keys(self._remoteMaps.receivingVideoStreams).some(function (resource) {
  8011. var ssrc = self._remoteMaps.receivingVideoStreams[resource];
  8012. var msid = self._remoteMaps.ssrc2Msid[ssrc];
  8013. if (msid == [stream.id, track.id].join(' ')) {
  8014. electedTrack = track;
  8015. return true;
  8016. }
  8017. });
  8018. });
  8019. if (!electedTrack) {
  8020. // we don't have an elected track, choose by initial quality.
  8021. tracks = stream.getVideoTracks();
  8022. for (i = 0; i < tracks.length; i++) {
  8023. msid = [stream.id, tracks[i].id].join(' ');
  8024. if (this._remoteMaps.msid2Quality[msid] === quality) {
  8025. electedTrack = tracks[i];
  8026. break;
  8027. }
  8028. }
  8029. // TODO(gp) if the initialQuality could not be satisfied, lower
  8030. // the requirement and try again.
  8031. }
  8032. }
  8033. return (electedTrack)
  8034. ? new webkitMediaStream([electedTrack])
  8035. : stream;
  8036. };
  8037. SimulcastReceiver.prototype.getReceivingSSRC = function (jid) {
  8038. var resource = Strophe.getResourceFromJid(jid);
  8039. var ssrc = this._remoteMaps.receivingVideoStreams[resource];
  8040. // If we haven't receiving a "changed" event yet, then we must be receiving
  8041. // low quality (that the sender always streams).
  8042. if(!ssrc)
  8043. {
  8044. var remoteStreamObject = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
  8045. var remoteStream = remoteStreamObject.getOriginalStream();
  8046. var tracks = remoteStream.getVideoTracks();
  8047. if (tracks) {
  8048. for (var k = 0; k < tracks.length; k++) {
  8049. var track = tracks[k];
  8050. var msid = [remoteStream.id, track.id].join(' ');
  8051. var _ssrc = this._remoteMaps.msid2ssrc[msid];
  8052. var quality = this._remoteMaps.msid2Quality[msid];
  8053. if (quality == 0) {
  8054. ssrc = _ssrc;
  8055. }
  8056. }
  8057. }
  8058. }
  8059. return ssrc;
  8060. };
  8061. SimulcastReceiver.prototype.getReceivingVideoStreamBySSRC = function (ssrc)
  8062. {
  8063. var sid, electedStream;
  8064. var i, j, k;
  8065. var jid = APP.xmpp.getJidFromSSRC(ssrc);
  8066. if(jid && APP.RTC.remoteStreams[jid])
  8067. {
  8068. var remoteStreamObject = APP.RTC.remoteStreams[jid][MediaStreamType.VIDEO_TYPE];
  8069. var remoteStream = remoteStreamObject.getOriginalStream();
  8070. var tracks = remoteStream.getVideoTracks();
  8071. if (tracks) {
  8072. for (k = 0; k < tracks.length; k++) {
  8073. var track = tracks[k];
  8074. var msid = [remoteStream.id, track.id].join(' ');
  8075. var tmp = this._remoteMaps.msid2ssrc[msid];
  8076. if (tmp == ssrc) {
  8077. electedStream = new webkitMediaStream([track]);
  8078. sid = remoteStreamObject.sid;
  8079. // stream found, stop.
  8080. break;
  8081. }
  8082. }
  8083. }
  8084. }
  8085. else
  8086. {
  8087. console.debug(APP.RTC.remoteStreams, jid, ssrc);
  8088. }
  8089. return {
  8090. sid: sid,
  8091. stream: electedStream
  8092. };
  8093. };
  8094. /**
  8095. * Gets the fully qualified msid (stream.id + track.id) associated to the
  8096. * SSRC.
  8097. *
  8098. * @param ssrc
  8099. * @returns {*}
  8100. */
  8101. SimulcastReceiver.prototype.getRemoteVideoStreamIdBySSRC = function (ssrc) {
  8102. return this._remoteMaps.ssrc2Msid[ssrc];
  8103. };
  8104. /**
  8105. * Removes the ssrc-group:SIM from the remote description bacause Chrome
  8106. * either gets confused and thinks this is an FID group or, if an FID group
  8107. * is already present, it fails to set the remote description.
  8108. *
  8109. * @param desc
  8110. * @returns {*}
  8111. */
  8112. SimulcastReceiver.prototype.transformRemoteDescription = function (desc) {
  8113. if (desc && desc.sdp) {
  8114. var sb = desc.sdp.split('\r\n');
  8115. this._updateRemoteMaps(sb);
  8116. this._cacheRemoteVideoSources(sb);
  8117. // NOTE(gp) this needs to be called after updateRemoteMaps because we
  8118. // need the simulcast group in the _updateRemoteMaps() method.
  8119. this.simulcastUtils._removeSimulcastGroup(sb);
  8120. if (desc.sdp.indexOf('a=ssrc-group:SIM') !== -1) {
  8121. // We don't need the goog conference flag if we're not doing
  8122. // simulcast.
  8123. this._ensureGoogConference(sb);
  8124. }
  8125. desc = new RTCSessionDescription({
  8126. type: desc.type,
  8127. sdp: sb.join('\r\n')
  8128. });
  8129. this.logger.fine(['Transformed remote description', desc.sdp].join(' '));
  8130. }
  8131. return desc;
  8132. };
  8133. module.exports = SimulcastReceiver;
  8134. },{"../../service/RTC/MediaStreamTypes":78,"./SimulcastLogger":38,"./SimulcastUtils":41}],40:[function(require,module,exports){
  8135. var SimulcastLogger = require("./SimulcastLogger");
  8136. var SimulcastUtils = require("./SimulcastUtils");
  8137. function SimulcastSender() {
  8138. this.simulcastUtils = new SimulcastUtils();
  8139. this.logger = new SimulcastLogger('SimulcastSender', 1);
  8140. }
  8141. SimulcastSender.prototype.displayedLocalVideoStream = null;
  8142. SimulcastSender.prototype._generateGuid = (function () {
  8143. function s4() {
  8144. return Math.floor((1 + Math.random()) * 0x10000)
  8145. .toString(16)
  8146. .substring(1);
  8147. }
  8148. return function () {
  8149. return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
  8150. s4() + '-' + s4() + s4() + s4();
  8151. };
  8152. }());
  8153. // Returns a random integer between min (included) and max (excluded)
  8154. // Using Math.round() gives a non-uniform distribution!
  8155. SimulcastSender.prototype._generateRandomSSRC = function () {
  8156. var min = 0, max = 0xffffffff;
  8157. return Math.floor(Math.random() * (max - min)) + min;
  8158. };
  8159. SimulcastSender.prototype.getLocalVideoStream = function () {
  8160. return (this.displayedLocalVideoStream != null)
  8161. ? this.displayedLocalVideoStream
  8162. // in case we have no simulcast at all, i.e. we didn't perform the GUM
  8163. : APP.RTC.localVideo.getOriginalStream();
  8164. };
  8165. function NativeSimulcastSender() {
  8166. SimulcastSender.call(this); // call the super constructor.
  8167. }
  8168. NativeSimulcastSender.prototype = Object.create(SimulcastSender.prototype);
  8169. NativeSimulcastSender.prototype._localExplosionMap = {};
  8170. NativeSimulcastSender.prototype._isUsingScreenStream = false;
  8171. NativeSimulcastSender.prototype._localVideoSourceCache = '';
  8172. NativeSimulcastSender.prototype.reset = function () {
  8173. this._localExplosionMap = {};
  8174. this._isUsingScreenStream = APP.desktopsharing.isUsingScreenStream();
  8175. };
  8176. NativeSimulcastSender.prototype._cacheLocalVideoSources = function (lines) {
  8177. this._localVideoSourceCache = this.simulcastUtils._getVideoSources(lines);
  8178. };
  8179. NativeSimulcastSender.prototype._restoreLocalVideoSources = function (lines) {
  8180. this.simulcastUtils._replaceVideoSources(lines, this._localVideoSourceCache);
  8181. };
  8182. NativeSimulcastSender.prototype._appendSimulcastGroup = function (lines) {
  8183. var videoSources, ssrcGroup, simSSRC, numOfSubs = 2, i, sb, msid;
  8184. this.logger.info('Appending simulcast group...');
  8185. // Get the primary SSRC information.
  8186. videoSources = this.simulcastUtils.parseMedia(lines, ['video'])[0];
  8187. // Start building the SIM SSRC group.
  8188. ssrcGroup = ['a=ssrc-group:SIM'];
  8189. // The video source buffer.
  8190. sb = [];
  8191. // Create the simulcast sub-streams.
  8192. for (i = 0; i < numOfSubs; i++) {
  8193. // TODO(gp) prevent SSRC collision.
  8194. simSSRC = this._generateRandomSSRC();
  8195. ssrcGroup.push(simSSRC);
  8196. if (videoSources.base) {
  8197. sb.splice.apply(sb, [sb.length, 0].concat(
  8198. [["a=ssrc:", simSSRC, " cname:", videoSources.base.cname].join(''),
  8199. ["a=ssrc:", simSSRC, " msid:", videoSources.base.msid].join('')]
  8200. ));
  8201. }
  8202. this.logger.info(['Generated substream ', i, ' with SSRC ', simSSRC, '.'].join(''));
  8203. }
  8204. // Add the group sim layers.
  8205. sb.splice(0, 0, ssrcGroup.join(' '))
  8206. this.simulcastUtils._replaceVideoSources(lines, sb);
  8207. };
  8208. // Does the actual patching.
  8209. NativeSimulcastSender.prototype._ensureSimulcastGroup = function (lines) {
  8210. this.logger.info('Ensuring simulcast group...');
  8211. if (this.simulcastUtils._indexOfArray('a=ssrc-group:SIM', lines) === this.simulcastUtils._emptyCompoundIndex) {
  8212. this._appendSimulcastGroup(lines);
  8213. this._cacheLocalVideoSources(lines);
  8214. } else {
  8215. // verify that the ssrcs participating in the SIM group are present
  8216. // in the SDP (needed for presence).
  8217. this._restoreLocalVideoSources(lines);
  8218. }
  8219. };
  8220. /**
  8221. * Produces a single stream with multiple tracks for local video sources.
  8222. *
  8223. * @param lines
  8224. * @private
  8225. */
  8226. NativeSimulcastSender.prototype._explodeSimulcastSenderSources = function (lines) {
  8227. var sb, msid, sid, tid, videoSources, self;
  8228. this.logger.info('Exploding local video sources...');
  8229. videoSources = this.simulcastUtils.parseMedia(lines, ['video'])[0];
  8230. self = this;
  8231. if (videoSources.groups && videoSources.groups.length !== 0) {
  8232. videoSources.groups.forEach(function (group) {
  8233. if (group.semantics === 'SIM') {
  8234. group.ssrcs.forEach(function (ssrc) {
  8235. // Get the msid for this ssrc..
  8236. if (self._localExplosionMap[ssrc]) {
  8237. // .. either from the explosion map..
  8238. msid = self._localExplosionMap[ssrc];
  8239. } else {
  8240. // .. or generate a new one (msid).
  8241. sid = videoSources.sources[ssrc].msid
  8242. .substring(0, videoSources.sources[ssrc].msid.indexOf(' '));
  8243. tid = self._generateGuid();
  8244. msid = [sid, tid].join(' ');
  8245. self._localExplosionMap[ssrc] = msid;
  8246. }
  8247. // Assign it to the source object.
  8248. videoSources.sources[ssrc].msid = msid;
  8249. // TODO(gp) Change the msid of associated sources.
  8250. });
  8251. }
  8252. });
  8253. }
  8254. sb = this.simulcastUtils._compileVideoSources(videoSources);
  8255. this.simulcastUtils._replaceVideoSources(lines, sb);
  8256. };
  8257. /**
  8258. * GUM for simulcast.
  8259. *
  8260. * @param constraints
  8261. * @param success
  8262. * @param err
  8263. */
  8264. NativeSimulcastSender.prototype.getUserMedia = function (constraints, success, err) {
  8265. // There's nothing special to do for native simulcast, so just do a normal GUM.
  8266. navigator.webkitGetUserMedia(constraints, function (hqStream) {
  8267. success(hqStream);
  8268. }, err);
  8269. };
  8270. /**
  8271. * Prepares the local description for public usage (i.e. to be signaled
  8272. * through Jingle to the focus).
  8273. *
  8274. * @param desc
  8275. * @returns {RTCSessionDescription}
  8276. */
  8277. NativeSimulcastSender.prototype.reverseTransformLocalDescription = function (desc) {
  8278. var sb;
  8279. if (!this.simulcastUtils.isValidDescription(desc) || this._isUsingScreenStream) {
  8280. return desc;
  8281. }
  8282. sb = desc.sdp.split('\r\n');
  8283. this._explodeSimulcastSenderSources(sb);
  8284. desc = new RTCSessionDescription({
  8285. type: desc.type,
  8286. sdp: sb.join('\r\n')
  8287. });
  8288. this.logger.fine(['Exploded local video sources', desc.sdp].join(' '));
  8289. return desc;
  8290. };
  8291. /**
  8292. * Ensures that the simulcast group is present in the answer, _if_ native
  8293. * simulcast is enabled,
  8294. *
  8295. * @param desc
  8296. * @returns {*}
  8297. */
  8298. NativeSimulcastSender.prototype.transformAnswer = function (desc) {
  8299. if (!this.simulcastUtils.isValidDescription(desc) || this._isUsingScreenStream) {
  8300. return desc;
  8301. }
  8302. var sb = desc.sdp.split('\r\n');
  8303. // Even if we have enabled native simulcasting previously
  8304. // (with a call to SLD with an appropriate SDP, for example),
  8305. // createAnswer seems to consistently generate incomplete SDP
  8306. // with missing SSRCS.
  8307. //
  8308. // So, subsequent calls to SLD will have missing SSRCS and presence
  8309. // won't have the complete list of SRCs.
  8310. this._ensureSimulcastGroup(sb);
  8311. desc = new RTCSessionDescription({
  8312. type: desc.type,
  8313. sdp: sb.join('\r\n')
  8314. });
  8315. this.logger.fine(['Transformed answer', desc.sdp].join(' '));
  8316. return desc;
  8317. };
  8318. /**
  8319. *
  8320. *
  8321. * @param desc
  8322. * @returns {*}
  8323. */
  8324. NativeSimulcastSender.prototype.transformLocalDescription = function (desc) {
  8325. return desc;
  8326. };
  8327. NativeSimulcastSender.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
  8328. // Nothing to do here, native simulcast does that auto-magically.
  8329. };
  8330. NativeSimulcastSender.prototype.constructor = NativeSimulcastSender;
  8331. function SimpleSimulcastSender() {
  8332. SimulcastSender.call(this);
  8333. }
  8334. SimpleSimulcastSender.prototype = Object.create(SimulcastSender.prototype);
  8335. SimpleSimulcastSender.prototype.localStream = null;
  8336. SimpleSimulcastSender.prototype._localMaps = {
  8337. msids: [],
  8338. msid2ssrc: {}
  8339. };
  8340. /**
  8341. * Groups local video sources together in the ssrc-group:SIM group.
  8342. *
  8343. * @param lines
  8344. * @private
  8345. */
  8346. SimpleSimulcastSender.prototype._groupLocalVideoSources = function (lines) {
  8347. var sb, videoSources, ssrcs = [], ssrc;
  8348. this.logger.info('Grouping local video sources...');
  8349. videoSources = this.simulcastUtils.parseMedia(lines, ['video'])[0];
  8350. for (ssrc in videoSources.sources) {
  8351. // jitsi-meet destroys/creates streams at various places causing
  8352. // the original local stream ids to change. The only thing that
  8353. // remains unchanged is the trackid.
  8354. this._localMaps.msid2ssrc[videoSources.sources[ssrc].msid.split(' ')[1]] = ssrc;
  8355. }
  8356. var self = this;
  8357. // TODO(gp) add only "free" sources.
  8358. this._localMaps.msids.forEach(function (msid) {
  8359. ssrcs.push(self._localMaps.msid2ssrc[msid]);
  8360. });
  8361. if (!videoSources.groups) {
  8362. videoSources.groups = [];
  8363. }
  8364. videoSources.groups.push({
  8365. 'semantics': 'SIM',
  8366. 'ssrcs': ssrcs
  8367. });
  8368. sb = this.simulcastUtils._compileVideoSources(videoSources);
  8369. this.simulcastUtils._replaceVideoSources(lines, sb);
  8370. };
  8371. /**
  8372. * GUM for simulcast.
  8373. *
  8374. * @param constraints
  8375. * @param success
  8376. * @param err
  8377. */
  8378. SimpleSimulcastSender.prototype.getUserMedia = function (constraints, success, err) {
  8379. // TODO(gp) what if we request a resolution not supported by the hardware?
  8380. // TODO(gp) make the lq stream configurable; although this wouldn't work with native simulcast
  8381. var lqConstraints = {
  8382. audio: false,
  8383. video: {
  8384. mandatory: {
  8385. maxWidth: 320,
  8386. maxHeight: 180,
  8387. maxFrameRate: 15
  8388. }
  8389. }
  8390. };
  8391. this.logger.info('HQ constraints: ', constraints);
  8392. this.logger.info('LQ constraints: ', lqConstraints);
  8393. // NOTE(gp) if we request the lq stream first webkitGetUserMedia
  8394. // fails randomly. Tested with Chrome 37. As fippo suggested, the
  8395. // reason appears to be that Chrome only acquires the cam once and
  8396. // then downscales the picture (https://code.google.com/p/chromium/issues/detail?id=346616#c11)
  8397. var self = this;
  8398. navigator.webkitGetUserMedia(constraints, function (hqStream) {
  8399. self.localStream = hqStream;
  8400. // reset local maps.
  8401. self._localMaps.msids = [];
  8402. self._localMaps.msid2ssrc = {};
  8403. // add hq trackid to local map
  8404. self._localMaps.msids.push(hqStream.getVideoTracks()[0].id);
  8405. navigator.webkitGetUserMedia(lqConstraints, function (lqStream) {
  8406. self.displayedLocalVideoStream = lqStream;
  8407. // NOTE(gp) The specification says Array.forEach() will visit
  8408. // the array elements in numeric order, and that it doesn't
  8409. // visit elements that don't exist.
  8410. // add lq trackid to local map
  8411. self._localMaps.msids.splice(0, 0, lqStream.getVideoTracks()[0].id);
  8412. self.localStream.addTrack(lqStream.getVideoTracks()[0]);
  8413. success(self.localStream);
  8414. }, err);
  8415. }, err);
  8416. };
  8417. /**
  8418. * Prepares the local description for public usage (i.e. to be signaled
  8419. * through Jingle to the focus).
  8420. *
  8421. * @param desc
  8422. * @returns {RTCSessionDescription}
  8423. */
  8424. SimpleSimulcastSender.prototype.reverseTransformLocalDescription = function (desc) {
  8425. var sb;
  8426. if (!this.simulcastUtils.isValidDescription(desc)) {
  8427. return desc;
  8428. }
  8429. sb = desc.sdp.split('\r\n');
  8430. this._groupLocalVideoSources(sb);
  8431. desc = new RTCSessionDescription({
  8432. type: desc.type,
  8433. sdp: sb.join('\r\n')
  8434. });
  8435. this.logger.fine('Grouped local video sources');
  8436. this.logger.fine(desc.sdp);
  8437. return desc;
  8438. };
  8439. /**
  8440. * Ensures that the simulcast group is present in the answer, _if_ native
  8441. * simulcast is enabled,
  8442. *
  8443. * @param desc
  8444. * @returns {*}
  8445. */
  8446. SimpleSimulcastSender.prototype.transformAnswer = function (desc) {
  8447. return desc;
  8448. };
  8449. /**
  8450. *
  8451. *
  8452. * @param desc
  8453. * @returns {*}
  8454. */
  8455. SimpleSimulcastSender.prototype.transformLocalDescription = function (desc) {
  8456. var sb = desc.sdp.split('\r\n');
  8457. this.simulcastUtils._removeSimulcastGroup(sb);
  8458. desc = new RTCSessionDescription({
  8459. type: desc.type,
  8460. sdp: sb.join('\r\n')
  8461. });
  8462. this.logger.fine('Transformed local description');
  8463. this.logger.fine(desc.sdp);
  8464. return desc;
  8465. };
  8466. SimpleSimulcastSender.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
  8467. var trackid;
  8468. var self = this;
  8469. this.logger.log(['Requested to', enabled ? 'enable' : 'disable', ssrc].join(' '));
  8470. if (Object.keys(this._localMaps.msid2ssrc).some(function (tid) {
  8471. // Search for the track id that corresponds to the ssrc
  8472. if (self._localMaps.msid2ssrc[tid] == ssrc) {
  8473. trackid = tid;
  8474. return true;
  8475. }
  8476. }) && self.localStream.getVideoTracks().some(function (track) {
  8477. // Start/stop the track that corresponds to the track id
  8478. if (track.id === trackid) {
  8479. track.enabled = enabled;
  8480. return true;
  8481. }
  8482. })) {
  8483. this.logger.log([trackid, enabled ? 'enabled' : 'disabled'].join(' '));
  8484. $(document).trigger(enabled
  8485. ? 'simulcastlayerstarted'
  8486. : 'simulcastlayerstopped');
  8487. } else {
  8488. this.logger.error("I don't have a local stream with SSRC " + ssrc);
  8489. }
  8490. };
  8491. SimpleSimulcastSender.prototype.constructor = SimpleSimulcastSender;
  8492. function NoSimulcastSender() {
  8493. SimulcastSender.call(this);
  8494. }
  8495. NoSimulcastSender.prototype = Object.create(SimulcastSender.prototype);
  8496. /**
  8497. * GUM for simulcast.
  8498. *
  8499. * @param constraints
  8500. * @param success
  8501. * @param err
  8502. */
  8503. NoSimulcastSender.prototype.getUserMedia = function (constraints, success, err) {
  8504. navigator.webkitGetUserMedia(constraints, function (hqStream) {
  8505. success(hqStream);
  8506. }, err);
  8507. };
  8508. /**
  8509. * Prepares the local description for public usage (i.e. to be signaled
  8510. * through Jingle to the focus).
  8511. *
  8512. * @param desc
  8513. * @returns {RTCSessionDescription}
  8514. */
  8515. NoSimulcastSender.prototype.reverseTransformLocalDescription = function (desc) {
  8516. return desc;
  8517. };
  8518. /**
  8519. * Ensures that the simulcast group is present in the answer, _if_ native
  8520. * simulcast is enabled,
  8521. *
  8522. * @param desc
  8523. * @returns {*}
  8524. */
  8525. NoSimulcastSender.prototype.transformAnswer = function (desc) {
  8526. return desc;
  8527. };
  8528. /**
  8529. *
  8530. *
  8531. * @param desc
  8532. * @returns {*}
  8533. */
  8534. NoSimulcastSender.prototype.transformLocalDescription = function (desc) {
  8535. return desc;
  8536. };
  8537. NoSimulcastSender.prototype._setLocalVideoStreamEnabled = function (ssrc, enabled) {
  8538. };
  8539. NoSimulcastSender.prototype.constructor = NoSimulcastSender;
  8540. module.exports = {
  8541. "native": NativeSimulcastSender,
  8542. "no": NoSimulcastSender
  8543. }
  8544. },{"./SimulcastLogger":38,"./SimulcastUtils":41}],41:[function(require,module,exports){
  8545. var SimulcastLogger = require("./SimulcastLogger");
  8546. /**
  8547. *
  8548. * @constructor
  8549. */
  8550. function SimulcastUtils() {
  8551. this.logger = new SimulcastLogger("SimulcastUtils", 1);
  8552. }
  8553. /**
  8554. *
  8555. * @type {{}}
  8556. * @private
  8557. */
  8558. SimulcastUtils.prototype._emptyCompoundIndex = {};
  8559. /**
  8560. *
  8561. * @param lines
  8562. * @param videoSources
  8563. * @private
  8564. */
  8565. SimulcastUtils.prototype._replaceVideoSources = function (lines, videoSources) {
  8566. var i, inVideo = false, index = -1, howMany = 0;
  8567. this.logger.info('Replacing video sources...');
  8568. for (i = 0; i < lines.length; i++) {
  8569. if (inVideo && lines[i].substring(0, 'm='.length) === 'm=') {
  8570. // Out of video.
  8571. break;
  8572. }
  8573. if (!inVideo && lines[i].substring(0, 'm=video '.length) === 'm=video ') {
  8574. // In video.
  8575. inVideo = true;
  8576. }
  8577. if (inVideo && (lines[i].substring(0, 'a=ssrc:'.length) === 'a=ssrc:'
  8578. || lines[i].substring(0, 'a=ssrc-group:'.length) === 'a=ssrc-group:')) {
  8579. if (index === -1) {
  8580. index = i;
  8581. }
  8582. howMany++;
  8583. }
  8584. }
  8585. // efficiency baby ;)
  8586. lines.splice.apply(lines,
  8587. [index, howMany].concat(videoSources));
  8588. };
  8589. SimulcastUtils.prototype.isValidDescription = function (desc)
  8590. {
  8591. return desc && desc != null
  8592. && desc.type && desc.type != ''
  8593. && desc.sdp && desc.sdp != '';
  8594. };
  8595. SimulcastUtils.prototype._getVideoSources = function (lines) {
  8596. var i, inVideo = false, sb = [];
  8597. this.logger.info('Getting video sources...');
  8598. for (i = 0; i < lines.length; i++) {
  8599. if (inVideo && lines[i].substring(0, 'm='.length) === 'm=') {
  8600. // Out of video.
  8601. break;
  8602. }
  8603. if (!inVideo && lines[i].substring(0, 'm=video '.length) === 'm=video ') {
  8604. // In video.
  8605. inVideo = true;
  8606. }
  8607. if (inVideo && lines[i].substring(0, 'a=ssrc:'.length) === 'a=ssrc:') {
  8608. // In SSRC.
  8609. sb.push(lines[i]);
  8610. }
  8611. if (inVideo && lines[i].substring(0, 'a=ssrc-group:'.length) === 'a=ssrc-group:') {
  8612. sb.push(lines[i]);
  8613. }
  8614. }
  8615. return sb;
  8616. };
  8617. SimulcastUtils.prototype.parseMedia = function (lines, mediatypes) {
  8618. var i, res = [], type, cur_media, idx, ssrcs, cur_ssrc, ssrc,
  8619. ssrc_attribute, group, semantics, skip = true;
  8620. this.logger.info('Parsing media sources...');
  8621. for (i = 0; i < lines.length; i++) {
  8622. if (lines[i].substring(0, 'm='.length) === 'm=') {
  8623. type = lines[i]
  8624. .substr('m='.length, lines[i].indexOf(' ') - 'm='.length);
  8625. skip = mediatypes !== undefined && mediatypes.indexOf(type) === -1;
  8626. if (!skip) {
  8627. cur_media = {
  8628. 'type': type,
  8629. 'sources': {},
  8630. 'groups': []
  8631. };
  8632. res.push(cur_media);
  8633. }
  8634. } else if (!skip && lines[i].substring(0, 'a=ssrc:'.length) === 'a=ssrc:') {
  8635. idx = lines[i].indexOf(' ');
  8636. ssrc = lines[i].substring('a=ssrc:'.length, idx);
  8637. if (cur_media.sources[ssrc] === undefined) {
  8638. cur_ssrc = {'ssrc': ssrc};
  8639. cur_media.sources[ssrc] = cur_ssrc;
  8640. }
  8641. ssrc_attribute = lines[i].substr(idx + 1).split(':', 2)[0];
  8642. cur_ssrc[ssrc_attribute] = lines[i].substr(idx + 1).split(':', 2)[1];
  8643. if (cur_media.base === undefined) {
  8644. cur_media.base = cur_ssrc;
  8645. }
  8646. } else if (!skip && lines[i].substring(0, 'a=ssrc-group:'.length) === 'a=ssrc-group:') {
  8647. idx = lines[i].indexOf(' ');
  8648. semantics = lines[i].substr(0, idx).substr('a=ssrc-group:'.length);
  8649. ssrcs = lines[i].substr(idx).trim().split(' ');
  8650. group = {
  8651. 'semantics': semantics,
  8652. 'ssrcs': ssrcs
  8653. };
  8654. cur_media.groups.push(group);
  8655. } else if (!skip && (lines[i].substring(0, 'a=sendrecv'.length) === 'a=sendrecv' ||
  8656. lines[i].substring(0, 'a=recvonly'.length) === 'a=recvonly' ||
  8657. lines[i].substring(0, 'a=sendonly'.length) === 'a=sendonly' ||
  8658. lines[i].substring(0, 'a=inactive'.length) === 'a=inactive')) {
  8659. cur_media.direction = lines[i].substring('a='.length);
  8660. }
  8661. }
  8662. return res;
  8663. };
  8664. /**
  8665. * The _indexOfArray() method returns the first a CompoundIndex at which a
  8666. * given element can be found in the array, or _emptyCompoundIndex if it is
  8667. * not present.
  8668. *
  8669. * Example:
  8670. *
  8671. * _indexOfArray('3', [ 'this is line 1', 'this is line 2', 'this is line 3' ])
  8672. *
  8673. * returns {row: 2, column: 14}
  8674. *
  8675. * @param needle
  8676. * @param haystack
  8677. * @param start
  8678. * @returns {}
  8679. * @private
  8680. */
  8681. SimulcastUtils.prototype._indexOfArray = function (needle, haystack, start) {
  8682. var length = haystack.length, idx, i;
  8683. if (!start) {
  8684. start = 0;
  8685. }
  8686. for (i = start; i < length; i++) {
  8687. idx = haystack[i].indexOf(needle);
  8688. if (idx !== -1) {
  8689. return {row: i, column: idx};
  8690. }
  8691. }
  8692. return this._emptyCompoundIndex;
  8693. };
  8694. SimulcastUtils.prototype._removeSimulcastGroup = function (lines) {
  8695. var i;
  8696. for (i = lines.length - 1; i >= 0; i--) {
  8697. if (lines[i].indexOf('a=ssrc-group:SIM') !== -1) {
  8698. lines.splice(i, 1);
  8699. }
  8700. }
  8701. };
  8702. SimulcastUtils.prototype._compileVideoSources = function (videoSources) {
  8703. var sb = [], ssrc, addedSSRCs = [];
  8704. this.logger.info('Compiling video sources...');
  8705. // Add the groups
  8706. if (videoSources.groups && videoSources.groups.length !== 0) {
  8707. videoSources.groups.forEach(function (group) {
  8708. if (group.ssrcs && group.ssrcs.length !== 0) {
  8709. sb.push([['a=ssrc-group:', group.semantics].join(''), group.ssrcs.join(' ')].join(' '));
  8710. // if (group.semantics !== 'SIM') {
  8711. group.ssrcs.forEach(function (ssrc) {
  8712. addedSSRCs.push(ssrc);
  8713. sb.splice.apply(sb, [sb.length, 0].concat([
  8714. ["a=ssrc:", ssrc, " cname:", videoSources.sources[ssrc].cname].join(''),
  8715. ["a=ssrc:", ssrc, " msid:", videoSources.sources[ssrc].msid].join('')]));
  8716. });
  8717. //}
  8718. }
  8719. });
  8720. }
  8721. // Then add any free sources.
  8722. if (videoSources.sources) {
  8723. for (ssrc in videoSources.sources) {
  8724. if (addedSSRCs.indexOf(ssrc) === -1) {
  8725. sb.splice.apply(sb, [sb.length, 0].concat([
  8726. ["a=ssrc:", ssrc, " cname:", videoSources.sources[ssrc].cname].join(''),
  8727. ["a=ssrc:", ssrc, " msid:", videoSources.sources[ssrc].msid].join('')]));
  8728. }
  8729. }
  8730. }
  8731. return sb;
  8732. };
  8733. module.exports = SimulcastUtils;
  8734. },{"./SimulcastLogger":38}],42:[function(require,module,exports){
  8735. /*jslint plusplus: true */
  8736. /*jslint nomen: true*/
  8737. var SimulcastSender = require("./SimulcastSender");
  8738. var NoSimulcastSender = SimulcastSender["no"];
  8739. var NativeSimulcastSender = SimulcastSender["native"];
  8740. var SimulcastReceiver = require("./SimulcastReceiver");
  8741. var SimulcastUtils = require("./SimulcastUtils");
  8742. var RTCEvents = require("../../service/RTC/RTCEvents");
  8743. /**
  8744. *
  8745. * @constructor
  8746. */
  8747. function SimulcastManager() {
  8748. // Create the simulcast utilities.
  8749. this.simulcastUtils = new SimulcastUtils();
  8750. // Create remote simulcast.
  8751. this.simulcastReceiver = new SimulcastReceiver();
  8752. // Initialize local simulcast.
  8753. // TODO(gp) move into SimulcastManager.prototype.getUserMedia and take into
  8754. // account constraints.
  8755. if (!config.enableSimulcast) {
  8756. this.simulcastSender = new NoSimulcastSender();
  8757. } else {
  8758. var isChromium = window.chrome,
  8759. vendorName = window.navigator.vendor;
  8760. if(isChromium !== null && isChromium !== undefined
  8761. /* skip opera */
  8762. && vendorName === "Google Inc."
  8763. /* skip Chromium as suggested by fippo */
  8764. && !window.navigator.appVersion.match(/Chromium\//) ) {
  8765. var ver = parseInt(window.navigator.appVersion.match(/Chrome\/(\d+)\./)[1], 10);
  8766. if (ver > 37) {
  8767. this.simulcastSender = new NativeSimulcastSender();
  8768. } else {
  8769. this.simulcastSender = new NoSimulcastSender();
  8770. }
  8771. } else {
  8772. this.simulcastSender = new NoSimulcastSender();
  8773. }
  8774. }
  8775. APP.RTC.addListener(RTCEvents.SIMULCAST_LAYER_CHANGED,
  8776. function (endpointSimulcastLayers) {
  8777. endpointSimulcastLayers.forEach(function (esl) {
  8778. var ssrc = esl.simulcastLayer.primarySSRC;
  8779. simulcast._setReceivingVideoStream(esl.endpoint, ssrc);
  8780. });
  8781. });
  8782. APP.RTC.addListener(RTCEvents.SIMULCAST_START, function (simulcastLayer) {
  8783. var ssrc = simulcastLayer.primarySSRC;
  8784. simulcast._setLocalVideoStreamEnabled(ssrc, true);
  8785. });
  8786. APP.RTC.addListener(RTCEvents.SIMULCAST_STOP, function (simulcastLayer) {
  8787. var ssrc = simulcastLayer.primarySSRC;
  8788. simulcast._setLocalVideoStreamEnabled(ssrc, false);
  8789. });
  8790. }
  8791. /**
  8792. * Restores the simulcast groups of the remote description. In
  8793. * transformRemoteDescription we remove those in order for the set remote
  8794. * description to succeed. The focus needs the signal the groups to new
  8795. * participants.
  8796. *
  8797. * @param desc
  8798. * @returns {*}
  8799. */
  8800. SimulcastManager.prototype.reverseTransformRemoteDescription = function (desc) {
  8801. return this.simulcastReceiver.reverseTransformRemoteDescription(desc);
  8802. };
  8803. /**
  8804. * Removes the ssrc-group:SIM from the remote description bacause Chrome
  8805. * either gets confused and thinks this is an FID group or, if an FID group
  8806. * is already present, it fails to set the remote description.
  8807. *
  8808. * @param desc
  8809. * @returns {*}
  8810. */
  8811. SimulcastManager.prototype.transformRemoteDescription = function (desc) {
  8812. return this.simulcastReceiver.transformRemoteDescription(desc);
  8813. };
  8814. /**
  8815. * Gets the fully qualified msid (stream.id + track.id) associated to the
  8816. * SSRC.
  8817. *
  8818. * @param ssrc
  8819. * @returns {*}
  8820. */
  8821. SimulcastManager.prototype.getRemoteVideoStreamIdBySSRC = function (ssrc) {
  8822. return this.simulcastReceiver.getRemoteVideoStreamIdBySSRC(ssrc);
  8823. };
  8824. /**
  8825. * Returns a stream with single video track, the one currently being
  8826. * received by this endpoint.
  8827. *
  8828. * @param stream the remote simulcast stream.
  8829. * @returns {webkitMediaStream}
  8830. */
  8831. SimulcastManager.prototype.getReceivingVideoStream = function (stream) {
  8832. return this.simulcastReceiver.getReceivingVideoStream(stream);
  8833. };
  8834. /**
  8835. *
  8836. *
  8837. * @param desc
  8838. * @returns {*}
  8839. */
  8840. SimulcastManager.prototype.transformLocalDescription = function (desc) {
  8841. return this.simulcastSender.transformLocalDescription(desc);
  8842. };
  8843. /**
  8844. *
  8845. * @returns {*}
  8846. */
  8847. SimulcastManager.prototype.getLocalVideoStream = function() {
  8848. return this.simulcastSender.getLocalVideoStream();
  8849. };
  8850. /**
  8851. * GUM for simulcast.
  8852. *
  8853. * @param constraints
  8854. * @param success
  8855. * @param err
  8856. */
  8857. SimulcastManager.prototype.getUserMedia = function (constraints, success, err) {
  8858. this.simulcastSender.getUserMedia(constraints, success, err);
  8859. };
  8860. /**
  8861. * Prepares the local description for public usage (i.e. to be signaled
  8862. * through Jingle to the focus).
  8863. *
  8864. * @param desc
  8865. * @returns {RTCSessionDescription}
  8866. */
  8867. SimulcastManager.prototype.reverseTransformLocalDescription = function (desc) {
  8868. return this.simulcastSender.reverseTransformLocalDescription(desc);
  8869. };
  8870. /**
  8871. * Ensures that the simulcast group is present in the answer, _if_ native
  8872. * simulcast is enabled,
  8873. *
  8874. * @param desc
  8875. * @returns {*}
  8876. */
  8877. SimulcastManager.prototype.transformAnswer = function (desc) {
  8878. return this.simulcastSender.transformAnswer(desc);
  8879. };
  8880. SimulcastManager.prototype.getReceivingSSRC = function (jid) {
  8881. return this.simulcastReceiver.getReceivingSSRC(jid);
  8882. };
  8883. SimulcastManager.prototype.getReceivingVideoStreamBySSRC = function (msid) {
  8884. return this.simulcastReceiver.getReceivingVideoStreamBySSRC(msid);
  8885. };
  8886. /**
  8887. *
  8888. * @param lines
  8889. * @param mediatypes
  8890. * @returns {*}
  8891. */
  8892. SimulcastManager.prototype.parseMedia = function(lines, mediatypes) {
  8893. var sb = lines.sdp.split('\r\n');
  8894. return this.simulcastUtils.parseMedia(sb, mediatypes);
  8895. };
  8896. SimulcastManager.prototype._setReceivingVideoStream = function(resource, ssrc) {
  8897. this.simulcastReceiver._setReceivingVideoStream(resource, ssrc);
  8898. };
  8899. SimulcastManager.prototype._setLocalVideoStreamEnabled = function(ssrc, enabled) {
  8900. this.simulcastSender._setLocalVideoStreamEnabled(ssrc, enabled);
  8901. };
  8902. SimulcastManager.prototype.resetSender = function() {
  8903. if (typeof this.simulcastSender.reset === 'function'){
  8904. this.simulcastSender.reset();
  8905. }
  8906. };
  8907. var simulcast = new SimulcastManager();
  8908. module.exports = simulcast;
  8909. },{"../../service/RTC/RTCEvents":80,"./SimulcastReceiver":39,"./SimulcastSender":40,"./SimulcastUtils":41}],43:[function(require,module,exports){
  8910. /**
  8911. * Provides statistics for the local stream.
  8912. */
  8913. /**
  8914. * Size of the webaudio analizer buffer.
  8915. * @type {number}
  8916. */
  8917. var WEBAUDIO_ANALIZER_FFT_SIZE = 2048;
  8918. /**
  8919. * Value of the webaudio analizer smoothing time parameter.
  8920. * @type {number}
  8921. */
  8922. var WEBAUDIO_ANALIZER_SMOOTING_TIME = 0.8;
  8923. /**
  8924. * Converts time domain data array to audio level.
  8925. * @param array the time domain data array.
  8926. * @returns {number} the audio level
  8927. */
  8928. function timeDomainDataToAudioLevel(samples) {
  8929. var maxVolume = 0;
  8930. var length = samples.length;
  8931. for (var i = 0; i < length; i++) {
  8932. if (maxVolume < samples[i])
  8933. maxVolume = samples[i];
  8934. }
  8935. return parseFloat(((maxVolume - 127) / 128).toFixed(3));
  8936. };
  8937. /**
  8938. * Animates audio level change
  8939. * @param newLevel the new audio level
  8940. * @param lastLevel the last audio level
  8941. * @returns {Number} the audio level to be set
  8942. */
  8943. function animateLevel(newLevel, lastLevel)
  8944. {
  8945. var value = 0;
  8946. var diff = lastLevel - newLevel;
  8947. if(diff > 0.2)
  8948. {
  8949. value = lastLevel - 0.2;
  8950. }
  8951. else if(diff < -0.4)
  8952. {
  8953. value = lastLevel + 0.4;
  8954. }
  8955. else
  8956. {
  8957. value = newLevel;
  8958. }
  8959. return parseFloat(value.toFixed(3));
  8960. }
  8961. /**
  8962. * <tt>LocalStatsCollector</tt> calculates statistics for the local stream.
  8963. *
  8964. * @param stream the local stream
  8965. * @param interval stats refresh interval given in ms.
  8966. * @param {function(LocalStatsCollector)} updateCallback the callback called on stats
  8967. * update.
  8968. * @constructor
  8969. */
  8970. function LocalStatsCollector(stream, interval, statisticsService, eventEmitter) {
  8971. window.AudioContext = window.AudioContext || window.webkitAudioContext;
  8972. this.stream = stream;
  8973. this.intervalId = null;
  8974. this.intervalMilis = interval;
  8975. this.eventEmitter = eventEmitter;
  8976. this.audioLevel = 0;
  8977. this.statisticsService = statisticsService;
  8978. }
  8979. /**
  8980. * Starts the collecting the statistics.
  8981. */
  8982. LocalStatsCollector.prototype.start = function () {
  8983. if (config.disableAudioLevels || !window.AudioContext)
  8984. return;
  8985. var context = new AudioContext();
  8986. var analyser = context.createAnalyser();
  8987. analyser.smoothingTimeConstant = WEBAUDIO_ANALIZER_SMOOTING_TIME;
  8988. analyser.fftSize = WEBAUDIO_ANALIZER_FFT_SIZE;
  8989. var source = context.createMediaStreamSource(this.stream);
  8990. source.connect(analyser);
  8991. var self = this;
  8992. this.intervalId = setInterval(
  8993. function () {
  8994. var array = new Uint8Array(analyser.frequencyBinCount);
  8995. analyser.getByteTimeDomainData(array);
  8996. var audioLevel = timeDomainDataToAudioLevel(array);
  8997. if(audioLevel != self.audioLevel) {
  8998. self.audioLevel = animateLevel(audioLevel, self.audioLevel);
  8999. self.eventEmitter.emit(
  9000. "statistics.audioLevel",
  9001. self.statisticsService.LOCAL_JID,
  9002. self.audioLevel);
  9003. }
  9004. },
  9005. this.intervalMilis
  9006. );
  9007. };
  9008. /**
  9009. * Stops collecting the statistics.
  9010. */
  9011. LocalStatsCollector.prototype.stop = function () {
  9012. if (this.intervalId) {
  9013. clearInterval(this.intervalId);
  9014. this.intervalId = null;
  9015. }
  9016. };
  9017. module.exports = LocalStatsCollector;
  9018. },{}],44:[function(require,module,exports){
  9019. /* global ssrc2jid */
  9020. /* jshint -W117 */
  9021. var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
  9022. /**
  9023. * Calculates packet lost percent using the number of lost packets and the
  9024. * number of all packet.
  9025. * @param lostPackets the number of lost packets
  9026. * @param totalPackets the number of all packets.
  9027. * @returns {number} packet loss percent
  9028. */
  9029. function calculatePacketLoss(lostPackets, totalPackets) {
  9030. if(!totalPackets || totalPackets <= 0 || !lostPackets || lostPackets <= 0)
  9031. return 0;
  9032. return Math.round((lostPackets/totalPackets)*100);
  9033. }
  9034. function getStatValue(item, name) {
  9035. if(!keyMap[APP.RTC.getBrowserType()][name])
  9036. throw "The property isn't supported!";
  9037. var key = keyMap[APP.RTC.getBrowserType()][name];
  9038. return APP.RTC.getBrowserType() == RTCBrowserType.RTC_BROWSER_CHROME? item.stat(key) : item[key];
  9039. }
  9040. /**
  9041. * Peer statistics data holder.
  9042. * @constructor
  9043. */
  9044. function PeerStats()
  9045. {
  9046. this.ssrc2Loss = {};
  9047. this.ssrc2AudioLevel = {};
  9048. this.ssrc2bitrate = {};
  9049. this.ssrc2resolution = {};
  9050. }
  9051. /**
  9052. * The bandwidth
  9053. * @type {{}}
  9054. */
  9055. PeerStats.bandwidth = {};
  9056. /**
  9057. * The bit rate
  9058. * @type {{}}
  9059. */
  9060. PeerStats.bitrate = {};
  9061. /**
  9062. * The packet loss rate
  9063. * @type {{}}
  9064. */
  9065. PeerStats.packetLoss = null;
  9066. /**
  9067. * Sets packets loss rate for given <tt>ssrc</tt> that blong to the peer
  9068. * represented by this instance.
  9069. * @param ssrc audio or video RTP stream SSRC.
  9070. * @param lossRate new packet loss rate value to be set.
  9071. */
  9072. PeerStats.prototype.setSsrcLoss = function (ssrc, lossRate)
  9073. {
  9074. this.ssrc2Loss[ssrc] = lossRate;
  9075. };
  9076. /**
  9077. * Sets resolution for given <tt>ssrc</tt> that belong to the peer
  9078. * represented by this instance.
  9079. * @param ssrc audio or video RTP stream SSRC.
  9080. * @param resolution new resolution value to be set.
  9081. */
  9082. PeerStats.prototype.setSsrcResolution = function (ssrc, resolution)
  9083. {
  9084. if(resolution === null && this.ssrc2resolution[ssrc])
  9085. {
  9086. delete this.ssrc2resolution[ssrc];
  9087. }
  9088. else if(resolution !== null)
  9089. this.ssrc2resolution[ssrc] = resolution;
  9090. };
  9091. /**
  9092. * Sets the bit rate for given <tt>ssrc</tt> that blong to the peer
  9093. * represented by this instance.
  9094. * @param ssrc audio or video RTP stream SSRC.
  9095. * @param bitrate new bitrate value to be set.
  9096. */
  9097. PeerStats.prototype.setSsrcBitrate = function (ssrc, bitrate)
  9098. {
  9099. if(this.ssrc2bitrate[ssrc])
  9100. {
  9101. this.ssrc2bitrate[ssrc].download += bitrate.download;
  9102. this.ssrc2bitrate[ssrc].upload += bitrate.upload;
  9103. }
  9104. else {
  9105. this.ssrc2bitrate[ssrc] = bitrate;
  9106. }
  9107. };
  9108. /**
  9109. * Sets new audio level(input or output) for given <tt>ssrc</tt> that identifies
  9110. * the stream which belongs to the peer represented by this instance.
  9111. * @param ssrc RTP stream SSRC for which current audio level value will be
  9112. * updated.
  9113. * @param audioLevel the new audio level value to be set. Value is truncated to
  9114. * fit the range from 0 to 1.
  9115. */
  9116. PeerStats.prototype.setSsrcAudioLevel = function (ssrc, audioLevel)
  9117. {
  9118. // Range limit 0 - 1
  9119. this.ssrc2AudioLevel[ssrc] = Math.min(Math.max(audioLevel, 0), 1);
  9120. };
  9121. /**
  9122. * Array with the transport information.
  9123. * @type {Array}
  9124. */
  9125. PeerStats.transport = [];
  9126. /**
  9127. * <tt>StatsCollector</tt> registers for stats updates of given
  9128. * <tt>peerconnection</tt> in given <tt>interval</tt>. On each update particular
  9129. * stats are extracted and put in {@link PeerStats} objects. Once the processing
  9130. * is done <tt>audioLevelsUpdateCallback</tt> is called with <tt>this</tt>
  9131. * instance as an event source.
  9132. *
  9133. * @param peerconnection webRTC peer connection object.
  9134. * @param interval stats refresh interval given in ms.
  9135. * @param {function(StatsCollector)} audioLevelsUpdateCallback the callback
  9136. * called on stats update.
  9137. * @constructor
  9138. */
  9139. function StatsCollector(peerconnection, audioLevelsInterval, statsInterval, eventEmitter)
  9140. {
  9141. this.peerconnection = peerconnection;
  9142. this.baselineAudioLevelsReport = null;
  9143. this.currentAudioLevelsReport = null;
  9144. this.currentStatsReport = null;
  9145. this.baselineStatsReport = null;
  9146. this.audioLevelsIntervalId = null;
  9147. this.eventEmitter = eventEmitter;
  9148. /**
  9149. * Gather PeerConnection stats once every this many milliseconds.
  9150. */
  9151. this.GATHER_INTERVAL = 10000;
  9152. /**
  9153. * Log stats via the focus once every this many milliseconds.
  9154. */
  9155. this.LOG_INTERVAL = 60000;
  9156. /**
  9157. * Gather stats and store them in this.statsToBeLogged.
  9158. */
  9159. this.gatherStatsIntervalId = null;
  9160. /**
  9161. * Send the stats already saved in this.statsToBeLogged to be logged via
  9162. * the focus.
  9163. */
  9164. this.logStatsIntervalId = null;
  9165. /**
  9166. * Stores the statistics which will be send to the focus to be logged.
  9167. */
  9168. this.statsToBeLogged =
  9169. {
  9170. timestamps: [],
  9171. stats: {}
  9172. };
  9173. // Updates stats interval
  9174. this.audioLevelsIntervalMilis = audioLevelsInterval;
  9175. this.statsIntervalId = null;
  9176. this.statsIntervalMilis = statsInterval;
  9177. // Map of jids to PeerStats
  9178. this.jid2stats = {};
  9179. }
  9180. module.exports = StatsCollector;
  9181. /**
  9182. * Stops stats updates.
  9183. */
  9184. StatsCollector.prototype.stop = function ()
  9185. {
  9186. if (this.audioLevelsIntervalId)
  9187. {
  9188. clearInterval(this.audioLevelsIntervalId);
  9189. this.audioLevelsIntervalId = null;
  9190. clearInterval(this.statsIntervalId);
  9191. this.statsIntervalId = null;
  9192. clearInterval(this.logStatsIntervalId);
  9193. this.logStatsIntervalId = null;
  9194. clearInterval(this.gatherStatsIntervalId);
  9195. this.gatherStatsIntervalId = null;
  9196. }
  9197. };
  9198. /**
  9199. * Callback passed to <tt>getStats</tt> method.
  9200. * @param error an error that occurred on <tt>getStats</tt> call.
  9201. */
  9202. StatsCollector.prototype.errorCallback = function (error)
  9203. {
  9204. console.error("Get stats error", error);
  9205. this.stop();
  9206. };
  9207. /**
  9208. * Starts stats updates.
  9209. */
  9210. StatsCollector.prototype.start = function ()
  9211. {
  9212. var self = this;
  9213. if(!config.disableAudioLevels) {
  9214. this.audioLevelsIntervalId = setInterval(
  9215. function () {
  9216. // Interval updates
  9217. self.peerconnection.getStats(
  9218. function (report) {
  9219. var results = null;
  9220. if (!report || !report.result ||
  9221. typeof report.result != 'function') {
  9222. results = report;
  9223. }
  9224. else {
  9225. results = report.result();
  9226. }
  9227. //console.error("Got interval report", results);
  9228. self.currentAudioLevelsReport = results;
  9229. self.processAudioLevelReport();
  9230. self.baselineAudioLevelsReport =
  9231. self.currentAudioLevelsReport;
  9232. },
  9233. self.errorCallback
  9234. );
  9235. },
  9236. self.audioLevelsIntervalMilis
  9237. );
  9238. }
  9239. if(!config.disableStats) {
  9240. this.statsIntervalId = setInterval(
  9241. function () {
  9242. // Interval updates
  9243. self.peerconnection.getStats(
  9244. function (report) {
  9245. var results = null;
  9246. if (!report || !report.result ||
  9247. typeof report.result != 'function') {
  9248. //firefox
  9249. results = report;
  9250. }
  9251. else {
  9252. //chrome
  9253. results = report.result();
  9254. }
  9255. //console.error("Got interval report", results);
  9256. self.currentStatsReport = results;
  9257. try {
  9258. self.processStatsReport();
  9259. }
  9260. catch (e) {
  9261. console.error("Unsupported key:" + e, e);
  9262. }
  9263. self.baselineStatsReport = self.currentStatsReport;
  9264. },
  9265. self.errorCallback
  9266. );
  9267. },
  9268. self.statsIntervalMilis
  9269. );
  9270. }
  9271. if (config.logStats) {
  9272. this.gatherStatsIntervalId = setInterval(
  9273. function () {
  9274. self.peerconnection.getStats(
  9275. function (report) {
  9276. self.addStatsToBeLogged(report.result());
  9277. },
  9278. function () {
  9279. }
  9280. );
  9281. },
  9282. this.GATHER_INTERVAL
  9283. );
  9284. this.logStatsIntervalId = setInterval(
  9285. function() { self.logStats(); },
  9286. this.LOG_INTERVAL);
  9287. }
  9288. };
  9289. /**
  9290. * Converts the stats to the format used for logging, and saves the data in
  9291. * this.statsToBeLogged.
  9292. * @param reports Reports as given by webkitRTCPerConnection.getStats.
  9293. */
  9294. StatsCollector.prototype.addStatsToBeLogged = function (reports) {
  9295. var self = this;
  9296. var num_records = this.statsToBeLogged.timestamps.length;
  9297. this.statsToBeLogged.timestamps.push(new Date().getTime());
  9298. reports.map(function (report) {
  9299. var stat = self.statsToBeLogged.stats[report.id];
  9300. if (!stat) {
  9301. stat = self.statsToBeLogged.stats[report.id] = {};
  9302. }
  9303. stat.type = report.type;
  9304. report.names().map(function (name) {
  9305. var values = stat[name];
  9306. if (!values) {
  9307. values = stat[name] = [];
  9308. }
  9309. while (values.length < num_records) {
  9310. values.push(null);
  9311. }
  9312. values.push(report.stat(name));
  9313. });
  9314. });
  9315. };
  9316. StatsCollector.prototype.logStats = function () {
  9317. if(!APP.xmpp.sendLogs(this.statsToBeLogged))
  9318. return;
  9319. // Reset the stats
  9320. this.statsToBeLogged.stats = {};
  9321. this.statsToBeLogged.timestamps = [];
  9322. };
  9323. var keyMap = {};
  9324. keyMap[RTCBrowserType.RTC_BROWSER_FIREFOX] = {
  9325. "ssrc": "ssrc",
  9326. "packetsReceived": "packetsReceived",
  9327. "packetsLost": "packetsLost",
  9328. "packetsSent": "packetsSent",
  9329. "bytesReceived": "bytesReceived",
  9330. "bytesSent": "bytesSent"
  9331. };
  9332. keyMap[RTCBrowserType.RTC_BROWSER_CHROME] = {
  9333. "receiveBandwidth": "googAvailableReceiveBandwidth",
  9334. "sendBandwidth": "googAvailableSendBandwidth",
  9335. "remoteAddress": "googRemoteAddress",
  9336. "transportType": "googTransportType",
  9337. "localAddress": "googLocalAddress",
  9338. "activeConnection": "googActiveConnection",
  9339. "ssrc": "ssrc",
  9340. "packetsReceived": "packetsReceived",
  9341. "packetsSent": "packetsSent",
  9342. "packetsLost": "packetsLost",
  9343. "bytesReceived": "bytesReceived",
  9344. "bytesSent": "bytesSent",
  9345. "googFrameHeightReceived": "googFrameHeightReceived",
  9346. "googFrameWidthReceived": "googFrameWidthReceived",
  9347. "googFrameHeightSent": "googFrameHeightSent",
  9348. "googFrameWidthSent": "googFrameWidthSent",
  9349. "audioInputLevel": "audioInputLevel",
  9350. "audioOutputLevel": "audioOutputLevel"
  9351. };
  9352. /**
  9353. * Stats processing logic.
  9354. */
  9355. StatsCollector.prototype.processStatsReport = function () {
  9356. if (!this.baselineStatsReport) {
  9357. return;
  9358. }
  9359. for (var idx in this.currentStatsReport) {
  9360. var now = this.currentStatsReport[idx];
  9361. try {
  9362. if (getStatValue(now, 'receiveBandwidth') ||
  9363. getStatValue(now, 'sendBandwidth')) {
  9364. PeerStats.bandwidth = {
  9365. "download": Math.round(
  9366. (getStatValue(now, 'receiveBandwidth')) / 1000),
  9367. "upload": Math.round(
  9368. (getStatValue(now, 'sendBandwidth')) / 1000)
  9369. };
  9370. }
  9371. }
  9372. catch(e){/*not supported*/}
  9373. if(now.type == 'googCandidatePair')
  9374. {
  9375. var ip, type, localIP, active;
  9376. try {
  9377. ip = getStatValue(now, 'remoteAddress');
  9378. type = getStatValue(now, "transportType");
  9379. localIP = getStatValue(now, "localAddress");
  9380. active = getStatValue(now, "activeConnection");
  9381. }
  9382. catch(e){/*not supported*/}
  9383. if(!ip || !type || !localIP || active != "true")
  9384. continue;
  9385. var addressSaved = false;
  9386. for(var i = 0; i < PeerStats.transport.length; i++)
  9387. {
  9388. if(PeerStats.transport[i].ip == ip &&
  9389. PeerStats.transport[i].type == type &&
  9390. PeerStats.transport[i].localip == localIP)
  9391. {
  9392. addressSaved = true;
  9393. }
  9394. }
  9395. if(addressSaved)
  9396. continue;
  9397. PeerStats.transport.push({localip: localIP, ip: ip, type: type});
  9398. continue;
  9399. }
  9400. if(now.type == "candidatepair")
  9401. {
  9402. if(now.state == "succeeded")
  9403. continue;
  9404. var local = this.currentStatsReport[now.localCandidateId];
  9405. var remote = this.currentStatsReport[now.remoteCandidateId];
  9406. PeerStats.transport.push({localip: local.ipAddress + ":" + local.portNumber,
  9407. ip: remote.ipAddress + ":" + remote.portNumber, type: local.transport});
  9408. }
  9409. if (now.type != 'ssrc' && now.type != "outboundrtp" &&
  9410. now.type != "inboundrtp") {
  9411. continue;
  9412. }
  9413. var before = this.baselineStatsReport[idx];
  9414. if (!before) {
  9415. console.warn(getStatValue(now, 'ssrc') + ' not enough data');
  9416. continue;
  9417. }
  9418. var ssrc = getStatValue(now, 'ssrc');
  9419. if(!ssrc)
  9420. continue;
  9421. var jid = APP.xmpp.getJidFromSSRC(ssrc);
  9422. if (!jid && (Date.now() - now.timestamp) < 3000) {
  9423. console.warn("No jid for ssrc: " + ssrc);
  9424. continue;
  9425. }
  9426. var jidStats = this.jid2stats[jid];
  9427. if (!jidStats) {
  9428. jidStats = new PeerStats();
  9429. this.jid2stats[jid] = jidStats;
  9430. }
  9431. var isDownloadStream = true;
  9432. var key = 'packetsReceived';
  9433. if (!getStatValue(now, key))
  9434. {
  9435. isDownloadStream = false;
  9436. key = 'packetsSent';
  9437. if (!getStatValue(now, key))
  9438. {
  9439. console.warn("No packetsReceived nor packetSent stat found");
  9440. continue;
  9441. }
  9442. }
  9443. var packetsNow = getStatValue(now, key);
  9444. if(!packetsNow || packetsNow < 0)
  9445. packetsNow = 0;
  9446. var packetsBefore = getStatValue(before, key);
  9447. if(!packetsBefore || packetsBefore < 0)
  9448. packetsBefore = 0;
  9449. var packetRate = packetsNow - packetsBefore;
  9450. if(!packetRate || packetRate < 0)
  9451. packetRate = 0;
  9452. var currentLoss = getStatValue(now, 'packetsLost');
  9453. if(!currentLoss || currentLoss < 0)
  9454. currentLoss = 0;
  9455. var previousLoss = getStatValue(before, 'packetsLost');
  9456. if(!previousLoss || previousLoss < 0)
  9457. previousLoss = 0;
  9458. var lossRate = currentLoss - previousLoss;
  9459. if(!lossRate || lossRate < 0)
  9460. lossRate = 0;
  9461. var packetsTotal = (packetRate + lossRate);
  9462. jidStats.setSsrcLoss(ssrc,
  9463. {"packetsTotal": packetsTotal,
  9464. "packetsLost": lossRate,
  9465. "isDownloadStream": isDownloadStream});
  9466. var bytesReceived = 0, bytesSent = 0;
  9467. if(getStatValue(now, "bytesReceived"))
  9468. {
  9469. bytesReceived = getStatValue(now, "bytesReceived") -
  9470. getStatValue(before, "bytesReceived");
  9471. }
  9472. if(getStatValue(now, "bytesSent"))
  9473. {
  9474. bytesSent = getStatValue(now, "bytesSent") -
  9475. getStatValue(before, "bytesSent");
  9476. }
  9477. var time = Math.round((now.timestamp - before.timestamp) / 1000);
  9478. if(bytesReceived <= 0 || time <= 0)
  9479. {
  9480. bytesReceived = 0;
  9481. }
  9482. else
  9483. {
  9484. bytesReceived = Math.round(((bytesReceived * 8) / time) / 1000);
  9485. }
  9486. if(bytesSent <= 0 || time <= 0)
  9487. {
  9488. bytesSent = 0;
  9489. }
  9490. else
  9491. {
  9492. bytesSent = Math.round(((bytesSent * 8) / time) / 1000);
  9493. }
  9494. jidStats.setSsrcBitrate(ssrc, {
  9495. "download": bytesReceived,
  9496. "upload": bytesSent});
  9497. var resolution = {height: null, width: null};
  9498. try {
  9499. if (getStatValue(now, "googFrameHeightReceived") &&
  9500. getStatValue(now, "googFrameWidthReceived")) {
  9501. resolution.height = getStatValue(now, "googFrameHeightReceived");
  9502. resolution.width = getStatValue(now, "googFrameWidthReceived");
  9503. }
  9504. else if (getStatValue(now, "googFrameHeightSent") &&
  9505. getStatValue(now, "googFrameWidthSent")) {
  9506. resolution.height = getStatValue(now, "googFrameHeightSent");
  9507. resolution.width = getStatValue(now, "googFrameWidthSent");
  9508. }
  9509. }
  9510. catch(e){/*not supported*/}
  9511. if(resolution.height && resolution.width)
  9512. {
  9513. jidStats.setSsrcResolution(ssrc, resolution);
  9514. }
  9515. else
  9516. {
  9517. jidStats.setSsrcResolution(ssrc, null);
  9518. }
  9519. }
  9520. var self = this;
  9521. // Jid stats
  9522. var totalPackets = {download: 0, upload: 0};
  9523. var lostPackets = {download: 0, upload: 0};
  9524. var bitrateDownload = 0;
  9525. var bitrateUpload = 0;
  9526. var resolutions = {};
  9527. Object.keys(this.jid2stats).forEach(
  9528. function (jid)
  9529. {
  9530. Object.keys(self.jid2stats[jid].ssrc2Loss).forEach(
  9531. function (ssrc)
  9532. {
  9533. var type = "upload";
  9534. if(self.jid2stats[jid].ssrc2Loss[ssrc].isDownloadStream)
  9535. type = "download";
  9536. totalPackets[type] +=
  9537. self.jid2stats[jid].ssrc2Loss[ssrc].packetsTotal;
  9538. lostPackets[type] +=
  9539. self.jid2stats[jid].ssrc2Loss[ssrc].packetsLost;
  9540. }
  9541. );
  9542. Object.keys(self.jid2stats[jid].ssrc2bitrate).forEach(
  9543. function (ssrc) {
  9544. bitrateDownload +=
  9545. self.jid2stats[jid].ssrc2bitrate[ssrc].download;
  9546. bitrateUpload +=
  9547. self.jid2stats[jid].ssrc2bitrate[ssrc].upload;
  9548. delete self.jid2stats[jid].ssrc2bitrate[ssrc];
  9549. }
  9550. );
  9551. resolutions[jid] = self.jid2stats[jid].ssrc2resolution;
  9552. }
  9553. );
  9554. PeerStats.bitrate = {"upload": bitrateUpload, "download": bitrateDownload};
  9555. PeerStats.packetLoss = {
  9556. total:
  9557. calculatePacketLoss(lostPackets.download + lostPackets.upload,
  9558. totalPackets.download + totalPackets.upload),
  9559. download:
  9560. calculatePacketLoss(lostPackets.download, totalPackets.download),
  9561. upload:
  9562. calculatePacketLoss(lostPackets.upload, totalPackets.upload)
  9563. };
  9564. this.eventEmitter.emit("statistics.connectionstats",
  9565. {
  9566. "bitrate": PeerStats.bitrate,
  9567. "packetLoss": PeerStats.packetLoss,
  9568. "bandwidth": PeerStats.bandwidth,
  9569. "resolution": resolutions,
  9570. "transport": PeerStats.transport
  9571. });
  9572. PeerStats.transport = [];
  9573. };
  9574. /**
  9575. * Stats processing logic.
  9576. */
  9577. StatsCollector.prototype.processAudioLevelReport = function ()
  9578. {
  9579. if (!this.baselineAudioLevelsReport)
  9580. {
  9581. return;
  9582. }
  9583. for (var idx in this.currentAudioLevelsReport)
  9584. {
  9585. var now = this.currentAudioLevelsReport[idx];
  9586. if (now.type != 'ssrc')
  9587. {
  9588. continue;
  9589. }
  9590. var before = this.baselineAudioLevelsReport[idx];
  9591. if (!before)
  9592. {
  9593. console.warn(getStatValue(now, 'ssrc') + ' not enough data');
  9594. continue;
  9595. }
  9596. var ssrc = getStatValue(now, 'ssrc');
  9597. var jid = APP.xmpp.getJidFromSSRC(ssrc);
  9598. if (!jid && (Date.now() - now.timestamp) < 3000)
  9599. {
  9600. console.warn("No jid for ssrc: " + ssrc);
  9601. continue;
  9602. }
  9603. var jidStats = this.jid2stats[jid];
  9604. if (!jidStats)
  9605. {
  9606. jidStats = new PeerStats();
  9607. this.jid2stats[jid] = jidStats;
  9608. }
  9609. // Audio level
  9610. var audioLevel = null;
  9611. try {
  9612. audioLevel = getStatValue(now, 'audioInputLevel');
  9613. if (!audioLevel)
  9614. audioLevel = getStatValue(now, 'audioOutputLevel');
  9615. }
  9616. catch(e) {/*not supported*/
  9617. console.warn("Audio Levels are not available in the statistics.");
  9618. clearInterval(this.audioLevelsIntervalId);
  9619. return;
  9620. }
  9621. if (audioLevel)
  9622. {
  9623. // TODO: can't find specs about what this value really is,
  9624. // but it seems to vary between 0 and around 32k.
  9625. audioLevel = audioLevel / 32767;
  9626. jidStats.setSsrcAudioLevel(ssrc, audioLevel);
  9627. if(jid != APP.xmpp.myJid())
  9628. this.eventEmitter.emit("statistics.audioLevel", jid, audioLevel);
  9629. }
  9630. }
  9631. };
  9632. },{"../../service/RTC/RTCBrowserType":79}],45:[function(require,module,exports){
  9633. /**
  9634. * Created by hristo on 8/4/14.
  9635. */
  9636. var LocalStats = require("./LocalStatsCollector.js");
  9637. var RTPStats = require("./RTPStatsCollector.js");
  9638. var EventEmitter = require("events");
  9639. var StreamEventTypes = require("../../service/RTC/StreamEventTypes.js");
  9640. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  9641. var eventEmitter = new EventEmitter();
  9642. var localStats = null;
  9643. var rtpStats = null;
  9644. function stopLocal()
  9645. {
  9646. if(localStats)
  9647. {
  9648. localStats.stop();
  9649. localStats = null;
  9650. }
  9651. }
  9652. function stopRemote()
  9653. {
  9654. if(rtpStats)
  9655. {
  9656. rtpStats.stop();
  9657. eventEmitter.emit("statistics.stop");
  9658. rtpStats = null;
  9659. }
  9660. }
  9661. function startRemoteStats (peerconnection) {
  9662. if(rtpStats)
  9663. {
  9664. rtpStats.stop();
  9665. rtpStats = null;
  9666. }
  9667. rtpStats = new RTPStats(peerconnection, 200, 2000, eventEmitter);
  9668. rtpStats.start();
  9669. }
  9670. function onStreamCreated(stream)
  9671. {
  9672. if(stream.getOriginalStream().getAudioTracks().length === 0)
  9673. return;
  9674. localStats = new LocalStats(stream.getOriginalStream(), 100, statistics,
  9675. eventEmitter);
  9676. localStats.start();
  9677. }
  9678. function onDisposeConference(onUnload) {
  9679. stopRemote();
  9680. if(onUnload) {
  9681. stopLocal();
  9682. eventEmitter.removeAllListeners();
  9683. }
  9684. }
  9685. var statistics =
  9686. {
  9687. /**
  9688. * Indicates that this audio level is for local jid.
  9689. * @type {string}
  9690. */
  9691. LOCAL_JID: 'local',
  9692. addAudioLevelListener: function(listener)
  9693. {
  9694. eventEmitter.on("statistics.audioLevel", listener);
  9695. },
  9696. removeAudioLevelListener: function(listener)
  9697. {
  9698. eventEmitter.removeListener("statistics.audioLevel", listener);
  9699. },
  9700. addConnectionStatsListener: function(listener)
  9701. {
  9702. eventEmitter.on("statistics.connectionstats", listener);
  9703. },
  9704. removeConnectionStatsListener: function(listener)
  9705. {
  9706. eventEmitter.removeListener("statistics.connectionstats", listener);
  9707. },
  9708. addRemoteStatsStopListener: function(listener)
  9709. {
  9710. eventEmitter.on("statistics.stop", listener);
  9711. },
  9712. removeRemoteStatsStopListener: function(listener)
  9713. {
  9714. eventEmitter.removeListener("statistics.stop", listener);
  9715. },
  9716. stop: function () {
  9717. stopLocal();
  9718. stopRemote();
  9719. if(eventEmitter)
  9720. {
  9721. eventEmitter.removeAllListeners();
  9722. }
  9723. },
  9724. stopRemoteStatistics: function()
  9725. {
  9726. stopRemote();
  9727. },
  9728. start: function () {
  9729. APP.RTC.addStreamListener(onStreamCreated,
  9730. StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
  9731. APP.xmpp.addListener(XMPPEvents.DISPOSE_CONFERENCE, onDisposeConference);
  9732. APP.xmpp.addListener(XMPPEvents.CALL_INCOMING, function (event) {
  9733. startRemoteStats(event.peerconnection);
  9734. });
  9735. }
  9736. };
  9737. module.exports = statistics;
  9738. },{"../../service/RTC/StreamEventTypes.js":81,"../../service/xmpp/XMPPEvents":86,"./LocalStatsCollector.js":43,"./RTPStatsCollector.js":44,"events":87}],46:[function(require,module,exports){
  9739. var i18n = require("i18next-client");
  9740. var languages = require("../../service/translation/languages");
  9741. var DEFAULT_LANG = languages.EN;
  9742. var initialized = false;
  9743. var waitingForInit = [];
  9744. i18n.addPostProcessor("resolveAppName", function(value, key, options) {
  9745. return value.replace("__app__", interfaceConfig.APP_NAME);
  9746. });
  9747. var defaultOptions = {
  9748. detectLngQS: "lang",
  9749. useCookie: false,
  9750. fallbackLng: DEFAULT_LANG,
  9751. load: "unspecific",
  9752. resGetPath: 'lang/__ns__-__lng__.json',
  9753. ns: {
  9754. namespaces: ['main', 'languages'],
  9755. defaultNs: 'main'
  9756. },
  9757. lngWhitelist : languages.getLanguages(),
  9758. fallbackOnNull: true,
  9759. useDataAttrOptions: true,
  9760. app: interfaceConfig.APP_NAME,
  9761. getAsync: true,
  9762. customLoad: function(lng, ns, options, done) {
  9763. var resPath = "lang/__ns__-__lng__.json";
  9764. if(lng === languages.EN)
  9765. resPath = "lang/__ns__.json";
  9766. var url = i18n.functions.applyReplacement(resPath, { lng: lng, ns: ns });
  9767. initialized = false;
  9768. i18n.functions.ajax({
  9769. url: url,
  9770. success: function(data, status, xhr) {
  9771. i18n.functions.log('loaded: ' + url);
  9772. done(null, data);
  9773. },
  9774. error : function(xhr, status, error) {
  9775. if ((status && status == 200) ||
  9776. (xhr && xhr.status && xhr.status == 200)) {
  9777. // file loaded but invalid json, stop waste time !
  9778. i18n.functions.error('There is a typo in: ' + url);
  9779. } else if ((status && status == 404) ||
  9780. (xhr && xhr.status && xhr.status == 404)) {
  9781. i18n.functions.log('Does not exist: ' + url);
  9782. } else {
  9783. var theStatus = status ? status :
  9784. ((xhr && xhr.status) ? xhr.status : null);
  9785. i18n.functions.log(theStatus + ' when loading ' + url);
  9786. }
  9787. done(error, {});
  9788. },
  9789. dataType: "json",
  9790. async : options.getAsync
  9791. });
  9792. }
  9793. // options for caching
  9794. // useLocalStorage: true,
  9795. // localStorageExpirationTime: 86400000 // in ms, default 1 week
  9796. };
  9797. function initCompleted(t)
  9798. {
  9799. initialized = true;
  9800. $("[data-i18n]").i18n();
  9801. for(var i = 0; i < waitingForInit.length; i++)
  9802. {
  9803. var obj = waitingForInit[i];
  9804. obj.callback(i18n.t(obj.key));
  9805. }
  9806. waitingForInit = [];
  9807. }
  9808. module.exports = {
  9809. init: function (lang) {
  9810. initialized = false;
  9811. var options = defaultOptions;
  9812. if(lang)
  9813. options.lng = lang;
  9814. i18n.init(options, initCompleted);
  9815. },
  9816. translateString: function (key, cb) {
  9817. if(!cb)
  9818. return i18n.t(key);
  9819. if(initialized)
  9820. {
  9821. cb(i18n.t(key));
  9822. }
  9823. else
  9824. {
  9825. waitingForInit.push({"callback": cb, "key": key});
  9826. }
  9827. },
  9828. setLanguage: function (lang) {
  9829. initialized = false;
  9830. if(!lang)
  9831. lang = DEFAULT_LANG;
  9832. i18n.setLng(lang, defaultOptions, initCompleted);
  9833. },
  9834. getCurrentLanguage: function () {
  9835. return i18n.lng();
  9836. },
  9837. translateElement: function (selector) {
  9838. selector.i18n();
  9839. }
  9840. };
  9841. },{"../../service/translation/languages":85,"i18next-client":61}],47:[function(require,module,exports){
  9842. /* jshint -W117 */
  9843. var TraceablePeerConnection = require("./TraceablePeerConnection");
  9844. var SDPDiffer = require("./SDPDiffer");
  9845. var SDPUtil = require("./SDPUtil");
  9846. var SDP = require("./SDP");
  9847. var RTCBrowserType = require("../../service/RTC/RTCBrowserType");
  9848. // Jingle stuff
  9849. function JingleSession(me, sid, connection, service) {
  9850. this.me = me;
  9851. this.sid = sid;
  9852. this.connection = connection;
  9853. this.initiator = null;
  9854. this.responder = null;
  9855. this.isInitiator = null;
  9856. this.peerjid = null;
  9857. this.state = null;
  9858. this.localSDP = null;
  9859. this.remoteSDP = null;
  9860. this.relayedStreams = [];
  9861. this.startTime = null;
  9862. this.stopTime = null;
  9863. this.media_constraints = null;
  9864. this.pc_constraints = null;
  9865. this.ice_config = {};
  9866. this.drip_container = [];
  9867. this.service = service;
  9868. this.usetrickle = true;
  9869. this.usepranswer = false; // early transport warmup -- mind you, this might fail. depends on webrtc issue 1718
  9870. this.usedrip = false; // dripping is sending trickle candidates not one-by-one
  9871. this.hadstuncandidate = false;
  9872. this.hadturncandidate = false;
  9873. this.lasticecandidate = false;
  9874. this.statsinterval = null;
  9875. this.reason = null;
  9876. this.addssrc = [];
  9877. this.removessrc = [];
  9878. this.pendingop = null;
  9879. this.switchstreams = false;
  9880. this.wait = true;
  9881. this.localStreamsSSRC = null;
  9882. /**
  9883. * The indicator which determines whether the (local) video has been muted
  9884. * in response to a user command in contrast to an automatic decision made
  9885. * by the application logic.
  9886. */
  9887. this.videoMuteByUser = false;
  9888. }
  9889. //TODO: this array must be removed when firefox implement multistream support
  9890. JingleSession.notReceivedSSRCs = [];
  9891. JingleSession.prototype.initiate = function (peerjid, isInitiator) {
  9892. var self = this;
  9893. if (this.state !== null) {
  9894. console.error('attempt to initiate on session ' + this.sid +
  9895. 'in state ' + this.state);
  9896. return;
  9897. }
  9898. this.isInitiator = isInitiator;
  9899. this.state = 'pending';
  9900. this.initiator = isInitiator ? this.me : peerjid;
  9901. this.responder = !isInitiator ? this.me : peerjid;
  9902. this.peerjid = peerjid;
  9903. this.hadstuncandidate = false;
  9904. this.hadturncandidate = false;
  9905. this.lasticecandidate = false;
  9906. this.peerconnection
  9907. = new TraceablePeerConnection(
  9908. this.connection.jingle.ice_config,
  9909. this.connection.jingle.pc_constraints );
  9910. this.peerconnection.onicecandidate = function (event) {
  9911. self.sendIceCandidate(event.candidate);
  9912. };
  9913. this.peerconnection.onaddstream = function (event) {
  9914. console.log("REMOTE STREAM ADDED: " + event.stream + " - " + event.stream.id);
  9915. self.remoteStreamAdded(event);
  9916. };
  9917. this.peerconnection.onremovestream = function (event) {
  9918. // Remove the stream from remoteStreams
  9919. // FIXME: remotestreamremoved.jingle not defined anywhere(unused)
  9920. $(document).trigger('remotestreamremoved.jingle', [event, self.sid]);
  9921. };
  9922. this.peerconnection.onsignalingstatechange = function (event) {
  9923. if (!(self && self.peerconnection)) return;
  9924. };
  9925. this.peerconnection.oniceconnectionstatechange = function (event) {
  9926. if (!(self && self.peerconnection)) return;
  9927. switch (self.peerconnection.iceConnectionState) {
  9928. case 'connected':
  9929. this.startTime = new Date();
  9930. break;
  9931. case 'disconnected':
  9932. this.stopTime = new Date();
  9933. break;
  9934. }
  9935. onIceConnectionStateChange(self.sid, self);
  9936. };
  9937. // add any local and relayed stream
  9938. APP.RTC.localStreams.forEach(function(stream) {
  9939. self.peerconnection.addStream(stream.getOriginalStream());
  9940. });
  9941. this.relayedStreams.forEach(function(stream) {
  9942. self.peerconnection.addStream(stream);
  9943. });
  9944. };
  9945. function onIceConnectionStateChange(sid, session) {
  9946. switch (session.peerconnection.iceConnectionState) {
  9947. case 'checking':
  9948. session.timeChecking = (new Date()).getTime();
  9949. session.firstconnect = true;
  9950. break;
  9951. case 'completed': // on caller side
  9952. case 'connected':
  9953. if (session.firstconnect) {
  9954. session.firstconnect = false;
  9955. var metadata = {};
  9956. metadata.setupTime
  9957. = (new Date()).getTime() - session.timeChecking;
  9958. session.peerconnection.getStats(function (res) {
  9959. if(res && res.result) {
  9960. res.result().forEach(function (report) {
  9961. if (report.type == 'googCandidatePair' &&
  9962. report.stat('googActiveConnection') == 'true') {
  9963. metadata.localCandidateType
  9964. = report.stat('googLocalCandidateType');
  9965. metadata.remoteCandidateType
  9966. = report.stat('googRemoteCandidateType');
  9967. // log pair as well so we can get nice pie
  9968. // charts
  9969. metadata.candidatePair
  9970. = report.stat('googLocalCandidateType') +
  9971. ';' +
  9972. report.stat('googRemoteCandidateType');
  9973. if (report.stat('googRemoteAddress').indexOf('[') === 0)
  9974. {
  9975. metadata.ipv6 = true;
  9976. }
  9977. }
  9978. });
  9979. }
  9980. });
  9981. }
  9982. break;
  9983. }
  9984. }
  9985. JingleSession.prototype.accept = function () {
  9986. var self = this;
  9987. this.state = 'active';
  9988. var pranswer = this.peerconnection.localDescription;
  9989. if (!pranswer || pranswer.type != 'pranswer') {
  9990. return;
  9991. }
  9992. console.log('going from pranswer to answer');
  9993. if (this.usetrickle) {
  9994. // remove candidates already sent from session-accept
  9995. var lines = SDPUtil.find_lines(pranswer.sdp, 'a=candidate:');
  9996. for (var i = 0; i < lines.length; i++) {
  9997. pranswer.sdp = pranswer.sdp.replace(lines[i] + '\r\n', '');
  9998. }
  9999. }
  10000. while (SDPUtil.find_line(pranswer.sdp, 'a=inactive')) {
  10001. // FIXME: change any inactive to sendrecv or whatever they were originally
  10002. pranswer.sdp = pranswer.sdp.replace('a=inactive', 'a=sendrecv');
  10003. }
  10004. pranswer = APP.simulcast.reverseTransformLocalDescription(pranswer);
  10005. var prsdp = new SDP(pranswer.sdp);
  10006. var accept = $iq({to: this.peerjid,
  10007. type: 'set'})
  10008. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10009. action: 'session-accept',
  10010. initiator: this.initiator,
  10011. responder: this.responder,
  10012. sid: this.sid });
  10013. prsdp.toJingle(accept, this.initiator == this.me ? 'initiator' : 'responder', this.localStreamsSSRC);
  10014. var sdp = this.peerconnection.localDescription.sdp;
  10015. while (SDPUtil.find_line(sdp, 'a=inactive')) {
  10016. // FIXME: change any inactive to sendrecv or whatever they were originally
  10017. sdp = sdp.replace('a=inactive', 'a=sendrecv');
  10018. }
  10019. var self = this;
  10020. this.peerconnection.setLocalDescription(new RTCSessionDescription({type: 'answer', sdp: sdp}),
  10021. function () {
  10022. //console.log('setLocalDescription success');
  10023. self.setLocalDescription();
  10024. self.connection.sendIQ(accept,
  10025. function () {
  10026. var ack = {};
  10027. ack.source = 'answer';
  10028. $(document).trigger('ack.jingle', [self.sid, ack]);
  10029. },
  10030. function (stanza) {
  10031. var error = ($(stanza).find('error').length) ? {
  10032. code: $(stanza).find('error').attr('code'),
  10033. reason: $(stanza).find('error :first')[0].tagName
  10034. }:{};
  10035. error.source = 'answer';
  10036. JingleSession.onJingleError(self.sid, error);
  10037. },
  10038. 10000);
  10039. },
  10040. function (e) {
  10041. console.error('setLocalDescription failed', e);
  10042. }
  10043. );
  10044. };
  10045. JingleSession.prototype.terminate = function (reason) {
  10046. this.state = 'ended';
  10047. this.reason = reason;
  10048. this.peerconnection.close();
  10049. if (this.statsinterval !== null) {
  10050. window.clearInterval(this.statsinterval);
  10051. this.statsinterval = null;
  10052. }
  10053. };
  10054. JingleSession.prototype.active = function () {
  10055. return this.state == 'active';
  10056. };
  10057. JingleSession.prototype.sendIceCandidate = function (candidate) {
  10058. var self = this;
  10059. if (candidate && !this.lasticecandidate) {
  10060. var ice = SDPUtil.iceparams(this.localSDP.media[candidate.sdpMLineIndex], this.localSDP.session);
  10061. var jcand = SDPUtil.candidateToJingle(candidate.candidate);
  10062. if (!(ice && jcand)) {
  10063. console.error('failed to get ice && jcand');
  10064. return;
  10065. }
  10066. ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
  10067. if (jcand.type === 'srflx') {
  10068. this.hadstuncandidate = true;
  10069. } else if (jcand.type === 'relay') {
  10070. this.hadturncandidate = true;
  10071. }
  10072. if (this.usetrickle) {
  10073. if (this.usedrip) {
  10074. if (this.drip_container.length === 0) {
  10075. // start 20ms callout
  10076. window.setTimeout(function () {
  10077. if (self.drip_container.length === 0) return;
  10078. self.sendIceCandidates(self.drip_container);
  10079. self.drip_container = [];
  10080. }, 20);
  10081. }
  10082. this.drip_container.push(candidate);
  10083. return;
  10084. } else {
  10085. self.sendIceCandidate([candidate]);
  10086. }
  10087. }
  10088. } else {
  10089. //console.log('sendIceCandidate: last candidate.');
  10090. if (!this.usetrickle) {
  10091. //console.log('should send full offer now...');
  10092. var init = $iq({to: this.peerjid,
  10093. type: 'set'})
  10094. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10095. action: this.peerconnection.localDescription.type == 'offer' ? 'session-initiate' : 'session-accept',
  10096. initiator: this.initiator,
  10097. sid: this.sid});
  10098. this.localSDP = new SDP(this.peerconnection.localDescription.sdp);
  10099. var self = this;
  10100. var sendJingle = function (ssrc) {
  10101. if(!ssrc)
  10102. ssrc = {};
  10103. self.localSDP.toJingle(init, self.initiator == self.me ? 'initiator' : 'responder', ssrc);
  10104. self.connection.sendIQ(init,
  10105. function () {
  10106. //console.log('session initiate ack');
  10107. var ack = {};
  10108. ack.source = 'offer';
  10109. $(document).trigger('ack.jingle', [self.sid, ack]);
  10110. },
  10111. function (stanza) {
  10112. self.state = 'error';
  10113. self.peerconnection.close();
  10114. var error = ($(stanza).find('error').length) ? {
  10115. code: $(stanza).find('error').attr('code'),
  10116. reason: $(stanza).find('error :first')[0].tagName,
  10117. }:{};
  10118. error.source = 'offer';
  10119. JingleSession.onJingleError(self.sid, error);
  10120. },
  10121. 10000);
  10122. }
  10123. sendJingle();
  10124. }
  10125. this.lasticecandidate = true;
  10126. console.log('Have we encountered any srflx candidates? ' + this.hadstuncandidate);
  10127. console.log('Have we encountered any relay candidates? ' + this.hadturncandidate);
  10128. if (!(this.hadstuncandidate || this.hadturncandidate) && this.peerconnection.signalingState != 'closed') {
  10129. $(document).trigger('nostuncandidates.jingle', [this.sid]);
  10130. }
  10131. }
  10132. };
  10133. JingleSession.prototype.sendIceCandidates = function (candidates) {
  10134. console.log('sendIceCandidates', candidates);
  10135. var cand = $iq({to: this.peerjid, type: 'set'})
  10136. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10137. action: 'transport-info',
  10138. initiator: this.initiator,
  10139. sid: this.sid});
  10140. for (var mid = 0; mid < this.localSDP.media.length; mid++) {
  10141. var cands = candidates.filter(function (el) { return el.sdpMLineIndex == mid; });
  10142. var mline = SDPUtil.parse_mline(this.localSDP.media[mid].split('\r\n')[0]);
  10143. if (cands.length > 0) {
  10144. var ice = SDPUtil.iceparams(this.localSDP.media[mid], this.localSDP.session);
  10145. ice.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
  10146. cand.c('content', {creator: this.initiator == this.me ? 'initiator' : 'responder',
  10147. name: (cands[0].sdpMid? cands[0].sdpMid : mline.media)
  10148. }).c('transport', ice);
  10149. for (var i = 0; i < cands.length; i++) {
  10150. cand.c('candidate', SDPUtil.candidateToJingle(cands[i].candidate)).up();
  10151. }
  10152. // add fingerprint
  10153. if (SDPUtil.find_line(this.localSDP.media[mid], 'a=fingerprint:', this.localSDP.session)) {
  10154. var tmp = SDPUtil.parse_fingerprint(SDPUtil.find_line(this.localSDP.media[mid], 'a=fingerprint:', this.localSDP.session));
  10155. tmp.required = true;
  10156. cand.c(
  10157. 'fingerprint',
  10158. {xmlns: 'urn:xmpp:jingle:apps:dtls:0'})
  10159. .t(tmp.fingerprint);
  10160. delete tmp.fingerprint;
  10161. cand.attrs(tmp);
  10162. cand.up();
  10163. }
  10164. cand.up(); // transport
  10165. cand.up(); // content
  10166. }
  10167. }
  10168. // might merge last-candidate notification into this, but it is called alot later. See webrtc issue #2340
  10169. //console.log('was this the last candidate', this.lasticecandidate);
  10170. this.connection.sendIQ(cand,
  10171. function () {
  10172. var ack = {};
  10173. ack.source = 'transportinfo';
  10174. $(document).trigger('ack.jingle', [this.sid, ack]);
  10175. },
  10176. function (stanza) {
  10177. var error = ($(stanza).find('error').length) ? {
  10178. code: $(stanza).find('error').attr('code'),
  10179. reason: $(stanza).find('error :first')[0].tagName,
  10180. }:{};
  10181. error.source = 'transportinfo';
  10182. JingleSession.onJingleError(this.sid, error);
  10183. },
  10184. 10000);
  10185. };
  10186. JingleSession.prototype.sendOffer = function () {
  10187. //console.log('sendOffer...');
  10188. var self = this;
  10189. this.peerconnection.createOffer(function (sdp) {
  10190. self.createdOffer(sdp);
  10191. },
  10192. function (e) {
  10193. console.error('createOffer failed', e);
  10194. },
  10195. this.media_constraints
  10196. );
  10197. };
  10198. JingleSession.prototype.createdOffer = function (sdp) {
  10199. //console.log('createdOffer', sdp);
  10200. var self = this;
  10201. this.localSDP = new SDP(sdp.sdp);
  10202. //this.localSDP.mangle();
  10203. var sendJingle = function () {
  10204. var init = $iq({to: this.peerjid,
  10205. type: 'set'})
  10206. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10207. action: 'session-initiate',
  10208. initiator: this.initiator,
  10209. sid: this.sid});
  10210. self.localSDP.toJingle(init, this.initiator == this.me ? 'initiator' : 'responder', this.localStreamsSSRC);
  10211. self.connection.sendIQ(init,
  10212. function () {
  10213. var ack = {};
  10214. ack.source = 'offer';
  10215. $(document).trigger('ack.jingle', [self.sid, ack]);
  10216. },
  10217. function (stanza) {
  10218. self.state = 'error';
  10219. self.peerconnection.close();
  10220. var error = ($(stanza).find('error').length) ? {
  10221. code: $(stanza).find('error').attr('code'),
  10222. reason: $(stanza).find('error :first')[0].tagName,
  10223. }:{};
  10224. error.source = 'offer';
  10225. JingleSession.onJingleError(self.sid, error);
  10226. },
  10227. 10000);
  10228. }
  10229. sdp.sdp = this.localSDP.raw;
  10230. this.peerconnection.setLocalDescription(sdp,
  10231. function () {
  10232. if(self.usetrickle)
  10233. {
  10234. sendJingle();
  10235. }
  10236. self.setLocalDescription();
  10237. //console.log('setLocalDescription success');
  10238. },
  10239. function (e) {
  10240. console.error('setLocalDescription failed', e);
  10241. }
  10242. );
  10243. var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
  10244. for (var i = 0; i < cands.length; i++) {
  10245. var cand = SDPUtil.parse_icecandidate(cands[i]);
  10246. if (cand.type == 'srflx') {
  10247. this.hadstuncandidate = true;
  10248. } else if (cand.type == 'relay') {
  10249. this.hadturncandidate = true;
  10250. }
  10251. }
  10252. };
  10253. JingleSession.prototype.setRemoteDescription = function (elem, desctype) {
  10254. //console.log('setting remote description... ', desctype);
  10255. this.remoteSDP = new SDP('');
  10256. this.remoteSDP.fromJingle(elem);
  10257. if (this.peerconnection.remoteDescription !== null) {
  10258. console.log('setRemoteDescription when remote description is not null, should be pranswer', this.peerconnection.remoteDescription);
  10259. if (this.peerconnection.remoteDescription.type == 'pranswer') {
  10260. var pranswer = new SDP(this.peerconnection.remoteDescription.sdp);
  10261. for (var i = 0; i < pranswer.media.length; i++) {
  10262. // make sure we have ice ufrag and pwd
  10263. if (!SDPUtil.find_line(this.remoteSDP.media[i], 'a=ice-ufrag:', this.remoteSDP.session)) {
  10264. if (SDPUtil.find_line(pranswer.media[i], 'a=ice-ufrag:', pranswer.session)) {
  10265. this.remoteSDP.media[i] += SDPUtil.find_line(pranswer.media[i], 'a=ice-ufrag:', pranswer.session) + '\r\n';
  10266. } else {
  10267. console.warn('no ice ufrag?');
  10268. }
  10269. if (SDPUtil.find_line(pranswer.media[i], 'a=ice-pwd:', pranswer.session)) {
  10270. this.remoteSDP.media[i] += SDPUtil.find_line(pranswer.media[i], 'a=ice-pwd:', pranswer.session) + '\r\n';
  10271. } else {
  10272. console.warn('no ice pwd?');
  10273. }
  10274. }
  10275. // copy over candidates
  10276. var lines = SDPUtil.find_lines(pranswer.media[i], 'a=candidate:');
  10277. for (var j = 0; j < lines.length; j++) {
  10278. this.remoteSDP.media[i] += lines[j] + '\r\n';
  10279. }
  10280. }
  10281. this.remoteSDP.raw = this.remoteSDP.session + this.remoteSDP.media.join('');
  10282. }
  10283. }
  10284. var remotedesc = new RTCSessionDescription({type: desctype, sdp: this.remoteSDP.raw});
  10285. this.peerconnection.setRemoteDescription(remotedesc,
  10286. function () {
  10287. //console.log('setRemoteDescription success');
  10288. },
  10289. function (e) {
  10290. console.error('setRemoteDescription error', e);
  10291. JingleSession.onJingleFatalError(self, e);
  10292. }
  10293. );
  10294. };
  10295. JingleSession.prototype.addIceCandidate = function (elem) {
  10296. var self = this;
  10297. if (this.peerconnection.signalingState == 'closed') {
  10298. return;
  10299. }
  10300. if (!this.peerconnection.remoteDescription && this.peerconnection.signalingState == 'have-local-offer') {
  10301. console.log('trickle ice candidate arriving before session accept...');
  10302. // create a PRANSWER for setRemoteDescription
  10303. if (!this.remoteSDP) {
  10304. var cobbled = 'v=0\r\n' +
  10305. 'o=- ' + '1923518516' + ' 2 IN IP4 0.0.0.0\r\n' +// FIXME
  10306. 's=-\r\n' +
  10307. 't=0 0\r\n';
  10308. // first, take some things from the local description
  10309. for (var i = 0; i < this.localSDP.media.length; i++) {
  10310. cobbled += SDPUtil.find_line(this.localSDP.media[i], 'm=') + '\r\n';
  10311. cobbled += SDPUtil.find_lines(this.localSDP.media[i], 'a=rtpmap:').join('\r\n') + '\r\n';
  10312. if (SDPUtil.find_line(this.localSDP.media[i], 'a=mid:')) {
  10313. cobbled += SDPUtil.find_line(this.localSDP.media[i], 'a=mid:') + '\r\n';
  10314. }
  10315. cobbled += 'a=inactive\r\n';
  10316. }
  10317. this.remoteSDP = new SDP(cobbled);
  10318. }
  10319. // then add things like ice and dtls from remote candidate
  10320. elem.each(function () {
  10321. for (var i = 0; i < self.remoteSDP.media.length; i++) {
  10322. if (SDPUtil.find_line(self.remoteSDP.media[i], 'a=mid:' + $(this).attr('name')) ||
  10323. self.remoteSDP.media[i].indexOf('m=' + $(this).attr('name')) === 0) {
  10324. if (!SDPUtil.find_line(self.remoteSDP.media[i], 'a=ice-ufrag:')) {
  10325. var tmp = $(this).find('transport');
  10326. self.remoteSDP.media[i] += 'a=ice-ufrag:' + tmp.attr('ufrag') + '\r\n';
  10327. self.remoteSDP.media[i] += 'a=ice-pwd:' + tmp.attr('pwd') + '\r\n';
  10328. tmp = $(this).find('transport>fingerprint');
  10329. if (tmp.length) {
  10330. self.remoteSDP.media[i] += 'a=fingerprint:' + tmp.attr('hash') + ' ' + tmp.text() + '\r\n';
  10331. } else {
  10332. console.log('no dtls fingerprint (webrtc issue #1718?)');
  10333. self.remoteSDP.media[i] += 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:BAADBAADBAADBAADBAADBAADBAADBAADBAADBAAD\r\n';
  10334. }
  10335. break;
  10336. }
  10337. }
  10338. }
  10339. });
  10340. this.remoteSDP.raw = this.remoteSDP.session + this.remoteSDP.media.join('');
  10341. // we need a complete SDP with ice-ufrag/ice-pwd in all parts
  10342. // this makes the assumption that the PRANSWER is constructed such that the ice-ufrag is in all mediaparts
  10343. // but it could be in the session part as well. since the code above constructs this sdp this can't happen however
  10344. var iscomplete = this.remoteSDP.media.filter(function (mediapart) {
  10345. return SDPUtil.find_line(mediapart, 'a=ice-ufrag:');
  10346. }).length == this.remoteSDP.media.length;
  10347. if (iscomplete) {
  10348. console.log('setting pranswer');
  10349. try {
  10350. this.peerconnection.setRemoteDescription(new RTCSessionDescription({type: 'pranswer', sdp: this.remoteSDP.raw }),
  10351. function() {
  10352. },
  10353. function(e) {
  10354. console.log('setRemoteDescription pranswer failed', e.toString());
  10355. });
  10356. } catch (e) {
  10357. console.error('setting pranswer failed', e);
  10358. }
  10359. } else {
  10360. //console.log('not yet setting pranswer');
  10361. }
  10362. }
  10363. // operate on each content element
  10364. elem.each(function () {
  10365. // would love to deactivate this, but firefox still requires it
  10366. var idx = -1;
  10367. var i;
  10368. for (i = 0; i < self.remoteSDP.media.length; i++) {
  10369. if (SDPUtil.find_line(self.remoteSDP.media[i], 'a=mid:' + $(this).attr('name')) ||
  10370. self.remoteSDP.media[i].indexOf('m=' + $(this).attr('name')) === 0) {
  10371. idx = i;
  10372. break;
  10373. }
  10374. }
  10375. if (idx == -1) { // fall back to localdescription
  10376. for (i = 0; i < self.localSDP.media.length; i++) {
  10377. if (SDPUtil.find_line(self.localSDP.media[i], 'a=mid:' + $(this).attr('name')) ||
  10378. self.localSDP.media[i].indexOf('m=' + $(this).attr('name')) === 0) {
  10379. idx = i;
  10380. break;
  10381. }
  10382. }
  10383. }
  10384. var name = $(this).attr('name');
  10385. // TODO: check ice-pwd and ice-ufrag?
  10386. $(this).find('transport>candidate').each(function () {
  10387. var line, candidate;
  10388. line = SDPUtil.candidateFromJingle(this);
  10389. candidate = new RTCIceCandidate({sdpMLineIndex: idx,
  10390. sdpMid: name,
  10391. candidate: line});
  10392. try {
  10393. self.peerconnection.addIceCandidate(candidate);
  10394. } catch (e) {
  10395. console.error('addIceCandidate failed', e.toString(), line);
  10396. }
  10397. });
  10398. });
  10399. };
  10400. JingleSession.prototype.sendAnswer = function (provisional) {
  10401. //console.log('createAnswer', provisional);
  10402. var self = this;
  10403. this.peerconnection.createAnswer(
  10404. function (sdp) {
  10405. self.createdAnswer(sdp, provisional);
  10406. },
  10407. function (e) {
  10408. console.error('createAnswer failed', e);
  10409. },
  10410. this.media_constraints
  10411. );
  10412. };
  10413. JingleSession.prototype.createdAnswer = function (sdp, provisional) {
  10414. //console.log('createAnswer callback');
  10415. var self = this;
  10416. this.localSDP = new SDP(sdp.sdp);
  10417. //this.localSDP.mangle();
  10418. this.usepranswer = provisional === true;
  10419. if (this.usetrickle) {
  10420. if (this.usepranswer) {
  10421. sdp.type = 'pranswer';
  10422. for (var i = 0; i < this.localSDP.media.length; i++) {
  10423. this.localSDP.media[i] = this.localSDP.media[i].replace('a=sendrecv\r\n', 'a=inactive\r\n');
  10424. }
  10425. this.localSDP.raw = this.localSDP.session + '\r\n' + this.localSDP.media.join('');
  10426. }
  10427. }
  10428. var self = this;
  10429. var sendJingle = function (ssrcs) {
  10430. var accept = $iq({to: self.peerjid,
  10431. type: 'set'})
  10432. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10433. action: 'session-accept',
  10434. initiator: self.initiator,
  10435. responder: self.responder,
  10436. sid: self.sid });
  10437. var publicLocalDesc = APP.simulcast.reverseTransformLocalDescription(sdp);
  10438. var publicLocalSDP = new SDP(publicLocalDesc.sdp);
  10439. publicLocalSDP.toJingle(accept, self.initiator == self.me ? 'initiator' : 'responder', ssrcs);
  10440. self.connection.sendIQ(accept,
  10441. function () {
  10442. var ack = {};
  10443. ack.source = 'answer';
  10444. $(document).trigger('ack.jingle', [self.sid, ack]);
  10445. },
  10446. function (stanza) {
  10447. var error = ($(stanza).find('error').length) ? {
  10448. code: $(stanza).find('error').attr('code'),
  10449. reason: $(stanza).find('error :first')[0].tagName,
  10450. }:{};
  10451. error.source = 'answer';
  10452. JingleSession.onJingleError(self.sid, error);
  10453. },
  10454. 10000);
  10455. }
  10456. sdp.sdp = this.localSDP.raw;
  10457. this.peerconnection.setLocalDescription(sdp,
  10458. function () {
  10459. //console.log('setLocalDescription success');
  10460. if (self.usetrickle && !self.usepranswer) {
  10461. sendJingle();
  10462. }
  10463. self.setLocalDescription();
  10464. },
  10465. function (e) {
  10466. console.error('setLocalDescription failed', e);
  10467. }
  10468. );
  10469. var cands = SDPUtil.find_lines(this.localSDP.raw, 'a=candidate:');
  10470. for (var j = 0; j < cands.length; j++) {
  10471. var cand = SDPUtil.parse_icecandidate(cands[j]);
  10472. if (cand.type == 'srflx') {
  10473. this.hadstuncandidate = true;
  10474. } else if (cand.type == 'relay') {
  10475. this.hadturncandidate = true;
  10476. }
  10477. }
  10478. };
  10479. JingleSession.prototype.sendTerminate = function (reason, text) {
  10480. var self = this,
  10481. term = $iq({to: this.peerjid,
  10482. type: 'set'})
  10483. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10484. action: 'session-terminate',
  10485. initiator: this.initiator,
  10486. sid: this.sid})
  10487. .c('reason')
  10488. .c(reason || 'success');
  10489. if (text) {
  10490. term.up().c('text').t(text);
  10491. }
  10492. this.connection.sendIQ(term,
  10493. function () {
  10494. self.peerconnection.close();
  10495. self.peerconnection = null;
  10496. self.terminate();
  10497. var ack = {};
  10498. ack.source = 'terminate';
  10499. $(document).trigger('ack.jingle', [self.sid, ack]);
  10500. },
  10501. function (stanza) {
  10502. var error = ($(stanza).find('error').length) ? {
  10503. code: $(stanza).find('error').attr('code'),
  10504. reason: $(stanza).find('error :first')[0].tagName,
  10505. }:{};
  10506. $(document).trigger('ack.jingle', [self.sid, error]);
  10507. },
  10508. 10000);
  10509. if (this.statsinterval !== null) {
  10510. window.clearInterval(this.statsinterval);
  10511. this.statsinterval = null;
  10512. }
  10513. };
  10514. JingleSession.prototype.addSource = function (elem, fromJid) {
  10515. var self = this;
  10516. // FIXME: dirty waiting
  10517. if (!this.peerconnection.localDescription)
  10518. {
  10519. console.warn("addSource - localDescription not ready yet")
  10520. setTimeout(function()
  10521. {
  10522. self.addSource(elem, fromJid);
  10523. },
  10524. 200
  10525. );
  10526. return;
  10527. }
  10528. console.log('addssrc', new Date().getTime());
  10529. console.log('ice', this.peerconnection.iceConnectionState);
  10530. var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
  10531. var mySdp = new SDP(this.peerconnection.localDescription.sdp);
  10532. $(elem).each(function (idx, content) {
  10533. var name = $(content).attr('name');
  10534. var lines = '';
  10535. tmp = $(content).find('ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
  10536. var semantics = this.getAttribute('semantics');
  10537. var ssrcs = $(this).find('>source').map(function () {
  10538. return this.getAttribute('ssrc');
  10539. }).get();
  10540. if (ssrcs.length != 0) {
  10541. lines += 'a=ssrc-group:' + semantics + ' ' + ssrcs.join(' ') + '\r\n';
  10542. }
  10543. });
  10544. tmp = $(content).find('source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]'); // can handle both >source and >description>source
  10545. tmp.each(function () {
  10546. var ssrc = $(this).attr('ssrc');
  10547. if(mySdp.containsSSRC(ssrc)){
  10548. /**
  10549. * This happens when multiple participants change their streams at the same time and
  10550. * ColibriFocus.modifySources have to wait for stable state. In the meantime multiple
  10551. * addssrc are scheduled for update IQ. See
  10552. */
  10553. console.warn("Got add stream request for my own ssrc: "+ssrc);
  10554. return;
  10555. }
  10556. $(this).find('>parameter').each(function () {
  10557. lines += 'a=ssrc:' + ssrc + ' ' + $(this).attr('name');
  10558. if ($(this).attr('value') && $(this).attr('value').length)
  10559. lines += ':' + $(this).attr('value');
  10560. lines += '\r\n';
  10561. });
  10562. });
  10563. sdp.media.forEach(function(media, idx) {
  10564. if (!SDPUtil.find_line(media, 'a=mid:' + name))
  10565. return;
  10566. sdp.media[idx] += lines;
  10567. if (!self.addssrc[idx]) self.addssrc[idx] = '';
  10568. self.addssrc[idx] += lines;
  10569. });
  10570. sdp.raw = sdp.session + sdp.media.join('');
  10571. });
  10572. this.modifySources();
  10573. };
  10574. JingleSession.prototype.removeSource = function (elem, fromJid) {
  10575. var self = this;
  10576. // FIXME: dirty waiting
  10577. if (!this.peerconnection.localDescription)
  10578. {
  10579. console.warn("removeSource - localDescription not ready yet")
  10580. setTimeout(function()
  10581. {
  10582. self.removeSource(elem, fromJid);
  10583. },
  10584. 200
  10585. );
  10586. return;
  10587. }
  10588. console.log('removessrc', new Date().getTime());
  10589. console.log('ice', this.peerconnection.iceConnectionState);
  10590. var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
  10591. var mySdp = new SDP(this.peerconnection.localDescription.sdp);
  10592. $(elem).each(function (idx, content) {
  10593. var name = $(content).attr('name');
  10594. var lines = '';
  10595. tmp = $(content).find('ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
  10596. var semantics = this.getAttribute('semantics');
  10597. var ssrcs = $(this).find('>source').map(function () {
  10598. return this.getAttribute('ssrc');
  10599. }).get();
  10600. if (ssrcs.length != 0) {
  10601. lines += 'a=ssrc-group:' + semantics + ' ' + ssrcs.join(' ') + '\r\n';
  10602. }
  10603. });
  10604. tmp = $(content).find('source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]'); // can handle both >source and >description>source
  10605. tmp.each(function () {
  10606. var ssrc = $(this).attr('ssrc');
  10607. // This should never happen, but can be useful for bug detection
  10608. if(mySdp.containsSSRC(ssrc)){
  10609. console.error("Got remove stream request for my own ssrc: "+ssrc);
  10610. return;
  10611. }
  10612. $(this).find('>parameter').each(function () {
  10613. lines += 'a=ssrc:' + ssrc + ' ' + $(this).attr('name');
  10614. if ($(this).attr('value') && $(this).attr('value').length)
  10615. lines += ':' + $(this).attr('value');
  10616. lines += '\r\n';
  10617. });
  10618. });
  10619. sdp.media.forEach(function(media, idx) {
  10620. if (!SDPUtil.find_line(media, 'a=mid:' + name))
  10621. return;
  10622. sdp.media[idx] += lines;
  10623. if (!self.removessrc[idx]) self.removessrc[idx] = '';
  10624. self.removessrc[idx] += lines;
  10625. });
  10626. sdp.raw = sdp.session + sdp.media.join('');
  10627. });
  10628. this.modifySources();
  10629. };
  10630. JingleSession.prototype.modifySources = function (successCallback) {
  10631. var self = this;
  10632. if (this.peerconnection.signalingState == 'closed') return;
  10633. if (!(this.addssrc.length || this.removessrc.length || this.pendingop !== null || this.switchstreams)){
  10634. // There is nothing to do since scheduled job might have been executed by another succeeding call
  10635. this.setLocalDescription();
  10636. if(successCallback){
  10637. successCallback();
  10638. }
  10639. return;
  10640. }
  10641. // FIXME: this is a big hack
  10642. // https://code.google.com/p/webrtc/issues/detail?id=2688
  10643. // ^ has been fixed.
  10644. if (!(this.peerconnection.signalingState == 'stable' && this.peerconnection.iceConnectionState == 'connected')) {
  10645. console.warn('modifySources not yet', this.peerconnection.signalingState, this.peerconnection.iceConnectionState);
  10646. this.wait = true;
  10647. window.setTimeout(function() { self.modifySources(successCallback); }, 250);
  10648. return;
  10649. }
  10650. if (this.wait) {
  10651. window.setTimeout(function() { self.modifySources(successCallback); }, 2500);
  10652. this.wait = false;
  10653. return;
  10654. }
  10655. // Reset switch streams flag
  10656. this.switchstreams = false;
  10657. var sdp = new SDP(this.peerconnection.remoteDescription.sdp);
  10658. // add sources
  10659. this.addssrc.forEach(function(lines, idx) {
  10660. sdp.media[idx] += lines;
  10661. });
  10662. this.addssrc = [];
  10663. // remove sources
  10664. this.removessrc.forEach(function(lines, idx) {
  10665. lines = lines.split('\r\n');
  10666. lines.pop(); // remove empty last element;
  10667. lines.forEach(function(line) {
  10668. sdp.media[idx] = sdp.media[idx].replace(line + '\r\n', '');
  10669. });
  10670. });
  10671. this.removessrc = [];
  10672. // FIXME:
  10673. // this was a hack for the situation when only one peer exists
  10674. // in the conference.
  10675. // check if still required and remove
  10676. if (sdp.media[0])
  10677. sdp.media[0] = sdp.media[0].replace('a=recvonly', 'a=sendrecv');
  10678. if (sdp.media[1])
  10679. sdp.media[1] = sdp.media[1].replace('a=recvonly', 'a=sendrecv');
  10680. sdp.raw = sdp.session + sdp.media.join('');
  10681. this.peerconnection.setRemoteDescription(new RTCSessionDescription({type: 'offer', sdp: sdp.raw}),
  10682. function() {
  10683. if(self.signalingState == 'closed') {
  10684. console.error("createAnswer attempt on closed state");
  10685. return;
  10686. }
  10687. self.peerconnection.createAnswer(
  10688. function(modifiedAnswer) {
  10689. // change video direction, see https://github.com/jitsi/jitmeet/issues/41
  10690. if (self.pendingop !== null) {
  10691. var sdp = new SDP(modifiedAnswer.sdp);
  10692. if (sdp.media.length > 1) {
  10693. switch(self.pendingop) {
  10694. case 'mute':
  10695. sdp.media[1] = sdp.media[1].replace('a=sendrecv', 'a=recvonly');
  10696. break;
  10697. case 'unmute':
  10698. sdp.media[1] = sdp.media[1].replace('a=recvonly', 'a=sendrecv');
  10699. break;
  10700. }
  10701. sdp.raw = sdp.session + sdp.media.join('');
  10702. modifiedAnswer.sdp = sdp.raw;
  10703. }
  10704. self.pendingop = null;
  10705. }
  10706. // FIXME: pushing down an answer while ice connection state
  10707. // is still checking is bad...
  10708. //console.log(self.peerconnection.iceConnectionState);
  10709. // trying to work around another chrome bug
  10710. //modifiedAnswer.sdp = modifiedAnswer.sdp.replace(/a=setup:active/g, 'a=setup:actpass');
  10711. self.peerconnection.setLocalDescription(modifiedAnswer,
  10712. function() {
  10713. //console.log('modified setLocalDescription ok');
  10714. self.setLocalDescription();
  10715. if(successCallback){
  10716. successCallback();
  10717. }
  10718. },
  10719. function(error) {
  10720. console.error('modified setLocalDescription failed', error);
  10721. }
  10722. );
  10723. },
  10724. function(error) {
  10725. console.error('modified answer failed', error);
  10726. }
  10727. );
  10728. },
  10729. function(error) {
  10730. console.error('modify failed', error);
  10731. }
  10732. );
  10733. };
  10734. /**
  10735. * Switches video streams.
  10736. * @param new_stream new stream that will be used as video of this session.
  10737. * @param oldStream old video stream of this session.
  10738. * @param success_callback callback executed after successful stream switch.
  10739. */
  10740. JingleSession.prototype.switchStreams = function (new_stream, oldStream, success_callback) {
  10741. var self = this;
  10742. // Remember SDP to figure out added/removed SSRCs
  10743. var oldSdp = null;
  10744. if(self.peerconnection) {
  10745. if(self.peerconnection.localDescription) {
  10746. oldSdp = new SDP(self.peerconnection.localDescription.sdp);
  10747. }
  10748. self.peerconnection.removeStream(oldStream, true);
  10749. self.peerconnection.addStream(new_stream);
  10750. }
  10751. APP.RTC.switchVideoStreams(new_stream, oldStream);
  10752. // Conference is not active
  10753. if(!oldSdp || !self.peerconnection) {
  10754. success_callback();
  10755. return;
  10756. }
  10757. self.switchstreams = true;
  10758. self.modifySources(function() {
  10759. console.log('modify sources done');
  10760. success_callback();
  10761. var newSdp = new SDP(self.peerconnection.localDescription.sdp);
  10762. console.log("SDPs", oldSdp, newSdp);
  10763. self.notifyMySSRCUpdate(oldSdp, newSdp);
  10764. });
  10765. };
  10766. /**
  10767. * Figures out added/removed ssrcs and send update IQs.
  10768. * @param old_sdp SDP object for old description.
  10769. * @param new_sdp SDP object for new description.
  10770. */
  10771. JingleSession.prototype.notifyMySSRCUpdate = function (old_sdp, new_sdp) {
  10772. if (!(this.peerconnection.signalingState == 'stable' &&
  10773. this.peerconnection.iceConnectionState == 'connected')){
  10774. console.log("Too early to send updates");
  10775. return;
  10776. }
  10777. // send source-remove IQ.
  10778. sdpDiffer = new SDPDiffer(new_sdp, old_sdp);
  10779. var remove = $iq({to: this.peerjid, type: 'set'})
  10780. .c('jingle', {
  10781. xmlns: 'urn:xmpp:jingle:1',
  10782. action: 'source-remove',
  10783. initiator: this.initiator,
  10784. sid: this.sid
  10785. }
  10786. );
  10787. var removed = sdpDiffer.toJingle(remove);
  10788. if (removed) {
  10789. this.connection.sendIQ(remove,
  10790. function (res) {
  10791. console.info('got remove result', res);
  10792. },
  10793. function (err) {
  10794. console.error('got remove error', err);
  10795. }
  10796. );
  10797. } else {
  10798. console.log('removal not necessary');
  10799. }
  10800. // send source-add IQ.
  10801. var sdpDiffer = new SDPDiffer(old_sdp, new_sdp);
  10802. var add = $iq({to: this.peerjid, type: 'set'})
  10803. .c('jingle', {
  10804. xmlns: 'urn:xmpp:jingle:1',
  10805. action: 'source-add',
  10806. initiator: this.initiator,
  10807. sid: this.sid
  10808. }
  10809. );
  10810. var added = sdpDiffer.toJingle(add);
  10811. if (added) {
  10812. this.connection.sendIQ(add,
  10813. function (res) {
  10814. console.info('got add result', res);
  10815. },
  10816. function (err) {
  10817. console.error('got add error', err);
  10818. }
  10819. );
  10820. } else {
  10821. console.log('addition not necessary');
  10822. }
  10823. };
  10824. /**
  10825. * Determines whether the (local) video is mute i.e. all video tracks are
  10826. * disabled.
  10827. *
  10828. * @return <tt>true</tt> if the (local) video is mute i.e. all video tracks are
  10829. * disabled; otherwise, <tt>false</tt>
  10830. */
  10831. JingleSession.prototype.isVideoMute = function () {
  10832. var tracks = APP.RTC.localVideo.getVideoTracks();
  10833. var mute = true;
  10834. for (var i = 0; i < tracks.length; ++i) {
  10835. if (tracks[i].enabled) {
  10836. mute = false;
  10837. break;
  10838. }
  10839. }
  10840. return mute;
  10841. };
  10842. /**
  10843. * Mutes/unmutes the (local) video i.e. enables/disables all video tracks.
  10844. *
  10845. * @param mute <tt>true</tt> to mute the (local) video i.e. to disable all video
  10846. * tracks; otherwise, <tt>false</tt>
  10847. * @param callback a function to be invoked with <tt>mute</tt> after all video
  10848. * tracks have been enabled/disabled. The function may, optionally, return
  10849. * another function which is to be invoked after the whole mute/unmute operation
  10850. * has completed successfully.
  10851. * @param options an object which specifies optional arguments such as the
  10852. * <tt>boolean</tt> key <tt>byUser</tt> with default value <tt>true</tt> which
  10853. * specifies whether the method was initiated in response to a user command (in
  10854. * contrast to an automatic decision made by the application logic)
  10855. */
  10856. JingleSession.prototype.setVideoMute = function (mute, callback, options) {
  10857. var byUser;
  10858. if (options) {
  10859. byUser = options.byUser;
  10860. if (typeof byUser === 'undefined') {
  10861. byUser = true;
  10862. }
  10863. } else {
  10864. byUser = true;
  10865. }
  10866. // The user's command to mute the (local) video takes precedence over any
  10867. // automatic decision made by the application logic.
  10868. if (byUser) {
  10869. this.videoMuteByUser = mute;
  10870. } else if (this.videoMuteByUser) {
  10871. return;
  10872. }
  10873. var self = this;
  10874. var localCallback = function (mute) {
  10875. self.connection.emuc.addVideoInfoToPresence(mute);
  10876. self.connection.emuc.sendPresence();
  10877. return callback(mute)
  10878. };
  10879. if (mute == APP.RTC.localVideo.isMuted())
  10880. {
  10881. // Even if no change occurs, the specified callback is to be executed.
  10882. // The specified callback may, optionally, return a successCallback
  10883. // which is to be executed as well.
  10884. var successCallback = localCallback(mute);
  10885. if (successCallback) {
  10886. successCallback();
  10887. }
  10888. } else {
  10889. APP.RTC.localVideo.setMute(!mute);
  10890. this.hardMuteVideo(mute);
  10891. this.modifySources(localCallback(mute));
  10892. }
  10893. };
  10894. // SDP-based mute by going recvonly/sendrecv
  10895. // FIXME: should probably black out the screen as well
  10896. JingleSession.prototype.toggleVideoMute = function (callback) {
  10897. this.service.setVideoMute(APP.RTC.localVideo.isMuted(), callback);
  10898. };
  10899. JingleSession.prototype.hardMuteVideo = function (muted) {
  10900. this.pendingop = muted ? 'mute' : 'unmute';
  10901. };
  10902. JingleSession.prototype.sendMute = function (muted, content) {
  10903. var info = $iq({to: this.peerjid,
  10904. type: 'set'})
  10905. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10906. action: 'session-info',
  10907. initiator: this.initiator,
  10908. sid: this.sid });
  10909. info.c(muted ? 'mute' : 'unmute', {xmlns: 'urn:xmpp:jingle:apps:rtp:info:1'});
  10910. info.attrs({'creator': this.me == this.initiator ? 'creator' : 'responder'});
  10911. if (content) {
  10912. info.attrs({'name': content});
  10913. }
  10914. this.connection.send(info);
  10915. };
  10916. JingleSession.prototype.sendRinging = function () {
  10917. var info = $iq({to: this.peerjid,
  10918. type: 'set'})
  10919. .c('jingle', {xmlns: 'urn:xmpp:jingle:1',
  10920. action: 'session-info',
  10921. initiator: this.initiator,
  10922. sid: this.sid });
  10923. info.c('ringing', {xmlns: 'urn:xmpp:jingle:apps:rtp:info:1'});
  10924. this.connection.send(info);
  10925. };
  10926. JingleSession.prototype.getStats = function (interval) {
  10927. var self = this;
  10928. var recv = {audio: 0, video: 0};
  10929. var lost = {audio: 0, video: 0};
  10930. var lastrecv = {audio: 0, video: 0};
  10931. var lastlost = {audio: 0, video: 0};
  10932. var loss = {audio: 0, video: 0};
  10933. var delta = {audio: 0, video: 0};
  10934. this.statsinterval = window.setInterval(function () {
  10935. if (self && self.peerconnection && self.peerconnection.getStats) {
  10936. self.peerconnection.getStats(function (stats) {
  10937. var results = stats.result();
  10938. // TODO: there are so much statistics you can get from this..
  10939. for (var i = 0; i < results.length; ++i) {
  10940. if (results[i].type == 'ssrc') {
  10941. var packetsrecv = results[i].stat('packetsReceived');
  10942. var packetslost = results[i].stat('packetsLost');
  10943. if (packetsrecv && packetslost) {
  10944. packetsrecv = parseInt(packetsrecv, 10);
  10945. packetslost = parseInt(packetslost, 10);
  10946. if (results[i].stat('googFrameRateReceived')) {
  10947. lastlost.video = lost.video;
  10948. lastrecv.video = recv.video;
  10949. recv.video = packetsrecv;
  10950. lost.video = packetslost;
  10951. } else {
  10952. lastlost.audio = lost.audio;
  10953. lastrecv.audio = recv.audio;
  10954. recv.audio = packetsrecv;
  10955. lost.audio = packetslost;
  10956. }
  10957. }
  10958. }
  10959. }
  10960. delta.audio = recv.audio - lastrecv.audio;
  10961. delta.video = recv.video - lastrecv.video;
  10962. loss.audio = (delta.audio > 0) ? Math.ceil(100 * (lost.audio - lastlost.audio) / delta.audio) : 0;
  10963. loss.video = (delta.video > 0) ? Math.ceil(100 * (lost.video - lastlost.video) / delta.video) : 0;
  10964. $(document).trigger('packetloss.jingle', [self.sid, loss]);
  10965. });
  10966. }
  10967. }, interval || 3000);
  10968. return this.statsinterval;
  10969. };
  10970. JingleSession.onJingleError = function (session, error)
  10971. {
  10972. console.error("Jingle error", error);
  10973. }
  10974. JingleSession.onJingleFatalError = function (session, error)
  10975. {
  10976. this.service.sessionTerminated = true;
  10977. this.connection.emuc.doLeave();
  10978. APP.UI.messageHandler.showError( "Sorry",
  10979. "Internal application error[setRemoteDescription]");
  10980. }
  10981. JingleSession.prototype.setLocalDescription = function () {
  10982. // put our ssrcs into presence so other clients can identify our stream
  10983. var newssrcs = [];
  10984. var media = APP.simulcast.parseMedia(this.peerconnection.localDescription);
  10985. media.forEach(function (media) {
  10986. if(Object.keys(media.sources).length > 0) {
  10987. // TODO(gp) maybe exclude FID streams?
  10988. Object.keys(media.sources).forEach(function (ssrc) {
  10989. newssrcs.push({
  10990. 'ssrc': ssrc,
  10991. 'type': media.type,
  10992. 'direction': media.direction
  10993. });
  10994. });
  10995. }
  10996. else if(this.localStreamsSSRC && this.localStreamsSSRC[media.type])
  10997. {
  10998. newssrcs.push({
  10999. 'ssrc': this.localStreamsSSRC[media.type],
  11000. 'type': media.type,
  11001. 'direction': media.direction
  11002. });
  11003. }
  11004. });
  11005. console.log('new ssrcs', newssrcs);
  11006. // Have to clear presence map to get rid of removed streams
  11007. this.connection.emuc.clearPresenceMedia();
  11008. if (newssrcs.length > 0) {
  11009. for (var i = 1; i <= newssrcs.length; i ++) {
  11010. // Change video type to screen
  11011. if (newssrcs[i-1].type === 'video' && APP.desktopsharing.isUsingScreenStream()) {
  11012. newssrcs[i-1].type = 'screen';
  11013. }
  11014. this.connection.emuc.addMediaToPresence(i,
  11015. newssrcs[i-1].type, newssrcs[i-1].ssrc, newssrcs[i-1].direction);
  11016. }
  11017. this.connection.emuc.sendPresence();
  11018. }
  11019. }
  11020. // an attempt to work around https://github.com/jitsi/jitmeet/issues/32
  11021. function sendKeyframe(pc) {
  11022. console.log('sendkeyframe', pc.iceConnectionState);
  11023. if (pc.iceConnectionState !== 'connected') return; // safe...
  11024. pc.setRemoteDescription(
  11025. pc.remoteDescription,
  11026. function () {
  11027. pc.createAnswer(
  11028. function (modifiedAnswer) {
  11029. pc.setLocalDescription(
  11030. modifiedAnswer,
  11031. function () {
  11032. // noop
  11033. },
  11034. function (error) {
  11035. console.log('triggerKeyframe setLocalDescription failed', error);
  11036. APP.UI.messageHandler.showError();
  11037. }
  11038. );
  11039. },
  11040. function (error) {
  11041. console.log('triggerKeyframe createAnswer failed', error);
  11042. APP.UI.messageHandler.showError();
  11043. }
  11044. );
  11045. },
  11046. function (error) {
  11047. console.log('triggerKeyframe setRemoteDescription failed', error);
  11048. APP.UI.messageHandler.showError();
  11049. }
  11050. );
  11051. }
  11052. JingleSession.prototype.remoteStreamAdded = function (data) {
  11053. var self = this;
  11054. var thessrc;
  11055. var ssrc2jid = this.connection.emuc.ssrc2jid;
  11056. // look up an associated JID for a stream id
  11057. if (data.stream.id && data.stream.id.indexOf('mixedmslabel') === -1) {
  11058. // look only at a=ssrc: and _not_ at a=ssrc-group: lines
  11059. var ssrclines
  11060. = SDPUtil.find_lines(this.peerconnection.remoteDescription.sdp, 'a=ssrc:');
  11061. ssrclines = ssrclines.filter(function (line) {
  11062. // NOTE(gp) previously we filtered on the mslabel, but that property
  11063. // is not always present.
  11064. // return line.indexOf('mslabel:' + data.stream.label) !== -1;
  11065. return ((line.indexOf('msid:' + data.stream.id) !== -1));
  11066. });
  11067. if (ssrclines.length) {
  11068. thessrc = ssrclines[0].substring(7).split(' ')[0];
  11069. // We signal our streams (through Jingle to the focus) before we set
  11070. // our presence (through which peers associate remote streams to
  11071. // jids). So, it might arrive that a remote stream is added but
  11072. // ssrc2jid is not yet updated and thus data.peerjid cannot be
  11073. // successfully set. Here we wait for up to a second for the
  11074. // presence to arrive.
  11075. if (!ssrc2jid[thessrc]) {
  11076. // TODO(gp) limit wait duration to 1 sec.
  11077. setTimeout(function(d) {
  11078. return function() {
  11079. self.remoteStreamAdded(d);
  11080. }
  11081. }(data), 250);
  11082. return;
  11083. }
  11084. // ok to overwrite the one from focus? might save work in colibri.js
  11085. console.log('associated jid', ssrc2jid[thessrc], data.peerjid);
  11086. if (ssrc2jid[thessrc]) {
  11087. data.peerjid = ssrc2jid[thessrc];
  11088. }
  11089. }
  11090. }
  11091. //TODO: this code should be removed when firefox implement multistream support
  11092. if(APP.RTC.getBrowserType() == RTCBrowserType.RTC_BROWSER_FIREFOX)
  11093. {
  11094. if((JingleSession.notReceivedSSRCs.length == 0) ||
  11095. !ssrc2jid[JingleSession.notReceivedSSRCs[JingleSession.notReceivedSSRCs.length - 1]])
  11096. {
  11097. // TODO(gp) limit wait duration to 1 sec.
  11098. setTimeout(function(d) {
  11099. return function() {
  11100. self.remoteStreamAdded(d);
  11101. }
  11102. }(data), 250);
  11103. return;
  11104. }
  11105. thessrc = JingleSession.notReceivedSSRCs.pop();
  11106. if (ssrc2jid[thessrc]) {
  11107. data.peerjid = ssrc2jid[thessrc];
  11108. }
  11109. }
  11110. APP.RTC.createRemoteStream(data, this.sid, thessrc);
  11111. var isVideo = data.stream.getVideoTracks().length > 0;
  11112. // an attempt to work around https://github.com/jitsi/jitmeet/issues/32
  11113. if (isVideo &&
  11114. data.peerjid && this.peerjid === data.peerjid &&
  11115. data.stream.getVideoTracks().length === 0 &&
  11116. APP.RTC.localVideo.getTracks().length > 0) {
  11117. window.setTimeout(function () {
  11118. sendKeyframe(self.peerconnection);
  11119. }, 3000);
  11120. }
  11121. }
  11122. module.exports = JingleSession;
  11123. },{"../../service/RTC/RTCBrowserType":79,"./SDP":48,"./SDPDiffer":49,"./SDPUtil":50,"./TraceablePeerConnection":51}],48:[function(require,module,exports){
  11124. /* jshint -W117 */
  11125. var SDPUtil = require("./SDPUtil");
  11126. // SDP STUFF
  11127. function SDP(sdp) {
  11128. this.media = sdp.split('\r\nm=');
  11129. for (var i = 1; i < this.media.length; i++) {
  11130. this.media[i] = 'm=' + this.media[i];
  11131. if (i != this.media.length - 1) {
  11132. this.media[i] += '\r\n';
  11133. }
  11134. }
  11135. this.session = this.media.shift() + '\r\n';
  11136. this.raw = this.session + this.media.join('');
  11137. }
  11138. /**
  11139. * Returns map of MediaChannel mapped per channel idx.
  11140. */
  11141. SDP.prototype.getMediaSsrcMap = function() {
  11142. var self = this;
  11143. var media_ssrcs = {};
  11144. var tmp;
  11145. for (var mediaindex = 0; mediaindex < self.media.length; mediaindex++) {
  11146. tmp = SDPUtil.find_lines(self.media[mediaindex], 'a=ssrc:');
  11147. var mid = SDPUtil.parse_mid(SDPUtil.find_line(self.media[mediaindex], 'a=mid:'));
  11148. var media = {
  11149. mediaindex: mediaindex,
  11150. mid: mid,
  11151. ssrcs: {},
  11152. ssrcGroups: []
  11153. };
  11154. media_ssrcs[mediaindex] = media;
  11155. tmp.forEach(function (line) {
  11156. var linessrc = line.substring(7).split(' ')[0];
  11157. // allocate new ChannelSsrc
  11158. if(!media.ssrcs[linessrc]) {
  11159. media.ssrcs[linessrc] = {
  11160. ssrc: linessrc,
  11161. lines: []
  11162. };
  11163. }
  11164. media.ssrcs[linessrc].lines.push(line);
  11165. });
  11166. tmp = SDPUtil.find_lines(self.media[mediaindex], 'a=ssrc-group:');
  11167. tmp.forEach(function(line){
  11168. var semantics = line.substr(0, idx).substr(13);
  11169. var ssrcs = line.substr(14 + semantics.length).split(' ');
  11170. if (ssrcs.length != 0) {
  11171. media.ssrcGroups.push({
  11172. semantics: semantics,
  11173. ssrcs: ssrcs
  11174. });
  11175. }
  11176. });
  11177. }
  11178. return media_ssrcs;
  11179. };
  11180. /**
  11181. * Returns <tt>true</tt> if this SDP contains given SSRC.
  11182. * @param ssrc the ssrc to check.
  11183. * @returns {boolean} <tt>true</tt> if this SDP contains given SSRC.
  11184. */
  11185. SDP.prototype.containsSSRC = function(ssrc) {
  11186. var medias = this.getMediaSsrcMap();
  11187. var contains = false;
  11188. Object.keys(medias).forEach(function(mediaindex){
  11189. var media = medias[mediaindex];
  11190. //console.log("Check", channel, ssrc);
  11191. if(Object.keys(media.ssrcs).indexOf(ssrc) != -1){
  11192. contains = true;
  11193. }
  11194. });
  11195. return contains;
  11196. };
  11197. // remove iSAC and CN from SDP
  11198. SDP.prototype.mangle = function () {
  11199. var i, j, mline, lines, rtpmap, newdesc;
  11200. for (i = 0; i < this.media.length; i++) {
  11201. lines = this.media[i].split('\r\n');
  11202. lines.pop(); // remove empty last element
  11203. mline = SDPUtil.parse_mline(lines.shift());
  11204. if (mline.media != 'audio')
  11205. continue;
  11206. newdesc = '';
  11207. mline.fmt.length = 0;
  11208. for (j = 0; j < lines.length; j++) {
  11209. if (lines[j].substr(0, 9) == 'a=rtpmap:') {
  11210. rtpmap = SDPUtil.parse_rtpmap(lines[j]);
  11211. if (rtpmap.name == 'CN' || rtpmap.name == 'ISAC')
  11212. continue;
  11213. mline.fmt.push(rtpmap.id);
  11214. newdesc += lines[j] + '\r\n';
  11215. } else {
  11216. newdesc += lines[j] + '\r\n';
  11217. }
  11218. }
  11219. this.media[i] = SDPUtil.build_mline(mline) + '\r\n';
  11220. this.media[i] += newdesc;
  11221. }
  11222. this.raw = this.session + this.media.join('');
  11223. };
  11224. // remove lines matching prefix from session section
  11225. SDP.prototype.removeSessionLines = function(prefix) {
  11226. var self = this;
  11227. var lines = SDPUtil.find_lines(this.session, prefix);
  11228. lines.forEach(function(line) {
  11229. self.session = self.session.replace(line + '\r\n', '');
  11230. });
  11231. this.raw = this.session + this.media.join('');
  11232. return lines;
  11233. }
  11234. // remove lines matching prefix from a media section specified by mediaindex
  11235. // TODO: non-numeric mediaindex could match mid
  11236. SDP.prototype.removeMediaLines = function(mediaindex, prefix) {
  11237. var self = this;
  11238. var lines = SDPUtil.find_lines(this.media[mediaindex], prefix);
  11239. lines.forEach(function(line) {
  11240. self.media[mediaindex] = self.media[mediaindex].replace(line + '\r\n', '');
  11241. });
  11242. this.raw = this.session + this.media.join('');
  11243. return lines;
  11244. }
  11245. // add content's to a jingle element
  11246. SDP.prototype.toJingle = function (elem, thecreator, ssrcs) {
  11247. // console.log("SSRC" + ssrcs["audio"] + " - " + ssrcs["video"]);
  11248. var i, j, k, mline, ssrc, rtpmap, tmp, line, lines;
  11249. var self = this;
  11250. // new bundle plan
  11251. if (SDPUtil.find_line(this.session, 'a=group:')) {
  11252. lines = SDPUtil.find_lines(this.session, 'a=group:');
  11253. for (i = 0; i < lines.length; i++) {
  11254. tmp = lines[i].split(' ');
  11255. var semantics = tmp.shift().substr(8);
  11256. elem.c('group', {xmlns: 'urn:xmpp:jingle:apps:grouping:0', semantics:semantics});
  11257. for (j = 0; j < tmp.length; j++) {
  11258. elem.c('content', {name: tmp[j]}).up();
  11259. }
  11260. elem.up();
  11261. }
  11262. }
  11263. for (i = 0; i < this.media.length; i++) {
  11264. mline = SDPUtil.parse_mline(this.media[i].split('\r\n')[0]);
  11265. if (!(mline.media === 'audio' ||
  11266. mline.media === 'video' ||
  11267. mline.media === 'application'))
  11268. {
  11269. continue;
  11270. }
  11271. if (SDPUtil.find_line(this.media[i], 'a=ssrc:')) {
  11272. ssrc = SDPUtil.find_line(this.media[i], 'a=ssrc:').substring(7).split(' ')[0]; // take the first
  11273. } else {
  11274. if(ssrcs && ssrcs[mline.media])
  11275. {
  11276. ssrc = ssrcs[mline.media];
  11277. }
  11278. else
  11279. ssrc = false;
  11280. }
  11281. elem.c('content', {creator: thecreator, name: mline.media});
  11282. if (SDPUtil.find_line(this.media[i], 'a=mid:')) {
  11283. // prefer identifier from a=mid if present
  11284. var mid = SDPUtil.parse_mid(SDPUtil.find_line(this.media[i], 'a=mid:'));
  11285. elem.attrs({ name: mid });
  11286. }
  11287. if (SDPUtil.find_line(this.media[i], 'a=rtpmap:').length)
  11288. {
  11289. elem.c('description',
  11290. {xmlns: 'urn:xmpp:jingle:apps:rtp:1',
  11291. media: mline.media });
  11292. if (ssrc) {
  11293. elem.attrs({ssrc: ssrc});
  11294. }
  11295. for (j = 0; j < mline.fmt.length; j++) {
  11296. rtpmap = SDPUtil.find_line(this.media[i], 'a=rtpmap:' + mline.fmt[j]);
  11297. elem.c('payload-type', SDPUtil.parse_rtpmap(rtpmap));
  11298. // put any 'a=fmtp:' + mline.fmt[j] lines into <param name=foo value=bar/>
  11299. if (SDPUtil.find_line(this.media[i], 'a=fmtp:' + mline.fmt[j])) {
  11300. tmp = SDPUtil.parse_fmtp(SDPUtil.find_line(this.media[i], 'a=fmtp:' + mline.fmt[j]));
  11301. for (k = 0; k < tmp.length; k++) {
  11302. elem.c('parameter', tmp[k]).up();
  11303. }
  11304. }
  11305. this.RtcpFbToJingle(i, elem, mline.fmt[j]); // XEP-0293 -- map a=rtcp-fb
  11306. elem.up();
  11307. }
  11308. if (SDPUtil.find_line(this.media[i], 'a=crypto:', this.session)) {
  11309. elem.c('encryption', {required: 1});
  11310. var crypto = SDPUtil.find_lines(this.media[i], 'a=crypto:', this.session);
  11311. crypto.forEach(function(line) {
  11312. elem.c('crypto', SDPUtil.parse_crypto(line)).up();
  11313. });
  11314. elem.up(); // end of encryption
  11315. }
  11316. if (ssrc) {
  11317. // new style mapping
  11318. elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  11319. // FIXME: group by ssrc and support multiple different ssrcs
  11320. var ssrclines = SDPUtil.find_lines(this.media[i], 'a=ssrc:');
  11321. if(ssrclines.length > 0) {
  11322. ssrclines.forEach(function (line) {
  11323. idx = line.indexOf(' ');
  11324. var linessrc = line.substr(0, idx).substr(7);
  11325. if (linessrc != ssrc) {
  11326. elem.up();
  11327. ssrc = linessrc;
  11328. elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  11329. }
  11330. var kv = line.substr(idx + 1);
  11331. elem.c('parameter');
  11332. if (kv.indexOf(':') == -1) {
  11333. elem.attrs({ name: kv });
  11334. } else {
  11335. elem.attrs({ name: kv.split(':', 2)[0] });
  11336. elem.attrs({ value: kv.split(':', 2)[1] });
  11337. }
  11338. elem.up();
  11339. });
  11340. elem.up();
  11341. }
  11342. else
  11343. {
  11344. elem.up();
  11345. elem.c('source', { ssrc: ssrc, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  11346. elem.c('parameter');
  11347. elem.attrs({name: "cname", value:Math.random().toString(36).substring(7)});
  11348. elem.up();
  11349. var msid = null;
  11350. if(mline.media == "audio")
  11351. {
  11352. msid = APP.RTC.localAudio.getId();
  11353. }
  11354. else
  11355. {
  11356. msid = APP.RTC.localVideo.getId();
  11357. }
  11358. if(msid != null)
  11359. {
  11360. msid = msid.replace(/[\{,\}]/g,"");
  11361. elem.c('parameter');
  11362. elem.attrs({name: "msid", value:msid});
  11363. elem.up();
  11364. elem.c('parameter');
  11365. elem.attrs({name: "mslabel", value:msid});
  11366. elem.up();
  11367. elem.c('parameter');
  11368. elem.attrs({name: "label", value:msid});
  11369. elem.up();
  11370. elem.up();
  11371. }
  11372. }
  11373. // XEP-0339 handle ssrc-group attributes
  11374. var ssrc_group_lines = SDPUtil.find_lines(this.media[i], 'a=ssrc-group:');
  11375. ssrc_group_lines.forEach(function(line) {
  11376. idx = line.indexOf(' ');
  11377. var semantics = line.substr(0, idx).substr(13);
  11378. var ssrcs = line.substr(14 + semantics.length).split(' ');
  11379. if (ssrcs.length != 0) {
  11380. elem.c('ssrc-group', { semantics: semantics, xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  11381. ssrcs.forEach(function(ssrc) {
  11382. elem.c('source', { ssrc: ssrc })
  11383. .up();
  11384. });
  11385. elem.up();
  11386. }
  11387. });
  11388. }
  11389. if (SDPUtil.find_line(this.media[i], 'a=rtcp-mux')) {
  11390. elem.c('rtcp-mux').up();
  11391. }
  11392. // XEP-0293 -- map a=rtcp-fb:*
  11393. this.RtcpFbToJingle(i, elem, '*');
  11394. // XEP-0294
  11395. if (SDPUtil.find_line(this.media[i], 'a=extmap:')) {
  11396. lines = SDPUtil.find_lines(this.media[i], 'a=extmap:');
  11397. for (j = 0; j < lines.length; j++) {
  11398. tmp = SDPUtil.parse_extmap(lines[j]);
  11399. elem.c('rtp-hdrext', { xmlns: 'urn:xmpp:jingle:apps:rtp:rtp-hdrext:0',
  11400. uri: tmp.uri,
  11401. id: tmp.value });
  11402. if (tmp.hasOwnProperty('direction')) {
  11403. switch (tmp.direction) {
  11404. case 'sendonly':
  11405. elem.attrs({senders: 'responder'});
  11406. break;
  11407. case 'recvonly':
  11408. elem.attrs({senders: 'initiator'});
  11409. break;
  11410. case 'sendrecv':
  11411. elem.attrs({senders: 'both'});
  11412. break;
  11413. case 'inactive':
  11414. elem.attrs({senders: 'none'});
  11415. break;
  11416. }
  11417. }
  11418. // TODO: handle params
  11419. elem.up();
  11420. }
  11421. }
  11422. elem.up(); // end of description
  11423. }
  11424. // map ice-ufrag/pwd, dtls fingerprint, candidates
  11425. this.TransportToJingle(i, elem);
  11426. if (SDPUtil.find_line(this.media[i], 'a=sendrecv', this.session)) {
  11427. elem.attrs({senders: 'both'});
  11428. } else if (SDPUtil.find_line(this.media[i], 'a=sendonly', this.session)) {
  11429. elem.attrs({senders: 'initiator'});
  11430. } else if (SDPUtil.find_line(this.media[i], 'a=recvonly', this.session)) {
  11431. elem.attrs({senders: 'responder'});
  11432. } else if (SDPUtil.find_line(this.media[i], 'a=inactive', this.session)) {
  11433. elem.attrs({senders: 'none'});
  11434. }
  11435. if (mline.port == '0') {
  11436. // estos hack to reject an m-line
  11437. elem.attrs({senders: 'rejected'});
  11438. }
  11439. elem.up(); // end of content
  11440. }
  11441. elem.up();
  11442. return elem;
  11443. };
  11444. SDP.prototype.TransportToJingle = function (mediaindex, elem) {
  11445. var i = mediaindex;
  11446. var tmp;
  11447. var self = this;
  11448. elem.c('transport');
  11449. // XEP-0343 DTLS/SCTP
  11450. if (SDPUtil.find_line(this.media[mediaindex], 'a=sctpmap:').length)
  11451. {
  11452. var sctpmap = SDPUtil.find_line(
  11453. this.media[i], 'a=sctpmap:', self.session);
  11454. if (sctpmap)
  11455. {
  11456. var sctpAttrs = SDPUtil.parse_sctpmap(sctpmap);
  11457. elem.c('sctpmap',
  11458. {
  11459. xmlns: 'urn:xmpp:jingle:transports:dtls-sctp:1',
  11460. number: sctpAttrs[0], /* SCTP port */
  11461. protocol: sctpAttrs[1], /* protocol */
  11462. });
  11463. // Optional stream count attribute
  11464. if (sctpAttrs.length > 2)
  11465. elem.attrs({ streams: sctpAttrs[2]});
  11466. elem.up();
  11467. }
  11468. }
  11469. // XEP-0320
  11470. var fingerprints = SDPUtil.find_lines(this.media[mediaindex], 'a=fingerprint:', this.session);
  11471. fingerprints.forEach(function(line) {
  11472. tmp = SDPUtil.parse_fingerprint(line);
  11473. tmp.xmlns = 'urn:xmpp:jingle:apps:dtls:0';
  11474. elem.c('fingerprint').t(tmp.fingerprint);
  11475. delete tmp.fingerprint;
  11476. line = SDPUtil.find_line(self.media[mediaindex], 'a=setup:', self.session);
  11477. if (line) {
  11478. tmp.setup = line.substr(8);
  11479. }
  11480. elem.attrs(tmp);
  11481. elem.up(); // end of fingerprint
  11482. });
  11483. tmp = SDPUtil.iceparams(this.media[mediaindex], this.session);
  11484. if (tmp) {
  11485. tmp.xmlns = 'urn:xmpp:jingle:transports:ice-udp:1';
  11486. elem.attrs(tmp);
  11487. // XEP-0176
  11488. if (SDPUtil.find_line(this.media[mediaindex], 'a=candidate:', this.session)) { // add any a=candidate lines
  11489. var lines = SDPUtil.find_lines(this.media[mediaindex], 'a=candidate:', this.session);
  11490. lines.forEach(function (line) {
  11491. elem.c('candidate', SDPUtil.candidateToJingle(line)).up();
  11492. });
  11493. }
  11494. }
  11495. elem.up(); // end of transport
  11496. }
  11497. SDP.prototype.RtcpFbToJingle = function (mediaindex, elem, payloadtype) { // XEP-0293
  11498. var lines = SDPUtil.find_lines(this.media[mediaindex], 'a=rtcp-fb:' + payloadtype);
  11499. lines.forEach(function (line) {
  11500. var tmp = SDPUtil.parse_rtcpfb(line);
  11501. if (tmp.type == 'trr-int') {
  11502. elem.c('rtcp-fb-trr-int', {xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0', value: tmp.params[0]});
  11503. elem.up();
  11504. } else {
  11505. elem.c('rtcp-fb', {xmlns: 'urn:xmpp:jingle:apps:rtp:rtcp-fb:0', type: tmp.type});
  11506. if (tmp.params.length > 0) {
  11507. elem.attrs({'subtype': tmp.params[0]});
  11508. }
  11509. elem.up();
  11510. }
  11511. });
  11512. };
  11513. SDP.prototype.RtcpFbFromJingle = function (elem, payloadtype) { // XEP-0293
  11514. var media = '';
  11515. var tmp = elem.find('>rtcp-fb-trr-int[xmlns="urn:xmpp:jingle:apps:rtp:rtcp-fb:0"]');
  11516. if (tmp.length) {
  11517. media += 'a=rtcp-fb:' + '*' + ' ' + 'trr-int' + ' ';
  11518. if (tmp.attr('value')) {
  11519. media += tmp.attr('value');
  11520. } else {
  11521. media += '0';
  11522. }
  11523. media += '\r\n';
  11524. }
  11525. tmp = elem.find('>rtcp-fb[xmlns="urn:xmpp:jingle:apps:rtp:rtcp-fb:0"]');
  11526. tmp.each(function () {
  11527. media += 'a=rtcp-fb:' + payloadtype + ' ' + $(this).attr('type');
  11528. if ($(this).attr('subtype')) {
  11529. media += ' ' + $(this).attr('subtype');
  11530. }
  11531. media += '\r\n';
  11532. });
  11533. return media;
  11534. };
  11535. // construct an SDP from a jingle stanza
  11536. SDP.prototype.fromJingle = function (jingle) {
  11537. var self = this;
  11538. this.raw = 'v=0\r\n' +
  11539. 'o=- ' + '1923518516' + ' 2 IN IP4 0.0.0.0\r\n' +// FIXME
  11540. 's=-\r\n' +
  11541. 't=0 0\r\n';
  11542. // http://tools.ietf.org/html/draft-ietf-mmusic-sdp-bundle-negotiation-04#section-8
  11543. if ($(jingle).find('>group[xmlns="urn:xmpp:jingle:apps:grouping:0"]').length) {
  11544. $(jingle).find('>group[xmlns="urn:xmpp:jingle:apps:grouping:0"]').each(function (idx, group) {
  11545. var contents = $(group).find('>content').map(function (idx, content) {
  11546. return content.getAttribute('name');
  11547. }).get();
  11548. if (contents.length > 0) {
  11549. self.raw += 'a=group:' + (group.getAttribute('semantics') || group.getAttribute('type')) + ' ' + contents.join(' ') + '\r\n';
  11550. }
  11551. });
  11552. }
  11553. this.session = this.raw;
  11554. jingle.find('>content').each(function () {
  11555. var m = self.jingle2media($(this));
  11556. self.media.push(m);
  11557. });
  11558. // reconstruct msid-semantic -- apparently not necessary
  11559. /*
  11560. var msid = SDPUtil.parse_ssrc(this.raw);
  11561. if (msid.hasOwnProperty('mslabel')) {
  11562. this.session += "a=msid-semantic: WMS " + msid.mslabel + "\r\n";
  11563. }
  11564. */
  11565. this.raw = this.session + this.media.join('');
  11566. };
  11567. // translate a jingle content element into an an SDP media part
  11568. SDP.prototype.jingle2media = function (content) {
  11569. var media = '',
  11570. desc = content.find('description'),
  11571. ssrc = desc.attr('ssrc'),
  11572. self = this,
  11573. tmp;
  11574. var sctp = content.find(
  11575. '>transport>sctpmap[xmlns="urn:xmpp:jingle:transports:dtls-sctp:1"]');
  11576. tmp = { media: desc.attr('media') };
  11577. tmp.port = '1';
  11578. if (content.attr('senders') == 'rejected') {
  11579. // estos hack to reject an m-line.
  11580. tmp.port = '0';
  11581. }
  11582. if (content.find('>transport>fingerprint').length || desc.find('encryption').length) {
  11583. if (sctp.length)
  11584. tmp.proto = 'DTLS/SCTP';
  11585. else
  11586. tmp.proto = 'RTP/SAVPF';
  11587. } else {
  11588. tmp.proto = 'RTP/AVPF';
  11589. }
  11590. if (!sctp.length)
  11591. {
  11592. tmp.fmt = desc.find('payload-type').map(
  11593. function () { return this.getAttribute('id'); }).get();
  11594. media += SDPUtil.build_mline(tmp) + '\r\n';
  11595. }
  11596. else
  11597. {
  11598. media += 'm=application 1 DTLS/SCTP ' + sctp.attr('number') + '\r\n';
  11599. media += 'a=sctpmap:' + sctp.attr('number') +
  11600. ' ' + sctp.attr('protocol');
  11601. var streamCount = sctp.attr('streams');
  11602. if (streamCount)
  11603. media += ' ' + streamCount + '\r\n';
  11604. else
  11605. media += '\r\n';
  11606. }
  11607. media += 'c=IN IP4 0.0.0.0\r\n';
  11608. if (!sctp.length)
  11609. media += 'a=rtcp:1 IN IP4 0.0.0.0\r\n';
  11610. tmp = content.find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]');
  11611. if (tmp.length) {
  11612. if (tmp.attr('ufrag')) {
  11613. media += SDPUtil.build_iceufrag(tmp.attr('ufrag')) + '\r\n';
  11614. }
  11615. if (tmp.attr('pwd')) {
  11616. media += SDPUtil.build_icepwd(tmp.attr('pwd')) + '\r\n';
  11617. }
  11618. tmp.find('>fingerprint').each(function () {
  11619. // FIXME: check namespace at some point
  11620. media += 'a=fingerprint:' + this.getAttribute('hash');
  11621. media += ' ' + $(this).text();
  11622. media += '\r\n';
  11623. if (this.getAttribute('setup')) {
  11624. media += 'a=setup:' + this.getAttribute('setup') + '\r\n';
  11625. }
  11626. });
  11627. }
  11628. switch (content.attr('senders')) {
  11629. case 'initiator':
  11630. media += 'a=sendonly\r\n';
  11631. break;
  11632. case 'responder':
  11633. media += 'a=recvonly\r\n';
  11634. break;
  11635. case 'none':
  11636. media += 'a=inactive\r\n';
  11637. break;
  11638. case 'both':
  11639. media += 'a=sendrecv\r\n';
  11640. break;
  11641. }
  11642. media += 'a=mid:' + content.attr('name') + '\r\n';
  11643. // <description><rtcp-mux/></description>
  11644. // see http://code.google.com/p/libjingle/issues/detail?id=309 -- no spec though
  11645. // and http://mail.jabber.org/pipermail/jingle/2011-December/001761.html
  11646. if (desc.find('rtcp-mux').length) {
  11647. media += 'a=rtcp-mux\r\n';
  11648. }
  11649. if (desc.find('encryption').length) {
  11650. desc.find('encryption>crypto').each(function () {
  11651. media += 'a=crypto:' + this.getAttribute('tag');
  11652. media += ' ' + this.getAttribute('crypto-suite');
  11653. media += ' ' + this.getAttribute('key-params');
  11654. if (this.getAttribute('session-params')) {
  11655. media += ' ' + this.getAttribute('session-params');
  11656. }
  11657. media += '\r\n';
  11658. });
  11659. }
  11660. desc.find('payload-type').each(function () {
  11661. media += SDPUtil.build_rtpmap(this) + '\r\n';
  11662. if ($(this).find('>parameter').length) {
  11663. media += 'a=fmtp:' + this.getAttribute('id') + ' ';
  11664. media += $(this).find('parameter').map(function () { return (this.getAttribute('name') ? (this.getAttribute('name') + '=') : '') + this.getAttribute('value'); }).get().join('; ');
  11665. media += '\r\n';
  11666. }
  11667. // xep-0293
  11668. media += self.RtcpFbFromJingle($(this), this.getAttribute('id'));
  11669. });
  11670. // xep-0293
  11671. media += self.RtcpFbFromJingle(desc, '*');
  11672. // xep-0294
  11673. tmp = desc.find('>rtp-hdrext[xmlns="urn:xmpp:jingle:apps:rtp:rtp-hdrext:0"]');
  11674. tmp.each(function () {
  11675. media += 'a=extmap:' + this.getAttribute('id') + ' ' + this.getAttribute('uri') + '\r\n';
  11676. });
  11677. content.find('>transport[xmlns="urn:xmpp:jingle:transports:ice-udp:1"]>candidate').each(function () {
  11678. media += SDPUtil.candidateFromJingle(this);
  11679. });
  11680. // XEP-0339 handle ssrc-group attributes
  11681. tmp = content.find('description>ssrc-group[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]').each(function() {
  11682. var semantics = this.getAttribute('semantics');
  11683. var ssrcs = $(this).find('>source').map(function() {
  11684. return this.getAttribute('ssrc');
  11685. }).get();
  11686. if (ssrcs.length != 0) {
  11687. media += 'a=ssrc-group:' + semantics + ' ' + ssrcs.join(' ') + '\r\n';
  11688. }
  11689. });
  11690. tmp = content.find('description>source[xmlns="urn:xmpp:jingle:apps:rtp:ssma:0"]');
  11691. tmp.each(function () {
  11692. var ssrc = this.getAttribute('ssrc');
  11693. $(this).find('>parameter').each(function () {
  11694. media += 'a=ssrc:' + ssrc + ' ' + this.getAttribute('name');
  11695. if (this.getAttribute('value') && this.getAttribute('value').length)
  11696. media += ':' + this.getAttribute('value');
  11697. media += '\r\n';
  11698. });
  11699. });
  11700. return media;
  11701. };
  11702. module.exports = SDP;
  11703. },{"./SDPUtil":50}],49:[function(require,module,exports){
  11704. function SDPDiffer(mySDP, otherSDP) {
  11705. this.mySDP = mySDP;
  11706. this.otherSDP = otherSDP;
  11707. }
  11708. /**
  11709. * Returns map of MediaChannel that contains only media not contained in <tt>otherSdp</tt>. Mapped by channel idx.
  11710. * @param otherSdp the other SDP to check ssrc with.
  11711. */
  11712. SDPDiffer.prototype.getNewMedia = function() {
  11713. // this could be useful in Array.prototype.
  11714. function arrayEquals(array) {
  11715. // if the other array is a falsy value, return
  11716. if (!array)
  11717. return false;
  11718. // compare lengths - can save a lot of time
  11719. if (this.length != array.length)
  11720. return false;
  11721. for (var i = 0, l=this.length; i < l; i++) {
  11722. // Check if we have nested arrays
  11723. if (this[i] instanceof Array && array[i] instanceof Array) {
  11724. // recurse into the nested arrays
  11725. if (!this[i].equals(array[i]))
  11726. return false;
  11727. }
  11728. else if (this[i] != array[i]) {
  11729. // Warning - two different object instances will never be equal: {x:20} != {x:20}
  11730. return false;
  11731. }
  11732. }
  11733. return true;
  11734. }
  11735. var myMedias = this.mySDP.getMediaSsrcMap();
  11736. var othersMedias = this.otherSDP.getMediaSsrcMap();
  11737. var newMedia = {};
  11738. Object.keys(othersMedias).forEach(function(othersMediaIdx) {
  11739. var myMedia = myMedias[othersMediaIdx];
  11740. var othersMedia = othersMedias[othersMediaIdx];
  11741. if(!myMedia && othersMedia) {
  11742. // Add whole channel
  11743. newMedia[othersMediaIdx] = othersMedia;
  11744. return;
  11745. }
  11746. // Look for new ssrcs accross the channel
  11747. Object.keys(othersMedia.ssrcs).forEach(function(ssrc) {
  11748. if(Object.keys(myMedia.ssrcs).indexOf(ssrc) === -1) {
  11749. // Allocate channel if we've found ssrc that doesn't exist in our channel
  11750. if(!newMedia[othersMediaIdx]){
  11751. newMedia[othersMediaIdx] = {
  11752. mediaindex: othersMedia.mediaindex,
  11753. mid: othersMedia.mid,
  11754. ssrcs: {},
  11755. ssrcGroups: []
  11756. };
  11757. }
  11758. newMedia[othersMediaIdx].ssrcs[ssrc] = othersMedia.ssrcs[ssrc];
  11759. }
  11760. });
  11761. // Look for new ssrc groups across the channels
  11762. othersMedia.ssrcGroups.forEach(function(otherSsrcGroup){
  11763. // try to match the other ssrc-group with an ssrc-group of ours
  11764. var matched = false;
  11765. for (var i = 0; i < myMedia.ssrcGroups.length; i++) {
  11766. var mySsrcGroup = myMedia.ssrcGroups[i];
  11767. if (otherSsrcGroup.semantics == mySsrcGroup.semantics
  11768. && arrayEquals.apply(otherSsrcGroup.ssrcs, [mySsrcGroup.ssrcs])) {
  11769. matched = true;
  11770. break;
  11771. }
  11772. }
  11773. if (!matched) {
  11774. // Allocate channel if we've found an ssrc-group that doesn't
  11775. // exist in our channel
  11776. if(!newMedia[othersMediaIdx]){
  11777. newMedia[othersMediaIdx] = {
  11778. mediaindex: othersMedia.mediaindex,
  11779. mid: othersMedia.mid,
  11780. ssrcs: {},
  11781. ssrcGroups: []
  11782. };
  11783. }
  11784. newMedia[othersMediaIdx].ssrcGroups.push(otherSsrcGroup);
  11785. }
  11786. });
  11787. });
  11788. return newMedia;
  11789. };
  11790. /**
  11791. * Sends SSRC update IQ.
  11792. * @param sdpMediaSsrcs SSRCs map obtained from SDP.getNewMedia. Cntains SSRCs to add/remove.
  11793. * @param sid session identifier that will be put into the IQ.
  11794. * @param initiator initiator identifier.
  11795. * @param toJid destination Jid
  11796. * @param isAdd indicates if this is remove or add operation.
  11797. */
  11798. SDPDiffer.prototype.toJingle = function(modify) {
  11799. var sdpMediaSsrcs = this.getNewMedia();
  11800. var self = this;
  11801. // FIXME: only announce video ssrcs since we mix audio and dont need
  11802. // the audio ssrcs therefore
  11803. var modified = false;
  11804. Object.keys(sdpMediaSsrcs).forEach(function(mediaindex){
  11805. modified = true;
  11806. var media = sdpMediaSsrcs[mediaindex];
  11807. modify.c('content', {name: media.mid});
  11808. modify.c('description', {xmlns:'urn:xmpp:jingle:apps:rtp:1', media: media.mid});
  11809. // FIXME: not completly sure this operates on blocks and / or handles different ssrcs correctly
  11810. // generate sources from lines
  11811. Object.keys(media.ssrcs).forEach(function(ssrcNum) {
  11812. var mediaSsrc = media.ssrcs[ssrcNum];
  11813. modify.c('source', { xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0' });
  11814. modify.attrs({ssrc: mediaSsrc.ssrc});
  11815. // iterate over ssrc lines
  11816. mediaSsrc.lines.forEach(function (line) {
  11817. var idx = line.indexOf(' ');
  11818. var kv = line.substr(idx + 1);
  11819. modify.c('parameter');
  11820. if (kv.indexOf(':') == -1) {
  11821. modify.attrs({ name: kv });
  11822. } else {
  11823. modify.attrs({ name: kv.split(':', 2)[0] });
  11824. modify.attrs({ value: kv.split(':', 2)[1] });
  11825. }
  11826. modify.up(); // end of parameter
  11827. });
  11828. modify.up(); // end of source
  11829. });
  11830. // generate source groups from lines
  11831. media.ssrcGroups.forEach(function(ssrcGroup) {
  11832. if (ssrcGroup.ssrcs.length != 0) {
  11833. modify.c('ssrc-group', {
  11834. semantics: ssrcGroup.semantics,
  11835. xmlns: 'urn:xmpp:jingle:apps:rtp:ssma:0'
  11836. });
  11837. ssrcGroup.ssrcs.forEach(function (ssrc) {
  11838. modify.c('source', { ssrc: ssrc })
  11839. .up(); // end of source
  11840. });
  11841. modify.up(); // end of ssrc-group
  11842. }
  11843. });
  11844. modify.up(); // end of description
  11845. modify.up(); // end of content
  11846. });
  11847. return modified;
  11848. };
  11849. module.exports = SDPDiffer;
  11850. },{}],50:[function(require,module,exports){
  11851. SDPUtil = {
  11852. iceparams: function (mediadesc, sessiondesc) {
  11853. var data = null;
  11854. if (SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc) &&
  11855. SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc)) {
  11856. data = {
  11857. ufrag: SDPUtil.parse_iceufrag(SDPUtil.find_line(mediadesc, 'a=ice-ufrag:', sessiondesc)),
  11858. pwd: SDPUtil.parse_icepwd(SDPUtil.find_line(mediadesc, 'a=ice-pwd:', sessiondesc))
  11859. };
  11860. }
  11861. return data;
  11862. },
  11863. parse_iceufrag: function (line) {
  11864. return line.substring(12);
  11865. },
  11866. build_iceufrag: function (frag) {
  11867. return 'a=ice-ufrag:' + frag;
  11868. },
  11869. parse_icepwd: function (line) {
  11870. return line.substring(10);
  11871. },
  11872. build_icepwd: function (pwd) {
  11873. return 'a=ice-pwd:' + pwd;
  11874. },
  11875. parse_mid: function (line) {
  11876. return line.substring(6);
  11877. },
  11878. parse_mline: function (line) {
  11879. var parts = line.substring(2).split(' '),
  11880. data = {};
  11881. data.media = parts.shift();
  11882. data.port = parts.shift();
  11883. data.proto = parts.shift();
  11884. if (parts[parts.length - 1] === '') { // trailing whitespace
  11885. parts.pop();
  11886. }
  11887. data.fmt = parts;
  11888. return data;
  11889. },
  11890. build_mline: function (mline) {
  11891. return 'm=' + mline.media + ' ' + mline.port + ' ' + mline.proto + ' ' + mline.fmt.join(' ');
  11892. },
  11893. parse_rtpmap: function (line) {
  11894. var parts = line.substring(9).split(' '),
  11895. data = {};
  11896. data.id = parts.shift();
  11897. parts = parts[0].split('/');
  11898. data.name = parts.shift();
  11899. data.clockrate = parts.shift();
  11900. data.channels = parts.length ? parts.shift() : '1';
  11901. return data;
  11902. },
  11903. /**
  11904. * Parses SDP line "a=sctpmap:..." and extracts SCTP port from it.
  11905. * @param line eg. "a=sctpmap:5000 webrtc-datachannel"
  11906. * @returns [SCTP port number, protocol, streams]
  11907. */
  11908. parse_sctpmap: function (line)
  11909. {
  11910. var parts = line.substring(10).split(' ');
  11911. var sctpPort = parts[0];
  11912. var protocol = parts[1];
  11913. // Stream count is optional
  11914. var streamCount = parts.length > 2 ? parts[2] : null;
  11915. return [sctpPort, protocol, streamCount];// SCTP port
  11916. },
  11917. build_rtpmap: function (el) {
  11918. var line = 'a=rtpmap:' + el.getAttribute('id') + ' ' + el.getAttribute('name') + '/' + el.getAttribute('clockrate');
  11919. if (el.getAttribute('channels') && el.getAttribute('channels') != '1') {
  11920. line += '/' + el.getAttribute('channels');
  11921. }
  11922. return line;
  11923. },
  11924. parse_crypto: function (line) {
  11925. var parts = line.substring(9).split(' '),
  11926. data = {};
  11927. data.tag = parts.shift();
  11928. data['crypto-suite'] = parts.shift();
  11929. data['key-params'] = parts.shift();
  11930. if (parts.length) {
  11931. data['session-params'] = parts.join(' ');
  11932. }
  11933. return data;
  11934. },
  11935. parse_fingerprint: function (line) { // RFC 4572
  11936. var parts = line.substring(14).split(' '),
  11937. data = {};
  11938. data.hash = parts.shift();
  11939. data.fingerprint = parts.shift();
  11940. // TODO assert that fingerprint satisfies 2UHEX *(":" 2UHEX) ?
  11941. return data;
  11942. },
  11943. parse_fmtp: function (line) {
  11944. var parts = line.split(' '),
  11945. i, key, value,
  11946. data = [];
  11947. parts.shift();
  11948. parts = parts.join(' ').split(';');
  11949. for (i = 0; i < parts.length; i++) {
  11950. key = parts[i].split('=')[0];
  11951. while (key.length && key[0] == ' ') {
  11952. key = key.substring(1);
  11953. }
  11954. value = parts[i].split('=')[1];
  11955. if (key && value) {
  11956. data.push({name: key, value: value});
  11957. } else if (key) {
  11958. // rfc 4733 (DTMF) style stuff
  11959. data.push({name: '', value: key});
  11960. }
  11961. }
  11962. return data;
  11963. },
  11964. parse_icecandidate: function (line) {
  11965. var candidate = {},
  11966. elems = line.split(' ');
  11967. candidate.foundation = elems[0].substring(12);
  11968. candidate.component = elems[1];
  11969. candidate.protocol = elems[2].toLowerCase();
  11970. candidate.priority = elems[3];
  11971. candidate.ip = elems[4];
  11972. candidate.port = elems[5];
  11973. // elems[6] => "typ"
  11974. candidate.type = elems[7];
  11975. candidate.generation = 0; // default value, may be overwritten below
  11976. for (var i = 8; i < elems.length; i += 2) {
  11977. switch (elems[i]) {
  11978. case 'raddr':
  11979. candidate['rel-addr'] = elems[i + 1];
  11980. break;
  11981. case 'rport':
  11982. candidate['rel-port'] = elems[i + 1];
  11983. break;
  11984. case 'generation':
  11985. candidate.generation = elems[i + 1];
  11986. break;
  11987. case 'tcptype':
  11988. candidate.tcptype = elems[i + 1];
  11989. break;
  11990. default: // TODO
  11991. console.log('parse_icecandidate not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
  11992. }
  11993. }
  11994. candidate.network = '1';
  11995. candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
  11996. return candidate;
  11997. },
  11998. build_icecandidate: function (cand) {
  11999. var line = ['a=candidate:' + cand.foundation, cand.component, cand.protocol, cand.priority, cand.ip, cand.port, 'typ', cand.type].join(' ');
  12000. line += ' ';
  12001. switch (cand.type) {
  12002. case 'srflx':
  12003. case 'prflx':
  12004. case 'relay':
  12005. if (cand.hasOwnAttribute('rel-addr') && cand.hasOwnAttribute('rel-port')) {
  12006. line += 'raddr';
  12007. line += ' ';
  12008. line += cand['rel-addr'];
  12009. line += ' ';
  12010. line += 'rport';
  12011. line += ' ';
  12012. line += cand['rel-port'];
  12013. line += ' ';
  12014. }
  12015. break;
  12016. }
  12017. if (cand.hasOwnAttribute('tcptype')) {
  12018. line += 'tcptype';
  12019. line += ' ';
  12020. line += cand.tcptype;
  12021. line += ' ';
  12022. }
  12023. line += 'generation';
  12024. line += ' ';
  12025. line += cand.hasOwnAttribute('generation') ? cand.generation : '0';
  12026. return line;
  12027. },
  12028. parse_ssrc: function (desc) {
  12029. // proprietary mapping of a=ssrc lines
  12030. // TODO: see "Jingle RTP Source Description" by Juberti and P. Thatcher on google docs
  12031. // and parse according to that
  12032. var lines = desc.split('\r\n'),
  12033. data = {};
  12034. for (var i = 0; i < lines.length; i++) {
  12035. if (lines[i].substring(0, 7) == 'a=ssrc:') {
  12036. var idx = lines[i].indexOf(' ');
  12037. data[lines[i].substr(idx + 1).split(':', 2)[0]] = lines[i].substr(idx + 1).split(':', 2)[1];
  12038. }
  12039. }
  12040. return data;
  12041. },
  12042. parse_rtcpfb: function (line) {
  12043. var parts = line.substr(10).split(' ');
  12044. var data = {};
  12045. data.pt = parts.shift();
  12046. data.type = parts.shift();
  12047. data.params = parts;
  12048. return data;
  12049. },
  12050. parse_extmap: function (line) {
  12051. var parts = line.substr(9).split(' ');
  12052. var data = {};
  12053. data.value = parts.shift();
  12054. if (data.value.indexOf('/') != -1) {
  12055. data.direction = data.value.substr(data.value.indexOf('/') + 1);
  12056. data.value = data.value.substr(0, data.value.indexOf('/'));
  12057. } else {
  12058. data.direction = 'both';
  12059. }
  12060. data.uri = parts.shift();
  12061. data.params = parts;
  12062. return data;
  12063. },
  12064. find_line: function (haystack, needle, sessionpart) {
  12065. var lines = haystack.split('\r\n');
  12066. for (var i = 0; i < lines.length; i++) {
  12067. if (lines[i].substring(0, needle.length) == needle) {
  12068. return lines[i];
  12069. }
  12070. }
  12071. if (!sessionpart) {
  12072. return false;
  12073. }
  12074. // search session part
  12075. lines = sessionpart.split('\r\n');
  12076. for (var j = 0; j < lines.length; j++) {
  12077. if (lines[j].substring(0, needle.length) == needle) {
  12078. return lines[j];
  12079. }
  12080. }
  12081. return false;
  12082. },
  12083. find_lines: function (haystack, needle, sessionpart) {
  12084. var lines = haystack.split('\r\n'),
  12085. needles = [];
  12086. for (var i = 0; i < lines.length; i++) {
  12087. if (lines[i].substring(0, needle.length) == needle)
  12088. needles.push(lines[i]);
  12089. }
  12090. if (needles.length || !sessionpart) {
  12091. return needles;
  12092. }
  12093. // search session part
  12094. lines = sessionpart.split('\r\n');
  12095. for (var j = 0; j < lines.length; j++) {
  12096. if (lines[j].substring(0, needle.length) == needle) {
  12097. needles.push(lines[j]);
  12098. }
  12099. }
  12100. return needles;
  12101. },
  12102. candidateToJingle: function (line) {
  12103. // a=candidate:2979166662 1 udp 2113937151 192.168.2.100 57698 typ host generation 0
  12104. // <candidate component=... foundation=... generation=... id=... ip=... network=... port=... priority=... protocol=... type=.../>
  12105. if (line.indexOf('candidate:') === 0) {
  12106. line = 'a=' + line;
  12107. } else if (line.substring(0, 12) != 'a=candidate:') {
  12108. console.log('parseCandidate called with a line that is not a candidate line');
  12109. console.log(line);
  12110. return null;
  12111. }
  12112. if (line.substring(line.length - 2) == '\r\n') // chomp it
  12113. line = line.substring(0, line.length - 2);
  12114. var candidate = {},
  12115. elems = line.split(' '),
  12116. i;
  12117. if (elems[6] != 'typ') {
  12118. console.log('did not find typ in the right place');
  12119. console.log(line);
  12120. return null;
  12121. }
  12122. candidate.foundation = elems[0].substring(12);
  12123. candidate.component = elems[1];
  12124. candidate.protocol = elems[2].toLowerCase();
  12125. candidate.priority = elems[3];
  12126. candidate.ip = elems[4];
  12127. candidate.port = elems[5];
  12128. // elems[6] => "typ"
  12129. candidate.type = elems[7];
  12130. candidate.generation = '0'; // default, may be overwritten below
  12131. for (i = 8; i < elems.length; i += 2) {
  12132. switch (elems[i]) {
  12133. case 'raddr':
  12134. candidate['rel-addr'] = elems[i + 1];
  12135. break;
  12136. case 'rport':
  12137. candidate['rel-port'] = elems[i + 1];
  12138. break;
  12139. case 'generation':
  12140. candidate.generation = elems[i + 1];
  12141. break;
  12142. case 'tcptype':
  12143. candidate.tcptype = elems[i + 1];
  12144. break;
  12145. default: // TODO
  12146. console.log('not translating "' + elems[i] + '" = "' + elems[i + 1] + '"');
  12147. }
  12148. }
  12149. candidate.network = '1';
  12150. candidate.id = Math.random().toString(36).substr(2, 10); // not applicable to SDP -- FIXME: should be unique, not just random
  12151. return candidate;
  12152. },
  12153. candidateFromJingle: function (cand) {
  12154. var line = 'a=candidate:';
  12155. line += cand.getAttribute('foundation');
  12156. line += ' ';
  12157. line += cand.getAttribute('component');
  12158. line += ' ';
  12159. line += cand.getAttribute('protocol'); //.toUpperCase(); // chrome M23 doesn't like this
  12160. line += ' ';
  12161. line += cand.getAttribute('priority');
  12162. line += ' ';
  12163. line += cand.getAttribute('ip');
  12164. line += ' ';
  12165. line += cand.getAttribute('port');
  12166. line += ' ';
  12167. line += 'typ';
  12168. line += ' ' + cand.getAttribute('type');
  12169. line += ' ';
  12170. switch (cand.getAttribute('type')) {
  12171. case 'srflx':
  12172. case 'prflx':
  12173. case 'relay':
  12174. if (cand.getAttribute('rel-addr') && cand.getAttribute('rel-port')) {
  12175. line += 'raddr';
  12176. line += ' ';
  12177. line += cand.getAttribute('rel-addr');
  12178. line += ' ';
  12179. line += 'rport';
  12180. line += ' ';
  12181. line += cand.getAttribute('rel-port');
  12182. line += ' ';
  12183. }
  12184. break;
  12185. }
  12186. if (cand.getAttribute('protocol').toLowerCase() == 'tcp') {
  12187. line += 'tcptype';
  12188. line += ' ';
  12189. line += cand.getAttribute('tcptype');
  12190. line += ' ';
  12191. }
  12192. line += 'generation';
  12193. line += ' ';
  12194. line += cand.getAttribute('generation') || '0';
  12195. return line + '\r\n';
  12196. }
  12197. };
  12198. module.exports = SDPUtil;
  12199. },{}],51:[function(require,module,exports){
  12200. function TraceablePeerConnection(ice_config, constraints) {
  12201. var self = this;
  12202. var RTCPeerconnection = navigator.mozGetUserMedia ? mozRTCPeerConnection : webkitRTCPeerConnection;
  12203. this.peerconnection = new RTCPeerconnection(ice_config, constraints);
  12204. this.updateLog = [];
  12205. this.stats = {};
  12206. this.statsinterval = null;
  12207. this.maxstats = 0; // limit to 300 values, i.e. 5 minutes; set to 0 to disable
  12208. // override as desired
  12209. this.trace = function (what, info) {
  12210. //console.warn('WTRACE', what, info);
  12211. self.updateLog.push({
  12212. time: new Date(),
  12213. type: what,
  12214. value: info || ""
  12215. });
  12216. };
  12217. this.onicecandidate = null;
  12218. this.peerconnection.onicecandidate = function (event) {
  12219. self.trace('onicecandidate', JSON.stringify(event.candidate, null, ' '));
  12220. if (self.onicecandidate !== null) {
  12221. self.onicecandidate(event);
  12222. }
  12223. };
  12224. this.onaddstream = null;
  12225. this.peerconnection.onaddstream = function (event) {
  12226. self.trace('onaddstream', event.stream.id);
  12227. if (self.onaddstream !== null) {
  12228. self.onaddstream(event);
  12229. }
  12230. };
  12231. this.onremovestream = null;
  12232. this.peerconnection.onremovestream = function (event) {
  12233. self.trace('onremovestream', event.stream.id);
  12234. if (self.onremovestream !== null) {
  12235. self.onremovestream(event);
  12236. }
  12237. };
  12238. this.onsignalingstatechange = null;
  12239. this.peerconnection.onsignalingstatechange = function (event) {
  12240. self.trace('onsignalingstatechange', self.signalingState);
  12241. if (self.onsignalingstatechange !== null) {
  12242. self.onsignalingstatechange(event);
  12243. }
  12244. };
  12245. this.oniceconnectionstatechange = null;
  12246. this.peerconnection.oniceconnectionstatechange = function (event) {
  12247. self.trace('oniceconnectionstatechange', self.iceConnectionState);
  12248. if (self.oniceconnectionstatechange !== null) {
  12249. self.oniceconnectionstatechange(event);
  12250. }
  12251. };
  12252. this.onnegotiationneeded = null;
  12253. this.peerconnection.onnegotiationneeded = function (event) {
  12254. self.trace('onnegotiationneeded');
  12255. if (self.onnegotiationneeded !== null) {
  12256. self.onnegotiationneeded(event);
  12257. }
  12258. };
  12259. self.ondatachannel = null;
  12260. this.peerconnection.ondatachannel = function (event) {
  12261. self.trace('ondatachannel', event);
  12262. if (self.ondatachannel !== null) {
  12263. self.ondatachannel(event);
  12264. }
  12265. };
  12266. if (!navigator.mozGetUserMedia && this.maxstats) {
  12267. this.statsinterval = window.setInterval(function() {
  12268. self.peerconnection.getStats(function(stats) {
  12269. var results = stats.result();
  12270. for (var i = 0; i < results.length; ++i) {
  12271. //console.log(results[i].type, results[i].id, results[i].names())
  12272. var now = new Date();
  12273. results[i].names().forEach(function (name) {
  12274. var id = results[i].id + '-' + name;
  12275. if (!self.stats[id]) {
  12276. self.stats[id] = {
  12277. startTime: now,
  12278. endTime: now,
  12279. values: [],
  12280. times: []
  12281. };
  12282. }
  12283. self.stats[id].values.push(results[i].stat(name));
  12284. self.stats[id].times.push(now.getTime());
  12285. if (self.stats[id].values.length > self.maxstats) {
  12286. self.stats[id].values.shift();
  12287. self.stats[id].times.shift();
  12288. }
  12289. self.stats[id].endTime = now;
  12290. });
  12291. }
  12292. });
  12293. }, 1000);
  12294. }
  12295. };
  12296. dumpSDP = function(description) {
  12297. return 'type: ' + description.type + '\r\n' + description.sdp;
  12298. }
  12299. if (TraceablePeerConnection.prototype.__defineGetter__ !== undefined) {
  12300. TraceablePeerConnection.prototype.__defineGetter__('signalingState', function() { return this.peerconnection.signalingState; });
  12301. TraceablePeerConnection.prototype.__defineGetter__('iceConnectionState', function() { return this.peerconnection.iceConnectionState; });
  12302. TraceablePeerConnection.prototype.__defineGetter__('localDescription', function() {
  12303. var publicLocalDescription = APP.simulcast.reverseTransformLocalDescription(this.peerconnection.localDescription);
  12304. return publicLocalDescription;
  12305. });
  12306. TraceablePeerConnection.prototype.__defineGetter__('remoteDescription', function() {
  12307. var publicRemoteDescription = APP.simulcast.reverseTransformRemoteDescription(this.peerconnection.remoteDescription);
  12308. return publicRemoteDescription;
  12309. });
  12310. }
  12311. TraceablePeerConnection.prototype.addStream = function (stream) {
  12312. this.trace('addStream', stream.id);
  12313. APP.simulcast.resetSender();
  12314. try
  12315. {
  12316. this.peerconnection.addStream(stream);
  12317. }
  12318. catch (e)
  12319. {
  12320. console.error(e);
  12321. return;
  12322. }
  12323. };
  12324. TraceablePeerConnection.prototype.removeStream = function (stream, stopStreams) {
  12325. this.trace('removeStream', stream.id);
  12326. APP.simulcast.resetSender();
  12327. if(stopStreams) {
  12328. stream.getAudioTracks().forEach(function (track) {
  12329. track.stop();
  12330. });
  12331. stream.getVideoTracks().forEach(function (track) {
  12332. track.stop();
  12333. });
  12334. }
  12335. this.peerconnection.removeStream(stream);
  12336. };
  12337. TraceablePeerConnection.prototype.createDataChannel = function (label, opts) {
  12338. this.trace('createDataChannel', label, opts);
  12339. return this.peerconnection.createDataChannel(label, opts);
  12340. };
  12341. TraceablePeerConnection.prototype.setLocalDescription = function (description, successCallback, failureCallback) {
  12342. var self = this;
  12343. description = APP.simulcast.transformLocalDescription(description);
  12344. this.trace('setLocalDescription', dumpSDP(description));
  12345. this.peerconnection.setLocalDescription(description,
  12346. function () {
  12347. self.trace('setLocalDescriptionOnSuccess');
  12348. successCallback();
  12349. },
  12350. function (err) {
  12351. self.trace('setLocalDescriptionOnFailure', err);
  12352. failureCallback(err);
  12353. }
  12354. );
  12355. /*
  12356. if (this.statsinterval === null && this.maxstats > 0) {
  12357. // start gathering stats
  12358. }
  12359. */
  12360. };
  12361. TraceablePeerConnection.prototype.setRemoteDescription = function (description, successCallback, failureCallback) {
  12362. var self = this;
  12363. description = APP.simulcast.transformRemoteDescription(description);
  12364. this.trace('setRemoteDescription', dumpSDP(description));
  12365. this.peerconnection.setRemoteDescription(description,
  12366. function () {
  12367. self.trace('setRemoteDescriptionOnSuccess');
  12368. successCallback();
  12369. },
  12370. function (err) {
  12371. self.trace('setRemoteDescriptionOnFailure', err);
  12372. failureCallback(err);
  12373. }
  12374. );
  12375. /*
  12376. if (this.statsinterval === null && this.maxstats > 0) {
  12377. // start gathering stats
  12378. }
  12379. */
  12380. };
  12381. TraceablePeerConnection.prototype.close = function () {
  12382. this.trace('stop');
  12383. if (this.statsinterval !== null) {
  12384. window.clearInterval(this.statsinterval);
  12385. this.statsinterval = null;
  12386. }
  12387. this.peerconnection.close();
  12388. };
  12389. TraceablePeerConnection.prototype.createOffer = function (successCallback, failureCallback, constraints) {
  12390. var self = this;
  12391. this.trace('createOffer', JSON.stringify(constraints, null, ' '));
  12392. this.peerconnection.createOffer(
  12393. function (offer) {
  12394. self.trace('createOfferOnSuccess', dumpSDP(offer));
  12395. successCallback(offer);
  12396. },
  12397. function(err) {
  12398. self.trace('createOfferOnFailure', err);
  12399. failureCallback(err);
  12400. },
  12401. constraints
  12402. );
  12403. };
  12404. TraceablePeerConnection.prototype.createAnswer = function (successCallback, failureCallback, constraints) {
  12405. var self = this;
  12406. this.trace('createAnswer', JSON.stringify(constraints, null, ' '));
  12407. this.peerconnection.createAnswer(
  12408. function (answer) {
  12409. answer = APP.simulcast.transformAnswer(answer);
  12410. self.trace('createAnswerOnSuccess', dumpSDP(answer));
  12411. successCallback(answer);
  12412. },
  12413. function(err) {
  12414. self.trace('createAnswerOnFailure', err);
  12415. failureCallback(err);
  12416. },
  12417. constraints
  12418. );
  12419. };
  12420. TraceablePeerConnection.prototype.addIceCandidate = function (candidate, successCallback, failureCallback) {
  12421. var self = this;
  12422. this.trace('addIceCandidate', JSON.stringify(candidate, null, ' '));
  12423. this.peerconnection.addIceCandidate(candidate);
  12424. /* maybe later
  12425. this.peerconnection.addIceCandidate(candidate,
  12426. function () {
  12427. self.trace('addIceCandidateOnSuccess');
  12428. successCallback();
  12429. },
  12430. function (err) {
  12431. self.trace('addIceCandidateOnFailure', err);
  12432. failureCallback(err);
  12433. }
  12434. );
  12435. */
  12436. };
  12437. TraceablePeerConnection.prototype.getStats = function(callback, errback) {
  12438. if (navigator.mozGetUserMedia) {
  12439. // ignore for now...
  12440. if(!errback)
  12441. errback = function () {
  12442. }
  12443. this.peerconnection.getStats(null,callback,errback);
  12444. } else {
  12445. this.peerconnection.getStats(callback);
  12446. }
  12447. };
  12448. module.exports = TraceablePeerConnection;
  12449. },{}],52:[function(require,module,exports){
  12450. /* global $, $iq, config, connection, UI, messageHandler,
  12451. roomName, sessionTerminated, Strophe, Util */
  12452. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  12453. /**
  12454. * Contains logic responsible for enabling/disabling functionality available
  12455. * only to moderator users.
  12456. */
  12457. var connection = null;
  12458. var focusUserJid;
  12459. function createExpBackoffTimer(step) {
  12460. var count = 1;
  12461. return function (reset) {
  12462. // Reset call
  12463. if (reset) {
  12464. count = 1;
  12465. return;
  12466. }
  12467. // Calculate next timeout
  12468. var timeout = Math.pow(2, count - 1);
  12469. count += 1;
  12470. return timeout * step;
  12471. };
  12472. }
  12473. var getNextTimeout = createExpBackoffTimer(1000);
  12474. var getNextErrorTimeout = createExpBackoffTimer(1000);
  12475. // External authentication stuff
  12476. var externalAuthEnabled = false;
  12477. // Sip gateway can be enabled by configuring Jigasi host in config.js or
  12478. // it will be enabled automatically if focus detects the component through
  12479. // service discovery.
  12480. var sipGatewayEnabled = config.hosts.call_control !== undefined;
  12481. var eventEmitter = null;
  12482. var Moderator = {
  12483. isModerator: function () {
  12484. return connection && connection.emuc.isModerator();
  12485. },
  12486. isPeerModerator: function (peerJid) {
  12487. return connection &&
  12488. connection.emuc.getMemberRole(peerJid) === 'moderator';
  12489. },
  12490. isExternalAuthEnabled: function () {
  12491. return externalAuthEnabled;
  12492. },
  12493. isSipGatewayEnabled: function () {
  12494. return sipGatewayEnabled;
  12495. },
  12496. setConnection: function (con) {
  12497. connection = con;
  12498. },
  12499. init: function (xmpp, emitter) {
  12500. this.xmppService = xmpp;
  12501. eventEmitter = emitter;
  12502. },
  12503. onMucLeft: function (jid) {
  12504. console.info("Someone left is it focus ? " + jid);
  12505. var resource = Strophe.getResourceFromJid(jid);
  12506. if (resource === 'focus' && !this.xmppService.sessionTerminated) {
  12507. console.info(
  12508. "Focus has left the room - leaving conference");
  12509. //hangUp();
  12510. // We'd rather reload to have everything re-initialized
  12511. // FIXME: show some message before reload
  12512. location.reload();
  12513. }
  12514. },
  12515. setFocusUserJid: function (focusJid) {
  12516. if (!focusUserJid) {
  12517. focusUserJid = focusJid;
  12518. console.info("Focus jid set to: " + focusUserJid);
  12519. }
  12520. },
  12521. getFocusUserJid: function () {
  12522. return focusUserJid;
  12523. },
  12524. getFocusComponent: function () {
  12525. // Get focus component address
  12526. var focusComponent = config.hosts.focus;
  12527. // If not specified use default: 'focus.domain'
  12528. if (!focusComponent) {
  12529. focusComponent = 'focus.' + config.hosts.domain;
  12530. }
  12531. return focusComponent;
  12532. },
  12533. createConferenceIq: function (roomName) {
  12534. // Generate create conference IQ
  12535. var elem = $iq({to: Moderator.getFocusComponent(), type: 'set'});
  12536. elem.c('conference', {
  12537. xmlns: 'http://jitsi.org/protocol/focus',
  12538. room: roomName
  12539. });
  12540. if (config.hosts.bridge !== undefined) {
  12541. elem.c(
  12542. 'property',
  12543. { name: 'bridge', value: config.hosts.bridge})
  12544. .up();
  12545. }
  12546. // Tell the focus we have Jigasi configured
  12547. if (config.hosts.call_control !== undefined) {
  12548. elem.c(
  12549. 'property',
  12550. { name: 'call_control', value: config.hosts.call_control})
  12551. .up();
  12552. }
  12553. if (config.channelLastN !== undefined) {
  12554. elem.c(
  12555. 'property',
  12556. { name: 'channelLastN', value: config.channelLastN})
  12557. .up();
  12558. }
  12559. if (config.adaptiveLastN !== undefined) {
  12560. elem.c(
  12561. 'property',
  12562. { name: 'adaptiveLastN', value: config.adaptiveLastN})
  12563. .up();
  12564. }
  12565. if (config.adaptiveSimulcast !== undefined) {
  12566. elem.c(
  12567. 'property',
  12568. { name: 'adaptiveSimulcast', value: config.adaptiveSimulcast})
  12569. .up();
  12570. }
  12571. if (config.openSctp !== undefined) {
  12572. elem.c(
  12573. 'property',
  12574. { name: 'openSctp', value: config.openSctp})
  12575. .up();
  12576. }
  12577. if (config.enableFirefoxSupport !== undefined) {
  12578. elem.c(
  12579. 'property',
  12580. { name: 'enableFirefoxHacks',
  12581. value: config.enableFirefoxSupport})
  12582. .up();
  12583. }
  12584. elem.up();
  12585. return elem;
  12586. },
  12587. parseConfigOptions: function (resultIq) {
  12588. Moderator.setFocusUserJid(
  12589. $(resultIq).find('conference').attr('focusjid'));
  12590. var extAuthParam
  12591. = $(resultIq).find('>conference>property[name=\'externalAuth\']');
  12592. if (extAuthParam.length) {
  12593. externalAuthEnabled = extAuthParam.attr('value') === 'true';
  12594. }
  12595. console.info("External authentication enabled: " + externalAuthEnabled);
  12596. // Check if focus has auto-detected Jigasi component(this will be also
  12597. // included if we have passed our host from the config)
  12598. if ($(resultIq).find(
  12599. '>conference>property[name=\'sipGatewayEnabled\']').length) {
  12600. sipGatewayEnabled = true;
  12601. }
  12602. console.info("Sip gateway enabled: " + sipGatewayEnabled);
  12603. },
  12604. // FIXME: we need to show the fact that we're waiting for the focus
  12605. // to the user(or that focus is not available)
  12606. allocateConferenceFocus: function (roomName, callback) {
  12607. // Try to use focus user JID from the config
  12608. Moderator.setFocusUserJid(config.focusUserJid);
  12609. // Send create conference IQ
  12610. var iq = Moderator.createConferenceIq(roomName);
  12611. var self = this;
  12612. connection.sendIQ(
  12613. iq,
  12614. function (result) {
  12615. if ('true' === $(result).find('conference').attr('ready')) {
  12616. // Reset both timers
  12617. getNextTimeout(true);
  12618. getNextErrorTimeout(true);
  12619. // Setup config options
  12620. Moderator.parseConfigOptions(result);
  12621. // Exec callback
  12622. callback();
  12623. } else {
  12624. var waitMs = getNextTimeout();
  12625. console.info("Waiting for the focus... " + waitMs);
  12626. // Reset error timeout
  12627. getNextErrorTimeout(true);
  12628. window.setTimeout(
  12629. function () {
  12630. Moderator.allocateConferenceFocus(
  12631. roomName, callback);
  12632. }, waitMs);
  12633. }
  12634. },
  12635. function (error) {
  12636. // Not authorized to create new room
  12637. if ($(error).find('>error>not-authorized').length) {
  12638. console.warn("Unauthorized to start the conference");
  12639. var toDomain
  12640. = Strophe.getDomainFromJid(error.getAttribute('to'));
  12641. if (toDomain === config.hosts.anonymousdomain) {
  12642. // we are connected with anonymous domain and
  12643. // only non anonymous users can create rooms
  12644. // we must authorize the user
  12645. self.xmppService.promptLogin();
  12646. } else {
  12647. eventEmitter.emit(XMPPEvents.AUTHENTICATION_REQUIRED, // External authentication mode
  12648. function () {
  12649. Moderator.allocateConferenceFocus(
  12650. roomName, callback);
  12651. });
  12652. }
  12653. return;
  12654. }
  12655. var waitMs = getNextErrorTimeout();
  12656. console.error("Focus error, retry after " + waitMs, error);
  12657. // Show message
  12658. APP.UI.messageHandler.notify(
  12659. 'Conference focus', 'disconnected',
  12660. Moderator.getFocusComponent() +
  12661. ' not available - retry in ' +
  12662. (waitMs / 1000) + ' sec');
  12663. // Reset response timeout
  12664. getNextTimeout(true);
  12665. window.setTimeout(
  12666. function () {
  12667. Moderator.allocateConferenceFocus(roomName, callback);
  12668. }, waitMs);
  12669. }
  12670. );
  12671. },
  12672. getAuthUrl: function (roomName, urlCallback) {
  12673. var iq = $iq({to: Moderator.getFocusComponent(), type: 'get'});
  12674. iq.c('auth-url', {
  12675. xmlns: 'http://jitsi.org/protocol/focus',
  12676. room: roomName
  12677. });
  12678. connection.sendIQ(
  12679. iq,
  12680. function (result) {
  12681. var url = $(result).find('auth-url').attr('url');
  12682. if (url) {
  12683. console.info("Got auth url: " + url);
  12684. urlCallback(url);
  12685. } else {
  12686. console.error(
  12687. "Failed to get auth url fro mthe focus", result);
  12688. }
  12689. },
  12690. function (error) {
  12691. console.error("Get auth url error", error);
  12692. }
  12693. );
  12694. }
  12695. };
  12696. module.exports = Moderator;
  12697. },{"../../service/xmpp/XMPPEvents":86}],53:[function(require,module,exports){
  12698. /* global $, $iq, config, connection, focusMucJid, messageHandler, Moderator,
  12699. Toolbar, Util */
  12700. var Moderator = require("./moderator");
  12701. var recordingToken = null;
  12702. var recordingEnabled;
  12703. /**
  12704. * Whether to use a jirecon component for recording, or use the videobridge
  12705. * through COLIBRI.
  12706. */
  12707. var useJirecon = (typeof config.hosts.jirecon != "undefined");
  12708. /**
  12709. * The ID of the jirecon recording session. Jirecon generates it when we
  12710. * initially start recording, and it needs to be used in subsequent requests
  12711. * to jirecon.
  12712. */
  12713. var jireconRid = null;
  12714. function setRecordingToken(token) {
  12715. recordingToken = token;
  12716. }
  12717. function setRecording(state, token, callback, connection) {
  12718. if (useJirecon){
  12719. setRecordingJirecon(state, token, callback, connection);
  12720. } else {
  12721. setRecordingColibri(state, token, callback, connection);
  12722. }
  12723. }
  12724. function setRecordingJirecon(state, token, callback, connection) {
  12725. if (state == recordingEnabled){
  12726. return;
  12727. }
  12728. var iq = $iq({to: config.hosts.jirecon, type: 'set'})
  12729. .c('recording', {xmlns: 'http://jitsi.org/protocol/jirecon',
  12730. action: state ? 'start' : 'stop',
  12731. mucjid: connection.emuc.roomjid});
  12732. if (!state){
  12733. iq.attrs({rid: jireconRid});
  12734. }
  12735. console.log('Start recording');
  12736. connection.sendIQ(
  12737. iq,
  12738. function (result) {
  12739. // TODO wait for an IQ with the real status, since this is
  12740. // provisional?
  12741. jireconRid = $(result).find('recording').attr('rid');
  12742. console.log('Recording ' + (state ? 'started' : 'stopped') +
  12743. '(jirecon)' + result);
  12744. recordingEnabled = state;
  12745. if (!state){
  12746. jireconRid = null;
  12747. }
  12748. callback(state);
  12749. },
  12750. function (error) {
  12751. console.log('Failed to start recording, error: ', error);
  12752. callback(recordingEnabled);
  12753. });
  12754. }
  12755. // Sends a COLIBRI message which enables or disables (according to 'state')
  12756. // the recording on the bridge. Waits for the result IQ and calls 'callback'
  12757. // with the new recording state, according to the IQ.
  12758. function setRecordingColibri(state, token, callback, connection) {
  12759. var elem = $iq({to: connection.emuc.focusMucJid, type: 'set'});
  12760. elem.c('conference', {
  12761. xmlns: 'http://jitsi.org/protocol/colibri'
  12762. });
  12763. elem.c('recording', {state: state, token: token});
  12764. connection.sendIQ(elem,
  12765. function (result) {
  12766. console.log('Set recording "', state, '". Result:', result);
  12767. var recordingElem = $(result).find('>conference>recording');
  12768. var newState = ('true' === recordingElem.attr('state'));
  12769. recordingEnabled = newState;
  12770. callback(newState);
  12771. },
  12772. function (error) {
  12773. console.warn(error);
  12774. callback(recordingEnabled);
  12775. }
  12776. );
  12777. }
  12778. var Recording = {
  12779. toggleRecording: function (tokenEmptyCallback,
  12780. startingCallback, startedCallback, connection) {
  12781. if (!Moderator.isModerator()) {
  12782. console.log(
  12783. 'non-focus, or conference not yet organized:' +
  12784. ' not enabling recording');
  12785. return;
  12786. }
  12787. var self = this;
  12788. // Jirecon does not (currently) support a token.
  12789. if (!recordingToken && !useJirecon) {
  12790. tokenEmptyCallback(function (value) {
  12791. setRecordingToken(value);
  12792. self.toggleRecording();
  12793. });
  12794. return;
  12795. }
  12796. var oldState = recordingEnabled;
  12797. startingCallback(!oldState);
  12798. setRecording(!oldState,
  12799. recordingToken,
  12800. function (state) {
  12801. console.log("New recording state: ", state);
  12802. if (state === oldState) {
  12803. // FIXME: new focus:
  12804. // this will not work when moderator changes
  12805. // during active session. Then it will assume that
  12806. // recording status has changed to true, but it might have
  12807. // been already true(and we only received actual status from
  12808. // the focus).
  12809. //
  12810. // SO we start with status null, so that it is initialized
  12811. // here and will fail only after second click, so if invalid
  12812. // token was used we have to press the button twice before
  12813. // current status will be fetched and token will be reset.
  12814. //
  12815. // Reliable way would be to return authentication error.
  12816. // Or status update when moderator connects.
  12817. // Or we have to stop recording session when current
  12818. // moderator leaves the room.
  12819. // Failed to change, reset the token because it might
  12820. // have been wrong
  12821. setRecordingToken(null);
  12822. }
  12823. startedCallback(state);
  12824. },
  12825. connection
  12826. );
  12827. }
  12828. }
  12829. module.exports = Recording;
  12830. },{"./moderator":52}],54:[function(require,module,exports){
  12831. /* jshint -W117 */
  12832. /* a simple MUC connection plugin
  12833. * can only handle a single MUC room
  12834. */
  12835. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  12836. var Moderator = require("./moderator");
  12837. var JingleSession = require("./JingleSession");
  12838. var bridgeIsDown = false;
  12839. module.exports = function(XMPP, eventEmitter) {
  12840. Strophe.addConnectionPlugin('emuc', {
  12841. connection: null,
  12842. roomjid: null,
  12843. myroomjid: null,
  12844. members: {},
  12845. list_members: [], // so we can elect a new focus
  12846. presMap: {},
  12847. preziMap: {},
  12848. joined: false,
  12849. isOwner: false,
  12850. role: null,
  12851. focusMucJid: null,
  12852. ssrc2jid: {},
  12853. init: function (conn) {
  12854. this.connection = conn;
  12855. },
  12856. initPresenceMap: function (myroomjid) {
  12857. this.presMap['to'] = myroomjid;
  12858. this.presMap['xns'] = 'http://jabber.org/protocol/muc';
  12859. },
  12860. doJoin: function (jid, password) {
  12861. this.myroomjid = jid;
  12862. console.info("Joined MUC as " + this.myroomjid);
  12863. this.initPresenceMap(this.myroomjid);
  12864. if (!this.roomjid) {
  12865. this.roomjid = Strophe.getBareJidFromJid(jid);
  12866. // add handlers (just once)
  12867. this.connection.addHandler(this.onPresence.bind(this), null, 'presence', null, null, this.roomjid, {matchBare: true});
  12868. this.connection.addHandler(this.onPresenceUnavailable.bind(this), null, 'presence', 'unavailable', null, this.roomjid, {matchBare: true});
  12869. this.connection.addHandler(this.onPresenceError.bind(this), null, 'presence', 'error', null, this.roomjid, {matchBare: true});
  12870. this.connection.addHandler(this.onMessage.bind(this), null, 'message', null, null, this.roomjid, {matchBare: true});
  12871. }
  12872. if (password !== undefined) {
  12873. this.presMap['password'] = password;
  12874. }
  12875. this.sendPresence();
  12876. },
  12877. doLeave: function () {
  12878. console.log("do leave", this.myroomjid);
  12879. var pres = $pres({to: this.myroomjid, type: 'unavailable' });
  12880. this.presMap.length = 0;
  12881. this.connection.send(pres);
  12882. },
  12883. createNonAnonymousRoom: function () {
  12884. // http://xmpp.org/extensions/xep-0045.html#createroom-reserved
  12885. var getForm = $iq({type: 'get', to: this.roomjid})
  12886. .c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'})
  12887. .c('x', {xmlns: 'jabber:x:data', type: 'submit'});
  12888. var self = this;
  12889. this.connection.sendIQ(getForm, function (form) {
  12890. if (!$(form).find(
  12891. '>query>x[xmlns="jabber:x:data"]' +
  12892. '>field[var="muc#roomconfig_whois"]').length) {
  12893. console.error('non-anonymous rooms not supported');
  12894. return;
  12895. }
  12896. var formSubmit = $iq({to: this.roomjid, type: 'set'})
  12897. .c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'});
  12898. formSubmit.c('x', {xmlns: 'jabber:x:data', type: 'submit'});
  12899. formSubmit.c('field', {'var': 'FORM_TYPE'})
  12900. .c('value')
  12901. .t('http://jabber.org/protocol/muc#roomconfig').up().up();
  12902. formSubmit.c('field', {'var': 'muc#roomconfig_whois'})
  12903. .c('value').t('anyone').up().up();
  12904. self.connection.sendIQ(formSubmit);
  12905. }, function (error) {
  12906. console.error("Error getting room configuration form");
  12907. });
  12908. },
  12909. onPresence: function (pres) {
  12910. var from = pres.getAttribute('from');
  12911. // What is this for? A workaround for something?
  12912. if (pres.getAttribute('type')) {
  12913. return true;
  12914. }
  12915. // Parse etherpad tag.
  12916. var etherpad = $(pres).find('>etherpad');
  12917. if (etherpad.length) {
  12918. if (config.etherpad_base && !Moderator.isModerator()) {
  12919. eventEmitter.emit(XMPPEvents.ETHERPAD, etherpad.text());
  12920. }
  12921. }
  12922. // Parse prezi tag.
  12923. var presentation = $(pres).find('>prezi');
  12924. if (presentation.length) {
  12925. var url = presentation.attr('url');
  12926. var current = presentation.find('>current').text();
  12927. console.log('presentation info received from', from, url);
  12928. if (this.preziMap[from] == null) {
  12929. this.preziMap[from] = url;
  12930. $(document).trigger('presentationadded.muc', [from, url, current]);
  12931. }
  12932. else {
  12933. $(document).trigger('gotoslide.muc', [from, url, current]);
  12934. }
  12935. }
  12936. else if (this.preziMap[from] != null) {
  12937. var url = this.preziMap[from];
  12938. delete this.preziMap[from];
  12939. $(document).trigger('presentationremoved.muc', [from, url]);
  12940. }
  12941. // Parse audio info tag.
  12942. var audioMuted = $(pres).find('>audiomuted');
  12943. if (audioMuted.length) {
  12944. $(document).trigger('audiomuted.muc', [from, audioMuted.text()]);
  12945. }
  12946. // Parse video info tag.
  12947. var videoMuted = $(pres).find('>videomuted');
  12948. if (videoMuted.length) {
  12949. $(document).trigger('videomuted.muc', [from, videoMuted.text()]);
  12950. }
  12951. var stats = $(pres).find('>stats');
  12952. if (stats.length) {
  12953. var statsObj = {};
  12954. Strophe.forEachChild(stats[0], "stat", function (el) {
  12955. statsObj[el.getAttribute("name")] = el.getAttribute("value");
  12956. });
  12957. eventEmitter.emit(XMPPEvents.REMOTE_STATS, from, statsObj);
  12958. }
  12959. // Parse status.
  12960. if ($(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="201"]').length) {
  12961. this.isOwner = true;
  12962. this.createNonAnonymousRoom();
  12963. }
  12964. // Parse roles.
  12965. var member = {};
  12966. member.show = $(pres).find('>show').text();
  12967. member.status = $(pres).find('>status').text();
  12968. var tmp = $(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>item');
  12969. member.affiliation = tmp.attr('affiliation');
  12970. member.role = tmp.attr('role');
  12971. // Focus recognition
  12972. member.jid = tmp.attr('jid');
  12973. member.isFocus = false;
  12974. if (member.jid
  12975. && member.jid.indexOf(Moderator.getFocusUserJid() + "/") == 0) {
  12976. member.isFocus = true;
  12977. }
  12978. var nicktag = $(pres).find('>nick[xmlns="http://jabber.org/protocol/nick"]');
  12979. member.displayName = (nicktag.length > 0 ? nicktag.html() : null);
  12980. if (from == this.myroomjid) {
  12981. if (member.affiliation == 'owner') this.isOwner = true;
  12982. if (this.role !== member.role) {
  12983. this.role = member.role;
  12984. eventEmitter.emit(XMPPEvents.LOCALROLE_CHANGED,
  12985. from, member, pres, Moderator.isModerator(),
  12986. Moderator.isExternalAuthEnabled());
  12987. }
  12988. if (!this.joined) {
  12989. this.joined = true;
  12990. eventEmitter.emit(XMPPEvents.MUC_JOINED, from, member);
  12991. this.list_members.push(from);
  12992. }
  12993. } else if (this.members[from] === undefined) {
  12994. // new participant
  12995. this.members[from] = member;
  12996. this.list_members.push(from);
  12997. console.log('entered', from, member);
  12998. if (member.isFocus) {
  12999. this.focusMucJid = from;
  13000. console.info("Ignore focus: " + from + ", real JID: " + member.jid);
  13001. }
  13002. else {
  13003. var id = $(pres).find('>userID').text();
  13004. var email = $(pres).find('>email');
  13005. if (email.length > 0) {
  13006. id = email.text();
  13007. }
  13008. eventEmitter.emit(XMPPEvents.MUC_ENTER, from, id, member.displayName);
  13009. }
  13010. } else {
  13011. // Presence update for existing participant
  13012. // Watch role change:
  13013. if (this.members[from].role != member.role) {
  13014. this.members[from].role = member.role;
  13015. eventEmitter.emit(XMPPEvents.MUC_ROLE_CHANGED,
  13016. member.role, member.displayName);
  13017. }
  13018. }
  13019. // Always trigger presence to update bindings
  13020. this.parsePresence(from, member, pres);
  13021. // Trigger status message update
  13022. if (member.status) {
  13023. eventEmitter.emit(XMPPEvents.PRESENCE_STATUS, from, member);
  13024. }
  13025. return true;
  13026. },
  13027. onPresenceUnavailable: function (pres) {
  13028. var from = pres.getAttribute('from');
  13029. // Status code 110 indicates that this notification is "self-presence".
  13030. if (!$(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="110"]').length) {
  13031. delete this.members[from];
  13032. this.list_members.splice(this.list_members.indexOf(from), 1);
  13033. this.onParticipantLeft(from);
  13034. }
  13035. // If the status code is 110 this means we're leaving and we would like
  13036. // to remove everyone else from our view, so we trigger the event.
  13037. else if (this.list_members.length > 1) {
  13038. for (var i = 0; i < this.list_members.length; i++) {
  13039. var member = this.list_members[i];
  13040. delete this.members[i];
  13041. this.list_members.splice(i, 1);
  13042. this.onParticipantLeft(member);
  13043. }
  13044. }
  13045. if ($(pres).find('>x[xmlns="http://jabber.org/protocol/muc#user"]>status[code="307"]').length) {
  13046. $(document).trigger('kicked.muc', [from]);
  13047. if (this.myroomjid === from) {
  13048. XMPP.disposeConference(false);
  13049. eventEmitter.emit(XMPPEvents.KICKED);
  13050. }
  13051. }
  13052. return true;
  13053. },
  13054. onPresenceError: function (pres) {
  13055. var from = pres.getAttribute('from');
  13056. if ($(pres).find('>error[type="auth"]>not-authorized[xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"]').length) {
  13057. console.log('on password required', from);
  13058. var self = this;
  13059. eventEmitter.emit(XMPPEvents.PASSWORD_REQUIRED, function (value) {
  13060. self.doJoin(from, value);
  13061. });
  13062. } else if ($(pres).find(
  13063. '>error[type="cancel"]>not-allowed[xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"]').length) {
  13064. var toDomain = Strophe.getDomainFromJid(pres.getAttribute('to'));
  13065. if (toDomain === config.hosts.anonymousdomain) {
  13066. // enter the room by replying with 'not-authorized'. This would
  13067. // result in reconnection from authorized domain.
  13068. // We're either missing Jicofo/Prosody config for anonymous
  13069. // domains or something is wrong.
  13070. // XMPP.promptLogin();
  13071. APP.UI.messageHandler.openReportDialog(null,
  13072. 'Oops ! We couldn`t join the conference.' +
  13073. ' There might be some problem with security' +
  13074. ' configuration. Please contact service' +
  13075. ' administrator.', pres);
  13076. } else {
  13077. console.warn('onPresError ', pres);
  13078. APP.UI.messageHandler.openReportDialog(null,
  13079. 'Oops! Something went wrong and we couldn`t connect to the conference.',
  13080. pres);
  13081. }
  13082. } else {
  13083. console.warn('onPresError ', pres);
  13084. APP.UI.messageHandler.openReportDialog(null,
  13085. 'Oops! Something went wrong and we couldn`t connect to the conference.',
  13086. pres);
  13087. }
  13088. return true;
  13089. },
  13090. sendMessage: function (body, nickname) {
  13091. var msg = $msg({to: this.roomjid, type: 'groupchat'});
  13092. msg.c('body', body).up();
  13093. if (nickname) {
  13094. msg.c('nick', {xmlns: 'http://jabber.org/protocol/nick'}).t(nickname).up().up();
  13095. }
  13096. this.connection.send(msg);
  13097. eventEmitter.emit(XMPPEvents.SENDING_CHAT_MESSAGE, body);
  13098. },
  13099. setSubject: function (subject) {
  13100. var msg = $msg({to: this.roomjid, type: 'groupchat'});
  13101. msg.c('subject', subject);
  13102. this.connection.send(msg);
  13103. console.log("topic changed to " + subject);
  13104. },
  13105. onMessage: function (msg) {
  13106. // FIXME: this is a hack. but jingle on muc makes nickchanges hard
  13107. var from = msg.getAttribute('from');
  13108. var nick =
  13109. $(msg).find('>nick[xmlns="http://jabber.org/protocol/nick"]')
  13110. .text() ||
  13111. Strophe.getResourceFromJid(from);
  13112. var txt = $(msg).find('>body').text();
  13113. var type = msg.getAttribute("type");
  13114. if (type == "error") {
  13115. eventEmitter.emit(XMPPEvents.CHAT_ERROR_RECEIVED,
  13116. $(msg).find('>text').text(), txt);
  13117. return true;
  13118. }
  13119. var subject = $(msg).find('>subject');
  13120. if (subject.length) {
  13121. var subjectText = subject.text();
  13122. if (subjectText || subjectText == "") {
  13123. eventEmitter.emit(XMPPEvents.SUBJECT_CHANGED, subjectText);
  13124. console.log("Subject is changed to " + subjectText);
  13125. }
  13126. }
  13127. if (txt) {
  13128. console.log('chat', nick, txt);
  13129. eventEmitter.emit(XMPPEvents.MESSAGE_RECEIVED,
  13130. from, nick, txt, this.myroomjid);
  13131. }
  13132. return true;
  13133. },
  13134. lockRoom: function (key, onSuccess, onError, onNotSupported) {
  13135. //http://xmpp.org/extensions/xep-0045.html#roomconfig
  13136. var ob = this;
  13137. this.connection.sendIQ($iq({to: this.roomjid, type: 'get'}).c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'}),
  13138. function (res) {
  13139. if ($(res).find('>query>x[xmlns="jabber:x:data"]>field[var="muc#roomconfig_roomsecret"]').length) {
  13140. var formsubmit = $iq({to: ob.roomjid, type: 'set'}).c('query', {xmlns: 'http://jabber.org/protocol/muc#owner'});
  13141. formsubmit.c('x', {xmlns: 'jabber:x:data', type: 'submit'});
  13142. formsubmit.c('field', {'var': 'FORM_TYPE'}).c('value').t('http://jabber.org/protocol/muc#roomconfig').up().up();
  13143. formsubmit.c('field', {'var': 'muc#roomconfig_roomsecret'}).c('value').t(key).up().up();
  13144. // Fixes a bug in prosody 0.9.+ https://code.google.com/p/lxmppd/issues/detail?id=373
  13145. formsubmit.c('field', {'var': 'muc#roomconfig_whois'}).c('value').t('anyone').up().up();
  13146. // FIXME: is muc#roomconfig_passwordprotectedroom required?
  13147. ob.connection.sendIQ(formsubmit,
  13148. onSuccess,
  13149. onError);
  13150. } else {
  13151. onNotSupported();
  13152. }
  13153. }, onError);
  13154. },
  13155. kick: function (jid) {
  13156. var kickIQ = $iq({to: this.roomjid, type: 'set'})
  13157. .c('query', {xmlns: 'http://jabber.org/protocol/muc#admin'})
  13158. .c('item', {nick: Strophe.getResourceFromJid(jid), role: 'none'})
  13159. .c('reason').t('You have been kicked.').up().up().up();
  13160. this.connection.sendIQ(
  13161. kickIQ,
  13162. function (result) {
  13163. console.log('Kick participant with jid: ', jid, result);
  13164. },
  13165. function (error) {
  13166. console.log('Kick participant error: ', error);
  13167. });
  13168. },
  13169. sendPresence: function () {
  13170. var pres = $pres({to: this.presMap['to'] });
  13171. pres.c('x', {xmlns: this.presMap['xns']});
  13172. if (this.presMap['password']) {
  13173. pres.c('password').t(this.presMap['password']).up();
  13174. }
  13175. pres.up();
  13176. // Send XEP-0115 'c' stanza that contains our capabilities info
  13177. if (this.connection.caps) {
  13178. this.connection.caps.node = config.clientNode;
  13179. pres.c('c', this.connection.caps.generateCapsAttrs()).up();
  13180. }
  13181. pres.c('user-agent', {xmlns: 'http://jitsi.org/jitmeet/user-agent'})
  13182. .t(navigator.userAgent).up();
  13183. if (this.presMap['bridgeIsDown']) {
  13184. pres.c('bridgeIsDown').up();
  13185. }
  13186. if (this.presMap['email']) {
  13187. pres.c('email').t(this.presMap['email']).up();
  13188. }
  13189. if (this.presMap['userId']) {
  13190. pres.c('userId').t(this.presMap['userId']).up();
  13191. }
  13192. if (this.presMap['displayName']) {
  13193. // XEP-0172
  13194. pres.c('nick', {xmlns: 'http://jabber.org/protocol/nick'})
  13195. .t(this.presMap['displayName']).up();
  13196. }
  13197. if (this.presMap['audions']) {
  13198. pres.c('audiomuted', {xmlns: this.presMap['audions']})
  13199. .t(this.presMap['audiomuted']).up();
  13200. }
  13201. if (this.presMap['videons']) {
  13202. pres.c('videomuted', {xmlns: this.presMap['videons']})
  13203. .t(this.presMap['videomuted']).up();
  13204. }
  13205. if (this.presMap['statsns']) {
  13206. var stats = pres.c('stats', {xmlns: this.presMap['statsns']});
  13207. for (var stat in this.presMap["stats"])
  13208. if (this.presMap["stats"][stat] != null)
  13209. stats.c("stat", {name: stat, value: this.presMap["stats"][stat]}).up();
  13210. pres.up();
  13211. }
  13212. if (this.presMap['prezins']) {
  13213. pres.c('prezi',
  13214. {xmlns: this.presMap['prezins'],
  13215. 'url': this.presMap['preziurl']})
  13216. .c('current').t(this.presMap['prezicurrent']).up().up();
  13217. }
  13218. if (this.presMap['etherpadns']) {
  13219. pres.c('etherpad', {xmlns: this.presMap['etherpadns']})
  13220. .t(this.presMap['etherpadname']).up();
  13221. }
  13222. if (this.presMap['medians']) {
  13223. pres.c('media', {xmlns: this.presMap['medians']});
  13224. var sourceNumber = 0;
  13225. Object.keys(this.presMap).forEach(function (key) {
  13226. if (key.indexOf('source') >= 0) {
  13227. sourceNumber++;
  13228. }
  13229. });
  13230. if (sourceNumber > 0)
  13231. for (var i = 1; i <= sourceNumber / 3; i++) {
  13232. pres.c('source',
  13233. {type: this.presMap['source' + i + '_type'],
  13234. ssrc: this.presMap['source' + i + '_ssrc'],
  13235. direction: this.presMap['source' + i + '_direction']
  13236. || 'sendrecv' }
  13237. ).up();
  13238. }
  13239. }
  13240. pres.up();
  13241. this.connection.send(pres);
  13242. },
  13243. addDisplayNameToPresence: function (displayName) {
  13244. this.presMap['displayName'] = displayName;
  13245. },
  13246. addMediaToPresence: function (sourceNumber, mtype, ssrcs, direction) {
  13247. if (!this.presMap['medians'])
  13248. this.presMap['medians'] = 'http://estos.de/ns/mjs';
  13249. this.presMap['source' + sourceNumber + '_type'] = mtype;
  13250. this.presMap['source' + sourceNumber + '_ssrc'] = ssrcs;
  13251. this.presMap['source' + sourceNumber + '_direction'] = direction;
  13252. },
  13253. clearPresenceMedia: function () {
  13254. var self = this;
  13255. Object.keys(this.presMap).forEach(function (key) {
  13256. if (key.indexOf('source') != -1) {
  13257. delete self.presMap[key];
  13258. }
  13259. });
  13260. },
  13261. addPreziToPresence: function (url, currentSlide) {
  13262. this.presMap['prezins'] = 'http://jitsi.org/jitmeet/prezi';
  13263. this.presMap['preziurl'] = url;
  13264. this.presMap['prezicurrent'] = currentSlide;
  13265. },
  13266. removePreziFromPresence: function () {
  13267. delete this.presMap['prezins'];
  13268. delete this.presMap['preziurl'];
  13269. delete this.presMap['prezicurrent'];
  13270. },
  13271. addCurrentSlideToPresence: function (currentSlide) {
  13272. this.presMap['prezicurrent'] = currentSlide;
  13273. },
  13274. getPrezi: function (roomjid) {
  13275. return this.preziMap[roomjid];
  13276. },
  13277. addEtherpadToPresence: function (etherpadName) {
  13278. this.presMap['etherpadns'] = 'http://jitsi.org/jitmeet/etherpad';
  13279. this.presMap['etherpadname'] = etherpadName;
  13280. },
  13281. addAudioInfoToPresence: function (isMuted) {
  13282. this.presMap['audions'] = 'http://jitsi.org/jitmeet/audio';
  13283. this.presMap['audiomuted'] = isMuted.toString();
  13284. },
  13285. addVideoInfoToPresence: function (isMuted) {
  13286. this.presMap['videons'] = 'http://jitsi.org/jitmeet/video';
  13287. this.presMap['videomuted'] = isMuted.toString();
  13288. },
  13289. addConnectionInfoToPresence: function (stats) {
  13290. this.presMap['statsns'] = 'http://jitsi.org/jitmeet/stats';
  13291. this.presMap['stats'] = stats;
  13292. },
  13293. findJidFromResource: function (resourceJid) {
  13294. if (resourceJid &&
  13295. resourceJid === Strophe.getResourceFromJid(this.myroomjid)) {
  13296. return this.myroomjid;
  13297. }
  13298. var peerJid = null;
  13299. Object.keys(this.members).some(function (jid) {
  13300. peerJid = jid;
  13301. return Strophe.getResourceFromJid(jid) === resourceJid;
  13302. });
  13303. return peerJid;
  13304. },
  13305. addBridgeIsDownToPresence: function () {
  13306. this.presMap['bridgeIsDown'] = true;
  13307. },
  13308. addEmailToPresence: function (email) {
  13309. this.presMap['email'] = email;
  13310. },
  13311. addUserIdToPresence: function (userId) {
  13312. this.presMap['userId'] = userId;
  13313. },
  13314. isModerator: function () {
  13315. return this.role === 'moderator';
  13316. },
  13317. getMemberRole: function (peerJid) {
  13318. if (this.members[peerJid]) {
  13319. return this.members[peerJid].role;
  13320. }
  13321. return null;
  13322. },
  13323. onParticipantLeft: function (jid) {
  13324. eventEmitter.emit(XMPPEvents.MUC_LEFT, jid);
  13325. this.connection.jingle.terminateByJid(jid);
  13326. if (this.getPrezi(jid)) {
  13327. $(document).trigger('presentationremoved.muc',
  13328. [jid, this.getPrezi(jid)]);
  13329. }
  13330. Moderator.onMucLeft(jid);
  13331. },
  13332. parsePresence: function (from, memeber, pres) {
  13333. if($(pres).find(">bridgeIsDown").length > 0 && !bridgeIsDown) {
  13334. bridgeIsDown = true;
  13335. eventEmitter.emit(XMPPEvents.BRIDGE_DOWN);
  13336. }
  13337. if(memeber.isFocus)
  13338. return;
  13339. var self = this;
  13340. // Remove old ssrcs coming from the jid
  13341. Object.keys(this.ssrc2jid).forEach(function (ssrc) {
  13342. if (self.ssrc2jid[ssrc] == from) {
  13343. delete self.ssrc2jid[ssrc];
  13344. }
  13345. });
  13346. var changedStreams = [];
  13347. $(pres).find('>media[xmlns="http://estos.de/ns/mjs"]>source').each(function (idx, ssrc) {
  13348. //console.log(jid, 'assoc ssrc', ssrc.getAttribute('type'), ssrc.getAttribute('ssrc'));
  13349. var ssrcV = ssrc.getAttribute('ssrc');
  13350. self.ssrc2jid[ssrcV] = from;
  13351. JingleSession.notReceivedSSRCs.push(ssrcV);
  13352. var type = ssrc.getAttribute('type');
  13353. var direction = ssrc.getAttribute('direction');
  13354. changedStreams.push({type: type, direction: direction});
  13355. });
  13356. eventEmitter.emit(XMPPEvents.CHANGED_STREAMS, from, changedStreams);
  13357. var displayName = !config.displayJids
  13358. ? memeber.displayName : Strophe.getResourceFromJid(from);
  13359. if (displayName && displayName.length > 0)
  13360. {
  13361. eventEmitter.emit(XMPPEvents.DISPLAY_NAME_CHANGED, from, displayName);
  13362. }
  13363. var id = $(pres).find('>userID').text();
  13364. var email = $(pres).find('>email');
  13365. if(email.length > 0) {
  13366. id = email.text();
  13367. }
  13368. eventEmitter.emit(XMPPEvents.USER_ID_CHANGED, from, id);
  13369. }
  13370. });
  13371. };
  13372. },{"../../service/xmpp/XMPPEvents":86,"./JingleSession":47,"./moderator":52}],55:[function(require,module,exports){
  13373. /* jshint -W117 */
  13374. var JingleSession = require("./JingleSession");
  13375. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  13376. module.exports = function(XMPP, eventEmitter)
  13377. {
  13378. function CallIncomingJingle(sid, connection) {
  13379. var sess = connection.jingle.sessions[sid];
  13380. // TODO: do we check activecall == null?
  13381. connection.jingle.activecall = sess;
  13382. eventEmitter.emit(XMPPEvents.CALL_INCOMING, sess);
  13383. // TODO: check affiliation and/or role
  13384. console.log('emuc data for', sess.peerjid, connection.emuc.members[sess.peerjid]);
  13385. sess.usedrip = true; // not-so-naive trickle ice
  13386. sess.sendAnswer();
  13387. sess.accept();
  13388. };
  13389. Strophe.addConnectionPlugin('jingle', {
  13390. connection: null,
  13391. sessions: {},
  13392. jid2session: {},
  13393. ice_config: {iceServers: []},
  13394. pc_constraints: {},
  13395. activecall: null,
  13396. media_constraints: {
  13397. mandatory: {
  13398. 'OfferToReceiveAudio': true,
  13399. 'OfferToReceiveVideo': true
  13400. }
  13401. // MozDontOfferDataChannel: true when this is firefox
  13402. },
  13403. init: function (conn) {
  13404. this.connection = conn;
  13405. if (this.connection.disco) {
  13406. // http://xmpp.org/extensions/xep-0167.html#support
  13407. // http://xmpp.org/extensions/xep-0176.html#support
  13408. this.connection.disco.addFeature('urn:xmpp:jingle:1');
  13409. this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:1');
  13410. this.connection.disco.addFeature('urn:xmpp:jingle:transports:ice-udp:1');
  13411. this.connection.disco.addFeature('urn:xmpp:jingle:transports:dtls-sctp:1');
  13412. this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:audio');
  13413. this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:video');
  13414. // this is dealt with by SDP O/A so we don't need to annouce this
  13415. //this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:rtcp-fb:0'); // XEP-0293
  13416. //this.connection.disco.addFeature('urn:xmpp:jingle:apps:rtp:rtp-hdrext:0'); // XEP-0294
  13417. if (config.useRtcpMux) {
  13418. this.connection.disco.addFeature('urn:ietf:rfc:5761'); // rtcp-mux
  13419. }
  13420. if (config.useBundle) {
  13421. this.connection.disco.addFeature('urn:ietf:rfc:5888'); // a=group, e.g. bundle
  13422. }
  13423. //this.connection.disco.addFeature('urn:ietf:rfc:5576'); // a=ssrc
  13424. }
  13425. this.connection.addHandler(this.onJingle.bind(this), 'urn:xmpp:jingle:1', 'iq', 'set', null, null);
  13426. },
  13427. onJingle: function (iq) {
  13428. var sid = $(iq).find('jingle').attr('sid');
  13429. var action = $(iq).find('jingle').attr('action');
  13430. var fromJid = iq.getAttribute('from');
  13431. // send ack first
  13432. var ack = $iq({type: 'result',
  13433. to: fromJid,
  13434. id: iq.getAttribute('id')
  13435. });
  13436. console.log('on jingle ' + action + ' from ' + fromJid, iq);
  13437. var sess = this.sessions[sid];
  13438. if ('session-initiate' != action) {
  13439. if (sess === null) {
  13440. ack.type = 'error';
  13441. ack.c('error', {type: 'cancel'})
  13442. .c('item-not-found', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up()
  13443. .c('unknown-session', {xmlns: 'urn:xmpp:jingle:errors:1'});
  13444. this.connection.send(ack);
  13445. return true;
  13446. }
  13447. // compare from to sess.peerjid (bare jid comparison for later compat with message-mode)
  13448. // local jid is not checked
  13449. if (Strophe.getBareJidFromJid(fromJid) != Strophe.getBareJidFromJid(sess.peerjid)) {
  13450. console.warn('jid mismatch for session id', sid, fromJid, sess.peerjid);
  13451. ack.type = 'error';
  13452. ack.c('error', {type: 'cancel'})
  13453. .c('item-not-found', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up()
  13454. .c('unknown-session', {xmlns: 'urn:xmpp:jingle:errors:1'});
  13455. this.connection.send(ack);
  13456. return true;
  13457. }
  13458. } else if (sess !== undefined) {
  13459. // existing session with same session id
  13460. // this might be out-of-order if the sess.peerjid is the same as from
  13461. ack.type = 'error';
  13462. ack.c('error', {type: 'cancel'})
  13463. .c('service-unavailable', {xmlns: 'urn:ietf:params:xml:ns:xmpp-stanzas'}).up();
  13464. console.warn('duplicate session id', sid);
  13465. this.connection.send(ack);
  13466. return true;
  13467. }
  13468. // FIXME: check for a defined action
  13469. this.connection.send(ack);
  13470. // see http://xmpp.org/extensions/xep-0166.html#concepts-session
  13471. switch (action) {
  13472. case 'session-initiate':
  13473. sess = new JingleSession(
  13474. $(iq).attr('to'), $(iq).find('jingle').attr('sid'),
  13475. this.connection, XMPP);
  13476. // configure session
  13477. sess.media_constraints = this.media_constraints;
  13478. sess.pc_constraints = this.pc_constraints;
  13479. sess.ice_config = this.ice_config;
  13480. sess.initiate(fromJid, false);
  13481. // FIXME: setRemoteDescription should only be done when this call is to be accepted
  13482. sess.setRemoteDescription($(iq).find('>jingle'), 'offer');
  13483. this.sessions[sess.sid] = sess;
  13484. this.jid2session[sess.peerjid] = sess;
  13485. // the callback should either
  13486. // .sendAnswer and .accept
  13487. // or .sendTerminate -- not necessarily synchronus
  13488. CallIncomingJingle(sess.sid, this.connection);
  13489. break;
  13490. case 'session-accept':
  13491. sess.setRemoteDescription($(iq).find('>jingle'), 'answer');
  13492. sess.accept();
  13493. $(document).trigger('callaccepted.jingle', [sess.sid]);
  13494. break;
  13495. case 'session-terminate':
  13496. // If this is not the focus sending the terminate, we have
  13497. // nothing more to do here.
  13498. if (Object.keys(this.sessions).length < 1
  13499. || !(this.sessions[Object.keys(this.sessions)[0]]
  13500. instanceof JingleSession))
  13501. {
  13502. break;
  13503. }
  13504. console.log('terminating...', sess.sid);
  13505. sess.terminate();
  13506. this.terminate(sess.sid);
  13507. if ($(iq).find('>jingle>reason').length) {
  13508. $(document).trigger('callterminated.jingle', [
  13509. sess.sid,
  13510. sess.peerjid,
  13511. $(iq).find('>jingle>reason>:first')[0].tagName,
  13512. $(iq).find('>jingle>reason>text').text()
  13513. ]);
  13514. } else {
  13515. $(document).trigger('callterminated.jingle',
  13516. [sess.sid, sess.peerjid]);
  13517. }
  13518. break;
  13519. case 'transport-info':
  13520. sess.addIceCandidate($(iq).find('>jingle>content'));
  13521. break;
  13522. case 'session-info':
  13523. var affected;
  13524. if ($(iq).find('>jingle>ringing[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').length) {
  13525. $(document).trigger('ringing.jingle', [sess.sid]);
  13526. } else if ($(iq).find('>jingle>mute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').length) {
  13527. affected = $(iq).find('>jingle>mute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').attr('name');
  13528. $(document).trigger('mute.jingle', [sess.sid, affected]);
  13529. } else if ($(iq).find('>jingle>unmute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').length) {
  13530. affected = $(iq).find('>jingle>unmute[xmlns="urn:xmpp:jingle:apps:rtp:info:1"]').attr('name');
  13531. $(document).trigger('unmute.jingle', [sess.sid, affected]);
  13532. }
  13533. break;
  13534. case 'addsource': // FIXME: proprietary, un-jingleish
  13535. case 'source-add': // FIXME: proprietary
  13536. sess.addSource($(iq).find('>jingle>content'), fromJid);
  13537. break;
  13538. case 'removesource': // FIXME: proprietary, un-jingleish
  13539. case 'source-remove': // FIXME: proprietary
  13540. sess.removeSource($(iq).find('>jingle>content'), fromJid);
  13541. break;
  13542. default:
  13543. console.warn('jingle action not implemented', action);
  13544. break;
  13545. }
  13546. return true;
  13547. },
  13548. initiate: function (peerjid, myjid) { // initiate a new jinglesession to peerjid
  13549. var sess = new JingleSession(myjid || this.connection.jid,
  13550. Math.random().toString(36).substr(2, 12), // random string
  13551. this.connection, XMPP);
  13552. // configure session
  13553. sess.media_constraints = this.media_constraints;
  13554. sess.pc_constraints = this.pc_constraints;
  13555. sess.ice_config = this.ice_config;
  13556. sess.initiate(peerjid, true);
  13557. this.sessions[sess.sid] = sess;
  13558. this.jid2session[sess.peerjid] = sess;
  13559. sess.sendOffer();
  13560. return sess;
  13561. },
  13562. terminate: function (sid, reason, text) { // terminate by sessionid (or all sessions)
  13563. if (sid === null || sid === undefined) {
  13564. for (sid in this.sessions) {
  13565. if (this.sessions[sid].state != 'ended') {
  13566. this.sessions[sid].sendTerminate(reason || (!this.sessions[sid].active()) ? 'cancel' : null, text);
  13567. this.sessions[sid].terminate();
  13568. }
  13569. delete this.jid2session[this.sessions[sid].peerjid];
  13570. delete this.sessions[sid];
  13571. }
  13572. } else if (this.sessions.hasOwnProperty(sid)) {
  13573. if (this.sessions[sid].state != 'ended') {
  13574. this.sessions[sid].sendTerminate(reason || (!this.sessions[sid].active()) ? 'cancel' : null, text);
  13575. this.sessions[sid].terminate();
  13576. }
  13577. delete this.jid2session[this.sessions[sid].peerjid];
  13578. delete this.sessions[sid];
  13579. }
  13580. },
  13581. // Used to terminate a session when an unavailable presence is received.
  13582. terminateByJid: function (jid) {
  13583. if (this.jid2session.hasOwnProperty(jid)) {
  13584. var sess = this.jid2session[jid];
  13585. if (sess) {
  13586. sess.terminate();
  13587. console.log('peer went away silently', jid);
  13588. delete this.sessions[sess.sid];
  13589. delete this.jid2session[jid];
  13590. $(document).trigger('callterminated.jingle',
  13591. [sess.sid, jid], 'gone');
  13592. }
  13593. }
  13594. },
  13595. terminateRemoteByJid: function (jid, reason) {
  13596. if (this.jid2session.hasOwnProperty(jid)) {
  13597. var sess = this.jid2session[jid];
  13598. if (sess) {
  13599. sess.sendTerminate(reason || (!sess.active()) ? 'kick' : null);
  13600. sess.terminate();
  13601. console.log('terminate peer with jid', sess.sid, jid);
  13602. delete this.sessions[sess.sid];
  13603. delete this.jid2session[jid];
  13604. $(document).trigger('callterminated.jingle',
  13605. [sess.sid, jid, 'kicked']);
  13606. }
  13607. }
  13608. },
  13609. getStunAndTurnCredentials: function () {
  13610. // get stun and turn configuration from server via xep-0215
  13611. // uses time-limited credentials as described in
  13612. // http://tools.ietf.org/html/draft-uberti-behave-turn-rest-00
  13613. //
  13614. // see https://code.google.com/p/prosody-modules/source/browse/mod_turncredentials/mod_turncredentials.lua
  13615. // for a prosody module which implements this
  13616. //
  13617. // currently, this doesn't work with updateIce and therefore credentials with a long
  13618. // validity have to be fetched before creating the peerconnection
  13619. // TODO: implement refresh via updateIce as described in
  13620. // https://code.google.com/p/webrtc/issues/detail?id=1650
  13621. var self = this;
  13622. this.connection.sendIQ(
  13623. $iq({type: 'get', to: this.connection.domain})
  13624. .c('services', {xmlns: 'urn:xmpp:extdisco:1'}).c('service', {host: 'turn.' + this.connection.domain}),
  13625. function (res) {
  13626. var iceservers = [];
  13627. $(res).find('>services>service').each(function (idx, el) {
  13628. el = $(el);
  13629. var dict = {};
  13630. var type = el.attr('type');
  13631. switch (type) {
  13632. case 'stun':
  13633. dict.url = 'stun:' + el.attr('host');
  13634. if (el.attr('port')) {
  13635. dict.url += ':' + el.attr('port');
  13636. }
  13637. iceservers.push(dict);
  13638. break;
  13639. case 'turn':
  13640. case 'turns':
  13641. dict.url = type + ':';
  13642. if (el.attr('username')) { // https://code.google.com/p/webrtc/issues/detail?id=1508
  13643. if (navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./) && parseInt(navigator.userAgent.match(/Chrom(e|ium)\/([0-9]+)\./)[2], 10) < 28) {
  13644. dict.url += el.attr('username') + '@';
  13645. } else {
  13646. dict.username = el.attr('username'); // only works in M28
  13647. }
  13648. }
  13649. dict.url += el.attr('host');
  13650. if (el.attr('port') && el.attr('port') != '3478') {
  13651. dict.url += ':' + el.attr('port');
  13652. }
  13653. if (el.attr('transport') && el.attr('transport') != 'udp') {
  13654. dict.url += '?transport=' + el.attr('transport');
  13655. }
  13656. if (el.attr('password')) {
  13657. dict.credential = el.attr('password');
  13658. }
  13659. iceservers.push(dict);
  13660. break;
  13661. }
  13662. });
  13663. self.ice_config.iceServers = iceservers;
  13664. },
  13665. function (err) {
  13666. console.warn('getting turn credentials failed', err);
  13667. console.warn('is mod_turncredentials or similar installed?');
  13668. }
  13669. );
  13670. // implement push?
  13671. },
  13672. /**
  13673. * Populates the log data
  13674. */
  13675. populateData: function () {
  13676. var data = {};
  13677. Object.keys(this.sessions).forEach(function (sid) {
  13678. var session = this.sessions[sid];
  13679. if (session.peerconnection && session.peerconnection.updateLog) {
  13680. // FIXME: should probably be a .dump call
  13681. data["jingle_" + session.sid] = {
  13682. updateLog: session.peerconnection.updateLog,
  13683. stats: session.peerconnection.stats,
  13684. url: window.location.href
  13685. };
  13686. }
  13687. });
  13688. return data;
  13689. }
  13690. });
  13691. };
  13692. },{"../../service/xmpp/XMPPEvents":86,"./JingleSession":47}],56:[function(require,module,exports){
  13693. /* global Strophe */
  13694. module.exports = function () {
  13695. Strophe.addConnectionPlugin('logger', {
  13696. // logs raw stanzas and makes them available for download as JSON
  13697. connection: null,
  13698. log: [],
  13699. init: function (conn) {
  13700. this.connection = conn;
  13701. this.connection.rawInput = this.log_incoming.bind(this);
  13702. this.connection.rawOutput = this.log_outgoing.bind(this);
  13703. },
  13704. log_incoming: function (stanza) {
  13705. this.log.push([new Date().getTime(), 'incoming', stanza]);
  13706. },
  13707. log_outgoing: function (stanza) {
  13708. this.log.push([new Date().getTime(), 'outgoing', stanza]);
  13709. }
  13710. });
  13711. };
  13712. },{}],57:[function(require,module,exports){
  13713. /* global $, $iq, config, connection, focusMucJid, forceMuted,
  13714. setAudioMuted, Strophe */
  13715. /**
  13716. * Moderate connection plugin.
  13717. */
  13718. module.exports = function (XMPP) {
  13719. Strophe.addConnectionPlugin('moderate', {
  13720. connection: null,
  13721. init: function (conn) {
  13722. this.connection = conn;
  13723. this.connection.addHandler(this.onMute.bind(this),
  13724. 'http://jitsi.org/jitmeet/audio',
  13725. 'iq',
  13726. 'set',
  13727. null,
  13728. null);
  13729. },
  13730. setMute: function (jid, mute) {
  13731. console.info("set mute", mute);
  13732. var iqToFocus = $iq({to: this.connection.emuc.focusMucJid, type: 'set'})
  13733. .c('mute', {
  13734. xmlns: 'http://jitsi.org/jitmeet/audio',
  13735. jid: jid
  13736. })
  13737. .t(mute.toString())
  13738. .up();
  13739. this.connection.sendIQ(
  13740. iqToFocus,
  13741. function (result) {
  13742. console.log('set mute', result);
  13743. },
  13744. function (error) {
  13745. console.log('set mute error', error);
  13746. });
  13747. },
  13748. onMute: function (iq) {
  13749. var from = iq.getAttribute('from');
  13750. if (from !== this.connection.emuc.focusMucJid) {
  13751. console.warn("Ignored mute from non focus peer");
  13752. return false;
  13753. }
  13754. var mute = $(iq).find('mute');
  13755. if (mute.length) {
  13756. var doMuteAudio = mute.text() === "true";
  13757. APP.UI.setAudioMuted(doMuteAudio);
  13758. XMPP.forceMuted = doMuteAudio;
  13759. }
  13760. return true;
  13761. },
  13762. eject: function (jid) {
  13763. // We're not the focus, so can't terminate
  13764. //connection.jingle.terminateRemoteByJid(jid, 'kick');
  13765. this.connection.emuc.kick(jid);
  13766. }
  13767. });
  13768. }
  13769. },{}],58:[function(require,module,exports){
  13770. /* jshint -W117 */
  13771. module.exports = function() {
  13772. Strophe.addConnectionPlugin('rayo',
  13773. {
  13774. RAYO_XMLNS: 'urn:xmpp:rayo:1',
  13775. connection: null,
  13776. init: function (conn) {
  13777. this.connection = conn;
  13778. if (this.connection.disco) {
  13779. this.connection.disco.addFeature('urn:xmpp:rayo:client:1');
  13780. }
  13781. this.connection.addHandler(
  13782. this.onRayo.bind(this), this.RAYO_XMLNS, 'iq', 'set', null, null);
  13783. },
  13784. onRayo: function (iq) {
  13785. console.info("Rayo IQ", iq);
  13786. },
  13787. dial: function (to, from, roomName, roomPass) {
  13788. var self = this;
  13789. var req = $iq(
  13790. {
  13791. type: 'set',
  13792. to: this.connection.emuc.focusMucJid
  13793. }
  13794. );
  13795. req.c('dial',
  13796. {
  13797. xmlns: this.RAYO_XMLNS,
  13798. to: to,
  13799. from: from
  13800. });
  13801. req.c('header',
  13802. {
  13803. name: 'JvbRoomName',
  13804. value: roomName
  13805. }).up();
  13806. if (roomPass !== null && roomPass.length) {
  13807. req.c('header',
  13808. {
  13809. name: 'JvbRoomPassword',
  13810. value: roomPass
  13811. }).up();
  13812. }
  13813. this.connection.sendIQ(
  13814. req,
  13815. function (result) {
  13816. console.info('Dial result ', result);
  13817. var resource = $(result).find('ref').attr('uri');
  13818. this.call_resource = resource.substr('xmpp:'.length);
  13819. console.info(
  13820. "Received call resource: " + this.call_resource);
  13821. },
  13822. function (error) {
  13823. console.info('Dial error ', error);
  13824. }
  13825. );
  13826. },
  13827. hang_up: function () {
  13828. if (!this.call_resource) {
  13829. console.warn("No call in progress");
  13830. return;
  13831. }
  13832. var self = this;
  13833. var req = $iq(
  13834. {
  13835. type: 'set',
  13836. to: this.call_resource
  13837. }
  13838. );
  13839. req.c('hangup',
  13840. {
  13841. xmlns: this.RAYO_XMLNS
  13842. });
  13843. this.connection.sendIQ(
  13844. req,
  13845. function (result) {
  13846. console.info('Hangup result ', result);
  13847. self.call_resource = null;
  13848. },
  13849. function (error) {
  13850. console.info('Hangup error ', error);
  13851. self.call_resource = null;
  13852. }
  13853. );
  13854. }
  13855. }
  13856. );
  13857. };
  13858. },{}],59:[function(require,module,exports){
  13859. /**
  13860. * Strophe logger implementation. Logs from level WARN and above.
  13861. */
  13862. module.exports = function () {
  13863. Strophe.log = function (level, msg) {
  13864. switch (level) {
  13865. case Strophe.LogLevel.WARN:
  13866. console.warn("Strophe: " + msg);
  13867. break;
  13868. case Strophe.LogLevel.ERROR:
  13869. case Strophe.LogLevel.FATAL:
  13870. console.error("Strophe: " + msg);
  13871. break;
  13872. }
  13873. };
  13874. Strophe.getStatusString = function (status) {
  13875. switch (status) {
  13876. case Strophe.Status.ERROR:
  13877. return "ERROR";
  13878. case Strophe.Status.CONNECTING:
  13879. return "CONNECTING";
  13880. case Strophe.Status.CONNFAIL:
  13881. return "CONNFAIL";
  13882. case Strophe.Status.AUTHENTICATING:
  13883. return "AUTHENTICATING";
  13884. case Strophe.Status.AUTHFAIL:
  13885. return "AUTHFAIL";
  13886. case Strophe.Status.CONNECTED:
  13887. return "CONNECTED";
  13888. case Strophe.Status.DISCONNECTED:
  13889. return "DISCONNECTED";
  13890. case Strophe.Status.DISCONNECTING:
  13891. return "DISCONNECTING";
  13892. case Strophe.Status.ATTACHED:
  13893. return "ATTACHED";
  13894. default:
  13895. return "unknown";
  13896. }
  13897. };
  13898. };
  13899. },{}],60:[function(require,module,exports){
  13900. var Moderator = require("./moderator");
  13901. var EventEmitter = require("events");
  13902. var Recording = require("./recording");
  13903. var SDP = require("./SDP");
  13904. var Pako = require("pako");
  13905. var StreamEventTypes = require("../../service/RTC/StreamEventTypes");
  13906. var UIEvents = require("../../service/UI/UIEvents");
  13907. var XMPPEvents = require("../../service/xmpp/XMPPEvents");
  13908. var eventEmitter = new EventEmitter();
  13909. var connection = null;
  13910. var authenticatedUser = false;
  13911. function connect(jid, password, uiCredentials) {
  13912. var bosh
  13913. = (uiCredentials && uiCredentials.bosh? uiCredentials.bosh : null)
  13914. || config.bosh || '/http-bind';
  13915. connection = new Strophe.Connection(bosh);
  13916. Moderator.setConnection(connection);
  13917. if(uiCredentials) {
  13918. var email = uiCredentials.email;
  13919. var displayName = uiCredentials.displayName;
  13920. if (email) {
  13921. connection.emuc.addEmailToPresence(email);
  13922. } else {
  13923. connection.emuc.addUserIdToPresence(uiCredentials.uid);
  13924. }
  13925. if (displayName) {
  13926. connection.emuc.addDisplayNameToPresence(displayName);
  13927. }
  13928. }
  13929. if (connection.disco) {
  13930. // for chrome, add multistream cap
  13931. }
  13932. connection.jingle.pc_constraints = APP.RTC.getPCConstraints();
  13933. if (config.useIPv6) {
  13934. // https://code.google.com/p/webrtc/issues/detail?id=2828
  13935. if (!connection.jingle.pc_constraints.optional)
  13936. connection.jingle.pc_constraints.optional = [];
  13937. connection.jingle.pc_constraints.optional.push({googIPv6: true});
  13938. }
  13939. if(!password)
  13940. password = uiCredentials.password;
  13941. var anonymousConnectionFailed = false;
  13942. connection.connect(jid, password, function (status, msg) {
  13943. console.log('Strophe status changed to',
  13944. Strophe.getStatusString(status));
  13945. if (status === Strophe.Status.CONNECTED) {
  13946. if (config.useStunTurn) {
  13947. connection.jingle.getStunAndTurnCredentials();
  13948. }
  13949. APP.UI.disableConnect();
  13950. console.info("My Jabber ID: " + connection.jid);
  13951. if(password)
  13952. authenticatedUser = true;
  13953. maybeDoJoin();
  13954. } else if (status === Strophe.Status.CONNFAIL) {
  13955. if(msg === 'x-strophe-bad-non-anon-jid') {
  13956. anonymousConnectionFailed = true;
  13957. }
  13958. } else if (status === Strophe.Status.DISCONNECTED) {
  13959. if(anonymousConnectionFailed) {
  13960. // prompt user for username and password
  13961. XMPP.promptLogin();
  13962. }
  13963. } else if (status === Strophe.Status.AUTHFAIL) {
  13964. // wrong password or username, prompt user
  13965. XMPP.promptLogin();
  13966. }
  13967. });
  13968. }
  13969. function maybeDoJoin() {
  13970. if (connection && connection.connected &&
  13971. Strophe.getResourceFromJid(connection.jid)
  13972. && (APP.RTC.localAudio || APP.RTC.localVideo)) {
  13973. // .connected is true while connecting?
  13974. doJoin();
  13975. }
  13976. }
  13977. function doJoin() {
  13978. var roomName = APP.UI.generateRoomName();
  13979. Moderator.allocateConferenceFocus(
  13980. roomName, APP.UI.checkForNicknameAndJoin);
  13981. }
  13982. function initStrophePlugins()
  13983. {
  13984. require("./strophe.emuc")(XMPP, eventEmitter);
  13985. require("./strophe.jingle")(XMPP, eventEmitter);
  13986. require("./strophe.moderate")(XMPP);
  13987. require("./strophe.util")();
  13988. require("./strophe.rayo")();
  13989. require("./strophe.logger")();
  13990. }
  13991. function registerListeners() {
  13992. APP.RTC.addStreamListener(maybeDoJoin,
  13993. StreamEventTypes.EVENT_TYPE_LOCAL_CREATED);
  13994. APP.UI.addListener(UIEvents.NICKNAME_CHANGED, function (nickname) {
  13995. XMPP.addToPresence("displayName", nickname);
  13996. });
  13997. }
  13998. function setupEvents() {
  13999. $(window).bind('beforeunload', function () {
  14000. if (connection && connection.connected) {
  14001. // ensure signout
  14002. $.ajax({
  14003. type: 'POST',
  14004. url: config.bosh,
  14005. async: false,
  14006. cache: false,
  14007. contentType: 'application/xml',
  14008. data: "<body rid='" + (connection.rid || connection._proto.rid)
  14009. + "' xmlns='http://jabber.org/protocol/httpbind' sid='"
  14010. + (connection.sid || connection._proto.sid)
  14011. + "' type='terminate'>" +
  14012. "<presence xmlns='jabber:client' type='unavailable'/>" +
  14013. "</body>",
  14014. success: function (data) {
  14015. console.log('signed out');
  14016. console.log(data);
  14017. },
  14018. error: function (XMLHttpRequest, textStatus, errorThrown) {
  14019. console.log('signout error',
  14020. textStatus + ' (' + errorThrown + ')');
  14021. }
  14022. });
  14023. }
  14024. XMPP.disposeConference(true);
  14025. });
  14026. }
  14027. var XMPP = {
  14028. sessionTerminated: false,
  14029. /**
  14030. * Remembers if we were muted by the focus.
  14031. * @type {boolean}
  14032. */
  14033. forceMuted: false,
  14034. start: function (uiCredentials) {
  14035. setupEvents();
  14036. initStrophePlugins();
  14037. registerListeners();
  14038. Moderator.init(this, eventEmitter);
  14039. var configDomain = config.hosts.anonymousdomain || config.hosts.domain;
  14040. // Force authenticated domain if room is appended with '?login=true'
  14041. if (config.hosts.anonymousdomain &&
  14042. window.location.search.indexOf("login=true") !== -1) {
  14043. configDomain = config.hosts.domain;
  14044. }
  14045. var jid = uiCredentials.jid || configDomain || window.location.hostname;
  14046. connect(jid, null, uiCredentials);
  14047. },
  14048. promptLogin: function () {
  14049. APP.UI.showLoginPopup(connect);
  14050. },
  14051. joinRoom: function(roomName, useNicks, nick)
  14052. {
  14053. var roomjid;
  14054. roomjid = roomName;
  14055. if (useNicks) {
  14056. if (nick) {
  14057. roomjid += '/' + nick;
  14058. } else {
  14059. roomjid += '/' + Strophe.getNodeFromJid(connection.jid);
  14060. }
  14061. } else {
  14062. var tmpJid = Strophe.getNodeFromJid(connection.jid);
  14063. if(!authenticatedUser)
  14064. tmpJid = tmpJid.substr(0, 8);
  14065. roomjid += '/' + tmpJid;
  14066. }
  14067. connection.emuc.doJoin(roomjid);
  14068. },
  14069. myJid: function () {
  14070. if(!connection)
  14071. return null;
  14072. return connection.emuc.myroomjid;
  14073. },
  14074. myResource: function () {
  14075. if(!connection || ! connection.emuc.myroomjid)
  14076. return null;
  14077. return Strophe.getResourceFromJid(connection.emuc.myroomjid);
  14078. },
  14079. disposeConference: function (onUnload) {
  14080. eventEmitter.emit(XMPPEvents.DISPOSE_CONFERENCE, onUnload);
  14081. var handler = connection.jingle.activecall;
  14082. if (handler && handler.peerconnection) {
  14083. // FIXME: probably removing streams is not required and close() should
  14084. // be enough
  14085. if (APP.RTC.localAudio) {
  14086. handler.peerconnection.removeStream(APP.RTC.localAudio.getOriginalStream(), onUnload);
  14087. }
  14088. if (APP.RTC.localVideo) {
  14089. handler.peerconnection.removeStream(APP.RTC.localVideo.getOriginalStream(), onUnload);
  14090. }
  14091. handler.peerconnection.close();
  14092. }
  14093. connection.jingle.activecall = null;
  14094. if(!onUnload)
  14095. {
  14096. this.sessionTerminated = true;
  14097. connection.emuc.doLeave();
  14098. }
  14099. },
  14100. addListener: function(type, listener)
  14101. {
  14102. eventEmitter.on(type, listener);
  14103. },
  14104. removeListener: function (type, listener) {
  14105. eventEmitter.removeListener(type, listener);
  14106. },
  14107. allocateConferenceFocus: function(roomName, callback) {
  14108. Moderator.allocateConferenceFocus(roomName, callback);
  14109. },
  14110. isModerator: function () {
  14111. return Moderator.isModerator();
  14112. },
  14113. isSipGatewayEnabled: function () {
  14114. return Moderator.isSipGatewayEnabled();
  14115. },
  14116. isExternalAuthEnabled: function () {
  14117. return Moderator.isExternalAuthEnabled();
  14118. },
  14119. switchStreams: function (stream, oldStream, callback) {
  14120. if (connection && connection.jingle.activecall) {
  14121. // FIXME: will block switchInProgress on true value in case of exception
  14122. connection.jingle.activecall.switchStreams(stream, oldStream, callback);
  14123. } else {
  14124. // We are done immediately
  14125. console.error("No conference handler");
  14126. APP.UI.messageHandler.showError('Error',
  14127. 'Unable to switch video stream.');
  14128. callback();
  14129. }
  14130. },
  14131. setVideoMute: function (mute, callback, options) {
  14132. if(connection && APP.RTC.localVideo && connection.jingle.activecall)
  14133. {
  14134. connection.jingle.activecall.setVideoMute(mute, callback, options);
  14135. }
  14136. },
  14137. setAudioMute: function (mute, callback) {
  14138. if (!(connection && APP.RTC.localAudio)) {
  14139. return false;
  14140. }
  14141. if (this.forceMuted && !mute) {
  14142. console.info("Asking focus for unmute");
  14143. connection.moderate.setMute(connection.emuc.myroomjid, mute);
  14144. // FIXME: wait for result before resetting muted status
  14145. this.forceMuted = false;
  14146. }
  14147. if (mute == APP.RTC.localAudio.isMuted()) {
  14148. // Nothing to do
  14149. return true;
  14150. }
  14151. // It is not clear what is the right way to handle multiple tracks.
  14152. // So at least make sure that they are all muted or all unmuted and
  14153. // that we send presence just once.
  14154. APP.RTC.localAudio.mute();
  14155. // isMuted is the opposite of audioEnabled
  14156. connection.emuc.addAudioInfoToPresence(mute);
  14157. connection.emuc.sendPresence();
  14158. callback();
  14159. return true;
  14160. },
  14161. // Really mute video, i.e. dont even send black frames
  14162. muteVideo: function (pc, unmute) {
  14163. // FIXME: this probably needs another of those lovely state safeguards...
  14164. // which checks for iceconn == connected and sigstate == stable
  14165. pc.setRemoteDescription(pc.remoteDescription,
  14166. function () {
  14167. pc.createAnswer(
  14168. function (answer) {
  14169. var sdp = new SDP(answer.sdp);
  14170. if (sdp.media.length > 1) {
  14171. if (unmute)
  14172. sdp.media[1] = sdp.media[1].replace('a=recvonly', 'a=sendrecv');
  14173. else
  14174. sdp.media[1] = sdp.media[1].replace('a=sendrecv', 'a=recvonly');
  14175. sdp.raw = sdp.session + sdp.media.join('');
  14176. answer.sdp = sdp.raw;
  14177. }
  14178. pc.setLocalDescription(answer,
  14179. function () {
  14180. console.log('mute SLD ok');
  14181. },
  14182. function (error) {
  14183. console.log('mute SLD error');
  14184. APP.UI.messageHandler.showError('Error',
  14185. 'Oops! Something went wrong and we failed to ' +
  14186. 'mute! (SLD Failure)');
  14187. }
  14188. );
  14189. },
  14190. function (error) {
  14191. console.log(error);
  14192. APP.UI.messageHandler.showError();
  14193. }
  14194. );
  14195. },
  14196. function (error) {
  14197. console.log('muteVideo SRD error');
  14198. APP.UI.messageHandler.showError('Error',
  14199. 'Oops! Something went wrong and we failed to stop video!' +
  14200. '(SRD Failure)');
  14201. }
  14202. );
  14203. },
  14204. toggleRecording: function (tokenEmptyCallback,
  14205. startingCallback, startedCallback) {
  14206. Recording.toggleRecording(tokenEmptyCallback,
  14207. startingCallback, startedCallback, connection);
  14208. },
  14209. addToPresence: function (name, value, dontSend) {
  14210. switch (name)
  14211. {
  14212. case "displayName":
  14213. connection.emuc.addDisplayNameToPresence(value);
  14214. break;
  14215. case "etherpad":
  14216. connection.emuc.addEtherpadToPresence(value);
  14217. break;
  14218. case "prezi":
  14219. connection.emuc.addPreziToPresence(value, 0);
  14220. break;
  14221. case "preziSlide":
  14222. connection.emuc.addCurrentSlideToPresence(value);
  14223. break;
  14224. case "connectionQuality":
  14225. connection.emuc.addConnectionInfoToPresence(value);
  14226. break;
  14227. case "email":
  14228. connection.emuc.addEmailToPresence(value);
  14229. default :
  14230. console.log("Unknown tag for presence.");
  14231. return;
  14232. }
  14233. if(!dontSend)
  14234. connection.emuc.sendPresence();
  14235. },
  14236. sendLogs: function (data) {
  14237. if(!connection.emuc.focusMucJid)
  14238. return;
  14239. var deflate = true;
  14240. var content = JSON.stringify(data);
  14241. if (deflate) {
  14242. content = String.fromCharCode.apply(null, Pako.deflateRaw(content));
  14243. }
  14244. content = Base64.encode(content);
  14245. // XEP-0337-ish
  14246. var message = $msg({to: connection.emuc.focusMucJid, type: 'normal'});
  14247. message.c('log', { xmlns: 'urn:xmpp:eventlog',
  14248. id: 'PeerConnectionStats'});
  14249. message.c('message').t(content).up();
  14250. if (deflate) {
  14251. message.c('tag', {name: "deflated", value: "true"}).up();
  14252. }
  14253. message.up();
  14254. connection.send(message);
  14255. },
  14256. populateData: function () {
  14257. var data = {};
  14258. if (connection.jingle) {
  14259. data = connection.jingle.populateData();
  14260. }
  14261. return data;
  14262. },
  14263. getLogger: function () {
  14264. if(connection.logger)
  14265. return connection.logger.log;
  14266. return null;
  14267. },
  14268. getPrezi: function () {
  14269. return connection.emuc.getPrezi(this.myJid());
  14270. },
  14271. removePreziFromPresence: function () {
  14272. connection.emuc.removePreziFromPresence();
  14273. connection.emuc.sendPresence();
  14274. },
  14275. sendChatMessage: function (message, nickname) {
  14276. connection.emuc.sendMessage(message, nickname);
  14277. },
  14278. setSubject: function (topic) {
  14279. connection.emuc.setSubject(topic);
  14280. },
  14281. lockRoom: function (key, onSuccess, onError, onNotSupported) {
  14282. connection.emuc.lockRoom(key, onSuccess, onError, onNotSupported);
  14283. },
  14284. dial: function (to, from, roomName,roomPass) {
  14285. connection.rayo.dial(to, from, roomName,roomPass);
  14286. },
  14287. setMute: function (jid, mute) {
  14288. connection.moderate.setMute(jid, mute);
  14289. },
  14290. eject: function (jid) {
  14291. connection.moderate.eject(jid);
  14292. },
  14293. findJidFromResource: function (resource) {
  14294. return connection.emuc.findJidFromResource(resource);
  14295. },
  14296. getMembers: function () {
  14297. return connection.emuc.members;
  14298. },
  14299. getJidFromSSRC: function (ssrc) {
  14300. if(!connection)
  14301. return null;
  14302. return connection.emuc.ssrc2jid[ssrc];
  14303. },
  14304. getMUCJoined: function () {
  14305. return connection.emuc.joined;
  14306. },
  14307. getSessions: function () {
  14308. return connection.jingle.sessions;
  14309. }
  14310. };
  14311. module.exports = XMPP;
  14312. },{"../../service/RTC/StreamEventTypes":81,"../../service/UI/UIEvents":82,"../../service/xmpp/XMPPEvents":86,"./SDP":48,"./moderator":52,"./recording":53,"./strophe.emuc":54,"./strophe.jingle":55,"./strophe.logger":56,"./strophe.moderate":57,"./strophe.rayo":58,"./strophe.util":59,"events":87,"pako":62}],61:[function(require,module,exports){
  14313. // i18next, v1.7.7
  14314. // Copyright (c)2014 Jan Mühlemann (jamuhl).
  14315. // Distributed under MIT license
  14316. // http://i18next.com
  14317. (function() {
  14318. // add indexOf to non ECMA-262 standard compliant browsers
  14319. if (!Array.prototype.indexOf) {
  14320. Array.prototype.indexOf = function (searchElement /*, fromIndex */ ) {
  14321. "use strict";
  14322. if (this == null) {
  14323. throw new TypeError();
  14324. }
  14325. var t = Object(this);
  14326. var len = t.length >>> 0;
  14327. if (len === 0) {
  14328. return -1;
  14329. }
  14330. var n = 0;
  14331. if (arguments.length > 0) {
  14332. n = Number(arguments[1]);
  14333. if (n != n) { // shortcut for verifying if it's NaN
  14334. n = 0;
  14335. } else if (n != 0 && n != Infinity && n != -Infinity) {
  14336. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  14337. }
  14338. }
  14339. if (n >= len) {
  14340. return -1;
  14341. }
  14342. var k = n >= 0 ? n : Math.max(len - Math.abs(n), 0);
  14343. for (; k < len; k++) {
  14344. if (k in t && t[k] === searchElement) {
  14345. return k;
  14346. }
  14347. }
  14348. return -1;
  14349. }
  14350. }
  14351. // add lastIndexOf to non ECMA-262 standard compliant browsers
  14352. if (!Array.prototype.lastIndexOf) {
  14353. Array.prototype.lastIndexOf = function(searchElement /*, fromIndex*/) {
  14354. "use strict";
  14355. if (this == null) {
  14356. throw new TypeError();
  14357. }
  14358. var t = Object(this);
  14359. var len = t.length >>> 0;
  14360. if (len === 0) {
  14361. return -1;
  14362. }
  14363. var n = len;
  14364. if (arguments.length > 1) {
  14365. n = Number(arguments[1]);
  14366. if (n != n) {
  14367. n = 0;
  14368. } else if (n != 0 && n != (1 / 0) && n != -(1 / 0)) {
  14369. n = (n > 0 || -1) * Math.floor(Math.abs(n));
  14370. }
  14371. }
  14372. var k = n >= 0 ? Math.min(n, len - 1) : len - Math.abs(n);
  14373. for (; k >= 0; k--) {
  14374. if (k in t && t[k] === searchElement) {
  14375. return k;
  14376. }
  14377. }
  14378. return -1;
  14379. };
  14380. }
  14381. // Add string trim for IE8.
  14382. if (typeof String.prototype.trim !== 'function') {
  14383. String.prototype.trim = function() {
  14384. return this.replace(/^\s+|\s+$/g, '');
  14385. }
  14386. }
  14387. var root = this
  14388. , $ = root.jQuery || root.Zepto
  14389. , i18n = {}
  14390. , resStore = {}
  14391. , currentLng
  14392. , replacementCounter = 0
  14393. , languages = []
  14394. , initialized = false
  14395. , sync = {};
  14396. // Export the i18next object for **CommonJS**.
  14397. // If we're not in CommonJS, add `i18n` to the
  14398. // global object or to jquery.
  14399. if (typeof module !== 'undefined' && module.exports) {
  14400. if (!$) {
  14401. try {
  14402. $ = require('jquery');
  14403. } catch(e) {
  14404. // just ignore
  14405. }
  14406. }
  14407. if ($) {
  14408. $.i18n = $.i18n || i18n;
  14409. }
  14410. module.exports = i18n;
  14411. } else {
  14412. if ($) {
  14413. $.i18n = $.i18n || i18n;
  14414. }
  14415. root.i18n = root.i18n || i18n;
  14416. }
  14417. sync = {
  14418. load: function(lngs, options, cb) {
  14419. if (options.useLocalStorage) {
  14420. sync._loadLocal(lngs, options, function(err, store) {
  14421. var missingLngs = [];
  14422. for (var i = 0, len = lngs.length; i < len; i++) {
  14423. if (!store[lngs[i]]) missingLngs.push(lngs[i]);
  14424. }
  14425. if (missingLngs.length > 0) {
  14426. sync._fetch(missingLngs, options, function(err, fetched) {
  14427. f.extend(store, fetched);
  14428. sync._storeLocal(fetched);
  14429. cb(null, store);
  14430. });
  14431. } else {
  14432. cb(null, store);
  14433. }
  14434. });
  14435. } else {
  14436. sync._fetch(lngs, options, function(err, store){
  14437. cb(null, store);
  14438. });
  14439. }
  14440. },
  14441. _loadLocal: function(lngs, options, cb) {
  14442. var store = {}
  14443. , nowMS = new Date().getTime();
  14444. if(window.localStorage) {
  14445. var todo = lngs.length;
  14446. f.each(lngs, function(key, lng) {
  14447. var local = window.localStorage.getItem('res_' + lng);
  14448. if (local) {
  14449. local = JSON.parse(local);
  14450. if (local.i18nStamp && local.i18nStamp + options.localStorageExpirationTime > nowMS) {
  14451. store[lng] = local;
  14452. }
  14453. }
  14454. todo--; // wait for all done befor callback
  14455. if (todo === 0) cb(null, store);
  14456. });
  14457. }
  14458. },
  14459. _storeLocal: function(store) {
  14460. if(window.localStorage) {
  14461. for (var m in store) {
  14462. store[m].i18nStamp = new Date().getTime();
  14463. f.localStorage.setItem('res_' + m, JSON.stringify(store[m]));
  14464. }
  14465. }
  14466. return;
  14467. },
  14468. _fetch: function(lngs, options, cb) {
  14469. var ns = options.ns
  14470. , store = {};
  14471. if (!options.dynamicLoad) {
  14472. var todo = ns.namespaces.length * lngs.length
  14473. , errors;
  14474. // load each file individual
  14475. f.each(ns.namespaces, function(nsIndex, nsValue) {
  14476. f.each(lngs, function(lngIndex, lngValue) {
  14477. // Call this once our translation has returned.
  14478. var loadComplete = function(err, data) {
  14479. if (err) {
  14480. errors = errors || [];
  14481. errors.push(err);
  14482. }
  14483. store[lngValue] = store[lngValue] || {};
  14484. store[lngValue][nsValue] = data;
  14485. todo--; // wait for all done befor callback
  14486. if (todo === 0) cb(errors, store);
  14487. };
  14488. if(typeof options.customLoad == 'function'){
  14489. // Use the specified custom callback.
  14490. options.customLoad(lngValue, nsValue, options, loadComplete);
  14491. } else {
  14492. //~ // Use our inbuilt sync.
  14493. sync._fetchOne(lngValue, nsValue, options, loadComplete);
  14494. }
  14495. });
  14496. });
  14497. } else {
  14498. // Call this once our translation has returned.
  14499. var loadComplete = function(err, data) {
  14500. cb(null, data);
  14501. };
  14502. if(typeof options.customLoad == 'function'){
  14503. // Use the specified custom callback.
  14504. options.customLoad(lngs, ns.namespaces, options, loadComplete);
  14505. } else {
  14506. var url = applyReplacement(options.resGetPath, { lng: lngs.join('+'), ns: ns.namespaces.join('+') });
  14507. // load all needed stuff once
  14508. f.ajax({
  14509. url: url,
  14510. success: function(data, status, xhr) {
  14511. f.log('loaded: ' + url);
  14512. loadComplete(null, data);
  14513. },
  14514. error : function(xhr, status, error) {
  14515. f.log('failed loading: ' + url);
  14516. loadComplete('failed loading resource.json error: ' + error);
  14517. },
  14518. dataType: "json",
  14519. async : options.getAsync
  14520. });
  14521. }
  14522. }
  14523. },
  14524. _fetchOne: function(lng, ns, options, done) {
  14525. var url = applyReplacement(options.resGetPath, { lng: lng, ns: ns });
  14526. f.ajax({
  14527. url: url,
  14528. success: function(data, status, xhr) {
  14529. f.log('loaded: ' + url);
  14530. done(null, data);
  14531. },
  14532. error : function(xhr, status, error) {
  14533. if ((status && status == 200) || (xhr && xhr.status && xhr.status == 200)) {
  14534. // file loaded but invalid json, stop waste time !
  14535. f.error('There is a typo in: ' + url);
  14536. } else if ((status && status == 404) || (xhr && xhr.status && xhr.status == 404)) {
  14537. f.log('Does not exist: ' + url);
  14538. } else {
  14539. var theStatus = status ? status : ((xhr && xhr.status) ? xhr.status : null);
  14540. f.log(theStatus + ' when loading ' + url);
  14541. }
  14542. done(error, {});
  14543. },
  14544. dataType: "json",
  14545. async : options.getAsync
  14546. });
  14547. },
  14548. postMissing: function(lng, ns, key, defaultValue, lngs) {
  14549. var payload = {};
  14550. payload[key] = defaultValue;
  14551. var urls = [];
  14552. if (o.sendMissingTo === 'fallback' && o.fallbackLng[0] !== false) {
  14553. for (var i = 0; i < o.fallbackLng.length; i++) {
  14554. urls.push({lng: o.fallbackLng[i], url: applyReplacement(o.resPostPath, { lng: o.fallbackLng[i], ns: ns })});
  14555. }
  14556. } else if (o.sendMissingTo === 'current' || (o.sendMissingTo === 'fallback' && o.fallbackLng[0] === false) ) {
  14557. urls.push({lng: lng, url: applyReplacement(o.resPostPath, { lng: lng, ns: ns })});
  14558. } else if (o.sendMissingTo === 'all') {
  14559. for (var i = 0, l = lngs.length; i < l; i++) {
  14560. urls.push({lng: lngs[i], url: applyReplacement(o.resPostPath, { lng: lngs[i], ns: ns })});
  14561. }
  14562. }
  14563. for (var y = 0, len = urls.length; y < len; y++) {
  14564. var item = urls[y];
  14565. f.ajax({
  14566. url: item.url,
  14567. type: o.sendType,
  14568. data: payload,
  14569. success: function(data, status, xhr) {
  14570. f.log('posted missing key \'' + key + '\' to: ' + item.url);
  14571. // add key to resStore
  14572. var keys = key.split('.');
  14573. var x = 0;
  14574. var value = resStore[item.lng][ns];
  14575. while (keys[x]) {
  14576. if (x === keys.length - 1) {
  14577. value = value[keys[x]] = defaultValue;
  14578. } else {
  14579. value = value[keys[x]] = value[keys[x]] || {};
  14580. }
  14581. x++;
  14582. }
  14583. },
  14584. error : function(xhr, status, error) {
  14585. f.log('failed posting missing key \'' + key + '\' to: ' + item.url);
  14586. },
  14587. dataType: "json",
  14588. async : o.postAsync
  14589. });
  14590. }
  14591. },
  14592. reload: reload
  14593. };
  14594. // defaults
  14595. var o = {
  14596. lng: undefined,
  14597. load: 'all',
  14598. preload: [],
  14599. lowerCaseLng: false,
  14600. returnObjectTrees: false,
  14601. fallbackLng: ['dev'],
  14602. fallbackNS: [],
  14603. detectLngQS: 'setLng',
  14604. detectLngFromLocalStorage: false,
  14605. ns: 'translation',
  14606. fallbackOnNull: true,
  14607. fallbackOnEmpty: false,
  14608. fallbackToDefaultNS: false,
  14609. nsseparator: ':',
  14610. keyseparator: '.',
  14611. selectorAttr: 'data-i18n',
  14612. debug: false,
  14613. resGetPath: 'locales/__lng__/__ns__.json',
  14614. resPostPath: 'locales/add/__lng__/__ns__',
  14615. getAsync: true,
  14616. postAsync: true,
  14617. resStore: undefined,
  14618. useLocalStorage: false,
  14619. localStorageExpirationTime: 7*24*60*60*1000,
  14620. dynamicLoad: false,
  14621. sendMissing: false,
  14622. sendMissingTo: 'fallback', // current | all
  14623. sendType: 'POST',
  14624. interpolationPrefix: '__',
  14625. interpolationSuffix: '__',
  14626. defaultVariables: false,
  14627. reusePrefix: '$t(',
  14628. reuseSuffix: ')',
  14629. pluralSuffix: '_plural',
  14630. pluralNotFound: ['plural_not_found', Math.random()].join(''),
  14631. contextNotFound: ['context_not_found', Math.random()].join(''),
  14632. escapeInterpolation: false,
  14633. indefiniteSuffix: '_indefinite',
  14634. indefiniteNotFound: ['indefinite_not_found', Math.random()].join(''),
  14635. setJqueryExt: true,
  14636. defaultValueFromContent: true,
  14637. useDataAttrOptions: false,
  14638. cookieExpirationTime: undefined,
  14639. useCookie: true,
  14640. cookieName: 'i18next',
  14641. cookieDomain: undefined,
  14642. objectTreeKeyHandler: undefined,
  14643. postProcess: undefined,
  14644. parseMissingKey: undefined,
  14645. missingKeyHandler: sync.postMissing,
  14646. shortcutFunction: 'sprintf' // or: defaultValue
  14647. };
  14648. function _extend(target, source) {
  14649. if (!source || typeof source === 'function') {
  14650. return target;
  14651. }
  14652. for (var attr in source) { target[attr] = source[attr]; }
  14653. return target;
  14654. }
  14655. function _deepExtend(target, source) {
  14656. for (var prop in source)
  14657. if (prop in target)
  14658. _deepExtend(target[prop], source[prop]);
  14659. else
  14660. target[prop] = source[prop];
  14661. return target;
  14662. }
  14663. function _each(object, callback, args) {
  14664. var name, i = 0,
  14665. length = object.length,
  14666. isObj = length === undefined || Object.prototype.toString.apply(object) !== '[object Array]' || typeof object === "function";
  14667. if (args) {
  14668. if (isObj) {
  14669. for (name in object) {
  14670. if (callback.apply(object[name], args) === false) {
  14671. break;
  14672. }
  14673. }
  14674. } else {
  14675. for ( ; i < length; ) {
  14676. if (callback.apply(object[i++], args) === false) {
  14677. break;
  14678. }
  14679. }
  14680. }
  14681. // A special, fast, case for the most common use of each
  14682. } else {
  14683. if (isObj) {
  14684. for (name in object) {
  14685. if (callback.call(object[name], name, object[name]) === false) {
  14686. break;
  14687. }
  14688. }
  14689. } else {
  14690. for ( ; i < length; ) {
  14691. if (callback.call(object[i], i, object[i++]) === false) {
  14692. break;
  14693. }
  14694. }
  14695. }
  14696. }
  14697. return object;
  14698. }
  14699. var _entityMap = {
  14700. "&": "&amp;",
  14701. "<": "&lt;",
  14702. ">": "&gt;",
  14703. '"': '&quot;',
  14704. "'": '&#39;',
  14705. "/": '&#x2F;'
  14706. };
  14707. function _escape(data) {
  14708. if (typeof data === 'string') {
  14709. return data.replace(/[&<>"'\/]/g, function (s) {
  14710. return _entityMap[s];
  14711. });
  14712. }else{
  14713. return data;
  14714. }
  14715. }
  14716. function _ajax(options) {
  14717. // v0.5.0 of https://github.com/goloroden/http.js
  14718. var getXhr = function (callback) {
  14719. // Use the native XHR object if the browser supports it.
  14720. if (window.XMLHttpRequest) {
  14721. return callback(null, new XMLHttpRequest());
  14722. } else if (window.ActiveXObject) {
  14723. // In Internet Explorer check for ActiveX versions of the XHR object.
  14724. try {
  14725. return callback(null, new ActiveXObject("Msxml2.XMLHTTP"));
  14726. } catch (e) {
  14727. return callback(null, new ActiveXObject("Microsoft.XMLHTTP"));
  14728. }
  14729. }
  14730. // If no XHR support was found, throw an error.
  14731. return callback(new Error());
  14732. };
  14733. var encodeUsingUrlEncoding = function (data) {
  14734. if(typeof data === 'string') {
  14735. return data;
  14736. }
  14737. var result = [];
  14738. for(var dataItem in data) {
  14739. if(data.hasOwnProperty(dataItem)) {
  14740. result.push(encodeURIComponent(dataItem) + '=' + encodeURIComponent(data[dataItem]));
  14741. }
  14742. }
  14743. return result.join('&');
  14744. };
  14745. var utf8 = function (text) {
  14746. text = text.replace(/\r\n/g, '\n');
  14747. var result = '';
  14748. for(var i = 0; i < text.length; i++) {
  14749. var c = text.charCodeAt(i);
  14750. if(c < 128) {
  14751. result += String.fromCharCode(c);
  14752. } else if((c > 127) && (c < 2048)) {
  14753. result += String.fromCharCode((c >> 6) | 192);
  14754. result += String.fromCharCode((c & 63) | 128);
  14755. } else {
  14756. result += String.fromCharCode((c >> 12) | 224);
  14757. result += String.fromCharCode(((c >> 6) & 63) | 128);
  14758. result += String.fromCharCode((c & 63) | 128);
  14759. }
  14760. }
  14761. return result;
  14762. };
  14763. var base64 = function (text) {
  14764. var keyStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
  14765. text = utf8(text);
  14766. var result = '',
  14767. chr1, chr2, chr3,
  14768. enc1, enc2, enc3, enc4,
  14769. i = 0;
  14770. do {
  14771. chr1 = text.charCodeAt(i++);
  14772. chr2 = text.charCodeAt(i++);
  14773. chr3 = text.charCodeAt(i++);
  14774. enc1 = chr1 >> 2;
  14775. enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
  14776. enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
  14777. enc4 = chr3 & 63;
  14778. if(isNaN(chr2)) {
  14779. enc3 = enc4 = 64;
  14780. } else if(isNaN(chr3)) {
  14781. enc4 = 64;
  14782. }
  14783. result +=
  14784. keyStr.charAt(enc1) +
  14785. keyStr.charAt(enc2) +
  14786. keyStr.charAt(enc3) +
  14787. keyStr.charAt(enc4);
  14788. chr1 = chr2 = chr3 = '';
  14789. enc1 = enc2 = enc3 = enc4 = '';
  14790. } while(i < text.length);
  14791. return result;
  14792. };
  14793. var mergeHeaders = function () {
  14794. // Use the first header object as base.
  14795. var result = arguments[0];
  14796. // Iterate through the remaining header objects and add them.
  14797. for(var i = 1; i < arguments.length; i++) {
  14798. var currentHeaders = arguments[i];
  14799. for(var header in currentHeaders) {
  14800. if(currentHeaders.hasOwnProperty(header)) {
  14801. result[header] = currentHeaders[header];
  14802. }
  14803. }
  14804. }
  14805. // Return the merged headers.
  14806. return result;
  14807. };
  14808. var ajax = function (method, url, options, callback) {
  14809. // Adjust parameters.
  14810. if(typeof options === 'function') {
  14811. callback = options;
  14812. options = {};
  14813. }
  14814. // Set default parameter values.
  14815. options.cache = options.cache || false;
  14816. options.data = options.data || {};
  14817. options.headers = options.headers || {};
  14818. options.jsonp = options.jsonp || false;
  14819. options.async = options.async === undefined ? true : options.async;
  14820. // Merge the various header objects.
  14821. var headers = mergeHeaders({
  14822. 'accept': '*/*',
  14823. 'content-type': 'application/x-www-form-urlencoded;charset=UTF-8'
  14824. }, ajax.headers, options.headers);
  14825. // Encode the data according to the content-type.
  14826. var payload;
  14827. if (headers['content-type'] === 'application/json') {
  14828. payload = JSON.stringify(options.data);
  14829. } else {
  14830. payload = encodeUsingUrlEncoding(options.data);
  14831. }
  14832. // Specially prepare GET requests: Setup the query string, handle caching and make a JSONP call
  14833. // if neccessary.
  14834. if(method === 'GET') {
  14835. // Setup the query string.
  14836. var queryString = [];
  14837. if(payload) {
  14838. queryString.push(payload);
  14839. payload = null;
  14840. }
  14841. // Handle caching.
  14842. if(!options.cache) {
  14843. queryString.push('_=' + (new Date()).getTime());
  14844. }
  14845. // If neccessary prepare the query string for a JSONP call.
  14846. if(options.jsonp) {
  14847. queryString.push('callback=' + options.jsonp);
  14848. queryString.push('jsonp=' + options.jsonp);
  14849. }
  14850. // Merge the query string and attach it to the url.
  14851. queryString = queryString.join('&');
  14852. if (queryString.length > 1) {
  14853. if (url.indexOf('?') > -1) {
  14854. url += '&' + queryString;
  14855. } else {
  14856. url += '?' + queryString;
  14857. }
  14858. }
  14859. // Make a JSONP call if neccessary.
  14860. if(options.jsonp) {
  14861. var head = document.getElementsByTagName('head')[0];
  14862. var script = document.createElement('script');
  14863. script.type = 'text/javascript';
  14864. script.src = url;
  14865. head.appendChild(script);
  14866. return;
  14867. }
  14868. }
  14869. // Since we got here, it is no JSONP request, so make a normal XHR request.
  14870. getXhr(function (err, xhr) {
  14871. if(err) return callback(err);
  14872. // Open the request.
  14873. xhr.open(method, url, options.async);
  14874. // Set the request headers.
  14875. for(var header in headers) {
  14876. if(headers.hasOwnProperty(header)) {
  14877. xhr.setRequestHeader(header, headers[header]);
  14878. }
  14879. }
  14880. // Handle the request events.
  14881. xhr.onreadystatechange = function () {
  14882. if(xhr.readyState === 4) {
  14883. var data = xhr.responseText || '';
  14884. // If no callback is given, return.
  14885. if(!callback) {
  14886. return;
  14887. }
  14888. // Return an object that provides access to the data as text and JSON.
  14889. callback(xhr.status, {
  14890. text: function () {
  14891. return data;
  14892. },
  14893. json: function () {
  14894. try {
  14895. return JSON.parse(data)
  14896. } catch (e) {
  14897. f.error('Can not parse JSON. URL: ' + url);
  14898. return {};
  14899. }
  14900. }
  14901. });
  14902. }
  14903. };
  14904. // Actually send the XHR request.
  14905. xhr.send(payload);
  14906. });
  14907. };
  14908. // Define the external interface.
  14909. var http = {
  14910. authBasic: function (username, password) {
  14911. ajax.headers['Authorization'] = 'Basic ' + base64(username + ':' + password);
  14912. },
  14913. connect: function (url, options, callback) {
  14914. return ajax('CONNECT', url, options, callback);
  14915. },
  14916. del: function (url, options, callback) {
  14917. return ajax('DELETE', url, options, callback);
  14918. },
  14919. get: function (url, options, callback) {
  14920. return ajax('GET', url, options, callback);
  14921. },
  14922. head: function (url, options, callback) {
  14923. return ajax('HEAD', url, options, callback);
  14924. },
  14925. headers: function (headers) {
  14926. ajax.headers = headers || {};
  14927. },
  14928. isAllowed: function (url, verb, callback) {
  14929. this.options(url, function (status, data) {
  14930. callback(data.text().indexOf(verb) !== -1);
  14931. });
  14932. },
  14933. options: function (url, options, callback) {
  14934. return ajax('OPTIONS', url, options, callback);
  14935. },
  14936. patch: function (url, options, callback) {
  14937. return ajax('PATCH', url, options, callback);
  14938. },
  14939. post: function (url, options, callback) {
  14940. return ajax('POST', url, options, callback);
  14941. },
  14942. put: function (url, options, callback) {
  14943. return ajax('PUT', url, options, callback);
  14944. },
  14945. trace: function (url, options, callback) {
  14946. return ajax('TRACE', url, options, callback);
  14947. }
  14948. };
  14949. var methode = options.type ? options.type.toLowerCase() : 'get';
  14950. http[methode](options.url, options, function (status, data) {
  14951. // file: protocol always gives status code 0, so check for data
  14952. if (status === 200 || (status === 0 && data.text())) {
  14953. options.success(data.json(), status, null);
  14954. } else {
  14955. options.error(data.text(), status, null);
  14956. }
  14957. });
  14958. }
  14959. var _cookie = {
  14960. create: function(name,value,minutes,domain) {
  14961. var expires;
  14962. if (minutes) {
  14963. var date = new Date();
  14964. date.setTime(date.getTime()+(minutes*60*1000));
  14965. expires = "; expires="+date.toGMTString();
  14966. }
  14967. else expires = "";
  14968. domain = (domain)? "domain="+domain+";" : "";
  14969. document.cookie = name+"="+value+expires+";"+domain+"path=/";
  14970. },
  14971. read: function(name) {
  14972. var nameEQ = name + "=";
  14973. var ca = document.cookie.split(';');
  14974. for(var i=0;i < ca.length;i++) {
  14975. var c = ca[i];
  14976. while (c.charAt(0)==' ') c = c.substring(1,c.length);
  14977. if (c.indexOf(nameEQ) === 0) return c.substring(nameEQ.length,c.length);
  14978. }
  14979. return null;
  14980. },
  14981. remove: function(name) {
  14982. this.create(name,"",-1);
  14983. }
  14984. };
  14985. var cookie_noop = {
  14986. create: function(name,value,minutes,domain) {},
  14987. read: function(name) { return null; },
  14988. remove: function(name) {}
  14989. };
  14990. // move dependent functions to a container so that
  14991. // they can be overriden easier in no jquery environment (node.js)
  14992. var f = {
  14993. extend: $ ? $.extend : _extend,
  14994. deepExtend: _deepExtend,
  14995. each: $ ? $.each : _each,
  14996. ajax: $ ? $.ajax : (typeof document !== 'undefined' ? _ajax : function() {}),
  14997. cookie: typeof document !== 'undefined' ? _cookie : cookie_noop,
  14998. detectLanguage: detectLanguage,
  14999. escape: _escape,
  15000. log: function(str) {
  15001. if (o.debug && typeof console !== "undefined") console.log(str);
  15002. },
  15003. error: function(str) {
  15004. if (typeof console !== "undefined") console.error(str);
  15005. },
  15006. getCountyIndexOfLng: function(lng) {
  15007. var lng_index = 0;
  15008. if (lng === 'nb-NO' || lng === 'nn-NO' || lng === 'nb-no' || lng === 'nn-no') lng_index = 1;
  15009. return lng_index;
  15010. },
  15011. toLanguages: function(lng) {
  15012. var log = this.log;
  15013. function applyCase(l) {
  15014. var ret = l;
  15015. if (typeof l === 'string' && l.indexOf('-') > -1) {
  15016. var parts = l.split('-');
  15017. ret = o.lowerCaseLng ?
  15018. parts[0].toLowerCase() + '-' + parts[1].toLowerCase() :
  15019. parts[0].toLowerCase() + '-' + parts[1].toUpperCase();
  15020. } else {
  15021. ret = o.lowerCaseLng ? l.toLowerCase() : l;
  15022. }
  15023. return ret;
  15024. }
  15025. var languages = [];
  15026. var whitelist = o.lngWhitelist || false;
  15027. var addLanguage = function(language){
  15028. //reject langs not whitelisted
  15029. if(!whitelist || whitelist.indexOf(language) > -1){
  15030. languages.push(language);
  15031. }else{
  15032. log('rejecting non-whitelisted language: ' + language);
  15033. }
  15034. };
  15035. if (typeof lng === 'string' && lng.indexOf('-') > -1) {
  15036. var parts = lng.split('-');
  15037. if (o.load !== 'unspecific') addLanguage(applyCase(lng));
  15038. if (o.load !== 'current') addLanguage(applyCase(parts[this.getCountyIndexOfLng(lng)]));
  15039. } else {
  15040. addLanguage(applyCase(lng));
  15041. }
  15042. for (var i = 0; i < o.fallbackLng.length; i++) {
  15043. if (languages.indexOf(o.fallbackLng[i]) === -1 && o.fallbackLng[i]) languages.push(applyCase(o.fallbackLng[i]));
  15044. }
  15045. return languages;
  15046. },
  15047. regexEscape: function(str) {
  15048. return str.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
  15049. },
  15050. regexReplacementEscape: function(strOrFn) {
  15051. if (typeof strOrFn === 'string') {
  15052. return strOrFn.replace(/\$/g, "$$$$");
  15053. } else {
  15054. return strOrFn;
  15055. }
  15056. },
  15057. localStorage: {
  15058. setItem: function(key, value) {
  15059. if (window.localStorage) {
  15060. try {
  15061. window.localStorage.setItem(key, value);
  15062. } catch (e) {
  15063. f.log('failed to set value for key "' + key + '" to localStorage.');
  15064. }
  15065. }
  15066. }
  15067. }
  15068. };
  15069. function init(options, cb) {
  15070. if (typeof options === 'function') {
  15071. cb = options;
  15072. options = {};
  15073. }
  15074. options = options || {};
  15075. // override defaults with passed in options
  15076. f.extend(o, options);
  15077. delete o.fixLng; /* passed in each time */
  15078. // override functions: .log(), .detectLanguage(), etc
  15079. if (o.functions) {
  15080. delete o.functions;
  15081. f.extend(f, options.functions);
  15082. }
  15083. // create namespace object if namespace is passed in as string
  15084. if (typeof o.ns == 'string') {
  15085. o.ns = { namespaces: [o.ns], defaultNs: o.ns};
  15086. }
  15087. // fallback namespaces
  15088. if (typeof o.fallbackNS == 'string') {
  15089. o.fallbackNS = [o.fallbackNS];
  15090. }
  15091. // fallback languages
  15092. if (typeof o.fallbackLng == 'string' || typeof o.fallbackLng == 'boolean') {
  15093. o.fallbackLng = [o.fallbackLng];
  15094. }
  15095. // escape prefix/suffix
  15096. o.interpolationPrefixEscaped = f.regexEscape(o.interpolationPrefix);
  15097. o.interpolationSuffixEscaped = f.regexEscape(o.interpolationSuffix);
  15098. if (!o.lng) o.lng = f.detectLanguage();
  15099. languages = f.toLanguages(o.lng);
  15100. currentLng = languages[0];
  15101. f.log('currentLng set to: ' + currentLng);
  15102. if (o.useCookie && f.cookie.read(o.cookieName) !== currentLng){ //cookie is unset or invalid
  15103. f.cookie.create(o.cookieName, currentLng, o.cookieExpirationTime, o.cookieDomain);
  15104. }
  15105. if (o.detectLngFromLocalStorage && typeof document !== 'undefined' && window.localStorage) {
  15106. f.localStorage.setItem('i18next_lng', currentLng);
  15107. }
  15108. var lngTranslate = translate;
  15109. if (options.fixLng) {
  15110. lngTranslate = function(key, options) {
  15111. options = options || {};
  15112. options.lng = options.lng || lngTranslate.lng;
  15113. return translate(key, options);
  15114. };
  15115. lngTranslate.lng = currentLng;
  15116. }
  15117. pluralExtensions.setCurrentLng(currentLng);
  15118. // add JQuery extensions
  15119. if ($ && o.setJqueryExt) addJqueryFunct();
  15120. // jQuery deferred
  15121. var deferred;
  15122. if ($ && $.Deferred) {
  15123. deferred = $.Deferred();
  15124. }
  15125. // return immidiatly if res are passed in
  15126. if (o.resStore) {
  15127. resStore = o.resStore;
  15128. initialized = true;
  15129. if (cb) cb(lngTranslate);
  15130. if (deferred) deferred.resolve(lngTranslate);
  15131. if (deferred) return deferred.promise();
  15132. return;
  15133. }
  15134. // languages to load
  15135. var lngsToLoad = f.toLanguages(o.lng);
  15136. if (typeof o.preload === 'string') o.preload = [o.preload];
  15137. for (var i = 0, l = o.preload.length; i < l; i++) {
  15138. var pres = f.toLanguages(o.preload[i]);
  15139. for (var y = 0, len = pres.length; y < len; y++) {
  15140. if (lngsToLoad.indexOf(pres[y]) < 0) {
  15141. lngsToLoad.push(pres[y]);
  15142. }
  15143. }
  15144. }
  15145. // else load them
  15146. i18n.sync.load(lngsToLoad, o, function(err, store) {
  15147. resStore = store;
  15148. initialized = true;
  15149. if (cb) cb(lngTranslate);
  15150. if (deferred) deferred.resolve(lngTranslate);
  15151. });
  15152. if (deferred) return deferred.promise();
  15153. }
  15154. function preload(lngs, cb) {
  15155. if (typeof lngs === 'string') lngs = [lngs];
  15156. for (var i = 0, l = lngs.length; i < l; i++) {
  15157. if (o.preload.indexOf(lngs[i]) < 0) {
  15158. o.preload.push(lngs[i]);
  15159. }
  15160. }
  15161. return init(cb);
  15162. }
  15163. function addResourceBundle(lng, ns, resources, deep) {
  15164. if (typeof ns !== 'string') {
  15165. resources = ns;
  15166. ns = o.ns.defaultNs;
  15167. } else if (o.ns.namespaces.indexOf(ns) < 0) {
  15168. o.ns.namespaces.push(ns);
  15169. }
  15170. resStore[lng] = resStore[lng] || {};
  15171. resStore[lng][ns] = resStore[lng][ns] || {};
  15172. if (deep) {
  15173. f.deepExtend(resStore[lng][ns], resources);
  15174. } else {
  15175. f.extend(resStore[lng][ns], resources);
  15176. }
  15177. }
  15178. function hasResourceBundle(lng, ns) {
  15179. if (typeof ns !== 'string') {
  15180. ns = o.ns.defaultNs;
  15181. }
  15182. resStore[lng] = resStore[lng] || {};
  15183. var res = resStore[lng][ns] || {};
  15184. var hasValues = false;
  15185. for(var prop in res) {
  15186. if (res.hasOwnProperty(prop)) {
  15187. hasValues = true;
  15188. }
  15189. }
  15190. return hasValues;
  15191. }
  15192. function removeResourceBundle(lng, ns) {
  15193. if (typeof ns !== 'string') {
  15194. ns = o.ns.defaultNs;
  15195. }
  15196. resStore[lng] = resStore[lng] || {};
  15197. resStore[lng][ns] = {};
  15198. }
  15199. function addResource(lng, ns, key, value) {
  15200. if (typeof ns !== 'string') {
  15201. resource = ns;
  15202. ns = o.ns.defaultNs;
  15203. } else if (o.ns.namespaces.indexOf(ns) < 0) {
  15204. o.ns.namespaces.push(ns);
  15205. }
  15206. resStore[lng] = resStore[lng] || {};
  15207. resStore[lng][ns] = resStore[lng][ns] || {};
  15208. var keys = key.split(o.keyseparator);
  15209. var x = 0;
  15210. var node = resStore[lng][ns];
  15211. var origRef = node;
  15212. while (keys[x]) {
  15213. if (x == keys.length - 1)
  15214. node[keys[x]] = value;
  15215. else {
  15216. if (node[keys[x]] == null)
  15217. node[keys[x]] = {};
  15218. node = node[keys[x]];
  15219. }
  15220. x++;
  15221. }
  15222. }
  15223. function addResources(lng, ns, resources) {
  15224. if (typeof ns !== 'string') {
  15225. resource = ns;
  15226. ns = o.ns.defaultNs;
  15227. } else if (o.ns.namespaces.indexOf(ns) < 0) {
  15228. o.ns.namespaces.push(ns);
  15229. }
  15230. for (var m in resources) {
  15231. if (typeof resources[m] === 'string') addResource(lng, ns, m, resources[m]);
  15232. }
  15233. }
  15234. function setDefaultNamespace(ns) {
  15235. o.ns.defaultNs = ns;
  15236. }
  15237. function loadNamespace(namespace, cb) {
  15238. loadNamespaces([namespace], cb);
  15239. }
  15240. function loadNamespaces(namespaces, cb) {
  15241. var opts = {
  15242. dynamicLoad: o.dynamicLoad,
  15243. resGetPath: o.resGetPath,
  15244. getAsync: o.getAsync,
  15245. customLoad: o.customLoad,
  15246. ns: { namespaces: namespaces, defaultNs: ''} /* new namespaces to load */
  15247. };
  15248. // languages to load
  15249. var lngsToLoad = f.toLanguages(o.lng);
  15250. if (typeof o.preload === 'string') o.preload = [o.preload];
  15251. for (var i = 0, l = o.preload.length; i < l; i++) {
  15252. var pres = f.toLanguages(o.preload[i]);
  15253. for (var y = 0, len = pres.length; y < len; y++) {
  15254. if (lngsToLoad.indexOf(pres[y]) < 0) {
  15255. lngsToLoad.push(pres[y]);
  15256. }
  15257. }
  15258. }
  15259. // check if we have to load
  15260. var lngNeedLoad = [];
  15261. for (var a = 0, lenA = lngsToLoad.length; a < lenA; a++) {
  15262. var needLoad = false;
  15263. var resSet = resStore[lngsToLoad[a]];
  15264. if (resSet) {
  15265. for (var b = 0, lenB = namespaces.length; b < lenB; b++) {
  15266. if (!resSet[namespaces[b]]) needLoad = true;
  15267. }
  15268. } else {
  15269. needLoad = true;
  15270. }
  15271. if (needLoad) lngNeedLoad.push(lngsToLoad[a]);
  15272. }
  15273. if (lngNeedLoad.length) {
  15274. i18n.sync._fetch(lngNeedLoad, opts, function(err, store) {
  15275. var todo = namespaces.length * lngNeedLoad.length;
  15276. // load each file individual
  15277. f.each(namespaces, function(nsIndex, nsValue) {
  15278. // append namespace to namespace array
  15279. if (o.ns.namespaces.indexOf(nsValue) < 0) {
  15280. o.ns.namespaces.push(nsValue);
  15281. }
  15282. f.each(lngNeedLoad, function(lngIndex, lngValue) {
  15283. resStore[lngValue] = resStore[lngValue] || {};
  15284. resStore[lngValue][nsValue] = store[lngValue][nsValue];
  15285. todo--; // wait for all done befor callback
  15286. if (todo === 0 && cb) {
  15287. if (o.useLocalStorage) i18n.sync._storeLocal(resStore);
  15288. cb();
  15289. }
  15290. });
  15291. });
  15292. });
  15293. } else {
  15294. if (cb) cb();
  15295. }
  15296. }
  15297. function setLng(lng, options, cb) {
  15298. if (typeof options === 'function') {
  15299. cb = options;
  15300. options = {};
  15301. } else if (!options) {
  15302. options = {};
  15303. }
  15304. options.lng = lng;
  15305. return init(options, cb);
  15306. }
  15307. function lng() {
  15308. return currentLng;
  15309. }
  15310. function reload(cb) {
  15311. resStore = {};
  15312. setLng(currentLng, cb);
  15313. }
  15314. function addJqueryFunct() {
  15315. // $.t shortcut
  15316. $.t = $.t || translate;
  15317. function parse(ele, key, options) {
  15318. if (key.length === 0) return;
  15319. var attr = 'text';
  15320. if (key.indexOf('[') === 0) {
  15321. var parts = key.split(']');
  15322. key = parts[1];
  15323. attr = parts[0].substr(1, parts[0].length-1);
  15324. }
  15325. if (key.indexOf(';') === key.length-1) {
  15326. key = key.substr(0, key.length-2);
  15327. }
  15328. var optionsToUse;
  15329. if (attr === 'html') {
  15330. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
  15331. ele.html($.t(key, optionsToUse));
  15332. } else if (attr === 'text') {
  15333. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.text() }, options) : options;
  15334. ele.text($.t(key, optionsToUse));
  15335. } else if (attr === 'prepend') {
  15336. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
  15337. ele.prepend($.t(key, optionsToUse));
  15338. } else if (attr === 'append') {
  15339. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.html() }, options) : options;
  15340. ele.append($.t(key, optionsToUse));
  15341. } else if (attr.indexOf("data-") === 0) {
  15342. var dataAttr = attr.substr(("data-").length);
  15343. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.data(dataAttr) }, options) : options;
  15344. var translated = $.t(key, optionsToUse);
  15345. //we change into the data cache
  15346. ele.data(dataAttr, translated);
  15347. //we change into the dom
  15348. ele.attr(attr, translated);
  15349. } else {
  15350. optionsToUse = o.defaultValueFromContent ? $.extend({ defaultValue: ele.attr(attr) }, options) : options;
  15351. ele.attr(attr, $.t(key, optionsToUse));
  15352. }
  15353. }
  15354. function localize(ele, options) {
  15355. var key = ele.attr(o.selectorAttr);
  15356. if (!key && typeof key !== 'undefined' && key !== false) key = ele.text() || ele.val();
  15357. if (!key) return;
  15358. var target = ele
  15359. , targetSelector = ele.data("i18n-target");
  15360. if (targetSelector) {
  15361. target = ele.find(targetSelector) || ele;
  15362. }
  15363. if (!options && o.useDataAttrOptions === true) {
  15364. options = ele.data("i18n-options");
  15365. }
  15366. options = options || {};
  15367. if (key.indexOf(';') >= 0) {
  15368. var keys = key.split(';');
  15369. $.each(keys, function(m, k) {
  15370. if (k !== '') parse(target, k, options);
  15371. });
  15372. } else {
  15373. parse(target, key, options);
  15374. }
  15375. if (o.useDataAttrOptions === true) ele.data("i18n-options", options);
  15376. }
  15377. // fn
  15378. $.fn.i18n = function (options) {
  15379. return this.each(function() {
  15380. // localize element itself
  15381. localize($(this), options);
  15382. // localize childs
  15383. var elements = $(this).find('[' + o.selectorAttr + ']');
  15384. elements.each(function() {
  15385. localize($(this), options);
  15386. });
  15387. });
  15388. };
  15389. }
  15390. function applyReplacement(str, replacementHash, nestedKey, options) {
  15391. if (!str) return str;
  15392. options = options || replacementHash; // first call uses replacement hash combined with options
  15393. if (str.indexOf(options.interpolationPrefix || o.interpolationPrefix) < 0) return str;
  15394. var prefix = options.interpolationPrefix ? f.regexEscape(options.interpolationPrefix) : o.interpolationPrefixEscaped
  15395. , suffix = options.interpolationSuffix ? f.regexEscape(options.interpolationSuffix) : o.interpolationSuffixEscaped
  15396. , unEscapingSuffix = 'HTML'+suffix;
  15397. var hash = replacementHash.replace && typeof replacementHash.replace === 'object' ? replacementHash.replace : replacementHash;
  15398. f.each(hash, function(key, value) {
  15399. var nextKey = nestedKey ? nestedKey + o.keyseparator + key : key;
  15400. if (typeof value === 'object' && value !== null) {
  15401. str = applyReplacement(str, value, nextKey, options);
  15402. } else {
  15403. if (options.escapeInterpolation || o.escapeInterpolation) {
  15404. str = str.replace(new RegExp([prefix, nextKey, unEscapingSuffix].join(''), 'g'), f.regexReplacementEscape(value));
  15405. str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.regexReplacementEscape(f.escape(value)));
  15406. } else {
  15407. str = str.replace(new RegExp([prefix, nextKey, suffix].join(''), 'g'), f.regexReplacementEscape(value));
  15408. }
  15409. // str = options.escapeInterpolation;
  15410. }
  15411. });
  15412. return str;
  15413. }
  15414. // append it to functions
  15415. f.applyReplacement = applyReplacement;
  15416. function applyReuse(translated, options) {
  15417. var comma = ',';
  15418. var options_open = '{';
  15419. var options_close = '}';
  15420. var opts = f.extend({}, options);
  15421. delete opts.postProcess;
  15422. while (translated.indexOf(o.reusePrefix) != -1) {
  15423. replacementCounter++;
  15424. if (replacementCounter > o.maxRecursion) { break; } // safety net for too much recursion
  15425. var index_of_opening = translated.lastIndexOf(o.reusePrefix);
  15426. var index_of_end_of_closing = translated.indexOf(o.reuseSuffix, index_of_opening) + o.reuseSuffix.length;
  15427. var token = translated.substring(index_of_opening, index_of_end_of_closing);
  15428. var token_without_symbols = token.replace(o.reusePrefix, '').replace(o.reuseSuffix, '');
  15429. if (index_of_end_of_closing <= index_of_opening) {
  15430. f.error('there is an missing closing in following translation value', translated);
  15431. return '';
  15432. }
  15433. if (token_without_symbols.indexOf(comma) != -1) {
  15434. var index_of_token_end_of_closing = token_without_symbols.indexOf(comma);
  15435. if (token_without_symbols.indexOf(options_open, index_of_token_end_of_closing) != -1 && token_without_symbols.indexOf(options_close, index_of_token_end_of_closing) != -1) {
  15436. var index_of_opts_opening = token_without_symbols.indexOf(options_open, index_of_token_end_of_closing);
  15437. var index_of_opts_end_of_closing = token_without_symbols.indexOf(options_close, index_of_opts_opening) + options_close.length;
  15438. try {
  15439. opts = f.extend(opts, JSON.parse(token_without_symbols.substring(index_of_opts_opening, index_of_opts_end_of_closing)));
  15440. token_without_symbols = token_without_symbols.substring(0, index_of_token_end_of_closing);
  15441. } catch (e) {
  15442. }
  15443. }
  15444. }
  15445. var translated_token = _translate(token_without_symbols, opts);
  15446. translated = translated.replace(token, f.regexReplacementEscape(translated_token));
  15447. }
  15448. return translated;
  15449. }
  15450. function hasContext(options) {
  15451. return (options.context && (typeof options.context == 'string' || typeof options.context == 'number'));
  15452. }
  15453. function needsPlural(options, lng) {
  15454. return (options.count !== undefined && typeof options.count != 'string'/* && pluralExtensions.needsPlural(lng, options.count)*/);
  15455. }
  15456. function needsIndefiniteArticle(options) {
  15457. return (options.indefinite_article !== undefined && typeof options.indefinite_article != 'string' && options.indefinite_article);
  15458. }
  15459. function exists(key, options) {
  15460. options = options || {};
  15461. var notFound = _getDefaultValue(key, options)
  15462. , found = _find(key, options);
  15463. return found !== undefined || found === notFound;
  15464. }
  15465. function translate(key, options) {
  15466. options = options || {};
  15467. if (!initialized) {
  15468. f.log('i18next not finished initialization. you might have called t function before loading resources finished.')
  15469. return options.defaultValue || '';
  15470. };
  15471. replacementCounter = 0;
  15472. return _translate.apply(null, arguments);
  15473. }
  15474. function _getDefaultValue(key, options) {
  15475. return (options.defaultValue !== undefined) ? options.defaultValue : key;
  15476. }
  15477. function _injectSprintfProcessor() {
  15478. var values = [];
  15479. // mh: build array from second argument onwards
  15480. for (var i = 1; i < arguments.length; i++) {
  15481. values.push(arguments[i]);
  15482. }
  15483. return {
  15484. postProcess: 'sprintf',
  15485. sprintf: values
  15486. };
  15487. }
  15488. function _translate(potentialKeys, options) {
  15489. if (options && typeof options !== 'object') {
  15490. if (o.shortcutFunction === 'sprintf') {
  15491. // mh: gettext like sprintf syntax found, automatically create sprintf processor
  15492. options = _injectSprintfProcessor.apply(null, arguments);
  15493. } else if (o.shortcutFunction === 'defaultValue') {
  15494. options = {
  15495. defaultValue: options
  15496. }
  15497. }
  15498. } else {
  15499. options = options || {};
  15500. }
  15501. if (typeof o.defaultVariables === 'object') {
  15502. options = f.extend({}, o.defaultVariables, options);
  15503. }
  15504. if (potentialKeys === undefined || potentialKeys === null || potentialKeys === '') return '';
  15505. if (typeof potentialKeys === 'string') {
  15506. potentialKeys = [potentialKeys];
  15507. }
  15508. var key = potentialKeys[0];
  15509. if (potentialKeys.length > 1) {
  15510. for (var i = 0; i < potentialKeys.length; i++) {
  15511. key = potentialKeys[i];
  15512. if (exists(key, options)) {
  15513. break;
  15514. }
  15515. }
  15516. }
  15517. var notFound = _getDefaultValue(key, options)
  15518. , found = _find(key, options)
  15519. , lngs = options.lng ? f.toLanguages(options.lng, options.fallbackLng) : languages
  15520. , ns = options.ns || o.ns.defaultNs
  15521. , parts;
  15522. // split ns and key
  15523. if (key.indexOf(o.nsseparator) > -1) {
  15524. parts = key.split(o.nsseparator);
  15525. ns = parts[0];
  15526. key = parts[1];
  15527. }
  15528. if (found === undefined && o.sendMissing && typeof o.missingKeyHandler === 'function') {
  15529. if (options.lng) {
  15530. o.missingKeyHandler(lngs[0], ns, key, notFound, lngs);
  15531. } else {
  15532. o.missingKeyHandler(o.lng, ns, key, notFound, lngs);
  15533. }
  15534. }
  15535. var postProcessor = options.postProcess || o.postProcess;
  15536. if (found !== undefined && postProcessor) {
  15537. if (postProcessors[postProcessor]) {
  15538. found = postProcessors[postProcessor](found, key, options);
  15539. }
  15540. }
  15541. // process notFound if function exists
  15542. var splitNotFound = notFound;
  15543. if (notFound.indexOf(o.nsseparator) > -1) {
  15544. parts = notFound.split(o.nsseparator);
  15545. splitNotFound = parts[1];
  15546. }
  15547. if (splitNotFound === key && o.parseMissingKey) {
  15548. notFound = o.parseMissingKey(notFound);
  15549. }
  15550. if (found === undefined) {
  15551. notFound = applyReplacement(notFound, options);
  15552. notFound = applyReuse(notFound, options);
  15553. if (postProcessor && postProcessors[postProcessor]) {
  15554. var val = _getDefaultValue(key, options);
  15555. found = postProcessors[postProcessor](val, key, options);
  15556. }
  15557. }
  15558. return (found !== undefined) ? found : notFound;
  15559. }
  15560. function _find(key, options) {
  15561. options = options || {};
  15562. var optionWithoutCount, translated
  15563. , notFound = _getDefaultValue(key, options)
  15564. , lngs = languages;
  15565. if (!resStore) { return notFound; } // no resStore to translate from
  15566. // CI mode
  15567. if (lngs[0].toLowerCase() === 'cimode') return notFound;
  15568. // passed in lng
  15569. if (options.lngs) lngs = options.lngs;
  15570. if (options.lng) {
  15571. lngs = f.toLanguages(options.lng, options.fallbackLng);
  15572. if (!resStore[lngs[0]]) {
  15573. var oldAsync = o.getAsync;
  15574. o.getAsync = false;
  15575. i18n.sync.load(lngs, o, function(err, store) {
  15576. f.extend(resStore, store);
  15577. o.getAsync = oldAsync;
  15578. });
  15579. }
  15580. }
  15581. var ns = options.ns || o.ns.defaultNs;
  15582. if (key.indexOf(o.nsseparator) > -1) {
  15583. var parts = key.split(o.nsseparator);
  15584. ns = parts[0];
  15585. key = parts[1];
  15586. }
  15587. if (hasContext(options)) {
  15588. optionWithoutCount = f.extend({}, options);
  15589. delete optionWithoutCount.context;
  15590. optionWithoutCount.defaultValue = o.contextNotFound;
  15591. var contextKey = ns + o.nsseparator + key + '_' + options.context;
  15592. translated = translate(contextKey, optionWithoutCount);
  15593. if (translated != o.contextNotFound) {
  15594. return applyReplacement(translated, { context: options.context }); // apply replacement for context only
  15595. } // else continue translation with original/nonContext key
  15596. }
  15597. if (needsPlural(options, lngs[0])) {
  15598. optionWithoutCount = f.extend({ lngs: [lngs[0]]}, options);
  15599. delete optionWithoutCount.count;
  15600. delete optionWithoutCount.lng;
  15601. optionWithoutCount.defaultValue = o.pluralNotFound;
  15602. var pluralKey;
  15603. if (!pluralExtensions.needsPlural(lngs[0], options.count)) {
  15604. pluralKey = ns + o.nsseparator + key;
  15605. } else {
  15606. pluralKey = ns + o.nsseparator + key + o.pluralSuffix;
  15607. var pluralExtension = pluralExtensions.get(lngs[0], options.count);
  15608. if (pluralExtension >= 0) {
  15609. pluralKey = pluralKey + '_' + pluralExtension;
  15610. } else if (pluralExtension === 1) {
  15611. pluralKey = ns + o.nsseparator + key; // singular
  15612. }
  15613. }
  15614. translated = translate(pluralKey, optionWithoutCount);
  15615. if (translated != o.pluralNotFound) {
  15616. return applyReplacement(translated, {
  15617. count: options.count,
  15618. interpolationPrefix: options.interpolationPrefix,
  15619. interpolationSuffix: options.interpolationSuffix
  15620. }); // apply replacement for count only
  15621. } else if (lngs.length > 1) {
  15622. // remove failed lng
  15623. var clone = lngs.slice();
  15624. clone.shift();
  15625. options = f.extend(options, { lngs: clone });
  15626. delete options.lng;
  15627. // retry with fallbacks
  15628. translated = translate(ns + o.nsseparator + key, options);
  15629. if (translated != o.pluralNotFound) return translated;
  15630. } else {
  15631. return translated;
  15632. }
  15633. }
  15634. if (needsIndefiniteArticle(options)) {
  15635. var optionsWithoutIndef = f.extend({}, options);
  15636. delete optionsWithoutIndef.indefinite_article;
  15637. optionsWithoutIndef.defaultValue = o.indefiniteNotFound;
  15638. // If we don't have a count, we want the indefinite, if we do have a count, and needsPlural is false
  15639. var indefiniteKey = ns + o.nsseparator + key + (((options.count && !needsPlural(options, lngs[0])) || !options.count) ? o.indefiniteSuffix : "");
  15640. translated = translate(indefiniteKey, optionsWithoutIndef);
  15641. if (translated != o.indefiniteNotFound) {
  15642. return translated;
  15643. }
  15644. }
  15645. var found;
  15646. var keys = key.split(o.keyseparator);
  15647. for (var i = 0, len = lngs.length; i < len; i++ ) {
  15648. if (found !== undefined) break;
  15649. var l = lngs[i];
  15650. var x = 0;
  15651. var value = resStore[l] && resStore[l][ns];
  15652. while (keys[x]) {
  15653. value = value && value[keys[x]];
  15654. x++;
  15655. }
  15656. if (value !== undefined) {
  15657. var valueType = Object.prototype.toString.apply(value);
  15658. if (typeof value === 'string') {
  15659. value = applyReplacement(value, options);
  15660. value = applyReuse(value, options);
  15661. } else if (valueType === '[object Array]' && !o.returnObjectTrees && !options.returnObjectTrees) {
  15662. value = value.join('\n');
  15663. value = applyReplacement(value, options);
  15664. value = applyReuse(value, options);
  15665. } else if (value === null && o.fallbackOnNull === true) {
  15666. value = undefined;
  15667. } else if (value !== null) {
  15668. if (!o.returnObjectTrees && !options.returnObjectTrees) {
  15669. if (o.objectTreeKeyHandler && typeof o.objectTreeKeyHandler == 'function') {
  15670. value = o.objectTreeKeyHandler(key, value, l, ns, options);
  15671. } else {
  15672. value = 'key \'' + ns + ':' + key + ' (' + l + ')\' ' +
  15673. 'returned an object instead of string.';
  15674. f.log(value);
  15675. }
  15676. } else if (valueType !== '[object Number]' && valueType !== '[object Function]' && valueType !== '[object RegExp]') {
  15677. var copy = (valueType === '[object Array]') ? [] : {}; // apply child translation on a copy
  15678. f.each(value, function(m) {
  15679. copy[m] = _translate(ns + o.nsseparator + key + o.keyseparator + m, options);
  15680. });
  15681. value = copy;
  15682. }
  15683. }
  15684. if (typeof value === 'string' && value.trim() === '' && o.fallbackOnEmpty === true)
  15685. value = undefined;
  15686. found = value;
  15687. }
  15688. }
  15689. if (found === undefined && !options.isFallbackLookup && (o.fallbackToDefaultNS === true || (o.fallbackNS && o.fallbackNS.length > 0))) {
  15690. // set flag for fallback lookup - avoid recursion
  15691. options.isFallbackLookup = true;
  15692. if (o.fallbackNS.length) {
  15693. for (var y = 0, lenY = o.fallbackNS.length; y < lenY; y++) {
  15694. found = _find(o.fallbackNS[y] + o.nsseparator + key, options);
  15695. if (found || (found==="" && o.fallbackOnEmpty === false)) {
  15696. /* compare value without namespace */
  15697. var foundValue = found.indexOf(o.nsseparator) > -1 ? found.split(o.nsseparator)[1] : found
  15698. , notFoundValue = notFound.indexOf(o.nsseparator) > -1 ? notFound.split(o.nsseparator)[1] : notFound;
  15699. if (foundValue !== notFoundValue) break;
  15700. }
  15701. }
  15702. } else {
  15703. found = _find(key, options); // fallback to default NS
  15704. }
  15705. options.isFallbackLookup = false;
  15706. }
  15707. return found;
  15708. }
  15709. function detectLanguage() {
  15710. var detectedLng;
  15711. var whitelist = o.lngWhitelist || [];
  15712. var userLngChoices = [];
  15713. // get from qs
  15714. var qsParm = [];
  15715. if (typeof window !== 'undefined') {
  15716. (function() {
  15717. var query = window.location.search.substring(1);
  15718. var params = query.split('&');
  15719. for (var i=0; i<params.length; i++) {
  15720. var pos = params[i].indexOf('=');
  15721. if (pos > 0) {
  15722. var key = params[i].substring(0,pos);
  15723. if (key == o.detectLngQS) {
  15724. userLngChoices.push(params[i].substring(pos+1));
  15725. }
  15726. }
  15727. }
  15728. })();
  15729. }
  15730. // get from cookie
  15731. if (o.useCookie && typeof document !== 'undefined') {
  15732. var c = f.cookie.read(o.cookieName);
  15733. if (c) userLngChoices.push(c);
  15734. }
  15735. // get from localStorage
  15736. if (o.detectLngFromLocalStorage && typeof window !== 'undefined' && window.localStorage) {
  15737. userLngChoices.push(window.localStorage.getItem('i18next_lng'));
  15738. }
  15739. // get from navigator
  15740. if (typeof navigator !== 'undefined') {
  15741. if (navigator.languages) { // chrome only; not an array, so can't use .push.apply instead of iterating
  15742. for (var i=0;i<navigator.languages.length;i++) {
  15743. userLngChoices.push(navigator.languages[i]);
  15744. }
  15745. }
  15746. if (navigator.userLanguage) {
  15747. userLngChoices.push(navigator.userLanguage);
  15748. }
  15749. if (navigator.language) {
  15750. userLngChoices.push(navigator.language);
  15751. }
  15752. }
  15753. (function() {
  15754. for (var i=0;i<userLngChoices.length;i++) {
  15755. var lng = userLngChoices[i];
  15756. if (lng.indexOf('-') > -1) {
  15757. var parts = lng.split('-');
  15758. lng = o.lowerCaseLng ?
  15759. parts[0].toLowerCase() + '-' + parts[1].toLowerCase() :
  15760. parts[0].toLowerCase() + '-' + parts[1].toUpperCase();
  15761. }
  15762. if (whitelist.length === 0 || whitelist.indexOf(lng) > -1) {
  15763. detectedLng = lng;
  15764. break;
  15765. }
  15766. }
  15767. })();
  15768. //fallback
  15769. if (!detectedLng){
  15770. detectedLng = o.fallbackLng[0];
  15771. }
  15772. return detectedLng;
  15773. }
  15774. // definition http://translate.sourceforge.net/wiki/l10n/pluralforms
  15775. /* [code, name, numbers, pluralsType] */
  15776. var _rules = [
  15777. ["ach", "Acholi", [1,2], 1],
  15778. ["af", "Afrikaans",[1,2], 2],
  15779. ["ak", "Akan", [1,2], 1],
  15780. ["am", "Amharic", [1,2], 1],
  15781. ["an", "Aragonese",[1,2], 2],
  15782. ["ar", "Arabic", [0,1,2,3,11,100],5],
  15783. ["arn", "Mapudungun",[1,2], 1],
  15784. ["ast", "Asturian", [1,2], 2],
  15785. ["ay", "Aymará", [1], 3],
  15786. ["az", "Azerbaijani",[1,2],2],
  15787. ["be", "Belarusian",[1,2,5],4],
  15788. ["bg", "Bulgarian",[1,2], 2],
  15789. ["bn", "Bengali", [1,2], 2],
  15790. ["bo", "Tibetan", [1], 3],
  15791. ["br", "Breton", [1,2], 1],
  15792. ["bs", "Bosnian", [1,2,5],4],
  15793. ["ca", "Catalan", [1,2], 2],
  15794. ["cgg", "Chiga", [1], 3],
  15795. ["cs", "Czech", [1,2,5],6],
  15796. ["csb", "Kashubian",[1,2,5],7],
  15797. ["cy", "Welsh", [1,2,3,8],8],
  15798. ["da", "Danish", [1,2], 2],
  15799. ["de", "German", [1,2], 2],
  15800. ["dev", "Development Fallback", [1,2], 2],
  15801. ["dz", "Dzongkha", [1], 3],
  15802. ["el", "Greek", [1,2], 2],
  15803. ["en", "English", [1,2], 2],
  15804. ["eo", "Esperanto",[1,2], 2],
  15805. ["es", "Spanish", [1,2], 2],
  15806. ["es_ar","Argentinean Spanish", [1,2], 2],
  15807. ["et", "Estonian", [1,2], 2],
  15808. ["eu", "Basque", [1,2], 2],
  15809. ["fa", "Persian", [1], 3],
  15810. ["fi", "Finnish", [1,2], 2],
  15811. ["fil", "Filipino", [1,2], 1],
  15812. ["fo", "Faroese", [1,2], 2],
  15813. ["fr", "French", [1,2], 9],
  15814. ["fur", "Friulian", [1,2], 2],
  15815. ["fy", "Frisian", [1,2], 2],
  15816. ["ga", "Irish", [1,2,3,7,11],10],
  15817. ["gd", "Scottish Gaelic",[1,2,3,20],11],
  15818. ["gl", "Galician", [1,2], 2],
  15819. ["gu", "Gujarati", [1,2], 2],
  15820. ["gun", "Gun", [1,2], 1],
  15821. ["ha", "Hausa", [1,2], 2],
  15822. ["he", "Hebrew", [1,2], 2],
  15823. ["hi", "Hindi", [1,2], 2],
  15824. ["hr", "Croatian", [1,2,5],4],
  15825. ["hu", "Hungarian",[1,2], 2],
  15826. ["hy", "Armenian", [1,2], 2],
  15827. ["ia", "Interlingua",[1,2],2],
  15828. ["id", "Indonesian",[1], 3],
  15829. ["is", "Icelandic",[1,2], 12],
  15830. ["it", "Italian", [1,2], 2],
  15831. ["ja", "Japanese", [1], 3],
  15832. ["jbo", "Lojban", [1], 3],
  15833. ["jv", "Javanese", [0,1], 13],
  15834. ["ka", "Georgian", [1], 3],
  15835. ["kk", "Kazakh", [1], 3],
  15836. ["km", "Khmer", [1], 3],
  15837. ["kn", "Kannada", [1,2], 2],
  15838. ["ko", "Korean", [1], 3],
  15839. ["ku", "Kurdish", [1,2], 2],
  15840. ["kw", "Cornish", [1,2,3,4],14],
  15841. ["ky", "Kyrgyz", [1], 3],
  15842. ["lb", "Letzeburgesch",[1,2],2],
  15843. ["ln", "Lingala", [1,2], 1],
  15844. ["lo", "Lao", [1], 3],
  15845. ["lt", "Lithuanian",[1,2,10],15],
  15846. ["lv", "Latvian", [1,2,0],16],
  15847. ["mai", "Maithili", [1,2], 2],
  15848. ["mfe", "Mauritian Creole",[1,2],1],
  15849. ["mg", "Malagasy", [1,2], 1],
  15850. ["mi", "Maori", [1,2], 1],
  15851. ["mk", "Macedonian",[1,2],17],
  15852. ["ml", "Malayalam",[1,2], 2],
  15853. ["mn", "Mongolian",[1,2], 2],
  15854. ["mnk", "Mandinka", [0,1,2],18],
  15855. ["mr", "Marathi", [1,2], 2],
  15856. ["ms", "Malay", [1], 3],
  15857. ["mt", "Maltese", [1,2,11,20],19],
  15858. ["nah", "Nahuatl", [1,2], 2],
  15859. ["nap", "Neapolitan",[1,2], 2],
  15860. ["nb", "Norwegian Bokmal",[1,2],2],
  15861. ["ne", "Nepali", [1,2], 2],
  15862. ["nl", "Dutch", [1,2], 2],
  15863. ["nn", "Norwegian Nynorsk",[1,2],2],
  15864. ["no", "Norwegian",[1,2], 2],
  15865. ["nso", "Northern Sotho",[1,2],2],
  15866. ["oc", "Occitan", [1,2], 1],
  15867. ["or", "Oriya", [2,1], 2],
  15868. ["pa", "Punjabi", [1,2], 2],
  15869. ["pap", "Papiamento",[1,2], 2],
  15870. ["pl", "Polish", [1,2,5],7],
  15871. ["pms", "Piemontese",[1,2], 2],
  15872. ["ps", "Pashto", [1,2], 2],
  15873. ["pt", "Portuguese",[1,2], 2],
  15874. ["pt_br","Brazilian Portuguese",[1,2], 2],
  15875. ["rm", "Romansh", [1,2], 2],
  15876. ["ro", "Romanian", [1,2,20],20],
  15877. ["ru", "Russian", [1,2,5],4],
  15878. ["sah", "Yakut", [1], 3],
  15879. ["sco", "Scots", [1,2], 2],
  15880. ["se", "Northern Sami",[1,2], 2],
  15881. ["si", "Sinhala", [1,2], 2],
  15882. ["sk", "Slovak", [1,2,5],6],
  15883. ["sl", "Slovenian",[5,1,2,3],21],
  15884. ["so", "Somali", [1,2], 2],
  15885. ["son", "Songhay", [1,2], 2],
  15886. ["sq", "Albanian", [1,2], 2],
  15887. ["sr", "Serbian", [1,2,5],4],
  15888. ["su", "Sundanese",[1], 3],
  15889. ["sv", "Swedish", [1,2], 2],
  15890. ["sw", "Swahili", [1,2], 2],
  15891. ["ta", "Tamil", [1,2], 2],
  15892. ["te", "Telugu", [1,2], 2],
  15893. ["tg", "Tajik", [1,2], 1],
  15894. ["th", "Thai", [1], 3],
  15895. ["ti", "Tigrinya", [1,2], 1],
  15896. ["tk", "Turkmen", [1,2], 2],
  15897. ["tr", "Turkish", [1,2], 1],
  15898. ["tt", "Tatar", [1], 3],
  15899. ["ug", "Uyghur", [1], 3],
  15900. ["uk", "Ukrainian",[1,2,5],4],
  15901. ["ur", "Urdu", [1,2], 2],
  15902. ["uz", "Uzbek", [1,2], 1],
  15903. ["vi", "Vietnamese",[1], 3],
  15904. ["wa", "Walloon", [1,2], 1],
  15905. ["wo", "Wolof", [1], 3],
  15906. ["yo", "Yoruba", [1,2], 2],
  15907. ["zh", "Chinese", [1], 3]
  15908. ];
  15909. var _rulesPluralsTypes = {
  15910. 1: function(n) {return Number(n > 1);},
  15911. 2: function(n) {return Number(n != 1);},
  15912. 3: function(n) {return 0;},
  15913. 4: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);},
  15914. 5: function(n) {return Number(n===0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 ? 4 : 5);},
  15915. 6: function(n) {return Number((n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2);},
  15916. 7: function(n) {return Number(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);},
  15917. 8: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n != 8 && n != 11) ? 2 : 3);},
  15918. 9: function(n) {return Number(n >= 2);},
  15919. 10: function(n) {return Number(n==1 ? 0 : n==2 ? 1 : n<7 ? 2 : n<11 ? 3 : 4) ;},
  15920. 11: function(n) {return Number((n==1 || n==11) ? 0 : (n==2 || n==12) ? 1 : (n > 2 && n < 20) ? 2 : 3);},
  15921. 12: function(n) {return Number(n%10!=1 || n%100==11);},
  15922. 13: function(n) {return Number(n !== 0);},
  15923. 14: function(n) {return Number((n==1) ? 0 : (n==2) ? 1 : (n == 3) ? 2 : 3);},
  15924. 15: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);},
  15925. 16: function(n) {return Number(n%10==1 && n%100!=11 ? 0 : n !== 0 ? 1 : 2);},
  15926. 17: function(n) {return Number(n==1 || n%10==1 ? 0 : 1);},
  15927. 18: function(n) {return Number(0 ? 0 : n==1 ? 1 : 2);},
  15928. 19: function(n) {return Number(n==1 ? 0 : n===0 || ( n%100>1 && n%100<11) ? 1 : (n%100>10 && n%100<20 ) ? 2 : 3);},
  15929. 20: function(n) {return Number(n==1 ? 0 : (n===0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2);},
  15930. 21: function(n) {return Number(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n%100==4 ? 3 : 0); }
  15931. };
  15932. var pluralExtensions = {
  15933. rules: (function () {
  15934. var l, rules = {};
  15935. for (l=_rules.length; l-- ;) {
  15936. rules[_rules[l][0]] = {
  15937. name: _rules[l][1],
  15938. numbers: _rules[l][2],
  15939. plurals: _rulesPluralsTypes[_rules[l][3]]
  15940. }
  15941. }
  15942. return rules;
  15943. }()),
  15944. // you can add your own pluralExtensions
  15945. addRule: function(lng, obj) {
  15946. pluralExtensions.rules[lng] = obj;
  15947. },
  15948. setCurrentLng: function(lng) {
  15949. if (!pluralExtensions.currentRule || pluralExtensions.currentRule.lng !== lng) {
  15950. var parts = lng.split('-');
  15951. pluralExtensions.currentRule = {
  15952. lng: lng,
  15953. rule: pluralExtensions.rules[parts[0]]
  15954. };
  15955. }
  15956. },
  15957. needsPlural: function(lng, count) {
  15958. var parts = lng.split('-');
  15959. var ext;
  15960. if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
  15961. ext = pluralExtensions.currentRule.rule;
  15962. } else {
  15963. ext = pluralExtensions.rules[parts[f.getCountyIndexOfLng(lng)]];
  15964. }
  15965. if (ext && ext.numbers.length <= 1) {
  15966. return false;
  15967. } else {
  15968. return this.get(lng, count) !== 1;
  15969. }
  15970. },
  15971. get: function(lng, count) {
  15972. var parts = lng.split('-');
  15973. function getResult(l, c) {
  15974. var ext;
  15975. if (pluralExtensions.currentRule && pluralExtensions.currentRule.lng === lng) {
  15976. ext = pluralExtensions.currentRule.rule;
  15977. } else {
  15978. ext = pluralExtensions.rules[l];
  15979. }
  15980. if (ext) {
  15981. var i;
  15982. if (ext.noAbs) {
  15983. i = ext.plurals(c);
  15984. } else {
  15985. i = ext.plurals(Math.abs(c));
  15986. }
  15987. var number = ext.numbers[i];
  15988. if (ext.numbers.length === 2 && ext.numbers[0] === 1) {
  15989. if (number === 2) {
  15990. number = -1; // regular plural
  15991. } else if (number === 1) {
  15992. number = 1; // singular
  15993. }
  15994. }//console.log(count + '-' + number);
  15995. return number;
  15996. } else {
  15997. return c === 1 ? '1' : '-1';
  15998. }
  15999. }
  16000. return getResult(parts[f.getCountyIndexOfLng(lng)], count);
  16001. }
  16002. };
  16003. var postProcessors = {};
  16004. var addPostProcessor = function(name, fc) {
  16005. postProcessors[name] = fc;
  16006. };
  16007. // sprintf support
  16008. var sprintf = (function() {
  16009. function get_type(variable) {
  16010. return Object.prototype.toString.call(variable).slice(8, -1).toLowerCase();
  16011. }
  16012. function str_repeat(input, multiplier) {
  16013. for (var output = []; multiplier > 0; output[--multiplier] = input) {/* do nothing */}
  16014. return output.join('');
  16015. }
  16016. var str_format = function() {
  16017. if (!str_format.cache.hasOwnProperty(arguments[0])) {
  16018. str_format.cache[arguments[0]] = str_format.parse(arguments[0]);
  16019. }
  16020. return str_format.format.call(null, str_format.cache[arguments[0]], arguments);
  16021. };
  16022. str_format.format = function(parse_tree, argv) {
  16023. var cursor = 1, tree_length = parse_tree.length, node_type = '', arg, output = [], i, k, match, pad, pad_character, pad_length;
  16024. for (i = 0; i < tree_length; i++) {
  16025. node_type = get_type(parse_tree[i]);
  16026. if (node_type === 'string') {
  16027. output.push(parse_tree[i]);
  16028. }
  16029. else if (node_type === 'array') {
  16030. match = parse_tree[i]; // convenience purposes only
  16031. if (match[2]) { // keyword argument
  16032. arg = argv[cursor];
  16033. for (k = 0; k < match[2].length; k++) {
  16034. if (!arg.hasOwnProperty(match[2][k])) {
  16035. throw(sprintf('[sprintf] property "%s" does not exist', match[2][k]));
  16036. }
  16037. arg = arg[match[2][k]];
  16038. }
  16039. }
  16040. else if (match[1]) { // positional argument (explicit)
  16041. arg = argv[match[1]];
  16042. }
  16043. else { // positional argument (implicit)
  16044. arg = argv[cursor++];
  16045. }
  16046. if (/[^s]/.test(match[8]) && (get_type(arg) != 'number')) {
  16047. throw(sprintf('[sprintf] expecting number but found %s', get_type(arg)));
  16048. }
  16049. switch (match[8]) {
  16050. case 'b': arg = arg.toString(2); break;
  16051. case 'c': arg = String.fromCharCode(arg); break;
  16052. case 'd': arg = parseInt(arg, 10); break;
  16053. case 'e': arg = match[7] ? arg.toExponential(match[7]) : arg.toExponential(); break;
  16054. case 'f': arg = match[7] ? parseFloat(arg).toFixed(match[7]) : parseFloat(arg); break;
  16055. case 'o': arg = arg.toString(8); break;
  16056. case 's': arg = ((arg = String(arg)) && match[7] ? arg.substring(0, match[7]) : arg); break;
  16057. case 'u': arg = Math.abs(arg); break;
  16058. case 'x': arg = arg.toString(16); break;
  16059. case 'X': arg = arg.toString(16).toUpperCase(); break;
  16060. }
  16061. arg = (/[def]/.test(match[8]) && match[3] && arg >= 0 ? '+'+ arg : arg);
  16062. pad_character = match[4] ? match[4] == '0' ? '0' : match[4].charAt(1) : ' ';
  16063. pad_length = match[6] - String(arg).length;
  16064. pad = match[6] ? str_repeat(pad_character, pad_length) : '';
  16065. output.push(match[5] ? arg + pad : pad + arg);
  16066. }
  16067. }
  16068. return output.join('');
  16069. };
  16070. str_format.cache = {};
  16071. str_format.parse = function(fmt) {
  16072. var _fmt = fmt, match = [], parse_tree = [], arg_names = 0;
  16073. while (_fmt) {
  16074. if ((match = /^[^\x25]+/.exec(_fmt)) !== null) {
  16075. parse_tree.push(match[0]);
  16076. }
  16077. else if ((match = /^\x25{2}/.exec(_fmt)) !== null) {
  16078. parse_tree.push('%');
  16079. }
  16080. else if ((match = /^\x25(?:([1-9]\d*)\$|\(([^\)]+)\))?(\+)?(0|'[^$])?(-)?(\d+)?(?:\.(\d+))?([b-fosuxX])/.exec(_fmt)) !== null) {
  16081. if (match[2]) {
  16082. arg_names |= 1;
  16083. var field_list = [], replacement_field = match[2], field_match = [];
  16084. if ((field_match = /^([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
  16085. field_list.push(field_match[1]);
  16086. while ((replacement_field = replacement_field.substring(field_match[0].length)) !== '') {
  16087. if ((field_match = /^\.([a-z_][a-z_\d]*)/i.exec(replacement_field)) !== null) {
  16088. field_list.push(field_match[1]);
  16089. }
  16090. else if ((field_match = /^\[(\d+)\]/.exec(replacement_field)) !== null) {
  16091. field_list.push(field_match[1]);
  16092. }
  16093. else {
  16094. throw('[sprintf] huh?');
  16095. }
  16096. }
  16097. }
  16098. else {
  16099. throw('[sprintf] huh?');
  16100. }
  16101. match[2] = field_list;
  16102. }
  16103. else {
  16104. arg_names |= 2;
  16105. }
  16106. if (arg_names === 3) {
  16107. throw('[sprintf] mixing positional and named placeholders is not (yet) supported');
  16108. }
  16109. parse_tree.push(match);
  16110. }
  16111. else {
  16112. throw('[sprintf] huh?');
  16113. }
  16114. _fmt = _fmt.substring(match[0].length);
  16115. }
  16116. return parse_tree;
  16117. };
  16118. return str_format;
  16119. })();
  16120. var vsprintf = function(fmt, argv) {
  16121. argv.unshift(fmt);
  16122. return sprintf.apply(null, argv);
  16123. };
  16124. addPostProcessor("sprintf", function(val, key, opts) {
  16125. if (!opts.sprintf) return val;
  16126. if (Object.prototype.toString.apply(opts.sprintf) === '[object Array]') {
  16127. return vsprintf(val, opts.sprintf);
  16128. } else if (typeof opts.sprintf === 'object') {
  16129. return sprintf(val, opts.sprintf);
  16130. }
  16131. return val;
  16132. });
  16133. // public api interface
  16134. i18n.init = init;
  16135. i18n.setLng = setLng;
  16136. i18n.preload = preload;
  16137. i18n.addResourceBundle = addResourceBundle;
  16138. i18n.hasResourceBundle = hasResourceBundle;
  16139. i18n.addResource = addResource;
  16140. i18n.addResources = addResources;
  16141. i18n.removeResourceBundle = removeResourceBundle;
  16142. i18n.loadNamespace = loadNamespace;
  16143. i18n.loadNamespaces = loadNamespaces;
  16144. i18n.setDefaultNamespace = setDefaultNamespace;
  16145. i18n.t = translate;
  16146. i18n.translate = translate;
  16147. i18n.exists = exists;
  16148. i18n.detectLanguage = f.detectLanguage;
  16149. i18n.pluralExtensions = pluralExtensions;
  16150. i18n.sync = sync;
  16151. i18n.functions = f;
  16152. i18n.lng = lng;
  16153. i18n.addPostProcessor = addPostProcessor;
  16154. i18n.options = o;
  16155. })();
  16156. },{"jquery":"jquery"}],62:[function(require,module,exports){
  16157. // Top level file is just a mixin of submodules & constants
  16158. 'use strict';
  16159. var assign = require('./lib/utils/common').assign;
  16160. var deflate = require('./lib/deflate');
  16161. var inflate = require('./lib/inflate');
  16162. var constants = require('./lib/zlib/constants');
  16163. var pako = {};
  16164. assign(pako, deflate, inflate, constants);
  16165. module.exports = pako;
  16166. },{"./lib/deflate":63,"./lib/inflate":64,"./lib/utils/common":65,"./lib/zlib/constants":68}],63:[function(require,module,exports){
  16167. 'use strict';
  16168. var zlib_deflate = require('./zlib/deflate.js');
  16169. var utils = require('./utils/common');
  16170. var strings = require('./utils/strings');
  16171. var msg = require('./zlib/messages');
  16172. var zstream = require('./zlib/zstream');
  16173. /* Public constants ==========================================================*/
  16174. /* ===========================================================================*/
  16175. var Z_NO_FLUSH = 0;
  16176. var Z_FINISH = 4;
  16177. var Z_OK = 0;
  16178. var Z_STREAM_END = 1;
  16179. var Z_DEFAULT_COMPRESSION = -1;
  16180. var Z_DEFAULT_STRATEGY = 0;
  16181. var Z_DEFLATED = 8;
  16182. /* ===========================================================================*/
  16183. /**
  16184. * class Deflate
  16185. *
  16186. * Generic JS-style wrapper for zlib calls. If you don't need
  16187. * streaming behaviour - use more simple functions: [[deflate]],
  16188. * [[deflateRaw]] and [[gzip]].
  16189. **/
  16190. /* internal
  16191. * Deflate.chunks -> Array
  16192. *
  16193. * Chunks of output data, if [[Deflate#onData]] not overriden.
  16194. **/
  16195. /**
  16196. * Deflate.result -> Uint8Array|Array
  16197. *
  16198. * Compressed result, generated by default [[Deflate#onData]]
  16199. * and [[Deflate#onEnd]] handlers. Filled after you push last chunk
  16200. * (call [[Deflate#push]] with `Z_FINISH` / `true` param).
  16201. **/
  16202. /**
  16203. * Deflate.err -> Number
  16204. *
  16205. * Error code after deflate finished. 0 (Z_OK) on success.
  16206. * You will not need it in real life, because deflate errors
  16207. * are possible only on wrong options or bad `onData` / `onEnd`
  16208. * custom handlers.
  16209. **/
  16210. /**
  16211. * Deflate.msg -> String
  16212. *
  16213. * Error message, if [[Deflate.err]] != 0
  16214. **/
  16215. /**
  16216. * new Deflate(options)
  16217. * - options (Object): zlib deflate options.
  16218. *
  16219. * Creates new deflator instance with specified params. Throws exception
  16220. * on bad params. Supported options:
  16221. *
  16222. * - `level`
  16223. * - `windowBits`
  16224. * - `memLevel`
  16225. * - `strategy`
  16226. *
  16227. * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
  16228. * for more information on these.
  16229. *
  16230. * Additional options, for internal needs:
  16231. *
  16232. * - `chunkSize` - size of generated data chunks (16K by default)
  16233. * - `raw` (Boolean) - do raw deflate
  16234. * - `gzip` (Boolean) - create gzip wrapper
  16235. * - `to` (String) - if equal to 'string', then result will be "binary string"
  16236. * (each char code [0..255])
  16237. * - `header` (Object) - custom header for gzip
  16238. * - `text` (Boolean) - true if compressed data believed to be text
  16239. * - `time` (Number) - modification time, unix timestamp
  16240. * - `os` (Number) - operation system code
  16241. * - `extra` (Array) - array of bytes with extra data (max 65536)
  16242. * - `name` (String) - file name (binary string)
  16243. * - `comment` (String) - comment (binary string)
  16244. * - `hcrc` (Boolean) - true if header crc should be added
  16245. *
  16246. * ##### Example:
  16247. *
  16248. * ```javascript
  16249. * var pako = require('pako')
  16250. * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
  16251. * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
  16252. *
  16253. * var deflate = new pako.Deflate({ level: 3});
  16254. *
  16255. * deflate.push(chunk1, false);
  16256. * deflate.push(chunk2, true); // true -> last chunk
  16257. *
  16258. * if (deflate.err) { throw new Error(deflate.err); }
  16259. *
  16260. * console.log(deflate.result);
  16261. * ```
  16262. **/
  16263. var Deflate = function(options) {
  16264. this.options = utils.assign({
  16265. level: Z_DEFAULT_COMPRESSION,
  16266. method: Z_DEFLATED,
  16267. chunkSize: 16384,
  16268. windowBits: 15,
  16269. memLevel: 8,
  16270. strategy: Z_DEFAULT_STRATEGY,
  16271. to: ''
  16272. }, options || {});
  16273. var opt = this.options;
  16274. if (opt.raw && (opt.windowBits > 0)) {
  16275. opt.windowBits = -opt.windowBits;
  16276. }
  16277. else if (opt.gzip && (opt.windowBits > 0) && (opt.windowBits < 16)) {
  16278. opt.windowBits += 16;
  16279. }
  16280. this.err = 0; // error code, if happens (0 = Z_OK)
  16281. this.msg = ''; // error message
  16282. this.ended = false; // used to avoid multiple onEnd() calls
  16283. this.chunks = []; // chunks of compressed data
  16284. this.strm = new zstream();
  16285. this.strm.avail_out = 0;
  16286. var status = zlib_deflate.deflateInit2(
  16287. this.strm,
  16288. opt.level,
  16289. opt.method,
  16290. opt.windowBits,
  16291. opt.memLevel,
  16292. opt.strategy
  16293. );
  16294. if (status !== Z_OK) {
  16295. throw new Error(msg[status]);
  16296. }
  16297. if (opt.header) {
  16298. zlib_deflate.deflateSetHeader(this.strm, opt.header);
  16299. }
  16300. };
  16301. /**
  16302. * Deflate#push(data[, mode]) -> Boolean
  16303. * - data (Uint8Array|Array|String): input data. Strings will be converted to
  16304. * utf8 byte sequence.
  16305. * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
  16306. * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
  16307. *
  16308. * Sends input data to deflate pipe, generating [[Deflate#onData]] calls with
  16309. * new compressed chunks. Returns `true` on success. The last data block must have
  16310. * mode Z_FINISH (or `true`). That flush internal pending buffers and call
  16311. * [[Deflate#onEnd]].
  16312. *
  16313. * On fail call [[Deflate#onEnd]] with error code and return false.
  16314. *
  16315. * We strongly recommend to use `Uint8Array` on input for best speed (output
  16316. * array format is detected automatically). Also, don't skip last param and always
  16317. * use the same type in your code (boolean or number). That will improve JS speed.
  16318. *
  16319. * For regular `Array`-s make sure all elements are [0..255].
  16320. *
  16321. * ##### Example
  16322. *
  16323. * ```javascript
  16324. * push(chunk, false); // push one of data chunks
  16325. * ...
  16326. * push(chunk, true); // push last chunk
  16327. * ```
  16328. **/
  16329. Deflate.prototype.push = function(data, mode) {
  16330. var strm = this.strm;
  16331. var chunkSize = this.options.chunkSize;
  16332. var status, _mode;
  16333. if (this.ended) { return false; }
  16334. _mode = (mode === ~~mode) ? mode : ((mode === true) ? Z_FINISH : Z_NO_FLUSH);
  16335. // Convert data if needed
  16336. if (typeof data === 'string') {
  16337. // If we need to compress text, change encoding to utf8.
  16338. strm.input = strings.string2buf(data);
  16339. } else {
  16340. strm.input = data;
  16341. }
  16342. strm.next_in = 0;
  16343. strm.avail_in = strm.input.length;
  16344. do {
  16345. if (strm.avail_out === 0) {
  16346. strm.output = new utils.Buf8(chunkSize);
  16347. strm.next_out = 0;
  16348. strm.avail_out = chunkSize;
  16349. }
  16350. status = zlib_deflate.deflate(strm, _mode); /* no bad return value */
  16351. if (status !== Z_STREAM_END && status !== Z_OK) {
  16352. this.onEnd(status);
  16353. this.ended = true;
  16354. return false;
  16355. }
  16356. if (strm.avail_out === 0 || (strm.avail_in === 0 && _mode === Z_FINISH)) {
  16357. if (this.options.to === 'string') {
  16358. this.onData(strings.buf2binstring(utils.shrinkBuf(strm.output, strm.next_out)));
  16359. } else {
  16360. this.onData(utils.shrinkBuf(strm.output, strm.next_out));
  16361. }
  16362. }
  16363. } while ((strm.avail_in > 0 || strm.avail_out === 0) && status !== Z_STREAM_END);
  16364. // Finalize on the last chunk.
  16365. if (_mode === Z_FINISH) {
  16366. status = zlib_deflate.deflateEnd(this.strm);
  16367. this.onEnd(status);
  16368. this.ended = true;
  16369. return status === Z_OK;
  16370. }
  16371. return true;
  16372. };
  16373. /**
  16374. * Deflate#onData(chunk) -> Void
  16375. * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
  16376. * on js engine support. When string output requested, each chunk
  16377. * will be string.
  16378. *
  16379. * By default, stores data blocks in `chunks[]` property and glue
  16380. * those in `onEnd`. Override this handler, if you need another behaviour.
  16381. **/
  16382. Deflate.prototype.onData = function(chunk) {
  16383. this.chunks.push(chunk);
  16384. };
  16385. /**
  16386. * Deflate#onEnd(status) -> Void
  16387. * - status (Number): deflate status. 0 (Z_OK) on success,
  16388. * other if not.
  16389. *
  16390. * Called once after you tell deflate that input stream complete
  16391. * or error happenned. By default - join collected chunks,
  16392. * free memory and fill `results` / `err` properties.
  16393. **/
  16394. Deflate.prototype.onEnd = function(status) {
  16395. // On success - join
  16396. if (status === Z_OK) {
  16397. if (this.options.to === 'string') {
  16398. this.result = this.chunks.join('');
  16399. } else {
  16400. this.result = utils.flattenChunks(this.chunks);
  16401. }
  16402. }
  16403. this.chunks = [];
  16404. this.err = status;
  16405. this.msg = this.strm.msg;
  16406. };
  16407. /**
  16408. * deflate(data[, options]) -> Uint8Array|Array|String
  16409. * - data (Uint8Array|Array|String): input data to compress.
  16410. * - options (Object): zlib deflate options.
  16411. *
  16412. * Compress `data` with deflate alrorythm and `options`.
  16413. *
  16414. * Supported options are:
  16415. *
  16416. * - level
  16417. * - windowBits
  16418. * - memLevel
  16419. * - strategy
  16420. *
  16421. * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
  16422. * for more information on these.
  16423. *
  16424. * Sugar (options):
  16425. *
  16426. * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
  16427. * negative windowBits implicitly.
  16428. * - `to` (String) - if equal to 'string', then result will be "binary string"
  16429. * (each char code [0..255])
  16430. *
  16431. * ##### Example:
  16432. *
  16433. * ```javascript
  16434. * var pako = require('pako')
  16435. * , data = Uint8Array([1,2,3,4,5,6,7,8,9]);
  16436. *
  16437. * console.log(pako.deflate(data));
  16438. * ```
  16439. **/
  16440. function deflate(input, options) {
  16441. var deflator = new Deflate(options);
  16442. deflator.push(input, true);
  16443. // That will never happens, if you don't cheat with options :)
  16444. if (deflator.err) { throw deflator.msg; }
  16445. return deflator.result;
  16446. }
  16447. /**
  16448. * deflateRaw(data[, options]) -> Uint8Array|Array|String
  16449. * - data (Uint8Array|Array|String): input data to compress.
  16450. * - options (Object): zlib deflate options.
  16451. *
  16452. * The same as [[deflate]], but creates raw data, without wrapper
  16453. * (header and adler32 crc).
  16454. **/
  16455. function deflateRaw(input, options) {
  16456. options = options || {};
  16457. options.raw = true;
  16458. return deflate(input, options);
  16459. }
  16460. /**
  16461. * gzip(data[, options]) -> Uint8Array|Array|String
  16462. * - data (Uint8Array|Array|String): input data to compress.
  16463. * - options (Object): zlib deflate options.
  16464. *
  16465. * The same as [[deflate]], but create gzip wrapper instead of
  16466. * deflate one.
  16467. **/
  16468. function gzip(input, options) {
  16469. options = options || {};
  16470. options.gzip = true;
  16471. return deflate(input, options);
  16472. }
  16473. exports.Deflate = Deflate;
  16474. exports.deflate = deflate;
  16475. exports.deflateRaw = deflateRaw;
  16476. exports.gzip = gzip;
  16477. },{"./utils/common":65,"./utils/strings":66,"./zlib/deflate.js":70,"./zlib/messages":75,"./zlib/zstream":77}],64:[function(require,module,exports){
  16478. 'use strict';
  16479. var zlib_inflate = require('./zlib/inflate.js');
  16480. var utils = require('./utils/common');
  16481. var strings = require('./utils/strings');
  16482. var c = require('./zlib/constants');
  16483. var msg = require('./zlib/messages');
  16484. var zstream = require('./zlib/zstream');
  16485. var gzheader = require('./zlib/gzheader');
  16486. /**
  16487. * class Inflate
  16488. *
  16489. * Generic JS-style wrapper for zlib calls. If you don't need
  16490. * streaming behaviour - use more simple functions: [[inflate]]
  16491. * and [[inflateRaw]].
  16492. **/
  16493. /* internal
  16494. * inflate.chunks -> Array
  16495. *
  16496. * Chunks of output data, if [[Inflate#onData]] not overriden.
  16497. **/
  16498. /**
  16499. * Inflate.result -> Uint8Array|Array|String
  16500. *
  16501. * Uncompressed result, generated by default [[Inflate#onData]]
  16502. * and [[Inflate#onEnd]] handlers. Filled after you push last chunk
  16503. * (call [[Inflate#push]] with `Z_FINISH` / `true` param).
  16504. **/
  16505. /**
  16506. * Inflate.err -> Number
  16507. *
  16508. * Error code after inflate finished. 0 (Z_OK) on success.
  16509. * Should be checked if broken data possible.
  16510. **/
  16511. /**
  16512. * Inflate.msg -> String
  16513. *
  16514. * Error message, if [[Inflate.err]] != 0
  16515. **/
  16516. /**
  16517. * new Inflate(options)
  16518. * - options (Object): zlib inflate options.
  16519. *
  16520. * Creates new inflator instance with specified params. Throws exception
  16521. * on bad params. Supported options:
  16522. *
  16523. * - `windowBits`
  16524. *
  16525. * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
  16526. * for more information on these.
  16527. *
  16528. * Additional options, for internal needs:
  16529. *
  16530. * - `chunkSize` - size of generated data chunks (16K by default)
  16531. * - `raw` (Boolean) - do raw inflate
  16532. * - `to` (String) - if equal to 'string', then result will be converted
  16533. * from utf8 to utf16 (javascript) string. When string output requested,
  16534. * chunk length can differ from `chunkSize`, depending on content.
  16535. *
  16536. * By default, when no options set, autodetect deflate/gzip data format via
  16537. * wrapper header.
  16538. *
  16539. * ##### Example:
  16540. *
  16541. * ```javascript
  16542. * var pako = require('pako')
  16543. * , chunk1 = Uint8Array([1,2,3,4,5,6,7,8,9])
  16544. * , chunk2 = Uint8Array([10,11,12,13,14,15,16,17,18,19]);
  16545. *
  16546. * var inflate = new pako.Inflate({ level: 3});
  16547. *
  16548. * inflate.push(chunk1, false);
  16549. * inflate.push(chunk2, true); // true -> last chunk
  16550. *
  16551. * if (inflate.err) { throw new Error(inflate.err); }
  16552. *
  16553. * console.log(inflate.result);
  16554. * ```
  16555. **/
  16556. var Inflate = function(options) {
  16557. this.options = utils.assign({
  16558. chunkSize: 16384,
  16559. windowBits: 0,
  16560. to: ''
  16561. }, options || {});
  16562. var opt = this.options;
  16563. // Force window size for `raw` data, if not set directly,
  16564. // because we have no header for autodetect.
  16565. if (opt.raw && (opt.windowBits >= 0) && (opt.windowBits < 16)) {
  16566. opt.windowBits = -opt.windowBits;
  16567. if (opt.windowBits === 0) { opt.windowBits = -15; }
  16568. }
  16569. // If `windowBits` not defined (and mode not raw) - set autodetect flag for gzip/deflate
  16570. if ((opt.windowBits >= 0) && (opt.windowBits < 16) &&
  16571. !(options && options.windowBits)) {
  16572. opt.windowBits += 32;
  16573. }
  16574. // Gzip header has no info about windows size, we can do autodetect only
  16575. // for deflate. So, if window size not set, force it to max when gzip possible
  16576. if ((opt.windowBits > 15) && (opt.windowBits < 48)) {
  16577. // bit 3 (16) -> gzipped data
  16578. // bit 4 (32) -> autodetect gzip/deflate
  16579. if ((opt.windowBits & 15) === 0) {
  16580. opt.windowBits |= 15;
  16581. }
  16582. }
  16583. this.err = 0; // error code, if happens (0 = Z_OK)
  16584. this.msg = ''; // error message
  16585. this.ended = false; // used to avoid multiple onEnd() calls
  16586. this.chunks = []; // chunks of compressed data
  16587. this.strm = new zstream();
  16588. this.strm.avail_out = 0;
  16589. var status = zlib_inflate.inflateInit2(
  16590. this.strm,
  16591. opt.windowBits
  16592. );
  16593. if (status !== c.Z_OK) {
  16594. throw new Error(msg[status]);
  16595. }
  16596. this.header = new gzheader();
  16597. zlib_inflate.inflateGetHeader(this.strm, this.header);
  16598. };
  16599. /**
  16600. * Inflate#push(data[, mode]) -> Boolean
  16601. * - data (Uint8Array|Array|String): input data
  16602. * - mode (Number|Boolean): 0..6 for corresponding Z_NO_FLUSH..Z_TREE modes.
  16603. * See constants. Skipped or `false` means Z_NO_FLUSH, `true` meansh Z_FINISH.
  16604. *
  16605. * Sends input data to inflate pipe, generating [[Inflate#onData]] calls with
  16606. * new output chunks. Returns `true` on success. The last data block must have
  16607. * mode Z_FINISH (or `true`). That flush internal pending buffers and call
  16608. * [[Inflate#onEnd]].
  16609. *
  16610. * On fail call [[Inflate#onEnd]] with error code and return false.
  16611. *
  16612. * We strongly recommend to use `Uint8Array` on input for best speed (output
  16613. * format is detected automatically). Also, don't skip last param and always
  16614. * use the same type in your code (boolean or number). That will improve JS speed.
  16615. *
  16616. * For regular `Array`-s make sure all elements are [0..255].
  16617. *
  16618. * ##### Example
  16619. *
  16620. * ```javascript
  16621. * push(chunk, false); // push one of data chunks
  16622. * ...
  16623. * push(chunk, true); // push last chunk
  16624. * ```
  16625. **/
  16626. Inflate.prototype.push = function(data, mode) {
  16627. var strm = this.strm;
  16628. var chunkSize = this.options.chunkSize;
  16629. var status, _mode;
  16630. var next_out_utf8, tail, utf8str;
  16631. if (this.ended) { return false; }
  16632. _mode = (mode === ~~mode) ? mode : ((mode === true) ? c.Z_FINISH : c.Z_NO_FLUSH);
  16633. // Convert data if needed
  16634. if (typeof data === 'string') {
  16635. // Only binary strings can be decompressed on practice
  16636. strm.input = strings.binstring2buf(data);
  16637. } else {
  16638. strm.input = data;
  16639. }
  16640. strm.next_in = 0;
  16641. strm.avail_in = strm.input.length;
  16642. do {
  16643. if (strm.avail_out === 0) {
  16644. strm.output = new utils.Buf8(chunkSize);
  16645. strm.next_out = 0;
  16646. strm.avail_out = chunkSize;
  16647. }
  16648. status = zlib_inflate.inflate(strm, c.Z_NO_FLUSH); /* no bad return value */
  16649. if (status !== c.Z_STREAM_END && status !== c.Z_OK) {
  16650. this.onEnd(status);
  16651. this.ended = true;
  16652. return false;
  16653. }
  16654. if (strm.next_out) {
  16655. if (strm.avail_out === 0 || status === c.Z_STREAM_END || (strm.avail_in === 0 && _mode === c.Z_FINISH)) {
  16656. if (this.options.to === 'string') {
  16657. next_out_utf8 = strings.utf8border(strm.output, strm.next_out);
  16658. tail = strm.next_out - next_out_utf8;
  16659. utf8str = strings.buf2string(strm.output, next_out_utf8);
  16660. // move tail
  16661. strm.next_out = tail;
  16662. strm.avail_out = chunkSize - tail;
  16663. if (tail) { utils.arraySet(strm.output, strm.output, next_out_utf8, tail, 0); }
  16664. this.onData(utf8str);
  16665. } else {
  16666. this.onData(utils.shrinkBuf(strm.output, strm.next_out));
  16667. }
  16668. }
  16669. }
  16670. } while ((strm.avail_in > 0) && status !== c.Z_STREAM_END);
  16671. if (status === c.Z_STREAM_END) {
  16672. _mode = c.Z_FINISH;
  16673. }
  16674. // Finalize on the last chunk.
  16675. if (_mode === c.Z_FINISH) {
  16676. status = zlib_inflate.inflateEnd(this.strm);
  16677. this.onEnd(status);
  16678. this.ended = true;
  16679. return status === c.Z_OK;
  16680. }
  16681. return true;
  16682. };
  16683. /**
  16684. * Inflate#onData(chunk) -> Void
  16685. * - chunk (Uint8Array|Array|String): ouput data. Type of array depends
  16686. * on js engine support. When string output requested, each chunk
  16687. * will be string.
  16688. *
  16689. * By default, stores data blocks in `chunks[]` property and glue
  16690. * those in `onEnd`. Override this handler, if you need another behaviour.
  16691. **/
  16692. Inflate.prototype.onData = function(chunk) {
  16693. this.chunks.push(chunk);
  16694. };
  16695. /**
  16696. * Inflate#onEnd(status) -> Void
  16697. * - status (Number): inflate status. 0 (Z_OK) on success,
  16698. * other if not.
  16699. *
  16700. * Called once after you tell inflate that input stream complete
  16701. * or error happenned. By default - join collected chunks,
  16702. * free memory and fill `results` / `err` properties.
  16703. **/
  16704. Inflate.prototype.onEnd = function(status) {
  16705. // On success - join
  16706. if (status === c.Z_OK) {
  16707. if (this.options.to === 'string') {
  16708. // Glue & convert here, until we teach pako to send
  16709. // utf8 alligned strings to onData
  16710. this.result = this.chunks.join('');
  16711. } else {
  16712. this.result = utils.flattenChunks(this.chunks);
  16713. }
  16714. }
  16715. this.chunks = [];
  16716. this.err = status;
  16717. this.msg = this.strm.msg;
  16718. };
  16719. /**
  16720. * inflate(data[, options]) -> Uint8Array|Array|String
  16721. * - data (Uint8Array|Array|String): input data to decompress.
  16722. * - options (Object): zlib inflate options.
  16723. *
  16724. * Decompress `data` with inflate/ungzip and `options`. Autodetect
  16725. * format via wrapper header by default. That's why we don't provide
  16726. * separate `ungzip` method.
  16727. *
  16728. * Supported options are:
  16729. *
  16730. * - windowBits
  16731. *
  16732. * [http://zlib.net/manual.html#Advanced](http://zlib.net/manual.html#Advanced)
  16733. * for more information.
  16734. *
  16735. * Sugar (options):
  16736. *
  16737. * - `raw` (Boolean) - say that we work with raw stream, if you don't wish to specify
  16738. * negative windowBits implicitly.
  16739. * - `to` (String) - if equal to 'string', then result will be converted
  16740. * from utf8 to utf16 (javascript) string. When string output requested,
  16741. * chunk length can differ from `chunkSize`, depending on content.
  16742. *
  16743. *
  16744. * ##### Example:
  16745. *
  16746. * ```javascript
  16747. * var pako = require('pako')
  16748. * , input = pako.deflate([1,2,3,4,5,6,7,8,9])
  16749. * , output;
  16750. *
  16751. * try {
  16752. * output = pako.inflate(input);
  16753. * } catch (err)
  16754. * console.log(err);
  16755. * }
  16756. * ```
  16757. **/
  16758. function inflate(input, options) {
  16759. var inflator = new Inflate(options);
  16760. inflator.push(input, true);
  16761. // That will never happens, if you don't cheat with options :)
  16762. if (inflator.err) { throw inflator.msg; }
  16763. return inflator.result;
  16764. }
  16765. /**
  16766. * inflateRaw(data[, options]) -> Uint8Array|Array|String
  16767. * - data (Uint8Array|Array|String): input data to decompress.
  16768. * - options (Object): zlib inflate options.
  16769. *
  16770. * The same as [[inflate]], but creates raw data, without wrapper
  16771. * (header and adler32 crc).
  16772. **/
  16773. function inflateRaw(input, options) {
  16774. options = options || {};
  16775. options.raw = true;
  16776. return inflate(input, options);
  16777. }
  16778. /**
  16779. * ungzip(data[, options]) -> Uint8Array|Array|String
  16780. * - data (Uint8Array|Array|String): input data to decompress.
  16781. * - options (Object): zlib inflate options.
  16782. *
  16783. * Just shortcut to [[inflate]], because it autodetects format
  16784. * by header.content. Done for convenience.
  16785. **/
  16786. exports.Inflate = Inflate;
  16787. exports.inflate = inflate;
  16788. exports.inflateRaw = inflateRaw;
  16789. exports.ungzip = inflate;
  16790. },{"./utils/common":65,"./utils/strings":66,"./zlib/constants":68,"./zlib/gzheader":71,"./zlib/inflate.js":73,"./zlib/messages":75,"./zlib/zstream":77}],65:[function(require,module,exports){
  16791. 'use strict';
  16792. var TYPED_OK = (typeof Uint8Array !== 'undefined') &&
  16793. (typeof Uint16Array !== 'undefined') &&
  16794. (typeof Int32Array !== 'undefined');
  16795. exports.assign = function (obj /*from1, from2, from3, ...*/) {
  16796. var sources = Array.prototype.slice.call(arguments, 1);
  16797. while (sources.length) {
  16798. var source = sources.shift();
  16799. if (!source) { continue; }
  16800. if (typeof(source) !== 'object') {
  16801. throw new TypeError(source + 'must be non-object');
  16802. }
  16803. for (var p in source) {
  16804. if (source.hasOwnProperty(p)) {
  16805. obj[p] = source[p];
  16806. }
  16807. }
  16808. }
  16809. return obj;
  16810. };
  16811. // reduce buffer size, avoiding mem copy
  16812. exports.shrinkBuf = function (buf, size) {
  16813. if (buf.length === size) { return buf; }
  16814. if (buf.subarray) { return buf.subarray(0, size); }
  16815. buf.length = size;
  16816. return buf;
  16817. };
  16818. var fnTyped = {
  16819. arraySet: function (dest, src, src_offs, len, dest_offs) {
  16820. if (src.subarray && dest.subarray) {
  16821. dest.set(src.subarray(src_offs, src_offs+len), dest_offs);
  16822. return;
  16823. }
  16824. // Fallback to ordinary array
  16825. for(var i=0; i<len; i++) {
  16826. dest[dest_offs + i] = src[src_offs + i];
  16827. }
  16828. },
  16829. // Join array of chunks to single array.
  16830. flattenChunks: function(chunks) {
  16831. var i, l, len, pos, chunk, result;
  16832. // calculate data length
  16833. len = 0;
  16834. for (i=0, l=chunks.length; i<l; i++) {
  16835. len += chunks[i].length;
  16836. }
  16837. // join chunks
  16838. result = new Uint8Array(len);
  16839. pos = 0;
  16840. for (i=0, l=chunks.length; i<l; i++) {
  16841. chunk = chunks[i];
  16842. result.set(chunk, pos);
  16843. pos += chunk.length;
  16844. }
  16845. return result;
  16846. }
  16847. };
  16848. var fnUntyped = {
  16849. arraySet: function (dest, src, src_offs, len, dest_offs) {
  16850. for(var i=0; i<len; i++) {
  16851. dest[dest_offs + i] = src[src_offs + i];
  16852. }
  16853. },
  16854. // Join array of chunks to single array.
  16855. flattenChunks: function(chunks) {
  16856. return [].concat.apply([], chunks);
  16857. }
  16858. };
  16859. // Enable/Disable typed arrays use, for testing
  16860. //
  16861. exports.setTyped = function (on) {
  16862. if (on) {
  16863. exports.Buf8 = Uint8Array;
  16864. exports.Buf16 = Uint16Array;
  16865. exports.Buf32 = Int32Array;
  16866. exports.assign(exports, fnTyped);
  16867. } else {
  16868. exports.Buf8 = Array;
  16869. exports.Buf16 = Array;
  16870. exports.Buf32 = Array;
  16871. exports.assign(exports, fnUntyped);
  16872. }
  16873. };
  16874. exports.setTyped(TYPED_OK);
  16875. },{}],66:[function(require,module,exports){
  16876. // String encode/decode helpers
  16877. 'use strict';
  16878. var utils = require('./common');
  16879. // Quick check if we can use fast array to bin string conversion
  16880. //
  16881. // - apply(Array) can fail on Android 2.2
  16882. // - apply(Uint8Array) can fail on iOS 5.1 Safary
  16883. //
  16884. var STR_APPLY_OK = true;
  16885. var STR_APPLY_UIA_OK = true;
  16886. try { String.fromCharCode.apply(null, [0]); } catch(__) { STR_APPLY_OK = false; }
  16887. try { String.fromCharCode.apply(null, new Uint8Array(1)); } catch(__) { STR_APPLY_UIA_OK = false; }
  16888. // Table with utf8 lengths (calculated by first byte of sequence)
  16889. // Note, that 5 & 6-byte values and some 4-byte values can not be represented in JS,
  16890. // because max possible codepoint is 0x10ffff
  16891. var _utf8len = new utils.Buf8(256);
  16892. for (var i=0; i<256; i++) {
  16893. _utf8len[i] = (i >= 252 ? 6 : i >= 248 ? 5 : i >= 240 ? 4 : i >= 224 ? 3 : i >= 192 ? 2 : 1);
  16894. }
  16895. _utf8len[254]=_utf8len[254]=1; // Invalid sequence start
  16896. // convert string to array (typed, when possible)
  16897. exports.string2buf = function (str) {
  16898. var buf, c, c2, m_pos, i, str_len = str.length, buf_len = 0;
  16899. // count binary size
  16900. for (m_pos = 0; m_pos < str_len; m_pos++) {
  16901. c = str.charCodeAt(m_pos);
  16902. if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
  16903. c2 = str.charCodeAt(m_pos+1);
  16904. if ((c2 & 0xfc00) === 0xdc00) {
  16905. c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
  16906. m_pos++;
  16907. }
  16908. }
  16909. buf_len += c < 0x80 ? 1 : c < 0x800 ? 2 : c < 0x10000 ? 3 : 4;
  16910. }
  16911. // allocate buffer
  16912. buf = new utils.Buf8(buf_len);
  16913. // convert
  16914. for (i=0, m_pos = 0; i < buf_len; m_pos++) {
  16915. c = str.charCodeAt(m_pos);
  16916. if ((c & 0xfc00) === 0xd800 && (m_pos+1 < str_len)) {
  16917. c2 = str.charCodeAt(m_pos+1);
  16918. if ((c2 & 0xfc00) === 0xdc00) {
  16919. c = 0x10000 + ((c - 0xd800) << 10) + (c2 - 0xdc00);
  16920. m_pos++;
  16921. }
  16922. }
  16923. if (c < 0x80) {
  16924. /* one byte */
  16925. buf[i++] = c;
  16926. } else if (c < 0x800) {
  16927. /* two bytes */
  16928. buf[i++] = 0xC0 | (c >>> 6);
  16929. buf[i++] = 0x80 | (c & 0x3f);
  16930. } else if (c < 0x10000) {
  16931. /* three bytes */
  16932. buf[i++] = 0xE0 | (c >>> 12);
  16933. buf[i++] = 0x80 | (c >>> 6 & 0x3f);
  16934. buf[i++] = 0x80 | (c & 0x3f);
  16935. } else {
  16936. /* four bytes */
  16937. buf[i++] = 0xf0 | (c >>> 18);
  16938. buf[i++] = 0x80 | (c >>> 12 & 0x3f);
  16939. buf[i++] = 0x80 | (c >>> 6 & 0x3f);
  16940. buf[i++] = 0x80 | (c & 0x3f);
  16941. }
  16942. }
  16943. return buf;
  16944. };
  16945. // Helper (used in 2 places)
  16946. function buf2binstring(buf, len) {
  16947. // use fallback for big arrays to avoid stack overflow
  16948. if (len < 65537) {
  16949. if ((buf.subarray && STR_APPLY_UIA_OK) || (!buf.subarray && STR_APPLY_OK)) {
  16950. return String.fromCharCode.apply(null, utils.shrinkBuf(buf, len));
  16951. }
  16952. }
  16953. var result = '';
  16954. for(var i=0; i < len; i++) {
  16955. result += String.fromCharCode(buf[i]);
  16956. }
  16957. return result;
  16958. }
  16959. // Convert byte array to binary string
  16960. exports.buf2binstring = function(buf) {
  16961. return buf2binstring(buf, buf.length);
  16962. };
  16963. // Convert binary string (typed, when possible)
  16964. exports.binstring2buf = function(str) {
  16965. var buf = new utils.Buf8(str.length);
  16966. for(var i=0, len=buf.length; i < len; i++) {
  16967. buf[i] = str.charCodeAt(i);
  16968. }
  16969. return buf;
  16970. };
  16971. // convert array to string
  16972. exports.buf2string = function (buf, max) {
  16973. var i, out, c, c_len;
  16974. var len = max || buf.length;
  16975. // Reserve max possible length (2 words per char)
  16976. // NB: by unknown reasons, Array is significantly faster for
  16977. // String.fromCharCode.apply than Uint16Array.
  16978. var utf16buf = new Array(len*2);
  16979. for (out=0, i=0; i<len;) {
  16980. c = buf[i++];
  16981. // quick process ascii
  16982. if (c < 0x80) { utf16buf[out++] = c; continue; }
  16983. c_len = _utf8len[c];
  16984. // skip 5 & 6 byte codes
  16985. if (c_len > 4) { utf16buf[out++] = 0xfffd; i += c_len-1; continue; }
  16986. // apply mask on first byte
  16987. c &= c_len === 2 ? 0x1f : c_len === 3 ? 0x0f : 0x07;
  16988. // join the rest
  16989. while (c_len > 1 && i < len) {
  16990. c = (c << 6) | (buf[i++] & 0x3f);
  16991. c_len--;
  16992. }
  16993. // terminated by end of string?
  16994. if (c_len > 1) { utf16buf[out++] = 0xfffd; continue; }
  16995. if (c < 0x10000) {
  16996. utf16buf[out++] = c;
  16997. } else {
  16998. c -= 0x10000;
  16999. utf16buf[out++] = 0xd800 | ((c >> 10) & 0x3ff);
  17000. utf16buf[out++] = 0xdc00 | (c & 0x3ff);
  17001. }
  17002. }
  17003. return buf2binstring(utf16buf, out);
  17004. };
  17005. // Calculate max possible position in utf8 buffer,
  17006. // that will not break sequence. If that's not possible
  17007. // - (very small limits) return max size as is.
  17008. //
  17009. // buf[] - utf8 bytes array
  17010. // max - length limit (mandatory);
  17011. exports.utf8border = function(buf, max) {
  17012. var pos;
  17013. max = max || buf.length;
  17014. if (max > buf.length) { max = buf.length; }
  17015. // go back from last position, until start of sequence found
  17016. pos = max-1;
  17017. while (pos >= 0 && (buf[pos] & 0xC0) === 0x80) { pos--; }
  17018. // Fuckup - very small and broken sequence,
  17019. // return max, because we should return something anyway.
  17020. if (pos < 0) { return max; }
  17021. // If we came to start of buffer - that means vuffer is too small,
  17022. // return max too.
  17023. if (pos === 0) { return max; }
  17024. return (pos + _utf8len[buf[pos]] > max) ? pos : max;
  17025. };
  17026. },{"./common":65}],67:[function(require,module,exports){
  17027. 'use strict';
  17028. // Note: adler32 takes 12% for level 0 and 2% for level 6.
  17029. // It doesn't worth to make additional optimizationa as in original.
  17030. // Small size is preferable.
  17031. function adler32(adler, buf, len, pos) {
  17032. var s1 = (adler & 0xffff) |0
  17033. , s2 = ((adler >>> 16) & 0xffff) |0
  17034. , n = 0;
  17035. while (len !== 0) {
  17036. // Set limit ~ twice less than 5552, to keep
  17037. // s2 in 31-bits, because we force signed ints.
  17038. // in other case %= will fail.
  17039. n = len > 2000 ? 2000 : len;
  17040. len -= n;
  17041. do {
  17042. s1 = (s1 + buf[pos++]) |0;
  17043. s2 = (s2 + s1) |0;
  17044. } while (--n);
  17045. s1 %= 65521;
  17046. s2 %= 65521;
  17047. }
  17048. return (s1 | (s2 << 16)) |0;
  17049. }
  17050. module.exports = adler32;
  17051. },{}],68:[function(require,module,exports){
  17052. module.exports = {
  17053. /* Allowed flush values; see deflate() and inflate() below for details */
  17054. Z_NO_FLUSH: 0,
  17055. Z_PARTIAL_FLUSH: 1,
  17056. Z_SYNC_FLUSH: 2,
  17057. Z_FULL_FLUSH: 3,
  17058. Z_FINISH: 4,
  17059. Z_BLOCK: 5,
  17060. Z_TREES: 6,
  17061. /* Return codes for the compression/decompression functions. Negative values
  17062. * are errors, positive values are used for special but normal events.
  17063. */
  17064. Z_OK: 0,
  17065. Z_STREAM_END: 1,
  17066. Z_NEED_DICT: 2,
  17067. Z_ERRNO: -1,
  17068. Z_STREAM_ERROR: -2,
  17069. Z_DATA_ERROR: -3,
  17070. //Z_MEM_ERROR: -4,
  17071. Z_BUF_ERROR: -5,
  17072. //Z_VERSION_ERROR: -6,
  17073. /* compression levels */
  17074. Z_NO_COMPRESSION: 0,
  17075. Z_BEST_SPEED: 1,
  17076. Z_BEST_COMPRESSION: 9,
  17077. Z_DEFAULT_COMPRESSION: -1,
  17078. Z_FILTERED: 1,
  17079. Z_HUFFMAN_ONLY: 2,
  17080. Z_RLE: 3,
  17081. Z_FIXED: 4,
  17082. Z_DEFAULT_STRATEGY: 0,
  17083. /* Possible values of the data_type field (though see inflate()) */
  17084. Z_BINARY: 0,
  17085. Z_TEXT: 1,
  17086. //Z_ASCII: 1, // = Z_TEXT (deprecated)
  17087. Z_UNKNOWN: 2,
  17088. /* The deflate compression method */
  17089. Z_DEFLATED: 8
  17090. //Z_NULL: null // Use -1 or null inline, depending on var type
  17091. };
  17092. },{}],69:[function(require,module,exports){
  17093. 'use strict';
  17094. // Note: we can't get significant speed boost here.
  17095. // So write code to minimize size - no pregenerated tables
  17096. // and array tools dependencies.
  17097. // Use ordinary array, since untyped makes no boost here
  17098. function makeTable() {
  17099. var c, table = [];
  17100. for(var n =0; n < 256; n++){
  17101. c = n;
  17102. for(var k =0; k < 8; k++){
  17103. c = ((c&1) ? (0xEDB88320 ^ (c >>> 1)) : (c >>> 1));
  17104. }
  17105. table[n] = c;
  17106. }
  17107. return table;
  17108. }
  17109. // Create table on load. Just 255 signed longs. Not a problem.
  17110. var crcTable = makeTable();
  17111. function crc32(crc, buf, len, pos) {
  17112. var t = crcTable
  17113. , end = pos + len;
  17114. crc = crc ^ (-1);
  17115. for (var i = pos; i < end; i++ ) {
  17116. crc = (crc >>> 8) ^ t[(crc ^ buf[i]) & 0xFF];
  17117. }
  17118. return (crc ^ (-1)); // >>> 0;
  17119. }
  17120. module.exports = crc32;
  17121. },{}],70:[function(require,module,exports){
  17122. 'use strict';
  17123. var utils = require('../utils/common');
  17124. var trees = require('./trees');
  17125. var adler32 = require('./adler32');
  17126. var crc32 = require('./crc32');
  17127. var msg = require('./messages');
  17128. /* Public constants ==========================================================*/
  17129. /* ===========================================================================*/
  17130. /* Allowed flush values; see deflate() and inflate() below for details */
  17131. var Z_NO_FLUSH = 0;
  17132. var Z_PARTIAL_FLUSH = 1;
  17133. //var Z_SYNC_FLUSH = 2;
  17134. var Z_FULL_FLUSH = 3;
  17135. var Z_FINISH = 4;
  17136. var Z_BLOCK = 5;
  17137. //var Z_TREES = 6;
  17138. /* Return codes for the compression/decompression functions. Negative values
  17139. * are errors, positive values are used for special but normal events.
  17140. */
  17141. var Z_OK = 0;
  17142. var Z_STREAM_END = 1;
  17143. //var Z_NEED_DICT = 2;
  17144. //var Z_ERRNO = -1;
  17145. var Z_STREAM_ERROR = -2;
  17146. var Z_DATA_ERROR = -3;
  17147. //var Z_MEM_ERROR = -4;
  17148. var Z_BUF_ERROR = -5;
  17149. //var Z_VERSION_ERROR = -6;
  17150. /* compression levels */
  17151. //var Z_NO_COMPRESSION = 0;
  17152. //var Z_BEST_SPEED = 1;
  17153. //var Z_BEST_COMPRESSION = 9;
  17154. var Z_DEFAULT_COMPRESSION = -1;
  17155. var Z_FILTERED = 1;
  17156. var Z_HUFFMAN_ONLY = 2;
  17157. var Z_RLE = 3;
  17158. var Z_FIXED = 4;
  17159. var Z_DEFAULT_STRATEGY = 0;
  17160. /* Possible values of the data_type field (though see inflate()) */
  17161. //var Z_BINARY = 0;
  17162. //var Z_TEXT = 1;
  17163. //var Z_ASCII = 1; // = Z_TEXT
  17164. var Z_UNKNOWN = 2;
  17165. /* The deflate compression method */
  17166. var Z_DEFLATED = 8;
  17167. /*============================================================================*/
  17168. var MAX_MEM_LEVEL = 9;
  17169. /* Maximum value for memLevel in deflateInit2 */
  17170. var MAX_WBITS = 15;
  17171. /* 32K LZ77 window */
  17172. var DEF_MEM_LEVEL = 8;
  17173. var LENGTH_CODES = 29;
  17174. /* number of length codes, not counting the special END_BLOCK code */
  17175. var LITERALS = 256;
  17176. /* number of literal bytes 0..255 */
  17177. var L_CODES = LITERALS + 1 + LENGTH_CODES;
  17178. /* number of Literal or Length codes, including the END_BLOCK code */
  17179. var D_CODES = 30;
  17180. /* number of distance codes */
  17181. var BL_CODES = 19;
  17182. /* number of codes used to transfer the bit lengths */
  17183. var HEAP_SIZE = 2*L_CODES + 1;
  17184. /* maximum heap size */
  17185. var MAX_BITS = 15;
  17186. /* All codes must not exceed MAX_BITS bits */
  17187. var MIN_MATCH = 3;
  17188. var MAX_MATCH = 258;
  17189. var MIN_LOOKAHEAD = (MAX_MATCH + MIN_MATCH + 1);
  17190. var PRESET_DICT = 0x20;
  17191. var INIT_STATE = 42;
  17192. var EXTRA_STATE = 69;
  17193. var NAME_STATE = 73;
  17194. var COMMENT_STATE = 91;
  17195. var HCRC_STATE = 103;
  17196. var BUSY_STATE = 113;
  17197. var FINISH_STATE = 666;
  17198. var BS_NEED_MORE = 1; /* block not completed, need more input or more output */
  17199. var BS_BLOCK_DONE = 2; /* block flush performed */
  17200. var BS_FINISH_STARTED = 3; /* finish started, need only more output at next deflate */
  17201. var BS_FINISH_DONE = 4; /* finish done, accept no more input or output */
  17202. var OS_CODE = 0x03; // Unix :) . Don't detect, use this default.
  17203. function err(strm, errorCode) {
  17204. strm.msg = msg[errorCode];
  17205. return errorCode;
  17206. }
  17207. function rank(f) {
  17208. return ((f) << 1) - ((f) > 4 ? 9 : 0);
  17209. }
  17210. function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
  17211. /* =========================================================================
  17212. * Flush as much pending output as possible. All deflate() output goes
  17213. * through this function so some applications may wish to modify it
  17214. * to avoid allocating a large strm->output buffer and copying into it.
  17215. * (See also read_buf()).
  17216. */
  17217. function flush_pending(strm) {
  17218. var s = strm.state;
  17219. //_tr_flush_bits(s);
  17220. var len = s.pending;
  17221. if (len > strm.avail_out) {
  17222. len = strm.avail_out;
  17223. }
  17224. if (len === 0) { return; }
  17225. utils.arraySet(strm.output, s.pending_buf, s.pending_out, len, strm.next_out);
  17226. strm.next_out += len;
  17227. s.pending_out += len;
  17228. strm.total_out += len;
  17229. strm.avail_out -= len;
  17230. s.pending -= len;
  17231. if (s.pending === 0) {
  17232. s.pending_out = 0;
  17233. }
  17234. }
  17235. function flush_block_only (s, last) {
  17236. trees._tr_flush_block(s, (s.block_start >= 0 ? s.block_start : -1), s.strstart - s.block_start, last);
  17237. s.block_start = s.strstart;
  17238. flush_pending(s.strm);
  17239. }
  17240. function put_byte(s, b) {
  17241. s.pending_buf[s.pending++] = b;
  17242. }
  17243. /* =========================================================================
  17244. * Put a short in the pending buffer. The 16-bit value is put in MSB order.
  17245. * IN assertion: the stream state is correct and there is enough room in
  17246. * pending_buf.
  17247. */
  17248. function putShortMSB(s, b) {
  17249. // put_byte(s, (Byte)(b >> 8));
  17250. // put_byte(s, (Byte)(b & 0xff));
  17251. s.pending_buf[s.pending++] = (b >>> 8) & 0xff;
  17252. s.pending_buf[s.pending++] = b & 0xff;
  17253. }
  17254. /* ===========================================================================
  17255. * Read a new buffer from the current input stream, update the adler32
  17256. * and total number of bytes read. All deflate() input goes through
  17257. * this function so some applications may wish to modify it to avoid
  17258. * allocating a large strm->input buffer and copying from it.
  17259. * (See also flush_pending()).
  17260. */
  17261. function read_buf(strm, buf, start, size) {
  17262. var len = strm.avail_in;
  17263. if (len > size) { len = size; }
  17264. if (len === 0) { return 0; }
  17265. strm.avail_in -= len;
  17266. utils.arraySet(buf, strm.input, strm.next_in, len, start);
  17267. if (strm.state.wrap === 1) {
  17268. strm.adler = adler32(strm.adler, buf, len, start);
  17269. }
  17270. else if (strm.state.wrap === 2) {
  17271. strm.adler = crc32(strm.adler, buf, len, start);
  17272. }
  17273. strm.next_in += len;
  17274. strm.total_in += len;
  17275. return len;
  17276. }
  17277. /* ===========================================================================
  17278. * Set match_start to the longest match starting at the given string and
  17279. * return its length. Matches shorter or equal to prev_length are discarded,
  17280. * in which case the result is equal to prev_length and match_start is
  17281. * garbage.
  17282. * IN assertions: cur_match is the head of the hash chain for the current
  17283. * string (strstart) and its distance is <= MAX_DIST, and prev_length >= 1
  17284. * OUT assertion: the match length is not greater than s->lookahead.
  17285. */
  17286. function longest_match(s, cur_match) {
  17287. var chain_length = s.max_chain_length; /* max hash chain length */
  17288. var scan = s.strstart; /* current string */
  17289. var match; /* matched string */
  17290. var len; /* length of current match */
  17291. var best_len = s.prev_length; /* best match length so far */
  17292. var nice_match = s.nice_match; /* stop if match long enough */
  17293. var limit = (s.strstart > (s.w_size - MIN_LOOKAHEAD)) ?
  17294. s.strstart - (s.w_size - MIN_LOOKAHEAD) : 0/*NIL*/;
  17295. var _win = s.window; // shortcut
  17296. var wmask = s.w_mask;
  17297. var prev = s.prev;
  17298. /* Stop when cur_match becomes <= limit. To simplify the code,
  17299. * we prevent matches with the string of window index 0.
  17300. */
  17301. var strend = s.strstart + MAX_MATCH;
  17302. var scan_end1 = _win[scan + best_len - 1];
  17303. var scan_end = _win[scan + best_len];
  17304. /* The code is optimized for HASH_BITS >= 8 and MAX_MATCH-2 multiple of 16.
  17305. * It is easy to get rid of this optimization if necessary.
  17306. */
  17307. // Assert(s->hash_bits >= 8 && MAX_MATCH == 258, "Code too clever");
  17308. /* Do not waste too much time if we already have a good match: */
  17309. if (s.prev_length >= s.good_match) {
  17310. chain_length >>= 2;
  17311. }
  17312. /* Do not look for matches beyond the end of the input. This is necessary
  17313. * to make deflate deterministic.
  17314. */
  17315. if (nice_match > s.lookahead) { nice_match = s.lookahead; }
  17316. // Assert((ulg)s->strstart <= s->window_size-MIN_LOOKAHEAD, "need lookahead");
  17317. do {
  17318. // Assert(cur_match < s->strstart, "no future");
  17319. match = cur_match;
  17320. /* Skip to next match if the match length cannot increase
  17321. * or if the match length is less than 2. Note that the checks below
  17322. * for insufficient lookahead only occur occasionally for performance
  17323. * reasons. Therefore uninitialized memory will be accessed, and
  17324. * conditional jumps will be made that depend on those values.
  17325. * However the length of the match is limited to the lookahead, so
  17326. * the output of deflate is not affected by the uninitialized values.
  17327. */
  17328. if (_win[match + best_len] !== scan_end ||
  17329. _win[match + best_len - 1] !== scan_end1 ||
  17330. _win[match] !== _win[scan] ||
  17331. _win[++match] !== _win[scan + 1]) {
  17332. continue;
  17333. }
  17334. /* The check at best_len-1 can be removed because it will be made
  17335. * again later. (This heuristic is not always a win.)
  17336. * It is not necessary to compare scan[2] and match[2] since they
  17337. * are always equal when the other bytes match, given that
  17338. * the hash keys are equal and that HASH_BITS >= 8.
  17339. */
  17340. scan += 2;
  17341. match++;
  17342. // Assert(*scan == *match, "match[2]?");
  17343. /* We check for insufficient lookahead only every 8th comparison;
  17344. * the 256th check will be made at strstart+258.
  17345. */
  17346. do {
  17347. /*jshint noempty:false*/
  17348. } while (_win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
  17349. _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
  17350. _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
  17351. _win[++scan] === _win[++match] && _win[++scan] === _win[++match] &&
  17352. scan < strend);
  17353. // Assert(scan <= s->window+(unsigned)(s->window_size-1), "wild scan");
  17354. len = MAX_MATCH - (strend - scan);
  17355. scan = strend - MAX_MATCH;
  17356. if (len > best_len) {
  17357. s.match_start = cur_match;
  17358. best_len = len;
  17359. if (len >= nice_match) {
  17360. break;
  17361. }
  17362. scan_end1 = _win[scan + best_len - 1];
  17363. scan_end = _win[scan + best_len];
  17364. }
  17365. } while ((cur_match = prev[cur_match & wmask]) > limit && --chain_length !== 0);
  17366. if (best_len <= s.lookahead) {
  17367. return best_len;
  17368. }
  17369. return s.lookahead;
  17370. }
  17371. /* ===========================================================================
  17372. * Fill the window when the lookahead becomes insufficient.
  17373. * Updates strstart and lookahead.
  17374. *
  17375. * IN assertion: lookahead < MIN_LOOKAHEAD
  17376. * OUT assertions: strstart <= window_size-MIN_LOOKAHEAD
  17377. * At least one byte has been read, or avail_in == 0; reads are
  17378. * performed for at least two bytes (required for the zip translate_eol
  17379. * option -- not supported here).
  17380. */
  17381. function fill_window(s) {
  17382. var _w_size = s.w_size;
  17383. var p, n, m, more, str;
  17384. //Assert(s->lookahead < MIN_LOOKAHEAD, "already enough lookahead");
  17385. do {
  17386. more = s.window_size - s.lookahead - s.strstart;
  17387. // JS ints have 32 bit, block below not needed
  17388. /* Deal with !@#$% 64K limit: */
  17389. //if (sizeof(int) <= 2) {
  17390. // if (more == 0 && s->strstart == 0 && s->lookahead == 0) {
  17391. // more = wsize;
  17392. //
  17393. // } else if (more == (unsigned)(-1)) {
  17394. // /* Very unlikely, but possible on 16 bit machine if
  17395. // * strstart == 0 && lookahead == 1 (input done a byte at time)
  17396. // */
  17397. // more--;
  17398. // }
  17399. //}
  17400. /* If the window is almost full and there is insufficient lookahead,
  17401. * move the upper half to the lower one to make room in the upper half.
  17402. */
  17403. if (s.strstart >= _w_size + (_w_size - MIN_LOOKAHEAD)) {
  17404. utils.arraySet(s.window, s.window, _w_size, _w_size, 0);
  17405. s.match_start -= _w_size;
  17406. s.strstart -= _w_size;
  17407. /* we now have strstart >= MAX_DIST */
  17408. s.block_start -= _w_size;
  17409. /* Slide the hash table (could be avoided with 32 bit values
  17410. at the expense of memory usage). We slide even when level == 0
  17411. to keep the hash table consistent if we switch back to level > 0
  17412. later. (Using level 0 permanently is not an optimal usage of
  17413. zlib, so we don't care about this pathological case.)
  17414. */
  17415. n = s.hash_size;
  17416. p = n;
  17417. do {
  17418. m = s.head[--p];
  17419. s.head[p] = (m >= _w_size ? m - _w_size : 0);
  17420. } while (--n);
  17421. n = _w_size;
  17422. p = n;
  17423. do {
  17424. m = s.prev[--p];
  17425. s.prev[p] = (m >= _w_size ? m - _w_size : 0);
  17426. /* If n is not on any hash chain, prev[n] is garbage but
  17427. * its value will never be used.
  17428. */
  17429. } while (--n);
  17430. more += _w_size;
  17431. }
  17432. if (s.strm.avail_in === 0) {
  17433. break;
  17434. }
  17435. /* If there was no sliding:
  17436. * strstart <= WSIZE+MAX_DIST-1 && lookahead <= MIN_LOOKAHEAD - 1 &&
  17437. * more == window_size - lookahead - strstart
  17438. * => more >= window_size - (MIN_LOOKAHEAD-1 + WSIZE + MAX_DIST-1)
  17439. * => more >= window_size - 2*WSIZE + 2
  17440. * In the BIG_MEM or MMAP case (not yet supported),
  17441. * window_size == input_size + MIN_LOOKAHEAD &&
  17442. * strstart + s->lookahead <= input_size => more >= MIN_LOOKAHEAD.
  17443. * Otherwise, window_size == 2*WSIZE so more >= 2.
  17444. * If there was sliding, more >= WSIZE. So in all cases, more >= 2.
  17445. */
  17446. //Assert(more >= 2, "more < 2");
  17447. n = read_buf(s.strm, s.window, s.strstart + s.lookahead, more);
  17448. s.lookahead += n;
  17449. /* Initialize the hash value now that we have some input: */
  17450. if (s.lookahead + s.insert >= MIN_MATCH) {
  17451. str = s.strstart - s.insert;
  17452. s.ins_h = s.window[str];
  17453. /* UPDATE_HASH(s, s->ins_h, s->window[str + 1]); */
  17454. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + 1]) & s.hash_mask;
  17455. //#if MIN_MATCH != 3
  17456. // Call update_hash() MIN_MATCH-3 more times
  17457. //#endif
  17458. while (s.insert) {
  17459. /* UPDATE_HASH(s, s->ins_h, s->window[str + MIN_MATCH-1]); */
  17460. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[str + MIN_MATCH-1]) & s.hash_mask;
  17461. s.prev[str & s.w_mask] = s.head[s.ins_h];
  17462. s.head[s.ins_h] = str;
  17463. str++;
  17464. s.insert--;
  17465. if (s.lookahead + s.insert < MIN_MATCH) {
  17466. break;
  17467. }
  17468. }
  17469. }
  17470. /* If the whole input has less than MIN_MATCH bytes, ins_h is garbage,
  17471. * but this is not important since only literal bytes will be emitted.
  17472. */
  17473. } while (s.lookahead < MIN_LOOKAHEAD && s.strm.avail_in !== 0);
  17474. /* If the WIN_INIT bytes after the end of the current data have never been
  17475. * written, then zero those bytes in order to avoid memory check reports of
  17476. * the use of uninitialized (or uninitialised as Julian writes) bytes by
  17477. * the longest match routines. Update the high water mark for the next
  17478. * time through here. WIN_INIT is set to MAX_MATCH since the longest match
  17479. * routines allow scanning to strstart + MAX_MATCH, ignoring lookahead.
  17480. */
  17481. // if (s.high_water < s.window_size) {
  17482. // var curr = s.strstart + s.lookahead;
  17483. // var init = 0;
  17484. //
  17485. // if (s.high_water < curr) {
  17486. // /* Previous high water mark below current data -- zero WIN_INIT
  17487. // * bytes or up to end of window, whichever is less.
  17488. // */
  17489. // init = s.window_size - curr;
  17490. // if (init > WIN_INIT)
  17491. // init = WIN_INIT;
  17492. // zmemzero(s->window + curr, (unsigned)init);
  17493. // s->high_water = curr + init;
  17494. // }
  17495. // else if (s->high_water < (ulg)curr + WIN_INIT) {
  17496. // /* High water mark at or above current data, but below current data
  17497. // * plus WIN_INIT -- zero out to current data plus WIN_INIT, or up
  17498. // * to end of window, whichever is less.
  17499. // */
  17500. // init = (ulg)curr + WIN_INIT - s->high_water;
  17501. // if (init > s->window_size - s->high_water)
  17502. // init = s->window_size - s->high_water;
  17503. // zmemzero(s->window + s->high_water, (unsigned)init);
  17504. // s->high_water += init;
  17505. // }
  17506. // }
  17507. //
  17508. // Assert((ulg)s->strstart <= s->window_size - MIN_LOOKAHEAD,
  17509. // "not enough room for search");
  17510. }
  17511. /* ===========================================================================
  17512. * Copy without compression as much as possible from the input stream, return
  17513. * the current block state.
  17514. * This function does not insert new strings in the dictionary since
  17515. * uncompressible data is probably not useful. This function is used
  17516. * only for the level=0 compression option.
  17517. * NOTE: this function should be optimized to avoid extra copying from
  17518. * window to pending_buf.
  17519. */
  17520. function deflate_stored(s, flush) {
  17521. /* Stored blocks are limited to 0xffff bytes, pending_buf is limited
  17522. * to pending_buf_size, and each stored block has a 5 byte header:
  17523. */
  17524. var max_block_size = 0xffff;
  17525. if (max_block_size > s.pending_buf_size - 5) {
  17526. max_block_size = s.pending_buf_size - 5;
  17527. }
  17528. /* Copy as much as possible from input to output: */
  17529. for (;;) {
  17530. /* Fill the window as much as possible: */
  17531. if (s.lookahead <= 1) {
  17532. //Assert(s->strstart < s->w_size+MAX_DIST(s) ||
  17533. // s->block_start >= (long)s->w_size, "slide too late");
  17534. // if (!(s.strstart < s.w_size + (s.w_size - MIN_LOOKAHEAD) ||
  17535. // s.block_start >= s.w_size)) {
  17536. // throw new Error("slide too late");
  17537. // }
  17538. fill_window(s);
  17539. if (s.lookahead === 0 && flush === Z_NO_FLUSH) {
  17540. return BS_NEED_MORE;
  17541. }
  17542. if (s.lookahead === 0) {
  17543. break;
  17544. }
  17545. /* flush the current block */
  17546. }
  17547. //Assert(s->block_start >= 0L, "block gone");
  17548. // if (s.block_start < 0) throw new Error("block gone");
  17549. s.strstart += s.lookahead;
  17550. s.lookahead = 0;
  17551. /* Emit a stored block if pending_buf will be full: */
  17552. var max_start = s.block_start + max_block_size;
  17553. if (s.strstart === 0 || s.strstart >= max_start) {
  17554. /* strstart == 0 is possible when wraparound on 16-bit machine */
  17555. s.lookahead = s.strstart - max_start;
  17556. s.strstart = max_start;
  17557. /*** FLUSH_BLOCK(s, 0); ***/
  17558. flush_block_only(s, false);
  17559. if (s.strm.avail_out === 0) {
  17560. return BS_NEED_MORE;
  17561. }
  17562. /***/
  17563. }
  17564. /* Flush if we may have to slide, otherwise block_start may become
  17565. * negative and the data will be gone:
  17566. */
  17567. if (s.strstart - s.block_start >= (s.w_size - MIN_LOOKAHEAD)) {
  17568. /*** FLUSH_BLOCK(s, 0); ***/
  17569. flush_block_only(s, false);
  17570. if (s.strm.avail_out === 0) {
  17571. return BS_NEED_MORE;
  17572. }
  17573. /***/
  17574. }
  17575. }
  17576. s.insert = 0;
  17577. if (flush === Z_FINISH) {
  17578. /*** FLUSH_BLOCK(s, 1); ***/
  17579. flush_block_only(s, true);
  17580. if (s.strm.avail_out === 0) {
  17581. return BS_FINISH_STARTED;
  17582. }
  17583. /***/
  17584. return BS_FINISH_DONE;
  17585. }
  17586. if (s.strstart > s.block_start) {
  17587. /*** FLUSH_BLOCK(s, 0); ***/
  17588. flush_block_only(s, false);
  17589. if (s.strm.avail_out === 0) {
  17590. return BS_NEED_MORE;
  17591. }
  17592. /***/
  17593. }
  17594. return BS_NEED_MORE;
  17595. }
  17596. /* ===========================================================================
  17597. * Compress as much as possible from the input stream, return the current
  17598. * block state.
  17599. * This function does not perform lazy evaluation of matches and inserts
  17600. * new strings in the dictionary only for unmatched strings or for short
  17601. * matches. It is used only for the fast compression options.
  17602. */
  17603. function deflate_fast(s, flush) {
  17604. var hash_head; /* head of the hash chain */
  17605. var bflush; /* set if current block must be flushed */
  17606. for (;;) {
  17607. /* Make sure that we always have enough lookahead, except
  17608. * at the end of the input file. We need MAX_MATCH bytes
  17609. * for the next match, plus MIN_MATCH bytes to insert the
  17610. * string following the next match.
  17611. */
  17612. if (s.lookahead < MIN_LOOKAHEAD) {
  17613. fill_window(s);
  17614. if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
  17615. return BS_NEED_MORE;
  17616. }
  17617. if (s.lookahead === 0) {
  17618. break; /* flush the current block */
  17619. }
  17620. }
  17621. /* Insert the string window[strstart .. strstart+2] in the
  17622. * dictionary, and set hash_head to the head of the hash chain:
  17623. */
  17624. hash_head = 0/*NIL*/;
  17625. if (s.lookahead >= MIN_MATCH) {
  17626. /*** INSERT_STRING(s, s.strstart, hash_head); ***/
  17627. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
  17628. hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
  17629. s.head[s.ins_h] = s.strstart;
  17630. /***/
  17631. }
  17632. /* Find the longest match, discarding those <= prev_length.
  17633. * At this point we have always match_length < MIN_MATCH
  17634. */
  17635. if (hash_head !== 0/*NIL*/ && ((s.strstart - hash_head) <= (s.w_size - MIN_LOOKAHEAD))) {
  17636. /* To simplify the code, we prevent matches with the string
  17637. * of window index 0 (in particular we have to avoid a match
  17638. * of the string with itself at the start of the input file).
  17639. */
  17640. s.match_length = longest_match(s, hash_head);
  17641. /* longest_match() sets match_start */
  17642. }
  17643. if (s.match_length >= MIN_MATCH) {
  17644. // check_match(s, s.strstart, s.match_start, s.match_length); // for debug only
  17645. /*** _tr_tally_dist(s, s.strstart - s.match_start,
  17646. s.match_length - MIN_MATCH, bflush); ***/
  17647. bflush = trees._tr_tally(s, s.strstart - s.match_start, s.match_length - MIN_MATCH);
  17648. s.lookahead -= s.match_length;
  17649. /* Insert new strings in the hash table only if the match length
  17650. * is not too large. This saves time but degrades compression.
  17651. */
  17652. if (s.match_length <= s.max_lazy_match/*max_insert_length*/ && s.lookahead >= MIN_MATCH) {
  17653. s.match_length--; /* string at strstart already in table */
  17654. do {
  17655. s.strstart++;
  17656. /*** INSERT_STRING(s, s.strstart, hash_head); ***/
  17657. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
  17658. hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
  17659. s.head[s.ins_h] = s.strstart;
  17660. /***/
  17661. /* strstart never exceeds WSIZE-MAX_MATCH, so there are
  17662. * always MIN_MATCH bytes ahead.
  17663. */
  17664. } while (--s.match_length !== 0);
  17665. s.strstart++;
  17666. } else
  17667. {
  17668. s.strstart += s.match_length;
  17669. s.match_length = 0;
  17670. s.ins_h = s.window[s.strstart];
  17671. /* UPDATE_HASH(s, s.ins_h, s.window[s.strstart+1]); */
  17672. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + 1]) & s.hash_mask;
  17673. //#if MIN_MATCH != 3
  17674. // Call UPDATE_HASH() MIN_MATCH-3 more times
  17675. //#endif
  17676. /* If lookahead < MIN_MATCH, ins_h is garbage, but it does not
  17677. * matter since it will be recomputed at next deflate call.
  17678. */
  17679. }
  17680. } else {
  17681. /* No match, output a literal byte */
  17682. //Tracevv((stderr,"%c", s.window[s.strstart]));
  17683. /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
  17684. bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
  17685. s.lookahead--;
  17686. s.strstart++;
  17687. }
  17688. if (bflush) {
  17689. /*** FLUSH_BLOCK(s, 0); ***/
  17690. flush_block_only(s, false);
  17691. if (s.strm.avail_out === 0) {
  17692. return BS_NEED_MORE;
  17693. }
  17694. /***/
  17695. }
  17696. }
  17697. s.insert = ((s.strstart < (MIN_MATCH-1)) ? s.strstart : MIN_MATCH-1);
  17698. if (flush === Z_FINISH) {
  17699. /*** FLUSH_BLOCK(s, 1); ***/
  17700. flush_block_only(s, true);
  17701. if (s.strm.avail_out === 0) {
  17702. return BS_FINISH_STARTED;
  17703. }
  17704. /***/
  17705. return BS_FINISH_DONE;
  17706. }
  17707. if (s.last_lit) {
  17708. /*** FLUSH_BLOCK(s, 0); ***/
  17709. flush_block_only(s, false);
  17710. if (s.strm.avail_out === 0) {
  17711. return BS_NEED_MORE;
  17712. }
  17713. /***/
  17714. }
  17715. return BS_BLOCK_DONE;
  17716. }
  17717. /* ===========================================================================
  17718. * Same as above, but achieves better compression. We use a lazy
  17719. * evaluation for matches: a match is finally adopted only if there is
  17720. * no better match at the next window position.
  17721. */
  17722. function deflate_slow(s, flush) {
  17723. var hash_head; /* head of hash chain */
  17724. var bflush; /* set if current block must be flushed */
  17725. var max_insert;
  17726. /* Process the input block. */
  17727. for (;;) {
  17728. /* Make sure that we always have enough lookahead, except
  17729. * at the end of the input file. We need MAX_MATCH bytes
  17730. * for the next match, plus MIN_MATCH bytes to insert the
  17731. * string following the next match.
  17732. */
  17733. if (s.lookahead < MIN_LOOKAHEAD) {
  17734. fill_window(s);
  17735. if (s.lookahead < MIN_LOOKAHEAD && flush === Z_NO_FLUSH) {
  17736. return BS_NEED_MORE;
  17737. }
  17738. if (s.lookahead === 0) { break; } /* flush the current block */
  17739. }
  17740. /* Insert the string window[strstart .. strstart+2] in the
  17741. * dictionary, and set hash_head to the head of the hash chain:
  17742. */
  17743. hash_head = 0/*NIL*/;
  17744. if (s.lookahead >= MIN_MATCH) {
  17745. /*** INSERT_STRING(s, s.strstart, hash_head); ***/
  17746. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
  17747. hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
  17748. s.head[s.ins_h] = s.strstart;
  17749. /***/
  17750. }
  17751. /* Find the longest match, discarding those <= prev_length.
  17752. */
  17753. s.prev_length = s.match_length;
  17754. s.prev_match = s.match_start;
  17755. s.match_length = MIN_MATCH-1;
  17756. if (hash_head !== 0/*NIL*/ && s.prev_length < s.max_lazy_match &&
  17757. s.strstart - hash_head <= (s.w_size-MIN_LOOKAHEAD)/*MAX_DIST(s)*/) {
  17758. /* To simplify the code, we prevent matches with the string
  17759. * of window index 0 (in particular we have to avoid a match
  17760. * of the string with itself at the start of the input file).
  17761. */
  17762. s.match_length = longest_match(s, hash_head);
  17763. /* longest_match() sets match_start */
  17764. if (s.match_length <= 5 &&
  17765. (s.strategy === Z_FILTERED || (s.match_length === MIN_MATCH && s.strstart - s.match_start > 4096/*TOO_FAR*/))) {
  17766. /* If prev_match is also MIN_MATCH, match_start is garbage
  17767. * but we will ignore the current match anyway.
  17768. */
  17769. s.match_length = MIN_MATCH-1;
  17770. }
  17771. }
  17772. /* If there was a match at the previous step and the current
  17773. * match is not better, output the previous match:
  17774. */
  17775. if (s.prev_length >= MIN_MATCH && s.match_length <= s.prev_length) {
  17776. max_insert = s.strstart + s.lookahead - MIN_MATCH;
  17777. /* Do not insert strings in hash table beyond this. */
  17778. //check_match(s, s.strstart-1, s.prev_match, s.prev_length);
  17779. /***_tr_tally_dist(s, s.strstart - 1 - s.prev_match,
  17780. s.prev_length - MIN_MATCH, bflush);***/
  17781. bflush = trees._tr_tally(s, s.strstart - 1- s.prev_match, s.prev_length - MIN_MATCH);
  17782. /* Insert in hash table all strings up to the end of the match.
  17783. * strstart-1 and strstart are already inserted. If there is not
  17784. * enough lookahead, the last two strings are not inserted in
  17785. * the hash table.
  17786. */
  17787. s.lookahead -= s.prev_length-1;
  17788. s.prev_length -= 2;
  17789. do {
  17790. if (++s.strstart <= max_insert) {
  17791. /*** INSERT_STRING(s, s.strstart, hash_head); ***/
  17792. s.ins_h = ((s.ins_h << s.hash_shift) ^ s.window[s.strstart + MIN_MATCH - 1]) & s.hash_mask;
  17793. hash_head = s.prev[s.strstart & s.w_mask] = s.head[s.ins_h];
  17794. s.head[s.ins_h] = s.strstart;
  17795. /***/
  17796. }
  17797. } while (--s.prev_length !== 0);
  17798. s.match_available = 0;
  17799. s.match_length = MIN_MATCH-1;
  17800. s.strstart++;
  17801. if (bflush) {
  17802. /*** FLUSH_BLOCK(s, 0); ***/
  17803. flush_block_only(s, false);
  17804. if (s.strm.avail_out === 0) {
  17805. return BS_NEED_MORE;
  17806. }
  17807. /***/
  17808. }
  17809. } else if (s.match_available) {
  17810. /* If there was no match at the previous position, output a
  17811. * single literal. If there was a match but the current match
  17812. * is longer, truncate the previous match to a single literal.
  17813. */
  17814. //Tracevv((stderr,"%c", s->window[s->strstart-1]));
  17815. /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
  17816. bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);
  17817. if (bflush) {
  17818. /*** FLUSH_BLOCK_ONLY(s, 0) ***/
  17819. flush_block_only(s, false);
  17820. /***/
  17821. }
  17822. s.strstart++;
  17823. s.lookahead--;
  17824. if (s.strm.avail_out === 0) {
  17825. return BS_NEED_MORE;
  17826. }
  17827. } else {
  17828. /* There is no previous match to compare with, wait for
  17829. * the next step to decide.
  17830. */
  17831. s.match_available = 1;
  17832. s.strstart++;
  17833. s.lookahead--;
  17834. }
  17835. }
  17836. //Assert (flush != Z_NO_FLUSH, "no flush?");
  17837. if (s.match_available) {
  17838. //Tracevv((stderr,"%c", s->window[s->strstart-1]));
  17839. /*** _tr_tally_lit(s, s.window[s.strstart-1], bflush); ***/
  17840. bflush = trees._tr_tally(s, 0, s.window[s.strstart-1]);
  17841. s.match_available = 0;
  17842. }
  17843. s.insert = s.strstart < MIN_MATCH-1 ? s.strstart : MIN_MATCH-1;
  17844. if (flush === Z_FINISH) {
  17845. /*** FLUSH_BLOCK(s, 1); ***/
  17846. flush_block_only(s, true);
  17847. if (s.strm.avail_out === 0) {
  17848. return BS_FINISH_STARTED;
  17849. }
  17850. /***/
  17851. return BS_FINISH_DONE;
  17852. }
  17853. if (s.last_lit) {
  17854. /*** FLUSH_BLOCK(s, 0); ***/
  17855. flush_block_only(s, false);
  17856. if (s.strm.avail_out === 0) {
  17857. return BS_NEED_MORE;
  17858. }
  17859. /***/
  17860. }
  17861. return BS_BLOCK_DONE;
  17862. }
  17863. /* ===========================================================================
  17864. * For Z_RLE, simply look for runs of bytes, generate matches only of distance
  17865. * one. Do not maintain a hash table. (It will be regenerated if this run of
  17866. * deflate switches away from Z_RLE.)
  17867. */
  17868. function deflate_rle(s, flush) {
  17869. var bflush; /* set if current block must be flushed */
  17870. var prev; /* byte at distance one to match */
  17871. var scan, strend; /* scan goes up to strend for length of run */
  17872. var _win = s.window;
  17873. for (;;) {
  17874. /* Make sure that we always have enough lookahead, except
  17875. * at the end of the input file. We need MAX_MATCH bytes
  17876. * for the longest run, plus one for the unrolled loop.
  17877. */
  17878. if (s.lookahead <= MAX_MATCH) {
  17879. fill_window(s);
  17880. if (s.lookahead <= MAX_MATCH && flush === Z_NO_FLUSH) {
  17881. return BS_NEED_MORE;
  17882. }
  17883. if (s.lookahead === 0) { break; } /* flush the current block */
  17884. }
  17885. /* See how many times the previous byte repeats */
  17886. s.match_length = 0;
  17887. if (s.lookahead >= MIN_MATCH && s.strstart > 0) {
  17888. scan = s.strstart - 1;
  17889. prev = _win[scan];
  17890. if (prev === _win[++scan] && prev === _win[++scan] && prev === _win[++scan]) {
  17891. strend = s.strstart + MAX_MATCH;
  17892. do {
  17893. /*jshint noempty:false*/
  17894. } while (prev === _win[++scan] && prev === _win[++scan] &&
  17895. prev === _win[++scan] && prev === _win[++scan] &&
  17896. prev === _win[++scan] && prev === _win[++scan] &&
  17897. prev === _win[++scan] && prev === _win[++scan] &&
  17898. scan < strend);
  17899. s.match_length = MAX_MATCH - (strend - scan);
  17900. if (s.match_length > s.lookahead) {
  17901. s.match_length = s.lookahead;
  17902. }
  17903. }
  17904. //Assert(scan <= s->window+(uInt)(s->window_size-1), "wild scan");
  17905. }
  17906. /* Emit match if have run of MIN_MATCH or longer, else emit literal */
  17907. if (s.match_length >= MIN_MATCH) {
  17908. //check_match(s, s.strstart, s.strstart - 1, s.match_length);
  17909. /*** _tr_tally_dist(s, 1, s.match_length - MIN_MATCH, bflush); ***/
  17910. bflush = trees._tr_tally(s, 1, s.match_length - MIN_MATCH);
  17911. s.lookahead -= s.match_length;
  17912. s.strstart += s.match_length;
  17913. s.match_length = 0;
  17914. } else {
  17915. /* No match, output a literal byte */
  17916. //Tracevv((stderr,"%c", s->window[s->strstart]));
  17917. /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
  17918. bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
  17919. s.lookahead--;
  17920. s.strstart++;
  17921. }
  17922. if (bflush) {
  17923. /*** FLUSH_BLOCK(s, 0); ***/
  17924. flush_block_only(s, false);
  17925. if (s.strm.avail_out === 0) {
  17926. return BS_NEED_MORE;
  17927. }
  17928. /***/
  17929. }
  17930. }
  17931. s.insert = 0;
  17932. if (flush === Z_FINISH) {
  17933. /*** FLUSH_BLOCK(s, 1); ***/
  17934. flush_block_only(s, true);
  17935. if (s.strm.avail_out === 0) {
  17936. return BS_FINISH_STARTED;
  17937. }
  17938. /***/
  17939. return BS_FINISH_DONE;
  17940. }
  17941. if (s.last_lit) {
  17942. /*** FLUSH_BLOCK(s, 0); ***/
  17943. flush_block_only(s, false);
  17944. if (s.strm.avail_out === 0) {
  17945. return BS_NEED_MORE;
  17946. }
  17947. /***/
  17948. }
  17949. return BS_BLOCK_DONE;
  17950. }
  17951. /* ===========================================================================
  17952. * For Z_HUFFMAN_ONLY, do not look for matches. Do not maintain a hash table.
  17953. * (It will be regenerated if this run of deflate switches away from Huffman.)
  17954. */
  17955. function deflate_huff(s, flush) {
  17956. var bflush; /* set if current block must be flushed */
  17957. for (;;) {
  17958. /* Make sure that we have a literal to write. */
  17959. if (s.lookahead === 0) {
  17960. fill_window(s);
  17961. if (s.lookahead === 0) {
  17962. if (flush === Z_NO_FLUSH) {
  17963. return BS_NEED_MORE;
  17964. }
  17965. break; /* flush the current block */
  17966. }
  17967. }
  17968. /* Output a literal byte */
  17969. s.match_length = 0;
  17970. //Tracevv((stderr,"%c", s->window[s->strstart]));
  17971. /*** _tr_tally_lit(s, s.window[s.strstart], bflush); ***/
  17972. bflush = trees._tr_tally(s, 0, s.window[s.strstart]);
  17973. s.lookahead--;
  17974. s.strstart++;
  17975. if (bflush) {
  17976. /*** FLUSH_BLOCK(s, 0); ***/
  17977. flush_block_only(s, false);
  17978. if (s.strm.avail_out === 0) {
  17979. return BS_NEED_MORE;
  17980. }
  17981. /***/
  17982. }
  17983. }
  17984. s.insert = 0;
  17985. if (flush === Z_FINISH) {
  17986. /*** FLUSH_BLOCK(s, 1); ***/
  17987. flush_block_only(s, true);
  17988. if (s.strm.avail_out === 0) {
  17989. return BS_FINISH_STARTED;
  17990. }
  17991. /***/
  17992. return BS_FINISH_DONE;
  17993. }
  17994. if (s.last_lit) {
  17995. /*** FLUSH_BLOCK(s, 0); ***/
  17996. flush_block_only(s, false);
  17997. if (s.strm.avail_out === 0) {
  17998. return BS_NEED_MORE;
  17999. }
  18000. /***/
  18001. }
  18002. return BS_BLOCK_DONE;
  18003. }
  18004. /* Values for max_lazy_match, good_match and max_chain_length, depending on
  18005. * the desired pack level (0..9). The values given below have been tuned to
  18006. * exclude worst case performance for pathological files. Better values may be
  18007. * found for specific files.
  18008. */
  18009. var Config = function (good_length, max_lazy, nice_length, max_chain, func) {
  18010. this.good_length = good_length;
  18011. this.max_lazy = max_lazy;
  18012. this.nice_length = nice_length;
  18013. this.max_chain = max_chain;
  18014. this.func = func;
  18015. };
  18016. var configuration_table;
  18017. configuration_table = [
  18018. /* good lazy nice chain */
  18019. new Config(0, 0, 0, 0, deflate_stored), /* 0 store only */
  18020. new Config(4, 4, 8, 4, deflate_fast), /* 1 max speed, no lazy matches */
  18021. new Config(4, 5, 16, 8, deflate_fast), /* 2 */
  18022. new Config(4, 6, 32, 32, deflate_fast), /* 3 */
  18023. new Config(4, 4, 16, 16, deflate_slow), /* 4 lazy matches */
  18024. new Config(8, 16, 32, 32, deflate_slow), /* 5 */
  18025. new Config(8, 16, 128, 128, deflate_slow), /* 6 */
  18026. new Config(8, 32, 128, 256, deflate_slow), /* 7 */
  18027. new Config(32, 128, 258, 1024, deflate_slow), /* 8 */
  18028. new Config(32, 258, 258, 4096, deflate_slow) /* 9 max compression */
  18029. ];
  18030. /* ===========================================================================
  18031. * Initialize the "longest match" routines for a new zlib stream
  18032. */
  18033. function lm_init(s) {
  18034. s.window_size = 2 * s.w_size;
  18035. /*** CLEAR_HASH(s); ***/
  18036. zero(s.head); // Fill with NIL (= 0);
  18037. /* Set the default configuration parameters:
  18038. */
  18039. s.max_lazy_match = configuration_table[s.level].max_lazy;
  18040. s.good_match = configuration_table[s.level].good_length;
  18041. s.nice_match = configuration_table[s.level].nice_length;
  18042. s.max_chain_length = configuration_table[s.level].max_chain;
  18043. s.strstart = 0;
  18044. s.block_start = 0;
  18045. s.lookahead = 0;
  18046. s.insert = 0;
  18047. s.match_length = s.prev_length = MIN_MATCH - 1;
  18048. s.match_available = 0;
  18049. s.ins_h = 0;
  18050. }
  18051. function DeflateState() {
  18052. this.strm = null; /* pointer back to this zlib stream */
  18053. this.status = 0; /* as the name implies */
  18054. this.pending_buf = null; /* output still pending */
  18055. this.pending_buf_size = 0; /* size of pending_buf */
  18056. this.pending_out = 0; /* next pending byte to output to the stream */
  18057. this.pending = 0; /* nb of bytes in the pending buffer */
  18058. this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
  18059. this.gzhead = null; /* gzip header information to write */
  18060. this.gzindex = 0; /* where in extra, name, or comment */
  18061. this.method = Z_DEFLATED; /* can only be DEFLATED */
  18062. this.last_flush = -1; /* value of flush param for previous deflate call */
  18063. this.w_size = 0; /* LZ77 window size (32K by default) */
  18064. this.w_bits = 0; /* log2(w_size) (8..16) */
  18065. this.w_mask = 0; /* w_size - 1 */
  18066. this.window = null;
  18067. /* Sliding window. Input bytes are read into the second half of the window,
  18068. * and move to the first half later to keep a dictionary of at least wSize
  18069. * bytes. With this organization, matches are limited to a distance of
  18070. * wSize-MAX_MATCH bytes, but this ensures that IO is always
  18071. * performed with a length multiple of the block size.
  18072. */
  18073. this.window_size = 0;
  18074. /* Actual size of window: 2*wSize, except when the user input buffer
  18075. * is directly used as sliding window.
  18076. */
  18077. this.prev = null;
  18078. /* Link to older string with same hash index. To limit the size of this
  18079. * array to 64K, this link is maintained only for the last 32K strings.
  18080. * An index in this array is thus a window index modulo 32K.
  18081. */
  18082. this.head = null; /* Heads of the hash chains or NIL. */
  18083. this.ins_h = 0; /* hash index of string to be inserted */
  18084. this.hash_size = 0; /* number of elements in hash table */
  18085. this.hash_bits = 0; /* log2(hash_size) */
  18086. this.hash_mask = 0; /* hash_size-1 */
  18087. this.hash_shift = 0;
  18088. /* Number of bits by which ins_h must be shifted at each input
  18089. * step. It must be such that after MIN_MATCH steps, the oldest
  18090. * byte no longer takes part in the hash key, that is:
  18091. * hash_shift * MIN_MATCH >= hash_bits
  18092. */
  18093. this.block_start = 0;
  18094. /* Window position at the beginning of the current output block. Gets
  18095. * negative when the window is moved backwards.
  18096. */
  18097. this.match_length = 0; /* length of best match */
  18098. this.prev_match = 0; /* previous match */
  18099. this.match_available = 0; /* set if previous match exists */
  18100. this.strstart = 0; /* start of string to insert */
  18101. this.match_start = 0; /* start of matching string */
  18102. this.lookahead = 0; /* number of valid bytes ahead in window */
  18103. this.prev_length = 0;
  18104. /* Length of the best match at previous step. Matches not greater than this
  18105. * are discarded. This is used in the lazy match evaluation.
  18106. */
  18107. this.max_chain_length = 0;
  18108. /* To speed up deflation, hash chains are never searched beyond this
  18109. * length. A higher limit improves compression ratio but degrades the
  18110. * speed.
  18111. */
  18112. this.max_lazy_match = 0;
  18113. /* Attempt to find a better match only when the current match is strictly
  18114. * smaller than this value. This mechanism is used only for compression
  18115. * levels >= 4.
  18116. */
  18117. // That's alias to max_lazy_match, don't use directly
  18118. //this.max_insert_length = 0;
  18119. /* Insert new strings in the hash table only if the match length is not
  18120. * greater than this length. This saves time but degrades compression.
  18121. * max_insert_length is used only for compression levels <= 3.
  18122. */
  18123. this.level = 0; /* compression level (1..9) */
  18124. this.strategy = 0; /* favor or force Huffman coding*/
  18125. this.good_match = 0;
  18126. /* Use a faster search when the previous match is longer than this */
  18127. this.nice_match = 0; /* Stop searching when current match exceeds this */
  18128. /* used by trees.c: */
  18129. /* Didn't use ct_data typedef below to suppress compiler warning */
  18130. // struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
  18131. // struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
  18132. // struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
  18133. // Use flat array of DOUBLE size, with interleaved fata,
  18134. // because JS does not support effective
  18135. this.dyn_ltree = new utils.Buf16(HEAP_SIZE * 2);
  18136. this.dyn_dtree = new utils.Buf16((2*D_CODES+1) * 2);
  18137. this.bl_tree = new utils.Buf16((2*BL_CODES+1) * 2);
  18138. zero(this.dyn_ltree);
  18139. zero(this.dyn_dtree);
  18140. zero(this.bl_tree);
  18141. this.l_desc = null; /* desc. for literal tree */
  18142. this.d_desc = null; /* desc. for distance tree */
  18143. this.bl_desc = null; /* desc. for bit length tree */
  18144. //ush bl_count[MAX_BITS+1];
  18145. this.bl_count = new utils.Buf16(MAX_BITS+1);
  18146. /* number of codes at each bit length for an optimal tree */
  18147. //int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
  18148. this.heap = new utils.Buf16(2*L_CODES+1); /* heap used to build the Huffman trees */
  18149. zero(this.heap);
  18150. this.heap_len = 0; /* number of elements in the heap */
  18151. this.heap_max = 0; /* element of largest frequency */
  18152. /* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
  18153. * The same heap array is used to build all trees.
  18154. */
  18155. this.depth = new utils.Buf16(2*L_CODES+1); //uch depth[2*L_CODES+1];
  18156. zero(this.depth);
  18157. /* Depth of each subtree used as tie breaker for trees of equal frequency
  18158. */
  18159. this.l_buf = 0; /* buffer index for literals or lengths */
  18160. this.lit_bufsize = 0;
  18161. /* Size of match buffer for literals/lengths. There are 4 reasons for
  18162. * limiting lit_bufsize to 64K:
  18163. * - frequencies can be kept in 16 bit counters
  18164. * - if compression is not successful for the first block, all input
  18165. * data is still in the window so we can still emit a stored block even
  18166. * when input comes from standard input. (This can also be done for
  18167. * all blocks if lit_bufsize is not greater than 32K.)
  18168. * - if compression is not successful for a file smaller than 64K, we can
  18169. * even emit a stored file instead of a stored block (saving 5 bytes).
  18170. * This is applicable only for zip (not gzip or zlib).
  18171. * - creating new Huffman trees less frequently may not provide fast
  18172. * adaptation to changes in the input data statistics. (Take for
  18173. * example a binary file with poorly compressible code followed by
  18174. * a highly compressible string table.) Smaller buffer sizes give
  18175. * fast adaptation but have of course the overhead of transmitting
  18176. * trees more frequently.
  18177. * - I can't count above 4
  18178. */
  18179. this.last_lit = 0; /* running index in l_buf */
  18180. this.d_buf = 0;
  18181. /* Buffer index for distances. To simplify the code, d_buf and l_buf have
  18182. * the same number of elements. To use different lengths, an extra flag
  18183. * array would be necessary.
  18184. */
  18185. this.opt_len = 0; /* bit length of current block with optimal trees */
  18186. this.static_len = 0; /* bit length of current block with static trees */
  18187. this.matches = 0; /* number of string matches in current block */
  18188. this.insert = 0; /* bytes at end of window left to insert */
  18189. this.bi_buf = 0;
  18190. /* Output buffer. bits are inserted starting at the bottom (least
  18191. * significant bits).
  18192. */
  18193. this.bi_valid = 0;
  18194. /* Number of valid bits in bi_buf. All bits above the last valid bit
  18195. * are always zero.
  18196. */
  18197. // Used for window memory init. We safely ignore it for JS. That makes
  18198. // sense only for pointers and memory check tools.
  18199. //this.high_water = 0;
  18200. /* High water mark offset in window for initialized bytes -- bytes above
  18201. * this are set to zero in order to avoid memory check warnings when
  18202. * longest match routines access bytes past the input. This is then
  18203. * updated to the new high water mark.
  18204. */
  18205. }
  18206. function deflateResetKeep(strm) {
  18207. var s;
  18208. if (!strm || !strm.state) {
  18209. return err(strm, Z_STREAM_ERROR);
  18210. }
  18211. strm.total_in = strm.total_out = 0;
  18212. strm.data_type = Z_UNKNOWN;
  18213. s = strm.state;
  18214. s.pending = 0;
  18215. s.pending_out = 0;
  18216. if (s.wrap < 0) {
  18217. s.wrap = -s.wrap;
  18218. /* was made negative by deflate(..., Z_FINISH); */
  18219. }
  18220. s.status = (s.wrap ? INIT_STATE : BUSY_STATE);
  18221. strm.adler = (s.wrap === 2) ?
  18222. 0 // crc32(0, Z_NULL, 0)
  18223. :
  18224. 1; // adler32(0, Z_NULL, 0)
  18225. s.last_flush = Z_NO_FLUSH;
  18226. trees._tr_init(s);
  18227. return Z_OK;
  18228. }
  18229. function deflateReset(strm) {
  18230. var ret = deflateResetKeep(strm);
  18231. if (ret === Z_OK) {
  18232. lm_init(strm.state);
  18233. }
  18234. return ret;
  18235. }
  18236. function deflateSetHeader(strm, head) {
  18237. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  18238. if (strm.state.wrap !== 2) { return Z_STREAM_ERROR; }
  18239. strm.state.gzhead = head;
  18240. return Z_OK;
  18241. }
  18242. function deflateInit2(strm, level, method, windowBits, memLevel, strategy) {
  18243. if (!strm) { // === Z_NULL
  18244. return Z_STREAM_ERROR;
  18245. }
  18246. var wrap = 1;
  18247. if (level === Z_DEFAULT_COMPRESSION) {
  18248. level = 6;
  18249. }
  18250. if (windowBits < 0) { /* suppress zlib wrapper */
  18251. wrap = 0;
  18252. windowBits = -windowBits;
  18253. }
  18254. else if (windowBits > 15) {
  18255. wrap = 2; /* write gzip wrapper instead */
  18256. windowBits -= 16;
  18257. }
  18258. if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method !== Z_DEFLATED ||
  18259. windowBits < 8 || windowBits > 15 || level < 0 || level > 9 ||
  18260. strategy < 0 || strategy > Z_FIXED) {
  18261. return err(strm, Z_STREAM_ERROR);
  18262. }
  18263. if (windowBits === 8) {
  18264. windowBits = 9;
  18265. }
  18266. /* until 256-byte window bug fixed */
  18267. var s = new DeflateState();
  18268. strm.state = s;
  18269. s.strm = strm;
  18270. s.wrap = wrap;
  18271. s.gzhead = null;
  18272. s.w_bits = windowBits;
  18273. s.w_size = 1 << s.w_bits;
  18274. s.w_mask = s.w_size - 1;
  18275. s.hash_bits = memLevel + 7;
  18276. s.hash_size = 1 << s.hash_bits;
  18277. s.hash_mask = s.hash_size - 1;
  18278. s.hash_shift = ~~((s.hash_bits + MIN_MATCH - 1) / MIN_MATCH);
  18279. s.window = new utils.Buf8(s.w_size * 2);
  18280. s.head = new utils.Buf16(s.hash_size);
  18281. s.prev = new utils.Buf16(s.w_size);
  18282. // Don't need mem init magic for JS.
  18283. //s.high_water = 0; /* nothing written to s->window yet */
  18284. s.lit_bufsize = 1 << (memLevel + 6); /* 16K elements by default */
  18285. s.pending_buf_size = s.lit_bufsize * 4;
  18286. s.pending_buf = new utils.Buf8(s.pending_buf_size);
  18287. s.d_buf = s.lit_bufsize >> 1;
  18288. s.l_buf = (1 + 2) * s.lit_bufsize;
  18289. s.level = level;
  18290. s.strategy = strategy;
  18291. s.method = method;
  18292. return deflateReset(strm);
  18293. }
  18294. function deflateInit(strm, level) {
  18295. return deflateInit2(strm, level, Z_DEFLATED, MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY);
  18296. }
  18297. function deflate(strm, flush) {
  18298. var old_flush, s;
  18299. var beg, val; // for gzip header write only
  18300. if (!strm || !strm.state ||
  18301. flush > Z_BLOCK || flush < 0) {
  18302. return strm ? err(strm, Z_STREAM_ERROR) : Z_STREAM_ERROR;
  18303. }
  18304. s = strm.state;
  18305. if (!strm.output ||
  18306. (!strm.input && strm.avail_in !== 0) ||
  18307. (s.status === FINISH_STATE && flush !== Z_FINISH)) {
  18308. return err(strm, (strm.avail_out === 0) ? Z_BUF_ERROR : Z_STREAM_ERROR);
  18309. }
  18310. s.strm = strm; /* just in case */
  18311. old_flush = s.last_flush;
  18312. s.last_flush = flush;
  18313. /* Write the header */
  18314. if (s.status === INIT_STATE) {
  18315. if (s.wrap === 2) { // GZIP header
  18316. strm.adler = 0; //crc32(0L, Z_NULL, 0);
  18317. put_byte(s, 31);
  18318. put_byte(s, 139);
  18319. put_byte(s, 8);
  18320. if (!s.gzhead) { // s->gzhead == Z_NULL
  18321. put_byte(s, 0);
  18322. put_byte(s, 0);
  18323. put_byte(s, 0);
  18324. put_byte(s, 0);
  18325. put_byte(s, 0);
  18326. put_byte(s, s.level === 9 ? 2 :
  18327. (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
  18328. 4 : 0));
  18329. put_byte(s, OS_CODE);
  18330. s.status = BUSY_STATE;
  18331. }
  18332. else {
  18333. put_byte(s, (s.gzhead.text ? 1 : 0) +
  18334. (s.gzhead.hcrc ? 2 : 0) +
  18335. (!s.gzhead.extra ? 0 : 4) +
  18336. (!s.gzhead.name ? 0 : 8) +
  18337. (!s.gzhead.comment ? 0 : 16)
  18338. );
  18339. put_byte(s, s.gzhead.time & 0xff);
  18340. put_byte(s, (s.gzhead.time >> 8) & 0xff);
  18341. put_byte(s, (s.gzhead.time >> 16) & 0xff);
  18342. put_byte(s, (s.gzhead.time >> 24) & 0xff);
  18343. put_byte(s, s.level === 9 ? 2 :
  18344. (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2 ?
  18345. 4 : 0));
  18346. put_byte(s, s.gzhead.os & 0xff);
  18347. if (s.gzhead.extra && s.gzhead.extra.length) {
  18348. put_byte(s, s.gzhead.extra.length & 0xff);
  18349. put_byte(s, (s.gzhead.extra.length >> 8) & 0xff);
  18350. }
  18351. if (s.gzhead.hcrc) {
  18352. strm.adler = crc32(strm.adler, s.pending_buf, s.pending, 0);
  18353. }
  18354. s.gzindex = 0;
  18355. s.status = EXTRA_STATE;
  18356. }
  18357. }
  18358. else // DEFLATE header
  18359. {
  18360. var header = (Z_DEFLATED + ((s.w_bits - 8) << 4)) << 8;
  18361. var level_flags = -1;
  18362. if (s.strategy >= Z_HUFFMAN_ONLY || s.level < 2) {
  18363. level_flags = 0;
  18364. } else if (s.level < 6) {
  18365. level_flags = 1;
  18366. } else if (s.level === 6) {
  18367. level_flags = 2;
  18368. } else {
  18369. level_flags = 3;
  18370. }
  18371. header |= (level_flags << 6);
  18372. if (s.strstart !== 0) { header |= PRESET_DICT; }
  18373. header += 31 - (header % 31);
  18374. s.status = BUSY_STATE;
  18375. putShortMSB(s, header);
  18376. /* Save the adler32 of the preset dictionary: */
  18377. if (s.strstart !== 0) {
  18378. putShortMSB(s, strm.adler >>> 16);
  18379. putShortMSB(s, strm.adler & 0xffff);
  18380. }
  18381. strm.adler = 1; // adler32(0L, Z_NULL, 0);
  18382. }
  18383. }
  18384. //#ifdef GZIP
  18385. if (s.status === EXTRA_STATE) {
  18386. if (s.gzhead.extra/* != Z_NULL*/) {
  18387. beg = s.pending; /* start of bytes to update crc */
  18388. while (s.gzindex < (s.gzhead.extra.length & 0xffff)) {
  18389. if (s.pending === s.pending_buf_size) {
  18390. if (s.gzhead.hcrc && s.pending > beg) {
  18391. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  18392. }
  18393. flush_pending(strm);
  18394. beg = s.pending;
  18395. if (s.pending === s.pending_buf_size) {
  18396. break;
  18397. }
  18398. }
  18399. put_byte(s, s.gzhead.extra[s.gzindex] & 0xff);
  18400. s.gzindex++;
  18401. }
  18402. if (s.gzhead.hcrc && s.pending > beg) {
  18403. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  18404. }
  18405. if (s.gzindex === s.gzhead.extra.length) {
  18406. s.gzindex = 0;
  18407. s.status = NAME_STATE;
  18408. }
  18409. }
  18410. else {
  18411. s.status = NAME_STATE;
  18412. }
  18413. }
  18414. if (s.status === NAME_STATE) {
  18415. if (s.gzhead.name/* != Z_NULL*/) {
  18416. beg = s.pending; /* start of bytes to update crc */
  18417. //int val;
  18418. do {
  18419. if (s.pending === s.pending_buf_size) {
  18420. if (s.gzhead.hcrc && s.pending > beg) {
  18421. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  18422. }
  18423. flush_pending(strm);
  18424. beg = s.pending;
  18425. if (s.pending === s.pending_buf_size) {
  18426. val = 1;
  18427. break;
  18428. }
  18429. }
  18430. // JS specific: little magic to add zero terminator to end of string
  18431. if (s.gzindex < s.gzhead.name.length) {
  18432. val = s.gzhead.name.charCodeAt(s.gzindex++) & 0xff;
  18433. } else {
  18434. val = 0;
  18435. }
  18436. put_byte(s, val);
  18437. } while (val !== 0);
  18438. if (s.gzhead.hcrc && s.pending > beg){
  18439. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  18440. }
  18441. if (val === 0) {
  18442. s.gzindex = 0;
  18443. s.status = COMMENT_STATE;
  18444. }
  18445. }
  18446. else {
  18447. s.status = COMMENT_STATE;
  18448. }
  18449. }
  18450. if (s.status === COMMENT_STATE) {
  18451. if (s.gzhead.comment/* != Z_NULL*/) {
  18452. beg = s.pending; /* start of bytes to update crc */
  18453. //int val;
  18454. do {
  18455. if (s.pending === s.pending_buf_size) {
  18456. if (s.gzhead.hcrc && s.pending > beg) {
  18457. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  18458. }
  18459. flush_pending(strm);
  18460. beg = s.pending;
  18461. if (s.pending === s.pending_buf_size) {
  18462. val = 1;
  18463. break;
  18464. }
  18465. }
  18466. // JS specific: little magic to add zero terminator to end of string
  18467. if (s.gzindex < s.gzhead.comment.length) {
  18468. val = s.gzhead.comment.charCodeAt(s.gzindex++) & 0xff;
  18469. } else {
  18470. val = 0;
  18471. }
  18472. put_byte(s, val);
  18473. } while (val !== 0);
  18474. if (s.gzhead.hcrc && s.pending > beg) {
  18475. strm.adler = crc32(strm.adler, s.pending_buf, s.pending - beg, beg);
  18476. }
  18477. if (val === 0) {
  18478. s.status = HCRC_STATE;
  18479. }
  18480. }
  18481. else {
  18482. s.status = HCRC_STATE;
  18483. }
  18484. }
  18485. if (s.status === HCRC_STATE) {
  18486. if (s.gzhead.hcrc) {
  18487. if (s.pending + 2 > s.pending_buf_size) {
  18488. flush_pending(strm);
  18489. }
  18490. if (s.pending + 2 <= s.pending_buf_size) {
  18491. put_byte(s, strm.adler & 0xff);
  18492. put_byte(s, (strm.adler >> 8) & 0xff);
  18493. strm.adler = 0; //crc32(0L, Z_NULL, 0);
  18494. s.status = BUSY_STATE;
  18495. }
  18496. }
  18497. else {
  18498. s.status = BUSY_STATE;
  18499. }
  18500. }
  18501. //#endif
  18502. /* Flush as much pending output as possible */
  18503. if (s.pending !== 0) {
  18504. flush_pending(strm);
  18505. if (strm.avail_out === 0) {
  18506. /* Since avail_out is 0, deflate will be called again with
  18507. * more output space, but possibly with both pending and
  18508. * avail_in equal to zero. There won't be anything to do,
  18509. * but this is not an error situation so make sure we
  18510. * return OK instead of BUF_ERROR at next call of deflate:
  18511. */
  18512. s.last_flush = -1;
  18513. return Z_OK;
  18514. }
  18515. /* Make sure there is something to do and avoid duplicate consecutive
  18516. * flushes. For repeated and useless calls with Z_FINISH, we keep
  18517. * returning Z_STREAM_END instead of Z_BUF_ERROR.
  18518. */
  18519. } else if (strm.avail_in === 0 && rank(flush) <= rank(old_flush) &&
  18520. flush !== Z_FINISH) {
  18521. return err(strm, Z_BUF_ERROR);
  18522. }
  18523. /* User must not provide more input after the first FINISH: */
  18524. if (s.status === FINISH_STATE && strm.avail_in !== 0) {
  18525. return err(strm, Z_BUF_ERROR);
  18526. }
  18527. /* Start a new block or continue the current one.
  18528. */
  18529. if (strm.avail_in !== 0 || s.lookahead !== 0 ||
  18530. (flush !== Z_NO_FLUSH && s.status !== FINISH_STATE)) {
  18531. var bstate = (s.strategy === Z_HUFFMAN_ONLY) ? deflate_huff(s, flush) :
  18532. (s.strategy === Z_RLE ? deflate_rle(s, flush) :
  18533. configuration_table[s.level].func(s, flush));
  18534. if (bstate === BS_FINISH_STARTED || bstate === BS_FINISH_DONE) {
  18535. s.status = FINISH_STATE;
  18536. }
  18537. if (bstate === BS_NEED_MORE || bstate === BS_FINISH_STARTED) {
  18538. if (strm.avail_out === 0) {
  18539. s.last_flush = -1;
  18540. /* avoid BUF_ERROR next call, see above */
  18541. }
  18542. return Z_OK;
  18543. /* If flush != Z_NO_FLUSH && avail_out == 0, the next call
  18544. * of deflate should use the same flush parameter to make sure
  18545. * that the flush is complete. So we don't have to output an
  18546. * empty block here, this will be done at next call. This also
  18547. * ensures that for a very small output buffer, we emit at most
  18548. * one empty block.
  18549. */
  18550. }
  18551. if (bstate === BS_BLOCK_DONE) {
  18552. if (flush === Z_PARTIAL_FLUSH) {
  18553. trees._tr_align(s);
  18554. }
  18555. else if (flush !== Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
  18556. trees._tr_stored_block(s, 0, 0, false);
  18557. /* For a full flush, this empty block will be recognized
  18558. * as a special marker by inflate_sync().
  18559. */
  18560. if (flush === Z_FULL_FLUSH) {
  18561. /*** CLEAR_HASH(s); ***/ /* forget history */
  18562. zero(s.head); // Fill with NIL (= 0);
  18563. if (s.lookahead === 0) {
  18564. s.strstart = 0;
  18565. s.block_start = 0;
  18566. s.insert = 0;
  18567. }
  18568. }
  18569. }
  18570. flush_pending(strm);
  18571. if (strm.avail_out === 0) {
  18572. s.last_flush = -1; /* avoid BUF_ERROR at next call, see above */
  18573. return Z_OK;
  18574. }
  18575. }
  18576. }
  18577. //Assert(strm->avail_out > 0, "bug2");
  18578. //if (strm.avail_out <= 0) { throw new Error("bug2");}
  18579. if (flush !== Z_FINISH) { return Z_OK; }
  18580. if (s.wrap <= 0) { return Z_STREAM_END; }
  18581. /* Write the trailer */
  18582. if (s.wrap === 2) {
  18583. put_byte(s, strm.adler & 0xff);
  18584. put_byte(s, (strm.adler >> 8) & 0xff);
  18585. put_byte(s, (strm.adler >> 16) & 0xff);
  18586. put_byte(s, (strm.adler >> 24) & 0xff);
  18587. put_byte(s, strm.total_in & 0xff);
  18588. put_byte(s, (strm.total_in >> 8) & 0xff);
  18589. put_byte(s, (strm.total_in >> 16) & 0xff);
  18590. put_byte(s, (strm.total_in >> 24) & 0xff);
  18591. }
  18592. else
  18593. {
  18594. putShortMSB(s, strm.adler >>> 16);
  18595. putShortMSB(s, strm.adler & 0xffff);
  18596. }
  18597. flush_pending(strm);
  18598. /* If avail_out is zero, the application will call deflate again
  18599. * to flush the rest.
  18600. */
  18601. if (s.wrap > 0) { s.wrap = -s.wrap; }
  18602. /* write the trailer only once! */
  18603. return s.pending !== 0 ? Z_OK : Z_STREAM_END;
  18604. }
  18605. function deflateEnd(strm) {
  18606. var status;
  18607. if (!strm/*== Z_NULL*/ || !strm.state/*== Z_NULL*/) {
  18608. return Z_STREAM_ERROR;
  18609. }
  18610. status = strm.state.status;
  18611. if (status !== INIT_STATE &&
  18612. status !== EXTRA_STATE &&
  18613. status !== NAME_STATE &&
  18614. status !== COMMENT_STATE &&
  18615. status !== HCRC_STATE &&
  18616. status !== BUSY_STATE &&
  18617. status !== FINISH_STATE
  18618. ) {
  18619. return err(strm, Z_STREAM_ERROR);
  18620. }
  18621. strm.state = null;
  18622. return status === BUSY_STATE ? err(strm, Z_DATA_ERROR) : Z_OK;
  18623. }
  18624. /* =========================================================================
  18625. * Copy the source state to the destination state
  18626. */
  18627. //function deflateCopy(dest, source) {
  18628. //
  18629. //}
  18630. exports.deflateInit = deflateInit;
  18631. exports.deflateInit2 = deflateInit2;
  18632. exports.deflateReset = deflateReset;
  18633. exports.deflateResetKeep = deflateResetKeep;
  18634. exports.deflateSetHeader = deflateSetHeader;
  18635. exports.deflate = deflate;
  18636. exports.deflateEnd = deflateEnd;
  18637. exports.deflateInfo = 'pako deflate (from Nodeca project)';
  18638. /* Not implemented
  18639. exports.deflateBound = deflateBound;
  18640. exports.deflateCopy = deflateCopy;
  18641. exports.deflateSetDictionary = deflateSetDictionary;
  18642. exports.deflateParams = deflateParams;
  18643. exports.deflatePending = deflatePending;
  18644. exports.deflatePrime = deflatePrime;
  18645. exports.deflateTune = deflateTune;
  18646. */
  18647. },{"../utils/common":65,"./adler32":67,"./crc32":69,"./messages":75,"./trees":76}],71:[function(require,module,exports){
  18648. 'use strict';
  18649. function GZheader() {
  18650. /* true if compressed data believed to be text */
  18651. this.text = 0;
  18652. /* modification time */
  18653. this.time = 0;
  18654. /* extra flags (not used when writing a gzip file) */
  18655. this.xflags = 0;
  18656. /* operating system */
  18657. this.os = 0;
  18658. /* pointer to extra field or Z_NULL if none */
  18659. this.extra = null;
  18660. /* extra field length (valid if extra != Z_NULL) */
  18661. this.extra_len = 0; // Actually, we don't need it in JS,
  18662. // but leave for few code modifications
  18663. //
  18664. // Setup limits is not necessary because in js we should not preallocate memory
  18665. // for inflate use constant limit in 65536 bytes
  18666. //
  18667. /* space at extra (only when reading header) */
  18668. // this.extra_max = 0;
  18669. /* pointer to zero-terminated file name or Z_NULL */
  18670. this.name = '';
  18671. /* space at name (only when reading header) */
  18672. // this.name_max = 0;
  18673. /* pointer to zero-terminated comment or Z_NULL */
  18674. this.comment = '';
  18675. /* space at comment (only when reading header) */
  18676. // this.comm_max = 0;
  18677. /* true if there was or will be a header crc */
  18678. this.hcrc = 0;
  18679. /* true when done reading gzip header (not used when writing a gzip file) */
  18680. this.done = false;
  18681. }
  18682. module.exports = GZheader;
  18683. },{}],72:[function(require,module,exports){
  18684. 'use strict';
  18685. // See state defs from inflate.js
  18686. var BAD = 30; /* got a data error -- remain here until reset */
  18687. var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
  18688. /*
  18689. Decode literal, length, and distance codes and write out the resulting
  18690. literal and match bytes until either not enough input or output is
  18691. available, an end-of-block is encountered, or a data error is encountered.
  18692. When large enough input and output buffers are supplied to inflate(), for
  18693. example, a 16K input buffer and a 64K output buffer, more than 95% of the
  18694. inflate execution time is spent in this routine.
  18695. Entry assumptions:
  18696. state.mode === LEN
  18697. strm.avail_in >= 6
  18698. strm.avail_out >= 258
  18699. start >= strm.avail_out
  18700. state.bits < 8
  18701. On return, state.mode is one of:
  18702. LEN -- ran out of enough output space or enough available input
  18703. TYPE -- reached end of block code, inflate() to interpret next block
  18704. BAD -- error in block data
  18705. Notes:
  18706. - The maximum input bits used by a length/distance pair is 15 bits for the
  18707. length code, 5 bits for the length extra, 15 bits for the distance code,
  18708. and 13 bits for the distance extra. This totals 48 bits, or six bytes.
  18709. Therefore if strm.avail_in >= 6, then there is enough input to avoid
  18710. checking for available input while decoding.
  18711. - The maximum bytes that a single length/distance pair can output is 258
  18712. bytes, which is the maximum length that can be coded. inflate_fast()
  18713. requires strm.avail_out >= 258 for each loop to avoid checking for
  18714. output space.
  18715. */
  18716. module.exports = function inflate_fast(strm, start) {
  18717. var state;
  18718. var _in; /* local strm.input */
  18719. var last; /* have enough input while in < last */
  18720. var _out; /* local strm.output */
  18721. var beg; /* inflate()'s initial strm.output */
  18722. var end; /* while out < end, enough space available */
  18723. //#ifdef INFLATE_STRICT
  18724. var dmax; /* maximum distance from zlib header */
  18725. //#endif
  18726. var wsize; /* window size or zero if not using window */
  18727. var whave; /* valid bytes in the window */
  18728. var wnext; /* window write index */
  18729. var window; /* allocated sliding window, if wsize != 0 */
  18730. var hold; /* local strm.hold */
  18731. var bits; /* local strm.bits */
  18732. var lcode; /* local strm.lencode */
  18733. var dcode; /* local strm.distcode */
  18734. var lmask; /* mask for first level of length codes */
  18735. var dmask; /* mask for first level of distance codes */
  18736. var here; /* retrieved table entry */
  18737. var op; /* code bits, operation, extra bits, or */
  18738. /* window position, window bytes to copy */
  18739. var len; /* match length, unused bytes */
  18740. var dist; /* match distance */
  18741. var from; /* where to copy match from */
  18742. var from_source;
  18743. var input, output; // JS specific, because we have no pointers
  18744. /* copy state to local variables */
  18745. state = strm.state;
  18746. //here = state.here;
  18747. _in = strm.next_in;
  18748. input = strm.input;
  18749. last = _in + (strm.avail_in - 5);
  18750. _out = strm.next_out;
  18751. output = strm.output;
  18752. beg = _out - (start - strm.avail_out);
  18753. end = _out + (strm.avail_out - 257);
  18754. //#ifdef INFLATE_STRICT
  18755. dmax = state.dmax;
  18756. //#endif
  18757. wsize = state.wsize;
  18758. whave = state.whave;
  18759. wnext = state.wnext;
  18760. window = state.window;
  18761. hold = state.hold;
  18762. bits = state.bits;
  18763. lcode = state.lencode;
  18764. dcode = state.distcode;
  18765. lmask = (1 << state.lenbits) - 1;
  18766. dmask = (1 << state.distbits) - 1;
  18767. /* decode literals and length/distances until end-of-block or not enough
  18768. input data or output space */
  18769. top:
  18770. do {
  18771. if (bits < 15) {
  18772. hold += input[_in++] << bits;
  18773. bits += 8;
  18774. hold += input[_in++] << bits;
  18775. bits += 8;
  18776. }
  18777. here = lcode[hold & lmask];
  18778. dolen:
  18779. for (;;) { // Goto emulation
  18780. op = here >>> 24/*here.bits*/;
  18781. hold >>>= op;
  18782. bits -= op;
  18783. op = (here >>> 16) & 0xff/*here.op*/;
  18784. if (op === 0) { /* literal */
  18785. //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
  18786. // "inflate: literal '%c'\n" :
  18787. // "inflate: literal 0x%02x\n", here.val));
  18788. output[_out++] = here & 0xffff/*here.val*/;
  18789. }
  18790. else if (op & 16) { /* length base */
  18791. len = here & 0xffff/*here.val*/;
  18792. op &= 15; /* number of extra bits */
  18793. if (op) {
  18794. if (bits < op) {
  18795. hold += input[_in++] << bits;
  18796. bits += 8;
  18797. }
  18798. len += hold & ((1 << op) - 1);
  18799. hold >>>= op;
  18800. bits -= op;
  18801. }
  18802. //Tracevv((stderr, "inflate: length %u\n", len));
  18803. if (bits < 15) {
  18804. hold += input[_in++] << bits;
  18805. bits += 8;
  18806. hold += input[_in++] << bits;
  18807. bits += 8;
  18808. }
  18809. here = dcode[hold & dmask];
  18810. dodist:
  18811. for (;;) { // goto emulation
  18812. op = here >>> 24/*here.bits*/;
  18813. hold >>>= op;
  18814. bits -= op;
  18815. op = (here >>> 16) & 0xff/*here.op*/;
  18816. if (op & 16) { /* distance base */
  18817. dist = here & 0xffff/*here.val*/;
  18818. op &= 15; /* number of extra bits */
  18819. if (bits < op) {
  18820. hold += input[_in++] << bits;
  18821. bits += 8;
  18822. if (bits < op) {
  18823. hold += input[_in++] << bits;
  18824. bits += 8;
  18825. }
  18826. }
  18827. dist += hold & ((1 << op) - 1);
  18828. //#ifdef INFLATE_STRICT
  18829. if (dist > dmax) {
  18830. strm.msg = 'invalid distance too far back';
  18831. state.mode = BAD;
  18832. break top;
  18833. }
  18834. //#endif
  18835. hold >>>= op;
  18836. bits -= op;
  18837. //Tracevv((stderr, "inflate: distance %u\n", dist));
  18838. op = _out - beg; /* max distance in output */
  18839. if (dist > op) { /* see if copy from window */
  18840. op = dist - op; /* distance back in window */
  18841. if (op > whave) {
  18842. if (state.sane) {
  18843. strm.msg = 'invalid distance too far back';
  18844. state.mode = BAD;
  18845. break top;
  18846. }
  18847. // (!) This block is disabled in zlib defailts,
  18848. // don't enable it for binary compatibility
  18849. //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
  18850. // if (len <= op - whave) {
  18851. // do {
  18852. // output[_out++] = 0;
  18853. // } while (--len);
  18854. // continue top;
  18855. // }
  18856. // len -= op - whave;
  18857. // do {
  18858. // output[_out++] = 0;
  18859. // } while (--op > whave);
  18860. // if (op === 0) {
  18861. // from = _out - dist;
  18862. // do {
  18863. // output[_out++] = output[from++];
  18864. // } while (--len);
  18865. // continue top;
  18866. // }
  18867. //#endif
  18868. }
  18869. from = 0; // window index
  18870. from_source = window;
  18871. if (wnext === 0) { /* very common case */
  18872. from += wsize - op;
  18873. if (op < len) { /* some from window */
  18874. len -= op;
  18875. do {
  18876. output[_out++] = window[from++];
  18877. } while (--op);
  18878. from = _out - dist; /* rest from output */
  18879. from_source = output;
  18880. }
  18881. }
  18882. else if (wnext < op) { /* wrap around window */
  18883. from += wsize + wnext - op;
  18884. op -= wnext;
  18885. if (op < len) { /* some from end of window */
  18886. len -= op;
  18887. do {
  18888. output[_out++] = window[from++];
  18889. } while (--op);
  18890. from = 0;
  18891. if (wnext < len) { /* some from start of window */
  18892. op = wnext;
  18893. len -= op;
  18894. do {
  18895. output[_out++] = window[from++];
  18896. } while (--op);
  18897. from = _out - dist; /* rest from output */
  18898. from_source = output;
  18899. }
  18900. }
  18901. }
  18902. else { /* contiguous in window */
  18903. from += wnext - op;
  18904. if (op < len) { /* some from window */
  18905. len -= op;
  18906. do {
  18907. output[_out++] = window[from++];
  18908. } while (--op);
  18909. from = _out - dist; /* rest from output */
  18910. from_source = output;
  18911. }
  18912. }
  18913. while (len > 2) {
  18914. output[_out++] = from_source[from++];
  18915. output[_out++] = from_source[from++];
  18916. output[_out++] = from_source[from++];
  18917. len -= 3;
  18918. }
  18919. if (len) {
  18920. output[_out++] = from_source[from++];
  18921. if (len > 1) {
  18922. output[_out++] = from_source[from++];
  18923. }
  18924. }
  18925. }
  18926. else {
  18927. from = _out - dist; /* copy direct from output */
  18928. do { /* minimum length is three */
  18929. output[_out++] = output[from++];
  18930. output[_out++] = output[from++];
  18931. output[_out++] = output[from++];
  18932. len -= 3;
  18933. } while (len > 2);
  18934. if (len) {
  18935. output[_out++] = output[from++];
  18936. if (len > 1) {
  18937. output[_out++] = output[from++];
  18938. }
  18939. }
  18940. }
  18941. }
  18942. else if ((op & 64) === 0) { /* 2nd level distance code */
  18943. here = dcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
  18944. continue dodist;
  18945. }
  18946. else {
  18947. strm.msg = 'invalid distance code';
  18948. state.mode = BAD;
  18949. break top;
  18950. }
  18951. break; // need to emulate goto via "continue"
  18952. }
  18953. }
  18954. else if ((op & 64) === 0) { /* 2nd level length code */
  18955. here = lcode[(here & 0xffff)/*here.val*/ + (hold & ((1 << op) - 1))];
  18956. continue dolen;
  18957. }
  18958. else if (op & 32) { /* end-of-block */
  18959. //Tracevv((stderr, "inflate: end of block\n"));
  18960. state.mode = TYPE;
  18961. break top;
  18962. }
  18963. else {
  18964. strm.msg = 'invalid literal/length code';
  18965. state.mode = BAD;
  18966. break top;
  18967. }
  18968. break; // need to emulate goto via "continue"
  18969. }
  18970. } while (_in < last && _out < end);
  18971. /* return unused bytes (on entry, bits < 8, so in won't go too far back) */
  18972. len = bits >> 3;
  18973. _in -= len;
  18974. bits -= len << 3;
  18975. hold &= (1 << bits) - 1;
  18976. /* update state and return */
  18977. strm.next_in = _in;
  18978. strm.next_out = _out;
  18979. strm.avail_in = (_in < last ? 5 + (last - _in) : 5 - (_in - last));
  18980. strm.avail_out = (_out < end ? 257 + (end - _out) : 257 - (_out - end));
  18981. state.hold = hold;
  18982. state.bits = bits;
  18983. return;
  18984. };
  18985. },{}],73:[function(require,module,exports){
  18986. 'use strict';
  18987. var utils = require('../utils/common');
  18988. var adler32 = require('./adler32');
  18989. var crc32 = require('./crc32');
  18990. var inflate_fast = require('./inffast');
  18991. var inflate_table = require('./inftrees');
  18992. var CODES = 0;
  18993. var LENS = 1;
  18994. var DISTS = 2;
  18995. /* Public constants ==========================================================*/
  18996. /* ===========================================================================*/
  18997. /* Allowed flush values; see deflate() and inflate() below for details */
  18998. //var Z_NO_FLUSH = 0;
  18999. //var Z_PARTIAL_FLUSH = 1;
  19000. //var Z_SYNC_FLUSH = 2;
  19001. //var Z_FULL_FLUSH = 3;
  19002. var Z_FINISH = 4;
  19003. var Z_BLOCK = 5;
  19004. var Z_TREES = 6;
  19005. /* Return codes for the compression/decompression functions. Negative values
  19006. * are errors, positive values are used for special but normal events.
  19007. */
  19008. var Z_OK = 0;
  19009. var Z_STREAM_END = 1;
  19010. var Z_NEED_DICT = 2;
  19011. //var Z_ERRNO = -1;
  19012. var Z_STREAM_ERROR = -2;
  19013. var Z_DATA_ERROR = -3;
  19014. var Z_MEM_ERROR = -4;
  19015. var Z_BUF_ERROR = -5;
  19016. //var Z_VERSION_ERROR = -6;
  19017. /* The deflate compression method */
  19018. var Z_DEFLATED = 8;
  19019. /* STATES ====================================================================*/
  19020. /* ===========================================================================*/
  19021. var HEAD = 1; /* i: waiting for magic header */
  19022. var FLAGS = 2; /* i: waiting for method and flags (gzip) */
  19023. var TIME = 3; /* i: waiting for modification time (gzip) */
  19024. var OS = 4; /* i: waiting for extra flags and operating system (gzip) */
  19025. var EXLEN = 5; /* i: waiting for extra length (gzip) */
  19026. var EXTRA = 6; /* i: waiting for extra bytes (gzip) */
  19027. var NAME = 7; /* i: waiting for end of file name (gzip) */
  19028. var COMMENT = 8; /* i: waiting for end of comment (gzip) */
  19029. var HCRC = 9; /* i: waiting for header crc (gzip) */
  19030. var DICTID = 10; /* i: waiting for dictionary check value */
  19031. var DICT = 11; /* waiting for inflateSetDictionary() call */
  19032. var TYPE = 12; /* i: waiting for type bits, including last-flag bit */
  19033. var TYPEDO = 13; /* i: same, but skip check to exit inflate on new block */
  19034. var STORED = 14; /* i: waiting for stored size (length and complement) */
  19035. var COPY_ = 15; /* i/o: same as COPY below, but only first time in */
  19036. var COPY = 16; /* i/o: waiting for input or output to copy stored block */
  19037. var TABLE = 17; /* i: waiting for dynamic block table lengths */
  19038. var LENLENS = 18; /* i: waiting for code length code lengths */
  19039. var CODELENS = 19; /* i: waiting for length/lit and distance code lengths */
  19040. var LEN_ = 20; /* i: same as LEN below, but only first time in */
  19041. var LEN = 21; /* i: waiting for length/lit/eob code */
  19042. var LENEXT = 22; /* i: waiting for length extra bits */
  19043. var DIST = 23; /* i: waiting for distance code */
  19044. var DISTEXT = 24; /* i: waiting for distance extra bits */
  19045. var MATCH = 25; /* o: waiting for output space to copy string */
  19046. var LIT = 26; /* o: waiting for output space to write literal */
  19047. var CHECK = 27; /* i: waiting for 32-bit check value */
  19048. var LENGTH = 28; /* i: waiting for 32-bit length (gzip) */
  19049. var DONE = 29; /* finished check, done -- remain here until reset */
  19050. var BAD = 30; /* got a data error -- remain here until reset */
  19051. var MEM = 31; /* got an inflate() memory error -- remain here until reset */
  19052. var SYNC = 32; /* looking for synchronization bytes to restart inflate() */
  19053. /* ===========================================================================*/
  19054. var ENOUGH_LENS = 852;
  19055. var ENOUGH_DISTS = 592;
  19056. //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
  19057. var MAX_WBITS = 15;
  19058. /* 32K LZ77 window */
  19059. var DEF_WBITS = MAX_WBITS;
  19060. function ZSWAP32(q) {
  19061. return (((q >>> 24) & 0xff) +
  19062. ((q >>> 8) & 0xff00) +
  19063. ((q & 0xff00) << 8) +
  19064. ((q & 0xff) << 24));
  19065. }
  19066. function InflateState() {
  19067. this.mode = 0; /* current inflate mode */
  19068. this.last = false; /* true if processing last block */
  19069. this.wrap = 0; /* bit 0 true for zlib, bit 1 true for gzip */
  19070. this.havedict = false; /* true if dictionary provided */
  19071. this.flags = 0; /* gzip header method and flags (0 if zlib) */
  19072. this.dmax = 0; /* zlib header max distance (INFLATE_STRICT) */
  19073. this.check = 0; /* protected copy of check value */
  19074. this.total = 0; /* protected copy of output count */
  19075. // TODO: may be {}
  19076. this.head = null; /* where to save gzip header information */
  19077. /* sliding window */
  19078. this.wbits = 0; /* log base 2 of requested window size */
  19079. this.wsize = 0; /* window size or zero if not using window */
  19080. this.whave = 0; /* valid bytes in the window */
  19081. this.wnext = 0; /* window write index */
  19082. this.window = null; /* allocated sliding window, if needed */
  19083. /* bit accumulator */
  19084. this.hold = 0; /* input bit accumulator */
  19085. this.bits = 0; /* number of bits in "in" */
  19086. /* for string and stored block copying */
  19087. this.length = 0; /* literal or length of data to copy */
  19088. this.offset = 0; /* distance back to copy string from */
  19089. /* for table and code decoding */
  19090. this.extra = 0; /* extra bits needed */
  19091. /* fixed and dynamic code tables */
  19092. this.lencode = null; /* starting table for length/literal codes */
  19093. this.distcode = null; /* starting table for distance codes */
  19094. this.lenbits = 0; /* index bits for lencode */
  19095. this.distbits = 0; /* index bits for distcode */
  19096. /* dynamic table building */
  19097. this.ncode = 0; /* number of code length code lengths */
  19098. this.nlen = 0; /* number of length code lengths */
  19099. this.ndist = 0; /* number of distance code lengths */
  19100. this.have = 0; /* number of code lengths in lens[] */
  19101. this.next = null; /* next available space in codes[] */
  19102. this.lens = new utils.Buf16(320); /* temporary storage for code lengths */
  19103. this.work = new utils.Buf16(288); /* work area for code table building */
  19104. /*
  19105. because we don't have pointers in js, we use lencode and distcode directly
  19106. as buffers so we don't need codes
  19107. */
  19108. //this.codes = new utils.Buf32(ENOUGH); /* space for code tables */
  19109. this.lendyn = null; /* dynamic table for length/literal codes (JS specific) */
  19110. this.distdyn = null; /* dynamic table for distance codes (JS specific) */
  19111. this.sane = 0; /* if false, allow invalid distance too far */
  19112. this.back = 0; /* bits back of last unprocessed length/lit */
  19113. this.was = 0; /* initial length of match */
  19114. }
  19115. function inflateResetKeep(strm) {
  19116. var state;
  19117. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  19118. state = strm.state;
  19119. strm.total_in = strm.total_out = state.total = 0;
  19120. strm.msg = ''; /*Z_NULL*/
  19121. if (state.wrap) { /* to support ill-conceived Java test suite */
  19122. strm.adler = state.wrap & 1;
  19123. }
  19124. state.mode = HEAD;
  19125. state.last = 0;
  19126. state.havedict = 0;
  19127. state.dmax = 32768;
  19128. state.head = null/*Z_NULL*/;
  19129. state.hold = 0;
  19130. state.bits = 0;
  19131. //state.lencode = state.distcode = state.next = state.codes;
  19132. state.lencode = state.lendyn = new utils.Buf32(ENOUGH_LENS);
  19133. state.distcode = state.distdyn = new utils.Buf32(ENOUGH_DISTS);
  19134. state.sane = 1;
  19135. state.back = -1;
  19136. //Tracev((stderr, "inflate: reset\n"));
  19137. return Z_OK;
  19138. }
  19139. function inflateReset(strm) {
  19140. var state;
  19141. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  19142. state = strm.state;
  19143. state.wsize = 0;
  19144. state.whave = 0;
  19145. state.wnext = 0;
  19146. return inflateResetKeep(strm);
  19147. }
  19148. function inflateReset2(strm, windowBits) {
  19149. var wrap;
  19150. var state;
  19151. /* get the state */
  19152. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  19153. state = strm.state;
  19154. /* extract wrap request from windowBits parameter */
  19155. if (windowBits < 0) {
  19156. wrap = 0;
  19157. windowBits = -windowBits;
  19158. }
  19159. else {
  19160. wrap = (windowBits >> 4) + 1;
  19161. if (windowBits < 48) {
  19162. windowBits &= 15;
  19163. }
  19164. }
  19165. /* set number of window bits, free window if different */
  19166. if (windowBits && (windowBits < 8 || windowBits > 15)) {
  19167. return Z_STREAM_ERROR;
  19168. }
  19169. if (state.window !== null && state.wbits !== windowBits) {
  19170. state.window = null;
  19171. }
  19172. /* update state and reset the rest of it */
  19173. state.wrap = wrap;
  19174. state.wbits = windowBits;
  19175. return inflateReset(strm);
  19176. }
  19177. function inflateInit2(strm, windowBits) {
  19178. var ret;
  19179. var state;
  19180. if (!strm) { return Z_STREAM_ERROR; }
  19181. //strm.msg = Z_NULL; /* in case we return an error */
  19182. state = new InflateState();
  19183. //if (state === Z_NULL) return Z_MEM_ERROR;
  19184. //Tracev((stderr, "inflate: allocated\n"));
  19185. strm.state = state;
  19186. state.window = null/*Z_NULL*/;
  19187. ret = inflateReset2(strm, windowBits);
  19188. if (ret !== Z_OK) {
  19189. strm.state = null/*Z_NULL*/;
  19190. }
  19191. return ret;
  19192. }
  19193. function inflateInit(strm) {
  19194. return inflateInit2(strm, DEF_WBITS);
  19195. }
  19196. /*
  19197. Return state with length and distance decoding tables and index sizes set to
  19198. fixed code decoding. Normally this returns fixed tables from inffixed.h.
  19199. If BUILDFIXED is defined, then instead this routine builds the tables the
  19200. first time it's called, and returns those tables the first time and
  19201. thereafter. This reduces the size of the code by about 2K bytes, in
  19202. exchange for a little execution time. However, BUILDFIXED should not be
  19203. used for threaded applications, since the rewriting of the tables and virgin
  19204. may not be thread-safe.
  19205. */
  19206. var virgin = true;
  19207. var lenfix, distfix; // We have no pointers in JS, so keep tables separate
  19208. function fixedtables(state) {
  19209. /* build fixed huffman tables if first call (may not be thread safe) */
  19210. if (virgin) {
  19211. var sym;
  19212. lenfix = new utils.Buf32(512);
  19213. distfix = new utils.Buf32(32);
  19214. /* literal/length table */
  19215. sym = 0;
  19216. while (sym < 144) { state.lens[sym++] = 8; }
  19217. while (sym < 256) { state.lens[sym++] = 9; }
  19218. while (sym < 280) { state.lens[sym++] = 7; }
  19219. while (sym < 288) { state.lens[sym++] = 8; }
  19220. inflate_table(LENS, state.lens, 0, 288, lenfix, 0, state.work, {bits: 9});
  19221. /* distance table */
  19222. sym = 0;
  19223. while (sym < 32) { state.lens[sym++] = 5; }
  19224. inflate_table(DISTS, state.lens, 0, 32, distfix, 0, state.work, {bits: 5});
  19225. /* do this just once */
  19226. virgin = false;
  19227. }
  19228. state.lencode = lenfix;
  19229. state.lenbits = 9;
  19230. state.distcode = distfix;
  19231. state.distbits = 5;
  19232. }
  19233. /*
  19234. Update the window with the last wsize (normally 32K) bytes written before
  19235. returning. If window does not exist yet, create it. This is only called
  19236. when a window is already in use, or when output has been written during this
  19237. inflate call, but the end of the deflate stream has not been reached yet.
  19238. It is also called to create a window for dictionary data when a dictionary
  19239. is loaded.
  19240. Providing output buffers larger than 32K to inflate() should provide a speed
  19241. advantage, since only the last 32K of output is copied to the sliding window
  19242. upon return from inflate(), and since all distances after the first 32K of
  19243. output will fall in the output data, making match copies simpler and faster.
  19244. The advantage may be dependent on the size of the processor's data caches.
  19245. */
  19246. function updatewindow(strm, src, end, copy) {
  19247. var dist;
  19248. var state = strm.state;
  19249. /* if it hasn't been done already, allocate space for the window */
  19250. if (state.window === null) {
  19251. state.wsize = 1 << state.wbits;
  19252. state.wnext = 0;
  19253. state.whave = 0;
  19254. state.window = new utils.Buf8(state.wsize);
  19255. }
  19256. /* copy state->wsize or less output bytes into the circular window */
  19257. if (copy >= state.wsize) {
  19258. utils.arraySet(state.window,src, end - state.wsize, state.wsize, 0);
  19259. state.wnext = 0;
  19260. state.whave = state.wsize;
  19261. }
  19262. else {
  19263. dist = state.wsize - state.wnext;
  19264. if (dist > copy) {
  19265. dist = copy;
  19266. }
  19267. //zmemcpy(state->window + state->wnext, end - copy, dist);
  19268. utils.arraySet(state.window,src, end - copy, dist, state.wnext);
  19269. copy -= dist;
  19270. if (copy) {
  19271. //zmemcpy(state->window, end - copy, copy);
  19272. utils.arraySet(state.window,src, end - copy, copy, 0);
  19273. state.wnext = copy;
  19274. state.whave = state.wsize;
  19275. }
  19276. else {
  19277. state.wnext += dist;
  19278. if (state.wnext === state.wsize) { state.wnext = 0; }
  19279. if (state.whave < state.wsize) { state.whave += dist; }
  19280. }
  19281. }
  19282. return 0;
  19283. }
  19284. function inflate(strm, flush) {
  19285. var state;
  19286. var input, output; // input/output buffers
  19287. var next; /* next input INDEX */
  19288. var put; /* next output INDEX */
  19289. var have, left; /* available input and output */
  19290. var hold; /* bit buffer */
  19291. var bits; /* bits in bit buffer */
  19292. var _in, _out; /* save starting available input and output */
  19293. var copy; /* number of stored or match bytes to copy */
  19294. var from; /* where to copy match bytes from */
  19295. var from_source;
  19296. var here = 0; /* current decoding table entry */
  19297. var here_bits, here_op, here_val; // paked "here" denormalized (JS specific)
  19298. //var last; /* parent table entry */
  19299. var last_bits, last_op, last_val; // paked "last" denormalized (JS specific)
  19300. var len; /* length to copy for repeats, bits to drop */
  19301. var ret; /* return code */
  19302. var hbuf = new utils.Buf8(4); /* buffer for gzip header crc calculation */
  19303. var opts;
  19304. var n; // temporary var for NEED_BITS
  19305. var order = /* permutation of code lengths */
  19306. [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];
  19307. if (!strm || !strm.state || !strm.output ||
  19308. (!strm.input && strm.avail_in !== 0)) {
  19309. return Z_STREAM_ERROR;
  19310. }
  19311. state = strm.state;
  19312. if (state.mode === TYPE) { state.mode = TYPEDO; } /* skip check */
  19313. //--- LOAD() ---
  19314. put = strm.next_out;
  19315. output = strm.output;
  19316. left = strm.avail_out;
  19317. next = strm.next_in;
  19318. input = strm.input;
  19319. have = strm.avail_in;
  19320. hold = state.hold;
  19321. bits = state.bits;
  19322. //---
  19323. _in = have;
  19324. _out = left;
  19325. ret = Z_OK;
  19326. inf_leave: // goto emulation
  19327. for (;;) {
  19328. switch (state.mode) {
  19329. case HEAD:
  19330. if (state.wrap === 0) {
  19331. state.mode = TYPEDO;
  19332. break;
  19333. }
  19334. //=== NEEDBITS(16);
  19335. while (bits < 16) {
  19336. if (have === 0) { break inf_leave; }
  19337. have--;
  19338. hold += input[next++] << bits;
  19339. bits += 8;
  19340. }
  19341. //===//
  19342. if ((state.wrap & 2) && hold === 0x8b1f) { /* gzip header */
  19343. state.check = 0/*crc32(0L, Z_NULL, 0)*/;
  19344. //=== CRC2(state.check, hold);
  19345. hbuf[0] = hold & 0xff;
  19346. hbuf[1] = (hold >>> 8) & 0xff;
  19347. state.check = crc32(state.check, hbuf, 2, 0);
  19348. //===//
  19349. //=== INITBITS();
  19350. hold = 0;
  19351. bits = 0;
  19352. //===//
  19353. state.mode = FLAGS;
  19354. break;
  19355. }
  19356. state.flags = 0; /* expect zlib header */
  19357. if (state.head) {
  19358. state.head.done = false;
  19359. }
  19360. if (!(state.wrap & 1) || /* check if zlib header allowed */
  19361. (((hold & 0xff)/*BITS(8)*/ << 8) + (hold >> 8)) % 31) {
  19362. strm.msg = 'incorrect header check';
  19363. state.mode = BAD;
  19364. break;
  19365. }
  19366. if ((hold & 0x0f)/*BITS(4)*/ !== Z_DEFLATED) {
  19367. strm.msg = 'unknown compression method';
  19368. state.mode = BAD;
  19369. break;
  19370. }
  19371. //--- DROPBITS(4) ---//
  19372. hold >>>= 4;
  19373. bits -= 4;
  19374. //---//
  19375. len = (hold & 0x0f)/*BITS(4)*/ + 8;
  19376. if (state.wbits === 0) {
  19377. state.wbits = len;
  19378. }
  19379. else if (len > state.wbits) {
  19380. strm.msg = 'invalid window size';
  19381. state.mode = BAD;
  19382. break;
  19383. }
  19384. state.dmax = 1 << len;
  19385. //Tracev((stderr, "inflate: zlib header ok\n"));
  19386. strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
  19387. state.mode = hold & 0x200 ? DICTID : TYPE;
  19388. //=== INITBITS();
  19389. hold = 0;
  19390. bits = 0;
  19391. //===//
  19392. break;
  19393. case FLAGS:
  19394. //=== NEEDBITS(16); */
  19395. while (bits < 16) {
  19396. if (have === 0) { break inf_leave; }
  19397. have--;
  19398. hold += input[next++] << bits;
  19399. bits += 8;
  19400. }
  19401. //===//
  19402. state.flags = hold;
  19403. if ((state.flags & 0xff) !== Z_DEFLATED) {
  19404. strm.msg = 'unknown compression method';
  19405. state.mode = BAD;
  19406. break;
  19407. }
  19408. if (state.flags & 0xe000) {
  19409. strm.msg = 'unknown header flags set';
  19410. state.mode = BAD;
  19411. break;
  19412. }
  19413. if (state.head) {
  19414. state.head.text = ((hold >> 8) & 1);
  19415. }
  19416. if (state.flags & 0x0200) {
  19417. //=== CRC2(state.check, hold);
  19418. hbuf[0] = hold & 0xff;
  19419. hbuf[1] = (hold >>> 8) & 0xff;
  19420. state.check = crc32(state.check, hbuf, 2, 0);
  19421. //===//
  19422. }
  19423. //=== INITBITS();
  19424. hold = 0;
  19425. bits = 0;
  19426. //===//
  19427. state.mode = TIME;
  19428. /* falls through */
  19429. case TIME:
  19430. //=== NEEDBITS(32); */
  19431. while (bits < 32) {
  19432. if (have === 0) { break inf_leave; }
  19433. have--;
  19434. hold += input[next++] << bits;
  19435. bits += 8;
  19436. }
  19437. //===//
  19438. if (state.head) {
  19439. state.head.time = hold;
  19440. }
  19441. if (state.flags & 0x0200) {
  19442. //=== CRC4(state.check, hold)
  19443. hbuf[0] = hold & 0xff;
  19444. hbuf[1] = (hold >>> 8) & 0xff;
  19445. hbuf[2] = (hold >>> 16) & 0xff;
  19446. hbuf[3] = (hold >>> 24) & 0xff;
  19447. state.check = crc32(state.check, hbuf, 4, 0);
  19448. //===
  19449. }
  19450. //=== INITBITS();
  19451. hold = 0;
  19452. bits = 0;
  19453. //===//
  19454. state.mode = OS;
  19455. /* falls through */
  19456. case OS:
  19457. //=== NEEDBITS(16); */
  19458. while (bits < 16) {
  19459. if (have === 0) { break inf_leave; }
  19460. have--;
  19461. hold += input[next++] << bits;
  19462. bits += 8;
  19463. }
  19464. //===//
  19465. if (state.head) {
  19466. state.head.xflags = (hold & 0xff);
  19467. state.head.os = (hold >> 8);
  19468. }
  19469. if (state.flags & 0x0200) {
  19470. //=== CRC2(state.check, hold);
  19471. hbuf[0] = hold & 0xff;
  19472. hbuf[1] = (hold >>> 8) & 0xff;
  19473. state.check = crc32(state.check, hbuf, 2, 0);
  19474. //===//
  19475. }
  19476. //=== INITBITS();
  19477. hold = 0;
  19478. bits = 0;
  19479. //===//
  19480. state.mode = EXLEN;
  19481. /* falls through */
  19482. case EXLEN:
  19483. if (state.flags & 0x0400) {
  19484. //=== NEEDBITS(16); */
  19485. while (bits < 16) {
  19486. if (have === 0) { break inf_leave; }
  19487. have--;
  19488. hold += input[next++] << bits;
  19489. bits += 8;
  19490. }
  19491. //===//
  19492. state.length = hold;
  19493. if (state.head) {
  19494. state.head.extra_len = hold;
  19495. }
  19496. if (state.flags & 0x0200) {
  19497. //=== CRC2(state.check, hold);
  19498. hbuf[0] = hold & 0xff;
  19499. hbuf[1] = (hold >>> 8) & 0xff;
  19500. state.check = crc32(state.check, hbuf, 2, 0);
  19501. //===//
  19502. }
  19503. //=== INITBITS();
  19504. hold = 0;
  19505. bits = 0;
  19506. //===//
  19507. }
  19508. else if (state.head) {
  19509. state.head.extra = null/*Z_NULL*/;
  19510. }
  19511. state.mode = EXTRA;
  19512. /* falls through */
  19513. case EXTRA:
  19514. if (state.flags & 0x0400) {
  19515. copy = state.length;
  19516. if (copy > have) { copy = have; }
  19517. if (copy) {
  19518. if (state.head) {
  19519. len = state.head.extra_len - state.length;
  19520. if (!state.head.extra) {
  19521. // Use untyped array for more conveniend processing later
  19522. state.head.extra = new Array(state.head.extra_len);
  19523. }
  19524. utils.arraySet(
  19525. state.head.extra,
  19526. input,
  19527. next,
  19528. // extra field is limited to 65536 bytes
  19529. // - no need for additional size check
  19530. copy,
  19531. /*len + copy > state.head.extra_max - len ? state.head.extra_max : copy,*/
  19532. len
  19533. );
  19534. //zmemcpy(state.head.extra + len, next,
  19535. // len + copy > state.head.extra_max ?
  19536. // state.head.extra_max - len : copy);
  19537. }
  19538. if (state.flags & 0x0200) {
  19539. state.check = crc32(state.check, input, copy, next);
  19540. }
  19541. have -= copy;
  19542. next += copy;
  19543. state.length -= copy;
  19544. }
  19545. if (state.length) { break inf_leave; }
  19546. }
  19547. state.length = 0;
  19548. state.mode = NAME;
  19549. /* falls through */
  19550. case NAME:
  19551. if (state.flags & 0x0800) {
  19552. if (have === 0) { break inf_leave; }
  19553. copy = 0;
  19554. do {
  19555. // TODO: 2 or 1 bytes?
  19556. len = input[next + copy++];
  19557. /* use constant limit because in js we should not preallocate memory */
  19558. if (state.head && len &&
  19559. (state.length < 65536 /*state.head.name_max*/)) {
  19560. state.head.name += String.fromCharCode(len);
  19561. }
  19562. } while (len && copy < have);
  19563. if (state.flags & 0x0200) {
  19564. state.check = crc32(state.check, input, copy, next);
  19565. }
  19566. have -= copy;
  19567. next += copy;
  19568. if (len) { break inf_leave; }
  19569. }
  19570. else if (state.head) {
  19571. state.head.name = null;
  19572. }
  19573. state.length = 0;
  19574. state.mode = COMMENT;
  19575. /* falls through */
  19576. case COMMENT:
  19577. if (state.flags & 0x1000) {
  19578. if (have === 0) { break inf_leave; }
  19579. copy = 0;
  19580. do {
  19581. len = input[next + copy++];
  19582. /* use constant limit because in js we should not preallocate memory */
  19583. if (state.head && len &&
  19584. (state.length < 65536 /*state.head.comm_max*/)) {
  19585. state.head.comment += String.fromCharCode(len);
  19586. }
  19587. } while (len && copy < have);
  19588. if (state.flags & 0x0200) {
  19589. state.check = crc32(state.check, input, copy, next);
  19590. }
  19591. have -= copy;
  19592. next += copy;
  19593. if (len) { break inf_leave; }
  19594. }
  19595. else if (state.head) {
  19596. state.head.comment = null;
  19597. }
  19598. state.mode = HCRC;
  19599. /* falls through */
  19600. case HCRC:
  19601. if (state.flags & 0x0200) {
  19602. //=== NEEDBITS(16); */
  19603. while (bits < 16) {
  19604. if (have === 0) { break inf_leave; }
  19605. have--;
  19606. hold += input[next++] << bits;
  19607. bits += 8;
  19608. }
  19609. //===//
  19610. if (hold !== (state.check & 0xffff)) {
  19611. strm.msg = 'header crc mismatch';
  19612. state.mode = BAD;
  19613. break;
  19614. }
  19615. //=== INITBITS();
  19616. hold = 0;
  19617. bits = 0;
  19618. //===//
  19619. }
  19620. if (state.head) {
  19621. state.head.hcrc = ((state.flags >> 9) & 1);
  19622. state.head.done = true;
  19623. }
  19624. strm.adler = state.check = 0 /*crc32(0L, Z_NULL, 0)*/;
  19625. state.mode = TYPE;
  19626. break;
  19627. case DICTID:
  19628. //=== NEEDBITS(32); */
  19629. while (bits < 32) {
  19630. if (have === 0) { break inf_leave; }
  19631. have--;
  19632. hold += input[next++] << bits;
  19633. bits += 8;
  19634. }
  19635. //===//
  19636. strm.adler = state.check = ZSWAP32(hold);
  19637. //=== INITBITS();
  19638. hold = 0;
  19639. bits = 0;
  19640. //===//
  19641. state.mode = DICT;
  19642. /* falls through */
  19643. case DICT:
  19644. if (state.havedict === 0) {
  19645. //--- RESTORE() ---
  19646. strm.next_out = put;
  19647. strm.avail_out = left;
  19648. strm.next_in = next;
  19649. strm.avail_in = have;
  19650. state.hold = hold;
  19651. state.bits = bits;
  19652. //---
  19653. return Z_NEED_DICT;
  19654. }
  19655. strm.adler = state.check = 1/*adler32(0L, Z_NULL, 0)*/;
  19656. state.mode = TYPE;
  19657. /* falls through */
  19658. case TYPE:
  19659. if (flush === Z_BLOCK || flush === Z_TREES) { break inf_leave; }
  19660. /* falls through */
  19661. case TYPEDO:
  19662. if (state.last) {
  19663. //--- BYTEBITS() ---//
  19664. hold >>>= bits & 7;
  19665. bits -= bits & 7;
  19666. //---//
  19667. state.mode = CHECK;
  19668. break;
  19669. }
  19670. //=== NEEDBITS(3); */
  19671. while (bits < 3) {
  19672. if (have === 0) { break inf_leave; }
  19673. have--;
  19674. hold += input[next++] << bits;
  19675. bits += 8;
  19676. }
  19677. //===//
  19678. state.last = (hold & 0x01)/*BITS(1)*/;
  19679. //--- DROPBITS(1) ---//
  19680. hold >>>= 1;
  19681. bits -= 1;
  19682. //---//
  19683. switch ((hold & 0x03)/*BITS(2)*/) {
  19684. case 0: /* stored block */
  19685. //Tracev((stderr, "inflate: stored block%s\n",
  19686. // state.last ? " (last)" : ""));
  19687. state.mode = STORED;
  19688. break;
  19689. case 1: /* fixed block */
  19690. fixedtables(state);
  19691. //Tracev((stderr, "inflate: fixed codes block%s\n",
  19692. // state.last ? " (last)" : ""));
  19693. state.mode = LEN_; /* decode codes */
  19694. if (flush === Z_TREES) {
  19695. //--- DROPBITS(2) ---//
  19696. hold >>>= 2;
  19697. bits -= 2;
  19698. //---//
  19699. break inf_leave;
  19700. }
  19701. break;
  19702. case 2: /* dynamic block */
  19703. //Tracev((stderr, "inflate: dynamic codes block%s\n",
  19704. // state.last ? " (last)" : ""));
  19705. state.mode = TABLE;
  19706. break;
  19707. case 3:
  19708. strm.msg = 'invalid block type';
  19709. state.mode = BAD;
  19710. }
  19711. //--- DROPBITS(2) ---//
  19712. hold >>>= 2;
  19713. bits -= 2;
  19714. //---//
  19715. break;
  19716. case STORED:
  19717. //--- BYTEBITS() ---// /* go to byte boundary */
  19718. hold >>>= bits & 7;
  19719. bits -= bits & 7;
  19720. //---//
  19721. //=== NEEDBITS(32); */
  19722. while (bits < 32) {
  19723. if (have === 0) { break inf_leave; }
  19724. have--;
  19725. hold += input[next++] << bits;
  19726. bits += 8;
  19727. }
  19728. //===//
  19729. if ((hold & 0xffff) !== ((hold >>> 16) ^ 0xffff)) {
  19730. strm.msg = 'invalid stored block lengths';
  19731. state.mode = BAD;
  19732. break;
  19733. }
  19734. state.length = hold & 0xffff;
  19735. //Tracev((stderr, "inflate: stored length %u\n",
  19736. // state.length));
  19737. //=== INITBITS();
  19738. hold = 0;
  19739. bits = 0;
  19740. //===//
  19741. state.mode = COPY_;
  19742. if (flush === Z_TREES) { break inf_leave; }
  19743. /* falls through */
  19744. case COPY_:
  19745. state.mode = COPY;
  19746. /* falls through */
  19747. case COPY:
  19748. copy = state.length;
  19749. if (copy) {
  19750. if (copy > have) { copy = have; }
  19751. if (copy > left) { copy = left; }
  19752. if (copy === 0) { break inf_leave; }
  19753. //--- zmemcpy(put, next, copy); ---
  19754. utils.arraySet(output, input, next, copy, put);
  19755. //---//
  19756. have -= copy;
  19757. next += copy;
  19758. left -= copy;
  19759. put += copy;
  19760. state.length -= copy;
  19761. break;
  19762. }
  19763. //Tracev((stderr, "inflate: stored end\n"));
  19764. state.mode = TYPE;
  19765. break;
  19766. case TABLE:
  19767. //=== NEEDBITS(14); */
  19768. while (bits < 14) {
  19769. if (have === 0) { break inf_leave; }
  19770. have--;
  19771. hold += input[next++] << bits;
  19772. bits += 8;
  19773. }
  19774. //===//
  19775. state.nlen = (hold & 0x1f)/*BITS(5)*/ + 257;
  19776. //--- DROPBITS(5) ---//
  19777. hold >>>= 5;
  19778. bits -= 5;
  19779. //---//
  19780. state.ndist = (hold & 0x1f)/*BITS(5)*/ + 1;
  19781. //--- DROPBITS(5) ---//
  19782. hold >>>= 5;
  19783. bits -= 5;
  19784. //---//
  19785. state.ncode = (hold & 0x0f)/*BITS(4)*/ + 4;
  19786. //--- DROPBITS(4) ---//
  19787. hold >>>= 4;
  19788. bits -= 4;
  19789. //---//
  19790. //#ifndef PKZIP_BUG_WORKAROUND
  19791. if (state.nlen > 286 || state.ndist > 30) {
  19792. strm.msg = 'too many length or distance symbols';
  19793. state.mode = BAD;
  19794. break;
  19795. }
  19796. //#endif
  19797. //Tracev((stderr, "inflate: table sizes ok\n"));
  19798. state.have = 0;
  19799. state.mode = LENLENS;
  19800. /* falls through */
  19801. case LENLENS:
  19802. while (state.have < state.ncode) {
  19803. //=== NEEDBITS(3);
  19804. while (bits < 3) {
  19805. if (have === 0) { break inf_leave; }
  19806. have--;
  19807. hold += input[next++] << bits;
  19808. bits += 8;
  19809. }
  19810. //===//
  19811. state.lens[order[state.have++]] = (hold & 0x07);//BITS(3);
  19812. //--- DROPBITS(3) ---//
  19813. hold >>>= 3;
  19814. bits -= 3;
  19815. //---//
  19816. }
  19817. while (state.have < 19) {
  19818. state.lens[order[state.have++]] = 0;
  19819. }
  19820. // We have separate tables & no pointers. 2 commented lines below not needed.
  19821. //state.next = state.codes;
  19822. //state.lencode = state.next;
  19823. // Switch to use dynamic table
  19824. state.lencode = state.lendyn;
  19825. state.lenbits = 7;
  19826. opts = {bits: state.lenbits};
  19827. ret = inflate_table(CODES, state.lens, 0, 19, state.lencode, 0, state.work, opts);
  19828. state.lenbits = opts.bits;
  19829. if (ret) {
  19830. strm.msg = 'invalid code lengths set';
  19831. state.mode = BAD;
  19832. break;
  19833. }
  19834. //Tracev((stderr, "inflate: code lengths ok\n"));
  19835. state.have = 0;
  19836. state.mode = CODELENS;
  19837. /* falls through */
  19838. case CODELENS:
  19839. while (state.have < state.nlen + state.ndist) {
  19840. for (;;) {
  19841. here = state.lencode[hold & ((1 << state.lenbits) - 1)];/*BITS(state.lenbits)*/
  19842. here_bits = here >>> 24;
  19843. here_op = (here >>> 16) & 0xff;
  19844. here_val = here & 0xffff;
  19845. if ((here_bits) <= bits) { break; }
  19846. //--- PULLBYTE() ---//
  19847. if (have === 0) { break inf_leave; }
  19848. have--;
  19849. hold += input[next++] << bits;
  19850. bits += 8;
  19851. //---//
  19852. }
  19853. if (here_val < 16) {
  19854. //--- DROPBITS(here.bits) ---//
  19855. hold >>>= here_bits;
  19856. bits -= here_bits;
  19857. //---//
  19858. state.lens[state.have++] = here_val;
  19859. }
  19860. else {
  19861. if (here_val === 16) {
  19862. //=== NEEDBITS(here.bits + 2);
  19863. n = here_bits + 2;
  19864. while (bits < n) {
  19865. if (have === 0) { break inf_leave; }
  19866. have--;
  19867. hold += input[next++] << bits;
  19868. bits += 8;
  19869. }
  19870. //===//
  19871. //--- DROPBITS(here.bits) ---//
  19872. hold >>>= here_bits;
  19873. bits -= here_bits;
  19874. //---//
  19875. if (state.have === 0) {
  19876. strm.msg = 'invalid bit length repeat';
  19877. state.mode = BAD;
  19878. break;
  19879. }
  19880. len = state.lens[state.have - 1];
  19881. copy = 3 + (hold & 0x03);//BITS(2);
  19882. //--- DROPBITS(2) ---//
  19883. hold >>>= 2;
  19884. bits -= 2;
  19885. //---//
  19886. }
  19887. else if (here_val === 17) {
  19888. //=== NEEDBITS(here.bits + 3);
  19889. n = here_bits + 3;
  19890. while (bits < n) {
  19891. if (have === 0) { break inf_leave; }
  19892. have--;
  19893. hold += input[next++] << bits;
  19894. bits += 8;
  19895. }
  19896. //===//
  19897. //--- DROPBITS(here.bits) ---//
  19898. hold >>>= here_bits;
  19899. bits -= here_bits;
  19900. //---//
  19901. len = 0;
  19902. copy = 3 + (hold & 0x07);//BITS(3);
  19903. //--- DROPBITS(3) ---//
  19904. hold >>>= 3;
  19905. bits -= 3;
  19906. //---//
  19907. }
  19908. else {
  19909. //=== NEEDBITS(here.bits + 7);
  19910. n = here_bits + 7;
  19911. while (bits < n) {
  19912. if (have === 0) { break inf_leave; }
  19913. have--;
  19914. hold += input[next++] << bits;
  19915. bits += 8;
  19916. }
  19917. //===//
  19918. //--- DROPBITS(here.bits) ---//
  19919. hold >>>= here_bits;
  19920. bits -= here_bits;
  19921. //---//
  19922. len = 0;
  19923. copy = 11 + (hold & 0x7f);//BITS(7);
  19924. //--- DROPBITS(7) ---//
  19925. hold >>>= 7;
  19926. bits -= 7;
  19927. //---//
  19928. }
  19929. if (state.have + copy > state.nlen + state.ndist) {
  19930. strm.msg = 'invalid bit length repeat';
  19931. state.mode = BAD;
  19932. break;
  19933. }
  19934. while (copy--) {
  19935. state.lens[state.have++] = len;
  19936. }
  19937. }
  19938. }
  19939. /* handle error breaks in while */
  19940. if (state.mode === BAD) { break; }
  19941. /* check for end-of-block code (better have one) */
  19942. if (state.lens[256] === 0) {
  19943. strm.msg = 'invalid code -- missing end-of-block';
  19944. state.mode = BAD;
  19945. break;
  19946. }
  19947. /* build code tables -- note: do not change the lenbits or distbits
  19948. values here (9 and 6) without reading the comments in inftrees.h
  19949. concerning the ENOUGH constants, which depend on those values */
  19950. state.lenbits = 9;
  19951. opts = {bits: state.lenbits};
  19952. ret = inflate_table(LENS, state.lens, 0, state.nlen, state.lencode, 0, state.work, opts);
  19953. // We have separate tables & no pointers. 2 commented lines below not needed.
  19954. // state.next_index = opts.table_index;
  19955. state.lenbits = opts.bits;
  19956. // state.lencode = state.next;
  19957. if (ret) {
  19958. strm.msg = 'invalid literal/lengths set';
  19959. state.mode = BAD;
  19960. break;
  19961. }
  19962. state.distbits = 6;
  19963. //state.distcode.copy(state.codes);
  19964. // Switch to use dynamic table
  19965. state.distcode = state.distdyn;
  19966. opts = {bits: state.distbits};
  19967. ret = inflate_table(DISTS, state.lens, state.nlen, state.ndist, state.distcode, 0, state.work, opts);
  19968. // We have separate tables & no pointers. 2 commented lines below not needed.
  19969. // state.next_index = opts.table_index;
  19970. state.distbits = opts.bits;
  19971. // state.distcode = state.next;
  19972. if (ret) {
  19973. strm.msg = 'invalid distances set';
  19974. state.mode = BAD;
  19975. break;
  19976. }
  19977. //Tracev((stderr, 'inflate: codes ok\n'));
  19978. state.mode = LEN_;
  19979. if (flush === Z_TREES) { break inf_leave; }
  19980. /* falls through */
  19981. case LEN_:
  19982. state.mode = LEN;
  19983. /* falls through */
  19984. case LEN:
  19985. if (have >= 6 && left >= 258) {
  19986. //--- RESTORE() ---
  19987. strm.next_out = put;
  19988. strm.avail_out = left;
  19989. strm.next_in = next;
  19990. strm.avail_in = have;
  19991. state.hold = hold;
  19992. state.bits = bits;
  19993. //---
  19994. inflate_fast(strm, _out);
  19995. //--- LOAD() ---
  19996. put = strm.next_out;
  19997. output = strm.output;
  19998. left = strm.avail_out;
  19999. next = strm.next_in;
  20000. input = strm.input;
  20001. have = strm.avail_in;
  20002. hold = state.hold;
  20003. bits = state.bits;
  20004. //---
  20005. if (state.mode === TYPE) {
  20006. state.back = -1;
  20007. }
  20008. break;
  20009. }
  20010. state.back = 0;
  20011. for (;;) {
  20012. here = state.lencode[hold & ((1 << state.lenbits) -1)]; /*BITS(state.lenbits)*/
  20013. here_bits = here >>> 24;
  20014. here_op = (here >>> 16) & 0xff;
  20015. here_val = here & 0xffff;
  20016. if (here_bits <= bits) { break; }
  20017. //--- PULLBYTE() ---//
  20018. if (have === 0) { break inf_leave; }
  20019. have--;
  20020. hold += input[next++] << bits;
  20021. bits += 8;
  20022. //---//
  20023. }
  20024. if (here_op && (here_op & 0xf0) === 0) {
  20025. last_bits = here_bits;
  20026. last_op = here_op;
  20027. last_val = here_val;
  20028. for (;;) {
  20029. here = state.lencode[last_val +
  20030. ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
  20031. here_bits = here >>> 24;
  20032. here_op = (here >>> 16) & 0xff;
  20033. here_val = here & 0xffff;
  20034. if ((last_bits + here_bits) <= bits) { break; }
  20035. //--- PULLBYTE() ---//
  20036. if (have === 0) { break inf_leave; }
  20037. have--;
  20038. hold += input[next++] << bits;
  20039. bits += 8;
  20040. //---//
  20041. }
  20042. //--- DROPBITS(last.bits) ---//
  20043. hold >>>= last_bits;
  20044. bits -= last_bits;
  20045. //---//
  20046. state.back += last_bits;
  20047. }
  20048. //--- DROPBITS(here.bits) ---//
  20049. hold >>>= here_bits;
  20050. bits -= here_bits;
  20051. //---//
  20052. state.back += here_bits;
  20053. state.length = here_val;
  20054. if (here_op === 0) {
  20055. //Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
  20056. // "inflate: literal '%c'\n" :
  20057. // "inflate: literal 0x%02x\n", here.val));
  20058. state.mode = LIT;
  20059. break;
  20060. }
  20061. if (here_op & 32) {
  20062. //Tracevv((stderr, "inflate: end of block\n"));
  20063. state.back = -1;
  20064. state.mode = TYPE;
  20065. break;
  20066. }
  20067. if (here_op & 64) {
  20068. strm.msg = 'invalid literal/length code';
  20069. state.mode = BAD;
  20070. break;
  20071. }
  20072. state.extra = here_op & 15;
  20073. state.mode = LENEXT;
  20074. /* falls through */
  20075. case LENEXT:
  20076. if (state.extra) {
  20077. //=== NEEDBITS(state.extra);
  20078. n = state.extra;
  20079. while (bits < n) {
  20080. if (have === 0) { break inf_leave; }
  20081. have--;
  20082. hold += input[next++] << bits;
  20083. bits += 8;
  20084. }
  20085. //===//
  20086. state.length += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
  20087. //--- DROPBITS(state.extra) ---//
  20088. hold >>>= state.extra;
  20089. bits -= state.extra;
  20090. //---//
  20091. state.back += state.extra;
  20092. }
  20093. //Tracevv((stderr, "inflate: length %u\n", state.length));
  20094. state.was = state.length;
  20095. state.mode = DIST;
  20096. /* falls through */
  20097. case DIST:
  20098. for (;;) {
  20099. here = state.distcode[hold & ((1 << state.distbits) -1)];/*BITS(state.distbits)*/
  20100. here_bits = here >>> 24;
  20101. here_op = (here >>> 16) & 0xff;
  20102. here_val = here & 0xffff;
  20103. if ((here_bits) <= bits) { break; }
  20104. //--- PULLBYTE() ---//
  20105. if (have === 0) { break inf_leave; }
  20106. have--;
  20107. hold += input[next++] << bits;
  20108. bits += 8;
  20109. //---//
  20110. }
  20111. if ((here_op & 0xf0) === 0) {
  20112. last_bits = here_bits;
  20113. last_op = here_op;
  20114. last_val = here_val;
  20115. for (;;) {
  20116. here = state.distcode[last_val +
  20117. ((hold & ((1 << (last_bits + last_op)) -1))/*BITS(last.bits + last.op)*/ >> last_bits)];
  20118. here_bits = here >>> 24;
  20119. here_op = (here >>> 16) & 0xff;
  20120. here_val = here & 0xffff;
  20121. if ((last_bits + here_bits) <= bits) { break; }
  20122. //--- PULLBYTE() ---//
  20123. if (have === 0) { break inf_leave; }
  20124. have--;
  20125. hold += input[next++] << bits;
  20126. bits += 8;
  20127. //---//
  20128. }
  20129. //--- DROPBITS(last.bits) ---//
  20130. hold >>>= last_bits;
  20131. bits -= last_bits;
  20132. //---//
  20133. state.back += last_bits;
  20134. }
  20135. //--- DROPBITS(here.bits) ---//
  20136. hold >>>= here_bits;
  20137. bits -= here_bits;
  20138. //---//
  20139. state.back += here_bits;
  20140. if (here_op & 64) {
  20141. strm.msg = 'invalid distance code';
  20142. state.mode = BAD;
  20143. break;
  20144. }
  20145. state.offset = here_val;
  20146. state.extra = (here_op) & 15;
  20147. state.mode = DISTEXT;
  20148. /* falls through */
  20149. case DISTEXT:
  20150. if (state.extra) {
  20151. //=== NEEDBITS(state.extra);
  20152. n = state.extra;
  20153. while (bits < n) {
  20154. if (have === 0) { break inf_leave; }
  20155. have--;
  20156. hold += input[next++] << bits;
  20157. bits += 8;
  20158. }
  20159. //===//
  20160. state.offset += hold & ((1 << state.extra) -1)/*BITS(state.extra)*/;
  20161. //--- DROPBITS(state.extra) ---//
  20162. hold >>>= state.extra;
  20163. bits -= state.extra;
  20164. //---//
  20165. state.back += state.extra;
  20166. }
  20167. //#ifdef INFLATE_STRICT
  20168. if (state.offset > state.dmax) {
  20169. strm.msg = 'invalid distance too far back';
  20170. state.mode = BAD;
  20171. break;
  20172. }
  20173. //#endif
  20174. //Tracevv((stderr, "inflate: distance %u\n", state.offset));
  20175. state.mode = MATCH;
  20176. /* falls through */
  20177. case MATCH:
  20178. if (left === 0) { break inf_leave; }
  20179. copy = _out - left;
  20180. if (state.offset > copy) { /* copy from window */
  20181. copy = state.offset - copy;
  20182. if (copy > state.whave) {
  20183. if (state.sane) {
  20184. strm.msg = 'invalid distance too far back';
  20185. state.mode = BAD;
  20186. break;
  20187. }
  20188. // (!) This block is disabled in zlib defailts,
  20189. // don't enable it for binary compatibility
  20190. //#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
  20191. // Trace((stderr, "inflate.c too far\n"));
  20192. // copy -= state.whave;
  20193. // if (copy > state.length) { copy = state.length; }
  20194. // if (copy > left) { copy = left; }
  20195. // left -= copy;
  20196. // state.length -= copy;
  20197. // do {
  20198. // output[put++] = 0;
  20199. // } while (--copy);
  20200. // if (state.length === 0) { state.mode = LEN; }
  20201. // break;
  20202. //#endif
  20203. }
  20204. if (copy > state.wnext) {
  20205. copy -= state.wnext;
  20206. from = state.wsize - copy;
  20207. }
  20208. else {
  20209. from = state.wnext - copy;
  20210. }
  20211. if (copy > state.length) { copy = state.length; }
  20212. from_source = state.window;
  20213. }
  20214. else { /* copy from output */
  20215. from_source = output;
  20216. from = put - state.offset;
  20217. copy = state.length;
  20218. }
  20219. if (copy > left) { copy = left; }
  20220. left -= copy;
  20221. state.length -= copy;
  20222. do {
  20223. output[put++] = from_source[from++];
  20224. } while (--copy);
  20225. if (state.length === 0) { state.mode = LEN; }
  20226. break;
  20227. case LIT:
  20228. if (left === 0) { break inf_leave; }
  20229. output[put++] = state.length;
  20230. left--;
  20231. state.mode = LEN;
  20232. break;
  20233. case CHECK:
  20234. if (state.wrap) {
  20235. //=== NEEDBITS(32);
  20236. while (bits < 32) {
  20237. if (have === 0) { break inf_leave; }
  20238. have--;
  20239. // Use '|' insdead of '+' to make sure that result is signed
  20240. hold |= input[next++] << bits;
  20241. bits += 8;
  20242. }
  20243. //===//
  20244. _out -= left;
  20245. strm.total_out += _out;
  20246. state.total += _out;
  20247. if (_out) {
  20248. strm.adler = state.check =
  20249. /*UPDATE(state.check, put - _out, _out);*/
  20250. (state.flags ? crc32(state.check, output, _out, put - _out) : adler32(state.check, output, _out, put - _out));
  20251. }
  20252. _out = left;
  20253. // NB: crc32 stored as signed 32-bit int, ZSWAP32 returns signed too
  20254. if ((state.flags ? hold : ZSWAP32(hold)) !== state.check) {
  20255. strm.msg = 'incorrect data check';
  20256. state.mode = BAD;
  20257. break;
  20258. }
  20259. //=== INITBITS();
  20260. hold = 0;
  20261. bits = 0;
  20262. //===//
  20263. //Tracev((stderr, "inflate: check matches trailer\n"));
  20264. }
  20265. state.mode = LENGTH;
  20266. /* falls through */
  20267. case LENGTH:
  20268. if (state.wrap && state.flags) {
  20269. //=== NEEDBITS(32);
  20270. while (bits < 32) {
  20271. if (have === 0) { break inf_leave; }
  20272. have--;
  20273. hold += input[next++] << bits;
  20274. bits += 8;
  20275. }
  20276. //===//
  20277. if (hold !== (state.total & 0xffffffff)) {
  20278. strm.msg = 'incorrect length check';
  20279. state.mode = BAD;
  20280. break;
  20281. }
  20282. //=== INITBITS();
  20283. hold = 0;
  20284. bits = 0;
  20285. //===//
  20286. //Tracev((stderr, "inflate: length matches trailer\n"));
  20287. }
  20288. state.mode = DONE;
  20289. /* falls through */
  20290. case DONE:
  20291. ret = Z_STREAM_END;
  20292. break inf_leave;
  20293. case BAD:
  20294. ret = Z_DATA_ERROR;
  20295. break inf_leave;
  20296. case MEM:
  20297. return Z_MEM_ERROR;
  20298. case SYNC:
  20299. /* falls through */
  20300. default:
  20301. return Z_STREAM_ERROR;
  20302. }
  20303. }
  20304. // inf_leave <- here is real place for "goto inf_leave", emulated via "break inf_leave"
  20305. /*
  20306. Return from inflate(), updating the total counts and the check value.
  20307. If there was no progress during the inflate() call, return a buffer
  20308. error. Call updatewindow() to create and/or update the window state.
  20309. Note: a memory error from inflate() is non-recoverable.
  20310. */
  20311. //--- RESTORE() ---
  20312. strm.next_out = put;
  20313. strm.avail_out = left;
  20314. strm.next_in = next;
  20315. strm.avail_in = have;
  20316. state.hold = hold;
  20317. state.bits = bits;
  20318. //---
  20319. if (state.wsize || (_out !== strm.avail_out && state.mode < BAD &&
  20320. (state.mode < CHECK || flush !== Z_FINISH))) {
  20321. if (updatewindow(strm, strm.output, strm.next_out, _out - strm.avail_out)) {
  20322. state.mode = MEM;
  20323. return Z_MEM_ERROR;
  20324. }
  20325. }
  20326. _in -= strm.avail_in;
  20327. _out -= strm.avail_out;
  20328. strm.total_in += _in;
  20329. strm.total_out += _out;
  20330. state.total += _out;
  20331. if (state.wrap && _out) {
  20332. strm.adler = state.check = /*UPDATE(state.check, strm.next_out - _out, _out);*/
  20333. (state.flags ? crc32(state.check, output, _out, strm.next_out - _out) : adler32(state.check, output, _out, strm.next_out - _out));
  20334. }
  20335. strm.data_type = state.bits + (state.last ? 64 : 0) +
  20336. (state.mode === TYPE ? 128 : 0) +
  20337. (state.mode === LEN_ || state.mode === COPY_ ? 256 : 0);
  20338. if (((_in === 0 && _out === 0) || flush === Z_FINISH) && ret === Z_OK) {
  20339. ret = Z_BUF_ERROR;
  20340. }
  20341. return ret;
  20342. }
  20343. function inflateEnd(strm) {
  20344. if (!strm || !strm.state /*|| strm->zfree == (free_func)0*/) {
  20345. return Z_STREAM_ERROR;
  20346. }
  20347. var state = strm.state;
  20348. if (state.window) {
  20349. state.window = null;
  20350. }
  20351. strm.state = null;
  20352. return Z_OK;
  20353. }
  20354. function inflateGetHeader(strm, head) {
  20355. var state;
  20356. /* check state */
  20357. if (!strm || !strm.state) { return Z_STREAM_ERROR; }
  20358. state = strm.state;
  20359. if ((state.wrap & 2) === 0) { return Z_STREAM_ERROR; }
  20360. /* save header structure */
  20361. state.head = head;
  20362. head.done = false;
  20363. return Z_OK;
  20364. }
  20365. exports.inflateReset = inflateReset;
  20366. exports.inflateReset2 = inflateReset2;
  20367. exports.inflateResetKeep = inflateResetKeep;
  20368. exports.inflateInit = inflateInit;
  20369. exports.inflateInit2 = inflateInit2;
  20370. exports.inflate = inflate;
  20371. exports.inflateEnd = inflateEnd;
  20372. exports.inflateGetHeader = inflateGetHeader;
  20373. exports.inflateInfo = 'pako inflate (from Nodeca project)';
  20374. /* Not implemented
  20375. exports.inflateCopy = inflateCopy;
  20376. exports.inflateGetDictionary = inflateGetDictionary;
  20377. exports.inflateMark = inflateMark;
  20378. exports.inflatePrime = inflatePrime;
  20379. exports.inflateSetDictionary = inflateSetDictionary;
  20380. exports.inflateSync = inflateSync;
  20381. exports.inflateSyncPoint = inflateSyncPoint;
  20382. exports.inflateUndermine = inflateUndermine;
  20383. */
  20384. },{"../utils/common":65,"./adler32":67,"./crc32":69,"./inffast":72,"./inftrees":74}],74:[function(require,module,exports){
  20385. 'use strict';
  20386. var utils = require('../utils/common');
  20387. var MAXBITS = 15;
  20388. var ENOUGH_LENS = 852;
  20389. var ENOUGH_DISTS = 592;
  20390. //var ENOUGH = (ENOUGH_LENS+ENOUGH_DISTS);
  20391. var CODES = 0;
  20392. var LENS = 1;
  20393. var DISTS = 2;
  20394. var lbase = [ /* Length codes 257..285 base */
  20395. 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31,
  20396. 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0
  20397. ];
  20398. var lext = [ /* Length codes 257..285 extra */
  20399. 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18,
  20400. 19, 19, 19, 19, 20, 20, 20, 20, 21, 21, 21, 21, 16, 72, 78
  20401. ];
  20402. var dbase = [ /* Distance codes 0..29 base */
  20403. 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193,
  20404. 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
  20405. 8193, 12289, 16385, 24577, 0, 0
  20406. ];
  20407. var dext = [ /* Distance codes 0..29 extra */
  20408. 16, 16, 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22,
  20409. 23, 23, 24, 24, 25, 25, 26, 26, 27, 27,
  20410. 28, 28, 29, 29, 64, 64
  20411. ];
  20412. module.exports = function inflate_table(type, lens, lens_index, codes, table, table_index, work, opts)
  20413. {
  20414. var bits = opts.bits;
  20415. //here = opts.here; /* table entry for duplication */
  20416. var len = 0; /* a code's length in bits */
  20417. var sym = 0; /* index of code symbols */
  20418. var min = 0, max = 0; /* minimum and maximum code lengths */
  20419. var root = 0; /* number of index bits for root table */
  20420. var curr = 0; /* number of index bits for current table */
  20421. var drop = 0; /* code bits to drop for sub-table */
  20422. var left = 0; /* number of prefix codes available */
  20423. var used = 0; /* code entries in table used */
  20424. var huff = 0; /* Huffman code */
  20425. var incr; /* for incrementing code, index */
  20426. var fill; /* index for replicating entries */
  20427. var low; /* low bits for current root entry */
  20428. var mask; /* mask for low root bits */
  20429. var next; /* next available space in table */
  20430. var base = null; /* base value table to use */
  20431. var base_index = 0;
  20432. // var shoextra; /* extra bits table to use */
  20433. var end; /* use base and extra for symbol > end */
  20434. var count = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* number of codes of each length */
  20435. var offs = new utils.Buf16(MAXBITS+1); //[MAXBITS+1]; /* offsets in table for each length */
  20436. var extra = null;
  20437. var extra_index = 0;
  20438. var here_bits, here_op, here_val;
  20439. /*
  20440. Process a set of code lengths to create a canonical Huffman code. The
  20441. code lengths are lens[0..codes-1]. Each length corresponds to the
  20442. symbols 0..codes-1. The Huffman code is generated by first sorting the
  20443. symbols by length from short to long, and retaining the symbol order
  20444. for codes with equal lengths. Then the code starts with all zero bits
  20445. for the first code of the shortest length, and the codes are integer
  20446. increments for the same length, and zeros are appended as the length
  20447. increases. For the deflate format, these bits are stored backwards
  20448. from their more natural integer increment ordering, and so when the
  20449. decoding tables are built in the large loop below, the integer codes
  20450. are incremented backwards.
  20451. This routine assumes, but does not check, that all of the entries in
  20452. lens[] are in the range 0..MAXBITS. The caller must assure this.
  20453. 1..MAXBITS is interpreted as that code length. zero means that that
  20454. symbol does not occur in this code.
  20455. The codes are sorted by computing a count of codes for each length,
  20456. creating from that a table of starting indices for each length in the
  20457. sorted table, and then entering the symbols in order in the sorted
  20458. table. The sorted table is work[], with that space being provided by
  20459. the caller.
  20460. The length counts are used for other purposes as well, i.e. finding
  20461. the minimum and maximum length codes, determining if there are any
  20462. codes at all, checking for a valid set of lengths, and looking ahead
  20463. at length counts to determine sub-table sizes when building the
  20464. decoding tables.
  20465. */
  20466. /* accumulate lengths for codes (assumes lens[] all in 0..MAXBITS) */
  20467. for (len = 0; len <= MAXBITS; len++) {
  20468. count[len] = 0;
  20469. }
  20470. for (sym = 0; sym < codes; sym++) {
  20471. count[lens[lens_index + sym]]++;
  20472. }
  20473. /* bound code lengths, force root to be within code lengths */
  20474. root = bits;
  20475. for (max = MAXBITS; max >= 1; max--) {
  20476. if (count[max] !== 0) { break; }
  20477. }
  20478. if (root > max) {
  20479. root = max;
  20480. }
  20481. if (max === 0) { /* no symbols to code at all */
  20482. //table.op[opts.table_index] = 64; //here.op = (var char)64; /* invalid code marker */
  20483. //table.bits[opts.table_index] = 1; //here.bits = (var char)1;
  20484. //table.val[opts.table_index++] = 0; //here.val = (var short)0;
  20485. table[table_index++] = (1 << 24) | (64 << 16) | 0;
  20486. //table.op[opts.table_index] = 64;
  20487. //table.bits[opts.table_index] = 1;
  20488. //table.val[opts.table_index++] = 0;
  20489. table[table_index++] = (1 << 24) | (64 << 16) | 0;
  20490. opts.bits = 1;
  20491. return 0; /* no symbols, but wait for decoding to report error */
  20492. }
  20493. for (min = 1; min < max; min++) {
  20494. if (count[min] !== 0) { break; }
  20495. }
  20496. if (root < min) {
  20497. root = min;
  20498. }
  20499. /* check for an over-subscribed or incomplete set of lengths */
  20500. left = 1;
  20501. for (len = 1; len <= MAXBITS; len++) {
  20502. left <<= 1;
  20503. left -= count[len];
  20504. if (left < 0) {
  20505. return -1;
  20506. } /* over-subscribed */
  20507. }
  20508. if (left > 0 && (type === CODES || max !== 1)) {
  20509. return -1; /* incomplete set */
  20510. }
  20511. /* generate offsets into symbol table for each length for sorting */
  20512. offs[1] = 0;
  20513. for (len = 1; len < MAXBITS; len++) {
  20514. offs[len + 1] = offs[len] + count[len];
  20515. }
  20516. /* sort symbols by length, by symbol order within each length */
  20517. for (sym = 0; sym < codes; sym++) {
  20518. if (lens[lens_index + sym] !== 0) {
  20519. work[offs[lens[lens_index + sym]]++] = sym;
  20520. }
  20521. }
  20522. /*
  20523. Create and fill in decoding tables. In this loop, the table being
  20524. filled is at next and has curr index bits. The code being used is huff
  20525. with length len. That code is converted to an index by dropping drop
  20526. bits off of the bottom. For codes where len is less than drop + curr,
  20527. those top drop + curr - len bits are incremented through all values to
  20528. fill the table with replicated entries.
  20529. root is the number of index bits for the root table. When len exceeds
  20530. root, sub-tables are created pointed to by the root entry with an index
  20531. of the low root bits of huff. This is saved in low to check for when a
  20532. new sub-table should be started. drop is zero when the root table is
  20533. being filled, and drop is root when sub-tables are being filled.
  20534. When a new sub-table is needed, it is necessary to look ahead in the
  20535. code lengths to determine what size sub-table is needed. The length
  20536. counts are used for this, and so count[] is decremented as codes are
  20537. entered in the tables.
  20538. used keeps track of how many table entries have been allocated from the
  20539. provided *table space. It is checked for LENS and DIST tables against
  20540. the constants ENOUGH_LENS and ENOUGH_DISTS to guard against changes in
  20541. the initial root table size constants. See the comments in inftrees.h
  20542. for more information.
  20543. sym increments through all symbols, and the loop terminates when
  20544. all codes of length max, i.e. all codes, have been processed. This
  20545. routine permits incomplete codes, so another loop after this one fills
  20546. in the rest of the decoding tables with invalid code markers.
  20547. */
  20548. /* set up for code type */
  20549. // poor man optimization - use if-else instead of switch,
  20550. // to avoid deopts in old v8
  20551. if (type === CODES) {
  20552. base = extra = work; /* dummy value--not used */
  20553. end = 19;
  20554. } else if (type === LENS) {
  20555. base = lbase;
  20556. base_index -= 257;
  20557. extra = lext;
  20558. extra_index -= 257;
  20559. end = 256;
  20560. } else { /* DISTS */
  20561. base = dbase;
  20562. extra = dext;
  20563. end = -1;
  20564. }
  20565. /* initialize opts for loop */
  20566. huff = 0; /* starting code */
  20567. sym = 0; /* starting code symbol */
  20568. len = min; /* starting code length */
  20569. next = table_index; /* current table to fill in */
  20570. curr = root; /* current table index bits */
  20571. drop = 0; /* current bits to drop from code for index */
  20572. low = -1; /* trigger new sub-table when len > root */
  20573. used = 1 << root; /* use root table entries */
  20574. mask = used - 1; /* mask for comparing low */
  20575. /* check available table space */
  20576. if ((type === LENS && used > ENOUGH_LENS) ||
  20577. (type === DISTS && used > ENOUGH_DISTS)) {
  20578. return 1;
  20579. }
  20580. var i=0;
  20581. /* process all codes and make table entries */
  20582. for (;;) {
  20583. i++;
  20584. /* create table entry */
  20585. here_bits = len - drop;
  20586. if (work[sym] < end) {
  20587. here_op = 0;
  20588. here_val = work[sym];
  20589. }
  20590. else if (work[sym] > end) {
  20591. here_op = extra[extra_index + work[sym]];
  20592. here_val = base[base_index + work[sym]];
  20593. }
  20594. else {
  20595. here_op = 32 + 64; /* end of block */
  20596. here_val = 0;
  20597. }
  20598. /* replicate for those indices with low len bits equal to huff */
  20599. incr = 1 << (len - drop);
  20600. fill = 1 << curr;
  20601. min = fill; /* save offset to next table */
  20602. do {
  20603. fill -= incr;
  20604. table[next + (huff >> drop) + fill] = (here_bits << 24) | (here_op << 16) | here_val |0;
  20605. } while (fill !== 0);
  20606. /* backwards increment the len-bit code huff */
  20607. incr = 1 << (len - 1);
  20608. while (huff & incr) {
  20609. incr >>= 1;
  20610. }
  20611. if (incr !== 0) {
  20612. huff &= incr - 1;
  20613. huff += incr;
  20614. } else {
  20615. huff = 0;
  20616. }
  20617. /* go to next symbol, update count, len */
  20618. sym++;
  20619. if (--count[len] === 0) {
  20620. if (len === max) { break; }
  20621. len = lens[lens_index + work[sym]];
  20622. }
  20623. /* create new sub-table if needed */
  20624. if (len > root && (huff & mask) !== low) {
  20625. /* if first time, transition to sub-tables */
  20626. if (drop === 0) {
  20627. drop = root;
  20628. }
  20629. /* increment past last table */
  20630. next += min; /* here min is 1 << curr */
  20631. /* determine length of next table */
  20632. curr = len - drop;
  20633. left = 1 << curr;
  20634. while (curr + drop < max) {
  20635. left -= count[curr + drop];
  20636. if (left <= 0) { break; }
  20637. curr++;
  20638. left <<= 1;
  20639. }
  20640. /* check for enough space */
  20641. used += 1 << curr;
  20642. if ((type === LENS && used > ENOUGH_LENS) ||
  20643. (type === DISTS && used > ENOUGH_DISTS)) {
  20644. return 1;
  20645. }
  20646. /* point entry in root table to sub-table */
  20647. low = huff & mask;
  20648. /*table.op[low] = curr;
  20649. table.bits[low] = root;
  20650. table.val[low] = next - opts.table_index;*/
  20651. table[low] = (root << 24) | (curr << 16) | (next - table_index) |0;
  20652. }
  20653. }
  20654. /* fill in remaining table entry if code is incomplete (guaranteed to have
  20655. at most one remaining entry, since if the code is incomplete, the
  20656. maximum code length that was allowed to get this far is one bit) */
  20657. if (huff !== 0) {
  20658. //table.op[next + huff] = 64; /* invalid code marker */
  20659. //table.bits[next + huff] = len - drop;
  20660. //table.val[next + huff] = 0;
  20661. table[next + huff] = ((len - drop) << 24) | (64 << 16) |0;
  20662. }
  20663. /* set return parameters */
  20664. //opts.table_index += used;
  20665. opts.bits = root;
  20666. return 0;
  20667. };
  20668. },{"../utils/common":65}],75:[function(require,module,exports){
  20669. 'use strict';
  20670. module.exports = {
  20671. '2': 'need dictionary', /* Z_NEED_DICT 2 */
  20672. '1': 'stream end', /* Z_STREAM_END 1 */
  20673. '0': '', /* Z_OK 0 */
  20674. '-1': 'file error', /* Z_ERRNO (-1) */
  20675. '-2': 'stream error', /* Z_STREAM_ERROR (-2) */
  20676. '-3': 'data error', /* Z_DATA_ERROR (-3) */
  20677. '-4': 'insufficient memory', /* Z_MEM_ERROR (-4) */
  20678. '-5': 'buffer error', /* Z_BUF_ERROR (-5) */
  20679. '-6': 'incompatible version' /* Z_VERSION_ERROR (-6) */
  20680. };
  20681. },{}],76:[function(require,module,exports){
  20682. 'use strict';
  20683. var utils = require('../utils/common');
  20684. /* Public constants ==========================================================*/
  20685. /* ===========================================================================*/
  20686. //var Z_FILTERED = 1;
  20687. //var Z_HUFFMAN_ONLY = 2;
  20688. //var Z_RLE = 3;
  20689. var Z_FIXED = 4;
  20690. //var Z_DEFAULT_STRATEGY = 0;
  20691. /* Possible values of the data_type field (though see inflate()) */
  20692. var Z_BINARY = 0;
  20693. var Z_TEXT = 1;
  20694. //var Z_ASCII = 1; // = Z_TEXT
  20695. var Z_UNKNOWN = 2;
  20696. /*============================================================================*/
  20697. function zero(buf) { var len = buf.length; while (--len >= 0) { buf[len] = 0; } }
  20698. // From zutil.h
  20699. var STORED_BLOCK = 0;
  20700. var STATIC_TREES = 1;
  20701. var DYN_TREES = 2;
  20702. /* The three kinds of block type */
  20703. var MIN_MATCH = 3;
  20704. var MAX_MATCH = 258;
  20705. /* The minimum and maximum match lengths */
  20706. // From deflate.h
  20707. /* ===========================================================================
  20708. * Internal compression state.
  20709. */
  20710. var LENGTH_CODES = 29;
  20711. /* number of length codes, not counting the special END_BLOCK code */
  20712. var LITERALS = 256;
  20713. /* number of literal bytes 0..255 */
  20714. var L_CODES = LITERALS + 1 + LENGTH_CODES;
  20715. /* number of Literal or Length codes, including the END_BLOCK code */
  20716. var D_CODES = 30;
  20717. /* number of distance codes */
  20718. var BL_CODES = 19;
  20719. /* number of codes used to transfer the bit lengths */
  20720. var HEAP_SIZE = 2*L_CODES + 1;
  20721. /* maximum heap size */
  20722. var MAX_BITS = 15;
  20723. /* All codes must not exceed MAX_BITS bits */
  20724. var Buf_size = 16;
  20725. /* size of bit buffer in bi_buf */
  20726. /* ===========================================================================
  20727. * Constants
  20728. */
  20729. var MAX_BL_BITS = 7;
  20730. /* Bit length codes must not exceed MAX_BL_BITS bits */
  20731. var END_BLOCK = 256;
  20732. /* end of block literal code */
  20733. var REP_3_6 = 16;
  20734. /* repeat previous bit length 3-6 times (2 bits of repeat count) */
  20735. var REPZ_3_10 = 17;
  20736. /* repeat a zero length 3-10 times (3 bits of repeat count) */
  20737. var REPZ_11_138 = 18;
  20738. /* repeat a zero length 11-138 times (7 bits of repeat count) */
  20739. var extra_lbits = /* extra bits for each length code */
  20740. [0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0];
  20741. var extra_dbits = /* extra bits for each distance code */
  20742. [0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13];
  20743. var extra_blbits = /* extra bits for each bit length code */
  20744. [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2,3,7];
  20745. var bl_order =
  20746. [16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15];
  20747. /* The lengths of the bit length codes are sent in order of decreasing
  20748. * probability, to avoid transmitting the lengths for unused bit length codes.
  20749. */
  20750. /* ===========================================================================
  20751. * Local data. These are initialized only once.
  20752. */
  20753. // We pre-fill arrays with 0 to avoid uninitialized gaps
  20754. var DIST_CODE_LEN = 512; /* see definition of array dist_code below */
  20755. // !!!! Use flat array insdead of structure, Freq = i*2, Len = i*2+1
  20756. var static_ltree = new Array((L_CODES+2) * 2);
  20757. zero(static_ltree);
  20758. /* The static literal tree. Since the bit lengths are imposed, there is no
  20759. * need for the L_CODES extra codes used during heap construction. However
  20760. * The codes 286 and 287 are needed to build a canonical tree (see _tr_init
  20761. * below).
  20762. */
  20763. var static_dtree = new Array(D_CODES * 2);
  20764. zero(static_dtree);
  20765. /* The static distance tree. (Actually a trivial tree since all codes use
  20766. * 5 bits.)
  20767. */
  20768. var _dist_code = new Array(DIST_CODE_LEN);
  20769. zero(_dist_code);
  20770. /* Distance codes. The first 256 values correspond to the distances
  20771. * 3 .. 258, the last 256 values correspond to the top 8 bits of
  20772. * the 15 bit distances.
  20773. */
  20774. var _length_code = new Array(MAX_MATCH-MIN_MATCH+1);
  20775. zero(_length_code);
  20776. /* length code for each normalized match length (0 == MIN_MATCH) */
  20777. var base_length = new Array(LENGTH_CODES);
  20778. zero(base_length);
  20779. /* First normalized length for each code (0 = MIN_MATCH) */
  20780. var base_dist = new Array(D_CODES);
  20781. zero(base_dist);
  20782. /* First normalized distance for each code (0 = distance of 1) */
  20783. var StaticTreeDesc = function (static_tree, extra_bits, extra_base, elems, max_length) {
  20784. this.static_tree = static_tree; /* static tree or NULL */
  20785. this.extra_bits = extra_bits; /* extra bits for each code or NULL */
  20786. this.extra_base = extra_base; /* base index for extra_bits */
  20787. this.elems = elems; /* max number of elements in the tree */
  20788. this.max_length = max_length; /* max bit length for the codes */
  20789. // show if `static_tree` has data or dummy - needed for monomorphic objects
  20790. this.has_stree = static_tree && static_tree.length;
  20791. };
  20792. var static_l_desc;
  20793. var static_d_desc;
  20794. var static_bl_desc;
  20795. var TreeDesc = function(dyn_tree, stat_desc) {
  20796. this.dyn_tree = dyn_tree; /* the dynamic tree */
  20797. this.max_code = 0; /* largest code with non zero frequency */
  20798. this.stat_desc = stat_desc; /* the corresponding static tree */
  20799. };
  20800. function d_code(dist) {
  20801. return dist < 256 ? _dist_code[dist] : _dist_code[256 + (dist >>> 7)];
  20802. }
  20803. /* ===========================================================================
  20804. * Output a short LSB first on the stream.
  20805. * IN assertion: there is enough room in pendingBuf.
  20806. */
  20807. function put_short (s, w) {
  20808. // put_byte(s, (uch)((w) & 0xff));
  20809. // put_byte(s, (uch)((ush)(w) >> 8));
  20810. s.pending_buf[s.pending++] = (w) & 0xff;
  20811. s.pending_buf[s.pending++] = (w >>> 8) & 0xff;
  20812. }
  20813. /* ===========================================================================
  20814. * Send a value on a given number of bits.
  20815. * IN assertion: length <= 16 and value fits in length bits.
  20816. */
  20817. function send_bits(s, value, length) {
  20818. if (s.bi_valid > (Buf_size - length)) {
  20819. s.bi_buf |= (value << s.bi_valid) & 0xffff;
  20820. put_short(s, s.bi_buf);
  20821. s.bi_buf = value >> (Buf_size - s.bi_valid);
  20822. s.bi_valid += length - Buf_size;
  20823. } else {
  20824. s.bi_buf |= (value << s.bi_valid) & 0xffff;
  20825. s.bi_valid += length;
  20826. }
  20827. }
  20828. function send_code(s, c, tree) {
  20829. send_bits(s, tree[c*2]/*.Code*/, tree[c*2 + 1]/*.Len*/);
  20830. }
  20831. /* ===========================================================================
  20832. * Reverse the first len bits of a code, using straightforward code (a faster
  20833. * method would use a table)
  20834. * IN assertion: 1 <= len <= 15
  20835. */
  20836. function bi_reverse(code, len) {
  20837. var res = 0;
  20838. do {
  20839. res |= code & 1;
  20840. code >>>= 1;
  20841. res <<= 1;
  20842. } while (--len > 0);
  20843. return res >>> 1;
  20844. }
  20845. /* ===========================================================================
  20846. * Flush the bit buffer, keeping at most 7 bits in it.
  20847. */
  20848. function bi_flush(s) {
  20849. if (s.bi_valid === 16) {
  20850. put_short(s, s.bi_buf);
  20851. s.bi_buf = 0;
  20852. s.bi_valid = 0;
  20853. } else if (s.bi_valid >= 8) {
  20854. s.pending_buf[s.pending++] = s.bi_buf & 0xff;
  20855. s.bi_buf >>= 8;
  20856. s.bi_valid -= 8;
  20857. }
  20858. }
  20859. /* ===========================================================================
  20860. * Compute the optimal bit lengths for a tree and update the total bit length
  20861. * for the current block.
  20862. * IN assertion: the fields freq and dad are set, heap[heap_max] and
  20863. * above are the tree nodes sorted by increasing frequency.
  20864. * OUT assertions: the field len is set to the optimal bit length, the
  20865. * array bl_count contains the frequencies for each bit length.
  20866. * The length opt_len is updated; static_len is also updated if stree is
  20867. * not null.
  20868. */
  20869. function gen_bitlen(s, desc)
  20870. // deflate_state *s;
  20871. // tree_desc *desc; /* the tree descriptor */
  20872. {
  20873. var tree = desc.dyn_tree;
  20874. var max_code = desc.max_code;
  20875. var stree = desc.stat_desc.static_tree;
  20876. var has_stree = desc.stat_desc.has_stree;
  20877. var extra = desc.stat_desc.extra_bits;
  20878. var base = desc.stat_desc.extra_base;
  20879. var max_length = desc.stat_desc.max_length;
  20880. var h; /* heap index */
  20881. var n, m; /* iterate over the tree elements */
  20882. var bits; /* bit length */
  20883. var xbits; /* extra bits */
  20884. var f; /* frequency */
  20885. var overflow = 0; /* number of elements with bit length too large */
  20886. for (bits = 0; bits <= MAX_BITS; bits++) {
  20887. s.bl_count[bits] = 0;
  20888. }
  20889. /* In a first pass, compute the optimal bit lengths (which may
  20890. * overflow in the case of the bit length tree).
  20891. */
  20892. tree[s.heap[s.heap_max]*2 + 1]/*.Len*/ = 0; /* root of the heap */
  20893. for (h = s.heap_max+1; h < HEAP_SIZE; h++) {
  20894. n = s.heap[h];
  20895. bits = tree[tree[n*2 +1]/*.Dad*/ * 2 + 1]/*.Len*/ + 1;
  20896. if (bits > max_length) {
  20897. bits = max_length;
  20898. overflow++;
  20899. }
  20900. tree[n*2 + 1]/*.Len*/ = bits;
  20901. /* We overwrite tree[n].Dad which is no longer needed */
  20902. if (n > max_code) { continue; } /* not a leaf node */
  20903. s.bl_count[bits]++;
  20904. xbits = 0;
  20905. if (n >= base) {
  20906. xbits = extra[n-base];
  20907. }
  20908. f = tree[n * 2]/*.Freq*/;
  20909. s.opt_len += f * (bits + xbits);
  20910. if (has_stree) {
  20911. s.static_len += f * (stree[n*2 + 1]/*.Len*/ + xbits);
  20912. }
  20913. }
  20914. if (overflow === 0) { return; }
  20915. // Trace((stderr,"\nbit length overflow\n"));
  20916. /* This happens for example on obj2 and pic of the Calgary corpus */
  20917. /* Find the first bit length which could increase: */
  20918. do {
  20919. bits = max_length-1;
  20920. while (s.bl_count[bits] === 0) { bits--; }
  20921. s.bl_count[bits]--; /* move one leaf down the tree */
  20922. s.bl_count[bits+1] += 2; /* move one overflow item as its brother */
  20923. s.bl_count[max_length]--;
  20924. /* The brother of the overflow item also moves one step up,
  20925. * but this does not affect bl_count[max_length]
  20926. */
  20927. overflow -= 2;
  20928. } while (overflow > 0);
  20929. /* Now recompute all bit lengths, scanning in increasing frequency.
  20930. * h is still equal to HEAP_SIZE. (It is simpler to reconstruct all
  20931. * lengths instead of fixing only the wrong ones. This idea is taken
  20932. * from 'ar' written by Haruhiko Okumura.)
  20933. */
  20934. for (bits = max_length; bits !== 0; bits--) {
  20935. n = s.bl_count[bits];
  20936. while (n !== 0) {
  20937. m = s.heap[--h];
  20938. if (m > max_code) { continue; }
  20939. if (tree[m*2 + 1]/*.Len*/ !== bits) {
  20940. // Trace((stderr,"code %d bits %d->%d\n", m, tree[m].Len, bits));
  20941. s.opt_len += (bits - tree[m*2 + 1]/*.Len*/)*tree[m*2]/*.Freq*/;
  20942. tree[m*2 + 1]/*.Len*/ = bits;
  20943. }
  20944. n--;
  20945. }
  20946. }
  20947. }
  20948. /* ===========================================================================
  20949. * Generate the codes for a given tree and bit counts (which need not be
  20950. * optimal).
  20951. * IN assertion: the array bl_count contains the bit length statistics for
  20952. * the given tree and the field len is set for all tree elements.
  20953. * OUT assertion: the field code is set for all tree elements of non
  20954. * zero code length.
  20955. */
  20956. function gen_codes(tree, max_code, bl_count)
  20957. // ct_data *tree; /* the tree to decorate */
  20958. // int max_code; /* largest code with non zero frequency */
  20959. // ushf *bl_count; /* number of codes at each bit length */
  20960. {
  20961. var next_code = new Array(MAX_BITS+1); /* next code value for each bit length */
  20962. var code = 0; /* running code value */
  20963. var bits; /* bit index */
  20964. var n; /* code index */
  20965. /* The distribution counts are first used to generate the code values
  20966. * without bit reversal.
  20967. */
  20968. for (bits = 1; bits <= MAX_BITS; bits++) {
  20969. next_code[bits] = code = (code + bl_count[bits-1]) << 1;
  20970. }
  20971. /* Check that the bit counts in bl_count are consistent. The last code
  20972. * must be all ones.
  20973. */
  20974. //Assert (code + bl_count[MAX_BITS]-1 == (1<<MAX_BITS)-1,
  20975. // "inconsistent bit counts");
  20976. //Tracev((stderr,"\ngen_codes: max_code %d ", max_code));
  20977. for (n = 0; n <= max_code; n++) {
  20978. var len = tree[n*2 + 1]/*.Len*/;
  20979. if (len === 0) { continue; }
  20980. /* Now reverse the bits */
  20981. tree[n*2]/*.Code*/ = bi_reverse(next_code[len]++, len);
  20982. //Tracecv(tree != static_ltree, (stderr,"\nn %3d %c l %2d c %4x (%x) ",
  20983. // n, (isgraph(n) ? n : ' '), len, tree[n].Code, next_code[len]-1));
  20984. }
  20985. }
  20986. /* ===========================================================================
  20987. * Initialize the various 'constant' tables.
  20988. */
  20989. function tr_static_init() {
  20990. var n; /* iterates over tree elements */
  20991. var bits; /* bit counter */
  20992. var length; /* length value */
  20993. var code; /* code value */
  20994. var dist; /* distance index */
  20995. var bl_count = new Array(MAX_BITS+1);
  20996. /* number of codes at each bit length for an optimal tree */
  20997. // do check in _tr_init()
  20998. //if (static_init_done) return;
  20999. /* For some embedded targets, global variables are not initialized: */
  21000. /*#ifdef NO_INIT_GLOBAL_POINTERS
  21001. static_l_desc.static_tree = static_ltree;
  21002. static_l_desc.extra_bits = extra_lbits;
  21003. static_d_desc.static_tree = static_dtree;
  21004. static_d_desc.extra_bits = extra_dbits;
  21005. static_bl_desc.extra_bits = extra_blbits;
  21006. #endif*/
  21007. /* Initialize the mapping length (0..255) -> length code (0..28) */
  21008. length = 0;
  21009. for (code = 0; code < LENGTH_CODES-1; code++) {
  21010. base_length[code] = length;
  21011. for (n = 0; n < (1<<extra_lbits[code]); n++) {
  21012. _length_code[length++] = code;
  21013. }
  21014. }
  21015. //Assert (length == 256, "tr_static_init: length != 256");
  21016. /* Note that the length 255 (match length 258) can be represented
  21017. * in two different ways: code 284 + 5 bits or code 285, so we
  21018. * overwrite length_code[255] to use the best encoding:
  21019. */
  21020. _length_code[length-1] = code;
  21021. /* Initialize the mapping dist (0..32K) -> dist code (0..29) */
  21022. dist = 0;
  21023. for (code = 0 ; code < 16; code++) {
  21024. base_dist[code] = dist;
  21025. for (n = 0; n < (1<<extra_dbits[code]); n++) {
  21026. _dist_code[dist++] = code;
  21027. }
  21028. }
  21029. //Assert (dist == 256, "tr_static_init: dist != 256");
  21030. dist >>= 7; /* from now on, all distances are divided by 128 */
  21031. for ( ; code < D_CODES; code++) {
  21032. base_dist[code] = dist << 7;
  21033. for (n = 0; n < (1<<(extra_dbits[code]-7)); n++) {
  21034. _dist_code[256 + dist++] = code;
  21035. }
  21036. }
  21037. //Assert (dist == 256, "tr_static_init: 256+dist != 512");
  21038. /* Construct the codes of the static literal tree */
  21039. for (bits = 0; bits <= MAX_BITS; bits++) {
  21040. bl_count[bits] = 0;
  21041. }
  21042. n = 0;
  21043. while (n <= 143) {
  21044. static_ltree[n*2 + 1]/*.Len*/ = 8;
  21045. n++;
  21046. bl_count[8]++;
  21047. }
  21048. while (n <= 255) {
  21049. static_ltree[n*2 + 1]/*.Len*/ = 9;
  21050. n++;
  21051. bl_count[9]++;
  21052. }
  21053. while (n <= 279) {
  21054. static_ltree[n*2 + 1]/*.Len*/ = 7;
  21055. n++;
  21056. bl_count[7]++;
  21057. }
  21058. while (n <= 287) {
  21059. static_ltree[n*2 + 1]/*.Len*/ = 8;
  21060. n++;
  21061. bl_count[8]++;
  21062. }
  21063. /* Codes 286 and 287 do not exist, but we must include them in the
  21064. * tree construction to get a canonical Huffman tree (longest code
  21065. * all ones)
  21066. */
  21067. gen_codes(static_ltree, L_CODES+1, bl_count);
  21068. /* The static distance tree is trivial: */
  21069. for (n = 0; n < D_CODES; n++) {
  21070. static_dtree[n*2 + 1]/*.Len*/ = 5;
  21071. static_dtree[n*2]/*.Code*/ = bi_reverse(n, 5);
  21072. }
  21073. // Now data ready and we can init static trees
  21074. static_l_desc = new StaticTreeDesc(static_ltree, extra_lbits, LITERALS+1, L_CODES, MAX_BITS);
  21075. static_d_desc = new StaticTreeDesc(static_dtree, extra_dbits, 0, D_CODES, MAX_BITS);
  21076. static_bl_desc =new StaticTreeDesc(new Array(0), extra_blbits, 0, BL_CODES, MAX_BL_BITS);
  21077. //static_init_done = true;
  21078. }
  21079. /* ===========================================================================
  21080. * Initialize a new block.
  21081. */
  21082. function init_block(s) {
  21083. var n; /* iterates over tree elements */
  21084. /* Initialize the trees. */
  21085. for (n = 0; n < L_CODES; n++) { s.dyn_ltree[n*2]/*.Freq*/ = 0; }
  21086. for (n = 0; n < D_CODES; n++) { s.dyn_dtree[n*2]/*.Freq*/ = 0; }
  21087. for (n = 0; n < BL_CODES; n++) { s.bl_tree[n*2]/*.Freq*/ = 0; }
  21088. s.dyn_ltree[END_BLOCK*2]/*.Freq*/ = 1;
  21089. s.opt_len = s.static_len = 0;
  21090. s.last_lit = s.matches = 0;
  21091. }
  21092. /* ===========================================================================
  21093. * Flush the bit buffer and align the output on a byte boundary
  21094. */
  21095. function bi_windup(s)
  21096. {
  21097. if (s.bi_valid > 8) {
  21098. put_short(s, s.bi_buf);
  21099. } else if (s.bi_valid > 0) {
  21100. //put_byte(s, (Byte)s->bi_buf);
  21101. s.pending_buf[s.pending++] = s.bi_buf;
  21102. }
  21103. s.bi_buf = 0;
  21104. s.bi_valid = 0;
  21105. }
  21106. /* ===========================================================================
  21107. * Copy a stored block, storing first the length and its
  21108. * one's complement if requested.
  21109. */
  21110. function copy_block(s, buf, len, header)
  21111. //DeflateState *s;
  21112. //charf *buf; /* the input data */
  21113. //unsigned len; /* its length */
  21114. //int header; /* true if block header must be written */
  21115. {
  21116. bi_windup(s); /* align on byte boundary */
  21117. if (header) {
  21118. put_short(s, len);
  21119. put_short(s, ~len);
  21120. }
  21121. // while (len--) {
  21122. // put_byte(s, *buf++);
  21123. // }
  21124. utils.arraySet(s.pending_buf, s.window, buf, len, s.pending);
  21125. s.pending += len;
  21126. }
  21127. /* ===========================================================================
  21128. * Compares to subtrees, using the tree depth as tie breaker when
  21129. * the subtrees have equal frequency. This minimizes the worst case length.
  21130. */
  21131. function smaller(tree, n, m, depth) {
  21132. var _n2 = n*2;
  21133. var _m2 = m*2;
  21134. return (tree[_n2]/*.Freq*/ < tree[_m2]/*.Freq*/ ||
  21135. (tree[_n2]/*.Freq*/ === tree[_m2]/*.Freq*/ && depth[n] <= depth[m]));
  21136. }
  21137. /* ===========================================================================
  21138. * Restore the heap property by moving down the tree starting at node k,
  21139. * exchanging a node with the smallest of its two sons if necessary, stopping
  21140. * when the heap property is re-established (each father smaller than its
  21141. * two sons).
  21142. */
  21143. function pqdownheap(s, tree, k)
  21144. // deflate_state *s;
  21145. // ct_data *tree; /* the tree to restore */
  21146. // int k; /* node to move down */
  21147. {
  21148. var v = s.heap[k];
  21149. var j = k << 1; /* left son of k */
  21150. while (j <= s.heap_len) {
  21151. /* Set j to the smallest of the two sons: */
  21152. if (j < s.heap_len &&
  21153. smaller(tree, s.heap[j+1], s.heap[j], s.depth)) {
  21154. j++;
  21155. }
  21156. /* Exit if v is smaller than both sons */
  21157. if (smaller(tree, v, s.heap[j], s.depth)) { break; }
  21158. /* Exchange v with the smallest son */
  21159. s.heap[k] = s.heap[j];
  21160. k = j;
  21161. /* And continue down the tree, setting j to the left son of k */
  21162. j <<= 1;
  21163. }
  21164. s.heap[k] = v;
  21165. }
  21166. // inlined manually
  21167. // var SMALLEST = 1;
  21168. /* ===========================================================================
  21169. * Send the block data compressed using the given Huffman trees
  21170. */
  21171. function compress_block(s, ltree, dtree)
  21172. // deflate_state *s;
  21173. // const ct_data *ltree; /* literal tree */
  21174. // const ct_data *dtree; /* distance tree */
  21175. {
  21176. var dist; /* distance of matched string */
  21177. var lc; /* match length or unmatched char (if dist == 0) */
  21178. var lx = 0; /* running index in l_buf */
  21179. var code; /* the code to send */
  21180. var extra; /* number of extra bits to send */
  21181. if (s.last_lit !== 0) {
  21182. do {
  21183. dist = (s.pending_buf[s.d_buf + lx*2] << 8) | (s.pending_buf[s.d_buf + lx*2 + 1]);
  21184. lc = s.pending_buf[s.l_buf + lx];
  21185. lx++;
  21186. if (dist === 0) {
  21187. send_code(s, lc, ltree); /* send a literal byte */
  21188. //Tracecv(isgraph(lc), (stderr," '%c' ", lc));
  21189. } else {
  21190. /* Here, lc is the match length - MIN_MATCH */
  21191. code = _length_code[lc];
  21192. send_code(s, code+LITERALS+1, ltree); /* send the length code */
  21193. extra = extra_lbits[code];
  21194. if (extra !== 0) {
  21195. lc -= base_length[code];
  21196. send_bits(s, lc, extra); /* send the extra length bits */
  21197. }
  21198. dist--; /* dist is now the match distance - 1 */
  21199. code = d_code(dist);
  21200. //Assert (code < D_CODES, "bad d_code");
  21201. send_code(s, code, dtree); /* send the distance code */
  21202. extra = extra_dbits[code];
  21203. if (extra !== 0) {
  21204. dist -= base_dist[code];
  21205. send_bits(s, dist, extra); /* send the extra distance bits */
  21206. }
  21207. } /* literal or match pair ? */
  21208. /* Check that the overlay between pending_buf and d_buf+l_buf is ok: */
  21209. //Assert((uInt)(s->pending) < s->lit_bufsize + 2*lx,
  21210. // "pendingBuf overflow");
  21211. } while (lx < s.last_lit);
  21212. }
  21213. send_code(s, END_BLOCK, ltree);
  21214. }
  21215. /* ===========================================================================
  21216. * Construct one Huffman tree and assigns the code bit strings and lengths.
  21217. * Update the total bit length for the current block.
  21218. * IN assertion: the field freq is set for all tree elements.
  21219. * OUT assertions: the fields len and code are set to the optimal bit length
  21220. * and corresponding code. The length opt_len is updated; static_len is
  21221. * also updated if stree is not null. The field max_code is set.
  21222. */
  21223. function build_tree(s, desc)
  21224. // deflate_state *s;
  21225. // tree_desc *desc; /* the tree descriptor */
  21226. {
  21227. var tree = desc.dyn_tree;
  21228. var stree = desc.stat_desc.static_tree;
  21229. var has_stree = desc.stat_desc.has_stree;
  21230. var elems = desc.stat_desc.elems;
  21231. var n, m; /* iterate over heap elements */
  21232. var max_code = -1; /* largest code with non zero frequency */
  21233. var node; /* new node being created */
  21234. /* Construct the initial heap, with least frequent element in
  21235. * heap[SMALLEST]. The sons of heap[n] are heap[2*n] and heap[2*n+1].
  21236. * heap[0] is not used.
  21237. */
  21238. s.heap_len = 0;
  21239. s.heap_max = HEAP_SIZE;
  21240. for (n = 0; n < elems; n++) {
  21241. if (tree[n * 2]/*.Freq*/ !== 0) {
  21242. s.heap[++s.heap_len] = max_code = n;
  21243. s.depth[n] = 0;
  21244. } else {
  21245. tree[n*2 + 1]/*.Len*/ = 0;
  21246. }
  21247. }
  21248. /* The pkzip format requires that at least one distance code exists,
  21249. * and that at least one bit should be sent even if there is only one
  21250. * possible code. So to avoid special checks later on we force at least
  21251. * two codes of non zero frequency.
  21252. */
  21253. while (s.heap_len < 2) {
  21254. node = s.heap[++s.heap_len] = (max_code < 2 ? ++max_code : 0);
  21255. tree[node * 2]/*.Freq*/ = 1;
  21256. s.depth[node] = 0;
  21257. s.opt_len--;
  21258. if (has_stree) {
  21259. s.static_len -= stree[node*2 + 1]/*.Len*/;
  21260. }
  21261. /* node is 0 or 1 so it does not have extra bits */
  21262. }
  21263. desc.max_code = max_code;
  21264. /* The elements heap[heap_len/2+1 .. heap_len] are leaves of the tree,
  21265. * establish sub-heaps of increasing lengths:
  21266. */
  21267. for (n = (s.heap_len >> 1/*int /2*/); n >= 1; n--) { pqdownheap(s, tree, n); }
  21268. /* Construct the Huffman tree by repeatedly combining the least two
  21269. * frequent nodes.
  21270. */
  21271. node = elems; /* next internal node of the tree */
  21272. do {
  21273. //pqremove(s, tree, n); /* n = node of least frequency */
  21274. /*** pqremove ***/
  21275. n = s.heap[1/*SMALLEST*/];
  21276. s.heap[1/*SMALLEST*/] = s.heap[s.heap_len--];
  21277. pqdownheap(s, tree, 1/*SMALLEST*/);
  21278. /***/
  21279. m = s.heap[1/*SMALLEST*/]; /* m = node of next least frequency */
  21280. s.heap[--s.heap_max] = n; /* keep the nodes sorted by frequency */
  21281. s.heap[--s.heap_max] = m;
  21282. /* Create a new node father of n and m */
  21283. tree[node * 2]/*.Freq*/ = tree[n * 2]/*.Freq*/ + tree[m * 2]/*.Freq*/;
  21284. s.depth[node] = (s.depth[n] >= s.depth[m] ? s.depth[n] : s.depth[m]) + 1;
  21285. tree[n*2 + 1]/*.Dad*/ = tree[m*2 + 1]/*.Dad*/ = node;
  21286. /* and insert the new node in the heap */
  21287. s.heap[1/*SMALLEST*/] = node++;
  21288. pqdownheap(s, tree, 1/*SMALLEST*/);
  21289. } while (s.heap_len >= 2);
  21290. s.heap[--s.heap_max] = s.heap[1/*SMALLEST*/];
  21291. /* At this point, the fields freq and dad are set. We can now
  21292. * generate the bit lengths.
  21293. */
  21294. gen_bitlen(s, desc);
  21295. /* The field len is now set, we can generate the bit codes */
  21296. gen_codes(tree, max_code, s.bl_count);
  21297. }
  21298. /* ===========================================================================
  21299. * Scan a literal or distance tree to determine the frequencies of the codes
  21300. * in the bit length tree.
  21301. */
  21302. function scan_tree(s, tree, max_code)
  21303. // deflate_state *s;
  21304. // ct_data *tree; /* the tree to be scanned */
  21305. // int max_code; /* and its largest code of non zero frequency */
  21306. {
  21307. var n; /* iterates over all tree elements */
  21308. var prevlen = -1; /* last emitted length */
  21309. var curlen; /* length of current code */
  21310. var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */
  21311. var count = 0; /* repeat count of the current code */
  21312. var max_count = 7; /* max repeat count */
  21313. var min_count = 4; /* min repeat count */
  21314. if (nextlen === 0) {
  21315. max_count = 138;
  21316. min_count = 3;
  21317. }
  21318. tree[(max_code+1)*2 + 1]/*.Len*/ = 0xffff; /* guard */
  21319. for (n = 0; n <= max_code; n++) {
  21320. curlen = nextlen;
  21321. nextlen = tree[(n+1)*2 + 1]/*.Len*/;
  21322. if (++count < max_count && curlen === nextlen) {
  21323. continue;
  21324. } else if (count < min_count) {
  21325. s.bl_tree[curlen * 2]/*.Freq*/ += count;
  21326. } else if (curlen !== 0) {
  21327. if (curlen !== prevlen) { s.bl_tree[curlen * 2]/*.Freq*/++; }
  21328. s.bl_tree[REP_3_6*2]/*.Freq*/++;
  21329. } else if (count <= 10) {
  21330. s.bl_tree[REPZ_3_10*2]/*.Freq*/++;
  21331. } else {
  21332. s.bl_tree[REPZ_11_138*2]/*.Freq*/++;
  21333. }
  21334. count = 0;
  21335. prevlen = curlen;
  21336. if (nextlen === 0) {
  21337. max_count = 138;
  21338. min_count = 3;
  21339. } else if (curlen === nextlen) {
  21340. max_count = 6;
  21341. min_count = 3;
  21342. } else {
  21343. max_count = 7;
  21344. min_count = 4;
  21345. }
  21346. }
  21347. }
  21348. /* ===========================================================================
  21349. * Send a literal or distance tree in compressed form, using the codes in
  21350. * bl_tree.
  21351. */
  21352. function send_tree(s, tree, max_code)
  21353. // deflate_state *s;
  21354. // ct_data *tree; /* the tree to be scanned */
  21355. // int max_code; /* and its largest code of non zero frequency */
  21356. {
  21357. var n; /* iterates over all tree elements */
  21358. var prevlen = -1; /* last emitted length */
  21359. var curlen; /* length of current code */
  21360. var nextlen = tree[0*2 + 1]/*.Len*/; /* length of next code */
  21361. var count = 0; /* repeat count of the current code */
  21362. var max_count = 7; /* max repeat count */
  21363. var min_count = 4; /* min repeat count */
  21364. /* tree[max_code+1].Len = -1; */ /* guard already set */
  21365. if (nextlen === 0) {
  21366. max_count = 138;
  21367. min_count = 3;
  21368. }
  21369. for (n = 0; n <= max_code; n++) {
  21370. curlen = nextlen;
  21371. nextlen = tree[(n+1)*2 + 1]/*.Len*/;
  21372. if (++count < max_count && curlen === nextlen) {
  21373. continue;
  21374. } else if (count < min_count) {
  21375. do { send_code(s, curlen, s.bl_tree); } while (--count !== 0);
  21376. } else if (curlen !== 0) {
  21377. if (curlen !== prevlen) {
  21378. send_code(s, curlen, s.bl_tree);
  21379. count--;
  21380. }
  21381. //Assert(count >= 3 && count <= 6, " 3_6?");
  21382. send_code(s, REP_3_6, s.bl_tree);
  21383. send_bits(s, count-3, 2);
  21384. } else if (count <= 10) {
  21385. send_code(s, REPZ_3_10, s.bl_tree);
  21386. send_bits(s, count-3, 3);
  21387. } else {
  21388. send_code(s, REPZ_11_138, s.bl_tree);
  21389. send_bits(s, count-11, 7);
  21390. }
  21391. count = 0;
  21392. prevlen = curlen;
  21393. if (nextlen === 0) {
  21394. max_count = 138;
  21395. min_count = 3;
  21396. } else if (curlen === nextlen) {
  21397. max_count = 6;
  21398. min_count = 3;
  21399. } else {
  21400. max_count = 7;
  21401. min_count = 4;
  21402. }
  21403. }
  21404. }
  21405. /* ===========================================================================
  21406. * Construct the Huffman tree for the bit lengths and return the index in
  21407. * bl_order of the last bit length code to send.
  21408. */
  21409. function build_bl_tree(s) {
  21410. var max_blindex; /* index of last bit length code of non zero freq */
  21411. /* Determine the bit length frequencies for literal and distance trees */
  21412. scan_tree(s, s.dyn_ltree, s.l_desc.max_code);
  21413. scan_tree(s, s.dyn_dtree, s.d_desc.max_code);
  21414. /* Build the bit length tree: */
  21415. build_tree(s, s.bl_desc);
  21416. /* opt_len now includes the length of the tree representations, except
  21417. * the lengths of the bit lengths codes and the 5+5+4 bits for the counts.
  21418. */
  21419. /* Determine the number of bit length codes to send. The pkzip format
  21420. * requires that at least 4 bit length codes be sent. (appnote.txt says
  21421. * 3 but the actual value used is 4.)
  21422. */
  21423. for (max_blindex = BL_CODES-1; max_blindex >= 3; max_blindex--) {
  21424. if (s.bl_tree[bl_order[max_blindex]*2 + 1]/*.Len*/ !== 0) {
  21425. break;
  21426. }
  21427. }
  21428. /* Update opt_len to include the bit length tree and counts */
  21429. s.opt_len += 3*(max_blindex+1) + 5+5+4;
  21430. //Tracev((stderr, "\ndyn trees: dyn %ld, stat %ld",
  21431. // s->opt_len, s->static_len));
  21432. return max_blindex;
  21433. }
  21434. /* ===========================================================================
  21435. * Send the header for a block using dynamic Huffman trees: the counts, the
  21436. * lengths of the bit length codes, the literal tree and the distance tree.
  21437. * IN assertion: lcodes >= 257, dcodes >= 1, blcodes >= 4.
  21438. */
  21439. function send_all_trees(s, lcodes, dcodes, blcodes)
  21440. // deflate_state *s;
  21441. // int lcodes, dcodes, blcodes; /* number of codes for each tree */
  21442. {
  21443. var rank; /* index in bl_order */
  21444. //Assert (lcodes >= 257 && dcodes >= 1 && blcodes >= 4, "not enough codes");
  21445. //Assert (lcodes <= L_CODES && dcodes <= D_CODES && blcodes <= BL_CODES,
  21446. // "too many codes");
  21447. //Tracev((stderr, "\nbl counts: "));
  21448. send_bits(s, lcodes-257, 5); /* not +255 as stated in appnote.txt */
  21449. send_bits(s, dcodes-1, 5);
  21450. send_bits(s, blcodes-4, 4); /* not -3 as stated in appnote.txt */
  21451. for (rank = 0; rank < blcodes; rank++) {
  21452. //Tracev((stderr, "\nbl code %2d ", bl_order[rank]));
  21453. send_bits(s, s.bl_tree[bl_order[rank]*2 + 1]/*.Len*/, 3);
  21454. }
  21455. //Tracev((stderr, "\nbl tree: sent %ld", s->bits_sent));
  21456. send_tree(s, s.dyn_ltree, lcodes-1); /* literal tree */
  21457. //Tracev((stderr, "\nlit tree: sent %ld", s->bits_sent));
  21458. send_tree(s, s.dyn_dtree, dcodes-1); /* distance tree */
  21459. //Tracev((stderr, "\ndist tree: sent %ld", s->bits_sent));
  21460. }
  21461. /* ===========================================================================
  21462. * Check if the data type is TEXT or BINARY, using the following algorithm:
  21463. * - TEXT if the two conditions below are satisfied:
  21464. * a) There are no non-portable control characters belonging to the
  21465. * "black list" (0..6, 14..25, 28..31).
  21466. * b) There is at least one printable character belonging to the
  21467. * "white list" (9 {TAB}, 10 {LF}, 13 {CR}, 32..255).
  21468. * - BINARY otherwise.
  21469. * - The following partially-portable control characters form a
  21470. * "gray list" that is ignored in this detection algorithm:
  21471. * (7 {BEL}, 8 {BS}, 11 {VT}, 12 {FF}, 26 {SUB}, 27 {ESC}).
  21472. * IN assertion: the fields Freq of dyn_ltree are set.
  21473. */
  21474. function detect_data_type(s) {
  21475. /* black_mask is the bit mask of black-listed bytes
  21476. * set bits 0..6, 14..25, and 28..31
  21477. * 0xf3ffc07f = binary 11110011111111111100000001111111
  21478. */
  21479. var black_mask = 0xf3ffc07f;
  21480. var n;
  21481. /* Check for non-textual ("black-listed") bytes. */
  21482. for (n = 0; n <= 31; n++, black_mask >>>= 1) {
  21483. if ((black_mask & 1) && (s.dyn_ltree[n*2]/*.Freq*/ !== 0)) {
  21484. return Z_BINARY;
  21485. }
  21486. }
  21487. /* Check for textual ("white-listed") bytes. */
  21488. if (s.dyn_ltree[9 * 2]/*.Freq*/ !== 0 || s.dyn_ltree[10 * 2]/*.Freq*/ !== 0 ||
  21489. s.dyn_ltree[13 * 2]/*.Freq*/ !== 0) {
  21490. return Z_TEXT;
  21491. }
  21492. for (n = 32; n < LITERALS; n++) {
  21493. if (s.dyn_ltree[n * 2]/*.Freq*/ !== 0) {
  21494. return Z_TEXT;
  21495. }
  21496. }
  21497. /* There are no "black-listed" or "white-listed" bytes:
  21498. * this stream either is empty or has tolerated ("gray-listed") bytes only.
  21499. */
  21500. return Z_BINARY;
  21501. }
  21502. var static_init_done = false;
  21503. /* ===========================================================================
  21504. * Initialize the tree data structures for a new zlib stream.
  21505. */
  21506. function _tr_init(s)
  21507. {
  21508. if (!static_init_done) {
  21509. tr_static_init();
  21510. static_init_done = true;
  21511. }
  21512. s.l_desc = new TreeDesc(s.dyn_ltree, static_l_desc);
  21513. s.d_desc = new TreeDesc(s.dyn_dtree, static_d_desc);
  21514. s.bl_desc = new TreeDesc(s.bl_tree, static_bl_desc);
  21515. s.bi_buf = 0;
  21516. s.bi_valid = 0;
  21517. /* Initialize the first block of the first file: */
  21518. init_block(s);
  21519. }
  21520. /* ===========================================================================
  21521. * Send a stored block
  21522. */
  21523. function _tr_stored_block(s, buf, stored_len, last)
  21524. //DeflateState *s;
  21525. //charf *buf; /* input block */
  21526. //ulg stored_len; /* length of input block */
  21527. //int last; /* one if this is the last block for a file */
  21528. {
  21529. send_bits(s, (STORED_BLOCK<<1)+(last ? 1 : 0), 3); /* send block type */
  21530. copy_block(s, buf, stored_len, true); /* with header */
  21531. }
  21532. /* ===========================================================================
  21533. * Send one empty static block to give enough lookahead for inflate.
  21534. * This takes 10 bits, of which 7 may remain in the bit buffer.
  21535. */
  21536. function _tr_align(s) {
  21537. send_bits(s, STATIC_TREES<<1, 3);
  21538. send_code(s, END_BLOCK, static_ltree);
  21539. bi_flush(s);
  21540. }
  21541. /* ===========================================================================
  21542. * Determine the best encoding for the current block: dynamic trees, static
  21543. * trees or store, and output the encoded block to the zip file.
  21544. */
  21545. function _tr_flush_block(s, buf, stored_len, last)
  21546. //DeflateState *s;
  21547. //charf *buf; /* input block, or NULL if too old */
  21548. //ulg stored_len; /* length of input block */
  21549. //int last; /* one if this is the last block for a file */
  21550. {
  21551. var opt_lenb, static_lenb; /* opt_len and static_len in bytes */
  21552. var max_blindex = 0; /* index of last bit length code of non zero freq */
  21553. /* Build the Huffman trees unless a stored block is forced */
  21554. if (s.level > 0) {
  21555. /* Check if the file is binary or text */
  21556. if (s.strm.data_type === Z_UNKNOWN) {
  21557. s.strm.data_type = detect_data_type(s);
  21558. }
  21559. /* Construct the literal and distance trees */
  21560. build_tree(s, s.l_desc);
  21561. // Tracev((stderr, "\nlit data: dyn %ld, stat %ld", s->opt_len,
  21562. // s->static_len));
  21563. build_tree(s, s.d_desc);
  21564. // Tracev((stderr, "\ndist data: dyn %ld, stat %ld", s->opt_len,
  21565. // s->static_len));
  21566. /* At this point, opt_len and static_len are the total bit lengths of
  21567. * the compressed block data, excluding the tree representations.
  21568. */
  21569. /* Build the bit length tree for the above two trees, and get the index
  21570. * in bl_order of the last bit length code to send.
  21571. */
  21572. max_blindex = build_bl_tree(s);
  21573. /* Determine the best encoding. Compute the block lengths in bytes. */
  21574. opt_lenb = (s.opt_len+3+7) >>> 3;
  21575. static_lenb = (s.static_len+3+7) >>> 3;
  21576. // Tracev((stderr, "\nopt %lu(%lu) stat %lu(%lu) stored %lu lit %u ",
  21577. // opt_lenb, s->opt_len, static_lenb, s->static_len, stored_len,
  21578. // s->last_lit));
  21579. if (static_lenb <= opt_lenb) { opt_lenb = static_lenb; }
  21580. } else {
  21581. // Assert(buf != (char*)0, "lost buf");
  21582. opt_lenb = static_lenb = stored_len + 5; /* force a stored block */
  21583. }
  21584. if ((stored_len+4 <= opt_lenb) && (buf !== -1)) {
  21585. /* 4: two words for the lengths */
  21586. /* The test buf != NULL is only necessary if LIT_BUFSIZE > WSIZE.
  21587. * Otherwise we can't have processed more than WSIZE input bytes since
  21588. * the last block flush, because compression would have been
  21589. * successful. If LIT_BUFSIZE <= WSIZE, it is never too late to
  21590. * transform a block into a stored block.
  21591. */
  21592. _tr_stored_block(s, buf, stored_len, last);
  21593. } else if (s.strategy === Z_FIXED || static_lenb === opt_lenb) {
  21594. send_bits(s, (STATIC_TREES<<1) + (last ? 1 : 0), 3);
  21595. compress_block(s, static_ltree, static_dtree);
  21596. } else {
  21597. send_bits(s, (DYN_TREES<<1) + (last ? 1 : 0), 3);
  21598. send_all_trees(s, s.l_desc.max_code+1, s.d_desc.max_code+1, max_blindex+1);
  21599. compress_block(s, s.dyn_ltree, s.dyn_dtree);
  21600. }
  21601. // Assert (s->compressed_len == s->bits_sent, "bad compressed size");
  21602. /* The above check is made mod 2^32, for files larger than 512 MB
  21603. * and uLong implemented on 32 bits.
  21604. */
  21605. init_block(s);
  21606. if (last) {
  21607. bi_windup(s);
  21608. }
  21609. // Tracev((stderr,"\ncomprlen %lu(%lu) ", s->compressed_len>>3,
  21610. // s->compressed_len-7*last));
  21611. }
  21612. /* ===========================================================================
  21613. * Save the match info and tally the frequency counts. Return true if
  21614. * the current block must be flushed.
  21615. */
  21616. function _tr_tally(s, dist, lc)
  21617. // deflate_state *s;
  21618. // unsigned dist; /* distance of matched string */
  21619. // unsigned lc; /* match length-MIN_MATCH or unmatched char (if dist==0) */
  21620. {
  21621. //var out_length, in_length, dcode;
  21622. s.pending_buf[s.d_buf + s.last_lit * 2] = (dist >>> 8) & 0xff;
  21623. s.pending_buf[s.d_buf + s.last_lit * 2 + 1] = dist & 0xff;
  21624. s.pending_buf[s.l_buf + s.last_lit] = lc & 0xff;
  21625. s.last_lit++;
  21626. if (dist === 0) {
  21627. /* lc is the unmatched char */
  21628. s.dyn_ltree[lc*2]/*.Freq*/++;
  21629. } else {
  21630. s.matches++;
  21631. /* Here, lc is the match length - MIN_MATCH */
  21632. dist--; /* dist = match distance - 1 */
  21633. //Assert((ush)dist < (ush)MAX_DIST(s) &&
  21634. // (ush)lc <= (ush)(MAX_MATCH-MIN_MATCH) &&
  21635. // (ush)d_code(dist) < (ush)D_CODES, "_tr_tally: bad match");
  21636. s.dyn_ltree[(_length_code[lc]+LITERALS+1) * 2]/*.Freq*/++;
  21637. s.dyn_dtree[d_code(dist) * 2]/*.Freq*/++;
  21638. }
  21639. // (!) This block is disabled in zlib defailts,
  21640. // don't enable it for binary compatibility
  21641. //#ifdef TRUNCATE_BLOCK
  21642. // /* Try to guess if it is profitable to stop the current block here */
  21643. // if ((s.last_lit & 0x1fff) === 0 && s.level > 2) {
  21644. // /* Compute an upper bound for the compressed length */
  21645. // out_length = s.last_lit*8;
  21646. // in_length = s.strstart - s.block_start;
  21647. //
  21648. // for (dcode = 0; dcode < D_CODES; dcode++) {
  21649. // out_length += s.dyn_dtree[dcode*2]/*.Freq*/ * (5 + extra_dbits[dcode]);
  21650. // }
  21651. // out_length >>>= 3;
  21652. // //Tracev((stderr,"\nlast_lit %u, in %ld, out ~%ld(%ld%%) ",
  21653. // // s->last_lit, in_length, out_length,
  21654. // // 100L - out_length*100L/in_length));
  21655. // if (s.matches < (s.last_lit>>1)/*int /2*/ && out_length < (in_length>>1)/*int /2*/) {
  21656. // return true;
  21657. // }
  21658. // }
  21659. //#endif
  21660. return (s.last_lit === s.lit_bufsize-1);
  21661. /* We avoid equality with lit_bufsize because of wraparound at 64K
  21662. * on 16 bit machines and because stored blocks are restricted to
  21663. * 64K-1 bytes.
  21664. */
  21665. }
  21666. exports._tr_init = _tr_init;
  21667. exports._tr_stored_block = _tr_stored_block;
  21668. exports._tr_flush_block = _tr_flush_block;
  21669. exports._tr_tally = _tr_tally;
  21670. exports._tr_align = _tr_align;
  21671. },{"../utils/common":65}],77:[function(require,module,exports){
  21672. 'use strict';
  21673. function ZStream() {
  21674. /* next input byte */
  21675. this.input = null; // JS specific, because we have no pointers
  21676. this.next_in = 0;
  21677. /* number of bytes available at input */
  21678. this.avail_in = 0;
  21679. /* total number of input bytes read so far */
  21680. this.total_in = 0;
  21681. /* next output byte should be put there */
  21682. this.output = null; // JS specific, because we have no pointers
  21683. this.next_out = 0;
  21684. /* remaining free space at output */
  21685. this.avail_out = 0;
  21686. /* total number of bytes output so far */
  21687. this.total_out = 0;
  21688. /* last error message, NULL if no error */
  21689. this.msg = ''/*Z_NULL*/;
  21690. /* not visible by applications */
  21691. this.state = null;
  21692. /* best guess about the data type: binary or text */
  21693. this.data_type = 2/*Z_UNKNOWN*/;
  21694. /* adler32 value of the uncompressed data */
  21695. this.adler = 0;
  21696. }
  21697. module.exports = ZStream;
  21698. },{}],78:[function(require,module,exports){
  21699. var MediaStreamType = {
  21700. VIDEO_TYPE: "Video",
  21701. AUDIO_TYPE: "Audio"
  21702. };
  21703. module.exports = MediaStreamType;
  21704. },{}],79:[function(require,module,exports){
  21705. var RTCBrowserType = {
  21706. RTC_BROWSER_CHROME: "rtc_browser.chrome",
  21707. RTC_BROWSER_FIREFOX: "rtc_browser.firefox"
  21708. };
  21709. module.exports = RTCBrowserType;
  21710. },{}],80:[function(require,module,exports){
  21711. var RTCEvents = {
  21712. LASTN_CHANGED: "rtc.lastn_changed",
  21713. DOMINANTSPEAKER_CHANGED: "rtc.dominantspeaker_changed",
  21714. LASTN_ENDPOINT_CHANGED: "rtc.lastn_endpoint_changed",
  21715. SIMULCAST_LAYER_CHANGED: "rtc.simulcast_layer_changed",
  21716. SIMULCAST_LAYER_CHANGING: "rtc.simulcast_layer_changing",
  21717. SIMULCAST_START: "rtc.simlcast_start",
  21718. SIMULCAST_STOP: "rtc.simlcast_stop"
  21719. };
  21720. module.exports = RTCEvents;
  21721. },{}],81:[function(require,module,exports){
  21722. var StreamEventTypes = {
  21723. EVENT_TYPE_LOCAL_CREATED: "stream.local_created",
  21724. EVENT_TYPE_LOCAL_CHANGED: "stream.local_changed",
  21725. EVENT_TYPE_LOCAL_ENDED: "stream.local_ended",
  21726. EVENT_TYPE_REMOTE_CREATED: "stream.remote_created",
  21727. EVENT_TYPE_REMOTE_ENDED: "stream.remote_ended"
  21728. };
  21729. module.exports = StreamEventTypes;
  21730. },{}],82:[function(require,module,exports){
  21731. var UIEvents = {
  21732. NICKNAME_CHANGED: "UI.nickname_changed",
  21733. SELECTED_ENDPOINT: "UI.selected_endpoint",
  21734. PINNED_ENDPOINT: "UI.pinned_endpoint"
  21735. };
  21736. module.exports = UIEvents;
  21737. },{}],83:[function(require,module,exports){
  21738. var CQEvents = {
  21739. LOCALSTATS_UPDATED: "cq.localstats_updated",
  21740. REMOTESTATS_UPDATED: "cq.remotestats_updated",
  21741. STOP: "cq.stop"
  21742. };
  21743. module.exports = CQEvents;
  21744. },{}],84:[function(require,module,exports){
  21745. var DesktopSharingEventTypes = {
  21746. INIT: "ds.init",
  21747. SWITCHING_DONE: "ds.switching_done",
  21748. NEW_STREAM_CREATED: "ds.new_stream_created"
  21749. };
  21750. module.exports = DesktopSharingEventTypes;
  21751. },{}],85:[function(require,module,exports){
  21752. module.exports = {
  21753. getLanguages : function () {
  21754. var languages = [];
  21755. for(var lang in this)
  21756. {
  21757. if(typeof this[lang] === "string")
  21758. languages.push(this[lang]);
  21759. }
  21760. return languages;
  21761. },
  21762. EN: "en"
  21763. }
  21764. },{}],86:[function(require,module,exports){
  21765. var XMPPEvents = {
  21766. CONFERENCE_CERATED: "xmpp.conferenceCreated.jingle",
  21767. CALL_TERMINATED: "xmpp.callterminated.jingle",
  21768. CALL_INCOMING: "xmpp.callincoming.jingle",
  21769. DISPOSE_CONFERENCE: "xmpp.dispoce_confernce",
  21770. KICKED: "xmpp.kicked",
  21771. BRIDGE_DOWN: "xmpp.bridge_down",
  21772. USER_ID_CHANGED: "xmpp.user_id_changed",
  21773. CHANGED_STREAMS: "xmpp.changed_streams",
  21774. MUC_JOINED: "xmpp.muc_joined",
  21775. MUC_ENTER: "xmpp.muc_enter",
  21776. MUC_ROLE_CHANGED: "xmpp.muc_role_changed",
  21777. MUC_LEFT: "xmpp.muc_left",
  21778. DISPLAY_NAME_CHANGED: "xmpp.display_name_changed",
  21779. REMOTE_STATS: "xmpp.remote_stats",
  21780. LOCALROLE_CHANGED: "xmpp.localrole_changed",
  21781. PRESENCE_STATUS: "xmpp.presence_status",
  21782. SUBJECT_CHANGED: "xmpp.subject_changed",
  21783. MESSAGE_RECEIVED: "xmpp.message_received",
  21784. SENDING_CHAT_MESSAGE: "xmpp.sending_chat_message",
  21785. PASSWORD_REQUIRED: "xmpp.password_required",
  21786. AUTHENTICATION_REQUIRED: "xmpp.authentication_required",
  21787. CHAT_ERROR_RECEIVED: "xmpp.chat_error_received",
  21788. ETHERPAD: "xmpp.etherpad"
  21789. };
  21790. module.exports = XMPPEvents;
  21791. },{}],87:[function(require,module,exports){
  21792. // Copyright Joyent, Inc. and other Node contributors.
  21793. //
  21794. // Permission is hereby granted, free of charge, to any person obtaining a
  21795. // copy of this software and associated documentation files (the
  21796. // "Software"), to deal in the Software without restriction, including
  21797. // without limitation the rights to use, copy, modify, merge, publish,
  21798. // distribute, sublicense, and/or sell copies of the Software, and to permit
  21799. // persons to whom the Software is furnished to do so, subject to the
  21800. // following conditions:
  21801. //
  21802. // The above copyright notice and this permission notice shall be included
  21803. // in all copies or substantial portions of the Software.
  21804. //
  21805. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  21806. // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  21807. // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
  21808. // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
  21809. // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  21810. // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
  21811. // USE OR OTHER DEALINGS IN THE SOFTWARE.
  21812. function EventEmitter() {
  21813. this._events = this._events || {};
  21814. this._maxListeners = this._maxListeners || undefined;
  21815. }
  21816. module.exports = EventEmitter;
  21817. // Backwards-compat with node 0.10.x
  21818. EventEmitter.EventEmitter = EventEmitter;
  21819. EventEmitter.prototype._events = undefined;
  21820. EventEmitter.prototype._maxListeners = undefined;
  21821. // By default EventEmitters will print a warning if more than 10 listeners are
  21822. // added to it. This is a useful default which helps finding memory leaks.
  21823. EventEmitter.defaultMaxListeners = 10;
  21824. // Obviously not all Emitters should be limited to 10. This function allows
  21825. // that to be increased. Set to zero for unlimited.
  21826. EventEmitter.prototype.setMaxListeners = function(n) {
  21827. if (!isNumber(n) || n < 0 || isNaN(n))
  21828. throw TypeError('n must be a positive number');
  21829. this._maxListeners = n;
  21830. return this;
  21831. };
  21832. EventEmitter.prototype.emit = function(type) {
  21833. var er, handler, len, args, i, listeners;
  21834. if (!this._events)
  21835. this._events = {};
  21836. // If there is no 'error' event listener then throw.
  21837. if (type === 'error') {
  21838. if (!this._events.error ||
  21839. (isObject(this._events.error) && !this._events.error.length)) {
  21840. er = arguments[1];
  21841. if (er instanceof Error) {
  21842. throw er; // Unhandled 'error' event
  21843. }
  21844. throw TypeError('Uncaught, unspecified "error" event.');
  21845. }
  21846. }
  21847. handler = this._events[type];
  21848. if (isUndefined(handler))
  21849. return false;
  21850. if (isFunction(handler)) {
  21851. switch (arguments.length) {
  21852. // fast cases
  21853. case 1:
  21854. handler.call(this);
  21855. break;
  21856. case 2:
  21857. handler.call(this, arguments[1]);
  21858. break;
  21859. case 3:
  21860. handler.call(this, arguments[1], arguments[2]);
  21861. break;
  21862. // slower
  21863. default:
  21864. len = arguments.length;
  21865. args = new Array(len - 1);
  21866. for (i = 1; i < len; i++)
  21867. args[i - 1] = arguments[i];
  21868. handler.apply(this, args);
  21869. }
  21870. } else if (isObject(handler)) {
  21871. len = arguments.length;
  21872. args = new Array(len - 1);
  21873. for (i = 1; i < len; i++)
  21874. args[i - 1] = arguments[i];
  21875. listeners = handler.slice();
  21876. len = listeners.length;
  21877. for (i = 0; i < len; i++)
  21878. listeners[i].apply(this, args);
  21879. }
  21880. return true;
  21881. };
  21882. EventEmitter.prototype.addListener = function(type, listener) {
  21883. var m;
  21884. if (!isFunction(listener))
  21885. throw TypeError('listener must be a function');
  21886. if (!this._events)
  21887. this._events = {};
  21888. // To avoid recursion in the case that type === "newListener"! Before
  21889. // adding it to the listeners, first emit "newListener".
  21890. if (this._events.newListener)
  21891. this.emit('newListener', type,
  21892. isFunction(listener.listener) ?
  21893. listener.listener : listener);
  21894. if (!this._events[type])
  21895. // Optimize the case of one listener. Don't need the extra array object.
  21896. this._events[type] = listener;
  21897. else if (isObject(this._events[type]))
  21898. // If we've already got an array, just append.
  21899. this._events[type].push(listener);
  21900. else
  21901. // Adding the second element, need to change to array.
  21902. this._events[type] = [this._events[type], listener];
  21903. // Check for listener leak
  21904. if (isObject(this._events[type]) && !this._events[type].warned) {
  21905. var m;
  21906. if (!isUndefined(this._maxListeners)) {
  21907. m = this._maxListeners;
  21908. } else {
  21909. m = EventEmitter.defaultMaxListeners;
  21910. }
  21911. if (m && m > 0 && this._events[type].length > m) {
  21912. this._events[type].warned = true;
  21913. console.error('(node) warning: possible EventEmitter memory ' +
  21914. 'leak detected. %d listeners added. ' +
  21915. 'Use emitter.setMaxListeners() to increase limit.',
  21916. this._events[type].length);
  21917. if (typeof console.trace === 'function') {
  21918. // not supported in IE 10
  21919. console.trace();
  21920. }
  21921. }
  21922. }
  21923. return this;
  21924. };
  21925. EventEmitter.prototype.on = EventEmitter.prototype.addListener;
  21926. EventEmitter.prototype.once = function(type, listener) {
  21927. if (!isFunction(listener))
  21928. throw TypeError('listener must be a function');
  21929. var fired = false;
  21930. function g() {
  21931. this.removeListener(type, g);
  21932. if (!fired) {
  21933. fired = true;
  21934. listener.apply(this, arguments);
  21935. }
  21936. }
  21937. g.listener = listener;
  21938. this.on(type, g);
  21939. return this;
  21940. };
  21941. // emits a 'removeListener' event iff the listener was removed
  21942. EventEmitter.prototype.removeListener = function(type, listener) {
  21943. var list, position, length, i;
  21944. if (!isFunction(listener))
  21945. throw TypeError('listener must be a function');
  21946. if (!this._events || !this._events[type])
  21947. return this;
  21948. list = this._events[type];
  21949. length = list.length;
  21950. position = -1;
  21951. if (list === listener ||
  21952. (isFunction(list.listener) && list.listener === listener)) {
  21953. delete this._events[type];
  21954. if (this._events.removeListener)
  21955. this.emit('removeListener', type, listener);
  21956. } else if (isObject(list)) {
  21957. for (i = length; i-- > 0;) {
  21958. if (list[i] === listener ||
  21959. (list[i].listener && list[i].listener === listener)) {
  21960. position = i;
  21961. break;
  21962. }
  21963. }
  21964. if (position < 0)
  21965. return this;
  21966. if (list.length === 1) {
  21967. list.length = 0;
  21968. delete this._events[type];
  21969. } else {
  21970. list.splice(position, 1);
  21971. }
  21972. if (this._events.removeListener)
  21973. this.emit('removeListener', type, listener);
  21974. }
  21975. return this;
  21976. };
  21977. EventEmitter.prototype.removeAllListeners = function(type) {
  21978. var key, listeners;
  21979. if (!this._events)
  21980. return this;
  21981. // not listening for removeListener, no need to emit
  21982. if (!this._events.removeListener) {
  21983. if (arguments.length === 0)
  21984. this._events = {};
  21985. else if (this._events[type])
  21986. delete this._events[type];
  21987. return this;
  21988. }
  21989. // emit removeListener for all listeners on all events
  21990. if (arguments.length === 0) {
  21991. for (key in this._events) {
  21992. if (key === 'removeListener') continue;
  21993. this.removeAllListeners(key);
  21994. }
  21995. this.removeAllListeners('removeListener');
  21996. this._events = {};
  21997. return this;
  21998. }
  21999. listeners = this._events[type];
  22000. if (isFunction(listeners)) {
  22001. this.removeListener(type, listeners);
  22002. } else {
  22003. // LIFO order
  22004. while (listeners.length)
  22005. this.removeListener(type, listeners[listeners.length - 1]);
  22006. }
  22007. delete this._events[type];
  22008. return this;
  22009. };
  22010. EventEmitter.prototype.listeners = function(type) {
  22011. var ret;
  22012. if (!this._events || !this._events[type])
  22013. ret = [];
  22014. else if (isFunction(this._events[type]))
  22015. ret = [this._events[type]];
  22016. else
  22017. ret = this._events[type].slice();
  22018. return ret;
  22019. };
  22020. EventEmitter.listenerCount = function(emitter, type) {
  22021. var ret;
  22022. if (!emitter._events || !emitter._events[type])
  22023. ret = 0;
  22024. else if (isFunction(emitter._events[type]))
  22025. ret = 1;
  22026. else
  22027. ret = emitter._events[type].length;
  22028. return ret;
  22029. };
  22030. function isFunction(arg) {
  22031. return typeof arg === 'function';
  22032. }
  22033. function isNumber(arg) {
  22034. return typeof arg === 'number';
  22035. }
  22036. function isObject(arg) {
  22037. return typeof arg === 'object' && arg !== null;
  22038. }
  22039. function isUndefined(arg) {
  22040. return arg === void 0;
  22041. }
  22042. },{}]},{},[1])(1)
  22043. });
  22044. //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uLy4uL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2Jyb3dzZXItcGFjay9fcHJlbHVkZS5qcyIsImFwcC5qcyIsIm1vZHVsZXMvQVBJL0FQSS5qcyIsIm1vZHVsZXMvUlRDL0RhdGFDaGFubmVscy5qcyIsIm1vZHVsZXMvUlRDL0xvY2FsU3RyZWFtLmpzIiwibW9kdWxlcy9SVEMvTWVkaWFTdHJlYW0uanMiLCJtb2R1bGVzL1JUQy9SVEMuanMiLCJtb2R1bGVzL1JUQy9SVENVdGlscy5qcyIsIm1vZHVsZXMvVUkvVUkuanMiLCJtb2R1bGVzL1VJL2F1ZGlvX2xldmVscy9BdWRpb0xldmVscy5qcyIsIm1vZHVsZXMvVUkvYXVkaW9fbGV2ZWxzL0NhbnZhc1V0aWxzLmpzIiwibW9kdWxlcy9VSS9hdXRoZW50aWNhdGlvbi9BdXRoZW50aWNhdGlvbi5qcyIsIm1vZHVsZXMvVUkvYXZhdGFyL0F2YXRhci5qcyIsIm1vZHVsZXMvVUkvZXRoZXJwYWQvRXRoZXJwYWQuanMiLCJtb2R1bGVzL1VJL3ByZXppL1ByZXppLmpzIiwibW9kdWxlcy9VSS9wcmV6aS9QcmV6aVBsYXllci5qcyIsIm1vZHVsZXMvVUkvc2lkZV9wYW5uZWxzL1NpZGVQYW5lbFRvZ2dsZXIuanMiLCJtb2R1bGVzL1VJL3NpZGVfcGFubmVscy9jaGF0L0NoYXQuanMiLCJtb2R1bGVzL1VJL3NpZGVfcGFubmVscy9jaGF0L0NvbW1hbmRzLmpzIiwibW9kdWxlcy9VSS9zaWRlX3Bhbm5lbHMvY2hhdC9SZXBsYWNlbWVudC5qcyIsIm1vZHVsZXMvVUkvc2lkZV9wYW5uZWxzL2NoYXQvc21pbGV5cy5qc29uIiwibW9kdWxlcy9VSS9zaWRlX3Bhbm5lbHMvY29udGFjdGxpc3QvQ29udGFjdExpc3QuanMiLCJtb2R1bGVzL1VJL3NpZGVfcGFubmVscy9zZXR0aW5ncy9TZXR0aW5ncy5qcyIsIm1vZHVsZXMvVUkvc2lkZV9wYW5uZWxzL3NldHRpbmdzL1NldHRpbmdzTWVudS5qcyIsIm1vZHVsZXMvVUkvdG9vbGJhcnMvQm90dG9tVG9vbGJhci5qcyIsIm1vZHVsZXMvVUkvdG9vbGJhcnMvVG9vbGJhci5qcyIsIm1vZHVsZXMvVUkvdG9vbGJhcnMvVG9vbGJhclRvZ2dsZXIuanMiLCJtb2R1bGVzL1VJL3V0aWwvSml0c2lQb3BvdmVyLmpzIiwibW9kdWxlcy9VSS91dGlsL01lc3NhZ2VIYW5kbGVyLmpzIiwibW9kdWxlcy9VSS91dGlsL05pY2tuYW1lSGFuZGxlci5qcyIsIm1vZHVsZXMvVUkvdXRpbC9VSVV0aWwuanMiLCJtb2R1bGVzL1VJL3ZpZGVvbGF5b3V0L0Nvbm5lY3Rpb25JbmRpY2F0b3IuanMiLCJtb2R1bGVzL1VJL3ZpZGVvbGF5b3V0L1ZpZGVvTGF5b3V0LmpzIiwibW9kdWxlcy9VSS93ZWxjb21lX3BhZ2UvUm9vbW5hbWVHZW5lcmF0b3IuanMiLCJtb2R1bGVzL1VJL3dlbGNvbWVfcGFnZS9XZWxjb21lUGFnZS5qcyIsIm1vZHVsZXMvY29ubmVjdGlvbnF1YWxpdHkvY29ubmVjdGlvbnF1YWxpdHkuanMiLCJtb2R1bGVzL2Rlc2t0b3BzaGFyaW5nL2Rlc2t0b3BzaGFyaW5nLmpzIiwibW9kdWxlcy9rZXlib2FyZHNob3J0Y3V0L2tleWJvYXJkc2hvcnRjdXQuanMiLCJtb2R1bGVzL3NpbXVsY2FzdC9TaW11bGNhc3RMb2dnZXIuanMiLCJtb2R1bGVzL3NpbXVsY2FzdC9TaW11bGNhc3RSZWNlaXZlci5qcyIsIm1vZHVsZXMvc2ltdWxjYXN0L1NpbXVsY2FzdFNlbmRlci5qcyIsIm1vZHVsZXMvc2ltdWxjYXN0L1NpbXVsY2FzdFV0aWxzLmpzIiwibW9kdWxlcy9zaW11bGNhc3Qvc2ltdWxjYXN0LmpzIiwibW9kdWxlcy9zdGF0aXN0aWNzL0xvY2FsU3RhdHNDb2xsZWN0b3IuanMiLCJtb2R1bGVzL3N0YXRpc3RpY3MvUlRQU3RhdHNDb2xsZWN0b3IuanMiLCJtb2R1bGVzL3N0YXRpc3RpY3Mvc3RhdGlzdGljcy5qcyIsIm1vZHVsZXMvdHJhbnNsYXRpb24vdHJhbnNsYXRpb24uanMiLCJtb2R1bGVzL3htcHAvSmluZ2xlU2Vzc2lvbi5qcyIsIm1vZHVsZXMveG1wcC9TRFAuanMiLCJtb2R1bGVzL3htcHAvU0RQRGlmZmVyLmpzIiwibW9kdWxlcy94bXBwL1NEUFV0aWwuanMiLCJtb2R1bGVzL3htcHAvVHJhY2VhYmxlUGVlckNvbm5lY3Rpb24uanMiLCJtb2R1bGVzL3htcHAvbW9kZXJhdG9yLmpzIiwibW9kdWxlcy94bXBwL3JlY29yZGluZy5qcyIsIm1vZHVsZXMveG1wcC9zdHJvcGhlLmVtdWMuanMiLCJtb2R1bGVzL3htcHAvc3Ryb3BoZS5qaW5nbGUuanMiLCJtb2R1bGVzL3htcHAvc3Ryb3BoZS5sb2dnZXIuanMiLCJtb2R1bGVzL3htcHAvc3Ryb3BoZS5tb2RlcmF0ZS5qcyIsIm1vZHVsZXMveG1wcC9zdHJvcGhlLnJheW8uanMiLCJtb2R1bGVzL3htcHAvc3Ryb3BoZS51dGlsLmpzIiwibW9kdWxlcy94bXBwL3htcHAuanMiLCJub2RlX21vZHVsZXMvaTE4bmV4dC1jbGllbnQvaTE4bmV4dC5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2luZGV4LmpzIiwibm9kZV9tb2R1bGVzL3Bha28vbGliL2RlZmxhdGUuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvaW5mbGF0ZS5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi91dGlscy9jb21tb24uanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvdXRpbHMvc3RyaW5ncy5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi96bGliL2FkbGVyMzIuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9jb25zdGFudHMuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9jcmMzMi5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi96bGliL2RlZmxhdGUuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9nemhlYWRlci5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi96bGliL2luZmZhc3QuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9pbmZsYXRlLmpzIiwibm9kZV9tb2R1bGVzL3Bha28vbGliL3psaWIvaW5mdHJlZXMuanMiLCJub2RlX21vZHVsZXMvcGFrby9saWIvemxpYi9tZXNzYWdlcy5qcyIsIm5vZGVfbW9kdWxlcy9wYWtvL2xpYi96bGliL3RyZWVzLmpzIiwibm9kZV9tb2R1bGVzL3Bha28vbGliL3psaWIvenN0cmVhbS5qcyIsInNlcnZpY2UvUlRDL01lZGlhU3RyZWFtVHlwZXMuanMiLCJzZXJ2aWNlL1JUQy9SVENCcm93c2VyVHlwZS5qcyIsInNlcnZpY2UvUlRDL1JUQ0V2ZW50cy5qcyIsInNlcnZpY2UvUlRDL1N0cmVhbUV2ZW50VHlwZXMuanMiLCJzZXJ2aWNlL1VJL1VJRXZlbnRzLmpzIiwic2VydmljZS9jb25uZWN0aW9ucXVhbGl0eS9DUUV2ZW50cy5qcyIsInNlcnZpY2UvZGVza3RvcHNoYXJpbmcvRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzLmpzIiwic2VydmljZS90cmFuc2xhdGlvbi9sYW5ndWFnZXMuanMiLCJzZXJ2aWNlL3htcHAvWE1QUEV2ZW50cy5qcyIsIi4uLy4uLy4uLy4uLy4uL3Vzci9sb2NhbC9saWIvbm9kZV9tb2R1bGVzL2Jyb3dzZXJpZnkvbm9kZV9tb2R1bGVzL2V2ZW50cy9ldmVudHMuanMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7QUNBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDckRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN0T0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4T0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1TUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM5VUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9zQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZRQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxSkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2xNQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JTQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvUEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3BXQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNoREE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3RMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzFEQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzVFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JnQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pIQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUhBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN2S0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzdCQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDaEZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOWFBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6cEVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuTEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNySUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25VQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzNGQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMzUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pnQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN4T0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDek1BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2pJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ2hyQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ25JQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOUdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNsM0NBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1bUJBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwS0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVZBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMxUUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyUkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekpBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZtQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNqVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNuQkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDekRBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUMvRkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDMUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzViQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6a0VBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDYkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDeFdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDNVdBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNyR0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3pMQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQy9CQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3hDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNwdURBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3ZDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JVQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDOTlDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ3JVQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNaQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQzlxQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUM1QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDVkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ0xBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQ05BO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUNSQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FDWEE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUN6QkE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSIsImZpbGUiOiJnZW5lcmF0ZWQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlc0NvbnRlbnQiOlsiKGZ1bmN0aW9uIGUodCxuLHIpe2Z1bmN0aW9uIHMobyx1KXtpZighbltvXSl7aWYoIXRbb10pe3ZhciBhPXR5cGVvZiByZXF1aXJlPT1cImZ1bmN0aW9uXCImJnJlcXVpcmU7aWYoIXUmJmEpcmV0dXJuIGEobywhMCk7aWYoaSlyZXR1cm4gaShvLCEwKTt2YXIgZj1uZXcgRXJyb3IoXCJDYW5ub3QgZmluZCBtb2R1bGUgJ1wiK28rXCInXCIpO3Rocm93IGYuY29kZT1cIk1PRFVMRV9OT1RfRk9VTkRcIixmfXZhciBsPW5bb109e2V4cG9ydHM6e319O3Rbb11bMF0uY2FsbChsLmV4cG9ydHMsZnVuY3Rpb24oZSl7dmFyIG49dFtvXVsxXVtlXTtyZXR1cm4gcyhuP246ZSl9LGwsbC5leHBvcnRzLGUsdCxuLHIpfXJldHVybiBuW29dLmV4cG9ydHN9dmFyIGk9dHlwZW9mIHJlcXVpcmU9PVwiZnVuY3Rpb25cIiYmcmVxdWlyZTtmb3IodmFyIG89MDtvPHIubGVuZ3RoO28rKylzKHJbb10pO3JldHVybiBzfSkiLCIvKiBqc2hpbnQgLVcxMTcgKi9cbi8qIGFwcGxpY2F0aW9uIHNwZWNpZmljIGxvZ2ljICovXG5cbnZhciBBUFAgPVxue1xuICAgIGluaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdGhpcy5VSSA9IHJlcXVpcmUoXCIuL21vZHVsZXMvVUkvVUlcIik7XG4gICAgICAgIHRoaXMuQVBJID0gcmVxdWlyZShcIi4vbW9kdWxlcy9BUEkvQVBJXCIpO1xuICAgICAgICB0aGlzLmNvbm5lY3Rpb25xdWFsaXR5ID0gcmVxdWlyZShcIi4vbW9kdWxlcy9jb25uZWN0aW9ucXVhbGl0eS9jb25uZWN0aW9ucXVhbGl0eVwiKTtcbiAgICAgICAgdGhpcy5zdGF0aXN0aWNzID0gcmVxdWlyZShcIi4vbW9kdWxlcy9zdGF0aXN0aWNzL3N0YXRpc3RpY3NcIik7XG4gICAgICAgIHRoaXMuUlRDID0gcmVxdWlyZShcIi4vbW9kdWxlcy9SVEMvUlRDXCIpO1xuICAgICAgICB0aGlzLnNpbXVsY2FzdCA9IHJlcXVpcmUoXCIuL21vZHVsZXMvc2ltdWxjYXN0L3NpbXVsY2FzdFwiKTtcbiAgICAgICAgdGhpcy5kZXNrdG9wc2hhcmluZyA9IHJlcXVpcmUoXCIuL21vZHVsZXMvZGVza3RvcHNoYXJpbmcvZGVza3RvcHNoYXJpbmdcIik7XG4gICAgICAgIHRoaXMueG1wcCA9IHJlcXVpcmUoXCIuL21vZHVsZXMveG1wcC94bXBwXCIpO1xuICAgICAgICB0aGlzLmtleWJvYXJkc2hvcnRjdXQgPSByZXF1aXJlKFwiLi9tb2R1bGVzL2tleWJvYXJkc2hvcnRjdXQva2V5Ym9hcmRzaG9ydGN1dFwiKTtcbiAgICAgICAgdGhpcy50cmFuc2xhdGlvbiA9IHJlcXVpcmUoXCIuL21vZHVsZXMvdHJhbnNsYXRpb24vdHJhbnNsYXRpb25cIik7XG4gICAgfVxufTtcblxuZnVuY3Rpb24gaW5pdCgpIHtcblxuICAgIEFQUC5SVEMuc3RhcnQoKTtcbiAgICBBUFAueG1wcC5zdGFydChBUFAuVUkuZ2V0Q3JlZGVudGlhbHMoKSk7XG4gICAgQVBQLnN0YXRpc3RpY3Muc3RhcnQoKTtcbiAgICBBUFAuY29ubmVjdGlvbnF1YWxpdHkuaW5pdCgpO1xuXG4gICAgLy8gU2V0IGRlZmF1bHQgZGVza3RvcCBzaGFyaW5nIG1ldGhvZFxuICAgIEFQUC5kZXNrdG9wc2hhcmluZy5pbml0KCk7XG5cbiAgICBBUFAua2V5Ym9hcmRzaG9ydGN1dC5pbml0KCk7XG59XG5cblxuJChkb2N1bWVudCkucmVhZHkoZnVuY3Rpb24gKCkge1xuXG4gICAgQVBQLmluaXQoKTtcblxuICAgIEFQUC50cmFuc2xhdGlvbi5pbml0KCk7XG5cbiAgICBpZihBUFAuQVBJLmlzRW5hYmxlZCgpKVxuICAgICAgICBBUFAuQVBJLmluaXQoKTtcblxuICAgIEFQUC5VSS5zdGFydChpbml0KTtcblxufSk7XG5cbiQod2luZG93KS5iaW5kKCdiZWZvcmV1bmxvYWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgaWYoQVBQLkFQSS5pc0VuYWJsZWQoKSlcbiAgICAgICAgQVBQLkFQSS5kaXNwb3NlKCk7XG59KTtcblxubW9kdWxlLmV4cG9ydHMgPSBBUFA7XG5cbiIsIi8qKlxuICogSW1wbGVtZW50cyBBUEkgY2xhc3MgdGhhdCBjb21tdW5pY2F0ZXMgd2l0aCBleHRlcm5hbCBhcGkgY2xhc3NcbiAqIGFuZCBwcm92aWRlcyBpbnRlcmZhY2UgdG8gYWNjZXNzIEppdHNpIE1lZXQgZmVhdHVyZXMgYnkgZXh0ZXJuYWxcbiAqIGFwcGxpY2F0aW9ucyB0aGF0IGVtYmVkIEppdHNpIE1lZXRcbiAqL1xuXG52YXIgWE1QUEV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL3htcHAvWE1QUEV2ZW50c1wiKTtcblxuLyoqXG4gKiBMaXN0IG9mIHRoZSBhdmFpbGFibGUgY29tbWFuZHMuXG4gKiBAdHlwZSB7e1xuICogICAgICAgICAgICAgIGRpc3BsYXlOYW1lOiBpbnB1dERpc3BsYXlOYW1lSGFuZGxlcixcbiAqICAgICAgICAgICAgICBtdXRlQXVkaW86IHRvZ2dsZUF1ZGlvLFxuICogICAgICAgICAgICAgIG11dGVWaWRlbzogdG9nZ2xlVmlkZW8sXG4gKiAgICAgICAgICAgICAgZmlsbVN0cmlwOiB0b2dnbGVGaWxtU3RyaXBcbiAqICAgICAgICAgIH19XG4gKi9cbnZhciBjb21tYW5kcyA9XG57XG4gICAgZGlzcGxheU5hbWU6IEFQUC5VSS5pbnB1dERpc3BsYXlOYW1lSGFuZGxlcixcbiAgICBtdXRlQXVkaW86IEFQUC5VSS50b2dnbGVBdWRpbyxcbiAgICBtdXRlVmlkZW86IEFQUC5VSS50b2dnbGVWaWRlbyxcbiAgICB0b2dnbGVGaWxtU3RyaXA6IEFQUC5VSS50b2dnbGVGaWxtU3RyaXAsXG4gICAgdG9nZ2xlQ2hhdDogQVBQLlVJLnRvZ2dsZUNoYXQsXG4gICAgdG9nZ2xlQ29udGFjdExpc3Q6IEFQUC5VSS50b2dnbGVDb250YWN0TGlzdFxufTtcblxuXG4vKipcbiAqIE1hcHMgdGhlIHN1cHBvcnRlZCBldmVudHMgYW5kIHRoZWlyIHN0YXR1c1xuICogKHRydWUgaXQgdGhlIGV2ZW50IGlzIGVuYWJsZWQgYW5kIGZhbHNlIGlmIGl0IGlzIGRpc2FibGVkKVxuICogQHR5cGUge3tcbiAqICAgICAgICAgICAgICBpbmNvbWluZ01lc3NhZ2U6IGJvb2xlYW4sXG4gKiAgICAgICAgICAgICAgb3V0Z29pbmdNZXNzYWdlOiBib29sZWFuLFxuICogICAgICAgICAgICAgIGRpc3BsYXlOYW1lQ2hhbmdlOiBib29sZWFuLFxuICogICAgICAgICAgICAgIHBhcnRpY2lwYW50Sm9pbmVkOiBib29sZWFuLFxuICogICAgICAgICAgICAgIHBhcnRpY2lwYW50TGVmdDogYm9vbGVhblxuICogICAgICB9fVxuICovXG52YXIgZXZlbnRzID1cbntcbiAgICBpbmNvbWluZ01lc3NhZ2U6IGZhbHNlLFxuICAgIG91dGdvaW5nTWVzc2FnZTpmYWxzZSxcbiAgICBkaXNwbGF5TmFtZUNoYW5nZTogZmFsc2UsXG4gICAgcGFydGljaXBhbnRKb2luZWQ6IGZhbHNlLFxuICAgIHBhcnRpY2lwYW50TGVmdDogZmFsc2Vcbn07XG5cbnZhciBkaXNwbGF5TmFtZSA9IHt9O1xuXG4vKipcbiAqIFByb2Nlc3NlcyBjb21tYW5kcyBmcm9tIGV4dGVybmFsIGFwcGxpY2FpdG9uLlxuICogQHBhcmFtIG1lc3NhZ2UgdGhlIG9iamVjdCB3aXRoIHRoZSBjb21tYW5kXG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3NDb21tYW5kKG1lc3NhZ2UpXG57XG4gICAgaWYobWVzc2FnZS5hY3Rpb24gIT0gXCJleGVjdXRlXCIpXG4gICAge1xuICAgICAgICBjb25zb2xlLmVycm9yKFwiVW5rbm93biBhY3Rpb24gb2YgdGhlIG1lc3NhZ2VcIik7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG4gICAgZm9yKHZhciBrZXkgaW4gbWVzc2FnZSlcbiAgICB7XG4gICAgICAgIGlmKGNvbW1hbmRzW2tleV0pXG4gICAgICAgICAgICBjb21tYW5kc1trZXldLmFwcGx5KG51bGwsIG1lc3NhZ2Vba2V5XSk7XG4gICAgfVxufVxuXG4vKipcbiAqIFByb2Nlc3NlcyBldmVudHMgb2JqZWN0cyBmcm9tIGV4dGVybmFsIGFwcGxpY2F0aW9uc1xuICogQHBhcmFtIGV2ZW50IHRoZSBldmVudFxuICovXG5mdW5jdGlvbiBwcm9jZXNzRXZlbnQoZXZlbnQpIHtcbiAgICBpZighZXZlbnQuYWN0aW9uKVxuICAgIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkV2ZW50IHdpdGggbm8gYWN0aW9uIGlzIHJlY2VpdmVkLlwiKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHZhciBpID0gMDtcbiAgICBzd2l0Y2goZXZlbnQuYWN0aW9uKVxuICAgIHtcbiAgICAgICAgY2FzZSBcImFkZFwiOlxuICAgICAgICAgICAgZm9yKDsgaSA8IGV2ZW50LmV2ZW50cy5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBldmVudHNbZXZlbnQuZXZlbnRzW2ldXSA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcInJlbW92ZVwiOlxuICAgICAgICAgICAgZm9yKDsgaSA8IGV2ZW50LmV2ZW50cy5sZW5ndGg7IGkrKylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBldmVudHNbZXZlbnQuZXZlbnRzW2ldXSA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiVW5rbm93biBhY3Rpb24gZm9yIGV2ZW50LlwiKTtcbiAgICB9XG5cbn1cblxuLyoqXG4gKiBTZW5kcyBtZXNzYWdlIHRvIHRoZSBleHRlcm5hbCBhcHBsaWNhdGlvbi5cbiAqIEBwYXJhbSBvYmplY3RcbiAqL1xuZnVuY3Rpb24gc2VuZE1lc3NhZ2Uob2JqZWN0KSB7XG4gICAgd2luZG93LnBhcmVudC5wb3N0TWVzc2FnZShKU09OLnN0cmluZ2lmeShvYmplY3QpLCBcIipcIik7XG59XG5cbi8qKlxuICogUHJvY2Vzc2VzIGEgbWVzc2FnZSBldmVudCBmcm9tIHRoZSBleHRlcm5hbCBhcHBsaWNhdGlvblxuICogQHBhcmFtIGV2ZW50IHRoZSBtZXNzYWdlIGV2ZW50XG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3NNZXNzYWdlKGV2ZW50KVxue1xuICAgIHZhciBtZXNzYWdlO1xuICAgIHRyeSB7XG4gICAgICAgIG1lc3NhZ2UgPSBKU09OLnBhcnNlKGV2ZW50LmRhdGEpO1xuICAgIH0gY2F0Y2ggKGUpIHt9XG5cbiAgICBpZighbWVzc2FnZS50eXBlKVxuICAgICAgICByZXR1cm47XG4gICAgc3dpdGNoIChtZXNzYWdlLnR5cGUpXG4gICAge1xuICAgICAgICBjYXNlIFwiY29tbWFuZFwiOlxuICAgICAgICAgICAgcHJvY2Vzc0NvbW1hbmQobWVzc2FnZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSBcImV2ZW50XCI6XG4gICAgICAgICAgICBwcm9jZXNzRXZlbnQobWVzc2FnZSk7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJVbmtub3duIHR5cGUgb2YgdGhlIG1lc3NhZ2VcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgfVxuXG59XG5cbmZ1bmN0aW9uIHNldHVwTGlzdGVuZXJzKCkge1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTVVDX0VOVEVSLCBmdW5jdGlvbiAoZnJvbSkge1xuICAgICAgICBBUEkudHJpZ2dlckV2ZW50KFwicGFydGljaXBhbnRKb2luZWRcIiwge2ppZDogZnJvbX0pO1xuICAgIH0pO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTUVTU0FHRV9SRUNFSVZFRCwgZnVuY3Rpb24gKGZyb20sIG5pY2ssIHR4dCwgbXlqaWQpIHtcbiAgICAgICAgaWYgKGZyb20gIT0gbXlqaWQpXG4gICAgICAgICAgICBBUEkudHJpZ2dlckV2ZW50KFwiaW5jb21pbmdNZXNzYWdlXCIsXG4gICAgICAgICAgICAgICAge1wiZnJvbVwiOiBmcm9tLCBcIm5pY2tcIjogbmljaywgXCJtZXNzYWdlXCI6IHR4dH0pO1xuICAgIH0pO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTVVDX0xFRlQsIGZ1bmN0aW9uIChqaWQpIHtcbiAgICAgICAgQVBJLnRyaWdnZXJFdmVudChcInBhcnRpY2lwYW50TGVmdFwiLCB7amlkOiBqaWR9KTtcbiAgICB9KTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLkRJU1BMQVlfTkFNRV9DSEFOR0VELCBmdW5jdGlvbiAoamlkLCBuZXdEaXNwbGF5TmFtZSkge1xuICAgICAgICBuYW1lID0gZGlzcGxheU5hbWVbamlkXTtcbiAgICAgICAgaWYoIW5hbWUgfHwgbmFtZSAhPSBuZXdEaXNwbGF5TmFtZSkge1xuICAgICAgICAgICAgQVBJLnRyaWdnZXJFdmVudChcImRpc3BsYXlOYW1lQ2hhbmdlXCIsIHtqaWQ6IGppZCwgZGlzcGxheW5hbWU6IG5ld0Rpc3BsYXlOYW1lfSk7XG4gICAgICAgICAgICBkaXNwbGF5TmFtZVtqaWRdID0gbmV3RGlzcGxheU5hbWU7XG4gICAgICAgIH1cbiAgICB9KTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLlNFTkRJTkdfQ0hBVF9NRVNTQUdFLCBmdW5jdGlvbiAoYm9keSkge1xuICAgICAgICBBUFAuQVBJLnRyaWdnZXJFdmVudChcIm91dGdvaW5nTWVzc2FnZVwiLCB7XCJtZXNzYWdlXCI6IGJvZHl9KTtcbiAgICB9KTtcbn1cblxudmFyIEFQSSA9IHtcbiAgICAvKipcbiAgICAgKiBDaGVjayB3aGV0aGVyIHRoZSBBUEkgc2hvdWxkIGJlIGVuYWJsZWQgb3Igbm90LlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufVxuICAgICAqL1xuICAgIGlzRW5hYmxlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgaGFzaCA9IGxvY2F0aW9uLmhhc2g7XG4gICAgICAgIGlmKGhhc2ggJiYgaGFzaC5pbmRleE9mKFwiZXh0ZXJuYWxcIikgPiAtMSAmJiB3aW5kb3cucG9zdE1lc3NhZ2UpXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH0sXG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZXMgdGhlIEFQSUNvbm5lY3Rvci4gU2V0dXBzIG1lc3NhZ2UgZXZlbnQgbGlzdGVuZXJzIHRoYXQgd2lsbFxuICAgICAqIHJlY2VpdmUgaW5mb3JtYXRpb24gZnJvbSBleHRlcm5hbCBhcHBsaWNhdGlvbnMgdGhhdCBlbWJlZCBKaXRzaSBNZWV0LlxuICAgICAqIEl0IGFsc28gc2VuZHMgYSBtZXNzYWdlIHRvIHRoZSBleHRlcm5hbCBhcHBsaWNhdGlvbiB0aGF0IEFQSUNvbm5lY3RvclxuICAgICAqIGlzIGluaXRpYWxpemVkLlxuICAgICAqL1xuICAgIGluaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKVxuICAgICAgICB7XG4gICAgICAgICAgICB3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lcignbWVzc2FnZScsXG4gICAgICAgICAgICAgICAgcHJvY2Vzc01lc3NhZ2UsIGZhbHNlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHdpbmRvdy5hdHRhY2hFdmVudCgnb25tZXNzYWdlJywgcHJvY2Vzc01lc3NhZ2UpO1xuICAgICAgICB9XG4gICAgICAgIHNlbmRNZXNzYWdlKHt0eXBlOiBcInN5c3RlbVwiLCBsb2FkZWQ6IHRydWV9KTtcbiAgICAgICAgc2V0dXBMaXN0ZW5lcnMoKTtcbiAgICB9LFxuICAgIC8qKlxuICAgICAqIENoZWNrcyB3aGV0aGVyIHRoZSBldmVudCBpcyBlbmFibGVkIG90IG5vdC5cbiAgICAgKiBAcGFyYW0gbmFtZSB0aGUgbmFtZSBvZiB0aGUgZXZlbnQuXG4gICAgICogQHJldHVybnMgeyp9XG4gICAgICovXG4gICAgaXNFdmVudEVuYWJsZWQ6IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgIHJldHVybiBldmVudHNbbmFtZV07XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFNlbmRzIGV2ZW50IG9iamVjdCB0byB0aGUgZXh0ZXJuYWwgYXBwbGljYXRpb24gdGhhdCBoYXMgYmVlbiBzdWJzY3JpYmVkXG4gICAgICogZm9yIHRoYXQgZXZlbnQuXG4gICAgICogQHBhcmFtIG5hbWUgdGhlIG5hbWUgZXZlbnRcbiAgICAgKiBAcGFyYW0gb2JqZWN0IGRhdGEgYXNzb2NpYXRlZCB3aXRoIHRoZSBldmVudFxuICAgICAqL1xuICAgIHRyaWdnZXJFdmVudDogZnVuY3Rpb24gKG5hbWUsIG9iamVjdCkge1xuICAgICAgICBpZih0aGlzLmlzRW5hYmxlZCgpICYmIHRoaXMuaXNFdmVudEVuYWJsZWQobmFtZSkpXG4gICAgICAgICAgICBzZW5kTWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgdHlwZTogXCJldmVudFwiLCBhY3Rpb246IFwicmVzdWx0XCIsIGV2ZW50OiBuYW1lLCByZXN1bHQ6IG9iamVjdH0pO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIHRoZSBsaXN0ZW5lcnMuXG4gICAgICovXG4gICAgZGlzcG9zZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZih3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lcilcbiAgICAgICAge1xuICAgICAgICAgICAgd2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJtZXNzYWdlXCIsXG4gICAgICAgICAgICAgICAgcHJvY2Vzc01lc3NhZ2UsIGZhbHNlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHdpbmRvdy5kZXRhY2hFdmVudCgnb25tZXNzYWdlJywgcHJvY2Vzc01lc3NhZ2UpO1xuICAgICAgICB9XG5cbiAgICB9XG5cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBUEk7IiwiLyogZ2xvYmFsIFN0cm9waGUsIHVwZGF0ZUxhcmdlVmlkZW8sIGZvY3VzZWRWaWRlb1NyYyovXG5cbi8vIGNhY2hlIGRhdGFjaGFubmVscyB0byBhdm9pZCBnYXJiYWdlIGNvbGxlY3Rpb25cbi8vIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3AvY2hyb21pdW0vaXNzdWVzL2RldGFpbD9pZD00MDU1NDVcbnZhciBSVENFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvUlRDRXZlbnRzXCIpO1xuXG52YXIgX2RhdGFDaGFubmVscyA9IFtdO1xudmFyIGV2ZW50RW1pdHRlciA9IG51bGw7XG5cblxuXG5cbnZhciBEYXRhQ2hhbm5lbHMgPVxue1xuXG4gICAgLyoqXG4gICAgICogQ2FsbGJhY2sgdHJpZ2dlcmVkIGJ5IFBlZXJDb25uZWN0aW9uIHdoZW4gbmV3IGRhdGEgY2hhbm5lbCBpcyBvcGVuZWRcbiAgICAgKiBvbiB0aGUgYnJpZGdlLlxuICAgICAqIEBwYXJhbSBldmVudCB0aGUgZXZlbnQgaW5mbyBvYmplY3QuXG4gICAgICovXG5cbiAgICBvbkRhdGFDaGFubmVsOiBmdW5jdGlvbiAoZXZlbnQpXG4gICAge1xuICAgICAgICB2YXIgZGF0YUNoYW5uZWwgPSBldmVudC5jaGFubmVsO1xuXG4gICAgICAgIGRhdGFDaGFubmVsLm9ub3BlbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkRhdGEgY2hhbm5lbCBvcGVuZWQgYnkgdGhlIFZpZGVvYnJpZGdlIVwiLCBkYXRhQ2hhbm5lbCk7XG5cbiAgICAgICAgICAgIC8vIENvZGUgc2FtcGxlIGZvciBzZW5kaW5nIHN0cmluZyBhbmQvb3IgYmluYXJ5IGRhdGFcbiAgICAgICAgICAgIC8vIFNlbmRzIFN0cmluZyBtZXNzYWdlIHRvIHRoZSBicmlkZ2VcbiAgICAgICAgICAgIC8vZGF0YUNoYW5uZWwuc2VuZChcIkhlbGxvIGJyaWRnZSFcIik7XG4gICAgICAgICAgICAvLyBTZW5kcyAxMiBieXRlcyBiaW5hcnkgbWVzc2FnZSB0byB0aGUgYnJpZGdlXG4gICAgICAgICAgICAvL2RhdGFDaGFubmVsLnNlbmQobmV3IEFycmF5QnVmZmVyKDEyKSk7XG5cbiAgICAgICAgICAgIC8vIHdoZW4gdGhlIGRhdGEgY2hhbm5lbCBiZWNvbWVzIGF2YWlsYWJsZSwgdGVsbCB0aGUgYnJpZGdlIGFib3V0IHZpZGVvXG4gICAgICAgICAgICAvLyBzZWxlY3Rpb25zIHNvIHRoYXQgaXQgY2FuIGRvIGFkYXB0aXZlIHNpbXVsY2FzdCxcbiAgICAgICAgICAgIC8vIHdlIHdhbnQgdGhlIG5vdGlmaWNhdGlvbiB0byB0cmlnZ2VyIGV2ZW4gaWYgdXNlckppZCBpcyB1bmRlZmluZWQsXG4gICAgICAgICAgICAvLyBvciBudWxsLlxuICAgICAgICAgICAgdmFyIHVzZXJKaWQgPSBBUFAuVUkuZ2V0TGFyZ2VWaWRlb1N0YXRlKCkudXNlckppZDtcbiAgICAgICAgICAgIC8vIHdlIHdhbnQgdGhlIG5vdGlmaWNhdGlvbiB0byB0cmlnZ2VyIGV2ZW4gaWYgdXNlckppZCBpcyB1bmRlZmluZWQsXG4gICAgICAgICAgICAvLyBvciBudWxsLlxuICAgICAgICAgICAgb25TZWxlY3RlZEVuZHBvaW50Q2hhbmdlZCh1c2VySmlkKTtcbiAgICAgICAgfTtcblxuICAgICAgICBkYXRhQ2hhbm5lbC5vbmVycm9yID0gZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKFwiRGF0YSBDaGFubmVsIEVycm9yOlwiLCBlcnJvciwgZGF0YUNoYW5uZWwpO1xuICAgICAgICB9O1xuXG4gICAgICAgIGRhdGFDaGFubmVsLm9ubWVzc2FnZSA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgICAgdmFyIGRhdGEgPSBldmVudC5kYXRhO1xuICAgICAgICAgICAgLy8gSlNPTlxuICAgICAgICAgICAgdmFyIG9iajtcblxuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICBvYmogPSBKU09OLnBhcnNlKGRhdGEpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY2F0Y2ggKGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKFxuICAgICAgICAgICAgICAgICAgICBcIkZhaWxlZCB0byBwYXJzZSBkYXRhIGNoYW5uZWwgbWVzc2FnZSBhcyBKU09OOiBcIixcbiAgICAgICAgICAgICAgICAgICAgZGF0YSxcbiAgICAgICAgICAgICAgICAgICAgZGF0YUNoYW5uZWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKCgndW5kZWZpbmVkJyAhPT0gdHlwZW9mKG9iaikpICYmIChudWxsICE9PSBvYmopKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvbGlicmlDbGFzcyA9IG9iai5jb2xpYnJpQ2xhc3M7XG5cbiAgICAgICAgICAgICAgICBpZiAoXCJEb21pbmFudFNwZWFrZXJFbmRwb2ludENoYW5nZUV2ZW50XCIgPT09IGNvbGlicmlDbGFzcykge1xuICAgICAgICAgICAgICAgICAgICAvLyBFbmRwb2ludCBJRCBmcm9tIHRoZSBWaWRlb2JyaWRnZS5cbiAgICAgICAgICAgICAgICAgICAgdmFyIGRvbWluYW50U3BlYWtlckVuZHBvaW50ID0gb2JqLmRvbWluYW50U3BlYWtlckVuZHBvaW50O1xuXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiRGF0YSBjaGFubmVsIG5ldyBkb21pbmFudCBzcGVha2VyIGV2ZW50OiBcIixcbiAgICAgICAgICAgICAgICAgICAgICAgIGRvbWluYW50U3BlYWtlckVuZHBvaW50KTtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoUlRDRXZlbnRzLkRPTUlOQU5UU1BFQUtFUl9DSEFOR0VELCBkb21pbmFudFNwZWFrZXJFbmRwb2ludCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKFwiSW5MYXN0TkNoYW5nZUV2ZW50XCIgPT09IGNvbGlicmlDbGFzcylcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBvbGRWYWx1ZSA9IG9iai5vbGRWYWx1ZTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG5ld1ZhbHVlID0gb2JqLm5ld1ZhbHVlO1xuICAgICAgICAgICAgICAgICAgICAvLyBNYWtlIHN1cmUgdGhhdCBvbGRWYWx1ZSBhbmQgbmV3VmFsdWUgYXJlIG9mIHR5cGUgYm9vbGVhbi5cbiAgICAgICAgICAgICAgICAgICAgdmFyIHR5cGU7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCh0eXBlID0gdHlwZW9mIG9sZFZhbHVlKSAhPT0gJ2Jvb2xlYW4nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAodHlwZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbGRWYWx1ZSA9IChvbGRWYWx1ZSA9PSBcInRydWVcIik7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9sZFZhbHVlID0gbmV3IEJvb2xlYW4ob2xkVmFsdWUpLnZhbHVlT2YoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoKHR5cGUgPSB0eXBlb2YgbmV3VmFsdWUpICE9PSAnYm9vbGVhbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0eXBlID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5ld1ZhbHVlID0gKG5ld1ZhbHVlID09IFwidHJ1ZVwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbmV3VmFsdWUgPSBuZXcgQm9vbGVhbihuZXdWYWx1ZSkudmFsdWVPZigpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoUlRDRXZlbnRzLkxBU1ROX0NIQU5HRUQsIG9sZFZhbHVlLCBuZXdWYWx1ZSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKFwiTGFzdE5FbmRwb2ludHNDaGFuZ2VFdmVudFwiID09PSBjb2xpYnJpQ2xhc3MpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAvLyBUaGUgbmV3L2xhdGVzdCBsaXN0IG9mIGxhc3QtbiBlbmRwb2ludCBJRHMuXG4gICAgICAgICAgICAgICAgICAgIHZhciBsYXN0TkVuZHBvaW50cyA9IG9iai5sYXN0TkVuZHBvaW50cztcbiAgICAgICAgICAgICAgICAgICAgLy8gVGhlIGxpc3Qgb2YgZW5kcG9pbnQgSURzIHdoaWNoIGFyZSBlbnRlcmluZyB0aGUgbGlzdCBvZlxuICAgICAgICAgICAgICAgICAgICAvLyBsYXN0LW4gYXQgdGhpcyB0aW1lIGkuZS4gd2VyZSBub3QgaW4gdGhlIG9sZCBsaXN0IG9mIGxhc3QtblxuICAgICAgICAgICAgICAgICAgICAvLyBlbmRwb2ludCBJRHMuXG4gICAgICAgICAgICAgICAgICAgIHZhciBlbmRwb2ludHNFbnRlcmluZ0xhc3ROID0gb2JqLmVuZHBvaW50c0VudGVyaW5nTGFzdE47XG4gICAgICAgICAgICAgICAgICAgIHZhciBzdHJlYW0gPSBvYmouc3RyZWFtO1xuXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFxuICAgICAgICAgICAgICAgICAgICAgICAgXCJEYXRhIGNoYW5uZWwgbmV3IGxhc3QtbiBldmVudDogXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXN0TkVuZHBvaW50cywgZW5kcG9pbnRzRW50ZXJpbmdMYXN0Tiwgb2JqKTtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoUlRDRXZlbnRzLkxBU1ROX0VORFBPSU5UX0NIQU5HRUQsXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXN0TkVuZHBvaW50cywgZW5kcG9pbnRzRW50ZXJpbmdMYXN0Tiwgb2JqKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoXCJTaW11bGNhc3RMYXllcnNDaGFuZ2VkRXZlbnRcIiA9PT0gY29saWJyaUNsYXNzKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoUlRDRXZlbnRzLlNJTVVMQ0FTVF9MQVlFUl9DSEFOR0VELFxuICAgICAgICAgICAgICAgICAgICAgICAgb2JqLmVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSBpZiAoXCJTaW11bGNhc3RMYXllcnNDaGFuZ2luZ0V2ZW50XCIgPT09IGNvbGlicmlDbGFzcylcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFJUQ0V2ZW50cy5TSU1VTENBU1RfTEFZRVJfQ0hBTkdJTkcsXG4gICAgICAgICAgICAgICAgICAgICAgICBvYmouZW5kcG9pbnRTaW11bGNhc3RMYXllcnMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChcIlN0YXJ0U2ltdWxjYXN0TGF5ZXJFdmVudFwiID09PSBjb2xpYnJpQ2xhc3MpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChSVENFdmVudHMuU0lNVUxDQVNUX1NUQVJULCBvYmouc2ltdWxjYXN0TGF5ZXIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChcIlN0b3BTaW11bGNhc3RMYXllckV2ZW50XCIgPT09IGNvbGlicmlDbGFzcylcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFJUQ0V2ZW50cy5TSU1VTENBU1RfU1RPUCwgb2JqLnNpbXVsY2FzdExheWVyKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5kZWJ1ZyhcIkRhdGEgY2hhbm5lbCBKU09OLWZvcm1hdHRlZCBtZXNzYWdlOiBcIiwgb2JqKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgZGF0YUNoYW5uZWwub25jbG9zZSA9IGZ1bmN0aW9uICgpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIlRoZSBEYXRhIENoYW5uZWwgY2xvc2VkXCIsIGRhdGFDaGFubmVsKTtcbiAgICAgICAgICAgIHZhciBpZHggPSBfZGF0YUNoYW5uZWxzLmluZGV4T2YoZGF0YUNoYW5uZWwpO1xuICAgICAgICAgICAgaWYgKGlkeCA+IC0xKVxuICAgICAgICAgICAgICAgIF9kYXRhQ2hhbm5lbHMgPSBfZGF0YUNoYW5uZWxzLnNwbGljZShpZHgsIDEpO1xuICAgICAgICB9O1xuICAgICAgICBfZGF0YUNoYW5uZWxzLnB1c2goZGF0YUNoYW5uZWwpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBCaW5kcyBcIm9uZGF0YWNoYW5uZWxcIiBldmVudCBsaXN0ZW5lciB0byBnaXZlbiBQZWVyQ29ubmVjdGlvbiBpbnN0YW5jZS5cbiAgICAgKiBAcGFyYW0gcGVlckNvbm5lY3Rpb24gV2ViUlRDIHBlZXIgY29ubmVjdGlvbiBpbnN0YW5jZS5cbiAgICAgKi9cbiAgICBpbml0OiBmdW5jdGlvbiAocGVlckNvbm5lY3Rpb24sIGVtaXR0ZXIpIHtcbiAgICAgICAgaWYoIWNvbmZpZy5vcGVuU2N0cClcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICBwZWVyQ29ubmVjdGlvbi5vbmRhdGFjaGFubmVsID0gdGhpcy5vbkRhdGFDaGFubmVsO1xuICAgICAgICBldmVudEVtaXR0ZXIgPSBlbWl0dGVyO1xuXG4gICAgICAgIC8vIFNhbXBsZSBjb2RlIGZvciBvcGVuaW5nIG5ldyBkYXRhIGNoYW5uZWwgZnJvbSBKaXRzaSBNZWV0IHRvIHRoZSBicmlkZ2UuXG4gICAgICAgIC8vIEFsdGhvdWdoIGl0J3Mgbm90IGEgcmVxdWlyZW1lbnQgdG8gb3BlbiBzZXBhcmF0ZSBjaGFubmVscyBmcm9tIGJvdGggYnJpZGdlXG4gICAgICAgIC8vIGFuZCBwZWVyIGFzIHNpbmdsZSBjaGFubmVsIGNhbiBiZSB1c2VkIGZvciBzZW5kaW5nIGFuZCByZWNlaXZpbmcgZGF0YS5cbiAgICAgICAgLy8gU28gZWl0aGVyIGNoYW5uZWwgb3BlbmVkIGJ5IHRoZSBicmlkZ2Ugb3IgdGhlIG9uZSBvcGVuZWQgaGVyZSBpcyBlbm91Z2hcbiAgICAgICAgLy8gZm9yIGNvbW11bmljYXRpb24gd2l0aCB0aGUgYnJpZGdlLlxuICAgICAgICAvKnZhciBkYXRhQ2hhbm5lbE9wdGlvbnMgPVxuICAgICAgICAge1xuICAgICAgICAgcmVsaWFibGU6IHRydWVcbiAgICAgICAgIH07XG4gICAgICAgICB2YXIgZGF0YUNoYW5uZWxcbiAgICAgICAgID0gcGVlckNvbm5lY3Rpb24uY3JlYXRlRGF0YUNoYW5uZWwoXCJteUNoYW5uZWxcIiwgZGF0YUNoYW5uZWxPcHRpb25zKTtcblxuICAgICAgICAgLy8gQ2FuIGJlIHVzZWQgb25seSB3aGVuIGlzIGluIG9wZW4gc3RhdGVcbiAgICAgICAgIGRhdGFDaGFubmVsLm9ub3BlbiA9IGZ1bmN0aW9uICgpXG4gICAgICAgICB7XG4gICAgICAgICBkYXRhQ2hhbm5lbC5zZW5kKFwiTXkgY2hhbm5lbCAhISFcIik7XG4gICAgICAgICB9O1xuICAgICAgICAgZGF0YUNoYW5uZWwub25tZXNzYWdlID0gZnVuY3Rpb24gKGV2ZW50KVxuICAgICAgICAge1xuICAgICAgICAgdmFyIG1zZ0RhdGEgPSBldmVudC5kYXRhO1xuICAgICAgICAgY29uc29sZS5pbmZvKFwiR290IE15IERhdGEgQ2hhbm5lbCBNZXNzYWdlOlwiLCBtc2dEYXRhLCBkYXRhQ2hhbm5lbCk7XG4gICAgICAgICB9OyovXG4gICAgfSxcbiAgICBoYW5kbGVTZWxlY3RlZEVuZHBvaW50RXZlbnQ6IG9uU2VsZWN0ZWRFbmRwb2ludENoYW5nZWQsXG4gICAgaGFuZGxlUGlubmVkRW5kcG9pbnRFdmVudDogb25QaW5uZWRFbmRwb2ludENoYW5nZWRcblxufTtcblxuZnVuY3Rpb24gb25TZWxlY3RlZEVuZHBvaW50Q2hhbmdlZCh1c2VyUmVzb3VyY2UpXG57XG4gICAgY29uc29sZS5sb2coJ3NlbGVjdGVkIGVuZHBvaW50IGNoYW5nZWQ6ICcsIHVzZXJSZXNvdXJjZSk7XG4gICAgaWYgKF9kYXRhQ2hhbm5lbHMgJiYgX2RhdGFDaGFubmVscy5sZW5ndGggIT0gMClcbiAgICB7XG4gICAgICAgIF9kYXRhQ2hhbm5lbHMuc29tZShmdW5jdGlvbiAoZGF0YUNoYW5uZWwpIHtcbiAgICAgICAgICAgIGlmIChkYXRhQ2hhbm5lbC5yZWFkeVN0YXRlID09ICdvcGVuJylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBkYXRhQ2hhbm5lbC5zZW5kKEpTT04uc3RyaW5naWZ5KHtcbiAgICAgICAgICAgICAgICAgICAgJ2NvbGlicmlDbGFzcyc6ICdTZWxlY3RlZEVuZHBvaW50Q2hhbmdlZEV2ZW50JyxcbiAgICAgICAgICAgICAgICAgICAgJ3NlbGVjdGVkRW5kcG9pbnQnOlxuICAgICAgICAgICAgICAgICAgICAgICAgKCF1c2VyUmVzb3VyY2UgfHwgdXNlclJlc291cmNlID09PSBudWxsKT9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBudWxsIDogdXNlclJlc291cmNlXG4gICAgICAgICAgICAgICAgfSkpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gb25QaW5uZWRFbmRwb2ludENoYW5nZWQodXNlclJlc291cmNlKVxue1xuICAgIGNvbnNvbGUubG9nKCdwaW5uZWQgZW5kcG9pbnQgY2hhbmdlZDogJywgdXNlclJlc291cmNlKTtcbiAgICBpZiAoX2RhdGFDaGFubmVscyAmJiBfZGF0YUNoYW5uZWxzLmxlbmd0aCAhPSAwKVxuICAgIHtcbiAgICAgICAgX2RhdGFDaGFubmVscy5zb21lKGZ1bmN0aW9uIChkYXRhQ2hhbm5lbCkge1xuICAgICAgICAgICAgaWYgKGRhdGFDaGFubmVsLnJlYWR5U3RhdGUgPT0gJ29wZW4nKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGRhdGFDaGFubmVsLnNlbmQoSlNPTi5zdHJpbmdpZnkoe1xuICAgICAgICAgICAgICAgICAgICAnY29saWJyaUNsYXNzJzogJ1Bpbm5lZEVuZHBvaW50Q2hhbmdlZEV2ZW50JyxcbiAgICAgICAgICAgICAgICAgICAgJ3Bpbm5lZEVuZHBvaW50JzpcbiAgICAgICAgICAgICAgICAgICAgICAgICghdXNlclJlc291cmNlIHx8IHVzZXJSZXNvdXJjZSA9PSBudWxsKT9cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBudWxsIDogdXNlclJlc291cmNlXG4gICAgICAgICAgICAgICAgfSkpO1xuXG4gICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBEYXRhQ2hhbm5lbHM7XG5cbiIsInZhciBTdHJlYW1FdmVudFR5cGVzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvUlRDL1N0cmVhbUV2ZW50VHlwZXMuanNcIik7XG5cbmZ1bmN0aW9uIExvY2FsU3RyZWFtKHN0cmVhbSwgdHlwZSwgZXZlbnRFbWl0dGVyLCB2aWRlb1R5cGUpXG57XG4gICAgdGhpcy5zdHJlYW0gPSBzdHJlYW07XG4gICAgdGhpcy5ldmVudEVtaXR0ZXIgPSBldmVudEVtaXR0ZXI7XG4gICAgdGhpcy50eXBlID0gdHlwZTtcbiAgICB0aGlzLnZpZGVvVHlwZSA9IHZpZGVvVHlwZTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgaWYodHlwZSA9PSBcImF1ZGlvXCIpXG4gICAge1xuICAgICAgICB0aGlzLmdldFRyYWNrcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZWxmLnN0cmVhbS5nZXRBdWRpb1RyYWNrcygpO1xuICAgICAgICB9O1xuICAgIH1cbiAgICBlbHNlXG4gICAge1xuICAgICAgICB0aGlzLmdldFRyYWNrcyA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHJldHVybiBzZWxmLnN0cmVhbS5nZXRWaWRlb1RyYWNrcygpO1xuICAgICAgICB9O1xuICAgIH1cblxuICAgIHRoaXMuc3RyZWFtLm9uZW5kZWQgPSBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICBzZWxmLnN0cmVhbUVuZGVkKCk7XG4gICAgfTtcbn1cblxuTG9jYWxTdHJlYW0ucHJvdG90eXBlLnN0cmVhbUVuZGVkID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMuZXZlbnRFbWl0dGVyLmVtaXQoU3RyZWFtRXZlbnRUeXBlcy5FVkVOVF9UWVBFX0xPQ0FMX0VOREVELCB0aGlzKTtcbn1cblxuTG9jYWxTdHJlYW0ucHJvdG90eXBlLmdldE9yaWdpbmFsU3RyZWFtID0gZnVuY3Rpb24oKVxue1xuICAgIHJldHVybiB0aGlzLnN0cmVhbTtcbn1cblxuTG9jYWxTdHJlYW0ucHJvdG90eXBlLmlzQXVkaW9TdHJlYW0gPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICh0aGlzLnN0cmVhbS5nZXRBdWRpb1RyYWNrcygpICYmIHRoaXMuc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCkubGVuZ3RoID4gMCk7XG59O1xuXG5Mb2NhbFN0cmVhbS5wcm90b3R5cGUubXV0ZSA9IGZ1bmN0aW9uKClcbntcbiAgICB2YXIgaXNtdXRlZCA9IGZhbHNlO1xuICAgIHZhciB0cmFja3MgPSB0aGlzLmdldFRyYWNrcygpO1xuXG4gICAgZm9yICh2YXIgaWR4ID0gMDsgaWR4IDwgdHJhY2tzLmxlbmd0aDsgaWR4KyspIHtcbiAgICAgICAgaXNtdXRlZCA9ICF0cmFja3NbaWR4XS5lbmFibGVkO1xuICAgICAgICB0cmFja3NbaWR4XS5lbmFibGVkID0gaXNtdXRlZDtcbiAgICB9XG4gICAgcmV0dXJuIGlzbXV0ZWQ7XG59O1xuXG5Mb2NhbFN0cmVhbS5wcm90b3R5cGUuc2V0TXV0ZSA9IGZ1bmN0aW9uKG11dGUpXG57XG4gICAgdmFyIHRyYWNrcyA9IHRoaXMuZ2V0VHJhY2tzKCk7XG5cbiAgICBmb3IgKHZhciBpZHggPSAwOyBpZHggPCB0cmFja3MubGVuZ3RoOyBpZHgrKykge1xuICAgICAgICB0cmFja3NbaWR4XS5lbmFibGVkID0gbXV0ZTtcbiAgICB9XG59O1xuXG5Mb2NhbFN0cmVhbS5wcm90b3R5cGUuaXNNdXRlZCA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgdHJhY2tzID0gW107XG4gICAgaWYodGhpcy50eXBlID09IFwiYXVkaW9cIilcbiAgICB7XG4gICAgICAgIHRyYWNrcyA9IHRoaXMuc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCk7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIHRyYWNrcyA9IHRoaXMuc3RyZWFtLmdldFZpZGVvVHJhY2tzKCk7XG4gICAgfVxuICAgIGZvciAodmFyIGlkeCA9IDA7IGlkeCA8IHRyYWNrcy5sZW5ndGg7IGlkeCsrKSB7XG4gICAgICAgIGlmKHRyYWNrc1tpZHhdLmVuYWJsZWQpXG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIHJldHVybiB0cnVlO1xufVxuXG5Mb2NhbFN0cmVhbS5wcm90b3R5cGUuZ2V0SWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHRoaXMuc3RyZWFtLmdldFRyYWNrcygpWzBdLmlkO1xufVxuXG5cblxubW9kdWxlLmV4cG9ydHMgPSBMb2NhbFN0cmVhbTtcbiIsIi8vLy9UaGVzZSBsaW5lcyBzaG91bGQgYmUgdW5jb21tZW50ZWQgd2hlbiByZXF1aXJlIHdvcmtzIGluIGFwcC5qc1xudmFyIFJUQ0Jyb3dzZXJUeXBlID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvUlRDL1JUQ0Jyb3dzZXJUeXBlLmpzXCIpO1xudmFyIE1lZGlhU3RyZWFtVHlwZSA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9NZWRpYVN0cmVhbVR5cGVzXCIpO1xuXG4vKipcbiAqIENyZWF0ZXMgYSBNZWRpYVN0cmVhbSBvYmplY3QgZm9yIHRoZSBnaXZlbiBkYXRhLCBzZXNzaW9uIGlkIGFuZCBzc3JjLlxuICogSXQgaXMgYSB3cmFwcGVyIGNsYXNzIGZvciB0aGUgTWVkaWFTdHJlYW0uXG4gKlxuICogQHBhcmFtIGRhdGEgdGhlIGRhdGEgb2JqZWN0IGZyb20gd2hpY2ggd2Ugb2J0YWluIHRoZSBzdHJlYW0sXG4gKiB0aGUgcGVlcmppZCwgZXRjLlxuICogQHBhcmFtIHNpZCB0aGUgc2Vzc2lvbiBpZFxuICogQHBhcmFtIHNzcmMgdGhlIHNzcmMgY29ycmVzcG9uZGluZyB0byB0aGlzIE1lZGlhU3RyZWFtXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIE1lZGlhU3RyZWFtKGRhdGEsIHNpZCwgc3NyYywgYnJvd3Nlcikge1xuXG4gICAgLy8gWFhYKGdwKSB0byBtaW5pbWl6ZSBoZWFkYWNoZXMgaW4gdGhlIGZ1dHVyZSwgd2Ugc2hvdWxkIGJ1aWxkIG91clxuICAgIC8vIGFic3RyYWN0aW9ucyBhcm91bmQgdHJhY2tzIGFuZCBub3Qgc3RyZWFtcy4gT1JUQyBpcyB0cmFjayBiYXNlZCBBUEkuXG4gICAgLy8gTW96aWxsYSBleHBlY3RzIG0tbGluZXMgdG8gcmVwcmVzZW50IG1lZGlhIHRyYWNrcy5cbiAgICAvL1xuICAgIC8vIFByYWN0aWNhbGx5LCB3aGF0IEknbSBzYXlpbmcgaXMgdGhhdCB3ZSBzaG91bGQgaGF2ZSBhIE1lZGlhVHJhY2sgY2xhc3NcbiAgICAvLyBhbmQgbm90IGEgTWVkaWFTdHJlYW0gY2xhc3MuXG4gICAgLy9cbiAgICAvLyBBbHNvLCB3ZSBzaG91bGQgYmUgYWJsZSB0byBhc3NvY2lhdGUgbXVsdGlwbGUgU1NSQ3Mgd2l0aCBhIE1lZGlhVHJhY2sgYXNcbiAgICAvLyBhIHRyYWNrIG1pZ2h0IGhhdmUgYW4gYXNzb2NpYXRlZCBSVFggYW5kIEZFQyBzb3VyY2VzLlxuXG4gICAgdGhpcy5zaWQgPSBzaWQ7XG4gICAgdGhpcy5zdHJlYW0gPSBkYXRhLnN0cmVhbTtcbiAgICB0aGlzLnBlZXJqaWQgPSBkYXRhLnBlZXJqaWQ7XG4gICAgdGhpcy5zc3JjID0gc3NyYztcbiAgICB0aGlzLnR5cGUgPSAodGhpcy5zdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGggPiAwKT9cbiAgICAgICAgTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEUgOiBNZWRpYVN0cmVhbVR5cGUuQVVESU9fVFlQRTtcbiAgICB0aGlzLnZpZGVvVHlwZSA9IG51bGw7XG4gICAgdGhpcy5tdXRlZCA9IGZhbHNlO1xuICAgIGlmKGJyb3dzZXIgPT0gUlRDQnJvd3NlclR5cGUuUlRDX0JST1dTRVJfRklSRUZPWClcbiAgICB7XG4gICAgICAgIGlmICghdGhpcy5nZXRWaWRlb1RyYWNrcylcbiAgICAgICAgICAgIHRoaXMuZ2V0VmlkZW9UcmFja3MgPSBmdW5jdGlvbiAoKSB7IHJldHVybiBbXTsgfTtcbiAgICAgICAgaWYgKCF0aGlzLmdldEF1ZGlvVHJhY2tzKVxuICAgICAgICAgICAgdGhpcy5nZXRBdWRpb1RyYWNrcyA9IGZ1bmN0aW9uICgpIHsgcmV0dXJuIFtdOyB9O1xuICAgIH1cbn1cblxuXG5NZWRpYVN0cmVhbS5wcm90b3R5cGUuZ2V0T3JpZ2luYWxTdHJlYW0gPSBmdW5jdGlvbigpXG57XG4gICAgcmV0dXJuIHRoaXMuc3RyZWFtO1xufVxuXG5NZWRpYVN0cmVhbS5wcm90b3R5cGUuc2V0TXV0ZSA9IGZ1bmN0aW9uICh2YWx1ZSlcbntcbiAgICB0aGlzLnN0cmVhbS5tdXRlZCA9IHZhbHVlO1xuICAgIHRoaXMubXV0ZWQgPSB2YWx1ZTtcbn1cblxuXG5tb2R1bGUuZXhwb3J0cyA9IE1lZGlhU3RyZWFtO1xuIiwidmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoXCJldmVudHNcIik7XG52YXIgUlRDVXRpbHMgPSByZXF1aXJlKFwiLi9SVENVdGlscy5qc1wiKTtcbnZhciBMb2NhbFN0cmVhbSA9IHJlcXVpcmUoXCIuL0xvY2FsU3RyZWFtLmpzXCIpO1xudmFyIERhdGFDaGFubmVscyA9IHJlcXVpcmUoXCIuL0RhdGFDaGFubmVsc1wiKTtcbnZhciBNZWRpYVN0cmVhbSA9IHJlcXVpcmUoXCIuL01lZGlhU3RyZWFtLmpzXCIpO1xudmFyIERlc2t0b3BTaGFyaW5nRXZlbnRUeXBlc1xuICAgID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvZGVza3RvcHNoYXJpbmcvRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzXCIpO1xudmFyIE1lZGlhU3RyZWFtVHlwZSA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9NZWRpYVN0cmVhbVR5cGVzXCIpO1xudmFyIFN0cmVhbUV2ZW50VHlwZXMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvU3RyZWFtRXZlbnRUeXBlcy5qc1wiKTtcbnZhciBYTVBQRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UveG1wcC9YTVBQRXZlbnRzXCIpO1xudmFyIFVJRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvVUkvVUlFdmVudHNcIik7XG5cbnZhciBldmVudEVtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG5cbnZhciBSVEMgPSB7XG4gICAgcnRjVXRpbHM6IG51bGwsXG4gICAgbG9jYWxTdHJlYW1zOiBbXSxcbiAgICByZW1vdGVTdHJlYW1zOiB7fSxcbiAgICBsb2NhbEF1ZGlvOiBudWxsLFxuICAgIGxvY2FsVmlkZW86IG51bGwsXG4gICAgYWRkU3RyZWFtTGlzdGVuZXI6IGZ1bmN0aW9uIChsaXN0ZW5lciwgZXZlbnRUeXBlKSB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5vbihldmVudFR5cGUsIGxpc3RlbmVyKTtcbiAgICB9LFxuICAgIGFkZExpc3RlbmVyOiBmdW5jdGlvbiAodHlwZSwgbGlzdGVuZXIpIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLm9uKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9LFxuICAgIHJlbW92ZVN0cmVhbUxpc3RlbmVyOiBmdW5jdGlvbiAobGlzdGVuZXIsIGV2ZW50VHlwZSkge1xuICAgICAgICBpZighKGV2ZW50VHlwZSBpbnN0YW5jZW9mIFN0cmVhbUV2ZW50VHlwZXMpKVxuICAgICAgICAgICAgdGhyb3cgXCJJbGxlZ2FsIGFyZ3VtZW50XCI7XG5cbiAgICAgICAgZXZlbnRFbWl0dGVyLnJlbW92ZUxpc3RlbmVyKGV2ZW50VHlwZSwgbGlzdGVuZXIpO1xuICAgIH0sXG4gICAgY3JlYXRlTG9jYWxTdHJlYW06IGZ1bmN0aW9uIChzdHJlYW0sIHR5cGUsIGNoYW5nZSkge1xuXG4gICAgICAgIHZhciBsb2NhbFN0cmVhbSA9ICBuZXcgTG9jYWxTdHJlYW0oc3RyZWFtLCB0eXBlLCBldmVudEVtaXR0ZXIpO1xuICAgICAgICAvL2luIGZpcmVmb3ggd2UgaGF2ZSBvbmx5IG9uZSBzdHJlYW0gb2JqZWN0XG4gICAgICAgIGlmKHRoaXMubG9jYWxTdHJlYW1zLmxlbmd0aCA9PSAwIHx8XG4gICAgICAgICAgICB0aGlzLmxvY2FsU3RyZWFtc1swXS5nZXRPcmlnaW5hbFN0cmVhbSgpICE9IHN0cmVhbSlcbiAgICAgICAgICAgIHRoaXMubG9jYWxTdHJlYW1zLnB1c2gobG9jYWxTdHJlYW0pO1xuICAgICAgICBpZih0eXBlID09IFwiYXVkaW9cIilcbiAgICAgICAge1xuICAgICAgICAgICAgdGhpcy5sb2NhbEF1ZGlvID0gbG9jYWxTdHJlYW07XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICB7XG4gICAgICAgICAgICB0aGlzLmxvY2FsVmlkZW8gPSBsb2NhbFN0cmVhbTtcbiAgICAgICAgfVxuICAgICAgICB2YXIgZXZlbnRUeXBlID0gU3RyZWFtRXZlbnRUeXBlcy5FVkVOVF9UWVBFX0xPQ0FMX0NSRUFURUQ7XG4gICAgICAgIGlmKGNoYW5nZSlcbiAgICAgICAgICAgIGV2ZW50VHlwZSA9IFN0cmVhbUV2ZW50VHlwZXMuRVZFTlRfVFlQRV9MT0NBTF9DSEFOR0VEO1xuXG4gICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KGV2ZW50VHlwZSwgbG9jYWxTdHJlYW0pO1xuICAgICAgICByZXR1cm4gbG9jYWxTdHJlYW07XG4gICAgfSxcbiAgICByZW1vdmVMb2NhbFN0cmVhbTogZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICBmb3IodmFyIGkgPSAwOyBpIDwgdGhpcy5sb2NhbFN0cmVhbXMubGVuZ3RoOyBpKyspXG4gICAgICAgIHtcbiAgICAgICAgICAgIGlmKHRoaXMubG9jYWxTdHJlYW1zW2ldLmdldE9yaWdpbmFsU3RyZWFtKCkgPT09IHN0cmVhbSkge1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLmxvY2FsU3RyZWFtc1tpXTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGNyZWF0ZVJlbW90ZVN0cmVhbTogZnVuY3Rpb24gKGRhdGEsIHNpZCwgdGhlc3NyYykge1xuICAgICAgICB2YXIgcmVtb3RlU3RyZWFtID0gbmV3IE1lZGlhU3RyZWFtKGRhdGEsIHNpZCwgdGhlc3NyYyxcbiAgICAgICAgICAgIHRoaXMuZ2V0QnJvd3NlclR5cGUoKSk7XG4gICAgICAgIHZhciBqaWQgPSBkYXRhLnBlZXJqaWQgfHwgQVBQLnhtcHAubXlKaWQoKTtcbiAgICAgICAgaWYoIXRoaXMucmVtb3RlU3RyZWFtc1tqaWRdKSB7XG4gICAgICAgICAgICB0aGlzLnJlbW90ZVN0cmVhbXNbamlkXSA9IHt9O1xuICAgICAgICB9XG4gICAgICAgIHRoaXMucmVtb3RlU3RyZWFtc1tqaWRdW3JlbW90ZVN0cmVhbS50eXBlXT0gcmVtb3RlU3RyZWFtO1xuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChTdHJlYW1FdmVudFR5cGVzLkVWRU5UX1RZUEVfUkVNT1RFX0NSRUFURUQsIHJlbW90ZVN0cmVhbSk7XG4gICAgICAgIGNvbnNvbGUuZGVidWcoXCJBREQgcmVtb3RlIHN0cmVhbSBcIiwgcmVtb3RlU3RyZWFtLnR5cGUsIFwiIFwiLCBqaWQsIFwiIFwiLCB0aGVzc3JjKTtcbiAgICAgICAgcmV0dXJuIHJlbW90ZVN0cmVhbTtcbiAgICB9LFxuICAgIGdldEJyb3dzZXJUeXBlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ0Y1V0aWxzLmJyb3dzZXI7XG4gICAgfSxcbiAgICBnZXRQQ0NvbnN0cmFpbnRzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ0Y1V0aWxzLnBjX2NvbnN0cmFpbnRzO1xuICAgIH0sXG4gICAgZ2V0VXNlck1lZGlhV2l0aENvbnN0cmFpbnRzOmZ1bmN0aW9uKHVtLCBzdWNjZXNzX2NhbGxiYWNrLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWlsdXJlX2NhbGxiYWNrLCByZXNvbHV0aW9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBiYW5kd2lkdGgsIGZwcywgZGVza3RvcFN0cmVhbSlcbiAgICB7XG4gICAgICAgIHJldHVybiB0aGlzLnJ0Y1V0aWxzLmdldFVzZXJNZWRpYVdpdGhDb25zdHJhaW50cyh1bSwgc3VjY2Vzc19jYWxsYmFjayxcbiAgICAgICAgICAgIGZhaWx1cmVfY2FsbGJhY2ssIHJlc29sdXRpb24sIGJhbmR3aWR0aCwgZnBzLCBkZXNrdG9wU3RyZWFtKTtcbiAgICB9LFxuICAgIGF0dGFjaE1lZGlhU3RyZWFtOiAgZnVuY3Rpb24gKGVsZW1lbnQsIHN0cmVhbSkge1xuICAgICAgICB0aGlzLnJ0Y1V0aWxzLmF0dGFjaE1lZGlhU3RyZWFtKGVsZW1lbnQsIHN0cmVhbSk7XG4gICAgfSxcbiAgICBnZXRTdHJlYW1JRDogIGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgcmV0dXJuIHRoaXMucnRjVXRpbHMuZ2V0U3RyZWFtSUQoc3RyZWFtKTtcbiAgICB9LFxuICAgIGdldFZpZGVvU3JjOiBmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICByZXR1cm4gdGhpcy5ydGNVdGlscy5nZXRWaWRlb1NyYyhlbGVtZW50KTtcbiAgICB9LFxuICAgIHNldFZpZGVvU3JjOiBmdW5jdGlvbiAoZWxlbWVudCwgc3JjKSB7XG4gICAgICAgIHRoaXMucnRjVXRpbHMuc2V0VmlkZW9TcmMoZWxlbWVudCwgc3JjKTtcbiAgICB9LFxuICAgIGRpc3Bvc2U6IGZ1bmN0aW9uKCkge1xuICAgICAgICBpZiAodGhpcy5ydGNVdGlscykge1xuICAgICAgICAgICAgdGhpcy5ydGNVdGlscyA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHN0b3A6ICBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHRoaXMuZGlzcG9zZSgpO1xuICAgIH0sXG4gICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICBBUFAuZGVza3RvcHNoYXJpbmcuYWRkTGlzdGVuZXIoXG4gICAgICAgICAgICBmdW5jdGlvbiAoc3RyZWFtLCBpc1VzaW5nU2NyZWVuU3RyZWFtLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHNlbGYuY2hhbmdlTG9jYWxWaWRlbyhzdHJlYW0sIGlzVXNpbmdTY3JlZW5TdHJlYW0sIGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0sIERlc2t0b3BTaGFyaW5nRXZlbnRUeXBlcy5ORVdfU1RSRUFNX0NSRUFURUQpO1xuICAgICAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLkNIQU5HRURfU1RSRUFNUywgZnVuY3Rpb24gKGppZCwgY2hhbmdlZFN0cmVhbXMpIHtcbiAgICAgICAgICAgIGZvcih2YXIgaSA9IDA7IGkgPCBjaGFuZ2VkU3RyZWFtcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHZhciB0eXBlID0gY2hhbmdlZFN0cmVhbXNbaV0udHlwZTtcbiAgICAgICAgICAgICAgICBpZiAodHlwZSAhPSBcImF1ZGlvXCIpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBlZXJTdHJlYW1zID0gc2VsZi5yZW1vdGVTdHJlYW1zW2ppZF07XG4gICAgICAgICAgICAgICAgICAgIGlmKCFwZWVyU3RyZWFtcylcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdmlkZW9TdHJlYW0gPSBwZWVyU3RyZWFtc1tNZWRpYVN0cmVhbVR5cGUuVklERU9fVFlQRV07XG4gICAgICAgICAgICAgICAgICAgIGlmKCF2aWRlb1N0cmVhbSlcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgICAgICAgICB2aWRlb1N0cmVhbS52aWRlb1R5cGUgPSBjaGFuZ2VkU3RyZWFtc1tpXS50eXBlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuQ0FMTF9JTkNPTUlORywgZnVuY3Rpb24oZXZlbnQpIHtcbiAgICAgICAgICAgIERhdGFDaGFubmVscy5pbml0KGV2ZW50LnBlZXJjb25uZWN0aW9uLCBldmVudEVtaXR0ZXIpO1xuICAgICAgICB9KTtcbiAgICAgICAgQVBQLlVJLmFkZExpc3RlbmVyKFVJRXZlbnRzLlNFTEVDVEVEX0VORFBPSU5ULFxuICAgICAgICAgICAgRGF0YUNoYW5uZWxzLmhhbmRsZVNlbGVjdGVkRW5kcG9pbnRFdmVudCk7XG4gICAgICAgIEFQUC5VSS5hZGRMaXN0ZW5lcihVSUV2ZW50cy5QSU5ORURfRU5EUE9JTlQsXG4gICAgICAgICAgICBEYXRhQ2hhbm5lbHMuaGFuZGxlUGlubmVkRW5kcG9pbnRFdmVudCk7XG4gICAgICAgIHRoaXMucnRjVXRpbHMgPSBuZXcgUlRDVXRpbHModGhpcyk7XG4gICAgICAgIHRoaXMucnRjVXRpbHMub2J0YWluQXVkaW9BbmRWaWRlb1Blcm1pc3Npb25zKCk7XG4gICAgfSxcbiAgICBtdXRlUmVtb3RlVmlkZW9TdHJlYW06IGZ1bmN0aW9uIChqaWQsIHZhbHVlKSB7XG4gICAgICAgIHZhciBzdHJlYW07XG5cbiAgICAgICAgaWYodGhpcy5yZW1vdGVTdHJlYW1zW2ppZF0gJiZcbiAgICAgICAgICAgIHRoaXMucmVtb3RlU3RyZWFtc1tqaWRdW01lZGlhU3RyZWFtVHlwZS5WSURFT19UWVBFXSlcbiAgICAgICAge1xuICAgICAgICAgICAgc3RyZWFtID0gdGhpcy5yZW1vdGVTdHJlYW1zW2ppZF1bTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEVdO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYoIXN0cmVhbSlcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcblxuICAgICAgICBpZiAodmFsdWUgIT0gc3RyZWFtLm11dGVkKSB7XG4gICAgICAgICAgICBzdHJlYW0uc2V0TXV0ZSh2YWx1ZSk7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfSxcbiAgICBzd2l0Y2hWaWRlb1N0cmVhbXM6IGZ1bmN0aW9uIChuZXdfc3RyZWFtKSB7XG4gICAgICAgIHRoaXMubG9jYWxWaWRlby5zdHJlYW0gPSBuZXdfc3RyZWFtO1xuXG4gICAgICAgIHRoaXMubG9jYWxTdHJlYW1zID0gW107XG5cbiAgICAgICAgLy9pbiBmaXJlZm94IHdlIGhhdmUgb25seSBvbmUgc3RyZWFtIG9iamVjdFxuICAgICAgICBpZiAodGhpcy5sb2NhbEF1ZGlvLmdldE9yaWdpbmFsU3RyZWFtKCkgIT0gbmV3X3N0cmVhbSlcbiAgICAgICAgICAgIHRoaXMubG9jYWxTdHJlYW1zLnB1c2godGhpcy5sb2NhbEF1ZGlvKTtcbiAgICAgICAgdGhpcy5sb2NhbFN0cmVhbXMucHVzaCh0aGlzLmxvY2FsVmlkZW8pO1xuICAgIH0sXG4gICAgY2hhbmdlTG9jYWxWaWRlbzogZnVuY3Rpb24gKHN0cmVhbSwgaXNVc2luZ1NjcmVlblN0cmVhbSwgY2FsbGJhY2spIHtcbiAgICAgICAgdmFyIG9sZFN0cmVhbSA9IHRoaXMubG9jYWxWaWRlby5nZXRPcmlnaW5hbFN0cmVhbSgpO1xuICAgICAgICB2YXIgdHlwZSA9IChpc1VzaW5nU2NyZWVuU3RyZWFtPyBcInNjcmVlblwiIDogXCJ2aWRlb1wiKTtcbiAgICAgICAgdGhpcy5sb2NhbFZpZGVvID0gdGhpcy5jcmVhdGVMb2NhbFN0cmVhbShzdHJlYW0sIFwidmlkZW9cIiwgdHJ1ZSwgdHlwZSk7XG4gICAgICAgIC8vIFN0b3AgdGhlIHN0cmVhbSB0byB0cmlnZ2VyIG9uZW5kZWQgZXZlbnQgZm9yIG9sZCBzdHJlYW1cbiAgICAgICAgb2xkU3RyZWFtLnN0b3AoKTtcbiAgICAgICAgQVBQLnhtcHAuc3dpdGNoU3RyZWFtcyhzdHJlYW0sIG9sZFN0cmVhbSxjYWxsYmFjayk7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgdmlkZW8gaWRlbnRpZmllZCBieSBnaXZlbiBzcmMgaXMgZGVza3RvcCBzdHJlYW0uXG4gICAgICogQHBhcmFtIHZpZGVvU3JjIGVnLlxuICAgICAqIGJsb2I6aHR0cHMlM0EvL3Bhd2VsLmppdHNpLm5ldC85YTQ2ZTBiZC0xMzFlLTRkMTgtOWMxNC1hOTI2NGU4ZGIzOTVcbiAgICAgKiBAcmV0dXJucyB7Ym9vbGVhbn1cbiAgICAgKi9cbiAgICBpc1ZpZGVvU3JjRGVza3RvcDogZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBpZighamlkKVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB2YXIgaXNEZXNrdG9wID0gZmFsc2U7XG4gICAgICAgIHZhciBzdHJlYW0gPSBudWxsO1xuICAgICAgICBpZiAoQVBQLnhtcHAubXlKaWQoKSAmJlxuICAgICAgICAgICAgQVBQLnhtcHAubXlSZXNvdXJjZSgpID09PSBqaWQpIHtcbiAgICAgICAgICAgIC8vIGxvY2FsIHZpZGVvXG4gICAgICAgICAgICBzdHJlYW0gPSB0aGlzLmxvY2FsVmlkZW87XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgcGVlclN0cmVhbXMgPSB0aGlzLnJlbW90ZVN0cmVhbXNbamlkXTtcbiAgICAgICAgICAgIGlmKCFwZWVyU3RyZWFtcylcbiAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICBzdHJlYW0gPSBwZWVyU3RyZWFtc1tNZWRpYVN0cmVhbVR5cGUuVklERU9fVFlQRV07XG4gICAgICAgIH1cblxuICAgICAgICBpZihzdHJlYW0pXG4gICAgICAgICAgICBpc0Rlc2t0b3AgPSAoc3RyZWFtLnZpZGVvVHlwZSA9PT0gXCJzY3JlZW5cIik7XG5cbiAgICAgICAgcmV0dXJuIGlzRGVza3RvcDtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJUQztcbiIsInZhciBSVENCcm93c2VyVHlwZSA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9SVENCcm93c2VyVHlwZS5qc1wiKTtcblxuZnVuY3Rpb24gc2V0UmVzb2x1dGlvbkNvbnN0cmFpbnRzKGNvbnN0cmFpbnRzLCByZXNvbHV0aW9uLCBpc0FuZHJvaWQpXG57XG4gICAgaWYgKHJlc29sdXRpb24gJiYgIWNvbnN0cmFpbnRzLnZpZGVvIHx8IGlzQW5kcm9pZCkge1xuICAgICAgICBjb25zdHJhaW50cy52aWRlbyA9IHsgbWFuZGF0b3J5OiB7fSwgb3B0aW9uYWw6IFtdIH07Ly8gc2FtZSBiZWhhdmlvdXIgYXMgdHJ1ZVxuICAgIH1cbiAgICAvLyBzZWUgaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTE0MzYzMSNjOSBmb3IgbGlzdCBvZiBzdXBwb3J0ZWQgcmVzb2x1dGlvbnNcbiAgICBzd2l0Y2ggKHJlc29sdXRpb24pIHtcbiAgICAgICAgLy8gMTY6OSBmaXJzdFxuICAgICAgICBjYXNlICcxMDgwJzpcbiAgICAgICAgY2FzZSAnZnVsbGhkJzpcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5XaWR0aCA9IDE5MjA7XG4gICAgICAgICAgICBjb25zdHJhaW50cy52aWRlby5tYW5kYXRvcnkubWluSGVpZ2h0ID0gMTA4MDtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICc3MjAnOlxuICAgICAgICBjYXNlICdoZCc6XG4gICAgICAgICAgICBjb25zdHJhaW50cy52aWRlby5tYW5kYXRvcnkubWluV2lkdGggPSAxMjgwO1xuICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbkhlaWdodCA9IDcyMDtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICczNjAnOlxuICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbldpZHRoID0gNjQwO1xuICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbkhlaWdodCA9IDM2MDtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICcxODAnOlxuICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbldpZHRoID0gMzIwO1xuICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbkhlaWdodCA9IDE4MDtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAvLyA0OjNcbiAgICAgICAgY2FzZSAnOTYwJzpcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5XaWR0aCA9IDk2MDtcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5IZWlnaHQgPSA3MjA7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnNjQwJzpcbiAgICAgICAgY2FzZSAndmdhJzpcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5XaWR0aCA9IDY0MDtcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5IZWlnaHQgPSA0ODA7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgY2FzZSAnMzIwJzpcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5XaWR0aCA9IDMyMDtcbiAgICAgICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5IZWlnaHQgPSAyNDA7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgIGlmIChpc0FuZHJvaWQpIHtcbiAgICAgICAgICAgICAgICBjb25zdHJhaW50cy52aWRlby5tYW5kYXRvcnkubWluV2lkdGggPSAzMjA7XG4gICAgICAgICAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbkhlaWdodCA9IDI0MDtcbiAgICAgICAgICAgICAgICBjb25zdHJhaW50cy52aWRlby5tYW5kYXRvcnkubWF4RnJhbWVSYXRlID0gMTU7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBicmVhaztcbiAgICB9XG4gICAgaWYgKGNvbnN0cmFpbnRzLnZpZGVvLm1hbmRhdG9yeS5taW5XaWR0aClcbiAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1heFdpZHRoID0gY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbldpZHRoO1xuICAgIGlmIChjb25zdHJhaW50cy52aWRlby5tYW5kYXRvcnkubWluSGVpZ2h0KVxuICAgICAgICBjb25zdHJhaW50cy52aWRlby5tYW5kYXRvcnkubWF4SGVpZ2h0ID0gY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbkhlaWdodDtcbn1cblxuXG5mdW5jdGlvbiBnZXRDb25zdHJhaW50cyh1bSwgcmVzb2x1dGlvbiwgYmFuZHdpZHRoLCBmcHMsIGRlc2t0b3BTdHJlYW0sIGlzQW5kcm9pZClcbntcbiAgICB2YXIgY29uc3RyYWludHMgPSB7YXVkaW86IGZhbHNlLCB2aWRlbzogZmFsc2V9O1xuXG4gICAgaWYgKHVtLmluZGV4T2YoJ3ZpZGVvJykgPj0gMCkge1xuICAgICAgICBjb25zdHJhaW50cy52aWRlbyA9IHsgbWFuZGF0b3J5OiB7fSwgb3B0aW9uYWw6IFtdIH07Ly8gc2FtZSBiZWhhdmlvdXIgYXMgdHJ1ZVxuICAgIH1cbiAgICBpZiAodW0uaW5kZXhPZignYXVkaW8nKSA+PSAwKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzLmF1ZGlvID0geyBtYW5kYXRvcnk6IHt9LCBvcHRpb25hbDogW119Oy8vIHNhbWUgYmVoYXZpb3VyIGFzIHRydWVcbiAgICB9XG4gICAgaWYgKHVtLmluZGV4T2YoJ3NjcmVlbicpID49IDApIHtcbiAgICAgICAgY29uc3RyYWludHMudmlkZW8gPSB7XG4gICAgICAgICAgICBtYW5kYXRvcnk6IHtcbiAgICAgICAgICAgICAgICBjaHJvbWVNZWRpYVNvdXJjZTogXCJzY3JlZW5cIixcbiAgICAgICAgICAgICAgICBnb29nTGVha3lCdWNrZXQ6IHRydWUsXG4gICAgICAgICAgICAgICAgbWF4V2lkdGg6IHdpbmRvdy5zY3JlZW4ud2lkdGgsXG4gICAgICAgICAgICAgICAgbWF4SGVpZ2h0OiB3aW5kb3cuc2NyZWVuLmhlaWdodCxcbiAgICAgICAgICAgICAgICBtYXhGcmFtZVJhdGU6IDNcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvcHRpb25hbDogW11cbiAgICAgICAgfTtcbiAgICB9XG4gICAgaWYgKHVtLmluZGV4T2YoJ2Rlc2t0b3AnKSA+PSAwKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvID0ge1xuICAgICAgICAgICAgbWFuZGF0b3J5OiB7XG4gICAgICAgICAgICAgICAgY2hyb21lTWVkaWFTb3VyY2U6IFwiZGVza3RvcFwiLFxuICAgICAgICAgICAgICAgIGNocm9tZU1lZGlhU291cmNlSWQ6IGRlc2t0b3BTdHJlYW0sXG4gICAgICAgICAgICAgICAgZ29vZ0xlYWt5QnVja2V0OiB0cnVlLFxuICAgICAgICAgICAgICAgIG1heFdpZHRoOiB3aW5kb3cuc2NyZWVuLndpZHRoLFxuICAgICAgICAgICAgICAgIG1heEhlaWdodDogd2luZG93LnNjcmVlbi5oZWlnaHQsXG4gICAgICAgICAgICAgICAgbWF4RnJhbWVSYXRlOiAzXG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgb3B0aW9uYWw6IFtdXG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgaWYgKGNvbnN0cmFpbnRzLmF1ZGlvKSB7XG4gICAgICAgIC8vIGlmIGl0IGlzIGdvb2QgZW5vdWdoIGZvciBoYW5nb3V0cy4uLlxuICAgICAgICBjb25zdHJhaW50cy5hdWRpby5vcHRpb25hbC5wdXNoKFxuICAgICAgICAgICAge2dvb2dFY2hvQ2FuY2VsbGF0aW9uOiB0cnVlfSxcbiAgICAgICAgICAgIHtnb29nQXV0b0dhaW5Db250cm9sOiB0cnVlfSxcbiAgICAgICAgICAgIHtnb29nTm9pc2VTdXByZXNzaW9uOiB0cnVlfSxcbiAgICAgICAgICAgIHtnb29nSGlnaHBhc3NGaWx0ZXI6IHRydWV9LFxuICAgICAgICAgICAge2dvb2dOb2lzZXN1cHByZXNzaW9uMjogdHJ1ZX0sXG4gICAgICAgICAgICB7Z29vZ0VjaG9DYW5jZWxsYXRpb24yOiB0cnVlfSxcbiAgICAgICAgICAgIHtnb29nQXV0b0dhaW5Db250cm9sMjogdHJ1ZX1cbiAgICAgICAgKTtcbiAgICB9XG4gICAgaWYgKGNvbnN0cmFpbnRzLnZpZGVvKSB7XG4gICAgICAgIGNvbnN0cmFpbnRzLnZpZGVvLm9wdGlvbmFsLnB1c2goXG4gICAgICAgICAgICB7Z29vZ05vaXNlUmVkdWN0aW9uOiBmYWxzZX0gLy8gY2hyb21lIDM3IHdvcmthcm91bmQgZm9yIGlzc3VlIDM4MDcsIHJlZW5hYmxlIGluIE0zOFxuICAgICAgICApO1xuICAgICAgICBpZiAodW0uaW5kZXhPZigndmlkZW8nKSA+PSAwKSB7XG4gICAgICAgICAgICBjb25zdHJhaW50cy52aWRlby5vcHRpb25hbC5wdXNoKFxuICAgICAgICAgICAgICAgIHtnb29nTGVha3lCdWNrZXQ6IHRydWV9XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHVtLmluZGV4T2YoJ3ZpZGVvJykgPj0gMCkge1xuICAgICAgICBzZXRSZXNvbHV0aW9uQ29uc3RyYWludHMoY29uc3RyYWludHMsIHJlc29sdXRpb24sIGlzQW5kcm9pZCk7XG4gICAgfVxuXG4gICAgaWYgKGJhbmR3aWR0aCkgeyAvLyBkb2Vzbid0IHdvcmsgY3VycmVudGx5LCBzZWUgd2VicnRjIGlzc3VlIDE4NDZcbiAgICAgICAgaWYgKCFjb25zdHJhaW50cy52aWRlbykgY29uc3RyYWludHMudmlkZW8gPSB7bWFuZGF0b3J5OiB7fSwgb3B0aW9uYWw6IFtdfTsvL3NhbWUgYmVoYXZpb3VyIGFzIHRydWVcbiAgICAgICAgY29uc3RyYWludHMudmlkZW8ub3B0aW9uYWwucHVzaCh7YmFuZHdpZHRoOiBiYW5kd2lkdGh9KTtcbiAgICB9XG4gICAgaWYgKGZwcykgeyAvLyBmb3Igc29tZSBjYW1lcmFzIGl0IG1pZ2h0IGJlIG5lY2Vzc2FyeSB0byByZXF1ZXN0IDMwZnBzXG4gICAgICAgIC8vIHNvIHRoZXkgY2hvb3NlIDMwZnBzIG1qcGcgb3ZlciAxMGZwcyB5dXkyXG4gICAgICAgIGlmICghY29uc3RyYWludHMudmlkZW8pIGNvbnN0cmFpbnRzLnZpZGVvID0ge21hbmRhdG9yeToge30sIG9wdGlvbmFsOiBbXX07Ly8gc2FtZSBiZWhhdmlvdXIgYXMgdHJ1ZTtcbiAgICAgICAgY29uc3RyYWludHMudmlkZW8ubWFuZGF0b3J5Lm1pbkZyYW1lUmF0ZSA9IGZwcztcbiAgICB9XG5cbiAgICByZXR1cm4gY29uc3RyYWludHM7XG59XG5cblxuZnVuY3Rpb24gUlRDVXRpbHMoUlRDU2VydmljZSlcbntcbiAgICB0aGlzLnNlcnZpY2UgPSBSVENTZXJ2aWNlO1xuICAgIGlmIChuYXZpZ2F0b3IubW96R2V0VXNlck1lZGlhKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdUaGlzIGFwcGVhcnMgdG8gYmUgRmlyZWZveCcpO1xuICAgICAgICB2YXIgdmVyc2lvbiA9IHBhcnNlSW50KG5hdmlnYXRvci51c2VyQWdlbnQubWF0Y2goL0ZpcmVmb3hcXC8oWzAtOV0rKVxcLi8pWzFdLCAxMCk7XG4gICAgICAgIGlmICh2ZXJzaW9uID49IDIyKSB7XG4gICAgICAgICAgICB0aGlzLnBlZXJjb25uZWN0aW9uID0gbW96UlRDUGVlckNvbm5lY3Rpb247XG4gICAgICAgICAgICB0aGlzLmJyb3dzZXIgPSBSVENCcm93c2VyVHlwZS5SVENfQlJPV1NFUl9GSVJFRk9YO1xuICAgICAgICAgICAgdGhpcy5nZXRVc2VyTWVkaWEgPSBuYXZpZ2F0b3IubW96R2V0VXNlck1lZGlhLmJpbmQobmF2aWdhdG9yKTtcbiAgICAgICAgICAgIHRoaXMucGNfY29uc3RyYWludHMgPSB7fTtcbiAgICAgICAgICAgIHRoaXMuYXR0YWNoTWVkaWFTdHJlYW0gPSAgZnVuY3Rpb24gKGVsZW1lbnQsIHN0cmVhbSkge1xuICAgICAgICAgICAgICAgIGVsZW1lbnRbMF0ubW96U3JjT2JqZWN0ID0gc3RyZWFtO1xuICAgICAgICAgICAgICAgIGVsZW1lbnRbMF0ucGxheSgpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHRoaXMuZ2V0U3RyZWFtSUQgPSAgZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICAgICAgICAgIHZhciB0cmFja3MgPSBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKTtcbiAgICAgICAgICAgICAgICBpZighdHJhY2tzIHx8IHRyYWNrcy5sZW5ndGggPT0gMClcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIHRyYWNrcyA9IHN0cmVhbS5nZXRBdWRpb1RyYWNrcygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICByZXR1cm4gdHJhY2tzWzBdLmlkLnJlcGxhY2UoL1tcXHssXFx9XS9nLFwiXCIpO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHRoaXMuZ2V0VmlkZW9TcmMgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICAgICAgICAgIHJldHVybiBlbGVtZW50Lm1velNyY09iamVjdDtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICB0aGlzLnNldFZpZGVvU3JjID0gZnVuY3Rpb24gKGVsZW1lbnQsIHNyYykge1xuICAgICAgICAgICAgICAgIGVsZW1lbnQubW96U3JjT2JqZWN0ID0gc3JjO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIFJUQ1Nlc3Npb25EZXNjcmlwdGlvbiA9IG1velJUQ1Nlc3Npb25EZXNjcmlwdGlvbjtcbiAgICAgICAgICAgIFJUQ0ljZUNhbmRpZGF0ZSA9IG1velJUQ0ljZUNhbmRpZGF0ZTtcbiAgICAgICAgfVxuICAgIH0gZWxzZSBpZiAobmF2aWdhdG9yLndlYmtpdEdldFVzZXJNZWRpYSkge1xuICAgICAgICBjb25zb2xlLmxvZygnVGhpcyBhcHBlYXJzIHRvIGJlIENocm9tZScpO1xuICAgICAgICB0aGlzLnBlZXJjb25uZWN0aW9uID0gd2Via2l0UlRDUGVlckNvbm5lY3Rpb247XG4gICAgICAgIHRoaXMuYnJvd3NlciA9IFJUQ0Jyb3dzZXJUeXBlLlJUQ19CUk9XU0VSX0NIUk9NRTtcbiAgICAgICAgdGhpcy5nZXRVc2VyTWVkaWEgPSBuYXZpZ2F0b3Iud2Via2l0R2V0VXNlck1lZGlhLmJpbmQobmF2aWdhdG9yKTtcbiAgICAgICAgdGhpcy5hdHRhY2hNZWRpYVN0cmVhbSA9IGZ1bmN0aW9uIChlbGVtZW50LCBzdHJlYW0pIHtcbiAgICAgICAgICAgIGVsZW1lbnQuYXR0cignc3JjJywgd2Via2l0VVJMLmNyZWF0ZU9iamVjdFVSTChzdHJlYW0pKTtcbiAgICAgICAgfTtcbiAgICAgICAgdGhpcy5nZXRTdHJlYW1JRCA9IGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgICAgIC8vIHN0cmVhbXMgZnJvbSBGRiBlbmRwb2ludHMgaGF2ZSB0aGUgY2hhcmFjdGVycyAneycgYW5kICd9J1xuICAgICAgICAgICAgLy8gdGhhdCBtYWtlIGpRdWVyeSBjaG9rZS5cbiAgICAgICAgICAgIHJldHVybiBzdHJlYW0uaWQucmVwbGFjZSgvW1xceyxcXH1dL2csXCJcIik7XG4gICAgICAgIH07XG4gICAgICAgIHRoaXMuZ2V0VmlkZW9TcmMgPSBmdW5jdGlvbiAoZWxlbWVudCkge1xuICAgICAgICAgICAgcmV0dXJuIGVsZW1lbnQuZ2V0QXR0cmlidXRlKFwic3JjXCIpO1xuICAgICAgICB9O1xuICAgICAgICB0aGlzLnNldFZpZGVvU3JjID0gZnVuY3Rpb24gKGVsZW1lbnQsIHNyYykge1xuICAgICAgICAgICAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoXCJzcmNcIiwgc3JjKTtcbiAgICAgICAgfTtcbiAgICAgICAgLy8gRFRMUyBzaG91bGQgbm93IGJlIGVuYWJsZWQgYnkgZGVmYXVsdCBidXQuLlxuICAgICAgICB0aGlzLnBjX2NvbnN0cmFpbnRzID0geydvcHRpb25hbCc6IFt7J0R0bHNTcnRwS2V5QWdyZWVtZW50JzogJ3RydWUnfV19O1xuICAgICAgICBpZiAobmF2aWdhdG9yLnVzZXJBZ2VudC5pbmRleE9mKCdBbmRyb2lkJykgIT0gLTEpIHtcbiAgICAgICAgICAgIHRoaXMucGNfY29uc3RyYWludHMgPSB7fTsgLy8gZGlzYWJsZSBEVExTIG9uIEFuZHJvaWRcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXdlYmtpdE1lZGlhU3RyZWFtLnByb3RvdHlwZS5nZXRWaWRlb1RyYWNrcykge1xuICAgICAgICAgICAgd2Via2l0TWVkaWFTdHJlYW0ucHJvdG90eXBlLmdldFZpZGVvVHJhY2tzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLnZpZGVvVHJhY2tzO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoIXdlYmtpdE1lZGlhU3RyZWFtLnByb3RvdHlwZS5nZXRBdWRpb1RyYWNrcykge1xuICAgICAgICAgICAgd2Via2l0TWVkaWFTdHJlYW0ucHJvdG90eXBlLmdldEF1ZGlvVHJhY2tzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmF1ZGlvVHJhY2tzO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBlbHNlXG4gICAge1xuICAgICAgICB0cnkgeyBjb25zb2xlLmxvZygnQnJvd3NlciBkb2VzIG5vdCBhcHBlYXIgdG8gYmUgV2ViUlRDLWNhcGFibGUnKTsgfSBjYXRjaCAoZSkgeyB9XG5cbiAgICAgICAgd2luZG93LmxvY2F0aW9uLmhyZWYgPSAnd2VicnRjcmVxdWlyZWQuaHRtbCc7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAodGhpcy5icm93c2VyICE9PSBSVENCcm93c2VyVHlwZS5SVENfQlJPV1NFUl9DSFJPTUUgJiZcbiAgICAgICAgY29uZmlnLmVuYWJsZUZpcmVmb3hTdXBwb3J0ICE9PSB0cnVlKSB7XG4gICAgICAgIHdpbmRvdy5sb2NhdGlvbi5ocmVmID0gJ2Nocm9tZW9ubHkuaHRtbCc7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbn1cblxuXG5SVENVdGlscy5wcm90b3R5cGUuZ2V0VXNlck1lZGlhV2l0aENvbnN0cmFpbnRzID0gZnVuY3Rpb24oXG4gICAgdW0sIHN1Y2Nlc3NfY2FsbGJhY2ssIGZhaWx1cmVfY2FsbGJhY2ssIHJlc29sdXRpb24sYmFuZHdpZHRoLCBmcHMsXG4gICAgZGVza3RvcFN0cmVhbSlcbntcbiAgICAvLyBDaGVjayBpZiB3ZSBhcmUgcnVubmluZyBvbiBBbmRyb2lkIGRldmljZVxuICAgIHZhciBpc0FuZHJvaWQgPSBuYXZpZ2F0b3IudXNlckFnZW50LmluZGV4T2YoJ0FuZHJvaWQnKSAhPSAtMTtcblxuICAgIHZhciBjb25zdHJhaW50cyA9IGdldENvbnN0cmFpbnRzKFxuICAgICAgICB1bSwgcmVzb2x1dGlvbiwgYmFuZHdpZHRoLCBmcHMsIGRlc2t0b3BTdHJlYW0sIGlzQW5kcm9pZCk7XG5cbiAgICB2YXIgaXNGRiA9IG5hdmlnYXRvci51c2VyQWdlbnQudG9Mb3dlckNhc2UoKS5pbmRleE9mKCdmaXJlZm94JykgPiAtMTtcblxuICAgIHRyeSB7XG4gICAgICAgIGlmIChjb25maWcuZW5hYmxlU2ltdWxjYXN0XG4gICAgICAgICAgICAmJiBjb25zdHJhaW50cy52aWRlb1xuICAgICAgICAgICAgJiYgY29uc3RyYWludHMudmlkZW8uY2hyb21lTWVkaWFTb3VyY2UgIT09ICdzY3JlZW4nXG4gICAgICAgICAgICAmJiBjb25zdHJhaW50cy52aWRlby5jaHJvbWVNZWRpYVNvdXJjZSAhPT0gJ2Rlc2t0b3AnXG4gICAgICAgICAgICAmJiAhaXNBbmRyb2lkXG5cbiAgICAgICAgICAgIC8vIFdlIGN1cnJlbnRseSBkbyBub3Qgc3VwcG9ydCBGRiwgYXMgaXQgZG9lc24ndCBoYXZlIG11bHRpc3RyZWFtIHN1cHBvcnQuXG4gICAgICAgICAgICAmJiAhaXNGRikge1xuICAgICAgICAgICAgQVBQLnNpbXVsY2FzdC5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMsIGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ29uVXNlck1lZGlhU3VjY2VzcycpO1xuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzX2NhbGxiYWNrKHN0cmVhbSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdGYWlsZWQgdG8gZ2V0IGFjY2VzcyB0byBsb2NhbCBtZWRpYS4gRXJyb3IgJywgZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZmFpbHVyZV9jYWxsYmFjaykge1xuICAgICAgICAgICAgICAgICAgICAgICAgZmFpbHVyZV9jYWxsYmFjayhlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgdGhpcy5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMsXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnb25Vc2VyTWVkaWFTdWNjZXNzJyk7XG4gICAgICAgICAgICAgICAgICAgIHN1Y2Nlc3NfY2FsbGJhY2soc3RyZWFtKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ0ZhaWxlZCB0byBnZXQgYWNjZXNzIHRvIGxvY2FsIG1lZGlhLiBFcnJvciAnLFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3IsIGNvbnN0cmFpbnRzKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGZhaWx1cmVfY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZhaWx1cmVfY2FsbGJhY2soZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgfVxuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignR1VNIGZhaWxlZDogJywgZSk7XG4gICAgICAgIGlmKGZhaWx1cmVfY2FsbGJhY2spIHtcbiAgICAgICAgICAgIGZhaWx1cmVfY2FsbGJhY2soZSk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG4vKipcbiAqIFdlIGFzayBmb3IgYXVkaW8gYW5kIHZpZGVvIGNvbWJpbmVkIHN0cmVhbSBpbiBvcmRlciB0byBnZXQgcGVybWlzc2lvbnMgYW5kXG4gKiBub3QgdG8gYXNrIHR3aWNlLlxuICovXG5SVENVdGlscy5wcm90b3R5cGUub2J0YWluQXVkaW9BbmRWaWRlb1Blcm1pc3Npb25zID0gZnVuY3Rpb24oKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIC8vIEdldCBBVlxuICAgIHZhciBjYiA9IGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgY29uc29sZS5sb2coJ2dvdCcsIHN0cmVhbSwgc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCkubGVuZ3RoLCBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGgpO1xuICAgICAgICBzZWxmLmhhbmRsZUxvY2FsU3RyZWFtKHN0cmVhbSk7XG4gICAgfTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5nZXRVc2VyTWVkaWFXaXRoQ29uc3RyYWludHMoXG4gICAgICAgIFsnYXVkaW8nLCAndmlkZW8nXSxcbiAgICAgICAgY2IsXG4gICAgICAgIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignZmFpbGVkIHRvIG9idGFpbiBhdWRpby92aWRlbyBzdHJlYW0gLSB0cnlpbmcgYXVkaW8gb25seScsIGVycm9yKTtcbiAgICAgICAgICAgIHNlbGYuZ2V0VXNlck1lZGlhV2l0aENvbnN0cmFpbnRzKFxuICAgICAgICAgICAgICAgIFsnYXVkaW8nXSxcbiAgICAgICAgICAgICAgICBjYixcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignZmFpbGVkIHRvIG9idGFpbiBhdWRpby92aWRlbyBzdHJlYW0gLSBzdG9wJywgZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKFwiRXJyb3JcIixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBcIkZhaWxlZCB0byBvYnRhaW4gcGVybWlzc2lvbnMgdG8gdXNlIHRoZSBsb2NhbCBtaWNyb3Bob25lXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiYW5kL29yIGNhbWVyYS5cIik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSxcbiAgICAgICAgICAgIGNvbmZpZy5yZXNvbHV0aW9uIHx8ICczNjAnKTtcbn1cblxuUlRDVXRpbHMucHJvdG90eXBlLmhhbmRsZUxvY2FsU3RyZWFtID0gZnVuY3Rpb24oc3RyZWFtKVxue1xuICAgIGlmKHdpbmRvdy53ZWJraXRNZWRpYVN0cmVhbSlcbiAgICB7XG4gICAgICAgIHZhciBhdWRpb1N0cmVhbSA9IG5ldyB3ZWJraXRNZWRpYVN0cmVhbSgpO1xuICAgICAgICB2YXIgdmlkZW9TdHJlYW0gPSBuZXcgd2Via2l0TWVkaWFTdHJlYW0oKTtcbiAgICAgICAgdmFyIGF1ZGlvVHJhY2tzID0gc3RyZWFtLmdldEF1ZGlvVHJhY2tzKCk7XG4gICAgICAgIHZhciB2aWRlb1RyYWNrcyA9IHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGF1ZGlvVHJhY2tzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBhdWRpb1N0cmVhbS5hZGRUcmFjayhhdWRpb1RyYWNrc1tpXSk7XG4gICAgICAgIH1cblxuICAgICAgICB0aGlzLnNlcnZpY2UuY3JlYXRlTG9jYWxTdHJlYW0oYXVkaW9TdHJlYW0sIFwiYXVkaW9cIik7XG5cbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHZpZGVvVHJhY2tzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB2aWRlb1N0cmVhbS5hZGRUcmFjayh2aWRlb1RyYWNrc1tpXSk7XG4gICAgICAgIH1cblxuXG4gICAgICAgIHRoaXMuc2VydmljZS5jcmVhdGVMb2NhbFN0cmVhbSh2aWRlb1N0cmVhbSwgXCJ2aWRlb1wiKTtcbiAgICB9XG4gICAgZWxzZVxuICAgIHsvL2ZpcmVmb3hcbiAgICAgICAgdGhpcy5zZXJ2aWNlLmNyZWF0ZUxvY2FsU3RyZWFtKHN0cmVhbSwgXCJzdHJlYW1cIik7XG4gICAgfVxuXG59O1xuXG5cblxubW9kdWxlLmV4cG9ydHMgPSBSVENVdGlsczsiLCJ2YXIgVUkgPSB7fTtcblxudmFyIFZpZGVvTGF5b3V0ID0gcmVxdWlyZShcIi4vdmlkZW9sYXlvdXQvVmlkZW9MYXlvdXQuanNcIik7XG52YXIgQXVkaW9MZXZlbHMgPSByZXF1aXJlKFwiLi9hdWRpb19sZXZlbHMvQXVkaW9MZXZlbHMuanNcIik7XG52YXIgUHJlemkgPSByZXF1aXJlKFwiLi9wcmV6aS9QcmV6aS5qc1wiKTtcbnZhciBFdGhlcnBhZCA9IHJlcXVpcmUoXCIuL2V0aGVycGFkL0V0aGVycGFkLmpzXCIpO1xudmFyIENoYXQgPSByZXF1aXJlKFwiLi9zaWRlX3Bhbm5lbHMvY2hhdC9DaGF0LmpzXCIpO1xudmFyIFRvb2xiYXIgPSByZXF1aXJlKFwiLi90b29sYmFycy9Ub29sYmFyXCIpO1xudmFyIFRvb2xiYXJUb2dnbGVyID0gcmVxdWlyZShcIi4vdG9vbGJhcnMvVG9vbGJhclRvZ2dsZXJcIik7XG52YXIgQm90dG9tVG9vbGJhciA9IHJlcXVpcmUoXCIuL3Rvb2xiYXJzL0JvdHRvbVRvb2xiYXJcIik7XG52YXIgQ29udGFjdExpc3QgPSByZXF1aXJlKFwiLi9zaWRlX3Bhbm5lbHMvY29udGFjdGxpc3QvQ29udGFjdExpc3RcIik7XG52YXIgQXZhdGFyID0gcmVxdWlyZShcIi4vYXZhdGFyL0F2YXRhclwiKTtcbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiZXZlbnRzXCIpO1xudmFyIFNldHRpbmdzTWVudSA9IHJlcXVpcmUoXCIuL3NpZGVfcGFubmVscy9zZXR0aW5ncy9TZXR0aW5nc01lbnVcIik7XG52YXIgU2V0dGluZ3MgPSByZXF1aXJlKFwiLi9zaWRlX3Bhbm5lbHMvc2V0dGluZ3MvU2V0dGluZ3NcIik7XG52YXIgUGFuZWxUb2dnbGVyID0gcmVxdWlyZShcIi4vc2lkZV9wYW5uZWxzL1NpZGVQYW5lbFRvZ2dsZXJcIik7XG52YXIgUm9vbU5hbWVHZW5lcmF0b3IgPSByZXF1aXJlKFwiLi93ZWxjb21lX3BhZ2UvUm9vbW5hbWVHZW5lcmF0b3JcIik7XG5VSS5tZXNzYWdlSGFuZGxlciA9IHJlcXVpcmUoXCIuL3V0aWwvTWVzc2FnZUhhbmRsZXJcIik7XG52YXIgbWVzc2FnZUhhbmRsZXIgPSBVSS5tZXNzYWdlSGFuZGxlcjtcbnZhciBBdXRoZW50aWNhdGlvbiAgPSByZXF1aXJlKFwiLi9hdXRoZW50aWNhdGlvbi9BdXRoZW50aWNhdGlvblwiKTtcbnZhciBVSVV0aWwgPSByZXF1aXJlKFwiLi91dGlsL1VJVXRpbFwiKTtcbnZhciBOaWNrbmFtZUhhbmRsZXIgPSByZXF1aXJlKFwiLi91dGlsL05pY2tuYW1lSGFuZGxlclwiKTtcbnZhciBDUUV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL2Nvbm5lY3Rpb25xdWFsaXR5L0NRRXZlbnRzXCIpO1xudmFyIERlc2t0b3BTaGFyaW5nRXZlbnRUeXBlc1xuICAgID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvZGVza3RvcHNoYXJpbmcvRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzXCIpO1xudmFyIFJUQ0V2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9SVENFdmVudHNcIik7XG52YXIgU3RyZWFtRXZlbnRUeXBlcyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9TdHJlYW1FdmVudFR5cGVzXCIpO1xudmFyIFhNUFBFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS94bXBwL1hNUFBFdmVudHNcIik7XG5cbnZhciBldmVudEVtaXR0ZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG52YXIgcm9vbU5hbWUgPSBudWxsO1xuXG5cbmZ1bmN0aW9uIHNldHVwUHJlemkoKVxue1xuICAgICQoXCIjcmVsb2FkUHJlc2VudGF0aW9uTGlua1wiKS5jbGljayhmdW5jdGlvbigpXG4gICAge1xuICAgICAgICBQcmV6aS5yZWxvYWRQcmVzZW50YXRpb24oKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gc2V0dXBDaGF0KClcbntcbiAgICBDaGF0LmluaXQoKTtcbiAgICAkKFwiI3RvZ2dsZV9zbWlsZXlzXCIpLmNsaWNrKGZ1bmN0aW9uKCkge1xuICAgICAgICBDaGF0LnRvZ2dsZVNtaWxleXMoKTtcbiAgICB9KTtcbn1cblxuZnVuY3Rpb24gc2V0dXBUb29sYmFycygpIHtcbiAgICBUb29sYmFyLmluaXQoVUkpO1xuICAgIFRvb2xiYXIuc2V0dXBCdXR0b25zRnJvbUNvbmZpZygpO1xuICAgIEJvdHRvbVRvb2xiYXIuaW5pdCgpO1xufVxuXG5mdW5jdGlvbiBzdHJlYW1IYW5kbGVyKHN0cmVhbSkge1xuICAgIHN3aXRjaCAoc3RyZWFtLnR5cGUpXG4gICAge1xuICAgICAgICBjYXNlIFwiYXVkaW9cIjpcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNoYW5nZUxvY2FsQXVkaW8oc3RyZWFtKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwidmlkZW9cIjpcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNoYW5nZUxvY2FsVmlkZW8oc3RyZWFtKTtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlIFwic3RyZWFtXCI6XG4gICAgICAgICAgICBWaWRlb0xheW91dC5jaGFuZ2VMb2NhbFN0cmVhbShzdHJlYW0pO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBvbkRpc3Bvc2VDb25mZXJlbmNlKHVubG9hZCkge1xuICAgIFRvb2xiYXIuc2hvd0F1dGhlbnRpY2F0ZUJ1dHRvbihmYWxzZSk7XG59O1xuXG5mdW5jdGlvbiBvbkRpc3BsYXlOYW1lQ2hhbmdlZChqaWQsIGRpc3BsYXlOYW1lKSB7XG4gICAgQ29udGFjdExpc3Qub25EaXNwbGF5TmFtZUNoYW5nZShqaWQsIGRpc3BsYXlOYW1lKTtcbiAgICBTZXR0aW5nc01lbnUub25EaXNwbGF5TmFtZUNoYW5nZShqaWQsIGRpc3BsYXlOYW1lKTtcbiAgICBWaWRlb0xheW91dC5vbkRpc3BsYXlOYW1lQ2hhbmdlZChqaWQsIGRpc3BsYXlOYW1lKTtcbn1cblxuZnVuY3Rpb24gcmVnaXN0ZXJMaXN0ZW5lcnMoKSB7XG4gICAgQVBQLlJUQy5hZGRTdHJlYW1MaXN0ZW5lcihzdHJlYW1IYW5kbGVyLCBTdHJlYW1FdmVudFR5cGVzLkVWRU5UX1RZUEVfTE9DQUxfQ1JFQVRFRCk7XG5cbiAgICBBUFAuUlRDLmFkZFN0cmVhbUxpc3RlbmVyKHN0cmVhbUhhbmRsZXIsIFN0cmVhbUV2ZW50VHlwZXMuRVZFTlRfVFlQRV9MT0NBTF9DSEFOR0VEKTtcbiAgICBBUFAuUlRDLmFkZFN0cmVhbUxpc3RlbmVyKGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgVmlkZW9MYXlvdXQub25SZW1vdGVTdHJlYW1BZGRlZChzdHJlYW0pO1xuICAgIH0sIFN0cmVhbUV2ZW50VHlwZXMuRVZFTlRfVFlQRV9SRU1PVEVfQ1JFQVRFRCk7XG4gICAgQVBQLlJUQy5hZGRMaXN0ZW5lcihSVENFdmVudHMuTEFTVE5fQ0hBTkdFRCwgb25MYXN0TkNoYW5nZWQpO1xuICAgIEFQUC5SVEMuYWRkTGlzdGVuZXIoUlRDRXZlbnRzLkRPTUlOQU5UU1BFQUtFUl9DSEFOR0VELCBmdW5jdGlvbiAocmVzb3VyY2VKaWQpIHtcbiAgICAgICAgVmlkZW9MYXlvdXQub25Eb21pbmFudFNwZWFrZXJDaGFuZ2VkKHJlc291cmNlSmlkKTtcbiAgICB9KTtcbiAgICBBUFAuUlRDLmFkZExpc3RlbmVyKFJUQ0V2ZW50cy5MQVNUTl9FTkRQT0lOVF9DSEFOR0VELFxuICAgICAgICBmdW5jdGlvbiAobGFzdE5FbmRwb2ludHMsIGVuZHBvaW50c0VudGVyaW5nTGFzdE4sIHN0cmVhbSkge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQub25MYXN0TkVuZHBvaW50c0NoYW5nZWQobGFzdE5FbmRwb2ludHMsXG4gICAgICAgICAgICAgICAgZW5kcG9pbnRzRW50ZXJpbmdMYXN0Tiwgc3RyZWFtKTtcbiAgICAgICAgfSk7XG4gICAgQVBQLlJUQy5hZGRMaXN0ZW5lcihSVENFdmVudHMuU0lNVUxDQVNUX0xBWUVSX0NIQU5HRUQsXG4gICAgICAgIGZ1bmN0aW9uIChlbmRwb2ludFNpbXVsY2FzdExheWVycykge1xuICAgICAgICAgICBWaWRlb0xheW91dC5vblNpbXVsY2FzdExheWVyc0NoYW5nZWQoZW5kcG9pbnRTaW11bGNhc3RMYXllcnMpO1xuICAgICAgICB9KTtcbiAgICBBUFAuUlRDLmFkZExpc3RlbmVyKFJUQ0V2ZW50cy5TSU1VTENBU1RfTEFZRVJfQ0hBTkdJTkcsXG4gICAgICAgIGZ1bmN0aW9uIChlbmRwb2ludFNpbXVsY2FzdExheWVycykge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQub25TaW11bGNhc3RMYXllcnNDaGFuZ2luZyhlbmRwb2ludFNpbXVsY2FzdExheWVycyk7XG4gICAgICAgIH0pO1xuICAgIFZpZGVvTGF5b3V0LmluaXQoZXZlbnRFbWl0dGVyKTtcblxuICAgIEFQUC5zdGF0aXN0aWNzLmFkZEF1ZGlvTGV2ZWxMaXN0ZW5lcihmdW5jdGlvbihqaWQsIGF1ZGlvTGV2ZWwpXG4gICAge1xuICAgICAgICB2YXIgcmVzb3VyY2VKaWQ7XG4gICAgICAgIGlmKGppZCA9PT0gQVBQLnN0YXRpc3RpY3MuTE9DQUxfSklEKVxuICAgICAgICB7XG4gICAgICAgICAgICByZXNvdXJjZUppZCA9IEF1ZGlvTGV2ZWxzLkxPQ0FMX0xFVkVMO1xuICAgICAgICAgICAgaWYoQVBQLlJUQy5sb2NhbEF1ZGlvLmlzTXV0ZWQoKSlcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhdWRpb0xldmVsID0gMDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIEF1ZGlvTGV2ZWxzLnVwZGF0ZUF1ZGlvTGV2ZWwocmVzb3VyY2VKaWQsIGF1ZGlvTGV2ZWwsXG4gICAgICAgICAgICBVSS5nZXRMYXJnZVZpZGVvU3RhdGUoKS51c2VyUmVzb3VyY2VKaWQpO1xuICAgIH0pO1xuICAgIEFQUC5kZXNrdG9wc2hhcmluZy5hZGRMaXN0ZW5lcihmdW5jdGlvbiAoKSB7XG4gICAgICAgIFRvb2xiYXJUb2dnbGVyLnNob3dEZXNrdG9wU2hhcmluZ0J1dHRvbigpO1xuICAgIH0sIERlc2t0b3BTaGFyaW5nRXZlbnRUeXBlcy5JTklUKTtcbiAgICBBUFAuZGVza3RvcHNoYXJpbmcuYWRkTGlzdGVuZXIoXG4gICAgICAgIFRvb2xiYXIuY2hhbmdlRGVza3RvcFNoYXJpbmdCdXR0b25TdGF0ZSxcbiAgICAgICAgRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzLlNXSVRDSElOR19ET05FKTtcbiAgICBBUFAuY29ubmVjdGlvbnF1YWxpdHkuYWRkTGlzdGVuZXIoQ1FFdmVudHMuTE9DQUxTVEFUU19VUERBVEVELFxuICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMb2NhbENvbm5lY3Rpb25TdGF0cyk7XG4gICAgQVBQLmNvbm5lY3Rpb25xdWFsaXR5LmFkZExpc3RlbmVyKENRRXZlbnRzLlJFTU9URVNUQVRTX1VQREFURUQsXG4gICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUNvbm5lY3Rpb25TdGF0cyk7XG4gICAgQVBQLmNvbm5lY3Rpb25xdWFsaXR5LmFkZExpc3RlbmVyKENRRXZlbnRzLlNUT1AsXG4gICAgICAgIFZpZGVvTGF5b3V0Lm9uU3RhdHNTdG9wKTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLkRJU1BPU0VfQ09ORkVSRU5DRSwgb25EaXNwb3NlQ29uZmVyZW5jZSk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5LSUNLRUQsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbWVzc2FnZUhhbmRsZXIub3Blbk1lc3NhZ2VEaWFsb2coXCJTZXNzaW9uIFRlcm1pbmF0ZWRcIixcbiAgICAgICAgICAgIFwiT3VjaCEgWW91IGhhdmUgYmVlbiBraWNrZWQgb3V0IG9mIHRoZSBtZWV0IVwiKTtcbiAgICB9KTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLkJSSURHRV9ET1dOLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyLnNob3dFcnJvcihcIkVycm9yXCIsXG4gICAgICAgICAgICBcIkppdHNpIFZpZGVvYnJpZGdlIGlzIGN1cnJlbnRseSB1bmF2YWlsYWJsZS4gUGxlYXNlIHRyeSBhZ2FpbiBsYXRlciFcIik7XG4gICAgfSk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5VU0VSX0lEX0NIQU5HRUQsIGZ1bmN0aW9uIChmcm9tLCBpZCkge1xuICAgICAgICBBdmF0YXIuc2V0VXNlckF2YXRhcihmcm9tLCBpZCk7XG4gICAgfSk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5DSEFOR0VEX1NUUkVBTVMsIGZ1bmN0aW9uIChqaWQsIGNoYW5nZWRTdHJlYW1zKSB7XG4gICAgICAgIGZvcihzdHJlYW0gaW4gY2hhbmdlZFN0cmVhbXMpXG4gICAgICAgIHtcbiAgICAgICAgICAgIC8vIG1pZ2h0IG5lZWQgdG8gdXBkYXRlIHRoZSBkaXJlY3Rpb24gaWYgcGFydGljaXBhbnQganVzdCB3ZW50IGZyb20gc2VuZHJlY3YgdG8gcmVjdm9ubHlcbiAgICAgICAgICAgIGlmIChzdHJlYW0udHlwZSA9PT0gJ3ZpZGVvJyB8fCBzdHJlYW0udHlwZSA9PT0gJ3NjcmVlbicpIHtcbiAgICAgICAgICAgICAgICB2YXIgZWwgPSAkKCcjcGFydGljaXBhbnRfJyAgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpICsgJz52aWRlbycpO1xuICAgICAgICAgICAgICAgIHN3aXRjaCAoc3RyZWFtLmRpcmVjdGlvbikge1xuICAgICAgICAgICAgICAgICAgICBjYXNlICdzZW5kcmVjdic6XG4gICAgICAgICAgICAgICAgICAgICAgICBlbC5zaG93KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgY2FzZSAncmVjdm9ubHknOlxuICAgICAgICAgICAgICAgICAgICAgICAgZWwuaGlkZSgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRklYTUU6IENoZWNrIGlmIHdlIGhhdmUgdG8gY2hhbmdlIGxhcmdlIHZpZGVvXG4gICAgICAgICAgICAgICAgICAgICAgICAvL1ZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8oZWwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICB9KTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLkRJU1BMQVlfTkFNRV9DSEFOR0VELCBvbkRpc3BsYXlOYW1lQ2hhbmdlZCk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5NVUNfSk9JTkVELCBvbk11Y0pvaW5lZCk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5MT0NBTFJPTEVfQ0hBTkdFRCwgb25Mb2NhbFJvbGVDaGFuZ2UpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTVVDX0VOVEVSLCBvbk11Y0VudGVyZWQpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuTVVDX1JPTEVfQ0hBTkdFRCwgb25NdWNSb2xlQ2hhbmdlZCk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5QUkVTRU5DRV9TVEFUVVMsIG9uTXVjUHJlc2VuY2VTdGF0dXMpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuU1VCSkVDVF9DSEFOR0VELCBjaGF0U2V0U3ViamVjdCk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5NRVNTQUdFX1JFQ0VJVkVELCB1cGRhdGVDaGF0Q29udmVyc2F0aW9uKTtcbiAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLk1VQ19MRUZULCBvbk11Y0xlZnQpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuUEFTU1dPUkRfUkVRVUlSRUQsIG9uUGFzc3dvcmRSZXFpdXJlZCk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5DSEFUX0VSUk9SX1JFQ0VJVkVELCBjaGF0QWRkRXJyb3IpO1xuICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuRVRIRVJQQUQsIGluaXRFdGhlcnBhZCk7XG4gICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5BVVRIRU5USUNBVElPTl9SRVFVSVJFRCwgb25BdXRoZW50aWNhdGlvblJlcXVpcmVkKTtcblxuXG59XG5cblxuLyoqXG4gKiBNdXRlcy91bm11dGVzIHRoZSBsb2NhbCB2aWRlby5cbiAqXG4gKiBAcGFyYW0gbXV0ZSA8dHQ+dHJ1ZTwvdHQ+IHRvIG11dGUgdGhlIGxvY2FsIHZpZGVvOyBvdGhlcndpc2UsIDx0dD5mYWxzZTwvdHQ+XG4gKiBAcGFyYW0gb3B0aW9ucyBhbiBvYmplY3Qgd2hpY2ggc3BlY2lmaWVzIG9wdGlvbmFsIGFyZ3VtZW50cyBzdWNoIGFzIHRoZVxuICogPHR0PmJvb2xlYW48L3R0PiBrZXkgPHR0PmJ5VXNlcjwvdHQ+IHdpdGggZGVmYXVsdCB2YWx1ZSA8dHQ+dHJ1ZTwvdHQ+IHdoaWNoXG4gKiBzcGVjaWZpZXMgd2hldGhlciB0aGUgbWV0aG9kIHdhcyBpbml0aWF0ZWQgaW4gcmVzcG9uc2UgdG8gYSB1c2VyIGNvbW1hbmQgKGluXG4gKiBjb250cmFzdCB0byBhbiBhdXRvbWF0aWMgZGVjaXNpb24gdGFrZW4gYnkgdGhlIGFwcGxpY2F0aW9uIGxvZ2ljKVxuICovXG5mdW5jdGlvbiBzZXRWaWRlb011dGUobXV0ZSwgb3B0aW9ucykge1xuICAgIEFQUC54bXBwLnNldFZpZGVvTXV0ZShcbiAgICAgICAgbXV0ZSxcbiAgICAgICAgZnVuY3Rpb24gKG11dGUpIHtcbiAgICAgICAgICAgIHZhciB2aWRlbyA9ICQoJyN2aWRlbycpO1xuICAgICAgICAgICAgdmFyIGNvbW11bmljYXRpdmVDbGFzcyA9IFwiaWNvbi1jYW1lcmFcIjtcbiAgICAgICAgICAgIHZhciBtdXRlQ2xhc3MgPSBcImljb24tY2FtZXJhIGljb24tY2FtZXJhLWRpc2FibGVkXCI7XG5cbiAgICAgICAgICAgIGlmIChtdXRlKSB7XG4gICAgICAgICAgICAgICAgdmlkZW8ucmVtb3ZlQ2xhc3MoY29tbXVuaWNhdGl2ZUNsYXNzKTtcbiAgICAgICAgICAgICAgICB2aWRlby5hZGRDbGFzcyhtdXRlQ2xhc3MpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICB2aWRlby5yZW1vdmVDbGFzcyhtdXRlQ2xhc3MpO1xuICAgICAgICAgICAgICAgIHZpZGVvLmFkZENsYXNzKGNvbW11bmljYXRpdmVDbGFzcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIG9wdGlvbnMpO1xufVxuXG5cbmZ1bmN0aW9uIGJpbmRFdmVudHMoKVxue1xuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgYW5kIHJlcG9zaXRpb25zIHZpZGVvcyBpbiBmdWxsIHNjcmVlbiBtb2RlLlxuICAgICAqL1xuICAgICQoZG9jdW1lbnQpLm9uKCd3ZWJraXRmdWxsc2NyZWVuY2hhbmdlIG1vemZ1bGxzY3JlZW5jaGFuZ2UgZnVsbHNjcmVlbmNoYW5nZScsXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LnJlc2l6ZUxhcmdlVmlkZW9Db250YWluZXIoKTtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LnBvc2l0aW9uTGFyZ2UoKTtcbiAgICAgICAgfVxuICAgICk7XG5cbiAgICAkKHdpbmRvdykucmVzaXplKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplTGFyZ2VWaWRlb0NvbnRhaW5lcigpO1xuICAgICAgICBWaWRlb0xheW91dC5wb3NpdGlvbkxhcmdlKCk7XG4gICAgfSk7XG59XG5cblVJLnN0YXJ0ID0gZnVuY3Rpb24gKGluaXQpIHtcbiAgICBkb2N1bWVudC50aXRsZSA9IGludGVyZmFjZUNvbmZpZy5BUFBfTkFNRTtcbiAgICBpZihjb25maWcuZW5hYmxlV2VsY29tZVBhZ2UgJiYgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lID09IFwiL1wiICYmXG4gICAgICAgICghd2luZG93LmxvY2FsU3RvcmFnZS53ZWxjb21lUGFnZURpc2FibGVkIHx8IHdpbmRvdy5sb2NhbFN0b3JhZ2Uud2VsY29tZVBhZ2VEaXNhYmxlZCA9PSBcImZhbHNlXCIpKVxuICAgIHtcbiAgICAgICAgJChcIiN2aWRlb2NvbmZlcmVuY2VfcGFnZVwiKS5oaWRlKCk7XG4gICAgICAgIHZhciBzZXR1cFdlbGNvbWVQYWdlID0gcmVxdWlyZShcIi4vd2VsY29tZV9wYWdlL1dlbGNvbWVQYWdlXCIpO1xuICAgICAgICBzZXR1cFdlbGNvbWVQYWdlKCk7XG5cbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGlmIChpbnRlcmZhY2VDb25maWcuU0hPV19KSVRTSV9XQVRFUk1BUkspIHtcbiAgICAgICAgdmFyIGxlZnRXYXRlcm1hcmtEaXZcbiAgICAgICAgICAgID0gJChcIiNsYXJnZVZpZGVvQ29udGFpbmVyIGRpdltjbGFzcz0nd2F0ZXJtYXJrIGxlZnR3YXRlcm1hcmsnXVwiKTtcblxuICAgICAgICBsZWZ0V2F0ZXJtYXJrRGl2LmNzcyh7ZGlzcGxheTogJ2Jsb2NrJ30pO1xuICAgICAgICBsZWZ0V2F0ZXJtYXJrRGl2LnBhcmVudCgpLmdldCgwKS5ocmVmXG4gICAgICAgICAgICA9IGludGVyZmFjZUNvbmZpZy5KSVRTSV9XQVRFUk1BUktfTElOSztcbiAgICB9XG5cbiAgICBpZiAoaW50ZXJmYWNlQ29uZmlnLlNIT1dfQlJBTkRfV0FURVJNQVJLKSB7XG4gICAgICAgIHZhciByaWdodFdhdGVybWFya0RpdlxuICAgICAgICAgICAgPSAkKFwiI2xhcmdlVmlkZW9Db250YWluZXIgZGl2W2NsYXNzPSd3YXRlcm1hcmsgcmlnaHR3YXRlcm1hcmsnXVwiKTtcblxuICAgICAgICByaWdodFdhdGVybWFya0Rpdi5jc3Moe2Rpc3BsYXk6ICdibG9jayd9KTtcbiAgICAgICAgcmlnaHRXYXRlcm1hcmtEaXYucGFyZW50KCkuZ2V0KDApLmhyZWZcbiAgICAgICAgICAgID0gaW50ZXJmYWNlQ29uZmlnLkJSQU5EX1dBVEVSTUFSS19MSU5LO1xuICAgICAgICByaWdodFdhdGVybWFya0Rpdi5nZXQoMCkuc3R5bGUuYmFja2dyb3VuZEltYWdlXG4gICAgICAgICAgICA9IFwidXJsKGltYWdlcy9yaWdodHdhdGVybWFyay5wbmcpXCI7XG4gICAgfVxuXG4gICAgaWYgKGludGVyZmFjZUNvbmZpZy5TSE9XX1BPV0VSRURfQlkpIHtcbiAgICAgICAgJChcIiNsYXJnZVZpZGVvQ29udGFpbmVyPmFbY2xhc3M9J3Bvd2VyZWRieSddXCIpLmNzcyh7ZGlzcGxheTogJ2Jsb2NrJ30pO1xuICAgIH1cblxuICAgICQoXCIjd2VsY29tZV9wYWdlXCIpLmhpZGUoKTtcblxuICAgIFZpZGVvTGF5b3V0LnJlc2l6ZUxhcmdlVmlkZW9Db250YWluZXIoKTtcbiAgICAkKFwiI3ZpZGVvc3BhY2VcIikubW91c2Vtb3ZlKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFRvb2xiYXJUb2dnbGVyLnNob3dUb29sYmFyKCk7XG4gICAgfSk7XG4gICAgLy8gU2V0IHRoZSBkZWZhdWx0cyBmb3IgcHJvbXB0IGRpYWxvZ3MuXG4gICAgalF1ZXJ5LnByb21wdC5zZXREZWZhdWx0cyh7cGVyc2lzdGVudDogZmFsc2V9KTtcblxuXG4gICAgTmlja25hbWVIYW5kbGVyLmluaXQoZXZlbnRFbWl0dGVyKTtcbiAgICByZWdpc3Rlckxpc3RlbmVycygpO1xuICAgIGJpbmRFdmVudHMoKTtcbiAgICBzZXR1cFByZXppKCk7XG4gICAgc2V0dXBUb29sYmFycygpO1xuICAgIHNldHVwQ2hhdCgpO1xuXG5cbiAgICBkb2N1bWVudC50aXRsZSA9IGludGVyZmFjZUNvbmZpZy5BUFBfTkFNRTtcblxuICAgICQoXCIjZG93bmxvYWRsb2dcIikuY2xpY2soZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIGR1bXAoZXZlbnQudGFyZ2V0KTtcbiAgICB9KTtcblxuICAgIGlmKGNvbmZpZy5lbmFibGVXZWxjb21lUGFnZSAmJiB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUgPT0gXCIvXCIgJiZcbiAgICAgICAgKCF3aW5kb3cubG9jYWxTdG9yYWdlLndlbGNvbWVQYWdlRGlzYWJsZWQgfHwgd2luZG93LmxvY2FsU3RvcmFnZS53ZWxjb21lUGFnZURpc2FibGVkID09IFwiZmFsc2VcIikpXG4gICAge1xuICAgICAgICAkKFwiI3ZpZGVvY29uZmVyZW5jZV9wYWdlXCIpLmhpZGUoKTtcbiAgICAgICAgdmFyIHNldHVwV2VsY29tZVBhZ2UgPSByZXF1aXJlKFwiLi93ZWxjb21lX3BhZ2UvV2VsY29tZVBhZ2VcIik7XG4gICAgICAgIHNldHVwV2VsY29tZVBhZ2UoKTtcblxuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgJChcIiN3ZWxjb21lX3BhZ2VcIikuaGlkZSgpO1xuXG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xhcmdlVmlkZW8nKS52b2x1bWUgPSAwO1xuXG4gICAgaWYgKCEkKCcjc2V0dGluZ3MnKS5pcygnOnZpc2libGUnKSkge1xuICAgICAgICBjb25zb2xlLmxvZygnaW5pdCcpO1xuICAgICAgICBpbml0KCk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgbG9naW5JbmZvLm9uc3VibWl0ID0gZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIGlmIChlLnByZXZlbnREZWZhdWx0KSBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAkKCcjc2V0dGluZ3MnKS5oaWRlKCk7XG4gICAgICAgICAgICBpbml0KCk7XG4gICAgICAgIH07XG4gICAgfVxuXG4gICAgdG9hc3RyLm9wdGlvbnMgPSB7XG4gICAgICAgIFwiY2xvc2VCdXR0b25cIjogdHJ1ZSxcbiAgICAgICAgXCJkZWJ1Z1wiOiBmYWxzZSxcbiAgICAgICAgXCJwb3NpdGlvbkNsYXNzXCI6IFwibm90aWZpY2F0aW9uLWJvdHRvbS1yaWdodFwiLFxuICAgICAgICBcIm9uY2xpY2tcIjogbnVsbCxcbiAgICAgICAgXCJzaG93RHVyYXRpb25cIjogXCIzMDBcIixcbiAgICAgICAgXCJoaWRlRHVyYXRpb25cIjogXCIxMDAwXCIsXG4gICAgICAgIFwidGltZU91dFwiOiBcIjIwMDBcIixcbiAgICAgICAgXCJleHRlbmRlZFRpbWVPdXRcIjogXCIxMDAwXCIsXG4gICAgICAgIFwic2hvd0Vhc2luZ1wiOiBcInN3aW5nXCIsXG4gICAgICAgIFwiaGlkZUVhc2luZ1wiOiBcImxpbmVhclwiLFxuICAgICAgICBcInNob3dNZXRob2RcIjogXCJmYWRlSW5cIixcbiAgICAgICAgXCJoaWRlTWV0aG9kXCI6IFwiZmFkZU91dFwiLFxuICAgICAgICBcInJlcG9zaXRpb25cIjogZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICBpZihQYW5lbFRvZ2dsZXIuaXNWaXNpYmxlKCkpIHtcbiAgICAgICAgICAgICAgICAkKFwiI3RvYXN0LWNvbnRhaW5lclwiKS5hZGRDbGFzcyhcIm5vdGlmaWNhdGlvbi1ib3R0b20tcmlnaHQtY2VudGVyXCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAkKFwiI3RvYXN0LWNvbnRhaW5lclwiKS5yZW1vdmVDbGFzcyhcIm5vdGlmaWNhdGlvbi1ib3R0b20tcmlnaHQtY2VudGVyXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICBcIm5ld2VzdE9uVG9wXCI6IGZhbHNlXG4gICAgfTtcblxuICAgIFNldHRpbmdzTWVudS5pbml0KCk7XG5cbn07XG5cbmZ1bmN0aW9uIGNoYXRBZGRFcnJvcihlcnJvck1lc3NhZ2UsIG9yaWdpbmFsVGV4dClcbntcbiAgICByZXR1cm4gQ2hhdC5jaGF0QWRkRXJyb3IoZXJyb3JNZXNzYWdlLCBvcmlnaW5hbFRleHQpO1xufTtcblxuZnVuY3Rpb24gY2hhdFNldFN1YmplY3QodGV4dClcbntcbiAgICByZXR1cm4gQ2hhdC5jaGF0U2V0U3ViamVjdCh0ZXh0KTtcbn07XG5cbmZ1bmN0aW9uIHVwZGF0ZUNoYXRDb252ZXJzYXRpb24oZnJvbSwgZGlzcGxheU5hbWUsIG1lc3NhZ2UpIHtcbiAgICByZXR1cm4gQ2hhdC51cGRhdGVDaGF0Q29udmVyc2F0aW9uKGZyb20sIGRpc3BsYXlOYW1lLCBtZXNzYWdlKTtcbn07XG5cbmZ1bmN0aW9uIG9uTXVjSm9pbmVkKGppZCwgaW5mbykge1xuICAgIFRvb2xiYXIudXBkYXRlUm9vbVVybCh3aW5kb3cubG9jYXRpb24uaHJlZik7XG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xvY2FsTmljaycpLmFwcGVuZENoaWxkKFxuICAgICAgICBkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpICsgJyAobWUpJylcbiAgICApO1xuXG4gICAgdmFyIHNldHRpbmdzID0gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbiAgICAvLyBBZGQgbXlzZWxmIHRvIHRoZSBjb250YWN0IGxpc3QuXG4gICAgQ29udGFjdExpc3QuYWRkQ29udGFjdChqaWQsIHNldHRpbmdzLmVtYWlsIHx8IHNldHRpbmdzLnVpZCk7XG5cbiAgICAvLyBPbmNlIHdlJ3ZlIGpvaW5lZCB0aGUgbXVjIHNob3cgdGhlIHRvb2xiYXJcbiAgICBUb29sYmFyVG9nZ2xlci5zaG93VG9vbGJhcigpO1xuXG4gICAgLy8gU2hvdyBhdXRoZW50aWNhdGUgYnV0dG9uIGlmIG5lZWRlZFxuICAgIFRvb2xiYXIuc2hvd0F1dGhlbnRpY2F0ZUJ1dHRvbihcbiAgICAgICAgICAgIEFQUC54bXBwLmlzRXh0ZXJuYWxBdXRoRW5hYmxlZCgpICYmICFBUFAueG1wcC5pc01vZGVyYXRvcigpKTtcblxuICAgIHZhciBkaXNwbGF5TmFtZSA9ICFjb25maWcuZGlzcGxheUppZHNcbiAgICAgICAgPyBpbmZvLmRpc3BsYXlOYW1lIDogU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcblxuICAgIGlmIChkaXNwbGF5TmFtZSlcbiAgICAgICAgb25EaXNwbGF5TmFtZUNoYW5nZWQoJ2xvY2FsVmlkZW9Db250YWluZXInLCBkaXNwbGF5TmFtZSArICcgKG1lKScpO1xufVxuXG5mdW5jdGlvbiBpbml0RXRoZXJwYWQobmFtZSkge1xuICAgIEV0aGVycGFkLmluaXQobmFtZSk7XG59O1xuXG5mdW5jdGlvbiBvbk11Y0xlZnQoamlkKSB7XG4gICAgY29uc29sZS5sb2coJ2xlZnQubXVjJywgamlkKTtcbiAgICB2YXIgZGlzcGxheU5hbWUgPSAkKCcjcGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCkgK1xuICAgICAgICAnPi5kaXNwbGF5bmFtZScpLmh0bWwoKTtcbiAgICBtZXNzYWdlSGFuZGxlci5ub3RpZnkoZGlzcGxheU5hbWUgfHwgJ1NvbWVib2R5JyxcbiAgICAgICAgJ2Rpc2Nvbm5lY3RlZCcsXG4gICAgICAgICdkaXNjb25uZWN0ZWQnKTtcbiAgICAvLyBOZWVkIHRvIGNhbGwgdGhpcyB3aXRoIGEgc2xpZ2h0IGRlbGF5LCBvdGhlcndpc2UgdGhlIGVsZW1lbnQgY291bGRuJ3QgYmVcbiAgICAvLyBmb3VuZCBmb3Igc29tZSByZWFzb24uXG4gICAgLy8gWFhYKGdwKSBpdCB3b3JrcyBmaW5lIHdpdGhvdXQgdGhlIHRpbWVvdXQgZm9yIG1lICh3aXRoIENocm9tZSAzOCkuXG4gICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgY29udGFpbmVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoXG4gICAgICAgICAgICAgICAgJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpKTtcbiAgICAgICAgaWYgKGNvbnRhaW5lcikge1xuICAgICAgICAgICAgQ29udGFjdExpc3QucmVtb3ZlQ29udGFjdChqaWQpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQucmVtb3ZlQ29ubmVjdGlvbkluZGljYXRvcihqaWQpO1xuICAgICAgICAgICAgLy8gaGlkZSBoZXJlLCB3YWl0IGZvciB2aWRlbyB0byBjbG9zZSBiZWZvcmUgcmVtb3ZpbmdcbiAgICAgICAgICAgICQoY29udGFpbmVyKS5oaWRlKCk7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5yZXNpemVUaHVtYm5haWxzKCk7XG4gICAgICAgIH1cbiAgICB9LCAxMCk7XG5cbiAgICBWaWRlb0xheW91dC5wYXJ0aWNpcGFudExlZnQoamlkKTtcblxufTtcblxuXG5mdW5jdGlvbiBvbkxvY2FsUm9sZUNoYW5nZShqaWQsIGluZm8sIHByZXMsIGlzTW9kZXJhdG9yLCBpc0V4dGVybmFsQXV0aEVuYWJsZWQpXG57XG5cbiAgICBjb25zb2xlLmluZm8oXCJNeSByb2xlIGNoYW5nZWQsIG5ldyByb2xlOiBcIiArIGluZm8ucm9sZSk7XG4gICAgb25Nb2RlcmF0b3JTdGF0dXNDaGFuZ2VkKGlzTW9kZXJhdG9yKTtcbiAgICBWaWRlb0xheW91dC5zaG93TW9kZXJhdG9ySW5kaWNhdG9yKCk7XG4gICAgVG9vbGJhci5zaG93QXV0aGVudGljYXRlQnV0dG9uKFxuICAgICAgICAgICAgaXNFeHRlcm5hbEF1dGhFbmFibGVkICYmICFpc01vZGVyYXRvcik7XG5cbiAgICBpZiAoaXNNb2RlcmF0b3IpIHtcbiAgICAgICAgQXV0aGVudGljYXRpb24uY2xvc2VBdXRoZW50aWNhdGlvbldpbmRvdygpO1xuICAgICAgICBtZXNzYWdlSGFuZGxlci5ub3RpZnkoXG4gICAgICAgICAgICAnTWUnLCAnY29ubmVjdGVkJywgJ01vZGVyYXRvciByaWdodHMgZ3JhbnRlZCAhJyk7XG4gICAgfVxufVxuXG5mdW5jdGlvbiBvbk1vZGVyYXRvclN0YXR1c0NoYW5nZWQoaXNNb2RlcmF0b3IpIHtcblxuICAgIFRvb2xiYXIuc2hvd1NpcENhbGxCdXR0b24oaXNNb2RlcmF0b3IpO1xuICAgIFRvb2xiYXIuc2hvd1JlY29yZGluZ0J1dHRvbihcbiAgICAgICAgaXNNb2RlcmF0b3IpOyAvLyYmXG4gICAgLy8gRklYTUU6XG4gICAgLy8gUmVjb3JkaW5nIHZpc2libGUgaWZcbiAgICAvLyB0aGVyZSBhcmUgYXQgbGVhc3QgMigrIDEgZm9jdXMpIHBhcnRpY2lwYW50c1xuICAgIC8vT2JqZWN0LmtleXMoY29ubmVjdGlvbi5lbXVjLm1lbWJlcnMpLmxlbmd0aCA+PSAzKTtcblxuICAgIGlmIChpc01vZGVyYXRvciAmJiBjb25maWcuZXRoZXJwYWRfYmFzZSkge1xuICAgICAgICBFdGhlcnBhZC5pbml0KCk7XG4gICAgfVxufTtcblxuZnVuY3Rpb24gb25QYXNzd29yZFJlcWl1cmVkKGNhbGxiYWNrKSB7XG4gICAgLy8gcGFzc3dvcmQgaXMgcmVxdWlyZWRcbiAgICBUb29sYmFyLmxvY2tMb2NrQnV0dG9uKCk7XG5cbiAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKG51bGwsXG4gICAgICAgICAgICAnPGgyPlBhc3N3b3JkIHJlcXVpcmVkPC9oMj4nICtcbiAgICAgICAgICAgICc8aW5wdXQgaWQ9XCJsb2NrS2V5XCIgdHlwZT1cInRleHRcIiBwbGFjZWhvbGRlcj1cInBhc3N3b3JkXCIgYXV0b2ZvY3VzPicsXG4gICAgICAgIHRydWUsXG4gICAgICAgIFwiT2tcIixcbiAgICAgICAgZnVuY3Rpb24gKGUsIHYsIG0sIGYpIHt9LFxuICAgICAgICBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2NrS2V5JykuZm9jdXMoKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGUsIHYsIG0sIGYpIHtcbiAgICAgICAgICAgIGlmICh2KSB7XG4gICAgICAgICAgICAgICAgdmFyIGxvY2tLZXkgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbG9ja0tleScpO1xuICAgICAgICAgICAgICAgIGlmIChsb2NrS2V5LnZhbHVlICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIFRvb2xiYXIuc2V0U2hhcmVkS2V5KGxvY2tLZXkudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjayhsb2NrS2V5LnZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICApO1xufVxuZnVuY3Rpb24gb25NdWNFbnRlcmVkKGppZCwgaWQsIGRpc3BsYXlOYW1lKSB7XG4gICAgbWVzc2FnZUhhbmRsZXIubm90aWZ5KGRpc3BsYXlOYW1lIHx8ICdTb21lYm9keScsXG4gICAgICAgICdjb25uZWN0ZWQnLFxuICAgICAgICAnY29ubmVjdGVkJyk7XG5cbiAgICAvLyBBZGQgUGVlcidzIGNvbnRhaW5lclxuICAgIFZpZGVvTGF5b3V0LmVuc3VyZVBlZXJDb250YWluZXJFeGlzdHMoamlkLGlkKTtcbn1cblxuZnVuY3Rpb24gb25NdWNQcmVzZW5jZVN0YXR1cyggamlkLCBpbmZvKSB7XG4gICAgVmlkZW9MYXlvdXQuc2V0UHJlc2VuY2VTdGF0dXMoXG4gICAgICAgICAgICAncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCksIGluZm8uc3RhdHVzKTtcbn1cblxuZnVuY3Rpb24gb25NdWNSb2xlQ2hhbmdlZChyb2xlLCBkaXNwbGF5TmFtZSkge1xuICAgIFZpZGVvTGF5b3V0LnNob3dNb2RlcmF0b3JJbmRpY2F0b3IoKTtcblxuICAgIGlmIChyb2xlID09PSAnbW9kZXJhdG9yJykge1xuICAgICAgICB2YXIgZGlzcGxheU5hbWUgPSBkaXNwbGF5TmFtZTtcbiAgICAgICAgaWYgKCFkaXNwbGF5TmFtZSkge1xuICAgICAgICAgICAgZGlzcGxheU5hbWUgPSAnU29tZWJvZHknO1xuICAgICAgICB9XG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyLm5vdGlmeShcbiAgICAgICAgICAgIGRpc3BsYXlOYW1lLFxuICAgICAgICAgICAgJ2Nvbm5lY3RlZCcsXG4gICAgICAgICAgICAgICAgJ01vZGVyYXRvciByaWdodHMgZ3JhbnRlZCB0byAnICsgZGlzcGxheU5hbWUgKyAnIScpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gb25BdXRoZW50aWNhdGlvblJlcXVpcmVkKGludGVydmFsQ2FsbGJhY2spIHtcbiAgICBBdXRoZW50aWNhdGlvbi5vcGVuQXV0aGVudGljYXRpb25EaWFsb2coXG4gICAgICAgIHJvb21OYW1lLCBpbnRlcnZhbENhbGxiYWNrLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBUb29sYmFyLmF1dGhlbnRpY2F0ZUNsaWNrZWQoKTtcbiAgICAgICAgfSk7XG59O1xuXG5cbmZ1bmN0aW9uIG9uTGFzdE5DaGFuZ2VkKG9sZFZhbHVlLCBuZXdWYWx1ZSkge1xuICAgIGlmIChjb25maWcubXV0ZUxvY2FsVmlkZW9JZk5vdEluTGFzdE4pIHtcbiAgICAgICAgc2V0VmlkZW9NdXRlKCFuZXdWYWx1ZSwgeyAnYnlVc2VyJzogZmFsc2UgfSk7XG4gICAgfVxufVxuXG5cblVJLnRvZ2dsZVNtaWxleXMgPSBmdW5jdGlvbiAoKSB7XG4gICAgQ2hhdC50b2dnbGVTbWlsZXlzKCk7XG59O1xuXG5VSS5nZXRTZXR0aW5ncyA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbn07XG5cblVJLnRvZ2dsZUZpbG1TdHJpcCA9IGZ1bmN0aW9uICgpIHtcbiAgICByZXR1cm4gQm90dG9tVG9vbGJhci50b2dnbGVGaWxtU3RyaXAoKTtcbn07XG5cblVJLnRvZ2dsZUNoYXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIEJvdHRvbVRvb2xiYXIudG9nZ2xlQ2hhdCgpO1xufTtcblxuVUkudG9nZ2xlQ29udGFjdExpc3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIEJvdHRvbVRvb2xiYXIudG9nZ2xlQ29udGFjdExpc3QoKTtcbn07XG5cblVJLmlucHV0RGlzcGxheU5hbWVIYW5kbGVyID0gZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgVmlkZW9MYXlvdXQuaW5wdXREaXNwbGF5TmFtZUhhbmRsZXIodmFsdWUpO1xufTtcblxuXG5VSS5nZXRMYXJnZVZpZGVvU3RhdGUgPSBmdW5jdGlvbigpXG57XG4gICAgcmV0dXJuIFZpZGVvTGF5b3V0LmdldExhcmdlVmlkZW9TdGF0ZSgpO1xufTtcblxuVUkuZ2VuZXJhdGVSb29tTmFtZSA9IGZ1bmN0aW9uKCkge1xuICAgIGlmKHJvb21OYW1lKVxuICAgICAgICByZXR1cm4gcm9vbU5hbWU7XG4gICAgdmFyIHJvb21ub2RlID0gbnVsbDtcbiAgICB2YXIgcGF0aCA9IHdpbmRvdy5sb2NhdGlvbi5wYXRobmFtZTtcblxuICAgIC8vIGRldGVybWluZGUgdGhlIHJvb20gbm9kZSBmcm9tIHRoZSB1cmxcbiAgICAvLyBUT0RPOiBqdXN0IHRoZSByb29tbm9kZSBvciB0aGUgd2hvbGUgYmFyZSBqaWQ/XG4gICAgaWYgKGNvbmZpZy5nZXRyb29tbm9kZSAmJiB0eXBlb2YgY29uZmlnLmdldHJvb21ub2RlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIC8vIGN1c3RvbSBmdW5jdGlvbiBtaWdodCBiZSByZXNwb25zaWJsZSBmb3IgZG9pbmcgdGhlIHB1c2hzdGF0ZVxuICAgICAgICByb29tbm9kZSA9IGNvbmZpZy5nZXRyb29tbm9kZShwYXRoKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICAvKiBmYWxsIGJhY2sgdG8gZGVmYXVsdCBzdHJhdGVneVxuICAgICAgICAgKiB0aGlzIGlzIG1ha2luZyBhc3N1bXB0aW9ucyBhYm91dCBob3cgdGhlIFVSTC0+cm9vbSBtYXBwaW5nIGhhcHBlbnMuXG4gICAgICAgICAqIEl0IGN1cnJlbnRseSBhc3N1bWVzIGRlcGxveW1lbnQgYXQgcm9vdCwgd2l0aCBhIHJld3JpdGUgbGlrZSB0aGVcbiAgICAgICAgICogZm9sbG93aW5nIG9uZSAoZm9yIG5naW54KTpcbiAgICAgICAgIGxvY2F0aW9uIH4gXi8oW2EtekEtWjAtOV0rKSQge1xuICAgICAgICAgcmV3cml0ZSBeLyguKikkIC8gYnJlYWs7XG4gICAgICAgICB9XG4gICAgICAgICAqL1xuICAgICAgICBpZiAocGF0aC5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICByb29tbm9kZSA9IHBhdGguc3Vic3RyKDEpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgd29yZCA9IFJvb21OYW1lR2VuZXJhdG9yLmdlbmVyYXRlUm9vbVdpdGhvdXRTZXBhcmF0b3IoKTtcbiAgICAgICAgICAgIHJvb21ub2RlID0gd29yZC50b0xvd2VyQ2FzZSgpO1xuXG4gICAgICAgICAgICB3aW5kb3cuaGlzdG9yeS5wdXNoU3RhdGUoJ1ZpZGVvQ2hhdCcsXG4gICAgICAgICAgICAgICAgICAgICdSb29tOiAnICsgd29yZCwgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lICsgd29yZCk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByb29tTmFtZSA9IHJvb21ub2RlICsgJ0AnICsgY29uZmlnLmhvc3RzLm11YztcbiAgICByZXR1cm4gcm9vbU5hbWU7XG59O1xuXG5cblVJLmNvbm5lY3Rpb25JbmRpY2F0b3JTaG93TW9yZSA9IGZ1bmN0aW9uKGlkKVxue1xuICAgIHJldHVybiBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tpZF0uc2hvd01vcmUoKTtcbn07XG5cblVJLmdldENyZWRlbnRpYWxzID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBzZXR0aW5ncyA9IHRoaXMuZ2V0U2V0dGluZ3MoKTtcbiAgICByZXR1cm4ge1xuICAgICAgICBib3NoOiBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnYm9zaFVSTCcpLnZhbHVlLFxuICAgICAgICBwYXNzd29yZDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Bhc3N3b3JkJykudmFsdWUsXG4gICAgICAgIGppZDogZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2ppZCcpLnZhbHVlLFxuICAgICAgICBlbWFpbDogc2V0dGluZ3MuZW1haWwsXG4gICAgICAgIGRpc3BsYXlOYW1lOiBzZXR0aW5ncy5kaXNwbGF5TmFtZSxcbiAgICAgICAgdWlkOiBzZXR0aW5ncy51aWRcbiAgICB9O1xufTtcblxuVUkuZGlzYWJsZUNvbm5lY3QgPSBmdW5jdGlvbiAoKSB7XG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2Nvbm5lY3QnKS5kaXNhYmxlZCA9IHRydWU7XG59O1xuXG5VSS5zaG93TG9naW5Qb3B1cCA9IGZ1bmN0aW9uKGNhbGxiYWNrKVxue1xuICAgIGNvbnNvbGUubG9nKCdwYXNzd29yZCBpcyByZXF1aXJlZCcpO1xuXG4gICAgVUkubWVzc2FnZUhhbmRsZXIub3BlblR3b0J1dHRvbkRpYWxvZyhudWxsLFxuICAgICAgICAgICAgJzxoMj5QYXNzd29yZCByZXF1aXJlZDwvaDI+JyArXG4gICAgICAgICAgICAnPGlucHV0IGlkPVwicGFzc3dvcmRyZXF1aXJlZC51c2VybmFtZVwiIHR5cGU9XCJ0ZXh0XCIgcGxhY2Vob2xkZXI9XCJ1c2VyQGRvbWFpbi5uZXRcIiBhdXRvZm9jdXM+JyArXG4gICAgICAgICAgICAnPGlucHV0IGlkPVwicGFzc3dvcmRyZXF1aXJlZC5wYXNzd29yZFwiIHR5cGU9XCJwYXNzd29yZFwiIHBsYWNlaG9sZGVyPVwidXNlciBwYXNzd29yZFwiPicsXG4gICAgICAgIHRydWUsXG4gICAgICAgIFwiT2tcIixcbiAgICAgICAgZnVuY3Rpb24gKGUsIHYsIG0sIGYpIHtcbiAgICAgICAgICAgIGlmICh2KSB7XG4gICAgICAgICAgICAgICAgdmFyIHVzZXJuYW1lID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Bhc3N3b3JkcmVxdWlyZWQudXNlcm5hbWUnKTtcbiAgICAgICAgICAgICAgICB2YXIgcGFzc3dvcmQgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncGFzc3dvcmRyZXF1aXJlZC5wYXNzd29yZCcpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHVzZXJuYW1lLnZhbHVlICE9PSBudWxsICYmIHBhc3N3b3JkLnZhbHVlICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2sodXNlcm5hbWUudmFsdWUsIHBhc3N3b3JkLnZhbHVlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3Bhc3N3b3JkcmVxdWlyZWQudXNlcm5hbWUnKS5mb2N1cygpO1xuICAgICAgICB9XG4gICAgKTtcbn1cblxuVUkuY2hlY2tGb3JOaWNrbmFtZUFuZEpvaW4gPSBmdW5jdGlvbiAoKSB7XG5cbiAgICBBdXRoZW50aWNhdGlvbi5jbG9zZUF1dGhlbnRpY2F0aW9uRGlhbG9nKCk7XG4gICAgQXV0aGVudGljYXRpb24uc3RvcEludGVydmFsKCk7XG5cbiAgICB2YXIgbmljayA9IG51bGw7XG4gICAgaWYgKGNvbmZpZy51c2VOaWNrcykge1xuICAgICAgICBuaWNrID0gd2luZG93LnByb21wdCgnWW91ciBuaWNrbmFtZSAob3B0aW9uYWwpJyk7XG4gICAgfVxuICAgIEFQUC54bXBwLmpvaW5Sb29tKHJvb21OYW1lLCBjb25maWcudXNlTmlja3MsIG5pY2spO1xufTtcblxuXG5mdW5jdGlvbiBkdW1wKGVsZW0sIGZpbGVuYW1lKSB7XG4gICAgZWxlbSA9IGVsZW0ucGFyZW50Tm9kZTtcbiAgICBlbGVtLmRvd25sb2FkID0gZmlsZW5hbWUgfHwgJ21lZXRsb2cuanNvbic7XG4gICAgZWxlbS5ocmVmID0gJ2RhdGE6YXBwbGljYXRpb24vanNvbjtjaGFyc2V0PXV0Zi04LFxcbic7XG4gICAgdmFyIGRhdGEgPSBBUFAueG1wcC5wb3B1bGF0ZURhdGEoKTtcbiAgICB2YXIgbWV0YWRhdGEgPSB7fTtcbiAgICBtZXRhZGF0YS50aW1lID0gbmV3IERhdGUoKTtcbiAgICBtZXRhZGF0YS51cmwgPSB3aW5kb3cubG9jYXRpb24uaHJlZjtcbiAgICBtZXRhZGF0YS51YSA9IG5hdmlnYXRvci51c2VyQWdlbnQ7XG4gICAgdmFyIGxvZyA9IEFQUC54bXBwLmdldExvZ2dlcigpO1xuICAgIGlmIChsb2cpIHtcbiAgICAgICAgbWV0YWRhdGEueG1wcCA9IGxvZztcbiAgICB9XG4gICAgZGF0YS5tZXRhZGF0YSA9IG1ldGFkYXRhO1xuICAgIGVsZW0uaHJlZiArPSBlbmNvZGVVUklDb21wb25lbnQoSlNPTi5zdHJpbmdpZnkoZGF0YSwgbnVsbCwgJyAgJykpO1xuICAgIHJldHVybiBmYWxzZTtcbn1cblxuVUkuZ2V0Um9vbU5hbWUgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIHJvb21OYW1lO1xufTtcblxuLyoqXG4gKiBNdXRlcy91bm11dGVzIHRoZSBsb2NhbCB2aWRlby5cbiAqL1xuVUkudG9nZ2xlVmlkZW8gPSBmdW5jdGlvbiAoKSB7XG4gICAgVUlVdGlsLmJ1dHRvbkNsaWNrKFwiI3ZpZGVvXCIsIFwiaWNvbi1jYW1lcmEgaWNvbi1jYW1lcmEtZGlzYWJsZWRcIik7XG5cbiAgICBzZXRWaWRlb011dGUoIUFQUC5SVEMubG9jYWxWaWRlby5pc011dGVkKCkpO1xufTtcblxuLyoqXG4gKiBNdXRlcyAvIHVubXV0ZXMgYXVkaW8gZm9yIHRoZSBsb2NhbCBwYXJ0aWNpcGFudC5cbiAqL1xuVUkudG9nZ2xlQXVkaW8gPSBmdW5jdGlvbigpIHtcbiAgICBVSS5zZXRBdWRpb011dGVkKCFBUFAuUlRDLmxvY2FsQXVkaW8uaXNNdXRlZCgpKTtcbn07XG5cbi8qKlxuICogU2V0cyBtdXRlZCBhdWRpbyBzdGF0ZSBmb3IgdGhlIGxvY2FsIHBhcnRpY2lwYW50LlxuICovXG5VSS5zZXRBdWRpb011dGVkID0gZnVuY3Rpb24gKG11dGUpIHtcblxuICAgIGlmKCFBUFAueG1wcC5zZXRBdWRpb011dGUobXV0ZSwgZnVuY3Rpb24gKCkge1xuICAgICAgICBWaWRlb0xheW91dC5zaG93TG9jYWxBdWRpb0luZGljYXRvcihtdXRlKTtcblxuICAgICAgICBVSVV0aWwuYnV0dG9uQ2xpY2soXCIjbXV0ZVwiLCBcImljb24tbWljcm9waG9uZSBpY29uLW1pYy1kaXNhYmxlZFwiKTtcbiAgICB9KSlcbiAgICB7XG4gICAgICAgIC8vIFdlIHN0aWxsIGNsaWNrIHRoZSBidXR0b24uXG4gICAgICAgIFVJVXRpbC5idXR0b25DbGljayhcIiNtdXRlXCIsIFwiaWNvbi1taWNyb3Bob25lIGljb24tbWljLWRpc2FibGVkXCIpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG59XG5cblVJLmFkZExpc3RlbmVyID0gZnVuY3Rpb24gKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgZXZlbnRFbWl0dGVyLm9uKHR5cGUsIGxpc3RlbmVyKTtcbn1cblxuVUkuY2xpY2tPblZpZGVvID0gZnVuY3Rpb24gKHZpZGVvTnVtYmVyKSB7XG4gICAgdmFyIHJlbW90ZVZpZGVvcyA9ICQoXCIudmlkZW9jb250YWluZXI6bm90KCNtaXhlZHN0cmVhbSlcIik7XG4gICAgaWYgKHJlbW90ZVZpZGVvcy5sZW5ndGggPiB2aWRlb051bWJlcikge1xuICAgICAgICByZW1vdGVWaWRlb3NbdmlkZW9OdW1iZXJdLmNsaWNrKCk7XG4gICAgfVxufVxuXG4vL1VzZWQgYnkgdG9ydHVyZVxuVUkuc2hvd1Rvb2xiYXIgPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuIFRvb2xiYXJUb2dnbGVyLnNob3dUb29sYmFyKCk7XG59XG5cbi8vVXNlZCBieSB0b3J0dXJlXG5VSS5kb2NrVG9vbGJhciA9IGZ1bmN0aW9uIChpc0RvY2spIHtcbiAgICByZXR1cm4gVG9vbGJhclRvZ2dsZXIuZG9ja1Rvb2xiYXIoaXNEb2NrKTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBVSTtcblxuIiwidmFyIENhbnZhc1V0aWwgPSByZXF1aXJlKFwiLi9DYW52YXNVdGlsc1wiKTtcblxuLyoqXG4gKiBUaGUgYXVkaW8gTGV2ZWxzIHBsdWdpbi5cbiAqL1xudmFyIEF1ZGlvTGV2ZWxzID0gKGZ1bmN0aW9uKG15KSB7XG4gICAgdmFyIGF1ZGlvTGV2ZWxDYW52YXNDYWNoZSA9IHt9O1xuXG4gICAgbXkuTE9DQUxfTEVWRUwgPSAnbG9jYWwnO1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgYXVkaW8gbGV2ZWwgY2FudmFzIGZvciB0aGUgZ2l2ZW4gcGVlckppZC4gSWYgdGhlIGNhbnZhc1xuICAgICAqIGRpZG4ndCBleGlzdCB3ZSBjcmVhdGUgaXQuXG4gICAgICovXG4gICAgbXkudXBkYXRlQXVkaW9MZXZlbENhbnZhcyA9IGZ1bmN0aW9uIChwZWVySmlkLCBWaWRlb0xheW91dCkge1xuICAgICAgICB2YXIgcmVzb3VyY2VKaWQgPSBudWxsO1xuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSBudWxsO1xuICAgICAgICBpZiAoIXBlZXJKaWQpXG4gICAgICAgICAgICB2aWRlb1NwYW5JZCA9ICdsb2NhbFZpZGVvQ29udGFpbmVyJztcbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKHBlZXJKaWQpO1xuXG4gICAgICAgICAgICB2aWRlb1NwYW5JZCA9ICdwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQ7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgdmlkZW9TcGFuID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodmlkZW9TcGFuSWQpO1xuXG4gICAgICAgIGlmICghdmlkZW9TcGFuKSB7XG4gICAgICAgICAgICBpZiAocmVzb3VyY2VKaWQpXG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIk5vIHZpZGVvIGVsZW1lbnQgZm9yIGppZFwiLCByZXNvdXJjZUppZCk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIk5vIHZpZGVvIGVsZW1lbnQgZm9yIGxvY2FsIHZpZGVvLlwiKTtcblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGF1ZGlvTGV2ZWxDYW52YXMgPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5jYW52YXMnKTtcblxuICAgICAgICB2YXIgdmlkZW9TcGFjZVdpZHRoID0gJCgnI3JlbW90ZVZpZGVvcycpLndpZHRoKCk7XG4gICAgICAgIHZhciB0aHVtYm5haWxTaXplID0gVmlkZW9MYXlvdXQuY2FsY3VsYXRlVGh1bWJuYWlsU2l6ZSh2aWRlb1NwYWNlV2lkdGgpO1xuICAgICAgICB2YXIgdGh1bWJuYWlsV2lkdGggPSB0aHVtYm5haWxTaXplWzBdO1xuICAgICAgICB2YXIgdGh1bWJuYWlsSGVpZ2h0ID0gdGh1bWJuYWlsU2l6ZVsxXTtcblxuICAgICAgICBpZiAoIWF1ZGlvTGV2ZWxDYW52YXMgfHwgYXVkaW9MZXZlbENhbnZhcy5sZW5ndGggPT09IDApIHtcblxuICAgICAgICAgICAgYXVkaW9MZXZlbENhbnZhcyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2NhbnZhcycpO1xuICAgICAgICAgICAgYXVkaW9MZXZlbENhbnZhcy5jbGFzc05hbWUgPSBcImF1ZGlvbGV2ZWxcIjtcbiAgICAgICAgICAgIGF1ZGlvTGV2ZWxDYW52YXMuc3R5bGUuYm90dG9tID0gXCItXCIgKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBLzIgKyBcInB4XCI7XG4gICAgICAgICAgICBhdWRpb0xldmVsQ2FudmFzLnN0eWxlLmxlZnQgPSBcIi1cIiArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEvMiArIFwicHhcIjtcbiAgICAgICAgICAgIHJlc2l6ZUF1ZGlvTGV2ZWxDYW52YXMoIGF1ZGlvTGV2ZWxDYW52YXMsXG4gICAgICAgICAgICAgICAgICAgIHRodW1ibmFpbFdpZHRoLFxuICAgICAgICAgICAgICAgICAgICB0aHVtYm5haWxIZWlnaHQpO1xuXG4gICAgICAgICAgICB2aWRlb1NwYW4uYXBwZW5kQ2hpbGQoYXVkaW9MZXZlbENhbnZhcyk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBhdWRpb0xldmVsQ2FudmFzID0gYXVkaW9MZXZlbENhbnZhcy5nZXQoMCk7XG5cbiAgICAgICAgICAgIHJlc2l6ZUF1ZGlvTGV2ZWxDYW52YXMoIGF1ZGlvTGV2ZWxDYW52YXMsXG4gICAgICAgICAgICAgICAgICAgIHRodW1ibmFpbFdpZHRoLFxuICAgICAgICAgICAgICAgICAgICB0aHVtYm5haWxIZWlnaHQpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIGF1ZGlvIGxldmVsIFVJIGZvciB0aGUgZ2l2ZW4gcmVzb3VyY2VKaWQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gcmVzb3VyY2VKaWQgdGhlIHJlc291cmNlIGppZCBpbmRpY2F0aW5nIHRoZSB2aWRlbyBlbGVtZW50IGZvclxuICAgICAqIHdoaWNoIHdlIGRyYXcgdGhlIGF1ZGlvIGxldmVsXG4gICAgICogQHBhcmFtIGF1ZGlvTGV2ZWwgdGhlIG5ld0F1ZGlvIGxldmVsIHRvIHJlbmRlclxuICAgICAqL1xuICAgIG15LnVwZGF0ZUF1ZGlvTGV2ZWwgPSBmdW5jdGlvbiAocmVzb3VyY2VKaWQsIGF1ZGlvTGV2ZWwsIGxhcmdlVmlkZW9SZXNvdXJjZUppZCkge1xuICAgICAgICBkcmF3QXVkaW9MZXZlbENhbnZhcyhyZXNvdXJjZUppZCwgYXVkaW9MZXZlbCk7XG5cbiAgICAgICAgdmFyIHZpZGVvU3BhbklkID0gZ2V0VmlkZW9TcGFuSWQocmVzb3VyY2VKaWQpO1xuXG4gICAgICAgIHZhciBhdWRpb0xldmVsQ2FudmFzID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+Y2FudmFzJykuZ2V0KDApO1xuXG4gICAgICAgIGlmICghYXVkaW9MZXZlbENhbnZhcylcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB2YXIgZHJhd0NvbnRleHQgPSBhdWRpb0xldmVsQ2FudmFzLmdldENvbnRleHQoJzJkJyk7XG5cbiAgICAgICAgdmFyIGNhbnZhc0NhY2hlID0gYXVkaW9MZXZlbENhbnZhc0NhY2hlW3Jlc291cmNlSmlkXTtcblxuICAgICAgICBkcmF3Q29udGV4dC5jbGVhclJlY3QgKDAsIDAsXG4gICAgICAgICAgICAgICAgYXVkaW9MZXZlbENhbnZhcy53aWR0aCwgYXVkaW9MZXZlbENhbnZhcy5oZWlnaHQpO1xuICAgICAgICBkcmF3Q29udGV4dC5kcmF3SW1hZ2UoY2FudmFzQ2FjaGUsIDAsIDApO1xuXG4gICAgICAgIGlmKHJlc291cmNlSmlkID09PSBBdWRpb0xldmVscy5MT0NBTF9MRVZFTCkge1xuICAgICAgICAgICAgaWYoIUFQUC54bXBwLm15SmlkKCkpIHtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXNvdXJjZUppZCA9IEFQUC54bXBwLm15UmVzb3VyY2UoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKHJlc291cmNlSmlkICA9PT0gbGFyZ2VWaWRlb1Jlc291cmNlSmlkKSB7XG4gICAgICAgICAgICBBdWRpb0xldmVscy51cGRhdGVBY3RpdmVTcGVha2VyQXVkaW9MZXZlbChhdWRpb0xldmVsKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBteS51cGRhdGVBY3RpdmVTcGVha2VyQXVkaW9MZXZlbCA9IGZ1bmN0aW9uKGF1ZGlvTGV2ZWwpIHtcbiAgICAgICAgdmFyIGRyYXdDb250ZXh0ID0gJCgnI2FjdGl2ZVNwZWFrZXJBdWRpb0xldmVsJylbMF0uZ2V0Q29udGV4dCgnMmQnKTtcbiAgICAgICAgdmFyIHIgPSBpbnRlcmZhY2VDb25maWcuQUNUSVZFX1NQRUFLRVJfQVZBVEFSX1NJWkUgLyAyO1xuICAgICAgICB2YXIgY2VudGVyID0gKGludGVyZmFjZUNvbmZpZy5BQ1RJVkVfU1BFQUtFUl9BVkFUQVJfU0laRSArIHIpIC8gMjtcblxuICAgICAgICAvLyBTYXZlIHRoZSBwcmV2aW91cyBzdGF0ZSBvZiB0aGUgY29udGV4dC5cbiAgICAgICAgZHJhd0NvbnRleHQuc2F2ZSgpO1xuXG4gICAgICAgIGRyYXdDb250ZXh0LmNsZWFyUmVjdCgwLCAwLCAzMDAsIDMwMCk7XG5cbiAgICAgICAgLy8gRHJhdyBhIGNpcmNsZS5cbiAgICAgICAgZHJhd0NvbnRleHQuYXJjKGNlbnRlciwgY2VudGVyLCByLCAwLCAyICogTWF0aC5QSSk7XG5cbiAgICAgICAgLy8gQWRkIGEgc2hhZG93IGFyb3VuZCB0aGUgY2lyY2xlXG4gICAgICAgIGRyYXdDb250ZXh0LnNoYWRvd0NvbG9yID0gaW50ZXJmYWNlQ29uZmlnLlNIQURPV19DT0xPUjtcbiAgICAgICAgZHJhd0NvbnRleHQuc2hhZG93Qmx1ciA9IGdldFNoYWRvd0xldmVsKGF1ZGlvTGV2ZWwpO1xuICAgICAgICBkcmF3Q29udGV4dC5zaGFkb3dPZmZzZXRYID0gMDtcbiAgICAgICAgZHJhd0NvbnRleHQuc2hhZG93T2Zmc2V0WSA9IDA7XG5cbiAgICAgICAgLy8gRmlsbCB0aGUgc2hhcGUuXG4gICAgICAgIGRyYXdDb250ZXh0LmZpbGwoKTtcblxuICAgICAgICBkcmF3Q29udGV4dC5zYXZlKCk7XG5cbiAgICAgICAgZHJhd0NvbnRleHQucmVzdG9yZSgpO1xuXG5cbiAgICAgICAgZHJhd0NvbnRleHQuYXJjKGNlbnRlciwgY2VudGVyLCByLCAwLCAyICogTWF0aC5QSSk7XG5cbiAgICAgICAgZHJhd0NvbnRleHQuY2xpcCgpO1xuICAgICAgICBkcmF3Q29udGV4dC5jbGVhclJlY3QoMCwgMCwgMjc3LCAyMDApO1xuXG4gICAgICAgIC8vIFJlc3RvcmUgdGhlIHByZXZpb3VzIGNvbnRleHQgc3RhdGUuXG4gICAgICAgIGRyYXdDb250ZXh0LnJlc3RvcmUoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmVzaXplcyB0aGUgZ2l2ZW4gYXVkaW8gbGV2ZWwgY2FudmFzIHRvIG1hdGNoIHRoZSBnaXZlbiB0aHVtYm5haWwgc2l6ZS5cbiAgICAgKi9cbiAgICBmdW5jdGlvbiByZXNpemVBdWRpb0xldmVsQ2FudmFzKGF1ZGlvTGV2ZWxDYW52YXMsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHVtYm5haWxXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRodW1ibmFpbEhlaWdodCkge1xuICAgICAgICBhdWRpb0xldmVsQ2FudmFzLndpZHRoID0gdGh1bWJuYWlsV2lkdGggKyBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBO1xuICAgICAgICBhdWRpb0xldmVsQ2FudmFzLmhlaWdodCA9IHRodW1ibmFpbEhlaWdodCArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkE7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogRHJhd3MgdGhlIGF1ZGlvIGxldmVsIGNhbnZhcyBpbnRvIHRoZSBjYWNoZWQgY2FudmFzIG9iamVjdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSByZXNvdXJjZUppZCB0aGUgcmVzb3VyY2UgamlkIGluZGljYXRpbmcgdGhlIHZpZGVvIGVsZW1lbnQgZm9yXG4gICAgICogd2hpY2ggd2UgZHJhdyB0aGUgYXVkaW8gbGV2ZWxcbiAgICAgKiBAcGFyYW0gYXVkaW9MZXZlbCB0aGUgbmV3QXVkaW8gbGV2ZWwgdG8gcmVuZGVyXG4gICAgICovXG4gICAgZnVuY3Rpb24gZHJhd0F1ZGlvTGV2ZWxDYW52YXMocmVzb3VyY2VKaWQsIGF1ZGlvTGV2ZWwpIHtcbiAgICAgICAgaWYgKCFhdWRpb0xldmVsQ2FudmFzQ2FjaGVbcmVzb3VyY2VKaWRdKSB7XG5cbiAgICAgICAgICAgIHZhciB2aWRlb1NwYW5JZCA9IGdldFZpZGVvU3BhbklkKHJlc291cmNlSmlkKTtcblxuICAgICAgICAgICAgdmFyIGF1ZGlvTGV2ZWxDYW52YXNPcmlnID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+Y2FudmFzJykuZ2V0KDApO1xuXG4gICAgICAgICAgICAvKlxuICAgICAgICAgICAgICogRklYTUUgVGVzdGluZyBoYXMgc2hvd24gdGhhdCBhdWRpb0xldmVsQ2FudmFzT3JpZyBtYXkgbm90IGV4aXN0LlxuICAgICAgICAgICAgICogSW4gc3VjaCBhIGNhc2UsIHRoZSBtZXRob2QgQ2FudmFzVXRpbC5jbG9uZUNhbnZhcyBtYXkgdGhyb3cgYW5cbiAgICAgICAgICAgICAqIGVycm9yLiBTaW5jZSBhdWRpbyBsZXZlbHMgYXJlIGZyZXF1ZW50bHkgdXBkYXRlZCwgdGhlIGVycm9ycyBoYXZlXG4gICAgICAgICAgICAgKiBiZWVuIG9ic2VydmVkIHRvIHBpbGUgaW50byB0aGUgY29uc29sZSwgc3RyYWluIHRoZSBDUFUuXG4gICAgICAgICAgICAgKi9cbiAgICAgICAgICAgIGlmIChhdWRpb0xldmVsQ2FudmFzT3JpZylcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBhdWRpb0xldmVsQ2FudmFzQ2FjaGVbcmVzb3VyY2VKaWRdXG4gICAgICAgICAgICAgICAgICAgID0gQ2FudmFzVXRpbC5jbG9uZUNhbnZhcyhhdWRpb0xldmVsQ2FudmFzT3JpZyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgY2FudmFzID0gYXVkaW9MZXZlbENhbnZhc0NhY2hlW3Jlc291cmNlSmlkXTtcblxuICAgICAgICBpZiAoIWNhbnZhcylcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB2YXIgZHJhd0NvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dCgnMmQnKTtcblxuICAgICAgICBkcmF3Q29udGV4dC5jbGVhclJlY3QoMCwgMCwgY2FudmFzLndpZHRoLCBjYW52YXMuaGVpZ2h0KTtcblxuICAgICAgICB2YXIgc2hhZG93TGV2ZWwgPSBnZXRTaGFkb3dMZXZlbChhdWRpb0xldmVsKTtcblxuICAgICAgICBpZiAoc2hhZG93TGV2ZWwgPiAwKVxuICAgICAgICAgICAgLy8gZHJhd0NvbnRleHQsIHgsIHksIHcsIGgsIHIsIHNoYWRvd0NvbG9yLCBzaGFkb3dMZXZlbFxuICAgICAgICAgICAgQ2FudmFzVXRpbC5kcmF3Um91bmRSZWN0R2xvdyggICBkcmF3Q29udGV4dCxcbiAgICAgICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBLzIsIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEvMixcbiAgICAgICAgICAgICAgICBjYW52YXMud2lkdGggLSBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBLFxuICAgICAgICAgICAgICAgIGNhbnZhcy5oZWlnaHQgLSBpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBLFxuICAgICAgICAgICAgICAgIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfUkFESVVTLFxuICAgICAgICAgICAgICAgIGludGVyZmFjZUNvbmZpZy5TSEFET1dfQ09MT1IsXG4gICAgICAgICAgICAgICAgc2hhZG93TGV2ZWwpO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHNoYWRvdy9nbG93IGxldmVsIGZvciB0aGUgZ2l2ZW4gYXVkaW8gbGV2ZWwuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gYXVkaW9MZXZlbCB0aGUgYXVkaW8gbGV2ZWwgZnJvbSB3aGljaCB3ZSBkZXRlcm1pbmUgdGhlIHNoYWRvd1xuICAgICAqIGxldmVsXG4gICAgICovXG4gICAgZnVuY3Rpb24gZ2V0U2hhZG93TGV2ZWwgKGF1ZGlvTGV2ZWwpIHtcbiAgICAgICAgdmFyIHNoYWRvd0xldmVsID0gMDtcblxuICAgICAgICBpZiAoYXVkaW9MZXZlbCA8PSAwLjMpIHtcbiAgICAgICAgICAgIHNoYWRvd0xldmVsID0gTWF0aC5yb3VuZChpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBLzIqKGF1ZGlvTGV2ZWwvMC4zKSk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZiAoYXVkaW9MZXZlbCA8PSAwLjYpIHtcbiAgICAgICAgICAgIHNoYWRvd0xldmVsID0gTWF0aC5yb3VuZChpbnRlcmZhY2VDb25maWcuQ0FOVkFTX0VYVFJBLzIqKChhdWRpb0xldmVsIC0gMC4zKSAvIDAuMykpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgc2hhZG93TGV2ZWwgPSBNYXRoLnJvdW5kKGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEvMiooKGF1ZGlvTGV2ZWwgLSAwLjYpIC8gMC40KSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHNoYWRvd0xldmVsO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHZpZGVvIHNwYW4gaWQgY29ycmVzcG9uZGluZyB0byB0aGUgZ2l2ZW4gcmVzb3VyY2VKaWQgb3IgbG9jYWxcbiAgICAgKiB1c2VyLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIGdldFZpZGVvU3BhbklkKHJlc291cmNlSmlkKSB7XG4gICAgICAgIHZhciB2aWRlb1NwYW5JZCA9IG51bGw7XG4gICAgICAgIGlmIChyZXNvdXJjZUppZCA9PT0gQXVkaW9MZXZlbHMuTE9DQUxfTEVWRUxcbiAgICAgICAgICAgICAgICB8fCAoQVBQLnhtcHAubXlSZXNvdXJjZSgpICYmIHJlc291cmNlSmlkXG4gICAgICAgICAgICAgICAgICAgID09PSBBUFAueG1wcC5teVJlc291cmNlKCkpKVxuICAgICAgICAgICAgdmlkZW9TcGFuSWQgPSAnbG9jYWxWaWRlb0NvbnRhaW5lcic7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZDtcblxuICAgICAgICByZXR1cm4gdmlkZW9TcGFuSWQ7XG4gICAgfVxuXG4gICAgLyoqXG4gICAgICogSW5kaWNhdGVzIHRoYXQgdGhlIHJlbW90ZSB2aWRlbyBoYXMgYmVlbiByZXNpemVkLlxuICAgICAqL1xuICAgICQoZG9jdW1lbnQpLmJpbmQoJ3JlbW90ZXZpZGVvLnJlc2l6ZWQnLCBmdW5jdGlvbiAoZXZlbnQsIHdpZHRoLCBoZWlnaHQpIHtcbiAgICAgICAgdmFyIHJlc2l6ZWQgPSBmYWxzZTtcbiAgICAgICAgJCgnI3JlbW90ZVZpZGVvcz5zcGFuPmNhbnZhcycpLmVhY2goZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgY2FudmFzID0gJCh0aGlzKS5nZXQoMCk7XG4gICAgICAgICAgICBpZiAoY2FudmFzLndpZHRoICE9PSB3aWR0aCArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEpIHtcbiAgICAgICAgICAgICAgICBjYW52YXMud2lkdGggPSB3aWR0aCArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkE7XG4gICAgICAgICAgICAgICAgcmVzaXplZCA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmIChjYW52YXMuaGVpZ2ggIT09IGhlaWdodCArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkEpIHtcbiAgICAgICAgICAgICAgICBjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0ICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQTtcbiAgICAgICAgICAgICAgICByZXNpemVkID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgaWYgKHJlc2l6ZWQpXG4gICAgICAgICAgICBPYmplY3Qua2V5cyhhdWRpb0xldmVsQ2FudmFzQ2FjaGUpLmZvckVhY2goZnVuY3Rpb24gKHJlc291cmNlSmlkKSB7XG4gICAgICAgICAgICAgICAgYXVkaW9MZXZlbENhbnZhc0NhY2hlW3Jlc291cmNlSmlkXS53aWR0aFxuICAgICAgICAgICAgICAgICAgICA9IHdpZHRoICsgaW50ZXJmYWNlQ29uZmlnLkNBTlZBU19FWFRSQTtcbiAgICAgICAgICAgICAgICBhdWRpb0xldmVsQ2FudmFzQ2FjaGVbcmVzb3VyY2VKaWRdLmhlaWdodFxuICAgICAgICAgICAgICAgICAgICA9IGhlaWdodCArIGludGVyZmFjZUNvbmZpZy5DQU5WQVNfRVhUUkE7XG4gICAgICAgICAgICB9KTtcbiAgICB9KTtcblxuICAgIHJldHVybiBteTtcblxufSkoQXVkaW9MZXZlbHMgfHwge30pO1xuXG5tb2R1bGUuZXhwb3J0cyA9IEF1ZGlvTGV2ZWxzOyIsIi8qKlxuICogVXRpbGl0eSBjbGFzcyBmb3IgZHJhd2luZyBjYW52YXMgc2hhcGVzLlxuICovXG52YXIgQ2FudmFzVXRpbCA9IChmdW5jdGlvbihteSkge1xuXG4gICAgLyoqXG4gICAgICogRHJhd3MgYSByb3VuZCByZWN0YW5nbGUgd2l0aCBhIGdsb3cuIFRoZSBnbG93V2lkdGggaW5kaWNhdGVzIHRoZSBkZXB0aFxuICAgICAqIG9mIHRoZSBnbG93LlxuICAgICAqXG4gICAgICogQHBhcmFtIGRyYXdDb250ZXh0IHRoZSBjb250ZXh0IG9mIHRoZSBjYW52YXMgdG8gZHJhdyB0b1xuICAgICAqIEBwYXJhbSB4IHRoZSB4IGNvb3JkaW5hdGUgb2YgdGhlIHJvdW5kIHJlY3RhbmdsZVxuICAgICAqIEBwYXJhbSB5IHRoZSB5IGNvb3JkaW5hdGUgb2YgdGhlIHJvdW5kIHJlY3RhbmdsZVxuICAgICAqIEBwYXJhbSB3IHRoZSB3aWR0aCBvZiB0aGUgcm91bmQgcmVjdGFuZ2xlXG4gICAgICogQHBhcmFtIGggdGhlIGhlaWdodCBvZiB0aGUgcm91bmQgcmVjdGFuZ2xlXG4gICAgICogQHBhcmFtIGdsb3dDb2xvciB0aGUgY29sb3Igb2YgdGhlIGdsb3dcbiAgICAgKiBAcGFyYW0gZ2xvd1dpZHRoIHRoZSB3aWR0aCBvZiB0aGUgZ2xvd1xuICAgICAqL1xuICAgIG15LmRyYXdSb3VuZFJlY3RHbG93XG4gICAgICAgID0gZnVuY3Rpb24oZHJhd0NvbnRleHQsIHgsIHksIHcsIGgsIHIsIGdsb3dDb2xvciwgZ2xvd1dpZHRoKSB7XG5cbiAgICAgICAgLy8gU2F2ZSB0aGUgcHJldmlvdXMgc3RhdGUgb2YgdGhlIGNvbnRleHQuXG4gICAgICAgIGRyYXdDb250ZXh0LnNhdmUoKTtcblxuICAgICAgICBpZiAodyA8IDIgKiByKSByID0gdyAvIDI7XG4gICAgICAgIGlmIChoIDwgMiAqIHIpIHIgPSBoIC8gMjtcblxuICAgICAgICAvLyBEcmF3IGEgcm91bmQgcmVjdGFuZ2xlLlxuICAgICAgICBkcmF3Q29udGV4dC5iZWdpblBhdGgoKTtcbiAgICAgICAgZHJhd0NvbnRleHQubW92ZVRvKHgrciwgeSk7XG4gICAgICAgIGRyYXdDb250ZXh0LmFyY1RvKHgrdywgeSwgICB4K3csIHkraCwgcik7XG4gICAgICAgIGRyYXdDb250ZXh0LmFyY1RvKHgrdywgeStoLCB4LCAgIHkraCwgcik7XG4gICAgICAgIGRyYXdDb250ZXh0LmFyY1RvKHgsICAgeStoLCB4LCAgIHksICAgcik7XG4gICAgICAgIGRyYXdDb250ZXh0LmFyY1RvKHgsICAgeSwgICB4K3csIHksICAgcik7XG4gICAgICAgIGRyYXdDb250ZXh0LmNsb3NlUGF0aCgpO1xuXG4gICAgICAgIC8vIEFkZCBhIHNoYWRvdyBhcm91bmQgdGhlIHJlY3RhbmdsZVxuICAgICAgICBkcmF3Q29udGV4dC5zaGFkb3dDb2xvciA9IGdsb3dDb2xvcjtcbiAgICAgICAgZHJhd0NvbnRleHQuc2hhZG93Qmx1ciA9IGdsb3dXaWR0aDtcbiAgICAgICAgZHJhd0NvbnRleHQuc2hhZG93T2Zmc2V0WCA9IDA7XG4gICAgICAgIGRyYXdDb250ZXh0LnNoYWRvd09mZnNldFkgPSAwO1xuXG4gICAgICAgIC8vIEZpbGwgdGhlIHNoYXBlLlxuICAgICAgICBkcmF3Q29udGV4dC5maWxsKCk7XG5cbiAgICAgICAgZHJhd0NvbnRleHQuc2F2ZSgpO1xuXG4gICAgICAgIGRyYXdDb250ZXh0LnJlc3RvcmUoKTtcblxuLy8gICAgICAxKSBVbmNvbW1lbnQgdGhpcyBsaW5lIHRvIHVzZSBDb21wb3NpdGUgT3BlcmF0aW9uLCB3aGljaCBpcyBkb2luZyB0aGVcbi8vICAgICAgc2FtZSBhcyB0aGUgY2xpcCBmdW5jdGlvbiBiZWxvdyBhbmQgaXMgYWxzbyBhbnRpYWxpYXNpbmcgdGhlIHJvdW5kXG4vLyAgICAgIGJvcmRlciwgYnV0IGlzIHNhaWQgdG8gYmUgbGVzcyBmYXN0IHBlcmZvcm1hbmNlIHdpc2UuXG5cbi8vICAgICAgZHJhd0NvbnRleHQuZ2xvYmFsQ29tcG9zaXRlT3BlcmF0aW9uPSdkZXN0aW5hdGlvbi1vdXQnO1xuXG4gICAgICAgIGRyYXdDb250ZXh0LmJlZ2luUGF0aCgpO1xuICAgICAgICBkcmF3Q29udGV4dC5tb3ZlVG8oeCtyLCB5KTtcbiAgICAgICAgZHJhd0NvbnRleHQuYXJjVG8oeCt3LCB5LCAgIHgrdywgeStoLCByKTtcbiAgICAgICAgZHJhd0NvbnRleHQuYXJjVG8oeCt3LCB5K2gsIHgsICAgeStoLCByKTtcbiAgICAgICAgZHJhd0NvbnRleHQuYXJjVG8oeCwgICB5K2gsIHgsICAgeSwgICByKTtcbiAgICAgICAgZHJhd0NvbnRleHQuYXJjVG8oeCwgICB5LCAgIHgrdywgeSwgICByKTtcbiAgICAgICAgZHJhd0NvbnRleHQuY2xvc2VQYXRoKCk7XG5cbi8vICAgICAgMikgVW5jb21tZW50IHRoaXMgbGluZSB0byB1c2UgQ29tcG9zaXRlIE9wZXJhdGlvbiwgd2hpY2ggaXMgZG9pbmcgdGhlXG4vLyAgICAgIHNhbWUgYXMgdGhlIGNsaXAgZnVuY3Rpb24gYmVsb3cgYW5kIGlzIGFsc28gYW50aWFsaWFzaW5nIHRoZSByb3VuZFxuLy8gICAgICBib3JkZXIsIGJ1dCBpcyBzYWlkIHRvIGJlIGxlc3MgZmFzdCBwZXJmb3JtYW5jZSB3aXNlLlxuXG4vLyAgICAgIGRyYXdDb250ZXh0LmZpbGwoKTtcblxuICAgICAgICAvLyBDb21tZW50IHRoZXNlIHR3byBsaW5lcyBpZiBjaG9vc2luZyB0byBkbyB0aGUgc2FtZSB3aXRoIGNvbXBvc2l0ZVxuICAgICAgICAvLyBvcGVyYXRpb24gYWJvdmUgMSBhbmQgMi5cbiAgICAgICAgZHJhd0NvbnRleHQuY2xpcCgpO1xuICAgICAgICBkcmF3Q29udGV4dC5jbGVhclJlY3QoMCwgMCwgMjc3LCAyMDApO1xuXG4gICAgICAgIC8vIFJlc3RvcmUgdGhlIHByZXZpb3VzIGNvbnRleHQgc3RhdGUuXG4gICAgICAgIGRyYXdDb250ZXh0LnJlc3RvcmUoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2xvbmVzIHRoZSBnaXZlbiBjYW52YXMuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHRoZSBuZXcgY2xvbmVkIGNhbnZhcy5cbiAgICAgKi9cbiAgICBteS5jbG9uZUNhbnZhcyA9IGZ1bmN0aW9uIChvbGRDYW52YXMpIHtcbiAgICAgICAgLypcbiAgICAgICAgICogRklYTUUgVGVzdGluZyBoYXMgc2hvd24gdGhhdCBvbGRDYW52YXMgbWF5IG5vdCBleGlzdC4gSW4gc3VjaCBhIGNhc2UsXG4gICAgICAgICAqIHRoZSBtZXRob2QgQ2FudmFzVXRpbC5jbG9uZUNhbnZhcyBtYXkgdGhyb3cgYW4gZXJyb3IuIFNpbmNlIGF1ZGlvXG4gICAgICAgICAqIGxldmVscyBhcmUgZnJlcXVlbnRseSB1cGRhdGVkLCB0aGUgZXJyb3JzIGhhdmUgYmVlbiBvYnNlcnZlZCB0byBwaWxlXG4gICAgICAgICAqIGludG8gdGhlIGNvbnNvbGUsIHN0cmFpbiB0aGUgQ1BVLlxuICAgICAgICAgKi9cbiAgICAgICAgaWYgKCFvbGRDYW52YXMpXG4gICAgICAgICAgICByZXR1cm4gb2xkQ2FudmFzO1xuXG4gICAgICAgIC8vY3JlYXRlIGEgbmV3IGNhbnZhc1xuICAgICAgICB2YXIgbmV3Q2FudmFzID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnY2FudmFzJyk7XG4gICAgICAgIHZhciBjb250ZXh0ID0gbmV3Q2FudmFzLmdldENvbnRleHQoJzJkJyk7XG5cbiAgICAgICAgLy9zZXQgZGltZW5zaW9uc1xuICAgICAgICBuZXdDYW52YXMud2lkdGggPSBvbGRDYW52YXMud2lkdGg7XG4gICAgICAgIG5ld0NhbnZhcy5oZWlnaHQgPSBvbGRDYW52YXMuaGVpZ2h0O1xuXG4gICAgICAgIC8vYXBwbHkgdGhlIG9sZCBjYW52YXMgdG8gdGhlIG5ldyBvbmVcbiAgICAgICAgY29udGV4dC5kcmF3SW1hZ2Uob2xkQ2FudmFzLCAwLCAwKTtcblxuICAgICAgICAvL3JldHVybiB0aGUgbmV3IGNhbnZhc1xuICAgICAgICByZXR1cm4gbmV3Q2FudmFzO1xuICAgIH07XG5cbiAgICByZXR1cm4gbXk7XG59KShDYW52YXNVdGlsIHx8IHt9KTtcblxubW9kdWxlLmV4cG9ydHMgPSBDYW52YXNVdGlsOyIsIi8qIEluaXRpYWwgXCJhdXRoZW50aWNhdGlvbiByZXF1aXJlZFwiIGRpYWxvZyAqL1xudmFyIGF1dGhEaWFsb2cgPSBudWxsO1xuLyogTG9vcCByZXRyeSBJRCB0aGF0IHdpdHMgZm9yIG90aGVyIHVzZXIgdG8gY3JlYXRlIHRoZSByb29tICovXG52YXIgYXV0aFJldHJ5SWQgPSBudWxsO1xudmFyIGF1dGhlbnRpY2F0aW9uV2luZG93ID0gbnVsbDtcblxudmFyIEF1dGhlbnRpY2F0aW9uID0ge1xuICAgIG9wZW5BdXRoZW50aWNhdGlvbkRpYWxvZzogZnVuY3Rpb24gKHJvb21OYW1lLCBpbnRlcnZhbENhbGxiYWNrLCBjYWxsYmFjaykge1xuICAgICAgICAvLyBUaGlzIGlzIHRoZSBsb29wIHRoYXQgd2lsbCB3YWl0IGZvciB0aGUgcm9vbSB0byBiZSBjcmVhdGVkIGJ5XG4gICAgICAgIC8vIHNvbWVvbmUgZWxzZS4gJ2F1dGhfcmVxdWlyZWQubW9kZXJhdG9yJyB3aWxsIGJyaW5nIHVzIGJhY2sgaGVyZS5cbiAgICAgICAgYXV0aFJldHJ5SWQgPSB3aW5kb3cuc2V0VGltZW91dChpbnRlcnZhbENhbGxiYWNrICwgNTAwMCk7XG4gICAgICAgIC8vIFNob3cgcHJvbXB0IG9ubHkgaWYgaXQncyBub3Qgb3BlblxuICAgICAgICBpZiAoYXV0aERpYWxvZyAhPT0gbnVsbCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgICAgIC8vIGV4dHJhY3Qgcm9vbSBuYW1lIGZyb20gJ3Jvb21AbXVjLnNlcnZlci5uZXQnXG4gICAgICAgIHZhciByb29tID0gcm9vbU5hbWUuc3Vic3RyKDAsIHJvb21OYW1lLmluZGV4T2YoJ0AnKSk7XG5cbiAgICAgICAgYXV0aERpYWxvZyA9IG1lc3NhZ2VIYW5kbGVyLm9wZW5EaWFsb2coXG4gICAgICAgICAgICAnU3RvcCcsXG4gICAgICAgICAgICAgICAgJ0F1dGhlbnRpY2F0aW9uIGlzIHJlcXVpcmVkIHRvIGNyZWF0ZSByb29tOjxici8+PGI+JyArIHJvb20gK1xuICAgICAgICAgICAgICAgICc8L2I+PC9icj4gWW91IGNhbiBlaXRoZXIgYXV0aGVudGljYXRlIHRvIGNyZWF0ZSB0aGUgcm9vbSBvciAnICtcbiAgICAgICAgICAgICAgICAnanVzdCB3YWl0IGZvciBzb21lb25lIGVsc2UgdG8gZG8gc28uJyxcbiAgICAgICAgICAgIHRydWUsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgQXV0aGVudGljYXRlOiAnYXV0aE5vdydcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAob25TdWJtaXRFdmVudCwgc3VibWl0VmFsdWUpIHtcblxuICAgICAgICAgICAgICAgIC8vIERvIG5vdCBjbG9zZSB0aGUgZGlhbG9nIHlldFxuICAgICAgICAgICAgICAgIG9uU3VibWl0RXZlbnQucHJldmVudERlZmF1bHQoKTtcblxuICAgICAgICAgICAgICAgIC8vIE9wZW4gbG9naW4gcG9wdXBcbiAgICAgICAgICAgICAgICBpZiAoc3VibWl0VmFsdWUgPT09ICdhdXRoTm93Jykge1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9LFxuICAgIGNsb3NlQXV0aGVudGljYXRpb25XaW5kb3c6ZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoYXV0aGVudGljYXRpb25XaW5kb3cpIHtcbiAgICAgICAgICAgIGF1dGhlbnRpY2F0aW9uV2luZG93LmNsb3NlKCk7XG4gICAgICAgICAgICBhdXRoZW50aWNhdGlvbldpbmRvdyA9IG51bGw7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIGZvY3VzQXV0aGVudGljYXRpb25XaW5kb3c6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gSWYgYXV0aCB3aW5kb3cgZXhpc3RzIGp1c3QgYnJpbmcgaXQgdG8gdGhlIGZyb250XG4gICAgICAgIGlmIChhdXRoZW50aWNhdGlvbldpbmRvdykge1xuICAgICAgICAgICAgYXV0aGVudGljYXRpb25XaW5kb3cuZm9jdXMoKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgY2xvc2VBdXRoZW50aWNhdGlvbkRpYWxvZzogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBDbG9zZSBhdXRoZW50aWNhdGlvbiBkaWFsb2cgaWYgb3BlbmVkXG4gICAgICAgIGlmIChhdXRoRGlhbG9nKSB7XG4gICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuY2xvc2VEaWFsb2coKTtcbiAgICAgICAgICAgIGF1dGhEaWFsb2cgPSBudWxsO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBjcmVhdGVBdXRoZW50aWNhdGlvbldpbmRvdzogZnVuY3Rpb24gKGNhbGxiYWNrLCB1cmwpIHtcbiAgICAgICAgYXV0aGVudGljYXRpb25XaW5kb3cgPSBtZXNzYWdlSGFuZGxlci5vcGVuQ2VudGVyZWRQb3B1cChcbiAgICAgICAgICAgIHVybCwgOTEwLCA2NjAsXG4gICAgICAgICAgICAvLyBPbiBjbG9zZWRcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyBDbG9zZSBhdXRoZW50aWNhdGlvbiBkaWFsb2cgaWYgb3BlbmVkXG4gICAgICAgICAgICAgICAgaWYgKGF1dGhEaWFsb2cpIHtcbiAgICAgICAgICAgICAgICAgICAgbWVzc2FnZUhhbmRsZXIuY2xvc2VEaWFsb2coKTtcbiAgICAgICAgICAgICAgICAgICAgYXV0aERpYWxvZyA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGNhbGxiYWNrKCk7XG4gICAgICAgICAgICAgICAgYXV0aGVudGljYXRpb25XaW5kb3cgPSBudWxsO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIHJldHVybiBhdXRoZW50aWNhdGlvbldpbmRvdztcbiAgICB9LFxuICAgIHN0b3BJbnRlcnZhbDogZnVuY3Rpb24gKCkge1xuICAgICAgICAvLyBDbGVhciByZXRyeSBpbnRlcnZhbCwgc28gdGhhdCB3ZSBkb24ndCBjYWxsICdkb0pvaW5BZnRlckZvY3VzJyB0d2ljZVxuICAgICAgICBpZiAoYXV0aFJldHJ5SWQpIHtcbiAgICAgICAgICAgIHdpbmRvdy5jbGVhclRpbWVvdXQoYXV0aFJldHJ5SWQpO1xuICAgICAgICAgICAgYXV0aFJldHJ5SWQgPSBudWxsO1xuICAgICAgICB9XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBBdXRoZW50aWNhdGlvbjsiLCJ2YXIgU2V0dGluZ3MgPSByZXF1aXJlKFwiLi4vc2lkZV9wYW5uZWxzL3NldHRpbmdzL1NldHRpbmdzXCIpO1xudmFyIE1lZGlhU3RyZWFtVHlwZSA9IHJlcXVpcmUoXCIuLi8uLi8uLi9zZXJ2aWNlL1JUQy9NZWRpYVN0cmVhbVR5cGVzXCIpO1xuXG52YXIgdXNlcnMgPSB7fTtcbnZhciBhY3RpdmVTcGVha2VySmlkO1xuXG5mdW5jdGlvbiBzZXRWaXNpYmlsaXR5KHNlbGVjdG9yLCBzaG93KSB7XG4gICAgaWYgKHNlbGVjdG9yICYmIHNlbGVjdG9yLmxlbmd0aCA+IDApIHtcbiAgICAgICAgc2VsZWN0b3IuY3NzKFwidmlzaWJpbGl0eVwiLCBzaG93ID8gXCJ2aXNpYmxlXCIgOiBcImhpZGRlblwiKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGlzVXNlck11dGVkKGppZCkge1xuICAgIC8vIFhYWChncCkgd2UgbWF5IHdhbnQgdG8gcmVuYW1lIHRoaXMgbWV0aG9kIHRvIHNvbWV0aGluZyBsaWtlXG4gICAgLy8gaXNVc2VyU3RyZWFtaW5nLCBmb3IgZXhhbXBsZS5cbiAgICBpZiAoamlkICYmIGppZCAhPSBBUFAueG1wcC5teUppZCgpKSB7XG4gICAgICAgIHZhciByZXNvdXJjZSA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIGlmICghcmVxdWlyZShcIi4uL3ZpZGVvbGF5b3V0L1ZpZGVvTGF5b3V0XCIpLmlzSW5MYXN0TihyZXNvdXJjZSkpIHtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgaWYgKCFBUFAuUlRDLnJlbW90ZVN0cmVhbXNbamlkXSB8fCAhQVBQLlJUQy5yZW1vdGVTdHJlYW1zW2ppZF1bTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEVdKSB7XG4gICAgICAgIHJldHVybiBudWxsO1xuICAgIH1cbiAgICByZXR1cm4gQVBQLlJUQy5yZW1vdGVTdHJlYW1zW2ppZF1bTWVkaWFTdHJlYW1UeXBlLlZJREVPX1RZUEVdLm11dGVkO1xufVxuXG5mdW5jdGlvbiBnZXRHcmF2YXRhclVybChpZCwgc2l6ZSkge1xuICAgIGlmKGlkID09PSBBUFAueG1wcC5teUppZCgpIHx8ICFpZCkge1xuICAgICAgICBpZCA9IFNldHRpbmdzLmdldFNldHRpbmdzKCkudWlkO1xuICAgIH1cbiAgICByZXR1cm4gJ2h0dHBzOi8vd3d3LmdyYXZhdGFyLmNvbS9hdmF0YXIvJyArXG4gICAgICAgIE1ENS5oZXhkaWdlc3QoaWQudHJpbSgpLnRvTG93ZXJDYXNlKCkpICtcbiAgICAgICAgXCI/ZD13YXZhdGFyJnNpemU9XCIgKyAoc2l6ZSB8fCBcIjMwXCIpO1xufVxuXG52YXIgQXZhdGFyID0ge1xuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgdXNlcidzIGF2YXRhciBpbiB0aGUgc2V0dGluZ3MgbWVudShpZiBsb2NhbCB1c2VyKSwgY29udGFjdCBsaXN0XG4gICAgICogYW5kIHRodW1ibmFpbFxuICAgICAqIEBwYXJhbSBqaWQgamlkIG9mIHRoZSB1c2VyXG4gICAgICogQHBhcmFtIGlkIGVtYWlsIG9yIHVzZXJJRCB0byBiZSB1c2VkIGFzIGEgaGFzaFxuICAgICAqL1xuICAgIHNldFVzZXJBdmF0YXI6IGZ1bmN0aW9uIChqaWQsIGlkKSB7XG4gICAgICAgIGlmIChpZCkge1xuICAgICAgICAgICAgaWYgKHVzZXJzW2ppZF0gPT09IGlkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdXNlcnNbamlkXSA9IGlkO1xuICAgICAgICB9XG4gICAgICAgIHZhciB0aHVtYlVybCA9IGdldEdyYXZhdGFyVXJsKHVzZXJzW2ppZF0gfHwgamlkLCAxMDApO1xuICAgICAgICB2YXIgY29udGFjdExpc3RVcmwgPSBnZXRHcmF2YXRhclVybCh1c2Vyc1tqaWRdIHx8IGppZCk7XG4gICAgICAgIHZhciByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIHZhciB0aHVtYm5haWwgPSAkKCcjcGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkKTtcbiAgICAgICAgdmFyIGF2YXRhciA9ICQoJyNhdmF0YXJfJyArIHJlc291cmNlSmlkKTtcblxuICAgICAgICAvLyBzZXQgdGhlIGF2YXRhciBpbiB0aGUgc2V0dGluZ3MgbWVudSBpZiBpdCBpcyBsb2NhbCB1c2VyIGFuZCBnZXQgdGhlXG4gICAgICAgIC8vIGxvY2FsIHZpZGVvIGNvbnRhaW5lclxuICAgICAgICBpZiAoamlkID09PSBBUFAueG1wcC5teUppZCgpKSB7XG4gICAgICAgICAgICAkKCcjYXZhdGFyJykuZ2V0KDApLnNyYyA9IHRodW1iVXJsO1xuICAgICAgICAgICAgdGh1bWJuYWlsID0gJCgnI2xvY2FsVmlkZW9Db250YWluZXInKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNldCB0aGUgYXZhdGFyIGluIHRoZSBjb250YWN0IGxpc3RcbiAgICAgICAgdmFyIGNvbnRhY3QgPSAkKCcjJyArIHJlc291cmNlSmlkICsgJz5pbWcnKTtcbiAgICAgICAgaWYgKGNvbnRhY3QgJiYgY29udGFjdC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBjb250YWN0LmdldCgwKS5zcmMgPSBjb250YWN0TGlzdFVybDtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHNldCB0aGUgYXZhdGFyIGluIHRoZSB0aHVtYm5haWxcbiAgICAgICAgaWYgKGF2YXRhciAmJiBhdmF0YXIubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgYXZhdGFyWzBdLnNyYyA9IHRodW1iVXJsO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYgKHRodW1ibmFpbCAmJiB0aHVtYm5haWwubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgIGF2YXRhciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2ltZycpO1xuICAgICAgICAgICAgICAgIGF2YXRhci5pZCA9ICdhdmF0YXJfJyArIHJlc291cmNlSmlkO1xuICAgICAgICAgICAgICAgIGF2YXRhci5jbGFzc05hbWUgPSAndXNlckF2YXRhcic7XG4gICAgICAgICAgICAgICAgYXZhdGFyLnNyYyA9IHRodW1iVXJsO1xuICAgICAgICAgICAgICAgIHRodW1ibmFpbC5hcHBlbmQoYXZhdGFyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vaWYgdGhlIHVzZXIgaXMgdGhlIGN1cnJlbnQgYWN0aXZlIHNwZWFrZXIgLSB1cGRhdGUgdGhlIGFjdGl2ZSBzcGVha2VyXG4gICAgICAgIC8vIGF2YXRhclxuICAgICAgICBpZiAoamlkID09PSBhY3RpdmVTcGVha2VySmlkKSB7XG4gICAgICAgICAgICB0aGlzLnVwZGF0ZUFjdGl2ZVNwZWFrZXJBdmF0YXJTcmMoamlkKTtcbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBIaWRlcyBvciBzaG93cyB0aGUgdXNlcidzIGF2YXRhclxuICAgICAqIEBwYXJhbSBqaWQgamlkIG9mIHRoZSB1c2VyXG4gICAgICogQHBhcmFtIHNob3cgd2hldGhlciB3ZSBzaG91bGQgc2hvdyB0aGUgYXZhdGFyIG9yIG5vdFxuICAgICAqIHZpZGVvIGJlY2F1c2UgdGhlcmUgaXMgbm8gZG9taW5hbnQgc3BlYWtlciBhbmQgbm8gZm9jdXNlZCBzcGVha2VyXG4gICAgICovXG4gICAgc2hvd1VzZXJBdmF0YXI6IGZ1bmN0aW9uIChqaWQsIHNob3cpIHtcbiAgICAgICAgaWYgKHVzZXJzW2ppZF0pIHtcbiAgICAgICAgICAgIHZhciByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgICAgICB2YXIgdmlkZW8gPSAkKCcjcGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkICsgJz52aWRlbycpO1xuICAgICAgICAgICAgdmFyIGF2YXRhciA9ICQoJyNhdmF0YXJfJyArIHJlc291cmNlSmlkKTtcblxuICAgICAgICAgICAgaWYgKGppZCA9PT0gQVBQLnhtcHAubXlKaWQoKSkge1xuICAgICAgICAgICAgICAgIHZpZGVvID0gJCgnI2xvY2FsVmlkZW9XcmFwcGVyPnZpZGVvJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoc2hvdyA9PT0gdW5kZWZpbmVkIHx8IHNob3cgPT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICBzaG93ID0gaXNVc2VyTXV0ZWQoamlkKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy9pZiB0aGUgdXNlciBpcyB0aGUgY3VycmVudGx5IGZvY3VzZWQsIHRoZSBkb21pbmFudCBzcGVha2VyIG9yIGlmXG4gICAgICAgICAgICAvL3RoZXJlIGlzIG5vIGZvY3VzZWQgYW5kIG5vIGRvbWluYW50IHNwZWFrZXIgYW5kIHRoZSBsYXJnZSB2aWRlbyBpc1xuICAgICAgICAgICAgLy9jdXJyZW50bHkgc2hvd25cbiAgICAgICAgICAgIGlmIChhY3RpdmVTcGVha2VySmlkID09PSBqaWQgJiYgcmVxdWlyZShcIi4uL3ZpZGVvbGF5b3V0L1ZpZGVvTGF5b3V0XCIpLmlzTGFyZ2VWaWRlb09uVG9wKCkpIHtcbiAgICAgICAgICAgICAgICBzZXRWaXNpYmlsaXR5KCQoXCIjbGFyZ2VWaWRlb1wiKSwgIXNob3cpO1xuICAgICAgICAgICAgICAgIHNldFZpc2liaWxpdHkoJCgnI2FjdGl2ZVNwZWFrZXInKSwgc2hvdyk7XG4gICAgICAgICAgICAgICAgc2V0VmlzaWJpbGl0eShhdmF0YXIsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICBzZXRWaXNpYmlsaXR5KHZpZGVvLCBmYWxzZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmICh2aWRlbyAmJiB2aWRlby5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHNldFZpc2liaWxpdHkodmlkZW8sICFzaG93KTtcbiAgICAgICAgICAgICAgICAgICAgc2V0VmlzaWJpbGl0eShhdmF0YXIsIHNob3cpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHRoZSBzcmMgb2YgdGhlIGFjdGl2ZSBzcGVha2VyIGF2YXRhclxuICAgICAqIEBwYXJhbSBqaWQgb2YgdGhlIGN1cnJlbnQgYWN0aXZlIHNwZWFrZXJcbiAgICAgKi9cbiAgICB1cGRhdGVBY3RpdmVTcGVha2VyQXZhdGFyU3JjOiBmdW5jdGlvbiAoamlkKSB7XG4gICAgICAgIGlmICghamlkKSB7XG4gICAgICAgICAgICBqaWQgPSBBUFAueG1wcC5maW5kSmlkRnJvbVJlc291cmNlKFxuICAgICAgICAgICAgICAgIHJlcXVpcmUoXCIuLi92aWRlb2xheW91dC9WaWRlb0xheW91dFwiKS5nZXRMYXJnZVZpZGVvU3RhdGUoKS51c2VyUmVzb3VyY2VKaWQpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBhdmF0YXIgPSAkKFwiI2FjdGl2ZVNwZWFrZXJBdmF0YXJcIilbMF07XG4gICAgICAgIHZhciB1cmwgPSBnZXRHcmF2YXRhclVybCh1c2Vyc1tqaWRdLFxuICAgICAgICAgICAgaW50ZXJmYWNlQ29uZmlnLkFDVElWRV9TUEVBS0VSX0FWQVRBUl9TSVpFKTtcbiAgICAgICAgaWYgKGppZCA9PT0gYWN0aXZlU3BlYWtlckppZCAmJiBhdmF0YXIuc3JjID09PSB1cmwpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBhY3RpdmVTcGVha2VySmlkID0gamlkO1xuICAgICAgICB2YXIgaXNNdXRlZCA9IGlzVXNlck11dGVkKGppZCk7XG4gICAgICAgIGlmIChqaWQgJiYgaXNNdXRlZCAhPT0gbnVsbCkge1xuICAgICAgICAgICAgYXZhdGFyLnNyYyA9IHVybDtcbiAgICAgICAgICAgIHNldFZpc2liaWxpdHkoJChcIiNsYXJnZVZpZGVvXCIpLCAhaXNNdXRlZCk7XG4gICAgICAgICAgICBBdmF0YXIuc2hvd1VzZXJBdmF0YXIoamlkLCBpc011dGVkKTtcbiAgICAgICAgfVxuICAgIH1cblxufTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IEF2YXRhcjsiLCIvKiBnbG9iYWwgJCwgY29uZmlnLFxuICAgc2V0TGFyZ2VWaWRlb1Zpc2libGUsIFV0aWwgKi9cblxudmFyIFZpZGVvTGF5b3V0ID0gcmVxdWlyZShcIi4uL3ZpZGVvbGF5b3V0L1ZpZGVvTGF5b3V0XCIpO1xudmFyIFByZXppID0gcmVxdWlyZShcIi4uL3ByZXppL1ByZXppXCIpO1xudmFyIFVJVXRpbCA9IHJlcXVpcmUoXCIuLi91dGlsL1VJVXRpbFwiKTtcblxudmFyIGV0aGVycGFkTmFtZSA9IG51bGw7XG52YXIgZXRoZXJwYWRJRnJhbWUgPSBudWxsO1xudmFyIGRvbWFpbiA9IG51bGw7XG52YXIgb3B0aW9ucyA9IFwiP3Nob3dDb250cm9scz10cnVlJnNob3dDaGF0PWZhbHNlJnNob3dMaW5lTnVtYmVycz10cnVlJnVzZU1vbm9zcGFjZUZvbnQ9ZmFsc2VcIjtcblxuXG4vKipcbiAqIFJlc2l6ZXMgdGhlIGV0aGVycGFkLlxuICovXG5mdW5jdGlvbiByZXNpemUoKSB7XG4gICAgaWYgKCQoJyNldGhlcnBhZD5pZnJhbWUnKS5sZW5ndGgpIHtcbiAgICAgICAgdmFyIHJlbW90ZVZpZGVvcyA9ICQoJyNyZW1vdGVWaWRlb3MnKTtcbiAgICAgICAgdmFyIGF2YWlsYWJsZUhlaWdodFxuICAgICAgICAgICAgPSB3aW5kb3cuaW5uZXJIZWlnaHQgLSByZW1vdGVWaWRlb3Mub3V0ZXJIZWlnaHQoKTtcbiAgICAgICAgdmFyIGF2YWlsYWJsZVdpZHRoID0gVUlVdGlsLmdldEF2YWlsYWJsZVZpZGVvV2lkdGgoKTtcblxuICAgICAgICAkKCcjZXRoZXJwYWQ+aWZyYW1lJykud2lkdGgoYXZhaWxhYmxlV2lkdGgpO1xuICAgICAgICAkKCcjZXRoZXJwYWQ+aWZyYW1lJykuaGVpZ2h0KGF2YWlsYWJsZUhlaWdodCk7XG4gICAgfVxufVxuXG4vKipcbiAqIFNoYXJlcyB0aGUgRXRoZXJwYWQgbmFtZSB3aXRoIG90aGVyIHBhcnRpY2lwYW50cy5cbiAqL1xuZnVuY3Rpb24gc2hhcmVFdGhlcnBhZCgpIHtcbiAgICBBUFAueG1wcC5hZGRUb1ByZXNlbmNlKFwiZXRoZXJwYWRcIiwgZXRoZXJwYWROYW1lKTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBFdGhlcnBhZCBidXR0b24gYW5kIGFkZHMgaXQgdG8gdGhlIHRvb2xiYXIuXG4gKi9cbmZ1bmN0aW9uIGVuYWJsZUV0aGVycGFkQnV0dG9uKCkge1xuICAgIGlmICghJCgnI2V0aGVycGFkQnV0dG9uJykuaXMoXCI6dmlzaWJsZVwiKSlcbiAgICAgICAgJCgnI2V0aGVycGFkQnV0dG9uJykuY3NzKHtkaXNwbGF5OiAnaW5saW5lLWJsb2NrJ30pO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIElGcmFtZSBmb3IgdGhlIGV0aGVycGFkLlxuICovXG5mdW5jdGlvbiBjcmVhdGVJRnJhbWUoKSB7XG4gICAgZXRoZXJwYWRJRnJhbWUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpZnJhbWUnKTtcbiAgICBldGhlcnBhZElGcmFtZS5zcmMgPSBkb21haW4gKyBldGhlcnBhZE5hbWUgKyBvcHRpb25zO1xuICAgIGV0aGVycGFkSUZyYW1lLmZyYW1lQm9yZGVyID0gMDtcbiAgICBldGhlcnBhZElGcmFtZS5zY3JvbGxpbmcgPSBcIm5vXCI7XG4gICAgZXRoZXJwYWRJRnJhbWUud2lkdGggPSAkKCcjbGFyZ2VWaWRlb0NvbnRhaW5lcicpLndpZHRoKCkgfHwgNjQwO1xuICAgIGV0aGVycGFkSUZyYW1lLmhlaWdodCA9ICQoJyNsYXJnZVZpZGVvQ29udGFpbmVyJykuaGVpZ2h0KCkgfHwgNDgwO1xuICAgIGV0aGVycGFkSUZyYW1lLnNldEF0dHJpYnV0ZSgnc3R5bGUnLCAndmlzaWJpbGl0eTogaGlkZGVuOycpO1xuXG4gICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2V0aGVycGFkJykuYXBwZW5kQ2hpbGQoZXRoZXJwYWRJRnJhbWUpO1xuXG4gICAgZXRoZXJwYWRJRnJhbWUub25sb2FkID0gZnVuY3Rpb24oKSB7XG5cbiAgICAgICAgZG9jdW1lbnQuZG9tYWluID0gZG9jdW1lbnQuZG9tYWluO1xuICAgICAgICBidWJibGVJZnJhbWVNb3VzZU1vdmUoZXRoZXJwYWRJRnJhbWUpO1xuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgLy8gdGhlIGlmcmFtZXMgaW5zaWRlIG9mIHRoZSBldGhlcnBhZCBhcmVcbiAgICAgICAgICAgIC8vIG5vdCB5ZXQgbG9hZGVkIHdoZW4gdGhlIGV0aGVycGFkIGlmcmFtZSBpcyBsb2FkZWRcbiAgICAgICAgICAgIHZhciBvdXRlciA9IGV0aGVycGFkSUZyYW1lLlxuICAgICAgICAgICAgICAgIGNvbnRlbnREb2N1bWVudC5nZXRFbGVtZW50c0J5TmFtZShcImFjZV9vdXRlclwiKVswXTtcbiAgICAgICAgICAgIGJ1YmJsZUlmcmFtZU1vdXNlTW92ZShvdXRlcik7XG4gICAgICAgICAgICB2YXIgaW5uZXIgPSBvdXRlci5cbiAgICAgICAgICAgICAgICBjb250ZW50RG9jdW1lbnQuZ2V0RWxlbWVudHNCeU5hbWUoXCJhY2VfaW5uZXJcIilbMF07XG4gICAgICAgICAgICBidWJibGVJZnJhbWVNb3VzZU1vdmUoaW5uZXIpO1xuICAgICAgICB9LCAyMDAwKTtcbiAgICB9O1xufVxuXG5mdW5jdGlvbiBidWJibGVJZnJhbWVNb3VzZU1vdmUoaWZyYW1lKXtcbiAgICB2YXIgZXhpc3RpbmdPbk1vdXNlTW92ZSA9IGlmcmFtZS5jb250ZW50V2luZG93Lm9ubW91c2Vtb3ZlO1xuICAgIGlmcmFtZS5jb250ZW50V2luZG93Lm9ubW91c2Vtb3ZlID0gZnVuY3Rpb24oZSl7XG4gICAgICAgIGlmKGV4aXN0aW5nT25Nb3VzZU1vdmUpIGV4aXN0aW5nT25Nb3VzZU1vdmUoZSk7XG4gICAgICAgIHZhciBldnQgPSBkb2N1bWVudC5jcmVhdGVFdmVudChcIk1vdXNlRXZlbnRzXCIpO1xuICAgICAgICB2YXIgYm91bmRpbmdDbGllbnRSZWN0ID0gaWZyYW1lLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuICAgICAgICBldnQuaW5pdE1vdXNlRXZlbnQoXG4gICAgICAgICAgICBcIm1vdXNlbW92ZVwiLFxuICAgICAgICAgICAgdHJ1ZSwgLy8gYnViYmxlc1xuICAgICAgICAgICAgZmFsc2UsIC8vIG5vdCBjYW5jZWxhYmxlXG4gICAgICAgICAgICB3aW5kb3csXG4gICAgICAgICAgICBlLmRldGFpbCxcbiAgICAgICAgICAgIGUuc2NyZWVuWCxcbiAgICAgICAgICAgIGUuc2NyZWVuWSxcbiAgICAgICAgICAgICAgICBlLmNsaWVudFggKyBib3VuZGluZ0NsaWVudFJlY3QubGVmdCxcbiAgICAgICAgICAgICAgICBlLmNsaWVudFkgKyBib3VuZGluZ0NsaWVudFJlY3QudG9wLFxuICAgICAgICAgICAgZS5jdHJsS2V5LFxuICAgICAgICAgICAgZS5hbHRLZXksXG4gICAgICAgICAgICBlLnNoaWZ0S2V5LFxuICAgICAgICAgICAgZS5tZXRhS2V5LFxuICAgICAgICAgICAgZS5idXR0b24sXG4gICAgICAgICAgICBudWxsIC8vIG5vIHJlbGF0ZWQgZWxlbWVudFxuICAgICAgICApO1xuICAgICAgICBpZnJhbWUuZGlzcGF0Y2hFdmVudChldnQpO1xuICAgIH07XG59XG5cblxuLyoqXG4gKiBPbiB2aWRlbyBzZWxlY3RlZCBldmVudC5cbiAqL1xuJChkb2N1bWVudCkuYmluZCgndmlkZW8uc2VsZWN0ZWQnLCBmdW5jdGlvbiAoZXZlbnQsIGlzUHJlc2VudGF0aW9uKSB7XG4gICAgaWYgKGNvbmZpZy5ldGhlcnBhZF9iYXNlICYmIGV0aGVycGFkSUZyYW1lICYmIGV0aGVycGFkSUZyYW1lLnN0eWxlLnZpc2liaWxpdHkgIT09ICdoaWRkZW4nKVxuICAgICAgICBFdGhlcnBhZC50b2dnbGVFdGhlcnBhZChpc1ByZXNlbnRhdGlvbik7XG59KTtcblxuXG52YXIgRXRoZXJwYWQgPSB7XG4gICAgLyoqXG4gICAgICogSW5pdGlhbGl6ZXMgdGhlIGV0aGVycGFkLlxuICAgICAqL1xuICAgIGluaXQ6IGZ1bmN0aW9uIChuYW1lKSB7XG5cbiAgICAgICAgaWYgKGNvbmZpZy5ldGhlcnBhZF9iYXNlICYmICFldGhlcnBhZE5hbWUpIHtcblxuICAgICAgICAgICAgZG9tYWluID0gY29uZmlnLmV0aGVycGFkX2Jhc2U7XG5cbiAgICAgICAgICAgIGlmICghbmFtZSkge1xuICAgICAgICAgICAgICAgIC8vIEluIGNhc2Ugd2UncmUgdGhlIGZvY3VzIHdlIGdlbmVyYXRlIHRoZSBuYW1lLlxuICAgICAgICAgICAgICAgIGV0aGVycGFkTmFtZSA9IE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cmluZyg3KSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdfJyArIChuZXcgRGF0ZSgpLmdldFRpbWUoKSkudG9TdHJpbmcoKTtcbiAgICAgICAgICAgICAgICBzaGFyZUV0aGVycGFkKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgZXRoZXJwYWROYW1lID0gbmFtZTtcblxuICAgICAgICAgICAgZW5hYmxlRXRoZXJwYWRCdXR0b24oKTtcblxuICAgICAgICAgICAgLyoqXG4gICAgICAgICAgICAgKiBSZXNpemVzIHRoZSBldGhlcnBhZCwgd2hlbiB0aGUgd2luZG93IGlzIHJlc2l6ZWQuXG4gICAgICAgICAgICAgKi9cbiAgICAgICAgICAgICQod2luZG93KS5yZXNpemUoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHJlc2l6ZSgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogT3BlbnMvaGlkZXMgdGhlIEV0aGVycGFkLlxuICAgICAqL1xuICAgIHRvZ2dsZUV0aGVycGFkOiBmdW5jdGlvbiAoaXNQcmVzZW50YXRpb24pIHtcbiAgICAgICAgaWYgKCFldGhlcnBhZElGcmFtZSlcbiAgICAgICAgICAgIGNyZWF0ZUlGcmFtZSgpO1xuXG4gICAgICAgIHZhciBsYXJnZVZpZGVvID0gbnVsbDtcbiAgICAgICAgaWYgKFByZXppLmlzUHJlc2VudGF0aW9uVmlzaWJsZSgpKVxuICAgICAgICAgICAgbGFyZ2VWaWRlbyA9ICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJyk7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGxhcmdlVmlkZW8gPSAkKCcjbGFyZ2VWaWRlbycpO1xuXG4gICAgICAgIGlmICgkKCcjZXRoZXJwYWQ+aWZyYW1lJykuY3NzKCd2aXNpYmlsaXR5JykgPT09ICdoaWRkZW4nKSB7XG4gICAgICAgICAgICAkKCcjYWN0aXZlU3BlYWtlcicpLmNzcygndmlzaWJpbGl0eScsICdoaWRkZW4nKTtcbiAgICAgICAgICAgIGxhcmdlVmlkZW8uZmFkZU91dCgzMDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAoUHJlemkuaXNQcmVzZW50YXRpb25WaXNpYmxlKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlby5jc3Moe29wYWNpdHk6ICcwJ30pO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNldExhcmdlVmlkZW9WaXNpYmxlKGZhbHNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLmZhZGVJbigzMDAsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5ib2R5LnN0eWxlLmJhY2tncm91bmQgPSAnI2VlZWVlZSc7XG4gICAgICAgICAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLmNzcyh7dmlzaWJpbGl0eTogJ3Zpc2libGUnfSk7XG4gICAgICAgICAgICAgICAgJCgnI2V0aGVycGFkJykuY3NzKHt6SW5kZXg6IDJ9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKCQoJyNldGhlcnBhZD5pZnJhbWUnKSkge1xuICAgICAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLmZhZGVPdXQoMzAwLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgJCgnI2V0aGVycGFkPmlmcmFtZScpLmNzcyh7dmlzaWJpbGl0eTogJ2hpZGRlbid9KTtcbiAgICAgICAgICAgICAgICAkKCcjZXRoZXJwYWQnKS5jc3Moe3pJbmRleDogMH0pO1xuICAgICAgICAgICAgICAgIGRvY3VtZW50LmJvZHkuc3R5bGUuYmFja2dyb3VuZCA9ICdibGFjayc7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgaWYgKCFpc1ByZXNlbnRhdGlvbikge1xuICAgICAgICAgICAgICAgICQoJyNsYXJnZVZpZGVvJykuZmFkZUluKDMwMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5zZXRMYXJnZVZpZGVvVmlzaWJsZSh0cnVlKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXNpemUoKTtcbiAgICB9LFxuXG4gICAgaXNWaXNpYmxlOiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGV0aGVycGFkSWZyYW1lID0gJCgnI2V0aGVycGFkPmlmcmFtZScpO1xuICAgICAgICByZXR1cm4gZXRoZXJwYWRJZnJhbWUgJiYgZXRoZXJwYWRJZnJhbWUuaXMoJzp2aXNpYmxlJyk7XG4gICAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEV0aGVycGFkO1xuIiwidmFyIFRvb2xiYXJUb2dnbGVyID0gcmVxdWlyZShcIi4uL3Rvb2xiYXJzL1Rvb2xiYXJUb2dnbGVyXCIpO1xudmFyIFVJVXRpbCA9IHJlcXVpcmUoXCIuLi91dGlsL1VJVXRpbFwiKTtcbnZhciBWaWRlb0xheW91dCA9IHJlcXVpcmUoXCIuLi92aWRlb2xheW91dC9WaWRlb0xheW91dFwiKTtcbnZhciBtZXNzYWdlSGFuZGxlciA9IHJlcXVpcmUoXCIuLi91dGlsL01lc3NhZ2VIYW5kbGVyXCIpO1xudmFyIFByZXppUGxheWVyID0gcmVxdWlyZShcIi4vUHJlemlQbGF5ZXJcIik7XG5cbnZhciBwcmV6aVBsYXllciA9IG51bGw7XG5cbnZhciBQcmV6aSA9IHtcblxuXG4gICAgLyoqXG4gICAgICogUmVsb2FkcyB0aGUgY3VycmVudCBwcmVzZW50YXRpb24uXG4gICAgICovXG4gICAgcmVsb2FkUHJlc2VudGF0aW9uOiBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIGlmcmFtZSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKHByZXppUGxheWVyLm9wdGlvbnMucHJlemlJZCk7XG4gICAgICAgIGlmcmFtZS5zcmMgPSBpZnJhbWUuc3JjO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIDx0dD50cnVlPC90dD4gaWYgdGhlIHByZXNlbnRhdGlvbiBpcyB2aXNpYmxlLCA8dHQ+ZmFsc2U8L3R0PiAtXG4gICAgICogb3RoZXJ3aXNlLlxuICAgICAqL1xuICAgIGlzUHJlc2VudGF0aW9uVmlzaWJsZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gKCQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykgIT0gbnVsbFxuICAgICAgICAgICAgICAgICYmICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykuY3NzKCdvcGFjaXR5JykgPT0gMSk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIE9wZW5zIHRoZSBQcmV6aSBkaWFsb2csIGZyb20gd2hpY2ggdGhlIHVzZXIgY291bGQgY2hvb3NlIGEgcHJlc2VudGF0aW9uXG4gICAgICogdG8gbG9hZC5cbiAgICAgKi9cbiAgICBvcGVuUHJlemlEaWFsb2c6IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgbXlwcmV6aSA9IEFQUC54bXBwLmdldFByZXppKCk7XG4gICAgICAgIGlmIChteXByZXppKSB7XG4gICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKFwiUmVtb3ZlIFByZXppXCIsXG4gICAgICAgICAgICAgICAgXCJBcmUgeW91IHN1cmUgeW91IHdvdWxkIGxpa2UgdG8gcmVtb3ZlIHlvdXIgUHJlemk/XCIsXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgXCJSZW1vdmVcIixcbiAgICAgICAgICAgICAgICBmdW5jdGlvbihlLHYsbSxmKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmKHYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIEFQUC54bXBwLnJlbW92ZVByZXppRnJvbVByZXNlbmNlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHByZXppUGxheWVyICE9IG51bGwpIHtcbiAgICAgICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2coXCJTaGFyZSBhIFByZXppXCIsXG4gICAgICAgICAgICAgICAgXCJBbm90aGVyIHBhcnRpY2lwYW50IGlzIGFscmVhZHkgc2hhcmluZyBhIFByZXppLlwiICtcbiAgICAgICAgICAgICAgICAgICAgXCJUaGlzIGNvbmZlcmVuY2UgYWxsb3dzIG9ubHkgb25lIFByZXppIGF0IGEgdGltZS5cIixcbiAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICBcIk9rXCIsXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24oZSx2LG0sZikge1xuICAgICAgICAgICAgICAgICAgICAkLnByb21wdC5jbG9zZSgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2YXIgb3BlblByZXppU3RhdGUgPSB7XG4gICAgICAgICAgICAgICAgc3RhdGUwOiB7XG4gICAgICAgICAgICAgICAgICAgIGh0bWw6ICAgJzxoMj5TaGFyZSBhIFByZXppPC9oMj4nICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnPGlucHV0IGlkPVwicHJlemlVcmxcIiB0eXBlPVwidGV4dFwiICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICdwbGFjZWhvbGRlcj1cImUuZy4gJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ2h0dHA6Ly9wcmV6aS5jb20vd3o3dmhqeWNsN2U2L215LXByZXppXCIgYXV0b2ZvY3VzPicsXG4gICAgICAgICAgICAgICAgICAgIHBlcnNpc3RlbnQ6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBidXR0b25zOiB7IFwiU2hhcmVcIjogdHJ1ZSAsIFwiQ2FuY2VsXCI6IGZhbHNlfSxcbiAgICAgICAgICAgICAgICAgICAgZGVmYXVsdEJ1dHRvbjogMSxcbiAgICAgICAgICAgICAgICAgICAgc3VibWl0OiBmdW5jdGlvbihlLHYsbSxmKXtcbiAgICAgICAgICAgICAgICAgICAgICAgIGUucHJldmVudERlZmF1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmKHYpXG4gICAgICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHByZXppVXJsID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3ByZXppVXJsJyk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocHJlemlVcmwudmFsdWUpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgdXJsVmFsdWVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gZW5jb2RlVVJJKFVJVXRpbC5lc2NhcGVIdG1sKHByZXppVXJsLnZhbHVlKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHVybFZhbHVlLmluZGV4T2YoJ2h0dHA6Ly9wcmV6aS5jb20vJykgIT0gMFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgdXJsVmFsdWUuaW5kZXhPZignaHR0cHM6Ly9wcmV6aS5jb20vJykgIT0gMClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuZ29Ub1N0YXRlKCdzdGF0ZTEnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhciBwcmVzSWRUbXAgPSB1cmxWYWx1ZS5zdWJzdHJpbmcoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHVybFZhbHVlLmluZGV4T2YoXCJwcmV6aS5jb20vXCIpICsgMTApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFpc0FscGhhbnVtZXJpYyhwcmVzSWRUbXApXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8IHByZXNJZFRtcC5pbmRleE9mKCcvJykgPCAyKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuZ29Ub1N0YXRlKCdzdGF0ZTEnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBBUFAueG1wcC5hZGRUb1ByZXNlbmNlKFwicHJlemlcIiwgdXJsVmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICQucHJvbXB0LmNsb3NlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuY2xvc2UoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgc3RhdGUxOiB7XG4gICAgICAgICAgICAgICAgICAgIGh0bWw6ICAgJzxoMj5TaGFyZSBhIFByZXppPC9oMj4nICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAnUGxlYXNlIHByb3ZpZGUgYSBjb3JyZWN0IHByZXppIGxpbmsuJyxcbiAgICAgICAgICAgICAgICAgICAgcGVyc2lzdGVudDogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIGJ1dHRvbnM6IHsgXCJCYWNrXCI6IHRydWUsIFwiQ2FuY2VsXCI6IGZhbHNlIH0sXG4gICAgICAgICAgICAgICAgICAgIGRlZmF1bHRCdXR0b246IDEsXG4gICAgICAgICAgICAgICAgICAgIHN1Ym1pdDpmdW5jdGlvbihlLHYsbSxmKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZih2PT0wKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQucHJvbXB0LmNsb3NlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJC5wcm9tcHQuZ29Ub1N0YXRlKCdzdGF0ZTAnKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICB2YXIgZm9jdXNQcmV6aVVybCA9ICBmdW5jdGlvbihlKSB7XG4gICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwcmV6aVVybCcpLmZvY3VzKCk7XG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5EaWFsb2dXaXRoU3RhdGVzKG9wZW5QcmV6aVN0YXRlLCBmb2N1c1ByZXppVXJsLCBmb2N1c1ByZXppVXJsKTtcbiAgICAgICAgfVxuICAgIH1cblxufTtcblxuLyoqXG4gKiBBIG5ldyBwcmVzZW50YXRpb24gaGFzIGJlZW4gYWRkZWQuXG4gKlxuICogQHBhcmFtIGV2ZW50IHRoZSBldmVudCBpbmRpY2F0aW5nIHRoZSBhZGQgb2YgYSBwcmVzZW50YXRpb25cbiAqIEBwYXJhbSBqaWQgdGhlIGppZCBmcm9tIHdoaWNoIHRoZSBwcmVzZW50YXRpb24gd2FzIGFkZGVkXG4gKiBAcGFyYW0gcHJlc1VybCB1cmwgb2YgdGhlIHByZXNlbnRhdGlvblxuICogQHBhcmFtIGN1cnJlbnRTbGlkZSB0aGUgY3VycmVudCBzbGlkZSB0byB3aGljaCB3ZSBzaG91bGQgbW92ZVxuICovXG5mdW5jdGlvbiBwcmVzZW50YXRpb25BZGRlZChldmVudCwgamlkLCBwcmVzVXJsLCBjdXJyZW50U2xpZGUpIHtcbiAgICBjb25zb2xlLmxvZyhcInByZXNlbnRhdGlvbiBhZGRlZFwiLCBwcmVzVXJsKTtcblxuICAgIHZhciBwcmVzSWQgPSBnZXRQcmVzZW50YXRpb25JZChwcmVzVXJsKTtcblxuICAgIHZhciBlbGVtZW50SWQgPSAncGFydGljaXBhbnRfJ1xuICAgICAgICArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZClcbiAgICAgICAgKyAnXycgKyBwcmVzSWQ7XG5cbiAgICAvLyBXZSBleHBsaWNpdGx5IGRvbid0IHNwZWNpZnkgdGhlIHBlZXIgamlkIGhlcmUsIGJlY2F1c2Ugd2UgZG9uJ3Qgd2FudFxuICAgIC8vIHRoaXMgdmlkZW8gdG8gYmUgZGVhbHQgd2l0aCBhcyBhIHBlZXIgcmVsYXRlZCBvbmUgKGZvciBleGFtcGxlIHdlXG4gICAgLy8gZG9uJ3Qgd2FudCB0byBzaG93IGEgbXV0ZS9raWNrIG1lbnUgZm9yIHRoaXMgb25lLCBldGMuKS5cbiAgICBWaWRlb0xheW91dC5hZGRSZW1vdGVWaWRlb0NvbnRhaW5lcihudWxsLCBlbGVtZW50SWQpO1xuICAgIFZpZGVvTGF5b3V0LnJlc2l6ZVRodW1ibmFpbHMoKTtcblxuICAgIHZhciBjb250cm9sc0VuYWJsZWQgPSBmYWxzZTtcbiAgICBpZiAoamlkID09PSBBUFAueG1wcC5teUppZCgpKVxuICAgICAgICBjb250cm9sc0VuYWJsZWQgPSB0cnVlO1xuXG4gICAgc2V0UHJlc2VudGF0aW9uVmlzaWJsZSh0cnVlKTtcbiAgICAkKCcjbGFyZ2VWaWRlb0NvbnRhaW5lcicpLmhvdmVyKFxuICAgICAgICBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmIChQcmV6aS5pc1ByZXNlbnRhdGlvblZpc2libGUoKSkge1xuICAgICAgICAgICAgICAgIHZhciByZWxvYWRCdXR0b25SaWdodCA9IHdpbmRvdy5pbm5lcldpZHRoXG4gICAgICAgICAgICAgICAgICAgIC0gJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS5vZmZzZXQoKS5sZWZ0XG4gICAgICAgICAgICAgICAgICAgIC0gJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS53aWR0aCgpO1xuXG4gICAgICAgICAgICAgICAgJCgnI3JlbG9hZFByZXNlbnRhdGlvbicpLmNzcyh7ICByaWdodDogcmVsb2FkQnV0dG9uUmlnaHQsXG4gICAgICAgICAgICAgICAgICAgIGRpc3BsYXk6J2lubGluZS1ibG9jayd9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICBpZiAoIVByZXppLmlzUHJlc2VudGF0aW9uVmlzaWJsZSgpKVxuICAgICAgICAgICAgICAgICQoJyNyZWxvYWRQcmVzZW50YXRpb24nKS5jc3Moe2Rpc3BsYXk6J25vbmUnfSk7XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB2YXIgZSA9IGV2ZW50LnRvRWxlbWVudCB8fCBldmVudC5yZWxhdGVkVGFyZ2V0O1xuXG4gICAgICAgICAgICAgICAgaWYgKGUgJiYgZS5pZCAhPSAncmVsb2FkUHJlc2VudGF0aW9uJyAmJiBlLmlkICE9ICdoZWFkZXInKVxuICAgICAgICAgICAgICAgICAgICAkKCcjcmVsb2FkUHJlc2VudGF0aW9uJykuY3NzKHtkaXNwbGF5Oidub25lJ30pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcblxuICAgIHByZXppUGxheWVyID0gbmV3IFByZXppUGxheWVyKFxuICAgICAgICAncHJlc2VudGF0aW9uJyxcbiAgICAgICAge3ByZXppSWQ6IHByZXNJZCxcbiAgICAgICAgICAgIHdpZHRoOiBnZXRQcmVzZW50YXRpb25XaWR0aCgpLFxuICAgICAgICAgICAgaGVpZ2h0OiBnZXRQcmVzZW50YXRpb25IZWloZ3QoKSxcbiAgICAgICAgICAgIGNvbnRyb2xzOiBjb250cm9sc0VuYWJsZWQsXG4gICAgICAgICAgICBkZWJ1ZzogdHJ1ZVxuICAgICAgICB9KTtcblxuICAgICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykuYXR0cignaWQnLCBwcmV6aVBsYXllci5vcHRpb25zLnByZXppSWQpO1xuXG4gICAgcHJlemlQbGF5ZXIub24oUHJlemlQbGF5ZXIuRVZFTlRfU1RBVFVTLCBmdW5jdGlvbihldmVudCkge1xuICAgICAgICBjb25zb2xlLmxvZyhcInByZXppIHN0YXR1c1wiLCBldmVudC52YWx1ZSk7XG4gICAgICAgIGlmIChldmVudC52YWx1ZSA9PSBQcmV6aVBsYXllci5TVEFUVVNfQ09OVEVOVF9SRUFEWSkge1xuICAgICAgICAgICAgaWYgKGppZCAhPSBBUFAueG1wcC5teUppZCgpKVxuICAgICAgICAgICAgICAgIHByZXppUGxheWVyLmZseVRvU3RlcChjdXJyZW50U2xpZGUpO1xuICAgICAgICB9XG4gICAgfSk7XG5cbiAgICBwcmV6aVBsYXllci5vbihQcmV6aVBsYXllci5FVkVOVF9DVVJSRU5UX1NURVAsIGZ1bmN0aW9uKGV2ZW50KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiZXZlbnQgdmFsdWVcIiwgZXZlbnQudmFsdWUpO1xuICAgICAgICBBUFAueG1wcC5hZGRUb1ByZXNlbmNlKFwicHJlemlTbGlkZVwiLCBldmVudC52YWx1ZSk7XG4gICAgfSk7XG5cbiAgICAkKFwiI1wiICsgZWxlbWVudElkKS5jc3MoICdiYWNrZ3JvdW5kLWltYWdlJyxcbiAgICAgICAgJ3VybCguLi9pbWFnZXMvYXZhdGFycHJlemkucG5nKScpO1xuICAgICQoXCIjXCIgKyBlbGVtZW50SWQpLmNsaWNrKFxuICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBzZXRQcmVzZW50YXRpb25WaXNpYmxlKHRydWUpO1xuICAgICAgICB9XG4gICAgKTtcbn07XG5cbi8qKlxuICogQSBwcmVzZW50YXRpb24gaGFzIGJlZW4gcmVtb3ZlZC5cbiAqXG4gKiBAcGFyYW0gZXZlbnQgdGhlIGV2ZW50IGluZGljYXRpbmcgdGhlIHJlbW92ZSBvZiBhIHByZXNlbnRhdGlvblxuICogQHBhcmFtIGppZCB0aGUgamlkIGZvciB3aGljaCB0aGUgcHJlc2VudGF0aW9uIHdhcyByZW1vdmVkXG4gKiBAcGFyYW0gdGhlIHVybCBvZiB0aGUgcHJlc2VudGF0aW9uXG4gKi9cbmZ1bmN0aW9uIHByZXNlbnRhdGlvblJlbW92ZWQoZXZlbnQsIGppZCwgcHJlc1VybCkge1xuICAgIGNvbnNvbGUubG9nKCdwcmVzZW50YXRpb24gcmVtb3ZlZCcsIHByZXNVcmwpO1xuICAgIHZhciBwcmVzSWQgPSBnZXRQcmVzZW50YXRpb25JZChwcmVzVXJsKTtcbiAgICBzZXRQcmVzZW50YXRpb25WaXNpYmxlKGZhbHNlKTtcbiAgICAkKCcjcGFydGljaXBhbnRfJ1xuICAgICAgICArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZClcbiAgICAgICAgKyAnXycgKyBwcmVzSWQpLnJlbW92ZSgpO1xuICAgICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykucmVtb3ZlKCk7XG4gICAgaWYgKHByZXppUGxheWVyICE9IG51bGwpIHtcbiAgICAgICAgcHJlemlQbGF5ZXIuZGVzdHJveSgpO1xuICAgICAgICBwcmV6aVBsYXllciA9IG51bGw7XG4gICAgfVxufTtcblxuLyoqXG4gKiBJbmRpY2F0ZXMgaWYgdGhlIGdpdmVuIHN0cmluZyBpcyBhbiBhbHBoYW51bWVyaWMgc3RyaW5nLlxuICogTm90ZSB0aGF0IHNvbWUgc3BlY2lhbCBjaGFyYWN0ZXJzIGFyZSBhbHNvIGFsbG93ZWQgKC0sIF8gLCAvLCAmLCA/LCA9LCA7KSBmb3IgdGhlXG4gKiBwdXJwb3NlIG9mIGNoZWNraW5nIFVSSXMuXG4gKi9cbmZ1bmN0aW9uIGlzQWxwaGFudW1lcmljKHVuc2FmZVRleHQpIHtcbiAgICB2YXIgcmVnZXggPSAvXlthLXowLTktX1xcLyZcXD89O10rJC9pO1xuICAgIHJldHVybiByZWdleC50ZXN0KHVuc2FmZVRleHQpO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHByZXNlbnRhdGlvbiBpZCBmcm9tIHRoZSBnaXZlbiB1cmwuXG4gKi9cbmZ1bmN0aW9uIGdldFByZXNlbnRhdGlvbklkIChwcmVzVXJsKSB7XG4gICAgdmFyIHByZXNJZFRtcCA9IHByZXNVcmwuc3Vic3RyaW5nKHByZXNVcmwuaW5kZXhPZihcInByZXppLmNvbS9cIikgKyAxMCk7XG4gICAgcmV0dXJuIHByZXNJZFRtcC5zdWJzdHJpbmcoMCwgcHJlc0lkVG1wLmluZGV4T2YoJy8nKSk7XG59XG5cbi8qKlxuICogUmV0dXJucyB0aGUgcHJlc2VudGF0aW9uIHdpZHRoLlxuICovXG5mdW5jdGlvbiBnZXRQcmVzZW50YXRpb25XaWR0aCgpIHtcbiAgICB2YXIgYXZhaWxhYmxlV2lkdGggPSBVSVV0aWwuZ2V0QXZhaWxhYmxlVmlkZW9XaWR0aCgpO1xuICAgIHZhciBhdmFpbGFibGVIZWlnaHQgPSBnZXRQcmVzZW50YXRpb25IZWloZ3QoKTtcblxuICAgIHZhciBhc3BlY3RSYXRpbyA9IDE2LjAgLyA5LjA7XG4gICAgaWYgKGF2YWlsYWJsZUhlaWdodCA8IGF2YWlsYWJsZVdpZHRoIC8gYXNwZWN0UmF0aW8pIHtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSBNYXRoLmZsb29yKGF2YWlsYWJsZUhlaWdodCAqIGFzcGVjdFJhdGlvKTtcbiAgICB9XG4gICAgcmV0dXJuIGF2YWlsYWJsZVdpZHRoO1xufVxuXG4vKipcbiAqIFJldHVybnMgdGhlIHByZXNlbnRhdGlvbiBoZWlnaHQuXG4gKi9cbmZ1bmN0aW9uIGdldFByZXNlbnRhdGlvbkhlaWhndCgpIHtcbiAgICB2YXIgcmVtb3RlVmlkZW9zID0gJCgnI3JlbW90ZVZpZGVvcycpO1xuICAgIHJldHVybiB3aW5kb3cuaW5uZXJIZWlnaHQgLSByZW1vdGVWaWRlb3Mub3V0ZXJIZWlnaHQoKTtcbn1cblxuLyoqXG4gKiBSZXNpemVzIHRoZSBwcmVzZW50YXRpb24gaWZyYW1lLlxuICovXG5mdW5jdGlvbiByZXNpemUoKSB7XG4gICAgaWYgKCQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykpIHtcbiAgICAgICAgJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS53aWR0aChnZXRQcmVzZW50YXRpb25XaWR0aCgpKTtcbiAgICAgICAgJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKS5oZWlnaHQoZ2V0UHJlc2VudGF0aW9uSGVpaGd0KCkpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBTaG93cy9oaWRlcyBhIHByZXNlbnRhdGlvbi5cbiAqL1xuZnVuY3Rpb24gc2V0UHJlc2VudGF0aW9uVmlzaWJsZSh2aXNpYmxlKSB7XG4gICAgdmFyIHByZXppID0gJCgnI3ByZXNlbnRhdGlvbj5pZnJhbWUnKTtcbiAgICBpZiAodmlzaWJsZSkge1xuICAgICAgICAvLyBUcmlnZ2VyIHRoZSB2aWRlby5zZWxlY3RlZCBldmVudCB0byBpbmRpY2F0ZSBhIGNoYW5nZSBpbiB0aGVcbiAgICAgICAgLy8gbGFyZ2UgdmlkZW8uXG4gICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoXCJ2aWRlby5zZWxlY3RlZFwiLCBbdHJ1ZV0pO1xuXG4gICAgICAgICQoJyNsYXJnZVZpZGVvJykuZmFkZU91dCgzMDApO1xuICAgICAgICBwcmV6aS5mYWRlSW4oMzAwLCBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHByZXppLmNzcyh7b3BhY2l0eTonMSd9KTtcbiAgICAgICAgICAgIFRvb2xiYXJUb2dnbGVyLmRvY2tUb29sYmFyKHRydWUpO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2V0TGFyZ2VWaWRlb1Zpc2libGUoZmFsc2UpO1xuICAgICAgICB9KTtcbiAgICAgICAgJCgnI2FjdGl2ZVNwZWFrZXInKS5jc3MoJ3Zpc2liaWxpdHknLCAnaGlkZGVuJyk7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICBpZiAocHJlemkuY3NzKCdvcGFjaXR5JykgPT0gJzEnKSB7XG4gICAgICAgICAgICBwcmV6aS5mYWRlT3V0KDMwMCwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHByZXppLmNzcyh7b3BhY2l0eTonMCd9KTtcbiAgICAgICAgICAgICAgICAkKCcjcmVsb2FkUHJlc2VudGF0aW9uJykuY3NzKHtkaXNwbGF5Oidub25lJ30pO1xuICAgICAgICAgICAgICAgICQoJyNsYXJnZVZpZGVvJykuZmFkZUluKDMwMCwgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNldExhcmdlVmlkZW9WaXNpYmxlKHRydWUpO1xuICAgICAgICAgICAgICAgICAgICBUb29sYmFyVG9nZ2xlci5kb2NrVG9vbGJhcihmYWxzZSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgIH1cbn1cblxuLyoqXG4gKiBQcmVzZW50YXRpb24gaGFzIGJlZW4gcmVtb3ZlZC5cbiAqL1xuJChkb2N1bWVudCkuYmluZCgncHJlc2VudGF0aW9ucmVtb3ZlZC5tdWMnLCBwcmVzZW50YXRpb25SZW1vdmVkKTtcblxuLyoqXG4gKiBQcmVzZW50YXRpb24gaGFzIGJlZW4gYWRkZWQuXG4gKi9cbiQoZG9jdW1lbnQpLmJpbmQoJ3ByZXNlbnRhdGlvbmFkZGVkLm11YycsIHByZXNlbnRhdGlvbkFkZGVkKTtcblxuLypcbiAqIEluZGljYXRlcyBwcmVzZW50YXRpb24gc2xpZGUgY2hhbmdlLlxuICovXG4kKGRvY3VtZW50KS5iaW5kKCdnb3Rvc2xpZGUubXVjJywgZnVuY3Rpb24gKGV2ZW50LCBqaWQsIHByZXNVcmwsIGN1cnJlbnQpIHtcbiAgICBpZiAocHJlemlQbGF5ZXIgJiYgcHJlemlQbGF5ZXIuZ2V0Q3VycmVudFN0ZXAoKSAhPSBjdXJyZW50KSB7XG4gICAgICAgIHByZXppUGxheWVyLmZseVRvU3RlcChjdXJyZW50KTtcblxuICAgICAgICB2YXIgYW5pbWF0aW9uU3RlcHNBcnJheSA9IHByZXppUGxheWVyLmdldEFuaW1hdGlvbkNvdW50T25TdGVwcygpO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHBhcnNlSW50KGFuaW1hdGlvblN0ZXBzQXJyYXlbY3VycmVudF0pOyBpKyspIHtcbiAgICAgICAgICAgIHByZXppUGxheWVyLmZseVRvU3RlcChjdXJyZW50LCBpKTtcbiAgICAgICAgfVxuICAgIH1cbn0pO1xuXG4vKipcbiAqIE9uIHZpZGVvIHNlbGVjdGVkIGV2ZW50LlxuICovXG4kKGRvY3VtZW50KS5iaW5kKCd2aWRlby5zZWxlY3RlZCcsIGZ1bmN0aW9uIChldmVudCwgaXNQcmVzZW50YXRpb24pIHtcbiAgICBpZiAoIWlzUHJlc2VudGF0aW9uICYmICQoJyNwcmVzZW50YXRpb24+aWZyYW1lJykpIHtcbiAgICAgICAgc2V0UHJlc2VudGF0aW9uVmlzaWJsZShmYWxzZSk7XG4gICAgfVxufSk7XG5cbiQod2luZG93KS5yZXNpemUoZnVuY3Rpb24gKCkge1xuICAgIHJlc2l6ZSgpO1xufSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUHJlemk7XG4iLCIoZnVuY3Rpb24oKSB7XG4gICAgXCJ1c2Ugc3RyaWN0XCI7XG4gICAgdmFyIF9fYmluZCA9IGZ1bmN0aW9uKGZuLCBtZSl7IHJldHVybiBmdW5jdGlvbigpeyByZXR1cm4gZm4uYXBwbHkobWUsIGFyZ3VtZW50cyk7IH07IH07XG5cbiAgICB3aW5kb3cuUHJlemlQbGF5ZXIgPSAoZnVuY3Rpb24oKSB7XG5cbiAgICAgICAgUHJlemlQbGF5ZXIuQVBJX1ZFUlNJT04gPSAxO1xuICAgICAgICBQcmV6aVBsYXllci5DVVJSRU5UX1NURVAgPSAnY3VycmVudFN0ZXAnO1xuICAgICAgICBQcmV6aVBsYXllci5DVVJSRU5UX0FOSU1BVElPTl9TVEVQID0gJ2N1cnJlbnRBbmltYXRpb25TdGVwJztcbiAgICAgICAgUHJlemlQbGF5ZXIuQ1VSUkVOVF9PQkpFQ1QgPSAnY3VycmVudE9iamVjdCc7XG4gICAgICAgIFByZXppUGxheWVyLlNUQVRVU19MT0FESU5HID0gJ2xvYWRpbmcnO1xuICAgICAgICBQcmV6aVBsYXllci5TVEFUVVNfUkVBRFkgPSAncmVhZHknO1xuICAgICAgICBQcmV6aVBsYXllci5TVEFUVVNfQ09OVEVOVF9SRUFEWSA9ICdjb250ZW50cmVhZHknO1xuICAgICAgICBQcmV6aVBsYXllci5FVkVOVF9DVVJSRU5UX1NURVAgPSBcImN1cnJlbnRTdGVwQ2hhbmdlXCI7XG4gICAgICAgIFByZXppUGxheWVyLkVWRU5UX0NVUlJFTlRfQU5JTUFUSU9OX1NURVAgPSBcImN1cnJlbnRBbmltYXRpb25TdGVwQ2hhbmdlXCI7XG4gICAgICAgIFByZXppUGxheWVyLkVWRU5UX0NVUlJFTlRfT0JKRUNUID0gXCJjdXJyZW50T2JqZWN0Q2hhbmdlXCI7XG4gICAgICAgIFByZXppUGxheWVyLkVWRU5UX1NUQVRVUyA9IFwic3RhdHVzQ2hhbmdlXCI7XG4gICAgICAgIFByZXppUGxheWVyLkVWRU5UX1BMQVlJTkcgPSBcImlzQXV0b1BsYXlpbmdDaGFuZ2VcIjtcbiAgICAgICAgUHJlemlQbGF5ZXIuRVZFTlRfSVNfTU9WSU5HID0gXCJpc01vdmluZ0NoYW5nZVwiO1xuICAgICAgICBQcmV6aVBsYXllci5kb21haW4gPSBcImh0dHBzOi8vcHJlemkuY29tXCI7XG4gICAgICAgIFByZXppUGxheWVyLnBhdGggPSBcIi9wbGF5ZXIvXCI7XG4gICAgICAgIFByZXppUGxheWVyLnBsYXllcnMgPSB7fTtcbiAgICAgICAgUHJlemlQbGF5ZXIuYmluZGVkX21ldGhvZHMgPSBbJ2NoYW5nZXNIYW5kbGVyJ107XG5cbiAgICAgICAgUHJlemlQbGF5ZXIuY3JlYXRlTXVsdGlwbGVQbGF5ZXJzID0gZnVuY3Rpb24ob3B0aW9uQXJyYXkpe1xuICAgICAgICAgICAgZm9yKHZhciBpPTA7IGk8b3B0aW9uQXJyYXkubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgb3B0aW9uU2V0ID0gb3B0aW9uQXJyYXlbaV07XG4gICAgICAgICAgICAgICAgbmV3IFByZXppUGxheWVyKG9wdGlvblNldC5pZCwgb3B0aW9uU2V0KTtcbiAgICAgICAgICAgIH07XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIubWVzc2FnZVJlY2VpdmVkID0gZnVuY3Rpb24oZXZlbnQpe1xuICAgICAgICAgICAgdmFyIG1lc3NhZ2UsIGl0ZW0sIHBsYXllcjtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZSA9IEpTT04ucGFyc2UoZXZlbnQuZGF0YSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7fVxuICAgICAgICAgICAgaWYgKG1lc3NhZ2UuaWQgJiYgKHBsYXllciA9IFByZXppUGxheWVyLnBsYXllcnNbbWVzc2FnZS5pZF0pKXtcbiAgICAgICAgICAgICAgICBpZiAocGxheWVyLm9wdGlvbnMuZGVidWcgPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNvbnNvbGUgJiYgY29uc29sZS5sb2cpIGNvbnNvbGUubG9nKCdyZWNlaXZlZCcsIG1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpZiAobWVzc2FnZS50eXBlID09PSBcImNoYW5nZXNcIil7XG4gICAgICAgICAgICAgICAgICAgIHBsYXllci5jaGFuZ2VzSGFuZGxlcihtZXNzYWdlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaT0wOyBpPHBsYXllci5jYWxsYmFja3MubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgaXRlbSA9IHBsYXllci5jYWxsYmFja3NbaV07XG4gICAgICAgICAgICAgICAgICAgIGlmIChpdGVtICYmIG1lc3NhZ2UudHlwZSA9PT0gaXRlbS5ldmVudCl7XG4gICAgICAgICAgICAgICAgICAgICAgICBpdGVtLmNhbGxiYWNrKG1lc3NhZ2UpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuXG4gICAgICAgIGZ1bmN0aW9uIFByZXppUGxheWVyKGlkLCBvcHRpb25zKSB7XG4gICAgICAgICAgICB2YXIgcGFyYW1zLCBwYXJhbVN0cmluZyA9IFwiXCIsIF90aGlzID0gdGhpcztcbiAgICAgICAgICAgIGlmIChQcmV6aVBsYXllci5wbGF5ZXJzW2lkXSl7XG4gICAgICAgICAgICAgICAgUHJlemlQbGF5ZXIucGxheWVyc1tpZF0uZGVzdHJveSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yKHZhciBpPTA7IGk8UHJlemlQbGF5ZXIuYmluZGVkX21ldGhvZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgbWV0aG9kX25hbWUgPSBQcmV6aVBsYXllci5iaW5kZWRfbWV0aG9kc1tpXTtcbiAgICAgICAgICAgICAgICBfdGhpc1ttZXRob2RfbmFtZV0gPSBfX2JpbmQoX3RoaXNbbWV0aG9kX25hbWVdLCBfdGhpcyk7XG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICB0aGlzLm9wdGlvbnMgPSBvcHRpb25zO1xuICAgICAgICAgICAgdGhpcy52YWx1ZXMgPSB7J3N0YXR1cyc6IFByZXppUGxheWVyLlNUQVRVU19MT0FESU5HfTtcbiAgICAgICAgICAgIHRoaXMudmFsdWVzW1ByZXppUGxheWVyLkNVUlJFTlRfU1RFUF0gPSAwO1xuICAgICAgICAgICAgdGhpcy52YWx1ZXNbUHJlemlQbGF5ZXIuQ1VSUkVOVF9BTklNQVRJT05fU1RFUF0gPSAwO1xuICAgICAgICAgICAgdGhpcy52YWx1ZXNbUHJlemlQbGF5ZXIuQ1VSUkVOVF9PQkpFQ1RdID0gbnVsbDtcbiAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tzID0gW107XG4gICAgICAgICAgICB0aGlzLmlkID0gaWQ7XG4gICAgICAgICAgICB0aGlzLmVtYmVkVG8gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChpZCk7XG4gICAgICAgICAgICBpZiAoIXRoaXMuZW1iZWRUbykge1xuICAgICAgICAgICAgICAgIHRocm93IFwiVGhlIGVsZW1lbnQgaWQgaXMgbm90IGF2YWlsYWJsZS5cIjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMuaWZyYW1lID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaWZyYW1lJyk7XG4gICAgICAgICAgICBwYXJhbXMgPSBbXG4gICAgICAgICAgICAgICAgeyBuYW1lOiAnb2lkJywgdmFsdWU6IG9wdGlvbnMucHJlemlJZCB9LFxuICAgICAgICAgICAgICAgIHsgbmFtZTogJ2V4cGxvcmFibGUnLCB2YWx1ZTogb3B0aW9ucy5leHBsb3JhYmxlID8gMSA6IDAgfSxcbiAgICAgICAgICAgICAgICB7IG5hbWU6ICdjb250cm9scycsIHZhbHVlOiBvcHRpb25zLmNvbnRyb2xzID8gMSA6IDAgfVxuICAgICAgICAgICAgXTtcbiAgICAgICAgICAgIGZvcih2YXIgaT0wOyBpPHBhcmFtcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHZhciBwYXJhbSA9IHBhcmFtc1tpXTtcbiAgICAgICAgICAgICAgICBwYXJhbVN0cmluZyArPSAoaT09PTAgPyBcIj9cIiA6IFwiJlwiKSArIHBhcmFtLm5hbWUgKyBcIj1cIiArIHBhcmFtLnZhbHVlO1xuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIHRoaXMuaWZyYW1lLnNyYyA9IFByZXppUGxheWVyLmRvbWFpbiArIFByZXppUGxheWVyLnBhdGggKyBwYXJhbVN0cmluZztcbiAgICAgICAgICAgIHRoaXMuaWZyYW1lLmZyYW1lQm9yZGVyID0gMDtcbiAgICAgICAgICAgIHRoaXMuaWZyYW1lLnNjcm9sbGluZyA9IFwibm9cIjtcbiAgICAgICAgICAgIHRoaXMuaWZyYW1lLndpZHRoID0gb3B0aW9ucy53aWR0aCB8fCA2NDA7XG4gICAgICAgICAgICB0aGlzLmlmcmFtZS5oZWlnaHQgPSBvcHRpb25zLmhlaWdodCB8fCA0ODA7XG4gICAgICAgICAgICB0aGlzLmVtYmVkVG8uaW5uZXJIVE1MID0gJyc7XG4gICAgICAgICAgICAvLyBKSVRTSTogSU4gQ0FTRSBTT01FVEhJTkcgR09FUyBXUk9ORy5cbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWJlZFRvLmFwcGVuZENoaWxkKHRoaXMuaWZyYW1lKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhdGNoIChlcnIpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIkNBVENIIEVSUk9SXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBKSVRTSTogSW5jcmVhc2UgaW50ZXJ2YWwgZnJvbSAyMDAgdG8gNTAwLCB3aGljaCBmaXhlcyBwcmV6aVxuICAgICAgICAgICAgLy8gY3Jhc2hlcyBmb3IgdXMuXG4gICAgICAgICAgICB0aGlzLmluaXRQb2xsSW50ZXJ2YWwgPSBzZXRJbnRlcnZhbChmdW5jdGlvbigpe1xuICAgICAgICAgICAgICAgIF90aGlzLnNlbmRNZXNzYWdlKHsnYWN0aW9uJzogJ2luaXQnfSk7XG4gICAgICAgICAgICB9LCA1MDApO1xuICAgICAgICAgICAgUHJlemlQbGF5ZXIucGxheWVyc1tpZF0gPSB0aGlzO1xuICAgICAgICB9XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmNoYW5nZXNIYW5kbGVyID0gZnVuY3Rpb24obWVzc2FnZSkge1xuICAgICAgICAgICAgdmFyIGtleSwgdmFsdWUsIGosIGl0ZW07XG4gICAgICAgICAgICBpZiAodGhpcy5pbml0UG9sbEludGVydmFsKSB7XG4gICAgICAgICAgICAgICAgY2xlYXJJbnRlcnZhbCh0aGlzLmluaXRQb2xsSW50ZXJ2YWwpO1xuICAgICAgICAgICAgICAgIHRoaXMuaW5pdFBvbGxJbnRlcnZhbCA9IGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZm9yIChrZXkgaW4gbWVzc2FnZS5kYXRhKSB7XG4gICAgICAgICAgICAgICAgaWYgKG1lc3NhZ2UuZGF0YS5oYXNPd25Qcm9wZXJ0eShrZXkpKXtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBtZXNzYWdlLmRhdGFba2V5XTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy52YWx1ZXNba2V5XSA9IHZhbHVlO1xuICAgICAgICAgICAgICAgICAgICBmb3IgKGo9MDsgajx0aGlzLmNhbGxiYWNrcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgaXRlbSA9IHRoaXMuY2FsbGJhY2tzW2pdO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGl0ZW0gJiYgaXRlbS5ldmVudCA9PT0ga2V5ICsgXCJDaGFuZ2VcIil7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaXRlbS5jYWxsYmFjayh7dHlwZTogaXRlbS5ldmVudCwgdmFsdWU6IHZhbHVlfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmRlc3Ryb3kgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmluaXRQb2xsSW50ZXJ2YWwpIHtcbiAgICAgICAgICAgICAgICBjbGVhckludGVydmFsKHRoaXMuaW5pdFBvbGxJbnRlcnZhbCk7XG4gICAgICAgICAgICAgICAgdGhpcy5pbml0UG9sbEludGVydmFsID0gZmFsc2U7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLmVtYmVkVG8uaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLnNlbmRNZXNzYWdlID0gZnVuY3Rpb24obWVzc2FnZSkge1xuICAgICAgICAgICAgaWYgKHRoaXMub3B0aW9ucy5kZWJ1ZyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIGlmIChjb25zb2xlICYmIGNvbnNvbGUubG9nKSBjb25zb2xlLmxvZygnc2VudCcsIG1lc3NhZ2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgbWVzc2FnZS52ZXJzaW9uID0gUHJlemlQbGF5ZXIuQVBJX1ZFUlNJT047XG4gICAgICAgICAgICBtZXNzYWdlLmlkID0gdGhpcy5pZDtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLmlmcmFtZS5jb250ZW50V2luZG93LnBvc3RNZXNzYWdlKEpTT04uc3RyaW5naWZ5KG1lc3NhZ2UpLCAnKicpO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5uZXh0U3RlcCA9IC8qIG5leHRTdGVwIGlzIERFUFJFQ0FURUQgKi9cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmZseVRvTmV4dFN0ZXAgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNlbmRNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAnYWN0aW9uJzogJ3ByZXNlbnQnLFxuICAgICAgICAgICAgICAgICdkYXRhJzogWydtb3ZlVG9OZXh0U3RlcCddXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUucHJldmlvdXNTdGVwID0gLyogcHJldmlvdXNTdGVwIGlzIERFUFJFQ0FURUQgKi9cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmZseVRvUHJldmlvdXNTdGVwID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZW5kTWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgJ2FjdGlvbic6ICdwcmVzZW50JyxcbiAgICAgICAgICAgICAgICAnZGF0YSc6IFsnbW92ZVRvUHJldlN0ZXAnXVxuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLnRvU3RlcCA9IC8qIHRvU3RlcCBpcyBERVBSRUNBVEVEICovXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5mbHlUb1N0ZXAgPSBmdW5jdGlvbihzdGVwLCBhbmltYXRpb25fc3RlcCkge1xuICAgICAgICAgICAgdmFyIG9iaiA9IHRoaXM7XG4gICAgICAgICAgICAvLyBjaGVjayBhbmltYXRpb25fc3RlcFxuICAgICAgICAgICAgaWYgKGFuaW1hdGlvbl9zdGVwID4gMCAmJlxuICAgICAgICAgICAgICAgIG9iai52YWx1ZXMuYW5pbWF0aW9uQ291bnRPblN0ZXBzICYmXG4gICAgICAgICAgICAgICAgb2JqLnZhbHVlcy5hbmltYXRpb25Db3VudE9uU3RlcHNbc3RlcF0gPD0gYW5pbWF0aW9uX3N0ZXApIHtcbiAgICAgICAgICAgICAgICBhbmltYXRpb25fc3RlcCA9IG9iai52YWx1ZXMuYW5pbWF0aW9uQ291bnRPblN0ZXBzW3N0ZXBdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8ganVtcCB0byBhbmltYXRpb24gc3RlcHMgYnkgY2FsbGluZyBmbHlUb05leHRTdGVwKClcbiAgICAgICAgICAgIGZ1bmN0aW9uIGRvQW5pbWF0aW9uU3RlcHMoKSB7XG4gICAgICAgICAgICAgICAgaWYgKG9iai52YWx1ZXMuaXNNb3ZpbmcgPT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgICAgICBzZXRUaW1lb3V0KGRvQW5pbWF0aW9uU3RlcHMsIDEwMCk7IC8vIHdhaXQgdW50aWwgdGhlIGZsaWdodCBlbmRzXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgd2hpbGUgKGFuaW1hdGlvbl9zdGVwLS0gPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIG9iai5mbHlUb05leHRTdGVwKCk7IC8vIGRvIHRoZSBhbmltYXRpb24gc3RlcHNcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBzZXRUaW1lb3V0KGRvQW5pbWF0aW9uU3RlcHMsIDIwMCk7IC8vIDIwMG1zIGlzIHRoZSBpbnRlcm5hbCBcInJlcG9ydGluZ1wiIHRpbWVcbiAgICAgICAgICAgIC8vIGp1bXAgdG8gdGhlIHN0ZXBcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNlbmRNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAnYWN0aW9uJzogJ3ByZXNlbnQnLFxuICAgICAgICAgICAgICAgICdkYXRhJzogWydtb3ZlVG9TdGVwJywgc3RlcF1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS50b09iamVjdCA9IC8qIHRvT2JqZWN0IGlzIERFUFJFQ0FURUQgKi9cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmZseVRvT2JqZWN0ID0gZnVuY3Rpb24ob2JqZWN0SWQpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnNlbmRNZXNzYWdlKHtcbiAgICAgICAgICAgICAgICAnYWN0aW9uJzogJ3ByZXNlbnQnLFxuICAgICAgICAgICAgICAgICdkYXRhJzogWydtb3ZlVG9PYmplY3QnLCBvYmplY3RJZF1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5wbGF5ID0gZnVuY3Rpb24oZGVmYXVsdERlbGF5KSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZW5kTWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgJ2FjdGlvbic6ICdwcmVzZW50JyxcbiAgICAgICAgICAgICAgICAnZGF0YSc6IFsnc3RhcnRBdXRvUGxheScsIGRlZmF1bHREZWxheV1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5zdG9wID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5zZW5kTWVzc2FnZSh7XG4gICAgICAgICAgICAgICAgJ2FjdGlvbic6ICdwcmVzZW50JyxcbiAgICAgICAgICAgICAgICAnZGF0YSc6IFsnc3RvcEF1dG9QbGF5J11cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5wYXVzZSA9IGZ1bmN0aW9uKGRlZmF1bHREZWxheSkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuc2VuZE1lc3NhZ2Uoe1xuICAgICAgICAgICAgICAgICdhY3Rpb24nOiAncHJlc2VudCcsXG4gICAgICAgICAgICAgICAgJ2RhdGEnOiBbJ3BhdXNlQXV0b1BsYXknLCBkZWZhdWx0RGVsYXldXG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0Q3VycmVudFN0ZXAgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnZhbHVlcy5jdXJyZW50U3RlcDtcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0Q3VycmVudEFuaW1hdGlvblN0ZXAgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnZhbHVlcy5jdXJyZW50QW5pbWF0aW9uU3RlcDtcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0Q3VycmVudE9iamVjdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzLmN1cnJlbnRPYmplY3Q7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmdldFN0YXR1cyA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMudmFsdWVzLnN0YXR1cztcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuaXNQbGF5aW5nID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXMuaXNBdXRvUGxheWluZztcbiAgICAgICAgfTtcblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0U3RlcENvdW50ID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXMuc3RlcENvdW50O1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5nZXRBbmltYXRpb25Db3VudE9uU3RlcHMgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHJldHVybiB0aGlzLnZhbHVlcy5hbmltYXRpb25Db3VudE9uU3RlcHM7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLmdldFRpdGxlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy52YWx1ZXMudGl0bGU7XG4gICAgICAgIH07XG5cbiAgICAgICAgUHJlemlQbGF5ZXIucHJvdG90eXBlLnNldERpbWVuc2lvbnMgPSBmdW5jdGlvbihkaW1zKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBwYXJhbWV0ZXIgaW4gZGltcykge1xuICAgICAgICAgICAgICAgIHRoaXMuaWZyYW1lW3BhcmFtZXRlcl0gPSBkaW1zW3BhcmFtZXRlcl07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUuZ2V0RGltZW5zaW9ucyA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgICAgICB3aWR0aDogcGFyc2VJbnQodGhpcy5pZnJhbWUud2lkdGgsIDEwKSxcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IHBhcnNlSW50KHRoaXMuaWZyYW1lLmhlaWdodCwgMTApXG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBQcmV6aVBsYXllci5wcm90b3R5cGUub24gPSBmdW5jdGlvbihldmVudCwgY2FsbGJhY2spIHtcbiAgICAgICAgICAgIHRoaXMuY2FsbGJhY2tzLnB1c2goe1xuICAgICAgICAgICAgICAgIGV2ZW50OiBldmVudCxcbiAgICAgICAgICAgICAgICBjYWxsYmFjazogY2FsbGJhY2tcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9O1xuXG4gICAgICAgIFByZXppUGxheWVyLnByb3RvdHlwZS5vZmYgPSBmdW5jdGlvbihldmVudCwgY2FsbGJhY2spIHtcbiAgICAgICAgICAgIHZhciBqLCBpdGVtO1xuICAgICAgICAgICAgaWYgKGV2ZW50ID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNhbGxiYWNrcyA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaiA9IHRoaXMuY2FsbGJhY2tzLmxlbmd0aDtcbiAgICAgICAgICAgIHdoaWxlIChqLS0pIHtcbiAgICAgICAgICAgICAgICBpdGVtID0gdGhpcy5jYWxsYmFja3Nbal07XG4gICAgICAgICAgICAgICAgaWYgKGl0ZW0gJiYgaXRlbS5ldmVudCA9PT0gZXZlbnQgJiYgKGNhbGxiYWNrID09PSB1bmRlZmluZWQgfHwgaXRlbS5jYWxsYmFjayA9PT0gY2FsbGJhY2spKXtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jYWxsYmFja3Muc3BsaWNlKGosIDEpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICBpZiAod2luZG93LmFkZEV2ZW50TGlzdGVuZXIpIHtcbiAgICAgICAgICAgIHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCdtZXNzYWdlJywgUHJlemlQbGF5ZXIubWVzc2FnZVJlY2VpdmVkLCBmYWxzZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB3aW5kb3cuYXR0YWNoRXZlbnQoJ29ubWVzc2FnZScsIFByZXppUGxheWVyLm1lc3NhZ2VSZWNlaXZlZCk7XG4gICAgICAgIH1cblxuICAgICAgICByZXR1cm4gUHJlemlQbGF5ZXI7XG5cbiAgICB9KSgpO1xuXG59KSgpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFByZXppUGxheWVyO1xuIiwidmFyIENoYXQgPSByZXF1aXJlKFwiLi9jaGF0L0NoYXRcIik7XG52YXIgQ29udGFjdExpc3QgPSByZXF1aXJlKFwiLi9jb250YWN0bGlzdC9Db250YWN0TGlzdFwiKTtcbnZhciBTZXR0aW5ncyA9IHJlcXVpcmUoXCIuL3NldHRpbmdzL1NldHRpbmdzXCIpO1xudmFyIFNldHRpbmdzTWVudSA9IHJlcXVpcmUoXCIuL3NldHRpbmdzL1NldHRpbmdzTWVudVwiKTtcbnZhciBWaWRlb0xheW91dCA9IHJlcXVpcmUoXCIuLi92aWRlb2xheW91dC9WaWRlb0xheW91dFwiKTtcbnZhciBUb29sYmFyVG9nZ2xlciA9IHJlcXVpcmUoXCIuLi90b29sYmFycy9Ub29sYmFyVG9nZ2xlclwiKTtcbnZhciBVSVV0aWwgPSByZXF1aXJlKFwiLi4vdXRpbC9VSVV0aWxcIik7XG5cbi8qKlxuICogVG9nZ2xlciBmb3IgdGhlIGNoYXQsIGNvbnRhY3QgbGlzdCwgc2V0dGluZ3MgbWVudSwgZXRjLi5cbiAqL1xudmFyIFBhbmVsVG9nZ2xlciA9IChmdW5jdGlvbihteSkge1xuXG4gICAgdmFyIGN1cnJlbnRseU9wZW4gPSBudWxsO1xuICAgIHZhciBidXR0b25zID0ge1xuICAgICAgICAnI2NoYXRzcGFjZSc6ICcjY2hhdEJvdHRvbUJ1dHRvbicsXG4gICAgICAgICcjY29udGFjdGxpc3QnOiAnI2NvbnRhY3RMaXN0QnV0dG9uJyxcbiAgICAgICAgJyNzZXR0aW5nc21lbnUnOiAnI3NldHRpbmdzQnV0dG9uJ1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXNpemVzIHRoZSB2aWRlbyBhcmVhXG4gICAgICogQHBhcmFtIGlzQ2xvc2luZyB3aGV0aGVyIHRoZSBzaWRlIHBhbmVsIGlzIGdvaW5nIHRvIGJlIGNsb3NlZCBvciBpcyBnb2luZyB0byBvcGVuIC8gcmVtYWluIG9wZW5lZFxuICAgICAqIEBwYXJhbSBjb21wbGV0ZUZ1bmN0aW9uIGEgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIHZpZGVvIHNwYWNlIGlzIHJlc2l6ZWRcbiAgICAgKi9cbiAgICB2YXIgcmVzaXplVmlkZW9BcmVhID0gZnVuY3Rpb24oaXNDbG9zaW5nLCBjb21wbGV0ZUZ1bmN0aW9uKSB7XG4gICAgICAgIHZhciB2aWRlb3NwYWNlID0gJCgnI3ZpZGVvc3BhY2UnKTtcblxuICAgICAgICB2YXIgcGFuZWxTaXplID0gaXNDbG9zaW5nID8gWzAsIDBdIDogUGFuZWxUb2dnbGVyLmdldFBhbmVsU2l6ZSgpO1xuICAgICAgICB2YXIgdmlkZW9zcGFjZVdpZHRoID0gd2luZG93LmlubmVyV2lkdGggLSBwYW5lbFNpemVbMF07XG4gICAgICAgIHZhciB2aWRlb3NwYWNlSGVpZ2h0ID0gd2luZG93LmlubmVySGVpZ2h0O1xuICAgICAgICB2YXIgdmlkZW9TaXplXG4gICAgICAgICAgICA9IFZpZGVvTGF5b3V0LmdldFZpZGVvU2l6ZShudWxsLCBudWxsLCB2aWRlb3NwYWNlV2lkdGgsIHZpZGVvc3BhY2VIZWlnaHQpO1xuICAgICAgICB2YXIgdmlkZW9XaWR0aCA9IHZpZGVvU2l6ZVswXTtcbiAgICAgICAgdmFyIHZpZGVvSGVpZ2h0ID0gdmlkZW9TaXplWzFdO1xuICAgICAgICB2YXIgdmlkZW9Qb3NpdGlvbiA9IFZpZGVvTGF5b3V0LmdldFZpZGVvUG9zaXRpb24odmlkZW9XaWR0aCxcbiAgICAgICAgICAgIHZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgdmlkZW9zcGFjZVdpZHRoLFxuICAgICAgICAgICAgdmlkZW9zcGFjZUhlaWdodCk7XG4gICAgICAgIHZhciBob3Jpem9udGFsSW5kZW50ID0gdmlkZW9Qb3NpdGlvblswXTtcbiAgICAgICAgdmFyIHZlcnRpY2FsSW5kZW50ID0gdmlkZW9Qb3NpdGlvblsxXTtcblxuICAgICAgICB2YXIgdGh1bWJuYWlsU2l6ZSA9IFZpZGVvTGF5b3V0LmNhbGN1bGF0ZVRodW1ibmFpbFNpemUodmlkZW9zcGFjZVdpZHRoKTtcbiAgICAgICAgdmFyIHRodW1ibmFpbHNXaWR0aCA9IHRodW1ibmFpbFNpemVbMF07XG4gICAgICAgIHZhciB0aHVtYm5haWxzSGVpZ2h0ID0gdGh1bWJuYWlsU2l6ZVsxXTtcbiAgICAgICAgLy9mb3IgY2hhdFxuXG4gICAgICAgIHZpZGVvc3BhY2UuYW5pbWF0ZSh7XG4gICAgICAgICAgICAgICAgcmlnaHQ6IHBhbmVsU2l6ZVswXSxcbiAgICAgICAgICAgICAgICB3aWR0aDogdmlkZW9zcGFjZVdpZHRoLFxuICAgICAgICAgICAgICAgIGhlaWdodDogdmlkZW9zcGFjZUhlaWdodFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBxdWV1ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDUwMCxcbiAgICAgICAgICAgICAgICBjb21wbGV0ZTogY29tcGxldGVGdW5jdGlvblxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgJCgnI3JlbW90ZVZpZGVvcycpLmFuaW1hdGUoe1xuICAgICAgICAgICAgICAgIGhlaWdodDogdGh1bWJuYWlsc0hlaWdodFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBxdWV1ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDUwMFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgJCgnI3JlbW90ZVZpZGVvcz5zcGFuJykuYW5pbWF0ZSh7XG4gICAgICAgICAgICAgICAgaGVpZ2h0OiB0aHVtYm5haWxzSGVpZ2h0LFxuICAgICAgICAgICAgICAgIHdpZHRoOiB0aHVtYm5haWxzV2lkdGhcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgcXVldWU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiA1MDAsXG4gICAgICAgICAgICAgICAgY29tcGxldGU6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcihcbiAgICAgICAgICAgICAgICAgICAgICAgIFwicmVtb3RldmlkZW8ucmVzaXplZFwiLFxuICAgICAgICAgICAgICAgICAgICAgICAgW3RodW1ibmFpbHNXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHVtYm5haWxzSGVpZ2h0XSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgJCgnI2xhcmdlVmlkZW9Db250YWluZXInKS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICB3aWR0aDogdmlkZW9zcGFjZVdpZHRoLFxuICAgICAgICAgICAgICAgIGhlaWdodDogdmlkZW9zcGFjZUhlaWdodFxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBxdWV1ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgZHVyYXRpb246IDUwMFxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgJCgnI2xhcmdlVmlkZW8nKS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICB3aWR0aDogdmlkZW9XaWR0aCxcbiAgICAgICAgICAgICAgICBoZWlnaHQ6IHZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgICAgIHRvcDogdmVydGljYWxJbmRlbnQsXG4gICAgICAgICAgICAgICAgYm90dG9tOiB2ZXJ0aWNhbEluZGVudCxcbiAgICAgICAgICAgICAgICBsZWZ0OiBob3Jpem9udGFsSW5kZW50LFxuICAgICAgICAgICAgICAgIHJpZ2h0OiBob3Jpem9udGFsSW5kZW50XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHF1ZXVlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwXG4gICAgICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVG9nZ2xlcyB0aGUgd2luZG93cyBpbiB0aGUgc2lkZSBwYW5lbFxuICAgICAqIEBwYXJhbSBvYmplY3QgdGhlIHdpbmRvdyB0aGF0IHNob3VsZCBiZSBzaG93blxuICAgICAqIEBwYXJhbSBzZWxlY3RvciB0aGUgc2VsZWN0b3IgZm9yIHRoZSBlbGVtZW50IGNvbnRhaW5pbmcgdGhlIHBhbmVsXG4gICAgICogQHBhcmFtIG9uT3BlbkNvbXBsZXRlIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB3aGVuIHRoZSBwYW5lbCBpcyBvcGVuZWRcbiAgICAgKiBAcGFyYW0gb25PcGVuIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBpZiB0aGUgd2luZG93IGlzIGdvaW5nIHRvIGJlIG9wZW5lZFxuICAgICAqIEBwYXJhbSBvbkNsb3NlIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBpZiB0aGUgd2luZG93IGlzIGdvaW5nIHRvIGJlIGNsb3NlZFxuICAgICAqL1xuICAgIHZhciB0b2dnbGUgPSBmdW5jdGlvbihvYmplY3QsIHNlbGVjdG9yLCBvbk9wZW5Db21wbGV0ZSwgb25PcGVuLCBvbkNsb3NlKSB7XG4gICAgICAgIFVJVXRpbC5idXR0b25DbGljayhidXR0b25zW3NlbGVjdG9yXSwgXCJhY3RpdmVcIik7XG5cbiAgICAgICAgaWYgKG9iamVjdC5pc1Zpc2libGUoKSkge1xuICAgICAgICAgICAgJChcIiN0b2FzdC1jb250YWluZXJcIikuYW5pbWF0ZSh7XG4gICAgICAgICAgICAgICAgICAgIHJpZ2h0OiAnNXB4J1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBxdWV1ZTogZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIGR1cmF0aW9uOiA1MDBcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICQoc2VsZWN0b3IpLmhpZGUoXCJzbGlkZVwiLCB7XG4gICAgICAgICAgICAgICAgZGlyZWN0aW9uOiBcInJpZ2h0XCIsXG4gICAgICAgICAgICAgICAgcXVldWU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGR1cmF0aW9uOiA1MDBcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgaWYodHlwZW9mIG9uQ2xvc2UgPT09IFwiZnVuY3Rpb25cIikge1xuICAgICAgICAgICAgICAgIG9uQ2xvc2UoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY3VycmVudGx5T3BlbiA9IG51bGw7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBVbmRvY2sgdGhlIHRvb2xiYXIgd2hlbiB0aGUgY2hhdCBpcyBzaG93biBhbmQgaWYgd2UncmUgaW4gYVxuICAgICAgICAgICAgLy8gdmlkZW8gbW9kZS5cbiAgICAgICAgICAgIGlmIChWaWRlb0xheW91dC5pc0xhcmdlVmlkZW9WaXNpYmxlKCkpIHtcbiAgICAgICAgICAgICAgICBUb29sYmFyVG9nZ2xlci5kb2NrVG9vbGJhcihmYWxzZSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmKGN1cnJlbnRseU9wZW4pIHtcbiAgICAgICAgICAgICAgICB2YXIgY3VycmVudCA9ICQoY3VycmVudGx5T3Blbik7XG4gICAgICAgICAgICAgICAgVUlVdGlsLmJ1dHRvbkNsaWNrKGJ1dHRvbnNbY3VycmVudGx5T3Blbl0sIFwiYWN0aXZlXCIpO1xuICAgICAgICAgICAgICAgIGN1cnJlbnQuY3NzKCd6LWluZGV4JywgNCk7XG4gICAgICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIGN1cnJlbnQuY3NzKCdkaXNwbGF5JywgJ25vbmUnKTtcbiAgICAgICAgICAgICAgICAgICAgY3VycmVudC5jc3MoJ3otaW5kZXgnLCA1KTtcbiAgICAgICAgICAgICAgICB9LCA1MDApO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAkKFwiI3RvYXN0LWNvbnRhaW5lclwiKS5hbmltYXRlKHtcbiAgICAgICAgICAgICAgICAgICAgcmlnaHQ6IChQYW5lbFRvZ2dsZXIuZ2V0UGFuZWxTaXplKClbMF0gKyA1KSArICdweCdcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgcXVldWU6IGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAkKHNlbGVjdG9yKS5zaG93KFwic2xpZGVcIiwge1xuICAgICAgICAgICAgICAgIGRpcmVjdGlvbjogXCJyaWdodFwiLFxuICAgICAgICAgICAgICAgIHF1ZXVlOiBmYWxzZSxcbiAgICAgICAgICAgICAgICBkdXJhdGlvbjogNTAwLFxuICAgICAgICAgICAgICAgIGNvbXBsZXRlOiBvbk9wZW5Db21wbGV0ZVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBpZih0eXBlb2Ygb25PcGVuID09PSBcImZ1bmN0aW9uXCIpIHtcbiAgICAgICAgICAgICAgICBvbk9wZW4oKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgY3VycmVudGx5T3BlbiA9IHNlbGVjdG9yO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIE9wZW5zIC8gY2xvc2VzIHRoZSBjaGF0IGFyZWEuXG4gICAgICovXG4gICAgbXkudG9nZ2xlQ2hhdCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgY2hhdENvbXBsZXRlRnVuY3Rpb24gPSBDaGF0LmlzVmlzaWJsZSgpID9cbiAgICAgICAgICAgIGZ1bmN0aW9uKCkge30gOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBDaGF0LnNjcm9sbENoYXRUb0JvdHRvbSgpO1xuICAgICAgICAgICAgJCgnI2NoYXRzcGFjZScpLnRyaWdnZXIoJ3Nob3duJyk7XG4gICAgICAgIH07XG5cbiAgICAgICAgcmVzaXplVmlkZW9BcmVhKENoYXQuaXNWaXNpYmxlKCksIGNoYXRDb21wbGV0ZUZ1bmN0aW9uKTtcblxuICAgICAgICB0b2dnbGUoQ2hhdCxcbiAgICAgICAgICAgICcjY2hhdHNwYWNlJyxcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyBSZXF1ZXN0IHRoZSBmb2N1cyBpbiB0aGUgbmlja25hbWUgZmllbGQgb3IgdGhlIGNoYXQgaW5wdXQgZmllbGQuXG4gICAgICAgICAgICAgICAgaWYgKCQoJyNuaWNrbmFtZScpLmNzcygndmlzaWJpbGl0eScpID09PSAndmlzaWJsZScpIHtcbiAgICAgICAgICAgICAgICAgICAgJCgnI25pY2tpbnB1dCcpLmZvY3VzKCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgJCgnI3VzZXJtc2cnKS5mb2N1cygpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgQ2hhdC5yZXNpemVDaGF0LFxuICAgICAgICAgICAgbnVsbCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIE9wZW5zIC8gY2xvc2VzIHRoZSBjb250YWN0IGxpc3QgYXJlYS5cbiAgICAgKi9cbiAgICBteS50b2dnbGVDb250YWN0TGlzdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGNvbXBsZXRlRnVuY3Rpb24gPSBDb250YWN0TGlzdC5pc1Zpc2libGUoKSA/XG4gICAgICAgICAgICBmdW5jdGlvbigpIHt9IDogZnVuY3Rpb24gKCkgeyAkKCcjY29udGFjdGxpc3QnKS50cmlnZ2VyKCdzaG93bicpO307XG4gICAgICAgIHJlc2l6ZVZpZGVvQXJlYShDb250YWN0TGlzdC5pc1Zpc2libGUoKSwgY29tcGxldGVGdW5jdGlvbik7XG5cbiAgICAgICAgdG9nZ2xlKENvbnRhY3RMaXN0LFxuICAgICAgICAgICAgJyNjb250YWN0bGlzdCcsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgQ29udGFjdExpc3Quc2V0VmlzdWFsTm90aWZpY2F0aW9uKGZhbHNlKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBudWxsKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogT3BlbnMgLyBjbG9zZXMgdGhlIHNldHRpbmdzIG1lbnVcbiAgICAgKi9cbiAgICBteS50b2dnbGVTZXR0aW5nc01lbnUgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgcmVzaXplVmlkZW9BcmVhKFNldHRpbmdzTWVudS5pc1Zpc2libGUoKSwgZnVuY3Rpb24gKCl7fSk7XG4gICAgICAgIHRvZ2dsZShTZXR0aW5nc01lbnUsXG4gICAgICAgICAgICAnI3NldHRpbmdzbWVudScsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNldHRpbmdzID0gU2V0dGluZ3MuZ2V0U2V0dGluZ3MoKTtcbiAgICAgICAgICAgICAgICAkKCcjc2V0RGlzcGxheU5hbWUnKS5nZXQoMCkudmFsdWUgPSBzZXR0aW5ncy5kaXNwbGF5TmFtZTtcbiAgICAgICAgICAgICAgICAkKCcjc2V0RW1haWwnKS5nZXQoMCkudmFsdWUgPSBzZXR0aW5ncy5lbWFpbDtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBudWxsKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgc2l6ZSBvZiB0aGUgc2lkZSBwYW5lbC5cbiAgICAgKi9cbiAgICBteS5nZXRQYW5lbFNpemUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBhdmFpbGFibGVIZWlnaHQgPSB3aW5kb3cuaW5uZXJIZWlnaHQ7XG4gICAgICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IHdpbmRvdy5pbm5lcldpZHRoO1xuXG4gICAgICAgIHZhciBwYW5lbFdpZHRoID0gMjAwO1xuICAgICAgICBpZiAoYXZhaWxhYmxlV2lkdGggKiAwLjIgPCAyMDApIHtcbiAgICAgICAgICAgIHBhbmVsV2lkdGggPSBhdmFpbGFibGVXaWR0aCAqIDAuMjtcbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBbcGFuZWxXaWR0aCwgYXZhaWxhYmxlSGVpZ2h0XTtcbiAgICB9O1xuXG4gICAgbXkuaXNWaXNpYmxlID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHJldHVybiAoQ2hhdC5pc1Zpc2libGUoKSB8fCBDb250YWN0TGlzdC5pc1Zpc2libGUoKSB8fCBTZXR0aW5nc01lbnUuaXNWaXNpYmxlKCkpO1xuICAgIH07XG5cbiAgICByZXR1cm4gbXk7XG5cbn0oUGFuZWxUb2dnbGVyIHx8IHt9KSk7XG5cbm1vZHVsZS5leHBvcnRzID0gUGFuZWxUb2dnbGVyOyIsIi8qIGdsb2JhbCAkLCBVdGlsLCBuaWNrbmFtZTp0cnVlICovXG52YXIgUmVwbGFjZW1lbnQgPSByZXF1aXJlKFwiLi9SZXBsYWNlbWVudFwiKTtcbnZhciBDb21tYW5kc1Byb2Nlc3NvciA9IHJlcXVpcmUoXCIuL0NvbW1hbmRzXCIpO1xudmFyIFRvb2xiYXJUb2dnbGVyID0gcmVxdWlyZShcIi4uLy4uL3Rvb2xiYXJzL1Rvb2xiYXJUb2dnbGVyXCIpO1xudmFyIHNtaWxleXMgPSByZXF1aXJlKFwiLi9zbWlsZXlzLmpzb25cIikuc21pbGV5cztcbnZhciBOaWNrbmFtZUhhbmRsZXIgPSByZXF1aXJlKFwiLi4vLi4vdXRpbC9OaWNrbmFtZUhhbmRsZXJcIik7XG52YXIgVUlVdGlsID0gcmVxdWlyZShcIi4uLy4uL3V0aWwvVUlVdGlsXCIpO1xudmFyIFVJRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uLy4uLy4uL3NlcnZpY2UvVUkvVUlFdmVudHNcIik7XG5cbnZhciBub3RpZmljYXRpb25JbnRlcnZhbCA9IGZhbHNlO1xudmFyIHVucmVhZE1lc3NhZ2VzID0gMDtcblxuXG4vKipcbiAqIFNob3dzL2hpZGVzIGEgdmlzdWFsIG5vdGlmaWNhdGlvbiwgaW5kaWNhdGluZyB0aGF0IGEgbWVzc2FnZSBoYXMgYXJyaXZlZC5cbiAqL1xuZnVuY3Rpb24gc2V0VmlzdWFsTm90aWZpY2F0aW9uKHNob3cpIHtcbiAgICB2YXIgdW5yZWFkTXNnRWxlbWVudCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCd1bnJlYWRNZXNzYWdlcycpO1xuICAgIHZhciB1bnJlYWRNc2dCb3R0b21FbGVtZW50XG4gICAgICAgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2JvdHRvbVVucmVhZE1lc3NhZ2VzJyk7XG5cbiAgICB2YXIgZ2xvd2VyID0gJCgnI2NoYXRCdXR0b24nKTtcbiAgICB2YXIgYm90dG9tR2xvd2VyID0gJCgnI2NoYXRCb3R0b21CdXR0b24nKTtcblxuICAgIGlmICh1bnJlYWRNZXNzYWdlcykge1xuICAgICAgICB1bnJlYWRNc2dFbGVtZW50LmlubmVySFRNTCA9IHVucmVhZE1lc3NhZ2VzLnRvU3RyaW5nKCk7XG4gICAgICAgIHVucmVhZE1zZ0JvdHRvbUVsZW1lbnQuaW5uZXJIVE1MID0gdW5yZWFkTWVzc2FnZXMudG9TdHJpbmcoKTtcblxuICAgICAgICBUb29sYmFyVG9nZ2xlci5kb2NrVG9vbGJhcih0cnVlKTtcblxuICAgICAgICB2YXIgY2hhdEJ1dHRvbkVsZW1lbnRcbiAgICAgICAgICAgID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2NoYXRCdXR0b24nKS5wYXJlbnROb2RlO1xuICAgICAgICB2YXIgbGVmdEluZGVudCA9IChVSVV0aWwuZ2V0VGV4dFdpZHRoKGNoYXRCdXR0b25FbGVtZW50KSAtXG4gICAgICAgICAgICBVSVV0aWwuZ2V0VGV4dFdpZHRoKHVucmVhZE1zZ0VsZW1lbnQpKSAvIDI7XG4gICAgICAgIHZhciB0b3BJbmRlbnQgPSAoVUlVdGlsLmdldFRleHRIZWlnaHQoY2hhdEJ1dHRvbkVsZW1lbnQpIC1cbiAgICAgICAgICAgIFVJVXRpbC5nZXRUZXh0SGVpZ2h0KHVucmVhZE1zZ0VsZW1lbnQpKSAvIDIgLSAzO1xuXG4gICAgICAgIHVucmVhZE1zZ0VsZW1lbnQuc2V0QXR0cmlidXRlKFxuICAgICAgICAgICAgJ3N0eWxlJyxcbiAgICAgICAgICAgICAgICAndG9wOicgKyB0b3BJbmRlbnQgK1xuICAgICAgICAgICAgICAgICc7IGxlZnQ6JyArIGxlZnRJbmRlbnQgKyAnOycpO1xuXG4gICAgICAgIHZhciBjaGF0Qm90dG9tQnV0dG9uRWxlbWVudFxuICAgICAgICAgICAgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnY2hhdEJvdHRvbUJ1dHRvbicpLnBhcmVudE5vZGU7XG4gICAgICAgIHZhciBib3R0b21MZWZ0SW5kZW50ID0gKFVJVXRpbC5nZXRUZXh0V2lkdGgoY2hhdEJvdHRvbUJ1dHRvbkVsZW1lbnQpIC1cbiAgICAgICAgICAgIFVJVXRpbC5nZXRUZXh0V2lkdGgodW5yZWFkTXNnQm90dG9tRWxlbWVudCkpIC8gMjtcbiAgICAgICAgdmFyIGJvdHRvbVRvcEluZGVudCA9IChVSVV0aWwuZ2V0VGV4dEhlaWdodChjaGF0Qm90dG9tQnV0dG9uRWxlbWVudCkgLVxuICAgICAgICAgICAgVUlVdGlsLmdldFRleHRIZWlnaHQodW5yZWFkTXNnQm90dG9tRWxlbWVudCkpIC8gMiAtIDI7XG5cbiAgICAgICAgdW5yZWFkTXNnQm90dG9tRWxlbWVudC5zZXRBdHRyaWJ1dGUoXG4gICAgICAgICAgICAnc3R5bGUnLFxuICAgICAgICAgICAgICAgICd0b3A6JyArIGJvdHRvbVRvcEluZGVudCArXG4gICAgICAgICAgICAgICAgJzsgbGVmdDonICsgYm90dG9tTGVmdEluZGVudCArICc7Jyk7XG5cblxuICAgICAgICBpZiAoIWdsb3dlci5oYXNDbGFzcygnaWNvbi1jaGF0LXNpbXBsZScpKSB7XG4gICAgICAgICAgICBnbG93ZXIucmVtb3ZlQ2xhc3MoJ2ljb24tY2hhdCcpO1xuICAgICAgICAgICAgZ2xvd2VyLmFkZENsYXNzKCdpY29uLWNoYXQtc2ltcGxlJyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIHVucmVhZE1zZ0VsZW1lbnQuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIHVucmVhZE1zZ0JvdHRvbUVsZW1lbnQuaW5uZXJIVE1MID0gJyc7XG4gICAgICAgIGdsb3dlci5yZW1vdmVDbGFzcygnaWNvbi1jaGF0LXNpbXBsZScpO1xuICAgICAgICBnbG93ZXIuYWRkQ2xhc3MoJ2ljb24tY2hhdCcpO1xuICAgIH1cblxuICAgIGlmIChzaG93ICYmICFub3RpZmljYXRpb25JbnRlcnZhbCkge1xuICAgICAgICBub3RpZmljYXRpb25JbnRlcnZhbCA9IHdpbmRvdy5zZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBnbG93ZXIudG9nZ2xlQ2xhc3MoJ2FjdGl2ZScpO1xuICAgICAgICAgICAgYm90dG9tR2xvd2VyLnRvZ2dsZUNsYXNzKCdhY3RpdmUgZ2xvd2luZycpO1xuICAgICAgICB9LCA4MDApO1xuICAgIH1cbiAgICBlbHNlIGlmICghc2hvdyAmJiBub3RpZmljYXRpb25JbnRlcnZhbCkge1xuICAgICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbChub3RpZmljYXRpb25JbnRlcnZhbCk7XG4gICAgICAgIG5vdGlmaWNhdGlvbkludGVydmFsID0gZmFsc2U7XG4gICAgICAgIGdsb3dlci5yZW1vdmVDbGFzcygnYWN0aXZlJyk7XG4gICAgICAgIGJvdHRvbUdsb3dlci5yZW1vdmVDbGFzcygnZ2xvd2luZycpO1xuICAgICAgICBib3R0b21HbG93ZXIuYWRkQ2xhc3MoJ2FjdGl2ZScpO1xuICAgIH1cbn1cblxuXG4vKipcbiAqIFJldHVybnMgdGhlIGN1cnJlbnQgdGltZSBpbiB0aGUgZm9ybWF0IGl0IGlzIHNob3duIHRvIHRoZSB1c2VyXG4gKiBAcmV0dXJucyB7c3RyaW5nfVxuICovXG5mdW5jdGlvbiBnZXRDdXJyZW50VGltZSgpIHtcbiAgICB2YXIgbm93ICAgICA9IG5ldyBEYXRlKCk7XG4gICAgdmFyIGhvdXIgICAgPSBub3cuZ2V0SG91cnMoKTtcbiAgICB2YXIgbWludXRlICA9IG5vdy5nZXRNaW51dGVzKCk7XG4gICAgdmFyIHNlY29uZCAgPSBub3cuZ2V0U2Vjb25kcygpO1xuICAgIGlmKGhvdXIudG9TdHJpbmcoKS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgaG91ciA9ICcwJytob3VyO1xuICAgIH1cbiAgICBpZihtaW51dGUudG9TdHJpbmcoKS5sZW5ndGggPT09IDEpIHtcbiAgICAgICAgbWludXRlID0gJzAnK21pbnV0ZTtcbiAgICB9XG4gICAgaWYoc2Vjb25kLnRvU3RyaW5nKCkubGVuZ3RoID09PSAxKSB7XG4gICAgICAgIHNlY29uZCA9ICcwJytzZWNvbmQ7XG4gICAgfVxuICAgIHJldHVybiBob3VyKyc6JyttaW51dGUrJzonK3NlY29uZDtcbn1cblxuZnVuY3Rpb24gdG9nZ2xlU21pbGV5cygpXG57XG4gICAgdmFyIHNtaWxleXMgPSAkKCcjc21pbGV5c0NvbnRhaW5lcicpO1xuICAgIGlmKCFzbWlsZXlzLmlzKCc6dmlzaWJsZScpKSB7XG4gICAgICAgIHNtaWxleXMuc2hvdyhcInNsaWRlXCIsIHsgZGlyZWN0aW9uOiBcImRvd25cIiwgZHVyYXRpb246IDMwMH0pO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHNtaWxleXMuaGlkZShcInNsaWRlXCIsIHsgZGlyZWN0aW9uOiBcImRvd25cIiwgZHVyYXRpb246IDMwMH0pO1xuICAgIH1cbiAgICAkKCcjdXNlcm1zZycpLmZvY3VzKCk7XG59XG5cbmZ1bmN0aW9uIGFkZENsaWNrRnVuY3Rpb24oc21pbGV5LCBudW1iZXIpIHtcbiAgICBzbWlsZXkub25jbGljayA9IGZ1bmN0aW9uIGFkZFNtaWxleVRvTWVzc2FnZSgpIHtcbiAgICAgICAgdmFyIHVzZXJtc2cgPSAkKCcjdXNlcm1zZycpO1xuICAgICAgICB2YXIgbWVzc2FnZSA9IHVzZXJtc2cudmFsKCk7XG4gICAgICAgIG1lc3NhZ2UgKz0gc21pbGV5c1snc21pbGV5JyArIG51bWJlcl07XG4gICAgICAgIHVzZXJtc2cudmFsKG1lc3NhZ2UpO1xuICAgICAgICB1c2VybXNnLmdldCgwKS5zZXRTZWxlY3Rpb25SYW5nZShtZXNzYWdlLmxlbmd0aCwgbWVzc2FnZS5sZW5ndGgpO1xuICAgICAgICB0b2dnbGVTbWlsZXlzKCk7XG4gICAgICAgIHVzZXJtc2cuZm9jdXMoKTtcbiAgICB9O1xufVxuXG4vKipcbiAqIEFkZHMgdGhlIHNtaWxleXMgY29udGFpbmVyIHRvIHRoZSBjaGF0XG4gKi9cbmZ1bmN0aW9uIGFkZFNtaWxleXMoKSB7XG4gICAgdmFyIHNtaWxleXNDb250YWluZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdkaXYnKTtcbiAgICBzbWlsZXlzQ29udGFpbmVyLmlkID0gJ3NtaWxleXNDb250YWluZXInO1xuICAgIGZvcih2YXIgaSA9IDE7IGkgPD0gMjE7IGkrKykge1xuICAgICAgICB2YXIgc21pbGV5Q29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnZGl2Jyk7XG4gICAgICAgIHNtaWxleUNvbnRhaW5lci5pZCA9ICdzbWlsZXknICsgaTtcbiAgICAgICAgc21pbGV5Q29udGFpbmVyLmNsYXNzTmFtZSA9ICdzbWlsZXlDb250YWluZXInO1xuICAgICAgICB2YXIgc21pbGV5ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW1nJyk7XG4gICAgICAgIHNtaWxleS5zcmMgPSAnaW1hZ2VzL3NtaWxleXMvc21pbGV5JyArIGkgKyAnLnN2Zyc7XG4gICAgICAgIHNtaWxleS5jbGFzc05hbWUgPSAgJ3NtaWxleSc7XG4gICAgICAgIGFkZENsaWNrRnVuY3Rpb24oc21pbGV5LCBpKTtcbiAgICAgICAgc21pbGV5Q29udGFpbmVyLmFwcGVuZENoaWxkKHNtaWxleSk7XG4gICAgICAgIHNtaWxleXNDb250YWluZXIuYXBwZW5kQ2hpbGQoc21pbGV5Q29udGFpbmVyKTtcbiAgICB9XG5cbiAgICAkKFwiI2NoYXRzcGFjZVwiKS5hcHBlbmQoc21pbGV5c0NvbnRhaW5lcik7XG59XG5cbi8qKlxuICogUmVzaXplcyB0aGUgY2hhdCBjb252ZXJzYXRpb24uXG4gKi9cbmZ1bmN0aW9uIHJlc2l6ZUNoYXRDb252ZXJzYXRpb24oKSB7XG4gICAgdmFyIG1zZ2FyZWFIZWlnaHQgPSAkKCcjdXNlcm1zZycpLm91dGVySGVpZ2h0KCk7XG4gICAgdmFyIGNoYXRzcGFjZSA9ICQoJyNjaGF0c3BhY2UnKTtcbiAgICB2YXIgd2lkdGggPSBjaGF0c3BhY2Uud2lkdGgoKTtcbiAgICB2YXIgY2hhdCA9ICQoJyNjaGF0Y29udmVyc2F0aW9uJyk7XG4gICAgdmFyIHNtaWxleXMgPSAkKCcjc21pbGV5c2FyZWEnKTtcblxuICAgIHNtaWxleXMuaGVpZ2h0KG1zZ2FyZWFIZWlnaHQpO1xuICAgICQoXCIjc21pbGV5c1wiKS5jc3MoJ2JvdHRvbScsIChtc2dhcmVhSGVpZ2h0IC0gMjYpIC8gMik7XG4gICAgJCgnI3NtaWxleXNDb250YWluZXInKS5jc3MoJ2JvdHRvbScsIG1zZ2FyZWFIZWlnaHQpO1xuICAgIGNoYXQud2lkdGgod2lkdGggLSAxMCk7XG4gICAgY2hhdC5oZWlnaHQod2luZG93LmlubmVySGVpZ2h0IC0gMTUgLSBtc2dhcmVhSGVpZ2h0KTtcbn1cblxuLyoqXG4gKiBDaGF0IHJlbGF0ZWQgdXNlciBpbnRlcmZhY2UuXG4gKi9cbnZhciBDaGF0ID0gKGZ1bmN0aW9uIChteSkge1xuICAgIC8qKlxuICAgICAqIEluaXRpYWxpemVzIGNoYXQgcmVsYXRlZCBpbnRlcmZhY2UuXG4gICAgICovXG4gICAgbXkuaW5pdCA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYoTmlja25hbWVIYW5kbGVyLmdldE5pY2tuYW1lKCkpXG4gICAgICAgICAgICBDaGF0LnNldENoYXRDb252ZXJzYXRpb25Nb2RlKHRydWUpO1xuICAgICAgICBOaWNrbmFtZUhhbmRsZXIuYWRkTGlzdGVuZXIoVUlFdmVudHMuTklDS05BTUVfQ0hBTkdFRCxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChuaWNrbmFtZSkge1xuICAgICAgICAgICAgICAgIENoYXQuc2V0Q2hhdENvbnZlcnNhdGlvbk1vZGUodHJ1ZSk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAkKCcjbmlja2lucHV0Jykua2V5ZG93bihmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmIChldmVudC5rZXlDb2RlID09PSAxMykge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgdmFyIHZhbCA9IFVJVXRpbC5lc2NhcGVIdG1sKHRoaXMudmFsdWUpO1xuICAgICAgICAgICAgICAgIHRoaXMudmFsdWUgPSAnJztcbiAgICAgICAgICAgICAgICBpZiAoIU5pY2tuYW1lSGFuZGxlci5nZXROaWNrbmFtZSgpKSB7XG4gICAgICAgICAgICAgICAgICAgIE5pY2tuYW1lSGFuZGxlci5zZXROaWNrbmFtZSh2YWwpO1xuXG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgICQoJyN1c2VybXNnJykua2V5ZG93bihmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIGlmIChldmVudC5rZXlDb2RlID09PSAxMykge1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgdmFyIHZhbHVlID0gdGhpcy52YWx1ZTtcbiAgICAgICAgICAgICAgICAkKCcjdXNlcm1zZycpLnZhbCgnJykudHJpZ2dlcignYXV0b3NpemUucmVzaXplJyk7XG4gICAgICAgICAgICAgICAgdGhpcy5mb2N1cygpO1xuICAgICAgICAgICAgICAgIHZhciBjb21tYW5kID0gbmV3IENvbW1hbmRzUHJvY2Vzc29yKHZhbHVlKTtcbiAgICAgICAgICAgICAgICBpZihjb21tYW5kLmlzQ29tbWFuZCgpKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgY29tbWFuZC5wcm9jZXNzQ29tbWFuZCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB2YXIgbWVzc2FnZSA9IFVJVXRpbC5lc2NhcGVIdG1sKHZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgQVBQLnhtcHAuc2VuZENoYXRNZXNzYWdlKG1lc3NhZ2UsIE5pY2tuYW1lSGFuZGxlci5nZXROaWNrbmFtZSgpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHZhciBvblRleHRBcmVhUmVzaXplID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmVzaXplQ2hhdENvbnZlcnNhdGlvbigpO1xuICAgICAgICAgICAgQ2hhdC5zY3JvbGxDaGF0VG9Cb3R0b20oKTtcbiAgICAgICAgfTtcbiAgICAgICAgJCgnI3VzZXJtc2cnKS5hdXRvc2l6ZSh7Y2FsbGJhY2s6IG9uVGV4dEFyZWFSZXNpemV9KTtcblxuICAgICAgICAkKFwiI2NoYXRzcGFjZVwiKS5iaW5kKFwic2hvd25cIixcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB1bnJlYWRNZXNzYWdlcyA9IDA7XG4gICAgICAgICAgICAgICAgc2V0VmlzdWFsTm90aWZpY2F0aW9uKGZhbHNlKTtcbiAgICAgICAgICAgIH0pO1xuXG4gICAgICAgIGFkZFNtaWxleXMoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQXBwZW5kcyB0aGUgZ2l2ZW4gbWVzc2FnZSB0byB0aGUgY2hhdCBjb252ZXJzYXRpb24uXG4gICAgICovXG4gICAgbXkudXBkYXRlQ2hhdENvbnZlcnNhdGlvbiA9IGZ1bmN0aW9uIChmcm9tLCBkaXNwbGF5TmFtZSwgbWVzc2FnZSkge1xuICAgICAgICB2YXIgZGl2Q2xhc3NOYW1lID0gJyc7XG5cbiAgICAgICAgaWYgKEFQUC54bXBwLm15SmlkKCkgPT09IGZyb20pIHtcbiAgICAgICAgICAgIGRpdkNsYXNzTmFtZSA9IFwibG9jYWx1c2VyXCI7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBkaXZDbGFzc05hbWUgPSBcInJlbW90ZXVzZXJcIjtcblxuICAgICAgICAgICAgaWYgKCFDaGF0LmlzVmlzaWJsZSgpKSB7XG4gICAgICAgICAgICAgICAgdW5yZWFkTWVzc2FnZXMrKztcbiAgICAgICAgICAgICAgICBVSVV0aWwucGxheVNvdW5kTm90aWZpY2F0aW9uKCdjaGF0Tm90aWZpY2F0aW9uJyk7XG4gICAgICAgICAgICAgICAgc2V0VmlzdWFsTm90aWZpY2F0aW9uKHRydWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gcmVwbGFjZSBsaW5rcyBhbmQgc21pbGV5c1xuICAgICAgICAvLyBTdHJvcGhlIGFscmVhZHkgZXNjYXBlcyBzcGVjaWFsIHN5bWJvbHMgb24gc2VuZGluZyxcbiAgICAgICAgLy8gc28gd2UgZXNjYXBlIGhlcmUgb25seSB0YWdzIHRvIGF2b2lkIGRvdWJsZSAmYW1wO1xuICAgICAgICB2YXIgZXNjTWVzc2FnZSA9IG1lc3NhZ2UucmVwbGFjZSgvPC9nLCAnJmx0OycpLlxuICAgICAgICAgICAgcmVwbGFjZSgvPi9nLCAnJmd0OycpLnJlcGxhY2UoL1xcbi9nLCAnPGJyLz4nKTtcbiAgICAgICAgdmFyIGVzY0Rpc3BsYXlOYW1lID0gVUlVdGlsLmVzY2FwZUh0bWwoZGlzcGxheU5hbWUpO1xuICAgICAgICBtZXNzYWdlID0gUmVwbGFjZW1lbnQucHJvY2Vzc1JlcGxhY2VtZW50cyhlc2NNZXNzYWdlKTtcblxuICAgICAgICB2YXIgbWVzc2FnZUNvbnRhaW5lciA9XG4gICAgICAgICAgICAnPGRpdiBjbGFzcz1cImNoYXRtZXNzYWdlXCI+JytcbiAgICAgICAgICAgICAgICAnPGltZyBzcmM9XCIuLi9pbWFnZXMvY2hhdEFycm93LnN2Z1wiIGNsYXNzPVwiY2hhdEFycm93XCI+JyArXG4gICAgICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJ1c2VybmFtZSAnICsgZGl2Q2xhc3NOYW1lICsnXCI+JyArIGVzY0Rpc3BsYXlOYW1lICtcbiAgICAgICAgICAgICAgICAnPC9kaXY+JyArICc8ZGl2IGNsYXNzPVwidGltZXN0YW1wXCI+JyArIGdldEN1cnJlbnRUaW1lKCkgK1xuICAgICAgICAgICAgICAgICc8L2Rpdj4nICsgJzxkaXYgY2xhc3M9XCJ1c2VybWVzc2FnZVwiPicgKyBtZXNzYWdlICsgJzwvZGl2PicgK1xuICAgICAgICAgICAgJzwvZGl2Pic7XG5cbiAgICAgICAgJCgnI2NoYXRjb252ZXJzYXRpb24nKS5hcHBlbmQobWVzc2FnZUNvbnRhaW5lcik7XG4gICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuYW5pbWF0ZShcbiAgICAgICAgICAgICAgICB7IHNjcm9sbFRvcDogJCgnI2NoYXRjb252ZXJzYXRpb24nKVswXS5zY3JvbGxIZWlnaHR9LCAxMDAwKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQXBwZW5kcyBlcnJvciBtZXNzYWdlIHRvIHRoZSBjb252ZXJzYXRpb25cbiAgICAgKiBAcGFyYW0gZXJyb3JNZXNzYWdlIHRoZSByZWNlaXZlZCBlcnJvciBtZXNzYWdlLlxuICAgICAqIEBwYXJhbSBvcmlnaW5hbFRleHQgdGhlIG9yaWdpbmFsIG1lc3NhZ2UuXG4gICAgICovXG4gICAgbXkuY2hhdEFkZEVycm9yID0gZnVuY3Rpb24oZXJyb3JNZXNzYWdlLCBvcmlnaW5hbFRleHQpXG4gICAge1xuICAgICAgICBlcnJvck1lc3NhZ2UgPSBVSVV0aWwuZXNjYXBlSHRtbChlcnJvck1lc3NhZ2UpO1xuICAgICAgICBvcmlnaW5hbFRleHQgPSBVSVV0aWwuZXNjYXBlSHRtbChvcmlnaW5hbFRleHQpO1xuXG4gICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuYXBwZW5kKFxuICAgICAgICAgICAgJzxkaXYgY2xhc3M9XCJlcnJvck1lc3NhZ2VcIj48Yj5FcnJvcjogPC9iPicgKyAnWW91ciBtZXNzYWdlJyArXG4gICAgICAgICAgICAob3JpZ2luYWxUZXh0PyAoJyBcXFwiJysgb3JpZ2luYWxUZXh0ICsgJ1xcXCInKSA6IFwiXCIpICtcbiAgICAgICAgICAgICcgd2FzIG5vdCBzZW50LicgK1xuICAgICAgICAgICAgKGVycm9yTWVzc2FnZT8gKCcgUmVhc29uOiAnICsgZXJyb3JNZXNzYWdlKSA6ICcnKSArICAnPC9kaXY+Jyk7XG4gICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuYW5pbWF0ZShcbiAgICAgICAgICAgIHsgc2Nyb2xsVG9wOiAkKCcjY2hhdGNvbnZlcnNhdGlvbicpWzBdLnNjcm9sbEhlaWdodH0sIDEwMDApO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBzdWJqZWN0IHRvIHRoZSBVSVxuICAgICAqIEBwYXJhbSBzdWJqZWN0IHRoZSBzdWJqZWN0XG4gICAgICovXG4gICAgbXkuY2hhdFNldFN1YmplY3QgPSBmdW5jdGlvbihzdWJqZWN0KVxuICAgIHtcbiAgICAgICAgaWYoc3ViamVjdClcbiAgICAgICAgICAgIHN1YmplY3QgPSBzdWJqZWN0LnRyaW0oKTtcbiAgICAgICAgJCgnI3N1YmplY3QnKS5odG1sKFJlcGxhY2VtZW50LmxpbmtpZnkoVUlVdGlsLmVzY2FwZUh0bWwoc3ViamVjdCkpKTtcbiAgICAgICAgaWYoc3ViamVjdCA9PT0gXCJcIilcbiAgICAgICAge1xuICAgICAgICAgICAgJChcIiNzdWJqZWN0XCIpLmNzcyh7ZGlzcGxheTogXCJub25lXCJ9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgICQoXCIjc3ViamVjdFwiKS5jc3Moe2Rpc3BsYXk6IFwiYmxvY2tcIn0pO1xuICAgICAgICB9XG4gICAgfTtcblxuXG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHRoZSBjaGF0IGNvbnZlcnNhdGlvbiBtb2RlLlxuICAgICAqL1xuICAgIG15LnNldENoYXRDb252ZXJzYXRpb25Nb2RlID0gZnVuY3Rpb24gKGlzQ29udmVyc2F0aW9uTW9kZSkge1xuICAgICAgICBpZiAoaXNDb252ZXJzYXRpb25Nb2RlKSB7XG4gICAgICAgICAgICAkKCcjbmlja25hbWUnKS5jc3Moe3Zpc2liaWxpdHk6ICdoaWRkZW4nfSk7XG4gICAgICAgICAgICAkKCcjY2hhdGNvbnZlcnNhdGlvbicpLmNzcyh7dmlzaWJpbGl0eTogJ3Zpc2libGUnfSk7XG4gICAgICAgICAgICAkKCcjdXNlcm1zZycpLmNzcyh7dmlzaWJpbGl0eTogJ3Zpc2libGUnfSk7XG4gICAgICAgICAgICAkKCcjc21pbGV5c2FyZWEnKS5jc3Moe3Zpc2liaWxpdHk6ICd2aXNpYmxlJ30pO1xuICAgICAgICAgICAgJCgnI3VzZXJtc2cnKS5mb2N1cygpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgdGhlIGNoYXQgYXJlYS5cbiAgICAgKi9cbiAgICBteS5yZXNpemVDaGF0ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgY2hhdFNpemUgPSByZXF1aXJlKFwiLi4vU2lkZVBhbmVsVG9nZ2xlclwiKS5nZXRQYW5lbFNpemUoKTtcblxuICAgICAgICAkKCcjY2hhdHNwYWNlJykud2lkdGgoY2hhdFNpemVbMF0pO1xuICAgICAgICAkKCcjY2hhdHNwYWNlJykuaGVpZ2h0KGNoYXRTaXplWzFdKTtcblxuICAgICAgICByZXNpemVDaGF0Q29udmVyc2F0aW9uKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEluZGljYXRlcyBpZiB0aGUgY2hhdCBpcyBjdXJyZW50bHkgdmlzaWJsZS5cbiAgICAgKi9cbiAgICBteS5pc1Zpc2libGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAkKCcjY2hhdHNwYWNlJykuaXMoXCI6dmlzaWJsZVwiKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFNob3dzIGFuZCBoaWRlcyB0aGUgd2luZG93IHdpdGggdGhlIHNtaWxleXNcbiAgICAgKi9cbiAgICBteS50b2dnbGVTbWlsZXlzID0gdG9nZ2xlU21pbGV5cztcblxuICAgIC8qKlxuICAgICAqIFNjcm9sbHMgY2hhdCB0byB0aGUgYm90dG9tLlxuICAgICAqL1xuICAgIG15LnNjcm9sbENoYXRUb0JvdHRvbSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJykuc2Nyb2xsVG9wKFxuICAgICAgICAgICAgICAgICQoJyNjaGF0Y29udmVyc2F0aW9uJylbMF0uc2Nyb2xsSGVpZ2h0KTtcbiAgICAgICAgfSwgNSk7XG4gICAgfTtcblxuXG4gICAgcmV0dXJuIG15O1xufShDaGF0IHx8IHt9KSk7XG5tb2R1bGUuZXhwb3J0cyA9IENoYXQ7IiwidmFyIFVJVXRpbCA9IHJlcXVpcmUoXCIuLi8uLi91dGlsL1VJVXRpbFwiKTtcblxuLyoqXG4gKiBMaXN0IHdpdGggc3VwcG9ydGVkIGNvbW1hbmRzLiBUaGUga2V5cyBhcmUgdGhlIG5hbWVzIG9mIHRoZSBjb21tYW5kcyBhbmRcbiAqIHRoZSB2YWx1ZSBpcyB0aGUgZnVuY3Rpb24gdGhhdCBwcm9jZXNzZXMgdGhlIG1lc3NhZ2UuXG4gKiBAdHlwZSB7e1N0cmluZzogZnVuY3Rpb259fVxuICovXG52YXIgY29tbWFuZHMgPSB7XG4gICAgXCJ0b3BpY1wiIDogcHJvY2Vzc1RvcGljXG59O1xuXG4vKipcbiAqIEV4dHJhY3RzIHRoZSBjb21tYW5kIGZyb20gdGhlIG1lc3NhZ2UuXG4gKiBAcGFyYW0gbWVzc2FnZSB0aGUgcmVjZWl2ZWQgbWVzc2FnZVxuICogQHJldHVybnMge3N0cmluZ30gdGhlIGNvbW1hbmRcbiAqL1xuZnVuY3Rpb24gZ2V0Q29tbWFuZChtZXNzYWdlKVxue1xuICAgIGlmKG1lc3NhZ2UpXG4gICAge1xuICAgICAgICBmb3IodmFyIGNvbW1hbmQgaW4gY29tbWFuZHMpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGlmKG1lc3NhZ2UuaW5kZXhPZihcIi9cIiArIGNvbW1hbmQpID09IDApXG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbW1hbmQ7XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIFwiXCI7XG59O1xuXG4vKipcbiAqIFByb2Nlc3NlcyB0aGUgZGF0YSBmb3IgdG9waWMgY29tbWFuZC5cbiAqIEBwYXJhbSBjb21tYW5kQXJndW1lbnRzIHRoZSBhcmd1bWVudHMgb2YgdGhlIHRvcGljIGNvbW1hbmQuXG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3NUb3BpYyhjb21tYW5kQXJndW1lbnRzKVxue1xuICAgIHZhciB0b3BpYyA9IFVJVXRpbC5lc2NhcGVIdG1sKGNvbW1hbmRBcmd1bWVudHMpO1xuICAgIEFQUC54bXBwLnNldFN1YmplY3QodG9waWMpO1xufVxuXG4vKipcbiAqIENvbnN0cnVjdHMgbmV3IENvbW1hbmRQcm9jY2Vzc29yIGluc3RhbmNlIGZyb20gYSBtZXNzYWdlIHRoYXRcbiAqIGhhbmRsZXMgY29tbWFuZHMgcmVjZWl2ZWQgdmlhIGNoYXQgbWVzc2FnZXMuXG4gKiBAcGFyYW0gbWVzc2FnZSB0aGUgbWVzc2FnZVxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIENvbW1hbmRzUHJvY2Vzc29yKG1lc3NhZ2UpXG57XG5cblxuICAgIHZhciBjb21tYW5kID0gZ2V0Q29tbWFuZChtZXNzYWdlKTtcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIG5hbWUgb2YgdGhlIGNvbW1hbmQuXG4gICAgICogQHJldHVybnMge1N0cmluZ30gdGhlIGNvbW1hbmRcbiAgICAgKi9cbiAgICB0aGlzLmdldENvbW1hbmQgPSBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICByZXR1cm4gY29tbWFuZDtcbiAgICB9O1xuXG5cbiAgICB2YXIgbWVzc2FnZUFyZ3VtZW50ID0gbWVzc2FnZS5zdWJzdHIoY29tbWFuZC5sZW5ndGggKyAyKTtcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGFyZ3VtZW50cyBvZiB0aGUgY29tbWFuZC5cbiAgICAgKiBAcmV0dXJucyB7c3RyaW5nfVxuICAgICAqL1xuICAgIHRoaXMuZ2V0QXJndW1lbnQgPSBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICByZXR1cm4gbWVzc2FnZUFyZ3VtZW50O1xuICAgIH07XG59XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgdGhpcyBpbnN0YW5jZSBpcyB2YWxpZCBjb21tYW5kIG9yIG5vdC5cbiAqIEByZXR1cm5zIHtib29sZWFufVxuICovXG5Db21tYW5kc1Byb2Nlc3Nvci5wcm90b3R5cGUuaXNDb21tYW5kID0gZnVuY3Rpb24oKVxue1xuICAgIGlmKHRoaXMuZ2V0Q29tbWFuZCgpKVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICByZXR1cm4gZmFsc2U7XG59O1xuXG4vKipcbiAqIFByb2Nlc3NlcyB0aGUgY29tbWFuZC5cbiAqL1xuQ29tbWFuZHNQcm9jZXNzb3IucHJvdG90eXBlLnByb2Nlc3NDb21tYW5kID0gZnVuY3Rpb24oKVxue1xuICAgIGlmKCF0aGlzLmlzQ29tbWFuZCgpKVxuICAgICAgICByZXR1cm47XG5cbiAgICBjb21tYW5kc1t0aGlzLmdldENvbW1hbmQoKV0odGhpcy5nZXRBcmd1bWVudCgpKTtcblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDb21tYW5kc1Byb2Nlc3NvcjsiLCJ2YXIgU21pbGV5cyA9IHJlcXVpcmUoXCIuL3NtaWxleXMuanNvblwiKTtcbi8qKlxuICogUHJvY2Vzc2VzIGxpbmtzIGFuZCBzbWlsZXlzIGluIFwiYm9keVwiXG4gKi9cbmZ1bmN0aW9uIHByb2Nlc3NSZXBsYWNlbWVudHMoYm9keSlcbntcbiAgICAvL21ha2UgbGlua3MgY2xpY2thYmxlXG4gICAgYm9keSA9IGxpbmtpZnkoYm9keSk7XG5cbiAgICAvL2FkZCBzbWlsZXlzXG4gICAgYm9keSA9IHNtaWxpZnkoYm9keSk7XG5cbiAgICByZXR1cm4gYm9keTtcbn1cblxuLyoqXG4gKiBGaW5kcyBhbmQgcmVwbGFjZXMgYWxsIGxpbmtzIGluIHRoZSBsaW5rcyBpbiBcImJvZHlcIlxuICogd2l0aCB0aGVpciA8YSBocmVmPVwiXCI+PC9hPlxuICovXG5mdW5jdGlvbiBsaW5raWZ5KGlucHV0VGV4dClcbntcbiAgICB2YXIgcmVwbGFjZWRUZXh0LCByZXBsYWNlUGF0dGVybjEsIHJlcGxhY2VQYXR0ZXJuMiwgcmVwbGFjZVBhdHRlcm4zO1xuXG4gICAgLy9VUkxzIHN0YXJ0aW5nIHdpdGggaHR0cDovLywgaHR0cHM6Ly8sIG9yIGZ0cDovL1xuICAgIHJlcGxhY2VQYXR0ZXJuMSA9IC8oXFxiKGh0dHBzP3xmdHApOlxcL1xcL1stQS1aMC05KyZAI1xcLyU/PX5ffCE6LC47XSpbLUEtWjAtOSsmQCNcXC8lPX5ffF0pL2dpbTtcbiAgICByZXBsYWNlZFRleHQgPSBpbnB1dFRleHQucmVwbGFjZShyZXBsYWNlUGF0dGVybjEsICc8YSBocmVmPVwiJDFcIiB0YXJnZXQ9XCJfYmxhbmtcIj4kMTwvYT4nKTtcblxuICAgIC8vVVJMcyBzdGFydGluZyB3aXRoIFwid3d3LlwiICh3aXRob3V0IC8vIGJlZm9yZSBpdCwgb3IgaXQnZCByZS1saW5rIHRoZSBvbmVzIGRvbmUgYWJvdmUpLlxuICAgIHJlcGxhY2VQYXR0ZXJuMiA9IC8oXnxbXlxcL10pKHd3d1xcLltcXFNdKyhcXGJ8JCkpL2dpbTtcbiAgICByZXBsYWNlZFRleHQgPSByZXBsYWNlZFRleHQucmVwbGFjZShyZXBsYWNlUGF0dGVybjIsICckMTxhIGhyZWY9XCJodHRwOi8vJDJcIiB0YXJnZXQ9XCJfYmxhbmtcIj4kMjwvYT4nKTtcblxuICAgIC8vQ2hhbmdlIGVtYWlsIGFkZHJlc3NlcyB0byBtYWlsdG86OiBsaW5rcy5cbiAgICByZXBsYWNlUGF0dGVybjMgPSAvKChbYS16QS1aMC05XFwtXFxfXFwuXSkrQFthLXpBLVpcXF9dKz8oXFwuW2EtekEtWl17Miw2fSkrKS9naW07XG4gICAgcmVwbGFjZWRUZXh0ID0gcmVwbGFjZWRUZXh0LnJlcGxhY2UocmVwbGFjZVBhdHRlcm4zLCAnPGEgaHJlZj1cIm1haWx0bzokMVwiPiQxPC9hPicpO1xuXG4gICAgcmV0dXJuIHJlcGxhY2VkVGV4dDtcbn1cblxuLyoqXG4gKiBSZXBsYWNlcyBjb21tb24gc21pbGV5IHN0cmluZ3Mgd2l0aCBpbWFnZXNcbiAqL1xuZnVuY3Rpb24gc21pbGlmeShib2R5KVxue1xuICAgIGlmKCFib2R5KSB7XG4gICAgICAgIHJldHVybiBib2R5O1xuICAgIH1cblxuICAgIHZhciByZWdleHMgPSBTbWlsZXlzW1wicmVnZXhzXCJdO1xuICAgIGZvcih2YXIgc21pbGV5IGluIHJlZ2V4cykge1xuICAgICAgICBpZihyZWdleHMuaGFzT3duUHJvcGVydHkoc21pbGV5KSkge1xuICAgICAgICAgICAgYm9keSA9IGJvZHkucmVwbGFjZShyZWdleHNbc21pbGV5XSxcbiAgICAgICAgICAgICAgICAgICAgJzxpbWcgY2xhc3M9XCJzbWlsZXlcIiBzcmM9XCJpbWFnZXMvc21pbGV5cy8nICsgc21pbGV5ICsgJy5zdmdcIj4nKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiBib2R5O1xufVxuXG5tb2R1bGUuZXhwb3J0cyA9IHtcbiAgICBwcm9jZXNzUmVwbGFjZW1lbnRzOiBwcm9jZXNzUmVwbGFjZW1lbnRzLFxuICAgIGxpbmtpZnk6IGxpbmtpZnlcbn07XG4iLCJtb2R1bGUuZXhwb3J0cz17XG4gICAgXCJzbWlsZXlzXCI6IHtcbiAgICAgICAgXCJzbWlsZXkxXCI6IFwiOilcIixcbiAgICAgICAgXCJzbWlsZXkyXCI6IFwiOihcIixcbiAgICAgICAgXCJzbWlsZXkzXCI6IFwiOkRcIixcbiAgICAgICAgXCJzbWlsZXk0XCI6IFwiKHkpXCIsXG4gICAgICAgIFwic21pbGV5NVwiOiBcIiA6UFwiLFxuICAgICAgICBcInNtaWxleTZcIjogXCIod2F2ZSlcIixcbiAgICAgICAgXCJzbWlsZXk3XCI6IFwiKGJsdXNoKVwiLFxuICAgICAgICBcInNtaWxleThcIjogXCIoY2h1Y2tsZSlcIixcbiAgICAgICAgXCJzbWlsZXk5XCI6IFwiKHNob2NrZWQpXCIsXG4gICAgICAgIFwic21pbGV5MTBcIjogXCI6KlwiLFxuICAgICAgICBcInNtaWxleTExXCI6IFwiKG4pXCIsXG4gICAgICAgIFwic21pbGV5MTJcIjogXCIoc2VhcmNoKVwiLFxuICAgICAgICBcInNtaWxleTEzXCI6IFwiIDwzXCIsXG4gICAgICAgIFwic21pbGV5MTRcIjogXCIob29wcylcIixcbiAgICAgICAgXCJzbWlsZXkxNVwiOiBcIihhbmdyeSlcIixcbiAgICAgICAgXCJzbWlsZXkxNlwiOiBcIihhbmdlbClcIixcbiAgICAgICAgXCJzbWlsZXkxN1wiOiBcIihzaWNrKVwiLFxuICAgICAgICBcInNtaWxleTE4XCI6IFwiOyhcIixcbiAgICAgICAgXCJzbWlsZXkxOVwiOiBcIihib21iKVwiLFxuICAgICAgICBcInNtaWxleTIwXCI6IFwiKGNsYXApXCIsXG4gICAgICAgIFwic21pbGV5MjFcIjogXCIgOylcIlxuICAgIH0sXG4gICAgXCJyZWdleHNcIjoge1xuICAgICAgICBcInNtaWxleTJcIjogLyg6LVxcKFxcKHw6LVxcKHw6XFwoXFwofDpcXCh8XFwoc2FkXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkzXCI6IC8oOi1cXClcXCl8OlxcKVxcKXxcXChsb2xcXCl8Oi1EfDpEKS9naSxcbiAgICAgICAgXCJzbWlsZXkxXCI6IC8oOi1cXCl8OlxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5NFwiOiAvKFxcKHlcXCl8XFwoWVxcKXxcXChva1xcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5NVwiOiAvKDotUHw6UHw6LXB8OnApL2dpLFxuICAgICAgICBcInNtaWxleTZcIjogLyhcXCh3YXZlXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXk3XCI6IC8oXFwoYmx1c2hcXCkpL2dpLFxuICAgICAgICBcInNtaWxleThcIjogLyhcXChjaHVja2xlXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXk5XCI6IC8oOi0wfFxcKHNob2NrZWRcXCkpL2dpLFxuICAgICAgICBcInNtaWxleTEwXCI6IC8oOi1cXCp8OlxcKnxcXChraXNzXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkxMVwiOiAvKFxcKG5cXCkpL2dpLFxuICAgICAgICBcInNtaWxleTEyXCI6IC8oXFwoc2VhcmNoXFwpKS9nLFxuICAgICAgICBcInNtaWxleTEzXCI6IC8oPDN8Jmx0OzN8JmFtcDtsdDszfFxcKExcXCl8XFwobFxcKXxcXChIXFwpfFxcKGhcXCkpL2dpLFxuICAgICAgICBcInNtaWxleTE0XCI6IC8oXFwob29wc1xcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MTVcIjogLyhcXChhbmdyeVxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MTZcIjogLyhcXChhbmdlbFxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MTdcIjogLyhcXChzaWNrXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkxOFwiOiAvKDstXFwoXFwofDtcXChcXCh8Oy1cXCh8O1xcKHw6XCJcXCh8OlwiLVxcKHw6fi1cXCh8On5cXCh8XFwodXBzZXRcXCkpL2dpLFxuICAgICAgICBcInNtaWxleTE5XCI6IC8oXFwoYm9tYlxcKSkvZ2ksXG4gICAgICAgIFwic21pbGV5MjBcIjogLyhcXChjbGFwXFwpKS9naSxcbiAgICAgICAgXCJzbWlsZXkyMVwiOiAvKDstXFwpfDtcXCl8Oy1cXClcXCl8O1xcKVxcKXw7LUR8O0R8XFwod2lua1xcKSkvZ2lcbiAgICB9XG59XG4iLCJcbnZhciBudW1iZXJPZkNvbnRhY3RzID0gMDtcbnZhciBub3RpZmljYXRpb25JbnRlcnZhbDtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBudW1iZXIgb2YgcGFydGljaXBhbnRzIGluIHRoZSBjb250YWN0IGxpc3QgYnV0dG9uIGFuZCBzZXRzXG4gKiB0aGUgZ2xvd1xuICogQHBhcmFtIGRlbHRhIGluZGljYXRlcyB3aGV0aGVyIGEgbmV3IHVzZXIgaGFzIGpvaW5lZCAoMSkgb3Igc29tZW9uZSBoYXNcbiAqIGxlZnQoLTEpXG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZU51bWJlck9mUGFydGljaXBhbnRzKGRlbHRhKSB7XG4gICAgLy93aGVuIHRoZSB1c2VyIGlzIGFsb25lIHdlIGRvbid0IHNob3cgdGhlIG51bWJlciBvZiBwYXJ0aWNpcGFudHNcbiAgICBpZihudW1iZXJPZkNvbnRhY3RzID09PSAwKSB7XG4gICAgICAgICQoXCIjbnVtYmVyT2ZQYXJ0aWNpcGFudHNcIikudGV4dCgnJyk7XG4gICAgICAgIG51bWJlck9mQ29udGFjdHMgKz0gZGVsdGE7XG4gICAgfSBlbHNlIGlmKG51bWJlck9mQ29udGFjdHMgIT09IDAgJiYgIUNvbnRhY3RMaXN0LmlzVmlzaWJsZSgpKSB7XG4gICAgICAgIENvbnRhY3RMaXN0LnNldFZpc3VhbE5vdGlmaWNhdGlvbih0cnVlKTtcbiAgICAgICAgbnVtYmVyT2ZDb250YWN0cyArPSBkZWx0YTtcbiAgICAgICAgJChcIiNudW1iZXJPZlBhcnRpY2lwYW50c1wiKS50ZXh0KG51bWJlck9mQ29udGFjdHMpO1xuICAgIH1cbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBhdmF0YXIgZWxlbWVudC5cbiAqXG4gKiBAcmV0dXJuIHRoZSBuZXdseSBjcmVhdGVkIGF2YXRhciBlbGVtZW50XG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUF2YXRhcihpZCkge1xuICAgIHZhciBhdmF0YXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdpbWcnKTtcbiAgICBhdmF0YXIuY2xhc3NOYW1lID0gXCJpY29uLWF2YXRhciBhdmF0YXJcIjtcbiAgICBhdmF0YXIuc3JjID0gXCJodHRwczovL3d3dy5ncmF2YXRhci5jb20vYXZhdGFyL1wiICsgaWQgKyBcIj9kPXdhdmF0YXImc2l6ZT0zMFwiO1xuXG4gICAgcmV0dXJuIGF2YXRhcjtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBkaXNwbGF5IG5hbWUgcGFyYWdyYXBoLlxuICpcbiAqIEBwYXJhbSBkaXNwbGF5TmFtZSB0aGUgZGlzcGxheSBuYW1lIHRvIHNldFxuICovXG5mdW5jdGlvbiBjcmVhdGVEaXNwbGF5TmFtZVBhcmFncmFwaChkaXNwbGF5TmFtZSkge1xuICAgIHZhciBwID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgncCcpO1xuICAgIHAuaW5uZXJUZXh0ID0gZGlzcGxheU5hbWU7XG5cbiAgICByZXR1cm4gcDtcbn1cblxuXG5mdW5jdGlvbiBzdG9wR2xvd2luZyhnbG93ZXIpIHtcbiAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbChub3RpZmljYXRpb25JbnRlcnZhbCk7XG4gICAgbm90aWZpY2F0aW9uSW50ZXJ2YWwgPSBmYWxzZTtcbiAgICBnbG93ZXIucmVtb3ZlQ2xhc3MoJ2dsb3dpbmcnKTtcbiAgICBpZiAoIUNvbnRhY3RMaXN0LmlzVmlzaWJsZSgpKSB7XG4gICAgICAgIGdsb3dlci5yZW1vdmVDbGFzcygnYWN0aXZlJyk7XG4gICAgfVxufVxuXG5cbi8qKlxuICogQ29udGFjdCBsaXN0LlxuICovXG52YXIgQ29udGFjdExpc3QgPSB7XG4gICAgLyoqXG4gICAgICogSW5kaWNhdGVzIGlmIHRoZSBjaGF0IGlzIGN1cnJlbnRseSB2aXNpYmxlLlxuICAgICAqXG4gICAgICogQHJldHVybiA8dHQ+dHJ1ZTwvdHQ+IGlmIHRoZSBjaGF0IGlzIGN1cnJlbnRseSB2aXNpYmxlLCA8dHQ+ZmFsc2U8L3R0PiAtXG4gICAgICogb3RoZXJ3aXNlXG4gICAgICovXG4gICAgaXNWaXNpYmxlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiAkKCcjY29udGFjdGxpc3QnKS5pcyhcIjp2aXNpYmxlXCIpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBBZGRzIGEgY29udGFjdCBmb3IgdGhlIGdpdmVuIHBlZXJKaWQgaWYgc3VjaCBkb2Vzbid0IHlldCBleGlzdC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBwZWVySmlkIHRoZSBwZWVySmlkIGNvcnJlc3BvbmRpbmcgdG8gdGhlIGNvbnRhY3RcbiAgICAgKiBAcGFyYW0gaWQgdGhlIHVzZXIncyBlbWFpbCBvciB1c2VySWQgdXNlZCB0byBnZXQgdGhlIHVzZXIncyBhdmF0YXJcbiAgICAgKi9cbiAgICBlbnN1cmVBZGRDb250YWN0OiBmdW5jdGlvbiAocGVlckppZCwgaWQpIHtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQocGVlckppZCk7XG5cbiAgICAgICAgdmFyIGNvbnRhY3QgPSAkKCcjY29udGFjdGxpc3Q+dWw+bGlbaWQ9XCInICsgcmVzb3VyY2VKaWQgKyAnXCJdJyk7XG5cbiAgICAgICAgaWYgKCFjb250YWN0IHx8IGNvbnRhY3QubGVuZ3RoIDw9IDApXG4gICAgICAgICAgICBDb250YWN0TGlzdC5hZGRDb250YWN0KHBlZXJKaWQsIGlkKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogQWRkcyBhIGNvbnRhY3QgZm9yIHRoZSBnaXZlbiBwZWVyIGppZC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBwZWVySmlkIHRoZSBqaWQgb2YgdGhlIGNvbnRhY3QgdG8gYWRkXG4gICAgICogQHBhcmFtIGlkIHRoZSBlbWFpbCBvciB1c2VySWQgb2YgdGhlIHVzZXJcbiAgICAgKi9cbiAgICBhZGRDb250YWN0OiBmdW5jdGlvbiAocGVlckppZCwgaWQpIHtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQocGVlckppZCk7XG5cbiAgICAgICAgdmFyIGNvbnRhY3RsaXN0ID0gJCgnI2NvbnRhY3RsaXN0PnVsJyk7XG5cbiAgICAgICAgdmFyIG5ld0NvbnRhY3QgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaScpO1xuICAgICAgICBuZXdDb250YWN0LmlkID0gcmVzb3VyY2VKaWQ7XG4gICAgICAgIG5ld0NvbnRhY3QuY2xhc3NOYW1lID0gXCJjbGlja2FibGVcIjtcbiAgICAgICAgbmV3Q29udGFjdC5vbmNsaWNrID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICBpZiAoZXZlbnQuY3VycmVudFRhcmdldC5jbGFzc05hbWUgPT09IFwiY2xpY2thYmxlXCIpIHtcbiAgICAgICAgICAgICAgICAkKENvbnRhY3RMaXN0KS50cmlnZ2VyKCdjb250YWN0Y2xpY2tlZCcsIFtwZWVySmlkXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH07XG5cbiAgICAgICAgbmV3Q29udGFjdC5hcHBlbmRDaGlsZChjcmVhdGVBdmF0YXIoaWQpKTtcbiAgICAgICAgbmV3Q29udGFjdC5hcHBlbmRDaGlsZChjcmVhdGVEaXNwbGF5TmFtZVBhcmFncmFwaChcIlBhcnRpY2lwYW50XCIpKTtcblxuICAgICAgICB2YXIgY2xFbGVtZW50ID0gY29udGFjdGxpc3QuZ2V0KDApO1xuXG4gICAgICAgIGlmIChyZXNvdXJjZUppZCA9PT0gQVBQLnhtcHAubXlSZXNvdXJjZSgpXG4gICAgICAgICAgICAmJiAkKCcjY29udGFjdGxpc3Q+dWwgLnRpdGxlJylbMF0ubmV4dFNpYmxpbmcubmV4dFNpYmxpbmcpIHtcbiAgICAgICAgICAgIGNsRWxlbWVudC5pbnNlcnRCZWZvcmUobmV3Q29udGFjdCxcbiAgICAgICAgICAgICAgICAkKCcjY29udGFjdGxpc3Q+dWwgLnRpdGxlJylbMF0ubmV4dFNpYmxpbmcubmV4dFNpYmxpbmcpO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgY2xFbGVtZW50LmFwcGVuZENoaWxkKG5ld0NvbnRhY3QpO1xuICAgICAgICB9XG4gICAgICAgIHVwZGF0ZU51bWJlck9mUGFydGljaXBhbnRzKDEpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZW1vdmVzIGEgY29udGFjdCBmb3IgdGhlIGdpdmVuIHBlZXIgamlkLlxuICAgICAqXG4gICAgICogQHBhcmFtIHBlZXJKaWQgdGhlIHBlZXJKaWQgY29ycmVzcG9uZGluZyB0byB0aGUgY29udGFjdCB0byByZW1vdmVcbiAgICAgKi9cbiAgICByZW1vdmVDb250YWN0OiBmdW5jdGlvbiAocGVlckppZCkge1xuICAgICAgICB2YXIgcmVzb3VyY2VKaWQgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChwZWVySmlkKTtcblxuICAgICAgICB2YXIgY29udGFjdCA9ICQoJyNjb250YWN0bGlzdD51bD5saVtpZD1cIicgKyByZXNvdXJjZUppZCArICdcIl0nKTtcblxuICAgICAgICBpZiAoY29udGFjdCAmJiBjb250YWN0Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHZhciBjb250YWN0bGlzdCA9ICQoJyNjb250YWN0bGlzdD51bCcpO1xuXG4gICAgICAgICAgICBjb250YWN0bGlzdC5nZXQoMCkucmVtb3ZlQ2hpbGQoY29udGFjdC5nZXQoMCkpO1xuXG4gICAgICAgICAgICB1cGRhdGVOdW1iZXJPZlBhcnRpY2lwYW50cygtMSk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc2V0VmlzdWFsTm90aWZpY2F0aW9uOiBmdW5jdGlvbiAoc2hvdywgc3RvcEdsb3dpbmdJbikge1xuICAgICAgICB2YXIgZ2xvd2VyID0gJCgnI2NvbnRhY3RMaXN0QnV0dG9uJyk7XG5cbiAgICAgICAgaWYgKHNob3cgJiYgIW5vdGlmaWNhdGlvbkludGVydmFsKSB7XG4gICAgICAgICAgICBub3RpZmljYXRpb25JbnRlcnZhbCA9IHdpbmRvdy5zZXRJbnRlcnZhbChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgZ2xvd2VyLnRvZ2dsZUNsYXNzKCdhY3RpdmUgZ2xvd2luZycpO1xuICAgICAgICAgICAgfSwgODAwKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIGlmICghc2hvdyAmJiBub3RpZmljYXRpb25JbnRlcnZhbCkge1xuICAgICAgICAgICAgc3RvcEdsb3dpbmcoZ2xvd2VyKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc3RvcEdsb3dpbmdJbikge1xuICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgc3RvcEdsb3dpbmcoZ2xvd2VyKTtcbiAgICAgICAgICAgIH0sIHN0b3BHbG93aW5nSW4pO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIHNldENsaWNrYWJsZTogZnVuY3Rpb24gKHJlc291cmNlSmlkLCBpc0NsaWNrYWJsZSkge1xuICAgICAgICB2YXIgY29udGFjdCA9ICQoJyNjb250YWN0bGlzdD51bD5saVtpZD1cIicgKyByZXNvdXJjZUppZCArICdcIl0nKTtcbiAgICAgICAgaWYgKGlzQ2xpY2thYmxlKSB7XG4gICAgICAgICAgICBjb250YWN0LmFkZENsYXNzKCdjbGlja2FibGUnKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGNvbnRhY3QucmVtb3ZlQ2xhc3MoJ2NsaWNrYWJsZScpO1xuICAgICAgICB9XG4gICAgfSxcblxuICAgIG9uRGlzcGxheU5hbWVDaGFuZ2U6IGZ1bmN0aW9uIChwZWVySmlkLCBkaXNwbGF5TmFtZSkge1xuICAgICAgICBpZiAocGVlckppZCA9PT0gJ2xvY2FsVmlkZW9Db250YWluZXInKVxuICAgICAgICAgICAgcGVlckppZCA9IEFQUC54bXBwLm15SmlkKCk7XG5cbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQocGVlckppZCk7XG5cbiAgICAgICAgdmFyIGNvbnRhY3ROYW1lID0gJCgnI2NvbnRhY3RsaXN0ICMnICsgcmVzb3VyY2VKaWQgKyAnPnAnKTtcblxuICAgICAgICBpZiAoY29udGFjdE5hbWUgJiYgZGlzcGxheU5hbWUgJiYgZGlzcGxheU5hbWUubGVuZ3RoID4gMClcbiAgICAgICAgICAgIGNvbnRhY3ROYW1lLmh0bWwoZGlzcGxheU5hbWUpO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQ29udGFjdExpc3Q7IiwidmFyIGVtYWlsID0gJyc7XG52YXIgZGlzcGxheU5hbWUgPSAnJztcbnZhciB1c2VySWQ7XG5cblxuZnVuY3Rpb24gc3VwcG9ydHNMb2NhbFN0b3JhZ2UoKSB7XG4gICAgdHJ5IHtcbiAgICAgICAgcmV0dXJuICdsb2NhbFN0b3JhZ2UnIGluIHdpbmRvdyAmJiB3aW5kb3cubG9jYWxTdG9yYWdlICE9PSBudWxsO1xuICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5sb2coXCJsb2NhbHN0b3JhZ2UgaXMgbm90IHN1cHBvcnRlZFwiKTtcbiAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBnZW5lcmF0ZVVuaXF1ZUlkKCkge1xuICAgIGZ1bmN0aW9uIF9wOCgpIHtcbiAgICAgICAgcmV0dXJuIChNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDE2KStcIjAwMDAwMDAwMFwiKS5zdWJzdHIoMiw4KTtcbiAgICB9XG4gICAgcmV0dXJuIF9wOCgpICsgX3A4KCkgKyBfcDgoKSArIF9wOCgpO1xufVxuXG5pZihzdXBwb3J0c0xvY2FsU3RvcmFnZSgpKSB7XG4gICAgaWYoIXdpbmRvdy5sb2NhbFN0b3JhZ2Uuaml0c2lNZWV0SWQpIHtcbiAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5qaXRzaU1lZXRJZCA9IGdlbmVyYXRlVW5pcXVlSWQoKTtcbiAgICAgICAgY29uc29sZS5sb2coXCJnZW5lcmF0ZWQgaWRcIiwgd2luZG93LmxvY2FsU3RvcmFnZS5qaXRzaU1lZXRJZCk7XG4gICAgfVxuICAgIHVzZXJJZCA9IHdpbmRvdy5sb2NhbFN0b3JhZ2Uuaml0c2lNZWV0SWQgfHwgJyc7XG4gICAgZW1haWwgPSB3aW5kb3cubG9jYWxTdG9yYWdlLmVtYWlsIHx8ICcnO1xuICAgIGRpc3BsYXlOYW1lID0gd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZSB8fCAnJztcbn0gZWxzZSB7XG4gICAgY29uc29sZS5sb2coXCJsb2NhbCBzdG9yYWdlIGlzIG5vdCBzdXBwb3J0ZWRcIik7XG4gICAgdXNlcklkID0gZ2VuZXJhdGVVbmlxdWVJZCgpO1xufVxuXG52YXIgU2V0dGluZ3MgPVxue1xuICAgIHNldERpc3BsYXlOYW1lOiBmdW5jdGlvbiAobmV3RGlzcGxheU5hbWUpIHtcbiAgICAgICAgZGlzcGxheU5hbWUgPSBuZXdEaXNwbGF5TmFtZTtcbiAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZSA9IGRpc3BsYXlOYW1lO1xuICAgICAgICByZXR1cm4gZGlzcGxheU5hbWU7XG4gICAgfSxcbiAgICBzZXRFbWFpbDogZnVuY3Rpb24obmV3RW1haWwpXG4gICAge1xuICAgICAgICBlbWFpbCA9IG5ld0VtYWlsO1xuICAgICAgICB3aW5kb3cubG9jYWxTdG9yYWdlLmVtYWlsID0gbmV3RW1haWw7XG4gICAgICAgIHJldHVybiBlbWFpbDtcbiAgICB9LFxuICAgIGdldFNldHRpbmdzOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgICBlbWFpbDogZW1haWwsXG4gICAgICAgICAgICBkaXNwbGF5TmFtZTogZGlzcGxheU5hbWUsXG4gICAgICAgICAgICB1aWQ6IHVzZXJJZFxuICAgICAgICB9O1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU2V0dGluZ3M7XG4iLCJ2YXIgQXZhdGFyID0gcmVxdWlyZShcIi4uLy4uL2F2YXRhci9BdmF0YXJcIik7XG52YXIgU2V0dGluZ3MgPSByZXF1aXJlKFwiLi9TZXR0aW5nc1wiKTtcbnZhciBVSVV0aWwgPSByZXF1aXJlKFwiLi4vLi4vdXRpbC9VSVV0aWxcIik7XG52YXIgbGFuZ3VhZ2VzID0gcmVxdWlyZShcIi4uLy4uLy4uLy4uL3NlcnZpY2UvdHJhbnNsYXRpb24vbGFuZ3VhZ2VzXCIpO1xuXG5mdW5jdGlvbiBnZW5lcmF0ZUxhbmd1YWdlc1NlbGVjdEJveCgpXG57XG4gICAgdmFyIGN1cnJlbnRMYW5nID0gQVBQLnRyYW5zbGF0aW9uLmdldEN1cnJlbnRMYW5ndWFnZSgpO1xuICAgIHZhciBodG1sID0gXCI8c2VsZWN0IGlkPVxcXCJsYW5ndWFnZXNfc2VsZWN0Ym94XFxcIj5cIjtcbiAgICB2YXIgbGFuZ0FycmF5ID0gbGFuZ3VhZ2VzLmdldExhbmd1YWdlcygpO1xuICAgIGZvcih2YXIgaSA9IDA7IGkgPCBsYW5nQXJyYXkubGVuZ3RoOyBpKyspXG4gICAge1xuICAgICAgICB2YXIgbGFuZyA9IGxhbmdBcnJheVtpXTtcbiAgICAgICAgaHRtbCArPSBcIjxvcHRpb24gXCI7XG4gICAgICAgIGlmKGxhbmcgPT09IGN1cnJlbnRMYW5nKVxuICAgICAgICAgICAgaHRtbCArPSBcInNlbGVjdGVkIFwiO1xuICAgICAgICBodG1sICs9IFwidmFsdWU9XFxcIlwiICsgbGFuZyArIFwiXFxcIiBkYXRhLWkxOG49J2xhbmd1YWdlczpcIiArIGxhbmcgKyBcIic+XCI7XG4gICAgICAgIGh0bWwgKz0gXCI8L29wdGlvbj5cIjtcblxuICAgIH1cblxuICAgIHJldHVybiBodG1sICsgXCI8L3NlbGVjdD5cIjtcbn1cblxuXG52YXIgU2V0dGluZ3NNZW51ID0ge1xuXG4gICAgaW5pdDogZnVuY3Rpb24gKCkge1xuICAgICAgICAkKFwiI3VwZGF0ZVNldHRpbmdzXCIpLmJlZm9yZShnZW5lcmF0ZUxhbmd1YWdlc1NlbGVjdEJveCgpKTtcbiAgICAgICAgJCgnI3NldHRpbmdzbWVudT5pbnB1dCcpLmtleXVwKGZ1bmN0aW9uKGV2ZW50KXtcbiAgICAgICAgICAgIGlmKGV2ZW50LmtleUNvZGUgPT09IDEzKSB7Ly9lbnRlclxuICAgICAgICAgICAgICAgIFNldHRpbmdzTWVudS51cGRhdGUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG5cbiAgICAgICAgJChcIiN1cGRhdGVTZXR0aW5nc1wiKS5jbGljayhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBTZXR0aW5nc01lbnUudXBkYXRlKCk7XG4gICAgICAgIH0pO1xuICAgIH0sXG5cbiAgICB1cGRhdGU6IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgbmV3RGlzcGxheU5hbWUgPSBVSVV0aWwuZXNjYXBlSHRtbCgkKCcjc2V0RGlzcGxheU5hbWUnKS5nZXQoMCkudmFsdWUpO1xuICAgICAgICB2YXIgbmV3RW1haWwgPSBVSVV0aWwuZXNjYXBlSHRtbCgkKCcjc2V0RW1haWwnKS5nZXQoMCkudmFsdWUpO1xuXG4gICAgICAgIGlmKG5ld0Rpc3BsYXlOYW1lKSB7XG4gICAgICAgICAgICB2YXIgZGlzcGxheU5hbWUgPSBTZXR0aW5ncy5zZXREaXNwbGF5TmFtZShuZXdEaXNwbGF5TmFtZSk7XG4gICAgICAgICAgICBBUFAueG1wcC5hZGRUb1ByZXNlbmNlKFwiZGlzcGxheU5hbWVcIiwgZGlzcGxheU5hbWUsIHRydWUpO1xuICAgICAgICB9XG5cbiAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnNldExhbmd1YWdlKCQoXCIjbGFuZ3VhZ2VzX3NlbGVjdGJveFwiKS52YWwoKSk7XG5cbiAgICAgICAgQVBQLnhtcHAuYWRkVG9QcmVzZW5jZShcImVtYWlsXCIsIG5ld0VtYWlsKTtcbiAgICAgICAgdmFyIGVtYWlsID0gU2V0dGluZ3Muc2V0RW1haWwobmV3RW1haWwpO1xuXG5cbiAgICAgICAgQXZhdGFyLnNldFVzZXJBdmF0YXIoQVBQLnhtcHAubXlKaWQoKSwgZW1haWwpO1xuICAgIH0sXG5cbiAgICBpc1Zpc2libGU6IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gJCgnI3NldHRpbmdzbWVudScpLmlzKCc6dmlzaWJsZScpO1xuICAgIH0sXG5cbiAgICBzZXREaXNwbGF5TmFtZTogZnVuY3Rpb24obmV3RGlzcGxheU5hbWUpIHtcbiAgICAgICAgdmFyIGRpc3BsYXlOYW1lID0gU2V0dGluZ3Muc2V0RGlzcGxheU5hbWUobmV3RGlzcGxheU5hbWUpO1xuICAgICAgICAkKCcjc2V0RGlzcGxheU5hbWUnKS5nZXQoMCkudmFsdWUgPSBkaXNwbGF5TmFtZTtcbiAgICB9LFxuXG4gICAgb25EaXNwbGF5TmFtZUNoYW5nZTogZnVuY3Rpb24ocGVlckppZCwgbmV3RGlzcGxheU5hbWUpIHtcbiAgICAgICAgaWYocGVlckppZCA9PT0gJ2xvY2FsVmlkZW9Db250YWluZXInIHx8XG4gICAgICAgICAgICBwZWVySmlkID09PSBBUFAueG1wcC5teUppZCgpKSB7XG4gICAgICAgICAgICB0aGlzLnNldERpc3BsYXlOYW1lKG5ld0Rpc3BsYXlOYW1lKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cblxubW9kdWxlLmV4cG9ydHMgPSBTZXR0aW5nc01lbnU7IiwidmFyIFBhbmVsVG9nZ2xlciA9IHJlcXVpcmUoXCIuLi9zaWRlX3Bhbm5lbHMvU2lkZVBhbmVsVG9nZ2xlclwiKTtcblxudmFyIGJ1dHRvbkhhbmRsZXJzID0ge1xuICAgIFwiYm90dG9tX3Rvb2xiYXJfY29udGFjdF9saXN0XCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQm90dG9tVG9vbGJhci50b2dnbGVDb250YWN0TGlzdCgpO1xuICAgIH0sXG4gICAgXCJib3R0b21fdG9vbGJhcl9maWxtX3N0cmlwXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQm90dG9tVG9vbGJhci50b2dnbGVGaWxtU3RyaXAoKTtcbiAgICB9LFxuICAgIFwiYm90dG9tX3Rvb2xiYXJfY2hhdFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIEJvdHRvbVRvb2xiYXIudG9nZ2xlQ2hhdCgpO1xuICAgIH1cbn07XG5cbnZhciBCb3R0b21Ub29sYmFyID0gKGZ1bmN0aW9uIChteSkge1xuICAgIG15LmluaXQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGZvcih2YXIgayBpbiBidXR0b25IYW5kbGVycylcbiAgICAgICAgICAgICQoXCIjXCIgKyBrKS5jbGljayhidXR0b25IYW5kbGVyc1trXSk7XG4gICAgfTtcblxuICAgIG15LnRvZ2dsZUNoYXQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgUGFuZWxUb2dnbGVyLnRvZ2dsZUNoYXQoKTtcbiAgICB9O1xuXG4gICAgbXkudG9nZ2xlQ29udGFjdExpc3QgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgUGFuZWxUb2dnbGVyLnRvZ2dsZUNvbnRhY3RMaXN0KCk7XG4gICAgfTtcblxuICAgIG15LnRvZ2dsZUZpbG1TdHJpcCA9IGZ1bmN0aW9uKCkge1xuICAgICAgICB2YXIgZmlsbXN0cmlwID0gJChcIiNyZW1vdGVWaWRlb3NcIik7XG4gICAgICAgIGZpbG1zdHJpcC50b2dnbGVDbGFzcyhcImhpZGRlblwiKTtcbiAgICB9O1xuXG4gICAgJChkb2N1bWVudCkuYmluZChcInJlbW90ZXZpZGVvLnJlc2l6ZWRcIiwgZnVuY3Rpb24gKGV2ZW50LCB3aWR0aCwgaGVpZ2h0KSB7XG4gICAgICAgIHZhciBib3R0b20gPSAoaGVpZ2h0IC0gJCgnI2JvdHRvbVRvb2xiYXInKS5vdXRlckhlaWdodCgpKS8yICsgMTg7XG5cbiAgICAgICAgJCgnI2JvdHRvbVRvb2xiYXInKS5jc3Moe2JvdHRvbTogYm90dG9tICsgJ3B4J30pO1xuICAgIH0pO1xuXG4gICAgcmV0dXJuIG15O1xufShCb3R0b21Ub29sYmFyIHx8IHt9KSk7XG5cbm1vZHVsZS5leHBvcnRzID0gQm90dG9tVG9vbGJhcjtcbiIsIi8qIGdsb2JhbCAkLCBidXR0b25DbGljaywgY29uZmlnLCBsb2NrUm9vbSxcbiAgIHNldFNoYXJlZEtleSwgVXRpbCAqL1xudmFyIG1lc3NhZ2VIYW5kbGVyID0gcmVxdWlyZShcIi4uL3V0aWwvTWVzc2FnZUhhbmRsZXJcIik7XG52YXIgQm90dG9tVG9vbGJhciA9IHJlcXVpcmUoXCIuL0JvdHRvbVRvb2xiYXJcIik7XG52YXIgUHJlemkgPSByZXF1aXJlKFwiLi4vcHJlemkvUHJlemlcIik7XG52YXIgRXRoZXJwYWQgPSByZXF1aXJlKFwiLi4vZXRoZXJwYWQvRXRoZXJwYWRcIik7XG52YXIgUGFuZWxUb2dnbGVyID0gcmVxdWlyZShcIi4uL3NpZGVfcGFubmVscy9TaWRlUGFuZWxUb2dnbGVyXCIpO1xudmFyIEF1dGhlbnRpY2F0aW9uID0gcmVxdWlyZShcIi4uL2F1dGhlbnRpY2F0aW9uL0F1dGhlbnRpY2F0aW9uXCIpO1xudmFyIFVJVXRpbCA9IHJlcXVpcmUoXCIuLi91dGlsL1VJVXRpbFwiKTtcblxudmFyIHJvb21VcmwgPSBudWxsO1xudmFyIHNoYXJlZEtleSA9ICcnO1xudmFyIFVJID0gbnVsbDtcblxudmFyIGJ1dHRvbkhhbmRsZXJzID1cbntcbiAgICBcInRvb2xiYXJfYnV0dG9uX211dGVcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gQVBQLlVJLnRvZ2dsZUF1ZGlvKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX2NhbWVyYVwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBBUFAuVUkudG9nZ2xlVmlkZW8oKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fYXV0aGVudGljYXRpb25cIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gVG9vbGJhci5hdXRoZW50aWNhdGVDbGlja2VkKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX3JlY29yZFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiB0b2dnbGVSZWNvcmRpbmcoKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fc2VjdXJpdHlcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gVG9vbGJhci5vcGVuTG9ja0RpYWxvZygpO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9saW5rXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIFRvb2xiYXIub3BlbkxpbmtEaWFsb2coKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fY2hhdFwiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBCb3R0b21Ub29sYmFyLnRvZ2dsZUNoYXQoKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fcHJlemlcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gUHJlemkub3BlblByZXppRGlhbG9nKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX2V0aGVycGFkXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIEV0aGVycGFkLnRvZ2dsZUV0aGVycGFkKDApO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9kZXNrdG9wc2hhcmluZ1wiOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBBUFAuZGVza3RvcHNoYXJpbmcudG9nZ2xlU2NyZWVuU2hhcmluZygpO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9mdWxsU2NyZWVuXCI6IGZ1bmN0aW9uKClcbiAgICB7XG4gICAgICAgIFVJVXRpbC5idXR0b25DbGljayhcIiNmdWxsU2NyZWVuXCIsIFwiaWNvbi1mdWxsLXNjcmVlbiBpY29uLWV4aXQtZnVsbC1zY3JlZW5cIik7XG4gICAgICAgIHJldHVybiBUb29sYmFyLnRvZ2dsZUZ1bGxTY3JlZW4oKTtcbiAgICB9LFxuICAgIFwidG9vbGJhcl9idXR0b25fc2lwXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGNhbGxTaXBCdXR0b25DbGlja2VkKCk7XG4gICAgfSxcbiAgICBcInRvb2xiYXJfYnV0dG9uX3NldHRpbmdzXCI6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgUGFuZWxUb2dnbGVyLnRvZ2dsZVNldHRpbmdzTWVudSgpO1xuICAgIH0sXG4gICAgXCJ0b29sYmFyX2J1dHRvbl9oYW5ndXBcIjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gaGFuZ3VwKCk7XG4gICAgfVxufTtcblxuZnVuY3Rpb24gaGFuZ3VwKCkge1xuICAgIEFQUC54bXBwLmRpc3Bvc2VDb25mZXJlbmNlKCk7XG4gICAgaWYoY29uZmlnLmVuYWJsZVdlbGNvbWVQYWdlKVxuICAgIHtcbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2Uud2VsY29tZVBhZ2VEaXNhYmxlZCA9IGZhbHNlO1xuICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLnBhdGhuYW1lID0gXCIvXCI7XG4gICAgICAgIH0sIDEwMDAwKTtcblxuICAgIH1cblxuICAgIFVJLm1lc3NhZ2VIYW5kbGVyLm9wZW5EaWFsb2coXG4gICAgICAgIFwiU2Vzc2lvbiBUZXJtaW5hdGVkXCIsXG4gICAgICAgIFwiWW91IGh1bmcgdXAgdGhlIGNhbGxcIixcbiAgICAgICAgdHJ1ZSxcbiAgICAgICAgeyBcIkpvaW4gYWdhaW5cIjogdHJ1ZSB9LFxuICAgICAgICBmdW5jdGlvbihldmVudCwgdmFsdWUsIG1lc3NhZ2UsIGZvcm1WYWxzKVxuICAgICAgICB7XG4gICAgICAgICAgICB3aW5kb3cubG9jYXRpb24ucmVsb2FkKCk7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cbiAgICApO1xufVxuXG4vKipcbiAqIFN0YXJ0cyBvciBzdG9wcyB0aGUgcmVjb3JkaW5nIGZvciB0aGUgY29uZmVyZW5jZS5cbiAqL1xuXG5mdW5jdGlvbiB0b2dnbGVSZWNvcmRpbmcoKSB7XG4gICAgQVBQLnhtcHAudG9nZ2xlUmVjb3JkaW5nKGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIub3BlblR3b0J1dHRvbkRpYWxvZyhudWxsLFxuICAgICAgICAgICAgICAgICc8aDI+RW50ZXIgcmVjb3JkaW5nIHRva2VuPC9oMj4nICtcbiAgICAgICAgICAgICAgICAnPGlucHV0IGlkPVwicmVjb3JkaW5nVG9rZW5cIiB0eXBlPVwidGV4dFwiICcgK1xuICAgICAgICAgICAgICAgICdwbGFjZWhvbGRlcj1cInRva2VuXCIgYXV0b2ZvY3VzPicsXG4gICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgIFwiU2F2ZVwiLFxuICAgICAgICAgICAgZnVuY3Rpb24gKGUsIHYsIG0sIGYpIHtcbiAgICAgICAgICAgICAgICBpZiAodikge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdG9rZW4gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmVjb3JkaW5nVG9rZW4nKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAodG9rZW4udmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhbGxiYWNrKFVJVXRpbC5lc2NhcGVIdG1sKHRva2VuLnZhbHVlKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3JlY29yZGluZ1Rva2VuJykuZm9jdXMoKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfSwgVG9vbGJhci5zZXRSZWNvcmRpbmdCdXR0b25TdGF0ZSwgVG9vbGJhci5zZXRSZWNvcmRpbmdCdXR0b25TdGF0ZSk7XG59XG5cbi8qKlxuICogTG9ja3MgLyB1bmxvY2tzIHRoZSByb29tLlxuICovXG5mdW5jdGlvbiBsb2NrUm9vbShsb2NrKSB7XG4gICAgdmFyIGN1cnJlbnRTaGFyZWRLZXkgPSAnJztcbiAgICBpZiAobG9jaylcbiAgICAgICAgY3VycmVudFNoYXJlZEtleSA9IHNoYXJlZEtleTtcblxuICAgIEFQUC54bXBwLmxvY2tSb29tKGN1cnJlbnRTaGFyZWRLZXksIGZ1bmN0aW9uIChyZXMpIHtcbiAgICAgICAgLy8gcGFzc3dvcmQgaXMgcmVxdWlyZWRcbiAgICAgICAgaWYgKHNoYXJlZEtleSlcbiAgICAgICAge1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ3NldCByb29tIHBhc3N3b3JkJyk7XG4gICAgICAgICAgICBUb29sYmFyLmxvY2tMb2NrQnV0dG9uKCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygncmVtb3ZlZCByb29tIHBhc3N3b3JkJyk7XG4gICAgICAgICAgICBUb29sYmFyLnVubG9ja0xvY2tCdXR0b24oKTtcbiAgICAgICAgfVxuICAgIH0sIGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgY29uc29sZS53YXJuKCdzZXR0aW5nIHBhc3N3b3JkIGZhaWxlZCcsIGVycik7XG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyLnNob3dFcnJvcignTG9jayBmYWlsZWQnLFxuICAgICAgICAgICAgJ0ZhaWxlZCB0byBsb2NrIGNvbmZlcmVuY2UuJyxcbiAgICAgICAgICAgIGVycik7XG4gICAgICAgIFRvb2xiYXIuc2V0U2hhcmVkS2V5KCcnKTtcbiAgICB9LCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGNvbnNvbGUud2Fybigncm9vbSBwYXNzd29yZHMgbm90IHN1cHBvcnRlZCcpO1xuICAgICAgICBtZXNzYWdlSGFuZGxlci5zaG93RXJyb3IoJ1dhcm5pbmcnLFxuICAgICAgICAgICAgJ1Jvb20gcGFzc3dvcmRzIGFyZSBjdXJyZW50bHkgbm90IHN1cHBvcnRlZC4nKTtcbiAgICAgICAgVG9vbGJhci5zZXRTaGFyZWRLZXkoJycpO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBJbnZpdGUgcGFydGljaXBhbnRzIHRvIGNvbmZlcmVuY2UuXG4gKi9cbmZ1bmN0aW9uIGludml0ZVBhcnRpY2lwYW50cygpIHtcbiAgICBpZiAocm9vbVVybCA9PT0gbnVsbClcbiAgICAgICAgcmV0dXJuO1xuXG4gICAgdmFyIHNoYXJlZEtleVRleHQgPSBcIlwiO1xuICAgIGlmIChzaGFyZWRLZXkgJiYgc2hhcmVkS2V5Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgc2hhcmVkS2V5VGV4dCA9XG4gICAgICAgICAgICBcIlRoaXMgY29uZmVyZW5jZSBpcyBwYXNzd29yZCBwcm90ZWN0ZWQuIFBsZWFzZSB1c2UgdGhlIFwiICtcbiAgICAgICAgICAgIFwiZm9sbG93aW5nIHBpbiB3aGVuIGpvaW5pbmc6JTBEJTBBJTBEJTBBXCIgK1xuICAgICAgICAgICAgc2hhcmVkS2V5ICsgXCIlMEQlMEElMEQlMEFcIjtcbiAgICB9XG5cbiAgICB2YXIgY29uZmVyZW5jZU5hbWUgPSByb29tVXJsLnN1YnN0cmluZyhyb29tVXJsLmxhc3RJbmRleE9mKCcvJykgKyAxKTtcbiAgICB2YXIgc3ViamVjdCA9IFwiSW52aXRhdGlvbiB0byBhIFwiICsgaW50ZXJmYWNlQ29uZmlnLkFQUF9OQU1FICsgXCIgKFwiICsgY29uZmVyZW5jZU5hbWUgKyBcIilcIjtcbiAgICB2YXIgYm9keSA9IFwiSGV5IHRoZXJlLCBJJTI3ZCBsaWtlIHRvIGludml0ZSB5b3UgdG8gYSBcIiArIGludGVyZmFjZUNvbmZpZy5BUFBfTkFNRSArXG4gICAgICAgIFwiIGNvbmZlcmVuY2UgSSUyN3ZlIGp1c3Qgc2V0IHVwLiUwRCUwQSUwRCUwQVwiICtcbiAgICAgICAgXCJQbGVhc2UgY2xpY2sgb24gdGhlIGZvbGxvd2luZyBsaW5rIGluIG9yZGVyXCIgK1xuICAgICAgICBcIiB0byBqb2luIHRoZSBjb25mZXJlbmNlLiUwRCUwQSUwRCUwQVwiICtcbiAgICAgICAgcm9vbVVybCArXG4gICAgICAgIFwiJTBEJTBBJTBEJTBBXCIgK1xuICAgICAgICBzaGFyZWRLZXlUZXh0ICtcbiAgICAgICAgXCJOb3RlIHRoYXQgXCIgKyBpbnRlcmZhY2VDb25maWcuQVBQX05BTUUgKyBcIiBpcyBjdXJyZW50bHlcIiArXG4gICAgICAgIFwiIG9ubHkgc3VwcG9ydGVkIGJ5IENocm9taXVtLFwiICtcbiAgICAgICAgXCIgR29vZ2xlIENocm9tZSBhbmQgT3BlcmEsIHNvIHlvdSBuZWVkXCIgK1xuICAgICAgICBcIiB0byBiZSB1c2luZyBvbmUgb2YgdGhlc2UgYnJvd3NlcnMuJTBEJTBBJTBEJTBBXCIgK1xuICAgICAgICBcIlRhbGsgdG8geW91IGluIGEgc2VjIVwiO1xuXG4gICAgaWYgKHdpbmRvdy5sb2NhbFN0b3JhZ2UuZGlzcGxheW5hbWUpIHtcbiAgICAgICAgYm9keSArPSBcIiUwRCUwQSUwRCUwQVwiICsgd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZTtcbiAgICB9XG5cbiAgICBpZiAoaW50ZXJmYWNlQ29uZmlnLklOVklUQVRJT05fUE9XRVJFRF9CWSkge1xuICAgICAgICBib2R5ICs9IFwiJTBEJTBBJTBEJTBBLS0lMEQlMEFwb3dlcmVkIGJ5IGppdHNpLm9yZ1wiO1xuICAgIH1cblxuICAgIHdpbmRvdy5vcGVuKFwibWFpbHRvOj9zdWJqZWN0PVwiICsgc3ViamVjdCArIFwiJmJvZHk9XCIgKyBib2R5LCAnX2JsYW5rJyk7XG59XG5cbmZ1bmN0aW9uIGNhbGxTaXBCdXR0b25DbGlja2VkKClcbntcbiAgICB2YXIgZGVmYXVsdE51bWJlclxuICAgICAgICA9IGNvbmZpZy5kZWZhdWx0U2lwTnVtYmVyID8gY29uZmlnLmRlZmF1bHRTaXBOdW1iZXIgOiAnJztcblxuICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2cobnVsbCxcbiAgICAgICAgJzxoMj5FbnRlciBTSVAgbnVtYmVyPC9oMj4nICtcbiAgICAgICAgJzxpbnB1dCBpZD1cInNpcE51bWJlclwiIHR5cGU9XCJ0ZXh0XCInICtcbiAgICAgICAgJyB2YWx1ZT1cIicgKyBkZWZhdWx0TnVtYmVyICsgJ1wiIGF1dG9mb2N1cz4nLFxuICAgICAgICBmYWxzZSxcbiAgICAgICAgXCJEaWFsXCIsXG4gICAgICAgIGZ1bmN0aW9uIChlLCB2LCBtLCBmKSB7XG4gICAgICAgICAgICBpZiAodikge1xuICAgICAgICAgICAgICAgIHZhciBudW1iZXJJbnB1dCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdzaXBOdW1iZXInKTtcbiAgICAgICAgICAgICAgICBpZiAobnVtYmVySW5wdXQudmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgQVBQLnhtcHAuZGlhbChudW1iZXJJbnB1dC52YWx1ZSwgJ2Zyb21udW1iZXInLFxuICAgICAgICAgICAgICAgICAgICAgICAgVUkuZ2V0Um9vbU5hbWUoKSwgc2hhcmVkS2V5KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ3NpcE51bWJlcicpLmZvY3VzKCk7XG4gICAgICAgIH1cbiAgICApO1xufVxuXG52YXIgVG9vbGJhciA9IChmdW5jdGlvbiAobXkpIHtcblxuICAgIG15LmluaXQgPSBmdW5jdGlvbiAodWkpIHtcbiAgICAgICAgZm9yKHZhciBrIGluIGJ1dHRvbkhhbmRsZXJzKVxuICAgICAgICAgICAgJChcIiNcIiArIGspLmNsaWNrKGJ1dHRvbkhhbmRsZXJzW2tdKTtcbiAgICAgICAgVUkgPSB1aTtcbiAgICB9XG5cbiAgICAvKipcbiAgICAgKiBTZXRzIHNoYXJlZCBrZXlcbiAgICAgKiBAcGFyYW0gc0tleSB0aGUgc2hhcmVkIGtleVxuICAgICAqL1xuICAgIG15LnNldFNoYXJlZEtleSA9IGZ1bmN0aW9uIChzS2V5KSB7XG4gICAgICAgIHNoYXJlZEtleSA9IHNLZXk7XG4gICAgfTtcblxuICAgIG15LmF1dGhlbnRpY2F0ZUNsaWNrZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIEF1dGhlbnRpY2F0aW9uLmZvY3VzQXV0aGVudGljYXRpb25XaW5kb3coKTtcbiAgICAgICAgLy8gR2V0IGF1dGhlbnRpY2F0aW9uIFVSTFxuICAgICAgICBBUFAueG1wcC5nZXRBdXRoVXJsKEFQUC5VSS5nZXRSb29tTmFtZSgpLCBmdW5jdGlvbiAodXJsKSB7XG4gICAgICAgICAgICAvLyBPcGVuIHBvcHVwIHdpdGggYXV0aGVudGljYXRpb24gVVJMXG4gICAgICAgICAgICB2YXIgYXV0aGVudGljYXRpb25XaW5kb3cgPSBBdXRoZW50aWNhdGlvbi5jcmVhdGVBdXRoZW50aWNhdGlvbldpbmRvdyhmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgLy8gT24gcG9wdXAgY2xvc2VkIC0gcmV0cnkgcm9vbSBhbGxvY2F0aW9uXG4gICAgICAgICAgICAgICAgQVBQLnhtcHAuYWxsb2NhdGVDb25mZXJlbmNlRm9jdXMoQVBQLlVJLmdldFJvb21OYW1lKCksIEFQUC5VSS5jaGVja0Zvck5pY2tuYW1lQW5kSm9pbik7XG4gICAgICAgICAgICB9LCB1cmwpO1xuICAgICAgICAgICAgaWYgKCFhdXRoZW50aWNhdGlvbldpbmRvdykge1xuICAgICAgICAgICAgICAgIFRvb2xiYXIuc2hvd0F1dGhlbnRpY2F0ZUJ1dHRvbih0cnVlKTtcbiAgICAgICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuTWVzc2FnZURpYWxvZyhcbiAgICAgICAgICAgICAgICAgICAgbnVsbCwgXCJZb3VyIGJyb3dzZXIgaXMgYmxvY2tpbmcgcG9wdXAgd2luZG93cyBmcm9tIHRoaXMgc2l0ZS5cIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiBQbGVhc2UgZW5hYmxlIHBvcHVwcyBpbiB5b3VyIGJyb3dzZXIgc2VjdXJpdHkgc2V0dGluZ3NcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiBhbmQgdHJ5IGFnYWluLlwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIHJvb20gaW52aXRlIHVybC5cbiAgICAgKi9cbiAgICBteS51cGRhdGVSb29tVXJsID0gZnVuY3Rpb24gKG5ld1Jvb21VcmwpIHtcbiAgICAgICAgcm9vbVVybCA9IG5ld1Jvb21Vcmw7XG5cbiAgICAgICAgLy8gSWYgdGhlIGludml0ZSBkaWFsb2cgaGFzIGJlZW4gYWxyZWFkeSBvcGVuZWQgd2UgdXBkYXRlIHRoZSBpbmZvcm1hdGlvbi5cbiAgICAgICAgdmFyIGludml0ZUxpbmsgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnaW52aXRlTGlua1JlZicpO1xuICAgICAgICBpZiAoaW52aXRlTGluaykge1xuICAgICAgICAgICAgaW52aXRlTGluay52YWx1ZSA9IHJvb21Vcmw7XG4gICAgICAgICAgICBpbnZpdGVMaW5rLnNlbGVjdCgpO1xuICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2pxaV9zdGF0ZTBfYnV0dG9uSW52aXRlJykuZGlzYWJsZWQgPSBmYWxzZTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBEaXNhYmxlcyBhbmQgZW5hYmxlcyBzb21lIG9mIHRoZSBidXR0b25zLlxuICAgICAqL1xuICAgIG15LnNldHVwQnV0dG9uc0Zyb21Db25maWcgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmIChjb25maWcuZGlzYWJsZVByZXppKVxuICAgICAgICB7XG4gICAgICAgICAgICAkKFwiI3ByZXppX2J1dHRvblwiKS5jc3Moe2Rpc3BsYXk6IFwibm9uZVwifSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogT3BlbnMgdGhlIGxvY2sgcm9vbSBkaWFsb2cuXG4gICAgICovXG4gICAgbXkub3BlbkxvY2tEaWFsb2cgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIE9ubHkgdGhlIGZvY3VzIGlzIGFibGUgdG8gc2V0IGEgc2hhcmVkIGtleS5cbiAgICAgICAgaWYgKCFBUFAueG1wcC5pc01vZGVyYXRvcigpKSB7XG4gICAgICAgICAgICBpZiAoc2hhcmVkS2V5KSB7XG4gICAgICAgICAgICAgICAgbWVzc2FnZUhhbmRsZXIub3Blbk1lc3NhZ2VEaWFsb2cobnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiVGhpcyBjb252ZXJzYXRpb24gaXMgY3VycmVudGx5IHByb3RlY3RlZCBieVwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiIGEgcGFzc3dvcmQuIE9ubHkgdGhlIG93bmVyIG9mIHRoZSBjb25mZXJlbmNlXCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgXCIgY291bGQgc2V0IGEgcGFzc3dvcmQuXCIsXG4gICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICBcIlBhc3N3b3JkXCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuTWVzc2FnZURpYWxvZyhudWxsLFxuICAgICAgICAgICAgICAgICAgICBcIlRoaXMgY29udmVyc2F0aW9uIGlzbid0IGN1cnJlbnRseSBwcm90ZWN0ZWQgYnlcIiArXG4gICAgICAgICAgICAgICAgICAgICAgICBcIiBhIHBhc3N3b3JkLiBPbmx5IHRoZSBvd25lciBvZiB0aGUgY29uZmVyZW5jZVwiICtcbiAgICAgICAgICAgICAgICAgICAgICAgIFwiIGNvdWxkIHNldCBhIHBhc3N3b3JkLlwiLFxuICAgICAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgXCJQYXNzd29yZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChzaGFyZWRLZXkpIHtcbiAgICAgICAgICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKG51bGwsXG4gICAgICAgICAgICAgICAgICAgIFwiQXJlIHlvdSBzdXJlIHlvdSB3b3VsZCBsaWtlIHRvIHJlbW92ZSB5b3VyIHBhc3N3b3JkP1wiLFxuICAgICAgICAgICAgICAgICAgICBmYWxzZSxcbiAgICAgICAgICAgICAgICAgICAgXCJSZW1vdmVcIixcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGUsIHYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh2KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgVG9vbGJhci5zZXRTaGFyZWRLZXkoJycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvY2tSb29tKGZhbHNlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2cobnVsbCxcbiAgICAgICAgICAgICAgICAgICAgJzxoMj5TZXQgYSBwYXNzd29yZCB0byBsb2NrIHlvdXIgcm9vbTwvaDI+JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAnPGlucHV0IGlkPVwibG9ja0tleVwiIHR5cGU9XCJ0ZXh0XCInICtcbiAgICAgICAgICAgICAgICAgICAgICAgICdwbGFjZWhvbGRlcj1cInlvdXIgcGFzc3dvcmRcIiBhdXRvZm9jdXM+JyxcbiAgICAgICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgICAgIFwiU2F2ZVwiLFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZSwgdikge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHYpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YXIgbG9ja0tleSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2NrS2V5Jyk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobG9ja0tleS52YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUb29sYmFyLnNldFNoYXJlZEtleShVSVV0aWwuZXNjYXBlSHRtbChsb2NrS2V5LnZhbHVlKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvY2tSb29tKHRydWUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xvY2tLZXknKS5mb2N1cygpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPcGVucyB0aGUgaW52aXRlIGxpbmsgZGlhbG9nLlxuICAgICAqL1xuICAgIG15Lm9wZW5MaW5rRGlhbG9nID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgaW52aXRlTGluaztcbiAgICAgICAgaWYgKHJvb21VcmwgPT09IG51bGwpIHtcbiAgICAgICAgICAgIGludml0ZUxpbmsgPSBcIllvdXIgY29uZmVyZW5jZSBpcyBjdXJyZW50bHkgYmVpbmcgY3JlYXRlZC4uLlwiO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaW52aXRlTGluayA9IGVuY29kZVVSSShyb29tVXJsKTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdlSGFuZGxlci5vcGVuVHdvQnV0dG9uRGlhbG9nKFxuICAgICAgICAgICAgXCJTaGFyZSB0aGlzIGxpbmsgd2l0aCBldmVyeW9uZSB5b3Ugd2FudCB0byBpbnZpdGVcIixcbiAgICAgICAgICAgICc8aW5wdXQgaWQ9XCJpbnZpdGVMaW5rUmVmXCIgdHlwZT1cInRleHRcIiB2YWx1ZT1cIicgK1xuICAgICAgICAgICAgICAgIGludml0ZUxpbmsgKyAnXCIgb25jbGljaz1cInRoaXMuc2VsZWN0KCk7XCIgcmVhZG9ubHk+JyxcbiAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgXCJJbnZpdGVcIixcbiAgICAgICAgICAgIGZ1bmN0aW9uIChlLCB2KSB7XG4gICAgICAgICAgICAgICAgaWYgKHYpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHJvb21VcmwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGludml0ZVBhcnRpY2lwYW50cygpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAocm9vbVVybCkge1xuICAgICAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnaW52aXRlTGlua1JlZicpLnNlbGVjdCgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdqcWlfc3RhdGUwX2J1dHRvbkludml0ZScpXG4gICAgICAgICAgICAgICAgICAgICAgICAuZGlzYWJsZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogT3BlbnMgdGhlIHNldHRpbmdzIGRpYWxvZy5cbiAgICAgKi9cbiAgICBteS5vcGVuU2V0dGluZ3NEaWFsb2cgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1lc3NhZ2VIYW5kbGVyLm9wZW5Ud29CdXR0b25EaWFsb2coXG4gICAgICAgICAgICAnPGgyPkNvbmZpZ3VyZSB5b3VyIGNvbmZlcmVuY2U8L2gyPicgK1xuICAgICAgICAgICAgICAgICc8aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgaWQ9XCJpbml0TXV0ZWRcIj4nICtcbiAgICAgICAgICAgICAgICAnUGFydGljaXBhbnRzIGpvaW4gbXV0ZWQ8YnIvPicgK1xuICAgICAgICAgICAgICAgICc8aW5wdXQgdHlwZT1cImNoZWNrYm94XCIgaWQ9XCJyZXF1aXJlTmlja25hbWVzXCI+JyArXG4gICAgICAgICAgICAgICAgJ1JlcXVpcmUgbmlja25hbWVzPGJyLz48YnIvPicgK1xuICAgICAgICAgICAgICAgICdTZXQgYSBwYXNzd29yZCB0byBsb2NrIHlvdXIgcm9vbTonICtcbiAgICAgICAgICAgICAgICAnPGlucHV0IGlkPVwibG9ja0tleVwiIHR5cGU9XCJ0ZXh0XCIgcGxhY2Vob2xkZXI9XCJ5b3VyIHBhc3N3b3JkXCInICtcbiAgICAgICAgICAgICAgICAnYXV0b2ZvY3VzPicsXG4gICAgICAgICAgICBudWxsLFxuICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICBcIlNhdmVcIixcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbG9ja0tleScpLmZvY3VzKCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKGUsIHYpIHtcbiAgICAgICAgICAgICAgICBpZiAodikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoJCgnI2luaXRNdXRlZCcpLmlzKFwiOmNoZWNrZWRcIikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGl0IGlzIGNoZWNrZWRcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGlmICgkKCcjcmVxdWlyZU5pY2tuYW1lcycpLmlzKFwiOmNoZWNrZWRcIikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGl0IGlzIGNoZWNrZWRcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvKlxuICAgICAgICAgICAgICAgICAgICB2YXIgbG9ja0tleSA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2NrS2V5Jyk7XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGxvY2tLZXkudmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNldFNoYXJlZEtleShsb2NrS2V5LnZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvY2tSb29tKHRydWUpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICovXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBUb2dnbGVzIHRoZSBhcHBsaWNhdGlvbiBpbiBhbmQgb3V0IG9mIGZ1bGwgc2NyZWVuIG1vZGVcbiAgICAgKiAoYS5rLmEuIHByZXNlbnRhdGlvbiBtb2RlIGluIENocm9tZSkuXG4gICAgICovXG4gICAgbXkudG9nZ2xlRnVsbFNjcmVlbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGZzRWxlbWVudCA9IGRvY3VtZW50LmRvY3VtZW50RWxlbWVudDtcblxuICAgICAgICBpZiAoIWRvY3VtZW50Lm1vekZ1bGxTY3JlZW4gJiYgIWRvY3VtZW50LndlYmtpdElzRnVsbFNjcmVlbikge1xuICAgICAgICAgICAgLy9FbnRlciBGdWxsIFNjcmVlblxuICAgICAgICAgICAgaWYgKGZzRWxlbWVudC5tb3pSZXF1ZXN0RnVsbFNjcmVlbikge1xuICAgICAgICAgICAgICAgIGZzRWxlbWVudC5tb3pSZXF1ZXN0RnVsbFNjcmVlbigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgZnNFbGVtZW50LndlYmtpdFJlcXVlc3RGdWxsU2NyZWVuKEVsZW1lbnQuQUxMT1dfS0VZQk9BUkRfSU5QVVQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgLy9FeGl0IEZ1bGwgU2NyZWVuXG4gICAgICAgICAgICBpZiAoZG9jdW1lbnQubW96Q2FuY2VsRnVsbFNjcmVlbikge1xuICAgICAgICAgICAgICAgIGRvY3VtZW50Lm1vekNhbmNlbEZ1bGxTY3JlZW4oKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgZG9jdW1lbnQud2Via2l0Q2FuY2VsRnVsbFNjcmVlbigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICAvKipcbiAgICAgKiBVbmxvY2tzIHRoZSBsb2NrIGJ1dHRvbiBzdGF0ZS5cbiAgICAgKi9cbiAgICBteS51bmxvY2tMb2NrQnV0dG9uID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoJChcIiNsb2NrSWNvblwiKS5oYXNDbGFzcyhcImljb24tc2VjdXJpdHktbG9ja2VkXCIpKVxuICAgICAgICAgICAgVUlVdGlsLmJ1dHRvbkNsaWNrKFwiI2xvY2tJY29uXCIsIFwiaWNvbi1zZWN1cml0eSBpY29uLXNlY3VyaXR5LWxvY2tlZFwiKTtcbiAgICB9O1xuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIGxvY2sgYnV0dG9uIHN0YXRlIHRvIGxvY2tlZC5cbiAgICAgKi9cbiAgICBteS5sb2NrTG9ja0J1dHRvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYgKCQoXCIjbG9ja0ljb25cIikuaGFzQ2xhc3MoXCJpY29uLXNlY3VyaXR5XCIpKVxuICAgICAgICAgICAgVUlVdGlsLmJ1dHRvbkNsaWNrKFwiI2xvY2tJY29uXCIsIFwiaWNvbi1zZWN1cml0eSBpY29uLXNlY3VyaXR5LWxvY2tlZFwiKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2hvd3Mgb3IgaGlkZXMgYXV0aGVudGljYXRpb24gYnV0dG9uXG4gICAgICogQHBhcmFtIHNob3cgPHR0PnRydWU8L3R0PiB0byBzaG93IG9yIDx0dD5mYWxzZTwvdHQ+IHRvIGhpZGVcbiAgICAgKi9cbiAgICBteS5zaG93QXV0aGVudGljYXRlQnV0dG9uID0gZnVuY3Rpb24gKHNob3cpIHtcbiAgICAgICAgaWYgKHNob3cpIHtcbiAgICAgICAgICAgICQoJyNhdXRoZW50aWNhdGlvbicpLmNzcyh7ZGlzcGxheTogXCJpbmxpbmVcIn0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgJCgnI2F1dGhlbnRpY2F0aW9uJykuY3NzKHtkaXNwbGF5OiBcIm5vbmVcIn0pO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8vIFNob3dzIG9yIGhpZGVzIHRoZSAncmVjb3JkaW5nJyBidXR0b24uXG4gICAgbXkuc2hvd1JlY29yZGluZ0J1dHRvbiA9IGZ1bmN0aW9uIChzaG93KSB7XG4gICAgICAgIGlmICghY29uZmlnLmVuYWJsZVJlY29yZGluZykge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHNob3cpIHtcbiAgICAgICAgICAgICQoJyNyZWNvcmRpbmcnKS5jc3Moe2Rpc3BsYXk6IFwiaW5saW5lXCJ9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICQoJyNyZWNvcmRpbmcnKS5jc3Moe2Rpc3BsYXk6IFwibm9uZVwifSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLy8gU2V0cyB0aGUgc3RhdGUgb2YgdGhlIHJlY29yZGluZyBidXR0b25cbiAgICBteS5zZXRSZWNvcmRpbmdCdXR0b25TdGF0ZSA9IGZ1bmN0aW9uIChpc1JlY29yZGluZykge1xuICAgICAgICBpZiAoaXNSZWNvcmRpbmcpIHtcbiAgICAgICAgICAgICQoJyNyZWNvcmRCdXR0b24nKS5yZW1vdmVDbGFzcyhcImljb24tcmVjRW5hYmxlXCIpO1xuICAgICAgICAgICAgJCgnI3JlY29yZEJ1dHRvbicpLmFkZENsYXNzKFwiaWNvbi1yZWNFbmFibGUgYWN0aXZlXCIpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgJCgnI3JlY29yZEJ1dHRvbicpLnJlbW92ZUNsYXNzKFwiaWNvbi1yZWNFbmFibGUgYWN0aXZlXCIpO1xuICAgICAgICAgICAgJCgnI3JlY29yZEJ1dHRvbicpLmFkZENsYXNzKFwiaWNvbi1yZWNFbmFibGVcIik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLy8gU2hvd3Mgb3IgaGlkZXMgU0lQIGNhbGxzIGJ1dHRvblxuICAgIG15LnNob3dTaXBDYWxsQnV0dG9uID0gZnVuY3Rpb24gKHNob3cpIHtcbiAgICAgICAgaWYgKEFQUC54bXBwLmlzU2lwR2F0ZXdheUVuYWJsZWQoKSAmJiBzaG93KSB7XG4gICAgICAgICAgICAkKCcjc2lwQ2FsbEJ1dHRvbicpLmNzcyh7ZGlzcGxheTogXCJpbmxpbmVcIn0pO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgJCgnI3NpcENhbGxCdXR0b24nKS5jc3Moe2Rpc3BsYXk6IFwibm9uZVwifSk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2V0cyB0aGUgc3RhdGUgb2YgdGhlIGJ1dHRvbi4gVGhlIGJ1dHRvbiBoYXMgYmx1ZSBnbG93IGlmIGRlc2t0b3BcbiAgICAgKiBzdHJlYW1pbmcgaXMgYWN0aXZlLlxuICAgICAqIEBwYXJhbSBhY3RpdmUgdGhlIHN0YXRlIG9mIHRoZSBkZXNrdG9wIHN0cmVhbWluZy5cbiAgICAgKi9cbiAgICBteS5jaGFuZ2VEZXNrdG9wU2hhcmluZ0J1dHRvblN0YXRlID0gZnVuY3Rpb24gKGFjdGl2ZSkge1xuICAgICAgICB2YXIgYnV0dG9uID0gJChcIiNkZXNrdG9wc2hhcmluZyA+IGFcIik7XG4gICAgICAgIGlmIChhY3RpdmUpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGJ1dHRvbi5hZGRDbGFzcyhcImdsb3dcIik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICB7XG4gICAgICAgICAgICBidXR0b24ucmVtb3ZlQ2xhc3MoXCJnbG93XCIpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIHJldHVybiBteTtcbn0oVG9vbGJhciB8fCB7fSkpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFRvb2xiYXI7IiwiLyogZ2xvYmFsICQsIGludGVyZmFjZUNvbmZpZywgTW9kZXJhdG9yLCBEZXNrdG9wU3RyZWFtaW5nLnNob3dEZXNrdG9wU2hhcmluZ0J1dHRvbiAqL1xuXG52YXIgdG9vbGJhclRpbWVvdXRPYmplY3QsXG4gICAgdG9vbGJhclRpbWVvdXQgPSBpbnRlcmZhY2VDb25maWcuSU5JVElBTF9UT09MQkFSX1RJTUVPVVQ7XG5cbmZ1bmN0aW9uIHNob3dEZXNrdG9wU2hhcmluZ0J1dHRvbigpIHtcbiAgICBpZiAoQVBQLmRlc2t0b3BzaGFyaW5nLmlzRGVza3RvcFNoYXJpbmdFbmFibGVkKCkpIHtcbiAgICAgICAgJCgnI2Rlc2t0b3BzaGFyaW5nJykuY3NzKHtkaXNwbGF5OiBcImlubGluZVwifSk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgJCgnI2Rlc2t0b3BzaGFyaW5nJykuY3NzKHtkaXNwbGF5OiBcIm5vbmVcIn0pO1xuICAgIH1cbn1cblxuLyoqXG4gKiBIaWRlcyB0aGUgdG9vbGJhci5cbiAqL1xuZnVuY3Rpb24gaGlkZVRvb2xiYXIoKSB7XG4gICAgdmFyIGhlYWRlciA9ICQoXCIjaGVhZGVyXCIpLFxuICAgICAgICBib3R0b21Ub29sYmFyID0gJChcIiNib3R0b21Ub29sYmFyXCIpO1xuICAgIHZhciBpc1Rvb2xiYXJIb3ZlciA9IGZhbHNlO1xuICAgIGhlYWRlci5maW5kKCcqJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBpZCA9ICQodGhpcykuYXR0cignaWQnKTtcbiAgICAgICAgaWYgKCQoXCIjXCIgKyBpZCArIFwiOmhvdmVyXCIpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIGlzVG9vbGJhckhvdmVyID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH0pO1xuICAgIGlmICgkKFwiI2JvdHRvbVRvb2xiYXI6aG92ZXJcIikubGVuZ3RoID4gMCkge1xuICAgICAgICBpc1Rvb2xiYXJIb3ZlciA9IHRydWU7XG4gICAgfVxuXG4gICAgY2xlYXJUaW1lb3V0KHRvb2xiYXJUaW1lb3V0T2JqZWN0KTtcbiAgICB0b29sYmFyVGltZW91dE9iamVjdCA9IG51bGw7XG5cbiAgICBpZiAoIWlzVG9vbGJhckhvdmVyKSB7XG4gICAgICAgIGhlYWRlci5oaWRlKFwic2xpZGVcIiwgeyBkaXJlY3Rpb246IFwidXBcIiwgZHVyYXRpb246IDMwMH0pO1xuICAgICAgICAkKCcjc3ViamVjdCcpLmFuaW1hdGUoe3RvcDogXCItPTQwXCJ9LCAzMDApO1xuICAgICAgICBpZiAoJChcIiNyZW1vdGVWaWRlb3NcIikuaGFzQ2xhc3MoXCJoaWRkZW5cIikpIHtcbiAgICAgICAgICAgIGJvdHRvbVRvb2xiYXIuaGlkZShcbiAgICAgICAgICAgICAgICBcInNsaWRlXCIsIHtkaXJlY3Rpb246IFwicmlnaHRcIiwgZHVyYXRpb246IDMwMH0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0b29sYmFyVGltZW91dE9iamVjdCA9IHNldFRpbWVvdXQoaGlkZVRvb2xiYXIsIHRvb2xiYXJUaW1lb3V0KTtcbiAgICB9XG59XG5cbnZhciBUb29sYmFyVG9nZ2xlciA9IHtcbiAgICAvKipcbiAgICAgKiBTaG93cyB0aGUgbWFpbiB0b29sYmFyLlxuICAgICAqL1xuICAgIHNob3dUb29sYmFyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBoZWFkZXIgPSAkKFwiI2hlYWRlclwiKSxcbiAgICAgICAgICAgIGJvdHRvbVRvb2xiYXIgPSAkKFwiI2JvdHRvbVRvb2xiYXJcIik7XG4gICAgICAgIGlmICghaGVhZGVyLmlzKCc6dmlzaWJsZScpIHx8ICFib3R0b21Ub29sYmFyLmlzKFwiOnZpc2libGVcIikpIHtcbiAgICAgICAgICAgIGhlYWRlci5zaG93KFwic2xpZGVcIiwgeyBkaXJlY3Rpb246IFwidXBcIiwgZHVyYXRpb246IDMwMH0pO1xuICAgICAgICAgICAgJCgnI3N1YmplY3QnKS5hbmltYXRlKHt0b3A6IFwiKz00MFwifSwgMzAwKTtcbiAgICAgICAgICAgIGlmICghYm90dG9tVG9vbGJhci5pcyhcIjp2aXNpYmxlXCIpKSB7XG4gICAgICAgICAgICAgICAgYm90dG9tVG9vbGJhci5zaG93KFxuICAgICAgICAgICAgICAgICAgICBcInNsaWRlXCIsIHtkaXJlY3Rpb246IFwicmlnaHRcIiwgZHVyYXRpb246IDMwMH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodG9vbGJhclRpbWVvdXRPYmplY3QpIHtcbiAgICAgICAgICAgICAgICBjbGVhclRpbWVvdXQodG9vbGJhclRpbWVvdXRPYmplY3QpO1xuICAgICAgICAgICAgICAgIHRvb2xiYXJUaW1lb3V0T2JqZWN0ID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRvb2xiYXJUaW1lb3V0T2JqZWN0ID0gc2V0VGltZW91dChoaWRlVG9vbGJhciwgdG9vbGJhclRpbWVvdXQpO1xuICAgICAgICAgICAgdG9vbGJhclRpbWVvdXQgPSBpbnRlcmZhY2VDb25maWcuVE9PTEJBUl9USU1FT1VUO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKEFQUC54bXBwLmlzTW9kZXJhdG9yKCkpXG4gICAgICAgIHtcbi8vICAgICAgICAgICAgVE9ETzogRW5hYmxlIHNldHRpbmdzIGZ1bmN0aW9uYWxpdHkuXG4vLyAgICAgICAgICAgICAgICAgIE5lZWQgdG8gdW5jb21tZW50IHRoZSBzZXR0aW5ncyBidXR0b24gaW4gaW5kZXguaHRtbC5cbi8vICAgICAgICAgICAgJCgnI3NldHRpbmdzQnV0dG9uJykuY3NzKHt2aXNpYmlsaXR5OlwidmlzaWJsZVwifSk7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBTaG93L2hpZGUgZGVza3RvcCBzaGFyaW5nIGJ1dHRvblxuICAgICAgICBzaG93RGVza3RvcFNoYXJpbmdCdXR0b24oKTtcbiAgICB9LFxuXG5cbiAgICAvKipcbiAgICAgKiBEb2Nrcy91bmRvY2tzIHRoZSB0b29sYmFyLlxuICAgICAqXG4gICAgICogQHBhcmFtIGlzRG9jayBpbmRpY2F0ZXMgd2hhdCBvcGVyYXRpb24gdG8gcGVyZm9ybVxuICAgICAqL1xuICAgIGRvY2tUb29sYmFyOiBmdW5jdGlvbiAoaXNEb2NrKSB7XG4gICAgICAgIGlmIChpc0RvY2spIHtcbiAgICAgICAgICAgIC8vIEZpcnN0IG1ha2Ugc3VyZSB0aGUgdG9vbGJhciBpcyBzaG93bi5cbiAgICAgICAgICAgIGlmICghJCgnI2hlYWRlcicpLmlzKCc6dmlzaWJsZScpKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zaG93VG9vbGJhcigpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBUaGVuIGNsZWFyIHRoZSB0aW1lIG91dCwgdG8gZG9jayB0aGUgdG9vbGJhci5cbiAgICAgICAgICAgIGlmICh0b29sYmFyVGltZW91dE9iamVjdCkge1xuICAgICAgICAgICAgICAgIGNsZWFyVGltZW91dCh0b29sYmFyVGltZW91dE9iamVjdCk7XG4gICAgICAgICAgICAgICAgdG9vbGJhclRpbWVvdXRPYmplY3QgPSBudWxsO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYgKCEkKCcjaGVhZGVyJykuaXMoJzp2aXNpYmxlJykpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNob3dUb29sYmFyKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICB0b29sYmFyVGltZW91dE9iamVjdCA9IHNldFRpbWVvdXQoaGlkZVRvb2xiYXIsIHRvb2xiYXJUaW1lb3V0KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG5cbiAgICBzaG93RGVza3RvcFNoYXJpbmdCdXR0b246IHNob3dEZXNrdG9wU2hhcmluZ0J1dHRvblxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFRvb2xiYXJUb2dnbGVyOyIsInZhciBKaXRzaVBvcG92ZXIgPSAoZnVuY3Rpb24gKCkge1xuICAgIC8qKlxuICAgICAqIENvbnN0cnVjdHMgbmV3IEppdHNpUG9wb3ZlciBhbmQgYXR0YWNoZXMgaXQgdG8gdGhlIGVsZW1lbnRcbiAgICAgKiBAcGFyYW0gZWxlbWVudCBqcXVlcnkgc2VsZWN0b3JcbiAgICAgKiBAcGFyYW0gb3B0aW9ucyB0aGUgb3B0aW9ucyBmb3IgdGhlIHBvcG92ZXIuXG4gICAgICogQGNvbnN0cnVjdG9yXG4gICAgICovXG4gICAgZnVuY3Rpb24gSml0c2lQb3BvdmVyKGVsZW1lbnQsIG9wdGlvbnMpXG4gICAge1xuICAgICAgICB0aGlzLm9wdGlvbnMgPSB7XG4gICAgICAgICAgICBza2luOiBcIndoaXRlXCIsXG4gICAgICAgICAgICBjb250ZW50OiBcIlwiXG4gICAgICAgIH07XG4gICAgICAgIGlmKG9wdGlvbnMpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGlmKG9wdGlvbnMuc2tpbilcbiAgICAgICAgICAgICAgICB0aGlzLm9wdGlvbnMuc2tpbiA9IG9wdGlvbnMuc2tpbjtcblxuICAgICAgICAgICAgaWYob3B0aW9ucy5jb250ZW50KVxuICAgICAgICAgICAgICAgIHRoaXMub3B0aW9ucy5jb250ZW50ID0gb3B0aW9ucy5jb250ZW50O1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5lbGVtZW50SXNIb3ZlcmVkID0gZmFsc2U7XG4gICAgICAgIHRoaXMucG9wb3ZlcklzSG92ZXJlZCA9IGZhbHNlO1xuICAgICAgICB0aGlzLnBvcG92ZXJTaG93biA9IGZhbHNlO1xuXG4gICAgICAgIGVsZW1lbnQuZGF0YShcImppdHNpX3BvcG92ZXJcIiwgdGhpcyk7XG4gICAgICAgIHRoaXMuZWxlbWVudCA9IGVsZW1lbnQ7XG4gICAgICAgIHRoaXMudGVtcGxhdGUgPSAnIDxkaXYgY2xhc3M9XCJqaXRzaXBvcG92ZXIgJyArIHRoaXMub3B0aW9ucy5za2luICtcbiAgICAgICAgICAgICdcIj48ZGl2IGNsYXNzPVwiYXJyb3dcIj48L2Rpdj48ZGl2IGNsYXNzPVwiaml0c2lwb3BvdmVyLWNvbnRlbnRcIj48L2Rpdj4nICtcbiAgICAgICAgICAgICc8ZGl2IGNsYXNzPVwiaml0c2lQb3B1cG1lbnVQYWRkaW5nXCI+PC9kaXY+PC9kaXY+JztcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICB0aGlzLmVsZW1lbnQub24oXCJtb3VzZWVudGVyXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlbGYuZWxlbWVudElzSG92ZXJlZCA9IHRydWU7XG4gICAgICAgICAgICBzZWxmLnNob3coKTtcbiAgICAgICAgfSkub24oXCJtb3VzZWxlYXZlXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlbGYuZWxlbWVudElzSG92ZXJlZCA9IGZhbHNlO1xuICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgc2VsZi5oaWRlKCk7XG4gICAgICAgICAgICB9LCAxMCk7XG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIC8qKlxuICAgICAqIFNob3dzIHRoZSBwb3BvdmVyXG4gICAgICovXG4gICAgSml0c2lQb3BvdmVyLnByb3RvdHlwZS5zaG93ID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB0aGlzLmNyZWF0ZVBvcG92ZXIoKTtcbiAgICAgICAgdGhpcy5wb3BvdmVyU2hvd24gPSB0cnVlO1xuXG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEhpZGVzIHRoZSBwb3BvdmVyXG4gICAgICovXG4gICAgSml0c2lQb3BvdmVyLnByb3RvdHlwZS5oaWRlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBpZighdGhpcy5lbGVtZW50SXNIb3ZlcmVkICYmICF0aGlzLnBvcG92ZXJJc0hvdmVyZWQgJiYgdGhpcy5wb3BvdmVyU2hvd24pXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMuZm9yY2VIaWRlKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogSGlkZXMgdGhlIHBvcG92ZXJcbiAgICAgKi9cbiAgICBKaXRzaVBvcG92ZXIucHJvdG90eXBlLmZvcmNlSGlkZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJChcIi5qaXRzaXBvcG92ZXJcIikucmVtb3ZlKCk7XG4gICAgICAgIHRoaXMucG9wb3ZlclNob3duID0gZmFsc2U7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgdGhlIHBvcG92ZXIgaHRtbFxuICAgICAqL1xuICAgIEppdHNpUG9wb3Zlci5wcm90b3R5cGUuY3JlYXRlUG9wb3ZlciA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJChcImJvZHlcIikuYXBwZW5kKHRoaXMudGVtcGxhdGUpO1xuICAgICAgICAkKFwiLmppdHNpcG9wb3ZlciA+IC5qaXRzaXBvcG92ZXItY29udGVudFwiKS5odG1sKHRoaXMub3B0aW9ucy5jb250ZW50KTtcbiAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAkKFwiLmppdHNpcG9wb3ZlclwiKS5vbihcIm1vdXNlZW50ZXJcIiwgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VsZi5wb3BvdmVySXNIb3ZlcmVkID0gdHJ1ZTtcbiAgICAgICAgfSkub24oXCJtb3VzZWxlYXZlXCIsIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlbGYucG9wb3ZlcklzSG92ZXJlZCA9IGZhbHNlO1xuICAgICAgICAgICAgc2VsZi5oaWRlKCk7XG4gICAgICAgIH0pO1xuXG4gICAgICAgIHRoaXMucmVmcmVzaFBvc2l0aW9uKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlZnJlc2hlcyB0aGUgcG9zaXRpb24gb2YgdGhlIHBvcG92ZXJcbiAgICAgKi9cbiAgICBKaXRzaVBvcG92ZXIucHJvdG90eXBlLnJlZnJlc2hQb3NpdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgJChcIi5qaXRzaXBvcG92ZXJcIikucG9zaXRpb24oe1xuICAgICAgICAgICAgbXk6IFwiYm90dG9tXCIsXG4gICAgICAgICAgICBhdDogXCJ0b3BcIixcbiAgICAgICAgICAgIGNvbGxpc2lvbjogXCJmaXRcIixcbiAgICAgICAgICAgIG9mOiB0aGlzLmVsZW1lbnQsXG4gICAgICAgICAgICB1c2luZzogZnVuY3Rpb24gKHBvc2l0aW9uLCBlbGVtZW50cykge1xuICAgICAgICAgICAgICAgIHZhciBjYWxjTGVmdCA9IGVsZW1lbnRzLnRhcmdldC5sZWZ0IC0gZWxlbWVudHMuZWxlbWVudC5sZWZ0ICsgZWxlbWVudHMudGFyZ2V0LndpZHRoLzI7XG4gICAgICAgICAgICAgICAgJChcIi5qaXRzaXBvcG92ZXJcIikuY3NzKHt0b3A6IHBvc2l0aW9uLnRvcCwgbGVmdDogcG9zaXRpb24ubGVmdCwgZGlzcGxheTogXCJ0YWJsZVwifSk7XG4gICAgICAgICAgICAgICAgJChcIi5qaXRzaXBvcG92ZXIgPiAuYXJyb3dcIikuY3NzKHtsZWZ0OiBjYWxjTGVmdH0pO1xuICAgICAgICAgICAgICAgICQoXCIuaml0c2lwb3BvdmVyID4gLmppdHNpUG9wdXBtZW51UGFkZGluZ1wiKS5jc3Moe2xlZnQ6IGNhbGNMZWZ0IC0gNTB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFVwZGF0ZXMgdGhlIGNvbnRlbnQgb2YgcG9wb3Zlci5cbiAgICAgKiBAcGFyYW0gY29udGVudCBuZXcgY29udGVudFxuICAgICAqL1xuICAgIEppdHNpUG9wb3Zlci5wcm90b3R5cGUudXBkYXRlQ29udGVudCA9IGZ1bmN0aW9uIChjb250ZW50KSB7XG4gICAgICAgIHRoaXMub3B0aW9ucy5jb250ZW50ID0gY29udGVudDtcbiAgICAgICAgaWYoIXRoaXMucG9wb3ZlclNob3duKVxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAkKFwiLmppdHNpcG9wb3ZlclwiKS5yZW1vdmUoKTtcbiAgICAgICAgdGhpcy5jcmVhdGVQb3BvdmVyKCk7XG4gICAgfTtcblxuICAgIHJldHVybiBKaXRzaVBvcG92ZXI7XG5cblxufSkoKTtcblxubW9kdWxlLmV4cG9ydHMgPSBKaXRzaVBvcG92ZXI7IiwiLyogZ2xvYmFsICQsIGpRdWVyeSAqL1xudmFyIG1lc3NhZ2VIYW5kbGVyID0gKGZ1bmN0aW9uKG15KSB7XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyBhIG1lc3NhZ2UgdG8gdGhlIHVzZXIuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdGl0bGVTdHJpbmcgdGhlIHRpdGxlIG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIG1lc3NhZ2VTdHJpbmcgdGhlIHRleHQgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKi9cbiAgICBteS5vcGVuTWVzc2FnZURpYWxvZyA9IGZ1bmN0aW9uKHRpdGxlU3RyaW5nLCBtZXNzYWdlU3RyaW5nKSB7XG4gICAgICAgICQucHJvbXB0KG1lc3NhZ2VTdHJpbmcsXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgdGl0bGU6IHRpdGxlU3RyaW5nLFxuICAgICAgICAgICAgICAgIHBlcnNpc3RlbnQ6IGZhbHNlXG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIGEgbWVzc2FnZSB0byB0aGUgdXNlciB3aXRoIHR3byBidXR0b25zOiBmaXJzdCBpcyBnaXZlbiBhcyBhIHBhcmFtZXRlciBhbmQgdGhlIHNlY29uZCBpcyBDYW5jZWwuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdGl0bGVTdHJpbmcgdGhlIHRpdGxlIG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIG1zZ1N0cmluZyB0aGUgdGV4dCBvZiB0aGUgbWVzc2FnZVxuICAgICAqIEBwYXJhbSBwZXJzaXN0ZW50IGJvb2xlYW4gdmFsdWUgd2hpY2ggZGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBtZXNzYWdlIGlzIHBlcnNpc3RlbnQgb3Igbm90XG4gICAgICogQHBhcmFtIGxlZnRCdXR0b24gdGhlIGZpc3QgYnV0dG9uJ3MgdGV4dFxuICAgICAqIEBwYXJhbSBzdWJtaXRGdW5jdGlvbiBmdW5jdGlvbiB0byBiZSBjYWxsZWQgb24gc3VibWl0XG4gICAgICogQHBhcmFtIGxvYWRlZEZ1bmN0aW9uIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgcHJvbXB0IGlzIGZ1bGx5IGxvYWRlZFxuICAgICAqIEBwYXJhbSBjbG9zZUZ1bmN0aW9uIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgcHJvbXB0IGlzIGNsb3NlZFxuICAgICAqL1xuICAgIG15Lm9wZW5Ud29CdXR0b25EaWFsb2cgPSBmdW5jdGlvbih0aXRsZVN0cmluZywgbXNnU3RyaW5nLCBwZXJzaXN0ZW50LCBsZWZ0QnV0dG9uLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWJtaXRGdW5jdGlvbiwgbG9hZGVkRnVuY3Rpb24sIGNsb3NlRnVuY3Rpb24pIHtcbiAgICAgICAgdmFyIGJ1dHRvbnMgPSB7fTtcbiAgICAgICAgYnV0dG9uc1tsZWZ0QnV0dG9uXSA9IHRydWU7XG4gICAgICAgIGJ1dHRvbnMuQ2FuY2VsID0gZmFsc2U7XG4gICAgICAgICQucHJvbXB0KG1zZ1N0cmluZywge1xuICAgICAgICAgICAgdGl0bGU6IHRpdGxlU3RyaW5nLFxuICAgICAgICAgICAgcGVyc2lzdGVudDogZmFsc2UsXG4gICAgICAgICAgICBidXR0b25zOiBidXR0b25zLFxuICAgICAgICAgICAgZGVmYXVsdEJ1dHRvbjogMSxcbiAgICAgICAgICAgIGxvYWRlZDogbG9hZGVkRnVuY3Rpb24sXG4gICAgICAgICAgICBzdWJtaXQ6IHN1Ym1pdEZ1bmN0aW9uLFxuICAgICAgICAgICAgY2xvc2U6IGNsb3NlRnVuY3Rpb25cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIGEgbWVzc2FnZSB0byB0aGUgdXNlciB3aXRoIHR3byBidXR0b25zOiBmaXJzdCBpcyBnaXZlbiBhcyBhIHBhcmFtZXRlciBhbmQgdGhlIHNlY29uZCBpcyBDYW5jZWwuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdGl0bGVTdHJpbmcgdGhlIHRpdGxlIG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIG1zZ1N0cmluZyB0aGUgdGV4dCBvZiB0aGUgbWVzc2FnZVxuICAgICAqIEBwYXJhbSBwZXJzaXN0ZW50IGJvb2xlYW4gdmFsdWUgd2hpY2ggZGV0ZXJtaW5lcyB3aGV0aGVyIHRoZSBtZXNzYWdlIGlzIHBlcnNpc3RlbnQgb3Igbm90XG4gICAgICogQHBhcmFtIGJ1dHRvbnMgb2JqZWN0IHdpdGggdGhlIGJ1dHRvbnMuIFRoZSBrZXlzIG11c3QgYmUgdGhlIG5hbWUgb2YgdGhlIGJ1dHRvbiBhbmQgdmFsdWUgaXMgdGhlIHZhbHVlXG4gICAgICogdGhhdCB3aWxsIGJlIHBhc3NlZCB0byBzdWJtaXRGdW5jdGlvblxuICAgICAqIEBwYXJhbSBzdWJtaXRGdW5jdGlvbiBmdW5jdGlvbiB0byBiZSBjYWxsZWQgb24gc3VibWl0XG4gICAgICogQHBhcmFtIGxvYWRlZEZ1bmN0aW9uIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCBhZnRlciB0aGUgcHJvbXB0IGlzIGZ1bGx5IGxvYWRlZFxuICAgICAqL1xuICAgIG15Lm9wZW5EaWFsb2cgPSBmdW5jdGlvbiAodGl0bGVTdHJpbmcsICAgIG1zZ1N0cmluZywgcGVyc2lzdGVudCwgYnV0dG9ucyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN1Ym1pdEZ1bmN0aW9uLCBsb2FkZWRGdW5jdGlvbikge1xuICAgICAgICB2YXIgYXJncyA9IHtcbiAgICAgICAgICAgIHRpdGxlOiB0aXRsZVN0cmluZyxcbiAgICAgICAgICAgIHBlcnNpc3RlbnQ6IHBlcnNpc3RlbnQsXG4gICAgICAgICAgICBidXR0b25zOiBidXR0b25zLFxuICAgICAgICAgICAgZGVmYXVsdEJ1dHRvbjogMSxcbiAgICAgICAgICAgIGxvYWRlZDogbG9hZGVkRnVuY3Rpb24sXG4gICAgICAgICAgICBzdWJtaXQ6IHN1Ym1pdEZ1bmN0aW9uXG4gICAgICAgIH07XG4gICAgICAgIGlmIChwZXJzaXN0ZW50KSB7XG4gICAgICAgICAgICBhcmdzLmNsb3NlVGV4dCA9ICcnO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiAkLnByb21wdChtc2dTdHJpbmcsIGFyZ3MpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDbG9zZXMgY3VycmVudGx5IG9wZW5lZCBkaWFsb2cuXG4gICAgICovXG4gICAgbXkuY2xvc2VEaWFsb2cgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICQucHJvbXB0LmNsb3NlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIGEgZGlhbG9nIHdpdGggZGlmZmVyZW50IHN0YXRlcyB0byB0aGUgdXNlci5cbiAgICAgKlxuICAgICAqIEBwYXJhbSBzdGF0ZXNPYmplY3Qgb2JqZWN0IGNvbnRhaW5pbmcgYWxsIHRoZSBzdGF0ZXMgb2YgdGhlIGRpYWxvZ1xuICAgICAqIEBwYXJhbSBsb2FkZWRGdW5jdGlvbiBmdW5jdGlvbiB0byBiZSBjYWxsZWQgYWZ0ZXIgdGhlIHByb21wdCBpcyBmdWxseSBsb2FkZWRcbiAgICAgKiBAcGFyYW0gc3RhdGVDaGFuZ2VkRnVuY3Rpb24gZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW4gdGhlIHN0YXRlIG9mIHRoZSBkaWFsb2cgaXMgY2hhbmdlZFxuICAgICAqL1xuICAgIG15Lm9wZW5EaWFsb2dXaXRoU3RhdGVzID0gZnVuY3Rpb24oc3RhdGVzT2JqZWN0LCBsb2FkZWRGdW5jdGlvbiwgc3RhdGVDaGFuZ2VkRnVuY3Rpb24pIHtcblxuXG4gICAgICAgIHZhciBteVByb21wdCA9ICQucHJvbXB0KHN0YXRlc09iamVjdCk7XG5cbiAgICAgICAgbXlQcm9tcHQub24oJ2ltcHJvbXB0dTpsb2FkZWQnLCBsb2FkZWRGdW5jdGlvbik7XG4gICAgICAgIG15UHJvbXB0Lm9uKCdpbXByb21wdHU6c3RhdGVjaGFuZ2VkJywgc3RhdGVDaGFuZ2VkRnVuY3Rpb24pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPcGVucyBuZXcgcG9wdXAgd2luZG93IGZvciBnaXZlbiA8dHQ+dXJsPC90dD4gY2VudGVyZWQgb3ZlciBjdXJyZW50XG4gICAgICogd2luZG93LlxuICAgICAqXG4gICAgICogQHBhcmFtIHVybCB0aGUgVVJMIHRvIGJlIGRpc3BsYXllZCBpbiB0aGUgcG9wdXAgd2luZG93XG4gICAgICogQHBhcmFtIHcgdGhlIHdpZHRoIG9mIHRoZSBwb3B1cCB3aW5kb3dcbiAgICAgKiBAcGFyYW0gaCB0aGUgaGVpZ2h0IG9mIHRoZSBwb3B1cCB3aW5kb3dcbiAgICAgKiBAcGFyYW0gb25Qb3B1cENsb3NlZCBvcHRpb25hbCBjYWxsYmFjayBmdW5jdGlvbiBjYWxsZWQgd2hlbiBwb3B1cCB3aW5kb3dcbiAgICAgKiAgICAgICAgaGFzIGJlZW4gY2xvc2VkLlxuICAgICAqXG4gICAgICogQHJldHVybnMgcG9wdXAgd2luZG93IG9iamVjdCBpZiBvcGVuZWQgc3VjY2Vzc2Z1bGx5IG9yIHVuZGVmaW5lZFxuICAgICAqICAgICAgICAgIGluIGNhc2Ugd2UgZmFpbGVkIHRvIG9wZW4gaXQocG9wdXAgYmxvY2tlZClcbiAgICAgKi9cbiAgICBteS5vcGVuQ2VudGVyZWRQb3B1cCA9IGZ1bmN0aW9uICh1cmwsIHcsIGgsIG9uUG9wdXBDbG9zZWQpIHtcbiAgICAgICAgdmFyIGwgPSB3aW5kb3cuc2NyZWVuWCArICh3aW5kb3cuaW5uZXJXaWR0aCAvIDIpIC0gKHcgLyAyKTtcbiAgICAgICAgdmFyIHQgPSB3aW5kb3cuc2NyZWVuWSArICh3aW5kb3cuaW5uZXJIZWlnaHQgLyAyKSAtIChoIC8gMik7XG4gICAgICAgIHZhciBwb3B1cCA9IHdpbmRvdy5vcGVuKFxuICAgICAgICAgICAgdXJsLCAnX2JsYW5rJyxcbiAgICAgICAgICAgICd0b3A9JyArIHQgKyAnLCBsZWZ0PScgKyBsICsgJywgd2lkdGg9JyArIHcgKyAnLCBoZWlnaHQ9JyArIGggKyAnJyk7XG4gICAgICAgIGlmIChwb3B1cCAmJiBvblBvcHVwQ2xvc2VkKSB7XG4gICAgICAgICAgICB2YXIgcG9sbFRpbWVyID0gd2luZG93LnNldEludGVydmFsKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAocG9wdXAuY2xvc2VkICE9PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbChwb2xsVGltZXIpO1xuICAgICAgICAgICAgICAgICAgICBvblBvcHVwQ2xvc2VkKCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSwgMjAwKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gcG9wdXA7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIGEgZGlhbG9nIHByb21wdGluZyB0aGUgdXNlciB0byBzZW5kIGFuIGVycm9yIHJlcG9ydC5cbiAgICAgKlxuICAgICAqIEBwYXJhbSB0aXRsZVN0cmluZyB0aGUgdGl0bGUgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gbXNnU3RyaW5nIHRoZSB0ZXh0IG9mIHRoZSBtZXNzYWdlXG4gICAgICogQHBhcmFtIGVycm9yIHRoZSBlcnJvciB0aGF0IGlzIGJlaW5nIHJlcG9ydGVkXG4gICAgICovXG4gICAgbXkub3BlblJlcG9ydERpYWxvZyA9IGZ1bmN0aW9uKHRpdGxlU3RyaW5nLCBtc2dTdHJpbmcsIGVycm9yKSB7XG4gICAgICAgIG15Lm9wZW5NZXNzYWdlRGlhbG9nKHRpdGxlU3RyaW5nLCBtc2dTdHJpbmcpO1xuICAgICAgICBjb25zb2xlLmxvZyhlcnJvcik7XG4gICAgICAgIC8vRklYTUUgc2VuZCB0aGUgZXJyb3IgdG8gdGhlIHNlcnZlclxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiAgU2hvd3MgYW4gZXJyb3IgZGlhbG9nIHRvIHRoZSB1c2VyLlxuICAgICAqIEBwYXJhbSB0aXRsZSB0aGUgdGl0bGUgb2YgdGhlIG1lc3NhZ2VcbiAgICAgKiBAcGFyYW0gbWVzc2FnZSB0aGUgdGV4dCBvZiB0aGUgbWVzc2FmZVxuICAgICAqL1xuICAgIG15LnNob3dFcnJvciA9IGZ1bmN0aW9uKHRpdGxlLCBtZXNzYWdlKSB7XG4gICAgICAgIGlmKCEodGl0bGUgfHwgbWVzc2FnZSkpIHtcbiAgICAgICAgICAgIHRpdGxlID0gdGl0bGUgfHwgXCJPb3BzIVwiO1xuICAgICAgICAgICAgbWVzc2FnZSA9IG1lc3NhZ2UgfHwgXCJUaGVyZSB3YXMgc29tZSBraW5kIG9mIGVycm9yXCI7XG4gICAgICAgIH1cbiAgICAgICAgbWVzc2FnZUhhbmRsZXIub3Blbk1lc3NhZ2VEaWFsb2codGl0bGUsIG1lc3NhZ2UpO1xuICAgIH07XG5cbiAgICBteS5ub3RpZnkgPSBmdW5jdGlvbihkaXNwbGF5TmFtZSwgY2xzLCBtZXNzYWdlKSB7XG4gICAgICAgIHRvYXN0ci5pbmZvKFxuICAgICAgICAgICAgJzxzcGFuIGNsYXNzPVwibmlja25hbWVcIj4nICtcbiAgICAgICAgICAgICAgICBkaXNwbGF5TmFtZSArXG4gICAgICAgICAgICAnPC9zcGFuPjxicj4nICtcbiAgICAgICAgICAgICc8c3BhbiBjbGFzcz0nICsgY2xzICsgJz4nICtcbiAgICAgICAgICAgICAgICBtZXNzYWdlICtcbiAgICAgICAgICAgICc8L3NwYW4+Jyk7XG4gICAgfTtcblxuICAgIHJldHVybiBteTtcbn0obWVzc2FnZUhhbmRsZXIgfHwge30pKTtcblxubW9kdWxlLmV4cG9ydHMgPSBtZXNzYWdlSGFuZGxlcjtcblxuXG4iLCJ2YXIgVUlFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vLi4vc2VydmljZS9VSS9VSUV2ZW50c1wiKTtcblxudmFyIG5pY2tuYW1lID0gbnVsbDtcbnZhciBldmVudEVtaXR0ZXIgPSBudWxsO1xuXG52YXIgTmlja2FuYW1lSGFuZGxlciA9IHtcbiAgICBpbml0OiBmdW5jdGlvbiAoZW1pdHRlcikge1xuICAgICAgICBldmVudEVtaXR0ZXIgPSBlbWl0dGVyO1xuICAgICAgICB2YXIgc3RvcmVkRGlzcGxheU5hbWUgPSB3aW5kb3cubG9jYWxTdG9yYWdlLmRpc3BsYXluYW1lO1xuICAgICAgICBpZiAoc3RvcmVkRGlzcGxheU5hbWUpIHtcbiAgICAgICAgICAgIG5pY2tuYW1lID0gc3RvcmVkRGlzcGxheU5hbWU7XG4gICAgICAgIH1cbiAgICB9LFxuICAgIHNldE5pY2tuYW1lOiBmdW5jdGlvbiAobmV3Tmlja25hbWUpIHtcbiAgICAgICAgaWYgKCFuZXdOaWNrbmFtZSB8fCBuaWNrbmFtZSA9PT0gbmV3Tmlja25hbWUpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgbmlja25hbWUgPSBuZXdOaWNrbmFtZTtcbiAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS5kaXNwbGF5bmFtZSA9IG5pY2tuYW1lO1xuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChVSUV2ZW50cy5OSUNLTkFNRV9DSEFOR0VELCBuZXdOaWNrbmFtZSk7XG4gICAgfSxcbiAgICBnZXROaWNrbmFtZTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gbmlja25hbWU7XG4gICAgfSxcbiAgICBhZGRMaXN0ZW5lcjogZnVuY3Rpb24gKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5vbih0eXBlLCBsaXN0ZW5lcik7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBOaWNrYW5hbWVIYW5kbGVyOyIsIi8qKlxuICogQ3JlYXRlZCBieSBocmlzdG8gb24gMTIvMjIvMTQuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGF2YWlsYWJsZSB2aWRlbyB3aWR0aC5cbiAgICAgKi9cbiAgICBnZXRBdmFpbGFibGVWaWRlb1dpZHRoOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBQYW5lbFRvZ2dsZXIgPSByZXF1aXJlKFwiLi4vc2lkZV9wYW5uZWxzL1NpZGVQYW5lbFRvZ2dsZXJcIik7XG4gICAgICAgIHZhciByaWdodFBhbmVsV2lkdGhcbiAgICAgICAgICAgID0gUGFuZWxUb2dnbGVyLmlzVmlzaWJsZSgpID8gUGFuZWxUb2dnbGVyLmdldFBhbmVsU2l6ZSgpWzBdIDogMDtcblxuICAgICAgICByZXR1cm4gd2luZG93LmlubmVyV2lkdGggLSByaWdodFBhbmVsV2lkdGg7XG4gICAgfSxcbiAgICAvKipcbiAgICAgKiBDaGFuZ2VzIHRoZSBzdHlsZSBjbGFzcyBvZiB0aGUgZWxlbWVudCBnaXZlbiBieSBpZC5cbiAgICAgKi9cbiAgICBidXR0b25DbGljazogZnVuY3Rpb24oaWQsIGNsYXNzbmFtZSkge1xuICAgICAgICAkKGlkKS50b2dnbGVDbGFzcyhjbGFzc25hbWUpOyAvLyBhZGQgdGhlIGNsYXNzIHRvIHRoZSBjbGlja2VkIGVsZW1lbnRcbiAgICB9LFxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIHRleHQgd2lkdGggZm9yIHRoZSBnaXZlbiBlbGVtZW50LlxuICAgICAqXG4gICAgICogQHBhcmFtIGVsIHRoZSBlbGVtZW50XG4gICAgICovXG4gICAgZ2V0VGV4dFdpZHRoOiBmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgcmV0dXJuIChlbC5jbGllbnRXaWR0aCArIDEpO1xuICAgIH0sXG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSB0ZXh0IGhlaWdodCBmb3IgdGhlIGdpdmVuIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gZWwgdGhlIGVsZW1lbnRcbiAgICAgKi9cbiAgICBnZXRUZXh0SGVpZ2h0OiBmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgcmV0dXJuIChlbC5jbGllbnRIZWlnaHQgKyAxKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogUGxheXMgdGhlIHNvdW5kIGdpdmVuIGJ5IGlkLlxuICAgICAqXG4gICAgICogQHBhcmFtIGlkIHRoZSBpZGVudGlmaWVyIG9mIHRoZSBhdWRpbyBlbGVtZW50LlxuICAgICAqL1xuICAgIHBsYXlTb3VuZE5vdGlmaWNhdGlvbjogZnVuY3Rpb24gKGlkKSB7XG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKGlkKS5wbGF5KCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEVzY2FwZXMgdGhlIGdpdmVuIHRleHQuXG4gICAgICovXG4gICAgZXNjYXBlSHRtbDogZnVuY3Rpb24gKHVuc2FmZVRleHQpIHtcbiAgICAgICAgcmV0dXJuICQoJzxkaXYvPicpLnRleHQodW5zYWZlVGV4dCkuaHRtbCgpO1xuICAgIH0sXG5cbiAgICBpbWFnZVRvR3JheVNjYWxlOiBmdW5jdGlvbiAoY2FudmFzKSB7XG4gICAgICAgIHZhciBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoJzJkJyk7XG4gICAgICAgIHZhciBpbWdEYXRhID0gY29udGV4dC5nZXRJbWFnZURhdGEoMCwgMCwgY2FudmFzLndpZHRoLCBjYW52YXMuaGVpZ2h0KTtcbiAgICAgICAgdmFyIHBpeGVscyAgPSBpbWdEYXRhLmRhdGE7XG5cbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIG4gPSBwaXhlbHMubGVuZ3RoOyBpIDwgbjsgaSArPSA0KSB7XG4gICAgICAgICAgICB2YXIgZ3JheXNjYWxlXG4gICAgICAgICAgICAgICAgPSBwaXhlbHNbaV0gKiAuMyArIHBpeGVsc1tpKzFdICogLjU5ICsgcGl4ZWxzW2krMl0gKiAuMTE7XG4gICAgICAgICAgICBwaXhlbHNbaSAgXSA9IGdyYXlzY2FsZTsgICAgICAgIC8vIHJlZFxuICAgICAgICAgICAgcGl4ZWxzW2krMV0gPSBncmF5c2NhbGU7ICAgICAgICAvLyBncmVlblxuICAgICAgICAgICAgcGl4ZWxzW2krMl0gPSBncmF5c2NhbGU7ICAgICAgICAvLyBibHVlXG4gICAgICAgICAgICAvLyBwaXhlbHNbaSszXSAgICAgICAgICAgICAgaXMgYWxwaGFcbiAgICAgICAgfVxuICAgICAgICAvLyByZWRyYXcgdGhlIGltYWdlIGluIGJsYWNrICYgd2hpdGVcbiAgICAgICAgY29udGV4dC5wdXRJbWFnZURhdGEoaW1nRGF0YSwgMCwgMCk7XG4gICAgfSxcblxuICAgIHNldFRvb2x0aXA6IGZ1bmN0aW9uIChlbGVtZW50LCBrZXksIHBvc2l0aW9uKSB7XG4gICAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKFwiZGF0YS1pMThuXCIsIFwiW2RhdGEtY29udGVudF1cIiArIGtleSk7XG4gICAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKFwiZGF0YS10b2dnbGVcIiwgXCJwb3BvdmVyXCIpO1xuICAgICAgICBlbGVtZW50LnNldEF0dHJpYnV0ZShcImRhdGEtcGxhY2VtZW50XCIsIHBvc2l0aW9uKTtcbiAgICAgICAgZWxlbWVudC5zZXRBdHRyaWJ1dGUoXCJkYXRhLWh0bWxcIiwgdHJ1ZSk7XG4gICAgICAgIGVsZW1lbnQuc2V0QXR0cmlidXRlKFwiZGF0YS1jb250YWluZXJcIiwgXCJib2R5XCIpO1xuICAgIH1cblxuXG59OyIsInZhciBKaXRzaVBvcG92ZXIgPSByZXF1aXJlKFwiLi4vdXRpbC9KaXRzaVBvcG92ZXJcIik7XG5cbi8qKlxuICogQ29uc3RydWN0cyBuZXcgY29ubmVjdGlvbiBpbmRpY2F0b3IuXG4gKiBAcGFyYW0gdmlkZW9Db250YWluZXIgdGhlIHZpZGVvIGNvbnRhaW5lciBhc3NvY2lhdGVkIHdpdGggdGhlIGluZGljYXRvci5cbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBDb25uZWN0aW9uSW5kaWNhdG9yKHZpZGVvQ29udGFpbmVyLCBqaWQsIFZpZGVvTGF5b3V0KVxue1xuICAgIHRoaXMudmlkZW9Db250YWluZXIgPSB2aWRlb0NvbnRhaW5lcjtcbiAgICB0aGlzLmJhbmR3aWR0aCA9IG51bGw7XG4gICAgdGhpcy5wYWNrZXRMb3NzID0gbnVsbDtcbiAgICB0aGlzLmJpdHJhdGUgPSBudWxsO1xuICAgIHRoaXMuc2hvd01vcmVWYWx1ZSA9IGZhbHNlO1xuICAgIHRoaXMucmVzb2x1dGlvbiA9IG51bGw7XG4gICAgdGhpcy50cmFuc3BvcnQgPSBbXTtcbiAgICB0aGlzLnBvcG92ZXIgPSBudWxsO1xuICAgIHRoaXMuamlkID0gamlkO1xuICAgIHRoaXMuY3JlYXRlKCk7XG4gICAgdGhpcy52aWRlb0xheW91dCA9IFZpZGVvTGF5b3V0O1xufVxuXG4vKipcbiAqIFZhbHVlcyBmb3IgdGhlIGNvbm5lY3Rpb24gcXVhbGl0eVxuICogQHR5cGUge3s5ODogc3RyaW5nLFxuICogICAgICAgICA4MTogc3RyaW5nLFxuICogICAgICAgICA2NDogc3RyaW5nLFxuICogICAgICAgICA0Nzogc3RyaW5nLFxuICogICAgICAgICAzMDogc3RyaW5nLFxuICogICAgICAgICAwOiBzdHJpbmd9fVxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLmNvbm5lY3Rpb25RdWFsaXR5VmFsdWVzID0ge1xuICAgIDk4OiBcIjE4cHhcIiwgLy9mdWxsXG4gICAgODE6IFwiMTVweFwiLC8vNCBiYXJzXG4gICAgNjQ6IFwiMTFweFwiLC8vMyBiYXJzXG4gICAgNDc6IFwiN3B4XCIsLy8yIGJhcnNcbiAgICAzMDogXCIzcHhcIiwvLzEgYmFyXG4gICAgMDogXCIwcHhcIi8vZW1wdHlcbn07XG5cbkNvbm5lY3Rpb25JbmRpY2F0b3IuZ2V0SVAgPSBmdW5jdGlvbih2YWx1ZSlcbntcbiAgICByZXR1cm4gdmFsdWUuc3Vic3RyaW5nKDAsIHZhbHVlLmxhc3RJbmRleE9mKFwiOlwiKSk7XG59O1xuXG5Db25uZWN0aW9uSW5kaWNhdG9yLmdldFBvcnQgPSBmdW5jdGlvbih2YWx1ZSlcbntcbiAgICByZXR1cm4gdmFsdWUuc3Vic3RyaW5nKHZhbHVlLmxhc3RJbmRleE9mKFwiOlwiKSArIDEsIHZhbHVlLmxlbmd0aCk7XG59O1xuXG5Db25uZWN0aW9uSW5kaWNhdG9yLmdldFN0cmluZ0Zyb21BcnJheSA9IGZ1bmN0aW9uIChhcnJheSkge1xuICAgIHZhciByZXMgPSBcIlwiO1xuICAgIGZvcih2YXIgaSA9IDA7IGkgPCBhcnJheS5sZW5ndGg7IGkrKylcbiAgICB7XG4gICAgICAgIHJlcyArPSAoaSA9PT0gMD8gXCJcIiA6IFwiLCBcIikgKyBhcnJheVtpXTtcbiAgICB9XG4gICAgcmV0dXJuIHJlcztcbn07XG5cbi8qKlxuICogR2VuZXJhdGVzIHRoZSBodG1sIGNvbnRlbnQuXG4gKiBAcmV0dXJucyB7c3RyaW5nfSB0aGUgaHRtbCBjb250ZW50LlxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5nZW5lcmF0ZVRleHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGRvd25sb2FkQml0cmF0ZSwgdXBsb2FkQml0cmF0ZSwgcGFja2V0TG9zcywgcmVzb2x1dGlvbiwgaTtcblxuICAgIHZhciB0cmFuc2xhdGUgPSBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlU3RyaW5nO1xuXG4gICAgaWYodGhpcy5iaXRyYXRlID09PSBudWxsKVxuICAgIHtcbiAgICAgICAgZG93bmxvYWRCaXRyYXRlID0gXCJOL0FcIjtcbiAgICAgICAgdXBsb2FkQml0cmF0ZSA9IFwiTi9BXCI7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIGRvd25sb2FkQml0cmF0ZSA9XG4gICAgICAgICAgICB0aGlzLmJpdHJhdGUuZG93bmxvYWQ/IHRoaXMuYml0cmF0ZS5kb3dubG9hZCArIFwiIEticHNcIiA6IFwiTi9BXCI7XG4gICAgICAgIHVwbG9hZEJpdHJhdGUgPVxuICAgICAgICAgICAgdGhpcy5iaXRyYXRlLnVwbG9hZD8gdGhpcy5iaXRyYXRlLnVwbG9hZCArIFwiIEticHNcIiA6IFwiTi9BXCI7XG4gICAgfVxuXG4gICAgaWYodGhpcy5wYWNrZXRMb3NzID09PSBudWxsKVxuICAgIHtcbiAgICAgICAgcGFja2V0TG9zcyA9IFwiTi9BXCI7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG5cbiAgICAgICAgcGFja2V0TG9zcyA9IFwiPHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ncmVlbic+JmRhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgICAgICh0aGlzLnBhY2tldExvc3MuZG93bmxvYWQgIT09IG51bGw/IHRoaXMucGFja2V0TG9zcy5kb3dubG9hZCA6IFwiTi9BXCIpICtcbiAgICAgICAgICAgIFwiJSA8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX29yYW5nZSc+JnVhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgICAgICh0aGlzLnBhY2tldExvc3MudXBsb2FkICE9PSBudWxsPyB0aGlzLnBhY2tldExvc3MudXBsb2FkIDogXCJOL0FcIikgKyBcIiVcIjtcbiAgICB9XG5cbiAgICB2YXIgcmVzb2x1dGlvblZhbHVlID0gbnVsbDtcbiAgICBpZih0aGlzLnJlc29sdXRpb24gJiYgdGhpcy5qaWQgIT0gbnVsbClcbiAgICB7XG4gICAgICAgIHZhciBrZXlzID0gT2JqZWN0LmtleXModGhpcy5yZXNvbHV0aW9uKTtcbiAgICAgICAgaWYoa2V5cy5sZW5ndGggPT0gMSlcbiAgICAgICAge1xuICAgICAgICAgICAgZm9yKHZhciBzc3JjIGluIHRoaXMucmVzb2x1dGlvbilcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSB0aGlzLnJlc29sdXRpb25bc3NyY107XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSBpZihrZXlzLmxlbmd0aCA+IDEpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhciBkaXNwbGF5ZWRTc3JjID0gQVBQLnNpbXVsY2FzdC5nZXRSZWNlaXZpbmdTU1JDKHRoaXMuamlkKTtcbiAgICAgICAgICAgIHJlc29sdXRpb25WYWx1ZSA9IHRoaXMucmVzb2x1dGlvbltkaXNwbGF5ZWRTc3JjXTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIGlmKHRoaXMuamlkID09PSBudWxsKVxuICAgIHtcbiAgICAgICAgcmVzb2x1dGlvbiA9IFwiXCI7XG4gICAgICAgIGlmKHRoaXMucmVzb2x1dGlvbiA9PT0gbnVsbCB8fCAhT2JqZWN0LmtleXModGhpcy5yZXNvbHV0aW9uKSB8fFxuICAgICAgICAgICAgT2JqZWN0LmtleXModGhpcy5yZXNvbHV0aW9uKS5sZW5ndGggPT09IDApXG4gICAgICAgIHtcbiAgICAgICAgICAgIHJlc29sdXRpb24gPSBcIk4vQVwiO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIGZvcihpIGluIHRoaXMucmVzb2x1dGlvbilcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXNvbHV0aW9uVmFsdWUgPSB0aGlzLnJlc29sdXRpb25baV07XG4gICAgICAgICAgICAgICAgaWYocmVzb2x1dGlvblZhbHVlKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgaWYocmVzb2x1dGlvblZhbHVlLmhlaWdodCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvblZhbHVlLndpZHRoKVxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXNvbHV0aW9uICs9IChyZXNvbHV0aW9uID09PSBcIlwiPyBcIlwiIDogXCIsIFwiKSArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb2x1dGlvblZhbHVlLndpZHRoICsgXCJ4XCIgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHJlc29sdXRpb25WYWx1ZS5oZWlnaHQ7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgfVxuICAgIGVsc2UgaWYoIXJlc29sdXRpb25WYWx1ZSB8fFxuICAgICAgICAhcmVzb2x1dGlvblZhbHVlLmhlaWdodCB8fFxuICAgICAgICAhcmVzb2x1dGlvblZhbHVlLndpZHRoKVxuICAgIHtcbiAgICAgICAgcmVzb2x1dGlvbiA9IFwiTi9BXCI7XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIHJlc29sdXRpb24gPSByZXNvbHV0aW9uVmFsdWUud2lkdGggKyBcInhcIiArIHJlc29sdXRpb25WYWx1ZS5oZWlnaHQ7XG4gICAgfVxuXG4gICAgdmFyIHJlc3VsdCA9IFwiPHRhYmxlIHN0eWxlPSd3aWR0aDoxMDAlJz5cIiArXG4gICAgICAgIFwiPHRyPlwiICtcbiAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJyBkYXRhLWkxOG49J2Nvbm5lY3Rpb25pbmRpY2F0b3IuYml0cmF0ZSc+XCIgK1xuICAgICAgICB0cmFuc2xhdGUoXCJjb25uZWN0aW9uaW5kaWNhdG9yLmJpdHJhdGVcIikgKyBcIjwvc3Bhbj48L3RkPlwiICtcbiAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ncmVlbic+JmRhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgZG93bmxvYWRCaXRyYXRlICsgXCIgPHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9vcmFuZ2UnPiZ1YXJyOzwvc3Bhbj5cIiArXG4gICAgICAgIHVwbG9hZEJpdHJhdGUgKyBcIjwvdGQ+XCIgK1xuICAgICAgICBcIjwvdHI+PHRyPlwiICtcbiAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJyBkYXRhLWkxOG49J2Nvbm5lY3Rpb25pbmRpY2F0b3IucGFja2V0bG9zcyc+XCIgK1xuICAgICAgICB0cmFuc2xhdGUoXCJjb25uZWN0aW9uaW5kaWNhdG9yLnBhY2tldGxvc3NcIikgKyBcIjwvc3Bhbj48L3RkPlwiICtcbiAgICAgICAgXCI8dGQ+XCIgKyBwYWNrZXRMb3NzICArIFwiPC90ZD5cIiArXG4gICAgICAgIFwiPC90cj48dHI+XCIgK1xuICAgICAgICBcIjx0ZD48c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnIGRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5yZXNvbHV0aW9uJz5cIiArXG4gICAgICAgIHRyYW5zbGF0ZShcImNvbm5lY3Rpb25pbmRpY2F0b3IucmVzb2x1dGlvblwiKSArIFwiPC9zcGFuPjwvdGQ+XCIgK1xuICAgICAgICBcIjx0ZD5cIiArIHJlc29sdXRpb24gKyBcIjwvdGQ+PC90cj48L3RhYmxlPlwiO1xuXG4gICAgaWYodGhpcy52aWRlb0NvbnRhaW5lci5pZCA9PSBcImxvY2FsVmlkZW9Db250YWluZXJcIikge1xuICAgICAgICByZXN1bHQgKz0gXCI8ZGl2IGNsYXNzPVxcXCJqaXRzaXBvcG92ZXJfc2hvd21vcmVcXFwiIFwiICtcbiAgICAgICAgICAgIFwib25jbGljayA9IFxcXCJBUFAuVUkuY29ubmVjdGlvbkluZGljYXRvclNob3dNb3JlKCdcIiArXG4gICAgICAgICAgICB0aGlzLnZpZGVvQ29udGFpbmVyLmlkICsgXCInKVxcXCIgIGRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5cIiArXG4gICAgICAgICAgICAgICAgKHRoaXMuc2hvd01vcmVWYWx1ZSA/IFwibGVzc1wiIDogXCJtb3JlXCIpICsgXCInPlwiICtcbiAgICAgICAgICAgIHRyYW5zbGF0ZShcImNvbm5lY3Rpb25pbmRpY2F0b3IuXCIgKyAodGhpcy5zaG93TW9yZVZhbHVlID8gXCJsZXNzXCIgOiBcIm1vcmVcIikpICtcbiAgICAgICAgICAgIFwiPC9kaXY+PGJyIC8+XCI7XG4gICAgfVxuXG4gICAgaWYodGhpcy5zaG93TW9yZVZhbHVlKVxuICAgIHtcbiAgICAgICAgdmFyIGRvd25sb2FkQmFuZHdpZHRoLCB1cGxvYWRCYW5kd2lkdGgsIHRyYW5zcG9ydDtcbiAgICAgICAgaWYodGhpcy5iYW5kd2lkdGggPT09IG51bGwpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGRvd25sb2FkQmFuZHdpZHRoID0gXCJOL0FcIjtcbiAgICAgICAgICAgIHVwbG9hZEJhbmR3aWR0aCA9IFwiTi9BXCI7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZVxuICAgICAgICB7XG4gICAgICAgICAgICBkb3dubG9hZEJhbmR3aWR0aCA9IHRoaXMuYmFuZHdpZHRoLmRvd25sb2FkP1xuICAgICAgICAgICAgICAgIHRoaXMuYmFuZHdpZHRoLmRvd25sb2FkICsgXCIgS2Jwc1wiIDpcbiAgICAgICAgICAgICAgICBcIk4vQVwiO1xuICAgICAgICAgICAgdXBsb2FkQmFuZHdpZHRoID0gdGhpcy5iYW5kd2lkdGgudXBsb2FkP1xuICAgICAgICAgICAgICAgIHRoaXMuYmFuZHdpZHRoLnVwbG9hZCArIFwiIEticHNcIiA6XG4gICAgICAgICAgICAgICAgXCJOL0FcIjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKCF0aGlzLnRyYW5zcG9ydCB8fCB0aGlzLnRyYW5zcG9ydC5sZW5ndGggPT09IDApXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRyYW5zcG9ydCA9IFwiPHRyPlwiICtcbiAgICAgICAgICAgICAgICBcIjx0ZD48c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnIFwiICtcbiAgICAgICAgICAgICAgICBcImRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5hZGRyZXNzJz5cIiArXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRlKFwiY29ubmVjdGlvbmluZGljYXRvci5hZGRyZXNzXCIpICsgXCI8L3NwYW4+PC90ZD5cIiArXG4gICAgICAgICAgICAgICAgXCI8dGQ+IE4vQTwvdGQ+PC90cj5cIjtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhciBkYXRhID0ge3JlbW90ZUlQOiBbXSwgbG9jYWxJUDpbXSwgcmVtb3RlUG9ydDpbXSwgbG9jYWxQb3J0OltdfTtcbiAgICAgICAgICAgIGZvcihpID0gMDsgaSA8IHRoaXMudHJhbnNwb3J0Lmxlbmd0aDsgaSsrKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHZhciBpcCA9ICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldElQKHRoaXMudHJhbnNwb3J0W2ldLmlwKTtcbiAgICAgICAgICAgICAgICB2YXIgcG9ydCA9IENvbm5lY3Rpb25JbmRpY2F0b3IuZ2V0UG9ydCh0aGlzLnRyYW5zcG9ydFtpXS5pcCk7XG4gICAgICAgICAgICAgICAgdmFyIGxvY2FsSVAgPVxuICAgICAgICAgICAgICAgICAgICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldElQKHRoaXMudHJhbnNwb3J0W2ldLmxvY2FsaXApO1xuICAgICAgICAgICAgICAgIHZhciBsb2NhbFBvcnQgPVxuICAgICAgICAgICAgICAgICAgICBDb25uZWN0aW9uSW5kaWNhdG9yLmdldFBvcnQodGhpcy50cmFuc3BvcnRbaV0ubG9jYWxpcCk7XG4gICAgICAgICAgICAgICAgaWYoZGF0YS5yZW1vdGVJUC5pbmRleE9mKGlwKSA9PSAtMSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEucmVtb3RlSVAucHVzaChpcCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgaWYoZGF0YS5yZW1vdGVQb3J0LmluZGV4T2YocG9ydCkgPT0gLTEpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBkYXRhLnJlbW90ZVBvcnQucHVzaChwb3J0KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZihkYXRhLmxvY2FsSVAuaW5kZXhPZihsb2NhbElQKSA9PSAtMSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEubG9jYWxJUC5wdXNoKGxvY2FsSVApO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGlmKGRhdGEubG9jYWxQb3J0LmluZGV4T2YobG9jYWxQb3J0KSA9PSAtMSlcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgIGRhdGEubG9jYWxQb3J0LnB1c2gobG9jYWxQb3J0KTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIGxvY2FsX2FkZHJlc3Nfa2V5ID0gXCJjb25uZWN0aW9uaW5kaWNhdG9yLlwiICtcbiAgICAgICAgICAgICAgICAoZGF0YS5sb2NhbElQLmxlbmd0aCA+IDE/IFwibG9jYWxhZGRyZXNzZXNcIiA6IFwibG9jYWxhZGRyZXNzXCIpO1xuICAgICAgICAgICAgdmFyIHJlbW90ZV9hZGRyZXNzX2tleSA9IFwiY29ubmVjdGlvbmluZGljYXRvci5cIiArXG4gICAgICAgICAgICAgICAgKGRhdGEucmVtb3RlSVAubGVuZ3RoID4gMT8gXCJyZW1vdGVhZGRyZXNzZXNcIiA6IFwicmVtb3RlYWRkcmVzc1wiKTtcbiAgICAgICAgICAgIHZhciBsb2NhbFRyYW5zcG9ydCA9XG4gICAgICAgICAgICAgICAgXCI8dHI+PHRkPjxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfYmx1ZScgZGF0YS1pMThuPSdcIiArXG4gICAgICAgICAgICAgICAgbG9jYWxfYWRkcmVzc19rZXkgK1wiJz5cIiArXG4gICAgICAgICAgICAgICAgICAgIHRyYW5zbGF0ZShsb2NhbF9hZGRyZXNzX2tleSkgKyBcIjwvc3Bhbj48L3RkPjx0ZD4gXCIgK1xuICAgICAgICAgICAgICAgIENvbm5lY3Rpb25JbmRpY2F0b3IuZ2V0U3RyaW5nRnJvbUFycmF5KGRhdGEubG9jYWxJUCkgK1xuICAgICAgICAgICAgICAgIFwiPC90ZD48L3RyPlwiO1xuICAgICAgICAgICAgdHJhbnNwb3J0ID1cbiAgICAgICAgICAgICAgICBcIjx0cj48dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJyBkYXRhLWkxOG49J1wiICtcbiAgICAgICAgICAgICAgICByZW1vdGVfYWRkcmVzc19rZXkgKyBcIic+XCIgK1xuICAgICAgICAgICAgICAgICAgICB0cmFuc2xhdGUocmVtb3RlX2FkZHJlc3Nfa2V5KSArIFwiPC9zcGFuPjwvdGQ+PHRkPiBcIiArXG4gICAgICAgICAgICAgICAgQ29ubmVjdGlvbkluZGljYXRvci5nZXRTdHJpbmdGcm9tQXJyYXkoZGF0YS5yZW1vdGVJUCkgK1xuICAgICAgICAgICAgICAgIFwiPC90ZD48L3RyPlwiO1xuXG4gICAgICAgICAgICB2YXIga2V5X3JlbW90ZSA9IFwiY29ubmVjdGlvbmluZGljYXRvci5cIixcbiAgICAgICAgICAgICAgICBrZXlfbG9jYWwgPSBcImNvbm5lY3Rpb25pbmRpY2F0b3IuXCI7XG5cbiAgICAgICAgICAgIGlmKHRoaXMudHJhbnNwb3J0Lmxlbmd0aCA+IDEpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAga2V5X3JlbW90ZSArPSBcInJlbW90ZXBvcnRzXCI7XG4gICAgICAgICAgICAgICAga2V5X2xvY2FsICs9IFwibG9jYWxwb3J0c1wiO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGtleV9yZW1vdGUgKz0gXCJyZW1vdGVwb3J0XCI7XG4gICAgICAgICAgICAgICAga2V5X2xvY2FsICs9IFwibG9jYWxwb3J0XCI7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHRyYW5zcG9ydCArPSBcIjx0cj5cIiArXG4gICAgICAgICAgICAgICAgXCI8dGQ+XCIgK1xuICAgICAgICAgICAgICAgIFwiPHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJyBkYXRhLWkxOG49J1wiICsga2V5X3JlbW90ZSArXG4gICAgICAgICAgICAgICAgXCInPlwiICtcbiAgICAgICAgICAgICAgICB0cmFuc2xhdGUoa2V5X3JlbW90ZSkgKyBcIjwvc3Bhbj48L3RkPjx0ZD5cIjtcbiAgICAgICAgICAgIGxvY2FsVHJhbnNwb3J0ICs9IFwiPHRyPlwiICtcbiAgICAgICAgICAgICAgICBcIjx0ZD5cIiArXG4gICAgICAgICAgICAgICAgXCI8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnIGRhdGEtaTE4bj0nXCIgKyBrZXlfbG9jYWwgK1xuICAgICAgICAgICAgICAgIFwiJz5cIiArXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRlKGtleV9sb2NhbCkgKyBcIjwvc3Bhbj48L3RkPjx0ZD5cIjtcblxuICAgICAgICAgICAgdHJhbnNwb3J0ICs9XG4gICAgICAgICAgICAgICAgQ29ubmVjdGlvbkluZGljYXRvci5nZXRTdHJpbmdGcm9tQXJyYXkoZGF0YS5yZW1vdGVQb3J0KTtcbiAgICAgICAgICAgIGxvY2FsVHJhbnNwb3J0ICs9XG4gICAgICAgICAgICAgICAgQ29ubmVjdGlvbkluZGljYXRvci5nZXRTdHJpbmdGcm9tQXJyYXkoZGF0YS5sb2NhbFBvcnQpO1xuICAgICAgICAgICAgdHJhbnNwb3J0ICs9IFwiPC90ZD48L3RyPlwiO1xuICAgICAgICAgICAgdHJhbnNwb3J0ICs9IGxvY2FsVHJhbnNwb3J0ICsgXCI8L3RkPjwvdHI+XCI7XG4gICAgICAgICAgICB0cmFuc3BvcnQgKz1cIjx0cj5cIiArXG4gICAgICAgICAgICAgICAgXCI8dGQ+PHNwYW4gY2xhc3M9J2ppdHNpcG9wb3Zlcl9ibHVlJyBkYXRhLWkxOG49J2Nvbm5lY3Rpb25pbmRpY2F0b3IudHJhbnNwb3J0Jz5cIiArXG4gICAgICAgICAgICAgICAgdHJhbnNsYXRlKFwiY29ubmVjdGlvbmluZGljYXRvci50cmFuc3BvcnRcIikgKyBcIjwvc3Bhbj48L3RkPlwiICtcbiAgICAgICAgICAgICAgICBcIjx0ZD5cIiArIHRoaXMudHJhbnNwb3J0WzBdLnR5cGUgKyBcIjwvdGQ+PC90cj5cIjtcblxuICAgICAgICB9XG5cbiAgICAgICAgcmVzdWx0ICs9IFwiPHRhYmxlICBzdHlsZT0nd2lkdGg6MTAwJSc+XCIgK1xuICAgICAgICAgICAgXCI8dHI+XCIgK1xuICAgICAgICAgICAgXCI8dGQ+XCIgK1xuICAgICAgICAgICAgXCI8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX2JsdWUnIGRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5iYW5kd2lkdGgnPlwiICtcbiAgICAgICAgICAgIHRyYW5zbGF0ZShcImNvbm5lY3Rpb25pbmRpY2F0b3IuYmFuZHdpZHRoXCIpICsgXCI8L3NwYW4+XCIgK1xuICAgICAgICAgICAgXCI8L3RkPjx0ZD5cIiArXG4gICAgICAgICAgICBcIjxzcGFuIGNsYXNzPSdqaXRzaXBvcG92ZXJfZ3JlZW4nPiZkYXJyOzwvc3Bhbj5cIiArXG4gICAgICAgICAgICBkb3dubG9hZEJhbmR3aWR0aCArXG4gICAgICAgICAgICBcIiA8c3BhbiBjbGFzcz0naml0c2lwb3BvdmVyX29yYW5nZSc+JnVhcnI7PC9zcGFuPlwiICtcbiAgICAgICAgICAgIHVwbG9hZEJhbmR3aWR0aCArIFwiPC90ZD48L3RyPlwiO1xuXG4gICAgICAgIHJlc3VsdCArPSB0cmFuc3BvcnQgKyBcIjwvdGFibGU+XCI7XG5cbiAgICB9XG5cbiAgICByZXR1cm4gcmVzdWx0O1xufTtcblxuLyoqXG4gKiBTaG93cyBvciBoaWRlIHRoZSBhZGRpdGlvbmFsIGluZm9ybWF0aW9uLlxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5zaG93TW9yZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLnNob3dNb3JlVmFsdWUgPSAhdGhpcy5zaG93TW9yZVZhbHVlO1xuICAgIHRoaXMudXBkYXRlUG9wb3ZlckRhdGEoKTtcbn07XG5cblxuZnVuY3Rpb24gY3JlYXRlSWNvbihjbGFzc2VzKVxue1xuICAgIHZhciBpY29uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcInNwYW5cIik7XG4gICAgZm9yKHZhciBpIGluIGNsYXNzZXMpXG4gICAge1xuICAgICAgICBpY29uLmNsYXNzTGlzdC5hZGQoY2xhc3Nlc1tpXSk7XG4gICAgfVxuICAgIGljb24uYXBwZW5kQ2hpbGQoXG4gICAgICAgIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoXCJpXCIpKS5jbGFzc0xpc3QuYWRkKFwiaWNvbi1jb25uZWN0aW9uXCIpO1xuICAgIHJldHVybiBpY29uO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIGluZGljYXRvclxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5jcmVhdGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudChcImRpdlwiKTtcbiAgICB0aGlzLmNvbm5lY3Rpb25JbmRpY2F0b3JDb250YWluZXIuY2xhc3NOYW1lID0gXCJjb25uZWN0aW9uaW5kaWNhdG9yXCI7XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICB0aGlzLnZpZGVvQ29udGFpbmVyLmFwcGVuZENoaWxkKHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lcik7XG4gICAgdGhpcy5wb3BvdmVyID0gbmV3IEppdHNpUG9wb3ZlcihcbiAgICAgICAgJChcIiNcIiArIHRoaXMudmlkZW9Db250YWluZXIuaWQgKyBcIiA+IC5jb25uZWN0aW9uaW5kaWNhdG9yXCIpLFxuICAgICAgICB7Y29udGVudDogXCI8ZGl2IGNsYXNzPVxcXCJjb25uZWN0aW9uX2luZm9cXFwiIGRhdGEtaTE4bj0nY29ubmVjdGlvbmluZGljYXRvci5uYSc+XCIgK1xuICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZVN0cmluZyhcImNvbm5lY3Rpb25pbmRpY2F0b3IubmFcIikgKyBcIjwvZGl2PlwiLFxuICAgICAgICAgICAgc2tpbjogXCJibGFja1wifSk7XG5cbiAgICB0aGlzLmVtcHR5SWNvbiA9IHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lci5hcHBlbmRDaGlsZChcbiAgICAgICAgY3JlYXRlSWNvbihbXCJjb25uZWN0aW9uXCIsIFwiY29ubmVjdGlvbl9lbXB0eVwiXSkpO1xuICAgIHRoaXMuZnVsbEljb24gPSB0aGlzLmNvbm5lY3Rpb25JbmRpY2F0b3JDb250YWluZXIuYXBwZW5kQ2hpbGQoXG4gICAgICAgIGNyZWF0ZUljb24oW1wiY29ubmVjdGlvblwiLCBcImNvbm5lY3Rpb25fZnVsbFwiXSkpO1xuXG59O1xuXG4vKipcbiAqIFJlbW92ZXMgdGhlIGluZGljYXRvclxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS5yZW1vdmUgPSBmdW5jdGlvbigpXG57XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnJlbW92ZSgpO1xuICAgIHRoaXMucG9wb3Zlci5mb3JjZUhpZGUoKTtcblxufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSBkYXRhIG9mIHRoZSBpbmRpY2F0b3JcbiAqIEBwYXJhbSBwZXJjZW50IHRoZSBwZXJjZW50IG9mIGNvbm5lY3Rpb24gcXVhbGl0eVxuICogQHBhcmFtIG9iamVjdCB0aGUgc3RhdGlzdGljcyBkYXRhLlxuICovXG5Db25uZWN0aW9uSW5kaWNhdG9yLnByb3RvdHlwZS51cGRhdGVDb25uZWN0aW9uUXVhbGl0eSA9XG5mdW5jdGlvbiAocGVyY2VudCwgb2JqZWN0KSB7XG5cbiAgICBpZihwZXJjZW50ID09PSBudWxsKVxuICAgIHtcbiAgICAgICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICAgICAgdGhpcy5wb3BvdmVyLmZvcmNlSGlkZSgpO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGVsc2VcbiAgICB7XG4gICAgICAgIGlmKHRoaXMuY29ubmVjdGlvbkluZGljYXRvckNvbnRhaW5lci5zdHlsZS5kaXNwbGF5ID09IFwibm9uZVwiKSB7XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb25JbmRpY2F0b3JDb250YWluZXIuc3R5bGUuZGlzcGxheSA9IFwiYmxvY2tcIjtcbiAgICAgICAgICAgIHRoaXMudmlkZW9MYXlvdXQudXBkYXRlTXV0ZVBvc2l0aW9uKHRoaXMudmlkZW9Db250YWluZXIuaWQpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHRoaXMuYmFuZHdpZHRoID0gb2JqZWN0LmJhbmR3aWR0aDtcbiAgICB0aGlzLmJpdHJhdGUgPSBvYmplY3QuYml0cmF0ZTtcbiAgICB0aGlzLnBhY2tldExvc3MgPSBvYmplY3QucGFja2V0TG9zcztcbiAgICB0aGlzLnRyYW5zcG9ydCA9IG9iamVjdC50cmFuc3BvcnQ7XG4gICAgaWYob2JqZWN0LnJlc29sdXRpb24pXG4gICAge1xuICAgICAgICB0aGlzLnJlc29sdXRpb24gPSBvYmplY3QucmVzb2x1dGlvbjtcbiAgICB9XG4gICAgZm9yKHZhciBxdWFsaXR5IGluIENvbm5lY3Rpb25JbmRpY2F0b3IuY29ubmVjdGlvblF1YWxpdHlWYWx1ZXMpXG4gICAge1xuICAgICAgICBpZihwZXJjZW50ID49IHF1YWxpdHkpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMuZnVsbEljb24uc3R5bGUud2lkdGggPVxuICAgICAgICAgICAgICAgIENvbm5lY3Rpb25JbmRpY2F0b3IuY29ubmVjdGlvblF1YWxpdHlWYWx1ZXNbcXVhbGl0eV07XG4gICAgICAgIH1cbiAgICB9XG4gICAgdGhpcy51cGRhdGVQb3BvdmVyRGF0YSgpO1xufTtcblxuLyoqXG4gKiBVcGRhdGVzIHRoZSByZXNvbHV0aW9uXG4gKiBAcGFyYW0gcmVzb2x1dGlvbiB0aGUgbmV3IHJlc29sdXRpb25cbiAqL1xuQ29ubmVjdGlvbkluZGljYXRvci5wcm90b3R5cGUudXBkYXRlUmVzb2x1dGlvbiA9IGZ1bmN0aW9uIChyZXNvbHV0aW9uKSB7XG4gICAgdGhpcy5yZXNvbHV0aW9uID0gcmVzb2x1dGlvbjtcbiAgICB0aGlzLnVwZGF0ZVBvcG92ZXJEYXRhKCk7XG59O1xuXG4vKipcbiAqIFVwZGF0ZXMgdGhlIGNvbnRlbnQgb2YgdGhlIHBvcG92ZXJcbiAqL1xuQ29ubmVjdGlvbkluZGljYXRvci5wcm90b3R5cGUudXBkYXRlUG9wb3ZlckRhdGEgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5wb3BvdmVyLnVwZGF0ZUNvbnRlbnQoXG4gICAgICAgIFwiPGRpdiBjbGFzcz1cXFwiY29ubmVjdGlvbl9pbmZvXFxcIj5cIiArIHRoaXMuZ2VuZXJhdGVUZXh0KCkgKyBcIjwvZGl2PlwiKTtcbiAgICBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlRWxlbWVudCgkKFwiLmNvbm5lY3Rpb25faW5mb1wiKSk7XG59O1xuXG4vKipcbiAqIEhpZGVzIHRoZSBwb3BvdmVyXG4gKi9cbkNvbm5lY3Rpb25JbmRpY2F0b3IucHJvdG90eXBlLmhpZGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5wb3BvdmVyLmZvcmNlSGlkZSgpO1xufTtcblxuLyoqXG4gKiBIaWRlcyB0aGUgaW5kaWNhdG9yXG4gKi9cbkNvbm5lY3Rpb25JbmRpY2F0b3IucHJvdG90eXBlLmhpZGVJbmRpY2F0b3IgPSBmdW5jdGlvbiAoKSB7XG4gICAgdGhpcy5jb25uZWN0aW9uSW5kaWNhdG9yQ29udGFpbmVyLnN0eWxlLmRpc3BsYXkgPSBcIm5vbmVcIjtcbiAgICBpZih0aGlzLnBvcG92ZXIpXG4gICAgICAgIHRoaXMucG9wb3Zlci5mb3JjZUhpZGUoKTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQ29ubmVjdGlvbkluZGljYXRvcjsiLCJ2YXIgQXVkaW9MZXZlbHMgPSByZXF1aXJlKFwiLi4vYXVkaW9fbGV2ZWxzL0F1ZGlvTGV2ZWxzXCIpO1xudmFyIEF2YXRhciA9IHJlcXVpcmUoXCIuLi9hdmF0YXIvQXZhdGFyXCIpO1xudmFyIENoYXQgPSByZXF1aXJlKFwiLi4vc2lkZV9wYW5uZWxzL2NoYXQvQ2hhdFwiKTtcbnZhciBDb250YWN0TGlzdCA9IHJlcXVpcmUoXCIuLi9zaWRlX3Bhbm5lbHMvY29udGFjdGxpc3QvQ29udGFjdExpc3RcIik7XG52YXIgVUlVdGlsID0gcmVxdWlyZShcIi4uL3V0aWwvVUlVdGlsXCIpO1xudmFyIENvbm5lY3Rpb25JbmRpY2F0b3IgPSByZXF1aXJlKFwiLi9Db25uZWN0aW9uSW5kaWNhdG9yXCIpO1xudmFyIE5pY2tuYW1lSGFuZGxlciA9IHJlcXVpcmUoXCIuLi91dGlsL05pY2tuYW1lSGFuZGxlclwiKTtcbnZhciBNZWRpYVN0cmVhbVR5cGUgPSByZXF1aXJlKFwiLi4vLi4vLi4vc2VydmljZS9SVEMvTWVkaWFTdHJlYW1UeXBlc1wiKTtcbnZhciBVSUV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi8uLi9zZXJ2aWNlL1VJL1VJRXZlbnRzXCIpO1xuXG52YXIgY3VycmVudERvbWluYW50U3BlYWtlciA9IG51bGw7XG52YXIgbGFzdE5Db3VudCA9IGNvbmZpZy5jaGFubmVsTGFzdE47XG52YXIgbG9jYWxMYXN0TkNvdW50ID0gY29uZmlnLmNoYW5uZWxMYXN0TjtcbnZhciBsb2NhbExhc3ROU2V0ID0gW107XG52YXIgbGFzdE5FbmRwb2ludHNDYWNoZSA9IFtdO1xudmFyIGxhc3ROUGlja3VwSmlkID0gbnVsbDtcbnZhciBsYXJnZVZpZGVvU3RhdGUgPSB7XG4gICAgdXBkYXRlSW5Qcm9ncmVzczogZmFsc2UsXG4gICAgbmV3U3JjOiAnJ1xufTtcblxudmFyIGV2ZW50RW1pdHRlciA9IG51bGw7XG5cbi8qKlxuICogQ3VycmVudGx5IGZvY3VzZWQgdmlkZW8gXCJzcmNcIihkaXNwbGF5ZWQgaW4gbGFyZ2UgdmlkZW8pLlxuICogQHR5cGUge1N0cmluZ31cbiAqL1xudmFyIGZvY3VzZWRWaWRlb0luZm8gPSBudWxsO1xuXG4vKipcbiAqIEluZGljYXRlcyBpZiB3ZSBoYXZlIG11dGVkIG91ciBhdWRpbyBiZWZvcmUgdGhlIGNvbmZlcmVuY2UgaGFzIHN0YXJ0ZWQuXG4gKiBAdHlwZSB7Ym9vbGVhbn1cbiAqL1xudmFyIHByZU11dGVkID0gZmFsc2U7XG5cbnZhciBtdXRlZEF1ZGlvcyA9IHt9O1xuXG52YXIgZmxpcFhMb2NhbFZpZGVvID0gdHJ1ZTtcbnZhciBjdXJyZW50VmlkZW9XaWR0aCA9IG51bGw7XG52YXIgY3VycmVudFZpZGVvSGVpZ2h0ID0gbnVsbDtcblxudmFyIGxvY2FsVmlkZW9TcmMgPSBudWxsO1xuXG5mdW5jdGlvbiB2aWRlb2FjdGl2ZSggdmlkZW9lbGVtKSB7XG4gICAgaWYgKHZpZGVvZWxlbS5hdHRyKCdpZCcpLmluZGV4T2YoJ21peGVkbXNsYWJlbCcpID09PSAtMSkge1xuICAgICAgICAvLyBpZ25vcmUgbWl4ZWRtc2xhYmVsYTAgYW5kIHYwXG5cbiAgICAgICAgdmlkZW9lbGVtLnNob3coKTtcbiAgICAgICAgVmlkZW9MYXlvdXQucmVzaXplVGh1bWJuYWlscygpO1xuXG4gICAgICAgIHZhciB2aWRlb1BhcmVudCA9IHZpZGVvZWxlbS5wYXJlbnQoKTtcbiAgICAgICAgdmFyIHBhcmVudFJlc291cmNlSmlkID0gbnVsbDtcbiAgICAgICAgaWYgKHZpZGVvUGFyZW50KVxuICAgICAgICAgICAgcGFyZW50UmVzb3VyY2VKaWRcbiAgICAgICAgICAgICAgICA9IFZpZGVvTGF5b3V0LmdldFBlZXJDb250YWluZXJSZXNvdXJjZUppZCh2aWRlb1BhcmVudFswXSk7XG5cbiAgICAgICAgLy8gVXBkYXRlIHRoZSBsYXJnZSB2aWRlbyB0byB0aGUgbGFzdCBhZGRlZCB2aWRlbyBvbmx5IGlmIHRoZXJlJ3Mgbm9cbiAgICAgICAgLy8gY3VycmVudCBkb21pbmFudCwgZm9jdXNlZCBzcGVha2VyIG9yIHByZXppIHBsYXlpbmcgb3IgdXBkYXRlIGl0IHRvXG4gICAgICAgIC8vIHRoZSBjdXJyZW50IGRvbWluYW50IHNwZWFrZXIuXG4gICAgICAgIGlmICgoIWZvY3VzZWRWaWRlb0luZm8gJiZcbiAgICAgICAgICAgICFWaWRlb0xheW91dC5nZXREb21pbmFudFNwZWFrZXJSZXNvdXJjZUppZCgpICYmXG4gICAgICAgICAgICAhcmVxdWlyZShcIi4uL3ByZXppL1ByZXppXCIpLmlzUHJlc2VudGF0aW9uVmlzaWJsZSgpKSB8fFxuICAgICAgICAgICAgKHBhcmVudFJlc291cmNlSmlkICYmXG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuZ2V0RG9taW5hbnRTcGVha2VyUmVzb3VyY2VKaWQoKSA9PT0gcGFyZW50UmVzb3VyY2VKaWQpKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKFxuICAgICAgICAgICAgICAgIEFQUC5SVEMuZ2V0VmlkZW9TcmModmlkZW9lbGVtWzBdKSxcbiAgICAgICAgICAgICAgICAxLFxuICAgICAgICAgICAgICAgIHBhcmVudFJlc291cmNlSmlkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIFZpZGVvTGF5b3V0LnNob3dNb2RlcmF0b3JJbmRpY2F0b3IoKTtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHdhaXRGb3JSZW1vdGVWaWRlbyhzZWxlY3Rvciwgc3NyYywgc3RyZWFtLCBqaWQpIHtcbiAgICAvLyBYWFgoZ3ApIHNvLCBldmVyeSBjYWxsIHRvIHRoaXMgZnVuY3Rpb24gaXMgKmFsd2F5cyogcHJlY2VkZWQgYnkgYSBjYWxsXG4gICAgLy8gdG8gdGhlIFJUQy5hdHRhY2hNZWRpYVN0cmVhbSgpIGZ1bmN0aW9uIGJ1dCB0aGF0IGNhbGwgaXMgKm5vdCogZm9sbG93ZWRcbiAgICAvLyBieSBhbiB1cGRhdGUgdG8gdGhlIHZpZGVvU3JjVG9Tc3JjIG1hcCFcbiAgICAvL1xuICAgIC8vIFRoZSBhYm92ZSB3YXkgb2YgZG9pbmcgdGhpbmdzIHJlc3VsdHMgaW4gdmlkZW8gU1JDcyB0aGF0IGRvbid0IGNvcnJlc3BvbmRcbiAgICAvLyB0byBhbnkgU1NSQyBmb3IgYSBzaG9ydCBwZXJpb2Qgb2YgdGltZSAodG8gYmUgbW9yZSBwcmVjaXNlLCBmb3IgYXMgbG9uZ1xuICAgIC8vIHRoZSB3YWl0Rm9yUmVtb3RlVmlkZW8gdGFrZXMgdG8gY29tcGxldGUpLiBUaGlzIGNhdXNlcyBwcm9ibGVtcyAoc2VlXG4gICAgLy8gYmVsbG93KS5cbiAgICAvL1xuICAgIC8vIEknbSB3b25kZXJpbmcgd2h5IHdlIG5lZWQgdG8gZG8gdGhhdDsgaS5lLiB3aHkgY2FsbCBSVEMuYXR0YWNoTWVkaWFTdHJlYW0oKVxuICAgIC8vIGEgc2Vjb25kIHRpbWUgaW4gaGVyZSBhbmQgb25seSB0aGVuIHVwZGF0ZSB0aGUgdmlkZW9TcmNUb1NzcmMgbWFwPyBXaHlcbiAgICAvLyBub3Qgc2ltcGx5IHVwZGF0ZSB0aGUgdmlkZW9TcmNUb1NzcmMgbWFwIHdoZW4gdGhlIFJUQy5hdHRhY2hNZWRpYVN0cmVhbSgpXG4gICAgLy8gaXMgY2FsbGVkIHRoZSBmaXJzdCB0aW1lPyBJIGFjdHVhbGx5IGRvIHRoYXQgaW4gdGhlIGxhc3ROIGNoYW5nZWQgZXZlbnRcbiAgICAvLyBoYW5kbGVyIGJlY2F1c2UgdGhlIFwib3JwaGFuXCIgdmlkZW8gU1JDIGlzIGNhdXNpbmcgdHJvdWJsZXMgdGhlcmUuIFRoZVxuICAgIC8vIHB1cnBvc2Ugb2YgdGhpcyBtZXRob2Qgd291bGQgdGhlbiBiZSB0byBmaXJlIHRoZSBcInZpZGVvYWN0aXZlLmppbmdsZVwiLlxuICAgIC8vXG4gICAgLy8gRm9vZCBmb3IgdGhvdWdoIEkgZ3Vlc3MgOi0pXG5cbiAgICBpZiAoc2VsZWN0b3IucmVtb3ZlZCB8fCAhc2VsZWN0b3IucGFyZW50KCkuaXMoXCI6dmlzaWJsZVwiKSkge1xuICAgICAgICBjb25zb2xlLndhcm4oXCJNZWRpYSByZW1vdmVkIGJlZm9yZSBoYWQgc3RhcnRlZFwiLCBzZWxlY3Rvcik7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBpZiAoc3RyZWFtLmlkID09PSAnbWl4ZWRtc2xhYmVsJykgcmV0dXJuO1xuXG4gICAgaWYgKHNlbGVjdG9yWzBdLmN1cnJlbnRUaW1lID4gMCkge1xuICAgICAgICB2YXIgdmlkZW9TdHJlYW0gPSBBUFAuc2ltdWxjYXN0LmdldFJlY2VpdmluZ1ZpZGVvU3RyZWFtKHN0cmVhbSk7XG4gICAgICAgIEFQUC5SVEMuYXR0YWNoTWVkaWFTdHJlYW0oc2VsZWN0b3IsIHZpZGVvU3RyZWFtKTsgLy8gRklYTUU6IHdoeSBkbyBpIGhhdmUgdG8gZG8gdGhpcyBmb3IgRkY/XG4gICAgICAgIHZpZGVvYWN0aXZlKHNlbGVjdG9yKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHdhaXRGb3JSZW1vdGVWaWRlbyhzZWxlY3Rvciwgc3NyYywgc3RyZWFtLCBqaWQpO1xuICAgICAgICB9LCAyNTApO1xuICAgIH1cbn1cblxuLyoqXG4gKiBSZXR1cm5zIGFuIGFycmF5IG9mIHRoZSB2aWRlbyBob3Jpem9udGFsIGFuZCB2ZXJ0aWNhbCBpbmRlbnRzLFxuICogc28gdGhhdCBpZiBmaXRzIGl0cyBwYXJlbnQuXG4gKlxuICogQHJldHVybiBhbiBhcnJheSB3aXRoIDIgZWxlbWVudHMsIHRoZSBob3Jpem9udGFsIGluZGVudCBhbmQgdGhlIHZlcnRpY2FsXG4gKiBpbmRlbnRcbiAqL1xuZnVuY3Rpb24gZ2V0Q2FtZXJhVmlkZW9Qb3NpdGlvbih2aWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb0hlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFjZVdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlSGVpZ2h0KSB7XG4gICAgLy8gUGFyZW50IGhlaWdodCBpc24ndCBjb21wbGV0ZWx5IGNhbGN1bGF0ZWQgd2hlbiB3ZSBwb3NpdGlvbiB0aGUgdmlkZW8gaW5cbiAgICAvLyBmdWxsIHNjcmVlbiBtb2RlIGFuZCB0aGlzIGlzIHdoeSB3ZSB1c2UgdGhlIHNjcmVlbiBoZWlnaHQgaW4gdGhpcyBjYXNlLlxuICAgIC8vIE5lZWQgdG8gdGhpbmsgaXQgZnVydGhlciBhdCBzb21lIHBvaW50IGFuZCBpbXBsZW1lbnQgaXQgcHJvcGVybHkuXG4gICAgdmFyIGlzRnVsbFNjcmVlbiA9IGRvY3VtZW50LmZ1bGxTY3JlZW4gfHxcbiAgICAgICAgZG9jdW1lbnQubW96RnVsbFNjcmVlbiB8fFxuICAgICAgICBkb2N1bWVudC53ZWJraXRJc0Z1bGxTY3JlZW47XG4gICAgaWYgKGlzRnVsbFNjcmVlbilcbiAgICAgICAgdmlkZW9TcGFjZUhlaWdodCA9IHdpbmRvdy5pbm5lckhlaWdodDtcblxuICAgIHZhciBob3Jpem9udGFsSW5kZW50ID0gKHZpZGVvU3BhY2VXaWR0aCAtIHZpZGVvV2lkdGgpIC8gMjtcbiAgICB2YXIgdmVydGljYWxJbmRlbnQgPSAodmlkZW9TcGFjZUhlaWdodCAtIHZpZGVvSGVpZ2h0KSAvIDI7XG5cbiAgICByZXR1cm4gW2hvcml6b250YWxJbmRlbnQsIHZlcnRpY2FsSW5kZW50XTtcbn1cblxuLyoqXG4gKiBSZXR1cm5zIGFuIGFycmF5IG9mIHRoZSB2aWRlbyBob3Jpem9udGFsIGFuZCB2ZXJ0aWNhbCBpbmRlbnRzLlxuICogQ2VudGVycyBob3Jpem9udGFsbHkgYW5kIHRvcCBhbGlnbnMgdmVydGljYWxseS5cbiAqXG4gKiBAcmV0dXJuIGFuIGFycmF5IHdpdGggMiBlbGVtZW50cywgdGhlIGhvcml6b250YWwgaW5kZW50IGFuZCB0aGUgdmVydGljYWxcbiAqIGluZGVudFxuICovXG5mdW5jdGlvbiBnZXREZXNrdG9wVmlkZW9Qb3NpdGlvbih2aWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9IZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlSGVpZ2h0KSB7XG5cbiAgICB2YXIgaG9yaXpvbnRhbEluZGVudCA9ICh2aWRlb1NwYWNlV2lkdGggLSB2aWRlb1dpZHRoKSAvIDI7XG5cbiAgICB2YXIgdmVydGljYWxJbmRlbnQgPSAwOy8vIFRvcCBhbGlnbmVkXG5cbiAgICByZXR1cm4gW2hvcml6b250YWxJbmRlbnQsIHZlcnRpY2FsSW5kZW50XTtcbn1cblxuXG4vKipcbiAqIFJldHVybnMgYW4gYXJyYXkgb2YgdGhlIHZpZGVvIGRpbWVuc2lvbnMsIHNvIHRoYXQgaXQgY292ZXJzIHRoZSBzY3JlZW4uXG4gKiBJdCBsZWF2ZXMgbm8gZW1wdHkgYXJlYXMsIGJ1dCBzb21lIHBhcnRzIG9mIHRoZSB2aWRlbyBtaWdodCBub3QgYmUgdmlzaWJsZS5cbiAqXG4gKiBAcmV0dXJuIGFuIGFycmF5IHdpdGggMiBlbGVtZW50cywgdGhlIHZpZGVvIHdpZHRoIGFuZCB0aGUgdmlkZW8gaGVpZ2h0XG4gKi9cbmZ1bmN0aW9uIGdldENhbWVyYVZpZGVvU2l6ZSh2aWRlb1dpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3BhY2VXaWR0aCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlSGVpZ2h0KSB7XG4gICAgaWYgKCF2aWRlb1dpZHRoKVxuICAgICAgICB2aWRlb1dpZHRoID0gY3VycmVudFZpZGVvV2lkdGg7XG4gICAgaWYgKCF2aWRlb0hlaWdodClcbiAgICAgICAgdmlkZW9IZWlnaHQgPSBjdXJyZW50VmlkZW9IZWlnaHQ7XG5cbiAgICB2YXIgYXNwZWN0UmF0aW8gPSB2aWRlb1dpZHRoIC8gdmlkZW9IZWlnaHQ7XG5cbiAgICB2YXIgYXZhaWxhYmxlV2lkdGggPSBNYXRoLm1heCh2aWRlb1dpZHRoLCB2aWRlb1NwYWNlV2lkdGgpO1xuICAgIHZhciBhdmFpbGFibGVIZWlnaHQgPSBNYXRoLm1heCh2aWRlb0hlaWdodCwgdmlkZW9TcGFjZUhlaWdodCk7XG5cbiAgICBpZiAoYXZhaWxhYmxlV2lkdGggLyBhc3BlY3RSYXRpbyA8IHZpZGVvU3BhY2VIZWlnaHQpIHtcbiAgICAgICAgYXZhaWxhYmxlSGVpZ2h0ID0gdmlkZW9TcGFjZUhlaWdodDtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSBhdmFpbGFibGVIZWlnaHQgKiBhc3BlY3RSYXRpbztcbiAgICB9XG5cbiAgICBpZiAoYXZhaWxhYmxlSGVpZ2h0ICogYXNwZWN0UmF0aW8gPCB2aWRlb1NwYWNlV2lkdGgpIHtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSB2aWRlb1NwYWNlV2lkdGg7XG4gICAgICAgIGF2YWlsYWJsZUhlaWdodCA9IGF2YWlsYWJsZVdpZHRoIC8gYXNwZWN0UmF0aW87XG4gICAgfVxuXG4gICAgcmV0dXJuIFthdmFpbGFibGVXaWR0aCwgYXZhaWxhYmxlSGVpZ2h0XTtcbn1cblxuLyoqXG4gKiBTZXRzIHRoZSBkaXNwbGF5IG5hbWUgZm9yIHRoZSBnaXZlbiB2aWRlbyBzcGFuIGlkLlxuICovXG5mdW5jdGlvbiBzZXREaXNwbGF5TmFtZSh2aWRlb1NwYW5JZCwgZGlzcGxheU5hbWUpIHtcbiAgICB2YXIgbmFtZVNwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLmRpc3BsYXluYW1lJyk7XG4gICAgdmFyIGRlZmF1bHRMb2NhbERpc3BsYXlOYW1lID0gaW50ZXJmYWNlQ29uZmlnLkRFRkFVTFRfTE9DQUxfRElTUExBWV9OQU1FO1xuXG4gICAgLy8gSWYgd2UgYWxyZWFkeSBoYXZlIGEgZGlzcGxheSBuYW1lIGZvciB0aGlzIHZpZGVvLlxuICAgIGlmIChuYW1lU3Bhbi5sZW5ndGggPiAwKSB7XG4gICAgICAgIHZhciBuYW1lU3BhbkVsZW1lbnQgPSBuYW1lU3Bhbi5nZXQoMCk7XG5cbiAgICAgICAgaWYgKG5hbWVTcGFuRWxlbWVudC5pZCA9PT0gJ2xvY2FsRGlzcGxheU5hbWUnICYmXG4gICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpLnRleHQoKSAhPT0gZGlzcGxheU5hbWUpIHtcbiAgICAgICAgICAgIGlmIChkaXNwbGF5TmFtZSAmJiBkaXNwbGF5TmFtZS5sZW5ndGggPiAwKVxuICAgICAgICAgICAgICAgICQoJyNsb2NhbERpc3BsYXlOYW1lJykuaHRtbChkaXNwbGF5TmFtZSArICcgKG1lKScpO1xuICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICQoJyNsb2NhbERpc3BsYXlOYW1lJykudGV4dChkZWZhdWx0TG9jYWxEaXNwbGF5TmFtZSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoZGlzcGxheU5hbWUgJiYgZGlzcGxheU5hbWUubGVuZ3RoID4gMClcbiAgICAgICAgICAgICAgICAkKCcjJyArIHZpZGVvU3BhbklkICsgJ19uYW1lJykuaHRtbChkaXNwbGF5TmFtZSk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZCArICdfbmFtZScpLnRleHQoaW50ZXJmYWNlQ29uZmlnLkRFRkFVTFRfUkVNT1RFX0RJU1BMQVlfTkFNRSk7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICB2YXIgZWRpdEJ1dHRvbiA9IG51bGw7XG5cbiAgICAgICAgbmFtZVNwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgIG5hbWVTcGFuLmNsYXNzTmFtZSA9ICdkaXNwbGF5bmFtZSc7XG4gICAgICAgICQoJyMnICsgdmlkZW9TcGFuSWQpWzBdLmFwcGVuZENoaWxkKG5hbWVTcGFuKTtcblxuICAgICAgICBpZiAodmlkZW9TcGFuSWQgPT09ICdsb2NhbFZpZGVvQ29udGFpbmVyJykge1xuICAgICAgICAgICAgZWRpdEJ1dHRvbiA9IGNyZWF0ZUVkaXREaXNwbGF5TmFtZUJ1dHRvbigpO1xuICAgICAgICAgICAgbmFtZVNwYW4uaW5uZXJUZXh0ID0gZGVmYXVsdExvY2FsRGlzcGxheU5hbWU7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBuYW1lU3Bhbi5pbm5lclRleHQgPSBpbnRlcmZhY2VDb25maWcuREVGQVVMVF9SRU1PVEVfRElTUExBWV9OQU1FO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGRpc3BsYXlOYW1lICYmIGRpc3BsYXlOYW1lLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIG5hbWVTcGFuLmlubmVyVGV4dCA9IGRpc3BsYXlOYW1lO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFlZGl0QnV0dG9uKSB7XG4gICAgICAgICAgICBuYW1lU3Bhbi5pZCA9IHZpZGVvU3BhbklkICsgJ19uYW1lJztcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIG5hbWVTcGFuLmlkID0gJ2xvY2FsRGlzcGxheU5hbWUnO1xuICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZClbMF0uYXBwZW5kQ2hpbGQoZWRpdEJ1dHRvbik7XG4gICAgICAgICAgICAvL3RyYW5zbGF0ZXMgcG9wb3ZlciBvZiBlZGl0IGJ1dHRvblxuICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZUVsZW1lbnQoJChcImEuZGlzcGxheW5hbWVcIikpO1xuXG4gICAgICAgICAgICB2YXIgZWRpdGFibGVUZXh0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaW5wdXQnKTtcbiAgICAgICAgICAgIGVkaXRhYmxlVGV4dC5jbGFzc05hbWUgPSAnZGlzcGxheW5hbWUnO1xuICAgICAgICAgICAgZWRpdGFibGVUZXh0LnR5cGUgPSAndGV4dCc7XG4gICAgICAgICAgICBlZGl0YWJsZVRleHQuaWQgPSAnZWRpdERpc3BsYXlOYW1lJztcblxuICAgICAgICAgICAgaWYgKGRpc3BsYXlOYW1lICYmIGRpc3BsYXlOYW1lLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIGVkaXRhYmxlVGV4dC52YWx1ZVxuICAgICAgICAgICAgICAgICAgICA9IGRpc3BsYXlOYW1lLnN1YnN0cmluZygwLCBkaXNwbGF5TmFtZS5pbmRleE9mKCcgKG1lKScpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgZWRpdGFibGVUZXh0LnNldEF0dHJpYnV0ZSgnc3R5bGUnLCAnZGlzcGxheTpub25lOycpO1xuICAgICAgICAgICAgZWRpdGFibGVUZXh0LnNldEF0dHJpYnV0ZSgncGxhY2Vob2xkZXInLCAnZXguIEphbmUgUGluaycpO1xuICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZClbMF0uYXBwZW5kQ2hpbGQoZWRpdGFibGVUZXh0KTtcblxuICAgICAgICAgICAgJCgnI2xvY2FsVmlkZW9Db250YWluZXIgLmRpc3BsYXluYW1lJylcbiAgICAgICAgICAgICAgICAuYmluZChcImNsaWNrXCIsIGZ1bmN0aW9uIChlKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgZS5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICAgICAgICAgICAgICBlLnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgICAgICAkKCcjbG9jYWxEaXNwbGF5TmFtZScpLmhpZGUoKTtcbiAgICAgICAgICAgICAgICAgICAgJCgnI2VkaXREaXNwbGF5TmFtZScpLnNob3coKTtcbiAgICAgICAgICAgICAgICAgICAgJCgnI2VkaXREaXNwbGF5TmFtZScpLmZvY3VzKCk7XG4gICAgICAgICAgICAgICAgICAgICQoJyNlZGl0RGlzcGxheU5hbWUnKS5zZWxlY3QoKTtcblxuICAgICAgICAgICAgICAgICAgICAkKCcjZWRpdERpc3BsYXlOYW1lJykub25lKFwiZm9jdXNvdXRcIiwgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmlucHV0RGlzcGxheU5hbWVIYW5kbGVyKHRoaXMudmFsdWUpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICAkKCcjZWRpdERpc3BsYXlOYW1lJykub24oJ2tleWRvd24nLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGUua2V5Q29kZSA9PT0gMTMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlLnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuaW5wdXREaXNwbGF5TmFtZUhhbmRsZXIodGhpcy52YWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgfVxufVxuXG4vKipcbiAqIEdldHMgdGhlIHNlbGVjdG9yIG9mIHZpZGVvIHRodW1ibmFpbCBjb250YWluZXIgZm9yIHRoZSB1c2VyIGlkZW50aWZpZWQgYnlcbiAqIGdpdmVuIDx0dD51c2VySmlkPC90dD5cbiAqIEBwYXJhbSByZXNvdXJjZUppZCB1c2VyJ3MgSmlkIGZvciB3aG9tIHdlIHdhbnQgdG8gZ2V0IHRoZSB2aWRlbyBjb250YWluZXIuXG4gKi9cbmZ1bmN0aW9uIGdldFBhcnRpY2lwYW50Q29udGFpbmVyKHJlc291cmNlSmlkKVxue1xuICAgIGlmICghcmVzb3VyY2VKaWQpXG4gICAgICAgIHJldHVybiBudWxsO1xuXG4gICAgaWYgKHJlc291cmNlSmlkID09PSBBUFAueG1wcC5teVJlc291cmNlKCkpXG4gICAgICAgIHJldHVybiAkKFwiI2xvY2FsVmlkZW9Db250YWluZXJcIik7XG4gICAgZWxzZVxuICAgICAgICByZXR1cm4gJChcIiNwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlSmlkKTtcbn1cblxuLyoqXG4gKiBTZXRzIHRoZSBzaXplIGFuZCBwb3NpdGlvbiBvZiB0aGUgZ2l2ZW4gdmlkZW8gZWxlbWVudC5cbiAqXG4gKiBAcGFyYW0gdmlkZW8gdGhlIHZpZGVvIGVsZW1lbnQgdG8gcG9zaXRpb25cbiAqIEBwYXJhbSB3aWR0aCB0aGUgZGVzaXJlZCB2aWRlbyB3aWR0aFxuICogQHBhcmFtIGhlaWdodCB0aGUgZGVzaXJlZCB2aWRlbyBoZWlnaHRcbiAqIEBwYXJhbSBob3Jpem9udGFsSW5kZW50IHRoZSBsZWZ0IGFuZCByaWdodCBpbmRlbnRcbiAqIEBwYXJhbSB2ZXJ0aWNhbEluZGVudCB0aGUgdG9wIGFuZCBib3R0b20gaW5kZW50XG4gKi9cbmZ1bmN0aW9uIHBvc2l0aW9uVmlkZW8odmlkZW8sXG4gICAgICAgICAgICAgICAgICAgICAgIHdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICBoZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgIGhvcml6b250YWxJbmRlbnQsXG4gICAgICAgICAgICAgICAgICAgICAgIHZlcnRpY2FsSW5kZW50KSB7XG4gICAgdmlkZW8ud2lkdGgod2lkdGgpO1xuICAgIHZpZGVvLmhlaWdodChoZWlnaHQpO1xuICAgIHZpZGVvLmNzcyh7ICB0b3A6IHZlcnRpY2FsSW5kZW50ICsgJ3B4JyxcbiAgICAgICAgYm90dG9tOiB2ZXJ0aWNhbEluZGVudCArICdweCcsXG4gICAgICAgIGxlZnQ6IGhvcml6b250YWxJbmRlbnQgKyAncHgnLFxuICAgICAgICByaWdodDogaG9yaXpvbnRhbEluZGVudCArICdweCd9KTtcbn1cblxuLyoqXG4gKiBBZGRzIHRoZSByZW1vdGUgdmlkZW8gbWVudSBlbGVtZW50IGZvciB0aGUgZ2l2ZW4gPHR0PmppZDwvdHQ+IGluIHRoZVxuICogZ2l2ZW4gPHR0PnBhcmVudEVsZW1lbnQ8L3R0Pi5cbiAqXG4gKiBAcGFyYW0gamlkIHRoZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZm9yIHdoaWNoIHdlJ3JlIGFkZGluZyBhIG1lbnUuXG4gKiBAcGFyYW0gcGFyZW50RWxlbWVudCB0aGUgcGFyZW50IGVsZW1lbnQgd2hlcmUgdGhpcyBtZW51IHdpbGwgYmUgYWRkZWRcbiAqL1xuZnVuY3Rpb24gYWRkUmVtb3RlVmlkZW9NZW51KGppZCwgcGFyZW50RWxlbWVudCkge1xuICAgIHZhciBzcGFuRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICBzcGFuRWxlbWVudC5jbGFzc05hbWUgPSAncmVtb3RldmlkZW9tZW51JztcblxuICAgIHBhcmVudEVsZW1lbnQuYXBwZW5kQ2hpbGQoc3BhbkVsZW1lbnQpO1xuXG4gICAgdmFyIG1lbnVFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaScpO1xuICAgIG1lbnVFbGVtZW50LmNsYXNzTmFtZSA9ICdmYSBmYS1hbmdsZS1kb3duJztcbiAgICBtZW51RWxlbWVudC50aXRsZSA9ICdSZW1vdGUgdXNlciBjb250cm9scyc7XG4gICAgc3BhbkVsZW1lbnQuYXBwZW5kQ2hpbGQobWVudUVsZW1lbnQpO1xuXG4vLyAgICAgICAgPHVsIGNsYXNzPVwicG9wdXBtZW51XCI+XG4vLyAgICAgICAgPGxpPjxhIGhyZWY9XCIjXCI+TXV0ZTwvYT48L2xpPlxuLy8gICAgICAgIDxsaT48YSBocmVmPVwiI1wiPkVqZWN0PC9hPjwvbGk+XG4vLyAgICAgICAgPC91bD5cblxuICAgIHZhciBwb3B1cG1lbnVFbGVtZW50ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgndWwnKTtcbiAgICBwb3B1cG1lbnVFbGVtZW50LmNsYXNzTmFtZSA9ICdwb3B1cG1lbnUnO1xuICAgIHBvcHVwbWVudUVsZW1lbnQuaWRcbiAgICAgICAgPSAncmVtb3RlX3BvcHVwbWVudV8nICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICBzcGFuRWxlbWVudC5hcHBlbmRDaGlsZChwb3B1cG1lbnVFbGVtZW50KTtcblxuICAgIHZhciBtdXRlTWVudUl0ZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdsaScpO1xuICAgIHZhciBtdXRlTGlua0l0ZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG5cbiAgICB2YXIgbXV0ZWRJbmRpY2F0b3IgPSBcIjxpIHN0eWxlPSdmbG9hdDpsZWZ0OycgY2xhc3M9J2ljb24tbWljLWRpc2FibGVkJz48L2k+XCI7XG5cbiAgICBpZiAoIW11dGVkQXVkaW9zW2ppZF0pIHtcbiAgICAgICAgbXV0ZUxpbmtJdGVtLmlubmVySFRNTCA9IG11dGVkSW5kaWNhdG9yICtcbiAgICAgICAgICAgIFwiIDxkaXYgc3R5bGU9J3dpZHRoOiA5MHB4O21hcmdpbi1sZWZ0OiAyMHB4OycgZGF0YS1pMThuPSd2aWRlb3RodW1ibmFpbC5kb211dGUnPjwvZGl2PlwiO1xuICAgICAgICBtdXRlTGlua0l0ZW0uY2xhc3NOYW1lID0gJ211dGVsaW5rJztcbiAgICB9XG4gICAgZWxzZSB7XG4gICAgICAgIG11dGVMaW5rSXRlbS5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArXG4gICAgICAgICAgICBcIiA8ZGl2IHN0eWxlPSd3aWR0aDogOTBweDttYXJnaW4tbGVmdDogMjBweDsnIGRhdGEtaTE4bj0ndmlkZW90aHVtYm5haWwubXV0ZWQnPjwvZGl2PlwiO1xuICAgICAgICBtdXRlTGlua0l0ZW0uY2xhc3NOYW1lID0gJ211dGVsaW5rIGRpc2FibGVkJztcbiAgICB9XG5cbiAgICBtdXRlTGlua0l0ZW0ub25jbGljayA9IGZ1bmN0aW9uKCl7XG4gICAgICAgIGlmICgkKHRoaXMpLmF0dHIoJ2Rpc2FibGVkJykgIT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuICAgICAgICB9XG4gICAgICAgIHZhciBpc011dGUgPSBtdXRlZEF1ZGlvc1tqaWRdID09IHRydWU7XG4gICAgICAgIEFQUC54bXBwLnNldE11dGUoamlkLCAhaXNNdXRlKTtcblxuICAgICAgICBwb3B1cG1lbnVFbGVtZW50LnNldEF0dHJpYnV0ZSgnc3R5bGUnLCAnZGlzcGxheTpub25lOycpO1xuXG4gICAgICAgIGlmIChpc011dGUpIHtcbiAgICAgICAgICAgIHRoaXMuaW5uZXJIVE1MID0gbXV0ZWRJbmRpY2F0b3IgK1xuICAgICAgICAgICAgICAgIFwiIDxkaXYgc3R5bGU9J3dpZHRoOiA5MHB4O21hcmdpbi1sZWZ0OiAyMHB4OycgZGF0YS1pMThuPSd2aWRlb3RodW1ibmFpbC5tdXRlZCc+PC9kaXY+XCI7XG4gICAgICAgICAgICB0aGlzLmNsYXNzTmFtZSA9ICdtdXRlbGluayBkaXNhYmxlZCc7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB0aGlzLmlubmVySFRNTCA9IG11dGVkSW5kaWNhdG9yICtcbiAgICAgICAgICAgICAgICBcIiA8ZGl2IHN0eWxlPSd3aWR0aDogOTBweDttYXJnaW4tbGVmdDogMjBweDsnIGRhdGEtaTE4bj0ndmlkZW90aHVtYm5haWwuZG9tdXRlJz48L2Rpdj5cIjtcbiAgICAgICAgICAgIHRoaXMuY2xhc3NOYW1lID0gJ211dGVsaW5rJztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBtdXRlTWVudUl0ZW0uYXBwZW5kQ2hpbGQobXV0ZUxpbmtJdGVtKTtcbiAgICBwb3B1cG1lbnVFbGVtZW50LmFwcGVuZENoaWxkKG11dGVNZW51SXRlbSk7XG5cbiAgICB2YXIgZWplY3RJbmRpY2F0b3IgPSBcIjxpIHN0eWxlPSdmbG9hdDpsZWZ0OycgY2xhc3M9J2ZhIGZhLWVqZWN0Jz48L2k+XCI7XG5cbiAgICB2YXIgZWplY3RNZW51SXRlbSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2xpJyk7XG4gICAgdmFyIGVqZWN0TGlua0l0ZW0gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdhJyk7XG4gICAgdmFyIGVqZWN0VGV4dCA9IFwiPGRpdiBzdHlsZT0nd2lkdGg6IDkwcHg7bWFyZ2luLWxlZnQ6IDIwcHg7JyBkYXRhLWkxOG49J3ZpZGVvdGh1bWJuYWlsLmtpY2snPiZuYnNwOzwvZGl2PlwiO1xuICAgIGVqZWN0TGlua0l0ZW0uaW5uZXJIVE1MID0gZWplY3RJbmRpY2F0b3IgKyAnICcgKyBlamVjdFRleHQ7XG4gICAgZWplY3RMaW5rSXRlbS5vbmNsaWNrID0gZnVuY3Rpb24oKXtcbiAgICAgICAgQVBQLnhtcHAuZWplY3QoamlkKTtcbiAgICAgICAgcG9wdXBtZW51RWxlbWVudC5zZXRBdHRyaWJ1dGUoJ3N0eWxlJywgJ2Rpc3BsYXk6bm9uZTsnKTtcbiAgICB9O1xuXG4gICAgZWplY3RNZW51SXRlbS5hcHBlbmRDaGlsZChlamVjdExpbmtJdGVtKTtcbiAgICBwb3B1cG1lbnVFbGVtZW50LmFwcGVuZENoaWxkKGVqZWN0TWVudUl0ZW0pO1xuXG4gICAgdmFyIHBhZGRpbmdTcGFuID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgIHBhZGRpbmdTcGFuLmNsYXNzTmFtZSA9ICdwb3B1cG1lbnVQYWRkaW5nJztcbiAgICBwb3B1cG1lbnVFbGVtZW50LmFwcGVuZENoaWxkKHBhZGRpbmdTcGFuKTtcbiAgICBBUFAudHJhbnNsYXRpb24udHJhbnNsYXRlRWxlbWVudCgkKFwiI1wiICsgcG9wdXBtZW51RWxlbWVudC5pZCArIFwiID4gbGkgPiBhID4gZGl2XCIpKTtcbn1cblxuLyoqXG4gKiBSZW1vdmVzIHJlbW90ZSB2aWRlbyBtZW51IGVsZW1lbnQgZnJvbSB2aWRlbyBlbGVtZW50IGlkZW50aWZpZWQgYnlcbiAqIGdpdmVuIDx0dD52aWRlb0VsZW1lbnRJZDwvdHQ+LlxuICpcbiAqIEBwYXJhbSB2aWRlb0VsZW1lbnRJZCB0aGUgaWQgb2YgbG9jYWwgb3IgcmVtb3RlIHZpZGVvIGVsZW1lbnQuXG4gKi9cbmZ1bmN0aW9uIHJlbW92ZVJlbW90ZVZpZGVvTWVudSh2aWRlb0VsZW1lbnRJZCkge1xuICAgIHZhciBtZW51U3BhbiA9ICQoJyMnICsgdmlkZW9FbGVtZW50SWQgKyAnPnNwYW4ucmVtb3RldmlkZW9tZW51Jyk7XG4gICAgaWYgKG1lbnVTcGFuLmxlbmd0aCkge1xuICAgICAgICBtZW51U3Bhbi5yZW1vdmUoKTtcbiAgICB9XG59XG5cbi8qKlxuICogVXBkYXRlcyB0aGUgZGF0YSBmb3IgdGhlIGluZGljYXRvclxuICogQHBhcmFtIGlkIHRoZSBpZCBvZiB0aGUgaW5kaWNhdG9yXG4gKiBAcGFyYW0gcGVyY2VudCB0aGUgcGVyY2VudCBmb3IgY29ubmVjdGlvbiBxdWFsaXR5XG4gKiBAcGFyYW0gb2JqZWN0IHRoZSBkYXRhXG4gKi9cbmZ1bmN0aW9uIHVwZGF0ZVN0YXRzSW5kaWNhdG9yKGlkLCBwZXJjZW50LCBvYmplY3QpIHtcbiAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tpZF0pXG4gICAgICAgIFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW2lkXS51cGRhdGVDb25uZWN0aW9uUXVhbGl0eShwZXJjZW50LCBvYmplY3QpO1xufVxuXG5cbi8qKlxuICogUmV0dXJucyBhbiBhcnJheSBvZiB0aGUgdmlkZW8gZGltZW5zaW9ucywgc28gdGhhdCBpdCBrZWVwcyBpdCdzIGFzcGVjdFxuICogcmF0aW8gYW5kIGZpdHMgYXZhaWxhYmxlIGFyZWEgd2l0aCBpdCdzIGxhcmdlciBkaW1lbnNpb24uIFRoaXMgbWV0aG9kXG4gKiBlbnN1cmVzIHRoYXQgd2hvbGUgdmlkZW8gd2lsbCBiZSB2aXNpYmxlIGFuZCBjYW4gbGVhdmUgZW1wdHkgYXJlYXMuXG4gKlxuICogQHJldHVybiBhbiBhcnJheSB3aXRoIDIgZWxlbWVudHMsIHRoZSB2aWRlbyB3aWR0aCBhbmQgdGhlIHZpZGVvIGhlaWdodFxuICovXG5mdW5jdGlvbiBnZXREZXNrdG9wVmlkZW9TaXplKHZpZGVvV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1NwYWNlV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3BhY2VIZWlnaHQpIHtcbiAgICBpZiAoIXZpZGVvV2lkdGgpXG4gICAgICAgIHZpZGVvV2lkdGggPSBjdXJyZW50VmlkZW9XaWR0aDtcbiAgICBpZiAoIXZpZGVvSGVpZ2h0KVxuICAgICAgICB2aWRlb0hlaWdodCA9IGN1cnJlbnRWaWRlb0hlaWdodDtcblxuICAgIHZhciBhc3BlY3RSYXRpbyA9IHZpZGVvV2lkdGggLyB2aWRlb0hlaWdodDtcblxuICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IE1hdGgubWF4KHZpZGVvV2lkdGgsIHZpZGVvU3BhY2VXaWR0aCk7XG4gICAgdmFyIGF2YWlsYWJsZUhlaWdodCA9IE1hdGgubWF4KHZpZGVvSGVpZ2h0LCB2aWRlb1NwYWNlSGVpZ2h0KTtcblxuICAgIHZpZGVvU3BhY2VIZWlnaHQgLT0gJCgnI3JlbW90ZVZpZGVvcycpLm91dGVySGVpZ2h0KCk7XG5cbiAgICBpZiAoYXZhaWxhYmxlV2lkdGggLyBhc3BlY3RSYXRpbyA+PSB2aWRlb1NwYWNlSGVpZ2h0KVxuICAgIHtcbiAgICAgICAgYXZhaWxhYmxlSGVpZ2h0ID0gdmlkZW9TcGFjZUhlaWdodDtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSBhdmFpbGFibGVIZWlnaHQgKiBhc3BlY3RSYXRpbztcbiAgICB9XG5cbiAgICBpZiAoYXZhaWxhYmxlSGVpZ2h0ICogYXNwZWN0UmF0aW8gPj0gdmlkZW9TcGFjZVdpZHRoKVxuICAgIHtcbiAgICAgICAgYXZhaWxhYmxlV2lkdGggPSB2aWRlb1NwYWNlV2lkdGg7XG4gICAgICAgIGF2YWlsYWJsZUhlaWdodCA9IGF2YWlsYWJsZVdpZHRoIC8gYXNwZWN0UmF0aW87XG4gICAgfVxuXG4gICAgcmV0dXJuIFthdmFpbGFibGVXaWR0aCwgYXZhaWxhYmxlSGVpZ2h0XTtcbn1cblxuLyoqXG4gKiBDcmVhdGVzIHRoZSBlZGl0IGRpc3BsYXkgbmFtZSBidXR0b24uXG4gKlxuICogQHJldHVybnMgdGhlIGVkaXQgYnV0dG9uXG4gKi9cbmZ1bmN0aW9uIGNyZWF0ZUVkaXREaXNwbGF5TmFtZUJ1dHRvbigpIHtcbiAgICB2YXIgZWRpdEJ1dHRvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2EnKTtcbiAgICBlZGl0QnV0dG9uLmNsYXNzTmFtZSA9ICdkaXNwbGF5bmFtZSc7XG4gICAgVUlVdGlsLnNldFRvb2x0aXAoZWRpdEJ1dHRvbixcbiAgICAgICAgXCJ2aWRlb3RodW1ibmFpbC5lZGl0bmlja25hbWVcIixcbiAgICAgICAgXCJ0b3BcIik7XG4gICAgZWRpdEJ1dHRvbi5pbm5lckhUTUwgPSAnPGkgY2xhc3M9XCJmYSBmYS1wZW5jaWxcIj48L2k+JztcblxuICAgIHJldHVybiBlZGl0QnV0dG9uO1xufVxuXG4vKipcbiAqIENyZWF0ZXMgdGhlIGVsZW1lbnQgaW5kaWNhdGluZyB0aGUgbW9kZXJhdG9yKG93bmVyKSBvZiB0aGUgY29uZmVyZW5jZS5cbiAqXG4gKiBAcGFyYW0gcGFyZW50RWxlbWVudCB0aGUgcGFyZW50IGVsZW1lbnQgd2hlcmUgdGhlIG93bmVyIGluZGljYXRvciB3aWxsXG4gKiBiZSBhZGRlZFxuICovXG5mdW5jdGlvbiBjcmVhdGVNb2RlcmF0b3JJbmRpY2F0b3JFbGVtZW50KHBhcmVudEVsZW1lbnQpIHtcbiAgICB2YXIgbW9kZXJhdG9ySW5kaWNhdG9yID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaScpO1xuICAgIG1vZGVyYXRvckluZGljYXRvci5jbGFzc05hbWUgPSAnZmEgZmEtc3Rhcic7XG4gICAgcGFyZW50RWxlbWVudC5hcHBlbmRDaGlsZChtb2RlcmF0b3JJbmRpY2F0b3IpO1xuXG4gICAgVUlVdGlsLnNldFRvb2x0aXAocGFyZW50RWxlbWVudCxcbiAgICAgICAgXCJ2aWRlb3RodW1ibmFpbC5tb2RlcmF0b3JcIixcbiAgICAgICAgXCJ0b3BcIik7XG59XG5cblxudmFyIFZpZGVvTGF5b3V0ID0gKGZ1bmN0aW9uIChteSkge1xuICAgIG15LmNvbm5lY3Rpb25JbmRpY2F0b3JzID0ge307XG5cbiAgICAvLyBCeSBkZWZhdWx0IHdlIHVzZSBjYW1lcmFcbiAgICBteS5nZXRWaWRlb1NpemUgPSBnZXRDYW1lcmFWaWRlb1NpemU7XG4gICAgbXkuZ2V0VmlkZW9Qb3NpdGlvbiA9IGdldENhbWVyYVZpZGVvUG9zaXRpb247XG5cbiAgICBteS5pbml0ID0gZnVuY3Rpb24gKGVtaXR0ZXIpIHtcbiAgICAgICAgLy8gTGlzdGVuIGZvciBsYXJnZSB2aWRlbyBzaXplIHVwZGF0ZXNcbiAgICAgICAgZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xhcmdlVmlkZW8nKVxuICAgICAgICAgICAgLmFkZEV2ZW50TGlzdGVuZXIoJ2xvYWRlZG1ldGFkYXRhJywgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgICAgICBjdXJyZW50VmlkZW9XaWR0aCA9IHRoaXMudmlkZW9XaWR0aDtcbiAgICAgICAgICAgICAgICBjdXJyZW50VmlkZW9IZWlnaHQgPSB0aGlzLnZpZGVvSGVpZ2h0O1xuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnBvc2l0aW9uTGFyZ2UoY3VycmVudFZpZGVvV2lkdGgsIGN1cnJlbnRWaWRlb0hlaWdodCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgZXZlbnRFbWl0dGVyID0gZW1pdHRlcjtcbiAgICB9O1xuXG4gICAgbXkuaXNJbkxhc3ROID0gZnVuY3Rpb24ocmVzb3VyY2UpIHtcbiAgICAgICAgcmV0dXJuIGxhc3ROQ291bnQgPCAwIC8vIGxhc3ROIGlzIGRpc2FibGVkLCByZXR1cm4gdHJ1ZVxuICAgICAgICAgICAgfHwgKGxhc3ROQ291bnQgPiAwICYmIGxhc3RORW5kcG9pbnRzQ2FjaGUubGVuZ3RoID09IDApIC8vIGxhc3RORW5kcG9pbnRzIGNhY2hlIG5vdCBidWlsdCB5ZXQsIHJldHVybiB0cnVlXG4gICAgICAgICAgICB8fCAobGFzdE5FbmRwb2ludHNDYWNoZSAmJiBsYXN0TkVuZHBvaW50c0NhY2hlLmluZGV4T2YocmVzb3VyY2UpICE9PSAtMSk7XG4gICAgfTtcblxuICAgIG15LmNoYW5nZUxvY2FsU3RyZWFtID0gZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICBWaWRlb0xheW91dC5jaGFuZ2VMb2NhbFZpZGVvKHN0cmVhbSk7XG4gICAgfTtcblxuICAgIG15LmNoYW5nZUxvY2FsQXVkaW8gPSBmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgQVBQLlJUQy5hdHRhY2hNZWRpYVN0cmVhbSgkKCcjbG9jYWxBdWRpbycpLCBzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKSk7XG4gICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2NhbEF1ZGlvJykuYXV0b3BsYXkgPSB0cnVlO1xuICAgICAgICBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgnbG9jYWxBdWRpbycpLnZvbHVtZSA9IDA7XG4gICAgICAgIGlmIChwcmVNdXRlZCkge1xuICAgICAgICAgICAgaWYoIUFQUC5VSS5zZXRBdWRpb011dGVkKHRydWUpKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHByZU11dGVkID0gbXV0ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHByZU11dGVkID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgbXkuY2hhbmdlTG9jYWxWaWRlbyA9IGZ1bmN0aW9uKHN0cmVhbSkge1xuICAgICAgICB2YXIgZmxpcFggPSB0cnVlO1xuICAgICAgICBpZihzdHJlYW0udmlkZW9UeXBlID09IFwic2NyZWVuXCIpXG4gICAgICAgICAgICBmbGlwWCA9IGZhbHNlO1xuICAgICAgICB2YXIgbG9jYWxWaWRlbyA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3ZpZGVvJyk7XG4gICAgICAgIGxvY2FsVmlkZW8uaWQgPSAnbG9jYWxWaWRlb18nICtcbiAgICAgICAgICAgIEFQUC5SVEMuZ2V0U3RyZWFtSUQoc3RyZWFtLmdldE9yaWdpbmFsU3RyZWFtKCkpO1xuICAgICAgICBsb2NhbFZpZGVvLmF1dG9wbGF5ID0gdHJ1ZTtcbiAgICAgICAgbG9jYWxWaWRlby52b2x1bWUgPSAwOyAvLyBpcyBpdCByZXF1aXJlZCBpZiBhdWRpbyBpcyBzZXBhcmF0ZWQgP1xuICAgICAgICBsb2NhbFZpZGVvLm9uY29udGV4dG1lbnUgPSBmdW5jdGlvbiAoKSB7IHJldHVybiBmYWxzZTsgfTtcblxuICAgICAgICB2YXIgbG9jYWxWaWRlb0NvbnRhaW5lciA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsb2NhbFZpZGVvV3JhcHBlcicpO1xuICAgICAgICBsb2NhbFZpZGVvQ29udGFpbmVyLmFwcGVuZENoaWxkKGxvY2FsVmlkZW8pO1xuXG4gICAgICAgIC8vIFNldCBkZWZhdWx0IGRpc3BsYXkgbmFtZS5cbiAgICAgICAgc2V0RGlzcGxheU5hbWUoJ2xvY2FsVmlkZW9Db250YWluZXInKTtcblxuICAgICAgICBpZighVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbXCJsb2NhbFZpZGVvQ29udGFpbmVyXCJdKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tcImxvY2FsVmlkZW9Db250YWluZXJcIl1cbiAgICAgICAgICAgICAgICA9IG5ldyBDb25uZWN0aW9uSW5kaWNhdG9yKCQoXCIjbG9jYWxWaWRlb0NvbnRhaW5lclwiKVswXSwgbnVsbCwgVmlkZW9MYXlvdXQpO1xuICAgICAgICB9XG5cbiAgICAgICAgQXVkaW9MZXZlbHMudXBkYXRlQXVkaW9MZXZlbENhbnZhcyhudWxsLCBWaWRlb0xheW91dCk7XG5cbiAgICAgICAgdmFyIGxvY2FsVmlkZW9TZWxlY3RvciA9ICQoJyMnICsgbG9jYWxWaWRlby5pZCk7XG5cbiAgICAgICAgZnVuY3Rpb24gbG9jYWxWaWRlb0NsaWNrKGV2ZW50KSB7XG4gICAgICAgICAgICBldmVudC5zdG9wUHJvcGFnYXRpb24oKTtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmhhbmRsZVZpZGVvVGh1bWJDbGlja2VkKFxuICAgICAgICAgICAgICAgIEFQUC5SVEMuZ2V0VmlkZW9TcmMobG9jYWxWaWRlbyksXG4gICAgICAgICAgICAgICAgZmFsc2UsXG4gICAgICAgICAgICAgICAgQVBQLnhtcHAubXlSZXNvdXJjZSgpKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBBZGQgY2xpY2sgaGFuZGxlciB0byBib3RoIHZpZGVvIGFuZCB2aWRlbyB3cmFwcGVyIGVsZW1lbnRzIGluIGNhc2VcbiAgICAgICAgLy8gdGhlcmUncyBubyB2aWRlby5cbiAgICAgICAgbG9jYWxWaWRlb1NlbGVjdG9yLmNsaWNrKGxvY2FsVmlkZW9DbGljayk7XG4gICAgICAgICQoJyNsb2NhbFZpZGVvQ29udGFpbmVyJykuY2xpY2sobG9jYWxWaWRlb0NsaWNrKTtcblxuICAgICAgICAvLyBBZGQgaG92ZXIgaGFuZGxlclxuICAgICAgICAkKCcjbG9jYWxWaWRlb0NvbnRhaW5lcicpLmhvdmVyKFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2hvd0Rpc3BsYXlOYW1lKCdsb2NhbFZpZGVvQ29udGFpbmVyJywgdHJ1ZSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgaWYgKCFWaWRlb0xheW91dC5pc0xhcmdlVmlkZW9WaXNpYmxlKClcbiAgICAgICAgICAgICAgICAgICAgICAgIHx8IEFQUC5SVEMuZ2V0VmlkZW9TcmMobG9jYWxWaWRlbykgIT09IEFQUC5SVEMuZ2V0VmlkZW9TcmMoJCgnI2xhcmdlVmlkZW8nKVswXSkpXG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNob3dEaXNwbGF5TmFtZSgnbG9jYWxWaWRlb0NvbnRhaW5lcicsIGZhbHNlKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICAgICAgLy8gQWRkIHN0cmVhbSBlbmRlZCBoYW5kbGVyXG4gICAgICAgIHN0cmVhbS5nZXRPcmlnaW5hbFN0cmVhbSgpLm9uZW5kZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBsb2NhbFZpZGVvQ29udGFpbmVyLnJlbW92ZUNoaWxkKGxvY2FsVmlkZW8pO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlUmVtb3ZlZFZpZGVvKEFQUC5SVEMuZ2V0VmlkZW9TcmMobG9jYWxWaWRlbykpO1xuICAgICAgICB9O1xuICAgICAgICAvLyBGbGlwIHZpZGVvIHggYXhpcyBpZiBuZWVkZWRcbiAgICAgICAgZmxpcFhMb2NhbFZpZGVvID0gZmxpcFg7XG4gICAgICAgIGlmIChmbGlwWCkge1xuICAgICAgICAgICAgbG9jYWxWaWRlb1NlbGVjdG9yLmFkZENsYXNzKFwiZmxpcFZpZGVvWFwiKTtcbiAgICAgICAgfVxuICAgICAgICAvLyBBdHRhY2ggV2ViUlRDIHN0cmVhbVxuICAgICAgICB2YXIgdmlkZW9TdHJlYW0gPSBBUFAuc2ltdWxjYXN0LmdldExvY2FsVmlkZW9TdHJlYW0oKTtcbiAgICAgICAgQVBQLlJUQy5hdHRhY2hNZWRpYVN0cmVhbShsb2NhbFZpZGVvU2VsZWN0b3IsIHZpZGVvU3RyZWFtKTtcblxuICAgICAgICBsb2NhbFZpZGVvU3JjID0gQVBQLlJUQy5nZXRWaWRlb1NyYyhsb2NhbFZpZGVvKTtcblxuICAgICAgICB2YXIgbXlSZXNvdXJjZUppZCA9IEFQUC54bXBwLm15UmVzb3VyY2UoKTtcblxuICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKGxvY2FsVmlkZW9TcmMsIDAsXG4gICAgICAgICAgICBteVJlc291cmNlSmlkKTtcblxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBDaGVja3MgaWYgcmVtb3ZlZCB2aWRlbyBpcyBjdXJyZW50bHkgZGlzcGxheWVkIGFuZCB0cmllcyB0byBkaXNwbGF5XG4gICAgICogYW5vdGhlciBvbmUgaW5zdGVhZC5cbiAgICAgKiBAcGFyYW0gcmVtb3ZlZFZpZGVvU3JjIHNyYyBzdHJlYW0gaWRlbnRpZmllciBvZiB0aGUgdmlkZW8uXG4gICAgICovXG4gICAgbXkudXBkYXRlUmVtb3ZlZFZpZGVvID0gZnVuY3Rpb24ocmVtb3ZlZFZpZGVvU3JjKSB7XG4gICAgICAgIGlmIChyZW1vdmVkVmlkZW9TcmMgPT09IEFQUC5SVEMuZ2V0VmlkZW9TcmMoJCgnI2xhcmdlVmlkZW8nKVswXSkpIHtcbiAgICAgICAgICAgIC8vIHRoaXMgaXMgY3VycmVudGx5IGRpc3BsYXllZCBhcyBsYXJnZVxuICAgICAgICAgICAgLy8gcGljayB0aGUgbGFzdCB2aXNpYmxlIHZpZGVvIGluIHRoZSByb3dcbiAgICAgICAgICAgIC8vIGlmIG5vYm9keSBlbHNlIGlzIGxlZnQsIHRoaXMgcGlja3MgdGhlIGxvY2FsIHZpZGVvXG4gICAgICAgICAgICB2YXIgcGlja1xuICAgICAgICAgICAgICAgID0gJCgnI3JlbW90ZVZpZGVvcz5zcGFuW2lkIT1cIm1peGVkc3RyZWFtXCJdOnZpc2libGU6bGFzdD52aWRlbycpXG4gICAgICAgICAgICAgICAgICAgIC5nZXQoMCk7XG5cbiAgICAgICAgICAgIGlmICghcGljaykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkxhc3QgdmlzaWJsZSB2aWRlbyBubyBsb25nZXIgZXhpc3RzXCIpO1xuICAgICAgICAgICAgICAgIHBpY2sgPSAkKCcjcmVtb3RlVmlkZW9zPnNwYW5baWQhPVwibWl4ZWRzdHJlYW1cIl0+dmlkZW8nKS5nZXQoMCk7XG5cbiAgICAgICAgICAgICAgICBpZiAoIXBpY2sgfHwgIUFQUC5SVEMuZ2V0VmlkZW9TcmMocGljaykpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gVHJ5IGxvY2FsIHZpZGVvXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkZhbGxiYWNrIHRvIGxvY2FsIHZpZGVvLi4uXCIpO1xuICAgICAgICAgICAgICAgICAgICBwaWNrID0gJCgnI3JlbW90ZVZpZGVvcz5zcGFuPnNwYW4+dmlkZW8nKS5nZXQoMCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBtdXRlIGlmIGxvY2FsdmlkZW9cbiAgICAgICAgICAgIGlmIChwaWNrKSB7XG4gICAgICAgICAgICAgICAgdmFyIGNvbnRhaW5lciA9IHBpY2sucGFyZW50Tm9kZTtcbiAgICAgICAgICAgICAgICB2YXIgamlkID0gbnVsbDtcbiAgICAgICAgICAgICAgICBpZihjb250YWluZXIpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBpZihjb250YWluZXIuaWQgPT0gXCJsb2NhbFZpZGVvV3JhcHBlclwiKVxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBqaWQgPSBBUFAueG1wcC5teVJlc291cmNlKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBqaWQgPSBWaWRlb0xheW91dC5nZXRQZWVyQ29udGFpbmVyUmVzb3VyY2VKaWQoY29udGFpbmVyKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8oQVBQLlJUQy5nZXRWaWRlb1NyYyhwaWNrKSwgcGljay52b2x1bWUsIGppZCk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIkZhaWxlZCB0byBlbGVjdCBsYXJnZSB2aWRlb1wiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG4gICAgXG4gICAgbXkub25SZW1vdGVTdHJlYW1BZGRlZCA9IGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgdmFyIGNvbnRhaW5lcjtcbiAgICAgICAgdmFyIHJlbW90ZXMgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmVtb3RlVmlkZW9zJyk7XG5cbiAgICAgICAgaWYgKHN0cmVhbS5wZWVyamlkKSB7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5lbnN1cmVQZWVyQ29udGFpbmVyRXhpc3RzKHN0cmVhbS5wZWVyamlkKTtcblxuICAgICAgICAgICAgY29udGFpbmVyICA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKFxuICAgICAgICAgICAgICAgICAgICAncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKHN0cmVhbS5wZWVyamlkKSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB2YXIgaWQgPSBzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKS5pZDtcbiAgICAgICAgICAgIGlmIChpZCAhPT0gJ21peGVkbXNsYWJlbCdcbiAgICAgICAgICAgICAgICAvLyBGSVhNRTogZGVmYXVsdCBzdHJlYW0gaXMgYWRkZWQgYWx3YXlzIHdpdGggbmV3IGZvY3VzXG4gICAgICAgICAgICAgICAgLy8gKHRvIGJlIGludmVzdGlnYXRlZClcbiAgICAgICAgICAgICAgICAmJiBpZCAhPT0gJ2RlZmF1bHQnKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignY2FuIG5vdCBhc3NvY2lhdGUgc3RyZWFtJyxcbiAgICAgICAgICAgICAgICAgICAgaWQsXG4gICAgICAgICAgICAgICAgICAgICd3aXRoIGEgcGFydGljaXBhbnQnKTtcbiAgICAgICAgICAgICAgICAvLyBXZSBkb24ndCB3YW50IHRvIGFkZCBpdCBoZXJlIHNpbmNlIGl0IHdpbGwgY2F1c2UgdHJvdWJsZXNcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBGSVhNRTogZm9yIHRoZSBtaXhlZCBtcyB3ZSBkb250IG5lZWQgYSB2aWRlbyAtLSBjdXJyZW50bHlcbiAgICAgICAgICAgIGNvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICAgICAgICAgIGNvbnRhaW5lci5pZCA9ICdtaXhlZHN0cmVhbSc7XG4gICAgICAgICAgICBjb250YWluZXIuY2xhc3NOYW1lID0gJ3ZpZGVvY29udGFpbmVyJztcbiAgICAgICAgICAgIHJlbW90ZXMuYXBwZW5kQ2hpbGQoY29udGFpbmVyKTtcbiAgICAgICAgICAgIFVJVXRpbC5wbGF5U291bmROb3RpZmljYXRpb24oJ3VzZXJKb2luZWQnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChjb250YWluZXIpIHtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmFkZFJlbW90ZVN0cmVhbUVsZW1lbnQoIGNvbnRhaW5lcixcbiAgICAgICAgICAgICAgICBzdHJlYW0uc2lkLFxuICAgICAgICAgICAgICAgIHN0cmVhbS5nZXRPcmlnaW5hbFN0cmVhbSgpLFxuICAgICAgICAgICAgICAgIHN0cmVhbS5wZWVyamlkLFxuICAgICAgICAgICAgICAgIHN0cmVhbS5zc3JjKTtcbiAgICAgICAgfVxuICAgIH1cblxuICAgIG15LmdldExhcmdlVmlkZW9TdGF0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGxhcmdlVmlkZW9TdGF0ZTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgbGFyZ2UgdmlkZW8gd2l0aCB0aGUgZ2l2ZW4gbmV3IHZpZGVvIHNvdXJjZS5cbiAgICAgKi9cbiAgICBteS51cGRhdGVMYXJnZVZpZGVvID0gZnVuY3Rpb24obmV3U3JjLCB2b2wsIHJlc291cmNlSmlkKSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdob3ZlciBpbicsIG5ld1NyYyk7XG5cbiAgICAgICAgaWYgKEFQUC5SVEMuZ2V0VmlkZW9TcmMoJCgnI2xhcmdlVmlkZW8nKVswXSkgIT09IG5ld1NyYykge1xuXG4gICAgICAgICAgICAkKCcjYWN0aXZlU3BlYWtlcicpLmNzcygndmlzaWJpbGl0eScsICdoaWRkZW4nKTtcbiAgICAgICAgICAgIC8vIER1ZSB0byB0aGUgc2ltdWxjYXN0IHRoZSBsb2NhbFZpZGVvU3JjIG1heSBoYXZlIGNoYW5nZWQgd2hlbiB0aGVcbiAgICAgICAgICAgIC8vIGZhZGVPdXQgZXZlbnQgdHJpZ2dlcnMuIEluIHRoYXQgY2FzZSB0aGUgZ2V0SmlkRnJvbVZpZGVvU3JjIGFuZFxuICAgICAgICAgICAgLy8gaXNWaWRlb1NyY0Rlc2t0b3AgbWV0aG9kcyB3aWxsIG5vdCBmdW5jdGlvbiBjb3JyZWN0bHkuXG4gICAgICAgICAgICAvL1xuICAgICAgICAgICAgLy8gQWxzbywgYWdhaW4gZHVlIHRvIHRoZSBzaW11bGNhc3QsIHRoZSB1cGRhdGVMYXJnZVZpZGVvIG1ldGhvZCBjYW5cbiAgICAgICAgICAgIC8vIGJlIGNhbGxlZCBtdWx0aXBsZSB0aW1lcyBhbG1vc3Qgc2ltdWx0YW5lb3VzbHkuIFRoZXJlZm9yZSwgd2VcbiAgICAgICAgICAgIC8vIHN0b3JlIHRoZSBzdGF0ZSBoZXJlIGFuZCB1cGRhdGUgb25seSBvbmNlLlxuXG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUubmV3U3JjID0gbmV3U3JjO1xuICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLmlzVmlzaWJsZSA9ICQoJyNsYXJnZVZpZGVvJykuaXMoJzp2aXNpYmxlJyk7XG4gICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUuaXNEZXNrdG9wID0gQVBQLlJUQy5pc1ZpZGVvU3JjRGVza3RvcChyZXNvdXJjZUppZCk7XG4gICAgICAgICAgICBpZihsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkKSB7XG4gICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLm9sZFJlc291cmNlSmlkID0gbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLm9sZFJlc291cmNlSmlkID0gbnVsbDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQgPSByZXNvdXJjZUppZDtcblxuICAgICAgICAgICAgLy8gU2NyZWVuIHN0cmVhbSBpcyBhbHJlYWR5IHJvdGF0ZWRcbiAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5mbGlwWCA9IChuZXdTcmMgPT09IGxvY2FsVmlkZW9TcmMpICYmIGZsaXBYTG9jYWxWaWRlbztcblxuICAgICAgICAgICAgdmFyIHVzZXJDaGFuZ2VkID0gZmFsc2U7XG4gICAgICAgICAgICBpZiAobGFyZ2VWaWRlb1N0YXRlLm9sZFJlc291cmNlSmlkICE9PSBsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkKSB7XG4gICAgICAgICAgICAgICAgdXNlckNoYW5nZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIC8vIHdlIHdhbnQgdGhlIG5vdGlmaWNhdGlvbiB0byB0cmlnZ2VyIGV2ZW4gaWYgdXNlckppZCBpcyB1bmRlZmluZWQsXG4gICAgICAgICAgICAgICAgLy8gb3IgbnVsbC5cbiAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChVSUV2ZW50cy5TRUxFQ1RFRF9FTkRQT0lOVCxcbiAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghbGFyZ2VWaWRlb1N0YXRlLnVwZGF0ZUluUHJvZ3Jlc3MpIHtcbiAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUudXBkYXRlSW5Qcm9ncmVzcyA9IHRydWU7XG5cbiAgICAgICAgICAgICAgICB2YXIgZG9VcGRhdGUgPSBmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgQXZhdGFyLnVwZGF0ZUFjdGl2ZVNwZWFrZXJBdmF0YXJTcmMoXG4gICAgICAgICAgICAgICAgICAgICAgICBBUFAueG1wcC5maW5kSmlkRnJvbVJlc291cmNlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQpKTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAoIXVzZXJDaGFuZ2VkICYmIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkICYmXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUucHJlbG9hZCAhPT0gbnVsbCAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5nZXRWaWRlb1NyYygkKGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkKVswXSkgPT09IG5ld1NyYylcbiAgICAgICAgICAgICAgICAgICAge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oJ1N3aXRjaGluZyB0byBwcmVsb2FkZWQgdmlkZW8nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhdHRyaWJ1dGVzID0gJCgnI2xhcmdlVmlkZW8nKS5wcm9wKFwiYXR0cmlidXRlc1wiKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gbG9vcCB0aHJvdWdoIGxhcmdlVmlkZW8gYXR0cmlidXRlcyBhbmQgYXBwbHkgdGhlbSBvblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gcHJlbG9hZC5cbiAgICAgICAgICAgICAgICAgICAgICAgICQuZWFjaChhdHRyaWJ1dGVzLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMubmFtZSAhPT0gJ2lkJyAmJiB0aGlzLm5hbWUgIT09ICdzcmMnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkLmF0dHIodGhpcy5uYW1lLCB0aGlzLnZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQuYXBwZW5kVG8oJCgnI2xhcmdlVmlkZW9Db250YWluZXInKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAkKCcjbGFyZ2VWaWRlbycpLmF0dHIoJ2lkJywgJ3ByZXZpb3VzTGFyZ2VWaWRlbycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQuYXR0cignaWQnLCAnbGFyZ2VWaWRlbycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgJCgnI3ByZXZpb3VzTGFyZ2VWaWRlbycpLnJlbW92ZSgpO1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUucHJlbG9hZC5vbignbG9hZGVkbWV0YWRhdGEnLCBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRWaWRlb1dpZHRoID0gdGhpcy52aWRlb1dpZHRoO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGN1cnJlbnRWaWRlb0hlaWdodCA9IHRoaXMudmlkZW9IZWlnaHQ7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQucG9zaXRpb25MYXJnZShjdXJyZW50VmlkZW9XaWR0aCwgY3VycmVudFZpZGVvSGVpZ2h0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWRfc3NyYyA9IDA7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBBUFAuUlRDLnNldFZpZGVvU3JjKCQoJyNsYXJnZVZpZGVvJylbMF0sIGxhcmdlVmlkZW9TdGF0ZS5uZXdTcmMpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIHZpZGVvVHJhbnNmb3JtID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQoJ2xhcmdlVmlkZW8nKVxuICAgICAgICAgICAgICAgICAgICAgICAgLnN0eWxlLndlYmtpdFRyYW5zZm9ybTtcblxuICAgICAgICAgICAgICAgICAgICBpZiAobGFyZ2VWaWRlb1N0YXRlLmZsaXBYICYmIHZpZGVvVHJhbnNmb3JtICE9PSAnc2NhbGVYKC0xKScpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsYXJnZVZpZGVvJykuc3R5bGUud2Via2l0VHJhbnNmb3JtXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPSBcInNjYWxlWCgtMSlcIjtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmICghbGFyZ2VWaWRlb1N0YXRlLmZsaXBYICYmIHZpZGVvVHJhbnNmb3JtID09PSAnc2NhbGVYKC0xKScpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdsYXJnZVZpZGVvJykuc3R5bGUud2Via2l0VHJhbnNmb3JtXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgPSBcIm5vbmVcIjtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIC8vIENoYW5nZSB0aGUgd2F5IHdlJ2xsIGJlIG1lYXN1cmluZyBhbmQgcG9zaXRpb25pbmcgbGFyZ2UgdmlkZW9cblxuICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5nZXRWaWRlb1NpemUgPSBsYXJnZVZpZGVvU3RhdGUuaXNEZXNrdG9wXG4gICAgICAgICAgICAgICAgICAgICAgICA/IGdldERlc2t0b3BWaWRlb1NpemVcbiAgICAgICAgICAgICAgICAgICAgICAgIDogZ2V0Q2FtZXJhVmlkZW9TaXplO1xuICAgICAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5nZXRWaWRlb1Bvc2l0aW9uID0gbGFyZ2VWaWRlb1N0YXRlLmlzRGVza3RvcFxuICAgICAgICAgICAgICAgICAgICAgICAgPyBnZXREZXNrdG9wVmlkZW9Qb3NpdGlvblxuICAgICAgICAgICAgICAgICAgICAgICAgOiBnZXRDYW1lcmFWaWRlb1Bvc2l0aW9uO1xuXG5cbiAgICAgICAgICAgICAgICAgICAgLy8gT25seSBpZiB0aGUgbGFyZ2UgdmlkZW8gaXMgY3VycmVudGx5IHZpc2libGUuXG4gICAgICAgICAgICAgICAgICAgIC8vIERpc2FibGUgcHJldmlvdXMgZG9taW5hbnQgc3BlYWtlciB2aWRlby5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGxhcmdlVmlkZW9TdGF0ZS5vbGRSZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5hYmxlRG9taW5hbnRTcGVha2VyKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS5vbGRSZXNvdXJjZUppZCxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmYWxzZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBFbmFibGUgbmV3IGRvbWluYW50IHNwZWFrZXIgaW4gdGhlIHJlbW90ZSB2aWRlb3Mgc2VjdGlvbi5cbiAgICAgICAgICAgICAgICAgICAgaWYgKGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmVuYWJsZURvbWluYW50U3BlYWtlcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRydWUpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYgKHVzZXJDaGFuZ2VkICYmIGxhcmdlVmlkZW9TdGF0ZS5pc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIHVzaW5nIFwidGhpc1wiIHNob3VsZCBiZSBvayBiZWNhdXNlIHdlJ3JlIGNhbGxlZFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gZnJvbSB3aXRoaW4gdGhlIGZhZGVPdXQgZXZlbnQuXG4gICAgICAgICAgICAgICAgICAgICAgICAkKHRoaXMpLmZhZGVJbigzMDApO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgaWYodXNlckNoYW5nZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIEF2YXRhci5zaG93VXNlckF2YXRhcihcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBBUFAueG1wcC5maW5kSmlkRnJvbVJlc291cmNlKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUub2xkUmVzb3VyY2VKaWQpKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgICAgIGxhcmdlVmlkZW9TdGF0ZS51cGRhdGVJblByb2dyZXNzID0gZmFsc2U7XG4gICAgICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgICAgIGlmICh1c2VyQ2hhbmdlZCkge1xuICAgICAgICAgICAgICAgICAgICAkKCcjbGFyZ2VWaWRlbycpLmZhZGVPdXQoMzAwLCBkb1VwZGF0ZSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgZG9VcGRhdGUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBBdmF0YXIuc2hvd1VzZXJBdmF0YXIoXG4gICAgICAgICAgICAgICAgQVBQLnhtcHAuZmluZEppZEZyb21SZXNvdXJjZShcbiAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZCkpO1xuICAgICAgICB9XG5cbiAgICB9O1xuXG4gICAgbXkuaGFuZGxlVmlkZW9UaHVtYkNsaWNrZWQgPSBmdW5jdGlvbih2aWRlb1NyYyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG5vUGlubmVkRW5kcG9pbnRDaGFuZ2VkRXZlbnQsIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzb3VyY2VKaWQpIHtcbiAgICAgICAgLy8gUmVzdG9yZSBzdHlsZSBmb3IgcHJldmlvdXNseSBmb2N1c2VkIHZpZGVvXG4gICAgICAgIHZhciBvbGRDb250YWluZXIgPSBudWxsO1xuICAgICAgICBpZihmb2N1c2VkVmlkZW9JbmZvKSB7XG4gICAgICAgICAgICB2YXIgZm9jdXNSZXNvdXJjZUppZCA9IGZvY3VzZWRWaWRlb0luZm8ucmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICBvbGRDb250YWluZXIgPSBnZXRQYXJ0aWNpcGFudENvbnRhaW5lcihmb2N1c1Jlc291cmNlSmlkKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChvbGRDb250YWluZXIpIHtcbiAgICAgICAgICAgIG9sZENvbnRhaW5lci5yZW1vdmVDbGFzcyhcInZpZGVvQ29udGFpbmVyRm9jdXNlZFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFVubG9jayBjdXJyZW50IGZvY3VzZWQuXG4gICAgICAgIGlmIChmb2N1c2VkVmlkZW9JbmZvICYmIGZvY3VzZWRWaWRlb0luZm8uc3JjID09PSB2aWRlb1NyYylcbiAgICAgICAge1xuICAgICAgICAgICAgZm9jdXNlZFZpZGVvSW5mbyA9IG51bGw7XG4gICAgICAgICAgICB2YXIgZG9taW5hbnRTcGVha2VyVmlkZW8gPSBudWxsO1xuICAgICAgICAgICAgLy8gRW5hYmxlIHRoZSBjdXJyZW50bHkgc2V0IGRvbWluYW50IHNwZWFrZXIuXG4gICAgICAgICAgICBpZiAoY3VycmVudERvbWluYW50U3BlYWtlcikge1xuICAgICAgICAgICAgICAgIGRvbWluYW50U3BlYWtlclZpZGVvXG4gICAgICAgICAgICAgICAgICAgID0gJCgnI3BhcnRpY2lwYW50XycgKyBjdXJyZW50RG9taW5hbnRTcGVha2VyICsgJz52aWRlbycpXG4gICAgICAgICAgICAgICAgICAgICAgICAuZ2V0KDApO1xuXG4gICAgICAgICAgICAgICAgaWYgKGRvbWluYW50U3BlYWtlclZpZGVvKSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8oXG4gICAgICAgICAgICAgICAgICAgICAgICBBUFAuUlRDLmdldFZpZGVvU3JjKGRvbWluYW50U3BlYWtlclZpZGVvKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIDEsXG4gICAgICAgICAgICAgICAgICAgICAgICBjdXJyZW50RG9taW5hbnRTcGVha2VyKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghbm9QaW5uZWRFbmRwb2ludENoYW5nZWRFdmVudCkge1xuICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFVJRXZlbnRzLlBJTk5FRF9FTkRQT0lOVCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBMb2NrIG5ldyB2aWRlb1xuICAgICAgICBmb2N1c2VkVmlkZW9JbmZvID0ge1xuICAgICAgICAgICAgc3JjOiB2aWRlb1NyYyxcbiAgICAgICAgICAgIHJlc291cmNlSmlkOiByZXNvdXJjZUppZFxuICAgICAgICB9O1xuXG4gICAgICAgIC8vIFVwZGF0ZSBmb2N1c2VkL3Bpbm5lZCBpbnRlcmZhY2UuXG4gICAgICAgIGlmIChyZXNvdXJjZUppZClcbiAgICAgICAge1xuICAgICAgICAgICAgdmFyIGNvbnRhaW5lciA9IGdldFBhcnRpY2lwYW50Q29udGFpbmVyKHJlc291cmNlSmlkKTtcbiAgICAgICAgICAgIGNvbnRhaW5lci5hZGRDbGFzcyhcInZpZGVvQ29udGFpbmVyRm9jdXNlZFwiKTtcblxuICAgICAgICAgICAgaWYgKCFub1Bpbm5lZEVuZHBvaW50Q2hhbmdlZEV2ZW50KSB7XG4gICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoVUlFdmVudHMuUElOTkVEX0VORFBPSU5ULCByZXNvdXJjZUppZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoJCgnI2xhcmdlVmlkZW8nKS5hdHRyKCdzcmMnKSA9PT0gdmlkZW9TcmMgJiZcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LmlzTGFyZ2VWaWRlb09uVG9wKCkpIHtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFRyaWdnZXJzIGEgXCJ2aWRlby5zZWxlY3RlZFwiIGV2ZW50LiBUaGUgXCJmYWxzZVwiIHBhcmFtZXRlciBpbmRpY2F0ZXNcbiAgICAgICAgLy8gdGhpcyBpc24ndCBhIHByZXppLlxuICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKFwidmlkZW8uc2VsZWN0ZWRcIiwgW2ZhbHNlXSk7XG5cbiAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlTGFyZ2VWaWRlbyh2aWRlb1NyYywgMSwgcmVzb3VyY2VKaWQpO1xuXG4gICAgICAgICQoJ2F1ZGlvJykuZWFjaChmdW5jdGlvbiAoaWR4LCBlbCkge1xuICAgICAgICAgICAgaWYgKGVsLmlkLmluZGV4T2YoJ21peGVkbXNsYWJlbCcpICE9PSAtMSkge1xuICAgICAgICAgICAgICAgIGVsLnZvbHVtZSA9IDA7XG4gICAgICAgICAgICAgICAgZWwudm9sdW1lID0gMTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFBvc2l0aW9ucyB0aGUgbGFyZ2UgdmlkZW8uXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdmlkZW9XaWR0aCB0aGUgc3RyZWFtIHZpZGVvIHdpZHRoXG4gICAgICogQHBhcmFtIHZpZGVvSGVpZ2h0IHRoZSBzdHJlYW0gdmlkZW8gaGVpZ2h0XG4gICAgICovXG4gICAgbXkucG9zaXRpb25MYXJnZSA9IGZ1bmN0aW9uICh2aWRlb1dpZHRoLCB2aWRlb0hlaWdodCkge1xuICAgICAgICB2YXIgdmlkZW9TcGFjZVdpZHRoID0gJCgnI3ZpZGVvc3BhY2UnKS53aWR0aCgpO1xuICAgICAgICB2YXIgdmlkZW9TcGFjZUhlaWdodCA9IHdpbmRvdy5pbm5lckhlaWdodDtcblxuICAgICAgICB2YXIgdmlkZW9TaXplID0gVmlkZW9MYXlvdXQuZ2V0VmlkZW9TaXplKHZpZGVvV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9IZWlnaHQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFjZVdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZpZGVvU3BhY2VIZWlnaHQpO1xuXG4gICAgICAgIHZhciBsYXJnZVZpZGVvV2lkdGggPSB2aWRlb1NpemVbMF07XG4gICAgICAgIHZhciBsYXJnZVZpZGVvSGVpZ2h0ID0gdmlkZW9TaXplWzFdO1xuXG4gICAgICAgIHZhciB2aWRlb1Bvc2l0aW9uID0gVmlkZW9MYXlvdXQuZ2V0VmlkZW9Qb3NpdGlvbihsYXJnZVZpZGVvV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvSGVpZ2h0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFjZVdpZHRoLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFjZUhlaWdodCk7XG5cbiAgICAgICAgdmFyIGhvcml6b250YWxJbmRlbnQgPSB2aWRlb1Bvc2l0aW9uWzBdO1xuICAgICAgICB2YXIgdmVydGljYWxJbmRlbnQgPSB2aWRlb1Bvc2l0aW9uWzFdO1xuXG4gICAgICAgIHBvc2l0aW9uVmlkZW8oJCgnI2xhcmdlVmlkZW8nKSxcbiAgICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvV2lkdGgsXG4gICAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb0hlaWdodCxcbiAgICAgICAgICAgICAgICAgICAgICBob3Jpem9udGFsSW5kZW50LCB2ZXJ0aWNhbEluZGVudCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzL2hpZGVzIHRoZSBsYXJnZSB2aWRlby5cbiAgICAgKi9cbiAgICBteS5zZXRMYXJnZVZpZGVvVmlzaWJsZSA9IGZ1bmN0aW9uKGlzVmlzaWJsZSkge1xuICAgICAgICB2YXIgcmVzb3VyY2VKaWQgPSBsYXJnZVZpZGVvU3RhdGUudXNlclJlc291cmNlSmlkO1xuXG4gICAgICAgIGlmIChpc1Zpc2libGUpIHtcbiAgICAgICAgICAgICQoJyNsYXJnZVZpZGVvJykuY3NzKHt2aXNpYmlsaXR5OiAndmlzaWJsZSd9KTtcbiAgICAgICAgICAgICQoJy53YXRlcm1hcmsnKS5jc3Moe3Zpc2liaWxpdHk6ICd2aXNpYmxlJ30pO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5hYmxlRG9taW5hbnRTcGVha2VyKHJlc291cmNlSmlkLCB0cnVlKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICQoJyNsYXJnZVZpZGVvJykuY3NzKHt2aXNpYmlsaXR5OiAnaGlkZGVuJ30pO1xuICAgICAgICAgICAgJCgnI2FjdGl2ZVNwZWFrZXInKS5jc3MoJ3Zpc2liaWxpdHknLCAnaGlkZGVuJyk7XG4gICAgICAgICAgICAkKCcud2F0ZXJtYXJrJykuY3NzKHt2aXNpYmlsaXR5OiAnaGlkZGVuJ30pO1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5hYmxlRG9taW5hbnRTcGVha2VyKHJlc291cmNlSmlkLCBmYWxzZSk7XG4gICAgICAgICAgICBpZihmb2N1c2VkVmlkZW9JbmZvKSB7XG4gICAgICAgICAgICAgICAgdmFyIGZvY3VzUmVzb3VyY2VKaWQgPSBmb2N1c2VkVmlkZW9JbmZvLnJlc291cmNlSmlkO1xuICAgICAgICAgICAgICAgIHZhciBvbGRDb250YWluZXIgPSBnZXRQYXJ0aWNpcGFudENvbnRhaW5lcihmb2N1c1Jlc291cmNlSmlkKTtcblxuICAgICAgICAgICAgICAgIGlmIChvbGRDb250YWluZXIgJiYgb2xkQ29udGFpbmVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgb2xkQ29udGFpbmVyLnJlbW92ZUNsYXNzKFwidmlkZW9Db250YWluZXJGb2N1c2VkXCIpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBmb2N1c2VkVmlkZW9JbmZvID0gbnVsbDtcbiAgICAgICAgICAgICAgICBpZihmb2N1c1Jlc291cmNlSmlkKSB7XG4gICAgICAgICAgICAgICAgICAgIEF2YXRhci5zaG93VXNlckF2YXRhcihcbiAgICAgICAgICAgICAgICAgICAgICAgIEFQUC54bXBwLmZpbmRKaWRGcm9tUmVzb3VyY2UoZm9jdXNSZXNvdXJjZUppZCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgaWYgdGhlIGxhcmdlIHZpZGVvIGlzIGN1cnJlbnRseSB2aXNpYmxlLlxuICAgICAqXG4gICAgICogQHJldHVybiA8dHQ+dHJ1ZTwvdHQ+IGlmIHZpc2libGUsIDx0dD5mYWxzZTwvdHQ+IC0gb3RoZXJ3aXNlXG4gICAgICovXG4gICAgbXkuaXNMYXJnZVZpZGVvVmlzaWJsZSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICByZXR1cm4gJCgnI2xhcmdlVmlkZW8nKS5pcygnOnZpc2libGUnKTtcbiAgICB9O1xuXG4gICAgbXkuaXNMYXJnZVZpZGVvT25Ub3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBFdGhlcnBhZCA9IHJlcXVpcmUoXCIuLi9ldGhlcnBhZC9FdGhlcnBhZFwiKTtcbiAgICAgICAgdmFyIFByZXppID0gcmVxdWlyZShcIi4uL3ByZXppL1ByZXppXCIpO1xuICAgICAgICByZXR1cm4gIVByZXppLmlzUHJlc2VudGF0aW9uVmlzaWJsZSgpICYmICFFdGhlcnBhZC5pc1Zpc2libGUoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogQ2hlY2tzIGlmIGNvbnRhaW5lciBmb3IgcGFydGljaXBhbnQgaWRlbnRpZmllZCBieSBnaXZlbiBwZWVySmlkIGV4aXN0c1xuICAgICAqIGluIHRoZSBkb2N1bWVudCBhbmQgY3JlYXRlcyBpdCBldmVudHVhbGx5LlxuICAgICAqIFxuICAgICAqIEBwYXJhbSBwZWVySmlkIHBlZXIgSmlkIHRvIGNoZWNrLlxuICAgICAqIEBwYXJhbSB1c2VySWQgdXNlciBlbWFpbCBvciBpZCBmb3Igc2V0dGluZyB0aGUgYXZhdGFyXG4gICAgICogXG4gICAgICogQHJldHVybiBSZXR1cm5zIDx0dD50cnVlPC90dD4gaWYgdGhlIHBlZXIgY29udGFpbmVyIGV4aXN0cyxcbiAgICAgKiA8dHQ+ZmFsc2U8L3R0PiAtIG90aGVyd2lzZVxuICAgICAqL1xuICAgIG15LmVuc3VyZVBlZXJDb250YWluZXJFeGlzdHMgPSBmdW5jdGlvbihwZWVySmlkLCB1c2VySWQpIHtcbiAgICAgICAgQ29udGFjdExpc3QuZW5zdXJlQWRkQ29udGFjdChwZWVySmlkLCB1c2VySWQpO1xuXG4gICAgICAgIHZhciByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKHBlZXJKaWQpO1xuXG4gICAgICAgIHZhciB2aWRlb1NwYW5JZCA9ICdwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQ7XG5cbiAgICAgICAgaWYgKCEkKCcjJyArIHZpZGVvU3BhbklkKS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHZhciBjb250YWluZXIgPVxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmFkZFJlbW90ZVZpZGVvQ29udGFpbmVyKHBlZXJKaWQsIHZpZGVvU3BhbklkLCB1c2VySWQpO1xuICAgICAgICAgICAgQXZhdGFyLnNldFVzZXJBdmF0YXIocGVlckppZCwgdXNlcklkKTtcbiAgICAgICAgICAgIC8vIFNldCBkZWZhdWx0IGRpc3BsYXkgbmFtZS5cbiAgICAgICAgICAgIHNldERpc3BsYXlOYW1lKHZpZGVvU3BhbklkKTtcblxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbdmlkZW9TcGFuSWRdID1cbiAgICAgICAgICAgICAgICBuZXcgQ29ubmVjdGlvbkluZGljYXRvcihjb250YWluZXIsIHBlZXJKaWQsIFZpZGVvTGF5b3V0KTtcblxuICAgICAgICAgICAgdmFyIG5pY2tmaWVsZCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICAgICAgICAgIG5pY2tmaWVsZC5jbGFzc05hbWUgPSBcIm5pY2tcIjtcbiAgICAgICAgICAgIG5pY2tmaWVsZC5hcHBlbmRDaGlsZChkb2N1bWVudC5jcmVhdGVUZXh0Tm9kZShyZXNvdXJjZUppZCkpO1xuICAgICAgICAgICAgY29udGFpbmVyLmFwcGVuZENoaWxkKG5pY2tmaWVsZCk7XG5cbiAgICAgICAgICAgIC8vIEluIGNhc2UgdGhpcyBpcyBub3QgY3VycmVudGx5IGluIHRoZSBsYXN0IG4gd2UgZG9uJ3Qgc2hvdyBpdC5cbiAgICAgICAgICAgIGlmIChsb2NhbExhc3ROQ291bnRcbiAgICAgICAgICAgICAgICAmJiBsb2NhbExhc3ROQ291bnQgPiAwXG4gICAgICAgICAgICAgICAgJiYgJCgnI3JlbW90ZVZpZGVvcz5zcGFuJykubGVuZ3RoID49IGxvY2FsTGFzdE5Db3VudCArIDIpIHtcbiAgICAgICAgICAgICAgICBzaG93UGVlckNvbnRhaW5lcihyZXNvdXJjZUppZCwgJ2hpZGUnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2VcbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5yZXNpemVUaHVtYm5haWxzKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgbXkuYWRkUmVtb3RlVmlkZW9Db250YWluZXIgPSBmdW5jdGlvbihwZWVySmlkLCBzcGFuSWQpIHtcbiAgICAgICAgdmFyIGNvbnRhaW5lciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICAgICAgY29udGFpbmVyLmlkID0gc3BhbklkO1xuICAgICAgICBjb250YWluZXIuY2xhc3NOYW1lID0gJ3ZpZGVvY29udGFpbmVyJztcbiAgICAgICAgdmFyIHJlbW90ZXMgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCgncmVtb3RlVmlkZW9zJyk7XG4gICAgICAgIHJlbW90ZXMuYXBwZW5kQ2hpbGQoY29udGFpbmVyKTtcbiAgICAgICAgLy8gSWYgdGhlIHBlZXJKaWQgaXMgbnVsbCB0aGVuIHRoaXMgdmlkZW8gc3BhbiBjb3VsZG4ndCBiZSBkaXJlY3RseVxuICAgICAgICAvLyBhc3NvY2lhdGVkIHdpdGggYSBwYXJ0aWNpcGFudCAodGhpcyBjb3VsZCBoYXBwZW4gaW4gdGhlIGNhc2Ugb2YgcHJlemkpLlxuICAgICAgICBpZiAoQVBQLnhtcHAuaXNNb2RlcmF0b3IoKSAmJiBwZWVySmlkICE9PSBudWxsKVxuICAgICAgICAgICAgYWRkUmVtb3RlVmlkZW9NZW51KHBlZXJKaWQsIGNvbnRhaW5lcik7XG4gICAgICAgIEF1ZGlvTGV2ZWxzLnVwZGF0ZUF1ZGlvTGV2ZWxDYW52YXMocGVlckppZCwgVmlkZW9MYXlvdXQpO1xuXG4gICAgICAgIHJldHVybiBjb250YWluZXI7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENyZWF0ZXMgYW4gYXVkaW8gb3IgdmlkZW8gc3RyZWFtIGVsZW1lbnQuXG4gICAgICovXG4gICAgbXkuY3JlYXRlU3RyZWFtRWxlbWVudCA9IGZ1bmN0aW9uIChzaWQsIHN0cmVhbSkge1xuICAgICAgICB2YXIgaXNWaWRlbyA9IHN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLmxlbmd0aCA+IDA7XG5cbiAgICAgICAgdmFyIGVsZW1lbnQgPSBpc1ZpZGVvXG4gICAgICAgICAgICAgICAgICAgICAgICA/IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3ZpZGVvJylcbiAgICAgICAgICAgICAgICAgICAgICAgIDogZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnYXVkaW8nKTtcbiAgICAgICAgdmFyIGlkID0gKGlzVmlkZW8gPyAncmVtb3RlVmlkZW9fJyA6ICdyZW1vdGVBdWRpb18nKVxuICAgICAgICAgICAgICAgICAgICArIHNpZCArICdfJyArIEFQUC5SVEMuZ2V0U3RyZWFtSUQoc3RyZWFtKTtcblxuICAgICAgICBlbGVtZW50LmlkID0gaWQ7XG4gICAgICAgIGVsZW1lbnQuYXV0b3BsYXkgPSB0cnVlO1xuICAgICAgICBlbGVtZW50Lm9uY29udGV4dG1lbnUgPSBmdW5jdGlvbiAoKSB7IHJldHVybiBmYWxzZTsgfTtcblxuICAgICAgICByZXR1cm4gZWxlbWVudDtcbiAgICB9O1xuXG4gICAgbXkuYWRkUmVtb3RlU3RyZWFtRWxlbWVudFxuICAgICAgICA9IGZ1bmN0aW9uIChjb250YWluZXIsIHNpZCwgc3RyZWFtLCBwZWVySmlkLCB0aGVzc3JjKSB7XG4gICAgICAgIHZhciBuZXdFbGVtZW50SWQgPSBudWxsO1xuXG4gICAgICAgIHZhciBpc1ZpZGVvID0gc3RyZWFtLmdldFZpZGVvVHJhY2tzKCkubGVuZ3RoID4gMDtcblxuICAgICAgICBpZiAoY29udGFpbmVyKSB7XG4gICAgICAgICAgICB2YXIgc3RyZWFtRWxlbWVudCA9IFZpZGVvTGF5b3V0LmNyZWF0ZVN0cmVhbUVsZW1lbnQoc2lkLCBzdHJlYW0pO1xuICAgICAgICAgICAgbmV3RWxlbWVudElkID0gc3RyZWFtRWxlbWVudC5pZDtcblxuICAgICAgICAgICAgY29udGFpbmVyLmFwcGVuZENoaWxkKHN0cmVhbUVsZW1lbnQpO1xuXG4gICAgICAgICAgICB2YXIgc2VsID0gJCgnIycgKyBuZXdFbGVtZW50SWQpO1xuICAgICAgICAgICAgc2VsLmhpZGUoKTtcblxuICAgICAgICAgICAgLy8gSWYgdGhlIGNvbnRhaW5lciBpcyBjdXJyZW50bHkgdmlzaWJsZSB3ZSBhdHRhY2ggdGhlIHN0cmVhbS5cbiAgICAgICAgICAgIGlmICghaXNWaWRlb1xuICAgICAgICAgICAgICAgIHx8IChjb250YWluZXIub2Zmc2V0UGFyZW50ICE9PSBudWxsICYmIGlzVmlkZW8pKSB7XG4gICAgICAgICAgICAgICAgdmFyIHZpZGVvU3RyZWFtID0gQVBQLnNpbXVsY2FzdC5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbShzdHJlYW0pO1xuICAgICAgICAgICAgICAgIEFQUC5SVEMuYXR0YWNoTWVkaWFTdHJlYW0oc2VsLCB2aWRlb1N0cmVhbSk7XG5cbiAgICAgICAgICAgICAgICBpZiAoaXNWaWRlbylcbiAgICAgICAgICAgICAgICAgICAgd2FpdEZvclJlbW90ZVZpZGVvKHNlbCwgdGhlc3NyYywgc3RyZWFtLCBwZWVySmlkKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgc3RyZWFtLm9uZW5kZWQgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3N0cmVhbSBlbmRlZCcsIHRoaXMpO1xuXG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQucmVtb3ZlUmVtb3RlU3RyZWFtRWxlbWVudChcbiAgICAgICAgICAgICAgICAgICAgc3RyZWFtLCBpc1ZpZGVvLCBjb250YWluZXIpO1xuXG4gICAgICAgICAgICAgICAgLy8gTk9URShncCkgaXQgc2VlbXMgdGhhdCB1bmRlciBjZXJ0YWluIGNpcmN1bXN0YW5jZXMsIHRoZVxuICAgICAgICAgICAgICAgIC8vIG9uZW5kZWQgZXZlbnQgaXMgbm90IGZpcmVkIGFuZCB0aHVzIHRoZSBjb250YWN0IGxpc3QgaXMgbm90XG4gICAgICAgICAgICAgICAgLy8gdXBkYXRlZC5cbiAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgIC8vIFRoZSBvbmVuZGVkIGV2ZW50IG9mIGEgc3RyZWFtIHNob3VsZCBiZSBmaXJlZCB3aGVuIHRoZSBTU1JDc1xuICAgICAgICAgICAgICAgIC8vIGNvcnJlc3BvbmRpbmcgdG8gdGhhdCBzdHJlYW0gYXJlIHJlbW92ZWQgZnJvbSB0aGUgU0RQOyBidXRcbiAgICAgICAgICAgICAgICAvLyB0aGlzIGRvZXNuJ3Qgc2VlbSB0byBhbHdheXMgYmUgdGhlIGNhc2UsIHJlc3VsdGluZyBpbiBnaG9zdFxuICAgICAgICAgICAgICAgIC8vIGNvbnRhY3RzLlxuICAgICAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAgICAgLy8gSW4gYW4gYXR0ZW1wdCB0byBmaXggdGhlIGdob3N0IGNvbnRhY3RzIHByb2JsZW0sIEknbSBtb3ZpbmdcbiAgICAgICAgICAgICAgICAvLyB0aGUgcmVtb3ZlQ29udGFjdCgpIG1ldGhvZCBjYWxsIGluIGFwcC5qcywgaW5zaWRlIHRoZVxuICAgICAgICAgICAgICAgIC8vICdtdWMubGVmdCcgZXZlbnQgaGFuZGxlci5cblxuICAgICAgICAgICAgICAgIC8vaWYgKHBlZXJKaWQpXG4gICAgICAgICAgICAgICAgLy8gICAgQ29udGFjdExpc3QucmVtb3ZlQ29udGFjdChwZWVySmlkKTtcbiAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgIC8vIEFkZCBjbGljayBoYW5kbGVyLlxuICAgICAgICAgICAgY29udGFpbmVyLm9uY2xpY2sgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgICAgICAvKlxuICAgICAgICAgICAgICAgICAqIEZJWE1FIEl0IHR1cm5zIG91dCB0aGF0IHZpZGVvVGh1bWIgbWF5IG5vdCBleGlzdCAoaWYgdGhlcmUgaXNcbiAgICAgICAgICAgICAgICAgKiBubyBhY3R1YWwgdmlkZW8pLlxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIHZhciB2aWRlb1RodW1iID0gJCgnIycgKyBjb250YWluZXIuaWQgKyAnPnZpZGVvJykuZ2V0KDApO1xuICAgICAgICAgICAgICAgIGlmICh2aWRlb1RodW1iKSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmhhbmRsZVZpZGVvVGh1bWJDbGlja2VkKFxuICAgICAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5nZXRWaWRlb1NyYyh2aWRlb1RodW1iKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQocGVlckppZCkpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGV2ZW50LnN0b3BQcm9wYWdhdGlvbigpO1xuICAgICAgICAgICAgICAgIGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfTtcblxuICAgICAgICAgICAgLy8gQWRkIGhvdmVyIGhhbmRsZXJcbiAgICAgICAgICAgICQoY29udGFpbmVyKS5ob3ZlcihcbiAgICAgICAgICAgICAgICBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuc2hvd0Rpc3BsYXlOYW1lKGNvbnRhaW5lci5pZCwgdHJ1ZSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHZpZGVvU3JjID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQoJyMnICsgY29udGFpbmVyLmlkICsgJz52aWRlbycpXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJiYgJCgnIycgKyBjb250YWluZXIuaWQgKyAnPnZpZGVvJykubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmlkZW9TcmMgPSBBUFAuUlRDLmdldFZpZGVvU3JjKCQoJyMnICsgY29udGFpbmVyLmlkICsgJz52aWRlbycpLmdldCgwKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB0aGUgdmlkZW8gaGFzIGJlZW4gXCJwaW5uZWRcIiBieSB0aGUgdXNlciB3ZSB3YW50IHRvXG4gICAgICAgICAgICAgICAgICAgIC8vIGtlZXAgdGhlIGRpc3BsYXkgbmFtZSBvbiBwbGFjZS5cbiAgICAgICAgICAgICAgICAgICAgaWYgKCFWaWRlb0xheW91dC5pc0xhcmdlVmlkZW9WaXNpYmxlKClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB8fCB2aWRlb1NyYyAhPT0gQVBQLlJUQy5nZXRWaWRlb1NyYygkKCcjbGFyZ2VWaWRlbycpWzBdKSlcbiAgICAgICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNob3dEaXNwbGF5TmFtZShjb250YWluZXIuaWQsIGZhbHNlKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9XG5cbiAgICAgICAgcmV0dXJuIG5ld0VsZW1lbnRJZDtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyB0aGUgcmVtb3RlIHN0cmVhbSBlbGVtZW50IGNvcnJlc3BvbmRpbmcgdG8gdGhlIGdpdmVuIHN0cmVhbSBhbmRcbiAgICAgKiBwYXJlbnQgY29udGFpbmVyLlxuICAgICAqIFxuICAgICAqIEBwYXJhbSBzdHJlYW0gdGhlIHN0cmVhbVxuICAgICAqIEBwYXJhbSBpc1ZpZGVvIDx0dD50cnVlPC90dD4gaWYgZ2l2ZW4gPHR0PnN0cmVhbTwvdHQ+IGlzIGEgdmlkZW8gb25lLlxuICAgICAqIEBwYXJhbSBjb250YWluZXJcbiAgICAgKi9cbiAgICBteS5yZW1vdmVSZW1vdGVTdHJlYW1FbGVtZW50ID0gZnVuY3Rpb24gKHN0cmVhbSwgaXNWaWRlbywgY29udGFpbmVyKSB7XG4gICAgICAgIGlmICghY29udGFpbmVyKVxuICAgICAgICAgICAgcmV0dXJuO1xuXG4gICAgICAgIHZhciBzZWxlY3QgPSBudWxsO1xuICAgICAgICB2YXIgcmVtb3ZlZFZpZGVvU3JjID0gbnVsbDtcbiAgICAgICAgaWYgKGlzVmlkZW8pIHtcbiAgICAgICAgICAgIHNlbGVjdCA9ICQoJyMnICsgY29udGFpbmVyLmlkICsgJz52aWRlbycpO1xuICAgICAgICAgICAgcmVtb3ZlZFZpZGVvU3JjID0gQVBQLlJUQy5nZXRWaWRlb1NyYyhzZWxlY3QuZ2V0KDApKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgICAgICBzZWxlY3QgPSAkKCcjJyArIGNvbnRhaW5lci5pZCArICc+YXVkaW8nKTtcblxuXG4gICAgICAgIC8vIE1hcmsgdmlkZW8gYXMgcmVtb3ZlZCB0byBjYW5jZWwgd2FpdGluZyBsb29wKGlmIHZpZGVvIGlzIHJlbW92ZWRcbiAgICAgICAgLy8gYmVmb3JlIGhhcyBzdGFydGVkKVxuICAgICAgICBzZWxlY3QucmVtb3ZlZCA9IHRydWU7XG4gICAgICAgIHNlbGVjdC5yZW1vdmUoKTtcblxuICAgICAgICB2YXIgYXVkaW9Db3VudCA9ICQoJyMnICsgY29udGFpbmVyLmlkICsgJz5hdWRpbycpLmxlbmd0aDtcbiAgICAgICAgdmFyIHZpZGVvQ291bnQgPSAkKCcjJyArIGNvbnRhaW5lci5pZCArICc+dmlkZW8nKS5sZW5ndGg7XG5cbiAgICAgICAgaWYgKCFhdWRpb0NvdW50ICYmICF2aWRlb0NvdW50KSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcIlJlbW92ZSB3aG9sZSB1c2VyXCIsIGNvbnRhaW5lci5pZCk7XG4gICAgICAgICAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1tjb250YWluZXIuaWRdKVxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW2NvbnRhaW5lci5pZF0ucmVtb3ZlKCk7XG4gICAgICAgICAgICAvLyBSZW1vdmUgd2hvbGUgY29udGFpbmVyXG4gICAgICAgICAgICBjb250YWluZXIucmVtb3ZlKCk7XG5cbiAgICAgICAgICAgIFVJVXRpbC5wbGF5U291bmROb3RpZmljYXRpb24oJ3VzZXJMZWZ0Jyk7XG4gICAgICAgICAgICBWaWRlb0xheW91dC5yZXNpemVUaHVtYm5haWxzKCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAocmVtb3ZlZFZpZGVvU3JjKVxuICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlUmVtb3ZlZFZpZGVvKHJlbW92ZWRWaWRlb1NyYyk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3cvaGlkZSBwZWVyIGNvbnRhaW5lciBmb3IgdGhlIGdpdmVuIHJlc291cmNlSmlkLlxuICAgICAqL1xuICAgIGZ1bmN0aW9uIHNob3dQZWVyQ29udGFpbmVyKHJlc291cmNlSmlkLCBzdGF0ZSkge1xuICAgICAgICB2YXIgcGVlckNvbnRhaW5lciA9ICQoJyNwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQpO1xuXG4gICAgICAgIGlmICghcGVlckNvbnRhaW5lcilcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICB2YXIgaXNIaWRlID0gc3RhdGUgPT09ICdoaWRlJztcbiAgICAgICAgdmFyIHJlc2l6ZVRodW1ibmFpbHMgPSBmYWxzZTtcblxuICAgICAgICBpZiAoIWlzSGlkZSkge1xuICAgICAgICAgICAgaWYgKCFwZWVyQ29udGFpbmVyLmlzKCc6dmlzaWJsZScpKSB7XG4gICAgICAgICAgICAgICAgcmVzaXplVGh1bWJuYWlscyA9IHRydWU7XG4gICAgICAgICAgICAgICAgcGVlckNvbnRhaW5lci5zaG93KCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBqaWQgPSBBUFAueG1wcC5maW5kSmlkRnJvbVJlc291cmNlKHJlc291cmNlSmlkKTtcbiAgICAgICAgICAgIGlmIChzdGF0ZSA9PSAnc2hvdycpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgLy8gcGVlckNvbnRhaW5lci5jc3MoJy13ZWJraXQtZmlsdGVyJywgJycpO1xuXG4gICAgICAgICAgICAgICAgQXZhdGFyLnNob3dVc2VyQXZhdGFyKGppZCwgZmFsc2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSAvLyBpZiAoc3RhdGUgPT0gJ2F2YXRhcicpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgLy8gcGVlckNvbnRhaW5lci5jc3MoJy13ZWJraXQtZmlsdGVyJywgJ2dyYXlzY2FsZSgxMDAlKScpO1xuICAgICAgICAgICAgICAgIEF2YXRhci5zaG93VXNlckF2YXRhcihqaWQsIHRydWUpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYgKHBlZXJDb250YWluZXIuaXMoJzp2aXNpYmxlJykgJiYgaXNIaWRlKVxuICAgICAgICB7XG4gICAgICAgICAgICByZXNpemVUaHVtYm5haWxzID0gdHJ1ZTtcbiAgICAgICAgICAgIHBlZXJDb250YWluZXIuaGlkZSgpO1xuICAgICAgICAgICAgaWYoVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZF0pXG4gICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZF0uaGlkZSgpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHJlc2l6ZVRodW1ibmFpbHMpIHtcbiAgICAgICAgICAgIFZpZGVvTGF5b3V0LnJlc2l6ZVRodW1ibmFpbHMoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIFdlIHdhbnQgdG8gYmUgYWJsZSB0byBwaW4gYSBwYXJ0aWNpcGFudCBmcm9tIHRoZSBjb250YWN0IGxpc3QsIGV2ZW5cbiAgICAgICAgLy8gaWYgaGUncyBub3QgaW4gdGhlIGxhc3ROIHNldCFcbiAgICAgICAgLy8gQ29udGFjdExpc3Quc2V0Q2xpY2thYmxlKHJlc291cmNlSmlkLCAhaXNIaWRlKTtcblxuICAgIH07XG5cbiAgICBteS5pbnB1dERpc3BsYXlOYW1lSGFuZGxlciA9IGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgIE5pY2tuYW1lSGFuZGxlci5zZXROaWNrbmFtZShuYW1lKTtcblxuICAgICAgICBpZiAoISQoJyNsb2NhbERpc3BsYXlOYW1lJykuaXMoXCI6dmlzaWJsZVwiKSkge1xuICAgICAgICAgICAgaWYgKE5pY2tuYW1lSGFuZGxlci5nZXROaWNrbmFtZSgpKVxuICAgICAgICAgICAgICAgICQoJyNsb2NhbERpc3BsYXlOYW1lJykudGV4dChOaWNrbmFtZUhhbmRsZXIuZ2V0Tmlja25hbWUoKSArIFwiIChtZSlcIik7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgJCgnI2xvY2FsRGlzcGxheU5hbWUnKVxuICAgICAgICAgICAgICAgICAgICAudGV4dChpbnRlcmZhY2VDb25maWcuREVGQVVMVF9MT0NBTF9ESVNQTEFZX05BTUUpO1xuICAgICAgICAgICAgJCgnI2xvY2FsRGlzcGxheU5hbWUnKS5zaG93KCk7XG4gICAgICAgIH1cblxuICAgICAgICAkKCcjZWRpdERpc3BsYXlOYW1lJykuaGlkZSgpO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93cy9oaWRlcyB0aGUgZGlzcGxheSBuYW1lIG9uIHRoZSByZW1vdGUgdmlkZW8uXG4gICAgICogQHBhcmFtIHZpZGVvU3BhbklkIHRoZSBpZGVudGlmaWVyIG9mIHRoZSB2aWRlbyBzcGFuIGVsZW1lbnRcbiAgICAgKiBAcGFyYW0gaXNTaG93IGluZGljYXRlcyBpZiB0aGUgZGlzcGxheSBuYW1lIHNob3VsZCBiZSBzaG93biBvciBoaWRkZW5cbiAgICAgKi9cbiAgICBteS5zaG93RGlzcGxheU5hbWUgPSBmdW5jdGlvbih2aWRlb1NwYW5JZCwgaXNTaG93KSB7XG4gICAgICAgIHZhciBuYW1lU3BhbiA9ICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnPnNwYW4uZGlzcGxheW5hbWUnKS5nZXQoMCk7XG4gICAgICAgIGlmIChpc1Nob3cpIHtcbiAgICAgICAgICAgIGlmIChuYW1lU3BhbiAmJiBuYW1lU3Bhbi5pbm5lckhUTUwgJiYgbmFtZVNwYW4uaW5uZXJIVE1MLmxlbmd0aCkgXG4gICAgICAgICAgICAgICAgbmFtZVNwYW4uc2V0QXR0cmlidXRlKFwic3R5bGVcIiwgXCJkaXNwbGF5OmlubGluZS1ibG9jaztcIik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBpZiAobmFtZVNwYW4pXG4gICAgICAgICAgICAgICAgbmFtZVNwYW4uc2V0QXR0cmlidXRlKFwic3R5bGVcIiwgXCJkaXNwbGF5Om5vbmU7XCIpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFNob3dzIHRoZSBwcmVzZW5jZSBzdGF0dXMgbWVzc2FnZSBmb3IgdGhlIGdpdmVuIHZpZGVvLlxuICAgICAqL1xuICAgIG15LnNldFByZXNlbmNlU3RhdHVzID0gZnVuY3Rpb24gKHZpZGVvU3BhbklkLCBzdGF0dXNNc2cpIHtcblxuICAgICAgICBpZiAoISQoJyMnICsgdmlkZW9TcGFuSWQpLmxlbmd0aCkge1xuICAgICAgICAgICAgLy8gTm8gY29udGFpbmVyXG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc3RhdHVzU3BhbiA9ICQoJyMnICsgdmlkZW9TcGFuSWQgKyAnPnNwYW4uc3RhdHVzJyk7XG4gICAgICAgIGlmICghc3RhdHVzU3Bhbi5sZW5ndGgpIHtcbiAgICAgICAgICAgIC8vQWRkIHN0YXR1cyBzcGFuXG4gICAgICAgICAgICBzdGF0dXNTcGFuID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgICAgICAgICAgc3RhdHVzU3Bhbi5jbGFzc05hbWUgPSAnc3RhdHVzJztcbiAgICAgICAgICAgIHN0YXR1c1NwYW4uaWQgPSB2aWRlb1NwYW5JZCArICdfc3RhdHVzJztcbiAgICAgICAgICAgICQoJyMnICsgdmlkZW9TcGFuSWQpWzBdLmFwcGVuZENoaWxkKHN0YXR1c1NwYW4pO1xuXG4gICAgICAgICAgICBzdGF0dXNTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi5zdGF0dXMnKTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIERpc3BsYXkgc3RhdHVzXG4gICAgICAgIGlmIChzdGF0dXNNc2cgJiYgc3RhdHVzTXNnLmxlbmd0aCkge1xuICAgICAgICAgICAgJCgnIycgKyB2aWRlb1NwYW5JZCArICdfc3RhdHVzJykudGV4dChzdGF0dXNNc2cpO1xuICAgICAgICAgICAgc3RhdHVzU3Bhbi5nZXQoMCkuc2V0QXR0cmlidXRlKFwic3R5bGVcIiwgXCJkaXNwbGF5OmlubGluZS1ibG9jaztcIik7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAvLyBIaWRlXG4gICAgICAgICAgICBzdGF0dXNTcGFuLmdldCgwKS5zZXRBdHRyaWJ1dGUoXCJzdHlsZVwiLCBcImRpc3BsYXk6bm9uZTtcIik7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogU2hvd3MgYSB2aXN1YWwgaW5kaWNhdG9yIGZvciB0aGUgbW9kZXJhdG9yIG9mIHRoZSBjb25mZXJlbmNlLlxuICAgICAqL1xuICAgIG15LnNob3dNb2RlcmF0b3JJbmRpY2F0b3IgPSBmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgdmFyIGlzTW9kZXJhdG9yID0gQVBQLnhtcHAuaXNNb2RlcmF0b3IoKTtcbiAgICAgICAgaWYgKGlzTW9kZXJhdG9yKSB7XG4gICAgICAgICAgICB2YXIgaW5kaWNhdG9yU3BhbiA9ICQoJyNsb2NhbFZpZGVvQ29udGFpbmVyIC5mb2N1c2luZGljYXRvcicpO1xuXG4gICAgICAgICAgICBpZiAoaW5kaWNhdG9yU3Bhbi5jaGlsZHJlbigpLmxlbmd0aCA9PT0gMClcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBjcmVhdGVNb2RlcmF0b3JJbmRpY2F0b3JFbGVtZW50KGluZGljYXRvclNwYW5bMF0pO1xuICAgICAgICAgICAgICAgIC8vdHJhbnNsYXRlcyB0ZXh0IGluIGZvY3VzIGluZGljYXRvclxuICAgICAgICAgICAgICAgIEFQUC50cmFuc2xhdGlvbi50cmFuc2xhdGVFbGVtZW50KCQoJyNsb2NhbFZpZGVvQ29udGFpbmVyIC5mb2N1c2luZGljYXRvcicpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBtZW1iZXJzID0gQVBQLnhtcHAuZ2V0TWVtYmVycygpO1xuXG4gICAgICAgIE9iamVjdC5rZXlzKG1lbWJlcnMpLmZvckVhY2goZnVuY3Rpb24gKGppZCkge1xuXG4gICAgICAgICAgICBpZiAoU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSA9PT0gJ2ZvY3VzJykge1xuICAgICAgICAgICAgICAgIC8vIFNraXAgc2VydmVyIHNpZGUgZm9jdXNcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciByZXNvdXJjZUppZCA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkO1xuICAgICAgICAgICAgdmFyIHZpZGVvQ29udGFpbmVyID0gZG9jdW1lbnQuZ2V0RWxlbWVudEJ5SWQodmlkZW9TcGFuSWQpO1xuXG4gICAgICAgICAgICBpZiAoIXZpZGVvQ29udGFpbmVyKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIk5vIHZpZGVvIGNvbnRhaW5lciBmb3IgXCIgKyBqaWQpO1xuICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIG1lbWJlciA9IG1lbWJlcnNbamlkXTtcblxuICAgICAgICAgICAgaWYgKG1lbWJlci5yb2xlID09PSAnbW9kZXJhdG9yJykge1xuICAgICAgICAgICAgICAgIC8vIFJlbW92ZSBtZW51IGlmIHBlZXIgaXMgbW9kZXJhdG9yXG4gICAgICAgICAgICAgICAgdmFyIG1lbnVTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi5yZW1vdGV2aWRlb21lbnUnKTtcbiAgICAgICAgICAgICAgICBpZiAobWVudVNwYW4ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgIHJlbW92ZVJlbW90ZVZpZGVvTWVudSh2aWRlb1NwYW5JZCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vIFNob3cgbW9kZXJhdG9yIGluZGljYXRvclxuICAgICAgICAgICAgICAgIHZhciBpbmRpY2F0b3JTcGFuXG4gICAgICAgICAgICAgICAgICAgID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICcgLmZvY3VzaW5kaWNhdG9yJyk7XG5cbiAgICAgICAgICAgICAgICBpZiAoIWluZGljYXRvclNwYW4gfHwgaW5kaWNhdG9yU3Bhbi5sZW5ndGggPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgaW5kaWNhdG9yU3BhbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ3NwYW4nKTtcbiAgICAgICAgICAgICAgICAgICAgaW5kaWNhdG9yU3Bhbi5jbGFzc05hbWUgPSAnZm9jdXNpbmRpY2F0b3InO1xuXG4gICAgICAgICAgICAgICAgICAgIHZpZGVvQ29udGFpbmVyLmFwcGVuZENoaWxkKGluZGljYXRvclNwYW4pO1xuXG4gICAgICAgICAgICAgICAgICAgIGNyZWF0ZU1vZGVyYXRvckluZGljYXRvckVsZW1lbnQoaW5kaWNhdG9yU3Bhbik7XG4gICAgICAgICAgICAgICAgICAgIC8vdHJhbnNsYXRlcyB0ZXh0IGluIGZvY3VzIGluZGljYXRvcnNcbiAgICAgICAgICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZUVsZW1lbnQoJCgnIycgKyB2aWRlb1NwYW5JZCArICcgLmZvY3VzaW5kaWNhdG9yJykpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoaXNNb2RlcmF0b3IpIHtcbiAgICAgICAgICAgICAgICAvLyBXZSBhcmUgbW9kZXJhdG9yLCBidXQgdXNlciBpcyBub3QgLSBhZGQgbWVudVxuICAgICAgICAgICAgICAgIGlmICgkKCcjcmVtb3RlX3BvcHVwbWVudV8nICsgcmVzb3VyY2VKaWQpLmxlbmd0aCA8PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGFkZFJlbW90ZVZpZGVvTWVudShcbiAgICAgICAgICAgICAgICAgICAgICAgIGppZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBTaG93cyB2aWRlbyBtdXRlZCBpbmRpY2F0b3Igb3ZlciBzbWFsbCB2aWRlb3MuXG4gICAgICovXG4gICAgbXkuc2hvd1ZpZGVvSW5kaWNhdG9yID0gZnVuY3Rpb24odmlkZW9TcGFuSWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgdmFyIHZpZGVvTXV0ZWRTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi52aWRlb011dGVkJyk7XG5cbiAgICAgICAgaWYgKGlzTXV0ZWQgPT09ICdmYWxzZScpIHtcbiAgICAgICAgICAgIGlmICh2aWRlb011dGVkU3Bhbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgdmlkZW9NdXRlZFNwYW4ucmVtb3ZlKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBpZih2aWRlb011dGVkU3Bhbi5sZW5ndGggPT0gMCkge1xuICAgICAgICAgICAgICAgIHZpZGVvTXV0ZWRTcGFuID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc3BhbicpO1xuICAgICAgICAgICAgICAgIHZpZGVvTXV0ZWRTcGFuLmNsYXNzTmFtZSA9ICd2aWRlb011dGVkJztcblxuICAgICAgICAgICAgICAgICQoJyMnICsgdmlkZW9TcGFuSWQpWzBdLmFwcGVuZENoaWxkKHZpZGVvTXV0ZWRTcGFuKTtcblxuICAgICAgICAgICAgICAgIHZhciBtdXRlZEluZGljYXRvciA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoJ2knKTtcbiAgICAgICAgICAgICAgICBtdXRlZEluZGljYXRvci5jbGFzc05hbWUgPSAnaWNvbi1jYW1lcmEtZGlzYWJsZWQnO1xuICAgICAgICAgICAgICAgIFVJVXRpbC5zZXRUb29sdGlwKG11dGVkSW5kaWNhdG9yLFxuICAgICAgICAgICAgICAgICAgICBcInZpZGVvdGh1bWJuYWlsLnZpZGVvbXV0ZVwiLFxuICAgICAgICAgICAgICAgICAgICBcInRvcFwiKTtcbiAgICAgICAgICAgICAgICB2aWRlb011dGVkU3Bhbi5hcHBlbmRDaGlsZChtdXRlZEluZGljYXRvcik7XG4gICAgICAgICAgICAgICAgLy90cmFuc2xhdGUgdGV4dHMgZm9yIG11dGVkIGluZGljYXRvclxuICAgICAgICAgICAgICAgIEFQUC50cmFuc2xhdGlvbi50cmFuc2xhdGVFbGVtZW50KCQoJyMnICsgdmlkZW9TcGFuSWQgICsgXCIgPiBpXCIpKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlTXV0ZVBvc2l0aW9uKHZpZGVvU3BhbklkKTtcblxuICAgICAgICB9XG4gICAgfTtcblxuICAgIG15LnVwZGF0ZU11dGVQb3NpdGlvbiA9IGZ1bmN0aW9uICh2aWRlb1NwYW5JZCkge1xuICAgICAgICB2YXIgYXVkaW9NdXRlZFNwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLmF1ZGlvTXV0ZWQnKTtcbiAgICAgICAgdmFyIGNvbm5lY3Rpb25JbmRpY2F0b3IgPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5kaXYuY29ubmVjdGlvbmluZGljYXRvcicpO1xuICAgICAgICB2YXIgdmlkZW9NdXRlZFNwYW4gPSAkKCcjJyArIHZpZGVvU3BhbklkICsgJz5zcGFuLnZpZGVvTXV0ZWQnKTtcbiAgICAgICAgaWYoY29ubmVjdGlvbkluZGljYXRvci5sZW5ndGggPiAwXG4gICAgICAgICAgICAmJiBjb25uZWN0aW9uSW5kaWNhdG9yWzBdLnN0eWxlLmRpc3BsYXkgIT0gXCJub25lXCIpIHtcbiAgICAgICAgICAgIGF1ZGlvTXV0ZWRTcGFuLmNzcyh7cmlnaHQ6IFwiMjNweFwifSk7XG4gICAgICAgICAgICB2aWRlb011dGVkU3Bhbi5jc3Moe3JpZ2h0OiAoKGF1ZGlvTXV0ZWRTcGFuLmxlbmd0aCA+IDA/IDIzIDogMCkgKyAzMCkgKyBcInB4XCJ9KTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIGF1ZGlvTXV0ZWRTcGFuLmNzcyh7cmlnaHQ6IFwiMHB4XCJ9KTtcbiAgICAgICAgICAgIHZpZGVvTXV0ZWRTcGFuLmNzcyh7cmlnaHQ6IChhdWRpb011dGVkU3Bhbi5sZW5ndGggPiAwPyAzMCA6IDApICsgXCJweFwifSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLyoqXG4gICAgICogU2hvd3MgYXVkaW8gbXV0ZWQgaW5kaWNhdG9yIG92ZXIgc21hbGwgdmlkZW9zLlxuICAgICAqIEBwYXJhbSB7c3RyaW5nfSBpc011dGVkXG4gICAgICovXG4gICAgbXkuc2hvd0F1ZGlvSW5kaWNhdG9yID0gZnVuY3Rpb24odmlkZW9TcGFuSWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgdmFyIGF1ZGlvTXV0ZWRTcGFuID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+c3Bhbi5hdWRpb011dGVkJyk7XG5cbiAgICAgICAgaWYgKGlzTXV0ZWQgPT09ICdmYWxzZScpIHtcbiAgICAgICAgICAgIGlmIChhdWRpb011dGVkU3Bhbi5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4ucG9wb3ZlcignaGlkZScpO1xuICAgICAgICAgICAgICAgIGF1ZGlvTXV0ZWRTcGFuLnJlbW92ZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgaWYoYXVkaW9NdXRlZFNwYW4ubGVuZ3RoID09IDAgKSB7XG4gICAgICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4gPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCdzcGFuJyk7XG4gICAgICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4uY2xhc3NOYW1lID0gJ2F1ZGlvTXV0ZWQnO1xuICAgICAgICAgICAgICAgIFVJVXRpbC5zZXRUb29sdGlwKGF1ZGlvTXV0ZWRTcGFuLFxuICAgICAgICAgICAgICAgICAgICBcInZpZGVvdGh1bWJuYWlsLm11dGVcIixcbiAgICAgICAgICAgICAgICAgICAgXCJ0b3BcIik7XG5cbiAgICAgICAgICAgICAgICAkKCcjJyArIHZpZGVvU3BhbklkKVswXS5hcHBlbmRDaGlsZChhdWRpb011dGVkU3Bhbik7XG4gICAgICAgICAgICAgICAgQVBQLnRyYW5zbGF0aW9uLnRyYW5zbGF0ZUVsZW1lbnQoJCgnIycgKyB2aWRlb1NwYW5JZCArIFwiID4gc3BhblwiKSk7XG4gICAgICAgICAgICAgICAgdmFyIG11dGVkSW5kaWNhdG9yID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnaScpO1xuICAgICAgICAgICAgICAgIG11dGVkSW5kaWNhdG9yLmNsYXNzTmFtZSA9ICdpY29uLW1pYy1kaXNhYmxlZCc7XG4gICAgICAgICAgICAgICAgYXVkaW9NdXRlZFNwYW4uYXBwZW5kQ2hpbGQobXV0ZWRJbmRpY2F0b3IpO1xuXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVNdXRlUG9zaXRpb24odmlkZW9TcGFuSWQpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qXG4gICAgICogU2hvd3Mgb3IgaGlkZXMgdGhlIGF1ZGlvIG11dGVkIGluZGljYXRvciBvdmVyIHRoZSBsb2NhbCB0aHVtYm5haWwgdmlkZW8uXG4gICAgICogQHBhcmFtIHtib29sZWFufSBpc011dGVkXG4gICAgICovXG4gICAgbXkuc2hvd0xvY2FsQXVkaW9JbmRpY2F0b3IgPSBmdW5jdGlvbihpc011dGVkKSB7XG4gICAgICAgIFZpZGVvTGF5b3V0LnNob3dBdWRpb0luZGljYXRvcignbG9jYWxWaWRlb0NvbnRhaW5lcicsIGlzTXV0ZWQudG9TdHJpbmcoKSk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgdGhlIGxhcmdlIHZpZGVvIGNvbnRhaW5lci5cbiAgICAgKi9cbiAgICBteS5yZXNpemVMYXJnZVZpZGVvQ29udGFpbmVyID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBDaGF0LnJlc2l6ZUNoYXQoKTtcbiAgICAgICAgdmFyIGF2YWlsYWJsZUhlaWdodCA9IHdpbmRvdy5pbm5lckhlaWdodDtcbiAgICAgICAgdmFyIGF2YWlsYWJsZVdpZHRoID0gVUlVdGlsLmdldEF2YWlsYWJsZVZpZGVvV2lkdGgoKTtcblxuICAgICAgICBpZiAoYXZhaWxhYmxlV2lkdGggPCAwIHx8IGF2YWlsYWJsZUhlaWdodCA8IDApIHJldHVybjtcblxuICAgICAgICAkKCcjdmlkZW9zcGFjZScpLndpZHRoKGF2YWlsYWJsZVdpZHRoKTtcbiAgICAgICAgJCgnI3ZpZGVvc3BhY2UnKS5oZWlnaHQoYXZhaWxhYmxlSGVpZ2h0KTtcbiAgICAgICAgJCgnI2xhcmdlVmlkZW9Db250YWluZXInKS53aWR0aChhdmFpbGFibGVXaWR0aCk7XG4gICAgICAgICQoJyNsYXJnZVZpZGVvQ29udGFpbmVyJykuaGVpZ2h0KGF2YWlsYWJsZUhlaWdodCk7XG5cbiAgICAgICAgdmFyIGF2YXRhclNpemUgPSBpbnRlcmZhY2VDb25maWcuQUNUSVZFX1NQRUFLRVJfQVZBVEFSX1NJWkU7XG4gICAgICAgIHZhciB0b3AgPSBhdmFpbGFibGVIZWlnaHQgLyAyIC0gYXZhdGFyU2l6ZSAvIDQgKiAzO1xuICAgICAgICAkKCcjYWN0aXZlU3BlYWtlcicpLmNzcygndG9wJywgdG9wKTtcblxuICAgICAgICBWaWRlb0xheW91dC5yZXNpemVUaHVtYm5haWxzKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIFJlc2l6ZXMgdGh1bWJuYWlscy5cbiAgICAgKi9cbiAgICBteS5yZXNpemVUaHVtYm5haWxzID0gZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciB2aWRlb1NwYWNlV2lkdGggPSAkKCcjcmVtb3RlVmlkZW9zJykud2lkdGgoKTtcblxuICAgICAgICB2YXIgdGh1bWJuYWlsU2l6ZSA9IFZpZGVvTGF5b3V0LmNhbGN1bGF0ZVRodW1ibmFpbFNpemUodmlkZW9TcGFjZVdpZHRoKTtcbiAgICAgICAgdmFyIHdpZHRoID0gdGh1bWJuYWlsU2l6ZVswXTtcbiAgICAgICAgdmFyIGhlaWdodCA9IHRodW1ibmFpbFNpemVbMV07XG5cbiAgICAgICAgLy8gc2l6ZSB2aWRlb3Mgc28gdGhhdCB3aGlsZSBrZWVwaW5nIEFSIGFuZCBtYXggaGVpZ2h0LCB3ZSBoYXZlIGFcbiAgICAgICAgLy8gbmljZSBmaXRcbiAgICAgICAgJCgnI3JlbW90ZVZpZGVvcycpLmhlaWdodChoZWlnaHQpO1xuICAgICAgICAkKCcjcmVtb3RlVmlkZW9zPnNwYW4nKS53aWR0aCh3aWR0aCk7XG4gICAgICAgICQoJyNyZW1vdGVWaWRlb3M+c3BhbicpLmhlaWdodChoZWlnaHQpO1xuXG4gICAgICAgICQoJy51c2VyQXZhdGFyJykuY3NzKCdsZWZ0JywgKHdpZHRoIC0gaGVpZ2h0KSAvIDIpO1xuXG5cblxuICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKFwicmVtb3RldmlkZW8ucmVzaXplZFwiLCBbd2lkdGgsIGhlaWdodF0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBFbmFibGVzIHRoZSBkb21pbmFudCBzcGVha2VyIFVJLlxuICAgICAqXG4gICAgICogQHBhcmFtIHJlc291cmNlSmlkIHRoZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZWxlbWVudCB0b1xuICAgICAqIGFjdGl2YXRlL2RlYWN0aXZhdGVcbiAgICAgKiBAcGFyYW0gaXNFbmFibGUgaW5kaWNhdGVzIGlmIHRoZSBkb21pbmFudCBzcGVha2VyIHNob3VsZCBiZSBlbmFibGVkIG9yXG4gICAgICogZGlzYWJsZWRcbiAgICAgKi9cbiAgICBteS5lbmFibGVEb21pbmFudFNwZWFrZXIgPSBmdW5jdGlvbihyZXNvdXJjZUppZCwgaXNFbmFibGUpIHtcblxuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSBudWxsO1xuICAgICAgICB2YXIgdmlkZW9Db250YWluZXJJZCA9IG51bGw7XG4gICAgICAgIGlmIChyZXNvdXJjZUppZFxuICAgICAgICAgICAgICAgID09PSBBUFAueG1wcC5teVJlc291cmNlKCkpIHtcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ2xvY2FsVmlkZW9XcmFwcGVyJztcbiAgICAgICAgICAgIHZpZGVvQ29udGFpbmVySWQgPSAnbG9jYWxWaWRlb0NvbnRhaW5lcic7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICB2aWRlb1NwYW5JZCA9ICdwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICB2aWRlb0NvbnRhaW5lcklkID0gdmlkZW9TcGFuSWQ7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgZGlzcGxheU5hbWUgPSByZXNvdXJjZUppZDtcbiAgICAgICAgdmFyIG5hbWVTcGFuID0gJCgnIycgKyB2aWRlb0NvbnRhaW5lcklkICsgJz5zcGFuLmRpc3BsYXluYW1lJyk7XG4gICAgICAgIGlmIChuYW1lU3Bhbi5sZW5ndGggPiAwKVxuICAgICAgICAgICAgZGlzcGxheU5hbWUgPSBuYW1lU3Bhbi5odG1sKCk7XG5cbiAgICAgICAgY29uc29sZS5sb2coXCJVSSBlbmFibGUgZG9taW5hbnQgc3BlYWtlclwiLFxuICAgICAgICAgICAgZGlzcGxheU5hbWUsXG4gICAgICAgICAgICByZXNvdXJjZUppZCxcbiAgICAgICAgICAgIGlzRW5hYmxlKTtcblxuICAgICAgICB2aWRlb1NwYW4gPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZCh2aWRlb0NvbnRhaW5lcklkKTtcblxuICAgICAgICBpZiAoIXZpZGVvU3Bhbikge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHZpZGVvID0gJCgnIycgKyB2aWRlb1NwYW5JZCArICc+dmlkZW8nKTtcblxuICAgICAgICBpZiAodmlkZW8gJiYgdmlkZW8ubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgaWYgKGlzRW5hYmxlKSB7XG4gICAgICAgICAgICAgICAgdmFyIGlzTGFyZ2VWaWRlb1Zpc2libGUgPSBWaWRlb0xheW91dC5pc0xhcmdlVmlkZW9PblRvcCgpO1xuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnNob3dEaXNwbGF5TmFtZSh2aWRlb0NvbnRhaW5lcklkLCBpc0xhcmdlVmlkZW9WaXNpYmxlKTtcblxuICAgICAgICAgICAgICAgIGlmICghdmlkZW9TcGFuLmNsYXNzTGlzdC5jb250YWlucyhcImRvbWluYW50c3BlYWtlclwiKSlcbiAgICAgICAgICAgICAgICAgICAgdmlkZW9TcGFuLmNsYXNzTGlzdC5hZGQoXCJkb21pbmFudHNwZWFrZXJcIik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC5zaG93RGlzcGxheU5hbWUodmlkZW9Db250YWluZXJJZCwgZmFsc2UpO1xuXG4gICAgICAgICAgICAgICAgaWYgKHZpZGVvU3Bhbi5jbGFzc0xpc3QuY29udGFpbnMoXCJkb21pbmFudHNwZWFrZXJcIikpXG4gICAgICAgICAgICAgICAgICAgIHZpZGVvU3Bhbi5jbGFzc0xpc3QucmVtb3ZlKFwiZG9taW5hbnRzcGVha2VyXCIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBBdmF0YXIuc2hvd1VzZXJBdmF0YXIoXG4gICAgICAgICAgICAgICAgQVBQLnhtcHAuZmluZEppZEZyb21SZXNvdXJjZShyZXNvdXJjZUppZCkpO1xuICAgICAgICB9XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIENhbGN1bGF0ZXMgdGhlIHRodW1ibmFpbCBzaXplLlxuICAgICAqXG4gICAgICogQHBhcmFtIHZpZGVvU3BhY2VXaWR0aCB0aGUgd2lkdGggb2YgdGhlIHZpZGVvIHNwYWNlXG4gICAgICovXG4gICAgbXkuY2FsY3VsYXRlVGh1bWJuYWlsU2l6ZSA9IGZ1bmN0aW9uICh2aWRlb1NwYWNlV2lkdGgpIHtcbiAgICAgICAgLy8gQ2FsY3VsYXRlIHRoZSBhdmFpbGFibGUgaGVpZ2h0LCB3aGljaCBpcyB0aGUgaW5uZXIgd2luZG93IGhlaWdodCBtaW51c1xuICAgICAgIC8vIDM5cHggZm9yIHRoZSBoZWFkZXIgbWludXMgMnB4IGZvciB0aGUgZGVsaW1pdGVyIGxpbmVzIG9uIHRoZSB0b3AgYW5kXG4gICAgICAgLy8gYm90dG9tIG9mIHRoZSBsYXJnZSB2aWRlbywgbWludXMgdGhlIDM2cHggc3BhY2UgaW5zaWRlIHRoZSByZW1vdGVWaWRlb3NcbiAgICAgICAvLyBjb250YWluZXIgdXNlZCBmb3IgaGlnaGxpZ2h0aW5nIHNoYWRvdy5cbiAgICAgICB2YXIgYXZhaWxhYmxlSGVpZ2h0ID0gMTAwO1xuXG4gICAgICAgIHZhciBudW12aWRzID0gJCgnI3JlbW90ZVZpZGVvcz5zcGFuOnZpc2libGUnKS5sZW5ndGg7XG4gICAgICAgIGlmIChsb2NhbExhc3ROQ291bnQgJiYgbG9jYWxMYXN0TkNvdW50ID4gMCkge1xuICAgICAgICAgICAgbnVtdmlkcyA9IE1hdGgubWluKGxvY2FsTGFzdE5Db3VudCArIDEsIG51bXZpZHMpO1xuICAgICAgICB9XG5cbiAgICAgICAvLyBSZW1vdmUgdGhlIDNweCBib3JkZXJzIGFycm91bmQgdmlkZW9zIGFuZCBib3JkZXIgYXJvdW5kIHRoZSByZW1vdGVcbiAgICAgICAvLyB2aWRlb3MgYXJlYSBhbmQgdGhlIDQgcGl4ZWxzIGJldHdlZW4gdGhlIGxvY2FsIHZpZGVvIGFuZCB0aGUgb3RoZXJzXG4gICAgICAgLy9UT0RPOiBGaW5kIG91dCB3aGVyZSB0aGUgNCBwaXhlbHMgY29tZSBmcm9tIGFuZCByZW1vdmUgdGhlbVxuICAgICAgIHZhciBhdmFpbGFibGVXaW5XaWR0aCA9IHZpZGVvU3BhY2VXaWR0aCAtIDIgKiAzICogbnVtdmlkcyAtIDcwIC0gNDtcblxuICAgICAgIHZhciBhdmFpbGFibGVXaWR0aCA9IGF2YWlsYWJsZVdpbldpZHRoIC8gbnVtdmlkcztcbiAgICAgICB2YXIgYXNwZWN0UmF0aW8gPSAxNi4wIC8gOS4wO1xuICAgICAgIHZhciBtYXhIZWlnaHQgPSBNYXRoLm1pbigxNjAsIGF2YWlsYWJsZUhlaWdodCk7XG4gICAgICAgYXZhaWxhYmxlSGVpZ2h0ID0gTWF0aC5taW4obWF4SGVpZ2h0LCBhdmFpbGFibGVXaWR0aCAvIGFzcGVjdFJhdGlvKTtcbiAgICAgICBpZiAoYXZhaWxhYmxlSGVpZ2h0IDwgYXZhaWxhYmxlV2lkdGggLyBhc3BlY3RSYXRpbykge1xuICAgICAgICAgICBhdmFpbGFibGVXaWR0aCA9IE1hdGguZmxvb3IoYXZhaWxhYmxlSGVpZ2h0ICogYXNwZWN0UmF0aW8pO1xuICAgICAgIH1cblxuICAgICAgIHJldHVybiBbYXZhaWxhYmxlV2lkdGgsIGF2YWlsYWJsZUhlaWdodF07XG4gICB9O1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgcmVtb3RlIHZpZGVvIG1lbnUuXG4gICAgICpcbiAgICAgKiBAcGFyYW0gamlkIHRoZSBqaWQgaW5kaWNhdGluZyB0aGUgdmlkZW8gZm9yIHdoaWNoIHdlJ3JlIGFkZGluZyBhIG1lbnUuXG4gICAgICogQHBhcmFtIGlzTXV0ZWQgaW5kaWNhdGVzIHRoZSBjdXJyZW50IG11dGUgc3RhdGVcbiAgICAgKi9cbiAgICBteS51cGRhdGVSZW1vdGVWaWRlb01lbnUgPSBmdW5jdGlvbihqaWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgdmFyIG11dGVNZW51SXRlbVxuICAgICAgICAgICAgPSAkKCcjcmVtb3RlX3BvcHVwbWVudV8nXG4gICAgICAgICAgICAgICAgICAgICsgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKVxuICAgICAgICAgICAgICAgICAgICArICc+bGk+YS5tdXRlbGluaycpO1xuXG4gICAgICAgIHZhciBtdXRlZEluZGljYXRvciA9IFwiPGkgY2xhc3M9J2ljb24tbWljLWRpc2FibGVkJz48L2k+XCI7XG5cbiAgICAgICAgaWYgKG11dGVNZW51SXRlbS5sZW5ndGgpIHtcbiAgICAgICAgICAgIHZhciBtdXRlTGluayA9IG11dGVNZW51SXRlbS5nZXQoMCk7XG5cbiAgICAgICAgICAgIGlmIChpc011dGVkID09PSAndHJ1ZScpIHtcbiAgICAgICAgICAgICAgICBtdXRlTGluay5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArICcgTXV0ZWQnO1xuICAgICAgICAgICAgICAgIG11dGVMaW5rLmNsYXNzTmFtZSA9ICdtdXRlbGluayBkaXNhYmxlZCc7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICBtdXRlTGluay5pbm5lckhUTUwgPSBtdXRlZEluZGljYXRvciArICcgTXV0ZSc7XG4gICAgICAgICAgICAgICAgbXV0ZUxpbmsuY2xhc3NOYW1lID0gJ211dGVsaW5rJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBSZXR1cm5zIHRoZSBjdXJyZW50IGRvbWluYW50IHNwZWFrZXIgcmVzb3VyY2UgamlkLlxuICAgICAqL1xuICAgIG15LmdldERvbWluYW50U3BlYWtlclJlc291cmNlSmlkID0gZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gY3VycmVudERvbWluYW50U3BlYWtlcjtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmV0dXJucyB0aGUgY29ycmVzcG9uZGluZyByZXNvdXJjZSBqaWQgdG8gdGhlIGdpdmVuIHBlZXIgY29udGFpbmVyXG4gICAgICogRE9NIGVsZW1lbnQuXG4gICAgICpcbiAgICAgKiBAcmV0dXJuIHRoZSBjb3JyZXNwb25kaW5nIHJlc291cmNlIGppZCB0byB0aGUgZ2l2ZW4gcGVlciBjb250YWluZXJcbiAgICAgKiBET00gZWxlbWVudFxuICAgICAqL1xuICAgIG15LmdldFBlZXJDb250YWluZXJSZXNvdXJjZUppZCA9IGZ1bmN0aW9uIChjb250YWluZXJFbGVtZW50KSB7XG4gICAgICAgIHZhciBpID0gY29udGFpbmVyRWxlbWVudC5pZC5pbmRleE9mKCdwYXJ0aWNpcGFudF8nKTtcblxuICAgICAgICBpZiAoaSA+PSAwKVxuICAgICAgICAgICAgcmV0dXJuIGNvbnRhaW5lckVsZW1lbnQuaWQuc3Vic3RyaW5nKGkgKyAxMik7IFxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPbiBjb250YWN0IGxpc3QgaXRlbSBjbGlja2VkLlxuICAgICAqL1xuICAgICQoQ29udGFjdExpc3QpLmJpbmQoJ2NvbnRhY3RjbGlja2VkJywgZnVuY3Rpb24oZXZlbnQsIGppZCkge1xuICAgICAgICBpZiAoIWppZCkge1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIHJlc291cmNlID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcbiAgICAgICAgdmFyIHZpZGVvQ29udGFpbmVyID0gJChcIiNwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlKTtcbiAgICAgICAgaWYgKHZpZGVvQ29udGFpbmVyLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHZhciB2aWRlb1RodW1iID0gJCgndmlkZW8nLCB2aWRlb0NvbnRhaW5lcikuZ2V0KDApO1xuICAgICAgICAgICAgLy8gSXQgaXMgbm90IGFsd2F5cyB0aGUgY2FzZSB0aGF0IGEgdmlkZW9UaHVtYiBleGlzdHMgKGlmIHRoZXJlIGlzXG4gICAgICAgICAgICAvLyBubyBhY3R1YWwgdmlkZW8pLlxuICAgICAgICAgICAgaWYgKHZpZGVvVGh1bWIpIHtcbiAgICAgICAgICAgICAgICBpZiAodmlkZW9UaHVtYi5zcmMgJiYgdmlkZW9UaHVtYi5zcmMgIT0gJycpIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBXZSBoYXZlIGEgdmlkZW8gc3JjLCBncmVhdCEgTGV0J3MgdXBkYXRlIHRoZSBsYXJnZSB2aWRlb1xuICAgICAgICAgICAgICAgICAgICAvLyBub3cuXG5cbiAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuaGFuZGxlVmlkZW9UaHVtYkNsaWNrZWQoXG4gICAgICAgICAgICAgICAgICAgICAgICB2aWRlb1RodW1iLnNyYyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcblxuICAgICAgICAgICAgICAgICAgICAvLyBJZiB3ZSBkb24ndCBoYXZlIGEgdmlkZW8gc3JjIGZvciBqaWQsIHRoZXJlJ3MgYWJzb2x1dGVseVxuICAgICAgICAgICAgICAgICAgICAvLyBubyBwb2ludCBpbiBjYWxsaW5nIGhhbmRsZVZpZGVvVGh1bWJDbGlja2VkOyBRdWl0ZVxuICAgICAgICAgICAgICAgICAgICAvLyBzaW1wbHksIGl0IHdvbid0IHdvcmsgYmVjYXVzZSBpdCBuZWVkcyBhbiBzcmMgdG8gYXR0YWNoXG4gICAgICAgICAgICAgICAgICAgIC8vIHRvIHRoZSBsYXJnZSB2aWRlby5cbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gSW5zdGVhZCwgd2UgdHJpZ2dlciB0aGUgcGlubmVkIGVuZHBvaW50IGNoYW5nZWQgZXZlbnQgdG9cbiAgICAgICAgICAgICAgICAgICAgLy8gbGV0IHRoZSBicmlkZ2UgYWRqdXN0IGl0cyBsYXN0TiBzZXQgZm9yIG15amlkIGFuZCBzdG9yZVxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgcGlubmVkIHVzZXIgaW4gdGhlIGxhc3ROUGlja3VwSmlkIHZhcmlhYmxlIHRvIGJlXG4gICAgICAgICAgICAgICAgICAgIC8vIHBpY2tlZCB1cCBsYXRlciBieSB0aGUgbGFzdE4gY2hhbmdlZCBldmVudCBoYW5kbGVyLlxuXG4gICAgICAgICAgICAgICAgICAgIGxhc3ROUGlja3VwSmlkID0gamlkO1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChVSUV2ZW50cy5QSU5ORURfRU5EUE9JTlQsXG4gICAgICAgICAgICAgICAgICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGppZCA9PSBBUFAueG1wcC5teUppZCgpKSB7XG4gICAgICAgICAgICAgICAgJChcIiNsb2NhbFZpZGVvQ29udGFpbmVyXCIpLmNsaWNrKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIE9uIGF1ZGlvIG11dGVkIGV2ZW50LlxuICAgICAqL1xuICAgICQoZG9jdW1lbnQpLmJpbmQoJ2F1ZGlvbXV0ZWQubXVjJywgZnVuY3Rpb24gKGV2ZW50LCBqaWQsIGlzTXV0ZWQpIHtcbiAgICAgICAgLypcbiAgICAgICAgIC8vIEZJWE1FOiBidXQgZm9jdXMgY2FuIG5vdCBtdXRlIGluIHRoaXMgY2FzZSA/IC0gY2hlY2tcbiAgICAgICAgaWYgKGppZCA9PT0geG1wcC5teUppZCgpKSB7XG5cbiAgICAgICAgICAgIC8vIFRoZSBsb2NhbCBtdXRlIGluZGljYXRvciBpcyBjb250cm9sbGVkIGxvY2FsbHlcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfSovXG4gICAgICAgIHZhciB2aWRlb1NwYW5JZCA9IG51bGw7XG4gICAgICAgIGlmIChqaWQgPT09IEFQUC54bXBwLm15SmlkKCkpIHtcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ2xvY2FsVmlkZW9Db250YWluZXInO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5zdXJlUGVlckNvbnRhaW5lckV4aXN0cyhqaWQpO1xuICAgICAgICAgICAgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIH1cblxuICAgICAgICBtdXRlZEF1ZGlvc1tqaWRdID0gaXNNdXRlZDtcblxuICAgICAgICBpZiAoQVBQLnhtcHAuaXNNb2RlcmF0b3IoKSkge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQudXBkYXRlUmVtb3RlVmlkZW9NZW51KGppZCwgaXNNdXRlZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodmlkZW9TcGFuSWQpXG4gICAgICAgICAgICBWaWRlb0xheW91dC5zaG93QXVkaW9JbmRpY2F0b3IodmlkZW9TcGFuSWQsIGlzTXV0ZWQpO1xuICAgIH0pO1xuXG4gICAgLyoqXG4gICAgICogT24gdmlkZW8gbXV0ZWQgZXZlbnQuXG4gICAgICovXG4gICAgJChkb2N1bWVudCkuYmluZCgndmlkZW9tdXRlZC5tdWMnLCBmdW5jdGlvbiAoZXZlbnQsIGppZCwgdmFsdWUpIHtcbiAgICAgICAgdmFyIGlzTXV0ZWQgPSAodmFsdWUgPT09IFwidHJ1ZVwiKTtcbiAgICAgICAgaWYoIUFQUC5SVEMubXV0ZVJlbW90ZVZpZGVvU3RyZWFtKGppZCwgaXNNdXRlZCkpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgQXZhdGFyLnNob3dVc2VyQXZhdGFyKGppZCwgaXNNdXRlZCk7XG4gICAgICAgIHZhciB2aWRlb1NwYW5JZCA9IG51bGw7XG4gICAgICAgIGlmIChqaWQgPT09IEFQUC54bXBwLm15SmlkKCkpIHtcbiAgICAgICAgICAgIHZpZGVvU3BhbklkID0gJ2xvY2FsVmlkZW9Db250YWluZXInO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5zdXJlUGVlckNvbnRhaW5lckV4aXN0cyhqaWQpO1xuICAgICAgICAgICAgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAodmlkZW9TcGFuSWQpXG4gICAgICAgICAgICBWaWRlb0xheW91dC5zaG93VmlkZW9JbmRpY2F0b3IodmlkZW9TcGFuSWQsIHZhbHVlKTtcbiAgICB9KTtcblxuICAgIC8qKlxuICAgICAqIERpc3BsYXkgbmFtZSBjaGFuZ2VkLlxuICAgICAqL1xuICAgIG15Lm9uRGlzcGxheU5hbWVDaGFuZ2VkID1cbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGppZCwgZGlzcGxheU5hbWUsIHN0YXR1cykge1xuICAgICAgICBpZiAoamlkID09PSAnbG9jYWxWaWRlb0NvbnRhaW5lcidcbiAgICAgICAgICAgIHx8IGppZCA9PT0gQVBQLnhtcHAubXlKaWQoKSkge1xuICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUoJ2xvY2FsVmlkZW9Db250YWluZXInLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgZGlzcGxheU5hbWUpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuZW5zdXJlUGVlckNvbnRhaW5lckV4aXN0cyhqaWQpO1xuICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUoXG4gICAgICAgICAgICAgICAgJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpLFxuICAgICAgICAgICAgICAgIGRpc3BsYXlOYW1lLFxuICAgICAgICAgICAgICAgIHN0YXR1cyk7XG4gICAgICAgIH1cblxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPbiBkb21pbmFudCBzcGVha2VyIGNoYW5nZWQgZXZlbnQuXG4gICAgICovXG4gICAgbXkub25Eb21pbmFudFNwZWFrZXJDaGFuZ2VkID0gZnVuY3Rpb24gKHJlc291cmNlSmlkKSB7XG4gICAgICAgIC8vIFdlIGlnbm9yZSBsb2NhbCB1c2VyIGV2ZW50cy5cbiAgICAgICAgaWYgKHJlc291cmNlSmlkXG4gICAgICAgICAgICAgICAgPT09IEFQUC54bXBwLm15UmVzb3VyY2UoKSlcbiAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICAvLyBVcGRhdGUgdGhlIGN1cnJlbnQgZG9taW5hbnQgc3BlYWtlci5cbiAgICAgICAgaWYgKHJlc291cmNlSmlkICE9PSBjdXJyZW50RG9taW5hbnRTcGVha2VyKSB7XG4gICAgICAgICAgICB2YXIgb2xkU3BlYWtlclZpZGVvU3BhbklkID0gXCJwYXJ0aWNpcGFudF9cIiArIGN1cnJlbnREb21pbmFudFNwZWFrZXIsXG4gICAgICAgICAgICAgICAgbmV3U3BlYWtlclZpZGVvU3BhbklkID0gXCJwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlSmlkO1xuICAgICAgICAgICAgaWYoJChcIiNcIiArIG9sZFNwZWFrZXJWaWRlb1NwYW5JZCArIFwiPnNwYW4uZGlzcGxheW5hbWVcIikudGV4dCgpID09PVxuICAgICAgICAgICAgICAgIGludGVyZmFjZUNvbmZpZy5ERUZBVUxUX0RPTUlOQU5UX1NQRUFLRVJfRElTUExBWV9OQU1FKSB7XG4gICAgICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUob2xkU3BlYWtlclZpZGVvU3BhbklkLCBudWxsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmKCQoXCIjXCIgKyBuZXdTcGVha2VyVmlkZW9TcGFuSWQgKyBcIj5zcGFuLmRpc3BsYXluYW1lXCIpLnRleHQoKSA9PT1cbiAgICAgICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuREVGQVVMVF9SRU1PVEVfRElTUExBWV9OQU1FKSB7XG4gICAgICAgICAgICAgICAgc2V0RGlzcGxheU5hbWUobmV3U3BlYWtlclZpZGVvU3BhbklkLFxuICAgICAgICAgICAgICAgICAgICBpbnRlcmZhY2VDb25maWcuREVGQVVMVF9ET01JTkFOVF9TUEVBS0VSX0RJU1BMQVlfTkFNRSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjdXJyZW50RG9taW5hbnRTcGVha2VyID0gcmVzb3VyY2VKaWQ7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICAvLyBPYnRhaW4gY29udGFpbmVyIGZvciBuZXcgZG9taW5hbnQgc3BlYWtlci5cbiAgICAgICAgdmFyIGNvbnRhaW5lciAgPSBkb2N1bWVudC5nZXRFbGVtZW50QnlJZChcbiAgICAgICAgICAgICAgICAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkKTtcblxuICAgICAgICAvLyBMb2NhbCB2aWRlbyB3aWxsIG5vdCBoYXZlIGNvbnRhaW5lciBmb3VuZCwgYnV0IHRoYXQncyBva1xuICAgICAgICAvLyBzaW5jZSB3ZSBkb24ndCB3YW50IHRvIHN3aXRjaCB0byBsb2NhbCB2aWRlby5cbiAgICAgICAgaWYgKGNvbnRhaW5lciAmJiAhZm9jdXNlZFZpZGVvSW5mbylcbiAgICAgICAge1xuICAgICAgICAgICAgdmFyIHZpZGVvID0gY29udGFpbmVyLmdldEVsZW1lbnRzQnlUYWdOYW1lKFwidmlkZW9cIik7XG5cbiAgICAgICAgICAgIC8vIFVwZGF0ZSB0aGUgbGFyZ2UgdmlkZW8gaWYgdGhlIHZpZGVvIHNvdXJjZSBpcyBhbHJlYWR5IGF2YWlsYWJsZSxcbiAgICAgICAgICAgIC8vIG90aGVyd2lzZSB3YWl0IGZvciB0aGUgXCJ2aWRlb2FjdGl2ZS5qaW5nbGVcIiBldmVudC5cbiAgICAgICAgICAgIGlmICh2aWRlby5sZW5ndGggJiYgdmlkZW9bMF0uY3VycmVudFRpbWUgPiAwKVxuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8oQVBQLlJUQy5nZXRWaWRlb1NyYyh2aWRlb1swXSksIHJlc291cmNlSmlkKTtcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPbiBsYXN0IE4gY2hhbmdlIGV2ZW50LlxuICAgICAqXG4gICAgICogQHBhcmFtIGxhc3RORW5kcG9pbnRzIHRoZSBsaXN0IG9mIGxhc3QgTiBlbmRwb2ludHNcbiAgICAgKiBAcGFyYW0gZW5kcG9pbnRzRW50ZXJpbmdMYXN0TiB0aGUgbGlzdCBjdXJyZW50bHkgZW50ZXJpbmcgbGFzdCBOXG4gICAgICogZW5kcG9pbnRzXG4gICAgICovXG4gICAgbXkub25MYXN0TkVuZHBvaW50c0NoYW5nZWQgPSBmdW5jdGlvbiAoIGxhc3RORW5kcG9pbnRzLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kcG9pbnRzRW50ZXJpbmdMYXN0TixcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0cmVhbSkge1xuICAgICAgICBpZiAobGFzdE5Db3VudCAhPT0gbGFzdE5FbmRwb2ludHMubGVuZ3RoKVxuICAgICAgICAgICAgbGFzdE5Db3VudCA9IGxhc3RORW5kcG9pbnRzLmxlbmd0aDtcblxuICAgICAgICBsYXN0TkVuZHBvaW50c0NhY2hlID0gbGFzdE5FbmRwb2ludHM7XG5cbiAgICAgICAgLy8gU2F5IEEsIEIsIEMsIEQsIEUsIGFuZCBGIGFyZSBpbiBhIGNvbmZlcmVuY2UgYW5kIExhc3ROID0gMy5cbiAgICAgICAgLy9cbiAgICAgICAgLy8gSWYgTGFzdE4gZHJvcHMgdG8sIHNheSwgMiwgYmVjYXVzZSBvZiBhZGFwdGl2aXR5LCB0aGVuIEUgc2hvdWxkIHNlZVxuICAgICAgICAvLyB0aHVtYm5haWxzIGZvciBBLCBCIGFuZCBDLiBBIGFuZCBCIGFyZSBpbiBFJ3Mgc2VydmVyIHNpZGUgTGFzdE4gc2V0LFxuICAgICAgICAvLyBzbyBFIHNlZXMgdGhlbS4gQyBpcyBvbmx5IGluIEUncyBsb2NhbCBMYXN0TiBzZXQuXG4gICAgICAgIC8vXG4gICAgICAgIC8vIElmIEYgc3RhcnRzIHRhbGtpbmcgYW5kIExhc3ROID0gMywgdGhlbiBFIHNob3VsZCBzZWUgdGh1bWJuYWlscyBmb3JcbiAgICAgICAgLy8gRiwgQSwgQi4gQiBnZXRzIFwiZWplY3RlZFwiIGZyb20gRSdzIHNlcnZlciBzaWRlIExhc3ROIHNldCwgYnV0IGl0XG4gICAgICAgIC8vIGVudGVycyBFJ3MgbG9jYWwgTGFzdE4gZWplY3RpbmcgQy5cblxuICAgICAgICAvLyBJbmNyZWFzZSB0aGUgbG9jYWwgTGFzdE4gc2V0IHNpemUsIGlmIG5lY2Vzc2FyeS5cbiAgICAgICAgaWYgKGxhc3ROQ291bnQgPiBsb2NhbExhc3ROQ291bnQpIHtcbiAgICAgICAgICAgIGxvY2FsTGFzdE5Db3VudCA9IGxhc3ROQ291bnQ7XG4gICAgICAgIH1cblxuICAgICAgICAvLyBVcGRhdGUgdGhlIGxvY2FsIExhc3ROIHNldCBwcmVzZXJ2aW5nIHRoZSBvcmRlciBpbiB3aGljaCB0aGVcbiAgICAgICAgLy8gZW5kcG9pbnRzIGFwcGVhcmVkIGluIHRoZSBMYXN0Ti9sb2NhbCBMYXN0TiBzZXQuXG5cbiAgICAgICAgdmFyIG5leHRMb2NhbExhc3ROU2V0ID0gbGFzdE5FbmRwb2ludHMuc2xpY2UoMCk7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbG9jYWxMYXN0TlNldC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKG5leHRMb2NhbExhc3ROU2V0Lmxlbmd0aCA+PSBsb2NhbExhc3ROQ291bnQpIHtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHJlc291cmNlSmlkID0gbG9jYWxMYXN0TlNldFtpXTtcbiAgICAgICAgICAgIGlmIChuZXh0TG9jYWxMYXN0TlNldC5pbmRleE9mKHJlc291cmNlSmlkKSA9PT0gLTEpIHtcbiAgICAgICAgICAgICAgICBuZXh0TG9jYWxMYXN0TlNldC5wdXNoKHJlc291cmNlSmlkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIGxvY2FsTGFzdE5TZXQgPSBuZXh0TG9jYWxMYXN0TlNldDtcblxuICAgICAgICB2YXIgdXBkYXRlTGFyZ2VWaWRlbyA9IGZhbHNlO1xuXG4gICAgICAgIC8vIEhhbmRsZSBMYXN0Ti9sb2NhbCBMYXN0TiBjaGFuZ2VzLlxuICAgICAgICAkKCcjcmVtb3RlVmlkZW9zPnNwYW4nKS5lYWNoKGZ1bmN0aW9uKCBpbmRleCwgZWxlbWVudCApIHtcbiAgICAgICAgICAgIHZhciByZXNvdXJjZUppZCA9IFZpZGVvTGF5b3V0LmdldFBlZXJDb250YWluZXJSZXNvdXJjZUppZChlbGVtZW50KTtcblxuICAgICAgICAgICAgdmFyIGlzUmVjZWl2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgaWYgKHJlc291cmNlSmlkXG4gICAgICAgICAgICAgICAgJiYgbGFzdE5FbmRwb2ludHMuaW5kZXhPZihyZXNvdXJjZUppZCkgPCAwXG4gICAgICAgICAgICAgICAgJiYgbG9jYWxMYXN0TlNldC5pbmRleE9mKHJlc291cmNlSmlkKSA8IDApIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIlJlbW92ZSBmcm9tIGxhc3QgTlwiLCByZXNvdXJjZUppZCk7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdoaWRlJyk7XG4gICAgICAgICAgICAgICAgaXNSZWNlaXZlZCA9IGZhbHNlO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChyZXNvdXJjZUppZFxuICAgICAgICAgICAgICAgICYmICQoJyNwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQpLmlzKCc6dmlzaWJsZScpXG4gICAgICAgICAgICAgICAgJiYgbGFzdE5FbmRwb2ludHMuaW5kZXhPZihyZXNvdXJjZUppZCkgPCAwXG4gICAgICAgICAgICAgICAgJiYgbG9jYWxMYXN0TlNldC5pbmRleE9mKHJlc291cmNlSmlkKSA+PSAwKSB7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdhdmF0YXInKTtcbiAgICAgICAgICAgICAgICBpc1JlY2VpdmVkID0gZmFsc2U7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghaXNSZWNlaXZlZCkge1xuICAgICAgICAgICAgICAgIC8vIHJlc291cmNlSmlkIGhhcyBkcm9wcGVkIG91dCBvZiB0aGUgc2VydmVyIHNpZGUgbGFzdE4gc2V0LCBzb1xuICAgICAgICAgICAgICAgIC8vIGl0IGlzIG5vIGxvbmdlciBiZWluZyByZWNlaXZlZC4gSWYgcmVzb3VyY2VKaWQgd2FzIGJlaW5nXG4gICAgICAgICAgICAgICAgLy8gZGlzcGxheWVkIGluIHRoZSBsYXJnZSB2aWRlbyB3ZSBoYXZlIHRvIHN3aXRjaCB0byBhbm90aGVyXG4gICAgICAgICAgICAgICAgLy8gdXNlci5cbiAgICAgICAgICAgICAgICB2YXIgbGFyZ2VWaWRlb1Jlc291cmNlID0gbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZDtcbiAgICAgICAgICAgICAgICBpZiAoIXVwZGF0ZUxhcmdlVmlkZW8gJiYgcmVzb3VyY2VKaWQgPT09IGxhcmdlVmlkZW9SZXNvdXJjZSkge1xuICAgICAgICAgICAgICAgICAgICB1cGRhdGVMYXJnZVZpZGVvID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIGlmICghZW5kcG9pbnRzRW50ZXJpbmdMYXN0TiB8fCBlbmRwb2ludHNFbnRlcmluZ0xhc3ROLmxlbmd0aCA8IDApXG4gICAgICAgICAgICBlbmRwb2ludHNFbnRlcmluZ0xhc3ROID0gbGFzdE5FbmRwb2ludHM7XG5cbiAgICAgICAgaWYgKGVuZHBvaW50c0VudGVyaW5nTGFzdE4gJiYgZW5kcG9pbnRzRW50ZXJpbmdMYXN0Ti5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICBlbmRwb2ludHNFbnRlcmluZ0xhc3ROLmZvckVhY2goZnVuY3Rpb24gKHJlc291cmNlSmlkKSB7XG5cbiAgICAgICAgICAgICAgICB2YXIgaXNWaXNpYmxlID0gJCgnI3BhcnRpY2lwYW50XycgKyByZXNvdXJjZUppZCkuaXMoJzp2aXNpYmxlJyk7XG4gICAgICAgICAgICAgICAgc2hvd1BlZXJDb250YWluZXIocmVzb3VyY2VKaWQsICdzaG93Jyk7XG4gICAgICAgICAgICAgICAgaWYgKCFpc1Zpc2libGUpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJBZGQgdG8gbGFzdCBOXCIsIHJlc291cmNlSmlkKTtcblxuICAgICAgICAgICAgICAgICAgICB2YXIgamlkID0gQVBQLnhtcHAuZmluZEppZEZyb21SZXNvdXJjZShyZXNvdXJjZUppZCk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBtZWRpYVN0cmVhbSA9IEFQUC5SVEMucmVtb3RlU3RyZWFtc1tqaWRdW01lZGlhU3RyZWFtVHlwZS5WSURFT19UWVBFXTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHNlbCA9ICQoJyNwYXJ0aWNpcGFudF8nICsgcmVzb3VyY2VKaWQgKyAnPnZpZGVvJyk7XG5cbiAgICAgICAgICAgICAgICAgICAgdmFyIHZpZGVvU3RyZWFtID0gQVBQLnNpbXVsY2FzdC5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbShcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhU3RyZWFtLnN0cmVhbSk7XG4gICAgICAgICAgICAgICAgICAgIEFQUC5SVEMuYXR0YWNoTWVkaWFTdHJlYW0oc2VsLCB2aWRlb1N0cmVhbSk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChsYXN0TlBpY2t1cEppZCA9PSBtZWRpYVN0cmVhbS5wZWVyamlkKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBDbGVhbiB1cCB0aGUgbGFzdE4gcGlja3VwIGppZC5cbiAgICAgICAgICAgICAgICAgICAgICAgIGxhc3ROUGlja3VwSmlkID0gbnVsbDtcblxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gRG9uJ3QgZmlyZSB0aGUgZXZlbnRzIGFnYWluLCB0aGV5J3ZlIGFscmVhZHlcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGJlZW4gZmlyZWQgaW4gdGhlIGNvbnRhY3QgbGlzdCBjbGljayBoYW5kbGVyLlxuICAgICAgICAgICAgICAgICAgICAgICAgVmlkZW9MYXlvdXQuaGFuZGxlVmlkZW9UaHVtYkNsaWNrZWQoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJChzZWwpLmF0dHIoJ3NyYycpLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZhbHNlLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKG1lZGlhU3RyZWFtLnBlZXJqaWQpKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlTGFyZ2VWaWRlbyA9IGZhbHNlO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIHdhaXRGb3JSZW1vdGVWaWRlbyhzZWwsIG1lZGlhU3RyZWFtLnNzcmMsIG1lZGlhU3RyZWFtLnN0cmVhbSwgcmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pXG4gICAgICAgIH1cblxuICAgICAgICAvLyBUaGUgZW5kcG9pbnQgdGhhdCB3YXMgYmVpbmcgc2hvd24gaW4gdGhlIGxhcmdlIHZpZGVvIGhhcyBkcm9wcGVkIG91dFxuICAgICAgICAvLyBvZiB0aGUgbGFzdE4gc2V0IGFuZCB0aGVyZSB3YXMgbm8gbGFzdE4gcGlja3VwIGppZC4gV2UgbmVlZCB0byB1cGRhdGVcbiAgICAgICAgLy8gdGhlIGxhcmdlIHZpZGVvIG5vdy5cblxuICAgICAgICBpZiAodXBkYXRlTGFyZ2VWaWRlbykge1xuXG4gICAgICAgICAgICB2YXIgcmVzb3VyY2UsIGNvbnRhaW5lciwgc3JjO1xuICAgICAgICAgICAgdmFyIG15UmVzb3VyY2VcbiAgICAgICAgICAgICAgICA9IEFQUC54bXBwLm15UmVzb3VyY2UoKTtcblxuICAgICAgICAgICAgLy8gRmluZCBvdXQgd2hpY2ggZW5kcG9pbnQgdG8gc2hvdyBpbiB0aGUgbGFyZ2UgdmlkZW8uXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxhc3RORW5kcG9pbnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgcmVzb3VyY2UgPSBsYXN0TkVuZHBvaW50c1tpXTtcbiAgICAgICAgICAgICAgICBpZiAoIXJlc291cmNlIHx8IHJlc291cmNlID09PSBteVJlc291cmNlKVxuICAgICAgICAgICAgICAgICAgICBjb250aW51ZTtcblxuICAgICAgICAgICAgICAgIGNvbnRhaW5lciA9ICQoXCIjcGFydGljaXBhbnRfXCIgKyByZXNvdXJjZSk7XG4gICAgICAgICAgICAgICAgaWYgKGNvbnRhaW5lci5sZW5ndGggPT0gMClcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG5cbiAgICAgICAgICAgICAgICBzcmMgPSAkKCd2aWRlbycsIGNvbnRhaW5lcikuYXR0cignc3JjJyk7XG4gICAgICAgICAgICAgICAgaWYgKCFzcmMpXG4gICAgICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuXG4gICAgICAgICAgICAgICAgLy8gdmlkZW9TcmNUb1NzcmMgbmVlZHMgdG8gYmUgdXBkYXRlIGZvciB0aGlzIGNhbGwgdG8gc3VjY2VlZC5cbiAgICAgICAgICAgICAgICBWaWRlb0xheW91dC51cGRhdGVMYXJnZVZpZGVvKHNyYyk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBteS5vblNpbXVsY2FzdExheWVyc0NoYW5naW5nID0gZnVuY3Rpb24gKGVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzKSB7XG4gICAgICAgIGVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzLmZvckVhY2goZnVuY3Rpb24gKGVzbCkge1xuXG4gICAgICAgICAgICB2YXIgcmVzb3VyY2UgPSBlc2wuZW5kcG9pbnQ7XG5cbiAgICAgICAgICAgIC8vIGlmIGxhc3ROIGlzIGVuYWJsZWQgKmFuZCogdGhlIGVuZHBvaW50IGlzICpub3QqIGluIHRoZSBsYXN0TiBzZXQsXG4gICAgICAgICAgICAvLyB0aGVuIGlnbm9yZSB0aGUgZXZlbnQgKD0gZG8gbm90IHByZWxvYWQgYW55dGhpbmcpLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIFRoZSBicmlkZ2UgY291bGQgcHJvYmFibHkgc3RvcCBzZW5kaW5nIHRoaXMgbWVzc2FnZSBpZiBpdCdzIGZvclxuICAgICAgICAgICAgLy8gYW4gZW5kcG9pbnQgdGhhdCdzIG5vdCBpbiBsYXN0Ti5cblxuICAgICAgICAgICAgaWYgKGxhc3ROQ291bnQgIT0gLTFcbiAgICAgICAgICAgICAgICAmJiAobGFzdE5Db3VudCA8IDEgfHwgbGFzdE5FbmRwb2ludHNDYWNoZS5pbmRleE9mKHJlc291cmNlKSA9PT0gLTEpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcHJpbWFyeVNTUkMgPSBlc2wuc2ltdWxjYXN0TGF5ZXIucHJpbWFyeVNTUkM7XG5cbiAgICAgICAgICAgIC8vIEdldCBzZXNzaW9uIGFuZCBzdHJlYW0gZnJvbSBwcmltYXJ5IHNzcmMuXG4gICAgICAgICAgICB2YXIgcmVzID0gQVBQLnNpbXVsY2FzdC5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbUJ5U1NSQyhwcmltYXJ5U1NSQyk7XG4gICAgICAgICAgICB2YXIgc2lkID0gcmVzLnNpZDtcbiAgICAgICAgICAgIHZhciBlbGVjdGVkU3RyZWFtID0gcmVzLnN0cmVhbTtcblxuICAgICAgICAgICAgaWYgKHNpZCAmJiBlbGVjdGVkU3RyZWFtKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1zaWQgPSBBUFAuc2ltdWxjYXN0LmdldFJlbW90ZVZpZGVvU3RyZWFtSWRCeVNTUkMocHJpbWFyeVNTUkMpO1xuXG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFtlc2wsIHByaW1hcnlTU1JDLCBtc2lkLCBzaWQsIGVsZWN0ZWRTdHJlYW1dKTtcblxuICAgICAgICAgICAgICAgIHZhciBwcmVsb2FkID0gKFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKEFQUC54bXBwLmdldEppZEZyb21TU1JDKHByaW1hcnlTU1JDKSkgPT0gbGFyZ2VWaWRlb1N0YXRlLnVzZXJSZXNvdXJjZUppZCk7XG5cbiAgICAgICAgICAgICAgICBpZiAocHJlbG9hZCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQpXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICQobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQpLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbygnUHJlbG9hZGluZyByZW1vdGUgdmlkZW8nKTtcbiAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQgPSAkKCc8dmlkZW8gYXV0b3BsYXk+PC92aWRlbz4nKTtcbiAgICAgICAgICAgICAgICAgICAgLy8gc3NyY3MgYXJlIHVuaXF1ZSBpbiBhbiBydHAgc2Vzc2lvblxuICAgICAgICAgICAgICAgICAgICBsYXJnZVZpZGVvU3RhdGUucHJlbG9hZF9zc3JjID0gcHJpbWFyeVNTUkM7XG5cbiAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5hdHRhY2hNZWRpYVN0cmVhbShsYXJnZVZpZGVvU3RhdGUucHJlbG9hZCwgZWxlY3RlZFN0cmVhbSlcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignQ291bGQgbm90IGZpbmQgYSBzdHJlYW0gb3IgYSBzZXNzaW9uLicsIHNpZCwgZWxlY3RlZFN0cmVhbSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBPbiBzaW11bGNhc3QgbGF5ZXJzIGNoYW5nZWQgZXZlbnQuXG4gICAgICovXG4gICAgbXkub25TaW11bGNhc3RMYXllcnNDaGFuZ2VkID0gZnVuY3Rpb24gKGVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzKSB7XG4gICAgICAgIGVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzLmZvckVhY2goZnVuY3Rpb24gKGVzbCkge1xuXG4gICAgICAgICAgICB2YXIgcmVzb3VyY2UgPSBlc2wuZW5kcG9pbnQ7XG5cbiAgICAgICAgICAgIC8vIGlmIGxhc3ROIGlzIGVuYWJsZWQgKmFuZCogdGhlIGVuZHBvaW50IGlzICpub3QqIGluIHRoZSBsYXN0TiBzZXQsXG4gICAgICAgICAgICAvLyB0aGVuIGlnbm9yZSB0aGUgZXZlbnQgKD0gZG8gbm90IGNoYW5nZSBsYXJnZSB2aWRlby90aHVtYm5haWxcbiAgICAgICAgICAgIC8vIFNSQ3MpLlxuICAgICAgICAgICAgLy9cbiAgICAgICAgICAgIC8vIE5vdGUgdGhhdCBldmVuIGlmIHdlIGlnbm9yZSB0aGUgXCJjaGFuZ2VkXCIgZXZlbnQgaW4gdGhpcyBldmVudFxuICAgICAgICAgICAgLy8gaGFuZGxlciwgdGhlIGJyaWRnZSBtdXN0IGNvbnRpbnVlIHNlbmRpbmcgdGhlc2UgZXZlbnRzIGJlY2F1c2VcbiAgICAgICAgICAgIC8vIHRoZSBzaW11bGNhc3QgY29kZSBpbiBzaW11bGNhc3QuanMgdXNlcyBpdCB0byBrbm93IHdoYXQncyBnb2luZ1xuICAgICAgICAgICAgLy8gdG8gYmUgc3RyZWFtZWQgYnkgdGhlIGJyaWRnZSB3aGVuL2lmIHRoZSBlbmRwb2ludCBnZXRzIGJhY2sgaW50b1xuICAgICAgICAgICAgLy8gdGhlIGxhc3ROIHNldC5cblxuICAgICAgICAgICAgaWYgKGxhc3ROQ291bnQgIT0gLTFcbiAgICAgICAgICAgICAgICAmJiAobGFzdE5Db3VudCA8IDEgfHwgbGFzdE5FbmRwb2ludHNDYWNoZS5pbmRleE9mKHJlc291cmNlKSA9PT0gLTEpKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICB2YXIgcHJpbWFyeVNTUkMgPSBlc2wuc2ltdWxjYXN0TGF5ZXIucHJpbWFyeVNTUkM7XG5cbiAgICAgICAgICAgIC8vIEdldCBzZXNzaW9uIGFuZCBzdHJlYW0gZnJvbSBwcmltYXJ5IHNzcmMuXG4gICAgICAgICAgICB2YXIgcmVzID0gQVBQLnNpbXVsY2FzdC5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbUJ5U1NSQyhwcmltYXJ5U1NSQyk7XG4gICAgICAgICAgICB2YXIgc2lkID0gcmVzLnNpZDtcbiAgICAgICAgICAgIHZhciBlbGVjdGVkU3RyZWFtID0gcmVzLnN0cmVhbTtcblxuICAgICAgICAgICAgaWYgKHNpZCAmJiBlbGVjdGVkU3RyZWFtKSB7XG4gICAgICAgICAgICAgICAgdmFyIG1zaWQgPSBBUFAuc2ltdWxjYXN0LmdldFJlbW90ZVZpZGVvU3RyZWFtSWRCeVNTUkMocHJpbWFyeVNTUkMpO1xuXG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKCdTd2l0Y2hpbmcgc2ltdWxjYXN0IHN1YnN0cmVhbS4nKTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oW2VzbCwgcHJpbWFyeVNTUkMsIG1zaWQsIHNpZCwgZWxlY3RlZFN0cmVhbV0pO1xuXG4gICAgICAgICAgICAgICAgdmFyIG1zaWRQYXJ0cyA9IG1zaWQuc3BsaXQoJyAnKTtcbiAgICAgICAgICAgICAgICB2YXIgc2VsUmVtb3RlVmlkZW8gPSAkKFsnIycsICdyZW1vdGVWaWRlb18nLCBzaWQsICdfJywgbXNpZFBhcnRzWzBdXS5qb2luKCcnKSk7XG5cbiAgICAgICAgICAgICAgICB2YXIgdXBkYXRlTGFyZ2VWaWRlbyA9IChTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChBUFAueG1wcC5nZXRKaWRGcm9tU1NSQyhwcmltYXJ5U1NSQykpXG4gICAgICAgICAgICAgICAgICAgID09IGxhcmdlVmlkZW9TdGF0ZS51c2VyUmVzb3VyY2VKaWQpO1xuICAgICAgICAgICAgICAgIHZhciB1cGRhdGVGb2N1c2VkVmlkZW9TcmMgPSAoZm9jdXNlZFZpZGVvSW5mbyAmJiBmb2N1c2VkVmlkZW9JbmZvLnNyYyAmJiBmb2N1c2VkVmlkZW9JbmZvLnNyYyAhPSAnJyAmJlxuICAgICAgICAgICAgICAgICAgICAoQVBQLlJUQy5nZXRWaWRlb1NyYyhzZWxSZW1vdGVWaWRlb1swXSkgPT0gZm9jdXNlZFZpZGVvSW5mby5zcmMpKTtcblxuICAgICAgICAgICAgICAgIHZhciBlbGVjdGVkU3RyZWFtVXJsO1xuICAgICAgICAgICAgICAgIGlmIChsYXJnZVZpZGVvU3RhdGUucHJlbG9hZF9zc3JjID09IHByaW1hcnlTU1JDKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5zZXRWaWRlb1NyYyhzZWxSZW1vdGVWaWRlb1swXSwgQVBQLlJUQy5nZXRWaWRlb1NyYyhsYXJnZVZpZGVvU3RhdGUucHJlbG9hZFswXSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBpZiAobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWRcbiAgICAgICAgICAgICAgICAgICAgICAgICYmIGxhcmdlVmlkZW9TdGF0ZS5wcmVsb2FkICE9IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICQobGFyZ2VWaWRlb1N0YXRlLnByZWxvYWQpLnJlbW92ZSgpO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgbGFyZ2VWaWRlb1N0YXRlLnByZWxvYWRfc3NyYyA9IDA7XG5cbiAgICAgICAgICAgICAgICAgICAgQVBQLlJUQy5hdHRhY2hNZWRpYVN0cmVhbShzZWxSZW1vdGVWaWRlbywgZWxlY3RlZFN0cmVhbSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIGppZCA9IEFQUC54bXBwLmdldEppZEZyb21TU1JDKHByaW1hcnlTU1JDKTtcblxuICAgICAgICAgICAgICAgIGlmICh1cGRhdGVMYXJnZVZpZGVvKSB7XG4gICAgICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LnVwZGF0ZUxhcmdlVmlkZW8oQVBQLlJUQy5nZXRWaWRlb1NyYyhzZWxSZW1vdGVWaWRlb1swXSksIG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpKTtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICBpZiAodXBkYXRlRm9jdXNlZFZpZGVvU3JjKSB7XG4gICAgICAgICAgICAgICAgICAgIGZvY3VzZWRWaWRlb0luZm8uc3JjID0gQVBQLlJUQy5nZXRWaWRlb1NyYyhzZWxSZW1vdGVWaWRlb1swXSk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIHZpZGVvSWQ7XG4gICAgICAgICAgICAgICAgaWYocmVzb3VyY2UgPT0gQVBQLnhtcHAubXlSZXNvdXJjZSgpKVxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgdmlkZW9JZCA9IFwibG9jYWxWaWRlb0NvbnRhaW5lclwiO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB2aWRlb0lkID0gXCJwYXJ0aWNpcGFudF9cIiArIHJlc291cmNlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgY29ubmVjdGlvbkluZGljYXRvciA9IFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW3ZpZGVvSWRdO1xuICAgICAgICAgICAgICAgIGlmKGNvbm5lY3Rpb25JbmRpY2F0b3IpXG4gICAgICAgICAgICAgICAgICAgIGNvbm5lY3Rpb25JbmRpY2F0b3IudXBkYXRlUG9wb3ZlckRhdGEoKTtcblxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdDb3VsZCBub3QgZmluZCBhIHN0cmVhbSBvciBhIHNpZC4nLCBzaWQsIGVsZWN0ZWRTdHJlYW0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyBsb2NhbCBzdGF0c1xuICAgICAqIEBwYXJhbSBwZXJjZW50XG4gICAgICogQHBhcmFtIG9iamVjdFxuICAgICAqL1xuICAgIG15LnVwZGF0ZUxvY2FsQ29ubmVjdGlvblN0YXRzID0gZnVuY3Rpb24gKHBlcmNlbnQsIG9iamVjdCkge1xuICAgICAgICB2YXIgcmVzb2x1dGlvbiA9IG51bGw7XG4gICAgICAgIGlmKG9iamVjdC5yZXNvbHV0aW9uICE9PSBudWxsKVxuICAgICAgICB7XG4gICAgICAgICAgICByZXNvbHV0aW9uID0gb2JqZWN0LnJlc29sdXRpb247XG4gICAgICAgICAgICBvYmplY3QucmVzb2x1dGlvbiA9IHJlc29sdXRpb25bQVBQLnhtcHAubXlKaWQoKV07XG4gICAgICAgICAgICBkZWxldGUgcmVzb2x1dGlvbltBUFAueG1wcC5teUppZCgpXTtcbiAgICAgICAgfVxuICAgICAgICB1cGRhdGVTdGF0c0luZGljYXRvcihcImxvY2FsVmlkZW9Db250YWluZXJcIiwgcGVyY2VudCwgb2JqZWN0KTtcbiAgICAgICAgZm9yKHZhciBqaWQgaW4gcmVzb2x1dGlvbilcbiAgICAgICAge1xuICAgICAgICAgICAgaWYocmVzb2x1dGlvbltqaWRdID09PSBudWxsKVxuICAgICAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICAgICAgdmFyIGlkID0gJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpO1xuICAgICAgICAgICAgaWYoVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbaWRdKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIFZpZGVvTGF5b3V0LmNvbm5lY3Rpb25JbmRpY2F0b3JzW2lkXS51cGRhdGVSZXNvbHV0aW9uKHJlc29sdXRpb25bamlkXSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cblxuICAgIH07XG5cbiAgICAvKipcbiAgICAgKiBVcGRhdGVzIHJlbW90ZSBzdGF0cy5cbiAgICAgKiBAcGFyYW0gamlkIHRoZSBqaWQgYXNzb2NpYXRlZCB3aXRoIHRoZSBzdGF0c1xuICAgICAqIEBwYXJhbSBwZXJjZW50IHRoZSBjb25uZWN0aW9uIHF1YWxpdHkgcGVyY2VudFxuICAgICAqIEBwYXJhbSBvYmplY3QgdGhlIHN0YXRzIGRhdGFcbiAgICAgKi9cbiAgICBteS51cGRhdGVDb25uZWN0aW9uU3RhdHMgPSBmdW5jdGlvbiAoamlkLCBwZXJjZW50LCBvYmplY3QpIHtcbiAgICAgICAgdmFyIHJlc291cmNlSmlkID0gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKTtcblxuICAgICAgICB2YXIgdmlkZW9TcGFuSWQgPSAncGFydGljaXBhbnRfJyArIHJlc291cmNlSmlkO1xuICAgICAgICB1cGRhdGVTdGF0c0luZGljYXRvcih2aWRlb1NwYW5JZCwgcGVyY2VudCwgb2JqZWN0KTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyB0aGUgY29ubmVjdGlvblxuICAgICAqIEBwYXJhbSBqaWRcbiAgICAgKi9cbiAgICBteS5yZW1vdmVDb25uZWN0aW9uSW5kaWNhdG9yID0gZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1sncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCldKVxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpXS5yZW1vdmUoKTtcbiAgICB9O1xuXG4gICAgLyoqXG4gICAgICogSGlkZXMgdGhlIGNvbm5lY3Rpb24gaW5kaWNhdG9yXG4gICAgICogQHBhcmFtIGppZFxuICAgICAqL1xuICAgIG15LmhpZGVDb25uZWN0aW9uSW5kaWNhdG9yID0gZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBpZihWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9yc1sncGFydGljaXBhbnRfJyArIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCldKVxuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbJ3BhcnRpY2lwYW50XycgKyBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpXS5oaWRlKCk7XG4gICAgfTtcblxuICAgIC8qKlxuICAgICAqIEhpZGVzIGFsbCB0aGUgaW5kaWNhdG9yc1xuICAgICAqL1xuICAgIG15Lm9uU3RhdHNTdG9wID0gZnVuY3Rpb24gKCkge1xuICAgICAgICBmb3IodmFyIGluZGljYXRvciBpbiBWaWRlb0xheW91dC5jb25uZWN0aW9uSW5kaWNhdG9ycylcbiAgICAgICAge1xuICAgICAgICAgICAgVmlkZW9MYXlvdXQuY29ubmVjdGlvbkluZGljYXRvcnNbaW5kaWNhdG9yXS5oaWRlSW5kaWNhdG9yKCk7XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgbXkucGFydGljaXBhbnRMZWZ0ID0gZnVuY3Rpb24gKGppZCkge1xuICAgICAgICAvLyBVbmxvY2sgbGFyZ2UgdmlkZW9cbiAgICAgICAgaWYgKGZvY3VzZWRWaWRlb0luZm8gJiYgZm9jdXNlZFZpZGVvSW5mby5qaWQgPT09IGppZClcbiAgICAgICAge1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiRm9jdXNlZCB2aWRlbyBvd25lciBoYXMgbGVmdCB0aGUgY29uZmVyZW5jZVwiKTtcbiAgICAgICAgICAgIGZvY3VzZWRWaWRlb0luZm8gPSBudWxsO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIG15O1xufShWaWRlb0xheW91dCB8fCB7fSkpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IFZpZGVvTGF5b3V0OyIsIi8vdmFyIG5vdW5zID0gW1xuLy9dO1xudmFyIHBsdXJhbE5vdW5zID0gW1xuICAgIFwiQWxpZW5zXCIsIFwiQW5pbWFsc1wiLCBcIkFudGVsb3Blc1wiLCBcIkFudHNcIiwgXCJBcGVzXCIsIFwiQXBwbGVzXCIsIFwiQmFib29uc1wiLCBcIkJhY3RlcmlhXCIsIFwiQmFkZ2Vyc1wiLCBcIkJhbmFuYXNcIiwgXCJCYXRzXCIsXG4gICAgXCJCZWFyc1wiLCBcIkJpcmRzXCIsIFwiQm9ub2Jvc1wiLCBcIkJyaWRlc1wiLCBcIkJ1Z3NcIiwgXCJCdWxsc1wiLCBcIkJ1dHRlcmZsaWVzXCIsIFwiQ2hlZXRhaHNcIixcbiAgICBcIkNoZXJyaWVzXCIsIFwiQ2hpY2tlblwiLCBcIkNoaWxkcmVuXCIsIFwiQ2hpbXBzXCIsIFwiQ2xvd25zXCIsIFwiQ293c1wiLCBcIkNyZWF0dXJlc1wiLCBcIkRpbm9zYXVyc1wiLCBcIkRvZ3NcIiwgXCJEb2xwaGluc1wiLFxuICAgIFwiRG9ua2V5c1wiLCBcIkRyYWdvbnNcIiwgXCJEdWNrc1wiLCBcIkR3YXJmc1wiLCBcIkVhZ2xlc1wiLCBcIkVsZXBoYW50c1wiLCBcIkVsdmVzXCIsIFwiRkFJTFwiLCBcIkZhdGhlcnNcIixcbiAgICBcIkZpc2hcIiwgXCJGbG93ZXJzXCIsIFwiRnJvZ3NcIiwgXCJGcnVpdFwiLCBcIkZ1bmdpXCIsIFwiR2FsYXhpZXNcIiwgXCJHZWVzZVwiLCBcIkdvYXRzXCIsXG4gICAgXCJHb3JpbGxhc1wiLCBcIkhlZGdlaG9nc1wiLCBcIkhpcHBvc1wiLCBcIkhvcnNlc1wiLCBcIkh1bnRlcnNcIiwgXCJJbnNlY3RzXCIsIFwiS2lkc1wiLCBcIktuaWdodHNcIixcbiAgICBcIkxlbW9uc1wiLCBcIkxlbXVyc1wiLCBcIkxlb3BhcmRzXCIsIFwiTGlmZUZvcm1zXCIsIFwiTGlvbnNcIiwgXCJMaXphcmRzXCIsIFwiTWljZVwiLCBcIk1vbmtleXNcIiwgXCJNb25zdGVyc1wiLFxuICAgIFwiTXVzaHJvb21zXCIsIFwiT2N0b3BvZGVzXCIsIFwiT3Jhbmdlc1wiLCBcIk9yYW5ndXRhbnNcIiwgXCJPcmdhbmlzbXNcIiwgXCJQYW50c1wiLCBcIlBhcnJvdHNcIiwgXCJQZW5ndWluc1wiLFxuICAgIFwiUGVvcGxlXCIsIFwiUGlnZW9uc1wiLCBcIlBpZ3NcIiwgXCJQaW5lYXBwbGVzXCIsIFwiUGxhbnRzXCIsIFwiUG90YXRvZXNcIiwgXCJQcmllc3RzXCIsIFwiUmF0c1wiLCBcIlJlcHRpbGVzXCIsIFwiUmVwdGlsaWFuc1wiLFxuICAgIFwiUmhpbm9zXCIsIFwiU2VhZ3VsbHNcIiwgXCJTaGVlcFwiLCBcIlNpYmxpbmdzXCIsIFwiU25ha2VzXCIsIFwiU3BhZ2hldHRpXCIsIFwiU3BpZGVyc1wiLCBcIlNxdWlkXCIsIFwiU3F1aXJyZWxzXCIsXG4gICAgXCJTdGFyc1wiLCBcIlN0dWRlbnRzXCIsIFwiVGVhY2hlcnNcIiwgXCJUaWdlcnNcIiwgXCJUb21hdG9lc1wiLCBcIlRyZWVzXCIsIFwiVmFtcGlyZXNcIiwgXCJWZWdldGFibGVzXCIsIFwiVmlydXNlc1wiLCBcIlZ1bGNhbnNcIixcbiAgICBcIldhcmV3b2x2ZXNcIiwgXCJXZWFzZWxzXCIsIFwiV2hhbGVzXCIsIFwiV2l0Y2hlc1wiLCBcIldpemFyZHNcIiwgXCJXb2x2ZXNcIiwgXCJXb3JrZXJzXCIsIFwiV29ybXNcIiwgXCJaZWJyYXNcIlxuXTtcbi8vdmFyIHBsYWNlcyA9IFtcbi8vXCJQdWJcIiwgXCJVbml2ZXJzaXR5XCIsIFwiQWlycG9ydFwiLCBcIkxpYnJhcnlcIiwgXCJNYWxsXCIsIFwiVGhlYXRlclwiLCBcIlN0YWRpdW1cIiwgXCJPZmZpY2VcIiwgXCJTaG93XCIsIFwiR2FsbG93c1wiLCBcIkJlYWNoXCIsXG4vLyBcIkNlbWV0ZXJ5XCIsIFwiSG9zcGl0YWxcIiwgXCJSZWNlcHRpb25cIiwgXCJSZXN0YXVyYW50XCIsIFwiQmFyXCIsIFwiQ2h1cmNoXCIsIFwiSG91c2VcIiwgXCJTY2hvb2xcIiwgXCJTcXVhcmVcIiwgXCJWaWxsYWdlXCIsXG4vLyBcIkNpbmVtYVwiLCBcIk1vdmllc1wiLCBcIlBhcnR5XCIsIFwiUmVzdHJvb21cIiwgXCJFbmRcIiwgXCJKYWlsXCIsIFwiUG9zdE9mZmljZVwiLCBcIlN0YXRpb25cIiwgXCJDaXJjdXNcIiwgXCJHYXRlc1wiLCBcIkVudHJhbmNlXCIsXG4vLyBcIkJyaWRnZVwiXG4vL107XG52YXIgdmVyYnMgPSBbXG4gICAgXCJBYmFuZG9uXCIsIFwiQWRhcHRcIiwgXCJBZHZlcnRpc2VcIiwgXCJBbnN3ZXJcIiwgXCJBbnRpY2lwYXRlXCIsIFwiQXBwcmVjaWF0ZVwiLFxuICAgIFwiQXBwcm9hY2hcIiwgXCJBcmd1ZVwiLCBcIkFza1wiLCBcIkJpdGVcIiwgXCJCbG9zc29tXCIsIFwiQmx1c2hcIiwgXCJCcmVhdGhlXCIsIFwiQnJlZWRcIiwgXCJCcmliZVwiLCBcIkJ1cm5cIiwgXCJDYWxjdWxhdGVcIixcbiAgICBcIkNsZWFuXCIsIFwiQ29kZVwiLCBcIkNvbW11bmljYXRlXCIsIFwiQ29tcHV0ZVwiLCBcIkNvbmZlc3NcIiwgXCJDb25maXNjYXRlXCIsIFwiQ29uanVnYXRlXCIsIFwiQ29uanVyZVwiLCBcIkNvbnN1bWVcIixcbiAgICBcIkNvbnRlbXBsYXRlXCIsIFwiQ3Jhd2xcIiwgXCJEYW5jZVwiLCBcIkRlbGVnYXRlXCIsIFwiRGV2b3VyXCIsIFwiRGV2ZWxvcFwiLCBcIkRpZmZlclwiLCBcIkRpc2N1c3NcIixcbiAgICBcIkRpc3NvbHZlXCIsIFwiRHJpbmtcIiwgXCJFYXRcIiwgXCJFbGFib3JhdGVcIiwgXCJFbWFuY2lwYXRlXCIsIFwiRXN0aW1hdGVcIiwgXCJFeHBpcmVcIiwgXCJFeHRpbmd1aXNoXCIsXG4gICAgXCJFeHRyYWN0XCIsIFwiRkFJTFwiLCBcIkZhY2lsaXRhdGVcIiwgXCJGYWxsXCIsIFwiRmVlZFwiLCBcIkZpbmlzaFwiLCBcIkZsb3NzXCIsIFwiRmx5XCIsIFwiRm9sbG93XCIsIFwiRnJhZ21lbnRcIiwgXCJGcmVlemVcIixcbiAgICBcIkdhdGhlclwiLCBcIkdsb3dcIiwgXCJHcm93XCIsIFwiSGV4XCIsIFwiSGlkZVwiLCBcIkh1Z1wiLCBcIkh1cnJ5XCIsIFwiSW1wcm92ZVwiLCBcIkludGVyc2VjdFwiLCBcIkludmVzdGlnYXRlXCIsIFwiSmlueFwiLFxuICAgIFwiSm9rZVwiLCBcIkp1YmlsYXRlXCIsIFwiS2lzc1wiLCBcIkxhdWdoXCIsIFwiTWFuYWdlXCIsIFwiTWVldFwiLCBcIk1lcmdlXCIsIFwiTW92ZVwiLCBcIk9iamVjdFwiLCBcIk9ic2VydmVcIiwgXCJPZmZlclwiLFxuICAgIFwiUGFpbnRcIiwgXCJQYXJ0aWNpcGF0ZVwiLCBcIlBhcnR5XCIsIFwiUGVyZm9ybVwiLCBcIlBsYW5cIiwgXCJQdXJzdWVcIiwgXCJQaWVyY2VcIiwgXCJQbGF5XCIsIFwiUG9zdHBvbmVcIiwgXCJQcmF5XCIsIFwiUHJvY2xhaW1cIixcbiAgICBcIlF1ZXN0aW9uXCIsIFwiUmVhZFwiLCBcIlJlY2tvblwiLCBcIlJlam9pY2VcIiwgXCJSZXByZXNlbnRcIiwgXCJSZXNpemVcIiwgXCJSaHltZVwiLCBcIlNjcmVhbVwiLCBcIlNlYXJjaFwiLCBcIlNlbGVjdFwiLCBcIlNoYXJlXCIsIFwiU2hvb3RcIixcbiAgICBcIlNob3V0XCIsIFwiU2lnbmFsXCIsIFwiU2luZ1wiLCBcIlNrYXRlXCIsIFwiU2xlZXBcIiwgXCJTbWlsZVwiLCBcIlNtb2tlXCIsIFwiU29sdmVcIiwgXCJTcGVsbFwiLCBcIlN0ZWVyXCIsIFwiU3RpbmtcIixcbiAgICBcIlN1YnN0aXR1dGVcIiwgXCJTd2ltXCIsIFwiVGFzdGVcIiwgXCJUZWFjaFwiLCBcIlRlcm1pbmF0ZVwiLCBcIlRoaW5rXCIsIFwiVHlwZVwiLCBcIlVuaXRlXCIsIFwiVmFuaXNoXCIsIFwiV29yc2hpcFwiXG5dO1xudmFyIGFkdmVyYnMgPSBbXG4gICAgXCJBYnNlbnRseVwiLCBcIkFjY3VyYXRlbHlcIiwgXCJBY2N1c2luZ2x5XCIsIFwiQWRvcmFibHlcIiwgXCJBbGxUaGVUaW1lXCIsIFwiQWxvbmVcIiwgXCJBbHdheXNcIiwgXCJBbWF6aW5nbHlcIiwgXCJBbmdyaWx5XCIsXG4gICAgXCJBbnhpb3VzbHlcIiwgXCJBbnl3aGVyZVwiLCBcIkFwcGFsbGluZ2x5XCIsIFwiQXBwYXJlbnRseVwiLCBcIkFydGljdWxhdGVseVwiLCBcIkFzdG9uaXNoaW5nbHlcIiwgXCJCYWRseVwiLCBcIkJhcmVseVwiLFxuICAgIFwiQmVhdXRpZnVsbHlcIiwgXCJCbGluZGx5XCIsIFwiQnJhdmVseVwiLCBcIkJyaWdodGx5XCIsIFwiQnJpc2tseVwiLCBcIkJydXRhbGx5XCIsIFwiQ2FsbWx5XCIsIFwiQ2FyZWZ1bGx5XCIsIFwiQ2FzdWFsbHlcIixcbiAgICBcIkNhdXRpb3VzbHlcIiwgXCJDbGV2ZXJseVwiLCBcIkNvbnN0YW50bHlcIiwgXCJDb3JyZWN0bHlcIiwgXCJDcmF6aWx5XCIsIFwiQ3VyaW91c2x5XCIsIFwiQ3luaWNhbGx5XCIsIFwiRGFpbHlcIixcbiAgICBcIkRhbmdlcm91c2x5XCIsIFwiRGVsaWJlcmF0ZWx5XCIsIFwiRGVsaWNhdGVseVwiLCBcIkRlc3BlcmF0ZWx5XCIsIFwiRGlzY3JlZXRseVwiLCBcIkVhZ2VybHlcIiwgXCJFYXNpbHlcIiwgXCJFdXBob3JpY2x5XCIsXG4gICAgXCJFdmVubHlcIiwgXCJFdmVyeXdoZXJlXCIsIFwiRXhhY3RseVwiLCBcIkV4cGVjdGFudGx5XCIsIFwiRXh0ZW5zaXZlbHlcIiwgXCJGQUlMXCIsIFwiRmVyb2Npb3VzbHlcIiwgXCJGaWVyY2VseVwiLCBcIkZpbmVseVwiLFxuICAgIFwiRmxhdGx5XCIsIFwiRnJlcXVlbnRseVwiLCBcIkZyaWdodGVuaW5nbHlcIiwgXCJHZW50bHlcIiwgXCJHbG9yaW91c2x5XCIsIFwiR3JpbWx5XCIsIFwiR3VpbHRpbHlcIiwgXCJIYXBwaWx5XCIsXG4gICAgXCJIYXJkXCIsIFwiSGFzdGlseVwiLCBcIkhlcm9pY2FsbHlcIiwgXCJIaWdoXCIsIFwiSGlnaGx5XCIsIFwiSG91cmx5XCIsIFwiSHVtYmx5XCIsIFwiSHlzdGVyaWNhbGx5XCIsIFwiSW1tZW5zZWx5XCIsXG4gICAgXCJJbXBhcnRpYWxseVwiLCBcIkltcG9saXRlbHlcIiwgXCJJbmRpZmZlcmVudGx5XCIsIFwiSW50ZW5zZWx5XCIsIFwiSmVhbG91c2x5XCIsIFwiSm92aWFsbHlcIiwgXCJLaW5kbHlcIiwgXCJMYXppbHlcIixcbiAgICBcIkxpZ2h0bHlcIiwgXCJMb3VkbHlcIiwgXCJMb3ZpbmdseVwiLCBcIkxveWFsbHlcIiwgXCJNYWduaWZpY2VudGx5XCIsIFwiTWFsZXZvbGVudGx5XCIsIFwiTWVycmlseVwiLCBcIk1pZ2h0aWx5XCIsIFwiTWlzZXJhYmx5XCIsXG4gICAgXCJNeXN0ZXJpb3VzbHlcIiwgXCJOT1RcIiwgXCJOZXJ2b3VzbHlcIiwgXCJOaWNlbHlcIiwgXCJOb3doZXJlXCIsIFwiT2JqZWN0aXZlbHlcIiwgXCJPYm5veGlvdXNseVwiLCBcIk9ic2Vzc2l2ZWx5XCIsXG4gICAgXCJPYnZpb3VzbHlcIiwgXCJPZnRlblwiLCBcIlBhaW5mdWxseVwiLCBcIlBhdGllbnRseVwiLCBcIlBsYXlmdWxseVwiLCBcIlBvbGl0ZWx5XCIsIFwiUG9vcmx5XCIsIFwiUHJlY2lzZWx5XCIsIFwiUHJvbXB0bHlcIixcbiAgICBcIlF1aWNrbHlcIiwgXCJRdWlldGx5XCIsIFwiUmFuZG9tbHlcIiwgXCJSYXBpZGx5XCIsIFwiUmFyZWx5XCIsIFwiUmVja2xlc3NseVwiLCBcIlJlZ3VsYXJseVwiLCBcIlJlbW9yc2VmdWxseVwiLCBcIlJlc3BvbnNpYmx5XCIsXG4gICAgXCJSdWRlbHlcIiwgXCJSdXRobGVzc2x5XCIsIFwiU2FkbHlcIiwgXCJTY29ybmZ1bGx5XCIsIFwiU2VhbWxlc3NseVwiLCBcIlNlbGRvbVwiLCBcIlNlbGZpc2hseVwiLCBcIlNlcmlvdXNseVwiLCBcIlNoYWtpbHlcIixcbiAgICBcIlNoYXJwbHlcIiwgXCJTaWRld2F5c1wiLCBcIlNpbGVudGx5XCIsIFwiU2xlZXBpbHlcIiwgXCJTbGlnaHRseVwiLCBcIlNsb3dseVwiLCBcIlNseWx5XCIsIFwiU21vb3RobHlcIiwgXCJTb2Z0bHlcIiwgXCJTb2xlbW5seVwiLCBcIlN0ZWFkaWx5XCIsIFwiU3Rlcm5seVwiLCBcIlN0cmFuZ2VseVwiLCBcIlN0cm9uZ2x5XCIsIFwiU3R1bm5pbmdseVwiLCBcIlN1cmVseVwiLCBcIlRlbmRlcmx5XCIsIFwiVGhvdWdodGZ1bGx5XCIsXG4gICAgXCJUaWdodGx5XCIsIFwiVW5lYXNpbHlcIiwgXCJWYW5pc2hpbmdseVwiLCBcIlZpb2xlbnRseVwiLCBcIldhcm1seVwiLCBcIldlYWtseVwiLCBcIldlYXJpbHlcIiwgXCJXZWVrbHlcIiwgXCJXZWlyZGx5XCIsIFwiV2VsbFwiLFxuICAgIFwiV2VsbFwiLCBcIldpY2tlZGx5XCIsIFwiV2lsZGx5XCIsIFwiV2lzZWx5XCIsIFwiV29uZGVyZnVsbHlcIiwgXCJZZWFybHlcIlxuXTtcbnZhciBhZGplY3RpdmVzID0gW1xuICAgIFwiQWJvbWluYWJsZVwiLCBcIkFjY3VyYXRlXCIsIFwiQWRvcmFibGVcIiwgXCJBbGxcIiwgXCJBbGxlZ2VkXCIsIFwiQW5jaWVudFwiLCBcIkFuZ3J5XCIsIFwiQW5ncnlcIiwgXCJBbnhpb3VzXCIsIFwiQXBwYWxsaW5nXCIsXG4gICAgXCJBcHBhcmVudFwiLCBcIkFzdG9uaXNoaW5nXCIsIFwiQXR0cmFjdGl2ZVwiLCBcIkF3ZXNvbWVcIiwgXCJCYWJ5XCIsIFwiQmFkXCIsIFwiQmVhdXRpZnVsXCIsIFwiQmVuaWduXCIsIFwiQmlnXCIsIFwiQml0dGVyXCIsXG4gICAgXCJCbGluZFwiLCBcIkJsdWVcIiwgXCJCb2xkXCIsIFwiQnJhdmVcIiwgXCJCcmlnaHRcIiwgXCJCcmlza1wiLCBcIkNhbG1cIiwgXCJDYW1vdWZsYWdlZFwiLCBcIkNhc3VhbFwiLCBcIkNhdXRpb3VzXCIsXG4gICAgXCJDaG9wcHlcIiwgXCJDaG9zZW5cIiwgXCJDbGV2ZXJcIiwgXCJDb2xkXCIsIFwiQ29vbFwiLCBcIkNyYXdseVwiLCBcIkNyYXp5XCIsIFwiQ3JlZXB5XCIsIFwiQ3J1ZWxcIiwgXCJDdXJpb3VzXCIsIFwiQ3luaWNhbFwiLFxuICAgIFwiRGFuZ2Vyb3VzXCIsIFwiRGFya1wiLCBcIkRlbGljYXRlXCIsIFwiRGVzcGVyYXRlXCIsIFwiRGlmZmljdWx0XCIsIFwiRGlzY3JlZXRcIiwgXCJEaXNndWlzZWRcIiwgXCJEaXp6eVwiLFxuICAgIFwiRHVtYlwiLCBcIkVhZ2VyXCIsIFwiRWFzeVwiLCBcIkVkZ3lcIiwgXCJFbGVjdHJpY1wiLCBcIkVsZWdhbnRcIiwgXCJFbWFuY2lwYXRlZFwiLCBcIkVub3Jtb3VzXCIsIFwiRXVwaG9yaWNcIiwgXCJFdmlsXCIsXG4gICAgXCJGQUlMXCIsIFwiRmFzdFwiLCBcIkZlcm9jaW91c1wiLCBcIkZpZXJjZVwiLCBcIkZpbmVcIiwgXCJGbGF3ZWRcIiwgXCJGbHlpbmdcIiwgXCJGb29saXNoXCIsIFwiRm94eVwiLFxuICAgIFwiRnJlZXppbmdcIiwgXCJGdW5ueVwiLCBcIkZ1cmlvdXNcIiwgXCJHZW50bGVcIiwgXCJHbG9yaW91c1wiLCBcIkdvbGRlblwiLCBcIkdvb2RcIiwgXCJHcmVlblwiLCBcIkdyZWVuXCIsIFwiR3VpbHR5XCIsXG4gICAgXCJIYWlyeVwiLCBcIkhhcHB5XCIsIFwiSGFyZFwiLCBcIkhhc3R5XCIsIFwiSGF6eVwiLCBcIkhlcm9pY1wiLCBcIkhvc3RpbGVcIiwgXCJIb3RcIiwgXCJIdW1ibGVcIiwgXCJIdW1vbmdvdXNcIixcbiAgICBcIkh1bW9yb3VzXCIsIFwiSHlzdGVyaWNhbFwiLCBcIklkZWFsaXN0aWNcIiwgXCJJZ25vcmFudFwiLCBcIkltbWVuc2VcIiwgXCJJbXBhcnRpYWxcIiwgXCJJbXBvbGl0ZVwiLCBcIkluZGlmZmVyZW50XCIsXG4gICAgXCJJbmZ1cmlhdGVkXCIsIFwiSW5zaWdodGZ1bFwiLCBcIkludGVuc2VcIiwgXCJJbnRlcmVzdGluZ1wiLCBcIkludGltaWRhdGVkXCIsIFwiSW50cmlndWluZ1wiLCBcIkplYWxvdXNcIiwgXCJKb2xseVwiLCBcIkpvdmlhbFwiLFxuICAgIFwiSnVtcHlcIiwgXCJLaW5kXCIsIFwiTGF1Z2hpbmdcIiwgXCJMYXp5XCIsIFwiTGlxdWlkXCIsIFwiTG9uZWx5XCIsIFwiTG9uZ2luZ1wiLCBcIkxvdWRcIiwgXCJMb3ZpbmdcIiwgXCJMb3lhbFwiLCBcIk1hY2FicmVcIiwgXCJNYWRcIixcbiAgICBcIk1hZ2ljYWxcIiwgXCJNYWduaWZpY2VudFwiLCBcIk1hbGV2b2xlbnRcIiwgXCJNZWRpZXZhbFwiLCBcIk1lbW9yYWJsZVwiLCBcIk1lcmVcIiwgXCJNZXJyeVwiLCBcIk1pZ2h0eVwiLFxuICAgIFwiTWlzY2hpZXZvdXNcIiwgXCJNaXNlcmFibGVcIiwgXCJNb2RpZmllZFwiLCBcIk1vb2R5XCIsIFwiTW9zdFwiLCBcIk15c3RlcmlvdXNcIiwgXCJNeXN0aWNhbFwiLCBcIk5lZWR5XCIsXG4gICAgXCJOZXJ2b3VzXCIsIFwiTmljZVwiLCBcIk9iamVjdGl2ZVwiLCBcIk9ibm94aW91c1wiLCBcIk9ic2Vzc2l2ZVwiLCBcIk9idmlvdXNcIiwgXCJPcGluaW9uYXRlZFwiLCBcIk9yYW5nZVwiLFxuICAgIFwiUGFpbmZ1bFwiLCBcIlBhc3Npb25hdGVcIiwgXCJQZXJmZWN0XCIsIFwiUGlua1wiLCBcIlBsYXlmdWxcIiwgXCJQb2lzb25vdXNcIiwgXCJQb2xpdGVcIiwgXCJQb29yXCIsIFwiUG9wdWxhclwiLCBcIlBvd2VyZnVsXCIsXG4gICAgXCJQcmVjaXNlXCIsIFwiUHJlc2VydmVkXCIsIFwiUHJldHR5XCIsIFwiUHVycGxlXCIsIFwiUXVpY2tcIiwgXCJRdWlldFwiLCBcIlJhbmRvbVwiLCBcIlJhcGlkXCIsIFwiUmFyZVwiLCBcIlJlYWxcIixcbiAgICBcIlJlYXNzdXJpbmdcIiwgXCJSZWNrbGVzc1wiLCBcIlJlZFwiLCBcIlJlZ3VsYXJcIiwgXCJSZW1vcnNlZnVsXCIsIFwiUmVzcG9uc2libGVcIiwgXCJSaWNoXCIsIFwiUnVkZVwiLCBcIlJ1dGhsZXNzXCIsXG4gICAgXCJTYWRcIiwgXCJTY2FyZWRcIiwgXCJTY2FyeVwiLCBcIlNjb3JuZnVsXCIsIFwiU2NyZWFtaW5nXCIsIFwiU2VsZmlzaFwiLCBcIlNlcmlvdXNcIiwgXCJTaGFkeVwiLCBcIlNoYWt5XCIsIFwiU2hhcnBcIixcbiAgICBcIlNoaW55XCIsIFwiU2h5XCIsIFwiU2ltcGxlXCIsIFwiU2xlZXB5XCIsIFwiU2xvd1wiLCBcIlNseVwiLCBcIlNtYWxsXCIsIFwiU21hcnRcIiwgXCJTbWVsbHlcIiwgXCJTbWlsaW5nXCIsIFwiU21vb3RoXCIsXG4gICAgXCJTbXVnXCIsIFwiU29iZXJcIiwgXCJTb2Z0XCIsIFwiU29sZW1uXCIsIFwiU3F1YXJlXCIsIFwiU3F1YXJlXCIsIFwiU3RlYWR5XCIsIFwiU3RyYW5nZVwiLCBcIlN0cm9uZ1wiLFxuICAgIFwiU3R1bm5pbmdcIiwgXCJTdWJqZWN0aXZlXCIsIFwiU3VjY2Vzc2Z1bFwiLCBcIlN1cmx5XCIsIFwiU3dlZXRcIiwgXCJUYWN0ZnVsXCIsIFwiVGVuc2VcIixcbiAgICBcIlRob3VnaHRmdWxcIiwgXCJUaWdodFwiLCBcIlRpbnlcIiwgXCJUb2xlcmFudFwiLCBcIlVuZWFzeVwiLCBcIlVuaXF1ZVwiLCBcIlVuc2VlblwiLCBcIldhcm1cIiwgXCJXZWFrXCIsXG4gICAgXCJXZWlyZFwiLCBcIldlbGxDb29rZWRcIiwgXCJXaWxkXCIsIFwiV2lzZVwiLCBcIldpdHR5XCIsIFwiV29uZGVyZnVsXCIsIFwiV29ycmllZFwiLCBcIlllbGxvd1wiLCBcIllvdW5nXCIsXG4gICAgXCJaZWFsb3VzXCJcbiAgICBdO1xuLy92YXIgcHJvbm91bnMgPSBbXG4vL107XG4vL3ZhciBjb25qdW5jdGlvbnMgPSBbXG4vL1wiQW5kXCIsIFwiT3JcIiwgXCJGb3JcIiwgXCJBYm92ZVwiLCBcIkJlZm9yZVwiLCBcIkFnYWluc3RcIiwgXCJCZXR3ZWVuXCJcbi8vXTtcblxuLypcbiAqIE1hcHMgYSBzdHJpbmcgKGNhdGVnb3J5IG5hbWUpIHRvIHRoZSBhcnJheSBvZiB3b3JkcyBmcm9tIHRoYXQgY2F0ZWdvcnkuXG4gKi9cbnZhciBDQVRFR09SSUVTID1cbntcbiAgICAvL1wiX05PVU5fXCI6IG5vdW5zLFxuICAgIFwiX1BMVVJBTE5PVU5fXCI6IHBsdXJhbE5vdW5zLFxuICAgIC8vXCJfUExBQ0VfXCI6IHBsYWNlcyxcbiAgICBcIl9WRVJCX1wiOiB2ZXJicyxcbiAgICBcIl9BRFZFUkJfXCI6IGFkdmVyYnMsXG4gICAgXCJfQURKRUNUSVZFX1wiOiBhZGplY3RpdmVzXG4gICAgLy9cIl9QUk9OT1VOX1wiOiBwcm9ub3VucyxcbiAgICAvL1wiX0NPTkpVTkNUSU9OX1wiOiBjb25qdW5jdGlvbnMsXG59O1xuXG52YXIgUEFUVEVSTlMgPSBbXG4gICAgXCJfQURKRUNUSVZFX19QTFVSQUxOT1VOX19WRVJCX19BRFZFUkJfXCJcblxuICAgIC8vIEJlYXV0aWZ1bEZ1bmdpT3JTcGFnaGV0dGlcbiAgICAvL1wiX0FESkVDVElWRV9fUExVUkFMTk9VTl9fQ09OSlVOQ1RJT05fX1BMVVJBTE5PVU5fXCIsXG5cbiAgICAvLyBBbWF6aW5nbHlTY2FyeVRveVxuICAgIC8vXCJfQURWRVJCX19BREpFQ1RJVkVfX05PVU5fXCIsXG5cbiAgICAvLyBOZWl0aGVyVHJhc2hOb3JSaWZsZVxuICAgIC8vXCJOZWl0aGVyX05PVU5fTm9yX05PVU5fXCIsXG4gICAgLy9cIkVpdGhlcl9OT1VOX09yX05PVU5fXCIsXG5cbiAgICAvLyBFaXRoZXJDb3B1bGF0ZU9ySW52ZXN0aWdhdGVcbiAgICAvL1wiRWl0aGVyX1ZFUkJfT3JfVkVSQl9cIixcbiAgICAvL1wiTmVpdGhlcl9WRVJCX05vcl9WRVJCX1wiLFxuXG4gICAgLy9cIlRoZV9BREpFQ1RJVkVfX0FESkVDVElWRV9fTk9VTl9cIixcbiAgICAvL1wiVGhlX0FEVkVSQl9fQURKRUNUSVZFX19OT1VOX1wiLFxuICAgIC8vXCJUaGVfQURWRVJCX19BREpFQ1RJVkVfX05PVU5fc1wiLFxuICAgIC8vXCJUaGVfQURWRVJCX19BREpFQ1RJVkVfX1BMVVJBTE5PVU5fX1ZFUkJfXCIsXG5cbiAgICAvLyBXb2x2ZXNDb21wdXRlQmFkbHlcbiAgICAvL1wiX1BMVVJBTE5PVU5fX1ZFUkJfX0FEVkVSQl9cIixcblxuICAgIC8vIFVuaXRlRmFjaWxpdGF0ZUFuZE1lcmdlXG4gICAgLy9cIl9WRVJCX19WRVJCX0FuZF9WRVJCX1wiLFxuXG4gICAgLy9OYXN0eVdpdGNoZXNBdFRoZVB1YlxuICAgIC8vXCJfQURKRUNUSVZFX19QTFVSQUxOT1VOX0F0VGhlX1BMQUNFX1wiLFxuXTtcblxuXG4vKlxuICogUmV0dXJucyBhIHJhbmRvbSBlbGVtZW50IGZyb20gdGhlIGFycmF5ICdhcnInXG4gKi9cbmZ1bmN0aW9uIHJhbmRvbUVsZW1lbnQoYXJyKVxue1xuICAgIHJldHVybiBhcnJbTWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogYXJyLmxlbmd0aCldO1xufVxuXG4vKlxuICogUmV0dXJucyB0cnVlIGlmIHRoZSBzdHJpbmcgJ3MnIGNvbnRhaW5zIG9uZSBvZiB0aGVcbiAqIHRlbXBsYXRlIHN0cmluZ3MuXG4gKi9cbmZ1bmN0aW9uIGhhc1RlbXBsYXRlKHMpXG57XG4gICAgZm9yICh2YXIgdGVtcGxhdGUgaW4gQ0FURUdPUklFUyl7XG4gICAgICAgIGlmIChzLmluZGV4T2YodGVtcGxhdGUpID49IDApe1xuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH1cbiAgICB9XG59XG5cbi8qKlxuICogR2VuZXJhdGVzIG5ldyByb29tIG5hbWUuXG4gKi9cbnZhciBSb29tTmFtZUdlbmVyYXRvciA9IHtcbiAgICBnZW5lcmF0ZVJvb21XaXRob3V0U2VwYXJhdG9yOiBmdW5jdGlvbigpXG4gICAge1xuICAgICAgICAvLyBOb3RlIHRoYXQgaWYgbW9yZSB0aGFuIG9uZSBwYXR0ZXJuIGlzIGF2YWlsYWJsZSwgdGhlIGNob2ljZSBvZiAnbmFtZScgd29uJ3QgYmUgcmFuZG9tIChuYW1lcyBmcm9tIHBhdHRlcm5zXG4gICAgICAgIC8vIHdpdGggZmV3ZXIgb3B0aW9ucyB3aWxsIGhhdmUgaGlnaGVyIHByb2JhYmlsaXR5IG9mIGJlaW5nIGNob3NlbiB0aGF0IG5hbWVzIGZyb20gcGF0dGVybnMgd2l0aCBtb3JlIG9wdGlvbnMpLlxuICAgICAgICB2YXIgbmFtZSA9IHJhbmRvbUVsZW1lbnQoUEFUVEVSTlMpO1xuICAgICAgICB2YXIgd29yZDtcbiAgICAgICAgd2hpbGUgKGhhc1RlbXBsYXRlKG5hbWUpKXtcbiAgICAgICAgICAgIGZvciAodmFyIHRlbXBsYXRlIGluIENBVEVHT1JJRVMpe1xuICAgICAgICAgICAgICAgIHdvcmQgPSByYW5kb21FbGVtZW50KENBVEVHT1JJRVNbdGVtcGxhdGVdKTtcbiAgICAgICAgICAgICAgICBuYW1lID0gbmFtZS5yZXBsYWNlKHRlbXBsYXRlLCB3b3JkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIHJldHVybiBuYW1lO1xuICAgIH1cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSb29tTmFtZUdlbmVyYXRvcjtcbiIsInZhciBhbmltYXRlVGltZW91dCwgdXBkYXRlVGltZW91dDtcblxudmFyIFJvb21OYW1lR2VuZXJhdG9yID0gcmVxdWlyZShcIi4vUm9vbW5hbWVHZW5lcmF0b3JcIik7XG5cbmZ1bmN0aW9uIGVudGVyX3Jvb20oKVxue1xuICAgIHZhciB2YWwgPSAkKFwiI2VudGVyX3Jvb21fZmllbGRcIikudmFsKCk7XG4gICAgaWYoIXZhbCkge1xuICAgICAgICB2YWwgPSAkKFwiI2VudGVyX3Jvb21fZmllbGRcIikuYXR0cihcInJvb21fbmFtZVwiKTtcbiAgICB9XG4gICAgaWYgKHZhbCkge1xuICAgICAgICB3aW5kb3cubG9jYXRpb24ucGF0aG5hbWUgPSBcIi9cIiArIHZhbDtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIGFuaW1hdGUod29yZCkge1xuICAgIHZhciBjdXJyZW50VmFsID0gJChcIiNlbnRlcl9yb29tX2ZpZWxkXCIpLmF0dHIoXCJwbGFjZWhvbGRlclwiKTtcbiAgICAkKFwiI2VudGVyX3Jvb21fZmllbGRcIikuYXR0cihcInBsYWNlaG9sZGVyXCIsIGN1cnJlbnRWYWwgKyB3b3JkLnN1YnN0cigwLCAxKSk7XG4gICAgYW5pbWF0ZVRpbWVvdXQgPSBzZXRUaW1lb3V0KGZ1bmN0aW9uKCkge1xuICAgICAgICBhbmltYXRlKHdvcmQuc3Vic3RyaW5nKDEsIHdvcmQubGVuZ3RoKSlcbiAgICB9LCA3MCk7XG59XG5cbmZ1bmN0aW9uIHVwZGF0ZV9yb29tbmFtZSgpXG57XG4gICAgdmFyIHdvcmQgPSBSb29tTmFtZUdlbmVyYXRvci5nZW5lcmF0ZVJvb21XaXRob3V0U2VwYXJhdG9yKCk7XG4gICAgJChcIiNlbnRlcl9yb29tX2ZpZWxkXCIpLmF0dHIoXCJyb29tX25hbWVcIiwgd29yZCk7XG4gICAgJChcIiNlbnRlcl9yb29tX2ZpZWxkXCIpLmF0dHIoXCJwbGFjZWhvbGRlclwiLCBcIlwiKTtcbiAgICBjbGVhclRpbWVvdXQoYW5pbWF0ZVRpbWVvdXQpO1xuICAgIGFuaW1hdGUod29yZCk7XG4gICAgdXBkYXRlVGltZW91dCA9IHNldFRpbWVvdXQodXBkYXRlX3Jvb21uYW1lLCAxMDAwMCk7XG59XG5cblxuZnVuY3Rpb24gc2V0dXBXZWxjb21lUGFnZSgpXG57XG4gICAgJChcIiN2aWRlb2NvbmZlcmVuY2VfcGFnZVwiKS5oaWRlKCk7XG4gICAgJChcIiNkb21haW5fbmFtZVwiKS50ZXh0KFxuICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLnByb3RvY29sICsgXCIvL1wiICsgd2luZG93LmxvY2F0aW9uLmhvc3QgKyBcIi9cIik7XG4gICAgaWYgKGludGVyZmFjZUNvbmZpZy5TSE9XX0pJVFNJX1dBVEVSTUFSSykge1xuICAgICAgICB2YXIgbGVmdFdhdGVybWFya0RpdlxuICAgICAgICAgICAgPSAkKFwiI3dlbGNvbWVfcGFnZV9oZWFkZXIgZGl2W2NsYXNzPSd3YXRlcm1hcmsgbGVmdHdhdGVybWFyayddXCIpO1xuICAgICAgICBpZihsZWZ0V2F0ZXJtYXJrRGl2ICYmIGxlZnRXYXRlcm1hcmtEaXYubGVuZ3RoID4gMClcbiAgICAgICAge1xuICAgICAgICAgICAgbGVmdFdhdGVybWFya0Rpdi5jc3Moe2Rpc3BsYXk6ICdibG9jayd9KTtcbiAgICAgICAgICAgIGxlZnRXYXRlcm1hcmtEaXYucGFyZW50KCkuZ2V0KDApLmhyZWZcbiAgICAgICAgICAgICAgICA9IGludGVyZmFjZUNvbmZpZy5KSVRTSV9XQVRFUk1BUktfTElOSztcbiAgICAgICAgfVxuXG4gICAgfVxuXG4gICAgaWYgKGludGVyZmFjZUNvbmZpZy5TSE9XX0JSQU5EX1dBVEVSTUFSSykge1xuICAgICAgICB2YXIgcmlnaHRXYXRlcm1hcmtEaXZcbiAgICAgICAgICAgID0gJChcIiN3ZWxjb21lX3BhZ2VfaGVhZGVyIGRpdltjbGFzcz0nd2F0ZXJtYXJrIHJpZ2h0d2F0ZXJtYXJrJ11cIik7XG4gICAgICAgIGlmKHJpZ2h0V2F0ZXJtYXJrRGl2ICYmIHJpZ2h0V2F0ZXJtYXJrRGl2Lmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHJpZ2h0V2F0ZXJtYXJrRGl2LmNzcyh7ZGlzcGxheTogJ2Jsb2NrJ30pO1xuICAgICAgICAgICAgcmlnaHRXYXRlcm1hcmtEaXYucGFyZW50KCkuZ2V0KDApLmhyZWZcbiAgICAgICAgICAgICAgICA9IGludGVyZmFjZUNvbmZpZy5CUkFORF9XQVRFUk1BUktfTElOSztcbiAgICAgICAgICAgIHJpZ2h0V2F0ZXJtYXJrRGl2LmdldCgwKS5zdHlsZS5iYWNrZ3JvdW5kSW1hZ2VcbiAgICAgICAgICAgICAgICA9IFwidXJsKGltYWdlcy9yaWdodHdhdGVybWFyay5wbmcpXCI7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoaW50ZXJmYWNlQ29uZmlnLlNIT1dfUE9XRVJFRF9CWSkge1xuICAgICAgICAkKFwiI3dlbGNvbWVfcGFnZV9oZWFkZXI+YVtjbGFzcz0ncG93ZXJlZGJ5J11cIilcbiAgICAgICAgICAgIC5jc3Moe2Rpc3BsYXk6ICdibG9jayd9KTtcbiAgICB9XG5cbiAgICAkKFwiI2VudGVyX3Jvb21fYnV0dG9uXCIpLmNsaWNrKGZ1bmN0aW9uKClcbiAgICB7XG4gICAgICAgIGVudGVyX3Jvb20oKTtcbiAgICB9KTtcblxuICAgICQoXCIjZW50ZXJfcm9vbV9maWVsZFwiKS5rZXlkb3duKGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBpZiAoZXZlbnQua2V5Q29kZSA9PT0gMTMgLyogZW50ZXIgKi8pIHtcbiAgICAgICAgICAgIGVudGVyX3Jvb20oKTtcbiAgICAgICAgfVxuICAgIH0pO1xuXG4gICAgaWYgKCEoaW50ZXJmYWNlQ29uZmlnLkdFTkVSQVRFX1JPT01OQU1FU19PTl9XRUxDT01FX1BBR0UgPT09IGZhbHNlKSl7XG4gICAgICAgIHZhciB1cGRhdGVUaW1lb3V0O1xuICAgICAgICB2YXIgYW5pbWF0ZVRpbWVvdXQ7XG4gICAgICAgICQoXCIjcmVsb2FkX3Jvb21uYW1lXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dCh1cGRhdGVUaW1lb3V0KTtcbiAgICAgICAgICAgIGNsZWFyVGltZW91dChhbmltYXRlVGltZW91dCk7XG4gICAgICAgICAgICB1cGRhdGVfcm9vbW5hbWUoKTtcbiAgICAgICAgfSk7XG4gICAgICAgICQoXCIjcmVsb2FkX3Jvb21uYW1lXCIpLnNob3coKTtcblxuXG4gICAgICAgIHVwZGF0ZV9yb29tbmFtZSgpO1xuICAgIH1cblxuICAgICQoXCIjZGlzYWJsZV93ZWxjb21lXCIpLmNsaWNrKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgd2luZG93LmxvY2FsU3RvcmFnZS53ZWxjb21lUGFnZURpc2FibGVkXG4gICAgICAgICAgICA9ICQoXCIjZGlzYWJsZV93ZWxjb21lXCIpLmlzKFwiOmNoZWNrZWRcIik7XG4gICAgfSk7XG5cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBzZXR1cFdlbGNvbWVQYWdlOyIsInZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiZXZlbnRzXCIpO1xudmFyIGV2ZW50RW1pdHRlciA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbnZhciBDUUV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL2Nvbm5lY3Rpb25xdWFsaXR5L0NRRXZlbnRzXCIpO1xudmFyIFhNUFBFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS94bXBwL1hNUFBFdmVudHNcIik7XG5cbi8qKlxuICogbG9jYWwgc3RhdHNcbiAqIEB0eXBlIHt7fX1cbiAqL1xudmFyIHN0YXRzID0ge307XG5cbi8qKlxuICogcmVtb3RlIHN0YXRzXG4gKiBAdHlwZSB7e319XG4gKi9cbnZhciByZW1vdGVTdGF0cyA9IHt9O1xuXG4vKipcbiAqIEludGVydmFsIGZvciBzZW5kaW5nIHN0YXRpc3RpY3MgdG8gb3RoZXIgcGFydGljaXBhbnRzXG4gKiBAdHlwZSB7bnVsbH1cbiAqL1xudmFyIHNlbmRJbnRlcnZhbElkID0gbnVsbDtcblxuXG4vKipcbiAqIFN0YXJ0IHN0YXRpc3RpY3Mgc2VuZGluZy5cbiAqL1xuZnVuY3Rpb24gc3RhcnRTZW5kaW5nU3RhdHMoKSB7XG4gICAgc2VuZFN0YXRzKCk7XG4gICAgc2VuZEludGVydmFsSWQgPSBzZXRJbnRlcnZhbChzZW5kU3RhdHMsIDEwMDAwKTtcbn1cblxuLyoqXG4gKiBTZW5kcyBzdGF0aXN0aWNzIHRvIG90aGVyIHBhcnRpY2lwYW50c1xuICovXG5mdW5jdGlvbiBzZW5kU3RhdHMoKSB7XG4gICAgQVBQLnhtcHAuYWRkVG9QcmVzZW5jZShcImNvbm5lY3Rpb25RdWFsaXR5XCIsIGNvbnZlcnRUb01VQ1N0YXRzKHN0YXRzKSk7XG59XG5cbi8qKlxuICogQ29udmVydHMgc3RhdGlzdGljcyB0byBmb3JtYXQgZm9yIHNlbmRpbmcgdGhyb3VnaCBYTVBQXG4gKiBAcGFyYW0gc3RhdHMgdGhlIHN0YXRpc3RpY3NcbiAqIEByZXR1cm5zIHt7Yml0cmF0ZV9kb253bG9hZDogKiwgYml0cmF0ZV91cGxwb2FkOiAqLCBwYWNrZXRMb3NzX3RvdGFsOiAqLCBwYWNrZXRMb3NzX2Rvd25sb2FkOiAqLCBwYWNrZXRMb3NzX3VwbG9hZDogKn19XG4gKi9cbmZ1bmN0aW9uIGNvbnZlcnRUb01VQ1N0YXRzKHN0YXRzKSB7XG4gICAgcmV0dXJuIHtcbiAgICAgICAgXCJiaXRyYXRlX2Rvd25sb2FkXCI6IHN0YXRzLmJpdHJhdGUuZG93bmxvYWQsXG4gICAgICAgIFwiYml0cmF0ZV91cGxvYWRcIjogc3RhdHMuYml0cmF0ZS51cGxvYWQsXG4gICAgICAgIFwicGFja2V0TG9zc190b3RhbFwiOiBzdGF0cy5wYWNrZXRMb3NzLnRvdGFsLFxuICAgICAgICBcInBhY2tldExvc3NfZG93bmxvYWRcIjogc3RhdHMucGFja2V0TG9zcy5kb3dubG9hZCxcbiAgICAgICAgXCJwYWNrZXRMb3NzX3VwbG9hZFwiOiBzdGF0cy5wYWNrZXRMb3NzLnVwbG9hZFxuICAgIH07XG59XG5cbi8qKlxuICogQ29udmVydHMgc3RhdGl0aXN0aWNzIHRvIGZvcm1hdCB1c2VkIGJ5IFZpZGVvTGF5b3V0XG4gKiBAcGFyYW0gc3RhdHNcbiAqIEByZXR1cm5zIHt7Yml0cmF0ZToge2Rvd25sb2FkOiAqLCB1cGxvYWQ6ICp9LCBwYWNrZXRMb3NzOiB7dG90YWw6ICosIGRvd25sb2FkOiAqLCB1cGxvYWQ6ICp9fX1cbiAqL1xuZnVuY3Rpb24gcGFyc2VNVUNTdGF0cyhzdGF0cykge1xuICAgIHJldHVybiB7XG4gICAgICAgIGJpdHJhdGU6IHtcbiAgICAgICAgICAgIGRvd25sb2FkOiBzdGF0cy5iaXRyYXRlX2Rvd25sb2FkLFxuICAgICAgICAgICAgdXBsb2FkOiBzdGF0cy5iaXRyYXRlX3VwbG9hZFxuICAgICAgICB9LFxuICAgICAgICBwYWNrZXRMb3NzOiB7XG4gICAgICAgICAgICB0b3RhbDogc3RhdHMucGFja2V0TG9zc190b3RhbCxcbiAgICAgICAgICAgIGRvd25sb2FkOiBzdGF0cy5wYWNrZXRMb3NzX2Rvd25sb2FkLFxuICAgICAgICAgICAgdXBsb2FkOiBzdGF0cy5wYWNrZXRMb3NzX3VwbG9hZFxuICAgICAgICB9XG4gICAgfTtcbn1cblxuXG52YXIgQ29ubmVjdGlvblF1YWxpdHkgPSB7XG4gICAgaW5pdDogZnVuY3Rpb24gKCkge1xuICAgICAgICBBUFAueG1wcC5hZGRMaXN0ZW5lcihYTVBQRXZlbnRzLlJFTU9URV9TVEFUUywgdGhpcy51cGRhdGVSZW1vdGVTdGF0cyk7XG4gICAgICAgIEFQUC5zdGF0aXN0aWNzLmFkZENvbm5lY3Rpb25TdGF0c0xpc3RlbmVyKHRoaXMudXBkYXRlTG9jYWxTdGF0cyk7XG4gICAgICAgIEFQUC5zdGF0aXN0aWNzLmFkZFJlbW90ZVN0YXRzU3RvcExpc3RlbmVyKHRoaXMuc3RvcFNlbmRpbmdTdGF0cyk7XG5cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyB0aGUgbG9jYWwgc3RhdGlzdGljc1xuICAgICAqIEBwYXJhbSBkYXRhIG5ldyBzdGF0aXN0aWNzXG4gICAgICovXG4gICAgdXBkYXRlTG9jYWxTdGF0czogZnVuY3Rpb24gKGRhdGEpIHtcbiAgICAgICAgc3RhdHMgPSBkYXRhO1xuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChDUUV2ZW50cy5MT0NBTFNUQVRTX1VQREFURUQsIDEwMCAtIHN0YXRzLnBhY2tldExvc3MudG90YWwsIHN0YXRzKTtcbiAgICAgICAgaWYgKHNlbmRJbnRlcnZhbElkID09IG51bGwpIHtcbiAgICAgICAgICAgIHN0YXJ0U2VuZGluZ1N0YXRzKCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogVXBkYXRlcyByZW1vdGUgc3RhdGlzdGljc1xuICAgICAqIEBwYXJhbSBqaWQgdGhlIGppZCBhc3NvY2lhdGVkIHdpdGggdGhlIHN0YXRpc3RpY3NcbiAgICAgKiBAcGFyYW0gZGF0YSB0aGUgc3RhdGlzdGljc1xuICAgICAqL1xuICAgIHVwZGF0ZVJlbW90ZVN0YXRzOiBmdW5jdGlvbiAoamlkLCBkYXRhKSB7XG4gICAgICAgIGlmIChkYXRhID09IG51bGwgfHwgZGF0YS5wYWNrZXRMb3NzX3RvdGFsID09IG51bGwpIHtcbiAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KENRRXZlbnRzLlJFTU9URVNUQVRTX1VQREFURUQsIGppZCwgbnVsbCwgbnVsbCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgcmVtb3RlU3RhdHNbamlkXSA9IHBhcnNlTVVDU3RhdHMoZGF0YSk7XG5cbiAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoQ1FFdmVudHMuUkVNT1RFU1RBVFNfVVBEQVRFRCxcbiAgICAgICAgICAgIGppZCwgMTAwIC0gZGF0YS5wYWNrZXRMb3NzX3RvdGFsLCByZW1vdGVTdGF0c1tqaWRdKTtcbiAgICB9LFxuXG4gICAgLyoqXG4gICAgICogU3RvcHMgc3RhdGlzdGljcyBzZW5kaW5nLlxuICAgICAqL1xuICAgIHN0b3BTZW5kaW5nU3RhdHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgY2xlYXJJbnRlcnZhbChzZW5kSW50ZXJ2YWxJZCk7XG4gICAgICAgIHNlbmRJbnRlcnZhbElkID0gbnVsbDtcbiAgICAgICAgLy9ub3RpZnkgVUkgYWJvdXQgc3RvcHBpbmcgc3RhdGlzdGljcyBnYXRoZXJpbmdcbiAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoQ1FFdmVudHMuU1RPUCk7XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIFJldHVybnMgdGhlIGxvY2FsIHN0YXRpc3RpY3MuXG4gICAgICovXG4gICAgZ2V0U3RhdHM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIHN0YXRzO1xuICAgIH0sXG4gICAgXG4gICAgYWRkTGlzdGVuZXI6IGZ1bmN0aW9uICh0eXBlLCBsaXN0ZW5lcikge1xuICAgICAgICBldmVudEVtaXR0ZXIub24odHlwZSwgbGlzdGVuZXIpO1xuICAgIH1cblxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBDb25uZWN0aW9uUXVhbGl0eTsiLCIvKiBnbG9iYWwgJCwgYWxlcnQsIGNoYW5nZUxvY2FsVmlkZW8sIGNocm9tZSwgY29uZmlnLCBnZXRDb25mZXJlbmNlSGFuZGxlciwgZ2V0VXNlck1lZGlhV2l0aENvbnN0cmFpbnRzICovXG4vKipcbiAqIEluZGljYXRlcyB0aGF0IGRlc2t0b3Agc3RyZWFtIGlzIGN1cnJlbnRseSBpbiB1c2UoZm9yIHRvZ2dsZSBwdXJwb3NlKS5cbiAqIEB0eXBlIHtib29sZWFufVxuICovXG52YXIgaXNVc2luZ1NjcmVlblN0cmVhbSA9IGZhbHNlO1xuLyoqXG4gKiBJbmRpY2F0ZXMgdGhhdCBzd2l0Y2ggc3RyZWFtIG9wZXJhdGlvbiBpcyBpbiBwcm9ncmVzcyBhbmQgcHJldmVudCBmcm9tIHRyaWdnZXJpbmcgbmV3IGV2ZW50cy5cbiAqIEB0eXBlIHtib29sZWFufVxuICovXG52YXIgc3dpdGNoSW5Qcm9ncmVzcyA9IGZhbHNlO1xuXG4vKipcbiAqIE1ldGhvZCB1c2VkIHRvIGdldCBzY3JlZW4gc2hhcmluZyBzdHJlYW0uXG4gKlxuICogQHR5cGUge2Z1bmN0aW9uIChzdHJlYW1fY2FsbGJhY2ssIGZhaWx1cmVfY2FsbGJhY2t9XG4gKi9cbnZhciBvYnRhaW5EZXNrdG9wU3RyZWFtID0gbnVsbDtcblxuLyoqXG4gKiBGbGFnIHVzZWQgdG8gY2FjaGUgZGVza3RvcCBzaGFyaW5nIGVuYWJsZWQgc3RhdGUuIERvIG5vdCB1c2UgZGlyZWN0bHkgYXMgaXQgY2FuIGJlIDx0dD5udWxsPC90dD4uXG4gKiBAdHlwZSB7bnVsbHxib29sZWFufVxuICovXG52YXIgX2Rlc2t0b3BTaGFyaW5nRW5hYmxlZCA9IG51bGw7XG5cbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiZXZlbnRzXCIpO1xuXG52YXIgZXZlbnRFbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG52YXIgRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvZGVza3RvcHNoYXJpbmcvRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzXCIpO1xuXG4vKipcbiAqIE1ldGhvZCBvYnRhaW5zIGRlc2t0b3Agc3RyZWFtIGZyb20gV2ViUlRDICdzY3JlZW4nIHNvdXJjZS5cbiAqIEZsYWcgJ2Nocm9tZTovL2ZsYWdzLyNlbmFibGUtdXNlcm1lZGlhLXNjcmVlbi1jYXB0dXJlJyBtdXN0IGJlIGVuYWJsZWQuXG4gKi9cbmZ1bmN0aW9uIG9idGFpbldlYlJUQ1NjcmVlbihzdHJlYW1DYWxsYmFjaywgZmFpbENhbGxiYWNrKSB7XG4gICAgQVBQLlJUQy5nZXRVc2VyTWVkaWFXaXRoQ29uc3RyYWludHMoXG4gICAgICAgIFsnc2NyZWVuJ10sXG4gICAgICAgIHN0cmVhbUNhbGxiYWNrLFxuICAgICAgICBmYWlsQ2FsbGJhY2tcbiAgICApO1xufVxuXG4vKipcbiAqIENvbnN0cnVjdHMgaW5saW5lIGluc3RhbGwgVVJMIGZvciBDaHJvbWUgZGVza3RvcCBzdHJlYW1pbmcgZXh0ZW5zaW9uLlxuICogVGhlICdjaHJvbWVFeHRlbnNpb25JZCcgbXVzdCBiZSBkZWZpbmVkIGluIGNvbmZpZy5qcy5cbiAqIEByZXR1cm5zIHtzdHJpbmd9XG4gKi9cbmZ1bmN0aW9uIGdldFdlYlN0b3JlSW5zdGFsbFVybCgpXG57XG4gICAgcmV0dXJuIFwiaHR0cHM6Ly9jaHJvbWUuZ29vZ2xlLmNvbS93ZWJzdG9yZS9kZXRhaWwvXCIgKyBjb25maWcuY2hyb21lRXh0ZW5zaW9uSWQ7XG59XG5cbi8qKlxuICogQ2hlY2tzIHdoZXRoZXIgZXh0ZW5zaW9uIHVwZGF0ZSBpcyByZXF1aXJlZC5cbiAqIEBwYXJhbSBtaW5WZXJzaW9uIG1pbmltYWwgcmVxdWlyZWQgdmVyc2lvblxuICogQHBhcmFtIGV4dFZlcnNpb24gY3VycmVudCBleHRlbnNpb24gdmVyc2lvblxuICogQHJldHVybnMge2Jvb2xlYW59XG4gKi9cbmZ1bmN0aW9uIGlzVXBkYXRlUmVxdWlyZWQobWluVmVyc2lvbiwgZXh0VmVyc2lvbilcbntcbiAgICB0cnlcbiAgICB7XG4gICAgICAgIHZhciBzMSA9IG1pblZlcnNpb24uc3BsaXQoJy4nKTtcbiAgICAgICAgdmFyIHMyID0gZXh0VmVyc2lvbi5zcGxpdCgnLicpO1xuXG4gICAgICAgIHZhciBsZW4gPSBNYXRoLm1heChzMS5sZW5ndGgsIHMyLmxlbmd0aCk7XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGVuOyBpKyspXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhciBuMSA9IDAsXG4gICAgICAgICAgICAgICAgbjIgPSAwO1xuXG4gICAgICAgICAgICBpZiAoaSA8IHMxLmxlbmd0aClcbiAgICAgICAgICAgICAgICBuMSA9IHBhcnNlSW50KHMxW2ldKTtcbiAgICAgICAgICAgIGlmIChpIDwgczIubGVuZ3RoKVxuICAgICAgICAgICAgICAgIG4yID0gcGFyc2VJbnQoczJbaV0pO1xuXG4gICAgICAgICAgICBpZiAoaXNOYU4objEpIHx8IGlzTmFOKG4yKSlcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKG4xICE9PSBuMilcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbjEgPiBuMjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuXG4gICAgICAgIC8vIHdpbGwgaGFwcGVuIGlmIGJvdGhzIHZlcnNpb24gaGFzIGlkZW50aWNhbCBudW1iZXJzIGluXG4gICAgICAgIC8vIHRoZWlyIGNvbXBvbmVudHMgKGV2ZW4gaWYgb25lIG9mIHRoZW0gaXMgbG9uZ2VyLCBoYXMgbW9yZSBjb21wb25lbnRzKVxuICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuICAgIGNhdGNoIChlKVxuICAgIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihcIkZhaWxlZCB0byBwYXJzZSBleHRlbnNpb24gdmVyc2lvblwiLCBlKTtcbiAgICAgICAgQVBQLlVJLm1lc3NhZ2VIYW5kbGVyLnNob3dFcnJvcignRXJyb3InLFxuICAgICAgICAgICAgJ0Vycm9yIHdoZW4gdHJ5aW5nIHRvIGRldGVjdCBkZXNrdG9wc2hhcmluZyBleHRlbnNpb24uJyk7XG4gICAgICAgIHJldHVybiB0cnVlO1xuICAgIH1cbn1cblxuXG5mdW5jdGlvbiBjaGVja0V4dEluc3RhbGxlZChpc0luc3RhbGxlZENhbGxiYWNrKSB7XG4gICAgaWYgKCFjaHJvbWUucnVudGltZSkge1xuICAgICAgICAvLyBObyBBUEksIHNvIG5vIGV4dGVuc2lvbiBmb3Igc3VyZVxuICAgICAgICBpc0luc3RhbGxlZENhbGxiYWNrKGZhbHNlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICBjaHJvbWUucnVudGltZS5zZW5kTWVzc2FnZShcbiAgICAgICAgY29uZmlnLmNocm9tZUV4dGVuc2lvbklkLFxuICAgICAgICB7IGdldFZlcnNpb246IHRydWUgfSxcbiAgICAgICAgZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoIXJlc3BvbnNlIHx8ICFyZXNwb25zZS52ZXJzaW9uKSB7XG4gICAgICAgICAgICAgICAgLy8gQ29tbXVuaWNhdGlvbiBmYWlsdXJlIC0gYXNzdW1lIHRoYXQgbm8gZW5kcG9pbnQgZXhpc3RzXG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiRXh0ZW5zaW9uIG5vdCBpbnN0YWxsZWQ/OiBcIiArIGNocm9tZS5ydW50aW1lLmxhc3RFcnJvcik7XG4gICAgICAgICAgICAgICAgaXNJbnN0YWxsZWRDYWxsYmFjayhmYWxzZSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIENoZWNrIGluc3RhbGxlZCBleHRlbnNpb24gdmVyc2lvblxuICAgICAgICAgICAgICAgIHZhciBleHRWZXJzaW9uID0gcmVzcG9uc2UudmVyc2lvbjtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnRXh0ZW5zaW9uIHZlcnNpb24gaXM6ICcgKyBleHRWZXJzaW9uKTtcbiAgICAgICAgICAgICAgICB2YXIgdXBkYXRlUmVxdWlyZWQgPSBpc1VwZGF0ZVJlcXVpcmVkKGNvbmZpZy5taW5DaHJvbWVFeHRWZXJzaW9uLCBleHRWZXJzaW9uKTtcbiAgICAgICAgICAgICAgICBpZiAodXBkYXRlUmVxdWlyZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgYWxlcnQoXG4gICAgICAgICAgICAgICAgICAgICAgICAnSml0c2kgRGVza3RvcCBTdHJlYW1lciByZXF1aXJlcyB1cGRhdGUuICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJ0NoYW5nZXMgd2lsbCB0YWtlIGVmZmVjdCBhZnRlciBuZXh0IENocm9tZSByZXN0YXJ0LicpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBpc0luc3RhbGxlZENhbGxiYWNrKCF1cGRhdGVSZXF1aXJlZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICApO1xufVxuXG5mdW5jdGlvbiBkb0dldFN0cmVhbUZyb21FeHRlbnNpb24oc3RyZWFtQ2FsbGJhY2ssIGZhaWxDYWxsYmFjaykge1xuICAgIC8vIFNlbmRzICdnZXRTdHJlYW0nIG1zZyB0byB0aGUgZXh0ZW5zaW9uLiBFeHRlbnNpb24gaWQgbXVzdCBiZSBkZWZpbmVkIGluIHRoZSBjb25maWcuXG4gICAgY2hyb21lLnJ1bnRpbWUuc2VuZE1lc3NhZ2UoXG4gICAgICAgIGNvbmZpZy5jaHJvbWVFeHRlbnNpb25JZCxcbiAgICAgICAgeyBnZXRTdHJlYW06IHRydWUsIHNvdXJjZXM6IGNvbmZpZy5kZXNrdG9wU2hhcmluZ1NvdXJjZXMgfSxcbiAgICAgICAgZnVuY3Rpb24gKHJlc3BvbnNlKSB7XG4gICAgICAgICAgICBpZiAoIXJlc3BvbnNlKSB7XG4gICAgICAgICAgICAgICAgZmFpbENhbGxiYWNrKGNocm9tZS5ydW50aW1lLmxhc3RFcnJvcik7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgY29uc29sZS5sb2coXCJSZXNwb25zZSBmcm9tIGV4dGVuc2lvbjogXCIgKyByZXNwb25zZSk7XG4gICAgICAgICAgICBpZiAocmVzcG9uc2Uuc3RyZWFtSWQpIHtcbiAgICAgICAgICAgICAgICBBUFAuUlRDLmdldFVzZXJNZWRpYVdpdGhDb25zdHJhaW50cyhcbiAgICAgICAgICAgICAgICAgICAgWydkZXNrdG9wJ10sXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN0cmVhbUNhbGxiYWNrKHN0cmVhbSk7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGZhaWxDYWxsYmFjayxcbiAgICAgICAgICAgICAgICAgICAgbnVsbCwgbnVsbCwgbnVsbCxcbiAgICAgICAgICAgICAgICAgICAgcmVzcG9uc2Uuc3RyZWFtSWQpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBmYWlsQ2FsbGJhY2soXCJFeHRlbnNpb24gZmFpbGVkIHRvIGdldCB0aGUgc3RyZWFtXCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgKTtcbn1cbi8qKlxuICogQXNrcyBDaHJvbWUgZXh0ZW5zaW9uIHRvIGNhbGwgY2hvb3NlRGVza3RvcE1lZGlhIGFuZCBnZXRzIGNocm9tZSAnZGVza3RvcCcgc3RyZWFtIGZvciByZXR1cm5lZCBzdHJlYW0gdG9rZW4uXG4gKi9cbmZ1bmN0aW9uIG9idGFpblNjcmVlbkZyb21FeHRlbnNpb24oc3RyZWFtQ2FsbGJhY2ssIGZhaWxDYWxsYmFjaykge1xuICAgIGNoZWNrRXh0SW5zdGFsbGVkKFxuICAgICAgICBmdW5jdGlvbiAoaXNJbnN0YWxsZWQpIHtcbiAgICAgICAgICAgIGlmIChpc0luc3RhbGxlZCkge1xuICAgICAgICAgICAgICAgIGRvR2V0U3RyZWFtRnJvbUV4dGVuc2lvbihzdHJlYW1DYWxsYmFjaywgZmFpbENhbGxiYWNrKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY2hyb21lLndlYnN0b3JlLmluc3RhbGwoXG4gICAgICAgICAgICAgICAgICAgIGdldFdlYlN0b3JlSW5zdGFsbFVybCgpLFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoYXJnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIkV4dGVuc2lvbiBpbnN0YWxsZWQgc3VjY2Vzc2Z1bGx5XCIsIGFyZyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBXZSBuZWVkIHRvIHJlbG9hZCB0aGUgcGFnZSBpbiBvcmRlciB0byBnZXQgdGhlIGFjY2VzcyB0byBjaHJvbWUucnVudGltZVxuICAgICAgICAgICAgICAgICAgICAgICAgd2luZG93LmxvY2F0aW9uLnJlbG9hZChmYWxzZSk7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChhcmcpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiRmFpbGVkIHRvIGluc3RhbGwgdGhlIGV4dGVuc2lvblwiLCBhcmcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZmFpbENhbGxiYWNrKGFyZyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKCdFcnJvcicsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJ0ZhaWxlZCB0byBpbnN0YWxsIGRlc2t0b3Agc2hhcmluZyBleHRlbnNpb24nKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICApO1xufVxuXG4vKipcbiAqIENhbGwgdGhpcyBtZXRob2QgdG8gdG9nZ2xlIGRlc2t0b3Agc2hhcmluZyBmZWF0dXJlLlxuICogQHBhcmFtIG1ldGhvZCBwYXNzIFwiZXh0XCIgdG8gdXNlIGNocm9tZSBleHRlbnNpb24gZm9yIGRlc2t0b3AgY2FwdHVyZShjaHJvbWUgZXh0ZW5zaW9uIHJlcXVpcmVkKSxcbiAqICAgICAgICBwYXNzIFwid2VicnRjXCIgdG8gdXNlIFdlYlJUQyBcInNjcmVlblwiIGRlc2t0b3Agc291cmNlKCdjaHJvbWU6Ly9mbGFncy8jZW5hYmxlLXVzZXJtZWRpYS1zY3JlZW4tY2FwdHVyZSdcbiAqICAgICAgICBtdXN0IGJlIGVuYWJsZWQpLCBwYXNzIGFueSBvdGhlciBzdHJpbmcgb3Igbm90aGluZyBpbiBvcmRlciB0byBkaXNhYmxlIHRoaXMgZmVhdHVyZSBjb21wbGV0ZWx5LlxuICovXG5mdW5jdGlvbiBzZXREZXNrdG9wU2hhcmluZyhtZXRob2QpIHtcbiAgICAvLyBDaGVjayBpZiB3ZSBhcmUgcnVubmluZyBjaHJvbWVcbiAgICBpZiAoIW5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEpIHtcbiAgICAgICAgb2J0YWluRGVza3RvcFN0cmVhbSA9IG51bGw7XG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIkRlc2t0b3Agc2hhcmluZyBkaXNhYmxlZFwiKTtcbiAgICB9IGVsc2UgaWYgKG1ldGhvZCA9PSBcImV4dFwiKSB7XG4gICAgICAgIG9idGFpbkRlc2t0b3BTdHJlYW0gPSBvYnRhaW5TY3JlZW5Gcm9tRXh0ZW5zaW9uO1xuICAgICAgICBjb25zb2xlLmluZm8oXCJVc2luZyBDaHJvbWUgZXh0ZW5zaW9uIGZvciBkZXNrdG9wIHNoYXJpbmdcIik7XG4gICAgfSBlbHNlIGlmIChtZXRob2QgPT0gXCJ3ZWJydGNcIikge1xuICAgICAgICBvYnRhaW5EZXNrdG9wU3RyZWFtID0gb2J0YWluV2ViUlRDU2NyZWVuO1xuICAgICAgICBjb25zb2xlLmluZm8oXCJVc2luZyBDaHJvbWUgV2ViUlRDIGZvciBkZXNrdG9wIHNoYXJpbmdcIik7XG4gICAgfVxuXG4gICAgLy8gUmVzZXQgZW5hYmxlZCBjYWNoZVxuICAgIF9kZXNrdG9wU2hhcmluZ0VuYWJsZWQgPSBudWxsO1xufVxuXG4vKipcbiAqIEluaXRpYWxpemVzIDxsaW5rIHJlbD1jaHJvbWUtd2Vic3RvcmUtaXRlbSAvPiB3aXRoIGV4dGVuc2lvbiBpZCBzZXQgaW4gY29uZmlnLmpzIHRvIHN1cHBvcnQgaW5saW5lIGluc3RhbGxzLlxuICogSG9zdCBzaXRlIG11c3QgYmUgc2VsZWN0ZWQgYXMgbWFpbiB3ZWJzaXRlIG9mIHB1Ymxpc2hlZCBleHRlbnNpb24uXG4gKi9cbmZ1bmN0aW9uIGluaXRJbmxpbmVJbnN0YWxscygpXG57XG4gICAgJChcImxpbmtbcmVsPWNocm9tZS13ZWJzdG9yZS1pdGVtXVwiKS5hdHRyKFwiaHJlZlwiLCBnZXRXZWJTdG9yZUluc3RhbGxVcmwoKSk7XG59XG5cbmZ1bmN0aW9uIGdldFN3aXRjaFN0cmVhbUZhaWxlZChlcnJvcikge1xuICAgIGNvbnNvbGUuZXJyb3IoXCJGYWlsZWQgdG8gb2J0YWluIHRoZSBzdHJlYW0gdG8gc3dpdGNoIHRvXCIsIGVycm9yKTtcbiAgICBzd2l0Y2hJblByb2dyZXNzID0gZmFsc2U7XG59XG5cbmZ1bmN0aW9uIHN0cmVhbVN3aXRjaERvbmUoKSB7XG4gICAgc3dpdGNoSW5Qcm9ncmVzcyA9IGZhbHNlO1xuICAgIGV2ZW50RW1pdHRlci5lbWl0KFxuICAgICAgICBEZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXMuU1dJVENISU5HX0RPTkUsXG4gICAgICAgIGlzVXNpbmdTY3JlZW5TdHJlYW0pO1xufVxuXG5mdW5jdGlvbiBuZXdTdHJlYW1DcmVhdGVkKHN0cmVhbSlcbntcbiAgICBldmVudEVtaXR0ZXIuZW1pdChEZXNrdG9wU2hhcmluZ0V2ZW50VHlwZXMuTkVXX1NUUkVBTV9DUkVBVEVELFxuICAgICAgICBzdHJlYW0sIGlzVXNpbmdTY3JlZW5TdHJlYW0sIHN0cmVhbVN3aXRjaERvbmUpO1xufVxuXG5cbm1vZHVsZS5leHBvcnRzID0ge1xuICAgIGlzVXNpbmdTY3JlZW5TdHJlYW06IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGlzVXNpbmdTY3JlZW5TdHJlYW07XG4gICAgfSxcblxuICAgIC8qKlxuICAgICAqIEByZXR1cm5zIHtib29sZWFufSA8dHQ+dHJ1ZTwvdHQ+IGlmIGRlc2t0b3Agc2hhcmluZyBmZWF0dXJlIGlzIGF2YWlsYWJsZSBhbmQgZW5hYmxlZC5cbiAgICAgKi9cbiAgICBpc0Rlc2t0b3BTaGFyaW5nRW5hYmxlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoX2Rlc2t0b3BTaGFyaW5nRW5hYmxlZCA9PT0gbnVsbCkge1xuICAgICAgICAgICAgaWYgKG9idGFpbkRlc2t0b3BTdHJlYW0gPT09IG9idGFpblNjcmVlbkZyb21FeHRlbnNpb24pIHtcbiAgICAgICAgICAgICAgICAvLyBQYXJzZSBjaHJvbWUgdmVyc2lvblxuICAgICAgICAgICAgICAgIHZhciB1c2VyQWdlbnQgPSBuYXZpZ2F0b3IudXNlckFnZW50LnRvTG93ZXJDYXNlKCk7XG4gICAgICAgICAgICAgICAgLy8gV2UgY2FuIGFzc3VtZSB0aGF0IHVzZXIgYWdlbnQgaXMgY2hyb21lLCBiZWNhdXNlIGl0J3MgZW5mb3JjZWQgd2hlbiAnZXh0JyBzdHJlYW1pbmcgbWV0aG9kIGlzIHNldFxuICAgICAgICAgICAgICAgIHZhciB2ZXIgPSBwYXJzZUludCh1c2VyQWdlbnQubWF0Y2goL2Nocm9tZVxcLyhcXGQrKVxcLi8pWzFdLCAxMCk7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coXCJDaHJvbWUgdmVyc2lvblwiICsgdXNlckFnZW50LCB2ZXIpO1xuICAgICAgICAgICAgICAgIF9kZXNrdG9wU2hhcmluZ0VuYWJsZWQgPSB2ZXIgPj0gMzQ7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIF9kZXNrdG9wU2hhcmluZ0VuYWJsZWQgPSBvYnRhaW5EZXNrdG9wU3RyZWFtID09PSBvYnRhaW5XZWJSVENTY3JlZW47XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIF9kZXNrdG9wU2hhcmluZ0VuYWJsZWQ7XG4gICAgfSxcbiAgICBcbiAgICBpbml0OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHNldERlc2t0b3BTaGFyaW5nKGNvbmZpZy5kZXNrdG9wU2hhcmluZyk7XG5cbiAgICAgICAgLy8gSW5pdGlhbGl6ZSBDaHJvbWUgZXh0ZW5zaW9uIGlubGluZSBpbnN0YWxsc1xuICAgICAgICBpZiAoY29uZmlnLmNocm9tZUV4dGVuc2lvbklkKSB7XG4gICAgICAgICAgICBpbml0SW5saW5lSW5zdGFsbHMoKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KERlc2t0b3BTaGFyaW5nRXZlbnRUeXBlcy5JTklUKTtcbiAgICB9LFxuXG4gICAgYWRkTGlzdGVuZXI6IGZ1bmN0aW9uKGxpc3RlbmVyLCB0eXBlKVxuICAgIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLm9uKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlTGlzdGVuZXI6IGZ1bmN0aW9uIChsaXN0ZW5lcix0eXBlKSB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcik7XG4gICAgfSxcblxuICAgIC8qXG4gICAgICogVG9nZ2xlcyBzY3JlZW4gc2hhcmluZy5cbiAgICAgKi9cbiAgICB0b2dnbGVTY3JlZW5TaGFyaW5nOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmIChzd2l0Y2hJblByb2dyZXNzIHx8ICFvYnRhaW5EZXNrdG9wU3RyZWFtKSB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oXCJTd2l0Y2ggaW4gcHJvZ3Jlc3Mgb3Igbm8gbWV0aG9kIGRlZmluZWRcIik7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgc3dpdGNoSW5Qcm9ncmVzcyA9IHRydWU7XG5cbiAgICAgICAgaWYgKCFpc1VzaW5nU2NyZWVuU3RyZWFtKVxuICAgICAgICB7XG4gICAgICAgICAgICAvLyBTd2l0Y2ggdG8gZGVza3RvcCBzdHJlYW1cbiAgICAgICAgICAgIG9idGFpbkRlc2t0b3BTdHJlYW0oXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHN0cmVhbSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBXZSBub3cgdXNlIHNjcmVlbiBzdHJlYW1cbiAgICAgICAgICAgICAgICAgICAgaXNVc2luZ1NjcmVlblN0cmVhbSA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgIC8vIEhvb2sgJ2VuZGVkJyBldmVudCB0byByZXN0b3JlIGNhbWVyYSB3aGVuIHNjcmVlbiBzdHJlYW0gc3RvcHNcbiAgICAgICAgICAgICAgICAgICAgc3RyZWFtLmFkZEV2ZW50TGlzdGVuZXIoJ2VuZGVkJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFzd2l0Y2hJblByb2dyZXNzICYmIGlzVXNpbmdTY3JlZW5TdHJlYW0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdG9nZ2xlU2NyZWVuU2hhcmluZygpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgbmV3U3RyZWFtQ3JlYXRlZChzdHJlYW0pO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZ2V0U3dpdGNoU3RyZWFtRmFpbGVkKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIERpc2FibGUgc2NyZWVuIHN0cmVhbVxuICAgICAgICAgICAgQVBQLlJUQy5nZXRVc2VyTWVkaWFXaXRoQ29uc3RyYWludHMoXG4gICAgICAgICAgICAgICAgWyd2aWRlbyddLFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gV2UgYXJlIG5vdyB1c2luZyBjYW1lcmEgc3RyZWFtXG4gICAgICAgICAgICAgICAgICAgIGlzVXNpbmdTY3JlZW5TdHJlYW0gPSBmYWxzZTtcbiAgICAgICAgICAgICAgICAgICAgbmV3U3RyZWFtQ3JlYXRlZChzdHJlYW0pO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZ2V0U3dpdGNoU3RyZWFtRmFpbGVkLCBjb25maWcucmVzb2x1dGlvbiB8fCAnMzYwJ1xuICAgICAgICAgICAgKTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbiIsIi8vbWFwcyBrZXljb2RlIHRvIGNoYXJhY3RlciwgaWQgb2YgcG9wb3ZlciBmb3IgZ2l2ZW4gZnVuY3Rpb24gYW5kIGZ1bmN0aW9uXG52YXIgc2hvcnRjdXRzID0ge1xuICAgIDY3OiB7XG4gICAgICAgIGNoYXJhY3RlcjogXCJDXCIsXG4gICAgICAgIGlkOiBcInRvZ2dsZUNoYXRQb3BvdmVyXCIsXG4gICAgICAgIGZ1bmN0aW9uOiBBUFAuVUkudG9nZ2xlQ2hhdFxuICAgIH0sXG4gICAgNzA6IHtcbiAgICAgICAgY2hhcmFjdGVyOiBcIkZcIixcbiAgICAgICAgaWQ6IFwiZmlsbXN0cmlwUG9wb3ZlclwiLFxuICAgICAgICBmdW5jdGlvbjogQVBQLlVJLnRvZ2dsZUZpbG1TdHJpcFxuICAgIH0sXG4gICAgNzc6IHtcbiAgICAgICAgY2hhcmFjdGVyOiBcIk1cIixcbiAgICAgICAgaWQ6IFwibXV0ZVBvcG92ZXJcIixcbiAgICAgICAgZnVuY3Rpb246IEFQUC5VSS50b2dnbGVBdWRpb1xuICAgIH0sXG4gICAgODQ6IHtcbiAgICAgICAgY2hhcmFjdGVyOiBcIlRcIixcbiAgICAgICAgZnVuY3Rpb246IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgaWYoIUFQUC5SVEMubG9jYWxBdWRpby5pc011dGVkKCkpIHtcbiAgICAgICAgICAgICAgICBBUFAuVUkudG9nZ2xlQXVkaW8oKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIH0sXG4gICAgODY6IHtcbiAgICAgICAgY2hhcmFjdGVyOiBcIlZcIixcbiAgICAgICAgaWQ6IFwidG9nZ2xlVmlkZW9Qb3BvdmVyXCIsXG4gICAgICAgIGZ1bmN0aW9uOiBBUFAuVUkudG9nZ2xlVmlkZW9cbiAgICB9XG59O1xuXG5cbnZhciBLZXlib2FyZFNob3J0Y3V0ID0ge1xuICAgIGluaXQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgd2luZG93Lm9ua2V5dXAgPSBmdW5jdGlvbihlKSB7XG4gICAgICAgICAgICB2YXIga2V5Y29kZSA9IGUud2hpY2g7XG4gICAgICAgICAgICBpZighKCQoXCI6Zm9jdXNcIikuaXMoXCJpbnB1dFt0eXBlPXRleHRdXCIpIHx8XG4gICAgICAgICAgICAgICAgJChcIjpmb2N1c1wiKS5pcyhcImlucHV0W3R5cGU9cGFzc3dvcmRdXCIpIHx8XG4gICAgICAgICAgICAgICAgJChcIjpmb2N1c1wiKS5pcyhcInRleHRhcmVhXCIpKSkge1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2Ygc2hvcnRjdXRzW2tleWNvZGVdID09PSBcIm9iamVjdFwiKSB7XG4gICAgICAgICAgICAgICAgICAgIHNob3J0Y3V0c1trZXljb2RlXS5mdW5jdGlvbigpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmIChrZXljb2RlID49IFwiMFwiLmNoYXJDb2RlQXQoMCkgJiZcbiAgICAgICAgICAgICAgICAgICAga2V5Y29kZSA8PSBcIjlcIi5jaGFyQ29kZUF0KDApKSB7XG4gICAgICAgICAgICAgICAgICAgIEFQUC5VSS5jbGlja09uVmlkZW8oa2V5Y29kZSAtIFwiMFwiLmNoYXJDb2RlQXQoMCkgKyAxKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy9lc2Mgd2hpbGUgdGhlIHNtaWxleXMgYXJlIHZpc2libGUgaGlkZXMgdGhlbVxuICAgICAgICAgICAgfSBlbHNlIGlmIChrZXljb2RlID09PSAyNyAmJiAkKCcjc21pbGV5c0NvbnRhaW5lcicpLmlzKCc6dmlzaWJsZScpKSB7XG4gICAgICAgICAgICAgICAgQVBQLlVJLnRvZ2dsZVNtaWxleXMoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcblxuICAgICAgICB3aW5kb3cub25rZXlkb3duID0gZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgaWYoISgkKFwiOmZvY3VzXCIpLmlzKFwiaW5wdXRbdHlwZT10ZXh0XVwiKSB8fFxuICAgICAgICAgICAgICAgICQoXCI6Zm9jdXNcIikuaXMoXCJpbnB1dFt0eXBlPXBhc3N3b3JkXVwiKSB8fFxuICAgICAgICAgICAgICAgICQoXCI6Zm9jdXNcIikuaXMoXCJ0ZXh0YXJlYVwiKSkpIHtcbiAgICAgICAgICAgICAgICBpZihlLndoaWNoID09PSBcIlRcIi5jaGFyQ29kZUF0KDApKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmKEFQUC5SVEMubG9jYWxBdWRpby5pc011dGVkKCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIEFQUC5VSS50b2dnbGVBdWRpbygpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9O1xuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgICQoJ2JvZHknKS5wb3BvdmVyKHsgc2VsZWN0b3I6ICdbZGF0YS10b2dnbGU9cG9wb3Zlcl0nLFxuICAgICAgICAgICAgdHJpZ2dlcjogJ2NsaWNrIGhvdmVyJyxcbiAgICAgICAgICAgIGNvbnRlbnQ6IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLmdldEF0dHJpYnV0ZShcImNvbnRlbnRcIikgK1xuICAgICAgICAgICAgICAgICAgICBzZWxmLmdldFNob3J0Y3V0KHRoaXMuZ2V0QXR0cmlidXRlKFwic2hvcnRjdXRcIikpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9LFxuICAgIC8qKlxuICAgICAqXG4gICAgICogQHBhcmFtIGlkIGluZGljYXRlcyB0aGUgcG9wb3ZlciBhc3NvY2lhdGVkIHdpdGggdGhlIHNob3J0Y3V0XG4gICAgICogQHJldHVybnMge3N0cmluZ30gdGhlIGtleWJvYXJkIHNob3J0Y3V0IHVzZWQgZm9yIHRoZSBpZCBnaXZlblxuICAgICAqL1xuICAgIGdldFNob3J0Y3V0OiBmdW5jdGlvbiAoaWQpIHtcbiAgICAgICAgZm9yICh2YXIga2V5Y29kZSBpbiBzaG9ydGN1dHMpIHtcbiAgICAgICAgICAgIGlmIChzaG9ydGN1dHMuaGFzT3duUHJvcGVydHkoa2V5Y29kZSkpIHtcbiAgICAgICAgICAgICAgICBpZiAoc2hvcnRjdXRzW2tleWNvZGVdLmlkID09PSBpZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gXCIgKFwiICsgc2hvcnRjdXRzW2tleWNvZGVdLmNoYXJhY3RlciArIFwiKVwiO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gXCJcIjtcbiAgICB9XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IEtleWJvYXJkU2hvcnRjdXQ7XG4iLCIvKipcbiAqXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZnVuY3Rpb24gU2ltdWxjYXN0TG9nZ2VyKG5hbWUsIGx2bCkge1xuICAgIHRoaXMubmFtZSA9IG5hbWU7XG4gICAgdGhpcy5sdmwgPSBsdmw7XG59XG5cblNpbXVsY2FzdExvZ2dlci5wcm90b3R5cGUubG9nID0gZnVuY3Rpb24gKHRleHQpIHtcbiAgICBpZiAodGhpcy5sdmwpIHtcbiAgICAgICAgY29uc29sZS5sb2codGV4dCk7XG4gICAgfVxufTtcblxuU2ltdWxjYXN0TG9nZ2VyLnByb3RvdHlwZS5pbmZvID0gZnVuY3Rpb24gKHRleHQpIHtcbiAgICBpZiAodGhpcy5sdmwgPiAxKSB7XG4gICAgICAgIGNvbnNvbGUuaW5mbyh0ZXh0KTtcbiAgICB9XG59O1xuXG5TaW11bGNhc3RMb2dnZXIucHJvdG90eXBlLmZpbmUgPSBmdW5jdGlvbiAodGV4dCkge1xuICAgIGlmICh0aGlzLmx2bCA+IDIpIHtcbiAgICAgICAgY29uc29sZS5sb2codGV4dCk7XG4gICAgfVxufTtcblxuU2ltdWxjYXN0TG9nZ2VyLnByb3RvdHlwZS5lcnJvciA9IGZ1bmN0aW9uICh0ZXh0KSB7XG4gICAgY29uc29sZS5lcnJvcih0ZXh0KTtcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU2ltdWxjYXN0TG9nZ2VyOyIsInZhciBTaW11bGNhc3RMb2dnZXIgPSByZXF1aXJlKFwiLi9TaW11bGNhc3RMb2dnZXJcIik7XG52YXIgU2ltdWxjYXN0VXRpbHMgPSByZXF1aXJlKFwiLi9TaW11bGNhc3RVdGlsc1wiKTtcbnZhciBNZWRpYVN0cmVhbVR5cGUgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvTWVkaWFTdHJlYW1UeXBlc1wiKTtcblxuZnVuY3Rpb24gU2ltdWxjYXN0UmVjZWl2ZXIoKSB7XG4gICAgdGhpcy5zaW11bGNhc3RVdGlscyA9IG5ldyBTaW11bGNhc3RVdGlscygpO1xuICAgIHRoaXMubG9nZ2VyID0gbmV3IFNpbXVsY2FzdExvZ2dlcignU2ltdWxjYXN0UmVjZWl2ZXInLCAxKTtcbn1cblxuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLl9yZW1vdGVWaWRlb1NvdXJjZUNhY2hlID0gJyc7XG5TaW11bGNhc3RSZWNlaXZlci5wcm90b3R5cGUuX3JlbW90ZU1hcHMgPSB7XG4gICAgbXNpZDJRdWFsaXR5OiB7fSxcbiAgICBzc3JjMk1zaWQ6IHt9LFxuICAgIG1zaWQyc3NyYzoge30sXG4gICAgcmVjZWl2aW5nVmlkZW9TdHJlYW1zOiB7fVxufTtcblxuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLl9jYWNoZVJlbW90ZVZpZGVvU291cmNlcyA9IGZ1bmN0aW9uIChsaW5lcykge1xuICAgIHRoaXMuX3JlbW90ZVZpZGVvU291cmNlQ2FjaGUgPSB0aGlzLnNpbXVsY2FzdFV0aWxzLl9nZXRWaWRlb1NvdXJjZXMobGluZXMpO1xufTtcblxuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLl9yZXN0b3JlUmVtb3RlVmlkZW9Tb3VyY2VzID0gZnVuY3Rpb24gKGxpbmVzKSB7XG4gICAgdGhpcy5zaW11bGNhc3RVdGlscy5fcmVwbGFjZVZpZGVvU291cmNlcyhsaW5lcywgdGhpcy5fcmVtb3RlVmlkZW9Tb3VyY2VDYWNoZSk7XG59O1xuXG5TaW11bGNhc3RSZWNlaXZlci5wcm90b3R5cGUuX2Vuc3VyZUdvb2dDb25mZXJlbmNlID0gZnVuY3Rpb24gKGxpbmVzKSB7XG4gICAgdmFyIHNiO1xuXG4gICAgdGhpcy5sb2dnZXIuaW5mbygnRW5zdXJpbmcgeC1nb29nbGUtY29uZmVyZW5jZSBmbGFnLi4uJylcblxuICAgIGlmICh0aGlzLnNpbXVsY2FzdFV0aWxzLl9pbmRleE9mQXJyYXkoJ2E9eC1nb29nbGUtZmxhZzpjb25mZXJlbmNlJywgbGluZXMpID09PSB0aGlzLnNpbXVsY2FzdFV0aWxzLl9lbXB0eUNvbXBvdW5kSW5kZXgpIHtcbiAgICAgICAgLy8gVE9ETyhncCkgZG8gdGhhdCBmb3IgdGhlIGF1ZGlvIGFzIHdlbGwgYXMgc3VnZ2VzdGVkIGJ5IGZpcHBvLlxuICAgICAgICAvLyBBZGQgdGhlIGdvb2dsZSBjb25mZXJlbmNlIGZsYWdcbiAgICAgICAgc2IgPSB0aGlzLnNpbXVsY2FzdFV0aWxzLl9nZXRWaWRlb1NvdXJjZXMobGluZXMpO1xuICAgICAgICBzYiA9IFsnYT14LWdvb2dsZS1mbGFnOmNvbmZlcmVuY2UnXS5jb25jYXQoc2IpO1xuICAgICAgICB0aGlzLnNpbXVsY2FzdFV0aWxzLl9yZXBsYWNlVmlkZW9Tb3VyY2VzKGxpbmVzLCBzYik7XG4gICAgfVxufTtcblxuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLl9yZXN0b3JlU2ltdWxjYXN0R3JvdXBzID0gZnVuY3Rpb24gKHNiKSB7XG4gICAgdGhpcy5fcmVzdG9yZVJlbW90ZVZpZGVvU291cmNlcyhzYik7XG59O1xuXG4vKipcbiAqIFJlc3RvcmVzIHRoZSBzaW11bGNhc3QgZ3JvdXBzIG9mIHRoZSByZW1vdGUgZGVzY3JpcHRpb24uIEluXG4gKiB0cmFuc2Zvcm1SZW1vdGVEZXNjcmlwdGlvbiB3ZSByZW1vdmUgdGhvc2UgaW4gb3JkZXIgZm9yIHRoZSBzZXQgcmVtb3RlXG4gKiBkZXNjcmlwdGlvbiB0byBzdWNjZWVkLiBUaGUgZm9jdXMgbmVlZHMgdGhlIHNpZ25hbCB0aGUgZ3JvdXBzIHRvIG5ld1xuICogcGFydGljaXBhbnRzLlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLnJldmVyc2VUcmFuc2Zvcm1SZW1vdGVEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgdmFyIHNiO1xuXG4gICAgaWYgKCF0aGlzLnNpbXVsY2FzdFV0aWxzLmlzVmFsaWREZXNjcmlwdGlvbihkZXNjKSkge1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICBpZiAoY29uZmlnLmVuYWJsZVNpbXVsY2FzdCkge1xuICAgICAgICBzYiA9IGRlc2Muc2RwLnNwbGl0KCdcXHJcXG4nKTtcblxuICAgICAgICB0aGlzLl9yZXN0b3JlU2ltdWxjYXN0R3JvdXBzKHNiKTtcblxuICAgICAgICBkZXNjID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICAgICAgICB0eXBlOiBkZXNjLnR5cGUsXG4gICAgICAgICAgICBzZHA6IHNiLmpvaW4oJ1xcclxcbicpXG4gICAgICAgIH0pO1xuICAgIH1cblxuICAgIHJldHVybiBkZXNjO1xufTtcblxuU2ltdWxjYXN0VXRpbHMucHJvdG90eXBlLl9lbnN1cmVPcmRlciA9IGZ1bmN0aW9uIChsaW5lcykge1xuICAgIHZhciB2aWRlb1NvdXJjZXMsIHNiO1xuXG4gICAgdmlkZW9Tb3VyY2VzID0gdGhpcy5wYXJzZU1lZGlhKGxpbmVzLCBbJ3ZpZGVvJ10pWzBdO1xuICAgIHNiID0gdGhpcy5fY29tcGlsZVZpZGVvU291cmNlcyh2aWRlb1NvdXJjZXMpO1xuXG4gICAgdGhpcy5fcmVwbGFjZVZpZGVvU291cmNlcyhsaW5lcywgc2IpO1xufTtcblxuU2ltdWxjYXN0UmVjZWl2ZXIucHJvdG90eXBlLl91cGRhdGVSZW1vdGVNYXBzID0gZnVuY3Rpb24gKGxpbmVzKSB7XG4gICAgdmFyIHJlbW90ZVZpZGVvU291cmNlcyA9IHRoaXMuc2ltdWxjYXN0VXRpbHMucGFyc2VNZWRpYShsaW5lcywgWyd2aWRlbyddKVswXSxcbiAgICAgICAgdmlkZW9Tb3VyY2UsIHF1YWxpdHk7XG5cbiAgICAvLyAocmUpIGluaXRpYWxpemUgdGhlIHJlbW90ZSBtYXBzLlxuICAgIHRoaXMuX3JlbW90ZU1hcHMubXNpZDJRdWFsaXR5ID0ge307XG4gICAgdGhpcy5fcmVtb3RlTWFwcy5zc3JjMk1zaWQgPSB7fTtcbiAgICB0aGlzLl9yZW1vdGVNYXBzLm1zaWQyc3NyYyA9IHt9O1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGlmIChyZW1vdGVWaWRlb1NvdXJjZXMuZ3JvdXBzICYmIHJlbW90ZVZpZGVvU291cmNlcy5ncm91cHMubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgIHJlbW90ZVZpZGVvU291cmNlcy5ncm91cHMuZm9yRWFjaChmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgIGlmIChncm91cC5zZW1hbnRpY3MgPT09ICdTSU0nICYmIGdyb3VwLnNzcmNzICYmIGdyb3VwLnNzcmNzLmxlbmd0aCAhPT0gMCkge1xuICAgICAgICAgICAgICAgIHF1YWxpdHkgPSAwO1xuICAgICAgICAgICAgICAgIGdyb3VwLnNzcmNzLmZvckVhY2goZnVuY3Rpb24gKHNzcmMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmlkZW9Tb3VyY2UgPSByZW1vdGVWaWRlb1NvdXJjZXMuc291cmNlc1tzc3JjXTtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fcmVtb3RlTWFwcy5tc2lkMlF1YWxpdHlbdmlkZW9Tb3VyY2UubXNpZF0gPSBxdWFsaXR5Kys7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuX3JlbW90ZU1hcHMuc3NyYzJNc2lkW3ZpZGVvU291cmNlLnNzcmNdID0gdmlkZW9Tb3VyY2UubXNpZDtcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5fcmVtb3RlTWFwcy5tc2lkMnNzcmNbdmlkZW9Tb3VyY2UubXNpZF0gPSB2aWRlb1NvdXJjZS5zc3JjO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG59O1xuXG5TaW11bGNhc3RSZWNlaXZlci5wcm90b3R5cGUuX3NldFJlY2VpdmluZ1ZpZGVvU3RyZWFtID0gZnVuY3Rpb24gKHJlc291cmNlLCBzc3JjKSB7XG4gICAgdGhpcy5fcmVtb3RlTWFwcy5yZWNlaXZpbmdWaWRlb1N0cmVhbXNbcmVzb3VyY2VdID0gc3NyYztcbn07XG5cbi8qKlxuICogUmV0dXJucyBhIHN0cmVhbSB3aXRoIHNpbmdsZSB2aWRlbyB0cmFjaywgdGhlIG9uZSBjdXJyZW50bHkgYmVpbmdcbiAqIHJlY2VpdmVkIGJ5IHRoaXMgZW5kcG9pbnQuXG4gKlxuICogQHBhcmFtIHN0cmVhbSB0aGUgcmVtb3RlIHNpbXVsY2FzdCBzdHJlYW0uXG4gKiBAcmV0dXJucyB7d2Via2l0TWVkaWFTdHJlYW19XG4gKi9cblNpbXVsY2FzdFJlY2VpdmVyLnByb3RvdHlwZS5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbSA9IGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICB2YXIgdHJhY2tzLCBpLCBlbGVjdGVkVHJhY2ssIG1zaWQsIHF1YWxpdHkgPSAwLCByZWNlaXZpbmdUcmFja0lkO1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGlmIChjb25maWcuZW5hYmxlU2ltdWxjYXN0KSB7XG5cbiAgICAgICAgc3RyZWFtLmdldFZpZGVvVHJhY2tzKCkuc29tZShmdW5jdGlvbiAodHJhY2spIHtcbiAgICAgICAgICAgIHJldHVybiBPYmplY3Qua2V5cyhzZWxmLl9yZW1vdGVNYXBzLnJlY2VpdmluZ1ZpZGVvU3RyZWFtcykuc29tZShmdW5jdGlvbiAocmVzb3VyY2UpIHtcbiAgICAgICAgICAgICAgICB2YXIgc3NyYyA9IHNlbGYuX3JlbW90ZU1hcHMucmVjZWl2aW5nVmlkZW9TdHJlYW1zW3Jlc291cmNlXTtcbiAgICAgICAgICAgICAgICB2YXIgbXNpZCA9IHNlbGYuX3JlbW90ZU1hcHMuc3NyYzJNc2lkW3NzcmNdO1xuICAgICAgICAgICAgICAgIGlmIChtc2lkID09IFtzdHJlYW0uaWQsIHRyYWNrLmlkXS5qb2luKCcgJykpIHtcbiAgICAgICAgICAgICAgICAgICAgZWxlY3RlZFRyYWNrID0gdHJhY2s7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9KTtcblxuICAgICAgICBpZiAoIWVsZWN0ZWRUcmFjaykge1xuICAgICAgICAgICAgLy8gd2UgZG9uJ3QgaGF2ZSBhbiBlbGVjdGVkIHRyYWNrLCBjaG9vc2UgYnkgaW5pdGlhbCBxdWFsaXR5LlxuICAgICAgICAgICAgdHJhY2tzID0gc3RyZWFtLmdldFZpZGVvVHJhY2tzKCk7XG4gICAgICAgICAgICBmb3IgKGkgPSAwOyBpIDwgdHJhY2tzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgbXNpZCA9IFtzdHJlYW0uaWQsIHRyYWNrc1tpXS5pZF0uam9pbignICcpO1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLl9yZW1vdGVNYXBzLm1zaWQyUXVhbGl0eVttc2lkXSA9PT0gcXVhbGl0eSkge1xuICAgICAgICAgICAgICAgICAgICBlbGVjdGVkVHJhY2sgPSB0cmFja3NbaV07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gVE9ETyhncCkgaWYgdGhlIGluaXRpYWxRdWFsaXR5IGNvdWxkIG5vdCBiZSBzYXRpc2ZpZWQsIGxvd2VyXG4gICAgICAgICAgICAvLyB0aGUgcmVxdWlyZW1lbnQgYW5kIHRyeSBhZ2Fpbi5cbiAgICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiAoZWxlY3RlZFRyYWNrKVxuICAgICAgICA/IG5ldyB3ZWJraXRNZWRpYVN0cmVhbShbZWxlY3RlZFRyYWNrXSlcbiAgICAgICAgOiBzdHJlYW07XG59O1xuXG5TaW11bGNhc3RSZWNlaXZlci5wcm90b3R5cGUuZ2V0UmVjZWl2aW5nU1NSQyA9IGZ1bmN0aW9uIChqaWQpIHtcbiAgICB2YXIgcmVzb3VyY2UgPSBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChqaWQpO1xuICAgIHZhciBzc3JjID0gdGhpcy5fcmVtb3RlTWFwcy5yZWNlaXZpbmdWaWRlb1N0cmVhbXNbcmVzb3VyY2VdO1xuXG4gICAgLy8gSWYgd2UgaGF2ZW4ndCByZWNlaXZpbmcgYSBcImNoYW5nZWRcIiBldmVudCB5ZXQsIHRoZW4gd2UgbXVzdCBiZSByZWNlaXZpbmdcbiAgICAvLyBsb3cgcXVhbGl0eSAodGhhdCB0aGUgc2VuZGVyIGFsd2F5cyBzdHJlYW1zKS5cbiAgICBpZighc3NyYylcbiAgICB7XG4gICAgICAgIHZhciByZW1vdGVTdHJlYW1PYmplY3QgPSBBUFAuUlRDLnJlbW90ZVN0cmVhbXNbamlkXVtNZWRpYVN0cmVhbVR5cGUuVklERU9fVFlQRV07XG4gICAgICAgIHZhciByZW1vdGVTdHJlYW0gPSByZW1vdGVTdHJlYW1PYmplY3QuZ2V0T3JpZ2luYWxTdHJlYW0oKTtcbiAgICAgICAgdmFyIHRyYWNrcyA9IHJlbW90ZVN0cmVhbS5nZXRWaWRlb1RyYWNrcygpO1xuICAgICAgICBpZiAodHJhY2tzKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBrID0gMDsgayA8IHRyYWNrcy5sZW5ndGg7IGsrKykge1xuICAgICAgICAgICAgICAgIHZhciB0cmFjayA9IHRyYWNrc1trXTtcbiAgICAgICAgICAgICAgICB2YXIgbXNpZCA9IFtyZW1vdGVTdHJlYW0uaWQsIHRyYWNrLmlkXS5qb2luKCcgJyk7XG4gICAgICAgICAgICAgICAgdmFyIF9zc3JjID0gdGhpcy5fcmVtb3RlTWFwcy5tc2lkMnNzcmNbbXNpZF07XG4gICAgICAgICAgICAgICAgdmFyIHF1YWxpdHkgPSB0aGlzLl9yZW1vdGVNYXBzLm1zaWQyUXVhbGl0eVttc2lkXTtcbiAgICAgICAgICAgICAgICBpZiAocXVhbGl0eSA9PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHNzcmMgPSBfc3NyYztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gc3NyYztcbn07XG5cblNpbXVsY2FzdFJlY2VpdmVyLnByb3RvdHlwZS5nZXRSZWNlaXZpbmdWaWRlb1N0cmVhbUJ5U1NSQyA9IGZ1bmN0aW9uIChzc3JjKVxue1xuICAgIHZhciBzaWQsIGVsZWN0ZWRTdHJlYW07XG4gICAgdmFyIGksIGosIGs7XG4gICAgdmFyIGppZCA9IEFQUC54bXBwLmdldEppZEZyb21TU1JDKHNzcmMpO1xuICAgIGlmKGppZCAmJiBBUFAuUlRDLnJlbW90ZVN0cmVhbXNbamlkXSlcbiAgICB7XG4gICAgICAgIHZhciByZW1vdGVTdHJlYW1PYmplY3QgPSBBUFAuUlRDLnJlbW90ZVN0cmVhbXNbamlkXVtNZWRpYVN0cmVhbVR5cGUuVklERU9fVFlQRV07XG4gICAgICAgIHZhciByZW1vdGVTdHJlYW0gPSByZW1vdGVTdHJlYW1PYmplY3QuZ2V0T3JpZ2luYWxTdHJlYW0oKTtcbiAgICAgICAgdmFyIHRyYWNrcyA9IHJlbW90ZVN0cmVhbS5nZXRWaWRlb1RyYWNrcygpO1xuICAgICAgICBpZiAodHJhY2tzKSB7XG4gICAgICAgICAgICBmb3IgKGsgPSAwOyBrIDwgdHJhY2tzLmxlbmd0aDsgaysrKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRyYWNrID0gdHJhY2tzW2tdO1xuICAgICAgICAgICAgICAgIHZhciBtc2lkID0gW3JlbW90ZVN0cmVhbS5pZCwgdHJhY2suaWRdLmpvaW4oJyAnKTtcbiAgICAgICAgICAgICAgICB2YXIgdG1wID0gdGhpcy5fcmVtb3RlTWFwcy5tc2lkMnNzcmNbbXNpZF07XG4gICAgICAgICAgICAgICAgaWYgKHRtcCA9PSBzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgIGVsZWN0ZWRTdHJlYW0gPSBuZXcgd2Via2l0TWVkaWFTdHJlYW0oW3RyYWNrXSk7XG4gICAgICAgICAgICAgICAgICAgIHNpZCA9IHJlbW90ZVN0cmVhbU9iamVjdC5zaWQ7XG4gICAgICAgICAgICAgICAgICAgIC8vIHN0cmVhbSBmb3VuZCwgc3RvcC5cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgICAgY29uc29sZS5kZWJ1ZyhBUFAuUlRDLnJlbW90ZVN0cmVhbXMsIGppZCwgc3NyYyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgICAgc2lkOiBzaWQsXG4gICAgICAgIHN0cmVhbTogZWxlY3RlZFN0cmVhbVxuICAgIH07XG59O1xuXG4vKipcbiAqIEdldHMgdGhlIGZ1bGx5IHF1YWxpZmllZCBtc2lkIChzdHJlYW0uaWQgKyB0cmFjay5pZCkgYXNzb2NpYXRlZCB0byB0aGVcbiAqIFNTUkMuXG4gKlxuICogQHBhcmFtIHNzcmNcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW11bGNhc3RSZWNlaXZlci5wcm90b3R5cGUuZ2V0UmVtb3RlVmlkZW9TdHJlYW1JZEJ5U1NSQyA9IGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgcmV0dXJuIHRoaXMuX3JlbW90ZU1hcHMuc3NyYzJNc2lkW3NzcmNdO1xufTtcblxuLyoqXG4gKiBSZW1vdmVzIHRoZSBzc3JjLWdyb3VwOlNJTSBmcm9tIHRoZSByZW1vdGUgZGVzY3JpcHRpb24gYmFjYXVzZSBDaHJvbWVcbiAqIGVpdGhlciBnZXRzIGNvbmZ1c2VkIGFuZCB0aGlua3MgdGhpcyBpcyBhbiBGSUQgZ3JvdXAgb3IsIGlmIGFuIEZJRCBncm91cFxuICogaXMgYWxyZWFkeSBwcmVzZW50LCBpdCBmYWlscyB0byBzZXQgdGhlIHJlbW90ZSBkZXNjcmlwdGlvbi5cbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cblNpbXVsY2FzdFJlY2VpdmVyLnByb3RvdHlwZS50cmFuc2Zvcm1SZW1vdGVEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjKSB7XG5cbiAgICBpZiAoZGVzYyAmJiBkZXNjLnNkcCkge1xuICAgICAgICB2YXIgc2IgPSBkZXNjLnNkcC5zcGxpdCgnXFxyXFxuJyk7XG5cbiAgICAgICAgdGhpcy5fdXBkYXRlUmVtb3RlTWFwcyhzYik7XG4gICAgICAgIHRoaXMuX2NhY2hlUmVtb3RlVmlkZW9Tb3VyY2VzKHNiKTtcblxuICAgICAgICAvLyBOT1RFKGdwKSB0aGlzIG5lZWRzIHRvIGJlIGNhbGxlZCBhZnRlciB1cGRhdGVSZW1vdGVNYXBzIGJlY2F1c2Ugd2VcbiAgICAgICAgLy8gbmVlZCB0aGUgc2ltdWxjYXN0IGdyb3VwIGluIHRoZSBfdXBkYXRlUmVtb3RlTWFwcygpIG1ldGhvZC5cbiAgICAgICAgdGhpcy5zaW11bGNhc3RVdGlscy5fcmVtb3ZlU2ltdWxjYXN0R3JvdXAoc2IpO1xuXG4gICAgICAgIGlmIChkZXNjLnNkcC5pbmRleE9mKCdhPXNzcmMtZ3JvdXA6U0lNJykgIT09IC0xKSB7XG4gICAgICAgICAgICAvLyBXZSBkb24ndCBuZWVkIHRoZSBnb29nIGNvbmZlcmVuY2UgZmxhZyBpZiB3ZSdyZSBub3QgZG9pbmdcbiAgICAgICAgICAgIC8vIHNpbXVsY2FzdC5cbiAgICAgICAgICAgIHRoaXMuX2Vuc3VyZUdvb2dDb25mZXJlbmNlKHNiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGRlc2MgPSBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgICAgIHR5cGU6IGRlc2MudHlwZSxcbiAgICAgICAgICAgIHNkcDogc2Iuam9pbignXFxyXFxuJylcbiAgICAgICAgfSk7XG5cbiAgICAgICAgdGhpcy5sb2dnZXIuZmluZShbJ1RyYW5zZm9ybWVkIHJlbW90ZSBkZXNjcmlwdGlvbicsIGRlc2Muc2RwXS5qb2luKCcgJykpO1xuICAgIH1cblxuICAgIHJldHVybiBkZXNjO1xufTtcblxubW9kdWxlLmV4cG9ydHMgPSBTaW11bGNhc3RSZWNlaXZlcjsiLCJ2YXIgU2ltdWxjYXN0TG9nZ2VyID0gcmVxdWlyZShcIi4vU2ltdWxjYXN0TG9nZ2VyXCIpO1xudmFyIFNpbXVsY2FzdFV0aWxzID0gcmVxdWlyZShcIi4vU2ltdWxjYXN0VXRpbHNcIik7XG5cbmZ1bmN0aW9uIFNpbXVsY2FzdFNlbmRlcigpIHtcbiAgICB0aGlzLnNpbXVsY2FzdFV0aWxzID0gbmV3IFNpbXVsY2FzdFV0aWxzKCk7XG4gICAgdGhpcy5sb2dnZXIgPSBuZXcgU2ltdWxjYXN0TG9nZ2VyKCdTaW11bGNhc3RTZW5kZXInLCAxKTtcbn1cblxuU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5kaXNwbGF5ZWRMb2NhbFZpZGVvU3RyZWFtID0gbnVsbDtcblxuU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fZ2VuZXJhdGVHdWlkID0gKGZ1bmN0aW9uICgpIHtcbiAgICBmdW5jdGlvbiBzNCgpIHtcbiAgICAgICAgcmV0dXJuIE1hdGguZmxvb3IoKDEgKyBNYXRoLnJhbmRvbSgpKSAqIDB4MTAwMDApXG4gICAgICAgICAgICAudG9TdHJpbmcoMTYpXG4gICAgICAgICAgICAuc3Vic3RyaW5nKDEpO1xuICAgIH1cblxuICAgIHJldHVybiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBzNCgpICsgczQoKSArICctJyArIHM0KCkgKyAnLScgKyBzNCgpICsgJy0nICtcbiAgICAgICAgICAgIHM0KCkgKyAnLScgKyBzNCgpICsgczQoKSArIHM0KCk7XG4gICAgfTtcbn0oKSk7XG5cbi8vIFJldHVybnMgYSByYW5kb20gaW50ZWdlciBiZXR3ZWVuIG1pbiAoaW5jbHVkZWQpIGFuZCBtYXggKGV4Y2x1ZGVkKVxuLy8gVXNpbmcgTWF0aC5yb3VuZCgpIGdpdmVzIGEgbm9uLXVuaWZvcm0gZGlzdHJpYnV0aW9uIVxuU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fZ2VuZXJhdGVSYW5kb21TU1JDID0gZnVuY3Rpb24gKCkge1xuICAgIHZhciBtaW4gPSAwLCBtYXggPSAweGZmZmZmZmZmO1xuICAgIHJldHVybiBNYXRoLmZsb29yKE1hdGgucmFuZG9tKCkgKiAobWF4IC0gbWluKSkgKyBtaW47XG59O1xuXG5TaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLmdldExvY2FsVmlkZW9TdHJlYW0gPSBmdW5jdGlvbiAoKSB7XG4gICAgcmV0dXJuICh0aGlzLmRpc3BsYXllZExvY2FsVmlkZW9TdHJlYW0gIT0gbnVsbClcbiAgICAgICAgPyB0aGlzLmRpc3BsYXllZExvY2FsVmlkZW9TdHJlYW1cbiAgICAgICAgLy8gaW4gY2FzZSB3ZSBoYXZlIG5vIHNpbXVsY2FzdCBhdCBhbGwsIGkuZS4gd2UgZGlkbid0IHBlcmZvcm0gdGhlIEdVTVxuICAgICAgICA6IEFQUC5SVEMubG9jYWxWaWRlby5nZXRPcmlnaW5hbFN0cmVhbSgpO1xufTtcblxuZnVuY3Rpb24gTmF0aXZlU2ltdWxjYXN0U2VuZGVyKCkge1xuICAgIFNpbXVsY2FzdFNlbmRlci5jYWxsKHRoaXMpOyAvLyBjYWxsIHRoZSBzdXBlciBjb25zdHJ1Y3Rvci5cbn1cblxuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZSk7XG5cbk5hdGl2ZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX2xvY2FsRXhwbG9zaW9uTWFwID0ge307XG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLl9pc1VzaW5nU2NyZWVuU3RyZWFtID0gZmFsc2U7XG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLl9sb2NhbFZpZGVvU291cmNlQ2FjaGUgPSAnJztcblxuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5yZXNldCA9IGZ1bmN0aW9uICgpIHtcbiAgICB0aGlzLl9sb2NhbEV4cGxvc2lvbk1hcCA9IHt9O1xuICAgIHRoaXMuX2lzVXNpbmdTY3JlZW5TdHJlYW0gPSBBUFAuZGVza3RvcHNoYXJpbmcuaXNVc2luZ1NjcmVlblN0cmVhbSgpO1xufTtcblxuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fY2FjaGVMb2NhbFZpZGVvU291cmNlcyA9IGZ1bmN0aW9uIChsaW5lcykge1xuICAgIHRoaXMuX2xvY2FsVmlkZW9Tb3VyY2VDYWNoZSA9IHRoaXMuc2ltdWxjYXN0VXRpbHMuX2dldFZpZGVvU291cmNlcyhsaW5lcyk7XG59O1xuXG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLl9yZXN0b3JlTG9jYWxWaWRlb1NvdXJjZXMgPSBmdW5jdGlvbiAobGluZXMpIHtcbiAgICB0aGlzLnNpbXVsY2FzdFV0aWxzLl9yZXBsYWNlVmlkZW9Tb3VyY2VzKGxpbmVzLCB0aGlzLl9sb2NhbFZpZGVvU291cmNlQ2FjaGUpO1xufTtcblxuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fYXBwZW5kU2ltdWxjYXN0R3JvdXAgPSBmdW5jdGlvbiAobGluZXMpIHtcbiAgICB2YXIgdmlkZW9Tb3VyY2VzLCBzc3JjR3JvdXAsIHNpbVNTUkMsIG51bU9mU3VicyA9IDIsIGksIHNiLCBtc2lkO1xuXG4gICAgdGhpcy5sb2dnZXIuaW5mbygnQXBwZW5kaW5nIHNpbXVsY2FzdCBncm91cC4uLicpO1xuXG4gICAgLy8gR2V0IHRoZSBwcmltYXJ5IFNTUkMgaW5mb3JtYXRpb24uXG4gICAgdmlkZW9Tb3VyY2VzID0gdGhpcy5zaW11bGNhc3RVdGlscy5wYXJzZU1lZGlhKGxpbmVzLCBbJ3ZpZGVvJ10pWzBdO1xuXG4gICAgLy8gU3RhcnQgYnVpbGRpbmcgdGhlIFNJTSBTU1JDIGdyb3VwLlxuICAgIHNzcmNHcm91cCA9IFsnYT1zc3JjLWdyb3VwOlNJTSddO1xuXG4gICAgLy8gVGhlIHZpZGVvIHNvdXJjZSBidWZmZXIuXG4gICAgc2IgPSBbXTtcblxuICAgIC8vIENyZWF0ZSB0aGUgc2ltdWxjYXN0IHN1Yi1zdHJlYW1zLlxuICAgIGZvciAoaSA9IDA7IGkgPCBudW1PZlN1YnM7IGkrKykge1xuICAgICAgICAvLyBUT0RPKGdwKSBwcmV2ZW50IFNTUkMgY29sbGlzaW9uLlxuICAgICAgICBzaW1TU1JDID0gdGhpcy5fZ2VuZXJhdGVSYW5kb21TU1JDKCk7XG4gICAgICAgIHNzcmNHcm91cC5wdXNoKHNpbVNTUkMpO1xuXG4gICAgICAgIGlmICh2aWRlb1NvdXJjZXMuYmFzZSkge1xuICAgICAgICAgICAgc2Iuc3BsaWNlLmFwcGx5KHNiLCBbc2IubGVuZ3RoLCAwXS5jb25jYXQoXG4gICAgICAgICAgICAgICAgW1tcImE9c3NyYzpcIiwgc2ltU1NSQywgXCIgY25hbWU6XCIsIHZpZGVvU291cmNlcy5iYXNlLmNuYW1lXS5qb2luKCcnKSxcbiAgICAgICAgICAgICAgICAgICAgW1wiYT1zc3JjOlwiLCBzaW1TU1JDLCBcIiBtc2lkOlwiLCB2aWRlb1NvdXJjZXMuYmFzZS5tc2lkXS5qb2luKCcnKV1cbiAgICAgICAgICAgICkpO1xuICAgICAgICB9XG5cbiAgICAgICAgdGhpcy5sb2dnZXIuaW5mbyhbJ0dlbmVyYXRlZCBzdWJzdHJlYW0gJywgaSwgJyB3aXRoIFNTUkMgJywgc2ltU1NSQywgJy4nXS5qb2luKCcnKSk7XG5cbiAgICB9XG5cbiAgICAvLyBBZGQgdGhlIGdyb3VwIHNpbSBsYXllcnMuXG4gICAgc2Iuc3BsaWNlKDAsIDAsIHNzcmNHcm91cC5qb2luKCcgJykpXG5cbiAgICB0aGlzLnNpbXVsY2FzdFV0aWxzLl9yZXBsYWNlVmlkZW9Tb3VyY2VzKGxpbmVzLCBzYik7XG59O1xuXG4vLyBEb2VzIHRoZSBhY3R1YWwgcGF0Y2hpbmcuXG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLl9lbnN1cmVTaW11bGNhc3RHcm91cCA9IGZ1bmN0aW9uIChsaW5lcykge1xuXG4gICAgdGhpcy5sb2dnZXIuaW5mbygnRW5zdXJpbmcgc2ltdWxjYXN0IGdyb3VwLi4uJyk7XG5cbiAgICBpZiAodGhpcy5zaW11bGNhc3RVdGlscy5faW5kZXhPZkFycmF5KCdhPXNzcmMtZ3JvdXA6U0lNJywgbGluZXMpID09PSB0aGlzLnNpbXVsY2FzdFV0aWxzLl9lbXB0eUNvbXBvdW5kSW5kZXgpIHtcbiAgICAgICAgdGhpcy5fYXBwZW5kU2ltdWxjYXN0R3JvdXAobGluZXMpO1xuICAgICAgICB0aGlzLl9jYWNoZUxvY2FsVmlkZW9Tb3VyY2VzKGxpbmVzKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICAvLyB2ZXJpZnkgdGhhdCB0aGUgc3NyY3MgcGFydGljaXBhdGluZyBpbiB0aGUgU0lNIGdyb3VwIGFyZSBwcmVzZW50XG4gICAgICAgIC8vIGluIHRoZSBTRFAgKG5lZWRlZCBmb3IgcHJlc2VuY2UpLlxuICAgICAgICB0aGlzLl9yZXN0b3JlTG9jYWxWaWRlb1NvdXJjZXMobGluZXMpO1xuICAgIH1cbn07XG5cbi8qKlxuICogUHJvZHVjZXMgYSBzaW5nbGUgc3RyZWFtIHdpdGggbXVsdGlwbGUgdHJhY2tzIGZvciBsb2NhbCB2aWRlbyBzb3VyY2VzLlxuICpcbiAqIEBwYXJhbSBsaW5lc1xuICogQHByaXZhdGVcbiAqL1xuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fZXhwbG9kZVNpbXVsY2FzdFNlbmRlclNvdXJjZXMgPSBmdW5jdGlvbiAobGluZXMpIHtcbiAgICB2YXIgc2IsIG1zaWQsIHNpZCwgdGlkLCB2aWRlb1NvdXJjZXMsIHNlbGY7XG5cbiAgICB0aGlzLmxvZ2dlci5pbmZvKCdFeHBsb2RpbmcgbG9jYWwgdmlkZW8gc291cmNlcy4uLicpO1xuXG4gICAgdmlkZW9Tb3VyY2VzID0gdGhpcy5zaW11bGNhc3RVdGlscy5wYXJzZU1lZGlhKGxpbmVzLCBbJ3ZpZGVvJ10pWzBdO1xuXG4gICAgc2VsZiA9IHRoaXM7XG4gICAgaWYgKHZpZGVvU291cmNlcy5ncm91cHMgJiYgdmlkZW9Tb3VyY2VzLmdyb3Vwcy5sZW5ndGggIT09IDApIHtcbiAgICAgICAgdmlkZW9Tb3VyY2VzLmdyb3Vwcy5mb3JFYWNoKGZ1bmN0aW9uIChncm91cCkge1xuICAgICAgICAgICAgaWYgKGdyb3VwLnNlbWFudGljcyA9PT0gJ1NJTScpIHtcbiAgICAgICAgICAgICAgICBncm91cC5zc3Jjcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gR2V0IHRoZSBtc2lkIGZvciB0aGlzIHNzcmMuLlxuICAgICAgICAgICAgICAgICAgICBpZiAoc2VsZi5fbG9jYWxFeHBsb3Npb25NYXBbc3NyY10pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIC4uIGVpdGhlciBmcm9tIHRoZSBleHBsb3Npb24gbWFwLi5cbiAgICAgICAgICAgICAgICAgICAgICAgIG1zaWQgPSBzZWxmLl9sb2NhbEV4cGxvc2lvbk1hcFtzc3JjXTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIC4uIG9yIGdlbmVyYXRlIGEgbmV3IG9uZSAobXNpZCkuXG4gICAgICAgICAgICAgICAgICAgICAgICBzaWQgPSB2aWRlb1NvdXJjZXMuc291cmNlc1tzc3JjXS5tc2lkXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLnN1YnN0cmluZygwLCB2aWRlb1NvdXJjZXMuc291cmNlc1tzc3JjXS5tc2lkLmluZGV4T2YoJyAnKSk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHRpZCA9IHNlbGYuX2dlbmVyYXRlR3VpZCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgbXNpZCA9IFtzaWQsIHRpZF0uam9pbignICcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5fbG9jYWxFeHBsb3Npb25NYXBbc3NyY10gPSBtc2lkO1xuICAgICAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gQXNzaWduIGl0IHRvIHRoZSBzb3VyY2Ugb2JqZWN0LlxuICAgICAgICAgICAgICAgICAgICB2aWRlb1NvdXJjZXMuc291cmNlc1tzc3JjXS5tc2lkID0gbXNpZDtcblxuICAgICAgICAgICAgICAgICAgICAvLyBUT0RPKGdwKSBDaGFuZ2UgdGhlIG1zaWQgb2YgYXNzb2NpYXRlZCBzb3VyY2VzLlxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICBzYiA9IHRoaXMuc2ltdWxjYXN0VXRpbHMuX2NvbXBpbGVWaWRlb1NvdXJjZXModmlkZW9Tb3VyY2VzKTtcblxuICAgIHRoaXMuc2ltdWxjYXN0VXRpbHMuX3JlcGxhY2VWaWRlb1NvdXJjZXMobGluZXMsIHNiKTtcbn07XG5cbi8qKlxuICogR1VNIGZvciBzaW11bGNhc3QuXG4gKlxuICogQHBhcmFtIGNvbnN0cmFpbnRzXG4gKiBAcGFyYW0gc3VjY2Vzc1xuICogQHBhcmFtIGVyclxuICovXG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uIChjb25zdHJhaW50cywgc3VjY2VzcywgZXJyKSB7XG5cbiAgICAvLyBUaGVyZSdzIG5vdGhpbmcgc3BlY2lhbCB0byBkbyBmb3IgbmF0aXZlIHNpbXVsY2FzdCwgc28ganVzdCBkbyBhIG5vcm1hbCBHVU0uXG4gICAgbmF2aWdhdG9yLndlYmtpdEdldFVzZXJNZWRpYShjb25zdHJhaW50cywgZnVuY3Rpb24gKGhxU3RyZWFtKSB7XG4gICAgICAgIHN1Y2Nlc3MoaHFTdHJlYW0pO1xuICAgIH0sIGVycik7XG59O1xuXG4vKipcbiAqIFByZXBhcmVzIHRoZSBsb2NhbCBkZXNjcmlwdGlvbiBmb3IgcHVibGljIHVzYWdlIChpLmUuIHRvIGJlIHNpZ25hbGVkXG4gKiB0aHJvdWdoIEppbmdsZSB0byB0aGUgZm9jdXMpLlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7UlRDU2Vzc2lvbkRlc2NyaXB0aW9ufVxuICovXG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLnJldmVyc2VUcmFuc2Zvcm1Mb2NhbERlc2NyaXB0aW9uID0gZnVuY3Rpb24gKGRlc2MpIHtcbiAgICB2YXIgc2I7XG5cbiAgICBpZiAoIXRoaXMuc2ltdWxjYXN0VXRpbHMuaXNWYWxpZERlc2NyaXB0aW9uKGRlc2MpIHx8IHRoaXMuX2lzVXNpbmdTY3JlZW5TdHJlYW0pIHtcbiAgICAgICAgcmV0dXJuIGRlc2M7XG4gICAgfVxuXG5cbiAgICBzYiA9IGRlc2Muc2RwLnNwbGl0KCdcXHJcXG4nKTtcblxuICAgIHRoaXMuX2V4cGxvZGVTaW11bGNhc3RTZW5kZXJTb3VyY2VzKHNiKTtcblxuICAgIGRlc2MgPSBuZXcgUlRDU2Vzc2lvbkRlc2NyaXB0aW9uKHtcbiAgICAgICAgdHlwZTogZGVzYy50eXBlLFxuICAgICAgICBzZHA6IHNiLmpvaW4oJ1xcclxcbicpXG4gICAgfSk7XG5cbiAgICB0aGlzLmxvZ2dlci5maW5lKFsnRXhwbG9kZWQgbG9jYWwgdmlkZW8gc291cmNlcycsIGRlc2Muc2RwXS5qb2luKCcgJykpO1xuXG4gICAgcmV0dXJuIGRlc2M7XG59O1xuXG4vKipcbiAqIEVuc3VyZXMgdGhhdCB0aGUgc2ltdWxjYXN0IGdyb3VwIGlzIHByZXNlbnQgaW4gdGhlIGFuc3dlciwgX2lmXyBuYXRpdmVcbiAqIHNpbXVsY2FzdCBpcyBlbmFibGVkLFxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuTmF0aXZlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS50cmFuc2Zvcm1BbnN3ZXIgPSBmdW5jdGlvbiAoZGVzYykge1xuXG4gICAgaWYgKCF0aGlzLnNpbXVsY2FzdFV0aWxzLmlzVmFsaWREZXNjcmlwdGlvbihkZXNjKSB8fCB0aGlzLl9pc1VzaW5nU2NyZWVuU3RyZWFtKSB7XG4gICAgICAgIHJldHVybiBkZXNjO1xuICAgIH1cblxuICAgIHZhciBzYiA9IGRlc2Muc2RwLnNwbGl0KCdcXHJcXG4nKTtcblxuICAgIC8vIEV2ZW4gaWYgd2UgaGF2ZSBlbmFibGVkIG5hdGl2ZSBzaW11bGNhc3RpbmcgcHJldmlvdXNseVxuICAgIC8vICh3aXRoIGEgY2FsbCB0byBTTEQgd2l0aCBhbiBhcHByb3ByaWF0ZSBTRFAsIGZvciBleGFtcGxlKSxcbiAgICAvLyBjcmVhdGVBbnN3ZXIgc2VlbXMgdG8gY29uc2lzdGVudGx5IGdlbmVyYXRlIGluY29tcGxldGUgU0RQXG4gICAgLy8gd2l0aCBtaXNzaW5nIFNTUkNTLlxuICAgIC8vXG4gICAgLy8gU28sIHN1YnNlcXVlbnQgY2FsbHMgdG8gU0xEIHdpbGwgaGF2ZSBtaXNzaW5nIFNTUkNTIGFuZCBwcmVzZW5jZVxuICAgIC8vIHdvbid0IGhhdmUgdGhlIGNvbXBsZXRlIGxpc3Qgb2YgU1JDcy5cbiAgICB0aGlzLl9lbnN1cmVTaW11bGNhc3RHcm91cChzYik7XG5cbiAgICBkZXNjID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7XG4gICAgICAgIHR5cGU6IGRlc2MudHlwZSxcbiAgICAgICAgc2RwOiBzYi5qb2luKCdcXHJcXG4nKVxuICAgIH0pO1xuXG4gICAgdGhpcy5sb2dnZXIuZmluZShbJ1RyYW5zZm9ybWVkIGFuc3dlcicsIGRlc2Muc2RwXS5qb2luKCcgJykpO1xuXG4gICAgcmV0dXJuIGRlc2M7XG59O1xuXG5cbi8qKlxuICpcbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cbk5hdGl2ZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUudHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgcmV0dXJuIGRlc2M7XG59O1xuXG5OYXRpdmVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLl9zZXRMb2NhbFZpZGVvU3RyZWFtRW5hYmxlZCA9IGZ1bmN0aW9uIChzc3JjLCBlbmFibGVkKSB7XG4gICAgLy8gTm90aGluZyB0byBkbyBoZXJlLCBuYXRpdmUgc2ltdWxjYXN0IGRvZXMgdGhhdCBhdXRvLW1hZ2ljYWxseS5cbn07XG5cbk5hdGl2ZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBOYXRpdmVTaW11bGNhc3RTZW5kZXI7XG5cbmZ1bmN0aW9uIFNpbXBsZVNpbXVsY2FzdFNlbmRlcigpIHtcbiAgICBTaW11bGNhc3RTZW5kZXIuY2FsbCh0aGlzKTtcbn1cblxuU2ltcGxlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZSk7XG5cblNpbXBsZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUubG9jYWxTdHJlYW0gPSBudWxsO1xuU2ltcGxlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fbG9jYWxNYXBzID0ge1xuICAgIG1zaWRzOiBbXSxcbiAgICBtc2lkMnNzcmM6IHt9XG59O1xuXG4vKipcbiAqIEdyb3VwcyBsb2NhbCB2aWRlbyBzb3VyY2VzIHRvZ2V0aGVyIGluIHRoZSBzc3JjLWdyb3VwOlNJTSBncm91cC5cbiAqXG4gKiBAcGFyYW0gbGluZXNcbiAqIEBwcml2YXRlXG4gKi9cblNpbXBsZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX2dyb3VwTG9jYWxWaWRlb1NvdXJjZXMgPSBmdW5jdGlvbiAobGluZXMpIHtcbiAgICB2YXIgc2IsIHZpZGVvU291cmNlcywgc3NyY3MgPSBbXSwgc3NyYztcblxuICAgIHRoaXMubG9nZ2VyLmluZm8oJ0dyb3VwaW5nIGxvY2FsIHZpZGVvIHNvdXJjZXMuLi4nKTtcblxuICAgIHZpZGVvU291cmNlcyA9IHRoaXMuc2ltdWxjYXN0VXRpbHMucGFyc2VNZWRpYShsaW5lcywgWyd2aWRlbyddKVswXTtcblxuICAgIGZvciAoc3NyYyBpbiB2aWRlb1NvdXJjZXMuc291cmNlcykge1xuICAgICAgICAvLyBqaXRzaS1tZWV0IGRlc3Ryb3lzL2NyZWF0ZXMgc3RyZWFtcyBhdCB2YXJpb3VzIHBsYWNlcyBjYXVzaW5nXG4gICAgICAgIC8vIHRoZSBvcmlnaW5hbCBsb2NhbCBzdHJlYW0gaWRzIHRvIGNoYW5nZS4gVGhlIG9ubHkgdGhpbmcgdGhhdFxuICAgICAgICAvLyByZW1haW5zIHVuY2hhbmdlZCBpcyB0aGUgdHJhY2tpZC5cbiAgICAgICAgdGhpcy5fbG9jYWxNYXBzLm1zaWQyc3NyY1t2aWRlb1NvdXJjZXMuc291cmNlc1tzc3JjXS5tc2lkLnNwbGl0KCcgJylbMV1dID0gc3NyYztcbiAgICB9XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgLy8gVE9ETyhncCkgYWRkIG9ubHkgXCJmcmVlXCIgc291cmNlcy5cbiAgICB0aGlzLl9sb2NhbE1hcHMubXNpZHMuZm9yRWFjaChmdW5jdGlvbiAobXNpZCkge1xuICAgICAgICBzc3Jjcy5wdXNoKHNlbGYuX2xvY2FsTWFwcy5tc2lkMnNzcmNbbXNpZF0pO1xuICAgIH0pO1xuXG4gICAgaWYgKCF2aWRlb1NvdXJjZXMuZ3JvdXBzKSB7XG4gICAgICAgIHZpZGVvU291cmNlcy5ncm91cHMgPSBbXTtcbiAgICB9XG5cbiAgICB2aWRlb1NvdXJjZXMuZ3JvdXBzLnB1c2goe1xuICAgICAgICAnc2VtYW50aWNzJzogJ1NJTScsXG4gICAgICAgICdzc3Jjcyc6IHNzcmNzXG4gICAgfSk7XG5cbiAgICBzYiA9IHRoaXMuc2ltdWxjYXN0VXRpbHMuX2NvbXBpbGVWaWRlb1NvdXJjZXModmlkZW9Tb3VyY2VzKTtcblxuICAgIHRoaXMuc2ltdWxjYXN0VXRpbHMuX3JlcGxhY2VWaWRlb1NvdXJjZXMobGluZXMsIHNiKTtcbn07XG5cbi8qKlxuICogR1VNIGZvciBzaW11bGNhc3QuXG4gKlxuICogQHBhcmFtIGNvbnN0cmFpbnRzXG4gKiBAcGFyYW0gc3VjY2Vzc1xuICogQHBhcmFtIGVyclxuICovXG5TaW1wbGVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uIChjb25zdHJhaW50cywgc3VjY2VzcywgZXJyKSB7XG5cbiAgICAvLyBUT0RPKGdwKSB3aGF0IGlmIHdlIHJlcXVlc3QgYSByZXNvbHV0aW9uIG5vdCBzdXBwb3J0ZWQgYnkgdGhlIGhhcmR3YXJlP1xuICAgIC8vIFRPRE8oZ3ApIG1ha2UgdGhlIGxxIHN0cmVhbSBjb25maWd1cmFibGU7IGFsdGhvdWdoIHRoaXMgd291bGRuJ3Qgd29yayB3aXRoIG5hdGl2ZSBzaW11bGNhc3RcbiAgICB2YXIgbHFDb25zdHJhaW50cyA9IHtcbiAgICAgICAgYXVkaW86IGZhbHNlLFxuICAgICAgICB2aWRlbzoge1xuICAgICAgICAgICAgbWFuZGF0b3J5OiB7XG4gICAgICAgICAgICAgICAgbWF4V2lkdGg6IDMyMCxcbiAgICAgICAgICAgICAgICBtYXhIZWlnaHQ6IDE4MCxcbiAgICAgICAgICAgICAgICBtYXhGcmFtZVJhdGU6IDE1XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9O1xuXG4gICAgdGhpcy5sb2dnZXIuaW5mbygnSFEgY29uc3RyYWludHM6ICcsIGNvbnN0cmFpbnRzKTtcbiAgICB0aGlzLmxvZ2dlci5pbmZvKCdMUSBjb25zdHJhaW50czogJywgbHFDb25zdHJhaW50cyk7XG5cblxuICAgIC8vIE5PVEUoZ3ApIGlmIHdlIHJlcXVlc3QgdGhlIGxxIHN0cmVhbSBmaXJzdCB3ZWJraXRHZXRVc2VyTWVkaWFcbiAgICAvLyBmYWlscyByYW5kb21seS4gVGVzdGVkIHdpdGggQ2hyb21lIDM3LiBBcyBmaXBwbyBzdWdnZXN0ZWQsIHRoZVxuICAgIC8vIHJlYXNvbiBhcHBlYXJzIHRvIGJlIHRoYXQgQ2hyb21lIG9ubHkgYWNxdWlyZXMgdGhlIGNhbSBvbmNlIGFuZFxuICAgIC8vIHRoZW4gZG93bnNjYWxlcyB0aGUgcGljdHVyZSAoaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9jaHJvbWl1bS9pc3N1ZXMvZGV0YWlsP2lkPTM0NjYxNiNjMTEpXG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgbmF2aWdhdG9yLndlYmtpdEdldFVzZXJNZWRpYShjb25zdHJhaW50cywgZnVuY3Rpb24gKGhxU3RyZWFtKSB7XG5cbiAgICAgICAgc2VsZi5sb2NhbFN0cmVhbSA9IGhxU3RyZWFtO1xuXG4gICAgICAgIC8vIHJlc2V0IGxvY2FsIG1hcHMuXG4gICAgICAgIHNlbGYuX2xvY2FsTWFwcy5tc2lkcyA9IFtdO1xuICAgICAgICBzZWxmLl9sb2NhbE1hcHMubXNpZDJzc3JjID0ge307XG5cbiAgICAgICAgLy8gYWRkIGhxIHRyYWNraWQgdG8gbG9jYWwgbWFwXG4gICAgICAgIHNlbGYuX2xvY2FsTWFwcy5tc2lkcy5wdXNoKGhxU3RyZWFtLmdldFZpZGVvVHJhY2tzKClbMF0uaWQpO1xuXG4gICAgICAgIG5hdmlnYXRvci53ZWJraXRHZXRVc2VyTWVkaWEobHFDb25zdHJhaW50cywgZnVuY3Rpb24gKGxxU3RyZWFtKSB7XG5cbiAgICAgICAgICAgIHNlbGYuZGlzcGxheWVkTG9jYWxWaWRlb1N0cmVhbSA9IGxxU3RyZWFtO1xuXG4gICAgICAgICAgICAvLyBOT1RFKGdwKSBUaGUgc3BlY2lmaWNhdGlvbiBzYXlzIEFycmF5LmZvckVhY2goKSB3aWxsIHZpc2l0XG4gICAgICAgICAgICAvLyB0aGUgYXJyYXkgZWxlbWVudHMgaW4gbnVtZXJpYyBvcmRlciwgYW5kIHRoYXQgaXQgZG9lc24ndFxuICAgICAgICAgICAgLy8gdmlzaXQgZWxlbWVudHMgdGhhdCBkb24ndCBleGlzdC5cblxuICAgICAgICAgICAgLy8gYWRkIGxxIHRyYWNraWQgdG8gbG9jYWwgbWFwXG4gICAgICAgICAgICBzZWxmLl9sb2NhbE1hcHMubXNpZHMuc3BsaWNlKDAsIDAsIGxxU3RyZWFtLmdldFZpZGVvVHJhY2tzKClbMF0uaWQpO1xuXG4gICAgICAgICAgICBzZWxmLmxvY2FsU3RyZWFtLmFkZFRyYWNrKGxxU3RyZWFtLmdldFZpZGVvVHJhY2tzKClbMF0pO1xuICAgICAgICAgICAgc3VjY2VzcyhzZWxmLmxvY2FsU3RyZWFtKTtcbiAgICAgICAgfSwgZXJyKTtcbiAgICB9LCBlcnIpO1xufTtcblxuLyoqXG4gKiBQcmVwYXJlcyB0aGUgbG9jYWwgZGVzY3JpcHRpb24gZm9yIHB1YmxpYyB1c2FnZSAoaS5lLiB0byBiZSBzaWduYWxlZFxuICogdGhyb3VnaCBKaW5nbGUgdG8gdGhlIGZvY3VzKS5cbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMge1JUQ1Nlc3Npb25EZXNjcmlwdGlvbn1cbiAqL1xuU2ltcGxlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5yZXZlcnNlVHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgdmFyIHNiO1xuXG4gICAgaWYgKCF0aGlzLnNpbXVsY2FzdFV0aWxzLmlzVmFsaWREZXNjcmlwdGlvbihkZXNjKSkge1xuICAgICAgICByZXR1cm4gZGVzYztcbiAgICB9XG5cbiAgICBzYiA9IGRlc2Muc2RwLnNwbGl0KCdcXHJcXG4nKTtcblxuICAgIHRoaXMuX2dyb3VwTG9jYWxWaWRlb1NvdXJjZXMoc2IpO1xuXG4gICAgZGVzYyA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgICB0eXBlOiBkZXNjLnR5cGUsXG4gICAgICAgIHNkcDogc2Iuam9pbignXFxyXFxuJylcbiAgICB9KTtcblxuICAgIHRoaXMubG9nZ2VyLmZpbmUoJ0dyb3VwZWQgbG9jYWwgdmlkZW8gc291cmNlcycpO1xuICAgIHRoaXMubG9nZ2VyLmZpbmUoZGVzYy5zZHApO1xuXG4gICAgcmV0dXJuIGRlc2M7XG59O1xuXG4vKipcbiAqIEVuc3VyZXMgdGhhdCB0aGUgc2ltdWxjYXN0IGdyb3VwIGlzIHByZXNlbnQgaW4gdGhlIGFuc3dlciwgX2lmXyBuYXRpdmVcbiAqIHNpbXVsY2FzdCBpcyBlbmFibGVkLFxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuU2ltcGxlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS50cmFuc2Zvcm1BbnN3ZXIgPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHJldHVybiBkZXNjO1xufTtcblxuXG4vKipcbiAqXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW1wbGVTaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLnRyYW5zZm9ybUxvY2FsRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuXG4gICAgdmFyIHNiID0gZGVzYy5zZHAuc3BsaXQoJ1xcclxcbicpO1xuXG4gICAgdGhpcy5zaW11bGNhc3RVdGlscy5fcmVtb3ZlU2ltdWxjYXN0R3JvdXAoc2IpO1xuXG4gICAgZGVzYyA9IG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe1xuICAgICAgICB0eXBlOiBkZXNjLnR5cGUsXG4gICAgICAgIHNkcDogc2Iuam9pbignXFxyXFxuJylcbiAgICB9KTtcblxuICAgIHRoaXMubG9nZ2VyLmZpbmUoJ1RyYW5zZm9ybWVkIGxvY2FsIGRlc2NyaXB0aW9uJyk7XG4gICAgdGhpcy5sb2dnZXIuZmluZShkZXNjLnNkcCk7XG5cbiAgICByZXR1cm4gZGVzYztcbn07XG5cblNpbXBsZVNpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuX3NldExvY2FsVmlkZW9TdHJlYW1FbmFibGVkID0gZnVuY3Rpb24gKHNzcmMsIGVuYWJsZWQpIHtcbiAgICB2YXIgdHJhY2tpZDtcblxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLmxvZ2dlci5sb2coWydSZXF1ZXN0ZWQgdG8nLCBlbmFibGVkID8gJ2VuYWJsZScgOiAnZGlzYWJsZScsIHNzcmNdLmpvaW4oJyAnKSk7XG4gICAgaWYgKE9iamVjdC5rZXlzKHRoaXMuX2xvY2FsTWFwcy5tc2lkMnNzcmMpLnNvbWUoZnVuY3Rpb24gKHRpZCkge1xuICAgICAgICAvLyBTZWFyY2ggZm9yIHRoZSB0cmFjayBpZCB0aGF0IGNvcnJlc3BvbmRzIHRvIHRoZSBzc3JjXG4gICAgICAgIGlmIChzZWxmLl9sb2NhbE1hcHMubXNpZDJzc3JjW3RpZF0gPT0gc3NyYykge1xuICAgICAgICAgICAgdHJhY2tpZCA9IHRpZDtcbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9XG4gICAgfSkgJiYgc2VsZi5sb2NhbFN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLnNvbWUoZnVuY3Rpb24gKHRyYWNrKSB7XG4gICAgICAgIC8vIFN0YXJ0L3N0b3AgdGhlIHRyYWNrIHRoYXQgY29ycmVzcG9uZHMgdG8gdGhlIHRyYWNrIGlkXG4gICAgICAgIGlmICh0cmFjay5pZCA9PT0gdHJhY2tpZCkge1xuICAgICAgICAgICAgdHJhY2suZW5hYmxlZCA9IGVuYWJsZWQ7XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH0pKSB7XG4gICAgICAgIHRoaXMubG9nZ2VyLmxvZyhbdHJhY2tpZCwgZW5hYmxlZCA/ICdlbmFibGVkJyA6ICdkaXNhYmxlZCddLmpvaW4oJyAnKSk7XG4gICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoZW5hYmxlZFxuICAgICAgICAgICAgPyAnc2ltdWxjYXN0bGF5ZXJzdGFydGVkJ1xuICAgICAgICAgICAgOiAnc2ltdWxjYXN0bGF5ZXJzdG9wcGVkJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5sb2dnZXIuZXJyb3IoXCJJIGRvbid0IGhhdmUgYSBsb2NhbCBzdHJlYW0gd2l0aCBTU1JDIFwiICsgc3NyYyk7XG4gICAgfVxufTtcblxuU2ltcGxlU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5jb25zdHJ1Y3RvciA9IFNpbXBsZVNpbXVsY2FzdFNlbmRlcjtcblxuZnVuY3Rpb24gTm9TaW11bGNhc3RTZW5kZXIoKSB7XG4gICAgU2ltdWxjYXN0U2VuZGVyLmNhbGwodGhpcyk7XG59XG5cbk5vU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUoU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZSk7XG5cbi8qKlxuICogR1VNIGZvciBzaW11bGNhc3QuXG4gKlxuICogQHBhcmFtIGNvbnN0cmFpbnRzXG4gKiBAcGFyYW0gc3VjY2Vzc1xuICogQHBhcmFtIGVyclxuICovXG5Ob1NpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuZ2V0VXNlck1lZGlhID0gZnVuY3Rpb24gKGNvbnN0cmFpbnRzLCBzdWNjZXNzLCBlcnIpIHtcbiAgICBuYXZpZ2F0b3Iud2Via2l0R2V0VXNlck1lZGlhKGNvbnN0cmFpbnRzLCBmdW5jdGlvbiAoaHFTdHJlYW0pIHtcbiAgICAgICAgc3VjY2VzcyhocVN0cmVhbSk7XG4gICAgfSwgZXJyKTtcbn07XG5cbi8qKlxuICogUHJlcGFyZXMgdGhlIGxvY2FsIGRlc2NyaXB0aW9uIGZvciBwdWJsaWMgdXNhZ2UgKGkuZS4gdG8gYmUgc2lnbmFsZWRcbiAqIHRocm91Z2ggSmluZ2xlIHRvIHRoZSBmb2N1cykuXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHtSVENTZXNzaW9uRGVzY3JpcHRpb259XG4gKi9cbk5vU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5yZXZlcnNlVHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgcmV0dXJuIGRlc2M7XG59O1xuXG4vKipcbiAqIEVuc3VyZXMgdGhhdCB0aGUgc2ltdWxjYXN0IGdyb3VwIGlzIHByZXNlbnQgaW4gdGhlIGFuc3dlciwgX2lmXyBuYXRpdmVcbiAqIHNpbXVsY2FzdCBpcyBlbmFibGVkLFxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7Kn1cbiAqL1xuTm9TaW11bGNhc3RTZW5kZXIucHJvdG90eXBlLnRyYW5zZm9ybUFuc3dlciA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgcmV0dXJuIGRlc2M7XG59O1xuXG5cbi8qKlxuICpcbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cbk5vU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS50cmFuc2Zvcm1Mb2NhbERlc2NyaXB0aW9uID0gZnVuY3Rpb24gKGRlc2MpIHtcbiAgICByZXR1cm4gZGVzYztcbn07XG5cbk5vU2ltdWxjYXN0U2VuZGVyLnByb3RvdHlwZS5fc2V0TG9jYWxWaWRlb1N0cmVhbUVuYWJsZWQgPSBmdW5jdGlvbiAoc3NyYywgZW5hYmxlZCkge1xuXG59O1xuXG5Ob1NpbXVsY2FzdFNlbmRlci5wcm90b3R5cGUuY29uc3RydWN0b3IgPSBOb1NpbXVsY2FzdFNlbmRlcjtcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgXCJuYXRpdmVcIjogTmF0aXZlU2ltdWxjYXN0U2VuZGVyLFxuICAgIFwibm9cIjogTm9TaW11bGNhc3RTZW5kZXJcbn1cbiIsInZhciBTaW11bGNhc3RMb2dnZXIgPSByZXF1aXJlKFwiLi9TaW11bGNhc3RMb2dnZXJcIik7XG5cbi8qKlxuICpcbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBTaW11bGNhc3RVdGlscygpIHtcbiAgICB0aGlzLmxvZ2dlciA9IG5ldyBTaW11bGNhc3RMb2dnZXIoXCJTaW11bGNhc3RVdGlsc1wiLCAxKTtcbn1cblxuLyoqXG4gKlxuICogQHR5cGUge3t9fVxuICogQHByaXZhdGVcbiAqL1xuU2ltdWxjYXN0VXRpbHMucHJvdG90eXBlLl9lbXB0eUNvbXBvdW5kSW5kZXggPSB7fTtcblxuLyoqXG4gKlxuICogQHBhcmFtIGxpbmVzXG4gKiBAcGFyYW0gdmlkZW9Tb3VyY2VzXG4gKiBAcHJpdmF0ZVxuICovXG5TaW11bGNhc3RVdGlscy5wcm90b3R5cGUuX3JlcGxhY2VWaWRlb1NvdXJjZXMgPSBmdW5jdGlvbiAobGluZXMsIHZpZGVvU291cmNlcykge1xuICAgIHZhciBpLCBpblZpZGVvID0gZmFsc2UsIGluZGV4ID0gLTEsIGhvd01hbnkgPSAwO1xuXG4gICAgdGhpcy5sb2dnZXIuaW5mbygnUmVwbGFjaW5nIHZpZGVvIHNvdXJjZXMuLi4nKTtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICBpZiAoaW5WaWRlbyAmJiBsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ209Jy5sZW5ndGgpID09PSAnbT0nKSB7XG4gICAgICAgICAgICAvLyBPdXQgb2YgdmlkZW8uXG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuXG4gICAgICAgIGlmICghaW5WaWRlbyAmJiBsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ209dmlkZW8gJy5sZW5ndGgpID09PSAnbT12aWRlbyAnKSB7XG4gICAgICAgICAgICAvLyBJbiB2aWRlby5cbiAgICAgICAgICAgIGluVmlkZW8gPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGluVmlkZW8gJiYgKGxpbmVzW2ldLnN1YnN0cmluZygwLCAnYT1zc3JjOicubGVuZ3RoKSA9PT0gJ2E9c3NyYzonXG4gICAgICAgICAgICB8fCBsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ2E9c3NyYy1ncm91cDonLmxlbmd0aCkgPT09ICdhPXNzcmMtZ3JvdXA6JykpIHtcblxuICAgICAgICAgICAgaWYgKGluZGV4ID09PSAtMSkge1xuICAgICAgICAgICAgICAgIGluZGV4ID0gaTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaG93TWFueSsrO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy8gIGVmZmljaWVuY3kgYmFieSA7KVxuICAgIGxpbmVzLnNwbGljZS5hcHBseShsaW5lcyxcbiAgICAgICAgW2luZGV4LCBob3dNYW55XS5jb25jYXQodmlkZW9Tb3VyY2VzKSk7XG5cbn07XG5cblNpbXVsY2FzdFV0aWxzLnByb3RvdHlwZS5pc1ZhbGlkRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYylcbntcbiAgICByZXR1cm4gZGVzYyAmJiBkZXNjICE9IG51bGxcbiAgICAgICAgJiYgZGVzYy50eXBlICYmIGRlc2MudHlwZSAhPSAnJ1xuICAgICAgICAmJiBkZXNjLnNkcCAmJiBkZXNjLnNkcCAhPSAnJztcbn07XG5cblNpbXVsY2FzdFV0aWxzLnByb3RvdHlwZS5fZ2V0VmlkZW9Tb3VyY2VzID0gZnVuY3Rpb24gKGxpbmVzKSB7XG4gICAgdmFyIGksIGluVmlkZW8gPSBmYWxzZSwgc2IgPSBbXTtcblxuICAgIHRoaXMubG9nZ2VyLmluZm8oJ0dldHRpbmcgdmlkZW8gc291cmNlcy4uLicpO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChpblZpZGVvICYmIGxpbmVzW2ldLnN1YnN0cmluZygwLCAnbT0nLmxlbmd0aCkgPT09ICdtPScpIHtcbiAgICAgICAgICAgIC8vIE91dCBvZiB2aWRlby5cbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKCFpblZpZGVvICYmIGxpbmVzW2ldLnN1YnN0cmluZygwLCAnbT12aWRlbyAnLmxlbmd0aCkgPT09ICdtPXZpZGVvICcpIHtcbiAgICAgICAgICAgIC8vIEluIHZpZGVvLlxuICAgICAgICAgICAgaW5WaWRlbyA9IHRydWU7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAoaW5WaWRlbyAmJiBsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ2E9c3NyYzonLmxlbmd0aCkgPT09ICdhPXNzcmM6Jykge1xuICAgICAgICAgICAgLy8gSW4gU1NSQy5cbiAgICAgICAgICAgIHNiLnB1c2gobGluZXNbaV0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKGluVmlkZW8gJiYgbGluZXNbaV0uc3Vic3RyaW5nKDAsICdhPXNzcmMtZ3JvdXA6Jy5sZW5ndGgpID09PSAnYT1zc3JjLWdyb3VwOicpIHtcbiAgICAgICAgICAgIHNiLnB1c2gobGluZXNbaV0pO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHNiO1xufTtcblxuU2ltdWxjYXN0VXRpbHMucHJvdG90eXBlLnBhcnNlTWVkaWEgPSBmdW5jdGlvbiAobGluZXMsIG1lZGlhdHlwZXMpIHtcbiAgICB2YXIgaSwgcmVzID0gW10sIHR5cGUsIGN1cl9tZWRpYSwgaWR4LCBzc3JjcywgY3VyX3NzcmMsIHNzcmMsXG4gICAgICAgIHNzcmNfYXR0cmlidXRlLCBncm91cCwgc2VtYW50aWNzLCBza2lwID0gdHJ1ZTtcblxuICAgIHRoaXMubG9nZ2VyLmluZm8oJ1BhcnNpbmcgbWVkaWEgc291cmNlcy4uLicpO1xuXG4gICAgZm9yIChpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ209Jy5sZW5ndGgpID09PSAnbT0nKSB7XG5cbiAgICAgICAgICAgIHR5cGUgPSBsaW5lc1tpXVxuICAgICAgICAgICAgICAgIC5zdWJzdHIoJ209Jy5sZW5ndGgsIGxpbmVzW2ldLmluZGV4T2YoJyAnKSAtICdtPScubGVuZ3RoKTtcbiAgICAgICAgICAgIHNraXAgPSBtZWRpYXR5cGVzICE9PSB1bmRlZmluZWQgJiYgbWVkaWF0eXBlcy5pbmRleE9mKHR5cGUpID09PSAtMTtcblxuICAgICAgICAgICAgaWYgKCFza2lwKSB7XG4gICAgICAgICAgICAgICAgY3VyX21lZGlhID0ge1xuICAgICAgICAgICAgICAgICAgICAndHlwZSc6IHR5cGUsXG4gICAgICAgICAgICAgICAgICAgICdzb3VyY2VzJzoge30sXG4gICAgICAgICAgICAgICAgICAgICdncm91cHMnOiBbXVxuICAgICAgICAgICAgICAgIH07XG5cbiAgICAgICAgICAgICAgICByZXMucHVzaChjdXJfbWVkaWEpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH0gZWxzZSBpZiAoIXNraXAgJiYgbGluZXNbaV0uc3Vic3RyaW5nKDAsICdhPXNzcmM6Jy5sZW5ndGgpID09PSAnYT1zc3JjOicpIHtcblxuICAgICAgICAgICAgaWR4ID0gbGluZXNbaV0uaW5kZXhPZignICcpO1xuICAgICAgICAgICAgc3NyYyA9IGxpbmVzW2ldLnN1YnN0cmluZygnYT1zc3JjOicubGVuZ3RoLCBpZHgpO1xuICAgICAgICAgICAgaWYgKGN1cl9tZWRpYS5zb3VyY2VzW3NzcmNdID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBjdXJfc3NyYyA9IHsnc3NyYyc6IHNzcmN9O1xuICAgICAgICAgICAgICAgIGN1cl9tZWRpYS5zb3VyY2VzW3NzcmNdID0gY3VyX3NzcmM7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNzcmNfYXR0cmlidXRlID0gbGluZXNbaV0uc3Vic3RyKGlkeCArIDEpLnNwbGl0KCc6JywgMilbMF07XG4gICAgICAgICAgICBjdXJfc3NyY1tzc3JjX2F0dHJpYnV0ZV0gPSBsaW5lc1tpXS5zdWJzdHIoaWR4ICsgMSkuc3BsaXQoJzonLCAyKVsxXTtcblxuICAgICAgICAgICAgaWYgKGN1cl9tZWRpYS5iYXNlID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICBjdXJfbWVkaWEuYmFzZSA9IGN1cl9zc3JjO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgIH0gZWxzZSBpZiAoIXNraXAgJiYgbGluZXNbaV0uc3Vic3RyaW5nKDAsICdhPXNzcmMtZ3JvdXA6Jy5sZW5ndGgpID09PSAnYT1zc3JjLWdyb3VwOicpIHtcbiAgICAgICAgICAgIGlkeCA9IGxpbmVzW2ldLmluZGV4T2YoJyAnKTtcbiAgICAgICAgICAgIHNlbWFudGljcyA9IGxpbmVzW2ldLnN1YnN0cigwLCBpZHgpLnN1YnN0cignYT1zc3JjLWdyb3VwOicubGVuZ3RoKTtcbiAgICAgICAgICAgIHNzcmNzID0gbGluZXNbaV0uc3Vic3RyKGlkeCkudHJpbSgpLnNwbGl0KCcgJyk7XG4gICAgICAgICAgICBncm91cCA9IHtcbiAgICAgICAgICAgICAgICAnc2VtYW50aWNzJzogc2VtYW50aWNzLFxuICAgICAgICAgICAgICAgICdzc3Jjcyc6IHNzcmNzXG4gICAgICAgICAgICB9O1xuICAgICAgICAgICAgY3VyX21lZGlhLmdyb3Vwcy5wdXNoKGdyb3VwKTtcbiAgICAgICAgfSBlbHNlIGlmICghc2tpcCAmJiAobGluZXNbaV0uc3Vic3RyaW5nKDAsICdhPXNlbmRyZWN2Jy5sZW5ndGgpID09PSAnYT1zZW5kcmVjdicgfHxcbiAgICAgICAgICAgIGxpbmVzW2ldLnN1YnN0cmluZygwLCAnYT1yZWN2b25seScubGVuZ3RoKSA9PT0gJ2E9cmVjdm9ubHknIHx8XG4gICAgICAgICAgICBsaW5lc1tpXS5zdWJzdHJpbmcoMCwgJ2E9c2VuZG9ubHknLmxlbmd0aCkgPT09ICdhPXNlbmRvbmx5JyB8fFxuICAgICAgICAgICAgbGluZXNbaV0uc3Vic3RyaW5nKDAsICdhPWluYWN0aXZlJy5sZW5ndGgpID09PSAnYT1pbmFjdGl2ZScpKSB7XG5cbiAgICAgICAgICAgIGN1cl9tZWRpYS5kaXJlY3Rpb24gPSBsaW5lc1tpXS5zdWJzdHJpbmcoJ2E9Jy5sZW5ndGgpO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlcztcbn07XG5cbi8qKlxuICogVGhlIF9pbmRleE9mQXJyYXkoKSBtZXRob2QgcmV0dXJucyB0aGUgZmlyc3QgYSBDb21wb3VuZEluZGV4IGF0IHdoaWNoIGFcbiAqIGdpdmVuIGVsZW1lbnQgY2FuIGJlIGZvdW5kIGluIHRoZSBhcnJheSwgb3IgX2VtcHR5Q29tcG91bmRJbmRleCBpZiBpdCBpc1xuICogbm90IHByZXNlbnQuXG4gKlxuICogRXhhbXBsZTpcbiAqXG4gKiBfaW5kZXhPZkFycmF5KCczJywgWyAndGhpcyBpcyBsaW5lIDEnLCAndGhpcyBpcyBsaW5lIDInLCAndGhpcyBpcyBsaW5lIDMnIF0pXG4gKlxuICogcmV0dXJucyB7cm93OiAyLCBjb2x1bW46IDE0fVxuICpcbiAqIEBwYXJhbSBuZWVkbGVcbiAqIEBwYXJhbSBoYXlzdGFja1xuICogQHBhcmFtIHN0YXJ0XG4gKiBAcmV0dXJucyB7fVxuICogQHByaXZhdGVcbiAqL1xuU2ltdWxjYXN0VXRpbHMucHJvdG90eXBlLl9pbmRleE9mQXJyYXkgPSBmdW5jdGlvbiAobmVlZGxlLCBoYXlzdGFjaywgc3RhcnQpIHtcbiAgICB2YXIgbGVuZ3RoID0gaGF5c3RhY2subGVuZ3RoLCBpZHgsIGk7XG5cbiAgICBpZiAoIXN0YXJ0KSB7XG4gICAgICAgIHN0YXJ0ID0gMDtcbiAgICB9XG5cbiAgICBmb3IgKGkgPSBzdGFydDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlkeCA9IGhheXN0YWNrW2ldLmluZGV4T2YobmVlZGxlKTtcbiAgICAgICAgaWYgKGlkeCAhPT0gLTEpIHtcbiAgICAgICAgICAgIHJldHVybiB7cm93OiBpLCBjb2x1bW46IGlkeH07XG4gICAgICAgIH1cbiAgICB9XG4gICAgcmV0dXJuIHRoaXMuX2VtcHR5Q29tcG91bmRJbmRleDtcbn07XG5cblNpbXVsY2FzdFV0aWxzLnByb3RvdHlwZS5fcmVtb3ZlU2ltdWxjYXN0R3JvdXAgPSBmdW5jdGlvbiAobGluZXMpIHtcbiAgICB2YXIgaTtcblxuICAgIGZvciAoaSA9IGxpbmVzLmxlbmd0aCAtIDE7IGkgPj0gMDsgaS0tKSB7XG4gICAgICAgIGlmIChsaW5lc1tpXS5pbmRleE9mKCdhPXNzcmMtZ3JvdXA6U0lNJykgIT09IC0xKSB7XG4gICAgICAgICAgICBsaW5lcy5zcGxpY2UoaSwgMSk7XG4gICAgICAgIH1cbiAgICB9XG59O1xuXG5TaW11bGNhc3RVdGlscy5wcm90b3R5cGUuX2NvbXBpbGVWaWRlb1NvdXJjZXMgPSBmdW5jdGlvbiAodmlkZW9Tb3VyY2VzKSB7XG4gICAgdmFyIHNiID0gW10sIHNzcmMsIGFkZGVkU1NSQ3MgPSBbXTtcblxuICAgIHRoaXMubG9nZ2VyLmluZm8oJ0NvbXBpbGluZyB2aWRlbyBzb3VyY2VzLi4uJyk7XG5cbiAgICAvLyBBZGQgdGhlIGdyb3Vwc1xuICAgIGlmICh2aWRlb1NvdXJjZXMuZ3JvdXBzICYmIHZpZGVvU291cmNlcy5ncm91cHMubGVuZ3RoICE9PSAwKSB7XG4gICAgICAgIHZpZGVvU291cmNlcy5ncm91cHMuZm9yRWFjaChmdW5jdGlvbiAoZ3JvdXApIHtcbiAgICAgICAgICAgIGlmIChncm91cC5zc3JjcyAmJiBncm91cC5zc3Jjcy5sZW5ndGggIT09IDApIHtcbiAgICAgICAgICAgICAgICBzYi5wdXNoKFtbJ2E9c3NyYy1ncm91cDonLCBncm91cC5zZW1hbnRpY3NdLmpvaW4oJycpLCBncm91cC5zc3Jjcy5qb2luKCcgJyldLmpvaW4oJyAnKSk7XG5cbiAgICAgICAgICAgICAgICAvLyBpZiAoZ3JvdXAuc2VtYW50aWNzICE9PSAnU0lNJykge1xuICAgICAgICAgICAgICAgIGdyb3VwLnNzcmNzLmZvckVhY2goZnVuY3Rpb24gKHNzcmMpIHtcbiAgICAgICAgICAgICAgICAgICAgYWRkZWRTU1JDcy5wdXNoKHNzcmMpO1xuICAgICAgICAgICAgICAgICAgICBzYi5zcGxpY2UuYXBwbHkoc2IsIFtzYi5sZW5ndGgsIDBdLmNvbmNhdChbXG4gICAgICAgICAgICAgICAgICAgICAgICBbXCJhPXNzcmM6XCIsIHNzcmMsIFwiIGNuYW1lOlwiLCB2aWRlb1NvdXJjZXMuc291cmNlc1tzc3JjXS5jbmFtZV0uam9pbignJyksXG4gICAgICAgICAgICAgICAgICAgICAgICBbXCJhPXNzcmM6XCIsIHNzcmMsIFwiIG1zaWQ6XCIsIHZpZGVvU291cmNlcy5zb3VyY2VzW3NzcmNdLm1zaWRdLmpvaW4oJycpXSkpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIC8vfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICAvLyBUaGVuIGFkZCBhbnkgZnJlZSBzb3VyY2VzLlxuICAgIGlmICh2aWRlb1NvdXJjZXMuc291cmNlcykge1xuICAgICAgICBmb3IgKHNzcmMgaW4gdmlkZW9Tb3VyY2VzLnNvdXJjZXMpIHtcbiAgICAgICAgICAgIGlmIChhZGRlZFNTUkNzLmluZGV4T2Yoc3NyYykgPT09IC0xKSB7XG4gICAgICAgICAgICAgICAgc2Iuc3BsaWNlLmFwcGx5KHNiLCBbc2IubGVuZ3RoLCAwXS5jb25jYXQoW1xuICAgICAgICAgICAgICAgICAgICBbXCJhPXNzcmM6XCIsIHNzcmMsIFwiIGNuYW1lOlwiLCB2aWRlb1NvdXJjZXMuc291cmNlc1tzc3JjXS5jbmFtZV0uam9pbignJyksXG4gICAgICAgICAgICAgICAgICAgIFtcImE9c3NyYzpcIiwgc3NyYywgXCIgbXNpZDpcIiwgdmlkZW9Tb3VyY2VzLnNvdXJjZXNbc3NyY10ubXNpZF0uam9pbignJyldKSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4gc2I7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNpbXVsY2FzdFV0aWxzOyIsIi8qanNsaW50IHBsdXNwbHVzOiB0cnVlICovXG4vKmpzbGludCBub21lbjogdHJ1ZSovXG5cbnZhciBTaW11bGNhc3RTZW5kZXIgPSByZXF1aXJlKFwiLi9TaW11bGNhc3RTZW5kZXJcIik7XG52YXIgTm9TaW11bGNhc3RTZW5kZXIgPSBTaW11bGNhc3RTZW5kZXJbXCJub1wiXTtcbnZhciBOYXRpdmVTaW11bGNhc3RTZW5kZXIgPSBTaW11bGNhc3RTZW5kZXJbXCJuYXRpdmVcIl07XG52YXIgU2ltdWxjYXN0UmVjZWl2ZXIgPSByZXF1aXJlKFwiLi9TaW11bGNhc3RSZWNlaXZlclwiKTtcbnZhciBTaW11bGNhc3RVdGlscyA9IHJlcXVpcmUoXCIuL1NpbXVsY2FzdFV0aWxzXCIpO1xudmFyIFJUQ0V2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9SVENFdmVudHNcIik7XG5cblxuLyoqXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIFNpbXVsY2FzdE1hbmFnZXIoKSB7XG5cbiAgICAvLyBDcmVhdGUgdGhlIHNpbXVsY2FzdCB1dGlsaXRpZXMuXG4gICAgdGhpcy5zaW11bGNhc3RVdGlscyA9IG5ldyBTaW11bGNhc3RVdGlscygpO1xuXG4gICAgLy8gQ3JlYXRlIHJlbW90ZSBzaW11bGNhc3QuXG4gICAgdGhpcy5zaW11bGNhc3RSZWNlaXZlciA9IG5ldyBTaW11bGNhc3RSZWNlaXZlcigpO1xuXG4gICAgLy8gSW5pdGlhbGl6ZSBsb2NhbCBzaW11bGNhc3QuXG5cbiAgICAvLyBUT0RPKGdwKSBtb3ZlIGludG8gU2ltdWxjYXN0TWFuYWdlci5wcm90b3R5cGUuZ2V0VXNlck1lZGlhIGFuZCB0YWtlIGludG9cbiAgICAvLyBhY2NvdW50IGNvbnN0cmFpbnRzLlxuICAgIGlmICghY29uZmlnLmVuYWJsZVNpbXVsY2FzdCkge1xuICAgICAgICB0aGlzLnNpbXVsY2FzdFNlbmRlciA9IG5ldyBOb1NpbXVsY2FzdFNlbmRlcigpO1xuICAgIH0gZWxzZSB7XG5cbiAgICAgICAgdmFyIGlzQ2hyb21pdW0gPSB3aW5kb3cuY2hyb21lLFxuICAgICAgICAgICAgdmVuZG9yTmFtZSA9IHdpbmRvdy5uYXZpZ2F0b3IudmVuZG9yO1xuICAgICAgICBpZihpc0Nocm9taXVtICE9PSBudWxsICYmIGlzQ2hyb21pdW0gIT09IHVuZGVmaW5lZFxuICAgICAgICAgICAgLyogc2tpcCBvcGVyYSAqL1xuICAgICAgICAgICAgJiYgdmVuZG9yTmFtZSA9PT0gXCJHb29nbGUgSW5jLlwiXG4gICAgICAgICAgICAvKiBza2lwIENocm9taXVtIGFzIHN1Z2dlc3RlZCBieSBmaXBwbyAqL1xuICAgICAgICAgICAgJiYgIXdpbmRvdy5uYXZpZ2F0b3IuYXBwVmVyc2lvbi5tYXRjaCgvQ2hyb21pdW1cXC8vKSApIHtcbiAgICAgICAgICAgIHZhciB2ZXIgPSBwYXJzZUludCh3aW5kb3cubmF2aWdhdG9yLmFwcFZlcnNpb24ubWF0Y2goL0Nocm9tZVxcLyhcXGQrKVxcLi8pWzFdLCAxMCk7XG4gICAgICAgICAgICBpZiAodmVyID4gMzcpIHtcbiAgICAgICAgICAgICAgICB0aGlzLnNpbXVsY2FzdFNlbmRlciA9IG5ldyBOYXRpdmVTaW11bGNhc3RTZW5kZXIoKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgdGhpcy5zaW11bGNhc3RTZW5kZXIgPSBuZXcgTm9TaW11bGNhc3RTZW5kZXIoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIHRoaXMuc2ltdWxjYXN0U2VuZGVyID0gbmV3IE5vU2ltdWxjYXN0U2VuZGVyKCk7XG4gICAgICAgIH1cblxuICAgIH1cbiAgICBBUFAuUlRDLmFkZExpc3RlbmVyKFJUQ0V2ZW50cy5TSU1VTENBU1RfTEFZRVJfQ0hBTkdFRCxcbiAgICAgICAgZnVuY3Rpb24gKGVuZHBvaW50U2ltdWxjYXN0TGF5ZXJzKSB7XG4gICAgICAgICAgICBlbmRwb2ludFNpbXVsY2FzdExheWVycy5mb3JFYWNoKGZ1bmN0aW9uIChlc2wpIHtcbiAgICAgICAgICAgICAgICB2YXIgc3NyYyA9IGVzbC5zaW11bGNhc3RMYXllci5wcmltYXJ5U1NSQztcbiAgICAgICAgICAgICAgICBzaW11bGNhc3QuX3NldFJlY2VpdmluZ1ZpZGVvU3RyZWFtKGVzbC5lbmRwb2ludCwgc3NyYyk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgQVBQLlJUQy5hZGRMaXN0ZW5lcihSVENFdmVudHMuU0lNVUxDQVNUX1NUQVJULCBmdW5jdGlvbiAoc2ltdWxjYXN0TGF5ZXIpIHtcbiAgICAgICAgdmFyIHNzcmMgPSBzaW11bGNhc3RMYXllci5wcmltYXJ5U1NSQztcbiAgICAgICAgc2ltdWxjYXN0Ll9zZXRMb2NhbFZpZGVvU3RyZWFtRW5hYmxlZChzc3JjLCB0cnVlKTtcbiAgICB9KTtcbiAgICBBUFAuUlRDLmFkZExpc3RlbmVyKFJUQ0V2ZW50cy5TSU1VTENBU1RfU1RPUCwgZnVuY3Rpb24gKHNpbXVsY2FzdExheWVyKSB7XG4gICAgICAgIHZhciBzc3JjID0gc2ltdWxjYXN0TGF5ZXIucHJpbWFyeVNTUkM7XG4gICAgICAgIHNpbXVsY2FzdC5fc2V0TG9jYWxWaWRlb1N0cmVhbUVuYWJsZWQoc3NyYywgZmFsc2UpO1xuICAgIH0pO1xuXG59XG5cbi8qKlxuICogUmVzdG9yZXMgdGhlIHNpbXVsY2FzdCBncm91cHMgb2YgdGhlIHJlbW90ZSBkZXNjcmlwdGlvbi4gSW5cbiAqIHRyYW5zZm9ybVJlbW90ZURlc2NyaXB0aW9uIHdlIHJlbW92ZSB0aG9zZSBpbiBvcmRlciBmb3IgdGhlIHNldCByZW1vdGVcbiAqIGRlc2NyaXB0aW9uIHRvIHN1Y2NlZWQuIFRoZSBmb2N1cyBuZWVkcyB0aGUgc2lnbmFsIHRoZSBncm91cHMgdG8gbmV3XG4gKiBwYXJ0aWNpcGFudHMuXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5yZXZlcnNlVHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHJldHVybiB0aGlzLnNpbXVsY2FzdFJlY2VpdmVyLnJldmVyc2VUcmFuc2Zvcm1SZW1vdGVEZXNjcmlwdGlvbihkZXNjKTtcbn07XG5cbi8qKlxuICogUmVtb3ZlcyB0aGUgc3NyYy1ncm91cDpTSU0gZnJvbSB0aGUgcmVtb3RlIGRlc2NyaXB0aW9uIGJhY2F1c2UgQ2hyb21lXG4gKiBlaXRoZXIgZ2V0cyBjb25mdXNlZCBhbmQgdGhpbmtzIHRoaXMgaXMgYW4gRklEIGdyb3VwIG9yLCBpZiBhbiBGSUQgZ3JvdXBcbiAqIGlzIGFscmVhZHkgcHJlc2VudCwgaXQgZmFpbHMgdG8gc2V0IHRoZSByZW1vdGUgZGVzY3JpcHRpb24uXG4gKlxuICogQHBhcmFtIGRlc2NcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS50cmFuc2Zvcm1SZW1vdGVEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgcmV0dXJuIHRoaXMuc2ltdWxjYXN0UmVjZWl2ZXIudHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24oZGVzYyk7XG59O1xuXG4vKipcbiAqIEdldHMgdGhlIGZ1bGx5IHF1YWxpZmllZCBtc2lkIChzdHJlYW0uaWQgKyB0cmFjay5pZCkgYXNzb2NpYXRlZCB0byB0aGVcbiAqIFNTUkMuXG4gKlxuICogQHBhcmFtIHNzcmNcbiAqIEByZXR1cm5zIHsqfVxuICovXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5nZXRSZW1vdGVWaWRlb1N0cmVhbUlkQnlTU1JDID0gZnVuY3Rpb24gKHNzcmMpIHtcbiAgICByZXR1cm4gdGhpcy5zaW11bGNhc3RSZWNlaXZlci5nZXRSZW1vdGVWaWRlb1N0cmVhbUlkQnlTU1JDKHNzcmMpO1xufTtcblxuLyoqXG4gKiBSZXR1cm5zIGEgc3RyZWFtIHdpdGggc2luZ2xlIHZpZGVvIHRyYWNrLCB0aGUgb25lIGN1cnJlbnRseSBiZWluZ1xuICogcmVjZWl2ZWQgYnkgdGhpcyBlbmRwb2ludC5cbiAqXG4gKiBAcGFyYW0gc3RyZWFtIHRoZSByZW1vdGUgc2ltdWxjYXN0IHN0cmVhbS5cbiAqIEByZXR1cm5zIHt3ZWJraXRNZWRpYVN0cmVhbX1cbiAqL1xuU2ltdWxjYXN0TWFuYWdlci5wcm90b3R5cGUuZ2V0UmVjZWl2aW5nVmlkZW9TdHJlYW0gPSBmdW5jdGlvbiAoc3RyZWFtKSB7XG4gICAgcmV0dXJuIHRoaXMuc2ltdWxjYXN0UmVjZWl2ZXIuZ2V0UmVjZWl2aW5nVmlkZW9TdHJlYW0oc3RyZWFtKTtcbn07XG5cbi8qKlxuICpcbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cblNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLnRyYW5zZm9ybUxvY2FsRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzYykge1xuICAgIHJldHVybiB0aGlzLnNpbXVsY2FzdFNlbmRlci50cmFuc2Zvcm1Mb2NhbERlc2NyaXB0aW9uKGRlc2MpO1xufTtcblxuLyoqXG4gKlxuICogQHJldHVybnMgeyp9XG4gKi9cblNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLmdldExvY2FsVmlkZW9TdHJlYW0gPSBmdW5jdGlvbigpIHtcbiAgICByZXR1cm4gdGhpcy5zaW11bGNhc3RTZW5kZXIuZ2V0TG9jYWxWaWRlb1N0cmVhbSgpO1xufTtcblxuLyoqXG4gKiBHVU0gZm9yIHNpbXVsY2FzdC5cbiAqXG4gKiBAcGFyYW0gY29uc3RyYWludHNcbiAqIEBwYXJhbSBzdWNjZXNzXG4gKiBAcGFyYW0gZXJyXG4gKi9cblNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLmdldFVzZXJNZWRpYSA9IGZ1bmN0aW9uIChjb25zdHJhaW50cywgc3VjY2VzcywgZXJyKSB7XG5cbiAgICB0aGlzLnNpbXVsY2FzdFNlbmRlci5nZXRVc2VyTWVkaWEoY29uc3RyYWludHMsIHN1Y2Nlc3MsIGVycik7XG59O1xuXG4vKipcbiAqIFByZXBhcmVzIHRoZSBsb2NhbCBkZXNjcmlwdGlvbiBmb3IgcHVibGljIHVzYWdlIChpLmUuIHRvIGJlIHNpZ25hbGVkXG4gKiB0aHJvdWdoIEppbmdsZSB0byB0aGUgZm9jdXMpLlxuICpcbiAqIEBwYXJhbSBkZXNjXG4gKiBAcmV0dXJucyB7UlRDU2Vzc2lvbkRlc2NyaXB0aW9ufVxuICovXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5yZXZlcnNlVHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgcmV0dXJuIHRoaXMuc2ltdWxjYXN0U2VuZGVyLnJldmVyc2VUcmFuc2Zvcm1Mb2NhbERlc2NyaXB0aW9uKGRlc2MpO1xufTtcblxuLyoqXG4gKiBFbnN1cmVzIHRoYXQgdGhlIHNpbXVsY2FzdCBncm91cCBpcyBwcmVzZW50IGluIHRoZSBhbnN3ZXIsIF9pZl8gbmF0aXZlXG4gKiBzaW11bGNhc3QgaXMgZW5hYmxlZCxcbiAqXG4gKiBAcGFyYW0gZGVzY1xuICogQHJldHVybnMgeyp9XG4gKi9cblNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLnRyYW5zZm9ybUFuc3dlciA9IGZ1bmN0aW9uIChkZXNjKSB7XG4gICAgcmV0dXJuIHRoaXMuc2ltdWxjYXN0U2VuZGVyLnRyYW5zZm9ybUFuc3dlcihkZXNjKTtcbn07XG5cblNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLmdldFJlY2VpdmluZ1NTUkMgPSBmdW5jdGlvbiAoamlkKSB7XG4gICAgcmV0dXJuIHRoaXMuc2ltdWxjYXN0UmVjZWl2ZXIuZ2V0UmVjZWl2aW5nU1NSQyhqaWQpO1xufTtcblxuU2ltdWxjYXN0TWFuYWdlci5wcm90b3R5cGUuZ2V0UmVjZWl2aW5nVmlkZW9TdHJlYW1CeVNTUkMgPSBmdW5jdGlvbiAobXNpZCkge1xuICAgIHJldHVybiB0aGlzLnNpbXVsY2FzdFJlY2VpdmVyLmdldFJlY2VpdmluZ1ZpZGVvU3RyZWFtQnlTU1JDKG1zaWQpO1xufTtcblxuLyoqXG4gKlxuICogQHBhcmFtIGxpbmVzXG4gKiBAcGFyYW0gbWVkaWF0eXBlc1xuICogQHJldHVybnMgeyp9XG4gKi9cblNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLnBhcnNlTWVkaWEgPSBmdW5jdGlvbihsaW5lcywgbWVkaWF0eXBlcykge1xuICAgIHZhciBzYiA9IGxpbmVzLnNkcC5zcGxpdCgnXFxyXFxuJyk7XG4gICAgcmV0dXJuIHRoaXMuc2ltdWxjYXN0VXRpbHMucGFyc2VNZWRpYShzYiwgbWVkaWF0eXBlcyk7XG59O1xuXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5fc2V0UmVjZWl2aW5nVmlkZW9TdHJlYW0gPSBmdW5jdGlvbihyZXNvdXJjZSwgc3NyYykge1xuICAgIHRoaXMuc2ltdWxjYXN0UmVjZWl2ZXIuX3NldFJlY2VpdmluZ1ZpZGVvU3RyZWFtKHJlc291cmNlLCBzc3JjKTtcbn07XG5cblNpbXVsY2FzdE1hbmFnZXIucHJvdG90eXBlLl9zZXRMb2NhbFZpZGVvU3RyZWFtRW5hYmxlZCA9IGZ1bmN0aW9uKHNzcmMsIGVuYWJsZWQpIHtcbiAgICB0aGlzLnNpbXVsY2FzdFNlbmRlci5fc2V0TG9jYWxWaWRlb1N0cmVhbUVuYWJsZWQoc3NyYywgZW5hYmxlZCk7XG59O1xuXG5TaW11bGNhc3RNYW5hZ2VyLnByb3RvdHlwZS5yZXNldFNlbmRlciA9IGZ1bmN0aW9uKCkge1xuICAgIGlmICh0eXBlb2YgdGhpcy5zaW11bGNhc3RTZW5kZXIucmVzZXQgPT09ICdmdW5jdGlvbicpe1xuICAgICAgICB0aGlzLnNpbXVsY2FzdFNlbmRlci5yZXNldCgpO1xuICAgIH1cbn07XG5cbnZhciBzaW11bGNhc3QgPSBuZXcgU2ltdWxjYXN0TWFuYWdlcigpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHNpbXVsY2FzdDsiLCIvKipcbiAqIFByb3ZpZGVzIHN0YXRpc3RpY3MgZm9yIHRoZSBsb2NhbCBzdHJlYW0uXG4gKi9cblxuXG4vKipcbiAqIFNpemUgb2YgdGhlIHdlYmF1ZGlvIGFuYWxpemVyIGJ1ZmZlci5cbiAqIEB0eXBlIHtudW1iZXJ9XG4gKi9cbnZhciBXRUJBVURJT19BTkFMSVpFUl9GRlRfU0laRSA9IDIwNDg7XG5cbi8qKlxuICogVmFsdWUgb2YgdGhlIHdlYmF1ZGlvIGFuYWxpemVyIHNtb290aGluZyB0aW1lIHBhcmFtZXRlci5cbiAqIEB0eXBlIHtudW1iZXJ9XG4gKi9cbnZhciBXRUJBVURJT19BTkFMSVpFUl9TTU9PVElOR19USU1FID0gMC44O1xuXG4vKipcbiAqIENvbnZlcnRzIHRpbWUgZG9tYWluIGRhdGEgYXJyYXkgdG8gYXVkaW8gbGV2ZWwuXG4gKiBAcGFyYW0gYXJyYXkgdGhlIHRpbWUgZG9tYWluIGRhdGEgYXJyYXkuXG4gKiBAcmV0dXJucyB7bnVtYmVyfSB0aGUgYXVkaW8gbGV2ZWxcbiAqL1xuZnVuY3Rpb24gdGltZURvbWFpbkRhdGFUb0F1ZGlvTGV2ZWwoc2FtcGxlcykge1xuXG4gICAgdmFyIG1heFZvbHVtZSA9IDA7XG5cbiAgICB2YXIgbGVuZ3RoID0gc2FtcGxlcy5sZW5ndGg7XG5cbiAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGlmIChtYXhWb2x1bWUgPCBzYW1wbGVzW2ldKVxuICAgICAgICAgICAgbWF4Vm9sdW1lID0gc2FtcGxlc1tpXTtcbiAgICB9XG5cbiAgICByZXR1cm4gcGFyc2VGbG9hdCgoKG1heFZvbHVtZSAtIDEyNykgLyAxMjgpLnRvRml4ZWQoMykpO1xufTtcblxuLyoqXG4gKiBBbmltYXRlcyBhdWRpbyBsZXZlbCBjaGFuZ2VcbiAqIEBwYXJhbSBuZXdMZXZlbCB0aGUgbmV3IGF1ZGlvIGxldmVsXG4gKiBAcGFyYW0gbGFzdExldmVsIHRoZSBsYXN0IGF1ZGlvIGxldmVsXG4gKiBAcmV0dXJucyB7TnVtYmVyfSB0aGUgYXVkaW8gbGV2ZWwgdG8gYmUgc2V0XG4gKi9cbmZ1bmN0aW9uIGFuaW1hdGVMZXZlbChuZXdMZXZlbCwgbGFzdExldmVsKVxue1xuICAgIHZhciB2YWx1ZSA9IDA7XG4gICAgdmFyIGRpZmYgPSBsYXN0TGV2ZWwgLSBuZXdMZXZlbDtcbiAgICBpZihkaWZmID4gMC4yKVxuICAgIHtcbiAgICAgICAgdmFsdWUgPSBsYXN0TGV2ZWwgLSAwLjI7XG4gICAgfVxuICAgIGVsc2UgaWYoZGlmZiA8IC0wLjQpXG4gICAge1xuICAgICAgICB2YWx1ZSA9IGxhc3RMZXZlbCArIDAuNDtcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgICAgdmFsdWUgPSBuZXdMZXZlbDtcbiAgICB9XG5cbiAgICByZXR1cm4gcGFyc2VGbG9hdCh2YWx1ZS50b0ZpeGVkKDMpKTtcbn1cblxuXG4vKipcbiAqIDx0dD5Mb2NhbFN0YXRzQ29sbGVjdG9yPC90dD4gY2FsY3VsYXRlcyBzdGF0aXN0aWNzIGZvciB0aGUgbG9jYWwgc3RyZWFtLlxuICpcbiAqIEBwYXJhbSBzdHJlYW0gdGhlIGxvY2FsIHN0cmVhbVxuICogQHBhcmFtIGludGVydmFsIHN0YXRzIHJlZnJlc2ggaW50ZXJ2YWwgZ2l2ZW4gaW4gbXMuXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKExvY2FsU3RhdHNDb2xsZWN0b3IpfSB1cGRhdGVDYWxsYmFjayB0aGUgY2FsbGJhY2sgY2FsbGVkIG9uIHN0YXRzXG4gKiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdXBkYXRlLlxuICogQGNvbnN0cnVjdG9yXG4gKi9cbmZ1bmN0aW9uIExvY2FsU3RhdHNDb2xsZWN0b3Ioc3RyZWFtLCBpbnRlcnZhbCwgc3RhdGlzdGljc1NlcnZpY2UsIGV2ZW50RW1pdHRlcikge1xuICAgIHdpbmRvdy5BdWRpb0NvbnRleHQgPSB3aW5kb3cuQXVkaW9Db250ZXh0IHx8IHdpbmRvdy53ZWJraXRBdWRpb0NvbnRleHQ7XG4gICAgdGhpcy5zdHJlYW0gPSBzdHJlYW07XG4gICAgdGhpcy5pbnRlcnZhbElkID0gbnVsbDtcbiAgICB0aGlzLmludGVydmFsTWlsaXMgPSBpbnRlcnZhbDtcbiAgICB0aGlzLmV2ZW50RW1pdHRlciA9IGV2ZW50RW1pdHRlcjtcbiAgICB0aGlzLmF1ZGlvTGV2ZWwgPSAwO1xuICAgIHRoaXMuc3RhdGlzdGljc1NlcnZpY2UgPSBzdGF0aXN0aWNzU2VydmljZTtcbn1cblxuLyoqXG4gKiBTdGFydHMgdGhlIGNvbGxlY3RpbmcgdGhlIHN0YXRpc3RpY3MuXG4gKi9cbkxvY2FsU3RhdHNDb2xsZWN0b3IucHJvdG90eXBlLnN0YXJ0ID0gZnVuY3Rpb24gKCkge1xuICAgIGlmIChjb25maWcuZGlzYWJsZUF1ZGlvTGV2ZWxzIHx8ICF3aW5kb3cuQXVkaW9Db250ZXh0KVxuICAgICAgICByZXR1cm47XG5cbiAgICB2YXIgY29udGV4dCA9IG5ldyBBdWRpb0NvbnRleHQoKTtcbiAgICB2YXIgYW5hbHlzZXIgPSBjb250ZXh0LmNyZWF0ZUFuYWx5c2VyKCk7XG4gICAgYW5hbHlzZXIuc21vb3RoaW5nVGltZUNvbnN0YW50ID0gV0VCQVVESU9fQU5BTElaRVJfU01PT1RJTkdfVElNRTtcbiAgICBhbmFseXNlci5mZnRTaXplID0gV0VCQVVESU9fQU5BTElaRVJfRkZUX1NJWkU7XG5cblxuICAgIHZhciBzb3VyY2UgPSBjb250ZXh0LmNyZWF0ZU1lZGlhU3RyZWFtU291cmNlKHRoaXMuc3RyZWFtKTtcbiAgICBzb3VyY2UuY29ubmVjdChhbmFseXNlcik7XG5cblxuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIHRoaXMuaW50ZXJ2YWxJZCA9IHNldEludGVydmFsKFxuICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgYXJyYXkgPSBuZXcgVWludDhBcnJheShhbmFseXNlci5mcmVxdWVuY3lCaW5Db3VudCk7XG4gICAgICAgICAgICBhbmFseXNlci5nZXRCeXRlVGltZURvbWFpbkRhdGEoYXJyYXkpO1xuICAgICAgICAgICAgdmFyIGF1ZGlvTGV2ZWwgPSB0aW1lRG9tYWluRGF0YVRvQXVkaW9MZXZlbChhcnJheSk7XG4gICAgICAgICAgICBpZihhdWRpb0xldmVsICE9IHNlbGYuYXVkaW9MZXZlbCkge1xuICAgICAgICAgICAgICAgIHNlbGYuYXVkaW9MZXZlbCA9IGFuaW1hdGVMZXZlbChhdWRpb0xldmVsLCBzZWxmLmF1ZGlvTGV2ZWwpO1xuICAgICAgICAgICAgICAgIHNlbGYuZXZlbnRFbWl0dGVyLmVtaXQoXG4gICAgICAgICAgICAgICAgICAgIFwic3RhdGlzdGljcy5hdWRpb0xldmVsXCIsXG4gICAgICAgICAgICAgICAgICAgIHNlbGYuc3RhdGlzdGljc1NlcnZpY2UuTE9DQUxfSklELFxuICAgICAgICAgICAgICAgICAgICBzZWxmLmF1ZGlvTGV2ZWwpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgICAgICB0aGlzLmludGVydmFsTWlsaXNcbiAgICApO1xuXG59O1xuXG4vKipcbiAqIFN0b3BzIGNvbGxlY3RpbmcgdGhlIHN0YXRpc3RpY3MuXG4gKi9cbkxvY2FsU3RhdHNDb2xsZWN0b3IucHJvdG90eXBlLnN0b3AgPSBmdW5jdGlvbiAoKSB7XG4gICAgaWYgKHRoaXMuaW50ZXJ2YWxJZCkge1xuICAgICAgICBjbGVhckludGVydmFsKHRoaXMuaW50ZXJ2YWxJZCk7XG4gICAgICAgIHRoaXMuaW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBMb2NhbFN0YXRzQ29sbGVjdG9yOyIsIi8qIGdsb2JhbCBzc3JjMmppZCAqL1xuLyoganNoaW50IC1XMTE3ICovXG52YXIgUlRDQnJvd3NlclR5cGUgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvUlRDQnJvd3NlclR5cGVcIik7XG5cblxuLyoqXG4gKiBDYWxjdWxhdGVzIHBhY2tldCBsb3N0IHBlcmNlbnQgdXNpbmcgdGhlIG51bWJlciBvZiBsb3N0IHBhY2tldHMgYW5kIHRoZVxuICogbnVtYmVyIG9mIGFsbCBwYWNrZXQuXG4gKiBAcGFyYW0gbG9zdFBhY2tldHMgdGhlIG51bWJlciBvZiBsb3N0IHBhY2tldHNcbiAqIEBwYXJhbSB0b3RhbFBhY2tldHMgdGhlIG51bWJlciBvZiBhbGwgcGFja2V0cy5cbiAqIEByZXR1cm5zIHtudW1iZXJ9IHBhY2tldCBsb3NzIHBlcmNlbnRcbiAqL1xuZnVuY3Rpb24gY2FsY3VsYXRlUGFja2V0TG9zcyhsb3N0UGFja2V0cywgdG90YWxQYWNrZXRzKSB7XG4gICAgaWYoIXRvdGFsUGFja2V0cyB8fCB0b3RhbFBhY2tldHMgPD0gMCB8fCAhbG9zdFBhY2tldHMgfHwgbG9zdFBhY2tldHMgPD0gMClcbiAgICAgICAgcmV0dXJuIDA7XG4gICAgcmV0dXJuIE1hdGgucm91bmQoKGxvc3RQYWNrZXRzL3RvdGFsUGFja2V0cykqMTAwKTtcbn1cblxuZnVuY3Rpb24gZ2V0U3RhdFZhbHVlKGl0ZW0sIG5hbWUpIHtcbiAgICBpZigha2V5TWFwW0FQUC5SVEMuZ2V0QnJvd3NlclR5cGUoKV1bbmFtZV0pXG4gICAgICAgIHRocm93IFwiVGhlIHByb3BlcnR5IGlzbid0IHN1cHBvcnRlZCFcIjtcbiAgICB2YXIga2V5ID0ga2V5TWFwW0FQUC5SVEMuZ2V0QnJvd3NlclR5cGUoKV1bbmFtZV07XG4gICAgcmV0dXJuIEFQUC5SVEMuZ2V0QnJvd3NlclR5cGUoKSA9PSBSVENCcm93c2VyVHlwZS5SVENfQlJPV1NFUl9DSFJPTUU/IGl0ZW0uc3RhdChrZXkpIDogaXRlbVtrZXldO1xufVxuXG4vKipcbiAqIFBlZXIgc3RhdGlzdGljcyBkYXRhIGhvbGRlci5cbiAqIEBjb25zdHJ1Y3RvclxuICovXG5mdW5jdGlvbiBQZWVyU3RhdHMoKVxue1xuICAgIHRoaXMuc3NyYzJMb3NzID0ge307XG4gICAgdGhpcy5zc3JjMkF1ZGlvTGV2ZWwgPSB7fTtcbiAgICB0aGlzLnNzcmMyYml0cmF0ZSA9IHt9O1xuICAgIHRoaXMuc3NyYzJyZXNvbHV0aW9uID0ge307XG59XG5cbi8qKlxuICogVGhlIGJhbmR3aWR0aFxuICogQHR5cGUge3t9fVxuICovXG5QZWVyU3RhdHMuYmFuZHdpZHRoID0ge307XG5cbi8qKlxuICogVGhlIGJpdCByYXRlXG4gKiBAdHlwZSB7e319XG4gKi9cblBlZXJTdGF0cy5iaXRyYXRlID0ge307XG5cblxuXG4vKipcbiAqIFRoZSBwYWNrZXQgbG9zcyByYXRlXG4gKiBAdHlwZSB7e319XG4gKi9cblBlZXJTdGF0cy5wYWNrZXRMb3NzID0gbnVsbDtcblxuLyoqXG4gKiBTZXRzIHBhY2tldHMgbG9zcyByYXRlIGZvciBnaXZlbiA8dHQ+c3NyYzwvdHQ+IHRoYXQgYmxvbmcgdG8gdGhlIHBlZXJcbiAqIHJlcHJlc2VudGVkIGJ5IHRoaXMgaW5zdGFuY2UuXG4gKiBAcGFyYW0gc3NyYyBhdWRpbyBvciB2aWRlbyBSVFAgc3RyZWFtIFNTUkMuXG4gKiBAcGFyYW0gbG9zc1JhdGUgbmV3IHBhY2tldCBsb3NzIHJhdGUgdmFsdWUgdG8gYmUgc2V0LlxuICovXG5QZWVyU3RhdHMucHJvdG90eXBlLnNldFNzcmNMb3NzID0gZnVuY3Rpb24gKHNzcmMsIGxvc3NSYXRlKVxue1xuICAgIHRoaXMuc3NyYzJMb3NzW3NzcmNdID0gbG9zc1JhdGU7XG59O1xuXG4vKipcbiAqIFNldHMgcmVzb2x1dGlvbiBmb3IgZ2l2ZW4gPHR0PnNzcmM8L3R0PiB0aGF0IGJlbG9uZyB0byB0aGUgcGVlclxuICogcmVwcmVzZW50ZWQgYnkgdGhpcyBpbnN0YW5jZS5cbiAqIEBwYXJhbSBzc3JjIGF1ZGlvIG9yIHZpZGVvIFJUUCBzdHJlYW0gU1NSQy5cbiAqIEBwYXJhbSByZXNvbHV0aW9uIG5ldyByZXNvbHV0aW9uIHZhbHVlIHRvIGJlIHNldC5cbiAqL1xuUGVlclN0YXRzLnByb3RvdHlwZS5zZXRTc3JjUmVzb2x1dGlvbiA9IGZ1bmN0aW9uIChzc3JjLCByZXNvbHV0aW9uKVxue1xuICAgIGlmKHJlc29sdXRpb24gPT09IG51bGwgJiYgdGhpcy5zc3JjMnJlc29sdXRpb25bc3NyY10pXG4gICAge1xuICAgICAgICBkZWxldGUgdGhpcy5zc3JjMnJlc29sdXRpb25bc3NyY107XG4gICAgfVxuICAgIGVsc2UgaWYocmVzb2x1dGlvbiAhPT0gbnVsbClcbiAgICAgICAgdGhpcy5zc3JjMnJlc29sdXRpb25bc3NyY10gPSByZXNvbHV0aW9uO1xufTtcblxuLyoqXG4gKiBTZXRzIHRoZSBiaXQgcmF0ZSBmb3IgZ2l2ZW4gPHR0PnNzcmM8L3R0PiB0aGF0IGJsb25nIHRvIHRoZSBwZWVyXG4gKiByZXByZXNlbnRlZCBieSB0aGlzIGluc3RhbmNlLlxuICogQHBhcmFtIHNzcmMgYXVkaW8gb3IgdmlkZW8gUlRQIHN0cmVhbSBTU1JDLlxuICogQHBhcmFtIGJpdHJhdGUgbmV3IGJpdHJhdGUgdmFsdWUgdG8gYmUgc2V0LlxuICovXG5QZWVyU3RhdHMucHJvdG90eXBlLnNldFNzcmNCaXRyYXRlID0gZnVuY3Rpb24gKHNzcmMsIGJpdHJhdGUpXG57XG4gICAgaWYodGhpcy5zc3JjMmJpdHJhdGVbc3NyY10pXG4gICAge1xuICAgICAgICB0aGlzLnNzcmMyYml0cmF0ZVtzc3JjXS5kb3dubG9hZCArPSBiaXRyYXRlLmRvd25sb2FkO1xuICAgICAgICB0aGlzLnNzcmMyYml0cmF0ZVtzc3JjXS51cGxvYWQgKz0gYml0cmF0ZS51cGxvYWQ7XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgICB0aGlzLnNzcmMyYml0cmF0ZVtzc3JjXSA9IGJpdHJhdGU7XG4gICAgfVxufTtcblxuLyoqXG4gKiBTZXRzIG5ldyBhdWRpbyBsZXZlbChpbnB1dCBvciBvdXRwdXQpIGZvciBnaXZlbiA8dHQ+c3NyYzwvdHQ+IHRoYXQgaWRlbnRpZmllc1xuICogdGhlIHN0cmVhbSB3aGljaCBiZWxvbmdzIHRvIHRoZSBwZWVyIHJlcHJlc2VudGVkIGJ5IHRoaXMgaW5zdGFuY2UuXG4gKiBAcGFyYW0gc3NyYyBSVFAgc3RyZWFtIFNTUkMgZm9yIHdoaWNoIGN1cnJlbnQgYXVkaW8gbGV2ZWwgdmFsdWUgd2lsbCBiZVxuICogICAgICAgIHVwZGF0ZWQuXG4gKiBAcGFyYW0gYXVkaW9MZXZlbCB0aGUgbmV3IGF1ZGlvIGxldmVsIHZhbHVlIHRvIGJlIHNldC4gVmFsdWUgaXMgdHJ1bmNhdGVkIHRvXG4gKiAgICAgICAgZml0IHRoZSByYW5nZSBmcm9tIDAgdG8gMS5cbiAqL1xuUGVlclN0YXRzLnByb3RvdHlwZS5zZXRTc3JjQXVkaW9MZXZlbCA9IGZ1bmN0aW9uIChzc3JjLCBhdWRpb0xldmVsKVxue1xuICAgIC8vIFJhbmdlIGxpbWl0IDAgLSAxXG4gICAgdGhpcy5zc3JjMkF1ZGlvTGV2ZWxbc3NyY10gPSBNYXRoLm1pbihNYXRoLm1heChhdWRpb0xldmVsLCAwKSwgMSk7XG59O1xuXG4vKipcbiAqIEFycmF5IHdpdGggdGhlIHRyYW5zcG9ydCBpbmZvcm1hdGlvbi5cbiAqIEB0eXBlIHtBcnJheX1cbiAqL1xuUGVlclN0YXRzLnRyYW5zcG9ydCA9IFtdO1xuXG5cbi8qKlxuICogPHR0PlN0YXRzQ29sbGVjdG9yPC90dD4gcmVnaXN0ZXJzIGZvciBzdGF0cyB1cGRhdGVzIG9mIGdpdmVuXG4gKiA8dHQ+cGVlcmNvbm5lY3Rpb248L3R0PiBpbiBnaXZlbiA8dHQ+aW50ZXJ2YWw8L3R0Pi4gT24gZWFjaCB1cGRhdGUgcGFydGljdWxhclxuICogc3RhdHMgYXJlIGV4dHJhY3RlZCBhbmQgcHV0IGluIHtAbGluayBQZWVyU3RhdHN9IG9iamVjdHMuIE9uY2UgdGhlIHByb2Nlc3NpbmdcbiAqIGlzIGRvbmUgPHR0PmF1ZGlvTGV2ZWxzVXBkYXRlQ2FsbGJhY2s8L3R0PiBpcyBjYWxsZWQgd2l0aCA8dHQ+dGhpczwvdHQ+XG4gKiBpbnN0YW5jZSBhcyBhbiBldmVudCBzb3VyY2UuXG4gKlxuICogQHBhcmFtIHBlZXJjb25uZWN0aW9uIHdlYlJUQyBwZWVyIGNvbm5lY3Rpb24gb2JqZWN0LlxuICogQHBhcmFtIGludGVydmFsIHN0YXRzIHJlZnJlc2ggaW50ZXJ2YWwgZ2l2ZW4gaW4gbXMuXG4gKiBAcGFyYW0ge2Z1bmN0aW9uKFN0YXRzQ29sbGVjdG9yKX0gYXVkaW9MZXZlbHNVcGRhdGVDYWxsYmFjayB0aGUgY2FsbGJhY2tcbiAqIGNhbGxlZCBvbiBzdGF0cyB1cGRhdGUuXG4gKiBAY29uc3RydWN0b3JcbiAqL1xuZnVuY3Rpb24gU3RhdHNDb2xsZWN0b3IocGVlcmNvbm5lY3Rpb24sIGF1ZGlvTGV2ZWxzSW50ZXJ2YWwsIHN0YXRzSW50ZXJ2YWwsIGV2ZW50RW1pdHRlcilcbntcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uID0gcGVlcmNvbm5lY3Rpb247XG4gICAgdGhpcy5iYXNlbGluZUF1ZGlvTGV2ZWxzUmVwb3J0ID0gbnVsbDtcbiAgICB0aGlzLmN1cnJlbnRBdWRpb0xldmVsc1JlcG9ydCA9IG51bGw7XG4gICAgdGhpcy5jdXJyZW50U3RhdHNSZXBvcnQgPSBudWxsO1xuICAgIHRoaXMuYmFzZWxpbmVTdGF0c1JlcG9ydCA9IG51bGw7XG4gICAgdGhpcy5hdWRpb0xldmVsc0ludGVydmFsSWQgPSBudWxsO1xuICAgIHRoaXMuZXZlbnRFbWl0dGVyID0gZXZlbnRFbWl0dGVyO1xuXG4gICAgLyoqXG4gICAgICogR2F0aGVyIFBlZXJDb25uZWN0aW9uIHN0YXRzIG9uY2UgZXZlcnkgdGhpcyBtYW55IG1pbGxpc2Vjb25kcy5cbiAgICAgKi9cbiAgICB0aGlzLkdBVEhFUl9JTlRFUlZBTCA9IDEwMDAwO1xuXG4gICAgLyoqXG4gICAgICogTG9nIHN0YXRzIHZpYSB0aGUgZm9jdXMgb25jZSBldmVyeSB0aGlzIG1hbnkgbWlsbGlzZWNvbmRzLlxuICAgICAqL1xuICAgIHRoaXMuTE9HX0lOVEVSVkFMID0gNjAwMDA7XG5cbiAgICAvKipcbiAgICAgKiBHYXRoZXIgc3RhdHMgYW5kIHN0b3JlIHRoZW0gaW4gdGhpcy5zdGF0c1RvQmVMb2dnZWQuXG4gICAgICovXG4gICAgdGhpcy5nYXRoZXJTdGF0c0ludGVydmFsSWQgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogU2VuZCB0aGUgc3RhdHMgYWxyZWFkeSBzYXZlZCBpbiB0aGlzLnN0YXRzVG9CZUxvZ2dlZCB0byBiZSBsb2dnZWQgdmlhXG4gICAgICogdGhlIGZvY3VzLlxuICAgICAqL1xuICAgIHRoaXMubG9nU3RhdHNJbnRlcnZhbElkID0gbnVsbDtcblxuICAgIC8qKlxuICAgICAqIFN0b3JlcyB0aGUgc3RhdGlzdGljcyB3aGljaCB3aWxsIGJlIHNlbmQgdG8gdGhlIGZvY3VzIHRvIGJlIGxvZ2dlZC5cbiAgICAgKi9cbiAgICB0aGlzLnN0YXRzVG9CZUxvZ2dlZCA9XG4gICAge1xuICAgICAgICB0aW1lc3RhbXBzOiBbXSxcbiAgICAgICAgc3RhdHM6IHt9XG4gICAgfTtcblxuICAgIC8vIFVwZGF0ZXMgc3RhdHMgaW50ZXJ2YWxcbiAgICB0aGlzLmF1ZGlvTGV2ZWxzSW50ZXJ2YWxNaWxpcyA9IGF1ZGlvTGV2ZWxzSW50ZXJ2YWw7XG5cbiAgICB0aGlzLnN0YXRzSW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgdGhpcy5zdGF0c0ludGVydmFsTWlsaXMgPSBzdGF0c0ludGVydmFsO1xuICAgIC8vIE1hcCBvZiBqaWRzIHRvIFBlZXJTdGF0c1xuICAgIHRoaXMuamlkMnN0YXRzID0ge307XG59XG5cbm1vZHVsZS5leHBvcnRzID0gU3RhdHNDb2xsZWN0b3I7XG5cbi8qKlxuICogU3RvcHMgc3RhdHMgdXBkYXRlcy5cbiAqL1xuU3RhdHNDb2xsZWN0b3IucHJvdG90eXBlLnN0b3AgPSBmdW5jdGlvbiAoKVxue1xuICAgIGlmICh0aGlzLmF1ZGlvTGV2ZWxzSW50ZXJ2YWxJZClcbiAgICB7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5hdWRpb0xldmVsc0ludGVydmFsSWQpO1xuICAgICAgICB0aGlzLmF1ZGlvTGV2ZWxzSW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5zdGF0c0ludGVydmFsSWQpO1xuICAgICAgICB0aGlzLnN0YXRzSW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5sb2dTdGF0c0ludGVydmFsSWQpO1xuICAgICAgICB0aGlzLmxvZ1N0YXRzSW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgICAgIGNsZWFySW50ZXJ2YWwodGhpcy5nYXRoZXJTdGF0c0ludGVydmFsSWQpO1xuICAgICAgICB0aGlzLmdhdGhlclN0YXRzSW50ZXJ2YWxJZCA9IG51bGw7XG4gICAgfVxufTtcblxuLyoqXG4gKiBDYWxsYmFjayBwYXNzZWQgdG8gPHR0PmdldFN0YXRzPC90dD4gbWV0aG9kLlxuICogQHBhcmFtIGVycm9yIGFuIGVycm9yIHRoYXQgb2NjdXJyZWQgb24gPHR0PmdldFN0YXRzPC90dD4gY2FsbC5cbiAqL1xuU3RhdHNDb2xsZWN0b3IucHJvdG90eXBlLmVycm9yQ2FsbGJhY2sgPSBmdW5jdGlvbiAoZXJyb3IpXG57XG4gICAgY29uc29sZS5lcnJvcihcIkdldCBzdGF0cyBlcnJvclwiLCBlcnJvcik7XG4gICAgdGhpcy5zdG9wKCk7XG59O1xuXG4vKipcbiAqIFN0YXJ0cyBzdGF0cyB1cGRhdGVzLlxuICovXG5TdGF0c0NvbGxlY3Rvci5wcm90b3R5cGUuc3RhcnQgPSBmdW5jdGlvbiAoKVxue1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZighY29uZmlnLmRpc2FibGVBdWRpb0xldmVscykge1xuICAgICAgICB0aGlzLmF1ZGlvTGV2ZWxzSW50ZXJ2YWxJZCA9IHNldEludGVydmFsKFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIC8vIEludGVydmFsIHVwZGF0ZXNcbiAgICAgICAgICAgICAgICBzZWxmLnBlZXJjb25uZWN0aW9uLmdldFN0YXRzKFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAocmVwb3J0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcmVzdWx0cyA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoIXJlcG9ydCB8fCAhcmVwb3J0LnJlc3VsdCB8fFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHR5cGVvZiByZXBvcnQucmVzdWx0ICE9ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRzID0gcmVwb3J0O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IHJlcG9ydC5yZXN1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vY29uc29sZS5lcnJvcihcIkdvdCBpbnRlcnZhbCByZXBvcnRcIiwgcmVzdWx0cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmN1cnJlbnRBdWRpb0xldmVsc1JlcG9ydCA9IHJlc3VsdHM7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnByb2Nlc3NBdWRpb0xldmVsUmVwb3J0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmJhc2VsaW5lQXVkaW9MZXZlbHNSZXBvcnQgPVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuY3VycmVudEF1ZGlvTGV2ZWxzUmVwb3J0O1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBzZWxmLmVycm9yQ2FsbGJhY2tcbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIHNlbGYuYXVkaW9MZXZlbHNJbnRlcnZhbE1pbGlzXG4gICAgICAgICk7XG4gICAgfVxuXG4gICAgaWYoIWNvbmZpZy5kaXNhYmxlU3RhdHMpIHtcbiAgICAgICAgdGhpcy5zdGF0c0ludGVydmFsSWQgPSBzZXRJbnRlcnZhbChcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAvLyBJbnRlcnZhbCB1cGRhdGVzXG4gICAgICAgICAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5nZXRTdGF0cyhcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlcG9ydCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFyZXBvcnQgfHwgIXJlcG9ydC5yZXN1bHQgfHxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0eXBlb2YgcmVwb3J0LnJlc3VsdCAhPSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy9maXJlZm94XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IHJlcG9ydDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vY2hyb21lXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0cyA9IHJlcG9ydC5yZXN1bHQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIC8vY29uc29sZS5lcnJvcihcIkdvdCBpbnRlcnZhbCByZXBvcnRcIiwgcmVzdWx0cyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmN1cnJlbnRTdGF0c1JlcG9ydCA9IHJlc3VsdHM7XG4gICAgICAgICAgICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYucHJvY2Vzc1N0YXRzUmVwb3J0KCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJVbnN1cHBvcnRlZCBrZXk6XCIgKyBlLCBlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5iYXNlbGluZVN0YXRzUmVwb3J0ID0gc2VsZi5jdXJyZW50U3RhdHNSZXBvcnQ7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIHNlbGYuZXJyb3JDYWxsYmFja1xuICAgICAgICAgICAgICAgICk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgc2VsZi5zdGF0c0ludGVydmFsTWlsaXNcbiAgICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAoY29uZmlnLmxvZ1N0YXRzKSB7XG4gICAgICAgIHRoaXMuZ2F0aGVyU3RhdHNJbnRlcnZhbElkID0gc2V0SW50ZXJ2YWwoXG4gICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5nZXRTdGF0cyhcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlcG9ydCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5hZGRTdGF0c1RvQmVMb2dnZWQocmVwb3J0LnJlc3VsdCgpKTtcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICB0aGlzLkdBVEhFUl9JTlRFUlZBTFxuICAgICAgICApO1xuXG4gICAgICAgIHRoaXMubG9nU3RhdHNJbnRlcnZhbElkID0gc2V0SW50ZXJ2YWwoXG4gICAgICAgICAgICBmdW5jdGlvbigpIHsgc2VsZi5sb2dTdGF0cygpOyB9LFxuICAgICAgICAgICAgdGhpcy5MT0dfSU5URVJWQUwpO1xuICAgIH1cbn07XG5cbi8qKlxuICogQ29udmVydHMgdGhlIHN0YXRzIHRvIHRoZSBmb3JtYXQgdXNlZCBmb3IgbG9nZ2luZywgYW5kIHNhdmVzIHRoZSBkYXRhIGluXG4gKiB0aGlzLnN0YXRzVG9CZUxvZ2dlZC5cbiAqIEBwYXJhbSByZXBvcnRzIFJlcG9ydHMgYXMgZ2l2ZW4gYnkgd2Via2l0UlRDUGVyQ29ubmVjdGlvbi5nZXRTdGF0cy5cbiAqL1xuU3RhdHNDb2xsZWN0b3IucHJvdG90eXBlLmFkZFN0YXRzVG9CZUxvZ2dlZCA9IGZ1bmN0aW9uIChyZXBvcnRzKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciBudW1fcmVjb3JkcyA9IHRoaXMuc3RhdHNUb0JlTG9nZ2VkLnRpbWVzdGFtcHMubGVuZ3RoO1xuICAgIHRoaXMuc3RhdHNUb0JlTG9nZ2VkLnRpbWVzdGFtcHMucHVzaChuZXcgRGF0ZSgpLmdldFRpbWUoKSk7XG4gICAgcmVwb3J0cy5tYXAoZnVuY3Rpb24gKHJlcG9ydCkge1xuICAgICAgICB2YXIgc3RhdCA9IHNlbGYuc3RhdHNUb0JlTG9nZ2VkLnN0YXRzW3JlcG9ydC5pZF07XG4gICAgICAgIGlmICghc3RhdCkge1xuICAgICAgICAgICAgc3RhdCA9IHNlbGYuc3RhdHNUb0JlTG9nZ2VkLnN0YXRzW3JlcG9ydC5pZF0gPSB7fTtcbiAgICAgICAgfVxuICAgICAgICBzdGF0LnR5cGUgPSByZXBvcnQudHlwZTtcbiAgICAgICAgcmVwb3J0Lm5hbWVzKCkubWFwKGZ1bmN0aW9uIChuYW1lKSB7XG4gICAgICAgICAgICB2YXIgdmFsdWVzID0gc3RhdFtuYW1lXTtcbiAgICAgICAgICAgIGlmICghdmFsdWVzKSB7XG4gICAgICAgICAgICAgICAgdmFsdWVzID0gc3RhdFtuYW1lXSA9IFtdO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgd2hpbGUgKHZhbHVlcy5sZW5ndGggPCBudW1fcmVjb3Jkcykge1xuICAgICAgICAgICAgICAgIHZhbHVlcy5wdXNoKG51bGwpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFsdWVzLnB1c2gocmVwb3J0LnN0YXQobmFtZSkpO1xuICAgICAgICB9KTtcbiAgICB9KTtcbn07XG5cblN0YXRzQ29sbGVjdG9yLnByb3RvdHlwZS5sb2dTdGF0cyA9IGZ1bmN0aW9uICgpIHtcblxuICAgIGlmKCFBUFAueG1wcC5zZW5kTG9ncyh0aGlzLnN0YXRzVG9CZUxvZ2dlZCkpXG4gICAgICAgIHJldHVybjtcbiAgICAvLyBSZXNldCB0aGUgc3RhdHNcbiAgICB0aGlzLnN0YXRzVG9CZUxvZ2dlZC5zdGF0cyA9IHt9O1xuICAgIHRoaXMuc3RhdHNUb0JlTG9nZ2VkLnRpbWVzdGFtcHMgPSBbXTtcbn07XG52YXIga2V5TWFwID0ge307XG5rZXlNYXBbUlRDQnJvd3NlclR5cGUuUlRDX0JST1dTRVJfRklSRUZPWF0gPSB7XG4gICAgXCJzc3JjXCI6IFwic3NyY1wiLFxuICAgIFwicGFja2V0c1JlY2VpdmVkXCI6IFwicGFja2V0c1JlY2VpdmVkXCIsXG4gICAgXCJwYWNrZXRzTG9zdFwiOiBcInBhY2tldHNMb3N0XCIsXG4gICAgXCJwYWNrZXRzU2VudFwiOiBcInBhY2tldHNTZW50XCIsXG4gICAgXCJieXRlc1JlY2VpdmVkXCI6IFwiYnl0ZXNSZWNlaXZlZFwiLFxuICAgIFwiYnl0ZXNTZW50XCI6IFwiYnl0ZXNTZW50XCJcbn07XG5rZXlNYXBbUlRDQnJvd3NlclR5cGUuUlRDX0JST1dTRVJfQ0hST01FXSA9IHtcbiAgICBcInJlY2VpdmVCYW5kd2lkdGhcIjogXCJnb29nQXZhaWxhYmxlUmVjZWl2ZUJhbmR3aWR0aFwiLFxuICAgIFwic2VuZEJhbmR3aWR0aFwiOiBcImdvb2dBdmFpbGFibGVTZW5kQmFuZHdpZHRoXCIsXG4gICAgXCJyZW1vdGVBZGRyZXNzXCI6IFwiZ29vZ1JlbW90ZUFkZHJlc3NcIixcbiAgICBcInRyYW5zcG9ydFR5cGVcIjogXCJnb29nVHJhbnNwb3J0VHlwZVwiLFxuICAgIFwibG9jYWxBZGRyZXNzXCI6IFwiZ29vZ0xvY2FsQWRkcmVzc1wiLFxuICAgIFwiYWN0aXZlQ29ubmVjdGlvblwiOiBcImdvb2dBY3RpdmVDb25uZWN0aW9uXCIsXG4gICAgXCJzc3JjXCI6IFwic3NyY1wiLFxuICAgIFwicGFja2V0c1JlY2VpdmVkXCI6IFwicGFja2V0c1JlY2VpdmVkXCIsXG4gICAgXCJwYWNrZXRzU2VudFwiOiBcInBhY2tldHNTZW50XCIsXG4gICAgXCJwYWNrZXRzTG9zdFwiOiBcInBhY2tldHNMb3N0XCIsXG4gICAgXCJieXRlc1JlY2VpdmVkXCI6IFwiYnl0ZXNSZWNlaXZlZFwiLFxuICAgIFwiYnl0ZXNTZW50XCI6IFwiYnl0ZXNTZW50XCIsXG4gICAgXCJnb29nRnJhbWVIZWlnaHRSZWNlaXZlZFwiOiBcImdvb2dGcmFtZUhlaWdodFJlY2VpdmVkXCIsXG4gICAgXCJnb29nRnJhbWVXaWR0aFJlY2VpdmVkXCI6IFwiZ29vZ0ZyYW1lV2lkdGhSZWNlaXZlZFwiLFxuICAgIFwiZ29vZ0ZyYW1lSGVpZ2h0U2VudFwiOiBcImdvb2dGcmFtZUhlaWdodFNlbnRcIixcbiAgICBcImdvb2dGcmFtZVdpZHRoU2VudFwiOiBcImdvb2dGcmFtZVdpZHRoU2VudFwiLFxuICAgIFwiYXVkaW9JbnB1dExldmVsXCI6IFwiYXVkaW9JbnB1dExldmVsXCIsXG4gICAgXCJhdWRpb091dHB1dExldmVsXCI6IFwiYXVkaW9PdXRwdXRMZXZlbFwiXG59O1xuXG5cbi8qKlxuICogU3RhdHMgcHJvY2Vzc2luZyBsb2dpYy5cbiAqL1xuU3RhdHNDb2xsZWN0b3IucHJvdG90eXBlLnByb2Nlc3NTdGF0c1JlcG9ydCA9IGZ1bmN0aW9uICgpIHtcbiAgICBpZiAoIXRoaXMuYmFzZWxpbmVTdGF0c1JlcG9ydCkge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaWR4IGluIHRoaXMuY3VycmVudFN0YXRzUmVwb3J0KSB7XG4gICAgICAgIHZhciBub3cgPSB0aGlzLmN1cnJlbnRTdGF0c1JlcG9ydFtpZHhdO1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKGdldFN0YXRWYWx1ZShub3csICdyZWNlaXZlQmFuZHdpZHRoJykgfHxcbiAgICAgICAgICAgICAgICBnZXRTdGF0VmFsdWUobm93LCAnc2VuZEJhbmR3aWR0aCcpKSB7XG4gICAgICAgICAgICAgICAgUGVlclN0YXRzLmJhbmR3aWR0aCA9IHtcbiAgICAgICAgICAgICAgICAgICAgXCJkb3dubG9hZFwiOiBNYXRoLnJvdW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChnZXRTdGF0VmFsdWUobm93LCAncmVjZWl2ZUJhbmR3aWR0aCcpKSAvIDEwMDApLFxuICAgICAgICAgICAgICAgICAgICBcInVwbG9hZFwiOiBNYXRoLnJvdW5kKFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIChnZXRTdGF0VmFsdWUobm93LCAnc2VuZEJhbmR3aWR0aCcpKSAvIDEwMDApXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBjYXRjaChlKXsvKm5vdCBzdXBwb3J0ZWQqL31cblxuICAgICAgICBpZihub3cudHlwZSA9PSAnZ29vZ0NhbmRpZGF0ZVBhaXInKVxuICAgICAgICB7XG4gICAgICAgICAgICB2YXIgaXAsIHR5cGUsIGxvY2FsSVAsIGFjdGl2ZTtcbiAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgaXAgPSBnZXRTdGF0VmFsdWUobm93LCAncmVtb3RlQWRkcmVzcycpO1xuICAgICAgICAgICAgICAgIHR5cGUgPSBnZXRTdGF0VmFsdWUobm93LCBcInRyYW5zcG9ydFR5cGVcIik7XG4gICAgICAgICAgICAgICAgbG9jYWxJUCA9IGdldFN0YXRWYWx1ZShub3csIFwibG9jYWxBZGRyZXNzXCIpO1xuICAgICAgICAgICAgICAgIGFjdGl2ZSA9IGdldFN0YXRWYWx1ZShub3csIFwiYWN0aXZlQ29ubmVjdGlvblwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGNhdGNoKGUpey8qbm90IHN1cHBvcnRlZCovfVxuICAgICAgICAgICAgaWYoIWlwIHx8ICF0eXBlIHx8ICFsb2NhbElQIHx8IGFjdGl2ZSAhPSBcInRydWVcIilcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIHZhciBhZGRyZXNzU2F2ZWQgPSBmYWxzZTtcbiAgICAgICAgICAgIGZvcih2YXIgaSA9IDA7IGkgPCBQZWVyU3RhdHMudHJhbnNwb3J0Lmxlbmd0aDsgaSsrKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIGlmKFBlZXJTdGF0cy50cmFuc3BvcnRbaV0uaXAgPT0gaXAgJiZcbiAgICAgICAgICAgICAgICAgICAgUGVlclN0YXRzLnRyYW5zcG9ydFtpXS50eXBlID09IHR5cGUgJiZcbiAgICAgICAgICAgICAgICAgICAgUGVlclN0YXRzLnRyYW5zcG9ydFtpXS5sb2NhbGlwID09IGxvY2FsSVApXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBhZGRyZXNzU2F2ZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmKGFkZHJlc3NTYXZlZClcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgICAgIFBlZXJTdGF0cy50cmFuc3BvcnQucHVzaCh7bG9jYWxpcDogbG9jYWxJUCwgaXA6IGlwLCB0eXBlOiB0eXBlfSk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmKG5vdy50eXBlID09IFwiY2FuZGlkYXRlcGFpclwiKVxuICAgICAgICB7XG4gICAgICAgICAgICBpZihub3cuc3RhdGUgPT0gXCJzdWNjZWVkZWRcIilcbiAgICAgICAgICAgICAgICBjb250aW51ZTtcblxuICAgICAgICAgICAgdmFyIGxvY2FsID0gdGhpcy5jdXJyZW50U3RhdHNSZXBvcnRbbm93LmxvY2FsQ2FuZGlkYXRlSWRdO1xuICAgICAgICAgICAgdmFyIHJlbW90ZSA9IHRoaXMuY3VycmVudFN0YXRzUmVwb3J0W25vdy5yZW1vdGVDYW5kaWRhdGVJZF07XG4gICAgICAgICAgICBQZWVyU3RhdHMudHJhbnNwb3J0LnB1c2goe2xvY2FsaXA6IGxvY2FsLmlwQWRkcmVzcyArIFwiOlwiICsgbG9jYWwucG9ydE51bWJlcixcbiAgICAgICAgICAgICAgICBpcDogcmVtb3RlLmlwQWRkcmVzcyArIFwiOlwiICsgcmVtb3RlLnBvcnROdW1iZXIsIHR5cGU6IGxvY2FsLnRyYW5zcG9ydH0pO1xuXG4gICAgICAgIH1cblxuICAgICAgICBpZiAobm93LnR5cGUgIT0gJ3NzcmMnICYmIG5vdy50eXBlICE9IFwib3V0Ym91bmRydHBcIiAmJlxuICAgICAgICAgICAgbm93LnR5cGUgIT0gXCJpbmJvdW5kcnRwXCIpIHtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGJlZm9yZSA9IHRoaXMuYmFzZWxpbmVTdGF0c1JlcG9ydFtpZHhdO1xuICAgICAgICBpZiAoIWJlZm9yZSkge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKGdldFN0YXRWYWx1ZShub3csICdzc3JjJykgKyAnIG5vdCBlbm91Z2ggZGF0YScpO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc3NyYyA9IGdldFN0YXRWYWx1ZShub3csICdzc3JjJyk7XG4gICAgICAgIGlmKCFzc3JjKVxuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIHZhciBqaWQgPSBBUFAueG1wcC5nZXRKaWRGcm9tU1NSQyhzc3JjKTtcbiAgICAgICAgaWYgKCFqaWQgJiYgKERhdGUubm93KCkgLSBub3cudGltZXN0YW1wKSA8IDMwMDApIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcIk5vIGppZCBmb3Igc3NyYzogXCIgKyBzc3JjKTtcbiAgICAgICAgICAgIGNvbnRpbnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIGppZFN0YXRzID0gdGhpcy5qaWQyc3RhdHNbamlkXTtcbiAgICAgICAgaWYgKCFqaWRTdGF0cykge1xuICAgICAgICAgICAgamlkU3RhdHMgPSBuZXcgUGVlclN0YXRzKCk7XG4gICAgICAgICAgICB0aGlzLmppZDJzdGF0c1tqaWRdID0gamlkU3RhdHM7XG4gICAgICAgIH1cblxuXG4gICAgICAgIHZhciBpc0Rvd25sb2FkU3RyZWFtID0gdHJ1ZTtcbiAgICAgICAgdmFyIGtleSA9ICdwYWNrZXRzUmVjZWl2ZWQnO1xuICAgICAgICBpZiAoIWdldFN0YXRWYWx1ZShub3csIGtleSkpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGlzRG93bmxvYWRTdHJlYW0gPSBmYWxzZTtcbiAgICAgICAgICAgIGtleSA9ICdwYWNrZXRzU2VudCc7XG4gICAgICAgICAgICBpZiAoIWdldFN0YXRWYWx1ZShub3csIGtleSkpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiTm8gcGFja2V0c1JlY2VpdmVkIG5vciBwYWNrZXRTZW50IHN0YXQgZm91bmRcIik7XG4gICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgdmFyIHBhY2tldHNOb3cgPSBnZXRTdGF0VmFsdWUobm93LCBrZXkpO1xuICAgICAgICBpZighcGFja2V0c05vdyB8fCBwYWNrZXRzTm93IDwgMClcbiAgICAgICAgICAgIHBhY2tldHNOb3cgPSAwO1xuXG4gICAgICAgIHZhciBwYWNrZXRzQmVmb3JlID0gZ2V0U3RhdFZhbHVlKGJlZm9yZSwga2V5KTtcbiAgICAgICAgaWYoIXBhY2tldHNCZWZvcmUgfHwgcGFja2V0c0JlZm9yZSA8IDApXG4gICAgICAgICAgICBwYWNrZXRzQmVmb3JlID0gMDtcbiAgICAgICAgdmFyIHBhY2tldFJhdGUgPSBwYWNrZXRzTm93IC0gcGFja2V0c0JlZm9yZTtcbiAgICAgICAgaWYoIXBhY2tldFJhdGUgfHwgcGFja2V0UmF0ZSA8IDApXG4gICAgICAgICAgICBwYWNrZXRSYXRlID0gMDtcbiAgICAgICAgdmFyIGN1cnJlbnRMb3NzID0gZ2V0U3RhdFZhbHVlKG5vdywgJ3BhY2tldHNMb3N0Jyk7XG4gICAgICAgIGlmKCFjdXJyZW50TG9zcyB8fCBjdXJyZW50TG9zcyA8IDApXG4gICAgICAgICAgICBjdXJyZW50TG9zcyA9IDA7XG4gICAgICAgIHZhciBwcmV2aW91c0xvc3MgPSBnZXRTdGF0VmFsdWUoYmVmb3JlLCAncGFja2V0c0xvc3QnKTtcbiAgICAgICAgaWYoIXByZXZpb3VzTG9zcyB8fCBwcmV2aW91c0xvc3MgPCAwKVxuICAgICAgICAgICAgcHJldmlvdXNMb3NzID0gMDtcbiAgICAgICAgdmFyIGxvc3NSYXRlID0gY3VycmVudExvc3MgLSBwcmV2aW91c0xvc3M7XG4gICAgICAgIGlmKCFsb3NzUmF0ZSB8fCBsb3NzUmF0ZSA8IDApXG4gICAgICAgICAgICBsb3NzUmF0ZSA9IDA7XG4gICAgICAgIHZhciBwYWNrZXRzVG90YWwgPSAocGFja2V0UmF0ZSArIGxvc3NSYXRlKTtcblxuICAgICAgICBqaWRTdGF0cy5zZXRTc3JjTG9zcyhzc3JjLFxuICAgICAgICAgICAge1wicGFja2V0c1RvdGFsXCI6IHBhY2tldHNUb3RhbCxcbiAgICAgICAgICAgICAgICBcInBhY2tldHNMb3N0XCI6IGxvc3NSYXRlLFxuICAgICAgICAgICAgICAgIFwiaXNEb3dubG9hZFN0cmVhbVwiOiBpc0Rvd25sb2FkU3RyZWFtfSk7XG5cblxuICAgICAgICB2YXIgYnl0ZXNSZWNlaXZlZCA9IDAsIGJ5dGVzU2VudCA9IDA7XG4gICAgICAgIGlmKGdldFN0YXRWYWx1ZShub3csIFwiYnl0ZXNSZWNlaXZlZFwiKSlcbiAgICAgICAge1xuICAgICAgICAgICAgYnl0ZXNSZWNlaXZlZCA9IGdldFN0YXRWYWx1ZShub3csIFwiYnl0ZXNSZWNlaXZlZFwiKSAtXG4gICAgICAgICAgICAgICAgZ2V0U3RhdFZhbHVlKGJlZm9yZSwgXCJieXRlc1JlY2VpdmVkXCIpO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYoZ2V0U3RhdFZhbHVlKG5vdywgXCJieXRlc1NlbnRcIikpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGJ5dGVzU2VudCA9IGdldFN0YXRWYWx1ZShub3csIFwiYnl0ZXNTZW50XCIpIC1cbiAgICAgICAgICAgICAgICBnZXRTdGF0VmFsdWUoYmVmb3JlLCBcImJ5dGVzU2VudFwiKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciB0aW1lID0gTWF0aC5yb3VuZCgobm93LnRpbWVzdGFtcCAtIGJlZm9yZS50aW1lc3RhbXApIC8gMTAwMCk7XG4gICAgICAgIGlmKGJ5dGVzUmVjZWl2ZWQgPD0gMCB8fCB0aW1lIDw9IDApXG4gICAgICAgIHtcbiAgICAgICAgICAgIGJ5dGVzUmVjZWl2ZWQgPSAwO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgYnl0ZXNSZWNlaXZlZCA9IE1hdGgucm91bmQoKChieXRlc1JlY2VpdmVkICogOCkgLyB0aW1lKSAvIDEwMDApO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYoYnl0ZXNTZW50IDw9IDAgfHwgdGltZSA8PSAwKVxuICAgICAgICB7XG4gICAgICAgICAgICBieXRlc1NlbnQgPSAwO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgYnl0ZXNTZW50ID0gTWF0aC5yb3VuZCgoKGJ5dGVzU2VudCAqIDgpIC8gdGltZSkgLyAxMDAwKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGppZFN0YXRzLnNldFNzcmNCaXRyYXRlKHNzcmMsIHtcbiAgICAgICAgICAgIFwiZG93bmxvYWRcIjogYnl0ZXNSZWNlaXZlZCxcbiAgICAgICAgICAgIFwidXBsb2FkXCI6IGJ5dGVzU2VudH0pO1xuXG4gICAgICAgIHZhciByZXNvbHV0aW9uID0ge2hlaWdodDogbnVsbCwgd2lkdGg6IG51bGx9O1xuICAgICAgICB0cnkge1xuICAgICAgICAgICAgaWYgKGdldFN0YXRWYWx1ZShub3csIFwiZ29vZ0ZyYW1lSGVpZ2h0UmVjZWl2ZWRcIikgJiZcbiAgICAgICAgICAgICAgICBnZXRTdGF0VmFsdWUobm93LCBcImdvb2dGcmFtZVdpZHRoUmVjZWl2ZWRcIikpIHtcbiAgICAgICAgICAgICAgICByZXNvbHV0aW9uLmhlaWdodCA9IGdldFN0YXRWYWx1ZShub3csIFwiZ29vZ0ZyYW1lSGVpZ2h0UmVjZWl2ZWRcIik7XG4gICAgICAgICAgICAgICAgcmVzb2x1dGlvbi53aWR0aCA9IGdldFN0YXRWYWx1ZShub3csIFwiZ29vZ0ZyYW1lV2lkdGhSZWNlaXZlZFwiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKGdldFN0YXRWYWx1ZShub3csIFwiZ29vZ0ZyYW1lSGVpZ2h0U2VudFwiKSAmJlxuICAgICAgICAgICAgICAgIGdldFN0YXRWYWx1ZShub3csIFwiZ29vZ0ZyYW1lV2lkdGhTZW50XCIpKSB7XG4gICAgICAgICAgICAgICAgcmVzb2x1dGlvbi5oZWlnaHQgPSBnZXRTdGF0VmFsdWUobm93LCBcImdvb2dGcmFtZUhlaWdodFNlbnRcIik7XG4gICAgICAgICAgICAgICAgcmVzb2x1dGlvbi53aWR0aCA9IGdldFN0YXRWYWx1ZShub3csIFwiZ29vZ0ZyYW1lV2lkdGhTZW50XCIpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNhdGNoKGUpey8qbm90IHN1cHBvcnRlZCovfVxuXG4gICAgICAgIGlmKHJlc29sdXRpb24uaGVpZ2h0ICYmIHJlc29sdXRpb24ud2lkdGgpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGppZFN0YXRzLnNldFNzcmNSZXNvbHV0aW9uKHNzcmMsIHJlc29sdXRpb24pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2VcbiAgICAgICAge1xuICAgICAgICAgICAgamlkU3RhdHMuc2V0U3NyY1Jlc29sdXRpb24oc3NyYywgbnVsbCk7XG4gICAgICAgIH1cblxuXG4gICAgfVxuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIC8vIEppZCBzdGF0c1xuICAgIHZhciB0b3RhbFBhY2tldHMgPSB7ZG93bmxvYWQ6IDAsIHVwbG9hZDogMH07XG4gICAgdmFyIGxvc3RQYWNrZXRzID0ge2Rvd25sb2FkOiAwLCB1cGxvYWQ6IDB9O1xuICAgIHZhciBiaXRyYXRlRG93bmxvYWQgPSAwO1xuICAgIHZhciBiaXRyYXRlVXBsb2FkID0gMDtcbiAgICB2YXIgcmVzb2x1dGlvbnMgPSB7fTtcbiAgICBPYmplY3Qua2V5cyh0aGlzLmppZDJzdGF0cykuZm9yRWFjaChcbiAgICAgICAgZnVuY3Rpb24gKGppZClcbiAgICAgICAge1xuICAgICAgICAgICAgT2JqZWN0LmtleXMoc2VsZi5qaWQyc3RhdHNbamlkXS5zc3JjMkxvc3MpLmZvckVhY2goXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHNzcmMpXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICB2YXIgdHlwZSA9IFwidXBsb2FkXCI7XG4gICAgICAgICAgICAgICAgICAgIGlmKHNlbGYuamlkMnN0YXRzW2ppZF0uc3NyYzJMb3NzW3NzcmNdLmlzRG93bmxvYWRTdHJlYW0pXG4gICAgICAgICAgICAgICAgICAgICAgICB0eXBlID0gXCJkb3dubG9hZFwiO1xuICAgICAgICAgICAgICAgICAgICB0b3RhbFBhY2tldHNbdHlwZV0gKz1cbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuamlkMnN0YXRzW2ppZF0uc3NyYzJMb3NzW3NzcmNdLnBhY2tldHNUb3RhbDtcbiAgICAgICAgICAgICAgICAgICAgbG9zdFBhY2tldHNbdHlwZV0gKz1cbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuamlkMnN0YXRzW2ppZF0uc3NyYzJMb3NzW3NzcmNdLnBhY2tldHNMb3N0O1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICBPYmplY3Qua2V5cyhzZWxmLmppZDJzdGF0c1tqaWRdLnNzcmMyYml0cmF0ZSkuZm9yRWFjaChcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgICAgICAgICAgICBiaXRyYXRlRG93bmxvYWQgKz1cbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuamlkMnN0YXRzW2ppZF0uc3NyYzJiaXRyYXRlW3NzcmNdLmRvd25sb2FkO1xuICAgICAgICAgICAgICAgICAgICBiaXRyYXRlVXBsb2FkICs9XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmppZDJzdGF0c1tqaWRdLnNzcmMyYml0cmF0ZVtzc3JjXS51cGxvYWQ7XG5cbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHNlbGYuamlkMnN0YXRzW2ppZF0uc3NyYzJiaXRyYXRlW3NzcmNdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICByZXNvbHV0aW9uc1tqaWRdID0gc2VsZi5qaWQyc3RhdHNbamlkXS5zc3JjMnJlc29sdXRpb247XG4gICAgICAgIH1cbiAgICApO1xuXG4gICAgUGVlclN0YXRzLmJpdHJhdGUgPSB7XCJ1cGxvYWRcIjogYml0cmF0ZVVwbG9hZCwgXCJkb3dubG9hZFwiOiBiaXRyYXRlRG93bmxvYWR9O1xuXG4gICAgUGVlclN0YXRzLnBhY2tldExvc3MgPSB7XG4gICAgICAgIHRvdGFsOlxuICAgICAgICAgICAgY2FsY3VsYXRlUGFja2V0TG9zcyhsb3N0UGFja2V0cy5kb3dubG9hZCArIGxvc3RQYWNrZXRzLnVwbG9hZCxcbiAgICAgICAgICAgICAgICAgICAgdG90YWxQYWNrZXRzLmRvd25sb2FkICsgdG90YWxQYWNrZXRzLnVwbG9hZCksXG4gICAgICAgIGRvd25sb2FkOlxuICAgICAgICAgICAgY2FsY3VsYXRlUGFja2V0TG9zcyhsb3N0UGFja2V0cy5kb3dubG9hZCwgdG90YWxQYWNrZXRzLmRvd25sb2FkKSxcbiAgICAgICAgdXBsb2FkOlxuICAgICAgICAgICAgY2FsY3VsYXRlUGFja2V0TG9zcyhsb3N0UGFja2V0cy51cGxvYWQsIHRvdGFsUGFja2V0cy51cGxvYWQpXG4gICAgfTtcbiAgICB0aGlzLmV2ZW50RW1pdHRlci5lbWl0KFwic3RhdGlzdGljcy5jb25uZWN0aW9uc3RhdHNcIixcbiAgICAgICAge1xuICAgICAgICAgICAgXCJiaXRyYXRlXCI6IFBlZXJTdGF0cy5iaXRyYXRlLFxuICAgICAgICAgICAgXCJwYWNrZXRMb3NzXCI6IFBlZXJTdGF0cy5wYWNrZXRMb3NzLFxuICAgICAgICAgICAgXCJiYW5kd2lkdGhcIjogUGVlclN0YXRzLmJhbmR3aWR0aCxcbiAgICAgICAgICAgIFwicmVzb2x1dGlvblwiOiByZXNvbHV0aW9ucyxcbiAgICAgICAgICAgIFwidHJhbnNwb3J0XCI6IFBlZXJTdGF0cy50cmFuc3BvcnRcbiAgICAgICAgfSk7XG4gICAgUGVlclN0YXRzLnRyYW5zcG9ydCA9IFtdO1xuXG59O1xuXG4vKipcbiAqIFN0YXRzIHByb2Nlc3NpbmcgbG9naWMuXG4gKi9cblN0YXRzQ29sbGVjdG9yLnByb3RvdHlwZS5wcm9jZXNzQXVkaW9MZXZlbFJlcG9ydCA9IGZ1bmN0aW9uICgpXG57XG4gICAgaWYgKCF0aGlzLmJhc2VsaW5lQXVkaW9MZXZlbHNSZXBvcnQpXG4gICAge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgZm9yICh2YXIgaWR4IGluIHRoaXMuY3VycmVudEF1ZGlvTGV2ZWxzUmVwb3J0KVxuICAgIHtcbiAgICAgICAgdmFyIG5vdyA9IHRoaXMuY3VycmVudEF1ZGlvTGV2ZWxzUmVwb3J0W2lkeF07XG5cbiAgICAgICAgaWYgKG5vdy50eXBlICE9ICdzc3JjJylcbiAgICAgICAge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgYmVmb3JlID0gdGhpcy5iYXNlbGluZUF1ZGlvTGV2ZWxzUmVwb3J0W2lkeF07XG4gICAgICAgIGlmICghYmVmb3JlKVxuICAgICAgICB7XG4gICAgICAgICAgICBjb25zb2xlLndhcm4oZ2V0U3RhdFZhbHVlKG5vdywgJ3NzcmMnKSArICcgbm90IGVub3VnaCBkYXRhJyk7XG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIHZhciBzc3JjID0gZ2V0U3RhdFZhbHVlKG5vdywgJ3NzcmMnKTtcbiAgICAgICAgdmFyIGppZCA9IEFQUC54bXBwLmdldEppZEZyb21TU1JDKHNzcmMpO1xuICAgICAgICBpZiAoIWppZCAmJiAoRGF0ZS5ub3coKSAtIG5vdy50aW1lc3RhbXApIDwgMzAwMClcbiAgICAgICAge1xuICAgICAgICAgICAgY29uc29sZS53YXJuKFwiTm8gamlkIGZvciBzc3JjOiBcIiArIHNzcmMpO1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgamlkU3RhdHMgPSB0aGlzLmppZDJzdGF0c1tqaWRdO1xuICAgICAgICBpZiAoIWppZFN0YXRzKVxuICAgICAgICB7XG4gICAgICAgICAgICBqaWRTdGF0cyA9IG5ldyBQZWVyU3RhdHMoKTtcbiAgICAgICAgICAgIHRoaXMuamlkMnN0YXRzW2ppZF0gPSBqaWRTdGF0cztcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEF1ZGlvIGxldmVsXG4gICAgICAgIHZhciBhdWRpb0xldmVsID0gbnVsbDtcblxuICAgICAgICB0cnkge1xuICAgICAgICAgICAgYXVkaW9MZXZlbCA9IGdldFN0YXRWYWx1ZShub3csICdhdWRpb0lucHV0TGV2ZWwnKTtcbiAgICAgICAgICAgIGlmICghYXVkaW9MZXZlbClcbiAgICAgICAgICAgICAgICBhdWRpb0xldmVsID0gZ2V0U3RhdFZhbHVlKG5vdywgJ2F1ZGlvT3V0cHV0TGV2ZWwnKTtcbiAgICAgICAgfVxuICAgICAgICBjYXRjaChlKSB7Lypub3Qgc3VwcG9ydGVkKi9cbiAgICAgICAgICAgIGNvbnNvbGUud2FybihcIkF1ZGlvIExldmVscyBhcmUgbm90IGF2YWlsYWJsZSBpbiB0aGUgc3RhdGlzdGljcy5cIik7XG4gICAgICAgICAgICBjbGVhckludGVydmFsKHRoaXMuYXVkaW9MZXZlbHNJbnRlcnZhbElkKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuXG4gICAgICAgIGlmIChhdWRpb0xldmVsKVxuICAgICAgICB7XG4gICAgICAgICAgICAvLyBUT0RPOiBjYW4ndCBmaW5kIHNwZWNzIGFib3V0IHdoYXQgdGhpcyB2YWx1ZSByZWFsbHkgaXMsXG4gICAgICAgICAgICAvLyBidXQgaXQgc2VlbXMgdG8gdmFyeSBiZXR3ZWVuIDAgYW5kIGFyb3VuZCAzMmsuXG4gICAgICAgICAgICBhdWRpb0xldmVsID0gYXVkaW9MZXZlbCAvIDMyNzY3O1xuICAgICAgICAgICAgamlkU3RhdHMuc2V0U3NyY0F1ZGlvTGV2ZWwoc3NyYywgYXVkaW9MZXZlbCk7XG4gICAgICAgICAgICBpZihqaWQgIT0gQVBQLnhtcHAubXlKaWQoKSlcbiAgICAgICAgICAgICAgICB0aGlzLmV2ZW50RW1pdHRlci5lbWl0KFwic3RhdGlzdGljcy5hdWRpb0xldmVsXCIsIGppZCwgYXVkaW9MZXZlbCk7XG4gICAgICAgIH1cblxuICAgIH1cblxuXG59OyIsIi8qKlxuICogQ3JlYXRlZCBieSBocmlzdG8gb24gOC80LzE0LlxuICovXG52YXIgTG9jYWxTdGF0cyA9IHJlcXVpcmUoXCIuL0xvY2FsU3RhdHNDb2xsZWN0b3IuanNcIik7XG52YXIgUlRQU3RhdHMgPSByZXF1aXJlKFwiLi9SVFBTdGF0c0NvbGxlY3Rvci5qc1wiKTtcbnZhciBFdmVudEVtaXR0ZXIgPSByZXF1aXJlKFwiZXZlbnRzXCIpO1xudmFyIFN0cmVhbUV2ZW50VHlwZXMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvU3RyZWFtRXZlbnRUeXBlcy5qc1wiKTtcbnZhciBYTVBQRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UveG1wcC9YTVBQRXZlbnRzXCIpO1xuXG52YXIgZXZlbnRFbWl0dGVyID0gbmV3IEV2ZW50RW1pdHRlcigpO1xuXG52YXIgbG9jYWxTdGF0cyA9IG51bGw7XG5cbnZhciBydHBTdGF0cyA9IG51bGw7XG5cbmZ1bmN0aW9uIHN0b3BMb2NhbCgpXG57XG4gICAgaWYobG9jYWxTdGF0cylcbiAgICB7XG4gICAgICAgIGxvY2FsU3RhdHMuc3RvcCgpO1xuICAgICAgICBsb2NhbFN0YXRzID0gbnVsbDtcbiAgICB9XG59XG5cbmZ1bmN0aW9uIHN0b3BSZW1vdGUoKVxue1xuICAgIGlmKHJ0cFN0YXRzKVxuICAgIHtcbiAgICAgICAgcnRwU3RhdHMuc3RvcCgpO1xuICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChcInN0YXRpc3RpY3Muc3RvcFwiKTtcbiAgICAgICAgcnRwU3RhdHMgPSBudWxsO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gc3RhcnRSZW1vdGVTdGF0cyAocGVlcmNvbm5lY3Rpb24pIHtcbiAgICBpZihydHBTdGF0cylcbiAgICB7XG4gICAgICAgIHJ0cFN0YXRzLnN0b3AoKTtcbiAgICAgICAgcnRwU3RhdHMgPSBudWxsO1xuICAgIH1cblxuICAgIHJ0cFN0YXRzID0gbmV3IFJUUFN0YXRzKHBlZXJjb25uZWN0aW9uLCAyMDAsIDIwMDAsIGV2ZW50RW1pdHRlcik7XG4gICAgcnRwU3RhdHMuc3RhcnQoKTtcbn1cblxuZnVuY3Rpb24gb25TdHJlYW1DcmVhdGVkKHN0cmVhbSlcbntcbiAgICBpZihzdHJlYW0uZ2V0T3JpZ2luYWxTdHJlYW0oKS5nZXRBdWRpb1RyYWNrcygpLmxlbmd0aCA9PT0gMClcbiAgICAgICAgcmV0dXJuO1xuXG4gICAgbG9jYWxTdGF0cyA9IG5ldyBMb2NhbFN0YXRzKHN0cmVhbS5nZXRPcmlnaW5hbFN0cmVhbSgpLCAxMDAsIHN0YXRpc3RpY3MsXG4gICAgICAgIGV2ZW50RW1pdHRlcik7XG4gICAgbG9jYWxTdGF0cy5zdGFydCgpO1xufVxuXG5mdW5jdGlvbiBvbkRpc3Bvc2VDb25mZXJlbmNlKG9uVW5sb2FkKSB7XG4gICAgc3RvcFJlbW90ZSgpO1xuICAgIGlmKG9uVW5sb2FkKSB7XG4gICAgICAgIHN0b3BMb2NhbCgpO1xuICAgICAgICBldmVudEVtaXR0ZXIucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgfVxufVxuXG5cbnZhciBzdGF0aXN0aWNzID1cbntcbiAgICAvKipcbiAgICAgKiBJbmRpY2F0ZXMgdGhhdCB0aGlzIGF1ZGlvIGxldmVsIGlzIGZvciBsb2NhbCBqaWQuXG4gICAgICogQHR5cGUge3N0cmluZ31cbiAgICAgKi9cbiAgICBMT0NBTF9KSUQ6ICdsb2NhbCcsXG5cbiAgICBhZGRBdWRpb0xldmVsTGlzdGVuZXI6IGZ1bmN0aW9uKGxpc3RlbmVyKVxuICAgIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLm9uKFwic3RhdGlzdGljcy5hdWRpb0xldmVsXCIsIGxpc3RlbmVyKTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlQXVkaW9MZXZlbExpc3RlbmVyOiBmdW5jdGlvbihsaXN0ZW5lcilcbiAgICB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5yZW1vdmVMaXN0ZW5lcihcInN0YXRpc3RpY3MuYXVkaW9MZXZlbFwiLCBsaXN0ZW5lcik7XG4gICAgfSxcblxuICAgIGFkZENvbm5lY3Rpb25TdGF0c0xpc3RlbmVyOiBmdW5jdGlvbihsaXN0ZW5lcilcbiAgICB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5vbihcInN0YXRpc3RpY3MuY29ubmVjdGlvbnN0YXRzXCIsIGxpc3RlbmVyKTtcbiAgICB9LFxuXG4gICAgcmVtb3ZlQ29ubmVjdGlvblN0YXRzTGlzdGVuZXI6IGZ1bmN0aW9uKGxpc3RlbmVyKVxuICAgIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLnJlbW92ZUxpc3RlbmVyKFwic3RhdGlzdGljcy5jb25uZWN0aW9uc3RhdHNcIiwgbGlzdGVuZXIpO1xuICAgIH0sXG5cblxuICAgIGFkZFJlbW90ZVN0YXRzU3RvcExpc3RlbmVyOiBmdW5jdGlvbihsaXN0ZW5lcilcbiAgICB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5vbihcInN0YXRpc3RpY3Muc3RvcFwiLCBsaXN0ZW5lcik7XG4gICAgfSxcblxuICAgIHJlbW92ZVJlbW90ZVN0YXRzU3RvcExpc3RlbmVyOiBmdW5jdGlvbihsaXN0ZW5lcilcbiAgICB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5yZW1vdmVMaXN0ZW5lcihcInN0YXRpc3RpY3Muc3RvcFwiLCBsaXN0ZW5lcik7XG4gICAgfSxcblxuICAgIHN0b3A6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgc3RvcExvY2FsKCk7XG4gICAgICAgIHN0b3BSZW1vdGUoKTtcbiAgICAgICAgaWYoZXZlbnRFbWl0dGVyKVxuICAgICAgICB7XG4gICAgICAgICAgICBldmVudEVtaXR0ZXIucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgc3RvcFJlbW90ZVN0YXRpc3RpY3M6IGZ1bmN0aW9uKClcbiAgICB7XG4gICAgICAgIHN0b3BSZW1vdGUoKTtcbiAgICB9LFxuXG4gICAgc3RhcnQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgQVBQLlJUQy5hZGRTdHJlYW1MaXN0ZW5lcihvblN0cmVhbUNyZWF0ZWQsXG4gICAgICAgICAgICBTdHJlYW1FdmVudFR5cGVzLkVWRU5UX1RZUEVfTE9DQUxfQ1JFQVRFRCk7XG4gICAgICAgIEFQUC54bXBwLmFkZExpc3RlbmVyKFhNUFBFdmVudHMuRElTUE9TRV9DT05GRVJFTkNFLCBvbkRpc3Bvc2VDb25mZXJlbmNlKTtcbiAgICAgICAgQVBQLnhtcHAuYWRkTGlzdGVuZXIoWE1QUEV2ZW50cy5DQUxMX0lOQ09NSU5HLCBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgICAgIHN0YXJ0UmVtb3RlU3RhdHMoZXZlbnQucGVlcmNvbm5lY3Rpb24pO1xuICAgICAgICB9KTtcbiAgICB9XG5cbn07XG5cblxuXG5cbm1vZHVsZS5leHBvcnRzID0gc3RhdGlzdGljczsiLCJ2YXIgaTE4biA9IHJlcXVpcmUoXCJpMThuZXh0LWNsaWVudFwiKTtcbnZhciBsYW5ndWFnZXMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS90cmFuc2xhdGlvbi9sYW5ndWFnZXNcIik7XG52YXIgREVGQVVMVF9MQU5HID0gbGFuZ3VhZ2VzLkVOO1xudmFyIGluaXRpYWxpemVkID0gZmFsc2U7XG52YXIgd2FpdGluZ0ZvckluaXQgPSBbXTtcblxuaTE4bi5hZGRQb3N0UHJvY2Vzc29yKFwicmVzb2x2ZUFwcE5hbWVcIiwgZnVuY3Rpb24odmFsdWUsIGtleSwgb3B0aW9ucykge1xuICAgIHJldHVybiB2YWx1ZS5yZXBsYWNlKFwiX19hcHBfX1wiLCBpbnRlcmZhY2VDb25maWcuQVBQX05BTUUpO1xufSk7XG5cblxuXG52YXIgZGVmYXVsdE9wdGlvbnMgPSB7XG4gICAgZGV0ZWN0TG5nUVM6IFwibGFuZ1wiLFxuICAgIHVzZUNvb2tpZTogZmFsc2UsXG4gICAgZmFsbGJhY2tMbmc6IERFRkFVTFRfTEFORyxcbiAgICBsb2FkOiBcInVuc3BlY2lmaWNcIixcbiAgICByZXNHZXRQYXRoOiAnbGFuZy9fX25zX18tX19sbmdfXy5qc29uJyxcbiAgICBuczoge1xuICAgICAgICBuYW1lc3BhY2VzOiBbJ21haW4nLCAnbGFuZ3VhZ2VzJ10sXG4gICAgICAgIGRlZmF1bHROczogJ21haW4nXG4gICAgfSxcbiAgICBsbmdXaGl0ZWxpc3QgOiBsYW5ndWFnZXMuZ2V0TGFuZ3VhZ2VzKCksXG4gICAgZmFsbGJhY2tPbk51bGw6IHRydWUsXG4gICAgdXNlRGF0YUF0dHJPcHRpb25zOiB0cnVlLFxuICAgIGFwcDogaW50ZXJmYWNlQ29uZmlnLkFQUF9OQU1FLFxuICAgIGdldEFzeW5jOiB0cnVlLFxuICAgIGN1c3RvbUxvYWQ6IGZ1bmN0aW9uKGxuZywgbnMsIG9wdGlvbnMsIGRvbmUpIHtcbiAgICAgICAgdmFyIHJlc1BhdGggPSBcImxhbmcvX19uc19fLV9fbG5nX18uanNvblwiO1xuICAgICAgICBpZihsbmcgPT09IGxhbmd1YWdlcy5FTilcbiAgICAgICAgICAgIHJlc1BhdGggPSBcImxhbmcvX19uc19fLmpzb25cIjtcbiAgICAgICAgdmFyIHVybCA9IGkxOG4uZnVuY3Rpb25zLmFwcGx5UmVwbGFjZW1lbnQocmVzUGF0aCwgeyBsbmc6IGxuZywgbnM6IG5zIH0pO1xuICAgICAgICBpbml0aWFsaXplZCA9IGZhbHNlO1xuICAgICAgICBpMThuLmZ1bmN0aW9ucy5hamF4KHtcbiAgICAgICAgICAgIHVybDogdXJsLFxuICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24oZGF0YSwgc3RhdHVzLCB4aHIpIHtcbiAgICAgICAgICAgICAgICBpMThuLmZ1bmN0aW9ucy5sb2coJ2xvYWRlZDogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgZG9uZShudWxsLCBkYXRhKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBlcnJvciA6IGZ1bmN0aW9uKHhociwgc3RhdHVzLCBlcnJvcikge1xuICAgICAgICAgICAgICAgIGlmICgoc3RhdHVzICYmIHN0YXR1cyA9PSAyMDApIHx8XG4gICAgICAgICAgICAgICAgICAgICh4aHIgJiYgeGhyLnN0YXR1cyAmJiB4aHIuc3RhdHVzID09IDIwMCkpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gZmlsZSBsb2FkZWQgYnV0IGludmFsaWQganNvbiwgc3RvcCB3YXN0ZSB0aW1lICFcbiAgICAgICAgICAgICAgICAgICAgaTE4bi5mdW5jdGlvbnMuZXJyb3IoJ1RoZXJlIGlzIGEgdHlwbyBpbjogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICgoc3RhdHVzICYmIHN0YXR1cyA9PSA0MDQpIHx8XG4gICAgICAgICAgICAgICAgICAgICh4aHIgJiYgeGhyLnN0YXR1cyAmJiB4aHIuc3RhdHVzID09IDQwNCkpIHtcbiAgICAgICAgICAgICAgICAgICAgaTE4bi5mdW5jdGlvbnMubG9nKCdEb2VzIG5vdCBleGlzdDogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHRoZVN0YXR1cyA9IHN0YXR1cyA/IHN0YXR1cyA6XG4gICAgICAgICAgICAgICAgICAgICAgICAoKHhociAmJiB4aHIuc3RhdHVzKSA/IHhoci5zdGF0dXMgOiBudWxsKTtcbiAgICAgICAgICAgICAgICAgICAgaTE4bi5mdW5jdGlvbnMubG9nKHRoZVN0YXR1cyArICcgd2hlbiBsb2FkaW5nICcgKyB1cmwpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIGRvbmUoZXJyb3IsIHt9KTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBkYXRhVHlwZTogXCJqc29uXCIsXG4gICAgICAgICAgICBhc3luYyA6IG9wdGlvbnMuZ2V0QXN5bmNcbiAgICAgICAgfSk7XG4gICAgfVxuICAgIC8vICAgICAgICAgICAgICBvcHRpb25zIGZvciBjYWNoaW5nXG4vLyAgICAgICAgICAgICAgICB1c2VMb2NhbFN0b3JhZ2U6IHRydWUsXG4vLyAgICAgICAgICAgICAgICBsb2NhbFN0b3JhZ2VFeHBpcmF0aW9uVGltZTogODY0MDAwMDAgLy8gaW4gbXMsIGRlZmF1bHQgMSB3ZWVrXG59O1xuXG5mdW5jdGlvbiBpbml0Q29tcGxldGVkKHQpXG57XG4gICAgaW5pdGlhbGl6ZWQgPSB0cnVlO1xuICAgICQoXCJbZGF0YS1pMThuXVwiKS5pMThuKCk7XG4gICAgZm9yKHZhciBpID0gMDsgaSA8IHdhaXRpbmdGb3JJbml0Lmxlbmd0aDsgaSsrKVxuICAgIHtcbiAgICAgICAgdmFyIG9iaiA9IHdhaXRpbmdGb3JJbml0W2ldO1xuICAgICAgICBvYmouY2FsbGJhY2soaTE4bi50KG9iai5rZXkpKTtcbiAgICB9XG4gICAgd2FpdGluZ0ZvckluaXQgPSBbXTtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICAgaW5pdDogZnVuY3Rpb24gKGxhbmcpIHtcbiAgICAgICAgaW5pdGlhbGl6ZWQgPSBmYWxzZTtcbiAgICAgICAgdmFyIG9wdGlvbnMgPSBkZWZhdWx0T3B0aW9ucztcbiAgICAgICAgaWYobGFuZylcbiAgICAgICAgICAgIG9wdGlvbnMubG5nID0gbGFuZztcbiAgICAgICAgaTE4bi5pbml0KG9wdGlvbnMsIGluaXRDb21wbGV0ZWQpO1xuICAgIH0sXG4gICAgdHJhbnNsYXRlU3RyaW5nOiBmdW5jdGlvbiAoa2V5LCBjYikge1xuICAgICAgICBpZighY2IpXG4gICAgICAgICAgICByZXR1cm4gaTE4bi50KGtleSk7XG5cbiAgICAgICAgaWYoaW5pdGlhbGl6ZWQpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNiKGkxOG4udChrZXkpKTtcbiAgICAgICAgfVxuICAgICAgICBlbHNlXG4gICAgICAgIHtcbiAgICAgICAgICAgIHdhaXRpbmdGb3JJbml0LnB1c2goe1wiY2FsbGJhY2tcIjogY2IsIFwia2V5XCI6IGtleX0pO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBzZXRMYW5ndWFnZTogZnVuY3Rpb24gKGxhbmcpIHtcbiAgICAgICAgaW5pdGlhbGl6ZWQgPSBmYWxzZTtcbiAgICAgICAgaWYoIWxhbmcpXG4gICAgICAgICAgICBsYW5nID0gREVGQVVMVF9MQU5HO1xuICAgICAgICBpMThuLnNldExuZyhsYW5nLCBkZWZhdWx0T3B0aW9ucywgaW5pdENvbXBsZXRlZCk7XG4gICAgfSxcbiAgICBnZXRDdXJyZW50TGFuZ3VhZ2U6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGkxOG4ubG5nKCk7XG4gICAgfSxcbiAgICB0cmFuc2xhdGVFbGVtZW50OiBmdW5jdGlvbiAoc2VsZWN0b3IpIHtcbiAgICAgICAgc2VsZWN0b3IuaTE4bigpO1xuICAgIH1cbn07XG4iLCIvKiBqc2hpbnQgLVcxMTcgKi9cbnZhciBUcmFjZWFibGVQZWVyQ29ubmVjdGlvbiA9IHJlcXVpcmUoXCIuL1RyYWNlYWJsZVBlZXJDb25uZWN0aW9uXCIpO1xudmFyIFNEUERpZmZlciA9IHJlcXVpcmUoXCIuL1NEUERpZmZlclwiKTtcbnZhciBTRFBVdGlsID0gcmVxdWlyZShcIi4vU0RQVXRpbFwiKTtcbnZhciBTRFAgPSByZXF1aXJlKFwiLi9TRFBcIik7XG52YXIgUlRDQnJvd3NlclR5cGUgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS9SVEMvUlRDQnJvd3NlclR5cGVcIik7XG5cbi8vIEppbmdsZSBzdHVmZlxuZnVuY3Rpb24gSmluZ2xlU2Vzc2lvbihtZSwgc2lkLCBjb25uZWN0aW9uLCBzZXJ2aWNlKSB7XG4gICAgdGhpcy5tZSA9IG1lO1xuICAgIHRoaXMuc2lkID0gc2lkO1xuICAgIHRoaXMuY29ubmVjdGlvbiA9IGNvbm5lY3Rpb247XG4gICAgdGhpcy5pbml0aWF0b3IgPSBudWxsO1xuICAgIHRoaXMucmVzcG9uZGVyID0gbnVsbDtcbiAgICB0aGlzLmlzSW5pdGlhdG9yID0gbnVsbDtcbiAgICB0aGlzLnBlZXJqaWQgPSBudWxsO1xuICAgIHRoaXMuc3RhdGUgPSBudWxsO1xuICAgIHRoaXMubG9jYWxTRFAgPSBudWxsO1xuICAgIHRoaXMucmVtb3RlU0RQID0gbnVsbDtcbiAgICB0aGlzLnJlbGF5ZWRTdHJlYW1zID0gW107XG4gICAgdGhpcy5zdGFydFRpbWUgPSBudWxsO1xuICAgIHRoaXMuc3RvcFRpbWUgPSBudWxsO1xuICAgIHRoaXMubWVkaWFfY29uc3RyYWludHMgPSBudWxsO1xuICAgIHRoaXMucGNfY29uc3RyYWludHMgPSBudWxsO1xuICAgIHRoaXMuaWNlX2NvbmZpZyA9IHt9O1xuICAgIHRoaXMuZHJpcF9jb250YWluZXIgPSBbXTtcbiAgICB0aGlzLnNlcnZpY2UgPSBzZXJ2aWNlO1xuXG4gICAgdGhpcy51c2V0cmlja2xlID0gdHJ1ZTtcbiAgICB0aGlzLnVzZXByYW5zd2VyID0gZmFsc2U7IC8vIGVhcmx5IHRyYW5zcG9ydCB3YXJtdXAgLS0gbWluZCB5b3UsIHRoaXMgbWlnaHQgZmFpbC4gZGVwZW5kcyBvbiB3ZWJydGMgaXNzdWUgMTcxOFxuICAgIHRoaXMudXNlZHJpcCA9IGZhbHNlOyAvLyBkcmlwcGluZyBpcyBzZW5kaW5nIHRyaWNrbGUgY2FuZGlkYXRlcyBub3Qgb25lLWJ5LW9uZVxuXG4gICAgdGhpcy5oYWRzdHVuY2FuZGlkYXRlID0gZmFsc2U7XG4gICAgdGhpcy5oYWR0dXJuY2FuZGlkYXRlID0gZmFsc2U7XG4gICAgdGhpcy5sYXN0aWNlY2FuZGlkYXRlID0gZmFsc2U7XG5cbiAgICB0aGlzLnN0YXRzaW50ZXJ2YWwgPSBudWxsO1xuXG4gICAgdGhpcy5yZWFzb24gPSBudWxsO1xuXG4gICAgdGhpcy5hZGRzc3JjID0gW107XG4gICAgdGhpcy5yZW1vdmVzc3JjID0gW107XG4gICAgdGhpcy5wZW5kaW5nb3AgPSBudWxsO1xuICAgIHRoaXMuc3dpdGNoc3RyZWFtcyA9IGZhbHNlO1xuXG4gICAgdGhpcy53YWl0ID0gdHJ1ZTtcbiAgICB0aGlzLmxvY2FsU3RyZWFtc1NTUkMgPSBudWxsO1xuXG4gICAgLyoqXG4gICAgICogVGhlIGluZGljYXRvciB3aGljaCBkZXRlcm1pbmVzIHdoZXRoZXIgdGhlIChsb2NhbCkgdmlkZW8gaGFzIGJlZW4gbXV0ZWRcbiAgICAgKiBpbiByZXNwb25zZSB0byBhIHVzZXIgY29tbWFuZCBpbiBjb250cmFzdCB0byBhbiBhdXRvbWF0aWMgZGVjaXNpb24gbWFkZVxuICAgICAqIGJ5IHRoZSBhcHBsaWNhdGlvbiBsb2dpYy5cbiAgICAgKi9cbiAgICB0aGlzLnZpZGVvTXV0ZUJ5VXNlciA9IGZhbHNlO1xufVxuXG4vL1RPRE86IHRoaXMgYXJyYXkgbXVzdCBiZSByZW1vdmVkIHdoZW4gZmlyZWZveCBpbXBsZW1lbnQgbXVsdGlzdHJlYW0gc3VwcG9ydFxuSmluZ2xlU2Vzc2lvbi5ub3RSZWNlaXZlZFNTUkNzID0gW107XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLmluaXRpYXRlID0gZnVuY3Rpb24gKHBlZXJqaWQsIGlzSW5pdGlhdG9yKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGlmICh0aGlzLnN0YXRlICE9PSBudWxsKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ2F0dGVtcHQgdG8gaW5pdGlhdGUgb24gc2Vzc2lvbiAnICsgdGhpcy5zaWQgK1xuICAgICAgICAgICAgJ2luIHN0YXRlICcgKyB0aGlzLnN0YXRlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbiAgICB0aGlzLmlzSW5pdGlhdG9yID0gaXNJbml0aWF0b3I7XG4gICAgdGhpcy5zdGF0ZSA9ICdwZW5kaW5nJztcbiAgICB0aGlzLmluaXRpYXRvciA9IGlzSW5pdGlhdG9yID8gdGhpcy5tZSA6IHBlZXJqaWQ7XG4gICAgdGhpcy5yZXNwb25kZXIgPSAhaXNJbml0aWF0b3IgPyB0aGlzLm1lIDogcGVlcmppZDtcbiAgICB0aGlzLnBlZXJqaWQgPSBwZWVyamlkO1xuICAgIHRoaXMuaGFkc3R1bmNhbmRpZGF0ZSA9IGZhbHNlO1xuICAgIHRoaXMuaGFkdHVybmNhbmRpZGF0ZSA9IGZhbHNlO1xuICAgIHRoaXMubGFzdGljZWNhbmRpZGF0ZSA9IGZhbHNlO1xuXG4gICAgdGhpcy5wZWVyY29ubmVjdGlvblxuICAgICAgICA9IG5ldyBUcmFjZWFibGVQZWVyQ29ubmVjdGlvbihcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5qaW5nbGUuaWNlX2NvbmZpZyxcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5qaW5nbGUucGNfY29uc3RyYWludHMgKTtcblxuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25pY2VjYW5kaWRhdGUgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgc2VsZi5zZW5kSWNlQ2FuZGlkYXRlKGV2ZW50LmNhbmRpZGF0ZSk7XG4gICAgfTtcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLm9uYWRkc3RyZWFtID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiUkVNT1RFIFNUUkVBTSBBRERFRDogXCIgKyBldmVudC5zdHJlYW0gKyBcIiAtIFwiICsgZXZlbnQuc3RyZWFtLmlkKTtcbiAgICAgICAgc2VsZi5yZW1vdGVTdHJlYW1BZGRlZChldmVudCk7XG4gICAgfTtcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLm9ucmVtb3Zlc3RyZWFtID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIC8vIFJlbW92ZSB0aGUgc3RyZWFtIGZyb20gcmVtb3RlU3RyZWFtc1xuICAgICAgICAvLyBGSVhNRTogcmVtb3Rlc3RyZWFtcmVtb3ZlZC5qaW5nbGUgbm90IGRlZmluZWQgYW55d2hlcmUodW51c2VkKVxuICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdyZW1vdGVzdHJlYW1yZW1vdmVkLmppbmdsZScsIFtldmVudCwgc2VsZi5zaWRdKTtcbiAgICB9O1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25zaWduYWxpbmdzdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBpZiAoIShzZWxmICYmIHNlbGYucGVlcmNvbm5lY3Rpb24pKSByZXR1cm47XG4gICAgfTtcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLm9uaWNlY29ubmVjdGlvbnN0YXRlY2hhbmdlID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIGlmICghKHNlbGYgJiYgc2VsZi5wZWVyY29ubmVjdGlvbikpIHJldHVybjtcbiAgICAgICAgc3dpdGNoIChzZWxmLnBlZXJjb25uZWN0aW9uLmljZUNvbm5lY3Rpb25TdGF0ZSkge1xuICAgICAgICAgICAgY2FzZSAnY29ubmVjdGVkJzpcbiAgICAgICAgICAgICAgICB0aGlzLnN0YXJ0VGltZSA9IG5ldyBEYXRlKCk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlICdkaXNjb25uZWN0ZWQnOlxuICAgICAgICAgICAgICAgIHRoaXMuc3RvcFRpbWUgPSBuZXcgRGF0ZSgpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIG9uSWNlQ29ubmVjdGlvblN0YXRlQ2hhbmdlKHNlbGYuc2lkLCBzZWxmKTtcbiAgICB9O1xuICAgIC8vIGFkZCBhbnkgbG9jYWwgYW5kIHJlbGF5ZWQgc3RyZWFtXG4gICAgQVBQLlJUQy5sb2NhbFN0cmVhbXMuZm9yRWFjaChmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5hZGRTdHJlYW0oc3RyZWFtLmdldE9yaWdpbmFsU3RyZWFtKCkpO1xuICAgIH0pO1xuICAgIHRoaXMucmVsYXllZFN0cmVhbXMuZm9yRWFjaChmdW5jdGlvbihzdHJlYW0pIHtcbiAgICAgICAgc2VsZi5wZWVyY29ubmVjdGlvbi5hZGRTdHJlYW0oc3RyZWFtKTtcbiAgICB9KTtcbn07XG5cbmZ1bmN0aW9uIG9uSWNlQ29ubmVjdGlvblN0YXRlQ2hhbmdlKHNpZCwgc2Vzc2lvbikge1xuICAgIHN3aXRjaCAoc2Vzc2lvbi5wZWVyY29ubmVjdGlvbi5pY2VDb25uZWN0aW9uU3RhdGUpIHtcbiAgICAgICAgY2FzZSAnY2hlY2tpbmcnOlxuICAgICAgICAgICAgc2Vzc2lvbi50aW1lQ2hlY2tpbmcgPSAobmV3IERhdGUoKSkuZ2V0VGltZSgpO1xuICAgICAgICAgICAgc2Vzc2lvbi5maXJzdGNvbm5lY3QgPSB0cnVlO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ2NvbXBsZXRlZCc6IC8vIG9uIGNhbGxlciBzaWRlXG4gICAgICAgIGNhc2UgJ2Nvbm5lY3RlZCc6XG4gICAgICAgICAgICBpZiAoc2Vzc2lvbi5maXJzdGNvbm5lY3QpIHtcbiAgICAgICAgICAgICAgICBzZXNzaW9uLmZpcnN0Y29ubmVjdCA9IGZhbHNlO1xuICAgICAgICAgICAgICAgIHZhciBtZXRhZGF0YSA9IHt9O1xuICAgICAgICAgICAgICAgIG1ldGFkYXRhLnNldHVwVGltZVxuICAgICAgICAgICAgICAgICAgICA9IChuZXcgRGF0ZSgpKS5nZXRUaW1lKCkgLSBzZXNzaW9uLnRpbWVDaGVja2luZztcbiAgICAgICAgICAgICAgICBzZXNzaW9uLnBlZXJjb25uZWN0aW9uLmdldFN0YXRzKGZ1bmN0aW9uIChyZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYocmVzICYmIHJlcy5yZXN1bHQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlcy5yZXN1bHQoKS5mb3JFYWNoKGZ1bmN0aW9uIChyZXBvcnQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAocmVwb3J0LnR5cGUgPT0gJ2dvb2dDYW5kaWRhdGVQYWlyJyAmJlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXBvcnQuc3RhdCgnZ29vZ0FjdGl2ZUNvbm5lY3Rpb24nKSA9PSAndHJ1ZScpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEubG9jYWxDYW5kaWRhdGVUeXBlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IHJlcG9ydC5zdGF0KCdnb29nTG9jYWxDYW5kaWRhdGVUeXBlJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhLnJlbW90ZUNhbmRpZGF0ZVR5cGVcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgID0gcmVwb3J0LnN0YXQoJ2dvb2dSZW1vdGVDYW5kaWRhdGVUeXBlJyk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gbG9nIHBhaXIgYXMgd2VsbCBzbyB3ZSBjYW4gZ2V0IG5pY2UgcGllXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIGNoYXJ0c1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRhZGF0YS5jYW5kaWRhdGVQYWlyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICA9IHJlcG9ydC5zdGF0KCdnb29nTG9jYWxDYW5kaWRhdGVUeXBlJykgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICc7JyArXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVwb3J0LnN0YXQoJ2dvb2dSZW1vdGVDYW5kaWRhdGVUeXBlJyk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHJlcG9ydC5zdGF0KCdnb29nUmVtb3RlQWRkcmVzcycpLmluZGV4T2YoJ1snKSA9PT0gMClcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbWV0YWRhdGEuaXB2NiA9IHRydWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgYnJlYWs7XG4gICAgfVxufVxuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5hY2NlcHQgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMuc3RhdGUgPSAnYWN0aXZlJztcblxuICAgIHZhciBwcmFuc3dlciA9IHRoaXMucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbjtcbiAgICBpZiAoIXByYW5zd2VyIHx8IHByYW5zd2VyLnR5cGUgIT0gJ3ByYW5zd2VyJykge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGNvbnNvbGUubG9nKCdnb2luZyBmcm9tIHByYW5zd2VyIHRvIGFuc3dlcicpO1xuICAgIGlmICh0aGlzLnVzZXRyaWNrbGUpIHtcbiAgICAgICAgLy8gcmVtb3ZlIGNhbmRpZGF0ZXMgYWxyZWFkeSBzZW50IGZyb20gc2Vzc2lvbi1hY2NlcHRcbiAgICAgICAgdmFyIGxpbmVzID0gU0RQVXRpbC5maW5kX2xpbmVzKHByYW5zd2VyLnNkcCwgJ2E9Y2FuZGlkYXRlOicpO1xuICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBwcmFuc3dlci5zZHAgPSBwcmFuc3dlci5zZHAucmVwbGFjZShsaW5lc1tpXSArICdcXHJcXG4nLCAnJyk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgd2hpbGUgKFNEUFV0aWwuZmluZF9saW5lKHByYW5zd2VyLnNkcCwgJ2E9aW5hY3RpdmUnKSkge1xuICAgICAgICAvLyBGSVhNRTogY2hhbmdlIGFueSBpbmFjdGl2ZSB0byBzZW5kcmVjdiBvciB3aGF0ZXZlciB0aGV5IHdlcmUgb3JpZ2luYWxseVxuICAgICAgICBwcmFuc3dlci5zZHAgPSBwcmFuc3dlci5zZHAucmVwbGFjZSgnYT1pbmFjdGl2ZScsICdhPXNlbmRyZWN2Jyk7XG4gICAgfVxuICAgIHByYW5zd2VyID0gQVBQLnNpbXVsY2FzdC5yZXZlcnNlVHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbihwcmFuc3dlcik7XG4gICAgdmFyIHByc2RwID0gbmV3IFNEUChwcmFuc3dlci5zZHApO1xuICAgIHZhciBhY2NlcHQgPSAkaXEoe3RvOiB0aGlzLnBlZXJqaWQsXG4gICAgICAgIHR5cGU6ICdzZXQnfSlcbiAgICAgICAgLmMoJ2ppbmdsZScsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZToxJyxcbiAgICAgICAgICAgIGFjdGlvbjogJ3Nlc3Npb24tYWNjZXB0JyxcbiAgICAgICAgICAgIGluaXRpYXRvcjogdGhpcy5pbml0aWF0b3IsXG4gICAgICAgICAgICByZXNwb25kZXI6IHRoaXMucmVzcG9uZGVyLFxuICAgICAgICAgICAgc2lkOiB0aGlzLnNpZCB9KTtcbiAgICBwcnNkcC50b0ppbmdsZShhY2NlcHQsIHRoaXMuaW5pdGlhdG9yID09IHRoaXMubWUgPyAnaW5pdGlhdG9yJyA6ICdyZXNwb25kZXInLCB0aGlzLmxvY2FsU3RyZWFtc1NTUkMpO1xuICAgIHZhciBzZHAgPSB0aGlzLnBlZXJjb25uZWN0aW9uLmxvY2FsRGVzY3JpcHRpb24uc2RwO1xuICAgIHdoaWxlIChTRFBVdGlsLmZpbmRfbGluZShzZHAsICdhPWluYWN0aXZlJykpIHtcbiAgICAgICAgLy8gRklYTUU6IGNoYW5nZSBhbnkgaW5hY3RpdmUgdG8gc2VuZHJlY3Ygb3Igd2hhdGV2ZXIgdGhleSB3ZXJlIG9yaWdpbmFsbHlcbiAgICAgICAgc2RwID0gc2RwLnJlcGxhY2UoJ2E9aW5hY3RpdmUnLCAnYT1zZW5kcmVjdicpO1xuICAgIH1cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5zZXRMb2NhbERlc2NyaXB0aW9uKG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe3R5cGU6ICdhbnN3ZXInLCBzZHA6IHNkcH0pLFxuICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAvL2NvbnNvbGUubG9nKCdzZXRMb2NhbERlc2NyaXB0aW9uIHN1Y2Nlc3MnKTtcbiAgICAgICAgICAgIHNlbGYuc2V0TG9jYWxEZXNjcmlwdGlvbigpO1xuXG4gICAgICAgICAgICBzZWxmLmNvbm5lY3Rpb24uc2VuZElRKGFjY2VwdCxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBhY2sgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgYWNrLnNvdXJjZSA9ICdhbnN3ZXInO1xuICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdhY2suamluZ2xlJywgW3NlbGYuc2lkLCBhY2tdKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChzdGFuemEpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGVycm9yID0gKCQoc3RhbnphKS5maW5kKCdlcnJvcicpLmxlbmd0aCkgPyB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb2RlOiAkKHN0YW56YSkuZmluZCgnZXJyb3InKS5hdHRyKCdjb2RlJyksXG4gICAgICAgICAgICAgICAgICAgICAgICByZWFzb246ICQoc3RhbnphKS5maW5kKCdlcnJvciA6Zmlyc3QnKVswXS50YWdOYW1lXG4gICAgICAgICAgICAgICAgICAgIH06e307XG4gICAgICAgICAgICAgICAgICAgIGVycm9yLnNvdXJjZSA9ICdhbnN3ZXInO1xuICAgICAgICAgICAgICAgICAgICBKaW5nbGVTZXNzaW9uLm9uSmluZ2xlRXJyb3Ioc2VsZi5zaWQsIGVycm9yKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIDEwMDAwKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ3NldExvY2FsRGVzY3JpcHRpb24gZmFpbGVkJywgZSk7XG4gICAgICAgIH1cbiAgICApO1xufTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUudGVybWluYXRlID0gZnVuY3Rpb24gKHJlYXNvbikge1xuICAgIHRoaXMuc3RhdGUgPSAnZW5kZWQnO1xuICAgIHRoaXMucmVhc29uID0gcmVhc29uO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uY2xvc2UoKTtcbiAgICBpZiAodGhpcy5zdGF0c2ludGVydmFsICE9PSBudWxsKSB7XG4gICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKHRoaXMuc3RhdHNpbnRlcnZhbCk7XG4gICAgICAgIHRoaXMuc3RhdHNpbnRlcnZhbCA9IG51bGw7XG4gICAgfVxufTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuYWN0aXZlID0gZnVuY3Rpb24gKCkge1xuICAgIHJldHVybiB0aGlzLnN0YXRlID09ICdhY3RpdmUnO1xufTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuc2VuZEljZUNhbmRpZGF0ZSA9IGZ1bmN0aW9uIChjYW5kaWRhdGUpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgaWYgKGNhbmRpZGF0ZSAmJiAhdGhpcy5sYXN0aWNlY2FuZGlkYXRlKSB7XG4gICAgICAgIHZhciBpY2UgPSBTRFBVdGlsLmljZXBhcmFtcyh0aGlzLmxvY2FsU0RQLm1lZGlhW2NhbmRpZGF0ZS5zZHBNTGluZUluZGV4XSwgdGhpcy5sb2NhbFNEUC5zZXNzaW9uKTtcbiAgICAgICAgdmFyIGpjYW5kID0gU0RQVXRpbC5jYW5kaWRhdGVUb0ppbmdsZShjYW5kaWRhdGUuY2FuZGlkYXRlKTtcbiAgICAgICAgaWYgKCEoaWNlICYmIGpjYW5kKSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignZmFpbGVkIHRvIGdldCBpY2UgJiYgamNhbmQnKTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICBpY2UueG1sbnMgPSAndXJuOnhtcHA6amluZ2xlOnRyYW5zcG9ydHM6aWNlLXVkcDoxJztcblxuICAgICAgICBpZiAoamNhbmQudHlwZSA9PT0gJ3NyZmx4Jykge1xuICAgICAgICAgICAgdGhpcy5oYWRzdHVuY2FuZGlkYXRlID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIGlmIChqY2FuZC50eXBlID09PSAncmVsYXknKSB7XG4gICAgICAgICAgICB0aGlzLmhhZHR1cm5jYW5kaWRhdGUgPSB0cnVlO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKHRoaXMudXNldHJpY2tsZSkge1xuICAgICAgICAgICAgaWYgKHRoaXMudXNlZHJpcCkge1xuICAgICAgICAgICAgICAgIGlmICh0aGlzLmRyaXBfY29udGFpbmVyLmxlbmd0aCA9PT0gMCkge1xuICAgICAgICAgICAgICAgICAgICAvLyBzdGFydCAyMG1zIGNhbGxvdXRcbiAgICAgICAgICAgICAgICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHNlbGYuZHJpcF9jb250YWluZXIubGVuZ3RoID09PSAwKSByZXR1cm47XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnNlbmRJY2VDYW5kaWRhdGVzKHNlbGYuZHJpcF9jb250YWluZXIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5kcmlwX2NvbnRhaW5lciA9IFtdO1xuICAgICAgICAgICAgICAgICAgICB9LCAyMCk7XG5cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgdGhpcy5kcmlwX2NvbnRhaW5lci5wdXNoKGNhbmRpZGF0ZSk7XG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzZWxmLnNlbmRJY2VDYW5kaWRhdGUoW2NhbmRpZGF0ZV0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgLy9jb25zb2xlLmxvZygnc2VuZEljZUNhbmRpZGF0ZTogbGFzdCBjYW5kaWRhdGUuJyk7XG4gICAgICAgIGlmICghdGhpcy51c2V0cmlja2xlKSB7XG4gICAgICAgICAgICAvL2NvbnNvbGUubG9nKCdzaG91bGQgc2VuZCBmdWxsIG9mZmVyIG5vdy4uLicpO1xuICAgICAgICAgICAgdmFyIGluaXQgPSAkaXEoe3RvOiB0aGlzLnBlZXJqaWQsXG4gICAgICAgICAgICAgICAgdHlwZTogJ3NldCd9KVxuICAgICAgICAgICAgICAgIC5jKCdqaW5nbGUnLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6MScsXG4gICAgICAgICAgICAgICAgICAgIGFjdGlvbjogdGhpcy5wZWVyY29ubmVjdGlvbi5sb2NhbERlc2NyaXB0aW9uLnR5cGUgPT0gJ29mZmVyJyA/ICdzZXNzaW9uLWluaXRpYXRlJyA6ICdzZXNzaW9uLWFjY2VwdCcsXG4gICAgICAgICAgICAgICAgICAgIGluaXRpYXRvcjogdGhpcy5pbml0aWF0b3IsXG4gICAgICAgICAgICAgICAgICAgIHNpZDogdGhpcy5zaWR9KTtcbiAgICAgICAgICAgIHRoaXMubG9jYWxTRFAgPSBuZXcgU0RQKHRoaXMucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbi5zZHApO1xuICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgICAgdmFyIHNlbmRKaW5nbGUgPSBmdW5jdGlvbiAoc3NyYykge1xuICAgICAgICAgICAgICAgIGlmKCFzc3JjKVxuICAgICAgICAgICAgICAgICAgICBzc3JjID0ge307XG4gICAgICAgICAgICAgICAgc2VsZi5sb2NhbFNEUC50b0ppbmdsZShpbml0LCBzZWxmLmluaXRpYXRvciA9PSBzZWxmLm1lID8gJ2luaXRpYXRvcicgOiAncmVzcG9uZGVyJywgc3NyYyk7XG4gICAgICAgICAgICAgICAgc2VsZi5jb25uZWN0aW9uLnNlbmRJUShpbml0LFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUubG9nKCdzZXNzaW9uIGluaXRpYXRlIGFjaycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGFjayA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgYWNrLnNvdXJjZSA9ICdvZmZlcic7XG4gICAgICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdhY2suamluZ2xlJywgW3NlbGYuc2lkLCBhY2tdKTtcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKHN0YW56YSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5zdGF0ZSA9ICdlcnJvcic7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnBlZXJjb25uZWN0aW9uLmNsb3NlKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSAoJChzdGFuemEpLmZpbmQoJ2Vycm9yJykubGVuZ3RoKSA/IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2RlOiAkKHN0YW56YSkuZmluZCgnZXJyb3InKS5hdHRyKCdjb2RlJyksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVhc29uOiAkKHN0YW56YSkuZmluZCgnZXJyb3IgOmZpcnN0JylbMF0udGFnTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH06e307XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvci5zb3VyY2UgPSAnb2ZmZXInO1xuICAgICAgICAgICAgICAgICAgICAgICAgSmluZ2xlU2Vzc2lvbi5vbkppbmdsZUVycm9yKHNlbGYuc2lkLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIDEwMDAwKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNlbmRKaW5nbGUoKTtcbiAgICAgICAgfVxuICAgICAgICB0aGlzLmxhc3RpY2VjYW5kaWRhdGUgPSB0cnVlO1xuICAgICAgICBjb25zb2xlLmxvZygnSGF2ZSB3ZSBlbmNvdW50ZXJlZCBhbnkgc3JmbHggY2FuZGlkYXRlcz8gJyArIHRoaXMuaGFkc3R1bmNhbmRpZGF0ZSk7XG4gICAgICAgIGNvbnNvbGUubG9nKCdIYXZlIHdlIGVuY291bnRlcmVkIGFueSByZWxheSBjYW5kaWRhdGVzPyAnICsgdGhpcy5oYWR0dXJuY2FuZGlkYXRlKTtcblxuICAgICAgICBpZiAoISh0aGlzLmhhZHN0dW5jYW5kaWRhdGUgfHwgdGhpcy5oYWR0dXJuY2FuZGlkYXRlKSAmJiB0aGlzLnBlZXJjb25uZWN0aW9uLnNpZ25hbGluZ1N0YXRlICE9ICdjbG9zZWQnKSB7XG4gICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdub3N0dW5jYW5kaWRhdGVzLmppbmdsZScsIFt0aGlzLnNpZF0pO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuc2VuZEljZUNhbmRpZGF0ZXMgPSBmdW5jdGlvbiAoY2FuZGlkYXRlcykge1xuICAgIGNvbnNvbGUubG9nKCdzZW5kSWNlQ2FuZGlkYXRlcycsIGNhbmRpZGF0ZXMpO1xuICAgIHZhciBjYW5kID0gJGlxKHt0bzogdGhpcy5wZWVyamlkLCB0eXBlOiAnc2V0J30pXG4gICAgICAgIC5jKCdqaW5nbGUnLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6MScsXG4gICAgICAgICAgICBhY3Rpb246ICd0cmFuc3BvcnQtaW5mbycsXG4gICAgICAgICAgICBpbml0aWF0b3I6IHRoaXMuaW5pdGlhdG9yLFxuICAgICAgICAgICAgc2lkOiB0aGlzLnNpZH0pO1xuICAgIGZvciAodmFyIG1pZCA9IDA7IG1pZCA8IHRoaXMubG9jYWxTRFAubWVkaWEubGVuZ3RoOyBtaWQrKykge1xuICAgICAgICB2YXIgY2FuZHMgPSBjYW5kaWRhdGVzLmZpbHRlcihmdW5jdGlvbiAoZWwpIHsgcmV0dXJuIGVsLnNkcE1MaW5lSW5kZXggPT0gbWlkOyB9KTtcbiAgICAgICAgdmFyIG1saW5lID0gU0RQVXRpbC5wYXJzZV9tbGluZSh0aGlzLmxvY2FsU0RQLm1lZGlhW21pZF0uc3BsaXQoJ1xcclxcbicpWzBdKTtcbiAgICAgICAgaWYgKGNhbmRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgIHZhciBpY2UgPSBTRFBVdGlsLmljZXBhcmFtcyh0aGlzLmxvY2FsU0RQLm1lZGlhW21pZF0sIHRoaXMubG9jYWxTRFAuc2Vzc2lvbik7XG4gICAgICAgICAgICBpY2UueG1sbnMgPSAndXJuOnhtcHA6amluZ2xlOnRyYW5zcG9ydHM6aWNlLXVkcDoxJztcbiAgICAgICAgICAgIGNhbmQuYygnY29udGVudCcsIHtjcmVhdG9yOiB0aGlzLmluaXRpYXRvciA9PSB0aGlzLm1lID8gJ2luaXRpYXRvcicgOiAncmVzcG9uZGVyJyxcbiAgICAgICAgICAgICAgICBuYW1lOiAoY2FuZHNbMF0uc2RwTWlkPyBjYW5kc1swXS5zZHBNaWQgOiBtbGluZS5tZWRpYSlcbiAgICAgICAgICAgIH0pLmMoJ3RyYW5zcG9ydCcsIGljZSk7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IGNhbmRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgY2FuZC5jKCdjYW5kaWRhdGUnLCBTRFBVdGlsLmNhbmRpZGF0ZVRvSmluZ2xlKGNhbmRzW2ldLmNhbmRpZGF0ZSkpLnVwKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBhZGQgZmluZ2VycHJpbnRcbiAgICAgICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLmxvY2FsU0RQLm1lZGlhW21pZF0sICdhPWZpbmdlcnByaW50OicsIHRoaXMubG9jYWxTRFAuc2Vzc2lvbikpIHtcbiAgICAgICAgICAgICAgICB2YXIgdG1wID0gU0RQVXRpbC5wYXJzZV9maW5nZXJwcmludChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLmxvY2FsU0RQLm1lZGlhW21pZF0sICdhPWZpbmdlcnByaW50OicsIHRoaXMubG9jYWxTRFAuc2Vzc2lvbikpO1xuICAgICAgICAgICAgICAgIHRtcC5yZXF1aXJlZCA9IHRydWU7XG4gICAgICAgICAgICAgICAgY2FuZC5jKFxuICAgICAgICAgICAgICAgICAgICAnZmluZ2VycHJpbnQnLFxuICAgICAgICAgICAgICAgICAgICB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6YXBwczpkdGxzOjAnfSlcbiAgICAgICAgICAgICAgICAgICAgLnQodG1wLmZpbmdlcnByaW50KTtcbiAgICAgICAgICAgICAgICBkZWxldGUgdG1wLmZpbmdlcnByaW50O1xuICAgICAgICAgICAgICAgIGNhbmQuYXR0cnModG1wKTtcbiAgICAgICAgICAgICAgICBjYW5kLnVwKCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBjYW5kLnVwKCk7IC8vIHRyYW5zcG9ydFxuICAgICAgICAgICAgY2FuZC51cCgpOyAvLyBjb250ZW50XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gbWlnaHQgbWVyZ2UgbGFzdC1jYW5kaWRhdGUgbm90aWZpY2F0aW9uIGludG8gdGhpcywgYnV0IGl0IGlzIGNhbGxlZCBhbG90IGxhdGVyLiBTZWUgd2VicnRjIGlzc3VlICMyMzQwXG4gICAgLy9jb25zb2xlLmxvZygnd2FzIHRoaXMgdGhlIGxhc3QgY2FuZGlkYXRlJywgdGhpcy5sYXN0aWNlY2FuZGlkYXRlKTtcbiAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZElRKGNhbmQsXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHZhciBhY2sgPSB7fTtcbiAgICAgICAgICAgIGFjay5zb3VyY2UgPSAndHJhbnNwb3J0aW5mbyc7XG4gICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdhY2suamluZ2xlJywgW3RoaXMuc2lkLCBhY2tdKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKHN0YW56YSkge1xuICAgICAgICAgICAgdmFyIGVycm9yID0gKCQoc3RhbnphKS5maW5kKCdlcnJvcicpLmxlbmd0aCkgPyB7XG4gICAgICAgICAgICAgICAgY29kZTogJChzdGFuemEpLmZpbmQoJ2Vycm9yJykuYXR0cignY29kZScpLFxuICAgICAgICAgICAgICAgIHJlYXNvbjogJChzdGFuemEpLmZpbmQoJ2Vycm9yIDpmaXJzdCcpWzBdLnRhZ05hbWUsXG4gICAgICAgICAgICB9Ont9O1xuICAgICAgICAgICAgZXJyb3Iuc291cmNlID0gJ3RyYW5zcG9ydGluZm8nO1xuICAgICAgICAgICAgSmluZ2xlU2Vzc2lvbi5vbkppbmdsZUVycm9yKHRoaXMuc2lkLCBlcnJvcik7XG4gICAgICAgIH0sXG4gICAgICAgIDEwMDAwKTtcbn07XG5cblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuc2VuZE9mZmVyID0gZnVuY3Rpb24gKCkge1xuICAgIC8vY29uc29sZS5sb2coJ3NlbmRPZmZlci4uLicpO1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLmNyZWF0ZU9mZmVyKGZ1bmN0aW9uIChzZHApIHtcbiAgICAgICAgICAgIHNlbGYuY3JlYXRlZE9mZmVyKHNkcCk7XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uIChlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmVycm9yKCdjcmVhdGVPZmZlciBmYWlsZWQnLCBlKTtcbiAgICAgICAgfSxcbiAgICAgICAgdGhpcy5tZWRpYV9jb25zdHJhaW50c1xuICAgICk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5jcmVhdGVkT2ZmZXIgPSBmdW5jdGlvbiAoc2RwKSB7XG4gICAgLy9jb25zb2xlLmxvZygnY3JlYXRlZE9mZmVyJywgc2RwKTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5sb2NhbFNEUCA9IG5ldyBTRFAoc2RwLnNkcCk7XG4gICAgLy90aGlzLmxvY2FsU0RQLm1hbmdsZSgpO1xuICAgIHZhciBzZW5kSmluZ2xlID0gZnVuY3Rpb24gKCkge1xuICAgICAgICB2YXIgaW5pdCA9ICRpcSh7dG86IHRoaXMucGVlcmppZCxcbiAgICAgICAgICAgIHR5cGU6ICdzZXQnfSlcbiAgICAgICAgICAgIC5jKCdqaW5nbGUnLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6MScsXG4gICAgICAgICAgICAgICAgYWN0aW9uOiAnc2Vzc2lvbi1pbml0aWF0ZScsXG4gICAgICAgICAgICAgICAgaW5pdGlhdG9yOiB0aGlzLmluaXRpYXRvcixcbiAgICAgICAgICAgICAgICBzaWQ6IHRoaXMuc2lkfSk7XG4gICAgICAgIHNlbGYubG9jYWxTRFAudG9KaW5nbGUoaW5pdCwgdGhpcy5pbml0aWF0b3IgPT0gdGhpcy5tZSA/ICdpbml0aWF0b3InIDogJ3Jlc3BvbmRlcicsIHRoaXMubG9jYWxTdHJlYW1zU1NSQyk7XG4gICAgICAgIHNlbGYuY29ubmVjdGlvbi5zZW5kSVEoaW5pdCxcbiAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICB2YXIgYWNrID0ge307XG4gICAgICAgICAgICAgICAgYWNrLnNvdXJjZSA9ICdvZmZlcic7XG4gICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignYWNrLmppbmdsZScsIFtzZWxmLnNpZCwgYWNrXSk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKHN0YW56YSkge1xuICAgICAgICAgICAgICAgIHNlbGYuc3RhdGUgPSAnZXJyb3InO1xuICAgICAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uY2xvc2UoKTtcbiAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSAoJChzdGFuemEpLmZpbmQoJ2Vycm9yJykubGVuZ3RoKSA/IHtcbiAgICAgICAgICAgICAgICAgICAgY29kZTogJChzdGFuemEpLmZpbmQoJ2Vycm9yJykuYXR0cignY29kZScpLFxuICAgICAgICAgICAgICAgICAgICByZWFzb246ICQoc3RhbnphKS5maW5kKCdlcnJvciA6Zmlyc3QnKVswXS50YWdOYW1lLFxuICAgICAgICAgICAgICAgIH06e307XG4gICAgICAgICAgICAgICAgZXJyb3Iuc291cmNlID0gJ29mZmVyJztcbiAgICAgICAgICAgICAgICBKaW5nbGVTZXNzaW9uLm9uSmluZ2xlRXJyb3Ioc2VsZi5zaWQsIGVycm9yKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAxMDAwMCk7XG4gICAgfVxuICAgIHNkcC5zZHAgPSB0aGlzLmxvY2FsU0RQLnJhdztcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLnNldExvY2FsRGVzY3JpcHRpb24oc2RwLFxuICAgICAgICBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBpZihzZWxmLnVzZXRyaWNrbGUpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgc2VuZEppbmdsZSgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgc2VsZi5zZXRMb2NhbERlc2NyaXB0aW9uKCk7XG4gICAgICAgICAgICAvL2NvbnNvbGUubG9nKCdzZXRMb2NhbERlc2NyaXB0aW9uIHN1Y2Nlc3MnKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ3NldExvY2FsRGVzY3JpcHRpb24gZmFpbGVkJywgZSk7XG4gICAgICAgIH1cbiAgICApO1xuICAgIHZhciBjYW5kcyA9IFNEUFV0aWwuZmluZF9saW5lcyh0aGlzLmxvY2FsU0RQLnJhdywgJ2E9Y2FuZGlkYXRlOicpO1xuICAgIGZvciAodmFyIGkgPSAwOyBpIDwgY2FuZHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgdmFyIGNhbmQgPSBTRFBVdGlsLnBhcnNlX2ljZWNhbmRpZGF0ZShjYW5kc1tpXSk7XG4gICAgICAgIGlmIChjYW5kLnR5cGUgPT0gJ3NyZmx4Jykge1xuICAgICAgICAgICAgdGhpcy5oYWRzdHVuY2FuZGlkYXRlID0gdHJ1ZTtcbiAgICAgICAgfSBlbHNlIGlmIChjYW5kLnR5cGUgPT0gJ3JlbGF5Jykge1xuICAgICAgICAgICAgdGhpcy5oYWR0dXJuY2FuZGlkYXRlID0gdHJ1ZTtcbiAgICAgICAgfVxuICAgIH1cbn07XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLnNldFJlbW90ZURlc2NyaXB0aW9uID0gZnVuY3Rpb24gKGVsZW0sIGRlc2N0eXBlKSB7XG4gICAgLy9jb25zb2xlLmxvZygnc2V0dGluZyByZW1vdGUgZGVzY3JpcHRpb24uLi4gJywgZGVzY3R5cGUpO1xuICAgIHRoaXMucmVtb3RlU0RQID0gbmV3IFNEUCgnJyk7XG4gICAgdGhpcy5yZW1vdGVTRFAuZnJvbUppbmdsZShlbGVtKTtcbiAgICBpZiAodGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbiAhPT0gbnVsbCkge1xuICAgICAgICBjb25zb2xlLmxvZygnc2V0UmVtb3RlRGVzY3JpcHRpb24gd2hlbiByZW1vdGUgZGVzY3JpcHRpb24gaXMgbm90IG51bGwsIHNob3VsZCBiZSBwcmFuc3dlcicsIHRoaXMucGVlcmNvbm5lY3Rpb24ucmVtb3RlRGVzY3JpcHRpb24pO1xuICAgICAgICBpZiAodGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbi50eXBlID09ICdwcmFuc3dlcicpIHtcbiAgICAgICAgICAgIHZhciBwcmFuc3dlciA9IG5ldyBTRFAodGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbi5zZHApO1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwcmFuc3dlci5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIC8vIG1ha2Ugc3VyZSB3ZSBoYXZlIGljZSB1ZnJhZyBhbmQgcHdkXG4gICAgICAgICAgICAgICAgaWYgKCFTRFBVdGlsLmZpbmRfbGluZSh0aGlzLnJlbW90ZVNEUC5tZWRpYVtpXSwgJ2E9aWNlLXVmcmFnOicsIHRoaXMucmVtb3RlU0RQLnNlc3Npb24pKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZShwcmFuc3dlci5tZWRpYVtpXSwgJ2E9aWNlLXVmcmFnOicsIHByYW5zd2VyLnNlc3Npb24pKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnJlbW90ZVNEUC5tZWRpYVtpXSArPSBTRFBVdGlsLmZpbmRfbGluZShwcmFuc3dlci5tZWRpYVtpXSwgJ2E9aWNlLXVmcmFnOicsIHByYW5zd2VyLnNlc3Npb24pICsgJ1xcclxcbic7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ25vIGljZSB1ZnJhZz8nKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUocHJhbnN3ZXIubWVkaWFbaV0sICdhPWljZS1wd2Q6JywgcHJhbnN3ZXIuc2Vzc2lvbikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3RlU0RQLm1lZGlhW2ldICs9IFNEUFV0aWwuZmluZF9saW5lKHByYW5zd2VyLm1lZGlhW2ldLCAnYT1pY2UtcHdkOicsIHByYW5zd2VyLnNlc3Npb24pICsgJ1xcclxcbic7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ25vIGljZSBwd2Q/Jyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gY29weSBvdmVyIGNhbmRpZGF0ZXNcbiAgICAgICAgICAgICAgICB2YXIgbGluZXMgPSBTRFBVdGlsLmZpbmRfbGluZXMocHJhbnN3ZXIubWVkaWFbaV0sICdhPWNhbmRpZGF0ZTonKTtcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBqID0gMDsgaiA8IGxpbmVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMucmVtb3RlU0RQLm1lZGlhW2ldICs9IGxpbmVzW2pdICsgJ1xcclxcbic7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5yZW1vdGVTRFAucmF3ID0gdGhpcy5yZW1vdGVTRFAuc2Vzc2lvbiArIHRoaXMucmVtb3RlU0RQLm1lZGlhLmpvaW4oJycpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHZhciByZW1vdGVkZXNjID0gbmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7dHlwZTogZGVzY3R5cGUsIHNkcDogdGhpcy5yZW1vdGVTRFAucmF3fSk7XG5cbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLnNldFJlbW90ZURlc2NyaXB0aW9uKHJlbW90ZWRlc2MsXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ3NldFJlbW90ZURlc2NyaXB0aW9uIHN1Y2Nlc3MnKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ3NldFJlbW90ZURlc2NyaXB0aW9uIGVycm9yJywgZSk7XG4gICAgICAgICAgICBKaW5nbGVTZXNzaW9uLm9uSmluZ2xlRmF0YWxFcnJvcihzZWxmLCBlKTtcbiAgICAgICAgfVxuICAgICk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGUgPSBmdW5jdGlvbiAoZWxlbSkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAodGhpcy5wZWVyY29ubmVjdGlvbi5zaWduYWxpbmdTdGF0ZSA9PSAnY2xvc2VkJykge1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICghdGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbiAmJiB0aGlzLnBlZXJjb25uZWN0aW9uLnNpZ25hbGluZ1N0YXRlID09ICdoYXZlLWxvY2FsLW9mZmVyJykge1xuICAgICAgICBjb25zb2xlLmxvZygndHJpY2tsZSBpY2UgY2FuZGlkYXRlIGFycml2aW5nIGJlZm9yZSBzZXNzaW9uIGFjY2VwdC4uLicpO1xuICAgICAgICAvLyBjcmVhdGUgYSBQUkFOU1dFUiBmb3Igc2V0UmVtb3RlRGVzY3JpcHRpb25cbiAgICAgICAgaWYgKCF0aGlzLnJlbW90ZVNEUCkge1xuICAgICAgICAgICAgdmFyIGNvYmJsZWQgPSAndj0wXFxyXFxuJyArXG4gICAgICAgICAgICAgICAgJ289LSAnICsgJzE5MjM1MTg1MTYnICsgJyAyIElOIElQNCAwLjAuMC4wXFxyXFxuJyArLy8gRklYTUVcbiAgICAgICAgICAgICAgICAncz0tXFxyXFxuJyArXG4gICAgICAgICAgICAgICAgJ3Q9MCAwXFxyXFxuJztcbiAgICAgICAgICAgIC8vIGZpcnN0LCB0YWtlIHNvbWUgdGhpbmdzIGZyb20gdGhlIGxvY2FsIGRlc2NyaXB0aW9uXG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubG9jYWxTRFAubWVkaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBjb2JibGVkICs9IFNEUFV0aWwuZmluZF9saW5lKHRoaXMubG9jYWxTRFAubWVkaWFbaV0sICdtPScpICsgJ1xcclxcbic7XG4gICAgICAgICAgICAgICAgY29iYmxlZCArPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5sb2NhbFNEUC5tZWRpYVtpXSwgJ2E9cnRwbWFwOicpLmpvaW4oJ1xcclxcbicpICsgJ1xcclxcbic7XG4gICAgICAgICAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubG9jYWxTRFAubWVkaWFbaV0sICdhPW1pZDonKSkge1xuICAgICAgICAgICAgICAgICAgICBjb2JibGVkICs9IFNEUFV0aWwuZmluZF9saW5lKHRoaXMubG9jYWxTRFAubWVkaWFbaV0sICdhPW1pZDonKSArICdcXHJcXG4nO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBjb2JibGVkICs9ICdhPWluYWN0aXZlXFxyXFxuJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMucmVtb3RlU0RQID0gbmV3IFNEUChjb2JibGVkKTtcbiAgICAgICAgfVxuICAgICAgICAvLyB0aGVuIGFkZCB0aGluZ3MgbGlrZSBpY2UgYW5kIGR0bHMgZnJvbSByZW1vdGUgY2FuZGlkYXRlXG4gICAgICAgIGVsZW0uZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHNlbGYucmVtb3RlU0RQLm1lZGlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHNlbGYucmVtb3RlU0RQLm1lZGlhW2ldLCAnYT1taWQ6JyArICQodGhpcykuYXR0cignbmFtZScpKSB8fFxuICAgICAgICAgICAgICAgICAgICBzZWxmLnJlbW90ZVNEUC5tZWRpYVtpXS5pbmRleE9mKCdtPScgKyAkKHRoaXMpLmF0dHIoJ25hbWUnKSkgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFTRFBVdGlsLmZpbmRfbGluZShzZWxmLnJlbW90ZVNEUC5tZWRpYVtpXSwgJ2E9aWNlLXVmcmFnOicpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgdG1wID0gJCh0aGlzKS5maW5kKCd0cmFuc3BvcnQnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYucmVtb3RlU0RQLm1lZGlhW2ldICs9ICdhPWljZS11ZnJhZzonICsgdG1wLmF0dHIoJ3VmcmFnJykgKyAnXFxyXFxuJztcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYucmVtb3RlU0RQLm1lZGlhW2ldICs9ICdhPWljZS1wd2Q6JyArIHRtcC5hdHRyKCdwd2QnKSArICdcXHJcXG4nO1xuICAgICAgICAgICAgICAgICAgICAgICAgdG1wID0gJCh0aGlzKS5maW5kKCd0cmFuc3BvcnQ+ZmluZ2VycHJpbnQnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0bXAubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5yZW1vdGVTRFAubWVkaWFbaV0gKz0gJ2E9ZmluZ2VycHJpbnQ6JyArIHRtcC5hdHRyKCdoYXNoJykgKyAnICcgKyB0bXAudGV4dCgpICsgJ1xcclxcbic7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdubyBkdGxzIGZpbmdlcnByaW50ICh3ZWJydGMgaXNzdWUgIzE3MTg/KScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYucmVtb3RlU0RQLm1lZGlhW2ldICs9ICdhPWNyeXB0bzoxIEFFU19DTV8xMjhfSE1BQ19TSEExXzgwIGlubGluZTpCQUFEQkFBREJBQURCQUFEQkFBREJBQURCQUFEQkFBREJBQURCQUFEXFxyXFxuJztcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICAgICAgdGhpcy5yZW1vdGVTRFAucmF3ID0gdGhpcy5yZW1vdGVTRFAuc2Vzc2lvbiArIHRoaXMucmVtb3RlU0RQLm1lZGlhLmpvaW4oJycpO1xuXG4gICAgICAgIC8vIHdlIG5lZWQgYSBjb21wbGV0ZSBTRFAgd2l0aCBpY2UtdWZyYWcvaWNlLXB3ZCBpbiBhbGwgcGFydHNcbiAgICAgICAgLy8gdGhpcyBtYWtlcyB0aGUgYXNzdW1wdGlvbiB0aGF0IHRoZSBQUkFOU1dFUiBpcyBjb25zdHJ1Y3RlZCBzdWNoIHRoYXQgdGhlIGljZS11ZnJhZyBpcyBpbiBhbGwgbWVkaWFwYXJ0c1xuICAgICAgICAvLyBidXQgaXQgY291bGQgYmUgaW4gdGhlIHNlc3Npb24gcGFydCBhcyB3ZWxsLiBzaW5jZSB0aGUgY29kZSBhYm92ZSBjb25zdHJ1Y3RzIHRoaXMgc2RwIHRoaXMgY2FuJ3QgaGFwcGVuIGhvd2V2ZXJcbiAgICAgICAgdmFyIGlzY29tcGxldGUgPSB0aGlzLnJlbW90ZVNEUC5tZWRpYS5maWx0ZXIoZnVuY3Rpb24gKG1lZGlhcGFydCkge1xuICAgICAgICAgICAgcmV0dXJuIFNEUFV0aWwuZmluZF9saW5lKG1lZGlhcGFydCwgJ2E9aWNlLXVmcmFnOicpO1xuICAgICAgICB9KS5sZW5ndGggPT0gdGhpcy5yZW1vdGVTRFAubWVkaWEubGVuZ3RoO1xuXG4gICAgICAgIGlmIChpc2NvbXBsZXRlKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnc2V0dGluZyBwcmFuc3dlcicpO1xuICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICB0aGlzLnBlZXJjb25uZWN0aW9uLnNldFJlbW90ZURlc2NyaXB0aW9uKG5ldyBSVENTZXNzaW9uRGVzY3JpcHRpb24oe3R5cGU6ICdwcmFuc3dlcicsIHNkcDogdGhpcy5yZW1vdGVTRFAucmF3IH0pLFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3NldFJlbW90ZURlc2NyaXB0aW9uIHByYW5zd2VyIGZhaWxlZCcsIGUudG9TdHJpbmcoKSk7XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ3NldHRpbmcgcHJhbnN3ZXIgZmFpbGVkJywgZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvL2NvbnNvbGUubG9nKCdub3QgeWV0IHNldHRpbmcgcHJhbnN3ZXInKTtcbiAgICAgICAgfVxuICAgIH1cbiAgICAvLyBvcGVyYXRlIG9uIGVhY2ggY29udGVudCBlbGVtZW50XG4gICAgZWxlbS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgLy8gd291bGQgbG92ZSB0byBkZWFjdGl2YXRlIHRoaXMsIGJ1dCBmaXJlZm94IHN0aWxsIHJlcXVpcmVzIGl0XG4gICAgICAgIHZhciBpZHggPSAtMTtcbiAgICAgICAgdmFyIGk7XG4gICAgICAgIGZvciAoaSA9IDA7IGkgPCBzZWxmLnJlbW90ZVNEUC5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHNlbGYucmVtb3RlU0RQLm1lZGlhW2ldLCAnYT1taWQ6JyArICQodGhpcykuYXR0cignbmFtZScpKSB8fFxuICAgICAgICAgICAgICAgIHNlbGYucmVtb3RlU0RQLm1lZGlhW2ldLmluZGV4T2YoJ209JyArICQodGhpcykuYXR0cignbmFtZScpKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgIGlkeCA9IGk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGlkeCA9PSAtMSkgeyAvLyBmYWxsIGJhY2sgdG8gbG9jYWxkZXNjcmlwdGlvblxuICAgICAgICAgICAgZm9yIChpID0gMDsgaSA8IHNlbGYubG9jYWxTRFAubWVkaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUoc2VsZi5sb2NhbFNEUC5tZWRpYVtpXSwgJ2E9bWlkOicgKyAkKHRoaXMpLmF0dHIoJ25hbWUnKSkgfHxcbiAgICAgICAgICAgICAgICAgICAgc2VsZi5sb2NhbFNEUC5tZWRpYVtpXS5pbmRleE9mKCdtPScgKyAkKHRoaXMpLmF0dHIoJ25hbWUnKSkgPT09IDApIHtcbiAgICAgICAgICAgICAgICAgICAgaWR4ID0gaTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHZhciBuYW1lID0gJCh0aGlzKS5hdHRyKCduYW1lJyk7XG4gICAgICAgIC8vIFRPRE86IGNoZWNrIGljZS1wd2QgYW5kIGljZS11ZnJhZz9cbiAgICAgICAgJCh0aGlzKS5maW5kKCd0cmFuc3BvcnQ+Y2FuZGlkYXRlJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbGluZSwgY2FuZGlkYXRlO1xuICAgICAgICAgICAgbGluZSA9IFNEUFV0aWwuY2FuZGlkYXRlRnJvbUppbmdsZSh0aGlzKTtcbiAgICAgICAgICAgIGNhbmRpZGF0ZSA9IG5ldyBSVENJY2VDYW5kaWRhdGUoe3NkcE1MaW5lSW5kZXg6IGlkeCxcbiAgICAgICAgICAgICAgICBzZHBNaWQ6IG5hbWUsXG4gICAgICAgICAgICAgICAgY2FuZGlkYXRlOiBsaW5lfSk7XG4gICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uYWRkSWNlQ2FuZGlkYXRlKGNhbmRpZGF0ZSk7XG4gICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignYWRkSWNlQ2FuZGlkYXRlIGZhaWxlZCcsIGUudG9TdHJpbmcoKSwgbGluZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgIH0pO1xufTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuc2VuZEFuc3dlciA9IGZ1bmN0aW9uIChwcm92aXNpb25hbCkge1xuICAgIC8vY29uc29sZS5sb2coJ2NyZWF0ZUFuc3dlcicsIHByb3Zpc2lvbmFsKTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5jcmVhdGVBbnN3ZXIoXG4gICAgICAgIGZ1bmN0aW9uIChzZHApIHtcbiAgICAgICAgICAgIHNlbGYuY3JlYXRlZEFuc3dlcihzZHAsIHByb3Zpc2lvbmFsKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ2NyZWF0ZUFuc3dlciBmYWlsZWQnLCBlKTtcbiAgICAgICAgfSxcbiAgICAgICAgdGhpcy5tZWRpYV9jb25zdHJhaW50c1xuICAgICk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5jcmVhdGVkQW5zd2VyID0gZnVuY3Rpb24gKHNkcCwgcHJvdmlzaW9uYWwpIHtcbiAgICAvL2NvbnNvbGUubG9nKCdjcmVhdGVBbnN3ZXIgY2FsbGJhY2snKTtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy5sb2NhbFNEUCA9IG5ldyBTRFAoc2RwLnNkcCk7XG4gICAgLy90aGlzLmxvY2FsU0RQLm1hbmdsZSgpO1xuICAgIHRoaXMudXNlcHJhbnN3ZXIgPSBwcm92aXNpb25hbCA9PT0gdHJ1ZTtcbiAgICBpZiAodGhpcy51c2V0cmlja2xlKSB7XG4gICAgICAgIGlmICh0aGlzLnVzZXByYW5zd2VyKSB7XG4gICAgICAgICAgICBzZHAudHlwZSA9ICdwcmFuc3dlcic7XG4gICAgICAgICAgICBmb3IgKHZhciBpID0gMDsgaSA8IHRoaXMubG9jYWxTRFAubWVkaWEubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICB0aGlzLmxvY2FsU0RQLm1lZGlhW2ldID0gdGhpcy5sb2NhbFNEUC5tZWRpYVtpXS5yZXBsYWNlKCdhPXNlbmRyZWN2XFxyXFxuJywgJ2E9aW5hY3RpdmVcXHJcXG4nKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHRoaXMubG9jYWxTRFAucmF3ID0gdGhpcy5sb2NhbFNEUC5zZXNzaW9uICsgJ1xcclxcbicgKyB0aGlzLmxvY2FsU0RQLm1lZGlhLmpvaW4oJycpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgc2VuZEppbmdsZSA9IGZ1bmN0aW9uIChzc3Jjcykge1xuXG4gICAgICAgICAgICAgICAgdmFyIGFjY2VwdCA9ICRpcSh7dG86IHNlbGYucGVlcmppZCxcbiAgICAgICAgICAgICAgICAgICAgdHlwZTogJ3NldCd9KVxuICAgICAgICAgICAgICAgICAgICAuYygnamluZ2xlJywge3htbG5zOiAndXJuOnhtcHA6amluZ2xlOjEnLFxuICAgICAgICAgICAgICAgICAgICAgICAgYWN0aW9uOiAnc2Vzc2lvbi1hY2NlcHQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgaW5pdGlhdG9yOiBzZWxmLmluaXRpYXRvcixcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3BvbmRlcjogc2VsZi5yZXNwb25kZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICBzaWQ6IHNlbGYuc2lkIH0pO1xuICAgICAgICAgICAgICAgIHZhciBwdWJsaWNMb2NhbERlc2MgPSBBUFAuc2ltdWxjYXN0LnJldmVyc2VUcmFuc2Zvcm1Mb2NhbERlc2NyaXB0aW9uKHNkcCk7XG4gICAgICAgICAgICAgICAgdmFyIHB1YmxpY0xvY2FsU0RQID0gbmV3IFNEUChwdWJsaWNMb2NhbERlc2Muc2RwKTtcbiAgICAgICAgICAgICAgICBwdWJsaWNMb2NhbFNEUC50b0ppbmdsZShhY2NlcHQsIHNlbGYuaW5pdGlhdG9yID09IHNlbGYubWUgPyAnaW5pdGlhdG9yJyA6ICdyZXNwb25kZXInLCBzc3Jjcyk7XG4gICAgICAgICAgICAgICAgc2VsZi5jb25uZWN0aW9uLnNlbmRJUShhY2NlcHQsXG4gICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBhY2sgPSB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFjay5zb3VyY2UgPSAnYW5zd2VyJztcbiAgICAgICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ2Fjay5qaW5nbGUnLCBbc2VsZi5zaWQsIGFja10pO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoc3RhbnphKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZXJyb3IgPSAoJChzdGFuemEpLmZpbmQoJ2Vycm9yJykubGVuZ3RoKSA/IHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb2RlOiAkKHN0YW56YSkuZmluZCgnZXJyb3InKS5hdHRyKCdjb2RlJyksXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVhc29uOiAkKHN0YW56YSkuZmluZCgnZXJyb3IgOmZpcnN0JylbMF0udGFnTmFtZSxcbiAgICAgICAgICAgICAgICAgICAgICAgIH06e307XG4gICAgICAgICAgICAgICAgICAgICAgICBlcnJvci5zb3VyY2UgPSAnYW5zd2VyJztcbiAgICAgICAgICAgICAgICAgICAgICAgIEppbmdsZVNlc3Npb24ub25KaW5nbGVFcnJvcihzZWxmLnNpZCwgZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAxMDAwMCk7XG4gICAgfVxuICAgIHNkcC5zZHAgPSB0aGlzLmxvY2FsU0RQLnJhdztcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLnNldExvY2FsRGVzY3JpcHRpb24oc2RwLFxuICAgICAgICBmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ3NldExvY2FsRGVzY3JpcHRpb24gc3VjY2VzcycpO1xuICAgICAgICAgICAgaWYgKHNlbGYudXNldHJpY2tsZSAmJiAhc2VsZi51c2VwcmFuc3dlcikge1xuICAgICAgICAgICAgICAgIHNlbmRKaW5nbGUoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHNlbGYuc2V0TG9jYWxEZXNjcmlwdGlvbigpO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZSkge1xuICAgICAgICAgICAgY29uc29sZS5lcnJvcignc2V0TG9jYWxEZXNjcmlwdGlvbiBmYWlsZWQnLCBlKTtcbiAgICAgICAgfVxuICAgICk7XG4gICAgdmFyIGNhbmRzID0gU0RQVXRpbC5maW5kX2xpbmVzKHRoaXMubG9jYWxTRFAucmF3LCAnYT1jYW5kaWRhdGU6Jyk7XG4gICAgZm9yICh2YXIgaiA9IDA7IGogPCBjYW5kcy5sZW5ndGg7IGorKykge1xuICAgICAgICB2YXIgY2FuZCA9IFNEUFV0aWwucGFyc2VfaWNlY2FuZGlkYXRlKGNhbmRzW2pdKTtcbiAgICAgICAgaWYgKGNhbmQudHlwZSA9PSAnc3JmbHgnKSB7XG4gICAgICAgICAgICB0aGlzLmhhZHN0dW5jYW5kaWRhdGUgPSB0cnVlO1xuICAgICAgICB9IGVsc2UgaWYgKGNhbmQudHlwZSA9PSAncmVsYXknKSB7XG4gICAgICAgICAgICB0aGlzLmhhZHR1cm5jYW5kaWRhdGUgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfVxufTtcblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuc2VuZFRlcm1pbmF0ZSA9IGZ1bmN0aW9uIChyZWFzb24sIHRleHQpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXMsXG4gICAgICAgIHRlcm0gPSAkaXEoe3RvOiB0aGlzLnBlZXJqaWQsXG4gICAgICAgICAgICB0eXBlOiAnc2V0J30pXG4gICAgICAgICAgICAuYygnamluZ2xlJywge3htbG5zOiAndXJuOnhtcHA6amluZ2xlOjEnLFxuICAgICAgICAgICAgICAgIGFjdGlvbjogJ3Nlc3Npb24tdGVybWluYXRlJyxcbiAgICAgICAgICAgICAgICBpbml0aWF0b3I6IHRoaXMuaW5pdGlhdG9yLFxuICAgICAgICAgICAgICAgIHNpZDogdGhpcy5zaWR9KVxuICAgICAgICAgICAgLmMoJ3JlYXNvbicpXG4gICAgICAgICAgICAuYyhyZWFzb24gfHwgJ3N1Y2Nlc3MnKTtcblxuICAgIGlmICh0ZXh0KSB7XG4gICAgICAgIHRlcm0udXAoKS5jKCd0ZXh0JykudCh0ZXh0KTtcbiAgICB9XG5cbiAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZElRKHRlcm0sXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uY2xvc2UoKTtcbiAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24gPSBudWxsO1xuICAgICAgICAgICAgc2VsZi50ZXJtaW5hdGUoKTtcbiAgICAgICAgICAgIHZhciBhY2sgPSB7fTtcbiAgICAgICAgICAgIGFjay5zb3VyY2UgPSAndGVybWluYXRlJztcbiAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ2Fjay5qaW5nbGUnLCBbc2VsZi5zaWQsIGFja10pO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoc3RhbnphKSB7XG4gICAgICAgICAgICB2YXIgZXJyb3IgPSAoJChzdGFuemEpLmZpbmQoJ2Vycm9yJykubGVuZ3RoKSA/IHtcbiAgICAgICAgICAgICAgICBjb2RlOiAkKHN0YW56YSkuZmluZCgnZXJyb3InKS5hdHRyKCdjb2RlJyksXG4gICAgICAgICAgICAgICAgcmVhc29uOiAkKHN0YW56YSkuZmluZCgnZXJyb3IgOmZpcnN0JylbMF0udGFnTmFtZSxcbiAgICAgICAgICAgIH06e307XG4gICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdhY2suamluZ2xlJywgW3NlbGYuc2lkLCBlcnJvcl0pO1xuICAgICAgICB9LFxuICAgICAgICAxMDAwMCk7XG4gICAgaWYgKHRoaXMuc3RhdHNpbnRlcnZhbCAhPT0gbnVsbCkge1xuICAgICAgICB3aW5kb3cuY2xlYXJJbnRlcnZhbCh0aGlzLnN0YXRzaW50ZXJ2YWwpO1xuICAgICAgICB0aGlzLnN0YXRzaW50ZXJ2YWwgPSBudWxsO1xuICAgIH1cbn07XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLmFkZFNvdXJjZSA9IGZ1bmN0aW9uIChlbGVtLCBmcm9tSmlkKSB7XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgLy8gRklYTUU6IGRpcnR5IHdhaXRpbmdcbiAgICBpZiAoIXRoaXMucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbilcbiAgICB7XG4gICAgICAgIGNvbnNvbGUud2FybihcImFkZFNvdXJjZSAtIGxvY2FsRGVzY3JpcHRpb24gbm90IHJlYWR5IHlldFwiKVxuICAgICAgICBzZXRUaW1lb3V0KGZ1bmN0aW9uKClcbiAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICBzZWxmLmFkZFNvdXJjZShlbGVtLCBmcm9tSmlkKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAyMDBcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKCdhZGRzc3JjJywgbmV3IERhdGUoKS5nZXRUaW1lKCkpO1xuICAgIGNvbnNvbGUubG9nKCdpY2UnLCB0aGlzLnBlZXJjb25uZWN0aW9uLmljZUNvbm5lY3Rpb25TdGF0ZSk7XG4gICAgdmFyIHNkcCA9IG5ldyBTRFAodGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbi5zZHApO1xuICAgIHZhciBteVNkcCA9IG5ldyBTRFAodGhpcy5wZWVyY29ubmVjdGlvbi5sb2NhbERlc2NyaXB0aW9uLnNkcCk7XG5cbiAgICAkKGVsZW0pLmVhY2goZnVuY3Rpb24gKGlkeCwgY29udGVudCkge1xuICAgICAgICB2YXIgbmFtZSA9ICQoY29udGVudCkuYXR0cignbmFtZScpO1xuICAgICAgICB2YXIgbGluZXMgPSAnJztcbiAgICAgICAgdG1wID0gJChjb250ZW50KS5maW5kKCdzc3JjLWdyb3VwW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnNzbWE6MFwiXScpLmVhY2goZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICB2YXIgc2VtYW50aWNzID0gdGhpcy5nZXRBdHRyaWJ1dGUoJ3NlbWFudGljcycpO1xuICAgICAgICAgICAgdmFyIHNzcmNzID0gJCh0aGlzKS5maW5kKCc+c291cmNlJykubWFwKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5nZXRBdHRyaWJ1dGUoJ3NzcmMnKTtcbiAgICAgICAgICAgIH0pLmdldCgpO1xuXG4gICAgICAgICAgICBpZiAoc3NyY3MubGVuZ3RoICE9IDApIHtcbiAgICAgICAgICAgICAgICBsaW5lcyArPSAnYT1zc3JjLWdyb3VwOicgKyBzZW1hbnRpY3MgKyAnICcgKyBzc3Jjcy5qb2luKCcgJykgKyAnXFxyXFxuJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgICAgIHRtcCA9ICQoY29udGVudCkuZmluZCgnc291cmNlW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnNzbWE6MFwiXScpOyAvLyBjYW4gaGFuZGxlIGJvdGggPnNvdXJjZSBhbmQgPmRlc2NyaXB0aW9uPnNvdXJjZVxuICAgICAgICB0bXAuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgc3NyYyA9ICQodGhpcykuYXR0cignc3NyYycpO1xuICAgICAgICAgICAgaWYobXlTZHAuY29udGFpbnNTU1JDKHNzcmMpKXtcbiAgICAgICAgICAgICAgICAvKipcbiAgICAgICAgICAgICAgICAgKiBUaGlzIGhhcHBlbnMgd2hlbiBtdWx0aXBsZSBwYXJ0aWNpcGFudHMgY2hhbmdlIHRoZWlyIHN0cmVhbXMgYXQgdGhlIHNhbWUgdGltZSBhbmRcbiAgICAgICAgICAgICAgICAgKiBDb2xpYnJpRm9jdXMubW9kaWZ5U291cmNlcyBoYXZlIHRvIHdhaXQgZm9yIHN0YWJsZSBzdGF0ZS4gSW4gdGhlIG1lYW50aW1lIG11bHRpcGxlXG4gICAgICAgICAgICAgICAgICogYWRkc3NyYyBhcmUgc2NoZWR1bGVkIGZvciB1cGRhdGUgSVEuIFNlZVxuICAgICAgICAgICAgICAgICAqL1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIkdvdCBhZGQgc3RyZWFtIHJlcXVlc3QgZm9yIG15IG93biBzc3JjOiBcIitzc3JjKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAkKHRoaXMpLmZpbmQoJz5wYXJhbWV0ZXInKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBsaW5lcyArPSAnYT1zc3JjOicgKyBzc3JjICsgJyAnICsgJCh0aGlzKS5hdHRyKCduYW1lJyk7XG4gICAgICAgICAgICAgICAgaWYgKCQodGhpcykuYXR0cigndmFsdWUnKSAmJiAkKHRoaXMpLmF0dHIoJ3ZhbHVlJykubGVuZ3RoKVxuICAgICAgICAgICAgICAgICAgICBsaW5lcyArPSAnOicgKyAkKHRoaXMpLmF0dHIoJ3ZhbHVlJyk7XG4gICAgICAgICAgICAgICAgbGluZXMgKz0gJ1xcclxcbic7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHNkcC5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKG1lZGlhLCBpZHgpIHtcbiAgICAgICAgICAgIGlmICghU0RQVXRpbC5maW5kX2xpbmUobWVkaWEsICdhPW1pZDonICsgbmFtZSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgc2RwLm1lZGlhW2lkeF0gKz0gbGluZXM7XG4gICAgICAgICAgICBpZiAoIXNlbGYuYWRkc3NyY1tpZHhdKSBzZWxmLmFkZHNzcmNbaWR4XSA9ICcnO1xuICAgICAgICAgICAgc2VsZi5hZGRzc3JjW2lkeF0gKz0gbGluZXM7XG4gICAgICAgIH0pO1xuICAgICAgICBzZHAucmF3ID0gc2RwLnNlc3Npb24gKyBzZHAubWVkaWEuam9pbignJyk7XG4gICAgfSk7XG4gICAgdGhpcy5tb2RpZnlTb3VyY2VzKCk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5yZW1vdmVTb3VyY2UgPSBmdW5jdGlvbiAoZWxlbSwgZnJvbUppZCkge1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIC8vIEZJWE1FOiBkaXJ0eSB3YWl0aW5nXG4gICAgaWYgKCF0aGlzLnBlZXJjb25uZWN0aW9uLmxvY2FsRGVzY3JpcHRpb24pXG4gICAge1xuICAgICAgICBjb25zb2xlLndhcm4oXCJyZW1vdmVTb3VyY2UgLSBsb2NhbERlc2NyaXB0aW9uIG5vdCByZWFkeSB5ZXRcIilcbiAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbigpXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgc2VsZi5yZW1vdmVTb3VyY2UoZWxlbSwgZnJvbUppZCk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgMjAwXG4gICAgICAgICk7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICBjb25zb2xlLmxvZygncmVtb3Zlc3NyYycsIG5ldyBEYXRlKCkuZ2V0VGltZSgpKTtcbiAgICBjb25zb2xlLmxvZygnaWNlJywgdGhpcy5wZWVyY29ubmVjdGlvbi5pY2VDb25uZWN0aW9uU3RhdGUpO1xuICAgIHZhciBzZHAgPSBuZXcgU0RQKHRoaXMucGVlcmNvbm5lY3Rpb24ucmVtb3RlRGVzY3JpcHRpb24uc2RwKTtcbiAgICB2YXIgbXlTZHAgPSBuZXcgU0RQKHRoaXMucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbi5zZHApO1xuXG4gICAgJChlbGVtKS5lYWNoKGZ1bmN0aW9uIChpZHgsIGNvbnRlbnQpIHtcbiAgICAgICAgdmFyIG5hbWUgPSAkKGNvbnRlbnQpLmF0dHIoJ25hbWUnKTtcbiAgICAgICAgdmFyIGxpbmVzID0gJyc7XG4gICAgICAgIHRtcCA9ICQoY29udGVudCkuZmluZCgnc3NyYy1ncm91cFt4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpzc21hOjBcIl0nKS5lYWNoKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgdmFyIHNlbWFudGljcyA9IHRoaXMuZ2V0QXR0cmlidXRlKCdzZW1hbnRpY3MnKTtcbiAgICAgICAgICAgIHZhciBzc3JjcyA9ICQodGhpcykuZmluZCgnPnNvdXJjZScpLm1hcChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QXR0cmlidXRlKCdzc3JjJyk7XG4gICAgICAgICAgICB9KS5nZXQoKTtcblxuICAgICAgICAgICAgaWYgKHNzcmNzLmxlbmd0aCAhPSAwKSB7XG4gICAgICAgICAgICAgICAgbGluZXMgKz0gJ2E9c3NyYy1ncm91cDonICsgc2VtYW50aWNzICsgJyAnICsgc3NyY3Muam9pbignICcpICsgJ1xcclxcbic7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICB0bXAgPSAkKGNvbnRlbnQpLmZpbmQoJ3NvdXJjZVt4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpzc21hOjBcIl0nKTsgLy8gY2FuIGhhbmRsZSBib3RoID5zb3VyY2UgYW5kID5kZXNjcmlwdGlvbj5zb3VyY2VcbiAgICAgICAgdG1wLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgdmFyIHNzcmMgPSAkKHRoaXMpLmF0dHIoJ3NzcmMnKTtcbiAgICAgICAgICAgIC8vIFRoaXMgc2hvdWxkIG5ldmVyIGhhcHBlbiwgYnV0IGNhbiBiZSB1c2VmdWwgZm9yIGJ1ZyBkZXRlY3Rpb25cbiAgICAgICAgICAgIGlmKG15U2RwLmNvbnRhaW5zU1NSQyhzc3JjKSl7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkdvdCByZW1vdmUgc3RyZWFtIHJlcXVlc3QgZm9yIG15IG93biBzc3JjOiBcIitzc3JjKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAkKHRoaXMpLmZpbmQoJz5wYXJhbWV0ZXInKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBsaW5lcyArPSAnYT1zc3JjOicgKyBzc3JjICsgJyAnICsgJCh0aGlzKS5hdHRyKCduYW1lJyk7XG4gICAgICAgICAgICAgICAgaWYgKCQodGhpcykuYXR0cigndmFsdWUnKSAmJiAkKHRoaXMpLmF0dHIoJ3ZhbHVlJykubGVuZ3RoKVxuICAgICAgICAgICAgICAgICAgICBsaW5lcyArPSAnOicgKyAkKHRoaXMpLmF0dHIoJ3ZhbHVlJyk7XG4gICAgICAgICAgICAgICAgbGluZXMgKz0gJ1xcclxcbic7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfSk7XG4gICAgICAgIHNkcC5tZWRpYS5mb3JFYWNoKGZ1bmN0aW9uKG1lZGlhLCBpZHgpIHtcbiAgICAgICAgICAgIGlmICghU0RQVXRpbC5maW5kX2xpbmUobWVkaWEsICdhPW1pZDonICsgbmFtZSkpXG4gICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgc2RwLm1lZGlhW2lkeF0gKz0gbGluZXM7XG4gICAgICAgICAgICBpZiAoIXNlbGYucmVtb3Zlc3NyY1tpZHhdKSBzZWxmLnJlbW92ZXNzcmNbaWR4XSA9ICcnO1xuICAgICAgICAgICAgc2VsZi5yZW1vdmVzc3JjW2lkeF0gKz0gbGluZXM7XG4gICAgICAgIH0pO1xuICAgICAgICBzZHAucmF3ID0gc2RwLnNlc3Npb24gKyBzZHAubWVkaWEuam9pbignJyk7XG4gICAgfSk7XG4gICAgdGhpcy5tb2RpZnlTb3VyY2VzKCk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5tb2RpZnlTb3VyY2VzID0gZnVuY3Rpb24gKHN1Y2Nlc3NDYWxsYmFjaykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBpZiAodGhpcy5wZWVyY29ubmVjdGlvbi5zaWduYWxpbmdTdGF0ZSA9PSAnY2xvc2VkJykgcmV0dXJuO1xuICAgIGlmICghKHRoaXMuYWRkc3NyYy5sZW5ndGggfHwgdGhpcy5yZW1vdmVzc3JjLmxlbmd0aCB8fCB0aGlzLnBlbmRpbmdvcCAhPT0gbnVsbCB8fCB0aGlzLnN3aXRjaHN0cmVhbXMpKXtcbiAgICAgICAgLy8gVGhlcmUgaXMgbm90aGluZyB0byBkbyBzaW5jZSBzY2hlZHVsZWQgam9iIG1pZ2h0IGhhdmUgYmVlbiBleGVjdXRlZCBieSBhbm90aGVyIHN1Y2NlZWRpbmcgY2FsbFxuICAgICAgICB0aGlzLnNldExvY2FsRGVzY3JpcHRpb24oKTtcbiAgICAgICAgaWYoc3VjY2Vzc0NhbGxiYWNrKXtcbiAgICAgICAgICAgIHN1Y2Nlc3NDYWxsYmFjaygpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBGSVhNRTogdGhpcyBpcyBhIGJpZyBoYWNrXG4gICAgLy8gaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC93ZWJydGMvaXNzdWVzL2RldGFpbD9pZD0yNjg4XG4gICAgLy8gXiBoYXMgYmVlbiBmaXhlZC5cbiAgICBpZiAoISh0aGlzLnBlZXJjb25uZWN0aW9uLnNpZ25hbGluZ1N0YXRlID09ICdzdGFibGUnICYmIHRoaXMucGVlcmNvbm5lY3Rpb24uaWNlQ29ubmVjdGlvblN0YXRlID09ICdjb25uZWN0ZWQnKSkge1xuICAgICAgICBjb25zb2xlLndhcm4oJ21vZGlmeVNvdXJjZXMgbm90IHlldCcsIHRoaXMucGVlcmNvbm5lY3Rpb24uc2lnbmFsaW5nU3RhdGUsIHRoaXMucGVlcmNvbm5lY3Rpb24uaWNlQ29ubmVjdGlvblN0YXRlKTtcbiAgICAgICAgdGhpcy53YWl0ID0gdHJ1ZTtcbiAgICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IHNlbGYubW9kaWZ5U291cmNlcyhzdWNjZXNzQ2FsbGJhY2spOyB9LCAyNTApO1xuICAgICAgICByZXR1cm47XG4gICAgfVxuICAgIGlmICh0aGlzLndhaXQpIHtcbiAgICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24oKSB7IHNlbGYubW9kaWZ5U291cmNlcyhzdWNjZXNzQ2FsbGJhY2spOyB9LCAyNTAwKTtcbiAgICAgICAgdGhpcy53YWl0ID0gZmFsc2U7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICAvLyBSZXNldCBzd2l0Y2ggc3RyZWFtcyBmbGFnXG4gICAgdGhpcy5zd2l0Y2hzdHJlYW1zID0gZmFsc2U7XG5cbiAgICB2YXIgc2RwID0gbmV3IFNEUCh0aGlzLnBlZXJjb25uZWN0aW9uLnJlbW90ZURlc2NyaXB0aW9uLnNkcCk7XG5cbiAgICAvLyBhZGQgc291cmNlc1xuICAgIHRoaXMuYWRkc3NyYy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmVzLCBpZHgpIHtcbiAgICAgICAgc2RwLm1lZGlhW2lkeF0gKz0gbGluZXM7XG4gICAgfSk7XG4gICAgdGhpcy5hZGRzc3JjID0gW107XG5cbiAgICAvLyByZW1vdmUgc291cmNlc1xuICAgIHRoaXMucmVtb3Zlc3NyYy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmVzLCBpZHgpIHtcbiAgICAgICAgbGluZXMgPSBsaW5lcy5zcGxpdCgnXFxyXFxuJyk7XG4gICAgICAgIGxpbmVzLnBvcCgpOyAvLyByZW1vdmUgZW1wdHkgbGFzdCBlbGVtZW50O1xuICAgICAgICBsaW5lcy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgICAgICAgIHNkcC5tZWRpYVtpZHhdID0gc2RwLm1lZGlhW2lkeF0ucmVwbGFjZShsaW5lICsgJ1xcclxcbicsICcnKTtcbiAgICAgICAgfSk7XG4gICAgfSk7XG4gICAgdGhpcy5yZW1vdmVzc3JjID0gW107XG5cbiAgICAvLyBGSVhNRTpcbiAgICAvLyB0aGlzIHdhcyBhIGhhY2sgZm9yIHRoZSBzaXR1YXRpb24gd2hlbiBvbmx5IG9uZSBwZWVyIGV4aXN0c1xuICAgIC8vIGluIHRoZSBjb25mZXJlbmNlLlxuICAgIC8vIGNoZWNrIGlmIHN0aWxsIHJlcXVpcmVkIGFuZCByZW1vdmVcbiAgICBpZiAoc2RwLm1lZGlhWzBdKVxuICAgICAgICBzZHAubWVkaWFbMF0gPSBzZHAubWVkaWFbMF0ucmVwbGFjZSgnYT1yZWN2b25seScsICdhPXNlbmRyZWN2Jyk7XG4gICAgaWYgKHNkcC5tZWRpYVsxXSlcbiAgICAgICAgc2RwLm1lZGlhWzFdID0gc2RwLm1lZGlhWzFdLnJlcGxhY2UoJ2E9cmVjdm9ubHknLCAnYT1zZW5kcmVjdicpO1xuXG4gICAgc2RwLnJhdyA9IHNkcC5zZXNzaW9uICsgc2RwLm1lZGlhLmpvaW4oJycpO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uc2V0UmVtb3RlRGVzY3JpcHRpb24obmV3IFJUQ1Nlc3Npb25EZXNjcmlwdGlvbih7dHlwZTogJ29mZmVyJywgc2RwOiBzZHAucmF3fSksXG4gICAgICAgIGZ1bmN0aW9uKCkge1xuXG4gICAgICAgICAgICBpZihzZWxmLnNpZ25hbGluZ1N0YXRlID09ICdjbG9zZWQnKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcImNyZWF0ZUFuc3dlciBhdHRlbXB0IG9uIGNsb3NlZCBzdGF0ZVwiKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uY3JlYXRlQW5zd2VyKFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uKG1vZGlmaWVkQW5zd2VyKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGNoYW5nZSB2aWRlbyBkaXJlY3Rpb24sIHNlZSBodHRwczovL2dpdGh1Yi5jb20vaml0c2kvaml0bWVldC9pc3N1ZXMvNDFcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNlbGYucGVuZGluZ29wICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgc2RwID0gbmV3IFNEUChtb2RpZmllZEFuc3dlci5zZHApO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHNkcC5tZWRpYS5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3dpdGNoKHNlbGYucGVuZGluZ29wKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ211dGUnOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2RwLm1lZGlhWzFdID0gc2RwLm1lZGlhWzFdLnJlcGxhY2UoJ2E9c2VuZHJlY3YnLCAnYT1yZWN2b25seScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ3VubXV0ZSc6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZHAubWVkaWFbMV0gPSBzZHAubWVkaWFbMV0ucmVwbGFjZSgnYT1yZWN2b25seScsICdhPXNlbmRyZWN2Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2RwLnJhdyA9IHNkcC5zZXNzaW9uICsgc2RwLm1lZGlhLmpvaW4oJycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG1vZGlmaWVkQW5zd2VyLnNkcCA9IHNkcC5yYXc7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnBlbmRpbmdvcCA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgICAgICAvLyBGSVhNRTogcHVzaGluZyBkb3duIGFuIGFuc3dlciB3aGlsZSBpY2UgY29ubmVjdGlvbiBzdGF0ZVxuICAgICAgICAgICAgICAgICAgICAvLyBpcyBzdGlsbCBjaGVja2luZyBpcyBiYWQuLi5cbiAgICAgICAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhzZWxmLnBlZXJjb25uZWN0aW9uLmljZUNvbm5lY3Rpb25TdGF0ZSk7XG5cbiAgICAgICAgICAgICAgICAgICAgLy8gdHJ5aW5nIHRvIHdvcmsgYXJvdW5kIGFub3RoZXIgY2hyb21lIGJ1Z1xuICAgICAgICAgICAgICAgICAgICAvL21vZGlmaWVkQW5zd2VyLnNkcCA9IG1vZGlmaWVkQW5zd2VyLnNkcC5yZXBsYWNlKC9hPXNldHVwOmFjdGl2ZS9nLCAnYT1zZXR1cDphY3RwYXNzJyk7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uc2V0TG9jYWxEZXNjcmlwdGlvbihtb2RpZmllZEFuc3dlcixcbiAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vY29uc29sZS5sb2coJ21vZGlmaWVkIHNldExvY2FsRGVzY3JpcHRpb24gb2snKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnNldExvY2FsRGVzY3JpcHRpb24oKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZihzdWNjZXNzQ2FsbGJhY2spe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdWNjZXNzQ2FsbGJhY2soKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24oZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdtb2RpZmllZCBzZXRMb2NhbERlc2NyaXB0aW9uIGZhaWxlZCcsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ21vZGlmaWVkIGFuc3dlciBmYWlsZWQnLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24oZXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ21vZGlmeSBmYWlsZWQnLCBlcnJvcik7XG4gICAgICAgIH1cbiAgICApO1xufTtcblxuLyoqXG4gKiBTd2l0Y2hlcyB2aWRlbyBzdHJlYW1zLlxuICogQHBhcmFtIG5ld19zdHJlYW0gbmV3IHN0cmVhbSB0aGF0IHdpbGwgYmUgdXNlZCBhcyB2aWRlbyBvZiB0aGlzIHNlc3Npb24uXG4gKiBAcGFyYW0gb2xkU3RyZWFtIG9sZCB2aWRlbyBzdHJlYW0gb2YgdGhpcyBzZXNzaW9uLlxuICogQHBhcmFtIHN1Y2Nlc3NfY2FsbGJhY2sgY2FsbGJhY2sgZXhlY3V0ZWQgYWZ0ZXIgc3VjY2Vzc2Z1bCBzdHJlYW0gc3dpdGNoLlxuICovXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zd2l0Y2hTdHJlYW1zID0gZnVuY3Rpb24gKG5ld19zdHJlYW0sIG9sZFN0cmVhbSwgc3VjY2Vzc19jYWxsYmFjaykge1xuXG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuXG4gICAgLy8gUmVtZW1iZXIgU0RQIHRvIGZpZ3VyZSBvdXQgYWRkZWQvcmVtb3ZlZCBTU1JDc1xuICAgIHZhciBvbGRTZHAgPSBudWxsO1xuICAgIGlmKHNlbGYucGVlcmNvbm5lY3Rpb24pIHtcbiAgICAgICAgaWYoc2VsZi5wZWVyY29ubmVjdGlvbi5sb2NhbERlc2NyaXB0aW9uKSB7XG4gICAgICAgICAgICBvbGRTZHAgPSBuZXcgU0RQKHNlbGYucGVlcmNvbm5lY3Rpb24ubG9jYWxEZXNjcmlwdGlvbi5zZHApO1xuICAgICAgICB9XG4gICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24ucmVtb3ZlU3RyZWFtKG9sZFN0cmVhbSwgdHJ1ZSk7XG4gICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uYWRkU3RyZWFtKG5ld19zdHJlYW0pO1xuICAgIH1cblxuICAgIEFQUC5SVEMuc3dpdGNoVmlkZW9TdHJlYW1zKG5ld19zdHJlYW0sIG9sZFN0cmVhbSk7XG5cbiAgICAvLyBDb25mZXJlbmNlIGlzIG5vdCBhY3RpdmVcbiAgICBpZighb2xkU2RwIHx8ICFzZWxmLnBlZXJjb25uZWN0aW9uKSB7XG4gICAgICAgIHN1Y2Nlc3NfY2FsbGJhY2soKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIHNlbGYuc3dpdGNoc3RyZWFtcyA9IHRydWU7XG4gICAgc2VsZi5tb2RpZnlTb3VyY2VzKGZ1bmN0aW9uKCkge1xuICAgICAgICBjb25zb2xlLmxvZygnbW9kaWZ5IHNvdXJjZXMgZG9uZScpO1xuXG4gICAgICAgIHN1Y2Nlc3NfY2FsbGJhY2soKTtcblxuICAgICAgICB2YXIgbmV3U2RwID0gbmV3IFNEUChzZWxmLnBlZXJjb25uZWN0aW9uLmxvY2FsRGVzY3JpcHRpb24uc2RwKTtcbiAgICAgICAgY29uc29sZS5sb2coXCJTRFBzXCIsIG9sZFNkcCwgbmV3U2RwKTtcbiAgICAgICAgc2VsZi5ub3RpZnlNeVNTUkNVcGRhdGUob2xkU2RwLCBuZXdTZHApO1xuICAgIH0pO1xufTtcblxuLyoqXG4gKiBGaWd1cmVzIG91dCBhZGRlZC9yZW1vdmVkIHNzcmNzIGFuZCBzZW5kIHVwZGF0ZSBJUXMuXG4gKiBAcGFyYW0gb2xkX3NkcCBTRFAgb2JqZWN0IGZvciBvbGQgZGVzY3JpcHRpb24uXG4gKiBAcGFyYW0gbmV3X3NkcCBTRFAgb2JqZWN0IGZvciBuZXcgZGVzY3JpcHRpb24uXG4gKi9cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLm5vdGlmeU15U1NSQ1VwZGF0ZSA9IGZ1bmN0aW9uIChvbGRfc2RwLCBuZXdfc2RwKSB7XG5cbiAgICBpZiAoISh0aGlzLnBlZXJjb25uZWN0aW9uLnNpZ25hbGluZ1N0YXRlID09ICdzdGFibGUnICYmXG4gICAgICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uaWNlQ29ubmVjdGlvblN0YXRlID09ICdjb25uZWN0ZWQnKSl7XG4gICAgICAgIGNvbnNvbGUubG9nKFwiVG9vIGVhcmx5IHRvIHNlbmQgdXBkYXRlc1wiKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cblxuICAgIC8vIHNlbmQgc291cmNlLXJlbW92ZSBJUS5cbiAgICBzZHBEaWZmZXIgPSBuZXcgU0RQRGlmZmVyKG5ld19zZHAsIG9sZF9zZHApO1xuICAgIHZhciByZW1vdmUgPSAkaXEoe3RvOiB0aGlzLnBlZXJqaWQsIHR5cGU6ICdzZXQnfSlcbiAgICAgICAgLmMoJ2ppbmdsZScsIHtcbiAgICAgICAgICAgIHhtbG5zOiAndXJuOnhtcHA6amluZ2xlOjEnLFxuICAgICAgICAgICAgYWN0aW9uOiAnc291cmNlLXJlbW92ZScsXG4gICAgICAgICAgICBpbml0aWF0b3I6IHRoaXMuaW5pdGlhdG9yLFxuICAgICAgICAgICAgc2lkOiB0aGlzLnNpZFxuICAgICAgICB9XG4gICAgKTtcbiAgICB2YXIgcmVtb3ZlZCA9IHNkcERpZmZlci50b0ppbmdsZShyZW1vdmUpO1xuICAgIGlmIChyZW1vdmVkKSB7XG4gICAgICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kSVEocmVtb3ZlLFxuICAgICAgICAgICAgZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbygnZ290IHJlbW92ZSByZXN1bHQnLCByZXMpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmVycm9yKCdnb3QgcmVtb3ZlIGVycm9yJywgZXJyKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBjb25zb2xlLmxvZygncmVtb3ZhbCBub3QgbmVjZXNzYXJ5Jyk7XG4gICAgfVxuXG4gICAgLy8gc2VuZCBzb3VyY2UtYWRkIElRLlxuICAgIHZhciBzZHBEaWZmZXIgPSBuZXcgU0RQRGlmZmVyKG9sZF9zZHAsIG5ld19zZHApO1xuICAgIHZhciBhZGQgPSAkaXEoe3RvOiB0aGlzLnBlZXJqaWQsIHR5cGU6ICdzZXQnfSlcbiAgICAgICAgLmMoJ2ppbmdsZScsIHtcbiAgICAgICAgICAgIHhtbG5zOiAndXJuOnhtcHA6amluZ2xlOjEnLFxuICAgICAgICAgICAgYWN0aW9uOiAnc291cmNlLWFkZCcsXG4gICAgICAgICAgICBpbml0aWF0b3I6IHRoaXMuaW5pdGlhdG9yLFxuICAgICAgICAgICAgc2lkOiB0aGlzLnNpZFxuICAgICAgICB9XG4gICAgKTtcbiAgICB2YXIgYWRkZWQgPSBzZHBEaWZmZXIudG9KaW5nbGUoYWRkKTtcbiAgICBpZiAoYWRkZWQpIHtcbiAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmRJUShhZGQsXG4gICAgICAgICAgICBmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKCdnb3QgYWRkIHJlc3VsdCcsIHJlcyk7XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKGVycikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoJ2dvdCBhZGQgZXJyb3InLCBlcnIpO1xuICAgICAgICAgICAgfVxuICAgICAgICApO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGNvbnNvbGUubG9nKCdhZGRpdGlvbiBub3QgbmVjZXNzYXJ5Jyk7XG4gICAgfVxufTtcblxuLyoqXG4gKiBEZXRlcm1pbmVzIHdoZXRoZXIgdGhlIChsb2NhbCkgdmlkZW8gaXMgbXV0ZSBpLmUuIGFsbCB2aWRlbyB0cmFja3MgYXJlXG4gKiBkaXNhYmxlZC5cbiAqXG4gKiBAcmV0dXJuIDx0dD50cnVlPC90dD4gaWYgdGhlIChsb2NhbCkgdmlkZW8gaXMgbXV0ZSBpLmUuIGFsbCB2aWRlbyB0cmFja3MgYXJlXG4gKiBkaXNhYmxlZDsgb3RoZXJ3aXNlLCA8dHQ+ZmFsc2U8L3R0PlxuICovXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5pc1ZpZGVvTXV0ZSA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgdHJhY2tzID0gQVBQLlJUQy5sb2NhbFZpZGVvLmdldFZpZGVvVHJhY2tzKCk7XG4gICAgdmFyIG11dGUgPSB0cnVlO1xuXG4gICAgZm9yICh2YXIgaSA9IDA7IGkgPCB0cmFja3MubGVuZ3RoOyArK2kpIHtcbiAgICAgICAgaWYgKHRyYWNrc1tpXS5lbmFibGVkKSB7XG4gICAgICAgICAgICBtdXRlID0gZmFsc2U7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gbXV0ZTtcbn07XG5cbi8qKlxuICogTXV0ZXMvdW5tdXRlcyB0aGUgKGxvY2FsKSB2aWRlbyBpLmUuIGVuYWJsZXMvZGlzYWJsZXMgYWxsIHZpZGVvIHRyYWNrcy5cbiAqXG4gKiBAcGFyYW0gbXV0ZSA8dHQ+dHJ1ZTwvdHQ+IHRvIG11dGUgdGhlIChsb2NhbCkgdmlkZW8gaS5lLiB0byBkaXNhYmxlIGFsbCB2aWRlb1xuICogdHJhY2tzOyBvdGhlcndpc2UsIDx0dD5mYWxzZTwvdHQ+XG4gKiBAcGFyYW0gY2FsbGJhY2sgYSBmdW5jdGlvbiB0byBiZSBpbnZva2VkIHdpdGggPHR0Pm11dGU8L3R0PiBhZnRlciBhbGwgdmlkZW9cbiAqIHRyYWNrcyBoYXZlIGJlZW4gZW5hYmxlZC9kaXNhYmxlZC4gVGhlIGZ1bmN0aW9uIG1heSwgb3B0aW9uYWxseSwgcmV0dXJuXG4gKiBhbm90aGVyIGZ1bmN0aW9uIHdoaWNoIGlzIHRvIGJlIGludm9rZWQgYWZ0ZXIgdGhlIHdob2xlIG11dGUvdW5tdXRlIG9wZXJhdGlvblxuICogaGFzIGNvbXBsZXRlZCBzdWNjZXNzZnVsbHkuXG4gKiBAcGFyYW0gb3B0aW9ucyBhbiBvYmplY3Qgd2hpY2ggc3BlY2lmaWVzIG9wdGlvbmFsIGFyZ3VtZW50cyBzdWNoIGFzIHRoZVxuICogPHR0PmJvb2xlYW48L3R0PiBrZXkgPHR0PmJ5VXNlcjwvdHQ+IHdpdGggZGVmYXVsdCB2YWx1ZSA8dHQ+dHJ1ZTwvdHQ+IHdoaWNoXG4gKiBzcGVjaWZpZXMgd2hldGhlciB0aGUgbWV0aG9kIHdhcyBpbml0aWF0ZWQgaW4gcmVzcG9uc2UgdG8gYSB1c2VyIGNvbW1hbmQgKGluXG4gKiBjb250cmFzdCB0byBhbiBhdXRvbWF0aWMgZGVjaXNpb24gbWFkZSBieSB0aGUgYXBwbGljYXRpb24gbG9naWMpXG4gKi9cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLnNldFZpZGVvTXV0ZSA9IGZ1bmN0aW9uIChtdXRlLCBjYWxsYmFjaywgb3B0aW9ucykge1xuICAgIHZhciBieVVzZXI7XG5cbiAgICBpZiAob3B0aW9ucykge1xuICAgICAgICBieVVzZXIgPSBvcHRpb25zLmJ5VXNlcjtcbiAgICAgICAgaWYgKHR5cGVvZiBieVVzZXIgPT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBieVVzZXIgPSB0cnVlO1xuICAgICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgICAgYnlVc2VyID0gdHJ1ZTtcbiAgICB9XG4gICAgLy8gVGhlIHVzZXIncyBjb21tYW5kIHRvIG11dGUgdGhlIChsb2NhbCkgdmlkZW8gdGFrZXMgcHJlY2VkZW5jZSBvdmVyIGFueVxuICAgIC8vIGF1dG9tYXRpYyBkZWNpc2lvbiBtYWRlIGJ5IHRoZSBhcHBsaWNhdGlvbiBsb2dpYy5cbiAgICBpZiAoYnlVc2VyKSB7XG4gICAgICAgIHRoaXMudmlkZW9NdXRlQnlVc2VyID0gbXV0ZTtcbiAgICB9IGVsc2UgaWYgKHRoaXMudmlkZW9NdXRlQnlVc2VyKSB7XG4gICAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIGxvY2FsQ2FsbGJhY2sgPSBmdW5jdGlvbiAobXV0ZSkge1xuICAgICAgICBzZWxmLmNvbm5lY3Rpb24uZW11Yy5hZGRWaWRlb0luZm9Ub1ByZXNlbmNlKG11dGUpO1xuICAgICAgICBzZWxmLmNvbm5lY3Rpb24uZW11Yy5zZW5kUHJlc2VuY2UoKTtcbiAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG11dGUpXG4gICAgfTtcblxuICAgIGlmIChtdXRlID09IEFQUC5SVEMubG9jYWxWaWRlby5pc011dGVkKCkpXG4gICAge1xuICAgICAgICAvLyBFdmVuIGlmIG5vIGNoYW5nZSBvY2N1cnMsIHRoZSBzcGVjaWZpZWQgY2FsbGJhY2sgaXMgdG8gYmUgZXhlY3V0ZWQuXG4gICAgICAgIC8vIFRoZSBzcGVjaWZpZWQgY2FsbGJhY2sgbWF5LCBvcHRpb25hbGx5LCByZXR1cm4gYSBzdWNjZXNzQ2FsbGJhY2tcbiAgICAgICAgLy8gd2hpY2ggaXMgdG8gYmUgZXhlY3V0ZWQgYXMgd2VsbC5cbiAgICAgICAgdmFyIHN1Y2Nlc3NDYWxsYmFjayA9IGxvY2FsQ2FsbGJhY2sobXV0ZSk7XG5cbiAgICAgICAgaWYgKHN1Y2Nlc3NDYWxsYmFjaykge1xuICAgICAgICAgICAgc3VjY2Vzc0NhbGxiYWNrKCk7XG4gICAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgICBBUFAuUlRDLmxvY2FsVmlkZW8uc2V0TXV0ZSghbXV0ZSk7XG5cbiAgICAgICAgdGhpcy5oYXJkTXV0ZVZpZGVvKG11dGUpO1xuXG4gICAgICAgIHRoaXMubW9kaWZ5U291cmNlcyhsb2NhbENhbGxiYWNrKG11dGUpKTtcbiAgICB9XG59O1xuXG4vLyBTRFAtYmFzZWQgbXV0ZSBieSBnb2luZyByZWN2b25seS9zZW5kcmVjdlxuLy8gRklYTUU6IHNob3VsZCBwcm9iYWJseSBibGFjayBvdXQgdGhlIHNjcmVlbiBhcyB3ZWxsXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS50b2dnbGVWaWRlb011dGUgPSBmdW5jdGlvbiAoY2FsbGJhY2spIHtcbiAgICB0aGlzLnNlcnZpY2Uuc2V0VmlkZW9NdXRlKEFQUC5SVEMubG9jYWxWaWRlby5pc011dGVkKCksIGNhbGxiYWNrKTtcbn07XG5cbkppbmdsZVNlc3Npb24ucHJvdG90eXBlLmhhcmRNdXRlVmlkZW8gPSBmdW5jdGlvbiAobXV0ZWQpIHtcbiAgICB0aGlzLnBlbmRpbmdvcCA9IG11dGVkID8gJ211dGUnIDogJ3VubXV0ZSc7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZW5kTXV0ZSA9IGZ1bmN0aW9uIChtdXRlZCwgY29udGVudCkge1xuICAgIHZhciBpbmZvID0gJGlxKHt0bzogdGhpcy5wZWVyamlkLFxuICAgICAgICB0eXBlOiAnc2V0J30pXG4gICAgICAgIC5jKCdqaW5nbGUnLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6MScsXG4gICAgICAgICAgICBhY3Rpb246ICdzZXNzaW9uLWluZm8nLFxuICAgICAgICAgICAgaW5pdGlhdG9yOiB0aGlzLmluaXRpYXRvcixcbiAgICAgICAgICAgIHNpZDogdGhpcy5zaWQgfSk7XG4gICAgaW5mby5jKG11dGVkID8gJ211dGUnIDogJ3VubXV0ZScsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDppbmZvOjEnfSk7XG4gICAgaW5mby5hdHRycyh7J2NyZWF0b3InOiB0aGlzLm1lID09IHRoaXMuaW5pdGlhdG9yID8gJ2NyZWF0b3InIDogJ3Jlc3BvbmRlcid9KTtcbiAgICBpZiAoY29udGVudCkge1xuICAgICAgICBpbmZvLmF0dHJzKHsnbmFtZSc6IGNvbnRlbnR9KTtcbiAgICB9XG4gICAgdGhpcy5jb25uZWN0aW9uLnNlbmQoaW5mbyk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5zZW5kUmluZ2luZyA9IGZ1bmN0aW9uICgpIHtcbiAgICB2YXIgaW5mbyA9ICRpcSh7dG86IHRoaXMucGVlcmppZCxcbiAgICAgICAgdHlwZTogJ3NldCd9KVxuICAgICAgICAuYygnamluZ2xlJywge3htbG5zOiAndXJuOnhtcHA6amluZ2xlOjEnLFxuICAgICAgICAgICAgYWN0aW9uOiAnc2Vzc2lvbi1pbmZvJyxcbiAgICAgICAgICAgIGluaXRpYXRvcjogdGhpcy5pbml0aWF0b3IsXG4gICAgICAgICAgICBzaWQ6IHRoaXMuc2lkIH0pO1xuICAgIGluZm8uYygncmluZ2luZycsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDppbmZvOjEnfSk7XG4gICAgdGhpcy5jb25uZWN0aW9uLnNlbmQoaW5mbyk7XG59O1xuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5nZXRTdGF0cyA9IGZ1bmN0aW9uIChpbnRlcnZhbCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgcmVjdiA9IHthdWRpbzogMCwgdmlkZW86IDB9O1xuICAgIHZhciBsb3N0ID0ge2F1ZGlvOiAwLCB2aWRlbzogMH07XG4gICAgdmFyIGxhc3RyZWN2ID0ge2F1ZGlvOiAwLCB2aWRlbzogMH07XG4gICAgdmFyIGxhc3Rsb3N0ID0ge2F1ZGlvOiAwLCB2aWRlbzogMH07XG4gICAgdmFyIGxvc3MgPSB7YXVkaW86IDAsIHZpZGVvOiAwfTtcbiAgICB2YXIgZGVsdGEgPSB7YXVkaW86IDAsIHZpZGVvOiAwfTtcbiAgICB0aGlzLnN0YXRzaW50ZXJ2YWwgPSB3aW5kb3cuc2V0SW50ZXJ2YWwoZnVuY3Rpb24gKCkge1xuICAgICAgICBpZiAoc2VsZiAmJiBzZWxmLnBlZXJjb25uZWN0aW9uICYmIHNlbGYucGVlcmNvbm5lY3Rpb24uZ2V0U3RhdHMpIHtcbiAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uZ2V0U3RhdHMoZnVuY3Rpb24gKHN0YXRzKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJlc3VsdHMgPSBzdGF0cy5yZXN1bHQoKTtcbiAgICAgICAgICAgICAgICAvLyBUT0RPOiB0aGVyZSBhcmUgc28gbXVjaCBzdGF0aXN0aWNzIHlvdSBjYW4gZ2V0IGZyb20gdGhpcy4uXG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCByZXN1bHRzLmxlbmd0aDsgKytpKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHRzW2ldLnR5cGUgPT0gJ3NzcmMnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgcGFja2V0c3JlY3YgPSByZXN1bHRzW2ldLnN0YXQoJ3BhY2tldHNSZWNlaXZlZCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHBhY2tldHNsb3N0ID0gcmVzdWx0c1tpXS5zdGF0KCdwYWNrZXRzTG9zdCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKHBhY2tldHNyZWN2ICYmIHBhY2tldHNsb3N0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcGFja2V0c3JlY3YgPSBwYXJzZUludChwYWNrZXRzcmVjdiwgMTApO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHBhY2tldHNsb3N0ID0gcGFyc2VJbnQocGFja2V0c2xvc3QsIDEwKTtcblxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmIChyZXN1bHRzW2ldLnN0YXQoJ2dvb2dGcmFtZVJhdGVSZWNlaXZlZCcpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3Rsb3N0LnZpZGVvID0gbG9zdC52aWRlbztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbGFzdHJlY3YudmlkZW8gPSByZWN2LnZpZGVvO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZWN2LnZpZGVvID0gcGFja2V0c3JlY3Y7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvc3QudmlkZW8gPSBwYWNrZXRzbG9zdDtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsYXN0bG9zdC5hdWRpbyA9IGxvc3QuYXVkaW87XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxhc3RyZWN2LmF1ZGlvID0gcmVjdi5hdWRpbztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmVjdi5hdWRpbyA9IHBhY2tldHNyZWN2O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb3N0LmF1ZGlvID0gcGFja2V0c2xvc3Q7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGRlbHRhLmF1ZGlvID0gcmVjdi5hdWRpbyAtIGxhc3RyZWN2LmF1ZGlvO1xuICAgICAgICAgICAgICAgIGRlbHRhLnZpZGVvID0gcmVjdi52aWRlbyAtIGxhc3RyZWN2LnZpZGVvO1xuICAgICAgICAgICAgICAgIGxvc3MuYXVkaW8gPSAoZGVsdGEuYXVkaW8gPiAwKSA/IE1hdGguY2VpbCgxMDAgKiAobG9zdC5hdWRpbyAtIGxhc3Rsb3N0LmF1ZGlvKSAvIGRlbHRhLmF1ZGlvKSA6IDA7XG4gICAgICAgICAgICAgICAgbG9zcy52aWRlbyA9IChkZWx0YS52aWRlbyA+IDApID8gTWF0aC5jZWlsKDEwMCAqIChsb3N0LnZpZGVvIC0gbGFzdGxvc3QudmlkZW8pIC8gZGVsdGEudmlkZW8pIDogMDtcbiAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdwYWNrZXRsb3NzLmppbmdsZScsIFtzZWxmLnNpZCwgbG9zc10pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9LCBpbnRlcnZhbCB8fCAzMDAwKTtcbiAgICByZXR1cm4gdGhpcy5zdGF0c2ludGVydmFsO1xufTtcblxuSmluZ2xlU2Vzc2lvbi5vbkppbmdsZUVycm9yID0gZnVuY3Rpb24gKHNlc3Npb24sIGVycm9yKVxue1xuICAgIGNvbnNvbGUuZXJyb3IoXCJKaW5nbGUgZXJyb3JcIiwgZXJyb3IpO1xufVxuXG5KaW5nbGVTZXNzaW9uLm9uSmluZ2xlRmF0YWxFcnJvciA9IGZ1bmN0aW9uIChzZXNzaW9uLCBlcnJvcilcbntcbiAgICB0aGlzLnNlcnZpY2Uuc2Vzc2lvblRlcm1pbmF0ZWQgPSB0cnVlO1xuICAgIHRoaXMuY29ubmVjdGlvbi5lbXVjLmRvTGVhdmUoKTtcbiAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKCAgXCJTb3JyeVwiLFxuICAgICAgICBcIkludGVybmFsIGFwcGxpY2F0aW9uIGVycm9yW3NldFJlbW90ZURlc2NyaXB0aW9uXVwiKTtcbn1cblxuSmluZ2xlU2Vzc2lvbi5wcm90b3R5cGUuc2V0TG9jYWxEZXNjcmlwdGlvbiA9IGZ1bmN0aW9uICgpIHtcbiAgICAvLyBwdXQgb3VyIHNzcmNzIGludG8gcHJlc2VuY2Ugc28gb3RoZXIgY2xpZW50cyBjYW4gaWRlbnRpZnkgb3VyIHN0cmVhbVxuICAgIHZhciBuZXdzc3JjcyA9IFtdO1xuICAgIHZhciBtZWRpYSA9IEFQUC5zaW11bGNhc3QucGFyc2VNZWRpYSh0aGlzLnBlZXJjb25uZWN0aW9uLmxvY2FsRGVzY3JpcHRpb24pO1xuICAgIG1lZGlhLmZvckVhY2goZnVuY3Rpb24gKG1lZGlhKSB7XG5cbiAgICAgICAgaWYoT2JqZWN0LmtleXMobWVkaWEuc291cmNlcykubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgLy8gVE9ETyhncCkgbWF5YmUgZXhjbHVkZSBGSUQgc3RyZWFtcz9cbiAgICAgICAgICAgIE9iamVjdC5rZXlzKG1lZGlhLnNvdXJjZXMpLmZvckVhY2goZnVuY3Rpb24gKHNzcmMpIHtcbiAgICAgICAgICAgICAgICBuZXdzc3Jjcy5wdXNoKHtcbiAgICAgICAgICAgICAgICAgICAgJ3NzcmMnOiBzc3JjLFxuICAgICAgICAgICAgICAgICAgICAndHlwZSc6IG1lZGlhLnR5cGUsXG4gICAgICAgICAgICAgICAgICAgICdkaXJlY3Rpb24nOiBtZWRpYS5kaXJlY3Rpb25cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG4gICAgICAgIGVsc2UgaWYodGhpcy5sb2NhbFN0cmVhbXNTU1JDICYmIHRoaXMubG9jYWxTdHJlYW1zU1NSQ1ttZWRpYS50eXBlXSlcbiAgICAgICAge1xuICAgICAgICAgICAgbmV3c3NyY3MucHVzaCh7XG4gICAgICAgICAgICAgICAgJ3NzcmMnOiB0aGlzLmxvY2FsU3RyZWFtc1NTUkNbbWVkaWEudHlwZV0sXG4gICAgICAgICAgICAgICAgJ3R5cGUnOiBtZWRpYS50eXBlLFxuICAgICAgICAgICAgICAgICdkaXJlY3Rpb24nOiBtZWRpYS5kaXJlY3Rpb25cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9XG5cbiAgICB9KTtcblxuICAgIGNvbnNvbGUubG9nKCduZXcgc3NyY3MnLCBuZXdzc3Jjcyk7XG5cbiAgICAvLyBIYXZlIHRvIGNsZWFyIHByZXNlbmNlIG1hcCB0byBnZXQgcmlkIG9mIHJlbW92ZWQgc3RyZWFtc1xuICAgIHRoaXMuY29ubmVjdGlvbi5lbXVjLmNsZWFyUHJlc2VuY2VNZWRpYSgpO1xuXG4gICAgaWYgKG5ld3NzcmNzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgZm9yICh2YXIgaSA9IDE7IGkgPD0gbmV3c3NyY3MubGVuZ3RoOyBpICsrKSB7XG4gICAgICAgICAgICAvLyBDaGFuZ2UgdmlkZW8gdHlwZSB0byBzY3JlZW5cbiAgICAgICAgICAgIGlmIChuZXdzc3Jjc1tpLTFdLnR5cGUgPT09ICd2aWRlbycgJiYgQVBQLmRlc2t0b3BzaGFyaW5nLmlzVXNpbmdTY3JlZW5TdHJlYW0oKSkge1xuICAgICAgICAgICAgICAgIG5ld3NzcmNzW2ktMV0udHlwZSA9ICdzY3JlZW4nO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmVtdWMuYWRkTWVkaWFUb1ByZXNlbmNlKGksXG4gICAgICAgICAgICAgICAgbmV3c3NyY3NbaS0xXS50eXBlLCBuZXdzc3Jjc1tpLTFdLnNzcmMsIG5ld3NzcmNzW2ktMV0uZGlyZWN0aW9uKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHRoaXMuY29ubmVjdGlvbi5lbXVjLnNlbmRQcmVzZW5jZSgpO1xuICAgIH1cbn1cblxuLy8gYW4gYXR0ZW1wdCB0byB3b3JrIGFyb3VuZCBodHRwczovL2dpdGh1Yi5jb20vaml0c2kvaml0bWVldC9pc3N1ZXMvMzJcbmZ1bmN0aW9uIHNlbmRLZXlmcmFtZShwYykge1xuICAgIGNvbnNvbGUubG9nKCdzZW5ka2V5ZnJhbWUnLCBwYy5pY2VDb25uZWN0aW9uU3RhdGUpO1xuICAgIGlmIChwYy5pY2VDb25uZWN0aW9uU3RhdGUgIT09ICdjb25uZWN0ZWQnKSByZXR1cm47IC8vIHNhZmUuLi5cbiAgICBwYy5zZXRSZW1vdGVEZXNjcmlwdGlvbihcbiAgICAgICAgcGMucmVtb3RlRGVzY3JpcHRpb24sXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHBjLmNyZWF0ZUFuc3dlcihcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAobW9kaWZpZWRBbnN3ZXIpIHtcbiAgICAgICAgICAgICAgICAgICAgcGMuc2V0TG9jYWxEZXNjcmlwdGlvbihcbiAgICAgICAgICAgICAgICAgICAgICAgIG1vZGlmaWVkQW5zd2VyLFxuICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIG5vb3BcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygndHJpZ2dlcktleWZyYW1lIHNldExvY2FsRGVzY3JpcHRpb24gZmFpbGVkJywgZXJyb3IpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIEFQUC5VSS5tZXNzYWdlSGFuZGxlci5zaG93RXJyb3IoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygndHJpZ2dlcktleWZyYW1lIGNyZWF0ZUFuc3dlciBmYWlsZWQnLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIEFQUC5VSS5tZXNzYWdlSGFuZGxlci5zaG93RXJyb3IoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICApO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCd0cmlnZ2VyS2V5ZnJhbWUgc2V0UmVtb3RlRGVzY3JpcHRpb24gZmFpbGVkJywgZXJyb3IpO1xuICAgICAgICAgICAgQVBQLlVJLm1lc3NhZ2VIYW5kbGVyLnNob3dFcnJvcigpO1xuICAgICAgICB9XG4gICAgKTtcbn1cblxuXG5KaW5nbGVTZXNzaW9uLnByb3RvdHlwZS5yZW1vdGVTdHJlYW1BZGRlZCA9IGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHZhciB0aGVzc3JjO1xuICAgIHZhciBzc3JjMmppZCA9IHRoaXMuY29ubmVjdGlvbi5lbXVjLnNzcmMyamlkO1xuXG4gICAgLy8gbG9vayB1cCBhbiBhc3NvY2lhdGVkIEpJRCBmb3IgYSBzdHJlYW0gaWRcbiAgICBpZiAoZGF0YS5zdHJlYW0uaWQgJiYgZGF0YS5zdHJlYW0uaWQuaW5kZXhPZignbWl4ZWRtc2xhYmVsJykgPT09IC0xKSB7XG4gICAgICAgIC8vIGxvb2sgb25seSBhdCBhPXNzcmM6IGFuZCBfbm90XyBhdCBhPXNzcmMtZ3JvdXA6IGxpbmVzXG5cbiAgICAgICAgdmFyIHNzcmNsaW5lc1xuICAgICAgICAgICAgPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbi5zZHAsICdhPXNzcmM6Jyk7XG4gICAgICAgIHNzcmNsaW5lcyA9IHNzcmNsaW5lcy5maWx0ZXIoZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgICAgIC8vIE5PVEUoZ3ApIHByZXZpb3VzbHkgd2UgZmlsdGVyZWQgb24gdGhlIG1zbGFiZWwsIGJ1dCB0aGF0IHByb3BlcnR5XG4gICAgICAgICAgICAvLyBpcyBub3QgYWx3YXlzIHByZXNlbnQuXG4gICAgICAgICAgICAvLyByZXR1cm4gbGluZS5pbmRleE9mKCdtc2xhYmVsOicgKyBkYXRhLnN0cmVhbS5sYWJlbCkgIT09IC0xO1xuXG4gICAgICAgICAgICByZXR1cm4gKChsaW5lLmluZGV4T2YoJ21zaWQ6JyArIGRhdGEuc3RyZWFtLmlkKSAhPT0gLTEpKTtcbiAgICAgICAgfSk7XG4gICAgICAgIGlmIChzc3JjbGluZXMubGVuZ3RoKSB7XG4gICAgICAgICAgICB0aGVzc3JjID0gc3NyY2xpbmVzWzBdLnN1YnN0cmluZyg3KS5zcGxpdCgnICcpWzBdO1xuXG4gICAgICAgICAgICAvLyBXZSBzaWduYWwgb3VyIHN0cmVhbXMgKHRocm91Z2ggSmluZ2xlIHRvIHRoZSBmb2N1cykgYmVmb3JlIHdlIHNldFxuICAgICAgICAgICAgLy8gb3VyIHByZXNlbmNlICh0aHJvdWdoIHdoaWNoIHBlZXJzIGFzc29jaWF0ZSByZW1vdGUgc3RyZWFtcyB0b1xuICAgICAgICAgICAgLy8gamlkcykuIFNvLCBpdCBtaWdodCBhcnJpdmUgdGhhdCBhIHJlbW90ZSBzdHJlYW0gaXMgYWRkZWQgYnV0XG4gICAgICAgICAgICAvLyBzc3JjMmppZCBpcyBub3QgeWV0IHVwZGF0ZWQgYW5kIHRodXMgZGF0YS5wZWVyamlkIGNhbm5vdCBiZVxuICAgICAgICAgICAgLy8gc3VjY2Vzc2Z1bGx5IHNldC4gSGVyZSB3ZSB3YWl0IGZvciB1cCB0byBhIHNlY29uZCBmb3IgdGhlXG4gICAgICAgICAgICAvLyBwcmVzZW5jZSB0byBhcnJpdmUuXG5cbiAgICAgICAgICAgIGlmICghc3NyYzJqaWRbdGhlc3NyY10pIHtcbiAgICAgICAgICAgICAgICAvLyBUT0RPKGdwKSBsaW1pdCB3YWl0IGR1cmF0aW9uIHRvIDEgc2VjLlxuICAgICAgICAgICAgICAgIHNldFRpbWVvdXQoZnVuY3Rpb24oZCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gZnVuY3Rpb24oKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnJlbW90ZVN0cmVhbUFkZGVkKGQpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfShkYXRhKSwgMjUwKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIG9rIHRvIG92ZXJ3cml0ZSB0aGUgb25lIGZyb20gZm9jdXM/IG1pZ2h0IHNhdmUgd29yayBpbiBjb2xpYnJpLmpzXG4gICAgICAgICAgICBjb25zb2xlLmxvZygnYXNzb2NpYXRlZCBqaWQnLCBzc3JjMmppZFt0aGVzc3JjXSwgZGF0YS5wZWVyamlkKTtcbiAgICAgICAgICAgIGlmIChzc3JjMmppZFt0aGVzc3JjXSkge1xuICAgICAgICAgICAgICAgIGRhdGEucGVlcmppZCA9IHNzcmMyamlkW3RoZXNzcmNdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfVxuXG4gICAgLy9UT0RPOiB0aGlzIGNvZGUgc2hvdWxkIGJlIHJlbW92ZWQgd2hlbiBmaXJlZm94IGltcGxlbWVudCBtdWx0aXN0cmVhbSBzdXBwb3J0XG4gICAgaWYoQVBQLlJUQy5nZXRCcm93c2VyVHlwZSgpID09IFJUQ0Jyb3dzZXJUeXBlLlJUQ19CUk9XU0VSX0ZJUkVGT1gpXG4gICAge1xuICAgICAgICBpZigoSmluZ2xlU2Vzc2lvbi5ub3RSZWNlaXZlZFNTUkNzLmxlbmd0aCA9PSAwKSB8fFxuICAgICAgICAgICAgIXNzcmMyamlkW0ppbmdsZVNlc3Npb24ubm90UmVjZWl2ZWRTU1JDc1tKaW5nbGVTZXNzaW9uLm5vdFJlY2VpdmVkU1NSQ3MubGVuZ3RoIC0gMV1dKVxuICAgICAgICB7XG4gICAgICAgICAgICAvLyBUT0RPKGdwKSBsaW1pdCB3YWl0IGR1cmF0aW9uIHRvIDEgc2VjLlxuICAgICAgICAgICAgc2V0VGltZW91dChmdW5jdGlvbihkKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgICAgICBzZWxmLnJlbW90ZVN0cmVhbUFkZGVkKGQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0oZGF0YSksIDI1MCk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB0aGVzc3JjID0gSmluZ2xlU2Vzc2lvbi5ub3RSZWNlaXZlZFNTUkNzLnBvcCgpO1xuICAgICAgICBpZiAoc3NyYzJqaWRbdGhlc3NyY10pIHtcbiAgICAgICAgICAgIGRhdGEucGVlcmppZCA9IHNzcmMyamlkW3RoZXNzcmNdO1xuICAgICAgICB9XG4gICAgfVxuXG4gICAgQVBQLlJUQy5jcmVhdGVSZW1vdGVTdHJlYW0oZGF0YSwgdGhpcy5zaWQsIHRoZXNzcmMpO1xuXG4gICAgdmFyIGlzVmlkZW8gPSBkYXRhLnN0cmVhbS5nZXRWaWRlb1RyYWNrcygpLmxlbmd0aCA+IDA7XG4gICAgLy8gYW4gYXR0ZW1wdCB0byB3b3JrIGFyb3VuZCBodHRwczovL2dpdGh1Yi5jb20vaml0c2kvaml0bWVldC9pc3N1ZXMvMzJcbiAgICBpZiAoaXNWaWRlbyAmJlxuICAgICAgICBkYXRhLnBlZXJqaWQgJiYgdGhpcy5wZWVyamlkID09PSBkYXRhLnBlZXJqaWQgJiZcbiAgICAgICAgZGF0YS5zdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5sZW5ndGggPT09IDAgJiZcbiAgICAgICAgQVBQLlJUQy5sb2NhbFZpZGVvLmdldFRyYWNrcygpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgd2luZG93LnNldFRpbWVvdXQoZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VuZEtleWZyYW1lKHNlbGYucGVlcmNvbm5lY3Rpb24pO1xuICAgICAgICB9LCAzMDAwKTtcbiAgICB9XG59XG5cbm1vZHVsZS5leHBvcnRzID0gSmluZ2xlU2Vzc2lvbjtcbiIsIi8qIGpzaGludCAtVzExNyAqL1xudmFyIFNEUFV0aWwgPSByZXF1aXJlKFwiLi9TRFBVdGlsXCIpO1xuXG4vLyBTRFAgU1RVRkZcbmZ1bmN0aW9uIFNEUChzZHApIHtcbiAgICB0aGlzLm1lZGlhID0gc2RwLnNwbGl0KCdcXHJcXG5tPScpO1xuICAgIGZvciAodmFyIGkgPSAxOyBpIDwgdGhpcy5tZWRpYS5sZW5ndGg7IGkrKykge1xuICAgICAgICB0aGlzLm1lZGlhW2ldID0gJ209JyArIHRoaXMubWVkaWFbaV07XG4gICAgICAgIGlmIChpICE9IHRoaXMubWVkaWEubGVuZ3RoIC0gMSkge1xuICAgICAgICAgICAgdGhpcy5tZWRpYVtpXSArPSAnXFxyXFxuJztcbiAgICAgICAgfVxuICAgIH1cbiAgICB0aGlzLnNlc3Npb24gPSB0aGlzLm1lZGlhLnNoaWZ0KCkgKyAnXFxyXFxuJztcbiAgICB0aGlzLnJhdyA9IHRoaXMuc2Vzc2lvbiArIHRoaXMubWVkaWEuam9pbignJyk7XG59XG4vKipcbiAqIFJldHVybnMgbWFwIG9mIE1lZGlhQ2hhbm5lbCBtYXBwZWQgcGVyIGNoYW5uZWwgaWR4LlxuICovXG5TRFAucHJvdG90eXBlLmdldE1lZGlhU3NyY01hcCA9IGZ1bmN0aW9uKCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgbWVkaWFfc3NyY3MgPSB7fTtcbiAgICB2YXIgdG1wO1xuICAgIGZvciAodmFyIG1lZGlhaW5kZXggPSAwOyBtZWRpYWluZGV4IDwgc2VsZi5tZWRpYS5sZW5ndGg7IG1lZGlhaW5kZXgrKykge1xuICAgICAgICB0bXAgPSBTRFBVdGlsLmZpbmRfbGluZXMoc2VsZi5tZWRpYVttZWRpYWluZGV4XSwgJ2E9c3NyYzonKTtcbiAgICAgICAgdmFyIG1pZCA9IFNEUFV0aWwucGFyc2VfbWlkKFNEUFV0aWwuZmluZF9saW5lKHNlbGYubWVkaWFbbWVkaWFpbmRleF0sICdhPW1pZDonKSk7XG4gICAgICAgIHZhciBtZWRpYSA9IHtcbiAgICAgICAgICAgIG1lZGlhaW5kZXg6IG1lZGlhaW5kZXgsXG4gICAgICAgICAgICBtaWQ6IG1pZCxcbiAgICAgICAgICAgIHNzcmNzOiB7fSxcbiAgICAgICAgICAgIHNzcmNHcm91cHM6IFtdXG4gICAgICAgIH07XG4gICAgICAgIG1lZGlhX3NzcmNzW21lZGlhaW5kZXhdID0gbWVkaWE7XG4gICAgICAgIHRtcC5mb3JFYWNoKGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgICAgICB2YXIgbGluZXNzcmMgPSBsaW5lLnN1YnN0cmluZyg3KS5zcGxpdCgnICcpWzBdO1xuICAgICAgICAgICAgLy8gYWxsb2NhdGUgbmV3IENoYW5uZWxTc3JjXG4gICAgICAgICAgICBpZighbWVkaWEuc3NyY3NbbGluZXNzcmNdKSB7XG4gICAgICAgICAgICAgICAgbWVkaWEuc3NyY3NbbGluZXNzcmNdID0ge1xuICAgICAgICAgICAgICAgICAgICBzc3JjOiBsaW5lc3NyYyxcbiAgICAgICAgICAgICAgICAgICAgbGluZXM6IFtdXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG1lZGlhLnNzcmNzW2xpbmVzc3JjXS5saW5lcy5wdXNoKGxpbmUpO1xuICAgICAgICB9KTtcbiAgICAgICAgdG1wID0gU0RQVXRpbC5maW5kX2xpbmVzKHNlbGYubWVkaWFbbWVkaWFpbmRleF0sICdhPXNzcmMtZ3JvdXA6Jyk7XG4gICAgICAgIHRtcC5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpe1xuICAgICAgICAgICAgdmFyIHNlbWFudGljcyA9IGxpbmUuc3Vic3RyKDAsIGlkeCkuc3Vic3RyKDEzKTtcbiAgICAgICAgICAgIHZhciBzc3JjcyA9IGxpbmUuc3Vic3RyKDE0ICsgc2VtYW50aWNzLmxlbmd0aCkuc3BsaXQoJyAnKTtcbiAgICAgICAgICAgIGlmIChzc3Jjcy5sZW5ndGggIT0gMCkge1xuICAgICAgICAgICAgICAgIG1lZGlhLnNzcmNHcm91cHMucHVzaCh7XG4gICAgICAgICAgICAgICAgICAgIHNlbWFudGljczogc2VtYW50aWNzLFxuICAgICAgICAgICAgICAgICAgICBzc3Jjczogc3NyY3NcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHJldHVybiBtZWRpYV9zc3Jjcztcbn07XG4vKipcbiAqIFJldHVybnMgPHR0PnRydWU8L3R0PiBpZiB0aGlzIFNEUCBjb250YWlucyBnaXZlbiBTU1JDLlxuICogQHBhcmFtIHNzcmMgdGhlIHNzcmMgdG8gY2hlY2suXG4gKiBAcmV0dXJucyB7Ym9vbGVhbn0gPHR0PnRydWU8L3R0PiBpZiB0aGlzIFNEUCBjb250YWlucyBnaXZlbiBTU1JDLlxuICovXG5TRFAucHJvdG90eXBlLmNvbnRhaW5zU1NSQyA9IGZ1bmN0aW9uKHNzcmMpIHtcbiAgICB2YXIgbWVkaWFzID0gdGhpcy5nZXRNZWRpYVNzcmNNYXAoKTtcbiAgICB2YXIgY29udGFpbnMgPSBmYWxzZTtcbiAgICBPYmplY3Qua2V5cyhtZWRpYXMpLmZvckVhY2goZnVuY3Rpb24obWVkaWFpbmRleCl7XG4gICAgICAgIHZhciBtZWRpYSA9IG1lZGlhc1ttZWRpYWluZGV4XTtcbiAgICAgICAgLy9jb25zb2xlLmxvZyhcIkNoZWNrXCIsIGNoYW5uZWwsIHNzcmMpO1xuICAgICAgICBpZihPYmplY3Qua2V5cyhtZWRpYS5zc3JjcykuaW5kZXhPZihzc3JjKSAhPSAtMSl7XG4gICAgICAgICAgICBjb250YWlucyA9IHRydWU7XG4gICAgICAgIH1cbiAgICB9KTtcbiAgICByZXR1cm4gY29udGFpbnM7XG59O1xuXG5cbi8vIHJlbW92ZSBpU0FDIGFuZCBDTiBmcm9tIFNEUFxuU0RQLnByb3RvdHlwZS5tYW5nbGUgPSBmdW5jdGlvbiAoKSB7XG4gICAgdmFyIGksIGosIG1saW5lLCBsaW5lcywgcnRwbWFwLCBuZXdkZXNjO1xuICAgIGZvciAoaSA9IDA7IGkgPCB0aGlzLm1lZGlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIGxpbmVzID0gdGhpcy5tZWRpYVtpXS5zcGxpdCgnXFxyXFxuJyk7XG4gICAgICAgIGxpbmVzLnBvcCgpOyAvLyByZW1vdmUgZW1wdHkgbGFzdCBlbGVtZW50XG4gICAgICAgIG1saW5lID0gU0RQVXRpbC5wYXJzZV9tbGluZShsaW5lcy5zaGlmdCgpKTtcbiAgICAgICAgaWYgKG1saW5lLm1lZGlhICE9ICdhdWRpbycpXG4gICAgICAgICAgICBjb250aW51ZTtcbiAgICAgICAgbmV3ZGVzYyA9ICcnO1xuICAgICAgICBtbGluZS5mbXQubGVuZ3RoID0gMDtcbiAgICAgICAgZm9yIChqID0gMDsgaiA8IGxpbmVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICBpZiAobGluZXNbal0uc3Vic3RyKDAsIDkpID09ICdhPXJ0cG1hcDonKSB7XG4gICAgICAgICAgICAgICAgcnRwbWFwID0gU0RQVXRpbC5wYXJzZV9ydHBtYXAobGluZXNbal0pO1xuICAgICAgICAgICAgICAgIGlmIChydHBtYXAubmFtZSA9PSAnQ04nIHx8IHJ0cG1hcC5uYW1lID09ICdJU0FDJylcbiAgICAgICAgICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgICAgICAgICAgbWxpbmUuZm10LnB1c2gocnRwbWFwLmlkKTtcbiAgICAgICAgICAgICAgICBuZXdkZXNjICs9IGxpbmVzW2pdICsgJ1xcclxcbic7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG5ld2Rlc2MgKz0gbGluZXNbal0gKyAnXFxyXFxuJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICB0aGlzLm1lZGlhW2ldID0gU0RQVXRpbC5idWlsZF9tbGluZShtbGluZSkgKyAnXFxyXFxuJztcbiAgICAgICAgdGhpcy5tZWRpYVtpXSArPSBuZXdkZXNjO1xuICAgIH1cbiAgICB0aGlzLnJhdyA9IHRoaXMuc2Vzc2lvbiArIHRoaXMubWVkaWEuam9pbignJyk7XG59O1xuXG4vLyByZW1vdmUgbGluZXMgbWF0Y2hpbmcgcHJlZml4IGZyb20gc2Vzc2lvbiBzZWN0aW9uXG5TRFAucHJvdG90eXBlLnJlbW92ZVNlc3Npb25MaW5lcyA9IGZ1bmN0aW9uKHByZWZpeCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgbGluZXMgPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5zZXNzaW9uLCBwcmVmaXgpO1xuICAgIGxpbmVzLmZvckVhY2goZnVuY3Rpb24obGluZSkge1xuICAgICAgICBzZWxmLnNlc3Npb24gPSBzZWxmLnNlc3Npb24ucmVwbGFjZShsaW5lICsgJ1xcclxcbicsICcnKTtcbiAgICB9KTtcbiAgICB0aGlzLnJhdyA9IHRoaXMuc2Vzc2lvbiArIHRoaXMubWVkaWEuam9pbignJyk7XG4gICAgcmV0dXJuIGxpbmVzO1xufVxuLy8gcmVtb3ZlIGxpbmVzIG1hdGNoaW5nIHByZWZpeCBmcm9tIGEgbWVkaWEgc2VjdGlvbiBzcGVjaWZpZWQgYnkgbWVkaWFpbmRleFxuLy8gVE9ETzogbm9uLW51bWVyaWMgbWVkaWFpbmRleCBjb3VsZCBtYXRjaCBtaWRcblNEUC5wcm90b3R5cGUucmVtb3ZlTWVkaWFMaW5lcyA9IGZ1bmN0aW9uKG1lZGlhaW5kZXgsIHByZWZpeCkge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB2YXIgbGluZXMgPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5tZWRpYVttZWRpYWluZGV4XSwgcHJlZml4KTtcbiAgICBsaW5lcy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgICAgc2VsZi5tZWRpYVttZWRpYWluZGV4XSA9IHNlbGYubWVkaWFbbWVkaWFpbmRleF0ucmVwbGFjZShsaW5lICsgJ1xcclxcbicsICcnKTtcbiAgICB9KTtcbiAgICB0aGlzLnJhdyA9IHRoaXMuc2Vzc2lvbiArIHRoaXMubWVkaWEuam9pbignJyk7XG4gICAgcmV0dXJuIGxpbmVzO1xufVxuXG4vLyBhZGQgY29udGVudCdzIHRvIGEgamluZ2xlIGVsZW1lbnRcblNEUC5wcm90b3R5cGUudG9KaW5nbGUgPSBmdW5jdGlvbiAoZWxlbSwgdGhlY3JlYXRvciwgc3NyY3MpIHtcbi8vICAgIGNvbnNvbGUubG9nKFwiU1NSQ1wiICsgc3NyY3NbXCJhdWRpb1wiXSArIFwiIC0gXCIgKyBzc3Jjc1tcInZpZGVvXCJdKTtcbiAgICB2YXIgaSwgaiwgaywgbWxpbmUsIHNzcmMsIHJ0cG1hcCwgdG1wLCBsaW5lLCBsaW5lcztcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgLy8gbmV3IGJ1bmRsZSBwbGFuXG4gICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMuc2Vzc2lvbiwgJ2E9Z3JvdXA6JykpIHtcbiAgICAgICAgbGluZXMgPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5zZXNzaW9uLCAnYT1ncm91cDonKTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IGxpbmVzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICB0bXAgPSBsaW5lc1tpXS5zcGxpdCgnICcpO1xuICAgICAgICAgICAgdmFyIHNlbWFudGljcyA9IHRtcC5zaGlmdCgpLnN1YnN0cig4KTtcbiAgICAgICAgICAgIGVsZW0uYygnZ3JvdXAnLCB7eG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6YXBwczpncm91cGluZzowJywgc2VtYW50aWNzOnNlbWFudGljc30pO1xuICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IHRtcC5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgICAgIGVsZW0uYygnY29udGVudCcsIHtuYW1lOiB0bXBbal19KS51cCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICB9XG4gICAgfVxuICAgIGZvciAoaSA9IDA7IGkgPCB0aGlzLm1lZGlhLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgIG1saW5lID0gU0RQVXRpbC5wYXJzZV9tbGluZSh0aGlzLm1lZGlhW2ldLnNwbGl0KCdcXHJcXG4nKVswXSk7XG4gICAgICAgIGlmICghKG1saW5lLm1lZGlhID09PSAnYXVkaW8nIHx8XG4gICAgICAgICAgICAgIG1saW5lLm1lZGlhID09PSAndmlkZW8nIHx8XG4gICAgICAgICAgICAgIG1saW5lLm1lZGlhID09PSAnYXBwbGljYXRpb24nKSlcbiAgICAgICAge1xuICAgICAgICAgICAgY29udGludWU7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPXNzcmM6JykpIHtcbiAgICAgICAgICAgIHNzcmMgPSBTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW2ldLCAnYT1zc3JjOicpLnN1YnN0cmluZyg3KS5zcGxpdCgnICcpWzBdOyAvLyB0YWtlIHRoZSBmaXJzdFxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgaWYoc3NyY3MgJiYgc3NyY3NbbWxpbmUubWVkaWFdKVxuICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgIHNzcmMgPSBzc3Jjc1ttbGluZS5tZWRpYV07XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgc3NyYyA9IGZhbHNlO1xuICAgICAgICB9XG5cbiAgICAgICAgZWxlbS5jKCdjb250ZW50Jywge2NyZWF0b3I6IHRoZWNyZWF0b3IsIG5hbWU6IG1saW5lLm1lZGlhfSk7XG4gICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW2ldLCAnYT1taWQ6JykpIHtcbiAgICAgICAgICAgIC8vIHByZWZlciBpZGVudGlmaWVyIGZyb20gYT1taWQgaWYgcHJlc2VudFxuICAgICAgICAgICAgdmFyIG1pZCA9IFNEUFV0aWwucGFyc2VfbWlkKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPW1pZDonKSk7XG4gICAgICAgICAgICBlbGVtLmF0dHJzKHsgbmFtZTogbWlkIH0pO1xuICAgICAgICB9XG5cbiAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPXJ0cG1hcDonKS5sZW5ndGgpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGVsZW0uYygnZGVzY3JpcHRpb24nLFxuICAgICAgICAgICAgICAgIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDoxJyxcbiAgICAgICAgICAgICAgICAgICAgbWVkaWE6IG1saW5lLm1lZGlhIH0pO1xuICAgICAgICAgICAgaWYgKHNzcmMpIHtcbiAgICAgICAgICAgICAgICBlbGVtLmF0dHJzKHtzc3JjOiBzc3JjfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBmb3IgKGogPSAwOyBqIDwgbWxpbmUuZm10Lmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgcnRwbWFwID0gU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9cnRwbWFwOicgKyBtbGluZS5mbXRbal0pO1xuICAgICAgICAgICAgICAgIGVsZW0uYygncGF5bG9hZC10eXBlJywgU0RQVXRpbC5wYXJzZV9ydHBtYXAocnRwbWFwKSk7XG4gICAgICAgICAgICAgICAgLy8gcHV0IGFueSAnYT1mbXRwOicgKyBtbGluZS5mbXRbal0gbGluZXMgaW50byA8cGFyYW0gbmFtZT1mb28gdmFsdWU9YmFyLz5cbiAgICAgICAgICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9Zm10cDonICsgbWxpbmUuZm10W2pdKSkge1xuICAgICAgICAgICAgICAgICAgICB0bXAgPSBTRFBVdGlsLnBhcnNlX2ZtdHAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9Zm10cDonICsgbWxpbmUuZm10W2pdKSk7XG4gICAgICAgICAgICAgICAgICAgIGZvciAoayA9IDA7IGsgPCB0bXAubGVuZ3RoOyBrKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYygncGFyYW1ldGVyJywgdG1wW2tdKS51cCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIHRoaXMuUnRjcEZiVG9KaW5nbGUoaSwgZWxlbSwgbWxpbmUuZm10W2pdKTsgLy8gWEVQLTAyOTMgLS0gbWFwIGE9cnRjcC1mYlxuXG4gICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPWNyeXB0bzonLCB0aGlzLnNlc3Npb24pKSB7XG4gICAgICAgICAgICAgICAgZWxlbS5jKCdlbmNyeXB0aW9uJywge3JlcXVpcmVkOiAxfSk7XG4gICAgICAgICAgICAgICAgdmFyIGNyeXB0byA9IFNEUFV0aWwuZmluZF9saW5lcyh0aGlzLm1lZGlhW2ldLCAnYT1jcnlwdG86JywgdGhpcy5zZXNzaW9uKTtcbiAgICAgICAgICAgICAgICBjcnlwdG8uZm9yRWFjaChmdW5jdGlvbihsaW5lKSB7XG4gICAgICAgICAgICAgICAgICAgIGVsZW0uYygnY3J5cHRvJywgU0RQVXRpbC5wYXJzZV9jcnlwdG8obGluZSkpLnVwKCk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgZWxlbS51cCgpOyAvLyBlbmQgb2YgZW5jcnlwdGlvblxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoc3NyYykge1xuICAgICAgICAgICAgICAgIC8vIG5ldyBzdHlsZSBtYXBwaW5nXG4gICAgICAgICAgICAgICAgZWxlbS5jKCdzb3VyY2UnLCB7IHNzcmM6IHNzcmMsIHhtbG5zOiAndXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnNzbWE6MCcgfSk7XG4gICAgICAgICAgICAgICAgLy8gRklYTUU6IGdyb3VwIGJ5IHNzcmMgYW5kIHN1cHBvcnQgbXVsdGlwbGUgZGlmZmVyZW50IHNzcmNzXG4gICAgICAgICAgICAgICAgdmFyIHNzcmNsaW5lcyA9IFNEUFV0aWwuZmluZF9saW5lcyh0aGlzLm1lZGlhW2ldLCAnYT1zc3JjOicpO1xuICAgICAgICAgICAgICAgIGlmKHNzcmNsaW5lcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgIHNzcmNsaW5lcy5mb3JFYWNoKGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZHggPSBsaW5lLmluZGV4T2YoJyAnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBsaW5lc3NyYyA9IGxpbmUuc3Vic3RyKDAsIGlkeCkuc3Vic3RyKDcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGxpbmVzc3JjICE9IHNzcmMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3NyYyA9IGxpbmVzc3JjO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYygnc291cmNlJywgeyBzc3JjOiBzc3JjLCB4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpzc21hOjAnIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGt2ID0gbGluZS5zdWJzdHIoaWR4ICsgMSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmMoJ3BhcmFtZXRlcicpO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGt2LmluZGV4T2YoJzonKSA9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYXR0cnMoeyBuYW1lOiBrdiB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7IG5hbWU6IGt2LnNwbGl0KCc6JywgMilbMF0gfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7IHZhbHVlOiBrdi5zcGxpdCgnOicsIDIpWzFdIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgICAgICAgICAgICAgIGVsZW0uYygnc291cmNlJywgeyBzc3JjOiBzc3JjLCB4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpzc21hOjAnIH0pO1xuICAgICAgICAgICAgICAgICAgICBlbGVtLmMoJ3BhcmFtZXRlcicpO1xuICAgICAgICAgICAgICAgICAgICBlbGVtLmF0dHJzKHtuYW1lOiBcImNuYW1lXCIsIHZhbHVlOk1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cmluZyg3KX0pO1xuICAgICAgICAgICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBtc2lkID0gbnVsbDtcbiAgICAgICAgICAgICAgICAgICAgaWYobWxpbmUubWVkaWEgPT0gXCJhdWRpb1wiKVxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtc2lkID0gQVBQLlJUQy5sb2NhbEF1ZGlvLmdldElkKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtc2lkID0gQVBQLlJUQy5sb2NhbFZpZGVvLmdldElkKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgaWYobXNpZCAhPSBudWxsKVxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBtc2lkID0gbXNpZC5yZXBsYWNlKC9bXFx7LFxcfV0vZyxcIlwiKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYygncGFyYW1ldGVyJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmF0dHJzKHtuYW1lOiBcIm1zaWRcIiwgdmFsdWU6bXNpZH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5jKCdwYXJhbWV0ZXInKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYXR0cnMoe25hbWU6IFwibXNsYWJlbFwiLCB2YWx1ZTptc2lkfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmMoJ3BhcmFtZXRlcicpO1xuICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7bmFtZTogXCJsYWJlbFwiLCB2YWx1ZTptc2lkfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgLy8gWEVQLTAzMzkgaGFuZGxlIHNzcmMtZ3JvdXAgYXR0cmlidXRlc1xuICAgICAgICAgICAgICAgIHZhciBzc3JjX2dyb3VwX2xpbmVzID0gU0RQVXRpbC5maW5kX2xpbmVzKHRoaXMubWVkaWFbaV0sICdhPXNzcmMtZ3JvdXA6Jyk7XG4gICAgICAgICAgICAgICAgc3NyY19ncm91cF9saW5lcy5mb3JFYWNoKGZ1bmN0aW9uKGxpbmUpIHtcbiAgICAgICAgICAgICAgICAgICAgaWR4ID0gbGluZS5pbmRleE9mKCcgJyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBzZW1hbnRpY3MgPSBsaW5lLnN1YnN0cigwLCBpZHgpLnN1YnN0cigxMyk7XG4gICAgICAgICAgICAgICAgICAgIHZhciBzc3JjcyA9IGxpbmUuc3Vic3RyKDE0ICsgc2VtYW50aWNzLmxlbmd0aCkuc3BsaXQoJyAnKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHNzcmNzLmxlbmd0aCAhPSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmMoJ3NzcmMtZ3JvdXAnLCB7IHNlbWFudGljczogc2VtYW50aWNzLCB4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpzc21hOjAnIH0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgc3NyY3MuZm9yRWFjaChmdW5jdGlvbihzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5jKCdzb3VyY2UnLCB7IHNzcmM6IHNzcmMgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLnVwKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0udXAoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9cnRjcC1tdXgnKSkge1xuICAgICAgICAgICAgICAgIGVsZW0uYygncnRjcC1tdXgnKS51cCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBYRVAtMDI5MyAtLSBtYXAgYT1ydGNwLWZiOipcbiAgICAgICAgICAgIHRoaXMuUnRjcEZiVG9KaW5nbGUoaSwgZWxlbSwgJyonKTtcblxuICAgICAgICAgICAgLy8gWEVQLTAyOTRcbiAgICAgICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW2ldLCAnYT1leHRtYXA6JykpIHtcbiAgICAgICAgICAgICAgICBsaW5lcyA9IFNEUFV0aWwuZmluZF9saW5lcyh0aGlzLm1lZGlhW2ldLCAnYT1leHRtYXA6Jyk7XG4gICAgICAgICAgICAgICAgZm9yIChqID0gMDsgaiA8IGxpbmVzLmxlbmd0aDsgaisrKSB7XG4gICAgICAgICAgICAgICAgICAgIHRtcCA9IFNEUFV0aWwucGFyc2VfZXh0bWFwKGxpbmVzW2pdKTtcbiAgICAgICAgICAgICAgICAgICAgZWxlbS5jKCdydHAtaGRyZXh0JywgeyB4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpydHAtaGRyZXh0OjAnLFxuICAgICAgICAgICAgICAgICAgICAgICAgdXJpOiB0bXAudXJpLFxuICAgICAgICAgICAgICAgICAgICAgICAgaWQ6IHRtcC52YWx1ZSB9KTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRtcC5oYXNPd25Qcm9wZXJ0eSgnZGlyZWN0aW9uJykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN3aXRjaCAodG1wLmRpcmVjdGlvbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ3NlbmRvbmx5JzpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7c2VuZGVyczogJ3Jlc3BvbmRlcid9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAncmVjdm9ubHknOlxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbGVtLmF0dHJzKHtzZW5kZXJzOiAnaW5pdGlhdG9yJ30pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdzZW5kcmVjdic6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYXR0cnMoe3NlbmRlcnM6ICdib3RoJ30pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdpbmFjdGl2ZSc6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsZW0uYXR0cnMoe3NlbmRlcnM6ICdub25lJ30pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAvLyBUT0RPOiBoYW5kbGUgcGFyYW1zXG4gICAgICAgICAgICAgICAgICAgIGVsZW0udXAoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbGVtLnVwKCk7IC8vIGVuZCBvZiBkZXNjcmlwdGlvblxuICAgICAgICB9XG5cbiAgICAgICAgLy8gbWFwIGljZS11ZnJhZy9wd2QsIGR0bHMgZmluZ2VycHJpbnQsIGNhbmRpZGF0ZXNcbiAgICAgICAgdGhpcy5UcmFuc3BvcnRUb0ppbmdsZShpLCBlbGVtKTtcblxuICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9c2VuZHJlY3YnLCB0aGlzLnNlc3Npb24pKSB7XG4gICAgICAgICAgICBlbGVtLmF0dHJzKHtzZW5kZXJzOiAnYm90aCd9KTtcbiAgICAgICAgfSBlbHNlIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW2ldLCAnYT1zZW5kb25seScsIHRoaXMuc2Vzc2lvbikpIHtcbiAgICAgICAgICAgIGVsZW0uYXR0cnMoe3NlbmRlcnM6ICdpbml0aWF0b3InfSk7XG4gICAgICAgIH0gZWxzZSBpZiAoU0RQVXRpbC5maW5kX2xpbmUodGhpcy5tZWRpYVtpXSwgJ2E9cmVjdm9ubHknLCB0aGlzLnNlc3Npb24pKSB7XG4gICAgICAgICAgICBlbGVtLmF0dHJzKHtzZW5kZXJzOiAncmVzcG9uZGVyJ30pO1xuICAgICAgICB9IGVsc2UgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbaV0sICdhPWluYWN0aXZlJywgdGhpcy5zZXNzaW9uKSkge1xuICAgICAgICAgICAgZWxlbS5hdHRycyh7c2VuZGVyczogJ25vbmUnfSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG1saW5lLnBvcnQgPT0gJzAnKSB7XG4gICAgICAgICAgICAvLyBlc3RvcyBoYWNrIHRvIHJlamVjdCBhbiBtLWxpbmVcbiAgICAgICAgICAgIGVsZW0uYXR0cnMoe3NlbmRlcnM6ICdyZWplY3RlZCd9KTtcbiAgICAgICAgfVxuICAgICAgICBlbGVtLnVwKCk7IC8vIGVuZCBvZiBjb250ZW50XG4gICAgfVxuICAgIGVsZW0udXAoKTtcbiAgICByZXR1cm4gZWxlbTtcbn07XG5cblNEUC5wcm90b3R5cGUuVHJhbnNwb3J0VG9KaW5nbGUgPSBmdW5jdGlvbiAobWVkaWFpbmRleCwgZWxlbSkge1xuICAgIHZhciBpID0gbWVkaWFpbmRleDtcbiAgICB2YXIgdG1wO1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBlbGVtLmMoJ3RyYW5zcG9ydCcpO1xuXG4gICAgLy8gWEVQLTAzNDMgRFRMUy9TQ1RQXG4gICAgaWYgKFNEUFV0aWwuZmluZF9saW5lKHRoaXMubWVkaWFbbWVkaWFpbmRleF0sICdhPXNjdHBtYXA6JykubGVuZ3RoKVxuICAgIHtcbiAgICAgICAgdmFyIHNjdHBtYXAgPSBTRFBVdGlsLmZpbmRfbGluZShcbiAgICAgICAgICAgIHRoaXMubWVkaWFbaV0sICdhPXNjdHBtYXA6Jywgc2VsZi5zZXNzaW9uKTtcbiAgICAgICAgaWYgKHNjdHBtYXApXG4gICAgICAgIHtcbiAgICAgICAgICAgIHZhciBzY3RwQXR0cnMgPSBTRFBVdGlsLnBhcnNlX3NjdHBtYXAoc2N0cG1hcCk7XG4gICAgICAgICAgICBlbGVtLmMoJ3NjdHBtYXAnLFxuICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgeG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6dHJhbnNwb3J0czpkdGxzLXNjdHA6MScsXG4gICAgICAgICAgICAgICAgICAgIG51bWJlcjogc2N0cEF0dHJzWzBdLCAvKiBTQ1RQIHBvcnQgKi9cbiAgICAgICAgICAgICAgICAgICAgcHJvdG9jb2w6IHNjdHBBdHRyc1sxXSwgLyogcHJvdG9jb2wgKi9cbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIC8vIE9wdGlvbmFsIHN0cmVhbSBjb3VudCBhdHRyaWJ1dGVcbiAgICAgICAgICAgIGlmIChzY3RwQXR0cnMubGVuZ3RoID4gMilcbiAgICAgICAgICAgICAgICBlbGVtLmF0dHJzKHsgc3RyZWFtczogc2N0cEF0dHJzWzJdfSk7XG4gICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgLy8gWEVQLTAzMjBcbiAgICB2YXIgZmluZ2VycHJpbnRzID0gU0RQVXRpbC5maW5kX2xpbmVzKHRoaXMubWVkaWFbbWVkaWFpbmRleF0sICdhPWZpbmdlcnByaW50OicsIHRoaXMuc2Vzc2lvbik7XG4gICAgZmluZ2VycHJpbnRzLmZvckVhY2goZnVuY3Rpb24obGluZSkge1xuICAgICAgICB0bXAgPSBTRFBVdGlsLnBhcnNlX2ZpbmdlcnByaW50KGxpbmUpO1xuICAgICAgICB0bXAueG1sbnMgPSAndXJuOnhtcHA6amluZ2xlOmFwcHM6ZHRsczowJztcbiAgICAgICAgZWxlbS5jKCdmaW5nZXJwcmludCcpLnQodG1wLmZpbmdlcnByaW50KTtcbiAgICAgICAgZGVsZXRlIHRtcC5maW5nZXJwcmludDtcbiAgICAgICAgbGluZSA9IFNEUFV0aWwuZmluZF9saW5lKHNlbGYubWVkaWFbbWVkaWFpbmRleF0sICdhPXNldHVwOicsIHNlbGYuc2Vzc2lvbik7XG4gICAgICAgIGlmIChsaW5lKSB7XG4gICAgICAgICAgICB0bXAuc2V0dXAgPSBsaW5lLnN1YnN0cig4KTtcbiAgICAgICAgfVxuICAgICAgICBlbGVtLmF0dHJzKHRtcCk7XG4gICAgICAgIGVsZW0udXAoKTsgLy8gZW5kIG9mIGZpbmdlcnByaW50XG4gICAgfSk7XG4gICAgdG1wID0gU0RQVXRpbC5pY2VwYXJhbXModGhpcy5tZWRpYVttZWRpYWluZGV4XSwgdGhpcy5zZXNzaW9uKTtcbiAgICBpZiAodG1wKSB7XG4gICAgICAgIHRtcC54bWxucyA9ICd1cm46eG1wcDpqaW5nbGU6dHJhbnNwb3J0czppY2UtdWRwOjEnO1xuICAgICAgICBlbGVtLmF0dHJzKHRtcCk7XG4gICAgICAgIC8vIFhFUC0wMTc2XG4gICAgICAgIGlmIChTRFBVdGlsLmZpbmRfbGluZSh0aGlzLm1lZGlhW21lZGlhaW5kZXhdLCAnYT1jYW5kaWRhdGU6JywgdGhpcy5zZXNzaW9uKSkgeyAvLyBhZGQgYW55IGE9Y2FuZGlkYXRlIGxpbmVzXG4gICAgICAgICAgICB2YXIgbGluZXMgPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5tZWRpYVttZWRpYWluZGV4XSwgJ2E9Y2FuZGlkYXRlOicsIHRoaXMuc2Vzc2lvbik7XG4gICAgICAgICAgICBsaW5lcy5mb3JFYWNoKGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgICAgICAgICAgZWxlbS5jKCdjYW5kaWRhdGUnLCBTRFBVdGlsLmNhbmRpZGF0ZVRvSmluZ2xlKGxpbmUpKS51cCgpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgZWxlbS51cCgpOyAvLyBlbmQgb2YgdHJhbnNwb3J0XG59XG5cblNEUC5wcm90b3R5cGUuUnRjcEZiVG9KaW5nbGUgPSBmdW5jdGlvbiAobWVkaWFpbmRleCwgZWxlbSwgcGF5bG9hZHR5cGUpIHsgLy8gWEVQLTAyOTNcbiAgICB2YXIgbGluZXMgPSBTRFBVdGlsLmZpbmRfbGluZXModGhpcy5tZWRpYVttZWRpYWluZGV4XSwgJ2E9cnRjcC1mYjonICsgcGF5bG9hZHR5cGUpO1xuICAgIGxpbmVzLmZvckVhY2goZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIHRtcCA9IFNEUFV0aWwucGFyc2VfcnRjcGZiKGxpbmUpO1xuICAgICAgICBpZiAodG1wLnR5cGUgPT0gJ3Ryci1pbnQnKSB7XG4gICAgICAgICAgICBlbGVtLmMoJ3J0Y3AtZmItdHJyLWludCcsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDpydGNwLWZiOjAnLCB2YWx1ZTogdG1wLnBhcmFtc1swXX0pO1xuICAgICAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZWxlbS5jKCdydGNwLWZiJywge3htbG5zOiAndXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnJ0Y3AtZmI6MCcsIHR5cGU6IHRtcC50eXBlfSk7XG4gICAgICAgICAgICBpZiAodG1wLnBhcmFtcy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgZWxlbS5hdHRycyh7J3N1YnR5cGUnOiB0bXAucGFyYW1zWzBdfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBlbGVtLnVwKCk7XG4gICAgICAgIH1cbiAgICB9KTtcbn07XG5cblNEUC5wcm90b3R5cGUuUnRjcEZiRnJvbUppbmdsZSA9IGZ1bmN0aW9uIChlbGVtLCBwYXlsb2FkdHlwZSkgeyAvLyBYRVAtMDI5M1xuICAgIHZhciBtZWRpYSA9ICcnO1xuICAgIHZhciB0bXAgPSBlbGVtLmZpbmQoJz5ydGNwLWZiLXRyci1pbnRbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6cnRjcC1mYjowXCJdJyk7XG4gICAgaWYgKHRtcC5sZW5ndGgpIHtcbiAgICAgICAgbWVkaWEgKz0gJ2E9cnRjcC1mYjonICsgJyonICsgJyAnICsgJ3Ryci1pbnQnICsgJyAnO1xuICAgICAgICBpZiAodG1wLmF0dHIoJ3ZhbHVlJykpIHtcbiAgICAgICAgICAgIG1lZGlhICs9IHRtcC5hdHRyKCd2YWx1ZScpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgbWVkaWEgKz0gJzAnO1xuICAgICAgICB9XG4gICAgICAgIG1lZGlhICs9ICdcXHJcXG4nO1xuICAgIH1cbiAgICB0bXAgPSBlbGVtLmZpbmQoJz5ydGNwLWZiW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnJ0Y3AtZmI6MFwiXScpO1xuICAgIHRtcC5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbWVkaWEgKz0gJ2E9cnRjcC1mYjonICsgcGF5bG9hZHR5cGUgKyAnICcgKyAkKHRoaXMpLmF0dHIoJ3R5cGUnKTtcbiAgICAgICAgaWYgKCQodGhpcykuYXR0cignc3VidHlwZScpKSB7XG4gICAgICAgICAgICBtZWRpYSArPSAnICcgKyAkKHRoaXMpLmF0dHIoJ3N1YnR5cGUnKTtcbiAgICAgICAgfVxuICAgICAgICBtZWRpYSArPSAnXFxyXFxuJztcbiAgICB9KTtcbiAgICByZXR1cm4gbWVkaWE7XG59O1xuXG4vLyBjb25zdHJ1Y3QgYW4gU0RQIGZyb20gYSBqaW5nbGUgc3RhbnphXG5TRFAucHJvdG90eXBlLmZyb21KaW5nbGUgPSBmdW5jdGlvbiAoamluZ2xlKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMucmF3ID0gJ3Y9MFxcclxcbicgK1xuICAgICAgICAnbz0tICcgKyAnMTkyMzUxODUxNicgKyAnIDIgSU4gSVA0IDAuMC4wLjBcXHJcXG4nICsvLyBGSVhNRVxuICAgICAgICAncz0tXFxyXFxuJyArXG4gICAgICAgICd0PTAgMFxcclxcbic7XG4gICAgLy8gaHR0cDovL3Rvb2xzLmlldGYub3JnL2h0bWwvZHJhZnQtaWV0Zi1tbXVzaWMtc2RwLWJ1bmRsZS1uZWdvdGlhdGlvbi0wNCNzZWN0aW9uLThcbiAgICBpZiAoJChqaW5nbGUpLmZpbmQoJz5ncm91cFt4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOmdyb3VwaW5nOjBcIl0nKS5sZW5ndGgpIHtcbiAgICAgICAgJChqaW5nbGUpLmZpbmQoJz5ncm91cFt4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOmdyb3VwaW5nOjBcIl0nKS5lYWNoKGZ1bmN0aW9uIChpZHgsIGdyb3VwKSB7XG4gICAgICAgICAgICB2YXIgY29udGVudHMgPSAkKGdyb3VwKS5maW5kKCc+Y29udGVudCcpLm1hcChmdW5jdGlvbiAoaWR4LCBjb250ZW50KSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGNvbnRlbnQuZ2V0QXR0cmlidXRlKCduYW1lJyk7XG4gICAgICAgICAgICB9KS5nZXQoKTtcbiAgICAgICAgICAgIGlmIChjb250ZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgc2VsZi5yYXcgKz0gJ2E9Z3JvdXA6JyArIChncm91cC5nZXRBdHRyaWJ1dGUoJ3NlbWFudGljcycpIHx8IGdyb3VwLmdldEF0dHJpYnV0ZSgndHlwZScpKSArICcgJyArIGNvbnRlbnRzLmpvaW4oJyAnKSArICdcXHJcXG4nO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9XG5cbiAgICB0aGlzLnNlc3Npb24gPSB0aGlzLnJhdztcbiAgICBqaW5nbGUuZmluZCgnPmNvbnRlbnQnKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIG0gPSBzZWxmLmppbmdsZTJtZWRpYSgkKHRoaXMpKTtcbiAgICAgICAgc2VsZi5tZWRpYS5wdXNoKG0pO1xuICAgIH0pO1xuXG4gICAgLy8gcmVjb25zdHJ1Y3QgbXNpZC1zZW1hbnRpYyAtLSBhcHBhcmVudGx5IG5vdCBuZWNlc3NhcnlcbiAgICAvKlxuICAgICB2YXIgbXNpZCA9IFNEUFV0aWwucGFyc2Vfc3NyYyh0aGlzLnJhdyk7XG4gICAgIGlmIChtc2lkLmhhc093blByb3BlcnR5KCdtc2xhYmVsJykpIHtcbiAgICAgdGhpcy5zZXNzaW9uICs9IFwiYT1tc2lkLXNlbWFudGljOiBXTVMgXCIgKyBtc2lkLm1zbGFiZWwgKyBcIlxcclxcblwiO1xuICAgICB9XG4gICAgICovXG5cbiAgICB0aGlzLnJhdyA9IHRoaXMuc2Vzc2lvbiArIHRoaXMubWVkaWEuam9pbignJyk7XG59O1xuXG4vLyB0cmFuc2xhdGUgYSBqaW5nbGUgY29udGVudCBlbGVtZW50IGludG8gYW4gYW4gU0RQIG1lZGlhIHBhcnRcblNEUC5wcm90b3R5cGUuamluZ2xlMm1lZGlhID0gZnVuY3Rpb24gKGNvbnRlbnQpIHtcbiAgICB2YXIgbWVkaWEgPSAnJyxcbiAgICAgICAgZGVzYyA9IGNvbnRlbnQuZmluZCgnZGVzY3JpcHRpb24nKSxcbiAgICAgICAgc3NyYyA9IGRlc2MuYXR0cignc3NyYycpLFxuICAgICAgICBzZWxmID0gdGhpcyxcbiAgICAgICAgdG1wO1xuICAgIHZhciBzY3RwID0gY29udGVudC5maW5kKFxuICAgICAgICAnPnRyYW5zcG9ydD5zY3RwbWFwW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOnRyYW5zcG9ydHM6ZHRscy1zY3RwOjFcIl0nKTtcblxuICAgIHRtcCA9IHsgbWVkaWE6IGRlc2MuYXR0cignbWVkaWEnKSB9O1xuICAgIHRtcC5wb3J0ID0gJzEnO1xuICAgIGlmIChjb250ZW50LmF0dHIoJ3NlbmRlcnMnKSA9PSAncmVqZWN0ZWQnKSB7XG4gICAgICAgIC8vIGVzdG9zIGhhY2sgdG8gcmVqZWN0IGFuIG0tbGluZS5cbiAgICAgICAgdG1wLnBvcnQgPSAnMCc7XG4gICAgfVxuICAgIGlmIChjb250ZW50LmZpbmQoJz50cmFuc3BvcnQ+ZmluZ2VycHJpbnQnKS5sZW5ndGggfHwgZGVzYy5maW5kKCdlbmNyeXB0aW9uJykubGVuZ3RoKSB7XG4gICAgICAgIGlmIChzY3RwLmxlbmd0aClcbiAgICAgICAgICAgIHRtcC5wcm90byA9ICdEVExTL1NDVFAnO1xuICAgICAgICBlbHNlXG4gICAgICAgICAgICB0bXAucHJvdG8gPSAnUlRQL1NBVlBGJztcbiAgICB9IGVsc2Uge1xuICAgICAgICB0bXAucHJvdG8gPSAnUlRQL0FWUEYnO1xuICAgIH1cbiAgICBpZiAoIXNjdHAubGVuZ3RoKVxuICAgIHtcbiAgICAgICAgdG1wLmZtdCA9IGRlc2MuZmluZCgncGF5bG9hZC10eXBlJykubWFwKFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkgeyByZXR1cm4gdGhpcy5nZXRBdHRyaWJ1dGUoJ2lkJyk7IH0pLmdldCgpO1xuICAgICAgICBtZWRpYSArPSBTRFBVdGlsLmJ1aWxkX21saW5lKHRtcCkgKyAnXFxyXFxuJztcbiAgICB9XG4gICAgZWxzZVxuICAgIHtcbiAgICAgICAgbWVkaWEgKz0gJ209YXBwbGljYXRpb24gMSBEVExTL1NDVFAgJyArIHNjdHAuYXR0cignbnVtYmVyJykgKyAnXFxyXFxuJztcbiAgICAgICAgbWVkaWEgKz0gJ2E9c2N0cG1hcDonICsgc2N0cC5hdHRyKCdudW1iZXInKSArXG4gICAgICAgICAgICAnICcgKyBzY3RwLmF0dHIoJ3Byb3RvY29sJyk7XG5cbiAgICAgICAgdmFyIHN0cmVhbUNvdW50ID0gc2N0cC5hdHRyKCdzdHJlYW1zJyk7XG4gICAgICAgIGlmIChzdHJlYW1Db3VudClcbiAgICAgICAgICAgIG1lZGlhICs9ICcgJyArIHN0cmVhbUNvdW50ICsgJ1xcclxcbic7XG4gICAgICAgIGVsc2VcbiAgICAgICAgICAgIG1lZGlhICs9ICdcXHJcXG4nO1xuICAgIH1cblxuICAgIG1lZGlhICs9ICdjPUlOIElQNCAwLjAuMC4wXFxyXFxuJztcbiAgICBpZiAoIXNjdHAubGVuZ3RoKVxuICAgICAgICBtZWRpYSArPSAnYT1ydGNwOjEgSU4gSVA0IDAuMC4wLjBcXHJcXG4nO1xuICAgIHRtcCA9IGNvbnRlbnQuZmluZCgnPnRyYW5zcG9ydFt4bWxucz1cInVybjp4bXBwOmppbmdsZTp0cmFuc3BvcnRzOmljZS11ZHA6MVwiXScpO1xuICAgIGlmICh0bXAubGVuZ3RoKSB7XG4gICAgICAgIGlmICh0bXAuYXR0cigndWZyYWcnKSkge1xuICAgICAgICAgICAgbWVkaWEgKz0gU0RQVXRpbC5idWlsZF9pY2V1ZnJhZyh0bXAuYXR0cigndWZyYWcnKSkgKyAnXFxyXFxuJztcbiAgICAgICAgfVxuICAgICAgICBpZiAodG1wLmF0dHIoJ3B3ZCcpKSB7XG4gICAgICAgICAgICBtZWRpYSArPSBTRFBVdGlsLmJ1aWxkX2ljZXB3ZCh0bXAuYXR0cigncHdkJykpICsgJ1xcclxcbic7XG4gICAgICAgIH1cbiAgICAgICAgdG1wLmZpbmQoJz5maW5nZXJwcmludCcpLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgLy8gRklYTUU6IGNoZWNrIG5hbWVzcGFjZSBhdCBzb21lIHBvaW50XG4gICAgICAgICAgICBtZWRpYSArPSAnYT1maW5nZXJwcmludDonICsgdGhpcy5nZXRBdHRyaWJ1dGUoJ2hhc2gnKTtcbiAgICAgICAgICAgIG1lZGlhICs9ICcgJyArICQodGhpcykudGV4dCgpO1xuICAgICAgICAgICAgbWVkaWEgKz0gJ1xcclxcbic7XG4gICAgICAgICAgICBpZiAodGhpcy5nZXRBdHRyaWJ1dGUoJ3NldHVwJykpIHtcbiAgICAgICAgICAgICAgICBtZWRpYSArPSAnYT1zZXR1cDonICsgdGhpcy5nZXRBdHRyaWJ1dGUoJ3NldHVwJykgKyAnXFxyXFxuJztcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIHN3aXRjaCAoY29udGVudC5hdHRyKCdzZW5kZXJzJykpIHtcbiAgICAgICAgY2FzZSAnaW5pdGlhdG9yJzpcbiAgICAgICAgICAgIG1lZGlhICs9ICdhPXNlbmRvbmx5XFxyXFxuJztcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICBjYXNlICdyZXNwb25kZXInOlxuICAgICAgICAgICAgbWVkaWEgKz0gJ2E9cmVjdm9ubHlcXHJcXG4nO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ25vbmUnOlxuICAgICAgICAgICAgbWVkaWEgKz0gJ2E9aW5hY3RpdmVcXHJcXG4nO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgIGNhc2UgJ2JvdGgnOlxuICAgICAgICAgICAgbWVkaWEgKz0gJ2E9c2VuZHJlY3ZcXHJcXG4nO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgfVxuICAgIG1lZGlhICs9ICdhPW1pZDonICsgY29udGVudC5hdHRyKCduYW1lJykgKyAnXFxyXFxuJztcblxuICAgIC8vIDxkZXNjcmlwdGlvbj48cnRjcC1tdXgvPjwvZGVzY3JpcHRpb24+XG4gICAgLy8gc2VlIGh0dHA6Ly9jb2RlLmdvb2dsZS5jb20vcC9saWJqaW5nbGUvaXNzdWVzL2RldGFpbD9pZD0zMDkgLS0gbm8gc3BlYyB0aG91Z2hcbiAgICAvLyBhbmQgaHR0cDovL21haWwuamFiYmVyLm9yZy9waXBlcm1haWwvamluZ2xlLzIwMTEtRGVjZW1iZXIvMDAxNzYxLmh0bWxcbiAgICBpZiAoZGVzYy5maW5kKCdydGNwLW11eCcpLmxlbmd0aCkge1xuICAgICAgICBtZWRpYSArPSAnYT1ydGNwLW11eFxcclxcbic7XG4gICAgfVxuXG4gICAgaWYgKGRlc2MuZmluZCgnZW5jcnlwdGlvbicpLmxlbmd0aCkge1xuICAgICAgICBkZXNjLmZpbmQoJ2VuY3J5cHRpb24+Y3J5cHRvJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBtZWRpYSArPSAnYT1jcnlwdG86JyArIHRoaXMuZ2V0QXR0cmlidXRlKCd0YWcnKTtcbiAgICAgICAgICAgIG1lZGlhICs9ICcgJyArIHRoaXMuZ2V0QXR0cmlidXRlKCdjcnlwdG8tc3VpdGUnKTtcbiAgICAgICAgICAgIG1lZGlhICs9ICcgJyArIHRoaXMuZ2V0QXR0cmlidXRlKCdrZXktcGFyYW1zJyk7XG4gICAgICAgICAgICBpZiAodGhpcy5nZXRBdHRyaWJ1dGUoJ3Nlc3Npb24tcGFyYW1zJykpIHtcbiAgICAgICAgICAgICAgICBtZWRpYSArPSAnICcgKyB0aGlzLmdldEF0dHJpYnV0ZSgnc2Vzc2lvbi1wYXJhbXMnKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG1lZGlhICs9ICdcXHJcXG4nO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgZGVzYy5maW5kKCdwYXlsb2FkLXR5cGUnKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgbWVkaWEgKz0gU0RQVXRpbC5idWlsZF9ydHBtYXAodGhpcykgKyAnXFxyXFxuJztcbiAgICAgICAgaWYgKCQodGhpcykuZmluZCgnPnBhcmFtZXRlcicpLmxlbmd0aCkge1xuICAgICAgICAgICAgbWVkaWEgKz0gJ2E9Zm10cDonICsgdGhpcy5nZXRBdHRyaWJ1dGUoJ2lkJykgKyAnICc7XG4gICAgICAgICAgICBtZWRpYSArPSAkKHRoaXMpLmZpbmQoJ3BhcmFtZXRlcicpLm1hcChmdW5jdGlvbiAoKSB7IHJldHVybiAodGhpcy5nZXRBdHRyaWJ1dGUoJ25hbWUnKSA/ICh0aGlzLmdldEF0dHJpYnV0ZSgnbmFtZScpICsgJz0nKSA6ICcnKSArIHRoaXMuZ2V0QXR0cmlidXRlKCd2YWx1ZScpOyB9KS5nZXQoKS5qb2luKCc7ICcpO1xuICAgICAgICAgICAgbWVkaWEgKz0gJ1xcclxcbic7XG4gICAgICAgIH1cbiAgICAgICAgLy8geGVwLTAyOTNcbiAgICAgICAgbWVkaWEgKz0gc2VsZi5SdGNwRmJGcm9tSmluZ2xlKCQodGhpcyksIHRoaXMuZ2V0QXR0cmlidXRlKCdpZCcpKTtcbiAgICB9KTtcblxuICAgIC8vIHhlcC0wMjkzXG4gICAgbWVkaWEgKz0gc2VsZi5SdGNwRmJGcm9tSmluZ2xlKGRlc2MsICcqJyk7XG5cbiAgICAvLyB4ZXAtMDI5NFxuICAgIHRtcCA9IGRlc2MuZmluZCgnPnJ0cC1oZHJleHRbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6cnRwLWhkcmV4dDowXCJdJyk7XG4gICAgdG1wLmVhY2goZnVuY3Rpb24gKCkge1xuICAgICAgICBtZWRpYSArPSAnYT1leHRtYXA6JyArIHRoaXMuZ2V0QXR0cmlidXRlKCdpZCcpICsgJyAnICsgdGhpcy5nZXRBdHRyaWJ1dGUoJ3VyaScpICsgJ1xcclxcbic7XG4gICAgfSk7XG5cbiAgICBjb250ZW50LmZpbmQoJz50cmFuc3BvcnRbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6dHJhbnNwb3J0czppY2UtdWRwOjFcIl0+Y2FuZGlkYXRlJykuZWFjaChmdW5jdGlvbiAoKSB7XG4gICAgICAgIG1lZGlhICs9IFNEUFV0aWwuY2FuZGlkYXRlRnJvbUppbmdsZSh0aGlzKTtcbiAgICB9KTtcblxuICAgIC8vIFhFUC0wMzM5IGhhbmRsZSBzc3JjLWdyb3VwIGF0dHJpYnV0ZXNcbiAgICB0bXAgPSBjb250ZW50LmZpbmQoJ2Rlc2NyaXB0aW9uPnNzcmMtZ3JvdXBbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6c3NtYTowXCJdJykuZWFjaChmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHNlbWFudGljcyA9IHRoaXMuZ2V0QXR0cmlidXRlKCdzZW1hbnRpY3MnKTtcbiAgICAgICAgdmFyIHNzcmNzID0gJCh0aGlzKS5maW5kKCc+c291cmNlJykubWFwKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMuZ2V0QXR0cmlidXRlKCdzc3JjJyk7XG4gICAgICAgIH0pLmdldCgpO1xuXG4gICAgICAgIGlmIChzc3Jjcy5sZW5ndGggIT0gMCkge1xuICAgICAgICAgICAgbWVkaWEgKz0gJ2E9c3NyYy1ncm91cDonICsgc2VtYW50aWNzICsgJyAnICsgc3NyY3Muam9pbignICcpICsgJ1xcclxcbic7XG4gICAgICAgIH1cbiAgICB9KTtcblxuICAgIHRtcCA9IGNvbnRlbnQuZmluZCgnZGVzY3JpcHRpb24+c291cmNlW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnNzbWE6MFwiXScpO1xuICAgIHRtcC5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIHNzcmMgPSB0aGlzLmdldEF0dHJpYnV0ZSgnc3NyYycpO1xuICAgICAgICAkKHRoaXMpLmZpbmQoJz5wYXJhbWV0ZXInKS5lYWNoKGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIG1lZGlhICs9ICdhPXNzcmM6JyArIHNzcmMgKyAnICcgKyB0aGlzLmdldEF0dHJpYnV0ZSgnbmFtZScpO1xuICAgICAgICAgICAgaWYgKHRoaXMuZ2V0QXR0cmlidXRlKCd2YWx1ZScpICYmIHRoaXMuZ2V0QXR0cmlidXRlKCd2YWx1ZScpLmxlbmd0aClcbiAgICAgICAgICAgICAgICBtZWRpYSArPSAnOicgKyB0aGlzLmdldEF0dHJpYnV0ZSgndmFsdWUnKTtcbiAgICAgICAgICAgIG1lZGlhICs9ICdcXHJcXG4nO1xuICAgICAgICB9KTtcbiAgICB9KTtcblxuICAgIHJldHVybiBtZWRpYTtcbn07XG5cblxubW9kdWxlLmV4cG9ydHMgPSBTRFA7XG5cbiIsImZ1bmN0aW9uIFNEUERpZmZlcihteVNEUCwgb3RoZXJTRFApIHtcbiAgICB0aGlzLm15U0RQID0gbXlTRFA7XG4gICAgdGhpcy5vdGhlclNEUCA9IG90aGVyU0RQO1xufVxuXG4vKipcbiAqIFJldHVybnMgbWFwIG9mIE1lZGlhQ2hhbm5lbCB0aGF0IGNvbnRhaW5zIG9ubHkgbWVkaWEgbm90IGNvbnRhaW5lZCBpbiA8dHQ+b3RoZXJTZHA8L3R0Pi4gTWFwcGVkIGJ5IGNoYW5uZWwgaWR4LlxuICogQHBhcmFtIG90aGVyU2RwIHRoZSBvdGhlciBTRFAgdG8gY2hlY2sgc3NyYyB3aXRoLlxuICovXG5TRFBEaWZmZXIucHJvdG90eXBlLmdldE5ld01lZGlhID0gZnVuY3Rpb24oKSB7XG5cbiAgICAvLyB0aGlzIGNvdWxkIGJlIHVzZWZ1bCBpbiBBcnJheS5wcm90b3R5cGUuXG4gICAgZnVuY3Rpb24gYXJyYXlFcXVhbHMoYXJyYXkpIHtcbiAgICAgICAgLy8gaWYgdGhlIG90aGVyIGFycmF5IGlzIGEgZmFsc3kgdmFsdWUsIHJldHVyblxuICAgICAgICBpZiAoIWFycmF5KVxuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuXG4gICAgICAgIC8vIGNvbXBhcmUgbGVuZ3RocyAtIGNhbiBzYXZlIGEgbG90IG9mIHRpbWVcbiAgICAgICAgaWYgKHRoaXMubGVuZ3RoICE9IGFycmF5Lmxlbmd0aClcbiAgICAgICAgICAgIHJldHVybiBmYWxzZTtcblxuICAgICAgICBmb3IgKHZhciBpID0gMCwgbD10aGlzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgLy8gQ2hlY2sgaWYgd2UgaGF2ZSBuZXN0ZWQgYXJyYXlzXG4gICAgICAgICAgICBpZiAodGhpc1tpXSBpbnN0YW5jZW9mIEFycmF5ICYmIGFycmF5W2ldIGluc3RhbmNlb2YgQXJyYXkpIHtcbiAgICAgICAgICAgICAgICAvLyByZWN1cnNlIGludG8gdGhlIG5lc3RlZCBhcnJheXNcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXNbaV0uZXF1YWxzKGFycmF5W2ldKSlcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBpZiAodGhpc1tpXSAhPSBhcnJheVtpXSkge1xuICAgICAgICAgICAgICAgIC8vIFdhcm5pbmcgLSB0d28gZGlmZmVyZW50IG9iamVjdCBpbnN0YW5jZXMgd2lsbCBuZXZlciBiZSBlcXVhbDoge3g6MjB9ICE9IHt4OjIwfVxuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICB9XG5cbiAgICB2YXIgbXlNZWRpYXMgPSB0aGlzLm15U0RQLmdldE1lZGlhU3NyY01hcCgpO1xuICAgIHZhciBvdGhlcnNNZWRpYXMgPSB0aGlzLm90aGVyU0RQLmdldE1lZGlhU3NyY01hcCgpO1xuICAgIHZhciBuZXdNZWRpYSA9IHt9O1xuICAgIE9iamVjdC5rZXlzKG90aGVyc01lZGlhcykuZm9yRWFjaChmdW5jdGlvbihvdGhlcnNNZWRpYUlkeCkge1xuICAgICAgICB2YXIgbXlNZWRpYSA9IG15TWVkaWFzW290aGVyc01lZGlhSWR4XTtcbiAgICAgICAgdmFyIG90aGVyc01lZGlhID0gb3RoZXJzTWVkaWFzW290aGVyc01lZGlhSWR4XTtcbiAgICAgICAgaWYoIW15TWVkaWEgJiYgb3RoZXJzTWVkaWEpIHtcbiAgICAgICAgICAgIC8vIEFkZCB3aG9sZSBjaGFubmVsXG4gICAgICAgICAgICBuZXdNZWRpYVtvdGhlcnNNZWRpYUlkeF0gPSBvdGhlcnNNZWRpYTtcbiAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgfVxuICAgICAgICAvLyBMb29rIGZvciBuZXcgc3NyY3MgYWNjcm9zcyB0aGUgY2hhbm5lbFxuICAgICAgICBPYmplY3Qua2V5cyhvdGhlcnNNZWRpYS5zc3JjcykuZm9yRWFjaChmdW5jdGlvbihzc3JjKSB7XG4gICAgICAgICAgICBpZihPYmplY3Qua2V5cyhteU1lZGlhLnNzcmNzKS5pbmRleE9mKHNzcmMpID09PSAtMSkge1xuICAgICAgICAgICAgICAgIC8vIEFsbG9jYXRlIGNoYW5uZWwgaWYgd2UndmUgZm91bmQgc3NyYyB0aGF0IGRvZXNuJ3QgZXhpc3QgaW4gb3VyIGNoYW5uZWxcbiAgICAgICAgICAgICAgICBpZighbmV3TWVkaWFbb3RoZXJzTWVkaWFJZHhdKXtcbiAgICAgICAgICAgICAgICAgICAgbmV3TWVkaWFbb3RoZXJzTWVkaWFJZHhdID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgbWVkaWFpbmRleDogb3RoZXJzTWVkaWEubWVkaWFpbmRleCxcbiAgICAgICAgICAgICAgICAgICAgICAgIG1pZDogb3RoZXJzTWVkaWEubWlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3NyY3M6IHt9LFxuICAgICAgICAgICAgICAgICAgICAgICAgc3NyY0dyb3VwczogW11cbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbmV3TWVkaWFbb3RoZXJzTWVkaWFJZHhdLnNzcmNzW3NzcmNdID0gb3RoZXJzTWVkaWEuc3NyY3Nbc3NyY107XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIC8vIExvb2sgZm9yIG5ldyBzc3JjIGdyb3VwcyBhY3Jvc3MgdGhlIGNoYW5uZWxzXG4gICAgICAgIG90aGVyc01lZGlhLnNzcmNHcm91cHMuZm9yRWFjaChmdW5jdGlvbihvdGhlclNzcmNHcm91cCl7XG5cbiAgICAgICAgICAgIC8vIHRyeSB0byBtYXRjaCB0aGUgb3RoZXIgc3NyYy1ncm91cCB3aXRoIGFuIHNzcmMtZ3JvdXAgb2Ygb3Vyc1xuICAgICAgICAgICAgdmFyIG1hdGNoZWQgPSBmYWxzZTtcbiAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbXlNZWRpYS5zc3JjR3JvdXBzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgdmFyIG15U3NyY0dyb3VwID0gbXlNZWRpYS5zc3JjR3JvdXBzW2ldO1xuICAgICAgICAgICAgICAgIGlmIChvdGhlclNzcmNHcm91cC5zZW1hbnRpY3MgPT0gbXlTc3JjR3JvdXAuc2VtYW50aWNzXG4gICAgICAgICAgICAgICAgICAgICYmIGFycmF5RXF1YWxzLmFwcGx5KG90aGVyU3NyY0dyb3VwLnNzcmNzLCBbbXlTc3JjR3JvdXAuc3NyY3NdKSkge1xuXG4gICAgICAgICAgICAgICAgICAgIG1hdGNoZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICghbWF0Y2hlZCkge1xuICAgICAgICAgICAgICAgIC8vIEFsbG9jYXRlIGNoYW5uZWwgaWYgd2UndmUgZm91bmQgYW4gc3NyYy1ncm91cCB0aGF0IGRvZXNuJ3RcbiAgICAgICAgICAgICAgICAvLyBleGlzdCBpbiBvdXIgY2hhbm5lbFxuXG4gICAgICAgICAgICAgICAgaWYoIW5ld01lZGlhW290aGVyc01lZGlhSWR4XSl7XG4gICAgICAgICAgICAgICAgICAgIG5ld01lZGlhW290aGVyc01lZGlhSWR4XSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG1lZGlhaW5kZXg6IG90aGVyc01lZGlhLm1lZGlhaW5kZXgsXG4gICAgICAgICAgICAgICAgICAgICAgICBtaWQ6IG90aGVyc01lZGlhLm1pZCxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNzcmNzOiB7fSxcbiAgICAgICAgICAgICAgICAgICAgICAgIHNzcmNHcm91cHM6IFtdXG4gICAgICAgICAgICAgICAgICAgIH07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIG5ld01lZGlhW290aGVyc01lZGlhSWR4XS5zc3JjR3JvdXBzLnB1c2gob3RoZXJTc3JjR3JvdXApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9KTtcbiAgICB9KTtcbiAgICByZXR1cm4gbmV3TWVkaWE7XG59O1xuXG4vKipcbiAqIFNlbmRzIFNTUkMgdXBkYXRlIElRLlxuICogQHBhcmFtIHNkcE1lZGlhU3NyY3MgU1NSQ3MgbWFwIG9idGFpbmVkIGZyb20gU0RQLmdldE5ld01lZGlhLiBDbnRhaW5zIFNTUkNzIHRvIGFkZC9yZW1vdmUuXG4gKiBAcGFyYW0gc2lkIHNlc3Npb24gaWRlbnRpZmllciB0aGF0IHdpbGwgYmUgcHV0IGludG8gdGhlIElRLlxuICogQHBhcmFtIGluaXRpYXRvciBpbml0aWF0b3IgaWRlbnRpZmllci5cbiAqIEBwYXJhbSB0b0ppZCBkZXN0aW5hdGlvbiBKaWRcbiAqIEBwYXJhbSBpc0FkZCBpbmRpY2F0ZXMgaWYgdGhpcyBpcyByZW1vdmUgb3IgYWRkIG9wZXJhdGlvbi5cbiAqL1xuU0RQRGlmZmVyLnByb3RvdHlwZS50b0ppbmdsZSA9IGZ1bmN0aW9uKG1vZGlmeSkge1xuICAgIHZhciBzZHBNZWRpYVNzcmNzID0gdGhpcy5nZXROZXdNZWRpYSgpO1xuICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgIC8vIEZJWE1FOiBvbmx5IGFubm91bmNlIHZpZGVvIHNzcmNzIHNpbmNlIHdlIG1peCBhdWRpbyBhbmQgZG9udCBuZWVkXG4gICAgLy8gICAgICB0aGUgYXVkaW8gc3NyY3MgdGhlcmVmb3JlXG4gICAgdmFyIG1vZGlmaWVkID0gZmFsc2U7XG4gICAgT2JqZWN0LmtleXMoc2RwTWVkaWFTc3JjcykuZm9yRWFjaChmdW5jdGlvbihtZWRpYWluZGV4KXtcbiAgICAgICAgbW9kaWZpZWQgPSB0cnVlO1xuICAgICAgICB2YXIgbWVkaWEgPSBzZHBNZWRpYVNzcmNzW21lZGlhaW5kZXhdO1xuICAgICAgICBtb2RpZnkuYygnY29udGVudCcsIHtuYW1lOiBtZWRpYS5taWR9KTtcblxuICAgICAgICBtb2RpZnkuYygnZGVzY3JpcHRpb24nLCB7eG1sbnM6J3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDoxJywgbWVkaWE6IG1lZGlhLm1pZH0pO1xuICAgICAgICAvLyBGSVhNRTogbm90IGNvbXBsZXRseSBzdXJlIHRoaXMgb3BlcmF0ZXMgb24gYmxvY2tzIGFuZCAvIG9yIGhhbmRsZXMgZGlmZmVyZW50IHNzcmNzIGNvcnJlY3RseVxuICAgICAgICAvLyBnZW5lcmF0ZSBzb3VyY2VzIGZyb20gbGluZXNcbiAgICAgICAgT2JqZWN0LmtleXMobWVkaWEuc3NyY3MpLmZvckVhY2goZnVuY3Rpb24oc3NyY051bSkge1xuICAgICAgICAgICAgdmFyIG1lZGlhU3NyYyA9IG1lZGlhLnNzcmNzW3NzcmNOdW1dO1xuICAgICAgICAgICAgbW9kaWZ5LmMoJ3NvdXJjZScsIHsgeG1sbnM6ICd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6c3NtYTowJyB9KTtcbiAgICAgICAgICAgIG1vZGlmeS5hdHRycyh7c3NyYzogbWVkaWFTc3JjLnNzcmN9KTtcbiAgICAgICAgICAgIC8vIGl0ZXJhdGUgb3ZlciBzc3JjIGxpbmVzXG4gICAgICAgICAgICBtZWRpYVNzcmMubGluZXMuZm9yRWFjaChmdW5jdGlvbiAobGluZSkge1xuICAgICAgICAgICAgICAgIHZhciBpZHggPSBsaW5lLmluZGV4T2YoJyAnKTtcbiAgICAgICAgICAgICAgICB2YXIga3YgPSBsaW5lLnN1YnN0cihpZHggKyAxKTtcbiAgICAgICAgICAgICAgICBtb2RpZnkuYygncGFyYW1ldGVyJyk7XG4gICAgICAgICAgICAgICAgaWYgKGt2LmluZGV4T2YoJzonKSA9PSAtMSkge1xuICAgICAgICAgICAgICAgICAgICBtb2RpZnkuYXR0cnMoeyBuYW1lOiBrdiB9KTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBtb2RpZnkuYXR0cnMoeyBuYW1lOiBrdi5zcGxpdCgnOicsIDIpWzBdIH0pO1xuICAgICAgICAgICAgICAgICAgICBtb2RpZnkuYXR0cnMoeyB2YWx1ZToga3Yuc3BsaXQoJzonLCAyKVsxXSB9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgbW9kaWZ5LnVwKCk7IC8vIGVuZCBvZiBwYXJhbWV0ZXJcbiAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgbW9kaWZ5LnVwKCk7IC8vIGVuZCBvZiBzb3VyY2VcbiAgICAgICAgfSk7XG5cbiAgICAgICAgLy8gZ2VuZXJhdGUgc291cmNlIGdyb3VwcyBmcm9tIGxpbmVzXG4gICAgICAgIG1lZGlhLnNzcmNHcm91cHMuZm9yRWFjaChmdW5jdGlvbihzc3JjR3JvdXApIHtcbiAgICAgICAgICAgIGlmIChzc3JjR3JvdXAuc3NyY3MubGVuZ3RoICE9IDApIHtcblxuICAgICAgICAgICAgICAgIG1vZGlmeS5jKCdzc3JjLWdyb3VwJywge1xuICAgICAgICAgICAgICAgICAgICBzZW1hbnRpY3M6IHNzcmNHcm91cC5zZW1hbnRpY3MsXG4gICAgICAgICAgICAgICAgICAgIHhtbG5zOiAndXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnNzbWE6MCdcbiAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIHNzcmNHcm91cC5zc3Jjcy5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgICAgICAgICAgIG1vZGlmeS5jKCdzb3VyY2UnLCB7IHNzcmM6IHNzcmMgfSlcbiAgICAgICAgICAgICAgICAgICAgICAgIC51cCgpOyAvLyBlbmQgb2Ygc291cmNlXG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgbW9kaWZ5LnVwKCk7IC8vIGVuZCBvZiBzc3JjLWdyb3VwXG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuXG4gICAgICAgIG1vZGlmeS51cCgpOyAvLyBlbmQgb2YgZGVzY3JpcHRpb25cbiAgICAgICAgbW9kaWZ5LnVwKCk7IC8vIGVuZCBvZiBjb250ZW50XG4gICAgfSk7XG5cbiAgICByZXR1cm4gbW9kaWZpZWQ7XG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFNEUERpZmZlcjsiLCJTRFBVdGlsID0ge1xuICAgIGljZXBhcmFtczogZnVuY3Rpb24gKG1lZGlhZGVzYywgc2Vzc2lvbmRlc2MpIHtcbiAgICAgICAgdmFyIGRhdGEgPSBudWxsO1xuICAgICAgICBpZiAoU0RQVXRpbC5maW5kX2xpbmUobWVkaWFkZXNjLCAnYT1pY2UtdWZyYWc6Jywgc2Vzc2lvbmRlc2MpICYmXG4gICAgICAgICAgICBTRFBVdGlsLmZpbmRfbGluZShtZWRpYWRlc2MsICdhPWljZS1wd2Q6Jywgc2Vzc2lvbmRlc2MpKSB7XG4gICAgICAgICAgICBkYXRhID0ge1xuICAgICAgICAgICAgICAgIHVmcmFnOiBTRFBVdGlsLnBhcnNlX2ljZXVmcmFnKFNEUFV0aWwuZmluZF9saW5lKG1lZGlhZGVzYywgJ2E9aWNlLXVmcmFnOicsIHNlc3Npb25kZXNjKSksXG4gICAgICAgICAgICAgICAgcHdkOiBTRFBVdGlsLnBhcnNlX2ljZXB3ZChTRFBVdGlsLmZpbmRfbGluZShtZWRpYWRlc2MsICdhPWljZS1wd2Q6Jywgc2Vzc2lvbmRlc2MpKVxuICAgICAgICAgICAgfTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9LFxuICAgIHBhcnNlX2ljZXVmcmFnOiBmdW5jdGlvbiAobGluZSkge1xuICAgICAgICByZXR1cm4gbGluZS5zdWJzdHJpbmcoMTIpO1xuICAgIH0sXG4gICAgYnVpbGRfaWNldWZyYWc6IGZ1bmN0aW9uIChmcmFnKSB7XG4gICAgICAgIHJldHVybiAnYT1pY2UtdWZyYWc6JyArIGZyYWc7XG4gICAgfSxcbiAgICBwYXJzZV9pY2Vwd2Q6IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHJldHVybiBsaW5lLnN1YnN0cmluZygxMCk7XG4gICAgfSxcbiAgICBidWlsZF9pY2Vwd2Q6IGZ1bmN0aW9uIChwd2QpIHtcbiAgICAgICAgcmV0dXJuICdhPWljZS1wd2Q6JyArIHB3ZDtcbiAgICB9LFxuICAgIHBhcnNlX21pZDogZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgcmV0dXJuIGxpbmUuc3Vic3RyaW5nKDYpO1xuICAgIH0sXG4gICAgcGFyc2VfbWxpbmU6IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHZhciBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDIpLnNwbGl0KCcgJyksXG4gICAgICAgICAgICBkYXRhID0ge307XG4gICAgICAgIGRhdGEubWVkaWEgPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBkYXRhLnBvcnQgPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBkYXRhLnByb3RvID0gcGFydHMuc2hpZnQoKTtcbiAgICAgICAgaWYgKHBhcnRzW3BhcnRzLmxlbmd0aCAtIDFdID09PSAnJykgeyAvLyB0cmFpbGluZyB3aGl0ZXNwYWNlXG4gICAgICAgICAgICBwYXJ0cy5wb3AoKTtcbiAgICAgICAgfVxuICAgICAgICBkYXRhLmZtdCA9IHBhcnRzO1xuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9LFxuICAgIGJ1aWxkX21saW5lOiBmdW5jdGlvbiAobWxpbmUpIHtcbiAgICAgICAgcmV0dXJuICdtPScgKyBtbGluZS5tZWRpYSArICcgJyArIG1saW5lLnBvcnQgKyAnICcgKyBtbGluZS5wcm90byArICcgJyArIG1saW5lLmZtdC5qb2luKCcgJyk7XG4gICAgfSxcbiAgICBwYXJzZV9ydHBtYXA6IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHZhciBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDkpLnNwbGl0KCcgJyksXG4gICAgICAgICAgICBkYXRhID0ge307XG4gICAgICAgIGRhdGEuaWQgPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBwYXJ0cyA9IHBhcnRzWzBdLnNwbGl0KCcvJyk7XG4gICAgICAgIGRhdGEubmFtZSA9IHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIGRhdGEuY2xvY2tyYXRlID0gcGFydHMuc2hpZnQoKTtcbiAgICAgICAgZGF0YS5jaGFubmVscyA9IHBhcnRzLmxlbmd0aCA/IHBhcnRzLnNoaWZ0KCkgOiAnMSc7XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH0sXG4gICAgLyoqXG4gICAgICogUGFyc2VzIFNEUCBsaW5lIFwiYT1zY3RwbWFwOi4uLlwiIGFuZCBleHRyYWN0cyBTQ1RQIHBvcnQgZnJvbSBpdC5cbiAgICAgKiBAcGFyYW0gbGluZSBlZy4gXCJhPXNjdHBtYXA6NTAwMCB3ZWJydGMtZGF0YWNoYW5uZWxcIlxuICAgICAqIEByZXR1cm5zIFtTQ1RQIHBvcnQgbnVtYmVyLCBwcm90b2NvbCwgc3RyZWFtc11cbiAgICAgKi9cbiAgICBwYXJzZV9zY3RwbWFwOiBmdW5jdGlvbiAobGluZSlcbiAgICB7XG4gICAgICAgIHZhciBwYXJ0cyA9IGxpbmUuc3Vic3RyaW5nKDEwKS5zcGxpdCgnICcpO1xuICAgICAgICB2YXIgc2N0cFBvcnQgPSBwYXJ0c1swXTtcbiAgICAgICAgdmFyIHByb3RvY29sID0gcGFydHNbMV07XG4gICAgICAgIC8vIFN0cmVhbSBjb3VudCBpcyBvcHRpb25hbFxuICAgICAgICB2YXIgc3RyZWFtQ291bnQgPSBwYXJ0cy5sZW5ndGggPiAyID8gcGFydHNbMl0gOiBudWxsO1xuICAgICAgICByZXR1cm4gW3NjdHBQb3J0LCBwcm90b2NvbCwgc3RyZWFtQ291bnRdOy8vIFNDVFAgcG9ydFxuICAgIH0sXG4gICAgYnVpbGRfcnRwbWFwOiBmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgdmFyIGxpbmUgPSAnYT1ydHBtYXA6JyArIGVsLmdldEF0dHJpYnV0ZSgnaWQnKSArICcgJyArIGVsLmdldEF0dHJpYnV0ZSgnbmFtZScpICsgJy8nICsgZWwuZ2V0QXR0cmlidXRlKCdjbG9ja3JhdGUnKTtcbiAgICAgICAgaWYgKGVsLmdldEF0dHJpYnV0ZSgnY2hhbm5lbHMnKSAmJiBlbC5nZXRBdHRyaWJ1dGUoJ2NoYW5uZWxzJykgIT0gJzEnKSB7XG4gICAgICAgICAgICBsaW5lICs9ICcvJyArIGVsLmdldEF0dHJpYnV0ZSgnY2hhbm5lbHMnKTtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gbGluZTtcbiAgICB9LFxuICAgIHBhcnNlX2NyeXB0bzogZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIHBhcnRzID0gbGluZS5zdWJzdHJpbmcoOSkuc3BsaXQoJyAnKSxcbiAgICAgICAgICAgIGRhdGEgPSB7fTtcbiAgICAgICAgZGF0YS50YWcgPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBkYXRhWydjcnlwdG8tc3VpdGUnXSA9IHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIGRhdGFbJ2tleS1wYXJhbXMnXSA9IHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIGlmIChwYXJ0cy5sZW5ndGgpIHtcbiAgICAgICAgICAgIGRhdGFbJ3Nlc3Npb24tcGFyYW1zJ10gPSBwYXJ0cy5qb2luKCcgJyk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSxcbiAgICBwYXJzZV9maW5nZXJwcmludDogZnVuY3Rpb24gKGxpbmUpIHsgLy8gUkZDIDQ1NzJcbiAgICAgICAgdmFyIHBhcnRzID0gbGluZS5zdWJzdHJpbmcoMTQpLnNwbGl0KCcgJyksXG4gICAgICAgICAgICBkYXRhID0ge307XG4gICAgICAgIGRhdGEuaGFzaCA9IHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIGRhdGEuZmluZ2VycHJpbnQgPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICAvLyBUT0RPIGFzc2VydCB0aGF0IGZpbmdlcnByaW50IHNhdGlzZmllcyAyVUhFWCAqKFwiOlwiIDJVSEVYKSA/XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH0sXG4gICAgcGFyc2VfZm10cDogZnVuY3Rpb24gKGxpbmUpIHtcbiAgICAgICAgdmFyIHBhcnRzID0gbGluZS5zcGxpdCgnICcpLFxuICAgICAgICAgICAgaSwga2V5LCB2YWx1ZSxcbiAgICAgICAgICAgIGRhdGEgPSBbXTtcbiAgICAgICAgcGFydHMuc2hpZnQoKTtcbiAgICAgICAgcGFydHMgPSBwYXJ0cy5qb2luKCcgJykuc3BsaXQoJzsnKTtcbiAgICAgICAgZm9yIChpID0gMDsgaSA8IHBhcnRzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICBrZXkgPSBwYXJ0c1tpXS5zcGxpdCgnPScpWzBdO1xuICAgICAgICAgICAgd2hpbGUgKGtleS5sZW5ndGggJiYga2V5WzBdID09ICcgJykge1xuICAgICAgICAgICAgICAgIGtleSA9IGtleS5zdWJzdHJpbmcoMSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB2YWx1ZSA9IHBhcnRzW2ldLnNwbGl0KCc9JylbMV07XG4gICAgICAgICAgICBpZiAoa2V5ICYmIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgZGF0YS5wdXNoKHtuYW1lOiBrZXksIHZhbHVlOiB2YWx1ZX0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChrZXkpIHtcbiAgICAgICAgICAgICAgICAvLyByZmMgNDczMyAoRFRNRikgc3R5bGUgc3R1ZmZcbiAgICAgICAgICAgICAgICBkYXRhLnB1c2goe25hbWU6ICcnLCB2YWx1ZToga2V5fSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgfSxcbiAgICBwYXJzZV9pY2VjYW5kaWRhdGU6IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIHZhciBjYW5kaWRhdGUgPSB7fSxcbiAgICAgICAgICAgIGVsZW1zID0gbGluZS5zcGxpdCgnICcpO1xuICAgICAgICBjYW5kaWRhdGUuZm91bmRhdGlvbiA9IGVsZW1zWzBdLnN1YnN0cmluZygxMik7XG4gICAgICAgIGNhbmRpZGF0ZS5jb21wb25lbnQgPSBlbGVtc1sxXTtcbiAgICAgICAgY2FuZGlkYXRlLnByb3RvY29sID0gZWxlbXNbMl0udG9Mb3dlckNhc2UoKTtcbiAgICAgICAgY2FuZGlkYXRlLnByaW9yaXR5ID0gZWxlbXNbM107XG4gICAgICAgIGNhbmRpZGF0ZS5pcCA9IGVsZW1zWzRdO1xuICAgICAgICBjYW5kaWRhdGUucG9ydCA9IGVsZW1zWzVdO1xuICAgICAgICAvLyBlbGVtc1s2XSA9PiBcInR5cFwiXG4gICAgICAgIGNhbmRpZGF0ZS50eXBlID0gZWxlbXNbN107XG4gICAgICAgIGNhbmRpZGF0ZS5nZW5lcmF0aW9uID0gMDsgLy8gZGVmYXVsdCB2YWx1ZSwgbWF5IGJlIG92ZXJ3cml0dGVuIGJlbG93XG4gICAgICAgIGZvciAodmFyIGkgPSA4OyBpIDwgZWxlbXMubGVuZ3RoOyBpICs9IDIpIHtcbiAgICAgICAgICAgIHN3aXRjaCAoZWxlbXNbaV0pIHtcbiAgICAgICAgICAgICAgICBjYXNlICdyYWRkcic6XG4gICAgICAgICAgICAgICAgICAgIGNhbmRpZGF0ZVsncmVsLWFkZHInXSA9IGVsZW1zW2kgKyAxXTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAncnBvcnQnOlxuICAgICAgICAgICAgICAgICAgICBjYW5kaWRhdGVbJ3JlbC1wb3J0J10gPSBlbGVtc1tpICsgMV07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ2dlbmVyYXRpb24nOlxuICAgICAgICAgICAgICAgICAgICBjYW5kaWRhdGUuZ2VuZXJhdGlvbiA9IGVsZW1zW2kgKyAxXTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAndGNwdHlwZSc6XG4gICAgICAgICAgICAgICAgICAgIGNhbmRpZGF0ZS50Y3B0eXBlID0gZWxlbXNbaSArIDFdO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBkZWZhdWx0OiAvLyBUT0RPXG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdwYXJzZV9pY2VjYW5kaWRhdGUgbm90IHRyYW5zbGF0aW5nIFwiJyArIGVsZW1zW2ldICsgJ1wiID0gXCInICsgZWxlbXNbaSArIDFdICsgJ1wiJyk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgY2FuZGlkYXRlLm5ldHdvcmsgPSAnMSc7XG4gICAgICAgIGNhbmRpZGF0ZS5pZCA9IE1hdGgucmFuZG9tKCkudG9TdHJpbmcoMzYpLnN1YnN0cigyLCAxMCk7IC8vIG5vdCBhcHBsaWNhYmxlIHRvIFNEUCAtLSBGSVhNRTogc2hvdWxkIGJlIHVuaXF1ZSwgbm90IGp1c3QgcmFuZG9tXG4gICAgICAgIHJldHVybiBjYW5kaWRhdGU7XG4gICAgfSxcbiAgICBidWlsZF9pY2VjYW5kaWRhdGU6IGZ1bmN0aW9uIChjYW5kKSB7XG4gICAgICAgIHZhciBsaW5lID0gWydhPWNhbmRpZGF0ZTonICsgY2FuZC5mb3VuZGF0aW9uLCBjYW5kLmNvbXBvbmVudCwgY2FuZC5wcm90b2NvbCwgY2FuZC5wcmlvcml0eSwgY2FuZC5pcCwgY2FuZC5wb3J0LCAndHlwJywgY2FuZC50eXBlXS5qb2luKCcgJyk7XG4gICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICBzd2l0Y2ggKGNhbmQudHlwZSkge1xuICAgICAgICAgICAgY2FzZSAnc3JmbHgnOlxuICAgICAgICAgICAgY2FzZSAncHJmbHgnOlxuICAgICAgICAgICAgY2FzZSAncmVsYXknOlxuICAgICAgICAgICAgICAgIGlmIChjYW5kLmhhc093bkF0dHJpYnV0ZSgncmVsLWFkZHInKSAmJiBjYW5kLmhhc093bkF0dHJpYnV0ZSgncmVsLXBvcnQnKSkge1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICdyYWRkcic7XG4gICAgICAgICAgICAgICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9IGNhbmRbJ3JlbC1hZGRyJ107XG4gICAgICAgICAgICAgICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICdycG9ydCc7XG4gICAgICAgICAgICAgICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9IGNhbmRbJ3JlbC1wb3J0J107XG4gICAgICAgICAgICAgICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICBpZiAoY2FuZC5oYXNPd25BdHRyaWJ1dGUoJ3RjcHR5cGUnKSkge1xuICAgICAgICAgICAgbGluZSArPSAndGNwdHlwZSc7XG4gICAgICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgICAgIGxpbmUgKz0gY2FuZC50Y3B0eXBlO1xuICAgICAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgIH1cbiAgICAgICAgbGluZSArPSAnZ2VuZXJhdGlvbic7XG4gICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICBsaW5lICs9IGNhbmQuaGFzT3duQXR0cmlidXRlKCdnZW5lcmF0aW9uJykgPyBjYW5kLmdlbmVyYXRpb24gOiAnMCc7XG4gICAgICAgIHJldHVybiBsaW5lO1xuICAgIH0sXG4gICAgcGFyc2Vfc3NyYzogZnVuY3Rpb24gKGRlc2MpIHtcbiAgICAgICAgLy8gcHJvcHJpZXRhcnkgbWFwcGluZyBvZiBhPXNzcmMgbGluZXNcbiAgICAgICAgLy8gVE9ETzogc2VlIFwiSmluZ2xlIFJUUCBTb3VyY2UgRGVzY3JpcHRpb25cIiBieSBKdWJlcnRpIGFuZCBQLiBUaGF0Y2hlciBvbiBnb29nbGUgZG9jc1xuICAgICAgICAvLyBhbmQgcGFyc2UgYWNjb3JkaW5nIHRvIHRoYXRcbiAgICAgICAgdmFyIGxpbmVzID0gZGVzYy5zcGxpdCgnXFxyXFxuJyksXG4gICAgICAgICAgICBkYXRhID0ge307XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChsaW5lc1tpXS5zdWJzdHJpbmcoMCwgNykgPT0gJ2E9c3NyYzonKSB7XG4gICAgICAgICAgICAgICAgdmFyIGlkeCA9IGxpbmVzW2ldLmluZGV4T2YoJyAnKTtcbiAgICAgICAgICAgICAgICBkYXRhW2xpbmVzW2ldLnN1YnN0cihpZHggKyAxKS5zcGxpdCgnOicsIDIpWzBdXSA9IGxpbmVzW2ldLnN1YnN0cihpZHggKyAxKS5zcGxpdCgnOicsIDIpWzFdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH0sXG4gICAgcGFyc2VfcnRjcGZiOiBmdW5jdGlvbiAobGluZSkge1xuICAgICAgICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cigxMCkuc3BsaXQoJyAnKTtcbiAgICAgICAgdmFyIGRhdGEgPSB7fTtcbiAgICAgICAgZGF0YS5wdCA9IHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIGRhdGEudHlwZSA9IHBhcnRzLnNoaWZ0KCk7XG4gICAgICAgIGRhdGEucGFyYW1zID0gcGFydHM7XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH0sXG4gICAgcGFyc2VfZXh0bWFwOiBmdW5jdGlvbiAobGluZSkge1xuICAgICAgICB2YXIgcGFydHMgPSBsaW5lLnN1YnN0cig5KS5zcGxpdCgnICcpO1xuICAgICAgICB2YXIgZGF0YSA9IHt9O1xuICAgICAgICBkYXRhLnZhbHVlID0gcGFydHMuc2hpZnQoKTtcbiAgICAgICAgaWYgKGRhdGEudmFsdWUuaW5kZXhPZignLycpICE9IC0xKSB7XG4gICAgICAgICAgICBkYXRhLmRpcmVjdGlvbiA9IGRhdGEudmFsdWUuc3Vic3RyKGRhdGEudmFsdWUuaW5kZXhPZignLycpICsgMSk7XG4gICAgICAgICAgICBkYXRhLnZhbHVlID0gZGF0YS52YWx1ZS5zdWJzdHIoMCwgZGF0YS52YWx1ZS5pbmRleE9mKCcvJykpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgZGF0YS5kaXJlY3Rpb24gPSAnYm90aCc7XG4gICAgICAgIH1cbiAgICAgICAgZGF0YS51cmkgPSBwYXJ0cy5zaGlmdCgpO1xuICAgICAgICBkYXRhLnBhcmFtcyA9IHBhcnRzO1xuICAgICAgICByZXR1cm4gZGF0YTtcbiAgICB9LFxuICAgIGZpbmRfbGluZTogZnVuY3Rpb24gKGhheXN0YWNrLCBuZWVkbGUsIHNlc3Npb25wYXJ0KSB7XG4gICAgICAgIHZhciBsaW5lcyA9IGhheXN0YWNrLnNwbGl0KCdcXHJcXG4nKTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBsaW5lcy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgaWYgKGxpbmVzW2ldLnN1YnN0cmluZygwLCBuZWVkbGUubGVuZ3RoKSA9PSBuZWVkbGUpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gbGluZXNbaV07XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgaWYgKCFzZXNzaW9ucGFydCkge1xuICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICB9XG4gICAgICAgIC8vIHNlYXJjaCBzZXNzaW9uIHBhcnRcbiAgICAgICAgbGluZXMgPSBzZXNzaW9ucGFydC5zcGxpdCgnXFxyXFxuJyk7XG4gICAgICAgIGZvciAodmFyIGogPSAwOyBqIDwgbGluZXMubGVuZ3RoOyBqKyspIHtcbiAgICAgICAgICAgIGlmIChsaW5lc1tqXS5zdWJzdHJpbmcoMCwgbmVlZGxlLmxlbmd0aCkgPT0gbmVlZGxlKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGxpbmVzW2pdO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9LFxuICAgIGZpbmRfbGluZXM6IGZ1bmN0aW9uIChoYXlzdGFjaywgbmVlZGxlLCBzZXNzaW9ucGFydCkge1xuICAgICAgICB2YXIgbGluZXMgPSBoYXlzdGFjay5zcGxpdCgnXFxyXFxuJyksXG4gICAgICAgICAgICBuZWVkbGVzID0gW107XG4gICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgbGluZXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChsaW5lc1tpXS5zdWJzdHJpbmcoMCwgbmVlZGxlLmxlbmd0aCkgPT0gbmVlZGxlKVxuICAgICAgICAgICAgICAgIG5lZWRsZXMucHVzaChsaW5lc1tpXSk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKG5lZWRsZXMubGVuZ3RoIHx8ICFzZXNzaW9ucGFydCkge1xuICAgICAgICAgICAgcmV0dXJuIG5lZWRsZXM7XG4gICAgICAgIH1cbiAgICAgICAgLy8gc2VhcmNoIHNlc3Npb24gcGFydFxuICAgICAgICBsaW5lcyA9IHNlc3Npb25wYXJ0LnNwbGl0KCdcXHJcXG4nKTtcbiAgICAgICAgZm9yICh2YXIgaiA9IDA7IGogPCBsaW5lcy5sZW5ndGg7IGorKykge1xuICAgICAgICAgICAgaWYgKGxpbmVzW2pdLnN1YnN0cmluZygwLCBuZWVkbGUubGVuZ3RoKSA9PSBuZWVkbGUpIHtcbiAgICAgICAgICAgICAgICBuZWVkbGVzLnB1c2gobGluZXNbal0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBuZWVkbGVzO1xuICAgIH0sXG4gICAgY2FuZGlkYXRlVG9KaW5nbGU6IGZ1bmN0aW9uIChsaW5lKSB7XG4gICAgICAgIC8vIGE9Y2FuZGlkYXRlOjI5NzkxNjY2NjIgMSB1ZHAgMjExMzkzNzE1MSAxOTIuMTY4LjIuMTAwIDU3Njk4IHR5cCBob3N0IGdlbmVyYXRpb24gMFxuICAgICAgICAvLyAgICAgIDxjYW5kaWRhdGUgY29tcG9uZW50PS4uLiBmb3VuZGF0aW9uPS4uLiBnZW5lcmF0aW9uPS4uLiBpZD0uLi4gaXA9Li4uIG5ldHdvcms9Li4uIHBvcnQ9Li4uIHByaW9yaXR5PS4uLiBwcm90b2NvbD0uLi4gdHlwZT0uLi4vPlxuICAgICAgICBpZiAobGluZS5pbmRleE9mKCdjYW5kaWRhdGU6JykgPT09IDApIHtcbiAgICAgICAgICAgIGxpbmUgPSAnYT0nICsgbGluZTtcbiAgICAgICAgfSBlbHNlIGlmIChsaW5lLnN1YnN0cmluZygwLCAxMikgIT0gJ2E9Y2FuZGlkYXRlOicpIHtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKCdwYXJzZUNhbmRpZGF0ZSBjYWxsZWQgd2l0aCBhIGxpbmUgdGhhdCBpcyBub3QgYSBjYW5kaWRhdGUgbGluZScpO1xuICAgICAgICAgICAgY29uc29sZS5sb2cobGluZSk7XG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgfVxuICAgICAgICBpZiAobGluZS5zdWJzdHJpbmcobGluZS5sZW5ndGggLSAyKSA9PSAnXFxyXFxuJykgLy8gY2hvbXAgaXRcbiAgICAgICAgICAgIGxpbmUgPSBsaW5lLnN1YnN0cmluZygwLCBsaW5lLmxlbmd0aCAtIDIpO1xuICAgICAgICB2YXIgY2FuZGlkYXRlID0ge30sXG4gICAgICAgICAgICBlbGVtcyA9IGxpbmUuc3BsaXQoJyAnKSxcbiAgICAgICAgICAgIGk7XG4gICAgICAgIGlmIChlbGVtc1s2XSAhPSAndHlwJykge1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ2RpZCBub3QgZmluZCB0eXAgaW4gdGhlIHJpZ2h0IHBsYWNlJyk7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhsaW5lKTtcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9XG4gICAgICAgIGNhbmRpZGF0ZS5mb3VuZGF0aW9uID0gZWxlbXNbMF0uc3Vic3RyaW5nKDEyKTtcbiAgICAgICAgY2FuZGlkYXRlLmNvbXBvbmVudCA9IGVsZW1zWzFdO1xuICAgICAgICBjYW5kaWRhdGUucHJvdG9jb2wgPSBlbGVtc1syXS50b0xvd2VyQ2FzZSgpO1xuICAgICAgICBjYW5kaWRhdGUucHJpb3JpdHkgPSBlbGVtc1szXTtcbiAgICAgICAgY2FuZGlkYXRlLmlwID0gZWxlbXNbNF07XG4gICAgICAgIGNhbmRpZGF0ZS5wb3J0ID0gZWxlbXNbNV07XG4gICAgICAgIC8vIGVsZW1zWzZdID0+IFwidHlwXCJcbiAgICAgICAgY2FuZGlkYXRlLnR5cGUgPSBlbGVtc1s3XTtcblxuICAgICAgICBjYW5kaWRhdGUuZ2VuZXJhdGlvbiA9ICcwJzsgLy8gZGVmYXVsdCwgbWF5IGJlIG92ZXJ3cml0dGVuIGJlbG93XG4gICAgICAgIGZvciAoaSA9IDg7IGkgPCBlbGVtcy5sZW5ndGg7IGkgKz0gMikge1xuICAgICAgICAgICAgc3dpdGNoIChlbGVtc1tpXSkge1xuICAgICAgICAgICAgICAgIGNhc2UgJ3JhZGRyJzpcbiAgICAgICAgICAgICAgICAgICAgY2FuZGlkYXRlWydyZWwtYWRkciddID0gZWxlbXNbaSArIDFdO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICdycG9ydCc6XG4gICAgICAgICAgICAgICAgICAgIGNhbmRpZGF0ZVsncmVsLXBvcnQnXSA9IGVsZW1zW2kgKyAxXTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAnZ2VuZXJhdGlvbic6XG4gICAgICAgICAgICAgICAgICAgIGNhbmRpZGF0ZS5nZW5lcmF0aW9uID0gZWxlbXNbaSArIDFdO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICBjYXNlICd0Y3B0eXBlJzpcbiAgICAgICAgICAgICAgICAgICAgY2FuZGlkYXRlLnRjcHR5cGUgPSBlbGVtc1tpICsgMV07XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGRlZmF1bHQ6IC8vIFRPRE9cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ25vdCB0cmFuc2xhdGluZyBcIicgKyBlbGVtc1tpXSArICdcIiA9IFwiJyArIGVsZW1zW2kgKyAxXSArICdcIicpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGNhbmRpZGF0ZS5uZXR3b3JrID0gJzEnO1xuICAgICAgICBjYW5kaWRhdGUuaWQgPSBNYXRoLnJhbmRvbSgpLnRvU3RyaW5nKDM2KS5zdWJzdHIoMiwgMTApOyAvLyBub3QgYXBwbGljYWJsZSB0byBTRFAgLS0gRklYTUU6IHNob3VsZCBiZSB1bmlxdWUsIG5vdCBqdXN0IHJhbmRvbVxuICAgICAgICByZXR1cm4gY2FuZGlkYXRlO1xuICAgIH0sXG4gICAgY2FuZGlkYXRlRnJvbUppbmdsZTogZnVuY3Rpb24gKGNhbmQpIHtcbiAgICAgICAgdmFyIGxpbmUgPSAnYT1jYW5kaWRhdGU6JztcbiAgICAgICAgbGluZSArPSBjYW5kLmdldEF0dHJpYnV0ZSgnZm91bmRhdGlvbicpO1xuICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgbGluZSArPSBjYW5kLmdldEF0dHJpYnV0ZSgnY29tcG9uZW50Jyk7XG4gICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICBsaW5lICs9IGNhbmQuZ2V0QXR0cmlidXRlKCdwcm90b2NvbCcpOyAvLy50b1VwcGVyQ2FzZSgpOyAvLyBjaHJvbWUgTTIzIGRvZXNuJ3QgbGlrZSB0aGlzXG4gICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICBsaW5lICs9IGNhbmQuZ2V0QXR0cmlidXRlKCdwcmlvcml0eScpO1xuICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgbGluZSArPSBjYW5kLmdldEF0dHJpYnV0ZSgnaXAnKTtcbiAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgIGxpbmUgKz0gY2FuZC5nZXRBdHRyaWJ1dGUoJ3BvcnQnKTtcbiAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgIGxpbmUgKz0gJ3R5cCc7XG4gICAgICAgIGxpbmUgKz0gJyAnICsgY2FuZC5nZXRBdHRyaWJ1dGUoJ3R5cGUnKTtcbiAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgIHN3aXRjaCAoY2FuZC5nZXRBdHRyaWJ1dGUoJ3R5cGUnKSkge1xuICAgICAgICAgICAgY2FzZSAnc3JmbHgnOlxuICAgICAgICAgICAgY2FzZSAncHJmbHgnOlxuICAgICAgICAgICAgY2FzZSAncmVsYXknOlxuICAgICAgICAgICAgICAgIGlmIChjYW5kLmdldEF0dHJpYnV0ZSgncmVsLWFkZHInKSAmJiBjYW5kLmdldEF0dHJpYnV0ZSgncmVsLXBvcnQnKSkge1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICdyYWRkcic7XG4gICAgICAgICAgICAgICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9IGNhbmQuZ2V0QXR0cmlidXRlKCdyZWwtYWRkcicpO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSAncnBvcnQnO1xuICAgICAgICAgICAgICAgICAgICBsaW5lICs9ICcgJztcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSBjYW5kLmdldEF0dHJpYnV0ZSgncmVsLXBvcnQnKTtcbiAgICAgICAgICAgICAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjYW5kLmdldEF0dHJpYnV0ZSgncHJvdG9jb2wnKS50b0xvd2VyQ2FzZSgpID09ICd0Y3AnKSB7XG4gICAgICAgICAgICBsaW5lICs9ICd0Y3B0eXBlJztcbiAgICAgICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICAgICAgbGluZSArPSBjYW5kLmdldEF0dHJpYnV0ZSgndGNwdHlwZScpO1xuICAgICAgICAgICAgbGluZSArPSAnICc7XG4gICAgICAgIH1cbiAgICAgICAgbGluZSArPSAnZ2VuZXJhdGlvbic7XG4gICAgICAgIGxpbmUgKz0gJyAnO1xuICAgICAgICBsaW5lICs9IGNhbmQuZ2V0QXR0cmlidXRlKCdnZW5lcmF0aW9uJykgfHwgJzAnO1xuICAgICAgICByZXR1cm4gbGluZSArICdcXHJcXG4nO1xuICAgIH1cbn07XG5tb2R1bGUuZXhwb3J0cyA9IFNEUFV0aWw7IiwiZnVuY3Rpb24gVHJhY2VhYmxlUGVlckNvbm5lY3Rpb24oaWNlX2NvbmZpZywgY29uc3RyYWludHMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdmFyIFJUQ1BlZXJjb25uZWN0aW9uID0gbmF2aWdhdG9yLm1vekdldFVzZXJNZWRpYSA/IG1velJUQ1BlZXJDb25uZWN0aW9uIDogd2Via2l0UlRDUGVlckNvbm5lY3Rpb247XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbiA9IG5ldyBSVENQZWVyY29ubmVjdGlvbihpY2VfY29uZmlnLCBjb25zdHJhaW50cyk7XG4gICAgdGhpcy51cGRhdGVMb2cgPSBbXTtcbiAgICB0aGlzLnN0YXRzID0ge307XG4gICAgdGhpcy5zdGF0c2ludGVydmFsID0gbnVsbDtcbiAgICB0aGlzLm1heHN0YXRzID0gMDsgLy8gbGltaXQgdG8gMzAwIHZhbHVlcywgaS5lLiA1IG1pbnV0ZXM7IHNldCB0byAwIHRvIGRpc2FibGVcblxuICAgIC8vIG92ZXJyaWRlIGFzIGRlc2lyZWRcbiAgICB0aGlzLnRyYWNlID0gZnVuY3Rpb24gKHdoYXQsIGluZm8pIHtcbiAgICAgICAgLy9jb25zb2xlLndhcm4oJ1dUUkFDRScsIHdoYXQsIGluZm8pO1xuICAgICAgICBzZWxmLnVwZGF0ZUxvZy5wdXNoKHtcbiAgICAgICAgICAgIHRpbWU6IG5ldyBEYXRlKCksXG4gICAgICAgICAgICB0eXBlOiB3aGF0LFxuICAgICAgICAgICAgdmFsdWU6IGluZm8gfHwgXCJcIlxuICAgICAgICB9KTtcbiAgICB9O1xuICAgIHRoaXMub25pY2VjYW5kaWRhdGUgPSBudWxsO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25pY2VjYW5kaWRhdGUgPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgc2VsZi50cmFjZSgnb25pY2VjYW5kaWRhdGUnLCBKU09OLnN0cmluZ2lmeShldmVudC5jYW5kaWRhdGUsIG51bGwsICcgJykpO1xuICAgICAgICBpZiAoc2VsZi5vbmljZWNhbmRpZGF0ZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgc2VsZi5vbmljZWNhbmRpZGF0ZShldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMub25hZGRzdHJlYW0gPSBudWxsO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25hZGRzdHJlYW0gPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgc2VsZi50cmFjZSgnb25hZGRzdHJlYW0nLCBldmVudC5zdHJlYW0uaWQpO1xuICAgICAgICBpZiAoc2VsZi5vbmFkZHN0cmVhbSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgc2VsZi5vbmFkZHN0cmVhbShldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMub25yZW1vdmVzdHJlYW0gPSBudWxsO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25yZW1vdmVzdHJlYW0gPSBmdW5jdGlvbiAoZXZlbnQpIHtcbiAgICAgICAgc2VsZi50cmFjZSgnb25yZW1vdmVzdHJlYW0nLCBldmVudC5zdHJlYW0uaWQpO1xuICAgICAgICBpZiAoc2VsZi5vbnJlbW92ZXN0cmVhbSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgc2VsZi5vbnJlbW92ZXN0cmVhbShldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHRoaXMub25zaWduYWxpbmdzdGF0ZWNoYW5nZSA9IG51bGw7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5vbnNpZ25hbGluZ3N0YXRlY2hhbmdlID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHNlbGYudHJhY2UoJ29uc2lnbmFsaW5nc3RhdGVjaGFuZ2UnLCBzZWxmLnNpZ25hbGluZ1N0YXRlKTtcbiAgICAgICAgaWYgKHNlbGYub25zaWduYWxpbmdzdGF0ZWNoYW5nZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgc2VsZi5vbnNpZ25hbGluZ3N0YXRlY2hhbmdlKGV2ZW50KTtcbiAgICAgICAgfVxuICAgIH07XG4gICAgdGhpcy5vbmljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZSA9IG51bGw7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5vbmljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZSA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBzZWxmLnRyYWNlKCdvbmljZWNvbm5lY3Rpb25zdGF0ZWNoYW5nZScsIHNlbGYuaWNlQ29ubmVjdGlvblN0YXRlKTtcbiAgICAgICAgaWYgKHNlbGYub25pY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UgIT09IG51bGwpIHtcbiAgICAgICAgICAgIHNlbGYub25pY2Vjb25uZWN0aW9uc3RhdGVjaGFuZ2UoZXZlbnQpO1xuICAgICAgICB9XG4gICAgfTtcbiAgICB0aGlzLm9ubmVnb3RpYXRpb25uZWVkZWQgPSBudWxsO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24ub25uZWdvdGlhdGlvbm5lZWRlZCA9IGZ1bmN0aW9uIChldmVudCkge1xuICAgICAgICBzZWxmLnRyYWNlKCdvbm5lZ290aWF0aW9ubmVlZGVkJyk7XG4gICAgICAgIGlmIChzZWxmLm9ubmVnb3RpYXRpb25uZWVkZWQgIT09IG51bGwpIHtcbiAgICAgICAgICAgIHNlbGYub25uZWdvdGlhdGlvbm5lZWRlZChldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIHNlbGYub25kYXRhY2hhbm5lbCA9IG51bGw7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5vbmRhdGFjaGFubmVsID0gZnVuY3Rpb24gKGV2ZW50KSB7XG4gICAgICAgIHNlbGYudHJhY2UoJ29uZGF0YWNoYW5uZWwnLCBldmVudCk7XG4gICAgICAgIGlmIChzZWxmLm9uZGF0YWNoYW5uZWwgIT09IG51bGwpIHtcbiAgICAgICAgICAgIHNlbGYub25kYXRhY2hhbm5lbChldmVudCk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIGlmICghbmF2aWdhdG9yLm1vekdldFVzZXJNZWRpYSAmJiB0aGlzLm1heHN0YXRzKSB7XG4gICAgICAgIHRoaXMuc3RhdHNpbnRlcnZhbCA9IHdpbmRvdy5zZXRJbnRlcnZhbChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIHNlbGYucGVlcmNvbm5lY3Rpb24uZ2V0U3RhdHMoZnVuY3Rpb24oc3RhdHMpIHtcbiAgICAgICAgICAgICAgICB2YXIgcmVzdWx0cyA9IHN0YXRzLnJlc3VsdCgpO1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgcmVzdWx0cy5sZW5ndGg7ICsraSkge1xuICAgICAgICAgICAgICAgICAgICAvL2NvbnNvbGUubG9nKHJlc3VsdHNbaV0udHlwZSwgcmVzdWx0c1tpXS5pZCwgcmVzdWx0c1tpXS5uYW1lcygpKVxuICAgICAgICAgICAgICAgICAgICB2YXIgbm93ID0gbmV3IERhdGUoKTtcbiAgICAgICAgICAgICAgICAgICAgcmVzdWx0c1tpXS5uYW1lcygpLmZvckVhY2goZnVuY3Rpb24gKG5hbWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBpZCA9IHJlc3VsdHNbaV0uaWQgKyAnLScgKyBuYW1lO1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKCFzZWxmLnN0YXRzW2lkXSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuc3RhdHNbaWRdID0ge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydFRpbWU6IG5vdyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZW5kVGltZTogbm93LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZXM6IFtdLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aW1lczogW11cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5zdGF0c1tpZF0udmFsdWVzLnB1c2gocmVzdWx0c1tpXS5zdGF0KG5hbWUpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuc3RhdHNbaWRdLnRpbWVzLnB1c2gobm93LmdldFRpbWUoKSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2VsZi5zdGF0c1tpZF0udmFsdWVzLmxlbmd0aCA+IHNlbGYubWF4c3RhdHMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnN0YXRzW2lkXS52YWx1ZXMuc2hpZnQoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZWxmLnN0YXRzW2lkXS50aW1lcy5zaGlmdCgpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi5zdGF0c1tpZF0uZW5kVGltZSA9IG5vdztcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgfSwgMTAwMCk7XG4gICAgfVxufTtcblxuZHVtcFNEUCA9IGZ1bmN0aW9uKGRlc2NyaXB0aW9uKSB7XG4gICAgcmV0dXJuICd0eXBlOiAnICsgZGVzY3JpcHRpb24udHlwZSArICdcXHJcXG4nICsgZGVzY3JpcHRpb24uc2RwO1xufVxuXG5pZiAoVHJhY2VhYmxlUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl9fZGVmaW5lR2V0dGVyX18gIT09IHVuZGVmaW5lZCkge1xuICAgIFRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5fX2RlZmluZUdldHRlcl9fKCdzaWduYWxpbmdTdGF0ZScsIGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5wZWVyY29ubmVjdGlvbi5zaWduYWxpbmdTdGF0ZTsgfSk7XG4gICAgVHJhY2VhYmxlUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLl9fZGVmaW5lR2V0dGVyX18oJ2ljZUNvbm5lY3Rpb25TdGF0ZScsIGZ1bmN0aW9uKCkgeyByZXR1cm4gdGhpcy5wZWVyY29ubmVjdGlvbi5pY2VDb25uZWN0aW9uU3RhdGU7IH0pO1xuICAgIFRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5fX2RlZmluZUdldHRlcl9fKCdsb2NhbERlc2NyaXB0aW9uJywgZnVuY3Rpb24oKSB7XG4gICAgICAgIHZhciBwdWJsaWNMb2NhbERlc2NyaXB0aW9uID0gQVBQLnNpbXVsY2FzdC5yZXZlcnNlVHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbih0aGlzLnBlZXJjb25uZWN0aW9uLmxvY2FsRGVzY3JpcHRpb24pO1xuICAgICAgICByZXR1cm4gcHVibGljTG9jYWxEZXNjcmlwdGlvbjtcbiAgICB9KTtcbiAgICBUcmFjZWFibGVQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuX19kZWZpbmVHZXR0ZXJfXygncmVtb3RlRGVzY3JpcHRpb24nLCBmdW5jdGlvbigpIHtcbiAgICAgICAgdmFyIHB1YmxpY1JlbW90ZURlc2NyaXB0aW9uID0gQVBQLnNpbXVsY2FzdC5yZXZlcnNlVHJhbnNmb3JtUmVtb3RlRGVzY3JpcHRpb24odGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdGVEZXNjcmlwdGlvbik7XG4gICAgICAgIHJldHVybiBwdWJsaWNSZW1vdGVEZXNjcmlwdGlvbjtcbiAgICB9KTtcbn1cblxuVHJhY2VhYmxlUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmFkZFN0cmVhbSA9IGZ1bmN0aW9uIChzdHJlYW0pIHtcbiAgICB0aGlzLnRyYWNlKCdhZGRTdHJlYW0nLCBzdHJlYW0uaWQpO1xuICAgIEFQUC5zaW11bGNhc3QucmVzZXRTZW5kZXIoKTtcbiAgICB0cnlcbiAgICB7XG4gICAgICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uYWRkU3RyZWFtKHN0cmVhbSk7XG4gICAgfVxuICAgIGNhdGNoIChlKVxuICAgIHtcbiAgICAgICAgY29uc29sZS5lcnJvcihlKTtcbiAgICAgICAgcmV0dXJuO1xuICAgIH1cbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5yZW1vdmVTdHJlYW0gPSBmdW5jdGlvbiAoc3RyZWFtLCBzdG9wU3RyZWFtcykge1xuICAgIHRoaXMudHJhY2UoJ3JlbW92ZVN0cmVhbScsIHN0cmVhbS5pZCk7XG4gICAgQVBQLnNpbXVsY2FzdC5yZXNldFNlbmRlcigpO1xuICAgIGlmKHN0b3BTdHJlYW1zKSB7XG4gICAgICAgIHN0cmVhbS5nZXRBdWRpb1RyYWNrcygpLmZvckVhY2goZnVuY3Rpb24gKHRyYWNrKSB7XG4gICAgICAgICAgICB0cmFjay5zdG9wKCk7XG4gICAgICAgIH0pO1xuICAgICAgICBzdHJlYW0uZ2V0VmlkZW9UcmFja3MoKS5mb3JFYWNoKGZ1bmN0aW9uICh0cmFjaykge1xuICAgICAgICAgICAgdHJhY2suc3RvcCgpO1xuICAgICAgICB9KTtcbiAgICB9XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5yZW1vdmVTdHJlYW0oc3RyZWFtKTtcbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5jcmVhdGVEYXRhQ2hhbm5lbCA9IGZ1bmN0aW9uIChsYWJlbCwgb3B0cykge1xuICAgIHRoaXMudHJhY2UoJ2NyZWF0ZURhdGFDaGFubmVsJywgbGFiZWwsIG9wdHMpO1xuICAgIHJldHVybiB0aGlzLnBlZXJjb25uZWN0aW9uLmNyZWF0ZURhdGFDaGFubmVsKGxhYmVsLCBvcHRzKTtcbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5zZXRMb2NhbERlc2NyaXB0aW9uID0gZnVuY3Rpb24gKGRlc2NyaXB0aW9uLCBzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjaykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICBkZXNjcmlwdGlvbiA9IEFQUC5zaW11bGNhc3QudHJhbnNmb3JtTG9jYWxEZXNjcmlwdGlvbihkZXNjcmlwdGlvbik7XG4gICAgdGhpcy50cmFjZSgnc2V0TG9jYWxEZXNjcmlwdGlvbicsIGR1bXBTRFAoZGVzY3JpcHRpb24pKTtcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLnNldExvY2FsRGVzY3JpcHRpb24oZGVzY3JpcHRpb24sXG4gICAgICAgIGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIHNlbGYudHJhY2UoJ3NldExvY2FsRGVzY3JpcHRpb25PblN1Y2Nlc3MnKTtcbiAgICAgICAgICAgIHN1Y2Nlc3NDYWxsYmFjaygpO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICBzZWxmLnRyYWNlKCdzZXRMb2NhbERlc2NyaXB0aW9uT25GYWlsdXJlJywgZXJyKTtcbiAgICAgICAgICAgIGZhaWx1cmVDYWxsYmFjayhlcnIpO1xuICAgICAgICB9XG4gICAgKTtcbiAgICAvKlxuICAgICBpZiAodGhpcy5zdGF0c2ludGVydmFsID09PSBudWxsICYmIHRoaXMubWF4c3RhdHMgPiAwKSB7XG4gICAgIC8vIHN0YXJ0IGdhdGhlcmluZyBzdGF0c1xuICAgICB9XG4gICAgICovXG59O1xuXG5UcmFjZWFibGVQZWVyQ29ubmVjdGlvbi5wcm90b3R5cGUuc2V0UmVtb3RlRGVzY3JpcHRpb24gPSBmdW5jdGlvbiAoZGVzY3JpcHRpb24sIHN1Y2Nlc3NDYWxsYmFjaywgZmFpbHVyZUNhbGxiYWNrKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIGRlc2NyaXB0aW9uID0gQVBQLnNpbXVsY2FzdC50cmFuc2Zvcm1SZW1vdGVEZXNjcmlwdGlvbihkZXNjcmlwdGlvbik7XG4gICAgdGhpcy50cmFjZSgnc2V0UmVtb3RlRGVzY3JpcHRpb24nLCBkdW1wU0RQKGRlc2NyaXB0aW9uKSk7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5zZXRSZW1vdGVEZXNjcmlwdGlvbihkZXNjcmlwdGlvbixcbiAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgc2VsZi50cmFjZSgnc2V0UmVtb3RlRGVzY3JpcHRpb25PblN1Y2Nlc3MnKTtcbiAgICAgICAgICAgIHN1Y2Nlc3NDYWxsYmFjaygpO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZXJyKSB7XG4gICAgICAgICAgICBzZWxmLnRyYWNlKCdzZXRSZW1vdGVEZXNjcmlwdGlvbk9uRmFpbHVyZScsIGVycik7XG4gICAgICAgICAgICBmYWlsdXJlQ2FsbGJhY2soZXJyKTtcbiAgICAgICAgfVxuICAgICk7XG4gICAgLypcbiAgICAgaWYgKHRoaXMuc3RhdHNpbnRlcnZhbCA9PT0gbnVsbCAmJiB0aGlzLm1heHN0YXRzID4gMCkge1xuICAgICAvLyBzdGFydCBnYXRoZXJpbmcgc3RhdHNcbiAgICAgfVxuICAgICAqL1xufTtcblxuVHJhY2VhYmxlUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmNsb3NlID0gZnVuY3Rpb24gKCkge1xuICAgIHRoaXMudHJhY2UoJ3N0b3AnKTtcbiAgICBpZiAodGhpcy5zdGF0c2ludGVydmFsICE9PSBudWxsKSB7XG4gICAgICAgIHdpbmRvdy5jbGVhckludGVydmFsKHRoaXMuc3RhdHNpbnRlcnZhbCk7XG4gICAgICAgIHRoaXMuc3RhdHNpbnRlcnZhbCA9IG51bGw7XG4gICAgfVxuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uY2xvc2UoKTtcbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5jcmVhdGVPZmZlciA9IGZ1bmN0aW9uIChzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjaywgY29uc3RyYWludHMpIHtcbiAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgdGhpcy50cmFjZSgnY3JlYXRlT2ZmZXInLCBKU09OLnN0cmluZ2lmeShjb25zdHJhaW50cywgbnVsbCwgJyAnKSk7XG4gICAgdGhpcy5wZWVyY29ubmVjdGlvbi5jcmVhdGVPZmZlcihcbiAgICAgICAgZnVuY3Rpb24gKG9mZmVyKSB7XG4gICAgICAgICAgICBzZWxmLnRyYWNlKCdjcmVhdGVPZmZlck9uU3VjY2VzcycsIGR1bXBTRFAob2ZmZXIpKTtcbiAgICAgICAgICAgIHN1Y2Nlc3NDYWxsYmFjayhvZmZlcik7XG4gICAgICAgIH0sXG4gICAgICAgIGZ1bmN0aW9uKGVycikge1xuICAgICAgICAgICAgc2VsZi50cmFjZSgnY3JlYXRlT2ZmZXJPbkZhaWx1cmUnLCBlcnIpO1xuICAgICAgICAgICAgZmFpbHVyZUNhbGxiYWNrKGVycik7XG4gICAgICAgIH0sXG4gICAgICAgIGNvbnN0cmFpbnRzXG4gICAgKTtcbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5jcmVhdGVBbnN3ZXIgPSBmdW5jdGlvbiAoc3VjY2Vzc0NhbGxiYWNrLCBmYWlsdXJlQ2FsbGJhY2ssIGNvbnN0cmFpbnRzKSB7XG4gICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgIHRoaXMudHJhY2UoJ2NyZWF0ZUFuc3dlcicsIEpTT04uc3RyaW5naWZ5KGNvbnN0cmFpbnRzLCBudWxsLCAnICcpKTtcbiAgICB0aGlzLnBlZXJjb25uZWN0aW9uLmNyZWF0ZUFuc3dlcihcbiAgICAgICAgZnVuY3Rpb24gKGFuc3dlcikge1xuICAgICAgICAgICAgYW5zd2VyID0gQVBQLnNpbXVsY2FzdC50cmFuc2Zvcm1BbnN3ZXIoYW5zd2VyKTtcbiAgICAgICAgICAgIHNlbGYudHJhY2UoJ2NyZWF0ZUFuc3dlck9uU3VjY2VzcycsIGR1bXBTRFAoYW5zd2VyKSk7XG4gICAgICAgICAgICBzdWNjZXNzQ2FsbGJhY2soYW5zd2VyKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24oZXJyKSB7XG4gICAgICAgICAgICBzZWxmLnRyYWNlKCdjcmVhdGVBbnN3ZXJPbkZhaWx1cmUnLCBlcnIpO1xuICAgICAgICAgICAgZmFpbHVyZUNhbGxiYWNrKGVycik7XG4gICAgICAgIH0sXG4gICAgICAgIGNvbnN0cmFpbnRzXG4gICAgKTtcbn07XG5cblRyYWNlYWJsZVBlZXJDb25uZWN0aW9uLnByb3RvdHlwZS5hZGRJY2VDYW5kaWRhdGUgPSBmdW5jdGlvbiAoY2FuZGlkYXRlLCBzdWNjZXNzQ2FsbGJhY2ssIGZhaWx1cmVDYWxsYmFjaykge1xuICAgIHZhciBzZWxmID0gdGhpcztcbiAgICB0aGlzLnRyYWNlKCdhZGRJY2VDYW5kaWRhdGUnLCBKU09OLnN0cmluZ2lmeShjYW5kaWRhdGUsIG51bGwsICcgJykpO1xuICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uYWRkSWNlQ2FuZGlkYXRlKGNhbmRpZGF0ZSk7XG4gICAgLyogbWF5YmUgbGF0ZXJcbiAgICAgdGhpcy5wZWVyY29ubmVjdGlvbi5hZGRJY2VDYW5kaWRhdGUoY2FuZGlkYXRlLFxuICAgICBmdW5jdGlvbiAoKSB7XG4gICAgIHNlbGYudHJhY2UoJ2FkZEljZUNhbmRpZGF0ZU9uU3VjY2VzcycpO1xuICAgICBzdWNjZXNzQ2FsbGJhY2soKTtcbiAgICAgfSxcbiAgICAgZnVuY3Rpb24gKGVycikge1xuICAgICBzZWxmLnRyYWNlKCdhZGRJY2VDYW5kaWRhdGVPbkZhaWx1cmUnLCBlcnIpO1xuICAgICBmYWlsdXJlQ2FsbGJhY2soZXJyKTtcbiAgICAgfVxuICAgICApO1xuICAgICAqL1xufTtcblxuVHJhY2VhYmxlUGVlckNvbm5lY3Rpb24ucHJvdG90eXBlLmdldFN0YXRzID0gZnVuY3Rpb24oY2FsbGJhY2ssIGVycmJhY2spIHtcbiAgICBpZiAobmF2aWdhdG9yLm1vekdldFVzZXJNZWRpYSkge1xuICAgICAgICAvLyBpZ25vcmUgZm9yIG5vdy4uLlxuICAgICAgICBpZighZXJyYmFjaylcbiAgICAgICAgICAgIGVycmJhY2sgPSBmdW5jdGlvbiAoKSB7XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgdGhpcy5wZWVyY29ubmVjdGlvbi5nZXRTdGF0cyhudWxsLGNhbGxiYWNrLGVycmJhY2spO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMucGVlcmNvbm5lY3Rpb24uZ2V0U3RhdHMoY2FsbGJhY2spO1xuICAgIH1cbn07XG5cbm1vZHVsZS5leHBvcnRzID0gVHJhY2VhYmxlUGVlckNvbm5lY3Rpb247XG5cbiIsIi8qIGdsb2JhbCAkLCAkaXEsIGNvbmZpZywgY29ubmVjdGlvbiwgVUksIG1lc3NhZ2VIYW5kbGVyLFxuIHJvb21OYW1lLCBzZXNzaW9uVGVybWluYXRlZCwgU3Ryb3BoZSwgVXRpbCAqL1xudmFyIFhNUFBFdmVudHMgPSByZXF1aXJlKFwiLi4vLi4vc2VydmljZS94bXBwL1hNUFBFdmVudHNcIik7XG5cbi8qKlxuICogQ29udGFpbnMgbG9naWMgcmVzcG9uc2libGUgZm9yIGVuYWJsaW5nL2Rpc2FibGluZyBmdW5jdGlvbmFsaXR5IGF2YWlsYWJsZVxuICogb25seSB0byBtb2RlcmF0b3IgdXNlcnMuXG4gKi9cbnZhciBjb25uZWN0aW9uID0gbnVsbDtcbnZhciBmb2N1c1VzZXJKaWQ7XG5cbmZ1bmN0aW9uIGNyZWF0ZUV4cEJhY2tvZmZUaW1lcihzdGVwKSB7XG4gICAgdmFyIGNvdW50ID0gMTtcbiAgICByZXR1cm4gZnVuY3Rpb24gKHJlc2V0KSB7XG4gICAgICAgIC8vIFJlc2V0IGNhbGxcbiAgICAgICAgaWYgKHJlc2V0KSB7XG4gICAgICAgICAgICBjb3VudCA9IDE7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgLy8gQ2FsY3VsYXRlIG5leHQgdGltZW91dFxuICAgICAgICB2YXIgdGltZW91dCA9IE1hdGgucG93KDIsIGNvdW50IC0gMSk7XG4gICAgICAgIGNvdW50ICs9IDE7XG4gICAgICAgIHJldHVybiB0aW1lb3V0ICogc3RlcDtcbiAgICB9O1xufVxuXG52YXIgZ2V0TmV4dFRpbWVvdXQgPSBjcmVhdGVFeHBCYWNrb2ZmVGltZXIoMTAwMCk7XG52YXIgZ2V0TmV4dEVycm9yVGltZW91dCA9IGNyZWF0ZUV4cEJhY2tvZmZUaW1lcigxMDAwKTtcbi8vIEV4dGVybmFsIGF1dGhlbnRpY2F0aW9uIHN0dWZmXG52YXIgZXh0ZXJuYWxBdXRoRW5hYmxlZCA9IGZhbHNlO1xuLy8gU2lwIGdhdGV3YXkgY2FuIGJlIGVuYWJsZWQgYnkgY29uZmlndXJpbmcgSmlnYXNpIGhvc3QgaW4gY29uZmlnLmpzIG9yXG4vLyBpdCB3aWxsIGJlIGVuYWJsZWQgYXV0b21hdGljYWxseSBpZiBmb2N1cyBkZXRlY3RzIHRoZSBjb21wb25lbnQgdGhyb3VnaFxuLy8gc2VydmljZSBkaXNjb3ZlcnkuXG52YXIgc2lwR2F0ZXdheUVuYWJsZWQgPSBjb25maWcuaG9zdHMuY2FsbF9jb250cm9sICE9PSB1bmRlZmluZWQ7XG5cbnZhciBldmVudEVtaXR0ZXIgPSBudWxsO1xuXG52YXIgTW9kZXJhdG9yID0ge1xuICAgIGlzTW9kZXJhdG9yOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uICYmIGNvbm5lY3Rpb24uZW11Yy5pc01vZGVyYXRvcigpO1xuICAgIH0sXG5cbiAgICBpc1BlZXJNb2RlcmF0b3I6IGZ1bmN0aW9uIChwZWVySmlkKSB7XG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uICYmXG4gICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuZ2V0TWVtYmVyUm9sZShwZWVySmlkKSA9PT0gJ21vZGVyYXRvcic7XG4gICAgfSxcblxuICAgIGlzRXh0ZXJuYWxBdXRoRW5hYmxlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gZXh0ZXJuYWxBdXRoRW5hYmxlZDtcbiAgICB9LFxuXG4gICAgaXNTaXBHYXRld2F5RW5hYmxlZDogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gc2lwR2F0ZXdheUVuYWJsZWQ7XG4gICAgfSxcblxuICAgIHNldENvbm5lY3Rpb246IGZ1bmN0aW9uIChjb24pIHtcbiAgICAgICAgY29ubmVjdGlvbiA9IGNvbjtcbiAgICB9LFxuXG4gICAgaW5pdDogZnVuY3Rpb24gKHhtcHAsIGVtaXR0ZXIpIHtcbiAgICAgICAgdGhpcy54bXBwU2VydmljZSA9IHhtcHA7XG4gICAgICAgIGV2ZW50RW1pdHRlciA9IGVtaXR0ZXI7XG4gICAgfSxcblxuICAgIG9uTXVjTGVmdDogZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBjb25zb2xlLmluZm8oXCJTb21lb25lIGxlZnQgaXMgaXQgZm9jdXMgPyBcIiArIGppZCk7XG4gICAgICAgIHZhciByZXNvdXJjZSA9IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCk7XG4gICAgICAgIGlmIChyZXNvdXJjZSA9PT0gJ2ZvY3VzJyAmJiAhdGhpcy54bXBwU2VydmljZS5zZXNzaW9uVGVybWluYXRlZCkge1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKFxuICAgICAgICAgICAgICAgIFwiRm9jdXMgaGFzIGxlZnQgdGhlIHJvb20gLSBsZWF2aW5nIGNvbmZlcmVuY2VcIik7XG4gICAgICAgICAgICAvL2hhbmdVcCgpO1xuICAgICAgICAgICAgLy8gV2UnZCByYXRoZXIgcmVsb2FkIHRvIGhhdmUgZXZlcnl0aGluZyByZS1pbml0aWFsaXplZFxuICAgICAgICAgICAgLy8gRklYTUU6IHNob3cgc29tZSBtZXNzYWdlIGJlZm9yZSByZWxvYWRcbiAgICAgICAgICAgIGxvY2F0aW9uLnJlbG9hZCgpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBcbiAgICBzZXRGb2N1c1VzZXJKaWQ6IGZ1bmN0aW9uIChmb2N1c0ppZCkge1xuICAgICAgICBpZiAoIWZvY3VzVXNlckppZCkge1xuICAgICAgICAgICAgZm9jdXNVc2VySmlkID0gZm9jdXNKaWQ7XG4gICAgICAgICAgICBjb25zb2xlLmluZm8oXCJGb2N1cyBqaWQgc2V0IHRvOiBcIiArIGZvY3VzVXNlckppZCk7XG4gICAgICAgIH1cbiAgICB9LFxuXG4gICAgZ2V0Rm9jdXNVc2VySmlkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBmb2N1c1VzZXJKaWQ7XG4gICAgfSxcblxuICAgIGdldEZvY3VzQ29tcG9uZW50OiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIC8vIEdldCBmb2N1cyBjb21wb25lbnQgYWRkcmVzc1xuICAgICAgICB2YXIgZm9jdXNDb21wb25lbnQgPSBjb25maWcuaG9zdHMuZm9jdXM7XG4gICAgICAgIC8vIElmIG5vdCBzcGVjaWZpZWQgdXNlIGRlZmF1bHQ6ICdmb2N1cy5kb21haW4nXG4gICAgICAgIGlmICghZm9jdXNDb21wb25lbnQpIHtcbiAgICAgICAgICAgIGZvY3VzQ29tcG9uZW50ID0gJ2ZvY3VzLicgKyBjb25maWcuaG9zdHMuZG9tYWluO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBmb2N1c0NvbXBvbmVudDtcbiAgICB9LFxuXG4gICAgY3JlYXRlQ29uZmVyZW5jZUlxOiBmdW5jdGlvbiAocm9vbU5hbWUpIHtcbiAgICAgICAgLy8gR2VuZXJhdGUgY3JlYXRlIGNvbmZlcmVuY2UgSVFcbiAgICAgICAgdmFyIGVsZW0gPSAkaXEoe3RvOiBNb2RlcmF0b3IuZ2V0Rm9jdXNDb21wb25lbnQoKSwgdHlwZTogJ3NldCd9KTtcbiAgICAgICAgZWxlbS5jKCdjb25mZXJlbmNlJywge1xuICAgICAgICAgICAgeG1sbnM6ICdodHRwOi8vaml0c2kub3JnL3Byb3RvY29sL2ZvY3VzJyxcbiAgICAgICAgICAgIHJvb206IHJvb21OYW1lXG4gICAgICAgIH0pO1xuICAgICAgICBpZiAoY29uZmlnLmhvc3RzLmJyaWRnZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBlbGVtLmMoXG4gICAgICAgICAgICAgICAgJ3Byb3BlcnR5JyxcbiAgICAgICAgICAgICAgICB7IG5hbWU6ICdicmlkZ2UnLCB2YWx1ZTogY29uZmlnLmhvc3RzLmJyaWRnZX0pXG4gICAgICAgICAgICAgICAgLnVwKCk7XG4gICAgICAgIH1cbiAgICAgICAgLy8gVGVsbCB0aGUgZm9jdXMgd2UgaGF2ZSBKaWdhc2kgY29uZmlndXJlZFxuICAgICAgICBpZiAoY29uZmlnLmhvc3RzLmNhbGxfY29udHJvbCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBlbGVtLmMoXG4gICAgICAgICAgICAgICAgJ3Byb3BlcnR5JyxcbiAgICAgICAgICAgICAgICB7IG5hbWU6ICdjYWxsX2NvbnRyb2wnLCB2YWx1ZTogY29uZmlnLmhvc3RzLmNhbGxfY29udHJvbH0pXG4gICAgICAgICAgICAgICAgLnVwKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNvbmZpZy5jaGFubmVsTGFzdE4gIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZWxlbS5jKFxuICAgICAgICAgICAgICAgICdwcm9wZXJ0eScsXG4gICAgICAgICAgICAgICAgeyBuYW1lOiAnY2hhbm5lbExhc3ROJywgdmFsdWU6IGNvbmZpZy5jaGFubmVsTGFzdE59KVxuICAgICAgICAgICAgICAgIC51cCgpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjb25maWcuYWRhcHRpdmVMYXN0TiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBlbGVtLmMoXG4gICAgICAgICAgICAgICAgJ3Byb3BlcnR5JyxcbiAgICAgICAgICAgICAgICB7IG5hbWU6ICdhZGFwdGl2ZUxhc3ROJywgdmFsdWU6IGNvbmZpZy5hZGFwdGl2ZUxhc3ROfSlcbiAgICAgICAgICAgICAgICAudXAoKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29uZmlnLmFkYXB0aXZlU2ltdWxjYXN0ICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIGVsZW0uYyhcbiAgICAgICAgICAgICAgICAncHJvcGVydHknLFxuICAgICAgICAgICAgICAgIHsgbmFtZTogJ2FkYXB0aXZlU2ltdWxjYXN0JywgdmFsdWU6IGNvbmZpZy5hZGFwdGl2ZVNpbXVsY2FzdH0pXG4gICAgICAgICAgICAgICAgLnVwKCk7XG4gICAgICAgIH1cbiAgICAgICAgaWYgKGNvbmZpZy5vcGVuU2N0cCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICBlbGVtLmMoXG4gICAgICAgICAgICAgICAgJ3Byb3BlcnR5JyxcbiAgICAgICAgICAgICAgICB7IG5hbWU6ICdvcGVuU2N0cCcsIHZhbHVlOiBjb25maWcub3BlblNjdHB9KVxuICAgICAgICAgICAgICAgIC51cCgpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChjb25maWcuZW5hYmxlRmlyZWZveFN1cHBvcnQgIT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgZWxlbS5jKFxuICAgICAgICAgICAgICAgICdwcm9wZXJ0eScsXG4gICAgICAgICAgICAgICAgeyBuYW1lOiAnZW5hYmxlRmlyZWZveEhhY2tzJyxcbiAgICAgICAgICAgICAgICAgICAgdmFsdWU6IGNvbmZpZy5lbmFibGVGaXJlZm94U3VwcG9ydH0pXG4gICAgICAgICAgICAgICAgLnVwKCk7XG4gICAgICAgIH1cbiAgICAgICAgZWxlbS51cCgpO1xuICAgICAgICByZXR1cm4gZWxlbTtcbiAgICB9LFxuXG4gICAgcGFyc2VDb25maWdPcHRpb25zOiBmdW5jdGlvbiAocmVzdWx0SXEpIHtcbiAgICBcbiAgICAgICAgTW9kZXJhdG9yLnNldEZvY3VzVXNlckppZChcbiAgICAgICAgICAgICQocmVzdWx0SXEpLmZpbmQoJ2NvbmZlcmVuY2UnKS5hdHRyKCdmb2N1c2ppZCcpKTtcbiAgICBcbiAgICAgICAgdmFyIGV4dEF1dGhQYXJhbVxuICAgICAgICAgICAgPSAkKHJlc3VsdElxKS5maW5kKCc+Y29uZmVyZW5jZT5wcm9wZXJ0eVtuYW1lPVxcJ2V4dGVybmFsQXV0aFxcJ10nKTtcbiAgICAgICAgaWYgKGV4dEF1dGhQYXJhbS5sZW5ndGgpIHtcbiAgICAgICAgICAgIGV4dGVybmFsQXV0aEVuYWJsZWQgPSBleHRBdXRoUGFyYW0uYXR0cigndmFsdWUnKSA9PT0gJ3RydWUnO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIkV4dGVybmFsIGF1dGhlbnRpY2F0aW9uIGVuYWJsZWQ6IFwiICsgZXh0ZXJuYWxBdXRoRW5hYmxlZCk7XG4gICAgXG4gICAgICAgIC8vIENoZWNrIGlmIGZvY3VzIGhhcyBhdXRvLWRldGVjdGVkIEppZ2FzaSBjb21wb25lbnQodGhpcyB3aWxsIGJlIGFsc29cbiAgICAgICAgLy8gaW5jbHVkZWQgaWYgd2UgaGF2ZSBwYXNzZWQgb3VyIGhvc3QgZnJvbSB0aGUgY29uZmlnKVxuICAgICAgICBpZiAoJChyZXN1bHRJcSkuZmluZChcbiAgICAgICAgICAgICc+Y29uZmVyZW5jZT5wcm9wZXJ0eVtuYW1lPVxcJ3NpcEdhdGV3YXlFbmFibGVkXFwnXScpLmxlbmd0aCkge1xuICAgICAgICAgICAgc2lwR2F0ZXdheUVuYWJsZWQgPSB0cnVlO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIGNvbnNvbGUuaW5mbyhcIlNpcCBnYXRld2F5IGVuYWJsZWQ6IFwiICsgc2lwR2F0ZXdheUVuYWJsZWQpO1xuICAgIH0sXG5cbiAgICAvLyBGSVhNRTogd2UgbmVlZCB0byBzaG93IHRoZSBmYWN0IHRoYXQgd2UncmUgd2FpdGluZyBmb3IgdGhlIGZvY3VzXG4gICAgLy8gdG8gdGhlIHVzZXIob3IgdGhhdCBmb2N1cyBpcyBub3QgYXZhaWxhYmxlKVxuICAgIGFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzOiBmdW5jdGlvbiAocm9vbU5hbWUsIGNhbGxiYWNrKSB7XG4gICAgICAgIC8vIFRyeSB0byB1c2UgZm9jdXMgdXNlciBKSUQgZnJvbSB0aGUgY29uZmlnXG4gICAgICAgIE1vZGVyYXRvci5zZXRGb2N1c1VzZXJKaWQoY29uZmlnLmZvY3VzVXNlckppZCk7XG4gICAgICAgIC8vIFNlbmQgY3JlYXRlIGNvbmZlcmVuY2UgSVFcbiAgICAgICAgdmFyIGlxID0gTW9kZXJhdG9yLmNyZWF0ZUNvbmZlcmVuY2VJcShyb29tTmFtZSk7XG4gICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgY29ubmVjdGlvbi5zZW5kSVEoXG4gICAgICAgICAgICBpcSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChyZXN1bHQpIHtcbiAgICAgICAgICAgICAgICBpZiAoJ3RydWUnID09PSAkKHJlc3VsdCkuZmluZCgnY29uZmVyZW5jZScpLmF0dHIoJ3JlYWR5JykpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gUmVzZXQgYm90aCB0aW1lcnNcbiAgICAgICAgICAgICAgICAgICAgZ2V0TmV4dFRpbWVvdXQodHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIGdldE5leHRFcnJvclRpbWVvdXQodHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIC8vIFNldHVwIGNvbmZpZyBvcHRpb25zXG4gICAgICAgICAgICAgICAgICAgIE1vZGVyYXRvci5wYXJzZUNvbmZpZ09wdGlvbnMocmVzdWx0KTtcbiAgICAgICAgICAgICAgICAgICAgLy8gRXhlYyBjYWxsYmFja1xuICAgICAgICAgICAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciB3YWl0TXMgPSBnZXROZXh0VGltZW91dCgpO1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXCJXYWl0aW5nIGZvciB0aGUgZm9jdXMuLi4gXCIgKyB3YWl0TXMpO1xuICAgICAgICAgICAgICAgICAgICAvLyBSZXNldCBlcnJvciB0aW1lb3V0XG4gICAgICAgICAgICAgICAgICAgIGdldE5leHRFcnJvclRpbWVvdXQodHJ1ZSk7XG4gICAgICAgICAgICAgICAgICAgIHdpbmRvdy5zZXRUaW1lb3V0KFxuICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIE1vZGVyYXRvci5hbGxvY2F0ZUNvbmZlcmVuY2VGb2N1cyhcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcm9vbU5hbWUsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sIHdhaXRNcyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgIC8vIE5vdCBhdXRob3JpemVkIHRvIGNyZWF0ZSBuZXcgcm9vbVxuICAgICAgICAgICAgICAgIGlmICgkKGVycm9yKS5maW5kKCc+ZXJyb3I+bm90LWF1dGhvcml6ZWQnKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKFwiVW5hdXRob3JpemVkIHRvIHN0YXJ0IHRoZSBjb25mZXJlbmNlXCIpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgdG9Eb21haW5cbiAgICAgICAgICAgICAgICAgICAgICAgID0gU3Ryb3BoZS5nZXREb21haW5Gcm9tSmlkKGVycm9yLmdldEF0dHJpYnV0ZSgndG8nKSk7XG4gICAgICAgICAgICAgICAgICAgIGlmICh0b0RvbWFpbiA9PT0gY29uZmlnLmhvc3RzLmFub255bW91c2RvbWFpbikge1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2UgYXJlIGNvbm5lY3RlZCB3aXRoIGFub255bW91cyBkb21haW4gYW5kXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBvbmx5IG5vbiBhbm9ueW1vdXMgdXNlcnMgY2FuIGNyZWF0ZSByb29tc1xuICAgICAgICAgICAgICAgICAgICAgICAgLy8gd2UgbXVzdCBhdXRob3JpemUgdGhlIHVzZXJcblxuICAgICAgICAgICAgICAgICAgICAgICAgc2VsZi54bXBwU2VydmljZS5wcm9tcHRMb2dpbigpO1xuICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuXG4gICAgICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLkFVVEhFTlRJQ0FUSU9OX1JFUVVJUkVELCAvLyBFeHRlcm5hbCBhdXRoZW50aWNhdGlvbiBtb2RlXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBNb2RlcmF0b3IuYWxsb2NhdGVDb25mZXJlbmNlRm9jdXMoXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByb29tTmFtZSwgY2FsbGJhY2spO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH0pO1xuXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB2YXIgd2FpdE1zID0gZ2V0TmV4dEVycm9yVGltZW91dCgpO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJGb2N1cyBlcnJvciwgcmV0cnkgYWZ0ZXIgXCIgKyB3YWl0TXMsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAvLyBTaG93IG1lc3NhZ2VcbiAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIubm90aWZ5KFxuICAgICAgICAgICAgICAgICAgICAnQ29uZmVyZW5jZSBmb2N1cycsICdkaXNjb25uZWN0ZWQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgTW9kZXJhdG9yLmdldEZvY3VzQ29tcG9uZW50KCkgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJyBub3QgYXZhaWxhYmxlIC0gcmV0cnkgaW4gJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAod2FpdE1zIC8gMTAwMCkgKyAnIHNlYycpO1xuICAgICAgICAgICAgICAgIC8vIFJlc2V0IHJlc3BvbnNlIHRpbWVvdXRcbiAgICAgICAgICAgICAgICBnZXROZXh0VGltZW91dCh0cnVlKTtcbiAgICAgICAgICAgICAgICB3aW5kb3cuc2V0VGltZW91dChcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgTW9kZXJhdG9yLmFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzKHJvb21OYW1lLCBjYWxsYmFjayk7XG4gICAgICAgICAgICAgICAgICAgIH0sIHdhaXRNcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfSxcblxuICAgIGdldEF1dGhVcmw6IGZ1bmN0aW9uIChyb29tTmFtZSwgdXJsQ2FsbGJhY2spIHtcbiAgICAgICAgdmFyIGlxID0gJGlxKHt0bzogTW9kZXJhdG9yLmdldEZvY3VzQ29tcG9uZW50KCksIHR5cGU6ICdnZXQnfSk7XG4gICAgICAgIGlxLmMoJ2F1dGgtdXJsJywge1xuICAgICAgICAgICAgeG1sbnM6ICdodHRwOi8vaml0c2kub3JnL3Byb3RvY29sL2ZvY3VzJyxcbiAgICAgICAgICAgIHJvb206IHJvb21OYW1lXG4gICAgICAgIH0pO1xuICAgICAgICBjb25uZWN0aW9uLnNlbmRJUShcbiAgICAgICAgICAgIGlxLFxuICAgICAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgIHZhciB1cmwgPSAkKHJlc3VsdCkuZmluZCgnYXV0aC11cmwnKS5hdHRyKCd1cmwnKTtcbiAgICAgICAgICAgICAgICBpZiAodXJsKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkdvdCBhdXRoIHVybDogXCIgKyB1cmwpO1xuICAgICAgICAgICAgICAgICAgICB1cmxDYWxsYmFjayh1cmwpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXG4gICAgICAgICAgICAgICAgICAgICAgICBcIkZhaWxlZCB0byBnZXQgYXV0aCB1cmwgZnJvIG10aGUgZm9jdXNcIiwgcmVzdWx0KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9LFxuICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIkdldCBhdXRoIHVybCBlcnJvclwiLCBlcnJvcik7XG4gICAgICAgICAgICB9XG4gICAgICAgICk7XG4gICAgfVxufTtcblxubW9kdWxlLmV4cG9ydHMgPSBNb2RlcmF0b3I7XG5cblxuXG4iLCIvKiBnbG9iYWwgJCwgJGlxLCBjb25maWcsIGNvbm5lY3Rpb24sIGZvY3VzTXVjSmlkLCBtZXNzYWdlSGFuZGxlciwgTW9kZXJhdG9yLFxuICAgVG9vbGJhciwgVXRpbCAqL1xudmFyIE1vZGVyYXRvciA9IHJlcXVpcmUoXCIuL21vZGVyYXRvclwiKTtcblxuXG52YXIgcmVjb3JkaW5nVG9rZW4gPSBudWxsO1xudmFyIHJlY29yZGluZ0VuYWJsZWQ7XG5cbi8qKlxuICogV2hldGhlciB0byB1c2UgYSBqaXJlY29uIGNvbXBvbmVudCBmb3IgcmVjb3JkaW5nLCBvciB1c2UgdGhlIHZpZGVvYnJpZGdlXG4gKiB0aHJvdWdoIENPTElCUkkuXG4gKi9cbnZhciB1c2VKaXJlY29uID0gKHR5cGVvZiBjb25maWcuaG9zdHMuamlyZWNvbiAhPSBcInVuZGVmaW5lZFwiKTtcblxuLyoqXG4gKiBUaGUgSUQgb2YgdGhlIGppcmVjb24gcmVjb3JkaW5nIHNlc3Npb24uIEppcmVjb24gZ2VuZXJhdGVzIGl0IHdoZW4gd2VcbiAqIGluaXRpYWxseSBzdGFydCByZWNvcmRpbmcsIGFuZCBpdCBuZWVkcyB0byBiZSB1c2VkIGluIHN1YnNlcXVlbnQgcmVxdWVzdHNcbiAqIHRvIGppcmVjb24uXG4gKi9cbnZhciBqaXJlY29uUmlkID0gbnVsbDtcblxuZnVuY3Rpb24gc2V0UmVjb3JkaW5nVG9rZW4odG9rZW4pIHtcbiAgICByZWNvcmRpbmdUb2tlbiA9IHRva2VuO1xufVxuXG5mdW5jdGlvbiBzZXRSZWNvcmRpbmcoc3RhdGUsIHRva2VuLCBjYWxsYmFjaywgY29ubmVjdGlvbikge1xuICAgIGlmICh1c2VKaXJlY29uKXtcbiAgICAgICAgc2V0UmVjb3JkaW5nSmlyZWNvbihzdGF0ZSwgdG9rZW4sIGNhbGxiYWNrLCBjb25uZWN0aW9uKTtcbiAgICB9IGVsc2Uge1xuICAgICAgICBzZXRSZWNvcmRpbmdDb2xpYnJpKHN0YXRlLCB0b2tlbiwgY2FsbGJhY2ssIGNvbm5lY3Rpb24pO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gc2V0UmVjb3JkaW5nSmlyZWNvbihzdGF0ZSwgdG9rZW4sIGNhbGxiYWNrLCBjb25uZWN0aW9uKSB7XG4gICAgaWYgKHN0YXRlID09IHJlY29yZGluZ0VuYWJsZWQpe1xuICAgICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgdmFyIGlxID0gJGlxKHt0bzogY29uZmlnLmhvc3RzLmppcmVjb24sIHR5cGU6ICdzZXQnfSlcbiAgICAgICAgLmMoJ3JlY29yZGluZycsIHt4bWxuczogJ2h0dHA6Ly9qaXRzaS5vcmcvcHJvdG9jb2wvamlyZWNvbicsXG4gICAgICAgICAgICBhY3Rpb246IHN0YXRlID8gJ3N0YXJ0JyA6ICdzdG9wJyxcbiAgICAgICAgICAgIG11Y2ppZDogY29ubmVjdGlvbi5lbXVjLnJvb21qaWR9KTtcbiAgICBpZiAoIXN0YXRlKXtcbiAgICAgICAgaXEuYXR0cnMoe3JpZDogamlyZWNvblJpZH0pO1xuICAgIH1cblxuICAgIGNvbnNvbGUubG9nKCdTdGFydCByZWNvcmRpbmcnKTtcblxuICAgIGNvbm5lY3Rpb24uc2VuZElRKFxuICAgICAgICBpcSxcbiAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgLy8gVE9ETyB3YWl0IGZvciBhbiBJUSB3aXRoIHRoZSByZWFsIHN0YXR1cywgc2luY2UgdGhpcyBpc1xuICAgICAgICAgICAgLy8gcHJvdmlzaW9uYWw/XG4gICAgICAgICAgICBqaXJlY29uUmlkID0gJChyZXN1bHQpLmZpbmQoJ3JlY29yZGluZycpLmF0dHIoJ3JpZCcpO1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ1JlY29yZGluZyAnICsgKHN0YXRlID8gJ3N0YXJ0ZWQnIDogJ3N0b3BwZWQnKSArXG4gICAgICAgICAgICAgICAgJyhqaXJlY29uKScgKyByZXN1bHQpO1xuICAgICAgICAgICAgcmVjb3JkaW5nRW5hYmxlZCA9IHN0YXRlO1xuICAgICAgICAgICAgaWYgKCFzdGF0ZSl7XG4gICAgICAgICAgICAgICAgamlyZWNvblJpZCA9IG51bGw7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGNhbGxiYWNrKHN0YXRlKTtcbiAgICAgICAgfSxcbiAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnRmFpbGVkIHRvIHN0YXJ0IHJlY29yZGluZywgZXJyb3I6ICcsIGVycm9yKTtcbiAgICAgICAgICAgIGNhbGxiYWNrKHJlY29yZGluZ0VuYWJsZWQpO1xuICAgICAgICB9KTtcbn1cblxuLy8gU2VuZHMgYSBDT0xJQlJJIG1lc3NhZ2Ugd2hpY2ggZW5hYmxlcyBvciBkaXNhYmxlcyAoYWNjb3JkaW5nIHRvICdzdGF0ZScpXG4vLyB0aGUgcmVjb3JkaW5nIG9uIHRoZSBicmlkZ2UuIFdhaXRzIGZvciB0aGUgcmVzdWx0IElRIGFuZCBjYWxscyAnY2FsbGJhY2snXG4vLyB3aXRoIHRoZSBuZXcgcmVjb3JkaW5nIHN0YXRlLCBhY2NvcmRpbmcgdG8gdGhlIElRLlxuZnVuY3Rpb24gc2V0UmVjb3JkaW5nQ29saWJyaShzdGF0ZSwgdG9rZW4sIGNhbGxiYWNrLCBjb25uZWN0aW9uKSB7XG4gICAgdmFyIGVsZW0gPSAkaXEoe3RvOiBjb25uZWN0aW9uLmVtdWMuZm9jdXNNdWNKaWQsIHR5cGU6ICdzZXQnfSk7XG4gICAgZWxlbS5jKCdjb25mZXJlbmNlJywge1xuICAgICAgICB4bWxuczogJ2h0dHA6Ly9qaXRzaS5vcmcvcHJvdG9jb2wvY29saWJyaSdcbiAgICB9KTtcbiAgICBlbGVtLmMoJ3JlY29yZGluZycsIHtzdGF0ZTogc3RhdGUsIHRva2VuOiB0b2tlbn0pO1xuXG4gICAgY29ubmVjdGlvbi5zZW5kSVEoZWxlbSxcbiAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgY29uc29sZS5sb2coJ1NldCByZWNvcmRpbmcgXCInLCBzdGF0ZSwgJ1wiLiBSZXN1bHQ6JywgcmVzdWx0KTtcbiAgICAgICAgICAgIHZhciByZWNvcmRpbmdFbGVtID0gJChyZXN1bHQpLmZpbmQoJz5jb25mZXJlbmNlPnJlY29yZGluZycpO1xuICAgICAgICAgICAgdmFyIG5ld1N0YXRlID0gKCd0cnVlJyA9PT0gcmVjb3JkaW5nRWxlbS5hdHRyKCdzdGF0ZScpKTtcblxuICAgICAgICAgICAgcmVjb3JkaW5nRW5hYmxlZCA9IG5ld1N0YXRlO1xuICAgICAgICAgICAgY2FsbGJhY2sobmV3U3RhdGUpO1xuICAgICAgICB9LFxuICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgIGNvbnNvbGUud2FybihlcnJvcik7XG4gICAgICAgICAgICBjYWxsYmFjayhyZWNvcmRpbmdFbmFibGVkKTtcbiAgICAgICAgfVxuICAgICk7XG59XG5cbnZhciBSZWNvcmRpbmcgPSB7XG4gICAgdG9nZ2xlUmVjb3JkaW5nOiBmdW5jdGlvbiAodG9rZW5FbXB0eUNhbGxiYWNrLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0YXJ0aW5nQ2FsbGJhY2ssIHN0YXJ0ZWRDYWxsYmFjaywgY29ubmVjdGlvbikge1xuICAgICAgICBpZiAoIU1vZGVyYXRvci5pc01vZGVyYXRvcigpKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcbiAgICAgICAgICAgICAgICAgICAgJ25vbi1mb2N1cywgb3IgY29uZmVyZW5jZSBub3QgeWV0IG9yZ2FuaXplZDonICtcbiAgICAgICAgICAgICAgICAgICAgJyBub3QgZW5hYmxpbmcgcmVjb3JkaW5nJyk7XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cblxuICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgIC8vIEppcmVjb24gZG9lcyBub3QgKGN1cnJlbnRseSkgc3VwcG9ydCBhIHRva2VuLlxuICAgICAgICBpZiAoIXJlY29yZGluZ1Rva2VuICYmICF1c2VKaXJlY29uKSB7XG4gICAgICAgICAgICB0b2tlbkVtcHR5Q2FsbGJhY2soZnVuY3Rpb24gKHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgc2V0UmVjb3JkaW5nVG9rZW4odmFsdWUpO1xuICAgICAgICAgICAgICAgIHNlbGYudG9nZ2xlUmVjb3JkaW5nKCk7XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG5cbiAgICAgICAgdmFyIG9sZFN0YXRlID0gcmVjb3JkaW5nRW5hYmxlZDtcbiAgICAgICAgc3RhcnRpbmdDYWxsYmFjayghb2xkU3RhdGUpO1xuICAgICAgICBzZXRSZWNvcmRpbmcoIW9sZFN0YXRlLFxuICAgICAgICAgICAgcmVjb3JkaW5nVG9rZW4sXG4gICAgICAgICAgICBmdW5jdGlvbiAoc3RhdGUpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhcIk5ldyByZWNvcmRpbmcgc3RhdGU6IFwiLCBzdGF0ZSk7XG4gICAgICAgICAgICAgICAgaWYgKHN0YXRlID09PSBvbGRTdGF0ZSkge1xuICAgICAgICAgICAgICAgICAgICAvLyBGSVhNRTogbmV3IGZvY3VzOlxuICAgICAgICAgICAgICAgICAgICAvLyB0aGlzIHdpbGwgbm90IHdvcmsgd2hlbiBtb2RlcmF0b3IgY2hhbmdlc1xuICAgICAgICAgICAgICAgICAgICAvLyBkdXJpbmcgYWN0aXZlIHNlc3Npb24uIFRoZW4gaXQgd2lsbCBhc3N1bWUgdGhhdFxuICAgICAgICAgICAgICAgICAgICAvLyByZWNvcmRpbmcgc3RhdHVzIGhhcyBjaGFuZ2VkIHRvIHRydWUsIGJ1dCBpdCBtaWdodCBoYXZlXG4gICAgICAgICAgICAgICAgICAgIC8vIGJlZW4gYWxyZWFkeSB0cnVlKGFuZCB3ZSBvbmx5IHJlY2VpdmVkIGFjdHVhbCBzdGF0dXMgZnJvbVxuICAgICAgICAgICAgICAgICAgICAvLyB0aGUgZm9jdXMpLlxuICAgICAgICAgICAgICAgICAgICAvL1xuICAgICAgICAgICAgICAgICAgICAvLyBTTyB3ZSBzdGFydCB3aXRoIHN0YXR1cyBudWxsLCBzbyB0aGF0IGl0IGlzIGluaXRpYWxpemVkXG4gICAgICAgICAgICAgICAgICAgIC8vIGhlcmUgYW5kIHdpbGwgZmFpbCBvbmx5IGFmdGVyIHNlY29uZCBjbGljaywgc28gaWYgaW52YWxpZFxuICAgICAgICAgICAgICAgICAgICAvLyB0b2tlbiB3YXMgdXNlZCB3ZSBoYXZlIHRvIHByZXNzIHRoZSBidXR0b24gdHdpY2UgYmVmb3JlXG4gICAgICAgICAgICAgICAgICAgIC8vIGN1cnJlbnQgc3RhdHVzIHdpbGwgYmUgZmV0Y2hlZCBhbmQgdG9rZW4gd2lsbCBiZSByZXNldC5cbiAgICAgICAgICAgICAgICAgICAgLy9cbiAgICAgICAgICAgICAgICAgICAgLy8gUmVsaWFibGUgd2F5IHdvdWxkIGJlIHRvIHJldHVybiBhdXRoZW50aWNhdGlvbiBlcnJvci5cbiAgICAgICAgICAgICAgICAgICAgLy8gT3Igc3RhdHVzIHVwZGF0ZSB3aGVuIG1vZGVyYXRvciBjb25uZWN0cy5cbiAgICAgICAgICAgICAgICAgICAgLy8gT3Igd2UgaGF2ZSB0byBzdG9wIHJlY29yZGluZyBzZXNzaW9uIHdoZW4gY3VycmVudFxuICAgICAgICAgICAgICAgICAgICAvLyBtb2RlcmF0b3IgbGVhdmVzIHRoZSByb29tLlxuXG4gICAgICAgICAgICAgICAgICAgIC8vIEZhaWxlZCB0byBjaGFuZ2UsIHJlc2V0IHRoZSB0b2tlbiBiZWNhdXNlIGl0IG1pZ2h0XG4gICAgICAgICAgICAgICAgICAgIC8vIGhhdmUgYmVlbiB3cm9uZ1xuICAgICAgICAgICAgICAgICAgICBzZXRSZWNvcmRpbmdUb2tlbihudWxsKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgc3RhcnRlZENhbGxiYWNrKHN0YXRlKTtcblxuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGNvbm5lY3Rpb25cbiAgICAgICAgKTtcbiAgICB9XG5cbn1cblxubW9kdWxlLmV4cG9ydHMgPSBSZWNvcmRpbmc7IiwiLyoganNoaW50IC1XMTE3ICovXG4vKiBhIHNpbXBsZSBNVUMgY29ubmVjdGlvbiBwbHVnaW5cbiAqIGNhbiBvbmx5IGhhbmRsZSBhIHNpbmdsZSBNVUMgcm9vbVxuICovXG52YXIgWE1QUEV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL3htcHAvWE1QUEV2ZW50c1wiKTtcbnZhciBNb2RlcmF0b3IgPSByZXF1aXJlKFwiLi9tb2RlcmF0b3JcIik7XG52YXIgSmluZ2xlU2Vzc2lvbiA9IHJlcXVpcmUoXCIuL0ppbmdsZVNlc3Npb25cIik7XG5cbnZhciBicmlkZ2VJc0Rvd24gPSBmYWxzZTtcblxubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbihYTVBQLCBldmVudEVtaXR0ZXIpIHtcbiAgICBTdHJvcGhlLmFkZENvbm5lY3Rpb25QbHVnaW4oJ2VtdWMnLCB7XG4gICAgICAgIGNvbm5lY3Rpb246IG51bGwsXG4gICAgICAgIHJvb21qaWQ6IG51bGwsXG4gICAgICAgIG15cm9vbWppZDogbnVsbCxcbiAgICAgICAgbWVtYmVyczoge30sXG4gICAgICAgIGxpc3RfbWVtYmVyczogW10sIC8vIHNvIHdlIGNhbiBlbGVjdCBhIG5ldyBmb2N1c1xuICAgICAgICBwcmVzTWFwOiB7fSxcbiAgICAgICAgcHJlemlNYXA6IHt9LFxuICAgICAgICBqb2luZWQ6IGZhbHNlLFxuICAgICAgICBpc093bmVyOiBmYWxzZSxcbiAgICAgICAgcm9sZTogbnVsbCxcbiAgICAgICAgZm9jdXNNdWNKaWQ6IG51bGwsXG4gICAgICAgIHNzcmMyamlkOiB7fSxcbiAgICAgICAgaW5pdDogZnVuY3Rpb24gKGNvbm4pIHtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbiA9IGNvbm47XG4gICAgICAgIH0sXG4gICAgICAgIGluaXRQcmVzZW5jZU1hcDogZnVuY3Rpb24gKG15cm9vbWppZCkge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWyd0byddID0gbXlyb29tamlkO1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWyd4bnMnXSA9ICdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMnO1xuICAgICAgICB9LFxuICAgICAgICBkb0pvaW46IGZ1bmN0aW9uIChqaWQsIHBhc3N3b3JkKSB7XG4gICAgICAgICAgICB0aGlzLm15cm9vbWppZCA9IGppZDtcblxuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwiSm9pbmVkIE1VQyBhcyBcIiArIHRoaXMubXlyb29tamlkKTtcblxuICAgICAgICAgICAgdGhpcy5pbml0UHJlc2VuY2VNYXAodGhpcy5teXJvb21qaWQpO1xuXG4gICAgICAgICAgICBpZiAoIXRoaXMucm9vbWppZCkge1xuICAgICAgICAgICAgICAgIHRoaXMucm9vbWppZCA9IFN0cm9waGUuZ2V0QmFyZUppZEZyb21KaWQoamlkKTtcbiAgICAgICAgICAgICAgICAvLyBhZGQgaGFuZGxlcnMgKGp1c3Qgb25jZSlcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uYWRkSGFuZGxlcih0aGlzLm9uUHJlc2VuY2UuYmluZCh0aGlzKSwgbnVsbCwgJ3ByZXNlbmNlJywgbnVsbCwgbnVsbCwgdGhpcy5yb29tamlkLCB7bWF0Y2hCYXJlOiB0cnVlfSk7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmFkZEhhbmRsZXIodGhpcy5vblByZXNlbmNlVW5hdmFpbGFibGUuYmluZCh0aGlzKSwgbnVsbCwgJ3ByZXNlbmNlJywgJ3VuYXZhaWxhYmxlJywgbnVsbCwgdGhpcy5yb29tamlkLCB7bWF0Y2hCYXJlOiB0cnVlfSk7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmFkZEhhbmRsZXIodGhpcy5vblByZXNlbmNlRXJyb3IuYmluZCh0aGlzKSwgbnVsbCwgJ3ByZXNlbmNlJywgJ2Vycm9yJywgbnVsbCwgdGhpcy5yb29tamlkLCB7bWF0Y2hCYXJlOiB0cnVlfSk7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmFkZEhhbmRsZXIodGhpcy5vbk1lc3NhZ2UuYmluZCh0aGlzKSwgbnVsbCwgJ21lc3NhZ2UnLCBudWxsLCBudWxsLCB0aGlzLnJvb21qaWQsIHttYXRjaEJhcmU6IHRydWV9KTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChwYXNzd29yZCAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydwYXNzd29yZCddID0gcGFzc3dvcmQ7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB0aGlzLnNlbmRQcmVzZW5jZSgpO1xuICAgICAgICB9LFxuICAgICAgICBkb0xlYXZlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBjb25zb2xlLmxvZyhcImRvIGxlYXZlXCIsIHRoaXMubXlyb29tamlkKTtcbiAgICAgICAgICAgIHZhciBwcmVzID0gJHByZXMoe3RvOiB0aGlzLm15cm9vbWppZCwgdHlwZTogJ3VuYXZhaWxhYmxlJyB9KTtcbiAgICAgICAgICAgIHRoaXMucHJlc01hcC5sZW5ndGggPSAwO1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmQocHJlcyk7XG4gICAgICAgIH0sXG4gICAgICAgIGNyZWF0ZU5vbkFub255bW91c1Jvb206IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgIC8vIGh0dHA6Ly94bXBwLm9yZy9leHRlbnNpb25zL3hlcC0wMDQ1Lmh0bWwjY3JlYXRlcm9vbS1yZXNlcnZlZFxuXG4gICAgICAgICAgICB2YXIgZ2V0Rm9ybSA9ICRpcSh7dHlwZTogJ2dldCcsIHRvOiB0aGlzLnJvb21qaWR9KVxuICAgICAgICAgICAgICAgIC5jKCdxdWVyeScsIHt4bWxuczogJ2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211YyNvd25lcid9KVxuICAgICAgICAgICAgICAgIC5jKCd4Jywge3htbG5zOiAnamFiYmVyOng6ZGF0YScsIHR5cGU6ICdzdWJtaXQnfSk7XG5cbiAgICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcblxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmRJUShnZXRGb3JtLCBmdW5jdGlvbiAoZm9ybSkge1xuXG4gICAgICAgICAgICAgICAgaWYgKCEkKGZvcm0pLmZpbmQoXG4gICAgICAgICAgICAgICAgICAgICAgICAnPnF1ZXJ5PnhbeG1sbnM9XCJqYWJiZXI6eDpkYXRhXCJdJyArXG4gICAgICAgICAgICAgICAgICAgICAgICAnPmZpZWxkW3Zhcj1cIm11YyNyb29tY29uZmlnX3dob2lzXCJdJykubGVuZ3RoKSB7XG5cbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcignbm9uLWFub255bW91cyByb29tcyBub3Qgc3VwcG9ydGVkJyk7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybjtcbiAgICAgICAgICAgICAgICB9XG5cbiAgICAgICAgICAgICAgICB2YXIgZm9ybVN1Ym1pdCA9ICRpcSh7dG86IHRoaXMucm9vbWppZCwgdHlwZTogJ3NldCd9KVxuICAgICAgICAgICAgICAgICAgICAuYygncXVlcnknLCB7eG1sbnM6ICdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjb3duZXInfSk7XG5cbiAgICAgICAgICAgICAgICBmb3JtU3VibWl0LmMoJ3gnLCB7eG1sbnM6ICdqYWJiZXI6eDpkYXRhJywgdHlwZTogJ3N1Ym1pdCd9KTtcblxuICAgICAgICAgICAgICAgIGZvcm1TdWJtaXQuYygnZmllbGQnLCB7J3Zhcic6ICdGT1JNX1RZUEUnfSlcbiAgICAgICAgICAgICAgICAgICAgLmMoJ3ZhbHVlJylcbiAgICAgICAgICAgICAgICAgICAgLnQoJ2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211YyNyb29tY29uZmlnJykudXAoKS51cCgpO1xuXG4gICAgICAgICAgICAgICAgZm9ybVN1Ym1pdC5jKCdmaWVsZCcsIHsndmFyJzogJ211YyNyb29tY29uZmlnX3dob2lzJ30pXG4gICAgICAgICAgICAgICAgICAgIC5jKCd2YWx1ZScpLnQoJ2FueW9uZScpLnVwKCkudXAoKTtcblxuICAgICAgICAgICAgICAgIHNlbGYuY29ubmVjdGlvbi5zZW5kSVEoZm9ybVN1Ym1pdCk7XG5cbiAgICAgICAgICAgIH0sIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuZXJyb3IoXCJFcnJvciBnZXR0aW5nIHJvb20gY29uZmlndXJhdGlvbiBmb3JtXCIpO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG4gICAgICAgIG9uUHJlc2VuY2U6IGZ1bmN0aW9uIChwcmVzKSB7XG4gICAgICAgICAgICB2YXIgZnJvbSA9IHByZXMuZ2V0QXR0cmlidXRlKCdmcm9tJyk7XG5cbiAgICAgICAgICAgIC8vIFdoYXQgaXMgdGhpcyBmb3I/IEEgd29ya2Fyb3VuZCBmb3Igc29tZXRoaW5nP1xuICAgICAgICAgICAgaWYgKHByZXMuZ2V0QXR0cmlidXRlKCd0eXBlJykpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gUGFyc2UgZXRoZXJwYWQgdGFnLlxuICAgICAgICAgICAgdmFyIGV0aGVycGFkID0gJChwcmVzKS5maW5kKCc+ZXRoZXJwYWQnKTtcbiAgICAgICAgICAgIGlmIChldGhlcnBhZC5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBpZiAoY29uZmlnLmV0aGVycGFkX2Jhc2UgJiYgIU1vZGVyYXRvci5pc01vZGVyYXRvcigpKSB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuRVRIRVJQQUQsIGV0aGVycGFkLnRleHQoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBQYXJzZSBwcmV6aSB0YWcuXG4gICAgICAgICAgICB2YXIgcHJlc2VudGF0aW9uID0gJChwcmVzKS5maW5kKCc+cHJlemknKTtcbiAgICAgICAgICAgIGlmIChwcmVzZW50YXRpb24ubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdmFyIHVybCA9IHByZXNlbnRhdGlvbi5hdHRyKCd1cmwnKTtcbiAgICAgICAgICAgICAgICB2YXIgY3VycmVudCA9IHByZXNlbnRhdGlvbi5maW5kKCc+Y3VycmVudCcpLnRleHQoKTtcblxuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdwcmVzZW50YXRpb24gaW5mbyByZWNlaXZlZCBmcm9tJywgZnJvbSwgdXJsKTtcblxuICAgICAgICAgICAgICAgIGlmICh0aGlzLnByZXppTWFwW2Zyb21dID09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5wcmV6aU1hcFtmcm9tXSA9IHVybDtcblxuICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdwcmVzZW50YXRpb25hZGRlZC5tdWMnLCBbZnJvbSwgdXJsLCBjdXJyZW50XSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdnb3Rvc2xpZGUubXVjJywgW2Zyb20sIHVybCwgY3VycmVudF0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGVsc2UgaWYgKHRoaXMucHJlemlNYXBbZnJvbV0gIT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHZhciB1cmwgPSB0aGlzLnByZXppTWFwW2Zyb21dO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnByZXppTWFwW2Zyb21dO1xuICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ3ByZXNlbnRhdGlvbnJlbW92ZWQubXVjJywgW2Zyb20sIHVybF0pO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBQYXJzZSBhdWRpbyBpbmZvIHRhZy5cbiAgICAgICAgICAgIHZhciBhdWRpb011dGVkID0gJChwcmVzKS5maW5kKCc+YXVkaW9tdXRlZCcpO1xuICAgICAgICAgICAgaWYgKGF1ZGlvTXV0ZWQubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignYXVkaW9tdXRlZC5tdWMnLCBbZnJvbSwgYXVkaW9NdXRlZC50ZXh0KCldKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gUGFyc2UgdmlkZW8gaW5mbyB0YWcuXG4gICAgICAgICAgICB2YXIgdmlkZW9NdXRlZCA9ICQocHJlcykuZmluZCgnPnZpZGVvbXV0ZWQnKTtcbiAgICAgICAgICAgIGlmICh2aWRlb011dGVkLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ3ZpZGVvbXV0ZWQubXVjJywgW2Zyb20sIHZpZGVvTXV0ZWQudGV4dCgpXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBzdGF0cyA9ICQocHJlcykuZmluZCgnPnN0YXRzJyk7XG4gICAgICAgICAgICBpZiAoc3RhdHMubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdmFyIHN0YXRzT2JqID0ge307XG4gICAgICAgICAgICAgICAgU3Ryb3BoZS5mb3JFYWNoQ2hpbGQoc3RhdHNbMF0sIFwic3RhdFwiLCBmdW5jdGlvbiAoZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgc3RhdHNPYmpbZWwuZ2V0QXR0cmlidXRlKFwibmFtZVwiKV0gPSBlbC5nZXRBdHRyaWJ1dGUoXCJ2YWx1ZVwiKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLlJFTU9URV9TVEFUUywgZnJvbSwgc3RhdHNPYmopO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAvLyBQYXJzZSBzdGF0dXMuXG4gICAgICAgICAgICBpZiAoJChwcmVzKS5maW5kKCc+eFt4bWxucz1cImh0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211YyN1c2VyXCJdPnN0YXR1c1tjb2RlPVwiMjAxXCJdJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5pc093bmVyID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB0aGlzLmNyZWF0ZU5vbkFub255bW91c1Jvb20oKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgLy8gUGFyc2Ugcm9sZXMuXG4gICAgICAgICAgICB2YXIgbWVtYmVyID0ge307XG4gICAgICAgICAgICBtZW1iZXIuc2hvdyA9ICQocHJlcykuZmluZCgnPnNob3cnKS50ZXh0KCk7XG4gICAgICAgICAgICBtZW1iZXIuc3RhdHVzID0gJChwcmVzKS5maW5kKCc+c3RhdHVzJykudGV4dCgpO1xuICAgICAgICAgICAgdmFyIHRtcCA9ICQocHJlcykuZmluZCgnPnhbeG1sbnM9XCJodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjdXNlclwiXT5pdGVtJyk7XG4gICAgICAgICAgICBtZW1iZXIuYWZmaWxpYXRpb24gPSB0bXAuYXR0cignYWZmaWxpYXRpb24nKTtcbiAgICAgICAgICAgIG1lbWJlci5yb2xlID0gdG1wLmF0dHIoJ3JvbGUnKTtcblxuICAgICAgICAgICAgLy8gRm9jdXMgcmVjb2duaXRpb25cbiAgICAgICAgICAgIG1lbWJlci5qaWQgPSB0bXAuYXR0cignamlkJyk7XG4gICAgICAgICAgICBtZW1iZXIuaXNGb2N1cyA9IGZhbHNlO1xuICAgICAgICAgICAgaWYgKG1lbWJlci5qaWRcbiAgICAgICAgICAgICAgICAmJiBtZW1iZXIuamlkLmluZGV4T2YoTW9kZXJhdG9yLmdldEZvY3VzVXNlckppZCgpICsgXCIvXCIpID09IDApIHtcbiAgICAgICAgICAgICAgICBtZW1iZXIuaXNGb2N1cyA9IHRydWU7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHZhciBuaWNrdGFnID0gJChwcmVzKS5maW5kKCc+bmlja1t4bWxucz1cImh0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL25pY2tcIl0nKTtcbiAgICAgICAgICAgIG1lbWJlci5kaXNwbGF5TmFtZSA9IChuaWNrdGFnLmxlbmd0aCA+IDAgPyBuaWNrdGFnLmh0bWwoKSA6IG51bGwpO1xuXG4gICAgICAgICAgICBpZiAoZnJvbSA9PSB0aGlzLm15cm9vbWppZCkge1xuICAgICAgICAgICAgICAgIGlmIChtZW1iZXIuYWZmaWxpYXRpb24gPT0gJ293bmVyJykgdGhpcy5pc093bmVyID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5yb2xlICE9PSBtZW1iZXIucm9sZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLnJvbGUgPSBtZW1iZXIucm9sZTtcblxuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLkxPQ0FMUk9MRV9DSEFOR0VELFxuICAgICAgICAgICAgICAgICAgICAgICAgZnJvbSwgbWVtYmVyLCBwcmVzLCBNb2RlcmF0b3IuaXNNb2RlcmF0b3IoKSxcbiAgICAgICAgICAgICAgICAgICAgICAgIE1vZGVyYXRvci5pc0V4dGVybmFsQXV0aEVuYWJsZWQoKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmICghdGhpcy5qb2luZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5qb2luZWQgPSB0cnVlO1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLk1VQ19KT0lORUQsIGZyb20sIG1lbWJlcik7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMubGlzdF9tZW1iZXJzLnB1c2goZnJvbSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLm1lbWJlcnNbZnJvbV0gPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIC8vIG5ldyBwYXJ0aWNpcGFudFxuICAgICAgICAgICAgICAgIHRoaXMubWVtYmVyc1tmcm9tXSA9IG1lbWJlcjtcbiAgICAgICAgICAgICAgICB0aGlzLmxpc3RfbWVtYmVycy5wdXNoKGZyb20pO1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdlbnRlcmVkJywgZnJvbSwgbWVtYmVyKTtcbiAgICAgICAgICAgICAgICBpZiAobWVtYmVyLmlzRm9jdXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5mb2N1c011Y0ppZCA9IGZyb207XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIklnbm9yZSBmb2N1czogXCIgKyBmcm9tICsgXCIsIHJlYWwgSklEOiBcIiArIG1lbWJlci5qaWQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGlkID0gJChwcmVzKS5maW5kKCc+dXNlcklEJykudGV4dCgpO1xuICAgICAgICAgICAgICAgICAgICB2YXIgZW1haWwgPSAkKHByZXMpLmZpbmQoJz5lbWFpbCcpO1xuICAgICAgICAgICAgICAgICAgICBpZiAoZW1haWwubGVuZ3RoID4gMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWQgPSBlbWFpbC50ZXh0KCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoWE1QUEV2ZW50cy5NVUNfRU5URVIsIGZyb20sIGlkLCBtZW1iZXIuZGlzcGxheU5hbWUpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgLy8gUHJlc2VuY2UgdXBkYXRlIGZvciBleGlzdGluZyBwYXJ0aWNpcGFudFxuICAgICAgICAgICAgICAgIC8vIFdhdGNoIHJvbGUgY2hhbmdlOlxuICAgICAgICAgICAgICAgIGlmICh0aGlzLm1lbWJlcnNbZnJvbV0ucm9sZSAhPSBtZW1iZXIucm9sZSkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLm1lbWJlcnNbZnJvbV0ucm9sZSA9IG1lbWJlci5yb2xlO1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLk1VQ19ST0xFX0NIQU5HRUQsXG4gICAgICAgICAgICAgICAgICAgICAgICBtZW1iZXIucm9sZSwgbWVtYmVyLmRpc3BsYXlOYW1lKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIC8vIEFsd2F5cyB0cmlnZ2VyIHByZXNlbmNlIHRvIHVwZGF0ZSBiaW5kaW5nc1xuICAgICAgICAgICAgdGhpcy5wYXJzZVByZXNlbmNlKGZyb20sIG1lbWJlciwgcHJlcyk7XG5cbiAgICAgICAgICAgIC8vIFRyaWdnZXIgc3RhdHVzIG1lc3NhZ2UgdXBkYXRlXG4gICAgICAgICAgICBpZiAobWVtYmVyLnN0YXR1cykge1xuICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuUFJFU0VOQ0VfU1RBVFVTLCBmcm9tLCBtZW1iZXIpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgb25QcmVzZW5jZVVuYXZhaWxhYmxlOiBmdW5jdGlvbiAocHJlcykge1xuICAgICAgICAgICAgdmFyIGZyb20gPSBwcmVzLmdldEF0dHJpYnV0ZSgnZnJvbScpO1xuICAgICAgICAgICAgLy8gU3RhdHVzIGNvZGUgMTEwIGluZGljYXRlcyB0aGF0IHRoaXMgbm90aWZpY2F0aW9uIGlzIFwic2VsZi1wcmVzZW5jZVwiLlxuICAgICAgICAgICAgaWYgKCEkKHByZXMpLmZpbmQoJz54W3htbG5zPVwiaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvbXVjI3VzZXJcIl0+c3RhdHVzW2NvZGU9XCIxMTBcIl0nKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5tZW1iZXJzW2Zyb21dO1xuICAgICAgICAgICAgICAgIHRoaXMubGlzdF9tZW1iZXJzLnNwbGljZSh0aGlzLmxpc3RfbWVtYmVycy5pbmRleE9mKGZyb20pLCAxKTtcbiAgICAgICAgICAgICAgICB0aGlzLm9uUGFydGljaXBhbnRMZWZ0KGZyb20pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gSWYgdGhlIHN0YXR1cyBjb2RlIGlzIDExMCB0aGlzIG1lYW5zIHdlJ3JlIGxlYXZpbmcgYW5kIHdlIHdvdWxkIGxpa2VcbiAgICAgICAgICAgIC8vIHRvIHJlbW92ZSBldmVyeW9uZSBlbHNlIGZyb20gb3VyIHZpZXcsIHNvIHdlIHRyaWdnZXIgdGhlIGV2ZW50LlxuICAgICAgICAgICAgZWxzZSBpZiAodGhpcy5saXN0X21lbWJlcnMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGkgPSAwOyBpIDwgdGhpcy5saXN0X21lbWJlcnMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIG1lbWJlciA9IHRoaXMubGlzdF9tZW1iZXJzW2ldO1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5tZW1iZXJzW2ldO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmxpc3RfbWVtYmVycy5zcGxpY2UoaSwgMSk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMub25QYXJ0aWNpcGFudExlZnQobWVtYmVyKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAoJChwcmVzKS5maW5kKCc+eFt4bWxucz1cImh0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211YyN1c2VyXCJdPnN0YXR1c1tjb2RlPVwiMzA3XCJdJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcigna2lja2VkLm11YycsIFtmcm9tXSk7XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMubXlyb29tamlkID09PSBmcm9tKSB7XG4gICAgICAgICAgICAgICAgICAgIFhNUFAuZGlzcG9zZUNvbmZlcmVuY2UoZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLktJQ0tFRCk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0sXG4gICAgICAgIG9uUHJlc2VuY2VFcnJvcjogZnVuY3Rpb24gKHByZXMpIHtcbiAgICAgICAgICAgIHZhciBmcm9tID0gcHJlcy5nZXRBdHRyaWJ1dGUoJ2Zyb20nKTtcbiAgICAgICAgICAgIGlmICgkKHByZXMpLmZpbmQoJz5lcnJvclt0eXBlPVwiYXV0aFwiXT5ub3QtYXV0aG9yaXplZFt4bWxucz1cInVybjppZXRmOnBhcmFtczp4bWw6bnM6eG1wcC1zdGFuemFzXCJdJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ29uIHBhc3N3b3JkIHJlcXVpcmVkJywgZnJvbSk7XG4gICAgICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuUEFTU1dPUkRfUkVRVUlSRUQsIGZ1bmN0aW9uICh2YWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICBzZWxmLmRvSm9pbihmcm9tLCB2YWx1ZSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKCQocHJlcykuZmluZChcbiAgICAgICAgICAgICAgICAnPmVycm9yW3R5cGU9XCJjYW5jZWxcIl0+bm90LWFsbG93ZWRbeG1sbnM9XCJ1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOnhtcHAtc3Rhbnphc1wiXScpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciB0b0RvbWFpbiA9IFN0cm9waGUuZ2V0RG9tYWluRnJvbUppZChwcmVzLmdldEF0dHJpYnV0ZSgndG8nKSk7XG4gICAgICAgICAgICAgICAgaWYgKHRvRG9tYWluID09PSBjb25maWcuaG9zdHMuYW5vbnltb3VzZG9tYWluKSB7XG4gICAgICAgICAgICAgICAgICAgIC8vIGVudGVyIHRoZSByb29tIGJ5IHJlcGx5aW5nIHdpdGggJ25vdC1hdXRob3JpemVkJy4gVGhpcyB3b3VsZFxuICAgICAgICAgICAgICAgICAgICAvLyByZXN1bHQgaW4gcmVjb25uZWN0aW9uIGZyb20gYXV0aG9yaXplZCBkb21haW4uXG4gICAgICAgICAgICAgICAgICAgIC8vIFdlJ3JlIGVpdGhlciBtaXNzaW5nIEppY29mby9Qcm9zb2R5IGNvbmZpZyBmb3IgYW5vbnltb3VzXG4gICAgICAgICAgICAgICAgICAgIC8vIGRvbWFpbnMgb3Igc29tZXRoaW5nIGlzIHdyb25nLlxuLy8gICAgICAgICAgICAgICAgICAgIFhNUFAucHJvbXB0TG9naW4oKTtcbiAgICAgICAgICAgICAgICAgICAgQVBQLlVJLm1lc3NhZ2VIYW5kbGVyLm9wZW5SZXBvcnREaWFsb2cobnVsbCxcbiAgICAgICAgICAgICAgICAgICAgICAgICdPb3BzICEgV2UgY291bGRuYHQgam9pbiB0aGUgY29uZmVyZW5jZS4nICtcbiAgICAgICAgICAgICAgICAgICAgICAgICcgVGhlcmUgbWlnaHQgYmUgc29tZSBwcm9ibGVtIHdpdGggc2VjdXJpdHknICtcbiAgICAgICAgICAgICAgICAgICAgICAgICcgY29uZmlndXJhdGlvbi4gUGxlYXNlIGNvbnRhY3Qgc2VydmljZScgK1xuICAgICAgICAgICAgICAgICAgICAgICAgJyBhZG1pbmlzdHJhdG9yLicsIHByZXMpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUud2Fybignb25QcmVzRXJyb3IgJywgcHJlcyk7XG4gICAgICAgICAgICAgICAgICAgIEFQUC5VSS5tZXNzYWdlSGFuZGxlci5vcGVuUmVwb3J0RGlhbG9nKG51bGwsXG4gICAgICAgICAgICAgICAgICAgICAgICAnT29wcyEgU29tZXRoaW5nIHdlbnQgd3JvbmcgYW5kIHdlIGNvdWxkbmB0IGNvbm5lY3QgdG8gdGhlIGNvbmZlcmVuY2UuJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZXMpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdvblByZXNFcnJvciAnLCBwcmVzKTtcbiAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIub3BlblJlcG9ydERpYWxvZyhudWxsLFxuICAgICAgICAgICAgICAgICAgICAnT29wcyEgU29tZXRoaW5nIHdlbnQgd3JvbmcgYW5kIHdlIGNvdWxkbmB0IGNvbm5lY3QgdG8gdGhlIGNvbmZlcmVuY2UuJyxcbiAgICAgICAgICAgICAgICAgICAgcHJlcyk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgc2VuZE1lc3NhZ2U6IGZ1bmN0aW9uIChib2R5LCBuaWNrbmFtZSkge1xuICAgICAgICAgICAgdmFyIG1zZyA9ICRtc2coe3RvOiB0aGlzLnJvb21qaWQsIHR5cGU6ICdncm91cGNoYXQnfSk7XG4gICAgICAgICAgICBtc2cuYygnYm9keScsIGJvZHkpLnVwKCk7XG4gICAgICAgICAgICBpZiAobmlja25hbWUpIHtcbiAgICAgICAgICAgICAgICBtc2cuYygnbmljaycsIHt4bWxuczogJ2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL25pY2snfSkudChuaWNrbmFtZSkudXAoKS51cCgpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmQobXNnKTtcbiAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuU0VORElOR19DSEFUX01FU1NBR0UsIGJvZHkpO1xuICAgICAgICB9LFxuICAgICAgICBzZXRTdWJqZWN0OiBmdW5jdGlvbiAoc3ViamVjdCkge1xuICAgICAgICAgICAgdmFyIG1zZyA9ICRtc2coe3RvOiB0aGlzLnJvb21qaWQsIHR5cGU6ICdncm91cGNoYXQnfSk7XG4gICAgICAgICAgICBtc2cuYygnc3ViamVjdCcsIHN1YmplY3QpO1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmQobXNnKTtcbiAgICAgICAgICAgIGNvbnNvbGUubG9nKFwidG9waWMgY2hhbmdlZCB0byBcIiArIHN1YmplY3QpO1xuICAgICAgICB9LFxuICAgICAgICBvbk1lc3NhZ2U6IGZ1bmN0aW9uIChtc2cpIHtcbiAgICAgICAgICAgIC8vIEZJWE1FOiB0aGlzIGlzIGEgaGFjay4gYnV0IGppbmdsZSBvbiBtdWMgbWFrZXMgbmlja2NoYW5nZXMgaGFyZFxuICAgICAgICAgICAgdmFyIGZyb20gPSBtc2cuZ2V0QXR0cmlidXRlKCdmcm9tJyk7XG4gICAgICAgICAgICB2YXIgbmljayA9XG4gICAgICAgICAgICAgICAgJChtc2cpLmZpbmQoJz5uaWNrW3htbG5zPVwiaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvbmlja1wiXScpXG4gICAgICAgICAgICAgICAgICAgIC50ZXh0KCkgfHxcbiAgICAgICAgICAgICAgICBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChmcm9tKTtcblxuICAgICAgICAgICAgdmFyIHR4dCA9ICQobXNnKS5maW5kKCc+Ym9keScpLnRleHQoKTtcbiAgICAgICAgICAgIHZhciB0eXBlID0gbXNnLmdldEF0dHJpYnV0ZShcInR5cGVcIik7XG4gICAgICAgICAgICBpZiAodHlwZSA9PSBcImVycm9yXCIpIHtcbiAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLkNIQVRfRVJST1JfUkVDRUlWRUQsXG4gICAgICAgICAgICAgICAgICAgICQobXNnKS5maW5kKCc+dGV4dCcpLnRleHQoKSwgdHh0KTtcbiAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgdmFyIHN1YmplY3QgPSAkKG1zZykuZmluZCgnPnN1YmplY3QnKTtcbiAgICAgICAgICAgIGlmIChzdWJqZWN0Lmxlbmd0aCkge1xuICAgICAgICAgICAgICAgIHZhciBzdWJqZWN0VGV4dCA9IHN1YmplY3QudGV4dCgpO1xuICAgICAgICAgICAgICAgIGlmIChzdWJqZWN0VGV4dCB8fCBzdWJqZWN0VGV4dCA9PSBcIlwiKSB7XG4gICAgICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuU1VCSkVDVF9DSEFOR0VELCBzdWJqZWN0VGV4dCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiU3ViamVjdCBpcyBjaGFuZ2VkIHRvIFwiICsgc3ViamVjdFRleHQpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cblxuXG4gICAgICAgICAgICBpZiAodHh0KSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ2NoYXQnLCBuaWNrLCB0eHQpO1xuICAgICAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuTUVTU0FHRV9SRUNFSVZFRCxcbiAgICAgICAgICAgICAgICAgICAgZnJvbSwgbmljaywgdHh0LCB0aGlzLm15cm9vbWppZCk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgbG9ja1Jvb206IGZ1bmN0aW9uIChrZXksIG9uU3VjY2Vzcywgb25FcnJvciwgb25Ob3RTdXBwb3J0ZWQpIHtcbiAgICAgICAgICAgIC8vaHR0cDovL3htcHAub3JnL2V4dGVuc2lvbnMveGVwLTAwNDUuaHRtbCNyb29tY29uZmlnXG4gICAgICAgICAgICB2YXIgb2IgPSB0aGlzO1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmRJUSgkaXEoe3RvOiB0aGlzLnJvb21qaWQsIHR5cGU6ICdnZXQnfSkuYygncXVlcnknLCB7eG1sbnM6ICdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjb3duZXInfSksXG4gICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlcykge1xuICAgICAgICAgICAgICAgICAgICBpZiAoJChyZXMpLmZpbmQoJz5xdWVyeT54W3htbG5zPVwiamFiYmVyOng6ZGF0YVwiXT5maWVsZFt2YXI9XCJtdWMjcm9vbWNvbmZpZ19yb29tc2VjcmV0XCJdJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZm9ybXN1Ym1pdCA9ICRpcSh7dG86IG9iLnJvb21qaWQsIHR5cGU6ICdzZXQnfSkuYygncXVlcnknLCB7eG1sbnM6ICdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjb3duZXInfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICBmb3Jtc3VibWl0LmMoJ3gnLCB7eG1sbnM6ICdqYWJiZXI6eDpkYXRhJywgdHlwZTogJ3N1Ym1pdCd9KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1zdWJtaXQuYygnZmllbGQnLCB7J3Zhcic6ICdGT1JNX1RZUEUnfSkuYygndmFsdWUnKS50KCdodHRwOi8vamFiYmVyLm9yZy9wcm90b2NvbC9tdWMjcm9vbWNvbmZpZycpLnVwKCkudXAoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1zdWJtaXQuYygnZmllbGQnLCB7J3Zhcic6ICdtdWMjcm9vbWNvbmZpZ19yb29tc2VjcmV0J30pLmMoJ3ZhbHVlJykudChrZXkpLnVwKCkudXAoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZpeGVzIGEgYnVnIGluIHByb3NvZHkgMC45LisgaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9seG1wcGQvaXNzdWVzL2RldGFpbD9pZD0zNzNcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvcm1zdWJtaXQuYygnZmllbGQnLCB7J3Zhcic6ICdtdWMjcm9vbWNvbmZpZ193aG9pcyd9KS5jKCd2YWx1ZScpLnQoJ2FueW9uZScpLnVwKCkudXAoKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIEZJWE1FOiBpcyBtdWMjcm9vbWNvbmZpZ19wYXNzd29yZHByb3RlY3RlZHJvb20gcmVxdWlyZWQ/XG4gICAgICAgICAgICAgICAgICAgICAgICBvYi5jb25uZWN0aW9uLnNlbmRJUShmb3Jtc3VibWl0LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIG9uU3VjY2VzcyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvbkVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uTm90U3VwcG9ydGVkKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9LCBvbkVycm9yKTtcbiAgICAgICAgfSxcbiAgICAgICAga2ljazogZnVuY3Rpb24gKGppZCkge1xuICAgICAgICAgICAgdmFyIGtpY2tJUSA9ICRpcSh7dG86IHRoaXMucm9vbWppZCwgdHlwZTogJ3NldCd9KVxuICAgICAgICAgICAgICAgIC5jKCdxdWVyeScsIHt4bWxuczogJ2h0dHA6Ly9qYWJiZXIub3JnL3Byb3RvY29sL211YyNhZG1pbid9KVxuICAgICAgICAgICAgICAgIC5jKCdpdGVtJywge25pY2s6IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGppZCksIHJvbGU6ICdub25lJ30pXG4gICAgICAgICAgICAgICAgLmMoJ3JlYXNvbicpLnQoJ1lvdSBoYXZlIGJlZW4ga2lja2VkLicpLnVwKCkudXAoKS51cCgpO1xuXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZElRKFxuICAgICAgICAgICAgICAgIGtpY2tJUSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdLaWNrIHBhcnRpY2lwYW50IHdpdGggamlkOiAnLCBqaWQsIHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ0tpY2sgcGFydGljaXBhbnQgZXJyb3I6ICcsIGVycm9yKTtcbiAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgfSxcbiAgICAgICAgc2VuZFByZXNlbmNlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgcHJlcyA9ICRwcmVzKHt0bzogdGhpcy5wcmVzTWFwWyd0byddIH0pO1xuICAgICAgICAgICAgcHJlcy5jKCd4Jywge3htbG5zOiB0aGlzLnByZXNNYXBbJ3hucyddfSk7XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnByZXNNYXBbJ3Bhc3N3b3JkJ10pIHtcbiAgICAgICAgICAgICAgICBwcmVzLmMoJ3Bhc3N3b3JkJykudCh0aGlzLnByZXNNYXBbJ3Bhc3N3b3JkJ10pLnVwKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHByZXMudXAoKTtcblxuICAgICAgICAgICAgLy8gU2VuZCBYRVAtMDExNSAnYycgc3RhbnphIHRoYXQgY29udGFpbnMgb3VyIGNhcGFiaWxpdGllcyBpbmZvXG4gICAgICAgICAgICBpZiAodGhpcy5jb25uZWN0aW9uLmNhcHMpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uY2Fwcy5ub2RlID0gY29uZmlnLmNsaWVudE5vZGU7XG4gICAgICAgICAgICAgICAgcHJlcy5jKCdjJywgdGhpcy5jb25uZWN0aW9uLmNhcHMuZ2VuZXJhdGVDYXBzQXR0cnMoKSkudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgcHJlcy5jKCd1c2VyLWFnZW50Jywge3htbG5zOiAnaHR0cDovL2ppdHNpLm9yZy9qaXRtZWV0L3VzZXItYWdlbnQnfSlcbiAgICAgICAgICAgICAgICAudChuYXZpZ2F0b3IudXNlckFnZW50KS51cCgpO1xuXG4gICAgICAgICAgICBpZiAodGhpcy5wcmVzTWFwWydicmlkZ2VJc0Rvd24nXSkge1xuICAgICAgICAgICAgICAgIHByZXMuYygnYnJpZGdlSXNEb3duJykudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMucHJlc01hcFsnZW1haWwnXSkge1xuICAgICAgICAgICAgICAgIHByZXMuYygnZW1haWwnKS50KHRoaXMucHJlc01hcFsnZW1haWwnXSkudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMucHJlc01hcFsndXNlcklkJ10pIHtcbiAgICAgICAgICAgICAgICBwcmVzLmMoJ3VzZXJJZCcpLnQodGhpcy5wcmVzTWFwWyd1c2VySWQnXSkudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMucHJlc01hcFsnZGlzcGxheU5hbWUnXSkge1xuICAgICAgICAgICAgICAgIC8vIFhFUC0wMTcyXG4gICAgICAgICAgICAgICAgcHJlcy5jKCduaWNrJywge3htbG5zOiAnaHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvbmljayd9KVxuICAgICAgICAgICAgICAgICAgICAudCh0aGlzLnByZXNNYXBbJ2Rpc3BsYXlOYW1lJ10pLnVwKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnByZXNNYXBbJ2F1ZGlvbnMnXSkge1xuICAgICAgICAgICAgICAgIHByZXMuYygnYXVkaW9tdXRlZCcsIHt4bWxuczogdGhpcy5wcmVzTWFwWydhdWRpb25zJ119KVxuICAgICAgICAgICAgICAgICAgICAudCh0aGlzLnByZXNNYXBbJ2F1ZGlvbXV0ZWQnXSkudXAoKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYgKHRoaXMucHJlc01hcFsndmlkZW9ucyddKSB7XG4gICAgICAgICAgICAgICAgcHJlcy5jKCd2aWRlb211dGVkJywge3htbG5zOiB0aGlzLnByZXNNYXBbJ3ZpZGVvbnMnXX0pXG4gICAgICAgICAgICAgICAgICAgIC50KHRoaXMucHJlc01hcFsndmlkZW9tdXRlZCddKS51cCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5wcmVzTWFwWydzdGF0c25zJ10pIHtcbiAgICAgICAgICAgICAgICB2YXIgc3RhdHMgPSBwcmVzLmMoJ3N0YXRzJywge3htbG5zOiB0aGlzLnByZXNNYXBbJ3N0YXRzbnMnXX0pO1xuICAgICAgICAgICAgICAgIGZvciAodmFyIHN0YXQgaW4gdGhpcy5wcmVzTWFwW1wic3RhdHNcIl0pXG4gICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLnByZXNNYXBbXCJzdGF0c1wiXVtzdGF0XSAhPSBudWxsKVxuICAgICAgICAgICAgICAgICAgICAgICAgc3RhdHMuYyhcInN0YXRcIiwge25hbWU6IHN0YXQsIHZhbHVlOiB0aGlzLnByZXNNYXBbXCJzdGF0c1wiXVtzdGF0XX0pLnVwKCk7XG4gICAgICAgICAgICAgICAgcHJlcy51cCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5wcmVzTWFwWydwcmV6aW5zJ10pIHtcbiAgICAgICAgICAgICAgICBwcmVzLmMoJ3ByZXppJyxcbiAgICAgICAgICAgICAgICAgICAge3htbG5zOiB0aGlzLnByZXNNYXBbJ3ByZXppbnMnXSxcbiAgICAgICAgICAgICAgICAgICAgICAgICd1cmwnOiB0aGlzLnByZXNNYXBbJ3ByZXppdXJsJ119KVxuICAgICAgICAgICAgICAgICAgICAuYygnY3VycmVudCcpLnQodGhpcy5wcmVzTWFwWydwcmV6aWN1cnJlbnQnXSkudXAoKS51cCgpO1xuICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICBpZiAodGhpcy5wcmVzTWFwWydldGhlcnBhZG5zJ10pIHtcbiAgICAgICAgICAgICAgICBwcmVzLmMoJ2V0aGVycGFkJywge3htbG5zOiB0aGlzLnByZXNNYXBbJ2V0aGVycGFkbnMnXX0pXG4gICAgICAgICAgICAgICAgICAgIC50KHRoaXMucHJlc01hcFsnZXRoZXJwYWRuYW1lJ10pLnVwKCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGlmICh0aGlzLnByZXNNYXBbJ21lZGlhbnMnXSkge1xuICAgICAgICAgICAgICAgIHByZXMuYygnbWVkaWEnLCB7eG1sbnM6IHRoaXMucHJlc01hcFsnbWVkaWFucyddfSk7XG4gICAgICAgICAgICAgICAgdmFyIHNvdXJjZU51bWJlciA9IDA7XG4gICAgICAgICAgICAgICAgT2JqZWN0LmtleXModGhpcy5wcmVzTWFwKS5mb3JFYWNoKGZ1bmN0aW9uIChrZXkpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGtleS5pbmRleE9mKCdzb3VyY2UnKSA+PSAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBzb3VyY2VOdW1iZXIrKztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIGlmIChzb3VyY2VOdW1iZXIgPiAwKVxuICAgICAgICAgICAgICAgICAgICBmb3IgKHZhciBpID0gMTsgaSA8PSBzb3VyY2VOdW1iZXIgLyAzOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHByZXMuYygnc291cmNlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB7dHlwZTogdGhpcy5wcmVzTWFwWydzb3VyY2UnICsgaSArICdfdHlwZSddLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzc3JjOiB0aGlzLnByZXNNYXBbJ3NvdXJjZScgKyBpICsgJ19zc3JjJ10sXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpcmVjdGlvbjogdGhpcy5wcmVzTWFwWydzb3VyY2UnICsgaSArICdfZGlyZWN0aW9uJ11cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHx8ICdzZW5kcmVjdicgfVxuICAgICAgICAgICAgICAgICAgICAgICAgKS51cCgpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIHByZXMudXAoKTtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kKHByZXMpO1xuICAgICAgICB9LFxuICAgICAgICBhZGREaXNwbGF5TmFtZVRvUHJlc2VuY2U6IGZ1bmN0aW9uIChkaXNwbGF5TmFtZSkge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydkaXNwbGF5TmFtZSddID0gZGlzcGxheU5hbWU7XG4gICAgICAgIH0sXG4gICAgICAgIGFkZE1lZGlhVG9QcmVzZW5jZTogZnVuY3Rpb24gKHNvdXJjZU51bWJlciwgbXR5cGUsIHNzcmNzLCBkaXJlY3Rpb24pIHtcbiAgICAgICAgICAgIGlmICghdGhpcy5wcmVzTWFwWydtZWRpYW5zJ10pXG4gICAgICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydtZWRpYW5zJ10gPSAnaHR0cDovL2VzdG9zLmRlL25zL21qcyc7XG5cbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsnc291cmNlJyArIHNvdXJjZU51bWJlciArICdfdHlwZSddID0gbXR5cGU7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3NvdXJjZScgKyBzb3VyY2VOdW1iZXIgKyAnX3NzcmMnXSA9IHNzcmNzO1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydzb3VyY2UnICsgc291cmNlTnVtYmVyICsgJ19kaXJlY3Rpb24nXSA9IGRpcmVjdGlvbjtcbiAgICAgICAgfSxcbiAgICAgICAgY2xlYXJQcmVzZW5jZU1lZGlhOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgc2VsZiA9IHRoaXM7XG4gICAgICAgICAgICBPYmplY3Qua2V5cyh0aGlzLnByZXNNYXApLmZvckVhY2goZnVuY3Rpb24gKGtleSkge1xuICAgICAgICAgICAgICAgIGlmIChrZXkuaW5kZXhPZignc291cmNlJykgIT0gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHNlbGYucHJlc01hcFtrZXldO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuICAgICAgICBhZGRQcmV6aVRvUHJlc2VuY2U6IGZ1bmN0aW9uICh1cmwsIGN1cnJlbnRTbGlkZSkge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydwcmV6aW5zJ10gPSAnaHR0cDovL2ppdHNpLm9yZy9qaXRtZWV0L3ByZXppJztcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsncHJleml1cmwnXSA9IHVybDtcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsncHJlemljdXJyZW50J10gPSBjdXJyZW50U2xpZGU7XG4gICAgICAgIH0sXG4gICAgICAgIHJlbW92ZVByZXppRnJvbVByZXNlbmNlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICBkZWxldGUgdGhpcy5wcmVzTWFwWydwcmV6aW5zJ107XG4gICAgICAgICAgICBkZWxldGUgdGhpcy5wcmVzTWFwWydwcmV6aXVybCddO1xuICAgICAgICAgICAgZGVsZXRlIHRoaXMucHJlc01hcFsncHJlemljdXJyZW50J107XG4gICAgICAgIH0sXG4gICAgICAgIGFkZEN1cnJlbnRTbGlkZVRvUHJlc2VuY2U6IGZ1bmN0aW9uIChjdXJyZW50U2xpZGUpIHtcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsncHJlemljdXJyZW50J10gPSBjdXJyZW50U2xpZGU7XG4gICAgICAgIH0sXG4gICAgICAgIGdldFByZXppOiBmdW5jdGlvbiAocm9vbWppZCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucHJlemlNYXBbcm9vbWppZF07XG4gICAgICAgIH0sXG4gICAgICAgIGFkZEV0aGVycGFkVG9QcmVzZW5jZTogZnVuY3Rpb24gKGV0aGVycGFkTmFtZSkge1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydldGhlcnBhZG5zJ10gPSAnaHR0cDovL2ppdHNpLm9yZy9qaXRtZWV0L2V0aGVycGFkJztcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsnZXRoZXJwYWRuYW1lJ10gPSBldGhlcnBhZE5hbWU7XG4gICAgICAgIH0sXG4gICAgICAgIGFkZEF1ZGlvSW5mb1RvUHJlc2VuY2U6IGZ1bmN0aW9uIChpc011dGVkKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ2F1ZGlvbnMnXSA9ICdodHRwOi8vaml0c2kub3JnL2ppdG1lZXQvYXVkaW8nO1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydhdWRpb211dGVkJ10gPSBpc011dGVkLnRvU3RyaW5nKCk7XG4gICAgICAgIH0sXG4gICAgICAgIGFkZFZpZGVvSW5mb1RvUHJlc2VuY2U6IGZ1bmN0aW9uIChpc011dGVkKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3ZpZGVvbnMnXSA9ICdodHRwOi8vaml0c2kub3JnL2ppdG1lZXQvdmlkZW8nO1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWyd2aWRlb211dGVkJ10gPSBpc011dGVkLnRvU3RyaW5nKCk7XG4gICAgICAgIH0sXG4gICAgICAgIGFkZENvbm5lY3Rpb25JbmZvVG9QcmVzZW5jZTogZnVuY3Rpb24gKHN0YXRzKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3N0YXRzbnMnXSA9ICdodHRwOi8vaml0c2kub3JnL2ppdG1lZXQvc3RhdHMnO1xuICAgICAgICAgICAgdGhpcy5wcmVzTWFwWydzdGF0cyddID0gc3RhdHM7XG4gICAgICAgIH0sXG4gICAgICAgIGZpbmRKaWRGcm9tUmVzb3VyY2U6IGZ1bmN0aW9uIChyZXNvdXJjZUppZCkge1xuICAgICAgICAgICAgaWYgKHJlc291cmNlSmlkICYmXG4gICAgICAgICAgICAgICAgcmVzb3VyY2VKaWQgPT09IFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKHRoaXMubXlyb29tamlkKSkge1xuICAgICAgICAgICAgICAgIHJldHVybiB0aGlzLm15cm9vbWppZDtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBwZWVySmlkID0gbnVsbDtcbiAgICAgICAgICAgIE9iamVjdC5rZXlzKHRoaXMubWVtYmVycykuc29tZShmdW5jdGlvbiAoamlkKSB7XG4gICAgICAgICAgICAgICAgcGVlckppZCA9IGppZDtcbiAgICAgICAgICAgICAgICByZXR1cm4gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoamlkKSA9PT0gcmVzb3VyY2VKaWQ7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBwZWVySmlkO1xuICAgICAgICB9LFxuICAgICAgICBhZGRCcmlkZ2VJc0Rvd25Ub1ByZXNlbmNlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ2JyaWRnZUlzRG93biddID0gdHJ1ZTtcbiAgICAgICAgfSxcbiAgICAgICAgYWRkRW1haWxUb1ByZXNlbmNlOiBmdW5jdGlvbiAoZW1haWwpIHtcbiAgICAgICAgICAgIHRoaXMucHJlc01hcFsnZW1haWwnXSA9IGVtYWlsO1xuICAgICAgICB9LFxuICAgICAgICBhZGRVc2VySWRUb1ByZXNlbmNlOiBmdW5jdGlvbiAodXNlcklkKSB7XG4gICAgICAgICAgICB0aGlzLnByZXNNYXBbJ3VzZXJJZCddID0gdXNlcklkO1xuICAgICAgICB9LFxuICAgICAgICBpc01vZGVyYXRvcjogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucm9sZSA9PT0gJ21vZGVyYXRvcic7XG4gICAgICAgIH0sXG4gICAgICAgIGdldE1lbWJlclJvbGU6IGZ1bmN0aW9uIChwZWVySmlkKSB7XG4gICAgICAgICAgICBpZiAodGhpcy5tZW1iZXJzW3BlZXJKaWRdKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRoaXMubWVtYmVyc1twZWVySmlkXS5yb2xlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIH0sXG4gICAgICAgIG9uUGFydGljaXBhbnRMZWZ0OiBmdW5jdGlvbiAoamlkKSB7XG5cbiAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuTVVDX0xFRlQsIGppZCk7XG5cbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5qaW5nbGUudGVybWluYXRlQnlKaWQoamlkKTtcblxuICAgICAgICAgICAgaWYgKHRoaXMuZ2V0UHJlemkoamlkKSkge1xuICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ3ByZXNlbnRhdGlvbnJlbW92ZWQubXVjJyxcbiAgICAgICAgICAgICAgICAgICAgW2ppZCwgdGhpcy5nZXRQcmV6aShqaWQpXSk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIE1vZGVyYXRvci5vbk11Y0xlZnQoamlkKTtcbiAgICAgICAgfSxcbiAgICAgICAgcGFyc2VQcmVzZW5jZTogZnVuY3Rpb24gKGZyb20sIG1lbWViZXIsIHByZXMpIHtcbiAgICAgICAgICAgIGlmKCQocHJlcykuZmluZChcIj5icmlkZ2VJc0Rvd25cIikubGVuZ3RoID4gMCAmJiAhYnJpZGdlSXNEb3duKSB7XG4gICAgICAgICAgICAgICAgYnJpZGdlSXNEb3duID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICBldmVudEVtaXR0ZXIuZW1pdChYTVBQRXZlbnRzLkJSSURHRV9ET1dOKTtcbiAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgaWYobWVtZWJlci5pc0ZvY3VzKVxuICAgICAgICAgICAgICAgIHJldHVybjtcblxuICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgICAgLy8gUmVtb3ZlIG9sZCBzc3JjcyBjb21pbmcgZnJvbSB0aGUgamlkXG4gICAgICAgICAgICBPYmplY3Qua2V5cyh0aGlzLnNzcmMyamlkKS5mb3JFYWNoKGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgICAgICAgICAgaWYgKHNlbGYuc3NyYzJqaWRbc3NyY10gPT0gZnJvbSkge1xuICAgICAgICAgICAgICAgICAgICBkZWxldGUgc2VsZi5zc3JjMmppZFtzc3JjXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgdmFyIGNoYW5nZWRTdHJlYW1zID0gW107XG4gICAgICAgICAgICAkKHByZXMpLmZpbmQoJz5tZWRpYVt4bWxucz1cImh0dHA6Ly9lc3Rvcy5kZS9ucy9tanNcIl0+c291cmNlJykuZWFjaChmdW5jdGlvbiAoaWR4LCBzc3JjKSB7XG4gICAgICAgICAgICAgICAgLy9jb25zb2xlLmxvZyhqaWQsICdhc3NvYyBzc3JjJywgc3NyYy5nZXRBdHRyaWJ1dGUoJ3R5cGUnKSwgc3NyYy5nZXRBdHRyaWJ1dGUoJ3NzcmMnKSk7XG4gICAgICAgICAgICAgICAgdmFyIHNzcmNWID0gc3NyYy5nZXRBdHRyaWJ1dGUoJ3NzcmMnKTtcbiAgICAgICAgICAgICAgICBzZWxmLnNzcmMyamlkW3NzcmNWXSA9IGZyb207XG4gICAgICAgICAgICAgICAgSmluZ2xlU2Vzc2lvbi5ub3RSZWNlaXZlZFNTUkNzLnB1c2goc3NyY1YpO1xuXG5cbiAgICAgICAgICAgICAgICB2YXIgdHlwZSA9IHNzcmMuZ2V0QXR0cmlidXRlKCd0eXBlJyk7XG5cbiAgICAgICAgICAgICAgICB2YXIgZGlyZWN0aW9uID0gc3NyYy5nZXRBdHRyaWJ1dGUoJ2RpcmVjdGlvbicpO1xuXG4gICAgICAgICAgICAgICAgY2hhbmdlZFN0cmVhbXMucHVzaCh7dHlwZTogdHlwZSwgZGlyZWN0aW9uOiBkaXJlY3Rpb259KTtcblxuICAgICAgICAgICAgfSk7XG5cbiAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuQ0hBTkdFRF9TVFJFQU1TLCBmcm9tLCBjaGFuZ2VkU3RyZWFtcyk7XG5cbiAgICAgICAgICAgIHZhciBkaXNwbGF5TmFtZSA9ICFjb25maWcuZGlzcGxheUppZHNcbiAgICAgICAgICAgICAgICA/IG1lbWViZXIuZGlzcGxheU5hbWUgOiBTdHJvcGhlLmdldFJlc291cmNlRnJvbUppZChmcm9tKTtcblxuICAgICAgICAgICAgaWYgKGRpc3BsYXlOYW1lICYmIGRpc3BsYXlOYW1lLmxlbmd0aCA+IDApXG4gICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgZXZlbnRFbWl0dGVyLmVtaXQoWE1QUEV2ZW50cy5ESVNQTEFZX05BTUVfQ0hBTkdFRCwgZnJvbSwgZGlzcGxheU5hbWUpO1xuICAgICAgICAgICAgfVxuXG5cbiAgICAgICAgICAgIHZhciBpZCA9ICQocHJlcykuZmluZCgnPnVzZXJJRCcpLnRleHQoKTtcbiAgICAgICAgICAgIHZhciBlbWFpbCA9ICQocHJlcykuZmluZCgnPmVtYWlsJyk7XG4gICAgICAgICAgICBpZihlbWFpbC5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgaWQgPSBlbWFpbC50ZXh0KCk7XG4gICAgICAgICAgICB9XG5cbiAgICAgICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuVVNFUl9JRF9DSEFOR0VELCBmcm9tLCBpZCk7XG4gICAgICAgIH1cbiAgICB9KTtcbn07XG5cbiIsIi8qIGpzaGludCAtVzExNyAqL1xuXG52YXIgSmluZ2xlU2Vzc2lvbiA9IHJlcXVpcmUoXCIuL0ppbmdsZVNlc3Npb25cIik7XG52YXIgWE1QUEV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL3htcHAvWE1QUEV2ZW50c1wiKTtcblxuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uKFhNUFAsIGV2ZW50RW1pdHRlcilcbntcbiAgICBmdW5jdGlvbiBDYWxsSW5jb21pbmdKaW5nbGUoc2lkLCBjb25uZWN0aW9uKSB7XG4gICAgICAgIHZhciBzZXNzID0gY29ubmVjdGlvbi5qaW5nbGUuc2Vzc2lvbnNbc2lkXTtcblxuICAgICAgICAvLyBUT0RPOiBkbyB3ZSBjaGVjayBhY3RpdmVjYWxsID09IG51bGw/XG4gICAgICAgIGNvbm5lY3Rpb24uamluZ2xlLmFjdGl2ZWNhbGwgPSBzZXNzO1xuXG4gICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuQ0FMTF9JTkNPTUlORywgc2Vzcyk7XG5cbiAgICAgICAgLy8gVE9ETzogY2hlY2sgYWZmaWxpYXRpb24gYW5kL29yIHJvbGVcbiAgICAgICAgY29uc29sZS5sb2coJ2VtdWMgZGF0YSBmb3InLCBzZXNzLnBlZXJqaWQsIGNvbm5lY3Rpb24uZW11Yy5tZW1iZXJzW3Nlc3MucGVlcmppZF0pO1xuICAgICAgICBzZXNzLnVzZWRyaXAgPSB0cnVlOyAvLyBub3Qtc28tbmFpdmUgdHJpY2tsZSBpY2VcbiAgICAgICAgc2Vzcy5zZW5kQW5zd2VyKCk7XG4gICAgICAgIHNlc3MuYWNjZXB0KCk7XG5cbiAgICB9O1xuXG4gICAgU3Ryb3BoZS5hZGRDb25uZWN0aW9uUGx1Z2luKCdqaW5nbGUnLCB7XG4gICAgICAgIGNvbm5lY3Rpb246IG51bGwsXG4gICAgICAgIHNlc3Npb25zOiB7fSxcbiAgICAgICAgamlkMnNlc3Npb246IHt9LFxuICAgICAgICBpY2VfY29uZmlnOiB7aWNlU2VydmVyczogW119LFxuICAgICAgICBwY19jb25zdHJhaW50czoge30sXG4gICAgICAgIGFjdGl2ZWNhbGw6IG51bGwsXG4gICAgICAgIG1lZGlhX2NvbnN0cmFpbnRzOiB7XG4gICAgICAgICAgICBtYW5kYXRvcnk6IHtcbiAgICAgICAgICAgICAgICAnT2ZmZXJUb1JlY2VpdmVBdWRpbyc6IHRydWUsXG4gICAgICAgICAgICAgICAgJ09mZmVyVG9SZWNlaXZlVmlkZW8nOiB0cnVlXG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLyBNb3pEb250T2ZmZXJEYXRhQ2hhbm5lbDogdHJ1ZSB3aGVuIHRoaXMgaXMgZmlyZWZveFxuICAgICAgICB9LFxuICAgICAgICBpbml0OiBmdW5jdGlvbiAoY29ubikge1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uID0gY29ubjtcbiAgICAgICAgICAgIGlmICh0aGlzLmNvbm5lY3Rpb24uZGlzY28pIHtcbiAgICAgICAgICAgICAgICAvLyBodHRwOi8veG1wcC5vcmcvZXh0ZW5zaW9ucy94ZXAtMDE2Ny5odG1sI3N1cHBvcnRcbiAgICAgICAgICAgICAgICAvLyBodHRwOi8veG1wcC5vcmcvZXh0ZW5zaW9ucy94ZXAtMDE3Ni5odG1sI3N1cHBvcnRcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZGlzY28uYWRkRmVhdHVyZSgndXJuOnhtcHA6amluZ2xlOjEnKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZGlzY28uYWRkRmVhdHVyZSgndXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOjEnKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZGlzY28uYWRkRmVhdHVyZSgndXJuOnhtcHA6amluZ2xlOnRyYW5zcG9ydHM6aWNlLXVkcDoxJyk7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3Vybjp4bXBwOmppbmdsZTp0cmFuc3BvcnRzOmR0bHMtc2N0cDoxJyk7XG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3Vybjp4bXBwOmppbmdsZTphcHBzOnJ0cDphdWRpbycpO1xuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5kaXNjby5hZGRGZWF0dXJlKCd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6dmlkZW8nKTtcblxuXG4gICAgICAgICAgICAgICAgLy8gdGhpcyBpcyBkZWFsdCB3aXRoIGJ5IFNEUCBPL0Egc28gd2UgZG9uJ3QgbmVlZCB0byBhbm5vdWNlIHRoaXNcbiAgICAgICAgICAgICAgICAvL3RoaXMuY29ubmVjdGlvbi5kaXNjby5hZGRGZWF0dXJlKCd1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6cnRjcC1mYjowJyk7IC8vIFhFUC0wMjkzXG4gICAgICAgICAgICAgICAgLy90aGlzLmNvbm5lY3Rpb24uZGlzY28uYWRkRmVhdHVyZSgndXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOnJ0cC1oZHJleHQ6MCcpOyAvLyBYRVAtMDI5NFxuICAgICAgICAgICAgICAgIGlmIChjb25maWcudXNlUnRjcE11eCkge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZGlzY28uYWRkRmVhdHVyZSgndXJuOmlldGY6cmZjOjU3NjEnKTsgLy8gcnRjcC1tdXhcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgaWYgKGNvbmZpZy51c2VCdW5kbGUpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3VybjppZXRmOnJmYzo1ODg4Jyk7IC8vIGE9Z3JvdXAsIGUuZy4gYnVuZGxlXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIC8vdGhpcy5jb25uZWN0aW9uLmRpc2NvLmFkZEZlYXR1cmUoJ3VybjppZXRmOnJmYzo1NTc2Jyk7IC8vIGE9c3NyY1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLmFkZEhhbmRsZXIodGhpcy5vbkppbmdsZS5iaW5kKHRoaXMpLCAndXJuOnhtcHA6amluZ2xlOjEnLCAnaXEnLCAnc2V0JywgbnVsbCwgbnVsbCk7XG4gICAgICAgIH0sXG4gICAgICAgIG9uSmluZ2xlOiBmdW5jdGlvbiAoaXEpIHtcbiAgICAgICAgICAgIHZhciBzaWQgPSAkKGlxKS5maW5kKCdqaW5nbGUnKS5hdHRyKCdzaWQnKTtcbiAgICAgICAgICAgIHZhciBhY3Rpb24gPSAkKGlxKS5maW5kKCdqaW5nbGUnKS5hdHRyKCdhY3Rpb24nKTtcbiAgICAgICAgICAgIHZhciBmcm9tSmlkID0gaXEuZ2V0QXR0cmlidXRlKCdmcm9tJyk7XG4gICAgICAgICAgICAvLyBzZW5kIGFjayBmaXJzdFxuICAgICAgICAgICAgdmFyIGFjayA9ICRpcSh7dHlwZTogJ3Jlc3VsdCcsXG4gICAgICAgICAgICAgICAgdG86IGZyb21KaWQsXG4gICAgICAgICAgICAgICAgaWQ6IGlxLmdldEF0dHJpYnV0ZSgnaWQnKVxuICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICBjb25zb2xlLmxvZygnb24gamluZ2xlICcgKyBhY3Rpb24gKyAnIGZyb20gJyArIGZyb21KaWQsIGlxKTtcbiAgICAgICAgICAgIHZhciBzZXNzID0gdGhpcy5zZXNzaW9uc1tzaWRdO1xuICAgICAgICAgICAgaWYgKCdzZXNzaW9uLWluaXRpYXRlJyAhPSBhY3Rpb24pIHtcbiAgICAgICAgICAgICAgICBpZiAoc2VzcyA9PT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBhY2sudHlwZSA9ICdlcnJvcic7XG4gICAgICAgICAgICAgICAgICAgIGFjay5jKCdlcnJvcicsIHt0eXBlOiAnY2FuY2VsJ30pXG4gICAgICAgICAgICAgICAgICAgICAgICAuYygnaXRlbS1ub3QtZm91bmQnLCB7eG1sbnM6ICd1cm46aWV0ZjpwYXJhbXM6eG1sOm5zOnhtcHAtc3Rhbnphcyd9KS51cCgpXG4gICAgICAgICAgICAgICAgICAgICAgICAuYygndW5rbm93bi1zZXNzaW9uJywge3htbG5zOiAndXJuOnhtcHA6amluZ2xlOmVycm9yczoxJ30pO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZChhY2spO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgLy8gY29tcGFyZSBmcm9tIHRvIHNlc3MucGVlcmppZCAoYmFyZSBqaWQgY29tcGFyaXNvbiBmb3IgbGF0ZXIgY29tcGF0IHdpdGggbWVzc2FnZS1tb2RlKVxuICAgICAgICAgICAgICAgIC8vIGxvY2FsIGppZCBpcyBub3QgY2hlY2tlZFxuICAgICAgICAgICAgICAgIGlmIChTdHJvcGhlLmdldEJhcmVKaWRGcm9tSmlkKGZyb21KaWQpICE9IFN0cm9waGUuZ2V0QmFyZUppZEZyb21KaWQoc2Vzcy5wZWVyamlkKSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ2ppZCBtaXNtYXRjaCBmb3Igc2Vzc2lvbiBpZCcsIHNpZCwgZnJvbUppZCwgc2Vzcy5wZWVyamlkKTtcbiAgICAgICAgICAgICAgICAgICAgYWNrLnR5cGUgPSAnZXJyb3InO1xuICAgICAgICAgICAgICAgICAgICBhY2suYygnZXJyb3InLCB7dHlwZTogJ2NhbmNlbCd9KVxuICAgICAgICAgICAgICAgICAgICAgICAgLmMoJ2l0ZW0tbm90LWZvdW5kJywge3htbG5zOiAndXJuOmlldGY6cGFyYW1zOnhtbDpuczp4bXBwLXN0YW56YXMnfSkudXAoKVxuICAgICAgICAgICAgICAgICAgICAgICAgLmMoJ3Vua25vd24tc2Vzc2lvbicsIHt4bWxuczogJ3Vybjp4bXBwOmppbmdsZTplcnJvcnM6MSd9KTtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmQoYWNrKTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmIChzZXNzICE9PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgICAgICAvLyBleGlzdGluZyBzZXNzaW9uIHdpdGggc2FtZSBzZXNzaW9uIGlkXG4gICAgICAgICAgICAgICAgLy8gdGhpcyBtaWdodCBiZSBvdXQtb2Ytb3JkZXIgaWYgdGhlIHNlc3MucGVlcmppZCBpcyB0aGUgc2FtZSBhcyBmcm9tXG4gICAgICAgICAgICAgICAgYWNrLnR5cGUgPSAnZXJyb3InO1xuICAgICAgICAgICAgICAgIGFjay5jKCdlcnJvcicsIHt0eXBlOiAnY2FuY2VsJ30pXG4gICAgICAgICAgICAgICAgICAgIC5jKCdzZXJ2aWNlLXVuYXZhaWxhYmxlJywge3htbG5zOiAndXJuOmlldGY6cGFyYW1zOnhtbDpuczp4bXBwLXN0YW56YXMnfSkudXAoKTtcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oJ2R1cGxpY2F0ZSBzZXNzaW9uIGlkJywgc2lkKTtcbiAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZChhY2spO1xuICAgICAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy8gRklYTUU6IGNoZWNrIGZvciBhIGRlZmluZWQgYWN0aW9uXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZChhY2spO1xuICAgICAgICAgICAgLy8gc2VlIGh0dHA6Ly94bXBwLm9yZy9leHRlbnNpb25zL3hlcC0wMTY2Lmh0bWwjY29uY2VwdHMtc2Vzc2lvblxuICAgICAgICAgICAgc3dpdGNoIChhY3Rpb24pIHtcbiAgICAgICAgICAgICAgICBjYXNlICdzZXNzaW9uLWluaXRpYXRlJzpcbiAgICAgICAgICAgICAgICAgICAgc2VzcyA9IG5ldyBKaW5nbGVTZXNzaW9uKFxuICAgICAgICAgICAgICAgICAgICAgICAgJChpcSkuYXR0cigndG8nKSwgJChpcSkuZmluZCgnamluZ2xlJykuYXR0cignc2lkJyksXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24sIFhNUFApO1xuICAgICAgICAgICAgICAgICAgICAvLyBjb25maWd1cmUgc2Vzc2lvblxuXG4gICAgICAgICAgICAgICAgICAgIHNlc3MubWVkaWFfY29uc3RyYWludHMgPSB0aGlzLm1lZGlhX2NvbnN0cmFpbnRzO1xuICAgICAgICAgICAgICAgICAgICBzZXNzLnBjX2NvbnN0cmFpbnRzID0gdGhpcy5wY19jb25zdHJhaW50cztcbiAgICAgICAgICAgICAgICAgICAgc2Vzcy5pY2VfY29uZmlnID0gdGhpcy5pY2VfY29uZmlnO1xuXG4gICAgICAgICAgICAgICAgICAgIHNlc3MuaW5pdGlhdGUoZnJvbUppZCwgZmFsc2UpO1xuICAgICAgICAgICAgICAgICAgICAvLyBGSVhNRTogc2V0UmVtb3RlRGVzY3JpcHRpb24gc2hvdWxkIG9ubHkgYmUgZG9uZSB3aGVuIHRoaXMgY2FsbCBpcyB0byBiZSBhY2NlcHRlZFxuICAgICAgICAgICAgICAgICAgICBzZXNzLnNldFJlbW90ZURlc2NyaXB0aW9uKCQoaXEpLmZpbmQoJz5qaW5nbGUnKSwgJ29mZmVyJyk7XG5cbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXNzaW9uc1tzZXNzLnNpZF0gPSBzZXNzO1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmppZDJzZXNzaW9uW3Nlc3MucGVlcmppZF0gPSBzZXNzO1xuXG4gICAgICAgICAgICAgICAgICAgIC8vIHRoZSBjYWxsYmFjayBzaG91bGQgZWl0aGVyXG4gICAgICAgICAgICAgICAgICAgIC8vIC5zZW5kQW5zd2VyIGFuZCAuYWNjZXB0XG4gICAgICAgICAgICAgICAgICAgIC8vIG9yIC5zZW5kVGVybWluYXRlIC0tIG5vdCBuZWNlc3NhcmlseSBzeW5jaHJvbnVzXG4gICAgICAgICAgICAgICAgICAgIENhbGxJbmNvbWluZ0ppbmdsZShzZXNzLnNpZCwgdGhpcy5jb25uZWN0aW9uKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAnc2Vzc2lvbi1hY2NlcHQnOlxuICAgICAgICAgICAgICAgICAgICBzZXNzLnNldFJlbW90ZURlc2NyaXB0aW9uKCQoaXEpLmZpbmQoJz5qaW5nbGUnKSwgJ2Fuc3dlcicpO1xuICAgICAgICAgICAgICAgICAgICBzZXNzLmFjY2VwdCgpO1xuICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdjYWxsYWNjZXB0ZWQuamluZ2xlJywgW3Nlc3Muc2lkXSk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ3Nlc3Npb24tdGVybWluYXRlJzpcbiAgICAgICAgICAgICAgICAgICAgLy8gSWYgdGhpcyBpcyBub3QgdGhlIGZvY3VzIHNlbmRpbmcgdGhlIHRlcm1pbmF0ZSwgd2UgaGF2ZVxuICAgICAgICAgICAgICAgICAgICAvLyBub3RoaW5nIG1vcmUgdG8gZG8gaGVyZS5cbiAgICAgICAgICAgICAgICAgICAgaWYgKE9iamVjdC5rZXlzKHRoaXMuc2Vzc2lvbnMpLmxlbmd0aCA8IDFcbiAgICAgICAgICAgICAgICAgICAgICAgIHx8ICEodGhpcy5zZXNzaW9uc1tPYmplY3Qua2V5cyh0aGlzLnNlc3Npb25zKVswXV1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpbnN0YW5jZW9mIEppbmdsZVNlc3Npb24pKVxuICAgICAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygndGVybWluYXRpbmcuLi4nLCBzZXNzLnNpZCk7XG4gICAgICAgICAgICAgICAgICAgIHNlc3MudGVybWluYXRlKCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMudGVybWluYXRlKHNlc3Muc2lkKTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQoaXEpLmZpbmQoJz5qaW5nbGU+cmVhc29uJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdjYWxsdGVybWluYXRlZC5qaW5nbGUnLCBbXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzcy5zaWQsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2Vzcy5wZWVyamlkLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICQoaXEpLmZpbmQoJz5qaW5nbGU+cmVhc29uPjpmaXJzdCcpWzBdLnRhZ05hbWUsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgJChpcSkuZmluZCgnPmppbmdsZT5yZWFzb24+dGV4dCcpLnRleHQoKVxuICAgICAgICAgICAgICAgICAgICAgICAgXSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAkKGRvY3VtZW50KS50cmlnZ2VyKCdjYWxsdGVybWluYXRlZC5qaW5nbGUnLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIFtzZXNzLnNpZCwgc2Vzcy5wZWVyamlkXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAndHJhbnNwb3J0LWluZm8nOlxuICAgICAgICAgICAgICAgICAgICBzZXNzLmFkZEljZUNhbmRpZGF0ZSgkKGlxKS5maW5kKCc+amluZ2xlPmNvbnRlbnQnKSk7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgICAgIGNhc2UgJ3Nlc3Npb24taW5mbyc6XG4gICAgICAgICAgICAgICAgICAgIHZhciBhZmZlY3RlZDtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCQoaXEpLmZpbmQoJz5qaW5nbGU+cmluZ2luZ1t4bWxucz1cInVybjp4bXBwOmppbmdsZTphcHBzOnJ0cDppbmZvOjFcIl0nKS5sZW5ndGgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ3JpbmdpbmcuamluZ2xlJywgW3Nlc3Muc2lkXSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoJChpcSkuZmluZCgnPmppbmdsZT5tdXRlW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOmluZm86MVwiXScpLmxlbmd0aCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYWZmZWN0ZWQgPSAkKGlxKS5maW5kKCc+amluZ2xlPm11dGVbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6aW5mbzoxXCJdJykuYXR0cignbmFtZScpO1xuICAgICAgICAgICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignbXV0ZS5qaW5nbGUnLCBbc2Vzcy5zaWQsIGFmZmVjdGVkXSk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAoJChpcSkuZmluZCgnPmppbmdsZT51bm11dGVbeG1sbnM9XCJ1cm46eG1wcDpqaW5nbGU6YXBwczpydHA6aW5mbzoxXCJdJykubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhZmZlY3RlZCA9ICQoaXEpLmZpbmQoJz5qaW5nbGU+dW5tdXRlW3htbG5zPVwidXJuOnhtcHA6amluZ2xlOmFwcHM6cnRwOmluZm86MVwiXScpLmF0dHIoJ25hbWUnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICQoZG9jdW1lbnQpLnRyaWdnZXIoJ3VubXV0ZS5qaW5nbGUnLCBbc2Vzcy5zaWQsIGFmZmVjdGVkXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAnYWRkc291cmNlJzogLy8gRklYTUU6IHByb3ByaWV0YXJ5LCB1bi1qaW5nbGVpc2hcbiAgICAgICAgICAgICAgICBjYXNlICdzb3VyY2UtYWRkJzogLy8gRklYTUU6IHByb3ByaWV0YXJ5XG4gICAgICAgICAgICAgICAgICAgIHNlc3MuYWRkU291cmNlKCQoaXEpLmZpbmQoJz5qaW5nbGU+Y29udGVudCcpLCBmcm9tSmlkKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgY2FzZSAncmVtb3Zlc291cmNlJzogLy8gRklYTUU6IHByb3ByaWV0YXJ5LCB1bi1qaW5nbGVpc2hcbiAgICAgICAgICAgICAgICBjYXNlICdzb3VyY2UtcmVtb3ZlJzogLy8gRklYTUU6IHByb3ByaWV0YXJ5XG4gICAgICAgICAgICAgICAgICAgIHNlc3MucmVtb3ZlU291cmNlKCQoaXEpLmZpbmQoJz5qaW5nbGU+Y29udGVudCcpLCBmcm9tSmlkKTtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdqaW5nbGUgYWN0aW9uIG5vdCBpbXBsZW1lbnRlZCcsIGFjdGlvbik7XG4gICAgICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgICAgIH0sXG4gICAgICAgIGluaXRpYXRlOiBmdW5jdGlvbiAocGVlcmppZCwgbXlqaWQpIHsgLy8gaW5pdGlhdGUgYSBuZXcgamluZ2xlc2Vzc2lvbiB0byBwZWVyamlkXG4gICAgICAgICAgICB2YXIgc2VzcyA9IG5ldyBKaW5nbGVTZXNzaW9uKG15amlkIHx8IHRoaXMuY29ubmVjdGlvbi5qaWQsXG4gICAgICAgICAgICAgICAgTWF0aC5yYW5kb20oKS50b1N0cmluZygzNikuc3Vic3RyKDIsIDEyKSwgLy8gcmFuZG9tIHN0cmluZ1xuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbiwgWE1QUCk7XG4gICAgICAgICAgICAvLyBjb25maWd1cmUgc2Vzc2lvblxuXG4gICAgICAgICAgICBzZXNzLm1lZGlhX2NvbnN0cmFpbnRzID0gdGhpcy5tZWRpYV9jb25zdHJhaW50cztcbiAgICAgICAgICAgIHNlc3MucGNfY29uc3RyYWludHMgPSB0aGlzLnBjX2NvbnN0cmFpbnRzO1xuICAgICAgICAgICAgc2Vzcy5pY2VfY29uZmlnID0gdGhpcy5pY2VfY29uZmlnO1xuXG4gICAgICAgICAgICBzZXNzLmluaXRpYXRlKHBlZXJqaWQsIHRydWUpO1xuICAgICAgICAgICAgdGhpcy5zZXNzaW9uc1tzZXNzLnNpZF0gPSBzZXNzO1xuICAgICAgICAgICAgdGhpcy5qaWQyc2Vzc2lvbltzZXNzLnBlZXJqaWRdID0gc2VzcztcbiAgICAgICAgICAgIHNlc3Muc2VuZE9mZmVyKCk7XG4gICAgICAgICAgICByZXR1cm4gc2VzcztcbiAgICAgICAgfSxcbiAgICAgICAgdGVybWluYXRlOiBmdW5jdGlvbiAoc2lkLCByZWFzb24sIHRleHQpIHsgLy8gdGVybWluYXRlIGJ5IHNlc3Npb25pZCAob3IgYWxsIHNlc3Npb25zKVxuICAgICAgICAgICAgaWYgKHNpZCA9PT0gbnVsbCB8fCBzaWQgPT09IHVuZGVmaW5lZCkge1xuICAgICAgICAgICAgICAgIGZvciAoc2lkIGluIHRoaXMuc2Vzc2lvbnMpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKHRoaXMuc2Vzc2lvbnNbc2lkXS5zdGF0ZSAhPSAnZW5kZWQnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnNlc3Npb25zW3NpZF0uc2VuZFRlcm1pbmF0ZShyZWFzb24gfHwgKCF0aGlzLnNlc3Npb25zW3NpZF0uYWN0aXZlKCkpID8gJ2NhbmNlbCcgOiBudWxsLCB0ZXh0KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc2Vzc2lvbnNbc2lkXS50ZXJtaW5hdGUoKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBkZWxldGUgdGhpcy5qaWQyc2Vzc2lvblt0aGlzLnNlc3Npb25zW3NpZF0ucGVlcmppZF07XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnNlc3Npb25zW3NpZF07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfSBlbHNlIGlmICh0aGlzLnNlc3Npb25zLmhhc093blByb3BlcnR5KHNpZCkpIHtcbiAgICAgICAgICAgICAgICBpZiAodGhpcy5zZXNzaW9uc1tzaWRdLnN0YXRlICE9ICdlbmRlZCcpIHtcbiAgICAgICAgICAgICAgICAgICAgdGhpcy5zZXNzaW9uc1tzaWRdLnNlbmRUZXJtaW5hdGUocmVhc29uIHx8ICghdGhpcy5zZXNzaW9uc1tzaWRdLmFjdGl2ZSgpKSA/ICdjYW5jZWwnIDogbnVsbCwgdGV4dCk7XG4gICAgICAgICAgICAgICAgICAgIHRoaXMuc2Vzc2lvbnNbc2lkXS50ZXJtaW5hdGUoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuamlkMnNlc3Npb25bdGhpcy5zZXNzaW9uc1tzaWRdLnBlZXJqaWRdO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnNlc3Npb25zW3NpZF07XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIC8vIFVzZWQgdG8gdGVybWluYXRlIGEgc2Vzc2lvbiB3aGVuIGFuIHVuYXZhaWxhYmxlIHByZXNlbmNlIGlzIHJlY2VpdmVkLlxuICAgICAgICB0ZXJtaW5hdGVCeUppZDogZnVuY3Rpb24gKGppZCkge1xuICAgICAgICAgICAgaWYgKHRoaXMuamlkMnNlc3Npb24uaGFzT3duUHJvcGVydHkoamlkKSkge1xuICAgICAgICAgICAgICAgIHZhciBzZXNzID0gdGhpcy5qaWQyc2Vzc2lvbltqaWRdO1xuICAgICAgICAgICAgICAgIGlmIChzZXNzKSB7XG4gICAgICAgICAgICAgICAgICAgIHNlc3MudGVybWluYXRlKCk7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdwZWVyIHdlbnQgYXdheSBzaWxlbnRseScsIGppZCk7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnNlc3Npb25zW3Nlc3Muc2lkXTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuamlkMnNlc3Npb25bamlkXTtcbiAgICAgICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignY2FsbHRlcm1pbmF0ZWQuamluZ2xlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIFtzZXNzLnNpZCwgamlkXSwgJ2dvbmUnKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIHRlcm1pbmF0ZVJlbW90ZUJ5SmlkOiBmdW5jdGlvbiAoamlkLCByZWFzb24pIHtcbiAgICAgICAgICAgIGlmICh0aGlzLmppZDJzZXNzaW9uLmhhc093blByb3BlcnR5KGppZCkpIHtcbiAgICAgICAgICAgICAgICB2YXIgc2VzcyA9IHRoaXMuamlkMnNlc3Npb25bamlkXTtcbiAgICAgICAgICAgICAgICBpZiAoc2Vzcykge1xuICAgICAgICAgICAgICAgICAgICBzZXNzLnNlbmRUZXJtaW5hdGUocmVhc29uIHx8ICghc2Vzcy5hY3RpdmUoKSkgPyAna2ljaycgOiBudWxsKTtcbiAgICAgICAgICAgICAgICAgICAgc2Vzcy50ZXJtaW5hdGUoKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3Rlcm1pbmF0ZSBwZWVyIHdpdGggamlkJywgc2Vzcy5zaWQsIGppZCk7XG4gICAgICAgICAgICAgICAgICAgIGRlbGV0ZSB0aGlzLnNlc3Npb25zW3Nlc3Muc2lkXTtcbiAgICAgICAgICAgICAgICAgICAgZGVsZXRlIHRoaXMuamlkMnNlc3Npb25bamlkXTtcbiAgICAgICAgICAgICAgICAgICAgJChkb2N1bWVudCkudHJpZ2dlcignY2FsbHRlcm1pbmF0ZWQuamluZ2xlJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIFtzZXNzLnNpZCwgamlkLCAna2lja2VkJ10pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgZ2V0U3R1bkFuZFR1cm5DcmVkZW50aWFsczogZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgLy8gZ2V0IHN0dW4gYW5kIHR1cm4gY29uZmlndXJhdGlvbiBmcm9tIHNlcnZlciB2aWEgeGVwLTAyMTVcbiAgICAgICAgICAgIC8vIHVzZXMgdGltZS1saW1pdGVkIGNyZWRlbnRpYWxzIGFzIGRlc2NyaWJlZCBpblxuICAgICAgICAgICAgLy8gaHR0cDovL3Rvb2xzLmlldGYub3JnL2h0bWwvZHJhZnQtdWJlcnRpLWJlaGF2ZS10dXJuLXJlc3QtMDBcbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyBzZWUgaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC9wcm9zb2R5LW1vZHVsZXMvc291cmNlL2Jyb3dzZS9tb2RfdHVybmNyZWRlbnRpYWxzL21vZF90dXJuY3JlZGVudGlhbHMubHVhXG4gICAgICAgICAgICAvLyBmb3IgYSBwcm9zb2R5IG1vZHVsZSB3aGljaCBpbXBsZW1lbnRzIHRoaXNcbiAgICAgICAgICAgIC8vXG4gICAgICAgICAgICAvLyBjdXJyZW50bHksIHRoaXMgZG9lc24ndCB3b3JrIHdpdGggdXBkYXRlSWNlIGFuZCB0aGVyZWZvcmUgY3JlZGVudGlhbHMgd2l0aCBhIGxvbmdcbiAgICAgICAgICAgIC8vIHZhbGlkaXR5IGhhdmUgdG8gYmUgZmV0Y2hlZCBiZWZvcmUgY3JlYXRpbmcgdGhlIHBlZXJjb25uZWN0aW9uXG4gICAgICAgICAgICAvLyBUT0RPOiBpbXBsZW1lbnQgcmVmcmVzaCB2aWEgdXBkYXRlSWNlIGFzIGRlc2NyaWJlZCBpblxuICAgICAgICAgICAgLy8gICAgICBodHRwczovL2NvZGUuZ29vZ2xlLmNvbS9wL3dlYnJ0Yy9pc3N1ZXMvZGV0YWlsP2lkPTE2NTBcbiAgICAgICAgICAgIHZhciBzZWxmID0gdGhpcztcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kSVEoXG4gICAgICAgICAgICAgICAgJGlxKHt0eXBlOiAnZ2V0JywgdG86IHRoaXMuY29ubmVjdGlvbi5kb21haW59KVxuICAgICAgICAgICAgICAgICAgICAuYygnc2VydmljZXMnLCB7eG1sbnM6ICd1cm46eG1wcDpleHRkaXNjbzoxJ30pLmMoJ3NlcnZpY2UnLCB7aG9zdDogJ3R1cm4uJyArIHRoaXMuY29ubmVjdGlvbi5kb21haW59KSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAocmVzKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBpY2VzZXJ2ZXJzID0gW107XG4gICAgICAgICAgICAgICAgICAgICQocmVzKS5maW5kKCc+c2VydmljZXM+c2VydmljZScpLmVhY2goZnVuY3Rpb24gKGlkeCwgZWwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGVsID0gJChlbCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZGljdCA9IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHR5cGUgPSBlbC5hdHRyKCd0eXBlJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzd2l0Y2ggKHR5cGUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdzdHVuJzpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGljdC51cmwgPSAnc3R1bjonICsgZWwuYXR0cignaG9zdCcpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoZWwuYXR0cigncG9ydCcpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWN0LnVybCArPSAnOicgKyBlbC5hdHRyKCdwb3J0Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNlc2VydmVycy5wdXNoKGRpY3QpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICd0dXJuJzpcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYXNlICd0dXJucyc6XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpY3QudXJsID0gdHlwZSArICc6JztcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsLmF0dHIoJ3VzZXJuYW1lJykpIHsgLy8gaHR0cHM6Ly9jb2RlLmdvb2dsZS5jb20vcC93ZWJydGMvaXNzdWVzL2RldGFpbD9pZD0xNTA4XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAobmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgvQ2hyb20oZXxpdW0pXFwvKFswLTldKylcXC4vKSAmJiBwYXJzZUludChuYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKC9DaHJvbShlfGl1bSlcXC8oWzAtOV0rKVxcLi8pWzJdLCAxMCkgPCAyOCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpY3QudXJsICs9IGVsLmF0dHIoJ3VzZXJuYW1lJykgKyAnQCc7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpY3QudXNlcm5hbWUgPSBlbC5hdHRyKCd1c2VybmFtZScpOyAvLyBvbmx5IHdvcmtzIGluIE0yOFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpY3QudXJsICs9IGVsLmF0dHIoJ2hvc3QnKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsLmF0dHIoJ3BvcnQnKSAmJiBlbC5hdHRyKCdwb3J0JykgIT0gJzM0NzgnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWN0LnVybCArPSAnOicgKyBlbC5hdHRyKCdwb3J0Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsLmF0dHIoJ3RyYW5zcG9ydCcpICYmIGVsLmF0dHIoJ3RyYW5zcG9ydCcpICE9ICd1ZHAnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkaWN0LnVybCArPSAnP3RyYW5zcG9ydD0nICsgZWwuYXR0cigndHJhbnNwb3J0Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVsLmF0dHIoJ3Bhc3N3b3JkJykpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRpY3QuY3JlZGVudGlhbCA9IGVsLmF0dHIoJ3Bhc3N3b3JkJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWNlc2VydmVycy5wdXNoKGRpY3QpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgIHNlbGYuaWNlX2NvbmZpZy5pY2VTZXJ2ZXJzID0gaWNlc2VydmVycztcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChlcnIpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdnZXR0aW5nIHR1cm4gY3JlZGVudGlhbHMgZmFpbGVkJywgZXJyKTtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS53YXJuKCdpcyBtb2RfdHVybmNyZWRlbnRpYWxzIG9yIHNpbWlsYXIgaW5zdGFsbGVkPycpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICk7XG4gICAgICAgICAgICAvLyBpbXBsZW1lbnQgcHVzaD9cbiAgICAgICAgfSxcblxuICAgICAgICAvKipcbiAgICAgICAgICogUG9wdWxhdGVzIHRoZSBsb2cgZGF0YVxuICAgICAgICAgKi9cbiAgICAgICAgcG9wdWxhdGVEYXRhOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgZGF0YSA9IHt9O1xuICAgICAgICAgICAgT2JqZWN0LmtleXModGhpcy5zZXNzaW9ucykuZm9yRWFjaChmdW5jdGlvbiAoc2lkKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNlc3Npb24gPSB0aGlzLnNlc3Npb25zW3NpZF07XG4gICAgICAgICAgICAgICAgaWYgKHNlc3Npb24ucGVlcmNvbm5lY3Rpb24gJiYgc2Vzc2lvbi5wZWVyY29ubmVjdGlvbi51cGRhdGVMb2cpIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gRklYTUU6IHNob3VsZCBwcm9iYWJseSBiZSBhIC5kdW1wIGNhbGxcbiAgICAgICAgICAgICAgICAgICAgZGF0YVtcImppbmdsZV9cIiArIHNlc3Npb24uc2lkXSA9IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVwZGF0ZUxvZzogc2Vzc2lvbi5wZWVyY29ubmVjdGlvbi51cGRhdGVMb2csXG4gICAgICAgICAgICAgICAgICAgICAgICBzdGF0czogc2Vzc2lvbi5wZWVyY29ubmVjdGlvbi5zdGF0cyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHVybDogd2luZG93LmxvY2F0aW9uLmhyZWZcbiAgICAgICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgICAgIHJldHVybiBkYXRhO1xuICAgICAgICB9XG4gICAgfSk7XG59O1xuXG4iLCIvKiBnbG9iYWwgU3Ryb3BoZSAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoKSB7XG5cbiAgICBTdHJvcGhlLmFkZENvbm5lY3Rpb25QbHVnaW4oJ2xvZ2dlcicsIHtcbiAgICAgICAgLy8gbG9ncyByYXcgc3RhbnphcyBhbmQgbWFrZXMgdGhlbSBhdmFpbGFibGUgZm9yIGRvd25sb2FkIGFzIEpTT05cbiAgICAgICAgY29ubmVjdGlvbjogbnVsbCxcbiAgICAgICAgbG9nOiBbXSxcbiAgICAgICAgaW5pdDogZnVuY3Rpb24gKGNvbm4pIHtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbiA9IGNvbm47XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24ucmF3SW5wdXQgPSB0aGlzLmxvZ19pbmNvbWluZy5iaW5kKHRoaXMpO1xuICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnJhd091dHB1dCA9IHRoaXMubG9nX291dGdvaW5nLmJpbmQodGhpcyk7XG4gICAgICAgIH0sXG4gICAgICAgIGxvZ19pbmNvbWluZzogZnVuY3Rpb24gKHN0YW56YSkge1xuICAgICAgICAgICAgdGhpcy5sb2cucHVzaChbbmV3IERhdGUoKS5nZXRUaW1lKCksICdpbmNvbWluZycsIHN0YW56YV0pO1xuICAgICAgICB9LFxuICAgICAgICBsb2dfb3V0Z29pbmc6IGZ1bmN0aW9uIChzdGFuemEpIHtcbiAgICAgICAgICAgIHRoaXMubG9nLnB1c2goW25ldyBEYXRlKCkuZ2V0VGltZSgpLCAnb3V0Z29pbmcnLCBzdGFuemFdKTtcbiAgICAgICAgfVxuICAgIH0pO1xufTsiLCIvKiBnbG9iYWwgJCwgJGlxLCBjb25maWcsIGNvbm5lY3Rpb24sIGZvY3VzTXVjSmlkLCBmb3JjZU11dGVkLFxuICAgc2V0QXVkaW9NdXRlZCwgU3Ryb3BoZSAqL1xuLyoqXG4gKiBNb2RlcmF0ZSBjb25uZWN0aW9uIHBsdWdpbi5cbiAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbiAoWE1QUCkge1xuICAgIFN0cm9waGUuYWRkQ29ubmVjdGlvblBsdWdpbignbW9kZXJhdGUnLCB7XG4gICAgICAgIGNvbm5lY3Rpb246IG51bGwsXG4gICAgICAgIGluaXQ6IGZ1bmN0aW9uIChjb25uKSB7XG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24gPSBjb25uO1xuXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uYWRkSGFuZGxlcih0aGlzLm9uTXV0ZS5iaW5kKHRoaXMpLFxuICAgICAgICAgICAgICAgICdodHRwOi8vaml0c2kub3JnL2ppdG1lZXQvYXVkaW8nLFxuICAgICAgICAgICAgICAgICdpcScsXG4gICAgICAgICAgICAgICAgJ3NldCcsXG4gICAgICAgICAgICAgICAgbnVsbCxcbiAgICAgICAgICAgICAgICBudWxsKTtcbiAgICAgICAgfSxcbiAgICAgICAgc2V0TXV0ZTogZnVuY3Rpb24gKGppZCwgbXV0ZSkge1xuICAgICAgICAgICAgY29uc29sZS5pbmZvKFwic2V0IG11dGVcIiwgbXV0ZSk7XG4gICAgICAgICAgICB2YXIgaXFUb0ZvY3VzID0gJGlxKHt0bzogdGhpcy5jb25uZWN0aW9uLmVtdWMuZm9jdXNNdWNKaWQsIHR5cGU6ICdzZXQnfSlcbiAgICAgICAgICAgICAgICAuYygnbXV0ZScsIHtcbiAgICAgICAgICAgICAgICAgICAgeG1sbnM6ICdodHRwOi8vaml0c2kub3JnL2ppdG1lZXQvYXVkaW8nLFxuICAgICAgICAgICAgICAgICAgICBqaWQ6IGppZFxuICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgLnQobXV0ZS50b1N0cmluZygpKVxuICAgICAgICAgICAgICAgIC51cCgpO1xuXG4gICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uc2VuZElRKFxuICAgICAgICAgICAgICAgIGlxVG9Gb2N1cyxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzZXQgbXV0ZScsIHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgY29uc29sZS5sb2coJ3NldCBtdXRlIGVycm9yJywgZXJyb3IpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICB9LFxuICAgICAgICBvbk11dGU6IGZ1bmN0aW9uIChpcSkge1xuICAgICAgICAgICAgdmFyIGZyb20gPSBpcS5nZXRBdHRyaWJ1dGUoJ2Zyb20nKTtcbiAgICAgICAgICAgIGlmIChmcm9tICE9PSB0aGlzLmNvbm5lY3Rpb24uZW11Yy5mb2N1c011Y0ppZCkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUud2FybihcIklnbm9yZWQgbXV0ZSBmcm9tIG5vbiBmb2N1cyBwZWVyXCIpO1xuICAgICAgICAgICAgICAgIHJldHVybiBmYWxzZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBtdXRlID0gJChpcSkuZmluZCgnbXV0ZScpO1xuICAgICAgICAgICAgaWYgKG11dGUubGVuZ3RoKSB7XG4gICAgICAgICAgICAgICAgdmFyIGRvTXV0ZUF1ZGlvID0gbXV0ZS50ZXh0KCkgPT09IFwidHJ1ZVwiO1xuICAgICAgICAgICAgICAgIEFQUC5VSS5zZXRBdWRpb011dGVkKGRvTXV0ZUF1ZGlvKTtcbiAgICAgICAgICAgICAgICBYTVBQLmZvcmNlTXV0ZWQgPSBkb011dGVBdWRpbztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiB0cnVlO1xuICAgICAgICB9LFxuICAgICAgICBlamVjdDogZnVuY3Rpb24gKGppZCkge1xuICAgICAgICAgICAgLy8gV2UncmUgbm90IHRoZSBmb2N1cywgc28gY2FuJ3QgdGVybWluYXRlXG4gICAgICAgICAgICAvL2Nvbm5lY3Rpb24uamluZ2xlLnRlcm1pbmF0ZVJlbW90ZUJ5SmlkKGppZCwgJ2tpY2snKTtcbiAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5lbXVjLmtpY2soamlkKTtcbiAgICAgICAgfVxuICAgIH0pO1xufSIsIi8qIGpzaGludCAtVzExNyAqL1xubW9kdWxlLmV4cG9ydHMgPSBmdW5jdGlvbigpIHtcbiAgICBTdHJvcGhlLmFkZENvbm5lY3Rpb25QbHVnaW4oJ3JheW8nLFxuICAgICAgICB7XG4gICAgICAgICAgICBSQVlPX1hNTE5TOiAndXJuOnhtcHA6cmF5bzoxJyxcbiAgICAgICAgICAgIGNvbm5lY3Rpb246IG51bGwsXG4gICAgICAgICAgICBpbml0OiBmdW5jdGlvbiAoY29ubikge1xuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbiA9IGNvbm47XG4gICAgICAgICAgICAgICAgaWYgKHRoaXMuY29ubmVjdGlvbi5kaXNjbykge1xuICAgICAgICAgICAgICAgICAgICB0aGlzLmNvbm5lY3Rpb24uZGlzY28uYWRkRmVhdHVyZSgndXJuOnhtcHA6cmF5bzpjbGllbnQ6MScpO1xuICAgICAgICAgICAgICAgIH1cblxuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5hZGRIYW5kbGVyKFxuICAgICAgICAgICAgICAgICAgICB0aGlzLm9uUmF5by5iaW5kKHRoaXMpLCB0aGlzLlJBWU9fWE1MTlMsICdpcScsICdzZXQnLCBudWxsLCBudWxsKTtcbiAgICAgICAgICAgIH0sXG4gICAgICAgICAgICBvblJheW86IGZ1bmN0aW9uIChpcSkge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIlJheW8gSVFcIiwgaXEpO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGRpYWw6IGZ1bmN0aW9uICh0bywgZnJvbSwgcm9vbU5hbWUsIHJvb21QYXNzKSB7XG4gICAgICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgICAgICAgIHZhciByZXEgPSAkaXEoXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdzZXQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgdG86IHRoaXMuY29ubmVjdGlvbi5lbXVjLmZvY3VzTXVjSmlkXG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgICAgIHJlcS5jKCdkaWFsJyxcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgeG1sbnM6IHRoaXMuUkFZT19YTUxOUyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvOiB0byxcbiAgICAgICAgICAgICAgICAgICAgICAgIGZyb206IGZyb21cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgcmVxLmMoJ2hlYWRlcicsXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIG5hbWU6ICdKdmJSb29tTmFtZScsXG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogcm9vbU5hbWVcbiAgICAgICAgICAgICAgICAgICAgfSkudXAoKTtcblxuICAgICAgICAgICAgICAgIGlmIChyb29tUGFzcyAhPT0gbnVsbCAmJiByb29tUGFzcy5sZW5ndGgpIHtcblxuICAgICAgICAgICAgICAgICAgICByZXEuYygnaGVhZGVyJyxcbiAgICAgICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBuYW1lOiAnSnZiUm9vbVBhc3N3b3JkJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZTogcm9vbVBhc3NcbiAgICAgICAgICAgICAgICAgICAgICAgIH0pLnVwKCk7XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdGhpcy5jb25uZWN0aW9uLnNlbmRJUShcbiAgICAgICAgICAgICAgICAgICAgcmVxLFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAocmVzdWx0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oJ0RpYWwgcmVzdWx0ICcsIHJlc3VsdCk7XG5cbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciByZXNvdXJjZSA9ICQocmVzdWx0KS5maW5kKCdyZWYnKS5hdHRyKCd1cmknKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuY2FsbF9yZXNvdXJjZSA9IHJlc291cmNlLnN1YnN0cigneG1wcDonLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFwiUmVjZWl2ZWQgY2FsbCByZXNvdXJjZTogXCIgKyB0aGlzLmNhbGxfcmVzb3VyY2UpO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbygnRGlhbCBlcnJvciAnLCBlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGhhbmdfdXA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICBpZiAoIXRoaXMuY2FsbF9yZXNvdXJjZSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXCJObyBjYWxsIGluIHByb2dyZXNzXCIpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgICAgICAgICAgfVxuXG4gICAgICAgICAgICAgICAgdmFyIHNlbGYgPSB0aGlzO1xuICAgICAgICAgICAgICAgIHZhciByZXEgPSAkaXEoXG4gICAgICAgICAgICAgICAgICAgIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHR5cGU6ICdzZXQnLFxuICAgICAgICAgICAgICAgICAgICAgICAgdG86IHRoaXMuY2FsbF9yZXNvdXJjZVxuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICByZXEuYygnaGFuZ3VwJyxcbiAgICAgICAgICAgICAgICAgICAge1xuICAgICAgICAgICAgICAgICAgICAgICAgeG1sbnM6IHRoaXMuUkFZT19YTUxOU1xuICAgICAgICAgICAgICAgICAgICB9KTtcblxuICAgICAgICAgICAgICAgIHRoaXMuY29ubmVjdGlvbi5zZW5kSVEoXG4gICAgICAgICAgICAgICAgICAgIHJlcSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKHJlc3VsdCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKCdIYW5ndXAgcmVzdWx0ICcsIHJlc3VsdCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBzZWxmLmNhbGxfcmVzb3VyY2UgPSBudWxsO1xuICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICBmdW5jdGlvbiAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNvbnNvbGUuaW5mbygnSGFuZ3VwIGVycm9yICcsIGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHNlbGYuY2FsbF9yZXNvdXJjZSA9IG51bGw7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgKTtcbn07XG4iLCIvKipcbiAqIFN0cm9waGUgbG9nZ2VyIGltcGxlbWVudGF0aW9uLiBMb2dzIGZyb20gbGV2ZWwgV0FSTiBhbmQgYWJvdmUuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gKCkge1xuXG4gICAgU3Ryb3BoZS5sb2cgPSBmdW5jdGlvbiAobGV2ZWwsIG1zZykge1xuICAgICAgICBzd2l0Y2ggKGxldmVsKSB7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuTG9nTGV2ZWwuV0FSTjpcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXCJTdHJvcGhlOiBcIiArIG1zZyk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuTG9nTGV2ZWwuRVJST1I6XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuTG9nTGV2ZWwuRkFUQUw6XG4gICAgICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIlN0cm9waGU6IFwiICsgbXNnKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgIH07XG5cbiAgICBTdHJvcGhlLmdldFN0YXR1c1N0cmluZyA9IGZ1bmN0aW9uIChzdGF0dXMpIHtcbiAgICAgICAgc3dpdGNoIChzdGF0dXMpIHtcbiAgICAgICAgICAgIGNhc2UgU3Ryb3BoZS5TdGF0dXMuRVJST1I6XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiRVJST1JcIjtcbiAgICAgICAgICAgIGNhc2UgU3Ryb3BoZS5TdGF0dXMuQ09OTkVDVElORzpcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJDT05ORUNUSU5HXCI7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuU3RhdHVzLkNPTk5GQUlMOlxuICAgICAgICAgICAgICAgIHJldHVybiBcIkNPTk5GQUlMXCI7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuU3RhdHVzLkFVVEhFTlRJQ0FUSU5HOlxuICAgICAgICAgICAgICAgIHJldHVybiBcIkFVVEhFTlRJQ0FUSU5HXCI7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuU3RhdHVzLkFVVEhGQUlMOlxuICAgICAgICAgICAgICAgIHJldHVybiBcIkFVVEhGQUlMXCI7XG4gICAgICAgICAgICBjYXNlIFN0cm9waGUuU3RhdHVzLkNPTk5FQ1RFRDpcbiAgICAgICAgICAgICAgICByZXR1cm4gXCJDT05ORUNURURcIjtcbiAgICAgICAgICAgIGNhc2UgU3Ryb3BoZS5TdGF0dXMuRElTQ09OTkVDVEVEOlxuICAgICAgICAgICAgICAgIHJldHVybiBcIkRJU0NPTk5FQ1RFRFwiO1xuICAgICAgICAgICAgY2FzZSBTdHJvcGhlLlN0YXR1cy5ESVNDT05ORUNUSU5HOlxuICAgICAgICAgICAgICAgIHJldHVybiBcIkRJU0NPTk5FQ1RJTkdcIjtcbiAgICAgICAgICAgIGNhc2UgU3Ryb3BoZS5TdGF0dXMuQVRUQUNIRUQ6XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwiQVRUQUNIRURcIjtcbiAgICAgICAgICAgIGRlZmF1bHQ6XG4gICAgICAgICAgICAgICAgcmV0dXJuIFwidW5rbm93blwiO1xuICAgICAgICB9XG4gICAgfTtcbn07XG4iLCJ2YXIgTW9kZXJhdG9yID0gcmVxdWlyZShcIi4vbW9kZXJhdG9yXCIpO1xudmFyIEV2ZW50RW1pdHRlciA9IHJlcXVpcmUoXCJldmVudHNcIik7XG52YXIgUmVjb3JkaW5nID0gcmVxdWlyZShcIi4vcmVjb3JkaW5nXCIpO1xudmFyIFNEUCA9IHJlcXVpcmUoXCIuL1NEUFwiKTtcbnZhciBQYWtvID0gcmVxdWlyZShcInBha29cIik7XG52YXIgU3RyZWFtRXZlbnRUeXBlcyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL1JUQy9TdHJlYW1FdmVudFR5cGVzXCIpO1xudmFyIFVJRXZlbnRzID0gcmVxdWlyZShcIi4uLy4uL3NlcnZpY2UvVUkvVUlFdmVudHNcIik7XG52YXIgWE1QUEV2ZW50cyA9IHJlcXVpcmUoXCIuLi8uLi9zZXJ2aWNlL3htcHAvWE1QUEV2ZW50c1wiKTtcblxudmFyIGV2ZW50RW1pdHRlciA9IG5ldyBFdmVudEVtaXR0ZXIoKTtcbnZhciBjb25uZWN0aW9uID0gbnVsbDtcbnZhciBhdXRoZW50aWNhdGVkVXNlciA9IGZhbHNlO1xuXG5mdW5jdGlvbiBjb25uZWN0KGppZCwgcGFzc3dvcmQsIHVpQ3JlZGVudGlhbHMpIHtcbiAgICB2YXIgYm9zaFxuICAgICAgICA9ICh1aUNyZWRlbnRpYWxzICYmIHVpQ3JlZGVudGlhbHMuYm9zaD8gdWlDcmVkZW50aWFscy5ib3NoIDogbnVsbClcbiAgICAgICAgfHwgY29uZmlnLmJvc2ggfHwgJy9odHRwLWJpbmQnO1xuICAgIGNvbm5lY3Rpb24gPSBuZXcgU3Ryb3BoZS5Db25uZWN0aW9uKGJvc2gpO1xuICAgIE1vZGVyYXRvci5zZXRDb25uZWN0aW9uKGNvbm5lY3Rpb24pO1xuXG4gICAgaWYodWlDcmVkZW50aWFscykge1xuICAgICAgICB2YXIgZW1haWwgPSB1aUNyZWRlbnRpYWxzLmVtYWlsO1xuICAgICAgICB2YXIgZGlzcGxheU5hbWUgPSB1aUNyZWRlbnRpYWxzLmRpc3BsYXlOYW1lO1xuICAgICAgICBpZiAoZW1haWwpIHtcbiAgICAgICAgICAgIGNvbm5lY3Rpb24uZW11Yy5hZGRFbWFpbFRvUHJlc2VuY2UoZW1haWwpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZFVzZXJJZFRvUHJlc2VuY2UodWlDcmVkZW50aWFscy51aWQpO1xuICAgICAgICB9XG4gICAgICAgIGlmIChkaXNwbGF5TmFtZSkge1xuICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZERpc3BsYXlOYW1lVG9QcmVzZW5jZShkaXNwbGF5TmFtZSk7XG4gICAgICAgIH1cbiAgICB9XG5cbiAgICBpZiAoY29ubmVjdGlvbi5kaXNjbykge1xuICAgICAgICAvLyBmb3IgY2hyb21lLCBhZGQgbXVsdGlzdHJlYW0gY2FwXG4gICAgfVxuICAgIGNvbm5lY3Rpb24uamluZ2xlLnBjX2NvbnN0cmFpbnRzID0gQVBQLlJUQy5nZXRQQ0NvbnN0cmFpbnRzKCk7XG4gICAgaWYgKGNvbmZpZy51c2VJUHY2KSB7XG4gICAgICAgIC8vIGh0dHBzOi8vY29kZS5nb29nbGUuY29tL3Avd2VicnRjL2lzc3Vlcy9kZXRhaWw/aWQ9MjgyOFxuICAgICAgICBpZiAoIWNvbm5lY3Rpb24uamluZ2xlLnBjX2NvbnN0cmFpbnRzLm9wdGlvbmFsKVxuICAgICAgICAgICAgY29ubmVjdGlvbi5qaW5nbGUucGNfY29uc3RyYWludHMub3B0aW9uYWwgPSBbXTtcbiAgICAgICAgY29ubmVjdGlvbi5qaW5nbGUucGNfY29uc3RyYWludHMub3B0aW9uYWwucHVzaCh7Z29vZ0lQdjY6IHRydWV9KTtcbiAgICB9XG5cbiAgICBpZighcGFzc3dvcmQpXG4gICAgICAgIHBhc3N3b3JkID0gdWlDcmVkZW50aWFscy5wYXNzd29yZDtcblxuICAgIHZhciBhbm9ueW1vdXNDb25uZWN0aW9uRmFpbGVkID0gZmFsc2U7XG4gICAgY29ubmVjdGlvbi5jb25uZWN0KGppZCwgcGFzc3dvcmQsIGZ1bmN0aW9uIChzdGF0dXMsIG1zZykge1xuICAgICAgICBjb25zb2xlLmxvZygnU3Ryb3BoZSBzdGF0dXMgY2hhbmdlZCB0bycsXG4gICAgICAgICAgICBTdHJvcGhlLmdldFN0YXR1c1N0cmluZyhzdGF0dXMpKTtcbiAgICAgICAgaWYgKHN0YXR1cyA9PT0gU3Ryb3BoZS5TdGF0dXMuQ09OTkVDVEVEKSB7XG4gICAgICAgICAgICBpZiAoY29uZmlnLnVzZVN0dW5UdXJuKSB7XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5qaW5nbGUuZ2V0U3R1bkFuZFR1cm5DcmVkZW50aWFscygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgQVBQLlVJLmRpc2FibGVDb25uZWN0KCk7XG5cbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIk15IEphYmJlciBJRDogXCIgKyBjb25uZWN0aW9uLmppZCk7XG5cbiAgICAgICAgICAgIGlmKHBhc3N3b3JkKVxuICAgICAgICAgICAgICAgIGF1dGhlbnRpY2F0ZWRVc2VyID0gdHJ1ZTtcbiAgICAgICAgICAgIG1heWJlRG9Kb2luKCk7XG4gICAgICAgIH0gZWxzZSBpZiAoc3RhdHVzID09PSBTdHJvcGhlLlN0YXR1cy5DT05ORkFJTCkge1xuICAgICAgICAgICAgaWYobXNnID09PSAneC1zdHJvcGhlLWJhZC1ub24tYW5vbi1qaWQnKSB7XG4gICAgICAgICAgICAgICAgYW5vbnltb3VzQ29ubmVjdGlvbkZhaWxlZCA9IHRydWU7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSBpZiAoc3RhdHVzID09PSBTdHJvcGhlLlN0YXR1cy5ESVNDT05ORUNURUQpIHtcbiAgICAgICAgICAgIGlmKGFub255bW91c0Nvbm5lY3Rpb25GYWlsZWQpIHtcbiAgICAgICAgICAgICAgICAvLyBwcm9tcHQgdXNlciBmb3IgdXNlcm5hbWUgYW5kIHBhc3N3b3JkXG4gICAgICAgICAgICAgICAgWE1QUC5wcm9tcHRMb2dpbigpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2UgaWYgKHN0YXR1cyA9PT0gU3Ryb3BoZS5TdGF0dXMuQVVUSEZBSUwpIHtcbiAgICAgICAgICAgIC8vIHdyb25nIHBhc3N3b3JkIG9yIHVzZXJuYW1lLCBwcm9tcHQgdXNlclxuICAgICAgICAgICAgWE1QUC5wcm9tcHRMb2dpbigpO1xuXG4gICAgICAgIH1cbiAgICB9KTtcbn1cblxuXG5cbmZ1bmN0aW9uIG1heWJlRG9Kb2luKCkge1xuICAgIGlmIChjb25uZWN0aW9uICYmIGNvbm5lY3Rpb24uY29ubmVjdGVkICYmXG4gICAgICAgIFN0cm9waGUuZ2V0UmVzb3VyY2VGcm9tSmlkKGNvbm5lY3Rpb24uamlkKVxuICAgICAgICAmJiAoQVBQLlJUQy5sb2NhbEF1ZGlvIHx8IEFQUC5SVEMubG9jYWxWaWRlbykpIHtcbiAgICAgICAgLy8gLmNvbm5lY3RlZCBpcyB0cnVlIHdoaWxlIGNvbm5lY3Rpbmc/XG4gICAgICAgIGRvSm9pbigpO1xuICAgIH1cbn1cblxuZnVuY3Rpb24gZG9Kb2luKCkge1xuICAgIHZhciByb29tTmFtZSA9IEFQUC5VSS5nZW5lcmF0ZVJvb21OYW1lKCk7XG5cbiAgICBNb2RlcmF0b3IuYWxsb2NhdGVDb25mZXJlbmNlRm9jdXMoXG4gICAgICAgIHJvb21OYW1lLCBBUFAuVUkuY2hlY2tGb3JOaWNrbmFtZUFuZEpvaW4pO1xufVxuXG5mdW5jdGlvbiBpbml0U3Ryb3BoZVBsdWdpbnMoKVxue1xuICAgIHJlcXVpcmUoXCIuL3N0cm9waGUuZW11Y1wiKShYTVBQLCBldmVudEVtaXR0ZXIpO1xuICAgIHJlcXVpcmUoXCIuL3N0cm9waGUuamluZ2xlXCIpKFhNUFAsIGV2ZW50RW1pdHRlcik7XG4gICAgcmVxdWlyZShcIi4vc3Ryb3BoZS5tb2RlcmF0ZVwiKShYTVBQKTtcbiAgICByZXF1aXJlKFwiLi9zdHJvcGhlLnV0aWxcIikoKTtcbiAgICByZXF1aXJlKFwiLi9zdHJvcGhlLnJheW9cIikoKTtcbiAgICByZXF1aXJlKFwiLi9zdHJvcGhlLmxvZ2dlclwiKSgpO1xufVxuXG5mdW5jdGlvbiByZWdpc3Rlckxpc3RlbmVycygpIHtcbiAgICBBUFAuUlRDLmFkZFN0cmVhbUxpc3RlbmVyKG1heWJlRG9Kb2luLFxuICAgICAgICBTdHJlYW1FdmVudFR5cGVzLkVWRU5UX1RZUEVfTE9DQUxfQ1JFQVRFRCk7XG4gICAgQVBQLlVJLmFkZExpc3RlbmVyKFVJRXZlbnRzLk5JQ0tOQU1FX0NIQU5HRUQsIGZ1bmN0aW9uIChuaWNrbmFtZSkge1xuICAgICAgICBYTVBQLmFkZFRvUHJlc2VuY2UoXCJkaXNwbGF5TmFtZVwiLCBuaWNrbmFtZSk7XG4gICAgfSk7XG59XG5cbmZ1bmN0aW9uIHNldHVwRXZlbnRzKCkge1xuICAgICQod2luZG93KS5iaW5kKCdiZWZvcmV1bmxvYWQnLCBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmIChjb25uZWN0aW9uICYmIGNvbm5lY3Rpb24uY29ubmVjdGVkKSB7XG4gICAgICAgICAgICAvLyBlbnN1cmUgc2lnbm91dFxuICAgICAgICAgICAgJC5hamF4KHtcbiAgICAgICAgICAgICAgICB0eXBlOiAnUE9TVCcsXG4gICAgICAgICAgICAgICAgdXJsOiBjb25maWcuYm9zaCxcbiAgICAgICAgICAgICAgICBhc3luYzogZmFsc2UsXG4gICAgICAgICAgICAgICAgY2FjaGU6IGZhbHNlLFxuICAgICAgICAgICAgICAgIGNvbnRlbnRUeXBlOiAnYXBwbGljYXRpb24veG1sJyxcbiAgICAgICAgICAgICAgICBkYXRhOiBcIjxib2R5IHJpZD0nXCIgKyAoY29ubmVjdGlvbi5yaWQgfHwgY29ubmVjdGlvbi5fcHJvdG8ucmlkKVxuICAgICAgICAgICAgICAgICAgICArIFwiJyB4bWxucz0naHR0cDovL2phYmJlci5vcmcvcHJvdG9jb2wvaHR0cGJpbmQnIHNpZD0nXCJcbiAgICAgICAgICAgICAgICAgICAgKyAoY29ubmVjdGlvbi5zaWQgfHwgY29ubmVjdGlvbi5fcHJvdG8uc2lkKVxuICAgICAgICAgICAgICAgICAgICArIFwiJyB0eXBlPSd0ZXJtaW5hdGUnPlwiICtcbiAgICAgICAgICAgICAgICAgICAgXCI8cHJlc2VuY2UgeG1sbnM9J2phYmJlcjpjbGllbnQnIHR5cGU9J3VuYXZhaWxhYmxlJy8+XCIgK1xuICAgICAgICAgICAgICAgICAgICBcIjwvYm9keT5cIixcbiAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnc2lnbmVkIG91dCcpO1xuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhkYXRhKTtcbiAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgIGVycm9yOiBmdW5jdGlvbiAoWE1MSHR0cFJlcXVlc3QsIHRleHRTdGF0dXMsIGVycm9yVGhyb3duKSB7XG4gICAgICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdzaWdub3V0IGVycm9yJyxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0ZXh0U3RhdHVzICsgJyAoJyArIGVycm9yVGhyb3duICsgJyknKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfVxuICAgICAgICBYTVBQLmRpc3Bvc2VDb25mZXJlbmNlKHRydWUpO1xuICAgIH0pO1xufVxuXG52YXIgWE1QUCA9IHtcbiAgICBzZXNzaW9uVGVybWluYXRlZDogZmFsc2UsXG4gICAgLyoqXG4gICAgICogUmVtZW1iZXJzIGlmIHdlIHdlcmUgbXV0ZWQgYnkgdGhlIGZvY3VzLlxuICAgICAqIEB0eXBlIHtib29sZWFufVxuICAgICAqL1xuICAgIGZvcmNlTXV0ZWQ6IGZhbHNlLFxuICAgIHN0YXJ0OiBmdW5jdGlvbiAodWlDcmVkZW50aWFscykge1xuICAgICAgICBzZXR1cEV2ZW50cygpO1xuICAgICAgICBpbml0U3Ryb3BoZVBsdWdpbnMoKTtcbiAgICAgICAgcmVnaXN0ZXJMaXN0ZW5lcnMoKTtcbiAgICAgICAgTW9kZXJhdG9yLmluaXQodGhpcywgZXZlbnRFbWl0dGVyKTtcbiAgICAgICAgdmFyIGNvbmZpZ0RvbWFpbiA9IGNvbmZpZy5ob3N0cy5hbm9ueW1vdXNkb21haW4gfHwgY29uZmlnLmhvc3RzLmRvbWFpbjtcbiAgICAgICAgLy8gRm9yY2UgYXV0aGVudGljYXRlZCBkb21haW4gaWYgcm9vbSBpcyBhcHBlbmRlZCB3aXRoICc/bG9naW49dHJ1ZSdcbiAgICAgICAgaWYgKGNvbmZpZy5ob3N0cy5hbm9ueW1vdXNkb21haW4gJiZcbiAgICAgICAgICAgIHdpbmRvdy5sb2NhdGlvbi5zZWFyY2guaW5kZXhPZihcImxvZ2luPXRydWVcIikgIT09IC0xKSB7XG4gICAgICAgICAgICBjb25maWdEb21haW4gPSBjb25maWcuaG9zdHMuZG9tYWluO1xuICAgICAgICB9XG4gICAgICAgIHZhciBqaWQgPSB1aUNyZWRlbnRpYWxzLmppZCB8fCBjb25maWdEb21haW4gfHwgd2luZG93LmxvY2F0aW9uLmhvc3RuYW1lO1xuICAgICAgICBjb25uZWN0KGppZCwgbnVsbCwgdWlDcmVkZW50aWFscyk7XG4gICAgfSxcbiAgICBwcm9tcHRMb2dpbjogZnVuY3Rpb24gKCkge1xuICAgICAgICBBUFAuVUkuc2hvd0xvZ2luUG9wdXAoY29ubmVjdCk7XG4gICAgfSxcbiAgICBqb2luUm9vbTogZnVuY3Rpb24ocm9vbU5hbWUsIHVzZU5pY2tzLCBuaWNrKVxuICAgIHtcbiAgICAgICAgdmFyIHJvb21qaWQ7XG4gICAgICAgIHJvb21qaWQgPSByb29tTmFtZTtcblxuICAgICAgICBpZiAodXNlTmlja3MpIHtcbiAgICAgICAgICAgIGlmIChuaWNrKSB7XG4gICAgICAgICAgICAgICAgcm9vbWppZCArPSAnLycgKyBuaWNrO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByb29tamlkICs9ICcvJyArIFN0cm9waGUuZ2V0Tm9kZUZyb21KaWQoY29ubmVjdGlvbi5qaWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9IGVsc2Uge1xuXG4gICAgICAgICAgICB2YXIgdG1wSmlkID0gU3Ryb3BoZS5nZXROb2RlRnJvbUppZChjb25uZWN0aW9uLmppZCk7XG5cbiAgICAgICAgICAgIGlmKCFhdXRoZW50aWNhdGVkVXNlcilcbiAgICAgICAgICAgICAgICB0bXBKaWQgPSB0bXBKaWQuc3Vic3RyKDAsIDgpO1xuXG4gICAgICAgICAgICByb29tamlkICs9ICcvJyArIHRtcEppZDtcbiAgICAgICAgfVxuICAgICAgICBjb25uZWN0aW9uLmVtdWMuZG9Kb2luKHJvb21qaWQpO1xuICAgIH0sXG4gICAgbXlKaWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgaWYoIWNvbm5lY3Rpb24pXG4gICAgICAgICAgICByZXR1cm4gbnVsbDtcbiAgICAgICAgcmV0dXJuIGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQ7XG4gICAgfSxcbiAgICBteVJlc291cmNlOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmKCFjb25uZWN0aW9uIHx8ICEgY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZClcbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICByZXR1cm4gU3Ryb3BoZS5nZXRSZXNvdXJjZUZyb21KaWQoY29ubmVjdGlvbi5lbXVjLm15cm9vbWppZCk7XG4gICAgfSxcbiAgICBkaXNwb3NlQ29uZmVyZW5jZTogZnVuY3Rpb24gKG9uVW5sb2FkKSB7XG4gICAgICAgIGV2ZW50RW1pdHRlci5lbWl0KFhNUFBFdmVudHMuRElTUE9TRV9DT05GRVJFTkNFLCBvblVubG9hZCk7XG4gICAgICAgIHZhciBoYW5kbGVyID0gY29ubmVjdGlvbi5qaW5nbGUuYWN0aXZlY2FsbDtcbiAgICAgICAgaWYgKGhhbmRsZXIgJiYgaGFuZGxlci5wZWVyY29ubmVjdGlvbikge1xuICAgICAgICAgICAgLy8gRklYTUU6IHByb2JhYmx5IHJlbW92aW5nIHN0cmVhbXMgaXMgbm90IHJlcXVpcmVkIGFuZCBjbG9zZSgpIHNob3VsZFxuICAgICAgICAgICAgLy8gYmUgZW5vdWdoXG4gICAgICAgICAgICBpZiAoQVBQLlJUQy5sb2NhbEF1ZGlvKSB7XG4gICAgICAgICAgICAgICAgaGFuZGxlci5wZWVyY29ubmVjdGlvbi5yZW1vdmVTdHJlYW0oQVBQLlJUQy5sb2NhbEF1ZGlvLmdldE9yaWdpbmFsU3RyZWFtKCksIG9uVW5sb2FkKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmIChBUFAuUlRDLmxvY2FsVmlkZW8pIHtcbiAgICAgICAgICAgICAgICBoYW5kbGVyLnBlZXJjb25uZWN0aW9uLnJlbW92ZVN0cmVhbShBUFAuUlRDLmxvY2FsVmlkZW8uZ2V0T3JpZ2luYWxTdHJlYW0oKSwgb25VbmxvYWQpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaGFuZGxlci5wZWVyY29ubmVjdGlvbi5jbG9zZSgpO1xuICAgICAgICB9XG4gICAgICAgIGNvbm5lY3Rpb24uamluZ2xlLmFjdGl2ZWNhbGwgPSBudWxsO1xuICAgICAgICBpZighb25VbmxvYWQpXG4gICAgICAgIHtcbiAgICAgICAgICAgIHRoaXMuc2Vzc2lvblRlcm1pbmF0ZWQgPSB0cnVlO1xuICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmRvTGVhdmUoKTtcbiAgICAgICAgfVxuICAgIH0sXG4gICAgYWRkTGlzdGVuZXI6IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKVxuICAgIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLm9uKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9LFxuICAgIHJlbW92ZUxpc3RlbmVyOiBmdW5jdGlvbiAodHlwZSwgbGlzdGVuZXIpIHtcbiAgICAgICAgZXZlbnRFbWl0dGVyLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9LFxuICAgIGFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzOiBmdW5jdGlvbihyb29tTmFtZSwgY2FsbGJhY2spIHtcbiAgICAgICAgTW9kZXJhdG9yLmFsbG9jYXRlQ29uZmVyZW5jZUZvY3VzKHJvb21OYW1lLCBjYWxsYmFjayk7XG4gICAgfSxcbiAgICBpc01vZGVyYXRvcjogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gTW9kZXJhdG9yLmlzTW9kZXJhdG9yKCk7XG4gICAgfSxcbiAgICBpc1NpcEdhdGV3YXlFbmFibGVkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBNb2RlcmF0b3IuaXNTaXBHYXRld2F5RW5hYmxlZCgpO1xuICAgIH0sXG4gICAgaXNFeHRlcm5hbEF1dGhFbmFibGVkOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHJldHVybiBNb2RlcmF0b3IuaXNFeHRlcm5hbEF1dGhFbmFibGVkKCk7XG4gICAgfSxcbiAgICBzd2l0Y2hTdHJlYW1zOiBmdW5jdGlvbiAoc3RyZWFtLCBvbGRTdHJlYW0sIGNhbGxiYWNrKSB7XG4gICAgICAgIGlmIChjb25uZWN0aW9uICYmIGNvbm5lY3Rpb24uamluZ2xlLmFjdGl2ZWNhbGwpIHtcbiAgICAgICAgICAgIC8vIEZJWE1FOiB3aWxsIGJsb2NrIHN3aXRjaEluUHJvZ3Jlc3Mgb24gdHJ1ZSB2YWx1ZSBpbiBjYXNlIG9mIGV4Y2VwdGlvblxuICAgICAgICAgICAgY29ubmVjdGlvbi5qaW5nbGUuYWN0aXZlY2FsbC5zd2l0Y2hTdHJlYW1zKHN0cmVhbSwgb2xkU3RyZWFtLCBjYWxsYmFjayk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBXZSBhcmUgZG9uZSBpbW1lZGlhdGVseVxuICAgICAgICAgICAgY29uc29sZS5lcnJvcihcIk5vIGNvbmZlcmVuY2UgaGFuZGxlclwiKTtcbiAgICAgICAgICAgIEFQUC5VSS5tZXNzYWdlSGFuZGxlci5zaG93RXJyb3IoJ0Vycm9yJyxcbiAgICAgICAgICAgICAgICAnVW5hYmxlIHRvIHN3aXRjaCB2aWRlbyBzdHJlYW0uJyk7XG4gICAgICAgICAgICBjYWxsYmFjaygpO1xuICAgICAgICB9XG4gICAgfSxcbiAgICBzZXRWaWRlb011dGU6IGZ1bmN0aW9uIChtdXRlLCBjYWxsYmFjaywgb3B0aW9ucykge1xuICAgICAgIGlmKGNvbm5lY3Rpb24gJiYgQVBQLlJUQy5sb2NhbFZpZGVvICYmIGNvbm5lY3Rpb24uamluZ2xlLmFjdGl2ZWNhbGwpXG4gICAgICAge1xuICAgICAgICAgICBjb25uZWN0aW9uLmppbmdsZS5hY3RpdmVjYWxsLnNldFZpZGVvTXV0ZShtdXRlLCBjYWxsYmFjaywgb3B0aW9ucyk7XG4gICAgICAgfVxuICAgIH0sXG4gICAgc2V0QXVkaW9NdXRlOiBmdW5jdGlvbiAobXV0ZSwgY2FsbGJhY2spIHtcbiAgICAgICAgaWYgKCEoY29ubmVjdGlvbiAmJiBBUFAuUlRDLmxvY2FsQXVkaW8pKSB7XG4gICAgICAgICAgICByZXR1cm4gZmFsc2U7XG4gICAgICAgIH1cblxuXG4gICAgICAgIGlmICh0aGlzLmZvcmNlTXV0ZWQgJiYgIW11dGUpIHtcbiAgICAgICAgICAgIGNvbnNvbGUuaW5mbyhcIkFza2luZyBmb2N1cyBmb3IgdW5tdXRlXCIpO1xuICAgICAgICAgICAgY29ubmVjdGlvbi5tb2RlcmF0ZS5zZXRNdXRlKGNvbm5lY3Rpb24uZW11Yy5teXJvb21qaWQsIG11dGUpO1xuICAgICAgICAgICAgLy8gRklYTUU6IHdhaXQgZm9yIHJlc3VsdCBiZWZvcmUgcmVzZXR0aW5nIG11dGVkIHN0YXR1c1xuICAgICAgICAgICAgdGhpcy5mb3JjZU11dGVkID0gZmFsc2U7XG4gICAgICAgIH1cblxuICAgICAgICBpZiAobXV0ZSA9PSBBUFAuUlRDLmxvY2FsQXVkaW8uaXNNdXRlZCgpKSB7XG4gICAgICAgICAgICAvLyBOb3RoaW5nIHRvIGRvXG4gICAgICAgICAgICByZXR1cm4gdHJ1ZTtcbiAgICAgICAgfVxuXG4gICAgICAgIC8vIEl0IGlzIG5vdCBjbGVhciB3aGF0IGlzIHRoZSByaWdodCB3YXkgdG8gaGFuZGxlIG11bHRpcGxlIHRyYWNrcy5cbiAgICAgICAgLy8gU28gYXQgbGVhc3QgbWFrZSBzdXJlIHRoYXQgdGhleSBhcmUgYWxsIG11dGVkIG9yIGFsbCB1bm11dGVkIGFuZFxuICAgICAgICAvLyB0aGF0IHdlIHNlbmQgcHJlc2VuY2UganVzdCBvbmNlLlxuICAgICAgICBBUFAuUlRDLmxvY2FsQXVkaW8ubXV0ZSgpO1xuICAgICAgICAvLyBpc011dGVkIGlzIHRoZSBvcHBvc2l0ZSBvZiBhdWRpb0VuYWJsZWRcbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZEF1ZGlvSW5mb1RvUHJlc2VuY2UobXV0ZSk7XG4gICAgICAgIGNvbm5lY3Rpb24uZW11Yy5zZW5kUHJlc2VuY2UoKTtcbiAgICAgICAgY2FsbGJhY2soKTtcbiAgICAgICAgcmV0dXJuIHRydWU7XG4gICAgfSxcbiAgICAvLyBSZWFsbHkgbXV0ZSB2aWRlbywgaS5lLiBkb250IGV2ZW4gc2VuZCBibGFjayBmcmFtZXNcbiAgICBtdXRlVmlkZW86IGZ1bmN0aW9uIChwYywgdW5tdXRlKSB7XG4gICAgICAgIC8vIEZJWE1FOiB0aGlzIHByb2JhYmx5IG5lZWRzIGFub3RoZXIgb2YgdGhvc2UgbG92ZWx5IHN0YXRlIHNhZmVndWFyZHMuLi5cbiAgICAgICAgLy8gd2hpY2ggY2hlY2tzIGZvciBpY2Vjb25uID09IGNvbm5lY3RlZCBhbmQgc2lnc3RhdGUgPT0gc3RhYmxlXG4gICAgICAgIHBjLnNldFJlbW90ZURlc2NyaXB0aW9uKHBjLnJlbW90ZURlc2NyaXB0aW9uLFxuICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgIHBjLmNyZWF0ZUFuc3dlcihcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGFuc3dlcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIHNkcCA9IG5ldyBTRFAoYW5zd2VyLnNkcCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoc2RwLm1lZGlhLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodW5tdXRlKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZHAubWVkaWFbMV0gPSBzZHAubWVkaWFbMV0ucmVwbGFjZSgnYT1yZWN2b25seScsICdhPXNlbmRyZWN2Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZWxzZVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzZHAubWVkaWFbMV0gPSBzZHAubWVkaWFbMV0ucmVwbGFjZSgnYT1zZW5kcmVjdicsICdhPXJlY3Zvbmx5Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc2RwLnJhdyA9IHNkcC5zZXNzaW9uICsgc2RwLm1lZGlhLmpvaW4oJycpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFuc3dlci5zZHAgPSBzZHAucmF3O1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgcGMuc2V0TG9jYWxEZXNjcmlwdGlvbihhbnN3ZXIsXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnbXV0ZSBTTEQgb2snKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZygnbXV0ZSBTTEQgZXJyb3InKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQVBQLlVJLm1lc3NhZ2VIYW5kbGVyLnNob3dFcnJvcignRXJyb3InLFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdPb3BzISBTb21ldGhpbmcgd2VudCB3cm9uZyBhbmQgd2UgZmFpbGVkIHRvICcgK1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICdtdXRlISAoU0xEIEZhaWx1cmUpJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgKTtcbiAgICAgICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICAgICAgZnVuY3Rpb24gKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zb2xlLmxvZyhlcnJvcik7XG4gICAgICAgICAgICAgICAgICAgICAgICBBUFAuVUkubWVzc2FnZUhhbmRsZXIuc2hvd0Vycm9yKCk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICApO1xuICAgICAgICAgICAgfSxcbiAgICAgICAgICAgIGZ1bmN0aW9uIChlcnJvcikge1xuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKCdtdXRlVmlkZW8gU1JEIGVycm9yJyk7XG4gICAgICAgICAgICAgICAgQVBQLlVJLm1lc3NhZ2VIYW5kbGVyLnNob3dFcnJvcignRXJyb3InLFxuICAgICAgICAgICAgICAgICAgICAgICAgJ09vcHMhIFNvbWV0aGluZyB3ZW50IHdyb25nIGFuZCB3ZSBmYWlsZWQgdG8gc3RvcCB2aWRlbyEnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICcoU1JEIEZhaWx1cmUpJyk7XG5cbiAgICAgICAgICAgIH1cbiAgICAgICAgKTtcbiAgICB9LFxuICAgIHRvZ2dsZVJlY29yZGluZzogZnVuY3Rpb24gKHRva2VuRW1wdHlDYWxsYmFjayxcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdGFydGluZ0NhbGxiYWNrLCBzdGFydGVkQ2FsbGJhY2spIHtcbiAgICAgICAgUmVjb3JkaW5nLnRvZ2dsZVJlY29yZGluZyh0b2tlbkVtcHR5Q2FsbGJhY2ssXG4gICAgICAgICAgICBzdGFydGluZ0NhbGxiYWNrLCBzdGFydGVkQ2FsbGJhY2ssIGNvbm5lY3Rpb24pO1xuICAgIH0sXG4gICAgYWRkVG9QcmVzZW5jZTogZnVuY3Rpb24gKG5hbWUsIHZhbHVlLCBkb250U2VuZCkge1xuICAgICAgICBzd2l0Y2ggKG5hbWUpXG4gICAgICAgIHtcbiAgICAgICAgICAgIGNhc2UgXCJkaXNwbGF5TmFtZVwiOlxuICAgICAgICAgICAgICAgIGNvbm5lY3Rpb24uZW11Yy5hZGREaXNwbGF5TmFtZVRvUHJlc2VuY2UodmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcImV0aGVycGFkXCI6XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZEV0aGVycGFkVG9QcmVzZW5jZSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwicHJlemlcIjpcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuYWRkUHJlemlUb1ByZXNlbmNlKHZhbHVlLCAwKTtcbiAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgIGNhc2UgXCJwcmV6aVNsaWRlXCI6XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZEN1cnJlbnRTbGlkZVRvUHJlc2VuY2UodmFsdWUpO1xuICAgICAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgICAgY2FzZSBcImNvbm5lY3Rpb25RdWFsaXR5XCI6XG4gICAgICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLmFkZENvbm5lY3Rpb25JbmZvVG9QcmVzZW5jZSh2YWx1ZSk7XG4gICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICBjYXNlIFwiZW1haWxcIjpcbiAgICAgICAgICAgICAgICBjb25uZWN0aW9uLmVtdWMuYWRkRW1haWxUb1ByZXNlbmNlKHZhbHVlKTtcbiAgICAgICAgICAgIGRlZmF1bHQgOlxuICAgICAgICAgICAgICAgIGNvbnNvbGUubG9nKFwiVW5rbm93biB0YWcgZm9yIHByZXNlbmNlLlwiKTtcbiAgICAgICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH1cbiAgICAgICAgaWYoIWRvbnRTZW5kKVxuICAgICAgICAgICAgY29ubmVjdGlvbi5lbXVjLnNlbmRQcmVzZW5jZSgpO1xuICAgIH0sXG4gICAgc2VuZExvZ3M6IGZ1bmN0aW9uIChkYXRhKSB7XG4gICAgICAgIGlmKCFjb25uZWN0aW9uLmVtdWMuZm9jdXNNdWNKaWQpXG4gICAgICAgICAgICByZXR1cm47XG5cbiAgICAgICAgdmFyIGRlZmxhdGUgPSB0cnVlO1xuXG4gICAgICAgIHZhciBjb250ZW50ID0gSlNPTi5zdHJpbmdpZnkoZGF0YSk7XG4gICAgICAgIGlmIChkZWZsYXRlKSB7XG4gICAgICAgICAgICBjb250ZW50ID0gU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLCBQYWtvLmRlZmxhdGVSYXcoY29udGVudCkpO1xuICAgICAgICB9XG4gICAgICAgIGNvbnRlbnQgPSBCYXNlNjQuZW5jb2RlKGNvbnRlbnQpO1xuICAgICAgICAvLyBYRVAtMDMzNy1pc2hcbiAgICAgICAgdmFyIG1lc3NhZ2UgPSAkbXNnKHt0bzogY29ubmVjdGlvbi5lbXVjLmZvY3VzTXVjSmlkLCB0eXBlOiAnbm9ybWFsJ30pO1xuICAgICAgICBtZXNzYWdlLmMoJ2xvZycsIHsgeG1sbnM6ICd1cm46eG1wcDpldmVudGxvZycsXG4gICAgICAgICAgICBpZDogJ1BlZXJDb25uZWN0aW9uU3RhdHMnfSk7XG4gICAgICAgIG1lc3NhZ2UuYygnbWVzc2FnZScpLnQoY29udGVudCkudXAoKTtcbiAgICAgICAgaWYgKGRlZmxhdGUpIHtcbiAgICAgICAgICAgIG1lc3NhZ2UuYygndGFnJywge25hbWU6IFwiZGVmbGF0ZWRcIiwgdmFsdWU6IFwidHJ1ZVwifSkudXAoKTtcbiAgICAgICAgfVxuICAgICAgICBtZXNzYWdlLnVwKCk7XG5cbiAgICAgICAgY29ubmVjdGlvbi5zZW5kKG1lc3NhZ2UpO1xuICAgIH0sXG4gICAgcG9wdWxhdGVEYXRhOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIHZhciBkYXRhID0ge307XG4gICAgICAgIGlmIChjb25uZWN0aW9uLmppbmdsZSkge1xuICAgICAgICAgICAgZGF0YSA9IGNvbm5lY3Rpb24uamluZ2xlLnBvcHVsYXRlRGF0YSgpO1xuICAgICAgICB9XG4gICAgICAgIHJldHVybiBkYXRhO1xuICAgIH0sXG4gICAgZ2V0TG9nZ2VyOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgIGlmKGNvbm5lY3Rpb24ubG9nZ2VyKVxuICAgICAgICAgICAgcmV0dXJuIGNvbm5lY3Rpb24ubG9nZ2VyLmxvZztcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgfSxcbiAgICBnZXRQcmV6aTogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gY29ubmVjdGlvbi5lbXVjLmdldFByZXppKHRoaXMubXlKaWQoKSk7XG4gICAgfSxcbiAgICByZW1vdmVQcmV6aUZyb21QcmVzZW5jZTogZnVuY3Rpb24gKCkge1xuICAgICAgICBjb25uZWN0aW9uLmVtdWMucmVtb3ZlUHJlemlGcm9tUHJlc2VuY2UoKTtcbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLnNlbmRQcmVzZW5jZSgpO1xuICAgIH0sXG4gICAgc2VuZENoYXRNZXNzYWdlOiBmdW5jdGlvbiAobWVzc2FnZSwgbmlja25hbWUpIHtcbiAgICAgICAgY29ubmVjdGlvbi5lbXVjLnNlbmRNZXNzYWdlKG1lc3NhZ2UsIG5pY2tuYW1lKTtcbiAgICB9LFxuICAgIHNldFN1YmplY3Q6IGZ1bmN0aW9uICh0b3BpYykge1xuICAgICAgICBjb25uZWN0aW9uLmVtdWMuc2V0U3ViamVjdCh0b3BpYyk7XG4gICAgfSxcbiAgICBsb2NrUm9vbTogZnVuY3Rpb24gKGtleSwgb25TdWNjZXNzLCBvbkVycm9yLCBvbk5vdFN1cHBvcnRlZCkge1xuICAgICAgICBjb25uZWN0aW9uLmVtdWMubG9ja1Jvb20oa2V5LCBvblN1Y2Nlc3MsIG9uRXJyb3IsIG9uTm90U3VwcG9ydGVkKTtcbiAgICB9LFxuICAgIGRpYWw6IGZ1bmN0aW9uICh0bywgZnJvbSwgcm9vbU5hbWUscm9vbVBhc3MpIHtcbiAgICAgICAgY29ubmVjdGlvbi5yYXlvLmRpYWwodG8sIGZyb20sIHJvb21OYW1lLHJvb21QYXNzKTtcbiAgICB9LFxuICAgIHNldE11dGU6IGZ1bmN0aW9uIChqaWQsIG11dGUpIHtcbiAgICAgICAgY29ubmVjdGlvbi5tb2RlcmF0ZS5zZXRNdXRlKGppZCwgbXV0ZSk7XG4gICAgfSxcbiAgICBlamVjdDogZnVuY3Rpb24gKGppZCkge1xuICAgICAgICBjb25uZWN0aW9uLm1vZGVyYXRlLmVqZWN0KGppZCk7XG4gICAgfSxcbiAgICBmaW5kSmlkRnJvbVJlc291cmNlOiBmdW5jdGlvbiAocmVzb3VyY2UpIHtcbiAgICAgICAgcmV0dXJuIGNvbm5lY3Rpb24uZW11Yy5maW5kSmlkRnJvbVJlc291cmNlKHJlc291cmNlKTtcbiAgICB9LFxuICAgIGdldE1lbWJlcnM6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGNvbm5lY3Rpb24uZW11Yy5tZW1iZXJzO1xuICAgIH0sXG4gICAgZ2V0SmlkRnJvbVNTUkM6IGZ1bmN0aW9uIChzc3JjKSB7XG4gICAgICAgIGlmKCFjb25uZWN0aW9uKVxuICAgICAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICAgIHJldHVybiBjb25uZWN0aW9uLmVtdWMuc3NyYzJqaWRbc3NyY107XG4gICAgfSxcbiAgICBnZXRNVUNKb2luZWQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgcmV0dXJuIGNvbm5lY3Rpb24uZW11Yy5qb2luZWQ7XG4gICAgfSxcbiAgICBnZXRTZXNzaW9uczogZnVuY3Rpb24gKCkge1xuICAgICAgICByZXR1cm4gY29ubmVjdGlvbi5qaW5nbGUuc2Vzc2lvbnM7XG4gICAgfVxuXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFhNUFA7XG4iLCIvLyBpMThuZXh0LCB2MS43Ljdcbi8vIENvcHlyaWdodCAoYykyMDE0IEphbiBNw7xobGVtYW5uIChqYW11aGwpLlxuLy8gRGlzdHJpYnV0ZWQgdW5kZXIgTUlUIGxpY2Vuc2Vcbi8vIGh0dHA6Ly9pMThuZXh0LmNvbVxuKGZ1bmN0aW9uKCkge1xuXG4gICAgLy8gYWRkIGluZGV4T2YgdG8gbm9uIEVDTUEtMjYyIHN0YW5kYXJkIGNvbXBsaWFudCBicm93c2Vyc1xuICAgIGlmICghQXJyYXkucHJvdG90eXBlLmluZGV4T2YpIHtcbiAgICAgICAgQXJyYXkucHJvdG90eXBlLmluZGV4T2YgPSBmdW5jdGlvbiAoc2VhcmNoRWxlbWVudCAvKiwgZnJvbUluZGV4ICovICkge1xuICAgICAgICAgICAgXCJ1c2Ugc3RyaWN0XCI7XG4gICAgICAgICAgICBpZiAodGhpcyA9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHQgPSBPYmplY3QodGhpcyk7XG4gICAgICAgICAgICB2YXIgbGVuID0gdC5sZW5ndGggPj4+IDA7XG4gICAgICAgICAgICBpZiAobGVuID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIG4gPSAwO1xuICAgICAgICAgICAgaWYgKGFyZ3VtZW50cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgICAgICAgbiA9IE51bWJlcihhcmd1bWVudHNbMV0pO1xuICAgICAgICAgICAgICAgIGlmIChuICE9IG4pIHsgLy8gc2hvcnRjdXQgZm9yIHZlcmlmeWluZyBpZiBpdCdzIE5hTlxuICAgICAgICAgICAgICAgICAgICBuID0gMDtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG4gIT0gMCAmJiBuICE9IEluZmluaXR5ICYmIG4gIT0gLUluZmluaXR5KSB7XG4gICAgICAgICAgICAgICAgICAgIG4gPSAobiA+IDAgfHwgLTEpICogTWF0aC5mbG9vcihNYXRoLmFicyhuKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgaWYgKG4gPj0gbGVuKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIGsgPSBuID49IDAgPyBuIDogTWF0aC5tYXgobGVuIC0gTWF0aC5hYnMobiksIDApO1xuICAgICAgICAgICAgZm9yICg7IGsgPCBsZW47IGsrKykge1xuICAgICAgICAgICAgICAgIGlmIChrIGluIHQgJiYgdFtrXSA9PT0gc2VhcmNoRWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgLy8gYWRkIGxhc3RJbmRleE9mIHRvIG5vbiBFQ01BLTI2MiBzdGFuZGFyZCBjb21wbGlhbnQgYnJvd3NlcnNcbiAgICBpZiAoIUFycmF5LnByb3RvdHlwZS5sYXN0SW5kZXhPZikge1xuICAgICAgICBBcnJheS5wcm90b3R5cGUubGFzdEluZGV4T2YgPSBmdW5jdGlvbihzZWFyY2hFbGVtZW50IC8qLCBmcm9tSW5kZXgqLykge1xuICAgICAgICAgICAgXCJ1c2Ugc3RyaWN0XCI7XG4gICAgICAgICAgICBpZiAodGhpcyA9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcigpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIHQgPSBPYmplY3QodGhpcyk7XG4gICAgICAgICAgICB2YXIgbGVuID0gdC5sZW5ndGggPj4+IDA7XG4gICAgICAgICAgICBpZiAobGVuID09PSAwKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIC0xO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgdmFyIG4gPSBsZW47XG4gICAgICAgICAgICBpZiAoYXJndW1lbnRzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICBuID0gTnVtYmVyKGFyZ3VtZW50c1sxXSk7XG4gICAgICAgICAgICAgICAgaWYgKG4gIT0gbikge1xuICAgICAgICAgICAgICAgICAgICBuID0gMDtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKG4gIT0gMCAmJiBuICE9ICgxIC8gMCkgJiYgbiAhPSAtKDEgLyAwKSkge1xuICAgICAgICAgICAgICAgICAgICBuID0gKG4gPiAwIHx8IC0xKSAqIE1hdGguZmxvb3IoTWF0aC5hYnMobikpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHZhciBrID0gbiA+PSAwID8gTWF0aC5taW4obiwgbGVuIC0gMSkgOiBsZW4gLSBNYXRoLmFicyhuKTtcbiAgICAgICAgICAgIGZvciAoOyBrID49IDA7IGstLSkge1xuICAgICAgICAgICAgICAgIGlmIChrIGluIHQgJiYgdFtrXSA9PT0gc2VhcmNoRWxlbWVudCkge1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm4gLTE7XG4gICAgICAgIH07XG4gICAgfVxuICAgIFxuICAgIC8vIEFkZCBzdHJpbmcgdHJpbSBmb3IgSUU4LlxuICAgIGlmICh0eXBlb2YgU3RyaW5nLnByb3RvdHlwZS50cmltICE9PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgIFN0cmluZy5wcm90b3R5cGUudHJpbSA9IGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgcmV0dXJuIHRoaXMucmVwbGFjZSgvXlxccyt8XFxzKyQvZywgJycpOyBcbiAgICAgICAgfVxuICAgIH1cblxuICAgIHZhciByb290ID0gdGhpc1xuICAgICAgLCAkID0gcm9vdC5qUXVlcnkgfHwgcm9vdC5aZXB0b1xuICAgICAgLCBpMThuID0ge31cbiAgICAgICwgcmVzU3RvcmUgPSB7fVxuICAgICAgLCBjdXJyZW50TG5nXG4gICAgICAsIHJlcGxhY2VtZW50Q291bnRlciA9IDBcbiAgICAgICwgbGFuZ3VhZ2VzID0gW11cbiAgICAgICwgaW5pdGlhbGl6ZWQgPSBmYWxzZVxuICAgICAgLCBzeW5jID0ge307XG5cblxuXG4gICAgLy8gRXhwb3J0IHRoZSBpMThuZXh0IG9iamVjdCBmb3IgKipDb21tb25KUyoqLiBcbiAgICAvLyBJZiB3ZSdyZSBub3QgaW4gQ29tbW9uSlMsIGFkZCBgaTE4bmAgdG8gdGhlXG4gICAgLy8gZ2xvYmFsIG9iamVjdCBvciB0byBqcXVlcnkuXG4gICAgaWYgKHR5cGVvZiBtb2R1bGUgIT09ICd1bmRlZmluZWQnICYmIG1vZHVsZS5leHBvcnRzKSB7XG4gICAgICAgIGlmICghJCkge1xuICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAkID0gcmVxdWlyZSgnanF1ZXJ5Jyk7XG4gICAgICAgICAgfSBjYXRjaChlKSB7XG4gICAgICAgICAgICAvLyBqdXN0IGlnbm9yZVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBpZiAoJCkge1xuICAgICAgICAgICAgJC5pMThuID0gJC5pMThuIHx8IGkxOG47XG4gICAgICAgIH1cbiAgICAgICAgbW9kdWxlLmV4cG9ydHMgPSBpMThuO1xuICAgIH0gZWxzZSB7XG4gICAgICAgIGlmICgkKSB7XG4gICAgICAgICAgICAkLmkxOG4gPSAkLmkxOG4gfHwgaTE4bjtcbiAgICAgICAgfVxuICAgICAgICBcbiAgICAgICAgcm9vdC5pMThuID0gcm9vdC5pMThuIHx8IGkxOG47XG4gICAgfVxuICAgIHN5bmMgPSB7XG4gICAgXG4gICAgICAgIGxvYWQ6IGZ1bmN0aW9uKGxuZ3MsIG9wdGlvbnMsIGNiKSB7XG4gICAgICAgICAgICBpZiAob3B0aW9ucy51c2VMb2NhbFN0b3JhZ2UpIHtcbiAgICAgICAgICAgICAgICBzeW5jLl9sb2FkTG9jYWwobG5ncywgb3B0aW9ucywgZnVuY3Rpb24oZXJyLCBzdG9yZSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgbWlzc2luZ0xuZ3MgPSBbXTtcbiAgICAgICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGxlbiA9IGxuZ3MubGVuZ3RoOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICghc3RvcmVbbG5nc1tpXV0pIG1pc3NpbmdMbmdzLnB1c2gobG5nc1tpXSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICAgICAgaWYgKG1pc3NpbmdMbmdzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHN5bmMuX2ZldGNoKG1pc3NpbmdMbmdzLCBvcHRpb25zLCBmdW5jdGlvbihlcnIsIGZldGNoZWQpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmLmV4dGVuZChzdG9yZSwgZmV0Y2hlZCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgc3luYy5fc3RvcmVMb2NhbChmZXRjaGVkKTtcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjYihudWxsLCBzdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGNiKG51bGwsIHN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBzeW5jLl9mZXRjaChsbmdzLCBvcHRpb25zLCBmdW5jdGlvbihlcnIsIHN0b3JlKXtcbiAgICAgICAgICAgICAgICAgICAgY2IobnVsbCwgc3RvcmUpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgIFxuICAgICAgICBfbG9hZExvY2FsOiBmdW5jdGlvbihsbmdzLCBvcHRpb25zLCBjYikge1xuICAgICAgICAgICAgdmFyIHN0b3JlID0ge31cbiAgICAgICAgICAgICAgLCBub3dNUyA9IG5ldyBEYXRlKCkuZ2V0VGltZSgpO1xuICAgIFxuICAgICAgICAgICAgaWYod2luZG93LmxvY2FsU3RvcmFnZSkge1xuICAgIFxuICAgICAgICAgICAgICAgIHZhciB0b2RvID0gbG5ncy5sZW5ndGg7XG4gICAgXG4gICAgICAgICAgICAgICAgZi5lYWNoKGxuZ3MsIGZ1bmN0aW9uKGtleSwgbG5nKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBsb2NhbCA9IHdpbmRvdy5sb2NhbFN0b3JhZ2UuZ2V0SXRlbSgncmVzXycgKyBsbmcpO1xuICAgIFxuICAgICAgICAgICAgICAgICAgICBpZiAobG9jYWwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGxvY2FsID0gSlNPTi5wYXJzZShsb2NhbCk7XG4gICAgXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAobG9jYWwuaTE4blN0YW1wICYmIGxvY2FsLmkxOG5TdGFtcCArIG9wdGlvbnMubG9jYWxTdG9yYWdlRXhwaXJhdGlvblRpbWUgPiBub3dNUykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0b3JlW2xuZ10gPSBsb2NhbDtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgICAgICAgICB0b2RvLS07IC8vIHdhaXQgZm9yIGFsbCBkb25lIGJlZm9yIGNhbGxiYWNrXG4gICAgICAgICAgICAgICAgICAgIGlmICh0b2RvID09PSAwKSBjYihudWxsLCBzdG9yZSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgXG4gICAgICAgIF9zdG9yZUxvY2FsOiBmdW5jdGlvbihzdG9yZSkge1xuICAgICAgICAgICAgaWYod2luZG93LmxvY2FsU3RvcmFnZSkge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIG0gaW4gc3RvcmUpIHtcbiAgICAgICAgICAgICAgICAgICAgc3RvcmVbbV0uaTE4blN0YW1wID0gbmV3IERhdGUoKS5nZXRUaW1lKCk7XG4gICAgICAgICAgICAgICAgICAgIGYubG9jYWxTdG9yYWdlLnNldEl0ZW0oJ3Jlc18nICsgbSwgSlNPTi5zdHJpbmdpZnkoc3RvcmVbbV0pKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICByZXR1cm47XG4gICAgICAgIH0sXG4gICAgXG4gICAgICAgIF9mZXRjaDogZnVuY3Rpb24obG5ncywgb3B0aW9ucywgY2IpIHtcbiAgICAgICAgICAgIHZhciBucyA9IG9wdGlvbnMubnNcbiAgICAgICAgICAgICAgLCBzdG9yZSA9IHt9O1xuICAgICAgICAgICAgXG4gICAgICAgICAgICBpZiAoIW9wdGlvbnMuZHluYW1pY0xvYWQpIHtcbiAgICAgICAgICAgICAgICB2YXIgdG9kbyA9IG5zLm5hbWVzcGFjZXMubGVuZ3RoICogbG5ncy5sZW5ndGhcbiAgICAgICAgICAgICAgICAgICwgZXJyb3JzO1xuICAgIFxuICAgICAgICAgICAgICAgIC8vIGxvYWQgZWFjaCBmaWxlIGluZGl2aWR1YWxcbiAgICAgICAgICAgICAgICBmLmVhY2gobnMubmFtZXNwYWNlcywgZnVuY3Rpb24obnNJbmRleCwgbnNWYWx1ZSkge1xuICAgICAgICAgICAgICAgICAgICBmLmVhY2gobG5ncywgZnVuY3Rpb24obG5nSW5kZXgsIGxuZ1ZhbHVlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIENhbGwgdGhpcyBvbmNlIG91ciB0cmFuc2xhdGlvbiBoYXMgcmV0dXJuZWQuXG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgbG9hZENvbXBsZXRlID0gZnVuY3Rpb24oZXJyLCBkYXRhKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlcnJvcnMgPSBlcnJvcnMgfHwgW107XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVycm9ycy5wdXNoKGVycik7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0b3JlW2xuZ1ZhbHVlXSA9IHN0b3JlW2xuZ1ZhbHVlXSB8fCB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzdG9yZVtsbmdWYWx1ZV1bbnNWYWx1ZV0gPSBkYXRhO1xuICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRvZG8tLTsgLy8gd2FpdCBmb3IgYWxsIGRvbmUgYmVmb3IgY2FsbGJhY2tcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAodG9kbyA9PT0gMCkgY2IoZXJyb3JzLCBzdG9yZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9O1xuICAgICAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgICAgICBpZih0eXBlb2Ygb3B0aW9ucy5jdXN0b21Mb2FkID09ICdmdW5jdGlvbicpe1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vIFVzZSB0aGUgc3BlY2lmaWVkIGN1c3RvbSBjYWxsYmFjay5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBvcHRpb25zLmN1c3RvbUxvYWQobG5nVmFsdWUsIG5zVmFsdWUsIG9wdGlvbnMsIGxvYWRDb21wbGV0ZSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8vfiAvLyBVc2Ugb3VyIGluYnVpbHQgc3luYy5cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBzeW5jLl9mZXRjaE9uZShsbmdWYWx1ZSwgbnNWYWx1ZSwgb3B0aW9ucywgbG9hZENvbXBsZXRlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIC8vIENhbGwgdGhpcyBvbmNlIG91ciB0cmFuc2xhdGlvbiBoYXMgcmV0dXJuZWQuXG4gICAgICAgICAgICAgICAgdmFyIGxvYWRDb21wbGV0ZSA9IGZ1bmN0aW9uKGVyciwgZGF0YSkge1xuICAgICAgICAgICAgICAgICAgICBjYihudWxsLCBkYXRhKTtcbiAgICAgICAgICAgICAgICB9O1xuICAgIFxuICAgICAgICAgICAgICAgIGlmKHR5cGVvZiBvcHRpb25zLmN1c3RvbUxvYWQgPT0gJ2Z1bmN0aW9uJyl7XG4gICAgICAgICAgICAgICAgICAgIC8vIFVzZSB0aGUgc3BlY2lmaWVkIGN1c3RvbSBjYWxsYmFjay5cbiAgICAgICAgICAgICAgICAgICAgb3B0aW9ucy5jdXN0b21Mb2FkKGxuZ3MsIG5zLm5hbWVzcGFjZXMsIG9wdGlvbnMsIGxvYWRDb21wbGV0ZSk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHVybCA9IGFwcGx5UmVwbGFjZW1lbnQob3B0aW9ucy5yZXNHZXRQYXRoLCB7IGxuZzogbG5ncy5qb2luKCcrJyksIG5zOiBucy5uYW1lc3BhY2VzLmpvaW4oJysnKSB9KTtcbiAgICAgICAgICAgICAgICAgICAgLy8gbG9hZCBhbGwgbmVlZGVkIHN0dWZmIG9uY2VcbiAgICAgICAgICAgICAgICAgICAgZi5hamF4KHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVybDogdXJsLFxuICAgICAgICAgICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24oZGF0YSwgc3RhdHVzLCB4aHIpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmLmxvZygnbG9hZGVkOiAnICsgdXJsKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBsb2FkQ29tcGxldGUobnVsbCwgZGF0YSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9LFxuICAgICAgICAgICAgICAgICAgICAgICAgZXJyb3IgOiBmdW5jdGlvbih4aHIsIHN0YXR1cywgZXJyb3IpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmLmxvZygnZmFpbGVkIGxvYWRpbmc6ICcgKyB1cmwpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGxvYWRDb21wbGV0ZSgnZmFpbGVkIGxvYWRpbmcgcmVzb3VyY2UuanNvbiBlcnJvcjogJyArIGVycm9yKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgICAgICBkYXRhVHlwZTogXCJqc29uXCIsXG4gICAgICAgICAgICAgICAgICAgICAgICBhc3luYyA6IG9wdGlvbnMuZ2V0QXN5bmNcbiAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgfSAgICBcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICBcbiAgICAgICAgX2ZldGNoT25lOiBmdW5jdGlvbihsbmcsIG5zLCBvcHRpb25zLCBkb25lKSB7XG4gICAgICAgICAgICB2YXIgdXJsID0gYXBwbHlSZXBsYWNlbWVudChvcHRpb25zLnJlc0dldFBhdGgsIHsgbG5nOiBsbmcsIG5zOiBucyB9KTtcbiAgICAgICAgICAgIGYuYWpheCh7XG4gICAgICAgICAgICAgICAgdXJsOiB1cmwsXG4gICAgICAgICAgICAgICAgc3VjY2VzczogZnVuY3Rpb24oZGF0YSwgc3RhdHVzLCB4aHIpIHtcbiAgICAgICAgICAgICAgICAgICAgZi5sb2coJ2xvYWRlZDogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgICAgIGRvbmUobnVsbCwgZGF0YSk7XG4gICAgICAgICAgICAgICAgfSxcbiAgICAgICAgICAgICAgICBlcnJvciA6IGZ1bmN0aW9uKHhociwgc3RhdHVzLCBlcnJvcikge1xuICAgICAgICAgICAgICAgICAgICBpZiAoKHN0YXR1cyAmJiBzdGF0dXMgPT0gMjAwKSB8fCAoeGhyICYmIHhoci5zdGF0dXMgJiYgeGhyLnN0YXR1cyA9PSAyMDApKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBmaWxlIGxvYWRlZCBidXQgaW52YWxpZCBqc29uLCBzdG9wIHdhc3RlIHRpbWUgIVxuICAgICAgICAgICAgICAgICAgICAgICAgZi5lcnJvcignVGhlcmUgaXMgYSB0eXBvIGluOiAnICsgdXJsKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICgoc3RhdHVzICYmIHN0YXR1cyA9PSA0MDQpIHx8ICh4aHIgJiYgeGhyLnN0YXR1cyAmJiB4aHIuc3RhdHVzID09IDQwNCkpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGYubG9nKCdEb2VzIG5vdCBleGlzdDogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgdGhlU3RhdHVzID0gc3RhdHVzID8gc3RhdHVzIDogKCh4aHIgJiYgeGhyLnN0YXR1cykgPyB4aHIuc3RhdHVzIDogbnVsbCk7XG4gICAgICAgICAgICAgICAgICAgICAgICBmLmxvZyh0aGVTdGF0dXMgKyAnIHdoZW4gbG9hZGluZyAnICsgdXJsKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgICAgICAgICAgZG9uZShlcnJvciwge30pO1xuICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgZGF0YVR5cGU6IFwianNvblwiLFxuICAgICAgICAgICAgICAgIGFzeW5jIDogb3B0aW9ucy5nZXRBc3luY1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0sXG4gICAgXG4gICAgICAgIHBvc3RNaXNzaW5nOiBmdW5jdGlvbihsbmcsIG5zLCBrZXksIGRlZmF1bHRWYWx1ZSwgbG5ncykge1xuICAgICAgICAgICAgdmFyIHBheWxvYWQgPSB7fTtcbiAgICAgICAgICAgIHBheWxvYWRba2V5XSA9IGRlZmF1bHRWYWx1ZTtcbiAgICBcbiAgICAgICAgICAgIHZhciB1cmxzID0gW107XG4gICAgXG4gICAgICAgICAgICBpZiAoby5zZW5kTWlzc2luZ1RvID09PSAnZmFsbGJhY2snICYmIG8uZmFsbGJhY2tMbmdbMF0gIT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvLmZhbGxiYWNrTG5nLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgICAgIHVybHMucHVzaCh7bG5nOiBvLmZhbGxiYWNrTG5nW2ldLCB1cmw6IGFwcGx5UmVwbGFjZW1lbnQoby5yZXNQb3N0UGF0aCwgeyBsbmc6IG8uZmFsbGJhY2tMbmdbaV0sIG5zOiBucyB9KX0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0gZWxzZSBpZiAoby5zZW5kTWlzc2luZ1RvID09PSAnY3VycmVudCcgfHwgKG8uc2VuZE1pc3NpbmdUbyA9PT0gJ2ZhbGxiYWNrJyAmJiBvLmZhbGxiYWNrTG5nWzBdID09PSBmYWxzZSkgKSB7XG4gICAgICAgICAgICAgICAgdXJscy5wdXNoKHtsbmc6IGxuZywgdXJsOiBhcHBseVJlcGxhY2VtZW50KG8ucmVzUG9zdFBhdGgsIHsgbG5nOiBsbmcsIG5zOiBucyB9KX0pO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChvLnNlbmRNaXNzaW5nVG8gPT09ICdhbGwnKSB7XG4gICAgICAgICAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBsbmdzLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgICAgICAgICB1cmxzLnB1c2goe2xuZzogbG5nc1tpXSwgdXJsOiBhcHBseVJlcGxhY2VtZW50KG8ucmVzUG9zdFBhdGgsIHsgbG5nOiBsbmdzW2ldLCBuczogbnMgfSl9KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICBmb3IgKHZhciB5ID0gMCwgbGVuID0gdXJscy5sZW5ndGg7IHkgPCBsZW47IHkrKykge1xuICAgICAgICAgICAgICAgIHZhciBpdGVtID0gdXJsc1t5XTtcbiAgICAgICAgICAgICAgICBmLmFqYXgoe1xuICAgICAgICAgICAgICAgICAgICB1cmw6IGl0ZW0udXJsLFxuICAgICAgICAgICAgICAgICAgICB0eXBlOiBvLnNlbmRUeXBlLFxuICAgICAgICAgICAgICAgICAgICBkYXRhOiBwYXlsb2FkLFxuICAgICAgICAgICAgICAgICAgICBzdWNjZXNzOiBmdW5jdGlvbihkYXRhLCBzdGF0dXMsIHhocikge1xuICAgICAgICAgICAgICAgICAgICAgICAgZi5sb2coJ3Bvc3RlZCBtaXNzaW5nIGtleSBcXCcnICsga2V5ICsgJ1xcJyB0bzogJyArIGl0ZW0udXJsKTtcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIGFkZCBrZXkgdG8gcmVzU3RvcmVcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBrZXlzID0ga2V5LnNwbGl0KCcuJyk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgeCA9IDA7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgdmFsdWUgPSByZXNTdG9yZVtpdGVtLmxuZ11bbnNdO1xuICAgICAgICAgICAgICAgICAgICAgICAgd2hpbGUgKGtleXNbeF0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZiAoeCA9PT0ga2V5cy5sZW5ndGggLSAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHZhbHVlID0gdmFsdWVba2V5c1t4XV0gPSBkZWZhdWx0VmFsdWU7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZVtrZXlzW3hdXSA9IHZhbHVlW2tleXNbeF1dIHx8IHt9O1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB4Kys7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGVycm9yIDogZnVuY3Rpb24oeGhyLCBzdGF0dXMsIGVycm9yKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBmLmxvZygnZmFpbGVkIHBvc3RpbmcgbWlzc2luZyBrZXkgXFwnJyArIGtleSArICdcXCcgdG86ICcgKyBpdGVtLnVybCk7XG4gICAgICAgICAgICAgICAgICAgIH0sXG4gICAgICAgICAgICAgICAgICAgIGRhdGFUeXBlOiBcImpzb25cIixcbiAgICAgICAgICAgICAgICAgICAgYXN5bmMgOiBvLnBvc3RBc3luY1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9LFxuICAgIFxuICAgICAgICByZWxvYWQ6IHJlbG9hZFxuICAgIH07XG4gICAgLy8gZGVmYXVsdHNcbiAgICB2YXIgbyA9IHtcbiAgICAgICAgbG5nOiB1bmRlZmluZWQsXG4gICAgICAgIGxvYWQ6ICdhbGwnLFxuICAgICAgICBwcmVsb2FkOiBbXSxcbiAgICAgICAgbG93ZXJDYXNlTG5nOiBmYWxzZSxcbiAgICAgICAgcmV0dXJuT2JqZWN0VHJlZXM6IGZhbHNlLFxuICAgICAgICBmYWxsYmFja0xuZzogWydkZXYnXSxcbiAgICAgICAgZmFsbGJhY2tOUzogW10sXG4gICAgICAgIGRldGVjdExuZ1FTOiAnc2V0TG5nJyxcbiAgICAgICAgZGV0ZWN0TG5nRnJvbUxvY2FsU3RvcmFnZTogZmFsc2UsXG4gICAgICAgIG5zOiAndHJhbnNsYXRpb24nLFxuICAgICAgICBmYWxsYmFja09uTnVsbDogdHJ1ZSxcbiAgICAgICAgZmFsbGJhY2tPbkVtcHR5OiBmYWxzZSxcbiAgICAgICAgZmFsbGJhY2tUb0RlZmF1bHROUzogZmFsc2UsXG4gICAgICAgIG5zc2VwYXJhdG9yOiAnOicsXG4gICAgICAgIGtleXNlcGFyYXRvcjogJy4nLFxuICAgICAgICBzZWxlY3RvckF0dHI6ICdkYXRhLWkxOG4nLFxuICAgICAgICBkZWJ1ZzogZmFsc2UsXG4gICAgICAgIFxuICAgICAgICByZXNHZXRQYXRoOiAnbG9jYWxlcy9fX2xuZ19fL19fbnNfXy5qc29uJyxcbiAgICAgICAgcmVzUG9zdFBhdGg6ICdsb2NhbGVzL2FkZC9fX2xuZ19fL19fbnNfXycsXG4gICAgXG4gICAgICAgIGdldEFzeW5jOiB0cnVlLFxuICAgICAgICBwb3N0QXN5bmM6IHRydWUsXG4gICAgXG4gICAgICAgIHJlc1N0b3JlOiB1bmRlZmluZWQsXG4gICAgICAgIHVzZUxvY2FsU3RvcmFnZTogZmFsc2UsXG4gICAgICAgIGxvY2FsU3RvcmFnZUV4cGlyYXRpb25UaW1lOiA3KjI0KjYwKjYwKjEwMDAsXG4gICAgXG4gICAgICAgIGR5bmFtaWNMb2FkOiBmYWxzZSxcbiAgICAgICAgc2VuZE1pc3Npbmc6IGZhbHNlLFxuICAgICAgICBzZW5kTWlzc2luZ1RvOiAnZmFsbGJhY2snLCAvLyBjdXJyZW50IHwgYWxsXG4gICAgICAgIHNlbmRUeXBlOiAnUE9TVCcsXG4gICAgXG4gICAgICAgIGludGVycG9sYXRpb25QcmVmaXg6ICdfXycsXG4gICAgICAgIGludGVycG9sYXRpb25TdWZmaXg6ICdfXycsXG4gICAgICAgIGRlZmF1bHRWYXJpYWJsZXM6IGZhbHNlLFxuICAgICAgICByZXVzZVByZWZpeDogJyR0KCcsXG4gICAgICAgIHJldXNlU3VmZml4OiAnKScsXG4gICAgICAgIHBsdXJhbFN1ZmZpeDogJ19wbHVyYWwnLFxuICAgICAgICBwbHVyYWxOb3RGb3VuZDogWydwbHVyYWxfbm90X2ZvdW5kJywgTWF0aC5yYW5kb20oKV0uam9pbignJyksXG4gICAgICAgIGNvbnRleHROb3RGb3VuZDogWydjb250ZXh0X25vdF9mb3VuZCcsIE1hdGgucmFuZG9tKCldLmpvaW4oJycpLFxuICAgICAgICBlc2NhcGVJbnRlcnBvbGF0aW9uOiBmYWxzZSxcbiAgICAgICAgaW5kZWZpbml0ZVN1ZmZpeDogJ19pbmRlZmluaXRlJyxcbiAgICAgICAgaW5kZWZpbml0ZU5vdEZvdW5kOiBbJ2luZGVmaW5pdGVfbm90X2ZvdW5kJywgTWF0aC5yYW5kb20oKV0uam9pbignJyksXG4gICAgXG4gICAgICAgIHNldEpxdWVyeUV4dDogdHJ1ZSxcbiAgICAgICAgZGVmYXVsdFZhbHVlRnJvbUNvbnRlbnQ6IHRydWUsXG4gICAgICAgIHVzZURhdGFBdHRyT3B0aW9uczogZmFsc2UsXG4gICAgICAgIGNvb2tpZUV4cGlyYXRpb25UaW1lOiB1bmRlZmluZWQsXG4gICAgICAgIHVzZUNvb2tpZTogdHJ1ZSxcbiAgICAgICAgY29va2llTmFtZTogJ2kxOG5leHQnLFxuICAgICAgICBjb29raWVEb21haW46IHVuZGVmaW5lZCxcbiAgICBcbiAgICAgICAgb2JqZWN0VHJlZUtleUhhbmRsZXI6IHVuZGVmaW5lZCxcbiAgICAgICAgcG9zdFByb2Nlc3M6IHVuZGVmaW5lZCxcbiAgICAgICAgcGFyc2VNaXNzaW5nS2V5OiB1bmRlZmluZWQsXG4gICAgICAgIG1pc3NpbmdLZXlIYW5kbGVyOiBzeW5jLnBvc3RNaXNzaW5nLFxuICAgIFxuICAgICAgICBzaG9ydGN1dEZ1bmN0aW9uOiAnc3ByaW50ZicgLy8gb3I6IGRlZmF1bHRWYWx1ZVxuICAgIH07XG4gICAgZnVuY3Rpb24gX2V4dGVuZCh0YXJnZXQsIHNvdXJjZSkge1xuICAgICAgICBpZiAoIXNvdXJjZSB8fCB0eXBlb2Ygc291cmNlID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICByZXR1cm4gdGFyZ2V0O1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIGZvciAodmFyIGF0dHIgaW4gc291cmNlKSB7IHRhcmdldFthdHRyXSA9IHNvdXJjZVthdHRyXTsgfVxuICAgICAgICByZXR1cm4gdGFyZ2V0O1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBfZGVlcEV4dGVuZCh0YXJnZXQsIHNvdXJjZSkge1xuICAgICAgICBmb3IgKHZhciBwcm9wIGluIHNvdXJjZSlcbiAgICAgICAgICAgIGlmIChwcm9wIGluIHRhcmdldClcbiAgICAgICAgICAgICAgICBfZGVlcEV4dGVuZCh0YXJnZXRbcHJvcF0sIHNvdXJjZVtwcm9wXSk7XG4gICAgICAgICAgICBlbHNlXG4gICAgICAgICAgICAgICAgdGFyZ2V0W3Byb3BdID0gc291cmNlW3Byb3BdO1xuICAgICAgICByZXR1cm4gdGFyZ2V0O1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBfZWFjaChvYmplY3QsIGNhbGxiYWNrLCBhcmdzKSB7XG4gICAgICAgIHZhciBuYW1lLCBpID0gMCxcbiAgICAgICAgICAgIGxlbmd0aCA9IG9iamVjdC5sZW5ndGgsXG4gICAgICAgICAgICBpc09iaiA9IGxlbmd0aCA9PT0gdW5kZWZpbmVkIHx8IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuYXBwbHkob2JqZWN0KSAhPT0gJ1tvYmplY3QgQXJyYXldJyB8fCB0eXBlb2Ygb2JqZWN0ID09PSBcImZ1bmN0aW9uXCI7XG4gICAgXG4gICAgICAgIGlmIChhcmdzKSB7XG4gICAgICAgICAgICBpZiAoaXNPYmopIHtcbiAgICAgICAgICAgICAgICBmb3IgKG5hbWUgaW4gb2JqZWN0KSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjYWxsYmFjay5hcHBseShvYmplY3RbbmFtZV0sIGFyZ3MpID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGZvciAoIDsgaSA8IGxlbmd0aDsgKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjYWxsYmFjay5hcHBseShvYmplY3RbaSsrXSwgYXJncykgPT09IGZhbHNlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gQSBzcGVjaWFsLCBmYXN0LCBjYXNlIGZvciB0aGUgbW9zdCBjb21tb24gdXNlIG9mIGVhY2hcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGlmIChpc09iaikge1xuICAgICAgICAgICAgICAgIGZvciAobmFtZSBpbiBvYmplY3QpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGNhbGxiYWNrLmNhbGwob2JqZWN0W25hbWVdLCBuYW1lLCBvYmplY3RbbmFtZV0pID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGZvciAoIDsgaSA8IGxlbmd0aDsgKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmIChjYWxsYmFjay5jYWxsKG9iamVjdFtpXSwgaSwgb2JqZWN0W2krK10pID09PSBmYWxzZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgcmV0dXJuIG9iamVjdDtcbiAgICB9XG4gICAgXG4gICAgdmFyIF9lbnRpdHlNYXAgPSB7XG4gICAgICAgIFwiJlwiOiBcIiZhbXA7XCIsXG4gICAgICAgIFwiPFwiOiBcIiZsdDtcIixcbiAgICAgICAgXCI+XCI6IFwiJmd0O1wiLFxuICAgICAgICAnXCInOiAnJnF1b3Q7JyxcbiAgICAgICAgXCInXCI6ICcmIzM5OycsXG4gICAgICAgIFwiL1wiOiAnJiN4MkY7J1xuICAgIH07XG4gICAgXG4gICAgZnVuY3Rpb24gX2VzY2FwZShkYXRhKSB7XG4gICAgICAgIGlmICh0eXBlb2YgZGF0YSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHJldHVybiBkYXRhLnJlcGxhY2UoL1smPD5cIidcXC9dL2csIGZ1bmN0aW9uIChzKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIF9lbnRpdHlNYXBbc107XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfWVsc2V7XG4gICAgICAgICAgICByZXR1cm4gZGF0YTtcbiAgICAgICAgfVxuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBfYWpheChvcHRpb25zKSB7XG4gICAgXG4gICAgICAgIC8vIHYwLjUuMCBvZiBodHRwczovL2dpdGh1Yi5jb20vZ29sb3JvZGVuL2h0dHAuanNcbiAgICAgICAgdmFyIGdldFhociA9IGZ1bmN0aW9uIChjYWxsYmFjaykge1xuICAgICAgICAgICAgLy8gVXNlIHRoZSBuYXRpdmUgWEhSIG9iamVjdCBpZiB0aGUgYnJvd3NlciBzdXBwb3J0cyBpdC5cbiAgICAgICAgICAgIGlmICh3aW5kb3cuWE1MSHR0cFJlcXVlc3QpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gY2FsbGJhY2sobnVsbCwgbmV3IFhNTEh0dHBSZXF1ZXN0KCkpO1xuICAgICAgICAgICAgfSBlbHNlIGlmICh3aW5kb3cuQWN0aXZlWE9iamVjdCkge1xuICAgICAgICAgICAgICAgIC8vIEluIEludGVybmV0IEV4cGxvcmVyIGNoZWNrIGZvciBBY3RpdmVYIHZlcnNpb25zIG9mIHRoZSBYSFIgb2JqZWN0LlxuICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCBuZXcgQWN0aXZlWE9iamVjdChcIk1zeG1sMi5YTUxIVFRQXCIpKTtcbiAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjYWxsYmFjayhudWxsLCBuZXcgQWN0aXZlWE9iamVjdChcIk1pY3Jvc29mdC5YTUxIVFRQXCIpKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAvLyBJZiBubyBYSFIgc3VwcG9ydCB3YXMgZm91bmQsIHRocm93IGFuIGVycm9yLlxuICAgICAgICAgICAgcmV0dXJuIGNhbGxiYWNrKG5ldyBFcnJvcigpKTtcbiAgICAgICAgfTtcbiAgICBcbiAgICAgICAgdmFyIGVuY29kZVVzaW5nVXJsRW5jb2RpbmcgPSBmdW5jdGlvbiAoZGF0YSkge1xuICAgICAgICAgICAgaWYodHlwZW9mIGRhdGEgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gW107XG4gICAgICAgICAgICBmb3IodmFyIGRhdGFJdGVtIGluIGRhdGEpIHtcbiAgICAgICAgICAgICAgICBpZihkYXRhLmhhc093blByb3BlcnR5KGRhdGFJdGVtKSkge1xuICAgICAgICAgICAgICAgICAgICByZXN1bHQucHVzaChlbmNvZGVVUklDb21wb25lbnQoZGF0YUl0ZW0pICsgJz0nICsgZW5jb2RlVVJJQ29tcG9uZW50KGRhdGFbZGF0YUl0ZW1dKSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdC5qb2luKCcmJyk7XG4gICAgICAgIH07XG4gICAgXG4gICAgICAgIHZhciB1dGY4ID0gZnVuY3Rpb24gKHRleHQpIHtcbiAgICAgICAgICAgIHRleHQgPSB0ZXh0LnJlcGxhY2UoL1xcclxcbi9nLCAnXFxuJyk7XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gJyc7XG4gICAgXG4gICAgICAgICAgICBmb3IodmFyIGkgPSAwOyBpIDwgdGV4dC5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHZhciBjID0gdGV4dC5jaGFyQ29kZUF0KGkpO1xuICAgIFxuICAgICAgICAgICAgICAgIGlmKGMgPCAxMjgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGMpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZigoYyA+IDEyNykgJiYgKGMgPCAyMDQ4KSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGMgPj4gNikgfCAxOTIpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKGMgJiA2MykgfCAxMjgpO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZSgoYyA+PiAxMikgfCAyMjQpO1xuICAgICAgICAgICAgICAgICAgICAgICAgcmVzdWx0ICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoKChjID4+IDYpICYgNjMpIHwgMTI4KTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKChjICYgNjMpIHwgMTI4KTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9O1xuICAgIFxuICAgICAgICB2YXIgYmFzZTY0ID0gZnVuY3Rpb24gKHRleHQpIHtcbiAgICAgICAgICAgIHZhciBrZXlTdHIgPSAnQUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODkrLz0nO1xuICAgIFxuICAgICAgICAgICAgdGV4dCA9IHV0ZjgodGV4dCk7XG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gJycsXG4gICAgICAgICAgICAgICAgICAgIGNocjEsIGNocjIsIGNocjMsXG4gICAgICAgICAgICAgICAgICAgIGVuYzEsIGVuYzIsIGVuYzMsIGVuYzQsXG4gICAgICAgICAgICAgICAgICAgIGkgPSAwO1xuICAgIFxuICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICAgIGNocjEgPSB0ZXh0LmNoYXJDb2RlQXQoaSsrKTtcbiAgICAgICAgICAgICAgICBjaHIyID0gdGV4dC5jaGFyQ29kZUF0KGkrKyk7XG4gICAgICAgICAgICAgICAgY2hyMyA9IHRleHQuY2hhckNvZGVBdChpKyspO1xuICAgIFxuICAgICAgICAgICAgICAgIGVuYzEgPSBjaHIxID4+IDI7XG4gICAgICAgICAgICAgICAgZW5jMiA9ICgoY2hyMSAmIDMpIDw8IDQpIHwgKGNocjIgPj4gNCk7XG4gICAgICAgICAgICAgICAgZW5jMyA9ICgoY2hyMiAmIDE1KSA8PCAyKSB8IChjaHIzID4+IDYpO1xuICAgICAgICAgICAgICAgIGVuYzQgPSBjaHIzICYgNjM7XG4gICAgXG4gICAgICAgICAgICAgICAgaWYoaXNOYU4oY2hyMikpIHtcbiAgICAgICAgICAgICAgICAgICAgZW5jMyA9IGVuYzQgPSA2NDtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYoaXNOYU4oY2hyMykpIHtcbiAgICAgICAgICAgICAgICAgICAgZW5jNCA9IDY0O1xuICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICByZXN1bHQgKz1cbiAgICAgICAgICAgICAgICAgICAga2V5U3RyLmNoYXJBdChlbmMxKSArXG4gICAgICAgICAgICAgICAgICAgIGtleVN0ci5jaGFyQXQoZW5jMikgK1xuICAgICAgICAgICAgICAgICAgICBrZXlTdHIuY2hhckF0KGVuYzMpICtcbiAgICAgICAgICAgICAgICAgICAga2V5U3RyLmNoYXJBdChlbmM0KTtcbiAgICAgICAgICAgICAgICBjaHIxID0gY2hyMiA9IGNocjMgPSAnJztcbiAgICAgICAgICAgICAgICBlbmMxID0gZW5jMiA9IGVuYzMgPSBlbmM0ID0gJyc7XG4gICAgICAgICAgICB9IHdoaWxlKGkgPCB0ZXh0Lmxlbmd0aCk7XG4gICAgXG4gICAgICAgICAgICByZXR1cm4gcmVzdWx0O1xuICAgICAgICB9O1xuICAgIFxuICAgICAgICB2YXIgbWVyZ2VIZWFkZXJzID0gZnVuY3Rpb24gKCkge1xuICAgICAgICAgICAgLy8gVXNlIHRoZSBmaXJzdCBoZWFkZXIgb2JqZWN0IGFzIGJhc2UuXG4gICAgICAgICAgICB2YXIgcmVzdWx0ID0gYXJndW1lbnRzWzBdO1xuICAgIFxuICAgICAgICAgICAgLy8gSXRlcmF0ZSB0aHJvdWdoIHRoZSByZW1haW5pbmcgaGVhZGVyIG9iamVjdHMgYW5kIGFkZCB0aGVtLlxuICAgICAgICAgICAgZm9yKHZhciBpID0gMTsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkrKykge1xuICAgICAgICAgICAgICAgIHZhciBjdXJyZW50SGVhZGVycyA9IGFyZ3VtZW50c1tpXTtcbiAgICAgICAgICAgICAgICBmb3IodmFyIGhlYWRlciBpbiBjdXJyZW50SGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBpZihjdXJyZW50SGVhZGVycy5oYXNPd25Qcm9wZXJ0eShoZWFkZXIpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICByZXN1bHRbaGVhZGVyXSA9IGN1cnJlbnRIZWFkZXJzW2hlYWRlcl07XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAvLyBSZXR1cm4gdGhlIG1lcmdlZCBoZWFkZXJzLlxuICAgICAgICAgICAgcmV0dXJuIHJlc3VsdDtcbiAgICAgICAgfTtcbiAgICBcbiAgICAgICAgdmFyIGFqYXggPSBmdW5jdGlvbiAobWV0aG9kLCB1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAvLyBBZGp1c3QgcGFyYW1ldGVycy5cbiAgICAgICAgICAgIGlmKHR5cGVvZiBvcHRpb25zID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICAgICAgY2FsbGJhY2sgPSBvcHRpb25zO1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSB7fTtcbiAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgIC8vIFNldCBkZWZhdWx0IHBhcmFtZXRlciB2YWx1ZXMuXG4gICAgICAgICAgICBvcHRpb25zLmNhY2hlID0gb3B0aW9ucy5jYWNoZSB8fCBmYWxzZTtcbiAgICAgICAgICAgIG9wdGlvbnMuZGF0YSA9IG9wdGlvbnMuZGF0YSB8fCB7fTtcbiAgICAgICAgICAgIG9wdGlvbnMuaGVhZGVycyA9IG9wdGlvbnMuaGVhZGVycyB8fCB7fTtcbiAgICAgICAgICAgIG9wdGlvbnMuanNvbnAgPSBvcHRpb25zLmpzb25wIHx8IGZhbHNlO1xuICAgICAgICAgICAgb3B0aW9ucy5hc3luYyA9IG9wdGlvbnMuYXN5bmMgPT09IHVuZGVmaW5lZCA/IHRydWUgOiBvcHRpb25zLmFzeW5jO1xuICAgIFxuICAgICAgICAgICAgLy8gTWVyZ2UgdGhlIHZhcmlvdXMgaGVhZGVyIG9iamVjdHMuXG4gICAgICAgICAgICB2YXIgaGVhZGVycyA9IG1lcmdlSGVhZGVycyh7XG4gICAgICAgICAgICAgICAgJ2FjY2VwdCc6ICcqLyonLFxuICAgICAgICAgICAgICAgICdjb250ZW50LXR5cGUnOiAnYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkO2NoYXJzZXQ9VVRGLTgnXG4gICAgICAgICAgICB9LCBhamF4LmhlYWRlcnMsIG9wdGlvbnMuaGVhZGVycyk7XG4gICAgXG4gICAgICAgICAgICAvLyBFbmNvZGUgdGhlIGRhdGEgYWNjb3JkaW5nIHRvIHRoZSBjb250ZW50LXR5cGUuXG4gICAgICAgICAgICB2YXIgcGF5bG9hZDtcbiAgICAgICAgICAgIGlmIChoZWFkZXJzWydjb250ZW50LXR5cGUnXSA9PT0gJ2FwcGxpY2F0aW9uL2pzb24nKSB7XG4gICAgICAgICAgICAgICAgcGF5bG9hZCA9IEpTT04uc3RyaW5naWZ5KG9wdGlvbnMuZGF0YSk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHBheWxvYWQgPSBlbmNvZGVVc2luZ1VybEVuY29kaW5nKG9wdGlvbnMuZGF0YSk7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAvLyBTcGVjaWFsbHkgcHJlcGFyZSBHRVQgcmVxdWVzdHM6IFNldHVwIHRoZSBxdWVyeSBzdHJpbmcsIGhhbmRsZSBjYWNoaW5nIGFuZCBtYWtlIGEgSlNPTlAgY2FsbFxuICAgICAgICAgICAgLy8gaWYgbmVjY2Vzc2FyeS5cbiAgICAgICAgICAgIGlmKG1ldGhvZCA9PT0gJ0dFVCcpIHtcbiAgICAgICAgICAgICAgICAvLyBTZXR1cCB0aGUgcXVlcnkgc3RyaW5nLlxuICAgICAgICAgICAgICAgIHZhciBxdWVyeVN0cmluZyA9IFtdO1xuICAgICAgICAgICAgICAgIGlmKHBheWxvYWQpIHtcbiAgICAgICAgICAgICAgICAgICAgcXVlcnlTdHJpbmcucHVzaChwYXlsb2FkKTtcbiAgICAgICAgICAgICAgICAgICAgcGF5bG9hZCA9IG51bGw7XG4gICAgICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgICAgIC8vIEhhbmRsZSBjYWNoaW5nLlxuICAgICAgICAgICAgICAgIGlmKCFvcHRpb25zLmNhY2hlKSB7XG4gICAgICAgICAgICAgICAgICAgIHF1ZXJ5U3RyaW5nLnB1c2goJ189JyArIChuZXcgRGF0ZSgpKS5nZXRUaW1lKCkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICAvLyBJZiBuZWNjZXNzYXJ5IHByZXBhcmUgdGhlIHF1ZXJ5IHN0cmluZyBmb3IgYSBKU09OUCBjYWxsLlxuICAgICAgICAgICAgICAgIGlmKG9wdGlvbnMuanNvbnApIHtcbiAgICAgICAgICAgICAgICAgICAgcXVlcnlTdHJpbmcucHVzaCgnY2FsbGJhY2s9JyArIG9wdGlvbnMuanNvbnApO1xuICAgICAgICAgICAgICAgICAgICBxdWVyeVN0cmluZy5wdXNoKCdqc29ucD0nICsgb3B0aW9ucy5qc29ucCk7XG4gICAgICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgICAgIC8vIE1lcmdlIHRoZSBxdWVyeSBzdHJpbmcgYW5kIGF0dGFjaCBpdCB0byB0aGUgdXJsLlxuICAgICAgICAgICAgICAgIHF1ZXJ5U3RyaW5nID0gcXVlcnlTdHJpbmcuam9pbignJicpO1xuICAgICAgICAgICAgICAgIGlmIChxdWVyeVN0cmluZy5sZW5ndGggPiAxKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmICh1cmwuaW5kZXhPZignPycpID4gLTEpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVybCArPSAnJicgKyBxdWVyeVN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHVybCArPSAnPycgKyBxdWVyeVN0cmluZztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICAvLyBNYWtlIGEgSlNPTlAgY2FsbCBpZiBuZWNjZXNzYXJ5LlxuICAgICAgICAgICAgICAgIGlmKG9wdGlvbnMuanNvbnApIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGhlYWQgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgnaGVhZCcpWzBdO1xuICAgICAgICAgICAgICAgICAgICB2YXIgc2NyaXB0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgnc2NyaXB0Jyk7XG4gICAgICAgICAgICAgICAgICAgIHNjcmlwdC50eXBlID0gJ3RleHQvamF2YXNjcmlwdCc7XG4gICAgICAgICAgICAgICAgICAgIHNjcmlwdC5zcmMgPSB1cmw7XG4gICAgICAgICAgICAgICAgICAgIGhlYWQuYXBwZW5kQ2hpbGQoc2NyaXB0KTtcbiAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgIC8vIFNpbmNlIHdlIGdvdCBoZXJlLCBpdCBpcyBubyBKU09OUCByZXF1ZXN0LCBzbyBtYWtlIGEgbm9ybWFsIFhIUiByZXF1ZXN0LlxuICAgICAgICAgICAgZ2V0WGhyKGZ1bmN0aW9uIChlcnIsIHhocikge1xuICAgICAgICAgICAgICAgIGlmKGVycikgcmV0dXJuIGNhbGxiYWNrKGVycik7XG4gICAgXG4gICAgICAgICAgICAgICAgLy8gT3BlbiB0aGUgcmVxdWVzdC5cbiAgICAgICAgICAgICAgICB4aHIub3BlbihtZXRob2QsIHVybCwgb3B0aW9ucy5hc3luYyk7XG4gICAgXG4gICAgICAgICAgICAgICAgLy8gU2V0IHRoZSByZXF1ZXN0IGhlYWRlcnMuXG4gICAgICAgICAgICAgICAgZm9yKHZhciBoZWFkZXIgaW4gaGVhZGVycykge1xuICAgICAgICAgICAgICAgICAgICBpZihoZWFkZXJzLmhhc093blByb3BlcnR5KGhlYWRlcikpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHhoci5zZXRSZXF1ZXN0SGVhZGVyKGhlYWRlciwgaGVhZGVyc1toZWFkZXJdKTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICAvLyBIYW5kbGUgdGhlIHJlcXVlc3QgZXZlbnRzLlxuICAgICAgICAgICAgICAgIHhoci5vbnJlYWR5c3RhdGVjaGFuZ2UgPSBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgIGlmKHhoci5yZWFkeVN0YXRlID09PSA0KSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgZGF0YSA9IHhoci5yZXNwb25zZVRleHQgfHwgJyc7XG4gICAgXG4gICAgICAgICAgICAgICAgICAgICAgICAvLyBJZiBubyBjYWxsYmFjayBpcyBnaXZlbiwgcmV0dXJuLlxuICAgICAgICAgICAgICAgICAgICAgICAgaWYoIWNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gUmV0dXJuIGFuIG9iamVjdCB0aGF0IHByb3ZpZGVzIGFjY2VzcyB0byB0aGUgZGF0YSBhcyB0ZXh0IGFuZCBKU09OLlxuICAgICAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2soeGhyLnN0YXR1cywge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRleHQ6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuIGRhdGE7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgfSxcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBqc29uOiBmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4gSlNPTi5wYXJzZShkYXRhKVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmLmVycm9yKCdDYW4gbm90IHBhcnNlIEpTT04uIFVSTDogJyArIHVybCk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICByZXR1cm4ge307XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH07XG4gICAgXG4gICAgICAgICAgICAgICAgLy8gQWN0dWFsbHkgc2VuZCB0aGUgWEhSIHJlcXVlc3QuXG4gICAgICAgICAgICAgICAgeGhyLnNlbmQocGF5bG9hZCk7XG4gICAgICAgICAgICB9KTtcbiAgICAgICAgfTtcbiAgICBcbiAgICAgICAgLy8gRGVmaW5lIHRoZSBleHRlcm5hbCBpbnRlcmZhY2UuXG4gICAgICAgIHZhciBodHRwID0ge1xuICAgICAgICAgICAgYXV0aEJhc2ljOiBmdW5jdGlvbiAodXNlcm5hbWUsIHBhc3N3b3JkKSB7XG4gICAgICAgICAgICAgICAgYWpheC5oZWFkZXJzWydBdXRob3JpemF0aW9uJ10gPSAnQmFzaWMgJyArIGJhc2U2NCh1c2VybmFtZSArICc6JyArIHBhc3N3b3JkKTtcbiAgICAgICAgICAgIH0sXG4gICAgXG4gICAgICAgICAgICBjb25uZWN0OiBmdW5jdGlvbiAodXJsLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJldHVybiBhamF4KCdDT05ORUNUJywgdXJsLCBvcHRpb25zLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgIFxuICAgICAgICAgICAgZGVsOiBmdW5jdGlvbiAodXJsLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJldHVybiBhamF4KCdERUxFVEUnLCB1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0sXG4gICAgXG4gICAgICAgICAgICBnZXQ6IGZ1bmN0aW9uICh1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFqYXgoJ0dFVCcsIHVybCwgb3B0aW9ucywgY2FsbGJhY2spO1xuICAgICAgICAgICAgfSxcbiAgICBcbiAgICAgICAgICAgIGhlYWQ6IGZ1bmN0aW9uICh1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFqYXgoJ0hFQUQnLCB1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0sXG4gICAgXG4gICAgICAgICAgICBoZWFkZXJzOiBmdW5jdGlvbiAoaGVhZGVycykge1xuICAgICAgICAgICAgICAgIGFqYXguaGVhZGVycyA9IGhlYWRlcnMgfHwge307XG4gICAgICAgICAgICB9LFxuICAgIFxuICAgICAgICAgICAgaXNBbGxvd2VkOiBmdW5jdGlvbiAodXJsLCB2ZXJiLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHRoaXMub3B0aW9ucyh1cmwsIGZ1bmN0aW9uIChzdGF0dXMsIGRhdGEpIHtcbiAgICAgICAgICAgICAgICAgICAgY2FsbGJhY2soZGF0YS50ZXh0KCkuaW5kZXhPZih2ZXJiKSAhPT0gLTEpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSxcbiAgICBcbiAgICAgICAgICAgIG9wdGlvbnM6IGZ1bmN0aW9uICh1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGFqYXgoJ09QVElPTlMnLCB1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0sXG4gICAgXG4gICAgICAgICAgICBwYXRjaDogZnVuY3Rpb24gKHVybCwgb3B0aW9ucywgY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWpheCgnUEFUQ0gnLCB1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0sXG4gICAgXG4gICAgICAgICAgICBwb3N0OiBmdW5jdGlvbiAodXJsLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJldHVybiBhamF4KCdQT1NUJywgdXJsLCBvcHRpb25zLCBjYWxsYmFjayk7XG4gICAgICAgICAgICB9LFxuICAgIFxuICAgICAgICAgICAgcHV0OiBmdW5jdGlvbiAodXJsLCBvcHRpb25zLCBjYWxsYmFjaykge1xuICAgICAgICAgICAgICAgIHJldHVybiBhamF4KCdQVVQnLCB1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH0sXG4gICAgXG4gICAgICAgICAgICB0cmFjZTogZnVuY3Rpb24gKHVybCwgb3B0aW9ucywgY2FsbGJhY2spIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYWpheCgnVFJBQ0UnLCB1cmwsIG9wdGlvbnMsIGNhbGxiYWNrKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfTtcbiAgICBcbiAgICBcbiAgICAgICAgdmFyIG1ldGhvZGUgPSBvcHRpb25zLnR5cGUgPyBvcHRpb25zLnR5cGUudG9Mb3dlckNhc2UoKSA6ICdnZXQnO1xuICAgIFxuICAgICAgICBodHRwW21ldGhvZGVdKG9wdGlvbnMudXJsLCBvcHRpb25zLCBmdW5jdGlvbiAoc3RhdHVzLCBkYXRhKSB7XG4gICAgICAgICAgICAvLyBmaWxlOiBwcm90b2NvbCBhbHdheXMgZ2l2ZXMgc3RhdHVzIGNvZGUgMCwgc28gY2hlY2sgZm9yIGRhdGFcbiAgICAgICAgICAgIGlmIChzdGF0dXMgPT09IDIwMCB8fCAoc3RhdHVzID09PSAwICYmIGRhdGEudGV4dCgpKSkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMuc3VjY2VzcyhkYXRhLmpzb24oKSwgc3RhdHVzLCBudWxsKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5lcnJvcihkYXRhLnRleHQoKSwgc3RhdHVzLCBudWxsKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSk7XG4gICAgfVxuICAgIFxuICAgIHZhciBfY29va2llID0ge1xuICAgICAgICBjcmVhdGU6IGZ1bmN0aW9uKG5hbWUsdmFsdWUsbWludXRlcyxkb21haW4pIHtcbiAgICAgICAgICAgIHZhciBleHBpcmVzO1xuICAgICAgICAgICAgaWYgKG1pbnV0ZXMpIHtcbiAgICAgICAgICAgICAgICB2YXIgZGF0ZSA9IG5ldyBEYXRlKCk7XG4gICAgICAgICAgICAgICAgZGF0ZS5zZXRUaW1lKGRhdGUuZ2V0VGltZSgpKyhtaW51dGVzKjYwKjEwMDApKTtcbiAgICAgICAgICAgICAgICBleHBpcmVzID0gXCI7IGV4cGlyZXM9XCIrZGF0ZS50b0dNVFN0cmluZygpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSBleHBpcmVzID0gXCJcIjtcbiAgICAgICAgICAgIGRvbWFpbiA9IChkb21haW4pPyBcImRvbWFpbj1cIitkb21haW4rXCI7XCIgOiBcIlwiO1xuICAgICAgICAgICAgZG9jdW1lbnQuY29va2llID0gbmFtZStcIj1cIit2YWx1ZStleHBpcmVzK1wiO1wiK2RvbWFpbitcInBhdGg9L1wiO1xuICAgICAgICB9LFxuICAgIFxuICAgICAgICByZWFkOiBmdW5jdGlvbihuYW1lKSB7XG4gICAgICAgICAgICB2YXIgbmFtZUVRID0gbmFtZSArIFwiPVwiO1xuICAgICAgICAgICAgdmFyIGNhID0gZG9jdW1lbnQuY29va2llLnNwbGl0KCc7Jyk7XG4gICAgICAgICAgICBmb3IodmFyIGk9MDtpIDwgY2EubGVuZ3RoO2krKykge1xuICAgICAgICAgICAgICAgIHZhciBjID0gY2FbaV07XG4gICAgICAgICAgICAgICAgd2hpbGUgKGMuY2hhckF0KDApPT0nICcpIGMgPSBjLnN1YnN0cmluZygxLGMubGVuZ3RoKTtcbiAgICAgICAgICAgICAgICBpZiAoYy5pbmRleE9mKG5hbWVFUSkgPT09IDApIHJldHVybiBjLnN1YnN0cmluZyhuYW1lRVEubGVuZ3RoLGMubGVuZ3RoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBudWxsO1xuICAgICAgICB9LFxuICAgIFxuICAgICAgICByZW1vdmU6IGZ1bmN0aW9uKG5hbWUpIHtcbiAgICAgICAgICAgIHRoaXMuY3JlYXRlKG5hbWUsXCJcIiwtMSk7XG4gICAgICAgIH1cbiAgICB9O1xuICAgIFxuICAgIHZhciBjb29raWVfbm9vcCA9IHtcbiAgICAgICAgY3JlYXRlOiBmdW5jdGlvbihuYW1lLHZhbHVlLG1pbnV0ZXMsZG9tYWluKSB7fSxcbiAgICAgICAgcmVhZDogZnVuY3Rpb24obmFtZSkgeyByZXR1cm4gbnVsbDsgfSxcbiAgICAgICAgcmVtb3ZlOiBmdW5jdGlvbihuYW1lKSB7fVxuICAgIH07XG4gICAgXG4gICAgXG4gICAgXG4gICAgLy8gbW92ZSBkZXBlbmRlbnQgZnVuY3Rpb25zIHRvIGEgY29udGFpbmVyIHNvIHRoYXRcbiAgICAvLyB0aGV5IGNhbiBiZSBvdmVycmlkZW4gZWFzaWVyIGluIG5vIGpxdWVyeSBlbnZpcm9ubWVudCAobm9kZS5qcylcbiAgICB2YXIgZiA9IHtcbiAgICAgICAgZXh0ZW5kOiAkID8gJC5leHRlbmQgOiBfZXh0ZW5kLFxuICAgICAgICBkZWVwRXh0ZW5kOiBfZGVlcEV4dGVuZCxcbiAgICAgICAgZWFjaDogJCA/ICQuZWFjaCA6IF9lYWNoLFxuICAgICAgICBhamF4OiAkID8gJC5hamF4IDogKHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcgPyBfYWpheCA6IGZ1bmN0aW9uKCkge30pLFxuICAgICAgICBjb29raWU6IHR5cGVvZiBkb2N1bWVudCAhPT0gJ3VuZGVmaW5lZCcgPyBfY29va2llIDogY29va2llX25vb3AsXG4gICAgICAgIGRldGVjdExhbmd1YWdlOiBkZXRlY3RMYW5ndWFnZSxcbiAgICAgICAgZXNjYXBlOiBfZXNjYXBlLFxuICAgICAgICBsb2c6IGZ1bmN0aW9uKHN0cikge1xuICAgICAgICAgICAgaWYgKG8uZGVidWcgJiYgdHlwZW9mIGNvbnNvbGUgIT09IFwidW5kZWZpbmVkXCIpIGNvbnNvbGUubG9nKHN0cik7XG4gICAgICAgIH0sXG4gICAgICAgIGVycm9yOiBmdW5jdGlvbihzdHIpIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgY29uc29sZSAhPT0gXCJ1bmRlZmluZWRcIikgY29uc29sZS5lcnJvcihzdHIpO1xuICAgICAgICB9LFxuICAgICAgICBnZXRDb3VudHlJbmRleE9mTG5nOiBmdW5jdGlvbihsbmcpIHtcbiAgICAgICAgICAgIHZhciBsbmdfaW5kZXggPSAwO1xuICAgICAgICAgICAgaWYgKGxuZyA9PT0gJ25iLU5PJyB8fCBsbmcgPT09ICdubi1OTycgfHwgbG5nID09PSAnbmItbm8nIHx8IGxuZyA9PT0gJ25uLW5vJykgbG5nX2luZGV4ID0gMTtcbiAgICAgICAgICAgIHJldHVybiBsbmdfaW5kZXg7XG4gICAgICAgIH0sXG4gICAgICAgIHRvTGFuZ3VhZ2VzOiBmdW5jdGlvbihsbmcpIHtcbiAgICAgICAgICAgIHZhciBsb2cgPSB0aGlzLmxvZztcbiAgICBcbiAgICAgICAgICAgIGZ1bmN0aW9uIGFwcGx5Q2FzZShsKSB7XG4gICAgICAgICAgICAgICAgdmFyIHJldCA9IGw7XG4gICAgXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiBsID09PSAnc3RyaW5nJyAmJiBsLmluZGV4T2YoJy0nKSA+IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBwYXJ0cyA9IGwuc3BsaXQoJy0nKTtcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgcmV0ID0gby5sb3dlckNhc2VMbmcgP1xuICAgICAgICAgICAgICAgICAgICAgICAgcGFydHNbMF0udG9Mb3dlckNhc2UoKSArICAnLScgKyBwYXJ0c1sxXS50b0xvd2VyQ2FzZSgpIDpcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRzWzBdLnRvTG93ZXJDYXNlKCkgKyAgJy0nICsgcGFydHNbMV0udG9VcHBlckNhc2UoKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICByZXQgPSBvLmxvd2VyQ2FzZUxuZyA/IGwudG9Mb3dlckNhc2UoKSA6IGw7XG4gICAgICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgICAgIHJldHVybiByZXQ7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICB2YXIgbGFuZ3VhZ2VzID0gW107XG4gICAgICAgICAgICB2YXIgd2hpdGVsaXN0ID0gby5sbmdXaGl0ZWxpc3QgfHwgZmFsc2U7XG4gICAgICAgICAgICB2YXIgYWRkTGFuZ3VhZ2UgPSBmdW5jdGlvbihsYW5ndWFnZSl7XG4gICAgICAgICAgICAgIC8vcmVqZWN0IGxhbmdzIG5vdCB3aGl0ZWxpc3RlZFxuICAgICAgICAgICAgICBpZighd2hpdGVsaXN0IHx8IHdoaXRlbGlzdC5pbmRleE9mKGxhbmd1YWdlKSA+IC0xKXtcbiAgICAgICAgICAgICAgICBsYW5ndWFnZXMucHVzaChsYW5ndWFnZSk7XG4gICAgICAgICAgICAgIH1lbHNle1xuICAgICAgICAgICAgICAgIGxvZygncmVqZWN0aW5nIG5vbi13aGl0ZWxpc3RlZCBsYW5ndWFnZTogJyArIGxhbmd1YWdlKTtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIGlmICh0eXBlb2YgbG5nID09PSAnc3RyaW5nJyAmJiBsbmcuaW5kZXhPZignLScpID4gLTEpIHtcbiAgICAgICAgICAgICAgICB2YXIgcGFydHMgPSBsbmcuc3BsaXQoJy0nKTtcbiAgICBcbiAgICAgICAgICAgICAgICBpZiAoby5sb2FkICE9PSAndW5zcGVjaWZpYycpIGFkZExhbmd1YWdlKGFwcGx5Q2FzZShsbmcpKTtcbiAgICAgICAgICAgICAgICBpZiAoby5sb2FkICE9PSAnY3VycmVudCcpIGFkZExhbmd1YWdlKGFwcGx5Q2FzZShwYXJ0c1t0aGlzLmdldENvdW50eUluZGV4T2ZMbmcobG5nKV0pKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgYWRkTGFuZ3VhZ2UoYXBwbHlDYXNlKGxuZykpO1xuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBvLmZhbGxiYWNrTG5nLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKGxhbmd1YWdlcy5pbmRleE9mKG8uZmFsbGJhY2tMbmdbaV0pID09PSAtMSAmJiBvLmZhbGxiYWNrTG5nW2ldKSBsYW5ndWFnZXMucHVzaChhcHBseUNhc2Uoby5mYWxsYmFja0xuZ1tpXSkpO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIGxhbmd1YWdlcztcbiAgICAgICAgfSxcbiAgICAgICAgcmVnZXhFc2NhcGU6IGZ1bmN0aW9uKHN0cikge1xuICAgICAgICAgICAgcmV0dXJuIHN0ci5yZXBsYWNlKC9bXFwtXFxbXFxdXFwvXFx7XFx9XFwoXFwpXFwqXFwrXFw/XFwuXFxcXFxcXlxcJFxcfF0vZywgXCJcXFxcJCZcIik7XG4gICAgICAgIH0sXG4gICAgICAgIHJlZ2V4UmVwbGFjZW1lbnRFc2NhcGU6IGZ1bmN0aW9uKHN0ck9yRm4pIHtcbiAgICAgICAgICAgIGlmICh0eXBlb2Ygc3RyT3JGbiA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3RyT3JGbi5yZXBsYWNlKC9cXCQvZywgXCIkJCQkXCIpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gc3RyT3JGbjtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgbG9jYWxTdG9yYWdlOiB7XG4gICAgICAgICAgICBzZXRJdGVtOiBmdW5jdGlvbihrZXksIHZhbHVlKSB7XG4gICAgICAgICAgICAgICAgaWYgKHdpbmRvdy5sb2NhbFN0b3JhZ2UpIHtcbiAgICAgICAgICAgICAgICAgICAgdHJ5IHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHdpbmRvdy5sb2NhbFN0b3JhZ2Uuc2V0SXRlbShrZXksIHZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgZi5sb2coJ2ZhaWxlZCB0byBzZXQgdmFsdWUgZm9yIGtleSBcIicgKyBrZXkgKyAnXCIgdG8gbG9jYWxTdG9yYWdlLicpO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgfTtcbiAgICBmdW5jdGlvbiBpbml0KG9wdGlvbnMsIGNiKSB7XG4gICAgICAgIFxuICAgICAgICBpZiAodHlwZW9mIG9wdGlvbnMgPT09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgIGNiID0gb3B0aW9ucztcbiAgICAgICAgICAgIG9wdGlvbnMgPSB7fTtcbiAgICAgICAgfVxuICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgXG4gICAgICAgIC8vIG92ZXJyaWRlIGRlZmF1bHRzIHdpdGggcGFzc2VkIGluIG9wdGlvbnNcbiAgICAgICAgZi5leHRlbmQobywgb3B0aW9ucyk7XG4gICAgICAgIGRlbGV0ZSBvLmZpeExuZzsgLyogcGFzc2VkIGluIGVhY2ggdGltZSAqL1xuICAgIFxuICAgICAgICAvLyBvdmVycmlkZSBmdW5jdGlvbnM6IC5sb2coKSwgLmRldGVjdExhbmd1YWdlKCksIGV0Y1xuICAgICAgICBpZiAoby5mdW5jdGlvbnMpIHtcbiAgICAgICAgICAgIGRlbGV0ZSBvLmZ1bmN0aW9ucztcbiAgICAgICAgICAgIGYuZXh0ZW5kKGYsIG9wdGlvbnMuZnVuY3Rpb25zKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBjcmVhdGUgbmFtZXNwYWNlIG9iamVjdCBpZiBuYW1lc3BhY2UgaXMgcGFzc2VkIGluIGFzIHN0cmluZ1xuICAgICAgICBpZiAodHlwZW9mIG8ubnMgPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIG8ubnMgPSB7IG5hbWVzcGFjZXM6IFtvLm5zXSwgZGVmYXVsdE5zOiBvLm5zfTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBmYWxsYmFjayBuYW1lc3BhY2VzXG4gICAgICAgIGlmICh0eXBlb2Ygby5mYWxsYmFja05TID09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBvLmZhbGxiYWNrTlMgPSBbby5mYWxsYmFja05TXTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBmYWxsYmFjayBsYW5ndWFnZXNcbiAgICAgICAgaWYgKHR5cGVvZiBvLmZhbGxiYWNrTG5nID09ICdzdHJpbmcnIHx8IHR5cGVvZiBvLmZhbGxiYWNrTG5nID09ICdib29sZWFuJykge1xuICAgICAgICAgICAgby5mYWxsYmFja0xuZyA9IFtvLmZhbGxiYWNrTG5nXTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBlc2NhcGUgcHJlZml4L3N1ZmZpeFxuICAgICAgICBvLmludGVycG9sYXRpb25QcmVmaXhFc2NhcGVkID0gZi5yZWdleEVzY2FwZShvLmludGVycG9sYXRpb25QcmVmaXgpO1xuICAgICAgICBvLmludGVycG9sYXRpb25TdWZmaXhFc2NhcGVkID0gZi5yZWdleEVzY2FwZShvLmludGVycG9sYXRpb25TdWZmaXgpO1xuICAgIFxuICAgICAgICBpZiAoIW8ubG5nKSBvLmxuZyA9IGYuZGV0ZWN0TGFuZ3VhZ2UoKTtcbiAgICBcbiAgICAgICAgbGFuZ3VhZ2VzID0gZi50b0xhbmd1YWdlcyhvLmxuZyk7XG4gICAgICAgIGN1cnJlbnRMbmcgPSBsYW5ndWFnZXNbMF07XG4gICAgICAgIGYubG9nKCdjdXJyZW50TG5nIHNldCB0bzogJyArIGN1cnJlbnRMbmcpO1xuICAgIFxuICAgICAgICBpZiAoby51c2VDb29raWUgJiYgZi5jb29raWUucmVhZChvLmNvb2tpZU5hbWUpICE9PSBjdXJyZW50TG5nKXsgLy9jb29raWUgaXMgdW5zZXQgb3IgaW52YWxpZFxuICAgICAgICAgICAgZi5jb29raWUuY3JlYXRlKG8uY29va2llTmFtZSwgY3VycmVudExuZywgby5jb29raWVFeHBpcmF0aW9uVGltZSwgby5jb29raWVEb21haW4pO1xuICAgICAgICB9XG4gICAgICAgIGlmIChvLmRldGVjdExuZ0Zyb21Mb2NhbFN0b3JhZ2UgJiYgdHlwZW9mIGRvY3VtZW50ICE9PSAndW5kZWZpbmVkJyAmJiB3aW5kb3cubG9jYWxTdG9yYWdlKSB7XG4gICAgICAgICAgICBmLmxvY2FsU3RvcmFnZS5zZXRJdGVtKCdpMThuZXh0X2xuZycsIGN1cnJlbnRMbmcpO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIHZhciBsbmdUcmFuc2xhdGUgPSB0cmFuc2xhdGU7XG4gICAgICAgIGlmIChvcHRpb25zLmZpeExuZykge1xuICAgICAgICAgICAgbG5nVHJhbnNsYXRlID0gZnVuY3Rpb24oa2V5LCBvcHRpb25zKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgICAgICAgICAgICAgb3B0aW9ucy5sbmcgPSBvcHRpb25zLmxuZyB8fCBsbmdUcmFuc2xhdGUubG5nO1xuICAgICAgICAgICAgICAgIHJldHVybiB0cmFuc2xhdGUoa2V5LCBvcHRpb25zKTtcbiAgICAgICAgICAgIH07XG4gICAgICAgICAgICBsbmdUcmFuc2xhdGUubG5nID0gY3VycmVudExuZztcbiAgICAgICAgfVxuICAgIFxuICAgICAgICBwbHVyYWxFeHRlbnNpb25zLnNldEN1cnJlbnRMbmcoY3VycmVudExuZyk7XG4gICAgXG4gICAgICAgIC8vIGFkZCBKUXVlcnkgZXh0ZW5zaW9uc1xuICAgICAgICBpZiAoJCAmJiBvLnNldEpxdWVyeUV4dCkgYWRkSnF1ZXJ5RnVuY3QoKTtcbiAgICBcbiAgICAgICAgLy8galF1ZXJ5IGRlZmVycmVkXG4gICAgICAgIHZhciBkZWZlcnJlZDtcbiAgICAgICAgaWYgKCQgJiYgJC5EZWZlcnJlZCkge1xuICAgICAgICAgICAgZGVmZXJyZWQgPSAkLkRlZmVycmVkKCk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gcmV0dXJuIGltbWlkaWF0bHkgaWYgcmVzIGFyZSBwYXNzZWQgaW5cbiAgICAgICAgaWYgKG8ucmVzU3RvcmUpIHtcbiAgICAgICAgICAgIHJlc1N0b3JlID0gby5yZXNTdG9yZTtcbiAgICAgICAgICAgIGluaXRpYWxpemVkID0gdHJ1ZTtcbiAgICAgICAgICAgIGlmIChjYikgY2IobG5nVHJhbnNsYXRlKTtcbiAgICAgICAgICAgIGlmIChkZWZlcnJlZCkgZGVmZXJyZWQucmVzb2x2ZShsbmdUcmFuc2xhdGUpO1xuICAgICAgICAgICAgaWYgKGRlZmVycmVkKSByZXR1cm4gZGVmZXJyZWQucHJvbWlzZSgpO1xuICAgICAgICAgICAgcmV0dXJuO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIC8vIGxhbmd1YWdlcyB0byBsb2FkXG4gICAgICAgIHZhciBsbmdzVG9Mb2FkID0gZi50b0xhbmd1YWdlcyhvLmxuZyk7XG4gICAgICAgIGlmICh0eXBlb2Ygby5wcmVsb2FkID09PSAnc3RyaW5nJykgby5wcmVsb2FkID0gW28ucHJlbG9hZF07XG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gby5wcmVsb2FkLmxlbmd0aDsgaSA8IGw7IGkrKykge1xuICAgICAgICAgICAgdmFyIHByZXMgPSBmLnRvTGFuZ3VhZ2VzKG8ucHJlbG9hZFtpXSk7XG4gICAgICAgICAgICBmb3IgKHZhciB5ID0gMCwgbGVuID0gcHJlcy5sZW5ndGg7IHkgPCBsZW47IHkrKykge1xuICAgICAgICAgICAgICAgIGlmIChsbmdzVG9Mb2FkLmluZGV4T2YocHJlc1t5XSkgPCAwKSB7XG4gICAgICAgICAgICAgICAgICAgIGxuZ3NUb0xvYWQucHVzaChwcmVzW3ldKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gZWxzZSBsb2FkIHRoZW1cbiAgICAgICAgaTE4bi5zeW5jLmxvYWQobG5nc1RvTG9hZCwgbywgZnVuY3Rpb24oZXJyLCBzdG9yZSkge1xuICAgICAgICAgICAgcmVzU3RvcmUgPSBzdG9yZTtcbiAgICAgICAgICAgIGluaXRpYWxpemVkID0gdHJ1ZTtcbiAgICBcbiAgICAgICAgICAgIGlmIChjYikgY2IobG5nVHJhbnNsYXRlKTtcbiAgICAgICAgICAgIGlmIChkZWZlcnJlZCkgZGVmZXJyZWQucmVzb2x2ZShsbmdUcmFuc2xhdGUpO1xuICAgICAgICB9KTtcbiAgICBcbiAgICAgICAgaWYgKGRlZmVycmVkKSByZXR1cm4gZGVmZXJyZWQucHJvbWlzZSgpO1xuICAgIH1cbiAgICBmdW5jdGlvbiBwcmVsb2FkKGxuZ3MsIGNiKSB7XG4gICAgICAgIGlmICh0eXBlb2YgbG5ncyA9PT0gJ3N0cmluZycpIGxuZ3MgPSBbbG5nc107XG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBsID0gbG5ncy5sZW5ndGg7IGkgPCBsOyBpKyspIHtcbiAgICAgICAgICAgIGlmIChvLnByZWxvYWQuaW5kZXhPZihsbmdzW2ldKSA8IDApIHtcbiAgICAgICAgICAgICAgICBvLnByZWxvYWQucHVzaChsbmdzW2ldKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gaW5pdChjYik7XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIGFkZFJlc291cmNlQnVuZGxlKGxuZywgbnMsIHJlc291cmNlcywgZGVlcCkge1xuICAgICAgICBpZiAodHlwZW9mIG5zICE9PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgcmVzb3VyY2VzID0gbnM7XG4gICAgICAgICAgICBucyA9IG8ubnMuZGVmYXVsdE5zO1xuICAgICAgICB9IGVsc2UgaWYgKG8ubnMubmFtZXNwYWNlcy5pbmRleE9mKG5zKSA8IDApIHtcbiAgICAgICAgICAgIG8ubnMubmFtZXNwYWNlcy5wdXNoKG5zKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICByZXNTdG9yZVtsbmddID0gcmVzU3RvcmVbbG5nXSB8fCB7fTtcbiAgICAgICAgcmVzU3RvcmVbbG5nXVtuc10gPSByZXNTdG9yZVtsbmddW25zXSB8fCB7fTtcbiAgICBcbiAgICAgICAgaWYgKGRlZXApIHtcbiAgICAgICAgICAgIGYuZGVlcEV4dGVuZChyZXNTdG9yZVtsbmddW25zXSwgcmVzb3VyY2VzKTtcbiAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIGYuZXh0ZW5kKHJlc1N0b3JlW2xuZ11bbnNdLCByZXNvdXJjZXMpO1xuICAgICAgICB9XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIGhhc1Jlc291cmNlQnVuZGxlKGxuZywgbnMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBucyAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIG5zID0gby5ucy5kZWZhdWx0TnM7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgcmVzU3RvcmVbbG5nXSA9IHJlc1N0b3JlW2xuZ10gfHwge307XG4gICAgICAgIHZhciByZXMgPSByZXNTdG9yZVtsbmddW25zXSB8fCB7fTtcbiAgICBcbiAgICAgICAgdmFyIGhhc1ZhbHVlcyA9IGZhbHNlO1xuICAgICAgICBmb3IodmFyIHByb3AgaW4gcmVzKSB7XG4gICAgICAgICAgICBpZiAocmVzLmhhc093blByb3BlcnR5KHByb3ApKSB7XG4gICAgICAgICAgICAgICAgaGFzVmFsdWVzID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICByZXR1cm4gaGFzVmFsdWVzO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiByZW1vdmVSZXNvdXJjZUJ1bmRsZShsbmcsIG5zKSB7XG4gICAgICAgIGlmICh0eXBlb2YgbnMgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICBucyA9IG8ubnMuZGVmYXVsdE5zO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIHJlc1N0b3JlW2xuZ10gPSByZXNTdG9yZVtsbmddIHx8IHt9O1xuICAgICAgICByZXNTdG9yZVtsbmddW25zXSA9IHt9O1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBhZGRSZXNvdXJjZShsbmcsIG5zLCBrZXksIHZhbHVlKSB7XG4gICAgICAgIGlmICh0eXBlb2YgbnMgIT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICByZXNvdXJjZSA9IG5zO1xuICAgICAgICAgICAgbnMgPSBvLm5zLmRlZmF1bHROcztcbiAgICAgICAgfSBlbHNlIGlmIChvLm5zLm5hbWVzcGFjZXMuaW5kZXhPZihucykgPCAwKSB7XG4gICAgICAgICAgICBvLm5zLm5hbWVzcGFjZXMucHVzaChucyk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgcmVzU3RvcmVbbG5nXSA9IHJlc1N0b3JlW2xuZ10gfHwge307XG4gICAgICAgIHJlc1N0b3JlW2xuZ11bbnNdID0gcmVzU3RvcmVbbG5nXVtuc10gfHwge307XG4gICAgXG4gICAgICAgIHZhciBrZXlzID0ga2V5LnNwbGl0KG8ua2V5c2VwYXJhdG9yKTtcbiAgICAgICAgdmFyIHggPSAwO1xuICAgICAgICB2YXIgbm9kZSA9IHJlc1N0b3JlW2xuZ11bbnNdO1xuICAgICAgICB2YXIgb3JpZ1JlZiA9IG5vZGU7XG4gICAgXG4gICAgICAgIHdoaWxlIChrZXlzW3hdKSB7XG4gICAgICAgICAgICBpZiAoeCA9PSBrZXlzLmxlbmd0aCAtIDEpXG4gICAgICAgICAgICAgICAgbm9kZVtrZXlzW3hdXSA9IHZhbHVlO1xuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgaWYgKG5vZGVba2V5c1t4XV0gPT0gbnVsbClcbiAgICAgICAgICAgICAgICAgICAgbm9kZVtrZXlzW3hdXSA9IHt9O1xuICAgIFxuICAgICAgICAgICAgICAgIG5vZGUgPSBub2RlW2tleXNbeF1dO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgeCsrO1xuICAgICAgICB9XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIGFkZFJlc291cmNlcyhsbmcsIG5zLCByZXNvdXJjZXMpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBucyAhPT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgIHJlc291cmNlID0gbnM7XG4gICAgICAgICAgICBucyA9IG8ubnMuZGVmYXVsdE5zO1xuICAgICAgICB9IGVsc2UgaWYgKG8ubnMubmFtZXNwYWNlcy5pbmRleE9mKG5zKSA8IDApIHtcbiAgICAgICAgICAgIG8ubnMubmFtZXNwYWNlcy5wdXNoKG5zKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICBmb3IgKHZhciBtIGluIHJlc291cmNlcykge1xuICAgICAgICAgICAgaWYgKHR5cGVvZiByZXNvdXJjZXNbbV0gPT09ICdzdHJpbmcnKSBhZGRSZXNvdXJjZShsbmcsIG5zLCBtLCByZXNvdXJjZXNbbV0pO1xuICAgICAgICB9XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIHNldERlZmF1bHROYW1lc3BhY2UobnMpIHtcbiAgICAgICAgby5ucy5kZWZhdWx0TnMgPSBucztcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gbG9hZE5hbWVzcGFjZShuYW1lc3BhY2UsIGNiKSB7XG4gICAgICAgIGxvYWROYW1lc3BhY2VzKFtuYW1lc3BhY2VdLCBjYik7XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIGxvYWROYW1lc3BhY2VzKG5hbWVzcGFjZXMsIGNiKSB7XG4gICAgICAgIHZhciBvcHRzID0ge1xuICAgICAgICAgICAgZHluYW1pY0xvYWQ6IG8uZHluYW1pY0xvYWQsXG4gICAgICAgICAgICByZXNHZXRQYXRoOiBvLnJlc0dldFBhdGgsXG4gICAgICAgICAgICBnZXRBc3luYzogby5nZXRBc3luYyxcbiAgICAgICAgICAgIGN1c3RvbUxvYWQ6IG8uY3VzdG9tTG9hZCxcbiAgICAgICAgICAgIG5zOiB7IG5hbWVzcGFjZXM6IG5hbWVzcGFjZXMsIGRlZmF1bHROczogJyd9IC8qIG5ldyBuYW1lc3BhY2VzIHRvIGxvYWQgKi9cbiAgICAgICAgfTtcbiAgICBcbiAgICAgICAgLy8gbGFuZ3VhZ2VzIHRvIGxvYWRcbiAgICAgICAgdmFyIGxuZ3NUb0xvYWQgPSBmLnRvTGFuZ3VhZ2VzKG8ubG5nKTtcbiAgICAgICAgaWYgKHR5cGVvZiBvLnByZWxvYWQgPT09ICdzdHJpbmcnKSBvLnByZWxvYWQgPSBbby5wcmVsb2FkXTtcbiAgICAgICAgZm9yICh2YXIgaSA9IDAsIGwgPSBvLnByZWxvYWQubGVuZ3RoOyBpIDwgbDsgaSsrKSB7XG4gICAgICAgICAgICB2YXIgcHJlcyA9IGYudG9MYW5ndWFnZXMoby5wcmVsb2FkW2ldKTtcbiAgICAgICAgICAgIGZvciAodmFyIHkgPSAwLCBsZW4gPSBwcmVzLmxlbmd0aDsgeSA8IGxlbjsgeSsrKSB7XG4gICAgICAgICAgICAgICAgaWYgKGxuZ3NUb0xvYWQuaW5kZXhPZihwcmVzW3ldKSA8IDApIHtcbiAgICAgICAgICAgICAgICAgICAgbG5nc1RvTG9hZC5wdXNoKHByZXNbeV0pO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBjaGVjayBpZiB3ZSBoYXZlIHRvIGxvYWRcbiAgICAgICAgdmFyIGxuZ05lZWRMb2FkID0gW107XG4gICAgICAgIGZvciAodmFyIGEgPSAwLCBsZW5BID0gbG5nc1RvTG9hZC5sZW5ndGg7IGEgPCBsZW5BOyBhKyspIHtcbiAgICAgICAgICAgIHZhciBuZWVkTG9hZCA9IGZhbHNlO1xuICAgICAgICAgICAgdmFyIHJlc1NldCA9IHJlc1N0b3JlW2xuZ3NUb0xvYWRbYV1dO1xuICAgICAgICAgICAgaWYgKHJlc1NldCkge1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGIgPSAwLCBsZW5CID0gbmFtZXNwYWNlcy5sZW5ndGg7IGIgPCBsZW5COyBiKyspIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKCFyZXNTZXRbbmFtZXNwYWNlc1tiXV0pIG5lZWRMb2FkID0gdHJ1ZTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIG5lZWRMb2FkID0gdHJ1ZTtcbiAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgIGlmIChuZWVkTG9hZCkgbG5nTmVlZExvYWQucHVzaChsbmdzVG9Mb2FkW2FdKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICBpZiAobG5nTmVlZExvYWQubGVuZ3RoKSB7XG4gICAgICAgICAgICBpMThuLnN5bmMuX2ZldGNoKGxuZ05lZWRMb2FkLCBvcHRzLCBmdW5jdGlvbihlcnIsIHN0b3JlKSB7XG4gICAgICAgICAgICAgICAgdmFyIHRvZG8gPSBuYW1lc3BhY2VzLmxlbmd0aCAqIGxuZ05lZWRMb2FkLmxlbmd0aDtcbiAgICBcbiAgICAgICAgICAgICAgICAvLyBsb2FkIGVhY2ggZmlsZSBpbmRpdmlkdWFsXG4gICAgICAgICAgICAgICAgZi5lYWNoKG5hbWVzcGFjZXMsIGZ1bmN0aW9uKG5zSW5kZXgsIG5zVmFsdWUpIHtcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgLy8gYXBwZW5kIG5hbWVzcGFjZSB0byBuYW1lc3BhY2UgYXJyYXlcbiAgICAgICAgICAgICAgICAgICAgaWYgKG8ubnMubmFtZXNwYWNlcy5pbmRleE9mKG5zVmFsdWUpIDwgMCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgby5ucy5uYW1lc3BhY2VzLnB1c2gobnNWYWx1ZSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgICAgICAgICAgZi5lYWNoKGxuZ05lZWRMb2FkLCBmdW5jdGlvbihsbmdJbmRleCwgbG5nVmFsdWUpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc1N0b3JlW2xuZ1ZhbHVlXSA9IHJlc1N0b3JlW2xuZ1ZhbHVlXSB8fCB7fTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHJlc1N0b3JlW2xuZ1ZhbHVlXVtuc1ZhbHVlXSA9IHN0b3JlW2xuZ1ZhbHVlXVtuc1ZhbHVlXTtcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgICAgIHRvZG8tLTsgLy8gd2FpdCBmb3IgYWxsIGRvbmUgYmVmb3IgY2FsbGJhY2tcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0b2RvID09PSAwICYmIGNiKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG8udXNlTG9jYWxTdG9yYWdlKSBpMThuLnN5bmMuX3N0b3JlTG9jYWwocmVzU3RvcmUpO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGNiKCk7XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBpZiAoY2IpIGNiKCk7XG4gICAgICAgIH1cbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gc2V0TG5nKGxuZywgb3B0aW9ucywgY2IpIHtcbiAgICAgICAgaWYgKHR5cGVvZiBvcHRpb25zID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBjYiA9IG9wdGlvbnM7XG4gICAgICAgICAgICBvcHRpb25zID0ge307XG4gICAgICAgIH0gZWxzZSBpZiAoIW9wdGlvbnMpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSB7fTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICBvcHRpb25zLmxuZyA9IGxuZztcbiAgICAgICAgcmV0dXJuIGluaXQob3B0aW9ucywgY2IpO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBsbmcoKSB7XG4gICAgICAgIHJldHVybiBjdXJyZW50TG5nO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiByZWxvYWQoY2IpIHtcbiAgICAgICAgcmVzU3RvcmUgPSB7fTtcbiAgICAgICAgc2V0TG5nKGN1cnJlbnRMbmcsIGNiKTtcbiAgICB9XG4gICAgZnVuY3Rpb24gYWRkSnF1ZXJ5RnVuY3QoKSB7XG4gICAgICAgIC8vICQudCBzaG9ydGN1dFxuICAgICAgICAkLnQgPSAkLnQgfHwgdHJhbnNsYXRlO1xuICAgIFxuICAgICAgICBmdW5jdGlvbiBwYXJzZShlbGUsIGtleSwgb3B0aW9ucykge1xuICAgICAgICAgICAgaWYgKGtleS5sZW5ndGggPT09IDApIHJldHVybjtcbiAgICBcbiAgICAgICAgICAgIHZhciBhdHRyID0gJ3RleHQnO1xuICAgIFxuICAgICAgICAgICAgaWYgKGtleS5pbmRleE9mKCdbJykgPT09IDApIHtcbiAgICAgICAgICAgICAgICB2YXIgcGFydHMgPSBrZXkuc3BsaXQoJ10nKTtcbiAgICAgICAgICAgICAgICBrZXkgPSBwYXJ0c1sxXTtcbiAgICAgICAgICAgICAgICBhdHRyID0gcGFydHNbMF0uc3Vic3RyKDEsIHBhcnRzWzBdLmxlbmd0aC0xKTtcbiAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgIGlmIChrZXkuaW5kZXhPZignOycpID09PSBrZXkubGVuZ3RoLTEpIHtcbiAgICAgICAgICAgICAgICBrZXkgPSBrZXkuc3Vic3RyKDAsIGtleS5sZW5ndGgtMik7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICB2YXIgb3B0aW9uc1RvVXNlO1xuICAgICAgICAgICAgaWYgKGF0dHIgPT09ICdodG1sJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNUb1VzZSA9IG8uZGVmYXVsdFZhbHVlRnJvbUNvbnRlbnQgPyAkLmV4dGVuZCh7IGRlZmF1bHRWYWx1ZTogZWxlLmh0bWwoKSB9LCBvcHRpb25zKSA6IG9wdGlvbnM7XG4gICAgICAgICAgICAgICAgZWxlLmh0bWwoJC50KGtleSwgb3B0aW9uc1RvVXNlKSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGF0dHIgPT09ICd0ZXh0Jykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNUb1VzZSA9IG8uZGVmYXVsdFZhbHVlRnJvbUNvbnRlbnQgPyAkLmV4dGVuZCh7IGRlZmF1bHRWYWx1ZTogZWxlLnRleHQoKSB9LCBvcHRpb25zKSA6IG9wdGlvbnM7XG4gICAgICAgICAgICAgICAgZWxlLnRleHQoJC50KGtleSwgb3B0aW9uc1RvVXNlKSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGF0dHIgPT09ICdwcmVwZW5kJykge1xuICAgICAgICAgICAgICAgIG9wdGlvbnNUb1VzZSA9IG8uZGVmYXVsdFZhbHVlRnJvbUNvbnRlbnQgPyAkLmV4dGVuZCh7IGRlZmF1bHRWYWx1ZTogZWxlLmh0bWwoKSB9LCBvcHRpb25zKSA6IG9wdGlvbnM7XG4gICAgICAgICAgICAgICAgZWxlLnByZXBlbmQoJC50KGtleSwgb3B0aW9uc1RvVXNlKSk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKGF0dHIgPT09ICdhcHBlbmQnKSB7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1RvVXNlID0gby5kZWZhdWx0VmFsdWVGcm9tQ29udGVudCA/ICQuZXh0ZW5kKHsgZGVmYXVsdFZhbHVlOiBlbGUuaHRtbCgpIH0sIG9wdGlvbnMpIDogb3B0aW9ucztcbiAgICAgICAgICAgICAgICBlbGUuYXBwZW5kKCQudChrZXksIG9wdGlvbnNUb1VzZSkpO1xuICAgICAgICAgICAgfSBlbHNlIGlmIChhdHRyLmluZGV4T2YoXCJkYXRhLVwiKSA9PT0gMCkge1xuICAgICAgICAgICAgICAgIHZhciBkYXRhQXR0ciA9IGF0dHIuc3Vic3RyKChcImRhdGEtXCIpLmxlbmd0aCk7XG4gICAgICAgICAgICAgICAgb3B0aW9uc1RvVXNlID0gby5kZWZhdWx0VmFsdWVGcm9tQ29udGVudCA/ICQuZXh0ZW5kKHsgZGVmYXVsdFZhbHVlOiBlbGUuZGF0YShkYXRhQXR0cikgfSwgb3B0aW9ucykgOiBvcHRpb25zO1xuICAgICAgICAgICAgICAgIHZhciB0cmFuc2xhdGVkID0gJC50KGtleSwgb3B0aW9uc1RvVXNlKTtcbiAgICAgICAgICAgICAgICAvL3dlIGNoYW5nZSBpbnRvIHRoZSBkYXRhIGNhY2hlXG4gICAgICAgICAgICAgICAgZWxlLmRhdGEoZGF0YUF0dHIsIHRyYW5zbGF0ZWQpO1xuICAgICAgICAgICAgICAgIC8vd2UgY2hhbmdlIGludG8gdGhlIGRvbVxuICAgICAgICAgICAgICAgIGVsZS5hdHRyKGF0dHIsIHRyYW5zbGF0ZWQpO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zVG9Vc2UgPSBvLmRlZmF1bHRWYWx1ZUZyb21Db250ZW50ID8gJC5leHRlbmQoeyBkZWZhdWx0VmFsdWU6IGVsZS5hdHRyKGF0dHIpIH0sIG9wdGlvbnMpIDogb3B0aW9ucztcbiAgICAgICAgICAgICAgICBlbGUuYXR0cihhdHRyLCAkLnQoa2V5LCBvcHRpb25zVG9Vc2UpKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICBmdW5jdGlvbiBsb2NhbGl6ZShlbGUsIG9wdGlvbnMpIHtcbiAgICAgICAgICAgIHZhciBrZXkgPSBlbGUuYXR0cihvLnNlbGVjdG9yQXR0cik7XG4gICAgICAgICAgICBpZiAoIWtleSAmJiB0eXBlb2Yga2V5ICE9PSAndW5kZWZpbmVkJyAmJiBrZXkgIT09IGZhbHNlKSBrZXkgPSBlbGUudGV4dCgpIHx8IGVsZS52YWwoKTtcbiAgICAgICAgICAgIGlmICgha2V5KSByZXR1cm47XG4gICAgXG4gICAgICAgICAgICB2YXIgdGFyZ2V0ID0gZWxlXG4gICAgICAgICAgICAgICwgdGFyZ2V0U2VsZWN0b3IgPSBlbGUuZGF0YShcImkxOG4tdGFyZ2V0XCIpO1xuICAgICAgICAgICAgaWYgKHRhcmdldFNlbGVjdG9yKSB7XG4gICAgICAgICAgICAgICAgdGFyZ2V0ID0gZWxlLmZpbmQodGFyZ2V0U2VsZWN0b3IpIHx8IGVsZTtcbiAgICAgICAgICAgIH1cbiAgICBcbiAgICAgICAgICAgIGlmICghb3B0aW9ucyAmJiBvLnVzZURhdGFBdHRyT3B0aW9ucyA9PT0gdHJ1ZSkge1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSBlbGUuZGF0YShcImkxOG4tb3B0aW9uc1wiKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIFxuICAgICAgICAgICAgaWYgKGtleS5pbmRleE9mKCc7JykgPj0gMCkge1xuICAgICAgICAgICAgICAgIHZhciBrZXlzID0ga2V5LnNwbGl0KCc7Jyk7XG4gICAgXG4gICAgICAgICAgICAgICAgJC5lYWNoKGtleXMsIGZ1bmN0aW9uKG0sIGspIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGsgIT09ICcnKSBwYXJzZSh0YXJnZXQsIGssIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgIFxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBwYXJzZSh0YXJnZXQsIGtleSwgb3B0aW9ucyk7XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICBpZiAoby51c2VEYXRhQXR0ck9wdGlvbnMgPT09IHRydWUpIGVsZS5kYXRhKFwiaTE4bi1vcHRpb25zXCIsIG9wdGlvbnMpO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIC8vIGZuXG4gICAgICAgICQuZm4uaTE4biA9IGZ1bmN0aW9uIChvcHRpb25zKSB7XG4gICAgICAgICAgICByZXR1cm4gdGhpcy5lYWNoKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIC8vIGxvY2FsaXplIGVsZW1lbnQgaXRzZWxmXG4gICAgICAgICAgICAgICAgbG9jYWxpemUoJCh0aGlzKSwgb3B0aW9ucyk7XG4gICAgXG4gICAgICAgICAgICAgICAgLy8gbG9jYWxpemUgY2hpbGRzXG4gICAgICAgICAgICAgICAgdmFyIGVsZW1lbnRzID0gICQodGhpcykuZmluZCgnWycgKyBvLnNlbGVjdG9yQXR0ciArICddJyk7XG4gICAgICAgICAgICAgICAgZWxlbWVudHMuZWFjaChmdW5jdGlvbigpIHsgXG4gICAgICAgICAgICAgICAgICAgIGxvY2FsaXplKCQodGhpcyksIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfSk7XG4gICAgICAgIH07XG4gICAgfVxuICAgIGZ1bmN0aW9uIGFwcGx5UmVwbGFjZW1lbnQoc3RyLCByZXBsYWNlbWVudEhhc2gsIG5lc3RlZEtleSwgb3B0aW9ucykge1xuICAgICAgICBpZiAoIXN0cikgcmV0dXJuIHN0cjtcbiAgICBcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwgcmVwbGFjZW1lbnRIYXNoOyAvLyBmaXJzdCBjYWxsIHVzZXMgcmVwbGFjZW1lbnQgaGFzaCBjb21iaW5lZCB3aXRoIG9wdGlvbnNcbiAgICAgICAgaWYgKHN0ci5pbmRleE9mKG9wdGlvbnMuaW50ZXJwb2xhdGlvblByZWZpeCB8fCBvLmludGVycG9sYXRpb25QcmVmaXgpIDwgMCkgcmV0dXJuIHN0cjtcbiAgICBcbiAgICAgICAgdmFyIHByZWZpeCA9IG9wdGlvbnMuaW50ZXJwb2xhdGlvblByZWZpeCA/IGYucmVnZXhFc2NhcGUob3B0aW9ucy5pbnRlcnBvbGF0aW9uUHJlZml4KSA6IG8uaW50ZXJwb2xhdGlvblByZWZpeEVzY2FwZWRcbiAgICAgICAgICAsIHN1ZmZpeCA9IG9wdGlvbnMuaW50ZXJwb2xhdGlvblN1ZmZpeCA/IGYucmVnZXhFc2NhcGUob3B0aW9ucy5pbnRlcnBvbGF0aW9uU3VmZml4KSA6IG8uaW50ZXJwb2xhdGlvblN1ZmZpeEVzY2FwZWRcbiAgICAgICAgICAsIHVuRXNjYXBpbmdTdWZmaXggPSAnSFRNTCcrc3VmZml4O1xuICAgIFxuICAgICAgICB2YXIgaGFzaCA9IHJlcGxhY2VtZW50SGFzaC5yZXBsYWNlICYmIHR5cGVvZiByZXBsYWNlbWVudEhhc2gucmVwbGFjZSA9PT0gJ29iamVjdCcgPyByZXBsYWNlbWVudEhhc2gucmVwbGFjZSA6IHJlcGxhY2VtZW50SGFzaDtcbiAgICAgICAgZi5lYWNoKGhhc2gsIGZ1bmN0aW9uKGtleSwgdmFsdWUpIHtcbiAgICAgICAgICAgIHZhciBuZXh0S2V5ID0gbmVzdGVkS2V5ID8gbmVzdGVkS2V5ICsgby5rZXlzZXBhcmF0b3IgKyBrZXkgOiBrZXk7XG4gICAgICAgICAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnb2JqZWN0JyAmJiB2YWx1ZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgIHN0ciA9IGFwcGx5UmVwbGFjZW1lbnQoc3RyLCB2YWx1ZSwgbmV4dEtleSwgb3B0aW9ucyk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGlmIChvcHRpb25zLmVzY2FwZUludGVycG9sYXRpb24gfHwgby5lc2NhcGVJbnRlcnBvbGF0aW9uKSB7XG4gICAgICAgICAgICAgICAgICAgIHN0ciA9IHN0ci5yZXBsYWNlKG5ldyBSZWdFeHAoW3ByZWZpeCwgbmV4dEtleSwgdW5Fc2NhcGluZ1N1ZmZpeF0uam9pbignJyksICdnJyksIGYucmVnZXhSZXBsYWNlbWVudEVzY2FwZSh2YWx1ZSkpO1xuICAgICAgICAgICAgICAgICAgICBzdHIgPSBzdHIucmVwbGFjZShuZXcgUmVnRXhwKFtwcmVmaXgsIG5leHRLZXksIHN1ZmZpeF0uam9pbignJyksICdnJyksIGYucmVnZXhSZXBsYWNlbWVudEVzY2FwZShmLmVzY2FwZSh2YWx1ZSkpKTtcbiAgICAgICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICBzdHIgPSBzdHIucmVwbGFjZShuZXcgUmVnRXhwKFtwcmVmaXgsIG5leHRLZXksIHN1ZmZpeF0uam9pbignJyksICdnJyksIGYucmVnZXhSZXBsYWNlbWVudEVzY2FwZSh2YWx1ZSkpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAvLyBzdHIgPSBvcHRpb25zLmVzY2FwZUludGVycG9sYXRpb247XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pO1xuICAgICAgICByZXR1cm4gc3RyO1xuICAgIH1cbiAgICBcbiAgICAvLyBhcHBlbmQgaXQgdG8gZnVuY3Rpb25zXG4gICAgZi5hcHBseVJlcGxhY2VtZW50ID0gYXBwbHlSZXBsYWNlbWVudDtcbiAgICBcbiAgICBmdW5jdGlvbiBhcHBseVJldXNlKHRyYW5zbGF0ZWQsIG9wdGlvbnMpIHtcbiAgICAgICAgdmFyIGNvbW1hID0gJywnO1xuICAgICAgICB2YXIgb3B0aW9uc19vcGVuID0gJ3snO1xuICAgICAgICB2YXIgb3B0aW9uc19jbG9zZSA9ICd9JztcbiAgICBcbiAgICAgICAgdmFyIG9wdHMgPSBmLmV4dGVuZCh7fSwgb3B0aW9ucyk7XG4gICAgICAgIGRlbGV0ZSBvcHRzLnBvc3RQcm9jZXNzO1xuICAgIFxuICAgICAgICB3aGlsZSAodHJhbnNsYXRlZC5pbmRleE9mKG8ucmV1c2VQcmVmaXgpICE9IC0xKSB7XG4gICAgICAgICAgICByZXBsYWNlbWVudENvdW50ZXIrKztcbiAgICAgICAgICAgIGlmIChyZXBsYWNlbWVudENvdW50ZXIgPiBvLm1heFJlY3Vyc2lvbikgeyBicmVhazsgfSAvLyBzYWZldHkgbmV0IGZvciB0b28gbXVjaCByZWN1cnNpb25cbiAgICAgICAgICAgIHZhciBpbmRleF9vZl9vcGVuaW5nID0gdHJhbnNsYXRlZC5sYXN0SW5kZXhPZihvLnJldXNlUHJlZml4KTtcbiAgICAgICAgICAgIHZhciBpbmRleF9vZl9lbmRfb2ZfY2xvc2luZyA9IHRyYW5zbGF0ZWQuaW5kZXhPZihvLnJldXNlU3VmZml4LCBpbmRleF9vZl9vcGVuaW5nKSArIG8ucmV1c2VTdWZmaXgubGVuZ3RoO1xuICAgICAgICAgICAgdmFyIHRva2VuID0gdHJhbnNsYXRlZC5zdWJzdHJpbmcoaW5kZXhfb2Zfb3BlbmluZywgaW5kZXhfb2ZfZW5kX29mX2Nsb3NpbmcpO1xuICAgICAgICAgICAgdmFyIHRva2VuX3dpdGhvdXRfc3ltYm9scyA9IHRva2VuLnJlcGxhY2Uoby5yZXVzZVByZWZpeCwgJycpLnJlcGxhY2Uoby5yZXVzZVN1ZmZpeCwgJycpO1xuICAgIFxuICAgICAgICAgICAgaWYgKGluZGV4X29mX2VuZF9vZl9jbG9zaW5nIDw9IGluZGV4X29mX29wZW5pbmcpIHtcbiAgICAgICAgICAgICAgICBmLmVycm9yKCd0aGVyZSBpcyBhbiBtaXNzaW5nIGNsb3NpbmcgaW4gZm9sbG93aW5nIHRyYW5zbGF0aW9uIHZhbHVlJywgdHJhbnNsYXRlZCk7XG4gICAgICAgICAgICAgICAgcmV0dXJuICcnO1xuICAgICAgICAgICAgfVxuICAgIFxuICAgICAgICAgICAgaWYgKHRva2VuX3dpdGhvdXRfc3ltYm9scy5pbmRleE9mKGNvbW1hKSAhPSAtMSkge1xuICAgICAgICAgICAgICAgIHZhciBpbmRleF9vZl90b2tlbl9lbmRfb2ZfY2xvc2luZyA9IHRva2VuX3dpdGhvdXRfc3ltYm9scy5pbmRleE9mKGNvbW1hKTtcbiAgICAgICAgICAgICAgICBpZiAodG9rZW5fd2l0aG91dF9zeW1ib2xzLmluZGV4T2Yob3B0aW9uc19vcGVuLCBpbmRleF9vZl90b2tlbl9lbmRfb2ZfY2xvc2luZykgIT0gLTEgJiYgdG9rZW5fd2l0aG91dF9zeW1ib2xzLmluZGV4T2Yob3B0aW9uc19jbG9zZSwgaW5kZXhfb2ZfdG9rZW5fZW5kX29mX2Nsb3NpbmcpICE9IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhciBpbmRleF9vZl9vcHRzX29wZW5pbmcgPSB0b2tlbl93aXRob3V0X3N5bWJvbHMuaW5kZXhPZihvcHRpb25zX29wZW4sIGluZGV4X29mX3Rva2VuX2VuZF9vZl9jbG9zaW5nKTtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGluZGV4X29mX29wdHNfZW5kX29mX2Nsb3NpbmcgPSB0b2tlbl93aXRob3V0X3N5bWJvbHMuaW5kZXhPZihvcHRpb25zX2Nsb3NlLCBpbmRleF9vZl9vcHRzX29wZW5pbmcpICsgb3B0aW9uc19jbG9zZS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBvcHRzID0gZi5leHRlbmQob3B0cywgSlNPTi5wYXJzZSh0b2tlbl93aXRob3V0X3N5bWJvbHMuc3Vic3RyaW5nKGluZGV4X29mX29wdHNfb3BlbmluZywgaW5kZXhfb2Zfb3B0c19lbmRfb2ZfY2xvc2luZykpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRva2VuX3dpdGhvdXRfc3ltYm9scyA9IHRva2VuX3dpdGhvdXRfc3ltYm9scy5zdWJzdHJpbmcoMCwgaW5kZXhfb2ZfdG9rZW5fZW5kX29mX2Nsb3NpbmcpO1xuICAgICAgICAgICAgICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICB2YXIgdHJhbnNsYXRlZF90b2tlbiA9IF90cmFuc2xhdGUodG9rZW5fd2l0aG91dF9zeW1ib2xzLCBvcHRzKTtcbiAgICAgICAgICAgIHRyYW5zbGF0ZWQgPSB0cmFuc2xhdGVkLnJlcGxhY2UodG9rZW4sIGYucmVnZXhSZXBsYWNlbWVudEVzY2FwZSh0cmFuc2xhdGVkX3Rva2VuKSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIHRyYW5zbGF0ZWQ7XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIGhhc0NvbnRleHQob3B0aW9ucykge1xuICAgICAgICByZXR1cm4gKG9wdGlvbnMuY29udGV4dCAmJiAodHlwZW9mIG9wdGlvbnMuY29udGV4dCA9PSAnc3RyaW5nJyB8fCB0eXBlb2Ygb3B0aW9ucy5jb250ZXh0ID09ICdudW1iZXInKSk7XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIG5lZWRzUGx1cmFsKG9wdGlvbnMsIGxuZykge1xuICAgICAgICByZXR1cm4gKG9wdGlvbnMuY291bnQgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb3B0aW9ucy5jb3VudCAhPSAnc3RyaW5nJy8qICYmIHBsdXJhbEV4dGVuc2lvbnMubmVlZHNQbHVyYWwobG5nLCBvcHRpb25zLmNvdW50KSovKTtcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gbmVlZHNJbmRlZmluaXRlQXJ0aWNsZShvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiAob3B0aW9ucy5pbmRlZmluaXRlX2FydGljbGUgIT09IHVuZGVmaW5lZCAmJiB0eXBlb2Ygb3B0aW9ucy5pbmRlZmluaXRlX2FydGljbGUgIT0gJ3N0cmluZycgJiYgb3B0aW9ucy5pbmRlZmluaXRlX2FydGljbGUpO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBleGlzdHMoa2V5LCBvcHRpb25zKSB7XG4gICAgICAgIG9wdGlvbnMgPSBvcHRpb25zIHx8IHt9O1xuICAgIFxuICAgICAgICB2YXIgbm90Rm91bmQgPSBfZ2V0RGVmYXVsdFZhbHVlKGtleSwgb3B0aW9ucylcbiAgICAgICAgICAgICwgZm91bmQgPSBfZmluZChrZXksIG9wdGlvbnMpO1xuICAgIFxuICAgICAgICByZXR1cm4gZm91bmQgIT09IHVuZGVmaW5lZCB8fCBmb3VuZCA9PT0gbm90Rm91bmQ7XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIHRyYW5zbGF0ZShrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgXG4gICAgICAgIGlmICghaW5pdGlhbGl6ZWQpIHtcbiAgICAgICAgICAgIGYubG9nKCdpMThuZXh0IG5vdCBmaW5pc2hlZCBpbml0aWFsaXphdGlvbi4geW91IG1pZ2h0IGhhdmUgY2FsbGVkIHQgZnVuY3Rpb24gYmVmb3JlIGxvYWRpbmcgcmVzb3VyY2VzIGZpbmlzaGVkLicpXG4gICAgICAgICAgICByZXR1cm4gb3B0aW9ucy5kZWZhdWx0VmFsdWUgfHwgJyc7XG4gICAgICAgIH07XG4gICAgICAgIHJlcGxhY2VtZW50Q291bnRlciA9IDA7XG4gICAgICAgIHJldHVybiBfdHJhbnNsYXRlLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIF9nZXREZWZhdWx0VmFsdWUoa2V5LCBvcHRpb25zKSB7XG4gICAgICAgIHJldHVybiAob3B0aW9ucy5kZWZhdWx0VmFsdWUgIT09IHVuZGVmaW5lZCkgPyBvcHRpb25zLmRlZmF1bHRWYWx1ZSA6IGtleTtcbiAgICB9XG4gICAgXG4gICAgZnVuY3Rpb24gX2luamVjdFNwcmludGZQcm9jZXNzb3IoKSB7XG4gICAgXG4gICAgICAgIHZhciB2YWx1ZXMgPSBbXTtcbiAgICBcbiAgICAgICAgLy8gbWg6IGJ1aWxkIGFycmF5IGZyb20gc2Vjb25kIGFyZ3VtZW50IG9ud2FyZHNcbiAgICAgICAgZm9yICh2YXIgaSA9IDE7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgIHZhbHVlcy5wdXNoKGFyZ3VtZW50c1tpXSk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgcmV0dXJuIHtcbiAgICAgICAgICAgIHBvc3RQcm9jZXNzOiAnc3ByaW50ZicsXG4gICAgICAgICAgICBzcHJpbnRmOiAgICAgdmFsdWVzXG4gICAgICAgIH07XG4gICAgfVxuICAgIFxuICAgIGZ1bmN0aW9uIF90cmFuc2xhdGUocG90ZW50aWFsS2V5cywgb3B0aW9ucykge1xuICAgICAgICBpZiAob3B0aW9ucyAmJiB0eXBlb2Ygb3B0aW9ucyAhPT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIGlmIChvLnNob3J0Y3V0RnVuY3Rpb24gPT09ICdzcHJpbnRmJykge1xuICAgICAgICAgICAgICAgIC8vIG1oOiBnZXR0ZXh0IGxpa2Ugc3ByaW50ZiBzeW50YXggZm91bmQsIGF1dG9tYXRpY2FsbHkgY3JlYXRlIHNwcmludGYgcHJvY2Vzc29yXG4gICAgICAgICAgICAgICAgb3B0aW9ucyA9IF9pbmplY3RTcHJpbnRmUHJvY2Vzc29yLmFwcGx5KG51bGwsIGFyZ3VtZW50cyk7XG4gICAgICAgICAgICB9IGVsc2UgaWYgKG8uc2hvcnRjdXRGdW5jdGlvbiA9PT0gJ2RlZmF1bHRWYWx1ZScpIHtcbiAgICAgICAgICAgICAgICBvcHRpb25zID0ge1xuICAgICAgICAgICAgICAgICAgICBkZWZhdWx0VmFsdWU6IG9wdGlvbnNcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICBpZiAodHlwZW9mIG8uZGVmYXVsdFZhcmlhYmxlcyA9PT0gJ29iamVjdCcpIHtcbiAgICAgICAgICAgIG9wdGlvbnMgPSBmLmV4dGVuZCh7fSwgby5kZWZhdWx0VmFyaWFibGVzLCBvcHRpb25zKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICBpZiAocG90ZW50aWFsS2V5cyA9PT0gdW5kZWZpbmVkIHx8IHBvdGVudGlhbEtleXMgPT09IG51bGwgfHwgcG90ZW50aWFsS2V5cyA9PT0gJycpIHJldHVybiAnJztcbiAgICBcbiAgICAgICAgaWYgKHR5cGVvZiBwb3RlbnRpYWxLZXlzID09PSAnc3RyaW5nJykge1xuICAgICAgICAgICAgcG90ZW50aWFsS2V5cyA9IFtwb3RlbnRpYWxLZXlzXTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICB2YXIga2V5ID0gcG90ZW50aWFsS2V5c1swXTtcbiAgICBcbiAgICAgICAgaWYgKHBvdGVudGlhbEtleXMubGVuZ3RoID4gMSkge1xuICAgICAgICAgICAgZm9yICh2YXIgaSA9IDA7IGkgPCBwb3RlbnRpYWxLZXlzLmxlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAga2V5ID0gcG90ZW50aWFsS2V5c1tpXTtcbiAgICAgICAgICAgICAgICBpZiAoZXhpc3RzKGtleSwgb3B0aW9ucykpIHtcbiAgICAgICAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIHZhciBub3RGb3VuZCA9IF9nZXREZWZhdWx0VmFsdWUoa2V5LCBvcHRpb25zKVxuICAgICAgICAgICAgLCBmb3VuZCA9IF9maW5kKGtleSwgb3B0aW9ucylcbiAgICAgICAgICAgICwgbG5ncyA9IG9wdGlvbnMubG5nID8gZi50b0xhbmd1YWdlcyhvcHRpb25zLmxuZywgb3B0aW9ucy5mYWxsYmFja0xuZykgOiBsYW5ndWFnZXNcbiAgICAgICAgICAgICwgbnMgPSBvcHRpb25zLm5zIHx8IG8ubnMuZGVmYXVsdE5zXG4gICAgICAgICAgICAsIHBhcnRzO1xuICAgIFxuICAgICAgICAvLyBzcGxpdCBucyBhbmQga2V5XG4gICAgICAgIGlmIChrZXkuaW5kZXhPZihvLm5zc2VwYXJhdG9yKSA+IC0xKSB7XG4gICAgICAgICAgICBwYXJ0cyA9IGtleS5zcGxpdChvLm5zc2VwYXJhdG9yKTtcbiAgICAgICAgICAgIG5zID0gcGFydHNbMF07XG4gICAgICAgICAgICBrZXkgPSBwYXJ0c1sxXTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICBpZiAoZm91bmQgPT09IHVuZGVmaW5lZCAmJiBvLnNlbmRNaXNzaW5nICYmIHR5cGVvZiBvLm1pc3NpbmdLZXlIYW5kbGVyID09PSAnZnVuY3Rpb24nKSB7XG4gICAgICAgICAgICBpZiAob3B0aW9ucy5sbmcpIHtcbiAgICAgICAgICAgICAgICBvLm1pc3NpbmdLZXlIYW5kbGVyKGxuZ3NbMF0sIG5zLCBrZXksIG5vdEZvdW5kLCBsbmdzKTtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgby5taXNzaW5nS2V5SGFuZGxlcihvLmxuZywgbnMsIGtleSwgbm90Rm91bmQsIGxuZ3MpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIHZhciBwb3N0UHJvY2Vzc29yID0gb3B0aW9ucy5wb3N0UHJvY2VzcyB8fCBvLnBvc3RQcm9jZXNzO1xuICAgICAgICBpZiAoZm91bmQgIT09IHVuZGVmaW5lZCAmJiBwb3N0UHJvY2Vzc29yKSB7XG4gICAgICAgICAgICBpZiAocG9zdFByb2Nlc3NvcnNbcG9zdFByb2Nlc3Nvcl0pIHtcbiAgICAgICAgICAgICAgICBmb3VuZCA9IHBvc3RQcm9jZXNzb3JzW3Bvc3RQcm9jZXNzb3JdKGZvdW5kLCBrZXksIG9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIC8vIHByb2Nlc3Mgbm90Rm91bmQgaWYgZnVuY3Rpb24gZXhpc3RzXG4gICAgICAgIHZhciBzcGxpdE5vdEZvdW5kID0gbm90Rm91bmQ7XG4gICAgICAgIGlmIChub3RGb3VuZC5pbmRleE9mKG8ubnNzZXBhcmF0b3IpID4gLTEpIHtcbiAgICAgICAgICAgIHBhcnRzID0gbm90Rm91bmQuc3BsaXQoby5uc3NlcGFyYXRvcik7XG4gICAgICAgICAgICBzcGxpdE5vdEZvdW5kID0gcGFydHNbMV07XG4gICAgICAgIH1cbiAgICAgICAgaWYgKHNwbGl0Tm90Rm91bmQgPT09IGtleSAmJiBvLnBhcnNlTWlzc2luZ0tleSkge1xuICAgICAgICAgICAgbm90Rm91bmQgPSBvLnBhcnNlTWlzc2luZ0tleShub3RGb3VuZCk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgaWYgKGZvdW5kID09PSB1bmRlZmluZWQpIHtcbiAgICAgICAgICAgIG5vdEZvdW5kID0gYXBwbHlSZXBsYWNlbWVudChub3RGb3VuZCwgb3B0aW9ucyk7XG4gICAgICAgICAgICBub3RGb3VuZCA9IGFwcGx5UmV1c2Uobm90Rm91bmQsIG9wdGlvbnMpO1xuICAgIFxuICAgICAgICAgICAgaWYgKHBvc3RQcm9jZXNzb3IgJiYgcG9zdFByb2Nlc3NvcnNbcG9zdFByb2Nlc3Nvcl0pIHtcbiAgICAgICAgICAgICAgICB2YXIgdmFsID0gX2dldERlZmF1bHRWYWx1ZShrZXksIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgIGZvdW5kID0gcG9zdFByb2Nlc3NvcnNbcG9zdFByb2Nlc3Nvcl0odmFsLCBrZXksIG9wdGlvbnMpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIHJldHVybiAoZm91bmQgIT09IHVuZGVmaW5lZCkgPyBmb3VuZCA6IG5vdEZvdW5kO1xuICAgIH1cbiAgICBcbiAgICBmdW5jdGlvbiBfZmluZChrZXksIG9wdGlvbnMpIHtcbiAgICAgICAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gICAgXG4gICAgICAgIHZhciBvcHRpb25XaXRob3V0Q291bnQsIHRyYW5zbGF0ZWRcbiAgICAgICAgICAgICwgbm90Rm91bmQgPSBfZ2V0RGVmYXVsdFZhbHVlKGtleSwgb3B0aW9ucylcbiAgICAgICAgICAgICwgbG5ncyA9IGxhbmd1YWdlcztcbiAgICBcbiAgICAgICAgaWYgKCFyZXNTdG9yZSkgeyByZXR1cm4gbm90Rm91bmQ7IH0gLy8gbm8gcmVzU3RvcmUgdG8gdHJhbnNsYXRlIGZyb21cbiAgICBcbiAgICAgICAgLy8gQ0kgbW9kZVxuICAgICAgICBpZiAobG5nc1swXS50b0xvd2VyQ2FzZSgpID09PSAnY2ltb2RlJykgcmV0dXJuIG5vdEZvdW5kO1xuICAgIFxuICAgICAgICAvLyBwYXNzZWQgaW4gbG5nXG4gICAgICAgIGlmIChvcHRpb25zLmxuZ3MpIGxuZ3MgPSBvcHRpb25zLmxuZ3M7XG4gICAgICAgIGlmIChvcHRpb25zLmxuZykge1xuICAgICAgICAgICAgbG5ncyA9IGYudG9MYW5ndWFnZXMob3B0aW9ucy5sbmcsIG9wdGlvbnMuZmFsbGJhY2tMbmcpO1xuICAgIFxuICAgICAgICAgICAgaWYgKCFyZXNTdG9yZVtsbmdzWzBdXSkge1xuICAgICAgICAgICAgICAgIHZhciBvbGRBc3luYyA9IG8uZ2V0QXN5bmM7XG4gICAgICAgICAgICAgICAgby5nZXRBc3luYyA9IGZhbHNlO1xuICAgIFxuICAgICAgICAgICAgICAgIGkxOG4uc3luYy5sb2FkKGxuZ3MsIG8sIGZ1bmN0aW9uKGVyciwgc3RvcmUpIHtcbiAgICAgICAgICAgICAgICAgICAgZi5leHRlbmQocmVzU3RvcmUsIHN0b3JlKTtcbiAgICAgICAgICAgICAgICAgICAgby5nZXRBc3luYyA9IG9sZEFzeW5jO1xuICAgICAgICAgICAgICAgIH0pO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIHZhciBucyA9IG9wdGlvbnMubnMgfHwgby5ucy5kZWZhdWx0TnM7XG4gICAgICAgIGlmIChrZXkuaW5kZXhPZihvLm5zc2VwYXJhdG9yKSA+IC0xKSB7XG4gICAgICAgICAgICB2YXIgcGFydHMgPSBrZXkuc3BsaXQoby5uc3NlcGFyYXRvcik7XG4gICAgICAgICAgICBucyA9IHBhcnRzWzBdO1xuICAgICAgICAgICAga2V5ID0gcGFydHNbMV07XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgaWYgKGhhc0NvbnRleHQob3B0aW9ucykpIHtcbiAgICAgICAgICAgIG9wdGlvbldpdGhvdXRDb3VudCA9IGYuZXh0ZW5kKHt9LCBvcHRpb25zKTtcbiAgICAgICAgICAgIGRlbGV0ZSBvcHRpb25XaXRob3V0Q291bnQuY29udGV4dDtcbiAgICAgICAgICAgIG9wdGlvbldpdGhvdXRDb3VudC5kZWZhdWx0VmFsdWUgPSBvLmNvbnRleHROb3RGb3VuZDtcbiAgICBcbiAgICAgICAgICAgIHZhciBjb250ZXh0S2V5ID0gbnMgKyBvLm5zc2VwYXJhdG9yICsga2V5ICsgJ18nICsgb3B0aW9ucy5jb250ZXh0O1xuICAgIFxuICAgICAgICAgICAgdHJhbnNsYXRlZCA9IHRyYW5zbGF0ZShjb250ZXh0S2V5LCBvcHRpb25XaXRob3V0Q291bnQpO1xuICAgICAgICAgICAgaWYgKHRyYW5zbGF0ZWQgIT0gby5jb250ZXh0Tm90Rm91bmQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYXBwbHlSZXBsYWNlbWVudCh0cmFuc2xhdGVkLCB7IGNvbnRleHQ6IG9wdGlvbnMuY29udGV4dCB9KTsgLy8gYXBwbHkgcmVwbGFjZW1lbnQgZm9yIGNvbnRleHQgb25seVxuICAgICAgICAgICAgfSAvLyBlbHNlIGNvbnRpbnVlIHRyYW5zbGF0aW9uIHdpdGggb3JpZ2luYWwvbm9uQ29udGV4dCBrZXlcbiAgICAgICAgfVxuICAgIFxuICAgICAgICBpZiAobmVlZHNQbHVyYWwob3B0aW9ucywgbG5nc1swXSkpIHtcbiAgICAgICAgICAgIG9wdGlvbldpdGhvdXRDb3VudCA9IGYuZXh0ZW5kKHsgbG5nczogW2xuZ3NbMF1dfSwgb3B0aW9ucyk7XG4gICAgICAgICAgICBkZWxldGUgb3B0aW9uV2l0aG91dENvdW50LmNvdW50O1xuICAgICAgICAgICAgZGVsZXRlIG9wdGlvbldpdGhvdXRDb3VudC5sbmc7XG4gICAgICAgICAgICBvcHRpb25XaXRob3V0Q291bnQuZGVmYXVsdFZhbHVlID0gby5wbHVyYWxOb3RGb3VuZDtcbiAgICBcbiAgICAgICAgICAgIHZhciBwbHVyYWxLZXk7XG4gICAgICAgICAgICBpZiAoIXBsdXJhbEV4dGVuc2lvbnMubmVlZHNQbHVyYWwobG5nc1swXSwgb3B0aW9ucy5jb3VudCkpIHtcbiAgICAgICAgICAgICAgICBwbHVyYWxLZXkgPSBucyArIG8ubnNzZXBhcmF0b3IgKyBrZXk7XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIHBsdXJhbEtleSA9IG5zICsgby5uc3NlcGFyYXRvciArIGtleSArIG8ucGx1cmFsU3VmZml4O1xuICAgICAgICAgICAgICAgIHZhciBwbHVyYWxFeHRlbnNpb24gPSBwbHVyYWxFeHRlbnNpb25zLmdldChsbmdzWzBdLCBvcHRpb25zLmNvdW50KTtcbiAgICAgICAgICAgICAgICBpZiAocGx1cmFsRXh0ZW5zaW9uID49IDApIHtcbiAgICAgICAgICAgICAgICAgICAgcGx1cmFsS2V5ID0gcGx1cmFsS2V5ICsgJ18nICsgcGx1cmFsRXh0ZW5zaW9uO1xuICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAocGx1cmFsRXh0ZW5zaW9uID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgIHBsdXJhbEtleSA9IG5zICsgby5uc3NlcGFyYXRvciArIGtleTsgLy8gc2luZ3VsYXJcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICB0cmFuc2xhdGVkID0gdHJhbnNsYXRlKHBsdXJhbEtleSwgb3B0aW9uV2l0aG91dENvdW50KTtcbiAgICBcbiAgICAgICAgICAgIGlmICh0cmFuc2xhdGVkICE9IG8ucGx1cmFsTm90Rm91bmQpIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gYXBwbHlSZXBsYWNlbWVudCh0cmFuc2xhdGVkLCB7XG4gICAgICAgICAgICAgICAgICAgIGNvdW50OiBvcHRpb25zLmNvdW50LFxuICAgICAgICAgICAgICAgICAgICBpbnRlcnBvbGF0aW9uUHJlZml4OiBvcHRpb25zLmludGVycG9sYXRpb25QcmVmaXgsXG4gICAgICAgICAgICAgICAgICAgIGludGVycG9sYXRpb25TdWZmaXg6IG9wdGlvbnMuaW50ZXJwb2xhdGlvblN1ZmZpeFxuICAgICAgICAgICAgICAgIH0pOyAvLyBhcHBseSByZXBsYWNlbWVudCBmb3IgY291bnQgb25seVxuICAgICAgICAgICAgfSBlbHNlIGlmIChsbmdzLmxlbmd0aCA+IDEpIHtcbiAgICAgICAgICAgICAgICAvLyByZW1vdmUgZmFpbGVkIGxuZ1xuICAgICAgICAgICAgICAgIHZhciBjbG9uZSA9IGxuZ3Muc2xpY2UoKTtcbiAgICAgICAgICAgICAgICBjbG9uZS5zaGlmdCgpO1xuICAgICAgICAgICAgICAgIG9wdGlvbnMgPSBmLmV4dGVuZChvcHRpb25zLCB7IGxuZ3M6IGNsb25lIH0pO1xuICAgICAgICAgICAgICAgIGRlbGV0ZSBvcHRpb25zLmxuZztcbiAgICAgICAgICAgICAgICAvLyByZXRyeSB3aXRoIGZhbGxiYWNrc1xuICAgICAgICAgICAgICAgIHRyYW5zbGF0ZWQgPSB0cmFuc2xhdGUobnMgKyBvLm5zc2VwYXJhdG9yICsga2V5LCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICBpZiAodHJhbnNsYXRlZCAhPSBvLnBsdXJhbE5vdEZvdW5kKSByZXR1cm4gdHJhbnNsYXRlZDtcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRyYW5zbGF0ZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgaWYgKG5lZWRzSW5kZWZpbml0ZUFydGljbGUob3B0aW9ucykpIHtcbiAgICAgICAgICAgIHZhciBvcHRpb25zV2l0aG91dEluZGVmID0gZi5leHRlbmQoe30sIG9wdGlvbnMpO1xuICAgICAgICAgICAgZGVsZXRlIG9wdGlvbnNXaXRob3V0SW5kZWYuaW5kZWZpbml0ZV9hcnRpY2xlO1xuICAgICAgICAgICAgb3B0aW9uc1dpdGhvdXRJbmRlZi5kZWZhdWx0VmFsdWUgPSBvLmluZGVmaW5pdGVOb3RGb3VuZDtcbiAgICAgICAgICAgIC8vIElmIHdlIGRvbid0IGhhdmUgYSBjb3VudCwgd2Ugd2FudCB0aGUgaW5kZWZpbml0ZSwgaWYgd2UgZG8gaGF2ZSBhIGNvdW50LCBhbmQgbmVlZHNQbHVyYWwgaXMgZmFsc2VcbiAgICAgICAgICAgIHZhciBpbmRlZmluaXRlS2V5ID0gbnMgKyBvLm5zc2VwYXJhdG9yICsga2V5ICsgKCgob3B0aW9ucy5jb3VudCAmJiAhbmVlZHNQbHVyYWwob3B0aW9ucywgbG5nc1swXSkpIHx8ICFvcHRpb25zLmNvdW50KSA/IG8uaW5kZWZpbml0ZVN1ZmZpeCA6IFwiXCIpO1xuICAgICAgICAgICAgdHJhbnNsYXRlZCA9IHRyYW5zbGF0ZShpbmRlZmluaXRlS2V5LCBvcHRpb25zV2l0aG91dEluZGVmKTtcbiAgICAgICAgICAgIGlmICh0cmFuc2xhdGVkICE9IG8uaW5kZWZpbml0ZU5vdEZvdW5kKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIHRyYW5zbGF0ZWQ7XG4gICAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgdmFyIGZvdW5kO1xuICAgICAgICB2YXIga2V5cyA9IGtleS5zcGxpdChvLmtleXNlcGFyYXRvcik7XG4gICAgICAgIGZvciAodmFyIGkgPSAwLCBsZW4gPSBsbmdzLmxlbmd0aDsgaSA8IGxlbjsgaSsrICkge1xuICAgICAgICAgICAgaWYgKGZvdW5kICE9PSB1bmRlZmluZWQpIGJyZWFrO1xuICAgIFxuICAgICAgICAgICAgdmFyIGwgPSBsbmdzW2ldO1xuICAgIFxuICAgICAgICAgICAgdmFyIHggPSAwO1xuICAgICAgICAgICAgdmFyIHZhbHVlID0gcmVzU3RvcmVbbF0gJiYgcmVzU3RvcmVbbF1bbnNdO1xuICAgICAgICAgICAgd2hpbGUgKGtleXNbeF0pIHtcbiAgICAgICAgICAgICAgICB2YWx1ZSA9IHZhbHVlICYmIHZhbHVlW2tleXNbeF1dO1xuICAgICAgICAgICAgICAgIHgrKztcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIGlmICh2YWx1ZSAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICAgICAgICAgICAgdmFyIHZhbHVlVHlwZSA9IE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuYXBwbHkodmFsdWUpO1xuICAgICAgICAgICAgICAgIGlmICh0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnKSB7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gYXBwbHlSZXBsYWNlbWVudCh2YWx1ZSwgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgICAgIHZhbHVlID0gYXBwbHlSZXVzZSh2YWx1ZSwgb3B0aW9ucyk7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZVR5cGUgPT09ICdbb2JqZWN0IEFycmF5XScgJiYgIW8ucmV0dXJuT2JqZWN0VHJlZXMgJiYgIW9wdGlvbnMucmV0dXJuT2JqZWN0VHJlZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB2YWx1ZS5qb2luKCdcXG4nKTtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBhcHBseVJlcGxhY2VtZW50KHZhbHVlLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSBhcHBseVJldXNlKHZhbHVlLCBvcHRpb25zKTtcbiAgICAgICAgICAgICAgICB9IGVsc2UgaWYgKHZhbHVlID09PSBudWxsICYmIG8uZmFsbGJhY2tPbk51bGwgPT09IHRydWUpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICBpZiAoIW8ucmV0dXJuT2JqZWN0VHJlZXMgJiYgIW9wdGlvbnMucmV0dXJuT2JqZWN0VHJlZXMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmIChvLm9iamVjdFRyZWVLZXlIYW5kbGVyICYmIHR5cGVvZiBvLm9iamVjdFRyZWVLZXlIYW5kbGVyID09ICdmdW5jdGlvbicpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IG8ub2JqZWN0VHJlZUtleUhhbmRsZXIoa2V5LCB2YWx1ZSwgbCwgbnMsIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9ICdrZXkgXFwnJyArIG5zICsgJzonICsga2V5ICsgJyAoJyArIGwgKyAnKVxcJyAnICtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgJ3JldHVybmVkIGFuIG9iamVjdCBpbnN0ZWFkIG9mIHN0cmluZy4nO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGYubG9nKHZhbHVlKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIGlmICh2YWx1ZVR5cGUgIT09ICdbb2JqZWN0IE51bWJlcl0nICYmIHZhbHVlVHlwZSAhPT0gJ1tvYmplY3QgRnVuY3Rpb25dJyAmJiB2YWx1ZVR5cGUgIT09ICdbb2JqZWN0IFJlZ0V4cF0nKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIgY29weSA9ICh2YWx1ZVR5cGUgPT09ICdbb2JqZWN0IEFycmF5XScpID8gW10gOiB7fTsgLy8gYXBwbHkgY2hpbGQgdHJhbnNsYXRpb24gb24gYSBjb3B5XG4gICAgICAgICAgICAgICAgICAgICAgICBmLmVhY2godmFsdWUsIGZ1bmN0aW9uKG0pIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb3B5W21dID0gX3RyYW5zbGF0ZShucyArIG8ubnNzZXBhcmF0b3IgKyBrZXkgKyBvLmtleXNlcGFyYXRvciArIG0sIG9wdGlvbnMpO1xuICAgICAgICAgICAgICAgICAgICAgICAgfSk7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YWx1ZSA9IGNvcHk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAgICAgaWYgKHR5cGVvZiB2YWx1ZSA9PT0gJ3N0cmluZycgJiYgdmFsdWUudHJpbSgpID09PSAnJyAmJiBvLmZhbGxiYWNrT25FbXB0eSA9PT0gdHJ1ZSlcbiAgICAgICAgICAgICAgICAgICAgdmFsdWUgPSB1bmRlZmluZWQ7XG4gICAgXG4gICAgICAgICAgICAgICAgZm91bmQgPSB2YWx1ZTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgIFxuICAgICAgICBpZiAoZm91bmQgPT09IHVuZGVmaW5lZCAmJiAhb3B0aW9ucy5pc0ZhbGxiYWNrTG9va3VwICYmIChvLmZhbGxiYWNrVG9EZWZhdWx0TlMgPT09IHRydWUgfHwgKG8uZmFsbGJhY2tOUyAmJiBvLmZhbGxiYWNrTlMubGVuZ3RoID4gMCkpKSB7XG4gICAgICAgICAgICAvLyBzZXQgZmxhZyBmb3IgZmFsbGJhY2sgbG9va3VwIC0gYXZvaWQgcmVjdXJzaW9uXG4gICAgICAgICAgICBvcHRpb25zLmlzRmFsbGJhY2tMb29rdXAgPSB0cnVlO1xuICAgIFxuICAgICAgICAgICAgaWYgKG8uZmFsbGJhY2tOUy5sZW5ndGgpIHtcbiAgICBcbiAgICAgICAgICAgICAgICBmb3IgKHZhciB5ID0gMCwgbGVuWSA9IG8uZmFsbGJhY2tOUy5sZW5ndGg7IHkgPCBsZW5ZOyB5KyspIHtcbiAgICAgICAgICAgICAgICAgICAgZm91bmQgPSBfZmluZChvLmZhbGxiYWNrTlNbeV0gKyBvLm5zc2VwYXJhdG9yICsga2V5LCBvcHRpb25zKTtcbiAgICBcbiAgICAgICAgICAgICAgICAgICAgaWYgKGZvdW5kIHx8IChmb3VuZD09PVwiXCIgJiYgby5mYWxsYmFja09uRW1wdHkgPT09IGZhbHNlKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgLyogY29tcGFyZSB2YWx1ZSB3aXRob3V0IG5hbWVzcGFjZSAqL1xuICAgICAgICAgICAgICAgICAgICAgICAgdmFyIGZvdW5kVmFsdWUgPSBmb3VuZC5pbmRleE9mKG8ubnNzZXBhcmF0b3IpID4gLTEgPyBmb3VuZC5zcGxpdChvLm5zc2VwYXJhdG9yKVsxXSA6IGZvdW5kXG4gICAgICAgICAgICAgICAgICAgICAgICAgICwgbm90Rm91bmRWYWx1ZSA9IG5vdEZvdW5kLmluZGV4T2Yoby5uc3NlcGFyYXRvcikgPiAtMSA/IG5vdEZvdW5kLnNwbGl0KG8ubnNzZXBhcmF0b3IpWzFdIDogbm90Rm91bmQ7XG4gICAgXG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoZm91bmRWYWx1ZSAhPT0gbm90Rm91bmRWYWx1ZSkgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICAgIGZvdW5kID0gX2ZpbmQoa2V5LCBvcHRpb25zKTsgLy8gZmFsbGJhY2sgdG8gZGVmYXVsdCBOU1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgb3B0aW9ucy5pc0ZhbGxiYWNrTG9va3VwID0gZmFsc2U7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgcmV0dXJuIGZvdW5kO1xuICAgIH1cbiAgICBmdW5jdGlvbiBkZXRlY3RMYW5ndWFnZSgpIHtcbiAgICAgICAgdmFyIGRldGVjdGVkTG5nO1xuICAgICAgICB2YXIgd2hpdGVsaXN0ID0gby5sbmdXaGl0ZWxpc3QgfHwgW107XG4gICAgICAgIHZhciB1c2VyTG5nQ2hvaWNlcyA9IFtdO1xuICAgIFxuICAgICAgICAvLyBnZXQgZnJvbSBxc1xuICAgICAgICB2YXIgcXNQYXJtID0gW107XG4gICAgICAgIGlmICh0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJykge1xuICAgICAgICAgICAgKGZ1bmN0aW9uKCkge1xuICAgICAgICAgICAgICAgIHZhciBxdWVyeSA9IHdpbmRvdy5sb2NhdGlvbi5zZWFyY2guc3Vic3RyaW5nKDEpO1xuICAgICAgICAgICAgICAgIHZhciBwYXJhbXMgPSBxdWVyeS5zcGxpdCgnJicpO1xuICAgICAgICAgICAgICAgIGZvciAodmFyIGk9MDsgaTxwYXJhbXMubGVuZ3RoOyBpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIHBvcyA9IHBhcmFtc1tpXS5pbmRleE9mKCc9Jyk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChwb3MgPiAwKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB2YXIga2V5ID0gcGFyYW1zW2ldLnN1YnN0cmluZygwLHBvcyk7XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoa2V5ID09IG8uZGV0ZWN0TG5nUVMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB1c2VyTG5nQ2hvaWNlcy5wdXNoKHBhcmFtc1tpXS5zdWJzdHJpbmcocG9zKzEpKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH0pKCk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgLy8gZ2V0IGZyb20gY29va2llXG4gICAgICAgIGlmIChvLnVzZUNvb2tpZSAmJiB0eXBlb2YgZG9jdW1lbnQgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICB2YXIgYyA9IGYuY29va2llLnJlYWQoby5jb29raWVOYW1lKTtcbiAgICAgICAgICAgIGlmIChjKSB1c2VyTG5nQ2hvaWNlcy5wdXNoKGMpO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIC8vIGdldCBmcm9tIGxvY2FsU3RvcmFnZVxuICAgICAgICBpZiAoby5kZXRlY3RMbmdGcm9tTG9jYWxTdG9yYWdlICYmIHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICYmIHdpbmRvdy5sb2NhbFN0b3JhZ2UpIHtcbiAgICAgICAgICAgIHVzZXJMbmdDaG9pY2VzLnB1c2god2luZG93LmxvY2FsU3RvcmFnZS5nZXRJdGVtKCdpMThuZXh0X2xuZycpKTtcbiAgICAgICAgfVxuICAgIFxuICAgICAgICAvLyBnZXQgZnJvbSBuYXZpZ2F0b3JcbiAgICAgICAgaWYgKHR5cGVvZiBuYXZpZ2F0b3IgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgICAgICBpZiAobmF2aWdhdG9yLmxhbmd1YWdlcykgeyAvLyBjaHJvbWUgb25seTsgbm90IGFuIGFycmF5LCBzbyBjYW4ndCB1c2UgLnB1c2guYXBwbHkgaW5zdGVhZCBvZiBpdGVyYXRpbmdcbiAgICAgICAgICAgICAgICBmb3IgKHZhciBpPTA7aTxuYXZpZ2F0b3IubGFuZ3VhZ2VzLmxlbmd0aDtpKyspIHtcbiAgICAgICAgICAgICAgICAgICAgdXNlckxuZ0Nob2ljZXMucHVzaChuYXZpZ2F0b3IubGFuZ3VhZ2VzW2ldKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobmF2aWdhdG9yLnVzZXJMYW5ndWFnZSkge1xuICAgICAgICAgICAgICAgIHVzZXJMbmdDaG9pY2VzLnB1c2gobmF2aWdhdG9yLnVzZXJMYW5ndWFnZSk7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBpZiAobmF2aWdhdG9yLmxhbmd1YWdlKSB7XG4gICAgICAgICAgICAgICAgdXNlckxuZ0Nob2ljZXMucHVzaChuYXZpZ2F0b3IubGFuZ3VhZ2UpO1xuICAgICAgICAgICAgfVxuICAgICAgICB9XG4gICAgXG4gICAgICAgIChmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGZvciAodmFyIGk9MDtpPHVzZXJMbmdDaG9pY2VzLmxlbmd0aDtpKyspIHtcbiAgICAgICAgICAgICAgICB2YXIgbG5nID0gdXNlckxuZ0Nob2ljZXNbaV07XG4gICAgXG4gICAgICAgICAgICAgICAgaWYgKGxuZy5pbmRleE9mKCctJykgPiAtMSkge1xuICAgICAgICAgICAgICAgICAgICB2YXIgcGFydHMgPSBsbmcuc3BsaXQoJy0nKTtcbiAgICAgICAgICAgICAgICAgICAgbG5nID0gby5sb3dlckNhc2VMbmcgP1xuICAgICAgICAgICAgICAgICAgICAgICAgcGFydHNbMF0udG9Mb3dlckNhc2UoKSArICAnLScgKyBwYXJ0c1sxXS50b0xvd2VyQ2FzZSgpIDpcbiAgICAgICAgICAgICAgICAgICAgICAgIHBhcnRzWzBdLnRvTG93ZXJDYXNlKCkgKyAgJy0nICsgcGFydHNbMV0udG9VcHBlckNhc2UoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAgICAgaWYgKHdoaXRlbGlzdC5sZW5ndGggPT09IDAgfHwgd2hpdGVsaXN0LmluZGV4T2YobG5nKSA+IC0xKSB7XG4gICAgICAgICAgICAgICAgICAgIGRldGVjdGVkTG5nID0gbG5nO1xuICAgICAgICAgICAgICAgICAgICBicmVhaztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgIH0pKCk7XG4gICAgXG4gICAgICAgIC8vZmFsbGJhY2tcbiAgICAgICAgaWYgKCFkZXRlY3RlZExuZyl7XG4gICAgICAgICAgZGV0ZWN0ZWRMbmcgPSBvLmZhbGxiYWNrTG5nWzBdO1xuICAgICAgICB9XG4gICAgICAgIFxuICAgICAgICByZXR1cm4gZGV0ZWN0ZWRMbmc7XG4gICAgfVxuICAgIC8vIGRlZmluaXRpb24gaHR0cDovL3RyYW5zbGF0ZS5zb3VyY2Vmb3JnZS5uZXQvd2lraS9sMTBuL3BsdXJhbGZvcm1zXG4gICAgXG4gICAgLyogW2NvZGUsIG5hbWUsIG51bWJlcnMsIHBsdXJhbHNUeXBlXSAqL1xuICAgIHZhciBfcnVsZXMgPSBbXG4gICAgICAgIFtcImFjaFwiLCBcIkFjaG9saVwiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcImFmXCIsIFwiQWZyaWthYW5zXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJha1wiLCBcIkFrYW5cIiwgWzEsMl0sIDFdLFxuICAgICAgICBbXCJhbVwiLCBcIkFtaGFyaWNcIiwgWzEsMl0sIDFdLFxuICAgICAgICBbXCJhblwiLCBcIkFyYWdvbmVzZVwiLFsxLDJdLCAyXSxcbiAgICAgICAgW1wiYXJcIiwgXCJBcmFiaWNcIiwgWzAsMSwyLDMsMTEsMTAwXSw1XSxcbiAgICAgICAgW1wiYXJuXCIsIFwiTWFwdWR1bmd1blwiLFsxLDJdLCAxXSxcbiAgICAgICAgW1wiYXN0XCIsIFwiQXN0dXJpYW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJheVwiLCBcIkF5bWFyw6FcIiwgWzFdLCAzXSxcbiAgICAgICAgW1wiYXpcIiwgXCJBemVyYmFpamFuaVwiLFsxLDJdLDJdLFxuICAgICAgICBbXCJiZVwiLCBcIkJlbGFydXNpYW5cIixbMSwyLDVdLDRdLFxuICAgICAgICBbXCJiZ1wiLCBcIkJ1bGdhcmlhblwiLFsxLDJdLCAyXSxcbiAgICAgICAgW1wiYm5cIiwgXCJCZW5nYWxpXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiYm9cIiwgXCJUaWJldGFuXCIsIFsxXSwgM10sXG4gICAgICAgIFtcImJyXCIsIFwiQnJldG9uXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1wiYnNcIiwgXCJCb3NuaWFuXCIsIFsxLDIsNV0sNF0sXG4gICAgICAgIFtcImNhXCIsIFwiQ2F0YWxhblwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImNnZ1wiLCBcIkNoaWdhXCIsIFsxXSwgM10sXG4gICAgICAgIFtcImNzXCIsIFwiQ3plY2hcIiwgWzEsMiw1XSw2XSxcbiAgICAgICAgW1wiY3NiXCIsIFwiS2FzaHViaWFuXCIsWzEsMiw1XSw3XSxcbiAgICAgICAgW1wiY3lcIiwgXCJXZWxzaFwiLCBbMSwyLDMsOF0sOF0sXG4gICAgICAgIFtcImRhXCIsIFwiRGFuaXNoXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZGVcIiwgXCJHZXJtYW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJkZXZcIiwgXCJEZXZlbG9wbWVudCBGYWxsYmFja1wiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImR6XCIsIFwiRHpvbmdraGFcIiwgWzFdLCAzXSxcbiAgICAgICAgW1wiZWxcIiwgXCJHcmVla1wiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImVuXCIsIFwiRW5nbGlzaFwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImVvXCIsIFwiRXNwZXJhbnRvXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJlc1wiLCBcIlNwYW5pc2hcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJlc19hclwiLFwiQXJnZW50aW5lYW4gU3BhbmlzaFwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImV0XCIsIFwiRXN0b25pYW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJldVwiLCBcIkJhc3F1ZVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImZhXCIsIFwiUGVyc2lhblwiLCBbMV0sIDNdLFxuICAgICAgICBbXCJmaVwiLCBcIkZpbm5pc2hcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJmaWxcIiwgXCJGaWxpcGlub1wiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcImZvXCIsIFwiRmFyb2VzZVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImZyXCIsIFwiRnJlbmNoXCIsIFsxLDJdLCA5XSxcbiAgICAgICAgW1wiZnVyXCIsIFwiRnJpdWxpYW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJmeVwiLCBcIkZyaXNpYW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJnYVwiLCBcIklyaXNoXCIsIFsxLDIsMyw3LDExXSwxMF0sXG4gICAgICAgIFtcImdkXCIsIFwiU2NvdHRpc2ggR2FlbGljXCIsWzEsMiwzLDIwXSwxMV0sXG4gICAgICAgIFtcImdsXCIsIFwiR2FsaWNpYW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJndVwiLCBcIkd1amFyYXRpXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiZ3VuXCIsIFwiR3VuXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1wiaGFcIiwgXCJIYXVzYVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImhlXCIsIFwiSGVicmV3XCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiaGlcIiwgXCJIaW5kaVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcImhyXCIsIFwiQ3JvYXRpYW5cIiwgWzEsMiw1XSw0XSxcbiAgICAgICAgW1wiaHVcIiwgXCJIdW5nYXJpYW5cIixbMSwyXSwgMl0sXG4gICAgICAgIFtcImh5XCIsIFwiQXJtZW5pYW5cIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJpYVwiLCBcIkludGVybGluZ3VhXCIsWzEsMl0sMl0sXG4gICAgICAgIFtcImlkXCIsIFwiSW5kb25lc2lhblwiLFsxXSwgM10sXG4gICAgICAgIFtcImlzXCIsIFwiSWNlbGFuZGljXCIsWzEsMl0sIDEyXSxcbiAgICAgICAgW1wiaXRcIiwgXCJJdGFsaWFuXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wiamFcIiwgXCJKYXBhbmVzZVwiLCBbMV0sIDNdLFxuICAgICAgICBbXCJqYm9cIiwgXCJMb2piYW5cIiwgWzFdLCAzXSxcbiAgICAgICAgW1wianZcIiwgXCJKYXZhbmVzZVwiLCBbMCwxXSwgMTNdLFxuICAgICAgICBbXCJrYVwiLCBcIkdlb3JnaWFuXCIsIFsxXSwgM10sXG4gICAgICAgIFtcImtrXCIsIFwiS2F6YWtoXCIsIFsxXSwgM10sXG4gICAgICAgIFtcImttXCIsIFwiS2htZXJcIiwgWzFdLCAzXSxcbiAgICAgICAgW1wia25cIiwgXCJLYW5uYWRhXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wia29cIiwgXCJLb3JlYW5cIiwgWzFdLCAzXSxcbiAgICAgICAgW1wia3VcIiwgXCJLdXJkaXNoXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wia3dcIiwgXCJDb3JuaXNoXCIsIFsxLDIsMyw0XSwxNF0sXG4gICAgICAgIFtcImt5XCIsIFwiS3lyZ3l6XCIsIFsxXSwgM10sXG4gICAgICAgIFtcImxiXCIsIFwiTGV0emVidXJnZXNjaFwiLFsxLDJdLDJdLFxuICAgICAgICBbXCJsblwiLCBcIkxpbmdhbGFcIiwgWzEsMl0sIDFdLFxuICAgICAgICBbXCJsb1wiLCBcIkxhb1wiLCBbMV0sIDNdLFxuICAgICAgICBbXCJsdFwiLCBcIkxpdGh1YW5pYW5cIixbMSwyLDEwXSwxNV0sXG4gICAgICAgIFtcImx2XCIsIFwiTGF0dmlhblwiLCBbMSwyLDBdLDE2XSxcbiAgICAgICAgW1wibWFpXCIsIFwiTWFpdGhpbGlcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJtZmVcIiwgXCJNYXVyaXRpYW4gQ3Jlb2xlXCIsWzEsMl0sMV0sXG4gICAgICAgIFtcIm1nXCIsIFwiTWFsYWdhc3lcIiwgWzEsMl0sIDFdLFxuICAgICAgICBbXCJtaVwiLCBcIk1hb3JpXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1wibWtcIiwgXCJNYWNlZG9uaWFuXCIsWzEsMl0sMTddLFxuICAgICAgICBbXCJtbFwiLCBcIk1hbGF5YWxhbVwiLFsxLDJdLCAyXSxcbiAgICAgICAgW1wibW5cIiwgXCJNb25nb2xpYW5cIixbMSwyXSwgMl0sXG4gICAgICAgIFtcIm1ua1wiLCBcIk1hbmRpbmthXCIsIFswLDEsMl0sMThdLFxuICAgICAgICBbXCJtclwiLCBcIk1hcmF0aGlcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJtc1wiLCBcIk1hbGF5XCIsIFsxXSwgM10sXG4gICAgICAgIFtcIm10XCIsIFwiTWFsdGVzZVwiLCBbMSwyLDExLDIwXSwxOV0sXG4gICAgICAgIFtcIm5haFwiLCBcIk5haHVhdGxcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJuYXBcIiwgXCJOZWFwb2xpdGFuXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJuYlwiLCBcIk5vcndlZ2lhbiBCb2ttYWxcIixbMSwyXSwyXSxcbiAgICAgICAgW1wibmVcIiwgXCJOZXBhbGlcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJubFwiLCBcIkR1dGNoXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wibm5cIiwgXCJOb3J3ZWdpYW4gTnlub3Jza1wiLFsxLDJdLDJdLFxuICAgICAgICBbXCJub1wiLCBcIk5vcndlZ2lhblwiLFsxLDJdLCAyXSxcbiAgICAgICAgW1wibnNvXCIsIFwiTm9ydGhlcm4gU290aG9cIixbMSwyXSwyXSxcbiAgICAgICAgW1wib2NcIiwgXCJPY2NpdGFuXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1wib3JcIiwgXCJPcml5YVwiLCBbMiwxXSwgMl0sXG4gICAgICAgIFtcInBhXCIsIFwiUHVuamFiaVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInBhcFwiLCBcIlBhcGlhbWVudG9cIixbMSwyXSwgMl0sXG4gICAgICAgIFtcInBsXCIsIFwiUG9saXNoXCIsIFsxLDIsNV0sN10sXG4gICAgICAgIFtcInBtc1wiLCBcIlBpZW1vbnRlc2VcIixbMSwyXSwgMl0sXG4gICAgICAgIFtcInBzXCIsIFwiUGFzaHRvXCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wicHRcIiwgXCJQb3J0dWd1ZXNlXCIsWzEsMl0sIDJdLFxuICAgICAgICBbXCJwdF9iclwiLFwiQnJhemlsaWFuIFBvcnR1Z3Vlc2VcIixbMSwyXSwgMl0sXG4gICAgICAgIFtcInJtXCIsIFwiUm9tYW5zaFwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInJvXCIsIFwiUm9tYW5pYW5cIiwgWzEsMiwyMF0sMjBdLFxuICAgICAgICBbXCJydVwiLCBcIlJ1c3NpYW5cIiwgWzEsMiw1XSw0XSxcbiAgICAgICAgW1wic2FoXCIsIFwiWWFrdXRcIiwgWzFdLCAzXSxcbiAgICAgICAgW1wic2NvXCIsIFwiU2NvdHNcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJzZVwiLCBcIk5vcnRoZXJuIFNhbWlcIixbMSwyXSwgMl0sXG4gICAgICAgIFtcInNpXCIsIFwiU2luaGFsYVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInNrXCIsIFwiU2xvdmFrXCIsIFsxLDIsNV0sNl0sXG4gICAgICAgIFtcInNsXCIsIFwiU2xvdmVuaWFuXCIsWzUsMSwyLDNdLDIxXSxcbiAgICAgICAgW1wic29cIiwgXCJTb21hbGlcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJzb25cIiwgXCJTb25naGF5XCIsIFsxLDJdLCAyXSxcbiAgICAgICAgW1wic3FcIiwgXCJBbGJhbmlhblwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInNyXCIsIFwiU2VyYmlhblwiLCBbMSwyLDVdLDRdLFxuICAgICAgICBbXCJzdVwiLCBcIlN1bmRhbmVzZVwiLFsxXSwgM10sXG4gICAgICAgIFtcInN2XCIsIFwiU3dlZGlzaFwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInN3XCIsIFwiU3dhaGlsaVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInRhXCIsIFwiVGFtaWxcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJ0ZVwiLCBcIlRlbHVndVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInRnXCIsIFwiVGFqaWtcIiwgWzEsMl0sIDFdLFxuICAgICAgICBbXCJ0aFwiLCBcIlRoYWlcIiwgWzFdLCAzXSxcbiAgICAgICAgW1widGlcIiwgXCJUaWdyaW55YVwiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcInRrXCIsIFwiVHVya21lblwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInRyXCIsIFwiVHVya2lzaFwiLCBbMSwyXSwgMV0sXG4gICAgICAgIFtcInR0XCIsIFwiVGF0YXJcIiwgWzFdLCAzXSxcbiAgICAgICAgW1widWdcIiwgXCJVeWdodXJcIiwgWzFdLCAzXSxcbiAgICAgICAgW1widWtcIiwgXCJVa3JhaW5pYW5cIixbMSwyLDVdLDRdLFxuICAgICAgICBbXCJ1clwiLCBcIlVyZHVcIiwgWzEsMl0sIDJdLFxuICAgICAgICBbXCJ1elwiLCBcIlV6YmVrXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1widmlcIiwgXCJWaWV0bmFtZXNlXCIsWzFdLCAzXSxcbiAgICAgICAgW1wid2FcIiwgXCJXYWxsb29uXCIsIFsxLDJdLCAxXSxcbiAgICAgICAgW1wid29cIiwgXCJXb2xvZlwiLCBbMV0sIDNdLFxuICAgICAgICBbXCJ5b1wiLCBcIllvcnViYVwiLCBbMSwyXSwgMl0sXG4gICAgICAgIFtcInpoXCIsIFwiQ2hpbmVzZVwiLCBbMV0sIDNdXG4gICAgXTtcbiAgICBcbiAgICB2YXIgX3J1bGVzUGx1cmFsc1R5cGVzID0ge1xuICAgICAgICAxOiBmdW5jdGlvbihuKSB7cmV0dXJuIE51bWJlcihuID4gMSk7fSxcbiAgICAgICAgMjogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobiAhPSAxKTt9LFxuICAgICAgICAzOiBmdW5jdGlvbihuKSB7cmV0dXJuIDA7fSxcbiAgICAgICAgNDogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobiUxMD09MSAmJiBuJTEwMCE9MTEgPyAwIDogbiUxMD49MiAmJiBuJTEwPD00ICYmIChuJTEwMDwxMCB8fCBuJTEwMD49MjApID8gMSA6IDIpO30sXG4gICAgICAgIDU6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG49PT0wID8gMCA6IG49PTEgPyAxIDogbj09MiA/IDIgOiBuJTEwMD49MyAmJiBuJTEwMDw9MTAgPyAzIDogbiUxMDA+PTExID8gNCA6IDUpO30sXG4gICAgICAgIDY6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKChuPT0xKSA/IDAgOiAobj49MiAmJiBuPD00KSA/IDEgOiAyKTt9LFxuICAgICAgICA3OiBmdW5jdGlvbihuKSB7cmV0dXJuIE51bWJlcihuPT0xID8gMCA6IG4lMTA+PTIgJiYgbiUxMDw9NCAmJiAobiUxMDA8MTAgfHwgbiUxMDA+PTIwKSA/IDEgOiAyKTt9LFxuICAgICAgICA4OiBmdW5jdGlvbihuKSB7cmV0dXJuIE51bWJlcigobj09MSkgPyAwIDogKG49PTIpID8gMSA6IChuICE9IDggJiYgbiAhPSAxMSkgPyAyIDogMyk7fSxcbiAgICAgICAgOTogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobiA+PSAyKTt9LFxuICAgICAgICAxMDogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobj09MSA/IDAgOiBuPT0yID8gMSA6IG48NyA/IDIgOiBuPDExID8gMyA6IDQpIDt9LFxuICAgICAgICAxMTogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIoKG49PTEgfHwgbj09MTEpID8gMCA6IChuPT0yIHx8IG49PTEyKSA/IDEgOiAobiA+IDIgJiYgbiA8IDIwKSA/IDIgOiAzKTt9LFxuICAgICAgICAxMjogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobiUxMCE9MSB8fCBuJTEwMD09MTEpO30sXG4gICAgICAgIDEzOiBmdW5jdGlvbihuKSB7cmV0dXJuIE51bWJlcihuICE9PSAwKTt9LFxuICAgICAgICAxNDogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIoKG49PTEpID8gMCA6IChuPT0yKSA/IDEgOiAobiA9PSAzKSA/IDIgOiAzKTt9LFxuICAgICAgICAxNTogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobiUxMD09MSAmJiBuJTEwMCE9MTEgPyAwIDogbiUxMD49MiAmJiAobiUxMDA8MTAgfHwgbiUxMDA+PTIwKSA/IDEgOiAyKTt9LFxuICAgICAgICAxNjogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobiUxMD09MSAmJiBuJTEwMCE9MTEgPyAwIDogbiAhPT0gMCA/IDEgOiAyKTt9LFxuICAgICAgICAxNzogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobj09MSB8fCBuJTEwPT0xID8gMCA6IDEpO30sXG4gICAgICAgIDE4OiBmdW5jdGlvbihuKSB7cmV0dXJuIE51bWJlcigwID8gMCA6IG49PTEgPyAxIDogMik7fSxcbiAgICAgICAgMTk6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG49PTEgPyAwIDogbj09PTAgfHwgKCBuJTEwMD4xICYmIG4lMTAwPDExKSA/IDEgOiAobiUxMDA+MTAgJiYgbiUxMDA8MjAgKSA/IDIgOiAzKTt9LFxuICAgICAgICAyMDogZnVuY3Rpb24obikge3JldHVybiBOdW1iZXIobj09MSA/IDAgOiAobj09PTAgfHwgKG4lMTAwID4gMCAmJiBuJTEwMCA8IDIwKSkgPyAxIDogMik7fSxcbiAgICAgICAgMjE6IGZ1bmN0aW9uKG4pIHtyZXR1cm4gTnVtYmVyKG4lMTAwPT0xID8gMSA6IG4lMTAwPT0yID8gMiA6IG4lMTAwPT0zIHx8IG4lMTAwPT00ID8gMyA6IDApOyB9XG4gICAgfTtcbiAgICBcbiAgICB2YXIgcGx1cmFsRXh0ZW5zaW9ucyA9IHtcbiAgICBcbiAgICAgICAgcnVsZXM6IChmdW5jdGlvbiAoKSB7XG4gICAgICAgICAgICB2YXIgbCwgcnVsZXMgPSB7fTtcbiAgICAgICAgICAgIGZvciAobD1fcnVsZXMubGVuZ3RoOyBsLS0gOykge1xuICAgICAgICAgICAgICAgIHJ1bGVzW19ydWxlc1tsXVswXV0gPSB7XG4gICAgICAgICAgICAgICAgICAgIG5hbWU6IF9ydWxlc1tsXVsxXSxcbiAgICAgICAgICAgICAgICAgICAgbnVtYmVyczogX3J1bGVzW2xdWzJdLFxuICAgICAgICAgICAgICAgICAgICBwbHVyYWxzOiBfcnVsZXNQbHVyYWxzVHlwZXNbX3J1bGVzW2xdWzNdXVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBydWxlcztcbiAgICAgICAgfSgpKSxcbiAgICBcbiAgICAgICAgLy8geW91IGNhbiBhZGQgeW91ciBvd24gcGx1cmFsRXh0ZW5zaW9uc1xuICAgICAgICBhZGRSdWxlOiBmdW5jdGlvbihsbmcsIG9iaikge1xuICAgICAgICAgICAgcGx1cmFsRXh0ZW5zaW9ucy5ydWxlc1tsbmddID0gb2JqO1xuICAgICAgICB9LFxuICAgIFxuICAgICAgICBzZXRDdXJyZW50TG5nOiBmdW5jdGlvbihsbmcpIHtcbiAgICAgICAgICAgIGlmICghcGx1cmFsRXh0ZW5zaW9ucy5jdXJyZW50UnVsZSB8fCBwbHVyYWxFeHRlbnNpb25zLmN1cnJlbnRSdWxlLmxuZyAhPT0gbG5nKSB7XG4gICAgICAgICAgICAgICAgdmFyIHBhcnRzID0gbG5nLnNwbGl0KCctJyk7XG4gICAgXG4gICAgICAgICAgICAgICAgcGx1cmFsRXh0ZW5zaW9ucy5jdXJyZW50UnVsZSA9IHtcbiAgICAgICAgICAgICAgICAgICAgbG5nOiBsbmcsXG4gICAgICAgICAgICAgICAgICAgIHJ1bGU6IHBsdXJhbEV4dGVuc2lvbnMucnVsZXNbcGFydHNbMF1dXG4gICAgICAgICAgICAgICAgfTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICBcbiAgICAgICAgbmVlZHNQbHVyYWw6IGZ1bmN0aW9uKGxuZywgY291bnQpIHtcbiAgICAgICAgICAgIHZhciBwYXJ0cyA9IGxuZy5zcGxpdCgnLScpO1xuICAgIFxuICAgICAgICAgICAgdmFyIGV4dDtcbiAgICAgICAgICAgIGlmIChwbHVyYWxFeHRlbnNpb25zLmN1cnJlbnRSdWxlICYmIHBsdXJhbEV4dGVuc2lvbnMuY3VycmVudFJ1bGUubG5nID09PSBsbmcpIHtcbiAgICAgICAgICAgICAgICBleHQgPSBwbHVyYWxFeHRlbnNpb25zLmN1cnJlbnRSdWxlLnJ1bGU7IFxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICBleHQgPSBwbHVyYWxFeHRlbnNpb25zLnJ1bGVzW3BhcnRzW2YuZ2V0Q291bnR5SW5kZXhPZkxuZyhsbmcpXV07XG4gICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICBpZiAoZXh0ICYmIGV4dC5udW1iZXJzLmxlbmd0aCA8PSAxKSB7XG4gICAgICAgICAgICAgICAgcmV0dXJuIGZhbHNlO1xuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICByZXR1cm4gdGhpcy5nZXQobG5nLCBjb3VudCkgIT09IDE7XG4gICAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgXG4gICAgICAgIGdldDogZnVuY3Rpb24obG5nLCBjb3VudCkge1xuICAgICAgICAgICAgdmFyIHBhcnRzID0gbG5nLnNwbGl0KCctJyk7XG4gICAgXG4gICAgICAgICAgICBmdW5jdGlvbiBnZXRSZXN1bHQobCwgYykge1xuICAgICAgICAgICAgICAgIHZhciBleHQ7XG4gICAgICAgICAgICAgICAgaWYgKHBsdXJhbEV4dGVuc2lvbnMuY3VycmVudFJ1bGUgJiYgcGx1cmFsRXh0ZW5zaW9ucy5jdXJyZW50UnVsZS5sbmcgPT09IGxuZykge1xuICAgICAgICAgICAgICAgICAgICBleHQgPSBwbHVyYWxFeHRlbnNpb25zLmN1cnJlbnRSdWxlLnJ1bGU7IFxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIGV4dCA9IHBsdXJhbEV4dGVuc2lvbnMucnVsZXNbbF07XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGlmIChleHQpIHtcbiAgICAgICAgICAgICAgICAgICAgdmFyIGk7XG4gICAgICAgICAgICAgICAgICAgIGlmIChleHQubm9BYnMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGkgPSBleHQucGx1cmFscyhjKTtcbiAgICAgICAgICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGkgPSBleHQucGx1cmFscyhNYXRoLmFicyhjKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgXG4gICAgICAgICAgICAgICAgICAgIHZhciBudW1iZXIgPSBleHQubnVtYmVyc1tpXTtcbiAgICAgICAgICAgICAgICAgICAgaWYgKGV4dC5udW1iZXJzLmxlbmd0aCA9PT0gMiAmJiBleHQubnVtYmVyc1swXSA9PT0gMSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgaWYgKG51bWJlciA9PT0gMikgeyBcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBudW1iZXIgPSAtMTsgLy8gcmVndWxhciBwbHVyYWxcbiAgICAgICAgICAgICAgICAgICAgICAgIH0gZWxzZSBpZiAobnVtYmVyID09PSAxKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgbnVtYmVyID0gMTsgLy8gc2luZ3VsYXJcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfS8vY29uc29sZS5sb2coY291bnQgKyAnLScgKyBudW1iZXIpO1xuICAgICAgICAgICAgICAgICAgICByZXR1cm4gbnVtYmVyO1xuICAgICAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHJldHVybiBjID09PSAxID8gJzEnIDogJy0xJztcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBcbiAgICAgICAgICAgIHJldHVybiBnZXRSZXN1bHQocGFydHNbZi5nZXRDb3VudHlJbmRleE9mTG5nKGxuZyldLCBjb3VudCk7XG4gICAgICAgIH1cbiAgICBcbiAgICB9O1xuICAgIHZhciBwb3N0UHJvY2Vzc29ycyA9IHt9O1xuICAgIHZhciBhZGRQb3N0UHJvY2Vzc29yID0gZnVuY3Rpb24obmFtZSwgZmMpIHtcbiAgICAgICAgcG9zdFByb2Nlc3NvcnNbbmFtZV0gPSBmYztcbiAgICB9O1xuICAgIC8vIHNwcmludGYgc3VwcG9ydFxuICAgIHZhciBzcHJpbnRmID0gKGZ1bmN0aW9uKCkge1xuICAgICAgICBmdW5jdGlvbiBnZXRfdHlwZSh2YXJpYWJsZSkge1xuICAgICAgICAgICAgcmV0dXJuIE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuY2FsbCh2YXJpYWJsZSkuc2xpY2UoOCwgLTEpLnRvTG93ZXJDYXNlKCk7XG4gICAgICAgIH1cbiAgICAgICAgZnVuY3Rpb24gc3RyX3JlcGVhdChpbnB1dCwgbXVsdGlwbGllcikge1xuICAgICAgICAgICAgZm9yICh2YXIgb3V0cHV0ID0gW107IG11bHRpcGxpZXIgPiAwOyBvdXRwdXRbLS1tdWx0aXBsaWVyXSA9IGlucHV0KSB7LyogZG8gbm90aGluZyAqL31cbiAgICAgICAgICAgIHJldHVybiBvdXRwdXQuam9pbignJyk7XG4gICAgICAgIH1cbiAgICBcbiAgICAgICAgdmFyIHN0cl9mb3JtYXQgPSBmdW5jdGlvbigpIHtcbiAgICAgICAgICAgIGlmICghc3RyX2Zvcm1hdC5jYWNoZS5oYXNPd25Qcm9wZXJ0eShhcmd1bWVudHNbMF0pKSB7XG4gICAgICAgICAgICAgICAgc3RyX2Zvcm1hdC5jYWNoZVthcmd1bWVudHNbMF1dID0gc3RyX2Zvcm1hdC5wYXJzZShhcmd1bWVudHNbMF0pO1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIHN0cl9mb3JtYXQuZm9ybWF0LmNhbGwobnVsbCwgc3RyX2Zvcm1hdC5jYWNoZVthcmd1bWVudHNbMF1dLCBhcmd1bWVudHMpO1xuICAgICAgICB9O1xuICAgIFxuICAgICAgICBzdHJfZm9ybWF0LmZvcm1hdCA9IGZ1bmN0aW9uKHBhcnNlX3RyZWUsIGFyZ3YpIHtcbiAgICAgICAgICAgIHZhciBjdXJzb3IgPSAxLCB0cmVlX2xlbmd0aCA9IHBhcnNlX3RyZWUubGVuZ3RoLCBub2RlX3R5cGUgPSAnJywgYXJnLCBvdXRwdXQgPSBbXSwgaSwgaywgbWF0Y2gsIHBhZCwgcGFkX2NoYXJhY3RlciwgcGFkX2xlbmd0aDtcbiAgICAgICAgICAgIGZvciAoaSA9IDA7IGkgPCB0cmVlX2xlbmd0aDsgaSsrKSB7XG4gICAgICAgICAgICAgICAgbm9kZV90eXBlID0gZ2V0X3R5cGUocGFyc2VfdHJlZVtpXSk7XG4gICAgICAgICAgICAgICAgaWYgKG5vZGVfdHlwZSA9PT0gJ3N0cmluZycpIHtcbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0LnB1c2gocGFyc2VfdHJlZVtpXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKG5vZGVfdHlwZSA9PT0gJ2FycmF5Jykge1xuICAgICAgICAgICAgICAgICAgICBtYXRjaCA9IHBhcnNlX3RyZWVbaV07IC8vIGNvbnZlbmllbmNlIHB1cnBvc2VzIG9ubHlcbiAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoWzJdKSB7IC8vIGtleXdvcmQgYXJndW1lbnRcbiAgICAgICAgICAgICAgICAgICAgICAgIGFyZyA9IGFyZ3ZbY3Vyc29yXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIGZvciAoayA9IDA7IGsgPCBtYXRjaFsyXS5sZW5ndGg7IGsrKykge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICghYXJnLmhhc093blByb3BlcnR5KG1hdGNoWzJdW2tdKSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyhzcHJpbnRmKCdbc3ByaW50Zl0gcHJvcGVydHkgXCIlc1wiIGRvZXMgbm90IGV4aXN0JywgbWF0Y2hbMl1ba10pKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgYXJnID0gYXJnW21hdGNoWzJdW2tdXTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIGlmIChtYXRjaFsxXSkgeyAvLyBwb3NpdGlvbmFsIGFyZ3VtZW50IChleHBsaWNpdClcbiAgICAgICAgICAgICAgICAgICAgICAgIGFyZyA9IGFyZ3ZbbWF0Y2hbMV1dO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGVsc2UgeyAvLyBwb3NpdGlvbmFsIGFyZ3VtZW50IChpbXBsaWNpdClcbiAgICAgICAgICAgICAgICAgICAgICAgIGFyZyA9IGFyZ3ZbY3Vyc29yKytdO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgXG4gICAgICAgICAgICAgICAgICAgIGlmICgvW15zXS8udGVzdChtYXRjaFs4XSkgJiYgKGdldF90eXBlKGFyZykgIT0gJ251bWJlcicpKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICB0aHJvdyhzcHJpbnRmKCdbc3ByaW50Zl0gZXhwZWN0aW5nIG51bWJlciBidXQgZm91bmQgJXMnLCBnZXRfdHlwZShhcmcpKSk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgc3dpdGNoIChtYXRjaFs4XSkge1xuICAgICAgICAgICAgICAgICAgICAgICAgY2FzZSAnYic6IGFyZyA9IGFyZy50b1N0cmluZygyKTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdjJzogYXJnID0gU3RyaW5nLmZyb21DaGFyQ29kZShhcmcpOyBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2QnOiBhcmcgPSBwYXJzZUludChhcmcsIDEwKTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdlJzogYXJnID0gbWF0Y2hbN10gPyBhcmcudG9FeHBvbmVudGlhbChtYXRjaFs3XSkgOiBhcmcudG9FeHBvbmVudGlhbCgpOyBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ2YnOiBhcmcgPSBtYXRjaFs3XSA/IHBhcnNlRmxvYXQoYXJnKS50b0ZpeGVkKG1hdGNoWzddKSA6IHBhcnNlRmxvYXQoYXJnKTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdvJzogYXJnID0gYXJnLnRvU3RyaW5nKDgpOyBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgICAgIGNhc2UgJ3MnOiBhcmcgPSAoKGFyZyA9IFN0cmluZyhhcmcpKSAmJiBtYXRjaFs3XSA/IGFyZy5zdWJzdHJpbmcoMCwgbWF0Y2hbN10pIDogYXJnKTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICd1JzogYXJnID0gTWF0aC5hYnMoYXJnKTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICd4JzogYXJnID0gYXJnLnRvU3RyaW5nKDE2KTsgYnJlYWs7XG4gICAgICAgICAgICAgICAgICAgICAgICBjYXNlICdYJzogYXJnID0gYXJnLnRvU3RyaW5nKDE2KS50b1VwcGVyQ2FzZSgpOyBicmVhaztcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBhcmcgPSAoL1tkZWZdLy50ZXN0KG1hdGNoWzhdKSAmJiBtYXRjaFszXSAmJiBhcmcgPj0gMCA/ICcrJysgYXJnIDogYXJnKTtcbiAgICAgICAgICAgICAgICAgICAgcGFkX2NoYXJhY3RlciA9IG1hdGNoWzRdID8gbWF0Y2hbNF0gPT0gJzAnID8gJzAnIDogbWF0Y2hbNF0uY2hhckF0KDEpIDogJyAnO1xuICAgICAgICAgICAgICAgICAgICBwYWRfbGVuZ3RoID0gbWF0Y2hbNl0gLSBTdHJpbmcoYXJnKS5sZW5ndGg7XG4gICAgICAgICAgICAgICAgICAgIHBhZCA9IG1hdGNoWzZdID8gc3RyX3JlcGVhdChwYWRfY2hhcmFjdGVyLCBwYWRfbGVuZ3RoKSA6ICcnO1xuICAgICAgICAgICAgICAgICAgICBvdXRwdXQucHVzaChtYXRjaFs1XSA/IGFyZyArIHBhZCA6IHBhZCArIGFyZyk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgcmV0dXJuIG91dHB1dC5qb2luKCcnKTtcbiAgICAgICAgfTtcbiAgICBcbiAgICAgICAgc3RyX2Zvcm1hdC5jYWNoZSA9IHt9O1xuICAgIFxuICAgICAgICBzdHJfZm9ybWF0LnBhcnNlID0gZnVuY3Rpb24oZm10KSB7XG4gICAgICAgICAgICB2YXIgX2ZtdCA9IGZtdCwgbWF0Y2ggPSBbXSwgcGFyc2VfdHJlZSA9IFtdLCBhcmdfbmFtZXMgPSAwO1xuICAgICAgICAgICAgd2hpbGUgKF9mbXQpIHtcbiAgICAgICAgICAgICAgICBpZiAoKG1hdGNoID0gL15bXlxceDI1XSsvLmV4ZWMoX2ZtdCkpICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIHBhcnNlX3RyZWUucHVzaChtYXRjaFswXSk7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIGVsc2UgaWYgKChtYXRjaCA9IC9eXFx4MjV7Mn0vLmV4ZWMoX2ZtdCkpICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgIHBhcnNlX3RyZWUucHVzaCgnJScpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBlbHNlIGlmICgobWF0Y2ggPSAvXlxceDI1KD86KFsxLTldXFxkKilcXCR8XFwoKFteXFwpXSspXFwpKT8oXFwrKT8oMHwnW14kXSk/KC0pPyhcXGQrKT8oPzpcXC4oXFxkKykpPyhbYi1mb3N1eFhdKS8uZXhlYyhfZm10KSkgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgaWYgKG1hdGNoWzJdKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICBhcmdfbmFtZXMgfD0gMTtcbiAgICAgICAgICAgICAgICAgICAgICAgIHZhciBmaWVsZF9saXN0ID0gW10sIHJlcGxhY2VtZW50X2ZpZWxkID0gbWF0Y2hbMl0sIGZpZWxkX21hdGNoID0gW107XG4gICAgICAgICAgICAgICAgICAgICAgICBpZiAoKGZpZWxkX21hdGNoID0gL14oW2Etel9dW2Etel9cXGRdKikvaS5leGVjKHJlcGxhY2VtZW50X2ZpZWxkKSkgIT09IG51bGwpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWVsZF9saXN0LnB1c2goZmllbGRfbWF0Y2hbMV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgIHdoaWxlICgocmVwbGFjZW1lbnRfZmllbGQgPSByZXBsYWNlbWVudF9maWVsZC5zdWJzdHJpbmcoZmllbGRfbWF0Y2hbMF0ubGVuZ3RoKSkgIT09ICcnKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGlmICgoZmllbGRfbWF0Y2ggPSAvXlxcLihbYS16X11bYS16X1xcZF0qKS9pLmV4ZWMocmVwbGFjZW1lbnRfZmllbGQpKSAhPT0gbnVsbCkge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZmllbGRfbGlzdC5wdXNoKGZpZWxkX21hdGNoWzFdKTtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIGlmICgoZmllbGRfbWF0Y2ggPSAvXlxcWyhcXGQrKVxcXS8uZXhlYyhyZXBsYWNlbWVudF9maWVsZCkpICE9PSBudWxsKSB7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBmaWVsZF9saXN0LnB1c2goZmllbGRfbWF0Y2hbMV0pO1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdGhyb3coJ1tzcHJpbnRmXSBodWg/Jyk7XG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICB0aHJvdygnW3NwcmludGZdIGh1aD8nKTtcbiAgICAgICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgICAgIG1hdGNoWzJdID0gZmllbGRfbGlzdDtcbiAgICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgICAgICBlbHNlIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIGFyZ19uYW1lcyB8PSAyO1xuICAgICAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgICAgIGlmIChhcmdfbmFtZXMgPT09IDMpIHtcbiAgICAgICAgICAgICAgICAgICAgICAgIHRocm93KCdbc3ByaW50Zl0gbWl4aW5nIHBvc2l0aW9uYWwgYW5kIG5hbWVkIHBsYWNlaG9sZGVycyBpcyBub3QgKHlldCkgc3VwcG9ydGVkJyk7XG4gICAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICAgICAgcGFyc2VfdHJlZS5wdXNoKG1hdGNoKTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgICAgICAgIHRocm93KCdbc3ByaW50Zl0gaHVoPycpO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICBfZm10ID0gX2ZtdC5zdWJzdHJpbmcobWF0Y2hbMF0ubGVuZ3RoKTtcbiAgICAgICAgICAgIH1cbiAgICAgICAgICAgIHJldHVybiBwYXJzZV90cmVlO1xuICAgICAgICB9O1xuICAgIFxuICAgICAgICByZXR1cm4gc3RyX2Zvcm1hdDtcbiAgICB9KSgpO1xuICAgIFxuICAgIHZhciB2c3ByaW50ZiA9IGZ1bmN0aW9uKGZtdCwgYXJndikge1xuICAgICAgICBhcmd2LnVuc2hpZnQoZm10KTtcbiAgICAgICAgcmV0dXJuIHNwcmludGYuYXBwbHkobnVsbCwgYXJndik7XG4gICAgfTtcbiAgICBcbiAgICBhZGRQb3N0UHJvY2Vzc29yKFwic3ByaW50ZlwiLCBmdW5jdGlvbih2YWwsIGtleSwgb3B0cykge1xuICAgICAgICBpZiAoIW9wdHMuc3ByaW50ZikgcmV0dXJuIHZhbDtcbiAgICBcbiAgICAgICAgaWYgKE9iamVjdC5wcm90b3R5cGUudG9TdHJpbmcuYXBwbHkob3B0cy5zcHJpbnRmKSA9PT0gJ1tvYmplY3QgQXJyYXldJykge1xuICAgICAgICAgICAgcmV0dXJuIHZzcHJpbnRmKHZhbCwgb3B0cy5zcHJpbnRmKTtcbiAgICAgICAgfSBlbHNlIGlmICh0eXBlb2Ygb3B0cy5zcHJpbnRmID09PSAnb2JqZWN0Jykge1xuICAgICAgICAgICAgcmV0dXJuIHNwcmludGYodmFsLCBvcHRzLnNwcmludGYpO1xuICAgICAgICB9XG4gICAgXG4gICAgICAgIHJldHVybiB2YWw7XG4gICAgfSk7XG4gICAgLy8gcHVibGljIGFwaSBpbnRlcmZhY2VcbiAgICBpMThuLmluaXQgPSBpbml0O1xuICAgIGkxOG4uc2V0TG5nID0gc2V0TG5nO1xuICAgIGkxOG4ucHJlbG9hZCA9IHByZWxvYWQ7XG4gICAgaTE4bi5hZGRSZXNvdXJjZUJ1bmRsZSA9IGFkZFJlc291cmNlQnVuZGxlO1xuICAgIGkxOG4uaGFzUmVzb3VyY2VCdW5kbGUgPSBoYXNSZXNvdXJjZUJ1bmRsZTtcbiAgICBpMThuLmFkZFJlc291cmNlID0gYWRkUmVzb3VyY2U7XG4gICAgaTE4bi5hZGRSZXNvdXJjZXMgPSBhZGRSZXNvdXJjZXM7XG4gICAgaTE4bi5yZW1vdmVSZXNvdXJjZUJ1bmRsZSA9IHJlbW92ZVJlc291cmNlQnVuZGxlO1xuICAgIGkxOG4ubG9hZE5hbWVzcGFjZSA9IGxvYWROYW1lc3BhY2U7XG4gICAgaTE4bi5sb2FkTmFtZXNwYWNlcyA9IGxvYWROYW1lc3BhY2VzO1xuICAgIGkxOG4uc2V0RGVmYXVsdE5hbWVzcGFjZSA9IHNldERlZmF1bHROYW1lc3BhY2U7XG4gICAgaTE4bi50ID0gdHJhbnNsYXRlO1xuICAgIGkxOG4udHJhbnNsYXRlID0gdHJhbnNsYXRlO1xuICAgIGkxOG4uZXhpc3RzID0gZXhpc3RzO1xuICAgIGkxOG4uZGV0ZWN0TGFuZ3VhZ2UgPSBmLmRldGVjdExhbmd1YWdlO1xuICAgIGkxOG4ucGx1cmFsRXh0ZW5zaW9ucyA9IHBsdXJhbEV4dGVuc2lvbnM7XG4gICAgaTE4bi5zeW5jID0gc3luYztcbiAgICBpMThuLmZ1bmN0aW9ucyA9IGY7XG4gICAgaTE4bi5sbmcgPSBsbmc7XG4gICAgaTE4bi5hZGRQb3N0UHJvY2Vzc29yID0gYWRkUG9zdFByb2Nlc3NvcjtcbiAgICBpMThuLm9wdGlvbnMgPSBvO1xuXG59KSgpOyIsIi8vIFRvcCBsZXZlbCBmaWxlIGlzIGp1c3QgYSBtaXhpbiBvZiBzdWJtb2R1bGVzICYgY29uc3RhbnRzXG4ndXNlIHN0cmljdCc7XG5cbnZhciBhc3NpZ24gICAgPSByZXF1aXJlKCcuL2xpYi91dGlscy9jb21tb24nKS5hc3NpZ247XG5cbnZhciBkZWZsYXRlICAgPSByZXF1aXJlKCcuL2xpYi9kZWZsYXRlJyk7XG52YXIgaW5mbGF0ZSAgID0gcmVxdWlyZSgnLi9saWIvaW5mbGF0ZScpO1xudmFyIGNvbnN0YW50cyA9IHJlcXVpcmUoJy4vbGliL3psaWIvY29uc3RhbnRzJyk7XG5cbnZhciBwYWtvID0ge307XG5cbmFzc2lnbihwYWtvLCBkZWZsYXRlLCBpbmZsYXRlLCBjb25zdGFudHMpO1xuXG5tb2R1bGUuZXhwb3J0cyA9IHBha287IiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciB6bGliX2RlZmxhdGUgPSByZXF1aXJlKCcuL3psaWIvZGVmbGF0ZS5qcycpO1xudmFyIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscy9jb21tb24nKTtcbnZhciBzdHJpbmdzID0gcmVxdWlyZSgnLi91dGlscy9zdHJpbmdzJyk7XG52YXIgbXNnID0gcmVxdWlyZSgnLi96bGliL21lc3NhZ2VzJyk7XG52YXIgenN0cmVhbSA9IHJlcXVpcmUoJy4vemxpYi96c3RyZWFtJyk7XG5cblxuLyogUHVibGljIGNvbnN0YW50cyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG5cbnZhciBaX05PX0ZMVVNIICAgICAgPSAwO1xudmFyIFpfRklOSVNIICAgICAgICA9IDQ7XG5cbnZhciBaX09LICAgICAgICAgICAgPSAwO1xudmFyIFpfU1RSRUFNX0VORCAgICA9IDE7XG5cbnZhciBaX0RFRkFVTFRfQ09NUFJFU1NJT04gPSAtMTtcblxudmFyIFpfREVGQVVMVF9TVFJBVEVHWSAgICA9IDA7XG5cbnZhciBaX0RFRkxBVEVEICA9IDg7XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG5cblxuLyoqXG4gKiBjbGFzcyBEZWZsYXRlXG4gKlxuICogR2VuZXJpYyBKUy1zdHlsZSB3cmFwcGVyIGZvciB6bGliIGNhbGxzLiBJZiB5b3UgZG9uJ3QgbmVlZFxuICogc3RyZWFtaW5nIGJlaGF2aW91ciAtIHVzZSBtb3JlIHNpbXBsZSBmdW5jdGlvbnM6IFtbZGVmbGF0ZV1dLFxuICogW1tkZWZsYXRlUmF3XV0gYW5kIFtbZ3ppcF1dLlxuICoqL1xuXG4vKiBpbnRlcm5hbFxuICogRGVmbGF0ZS5jaHVua3MgLT4gQXJyYXlcbiAqXG4gKiBDaHVua3Mgb2Ygb3V0cHV0IGRhdGEsIGlmIFtbRGVmbGF0ZSNvbkRhdGFdXSBub3Qgb3ZlcnJpZGVuLlxuICoqL1xuXG4vKipcbiAqIERlZmxhdGUucmVzdWx0IC0+IFVpbnQ4QXJyYXl8QXJyYXlcbiAqXG4gKiBDb21wcmVzc2VkIHJlc3VsdCwgZ2VuZXJhdGVkIGJ5IGRlZmF1bHQgW1tEZWZsYXRlI29uRGF0YV1dXG4gKiBhbmQgW1tEZWZsYXRlI29uRW5kXV0gaGFuZGxlcnMuIEZpbGxlZCBhZnRlciB5b3UgcHVzaCBsYXN0IGNodW5rXG4gKiAoY2FsbCBbW0RlZmxhdGUjcHVzaF1dIHdpdGggYFpfRklOSVNIYCAvIGB0cnVlYCBwYXJhbSkuXG4gKiovXG5cbi8qKlxuICogRGVmbGF0ZS5lcnIgLT4gTnVtYmVyXG4gKlxuICogRXJyb3IgY29kZSBhZnRlciBkZWZsYXRlIGZpbmlzaGVkLiAwIChaX09LKSBvbiBzdWNjZXNzLlxuICogWW91IHdpbGwgbm90IG5lZWQgaXQgaW4gcmVhbCBsaWZlLCBiZWNhdXNlIGRlZmxhdGUgZXJyb3JzXG4gKiBhcmUgcG9zc2libGUgb25seSBvbiB3cm9uZyBvcHRpb25zIG9yIGJhZCBgb25EYXRhYCAvIGBvbkVuZGBcbiAqIGN1c3RvbSBoYW5kbGVycy5cbiAqKi9cblxuLyoqXG4gKiBEZWZsYXRlLm1zZyAtPiBTdHJpbmdcbiAqXG4gKiBFcnJvciBtZXNzYWdlLCBpZiBbW0RlZmxhdGUuZXJyXV0gIT0gMFxuICoqL1xuXG5cbi8qKlxuICogbmV3IERlZmxhdGUob3B0aW9ucylcbiAqIC0gb3B0aW9ucyAoT2JqZWN0KTogemxpYiBkZWZsYXRlIG9wdGlvbnMuXG4gKlxuICogQ3JlYXRlcyBuZXcgZGVmbGF0b3IgaW5zdGFuY2Ugd2l0aCBzcGVjaWZpZWQgcGFyYW1zLiBUaHJvd3MgZXhjZXB0aW9uXG4gKiBvbiBiYWQgcGFyYW1zLiBTdXBwb3J0ZWQgb3B0aW9uczpcbiAqXG4gKiAtIGBsZXZlbGBcbiAqIC0gYHdpbmRvd0JpdHNgXG4gKiAtIGBtZW1MZXZlbGBcbiAqIC0gYHN0cmF0ZWd5YFxuICpcbiAqIFtodHRwOi8vemxpYi5uZXQvbWFudWFsLmh0bWwjQWR2YW5jZWRdKGh0dHA6Ly96bGliLm5ldC9tYW51YWwuaHRtbCNBZHZhbmNlZClcbiAqIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHRoZXNlLlxuICpcbiAqIEFkZGl0aW9uYWwgb3B0aW9ucywgZm9yIGludGVybmFsIG5lZWRzOlxuICpcbiAqIC0gYGNodW5rU2l6ZWAgLSBzaXplIG9mIGdlbmVyYXRlZCBkYXRhIGNodW5rcyAoMTZLIGJ5IGRlZmF1bHQpXG4gKiAtIGByYXdgIChCb29sZWFuKSAtIGRvIHJhdyBkZWZsYXRlXG4gKiAtIGBnemlwYCAoQm9vbGVhbikgLSBjcmVhdGUgZ3ppcCB3cmFwcGVyXG4gKiAtIGB0b2AgKFN0cmluZykgLSBpZiBlcXVhbCB0byAnc3RyaW5nJywgdGhlbiByZXN1bHQgd2lsbCBiZSBcImJpbmFyeSBzdHJpbmdcIlxuICogICAgKGVhY2ggY2hhciBjb2RlIFswLi4yNTVdKVxuICogLSBgaGVhZGVyYCAoT2JqZWN0KSAtIGN1c3RvbSBoZWFkZXIgZm9yIGd6aXBcbiAqICAgLSBgdGV4dGAgKEJvb2xlYW4pIC0gdHJ1ZSBpZiBjb21wcmVzc2VkIGRhdGEgYmVsaWV2ZWQgdG8gYmUgdGV4dFxuICogICAtIGB0aW1lYCAoTnVtYmVyKSAtIG1vZGlmaWNhdGlvbiB0aW1lLCB1bml4IHRpbWVzdGFtcFxuICogICAtIGBvc2AgKE51bWJlcikgLSBvcGVyYXRpb24gc3lzdGVtIGNvZGVcbiAqICAgLSBgZXh0cmFgIChBcnJheSkgLSBhcnJheSBvZiBieXRlcyB3aXRoIGV4dHJhIGRhdGEgKG1heCA2NTUzNilcbiAqICAgLSBgbmFtZWAgKFN0cmluZykgLSBmaWxlIG5hbWUgKGJpbmFyeSBzdHJpbmcpXG4gKiAgIC0gYGNvbW1lbnRgIChTdHJpbmcpIC0gY29tbWVudCAoYmluYXJ5IHN0cmluZylcbiAqICAgLSBgaGNyY2AgKEJvb2xlYW4pIC0gdHJ1ZSBpZiBoZWFkZXIgY3JjIHNob3VsZCBiZSBhZGRlZFxuICpcbiAqICMjIyMjIEV4YW1wbGU6XG4gKlxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIHBha28gPSByZXF1aXJlKCdwYWtvJylcbiAqICAgLCBjaHVuazEgPSBVaW50OEFycmF5KFsxLDIsMyw0LDUsNiw3LDgsOV0pXG4gKiAgICwgY2h1bmsyID0gVWludDhBcnJheShbMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgsMTldKTtcbiAqXG4gKiB2YXIgZGVmbGF0ZSA9IG5ldyBwYWtvLkRlZmxhdGUoeyBsZXZlbDogM30pO1xuICpcbiAqIGRlZmxhdGUucHVzaChjaHVuazEsIGZhbHNlKTtcbiAqIGRlZmxhdGUucHVzaChjaHVuazIsIHRydWUpOyAgLy8gdHJ1ZSAtPiBsYXN0IGNodW5rXG4gKlxuICogaWYgKGRlZmxhdGUuZXJyKSB7IHRocm93IG5ldyBFcnJvcihkZWZsYXRlLmVycik7IH1cbiAqXG4gKiBjb25zb2xlLmxvZyhkZWZsYXRlLnJlc3VsdCk7XG4gKiBgYGBcbiAqKi9cbnZhciBEZWZsYXRlID0gZnVuY3Rpb24ob3B0aW9ucykge1xuXG4gIHRoaXMub3B0aW9ucyA9IHV0aWxzLmFzc2lnbih7XG4gICAgbGV2ZWw6IFpfREVGQVVMVF9DT01QUkVTU0lPTixcbiAgICBtZXRob2Q6IFpfREVGTEFURUQsXG4gICAgY2h1bmtTaXplOiAxNjM4NCxcbiAgICB3aW5kb3dCaXRzOiAxNSxcbiAgICBtZW1MZXZlbDogOCxcbiAgICBzdHJhdGVneTogWl9ERUZBVUxUX1NUUkFURUdZLFxuICAgIHRvOiAnJ1xuICB9LCBvcHRpb25zIHx8IHt9KTtcblxuICB2YXIgb3B0ID0gdGhpcy5vcHRpb25zO1xuXG4gIGlmIChvcHQucmF3ICYmIChvcHQud2luZG93Qml0cyA+IDApKSB7XG4gICAgb3B0LndpbmRvd0JpdHMgPSAtb3B0LndpbmRvd0JpdHM7XG4gIH1cblxuICBlbHNlIGlmIChvcHQuZ3ppcCAmJiAob3B0LndpbmRvd0JpdHMgPiAwKSAmJiAob3B0LndpbmRvd0JpdHMgPCAxNikpIHtcbiAgICBvcHQud2luZG93Qml0cyArPSAxNjtcbiAgfVxuXG4gIHRoaXMuZXJyICAgID0gMDsgICAgICAvLyBlcnJvciBjb2RlLCBpZiBoYXBwZW5zICgwID0gWl9PSylcbiAgdGhpcy5tc2cgICAgPSAnJzsgICAgIC8vIGVycm9yIG1lc3NhZ2VcbiAgdGhpcy5lbmRlZCAgPSBmYWxzZTsgIC8vIHVzZWQgdG8gYXZvaWQgbXVsdGlwbGUgb25FbmQoKSBjYWxsc1xuICB0aGlzLmNodW5rcyA9IFtdOyAgICAgLy8gY2h1bmtzIG9mIGNvbXByZXNzZWQgZGF0YVxuXG4gIHRoaXMuc3RybSA9IG5ldyB6c3RyZWFtKCk7XG4gIHRoaXMuc3RybS5hdmFpbF9vdXQgPSAwO1xuXG4gIHZhciBzdGF0dXMgPSB6bGliX2RlZmxhdGUuZGVmbGF0ZUluaXQyKFxuICAgIHRoaXMuc3RybSxcbiAgICBvcHQubGV2ZWwsXG4gICAgb3B0Lm1ldGhvZCxcbiAgICBvcHQud2luZG93Qml0cyxcbiAgICBvcHQubWVtTGV2ZWwsXG4gICAgb3B0LnN0cmF0ZWd5XG4gICk7XG5cbiAgaWYgKHN0YXR1cyAhPT0gWl9PSykge1xuICAgIHRocm93IG5ldyBFcnJvcihtc2dbc3RhdHVzXSk7XG4gIH1cblxuICBpZiAob3B0LmhlYWRlcikge1xuICAgIHpsaWJfZGVmbGF0ZS5kZWZsYXRlU2V0SGVhZGVyKHRoaXMuc3RybSwgb3B0LmhlYWRlcik7XG4gIH1cbn07XG5cbi8qKlxuICogRGVmbGF0ZSNwdXNoKGRhdGFbLCBtb2RlXSkgLT4gQm9vbGVhblxuICogLSBkYXRhIChVaW50OEFycmF5fEFycmF5fFN0cmluZyk6IGlucHV0IGRhdGEuIFN0cmluZ3Mgd2lsbCBiZSBjb252ZXJ0ZWQgdG9cbiAqICAgdXRmOCBieXRlIHNlcXVlbmNlLlxuICogLSBtb2RlIChOdW1iZXJ8Qm9vbGVhbik6IDAuLjYgZm9yIGNvcnJlc3BvbmRpbmcgWl9OT19GTFVTSC4uWl9UUkVFIG1vZGVzLlxuICogICBTZWUgY29uc3RhbnRzLiBTa2lwcGVkIG9yIGBmYWxzZWAgbWVhbnMgWl9OT19GTFVTSCwgYHRydWVgIG1lYW5zaCBaX0ZJTklTSC5cbiAqXG4gKiBTZW5kcyBpbnB1dCBkYXRhIHRvIGRlZmxhdGUgcGlwZSwgZ2VuZXJhdGluZyBbW0RlZmxhdGUjb25EYXRhXV0gY2FsbHMgd2l0aFxuICogbmV3IGNvbXByZXNzZWQgY2h1bmtzLiBSZXR1cm5zIGB0cnVlYCBvbiBzdWNjZXNzLiBUaGUgbGFzdCBkYXRhIGJsb2NrIG11c3QgaGF2ZVxuICogbW9kZSBaX0ZJTklTSCAob3IgYHRydWVgKS4gVGhhdCBmbHVzaCBpbnRlcm5hbCBwZW5kaW5nIGJ1ZmZlcnMgYW5kIGNhbGxcbiAqIFtbRGVmbGF0ZSNvbkVuZF1dLlxuICpcbiAqIE9uIGZhaWwgY2FsbCBbW0RlZmxhdGUjb25FbmRdXSB3aXRoIGVycm9yIGNvZGUgYW5kIHJldHVybiBmYWxzZS5cbiAqXG4gKiBXZSBzdHJvbmdseSByZWNvbW1lbmQgdG8gdXNlIGBVaW50OEFycmF5YCBvbiBpbnB1dCBmb3IgYmVzdCBzcGVlZCAob3V0cHV0XG4gKiBhcnJheSBmb3JtYXQgaXMgZGV0ZWN0ZWQgYXV0b21hdGljYWxseSkuIEFsc28sIGRvbid0IHNraXAgbGFzdCBwYXJhbSBhbmQgYWx3YXlzXG4gKiB1c2UgdGhlIHNhbWUgdHlwZSBpbiB5b3VyIGNvZGUgKGJvb2xlYW4gb3IgbnVtYmVyKS4gVGhhdCB3aWxsIGltcHJvdmUgSlMgc3BlZWQuXG4gKlxuICogRm9yIHJlZ3VsYXIgYEFycmF5YC1zIG1ha2Ugc3VyZSBhbGwgZWxlbWVudHMgYXJlIFswLi4yNTVdLlxuICpcbiAqICMjIyMjIEV4YW1wbGVcbiAqXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiBwdXNoKGNodW5rLCBmYWxzZSk7IC8vIHB1c2ggb25lIG9mIGRhdGEgY2h1bmtzXG4gKiAuLi5cbiAqIHB1c2goY2h1bmssIHRydWUpOyAgLy8gcHVzaCBsYXN0IGNodW5rXG4gKiBgYGBcbiAqKi9cbkRlZmxhdGUucHJvdG90eXBlLnB1c2ggPSBmdW5jdGlvbihkYXRhLCBtb2RlKSB7XG4gIHZhciBzdHJtID0gdGhpcy5zdHJtO1xuICB2YXIgY2h1bmtTaXplID0gdGhpcy5vcHRpb25zLmNodW5rU2l6ZTtcbiAgdmFyIHN0YXR1cywgX21vZGU7XG5cbiAgaWYgKHRoaXMuZW5kZWQpIHsgcmV0dXJuIGZhbHNlOyB9XG5cbiAgX21vZGUgPSAobW9kZSA9PT0gfn5tb2RlKSA/IG1vZGUgOiAoKG1vZGUgPT09IHRydWUpID8gWl9GSU5JU0ggOiBaX05PX0ZMVVNIKTtcblxuICAvLyBDb252ZXJ0IGRhdGEgaWYgbmVlZGVkXG4gIGlmICh0eXBlb2YgZGF0YSA9PT0gJ3N0cmluZycpIHtcbiAgICAvLyBJZiB3ZSBuZWVkIHRvIGNvbXByZXNzIHRleHQsIGNoYW5nZSBlbmNvZGluZyB0byB1dGY4LlxuICAgIHN0cm0uaW5wdXQgPSBzdHJpbmdzLnN0cmluZzJidWYoZGF0YSk7XG4gIH0gZWxzZSB7XG4gICAgc3RybS5pbnB1dCA9IGRhdGE7XG4gIH1cblxuICBzdHJtLm5leHRfaW4gPSAwO1xuICBzdHJtLmF2YWlsX2luID0gc3RybS5pbnB1dC5sZW5ndGg7XG5cbiAgZG8ge1xuICAgIGlmIChzdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgc3RybS5vdXRwdXQgPSBuZXcgdXRpbHMuQnVmOChjaHVua1NpemUpO1xuICAgICAgc3RybS5uZXh0X291dCA9IDA7XG4gICAgICBzdHJtLmF2YWlsX291dCA9IGNodW5rU2l6ZTtcbiAgICB9XG4gICAgc3RhdHVzID0gemxpYl9kZWZsYXRlLmRlZmxhdGUoc3RybSwgX21vZGUpOyAgICAvKiBubyBiYWQgcmV0dXJuIHZhbHVlICovXG5cbiAgICBpZiAoc3RhdHVzICE9PSBaX1NUUkVBTV9FTkQgJiYgc3RhdHVzICE9PSBaX09LKSB7XG4gICAgICB0aGlzLm9uRW5kKHN0YXR1cyk7XG4gICAgICB0aGlzLmVuZGVkID0gdHJ1ZTtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG4gICAgaWYgKHN0cm0uYXZhaWxfb3V0ID09PSAwIHx8IChzdHJtLmF2YWlsX2luID09PSAwICYmIF9tb2RlID09PSBaX0ZJTklTSCkpIHtcbiAgICAgIGlmICh0aGlzLm9wdGlvbnMudG8gPT09ICdzdHJpbmcnKSB7XG4gICAgICAgIHRoaXMub25EYXRhKHN0cmluZ3MuYnVmMmJpbnN0cmluZyh1dGlscy5zaHJpbmtCdWYoc3RybS5vdXRwdXQsIHN0cm0ubmV4dF9vdXQpKSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLm9uRGF0YSh1dGlscy5zaHJpbmtCdWYoc3RybS5vdXRwdXQsIHN0cm0ubmV4dF9vdXQpKTtcbiAgICAgIH1cbiAgICB9XG4gIH0gd2hpbGUgKChzdHJtLmF2YWlsX2luID4gMCB8fCBzdHJtLmF2YWlsX291dCA9PT0gMCkgJiYgc3RhdHVzICE9PSBaX1NUUkVBTV9FTkQpO1xuXG4gIC8vIEZpbmFsaXplIG9uIHRoZSBsYXN0IGNodW5rLlxuICBpZiAoX21vZGUgPT09IFpfRklOSVNIKSB7XG4gICAgc3RhdHVzID0gemxpYl9kZWZsYXRlLmRlZmxhdGVFbmQodGhpcy5zdHJtKTtcbiAgICB0aGlzLm9uRW5kKHN0YXR1cyk7XG4gICAgdGhpcy5lbmRlZCA9IHRydWU7XG4gICAgcmV0dXJuIHN0YXR1cyA9PT0gWl9PSztcbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuXG4vKipcbiAqIERlZmxhdGUjb25EYXRhKGNodW5rKSAtPiBWb2lkXG4gKiAtIGNodW5rIChVaW50OEFycmF5fEFycmF5fFN0cmluZyk6IG91cHV0IGRhdGEuIFR5cGUgb2YgYXJyYXkgZGVwZW5kc1xuICogICBvbiBqcyBlbmdpbmUgc3VwcG9ydC4gV2hlbiBzdHJpbmcgb3V0cHV0IHJlcXVlc3RlZCwgZWFjaCBjaHVua1xuICogICB3aWxsIGJlIHN0cmluZy5cbiAqXG4gKiBCeSBkZWZhdWx0LCBzdG9yZXMgZGF0YSBibG9ja3MgaW4gYGNodW5rc1tdYCBwcm9wZXJ0eSBhbmQgZ2x1ZVxuICogdGhvc2UgaW4gYG9uRW5kYC4gT3ZlcnJpZGUgdGhpcyBoYW5kbGVyLCBpZiB5b3UgbmVlZCBhbm90aGVyIGJlaGF2aW91ci5cbiAqKi9cbkRlZmxhdGUucHJvdG90eXBlLm9uRGF0YSA9IGZ1bmN0aW9uKGNodW5rKSB7XG4gIHRoaXMuY2h1bmtzLnB1c2goY2h1bmspO1xufTtcblxuXG4vKipcbiAqIERlZmxhdGUjb25FbmQoc3RhdHVzKSAtPiBWb2lkXG4gKiAtIHN0YXR1cyAoTnVtYmVyKTogZGVmbGF0ZSBzdGF0dXMuIDAgKFpfT0spIG9uIHN1Y2Nlc3MsXG4gKiAgIG90aGVyIGlmIG5vdC5cbiAqXG4gKiBDYWxsZWQgb25jZSBhZnRlciB5b3UgdGVsbCBkZWZsYXRlIHRoYXQgaW5wdXQgc3RyZWFtIGNvbXBsZXRlXG4gKiBvciBlcnJvciBoYXBwZW5uZWQuIEJ5IGRlZmF1bHQgLSBqb2luIGNvbGxlY3RlZCBjaHVua3MsXG4gKiBmcmVlIG1lbW9yeSBhbmQgZmlsbCBgcmVzdWx0c2AgLyBgZXJyYCBwcm9wZXJ0aWVzLlxuICoqL1xuRGVmbGF0ZS5wcm90b3R5cGUub25FbmQgPSBmdW5jdGlvbihzdGF0dXMpIHtcbiAgLy8gT24gc3VjY2VzcyAtIGpvaW5cbiAgaWYgKHN0YXR1cyA9PT0gWl9PSykge1xuICAgIGlmICh0aGlzLm9wdGlvbnMudG8gPT09ICdzdHJpbmcnKSB7XG4gICAgICB0aGlzLnJlc3VsdCA9IHRoaXMuY2h1bmtzLmpvaW4oJycpO1xuICAgIH0gZWxzZSB7XG4gICAgICB0aGlzLnJlc3VsdCA9IHV0aWxzLmZsYXR0ZW5DaHVua3ModGhpcy5jaHVua3MpO1xuICAgIH1cbiAgfVxuICB0aGlzLmNodW5rcyA9IFtdO1xuICB0aGlzLmVyciA9IHN0YXR1cztcbiAgdGhpcy5tc2cgPSB0aGlzLnN0cm0ubXNnO1xufTtcblxuXG4vKipcbiAqIGRlZmxhdGUoZGF0YVssIG9wdGlvbnNdKSAtPiBVaW50OEFycmF5fEFycmF5fFN0cmluZ1xuICogLSBkYXRhIChVaW50OEFycmF5fEFycmF5fFN0cmluZyk6IGlucHV0IGRhdGEgdG8gY29tcHJlc3MuXG4gKiAtIG9wdGlvbnMgKE9iamVjdCk6IHpsaWIgZGVmbGF0ZSBvcHRpb25zLlxuICpcbiAqIENvbXByZXNzIGBkYXRhYCB3aXRoIGRlZmxhdGUgYWxyb3J5dGhtIGFuZCBgb3B0aW9uc2AuXG4gKlxuICogU3VwcG9ydGVkIG9wdGlvbnMgYXJlOlxuICpcbiAqIC0gbGV2ZWxcbiAqIC0gd2luZG93Qml0c1xuICogLSBtZW1MZXZlbFxuICogLSBzdHJhdGVneVxuICpcbiAqIFtodHRwOi8vemxpYi5uZXQvbWFudWFsLmh0bWwjQWR2YW5jZWRdKGh0dHA6Ly96bGliLm5ldC9tYW51YWwuaHRtbCNBZHZhbmNlZClcbiAqIGZvciBtb3JlIGluZm9ybWF0aW9uIG9uIHRoZXNlLlxuICpcbiAqIFN1Z2FyIChvcHRpb25zKTpcbiAqXG4gKiAtIGByYXdgIChCb29sZWFuKSAtIHNheSB0aGF0IHdlIHdvcmsgd2l0aCByYXcgc3RyZWFtLCBpZiB5b3UgZG9uJ3Qgd2lzaCB0byBzcGVjaWZ5XG4gKiAgIG5lZ2F0aXZlIHdpbmRvd0JpdHMgaW1wbGljaXRseS5cbiAqIC0gYHRvYCAoU3RyaW5nKSAtIGlmIGVxdWFsIHRvICdzdHJpbmcnLCB0aGVuIHJlc3VsdCB3aWxsIGJlIFwiYmluYXJ5IHN0cmluZ1wiXG4gKiAgICAoZWFjaCBjaGFyIGNvZGUgWzAuLjI1NV0pXG4gKlxuICogIyMjIyMgRXhhbXBsZTpcbiAqXG4gKiBgYGBqYXZhc2NyaXB0XG4gKiB2YXIgcGFrbyA9IHJlcXVpcmUoJ3Bha28nKVxuICogICAsIGRhdGEgPSBVaW50OEFycmF5KFsxLDIsMyw0LDUsNiw3LDgsOV0pO1xuICpcbiAqIGNvbnNvbGUubG9nKHBha28uZGVmbGF0ZShkYXRhKSk7XG4gKiBgYGBcbiAqKi9cbmZ1bmN0aW9uIGRlZmxhdGUoaW5wdXQsIG9wdGlvbnMpIHtcbiAgdmFyIGRlZmxhdG9yID0gbmV3IERlZmxhdGUob3B0aW9ucyk7XG5cbiAgZGVmbGF0b3IucHVzaChpbnB1dCwgdHJ1ZSk7XG5cbiAgLy8gVGhhdCB3aWxsIG5ldmVyIGhhcHBlbnMsIGlmIHlvdSBkb24ndCBjaGVhdCB3aXRoIG9wdGlvbnMgOilcbiAgaWYgKGRlZmxhdG9yLmVycikgeyB0aHJvdyBkZWZsYXRvci5tc2c7IH1cblxuICByZXR1cm4gZGVmbGF0b3IucmVzdWx0O1xufVxuXG5cbi8qKlxuICogZGVmbGF0ZVJhdyhkYXRhWywgb3B0aW9uc10pIC0+IFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nXG4gKiAtIGRhdGEgKFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nKTogaW5wdXQgZGF0YSB0byBjb21wcmVzcy5cbiAqIC0gb3B0aW9ucyAoT2JqZWN0KTogemxpYiBkZWZsYXRlIG9wdGlvbnMuXG4gKlxuICogVGhlIHNhbWUgYXMgW1tkZWZsYXRlXV0sIGJ1dCBjcmVhdGVzIHJhdyBkYXRhLCB3aXRob3V0IHdyYXBwZXJcbiAqIChoZWFkZXIgYW5kIGFkbGVyMzIgY3JjKS5cbiAqKi9cbmZ1bmN0aW9uIGRlZmxhdGVSYXcoaW5wdXQsIG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gIG9wdGlvbnMucmF3ID0gdHJ1ZTtcbiAgcmV0dXJuIGRlZmxhdGUoaW5wdXQsIG9wdGlvbnMpO1xufVxuXG5cbi8qKlxuICogZ3ppcChkYXRhWywgb3B0aW9uc10pIC0+IFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nXG4gKiAtIGRhdGEgKFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nKTogaW5wdXQgZGF0YSB0byBjb21wcmVzcy5cbiAqIC0gb3B0aW9ucyAoT2JqZWN0KTogemxpYiBkZWZsYXRlIG9wdGlvbnMuXG4gKlxuICogVGhlIHNhbWUgYXMgW1tkZWZsYXRlXV0sIGJ1dCBjcmVhdGUgZ3ppcCB3cmFwcGVyIGluc3RlYWQgb2ZcbiAqIGRlZmxhdGUgb25lLlxuICoqL1xuZnVuY3Rpb24gZ3ppcChpbnB1dCwgb3B0aW9ucykge1xuICBvcHRpb25zID0gb3B0aW9ucyB8fCB7fTtcbiAgb3B0aW9ucy5nemlwID0gdHJ1ZTtcbiAgcmV0dXJuIGRlZmxhdGUoaW5wdXQsIG9wdGlvbnMpO1xufVxuXG5cbmV4cG9ydHMuRGVmbGF0ZSA9IERlZmxhdGU7XG5leHBvcnRzLmRlZmxhdGUgPSBkZWZsYXRlO1xuZXhwb3J0cy5kZWZsYXRlUmF3ID0gZGVmbGF0ZVJhdztcbmV4cG9ydHMuZ3ppcCA9IGd6aXA7IiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciB6bGliX2luZmxhdGUgPSByZXF1aXJlKCcuL3psaWIvaW5mbGF0ZS5qcycpO1xudmFyIHV0aWxzID0gcmVxdWlyZSgnLi91dGlscy9jb21tb24nKTtcbnZhciBzdHJpbmdzID0gcmVxdWlyZSgnLi91dGlscy9zdHJpbmdzJyk7XG52YXIgYyA9IHJlcXVpcmUoJy4vemxpYi9jb25zdGFudHMnKTtcbnZhciBtc2cgPSByZXF1aXJlKCcuL3psaWIvbWVzc2FnZXMnKTtcbnZhciB6c3RyZWFtID0gcmVxdWlyZSgnLi96bGliL3pzdHJlYW0nKTtcbnZhciBnemhlYWRlciA9IHJlcXVpcmUoJy4vemxpYi9nemhlYWRlcicpO1xuXG5cbi8qKlxuICogY2xhc3MgSW5mbGF0ZVxuICpcbiAqIEdlbmVyaWMgSlMtc3R5bGUgd3JhcHBlciBmb3IgemxpYiBjYWxscy4gSWYgeW91IGRvbid0IG5lZWRcbiAqIHN0cmVhbWluZyBiZWhhdmlvdXIgLSB1c2UgbW9yZSBzaW1wbGUgZnVuY3Rpb25zOiBbW2luZmxhdGVdXVxuICogYW5kIFtbaW5mbGF0ZVJhd11dLlxuICoqL1xuXG4vKiBpbnRlcm5hbFxuICogaW5mbGF0ZS5jaHVua3MgLT4gQXJyYXlcbiAqXG4gKiBDaHVua3Mgb2Ygb3V0cHV0IGRhdGEsIGlmIFtbSW5mbGF0ZSNvbkRhdGFdXSBub3Qgb3ZlcnJpZGVuLlxuICoqL1xuXG4vKipcbiAqIEluZmxhdGUucmVzdWx0IC0+IFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nXG4gKlxuICogVW5jb21wcmVzc2VkIHJlc3VsdCwgZ2VuZXJhdGVkIGJ5IGRlZmF1bHQgW1tJbmZsYXRlI29uRGF0YV1dXG4gKiBhbmQgW1tJbmZsYXRlI29uRW5kXV0gaGFuZGxlcnMuIEZpbGxlZCBhZnRlciB5b3UgcHVzaCBsYXN0IGNodW5rXG4gKiAoY2FsbCBbW0luZmxhdGUjcHVzaF1dIHdpdGggYFpfRklOSVNIYCAvIGB0cnVlYCBwYXJhbSkuXG4gKiovXG5cbi8qKlxuICogSW5mbGF0ZS5lcnIgLT4gTnVtYmVyXG4gKlxuICogRXJyb3IgY29kZSBhZnRlciBpbmZsYXRlIGZpbmlzaGVkLiAwIChaX09LKSBvbiBzdWNjZXNzLlxuICogU2hvdWxkIGJlIGNoZWNrZWQgaWYgYnJva2VuIGRhdGEgcG9zc2libGUuXG4gKiovXG5cbi8qKlxuICogSW5mbGF0ZS5tc2cgLT4gU3RyaW5nXG4gKlxuICogRXJyb3IgbWVzc2FnZSwgaWYgW1tJbmZsYXRlLmVycl1dICE9IDBcbiAqKi9cblxuXG4vKipcbiAqIG5ldyBJbmZsYXRlKG9wdGlvbnMpXG4gKiAtIG9wdGlvbnMgKE9iamVjdCk6IHpsaWIgaW5mbGF0ZSBvcHRpb25zLlxuICpcbiAqIENyZWF0ZXMgbmV3IGluZmxhdG9yIGluc3RhbmNlIHdpdGggc3BlY2lmaWVkIHBhcmFtcy4gVGhyb3dzIGV4Y2VwdGlvblxuICogb24gYmFkIHBhcmFtcy4gU3VwcG9ydGVkIG9wdGlvbnM6XG4gKlxuICogLSBgd2luZG93Qml0c2BcbiAqXG4gKiBbaHR0cDovL3psaWIubmV0L21hbnVhbC5odG1sI0FkdmFuY2VkXShodHRwOi8vemxpYi5uZXQvbWFudWFsLmh0bWwjQWR2YW5jZWQpXG4gKiBmb3IgbW9yZSBpbmZvcm1hdGlvbiBvbiB0aGVzZS5cbiAqXG4gKiBBZGRpdGlvbmFsIG9wdGlvbnMsIGZvciBpbnRlcm5hbCBuZWVkczpcbiAqXG4gKiAtIGBjaHVua1NpemVgIC0gc2l6ZSBvZiBnZW5lcmF0ZWQgZGF0YSBjaHVua3MgKDE2SyBieSBkZWZhdWx0KVxuICogLSBgcmF3YCAoQm9vbGVhbikgLSBkbyByYXcgaW5mbGF0ZVxuICogLSBgdG9gIChTdHJpbmcpIC0gaWYgZXF1YWwgdG8gJ3N0cmluZycsIHRoZW4gcmVzdWx0IHdpbGwgYmUgY29udmVydGVkXG4gKiAgIGZyb20gdXRmOCB0byB1dGYxNiAoamF2YXNjcmlwdCkgc3RyaW5nLiBXaGVuIHN0cmluZyBvdXRwdXQgcmVxdWVzdGVkLFxuICogICBjaHVuayBsZW5ndGggY2FuIGRpZmZlciBmcm9tIGBjaHVua1NpemVgLCBkZXBlbmRpbmcgb24gY29udGVudC5cbiAqXG4gKiBCeSBkZWZhdWx0LCB3aGVuIG5vIG9wdGlvbnMgc2V0LCBhdXRvZGV0ZWN0IGRlZmxhdGUvZ3ppcCBkYXRhIGZvcm1hdCB2aWFcbiAqIHdyYXBwZXIgaGVhZGVyLlxuICpcbiAqICMjIyMjIEV4YW1wbGU6XG4gKlxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIHBha28gPSByZXF1aXJlKCdwYWtvJylcbiAqICAgLCBjaHVuazEgPSBVaW50OEFycmF5KFsxLDIsMyw0LDUsNiw3LDgsOV0pXG4gKiAgICwgY2h1bmsyID0gVWludDhBcnJheShbMTAsMTEsMTIsMTMsMTQsMTUsMTYsMTcsMTgsMTldKTtcbiAqXG4gKiB2YXIgaW5mbGF0ZSA9IG5ldyBwYWtvLkluZmxhdGUoeyBsZXZlbDogM30pO1xuICpcbiAqIGluZmxhdGUucHVzaChjaHVuazEsIGZhbHNlKTtcbiAqIGluZmxhdGUucHVzaChjaHVuazIsIHRydWUpOyAgLy8gdHJ1ZSAtPiBsYXN0IGNodW5rXG4gKlxuICogaWYgKGluZmxhdGUuZXJyKSB7IHRocm93IG5ldyBFcnJvcihpbmZsYXRlLmVycik7IH1cbiAqXG4gKiBjb25zb2xlLmxvZyhpbmZsYXRlLnJlc3VsdCk7XG4gKiBgYGBcbiAqKi9cbnZhciBJbmZsYXRlID0gZnVuY3Rpb24ob3B0aW9ucykge1xuXG4gIHRoaXMub3B0aW9ucyA9IHV0aWxzLmFzc2lnbih7XG4gICAgY2h1bmtTaXplOiAxNjM4NCxcbiAgICB3aW5kb3dCaXRzOiAwLFxuICAgIHRvOiAnJ1xuICB9LCBvcHRpb25zIHx8IHt9KTtcblxuICB2YXIgb3B0ID0gdGhpcy5vcHRpb25zO1xuXG4gIC8vIEZvcmNlIHdpbmRvdyBzaXplIGZvciBgcmF3YCBkYXRhLCBpZiBub3Qgc2V0IGRpcmVjdGx5LFxuICAvLyBiZWNhdXNlIHdlIGhhdmUgbm8gaGVhZGVyIGZvciBhdXRvZGV0ZWN0LlxuICBpZiAob3B0LnJhdyAmJiAob3B0LndpbmRvd0JpdHMgPj0gMCkgJiYgKG9wdC53aW5kb3dCaXRzIDwgMTYpKSB7XG4gICAgb3B0LndpbmRvd0JpdHMgPSAtb3B0LndpbmRvd0JpdHM7XG4gICAgaWYgKG9wdC53aW5kb3dCaXRzID09PSAwKSB7IG9wdC53aW5kb3dCaXRzID0gLTE1OyB9XG4gIH1cblxuICAvLyBJZiBgd2luZG93Qml0c2Agbm90IGRlZmluZWQgKGFuZCBtb2RlIG5vdCByYXcpIC0gc2V0IGF1dG9kZXRlY3QgZmxhZyBmb3IgZ3ppcC9kZWZsYXRlXG4gIGlmICgob3B0LndpbmRvd0JpdHMgPj0gMCkgJiYgKG9wdC53aW5kb3dCaXRzIDwgMTYpICYmXG4gICAgICAhKG9wdGlvbnMgJiYgb3B0aW9ucy53aW5kb3dCaXRzKSkge1xuICAgIG9wdC53aW5kb3dCaXRzICs9IDMyO1xuICB9XG5cbiAgLy8gR3ppcCBoZWFkZXIgaGFzIG5vIGluZm8gYWJvdXQgd2luZG93cyBzaXplLCB3ZSBjYW4gZG8gYXV0b2RldGVjdCBvbmx5XG4gIC8vIGZvciBkZWZsYXRlLiBTbywgaWYgd2luZG93IHNpemUgbm90IHNldCwgZm9yY2UgaXQgdG8gbWF4IHdoZW4gZ3ppcCBwb3NzaWJsZVxuICBpZiAoKG9wdC53aW5kb3dCaXRzID4gMTUpICYmIChvcHQud2luZG93Qml0cyA8IDQ4KSkge1xuICAgIC8vIGJpdCAzICgxNikgLT4gZ3ppcHBlZCBkYXRhXG4gICAgLy8gYml0IDQgKDMyKSAtPiBhdXRvZGV0ZWN0IGd6aXAvZGVmbGF0ZVxuICAgIGlmICgob3B0LndpbmRvd0JpdHMgJiAxNSkgPT09IDApIHtcbiAgICAgIG9wdC53aW5kb3dCaXRzIHw9IDE1O1xuICAgIH1cbiAgfVxuXG4gIHRoaXMuZXJyICAgID0gMDsgICAgICAvLyBlcnJvciBjb2RlLCBpZiBoYXBwZW5zICgwID0gWl9PSylcbiAgdGhpcy5tc2cgICAgPSAnJzsgICAgIC8vIGVycm9yIG1lc3NhZ2VcbiAgdGhpcy5lbmRlZCAgPSBmYWxzZTsgIC8vIHVzZWQgdG8gYXZvaWQgbXVsdGlwbGUgb25FbmQoKSBjYWxsc1xuICB0aGlzLmNodW5rcyA9IFtdOyAgICAgLy8gY2h1bmtzIG9mIGNvbXByZXNzZWQgZGF0YVxuXG4gIHRoaXMuc3RybSAgID0gbmV3IHpzdHJlYW0oKTtcbiAgdGhpcy5zdHJtLmF2YWlsX291dCA9IDA7XG5cbiAgdmFyIHN0YXR1cyAgPSB6bGliX2luZmxhdGUuaW5mbGF0ZUluaXQyKFxuICAgIHRoaXMuc3RybSxcbiAgICBvcHQud2luZG93Qml0c1xuICApO1xuXG4gIGlmIChzdGF0dXMgIT09IGMuWl9PSykge1xuICAgIHRocm93IG5ldyBFcnJvcihtc2dbc3RhdHVzXSk7XG4gIH1cblxuICB0aGlzLmhlYWRlciA9IG5ldyBnemhlYWRlcigpO1xuXG4gIHpsaWJfaW5mbGF0ZS5pbmZsYXRlR2V0SGVhZGVyKHRoaXMuc3RybSwgdGhpcy5oZWFkZXIpO1xufTtcblxuLyoqXG4gKiBJbmZsYXRlI3B1c2goZGF0YVssIG1vZGVdKSAtPiBCb29sZWFuXG4gKiAtIGRhdGEgKFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nKTogaW5wdXQgZGF0YVxuICogLSBtb2RlIChOdW1iZXJ8Qm9vbGVhbik6IDAuLjYgZm9yIGNvcnJlc3BvbmRpbmcgWl9OT19GTFVTSC4uWl9UUkVFIG1vZGVzLlxuICogICBTZWUgY29uc3RhbnRzLiBTa2lwcGVkIG9yIGBmYWxzZWAgbWVhbnMgWl9OT19GTFVTSCwgYHRydWVgIG1lYW5zaCBaX0ZJTklTSC5cbiAqXG4gKiBTZW5kcyBpbnB1dCBkYXRhIHRvIGluZmxhdGUgcGlwZSwgZ2VuZXJhdGluZyBbW0luZmxhdGUjb25EYXRhXV0gY2FsbHMgd2l0aFxuICogbmV3IG91dHB1dCBjaHVua3MuIFJldHVybnMgYHRydWVgIG9uIHN1Y2Nlc3MuIFRoZSBsYXN0IGRhdGEgYmxvY2sgbXVzdCBoYXZlXG4gKiBtb2RlIFpfRklOSVNIIChvciBgdHJ1ZWApLiBUaGF0IGZsdXNoIGludGVybmFsIHBlbmRpbmcgYnVmZmVycyBhbmQgY2FsbFxuICogW1tJbmZsYXRlI29uRW5kXV0uXG4gKlxuICogT24gZmFpbCBjYWxsIFtbSW5mbGF0ZSNvbkVuZF1dIHdpdGggZXJyb3IgY29kZSBhbmQgcmV0dXJuIGZhbHNlLlxuICpcbiAqIFdlIHN0cm9uZ2x5IHJlY29tbWVuZCB0byB1c2UgYFVpbnQ4QXJyYXlgIG9uIGlucHV0IGZvciBiZXN0IHNwZWVkIChvdXRwdXRcbiAqIGZvcm1hdCBpcyBkZXRlY3RlZCBhdXRvbWF0aWNhbGx5KS4gQWxzbywgZG9uJ3Qgc2tpcCBsYXN0IHBhcmFtIGFuZCBhbHdheXNcbiAqIHVzZSB0aGUgc2FtZSB0eXBlIGluIHlvdXIgY29kZSAoYm9vbGVhbiBvciBudW1iZXIpLiBUaGF0IHdpbGwgaW1wcm92ZSBKUyBzcGVlZC5cbiAqXG4gKiBGb3IgcmVndWxhciBgQXJyYXlgLXMgbWFrZSBzdXJlIGFsbCBlbGVtZW50cyBhcmUgWzAuLjI1NV0uXG4gKlxuICogIyMjIyMgRXhhbXBsZVxuICpcbiAqIGBgYGphdmFzY3JpcHRcbiAqIHB1c2goY2h1bmssIGZhbHNlKTsgLy8gcHVzaCBvbmUgb2YgZGF0YSBjaHVua3NcbiAqIC4uLlxuICogcHVzaChjaHVuaywgdHJ1ZSk7ICAvLyBwdXNoIGxhc3QgY2h1bmtcbiAqIGBgYFxuICoqL1xuSW5mbGF0ZS5wcm90b3R5cGUucHVzaCA9IGZ1bmN0aW9uKGRhdGEsIG1vZGUpIHtcbiAgdmFyIHN0cm0gPSB0aGlzLnN0cm07XG4gIHZhciBjaHVua1NpemUgPSB0aGlzLm9wdGlvbnMuY2h1bmtTaXplO1xuICB2YXIgc3RhdHVzLCBfbW9kZTtcbiAgdmFyIG5leHRfb3V0X3V0ZjgsIHRhaWwsIHV0ZjhzdHI7XG5cbiAgaWYgKHRoaXMuZW5kZWQpIHsgcmV0dXJuIGZhbHNlOyB9XG4gIF9tb2RlID0gKG1vZGUgPT09IH5+bW9kZSkgPyBtb2RlIDogKChtb2RlID09PSB0cnVlKSA/IGMuWl9GSU5JU0ggOiBjLlpfTk9fRkxVU0gpO1xuXG4gIC8vIENvbnZlcnQgZGF0YSBpZiBuZWVkZWRcbiAgaWYgKHR5cGVvZiBkYXRhID09PSAnc3RyaW5nJykge1xuICAgIC8vIE9ubHkgYmluYXJ5IHN0cmluZ3MgY2FuIGJlIGRlY29tcHJlc3NlZCBvbiBwcmFjdGljZVxuICAgIHN0cm0uaW5wdXQgPSBzdHJpbmdzLmJpbnN0cmluZzJidWYoZGF0YSk7XG4gIH0gZWxzZSB7XG4gICAgc3RybS5pbnB1dCA9IGRhdGE7XG4gIH1cblxuICBzdHJtLm5leHRfaW4gPSAwO1xuICBzdHJtLmF2YWlsX2luID0gc3RybS5pbnB1dC5sZW5ndGg7XG5cbiAgZG8ge1xuICAgIGlmIChzdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgc3RybS5vdXRwdXQgPSBuZXcgdXRpbHMuQnVmOChjaHVua1NpemUpO1xuICAgICAgc3RybS5uZXh0X291dCA9IDA7XG4gICAgICBzdHJtLmF2YWlsX291dCA9IGNodW5rU2l6ZTtcbiAgICB9XG5cbiAgICBzdGF0dXMgPSB6bGliX2luZmxhdGUuaW5mbGF0ZShzdHJtLCBjLlpfTk9fRkxVU0gpOyAgICAvKiBubyBiYWQgcmV0dXJuIHZhbHVlICovXG5cbiAgICBpZiAoc3RhdHVzICE9PSBjLlpfU1RSRUFNX0VORCAmJiBzdGF0dXMgIT09IGMuWl9PSykge1xuICAgICAgdGhpcy5vbkVuZChzdGF0dXMpO1xuICAgICAgdGhpcy5lbmRlZCA9IHRydWU7XG4gICAgICByZXR1cm4gZmFsc2U7XG4gICAgfVxuXG4gICAgaWYgKHN0cm0ubmV4dF9vdXQpIHtcbiAgICAgIGlmIChzdHJtLmF2YWlsX291dCA9PT0gMCB8fCBzdGF0dXMgPT09IGMuWl9TVFJFQU1fRU5EIHx8IChzdHJtLmF2YWlsX2luID09PSAwICYmIF9tb2RlID09PSBjLlpfRklOSVNIKSkge1xuXG4gICAgICAgIGlmICh0aGlzLm9wdGlvbnMudG8gPT09ICdzdHJpbmcnKSB7XG5cbiAgICAgICAgICBuZXh0X291dF91dGY4ID0gc3RyaW5ncy51dGY4Ym9yZGVyKHN0cm0ub3V0cHV0LCBzdHJtLm5leHRfb3V0KTtcblxuICAgICAgICAgIHRhaWwgPSBzdHJtLm5leHRfb3V0IC0gbmV4dF9vdXRfdXRmODtcbiAgICAgICAgICB1dGY4c3RyID0gc3RyaW5ncy5idWYyc3RyaW5nKHN0cm0ub3V0cHV0LCBuZXh0X291dF91dGY4KTtcblxuICAgICAgICAgIC8vIG1vdmUgdGFpbFxuICAgICAgICAgIHN0cm0ubmV4dF9vdXQgPSB0YWlsO1xuICAgICAgICAgIHN0cm0uYXZhaWxfb3V0ID0gY2h1bmtTaXplIC0gdGFpbDtcbiAgICAgICAgICBpZiAodGFpbCkgeyB1dGlscy5hcnJheVNldChzdHJtLm91dHB1dCwgc3RybS5vdXRwdXQsIG5leHRfb3V0X3V0ZjgsIHRhaWwsIDApOyB9XG5cbiAgICAgICAgICB0aGlzLm9uRGF0YSh1dGY4c3RyKTtcblxuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHRoaXMub25EYXRhKHV0aWxzLnNocmlua0J1ZihzdHJtLm91dHB1dCwgc3RybS5uZXh0X291dCkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9IHdoaWxlICgoc3RybS5hdmFpbF9pbiA+IDApICYmIHN0YXR1cyAhPT0gYy5aX1NUUkVBTV9FTkQpO1xuXG4gIGlmIChzdGF0dXMgPT09IGMuWl9TVFJFQU1fRU5EKSB7XG4gICAgX21vZGUgPSBjLlpfRklOSVNIO1xuICB9XG4gIC8vIEZpbmFsaXplIG9uIHRoZSBsYXN0IGNodW5rLlxuICBpZiAoX21vZGUgPT09IGMuWl9GSU5JU0gpIHtcbiAgICBzdGF0dXMgPSB6bGliX2luZmxhdGUuaW5mbGF0ZUVuZCh0aGlzLnN0cm0pO1xuICAgIHRoaXMub25FbmQoc3RhdHVzKTtcbiAgICB0aGlzLmVuZGVkID0gdHJ1ZTtcbiAgICByZXR1cm4gc3RhdHVzID09PSBjLlpfT0s7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cblxuLyoqXG4gKiBJbmZsYXRlI29uRGF0YShjaHVuaykgLT4gVm9pZFxuICogLSBjaHVuayAoVWludDhBcnJheXxBcnJheXxTdHJpbmcpOiBvdXB1dCBkYXRhLiBUeXBlIG9mIGFycmF5IGRlcGVuZHNcbiAqICAgb24ganMgZW5naW5lIHN1cHBvcnQuIFdoZW4gc3RyaW5nIG91dHB1dCByZXF1ZXN0ZWQsIGVhY2ggY2h1bmtcbiAqICAgd2lsbCBiZSBzdHJpbmcuXG4gKlxuICogQnkgZGVmYXVsdCwgc3RvcmVzIGRhdGEgYmxvY2tzIGluIGBjaHVua3NbXWAgcHJvcGVydHkgYW5kIGdsdWVcbiAqIHRob3NlIGluIGBvbkVuZGAuIE92ZXJyaWRlIHRoaXMgaGFuZGxlciwgaWYgeW91IG5lZWQgYW5vdGhlciBiZWhhdmlvdXIuXG4gKiovXG5JbmZsYXRlLnByb3RvdHlwZS5vbkRhdGEgPSBmdW5jdGlvbihjaHVuaykge1xuICB0aGlzLmNodW5rcy5wdXNoKGNodW5rKTtcbn07XG5cblxuLyoqXG4gKiBJbmZsYXRlI29uRW5kKHN0YXR1cykgLT4gVm9pZFxuICogLSBzdGF0dXMgKE51bWJlcik6IGluZmxhdGUgc3RhdHVzLiAwIChaX09LKSBvbiBzdWNjZXNzLFxuICogICBvdGhlciBpZiBub3QuXG4gKlxuICogQ2FsbGVkIG9uY2UgYWZ0ZXIgeW91IHRlbGwgaW5mbGF0ZSB0aGF0IGlucHV0IHN0cmVhbSBjb21wbGV0ZVxuICogb3IgZXJyb3IgaGFwcGVubmVkLiBCeSBkZWZhdWx0IC0gam9pbiBjb2xsZWN0ZWQgY2h1bmtzLFxuICogZnJlZSBtZW1vcnkgYW5kIGZpbGwgYHJlc3VsdHNgIC8gYGVycmAgcHJvcGVydGllcy5cbiAqKi9cbkluZmxhdGUucHJvdG90eXBlLm9uRW5kID0gZnVuY3Rpb24oc3RhdHVzKSB7XG4gIC8vIE9uIHN1Y2Nlc3MgLSBqb2luXG4gIGlmIChzdGF0dXMgPT09IGMuWl9PSykge1xuICAgIGlmICh0aGlzLm9wdGlvbnMudG8gPT09ICdzdHJpbmcnKSB7XG4gICAgICAvLyBHbHVlICYgY29udmVydCBoZXJlLCB1bnRpbCB3ZSB0ZWFjaCBwYWtvIHRvIHNlbmRcbiAgICAgIC8vIHV0ZjggYWxsaWduZWQgc3RyaW5ncyB0byBvbkRhdGFcbiAgICAgIHRoaXMucmVzdWx0ID0gdGhpcy5jaHVua3Muam9pbignJyk7XG4gICAgfSBlbHNlIHtcbiAgICAgIHRoaXMucmVzdWx0ID0gdXRpbHMuZmxhdHRlbkNodW5rcyh0aGlzLmNodW5rcyk7XG4gICAgfVxuICB9XG4gIHRoaXMuY2h1bmtzID0gW107XG4gIHRoaXMuZXJyID0gc3RhdHVzO1xuICB0aGlzLm1zZyA9IHRoaXMuc3RybS5tc2c7XG59O1xuXG5cbi8qKlxuICogaW5mbGF0ZShkYXRhWywgb3B0aW9uc10pIC0+IFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nXG4gKiAtIGRhdGEgKFVpbnQ4QXJyYXl8QXJyYXl8U3RyaW5nKTogaW5wdXQgZGF0YSB0byBkZWNvbXByZXNzLlxuICogLSBvcHRpb25zIChPYmplY3QpOiB6bGliIGluZmxhdGUgb3B0aW9ucy5cbiAqXG4gKiBEZWNvbXByZXNzIGBkYXRhYCB3aXRoIGluZmxhdGUvdW5nemlwIGFuZCBgb3B0aW9uc2AuIEF1dG9kZXRlY3RcbiAqIGZvcm1hdCB2aWEgd3JhcHBlciBoZWFkZXIgYnkgZGVmYXVsdC4gVGhhdCdzIHdoeSB3ZSBkb24ndCBwcm92aWRlXG4gKiBzZXBhcmF0ZSBgdW5nemlwYCBtZXRob2QuXG4gKlxuICogU3VwcG9ydGVkIG9wdGlvbnMgYXJlOlxuICpcbiAqIC0gd2luZG93Qml0c1xuICpcbiAqIFtodHRwOi8vemxpYi5uZXQvbWFudWFsLmh0bWwjQWR2YW5jZWRdKGh0dHA6Ly96bGliLm5ldC9tYW51YWwuaHRtbCNBZHZhbmNlZClcbiAqIGZvciBtb3JlIGluZm9ybWF0aW9uLlxuICpcbiAqIFN1Z2FyIChvcHRpb25zKTpcbiAqXG4gKiAtIGByYXdgIChCb29sZWFuKSAtIHNheSB0aGF0IHdlIHdvcmsgd2l0aCByYXcgc3RyZWFtLCBpZiB5b3UgZG9uJ3Qgd2lzaCB0byBzcGVjaWZ5XG4gKiAgIG5lZ2F0aXZlIHdpbmRvd0JpdHMgaW1wbGljaXRseS5cbiAqIC0gYHRvYCAoU3RyaW5nKSAtIGlmIGVxdWFsIHRvICdzdHJpbmcnLCB0aGVuIHJlc3VsdCB3aWxsIGJlIGNvbnZlcnRlZFxuICogICBmcm9tIHV0ZjggdG8gdXRmMTYgKGphdmFzY3JpcHQpIHN0cmluZy4gV2hlbiBzdHJpbmcgb3V0cHV0IHJlcXVlc3RlZCxcbiAqICAgY2h1bmsgbGVuZ3RoIGNhbiBkaWZmZXIgZnJvbSBgY2h1bmtTaXplYCwgZGVwZW5kaW5nIG9uIGNvbnRlbnQuXG4gKlxuICpcbiAqICMjIyMjIEV4YW1wbGU6XG4gKlxuICogYGBgamF2YXNjcmlwdFxuICogdmFyIHBha28gPSByZXF1aXJlKCdwYWtvJylcbiAqICAgLCBpbnB1dCA9IHBha28uZGVmbGF0ZShbMSwyLDMsNCw1LDYsNyw4LDldKVxuICogICAsIG91dHB1dDtcbiAqXG4gKiB0cnkge1xuICogICBvdXRwdXQgPSBwYWtvLmluZmxhdGUoaW5wdXQpO1xuICogfSBjYXRjaCAoZXJyKVxuICogICBjb25zb2xlLmxvZyhlcnIpO1xuICogfVxuICogYGBgXG4gKiovXG5mdW5jdGlvbiBpbmZsYXRlKGlucHV0LCBvcHRpb25zKSB7XG4gIHZhciBpbmZsYXRvciA9IG5ldyBJbmZsYXRlKG9wdGlvbnMpO1xuXG4gIGluZmxhdG9yLnB1c2goaW5wdXQsIHRydWUpO1xuXG4gIC8vIFRoYXQgd2lsbCBuZXZlciBoYXBwZW5zLCBpZiB5b3UgZG9uJ3QgY2hlYXQgd2l0aCBvcHRpb25zIDopXG4gIGlmIChpbmZsYXRvci5lcnIpIHsgdGhyb3cgaW5mbGF0b3IubXNnOyB9XG5cbiAgcmV0dXJuIGluZmxhdG9yLnJlc3VsdDtcbn1cblxuXG4vKipcbiAqIGluZmxhdGVSYXcoZGF0YVssIG9wdGlvbnNdKSAtPiBVaW50OEFycmF5fEFycmF5fFN0cmluZ1xuICogLSBkYXRhIChVaW50OEFycmF5fEFycmF5fFN0cmluZyk6IGlucHV0IGRhdGEgdG8gZGVjb21wcmVzcy5cbiAqIC0gb3B0aW9ucyAoT2JqZWN0KTogemxpYiBpbmZsYXRlIG9wdGlvbnMuXG4gKlxuICogVGhlIHNhbWUgYXMgW1tpbmZsYXRlXV0sIGJ1dCBjcmVhdGVzIHJhdyBkYXRhLCB3aXRob3V0IHdyYXBwZXJcbiAqIChoZWFkZXIgYW5kIGFkbGVyMzIgY3JjKS5cbiAqKi9cbmZ1bmN0aW9uIGluZmxhdGVSYXcoaW5wdXQsIG9wdGlvbnMpIHtcbiAgb3B0aW9ucyA9IG9wdGlvbnMgfHwge307XG4gIG9wdGlvbnMucmF3ID0gdHJ1ZTtcbiAgcmV0dXJuIGluZmxhdGUoaW5wdXQsIG9wdGlvbnMpO1xufVxuXG5cbi8qKlxuICogdW5nemlwKGRhdGFbLCBvcHRpb25zXSkgLT4gVWludDhBcnJheXxBcnJheXxTdHJpbmdcbiAqIC0gZGF0YSAoVWludDhBcnJheXxBcnJheXxTdHJpbmcpOiBpbnB1dCBkYXRhIHRvIGRlY29tcHJlc3MuXG4gKiAtIG9wdGlvbnMgKE9iamVjdCk6IHpsaWIgaW5mbGF0ZSBvcHRpb25zLlxuICpcbiAqIEp1c3Qgc2hvcnRjdXQgdG8gW1tpbmZsYXRlXV0sIGJlY2F1c2UgaXQgYXV0b2RldGVjdHMgZm9ybWF0XG4gKiBieSBoZWFkZXIuY29udGVudC4gRG9uZSBmb3IgY29udmVuaWVuY2UuXG4gKiovXG5cblxuZXhwb3J0cy5JbmZsYXRlID0gSW5mbGF0ZTtcbmV4cG9ydHMuaW5mbGF0ZSA9IGluZmxhdGU7XG5leHBvcnRzLmluZmxhdGVSYXcgPSBpbmZsYXRlUmF3O1xuZXhwb3J0cy51bmd6aXAgID0gaW5mbGF0ZTtcbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgVFlQRURfT0sgPSAgKHR5cGVvZiBVaW50OEFycmF5ICE9PSAndW5kZWZpbmVkJykgJiZcbiAgICAgICAgICAgICAgICAodHlwZW9mIFVpbnQxNkFycmF5ICE9PSAndW5kZWZpbmVkJykgJiZcbiAgICAgICAgICAgICAgICAodHlwZW9mIEludDMyQXJyYXkgIT09ICd1bmRlZmluZWQnKTtcblxuXG5leHBvcnRzLmFzc2lnbiA9IGZ1bmN0aW9uIChvYmogLypmcm9tMSwgZnJvbTIsIGZyb20zLCAuLi4qLykge1xuICB2YXIgc291cmNlcyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKGFyZ3VtZW50cywgMSk7XG4gIHdoaWxlIChzb3VyY2VzLmxlbmd0aCkge1xuICAgIHZhciBzb3VyY2UgPSBzb3VyY2VzLnNoaWZ0KCk7XG4gICAgaWYgKCFzb3VyY2UpIHsgY29udGludWU7IH1cblxuICAgIGlmICh0eXBlb2Yoc291cmNlKSAhPT0gJ29iamVjdCcpIHtcbiAgICAgIHRocm93IG5ldyBUeXBlRXJyb3Ioc291cmNlICsgJ211c3QgYmUgbm9uLW9iamVjdCcpO1xuICAgIH1cblxuICAgIGZvciAodmFyIHAgaW4gc291cmNlKSB7XG4gICAgICBpZiAoc291cmNlLmhhc093blByb3BlcnR5KHApKSB7XG4gICAgICAgIG9ialtwXSA9IHNvdXJjZVtwXTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gb2JqO1xufTtcblxuXG4vLyByZWR1Y2UgYnVmZmVyIHNpemUsIGF2b2lkaW5nIG1lbSBjb3B5XG5leHBvcnRzLnNocmlua0J1ZiA9IGZ1bmN0aW9uIChidWYsIHNpemUpIHtcbiAgaWYgKGJ1Zi5sZW5ndGggPT09IHNpemUpIHsgcmV0dXJuIGJ1ZjsgfVxuICBpZiAoYnVmLnN1YmFycmF5KSB7IHJldHVybiBidWYuc3ViYXJyYXkoMCwgc2l6ZSk7IH1cbiAgYnVmLmxlbmd0aCA9IHNpemU7XG4gIHJldHVybiBidWY7XG59O1xuXG5cbnZhciBmblR5cGVkID0ge1xuICBhcnJheVNldDogZnVuY3Rpb24gKGRlc3QsIHNyYywgc3JjX29mZnMsIGxlbiwgZGVzdF9vZmZzKSB7XG4gICAgaWYgKHNyYy5zdWJhcnJheSAmJiBkZXN0LnN1YmFycmF5KSB7XG4gICAgICBkZXN0LnNldChzcmMuc3ViYXJyYXkoc3JjX29mZnMsIHNyY19vZmZzK2xlbiksIGRlc3Rfb2Zmcyk7XG4gICAgICByZXR1cm47XG4gICAgfVxuICAgIC8vIEZhbGxiYWNrIHRvIG9yZGluYXJ5IGFycmF5XG4gICAgZm9yKHZhciBpPTA7IGk8bGVuOyBpKyspIHtcbiAgICAgIGRlc3RbZGVzdF9vZmZzICsgaV0gPSBzcmNbc3JjX29mZnMgKyBpXTtcbiAgICB9XG4gIH0sXG4gIC8vIEpvaW4gYXJyYXkgb2YgY2h1bmtzIHRvIHNpbmdsZSBhcnJheS5cbiAgZmxhdHRlbkNodW5rczogZnVuY3Rpb24oY2h1bmtzKSB7XG4gICAgdmFyIGksIGwsIGxlbiwgcG9zLCBjaHVuaywgcmVzdWx0O1xuXG4gICAgLy8gY2FsY3VsYXRlIGRhdGEgbGVuZ3RoXG4gICAgbGVuID0gMDtcbiAgICBmb3IgKGk9MCwgbD1jaHVua3MubGVuZ3RoOyBpPGw7IGkrKykge1xuICAgICAgbGVuICs9IGNodW5rc1tpXS5sZW5ndGg7XG4gICAgfVxuXG4gICAgLy8gam9pbiBjaHVua3NcbiAgICByZXN1bHQgPSBuZXcgVWludDhBcnJheShsZW4pO1xuICAgIHBvcyA9IDA7XG4gICAgZm9yIChpPTAsIGw9Y2h1bmtzLmxlbmd0aDsgaTxsOyBpKyspIHtcbiAgICAgIGNodW5rID0gY2h1bmtzW2ldO1xuICAgICAgcmVzdWx0LnNldChjaHVuaywgcG9zKTtcbiAgICAgIHBvcyArPSBjaHVuay5sZW5ndGg7XG4gICAgfVxuXG4gICAgcmV0dXJuIHJlc3VsdDtcbiAgfVxufTtcblxudmFyIGZuVW50eXBlZCA9IHtcbiAgYXJyYXlTZXQ6IGZ1bmN0aW9uIChkZXN0LCBzcmMsIHNyY19vZmZzLCBsZW4sIGRlc3Rfb2Zmcykge1xuICAgIGZvcih2YXIgaT0wOyBpPGxlbjsgaSsrKSB7XG4gICAgICBkZXN0W2Rlc3Rfb2ZmcyArIGldID0gc3JjW3NyY19vZmZzICsgaV07XG4gICAgfVxuICB9LFxuICAvLyBKb2luIGFycmF5IG9mIGNodW5rcyB0byBzaW5nbGUgYXJyYXkuXG4gIGZsYXR0ZW5DaHVua3M6IGZ1bmN0aW9uKGNodW5rcykge1xuICAgIHJldHVybiBbXS5jb25jYXQuYXBwbHkoW10sIGNodW5rcyk7XG4gIH1cbn07XG5cblxuLy8gRW5hYmxlL0Rpc2FibGUgdHlwZWQgYXJyYXlzIHVzZSwgZm9yIHRlc3Rpbmdcbi8vXG5leHBvcnRzLnNldFR5cGVkID0gZnVuY3Rpb24gKG9uKSB7XG4gIGlmIChvbikge1xuICAgIGV4cG9ydHMuQnVmOCAgPSBVaW50OEFycmF5O1xuICAgIGV4cG9ydHMuQnVmMTYgPSBVaW50MTZBcnJheTtcbiAgICBleHBvcnRzLkJ1ZjMyID0gSW50MzJBcnJheTtcbiAgICBleHBvcnRzLmFzc2lnbihleHBvcnRzLCBmblR5cGVkKTtcbiAgfSBlbHNlIHtcbiAgICBleHBvcnRzLkJ1ZjggID0gQXJyYXk7XG4gICAgZXhwb3J0cy5CdWYxNiA9IEFycmF5O1xuICAgIGV4cG9ydHMuQnVmMzIgPSBBcnJheTtcbiAgICBleHBvcnRzLmFzc2lnbihleHBvcnRzLCBmblVudHlwZWQpO1xuICB9XG59O1xuXG5leHBvcnRzLnNldFR5cGVkKFRZUEVEX09LKTsiLCIvLyBTdHJpbmcgZW5jb2RlL2RlY29kZSBoZWxwZXJzXG4ndXNlIHN0cmljdCc7XG5cblxudmFyIHV0aWxzID0gcmVxdWlyZSgnLi9jb21tb24nKTtcblxuXG4vLyBRdWljayBjaGVjayBpZiB3ZSBjYW4gdXNlIGZhc3QgYXJyYXkgdG8gYmluIHN0cmluZyBjb252ZXJzaW9uXG4vL1xuLy8gLSBhcHBseShBcnJheSkgY2FuIGZhaWwgb24gQW5kcm9pZCAyLjJcbi8vIC0gYXBwbHkoVWludDhBcnJheSkgY2FuIGZhaWwgb24gaU9TIDUuMSBTYWZhcnlcbi8vXG52YXIgU1RSX0FQUExZX09LID0gdHJ1ZTtcbnZhciBTVFJfQVBQTFlfVUlBX09LID0gdHJ1ZTtcblxudHJ5IHsgU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseShudWxsLCBbMF0pOyB9IGNhdGNoKF9fKSB7IFNUUl9BUFBMWV9PSyA9IGZhbHNlOyB9XG50cnkgeyBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIG5ldyBVaW50OEFycmF5KDEpKTsgfSBjYXRjaChfXykgeyBTVFJfQVBQTFlfVUlBX09LID0gZmFsc2U7IH1cblxuXG4vLyBUYWJsZSB3aXRoIHV0ZjggbGVuZ3RocyAoY2FsY3VsYXRlZCBieSBmaXJzdCBieXRlIG9mIHNlcXVlbmNlKVxuLy8gTm90ZSwgdGhhdCA1ICYgNi1ieXRlIHZhbHVlcyBhbmQgc29tZSA0LWJ5dGUgdmFsdWVzIGNhbiBub3QgYmUgcmVwcmVzZW50ZWQgaW4gSlMsXG4vLyBiZWNhdXNlIG1heCBwb3NzaWJsZSBjb2RlcG9pbnQgaXMgMHgxMGZmZmZcbnZhciBfdXRmOGxlbiA9IG5ldyB1dGlscy5CdWY4KDI1Nik7XG5mb3IgKHZhciBpPTA7IGk8MjU2OyBpKyspIHtcbiAgX3V0ZjhsZW5baV0gPSAoaSA+PSAyNTIgPyA2IDogaSA+PSAyNDggPyA1IDogaSA+PSAyNDAgPyA0IDogaSA+PSAyMjQgPyAzIDogaSA+PSAxOTIgPyAyIDogMSk7XG59XG5fdXRmOGxlblsyNTRdPV91dGY4bGVuWzI1NF09MTsgLy8gSW52YWxpZCBzZXF1ZW5jZSBzdGFydFxuXG5cbi8vIGNvbnZlcnQgc3RyaW5nIHRvIGFycmF5ICh0eXBlZCwgd2hlbiBwb3NzaWJsZSlcbmV4cG9ydHMuc3RyaW5nMmJ1ZiA9IGZ1bmN0aW9uIChzdHIpIHtcbiAgdmFyIGJ1ZiwgYywgYzIsIG1fcG9zLCBpLCBzdHJfbGVuID0gc3RyLmxlbmd0aCwgYnVmX2xlbiA9IDA7XG5cbiAgLy8gY291bnQgYmluYXJ5IHNpemVcbiAgZm9yIChtX3BvcyA9IDA7IG1fcG9zIDwgc3RyX2xlbjsgbV9wb3MrKykge1xuICAgIGMgPSBzdHIuY2hhckNvZGVBdChtX3Bvcyk7XG4gICAgaWYgKChjICYgMHhmYzAwKSA9PT0gMHhkODAwICYmIChtX3BvcysxIDwgc3RyX2xlbikpIHtcbiAgICAgIGMyID0gc3RyLmNoYXJDb2RlQXQobV9wb3MrMSk7XG4gICAgICBpZiAoKGMyICYgMHhmYzAwKSA9PT0gMHhkYzAwKSB7XG4gICAgICAgIGMgPSAweDEwMDAwICsgKChjIC0gMHhkODAwKSA8PCAxMCkgKyAoYzIgLSAweGRjMDApO1xuICAgICAgICBtX3BvcysrO1xuICAgICAgfVxuICAgIH1cbiAgICBidWZfbGVuICs9IGMgPCAweDgwID8gMSA6IGMgPCAweDgwMCA/IDIgOiBjIDwgMHgxMDAwMCA/IDMgOiA0O1xuICB9XG5cbiAgLy8gYWxsb2NhdGUgYnVmZmVyXG4gIGJ1ZiA9IG5ldyB1dGlscy5CdWY4KGJ1Zl9sZW4pO1xuXG4gIC8vIGNvbnZlcnRcbiAgZm9yIChpPTAsIG1fcG9zID0gMDsgaSA8IGJ1Zl9sZW47IG1fcG9zKyspIHtcbiAgICBjID0gc3RyLmNoYXJDb2RlQXQobV9wb3MpO1xuICAgIGlmICgoYyAmIDB4ZmMwMCkgPT09IDB4ZDgwMCAmJiAobV9wb3MrMSA8IHN0cl9sZW4pKSB7XG4gICAgICBjMiA9IHN0ci5jaGFyQ29kZUF0KG1fcG9zKzEpO1xuICAgICAgaWYgKChjMiAmIDB4ZmMwMCkgPT09IDB4ZGMwMCkge1xuICAgICAgICBjID0gMHgxMDAwMCArICgoYyAtIDB4ZDgwMCkgPDwgMTApICsgKGMyIC0gMHhkYzAwKTtcbiAgICAgICAgbV9wb3MrKztcbiAgICAgIH1cbiAgICB9XG4gICAgaWYgKGMgPCAweDgwKSB7XG4gICAgICAvKiBvbmUgYnl0ZSAqL1xuICAgICAgYnVmW2krK10gPSBjO1xuICAgIH0gZWxzZSBpZiAoYyA8IDB4ODAwKSB7XG4gICAgICAvKiB0d28gYnl0ZXMgKi9cbiAgICAgIGJ1ZltpKytdID0gMHhDMCB8IChjID4+PiA2KTtcbiAgICAgIGJ1ZltpKytdID0gMHg4MCB8IChjICYgMHgzZik7XG4gICAgfSBlbHNlIGlmIChjIDwgMHgxMDAwMCkge1xuICAgICAgLyogdGhyZWUgYnl0ZXMgKi9cbiAgICAgIGJ1ZltpKytdID0gMHhFMCB8IChjID4+PiAxMik7XG4gICAgICBidWZbaSsrXSA9IDB4ODAgfCAoYyA+Pj4gNiAmIDB4M2YpO1xuICAgICAgYnVmW2krK10gPSAweDgwIHwgKGMgJiAweDNmKTtcbiAgICB9IGVsc2Uge1xuICAgICAgLyogZm91ciBieXRlcyAqL1xuICAgICAgYnVmW2krK10gPSAweGYwIHwgKGMgPj4+IDE4KTtcbiAgICAgIGJ1ZltpKytdID0gMHg4MCB8IChjID4+PiAxMiAmIDB4M2YpO1xuICAgICAgYnVmW2krK10gPSAweDgwIHwgKGMgPj4+IDYgJiAweDNmKTtcbiAgICAgIGJ1ZltpKytdID0gMHg4MCB8IChjICYgMHgzZik7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGJ1Zjtcbn07XG5cbi8vIEhlbHBlciAodXNlZCBpbiAyIHBsYWNlcylcbmZ1bmN0aW9uIGJ1ZjJiaW5zdHJpbmcoYnVmLCBsZW4pIHtcbiAgLy8gdXNlIGZhbGxiYWNrIGZvciBiaWcgYXJyYXlzIHRvIGF2b2lkIHN0YWNrIG92ZXJmbG93XG4gIGlmIChsZW4gPCA2NTUzNykge1xuICAgIGlmICgoYnVmLnN1YmFycmF5ICYmIFNUUl9BUFBMWV9VSUFfT0spIHx8ICghYnVmLnN1YmFycmF5ICYmIFNUUl9BUFBMWV9PSykpIHtcbiAgICAgIHJldHVybiBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIHV0aWxzLnNocmlua0J1ZihidWYsIGxlbikpO1xuICAgIH1cbiAgfVxuXG4gIHZhciByZXN1bHQgPSAnJztcbiAgZm9yKHZhciBpPTA7IGkgPCBsZW47IGkrKykge1xuICAgIHJlc3VsdCArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKGJ1ZltpXSk7XG4gIH1cbiAgcmV0dXJuIHJlc3VsdDtcbn1cblxuXG4vLyBDb252ZXJ0IGJ5dGUgYXJyYXkgdG8gYmluYXJ5IHN0cmluZ1xuZXhwb3J0cy5idWYyYmluc3RyaW5nID0gZnVuY3Rpb24oYnVmKSB7XG4gIHJldHVybiBidWYyYmluc3RyaW5nKGJ1ZiwgYnVmLmxlbmd0aCk7XG59O1xuXG5cbi8vIENvbnZlcnQgYmluYXJ5IHN0cmluZyAodHlwZWQsIHdoZW4gcG9zc2libGUpXG5leHBvcnRzLmJpbnN0cmluZzJidWYgPSBmdW5jdGlvbihzdHIpIHtcbiAgdmFyIGJ1ZiA9IG5ldyB1dGlscy5CdWY4KHN0ci5sZW5ndGgpO1xuICBmb3IodmFyIGk9MCwgbGVuPWJ1Zi5sZW5ndGg7IGkgPCBsZW47IGkrKykge1xuICAgIGJ1ZltpXSA9IHN0ci5jaGFyQ29kZUF0KGkpO1xuICB9XG4gIHJldHVybiBidWY7XG59O1xuXG5cbi8vIGNvbnZlcnQgYXJyYXkgdG8gc3RyaW5nXG5leHBvcnRzLmJ1ZjJzdHJpbmcgPSBmdW5jdGlvbiAoYnVmLCBtYXgpIHtcbiAgdmFyIGksIG91dCwgYywgY19sZW47XG4gIHZhciBsZW4gPSBtYXggfHwgYnVmLmxlbmd0aDtcblxuICAvLyBSZXNlcnZlIG1heCBwb3NzaWJsZSBsZW5ndGggKDIgd29yZHMgcGVyIGNoYXIpXG4gIC8vIE5COiBieSB1bmtub3duIHJlYXNvbnMsIEFycmF5IGlzIHNpZ25pZmljYW50bHkgZmFzdGVyIGZvclxuICAvLyAgICAgU3RyaW5nLmZyb21DaGFyQ29kZS5hcHBseSB0aGFuIFVpbnQxNkFycmF5LlxuICB2YXIgdXRmMTZidWYgPSBuZXcgQXJyYXkobGVuKjIpO1xuXG4gIGZvciAob3V0PTAsIGk9MDsgaTxsZW47KSB7XG4gICAgYyA9IGJ1ZltpKytdO1xuICAgIC8vIHF1aWNrIHByb2Nlc3MgYXNjaWlcbiAgICBpZiAoYyA8IDB4ODApIHsgdXRmMTZidWZbb3V0KytdID0gYzsgY29udGludWU7IH1cblxuICAgIGNfbGVuID0gX3V0ZjhsZW5bY107XG4gICAgLy8gc2tpcCA1ICYgNiBieXRlIGNvZGVzXG4gICAgaWYgKGNfbGVuID4gNCkgeyB1dGYxNmJ1ZltvdXQrK10gPSAweGZmZmQ7IGkgKz0gY19sZW4tMTsgY29udGludWU7IH1cblxuICAgIC8vIGFwcGx5IG1hc2sgb24gZmlyc3QgYnl0ZVxuICAgIGMgJj0gY19sZW4gPT09IDIgPyAweDFmIDogY19sZW4gPT09IDMgPyAweDBmIDogMHgwNztcbiAgICAvLyBqb2luIHRoZSByZXN0XG4gICAgd2hpbGUgKGNfbGVuID4gMSAmJiBpIDwgbGVuKSB7XG4gICAgICBjID0gKGMgPDwgNikgfCAoYnVmW2krK10gJiAweDNmKTtcbiAgICAgIGNfbGVuLS07XG4gICAgfVxuXG4gICAgLy8gdGVybWluYXRlZCBieSBlbmQgb2Ygc3RyaW5nP1xuICAgIGlmIChjX2xlbiA+IDEpIHsgdXRmMTZidWZbb3V0KytdID0gMHhmZmZkOyBjb250aW51ZTsgfVxuXG4gICAgaWYgKGMgPCAweDEwMDAwKSB7XG4gICAgICB1dGYxNmJ1ZltvdXQrK10gPSBjO1xuICAgIH0gZWxzZSB7XG4gICAgICBjIC09IDB4MTAwMDA7XG4gICAgICB1dGYxNmJ1ZltvdXQrK10gPSAweGQ4MDAgfCAoKGMgPj4gMTApICYgMHgzZmYpO1xuICAgICAgdXRmMTZidWZbb3V0KytdID0gMHhkYzAwIHwgKGMgJiAweDNmZik7XG4gICAgfVxuICB9XG5cbiAgcmV0dXJuIGJ1ZjJiaW5zdHJpbmcodXRmMTZidWYsIG91dCk7XG59O1xuXG5cbi8vIENhbGN1bGF0ZSBtYXggcG9zc2libGUgcG9zaXRpb24gaW4gdXRmOCBidWZmZXIsXG4vLyB0aGF0IHdpbGwgbm90IGJyZWFrIHNlcXVlbmNlLiBJZiB0aGF0J3Mgbm90IHBvc3NpYmxlXG4vLyAtICh2ZXJ5IHNtYWxsIGxpbWl0cykgcmV0dXJuIG1heCBzaXplIGFzIGlzLlxuLy9cbi8vIGJ1ZltdIC0gdXRmOCBieXRlcyBhcnJheVxuLy8gbWF4ICAgLSBsZW5ndGggbGltaXQgKG1hbmRhdG9yeSk7XG5leHBvcnRzLnV0Zjhib3JkZXIgPSBmdW5jdGlvbihidWYsIG1heCkge1xuICB2YXIgcG9zO1xuXG4gIG1heCA9IG1heCB8fCBidWYubGVuZ3RoO1xuICBpZiAobWF4ID4gYnVmLmxlbmd0aCkgeyBtYXggPSBidWYubGVuZ3RoOyB9XG5cbiAgLy8gZ28gYmFjayBmcm9tIGxhc3QgcG9zaXRpb24sIHVudGlsIHN0YXJ0IG9mIHNlcXVlbmNlIGZvdW5kXG4gIHBvcyA9IG1heC0xO1xuICB3aGlsZSAocG9zID49IDAgJiYgKGJ1Zltwb3NdICYgMHhDMCkgPT09IDB4ODApIHsgcG9zLS07IH1cblxuICAvLyBGdWNrdXAgLSB2ZXJ5IHNtYWxsIGFuZCBicm9rZW4gc2VxdWVuY2UsXG4gIC8vIHJldHVybiBtYXgsIGJlY2F1c2Ugd2Ugc2hvdWxkIHJldHVybiBzb21ldGhpbmcgYW55d2F5LlxuICBpZiAocG9zIDwgMCkgeyByZXR1cm4gbWF4OyB9XG5cbiAgLy8gSWYgd2UgY2FtZSB0byBzdGFydCBvZiBidWZmZXIgLSB0aGF0IG1lYW5zIHZ1ZmZlciBpcyB0b28gc21hbGwsXG4gIC8vIHJldHVybiBtYXggdG9vLlxuICBpZiAocG9zID09PSAwKSB7IHJldHVybiBtYXg7IH1cblxuICByZXR1cm4gKHBvcyArIF91dGY4bGVuW2J1Zltwb3NdXSA+IG1heCkgPyBwb3MgOiBtYXg7XG59O1xuIiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyBOb3RlOiBhZGxlcjMyIHRha2VzIDEyJSBmb3IgbGV2ZWwgMCBhbmQgMiUgZm9yIGxldmVsIDYuXG4vLyBJdCBkb2Vzbid0IHdvcnRoIHRvIG1ha2UgYWRkaXRpb25hbCBvcHRpbWl6YXRpb25hIGFzIGluIG9yaWdpbmFsLlxuLy8gU21hbGwgc2l6ZSBpcyBwcmVmZXJhYmxlLlxuXG5mdW5jdGlvbiBhZGxlcjMyKGFkbGVyLCBidWYsIGxlbiwgcG9zKSB7XG4gIHZhciBzMSA9IChhZGxlciAmIDB4ZmZmZikgfDBcbiAgICAsIHMyID0gKChhZGxlciA+Pj4gMTYpICYgMHhmZmZmKSB8MFxuICAgICwgbiA9IDA7XG5cbiAgd2hpbGUgKGxlbiAhPT0gMCkge1xuICAgIC8vIFNldCBsaW1pdCB+IHR3aWNlIGxlc3MgdGhhbiA1NTUyLCB0byBrZWVwXG4gICAgLy8gczIgaW4gMzEtYml0cywgYmVjYXVzZSB3ZSBmb3JjZSBzaWduZWQgaW50cy5cbiAgICAvLyBpbiBvdGhlciBjYXNlICU9IHdpbGwgZmFpbC5cbiAgICBuID0gbGVuID4gMjAwMCA/IDIwMDAgOiBsZW47XG4gICAgbGVuIC09IG47XG5cbiAgICBkbyB7XG4gICAgICBzMSA9IChzMSArIGJ1Zltwb3MrK10pIHwwO1xuICAgICAgczIgPSAoczIgKyBzMSkgfDA7XG4gICAgfSB3aGlsZSAoLS1uKTtcblxuICAgIHMxICU9IDY1NTIxO1xuICAgIHMyICU9IDY1NTIxO1xuICB9XG5cbiAgcmV0dXJuIChzMSB8IChzMiA8PCAxNikpIHwwO1xufVxuXG5cbm1vZHVsZS5leHBvcnRzID0gYWRsZXIzMjsiLCJtb2R1bGUuZXhwb3J0cyA9IHtcblxuICAvKiBBbGxvd2VkIGZsdXNoIHZhbHVlczsgc2VlIGRlZmxhdGUoKSBhbmQgaW5mbGF0ZSgpIGJlbG93IGZvciBkZXRhaWxzICovXG4gIFpfTk9fRkxVU0g6ICAgICAgICAgMCxcbiAgWl9QQVJUSUFMX0ZMVVNIOiAgICAxLFxuICBaX1NZTkNfRkxVU0g6ICAgICAgIDIsXG4gIFpfRlVMTF9GTFVTSDogICAgICAgMyxcbiAgWl9GSU5JU0g6ICAgICAgICAgICA0LFxuICBaX0JMT0NLOiAgICAgICAgICAgIDUsXG4gIFpfVFJFRVM6ICAgICAgICAgICAgNixcblxuICAvKiBSZXR1cm4gY29kZXMgZm9yIHRoZSBjb21wcmVzc2lvbi9kZWNvbXByZXNzaW9uIGZ1bmN0aW9ucy4gTmVnYXRpdmUgdmFsdWVzXG4gICogYXJlIGVycm9ycywgcG9zaXRpdmUgdmFsdWVzIGFyZSB1c2VkIGZvciBzcGVjaWFsIGJ1dCBub3JtYWwgZXZlbnRzLlxuICAqL1xuICBaX09LOiAgICAgICAgICAgICAgIDAsXG4gIFpfU1RSRUFNX0VORDogICAgICAgMSxcbiAgWl9ORUVEX0RJQ1Q6ICAgICAgICAyLFxuICBaX0VSUk5POiAgICAgICAgICAgLTEsXG4gIFpfU1RSRUFNX0VSUk9SOiAgICAtMixcbiAgWl9EQVRBX0VSUk9SOiAgICAgIC0zLFxuICAvL1pfTUVNX0VSUk9SOiAgICAgLTQsXG4gIFpfQlVGX0VSUk9SOiAgICAgICAtNSxcbiAgLy9aX1ZFUlNJT05fRVJST1I6IC02LFxuXG4gIC8qIGNvbXByZXNzaW9uIGxldmVscyAqL1xuICBaX05PX0NPTVBSRVNTSU9OOiAgICAgICAgIDAsXG4gIFpfQkVTVF9TUEVFRDogICAgICAgICAgICAgMSxcbiAgWl9CRVNUX0NPTVBSRVNTSU9OOiAgICAgICA5LFxuICBaX0RFRkFVTFRfQ09NUFJFU1NJT046ICAgLTEsXG5cblxuICBaX0ZJTFRFUkVEOiAgICAgICAgICAgICAgIDEsXG4gIFpfSFVGRk1BTl9PTkxZOiAgICAgICAgICAgMixcbiAgWl9STEU6ICAgICAgICAgICAgICAgICAgICAzLFxuICBaX0ZJWEVEOiAgICAgICAgICAgICAgICAgIDQsXG4gIFpfREVGQVVMVF9TVFJBVEVHWTogICAgICAgMCxcblxuICAvKiBQb3NzaWJsZSB2YWx1ZXMgb2YgdGhlIGRhdGFfdHlwZSBmaWVsZCAodGhvdWdoIHNlZSBpbmZsYXRlKCkpICovXG4gIFpfQklOQVJZOiAgICAgICAgICAgICAgICAgMCxcbiAgWl9URVhUOiAgICAgICAgICAgICAgICAgICAxLFxuICAvL1pfQVNDSUk6ICAgICAgICAgICAgICAgIDEsIC8vID0gWl9URVhUIChkZXByZWNhdGVkKVxuICBaX1VOS05PV046ICAgICAgICAgICAgICAgIDIsXG5cbiAgLyogVGhlIGRlZmxhdGUgY29tcHJlc3Npb24gbWV0aG9kICovXG4gIFpfREVGTEFURUQ6ICAgICAgICAgICAgICAgOFxuICAvL1pfTlVMTDogICAgICAgICAgICAgICAgIG51bGwgLy8gVXNlIC0xIG9yIG51bGwgaW5saW5lLCBkZXBlbmRpbmcgb24gdmFyIHR5cGVcbn07IiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyBOb3RlOiB3ZSBjYW4ndCBnZXQgc2lnbmlmaWNhbnQgc3BlZWQgYm9vc3QgaGVyZS5cbi8vIFNvIHdyaXRlIGNvZGUgdG8gbWluaW1pemUgc2l6ZSAtIG5vIHByZWdlbmVyYXRlZCB0YWJsZXNcbi8vIGFuZCBhcnJheSB0b29scyBkZXBlbmRlbmNpZXMuXG5cblxuLy8gVXNlIG9yZGluYXJ5IGFycmF5LCBzaW5jZSB1bnR5cGVkIG1ha2VzIG5vIGJvb3N0IGhlcmVcbmZ1bmN0aW9uIG1ha2VUYWJsZSgpIHtcbiAgdmFyIGMsIHRhYmxlID0gW107XG5cbiAgZm9yKHZhciBuID0wOyBuIDwgMjU2OyBuKyspe1xuICAgIGMgPSBuO1xuICAgIGZvcih2YXIgayA9MDsgayA8IDg7IGsrKyl7XG4gICAgICBjID0gKChjJjEpID8gKDB4RURCODgzMjAgXiAoYyA+Pj4gMSkpIDogKGMgPj4+IDEpKTtcbiAgICB9XG4gICAgdGFibGVbbl0gPSBjO1xuICB9XG5cbiAgcmV0dXJuIHRhYmxlO1xufVxuXG4vLyBDcmVhdGUgdGFibGUgb24gbG9hZC4gSnVzdCAyNTUgc2lnbmVkIGxvbmdzLiBOb3QgYSBwcm9ibGVtLlxudmFyIGNyY1RhYmxlID0gbWFrZVRhYmxlKCk7XG5cblxuZnVuY3Rpb24gY3JjMzIoY3JjLCBidWYsIGxlbiwgcG9zKSB7XG4gIHZhciB0ID0gY3JjVGFibGVcbiAgICAsIGVuZCA9IHBvcyArIGxlbjtcblxuICBjcmMgPSBjcmMgXiAoLTEpO1xuXG4gIGZvciAodmFyIGkgPSBwb3M7IGkgPCBlbmQ7IGkrKyApIHtcbiAgICBjcmMgPSAoY3JjID4+PiA4KSBeIHRbKGNyYyBeIGJ1ZltpXSkgJiAweEZGXTtcbiAgfVxuXG4gIHJldHVybiAoY3JjIF4gKC0xKSk7IC8vID4+PiAwO1xufVxuXG5cbm1vZHVsZS5leHBvcnRzID0gY3JjMzI7IiwiJ3VzZSBzdHJpY3QnO1xuXG52YXIgdXRpbHMgICA9IHJlcXVpcmUoJy4uL3V0aWxzL2NvbW1vbicpO1xudmFyIHRyZWVzICAgPSByZXF1aXJlKCcuL3RyZWVzJyk7XG52YXIgYWRsZXIzMiA9IHJlcXVpcmUoJy4vYWRsZXIzMicpO1xudmFyIGNyYzMyICAgPSByZXF1aXJlKCcuL2NyYzMyJyk7XG52YXIgbXNnICAgPSByZXF1aXJlKCcuL21lc3NhZ2VzJyk7XG5cbi8qIFB1YmxpYyBjb25zdGFudHMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0qL1xuXG5cbi8qIEFsbG93ZWQgZmx1c2ggdmFsdWVzOyBzZWUgZGVmbGF0ZSgpIGFuZCBpbmZsYXRlKCkgYmVsb3cgZm9yIGRldGFpbHMgKi9cbnZhciBaX05PX0ZMVVNIICAgICAgPSAwO1xudmFyIFpfUEFSVElBTF9GTFVTSCA9IDE7XG4vL3ZhciBaX1NZTkNfRkxVU0ggICAgPSAyO1xudmFyIFpfRlVMTF9GTFVTSCAgICA9IDM7XG52YXIgWl9GSU5JU0ggICAgICAgID0gNDtcbnZhciBaX0JMT0NLICAgICAgICAgPSA1O1xuLy92YXIgWl9UUkVFUyAgICAgICAgID0gNjtcblxuXG4vKiBSZXR1cm4gY29kZXMgZm9yIHRoZSBjb21wcmVzc2lvbi9kZWNvbXByZXNzaW9uIGZ1bmN0aW9ucy4gTmVnYXRpdmUgdmFsdWVzXG4gKiBhcmUgZXJyb3JzLCBwb3NpdGl2ZSB2YWx1ZXMgYXJlIHVzZWQgZm9yIHNwZWNpYWwgYnV0IG5vcm1hbCBldmVudHMuXG4gKi9cbnZhciBaX09LICAgICAgICAgICAgPSAwO1xudmFyIFpfU1RSRUFNX0VORCAgICA9IDE7XG4vL3ZhciBaX05FRURfRElDVCAgICAgPSAyO1xuLy92YXIgWl9FUlJOTyAgICAgICAgID0gLTE7XG52YXIgWl9TVFJFQU1fRVJST1IgID0gLTI7XG52YXIgWl9EQVRBX0VSUk9SICAgID0gLTM7XG4vL3ZhciBaX01FTV9FUlJPUiAgICAgPSAtNDtcbnZhciBaX0JVRl9FUlJPUiAgICAgPSAtNTtcbi8vdmFyIFpfVkVSU0lPTl9FUlJPUiA9IC02O1xuXG5cbi8qIGNvbXByZXNzaW9uIGxldmVscyAqL1xuLy92YXIgWl9OT19DT01QUkVTU0lPTiAgICAgID0gMDtcbi8vdmFyIFpfQkVTVF9TUEVFRCAgICAgICAgICA9IDE7XG4vL3ZhciBaX0JFU1RfQ09NUFJFU1NJT04gICAgPSA5O1xudmFyIFpfREVGQVVMVF9DT01QUkVTU0lPTiA9IC0xO1xuXG5cbnZhciBaX0ZJTFRFUkVEICAgICAgICAgICAgPSAxO1xudmFyIFpfSFVGRk1BTl9PTkxZICAgICAgICA9IDI7XG52YXIgWl9STEUgICAgICAgICAgICAgICAgID0gMztcbnZhciBaX0ZJWEVEICAgICAgICAgICAgICAgPSA0O1xudmFyIFpfREVGQVVMVF9TVFJBVEVHWSAgICA9IDA7XG5cbi8qIFBvc3NpYmxlIHZhbHVlcyBvZiB0aGUgZGF0YV90eXBlIGZpZWxkICh0aG91Z2ggc2VlIGluZmxhdGUoKSkgKi9cbi8vdmFyIFpfQklOQVJZICAgICAgICAgICAgICA9IDA7XG4vL3ZhciBaX1RFWFQgICAgICAgICAgICAgICAgPSAxO1xuLy92YXIgWl9BU0NJSSAgICAgICAgICAgICAgID0gMTsgLy8gPSBaX1RFWFRcbnZhciBaX1VOS05PV04gICAgICAgICAgICAgPSAyO1xuXG5cbi8qIFRoZSBkZWZsYXRlIGNvbXByZXNzaW9uIG1ldGhvZCAqL1xudmFyIFpfREVGTEFURUQgID0gODtcblxuLyo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cblxuXG52YXIgTUFYX01FTV9MRVZFTCA9IDk7XG4vKiBNYXhpbXVtIHZhbHVlIGZvciBtZW1MZXZlbCBpbiBkZWZsYXRlSW5pdDIgKi9cbnZhciBNQVhfV0JJVFMgPSAxNTtcbi8qIDMySyBMWjc3IHdpbmRvdyAqL1xudmFyIERFRl9NRU1fTEVWRUwgPSA4O1xuXG5cbnZhciBMRU5HVEhfQ09ERVMgID0gMjk7XG4vKiBudW1iZXIgb2YgbGVuZ3RoIGNvZGVzLCBub3QgY291bnRpbmcgdGhlIHNwZWNpYWwgRU5EX0JMT0NLIGNvZGUgKi9cbnZhciBMSVRFUkFMUyAgICAgID0gMjU2O1xuLyogbnVtYmVyIG9mIGxpdGVyYWwgYnl0ZXMgMC4uMjU1ICovXG52YXIgTF9DT0RFUyAgICAgICA9IExJVEVSQUxTICsgMSArIExFTkdUSF9DT0RFUztcbi8qIG51bWJlciBvZiBMaXRlcmFsIG9yIExlbmd0aCBjb2RlcywgaW5jbHVkaW5nIHRoZSBFTkRfQkxPQ0sgY29kZSAqL1xudmFyIERfQ09ERVMgICAgICAgPSAzMDtcbi8qIG51bWJlciBvZiBkaXN0YW5jZSBjb2RlcyAqL1xudmFyIEJMX0NPREVTICAgICAgPSAxOTtcbi8qIG51bWJlciBvZiBjb2RlcyB1c2VkIHRvIHRyYW5zZmVyIHRoZSBiaXQgbGVuZ3RocyAqL1xudmFyIEhFQVBfU0laRSAgICAgPSAyKkxfQ09ERVMgKyAxO1xuLyogbWF4aW11bSBoZWFwIHNpemUgKi9cbnZhciBNQVhfQklUUyAgPSAxNTtcbi8qIEFsbCBjb2RlcyBtdXN0IG5vdCBleGNlZWQgTUFYX0JJVFMgYml0cyAqL1xuXG52YXIgTUlOX01BVENIID0gMztcbnZhciBNQVhfTUFUQ0ggPSAyNTg7XG52YXIgTUlOX0xPT0tBSEVBRCA9IChNQVhfTUFUQ0ggKyBNSU5fTUFUQ0ggKyAxKTtcblxudmFyIFBSRVNFVF9ESUNUID0gMHgyMDtcblxudmFyIElOSVRfU1RBVEUgPSA0MjtcbnZhciBFWFRSQV9TVEFURSA9IDY5O1xudmFyIE5BTUVfU1RBVEUgPSA3MztcbnZhciBDT01NRU5UX1NUQVRFID0gOTE7XG52YXIgSENSQ19TVEFURSA9IDEwMztcbnZhciBCVVNZX1NUQVRFID0gMTEzO1xudmFyIEZJTklTSF9TVEFURSA9IDY2NjtcblxudmFyIEJTX05FRURfTU9SRSAgICAgID0gMTsgLyogYmxvY2sgbm90IGNvbXBsZXRlZCwgbmVlZCBtb3JlIGlucHV0IG9yIG1vcmUgb3V0cHV0ICovXG52YXIgQlNfQkxPQ0tfRE9ORSAgICAgPSAyOyAvKiBibG9jayBmbHVzaCBwZXJmb3JtZWQgKi9cbnZhciBCU19GSU5JU0hfU1RBUlRFRCA9IDM7IC8qIGZpbmlzaCBzdGFydGVkLCBuZWVkIG9ubHkgbW9yZSBvdXRwdXQgYXQgbmV4dCBkZWZsYXRlICovXG52YXIgQlNfRklOSVNIX0RPTkUgICAgPSA0OyAvKiBmaW5pc2ggZG9uZSwgYWNjZXB0IG5vIG1vcmUgaW5wdXQgb3Igb3V0cHV0ICovXG5cbnZhciBPU19DT0RFID0gMHgwMzsgLy8gVW5peCA6KSAuIERvbid0IGRldGVjdCwgdXNlIHRoaXMgZGVmYXVsdC5cblxuZnVuY3Rpb24gZXJyKHN0cm0sIGVycm9yQ29kZSkge1xuICBzdHJtLm1zZyA9IG1zZ1tlcnJvckNvZGVdO1xuICByZXR1cm4gZXJyb3JDb2RlO1xufVxuXG5mdW5jdGlvbiByYW5rKGYpIHtcbiAgcmV0dXJuICgoZikgPDwgMSkgLSAoKGYpID4gNCA/IDkgOiAwKTtcbn1cblxuZnVuY3Rpb24gemVybyhidWYpIHsgdmFyIGxlbiA9IGJ1Zi5sZW5ndGg7IHdoaWxlICgtLWxlbiA+PSAwKSB7IGJ1ZltsZW5dID0gMDsgfSB9XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogRmx1c2ggYXMgbXVjaCBwZW5kaW5nIG91dHB1dCBhcyBwb3NzaWJsZS4gQWxsIGRlZmxhdGUoKSBvdXRwdXQgZ29lc1xuICogdGhyb3VnaCB0aGlzIGZ1bmN0aW9uIHNvIHNvbWUgYXBwbGljYXRpb25zIG1heSB3aXNoIHRvIG1vZGlmeSBpdFxuICogdG8gYXZvaWQgYWxsb2NhdGluZyBhIGxhcmdlIHN0cm0tPm91dHB1dCBidWZmZXIgYW5kIGNvcHlpbmcgaW50byBpdC5cbiAqIChTZWUgYWxzbyByZWFkX2J1ZigpKS5cbiAqL1xuZnVuY3Rpb24gZmx1c2hfcGVuZGluZyhzdHJtKSB7XG4gIHZhciBzID0gc3RybS5zdGF0ZTtcblxuICAvL190cl9mbHVzaF9iaXRzKHMpO1xuICB2YXIgbGVuID0gcy5wZW5kaW5nO1xuICBpZiAobGVuID4gc3RybS5hdmFpbF9vdXQpIHtcbiAgICBsZW4gPSBzdHJtLmF2YWlsX291dDtcbiAgfVxuICBpZiAobGVuID09PSAwKSB7IHJldHVybjsgfVxuXG4gIHV0aWxzLmFycmF5U2V0KHN0cm0ub3V0cHV0LCBzLnBlbmRpbmdfYnVmLCBzLnBlbmRpbmdfb3V0LCBsZW4sIHN0cm0ubmV4dF9vdXQpO1xuICBzdHJtLm5leHRfb3V0ICs9IGxlbjtcbiAgcy5wZW5kaW5nX291dCArPSBsZW47XG4gIHN0cm0udG90YWxfb3V0ICs9IGxlbjtcbiAgc3RybS5hdmFpbF9vdXQgLT0gbGVuO1xuICBzLnBlbmRpbmcgLT0gbGVuO1xuICBpZiAocy5wZW5kaW5nID09PSAwKSB7XG4gICAgcy5wZW5kaW5nX291dCA9IDA7XG4gIH1cbn1cblxuXG5mdW5jdGlvbiBmbHVzaF9ibG9ja19vbmx5IChzLCBsYXN0KSB7XG4gIHRyZWVzLl90cl9mbHVzaF9ibG9jayhzLCAocy5ibG9ja19zdGFydCA+PSAwID8gcy5ibG9ja19zdGFydCA6IC0xKSwgcy5zdHJzdGFydCAtIHMuYmxvY2tfc3RhcnQsIGxhc3QpO1xuICBzLmJsb2NrX3N0YXJ0ID0gcy5zdHJzdGFydDtcbiAgZmx1c2hfcGVuZGluZyhzLnN0cm0pO1xufVxuXG5cbmZ1bmN0aW9uIHB1dF9ieXRlKHMsIGIpIHtcbiAgcy5wZW5kaW5nX2J1ZltzLnBlbmRpbmcrK10gPSBiO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFB1dCBhIHNob3J0IGluIHRoZSBwZW5kaW5nIGJ1ZmZlci4gVGhlIDE2LWJpdCB2YWx1ZSBpcyBwdXQgaW4gTVNCIG9yZGVyLlxuICogSU4gYXNzZXJ0aW9uOiB0aGUgc3RyZWFtIHN0YXRlIGlzIGNvcnJlY3QgYW5kIHRoZXJlIGlzIGVub3VnaCByb29tIGluXG4gKiBwZW5kaW5nX2J1Zi5cbiAqL1xuZnVuY3Rpb24gcHV0U2hvcnRNU0IocywgYikge1xuLy8gIHB1dF9ieXRlKHMsIChCeXRlKShiID4+IDgpKTtcbi8vICBwdXRfYnl0ZShzLCAoQnl0ZSkoYiAmIDB4ZmYpKTtcbiAgcy5wZW5kaW5nX2J1ZltzLnBlbmRpbmcrK10gPSAoYiA+Pj4gOCkgJiAweGZmO1xuICBzLnBlbmRpbmdfYnVmW3MucGVuZGluZysrXSA9IGIgJiAweGZmO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogUmVhZCBhIG5ldyBidWZmZXIgZnJvbSB0aGUgY3VycmVudCBpbnB1dCBzdHJlYW0sIHVwZGF0ZSB0aGUgYWRsZXIzMlxuICogYW5kIHRvdGFsIG51bWJlciBvZiBieXRlcyByZWFkLiAgQWxsIGRlZmxhdGUoKSBpbnB1dCBnb2VzIHRocm91Z2hcbiAqIHRoaXMgZnVuY3Rpb24gc28gc29tZSBhcHBsaWNhdGlvbnMgbWF5IHdpc2ggdG8gbW9kaWZ5IGl0IHRvIGF2b2lkXG4gKiBhbGxvY2F0aW5nIGEgbGFyZ2Ugc3RybS0+aW5wdXQgYnVmZmVyIGFuZCBjb3B5aW5nIGZyb20gaXQuXG4gKiAoU2VlIGFsc28gZmx1c2hfcGVuZGluZygpKS5cbiAqL1xuZnVuY3Rpb24gcmVhZF9idWYoc3RybSwgYnVmLCBzdGFydCwgc2l6ZSkge1xuICB2YXIgbGVuID0gc3RybS5hdmFpbF9pbjtcblxuICBpZiAobGVuID4gc2l6ZSkgeyBsZW4gPSBzaXplOyB9XG4gIGlmIChsZW4gPT09IDApIHsgcmV0dXJuIDA7IH1cblxuICBzdHJtLmF2YWlsX2luIC09IGxlbjtcblxuICB1dGlscy5hcnJheVNldChidWYsIHN0cm0uaW5wdXQsIHN0cm0ubmV4dF9pbiwgbGVuLCBzdGFydCk7XG4gIGlmIChzdHJtLnN0YXRlLndyYXAgPT09IDEpIHtcbiAgICBzdHJtLmFkbGVyID0gYWRsZXIzMihzdHJtLmFkbGVyLCBidWYsIGxlbiwgc3RhcnQpO1xuICB9XG5cbiAgZWxzZSBpZiAoc3RybS5zdGF0ZS53cmFwID09PSAyKSB7XG4gICAgc3RybS5hZGxlciA9IGNyYzMyKHN0cm0uYWRsZXIsIGJ1ZiwgbGVuLCBzdGFydCk7XG4gIH1cblxuICBzdHJtLm5leHRfaW4gKz0gbGVuO1xuICBzdHJtLnRvdGFsX2luICs9IGxlbjtcblxuICByZXR1cm4gbGVuO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogU2V0IG1hdGNoX3N0YXJ0IHRvIHRoZSBsb25nZXN0IG1hdGNoIHN0YXJ0aW5nIGF0IHRoZSBnaXZlbiBzdHJpbmcgYW5kXG4gKiByZXR1cm4gaXRzIGxlbmd0aC4gTWF0Y2hlcyBzaG9ydGVyIG9yIGVxdWFsIHRvIHByZXZfbGVuZ3RoIGFyZSBkaXNjYXJkZWQsXG4gKiBpbiB3aGljaCBjYXNlIHRoZSByZXN1bHQgaXMgZXF1YWwgdG8gcHJldl9sZW5ndGggYW5kIG1hdGNoX3N0YXJ0IGlzXG4gKiBnYXJiYWdlLlxuICogSU4gYXNzZXJ0aW9uczogY3VyX21hdGNoIGlzIHRoZSBoZWFkIG9mIHRoZSBoYXNoIGNoYWluIGZvciB0aGUgY3VycmVudFxuICogICBzdHJpbmcgKHN0cnN0YXJ0KSBhbmQgaXRzIGRpc3RhbmNlIGlzIDw9IE1BWF9ESVNULCBhbmQgcHJldl9sZW5ndGggPj0gMVxuICogT1VUIGFzc2VydGlvbjogdGhlIG1hdGNoIGxlbmd0aCBpcyBub3QgZ3JlYXRlciB0aGFuIHMtPmxvb2thaGVhZC5cbiAqL1xuZnVuY3Rpb24gbG9uZ2VzdF9tYXRjaChzLCBjdXJfbWF0Y2gpIHtcbiAgdmFyIGNoYWluX2xlbmd0aCA9IHMubWF4X2NoYWluX2xlbmd0aDsgICAgICAvKiBtYXggaGFzaCBjaGFpbiBsZW5ndGggKi9cbiAgdmFyIHNjYW4gPSBzLnN0cnN0YXJ0OyAvKiBjdXJyZW50IHN0cmluZyAqL1xuICB2YXIgbWF0Y2g7ICAgICAgICAgICAgICAgICAgICAgICAvKiBtYXRjaGVkIHN0cmluZyAqL1xuICB2YXIgbGVuOyAgICAgICAgICAgICAgICAgICAgICAgICAgIC8qIGxlbmd0aCBvZiBjdXJyZW50IG1hdGNoICovXG4gIHZhciBiZXN0X2xlbiA9IHMucHJldl9sZW5ndGg7ICAgICAgICAgICAgICAvKiBiZXN0IG1hdGNoIGxlbmd0aCBzbyBmYXIgKi9cbiAgdmFyIG5pY2VfbWF0Y2ggPSBzLm5pY2VfbWF0Y2g7ICAgICAgICAgICAgIC8qIHN0b3AgaWYgbWF0Y2ggbG9uZyBlbm91Z2ggKi9cbiAgdmFyIGxpbWl0ID0gKHMuc3Ryc3RhcnQgPiAocy53X3NpemUgLSBNSU5fTE9PS0FIRUFEKSkgP1xuICAgICAgcy5zdHJzdGFydCAtIChzLndfc2l6ZSAtIE1JTl9MT09LQUhFQUQpIDogMC8qTklMKi87XG5cbiAgdmFyIF93aW4gPSBzLndpbmRvdzsgLy8gc2hvcnRjdXRcblxuICB2YXIgd21hc2sgPSBzLndfbWFzaztcbiAgdmFyIHByZXYgID0gcy5wcmV2O1xuXG4gIC8qIFN0b3Agd2hlbiBjdXJfbWF0Y2ggYmVjb21lcyA8PSBsaW1pdC4gVG8gc2ltcGxpZnkgdGhlIGNvZGUsXG4gICAqIHdlIHByZXZlbnQgbWF0Y2hlcyB3aXRoIHRoZSBzdHJpbmcgb2Ygd2luZG93IGluZGV4IDAuXG4gICAqL1xuXG4gIHZhciBzdHJlbmQgPSBzLnN0cnN0YXJ0ICsgTUFYX01BVENIO1xuICB2YXIgc2Nhbl9lbmQxICA9IF93aW5bc2NhbiArIGJlc3RfbGVuIC0gMV07XG4gIHZhciBzY2FuX2VuZCAgID0gX3dpbltzY2FuICsgYmVzdF9sZW5dO1xuXG4gIC8qIFRoZSBjb2RlIGlzIG9wdGltaXplZCBmb3IgSEFTSF9CSVRTID49IDggYW5kIE1BWF9NQVRDSC0yIG11bHRpcGxlIG9mIDE2LlxuICAgKiBJdCBpcyBlYXN5IHRvIGdldCByaWQgb2YgdGhpcyBvcHRpbWl6YXRpb24gaWYgbmVjZXNzYXJ5LlxuICAgKi9cbiAgLy8gQXNzZXJ0KHMtPmhhc2hfYml0cyA+PSA4ICYmIE1BWF9NQVRDSCA9PSAyNTgsIFwiQ29kZSB0b28gY2xldmVyXCIpO1xuXG4gIC8qIERvIG5vdCB3YXN0ZSB0b28gbXVjaCB0aW1lIGlmIHdlIGFscmVhZHkgaGF2ZSBhIGdvb2QgbWF0Y2g6ICovXG4gIGlmIChzLnByZXZfbGVuZ3RoID49IHMuZ29vZF9tYXRjaCkge1xuICAgIGNoYWluX2xlbmd0aCA+Pj0gMjtcbiAgfVxuICAvKiBEbyBub3QgbG9vayBmb3IgbWF0Y2hlcyBiZXlvbmQgdGhlIGVuZCBvZiB0aGUgaW5wdXQuIFRoaXMgaXMgbmVjZXNzYXJ5XG4gICAqIHRvIG1ha2UgZGVmbGF0ZSBkZXRlcm1pbmlzdGljLlxuICAgKi9cbiAgaWYgKG5pY2VfbWF0Y2ggPiBzLmxvb2thaGVhZCkgeyBuaWNlX21hdGNoID0gcy5sb29rYWhlYWQ7IH1cblxuICAvLyBBc3NlcnQoKHVsZylzLT5zdHJzdGFydCA8PSBzLT53aW5kb3dfc2l6ZS1NSU5fTE9PS0FIRUFELCBcIm5lZWQgbG9va2FoZWFkXCIpO1xuXG4gIGRvIHtcbiAgICAvLyBBc3NlcnQoY3VyX21hdGNoIDwgcy0+c3Ryc3RhcnQsIFwibm8gZnV0dXJlXCIpO1xuICAgIG1hdGNoID0gY3VyX21hdGNoO1xuXG4gICAgLyogU2tpcCB0byBuZXh0IG1hdGNoIGlmIHRoZSBtYXRjaCBsZW5ndGggY2Fubm90IGluY3JlYXNlXG4gICAgICogb3IgaWYgdGhlIG1hdGNoIGxlbmd0aCBpcyBsZXNzIHRoYW4gMi4gIE5vdGUgdGhhdCB0aGUgY2hlY2tzIGJlbG93XG4gICAgICogZm9yIGluc3VmZmljaWVudCBsb29rYWhlYWQgb25seSBvY2N1ciBvY2Nhc2lvbmFsbHkgZm9yIHBlcmZvcm1hbmNlXG4gICAgICogcmVhc29ucy4gIFRoZXJlZm9yZSB1bmluaXRpYWxpemVkIG1lbW9yeSB3aWxsIGJlIGFjY2Vzc2VkLCBhbmRcbiAgICAgKiBjb25kaXRpb25hbCBqdW1wcyB3aWxsIGJlIG1hZGUgdGhhdCBkZXBlbmQgb24gdGhvc2UgdmFsdWVzLlxuICAgICAqIEhvd2V2ZXIgdGhlIGxlbmd0aCBvZiB0aGUgbWF0Y2ggaXMgbGltaXRlZCB0byB0aGUgbG9va2FoZWFkLCBzb1xuICAgICAqIHRoZSBvdXRwdXQgb2YgZGVmbGF0ZSBpcyBub3QgYWZmZWN0ZWQgYnkgdGhlIHVuaW5pdGlhbGl6ZWQgdmFsdWVzLlxuICAgICAqL1xuXG4gICAgaWYgKF93aW5bbWF0Y2ggKyBiZXN0X2xlbl0gICAgICE9PSBzY2FuX2VuZCAgfHxcbiAgICAgICAgX3dpblttYXRjaCArIGJlc3RfbGVuIC0gMV0gIT09IHNjYW5fZW5kMSB8fFxuICAgICAgICBfd2luW21hdGNoXSAgICAgICAgICAgICAgICAhPT0gX3dpbltzY2FuXSB8fFxuICAgICAgICBfd2luWysrbWF0Y2hdICAgICAgICAgICAgICAhPT0gX3dpbltzY2FuICsgMV0pIHtcbiAgICAgIGNvbnRpbnVlO1xuICAgIH1cblxuICAgIC8qIFRoZSBjaGVjayBhdCBiZXN0X2xlbi0xIGNhbiBiZSByZW1vdmVkIGJlY2F1c2UgaXQgd2lsbCBiZSBtYWRlXG4gICAgICogYWdhaW4gbGF0ZXIuIChUaGlzIGhldXJpc3RpYyBpcyBub3QgYWx3YXlzIGEgd2luLilcbiAgICAgKiBJdCBpcyBub3QgbmVjZXNzYXJ5IHRvIGNvbXBhcmUgc2NhblsyXSBhbmQgbWF0Y2hbMl0gc2luY2UgdGhleVxuICAgICAqIGFyZSBhbHdheXMgZXF1YWwgd2hlbiB0aGUgb3RoZXIgYnl0ZXMgbWF0Y2gsIGdpdmVuIHRoYXRcbiAgICAgKiB0aGUgaGFzaCBrZXlzIGFyZSBlcXVhbCBhbmQgdGhhdCBIQVNIX0JJVFMgPj0gOC5cbiAgICAgKi9cbiAgICBzY2FuICs9IDI7XG4gICAgbWF0Y2grKztcbiAgICAvLyBBc3NlcnQoKnNjYW4gPT0gKm1hdGNoLCBcIm1hdGNoWzJdP1wiKTtcblxuICAgIC8qIFdlIGNoZWNrIGZvciBpbnN1ZmZpY2llbnQgbG9va2FoZWFkIG9ubHkgZXZlcnkgOHRoIGNvbXBhcmlzb247XG4gICAgICogdGhlIDI1NnRoIGNoZWNrIHdpbGwgYmUgbWFkZSBhdCBzdHJzdGFydCsyNTguXG4gICAgICovXG4gICAgZG8ge1xuICAgICAgLypqc2hpbnQgbm9lbXB0eTpmYWxzZSovXG4gICAgfSB3aGlsZSAoX3dpblsrK3NjYW5dID09PSBfd2luWysrbWF0Y2hdICYmIF93aW5bKytzY2FuXSA9PT0gX3dpblsrK21hdGNoXSAmJlxuICAgICAgICAgICAgIF93aW5bKytzY2FuXSA9PT0gX3dpblsrK21hdGNoXSAmJiBfd2luWysrc2Nhbl0gPT09IF93aW5bKyttYXRjaF0gJiZcbiAgICAgICAgICAgICBfd2luWysrc2Nhbl0gPT09IF93aW5bKyttYXRjaF0gJiYgX3dpblsrK3NjYW5dID09PSBfd2luWysrbWF0Y2hdICYmXG4gICAgICAgICAgICAgX3dpblsrK3NjYW5dID09PSBfd2luWysrbWF0Y2hdICYmIF93aW5bKytzY2FuXSA9PT0gX3dpblsrK21hdGNoXSAmJlxuICAgICAgICAgICAgIHNjYW4gPCBzdHJlbmQpO1xuXG4gICAgLy8gQXNzZXJ0KHNjYW4gPD0gcy0+d2luZG93Kyh1bnNpZ25lZCkocy0+d2luZG93X3NpemUtMSksIFwid2lsZCBzY2FuXCIpO1xuXG4gICAgbGVuID0gTUFYX01BVENIIC0gKHN0cmVuZCAtIHNjYW4pO1xuICAgIHNjYW4gPSBzdHJlbmQgLSBNQVhfTUFUQ0g7XG5cbiAgICBpZiAobGVuID4gYmVzdF9sZW4pIHtcbiAgICAgIHMubWF0Y2hfc3RhcnQgPSBjdXJfbWF0Y2g7XG4gICAgICBiZXN0X2xlbiA9IGxlbjtcbiAgICAgIGlmIChsZW4gPj0gbmljZV9tYXRjaCkge1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIHNjYW5fZW5kMSAgPSBfd2luW3NjYW4gKyBiZXN0X2xlbiAtIDFdO1xuICAgICAgc2Nhbl9lbmQgICA9IF93aW5bc2NhbiArIGJlc3RfbGVuXTtcbiAgICB9XG4gIH0gd2hpbGUgKChjdXJfbWF0Y2ggPSBwcmV2W2N1cl9tYXRjaCAmIHdtYXNrXSkgPiBsaW1pdCAmJiAtLWNoYWluX2xlbmd0aCAhPT0gMCk7XG5cbiAgaWYgKGJlc3RfbGVuIDw9IHMubG9va2FoZWFkKSB7XG4gICAgcmV0dXJuIGJlc3RfbGVuO1xuICB9XG4gIHJldHVybiBzLmxvb2thaGVhZDtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEZpbGwgdGhlIHdpbmRvdyB3aGVuIHRoZSBsb29rYWhlYWQgYmVjb21lcyBpbnN1ZmZpY2llbnQuXG4gKiBVcGRhdGVzIHN0cnN0YXJ0IGFuZCBsb29rYWhlYWQuXG4gKlxuICogSU4gYXNzZXJ0aW9uOiBsb29rYWhlYWQgPCBNSU5fTE9PS0FIRUFEXG4gKiBPVVQgYXNzZXJ0aW9uczogc3Ryc3RhcnQgPD0gd2luZG93X3NpemUtTUlOX0xPT0tBSEVBRFxuICogICAgQXQgbGVhc3Qgb25lIGJ5dGUgaGFzIGJlZW4gcmVhZCwgb3IgYXZhaWxfaW4gPT0gMDsgcmVhZHMgYXJlXG4gKiAgICBwZXJmb3JtZWQgZm9yIGF0IGxlYXN0IHR3byBieXRlcyAocmVxdWlyZWQgZm9yIHRoZSB6aXAgdHJhbnNsYXRlX2VvbFxuICogICAgb3B0aW9uIC0tIG5vdCBzdXBwb3J0ZWQgaGVyZSkuXG4gKi9cbmZ1bmN0aW9uIGZpbGxfd2luZG93KHMpIHtcbiAgdmFyIF93X3NpemUgPSBzLndfc2l6ZTtcbiAgdmFyIHAsIG4sIG0sIG1vcmUsIHN0cjtcblxuICAvL0Fzc2VydChzLT5sb29rYWhlYWQgPCBNSU5fTE9PS0FIRUFELCBcImFscmVhZHkgZW5vdWdoIGxvb2thaGVhZFwiKTtcblxuICBkbyB7XG4gICAgbW9yZSA9IHMud2luZG93X3NpemUgLSBzLmxvb2thaGVhZCAtIHMuc3Ryc3RhcnQ7XG5cbiAgICAvLyBKUyBpbnRzIGhhdmUgMzIgYml0LCBibG9jayBiZWxvdyBub3QgbmVlZGVkXG4gICAgLyogRGVhbCB3aXRoICFAIyQlIDY0SyBsaW1pdDogKi9cbiAgICAvL2lmIChzaXplb2YoaW50KSA8PSAyKSB7XG4gICAgLy8gICAgaWYgKG1vcmUgPT0gMCAmJiBzLT5zdHJzdGFydCA9PSAwICYmIHMtPmxvb2thaGVhZCA9PSAwKSB7XG4gICAgLy8gICAgICAgIG1vcmUgPSB3c2l6ZTtcbiAgICAvL1xuICAgIC8vICB9IGVsc2UgaWYgKG1vcmUgPT0gKHVuc2lnbmVkKSgtMSkpIHtcbiAgICAvLyAgICAgICAgLyogVmVyeSB1bmxpa2VseSwgYnV0IHBvc3NpYmxlIG9uIDE2IGJpdCBtYWNoaW5lIGlmXG4gICAgLy8gICAgICAgICAqIHN0cnN0YXJ0ID09IDAgJiYgbG9va2FoZWFkID09IDEgKGlucHV0IGRvbmUgYSBieXRlIGF0IHRpbWUpXG4gICAgLy8gICAgICAgICAqL1xuICAgIC8vICAgICAgICBtb3JlLS07XG4gICAgLy8gICAgfVxuICAgIC8vfVxuXG5cbiAgICAvKiBJZiB0aGUgd2luZG93IGlzIGFsbW9zdCBmdWxsIGFuZCB0aGVyZSBpcyBpbnN1ZmZpY2llbnQgbG9va2FoZWFkLFxuICAgICAqIG1vdmUgdGhlIHVwcGVyIGhhbGYgdG8gdGhlIGxvd2VyIG9uZSB0byBtYWtlIHJvb20gaW4gdGhlIHVwcGVyIGhhbGYuXG4gICAgICovXG4gICAgaWYgKHMuc3Ryc3RhcnQgPj0gX3dfc2l6ZSArIChfd19zaXplIC0gTUlOX0xPT0tBSEVBRCkpIHtcblxuICAgICAgdXRpbHMuYXJyYXlTZXQocy53aW5kb3csIHMud2luZG93LCBfd19zaXplLCBfd19zaXplLCAwKTtcbiAgICAgIHMubWF0Y2hfc3RhcnQgLT0gX3dfc2l6ZTtcbiAgICAgIHMuc3Ryc3RhcnQgLT0gX3dfc2l6ZTtcbiAgICAgIC8qIHdlIG5vdyBoYXZlIHN0cnN0YXJ0ID49IE1BWF9ESVNUICovXG4gICAgICBzLmJsb2NrX3N0YXJ0IC09IF93X3NpemU7XG5cbiAgICAgIC8qIFNsaWRlIHRoZSBoYXNoIHRhYmxlIChjb3VsZCBiZSBhdm9pZGVkIHdpdGggMzIgYml0IHZhbHVlc1xuICAgICAgIGF0IHRoZSBleHBlbnNlIG9mIG1lbW9yeSB1c2FnZSkuIFdlIHNsaWRlIGV2ZW4gd2hlbiBsZXZlbCA9PSAwXG4gICAgICAgdG8ga2VlcCB0aGUgaGFzaCB0YWJsZSBjb25zaXN0ZW50IGlmIHdlIHN3aXRjaCBiYWNrIHRvIGxldmVsID4gMFxuICAgICAgIGxhdGVyLiAoVXNpbmcgbGV2ZWwgMCBwZXJtYW5lbnRseSBpcyBub3QgYW4gb3B0aW1hbCB1c2FnZSBvZlxuICAgICAgIHpsaWIsIHNvIHdlIGRvbid0IGNhcmUgYWJvdXQgdGhpcyBwYXRob2xvZ2ljYWwgY2FzZS4pXG4gICAgICAgKi9cblxuICAgICAgbiA9IHMuaGFzaF9zaXplO1xuICAgICAgcCA9IG47XG4gICAgICBkbyB7XG4gICAgICAgIG0gPSBzLmhlYWRbLS1wXTtcbiAgICAgICAgcy5oZWFkW3BdID0gKG0gPj0gX3dfc2l6ZSA/IG0gLSBfd19zaXplIDogMCk7XG4gICAgICB9IHdoaWxlICgtLW4pO1xuXG4gICAgICBuID0gX3dfc2l6ZTtcbiAgICAgIHAgPSBuO1xuICAgICAgZG8ge1xuICAgICAgICBtID0gcy5wcmV2Wy0tcF07XG4gICAgICAgIHMucHJldltwXSA9IChtID49IF93X3NpemUgPyBtIC0gX3dfc2l6ZSA6IDApO1xuICAgICAgICAvKiBJZiBuIGlzIG5vdCBvbiBhbnkgaGFzaCBjaGFpbiwgcHJldltuXSBpcyBnYXJiYWdlIGJ1dFxuICAgICAgICAgKiBpdHMgdmFsdWUgd2lsbCBuZXZlciBiZSB1c2VkLlxuICAgICAgICAgKi9cbiAgICAgIH0gd2hpbGUgKC0tbik7XG5cbiAgICAgIG1vcmUgKz0gX3dfc2l6ZTtcbiAgICB9XG4gICAgaWYgKHMuc3RybS5hdmFpbF9pbiA9PT0gMCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuXG4gICAgLyogSWYgdGhlcmUgd2FzIG5vIHNsaWRpbmc6XG4gICAgICogICAgc3Ryc3RhcnQgPD0gV1NJWkUrTUFYX0RJU1QtMSAmJiBsb29rYWhlYWQgPD0gTUlOX0xPT0tBSEVBRCAtIDEgJiZcbiAgICAgKiAgICBtb3JlID09IHdpbmRvd19zaXplIC0gbG9va2FoZWFkIC0gc3Ryc3RhcnRcbiAgICAgKiA9PiBtb3JlID49IHdpbmRvd19zaXplIC0gKE1JTl9MT09LQUhFQUQtMSArIFdTSVpFICsgTUFYX0RJU1QtMSlcbiAgICAgKiA9PiBtb3JlID49IHdpbmRvd19zaXplIC0gMipXU0laRSArIDJcbiAgICAgKiBJbiB0aGUgQklHX01FTSBvciBNTUFQIGNhc2UgKG5vdCB5ZXQgc3VwcG9ydGVkKSxcbiAgICAgKiAgIHdpbmRvd19zaXplID09IGlucHV0X3NpemUgKyBNSU5fTE9PS0FIRUFEICAmJlxuICAgICAqICAgc3Ryc3RhcnQgKyBzLT5sb29rYWhlYWQgPD0gaW5wdXRfc2l6ZSA9PiBtb3JlID49IE1JTl9MT09LQUhFQUQuXG4gICAgICogT3RoZXJ3aXNlLCB3aW5kb3dfc2l6ZSA9PSAyKldTSVpFIHNvIG1vcmUgPj0gMi5cbiAgICAgKiBJZiB0aGVyZSB3YXMgc2xpZGluZywgbW9yZSA+PSBXU0laRS4gU28gaW4gYWxsIGNhc2VzLCBtb3JlID49IDIuXG4gICAgICovXG4gICAgLy9Bc3NlcnQobW9yZSA+PSAyLCBcIm1vcmUgPCAyXCIpO1xuICAgIG4gPSByZWFkX2J1ZihzLnN0cm0sIHMud2luZG93LCBzLnN0cnN0YXJ0ICsgcy5sb29rYWhlYWQsIG1vcmUpO1xuICAgIHMubG9va2FoZWFkICs9IG47XG5cbiAgICAvKiBJbml0aWFsaXplIHRoZSBoYXNoIHZhbHVlIG5vdyB0aGF0IHdlIGhhdmUgc29tZSBpbnB1dDogKi9cbiAgICBpZiAocy5sb29rYWhlYWQgKyBzLmluc2VydCA+PSBNSU5fTUFUQ0gpIHtcbiAgICAgIHN0ciA9IHMuc3Ryc3RhcnQgLSBzLmluc2VydDtcbiAgICAgIHMuaW5zX2ggPSBzLndpbmRvd1tzdHJdO1xuXG4gICAgICAvKiBVUERBVEVfSEFTSChzLCBzLT5pbnNfaCwgcy0+d2luZG93W3N0ciArIDFdKTsgKi9cbiAgICAgIHMuaW5zX2ggPSAoKHMuaW5zX2ggPDwgcy5oYXNoX3NoaWZ0KSBeIHMud2luZG93W3N0ciArIDFdKSAmIHMuaGFzaF9tYXNrO1xuLy8jaWYgTUlOX01BVENIICE9IDNcbi8vICAgICAgICBDYWxsIHVwZGF0ZV9oYXNoKCkgTUlOX01BVENILTMgbW9yZSB0aW1lc1xuLy8jZW5kaWZcbiAgICAgIHdoaWxlIChzLmluc2VydCkge1xuICAgICAgICAvKiBVUERBVEVfSEFTSChzLCBzLT5pbnNfaCwgcy0+d2luZG93W3N0ciArIE1JTl9NQVRDSC0xXSk7ICovXG4gICAgICAgIHMuaW5zX2ggPSAoKHMuaW5zX2ggPDwgcy5oYXNoX3NoaWZ0KSBeIHMud2luZG93W3N0ciArIE1JTl9NQVRDSC0xXSkgJiBzLmhhc2hfbWFzaztcblxuICAgICAgICBzLnByZXZbc3RyICYgcy53X21hc2tdID0gcy5oZWFkW3MuaW5zX2hdO1xuICAgICAgICBzLmhlYWRbcy5pbnNfaF0gPSBzdHI7XG4gICAgICAgIHN0cisrO1xuICAgICAgICBzLmluc2VydC0tO1xuICAgICAgICBpZiAocy5sb29rYWhlYWQgKyBzLmluc2VydCA8IE1JTl9NQVRDSCkge1xuICAgICAgICAgIGJyZWFrO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICAgIC8qIElmIHRoZSB3aG9sZSBpbnB1dCBoYXMgbGVzcyB0aGFuIE1JTl9NQVRDSCBieXRlcywgaW5zX2ggaXMgZ2FyYmFnZSxcbiAgICAgKiBidXQgdGhpcyBpcyBub3QgaW1wb3J0YW50IHNpbmNlIG9ubHkgbGl0ZXJhbCBieXRlcyB3aWxsIGJlIGVtaXR0ZWQuXG4gICAgICovXG5cbiAgfSB3aGlsZSAocy5sb29rYWhlYWQgPCBNSU5fTE9PS0FIRUFEICYmIHMuc3RybS5hdmFpbF9pbiAhPT0gMCk7XG5cbiAgLyogSWYgdGhlIFdJTl9JTklUIGJ5dGVzIGFmdGVyIHRoZSBlbmQgb2YgdGhlIGN1cnJlbnQgZGF0YSBoYXZlIG5ldmVyIGJlZW5cbiAgICogd3JpdHRlbiwgdGhlbiB6ZXJvIHRob3NlIGJ5dGVzIGluIG9yZGVyIHRvIGF2b2lkIG1lbW9yeSBjaGVjayByZXBvcnRzIG9mXG4gICAqIHRoZSB1c2Ugb2YgdW5pbml0aWFsaXplZCAob3IgdW5pbml0aWFsaXNlZCBhcyBKdWxpYW4gd3JpdGVzKSBieXRlcyBieVxuICAgKiB0aGUgbG9uZ2VzdCBtYXRjaCByb3V0aW5lcy4gIFVwZGF0ZSB0aGUgaGlnaCB3YXRlciBtYXJrIGZvciB0aGUgbmV4dFxuICAgKiB0aW1lIHRocm91Z2ggaGVyZS4gIFdJTl9JTklUIGlzIHNldCB0byBNQVhfTUFUQ0ggc2luY2UgdGhlIGxvbmdlc3QgbWF0Y2hcbiAgICogcm91dGluZXMgYWxsb3cgc2Nhbm5pbmcgdG8gc3Ryc3RhcnQgKyBNQVhfTUFUQ0gsIGlnbm9yaW5nIGxvb2thaGVhZC5cbiAgICovXG4vLyAgaWYgKHMuaGlnaF93YXRlciA8IHMud2luZG93X3NpemUpIHtcbi8vICAgIHZhciBjdXJyID0gcy5zdHJzdGFydCArIHMubG9va2FoZWFkO1xuLy8gICAgdmFyIGluaXQgPSAwO1xuLy9cbi8vICAgIGlmIChzLmhpZ2hfd2F0ZXIgPCBjdXJyKSB7XG4vLyAgICAgIC8qIFByZXZpb3VzIGhpZ2ggd2F0ZXIgbWFyayBiZWxvdyBjdXJyZW50IGRhdGEgLS0gemVybyBXSU5fSU5JVFxuLy8gICAgICAgKiBieXRlcyBvciB1cCB0byBlbmQgb2Ygd2luZG93LCB3aGljaGV2ZXIgaXMgbGVzcy5cbi8vICAgICAgICovXG4vLyAgICAgIGluaXQgPSBzLndpbmRvd19zaXplIC0gY3Vycjtcbi8vICAgICAgaWYgKGluaXQgPiBXSU5fSU5JVClcbi8vICAgICAgICBpbml0ID0gV0lOX0lOSVQ7XG4vLyAgICAgIHptZW16ZXJvKHMtPndpbmRvdyArIGN1cnIsICh1bnNpZ25lZClpbml0KTtcbi8vICAgICAgcy0+aGlnaF93YXRlciA9IGN1cnIgKyBpbml0O1xuLy8gICAgfVxuLy8gICAgZWxzZSBpZiAocy0+aGlnaF93YXRlciA8ICh1bGcpY3VyciArIFdJTl9JTklUKSB7XG4vLyAgICAgIC8qIEhpZ2ggd2F0ZXIgbWFyayBhdCBvciBhYm92ZSBjdXJyZW50IGRhdGEsIGJ1dCBiZWxvdyBjdXJyZW50IGRhdGFcbi8vICAgICAgICogcGx1cyBXSU5fSU5JVCAtLSB6ZXJvIG91dCB0byBjdXJyZW50IGRhdGEgcGx1cyBXSU5fSU5JVCwgb3IgdXBcbi8vICAgICAgICogdG8gZW5kIG9mIHdpbmRvdywgd2hpY2hldmVyIGlzIGxlc3MuXG4vLyAgICAgICAqL1xuLy8gICAgICBpbml0ID0gKHVsZyljdXJyICsgV0lOX0lOSVQgLSBzLT5oaWdoX3dhdGVyO1xuLy8gICAgICBpZiAoaW5pdCA+IHMtPndpbmRvd19zaXplIC0gcy0+aGlnaF93YXRlcilcbi8vICAgICAgICBpbml0ID0gcy0+d2luZG93X3NpemUgLSBzLT5oaWdoX3dhdGVyO1xuLy8gICAgICB6bWVtemVybyhzLT53aW5kb3cgKyBzLT5oaWdoX3dhdGVyLCAodW5zaWduZWQpaW5pdCk7XG4vLyAgICAgIHMtPmhpZ2hfd2F0ZXIgKz0gaW5pdDtcbi8vICAgIH1cbi8vICB9XG4vL1xuLy8gIEFzc2VydCgodWxnKXMtPnN0cnN0YXJ0IDw9IHMtPndpbmRvd19zaXplIC0gTUlOX0xPT0tBSEVBRCxcbi8vICAgIFwibm90IGVub3VnaCByb29tIGZvciBzZWFyY2hcIik7XG59XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29weSB3aXRob3V0IGNvbXByZXNzaW9uIGFzIG11Y2ggYXMgcG9zc2libGUgZnJvbSB0aGUgaW5wdXQgc3RyZWFtLCByZXR1cm5cbiAqIHRoZSBjdXJyZW50IGJsb2NrIHN0YXRlLlxuICogVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCBpbnNlcnQgbmV3IHN0cmluZ3MgaW4gdGhlIGRpY3Rpb25hcnkgc2luY2VcbiAqIHVuY29tcHJlc3NpYmxlIGRhdGEgaXMgcHJvYmFibHkgbm90IHVzZWZ1bC4gVGhpcyBmdW5jdGlvbiBpcyB1c2VkXG4gKiBvbmx5IGZvciB0aGUgbGV2ZWw9MCBjb21wcmVzc2lvbiBvcHRpb24uXG4gKiBOT1RFOiB0aGlzIGZ1bmN0aW9uIHNob3VsZCBiZSBvcHRpbWl6ZWQgdG8gYXZvaWQgZXh0cmEgY29weWluZyBmcm9tXG4gKiB3aW5kb3cgdG8gcGVuZGluZ19idWYuXG4gKi9cbmZ1bmN0aW9uIGRlZmxhdGVfc3RvcmVkKHMsIGZsdXNoKSB7XG4gIC8qIFN0b3JlZCBibG9ja3MgYXJlIGxpbWl0ZWQgdG8gMHhmZmZmIGJ5dGVzLCBwZW5kaW5nX2J1ZiBpcyBsaW1pdGVkXG4gICAqIHRvIHBlbmRpbmdfYnVmX3NpemUsIGFuZCBlYWNoIHN0b3JlZCBibG9jayBoYXMgYSA1IGJ5dGUgaGVhZGVyOlxuICAgKi9cbiAgdmFyIG1heF9ibG9ja19zaXplID0gMHhmZmZmO1xuXG4gIGlmIChtYXhfYmxvY2tfc2l6ZSA+IHMucGVuZGluZ19idWZfc2l6ZSAtIDUpIHtcbiAgICBtYXhfYmxvY2tfc2l6ZSA9IHMucGVuZGluZ19idWZfc2l6ZSAtIDU7XG4gIH1cblxuICAvKiBDb3B5IGFzIG11Y2ggYXMgcG9zc2libGUgZnJvbSBpbnB1dCB0byBvdXRwdXQ6ICovXG4gIGZvciAoOzspIHtcbiAgICAvKiBGaWxsIHRoZSB3aW5kb3cgYXMgbXVjaCBhcyBwb3NzaWJsZTogKi9cbiAgICBpZiAocy5sb29rYWhlYWQgPD0gMSkge1xuXG4gICAgICAvL0Fzc2VydChzLT5zdHJzdGFydCA8IHMtPndfc2l6ZStNQVhfRElTVChzKSB8fFxuICAgICAgLy8gIHMtPmJsb2NrX3N0YXJ0ID49IChsb25nKXMtPndfc2l6ZSwgXCJzbGlkZSB0b28gbGF0ZVwiKTtcbi8vICAgICAgaWYgKCEocy5zdHJzdGFydCA8IHMud19zaXplICsgKHMud19zaXplIC0gTUlOX0xPT0tBSEVBRCkgfHxcbi8vICAgICAgICBzLmJsb2NrX3N0YXJ0ID49IHMud19zaXplKSkge1xuLy8gICAgICAgIHRocm93ICBuZXcgRXJyb3IoXCJzbGlkZSB0b28gbGF0ZVwiKTtcbi8vICAgICAgfVxuXG4gICAgICBmaWxsX3dpbmRvdyhzKTtcbiAgICAgIGlmIChzLmxvb2thaGVhZCA9PT0gMCAmJiBmbHVzaCA9PT0gWl9OT19GTFVTSCkge1xuICAgICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgICAgfVxuXG4gICAgICBpZiAocy5sb29rYWhlYWQgPT09IDApIHtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICAvKiBmbHVzaCB0aGUgY3VycmVudCBibG9jayAqL1xuICAgIH1cbiAgICAvL0Fzc2VydChzLT5ibG9ja19zdGFydCA+PSAwTCwgXCJibG9jayBnb25lXCIpO1xuLy8gICAgaWYgKHMuYmxvY2tfc3RhcnQgPCAwKSB0aHJvdyBuZXcgRXJyb3IoXCJibG9jayBnb25lXCIpO1xuXG4gICAgcy5zdHJzdGFydCArPSBzLmxvb2thaGVhZDtcbiAgICBzLmxvb2thaGVhZCA9IDA7XG5cbiAgICAvKiBFbWl0IGEgc3RvcmVkIGJsb2NrIGlmIHBlbmRpbmdfYnVmIHdpbGwgYmUgZnVsbDogKi9cbiAgICB2YXIgbWF4X3N0YXJ0ID0gcy5ibG9ja19zdGFydCArIG1heF9ibG9ja19zaXplO1xuXG4gICAgaWYgKHMuc3Ryc3RhcnQgPT09IDAgfHwgcy5zdHJzdGFydCA+PSBtYXhfc3RhcnQpIHtcbiAgICAgIC8qIHN0cnN0YXJ0ID09IDAgaXMgcG9zc2libGUgd2hlbiB3cmFwYXJvdW5kIG9uIDE2LWJpdCBtYWNoaW5lICovXG4gICAgICBzLmxvb2thaGVhZCA9IHMuc3Ryc3RhcnQgLSBtYXhfc3RhcnQ7XG4gICAgICBzLnN0cnN0YXJ0ID0gbWF4X3N0YXJ0O1xuICAgICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAwKTsgKioqL1xuICAgICAgZmx1c2hfYmxvY2tfb25seShzLCBmYWxzZSk7XG4gICAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgICAgfVxuICAgICAgLyoqKi9cblxuXG4gICAgfVxuICAgIC8qIEZsdXNoIGlmIHdlIG1heSBoYXZlIHRvIHNsaWRlLCBvdGhlcndpc2UgYmxvY2tfc3RhcnQgbWF5IGJlY29tZVxuICAgICAqIG5lZ2F0aXZlIGFuZCB0aGUgZGF0YSB3aWxsIGJlIGdvbmU6XG4gICAgICovXG4gICAgaWYgKHMuc3Ryc3RhcnQgLSBzLmJsb2NrX3N0YXJ0ID49IChzLndfc2l6ZSAtIE1JTl9MT09LQUhFQUQpKSB7XG4gICAgICAvKioqIEZMVVNIX0JMT0NLKHMsIDApOyAqKiovXG4gICAgICBmbHVzaF9ibG9ja19vbmx5KHMsIGZhbHNlKTtcbiAgICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICAgIHJldHVybiBCU19ORUVEX01PUkU7XG4gICAgICB9XG4gICAgICAvKioqL1xuICAgIH1cbiAgfVxuXG4gIHMuaW5zZXJ0ID0gMDtcblxuICBpZiAoZmx1c2ggPT09IFpfRklOSVNIKSB7XG4gICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAxKTsgKioqL1xuICAgIGZsdXNoX2Jsb2NrX29ubHkocywgdHJ1ZSk7XG4gICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgIHJldHVybiBCU19GSU5JU0hfU1RBUlRFRDtcbiAgICB9XG4gICAgLyoqKi9cbiAgICByZXR1cm4gQlNfRklOSVNIX0RPTkU7XG4gIH1cblxuICBpZiAocy5zdHJzdGFydCA+IHMuYmxvY2tfc3RhcnQpIHtcbiAgICAvKioqIEZMVVNIX0JMT0NLKHMsIDApOyAqKiovXG4gICAgZmx1c2hfYmxvY2tfb25seShzLCBmYWxzZSk7XG4gICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgIHJldHVybiBCU19ORUVEX01PUkU7XG4gICAgfVxuICAgIC8qKiovXG4gIH1cblxuICByZXR1cm4gQlNfTkVFRF9NT1JFO1xufVxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvbXByZXNzIGFzIG11Y2ggYXMgcG9zc2libGUgZnJvbSB0aGUgaW5wdXQgc3RyZWFtLCByZXR1cm4gdGhlIGN1cnJlbnRcbiAqIGJsb2NrIHN0YXRlLlxuICogVGhpcyBmdW5jdGlvbiBkb2VzIG5vdCBwZXJmb3JtIGxhenkgZXZhbHVhdGlvbiBvZiBtYXRjaGVzIGFuZCBpbnNlcnRzXG4gKiBuZXcgc3RyaW5ncyBpbiB0aGUgZGljdGlvbmFyeSBvbmx5IGZvciB1bm1hdGNoZWQgc3RyaW5ncyBvciBmb3Igc2hvcnRcbiAqIG1hdGNoZXMuIEl0IGlzIHVzZWQgb25seSBmb3IgdGhlIGZhc3QgY29tcHJlc3Npb24gb3B0aW9ucy5cbiAqL1xuZnVuY3Rpb24gZGVmbGF0ZV9mYXN0KHMsIGZsdXNoKSB7XG4gIHZhciBoYXNoX2hlYWQ7ICAgICAgICAvKiBoZWFkIG9mIHRoZSBoYXNoIGNoYWluICovXG4gIHZhciBiZmx1c2g7ICAgICAgICAgICAvKiBzZXQgaWYgY3VycmVudCBibG9jayBtdXN0IGJlIGZsdXNoZWQgKi9cblxuICBmb3IgKDs7KSB7XG4gICAgLyogTWFrZSBzdXJlIHRoYXQgd2UgYWx3YXlzIGhhdmUgZW5vdWdoIGxvb2thaGVhZCwgZXhjZXB0XG4gICAgICogYXQgdGhlIGVuZCBvZiB0aGUgaW5wdXQgZmlsZS4gV2UgbmVlZCBNQVhfTUFUQ0ggYnl0ZXNcbiAgICAgKiBmb3IgdGhlIG5leHQgbWF0Y2gsIHBsdXMgTUlOX01BVENIIGJ5dGVzIHRvIGluc2VydCB0aGVcbiAgICAgKiBzdHJpbmcgZm9sbG93aW5nIHRoZSBuZXh0IG1hdGNoLlxuICAgICAqL1xuICAgIGlmIChzLmxvb2thaGVhZCA8IE1JTl9MT09LQUhFQUQpIHtcbiAgICAgIGZpbGxfd2luZG93KHMpO1xuICAgICAgaWYgKHMubG9va2FoZWFkIDwgTUlOX0xPT0tBSEVBRCAmJiBmbHVzaCA9PT0gWl9OT19GTFVTSCkge1xuICAgICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgICAgfVxuICAgICAgaWYgKHMubG9va2FoZWFkID09PSAwKSB7XG4gICAgICAgIGJyZWFrOyAvKiBmbHVzaCB0aGUgY3VycmVudCBibG9jayAqL1xuICAgICAgfVxuICAgIH1cblxuICAgIC8qIEluc2VydCB0aGUgc3RyaW5nIHdpbmRvd1tzdHJzdGFydCAuLiBzdHJzdGFydCsyXSBpbiB0aGVcbiAgICAgKiBkaWN0aW9uYXJ5LCBhbmQgc2V0IGhhc2hfaGVhZCB0byB0aGUgaGVhZCBvZiB0aGUgaGFzaCBjaGFpbjpcbiAgICAgKi9cbiAgICBoYXNoX2hlYWQgPSAwLypOSUwqLztcbiAgICBpZiAocy5sb29rYWhlYWQgPj0gTUlOX01BVENIKSB7XG4gICAgICAvKioqIElOU0VSVF9TVFJJTkcocywgcy5zdHJzdGFydCwgaGFzaF9oZWFkKTsgKioqL1xuICAgICAgcy5pbnNfaCA9ICgocy5pbnNfaCA8PCBzLmhhc2hfc2hpZnQpIF4gcy53aW5kb3dbcy5zdHJzdGFydCArIE1JTl9NQVRDSCAtIDFdKSAmIHMuaGFzaF9tYXNrO1xuICAgICAgaGFzaF9oZWFkID0gcy5wcmV2W3Muc3Ryc3RhcnQgJiBzLndfbWFza10gPSBzLmhlYWRbcy5pbnNfaF07XG4gICAgICBzLmhlYWRbcy5pbnNfaF0gPSBzLnN0cnN0YXJ0O1xuICAgICAgLyoqKi9cbiAgICB9XG5cbiAgICAvKiBGaW5kIHRoZSBsb25nZXN0IG1hdGNoLCBkaXNjYXJkaW5nIHRob3NlIDw9IHByZXZfbGVuZ3RoLlxuICAgICAqIEF0IHRoaXMgcG9pbnQgd2UgaGF2ZSBhbHdheXMgbWF0Y2hfbGVuZ3RoIDwgTUlOX01BVENIXG4gICAgICovXG4gICAgaWYgKGhhc2hfaGVhZCAhPT0gMC8qTklMKi8gJiYgKChzLnN0cnN0YXJ0IC0gaGFzaF9oZWFkKSA8PSAocy53X3NpemUgLSBNSU5fTE9PS0FIRUFEKSkpIHtcbiAgICAgIC8qIFRvIHNpbXBsaWZ5IHRoZSBjb2RlLCB3ZSBwcmV2ZW50IG1hdGNoZXMgd2l0aCB0aGUgc3RyaW5nXG4gICAgICAgKiBvZiB3aW5kb3cgaW5kZXggMCAoaW4gcGFydGljdWxhciB3ZSBoYXZlIHRvIGF2b2lkIGEgbWF0Y2hcbiAgICAgICAqIG9mIHRoZSBzdHJpbmcgd2l0aCBpdHNlbGYgYXQgdGhlIHN0YXJ0IG9mIHRoZSBpbnB1dCBmaWxlKS5cbiAgICAgICAqL1xuICAgICAgcy5tYXRjaF9sZW5ndGggPSBsb25nZXN0X21hdGNoKHMsIGhhc2hfaGVhZCk7XG4gICAgICAvKiBsb25nZXN0X21hdGNoKCkgc2V0cyBtYXRjaF9zdGFydCAqL1xuICAgIH1cbiAgICBpZiAocy5tYXRjaF9sZW5ndGggPj0gTUlOX01BVENIKSB7XG4gICAgICAvLyBjaGVja19tYXRjaChzLCBzLnN0cnN0YXJ0LCBzLm1hdGNoX3N0YXJ0LCBzLm1hdGNoX2xlbmd0aCk7IC8vIGZvciBkZWJ1ZyBvbmx5XG5cbiAgICAgIC8qKiogX3RyX3RhbGx5X2Rpc3Qocywgcy5zdHJzdGFydCAtIHMubWF0Y2hfc3RhcnQsXG4gICAgICAgICAgICAgICAgICAgICBzLm1hdGNoX2xlbmd0aCAtIE1JTl9NQVRDSCwgYmZsdXNoKTsgKioqL1xuICAgICAgYmZsdXNoID0gdHJlZXMuX3RyX3RhbGx5KHMsIHMuc3Ryc3RhcnQgLSBzLm1hdGNoX3N0YXJ0LCBzLm1hdGNoX2xlbmd0aCAtIE1JTl9NQVRDSCk7XG5cbiAgICAgIHMubG9va2FoZWFkIC09IHMubWF0Y2hfbGVuZ3RoO1xuXG4gICAgICAvKiBJbnNlcnQgbmV3IHN0cmluZ3MgaW4gdGhlIGhhc2ggdGFibGUgb25seSBpZiB0aGUgbWF0Y2ggbGVuZ3RoXG4gICAgICAgKiBpcyBub3QgdG9vIGxhcmdlLiBUaGlzIHNhdmVzIHRpbWUgYnV0IGRlZ3JhZGVzIGNvbXByZXNzaW9uLlxuICAgICAgICovXG4gICAgICBpZiAocy5tYXRjaF9sZW5ndGggPD0gcy5tYXhfbGF6eV9tYXRjaC8qbWF4X2luc2VydF9sZW5ndGgqLyAmJiBzLmxvb2thaGVhZCA+PSBNSU5fTUFUQ0gpIHtcbiAgICAgICAgcy5tYXRjaF9sZW5ndGgtLTsgLyogc3RyaW5nIGF0IHN0cnN0YXJ0IGFscmVhZHkgaW4gdGFibGUgKi9cbiAgICAgICAgZG8ge1xuICAgICAgICAgIHMuc3Ryc3RhcnQrKztcbiAgICAgICAgICAvKioqIElOU0VSVF9TVFJJTkcocywgcy5zdHJzdGFydCwgaGFzaF9oZWFkKTsgKioqL1xuICAgICAgICAgIHMuaW5zX2ggPSAoKHMuaW5zX2ggPDwgcy5oYXNoX3NoaWZ0KSBeIHMud2luZG93W3Muc3Ryc3RhcnQgKyBNSU5fTUFUQ0ggLSAxXSkgJiBzLmhhc2hfbWFzaztcbiAgICAgICAgICBoYXNoX2hlYWQgPSBzLnByZXZbcy5zdHJzdGFydCAmIHMud19tYXNrXSA9IHMuaGVhZFtzLmluc19oXTtcbiAgICAgICAgICBzLmhlYWRbcy5pbnNfaF0gPSBzLnN0cnN0YXJ0O1xuICAgICAgICAgIC8qKiovXG4gICAgICAgICAgLyogc3Ryc3RhcnQgbmV2ZXIgZXhjZWVkcyBXU0laRS1NQVhfTUFUQ0gsIHNvIHRoZXJlIGFyZVxuICAgICAgICAgICAqIGFsd2F5cyBNSU5fTUFUQ0ggYnl0ZXMgYWhlYWQuXG4gICAgICAgICAgICovXG4gICAgICAgIH0gd2hpbGUgKC0tcy5tYXRjaF9sZW5ndGggIT09IDApO1xuICAgICAgICBzLnN0cnN0YXJ0Kys7XG4gICAgICB9IGVsc2VcbiAgICAgIHtcbiAgICAgICAgcy5zdHJzdGFydCArPSBzLm1hdGNoX2xlbmd0aDtcbiAgICAgICAgcy5tYXRjaF9sZW5ndGggPSAwO1xuICAgICAgICBzLmluc19oID0gcy53aW5kb3dbcy5zdHJzdGFydF07XG4gICAgICAgIC8qIFVQREFURV9IQVNIKHMsIHMuaW5zX2gsIHMud2luZG93W3Muc3Ryc3RhcnQrMV0pOyAqL1xuICAgICAgICBzLmluc19oID0gKChzLmluc19oIDw8IHMuaGFzaF9zaGlmdCkgXiBzLndpbmRvd1tzLnN0cnN0YXJ0ICsgMV0pICYgcy5oYXNoX21hc2s7XG5cbi8vI2lmIE1JTl9NQVRDSCAhPSAzXG4vLyAgICAgICAgICAgICAgICBDYWxsIFVQREFURV9IQVNIKCkgTUlOX01BVENILTMgbW9yZSB0aW1lc1xuLy8jZW5kaWZcbiAgICAgICAgLyogSWYgbG9va2FoZWFkIDwgTUlOX01BVENILCBpbnNfaCBpcyBnYXJiYWdlLCBidXQgaXQgZG9lcyBub3RcbiAgICAgICAgICogbWF0dGVyIHNpbmNlIGl0IHdpbGwgYmUgcmVjb21wdXRlZCBhdCBuZXh0IGRlZmxhdGUgY2FsbC5cbiAgICAgICAgICovXG4gICAgICB9XG4gICAgfSBlbHNlIHtcbiAgICAgIC8qIE5vIG1hdGNoLCBvdXRwdXQgYSBsaXRlcmFsIGJ5dGUgKi9cbiAgICAgIC8vVHJhY2V2digoc3RkZXJyLFwiJWNcIiwgcy53aW5kb3dbcy5zdHJzdGFydF0pKTtcbiAgICAgIC8qKiogX3RyX3RhbGx5X2xpdChzLCBzLndpbmRvd1tzLnN0cnN0YXJ0XSwgYmZsdXNoKTsgKioqL1xuICAgICAgYmZsdXNoID0gdHJlZXMuX3RyX3RhbGx5KHMsIDAsIHMud2luZG93W3Muc3Ryc3RhcnRdKTtcblxuICAgICAgcy5sb29rYWhlYWQtLTtcbiAgICAgIHMuc3Ryc3RhcnQrKztcbiAgICB9XG4gICAgaWYgKGJmbHVzaCkge1xuICAgICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAwKTsgKioqL1xuICAgICAgZmx1c2hfYmxvY2tfb25seShzLCBmYWxzZSk7XG4gICAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgICAgfVxuICAgICAgLyoqKi9cbiAgICB9XG4gIH1cbiAgcy5pbnNlcnQgPSAoKHMuc3Ryc3RhcnQgPCAoTUlOX01BVENILTEpKSA/IHMuc3Ryc3RhcnQgOiBNSU5fTUFUQ0gtMSk7XG4gIGlmIChmbHVzaCA9PT0gWl9GSU5JU0gpIHtcbiAgICAvKioqIEZMVVNIX0JMT0NLKHMsIDEpOyAqKiovXG4gICAgZmx1c2hfYmxvY2tfb25seShzLCB0cnVlKTtcbiAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgcmV0dXJuIEJTX0ZJTklTSF9TVEFSVEVEO1xuICAgIH1cbiAgICAvKioqL1xuICAgIHJldHVybiBCU19GSU5JU0hfRE9ORTtcbiAgfVxuICBpZiAocy5sYXN0X2xpdCkge1xuICAgIC8qKiogRkxVU0hfQkxPQ0socywgMCk7ICoqKi9cbiAgICBmbHVzaF9ibG9ja19vbmx5KHMsIGZhbHNlKTtcbiAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICB9XG4gICAgLyoqKi9cbiAgfVxuICByZXR1cm4gQlNfQkxPQ0tfRE9ORTtcbn1cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBTYW1lIGFzIGFib3ZlLCBidXQgYWNoaWV2ZXMgYmV0dGVyIGNvbXByZXNzaW9uLiBXZSB1c2UgYSBsYXp5XG4gKiBldmFsdWF0aW9uIGZvciBtYXRjaGVzOiBhIG1hdGNoIGlzIGZpbmFsbHkgYWRvcHRlZCBvbmx5IGlmIHRoZXJlIGlzXG4gKiBubyBiZXR0ZXIgbWF0Y2ggYXQgdGhlIG5leHQgd2luZG93IHBvc2l0aW9uLlxuICovXG5mdW5jdGlvbiBkZWZsYXRlX3Nsb3cocywgZmx1c2gpIHtcbiAgdmFyIGhhc2hfaGVhZDsgICAgICAgICAgLyogaGVhZCBvZiBoYXNoIGNoYWluICovXG4gIHZhciBiZmx1c2g7ICAgICAgICAgICAgICAvKiBzZXQgaWYgY3VycmVudCBibG9jayBtdXN0IGJlIGZsdXNoZWQgKi9cblxuICB2YXIgbWF4X2luc2VydDtcblxuICAvKiBQcm9jZXNzIHRoZSBpbnB1dCBibG9jay4gKi9cbiAgZm9yICg7Oykge1xuICAgIC8qIE1ha2Ugc3VyZSB0aGF0IHdlIGFsd2F5cyBoYXZlIGVub3VnaCBsb29rYWhlYWQsIGV4Y2VwdFxuICAgICAqIGF0IHRoZSBlbmQgb2YgdGhlIGlucHV0IGZpbGUuIFdlIG5lZWQgTUFYX01BVENIIGJ5dGVzXG4gICAgICogZm9yIHRoZSBuZXh0IG1hdGNoLCBwbHVzIE1JTl9NQVRDSCBieXRlcyB0byBpbnNlcnQgdGhlXG4gICAgICogc3RyaW5nIGZvbGxvd2luZyB0aGUgbmV4dCBtYXRjaC5cbiAgICAgKi9cbiAgICBpZiAocy5sb29rYWhlYWQgPCBNSU5fTE9PS0FIRUFEKSB7XG4gICAgICBmaWxsX3dpbmRvdyhzKTtcbiAgICAgIGlmIChzLmxvb2thaGVhZCA8IE1JTl9MT09LQUhFQUQgJiYgZmx1c2ggPT09IFpfTk9fRkxVU0gpIHtcbiAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgIH1cbiAgICAgIGlmIChzLmxvb2thaGVhZCA9PT0gMCkgeyBicmVhazsgfSAvKiBmbHVzaCB0aGUgY3VycmVudCBibG9jayAqL1xuICAgIH1cblxuICAgIC8qIEluc2VydCB0aGUgc3RyaW5nIHdpbmRvd1tzdHJzdGFydCAuLiBzdHJzdGFydCsyXSBpbiB0aGVcbiAgICAgKiBkaWN0aW9uYXJ5LCBhbmQgc2V0IGhhc2hfaGVhZCB0byB0aGUgaGVhZCBvZiB0aGUgaGFzaCBjaGFpbjpcbiAgICAgKi9cbiAgICBoYXNoX2hlYWQgPSAwLypOSUwqLztcbiAgICBpZiAocy5sb29rYWhlYWQgPj0gTUlOX01BVENIKSB7XG4gICAgICAvKioqIElOU0VSVF9TVFJJTkcocywgcy5zdHJzdGFydCwgaGFzaF9oZWFkKTsgKioqL1xuICAgICAgcy5pbnNfaCA9ICgocy5pbnNfaCA8PCBzLmhhc2hfc2hpZnQpIF4gcy53aW5kb3dbcy5zdHJzdGFydCArIE1JTl9NQVRDSCAtIDFdKSAmIHMuaGFzaF9tYXNrO1xuICAgICAgaGFzaF9oZWFkID0gcy5wcmV2W3Muc3Ryc3RhcnQgJiBzLndfbWFza10gPSBzLmhlYWRbcy5pbnNfaF07XG4gICAgICBzLmhlYWRbcy5pbnNfaF0gPSBzLnN0cnN0YXJ0O1xuICAgICAgLyoqKi9cbiAgICB9XG5cbiAgICAvKiBGaW5kIHRoZSBsb25nZXN0IG1hdGNoLCBkaXNjYXJkaW5nIHRob3NlIDw9IHByZXZfbGVuZ3RoLlxuICAgICAqL1xuICAgIHMucHJldl9sZW5ndGggPSBzLm1hdGNoX2xlbmd0aDtcbiAgICBzLnByZXZfbWF0Y2ggPSBzLm1hdGNoX3N0YXJ0O1xuICAgIHMubWF0Y2hfbGVuZ3RoID0gTUlOX01BVENILTE7XG5cbiAgICBpZiAoaGFzaF9oZWFkICE9PSAwLypOSUwqLyAmJiBzLnByZXZfbGVuZ3RoIDwgcy5tYXhfbGF6eV9tYXRjaCAmJlxuICAgICAgICBzLnN0cnN0YXJ0IC0gaGFzaF9oZWFkIDw9IChzLndfc2l6ZS1NSU5fTE9PS0FIRUFEKS8qTUFYX0RJU1QocykqLykge1xuICAgICAgLyogVG8gc2ltcGxpZnkgdGhlIGNvZGUsIHdlIHByZXZlbnQgbWF0Y2hlcyB3aXRoIHRoZSBzdHJpbmdcbiAgICAgICAqIG9mIHdpbmRvdyBpbmRleCAwIChpbiBwYXJ0aWN1bGFyIHdlIGhhdmUgdG8gYXZvaWQgYSBtYXRjaFxuICAgICAgICogb2YgdGhlIHN0cmluZyB3aXRoIGl0c2VsZiBhdCB0aGUgc3RhcnQgb2YgdGhlIGlucHV0IGZpbGUpLlxuICAgICAgICovXG4gICAgICBzLm1hdGNoX2xlbmd0aCA9IGxvbmdlc3RfbWF0Y2gocywgaGFzaF9oZWFkKTtcbiAgICAgIC8qIGxvbmdlc3RfbWF0Y2goKSBzZXRzIG1hdGNoX3N0YXJ0ICovXG5cbiAgICAgIGlmIChzLm1hdGNoX2xlbmd0aCA8PSA1ICYmXG4gICAgICAgICAocy5zdHJhdGVneSA9PT0gWl9GSUxURVJFRCB8fCAocy5tYXRjaF9sZW5ndGggPT09IE1JTl9NQVRDSCAmJiBzLnN0cnN0YXJ0IC0gcy5tYXRjaF9zdGFydCA+IDQwOTYvKlRPT19GQVIqLykpKSB7XG5cbiAgICAgICAgLyogSWYgcHJldl9tYXRjaCBpcyBhbHNvIE1JTl9NQVRDSCwgbWF0Y2hfc3RhcnQgaXMgZ2FyYmFnZVxuICAgICAgICAgKiBidXQgd2Ugd2lsbCBpZ25vcmUgdGhlIGN1cnJlbnQgbWF0Y2ggYW55d2F5LlxuICAgICAgICAgKi9cbiAgICAgICAgcy5tYXRjaF9sZW5ndGggPSBNSU5fTUFUQ0gtMTtcbiAgICAgIH1cbiAgICB9XG4gICAgLyogSWYgdGhlcmUgd2FzIGEgbWF0Y2ggYXQgdGhlIHByZXZpb3VzIHN0ZXAgYW5kIHRoZSBjdXJyZW50XG4gICAgICogbWF0Y2ggaXMgbm90IGJldHRlciwgb3V0cHV0IHRoZSBwcmV2aW91cyBtYXRjaDpcbiAgICAgKi9cbiAgICBpZiAocy5wcmV2X2xlbmd0aCA+PSBNSU5fTUFUQ0ggJiYgcy5tYXRjaF9sZW5ndGggPD0gcy5wcmV2X2xlbmd0aCkge1xuICAgICAgbWF4X2luc2VydCA9IHMuc3Ryc3RhcnQgKyBzLmxvb2thaGVhZCAtIE1JTl9NQVRDSDtcbiAgICAgIC8qIERvIG5vdCBpbnNlcnQgc3RyaW5ncyBpbiBoYXNoIHRhYmxlIGJleW9uZCB0aGlzLiAqL1xuXG4gICAgICAvL2NoZWNrX21hdGNoKHMsIHMuc3Ryc3RhcnQtMSwgcy5wcmV2X21hdGNoLCBzLnByZXZfbGVuZ3RoKTtcblxuICAgICAgLyoqKl90cl90YWxseV9kaXN0KHMsIHMuc3Ryc3RhcnQgLSAxIC0gcy5wcmV2X21hdGNoLFxuICAgICAgICAgICAgICAgICAgICAgcy5wcmV2X2xlbmd0aCAtIE1JTl9NQVRDSCwgYmZsdXNoKTsqKiovXG4gICAgICBiZmx1c2ggPSB0cmVlcy5fdHJfdGFsbHkocywgcy5zdHJzdGFydCAtIDEtIHMucHJldl9tYXRjaCwgcy5wcmV2X2xlbmd0aCAtIE1JTl9NQVRDSCk7XG4gICAgICAvKiBJbnNlcnQgaW4gaGFzaCB0YWJsZSBhbGwgc3RyaW5ncyB1cCB0byB0aGUgZW5kIG9mIHRoZSBtYXRjaC5cbiAgICAgICAqIHN0cnN0YXJ0LTEgYW5kIHN0cnN0YXJ0IGFyZSBhbHJlYWR5IGluc2VydGVkLiBJZiB0aGVyZSBpcyBub3RcbiAgICAgICAqIGVub3VnaCBsb29rYWhlYWQsIHRoZSBsYXN0IHR3byBzdHJpbmdzIGFyZSBub3QgaW5zZXJ0ZWQgaW5cbiAgICAgICAqIHRoZSBoYXNoIHRhYmxlLlxuICAgICAgICovXG4gICAgICBzLmxvb2thaGVhZCAtPSBzLnByZXZfbGVuZ3RoLTE7XG4gICAgICBzLnByZXZfbGVuZ3RoIC09IDI7XG4gICAgICBkbyB7XG4gICAgICAgIGlmICgrK3Muc3Ryc3RhcnQgPD0gbWF4X2luc2VydCkge1xuICAgICAgICAgIC8qKiogSU5TRVJUX1NUUklORyhzLCBzLnN0cnN0YXJ0LCBoYXNoX2hlYWQpOyAqKiovXG4gICAgICAgICAgcy5pbnNfaCA9ICgocy5pbnNfaCA8PCBzLmhhc2hfc2hpZnQpIF4gcy53aW5kb3dbcy5zdHJzdGFydCArIE1JTl9NQVRDSCAtIDFdKSAmIHMuaGFzaF9tYXNrO1xuICAgICAgICAgIGhhc2hfaGVhZCA9IHMucHJldltzLnN0cnN0YXJ0ICYgcy53X21hc2tdID0gcy5oZWFkW3MuaW5zX2hdO1xuICAgICAgICAgIHMuaGVhZFtzLmluc19oXSA9IHMuc3Ryc3RhcnQ7XG4gICAgICAgICAgLyoqKi9cbiAgICAgICAgfVxuICAgICAgfSB3aGlsZSAoLS1zLnByZXZfbGVuZ3RoICE9PSAwKTtcbiAgICAgIHMubWF0Y2hfYXZhaWxhYmxlID0gMDtcbiAgICAgIHMubWF0Y2hfbGVuZ3RoID0gTUlOX01BVENILTE7XG4gICAgICBzLnN0cnN0YXJ0Kys7XG5cbiAgICAgIGlmIChiZmx1c2gpIHtcbiAgICAgICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAwKTsgKioqL1xuICAgICAgICBmbHVzaF9ibG9ja19vbmx5KHMsIGZhbHNlKTtcbiAgICAgICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgICAgICB9XG4gICAgICAgIC8qKiovXG4gICAgICB9XG5cbiAgICB9IGVsc2UgaWYgKHMubWF0Y2hfYXZhaWxhYmxlKSB7XG4gICAgICAvKiBJZiB0aGVyZSB3YXMgbm8gbWF0Y2ggYXQgdGhlIHByZXZpb3VzIHBvc2l0aW9uLCBvdXRwdXQgYVxuICAgICAgICogc2luZ2xlIGxpdGVyYWwuIElmIHRoZXJlIHdhcyBhIG1hdGNoIGJ1dCB0aGUgY3VycmVudCBtYXRjaFxuICAgICAgICogaXMgbG9uZ2VyLCB0cnVuY2F0ZSB0aGUgcHJldmlvdXMgbWF0Y2ggdG8gYSBzaW5nbGUgbGl0ZXJhbC5cbiAgICAgICAqL1xuICAgICAgLy9UcmFjZXZ2KChzdGRlcnIsXCIlY1wiLCBzLT53aW5kb3dbcy0+c3Ryc3RhcnQtMV0pKTtcbiAgICAgIC8qKiogX3RyX3RhbGx5X2xpdChzLCBzLndpbmRvd1tzLnN0cnN0YXJ0LTFdLCBiZmx1c2gpOyAqKiovXG4gICAgICBiZmx1c2ggPSB0cmVlcy5fdHJfdGFsbHkocywgMCwgcy53aW5kb3dbcy5zdHJzdGFydC0xXSk7XG5cbiAgICAgIGlmIChiZmx1c2gpIHtcbiAgICAgICAgLyoqKiBGTFVTSF9CTE9DS19PTkxZKHMsIDApICoqKi9cbiAgICAgICAgZmx1c2hfYmxvY2tfb25seShzLCBmYWxzZSk7XG4gICAgICAgIC8qKiovXG4gICAgICB9XG4gICAgICBzLnN0cnN0YXJ0Kys7XG4gICAgICBzLmxvb2thaGVhZC0tO1xuICAgICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgLyogVGhlcmUgaXMgbm8gcHJldmlvdXMgbWF0Y2ggdG8gY29tcGFyZSB3aXRoLCB3YWl0IGZvclxuICAgICAgICogdGhlIG5leHQgc3RlcCB0byBkZWNpZGUuXG4gICAgICAgKi9cbiAgICAgIHMubWF0Y2hfYXZhaWxhYmxlID0gMTtcbiAgICAgIHMuc3Ryc3RhcnQrKztcbiAgICAgIHMubG9va2FoZWFkLS07XG4gICAgfVxuICB9XG4gIC8vQXNzZXJ0IChmbHVzaCAhPSBaX05PX0ZMVVNILCBcIm5vIGZsdXNoP1wiKTtcbiAgaWYgKHMubWF0Y2hfYXZhaWxhYmxlKSB7XG4gICAgLy9UcmFjZXZ2KChzdGRlcnIsXCIlY1wiLCBzLT53aW5kb3dbcy0+c3Ryc3RhcnQtMV0pKTtcbiAgICAvKioqIF90cl90YWxseV9saXQocywgcy53aW5kb3dbcy5zdHJzdGFydC0xXSwgYmZsdXNoKTsgKioqL1xuICAgIGJmbHVzaCA9IHRyZWVzLl90cl90YWxseShzLCAwLCBzLndpbmRvd1tzLnN0cnN0YXJ0LTFdKTtcblxuICAgIHMubWF0Y2hfYXZhaWxhYmxlID0gMDtcbiAgfVxuICBzLmluc2VydCA9IHMuc3Ryc3RhcnQgPCBNSU5fTUFUQ0gtMSA/IHMuc3Ryc3RhcnQgOiBNSU5fTUFUQ0gtMTtcbiAgaWYgKGZsdXNoID09PSBaX0ZJTklTSCkge1xuICAgIC8qKiogRkxVU0hfQkxPQ0socywgMSk7ICoqKi9cbiAgICBmbHVzaF9ibG9ja19vbmx5KHMsIHRydWUpO1xuICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICByZXR1cm4gQlNfRklOSVNIX1NUQVJURUQ7XG4gICAgfVxuICAgIC8qKiovXG4gICAgcmV0dXJuIEJTX0ZJTklTSF9ET05FO1xuICB9XG4gIGlmIChzLmxhc3RfbGl0KSB7XG4gICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAwKTsgKioqL1xuICAgIGZsdXNoX2Jsb2NrX29ubHkocywgZmFsc2UpO1xuICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgIH1cbiAgICAvKioqL1xuICB9XG5cbiAgcmV0dXJuIEJTX0JMT0NLX0RPTkU7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBGb3IgWl9STEUsIHNpbXBseSBsb29rIGZvciBydW5zIG9mIGJ5dGVzLCBnZW5lcmF0ZSBtYXRjaGVzIG9ubHkgb2YgZGlzdGFuY2VcbiAqIG9uZS4gIERvIG5vdCBtYWludGFpbiBhIGhhc2ggdGFibGUuICAoSXQgd2lsbCBiZSByZWdlbmVyYXRlZCBpZiB0aGlzIHJ1biBvZlxuICogZGVmbGF0ZSBzd2l0Y2hlcyBhd2F5IGZyb20gWl9STEUuKVxuICovXG5mdW5jdGlvbiBkZWZsYXRlX3JsZShzLCBmbHVzaCkge1xuICB2YXIgYmZsdXNoOyAgICAgICAgICAgIC8qIHNldCBpZiBjdXJyZW50IGJsb2NrIG11c3QgYmUgZmx1c2hlZCAqL1xuICB2YXIgcHJldjsgICAgICAgICAgICAgIC8qIGJ5dGUgYXQgZGlzdGFuY2Ugb25lIHRvIG1hdGNoICovXG4gIHZhciBzY2FuLCBzdHJlbmQ7ICAgICAgLyogc2NhbiBnb2VzIHVwIHRvIHN0cmVuZCBmb3IgbGVuZ3RoIG9mIHJ1biAqL1xuXG4gIHZhciBfd2luID0gcy53aW5kb3c7XG5cbiAgZm9yICg7Oykge1xuICAgIC8qIE1ha2Ugc3VyZSB0aGF0IHdlIGFsd2F5cyBoYXZlIGVub3VnaCBsb29rYWhlYWQsIGV4Y2VwdFxuICAgICAqIGF0IHRoZSBlbmQgb2YgdGhlIGlucHV0IGZpbGUuIFdlIG5lZWQgTUFYX01BVENIIGJ5dGVzXG4gICAgICogZm9yIHRoZSBsb25nZXN0IHJ1biwgcGx1cyBvbmUgZm9yIHRoZSB1bnJvbGxlZCBsb29wLlxuICAgICAqL1xuICAgIGlmIChzLmxvb2thaGVhZCA8PSBNQVhfTUFUQ0gpIHtcbiAgICAgIGZpbGxfd2luZG93KHMpO1xuICAgICAgaWYgKHMubG9va2FoZWFkIDw9IE1BWF9NQVRDSCAmJiBmbHVzaCA9PT0gWl9OT19GTFVTSCkge1xuICAgICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgICAgfVxuICAgICAgaWYgKHMubG9va2FoZWFkID09PSAwKSB7IGJyZWFrOyB9IC8qIGZsdXNoIHRoZSBjdXJyZW50IGJsb2NrICovXG4gICAgfVxuXG4gICAgLyogU2VlIGhvdyBtYW55IHRpbWVzIHRoZSBwcmV2aW91cyBieXRlIHJlcGVhdHMgKi9cbiAgICBzLm1hdGNoX2xlbmd0aCA9IDA7XG4gICAgaWYgKHMubG9va2FoZWFkID49IE1JTl9NQVRDSCAmJiBzLnN0cnN0YXJ0ID4gMCkge1xuICAgICAgc2NhbiA9IHMuc3Ryc3RhcnQgLSAxO1xuICAgICAgcHJldiA9IF93aW5bc2Nhbl07XG4gICAgICBpZiAocHJldiA9PT0gX3dpblsrK3NjYW5dICYmIHByZXYgPT09IF93aW5bKytzY2FuXSAmJiBwcmV2ID09PSBfd2luWysrc2Nhbl0pIHtcbiAgICAgICAgc3RyZW5kID0gcy5zdHJzdGFydCArIE1BWF9NQVRDSDtcbiAgICAgICAgZG8ge1xuICAgICAgICAgIC8qanNoaW50IG5vZW1wdHk6ZmFsc2UqL1xuICAgICAgICB9IHdoaWxlIChwcmV2ID09PSBfd2luWysrc2Nhbl0gJiYgcHJldiA9PT0gX3dpblsrK3NjYW5dICYmXG4gICAgICAgICAgICAgICAgIHByZXYgPT09IF93aW5bKytzY2FuXSAmJiBwcmV2ID09PSBfd2luWysrc2Nhbl0gJiZcbiAgICAgICAgICAgICAgICAgcHJldiA9PT0gX3dpblsrK3NjYW5dICYmIHByZXYgPT09IF93aW5bKytzY2FuXSAmJlxuICAgICAgICAgICAgICAgICBwcmV2ID09PSBfd2luWysrc2Nhbl0gJiYgcHJldiA9PT0gX3dpblsrK3NjYW5dICYmXG4gICAgICAgICAgICAgICAgIHNjYW4gPCBzdHJlbmQpO1xuICAgICAgICBzLm1hdGNoX2xlbmd0aCA9IE1BWF9NQVRDSCAtIChzdHJlbmQgLSBzY2FuKTtcbiAgICAgICAgaWYgKHMubWF0Y2hfbGVuZ3RoID4gcy5sb29rYWhlYWQpIHtcbiAgICAgICAgICBzLm1hdGNoX2xlbmd0aCA9IHMubG9va2FoZWFkO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvL0Fzc2VydChzY2FuIDw9IHMtPndpbmRvdysodUludCkocy0+d2luZG93X3NpemUtMSksIFwid2lsZCBzY2FuXCIpO1xuICAgIH1cblxuICAgIC8qIEVtaXQgbWF0Y2ggaWYgaGF2ZSBydW4gb2YgTUlOX01BVENIIG9yIGxvbmdlciwgZWxzZSBlbWl0IGxpdGVyYWwgKi9cbiAgICBpZiAocy5tYXRjaF9sZW5ndGggPj0gTUlOX01BVENIKSB7XG4gICAgICAvL2NoZWNrX21hdGNoKHMsIHMuc3Ryc3RhcnQsIHMuc3Ryc3RhcnQgLSAxLCBzLm1hdGNoX2xlbmd0aCk7XG5cbiAgICAgIC8qKiogX3RyX3RhbGx5X2Rpc3QocywgMSwgcy5tYXRjaF9sZW5ndGggLSBNSU5fTUFUQ0gsIGJmbHVzaCk7ICoqKi9cbiAgICAgIGJmbHVzaCA9IHRyZWVzLl90cl90YWxseShzLCAxLCBzLm1hdGNoX2xlbmd0aCAtIE1JTl9NQVRDSCk7XG5cbiAgICAgIHMubG9va2FoZWFkIC09IHMubWF0Y2hfbGVuZ3RoO1xuICAgICAgcy5zdHJzdGFydCArPSBzLm1hdGNoX2xlbmd0aDtcbiAgICAgIHMubWF0Y2hfbGVuZ3RoID0gMDtcbiAgICB9IGVsc2Uge1xuICAgICAgLyogTm8gbWF0Y2gsIG91dHB1dCBhIGxpdGVyYWwgYnl0ZSAqL1xuICAgICAgLy9UcmFjZXZ2KChzdGRlcnIsXCIlY1wiLCBzLT53aW5kb3dbcy0+c3Ryc3RhcnRdKSk7XG4gICAgICAvKioqIF90cl90YWxseV9saXQocywgcy53aW5kb3dbcy5zdHJzdGFydF0sIGJmbHVzaCk7ICoqKi9cbiAgICAgIGJmbHVzaCA9IHRyZWVzLl90cl90YWxseShzLCAwLCBzLndpbmRvd1tzLnN0cnN0YXJ0XSk7XG5cbiAgICAgIHMubG9va2FoZWFkLS07XG4gICAgICBzLnN0cnN0YXJ0Kys7XG4gICAgfVxuICAgIGlmIChiZmx1c2gpIHtcbiAgICAgIC8qKiogRkxVU0hfQkxPQ0socywgMCk7ICoqKi9cbiAgICAgIGZsdXNoX2Jsb2NrX29ubHkocywgZmFsc2UpO1xuICAgICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgICAgcmV0dXJuIEJTX05FRURfTU9SRTtcbiAgICAgIH1cbiAgICAgIC8qKiovXG4gICAgfVxuICB9XG4gIHMuaW5zZXJ0ID0gMDtcbiAgaWYgKGZsdXNoID09PSBaX0ZJTklTSCkge1xuICAgIC8qKiogRkxVU0hfQkxPQ0socywgMSk7ICoqKi9cbiAgICBmbHVzaF9ibG9ja19vbmx5KHMsIHRydWUpO1xuICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICByZXR1cm4gQlNfRklOSVNIX1NUQVJURUQ7XG4gICAgfVxuICAgIC8qKiovXG4gICAgcmV0dXJuIEJTX0ZJTklTSF9ET05FO1xuICB9XG4gIGlmIChzLmxhc3RfbGl0KSB7XG4gICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAwKTsgKioqL1xuICAgIGZsdXNoX2Jsb2NrX29ubHkocywgZmFsc2UpO1xuICAgIGlmIChzLnN0cm0uYXZhaWxfb3V0ID09PSAwKSB7XG4gICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgIH1cbiAgICAvKioqL1xuICB9XG4gIHJldHVybiBCU19CTE9DS19ET05FO1xufVxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEZvciBaX0hVRkZNQU5fT05MWSwgZG8gbm90IGxvb2sgZm9yIG1hdGNoZXMuICBEbyBub3QgbWFpbnRhaW4gYSBoYXNoIHRhYmxlLlxuICogKEl0IHdpbGwgYmUgcmVnZW5lcmF0ZWQgaWYgdGhpcyBydW4gb2YgZGVmbGF0ZSBzd2l0Y2hlcyBhd2F5IGZyb20gSHVmZm1hbi4pXG4gKi9cbmZ1bmN0aW9uIGRlZmxhdGVfaHVmZihzLCBmbHVzaCkge1xuICB2YXIgYmZsdXNoOyAgICAgICAgICAgICAvKiBzZXQgaWYgY3VycmVudCBibG9jayBtdXN0IGJlIGZsdXNoZWQgKi9cblxuICBmb3IgKDs7KSB7XG4gICAgLyogTWFrZSBzdXJlIHRoYXQgd2UgaGF2ZSBhIGxpdGVyYWwgdG8gd3JpdGUuICovXG4gICAgaWYgKHMubG9va2FoZWFkID09PSAwKSB7XG4gICAgICBmaWxsX3dpbmRvdyhzKTtcbiAgICAgIGlmIChzLmxvb2thaGVhZCA9PT0gMCkge1xuICAgICAgICBpZiAoZmx1c2ggPT09IFpfTk9fRkxVU0gpIHtcbiAgICAgICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgICAgICB9XG4gICAgICAgIGJyZWFrOyAgICAgIC8qIGZsdXNoIHRoZSBjdXJyZW50IGJsb2NrICovXG4gICAgICB9XG4gICAgfVxuXG4gICAgLyogT3V0cHV0IGEgbGl0ZXJhbCBieXRlICovXG4gICAgcy5tYXRjaF9sZW5ndGggPSAwO1xuICAgIC8vVHJhY2V2digoc3RkZXJyLFwiJWNcIiwgcy0+d2luZG93W3MtPnN0cnN0YXJ0XSkpO1xuICAgIC8qKiogX3RyX3RhbGx5X2xpdChzLCBzLndpbmRvd1tzLnN0cnN0YXJ0XSwgYmZsdXNoKTsgKioqL1xuICAgIGJmbHVzaCA9IHRyZWVzLl90cl90YWxseShzLCAwLCBzLndpbmRvd1tzLnN0cnN0YXJ0XSk7XG4gICAgcy5sb29rYWhlYWQtLTtcbiAgICBzLnN0cnN0YXJ0Kys7XG4gICAgaWYgKGJmbHVzaCkge1xuICAgICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAwKTsgKioqL1xuICAgICAgZmx1c2hfYmxvY2tfb25seShzLCBmYWxzZSk7XG4gICAgICBpZiAocy5zdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgICByZXR1cm4gQlNfTkVFRF9NT1JFO1xuICAgICAgfVxuICAgICAgLyoqKi9cbiAgICB9XG4gIH1cbiAgcy5pbnNlcnQgPSAwO1xuICBpZiAoZmx1c2ggPT09IFpfRklOSVNIKSB7XG4gICAgLyoqKiBGTFVTSF9CTE9DSyhzLCAxKTsgKioqL1xuICAgIGZsdXNoX2Jsb2NrX29ubHkocywgdHJ1ZSk7XG4gICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgIHJldHVybiBCU19GSU5JU0hfU1RBUlRFRDtcbiAgICB9XG4gICAgLyoqKi9cbiAgICByZXR1cm4gQlNfRklOSVNIX0RPTkU7XG4gIH1cbiAgaWYgKHMubGFzdF9saXQpIHtcbiAgICAvKioqIEZMVVNIX0JMT0NLKHMsIDApOyAqKiovXG4gICAgZmx1c2hfYmxvY2tfb25seShzLCBmYWxzZSk7XG4gICAgaWYgKHMuc3RybS5hdmFpbF9vdXQgPT09IDApIHtcbiAgICAgIHJldHVybiBCU19ORUVEX01PUkU7XG4gICAgfVxuICAgIC8qKiovXG4gIH1cbiAgcmV0dXJuIEJTX0JMT0NLX0RPTkU7XG59XG5cbi8qIFZhbHVlcyBmb3IgbWF4X2xhenlfbWF0Y2gsIGdvb2RfbWF0Y2ggYW5kIG1heF9jaGFpbl9sZW5ndGgsIGRlcGVuZGluZyBvblxuICogdGhlIGRlc2lyZWQgcGFjayBsZXZlbCAoMC4uOSkuIFRoZSB2YWx1ZXMgZ2l2ZW4gYmVsb3cgaGF2ZSBiZWVuIHR1bmVkIHRvXG4gKiBleGNsdWRlIHdvcnN0IGNhc2UgcGVyZm9ybWFuY2UgZm9yIHBhdGhvbG9naWNhbCBmaWxlcy4gQmV0dGVyIHZhbHVlcyBtYXkgYmVcbiAqIGZvdW5kIGZvciBzcGVjaWZpYyBmaWxlcy5cbiAqL1xudmFyIENvbmZpZyA9IGZ1bmN0aW9uIChnb29kX2xlbmd0aCwgbWF4X2xhenksIG5pY2VfbGVuZ3RoLCBtYXhfY2hhaW4sIGZ1bmMpIHtcbiAgdGhpcy5nb29kX2xlbmd0aCA9IGdvb2RfbGVuZ3RoO1xuICB0aGlzLm1heF9sYXp5ID0gbWF4X2xhenk7XG4gIHRoaXMubmljZV9sZW5ndGggPSBuaWNlX2xlbmd0aDtcbiAgdGhpcy5tYXhfY2hhaW4gPSBtYXhfY2hhaW47XG4gIHRoaXMuZnVuYyA9IGZ1bmM7XG59O1xuXG52YXIgY29uZmlndXJhdGlvbl90YWJsZTtcblxuY29uZmlndXJhdGlvbl90YWJsZSA9IFtcbiAgLyogICAgICBnb29kIGxhenkgbmljZSBjaGFpbiAqL1xuICBuZXcgQ29uZmlnKDAsIDAsIDAsIDAsIGRlZmxhdGVfc3RvcmVkKSwgICAgICAgICAgLyogMCBzdG9yZSBvbmx5ICovXG4gIG5ldyBDb25maWcoNCwgNCwgOCwgNCwgZGVmbGF0ZV9mYXN0KSwgICAgICAgICAgICAvKiAxIG1heCBzcGVlZCwgbm8gbGF6eSBtYXRjaGVzICovXG4gIG5ldyBDb25maWcoNCwgNSwgMTYsIDgsIGRlZmxhdGVfZmFzdCksICAgICAgICAgICAvKiAyICovXG4gIG5ldyBDb25maWcoNCwgNiwgMzIsIDMyLCBkZWZsYXRlX2Zhc3QpLCAgICAgICAgICAvKiAzICovXG5cbiAgbmV3IENvbmZpZyg0LCA0LCAxNiwgMTYsIGRlZmxhdGVfc2xvdyksICAgICAgICAgIC8qIDQgbGF6eSBtYXRjaGVzICovXG4gIG5ldyBDb25maWcoOCwgMTYsIDMyLCAzMiwgZGVmbGF0ZV9zbG93KSwgICAgICAgICAvKiA1ICovXG4gIG5ldyBDb25maWcoOCwgMTYsIDEyOCwgMTI4LCBkZWZsYXRlX3Nsb3cpLCAgICAgICAvKiA2ICovXG4gIG5ldyBDb25maWcoOCwgMzIsIDEyOCwgMjU2LCBkZWZsYXRlX3Nsb3cpLCAgICAgICAvKiA3ICovXG4gIG5ldyBDb25maWcoMzIsIDEyOCwgMjU4LCAxMDI0LCBkZWZsYXRlX3Nsb3cpLCAgICAvKiA4ICovXG4gIG5ldyBDb25maWcoMzIsIDI1OCwgMjU4LCA0MDk2LCBkZWZsYXRlX3Nsb3cpICAgICAvKiA5IG1heCBjb21wcmVzc2lvbiAqL1xuXTtcblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEluaXRpYWxpemUgdGhlIFwibG9uZ2VzdCBtYXRjaFwiIHJvdXRpbmVzIGZvciBhIG5ldyB6bGliIHN0cmVhbVxuICovXG5mdW5jdGlvbiBsbV9pbml0KHMpIHtcbiAgcy53aW5kb3dfc2l6ZSA9IDIgKiBzLndfc2l6ZTtcblxuICAvKioqIENMRUFSX0hBU0gocyk7ICoqKi9cbiAgemVybyhzLmhlYWQpOyAvLyBGaWxsIHdpdGggTklMICg9IDApO1xuXG4gIC8qIFNldCB0aGUgZGVmYXVsdCBjb25maWd1cmF0aW9uIHBhcmFtZXRlcnM6XG4gICAqL1xuICBzLm1heF9sYXp5X21hdGNoID0gY29uZmlndXJhdGlvbl90YWJsZVtzLmxldmVsXS5tYXhfbGF6eTtcbiAgcy5nb29kX21hdGNoID0gY29uZmlndXJhdGlvbl90YWJsZVtzLmxldmVsXS5nb29kX2xlbmd0aDtcbiAgcy5uaWNlX21hdGNoID0gY29uZmlndXJhdGlvbl90YWJsZVtzLmxldmVsXS5uaWNlX2xlbmd0aDtcbiAgcy5tYXhfY2hhaW5fbGVuZ3RoID0gY29uZmlndXJhdGlvbl90YWJsZVtzLmxldmVsXS5tYXhfY2hhaW47XG5cbiAgcy5zdHJzdGFydCA9IDA7XG4gIHMuYmxvY2tfc3RhcnQgPSAwO1xuICBzLmxvb2thaGVhZCA9IDA7XG4gIHMuaW5zZXJ0ID0gMDtcbiAgcy5tYXRjaF9sZW5ndGggPSBzLnByZXZfbGVuZ3RoID0gTUlOX01BVENIIC0gMTtcbiAgcy5tYXRjaF9hdmFpbGFibGUgPSAwO1xuICBzLmluc19oID0gMDtcbn1cblxuXG5mdW5jdGlvbiBEZWZsYXRlU3RhdGUoKSB7XG4gIHRoaXMuc3RybSA9IG51bGw7ICAgICAgICAgICAgLyogcG9pbnRlciBiYWNrIHRvIHRoaXMgemxpYiBzdHJlYW0gKi9cbiAgdGhpcy5zdGF0dXMgPSAwOyAgICAgICAgICAgIC8qIGFzIHRoZSBuYW1lIGltcGxpZXMgKi9cbiAgdGhpcy5wZW5kaW5nX2J1ZiA9IG51bGw7ICAgICAgLyogb3V0cHV0IHN0aWxsIHBlbmRpbmcgKi9cbiAgdGhpcy5wZW5kaW5nX2J1Zl9zaXplID0gMDsgIC8qIHNpemUgb2YgcGVuZGluZ19idWYgKi9cbiAgdGhpcy5wZW5kaW5nX291dCA9IDA7ICAgICAgIC8qIG5leHQgcGVuZGluZyBieXRlIHRvIG91dHB1dCB0byB0aGUgc3RyZWFtICovXG4gIHRoaXMucGVuZGluZyA9IDA7ICAgICAgICAgICAvKiBuYiBvZiBieXRlcyBpbiB0aGUgcGVuZGluZyBidWZmZXIgKi9cbiAgdGhpcy53cmFwID0gMDsgICAgICAgICAgICAgIC8qIGJpdCAwIHRydWUgZm9yIHpsaWIsIGJpdCAxIHRydWUgZm9yIGd6aXAgKi9cbiAgdGhpcy5nemhlYWQgPSBudWxsOyAgICAgICAgIC8qIGd6aXAgaGVhZGVyIGluZm9ybWF0aW9uIHRvIHdyaXRlICovXG4gIHRoaXMuZ3ppbmRleCA9IDA7ICAgICAgICAgICAvKiB3aGVyZSBpbiBleHRyYSwgbmFtZSwgb3IgY29tbWVudCAqL1xuICB0aGlzLm1ldGhvZCA9IFpfREVGTEFURUQ7IC8qIGNhbiBvbmx5IGJlIERFRkxBVEVEICovXG4gIHRoaXMubGFzdF9mbHVzaCA9IC0xOyAgIC8qIHZhbHVlIG9mIGZsdXNoIHBhcmFtIGZvciBwcmV2aW91cyBkZWZsYXRlIGNhbGwgKi9cblxuICB0aGlzLndfc2l6ZSA9IDA7ICAvKiBMWjc3IHdpbmRvdyBzaXplICgzMksgYnkgZGVmYXVsdCkgKi9cbiAgdGhpcy53X2JpdHMgPSAwOyAgLyogbG9nMih3X3NpemUpICAoOC4uMTYpICovXG4gIHRoaXMud19tYXNrID0gMDsgIC8qIHdfc2l6ZSAtIDEgKi9cblxuICB0aGlzLndpbmRvdyA9IG51bGw7XG4gIC8qIFNsaWRpbmcgd2luZG93LiBJbnB1dCBieXRlcyBhcmUgcmVhZCBpbnRvIHRoZSBzZWNvbmQgaGFsZiBvZiB0aGUgd2luZG93LFxuICAgKiBhbmQgbW92ZSB0byB0aGUgZmlyc3QgaGFsZiBsYXRlciB0byBrZWVwIGEgZGljdGlvbmFyeSBvZiBhdCBsZWFzdCB3U2l6ZVxuICAgKiBieXRlcy4gV2l0aCB0aGlzIG9yZ2FuaXphdGlvbiwgbWF0Y2hlcyBhcmUgbGltaXRlZCB0byBhIGRpc3RhbmNlIG9mXG4gICAqIHdTaXplLU1BWF9NQVRDSCBieXRlcywgYnV0IHRoaXMgZW5zdXJlcyB0aGF0IElPIGlzIGFsd2F5c1xuICAgKiBwZXJmb3JtZWQgd2l0aCBhIGxlbmd0aCBtdWx0aXBsZSBvZiB0aGUgYmxvY2sgc2l6ZS5cbiAgICovXG5cbiAgdGhpcy53aW5kb3dfc2l6ZSA9IDA7XG4gIC8qIEFjdHVhbCBzaXplIG9mIHdpbmRvdzogMip3U2l6ZSwgZXhjZXB0IHdoZW4gdGhlIHVzZXIgaW5wdXQgYnVmZmVyXG4gICAqIGlzIGRpcmVjdGx5IHVzZWQgYXMgc2xpZGluZyB3aW5kb3cuXG4gICAqL1xuXG4gIHRoaXMucHJldiA9IG51bGw7XG4gIC8qIExpbmsgdG8gb2xkZXIgc3RyaW5nIHdpdGggc2FtZSBoYXNoIGluZGV4LiBUbyBsaW1pdCB0aGUgc2l6ZSBvZiB0aGlzXG4gICAqIGFycmF5IHRvIDY0SywgdGhpcyBsaW5rIGlzIG1haW50YWluZWQgb25seSBmb3IgdGhlIGxhc3QgMzJLIHN0cmluZ3MuXG4gICAqIEFuIGluZGV4IGluIHRoaXMgYXJyYXkgaXMgdGh1cyBhIHdpbmRvdyBpbmRleCBtb2R1bG8gMzJLLlxuICAgKi9cblxuICB0aGlzLmhlYWQgPSBudWxsOyAgIC8qIEhlYWRzIG9mIHRoZSBoYXNoIGNoYWlucyBvciBOSUwuICovXG5cbiAgdGhpcy5pbnNfaCA9IDA7ICAgICAgIC8qIGhhc2ggaW5kZXggb2Ygc3RyaW5nIHRvIGJlIGluc2VydGVkICovXG4gIHRoaXMuaGFzaF9zaXplID0gMDsgICAvKiBudW1iZXIgb2YgZWxlbWVudHMgaW4gaGFzaCB0YWJsZSAqL1xuICB0aGlzLmhhc2hfYml0cyA9IDA7ICAgLyogbG9nMihoYXNoX3NpemUpICovXG4gIHRoaXMuaGFzaF9tYXNrID0gMDsgICAvKiBoYXNoX3NpemUtMSAqL1xuXG4gIHRoaXMuaGFzaF9zaGlmdCA9IDA7XG4gIC8qIE51bWJlciBvZiBiaXRzIGJ5IHdoaWNoIGluc19oIG11c3QgYmUgc2hpZnRlZCBhdCBlYWNoIGlucHV0XG4gICAqIHN0ZXAuIEl0IG11c3QgYmUgc3VjaCB0aGF0IGFmdGVyIE1JTl9NQVRDSCBzdGVwcywgdGhlIG9sZGVzdFxuICAgKiBieXRlIG5vIGxvbmdlciB0YWtlcyBwYXJ0IGluIHRoZSBoYXNoIGtleSwgdGhhdCBpczpcbiAgICogICBoYXNoX3NoaWZ0ICogTUlOX01BVENIID49IGhhc2hfYml0c1xuICAgKi9cblxuICB0aGlzLmJsb2NrX3N0YXJ0ID0gMDtcbiAgLyogV2luZG93IHBvc2l0aW9uIGF0IHRoZSBiZWdpbm5pbmcgb2YgdGhlIGN1cnJlbnQgb3V0cHV0IGJsb2NrLiBHZXRzXG4gICAqIG5lZ2F0aXZlIHdoZW4gdGhlIHdpbmRvdyBpcyBtb3ZlZCBiYWNrd2FyZHMuXG4gICAqL1xuXG4gIHRoaXMubWF0Y2hfbGVuZ3RoID0gMDsgICAgICAvKiBsZW5ndGggb2YgYmVzdCBtYXRjaCAqL1xuICB0aGlzLnByZXZfbWF0Y2ggPSAwOyAgICAgICAgLyogcHJldmlvdXMgbWF0Y2ggKi9cbiAgdGhpcy5tYXRjaF9hdmFpbGFibGUgPSAwOyAgIC8qIHNldCBpZiBwcmV2aW91cyBtYXRjaCBleGlzdHMgKi9cbiAgdGhpcy5zdHJzdGFydCA9IDA7ICAgICAgICAgIC8qIHN0YXJ0IG9mIHN0cmluZyB0byBpbnNlcnQgKi9cbiAgdGhpcy5tYXRjaF9zdGFydCA9IDA7ICAgICAgIC8qIHN0YXJ0IG9mIG1hdGNoaW5nIHN0cmluZyAqL1xuICB0aGlzLmxvb2thaGVhZCA9IDA7ICAgICAgICAgLyogbnVtYmVyIG9mIHZhbGlkIGJ5dGVzIGFoZWFkIGluIHdpbmRvdyAqL1xuXG4gIHRoaXMucHJldl9sZW5ndGggPSAwO1xuICAvKiBMZW5ndGggb2YgdGhlIGJlc3QgbWF0Y2ggYXQgcHJldmlvdXMgc3RlcC4gTWF0Y2hlcyBub3QgZ3JlYXRlciB0aGFuIHRoaXNcbiAgICogYXJlIGRpc2NhcmRlZC4gVGhpcyBpcyB1c2VkIGluIHRoZSBsYXp5IG1hdGNoIGV2YWx1YXRpb24uXG4gICAqL1xuXG4gIHRoaXMubWF4X2NoYWluX2xlbmd0aCA9IDA7XG4gIC8qIFRvIHNwZWVkIHVwIGRlZmxhdGlvbiwgaGFzaCBjaGFpbnMgYXJlIG5ldmVyIHNlYXJjaGVkIGJleW9uZCB0aGlzXG4gICAqIGxlbmd0aC4gIEEgaGlnaGVyIGxpbWl0IGltcHJvdmVzIGNvbXByZXNzaW9uIHJhdGlvIGJ1dCBkZWdyYWRlcyB0aGVcbiAgICogc3BlZWQuXG4gICAqL1xuXG4gIHRoaXMubWF4X2xhenlfbWF0Y2ggPSAwO1xuICAvKiBBdHRlbXB0IHRvIGZpbmQgYSBiZXR0ZXIgbWF0Y2ggb25seSB3aGVuIHRoZSBjdXJyZW50IG1hdGNoIGlzIHN0cmljdGx5XG4gICAqIHNtYWxsZXIgdGhhbiB0aGlzIHZhbHVlLiBUaGlzIG1lY2hhbmlzbSBpcyB1c2VkIG9ubHkgZm9yIGNvbXByZXNzaW9uXG4gICAqIGxldmVscyA+PSA0LlxuICAgKi9cbiAgLy8gVGhhdCdzIGFsaWFzIHRvIG1heF9sYXp5X21hdGNoLCBkb24ndCB1c2UgZGlyZWN0bHlcbiAgLy90aGlzLm1heF9pbnNlcnRfbGVuZ3RoID0gMDtcbiAgLyogSW5zZXJ0IG5ldyBzdHJpbmdzIGluIHRoZSBoYXNoIHRhYmxlIG9ubHkgaWYgdGhlIG1hdGNoIGxlbmd0aCBpcyBub3RcbiAgICogZ3JlYXRlciB0aGFuIHRoaXMgbGVuZ3RoLiBUaGlzIHNhdmVzIHRpbWUgYnV0IGRlZ3JhZGVzIGNvbXByZXNzaW9uLlxuICAgKiBtYXhfaW5zZXJ0X2xlbmd0aCBpcyB1c2VkIG9ubHkgZm9yIGNvbXByZXNzaW9uIGxldmVscyA8PSAzLlxuICAgKi9cblxuICB0aGlzLmxldmVsID0gMDsgICAgIC8qIGNvbXByZXNzaW9uIGxldmVsICgxLi45KSAqL1xuICB0aGlzLnN0cmF0ZWd5ID0gMDsgIC8qIGZhdm9yIG9yIGZvcmNlIEh1ZmZtYW4gY29kaW5nKi9cblxuICB0aGlzLmdvb2RfbWF0Y2ggPSAwO1xuICAvKiBVc2UgYSBmYXN0ZXIgc2VhcmNoIHdoZW4gdGhlIHByZXZpb3VzIG1hdGNoIGlzIGxvbmdlciB0aGFuIHRoaXMgKi9cblxuICB0aGlzLm5pY2VfbWF0Y2ggPSAwOyAvKiBTdG9wIHNlYXJjaGluZyB3aGVuIGN1cnJlbnQgbWF0Y2ggZXhjZWVkcyB0aGlzICovXG5cbiAgICAgICAgICAgICAgLyogdXNlZCBieSB0cmVlcy5jOiAqL1xuXG4gIC8qIERpZG4ndCB1c2UgY3RfZGF0YSB0eXBlZGVmIGJlbG93IHRvIHN1cHByZXNzIGNvbXBpbGVyIHdhcm5pbmcgKi9cblxuICAvLyBzdHJ1Y3QgY3RfZGF0YV9zIGR5bl9sdHJlZVtIRUFQX1NJWkVdOyAgIC8qIGxpdGVyYWwgYW5kIGxlbmd0aCB0cmVlICovXG4gIC8vIHN0cnVjdCBjdF9kYXRhX3MgZHluX2R0cmVlWzIqRF9DT0RFUysxXTsgLyogZGlzdGFuY2UgdHJlZSAqL1xuICAvLyBzdHJ1Y3QgY3RfZGF0YV9zIGJsX3RyZWVbMipCTF9DT0RFUysxXTsgIC8qIEh1ZmZtYW4gdHJlZSBmb3IgYml0IGxlbmd0aHMgKi9cblxuICAvLyBVc2UgZmxhdCBhcnJheSBvZiBET1VCTEUgc2l6ZSwgd2l0aCBpbnRlcmxlYXZlZCBmYXRhLFxuICAvLyBiZWNhdXNlIEpTIGRvZXMgbm90IHN1cHBvcnQgZWZmZWN0aXZlXG4gIHRoaXMuZHluX2x0cmVlICA9IG5ldyB1dGlscy5CdWYxNihIRUFQX1NJWkUgKiAyKTtcbiAgdGhpcy5keW5fZHRyZWUgID0gbmV3IHV0aWxzLkJ1ZjE2KCgyKkRfQ09ERVMrMSkgKiAyKTtcbiAgdGhpcy5ibF90cmVlICAgID0gbmV3IHV0aWxzLkJ1ZjE2KCgyKkJMX0NPREVTKzEpICogMik7XG4gIHplcm8odGhpcy5keW5fbHRyZWUpO1xuICB6ZXJvKHRoaXMuZHluX2R0cmVlKTtcbiAgemVybyh0aGlzLmJsX3RyZWUpO1xuXG4gIHRoaXMubF9kZXNjICAgPSBudWxsOyAgICAgICAgIC8qIGRlc2MuIGZvciBsaXRlcmFsIHRyZWUgKi9cbiAgdGhpcy5kX2Rlc2MgICA9IG51bGw7ICAgICAgICAgLyogZGVzYy4gZm9yIGRpc3RhbmNlIHRyZWUgKi9cbiAgdGhpcy5ibF9kZXNjICA9IG51bGw7ICAgICAgICAgLyogZGVzYy4gZm9yIGJpdCBsZW5ndGggdHJlZSAqL1xuXG4gIC8vdXNoIGJsX2NvdW50W01BWF9CSVRTKzFdO1xuICB0aGlzLmJsX2NvdW50ID0gbmV3IHV0aWxzLkJ1ZjE2KE1BWF9CSVRTKzEpO1xuICAvKiBudW1iZXIgb2YgY29kZXMgYXQgZWFjaCBiaXQgbGVuZ3RoIGZvciBhbiBvcHRpbWFsIHRyZWUgKi9cblxuICAvL2ludCBoZWFwWzIqTF9DT0RFUysxXTsgICAgICAvKiBoZWFwIHVzZWQgdG8gYnVpbGQgdGhlIEh1ZmZtYW4gdHJlZXMgKi9cbiAgdGhpcy5oZWFwID0gbmV3IHV0aWxzLkJ1ZjE2KDIqTF9DT0RFUysxKTsgIC8qIGhlYXAgdXNlZCB0byBidWlsZCB0aGUgSHVmZm1hbiB0cmVlcyAqL1xuICB6ZXJvKHRoaXMuaGVhcCk7XG5cbiAgdGhpcy5oZWFwX2xlbiA9IDA7ICAgICAgICAgICAgICAgLyogbnVtYmVyIG9mIGVsZW1lbnRzIGluIHRoZSBoZWFwICovXG4gIHRoaXMuaGVhcF9tYXggPSAwOyAgICAgICAgICAgICAgIC8qIGVsZW1lbnQgb2YgbGFyZ2VzdCBmcmVxdWVuY3kgKi9cbiAgLyogVGhlIHNvbnMgb2YgaGVhcFtuXSBhcmUgaGVhcFsyKm5dIGFuZCBoZWFwWzIqbisxXS4gaGVhcFswXSBpcyBub3QgdXNlZC5cbiAgICogVGhlIHNhbWUgaGVhcCBhcnJheSBpcyB1c2VkIHRvIGJ1aWxkIGFsbCB0cmVlcy5cbiAgICovXG5cbiAgdGhpcy5kZXB0aCA9IG5ldyB1dGlscy5CdWYxNigyKkxfQ09ERVMrMSk7IC8vdWNoIGRlcHRoWzIqTF9DT0RFUysxXTtcbiAgemVybyh0aGlzLmRlcHRoKTtcbiAgLyogRGVwdGggb2YgZWFjaCBzdWJ0cmVlIHVzZWQgYXMgdGllIGJyZWFrZXIgZm9yIHRyZWVzIG9mIGVxdWFsIGZyZXF1ZW5jeVxuICAgKi9cblxuICB0aGlzLmxfYnVmID0gMDsgICAgICAgICAgLyogYnVmZmVyIGluZGV4IGZvciBsaXRlcmFscyBvciBsZW5ndGhzICovXG5cbiAgdGhpcy5saXRfYnVmc2l6ZSA9IDA7XG4gIC8qIFNpemUgb2YgbWF0Y2ggYnVmZmVyIGZvciBsaXRlcmFscy9sZW5ndGhzLiAgVGhlcmUgYXJlIDQgcmVhc29ucyBmb3JcbiAgICogbGltaXRpbmcgbGl0X2J1ZnNpemUgdG8gNjRLOlxuICAgKiAgIC0gZnJlcXVlbmNpZXMgY2FuIGJlIGtlcHQgaW4gMTYgYml0IGNvdW50ZXJzXG4gICAqICAgLSBpZiBjb21wcmVzc2lvbiBpcyBub3Qgc3VjY2Vzc2Z1bCBmb3IgdGhlIGZpcnN0IGJsb2NrLCBhbGwgaW5wdXRcbiAgICogICAgIGRhdGEgaXMgc3RpbGwgaW4gdGhlIHdpbmRvdyBzbyB3ZSBjYW4gc3RpbGwgZW1pdCBhIHN0b3JlZCBibG9jayBldmVuXG4gICAqICAgICB3aGVuIGlucHV0IGNvbWVzIGZyb20gc3RhbmRhcmQgaW5wdXQuICAoVGhpcyBjYW4gYWxzbyBiZSBkb25lIGZvclxuICAgKiAgICAgYWxsIGJsb2NrcyBpZiBsaXRfYnVmc2l6ZSBpcyBub3QgZ3JlYXRlciB0aGFuIDMySy4pXG4gICAqICAgLSBpZiBjb21wcmVzc2lvbiBpcyBub3Qgc3VjY2Vzc2Z1bCBmb3IgYSBmaWxlIHNtYWxsZXIgdGhhbiA2NEssIHdlIGNhblxuICAgKiAgICAgZXZlbiBlbWl0IGEgc3RvcmVkIGZpbGUgaW5zdGVhZCBvZiBhIHN0b3JlZCBibG9jayAoc2F2aW5nIDUgYnl0ZXMpLlxuICAgKiAgICAgVGhpcyBpcyBhcHBsaWNhYmxlIG9ubHkgZm9yIHppcCAobm90IGd6aXAgb3IgemxpYikuXG4gICAqICAgLSBjcmVhdGluZyBuZXcgSHVmZm1hbiB0cmVlcyBsZXNzIGZyZXF1ZW50bHkgbWF5IG5vdCBwcm92aWRlIGZhc3RcbiAgICogICAgIGFkYXB0YXRpb24gdG8gY2hhbmdlcyBpbiB0aGUgaW5wdXQgZGF0YSBzdGF0aXN0aWNzLiAoVGFrZSBmb3JcbiAgICogICAgIGV4YW1wbGUgYSBiaW5hcnkgZmlsZSB3aXRoIHBvb3JseSBjb21wcmVzc2libGUgY29kZSBmb2xsb3dlZCBieVxuICAgKiAgICAgYSBoaWdobHkgY29tcHJlc3NpYmxlIHN0cmluZyB0YWJsZS4pIFNtYWxsZXIgYnVmZmVyIHNpemVzIGdpdmVcbiAgICogICAgIGZhc3QgYWRhcHRhdGlvbiBidXQgaGF2ZSBvZiBjb3Vyc2UgdGhlIG92ZXJoZWFkIG9mIHRyYW5zbWl0dGluZ1xuICAgKiAgICAgdHJlZXMgbW9yZSBmcmVxdWVudGx5LlxuICAgKiAgIC0gSSBjYW4ndCBjb3VudCBhYm92ZSA0XG4gICAqL1xuXG4gIHRoaXMubGFzdF9saXQgPSAwOyAgICAgIC8qIHJ1bm5pbmcgaW5kZXggaW4gbF9idWYgKi9cblxuICB0aGlzLmRfYnVmID0gMDtcbiAgLyogQnVmZmVyIGluZGV4IGZvciBkaXN0YW5jZXMuIFRvIHNpbXBsaWZ5IHRoZSBjb2RlLCBkX2J1ZiBhbmQgbF9idWYgaGF2ZVxuICAgKiB0aGUgc2FtZSBudW1iZXIgb2YgZWxlbWVudHMuIFRvIHVzZSBkaWZmZXJlbnQgbGVuZ3RocywgYW4gZXh0cmEgZmxhZ1xuICAgKiBhcnJheSB3b3VsZCBiZSBuZWNlc3NhcnkuXG4gICAqL1xuXG4gIHRoaXMub3B0X2xlbiA9IDA7ICAgICAgIC8qIGJpdCBsZW5ndGggb2YgY3VycmVudCBibG9jayB3aXRoIG9wdGltYWwgdHJlZXMgKi9cbiAgdGhpcy5zdGF0aWNfbGVuID0gMDsgICAgLyogYml0IGxlbmd0aCBvZiBjdXJyZW50IGJsb2NrIHdpdGggc3RhdGljIHRyZWVzICovXG4gIHRoaXMubWF0Y2hlcyA9IDA7ICAgICAgIC8qIG51bWJlciBvZiBzdHJpbmcgbWF0Y2hlcyBpbiBjdXJyZW50IGJsb2NrICovXG4gIHRoaXMuaW5zZXJ0ID0gMDsgICAgICAgIC8qIGJ5dGVzIGF0IGVuZCBvZiB3aW5kb3cgbGVmdCB0byBpbnNlcnQgKi9cblxuXG4gIHRoaXMuYmlfYnVmID0gMDtcbiAgLyogT3V0cHV0IGJ1ZmZlci4gYml0cyBhcmUgaW5zZXJ0ZWQgc3RhcnRpbmcgYXQgdGhlIGJvdHRvbSAobGVhc3RcbiAgICogc2lnbmlmaWNhbnQgYml0cykuXG4gICAqL1xuICB0aGlzLmJpX3ZhbGlkID0gMDtcbiAgLyogTnVtYmVyIG9mIHZhbGlkIGJpdHMgaW4gYmlfYnVmLiAgQWxsIGJpdHMgYWJvdmUgdGhlIGxhc3QgdmFsaWQgYml0XG4gICAqIGFyZSBhbHdheXMgemVyby5cbiAgICovXG5cbiAgLy8gVXNlZCBmb3Igd2luZG93IG1lbW9yeSBpbml0LiBXZSBzYWZlbHkgaWdub3JlIGl0IGZvciBKUy4gVGhhdCBtYWtlc1xuICAvLyBzZW5zZSBvbmx5IGZvciBwb2ludGVycyBhbmQgbWVtb3J5IGNoZWNrIHRvb2xzLlxuICAvL3RoaXMuaGlnaF93YXRlciA9IDA7XG4gIC8qIEhpZ2ggd2F0ZXIgbWFyayBvZmZzZXQgaW4gd2luZG93IGZvciBpbml0aWFsaXplZCBieXRlcyAtLSBieXRlcyBhYm92ZVxuICAgKiB0aGlzIGFyZSBzZXQgdG8gemVybyBpbiBvcmRlciB0byBhdm9pZCBtZW1vcnkgY2hlY2sgd2FybmluZ3Mgd2hlblxuICAgKiBsb25nZXN0IG1hdGNoIHJvdXRpbmVzIGFjY2VzcyBieXRlcyBwYXN0IHRoZSBpbnB1dC4gIFRoaXMgaXMgdGhlblxuICAgKiB1cGRhdGVkIHRvIHRoZSBuZXcgaGlnaCB3YXRlciBtYXJrLlxuICAgKi9cbn1cblxuXG5mdW5jdGlvbiBkZWZsYXRlUmVzZXRLZWVwKHN0cm0pIHtcbiAgdmFyIHM7XG5cbiAgaWYgKCFzdHJtIHx8ICFzdHJtLnN0YXRlKSB7XG4gICAgcmV0dXJuIGVycihzdHJtLCBaX1NUUkVBTV9FUlJPUik7XG4gIH1cblxuICBzdHJtLnRvdGFsX2luID0gc3RybS50b3RhbF9vdXQgPSAwO1xuICBzdHJtLmRhdGFfdHlwZSA9IFpfVU5LTk9XTjtcblxuICBzID0gc3RybS5zdGF0ZTtcbiAgcy5wZW5kaW5nID0gMDtcbiAgcy5wZW5kaW5nX291dCA9IDA7XG5cbiAgaWYgKHMud3JhcCA8IDApIHtcbiAgICBzLndyYXAgPSAtcy53cmFwO1xuICAgIC8qIHdhcyBtYWRlIG5lZ2F0aXZlIGJ5IGRlZmxhdGUoLi4uLCBaX0ZJTklTSCk7ICovXG4gIH1cbiAgcy5zdGF0dXMgPSAocy53cmFwID8gSU5JVF9TVEFURSA6IEJVU1lfU1RBVEUpO1xuICBzdHJtLmFkbGVyID0gKHMud3JhcCA9PT0gMikgP1xuICAgIDAgIC8vIGNyYzMyKDAsIFpfTlVMTCwgMClcbiAgOlxuICAgIDE7IC8vIGFkbGVyMzIoMCwgWl9OVUxMLCAwKVxuICBzLmxhc3RfZmx1c2ggPSBaX05PX0ZMVVNIO1xuICB0cmVlcy5fdHJfaW5pdChzKTtcbiAgcmV0dXJuIFpfT0s7XG59XG5cblxuZnVuY3Rpb24gZGVmbGF0ZVJlc2V0KHN0cm0pIHtcbiAgdmFyIHJldCA9IGRlZmxhdGVSZXNldEtlZXAoc3RybSk7XG4gIGlmIChyZXQgPT09IFpfT0spIHtcbiAgICBsbV9pbml0KHN0cm0uc3RhdGUpO1xuICB9XG4gIHJldHVybiByZXQ7XG59XG5cblxuZnVuY3Rpb24gZGVmbGF0ZVNldEhlYWRlcihzdHJtLCBoZWFkKSB7XG4gIGlmICghc3RybSB8fCAhc3RybS5zdGF0ZSkgeyByZXR1cm4gWl9TVFJFQU1fRVJST1I7IH1cbiAgaWYgKHN0cm0uc3RhdGUud3JhcCAhPT0gMikgeyByZXR1cm4gWl9TVFJFQU1fRVJST1I7IH1cbiAgc3RybS5zdGF0ZS5nemhlYWQgPSBoZWFkO1xuICByZXR1cm4gWl9PSztcbn1cblxuXG5mdW5jdGlvbiBkZWZsYXRlSW5pdDIoc3RybSwgbGV2ZWwsIG1ldGhvZCwgd2luZG93Qml0cywgbWVtTGV2ZWwsIHN0cmF0ZWd5KSB7XG4gIGlmICghc3RybSkgeyAvLyA9PT0gWl9OVUxMXG4gICAgcmV0dXJuIFpfU1RSRUFNX0VSUk9SO1xuICB9XG4gIHZhciB3cmFwID0gMTtcblxuICBpZiAobGV2ZWwgPT09IFpfREVGQVVMVF9DT01QUkVTU0lPTikge1xuICAgIGxldmVsID0gNjtcbiAgfVxuXG4gIGlmICh3aW5kb3dCaXRzIDwgMCkgeyAvKiBzdXBwcmVzcyB6bGliIHdyYXBwZXIgKi9cbiAgICB3cmFwID0gMDtcbiAgICB3aW5kb3dCaXRzID0gLXdpbmRvd0JpdHM7XG4gIH1cblxuICBlbHNlIGlmICh3aW5kb3dCaXRzID4gMTUpIHtcbiAgICB3cmFwID0gMjsgICAgICAgICAgIC8qIHdyaXRlIGd6aXAgd3JhcHBlciBpbnN0ZWFkICovXG4gICAgd2luZG93Qml0cyAtPSAxNjtcbiAgfVxuXG5cbiAgaWYgKG1lbUxldmVsIDwgMSB8fCBtZW1MZXZlbCA+IE1BWF9NRU1fTEVWRUwgfHwgbWV0aG9kICE9PSBaX0RFRkxBVEVEIHx8XG4gICAgd2luZG93Qml0cyA8IDggfHwgd2luZG93Qml0cyA+IDE1IHx8IGxldmVsIDwgMCB8fCBsZXZlbCA+IDkgfHxcbiAgICBzdHJhdGVneSA8IDAgfHwgc3RyYXRlZ3kgPiBaX0ZJWEVEKSB7XG4gICAgcmV0dXJuIGVycihzdHJtLCBaX1NUUkVBTV9FUlJPUik7XG4gIH1cblxuXG4gIGlmICh3aW5kb3dCaXRzID09PSA4KSB7XG4gICAgd2luZG93Qml0cyA9IDk7XG4gIH1cbiAgLyogdW50aWwgMjU2LWJ5dGUgd2luZG93IGJ1ZyBmaXhlZCAqL1xuXG4gIHZhciBzID0gbmV3IERlZmxhdGVTdGF0ZSgpO1xuXG4gIHN0cm0uc3RhdGUgPSBzO1xuICBzLnN0cm0gPSBzdHJtO1xuXG4gIHMud3JhcCA9IHdyYXA7XG4gIHMuZ3poZWFkID0gbnVsbDtcbiAgcy53X2JpdHMgPSB3aW5kb3dCaXRzO1xuICBzLndfc2l6ZSA9IDEgPDwgcy53X2JpdHM7XG4gIHMud19tYXNrID0gcy53X3NpemUgLSAxO1xuXG4gIHMuaGFzaF9iaXRzID0gbWVtTGV2ZWwgKyA3O1xuICBzLmhhc2hfc2l6ZSA9IDEgPDwgcy5oYXNoX2JpdHM7XG4gIHMuaGFzaF9tYXNrID0gcy5oYXNoX3NpemUgLSAxO1xuICBzLmhhc2hfc2hpZnQgPSB+figocy5oYXNoX2JpdHMgKyBNSU5fTUFUQ0ggLSAxKSAvIE1JTl9NQVRDSCk7XG5cbiAgcy53aW5kb3cgPSBuZXcgdXRpbHMuQnVmOChzLndfc2l6ZSAqIDIpO1xuICBzLmhlYWQgPSBuZXcgdXRpbHMuQnVmMTYocy5oYXNoX3NpemUpO1xuICBzLnByZXYgPSBuZXcgdXRpbHMuQnVmMTYocy53X3NpemUpO1xuXG4gIC8vIERvbid0IG5lZWQgbWVtIGluaXQgbWFnaWMgZm9yIEpTLlxuICAvL3MuaGlnaF93YXRlciA9IDA7ICAvKiBub3RoaW5nIHdyaXR0ZW4gdG8gcy0+d2luZG93IHlldCAqL1xuXG4gIHMubGl0X2J1ZnNpemUgPSAxIDw8IChtZW1MZXZlbCArIDYpOyAvKiAxNksgZWxlbWVudHMgYnkgZGVmYXVsdCAqL1xuXG4gIHMucGVuZGluZ19idWZfc2l6ZSA9IHMubGl0X2J1ZnNpemUgKiA0O1xuICBzLnBlbmRpbmdfYnVmID0gbmV3IHV0aWxzLkJ1Zjgocy5wZW5kaW5nX2J1Zl9zaXplKTtcblxuICBzLmRfYnVmID0gcy5saXRfYnVmc2l6ZSA+PiAxO1xuICBzLmxfYnVmID0gKDEgKyAyKSAqIHMubGl0X2J1ZnNpemU7XG5cbiAgcy5sZXZlbCA9IGxldmVsO1xuICBzLnN0cmF0ZWd5ID0gc3RyYXRlZ3k7XG4gIHMubWV0aG9kID0gbWV0aG9kO1xuXG4gIHJldHVybiBkZWZsYXRlUmVzZXQoc3RybSk7XG59XG5cbmZ1bmN0aW9uIGRlZmxhdGVJbml0KHN0cm0sIGxldmVsKSB7XG4gIHJldHVybiBkZWZsYXRlSW5pdDIoc3RybSwgbGV2ZWwsIFpfREVGTEFURUQsIE1BWF9XQklUUywgREVGX01FTV9MRVZFTCwgWl9ERUZBVUxUX1NUUkFURUdZKTtcbn1cblxuXG5mdW5jdGlvbiBkZWZsYXRlKHN0cm0sIGZsdXNoKSB7XG4gIHZhciBvbGRfZmx1c2gsIHM7XG4gIHZhciBiZWcsIHZhbDsgLy8gZm9yIGd6aXAgaGVhZGVyIHdyaXRlIG9ubHlcblxuICBpZiAoIXN0cm0gfHwgIXN0cm0uc3RhdGUgfHxcbiAgICBmbHVzaCA+IFpfQkxPQ0sgfHwgZmx1c2ggPCAwKSB7XG4gICAgcmV0dXJuIHN0cm0gPyBlcnIoc3RybSwgWl9TVFJFQU1fRVJST1IpIDogWl9TVFJFQU1fRVJST1I7XG4gIH1cblxuICBzID0gc3RybS5zdGF0ZTtcblxuICBpZiAoIXN0cm0ub3V0cHV0IHx8XG4gICAgICAoIXN0cm0uaW5wdXQgJiYgc3RybS5hdmFpbF9pbiAhPT0gMCkgfHxcbiAgICAgIChzLnN0YXR1cyA9PT0gRklOSVNIX1NUQVRFICYmIGZsdXNoICE9PSBaX0ZJTklTSCkpIHtcbiAgICByZXR1cm4gZXJyKHN0cm0sIChzdHJtLmF2YWlsX291dCA9PT0gMCkgPyBaX0JVRl9FUlJPUiA6IFpfU1RSRUFNX0VSUk9SKTtcbiAgfVxuXG4gIHMuc3RybSA9IHN0cm07IC8qIGp1c3QgaW4gY2FzZSAqL1xuICBvbGRfZmx1c2ggPSBzLmxhc3RfZmx1c2g7XG4gIHMubGFzdF9mbHVzaCA9IGZsdXNoO1xuXG4gIC8qIFdyaXRlIHRoZSBoZWFkZXIgKi9cbiAgaWYgKHMuc3RhdHVzID09PSBJTklUX1NUQVRFKSB7XG5cbiAgICBpZiAocy53cmFwID09PSAyKSB7IC8vIEdaSVAgaGVhZGVyXG4gICAgICBzdHJtLmFkbGVyID0gMDsgIC8vY3JjMzIoMEwsIFpfTlVMTCwgMCk7XG4gICAgICBwdXRfYnl0ZShzLCAzMSk7XG4gICAgICBwdXRfYnl0ZShzLCAxMzkpO1xuICAgICAgcHV0X2J5dGUocywgOCk7XG4gICAgICBpZiAoIXMuZ3poZWFkKSB7IC8vIHMtPmd6aGVhZCA9PSBaX05VTExcbiAgICAgICAgcHV0X2J5dGUocywgMCk7XG4gICAgICAgIHB1dF9ieXRlKHMsIDApO1xuICAgICAgICBwdXRfYnl0ZShzLCAwKTtcbiAgICAgICAgcHV0X2J5dGUocywgMCk7XG4gICAgICAgIHB1dF9ieXRlKHMsIDApO1xuICAgICAgICBwdXRfYnl0ZShzLCBzLmxldmVsID09PSA5ID8gMiA6XG4gICAgICAgICAgICAgICAgICAgIChzLnN0cmF0ZWd5ID49IFpfSFVGRk1BTl9PTkxZIHx8IHMubGV2ZWwgPCAyID9cbiAgICAgICAgICAgICAgICAgICAgIDQgOiAwKSk7XG4gICAgICAgIHB1dF9ieXRlKHMsIE9TX0NPREUpO1xuICAgICAgICBzLnN0YXR1cyA9IEJVU1lfU1RBVEU7XG4gICAgICB9XG4gICAgICBlbHNlIHtcbiAgICAgICAgcHV0X2J5dGUocywgKHMuZ3poZWFkLnRleHQgPyAxIDogMCkgK1xuICAgICAgICAgICAgICAgICAgICAocy5nemhlYWQuaGNyYyA/IDIgOiAwKSArXG4gICAgICAgICAgICAgICAgICAgICghcy5nemhlYWQuZXh0cmEgPyAwIDogNCkgK1xuICAgICAgICAgICAgICAgICAgICAoIXMuZ3poZWFkLm5hbWUgPyAwIDogOCkgK1xuICAgICAgICAgICAgICAgICAgICAoIXMuZ3poZWFkLmNvbW1lbnQgPyAwIDogMTYpXG4gICAgICAgICAgICAgICAgKTtcbiAgICAgICAgcHV0X2J5dGUocywgcy5nemhlYWQudGltZSAmIDB4ZmYpO1xuICAgICAgICBwdXRfYnl0ZShzLCAocy5nemhlYWQudGltZSA+PiA4KSAmIDB4ZmYpO1xuICAgICAgICBwdXRfYnl0ZShzLCAocy5nemhlYWQudGltZSA+PiAxNikgJiAweGZmKTtcbiAgICAgICAgcHV0X2J5dGUocywgKHMuZ3poZWFkLnRpbWUgPj4gMjQpICYgMHhmZik7XG4gICAgICAgIHB1dF9ieXRlKHMsIHMubGV2ZWwgPT09IDkgPyAyIDpcbiAgICAgICAgICAgICAgICAgICAgKHMuc3RyYXRlZ3kgPj0gWl9IVUZGTUFOX09OTFkgfHwgcy5sZXZlbCA8IDIgP1xuICAgICAgICAgICAgICAgICAgICAgNCA6IDApKTtcbiAgICAgICAgcHV0X2J5dGUocywgcy5nemhlYWQub3MgJiAweGZmKTtcbiAgICAgICAgaWYgKHMuZ3poZWFkLmV4dHJhICYmIHMuZ3poZWFkLmV4dHJhLmxlbmd0aCkge1xuICAgICAgICAgIHB1dF9ieXRlKHMsIHMuZ3poZWFkLmV4dHJhLmxlbmd0aCAmIDB4ZmYpO1xuICAgICAgICAgIHB1dF9ieXRlKHMsIChzLmd6aGVhZC5leHRyYS5sZW5ndGggPj4gOCkgJiAweGZmKTtcbiAgICAgICAgfVxuICAgICAgICBpZiAocy5nemhlYWQuaGNyYykge1xuICAgICAgICAgIHN0cm0uYWRsZXIgPSBjcmMzMihzdHJtLmFkbGVyLCBzLnBlbmRpbmdfYnVmLCBzLnBlbmRpbmcsIDApO1xuICAgICAgICB9XG4gICAgICAgIHMuZ3ppbmRleCA9IDA7XG4gICAgICAgIHMuc3RhdHVzID0gRVhUUkFfU1RBVEU7XG4gICAgICB9XG4gICAgfVxuICAgIGVsc2UgLy8gREVGTEFURSBoZWFkZXJcbiAgICB7XG4gICAgICB2YXIgaGVhZGVyID0gKFpfREVGTEFURUQgKyAoKHMud19iaXRzIC0gOCkgPDwgNCkpIDw8IDg7XG4gICAgICB2YXIgbGV2ZWxfZmxhZ3MgPSAtMTtcblxuICAgICAgaWYgKHMuc3RyYXRlZ3kgPj0gWl9IVUZGTUFOX09OTFkgfHwgcy5sZXZlbCA8IDIpIHtcbiAgICAgICAgbGV2ZWxfZmxhZ3MgPSAwO1xuICAgICAgfSBlbHNlIGlmIChzLmxldmVsIDwgNikge1xuICAgICAgICBsZXZlbF9mbGFncyA9IDE7XG4gICAgICB9IGVsc2UgaWYgKHMubGV2ZWwgPT09IDYpIHtcbiAgICAgICAgbGV2ZWxfZmxhZ3MgPSAyO1xuICAgICAgfSBlbHNlIHtcbiAgICAgICAgbGV2ZWxfZmxhZ3MgPSAzO1xuICAgICAgfVxuICAgICAgaGVhZGVyIHw9IChsZXZlbF9mbGFncyA8PCA2KTtcbiAgICAgIGlmIChzLnN0cnN0YXJ0ICE9PSAwKSB7IGhlYWRlciB8PSBQUkVTRVRfRElDVDsgfVxuICAgICAgaGVhZGVyICs9IDMxIC0gKGhlYWRlciAlIDMxKTtcblxuICAgICAgcy5zdGF0dXMgPSBCVVNZX1NUQVRFO1xuICAgICAgcHV0U2hvcnRNU0IocywgaGVhZGVyKTtcblxuICAgICAgLyogU2F2ZSB0aGUgYWRsZXIzMiBvZiB0aGUgcHJlc2V0IGRpY3Rpb25hcnk6ICovXG4gICAgICBpZiAocy5zdHJzdGFydCAhPT0gMCkge1xuICAgICAgICBwdXRTaG9ydE1TQihzLCBzdHJtLmFkbGVyID4+PiAxNik7XG4gICAgICAgIHB1dFNob3J0TVNCKHMsIHN0cm0uYWRsZXIgJiAweGZmZmYpO1xuICAgICAgfVxuICAgICAgc3RybS5hZGxlciA9IDE7IC8vIGFkbGVyMzIoMEwsIFpfTlVMTCwgMCk7XG4gICAgfVxuICB9XG5cbi8vI2lmZGVmIEdaSVBcbiAgaWYgKHMuc3RhdHVzID09PSBFWFRSQV9TVEFURSkge1xuICAgIGlmIChzLmd6aGVhZC5leHRyYS8qICE9IFpfTlVMTCovKSB7XG4gICAgICBiZWcgPSBzLnBlbmRpbmc7ICAvKiBzdGFydCBvZiBieXRlcyB0byB1cGRhdGUgY3JjICovXG5cbiAgICAgIHdoaWxlIChzLmd6aW5kZXggPCAocy5nemhlYWQuZXh0cmEubGVuZ3RoICYgMHhmZmZmKSkge1xuICAgICAgICBpZiAocy5wZW5kaW5nID09PSBzLnBlbmRpbmdfYnVmX3NpemUpIHtcbiAgICAgICAgICBpZiAocy5nemhlYWQuaGNyYyAmJiBzLnBlbmRpbmcgPiBiZWcpIHtcbiAgICAgICAgICAgIHN0cm0uYWRsZXIgPSBjcmMzMihzdHJtLmFkbGVyLCBzLnBlbmRpbmdfYnVmLCBzLnBlbmRpbmcgLSBiZWcsIGJlZyk7XG4gICAgICAgICAgfVxuICAgICAgICAgIGZsdXNoX3BlbmRpbmcoc3RybSk7XG4gICAgICAgICAgYmVnID0gcy5wZW5kaW5nO1xuICAgICAgICAgIGlmIChzLnBlbmRpbmcgPT09IHMucGVuZGluZ19idWZfc2l6ZSkge1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIHB1dF9ieXRlKHMsIHMuZ3poZWFkLmV4dHJhW3MuZ3ppbmRleF0gJiAweGZmKTtcbiAgICAgICAgcy5nemluZGV4Kys7XG4gICAgICB9XG4gICAgICBpZiAocy5nemhlYWQuaGNyYyAmJiBzLnBlbmRpbmcgPiBiZWcpIHtcbiAgICAgICAgc3RybS5hZGxlciA9IGNyYzMyKHN0cm0uYWRsZXIsIHMucGVuZGluZ19idWYsIHMucGVuZGluZyAtIGJlZywgYmVnKTtcbiAgICAgIH1cbiAgICAgIGlmIChzLmd6aW5kZXggPT09IHMuZ3poZWFkLmV4dHJhLmxlbmd0aCkge1xuICAgICAgICBzLmd6aW5kZXggPSAwO1xuICAgICAgICBzLnN0YXR1cyA9IE5BTUVfU1RBVEU7XG4gICAgICB9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgcy5zdGF0dXMgPSBOQU1FX1NUQVRFO1xuICAgIH1cbiAgfVxuICBpZiAocy5zdGF0dXMgPT09IE5BTUVfU1RBVEUpIHtcbiAgICBpZiAocy5nemhlYWQubmFtZS8qICE9IFpfTlVMTCovKSB7XG4gICAgICBiZWcgPSBzLnBlbmRpbmc7ICAvKiBzdGFydCBvZiBieXRlcyB0byB1cGRhdGUgY3JjICovXG4gICAgICAvL2ludCB2YWw7XG5cbiAgICAgIGRvIHtcbiAgICAgICAgaWYgKHMucGVuZGluZyA9PT0gcy5wZW5kaW5nX2J1Zl9zaXplKSB7XG4gICAgICAgICAgaWYgKHMuZ3poZWFkLmhjcmMgJiYgcy5wZW5kaW5nID4gYmVnKSB7XG4gICAgICAgICAgICBzdHJtLmFkbGVyID0gY3JjMzIoc3RybS5hZGxlciwgcy5wZW5kaW5nX2J1Ziwgcy5wZW5kaW5nIC0gYmVnLCBiZWcpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBmbHVzaF9wZW5kaW5nKHN0cm0pO1xuICAgICAgICAgIGJlZyA9IHMucGVuZGluZztcbiAgICAgICAgICBpZiAocy5wZW5kaW5nID09PSBzLnBlbmRpbmdfYnVmX3NpemUpIHtcbiAgICAgICAgICAgIHZhbCA9IDE7XG4gICAgICAgICAgICBicmVhaztcbiAgICAgICAgICB9XG4gICAgICAgIH1cbiAgICAgICAgLy8gSlMgc3BlY2lmaWM6IGxpdHRsZSBtYWdpYyB0byBhZGQgemVybyB0ZXJtaW5hdG9yIHRvIGVuZCBvZiBzdHJpbmdcbiAgICAgICAgaWYgKHMuZ3ppbmRleCA8IHMuZ3poZWFkLm5hbWUubGVuZ3RoKSB7XG4gICAgICAgICAgdmFsID0gcy5nemhlYWQubmFtZS5jaGFyQ29kZUF0KHMuZ3ppbmRleCsrKSAmIDB4ZmY7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgdmFsID0gMDtcbiAgICAgICAgfVxuICAgICAgICBwdXRfYnl0ZShzLCB2YWwpO1xuICAgICAgfSB3aGlsZSAodmFsICE9PSAwKTtcblxuICAgICAgaWYgKHMuZ3poZWFkLmhjcmMgJiYgcy5wZW5kaW5nID4gYmVnKXtcbiAgICAgICAgc3RybS5hZGxlciA9IGNyYzMyKHN0cm0uYWRsZXIsIHMucGVuZGluZ19idWYsIHMucGVuZGluZyAtIGJlZywgYmVnKTtcbiAgICAgIH1cbiAgICAgIGlmICh2YWwgPT09IDApIHtcbiAgICAgICAgcy5nemluZGV4ID0gMDtcbiAgICAgICAgcy5zdGF0dXMgPSBDT01NRU5UX1NUQVRFO1xuICAgICAgfVxuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHMuc3RhdHVzID0gQ09NTUVOVF9TVEFURTtcbiAgICB9XG4gIH1cbiAgaWYgKHMuc3RhdHVzID09PSBDT01NRU5UX1NUQVRFKSB7XG4gICAgaWYgKHMuZ3poZWFkLmNvbW1lbnQvKiAhPSBaX05VTEwqLykge1xuICAgICAgYmVnID0gcy5wZW5kaW5nOyAgLyogc3RhcnQgb2YgYnl0ZXMgdG8gdXBkYXRlIGNyYyAqL1xuICAgICAgLy9pbnQgdmFsO1xuXG4gICAgICBkbyB7XG4gICAgICAgIGlmIChzLnBlbmRpbmcgPT09IHMucGVuZGluZ19idWZfc2l6ZSkge1xuICAgICAgICAgIGlmIChzLmd6aGVhZC5oY3JjICYmIHMucGVuZGluZyA+IGJlZykge1xuICAgICAgICAgICAgc3RybS5hZGxlciA9IGNyYzMyKHN0cm0uYWRsZXIsIHMucGVuZGluZ19idWYsIHMucGVuZGluZyAtIGJlZywgYmVnKTtcbiAgICAgICAgICB9XG4gICAgICAgICAgZmx1c2hfcGVuZGluZyhzdHJtKTtcbiAgICAgICAgICBiZWcgPSBzLnBlbmRpbmc7XG4gICAgICAgICAgaWYgKHMucGVuZGluZyA9PT0gcy5wZW5kaW5nX2J1Zl9zaXplKSB7XG4gICAgICAgICAgICB2YWwgPSAxO1xuICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIC8vIEpTIHNwZWNpZmljOiBsaXR0bGUgbWFnaWMgdG8gYWRkIHplcm8gdGVybWluYXRvciB0byBlbmQgb2Ygc3RyaW5nXG4gICAgICAgIGlmIChzLmd6aW5kZXggPCBzLmd6aGVhZC5jb21tZW50Lmxlbmd0aCkge1xuICAgICAgICAgIHZhbCA9IHMuZ3poZWFkLmNvbW1lbnQuY2hhckNvZGVBdChzLmd6aW5kZXgrKykgJiAweGZmO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIHZhbCA9IDA7XG4gICAgICAgIH1cbiAgICAgICAgcHV0X2J5dGUocywgdmFsKTtcbiAgICAgIH0gd2hpbGUgKHZhbCAhPT0gMCk7XG5cbiAgICAgIGlmIChzLmd6aGVhZC5oY3JjICYmIHMucGVuZGluZyA+IGJlZykge1xuICAgICAgICBzdHJtLmFkbGVyID0gY3JjMzIoc3RybS5hZGxlciwgcy5wZW5kaW5nX2J1Ziwgcy5wZW5kaW5nIC0gYmVnLCBiZWcpO1xuICAgICAgfVxuICAgICAgaWYgKHZhbCA9PT0gMCkge1xuICAgICAgICBzLnN0YXR1cyA9IEhDUkNfU1RBVEU7XG4gICAgICB9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgcy5zdGF0dXMgPSBIQ1JDX1NUQVRFO1xuICAgIH1cbiAgfVxuICBpZiAocy5zdGF0dXMgPT09IEhDUkNfU1RBVEUpIHtcbiAgICBpZiAocy5nemhlYWQuaGNyYykge1xuICAgICAgaWYgKHMucGVuZGluZyArIDIgPiBzLnBlbmRpbmdfYnVmX3NpemUpIHtcbiAgICAgICAgZmx1c2hfcGVuZGluZyhzdHJtKTtcbiAgICAgIH1cbiAgICAgIGlmIChzLnBlbmRpbmcgKyAyIDw9IHMucGVuZGluZ19idWZfc2l6ZSkge1xuICAgICAgICBwdXRfYnl0ZShzLCBzdHJtLmFkbGVyICYgMHhmZik7XG4gICAgICAgIHB1dF9ieXRlKHMsIChzdHJtLmFkbGVyID4+IDgpICYgMHhmZik7XG4gICAgICAgIHN0cm0uYWRsZXIgPSAwOyAvL2NyYzMyKDBMLCBaX05VTEwsIDApO1xuICAgICAgICBzLnN0YXR1cyA9IEJVU1lfU1RBVEU7XG4gICAgICB9XG4gICAgfVxuICAgIGVsc2Uge1xuICAgICAgcy5zdGF0dXMgPSBCVVNZX1NUQVRFO1xuICAgIH1cbiAgfVxuLy8jZW5kaWZcblxuICAvKiBGbHVzaCBhcyBtdWNoIHBlbmRpbmcgb3V0cHV0IGFzIHBvc3NpYmxlICovXG4gIGlmIChzLnBlbmRpbmcgIT09IDApIHtcbiAgICBmbHVzaF9wZW5kaW5nKHN0cm0pO1xuICAgIGlmIChzdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgLyogU2luY2UgYXZhaWxfb3V0IGlzIDAsIGRlZmxhdGUgd2lsbCBiZSBjYWxsZWQgYWdhaW4gd2l0aFxuICAgICAgICogbW9yZSBvdXRwdXQgc3BhY2UsIGJ1dCBwb3NzaWJseSB3aXRoIGJvdGggcGVuZGluZyBhbmRcbiAgICAgICAqIGF2YWlsX2luIGVxdWFsIHRvIHplcm8uIFRoZXJlIHdvbid0IGJlIGFueXRoaW5nIHRvIGRvLFxuICAgICAgICogYnV0IHRoaXMgaXMgbm90IGFuIGVycm9yIHNpdHVhdGlvbiBzbyBtYWtlIHN1cmUgd2VcbiAgICAgICAqIHJldHVybiBPSyBpbnN0ZWFkIG9mIEJVRl9FUlJPUiBhdCBuZXh0IGNhbGwgb2YgZGVmbGF0ZTpcbiAgICAgICAqL1xuICAgICAgcy5sYXN0X2ZsdXNoID0gLTE7XG4gICAgICByZXR1cm4gWl9PSztcbiAgICB9XG5cbiAgICAvKiBNYWtlIHN1cmUgdGhlcmUgaXMgc29tZXRoaW5nIHRvIGRvIGFuZCBhdm9pZCBkdXBsaWNhdGUgY29uc2VjdXRpdmVcbiAgICAgKiBmbHVzaGVzLiBGb3IgcmVwZWF0ZWQgYW5kIHVzZWxlc3MgY2FsbHMgd2l0aCBaX0ZJTklTSCwgd2Uga2VlcFxuICAgICAqIHJldHVybmluZyBaX1NUUkVBTV9FTkQgaW5zdGVhZCBvZiBaX0JVRl9FUlJPUi5cbiAgICAgKi9cbiAgfSBlbHNlIGlmIChzdHJtLmF2YWlsX2luID09PSAwICYmIHJhbmsoZmx1c2gpIDw9IHJhbmsob2xkX2ZsdXNoKSAmJlxuICAgIGZsdXNoICE9PSBaX0ZJTklTSCkge1xuICAgIHJldHVybiBlcnIoc3RybSwgWl9CVUZfRVJST1IpO1xuICB9XG5cbiAgLyogVXNlciBtdXN0IG5vdCBwcm92aWRlIG1vcmUgaW5wdXQgYWZ0ZXIgdGhlIGZpcnN0IEZJTklTSDogKi9cbiAgaWYgKHMuc3RhdHVzID09PSBGSU5JU0hfU1RBVEUgJiYgc3RybS5hdmFpbF9pbiAhPT0gMCkge1xuICAgIHJldHVybiBlcnIoc3RybSwgWl9CVUZfRVJST1IpO1xuICB9XG5cbiAgLyogU3RhcnQgYSBuZXcgYmxvY2sgb3IgY29udGludWUgdGhlIGN1cnJlbnQgb25lLlxuICAgKi9cbiAgaWYgKHN0cm0uYXZhaWxfaW4gIT09IDAgfHwgcy5sb29rYWhlYWQgIT09IDAgfHxcbiAgICAoZmx1c2ggIT09IFpfTk9fRkxVU0ggJiYgcy5zdGF0dXMgIT09IEZJTklTSF9TVEFURSkpIHtcbiAgICB2YXIgYnN0YXRlID0gKHMuc3RyYXRlZ3kgPT09IFpfSFVGRk1BTl9PTkxZKSA/IGRlZmxhdGVfaHVmZihzLCBmbHVzaCkgOlxuICAgICAgKHMuc3RyYXRlZ3kgPT09IFpfUkxFID8gZGVmbGF0ZV9ybGUocywgZmx1c2gpIDpcbiAgICAgICAgY29uZmlndXJhdGlvbl90YWJsZVtzLmxldmVsXS5mdW5jKHMsIGZsdXNoKSk7XG5cbiAgICBpZiAoYnN0YXRlID09PSBCU19GSU5JU0hfU1RBUlRFRCB8fCBic3RhdGUgPT09IEJTX0ZJTklTSF9ET05FKSB7XG4gICAgICBzLnN0YXR1cyA9IEZJTklTSF9TVEFURTtcbiAgICB9XG4gICAgaWYgKGJzdGF0ZSA9PT0gQlNfTkVFRF9NT1JFIHx8IGJzdGF0ZSA9PT0gQlNfRklOSVNIX1NUQVJURUQpIHtcbiAgICAgIGlmIChzdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgICBzLmxhc3RfZmx1c2ggPSAtMTtcbiAgICAgICAgLyogYXZvaWQgQlVGX0VSUk9SIG5leHQgY2FsbCwgc2VlIGFib3ZlICovXG4gICAgICB9XG4gICAgICByZXR1cm4gWl9PSztcbiAgICAgIC8qIElmIGZsdXNoICE9IFpfTk9fRkxVU0ggJiYgYXZhaWxfb3V0ID09IDAsIHRoZSBuZXh0IGNhbGxcbiAgICAgICAqIG9mIGRlZmxhdGUgc2hvdWxkIHVzZSB0aGUgc2FtZSBmbHVzaCBwYXJhbWV0ZXIgdG8gbWFrZSBzdXJlXG4gICAgICAgKiB0aGF0IHRoZSBmbHVzaCBpcyBjb21wbGV0ZS4gU28gd2UgZG9uJ3QgaGF2ZSB0byBvdXRwdXQgYW5cbiAgICAgICAqIGVtcHR5IGJsb2NrIGhlcmUsIHRoaXMgd2lsbCBiZSBkb25lIGF0IG5leHQgY2FsbC4gVGhpcyBhbHNvXG4gICAgICAgKiBlbnN1cmVzIHRoYXQgZm9yIGEgdmVyeSBzbWFsbCBvdXRwdXQgYnVmZmVyLCB3ZSBlbWl0IGF0IG1vc3RcbiAgICAgICAqIG9uZSBlbXB0eSBibG9jay5cbiAgICAgICAqL1xuICAgIH1cbiAgICBpZiAoYnN0YXRlID09PSBCU19CTE9DS19ET05FKSB7XG4gICAgICBpZiAoZmx1c2ggPT09IFpfUEFSVElBTF9GTFVTSCkge1xuICAgICAgICB0cmVlcy5fdHJfYWxpZ24ocyk7XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChmbHVzaCAhPT0gWl9CTE9DSykgeyAvKiBGVUxMX0ZMVVNIIG9yIFNZTkNfRkxVU0ggKi9cblxuICAgICAgICB0cmVlcy5fdHJfc3RvcmVkX2Jsb2NrKHMsIDAsIDAsIGZhbHNlKTtcbiAgICAgICAgLyogRm9yIGEgZnVsbCBmbHVzaCwgdGhpcyBlbXB0eSBibG9jayB3aWxsIGJlIHJlY29nbml6ZWRcbiAgICAgICAgICogYXMgYSBzcGVjaWFsIG1hcmtlciBieSBpbmZsYXRlX3N5bmMoKS5cbiAgICAgICAgICovXG4gICAgICAgIGlmIChmbHVzaCA9PT0gWl9GVUxMX0ZMVVNIKSB7XG4gICAgICAgICAgLyoqKiBDTEVBUl9IQVNIKHMpOyAqKiovICAgICAgICAgICAgIC8qIGZvcmdldCBoaXN0b3J5ICovXG4gICAgICAgICAgemVybyhzLmhlYWQpOyAvLyBGaWxsIHdpdGggTklMICg9IDApO1xuXG4gICAgICAgICAgaWYgKHMubG9va2FoZWFkID09PSAwKSB7XG4gICAgICAgICAgICBzLnN0cnN0YXJ0ID0gMDtcbiAgICAgICAgICAgIHMuYmxvY2tfc3RhcnQgPSAwO1xuICAgICAgICAgICAgcy5pbnNlcnQgPSAwO1xuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgZmx1c2hfcGVuZGluZyhzdHJtKTtcbiAgICAgIGlmIChzdHJtLmF2YWlsX291dCA9PT0gMCkge1xuICAgICAgICBzLmxhc3RfZmx1c2ggPSAtMTsgLyogYXZvaWQgQlVGX0VSUk9SIGF0IG5leHQgY2FsbCwgc2VlIGFib3ZlICovXG4gICAgICAgIHJldHVybiBaX09LO1xuICAgICAgfVxuICAgIH1cbiAgfVxuICAvL0Fzc2VydChzdHJtLT5hdmFpbF9vdXQgPiAwLCBcImJ1ZzJcIik7XG4gIC8vaWYgKHN0cm0uYXZhaWxfb3V0IDw9IDApIHsgdGhyb3cgbmV3IEVycm9yKFwiYnVnMlwiKTt9XG5cbiAgaWYgKGZsdXNoICE9PSBaX0ZJTklTSCkgeyByZXR1cm4gWl9PSzsgfVxuICBpZiAocy53cmFwIDw9IDApIHsgcmV0dXJuIFpfU1RSRUFNX0VORDsgfVxuXG4gIC8qIFdyaXRlIHRoZSB0cmFpbGVyICovXG4gIGlmIChzLndyYXAgPT09IDIpIHtcbiAgICBwdXRfYnl0ZShzLCBzdHJtLmFkbGVyICYgMHhmZik7XG4gICAgcHV0X2J5dGUocywgKHN0cm0uYWRsZXIgPj4gOCkgJiAweGZmKTtcbiAgICBwdXRfYnl0ZShzLCAoc3RybS5hZGxlciA+PiAxNikgJiAweGZmKTtcbiAgICBwdXRfYnl0ZShzLCAoc3RybS5hZGxlciA+PiAyNCkgJiAweGZmKTtcbiAgICBwdXRfYnl0ZShzLCBzdHJtLnRvdGFsX2luICYgMHhmZik7XG4gICAgcHV0X2J5dGUocywgKHN0cm0udG90YWxfaW4gPj4gOCkgJiAweGZmKTtcbiAgICBwdXRfYnl0ZShzLCAoc3RybS50b3RhbF9pbiA+PiAxNikgJiAweGZmKTtcbiAgICBwdXRfYnl0ZShzLCAoc3RybS50b3RhbF9pbiA+PiAyNCkgJiAweGZmKTtcbiAgfVxuICBlbHNlXG4gIHtcbiAgICBwdXRTaG9ydE1TQihzLCBzdHJtLmFkbGVyID4+PiAxNik7XG4gICAgcHV0U2hvcnRNU0Iocywgc3RybS5hZGxlciAmIDB4ZmZmZik7XG4gIH1cblxuICBmbHVzaF9wZW5kaW5nKHN0cm0pO1xuICAvKiBJZiBhdmFpbF9vdXQgaXMgemVybywgdGhlIGFwcGxpY2F0aW9uIHdpbGwgY2FsbCBkZWZsYXRlIGFnYWluXG4gICAqIHRvIGZsdXNoIHRoZSByZXN0LlxuICAgKi9cbiAgaWYgKHMud3JhcCA+IDApIHsgcy53cmFwID0gLXMud3JhcDsgfVxuICAvKiB3cml0ZSB0aGUgdHJhaWxlciBvbmx5IG9uY2UhICovXG4gIHJldHVybiBzLnBlbmRpbmcgIT09IDAgPyBaX09LIDogWl9TVFJFQU1fRU5EO1xufVxuXG5mdW5jdGlvbiBkZWZsYXRlRW5kKHN0cm0pIHtcbiAgdmFyIHN0YXR1cztcblxuICBpZiAoIXN0cm0vKj09IFpfTlVMTCovIHx8ICFzdHJtLnN0YXRlLyo9PSBaX05VTEwqLykge1xuICAgIHJldHVybiBaX1NUUkVBTV9FUlJPUjtcbiAgfVxuXG4gIHN0YXR1cyA9IHN0cm0uc3RhdGUuc3RhdHVzO1xuICBpZiAoc3RhdHVzICE9PSBJTklUX1NUQVRFICYmXG4gICAgc3RhdHVzICE9PSBFWFRSQV9TVEFURSAmJlxuICAgIHN0YXR1cyAhPT0gTkFNRV9TVEFURSAmJlxuICAgIHN0YXR1cyAhPT0gQ09NTUVOVF9TVEFURSAmJlxuICAgIHN0YXR1cyAhPT0gSENSQ19TVEFURSAmJlxuICAgIHN0YXR1cyAhPT0gQlVTWV9TVEFURSAmJlxuICAgIHN0YXR1cyAhPT0gRklOSVNIX1NUQVRFXG4gICkge1xuICAgIHJldHVybiBlcnIoc3RybSwgWl9TVFJFQU1fRVJST1IpO1xuICB9XG5cbiAgc3RybS5zdGF0ZSA9IG51bGw7XG5cbiAgcmV0dXJuIHN0YXR1cyA9PT0gQlVTWV9TVEFURSA/IGVycihzdHJtLCBaX0RBVEFfRVJST1IpIDogWl9PSztcbn1cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogQ29weSB0aGUgc291cmNlIHN0YXRlIHRvIHRoZSBkZXN0aW5hdGlvbiBzdGF0ZVxuICovXG4vL2Z1bmN0aW9uIGRlZmxhdGVDb3B5KGRlc3QsIHNvdXJjZSkge1xuLy9cbi8vfVxuXG5leHBvcnRzLmRlZmxhdGVJbml0ID0gZGVmbGF0ZUluaXQ7XG5leHBvcnRzLmRlZmxhdGVJbml0MiA9IGRlZmxhdGVJbml0MjtcbmV4cG9ydHMuZGVmbGF0ZVJlc2V0ID0gZGVmbGF0ZVJlc2V0O1xuZXhwb3J0cy5kZWZsYXRlUmVzZXRLZWVwID0gZGVmbGF0ZVJlc2V0S2VlcDtcbmV4cG9ydHMuZGVmbGF0ZVNldEhlYWRlciA9IGRlZmxhdGVTZXRIZWFkZXI7XG5leHBvcnRzLmRlZmxhdGUgPSBkZWZsYXRlO1xuZXhwb3J0cy5kZWZsYXRlRW5kID0gZGVmbGF0ZUVuZDtcbmV4cG9ydHMuZGVmbGF0ZUluZm8gPSAncGFrbyBkZWZsYXRlIChmcm9tIE5vZGVjYSBwcm9qZWN0KSc7XG5cbi8qIE5vdCBpbXBsZW1lbnRlZFxuZXhwb3J0cy5kZWZsYXRlQm91bmQgPSBkZWZsYXRlQm91bmQ7XG5leHBvcnRzLmRlZmxhdGVDb3B5ID0gZGVmbGF0ZUNvcHk7XG5leHBvcnRzLmRlZmxhdGVTZXREaWN0aW9uYXJ5ID0gZGVmbGF0ZVNldERpY3Rpb25hcnk7XG5leHBvcnRzLmRlZmxhdGVQYXJhbXMgPSBkZWZsYXRlUGFyYW1zO1xuZXhwb3J0cy5kZWZsYXRlUGVuZGluZyA9IGRlZmxhdGVQZW5kaW5nO1xuZXhwb3J0cy5kZWZsYXRlUHJpbWUgPSBkZWZsYXRlUHJpbWU7XG5leHBvcnRzLmRlZmxhdGVUdW5lID0gZGVmbGF0ZVR1bmU7XG4qLyIsIid1c2Ugc3RyaWN0JztcblxuXG5mdW5jdGlvbiBHWmhlYWRlcigpIHtcbiAgLyogdHJ1ZSBpZiBjb21wcmVzc2VkIGRhdGEgYmVsaWV2ZWQgdG8gYmUgdGV4dCAqL1xuICB0aGlzLnRleHQgICAgICAgPSAwO1xuICAvKiBtb2RpZmljYXRpb24gdGltZSAqL1xuICB0aGlzLnRpbWUgICAgICAgPSAwO1xuICAvKiBleHRyYSBmbGFncyAobm90IHVzZWQgd2hlbiB3cml0aW5nIGEgZ3ppcCBmaWxlKSAqL1xuICB0aGlzLnhmbGFncyAgICAgPSAwO1xuICAvKiBvcGVyYXRpbmcgc3lzdGVtICovXG4gIHRoaXMub3MgICAgICAgICA9IDA7XG4gIC8qIHBvaW50ZXIgdG8gZXh0cmEgZmllbGQgb3IgWl9OVUxMIGlmIG5vbmUgKi9cbiAgdGhpcy5leHRyYSAgICAgID0gbnVsbDtcbiAgLyogZXh0cmEgZmllbGQgbGVuZ3RoICh2YWxpZCBpZiBleHRyYSAhPSBaX05VTEwpICovXG4gIHRoaXMuZXh0cmFfbGVuICA9IDA7IC8vIEFjdHVhbGx5LCB3ZSBkb24ndCBuZWVkIGl0IGluIEpTLFxuICAgICAgICAgICAgICAgICAgICAgICAvLyBidXQgbGVhdmUgZm9yIGZldyBjb2RlIG1vZGlmaWNhdGlvbnNcblxuICAvL1xuICAvLyBTZXR1cCBsaW1pdHMgaXMgbm90IG5lY2Vzc2FyeSBiZWNhdXNlIGluIGpzIHdlIHNob3VsZCBub3QgcHJlYWxsb2NhdGUgbWVtb3J5IFxuICAvLyBmb3IgaW5mbGF0ZSB1c2UgY29uc3RhbnQgbGltaXQgaW4gNjU1MzYgYnl0ZXNcbiAgLy9cblxuICAvKiBzcGFjZSBhdCBleHRyYSAob25seSB3aGVuIHJlYWRpbmcgaGVhZGVyKSAqL1xuICAvLyB0aGlzLmV4dHJhX21heCAgPSAwO1xuICAvKiBwb2ludGVyIHRvIHplcm8tdGVybWluYXRlZCBmaWxlIG5hbWUgb3IgWl9OVUxMICovXG4gIHRoaXMubmFtZSAgICAgICA9ICcnO1xuICAvKiBzcGFjZSBhdCBuYW1lIChvbmx5IHdoZW4gcmVhZGluZyBoZWFkZXIpICovXG4gIC8vIHRoaXMubmFtZV9tYXggICA9IDA7XG4gIC8qIHBvaW50ZXIgdG8gemVyby10ZXJtaW5hdGVkIGNvbW1lbnQgb3IgWl9OVUxMICovXG4gIHRoaXMuY29tbWVudCAgICA9ICcnO1xuICAvKiBzcGFjZSBhdCBjb21tZW50IChvbmx5IHdoZW4gcmVhZGluZyBoZWFkZXIpICovXG4gIC8vIHRoaXMuY29tbV9tYXggICA9IDA7XG4gIC8qIHRydWUgaWYgdGhlcmUgd2FzIG9yIHdpbGwgYmUgYSBoZWFkZXIgY3JjICovXG4gIHRoaXMuaGNyYyAgICAgICA9IDA7XG4gIC8qIHRydWUgd2hlbiBkb25lIHJlYWRpbmcgZ3ppcCBoZWFkZXIgKG5vdCB1c2VkIHdoZW4gd3JpdGluZyBhIGd6aXAgZmlsZSkgKi9cbiAgdGhpcy5kb25lICAgICAgID0gZmFsc2U7XG59XG5cbm1vZHVsZS5leHBvcnRzID0gR1poZWFkZXI7IiwiJ3VzZSBzdHJpY3QnO1xuXG4vLyBTZWUgc3RhdGUgZGVmcyBmcm9tIGluZmxhdGUuanNcbnZhciBCQUQgPSAzMDsgICAgICAgLyogZ290IGEgZGF0YSBlcnJvciAtLSByZW1haW4gaGVyZSB1bnRpbCByZXNldCAqL1xudmFyIFRZUEUgPSAxMjsgICAgICAvKiBpOiB3YWl0aW5nIGZvciB0eXBlIGJpdHMsIGluY2x1ZGluZyBsYXN0LWZsYWcgYml0ICovXG5cbi8qXG4gICBEZWNvZGUgbGl0ZXJhbCwgbGVuZ3RoLCBhbmQgZGlzdGFuY2UgY29kZXMgYW5kIHdyaXRlIG91dCB0aGUgcmVzdWx0aW5nXG4gICBsaXRlcmFsIGFuZCBtYXRjaCBieXRlcyB1bnRpbCBlaXRoZXIgbm90IGVub3VnaCBpbnB1dCBvciBvdXRwdXQgaXNcbiAgIGF2YWlsYWJsZSwgYW4gZW5kLW9mLWJsb2NrIGlzIGVuY291bnRlcmVkLCBvciBhIGRhdGEgZXJyb3IgaXMgZW5jb3VudGVyZWQuXG4gICBXaGVuIGxhcmdlIGVub3VnaCBpbnB1dCBhbmQgb3V0cHV0IGJ1ZmZlcnMgYXJlIHN1cHBsaWVkIHRvIGluZmxhdGUoKSwgZm9yXG4gICBleGFtcGxlLCBhIDE2SyBpbnB1dCBidWZmZXIgYW5kIGEgNjRLIG91dHB1dCBidWZmZXIsIG1vcmUgdGhhbiA5NSUgb2YgdGhlXG4gICBpbmZsYXRlIGV4ZWN1dGlvbiB0aW1lIGlzIHNwZW50IGluIHRoaXMgcm91dGluZS5cblxuICAgRW50cnkgYXNzdW1wdGlvbnM6XG5cbiAgICAgICAgc3RhdGUubW9kZSA9PT0gTEVOXG4gICAgICAgIHN0cm0uYXZhaWxfaW4gPj0gNlxuICAgICAgICBzdHJtLmF2YWlsX291dCA+PSAyNThcbiAgICAgICAgc3RhcnQgPj0gc3RybS5hdmFpbF9vdXRcbiAgICAgICAgc3RhdGUuYml0cyA8IDhcblxuICAgT24gcmV0dXJuLCBzdGF0ZS5tb2RlIGlzIG9uZSBvZjpcblxuICAgICAgICBMRU4gLS0gcmFuIG91dCBvZiBlbm91Z2ggb3V0cHV0IHNwYWNlIG9yIGVub3VnaCBhdmFpbGFibGUgaW5wdXRcbiAgICAgICAgVFlQRSAtLSByZWFjaGVkIGVuZCBvZiBibG9jayBjb2RlLCBpbmZsYXRlKCkgdG8gaW50ZXJwcmV0IG5leHQgYmxvY2tcbiAgICAgICAgQkFEIC0tIGVycm9yIGluIGJsb2NrIGRhdGFcblxuICAgTm90ZXM6XG5cbiAgICAtIFRoZSBtYXhpbXVtIGlucHV0IGJpdHMgdXNlZCBieSBhIGxlbmd0aC9kaXN0YW5jZSBwYWlyIGlzIDE1IGJpdHMgZm9yIHRoZVxuICAgICAgbGVuZ3RoIGNvZGUsIDUgYml0cyBmb3IgdGhlIGxlbmd0aCBleHRyYSwgMTUgYml0cyBmb3IgdGhlIGRpc3RhbmNlIGNvZGUsXG4gICAgICBhbmQgMTMgYml0cyBmb3IgdGhlIGRpc3RhbmNlIGV4dHJhLiAgVGhpcyB0b3RhbHMgNDggYml0cywgb3Igc2l4IGJ5dGVzLlxuICAgICAgVGhlcmVmb3JlIGlmIHN0cm0uYXZhaWxfaW4gPj0gNiwgdGhlbiB0aGVyZSBpcyBlbm91Z2ggaW5wdXQgdG8gYXZvaWRcbiAgICAgIGNoZWNraW5nIGZvciBhdmFpbGFibGUgaW5wdXQgd2hpbGUgZGVjb2RpbmcuXG5cbiAgICAtIFRoZSBtYXhpbXVtIGJ5dGVzIHRoYXQgYSBzaW5nbGUgbGVuZ3RoL2Rpc3RhbmNlIHBhaXIgY2FuIG91dHB1dCBpcyAyNThcbiAgICAgIGJ5dGVzLCB3aGljaCBpcyB0aGUgbWF4aW11bSBsZW5ndGggdGhhdCBjYW4gYmUgY29kZWQuICBpbmZsYXRlX2Zhc3QoKVxuICAgICAgcmVxdWlyZXMgc3RybS5hdmFpbF9vdXQgPj0gMjU4IGZvciBlYWNoIGxvb3AgdG8gYXZvaWQgY2hlY2tpbmcgZm9yXG4gICAgICBvdXRwdXQgc3BhY2UuXG4gKi9cbm1vZHVsZS5leHBvcnRzID0gZnVuY3Rpb24gaW5mbGF0ZV9mYXN0KHN0cm0sIHN0YXJ0KSB7XG4gIHZhciBzdGF0ZTtcbiAgdmFyIF9pbjsgICAgICAgICAgICAgICAgICAgIC8qIGxvY2FsIHN0cm0uaW5wdXQgKi9cbiAgdmFyIGxhc3Q7ICAgICAgICAgICAgICAgICAgIC8qIGhhdmUgZW5vdWdoIGlucHV0IHdoaWxlIGluIDwgbGFzdCAqL1xuICB2YXIgX291dDsgICAgICAgICAgICAgICAgICAgLyogbG9jYWwgc3RybS5vdXRwdXQgKi9cbiAgdmFyIGJlZzsgICAgICAgICAgICAgICAgICAgIC8qIGluZmxhdGUoKSdzIGluaXRpYWwgc3RybS5vdXRwdXQgKi9cbiAgdmFyIGVuZDsgICAgICAgICAgICAgICAgICAgIC8qIHdoaWxlIG91dCA8IGVuZCwgZW5vdWdoIHNwYWNlIGF2YWlsYWJsZSAqL1xuLy8jaWZkZWYgSU5GTEFURV9TVFJJQ1RcbiAgdmFyIGRtYXg7ICAgICAgICAgICAgICAgICAgIC8qIG1heGltdW0gZGlzdGFuY2UgZnJvbSB6bGliIGhlYWRlciAqL1xuLy8jZW5kaWZcbiAgdmFyIHdzaXplOyAgICAgICAgICAgICAgICAgIC8qIHdpbmRvdyBzaXplIG9yIHplcm8gaWYgbm90IHVzaW5nIHdpbmRvdyAqL1xuICB2YXIgd2hhdmU7ICAgICAgICAgICAgICAgICAgLyogdmFsaWQgYnl0ZXMgaW4gdGhlIHdpbmRvdyAqL1xuICB2YXIgd25leHQ7ICAgICAgICAgICAgICAgICAgLyogd2luZG93IHdyaXRlIGluZGV4ICovXG4gIHZhciB3aW5kb3c7ICAgICAgICAgICAgICAgICAvKiBhbGxvY2F0ZWQgc2xpZGluZyB3aW5kb3csIGlmIHdzaXplICE9IDAgKi9cbiAgdmFyIGhvbGQ7ICAgICAgICAgICAgICAgICAgIC8qIGxvY2FsIHN0cm0uaG9sZCAqL1xuICB2YXIgYml0czsgICAgICAgICAgICAgICAgICAgLyogbG9jYWwgc3RybS5iaXRzICovXG4gIHZhciBsY29kZTsgICAgICAgICAgICAgICAgICAvKiBsb2NhbCBzdHJtLmxlbmNvZGUgKi9cbiAgdmFyIGRjb2RlOyAgICAgICAgICAgICAgICAgIC8qIGxvY2FsIHN0cm0uZGlzdGNvZGUgKi9cbiAgdmFyIGxtYXNrOyAgICAgICAgICAgICAgICAgIC8qIG1hc2sgZm9yIGZpcnN0IGxldmVsIG9mIGxlbmd0aCBjb2RlcyAqL1xuICB2YXIgZG1hc2s7ICAgICAgICAgICAgICAgICAgLyogbWFzayBmb3IgZmlyc3QgbGV2ZWwgb2YgZGlzdGFuY2UgY29kZXMgKi9cbiAgdmFyIGhlcmU7ICAgICAgICAgICAgICAgICAgIC8qIHJldHJpZXZlZCB0YWJsZSBlbnRyeSAqL1xuICB2YXIgb3A7ICAgICAgICAgICAgICAgICAgICAgLyogY29kZSBiaXRzLCBvcGVyYXRpb24sIGV4dHJhIGJpdHMsIG9yICovXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiAgd2luZG93IHBvc2l0aW9uLCB3aW5kb3cgYnl0ZXMgdG8gY29weSAqL1xuICB2YXIgbGVuOyAgICAgICAgICAgICAgICAgICAgLyogbWF0Y2ggbGVuZ3RoLCB1bnVzZWQgYnl0ZXMgKi9cbiAgdmFyIGRpc3Q7ICAgICAgICAgICAgICAgICAgIC8qIG1hdGNoIGRpc3RhbmNlICovXG4gIHZhciBmcm9tOyAgICAgICAgICAgICAgICAgICAvKiB3aGVyZSB0byBjb3B5IG1hdGNoIGZyb20gKi9cbiAgdmFyIGZyb21fc291cmNlO1xuXG5cbiAgdmFyIGlucHV0LCBvdXRwdXQ7IC8vIEpTIHNwZWNpZmljLCBiZWNhdXNlIHdlIGhhdmUgbm8gcG9pbnRlcnNcblxuICAvKiBjb3B5IHN0YXRlIHRvIGxvY2FsIHZhcmlhYmxlcyAqL1xuICBzdGF0ZSA9IHN0cm0uc3RhdGU7XG4gIC8vaGVyZSA9IHN0YXRlLmhlcmU7XG4gIF9pbiA9IHN0cm0ubmV4dF9pbjtcbiAgaW5wdXQgPSBzdHJtLmlucHV0O1xuICBsYXN0ID0gX2luICsgKHN0cm0uYXZhaWxfaW4gLSA1KTtcbiAgX291dCA9IHN0cm0ubmV4dF9vdXQ7XG4gIG91dHB1dCA9IHN0cm0ub3V0cHV0O1xuICBiZWcgPSBfb3V0IC0gKHN0YXJ0IC0gc3RybS5hdmFpbF9vdXQpO1xuICBlbmQgPSBfb3V0ICsgKHN0cm0uYXZhaWxfb3V0IC0gMjU3KTtcbi8vI2lmZGVmIElORkxBVEVfU1RSSUNUXG4gIGRtYXggPSBzdGF0ZS5kbWF4O1xuLy8jZW5kaWZcbiAgd3NpemUgPSBzdGF0ZS53c2l6ZTtcbiAgd2hhdmUgPSBzdGF0ZS53aGF2ZTtcbiAgd25leHQgPSBzdGF0ZS53bmV4dDtcbiAgd2luZG93ID0gc3RhdGUud2luZG93O1xuICBob2xkID0gc3RhdGUuaG9sZDtcbiAgYml0cyA9IHN0YXRlLmJpdHM7XG4gIGxjb2RlID0gc3RhdGUubGVuY29kZTtcbiAgZGNvZGUgPSBzdGF0ZS5kaXN0Y29kZTtcbiAgbG1hc2sgPSAoMSA8PCBzdGF0ZS5sZW5iaXRzKSAtIDE7XG4gIGRtYXNrID0gKDEgPDwgc3RhdGUuZGlzdGJpdHMpIC0gMTtcblxuXG4gIC8qIGRlY29kZSBsaXRlcmFscyBhbmQgbGVuZ3RoL2Rpc3RhbmNlcyB1bnRpbCBlbmQtb2YtYmxvY2sgb3Igbm90IGVub3VnaFxuICAgICBpbnB1dCBkYXRhIG9yIG91dHB1dCBzcGFjZSAqL1xuXG4gIHRvcDpcbiAgZG8ge1xuICAgIGlmIChiaXRzIDwgMTUpIHtcbiAgICAgIGhvbGQgKz0gaW5wdXRbX2luKytdIDw8IGJpdHM7XG4gICAgICBiaXRzICs9IDg7XG4gICAgICBob2xkICs9IGlucHV0W19pbisrXSA8PCBiaXRzO1xuICAgICAgYml0cyArPSA4O1xuICAgIH1cblxuICAgIGhlcmUgPSBsY29kZVtob2xkICYgbG1hc2tdO1xuXG4gICAgZG9sZW46XG4gICAgZm9yICg7OykgeyAvLyBHb3RvIGVtdWxhdGlvblxuICAgICAgb3AgPSBoZXJlID4+PiAyNC8qaGVyZS5iaXRzKi87XG4gICAgICBob2xkID4+Pj0gb3A7XG4gICAgICBiaXRzIC09IG9wO1xuICAgICAgb3AgPSAoaGVyZSA+Pj4gMTYpICYgMHhmZi8qaGVyZS5vcCovO1xuICAgICAgaWYgKG9wID09PSAwKSB7ICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBsaXRlcmFsICovXG4gICAgICAgIC8vVHJhY2V2digoc3RkZXJyLCBoZXJlLnZhbCA+PSAweDIwICYmIGhlcmUudmFsIDwgMHg3ZiA/XG4gICAgICAgIC8vICAgICAgICBcImluZmxhdGU6ICAgICAgICAgbGl0ZXJhbCAnJWMnXFxuXCIgOlxuICAgICAgICAvLyAgICAgICAgXCJpbmZsYXRlOiAgICAgICAgIGxpdGVyYWwgMHglMDJ4XFxuXCIsIGhlcmUudmFsKSk7XG4gICAgICAgIG91dHB1dFtfb3V0KytdID0gaGVyZSAmIDB4ZmZmZi8qaGVyZS52YWwqLztcbiAgICAgIH1cbiAgICAgIGVsc2UgaWYgKG9wICYgMTYpIHsgICAgICAgICAgICAgICAgICAgICAvKiBsZW5ndGggYmFzZSAqL1xuICAgICAgICBsZW4gPSBoZXJlICYgMHhmZmZmLypoZXJlLnZhbCovO1xuICAgICAgICBvcCAmPSAxNTsgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBudW1iZXIgb2YgZXh0cmEgYml0cyAqL1xuICAgICAgICBpZiAob3ApIHtcbiAgICAgICAgICBpZiAoYml0cyA8IG9wKSB7XG4gICAgICAgICAgICBob2xkICs9IGlucHV0W19pbisrXSA8PCBiaXRzO1xuICAgICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAgIH1cbiAgICAgICAgICBsZW4gKz0gaG9sZCAmICgoMSA8PCBvcCkgLSAxKTtcbiAgICAgICAgICBob2xkID4+Pj0gb3A7XG4gICAgICAgICAgYml0cyAtPSBvcDtcbiAgICAgICAgfVxuICAgICAgICAvL1RyYWNldnYoKHN0ZGVyciwgXCJpbmZsYXRlOiAgICAgICAgIGxlbmd0aCAldVxcblwiLCBsZW4pKTtcbiAgICAgICAgaWYgKGJpdHMgPCAxNSkge1xuICAgICAgICAgIGhvbGQgKz0gaW5wdXRbX2luKytdIDw8IGJpdHM7XG4gICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAgIGhvbGQgKz0gaW5wdXRbX2luKytdIDw8IGJpdHM7XG4gICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICB9XG4gICAgICAgIGhlcmUgPSBkY29kZVtob2xkICYgZG1hc2tdO1xuXG4gICAgICAgIGRvZGlzdDpcbiAgICAgICAgZm9yICg7OykgeyAvLyBnb3RvIGVtdWxhdGlvblxuICAgICAgICAgIG9wID0gaGVyZSA+Pj4gMjQvKmhlcmUuYml0cyovO1xuICAgICAgICAgIGhvbGQgPj4+PSBvcDtcbiAgICAgICAgICBiaXRzIC09IG9wO1xuICAgICAgICAgIG9wID0gKGhlcmUgPj4+IDE2KSAmIDB4ZmYvKmhlcmUub3AqLztcblxuICAgICAgICAgIGlmIChvcCAmIDE2KSB7ICAgICAgICAgICAgICAgICAgICAgIC8qIGRpc3RhbmNlIGJhc2UgKi9cbiAgICAgICAgICAgIGRpc3QgPSBoZXJlICYgMHhmZmZmLypoZXJlLnZhbCovO1xuICAgICAgICAgICAgb3AgJj0gMTU7ICAgICAgICAgICAgICAgICAgICAgICAvKiBudW1iZXIgb2YgZXh0cmEgYml0cyAqL1xuICAgICAgICAgICAgaWYgKGJpdHMgPCBvcCkge1xuICAgICAgICAgICAgICBob2xkICs9IGlucHV0W19pbisrXSA8PCBiaXRzO1xuICAgICAgICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgICAgICAgIGlmIChiaXRzIDwgb3ApIHtcbiAgICAgICAgICAgICAgICBob2xkICs9IGlucHV0W19pbisrXSA8PCBiaXRzO1xuICAgICAgICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZGlzdCArPSBob2xkICYgKCgxIDw8IG9wKSAtIDEpO1xuLy8jaWZkZWYgSU5GTEFURV9TVFJJQ1RcbiAgICAgICAgICAgIGlmIChkaXN0ID4gZG1heCkge1xuICAgICAgICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgYmFjayc7XG4gICAgICAgICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgICAgICAgIGJyZWFrIHRvcDtcbiAgICAgICAgICAgIH1cbi8vI2VuZGlmXG4gICAgICAgICAgICBob2xkID4+Pj0gb3A7XG4gICAgICAgICAgICBiaXRzIC09IG9wO1xuICAgICAgICAgICAgLy9UcmFjZXZ2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgICAgICBkaXN0YW5jZSAldVxcblwiLCBkaXN0KSk7XG4gICAgICAgICAgICBvcCA9IF9vdXQgLSBiZWc7ICAgICAgICAgICAgICAgIC8qIG1heCBkaXN0YW5jZSBpbiBvdXRwdXQgKi9cbiAgICAgICAgICAgIGlmIChkaXN0ID4gb3ApIHsgICAgICAgICAgICAgICAgLyogc2VlIGlmIGNvcHkgZnJvbSB3aW5kb3cgKi9cbiAgICAgICAgICAgICAgb3AgPSBkaXN0IC0gb3A7ICAgICAgICAgICAgICAgLyogZGlzdGFuY2UgYmFjayBpbiB3aW5kb3cgKi9cbiAgICAgICAgICAgICAgaWYgKG9wID4gd2hhdmUpIHtcbiAgICAgICAgICAgICAgICBpZiAoc3RhdGUuc2FuZSkge1xuICAgICAgICAgICAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBkaXN0YW5jZSB0b28gZmFyIGJhY2snO1xuICAgICAgICAgICAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgICAgICAgICAgIGJyZWFrIHRvcDtcbiAgICAgICAgICAgICAgICB9XG5cbi8vICghKSBUaGlzIGJsb2NrIGlzIGRpc2FibGVkIGluIHpsaWIgZGVmYWlsdHMsXG4vLyBkb24ndCBlbmFibGUgaXQgZm9yIGJpbmFyeSBjb21wYXRpYmlsaXR5XG4vLyNpZmRlZiBJTkZMQVRFX0FMTE9XX0lOVkFMSURfRElTVEFOQ0VfVE9PRkFSX0FSUlJcbi8vICAgICAgICAgICAgICAgIGlmIChsZW4gPD0gb3AgLSB3aGF2ZSkge1xuLy8gICAgICAgICAgICAgICAgICBkbyB7XG4vLyAgICAgICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSAwO1xuLy8gICAgICAgICAgICAgICAgICB9IHdoaWxlICgtLWxlbik7XG4vLyAgICAgICAgICAgICAgICAgIGNvbnRpbnVlIHRvcDtcbi8vICAgICAgICAgICAgICAgIH1cbi8vICAgICAgICAgICAgICAgIGxlbiAtPSBvcCAtIHdoYXZlO1xuLy8gICAgICAgICAgICAgICAgZG8ge1xuLy8gICAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IDA7XG4vLyAgICAgICAgICAgICAgICB9IHdoaWxlICgtLW9wID4gd2hhdmUpO1xuLy8gICAgICAgICAgICAgICAgaWYgKG9wID09PSAwKSB7XG4vLyAgICAgICAgICAgICAgICAgIGZyb20gPSBfb3V0IC0gZGlzdDtcbi8vICAgICAgICAgICAgICAgICAgZG8ge1xuLy8gICAgICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gb3V0cHV0W2Zyb20rK107XG4vLyAgICAgICAgICAgICAgICAgIH0gd2hpbGUgKC0tbGVuKTtcbi8vICAgICAgICAgICAgICAgICAgY29udGludWUgdG9wO1xuLy8gICAgICAgICAgICAgICAgfVxuLy8jZW5kaWZcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICBmcm9tID0gMDsgLy8gd2luZG93IGluZGV4XG4gICAgICAgICAgICAgIGZyb21fc291cmNlID0gd2luZG93O1xuICAgICAgICAgICAgICBpZiAod25leHQgPT09IDApIHsgICAgICAgICAgIC8qIHZlcnkgY29tbW9uIGNhc2UgKi9cbiAgICAgICAgICAgICAgICBmcm9tICs9IHdzaXplIC0gb3A7XG4gICAgICAgICAgICAgICAgaWYgKG9wIDwgbGVuKSB7ICAgICAgICAgLyogc29tZSBmcm9tIHdpbmRvdyAqL1xuICAgICAgICAgICAgICAgICAgbGVuIC09IG9wO1xuICAgICAgICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IHdpbmRvd1tmcm9tKytdO1xuICAgICAgICAgICAgICAgICAgfSB3aGlsZSAoLS1vcCk7XG4gICAgICAgICAgICAgICAgICBmcm9tID0gX291dCAtIGRpc3Q7ICAvKiByZXN0IGZyb20gb3V0cHV0ICovXG4gICAgICAgICAgICAgICAgICBmcm9tX3NvdXJjZSA9IG91dHB1dDtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgZWxzZSBpZiAod25leHQgPCBvcCkgeyAgICAgIC8qIHdyYXAgYXJvdW5kIHdpbmRvdyAqL1xuICAgICAgICAgICAgICAgIGZyb20gKz0gd3NpemUgKyB3bmV4dCAtIG9wO1xuICAgICAgICAgICAgICAgIG9wIC09IHduZXh0O1xuICAgICAgICAgICAgICAgIGlmIChvcCA8IGxlbikgeyAgICAgICAgIC8qIHNvbWUgZnJvbSBlbmQgb2Ygd2luZG93ICovXG4gICAgICAgICAgICAgICAgICBsZW4gLT0gb3A7XG4gICAgICAgICAgICAgICAgICBkbyB7XG4gICAgICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gd2luZG93W2Zyb20rK107XG4gICAgICAgICAgICAgICAgICB9IHdoaWxlICgtLW9wKTtcbiAgICAgICAgICAgICAgICAgIGZyb20gPSAwO1xuICAgICAgICAgICAgICAgICAgaWYgKHduZXh0IDwgbGVuKSB7ICAvKiBzb21lIGZyb20gc3RhcnQgb2Ygd2luZG93ICovXG4gICAgICAgICAgICAgICAgICAgIG9wID0gd25leHQ7XG4gICAgICAgICAgICAgICAgICAgIGxlbiAtPSBvcDtcbiAgICAgICAgICAgICAgICAgICAgZG8ge1xuICAgICAgICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gd2luZG93W2Zyb20rK107XG4gICAgICAgICAgICAgICAgICAgIH0gd2hpbGUgKC0tb3ApO1xuICAgICAgICAgICAgICAgICAgICBmcm9tID0gX291dCAtIGRpc3Q7ICAgICAgLyogcmVzdCBmcm9tIG91dHB1dCAqL1xuICAgICAgICAgICAgICAgICAgICBmcm9tX3NvdXJjZSA9IG91dHB1dDtcbiAgICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgZWxzZSB7ICAgICAgICAgICAgICAgICAgICAgIC8qIGNvbnRpZ3VvdXMgaW4gd2luZG93ICovXG4gICAgICAgICAgICAgICAgZnJvbSArPSB3bmV4dCAtIG9wO1xuICAgICAgICAgICAgICAgIGlmIChvcCA8IGxlbikgeyAgICAgICAgIC8qIHNvbWUgZnJvbSB3aW5kb3cgKi9cbiAgICAgICAgICAgICAgICAgIGxlbiAtPSBvcDtcbiAgICAgICAgICAgICAgICAgIGRvIHtcbiAgICAgICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSB3aW5kb3dbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICAgIH0gd2hpbGUgKC0tb3ApO1xuICAgICAgICAgICAgICAgICAgZnJvbSA9IF9vdXQgLSBkaXN0OyAgLyogcmVzdCBmcm9tIG91dHB1dCAqL1xuICAgICAgICAgICAgICAgICAgZnJvbV9zb3VyY2UgPSBvdXRwdXQ7XG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHdoaWxlIChsZW4gPiAyKSB7XG4gICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSBmcm9tX3NvdXJjZVtmcm9tKytdO1xuICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gZnJvbV9zb3VyY2VbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IGZyb21fc291cmNlW2Zyb20rK107XG4gICAgICAgICAgICAgICAgbGVuIC09IDM7XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgaWYgKGxlbikge1xuICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gZnJvbV9zb3VyY2VbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICBpZiAobGVuID4gMSkge1xuICAgICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSBmcm9tX3NvdXJjZVtmcm9tKytdO1xuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICAgIGZyb20gPSBfb3V0IC0gZGlzdDsgICAgICAgICAgLyogY29weSBkaXJlY3QgZnJvbSBvdXRwdXQgKi9cbiAgICAgICAgICAgICAgZG8geyAgICAgICAgICAgICAgICAgICAgICAgIC8qIG1pbmltdW0gbGVuZ3RoIGlzIHRocmVlICovXG4gICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSBvdXRwdXRbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICBvdXRwdXRbX291dCsrXSA9IG91dHB1dFtmcm9tKytdO1xuICAgICAgICAgICAgICAgIG91dHB1dFtfb3V0KytdID0gb3V0cHV0W2Zyb20rK107XG4gICAgICAgICAgICAgICAgbGVuIC09IDM7XG4gICAgICAgICAgICAgIH0gd2hpbGUgKGxlbiA+IDIpO1xuICAgICAgICAgICAgICBpZiAobGVuKSB7XG4gICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSBvdXRwdXRbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICBpZiAobGVuID4gMSkge1xuICAgICAgICAgICAgICAgICAgb3V0cHV0W19vdXQrK10gPSBvdXRwdXRbZnJvbSsrXTtcbiAgICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgICAgZWxzZSBpZiAoKG9wICYgNjQpID09PSAwKSB7ICAgICAgICAgIC8qIDJuZCBsZXZlbCBkaXN0YW5jZSBjb2RlICovXG4gICAgICAgICAgICBoZXJlID0gZGNvZGVbKGhlcmUgJiAweGZmZmYpLypoZXJlLnZhbCovICsgKGhvbGQgJiAoKDEgPDwgb3ApIC0gMSkpXTtcbiAgICAgICAgICAgIGNvbnRpbnVlIGRvZGlzdDtcbiAgICAgICAgICB9XG4gICAgICAgICAgZWxzZSB7XG4gICAgICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGRpc3RhbmNlIGNvZGUnO1xuICAgICAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgICAgIGJyZWFrIHRvcDtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBicmVhazsgLy8gbmVlZCB0byBlbXVsYXRlIGdvdG8gdmlhIFwiY29udGludWVcIlxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBlbHNlIGlmICgob3AgJiA2NCkgPT09IDApIHsgICAgICAgICAgICAgIC8qIDJuZCBsZXZlbCBsZW5ndGggY29kZSAqL1xuICAgICAgICBoZXJlID0gbGNvZGVbKGhlcmUgJiAweGZmZmYpLypoZXJlLnZhbCovICsgKGhvbGQgJiAoKDEgPDwgb3ApIC0gMSkpXTtcbiAgICAgICAgY29udGludWUgZG9sZW47XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChvcCAmIDMyKSB7ICAgICAgICAgICAgICAgICAgICAgLyogZW5kLW9mLWJsb2NrICovXG4gICAgICAgIC8vVHJhY2V2digoc3RkZXJyLCBcImluZmxhdGU6ICAgICAgICAgZW5kIG9mIGJsb2NrXFxuXCIpKTtcbiAgICAgICAgc3RhdGUubW9kZSA9IFRZUEU7XG4gICAgICAgIGJyZWFrIHRvcDtcbiAgICAgIH1cbiAgICAgIGVsc2Uge1xuICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGxpdGVyYWwvbGVuZ3RoIGNvZGUnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhayB0b3A7XG4gICAgICB9XG5cbiAgICAgIGJyZWFrOyAvLyBuZWVkIHRvIGVtdWxhdGUgZ290byB2aWEgXCJjb250aW51ZVwiXG4gICAgfVxuICB9IHdoaWxlIChfaW4gPCBsYXN0ICYmIF9vdXQgPCBlbmQpO1xuXG4gIC8qIHJldHVybiB1bnVzZWQgYnl0ZXMgKG9uIGVudHJ5LCBiaXRzIDwgOCwgc28gaW4gd29uJ3QgZ28gdG9vIGZhciBiYWNrKSAqL1xuICBsZW4gPSBiaXRzID4+IDM7XG4gIF9pbiAtPSBsZW47XG4gIGJpdHMgLT0gbGVuIDw8IDM7XG4gIGhvbGQgJj0gKDEgPDwgYml0cykgLSAxO1xuXG4gIC8qIHVwZGF0ZSBzdGF0ZSBhbmQgcmV0dXJuICovXG4gIHN0cm0ubmV4dF9pbiA9IF9pbjtcbiAgc3RybS5uZXh0X291dCA9IF9vdXQ7XG4gIHN0cm0uYXZhaWxfaW4gPSAoX2luIDwgbGFzdCA/IDUgKyAobGFzdCAtIF9pbikgOiA1IC0gKF9pbiAtIGxhc3QpKTtcbiAgc3RybS5hdmFpbF9vdXQgPSAoX291dCA8IGVuZCA/IDI1NyArIChlbmQgLSBfb3V0KSA6IDI1NyAtIChfb3V0IC0gZW5kKSk7XG4gIHN0YXRlLmhvbGQgPSBob2xkO1xuICBzdGF0ZS5iaXRzID0gYml0cztcbiAgcmV0dXJuO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy9jb21tb24nKTtcbnZhciBhZGxlcjMyID0gcmVxdWlyZSgnLi9hZGxlcjMyJyk7XG52YXIgY3JjMzIgICA9IHJlcXVpcmUoJy4vY3JjMzInKTtcbnZhciBpbmZsYXRlX2Zhc3QgPSByZXF1aXJlKCcuL2luZmZhc3QnKTtcbnZhciBpbmZsYXRlX3RhYmxlID0gcmVxdWlyZSgnLi9pbmZ0cmVlcycpO1xuXG52YXIgQ09ERVMgPSAwO1xudmFyIExFTlMgPSAxO1xudmFyIERJU1RTID0gMjtcblxuLyogUHVibGljIGNvbnN0YW50cyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG5cblxuLyogQWxsb3dlZCBmbHVzaCB2YWx1ZXM7IHNlZSBkZWZsYXRlKCkgYW5kIGluZmxhdGUoKSBiZWxvdyBmb3IgZGV0YWlscyAqL1xuLy92YXIgWl9OT19GTFVTSCAgICAgID0gMDtcbi8vdmFyIFpfUEFSVElBTF9GTFVTSCA9IDE7XG4vL3ZhciBaX1NZTkNfRkxVU0ggICAgPSAyO1xuLy92YXIgWl9GVUxMX0ZMVVNIICAgID0gMztcbnZhciBaX0ZJTklTSCAgICAgICAgPSA0O1xudmFyIFpfQkxPQ0sgICAgICAgICA9IDU7XG52YXIgWl9UUkVFUyAgICAgICAgID0gNjtcblxuXG4vKiBSZXR1cm4gY29kZXMgZm9yIHRoZSBjb21wcmVzc2lvbi9kZWNvbXByZXNzaW9uIGZ1bmN0aW9ucy4gTmVnYXRpdmUgdmFsdWVzXG4gKiBhcmUgZXJyb3JzLCBwb3NpdGl2ZSB2YWx1ZXMgYXJlIHVzZWQgZm9yIHNwZWNpYWwgYnV0IG5vcm1hbCBldmVudHMuXG4gKi9cbnZhciBaX09LICAgICAgICAgICAgPSAwO1xudmFyIFpfU1RSRUFNX0VORCAgICA9IDE7XG52YXIgWl9ORUVEX0RJQ1QgICAgID0gMjtcbi8vdmFyIFpfRVJSTk8gICAgICAgICA9IC0xO1xudmFyIFpfU1RSRUFNX0VSUk9SICA9IC0yO1xudmFyIFpfREFUQV9FUlJPUiAgICA9IC0zO1xudmFyIFpfTUVNX0VSUk9SICAgICA9IC00O1xudmFyIFpfQlVGX0VSUk9SICAgICA9IC01O1xuLy92YXIgWl9WRVJTSU9OX0VSUk9SID0gLTY7XG5cbi8qIFRoZSBkZWZsYXRlIGNvbXByZXNzaW9uIG1ldGhvZCAqL1xudmFyIFpfREVGTEFURUQgID0gODtcblxuXG4vKiBTVEFURVMgPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0qL1xuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cblxuXG52YXIgICAgSEVBRCA9IDE7ICAgICAgIC8qIGk6IHdhaXRpbmcgZm9yIG1hZ2ljIGhlYWRlciAqL1xudmFyICAgIEZMQUdTID0gMjsgICAgICAvKiBpOiB3YWl0aW5nIGZvciBtZXRob2QgYW5kIGZsYWdzIChnemlwKSAqL1xudmFyICAgIFRJTUUgPSAzOyAgICAgICAvKiBpOiB3YWl0aW5nIGZvciBtb2RpZmljYXRpb24gdGltZSAoZ3ppcCkgKi9cbnZhciAgICBPUyA9IDQ7ICAgICAgICAgLyogaTogd2FpdGluZyBmb3IgZXh0cmEgZmxhZ3MgYW5kIG9wZXJhdGluZyBzeXN0ZW0gKGd6aXApICovXG52YXIgICAgRVhMRU4gPSA1OyAgICAgIC8qIGk6IHdhaXRpbmcgZm9yIGV4dHJhIGxlbmd0aCAoZ3ppcCkgKi9cbnZhciAgICBFWFRSQSA9IDY7ICAgICAgLyogaTogd2FpdGluZyBmb3IgZXh0cmEgYnl0ZXMgKGd6aXApICovXG52YXIgICAgTkFNRSA9IDc7ICAgICAgIC8qIGk6IHdhaXRpbmcgZm9yIGVuZCBvZiBmaWxlIG5hbWUgKGd6aXApICovXG52YXIgICAgQ09NTUVOVCA9IDg7ICAgIC8qIGk6IHdhaXRpbmcgZm9yIGVuZCBvZiBjb21tZW50IChnemlwKSAqL1xudmFyICAgIEhDUkMgPSA5OyAgICAgICAvKiBpOiB3YWl0aW5nIGZvciBoZWFkZXIgY3JjIChnemlwKSAqL1xudmFyICAgIERJQ1RJRCA9IDEwOyAgICAvKiBpOiB3YWl0aW5nIGZvciBkaWN0aW9uYXJ5IGNoZWNrIHZhbHVlICovXG52YXIgICAgRElDVCA9IDExOyAgICAgIC8qIHdhaXRpbmcgZm9yIGluZmxhdGVTZXREaWN0aW9uYXJ5KCkgY2FsbCAqL1xudmFyICAgICAgICBUWVBFID0gMTI7ICAgICAgLyogaTogd2FpdGluZyBmb3IgdHlwZSBiaXRzLCBpbmNsdWRpbmcgbGFzdC1mbGFnIGJpdCAqL1xudmFyICAgICAgICBUWVBFRE8gPSAxMzsgICAgLyogaTogc2FtZSwgYnV0IHNraXAgY2hlY2sgdG8gZXhpdCBpbmZsYXRlIG9uIG5ldyBibG9jayAqL1xudmFyICAgICAgICBTVE9SRUQgPSAxNDsgICAgLyogaTogd2FpdGluZyBmb3Igc3RvcmVkIHNpemUgKGxlbmd0aCBhbmQgY29tcGxlbWVudCkgKi9cbnZhciAgICAgICAgQ09QWV8gPSAxNTsgICAgIC8qIGkvbzogc2FtZSBhcyBDT1BZIGJlbG93LCBidXQgb25seSBmaXJzdCB0aW1lIGluICovXG52YXIgICAgICAgIENPUFkgPSAxNjsgICAgICAvKiBpL286IHdhaXRpbmcgZm9yIGlucHV0IG9yIG91dHB1dCB0byBjb3B5IHN0b3JlZCBibG9jayAqL1xudmFyICAgICAgICBUQUJMRSA9IDE3OyAgICAgLyogaTogd2FpdGluZyBmb3IgZHluYW1pYyBibG9jayB0YWJsZSBsZW5ndGhzICovXG52YXIgICAgICAgIExFTkxFTlMgPSAxODsgICAvKiBpOiB3YWl0aW5nIGZvciBjb2RlIGxlbmd0aCBjb2RlIGxlbmd0aHMgKi9cbnZhciAgICAgICAgQ09ERUxFTlMgPSAxOTsgIC8qIGk6IHdhaXRpbmcgZm9yIGxlbmd0aC9saXQgYW5kIGRpc3RhbmNlIGNvZGUgbGVuZ3RocyAqL1xudmFyICAgICAgICAgICAgTEVOXyA9IDIwOyAgICAgIC8qIGk6IHNhbWUgYXMgTEVOIGJlbG93LCBidXQgb25seSBmaXJzdCB0aW1lIGluICovXG52YXIgICAgICAgICAgICBMRU4gPSAyMTsgICAgICAgLyogaTogd2FpdGluZyBmb3IgbGVuZ3RoL2xpdC9lb2IgY29kZSAqL1xudmFyICAgICAgICAgICAgTEVORVhUID0gMjI7ICAgIC8qIGk6IHdhaXRpbmcgZm9yIGxlbmd0aCBleHRyYSBiaXRzICovXG52YXIgICAgICAgICAgICBESVNUID0gMjM7ICAgICAgLyogaTogd2FpdGluZyBmb3IgZGlzdGFuY2UgY29kZSAqL1xudmFyICAgICAgICAgICAgRElTVEVYVCA9IDI0OyAgIC8qIGk6IHdhaXRpbmcgZm9yIGRpc3RhbmNlIGV4dHJhIGJpdHMgKi9cbnZhciAgICAgICAgICAgIE1BVENIID0gMjU7ICAgICAvKiBvOiB3YWl0aW5nIGZvciBvdXRwdXQgc3BhY2UgdG8gY29weSBzdHJpbmcgKi9cbnZhciAgICAgICAgICAgIExJVCA9IDI2OyAgICAgICAvKiBvOiB3YWl0aW5nIGZvciBvdXRwdXQgc3BhY2UgdG8gd3JpdGUgbGl0ZXJhbCAqL1xudmFyICAgIENIRUNLID0gMjc7ICAgICAvKiBpOiB3YWl0aW5nIGZvciAzMi1iaXQgY2hlY2sgdmFsdWUgKi9cbnZhciAgICBMRU5HVEggPSAyODsgICAgLyogaTogd2FpdGluZyBmb3IgMzItYml0IGxlbmd0aCAoZ3ppcCkgKi9cbnZhciAgICBET05FID0gMjk7ICAgICAgLyogZmluaXNoZWQgY2hlY2ssIGRvbmUgLS0gcmVtYWluIGhlcmUgdW50aWwgcmVzZXQgKi9cbnZhciAgICBCQUQgPSAzMDsgICAgICAgLyogZ290IGEgZGF0YSBlcnJvciAtLSByZW1haW4gaGVyZSB1bnRpbCByZXNldCAqL1xudmFyICAgIE1FTSA9IDMxOyAgICAgICAvKiBnb3QgYW4gaW5mbGF0ZSgpIG1lbW9yeSBlcnJvciAtLSByZW1haW4gaGVyZSB1bnRpbCByZXNldCAqL1xudmFyICAgIFNZTkMgPSAzMjsgICAgICAvKiBsb29raW5nIGZvciBzeW5jaHJvbml6YXRpb24gYnl0ZXMgdG8gcmVzdGFydCBpbmZsYXRlKCkgKi9cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cblxuXG5cbnZhciBFTk9VR0hfTEVOUyA9IDg1MjtcbnZhciBFTk9VR0hfRElTVFMgPSA1OTI7XG4vL3ZhciBFTk9VR0ggPSAgKEVOT1VHSF9MRU5TK0VOT1VHSF9ESVNUUyk7XG5cbnZhciBNQVhfV0JJVFMgPSAxNTtcbi8qIDMySyBMWjc3IHdpbmRvdyAqL1xudmFyIERFRl9XQklUUyA9IE1BWF9XQklUUztcblxuXG5mdW5jdGlvbiBaU1dBUDMyKHEpIHtcbiAgcmV0dXJuICAoKChxID4+PiAyNCkgJiAweGZmKSArXG4gICAgICAgICAgKChxID4+PiA4KSAmIDB4ZmYwMCkgK1xuICAgICAgICAgICgocSAmIDB4ZmYwMCkgPDwgOCkgK1xuICAgICAgICAgICgocSAmIDB4ZmYpIDw8IDI0KSk7XG59XG5cblxuZnVuY3Rpb24gSW5mbGF0ZVN0YXRlKCkge1xuICB0aGlzLm1vZGUgPSAwOyAgICAgICAgICAgICAvKiBjdXJyZW50IGluZmxhdGUgbW9kZSAqL1xuICB0aGlzLmxhc3QgPSBmYWxzZTsgICAgICAgICAgLyogdHJ1ZSBpZiBwcm9jZXNzaW5nIGxhc3QgYmxvY2sgKi9cbiAgdGhpcy53cmFwID0gMDsgICAgICAgICAgICAgIC8qIGJpdCAwIHRydWUgZm9yIHpsaWIsIGJpdCAxIHRydWUgZm9yIGd6aXAgKi9cbiAgdGhpcy5oYXZlZGljdCA9IGZhbHNlOyAgICAgIC8qIHRydWUgaWYgZGljdGlvbmFyeSBwcm92aWRlZCAqL1xuICB0aGlzLmZsYWdzID0gMDsgICAgICAgICAgICAgLyogZ3ppcCBoZWFkZXIgbWV0aG9kIGFuZCBmbGFncyAoMCBpZiB6bGliKSAqL1xuICB0aGlzLmRtYXggPSAwOyAgICAgICAgICAgICAgLyogemxpYiBoZWFkZXIgbWF4IGRpc3RhbmNlIChJTkZMQVRFX1NUUklDVCkgKi9cbiAgdGhpcy5jaGVjayA9IDA7ICAgICAgICAgICAgIC8qIHByb3RlY3RlZCBjb3B5IG9mIGNoZWNrIHZhbHVlICovXG4gIHRoaXMudG90YWwgPSAwOyAgICAgICAgICAgICAvKiBwcm90ZWN0ZWQgY29weSBvZiBvdXRwdXQgY291bnQgKi9cbiAgLy8gVE9ETzogbWF5IGJlIHt9XG4gIHRoaXMuaGVhZCA9IG51bGw7ICAgICAgICAgICAvKiB3aGVyZSB0byBzYXZlIGd6aXAgaGVhZGVyIGluZm9ybWF0aW9uICovXG5cbiAgLyogc2xpZGluZyB3aW5kb3cgKi9cbiAgdGhpcy53Yml0cyA9IDA7ICAgICAgICAgICAgIC8qIGxvZyBiYXNlIDIgb2YgcmVxdWVzdGVkIHdpbmRvdyBzaXplICovXG4gIHRoaXMud3NpemUgPSAwOyAgICAgICAgICAgICAvKiB3aW5kb3cgc2l6ZSBvciB6ZXJvIGlmIG5vdCB1c2luZyB3aW5kb3cgKi9cbiAgdGhpcy53aGF2ZSA9IDA7ICAgICAgICAgICAgIC8qIHZhbGlkIGJ5dGVzIGluIHRoZSB3aW5kb3cgKi9cbiAgdGhpcy53bmV4dCA9IDA7ICAgICAgICAgICAgIC8qIHdpbmRvdyB3cml0ZSBpbmRleCAqL1xuICB0aGlzLndpbmRvdyA9IG51bGw7ICAgICAgICAgLyogYWxsb2NhdGVkIHNsaWRpbmcgd2luZG93LCBpZiBuZWVkZWQgKi9cblxuICAvKiBiaXQgYWNjdW11bGF0b3IgKi9cbiAgdGhpcy5ob2xkID0gMDsgICAgICAgICAgICAgIC8qIGlucHV0IGJpdCBhY2N1bXVsYXRvciAqL1xuICB0aGlzLmJpdHMgPSAwOyAgICAgICAgICAgICAgLyogbnVtYmVyIG9mIGJpdHMgaW4gXCJpblwiICovXG5cbiAgLyogZm9yIHN0cmluZyBhbmQgc3RvcmVkIGJsb2NrIGNvcHlpbmcgKi9cbiAgdGhpcy5sZW5ndGggPSAwOyAgICAgICAgICAgIC8qIGxpdGVyYWwgb3IgbGVuZ3RoIG9mIGRhdGEgdG8gY29weSAqL1xuICB0aGlzLm9mZnNldCA9IDA7ICAgICAgICAgICAgLyogZGlzdGFuY2UgYmFjayB0byBjb3B5IHN0cmluZyBmcm9tICovXG5cbiAgLyogZm9yIHRhYmxlIGFuZCBjb2RlIGRlY29kaW5nICovXG4gIHRoaXMuZXh0cmEgPSAwOyAgICAgICAgICAgICAvKiBleHRyYSBiaXRzIG5lZWRlZCAqL1xuXG4gIC8qIGZpeGVkIGFuZCBkeW5hbWljIGNvZGUgdGFibGVzICovXG4gIHRoaXMubGVuY29kZSA9IG51bGw7ICAgICAgICAgIC8qIHN0YXJ0aW5nIHRhYmxlIGZvciBsZW5ndGgvbGl0ZXJhbCBjb2RlcyAqL1xuICB0aGlzLmRpc3Rjb2RlID0gbnVsbDsgICAgICAgICAvKiBzdGFydGluZyB0YWJsZSBmb3IgZGlzdGFuY2UgY29kZXMgKi9cbiAgdGhpcy5sZW5iaXRzID0gMDsgICAgICAgICAgIC8qIGluZGV4IGJpdHMgZm9yIGxlbmNvZGUgKi9cbiAgdGhpcy5kaXN0Yml0cyA9IDA7ICAgICAgICAgIC8qIGluZGV4IGJpdHMgZm9yIGRpc3Rjb2RlICovXG5cbiAgLyogZHluYW1pYyB0YWJsZSBidWlsZGluZyAqL1xuICB0aGlzLm5jb2RlID0gMDsgICAgICAgICAgICAgLyogbnVtYmVyIG9mIGNvZGUgbGVuZ3RoIGNvZGUgbGVuZ3RocyAqL1xuICB0aGlzLm5sZW4gPSAwOyAgICAgICAgICAgICAgLyogbnVtYmVyIG9mIGxlbmd0aCBjb2RlIGxlbmd0aHMgKi9cbiAgdGhpcy5uZGlzdCA9IDA7ICAgICAgICAgICAgIC8qIG51bWJlciBvZiBkaXN0YW5jZSBjb2RlIGxlbmd0aHMgKi9cbiAgdGhpcy5oYXZlID0gMDsgICAgICAgICAgICAgIC8qIG51bWJlciBvZiBjb2RlIGxlbmd0aHMgaW4gbGVuc1tdICovXG4gIHRoaXMubmV4dCA9IG51bGw7ICAgICAgICAgICAgICAvKiBuZXh0IGF2YWlsYWJsZSBzcGFjZSBpbiBjb2Rlc1tdICovXG5cbiAgdGhpcy5sZW5zID0gbmV3IHV0aWxzLkJ1ZjE2KDMyMCk7IC8qIHRlbXBvcmFyeSBzdG9yYWdlIGZvciBjb2RlIGxlbmd0aHMgKi9cbiAgdGhpcy53b3JrID0gbmV3IHV0aWxzLkJ1ZjE2KDI4OCk7IC8qIHdvcmsgYXJlYSBmb3IgY29kZSB0YWJsZSBidWlsZGluZyAqL1xuXG4gIC8qXG4gICBiZWNhdXNlIHdlIGRvbid0IGhhdmUgcG9pbnRlcnMgaW4ganMsIHdlIHVzZSBsZW5jb2RlIGFuZCBkaXN0Y29kZSBkaXJlY3RseVxuICAgYXMgYnVmZmVycyBzbyB3ZSBkb24ndCBuZWVkIGNvZGVzXG4gICovXG4gIC8vdGhpcy5jb2RlcyA9IG5ldyB1dGlscy5CdWYzMihFTk9VR0gpOyAgICAgICAvKiBzcGFjZSBmb3IgY29kZSB0YWJsZXMgKi9cbiAgdGhpcy5sZW5keW4gPSBudWxsOyAgICAgICAgICAgICAgLyogZHluYW1pYyB0YWJsZSBmb3IgbGVuZ3RoL2xpdGVyYWwgY29kZXMgKEpTIHNwZWNpZmljKSAqL1xuICB0aGlzLmRpc3RkeW4gPSBudWxsOyAgICAgICAgICAgICAvKiBkeW5hbWljIHRhYmxlIGZvciBkaXN0YW5jZSBjb2RlcyAoSlMgc3BlY2lmaWMpICovXG4gIHRoaXMuc2FuZSA9IDA7ICAgICAgICAgICAgICAgICAgIC8qIGlmIGZhbHNlLCBhbGxvdyBpbnZhbGlkIGRpc3RhbmNlIHRvbyBmYXIgKi9cbiAgdGhpcy5iYWNrID0gMDsgICAgICAgICAgICAgICAgICAgLyogYml0cyBiYWNrIG9mIGxhc3QgdW5wcm9jZXNzZWQgbGVuZ3RoL2xpdCAqL1xuICB0aGlzLndhcyA9IDA7ICAgICAgICAgICAgICAgICAgICAvKiBpbml0aWFsIGxlbmd0aCBvZiBtYXRjaCAqL1xufVxuXG5mdW5jdGlvbiBpbmZsYXRlUmVzZXRLZWVwKHN0cm0pIHtcbiAgdmFyIHN0YXRlO1xuXG4gIGlmICghc3RybSB8fCAhc3RybS5zdGF0ZSkgeyByZXR1cm4gWl9TVFJFQU1fRVJST1I7IH1cbiAgc3RhdGUgPSBzdHJtLnN0YXRlO1xuICBzdHJtLnRvdGFsX2luID0gc3RybS50b3RhbF9vdXQgPSBzdGF0ZS50b3RhbCA9IDA7XG4gIHN0cm0ubXNnID0gJyc7IC8qWl9OVUxMKi9cbiAgaWYgKHN0YXRlLndyYXApIHsgICAgICAgLyogdG8gc3VwcG9ydCBpbGwtY29uY2VpdmVkIEphdmEgdGVzdCBzdWl0ZSAqL1xuICAgIHN0cm0uYWRsZXIgPSBzdGF0ZS53cmFwICYgMTtcbiAgfVxuICBzdGF0ZS5tb2RlID0gSEVBRDtcbiAgc3RhdGUubGFzdCA9IDA7XG4gIHN0YXRlLmhhdmVkaWN0ID0gMDtcbiAgc3RhdGUuZG1heCA9IDMyNzY4O1xuICBzdGF0ZS5oZWFkID0gbnVsbC8qWl9OVUxMKi87XG4gIHN0YXRlLmhvbGQgPSAwO1xuICBzdGF0ZS5iaXRzID0gMDtcbiAgLy9zdGF0ZS5sZW5jb2RlID0gc3RhdGUuZGlzdGNvZGUgPSBzdGF0ZS5uZXh0ID0gc3RhdGUuY29kZXM7XG4gIHN0YXRlLmxlbmNvZGUgPSBzdGF0ZS5sZW5keW4gPSBuZXcgdXRpbHMuQnVmMzIoRU5PVUdIX0xFTlMpO1xuICBzdGF0ZS5kaXN0Y29kZSA9IHN0YXRlLmRpc3RkeW4gPSBuZXcgdXRpbHMuQnVmMzIoRU5PVUdIX0RJU1RTKTtcblxuICBzdGF0ZS5zYW5lID0gMTtcbiAgc3RhdGUuYmFjayA9IC0xO1xuICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6IHJlc2V0XFxuXCIpKTtcbiAgcmV0dXJuIFpfT0s7XG59XG5cbmZ1bmN0aW9uIGluZmxhdGVSZXNldChzdHJtKSB7XG4gIHZhciBzdGF0ZTtcblxuICBpZiAoIXN0cm0gfHwgIXN0cm0uc3RhdGUpIHsgcmV0dXJuIFpfU1RSRUFNX0VSUk9SOyB9XG4gIHN0YXRlID0gc3RybS5zdGF0ZTtcbiAgc3RhdGUud3NpemUgPSAwO1xuICBzdGF0ZS53aGF2ZSA9IDA7XG4gIHN0YXRlLnduZXh0ID0gMDtcbiAgcmV0dXJuIGluZmxhdGVSZXNldEtlZXAoc3RybSk7XG5cbn1cblxuZnVuY3Rpb24gaW5mbGF0ZVJlc2V0MihzdHJtLCB3aW5kb3dCaXRzKSB7XG4gIHZhciB3cmFwO1xuICB2YXIgc3RhdGU7XG5cbiAgLyogZ2V0IHRoZSBzdGF0ZSAqL1xuICBpZiAoIXN0cm0gfHwgIXN0cm0uc3RhdGUpIHsgcmV0dXJuIFpfU1RSRUFNX0VSUk9SOyB9XG4gIHN0YXRlID0gc3RybS5zdGF0ZTtcblxuICAvKiBleHRyYWN0IHdyYXAgcmVxdWVzdCBmcm9tIHdpbmRvd0JpdHMgcGFyYW1ldGVyICovXG4gIGlmICh3aW5kb3dCaXRzIDwgMCkge1xuICAgIHdyYXAgPSAwO1xuICAgIHdpbmRvd0JpdHMgPSAtd2luZG93Qml0cztcbiAgfVxuICBlbHNlIHtcbiAgICB3cmFwID0gKHdpbmRvd0JpdHMgPj4gNCkgKyAxO1xuICAgIGlmICh3aW5kb3dCaXRzIDwgNDgpIHtcbiAgICAgIHdpbmRvd0JpdHMgJj0gMTU7XG4gICAgfVxuICB9XG5cbiAgLyogc2V0IG51bWJlciBvZiB3aW5kb3cgYml0cywgZnJlZSB3aW5kb3cgaWYgZGlmZmVyZW50ICovXG4gIGlmICh3aW5kb3dCaXRzICYmICh3aW5kb3dCaXRzIDwgOCB8fCB3aW5kb3dCaXRzID4gMTUpKSB7XG4gICAgcmV0dXJuIFpfU1RSRUFNX0VSUk9SO1xuICB9XG4gIGlmIChzdGF0ZS53aW5kb3cgIT09IG51bGwgJiYgc3RhdGUud2JpdHMgIT09IHdpbmRvd0JpdHMpIHtcbiAgICBzdGF0ZS53aW5kb3cgPSBudWxsO1xuICB9XG5cbiAgLyogdXBkYXRlIHN0YXRlIGFuZCByZXNldCB0aGUgcmVzdCBvZiBpdCAqL1xuICBzdGF0ZS53cmFwID0gd3JhcDtcbiAgc3RhdGUud2JpdHMgPSB3aW5kb3dCaXRzO1xuICByZXR1cm4gaW5mbGF0ZVJlc2V0KHN0cm0pO1xufVxuXG5mdW5jdGlvbiBpbmZsYXRlSW5pdDIoc3RybSwgd2luZG93Qml0cykge1xuICB2YXIgcmV0O1xuICB2YXIgc3RhdGU7XG5cbiAgaWYgKCFzdHJtKSB7IHJldHVybiBaX1NUUkVBTV9FUlJPUjsgfVxuICAvL3N0cm0ubXNnID0gWl9OVUxMOyAgICAgICAgICAgICAgICAgLyogaW4gY2FzZSB3ZSByZXR1cm4gYW4gZXJyb3IgKi9cblxuICBzdGF0ZSA9IG5ldyBJbmZsYXRlU3RhdGUoKTtcblxuICAvL2lmIChzdGF0ZSA9PT0gWl9OVUxMKSByZXR1cm4gWl9NRU1fRVJST1I7XG4gIC8vVHJhY2V2KChzdGRlcnIsIFwiaW5mbGF0ZTogYWxsb2NhdGVkXFxuXCIpKTtcbiAgc3RybS5zdGF0ZSA9IHN0YXRlO1xuICBzdGF0ZS53aW5kb3cgPSBudWxsLypaX05VTEwqLztcbiAgcmV0ID0gaW5mbGF0ZVJlc2V0MihzdHJtLCB3aW5kb3dCaXRzKTtcbiAgaWYgKHJldCAhPT0gWl9PSykge1xuICAgIHN0cm0uc3RhdGUgPSBudWxsLypaX05VTEwqLztcbiAgfVxuICByZXR1cm4gcmV0O1xufVxuXG5mdW5jdGlvbiBpbmZsYXRlSW5pdChzdHJtKSB7XG4gIHJldHVybiBpbmZsYXRlSW5pdDIoc3RybSwgREVGX1dCSVRTKTtcbn1cblxuXG4vKlxuIFJldHVybiBzdGF0ZSB3aXRoIGxlbmd0aCBhbmQgZGlzdGFuY2UgZGVjb2RpbmcgdGFibGVzIGFuZCBpbmRleCBzaXplcyBzZXQgdG9cbiBmaXhlZCBjb2RlIGRlY29kaW5nLiAgTm9ybWFsbHkgdGhpcyByZXR1cm5zIGZpeGVkIHRhYmxlcyBmcm9tIGluZmZpeGVkLmguXG4gSWYgQlVJTERGSVhFRCBpcyBkZWZpbmVkLCB0aGVuIGluc3RlYWQgdGhpcyByb3V0aW5lIGJ1aWxkcyB0aGUgdGFibGVzIHRoZVxuIGZpcnN0IHRpbWUgaXQncyBjYWxsZWQsIGFuZCByZXR1cm5zIHRob3NlIHRhYmxlcyB0aGUgZmlyc3QgdGltZSBhbmRcbiB0aGVyZWFmdGVyLiAgVGhpcyByZWR1Y2VzIHRoZSBzaXplIG9mIHRoZSBjb2RlIGJ5IGFib3V0IDJLIGJ5dGVzLCBpblxuIGV4Y2hhbmdlIGZvciBhIGxpdHRsZSBleGVjdXRpb24gdGltZS4gIEhvd2V2ZXIsIEJVSUxERklYRUQgc2hvdWxkIG5vdCBiZVxuIHVzZWQgZm9yIHRocmVhZGVkIGFwcGxpY2F0aW9ucywgc2luY2UgdGhlIHJld3JpdGluZyBvZiB0aGUgdGFibGVzIGFuZCB2aXJnaW5cbiBtYXkgbm90IGJlIHRocmVhZC1zYWZlLlxuICovXG52YXIgdmlyZ2luID0gdHJ1ZTtcblxudmFyIGxlbmZpeCwgZGlzdGZpeDsgLy8gV2UgaGF2ZSBubyBwb2ludGVycyBpbiBKUywgc28ga2VlcCB0YWJsZXMgc2VwYXJhdGVcblxuZnVuY3Rpb24gZml4ZWR0YWJsZXMoc3RhdGUpIHtcbiAgLyogYnVpbGQgZml4ZWQgaHVmZm1hbiB0YWJsZXMgaWYgZmlyc3QgY2FsbCAobWF5IG5vdCBiZSB0aHJlYWQgc2FmZSkgKi9cbiAgaWYgKHZpcmdpbikge1xuICAgIHZhciBzeW07XG5cbiAgICBsZW5maXggPSBuZXcgdXRpbHMuQnVmMzIoNTEyKTtcbiAgICBkaXN0Zml4ID0gbmV3IHV0aWxzLkJ1ZjMyKDMyKTtcblxuICAgIC8qIGxpdGVyYWwvbGVuZ3RoIHRhYmxlICovXG4gICAgc3ltID0gMDtcbiAgICB3aGlsZSAoc3ltIDwgMTQ0KSB7IHN0YXRlLmxlbnNbc3ltKytdID0gODsgfVxuICAgIHdoaWxlIChzeW0gPCAyNTYpIHsgc3RhdGUubGVuc1tzeW0rK10gPSA5OyB9XG4gICAgd2hpbGUgKHN5bSA8IDI4MCkgeyBzdGF0ZS5sZW5zW3N5bSsrXSA9IDc7IH1cbiAgICB3aGlsZSAoc3ltIDwgMjg4KSB7IHN0YXRlLmxlbnNbc3ltKytdID0gODsgfVxuXG4gICAgaW5mbGF0ZV90YWJsZShMRU5TLCAgc3RhdGUubGVucywgMCwgMjg4LCBsZW5maXgsICAgMCwgc3RhdGUud29yaywge2JpdHM6IDl9KTtcblxuICAgIC8qIGRpc3RhbmNlIHRhYmxlICovXG4gICAgc3ltID0gMDtcbiAgICB3aGlsZSAoc3ltIDwgMzIpIHsgc3RhdGUubGVuc1tzeW0rK10gPSA1OyB9XG5cbiAgICBpbmZsYXRlX3RhYmxlKERJU1RTLCBzdGF0ZS5sZW5zLCAwLCAzMiwgICBkaXN0Zml4LCAwLCBzdGF0ZS53b3JrLCB7Yml0czogNX0pO1xuXG4gICAgLyogZG8gdGhpcyBqdXN0IG9uY2UgKi9cbiAgICB2aXJnaW4gPSBmYWxzZTtcbiAgfVxuXG4gIHN0YXRlLmxlbmNvZGUgPSBsZW5maXg7XG4gIHN0YXRlLmxlbmJpdHMgPSA5O1xuICBzdGF0ZS5kaXN0Y29kZSA9IGRpc3RmaXg7XG4gIHN0YXRlLmRpc3RiaXRzID0gNTtcbn1cblxuXG4vKlxuIFVwZGF0ZSB0aGUgd2luZG93IHdpdGggdGhlIGxhc3Qgd3NpemUgKG5vcm1hbGx5IDMySykgYnl0ZXMgd3JpdHRlbiBiZWZvcmVcbiByZXR1cm5pbmcuICBJZiB3aW5kb3cgZG9lcyBub3QgZXhpc3QgeWV0LCBjcmVhdGUgaXQuICBUaGlzIGlzIG9ubHkgY2FsbGVkXG4gd2hlbiBhIHdpbmRvdyBpcyBhbHJlYWR5IGluIHVzZSwgb3Igd2hlbiBvdXRwdXQgaGFzIGJlZW4gd3JpdHRlbiBkdXJpbmcgdGhpc1xuIGluZmxhdGUgY2FsbCwgYnV0IHRoZSBlbmQgb2YgdGhlIGRlZmxhdGUgc3RyZWFtIGhhcyBub3QgYmVlbiByZWFjaGVkIHlldC5cbiBJdCBpcyBhbHNvIGNhbGxlZCB0byBjcmVhdGUgYSB3aW5kb3cgZm9yIGRpY3Rpb25hcnkgZGF0YSB3aGVuIGEgZGljdGlvbmFyeVxuIGlzIGxvYWRlZC5cblxuIFByb3ZpZGluZyBvdXRwdXQgYnVmZmVycyBsYXJnZXIgdGhhbiAzMksgdG8gaW5mbGF0ZSgpIHNob3VsZCBwcm92aWRlIGEgc3BlZWRcbiBhZHZhbnRhZ2UsIHNpbmNlIG9ubHkgdGhlIGxhc3QgMzJLIG9mIG91dHB1dCBpcyBjb3BpZWQgdG8gdGhlIHNsaWRpbmcgd2luZG93XG4gdXBvbiByZXR1cm4gZnJvbSBpbmZsYXRlKCksIGFuZCBzaW5jZSBhbGwgZGlzdGFuY2VzIGFmdGVyIHRoZSBmaXJzdCAzMksgb2ZcbiBvdXRwdXQgd2lsbCBmYWxsIGluIHRoZSBvdXRwdXQgZGF0YSwgbWFraW5nIG1hdGNoIGNvcGllcyBzaW1wbGVyIGFuZCBmYXN0ZXIuXG4gVGhlIGFkdmFudGFnZSBtYXkgYmUgZGVwZW5kZW50IG9uIHRoZSBzaXplIG9mIHRoZSBwcm9jZXNzb3IncyBkYXRhIGNhY2hlcy5cbiAqL1xuZnVuY3Rpb24gdXBkYXRld2luZG93KHN0cm0sIHNyYywgZW5kLCBjb3B5KSB7XG4gIHZhciBkaXN0O1xuICB2YXIgc3RhdGUgPSBzdHJtLnN0YXRlO1xuXG4gIC8qIGlmIGl0IGhhc24ndCBiZWVuIGRvbmUgYWxyZWFkeSwgYWxsb2NhdGUgc3BhY2UgZm9yIHRoZSB3aW5kb3cgKi9cbiAgaWYgKHN0YXRlLndpbmRvdyA9PT0gbnVsbCkge1xuICAgIHN0YXRlLndzaXplID0gMSA8PCBzdGF0ZS53Yml0cztcbiAgICBzdGF0ZS53bmV4dCA9IDA7XG4gICAgc3RhdGUud2hhdmUgPSAwO1xuXG4gICAgc3RhdGUud2luZG93ID0gbmV3IHV0aWxzLkJ1Zjgoc3RhdGUud3NpemUpO1xuICB9XG5cbiAgLyogY29weSBzdGF0ZS0+d3NpemUgb3IgbGVzcyBvdXRwdXQgYnl0ZXMgaW50byB0aGUgY2lyY3VsYXIgd2luZG93ICovXG4gIGlmIChjb3B5ID49IHN0YXRlLndzaXplKSB7XG4gICAgdXRpbHMuYXJyYXlTZXQoc3RhdGUud2luZG93LHNyYywgZW5kIC0gc3RhdGUud3NpemUsIHN0YXRlLndzaXplLCAwKTtcbiAgICBzdGF0ZS53bmV4dCA9IDA7XG4gICAgc3RhdGUud2hhdmUgPSBzdGF0ZS53c2l6ZTtcbiAgfVxuICBlbHNlIHtcbiAgICBkaXN0ID0gc3RhdGUud3NpemUgLSBzdGF0ZS53bmV4dDtcbiAgICBpZiAoZGlzdCA+IGNvcHkpIHtcbiAgICAgIGRpc3QgPSBjb3B5O1xuICAgIH1cbiAgICAvL3ptZW1jcHkoc3RhdGUtPndpbmRvdyArIHN0YXRlLT53bmV4dCwgZW5kIC0gY29weSwgZGlzdCk7XG4gICAgdXRpbHMuYXJyYXlTZXQoc3RhdGUud2luZG93LHNyYywgZW5kIC0gY29weSwgZGlzdCwgc3RhdGUud25leHQpO1xuICAgIGNvcHkgLT0gZGlzdDtcbiAgICBpZiAoY29weSkge1xuICAgICAgLy96bWVtY3B5KHN0YXRlLT53aW5kb3csIGVuZCAtIGNvcHksIGNvcHkpO1xuICAgICAgdXRpbHMuYXJyYXlTZXQoc3RhdGUud2luZG93LHNyYywgZW5kIC0gY29weSwgY29weSwgMCk7XG4gICAgICBzdGF0ZS53bmV4dCA9IGNvcHk7XG4gICAgICBzdGF0ZS53aGF2ZSA9IHN0YXRlLndzaXplO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIHN0YXRlLnduZXh0ICs9IGRpc3Q7XG4gICAgICBpZiAoc3RhdGUud25leHQgPT09IHN0YXRlLndzaXplKSB7IHN0YXRlLnduZXh0ID0gMDsgfVxuICAgICAgaWYgKHN0YXRlLndoYXZlIDwgc3RhdGUud3NpemUpIHsgc3RhdGUud2hhdmUgKz0gZGlzdDsgfVxuICAgIH1cbiAgfVxuICByZXR1cm4gMDtcbn1cblxuZnVuY3Rpb24gaW5mbGF0ZShzdHJtLCBmbHVzaCkge1xuICB2YXIgc3RhdGU7XG4gIHZhciBpbnB1dCwgb3V0cHV0OyAgICAgICAgICAvLyBpbnB1dC9vdXRwdXQgYnVmZmVyc1xuICB2YXIgbmV4dDsgICAgICAgICAgICAgICAgICAgLyogbmV4dCBpbnB1dCBJTkRFWCAqL1xuICB2YXIgcHV0OyAgICAgICAgICAgICAgICAgICAgLyogbmV4dCBvdXRwdXQgSU5ERVggKi9cbiAgdmFyIGhhdmUsIGxlZnQ7ICAgICAgICAgICAgIC8qIGF2YWlsYWJsZSBpbnB1dCBhbmQgb3V0cHV0ICovXG4gIHZhciBob2xkOyAgICAgICAgICAgICAgICAgICAvKiBiaXQgYnVmZmVyICovXG4gIHZhciBiaXRzOyAgICAgICAgICAgICAgICAgICAvKiBiaXRzIGluIGJpdCBidWZmZXIgKi9cbiAgdmFyIF9pbiwgX291dDsgICAgICAgICAgICAgIC8qIHNhdmUgc3RhcnRpbmcgYXZhaWxhYmxlIGlucHV0IGFuZCBvdXRwdXQgKi9cbiAgdmFyIGNvcHk7ICAgICAgICAgICAgICAgICAgIC8qIG51bWJlciBvZiBzdG9yZWQgb3IgbWF0Y2ggYnl0ZXMgdG8gY29weSAqL1xuICB2YXIgZnJvbTsgICAgICAgICAgICAgICAgICAgLyogd2hlcmUgdG8gY29weSBtYXRjaCBieXRlcyBmcm9tICovXG4gIHZhciBmcm9tX3NvdXJjZTtcbiAgdmFyIGhlcmUgPSAwOyAgICAgICAgICAgICAgIC8qIGN1cnJlbnQgZGVjb2RpbmcgdGFibGUgZW50cnkgKi9cbiAgdmFyIGhlcmVfYml0cywgaGVyZV9vcCwgaGVyZV92YWw7IC8vIHBha2VkIFwiaGVyZVwiIGRlbm9ybWFsaXplZCAoSlMgc3BlY2lmaWMpXG4gIC8vdmFyIGxhc3Q7ICAgICAgICAgICAgICAgICAgIC8qIHBhcmVudCB0YWJsZSBlbnRyeSAqL1xuICB2YXIgbGFzdF9iaXRzLCBsYXN0X29wLCBsYXN0X3ZhbDsgLy8gcGFrZWQgXCJsYXN0XCIgZGVub3JtYWxpemVkIChKUyBzcGVjaWZpYylcbiAgdmFyIGxlbjsgICAgICAgICAgICAgICAgICAgIC8qIGxlbmd0aCB0byBjb3B5IGZvciByZXBlYXRzLCBiaXRzIHRvIGRyb3AgKi9cbiAgdmFyIHJldDsgICAgICAgICAgICAgICAgICAgIC8qIHJldHVybiBjb2RlICovXG4gIHZhciBoYnVmID0gbmV3IHV0aWxzLkJ1ZjgoNCk7ICAgIC8qIGJ1ZmZlciBmb3IgZ3ppcCBoZWFkZXIgY3JjIGNhbGN1bGF0aW9uICovXG4gIHZhciBvcHRzO1xuXG4gIHZhciBuOyAvLyB0ZW1wb3JhcnkgdmFyIGZvciBORUVEX0JJVFNcblxuICB2YXIgb3JkZXIgPSAvKiBwZXJtdXRhdGlvbiBvZiBjb2RlIGxlbmd0aHMgKi9cbiAgICBbMTYsIDE3LCAxOCwgMCwgOCwgNywgOSwgNiwgMTAsIDUsIDExLCA0LCAxMiwgMywgMTMsIDIsIDE0LCAxLCAxNV07XG5cblxuICBpZiAoIXN0cm0gfHwgIXN0cm0uc3RhdGUgfHwgIXN0cm0ub3V0cHV0IHx8XG4gICAgICAoIXN0cm0uaW5wdXQgJiYgc3RybS5hdmFpbF9pbiAhPT0gMCkpIHtcbiAgICByZXR1cm4gWl9TVFJFQU1fRVJST1I7XG4gIH1cblxuICBzdGF0ZSA9IHN0cm0uc3RhdGU7XG4gIGlmIChzdGF0ZS5tb2RlID09PSBUWVBFKSB7IHN0YXRlLm1vZGUgPSBUWVBFRE87IH0gICAgLyogc2tpcCBjaGVjayAqL1xuXG5cbiAgLy8tLS0gTE9BRCgpIC0tLVxuICBwdXQgPSBzdHJtLm5leHRfb3V0O1xuICBvdXRwdXQgPSBzdHJtLm91dHB1dDtcbiAgbGVmdCA9IHN0cm0uYXZhaWxfb3V0O1xuICBuZXh0ID0gc3RybS5uZXh0X2luO1xuICBpbnB1dCA9IHN0cm0uaW5wdXQ7XG4gIGhhdmUgPSBzdHJtLmF2YWlsX2luO1xuICBob2xkID0gc3RhdGUuaG9sZDtcbiAgYml0cyA9IHN0YXRlLmJpdHM7XG4gIC8vLS0tXG5cbiAgX2luID0gaGF2ZTtcbiAgX291dCA9IGxlZnQ7XG4gIHJldCA9IFpfT0s7XG5cbiAgaW5mX2xlYXZlOiAvLyBnb3RvIGVtdWxhdGlvblxuICBmb3IgKDs7KSB7XG4gICAgc3dpdGNoIChzdGF0ZS5tb2RlKSB7XG4gICAgY2FzZSBIRUFEOlxuICAgICAgaWYgKHN0YXRlLndyYXAgPT09IDApIHtcbiAgICAgICAgc3RhdGUubW9kZSA9IFRZUEVETztcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICAvLz09PSBORUVEQklUUygxNik7XG4gICAgICB3aGlsZSAoYml0cyA8IDE2KSB7XG4gICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICBoYXZlLS07XG4gICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICBiaXRzICs9IDg7XG4gICAgICB9XG4gICAgICAvLz09PS8vXG4gICAgICBpZiAoKHN0YXRlLndyYXAgJiAyKSAmJiBob2xkID09PSAweDhiMWYpIHsgIC8qIGd6aXAgaGVhZGVyICovXG4gICAgICAgIHN0YXRlLmNoZWNrID0gMC8qY3JjMzIoMEwsIFpfTlVMTCwgMCkqLztcbiAgICAgICAgLy89PT0gQ1JDMihzdGF0ZS5jaGVjaywgaG9sZCk7XG4gICAgICAgIGhidWZbMF0gPSBob2xkICYgMHhmZjtcbiAgICAgICAgaGJ1ZlsxXSA9IChob2xkID4+PiA4KSAmIDB4ZmY7XG4gICAgICAgIHN0YXRlLmNoZWNrID0gY3JjMzIoc3RhdGUuY2hlY2ssIGhidWYsIDIsIDApO1xuICAgICAgICAvLz09PS8vXG5cbiAgICAgICAgLy89PT0gSU5JVEJJVFMoKTtcbiAgICAgICAgaG9sZCA9IDA7XG4gICAgICAgIGJpdHMgPSAwO1xuICAgICAgICAvLz09PS8vXG4gICAgICAgIHN0YXRlLm1vZGUgPSBGTEFHUztcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBzdGF0ZS5mbGFncyA9IDA7ICAgICAgICAgICAvKiBleHBlY3QgemxpYiBoZWFkZXIgKi9cbiAgICAgIGlmIChzdGF0ZS5oZWFkKSB7XG4gICAgICAgIHN0YXRlLmhlYWQuZG9uZSA9IGZhbHNlO1xuICAgICAgfVxuICAgICAgaWYgKCEoc3RhdGUud3JhcCAmIDEpIHx8ICAgLyogY2hlY2sgaWYgemxpYiBoZWFkZXIgYWxsb3dlZCAqL1xuICAgICAgICAoKChob2xkICYgMHhmZikvKkJJVFMoOCkqLyA8PCA4KSArIChob2xkID4+IDgpKSAlIDMxKSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ2luY29ycmVjdCBoZWFkZXIgY2hlY2snO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGlmICgoaG9sZCAmIDB4MGYpLypCSVRTKDQpKi8gIT09IFpfREVGTEFURUQpIHtcbiAgICAgICAgc3RybS5tc2cgPSAndW5rbm93biBjb21wcmVzc2lvbiBtZXRob2QnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIC8vLS0tIERST1BCSVRTKDQpIC0tLS8vXG4gICAgICBob2xkID4+Pj0gNDtcbiAgICAgIGJpdHMgLT0gNDtcbiAgICAgIC8vLS0tLy9cbiAgICAgIGxlbiA9IChob2xkICYgMHgwZikvKkJJVFMoNCkqLyArIDg7XG4gICAgICBpZiAoc3RhdGUud2JpdHMgPT09IDApIHtcbiAgICAgICAgc3RhdGUud2JpdHMgPSBsZW47XG4gICAgICB9XG4gICAgICBlbHNlIGlmIChsZW4gPiBzdGF0ZS53Yml0cykge1xuICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIHdpbmRvdyBzaXplJztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBzdGF0ZS5kbWF4ID0gMSA8PCBsZW47XG4gICAgICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6ICAgemxpYiBoZWFkZXIgb2tcXG5cIikpO1xuICAgICAgc3RybS5hZGxlciA9IHN0YXRlLmNoZWNrID0gMS8qYWRsZXIzMigwTCwgWl9OVUxMLCAwKSovO1xuICAgICAgc3RhdGUubW9kZSA9IGhvbGQgJiAweDIwMCA/IERJQ1RJRCA6IFRZUEU7XG4gICAgICAvLz09PSBJTklUQklUUygpO1xuICAgICAgaG9sZCA9IDA7XG4gICAgICBiaXRzID0gMDtcbiAgICAgIC8vPT09Ly9cbiAgICAgIGJyZWFrO1xuICAgIGNhc2UgRkxBR1M6XG4gICAgICAvLz09PSBORUVEQklUUygxNik7ICovXG4gICAgICB3aGlsZSAoYml0cyA8IDE2KSB7XG4gICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICBoYXZlLS07XG4gICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICBiaXRzICs9IDg7XG4gICAgICB9XG4gICAgICAvLz09PS8vXG4gICAgICBzdGF0ZS5mbGFncyA9IGhvbGQ7XG4gICAgICBpZiAoKHN0YXRlLmZsYWdzICYgMHhmZikgIT09IFpfREVGTEFURUQpIHtcbiAgICAgICAgc3RybS5tc2cgPSAndW5rbm93biBjb21wcmVzc2lvbiBtZXRob2QnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4ZTAwMCkge1xuICAgICAgICBzdHJtLm1zZyA9ICd1bmtub3duIGhlYWRlciBmbGFncyBzZXQnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGlmIChzdGF0ZS5oZWFkKSB7XG4gICAgICAgIHN0YXRlLmhlYWQudGV4dCA9ICgoaG9sZCA+PiA4KSAmIDEpO1xuICAgICAgfVxuICAgICAgaWYgKHN0YXRlLmZsYWdzICYgMHgwMjAwKSB7XG4gICAgICAgIC8vPT09IENSQzIoc3RhdGUuY2hlY2ssIGhvbGQpO1xuICAgICAgICBoYnVmWzBdID0gaG9sZCAmIDB4ZmY7XG4gICAgICAgIGhidWZbMV0gPSAoaG9sZCA+Pj4gOCkgJiAweGZmO1xuICAgICAgICBzdGF0ZS5jaGVjayA9IGNyYzMyKHN0YXRlLmNoZWNrLCBoYnVmLCAyLCAwKTtcbiAgICAgICAgLy89PT0vL1xuICAgICAgfVxuICAgICAgLy89PT0gSU5JVEJJVFMoKTtcbiAgICAgIGhvbGQgPSAwO1xuICAgICAgYml0cyA9IDA7XG4gICAgICAvLz09PS8vXG4gICAgICBzdGF0ZS5tb2RlID0gVElNRTtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIFRJTUU6XG4gICAgICAvLz09PSBORUVEQklUUygzMik7ICovXG4gICAgICB3aGlsZSAoYml0cyA8IDMyKSB7XG4gICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICBoYXZlLS07XG4gICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICBiaXRzICs9IDg7XG4gICAgICB9XG4gICAgICAvLz09PS8vXG4gICAgICBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICBzdGF0ZS5oZWFkLnRpbWUgPSBob2xkO1xuICAgICAgfVxuICAgICAgaWYgKHN0YXRlLmZsYWdzICYgMHgwMjAwKSB7XG4gICAgICAgIC8vPT09IENSQzQoc3RhdGUuY2hlY2ssIGhvbGQpXG4gICAgICAgIGhidWZbMF0gPSBob2xkICYgMHhmZjtcbiAgICAgICAgaGJ1ZlsxXSA9IChob2xkID4+PiA4KSAmIDB4ZmY7XG4gICAgICAgIGhidWZbMl0gPSAoaG9sZCA+Pj4gMTYpICYgMHhmZjtcbiAgICAgICAgaGJ1ZlszXSA9IChob2xkID4+PiAyNCkgJiAweGZmO1xuICAgICAgICBzdGF0ZS5jaGVjayA9IGNyYzMyKHN0YXRlLmNoZWNrLCBoYnVmLCA0LCAwKTtcbiAgICAgICAgLy89PT1cbiAgICAgIH1cbiAgICAgIC8vPT09IElOSVRCSVRTKCk7XG4gICAgICBob2xkID0gMDtcbiAgICAgIGJpdHMgPSAwO1xuICAgICAgLy89PT0vL1xuICAgICAgc3RhdGUubW9kZSA9IE9TO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgT1M6XG4gICAgICAvLz09PSBORUVEQklUUygxNik7ICovXG4gICAgICB3aGlsZSAoYml0cyA8IDE2KSB7XG4gICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICBoYXZlLS07XG4gICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICBiaXRzICs9IDg7XG4gICAgICB9XG4gICAgICAvLz09PS8vXG4gICAgICBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICBzdGF0ZS5oZWFkLnhmbGFncyA9IChob2xkICYgMHhmZik7XG4gICAgICAgIHN0YXRlLmhlYWQub3MgPSAoaG9sZCA+PiA4KTtcbiAgICAgIH1cbiAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MDIwMCkge1xuICAgICAgICAvLz09PSBDUkMyKHN0YXRlLmNoZWNrLCBob2xkKTtcbiAgICAgICAgaGJ1ZlswXSA9IGhvbGQgJiAweGZmO1xuICAgICAgICBoYnVmWzFdID0gKGhvbGQgPj4+IDgpICYgMHhmZjtcbiAgICAgICAgc3RhdGUuY2hlY2sgPSBjcmMzMihzdGF0ZS5jaGVjaywgaGJ1ZiwgMiwgMCk7XG4gICAgICAgIC8vPT09Ly9cbiAgICAgIH1cbiAgICAgIC8vPT09IElOSVRCSVRTKCk7XG4gICAgICBob2xkID0gMDtcbiAgICAgIGJpdHMgPSAwO1xuICAgICAgLy89PT0vL1xuICAgICAgc3RhdGUubW9kZSA9IEVYTEVOO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgRVhMRU46XG4gICAgICBpZiAoc3RhdGUuZmxhZ3MgJiAweDA0MDApIHtcbiAgICAgICAgLy89PT0gTkVFREJJVFMoMTYpOyAqL1xuICAgICAgICB3aGlsZSAoYml0cyA8IDE2KSB7XG4gICAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgfVxuICAgICAgICAvLz09PS8vXG4gICAgICAgIHN0YXRlLmxlbmd0aCA9IGhvbGQ7XG4gICAgICAgIGlmIChzdGF0ZS5oZWFkKSB7XG4gICAgICAgICAgc3RhdGUuaGVhZC5leHRyYV9sZW4gPSBob2xkO1xuICAgICAgICB9XG4gICAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MDIwMCkge1xuICAgICAgICAgIC8vPT09IENSQzIoc3RhdGUuY2hlY2ssIGhvbGQpO1xuICAgICAgICAgIGhidWZbMF0gPSBob2xkICYgMHhmZjtcbiAgICAgICAgICBoYnVmWzFdID0gKGhvbGQgPj4+IDgpICYgMHhmZjtcbiAgICAgICAgICBzdGF0ZS5jaGVjayA9IGNyYzMyKHN0YXRlLmNoZWNrLCBoYnVmLCAyLCAwKTtcbiAgICAgICAgICAvLz09PS8vXG4gICAgICAgIH1cbiAgICAgICAgLy89PT0gSU5JVEJJVFMoKTtcbiAgICAgICAgaG9sZCA9IDA7XG4gICAgICAgIGJpdHMgPSAwO1xuICAgICAgICAvLz09PS8vXG4gICAgICB9XG4gICAgICBlbHNlIGlmIChzdGF0ZS5oZWFkKSB7XG4gICAgICAgIHN0YXRlLmhlYWQuZXh0cmEgPSBudWxsLypaX05VTEwqLztcbiAgICAgIH1cbiAgICAgIHN0YXRlLm1vZGUgPSBFWFRSQTtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIEVYVFJBOlxuICAgICAgaWYgKHN0YXRlLmZsYWdzICYgMHgwNDAwKSB7XG4gICAgICAgIGNvcHkgPSBzdGF0ZS5sZW5ndGg7XG4gICAgICAgIGlmIChjb3B5ID4gaGF2ZSkgeyBjb3B5ID0gaGF2ZTsgfVxuICAgICAgICBpZiAoY29weSkge1xuICAgICAgICAgIGlmIChzdGF0ZS5oZWFkKSB7XG4gICAgICAgICAgICBsZW4gPSBzdGF0ZS5oZWFkLmV4dHJhX2xlbiAtIHN0YXRlLmxlbmd0aDtcbiAgICAgICAgICAgIGlmICghc3RhdGUuaGVhZC5leHRyYSkge1xuICAgICAgICAgICAgICAvLyBVc2UgdW50eXBlZCBhcnJheSBmb3IgbW9yZSBjb252ZW5pZW5kIHByb2Nlc3NpbmcgbGF0ZXJcbiAgICAgICAgICAgICAgc3RhdGUuaGVhZC5leHRyYSA9IG5ldyBBcnJheShzdGF0ZS5oZWFkLmV4dHJhX2xlbik7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICB1dGlscy5hcnJheVNldChcbiAgICAgICAgICAgICAgc3RhdGUuaGVhZC5leHRyYSxcbiAgICAgICAgICAgICAgaW5wdXQsXG4gICAgICAgICAgICAgIG5leHQsXG4gICAgICAgICAgICAgIC8vIGV4dHJhIGZpZWxkIGlzIGxpbWl0ZWQgdG8gNjU1MzYgYnl0ZXNcbiAgICAgICAgICAgICAgLy8gLSBubyBuZWVkIGZvciBhZGRpdGlvbmFsIHNpemUgY2hlY2tcbiAgICAgICAgICAgICAgY29weSxcbiAgICAgICAgICAgICAgLypsZW4gKyBjb3B5ID4gc3RhdGUuaGVhZC5leHRyYV9tYXggLSBsZW4gPyBzdGF0ZS5oZWFkLmV4dHJhX21heCA6IGNvcHksKi9cbiAgICAgICAgICAgICAgbGVuXG4gICAgICAgICAgICApO1xuICAgICAgICAgICAgLy96bWVtY3B5KHN0YXRlLmhlYWQuZXh0cmEgKyBsZW4sIG5leHQsXG4gICAgICAgICAgICAvLyAgICAgICAgbGVuICsgY29weSA+IHN0YXRlLmhlYWQuZXh0cmFfbWF4ID9cbiAgICAgICAgICAgIC8vICAgICAgICBzdGF0ZS5oZWFkLmV4dHJhX21heCAtIGxlbiA6IGNvcHkpO1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoc3RhdGUuZmxhZ3MgJiAweDAyMDApIHtcbiAgICAgICAgICAgIHN0YXRlLmNoZWNrID0gY3JjMzIoc3RhdGUuY2hlY2ssIGlucHV0LCBjb3B5LCBuZXh0KTtcbiAgICAgICAgICB9XG4gICAgICAgICAgaGF2ZSAtPSBjb3B5O1xuICAgICAgICAgIG5leHQgKz0gY29weTtcbiAgICAgICAgICBzdGF0ZS5sZW5ndGggLT0gY29weTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoc3RhdGUubGVuZ3RoKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgfVxuICAgICAgc3RhdGUubGVuZ3RoID0gMDtcbiAgICAgIHN0YXRlLm1vZGUgPSBOQU1FO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgTkFNRTpcbiAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MDgwMCkge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgY29weSA9IDA7XG4gICAgICAgIGRvIHtcbiAgICAgICAgICAvLyBUT0RPOiAyIG9yIDEgYnl0ZXM/XG4gICAgICAgICAgbGVuID0gaW5wdXRbbmV4dCArIGNvcHkrK107XG4gICAgICAgICAgLyogdXNlIGNvbnN0YW50IGxpbWl0IGJlY2F1c2UgaW4ganMgd2Ugc2hvdWxkIG5vdCBwcmVhbGxvY2F0ZSBtZW1vcnkgKi9cbiAgICAgICAgICBpZiAoc3RhdGUuaGVhZCAmJiBsZW4gJiZcbiAgICAgICAgICAgICAgKHN0YXRlLmxlbmd0aCA8IDY1NTM2IC8qc3RhdGUuaGVhZC5uYW1lX21heCovKSkge1xuICAgICAgICAgICAgc3RhdGUuaGVhZC5uYW1lICs9IFN0cmluZy5mcm9tQ2hhckNvZGUobGVuKTtcbiAgICAgICAgICB9XG4gICAgICAgIH0gd2hpbGUgKGxlbiAmJiBjb3B5IDwgaGF2ZSk7XG5cbiAgICAgICAgaWYgKHN0YXRlLmZsYWdzICYgMHgwMjAwKSB7XG4gICAgICAgICAgc3RhdGUuY2hlY2sgPSBjcmMzMihzdGF0ZS5jaGVjaywgaW5wdXQsIGNvcHksIG5leHQpO1xuICAgICAgICB9XG4gICAgICAgIGhhdmUgLT0gY29weTtcbiAgICAgICAgbmV4dCArPSBjb3B5O1xuICAgICAgICBpZiAobGVuKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICBzdGF0ZS5oZWFkLm5hbWUgPSBudWxsO1xuICAgICAgfVxuICAgICAgc3RhdGUubGVuZ3RoID0gMDtcbiAgICAgIHN0YXRlLm1vZGUgPSBDT01NRU5UO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgQ09NTUVOVDpcbiAgICAgIGlmIChzdGF0ZS5mbGFncyAmIDB4MTAwMCkge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgY29weSA9IDA7XG4gICAgICAgIGRvIHtcbiAgICAgICAgICBsZW4gPSBpbnB1dFtuZXh0ICsgY29weSsrXTtcbiAgICAgICAgICAvKiB1c2UgY29uc3RhbnQgbGltaXQgYmVjYXVzZSBpbiBqcyB3ZSBzaG91bGQgbm90IHByZWFsbG9jYXRlIG1lbW9yeSAqL1xuICAgICAgICAgIGlmIChzdGF0ZS5oZWFkICYmIGxlbiAmJlxuICAgICAgICAgICAgICAoc3RhdGUubGVuZ3RoIDwgNjU1MzYgLypzdGF0ZS5oZWFkLmNvbW1fbWF4Ki8pKSB7XG4gICAgICAgICAgICBzdGF0ZS5oZWFkLmNvbW1lbnQgKz0gU3RyaW5nLmZyb21DaGFyQ29kZShsZW4pO1xuICAgICAgICAgIH1cbiAgICAgICAgfSB3aGlsZSAobGVuICYmIGNvcHkgPCBoYXZlKTtcbiAgICAgICAgaWYgKHN0YXRlLmZsYWdzICYgMHgwMjAwKSB7XG4gICAgICAgICAgc3RhdGUuY2hlY2sgPSBjcmMzMihzdGF0ZS5jaGVjaywgaW5wdXQsIGNvcHksIG5leHQpO1xuICAgICAgICB9XG4gICAgICAgIGhhdmUgLT0gY29weTtcbiAgICAgICAgbmV4dCArPSBjb3B5O1xuICAgICAgICBpZiAobGVuKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgfVxuICAgICAgZWxzZSBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICBzdGF0ZS5oZWFkLmNvbW1lbnQgPSBudWxsO1xuICAgICAgfVxuICAgICAgc3RhdGUubW9kZSA9IEhDUkM7XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBIQ1JDOlxuICAgICAgaWYgKHN0YXRlLmZsYWdzICYgMHgwMjAwKSB7XG4gICAgICAgIC8vPT09IE5FRURCSVRTKDE2KTsgKi9cbiAgICAgICAgd2hpbGUgKGJpdHMgPCAxNikge1xuICAgICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICAgIGhhdmUtLTtcbiAgICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgIH1cbiAgICAgICAgLy89PT0vL1xuICAgICAgICBpZiAoaG9sZCAhPT0gKHN0YXRlLmNoZWNrICYgMHhmZmZmKSkge1xuICAgICAgICAgIHN0cm0ubXNnID0gJ2hlYWRlciBjcmMgbWlzbWF0Y2gnO1xuICAgICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgLy89PT0gSU5JVEJJVFMoKTtcbiAgICAgICAgaG9sZCA9IDA7XG4gICAgICAgIGJpdHMgPSAwO1xuICAgICAgICAvLz09PS8vXG4gICAgICB9XG4gICAgICBpZiAoc3RhdGUuaGVhZCkge1xuICAgICAgICBzdGF0ZS5oZWFkLmhjcmMgPSAoKHN0YXRlLmZsYWdzID4+IDkpICYgMSk7XG4gICAgICAgIHN0YXRlLmhlYWQuZG9uZSA9IHRydWU7XG4gICAgICB9XG4gICAgICBzdHJtLmFkbGVyID0gc3RhdGUuY2hlY2sgPSAwIC8qY3JjMzIoMEwsIFpfTlVMTCwgMCkqLztcbiAgICAgIHN0YXRlLm1vZGUgPSBUWVBFO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBESUNUSUQ6XG4gICAgICAvLz09PSBORUVEQklUUygzMik7ICovXG4gICAgICB3aGlsZSAoYml0cyA8IDMyKSB7XG4gICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICBoYXZlLS07XG4gICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICBiaXRzICs9IDg7XG4gICAgICB9XG4gICAgICAvLz09PS8vXG4gICAgICBzdHJtLmFkbGVyID0gc3RhdGUuY2hlY2sgPSBaU1dBUDMyKGhvbGQpO1xuICAgICAgLy89PT0gSU5JVEJJVFMoKTtcbiAgICAgIGhvbGQgPSAwO1xuICAgICAgYml0cyA9IDA7XG4gICAgICAvLz09PS8vXG4gICAgICBzdGF0ZS5tb2RlID0gRElDVDtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIERJQ1Q6XG4gICAgICBpZiAoc3RhdGUuaGF2ZWRpY3QgPT09IDApIHtcbiAgICAgICAgLy8tLS0gUkVTVE9SRSgpIC0tLVxuICAgICAgICBzdHJtLm5leHRfb3V0ID0gcHV0O1xuICAgICAgICBzdHJtLmF2YWlsX291dCA9IGxlZnQ7XG4gICAgICAgIHN0cm0ubmV4dF9pbiA9IG5leHQ7XG4gICAgICAgIHN0cm0uYXZhaWxfaW4gPSBoYXZlO1xuICAgICAgICBzdGF0ZS5ob2xkID0gaG9sZDtcbiAgICAgICAgc3RhdGUuYml0cyA9IGJpdHM7XG4gICAgICAgIC8vLS0tXG4gICAgICAgIHJldHVybiBaX05FRURfRElDVDtcbiAgICAgIH1cbiAgICAgIHN0cm0uYWRsZXIgPSBzdGF0ZS5jaGVjayA9IDEvKmFkbGVyMzIoMEwsIFpfTlVMTCwgMCkqLztcbiAgICAgIHN0YXRlLm1vZGUgPSBUWVBFO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgVFlQRTpcbiAgICAgIGlmIChmbHVzaCA9PT0gWl9CTE9DSyB8fCBmbHVzaCA9PT0gWl9UUkVFUykgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIFRZUEVETzpcbiAgICAgIGlmIChzdGF0ZS5sYXN0KSB7XG4gICAgICAgIC8vLS0tIEJZVEVCSVRTKCkgLS0tLy9cbiAgICAgICAgaG9sZCA+Pj49IGJpdHMgJiA3O1xuICAgICAgICBiaXRzIC09IGJpdHMgJiA3O1xuICAgICAgICAvLy0tLS8vXG4gICAgICAgIHN0YXRlLm1vZGUgPSBDSEVDSztcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICAvLz09PSBORUVEQklUUygzKTsgKi9cbiAgICAgIHdoaWxlIChiaXRzIDwgMykge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgfVxuICAgICAgLy89PT0vL1xuICAgICAgc3RhdGUubGFzdCA9IChob2xkICYgMHgwMSkvKkJJVFMoMSkqLztcbiAgICAgIC8vLS0tIERST1BCSVRTKDEpIC0tLS8vXG4gICAgICBob2xkID4+Pj0gMTtcbiAgICAgIGJpdHMgLT0gMTtcbiAgICAgIC8vLS0tLy9cblxuICAgICAgc3dpdGNoICgoaG9sZCAmIDB4MDMpLypCSVRTKDIpKi8pIHtcbiAgICAgIGNhc2UgMDogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8qIHN0b3JlZCBibG9jayAqL1xuICAgICAgICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6ICAgICBzdG9yZWQgYmxvY2slc1xcblwiLFxuICAgICAgICAvLyAgICAgICAgc3RhdGUubGFzdCA/IFwiIChsYXN0KVwiIDogXCJcIikpO1xuICAgICAgICBzdGF0ZS5tb2RlID0gU1RPUkVEO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMTogICAgICAgICAgICAgICAgICAgICAgICAgICAgIC8qIGZpeGVkIGJsb2NrICovXG4gICAgICAgIGZpeGVkdGFibGVzKHN0YXRlKTtcbiAgICAgICAgLy9UcmFjZXYoKHN0ZGVyciwgXCJpbmZsYXRlOiAgICAgZml4ZWQgY29kZXMgYmxvY2slc1xcblwiLFxuICAgICAgICAvLyAgICAgICAgc3RhdGUubGFzdCA/IFwiIChsYXN0KVwiIDogXCJcIikpO1xuICAgICAgICBzdGF0ZS5tb2RlID0gTEVOXzsgICAgICAgICAgICAgLyogZGVjb2RlIGNvZGVzICovXG4gICAgICAgIGlmIChmbHVzaCA9PT0gWl9UUkVFUykge1xuICAgICAgICAgIC8vLS0tIERST1BCSVRTKDIpIC0tLS8vXG4gICAgICAgICAgaG9sZCA+Pj49IDI7XG4gICAgICAgICAgYml0cyAtPSAyO1xuICAgICAgICAgIC8vLS0tLy9cbiAgICAgICAgICBicmVhayBpbmZfbGVhdmU7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDI6ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAvKiBkeW5hbWljIGJsb2NrICovXG4gICAgICAgIC8vVHJhY2V2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgIGR5bmFtaWMgY29kZXMgYmxvY2slc1xcblwiLFxuICAgICAgICAvLyAgICAgICAgc3RhdGUubGFzdCA/IFwiIChsYXN0KVwiIDogXCJcIikpO1xuICAgICAgICBzdGF0ZS5tb2RlID0gVEFCTEU7XG4gICAgICAgIGJyZWFrO1xuICAgICAgY2FzZSAzOlxuICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGJsb2NrIHR5cGUnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgfVxuICAgICAgLy8tLS0gRFJPUEJJVFMoMikgLS0tLy9cbiAgICAgIGhvbGQgPj4+PSAyO1xuICAgICAgYml0cyAtPSAyO1xuICAgICAgLy8tLS0vL1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBTVE9SRUQ6XG4gICAgICAvLy0tLSBCWVRFQklUUygpIC0tLS8vIC8qIGdvIHRvIGJ5dGUgYm91bmRhcnkgKi9cbiAgICAgIGhvbGQgPj4+PSBiaXRzICYgNztcbiAgICAgIGJpdHMgLT0gYml0cyAmIDc7XG4gICAgICAvLy0tLS8vXG4gICAgICAvLz09PSBORUVEQklUUygzMik7ICovXG4gICAgICB3aGlsZSAoYml0cyA8IDMyKSB7XG4gICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICBoYXZlLS07XG4gICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICBiaXRzICs9IDg7XG4gICAgICB9XG4gICAgICAvLz09PS8vXG4gICAgICBpZiAoKGhvbGQgJiAweGZmZmYpICE9PSAoKGhvbGQgPj4+IDE2KSBeIDB4ZmZmZikpIHtcbiAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBzdG9yZWQgYmxvY2sgbGVuZ3Rocyc7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgc3RhdGUubGVuZ3RoID0gaG9sZCAmIDB4ZmZmZjtcbiAgICAgIC8vVHJhY2V2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgICAgc3RvcmVkIGxlbmd0aCAldVxcblwiLFxuICAgICAgLy8gICAgICAgIHN0YXRlLmxlbmd0aCkpO1xuICAgICAgLy89PT0gSU5JVEJJVFMoKTtcbiAgICAgIGhvbGQgPSAwO1xuICAgICAgYml0cyA9IDA7XG4gICAgICAvLz09PS8vXG4gICAgICBzdGF0ZS5tb2RlID0gQ09QWV87XG4gICAgICBpZiAoZmx1c2ggPT09IFpfVFJFRVMpIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBDT1BZXzpcbiAgICAgIHN0YXRlLm1vZGUgPSBDT1BZO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgQ09QWTpcbiAgICAgIGNvcHkgPSBzdGF0ZS5sZW5ndGg7XG4gICAgICBpZiAoY29weSkge1xuICAgICAgICBpZiAoY29weSA+IGhhdmUpIHsgY29weSA9IGhhdmU7IH1cbiAgICAgICAgaWYgKGNvcHkgPiBsZWZ0KSB7IGNvcHkgPSBsZWZ0OyB9XG4gICAgICAgIGlmIChjb3B5ID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICAvLy0tLSB6bWVtY3B5KHB1dCwgbmV4dCwgY29weSk7IC0tLVxuICAgICAgICB1dGlscy5hcnJheVNldChvdXRwdXQsIGlucHV0LCBuZXh0LCBjb3B5LCBwdXQpO1xuICAgICAgICAvLy0tLS8vXG4gICAgICAgIGhhdmUgLT0gY29weTtcbiAgICAgICAgbmV4dCArPSBjb3B5O1xuICAgICAgICBsZWZ0IC09IGNvcHk7XG4gICAgICAgIHB1dCArPSBjb3B5O1xuICAgICAgICBzdGF0ZS5sZW5ndGggLT0gY29weTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICAvL1RyYWNldigoc3RkZXJyLCBcImluZmxhdGU6ICAgICAgIHN0b3JlZCBlbmRcXG5cIikpO1xuICAgICAgc3RhdGUubW9kZSA9IFRZUEU7XG4gICAgICBicmVhaztcbiAgICBjYXNlIFRBQkxFOlxuICAgICAgLy89PT0gTkVFREJJVFMoMTQpOyAqL1xuICAgICAgd2hpbGUgKGJpdHMgPCAxNCkge1xuICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgaGF2ZS0tO1xuICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgYml0cyArPSA4O1xuICAgICAgfVxuICAgICAgLy89PT0vL1xuICAgICAgc3RhdGUubmxlbiA9IChob2xkICYgMHgxZikvKkJJVFMoNSkqLyArIDI1NztcbiAgICAgIC8vLS0tIERST1BCSVRTKDUpIC0tLS8vXG4gICAgICBob2xkID4+Pj0gNTtcbiAgICAgIGJpdHMgLT0gNTtcbiAgICAgIC8vLS0tLy9cbiAgICAgIHN0YXRlLm5kaXN0ID0gKGhvbGQgJiAweDFmKS8qQklUUyg1KSovICsgMTtcbiAgICAgIC8vLS0tIERST1BCSVRTKDUpIC0tLS8vXG4gICAgICBob2xkID4+Pj0gNTtcbiAgICAgIGJpdHMgLT0gNTtcbiAgICAgIC8vLS0tLy9cbiAgICAgIHN0YXRlLm5jb2RlID0gKGhvbGQgJiAweDBmKS8qQklUUyg0KSovICsgNDtcbiAgICAgIC8vLS0tIERST1BCSVRTKDQpIC0tLS8vXG4gICAgICBob2xkID4+Pj0gNDtcbiAgICAgIGJpdHMgLT0gNDtcbiAgICAgIC8vLS0tLy9cbi8vI2lmbmRlZiBQS1pJUF9CVUdfV09SS0FST1VORFxuICAgICAgaWYgKHN0YXRlLm5sZW4gPiAyODYgfHwgc3RhdGUubmRpc3QgPiAzMCkge1xuICAgICAgICBzdHJtLm1zZyA9ICd0b28gbWFueSBsZW5ndGggb3IgZGlzdGFuY2Ugc3ltYm9scyc7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuLy8jZW5kaWZcbiAgICAgIC8vVHJhY2V2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgICAgdGFibGUgc2l6ZXMgb2tcXG5cIikpO1xuICAgICAgc3RhdGUuaGF2ZSA9IDA7XG4gICAgICBzdGF0ZS5tb2RlID0gTEVOTEVOUztcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIExFTkxFTlM6XG4gICAgICB3aGlsZSAoc3RhdGUuaGF2ZSA8IHN0YXRlLm5jb2RlKSB7XG4gICAgICAgIC8vPT09IE5FRURCSVRTKDMpO1xuICAgICAgICB3aGlsZSAoYml0cyA8IDMpIHtcbiAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICBoYXZlLS07XG4gICAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICB9XG4gICAgICAgIC8vPT09Ly9cbiAgICAgICAgc3RhdGUubGVuc1tvcmRlcltzdGF0ZS5oYXZlKytdXSA9IChob2xkICYgMHgwNyk7Ly9CSVRTKDMpO1xuICAgICAgICAvLy0tLSBEUk9QQklUUygzKSAtLS0vL1xuICAgICAgICBob2xkID4+Pj0gMztcbiAgICAgICAgYml0cyAtPSAzO1xuICAgICAgICAvLy0tLS8vXG4gICAgICB9XG4gICAgICB3aGlsZSAoc3RhdGUuaGF2ZSA8IDE5KSB7XG4gICAgICAgIHN0YXRlLmxlbnNbb3JkZXJbc3RhdGUuaGF2ZSsrXV0gPSAwO1xuICAgICAgfVxuICAgICAgLy8gV2UgaGF2ZSBzZXBhcmF0ZSB0YWJsZXMgJiBubyBwb2ludGVycy4gMiBjb21tZW50ZWQgbGluZXMgYmVsb3cgbm90IG5lZWRlZC5cbiAgICAgIC8vc3RhdGUubmV4dCA9IHN0YXRlLmNvZGVzO1xuICAgICAgLy9zdGF0ZS5sZW5jb2RlID0gc3RhdGUubmV4dDtcbiAgICAgIC8vIFN3aXRjaCB0byB1c2UgZHluYW1pYyB0YWJsZVxuICAgICAgc3RhdGUubGVuY29kZSA9IHN0YXRlLmxlbmR5bjtcbiAgICAgIHN0YXRlLmxlbmJpdHMgPSA3O1xuXG4gICAgICBvcHRzID0ge2JpdHM6IHN0YXRlLmxlbmJpdHN9O1xuICAgICAgcmV0ID0gaW5mbGF0ZV90YWJsZShDT0RFUywgc3RhdGUubGVucywgMCwgMTksIHN0YXRlLmxlbmNvZGUsIDAsIHN0YXRlLndvcmssIG9wdHMpO1xuICAgICAgc3RhdGUubGVuYml0cyA9IG9wdHMuYml0cztcblxuICAgICAgaWYgKHJldCkge1xuICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGNvZGUgbGVuZ3RocyBzZXQnO1xuICAgICAgICBzdGF0ZS5tb2RlID0gQkFEO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIC8vVHJhY2V2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgICAgY29kZSBsZW5ndGhzIG9rXFxuXCIpKTtcbiAgICAgIHN0YXRlLmhhdmUgPSAwO1xuICAgICAgc3RhdGUubW9kZSA9IENPREVMRU5TO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgQ09ERUxFTlM6XG4gICAgICB3aGlsZSAoc3RhdGUuaGF2ZSA8IHN0YXRlLm5sZW4gKyBzdGF0ZS5uZGlzdCkge1xuICAgICAgICBmb3IgKDs7KSB7XG4gICAgICAgICAgaGVyZSA9IHN0YXRlLmxlbmNvZGVbaG9sZCAmICgoMSA8PCBzdGF0ZS5sZW5iaXRzKSAtIDEpXTsvKkJJVFMoc3RhdGUubGVuYml0cykqL1xuICAgICAgICAgIGhlcmVfYml0cyA9IGhlcmUgPj4+IDI0O1xuICAgICAgICAgIGhlcmVfb3AgPSAoaGVyZSA+Pj4gMTYpICYgMHhmZjtcbiAgICAgICAgICBoZXJlX3ZhbCA9IGhlcmUgJiAweGZmZmY7XG5cbiAgICAgICAgICBpZiAoKGhlcmVfYml0cykgPD0gYml0cykgeyBicmVhazsgfVxuICAgICAgICAgIC8vLS0tIFBVTExCWVRFKCkgLS0tLy9cbiAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICBoYXZlLS07XG4gICAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAgIC8vLS0tLy9cbiAgICAgICAgfVxuICAgICAgICBpZiAoaGVyZV92YWwgPCAxNikge1xuICAgICAgICAgIC8vLS0tIERST1BCSVRTKGhlcmUuYml0cykgLS0tLy9cbiAgICAgICAgICBob2xkID4+Pj0gaGVyZV9iaXRzO1xuICAgICAgICAgIGJpdHMgLT0gaGVyZV9iaXRzO1xuICAgICAgICAgIC8vLS0tLy9cbiAgICAgICAgICBzdGF0ZS5sZW5zW3N0YXRlLmhhdmUrK10gPSBoZXJlX3ZhbDtcbiAgICAgICAgfVxuICAgICAgICBlbHNlIHtcbiAgICAgICAgICBpZiAoaGVyZV92YWwgPT09IDE2KSB7XG4gICAgICAgICAgICAvLz09PSBORUVEQklUUyhoZXJlLmJpdHMgKyAyKTtcbiAgICAgICAgICAgIG4gPSBoZXJlX2JpdHMgKyAyO1xuICAgICAgICAgICAgd2hpbGUgKGJpdHMgPCBuKSB7XG4gICAgICAgICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICAgICAgICBoYXZlLS07XG4gICAgICAgICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICAvLz09PS8vXG4gICAgICAgICAgICAvLy0tLSBEUk9QQklUUyhoZXJlLmJpdHMpIC0tLS8vXG4gICAgICAgICAgICBob2xkID4+Pj0gaGVyZV9iaXRzO1xuICAgICAgICAgICAgYml0cyAtPSBoZXJlX2JpdHM7XG4gICAgICAgICAgICAvLy0tLS8vXG4gICAgICAgICAgICBpZiAoc3RhdGUuaGF2ZSA9PT0gMCkge1xuICAgICAgICAgICAgICBzdHJtLm1zZyA9ICdpbnZhbGlkIGJpdCBsZW5ndGggcmVwZWF0JztcbiAgICAgICAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgICAgICAgYnJlYWs7XG4gICAgICAgICAgICB9XG4gICAgICAgICAgICBsZW4gPSBzdGF0ZS5sZW5zW3N0YXRlLmhhdmUgLSAxXTtcbiAgICAgICAgICAgIGNvcHkgPSAzICsgKGhvbGQgJiAweDAzKTsvL0JJVFMoMik7XG4gICAgICAgICAgICAvLy0tLSBEUk9QQklUUygyKSAtLS0vL1xuICAgICAgICAgICAgaG9sZCA+Pj49IDI7XG4gICAgICAgICAgICBiaXRzIC09IDI7XG4gICAgICAgICAgICAvLy0tLS8vXG4gICAgICAgICAgfVxuICAgICAgICAgIGVsc2UgaWYgKGhlcmVfdmFsID09PSAxNykge1xuICAgICAgICAgICAgLy89PT0gTkVFREJJVFMoaGVyZS5iaXRzICsgMyk7XG4gICAgICAgICAgICBuID0gaGVyZV9iaXRzICsgMztcbiAgICAgICAgICAgIHdoaWxlIChiaXRzIDwgbikge1xuICAgICAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy89PT0vL1xuICAgICAgICAgICAgLy8tLS0gRFJPUEJJVFMoaGVyZS5iaXRzKSAtLS0vL1xuICAgICAgICAgICAgaG9sZCA+Pj49IGhlcmVfYml0cztcbiAgICAgICAgICAgIGJpdHMgLT0gaGVyZV9iaXRzO1xuICAgICAgICAgICAgLy8tLS0vL1xuICAgICAgICAgICAgbGVuID0gMDtcbiAgICAgICAgICAgIGNvcHkgPSAzICsgKGhvbGQgJiAweDA3KTsvL0JJVFMoMyk7XG4gICAgICAgICAgICAvLy0tLSBEUk9QQklUUygzKSAtLS0vL1xuICAgICAgICAgICAgaG9sZCA+Pj49IDM7XG4gICAgICAgICAgICBiaXRzIC09IDM7XG4gICAgICAgICAgICAvLy0tLS8vXG4gICAgICAgICAgfVxuICAgICAgICAgIGVsc2Uge1xuICAgICAgICAgICAgLy89PT0gTkVFREJJVFMoaGVyZS5iaXRzICsgNyk7XG4gICAgICAgICAgICBuID0gaGVyZV9iaXRzICsgNztcbiAgICAgICAgICAgIHdoaWxlIChiaXRzIDwgbikge1xuICAgICAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAgICAgfVxuICAgICAgICAgICAgLy89PT0vL1xuICAgICAgICAgICAgLy8tLS0gRFJPUEJJVFMoaGVyZS5iaXRzKSAtLS0vL1xuICAgICAgICAgICAgaG9sZCA+Pj49IGhlcmVfYml0cztcbiAgICAgICAgICAgIGJpdHMgLT0gaGVyZV9iaXRzO1xuICAgICAgICAgICAgLy8tLS0vL1xuICAgICAgICAgICAgbGVuID0gMDtcbiAgICAgICAgICAgIGNvcHkgPSAxMSArIChob2xkICYgMHg3Zik7Ly9CSVRTKDcpO1xuICAgICAgICAgICAgLy8tLS0gRFJPUEJJVFMoNykgLS0tLy9cbiAgICAgICAgICAgIGhvbGQgPj4+PSA3O1xuICAgICAgICAgICAgYml0cyAtPSA3O1xuICAgICAgICAgICAgLy8tLS0vL1xuICAgICAgICAgIH1cbiAgICAgICAgICBpZiAoc3RhdGUuaGF2ZSArIGNvcHkgPiBzdGF0ZS5ubGVuICsgc3RhdGUubmRpc3QpIHtcbiAgICAgICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgYml0IGxlbmd0aCByZXBlYXQnO1xuICAgICAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbiAgICAgICAgICB3aGlsZSAoY29weS0tKSB7XG4gICAgICAgICAgICBzdGF0ZS5sZW5zW3N0YXRlLmhhdmUrK10gPSBsZW47XG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIC8qIGhhbmRsZSBlcnJvciBicmVha3MgaW4gd2hpbGUgKi9cbiAgICAgIGlmIChzdGF0ZS5tb2RlID09PSBCQUQpIHsgYnJlYWs7IH1cblxuICAgICAgLyogY2hlY2sgZm9yIGVuZC1vZi1ibG9jayBjb2RlIChiZXR0ZXIgaGF2ZSBvbmUpICovXG4gICAgICBpZiAoc3RhdGUubGVuc1syNTZdID09PSAwKSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgY29kZSAtLSBtaXNzaW5nIGVuZC1vZi1ibG9jayc7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuXG4gICAgICAvKiBidWlsZCBjb2RlIHRhYmxlcyAtLSBub3RlOiBkbyBub3QgY2hhbmdlIHRoZSBsZW5iaXRzIG9yIGRpc3RiaXRzXG4gICAgICAgICB2YWx1ZXMgaGVyZSAoOSBhbmQgNikgd2l0aG91dCByZWFkaW5nIHRoZSBjb21tZW50cyBpbiBpbmZ0cmVlcy5oXG4gICAgICAgICBjb25jZXJuaW5nIHRoZSBFTk9VR0ggY29uc3RhbnRzLCB3aGljaCBkZXBlbmQgb24gdGhvc2UgdmFsdWVzICovXG4gICAgICBzdGF0ZS5sZW5iaXRzID0gOTtcblxuICAgICAgb3B0cyA9IHtiaXRzOiBzdGF0ZS5sZW5iaXRzfTtcbiAgICAgIHJldCA9IGluZmxhdGVfdGFibGUoTEVOUywgc3RhdGUubGVucywgMCwgc3RhdGUubmxlbiwgc3RhdGUubGVuY29kZSwgMCwgc3RhdGUud29yaywgb3B0cyk7XG4gICAgICAvLyBXZSBoYXZlIHNlcGFyYXRlIHRhYmxlcyAmIG5vIHBvaW50ZXJzLiAyIGNvbW1lbnRlZCBsaW5lcyBiZWxvdyBub3QgbmVlZGVkLlxuICAgICAgLy8gc3RhdGUubmV4dF9pbmRleCA9IG9wdHMudGFibGVfaW5kZXg7XG4gICAgICBzdGF0ZS5sZW5iaXRzID0gb3B0cy5iaXRzO1xuICAgICAgLy8gc3RhdGUubGVuY29kZSA9IHN0YXRlLm5leHQ7XG5cbiAgICAgIGlmIChyZXQpIHtcbiAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBsaXRlcmFsL2xlbmd0aHMgc2V0JztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG5cbiAgICAgIHN0YXRlLmRpc3RiaXRzID0gNjtcbiAgICAgIC8vc3RhdGUuZGlzdGNvZGUuY29weShzdGF0ZS5jb2Rlcyk7XG4gICAgICAvLyBTd2l0Y2ggdG8gdXNlIGR5bmFtaWMgdGFibGVcbiAgICAgIHN0YXRlLmRpc3Rjb2RlID0gc3RhdGUuZGlzdGR5bjtcbiAgICAgIG9wdHMgPSB7Yml0czogc3RhdGUuZGlzdGJpdHN9O1xuICAgICAgcmV0ID0gaW5mbGF0ZV90YWJsZShESVNUUywgc3RhdGUubGVucywgc3RhdGUubmxlbiwgc3RhdGUubmRpc3QsIHN0YXRlLmRpc3Rjb2RlLCAwLCBzdGF0ZS53b3JrLCBvcHRzKTtcbiAgICAgIC8vIFdlIGhhdmUgc2VwYXJhdGUgdGFibGVzICYgbm8gcG9pbnRlcnMuIDIgY29tbWVudGVkIGxpbmVzIGJlbG93IG5vdCBuZWVkZWQuXG4gICAgICAvLyBzdGF0ZS5uZXh0X2luZGV4ID0gb3B0cy50YWJsZV9pbmRleDtcbiAgICAgIHN0YXRlLmRpc3RiaXRzID0gb3B0cy5iaXRzO1xuICAgICAgLy8gc3RhdGUuZGlzdGNvZGUgPSBzdGF0ZS5uZXh0O1xuXG4gICAgICBpZiAocmV0KSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgZGlzdGFuY2VzIHNldCc7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgLy9UcmFjZXYoKHN0ZGVyciwgJ2luZmxhdGU6ICAgICAgIGNvZGVzIG9rXFxuJykpO1xuICAgICAgc3RhdGUubW9kZSA9IExFTl87XG4gICAgICBpZiAoZmx1c2ggPT09IFpfVFJFRVMpIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBMRU5fOlxuICAgICAgc3RhdGUubW9kZSA9IExFTjtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIExFTjpcbiAgICAgIGlmIChoYXZlID49IDYgJiYgbGVmdCA+PSAyNTgpIHtcbiAgICAgICAgLy8tLS0gUkVTVE9SRSgpIC0tLVxuICAgICAgICBzdHJtLm5leHRfb3V0ID0gcHV0O1xuICAgICAgICBzdHJtLmF2YWlsX291dCA9IGxlZnQ7XG4gICAgICAgIHN0cm0ubmV4dF9pbiA9IG5leHQ7XG4gICAgICAgIHN0cm0uYXZhaWxfaW4gPSBoYXZlO1xuICAgICAgICBzdGF0ZS5ob2xkID0gaG9sZDtcbiAgICAgICAgc3RhdGUuYml0cyA9IGJpdHM7XG4gICAgICAgIC8vLS0tXG4gICAgICAgIGluZmxhdGVfZmFzdChzdHJtLCBfb3V0KTtcbiAgICAgICAgLy8tLS0gTE9BRCgpIC0tLVxuICAgICAgICBwdXQgPSBzdHJtLm5leHRfb3V0O1xuICAgICAgICBvdXRwdXQgPSBzdHJtLm91dHB1dDtcbiAgICAgICAgbGVmdCA9IHN0cm0uYXZhaWxfb3V0O1xuICAgICAgICBuZXh0ID0gc3RybS5uZXh0X2luO1xuICAgICAgICBpbnB1dCA9IHN0cm0uaW5wdXQ7XG4gICAgICAgIGhhdmUgPSBzdHJtLmF2YWlsX2luO1xuICAgICAgICBob2xkID0gc3RhdGUuaG9sZDtcbiAgICAgICAgYml0cyA9IHN0YXRlLmJpdHM7XG4gICAgICAgIC8vLS0tXG5cbiAgICAgICAgaWYgKHN0YXRlLm1vZGUgPT09IFRZUEUpIHtcbiAgICAgICAgICBzdGF0ZS5iYWNrID0gLTE7XG4gICAgICAgIH1cbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBzdGF0ZS5iYWNrID0gMDtcbiAgICAgIGZvciAoOzspIHtcbiAgICAgICAgaGVyZSA9IHN0YXRlLmxlbmNvZGVbaG9sZCAmICgoMSA8PCBzdGF0ZS5sZW5iaXRzKSAtMSldOyAgLypCSVRTKHN0YXRlLmxlbmJpdHMpKi9cbiAgICAgICAgaGVyZV9iaXRzID0gaGVyZSA+Pj4gMjQ7XG4gICAgICAgIGhlcmVfb3AgPSAoaGVyZSA+Pj4gMTYpICYgMHhmZjtcbiAgICAgICAgaGVyZV92YWwgPSBoZXJlICYgMHhmZmZmO1xuXG4gICAgICAgIGlmIChoZXJlX2JpdHMgPD0gYml0cykgeyBicmVhazsgfVxuICAgICAgICAvLy0tLSBQVUxMQllURSgpIC0tLS8vXG4gICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICBoYXZlLS07XG4gICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgIC8vLS0tLy9cbiAgICAgIH1cbiAgICAgIGlmIChoZXJlX29wICYmIChoZXJlX29wICYgMHhmMCkgPT09IDApIHtcbiAgICAgICAgbGFzdF9iaXRzID0gaGVyZV9iaXRzO1xuICAgICAgICBsYXN0X29wID0gaGVyZV9vcDtcbiAgICAgICAgbGFzdF92YWwgPSBoZXJlX3ZhbDtcbiAgICAgICAgZm9yICg7Oykge1xuICAgICAgICAgIGhlcmUgPSBzdGF0ZS5sZW5jb2RlW2xhc3RfdmFsICtcbiAgICAgICAgICAgICAgICAgICgoaG9sZCAmICgoMSA8PCAobGFzdF9iaXRzICsgbGFzdF9vcCkpIC0xKSkvKkJJVFMobGFzdC5iaXRzICsgbGFzdC5vcCkqLyA+PiBsYXN0X2JpdHMpXTtcbiAgICAgICAgICBoZXJlX2JpdHMgPSBoZXJlID4+PiAyNDtcbiAgICAgICAgICBoZXJlX29wID0gKGhlcmUgPj4+IDE2KSAmIDB4ZmY7XG4gICAgICAgICAgaGVyZV92YWwgPSBoZXJlICYgMHhmZmZmO1xuXG4gICAgICAgICAgaWYgKChsYXN0X2JpdHMgKyBoZXJlX2JpdHMpIDw9IGJpdHMpIHsgYnJlYWs7IH1cbiAgICAgICAgICAvLy0tLSBQVUxMQllURSgpIC0tLS8vXG4gICAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgICAvLy0tLS8vXG4gICAgICAgIH1cbiAgICAgICAgLy8tLS0gRFJPUEJJVFMobGFzdC5iaXRzKSAtLS0vL1xuICAgICAgICBob2xkID4+Pj0gbGFzdF9iaXRzO1xuICAgICAgICBiaXRzIC09IGxhc3RfYml0cztcbiAgICAgICAgLy8tLS0vL1xuICAgICAgICBzdGF0ZS5iYWNrICs9IGxhc3RfYml0cztcbiAgICAgIH1cbiAgICAgIC8vLS0tIERST1BCSVRTKGhlcmUuYml0cykgLS0tLy9cbiAgICAgIGhvbGQgPj4+PSBoZXJlX2JpdHM7XG4gICAgICBiaXRzIC09IGhlcmVfYml0cztcbiAgICAgIC8vLS0tLy9cbiAgICAgIHN0YXRlLmJhY2sgKz0gaGVyZV9iaXRzO1xuICAgICAgc3RhdGUubGVuZ3RoID0gaGVyZV92YWw7XG4gICAgICBpZiAoaGVyZV9vcCA9PT0gMCkge1xuICAgICAgICAvL1RyYWNldnYoKHN0ZGVyciwgaGVyZS52YWwgPj0gMHgyMCAmJiBoZXJlLnZhbCA8IDB4N2YgP1xuICAgICAgICAvLyAgICAgICAgXCJpbmZsYXRlOiAgICAgICAgIGxpdGVyYWwgJyVjJ1xcblwiIDpcbiAgICAgICAgLy8gICAgICAgIFwiaW5mbGF0ZTogICAgICAgICBsaXRlcmFsIDB4JTAyeFxcblwiLCBoZXJlLnZhbCkpO1xuICAgICAgICBzdGF0ZS5tb2RlID0gTElUO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGlmIChoZXJlX29wICYgMzIpIHtcbiAgICAgICAgLy9UcmFjZXZ2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgICAgICBlbmQgb2YgYmxvY2tcXG5cIikpO1xuICAgICAgICBzdGF0ZS5iYWNrID0gLTE7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBUWVBFO1xuICAgICAgICBicmVhaztcbiAgICAgIH1cbiAgICAgIGlmIChoZXJlX29wICYgNjQpIHtcbiAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBsaXRlcmFsL2xlbmd0aCBjb2RlJztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgICBzdGF0ZS5leHRyYSA9IGhlcmVfb3AgJiAxNTtcbiAgICAgIHN0YXRlLm1vZGUgPSBMRU5FWFQ7XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBMRU5FWFQ6XG4gICAgICBpZiAoc3RhdGUuZXh0cmEpIHtcbiAgICAgICAgLy89PT0gTkVFREJJVFMoc3RhdGUuZXh0cmEpO1xuICAgICAgICBuID0gc3RhdGUuZXh0cmE7XG4gICAgICAgIHdoaWxlIChiaXRzIDwgbikge1xuICAgICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICAgIGhhdmUtLTtcbiAgICAgICAgICBob2xkICs9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgIH1cbiAgICAgICAgLy89PT0vL1xuICAgICAgICBzdGF0ZS5sZW5ndGggKz0gaG9sZCAmICgoMSA8PCBzdGF0ZS5leHRyYSkgLTEpLypCSVRTKHN0YXRlLmV4dHJhKSovO1xuICAgICAgICAvLy0tLSBEUk9QQklUUyhzdGF0ZS5leHRyYSkgLS0tLy9cbiAgICAgICAgaG9sZCA+Pj49IHN0YXRlLmV4dHJhO1xuICAgICAgICBiaXRzIC09IHN0YXRlLmV4dHJhO1xuICAgICAgICAvLy0tLS8vXG4gICAgICAgIHN0YXRlLmJhY2sgKz0gc3RhdGUuZXh0cmE7XG4gICAgICB9XG4gICAgICAvL1RyYWNldnYoKHN0ZGVyciwgXCJpbmZsYXRlOiAgICAgICAgIGxlbmd0aCAldVxcblwiLCBzdGF0ZS5sZW5ndGgpKTtcbiAgICAgIHN0YXRlLndhcyA9IHN0YXRlLmxlbmd0aDtcbiAgICAgIHN0YXRlLm1vZGUgPSBESVNUO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgRElTVDpcbiAgICAgIGZvciAoOzspIHtcbiAgICAgICAgaGVyZSA9IHN0YXRlLmRpc3Rjb2RlW2hvbGQgJiAoKDEgPDwgc3RhdGUuZGlzdGJpdHMpIC0xKV07LypCSVRTKHN0YXRlLmRpc3RiaXRzKSovXG4gICAgICAgIGhlcmVfYml0cyA9IGhlcmUgPj4+IDI0O1xuICAgICAgICBoZXJlX29wID0gKGhlcmUgPj4+IDE2KSAmIDB4ZmY7XG4gICAgICAgIGhlcmVfdmFsID0gaGVyZSAmIDB4ZmZmZjtcblxuICAgICAgICBpZiAoKGhlcmVfYml0cykgPD0gYml0cykgeyBicmVhazsgfVxuICAgICAgICAvLy0tLSBQVUxMQllURSgpIC0tLS8vXG4gICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICBoYXZlLS07XG4gICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgIC8vLS0tLy9cbiAgICAgIH1cbiAgICAgIGlmICgoaGVyZV9vcCAmIDB4ZjApID09PSAwKSB7XG4gICAgICAgIGxhc3RfYml0cyA9IGhlcmVfYml0cztcbiAgICAgICAgbGFzdF9vcCA9IGhlcmVfb3A7XG4gICAgICAgIGxhc3RfdmFsID0gaGVyZV92YWw7XG4gICAgICAgIGZvciAoOzspIHtcbiAgICAgICAgICBoZXJlID0gc3RhdGUuZGlzdGNvZGVbbGFzdF92YWwgK1xuICAgICAgICAgICAgICAgICAgKChob2xkICYgKCgxIDw8IChsYXN0X2JpdHMgKyBsYXN0X29wKSkgLTEpKS8qQklUUyhsYXN0LmJpdHMgKyBsYXN0Lm9wKSovID4+IGxhc3RfYml0cyldO1xuICAgICAgICAgIGhlcmVfYml0cyA9IGhlcmUgPj4+IDI0O1xuICAgICAgICAgIGhlcmVfb3AgPSAoaGVyZSA+Pj4gMTYpICYgMHhmZjtcbiAgICAgICAgICBoZXJlX3ZhbCA9IGhlcmUgJiAweGZmZmY7XG5cbiAgICAgICAgICBpZiAoKGxhc3RfYml0cyArIGhlcmVfYml0cykgPD0gYml0cykgeyBicmVhazsgfVxuICAgICAgICAgIC8vLS0tIFBVTExCWVRFKCkgLS0tLy9cbiAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICBoYXZlLS07XG4gICAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICAgIC8vLS0tLy9cbiAgICAgICAgfVxuICAgICAgICAvLy0tLSBEUk9QQklUUyhsYXN0LmJpdHMpIC0tLS8vXG4gICAgICAgIGhvbGQgPj4+PSBsYXN0X2JpdHM7XG4gICAgICAgIGJpdHMgLT0gbGFzdF9iaXRzO1xuICAgICAgICAvLy0tLS8vXG4gICAgICAgIHN0YXRlLmJhY2sgKz0gbGFzdF9iaXRzO1xuICAgICAgfVxuICAgICAgLy8tLS0gRFJPUEJJVFMoaGVyZS5iaXRzKSAtLS0vL1xuICAgICAgaG9sZCA+Pj49IGhlcmVfYml0cztcbiAgICAgIGJpdHMgLT0gaGVyZV9iaXRzO1xuICAgICAgLy8tLS0vL1xuICAgICAgc3RhdGUuYmFjayArPSBoZXJlX2JpdHM7XG4gICAgICBpZiAoaGVyZV9vcCAmIDY0KSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgZGlzdGFuY2UgY29kZSc7XG4gICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgIGJyZWFrO1xuICAgICAgfVxuICAgICAgc3RhdGUub2Zmc2V0ID0gaGVyZV92YWw7XG4gICAgICBzdGF0ZS5leHRyYSA9IChoZXJlX29wKSAmIDE1O1xuICAgICAgc3RhdGUubW9kZSA9IERJU1RFWFQ7XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgY2FzZSBESVNURVhUOlxuICAgICAgaWYgKHN0YXRlLmV4dHJhKSB7XG4gICAgICAgIC8vPT09IE5FRURCSVRTKHN0YXRlLmV4dHJhKTtcbiAgICAgICAgbiA9IHN0YXRlLmV4dHJhO1xuICAgICAgICB3aGlsZSAoYml0cyA8IG4pIHtcbiAgICAgICAgICBpZiAoaGF2ZSA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgICAgICBoYXZlLS07XG4gICAgICAgICAgaG9sZCArPSBpbnB1dFtuZXh0KytdIDw8IGJpdHM7XG4gICAgICAgICAgYml0cyArPSA4O1xuICAgICAgICB9XG4gICAgICAgIC8vPT09Ly9cbiAgICAgICAgc3RhdGUub2Zmc2V0ICs9IGhvbGQgJiAoKDEgPDwgc3RhdGUuZXh0cmEpIC0xKS8qQklUUyhzdGF0ZS5leHRyYSkqLztcbiAgICAgICAgLy8tLS0gRFJPUEJJVFMoc3RhdGUuZXh0cmEpIC0tLS8vXG4gICAgICAgIGhvbGQgPj4+PSBzdGF0ZS5leHRyYTtcbiAgICAgICAgYml0cyAtPSBzdGF0ZS5leHRyYTtcbiAgICAgICAgLy8tLS0vL1xuICAgICAgICBzdGF0ZS5iYWNrICs9IHN0YXRlLmV4dHJhO1xuICAgICAgfVxuLy8jaWZkZWYgSU5GTEFURV9TVFJJQ1RcbiAgICAgIGlmIChzdGF0ZS5vZmZzZXQgPiBzdGF0ZS5kbWF4KSB7XG4gICAgICAgIHN0cm0ubXNnID0gJ2ludmFsaWQgZGlzdGFuY2UgdG9vIGZhciBiYWNrJztcbiAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4vLyNlbmRpZlxuICAgICAgLy9UcmFjZXZ2KChzdGRlcnIsIFwiaW5mbGF0ZTogICAgICAgICBkaXN0YW5jZSAldVxcblwiLCBzdGF0ZS5vZmZzZXQpKTtcbiAgICAgIHN0YXRlLm1vZGUgPSBNQVRDSDtcbiAgICAgIC8qIGZhbGxzIHRocm91Z2ggKi9cbiAgICBjYXNlIE1BVENIOlxuICAgICAgaWYgKGxlZnQgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICBjb3B5ID0gX291dCAtIGxlZnQ7XG4gICAgICBpZiAoc3RhdGUub2Zmc2V0ID4gY29weSkgeyAgICAgICAgIC8qIGNvcHkgZnJvbSB3aW5kb3cgKi9cbiAgICAgICAgY29weSA9IHN0YXRlLm9mZnNldCAtIGNvcHk7XG4gICAgICAgIGlmIChjb3B5ID4gc3RhdGUud2hhdmUpIHtcbiAgICAgICAgICBpZiAoc3RhdGUuc2FuZSkge1xuICAgICAgICAgICAgc3RybS5tc2cgPSAnaW52YWxpZCBkaXN0YW5jZSB0b28gZmFyIGJhY2snO1xuICAgICAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgICAgIGJyZWFrO1xuICAgICAgICAgIH1cbi8vICghKSBUaGlzIGJsb2NrIGlzIGRpc2FibGVkIGluIHpsaWIgZGVmYWlsdHMsXG4vLyBkb24ndCBlbmFibGUgaXQgZm9yIGJpbmFyeSBjb21wYXRpYmlsaXR5XG4vLyNpZmRlZiBJTkZMQVRFX0FMTE9XX0lOVkFMSURfRElTVEFOQ0VfVE9PRkFSX0FSUlJcbi8vICAgICAgICAgIFRyYWNlKChzdGRlcnIsIFwiaW5mbGF0ZS5jIHRvbyBmYXJcXG5cIikpO1xuLy8gICAgICAgICAgY29weSAtPSBzdGF0ZS53aGF2ZTtcbi8vICAgICAgICAgIGlmIChjb3B5ID4gc3RhdGUubGVuZ3RoKSB7IGNvcHkgPSBzdGF0ZS5sZW5ndGg7IH1cbi8vICAgICAgICAgIGlmIChjb3B5ID4gbGVmdCkgeyBjb3B5ID0gbGVmdDsgfVxuLy8gICAgICAgICAgbGVmdCAtPSBjb3B5O1xuLy8gICAgICAgICAgc3RhdGUubGVuZ3RoIC09IGNvcHk7XG4vLyAgICAgICAgICBkbyB7XG4vLyAgICAgICAgICAgIG91dHB1dFtwdXQrK10gPSAwO1xuLy8gICAgICAgICAgfSB3aGlsZSAoLS1jb3B5KTtcbi8vICAgICAgICAgIGlmIChzdGF0ZS5sZW5ndGggPT09IDApIHsgc3RhdGUubW9kZSA9IExFTjsgfVxuLy8gICAgICAgICAgYnJlYWs7XG4vLyNlbmRpZlxuICAgICAgICB9XG4gICAgICAgIGlmIChjb3B5ID4gc3RhdGUud25leHQpIHtcbiAgICAgICAgICBjb3B5IC09IHN0YXRlLnduZXh0O1xuICAgICAgICAgIGZyb20gPSBzdGF0ZS53c2l6ZSAtIGNvcHk7XG4gICAgICAgIH1cbiAgICAgICAgZWxzZSB7XG4gICAgICAgICAgZnJvbSA9IHN0YXRlLnduZXh0IC0gY29weTtcbiAgICAgICAgfVxuICAgICAgICBpZiAoY29weSA+IHN0YXRlLmxlbmd0aCkgeyBjb3B5ID0gc3RhdGUubGVuZ3RoOyB9XG4gICAgICAgIGZyb21fc291cmNlID0gc3RhdGUud2luZG93O1xuICAgICAgfVxuICAgICAgZWxzZSB7ICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgLyogY29weSBmcm9tIG91dHB1dCAqL1xuICAgICAgICBmcm9tX3NvdXJjZSA9IG91dHB1dDtcbiAgICAgICAgZnJvbSA9IHB1dCAtIHN0YXRlLm9mZnNldDtcbiAgICAgICAgY29weSA9IHN0YXRlLmxlbmd0aDtcbiAgICAgIH1cbiAgICAgIGlmIChjb3B5ID4gbGVmdCkgeyBjb3B5ID0gbGVmdDsgfVxuICAgICAgbGVmdCAtPSBjb3B5O1xuICAgICAgc3RhdGUubGVuZ3RoIC09IGNvcHk7XG4gICAgICBkbyB7XG4gICAgICAgIG91dHB1dFtwdXQrK10gPSBmcm9tX3NvdXJjZVtmcm9tKytdO1xuICAgICAgfSB3aGlsZSAoLS1jb3B5KTtcbiAgICAgIGlmIChzdGF0ZS5sZW5ndGggPT09IDApIHsgc3RhdGUubW9kZSA9IExFTjsgfVxuICAgICAgYnJlYWs7XG4gICAgY2FzZSBMSVQ6XG4gICAgICBpZiAobGVmdCA9PT0gMCkgeyBicmVhayBpbmZfbGVhdmU7IH1cbiAgICAgIG91dHB1dFtwdXQrK10gPSBzdGF0ZS5sZW5ndGg7XG4gICAgICBsZWZ0LS07XG4gICAgICBzdGF0ZS5tb2RlID0gTEVOO1xuICAgICAgYnJlYWs7XG4gICAgY2FzZSBDSEVDSzpcbiAgICAgIGlmIChzdGF0ZS53cmFwKSB7XG4gICAgICAgIC8vPT09IE5FRURCSVRTKDMyKTtcbiAgICAgICAgd2hpbGUgKGJpdHMgPCAzMikge1xuICAgICAgICAgIGlmIChoYXZlID09PSAwKSB7IGJyZWFrIGluZl9sZWF2ZTsgfVxuICAgICAgICAgIGhhdmUtLTtcbiAgICAgICAgICAvLyBVc2UgJ3wnIGluc2RlYWQgb2YgJysnIHRvIG1ha2Ugc3VyZSB0aGF0IHJlc3VsdCBpcyBzaWduZWRcbiAgICAgICAgICBob2xkIHw9IGlucHV0W25leHQrK10gPDwgYml0cztcbiAgICAgICAgICBiaXRzICs9IDg7XG4gICAgICAgIH1cbiAgICAgICAgLy89PT0vL1xuICAgICAgICBfb3V0IC09IGxlZnQ7XG4gICAgICAgIHN0cm0udG90YWxfb3V0ICs9IF9vdXQ7XG4gICAgICAgIHN0YXRlLnRvdGFsICs9IF9vdXQ7XG4gICAgICAgIGlmIChfb3V0KSB7XG4gICAgICAgICAgc3RybS5hZGxlciA9IHN0YXRlLmNoZWNrID1cbiAgICAgICAgICAgICAgLypVUERBVEUoc3RhdGUuY2hlY2ssIHB1dCAtIF9vdXQsIF9vdXQpOyovXG4gICAgICAgICAgICAgIChzdGF0ZS5mbGFncyA/IGNyYzMyKHN0YXRlLmNoZWNrLCBvdXRwdXQsIF9vdXQsIHB1dCAtIF9vdXQpIDogYWRsZXIzMihzdGF0ZS5jaGVjaywgb3V0cHV0LCBfb3V0LCBwdXQgLSBfb3V0KSk7XG5cbiAgICAgICAgfVxuICAgICAgICBfb3V0ID0gbGVmdDtcbiAgICAgICAgLy8gTkI6IGNyYzMyIHN0b3JlZCBhcyBzaWduZWQgMzItYml0IGludCwgWlNXQVAzMiByZXR1cm5zIHNpZ25lZCB0b29cbiAgICAgICAgaWYgKChzdGF0ZS5mbGFncyA/IGhvbGQgOiBaU1dBUDMyKGhvbGQpKSAhPT0gc3RhdGUuY2hlY2spIHtcbiAgICAgICAgICBzdHJtLm1zZyA9ICdpbmNvcnJlY3QgZGF0YSBjaGVjayc7XG4gICAgICAgICAgc3RhdGUubW9kZSA9IEJBRDtcbiAgICAgICAgICBicmVhaztcbiAgICAgICAgfVxuICAgICAgICAvLz09PSBJTklUQklUUygpO1xuICAgICAgICBob2xkID0gMDtcbiAgICAgICAgYml0cyA9IDA7XG4gICAgICAgIC8vPT09Ly9cbiAgICAgICAgLy9UcmFjZXYoKHN0ZGVyciwgXCJpbmZsYXRlOiAgIGNoZWNrIG1hdGNoZXMgdHJhaWxlclxcblwiKSk7XG4gICAgICB9XG4gICAgICBzdGF0ZS5tb2RlID0gTEVOR1RIO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgTEVOR1RIOlxuICAgICAgaWYgKHN0YXRlLndyYXAgJiYgc3RhdGUuZmxhZ3MpIHtcbiAgICAgICAgLy89PT0gTkVFREJJVFMoMzIpO1xuICAgICAgICB3aGlsZSAoYml0cyA8IDMyKSB7XG4gICAgICAgICAgaWYgKGhhdmUgPT09IDApIHsgYnJlYWsgaW5mX2xlYXZlOyB9XG4gICAgICAgICAgaGF2ZS0tO1xuICAgICAgICAgIGhvbGQgKz0gaW5wdXRbbmV4dCsrXSA8PCBiaXRzO1xuICAgICAgICAgIGJpdHMgKz0gODtcbiAgICAgICAgfVxuICAgICAgICAvLz09PS8vXG4gICAgICAgIGlmIChob2xkICE9PSAoc3RhdGUudG90YWwgJiAweGZmZmZmZmZmKSkge1xuICAgICAgICAgIHN0cm0ubXNnID0gJ2luY29ycmVjdCBsZW5ndGggY2hlY2snO1xuICAgICAgICAgIHN0YXRlLm1vZGUgPSBCQUQ7XG4gICAgICAgICAgYnJlYWs7XG4gICAgICAgIH1cbiAgICAgICAgLy89PT0gSU5JVEJJVFMoKTtcbiAgICAgICAgaG9sZCA9IDA7XG4gICAgICAgIGJpdHMgPSAwO1xuICAgICAgICAvLz09PS8vXG4gICAgICAgIC8vVHJhY2V2KChzdGRlcnIsIFwiaW5mbGF0ZTogICBsZW5ndGggbWF0Y2hlcyB0cmFpbGVyXFxuXCIpKTtcbiAgICAgIH1cbiAgICAgIHN0YXRlLm1vZGUgPSBET05FO1xuICAgICAgLyogZmFsbHMgdGhyb3VnaCAqL1xuICAgIGNhc2UgRE9ORTpcbiAgICAgIHJldCA9IFpfU1RSRUFNX0VORDtcbiAgICAgIGJyZWFrIGluZl9sZWF2ZTtcbiAgICBjYXNlIEJBRDpcbiAgICAgIHJldCA9IFpfREFUQV9FUlJPUjtcbiAgICAgIGJyZWFrIGluZl9sZWF2ZTtcbiAgICBjYXNlIE1FTTpcbiAgICAgIHJldHVybiBaX01FTV9FUlJPUjtcbiAgICBjYXNlIFNZTkM6XG4gICAgICAvKiBmYWxscyB0aHJvdWdoICovXG4gICAgZGVmYXVsdDpcbiAgICAgIHJldHVybiBaX1NUUkVBTV9FUlJPUjtcbiAgICB9XG4gIH1cblxuICAvLyBpbmZfbGVhdmUgPC0gaGVyZSBpcyByZWFsIHBsYWNlIGZvciBcImdvdG8gaW5mX2xlYXZlXCIsIGVtdWxhdGVkIHZpYSBcImJyZWFrIGluZl9sZWF2ZVwiXG5cbiAgLypcbiAgICAgUmV0dXJuIGZyb20gaW5mbGF0ZSgpLCB1cGRhdGluZyB0aGUgdG90YWwgY291bnRzIGFuZCB0aGUgY2hlY2sgdmFsdWUuXG4gICAgIElmIHRoZXJlIHdhcyBubyBwcm9ncmVzcyBkdXJpbmcgdGhlIGluZmxhdGUoKSBjYWxsLCByZXR1cm4gYSBidWZmZXJcbiAgICAgZXJyb3IuICBDYWxsIHVwZGF0ZXdpbmRvdygpIHRvIGNyZWF0ZSBhbmQvb3IgdXBkYXRlIHRoZSB3aW5kb3cgc3RhdGUuXG4gICAgIE5vdGU6IGEgbWVtb3J5IGVycm9yIGZyb20gaW5mbGF0ZSgpIGlzIG5vbi1yZWNvdmVyYWJsZS5cbiAgICovXG5cbiAgLy8tLS0gUkVTVE9SRSgpIC0tLVxuICBzdHJtLm5leHRfb3V0ID0gcHV0O1xuICBzdHJtLmF2YWlsX291dCA9IGxlZnQ7XG4gIHN0cm0ubmV4dF9pbiA9IG5leHQ7XG4gIHN0cm0uYXZhaWxfaW4gPSBoYXZlO1xuICBzdGF0ZS5ob2xkID0gaG9sZDtcbiAgc3RhdGUuYml0cyA9IGJpdHM7XG4gIC8vLS0tXG5cbiAgaWYgKHN0YXRlLndzaXplIHx8IChfb3V0ICE9PSBzdHJtLmF2YWlsX291dCAmJiBzdGF0ZS5tb2RlIDwgQkFEICYmXG4gICAgICAgICAgICAgICAgICAgICAgKHN0YXRlLm1vZGUgPCBDSEVDSyB8fCBmbHVzaCAhPT0gWl9GSU5JU0gpKSkge1xuICAgIGlmICh1cGRhdGV3aW5kb3coc3RybSwgc3RybS5vdXRwdXQsIHN0cm0ubmV4dF9vdXQsIF9vdXQgLSBzdHJtLmF2YWlsX291dCkpIHtcbiAgICAgIHN0YXRlLm1vZGUgPSBNRU07XG4gICAgICByZXR1cm4gWl9NRU1fRVJST1I7XG4gICAgfVxuICB9XG4gIF9pbiAtPSBzdHJtLmF2YWlsX2luO1xuICBfb3V0IC09IHN0cm0uYXZhaWxfb3V0O1xuICBzdHJtLnRvdGFsX2luICs9IF9pbjtcbiAgc3RybS50b3RhbF9vdXQgKz0gX291dDtcbiAgc3RhdGUudG90YWwgKz0gX291dDtcbiAgaWYgKHN0YXRlLndyYXAgJiYgX291dCkge1xuICAgIHN0cm0uYWRsZXIgPSBzdGF0ZS5jaGVjayA9IC8qVVBEQVRFKHN0YXRlLmNoZWNrLCBzdHJtLm5leHRfb3V0IC0gX291dCwgX291dCk7Ki9cbiAgICAgIChzdGF0ZS5mbGFncyA/IGNyYzMyKHN0YXRlLmNoZWNrLCBvdXRwdXQsIF9vdXQsIHN0cm0ubmV4dF9vdXQgLSBfb3V0KSA6IGFkbGVyMzIoc3RhdGUuY2hlY2ssIG91dHB1dCwgX291dCwgc3RybS5uZXh0X291dCAtIF9vdXQpKTtcbiAgfVxuICBzdHJtLmRhdGFfdHlwZSA9IHN0YXRlLmJpdHMgKyAoc3RhdGUubGFzdCA/IDY0IDogMCkgK1xuICAgICAgICAgICAgICAgICAgICAoc3RhdGUubW9kZSA9PT0gVFlQRSA/IDEyOCA6IDApICtcbiAgICAgICAgICAgICAgICAgICAgKHN0YXRlLm1vZGUgPT09IExFTl8gfHwgc3RhdGUubW9kZSA9PT0gQ09QWV8gPyAyNTYgOiAwKTtcbiAgaWYgKCgoX2luID09PSAwICYmIF9vdXQgPT09IDApIHx8IGZsdXNoID09PSBaX0ZJTklTSCkgJiYgcmV0ID09PSBaX09LKSB7XG4gICAgcmV0ID0gWl9CVUZfRVJST1I7XG4gIH1cbiAgcmV0dXJuIHJldDtcbn1cblxuZnVuY3Rpb24gaW5mbGF0ZUVuZChzdHJtKSB7XG5cbiAgaWYgKCFzdHJtIHx8ICFzdHJtLnN0YXRlIC8qfHwgc3RybS0+emZyZWUgPT0gKGZyZWVfZnVuYykwKi8pIHtcbiAgICByZXR1cm4gWl9TVFJFQU1fRVJST1I7XG4gIH1cblxuICB2YXIgc3RhdGUgPSBzdHJtLnN0YXRlO1xuICBpZiAoc3RhdGUud2luZG93KSB7XG4gICAgc3RhdGUud2luZG93ID0gbnVsbDtcbiAgfVxuICBzdHJtLnN0YXRlID0gbnVsbDtcbiAgcmV0dXJuIFpfT0s7XG59XG5cbmZ1bmN0aW9uIGluZmxhdGVHZXRIZWFkZXIoc3RybSwgaGVhZCkge1xuICB2YXIgc3RhdGU7XG5cbiAgLyogY2hlY2sgc3RhdGUgKi9cbiAgaWYgKCFzdHJtIHx8ICFzdHJtLnN0YXRlKSB7IHJldHVybiBaX1NUUkVBTV9FUlJPUjsgfVxuICBzdGF0ZSA9IHN0cm0uc3RhdGU7XG4gIGlmICgoc3RhdGUud3JhcCAmIDIpID09PSAwKSB7IHJldHVybiBaX1NUUkVBTV9FUlJPUjsgfVxuXG4gIC8qIHNhdmUgaGVhZGVyIHN0cnVjdHVyZSAqL1xuICBzdGF0ZS5oZWFkID0gaGVhZDtcbiAgaGVhZC5kb25lID0gZmFsc2U7XG4gIHJldHVybiBaX09LO1xufVxuXG5cbmV4cG9ydHMuaW5mbGF0ZVJlc2V0ID0gaW5mbGF0ZVJlc2V0O1xuZXhwb3J0cy5pbmZsYXRlUmVzZXQyID0gaW5mbGF0ZVJlc2V0MjtcbmV4cG9ydHMuaW5mbGF0ZVJlc2V0S2VlcCA9IGluZmxhdGVSZXNldEtlZXA7XG5leHBvcnRzLmluZmxhdGVJbml0ID0gaW5mbGF0ZUluaXQ7XG5leHBvcnRzLmluZmxhdGVJbml0MiA9IGluZmxhdGVJbml0MjtcbmV4cG9ydHMuaW5mbGF0ZSA9IGluZmxhdGU7XG5leHBvcnRzLmluZmxhdGVFbmQgPSBpbmZsYXRlRW5kO1xuZXhwb3J0cy5pbmZsYXRlR2V0SGVhZGVyID0gaW5mbGF0ZUdldEhlYWRlcjtcbmV4cG9ydHMuaW5mbGF0ZUluZm8gPSAncGFrbyBpbmZsYXRlIChmcm9tIE5vZGVjYSBwcm9qZWN0KSc7XG5cbi8qIE5vdCBpbXBsZW1lbnRlZFxuZXhwb3J0cy5pbmZsYXRlQ29weSA9IGluZmxhdGVDb3B5O1xuZXhwb3J0cy5pbmZsYXRlR2V0RGljdGlvbmFyeSA9IGluZmxhdGVHZXREaWN0aW9uYXJ5O1xuZXhwb3J0cy5pbmZsYXRlTWFyayA9IGluZmxhdGVNYXJrO1xuZXhwb3J0cy5pbmZsYXRlUHJpbWUgPSBpbmZsYXRlUHJpbWU7XG5leHBvcnRzLmluZmxhdGVTZXREaWN0aW9uYXJ5ID0gaW5mbGF0ZVNldERpY3Rpb25hcnk7XG5leHBvcnRzLmluZmxhdGVTeW5jID0gaW5mbGF0ZVN5bmM7XG5leHBvcnRzLmluZmxhdGVTeW5jUG9pbnQgPSBpbmZsYXRlU3luY1BvaW50O1xuZXhwb3J0cy5pbmZsYXRlVW5kZXJtaW5lID0gaW5mbGF0ZVVuZGVybWluZTtcbiovIiwiJ3VzZSBzdHJpY3QnO1xuXG5cbnZhciB1dGlscyA9IHJlcXVpcmUoJy4uL3V0aWxzL2NvbW1vbicpO1xuXG52YXIgTUFYQklUUyA9IDE1O1xudmFyIEVOT1VHSF9MRU5TID0gODUyO1xudmFyIEVOT1VHSF9ESVNUUyA9IDU5Mjtcbi8vdmFyIEVOT1VHSCA9IChFTk9VR0hfTEVOUytFTk9VR0hfRElTVFMpO1xuXG52YXIgQ09ERVMgPSAwO1xudmFyIExFTlMgPSAxO1xudmFyIERJU1RTID0gMjtcblxudmFyIGxiYXNlID0gWyAvKiBMZW5ndGggY29kZXMgMjU3Li4yODUgYmFzZSAqL1xuICAzLCA0LCA1LCA2LCA3LCA4LCA5LCAxMCwgMTEsIDEzLCAxNSwgMTcsIDE5LCAyMywgMjcsIDMxLFxuICAzNSwgNDMsIDUxLCA1OSwgNjcsIDgzLCA5OSwgMTE1LCAxMzEsIDE2MywgMTk1LCAyMjcsIDI1OCwgMCwgMFxuXTtcblxudmFyIGxleHQgPSBbIC8qIExlbmd0aCBjb2RlcyAyNTcuLjI4NSBleHRyYSAqL1xuICAxNiwgMTYsIDE2LCAxNiwgMTYsIDE2LCAxNiwgMTYsIDE3LCAxNywgMTcsIDE3LCAxOCwgMTgsIDE4LCAxOCxcbiAgMTksIDE5LCAxOSwgMTksIDIwLCAyMCwgMjAsIDIwLCAyMSwgMjEsIDIxLCAyMSwgMTYsIDcyLCA3OFxuXTtcblxudmFyIGRiYXNlID0gWyAvKiBEaXN0YW5jZSBjb2RlcyAwLi4yOSBiYXNlICovXG4gIDEsIDIsIDMsIDQsIDUsIDcsIDksIDEzLCAxNywgMjUsIDMzLCA0OSwgNjUsIDk3LCAxMjksIDE5MyxcbiAgMjU3LCAzODUsIDUxMywgNzY5LCAxMDI1LCAxNTM3LCAyMDQ5LCAzMDczLCA0MDk3LCA2MTQ1LFxuICA4MTkzLCAxMjI4OSwgMTYzODUsIDI0NTc3LCAwLCAwXG5dO1xuXG52YXIgZGV4dCA9IFsgLyogRGlzdGFuY2UgY29kZXMgMC4uMjkgZXh0cmEgKi9cbiAgMTYsIDE2LCAxNiwgMTYsIDE3LCAxNywgMTgsIDE4LCAxOSwgMTksIDIwLCAyMCwgMjEsIDIxLCAyMiwgMjIsXG4gIDIzLCAyMywgMjQsIDI0LCAyNSwgMjUsIDI2LCAyNiwgMjcsIDI3LFxuICAyOCwgMjgsIDI5LCAyOSwgNjQsIDY0XG5dO1xuXG5tb2R1bGUuZXhwb3J0cyA9IGZ1bmN0aW9uIGluZmxhdGVfdGFibGUodHlwZSwgbGVucywgbGVuc19pbmRleCwgY29kZXMsIHRhYmxlLCB0YWJsZV9pbmRleCwgd29yaywgb3B0cylcbntcbiAgdmFyIGJpdHMgPSBvcHRzLmJpdHM7XG4gICAgICAvL2hlcmUgPSBvcHRzLmhlcmU7IC8qIHRhYmxlIGVudHJ5IGZvciBkdXBsaWNhdGlvbiAqL1xuXG4gIHZhciBsZW4gPSAwOyAgICAgICAgICAgICAgIC8qIGEgY29kZSdzIGxlbmd0aCBpbiBiaXRzICovXG4gIHZhciBzeW0gPSAwOyAgICAgICAgICAgICAgIC8qIGluZGV4IG9mIGNvZGUgc3ltYm9scyAqL1xuICB2YXIgbWluID0gMCwgbWF4ID0gMDsgICAgICAgICAgLyogbWluaW11bSBhbmQgbWF4aW11bSBjb2RlIGxlbmd0aHMgKi9cbiAgdmFyIHJvb3QgPSAwOyAgICAgICAgICAgICAgLyogbnVtYmVyIG9mIGluZGV4IGJpdHMgZm9yIHJvb3QgdGFibGUgKi9cbiAgdmFyIGN1cnIgPSAwOyAgICAgICAgICAgICAgLyogbnVtYmVyIG9mIGluZGV4IGJpdHMgZm9yIGN1cnJlbnQgdGFibGUgKi9cbiAgdmFyIGRyb3AgPSAwOyAgICAgICAgICAgICAgLyogY29kZSBiaXRzIHRvIGRyb3AgZm9yIHN1Yi10YWJsZSAqL1xuICB2YXIgbGVmdCA9IDA7ICAgICAgICAgICAgICAgICAgIC8qIG51bWJlciBvZiBwcmVmaXggY29kZXMgYXZhaWxhYmxlICovXG4gIHZhciB1c2VkID0gMDsgICAgICAgICAgICAgIC8qIGNvZGUgZW50cmllcyBpbiB0YWJsZSB1c2VkICovXG4gIHZhciBodWZmID0gMDsgICAgICAgICAgICAgIC8qIEh1ZmZtYW4gY29kZSAqL1xuICB2YXIgaW5jcjsgICAgICAgICAgICAgIC8qIGZvciBpbmNyZW1lbnRpbmcgY29kZSwgaW5kZXggKi9cbiAgdmFyIGZpbGw7ICAgICAgICAgICAgICAvKiBpbmRleCBmb3IgcmVwbGljYXRpbmcgZW50cmllcyAqL1xuICB2YXIgbG93OyAgICAgICAgICAgICAgIC8qIGxvdyBiaXRzIGZvciBjdXJyZW50IHJvb3QgZW50cnkgKi9cbiAgdmFyIG1hc2s7ICAgICAgICAgICAgICAvKiBtYXNrIGZvciBsb3cgcm9vdCBiaXRzICovXG4gIHZhciBuZXh0OyAgICAgICAgICAgICAvKiBuZXh0IGF2YWlsYWJsZSBzcGFjZSBpbiB0YWJsZSAqL1xuICB2YXIgYmFzZSA9IG51bGw7ICAgICAvKiBiYXNlIHZhbHVlIHRhYmxlIHRvIHVzZSAqL1xuICB2YXIgYmFzZV9pbmRleCA9IDA7XG4vLyAgdmFyIHNob2V4dHJhOyAgICAvKiBleHRyYSBiaXRzIHRhYmxlIHRvIHVzZSAqL1xuICB2YXIgZW5kOyAgICAgICAgICAgICAgICAgICAgLyogdXNlIGJhc2UgYW5kIGV4dHJhIGZvciBzeW1ib2wgPiBlbmQgKi9cbiAgdmFyIGNvdW50ID0gbmV3IHV0aWxzLkJ1ZjE2KE1BWEJJVFMrMSk7IC8vW01BWEJJVFMrMV07ICAgIC8qIG51bWJlciBvZiBjb2RlcyBvZiBlYWNoIGxlbmd0aCAqL1xuICB2YXIgb2ZmcyA9IG5ldyB1dGlscy5CdWYxNihNQVhCSVRTKzEpOyAvL1tNQVhCSVRTKzFdOyAgICAgLyogb2Zmc2V0cyBpbiB0YWJsZSBmb3IgZWFjaCBsZW5ndGggKi9cbiAgdmFyIGV4dHJhID0gbnVsbDtcbiAgdmFyIGV4dHJhX2luZGV4ID0gMDtcblxuICB2YXIgaGVyZV9iaXRzLCBoZXJlX29wLCBoZXJlX3ZhbDtcblxuICAvKlxuICAgUHJvY2VzcyBhIHNldCBvZiBjb2RlIGxlbmd0aHMgdG8gY3JlYXRlIGEgY2Fub25pY2FsIEh1ZmZtYW4gY29kZS4gIFRoZVxuICAgY29kZSBsZW5ndGhzIGFyZSBsZW5zWzAuLmNvZGVzLTFdLiAgRWFjaCBsZW5ndGggY29ycmVzcG9uZHMgdG8gdGhlXG4gICBzeW1ib2xzIDAuLmNvZGVzLTEuICBUaGUgSHVmZm1hbiBjb2RlIGlzIGdlbmVyYXRlZCBieSBmaXJzdCBzb3J0aW5nIHRoZVxuICAgc3ltYm9scyBieSBsZW5ndGggZnJvbSBzaG9ydCB0byBsb25nLCBhbmQgcmV0YWluaW5nIHRoZSBzeW1ib2wgb3JkZXJcbiAgIGZvciBjb2RlcyB3aXRoIGVxdWFsIGxlbmd0aHMuICBUaGVuIHRoZSBjb2RlIHN0YXJ0cyB3aXRoIGFsbCB6ZXJvIGJpdHNcbiAgIGZvciB0aGUgZmlyc3QgY29kZSBvZiB0aGUgc2hvcnRlc3QgbGVuZ3RoLCBhbmQgdGhlIGNvZGVzIGFyZSBpbnRlZ2VyXG4gICBpbmNyZW1lbnRzIGZvciB0aGUgc2FtZSBsZW5ndGgsIGFuZCB6ZXJvcyBhcmUgYXBwZW5kZWQgYXMgdGhlIGxlbmd0aFxuICAgaW5jcmVhc2VzLiAgRm9yIHRoZSBkZWZsYXRlIGZvcm1hdCwgdGhlc2UgYml0cyBhcmUgc3RvcmVkIGJhY2t3YXJkc1xuICAgZnJvbSB0aGVpciBtb3JlIG5hdHVyYWwgaW50ZWdlciBpbmNyZW1lbnQgb3JkZXJpbmcsIGFuZCBzbyB3aGVuIHRoZVxuICAgZGVjb2RpbmcgdGFibGVzIGFyZSBidWlsdCBpbiB0aGUgbGFyZ2UgbG9vcCBiZWxvdywgdGhlIGludGVnZXIgY29kZXNcbiAgIGFyZSBpbmNyZW1lbnRlZCBiYWNrd2FyZHMuXG5cbiAgIFRoaXMgcm91dGluZSBhc3N1bWVzLCBidXQgZG9lcyBub3QgY2hlY2ssIHRoYXQgYWxsIG9mIHRoZSBlbnRyaWVzIGluXG4gICBsZW5zW10gYXJlIGluIHRoZSByYW5nZSAwLi5NQVhCSVRTLiAgVGhlIGNhbGxlciBtdXN0IGFzc3VyZSB0aGlzLlxuICAgMS4uTUFYQklUUyBpcyBpbnRlcnByZXRlZCBhcyB0aGF0IGNvZGUgbGVuZ3RoLiAgemVybyBtZWFucyB0aGF0IHRoYXRcbiAgIHN5bWJvbCBkb2VzIG5vdCBvY2N1ciBpbiB0aGlzIGNvZGUuXG5cbiAgIFRoZSBjb2RlcyBhcmUgc29ydGVkIGJ5IGNvbXB1dGluZyBhIGNvdW50IG9mIGNvZGVzIGZvciBlYWNoIGxlbmd0aCxcbiAgIGNyZWF0aW5nIGZyb20gdGhhdCBhIHRhYmxlIG9mIHN0YXJ0aW5nIGluZGljZXMgZm9yIGVhY2ggbGVuZ3RoIGluIHRoZVxuICAgc29ydGVkIHRhYmxlLCBhbmQgdGhlbiBlbnRlcmluZyB0aGUgc3ltYm9scyBpbiBvcmRlciBpbiB0aGUgc29ydGVkXG4gICB0YWJsZS4gIFRoZSBzb3J0ZWQgdGFibGUgaXMgd29ya1tdLCB3aXRoIHRoYXQgc3BhY2UgYmVpbmcgcHJvdmlkZWQgYnlcbiAgIHRoZSBjYWxsZXIuXG5cbiAgIFRoZSBsZW5ndGggY291bnRzIGFyZSB1c2VkIGZvciBvdGhlciBwdXJwb3NlcyBhcyB3ZWxsLCBpLmUuIGZpbmRpbmdcbiAgIHRoZSBtaW5pbXVtIGFuZCBtYXhpbXVtIGxlbmd0aCBjb2RlcywgZGV0ZXJtaW5pbmcgaWYgdGhlcmUgYXJlIGFueVxuICAgY29kZXMgYXQgYWxsLCBjaGVja2luZyBmb3IgYSB2YWxpZCBzZXQgb2YgbGVuZ3RocywgYW5kIGxvb2tpbmcgYWhlYWRcbiAgIGF0IGxlbmd0aCBjb3VudHMgdG8gZGV0ZXJtaW5lIHN1Yi10YWJsZSBzaXplcyB3aGVuIGJ1aWxkaW5nIHRoZVxuICAgZGVjb2RpbmcgdGFibGVzLlxuICAgKi9cblxuICAvKiBhY2N1bXVsYXRlIGxlbmd0aHMgZm9yIGNvZGVzIChhc3N1bWVzIGxlbnNbXSBhbGwgaW4gMC4uTUFYQklUUykgKi9cbiAgZm9yIChsZW4gPSAwOyBsZW4gPD0gTUFYQklUUzsgbGVuKyspIHtcbiAgICBjb3VudFtsZW5dID0gMDtcbiAgfVxuICBmb3IgKHN5bSA9IDA7IHN5bSA8IGNvZGVzOyBzeW0rKykge1xuICAgIGNvdW50W2xlbnNbbGVuc19pbmRleCArIHN5bV1dKys7XG4gIH1cblxuICAvKiBib3VuZCBjb2RlIGxlbmd0aHMsIGZvcmNlIHJvb3QgdG8gYmUgd2l0aGluIGNvZGUgbGVuZ3RocyAqL1xuICByb290ID0gYml0cztcbiAgZm9yIChtYXggPSBNQVhCSVRTOyBtYXggPj0gMTsgbWF4LS0pIHtcbiAgICBpZiAoY291bnRbbWF4XSAhPT0gMCkgeyBicmVhazsgfVxuICB9XG4gIGlmIChyb290ID4gbWF4KSB7XG4gICAgcm9vdCA9IG1heDtcbiAgfVxuICBpZiAobWF4ID09PSAwKSB7ICAgICAgICAgICAgICAgICAgICAgLyogbm8gc3ltYm9scyB0byBjb2RlIGF0IGFsbCAqL1xuICAgIC8vdGFibGUub3Bbb3B0cy50YWJsZV9pbmRleF0gPSA2NDsgIC8vaGVyZS5vcCA9ICh2YXIgY2hhcik2NDsgICAgLyogaW52YWxpZCBjb2RlIG1hcmtlciAqL1xuICAgIC8vdGFibGUuYml0c1tvcHRzLnRhYmxlX2luZGV4XSA9IDE7ICAgLy9oZXJlLmJpdHMgPSAodmFyIGNoYXIpMTtcbiAgICAvL3RhYmxlLnZhbFtvcHRzLnRhYmxlX2luZGV4KytdID0gMDsgICAvL2hlcmUudmFsID0gKHZhciBzaG9ydCkwO1xuICAgIHRhYmxlW3RhYmxlX2luZGV4KytdID0gKDEgPDwgMjQpIHwgKDY0IDw8IDE2KSB8IDA7XG5cblxuICAgIC8vdGFibGUub3Bbb3B0cy50YWJsZV9pbmRleF0gPSA2NDtcbiAgICAvL3RhYmxlLmJpdHNbb3B0cy50YWJsZV9pbmRleF0gPSAxO1xuICAgIC8vdGFibGUudmFsW29wdHMudGFibGVfaW5kZXgrK10gPSAwO1xuICAgIHRhYmxlW3RhYmxlX2luZGV4KytdID0gKDEgPDwgMjQpIHwgKDY0IDw8IDE2KSB8IDA7XG5cbiAgICBvcHRzLmJpdHMgPSAxO1xuICAgIHJldHVybiAwOyAgICAgLyogbm8gc3ltYm9scywgYnV0IHdhaXQgZm9yIGRlY29kaW5nIHRvIHJlcG9ydCBlcnJvciAqL1xuICB9XG4gIGZvciAobWluID0gMTsgbWluIDwgbWF4OyBtaW4rKykge1xuICAgIGlmIChjb3VudFttaW5dICE9PSAwKSB7IGJyZWFrOyB9XG4gIH1cbiAgaWYgKHJvb3QgPCBtaW4pIHtcbiAgICByb290ID0gbWluO1xuICB9XG5cbiAgLyogY2hlY2sgZm9yIGFuIG92ZXItc3Vic2NyaWJlZCBvciBpbmNvbXBsZXRlIHNldCBvZiBsZW5ndGhzICovXG4gIGxlZnQgPSAxO1xuICBmb3IgKGxlbiA9IDE7IGxlbiA8PSBNQVhCSVRTOyBsZW4rKykge1xuICAgIGxlZnQgPDw9IDE7XG4gICAgbGVmdCAtPSBjb3VudFtsZW5dO1xuICAgIGlmIChsZWZ0IDwgMCkge1xuICAgICAgcmV0dXJuIC0xO1xuICAgIH0gICAgICAgIC8qIG92ZXItc3Vic2NyaWJlZCAqL1xuICB9XG4gIGlmIChsZWZ0ID4gMCAmJiAodHlwZSA9PT0gQ09ERVMgfHwgbWF4ICE9PSAxKSkge1xuICAgIHJldHVybiAtMTsgICAgICAgICAgICAgICAgICAgICAgLyogaW5jb21wbGV0ZSBzZXQgKi9cbiAgfVxuXG4gIC8qIGdlbmVyYXRlIG9mZnNldHMgaW50byBzeW1ib2wgdGFibGUgZm9yIGVhY2ggbGVuZ3RoIGZvciBzb3J0aW5nICovXG4gIG9mZnNbMV0gPSAwO1xuICBmb3IgKGxlbiA9IDE7IGxlbiA8IE1BWEJJVFM7IGxlbisrKSB7XG4gICAgb2Zmc1tsZW4gKyAxXSA9IG9mZnNbbGVuXSArIGNvdW50W2xlbl07XG4gIH1cblxuICAvKiBzb3J0IHN5bWJvbHMgYnkgbGVuZ3RoLCBieSBzeW1ib2wgb3JkZXIgd2l0aGluIGVhY2ggbGVuZ3RoICovXG4gIGZvciAoc3ltID0gMDsgc3ltIDwgY29kZXM7IHN5bSsrKSB7XG4gICAgaWYgKGxlbnNbbGVuc19pbmRleCArIHN5bV0gIT09IDApIHtcbiAgICAgIHdvcmtbb2Zmc1tsZW5zW2xlbnNfaW5kZXggKyBzeW1dXSsrXSA9IHN5bTtcbiAgICB9XG4gIH1cblxuICAvKlxuICAgQ3JlYXRlIGFuZCBmaWxsIGluIGRlY29kaW5nIHRhYmxlcy4gIEluIHRoaXMgbG9vcCwgdGhlIHRhYmxlIGJlaW5nXG4gICBmaWxsZWQgaXMgYXQgbmV4dCBhbmQgaGFzIGN1cnIgaW5kZXggYml0cy4gIFRoZSBjb2RlIGJlaW5nIHVzZWQgaXMgaHVmZlxuICAgd2l0aCBsZW5ndGggbGVuLiAgVGhhdCBjb2RlIGlzIGNvbnZlcnRlZCB0byBhbiBpbmRleCBieSBkcm9wcGluZyBkcm9wXG4gICBiaXRzIG9mZiBvZiB0aGUgYm90dG9tLiAgRm9yIGNvZGVzIHdoZXJlIGxlbiBpcyBsZXNzIHRoYW4gZHJvcCArIGN1cnIsXG4gICB0aG9zZSB0b3AgZHJvcCArIGN1cnIgLSBsZW4gYml0cyBhcmUgaW5jcmVtZW50ZWQgdGhyb3VnaCBhbGwgdmFsdWVzIHRvXG4gICBmaWxsIHRoZSB0YWJsZSB3aXRoIHJlcGxpY2F0ZWQgZW50cmllcy5cblxuICAgcm9vdCBpcyB0aGUgbnVtYmVyIG9mIGluZGV4IGJpdHMgZm9yIHRoZSByb290IHRhYmxlLiAgV2hlbiBsZW4gZXhjZWVkc1xuICAgcm9vdCwgc3ViLXRhYmxlcyBhcmUgY3JlYXRlZCBwb2ludGVkIHRvIGJ5IHRoZSByb290IGVudHJ5IHdpdGggYW4gaW5kZXhcbiAgIG9mIHRoZSBsb3cgcm9vdCBiaXRzIG9mIGh1ZmYuICBUaGlzIGlzIHNhdmVkIGluIGxvdyB0byBjaGVjayBmb3Igd2hlbiBhXG4gICBuZXcgc3ViLXRhYmxlIHNob3VsZCBiZSBzdGFydGVkLiAgZHJvcCBpcyB6ZXJvIHdoZW4gdGhlIHJvb3QgdGFibGUgaXNcbiAgIGJlaW5nIGZpbGxlZCwgYW5kIGRyb3AgaXMgcm9vdCB3aGVuIHN1Yi10YWJsZXMgYXJlIGJlaW5nIGZpbGxlZC5cblxuICAgV2hlbiBhIG5ldyBzdWItdGFibGUgaXMgbmVlZGVkLCBpdCBpcyBuZWNlc3NhcnkgdG8gbG9vayBhaGVhZCBpbiB0aGVcbiAgIGNvZGUgbGVuZ3RocyB0byBkZXRlcm1pbmUgd2hhdCBzaXplIHN1Yi10YWJsZSBpcyBuZWVkZWQuICBUaGUgbGVuZ3RoXG4gICBjb3VudHMgYXJlIHVzZWQgZm9yIHRoaXMsIGFuZCBzbyBjb3VudFtdIGlzIGRlY3JlbWVudGVkIGFzIGNvZGVzIGFyZVxuICAgZW50ZXJlZCBpbiB0aGUgdGFibGVzLlxuXG4gICB1c2VkIGtlZXBzIHRyYWNrIG9mIGhvdyBtYW55IHRhYmxlIGVudHJpZXMgaGF2ZSBiZWVuIGFsbG9jYXRlZCBmcm9tIHRoZVxuICAgcHJvdmlkZWQgKnRhYmxlIHNwYWNlLiAgSXQgaXMgY2hlY2tlZCBmb3IgTEVOUyBhbmQgRElTVCB0YWJsZXMgYWdhaW5zdFxuICAgdGhlIGNvbnN0YW50cyBFTk9VR0hfTEVOUyBhbmQgRU5PVUdIX0RJU1RTIHRvIGd1YXJkIGFnYWluc3QgY2hhbmdlcyBpblxuICAgdGhlIGluaXRpYWwgcm9vdCB0YWJsZSBzaXplIGNvbnN0YW50cy4gIFNlZSB0aGUgY29tbWVudHMgaW4gaW5mdHJlZXMuaFxuICAgZm9yIG1vcmUgaW5mb3JtYXRpb24uXG5cbiAgIHN5bSBpbmNyZW1lbnRzIHRocm91Z2ggYWxsIHN5bWJvbHMsIGFuZCB0aGUgbG9vcCB0ZXJtaW5hdGVzIHdoZW5cbiAgIGFsbCBjb2RlcyBvZiBsZW5ndGggbWF4LCBpLmUuIGFsbCBjb2RlcywgaGF2ZSBiZWVuIHByb2Nlc3NlZC4gIFRoaXNcbiAgIHJvdXRpbmUgcGVybWl0cyBpbmNvbXBsZXRlIGNvZGVzLCBzbyBhbm90aGVyIGxvb3AgYWZ0ZXIgdGhpcyBvbmUgZmlsbHNcbiAgIGluIHRoZSByZXN0IG9mIHRoZSBkZWNvZGluZyB0YWJsZXMgd2l0aCBpbnZhbGlkIGNvZGUgbWFya2Vycy5cbiAgICovXG5cbiAgLyogc2V0IHVwIGZvciBjb2RlIHR5cGUgKi9cbiAgLy8gcG9vciBtYW4gb3B0aW1pemF0aW9uIC0gdXNlIGlmLWVsc2UgaW5zdGVhZCBvZiBzd2l0Y2gsXG4gIC8vIHRvIGF2b2lkIGRlb3B0cyBpbiBvbGQgdjhcbiAgaWYgKHR5cGUgPT09IENPREVTKSB7XG4gICAgICBiYXNlID0gZXh0cmEgPSB3b3JrOyAgICAvKiBkdW1teSB2YWx1ZS0tbm90IHVzZWQgKi9cbiAgICAgIGVuZCA9IDE5O1xuICB9IGVsc2UgaWYgKHR5cGUgPT09IExFTlMpIHtcbiAgICAgIGJhc2UgPSBsYmFzZTtcbiAgICAgIGJhc2VfaW5kZXggLT0gMjU3O1xuICAgICAgZXh0cmEgPSBsZXh0O1xuICAgICAgZXh0cmFfaW5kZXggLT0gMjU3O1xuICAgICAgZW5kID0gMjU2O1xuICB9IGVsc2UgeyAgICAgICAgICAgICAgICAgICAgLyogRElTVFMgKi9cbiAgICAgIGJhc2UgPSBkYmFzZTtcbiAgICAgIGV4dHJhID0gZGV4dDtcbiAgICAgIGVuZCA9IC0xO1xuICB9XG5cbiAgLyogaW5pdGlhbGl6ZSBvcHRzIGZvciBsb29wICovXG4gIGh1ZmYgPSAwOyAgICAgICAgICAgICAgICAgICAvKiBzdGFydGluZyBjb2RlICovXG4gIHN5bSA9IDA7ICAgICAgICAgICAgICAgICAgICAvKiBzdGFydGluZyBjb2RlIHN5bWJvbCAqL1xuICBsZW4gPSBtaW47ICAgICAgICAgICAgICAgICAgLyogc3RhcnRpbmcgY29kZSBsZW5ndGggKi9cbiAgbmV4dCA9IHRhYmxlX2luZGV4OyAgICAgICAgICAgICAgLyogY3VycmVudCB0YWJsZSB0byBmaWxsIGluICovXG4gIGN1cnIgPSByb290OyAgICAgICAgICAgICAgICAvKiBjdXJyZW50IHRhYmxlIGluZGV4IGJpdHMgKi9cbiAgZHJvcCA9IDA7ICAgICAgICAgICAgICAgICAgIC8qIGN1cnJlbnQgYml0cyB0byBkcm9wIGZyb20gY29kZSBmb3IgaW5kZXggKi9cbiAgbG93ID0gLTE7ICAgICAgICAgICAgICAgICAgIC8qIHRyaWdnZXIgbmV3IHN1Yi10YWJsZSB3aGVuIGxlbiA+IHJvb3QgKi9cbiAgdXNlZCA9IDEgPDwgcm9vdDsgICAgICAgICAgLyogdXNlIHJvb3QgdGFibGUgZW50cmllcyAqL1xuICBtYXNrID0gdXNlZCAtIDE7ICAgICAgICAgICAgLyogbWFzayBmb3IgY29tcGFyaW5nIGxvdyAqL1xuXG4gIC8qIGNoZWNrIGF2YWlsYWJsZSB0YWJsZSBzcGFjZSAqL1xuICBpZiAoKHR5cGUgPT09IExFTlMgJiYgdXNlZCA+IEVOT1VHSF9MRU5TKSB8fFxuICAgICh0eXBlID09PSBESVNUUyAmJiB1c2VkID4gRU5PVUdIX0RJU1RTKSkge1xuICAgIHJldHVybiAxO1xuICB9XG5cbiAgdmFyIGk9MDtcbiAgLyogcHJvY2VzcyBhbGwgY29kZXMgYW5kIG1ha2UgdGFibGUgZW50cmllcyAqL1xuICBmb3IgKDs7KSB7XG4gICAgaSsrO1xuICAgIC8qIGNyZWF0ZSB0YWJsZSBlbnRyeSAqL1xuICAgIGhlcmVfYml0cyA9IGxlbiAtIGRyb3A7XG4gICAgaWYgKHdvcmtbc3ltXSA8IGVuZCkge1xuICAgICAgaGVyZV9vcCA9IDA7XG4gICAgICBoZXJlX3ZhbCA9IHdvcmtbc3ltXTtcbiAgICB9XG4gICAgZWxzZSBpZiAod29ya1tzeW1dID4gZW5kKSB7XG4gICAgICBoZXJlX29wID0gZXh0cmFbZXh0cmFfaW5kZXggKyB3b3JrW3N5bV1dO1xuICAgICAgaGVyZV92YWwgPSBiYXNlW2Jhc2VfaW5kZXggKyB3b3JrW3N5bV1dO1xuICAgIH1cbiAgICBlbHNlIHtcbiAgICAgIGhlcmVfb3AgPSAzMiArIDY0OyAgICAgICAgIC8qIGVuZCBvZiBibG9jayAqL1xuICAgICAgaGVyZV92YWwgPSAwO1xuICAgIH1cblxuICAgIC8qIHJlcGxpY2F0ZSBmb3IgdGhvc2UgaW5kaWNlcyB3aXRoIGxvdyBsZW4gYml0cyBlcXVhbCB0byBodWZmICovXG4gICAgaW5jciA9IDEgPDwgKGxlbiAtIGRyb3ApO1xuICAgIGZpbGwgPSAxIDw8IGN1cnI7XG4gICAgbWluID0gZmlsbDsgICAgICAgICAgICAgICAgIC8qIHNhdmUgb2Zmc2V0IHRvIG5leHQgdGFibGUgKi9cbiAgICBkbyB7XG4gICAgICBmaWxsIC09IGluY3I7XG4gICAgICB0YWJsZVtuZXh0ICsgKGh1ZmYgPj4gZHJvcCkgKyBmaWxsXSA9IChoZXJlX2JpdHMgPDwgMjQpIHwgKGhlcmVfb3AgPDwgMTYpIHwgaGVyZV92YWwgfDA7XG4gICAgfSB3aGlsZSAoZmlsbCAhPT0gMCk7XG5cbiAgICAvKiBiYWNrd2FyZHMgaW5jcmVtZW50IHRoZSBsZW4tYml0IGNvZGUgaHVmZiAqL1xuICAgIGluY3IgPSAxIDw8IChsZW4gLSAxKTtcbiAgICB3aGlsZSAoaHVmZiAmIGluY3IpIHtcbiAgICAgIGluY3IgPj49IDE7XG4gICAgfVxuICAgIGlmIChpbmNyICE9PSAwKSB7XG4gICAgICBodWZmICY9IGluY3IgLSAxO1xuICAgICAgaHVmZiArPSBpbmNyO1xuICAgIH0gZWxzZSB7XG4gICAgICBodWZmID0gMDtcbiAgICB9XG5cbiAgICAvKiBnbyB0byBuZXh0IHN5bWJvbCwgdXBkYXRlIGNvdW50LCBsZW4gKi9cbiAgICBzeW0rKztcbiAgICBpZiAoLS1jb3VudFtsZW5dID09PSAwKSB7XG4gICAgICBpZiAobGVuID09PSBtYXgpIHsgYnJlYWs7IH1cbiAgICAgIGxlbiA9IGxlbnNbbGVuc19pbmRleCArIHdvcmtbc3ltXV07XG4gICAgfVxuXG4gICAgLyogY3JlYXRlIG5ldyBzdWItdGFibGUgaWYgbmVlZGVkICovXG4gICAgaWYgKGxlbiA+IHJvb3QgJiYgKGh1ZmYgJiBtYXNrKSAhPT0gbG93KSB7XG4gICAgICAvKiBpZiBmaXJzdCB0aW1lLCB0cmFuc2l0aW9uIHRvIHN1Yi10YWJsZXMgKi9cbiAgICAgIGlmIChkcm9wID09PSAwKSB7XG4gICAgICAgIGRyb3AgPSByb290O1xuICAgICAgfVxuXG4gICAgICAvKiBpbmNyZW1lbnQgcGFzdCBsYXN0IHRhYmxlICovXG4gICAgICBuZXh0ICs9IG1pbjsgICAgICAgICAgICAvKiBoZXJlIG1pbiBpcyAxIDw8IGN1cnIgKi9cblxuICAgICAgLyogZGV0ZXJtaW5lIGxlbmd0aCBvZiBuZXh0IHRhYmxlICovXG4gICAgICBjdXJyID0gbGVuIC0gZHJvcDtcbiAgICAgIGxlZnQgPSAxIDw8IGN1cnI7XG4gICAgICB3aGlsZSAoY3VyciArIGRyb3AgPCBtYXgpIHtcbiAgICAgICAgbGVmdCAtPSBjb3VudFtjdXJyICsgZHJvcF07XG4gICAgICAgIGlmIChsZWZ0IDw9IDApIHsgYnJlYWs7IH1cbiAgICAgICAgY3VycisrO1xuICAgICAgICBsZWZ0IDw8PSAxO1xuICAgICAgfVxuXG4gICAgICAvKiBjaGVjayBmb3IgZW5vdWdoIHNwYWNlICovXG4gICAgICB1c2VkICs9IDEgPDwgY3VycjtcbiAgICAgIGlmICgodHlwZSA9PT0gTEVOUyAmJiB1c2VkID4gRU5PVUdIX0xFTlMpIHx8XG4gICAgICAgICh0eXBlID09PSBESVNUUyAmJiB1c2VkID4gRU5PVUdIX0RJU1RTKSkge1xuICAgICAgICByZXR1cm4gMTtcbiAgICAgIH1cblxuICAgICAgLyogcG9pbnQgZW50cnkgaW4gcm9vdCB0YWJsZSB0byBzdWItdGFibGUgKi9cbiAgICAgIGxvdyA9IGh1ZmYgJiBtYXNrO1xuICAgICAgLyp0YWJsZS5vcFtsb3ddID0gY3VycjtcbiAgICAgIHRhYmxlLmJpdHNbbG93XSA9IHJvb3Q7XG4gICAgICB0YWJsZS52YWxbbG93XSA9IG5leHQgLSBvcHRzLnRhYmxlX2luZGV4OyovXG4gICAgICB0YWJsZVtsb3ddID0gKHJvb3QgPDwgMjQpIHwgKGN1cnIgPDwgMTYpIHwgKG5leHQgLSB0YWJsZV9pbmRleCkgfDA7XG4gICAgfVxuICB9XG5cbiAgLyogZmlsbCBpbiByZW1haW5pbmcgdGFibGUgZW50cnkgaWYgY29kZSBpcyBpbmNvbXBsZXRlIChndWFyYW50ZWVkIHRvIGhhdmVcbiAgIGF0IG1vc3Qgb25lIHJlbWFpbmluZyBlbnRyeSwgc2luY2UgaWYgdGhlIGNvZGUgaXMgaW5jb21wbGV0ZSwgdGhlXG4gICBtYXhpbXVtIGNvZGUgbGVuZ3RoIHRoYXQgd2FzIGFsbG93ZWQgdG8gZ2V0IHRoaXMgZmFyIGlzIG9uZSBiaXQpICovXG4gIGlmIChodWZmICE9PSAwKSB7XG4gICAgLy90YWJsZS5vcFtuZXh0ICsgaHVmZl0gPSA2NDsgICAgICAgICAgICAvKiBpbnZhbGlkIGNvZGUgbWFya2VyICovXG4gICAgLy90YWJsZS5iaXRzW25leHQgKyBodWZmXSA9IGxlbiAtIGRyb3A7XG4gICAgLy90YWJsZS52YWxbbmV4dCArIGh1ZmZdID0gMDtcbiAgICB0YWJsZVtuZXh0ICsgaHVmZl0gPSAoKGxlbiAtIGRyb3ApIDw8IDI0KSB8ICg2NCA8PCAxNikgfDA7XG4gIH1cblxuICAvKiBzZXQgcmV0dXJuIHBhcmFtZXRlcnMgKi9cbiAgLy9vcHRzLnRhYmxlX2luZGV4ICs9IHVzZWQ7XG4gIG9wdHMuYml0cyA9IHJvb3Q7XG4gIHJldHVybiAwO1xufTtcbiIsIid1c2Ugc3RyaWN0JztcblxubW9kdWxlLmV4cG9ydHMgPSB7XG4gICcyJzogICAgJ25lZWQgZGljdGlvbmFyeScsICAgICAvKiBaX05FRURfRElDVCAgICAgICAyICAqL1xuICAnMSc6ICAgICdzdHJlYW0gZW5kJywgICAgICAgICAgLyogWl9TVFJFQU1fRU5EICAgICAgMSAgKi9cbiAgJzAnOiAgICAnJywgICAgICAgICAgICAgICAgICAgIC8qIFpfT0sgICAgICAgICAgICAgIDAgICovXG4gICctMSc6ICAgJ2ZpbGUgZXJyb3InLCAgICAgICAgICAvKiBaX0VSUk5PICAgICAgICAgKC0xKSAqL1xuICAnLTInOiAgICdzdHJlYW0gZXJyb3InLCAgICAgICAgLyogWl9TVFJFQU1fRVJST1IgICgtMikgKi9cbiAgJy0zJzogICAnZGF0YSBlcnJvcicsICAgICAgICAgIC8qIFpfREFUQV9FUlJPUiAgICAoLTMpICovXG4gICctNCc6ICAgJ2luc3VmZmljaWVudCBtZW1vcnknLCAvKiBaX01FTV9FUlJPUiAgICAgKC00KSAqL1xuICAnLTUnOiAgICdidWZmZXIgZXJyb3InLCAgICAgICAgLyogWl9CVUZfRVJST1IgICAgICgtNSkgKi9cbiAgJy02JzogICAnaW5jb21wYXRpYmxlIHZlcnNpb24nIC8qIFpfVkVSU0lPTl9FUlJPUiAoLTYpICovXG59OyIsIid1c2Ugc3RyaWN0JztcblxuXG52YXIgdXRpbHMgPSByZXF1aXJlKCcuLi91dGlscy9jb21tb24nKTtcblxuLyogUHVibGljIGNvbnN0YW50cyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09Ki9cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG5cblxuLy92YXIgWl9GSUxURVJFRCAgICAgICAgICA9IDE7XG4vL3ZhciBaX0hVRkZNQU5fT05MWSAgICAgID0gMjtcbi8vdmFyIFpfUkxFICAgICAgICAgICAgICAgPSAzO1xudmFyIFpfRklYRUQgICAgICAgICAgICAgICA9IDQ7XG4vL3ZhciBaX0RFRkFVTFRfU1RSQVRFR1kgID0gMDtcblxuLyogUG9zc2libGUgdmFsdWVzIG9mIHRoZSBkYXRhX3R5cGUgZmllbGQgKHRob3VnaCBzZWUgaW5mbGF0ZSgpKSAqL1xudmFyIFpfQklOQVJZICAgICAgICAgICAgICA9IDA7XG52YXIgWl9URVhUICAgICAgICAgICAgICAgID0gMTtcbi8vdmFyIFpfQVNDSUkgICAgICAgICAgICAgPSAxOyAvLyA9IFpfVEVYVFxudmFyIFpfVU5LTk9XTiAgICAgICAgICAgICA9IDI7XG5cbi8qPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG5cblxuZnVuY3Rpb24gemVybyhidWYpIHsgdmFyIGxlbiA9IGJ1Zi5sZW5ndGg7IHdoaWxlICgtLWxlbiA+PSAwKSB7IGJ1ZltsZW5dID0gMDsgfSB9XG5cbi8vIEZyb20genV0aWwuaFxuXG52YXIgU1RPUkVEX0JMT0NLID0gMDtcbnZhciBTVEFUSUNfVFJFRVMgPSAxO1xudmFyIERZTl9UUkVFUyAgICA9IDI7XG4vKiBUaGUgdGhyZWUga2luZHMgb2YgYmxvY2sgdHlwZSAqL1xuXG52YXIgTUlOX01BVENIICAgID0gMztcbnZhciBNQVhfTUFUQ0ggICAgPSAyNTg7XG4vKiBUaGUgbWluaW11bSBhbmQgbWF4aW11bSBtYXRjaCBsZW5ndGhzICovXG5cbi8vIEZyb20gZGVmbGF0ZS5oXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEludGVybmFsIGNvbXByZXNzaW9uIHN0YXRlLlxuICovXG5cbnZhciBMRU5HVEhfQ09ERVMgID0gMjk7XG4vKiBudW1iZXIgb2YgbGVuZ3RoIGNvZGVzLCBub3QgY291bnRpbmcgdGhlIHNwZWNpYWwgRU5EX0JMT0NLIGNvZGUgKi9cblxudmFyIExJVEVSQUxTICAgICAgPSAyNTY7XG4vKiBudW1iZXIgb2YgbGl0ZXJhbCBieXRlcyAwLi4yNTUgKi9cblxudmFyIExfQ09ERVMgICAgICAgPSBMSVRFUkFMUyArIDEgKyBMRU5HVEhfQ09ERVM7XG4vKiBudW1iZXIgb2YgTGl0ZXJhbCBvciBMZW5ndGggY29kZXMsIGluY2x1ZGluZyB0aGUgRU5EX0JMT0NLIGNvZGUgKi9cblxudmFyIERfQ09ERVMgICAgICAgPSAzMDtcbi8qIG51bWJlciBvZiBkaXN0YW5jZSBjb2RlcyAqL1xuXG52YXIgQkxfQ09ERVMgICAgICA9IDE5O1xuLyogbnVtYmVyIG9mIGNvZGVzIHVzZWQgdG8gdHJhbnNmZXIgdGhlIGJpdCBsZW5ndGhzICovXG5cbnZhciBIRUFQX1NJWkUgICAgID0gMipMX0NPREVTICsgMTtcbi8qIG1heGltdW0gaGVhcCBzaXplICovXG5cbnZhciBNQVhfQklUUyAgICAgID0gMTU7XG4vKiBBbGwgY29kZXMgbXVzdCBub3QgZXhjZWVkIE1BWF9CSVRTIGJpdHMgKi9cblxudmFyIEJ1Zl9zaXplICAgICAgPSAxNjtcbi8qIHNpemUgb2YgYml0IGJ1ZmZlciBpbiBiaV9idWYgKi9cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvbnN0YW50c1xuICovXG5cbnZhciBNQVhfQkxfQklUUyA9IDc7XG4vKiBCaXQgbGVuZ3RoIGNvZGVzIG11c3Qgbm90IGV4Y2VlZCBNQVhfQkxfQklUUyBiaXRzICovXG5cbnZhciBFTkRfQkxPQ0sgICA9IDI1Njtcbi8qIGVuZCBvZiBibG9jayBsaXRlcmFsIGNvZGUgKi9cblxudmFyIFJFUF8zXzYgICAgID0gMTY7XG4vKiByZXBlYXQgcHJldmlvdXMgYml0IGxlbmd0aCAzLTYgdGltZXMgKDIgYml0cyBvZiByZXBlYXQgY291bnQpICovXG5cbnZhciBSRVBaXzNfMTAgICA9IDE3O1xuLyogcmVwZWF0IGEgemVybyBsZW5ndGggMy0xMCB0aW1lcyAgKDMgYml0cyBvZiByZXBlYXQgY291bnQpICovXG5cbnZhciBSRVBaXzExXzEzOCA9IDE4O1xuLyogcmVwZWF0IGEgemVybyBsZW5ndGggMTEtMTM4IHRpbWVzICAoNyBiaXRzIG9mIHJlcGVhdCBjb3VudCkgKi9cblxudmFyIGV4dHJhX2xiaXRzID0gICAvKiBleHRyYSBiaXRzIGZvciBlYWNoIGxlbmd0aCBjb2RlICovXG4gIFswLDAsMCwwLDAsMCwwLDAsMSwxLDEsMSwyLDIsMiwyLDMsMywzLDMsNCw0LDQsNCw1LDUsNSw1LDBdO1xuXG52YXIgZXh0cmFfZGJpdHMgPSAgIC8qIGV4dHJhIGJpdHMgZm9yIGVhY2ggZGlzdGFuY2UgY29kZSAqL1xuICBbMCwwLDAsMCwxLDEsMiwyLDMsMyw0LDQsNSw1LDYsNiw3LDcsOCw4LDksOSwxMCwxMCwxMSwxMSwxMiwxMiwxMywxM107XG5cbnZhciBleHRyYV9ibGJpdHMgPSAgLyogZXh0cmEgYml0cyBmb3IgZWFjaCBiaXQgbGVuZ3RoIGNvZGUgKi9cbiAgWzAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMCwwLDAsMiwzLDddO1xuXG52YXIgYmxfb3JkZXIgPVxuICBbMTYsMTcsMTgsMCw4LDcsOSw2LDEwLDUsMTEsNCwxMiwzLDEzLDIsMTQsMSwxNV07XG4vKiBUaGUgbGVuZ3RocyBvZiB0aGUgYml0IGxlbmd0aCBjb2RlcyBhcmUgc2VudCBpbiBvcmRlciBvZiBkZWNyZWFzaW5nXG4gKiBwcm9iYWJpbGl0eSwgdG8gYXZvaWQgdHJhbnNtaXR0aW5nIHRoZSBsZW5ndGhzIGZvciB1bnVzZWQgYml0IGxlbmd0aCBjb2Rlcy5cbiAqL1xuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIExvY2FsIGRhdGEuIFRoZXNlIGFyZSBpbml0aWFsaXplZCBvbmx5IG9uY2UuXG4gKi9cblxuLy8gV2UgcHJlLWZpbGwgYXJyYXlzIHdpdGggMCB0byBhdm9pZCB1bmluaXRpYWxpemVkIGdhcHNcblxudmFyIERJU1RfQ09ERV9MRU4gPSA1MTI7IC8qIHNlZSBkZWZpbml0aW9uIG9mIGFycmF5IGRpc3RfY29kZSBiZWxvdyAqL1xuXG4vLyAhISEhIFVzZSBmbGF0IGFycmF5IGluc2RlYWQgb2Ygc3RydWN0dXJlLCBGcmVxID0gaSoyLCBMZW4gPSBpKjIrMVxudmFyIHN0YXRpY19sdHJlZSAgPSBuZXcgQXJyYXkoKExfQ09ERVMrMikgKiAyKTtcbnplcm8oc3RhdGljX2x0cmVlKTtcbi8qIFRoZSBzdGF0aWMgbGl0ZXJhbCB0cmVlLiBTaW5jZSB0aGUgYml0IGxlbmd0aHMgYXJlIGltcG9zZWQsIHRoZXJlIGlzIG5vXG4gKiBuZWVkIGZvciB0aGUgTF9DT0RFUyBleHRyYSBjb2RlcyB1c2VkIGR1cmluZyBoZWFwIGNvbnN0cnVjdGlvbi4gSG93ZXZlclxuICogVGhlIGNvZGVzIDI4NiBhbmQgMjg3IGFyZSBuZWVkZWQgdG8gYnVpbGQgYSBjYW5vbmljYWwgdHJlZSAoc2VlIF90cl9pbml0XG4gKiBiZWxvdykuXG4gKi9cblxudmFyIHN0YXRpY19kdHJlZSAgPSBuZXcgQXJyYXkoRF9DT0RFUyAqIDIpO1xuemVybyhzdGF0aWNfZHRyZWUpO1xuLyogVGhlIHN0YXRpYyBkaXN0YW5jZSB0cmVlLiAoQWN0dWFsbHkgYSB0cml2aWFsIHRyZWUgc2luY2UgYWxsIGNvZGVzIHVzZVxuICogNSBiaXRzLilcbiAqL1xuXG52YXIgX2Rpc3RfY29kZSAgICA9IG5ldyBBcnJheShESVNUX0NPREVfTEVOKTtcbnplcm8oX2Rpc3RfY29kZSk7XG4vKiBEaXN0YW5jZSBjb2Rlcy4gVGhlIGZpcnN0IDI1NiB2YWx1ZXMgY29ycmVzcG9uZCB0byB0aGUgZGlzdGFuY2VzXG4gKiAzIC4uIDI1OCwgdGhlIGxhc3QgMjU2IHZhbHVlcyBjb3JyZXNwb25kIHRvIHRoZSB0b3AgOCBiaXRzIG9mXG4gKiB0aGUgMTUgYml0IGRpc3RhbmNlcy5cbiAqL1xuXG52YXIgX2xlbmd0aF9jb2RlICA9IG5ldyBBcnJheShNQVhfTUFUQ0gtTUlOX01BVENIKzEpO1xuemVybyhfbGVuZ3RoX2NvZGUpO1xuLyogbGVuZ3RoIGNvZGUgZm9yIGVhY2ggbm9ybWFsaXplZCBtYXRjaCBsZW5ndGggKDAgPT0gTUlOX01BVENIKSAqL1xuXG52YXIgYmFzZV9sZW5ndGggICA9IG5ldyBBcnJheShMRU5HVEhfQ09ERVMpO1xuemVybyhiYXNlX2xlbmd0aCk7XG4vKiBGaXJzdCBub3JtYWxpemVkIGxlbmd0aCBmb3IgZWFjaCBjb2RlICgwID0gTUlOX01BVENIKSAqL1xuXG52YXIgYmFzZV9kaXN0ICAgICA9IG5ldyBBcnJheShEX0NPREVTKTtcbnplcm8oYmFzZV9kaXN0KTtcbi8qIEZpcnN0IG5vcm1hbGl6ZWQgZGlzdGFuY2UgZm9yIGVhY2ggY29kZSAoMCA9IGRpc3RhbmNlIG9mIDEpICovXG5cblxudmFyIFN0YXRpY1RyZWVEZXNjID0gZnVuY3Rpb24gKHN0YXRpY190cmVlLCBleHRyYV9iaXRzLCBleHRyYV9iYXNlLCBlbGVtcywgbWF4X2xlbmd0aCkge1xuXG4gIHRoaXMuc3RhdGljX3RyZWUgID0gc3RhdGljX3RyZWU7ICAvKiBzdGF0aWMgdHJlZSBvciBOVUxMICovXG4gIHRoaXMuZXh0cmFfYml0cyAgID0gZXh0cmFfYml0czsgICAvKiBleHRyYSBiaXRzIGZvciBlYWNoIGNvZGUgb3IgTlVMTCAqL1xuICB0aGlzLmV4dHJhX2Jhc2UgICA9IGV4dHJhX2Jhc2U7ICAgLyogYmFzZSBpbmRleCBmb3IgZXh0cmFfYml0cyAqL1xuICB0aGlzLmVsZW1zICAgICAgICA9IGVsZW1zOyAgICAgICAgLyogbWF4IG51bWJlciBvZiBlbGVtZW50cyBpbiB0aGUgdHJlZSAqL1xuICB0aGlzLm1heF9sZW5ndGggICA9IG1heF9sZW5ndGg7ICAgLyogbWF4IGJpdCBsZW5ndGggZm9yIHRoZSBjb2RlcyAqL1xuXG4gIC8vIHNob3cgaWYgYHN0YXRpY190cmVlYCBoYXMgZGF0YSBvciBkdW1teSAtIG5lZWRlZCBmb3IgbW9ub21vcnBoaWMgb2JqZWN0c1xuICB0aGlzLmhhc19zdHJlZSAgICA9IHN0YXRpY190cmVlICYmIHN0YXRpY190cmVlLmxlbmd0aDtcbn07XG5cblxudmFyIHN0YXRpY19sX2Rlc2M7XG52YXIgc3RhdGljX2RfZGVzYztcbnZhciBzdGF0aWNfYmxfZGVzYztcblxuXG52YXIgVHJlZURlc2MgPSBmdW5jdGlvbihkeW5fdHJlZSwgc3RhdF9kZXNjKSB7XG4gIHRoaXMuZHluX3RyZWUgPSBkeW5fdHJlZTsgICAgIC8qIHRoZSBkeW5hbWljIHRyZWUgKi9cbiAgdGhpcy5tYXhfY29kZSA9IDA7ICAgICAgICAgICAgLyogbGFyZ2VzdCBjb2RlIHdpdGggbm9uIHplcm8gZnJlcXVlbmN5ICovXG4gIHRoaXMuc3RhdF9kZXNjID0gc3RhdF9kZXNjOyAgIC8qIHRoZSBjb3JyZXNwb25kaW5nIHN0YXRpYyB0cmVlICovXG59O1xuXG5cblxuZnVuY3Rpb24gZF9jb2RlKGRpc3QpIHtcbiAgcmV0dXJuIGRpc3QgPCAyNTYgPyBfZGlzdF9jb2RlW2Rpc3RdIDogX2Rpc3RfY29kZVsyNTYgKyAoZGlzdCA+Pj4gNyldO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogT3V0cHV0IGEgc2hvcnQgTFNCIGZpcnN0IG9uIHRoZSBzdHJlYW0uXG4gKiBJTiBhc3NlcnRpb246IHRoZXJlIGlzIGVub3VnaCByb29tIGluIHBlbmRpbmdCdWYuXG4gKi9cbmZ1bmN0aW9uIHB1dF9zaG9ydCAocywgdykge1xuLy8gICAgcHV0X2J5dGUocywgKHVjaCkoKHcpICYgMHhmZikpO1xuLy8gICAgcHV0X2J5dGUocywgKHVjaCkoKHVzaCkodykgPj4gOCkpO1xuICBzLnBlbmRpbmdfYnVmW3MucGVuZGluZysrXSA9ICh3KSAmIDB4ZmY7XG4gIHMucGVuZGluZ19idWZbcy5wZW5kaW5nKytdID0gKHcgPj4+IDgpICYgMHhmZjtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFNlbmQgYSB2YWx1ZSBvbiBhIGdpdmVuIG51bWJlciBvZiBiaXRzLlxuICogSU4gYXNzZXJ0aW9uOiBsZW5ndGggPD0gMTYgYW5kIHZhbHVlIGZpdHMgaW4gbGVuZ3RoIGJpdHMuXG4gKi9cbmZ1bmN0aW9uIHNlbmRfYml0cyhzLCB2YWx1ZSwgbGVuZ3RoKSB7XG4gIGlmIChzLmJpX3ZhbGlkID4gKEJ1Zl9zaXplIC0gbGVuZ3RoKSkge1xuICAgIHMuYmlfYnVmIHw9ICh2YWx1ZSA8PCBzLmJpX3ZhbGlkKSAmIDB4ZmZmZjtcbiAgICBwdXRfc2hvcnQocywgcy5iaV9idWYpO1xuICAgIHMuYmlfYnVmID0gdmFsdWUgPj4gKEJ1Zl9zaXplIC0gcy5iaV92YWxpZCk7XG4gICAgcy5iaV92YWxpZCArPSBsZW5ndGggLSBCdWZfc2l6ZTtcbiAgfSBlbHNlIHtcbiAgICBzLmJpX2J1ZiB8PSAodmFsdWUgPDwgcy5iaV92YWxpZCkgJiAweGZmZmY7XG4gICAgcy5iaV92YWxpZCArPSBsZW5ndGg7XG4gIH1cbn1cblxuXG5mdW5jdGlvbiBzZW5kX2NvZGUocywgYywgdHJlZSkge1xuICBzZW5kX2JpdHMocywgdHJlZVtjKjJdLyouQ29kZSovLCB0cmVlW2MqMiArIDFdLyouTGVuKi8pO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogUmV2ZXJzZSB0aGUgZmlyc3QgbGVuIGJpdHMgb2YgYSBjb2RlLCB1c2luZyBzdHJhaWdodGZvcndhcmQgY29kZSAoYSBmYXN0ZXJcbiAqIG1ldGhvZCB3b3VsZCB1c2UgYSB0YWJsZSlcbiAqIElOIGFzc2VydGlvbjogMSA8PSBsZW4gPD0gMTVcbiAqL1xuZnVuY3Rpb24gYmlfcmV2ZXJzZShjb2RlLCBsZW4pIHtcbiAgdmFyIHJlcyA9IDA7XG4gIGRvIHtcbiAgICByZXMgfD0gY29kZSAmIDE7XG4gICAgY29kZSA+Pj49IDE7XG4gICAgcmVzIDw8PSAxO1xuICB9IHdoaWxlICgtLWxlbiA+IDApO1xuICByZXR1cm4gcmVzID4+PiAxO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogRmx1c2ggdGhlIGJpdCBidWZmZXIsIGtlZXBpbmcgYXQgbW9zdCA3IGJpdHMgaW4gaXQuXG4gKi9cbmZ1bmN0aW9uIGJpX2ZsdXNoKHMpIHtcbiAgaWYgKHMuYmlfdmFsaWQgPT09IDE2KSB7XG4gICAgcHV0X3Nob3J0KHMsIHMuYmlfYnVmKTtcbiAgICBzLmJpX2J1ZiA9IDA7XG4gICAgcy5iaV92YWxpZCA9IDA7XG5cbiAgfSBlbHNlIGlmIChzLmJpX3ZhbGlkID49IDgpIHtcbiAgICBzLnBlbmRpbmdfYnVmW3MucGVuZGluZysrXSA9IHMuYmlfYnVmICYgMHhmZjtcbiAgICBzLmJpX2J1ZiA+Pj0gODtcbiAgICBzLmJpX3ZhbGlkIC09IDg7XG4gIH1cbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvbXB1dGUgdGhlIG9wdGltYWwgYml0IGxlbmd0aHMgZm9yIGEgdHJlZSBhbmQgdXBkYXRlIHRoZSB0b3RhbCBiaXQgbGVuZ3RoXG4gKiBmb3IgdGhlIGN1cnJlbnQgYmxvY2suXG4gKiBJTiBhc3NlcnRpb246IHRoZSBmaWVsZHMgZnJlcSBhbmQgZGFkIGFyZSBzZXQsIGhlYXBbaGVhcF9tYXhdIGFuZFxuICogICAgYWJvdmUgYXJlIHRoZSB0cmVlIG5vZGVzIHNvcnRlZCBieSBpbmNyZWFzaW5nIGZyZXF1ZW5jeS5cbiAqIE9VVCBhc3NlcnRpb25zOiB0aGUgZmllbGQgbGVuIGlzIHNldCB0byB0aGUgb3B0aW1hbCBiaXQgbGVuZ3RoLCB0aGVcbiAqICAgICBhcnJheSBibF9jb3VudCBjb250YWlucyB0aGUgZnJlcXVlbmNpZXMgZm9yIGVhY2ggYml0IGxlbmd0aC5cbiAqICAgICBUaGUgbGVuZ3RoIG9wdF9sZW4gaXMgdXBkYXRlZDsgc3RhdGljX2xlbiBpcyBhbHNvIHVwZGF0ZWQgaWYgc3RyZWUgaXNcbiAqICAgICBub3QgbnVsbC5cbiAqL1xuZnVuY3Rpb24gZ2VuX2JpdGxlbihzLCBkZXNjKVxuLy8gICAgZGVmbGF0ZV9zdGF0ZSAqcztcbi8vICAgIHRyZWVfZGVzYyAqZGVzYzsgICAgLyogdGhlIHRyZWUgZGVzY3JpcHRvciAqL1xue1xuICB2YXIgdHJlZSAgICAgICAgICAgID0gZGVzYy5keW5fdHJlZTtcbiAgdmFyIG1heF9jb2RlICAgICAgICA9IGRlc2MubWF4X2NvZGU7XG4gIHZhciBzdHJlZSAgICAgICAgICAgPSBkZXNjLnN0YXRfZGVzYy5zdGF0aWNfdHJlZTtcbiAgdmFyIGhhc19zdHJlZSAgICAgICA9IGRlc2Muc3RhdF9kZXNjLmhhc19zdHJlZTtcbiAgdmFyIGV4dHJhICAgICAgICAgICA9IGRlc2Muc3RhdF9kZXNjLmV4dHJhX2JpdHM7XG4gIHZhciBiYXNlICAgICAgICAgICAgPSBkZXNjLnN0YXRfZGVzYy5leHRyYV9iYXNlO1xuICB2YXIgbWF4X2xlbmd0aCAgICAgID0gZGVzYy5zdGF0X2Rlc2MubWF4X2xlbmd0aDtcbiAgdmFyIGg7ICAgICAgICAgICAgICAvKiBoZWFwIGluZGV4ICovXG4gIHZhciBuLCBtOyAgICAgICAgICAgLyogaXRlcmF0ZSBvdmVyIHRoZSB0cmVlIGVsZW1lbnRzICovXG4gIHZhciBiaXRzOyAgICAgICAgICAgLyogYml0IGxlbmd0aCAqL1xuICB2YXIgeGJpdHM7ICAgICAgICAgIC8qIGV4dHJhIGJpdHMgKi9cbiAgdmFyIGY7ICAgICAgICAgICAgICAvKiBmcmVxdWVuY3kgKi9cbiAgdmFyIG92ZXJmbG93ID0gMDsgICAvKiBudW1iZXIgb2YgZWxlbWVudHMgd2l0aCBiaXQgbGVuZ3RoIHRvbyBsYXJnZSAqL1xuXG4gIGZvciAoYml0cyA9IDA7IGJpdHMgPD0gTUFYX0JJVFM7IGJpdHMrKykge1xuICAgIHMuYmxfY291bnRbYml0c10gPSAwO1xuICB9XG5cbiAgLyogSW4gYSBmaXJzdCBwYXNzLCBjb21wdXRlIHRoZSBvcHRpbWFsIGJpdCBsZW5ndGhzICh3aGljaCBtYXlcbiAgICogb3ZlcmZsb3cgaW4gdGhlIGNhc2Ugb2YgdGhlIGJpdCBsZW5ndGggdHJlZSkuXG4gICAqL1xuICB0cmVlW3MuaGVhcFtzLmhlYXBfbWF4XSoyICsgMV0vKi5MZW4qLyA9IDA7IC8qIHJvb3Qgb2YgdGhlIGhlYXAgKi9cblxuICBmb3IgKGggPSBzLmhlYXBfbWF4KzE7IGggPCBIRUFQX1NJWkU7IGgrKykge1xuICAgIG4gPSBzLmhlYXBbaF07XG4gICAgYml0cyA9IHRyZWVbdHJlZVtuKjIgKzFdLyouRGFkKi8gKiAyICsgMV0vKi5MZW4qLyArIDE7XG4gICAgaWYgKGJpdHMgPiBtYXhfbGVuZ3RoKSB7XG4gICAgICBiaXRzID0gbWF4X2xlbmd0aDtcbiAgICAgIG92ZXJmbG93Kys7XG4gICAgfVxuICAgIHRyZWVbbioyICsgMV0vKi5MZW4qLyA9IGJpdHM7XG4gICAgLyogV2Ugb3ZlcndyaXRlIHRyZWVbbl0uRGFkIHdoaWNoIGlzIG5vIGxvbmdlciBuZWVkZWQgKi9cblxuICAgIGlmIChuID4gbWF4X2NvZGUpIHsgY29udGludWU7IH0gLyogbm90IGEgbGVhZiBub2RlICovXG5cbiAgICBzLmJsX2NvdW50W2JpdHNdKys7XG4gICAgeGJpdHMgPSAwO1xuICAgIGlmIChuID49IGJhc2UpIHtcbiAgICAgIHhiaXRzID0gZXh0cmFbbi1iYXNlXTtcbiAgICB9XG4gICAgZiA9IHRyZWVbbiAqIDJdLyouRnJlcSovO1xuICAgIHMub3B0X2xlbiArPSBmICogKGJpdHMgKyB4Yml0cyk7XG4gICAgaWYgKGhhc19zdHJlZSkge1xuICAgICAgcy5zdGF0aWNfbGVuICs9IGYgKiAoc3RyZWVbbioyICsgMV0vKi5MZW4qLyArIHhiaXRzKTtcbiAgICB9XG4gIH1cbiAgaWYgKG92ZXJmbG93ID09PSAwKSB7IHJldHVybjsgfVxuXG4gIC8vIFRyYWNlKChzdGRlcnIsXCJcXG5iaXQgbGVuZ3RoIG92ZXJmbG93XFxuXCIpKTtcbiAgLyogVGhpcyBoYXBwZW5zIGZvciBleGFtcGxlIG9uIG9iajIgYW5kIHBpYyBvZiB0aGUgQ2FsZ2FyeSBjb3JwdXMgKi9cblxuICAvKiBGaW5kIHRoZSBmaXJzdCBiaXQgbGVuZ3RoIHdoaWNoIGNvdWxkIGluY3JlYXNlOiAqL1xuICBkbyB7XG4gICAgYml0cyA9IG1heF9sZW5ndGgtMTtcbiAgICB3aGlsZSAocy5ibF9jb3VudFtiaXRzXSA9PT0gMCkgeyBiaXRzLS07IH1cbiAgICBzLmJsX2NvdW50W2JpdHNdLS07ICAgICAgLyogbW92ZSBvbmUgbGVhZiBkb3duIHRoZSB0cmVlICovXG4gICAgcy5ibF9jb3VudFtiaXRzKzFdICs9IDI7IC8qIG1vdmUgb25lIG92ZXJmbG93IGl0ZW0gYXMgaXRzIGJyb3RoZXIgKi9cbiAgICBzLmJsX2NvdW50W21heF9sZW5ndGhdLS07XG4gICAgLyogVGhlIGJyb3RoZXIgb2YgdGhlIG92ZXJmbG93IGl0ZW0gYWxzbyBtb3ZlcyBvbmUgc3RlcCB1cCxcbiAgICAgKiBidXQgdGhpcyBkb2VzIG5vdCBhZmZlY3QgYmxfY291bnRbbWF4X2xlbmd0aF1cbiAgICAgKi9cbiAgICBvdmVyZmxvdyAtPSAyO1xuICB9IHdoaWxlIChvdmVyZmxvdyA+IDApO1xuXG4gIC8qIE5vdyByZWNvbXB1dGUgYWxsIGJpdCBsZW5ndGhzLCBzY2FubmluZyBpbiBpbmNyZWFzaW5nIGZyZXF1ZW5jeS5cbiAgICogaCBpcyBzdGlsbCBlcXVhbCB0byBIRUFQX1NJWkUuIChJdCBpcyBzaW1wbGVyIHRvIHJlY29uc3RydWN0IGFsbFxuICAgKiBsZW5ndGhzIGluc3RlYWQgb2YgZml4aW5nIG9ubHkgdGhlIHdyb25nIG9uZXMuIFRoaXMgaWRlYSBpcyB0YWtlblxuICAgKiBmcm9tICdhcicgd3JpdHRlbiBieSBIYXJ1aGlrbyBPa3VtdXJhLilcbiAgICovXG4gIGZvciAoYml0cyA9IG1heF9sZW5ndGg7IGJpdHMgIT09IDA7IGJpdHMtLSkge1xuICAgIG4gPSBzLmJsX2NvdW50W2JpdHNdO1xuICAgIHdoaWxlIChuICE9PSAwKSB7XG4gICAgICBtID0gcy5oZWFwWy0taF07XG4gICAgICBpZiAobSA+IG1heF9jb2RlKSB7IGNvbnRpbnVlOyB9XG4gICAgICBpZiAodHJlZVttKjIgKyAxXS8qLkxlbiovICE9PSBiaXRzKSB7XG4gICAgICAgIC8vIFRyYWNlKChzdGRlcnIsXCJjb2RlICVkIGJpdHMgJWQtPiVkXFxuXCIsIG0sIHRyZWVbbV0uTGVuLCBiaXRzKSk7XG4gICAgICAgIHMub3B0X2xlbiArPSAoYml0cyAtIHRyZWVbbSoyICsgMV0vKi5MZW4qLykqdHJlZVttKjJdLyouRnJlcSovO1xuICAgICAgICB0cmVlW20qMiArIDFdLyouTGVuKi8gPSBiaXRzO1xuICAgICAgfVxuICAgICAgbi0tO1xuICAgIH1cbiAgfVxufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogR2VuZXJhdGUgdGhlIGNvZGVzIGZvciBhIGdpdmVuIHRyZWUgYW5kIGJpdCBjb3VudHMgKHdoaWNoIG5lZWQgbm90IGJlXG4gKiBvcHRpbWFsKS5cbiAqIElOIGFzc2VydGlvbjogdGhlIGFycmF5IGJsX2NvdW50IGNvbnRhaW5zIHRoZSBiaXQgbGVuZ3RoIHN0YXRpc3RpY3MgZm9yXG4gKiB0aGUgZ2l2ZW4gdHJlZSBhbmQgdGhlIGZpZWxkIGxlbiBpcyBzZXQgZm9yIGFsbCB0cmVlIGVsZW1lbnRzLlxuICogT1VUIGFzc2VydGlvbjogdGhlIGZpZWxkIGNvZGUgaXMgc2V0IGZvciBhbGwgdHJlZSBlbGVtZW50cyBvZiBub25cbiAqICAgICB6ZXJvIGNvZGUgbGVuZ3RoLlxuICovXG5mdW5jdGlvbiBnZW5fY29kZXModHJlZSwgbWF4X2NvZGUsIGJsX2NvdW50KVxuLy8gICAgY3RfZGF0YSAqdHJlZTsgICAgICAgICAgICAgLyogdGhlIHRyZWUgdG8gZGVjb3JhdGUgKi9cbi8vICAgIGludCBtYXhfY29kZTsgICAgICAgICAgICAgIC8qIGxhcmdlc3QgY29kZSB3aXRoIG5vbiB6ZXJvIGZyZXF1ZW5jeSAqL1xuLy8gICAgdXNoZiAqYmxfY291bnQ7ICAgICAgICAgICAgLyogbnVtYmVyIG9mIGNvZGVzIGF0IGVhY2ggYml0IGxlbmd0aCAqL1xue1xuICB2YXIgbmV4dF9jb2RlID0gbmV3IEFycmF5KE1BWF9CSVRTKzEpOyAvKiBuZXh0IGNvZGUgdmFsdWUgZm9yIGVhY2ggYml0IGxlbmd0aCAqL1xuICB2YXIgY29kZSA9IDA7ICAgICAgICAgICAgICAvKiBydW5uaW5nIGNvZGUgdmFsdWUgKi9cbiAgdmFyIGJpdHM7ICAgICAgICAgICAgICAgICAgLyogYml0IGluZGV4ICovXG4gIHZhciBuOyAgICAgICAgICAgICAgICAgICAgIC8qIGNvZGUgaW5kZXggKi9cblxuICAvKiBUaGUgZGlzdHJpYnV0aW9uIGNvdW50cyBhcmUgZmlyc3QgdXNlZCB0byBnZW5lcmF0ZSB0aGUgY29kZSB2YWx1ZXNcbiAgICogd2l0aG91dCBiaXQgcmV2ZXJzYWwuXG4gICAqL1xuICBmb3IgKGJpdHMgPSAxOyBiaXRzIDw9IE1BWF9CSVRTOyBiaXRzKyspIHtcbiAgICBuZXh0X2NvZGVbYml0c10gPSBjb2RlID0gKGNvZGUgKyBibF9jb3VudFtiaXRzLTFdKSA8PCAxO1xuICB9XG4gIC8qIENoZWNrIHRoYXQgdGhlIGJpdCBjb3VudHMgaW4gYmxfY291bnQgYXJlIGNvbnNpc3RlbnQuIFRoZSBsYXN0IGNvZGVcbiAgICogbXVzdCBiZSBhbGwgb25lcy5cbiAgICovXG4gIC8vQXNzZXJ0IChjb2RlICsgYmxfY291bnRbTUFYX0JJVFNdLTEgPT0gKDE8PE1BWF9CSVRTKS0xLFxuICAvLyAgICAgICAgXCJpbmNvbnNpc3RlbnQgYml0IGNvdW50c1wiKTtcbiAgLy9UcmFjZXYoKHN0ZGVycixcIlxcbmdlbl9jb2RlczogbWF4X2NvZGUgJWQgXCIsIG1heF9jb2RlKSk7XG5cbiAgZm9yIChuID0gMDsgIG4gPD0gbWF4X2NvZGU7IG4rKykge1xuICAgIHZhciBsZW4gPSB0cmVlW24qMiArIDFdLyouTGVuKi87XG4gICAgaWYgKGxlbiA9PT0gMCkgeyBjb250aW51ZTsgfVxuICAgIC8qIE5vdyByZXZlcnNlIHRoZSBiaXRzICovXG4gICAgdHJlZVtuKjJdLyouQ29kZSovID0gYmlfcmV2ZXJzZShuZXh0X2NvZGVbbGVuXSsrLCBsZW4pO1xuXG4gICAgLy9UcmFjZWN2KHRyZWUgIT0gc3RhdGljX2x0cmVlLCAoc3RkZXJyLFwiXFxubiAlM2QgJWMgbCAlMmQgYyAlNHggKCV4KSBcIixcbiAgICAvLyAgICAgbiwgKGlzZ3JhcGgobikgPyBuIDogJyAnKSwgbGVuLCB0cmVlW25dLkNvZGUsIG5leHRfY29kZVtsZW5dLTEpKTtcbiAgfVxufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogSW5pdGlhbGl6ZSB0aGUgdmFyaW91cyAnY29uc3RhbnQnIHRhYmxlcy5cbiAqL1xuZnVuY3Rpb24gdHJfc3RhdGljX2luaXQoKSB7XG4gIHZhciBuOyAgICAgICAgLyogaXRlcmF0ZXMgb3ZlciB0cmVlIGVsZW1lbnRzICovXG4gIHZhciBiaXRzOyAgICAgLyogYml0IGNvdW50ZXIgKi9cbiAgdmFyIGxlbmd0aDsgICAvKiBsZW5ndGggdmFsdWUgKi9cbiAgdmFyIGNvZGU7ICAgICAvKiBjb2RlIHZhbHVlICovXG4gIHZhciBkaXN0OyAgICAgLyogZGlzdGFuY2UgaW5kZXggKi9cbiAgdmFyIGJsX2NvdW50ID0gbmV3IEFycmF5KE1BWF9CSVRTKzEpO1xuICAvKiBudW1iZXIgb2YgY29kZXMgYXQgZWFjaCBiaXQgbGVuZ3RoIGZvciBhbiBvcHRpbWFsIHRyZWUgKi9cblxuICAvLyBkbyBjaGVjayBpbiBfdHJfaW5pdCgpXG4gIC8vaWYgKHN0YXRpY19pbml0X2RvbmUpIHJldHVybjtcblxuICAvKiBGb3Igc29tZSBlbWJlZGRlZCB0YXJnZXRzLCBnbG9iYWwgdmFyaWFibGVzIGFyZSBub3QgaW5pdGlhbGl6ZWQ6ICovXG4vKiNpZmRlZiBOT19JTklUX0dMT0JBTF9QT0lOVEVSU1xuICBzdGF0aWNfbF9kZXNjLnN0YXRpY190cmVlID0gc3RhdGljX2x0cmVlO1xuICBzdGF0aWNfbF9kZXNjLmV4dHJhX2JpdHMgPSBleHRyYV9sYml0cztcbiAgc3RhdGljX2RfZGVzYy5zdGF0aWNfdHJlZSA9IHN0YXRpY19kdHJlZTtcbiAgc3RhdGljX2RfZGVzYy5leHRyYV9iaXRzID0gZXh0cmFfZGJpdHM7XG4gIHN0YXRpY19ibF9kZXNjLmV4dHJhX2JpdHMgPSBleHRyYV9ibGJpdHM7XG4jZW5kaWYqL1xuXG4gIC8qIEluaXRpYWxpemUgdGhlIG1hcHBpbmcgbGVuZ3RoICgwLi4yNTUpIC0+IGxlbmd0aCBjb2RlICgwLi4yOCkgKi9cbiAgbGVuZ3RoID0gMDtcbiAgZm9yIChjb2RlID0gMDsgY29kZSA8IExFTkdUSF9DT0RFUy0xOyBjb2RlKyspIHtcbiAgICBiYXNlX2xlbmd0aFtjb2RlXSA9IGxlbmd0aDtcbiAgICBmb3IgKG4gPSAwOyBuIDwgKDE8PGV4dHJhX2xiaXRzW2NvZGVdKTsgbisrKSB7XG4gICAgICBfbGVuZ3RoX2NvZGVbbGVuZ3RoKytdID0gY29kZTtcbiAgICB9XG4gIH1cbiAgLy9Bc3NlcnQgKGxlbmd0aCA9PSAyNTYsIFwidHJfc3RhdGljX2luaXQ6IGxlbmd0aCAhPSAyNTZcIik7XG4gIC8qIE5vdGUgdGhhdCB0aGUgbGVuZ3RoIDI1NSAobWF0Y2ggbGVuZ3RoIDI1OCkgY2FuIGJlIHJlcHJlc2VudGVkXG4gICAqIGluIHR3byBkaWZmZXJlbnQgd2F5czogY29kZSAyODQgKyA1IGJpdHMgb3IgY29kZSAyODUsIHNvIHdlXG4gICAqIG92ZXJ3cml0ZSBsZW5ndGhfY29kZVsyNTVdIHRvIHVzZSB0aGUgYmVzdCBlbmNvZGluZzpcbiAgICovXG4gIF9sZW5ndGhfY29kZVtsZW5ndGgtMV0gPSBjb2RlO1xuXG4gIC8qIEluaXRpYWxpemUgdGhlIG1hcHBpbmcgZGlzdCAoMC4uMzJLKSAtPiBkaXN0IGNvZGUgKDAuLjI5KSAqL1xuICBkaXN0ID0gMDtcbiAgZm9yIChjb2RlID0gMCA7IGNvZGUgPCAxNjsgY29kZSsrKSB7XG4gICAgYmFzZV9kaXN0W2NvZGVdID0gZGlzdDtcbiAgICBmb3IgKG4gPSAwOyBuIDwgKDE8PGV4dHJhX2RiaXRzW2NvZGVdKTsgbisrKSB7XG4gICAgICBfZGlzdF9jb2RlW2Rpc3QrK10gPSBjb2RlO1xuICAgIH1cbiAgfVxuICAvL0Fzc2VydCAoZGlzdCA9PSAyNTYsIFwidHJfc3RhdGljX2luaXQ6IGRpc3QgIT0gMjU2XCIpO1xuICBkaXN0ID4+PSA3OyAvKiBmcm9tIG5vdyBvbiwgYWxsIGRpc3RhbmNlcyBhcmUgZGl2aWRlZCBieSAxMjggKi9cbiAgZm9yICggOyBjb2RlIDwgRF9DT0RFUzsgY29kZSsrKSB7XG4gICAgYmFzZV9kaXN0W2NvZGVdID0gZGlzdCA8PCA3O1xuICAgIGZvciAobiA9IDA7IG4gPCAoMTw8KGV4dHJhX2RiaXRzW2NvZGVdLTcpKTsgbisrKSB7XG4gICAgICBfZGlzdF9jb2RlWzI1NiArIGRpc3QrK10gPSBjb2RlO1xuICAgIH1cbiAgfVxuICAvL0Fzc2VydCAoZGlzdCA9PSAyNTYsIFwidHJfc3RhdGljX2luaXQ6IDI1NitkaXN0ICE9IDUxMlwiKTtcblxuICAvKiBDb25zdHJ1Y3QgdGhlIGNvZGVzIG9mIHRoZSBzdGF0aWMgbGl0ZXJhbCB0cmVlICovXG4gIGZvciAoYml0cyA9IDA7IGJpdHMgPD0gTUFYX0JJVFM7IGJpdHMrKykge1xuICAgIGJsX2NvdW50W2JpdHNdID0gMDtcbiAgfVxuXG4gIG4gPSAwO1xuICB3aGlsZSAobiA8PSAxNDMpIHtcbiAgICBzdGF0aWNfbHRyZWVbbioyICsgMV0vKi5MZW4qLyA9IDg7XG4gICAgbisrO1xuICAgIGJsX2NvdW50WzhdKys7XG4gIH1cbiAgd2hpbGUgKG4gPD0gMjU1KSB7XG4gICAgc3RhdGljX2x0cmVlW24qMiArIDFdLyouTGVuKi8gPSA5O1xuICAgIG4rKztcbiAgICBibF9jb3VudFs5XSsrO1xuICB9XG4gIHdoaWxlIChuIDw9IDI3OSkge1xuICAgIHN0YXRpY19sdHJlZVtuKjIgKyAxXS8qLkxlbiovID0gNztcbiAgICBuKys7XG4gICAgYmxfY291bnRbN10rKztcbiAgfVxuICB3aGlsZSAobiA8PSAyODcpIHtcbiAgICBzdGF0aWNfbHRyZWVbbioyICsgMV0vKi5MZW4qLyA9IDg7XG4gICAgbisrO1xuICAgIGJsX2NvdW50WzhdKys7XG4gIH1cbiAgLyogQ29kZXMgMjg2IGFuZCAyODcgZG8gbm90IGV4aXN0LCBidXQgd2UgbXVzdCBpbmNsdWRlIHRoZW0gaW4gdGhlXG4gICAqIHRyZWUgY29uc3RydWN0aW9uIHRvIGdldCBhIGNhbm9uaWNhbCBIdWZmbWFuIHRyZWUgKGxvbmdlc3QgY29kZVxuICAgKiBhbGwgb25lcylcbiAgICovXG4gIGdlbl9jb2RlcyhzdGF0aWNfbHRyZWUsIExfQ09ERVMrMSwgYmxfY291bnQpO1xuXG4gIC8qIFRoZSBzdGF0aWMgZGlzdGFuY2UgdHJlZSBpcyB0cml2aWFsOiAqL1xuICBmb3IgKG4gPSAwOyBuIDwgRF9DT0RFUzsgbisrKSB7XG4gICAgc3RhdGljX2R0cmVlW24qMiArIDFdLyouTGVuKi8gPSA1O1xuICAgIHN0YXRpY19kdHJlZVtuKjJdLyouQ29kZSovID0gYmlfcmV2ZXJzZShuLCA1KTtcbiAgfVxuXG4gIC8vIE5vdyBkYXRhIHJlYWR5IGFuZCB3ZSBjYW4gaW5pdCBzdGF0aWMgdHJlZXNcbiAgc3RhdGljX2xfZGVzYyA9IG5ldyBTdGF0aWNUcmVlRGVzYyhzdGF0aWNfbHRyZWUsIGV4dHJhX2xiaXRzLCBMSVRFUkFMUysxLCBMX0NPREVTLCBNQVhfQklUUyk7XG4gIHN0YXRpY19kX2Rlc2MgPSBuZXcgU3RhdGljVHJlZURlc2Moc3RhdGljX2R0cmVlLCBleHRyYV9kYml0cywgMCwgICAgICAgICAgRF9DT0RFUywgTUFYX0JJVFMpO1xuICBzdGF0aWNfYmxfZGVzYyA9bmV3IFN0YXRpY1RyZWVEZXNjKG5ldyBBcnJheSgwKSwgZXh0cmFfYmxiaXRzLCAwLCAgICAgICAgIEJMX0NPREVTLCBNQVhfQkxfQklUUyk7XG5cbiAgLy9zdGF0aWNfaW5pdF9kb25lID0gdHJ1ZTtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEluaXRpYWxpemUgYSBuZXcgYmxvY2suXG4gKi9cbmZ1bmN0aW9uIGluaXRfYmxvY2socykge1xuICB2YXIgbjsgLyogaXRlcmF0ZXMgb3ZlciB0cmVlIGVsZW1lbnRzICovXG5cbiAgLyogSW5pdGlhbGl6ZSB0aGUgdHJlZXMuICovXG4gIGZvciAobiA9IDA7IG4gPCBMX0NPREVTOyAgbisrKSB7IHMuZHluX2x0cmVlW24qMl0vKi5GcmVxKi8gPSAwOyB9XG4gIGZvciAobiA9IDA7IG4gPCBEX0NPREVTOyAgbisrKSB7IHMuZHluX2R0cmVlW24qMl0vKi5GcmVxKi8gPSAwOyB9XG4gIGZvciAobiA9IDA7IG4gPCBCTF9DT0RFUzsgbisrKSB7IHMuYmxfdHJlZVtuKjJdLyouRnJlcSovID0gMDsgfVxuXG4gIHMuZHluX2x0cmVlW0VORF9CTE9DSyoyXS8qLkZyZXEqLyA9IDE7XG4gIHMub3B0X2xlbiA9IHMuc3RhdGljX2xlbiA9IDA7XG4gIHMubGFzdF9saXQgPSBzLm1hdGNoZXMgPSAwO1xufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogRmx1c2ggdGhlIGJpdCBidWZmZXIgYW5kIGFsaWduIHRoZSBvdXRwdXQgb24gYSBieXRlIGJvdW5kYXJ5XG4gKi9cbmZ1bmN0aW9uIGJpX3dpbmR1cChzKVxue1xuICBpZiAocy5iaV92YWxpZCA+IDgpIHtcbiAgICBwdXRfc2hvcnQocywgcy5iaV9idWYpO1xuICB9IGVsc2UgaWYgKHMuYmlfdmFsaWQgPiAwKSB7XG4gICAgLy9wdXRfYnl0ZShzLCAoQnl0ZSlzLT5iaV9idWYpO1xuICAgIHMucGVuZGluZ19idWZbcy5wZW5kaW5nKytdID0gcy5iaV9idWY7XG4gIH1cbiAgcy5iaV9idWYgPSAwO1xuICBzLmJpX3ZhbGlkID0gMDtcbn1cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb3B5IGEgc3RvcmVkIGJsb2NrLCBzdG9yaW5nIGZpcnN0IHRoZSBsZW5ndGggYW5kIGl0c1xuICogb25lJ3MgY29tcGxlbWVudCBpZiByZXF1ZXN0ZWQuXG4gKi9cbmZ1bmN0aW9uIGNvcHlfYmxvY2socywgYnVmLCBsZW4sIGhlYWRlcilcbi8vRGVmbGF0ZVN0YXRlICpzO1xuLy9jaGFyZiAgICAqYnVmOyAgICAvKiB0aGUgaW5wdXQgZGF0YSAqL1xuLy91bnNpZ25lZCBsZW47ICAgICAvKiBpdHMgbGVuZ3RoICovXG4vL2ludCAgICAgIGhlYWRlcjsgIC8qIHRydWUgaWYgYmxvY2sgaGVhZGVyIG11c3QgYmUgd3JpdHRlbiAqL1xue1xuICBiaV93aW5kdXAocyk7ICAgICAgICAvKiBhbGlnbiBvbiBieXRlIGJvdW5kYXJ5ICovXG5cbiAgaWYgKGhlYWRlcikge1xuICAgIHB1dF9zaG9ydChzLCBsZW4pO1xuICAgIHB1dF9zaG9ydChzLCB+bGVuKTtcbiAgfVxuLy8gIHdoaWxlIChsZW4tLSkge1xuLy8gICAgcHV0X2J5dGUocywgKmJ1ZisrKTtcbi8vICB9XG4gIHV0aWxzLmFycmF5U2V0KHMucGVuZGluZ19idWYsIHMud2luZG93LCBidWYsIGxlbiwgcy5wZW5kaW5nKTtcbiAgcy5wZW5kaW5nICs9IGxlbjtcbn1cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb21wYXJlcyB0byBzdWJ0cmVlcywgdXNpbmcgdGhlIHRyZWUgZGVwdGggYXMgdGllIGJyZWFrZXIgd2hlblxuICogdGhlIHN1YnRyZWVzIGhhdmUgZXF1YWwgZnJlcXVlbmN5LiBUaGlzIG1pbmltaXplcyB0aGUgd29yc3QgY2FzZSBsZW5ndGguXG4gKi9cbmZ1bmN0aW9uIHNtYWxsZXIodHJlZSwgbiwgbSwgZGVwdGgpIHtcbiAgdmFyIF9uMiA9IG4qMjtcbiAgdmFyIF9tMiA9IG0qMjtcbiAgcmV0dXJuICh0cmVlW19uMl0vKi5GcmVxKi8gPCB0cmVlW19tMl0vKi5GcmVxKi8gfHxcbiAgICAgICAgICh0cmVlW19uMl0vKi5GcmVxKi8gPT09IHRyZWVbX20yXS8qLkZyZXEqLyAmJiBkZXB0aFtuXSA8PSBkZXB0aFttXSkpO1xufVxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFJlc3RvcmUgdGhlIGhlYXAgcHJvcGVydHkgYnkgbW92aW5nIGRvd24gdGhlIHRyZWUgc3RhcnRpbmcgYXQgbm9kZSBrLFxuICogZXhjaGFuZ2luZyBhIG5vZGUgd2l0aCB0aGUgc21hbGxlc3Qgb2YgaXRzIHR3byBzb25zIGlmIG5lY2Vzc2FyeSwgc3RvcHBpbmdcbiAqIHdoZW4gdGhlIGhlYXAgcHJvcGVydHkgaXMgcmUtZXN0YWJsaXNoZWQgKGVhY2ggZmF0aGVyIHNtYWxsZXIgdGhhbiBpdHNcbiAqIHR3byBzb25zKS5cbiAqL1xuZnVuY3Rpb24gcHFkb3duaGVhcChzLCB0cmVlLCBrKVxuLy8gICAgZGVmbGF0ZV9zdGF0ZSAqcztcbi8vICAgIGN0X2RhdGEgKnRyZWU7ICAvKiB0aGUgdHJlZSB0byByZXN0b3JlICovXG4vLyAgICBpbnQgazsgICAgICAgICAgICAgICAvKiBub2RlIHRvIG1vdmUgZG93biAqL1xue1xuICB2YXIgdiA9IHMuaGVhcFtrXTtcbiAgdmFyIGogPSBrIDw8IDE7ICAvKiBsZWZ0IHNvbiBvZiBrICovXG4gIHdoaWxlIChqIDw9IHMuaGVhcF9sZW4pIHtcbiAgICAvKiBTZXQgaiB0byB0aGUgc21hbGxlc3Qgb2YgdGhlIHR3byBzb25zOiAqL1xuICAgIGlmIChqIDwgcy5oZWFwX2xlbiAmJlxuICAgICAgc21hbGxlcih0cmVlLCBzLmhlYXBbaisxXSwgcy5oZWFwW2pdLCBzLmRlcHRoKSkge1xuICAgICAgaisrO1xuICAgIH1cbiAgICAvKiBFeGl0IGlmIHYgaXMgc21hbGxlciB0aGFuIGJvdGggc29ucyAqL1xuICAgIGlmIChzbWFsbGVyKHRyZWUsIHYsIHMuaGVhcFtqXSwgcy5kZXB0aCkpIHsgYnJlYWs7IH1cblxuICAgIC8qIEV4Y2hhbmdlIHYgd2l0aCB0aGUgc21hbGxlc3Qgc29uICovXG4gICAgcy5oZWFwW2tdID0gcy5oZWFwW2pdO1xuICAgIGsgPSBqO1xuXG4gICAgLyogQW5kIGNvbnRpbnVlIGRvd24gdGhlIHRyZWUsIHNldHRpbmcgaiB0byB0aGUgbGVmdCBzb24gb2YgayAqL1xuICAgIGogPDw9IDE7XG4gIH1cbiAgcy5oZWFwW2tdID0gdjtcbn1cblxuXG4vLyBpbmxpbmVkIG1hbnVhbGx5XG4vLyB2YXIgU01BTExFU1QgPSAxO1xuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFNlbmQgdGhlIGJsb2NrIGRhdGEgY29tcHJlc3NlZCB1c2luZyB0aGUgZ2l2ZW4gSHVmZm1hbiB0cmVlc1xuICovXG5mdW5jdGlvbiBjb21wcmVzc19ibG9jayhzLCBsdHJlZSwgZHRyZWUpXG4vLyAgICBkZWZsYXRlX3N0YXRlICpzO1xuLy8gICAgY29uc3QgY3RfZGF0YSAqbHRyZWU7IC8qIGxpdGVyYWwgdHJlZSAqL1xuLy8gICAgY29uc3QgY3RfZGF0YSAqZHRyZWU7IC8qIGRpc3RhbmNlIHRyZWUgKi9cbntcbiAgdmFyIGRpc3Q7ICAgICAgICAgICAvKiBkaXN0YW5jZSBvZiBtYXRjaGVkIHN0cmluZyAqL1xuICB2YXIgbGM7ICAgICAgICAgICAgIC8qIG1hdGNoIGxlbmd0aCBvciB1bm1hdGNoZWQgY2hhciAoaWYgZGlzdCA9PSAwKSAqL1xuICB2YXIgbHggPSAwOyAgICAgICAgIC8qIHJ1bm5pbmcgaW5kZXggaW4gbF9idWYgKi9cbiAgdmFyIGNvZGU7ICAgICAgICAgICAvKiB0aGUgY29kZSB0byBzZW5kICovXG4gIHZhciBleHRyYTsgICAgICAgICAgLyogbnVtYmVyIG9mIGV4dHJhIGJpdHMgdG8gc2VuZCAqL1xuXG4gIGlmIChzLmxhc3RfbGl0ICE9PSAwKSB7XG4gICAgZG8ge1xuICAgICAgZGlzdCA9IChzLnBlbmRpbmdfYnVmW3MuZF9idWYgKyBseCoyXSA8PCA4KSB8IChzLnBlbmRpbmdfYnVmW3MuZF9idWYgKyBseCoyICsgMV0pO1xuICAgICAgbGMgPSBzLnBlbmRpbmdfYnVmW3MubF9idWYgKyBseF07XG4gICAgICBseCsrO1xuXG4gICAgICBpZiAoZGlzdCA9PT0gMCkge1xuICAgICAgICBzZW5kX2NvZGUocywgbGMsIGx0cmVlKTsgLyogc2VuZCBhIGxpdGVyYWwgYnl0ZSAqL1xuICAgICAgICAvL1RyYWNlY3YoaXNncmFwaChsYyksIChzdGRlcnIsXCIgJyVjJyBcIiwgbGMpKTtcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIC8qIEhlcmUsIGxjIGlzIHRoZSBtYXRjaCBsZW5ndGggLSBNSU5fTUFUQ0ggKi9cbiAgICAgICAgY29kZSA9IF9sZW5ndGhfY29kZVtsY107XG4gICAgICAgIHNlbmRfY29kZShzLCBjb2RlK0xJVEVSQUxTKzEsIGx0cmVlKTsgLyogc2VuZCB0aGUgbGVuZ3RoIGNvZGUgKi9cbiAgICAgICAgZXh0cmEgPSBleHRyYV9sYml0c1tjb2RlXTtcbiAgICAgICAgaWYgKGV4dHJhICE9PSAwKSB7XG4gICAgICAgICAgbGMgLT0gYmFzZV9sZW5ndGhbY29kZV07XG4gICAgICAgICAgc2VuZF9iaXRzKHMsIGxjLCBleHRyYSk7ICAgICAgIC8qIHNlbmQgdGhlIGV4dHJhIGxlbmd0aCBiaXRzICovXG4gICAgICAgIH1cbiAgICAgICAgZGlzdC0tOyAvKiBkaXN0IGlzIG5vdyB0aGUgbWF0Y2ggZGlzdGFuY2UgLSAxICovXG4gICAgICAgIGNvZGUgPSBkX2NvZGUoZGlzdCk7XG4gICAgICAgIC8vQXNzZXJ0IChjb2RlIDwgRF9DT0RFUywgXCJiYWQgZF9jb2RlXCIpO1xuXG4gICAgICAgIHNlbmRfY29kZShzLCBjb2RlLCBkdHJlZSk7ICAgICAgIC8qIHNlbmQgdGhlIGRpc3RhbmNlIGNvZGUgKi9cbiAgICAgICAgZXh0cmEgPSBleHRyYV9kYml0c1tjb2RlXTtcbiAgICAgICAgaWYgKGV4dHJhICE9PSAwKSB7XG4gICAgICAgICAgZGlzdCAtPSBiYXNlX2Rpc3RbY29kZV07XG4gICAgICAgICAgc2VuZF9iaXRzKHMsIGRpc3QsIGV4dHJhKTsgICAvKiBzZW5kIHRoZSBleHRyYSBkaXN0YW5jZSBiaXRzICovXG4gICAgICAgIH1cbiAgICAgIH0gLyogbGl0ZXJhbCBvciBtYXRjaCBwYWlyID8gKi9cblxuICAgICAgLyogQ2hlY2sgdGhhdCB0aGUgb3ZlcmxheSBiZXR3ZWVuIHBlbmRpbmdfYnVmIGFuZCBkX2J1ZitsX2J1ZiBpcyBvazogKi9cbiAgICAgIC8vQXNzZXJ0KCh1SW50KShzLT5wZW5kaW5nKSA8IHMtPmxpdF9idWZzaXplICsgMipseCxcbiAgICAgIC8vICAgICAgIFwicGVuZGluZ0J1ZiBvdmVyZmxvd1wiKTtcblxuICAgIH0gd2hpbGUgKGx4IDwgcy5sYXN0X2xpdCk7XG4gIH1cblxuICBzZW5kX2NvZGUocywgRU5EX0JMT0NLLCBsdHJlZSk7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBDb25zdHJ1Y3Qgb25lIEh1ZmZtYW4gdHJlZSBhbmQgYXNzaWducyB0aGUgY29kZSBiaXQgc3RyaW5ncyBhbmQgbGVuZ3Rocy5cbiAqIFVwZGF0ZSB0aGUgdG90YWwgYml0IGxlbmd0aCBmb3IgdGhlIGN1cnJlbnQgYmxvY2suXG4gKiBJTiBhc3NlcnRpb246IHRoZSBmaWVsZCBmcmVxIGlzIHNldCBmb3IgYWxsIHRyZWUgZWxlbWVudHMuXG4gKiBPVVQgYXNzZXJ0aW9uczogdGhlIGZpZWxkcyBsZW4gYW5kIGNvZGUgYXJlIHNldCB0byB0aGUgb3B0aW1hbCBiaXQgbGVuZ3RoXG4gKiAgICAgYW5kIGNvcnJlc3BvbmRpbmcgY29kZS4gVGhlIGxlbmd0aCBvcHRfbGVuIGlzIHVwZGF0ZWQ7IHN0YXRpY19sZW4gaXNcbiAqICAgICBhbHNvIHVwZGF0ZWQgaWYgc3RyZWUgaXMgbm90IG51bGwuIFRoZSBmaWVsZCBtYXhfY29kZSBpcyBzZXQuXG4gKi9cbmZ1bmN0aW9uIGJ1aWxkX3RyZWUocywgZGVzYylcbi8vICAgIGRlZmxhdGVfc3RhdGUgKnM7XG4vLyAgICB0cmVlX2Rlc2MgKmRlc2M7IC8qIHRoZSB0cmVlIGRlc2NyaXB0b3IgKi9cbntcbiAgdmFyIHRyZWUgICAgID0gZGVzYy5keW5fdHJlZTtcbiAgdmFyIHN0cmVlICAgID0gZGVzYy5zdGF0X2Rlc2Muc3RhdGljX3RyZWU7XG4gIHZhciBoYXNfc3RyZWUgPSBkZXNjLnN0YXRfZGVzYy5oYXNfc3RyZWU7XG4gIHZhciBlbGVtcyAgICA9IGRlc2Muc3RhdF9kZXNjLmVsZW1zO1xuICB2YXIgbiwgbTsgICAgICAgICAgLyogaXRlcmF0ZSBvdmVyIGhlYXAgZWxlbWVudHMgKi9cbiAgdmFyIG1heF9jb2RlID0gLTE7IC8qIGxhcmdlc3QgY29kZSB3aXRoIG5vbiB6ZXJvIGZyZXF1ZW5jeSAqL1xuICB2YXIgbm9kZTsgICAgICAgICAgLyogbmV3IG5vZGUgYmVpbmcgY3JlYXRlZCAqL1xuXG4gIC8qIENvbnN0cnVjdCB0aGUgaW5pdGlhbCBoZWFwLCB3aXRoIGxlYXN0IGZyZXF1ZW50IGVsZW1lbnQgaW5cbiAgICogaGVhcFtTTUFMTEVTVF0uIFRoZSBzb25zIG9mIGhlYXBbbl0gYXJlIGhlYXBbMipuXSBhbmQgaGVhcFsyKm4rMV0uXG4gICAqIGhlYXBbMF0gaXMgbm90IHVzZWQuXG4gICAqL1xuICBzLmhlYXBfbGVuID0gMDtcbiAgcy5oZWFwX21heCA9IEhFQVBfU0laRTtcblxuICBmb3IgKG4gPSAwOyBuIDwgZWxlbXM7IG4rKykge1xuICAgIGlmICh0cmVlW24gKiAyXS8qLkZyZXEqLyAhPT0gMCkge1xuICAgICAgcy5oZWFwWysrcy5oZWFwX2xlbl0gPSBtYXhfY29kZSA9IG47XG4gICAgICBzLmRlcHRoW25dID0gMDtcblxuICAgIH0gZWxzZSB7XG4gICAgICB0cmVlW24qMiArIDFdLyouTGVuKi8gPSAwO1xuICAgIH1cbiAgfVxuXG4gIC8qIFRoZSBwa3ppcCBmb3JtYXQgcmVxdWlyZXMgdGhhdCBhdCBsZWFzdCBvbmUgZGlzdGFuY2UgY29kZSBleGlzdHMsXG4gICAqIGFuZCB0aGF0IGF0IGxlYXN0IG9uZSBiaXQgc2hvdWxkIGJlIHNlbnQgZXZlbiBpZiB0aGVyZSBpcyBvbmx5IG9uZVxuICAgKiBwb3NzaWJsZSBjb2RlLiBTbyB0byBhdm9pZCBzcGVjaWFsIGNoZWNrcyBsYXRlciBvbiB3ZSBmb3JjZSBhdCBsZWFzdFxuICAgKiB0d28gY29kZXMgb2Ygbm9uIHplcm8gZnJlcXVlbmN5LlxuICAgKi9cbiAgd2hpbGUgKHMuaGVhcF9sZW4gPCAyKSB7XG4gICAgbm9kZSA9IHMuaGVhcFsrK3MuaGVhcF9sZW5dID0gKG1heF9jb2RlIDwgMiA/ICsrbWF4X2NvZGUgOiAwKTtcbiAgICB0cmVlW25vZGUgKiAyXS8qLkZyZXEqLyA9IDE7XG4gICAgcy5kZXB0aFtub2RlXSA9IDA7XG4gICAgcy5vcHRfbGVuLS07XG5cbiAgICBpZiAoaGFzX3N0cmVlKSB7XG4gICAgICBzLnN0YXRpY19sZW4gLT0gc3RyZWVbbm9kZSoyICsgMV0vKi5MZW4qLztcbiAgICB9XG4gICAgLyogbm9kZSBpcyAwIG9yIDEgc28gaXQgZG9lcyBub3QgaGF2ZSBleHRyYSBiaXRzICovXG4gIH1cbiAgZGVzYy5tYXhfY29kZSA9IG1heF9jb2RlO1xuXG4gIC8qIFRoZSBlbGVtZW50cyBoZWFwW2hlYXBfbGVuLzIrMSAuLiBoZWFwX2xlbl0gYXJlIGxlYXZlcyBvZiB0aGUgdHJlZSxcbiAgICogZXN0YWJsaXNoIHN1Yi1oZWFwcyBvZiBpbmNyZWFzaW5nIGxlbmd0aHM6XG4gICAqL1xuICBmb3IgKG4gPSAocy5oZWFwX2xlbiA+PiAxLyppbnQgLzIqLyk7IG4gPj0gMTsgbi0tKSB7IHBxZG93bmhlYXAocywgdHJlZSwgbik7IH1cblxuICAvKiBDb25zdHJ1Y3QgdGhlIEh1ZmZtYW4gdHJlZSBieSByZXBlYXRlZGx5IGNvbWJpbmluZyB0aGUgbGVhc3QgdHdvXG4gICAqIGZyZXF1ZW50IG5vZGVzLlxuICAgKi9cbiAgbm9kZSA9IGVsZW1zOyAgICAgICAgICAgICAgLyogbmV4dCBpbnRlcm5hbCBub2RlIG9mIHRoZSB0cmVlICovXG4gIGRvIHtcbiAgICAvL3BxcmVtb3ZlKHMsIHRyZWUsIG4pOyAgLyogbiA9IG5vZGUgb2YgbGVhc3QgZnJlcXVlbmN5ICovXG4gICAgLyoqKiBwcXJlbW92ZSAqKiovXG4gICAgbiA9IHMuaGVhcFsxLypTTUFMTEVTVCovXTtcbiAgICBzLmhlYXBbMS8qU01BTExFU1QqL10gPSBzLmhlYXBbcy5oZWFwX2xlbi0tXTtcbiAgICBwcWRvd25oZWFwKHMsIHRyZWUsIDEvKlNNQUxMRVNUKi8pO1xuICAgIC8qKiovXG5cbiAgICBtID0gcy5oZWFwWzEvKlNNQUxMRVNUKi9dOyAvKiBtID0gbm9kZSBvZiBuZXh0IGxlYXN0IGZyZXF1ZW5jeSAqL1xuXG4gICAgcy5oZWFwWy0tcy5oZWFwX21heF0gPSBuOyAvKiBrZWVwIHRoZSBub2RlcyBzb3J0ZWQgYnkgZnJlcXVlbmN5ICovXG4gICAgcy5oZWFwWy0tcy5oZWFwX21heF0gPSBtO1xuXG4gICAgLyogQ3JlYXRlIGEgbmV3IG5vZGUgZmF0aGVyIG9mIG4gYW5kIG0gKi9cbiAgICB0cmVlW25vZGUgKiAyXS8qLkZyZXEqLyA9IHRyZWVbbiAqIDJdLyouRnJlcSovICsgdHJlZVttICogMl0vKi5GcmVxKi87XG4gICAgcy5kZXB0aFtub2RlXSA9IChzLmRlcHRoW25dID49IHMuZGVwdGhbbV0gPyBzLmRlcHRoW25dIDogcy5kZXB0aFttXSkgKyAxO1xuICAgIHRyZWVbbioyICsgMV0vKi5EYWQqLyA9IHRyZWVbbSoyICsgMV0vKi5EYWQqLyA9IG5vZGU7XG5cbiAgICAvKiBhbmQgaW5zZXJ0IHRoZSBuZXcgbm9kZSBpbiB0aGUgaGVhcCAqL1xuICAgIHMuaGVhcFsxLypTTUFMTEVTVCovXSA9IG5vZGUrKztcbiAgICBwcWRvd25oZWFwKHMsIHRyZWUsIDEvKlNNQUxMRVNUKi8pO1xuXG4gIH0gd2hpbGUgKHMuaGVhcF9sZW4gPj0gMik7XG5cbiAgcy5oZWFwWy0tcy5oZWFwX21heF0gPSBzLmhlYXBbMS8qU01BTExFU1QqL107XG5cbiAgLyogQXQgdGhpcyBwb2ludCwgdGhlIGZpZWxkcyBmcmVxIGFuZCBkYWQgYXJlIHNldC4gV2UgY2FuIG5vd1xuICAgKiBnZW5lcmF0ZSB0aGUgYml0IGxlbmd0aHMuXG4gICAqL1xuICBnZW5fYml0bGVuKHMsIGRlc2MpO1xuXG4gIC8qIFRoZSBmaWVsZCBsZW4gaXMgbm93IHNldCwgd2UgY2FuIGdlbmVyYXRlIHRoZSBiaXQgY29kZXMgKi9cbiAgZ2VuX2NvZGVzKHRyZWUsIG1heF9jb2RlLCBzLmJsX2NvdW50KTtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIFNjYW4gYSBsaXRlcmFsIG9yIGRpc3RhbmNlIHRyZWUgdG8gZGV0ZXJtaW5lIHRoZSBmcmVxdWVuY2llcyBvZiB0aGUgY29kZXNcbiAqIGluIHRoZSBiaXQgbGVuZ3RoIHRyZWUuXG4gKi9cbmZ1bmN0aW9uIHNjYW5fdHJlZShzLCB0cmVlLCBtYXhfY29kZSlcbi8vICAgIGRlZmxhdGVfc3RhdGUgKnM7XG4vLyAgICBjdF9kYXRhICp0cmVlOyAgIC8qIHRoZSB0cmVlIHRvIGJlIHNjYW5uZWQgKi9cbi8vICAgIGludCBtYXhfY29kZTsgICAgLyogYW5kIGl0cyBsYXJnZXN0IGNvZGUgb2Ygbm9uIHplcm8gZnJlcXVlbmN5ICovXG57XG4gIHZhciBuOyAgICAgICAgICAgICAgICAgICAgIC8qIGl0ZXJhdGVzIG92ZXIgYWxsIHRyZWUgZWxlbWVudHMgKi9cbiAgdmFyIHByZXZsZW4gPSAtMTsgICAgICAgICAgLyogbGFzdCBlbWl0dGVkIGxlbmd0aCAqL1xuICB2YXIgY3VybGVuOyAgICAgICAgICAgICAgICAvKiBsZW5ndGggb2YgY3VycmVudCBjb2RlICovXG5cbiAgdmFyIG5leHRsZW4gPSB0cmVlWzAqMiArIDFdLyouTGVuKi87IC8qIGxlbmd0aCBvZiBuZXh0IGNvZGUgKi9cblxuICB2YXIgY291bnQgPSAwOyAgICAgICAgICAgICAvKiByZXBlYXQgY291bnQgb2YgdGhlIGN1cnJlbnQgY29kZSAqL1xuICB2YXIgbWF4X2NvdW50ID0gNzsgICAgICAgICAvKiBtYXggcmVwZWF0IGNvdW50ICovXG4gIHZhciBtaW5fY291bnQgPSA0OyAgICAgICAgIC8qIG1pbiByZXBlYXQgY291bnQgKi9cblxuICBpZiAobmV4dGxlbiA9PT0gMCkge1xuICAgIG1heF9jb3VudCA9IDEzODtcbiAgICBtaW5fY291bnQgPSAzO1xuICB9XG4gIHRyZWVbKG1heF9jb2RlKzEpKjIgKyAxXS8qLkxlbiovID0gMHhmZmZmOyAvKiBndWFyZCAqL1xuXG4gIGZvciAobiA9IDA7IG4gPD0gbWF4X2NvZGU7IG4rKykge1xuICAgIGN1cmxlbiA9IG5leHRsZW47XG4gICAgbmV4dGxlbiA9IHRyZWVbKG4rMSkqMiArIDFdLyouTGVuKi87XG5cbiAgICBpZiAoKytjb3VudCA8IG1heF9jb3VudCAmJiBjdXJsZW4gPT09IG5leHRsZW4pIHtcbiAgICAgIGNvbnRpbnVlO1xuXG4gICAgfSBlbHNlIGlmIChjb3VudCA8IG1pbl9jb3VudCkge1xuICAgICAgcy5ibF90cmVlW2N1cmxlbiAqIDJdLyouRnJlcSovICs9IGNvdW50O1xuXG4gICAgfSBlbHNlIGlmIChjdXJsZW4gIT09IDApIHtcblxuICAgICAgaWYgKGN1cmxlbiAhPT0gcHJldmxlbikgeyBzLmJsX3RyZWVbY3VybGVuICogMl0vKi5GcmVxKi8rKzsgfVxuICAgICAgcy5ibF90cmVlW1JFUF8zXzYqMl0vKi5GcmVxKi8rKztcblxuICAgIH0gZWxzZSBpZiAoY291bnQgPD0gMTApIHtcbiAgICAgIHMuYmxfdHJlZVtSRVBaXzNfMTAqMl0vKi5GcmVxKi8rKztcblxuICAgIH0gZWxzZSB7XG4gICAgICBzLmJsX3RyZWVbUkVQWl8xMV8xMzgqMl0vKi5GcmVxKi8rKztcbiAgICB9XG5cbiAgICBjb3VudCA9IDA7XG4gICAgcHJldmxlbiA9IGN1cmxlbjtcblxuICAgIGlmIChuZXh0bGVuID09PSAwKSB7XG4gICAgICBtYXhfY291bnQgPSAxMzg7XG4gICAgICBtaW5fY291bnQgPSAzO1xuXG4gICAgfSBlbHNlIGlmIChjdXJsZW4gPT09IG5leHRsZW4pIHtcbiAgICAgIG1heF9jb3VudCA9IDY7XG4gICAgICBtaW5fY291bnQgPSAzO1xuXG4gICAgfSBlbHNlIHtcbiAgICAgIG1heF9jb3VudCA9IDc7XG4gICAgICBtaW5fY291bnQgPSA0O1xuICAgIH1cbiAgfVxufVxuXG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogU2VuZCBhIGxpdGVyYWwgb3IgZGlzdGFuY2UgdHJlZSBpbiBjb21wcmVzc2VkIGZvcm0sIHVzaW5nIHRoZSBjb2RlcyBpblxuICogYmxfdHJlZS5cbiAqL1xuZnVuY3Rpb24gc2VuZF90cmVlKHMsIHRyZWUsIG1heF9jb2RlKVxuLy8gICAgZGVmbGF0ZV9zdGF0ZSAqcztcbi8vICAgIGN0X2RhdGEgKnRyZWU7IC8qIHRoZSB0cmVlIHRvIGJlIHNjYW5uZWQgKi9cbi8vICAgIGludCBtYXhfY29kZTsgICAgICAgLyogYW5kIGl0cyBsYXJnZXN0IGNvZGUgb2Ygbm9uIHplcm8gZnJlcXVlbmN5ICovXG57XG4gIHZhciBuOyAgICAgICAgICAgICAgICAgICAgIC8qIGl0ZXJhdGVzIG92ZXIgYWxsIHRyZWUgZWxlbWVudHMgKi9cbiAgdmFyIHByZXZsZW4gPSAtMTsgICAgICAgICAgLyogbGFzdCBlbWl0dGVkIGxlbmd0aCAqL1xuICB2YXIgY3VybGVuOyAgICAgICAgICAgICAgICAvKiBsZW5ndGggb2YgY3VycmVudCBjb2RlICovXG5cbiAgdmFyIG5leHRsZW4gPSB0cmVlWzAqMiArIDFdLyouTGVuKi87IC8qIGxlbmd0aCBvZiBuZXh0IGNvZGUgKi9cblxuICB2YXIgY291bnQgPSAwOyAgICAgICAgICAgICAvKiByZXBlYXQgY291bnQgb2YgdGhlIGN1cnJlbnQgY29kZSAqL1xuICB2YXIgbWF4X2NvdW50ID0gNzsgICAgICAgICAvKiBtYXggcmVwZWF0IGNvdW50ICovXG4gIHZhciBtaW5fY291bnQgPSA0OyAgICAgICAgIC8qIG1pbiByZXBlYXQgY291bnQgKi9cblxuICAvKiB0cmVlW21heF9jb2RlKzFdLkxlbiA9IC0xOyAqLyAgLyogZ3VhcmQgYWxyZWFkeSBzZXQgKi9cbiAgaWYgKG5leHRsZW4gPT09IDApIHtcbiAgICBtYXhfY291bnQgPSAxMzg7XG4gICAgbWluX2NvdW50ID0gMztcbiAgfVxuXG4gIGZvciAobiA9IDA7IG4gPD0gbWF4X2NvZGU7IG4rKykge1xuICAgIGN1cmxlbiA9IG5leHRsZW47XG4gICAgbmV4dGxlbiA9IHRyZWVbKG4rMSkqMiArIDFdLyouTGVuKi87XG5cbiAgICBpZiAoKytjb3VudCA8IG1heF9jb3VudCAmJiBjdXJsZW4gPT09IG5leHRsZW4pIHtcbiAgICAgIGNvbnRpbnVlO1xuXG4gICAgfSBlbHNlIGlmIChjb3VudCA8IG1pbl9jb3VudCkge1xuICAgICAgZG8geyBzZW5kX2NvZGUocywgY3VybGVuLCBzLmJsX3RyZWUpOyB9IHdoaWxlICgtLWNvdW50ICE9PSAwKTtcblxuICAgIH0gZWxzZSBpZiAoY3VybGVuICE9PSAwKSB7XG4gICAgICBpZiAoY3VybGVuICE9PSBwcmV2bGVuKSB7XG4gICAgICAgIHNlbmRfY29kZShzLCBjdXJsZW4sIHMuYmxfdHJlZSk7XG4gICAgICAgIGNvdW50LS07XG4gICAgICB9XG4gICAgICAvL0Fzc2VydChjb3VudCA+PSAzICYmIGNvdW50IDw9IDYsIFwiIDNfNj9cIik7XG4gICAgICBzZW5kX2NvZGUocywgUkVQXzNfNiwgcy5ibF90cmVlKTtcbiAgICAgIHNlbmRfYml0cyhzLCBjb3VudC0zLCAyKTtcblxuICAgIH0gZWxzZSBpZiAoY291bnQgPD0gMTApIHtcbiAgICAgIHNlbmRfY29kZShzLCBSRVBaXzNfMTAsIHMuYmxfdHJlZSk7XG4gICAgICBzZW5kX2JpdHMocywgY291bnQtMywgMyk7XG5cbiAgICB9IGVsc2Uge1xuICAgICAgc2VuZF9jb2RlKHMsIFJFUFpfMTFfMTM4LCBzLmJsX3RyZWUpO1xuICAgICAgc2VuZF9iaXRzKHMsIGNvdW50LTExLCA3KTtcbiAgICB9XG5cbiAgICBjb3VudCA9IDA7XG4gICAgcHJldmxlbiA9IGN1cmxlbjtcbiAgICBpZiAobmV4dGxlbiA9PT0gMCkge1xuICAgICAgbWF4X2NvdW50ID0gMTM4O1xuICAgICAgbWluX2NvdW50ID0gMztcblxuICAgIH0gZWxzZSBpZiAoY3VybGVuID09PSBuZXh0bGVuKSB7XG4gICAgICBtYXhfY291bnQgPSA2O1xuICAgICAgbWluX2NvdW50ID0gMztcblxuICAgIH0gZWxzZSB7XG4gICAgICBtYXhfY291bnQgPSA3O1xuICAgICAgbWluX2NvdW50ID0gNDtcbiAgICB9XG4gIH1cbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENvbnN0cnVjdCB0aGUgSHVmZm1hbiB0cmVlIGZvciB0aGUgYml0IGxlbmd0aHMgYW5kIHJldHVybiB0aGUgaW5kZXggaW5cbiAqIGJsX29yZGVyIG9mIHRoZSBsYXN0IGJpdCBsZW5ndGggY29kZSB0byBzZW5kLlxuICovXG5mdW5jdGlvbiBidWlsZF9ibF90cmVlKHMpIHtcbiAgdmFyIG1heF9ibGluZGV4OyAgLyogaW5kZXggb2YgbGFzdCBiaXQgbGVuZ3RoIGNvZGUgb2Ygbm9uIHplcm8gZnJlcSAqL1xuXG4gIC8qIERldGVybWluZSB0aGUgYml0IGxlbmd0aCBmcmVxdWVuY2llcyBmb3IgbGl0ZXJhbCBhbmQgZGlzdGFuY2UgdHJlZXMgKi9cbiAgc2Nhbl90cmVlKHMsIHMuZHluX2x0cmVlLCBzLmxfZGVzYy5tYXhfY29kZSk7XG4gIHNjYW5fdHJlZShzLCBzLmR5bl9kdHJlZSwgcy5kX2Rlc2MubWF4X2NvZGUpO1xuXG4gIC8qIEJ1aWxkIHRoZSBiaXQgbGVuZ3RoIHRyZWU6ICovXG4gIGJ1aWxkX3RyZWUocywgcy5ibF9kZXNjKTtcbiAgLyogb3B0X2xlbiBub3cgaW5jbHVkZXMgdGhlIGxlbmd0aCBvZiB0aGUgdHJlZSByZXByZXNlbnRhdGlvbnMsIGV4Y2VwdFxuICAgKiB0aGUgbGVuZ3RocyBvZiB0aGUgYml0IGxlbmd0aHMgY29kZXMgYW5kIHRoZSA1KzUrNCBiaXRzIGZvciB0aGUgY291bnRzLlxuICAgKi9cblxuICAvKiBEZXRlcm1pbmUgdGhlIG51bWJlciBvZiBiaXQgbGVuZ3RoIGNvZGVzIHRvIHNlbmQuIFRoZSBwa3ppcCBmb3JtYXRcbiAgICogcmVxdWlyZXMgdGhhdCBhdCBsZWFzdCA0IGJpdCBsZW5ndGggY29kZXMgYmUgc2VudC4gKGFwcG5vdGUudHh0IHNheXNcbiAgICogMyBidXQgdGhlIGFjdHVhbCB2YWx1ZSB1c2VkIGlzIDQuKVxuICAgKi9cbiAgZm9yIChtYXhfYmxpbmRleCA9IEJMX0NPREVTLTE7IG1heF9ibGluZGV4ID49IDM7IG1heF9ibGluZGV4LS0pIHtcbiAgICBpZiAocy5ibF90cmVlW2JsX29yZGVyW21heF9ibGluZGV4XSoyICsgMV0vKi5MZW4qLyAhPT0gMCkge1xuICAgICAgYnJlYWs7XG4gICAgfVxuICB9XG4gIC8qIFVwZGF0ZSBvcHRfbGVuIHRvIGluY2x1ZGUgdGhlIGJpdCBsZW5ndGggdHJlZSBhbmQgY291bnRzICovXG4gIHMub3B0X2xlbiArPSAzKihtYXhfYmxpbmRleCsxKSArIDUrNSs0O1xuICAvL1RyYWNldigoc3RkZXJyLCBcIlxcbmR5biB0cmVlczogZHluICVsZCwgc3RhdCAlbGRcIixcbiAgLy8gICAgICAgIHMtPm9wdF9sZW4sIHMtPnN0YXRpY19sZW4pKTtcblxuICByZXR1cm4gbWF4X2JsaW5kZXg7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBTZW5kIHRoZSBoZWFkZXIgZm9yIGEgYmxvY2sgdXNpbmcgZHluYW1pYyBIdWZmbWFuIHRyZWVzOiB0aGUgY291bnRzLCB0aGVcbiAqIGxlbmd0aHMgb2YgdGhlIGJpdCBsZW5ndGggY29kZXMsIHRoZSBsaXRlcmFsIHRyZWUgYW5kIHRoZSBkaXN0YW5jZSB0cmVlLlxuICogSU4gYXNzZXJ0aW9uOiBsY29kZXMgPj0gMjU3LCBkY29kZXMgPj0gMSwgYmxjb2RlcyA+PSA0LlxuICovXG5mdW5jdGlvbiBzZW5kX2FsbF90cmVlcyhzLCBsY29kZXMsIGRjb2RlcywgYmxjb2Rlcylcbi8vICAgIGRlZmxhdGVfc3RhdGUgKnM7XG4vLyAgICBpbnQgbGNvZGVzLCBkY29kZXMsIGJsY29kZXM7IC8qIG51bWJlciBvZiBjb2RlcyBmb3IgZWFjaCB0cmVlICovXG57XG4gIHZhciByYW5rOyAgICAgICAgICAgICAgICAgICAgLyogaW5kZXggaW4gYmxfb3JkZXIgKi9cblxuICAvL0Fzc2VydCAobGNvZGVzID49IDI1NyAmJiBkY29kZXMgPj0gMSAmJiBibGNvZGVzID49IDQsIFwibm90IGVub3VnaCBjb2Rlc1wiKTtcbiAgLy9Bc3NlcnQgKGxjb2RlcyA8PSBMX0NPREVTICYmIGRjb2RlcyA8PSBEX0NPREVTICYmIGJsY29kZXMgPD0gQkxfQ09ERVMsXG4gIC8vICAgICAgICBcInRvbyBtYW55IGNvZGVzXCIpO1xuICAvL1RyYWNldigoc3RkZXJyLCBcIlxcbmJsIGNvdW50czogXCIpKTtcbiAgc2VuZF9iaXRzKHMsIGxjb2Rlcy0yNTcsIDUpOyAvKiBub3QgKzI1NSBhcyBzdGF0ZWQgaW4gYXBwbm90ZS50eHQgKi9cbiAgc2VuZF9iaXRzKHMsIGRjb2Rlcy0xLCAgIDUpO1xuICBzZW5kX2JpdHMocywgYmxjb2Rlcy00LCAgNCk7IC8qIG5vdCAtMyBhcyBzdGF0ZWQgaW4gYXBwbm90ZS50eHQgKi9cbiAgZm9yIChyYW5rID0gMDsgcmFuayA8IGJsY29kZXM7IHJhbmsrKykge1xuICAgIC8vVHJhY2V2KChzdGRlcnIsIFwiXFxuYmwgY29kZSAlMmQgXCIsIGJsX29yZGVyW3JhbmtdKSk7XG4gICAgc2VuZF9iaXRzKHMsIHMuYmxfdHJlZVtibF9vcmRlcltyYW5rXSoyICsgMV0vKi5MZW4qLywgMyk7XG4gIH1cbiAgLy9UcmFjZXYoKHN0ZGVyciwgXCJcXG5ibCB0cmVlOiBzZW50ICVsZFwiLCBzLT5iaXRzX3NlbnQpKTtcblxuICBzZW5kX3RyZWUocywgcy5keW5fbHRyZWUsIGxjb2Rlcy0xKTsgLyogbGl0ZXJhbCB0cmVlICovXG4gIC8vVHJhY2V2KChzdGRlcnIsIFwiXFxubGl0IHRyZWU6IHNlbnQgJWxkXCIsIHMtPmJpdHNfc2VudCkpO1xuXG4gIHNlbmRfdHJlZShzLCBzLmR5bl9kdHJlZSwgZGNvZGVzLTEpOyAvKiBkaXN0YW5jZSB0cmVlICovXG4gIC8vVHJhY2V2KChzdGRlcnIsIFwiXFxuZGlzdCB0cmVlOiBzZW50ICVsZFwiLCBzLT5iaXRzX3NlbnQpKTtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIENoZWNrIGlmIHRoZSBkYXRhIHR5cGUgaXMgVEVYVCBvciBCSU5BUlksIHVzaW5nIHRoZSBmb2xsb3dpbmcgYWxnb3JpdGhtOlxuICogLSBURVhUIGlmIHRoZSB0d28gY29uZGl0aW9ucyBiZWxvdyBhcmUgc2F0aXNmaWVkOlxuICogICAgYSkgVGhlcmUgYXJlIG5vIG5vbi1wb3J0YWJsZSBjb250cm9sIGNoYXJhY3RlcnMgYmVsb25naW5nIHRvIHRoZVxuICogICAgICAgXCJibGFjayBsaXN0XCIgKDAuLjYsIDE0Li4yNSwgMjguLjMxKS5cbiAqICAgIGIpIFRoZXJlIGlzIGF0IGxlYXN0IG9uZSBwcmludGFibGUgY2hhcmFjdGVyIGJlbG9uZ2luZyB0byB0aGVcbiAqICAgICAgIFwid2hpdGUgbGlzdFwiICg5IHtUQUJ9LCAxMCB7TEZ9LCAxMyB7Q1J9LCAzMi4uMjU1KS5cbiAqIC0gQklOQVJZIG90aGVyd2lzZS5cbiAqIC0gVGhlIGZvbGxvd2luZyBwYXJ0aWFsbHktcG9ydGFibGUgY29udHJvbCBjaGFyYWN0ZXJzIGZvcm0gYVxuICogICBcImdyYXkgbGlzdFwiIHRoYXQgaXMgaWdub3JlZCBpbiB0aGlzIGRldGVjdGlvbiBhbGdvcml0aG06XG4gKiAgICg3IHtCRUx9LCA4IHtCU30sIDExIHtWVH0sIDEyIHtGRn0sIDI2IHtTVUJ9LCAyNyB7RVNDfSkuXG4gKiBJTiBhc3NlcnRpb246IHRoZSBmaWVsZHMgRnJlcSBvZiBkeW5fbHRyZWUgYXJlIHNldC5cbiAqL1xuZnVuY3Rpb24gZGV0ZWN0X2RhdGFfdHlwZShzKSB7XG4gIC8qIGJsYWNrX21hc2sgaXMgdGhlIGJpdCBtYXNrIG9mIGJsYWNrLWxpc3RlZCBieXRlc1xuICAgKiBzZXQgYml0cyAwLi42LCAxNC4uMjUsIGFuZCAyOC4uMzFcbiAgICogMHhmM2ZmYzA3ZiA9IGJpbmFyeSAxMTExMDAxMTExMTExMTExMTEwMDAwMDAwMTExMTExMVxuICAgKi9cbiAgdmFyIGJsYWNrX21hc2sgPSAweGYzZmZjMDdmO1xuICB2YXIgbjtcblxuICAvKiBDaGVjayBmb3Igbm9uLXRleHR1YWwgKFwiYmxhY2stbGlzdGVkXCIpIGJ5dGVzLiAqL1xuICBmb3IgKG4gPSAwOyBuIDw9IDMxOyBuKyssIGJsYWNrX21hc2sgPj4+PSAxKSB7XG4gICAgaWYgKChibGFja19tYXNrICYgMSkgJiYgKHMuZHluX2x0cmVlW24qMl0vKi5GcmVxKi8gIT09IDApKSB7XG4gICAgICByZXR1cm4gWl9CSU5BUlk7XG4gICAgfVxuICB9XG5cbiAgLyogQ2hlY2sgZm9yIHRleHR1YWwgKFwid2hpdGUtbGlzdGVkXCIpIGJ5dGVzLiAqL1xuICBpZiAocy5keW5fbHRyZWVbOSAqIDJdLyouRnJlcSovICE9PSAwIHx8IHMuZHluX2x0cmVlWzEwICogMl0vKi5GcmVxKi8gIT09IDAgfHxcbiAgICAgIHMuZHluX2x0cmVlWzEzICogMl0vKi5GcmVxKi8gIT09IDApIHtcbiAgICByZXR1cm4gWl9URVhUO1xuICB9XG4gIGZvciAobiA9IDMyOyBuIDwgTElURVJBTFM7IG4rKykge1xuICAgIGlmIChzLmR5bl9sdHJlZVtuICogMl0vKi5GcmVxKi8gIT09IDApIHtcbiAgICAgIHJldHVybiBaX1RFWFQ7XG4gICAgfVxuICB9XG5cbiAgLyogVGhlcmUgYXJlIG5vIFwiYmxhY2stbGlzdGVkXCIgb3IgXCJ3aGl0ZS1saXN0ZWRcIiBieXRlczpcbiAgICogdGhpcyBzdHJlYW0gZWl0aGVyIGlzIGVtcHR5IG9yIGhhcyB0b2xlcmF0ZWQgKFwiZ3JheS1saXN0ZWRcIikgYnl0ZXMgb25seS5cbiAgICovXG4gIHJldHVybiBaX0JJTkFSWTtcbn1cblxuXG52YXIgc3RhdGljX2luaXRfZG9uZSA9IGZhbHNlO1xuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIEluaXRpYWxpemUgdGhlIHRyZWUgZGF0YSBzdHJ1Y3R1cmVzIGZvciBhIG5ldyB6bGliIHN0cmVhbS5cbiAqL1xuZnVuY3Rpb24gX3RyX2luaXQocylcbntcblxuICBpZiAoIXN0YXRpY19pbml0X2RvbmUpIHtcbiAgICB0cl9zdGF0aWNfaW5pdCgpO1xuICAgIHN0YXRpY19pbml0X2RvbmUgPSB0cnVlO1xuICB9XG5cbiAgcy5sX2Rlc2MgID0gbmV3IFRyZWVEZXNjKHMuZHluX2x0cmVlLCBzdGF0aWNfbF9kZXNjKTtcbiAgcy5kX2Rlc2MgID0gbmV3IFRyZWVEZXNjKHMuZHluX2R0cmVlLCBzdGF0aWNfZF9kZXNjKTtcbiAgcy5ibF9kZXNjID0gbmV3IFRyZWVEZXNjKHMuYmxfdHJlZSwgc3RhdGljX2JsX2Rlc2MpO1xuXG4gIHMuYmlfYnVmID0gMDtcbiAgcy5iaV92YWxpZCA9IDA7XG5cbiAgLyogSW5pdGlhbGl6ZSB0aGUgZmlyc3QgYmxvY2sgb2YgdGhlIGZpcnN0IGZpbGU6ICovXG4gIGluaXRfYmxvY2socyk7XG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBTZW5kIGEgc3RvcmVkIGJsb2NrXG4gKi9cbmZ1bmN0aW9uIF90cl9zdG9yZWRfYmxvY2socywgYnVmLCBzdG9yZWRfbGVuLCBsYXN0KVxuLy9EZWZsYXRlU3RhdGUgKnM7XG4vL2NoYXJmICpidWY7ICAgICAgIC8qIGlucHV0IGJsb2NrICovXG4vL3VsZyBzdG9yZWRfbGVuOyAgIC8qIGxlbmd0aCBvZiBpbnB1dCBibG9jayAqL1xuLy9pbnQgbGFzdDsgICAgICAgICAvKiBvbmUgaWYgdGhpcyBpcyB0aGUgbGFzdCBibG9jayBmb3IgYSBmaWxlICovXG57XG4gIHNlbmRfYml0cyhzLCAoU1RPUkVEX0JMT0NLPDwxKSsobGFzdCA/IDEgOiAwKSwgMyk7ICAgIC8qIHNlbmQgYmxvY2sgdHlwZSAqL1xuICBjb3B5X2Jsb2NrKHMsIGJ1Ziwgc3RvcmVkX2xlbiwgdHJ1ZSk7IC8qIHdpdGggaGVhZGVyICovXG59XG5cblxuLyogPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gKiBTZW5kIG9uZSBlbXB0eSBzdGF0aWMgYmxvY2sgdG8gZ2l2ZSBlbm91Z2ggbG9va2FoZWFkIGZvciBpbmZsYXRlLlxuICogVGhpcyB0YWtlcyAxMCBiaXRzLCBvZiB3aGljaCA3IG1heSByZW1haW4gaW4gdGhlIGJpdCBidWZmZXIuXG4gKi9cbmZ1bmN0aW9uIF90cl9hbGlnbihzKSB7XG4gIHNlbmRfYml0cyhzLCBTVEFUSUNfVFJFRVM8PDEsIDMpO1xuICBzZW5kX2NvZGUocywgRU5EX0JMT0NLLCBzdGF0aWNfbHRyZWUpO1xuICBiaV9mbHVzaChzKTtcbn1cblxuXG4vKiA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAqIERldGVybWluZSB0aGUgYmVzdCBlbmNvZGluZyBmb3IgdGhlIGN1cnJlbnQgYmxvY2s6IGR5bmFtaWMgdHJlZXMsIHN0YXRpY1xuICogdHJlZXMgb3Igc3RvcmUsIGFuZCBvdXRwdXQgdGhlIGVuY29kZWQgYmxvY2sgdG8gdGhlIHppcCBmaWxlLlxuICovXG5mdW5jdGlvbiBfdHJfZmx1c2hfYmxvY2socywgYnVmLCBzdG9yZWRfbGVuLCBsYXN0KVxuLy9EZWZsYXRlU3RhdGUgKnM7XG4vL2NoYXJmICpidWY7ICAgICAgIC8qIGlucHV0IGJsb2NrLCBvciBOVUxMIGlmIHRvbyBvbGQgKi9cbi8vdWxnIHN0b3JlZF9sZW47ICAgLyogbGVuZ3RoIG9mIGlucHV0IGJsb2NrICovXG4vL2ludCBsYXN0OyAgICAgICAgIC8qIG9uZSBpZiB0aGlzIGlzIHRoZSBsYXN0IGJsb2NrIGZvciBhIGZpbGUgKi9cbntcbiAgdmFyIG9wdF9sZW5iLCBzdGF0aWNfbGVuYjsgIC8qIG9wdF9sZW4gYW5kIHN0YXRpY19sZW4gaW4gYnl0ZXMgKi9cbiAgdmFyIG1heF9ibGluZGV4ID0gMDsgICAgICAgIC8qIGluZGV4IG9mIGxhc3QgYml0IGxlbmd0aCBjb2RlIG9mIG5vbiB6ZXJvIGZyZXEgKi9cblxuICAvKiBCdWlsZCB0aGUgSHVmZm1hbiB0cmVlcyB1bmxlc3MgYSBzdG9yZWQgYmxvY2sgaXMgZm9yY2VkICovXG4gIGlmIChzLmxldmVsID4gMCkge1xuXG4gICAgLyogQ2hlY2sgaWYgdGhlIGZpbGUgaXMgYmluYXJ5IG9yIHRleHQgKi9cbiAgICBpZiAocy5zdHJtLmRhdGFfdHlwZSA9PT0gWl9VTktOT1dOKSB7XG4gICAgICBzLnN0cm0uZGF0YV90eXBlID0gZGV0ZWN0X2RhdGFfdHlwZShzKTtcbiAgICB9XG5cbiAgICAvKiBDb25zdHJ1Y3QgdGhlIGxpdGVyYWwgYW5kIGRpc3RhbmNlIHRyZWVzICovXG4gICAgYnVpbGRfdHJlZShzLCBzLmxfZGVzYyk7XG4gICAgLy8gVHJhY2V2KChzdGRlcnIsIFwiXFxubGl0IGRhdGE6IGR5biAlbGQsIHN0YXQgJWxkXCIsIHMtPm9wdF9sZW4sXG4gICAgLy8gICAgICAgIHMtPnN0YXRpY19sZW4pKTtcblxuICAgIGJ1aWxkX3RyZWUocywgcy5kX2Rlc2MpO1xuICAgIC8vIFRyYWNldigoc3RkZXJyLCBcIlxcbmRpc3QgZGF0YTogZHluICVsZCwgc3RhdCAlbGRcIiwgcy0+b3B0X2xlbixcbiAgICAvLyAgICAgICAgcy0+c3RhdGljX2xlbikpO1xuICAgIC8qIEF0IHRoaXMgcG9pbnQsIG9wdF9sZW4gYW5kIHN0YXRpY19sZW4gYXJlIHRoZSB0b3RhbCBiaXQgbGVuZ3RocyBvZlxuICAgICAqIHRoZSBjb21wcmVzc2VkIGJsb2NrIGRhdGEsIGV4Y2x1ZGluZyB0aGUgdHJlZSByZXByZXNlbnRhdGlvbnMuXG4gICAgICovXG5cbiAgICAvKiBCdWlsZCB0aGUgYml0IGxlbmd0aCB0cmVlIGZvciB0aGUgYWJvdmUgdHdvIHRyZWVzLCBhbmQgZ2V0IHRoZSBpbmRleFxuICAgICAqIGluIGJsX29yZGVyIG9mIHRoZSBsYXN0IGJpdCBsZW5ndGggY29kZSB0byBzZW5kLlxuICAgICAqL1xuICAgIG1heF9ibGluZGV4ID0gYnVpbGRfYmxfdHJlZShzKTtcblxuICAgIC8qIERldGVybWluZSB0aGUgYmVzdCBlbmNvZGluZy4gQ29tcHV0ZSB0aGUgYmxvY2sgbGVuZ3RocyBpbiBieXRlcy4gKi9cbiAgICBvcHRfbGVuYiA9IChzLm9wdF9sZW4rMys3KSA+Pj4gMztcbiAgICBzdGF0aWNfbGVuYiA9IChzLnN0YXRpY19sZW4rMys3KSA+Pj4gMztcblxuICAgIC8vIFRyYWNldigoc3RkZXJyLCBcIlxcbm9wdCAlbHUoJWx1KSBzdGF0ICVsdSglbHUpIHN0b3JlZCAlbHUgbGl0ICV1IFwiLFxuICAgIC8vICAgICAgICBvcHRfbGVuYiwgcy0+b3B0X2xlbiwgc3RhdGljX2xlbmIsIHMtPnN0YXRpY19sZW4sIHN0b3JlZF9sZW4sXG4gICAgLy8gICAgICAgIHMtPmxhc3RfbGl0KSk7XG5cbiAgICBpZiAoc3RhdGljX2xlbmIgPD0gb3B0X2xlbmIpIHsgb3B0X2xlbmIgPSBzdGF0aWNfbGVuYjsgfVxuXG4gIH0gZWxzZSB7XG4gICAgLy8gQXNzZXJ0KGJ1ZiAhPSAoY2hhciopMCwgXCJsb3N0IGJ1ZlwiKTtcbiAgICBvcHRfbGVuYiA9IHN0YXRpY19sZW5iID0gc3RvcmVkX2xlbiArIDU7IC8qIGZvcmNlIGEgc3RvcmVkIGJsb2NrICovXG4gIH1cblxuICBpZiAoKHN0b3JlZF9sZW4rNCA8PSBvcHRfbGVuYikgJiYgKGJ1ZiAhPT0gLTEpKSB7XG4gICAgLyogNDogdHdvIHdvcmRzIGZvciB0aGUgbGVuZ3RocyAqL1xuXG4gICAgLyogVGhlIHRlc3QgYnVmICE9IE5VTEwgaXMgb25seSBuZWNlc3NhcnkgaWYgTElUX0JVRlNJWkUgPiBXU0laRS5cbiAgICAgKiBPdGhlcndpc2Ugd2UgY2FuJ3QgaGF2ZSBwcm9jZXNzZWQgbW9yZSB0aGFuIFdTSVpFIGlucHV0IGJ5dGVzIHNpbmNlXG4gICAgICogdGhlIGxhc3QgYmxvY2sgZmx1c2gsIGJlY2F1c2UgY29tcHJlc3Npb24gd291bGQgaGF2ZSBiZWVuXG4gICAgICogc3VjY2Vzc2Z1bC4gSWYgTElUX0JVRlNJWkUgPD0gV1NJWkUsIGl0IGlzIG5ldmVyIHRvbyBsYXRlIHRvXG4gICAgICogdHJhbnNmb3JtIGEgYmxvY2sgaW50byBhIHN0b3JlZCBibG9jay5cbiAgICAgKi9cbiAgICBfdHJfc3RvcmVkX2Jsb2NrKHMsIGJ1Ziwgc3RvcmVkX2xlbiwgbGFzdCk7XG5cbiAgfSBlbHNlIGlmIChzLnN0cmF0ZWd5ID09PSBaX0ZJWEVEIHx8IHN0YXRpY19sZW5iID09PSBvcHRfbGVuYikge1xuXG4gICAgc2VuZF9iaXRzKHMsIChTVEFUSUNfVFJFRVM8PDEpICsgKGxhc3QgPyAxIDogMCksIDMpO1xuICAgIGNvbXByZXNzX2Jsb2NrKHMsIHN0YXRpY19sdHJlZSwgc3RhdGljX2R0cmVlKTtcblxuICB9IGVsc2Uge1xuICAgIHNlbmRfYml0cyhzLCAoRFlOX1RSRUVTPDwxKSArIChsYXN0ID8gMSA6IDApLCAzKTtcbiAgICBzZW5kX2FsbF90cmVlcyhzLCBzLmxfZGVzYy5tYXhfY29kZSsxLCBzLmRfZGVzYy5tYXhfY29kZSsxLCBtYXhfYmxpbmRleCsxKTtcbiAgICBjb21wcmVzc19ibG9jayhzLCBzLmR5bl9sdHJlZSwgcy5keW5fZHRyZWUpO1xuICB9XG4gIC8vIEFzc2VydCAocy0+Y29tcHJlc3NlZF9sZW4gPT0gcy0+Yml0c19zZW50LCBcImJhZCBjb21wcmVzc2VkIHNpemVcIik7XG4gIC8qIFRoZSBhYm92ZSBjaGVjayBpcyBtYWRlIG1vZCAyXjMyLCBmb3IgZmlsZXMgbGFyZ2VyIHRoYW4gNTEyIE1CXG4gICAqIGFuZCB1TG9uZyBpbXBsZW1lbnRlZCBvbiAzMiBiaXRzLlxuICAgKi9cbiAgaW5pdF9ibG9jayhzKTtcblxuICBpZiAobGFzdCkge1xuICAgIGJpX3dpbmR1cChzKTtcbiAgfVxuICAvLyBUcmFjZXYoKHN0ZGVycixcIlxcbmNvbXBybGVuICVsdSglbHUpIFwiLCBzLT5jb21wcmVzc2VkX2xlbj4+MyxcbiAgLy8gICAgICAgcy0+Y29tcHJlc3NlZF9sZW4tNypsYXN0KSk7XG59XG5cbi8qID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICogU2F2ZSB0aGUgbWF0Y2ggaW5mbyBhbmQgdGFsbHkgdGhlIGZyZXF1ZW5jeSBjb3VudHMuIFJldHVybiB0cnVlIGlmXG4gKiB0aGUgY3VycmVudCBibG9jayBtdXN0IGJlIGZsdXNoZWQuXG4gKi9cbmZ1bmN0aW9uIF90cl90YWxseShzLCBkaXN0LCBsYylcbi8vICAgIGRlZmxhdGVfc3RhdGUgKnM7XG4vLyAgICB1bnNpZ25lZCBkaXN0OyAgLyogZGlzdGFuY2Ugb2YgbWF0Y2hlZCBzdHJpbmcgKi9cbi8vICAgIHVuc2lnbmVkIGxjOyAgICAvKiBtYXRjaCBsZW5ndGgtTUlOX01BVENIIG9yIHVubWF0Y2hlZCBjaGFyIChpZiBkaXN0PT0wKSAqL1xue1xuICAvL3ZhciBvdXRfbGVuZ3RoLCBpbl9sZW5ndGgsIGRjb2RlO1xuXG4gIHMucGVuZGluZ19idWZbcy5kX2J1ZiArIHMubGFzdF9saXQgKiAyXSAgICAgPSAoZGlzdCA+Pj4gOCkgJiAweGZmO1xuICBzLnBlbmRpbmdfYnVmW3MuZF9idWYgKyBzLmxhc3RfbGl0ICogMiArIDFdID0gZGlzdCAmIDB4ZmY7XG5cbiAgcy5wZW5kaW5nX2J1ZltzLmxfYnVmICsgcy5sYXN0X2xpdF0gPSBsYyAmIDB4ZmY7XG4gIHMubGFzdF9saXQrKztcblxuICBpZiAoZGlzdCA9PT0gMCkge1xuICAgIC8qIGxjIGlzIHRoZSB1bm1hdGNoZWQgY2hhciAqL1xuICAgIHMuZHluX2x0cmVlW2xjKjJdLyouRnJlcSovKys7XG4gIH0gZWxzZSB7XG4gICAgcy5tYXRjaGVzKys7XG4gICAgLyogSGVyZSwgbGMgaXMgdGhlIG1hdGNoIGxlbmd0aCAtIE1JTl9NQVRDSCAqL1xuICAgIGRpc3QtLTsgICAgICAgICAgICAgLyogZGlzdCA9IG1hdGNoIGRpc3RhbmNlIC0gMSAqL1xuICAgIC8vQXNzZXJ0KCh1c2gpZGlzdCA8ICh1c2gpTUFYX0RJU1QocykgJiZcbiAgICAvLyAgICAgICAodXNoKWxjIDw9ICh1c2gpKE1BWF9NQVRDSC1NSU5fTUFUQ0gpICYmXG4gICAgLy8gICAgICAgKHVzaClkX2NvZGUoZGlzdCkgPCAodXNoKURfQ09ERVMsICBcIl90cl90YWxseTogYmFkIG1hdGNoXCIpO1xuXG4gICAgcy5keW5fbHRyZWVbKF9sZW5ndGhfY29kZVtsY10rTElURVJBTFMrMSkgKiAyXS8qLkZyZXEqLysrO1xuICAgIHMuZHluX2R0cmVlW2RfY29kZShkaXN0KSAqIDJdLyouRnJlcSovKys7XG4gIH1cblxuLy8gKCEpIFRoaXMgYmxvY2sgaXMgZGlzYWJsZWQgaW4gemxpYiBkZWZhaWx0cyxcbi8vIGRvbid0IGVuYWJsZSBpdCBmb3IgYmluYXJ5IGNvbXBhdGliaWxpdHlcblxuLy8jaWZkZWYgVFJVTkNBVEVfQkxPQ0tcbi8vICAvKiBUcnkgdG8gZ3Vlc3MgaWYgaXQgaXMgcHJvZml0YWJsZSB0byBzdG9wIHRoZSBjdXJyZW50IGJsb2NrIGhlcmUgKi9cbi8vICBpZiAoKHMubGFzdF9saXQgJiAweDFmZmYpID09PSAwICYmIHMubGV2ZWwgPiAyKSB7XG4vLyAgICAvKiBDb21wdXRlIGFuIHVwcGVyIGJvdW5kIGZvciB0aGUgY29tcHJlc3NlZCBsZW5ndGggKi9cbi8vICAgIG91dF9sZW5ndGggPSBzLmxhc3RfbGl0Kjg7XG4vLyAgICBpbl9sZW5ndGggPSBzLnN0cnN0YXJ0IC0gcy5ibG9ja19zdGFydDtcbi8vXG4vLyAgICBmb3IgKGRjb2RlID0gMDsgZGNvZGUgPCBEX0NPREVTOyBkY29kZSsrKSB7XG4vLyAgICAgIG91dF9sZW5ndGggKz0gcy5keW5fZHRyZWVbZGNvZGUqMl0vKi5GcmVxKi8gKiAoNSArIGV4dHJhX2RiaXRzW2Rjb2RlXSk7XG4vLyAgICB9XG4vLyAgICBvdXRfbGVuZ3RoID4+Pj0gMztcbi8vICAgIC8vVHJhY2V2KChzdGRlcnIsXCJcXG5sYXN0X2xpdCAldSwgaW4gJWxkLCBvdXQgfiVsZCglbGQlJSkgXCIsXG4vLyAgICAvLyAgICAgICBzLT5sYXN0X2xpdCwgaW5fbGVuZ3RoLCBvdXRfbGVuZ3RoLFxuLy8gICAgLy8gICAgICAgMTAwTCAtIG91dF9sZW5ndGgqMTAwTC9pbl9sZW5ndGgpKTtcbi8vICAgIGlmIChzLm1hdGNoZXMgPCAocy5sYXN0X2xpdD4+MSkvKmludCAvMiovICYmIG91dF9sZW5ndGggPCAoaW5fbGVuZ3RoPj4xKS8qaW50IC8yKi8pIHtcbi8vICAgICAgcmV0dXJuIHRydWU7XG4vLyAgICB9XG4vLyAgfVxuLy8jZW5kaWZcblxuICByZXR1cm4gKHMubGFzdF9saXQgPT09IHMubGl0X2J1ZnNpemUtMSk7XG4gIC8qIFdlIGF2b2lkIGVxdWFsaXR5IHdpdGggbGl0X2J1ZnNpemUgYmVjYXVzZSBvZiB3cmFwYXJvdW5kIGF0IDY0S1xuICAgKiBvbiAxNiBiaXQgbWFjaGluZXMgYW5kIGJlY2F1c2Ugc3RvcmVkIGJsb2NrcyBhcmUgcmVzdHJpY3RlZCB0b1xuICAgKiA2NEstMSBieXRlcy5cbiAgICovXG59XG5cbmV4cG9ydHMuX3RyX2luaXQgID0gX3RyX2luaXQ7XG5leHBvcnRzLl90cl9zdG9yZWRfYmxvY2sgPSBfdHJfc3RvcmVkX2Jsb2NrO1xuZXhwb3J0cy5fdHJfZmx1c2hfYmxvY2sgID0gX3RyX2ZsdXNoX2Jsb2NrO1xuZXhwb3J0cy5fdHJfdGFsbHkgPSBfdHJfdGFsbHk7XG5leHBvcnRzLl90cl9hbGlnbiA9IF90cl9hbGlnbjsiLCIndXNlIHN0cmljdCc7XG5cblxuZnVuY3Rpb24gWlN0cmVhbSgpIHtcbiAgLyogbmV4dCBpbnB1dCBieXRlICovXG4gIHRoaXMuaW5wdXQgPSBudWxsOyAvLyBKUyBzcGVjaWZpYywgYmVjYXVzZSB3ZSBoYXZlIG5vIHBvaW50ZXJzXG4gIHRoaXMubmV4dF9pbiA9IDA7XG4gIC8qIG51bWJlciBvZiBieXRlcyBhdmFpbGFibGUgYXQgaW5wdXQgKi9cbiAgdGhpcy5hdmFpbF9pbiA9IDA7XG4gIC8qIHRvdGFsIG51bWJlciBvZiBpbnB1dCBieXRlcyByZWFkIHNvIGZhciAqL1xuICB0aGlzLnRvdGFsX2luID0gMDtcbiAgLyogbmV4dCBvdXRwdXQgYnl0ZSBzaG91bGQgYmUgcHV0IHRoZXJlICovXG4gIHRoaXMub3V0cHV0ID0gbnVsbDsgLy8gSlMgc3BlY2lmaWMsIGJlY2F1c2Ugd2UgaGF2ZSBubyBwb2ludGVyc1xuICB0aGlzLm5leHRfb3V0ID0gMDtcbiAgLyogcmVtYWluaW5nIGZyZWUgc3BhY2UgYXQgb3V0cHV0ICovXG4gIHRoaXMuYXZhaWxfb3V0ID0gMDtcbiAgLyogdG90YWwgbnVtYmVyIG9mIGJ5dGVzIG91dHB1dCBzbyBmYXIgKi9cbiAgdGhpcy50b3RhbF9vdXQgPSAwO1xuICAvKiBsYXN0IGVycm9yIG1lc3NhZ2UsIE5VTEwgaWYgbm8gZXJyb3IgKi9cbiAgdGhpcy5tc2cgPSAnJy8qWl9OVUxMKi87XG4gIC8qIG5vdCB2aXNpYmxlIGJ5IGFwcGxpY2F0aW9ucyAqL1xuICB0aGlzLnN0YXRlID0gbnVsbDtcbiAgLyogYmVzdCBndWVzcyBhYm91dCB0aGUgZGF0YSB0eXBlOiBiaW5hcnkgb3IgdGV4dCAqL1xuICB0aGlzLmRhdGFfdHlwZSA9IDIvKlpfVU5LTk9XTiovO1xuICAvKiBhZGxlcjMyIHZhbHVlIG9mIHRoZSB1bmNvbXByZXNzZWQgZGF0YSAqL1xuICB0aGlzLmFkbGVyID0gMDtcbn1cblxubW9kdWxlLmV4cG9ydHMgPSBaU3RyZWFtOyIsInZhciBNZWRpYVN0cmVhbVR5cGUgPSB7XG4gICAgVklERU9fVFlQRTogXCJWaWRlb1wiLFxuXG4gICAgQVVESU9fVFlQRTogXCJBdWRpb1wiXG59O1xubW9kdWxlLmV4cG9ydHMgPSBNZWRpYVN0cmVhbVR5cGU7IiwidmFyIFJUQ0Jyb3dzZXJUeXBlID0ge1xuICAgIFJUQ19CUk9XU0VSX0NIUk9NRTogXCJydGNfYnJvd3Nlci5jaHJvbWVcIixcblxuICAgIFJUQ19CUk9XU0VSX0ZJUkVGT1g6IFwicnRjX2Jyb3dzZXIuZmlyZWZveFwiXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJUQ0Jyb3dzZXJUeXBlOyIsInZhciBSVENFdmVudHMgPSB7XG4gICAgTEFTVE5fQ0hBTkdFRDogXCJydGMubGFzdG5fY2hhbmdlZFwiLFxuICAgIERPTUlOQU5UU1BFQUtFUl9DSEFOR0VEOiBcInJ0Yy5kb21pbmFudHNwZWFrZXJfY2hhbmdlZFwiLFxuICAgIExBU1ROX0VORFBPSU5UX0NIQU5HRUQ6IFwicnRjLmxhc3RuX2VuZHBvaW50X2NoYW5nZWRcIixcbiAgICBTSU1VTENBU1RfTEFZRVJfQ0hBTkdFRDogXCJydGMuc2ltdWxjYXN0X2xheWVyX2NoYW5nZWRcIixcbiAgICBTSU1VTENBU1RfTEFZRVJfQ0hBTkdJTkc6IFwicnRjLnNpbXVsY2FzdF9sYXllcl9jaGFuZ2luZ1wiLFxuICAgIFNJTVVMQ0FTVF9TVEFSVDogXCJydGMuc2ltbGNhc3Rfc3RhcnRcIixcbiAgICBTSU1VTENBU1RfU1RPUDogXCJydGMuc2ltbGNhc3Rfc3RvcFwiXG59O1xuXG5tb2R1bGUuZXhwb3J0cyA9IFJUQ0V2ZW50czsiLCJ2YXIgU3RyZWFtRXZlbnRUeXBlcyA9IHtcbiAgICBFVkVOVF9UWVBFX0xPQ0FMX0NSRUFURUQ6IFwic3RyZWFtLmxvY2FsX2NyZWF0ZWRcIixcblxuICAgIEVWRU5UX1RZUEVfTE9DQUxfQ0hBTkdFRDogXCJzdHJlYW0ubG9jYWxfY2hhbmdlZFwiLFxuXG4gICAgRVZFTlRfVFlQRV9MT0NBTF9FTkRFRDogXCJzdHJlYW0ubG9jYWxfZW5kZWRcIixcblxuICAgIEVWRU5UX1RZUEVfUkVNT1RFX0NSRUFURUQ6IFwic3RyZWFtLnJlbW90ZV9jcmVhdGVkXCIsXG5cbiAgICBFVkVOVF9UWVBFX1JFTU9URV9FTkRFRDogXCJzdHJlYW0ucmVtb3RlX2VuZGVkXCJcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gU3RyZWFtRXZlbnRUeXBlczsiLCJ2YXIgVUlFdmVudHMgPSB7XG4gICAgTklDS05BTUVfQ0hBTkdFRDogXCJVSS5uaWNrbmFtZV9jaGFuZ2VkXCIsXG4gICAgU0VMRUNURURfRU5EUE9JTlQ6IFwiVUkuc2VsZWN0ZWRfZW5kcG9pbnRcIixcbiAgICBQSU5ORURfRU5EUE9JTlQ6IFwiVUkucGlubmVkX2VuZHBvaW50XCJcbn07XG5tb2R1bGUuZXhwb3J0cyA9IFVJRXZlbnRzOyIsInZhciBDUUV2ZW50cyA9IHtcbiAgICBMT0NBTFNUQVRTX1VQREFURUQ6IFwiY3EubG9jYWxzdGF0c191cGRhdGVkXCIsXG4gICAgUkVNT1RFU1RBVFNfVVBEQVRFRDogXCJjcS5yZW1vdGVzdGF0c191cGRhdGVkXCIsXG4gICAgU1RPUDogXCJjcS5zdG9wXCJcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gQ1FFdmVudHM7IiwidmFyIERlc2t0b3BTaGFyaW5nRXZlbnRUeXBlcyA9IHtcbiAgICBJTklUOiBcImRzLmluaXRcIixcblxuICAgIFNXSVRDSElOR19ET05FOiBcImRzLnN3aXRjaGluZ19kb25lXCIsXG5cbiAgICBORVdfU1RSRUFNX0NSRUFURUQ6IFwiZHMubmV3X3N0cmVhbV9jcmVhdGVkXCJcbn07XG5cbm1vZHVsZS5leHBvcnRzID0gRGVza3RvcFNoYXJpbmdFdmVudFR5cGVzOyIsIm1vZHVsZS5leHBvcnRzID0ge1xuICAgIGdldExhbmd1YWdlcyA6IGZ1bmN0aW9uICgpIHtcbiAgICAgICAgdmFyIGxhbmd1YWdlcyA9IFtdO1xuICAgICAgICBmb3IodmFyIGxhbmcgaW4gdGhpcylcbiAgICAgICAge1xuICAgICAgICAgICAgaWYodHlwZW9mIHRoaXNbbGFuZ10gPT09IFwic3RyaW5nXCIpXG4gICAgICAgICAgICAgICAgbGFuZ3VhZ2VzLnB1c2godGhpc1tsYW5nXSk7XG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIGxhbmd1YWdlcztcbiAgICB9LFxuICAgIEVOOiBcImVuXCJcbn0iLCJ2YXIgWE1QUEV2ZW50cyA9IHtcbiAgICBDT05GRVJFTkNFX0NFUkFURUQ6IFwieG1wcC5jb25mZXJlbmNlQ3JlYXRlZC5qaW5nbGVcIixcbiAgICBDQUxMX1RFUk1JTkFURUQ6IFwieG1wcC5jYWxsdGVybWluYXRlZC5qaW5nbGVcIixcbiAgICBDQUxMX0lOQ09NSU5HOiBcInhtcHAuY2FsbGluY29taW5nLmppbmdsZVwiLFxuICAgIERJU1BPU0VfQ09ORkVSRU5DRTogXCJ4bXBwLmRpc3BvY2VfY29uZmVybmNlXCIsXG4gICAgS0lDS0VEOiBcInhtcHAua2lja2VkXCIsXG4gICAgQlJJREdFX0RPV046IFwieG1wcC5icmlkZ2VfZG93blwiLFxuICAgIFVTRVJfSURfQ0hBTkdFRDogXCJ4bXBwLnVzZXJfaWRfY2hhbmdlZFwiLFxuICAgIENIQU5HRURfU1RSRUFNUzogXCJ4bXBwLmNoYW5nZWRfc3RyZWFtc1wiLFxuICAgIE1VQ19KT0lORUQ6IFwieG1wcC5tdWNfam9pbmVkXCIsXG4gICAgTVVDX0VOVEVSOiBcInhtcHAubXVjX2VudGVyXCIsXG4gICAgTVVDX1JPTEVfQ0hBTkdFRDogXCJ4bXBwLm11Y19yb2xlX2NoYW5nZWRcIixcbiAgICBNVUNfTEVGVDogXCJ4bXBwLm11Y19sZWZ0XCIsXG4gICAgRElTUExBWV9OQU1FX0NIQU5HRUQ6IFwieG1wcC5kaXNwbGF5X25hbWVfY2hhbmdlZFwiLFxuICAgIFJFTU9URV9TVEFUUzogXCJ4bXBwLnJlbW90ZV9zdGF0c1wiLFxuICAgIExPQ0FMUk9MRV9DSEFOR0VEOiBcInhtcHAubG9jYWxyb2xlX2NoYW5nZWRcIixcbiAgICBQUkVTRU5DRV9TVEFUVVM6IFwieG1wcC5wcmVzZW5jZV9zdGF0dXNcIixcbiAgICBTVUJKRUNUX0NIQU5HRUQ6IFwieG1wcC5zdWJqZWN0X2NoYW5nZWRcIixcbiAgICBNRVNTQUdFX1JFQ0VJVkVEOiBcInhtcHAubWVzc2FnZV9yZWNlaXZlZFwiLFxuICAgIFNFTkRJTkdfQ0hBVF9NRVNTQUdFOiBcInhtcHAuc2VuZGluZ19jaGF0X21lc3NhZ2VcIixcbiAgICBQQVNTV09SRF9SRVFVSVJFRDogXCJ4bXBwLnBhc3N3b3JkX3JlcXVpcmVkXCIsXG4gICAgQVVUSEVOVElDQVRJT05fUkVRVUlSRUQ6IFwieG1wcC5hdXRoZW50aWNhdGlvbl9yZXF1aXJlZFwiLFxuICAgIENIQVRfRVJST1JfUkVDRUlWRUQ6IFwieG1wcC5jaGF0X2Vycm9yX3JlY2VpdmVkXCIsXG4gICAgRVRIRVJQQUQ6IFwieG1wcC5ldGhlcnBhZFwiXG59O1xubW9kdWxlLmV4cG9ydHMgPSBYTVBQRXZlbnRzOyIsIi8vIENvcHlyaWdodCBKb3llbnQsIEluYy4gYW5kIG90aGVyIE5vZGUgY29udHJpYnV0b3JzLlxuLy9cbi8vIFBlcm1pc3Npb24gaXMgaGVyZWJ5IGdyYW50ZWQsIGZyZWUgb2YgY2hhcmdlLCB0byBhbnkgcGVyc29uIG9idGFpbmluZyBhXG4vLyBjb3B5IG9mIHRoaXMgc29mdHdhcmUgYW5kIGFzc29jaWF0ZWQgZG9jdW1lbnRhdGlvbiBmaWxlcyAodGhlXG4vLyBcIlNvZnR3YXJlXCIpLCB0byBkZWFsIGluIHRoZSBTb2Z0d2FyZSB3aXRob3V0IHJlc3RyaWN0aW9uLCBpbmNsdWRpbmdcbi8vIHdpdGhvdXQgbGltaXRhdGlvbiB0aGUgcmlnaHRzIHRvIHVzZSwgY29weSwgbW9kaWZ5LCBtZXJnZSwgcHVibGlzaCxcbi8vIGRpc3RyaWJ1dGUsIHN1YmxpY2Vuc2UsIGFuZC9vciBzZWxsIGNvcGllcyBvZiB0aGUgU29mdHdhcmUsIGFuZCB0byBwZXJtaXRcbi8vIHBlcnNvbnMgdG8gd2hvbSB0aGUgU29mdHdhcmUgaXMgZnVybmlzaGVkIHRvIGRvIHNvLCBzdWJqZWN0IHRvIHRoZVxuLy8gZm9sbG93aW5nIGNvbmRpdGlvbnM6XG4vL1xuLy8gVGhlIGFib3ZlIGNvcHlyaWdodCBub3RpY2UgYW5kIHRoaXMgcGVybWlzc2lvbiBub3RpY2Ugc2hhbGwgYmUgaW5jbHVkZWRcbi8vIGluIGFsbCBjb3BpZXMgb3Igc3Vic3RhbnRpYWwgcG9ydGlvbnMgb2YgdGhlIFNvZnR3YXJlLlxuLy9cbi8vIFRIRSBTT0ZUV0FSRSBJUyBQUk9WSURFRCBcIkFTIElTXCIsIFdJVEhPVVQgV0FSUkFOVFkgT0YgQU5ZIEtJTkQsIEVYUFJFU1Ncbi8vIE9SIElNUExJRUQsIElOQ0xVRElORyBCVVQgTk9UIExJTUlURUQgVE8gVEhFIFdBUlJBTlRJRVMgT0Zcbi8vIE1FUkNIQU5UQUJJTElUWSwgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UgQU5EIE5PTklORlJJTkdFTUVOVC4gSU5cbi8vIE5PIEVWRU5UIFNIQUxMIFRIRSBBVVRIT1JTIE9SIENPUFlSSUdIVCBIT0xERVJTIEJFIExJQUJMRSBGT1IgQU5ZIENMQUlNLFxuLy8gREFNQUdFUyBPUiBPVEhFUiBMSUFCSUxJVFksIFdIRVRIRVIgSU4gQU4gQUNUSU9OIE9GIENPTlRSQUNULCBUT1JUIE9SXG4vLyBPVEhFUldJU0UsIEFSSVNJTkcgRlJPTSwgT1VUIE9GIE9SIElOIENPTk5FQ1RJT04gV0lUSCBUSEUgU09GVFdBUkUgT1IgVEhFXG4vLyBVU0UgT1IgT1RIRVIgREVBTElOR1MgSU4gVEhFIFNPRlRXQVJFLlxuXG5mdW5jdGlvbiBFdmVudEVtaXR0ZXIoKSB7XG4gIHRoaXMuX2V2ZW50cyA9IHRoaXMuX2V2ZW50cyB8fCB7fTtcbiAgdGhpcy5fbWF4TGlzdGVuZXJzID0gdGhpcy5fbWF4TGlzdGVuZXJzIHx8IHVuZGVmaW5lZDtcbn1cbm1vZHVsZS5leHBvcnRzID0gRXZlbnRFbWl0dGVyO1xuXG4vLyBCYWNrd2FyZHMtY29tcGF0IHdpdGggbm9kZSAwLjEwLnhcbkV2ZW50RW1pdHRlci5FdmVudEVtaXR0ZXIgPSBFdmVudEVtaXR0ZXI7XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuX2V2ZW50cyA9IHVuZGVmaW5lZDtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuX21heExpc3RlbmVycyA9IHVuZGVmaW5lZDtcblxuLy8gQnkgZGVmYXVsdCBFdmVudEVtaXR0ZXJzIHdpbGwgcHJpbnQgYSB3YXJuaW5nIGlmIG1vcmUgdGhhbiAxMCBsaXN0ZW5lcnMgYXJlXG4vLyBhZGRlZCB0byBpdC4gVGhpcyBpcyBhIHVzZWZ1bCBkZWZhdWx0IHdoaWNoIGhlbHBzIGZpbmRpbmcgbWVtb3J5IGxlYWtzLlxuRXZlbnRFbWl0dGVyLmRlZmF1bHRNYXhMaXN0ZW5lcnMgPSAxMDtcblxuLy8gT2J2aW91c2x5IG5vdCBhbGwgRW1pdHRlcnMgc2hvdWxkIGJlIGxpbWl0ZWQgdG8gMTAuIFRoaXMgZnVuY3Rpb24gYWxsb3dzXG4vLyB0aGF0IHRvIGJlIGluY3JlYXNlZC4gU2V0IHRvIHplcm8gZm9yIHVubGltaXRlZC5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuc2V0TWF4TGlzdGVuZXJzID0gZnVuY3Rpb24obikge1xuICBpZiAoIWlzTnVtYmVyKG4pIHx8IG4gPCAwIHx8IGlzTmFOKG4pKVxuICAgIHRocm93IFR5cGVFcnJvcignbiBtdXN0IGJlIGEgcG9zaXRpdmUgbnVtYmVyJyk7XG4gIHRoaXMuX21heExpc3RlbmVycyA9IG47XG4gIHJldHVybiB0aGlzO1xufTtcblxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5lbWl0ID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIgZXIsIGhhbmRsZXIsIGxlbiwgYXJncywgaSwgbGlzdGVuZXJzO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzKVxuICAgIHRoaXMuX2V2ZW50cyA9IHt9O1xuXG4gIC8vIElmIHRoZXJlIGlzIG5vICdlcnJvcicgZXZlbnQgbGlzdGVuZXIgdGhlbiB0aHJvdy5cbiAgaWYgKHR5cGUgPT09ICdlcnJvcicpIHtcbiAgICBpZiAoIXRoaXMuX2V2ZW50cy5lcnJvciB8fFxuICAgICAgICAoaXNPYmplY3QodGhpcy5fZXZlbnRzLmVycm9yKSAmJiAhdGhpcy5fZXZlbnRzLmVycm9yLmxlbmd0aCkpIHtcbiAgICAgIGVyID0gYXJndW1lbnRzWzFdO1xuICAgICAgaWYgKGVyIGluc3RhbmNlb2YgRXJyb3IpIHtcbiAgICAgICAgdGhyb3cgZXI7IC8vIFVuaGFuZGxlZCAnZXJyb3InIGV2ZW50XG4gICAgICB9XG4gICAgICB0aHJvdyBUeXBlRXJyb3IoJ1VuY2F1Z2h0LCB1bnNwZWNpZmllZCBcImVycm9yXCIgZXZlbnQuJyk7XG4gICAgfVxuICB9XG5cbiAgaGFuZGxlciA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICBpZiAoaXNVbmRlZmluZWQoaGFuZGxlcikpXG4gICAgcmV0dXJuIGZhbHNlO1xuXG4gIGlmIChpc0Z1bmN0aW9uKGhhbmRsZXIpKSB7XG4gICAgc3dpdGNoIChhcmd1bWVudHMubGVuZ3RoKSB7XG4gICAgICAvLyBmYXN0IGNhc2VzXG4gICAgICBjYXNlIDE6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICBjYXNlIDI6XG4gICAgICAgIGhhbmRsZXIuY2FsbCh0aGlzLCBhcmd1bWVudHNbMV0pO1xuICAgICAgICBicmVhaztcbiAgICAgIGNhc2UgMzpcbiAgICAgICAgaGFuZGxlci5jYWxsKHRoaXMsIGFyZ3VtZW50c1sxXSwgYXJndW1lbnRzWzJdKTtcbiAgICAgICAgYnJlYWs7XG4gICAgICAvLyBzbG93ZXJcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIGxlbiA9IGFyZ3VtZW50cy5sZW5ndGg7XG4gICAgICAgIGFyZ3MgPSBuZXcgQXJyYXkobGVuIC0gMSk7XG4gICAgICAgIGZvciAoaSA9IDE7IGkgPCBsZW47IGkrKylcbiAgICAgICAgICBhcmdzW2kgLSAxXSA9IGFyZ3VtZW50c1tpXTtcbiAgICAgICAgaGFuZGxlci5hcHBseSh0aGlzLCBhcmdzKTtcbiAgICB9XG4gIH0gZWxzZSBpZiAoaXNPYmplY3QoaGFuZGxlcikpIHtcbiAgICBsZW4gPSBhcmd1bWVudHMubGVuZ3RoO1xuICAgIGFyZ3MgPSBuZXcgQXJyYXkobGVuIC0gMSk7XG4gICAgZm9yIChpID0gMTsgaSA8IGxlbjsgaSsrKVxuICAgICAgYXJnc1tpIC0gMV0gPSBhcmd1bWVudHNbaV07XG5cbiAgICBsaXN0ZW5lcnMgPSBoYW5kbGVyLnNsaWNlKCk7XG4gICAgbGVuID0gbGlzdGVuZXJzLmxlbmd0aDtcbiAgICBmb3IgKGkgPSAwOyBpIDwgbGVuOyBpKyspXG4gICAgICBsaXN0ZW5lcnNbaV0uYXBwbHkodGhpcywgYXJncyk7XG4gIH1cblxuICByZXR1cm4gdHJ1ZTtcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXIgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICB2YXIgbTtcblxuICBpZiAoIWlzRnVuY3Rpb24obGlzdGVuZXIpKVxuICAgIHRocm93IFR5cGVFcnJvcignbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgdGhpcy5fZXZlbnRzID0ge307XG5cbiAgLy8gVG8gYXZvaWQgcmVjdXJzaW9uIGluIHRoZSBjYXNlIHRoYXQgdHlwZSA9PT0gXCJuZXdMaXN0ZW5lclwiISBCZWZvcmVcbiAgLy8gYWRkaW5nIGl0IHRvIHRoZSBsaXN0ZW5lcnMsIGZpcnN0IGVtaXQgXCJuZXdMaXN0ZW5lclwiLlxuICBpZiAodGhpcy5fZXZlbnRzLm5ld0xpc3RlbmVyKVxuICAgIHRoaXMuZW1pdCgnbmV3TGlzdGVuZXInLCB0eXBlLFxuICAgICAgICAgICAgICBpc0Z1bmN0aW9uKGxpc3RlbmVyLmxpc3RlbmVyKSA/XG4gICAgICAgICAgICAgIGxpc3RlbmVyLmxpc3RlbmVyIDogbGlzdGVuZXIpO1xuXG4gIGlmICghdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIC8vIE9wdGltaXplIHRoZSBjYXNlIG9mIG9uZSBsaXN0ZW5lci4gRG9uJ3QgbmVlZCB0aGUgZXh0cmEgYXJyYXkgb2JqZWN0LlxuICAgIHRoaXMuX2V2ZW50c1t0eXBlXSA9IGxpc3RlbmVyO1xuICBlbHNlIGlmIChpc09iamVjdCh0aGlzLl9ldmVudHNbdHlwZV0pKVxuICAgIC8vIElmIHdlJ3ZlIGFscmVhZHkgZ290IGFuIGFycmF5LCBqdXN0IGFwcGVuZC5cbiAgICB0aGlzLl9ldmVudHNbdHlwZV0ucHVzaChsaXN0ZW5lcik7XG4gIGVsc2VcbiAgICAvLyBBZGRpbmcgdGhlIHNlY29uZCBlbGVtZW50LCBuZWVkIHRvIGNoYW5nZSB0byBhcnJheS5cbiAgICB0aGlzLl9ldmVudHNbdHlwZV0gPSBbdGhpcy5fZXZlbnRzW3R5cGVdLCBsaXN0ZW5lcl07XG5cbiAgLy8gQ2hlY2sgZm9yIGxpc3RlbmVyIGxlYWtcbiAgaWYgKGlzT2JqZWN0KHRoaXMuX2V2ZW50c1t0eXBlXSkgJiYgIXRoaXMuX2V2ZW50c1t0eXBlXS53YXJuZWQpIHtcbiAgICB2YXIgbTtcbiAgICBpZiAoIWlzVW5kZWZpbmVkKHRoaXMuX21heExpc3RlbmVycykpIHtcbiAgICAgIG0gPSB0aGlzLl9tYXhMaXN0ZW5lcnM7XG4gICAgfSBlbHNlIHtcbiAgICAgIG0gPSBFdmVudEVtaXR0ZXIuZGVmYXVsdE1heExpc3RlbmVycztcbiAgICB9XG5cbiAgICBpZiAobSAmJiBtID4gMCAmJiB0aGlzLl9ldmVudHNbdHlwZV0ubGVuZ3RoID4gbSkge1xuICAgICAgdGhpcy5fZXZlbnRzW3R5cGVdLndhcm5lZCA9IHRydWU7XG4gICAgICBjb25zb2xlLmVycm9yKCcobm9kZSkgd2FybmluZzogcG9zc2libGUgRXZlbnRFbWl0dGVyIG1lbW9yeSAnICtcbiAgICAgICAgICAgICAgICAgICAgJ2xlYWsgZGV0ZWN0ZWQuICVkIGxpc3RlbmVycyBhZGRlZC4gJyArXG4gICAgICAgICAgICAgICAgICAgICdVc2UgZW1pdHRlci5zZXRNYXhMaXN0ZW5lcnMoKSB0byBpbmNyZWFzZSBsaW1pdC4nLFxuICAgICAgICAgICAgICAgICAgICB0aGlzLl9ldmVudHNbdHlwZV0ubGVuZ3RoKTtcbiAgICAgIGlmICh0eXBlb2YgY29uc29sZS50cmFjZSA9PT0gJ2Z1bmN0aW9uJykge1xuICAgICAgICAvLyBub3Qgc3VwcG9ydGVkIGluIElFIDEwXG4gICAgICAgIGNvbnNvbGUudHJhY2UoKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub24gPSBFdmVudEVtaXR0ZXIucHJvdG90eXBlLmFkZExpc3RlbmVyO1xuXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbih0eXBlLCBsaXN0ZW5lcikge1xuICBpZiAoIWlzRnVuY3Rpb24obGlzdGVuZXIpKVxuICAgIHRocm93IFR5cGVFcnJvcignbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG5cbiAgdmFyIGZpcmVkID0gZmFsc2U7XG5cbiAgZnVuY3Rpb24gZygpIHtcbiAgICB0aGlzLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGcpO1xuXG4gICAgaWYgKCFmaXJlZCkge1xuICAgICAgZmlyZWQgPSB0cnVlO1xuICAgICAgbGlzdGVuZXIuYXBwbHkodGhpcywgYXJndW1lbnRzKTtcbiAgICB9XG4gIH1cblxuICBnLmxpc3RlbmVyID0gbGlzdGVuZXI7XG4gIHRoaXMub24odHlwZSwgZyk7XG5cbiAgcmV0dXJuIHRoaXM7XG59O1xuXG4vLyBlbWl0cyBhICdyZW1vdmVMaXN0ZW5lcicgZXZlbnQgaWZmIHRoZSBsaXN0ZW5lciB3YXMgcmVtb3ZlZFxuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lciA9IGZ1bmN0aW9uKHR5cGUsIGxpc3RlbmVyKSB7XG4gIHZhciBsaXN0LCBwb3NpdGlvbiwgbGVuZ3RoLCBpO1xuXG4gIGlmICghaXNGdW5jdGlvbihsaXN0ZW5lcikpXG4gICAgdGhyb3cgVHlwZUVycm9yKCdsaXN0ZW5lciBtdXN0IGJlIGEgZnVuY3Rpb24nKTtcblxuICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIHJldHVybiB0aGlzO1xuXG4gIGxpc3QgPSB0aGlzLl9ldmVudHNbdHlwZV07XG4gIGxlbmd0aCA9IGxpc3QubGVuZ3RoO1xuICBwb3NpdGlvbiA9IC0xO1xuXG4gIGlmIChsaXN0ID09PSBsaXN0ZW5lciB8fFxuICAgICAgKGlzRnVuY3Rpb24obGlzdC5saXN0ZW5lcikgJiYgbGlzdC5saXN0ZW5lciA9PT0gbGlzdGVuZXIpKSB7XG4gICAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgICBpZiAodGhpcy5fZXZlbnRzLnJlbW92ZUxpc3RlbmVyKVxuICAgICAgdGhpcy5lbWl0KCdyZW1vdmVMaXN0ZW5lcicsIHR5cGUsIGxpc3RlbmVyKTtcblxuICB9IGVsc2UgaWYgKGlzT2JqZWN0KGxpc3QpKSB7XG4gICAgZm9yIChpID0gbGVuZ3RoOyBpLS0gPiAwOykge1xuICAgICAgaWYgKGxpc3RbaV0gPT09IGxpc3RlbmVyIHx8XG4gICAgICAgICAgKGxpc3RbaV0ubGlzdGVuZXIgJiYgbGlzdFtpXS5saXN0ZW5lciA9PT0gbGlzdGVuZXIpKSB7XG4gICAgICAgIHBvc2l0aW9uID0gaTtcbiAgICAgICAgYnJlYWs7XG4gICAgICB9XG4gICAgfVxuXG4gICAgaWYgKHBvc2l0aW9uIDwgMClcbiAgICAgIHJldHVybiB0aGlzO1xuXG4gICAgaWYgKGxpc3QubGVuZ3RoID09PSAxKSB7XG4gICAgICBsaXN0Lmxlbmd0aCA9IDA7XG4gICAgICBkZWxldGUgdGhpcy5fZXZlbnRzW3R5cGVdO1xuICAgIH0gZWxzZSB7XG4gICAgICBsaXN0LnNwbGljZShwb3NpdGlvbiwgMSk7XG4gICAgfVxuXG4gICAgaWYgKHRoaXMuX2V2ZW50cy5yZW1vdmVMaXN0ZW5lcilcbiAgICAgIHRoaXMuZW1pdCgncmVtb3ZlTGlzdGVuZXInLCB0eXBlLCBsaXN0ZW5lcik7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUucmVtb3ZlQWxsTGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIga2V5LCBsaXN0ZW5lcnM7XG5cbiAgaWYgKCF0aGlzLl9ldmVudHMpXG4gICAgcmV0dXJuIHRoaXM7XG5cbiAgLy8gbm90IGxpc3RlbmluZyBmb3IgcmVtb3ZlTGlzdGVuZXIsIG5vIG5lZWQgdG8gZW1pdFxuICBpZiAoIXRoaXMuX2V2ZW50cy5yZW1vdmVMaXN0ZW5lcikge1xuICAgIGlmIChhcmd1bWVudHMubGVuZ3RoID09PSAwKVxuICAgICAgdGhpcy5fZXZlbnRzID0ge307XG4gICAgZWxzZSBpZiAodGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgICAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIC8vIGVtaXQgcmVtb3ZlTGlzdGVuZXIgZm9yIGFsbCBsaXN0ZW5lcnMgb24gYWxsIGV2ZW50c1xuICBpZiAoYXJndW1lbnRzLmxlbmd0aCA9PT0gMCkge1xuICAgIGZvciAoa2V5IGluIHRoaXMuX2V2ZW50cykge1xuICAgICAgaWYgKGtleSA9PT0gJ3JlbW92ZUxpc3RlbmVyJykgY29udGludWU7XG4gICAgICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycyhrZXkpO1xuICAgIH1cbiAgICB0aGlzLnJlbW92ZUFsbExpc3RlbmVycygncmVtb3ZlTGlzdGVuZXInKTtcbiAgICB0aGlzLl9ldmVudHMgPSB7fTtcbiAgICByZXR1cm4gdGhpcztcbiAgfVxuXG4gIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICBpZiAoaXNGdW5jdGlvbihsaXN0ZW5lcnMpKSB7XG4gICAgdGhpcy5yZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcnMpO1xuICB9IGVsc2Uge1xuICAgIC8vIExJRk8gb3JkZXJcbiAgICB3aGlsZSAobGlzdGVuZXJzLmxlbmd0aClcbiAgICAgIHRoaXMucmVtb3ZlTGlzdGVuZXIodHlwZSwgbGlzdGVuZXJzW2xpc3RlbmVycy5sZW5ndGggLSAxXSk7XG4gIH1cbiAgZGVsZXRlIHRoaXMuX2V2ZW50c1t0eXBlXTtcblxuICByZXR1cm4gdGhpcztcbn07XG5cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJzID0gZnVuY3Rpb24odHlwZSkge1xuICB2YXIgcmV0O1xuICBpZiAoIXRoaXMuX2V2ZW50cyB8fCAhdGhpcy5fZXZlbnRzW3R5cGVdKVxuICAgIHJldCA9IFtdO1xuICBlbHNlIGlmIChpc0Z1bmN0aW9uKHRoaXMuX2V2ZW50c1t0eXBlXSkpXG4gICAgcmV0ID0gW3RoaXMuX2V2ZW50c1t0eXBlXV07XG4gIGVsc2VcbiAgICByZXQgPSB0aGlzLl9ldmVudHNbdHlwZV0uc2xpY2UoKTtcbiAgcmV0dXJuIHJldDtcbn07XG5cbkV2ZW50RW1pdHRlci5saXN0ZW5lckNvdW50ID0gZnVuY3Rpb24oZW1pdHRlciwgdHlwZSkge1xuICB2YXIgcmV0O1xuICBpZiAoIWVtaXR0ZXIuX2V2ZW50cyB8fCAhZW1pdHRlci5fZXZlbnRzW3R5cGVdKVxuICAgIHJldCA9IDA7XG4gIGVsc2UgaWYgKGlzRnVuY3Rpb24oZW1pdHRlci5fZXZlbnRzW3R5cGVdKSlcbiAgICByZXQgPSAxO1xuICBlbHNlXG4gICAgcmV0ID0gZW1pdHRlci5fZXZlbnRzW3R5cGVdLmxlbmd0aDtcbiAgcmV0dXJuIHJldDtcbn07XG5cbmZ1bmN0aW9uIGlzRnVuY3Rpb24oYXJnKSB7XG4gIHJldHVybiB0eXBlb2YgYXJnID09PSAnZnVuY3Rpb24nO1xufVxuXG5mdW5jdGlvbiBpc051bWJlcihhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdudW1iZXInO1xufVxuXG5mdW5jdGlvbiBpc09iamVjdChhcmcpIHtcbiAgcmV0dXJuIHR5cGVvZiBhcmcgPT09ICdvYmplY3QnICYmIGFyZyAhPT0gbnVsbDtcbn1cblxuZnVuY3Rpb24gaXNVbmRlZmluZWQoYXJnKSB7XG4gIHJldHVybiBhcmcgPT09IHZvaWQgMDtcbn1cbiJdfQ==